libdap++  Updated for version 3.8.2
DDS.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2002,2003 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 // (c) COPYRIGHT URI/MIT 1994-1999
26 // Please read the full copyright statement in the file COPYRIGHT_URI.
27 //
28 // Authors:
29 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
30 
31 //
32 // jhrg 9/7/94
33 
34 #include "config.h"
35 
36 static char rcsid[] not_used =
37  {"$Id: DDS.cc 23577 2010-09-14 22:20:18Z jimg $"
38  };
39 
40 #include <cstdio>
41 #include <sys/types.h>
42 
43 #ifdef WIN32
44 #include <io.h>
45 #include <process.h>
46 #include <fstream>
47 #else
48 #include <unistd.h> // for alarm and dup
49 #include <sys/wait.h>
50 #endif
51 
52 #include <iostream>
53 #include <sstream>
54 #include <algorithm>
55 #include <functional>
56 
57 //#define DODS_DEBUG
58 //#define DODS_DEBUG2
59 
60 #include "GNURegex.h"
61 
62 #include "DAS.h"
63 #include "Clause.h"
64 #include "Error.h"
65 #include "InternalErr.h"
66 
67 #include "parser.h"
68 #include "debug.h"
69 #include "util.h"
70 
71 #include "Byte.h"
72 #include "Int16.h"
73 #include "UInt16.h"
74 #include "Int32.h"
75 #include "UInt32.h"
76 #include "Float32.h"
77 #include "Float64.h"
78 #include "Str.h"
79 #include "Url.h"
80 #include "Array.h"
81 #include "Structure.h"
82 #include "Sequence.h"
83 #include "Grid.h"
84 
85 #include "escaping.h"
86 
87 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
88 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
89 
90 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
91 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
92 
93 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
94 
95 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
96 
97 using namespace std;
98 
99 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
100 int ddsparse(void *arg);
101 
102 // Glue for the DDS parser defined in dds.lex
103 void dds_switch_to_buffer(void *new_buffer);
104 void dds_delete_buffer(void * buffer);
105 void *dds_buffer(FILE *fp);
106 
107 namespace libdap {
108 
109 void
110 DDS::duplicate(const DDS &dds)
111 {
112  DBG(cerr << "Entering DDS::duplicate... " <<endl);
113  name = dds.name;
114  d_filename = dds.d_filename;
115  d_container_name = dds.d_container_name;
116  d_timeout = dds.d_timeout;
117  d_attr = dds.d_attr;
118 
119  d_factory = dds.d_factory;
120  d_container = dds.d_container;
121  d_dap_major = dds.d_dap_major;
122  d_dap_minor = dds.d_dap_minor;
123 
124  DDS &dds_tmp = const_cast<DDS &>(dds);
125 
126  // copy the things pointed to by the list, not just the pointers
127  for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
128  add_var(*i); // add_var() dups the BaseType.
129  }
130 }
131 
142 DDS::DDS(BaseTypeFactory *factory, const string &n)
143 
144  : d_factory(factory), name(n), d_container(0), d_dap_major(2),
145  d_dap_minor(0),
146  d_request_xml_base(""), d_timeout(0)
147 {
148  DBG(cerr << "Building a DDS with client major/minor: "
149  << d_dap_major << "." << d_dap_minor << endl);
150 }
151 
153 DDS::DDS(const DDS &rhs) : DapObj()
154 {
155  DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
156  duplicate(rhs);
157  DBG(cerr << " bye." << endl);
158 }
159 
161 {
162  // delete all the variables in this DDS
163  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
164  BaseType *btp = *i ;
165  delete btp ; btp = 0;
166  }
167 }
168 
169 DDS &
170 DDS::operator=(const DDS &rhs)
171 {
172  DBG(cerr << "Entering DDS::operator= ..." << endl);
173  if (this == &rhs)
174  return *this;
175 
176  duplicate(rhs);
177 
178  DBG(cerr << " bye." << endl);
179  return *this;
180 }
181 
182 #if 0
183 
198 BaseType *
199 DDS::find_hdf4_dimension_attribute_home(AttrTable::entry *source)
200 {
201  BaseType *btp;
202  string::size_type i = source->name.find("_dim_");
203  if (i != string::npos && (btp = var(source->name.substr(0, i)))) {
204  if (btp->is_vector_type()) {
205  return btp;
206  }
207  else if (btp->type() == dods_grid_c) {
208  // For a Grid, the hdf4 handler uses _dim_n for the n-th Map
209  // i+5 points to the character holding 'n'
210  int n = atoi(source->name.substr(i + 5).c_str());
211  DBG(cerr << "Found a Grid (" << btp->name() << ") and "
212  << source->name.substr(i) << ", extracted n: " << n << endl);
213  return *(dynamic_cast<Grid&>(*btp).map_begin() + n);
214  }
215  }
216 
217  return 0;
218 }
219 
225 AttrTable *
226 DDS::find_matching_container(AttrTable::entry *source, BaseType **dest_variable)
227 {
228  // The attribute entry 'source' must be a container
229  if (source->type != Attr_container)
230  throw InternalErr(__FILE__, __LINE__, "DDS::find_matching_container; expected 'source' to be a container.");
231 
232  // Use the name of the attribute container 'source' to figure out where
233  // to put its contents.
234  BaseType *btp;
235  if ((btp = var(source->name))) {
236  // ... matches a variable name? Use var's table
237  *dest_variable = btp;
238  return &btp->get_attr_table();
239  }
240  else if ((btp = find_hdf4_dimension_attribute_home(source))) {
241  // ... hdf4 dimension attribute? Make a sub table and use that.
242  // btp can only be an Array or a Grid Map (which is an array)
243  if (btp->get_parent() && btp->get_parent()->type() == dods_grid_c) {
244  DBG(cerr << "Found a Grid, assigning to the map" << endl);
245  *dest_variable = btp;
246  return &btp->get_attr_table();
247  }
248  else { // must be a plain Array
249  string::size_type i = source->name.find("_dim_");
250  string ext = source->name.substr(i + 1);
251  *dest_variable = btp;
252  return btp->get_attr_table().append_container(ext);
253  }
254  }
255  else {
256  // ... otherwise assume it's a global attribute.
257  AttrTable *at = d_attr.find_container(source->name);
258  if (!at) {
259  at = new AttrTable(); // Make a new global table if needed
260  d_attr.append_container(at, source->name);
261  }
262 
263  *dest_variable = 0;
264  return at;
265  }
266 }
267 
289 void
291 {
292  // If there is a container set in the DDS then get the container from
293  // the DAS. If they are not the same container, then throw an exception
294  // (should be working on the same container). If the container does not
295  // exist in the DAS, then throw an exception
296  if( d_container )
297  {
298  if( das->container_name() != d_container_name )
299  {
300  string err = (string)"Error transferring attributes: "
301  + "working on container in dds, but not das" ;
302  throw InternalErr(__FILE__, __LINE__, err ) ;
303  }
304  }
305 
306  AttrTable *top_level = das->get_top_level_attributes() ;
307 
308  // foreach container at the outer level
309  AttrTable::Attr_iter das_i = top_level->attr_begin();
310  AttrTable::Attr_iter das_e = top_level->attr_end();
311  while (das_i != das_e) {
312  DBG(cerr << "Working on the '" << (*das_i)->name << "' container."
313  << endl);
314 
315  AttrTable *source = (*das_i)->attributes;
316  // Variable that holds 'dest'; null for a global attribute.
317  BaseType *dest_variable = 0;
318  AttrTable *dest = find_matching_container(*das_i, &dest_variable);
319 
320  // foreach source attribute in the das_i container
321  AttrTable::Attr_iter source_p = source->attr_begin();
322  while (source_p != source->attr_end()) {
323  DBG(cerr << "Working on the '" << (*source_p)->name << "' attribute"
324  << endl);
325 
326  // If this is an attribute container, we must have a container
327  // (this one) within a container (the 'source'). Look and see if
328  // the variable is a Constructor. If so, pass that container into
329  // Constructor::transfer_attributes()
330  if ((*source_p)->type == Attr_container) {
331  if (dest_variable && dest_variable->is_constructor_type()) {
332  dynamic_cast<Constructor&>(*dest_variable).transfer_attributes(*source_p);
333  }
334  else {
335  dest->append_container(new AttrTable(*(*source_p)->attributes),
336  (*source_p)->name);
337  }
338  }
339  else {
340  dest->append_attr(source->get_name(source_p),
341  source->get_type(source_p),
342  source->get_attr_vector(source_p));
343  }
344 
345  ++source_p;
346  }
347 
348  ++das_i;
349  }
350 }
351 #endif
352 
366 void
368 {
369  // If there is a container set in the DDS then get the container from
370  // the DAS. If they are not the same container, then throw an exception
371  // (should be working on the same container). If the container does not
372  // exist in the DAS, then throw an exception
373  if( d_container )
374  {
375  if( das->container_name() != d_container_name )
376  throw InternalErr(__FILE__, __LINE__, "Error transferring attributes: working on a container in dds, but not das" ) ;
377  }
378 
379  // Give each variable a chance to claim its attributes.
380  AttrTable *top_level = das->get_top_level_attributes() ;
381 
382  Vars_iter var = var_begin();
383  while (var != var_end()) {
384  (*var)->transfer_attributes(top_level);
385  var++;
386  }
387 
388  // Now we transfer all of the attributes still marked as global to the
389  // global container in the DDS.
390 
391  AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
392  while (at_cont_p != top_level->attr_end()) {
393  // In truth, all of the top level attributes should be containers, but
394  // this test handles the abnormal case where somehow someone makes a
395  // top level attribute that is not a container by silently dropping it.
396  if ((*at_cont_p)->type == Attr_container
397  && (*at_cont_p)->attributes->is_global_attribute()) {
398  DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl);
399  // copy the source container so that the DAS passed in can be
400  // deleted after calling htis method.
401  AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
402  d_attr.append_container(at, at->get_name());
403  }
404 
405  at_cont_p++;
406  }
407 }
408 
409 #if 0
410  // cruft from the above method
411 
412  AttrTable *dest = d_attr.find_container(at->get_name());
413  if (!dest) {
414  cerr << "making a new sub containter for it" << endl;
415  // If there's currently no top level container with this
416  //container's name (the typical case) make one.
417  dest = new AttrTable(); // Make a new global table if needed
418  d_attr.append_container(dest, at->get_name());
419  }
420 
421  cerr << "now copying its contents to the new container" << endl;
422  // Now copy all of the global attribute's stuff into the matching
423  // container in the DDS.
424  AttrTable::Attr_iter at_p = at->attr_begin();
425  while (at_p != at->attr_end()) {
426  if (at->get_attr_type(at_p) == Attr_container)
427  dest->append_container(at->get_attr_table(at_p), at->get_name(at_p));
428  else
429  dest->append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
430  at_p++;
431  }
432 #endif
433 
441 
443 string
445 {
446  return name;
447 }
448 
450 void
451 DDS::set_dataset_name(const string &n)
452 {
453  name = n;
454 }
455 
457 
459 AttrTable &
461 {
462  return d_attr;
463 }
464 
474 string
476 {
477  return d_filename;
478 }
479 
481 void
482 DDS::filename(const string &fn)
483 {
484  d_filename = fn;
485 }
487 
493 void
494 DDS::set_dap_version(const string &version_string)
495 {
496  istringstream iss(version_string);
497 
498  int major = -1, minor = -1;
499  char dot;
500  iss >> major;
501  iss >> dot;
502  iss >> minor;
503 
504  DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
505 
506  if (major == -1 || minor == -1)
507  throw Error("Could not parse the client dap (XDAP-Accept header) value");
508 
509  set_dap_major(major);
510  set_dap_minor(minor);
511 }
512 
522 string
524 {
525  return d_container_name;
526 }
527 
530 void
531 DDS::container_name(const string &cn)
532 {
533  // we want to search the DDS for the top level structure with the given
534  // name. Set the container to null so that we don't search some previous
535  // container.
536  d_container = 0 ;
537  if( !cn.empty() )
538  {
539  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
540  if( !d_container )
541  {
542  // create a structure for this container. Calling add_var
543  // while_container is null will add the new structure to DDS and
544  // not some sub structure. Adding the new structure makes a copy
545  // of it. So after adding it, go get it and set d_container.
546  Structure *s = new Structure( cn ) ;
547  add_var( s ) ;
548  delete s ;
549  s = 0 ;
550  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
551  }
552  }
553  d_container_name = cn;
554 
555 }
556 
558 Structure *
560 {
561  return d_container ;
562 }
563 
565 
571 void
573 {
574  if (!bt)
575  throw InternalErr(__FILE__, __LINE__,
576  "Trying to add a BaseType object with a NULL pointer.");
577 
578  DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
579 
580  BaseType *btp = bt->ptr_duplicate();
581  DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
582  if( d_container )
583  {
584  // Mem leak fix [mjohnson nov 2009]
585  // Structure::add_var() creates ANOTHER copy.
586  d_container->add_var( bt ) ;
587  // So we need to delete btp or else it leaks
588  delete btp; btp = 0;
589  }
590  else
591  {
592  vars.push_back(btp);
593  }
594 }
595 
602 void
603 DDS::del_var(const string &n)
604 {
605  if( d_container )
606  {
607  d_container->del_var( n ) ;
608  return ;
609  }
610 
611  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
612  if ((*i)->name() == n) {
613  BaseType *bt = *i ;
614  vars.erase(i) ;
615  delete bt ; bt = 0;
616  return;
617  }
618  }
619 }
620 
625 void
627 {
628  if (i != vars.end()) {
629  BaseType *bt = *i ;
630  vars.erase(i) ;
631  delete bt ; bt = 0;
632  }
633 }
634 
641 void
643 {
644  for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
645  BaseType *bt = *i_tmp ;
646  delete bt ; bt = 0;
647  }
648  vars.erase(i1, i2) ;
649 }
650 
658 BaseType *
659 DDS::var(const string &n, BaseType::btp_stack &s)
660 {
661  return var(n, &s);
662 }
682 BaseType *
683 DDS::var(const string &n, BaseType::btp_stack *s)
684 {
685  string name = www2id(n);
686  if( d_container )
687  return d_container->var( name, false, s ) ;
688 
689  BaseType *v = exact_match(name, s);
690  if (v)
691  return v;
692 
693  return leaf_match(name, s);
694 }
695 
696 BaseType *
698 {
699  DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
700 
701  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
702  BaseType *btp = *i;
703  DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
704  // Look for the name in the dataset's top-level
705  if (btp->name() == n) {
706  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
707  return btp;
708  }
709 
710  if (btp->is_constructor_type()) {
711  BaseType *found = btp->var(n, false, s);
712  if (found) {
713  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
714  return found;
715  }
716  }
717 #if STRUCTURE_ARRAY_SYNTAX_OLD
718  if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
719  s->push(btp);
720  BaseType *found = btp->var()->var(n, false, s);
721  if (found) {
722  DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
723  return found;
724  }
725  }
726 #endif
727  }
728 
729  return 0; // It is not here.
730 }
731 
732 BaseType *
733 DDS::exact_match(const string &name, BaseType::btp_stack *s)
734 {
735  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
736  BaseType *btp = *i;
737  DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
738  // Look for the name in the current ctor type or the top level
739  if (btp->name() == name) {
740  DBG2(cerr << "Found " << name << " in: " << btp << endl);
741  return btp;
742  }
743  }
744 
745  string::size_type dot_pos = name.find(".");
746  if (dot_pos != string::npos) {
747  string aggregate = name.substr(0, dot_pos);
748  string field = name.substr(dot_pos + 1);
749 
750  BaseType *agg_ptr = var(aggregate, s);
751  if (agg_ptr) {
752  DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
753  return agg_ptr->var(field, true, s);
754  }
755  else
756  return 0; // qualified names must be *fully* qualified
757  }
758 
759  return 0; // It is not here.
760 }
761 
762 
767 {
768  return vars.begin();
769 }
770 
773 {
774  return vars.rbegin();
775 }
776 
779 {
780  return vars.end() ;
781 }
782 
785 {
786  return vars.rend() ;
787 }
788 
794 {
795  return vars.begin() + i;
796 }
797 
801 BaseType *
803 {
804  return *(vars.begin() + i);
805 }
806 
808 int
810 {
811  return vars.size();
812 }
813 
814 void
816 {
817 #ifndef WIN32
818  alarm(d_timeout);
819 #endif
820 }
821 
822 void
824 {
825 #ifndef WIN32
826  d_timeout = alarm(0);
827 #endif
828 }
829 
830 void
832 {
833  // Has no effect under win32
834  d_timeout = t;
835 }
836 
837 int
839 {
840  // Has to effect under win32
841  return d_timeout;
842 }
843 
845 void
847 {
848  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
849  if ((*i)->type() == dods_sequence_c)
850  dynamic_cast<Sequence&>(**i).set_leaf_sequence();
851  else if ((*i)->type() == dods_structure_c)
852  dynamic_cast<Structure&>(**i).set_leaf_sequence();
853  }
854 }
855 
857 void
858 DDS::parse(string fname)
859 {
860  FILE *in = fopen(fname.c_str(), "r");
861 
862  if (!in) {
863  throw Error(cannot_read_file, "Could not open: " + fname);
864  }
865 
866  try {
867  parse(in);
868  fclose(in);
869  }
870  catch (Error &e) {
871  fclose(in);
872  throw e;
873  }
874 }
875 
876 
878 void
879 DDS::parse(int fd)
880 {
881 #ifdef WIN32
882  FILE *in = fdopen(_dup(fd), "r");
883 #else
884  FILE *in = fdopen(dup(fd), "r");
885 #endif
886 
887  if (!in) {
888  throw InternalErr(__FILE__, __LINE__, "Could not access file.");
889  }
890 
891  try {
892  parse(in);
893  fclose(in);
894  }
895  catch (Error &e) {
896  fclose(in);
897  throw e;
898  }
899 }
900 
907 void
908 DDS::parse(FILE *in)
909 {
910  if (!in) {
911  throw InternalErr(__FILE__, __LINE__, "Null input stream.");
912  }
913 
914  void *buffer = dds_buffer(in);
915  dds_switch_to_buffer(buffer);
916 
917  parser_arg arg(this);
918 
919  bool status = ddsparse((void *) & arg) == 0;
920 
921  dds_delete_buffer(buffer);
922 
923  DBG2(cout << "Status from parser: " << status << endl);
924 
925  // STATUS is the result of the parser function; if a recoverable error
926  // was found it will be true but arg.status() will be false.
927  if (!status || !arg.status()) {// Check parse result
928  if (arg.error())
929  throw *arg.error();
930  }
931 }
932 
933 #if FILE_METHODS
934 
935 void
936 DDS::print(FILE *out)
937 {
938 #if 0
939  ostringstream oss;
940  print(oss);
941 
942  fwrite(oss.str().c_str(), oss.str().length(), 1, out);
943 #else
944  fprintf(out, "Dataset {\n") ;
945 
946  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
947  (*i)->print_decl(out) ;
948  }
949 
950  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
951 
952  return ;
953 #endif
954 }
955 #endif
956 
958 void
959 DDS::print(ostream &out)
960 {
961  out << "Dataset {\n" ;
962 
963  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
964  (*i)->print_decl(out) ;
965  }
966 
967  out << "} " << id2www(name) << ";\n" ;
968 
969  return ;
970 }
971 
972 #if FILE_METHODS
973 
983 void
985 {
986  fprintf(out, "Dataset {\n") ;
987 
988  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
989  // for each variable, indent with four spaces, print a trailing
990  // semicolon, do not print debugging information, print only
991  // variables in the current projection.
992  (*i)->print_decl(out, " ", true, false, true) ;
993  }
994 
995  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
996 
997  return;
998 }
999 #endif
1000 
1011 void
1013 {
1014  out << "Dataset {\n" ;
1015 
1016  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1017  // for each variable, indent with four spaces, print a trailing
1018  // semicolon, do not print debugging information, print only
1019  // variables in the current projection.
1020  (*i)->print_decl(out, " ", true, false, true) ;
1021  }
1022 
1023  out << "} " << id2www(name) << ";\n" ;
1024 
1025  return;
1026 }
1027 
1028 #if FILE_METHODS
1029 class VariablePrintXML : public unary_function<BaseType *, void>
1030 {
1031  FILE *d_out;
1032  bool d_constrained;
1033 public:
1034  VariablePrintXML(FILE *out, bool constrained)
1035  : d_out(out), d_constrained(constrained)
1036  {}
1037  void operator()(BaseType *bt)
1038  {
1039  bt->print_xml(d_out, " ", d_constrained);
1040  }
1041 };
1042 
1053 void
1054 DDS::print_xml(FILE *out, bool constrained, const string &blob)
1055 {
1056  fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1057 
1058  fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
1059 
1060  fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
1061 
1062  fprintf(out,"method=\"FILE*\"\n");
1063  fprintf(out, "dap_major=\"%d\"\n", get_dap_major());
1064  fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor());
1065 
1066  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1067  // this at some point... jhrg
1068  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1069  fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
1070 
1071  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
1073  }
1074  else {
1075  fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
1076  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
1078  }
1079 
1080 
1081  d_attr.print_xml(out, " ", constrained);
1082 
1083  fprintf(out, "\n");
1084 
1085  for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
1086 
1087  fprintf(out, "\n");
1088 
1089  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1090  // the same. jhrg
1091  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1092  fprintf(out, " <dataBLOB href=\"\"/>\n");
1093  }
1094  else if (!blob.empty()
1095  && (get_dap_major() == 3 && get_dap_minor() >= 2)
1096  || get_dap_major() >= 4) {
1097  fprintf(out, " <blob href=\"cid:%s\"/>\n", blob.c_str());
1098  }
1099 
1100 
1101  fprintf(out, "</Dataset>\n");
1102 }
1103 #endif
1104 
1105 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
1106 {
1107  ostream &d_out;
1108  bool d_constrained;
1109 public:
1110  VariablePrintXMLStrm(ostream &out, bool constrained)
1111  : d_out(out), d_constrained(constrained)
1112  {}
1113  void operator()(BaseType *bt)
1114  {
1115  bt->print_xml(d_out, " ", d_constrained);
1116  }
1117 };
1118 
1129 void
1130 DDS::print_xml(ostream &out, bool constrained, const string &blob)
1131 {
1132  out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
1133 
1134  out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
1135 
1136  out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
1137 
1138  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1139  // this at some point... jhrg
1140  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1141  out << "xsi:schemaLocation=\"" << c_dap32_namespace
1142  << " " << c_default_dap32_schema_location << "\"\n" ;
1143 
1144  out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
1145  out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
1146 
1147  out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
1148  out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
1149 
1150  out << "dapVersion=\"" << get_dap_major() << "."
1151  << get_dap_minor() << "\"";
1152 
1153  if (!get_request_xml_base().empty()) {
1154  out << "\n";
1155  out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
1156  out << "xml:base=\"" << get_request_xml_base() << "\"";
1157  }
1158 
1159  // Close the Dataset element
1160  out << ">\n";
1161  }
1162  else {
1163  out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
1164  out << "xsi:schemaLocation=\"" << c_dap20_namespace
1165  << " " << c_default_dap20_schema_location << "\">\n\n" ;
1166  }
1167 
1168  d_attr.print_xml(out, " ", constrained);
1169 
1170  out << "\n" ;
1171 
1172  for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
1173 
1174  out << "\n" ;
1175 
1176  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1177  // the same.
1178  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1179  // actually the CID of the MIME part that holds the data.
1180  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1181  out << " <dataBLOB href=\"\"/>\n" ;
1182  }
1183  else if (!blob.empty()
1184  && (get_dap_major() == 3 && get_dap_minor() >= 2)
1185  || get_dap_major() >= 4) {
1186  out << " <blob href=\"cid:" << blob << "\"/>\n";
1187  }
1188 
1189  out << "</Dataset>\n" ;
1190 }
1191 
1192 // Used by DDS::send() when returning data from a function call.
1207 bool
1209 {
1210  // The dataset must have a name
1211  if (name == "") {
1212  cerr << "A dataset must have a name" << endl;
1213  return false;
1214  }
1215 
1216  string msg;
1217  if (!unique_names(vars, name, "Dataset", msg))
1218  return false;
1219 
1220  if (all)
1221  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1222  if (!(*i)->check_semantics(msg, true))
1223  return false;
1224 
1225  return true;
1226 }
1227 
1253 bool
1254 DDS::mark(const string &n, bool state)
1255 {
1257 
1258  DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1259 
1260  BaseType *variable = var(n, s);
1261  if (!variable) {
1262  DBG2(cerr << "Could not find variable " << n << endl);
1263  delete s; s = 0;
1264  return false;
1265  }
1266  variable->set_send_p(state);
1267 
1268  DBG2(cerr << "DDS::mark: Set variable " << variable->name()
1269  << " (a " << variable->type_name() << ")" << endl);
1270 
1271  // Now check the btp_stack and run BaseType::set_send_p for every
1272  // BaseType pointer on the stack. Using BaseType::set_send_p() will
1273  // set the property for a Constructor but not its contained variables
1274  // which preserves the semantics of projecting just one field.
1275  while (!s->empty()) {
1276  s->top()->BaseType::set_send_p(state);
1277 
1278  DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
1279  << " (a " << s->top()->type_name() << ")" << endl);
1280  string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1281  string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1282  DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1283 
1284  s->pop();
1285  }
1286 
1287  delete s ; s = 0;
1288 
1289  return true;
1290 }
1291 
1297 void
1298 DDS::mark_all(bool state)
1299 {
1300  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1301  (*i)->set_send_p(state);
1302 }
1303 
1311 void
1312 DDS::dump(ostream &strm) const
1313 {
1314  strm << DapIndent::LMarg << "DDS::dump - ("
1315  << (void *)this << ")" << endl ;
1316  DapIndent::Indent() ;
1317  strm << DapIndent::LMarg << "name: " << name << endl ;
1318  strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1319  strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1320  strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1321  strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1322 
1323  strm << DapIndent::LMarg << "global attributes:" << endl ;
1324  DapIndent::Indent() ;
1325  d_attr.dump(strm) ;
1327 
1328  if (vars.size()) {
1329  strm << DapIndent::LMarg << "vars:" << endl ;
1330  DapIndent::Indent() ;
1331  Vars_citer i = vars.begin() ;
1332  Vars_citer ie = vars.end() ;
1333  for (; i != ie; i++) {
1334  (*i)->dump(strm) ;
1335  }
1337  }
1338  else {
1339  strm << DapIndent::LMarg << "vars: none" << endl ;
1340  }
1341 
1343 }
1344 
1345 } // namespace libdap
std::vector< entry * >::iterator Attr_iter
Definition: AttrTable.h:233
string name() const
Returns the name of the class instance.
Definition: BaseType.cc:210
const string c_dap32_namespace
Definition: DDS.cc:91
static void UnIndent()
Definition: DapIndent.cc:49
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:936
virtual Attr_iter attr_end()
Definition: AttrTable.cc:649
DDS(BaseTypeFactory *factory, const string &n="")
Definition: DDS.cc:142
virtual void print_xml(FILE *out, string space=" ", bool constrained=false)
Definition: BaseType.cc:948
int ddsparse(void *arg)
bool unique_names(vector< BaseType *> l, const string &var_name, const string &type_name, string &msg)
Definition: util.cc:119
const string c_dap20_namespace
Definition: DDS.cc:90
Contains the attributes for a dataset.
Definition: AttrTable.h:146
#define not_used
Definition: config.h:521
void dds_delete_buffer(void *buffer)
virtual BaseType * var(const string &name, bool exact_match=true, btp_stack *s=0)
Returns a pointer to a member of a constructor class.
Definition: Structure.cc:359
Vars_iter get_vars_iter(int i)
Get an iterator.
Definition: DDS.cc:793
const string c_default_dap32_schema_location
Definition: DDS.cc:88
virtual string get_type(const string &name)
Get the type name of an attribute within this attribute table.
Definition: AttrTable.cc:543
BaseType * leaf_match(const string &name, BaseType::btp_stack *s=0)
Definition: DDS.cc:697
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:766
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:208
string id2xml(string in, const string &not_allowed)
Definition: escaping.cc:266
virtual BaseType * get_parent()
Definition: BaseType.cc:655
void set_timeout(int t)
Definition: DDS.cc:831
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition: DDS.cc:659
virtual void transfer_attributes(DAS *das)
Definition: DDS.cc:367
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition: DDS.cc:1054
std::vector< BaseType * >::const_iterator Vars_citer
Definition: DDS.h:210
virtual AttrTable * find_container(const string &target)
Find an attribute with a given name.
Definition: AttrTable.cc:495
void timeout_off()
Definition: DDS.cc:823
virtual void add_var(BaseType *bt, Part part=nil)
Definition: Structure.cc:220
Holds a structure (aggregate) type.
Definition: Structure.h:100
Vars_riter var_rend()
Return a reverse iterator.
Definition: DDS.cc:784
string get_dataset_name() const
Definition: DDS.cc:444
#define DBG2(x)
Definition: debug.h:73
int num_var()
Returns the number of variables in the DDS.
Definition: DDS.cc:809
std::vector< BaseType * >::reverse_iterator Vars_riter
Definition: DDS.h:212
stack< BaseType * > btp_stack
Definition: BaseType.h:214
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition: DDS.cc:1254
AttrTable * attributes
Definition: AttrTable.h:167
A class for software fault reporting.
Definition: InternalErr.h:64
virtual bool is_vector_type()
Returns true if the instance is a vector (i.e., array) type variable.
Definition: BaseType.cc:324
void parse(string fname)
Parse a DDS from a file with the given name.
Definition: DDS.cc:858
DDS & operator=(const DDS &rhs)
Definition: DDS.cc:170
virtual bool is_constructor_type()
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
Definition: BaseType.cc:356
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:539
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Returns a pointer to a member of a constructor class.
Definition: BaseType.cc:662
#define DBG(x)
Definition: debug.h:58
virtual ~DDS()
Definition: DDS.cc:160
virtual void set_send_p(bool state)
Definition: BaseType.cc:517
virtual void transfer_attributes(AttrTable *at_container)
Definition: Constructor.cc:260
void mark_all(bool state)
Definition: DDS.cc:1298
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:341
static void Indent()
Definition: DapIndent.cc:43
#define cannot_read_file
Definition: Error.h:66
Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:238
const string c_xml_namespace
Definition: DDS.cc:95
std::vector< BaseType * >::iterator Vars_iter
Definition: DDS.h:211
Holds the Grid data type.
Definition: Grid.h:123
virtual AttrTable & get_attr_table()
Definition: DDS.cc:460
BaseType * get_var_index(int i)
Get a variable.
Definition: DDS.cc:802
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition: DDS.cc:1208
void * dds_buffer(FILE *fp)
void set_dap_version(const string &version_string)
Definition: DDS.cc:494
Structure * container()
Definition: DDS.cc:559
int get_dap_major() const
Get the DAP major version as sent by the client.
Definition: DDS.h:254
string get_request_xml_base() const
Get the URL that will return this DDS/DDX/DataThing.
Definition: DDS.h:266
string container_name()
Definition: DDS.cc:523
virtual void del_var(const string &name)
Definition: Structure.cc:242
void dds_switch_to_buffer(void *new_buffer)
virtual AttrTable * get_top_level_attributes()
Returns the top most set of attributes.
Definition: DAS.h:149
virtual void dump(ostream &strm) const
dumps information about this object
Definition: DDS.cc:1312
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:640
virtual BaseType * ptr_duplicate()=0
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:214
void timeout_on()
Definition: DDS.cc:815
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:778
BaseType * exact_match(const string &name, BaseType::btp_stack *s=0)
Definition: DDS.cc:733
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition: DDS.cc:846
static ostream & LMarg(ostream &strm)
Definition: DapIndent.cc:78
const string c_default_dap20_schema_location
Definition: DDS.cc:87
virtual AttrTable & get_attr_table()
Definition: BaseType.cc:531
void ddsrestart(FILE *yyin)
void set_dap_minor(int p)
Set the DAP minor version (typically using info from the client)
Definition: DDS.h:261
void set_dataset_name(const string &n)
Definition: DDS.cc:451
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:239
The basic data type for the DODS DAP types.
Definition: BaseType.h:190
libdap base object for common functionality of libdap objects
Definition: DapObj.h:55
Pass parameters by reference to a parser.
Definition: parser.h:68
void del_var(const string &n)
Removes a variable from the DDS.
Definition: DDS.cc:603
string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:252
Vars_riter var_rbegin()
Return a reverse iterator.
Definition: DDS.cc:772
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:585
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:123
const string grddl_transformation_dap32
Definition: DDS.cc:93
A class for error processing.
Definition: Error.h:90
void duplicate(const DDS &dds)
Definition: DDS.cc:110
int get_dap_minor() const
Get the DAP minor version as sent by the client.
Definition: DDS.h:256
void set_dap_major(int p)
Set the DAP major version (typically using info from the client)
Definition: DDS.h:259
string filename()
Definition: DDS.cc:475
int get_timeout()
Definition: DDS.cc:838
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition: DDS.cc:984
virtual string container_name()
Returns the name of the current attribute container when multiple files used to build this DAS...
Definition: DAS.cc:109
string id2www(string in, const string &allowable)
Definition: escaping.cc:151
void add_var(BaseType *bt)
Adds a copy of the variable to the DDS. Using the ptr_duplicate() method, perform a deep copy on the ...
Definition: DDS.cc:572