libdap  Updated for version 3.18.2
DDS.cc
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 #include <cstdio>
37 #include <cmath>
38 #include <sys/types.h>
39 
40 #ifdef WIN32
41 #include <io.h>
42 #include <process.h>
43 #include <fstream>
44 #else
45 #include <unistd.h> // for alarm and dup
46 #include <sys/wait.h>
47 #endif
48 
49 #include <iostream>
50 #include <sstream>
51 #include <algorithm>
52 #include <functional>
53 
54 //#define DODS_DEBUG
55 //#define DODS_DEBUG2
56 
57 #include "GNURegex.h"
58 
59 #include "DAS.h"
60 #include "Clause.h"
61 #include "Error.h"
62 #include "InternalErr.h"
63 #include "Keywords2.h"
64 
65 #include "parser.h"
66 #include "debug.h"
67 #include "util.h"
68 
69 #include "Byte.h"
70 #include "Int16.h"
71 #include "UInt16.h"
72 #include "Int32.h"
73 #include "UInt32.h"
74 #include "Float32.h"
75 #include "Float64.h"
76 #include "Str.h"
77 #include "Url.h"
78 #include "Array.h"
79 #include "Structure.h"
80 #include "Sequence.h"
81 #include "Grid.h"
82 
83 #include "escaping.h"
84 
95 const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
96 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
97 
98 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
99 
100 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
101 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
102 const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
103 
104 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
105 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
106 const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
107 
108 const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
109 const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
110 const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
121 using namespace std;
122 
123 int ddsparse(libdap::parser_arg *arg);
124 
125 // Glue for the DDS parser defined in dds.lex
126 void dds_switch_to_buffer(void *new_buffer);
127 void dds_delete_buffer(void * buffer);
128 void *dds_buffer(FILE *fp);
129 
130 namespace libdap {
131 
132 void
133 DDS::duplicate(const DDS &dds)
134 {
135  DBG(cerr << "Entering DDS::duplicate... " <<endl);
136 #if 0
137  BaseTypeFactory *d_factory;
138 
139  string d_name; // The dataset d_name
140  string d_filename; // File d_name (or other OS identifier) for
141  string d_container_name; // d_name of container structure
142  Structure *d_container; // current container for container d_name
143  // dataset or part of dataset.
144 
145  int d_dap_major; // The protocol major version number
146  int d_dap_minor; // ... and minor version number
147  string d_dap_version; // String version of the protocol
148  string d_request_xml_base;
149  string d_namespace;
150 
151  AttrTable d_attr; // Global attributes.
152 
153  vector<BaseType *> vars; // Variables at the top level
154 
155  int d_timeout; // alarm time in seconds. If greater than
156  // zero, raise the alarm signal if more than
157  // d_timeout seconds are spent reading data.
158  Keywords d_keywords; // Holds keywords parsed from the CE
159 
160  long d_max_response_size; // In bytes
161 #endif
162 
163  d_factory = dds.d_factory;
164 
165  d_name = dds.d_name;
166  d_filename = dds.d_filename;
167  d_container_name = dds.d_container_name;
168  d_container = dds.d_container;
169 
170  d_dap_major = dds.d_dap_major;
171  d_dap_minor = dds.d_dap_minor;
172 
173  d_dap_version = dds.d_dap_version; // String version of the protocol
174  d_request_xml_base = dds.d_request_xml_base;
175  d_namespace = dds.d_namespace;
176 
177  d_attr = dds.d_attr;
178 
179  DDS &dds_tmp = const_cast<DDS &>(dds);
180 
181  // copy the things pointed to by the list, not just the pointers
182  for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
183  add_var(*i); // add_var() dups the BaseType.
184  }
185 
186  d_timeout = dds.d_timeout;
187 
188  d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
189 
190  d_max_response_size = dds.d_max_response_size;
191 }
192 
205 DDS::DDS(BaseTypeFactory *factory, const string &name)
206  : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
207  d_request_xml_base(""),
208  d_timeout(0), d_keywords(), d_max_response_size(0)
209 {
210  DBG(cerr << "Building a DDS for the default version (2.0)" << endl);
211 
212  // This method sets a number of values, including those returned by
213  // get_protocol_major(), ..., get_namespace().
214  set_dap_version("2.0");
215 }
216 
232 DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version)
233  : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
234  d_request_xml_base(""),
235  d_timeout(0), d_keywords(), d_max_response_size(0)
236 {
237  DBG(cerr << "Building a DDS for version: " << version << endl);
238 
239  // This method sets a number of values, including those returned by
240  // get_protocol_major(), ..., get_namespace().
241  set_dap_version(version);
242 }
243 
245 DDS::DDS(const DDS &rhs) : DapObj()
246 {
247  DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
248  duplicate(rhs);
249  DBG(cerr << " bye." << endl);
250 }
251 
252 DDS::~DDS()
253 {
254  // delete all the variables in this DDS
255  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
256  BaseType *btp = *i ;
257  delete btp ; btp = 0;
258  }
259 }
260 
261 DDS &
262 DDS::operator=(const DDS &rhs)
263 {
264  DBG(cerr << "Entering DDS::operator= ..." << endl);
265  if (this == &rhs)
266  return *this;
267 
268  duplicate(rhs);
269 
270  DBG(cerr << " bye." << endl);
271  return *this;
272 }
273 
288 {
289  // If there is a container set in the DDS then check the container from
290  // the DAS. If they are not the same container, then throw an exception
291  // (should be working on the same container). If the container does not
292  // exist in the DAS, then throw an exception
293  if (d_container && das->container_name() != d_container_name)
294  throw InternalErr(__FILE__, __LINE__,
295  "Error transferring attributes: working on a container in dds, but not das");
296 
297  // Give each variable a chance to claim its attributes.
298  AttrTable *top = das->get_top_level_attributes();
299 
300  for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) {
301  (*i)->transfer_attributes(top);
302  }
303 #if 0
304  Vars_iter var = var_begin();
305  while (var != var_end()) {
306  try {
307  DBG(cerr << "Processing the attributes for: " << (*var)->d_name() << " a " << (*var)->type_name() << endl);
308  (*var)->transfer_attributes(top);
309  var++;
310  }
311  catch (Error &e) {
312  DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
313  var++;
314  throw e;
315  }
316  }
317 #endif
318  // Now we transfer all of the attributes still marked as global to the
319  // global container in the DDS.
320  for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) {
321  if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) {
322  // copy the source container so that the DAS passed in can be
323  // deleted after calling this method.
324  AttrTable *at = new AttrTable(*(*i)->attributes);
325  d_attr.append_container(at, at->get_name());
326  }
327  }
328 #if 0
329  AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
330  while (at_cont_p != top_level->attr_end()) {
331  // In truth, all of the top level attributes should be containers, but
332  // this test handles the abnormal case where somehow someone makes a
333  // top level attribute that is not a container by silently dropping it.
334  if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
335  DBG(cerr << (*at_cont_p)->d_name << " is a global attribute." << endl);
336  // copy the source container so that the DAS passed in can be
337  // deleted after calling this method.
338  AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
339  d_attr.append_container(at, at->get_name());
340  }
341 
342  at_cont_p++;
343  }
344 #endif
345 }
346 
354 
356 string
358 {
359  return d_name;
360 }
361 
363 void
364 DDS::set_dataset_name(const string &n)
365 {
366  d_name = n;
367 }
368 
370 
372 AttrTable &
374 {
375  return d_attr;
376 }
377 
387 string
389 {
390  return d_filename;
391 }
392 
394 void
395 DDS::filename(const string &fn)
396 {
397  d_filename = fn;
398 }
400 
404 void
406 {
407  d_dap_major = p;
408 
409  // This works because regardless of the order set_dap_major and set_dap_minor
410  // are called, once they both are called, the value in the string is
411  // correct. I protect against negative numbers because that would be
412  // nonsensical.
413  if (d_dap_minor >= 0) {
414  ostringstream oss;
415  oss << d_dap_major << "." << d_dap_minor;
416  d_dap_version = oss.str();
417  }
418 }
419 
423 void
425 {
426  d_dap_minor = p;
427 
428  if (d_dap_major >= 0) {
429  ostringstream oss;
430  oss << d_dap_major << "." << d_dap_minor;
431  d_dap_version = oss.str();
432  }
433 }
434 
440 void
441 DDS::set_dap_version(const string &v /* = "2.0" */)
442 {
443  istringstream iss(v);
444 
445  int major = -1, minor = -1;
446  char dot;
447  if (!iss.eof() && !iss.fail())
448  iss >> major;
449  if (!iss.eof() && !iss.fail())
450  iss >> dot;
451  if (!iss.eof() && !iss.fail())
452  iss >> minor;
453 
454  if (major == -1 || minor == -1 or dot != '.')
455  throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
456 
457  d_dap_version = v;
458 
459  d_dap_major = major;
460  d_dap_minor = minor;
461 
462  // Now set the related XML constants. These might be overwritten if
463  // the DDS instance is being built from a document parse, but if it's
464  // being constructed by a server the code to generate the XML document
465  // needs these values to match the DAP version information.
466  switch (d_dap_major) {
467  case 2:
468  d_namespace = c_dap20_namespace;
469  break;
470  case 3:
471  d_namespace = c_dap32_namespace;
472  break;
473  case 4:
474  d_namespace = c_dap40_namespace;
475  break;
476  default:
477  throw InternalErr(__FILE__, __LINE__, "Unknown DAP version.");
478  }
479 }
480 
488 void
490 {
491  int major = floor(d);
492  int minor = (d-major)*10;
493 
494  DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
495 
496  ostringstream oss;
497  oss << major << "." << minor;
498 
499  set_dap_version(oss.str());
500 }
501 
511 string
513 {
514  return d_container_name;
515 }
516 
519 void
520 DDS::container_name(const string &cn)
521 {
522  // we want to search the DDS for the top level structure with the given
523  // d_name. Set the container to null so that we don't search some previous
524  // container.
525  d_container = 0 ;
526  if( !cn.empty() )
527  {
528  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
529  if( !d_container )
530  {
531  // create a structure for this container. Calling add_var
532  // while_container is null will add the new structure to DDS and
533  // not some sub structure. Adding the new structure makes a copy
534  // of it. So after adding it, go get it and set d_container.
535  Structure *s = new Structure( cn ) ;
536  add_var( s ) ;
537  delete s ;
538  s = 0 ;
539  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
540  }
541  }
542  d_container_name = cn;
543 
544 }
545 
547 Structure *
549 {
550  return d_container ;
551 }
552 
554 
565 int
566 DDS::get_request_size(bool constrained)
567 {
568  int w = 0;
569  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
570  if (constrained) {
571  if ((*i)->send_p())
572  w += (*i)->width(constrained);
573  }
574  else {
575  w += (*i)->width(constrained);
576  }
577  }
578 
579  return w;
580 }
581 
588  if (!bt)
589  throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
590 #if 0
591  if (bt->is_dap4_only_type())
592  throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
593 #endif
594  DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
595 
596  BaseType *btp = bt->ptr_duplicate();
597  DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
598  if (d_container) {
599  // Mem leak fix [mjohnson nov 2009]
600  // Structure::add_var() creates ANOTHER copy.
601  d_container->add_var(bt);
602  // So we need to delete btp or else it leaks
603  delete btp;
604  btp = 0;
605  }
606  else {
607  vars.push_back(btp);
608  }
609 }
610 
613 void
615 {
616  if (!bt)
617  throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
618 #if 0
619  //FIXME There's no longer a DAP2 and DAP4 DDS
620  if (bt->is_dap4_only_type())
621  throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
622 #endif
623 
624  DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
625 
626  if (d_container) {
627  d_container->add_var_nocopy(bt);
628  }
629  else {
630  vars.push_back(bt);
631  }
632 }
633 
634 
641 void
642 DDS::del_var(const string &n)
643 {
644  if( d_container )
645  {
646  d_container->del_var( n ) ;
647  return ;
648  }
649 
650  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
651  if ((*i)->name() == n) {
652  BaseType *bt = *i ;
653  vars.erase(i) ;
654  delete bt ; bt = 0;
655  return;
656  }
657  }
658 }
659 
664 void
665 DDS::del_var(Vars_iter i)
666 {
667  if (i != vars.end()) {
668  BaseType *bt = *i ;
669  vars.erase(i) ;
670  delete bt ; bt = 0;
671  }
672 }
673 
680 void
681 DDS::del_var(Vars_iter i1, Vars_iter i2)
682 {
683  for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
684  BaseType *bt = *i_tmp ;
685  delete bt ; bt = 0;
686  }
687  vars.erase(i1, i2) ;
688 }
689 
697 BaseType *
698 DDS::var(const string &n, BaseType::btp_stack &s)
699 {
700  return var(n, &s);
701 }
721 BaseType *
722 DDS::var(const string &n, BaseType::btp_stack *s)
723 {
724  string name = www2id(n);
725  if( d_container )
726  return d_container->var( name, false, s ) ;
727 
728  BaseType *v = exact_match(name, s);
729  if (v)
730  return v;
731 
732  return leaf_match(name, s);
733 }
734 
735 BaseType *
736 DDS::leaf_match(const string &n, BaseType::btp_stack *s)
737 {
738  DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
739 
740  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
741  BaseType *btp = *i;
742  DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->d_name() << endl);
743  // Look for the d_name in the dataset's top-level
744  if (btp->name() == n) {
745  DBG(cerr << "Found " << n << " in: " << btp->d_name() << endl);
746  return btp;
747  }
748 
749  if (btp->is_constructor_type()) {
750  BaseType *found = btp->var(n, false, s);
751  if (found) {
752  DBG(cerr << "Found " << n << " in: " << btp->d_name() << endl);
753  return found;
754  }
755  }
756 #if STRUCTURE_ARRAY_SYNTAX_OLD
757  if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
758  s->push(btp);
759  BaseType *found = btp->var()->var(n, false, s);
760  if (found) {
761  DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl);
762  return found;
763  }
764  }
765 #endif
766  }
767 
768  return 0; // It is not here.
769 }
770 
771 BaseType *
772 DDS::exact_match(const string &name, BaseType::btp_stack *s)
773 {
774  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
775  BaseType *btp = *i;
776  DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl);
777  // Look for the d_name in the current ctor type or the top level
778  if (btp->name() == name) {
779  DBG2(cerr << "Found " << d_name << " in: " << btp << endl);
780  return btp;
781  }
782  }
783 
784  string::size_type dot_pos = name.find(".");
785  if (dot_pos != string::npos) {
786  string aggregate = name.substr(0, dot_pos);
787  string field = name.substr(dot_pos + 1);
788 
789  BaseType *agg_ptr = var(aggregate, s);
790  if (agg_ptr) {
791  DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
792  return agg_ptr->var(field, true, s);
793  }
794  else
795  return 0; // qualified names must be *fully* qualified
796  }
797 
798  return 0; // It is not here.
799 }
800 
801 
804 DDS::Vars_iter
806 {
807  return vars.begin();
808 }
809 
810 DDS::Vars_riter
812 {
813  return vars.rbegin();
814 }
815 
816 DDS::Vars_iter
818 {
819  return vars.end() ;
820 }
821 
822 DDS::Vars_riter
824 {
825  return vars.rend() ;
826 }
827 
831 DDS::Vars_iter
833 {
834  return vars.begin() + i;
835 }
836 
840 BaseType *
842 {
843  return *(vars.begin() + i);
844 }
845 
850 void
851 DDS::insert_var(Vars_iter i, BaseType *ptr)
852 {
853 #if 0
854  if (ptr->is_dap4_only_type())
855  throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
856 #endif
857  vars.insert(i, ptr->ptr_duplicate());
858 }
859 
867 void
869 {
870 #if 0
871  if (ptr->is_dap4_only_type())
872  throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
873 #endif
874  vars.insert(i, ptr);
875 }
876 
878 int
880 {
881  return vars.size();
882 }
883 
884 void
885 DDS::timeout_on()
886 {
887 #if USE_LOCAL_TIMEOUT_SCHEME
888 #ifndef WIN32
889  alarm(d_timeout);
890 #endif
891 #endif
892 }
893 
894 void
895 DDS::timeout_off()
896 {
897 #if USE_LOCAL_TIMEOUT_SCHEME
898 #ifndef WIN32
899  // Old behavior commented out. I think it is an error to change the value
900  // of d_timeout. The way this will likely be used is to set the timeout
901  // value once and then 'turn on' or turn off' that timeout as the situation
902  // dictates. The initeded use for the DDS timeout is so that timeouts for
903  // data responses will include the CPU resources needed to build the response
904  // but not the time spent transmitting the response. This may change when
905  // more parallelism is added to the server... These methods are called from
906  // BESDapResponseBuilder in bes/dap. jhrg 12/22/15
907 
908  // d_timeout = alarm(0);
909 
910  alarm(0);
911 #endif
912 #endif
913 }
914 
915 void
916 DDS::set_timeout(int)
917 {
918 #if USE_LOCAL_TIMEOUT_SCHEME
919  // Has no effect under win32
920  d_timeout = t;
921 #endif
922 }
923 
924 int
925 DDS::get_timeout()
926 {
927 #if USE_LOCAL_TIMEOUT_SCHEME
928  // Has to effect under win32
929  return d_timeout;
930 #endif
931  return 0;
932 }
933 
935 void
937 {
938  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
939  if ((*i)->type() == dods_sequence_c)
940  dynamic_cast<Sequence&>(**i).set_leaf_sequence();
941  else if ((*i)->type() == dods_structure_c)
942  dynamic_cast<Structure&>(**i).set_leaf_sequence();
943  }
944 }
945 
947 void
948 DDS::parse(string fname)
949 {
950  FILE *in = fopen(fname.c_str(), "r");
951 
952  if (!in) {
953  throw Error(cannot_read_file, "Could not open: " + fname);
954  }
955 
956  try {
957  parse(in);
958  fclose(in);
959  }
960  catch (Error &e) {
961  fclose(in);
962  throw ;
963  }
964 }
965 
966 
968 void
969 DDS::parse(int fd)
970 {
971 #ifdef WIN32
972  int new_fd = _dup(fd);
973 #else
974  int new_fd = dup(fd);
975 #endif
976 
977  if (new_fd < 0)
978  throw InternalErr(__FILE__, __LINE__, "Could not access file.");
979  FILE *in = fdopen(new_fd, "r");
980 
981  if (!in) {
982  throw InternalErr(__FILE__, __LINE__, "Could not access file.");
983  }
984 
985  try {
986  parse(in);
987  fclose(in);
988  }
989  catch (Error &e) {
990  fclose(in);
991  throw ;
992  }
993 }
994 
1001 void
1002 DDS::parse(FILE *in)
1003 {
1004  if (!in) {
1005  throw InternalErr(__FILE__, __LINE__, "Null input stream.");
1006  }
1007 
1008  void *buffer = dds_buffer(in);
1009  dds_switch_to_buffer(buffer);
1010 
1011  parser_arg arg(this);
1012 
1013  bool status = ddsparse(&arg) == 0;
1014 
1015  dds_delete_buffer(buffer);
1016 
1017  DBG2(cout << "Status from parser: " << status << endl);
1018 
1019  // STATUS is the result of the parser function; if a recoverable error
1020  // was found it will be true but arg.status() will be false.
1021  if (!status || !arg.status()) {// Check parse result
1022  if (arg.error())
1023  throw *arg.error();
1024  }
1025 }
1026 
1028 void
1029 DDS::print(FILE *out)
1030 {
1031  ostringstream oss;
1032  print(oss);
1033  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1034 }
1035 
1037 void
1038 DDS::print(ostream &out)
1039 {
1040  out << "Dataset {\n" ;
1041 
1042  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1043  (*i)->print_decl(out) ;
1044  }
1045 
1046  out << "} " << id2www(d_name) << ";\n" ;
1047 
1048  return ;
1049 }
1050 
1060 void
1061 DDS::print_das(ostream &out)
1062 {
1063  out << "Attributes {\n" ;
1064 
1065  d_attr.print(out, " ");
1066  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1067  (*i)->get_attr_table().print(out, " ");
1068  }
1069 
1070  out << "}\n" ;
1071 }
1072 
1083 void
1085 {
1086  ostringstream oss;
1087  print_constrained(oss);
1088  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1089 }
1090 
1101 void
1103 {
1104  out << "Dataset {\n" ;
1105 
1106  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
1107  // for each variable, indent with four spaces, print a trailing
1108  // semicolon, do not print debugging information, print only
1109  // variables in the current projection.
1110  (*i)->print_decl(out, " ", true, false, true) ;
1111  }
1112 
1113  out << "} " << id2www(d_name) << ";\n" ;
1114 
1115  return;
1116 }
1117 
1129 void
1130 DDS::print_xml(FILE *out, bool constrained, const string &blob)
1131 {
1132  ostringstream oss;
1133  print_xml_writer(oss, constrained, blob);
1134  fwrite(oss.str().data(), 1, oss.str().length(), out);
1135 }
1136 
1148 void
1149 DDS::print_xml(ostream &out, bool constrained, const string &blob)
1150 {
1151  print_xml_writer(out, constrained, blob);
1152 }
1153 
1154 class VariablePrintXMLWriter : public unary_function<BaseType *, void>
1155 {
1156  XMLWriter &d_xml;
1157  bool d_constrained;
1158 public:
1159  VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
1160  : d_xml(xml), d_constrained(constrained)
1161  {}
1162  void operator()(BaseType *bt)
1163  {
1164  bt->print_xml_writer(d_xml, d_constrained);
1165  }
1166 };
1167 
1184 void
1185 DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
1186 {
1187  XMLWriter xml(" ");
1188 
1189  // Stamp and repeat for these sections; trying to economize is makes it
1190  // even more confusing
1191  if (get_dap_major() >= 4) {
1192  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
1193  throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
1194  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1195  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1196 
1197  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)get_dap_version().c_str()) < 0)
1198  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1199 
1200  if (!get_request_xml_base().empty()) {
1201  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1202  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1203 
1204  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1205  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1206  }
1207  if (!get_namespace().empty()) {
1208  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)get_namespace().c_str()) < 0)
1209  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1210  }
1211  }
1212  else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
1213  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1214  throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1215  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1216  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1217  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1218  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1219 
1220  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
1221  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1222 
1223  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
1224  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
1225 
1226  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
1227  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
1228 
1229  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1230  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1231  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
1232  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
1233 
1234  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
1235  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1236 
1237  if (!get_request_xml_base().empty()) {
1238  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
1239  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1240 
1241  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
1242  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1243  }
1244  }
1245  else { // dap2
1246  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
1247  throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
1248  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
1249  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1250  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
1251  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1252 
1253  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
1254  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1255 
1256  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
1257  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1258  }
1259 
1260  // Print the global attributes
1261  d_attr.print_xml_writer(xml);
1262 
1263  // Print each variable
1264  for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1265 
1266  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1267  // the CID of the MIME part that holds the data. For DAP2 (which includes
1268  // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
1269  // given.
1270  if (get_dap_major() >= 4) {
1271  if (!blob.empty()) {
1272  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1273  throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1274  string cid = "cid:" + blob;
1275  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1276  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1277  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1278  throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1279  }
1280  }
1281  else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
1282  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1283  throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1284  string cid = "cid:" + blob;
1285  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1286  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1287  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1288  throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1289  }
1290  else { // dap2
1291  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
1292  throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
1293  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0)
1294  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1295  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1296  throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
1297  }
1298 
1299  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1300  throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
1301 
1302  out << xml.get_doc();// << ends;// << endl;
1303 }
1304 
1317 void
1318 DDS::print_dmr(ostream &out, bool constrained)
1319 {
1320  if (get_dap_major() < 4)
1321  throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4");
1322 
1323  XMLWriter xml(" ");
1324 
1325  // DAP4 wraps a dataset in a top-level Group element.
1326  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
1327  throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
1328 
1329  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
1330  (const xmlChar*) c_xml_namespace.c_str()) < 0)
1331  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
1332 
1333  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
1334  < 0)
1335  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
1336 
1337  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
1338  (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
1339  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
1340 
1341  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns",
1342  (const xmlChar*) get_namespace().c_str()) < 0)
1343  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
1344 
1345  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",
1346  (const xmlChar*) get_dap_version().c_str()) < 0)
1347  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1348 
1349  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0)
1350  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
1351 
1352  if (!get_request_xml_base().empty()) {
1353  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
1354  (const xmlChar*) get_request_xml_base().c_str()) < 0)
1355  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
1356  }
1357 
1358  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0)
1359  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
1360 
1361  // Print the global attributes
1362  d_attr.print_xml_writer(xml);
1363 
1364  // Print each variable
1365  for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
1366 
1367 #if 0
1368  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1369  // the CID of the MIME part that holds the data. For DAP2 (which includes
1370  // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
1371  // given.
1372  if (get_dap_major() >= 4) {
1373  if (!blob.empty()) {
1374  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
1375  throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
1376  string cid = "cid:" + blob;
1377  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
1378  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
1379  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1380  throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
1381  }
1382  }
1383 #endif
1384 
1385  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
1386  throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
1387 
1388  out << xml.get_doc();
1389 }
1390 
1391 // Used by DDS::send() when returning data from a function call.
1406 bool
1408 {
1409  // The dataset must have a d_name
1410  if (d_name == "") {
1411  cerr << "A dataset must have a d_name" << endl;
1412  return false;
1413  }
1414 
1415  string msg;
1416  if (!unique_names(vars, d_name, "Dataset", msg))
1417  return false;
1418 
1419  if (all)
1420  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1421  if (!(*i)->check_semantics(msg, true))
1422  return false;
1423 
1424  return true;
1425 }
1426 
1452 bool
1453 DDS::mark(const string &n, bool state)
1454 {
1455  // TODO use auto_ptr
1456  BaseType::btp_stack *s = new BaseType::btp_stack;
1457 
1458  DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1459 
1460  BaseType *variable = var(n, s);
1461  if (!variable) {
1462  DBG2(cerr << "Could not find variable " << n << endl);
1463  delete s; s = 0;
1464  return false;
1465  }
1466  variable->set_send_p(state);
1467 
1468  DBG2(cerr << "DDS::mark: Set variable " << variable->d_name()
1469  << " (a " << variable->type_name() << ")" << endl);
1470 
1471  // Now check the btp_stack and run BaseType::set_send_p for every
1472  // BaseType pointer on the stack. Using BaseType::set_send_p() will
1473  // set the property for a Constructor but not its contained variables
1474  // which preserves the semantics of projecting just one field.
1475  while (!s->empty()) {
1476  s->top()->BaseType::set_send_p(state);
1477 
1478  DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name()
1479  << " (a " << s->top()->type_name() << ")" << endl);
1480  // FIXME get_parent() hosed?
1481 #if 1
1482  string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1483  string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1484  DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1485 #endif
1486  s->pop();
1487  }
1488 
1489  delete s ; s = 0;
1490 
1491  return true;
1492 }
1493 
1499 void
1500 DDS::mark_all(bool state)
1501 {
1502  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1503  (*i)->set_send_p(state);
1504 }
1505 
1513 void
1514 DDS::dump(ostream &strm) const
1515 {
1516  strm << DapIndent::LMarg << "DDS::dump - ("
1517  << (void *)this << ")" << endl ;
1518  DapIndent::Indent() ;
1519  strm << DapIndent::LMarg << "d_name: " << d_name << endl ;
1520  strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1521  strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1522  strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1523  strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1524 
1525  strm << DapIndent::LMarg << "global attributes:" << endl ;
1526  DapIndent::Indent() ;
1527  d_attr.dump(strm) ;
1528  DapIndent::UnIndent() ;
1529 
1530  if (vars.size()) {
1531  strm << DapIndent::LMarg << "vars:" << endl ;
1532  DapIndent::Indent() ;
1533  Vars_citer i = vars.begin() ;
1534  Vars_citer ie = vars.end() ;
1535  for (; i != ie; i++) {
1536  (*i)->dump(strm) ;
1537  }
1538  DapIndent::UnIndent() ;
1539  }
1540  else {
1541  strm << DapIndent::LMarg << "vars: none" << endl ;
1542  }
1543 
1544  DapIndent::UnIndent() ;
1545 }
1546 
1547 } // namespace libdap
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:265
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:1029
virtual Attr_iter attr_end()
Definition: AttrTable.cc:718
void insert_var_nocopy(Vars_iter i, BaseType *ptr)
Definition: DDS.cc:868
Contains the attributes for a dataset.
Definition: AttrTable.h:142
Vars_iter get_vars_iter(int i)
Get an iterator.
Definition: DDS.cc:832
void insert_var(Vars_iter i, BaseType *ptr)
Insert a variable before the referenced element.
Definition: DDS.cc:851
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:805
virtual void print_xml_writer(XMLWriter &xml, bool constrained=false)
Definition: BaseType.cc:1055
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:237
DDS(BaseTypeFactory *factory, const string &name="")
Definition: DDS.cc:205
int get_request_size(bool constrained)
Get the estimated response size.
Definition: DDS.cc:566
STL namespace.
BaseType * var(const string &n, BaseType::btp_stack &s)
Definition: DDS.cc:698
virtual void transfer_attributes(DAS *das)
Definition: DDS.cc:287
string filename() const
Definition: DDS.cc:388
void print_xml(FILE *out, bool constrained, const string &blob="")
Definition: DDS.cc:1130
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition: DDS.cc:1185
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:614
Holds a structure (aggregate) type.
Definition: Structure.h:83
Vars_riter var_rend()
Return a reverse iterator.
Definition: DDS.cc:823
string get_dataset_name() const
Definition: DDS.cc:357
int num_var()
Returns the number of variables in the DDS.
Definition: DDS.cc:879
bool mark(const string &name, bool state)
Mark the send_p flag of the named variable to state.
Definition: DDS.cc:1453
A class for software fault reporting.
Definition: InternalErr.h:64
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition: DDS.cc:948
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:679
virtual bool is_vector_type() const
Returns true if the instance is a vector (i.e., array) type variable.
Definition: BaseType.cc:347
virtual void set_send_p(bool state)
Definition: BaseType.cc:513
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
Definition: BaseType.cc:357
void mark_all(bool state)
Definition: DDS.cc:1500
void print_das(ostream &out)
Definition: DDS.cc:1061
void print_dmr(ostream &out, bool constrained)
Definition: DDS.cc:1318
virtual AttrTable & get_attr_table()
Definition: DDS.cc:373
BaseType * get_var_index(int i)
Get a variable.
Definition: DDS.cc:841
bool check_semantics(bool all=false)
Check the semantics of each of the variables represented in the DDS.
Definition: DDS.cc:1407
Structure * container()
Definition: DDS.cc:548
int get_dap_major() const
Get the DAP major version as sent by the client.
Definition: DDS.h:261
string get_request_xml_base() const
Get the URL that will return this DDS/DDX/DataThing.
Definition: DDS.h:279
string container_name()
Definition: DDS.cc:512
string get_error_message() const
Definition: Error.cc:276
virtual AttrTable * get_top_level_attributes()
Returns the top most set of attributes.
Definition: DAS.h:166
virtual void dump(ostream &strm) const
dumps information about this object
Definition: DDS.cc:1514
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:710
virtual string container_name() const
Returns the name of the current attribute container when multiple files used to build this DAS...
Definition: DAS.h:149
virtual BaseType * ptr_duplicate()=0
string get_namespace() const
Get the namespace associated with the DDS - likely set only by DDX responses.
Definition: DDS.h:285
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:817
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition: DDS.cc:936
void set_dap_minor(int p)
Definition: DDS.cc:424
void set_dataset_name(const string &n)
Definition: DDS.cc:364
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
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:642
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:324
Vars_riter var_rbegin()
Return a reverse iterator.
Definition: DDS.cc:811
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:121
A class for error processing.
Definition: Error.h:90
int get_dap_minor() const
Get the DAP minor version as sent by the client.
Definition: DDS.h:263
void set_dap_major(int p)
Definition: DDS.cc:405
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition: DDS.cc:1084
void set_dap_version(const string &version_string="2.0")
Definition: DDS.cc:441
string id2www(string in, const string &allowable)
Definition: escaping.cc:153
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:587