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 24370 2011-03-28 16:21:32Z 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 #include "Keywords2.h"
67 
68 #include "parser.h"
69 #include "debug.h"
70 #include "util.h"
71 
72 #include "Byte.h"
73 #include "Int16.h"
74 #include "UInt16.h"
75 #include "Int32.h"
76 #include "UInt32.h"
77 #include "Float32.h"
78 #include "Float64.h"
79 #include "Str.h"
80 #include "Url.h"
81 #include "Array.h"
82 #include "Structure.h"
83 #include "Sequence.h"
84 #include "Grid.h"
85 
86 #include "escaping.h"
87 
88 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
89 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
90 
91 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
92 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
93 
94 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
95 
96 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
97 
98 using namespace std;
99 
100 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
101 int ddsparse(void *arg);
102 
103 // Glue for the DDS parser defined in dds.lex
104 void dds_switch_to_buffer(void *new_buffer);
105 void dds_delete_buffer(void * buffer);
106 void *dds_buffer(FILE *fp);
107 
108 namespace libdap {
109 
110 void
111 DDS::duplicate(const DDS &dds)
112 {
113  DBG(cerr << "Entering DDS::duplicate... " <<endl);
114  name = dds.name;
115  d_filename = dds.d_filename;
116  d_container_name = dds.d_container_name;
117  d_timeout = dds.d_timeout;
118  d_attr = dds.d_attr;
119 
120  d_factory = dds.d_factory;
121  d_container = dds.d_container;
122  d_dap_major = dds.d_dap_major;
123  d_dap_minor = dds.d_dap_minor;
124 
125  d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
126 
127  DDS &dds_tmp = const_cast<DDS &>(dds);
128 
129  // copy the things pointed to by the list, not just the pointers
130  for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
131  add_var(*i); // add_var() dups the BaseType.
132  }
133 }
134 
145 DDS::DDS(BaseTypeFactory *factory, const string &n)
146 
147  : d_factory(factory), name(n), d_container(0),
148  d_dap_major(2), d_dap_minor(0),
149  d_request_xml_base(""), d_timeout(0), d_keywords()
150 {
151  DBG(cerr << "Building a DDS with client major/minor: "
152  << d_dap_major << "." << d_dap_minor << endl);
153 }
154 
156 DDS::DDS(const DDS &rhs) : DapObj()
157 {
158  DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
159  duplicate(rhs);
160  DBG(cerr << " bye." << endl);
161 }
162 
164 {
165  // delete all the variables in this DDS
166  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
167  BaseType *btp = *i ;
168  delete btp ; btp = 0;
169  }
170 }
171 
172 DDS &
173 DDS::operator=(const DDS &rhs)
174 {
175  DBG(cerr << "Entering DDS::operator= ..." << endl);
176  if (this == &rhs)
177  return *this;
178 
179  duplicate(rhs);
180 
181  DBG(cerr << " bye." << endl);
182  return *this;
183 }
184 
198 void
200 {
201  // If there is a container set in the DDS then get the container from
202  // the DAS. If they are not the same container, then throw an exception
203  // (should be working on the same container). If the container does not
204  // exist in the DAS, then throw an exception
205  if( d_container ) {
206  if( das->container_name() != d_container_name )
207  throw InternalErr(__FILE__, __LINE__, "Error transferring attributes: working on a container in dds, but not das" ) ;
208  }
209 
210  // Give each variable a chance to claim its attributes.
211  AttrTable *top_level = das->get_top_level_attributes() ;
212 
213  Vars_iter var = var_begin();
214  while (var != var_end()) {
215  (*var)->transfer_attributes(top_level);
216  var++;
217  }
218 
219  // Now we transfer all of the attributes still marked as global to the
220  // global container in the DDS.
221 
222  AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
223  while (at_cont_p != top_level->attr_end()) {
224  // In truth, all of the top level attributes should be containers, but
225  // this test handles the abnormal case where somehow someone makes a
226  // top level attribute that is not a container by silently dropping it.
227  if ((*at_cont_p)->type == Attr_container
228  && (*at_cont_p)->attributes->is_global_attribute()) {
229  DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl);
230  // copy the source container so that the DAS passed in can be
231  // deleted after calling htis method.
232  AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
233  d_attr.append_container(at, at->get_name());
234  }
235 
236  at_cont_p++;
237  }
238 }
239 
247 
249 string
251 {
252  return name;
253 }
254 
256 void
257 DDS::set_dataset_name(const string &n)
258 {
259  name = n;
260 }
261 
263 
265 AttrTable &
267 {
268  return d_attr;
269 }
270 
280 string
282 {
283  return d_filename;
284 }
285 
287 void
288 DDS::filename(const string &fn)
289 {
290  d_filename = fn;
291 }
293 
294 void
296 {
297  d_dap_major = p;
298 
299  // This works because regardless of the order set_dap_major and set_dap_minor
300  // are called, once they both are called, the value in the string is
301  // correct. I protect against negative numbers because that would be
302  // nonsensical.
303  if (d_dap_minor >= 0) {
304  ostringstream oss;
305  oss << d_dap_major << "." << d_dap_minor;
306  d_dap_version = oss.str();
307  }
308 }
309 
310 void
312 {
313  d_dap_minor = p;
314 
315  if (d_dap_major >= 0) {
316  ostringstream oss;
317  oss << d_dap_major << "." << d_dap_minor;
318  d_dap_version = oss.str();
319  }
320 }
321 
328 void
329 DDS::set_dap_version(const string &version_string)
330 {
331  istringstream iss(version_string);
332 
333  int major = -1, minor = -1;
334  char dot;
335  if (!iss.eof() && !iss.fail())
336  iss >> major;
337  if (!iss.eof() && !iss.fail())
338  iss >> dot;
339  if (!iss.eof() && !iss.fail())
340  iss >> minor;
341 
342  DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
343 #if 0
344  if (major == -1 || minor == -1)
345  throw Error("Could not parse the client dap (XDAP-Accept header) value");
346 #endif
347 
348  d_dap_version = version_string;
349 
350  set_dap_major(major == -1 ? 2 : major);
351  set_dap_minor(minor == -1 ? 0 : minor);
352 }
353 
361 void
363 {
364  int major = d;
365  int minor = (d-major)*10;
366 
367  DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
368 
369  ostringstream oss;
370  oss << major << "." << minor;
371  d_dap_version = oss.str();
372 
373  set_dap_major(major);
374  set_dap_minor(minor);
375 }
376 
386 string
388 {
389  return d_container_name;
390 }
391 
394 void
395 DDS::container_name(const string &cn)
396 {
397  // we want to search the DDS for the top level structure with the given
398  // name. Set the container to null so that we don't search some previous
399  // container.
400  d_container = 0 ;
401  if( !cn.empty() )
402  {
403  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
404  if( !d_container )
405  {
406  // create a structure for this container. Calling add_var
407  // while_container is null will add the new structure to DDS and
408  // not some sub structure. Adding the new structure makes a copy
409  // of it. So after adding it, go get it and set d_container.
410  Structure *s = new Structure( cn ) ;
411  add_var( s ) ;
412  delete s ;
413  s = 0 ;
414  d_container = dynamic_cast<Structure *>( var( cn ) ) ;
415  }
416  }
417  d_container_name = cn;
418 
419 }
420 
422 Structure *
424 {
425  return d_container ;
426 }
427 
429 
435 void
437 {
438  if (!bt)
439  throw InternalErr(__FILE__, __LINE__,
440  "Trying to add a BaseType object with a NULL pointer.");
441 
442  DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
443 
444  BaseType *btp = bt->ptr_duplicate();
445  DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
446  if( d_container )
447  {
448  // Mem leak fix [mjohnson nov 2009]
449  // Structure::add_var() creates ANOTHER copy.
450  d_container->add_var( bt ) ;
451  // So we need to delete btp or else it leaks
452  delete btp; btp = 0;
453  }
454  else
455  {
456  vars.push_back(btp);
457  }
458 }
459 
466 void
467 DDS::del_var(const string &n)
468 {
469  if( d_container )
470  {
471  d_container->del_var( n ) ;
472  return ;
473  }
474 
475  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
476  if ((*i)->name() == n) {
477  BaseType *bt = *i ;
478  vars.erase(i) ;
479  delete bt ; bt = 0;
480  return;
481  }
482  }
483 }
484 
489 void
491 {
492  if (i != vars.end()) {
493  BaseType *bt = *i ;
494  vars.erase(i) ;
495  delete bt ; bt = 0;
496  }
497 }
498 
505 void
507 {
508  for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
509  BaseType *bt = *i_tmp ;
510  delete bt ; bt = 0;
511  }
512  vars.erase(i1, i2) ;
513 }
514 
522 BaseType *
523 DDS::var(const string &n, BaseType::btp_stack &s)
524 {
525  return var(n, &s);
526 }
546 BaseType *
547 DDS::var(const string &n, BaseType::btp_stack *s)
548 {
549  string name = www2id(n);
550  if( d_container )
551  return d_container->var( name, false, s ) ;
552 
553  BaseType *v = exact_match(name, s);
554  if (v)
555  return v;
556 
557  return leaf_match(name, s);
558 }
559 
560 BaseType *
562 {
563  DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
564 
565  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
566  BaseType *btp = *i;
567  DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
568  // Look for the name in the dataset's top-level
569  if (btp->name() == n) {
570  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
571  return btp;
572  }
573 
574  if (btp->is_constructor_type()) {
575  BaseType *found = btp->var(n, false, s);
576  if (found) {
577  DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
578  return found;
579  }
580  }
581 #if STRUCTURE_ARRAY_SYNTAX_OLD
582  if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
583  s->push(btp);
584  BaseType *found = btp->var()->var(n, false, s);
585  if (found) {
586  DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
587  return found;
588  }
589  }
590 #endif
591  }
592 
593  return 0; // It is not here.
594 }
595 
596 BaseType *
597 DDS::exact_match(const string &name, BaseType::btp_stack *s)
598 {
599  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
600  BaseType *btp = *i;
601  DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
602  // Look for the name in the current ctor type or the top level
603  if (btp->name() == name) {
604  DBG2(cerr << "Found " << name << " in: " << btp << endl);
605  return btp;
606  }
607  }
608 
609  string::size_type dot_pos = name.find(".");
610  if (dot_pos != string::npos) {
611  string aggregate = name.substr(0, dot_pos);
612  string field = name.substr(dot_pos + 1);
613 
614  BaseType *agg_ptr = var(aggregate, s);
615  if (agg_ptr) {
616  DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
617  return agg_ptr->var(field, true, s);
618  }
619  else
620  return 0; // qualified names must be *fully* qualified
621  }
622 
623  return 0; // It is not here.
624 }
625 
626 
631 {
632  return vars.begin();
633 }
634 
637 {
638  return vars.rbegin();
639 }
640 
643 {
644  return vars.end() ;
645 }
646 
649 {
650  return vars.rend() ;
651 }
652 
658 {
659  return vars.begin() + i;
660 }
661 
665 BaseType *
667 {
668  return *(vars.begin() + i);
669 }
670 
672 int
674 {
675  return vars.size();
676 }
677 
678 void
680 {
681 #ifndef WIN32
682  alarm(d_timeout);
683 #endif
684 }
685 
686 void
688 {
689 #ifndef WIN32
690  d_timeout = alarm(0);
691 #endif
692 }
693 
694 void
696 {
697  // Has no effect under win32
698  d_timeout = t;
699 }
700 
701 int
703 {
704  // Has to effect under win32
705  return d_timeout;
706 }
707 
709 void
711 {
712  for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
713  if ((*i)->type() == dods_sequence_c)
714  dynamic_cast<Sequence&>(**i).set_leaf_sequence();
715  else if ((*i)->type() == dods_structure_c)
716  dynamic_cast<Structure&>(**i).set_leaf_sequence();
717  }
718 }
719 
721 void
722 DDS::parse(string fname)
723 {
724  FILE *in = fopen(fname.c_str(), "r");
725 
726  if (!in) {
727  throw Error(cannot_read_file, "Could not open: " + fname);
728  }
729 
730  try {
731  parse(in);
732  fclose(in);
733  }
734  catch (Error &e) {
735  fclose(in);
736  throw ;
737  }
738 }
739 
740 
742 void
743 DDS::parse(int fd)
744 {
745 #ifdef WIN32
746  FILE *in = fdopen(_dup(fd), "r");
747 #else
748  FILE *in = fdopen(dup(fd), "r");
749 #endif
750 
751  if (!in) {
752  throw InternalErr(__FILE__, __LINE__, "Could not access file.");
753  }
754 
755  try {
756  parse(in);
757  fclose(in);
758  }
759  catch (Error &e) {
760  fclose(in);
761  throw ;
762  }
763 }
764 
771 void
772 DDS::parse(FILE *in)
773 {
774  if (!in) {
775  throw InternalErr(__FILE__, __LINE__, "Null input stream.");
776  }
777 
778  void *buffer = dds_buffer(in);
779  dds_switch_to_buffer(buffer);
780 
781  parser_arg arg(this);
782 
783  bool status = ddsparse((void *) & arg) == 0;
784 
785  dds_delete_buffer(buffer);
786 
787  DBG2(cout << "Status from parser: " << status << endl);
788 
789  // STATUS is the result of the parser function; if a recoverable error
790  // was found it will be true but arg.status() will be false.
791  if (!status || !arg.status()) {// Check parse result
792  if (arg.error())
793  throw *arg.error();
794  }
795 }
796 
797 #if FILE_METHODS
798 
799 void
800 DDS::print(FILE *out)
801 {
802 #if 0
803  ostringstream oss;
804  print(oss);
805 
806  fwrite(oss.str().c_str(), oss.str().length(), 1, out);
807 #else
808  fprintf(out, "Dataset {\n") ;
809 
810  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
811  (*i)->print_decl(out) ;
812  }
813 
814  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
815 
816  return ;
817 #endif
818 }
819 #endif
820 
822 void
823 DDS::print(ostream &out)
824 {
825  out << "Dataset {\n" ;
826 
827  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
828  (*i)->print_decl(out) ;
829  }
830 
831  out << "} " << id2www(name) << ";\n" ;
832 
833  return ;
834 }
835 
836 #if FILE_METHODS
837 
847 void
849 {
850  fprintf(out, "Dataset {\n") ;
851 
852  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
853  // for each variable, indent with four spaces, print a trailing
854  // semicolon, do not print debugging information, print only
855  // variables in the current projection.
856  (*i)->print_decl(out, " ", true, false, true) ;
857  }
858 
859  fprintf(out, "} %s;\n", id2www(name).c_str()) ;
860 
861  return;
862 }
863 #endif
864 
875 void
877 {
878  out << "Dataset {\n" ;
879 
880  for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
881  // for each variable, indent with four spaces, print a trailing
882  // semicolon, do not print debugging information, print only
883  // variables in the current projection.
884  (*i)->print_decl(out, " ", true, false, true) ;
885  }
886 
887  out << "} " << id2www(name) << ";\n" ;
888 
889  return;
890 }
891 
892 #if FILE_METHODS
893 class VariablePrintXML : public unary_function<BaseType *, void>
894 {
895  FILE *d_out;
896  bool d_constrained;
897 public:
898  VariablePrintXML(FILE *out, bool constrained)
899  : d_out(out), d_constrained(constrained)
900  {}
901  void operator()(BaseType *bt)
902  {
903  bt->print_xml(d_out, " ", d_constrained);
904  }
905 };
906 
917 void
918 DDS::print_xml(FILE *out, bool constrained, const string &blob)
919 {
920  fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
921 
922  fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
923 
924  fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
925 
926  fprintf(out,"method=\"FILE*\"\n");
927  fprintf(out, "dap_major=\"%d\"\n", get_dap_major());
928  fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor());
929 
930  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
931  // this at some point... jhrg
932  if (get_dap_major() == 3 && get_dap_minor() == 2) {
933  fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
934 
935  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
937  }
938  else {
939  fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
940  fprintf(out, "xsi:schemaLocation=\"%s %s\">\n\n",
942  }
943 
944 
945  d_attr.print_xml(out, " ", constrained);
946 
947  fprintf(out, "\n");
948 
949  for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
950 
951  fprintf(out, "\n");
952 
953  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
954  // the same. jhrg
955  if (get_dap_major() == 2 && get_dap_minor() == 0) {
956  fprintf(out, " <dataBLOB href=\"\"/>\n");
957  }
958  else if (!blob.empty()
959  && (get_dap_major() == 3 && get_dap_minor() >= 2)
960  || get_dap_major() >= 4) {
961  fprintf(out, " <blob href=\"cid:%s\"/>\n", blob.c_str());
962  }
963 
964 
965  fprintf(out, "</Dataset>\n");
966 }
967 #endif
968 
969 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
970 {
971  ostream &d_out;
972  bool d_constrained;
973 public:
974  VariablePrintXMLStrm(ostream &out, bool constrained)
975  : d_out(out), d_constrained(constrained)
976  {}
977  void operator()(BaseType *bt)
978  {
979  bt->print_xml(d_out, " ", d_constrained);
980  }
981 };
982 
993 void
994 DDS::print_xml(ostream &out, bool constrained, const string &blob)
995 {
996  out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
997 
998  out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
999 
1000  out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
1001 
1002  // Are we responding to a 3.2 or 2.0 client? We will have to improve on
1003  // this at some point... jhrg
1004  if (get_dap_major() == 3 && get_dap_minor() == 2) {
1005  out << "xsi:schemaLocation=\"" << c_dap32_namespace
1006  << " " << c_default_dap32_schema_location << "\"\n" ;
1007 
1008  out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
1009  out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
1010 
1011  out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
1012  out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
1013 
1014  out << "dapVersion=\"" << get_dap_major() << "."
1015  << get_dap_minor() << "\"";
1016 
1017  if (!get_request_xml_base().empty()) {
1018  out << "\n";
1019  out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
1020  out << "xml:base=\"" << get_request_xml_base() << "\"";
1021  }
1022 
1023  // Close the Dataset element
1024  out << ">\n";
1025  }
1026  else {
1027  out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
1028  out << "xsi:schemaLocation=\"" << c_dap20_namespace
1029  << " " << c_default_dap20_schema_location << "\">\n\n" ;
1030  }
1031 
1032  d_attr.print_xml(out, " ", constrained);
1033 
1034  out << "\n" ;
1035 
1036  for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
1037 
1038  out << "\n" ;
1039 
1040  // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
1041  // the same.
1042  // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
1043  // actually the CID of the MIME part that holds the data.
1044  if (get_dap_major() == 2 && get_dap_minor() == 0) {
1045  out << " <dataBLOB href=\"\"/>\n" ;
1046  }
1047  else if (!blob.empty()
1048  && (get_dap_major() == 3 && get_dap_minor() >= 2)
1049  || get_dap_major() >= 4) {
1050  out << " <blob href=\"cid:" << blob << "\"/>\n";
1051  }
1052 
1053  out << "</Dataset>\n" ;
1054 }
1055 
1056 // Used by DDS::send() when returning data from a function call.
1071 bool
1073 {
1074  // The dataset must have a name
1075  if (name == "") {
1076  cerr << "A dataset must have a name" << endl;
1077  return false;
1078  }
1079 
1080  string msg;
1081  if (!unique_names(vars, name, "Dataset", msg))
1082  return false;
1083 
1084  if (all)
1085  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1086  if (!(*i)->check_semantics(msg, true))
1087  return false;
1088 
1089  return true;
1090 }
1091 
1117 bool
1118 DDS::mark(const string &n, bool state)
1119 {
1121 
1122  DBG2(cerr << "DDS::mark: Looking for " << n << endl);
1123 
1124  BaseType *variable = var(n, s);
1125  if (!variable) {
1126  DBG2(cerr << "Could not find variable " << n << endl);
1127  delete s; s = 0;
1128  return false;
1129  }
1130  variable->set_send_p(state);
1131 
1132  DBG2(cerr << "DDS::mark: Set variable " << variable->name()
1133  << " (a " << variable->type_name() << ")" << endl);
1134 
1135  // Now check the btp_stack and run BaseType::set_send_p for every
1136  // BaseType pointer on the stack. Using BaseType::set_send_p() will
1137  // set the property for a Constructor but not its contained variables
1138  // which preserves the semantics of projecting just one field.
1139  while (!s->empty()) {
1140  s->top()->BaseType::set_send_p(state);
1141 
1142  DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
1143  << " (a " << s->top()->type_name() << ")" << endl);
1144  string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
1145  string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
1146  DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
1147 
1148  s->pop();
1149  }
1150 
1151  delete s ; s = 0;
1152 
1153  return true;
1154 }
1155 
1161 void
1162 DDS::mark_all(bool state)
1163 {
1164  for (Vars_iter i = vars.begin(); i != vars.end(); i++)
1165  (*i)->set_send_p(state);
1166 }
1167 
1175 void
1176 DDS::dump(ostream &strm) const
1177 {
1178  strm << DapIndent::LMarg << "DDS::dump - ("
1179  << (void *)this << ")" << endl ;
1180  DapIndent::Indent() ;
1181  strm << DapIndent::LMarg << "name: " << name << endl ;
1182  strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
1183  strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
1184  strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
1185  strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
1186 
1187  strm << DapIndent::LMarg << "global attributes:" << endl ;
1188  DapIndent::Indent() ;
1189  d_attr.dump(strm) ;
1191 
1192  if (vars.size()) {
1193  strm << DapIndent::LMarg << "vars:" << endl ;
1194  DapIndent::Indent() ;
1195  Vars_citer i = vars.begin() ;
1196  Vars_citer ie = vars.end() ;
1197  for (; i != ie; i++) {
1198  (*i)->dump(strm) ;
1199  }
1201  }
1202  else {
1203  strm << DapIndent::LMarg << "vars: none" << endl ;
1204  }
1205 
1207 }
1208 
1209 } // namespace libdap