libdap++ Updated for version 3.8.2
DDS.cc
Go to the documentation of this file.
00001 // -*- mode: c++; c-basic-offset:4 -*-
00002 
00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00004 // Access Protocol.
00005 
00006 // Copyright (c) 2002,2003 OPeNDAP, Inc.
00007 // Author: James Gallagher <jgallagher@opendap.org>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00024 
00025 // (c) COPYRIGHT URI/MIT 1994-1999
00026 // Please read the full copyright statement in the file COPYRIGHT_URI.
00027 //
00028 // Authors:
00029 //      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
00030 
00031 //
00032 // jhrg 9/7/94
00033 
00034 #include "config.h"
00035 
00036 static char rcsid[] not_used =
00037     {"$Id: DDS.cc 24370 2011-03-28 16:21:32Z jimg $"
00038     };
00039 
00040 #include <cstdio>
00041 #include <sys/types.h>
00042 
00043 #ifdef WIN32
00044 #include <io.h>
00045 #include <process.h>
00046 #include <fstream>
00047 #else
00048 #include <unistd.h>    // for alarm and dup
00049 #include <sys/wait.h>
00050 #endif
00051 
00052 #include <iostream>
00053 #include <sstream>
00054 #include <algorithm>
00055 #include <functional>
00056 
00057 //#define DODS_DEBUG
00058 //#define DODS_DEBUG2
00059 
00060 #include "GNURegex.h"
00061 
00062 #include "DAS.h"
00063 #include "Clause.h"
00064 #include "Error.h"
00065 #include "InternalErr.h"
00066 #include "Keywords2.h"
00067 
00068 #include "parser.h"
00069 #include "debug.h"
00070 #include "util.h"
00071 
00072 #include "Byte.h"
00073 #include "Int16.h"
00074 #include "UInt16.h"
00075 #include "Int32.h"
00076 #include "UInt32.h"
00077 #include "Float32.h"
00078 #include "Float64.h"
00079 #include "Str.h"
00080 #include "Url.h"
00081 #include "Array.h"
00082 #include "Structure.h"
00083 #include "Sequence.h"
00084 #include "Grid.h"
00085 
00086 #include "escaping.h"
00087 
00088 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
00089 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
00090 
00091 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
00092 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
00093 
00094 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
00095 
00096 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
00097 
00098 using namespace std;
00099 
00100 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
00101 int ddsparse(void *arg);
00102 
00103 // Glue for the DDS parser defined in dds.lex
00104 void dds_switch_to_buffer(void *new_buffer);
00105 void dds_delete_buffer(void * buffer);
00106 void *dds_buffer(FILE *fp);
00107 
00108 namespace libdap {
00109 
00110 void
00111 DDS::duplicate(const DDS &dds)
00112 {
00113     DBG(cerr << "Entering DDS::duplicate... " <<endl);
00114     name = dds.name;
00115     d_filename = dds.d_filename;
00116     d_container_name = dds.d_container_name;
00117     d_timeout = dds.d_timeout;
00118     d_attr = dds.d_attr;
00119 
00120     d_factory = dds.d_factory;
00121     d_container = dds.d_container;
00122     d_dap_major = dds.d_dap_major;
00123     d_dap_minor = dds.d_dap_minor;
00124 
00125     d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
00126 
00127     DDS &dds_tmp = const_cast<DDS &>(dds);
00128 
00129     // copy the things pointed to by the list, not just the pointers
00130     for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
00131         add_var(*i); // add_var() dups the BaseType.
00132     }
00133 }
00134 
00145 DDS::DDS(BaseTypeFactory *factory, const string &n)
00146 
00147         : d_factory(factory), name(n), d_container(0),
00148           d_dap_major(2), d_dap_minor(0),
00149         d_request_xml_base(""), d_timeout(0), d_keywords()
00150 {
00151     DBG(cerr << "Building a DDS with client major/minor: "
00152             << d_dap_major << "." << d_dap_minor << endl);
00153 }
00154 
00156 DDS::DDS(const DDS &rhs) : DapObj()
00157 {
00158     DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
00159     duplicate(rhs);
00160     DBG(cerr << " bye." << endl);
00161 }
00162 
00163 DDS::~DDS()
00164 {
00165     // delete all the variables in this DDS
00166     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00167         BaseType *btp = *i ;
00168         delete btp ; btp = 0;
00169     }
00170 }
00171 
00172 DDS &
00173 DDS::operator=(const DDS &rhs)
00174 {
00175     DBG(cerr << "Entering DDS::operator= ..." << endl);
00176     if (this == &rhs)
00177         return *this;
00178 
00179     duplicate(rhs);
00180 
00181     DBG(cerr << " bye." << endl);
00182     return *this;
00183 }
00184 
00198 void
00199 DDS::transfer_attributes(DAS *das)
00200 {
00201     // If there is a container set in the DDS then get the container from
00202     // the DAS. If they are not the same container, then throw an exception
00203     // (should be working on the same container). If the container does not
00204     // exist in the DAS, then throw an exception
00205     if( d_container ) {
00206         if( das->container_name() != d_container_name )
00207             throw InternalErr(__FILE__, __LINE__, "Error transferring attributes: working on a container in dds, but not das" ) ;
00208     }
00209 
00210     // Give each variable a chance to claim its attributes.
00211     AttrTable *top_level = das->get_top_level_attributes() ;
00212 
00213     Vars_iter var = var_begin();
00214     while (var != var_end()) {
00215         (*var)->transfer_attributes(top_level);
00216         var++;
00217     }
00218 
00219     // Now we transfer all of the attributes still marked as global to the
00220     // global container in the DDS.
00221 
00222     AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
00223     while (at_cont_p != top_level->attr_end()) {
00224         // In truth, all of the top level attributes should be containers, but
00225         // this test handles the abnormal case where somehow someone makes a
00226         // top level attribute that is not a container by silently dropping it.
00227         if ((*at_cont_p)->type == Attr_container
00228                 && (*at_cont_p)->attributes->is_global_attribute()) {
00229             DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl);
00230             // copy the source container so that the DAS passed in can be
00231             // deleted after calling htis method.
00232             AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
00233             d_attr.append_container(at, at->get_name());
00234         }
00235 
00236         at_cont_p++;
00237     }
00238 }
00239 
00247 
00249 string
00250 DDS::get_dataset_name() const
00251 {
00252     return name;
00253 }
00254 
00256 void
00257 DDS::set_dataset_name(const string &n)
00258 {
00259     name = n;
00260 }
00261 
00263 
00265 AttrTable &
00266 DDS::get_attr_table()
00267 {
00268     return d_attr;
00269 }
00270 
00280 string
00281 DDS::filename()
00282 {
00283     return d_filename;
00284 }
00285 
00287 void
00288 DDS::filename(const string &fn)
00289 {
00290     d_filename = fn;
00291 }
00293 
00294 void
00295 DDS::set_dap_major(int p)
00296 {
00297     d_dap_major = p;
00298 
00299     // This works because regardless of the order set_dap_major and set_dap_minor
00300     // are called, once they both are called, the value in the string is
00301     // correct. I protect against negative numbers because that would be
00302     // nonsensical.
00303     if (d_dap_minor >= 0) {
00304         ostringstream oss;
00305         oss << d_dap_major << "." << d_dap_minor;
00306         d_dap_version = oss.str();
00307     }
00308 }
00309 
00310 void
00311 DDS::set_dap_minor(int p)
00312 {
00313     d_dap_minor = p;
00314 
00315     if (d_dap_major >= 0) {
00316         ostringstream oss;
00317         oss << d_dap_major << "." << d_dap_minor;
00318         d_dap_version = oss.str();
00319     }
00320 }
00321 
00328 void
00329 DDS::set_dap_version(const string &version_string)
00330 {
00331     istringstream iss(version_string);
00332 
00333     int major = -1, minor = -1;
00334     char dot;
00335     if (!iss.eof() && !iss.fail())
00336         iss >> major;
00337     if (!iss.eof() && !iss.fail())
00338         iss >> dot;
00339     if (!iss.eof() && !iss.fail())
00340         iss >> minor;
00341 
00342     DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
00343 #if 0
00344     if (major == -1 || minor == -1)
00345         throw Error("Could not parse the client dap (XDAP-Accept header) value");
00346 #endif
00347 
00348     d_dap_version = version_string;
00349 
00350     set_dap_major(major == -1 ? 2 : major);
00351     set_dap_minor(minor == -1 ? 0 : minor);
00352 }
00353 
00361 void
00362 DDS::set_dap_version(double d)
00363 {
00364     int major = d;
00365     int minor = (d-major)*10;
00366 
00367     DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
00368 
00369     ostringstream oss;
00370     oss << major << "." << minor;
00371     d_dap_version = oss.str();
00372 
00373     set_dap_major(major);
00374     set_dap_minor(minor);
00375 }
00376 
00386 string
00387 DDS::container_name()
00388 {
00389     return d_container_name;
00390 }
00391 
00394 void
00395 DDS::container_name(const string &cn)
00396 {
00397     // we want to search the DDS for the top level structure with the given
00398     // name. Set the container to null so that we don't search some previous
00399     // container.
00400     d_container = 0 ;
00401     if( !cn.empty() )
00402     {
00403         d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00404         if( !d_container )
00405         {
00406             // create a structure for this container. Calling add_var
00407             // while_container is null will add the new structure to DDS and
00408             // not some sub structure. Adding the new structure makes a copy
00409             // of it.  So after adding it, go get it and set d_container.
00410             Structure *s = new Structure( cn ) ;
00411             add_var( s ) ;
00412             delete s ;
00413             s = 0 ;
00414             d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00415         }
00416     }
00417     d_container_name = cn;
00418 
00419 }
00420 
00422 Structure *
00423 DDS::container()
00424 {
00425     return d_container ;
00426 }
00427 
00429 
00435 void
00436 DDS::add_var(BaseType *bt)
00437 {
00438     if (!bt)
00439         throw InternalErr(__FILE__, __LINE__,
00440                           "Trying to add a BaseType object with a NULL pointer.");
00441 
00442     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00443 
00444     BaseType *btp = bt->ptr_duplicate();
00445     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00446     if( d_container )
00447     {
00448         // Mem leak fix [mjohnson nov 2009]
00449         // Structure::add_var() creates ANOTHER copy.
00450         d_container->add_var( bt ) ;
00451         // So we need to delete btp or else it leaks
00452         delete btp; btp = 0;
00453     }
00454     else
00455     {
00456         vars.push_back(btp);
00457     }
00458 }
00459 
00466 void
00467 DDS::del_var(const string &n)
00468 {
00469     if( d_container )
00470     {
00471         d_container->del_var( n ) ;
00472         return ;
00473     }
00474 
00475     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00476         if ((*i)->name() == n) {
00477             BaseType *bt = *i ;
00478             vars.erase(i) ;
00479             delete bt ; bt = 0;
00480             return;
00481         }
00482     }
00483 }
00484 
00489 void
00490 DDS::del_var(Vars_iter i)
00491 {
00492     if (i != vars.end()) {
00493         BaseType *bt = *i ;
00494         vars.erase(i) ;
00495         delete bt ; bt = 0;
00496     }
00497 }
00498 
00505 void
00506 DDS::del_var(Vars_iter i1, Vars_iter i2)
00507 {
00508     for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
00509         BaseType *bt = *i_tmp ;
00510         delete bt ; bt = 0;
00511     }
00512     vars.erase(i1, i2) ;
00513 }
00514 
00522 BaseType *
00523 DDS::var(const string &n, BaseType::btp_stack &s)
00524 {
00525     return var(n, &s);
00526 }
00546 BaseType *
00547 DDS::var(const string &n, BaseType::btp_stack *s)
00548 {
00549     string name = www2id(n);
00550     if( d_container )
00551         return d_container->var( name, false, s ) ;
00552 
00553     BaseType *v = exact_match(name, s);
00554     if (v)
00555         return v;
00556 
00557     return leaf_match(name, s);
00558 }
00559 
00560 BaseType *
00561 DDS::leaf_match(const string &n, BaseType::btp_stack *s)
00562 {
00563     DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
00564 
00565     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00566         BaseType *btp = *i;
00567         DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
00568         // Look for the name in the dataset's top-level
00569         if (btp->name() == n) {
00570             DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00571             return btp;
00572         }
00573 
00574         if (btp->is_constructor_type()) {
00575             BaseType *found = btp->var(n, false, s);
00576             if (found) {
00577                 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00578                 return found;
00579             }
00580         }
00581 #if STRUCTURE_ARRAY_SYNTAX_OLD
00582         if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
00583             s->push(btp);
00584             BaseType *found = btp->var()->var(n, false, s);
00585             if (found) {
00586                 DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
00587                 return found;
00588             }
00589         }
00590 #endif
00591     }
00592 
00593     return 0;   // It is not here.
00594 }
00595 
00596 BaseType *
00597 DDS::exact_match(const string &name, BaseType::btp_stack *s)
00598 {
00599     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00600         BaseType *btp = *i;
00601         DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
00602         // Look for the name in the current ctor type or the top level
00603         if (btp->name() == name) {
00604             DBG2(cerr << "Found " << name << " in: " << btp << endl);
00605             return btp;
00606         }
00607     }
00608 
00609     string::size_type dot_pos = name.find(".");
00610     if (dot_pos != string::npos) {
00611         string aggregate = name.substr(0, dot_pos);
00612         string field = name.substr(dot_pos + 1);
00613 
00614         BaseType *agg_ptr = var(aggregate, s);
00615         if (agg_ptr) {
00616             DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
00617             return agg_ptr->var(field, true, s);
00618         }
00619         else
00620             return 0;  // qualified names must be *fully* qualified
00621     }
00622 
00623     return 0;   // It is not here.
00624 }
00625 
00626 
00629 DDS::Vars_iter
00630 DDS::var_begin()
00631 {
00632     return vars.begin();
00633 }
00634 
00635 DDS::Vars_riter
00636 DDS::var_rbegin()
00637 {
00638     return vars.rbegin();
00639 }
00640 
00641 DDS::Vars_iter
00642 DDS::var_end()
00643 {
00644     return vars.end() ;
00645 }
00646 
00647 DDS::Vars_riter
00648 DDS::var_rend()
00649 {
00650     return vars.rend() ;
00651 }
00652 
00656 DDS::Vars_iter
00657 DDS::get_vars_iter(int i)
00658 {
00659     return vars.begin() + i;
00660 }
00661 
00665 BaseType *
00666 DDS::get_var_index(int i)
00667 {
00668     return *(vars.begin() + i);
00669 }
00670 
00672 int
00673 DDS::num_var()
00674 {
00675     return vars.size();
00676 }
00677 
00678 void
00679 DDS::timeout_on()
00680 {
00681 #ifndef WIN32
00682     alarm(d_timeout);
00683 #endif
00684 }
00685 
00686 void
00687 DDS::timeout_off()
00688 {
00689 #ifndef WIN32
00690     d_timeout = alarm(0);
00691 #endif
00692 }
00693 
00694 void
00695 DDS::set_timeout(int t)
00696 {
00697     //  Has no effect under win32
00698     d_timeout = t;
00699 }
00700 
00701 int
00702 DDS::get_timeout()
00703 {
00704     //  Has to effect under win32
00705     return d_timeout;
00706 }
00707 
00709 void
00710 DDS::tag_nested_sequences()
00711 {
00712     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00713         if ((*i)->type() == dods_sequence_c)
00714             dynamic_cast<Sequence&>(**i).set_leaf_sequence();
00715         else if ((*i)->type() == dods_structure_c)
00716             dynamic_cast<Structure&>(**i).set_leaf_sequence();
00717     }
00718 }
00719 
00721 void
00722 DDS::parse(string fname)
00723 {
00724     FILE *in = fopen(fname.c_str(), "r");
00725 
00726     if (!in) {
00727         throw Error(cannot_read_file, "Could not open: " + fname);
00728     }
00729 
00730     try {
00731         parse(in);
00732         fclose(in);
00733     }
00734     catch (Error &e) {
00735         fclose(in);
00736         throw ;
00737     }
00738 }
00739 
00740 
00742 void
00743 DDS::parse(int fd)
00744 {
00745 #ifdef WIN32
00746     FILE *in = fdopen(_dup(fd), "r");
00747 #else
00748     FILE *in = fdopen(dup(fd), "r");
00749 #endif
00750 
00751     if (!in) {
00752         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00753     }
00754 
00755     try {
00756         parse(in);
00757         fclose(in);
00758     }
00759     catch (Error &e) {
00760         fclose(in);
00761         throw ;
00762     }
00763 }
00764 
00771 void
00772 DDS::parse(FILE *in)
00773 {
00774     if (!in) {
00775         throw InternalErr(__FILE__, __LINE__, "Null input stream.");
00776     }
00777 
00778     void *buffer = dds_buffer(in);
00779     dds_switch_to_buffer(buffer);
00780 
00781     parser_arg arg(this);
00782 
00783     bool status = ddsparse((void *) & arg) == 0;
00784 
00785     dds_delete_buffer(buffer);
00786 
00787     DBG2(cout << "Status from parser: " << status << endl);
00788 
00789     //  STATUS is the result of the parser function; if a recoverable error
00790     //  was found it will be true but arg.status() will be false.
00791     if (!status || !arg.status()) {// Check parse result
00792         if (arg.error())
00793             throw *arg.error();
00794     }
00795 }
00796 
00797 #if FILE_METHODS
00798 
00799 void
00800 DDS::print(FILE *out)
00801 {
00802 #if 0
00803     ostringstream oss;
00804     print(oss);
00805 
00806     fwrite(oss.str().c_str(), oss.str().length(), 1, out);
00807 #else
00808     fprintf(out, "Dataset {\n") ;
00809 
00810     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00811         (*i)->print_decl(out) ;
00812     }
00813 
00814     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00815 
00816     return ;
00817 #endif
00818 }
00819 #endif
00820 
00822 void
00823 DDS::print(ostream &out)
00824 {
00825     out << "Dataset {\n" ;
00826 
00827     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00828         (*i)->print_decl(out) ;
00829     }
00830 
00831     out << "} " << id2www(name) << ";\n" ;
00832 
00833     return ;
00834 }
00835 
00836 #if FILE_METHODS
00837 
00847 void
00848 DDS::print_constrained(FILE *out)
00849 {
00850     fprintf(out, "Dataset {\n") ;
00851 
00852     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00853         // for each variable, indent with four spaces, print a trailing
00854         // semicolon, do not print debugging information, print only
00855         // variables in the current projection.
00856         (*i)->print_decl(out, "    ", true, false, true) ;
00857     }
00858 
00859     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00860 
00861     return;
00862 }
00863 #endif
00864 
00875 void
00876 DDS::print_constrained(ostream &out)
00877 {
00878     out << "Dataset {\n" ;
00879 
00880     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00881         // for each variable, indent with four spaces, print a trailing
00882         // semicolon, do not print debugging information, print only
00883         // variables in the current projection.
00884         (*i)->print_decl(out, "    ", true, false, true) ;
00885     }
00886 
00887     out << "} " << id2www(name) << ";\n" ;
00888 
00889     return;
00890 }
00891 
00892 #if FILE_METHODS
00893 class VariablePrintXML : public unary_function<BaseType *, void>
00894 {
00895     FILE *d_out;
00896     bool d_constrained;
00897 public:
00898     VariablePrintXML(FILE *out, bool constrained)
00899             : d_out(out), d_constrained(constrained)
00900     {}
00901     void operator()(BaseType *bt)
00902     {
00903         bt->print_xml(d_out, "    ", d_constrained);
00904     }
00905 };
00906 
00917 void
00918 DDS::print_xml(FILE *out, bool constrained, const string &blob)
00919 {
00920     fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00921 
00922     fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
00923 
00924     fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
00925 
00926     fprintf(out,"method=\"FILE*\"\n");
00927     fprintf(out, "dap_major=\"%d\"\n", get_dap_major());
00928     fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor());
00929 
00930     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
00931     // this at some point... jhrg
00932     if (get_dap_major() == 3 && get_dap_minor() == 2) {
00933     fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
00934 
00935     fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
00936             c_dap32_namespace.c_str(), c_default_dap32_schema_location.c_str());
00937     }
00938     else {
00939         fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
00940         fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
00941                 c_dap20_namespace.c_str(), c_default_dap20_schema_location.c_str());
00942     }
00943 
00944 
00945     d_attr.print_xml(out, "    ", constrained);
00946 
00947     fprintf(out, "\n");
00948 
00949     for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
00950 
00951     fprintf(out, "\n");
00952 
00953     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
00954     // the same. jhrg
00955     if (get_dap_major() == 2 && get_dap_minor() == 0) {
00956         fprintf(out, "    <dataBLOB href=\"\"/>\n");
00957     }
00958     else if (!blob.empty()
00959              && (get_dap_major() == 3 && get_dap_minor() >= 2)
00960              || get_dap_major() >= 4) {
00961         fprintf(out, "    <blob href=\"cid:%s\"/>\n", blob.c_str());
00962     }
00963 
00964 
00965     fprintf(out, "</Dataset>\n");
00966 }
00967 #endif
00968 
00969 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
00970 {
00971     ostream &d_out;
00972     bool d_constrained;
00973 public:
00974     VariablePrintXMLStrm(ostream &out, bool constrained)
00975             : d_out(out), d_constrained(constrained)
00976     {}
00977     void operator()(BaseType *bt)
00978     {
00979         bt->print_xml(d_out, "    ", d_constrained);
00980     }
00981 };
00982 
00993 void
00994 DDS::print_xml(ostream &out, bool constrained, const string &blob)
00995 {
00996     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
00997 
00998     out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
00999 
01000     out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
01001 
01002     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01003     // this at some point... jhrg
01004     if (get_dap_major() == 3 && get_dap_minor() == 2) {
01005         out << "xsi:schemaLocation=\"" << c_dap32_namespace
01006             << "  " << c_default_dap32_schema_location << "\"\n" ;
01007 
01008         out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
01009         out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
01010 
01011         out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
01012         out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
01013 
01014         out << "dapVersion=\"" << get_dap_major() << "."
01015             << get_dap_minor() << "\"";
01016 
01017         if (!get_request_xml_base().empty()) {
01018             out << "\n";
01019             out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
01020             out << "xml:base=\"" << get_request_xml_base() << "\"";
01021         }
01022 
01023         // Close the Dataset element
01024         out << ">\n";
01025     }
01026     else {
01027         out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
01028         out << "xsi:schemaLocation=\"" << c_dap20_namespace
01029             << "  " << c_default_dap20_schema_location << "\">\n\n" ;
01030     }
01031 
01032     d_attr.print_xml(out, "    ", constrained);
01033 
01034     out << "\n" ;
01035 
01036     for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
01037 
01038     out << "\n" ;
01039 
01040     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01041     // the same.
01042     // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
01043     // actually the CID of the MIME part that holds the data.
01044     if (get_dap_major() == 2 && get_dap_minor() == 0) {
01045         out << "    <dataBLOB href=\"\"/>\n" ;
01046     }
01047     else if (!blob.empty()
01048              && (get_dap_major() == 3 && get_dap_minor() >= 2)
01049              || get_dap_major() >= 4) {
01050         out << "    <blob href=\"cid:" << blob << "\"/>\n";
01051     }
01052 
01053     out << "</Dataset>\n" ;
01054 }
01055 
01056 // Used by DDS::send() when returning data from a function call.
01071 bool
01072 DDS::check_semantics(bool all)
01073 {
01074     // The dataset must have a name
01075     if (name == "") {
01076         cerr << "A dataset must have a name" << endl;
01077         return false;
01078     }
01079 
01080     string msg;
01081     if (!unique_names(vars, name, "Dataset", msg))
01082         return false;
01083 
01084     if (all)
01085         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01086             if (!(*i)->check_semantics(msg, true))
01087                 return false;
01088 
01089     return true;
01090 }
01091 
01117 bool
01118 DDS::mark(const string &n, bool state)
01119 {
01120     BaseType::btp_stack *s = new BaseType::btp_stack;
01121 
01122     DBG2(cerr << "DDS::mark: Looking for " << n << endl);
01123 
01124     BaseType *variable = var(n, s);
01125     if (!variable) {
01126         DBG2(cerr << "Could not find variable " << n << endl);
01127         delete s; s = 0;
01128         return false;
01129     }
01130     variable->set_send_p(state);
01131 
01132     DBG2(cerr << "DDS::mark: Set variable " << variable->name()
01133             << " (a " << variable->type_name() << ")" << endl);
01134 
01135     // Now check the btp_stack and run BaseType::set_send_p for every
01136     // BaseType pointer on the stack. Using BaseType::set_send_p() will
01137     // set the property for a Constructor but not its contained variables
01138     // which preserves the semantics of projecting just one field.
01139     while (!s->empty()) {
01140         s->top()->BaseType::set_send_p(state);
01141 
01142         DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
01143                 << " (a " << s->top()->type_name() << ")" << endl);
01144         string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
01145         string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
01146         DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
01147 
01148         s->pop();
01149     }
01150 
01151     delete s ; s = 0;
01152 
01153     return true;
01154 }
01155 
01161 void
01162 DDS::mark_all(bool state)
01163 {
01164     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01165         (*i)->set_send_p(state);
01166 }
01167 
01175 void
01176 DDS::dump(ostream &strm) const
01177 {
01178     strm << DapIndent::LMarg << "DDS::dump - ("
01179     << (void *)this << ")" << endl ;
01180     DapIndent::Indent() ;
01181     strm << DapIndent::LMarg << "name: " << name << endl ;
01182     strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
01183     strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
01184     strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
01185     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
01186 
01187     strm << DapIndent::LMarg << "global attributes:" << endl ;
01188     DapIndent::Indent() ;
01189     d_attr.dump(strm) ;
01190     DapIndent::UnIndent() ;
01191 
01192     if (vars.size()) {
01193         strm << DapIndent::LMarg << "vars:" << endl ;
01194         DapIndent::Indent() ;
01195         Vars_citer i = vars.begin() ;
01196         Vars_citer ie = vars.end() ;
01197         for (; i != ie; i++) {
01198             (*i)->dump(strm) ;
01199         }
01200         DapIndent::UnIndent() ;
01201     }
01202     else {
01203         strm << DapIndent::LMarg << "vars: none" << endl ;
01204     }
01205 
01206     DapIndent::UnIndent() ;
01207 }
01208 
01209 } // namespace libdap