libdap  Updated for version 3.17.0
DDS.cc
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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 #include <cstdio>
00037 #include <cmath>
00038 #include <sys/types.h>
00039 
00040 #ifdef WIN32
00041 #include <io.h>
00042 #include <process.h>
00043 #include <fstream>
00044 #else
00045 #include <unistd.h>    // for alarm and dup
00046 #include <sys/wait.h>
00047 #endif
00048 
00049 #include <iostream>
00050 #include <sstream>
00051 #include <algorithm>
00052 #include <functional>
00053 
00054 //#define DODS_DEBUG
00055 //#define DODS_DEBUG2
00056 
00057 #include "GNURegex.h"
00058 
00059 #include "DAS.h"
00060 #include "Clause.h"
00061 #include "Error.h"
00062 #include "InternalErr.h"
00063 #include "Keywords2.h"
00064 
00065 #include "parser.h"
00066 #include "debug.h"
00067 #include "util.h"
00068 
00069 #include "Byte.h"
00070 #include "Int16.h"
00071 #include "UInt16.h"
00072 #include "Int32.h"
00073 #include "UInt32.h"
00074 #include "Float32.h"
00075 #include "Float64.h"
00076 #include "Str.h"
00077 #include "Url.h"
00078 #include "Array.h"
00079 #include "Structure.h"
00080 #include "Sequence.h"
00081 #include "Grid.h"
00082 
00083 #include "escaping.h"
00084 
00095 const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
00096 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
00097 
00098 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
00099 
00100 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
00101 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
00102 const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
00103 
00104 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
00105 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
00106 const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
00107 
00108 const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
00109 const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
00110 const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
00121 using namespace std;
00122 
00123 int ddsparse(libdap::parser_arg *arg);
00124 
00125 // Glue for the DDS parser defined in dds.lex
00126 void dds_switch_to_buffer(void *new_buffer);
00127 void dds_delete_buffer(void * buffer);
00128 void *dds_buffer(FILE *fp);
00129 
00130 namespace libdap {
00131 
00132 void
00133 DDS::duplicate(const DDS &dds)
00134 {
00135     DBG(cerr << "Entering DDS::duplicate... " <<endl);
00136 #if 0
00137     BaseTypeFactory *d_factory;
00138 
00139     string d_name;                // The dataset d_name
00140     string d_filename;          // File d_name (or other OS identifier) for
00141     string d_container_name;    // d_name of container structure
00142     Structure *d_container;     // current container for container d_name
00143                                 // dataset or part of dataset.
00144 
00145     int d_dap_major;            // The protocol major version number
00146     int d_dap_minor;            // ... and minor version number
00147     string d_dap_version;       // String version of the protocol
00148     string d_request_xml_base;
00149     string d_namespace;
00150 
00151     AttrTable d_attr;           // Global attributes.
00152 
00153     vector<BaseType *> vars;    // Variables at the top level
00154 
00155     int d_timeout;              // alarm time in seconds. If greater than
00156                                 // zero, raise the alarm signal if more than
00157                                 // d_timeout seconds are spent reading data.
00158     Keywords d_keywords;        // Holds keywords parsed from the CE
00159 
00160     long d_max_response_size;   // In bytes
00161 #endif
00162 
00163     d_factory = dds.d_factory;
00164 
00165     d_name = dds.d_name;
00166     d_filename = dds.d_filename;
00167     d_container_name = dds.d_container_name;
00168     d_container = dds.d_container;
00169 
00170     d_dap_major = dds.d_dap_major;
00171     d_dap_minor = dds.d_dap_minor;
00172 
00173     d_dap_version = dds.d_dap_version;       // String version of the protocol
00174     d_request_xml_base = dds.d_request_xml_base;
00175     d_namespace = dds.d_namespace;
00176 
00177     d_attr = dds.d_attr;
00178 
00179     DDS &dds_tmp = const_cast<DDS &>(dds);
00180 
00181     // copy the things pointed to by the list, not just the pointers
00182     for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
00183         add_var(*i); // add_var() dups the BaseType.
00184     }
00185 
00186     d_timeout = dds.d_timeout;
00187 
00188     d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
00189 
00190     d_max_response_size = dds.d_max_response_size;
00191 }
00192 
00205 DDS::DDS(BaseTypeFactory *factory, const string &name)
00206         : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
00207           d_request_xml_base(""),
00208           d_timeout(0), d_keywords(), d_max_response_size(0)
00209 {
00210     DBG(cerr << "Building a DDS for the default version (2.0)" << endl);
00211 
00212     // This method sets a number of values, including those returned by
00213     // get_protocol_major(), ..., get_namespace().
00214     set_dap_version("2.0");
00215 }
00216 
00232 DDS::DDS(BaseTypeFactory *factory, const string &name, const string &version)
00233         : d_factory(factory), d_name(name), d_container_name(""), d_container(0),
00234           d_request_xml_base(""),
00235           d_timeout(0), d_keywords(), d_max_response_size(0)
00236 {
00237     DBG(cerr << "Building a DDS for version: " << version << endl);
00238 
00239     // This method sets a number of values, including those returned by
00240     // get_protocol_major(), ..., get_namespace().
00241     set_dap_version(version);
00242 }
00243 
00245 DDS::DDS(const DDS &rhs) : DapObj()
00246 {
00247     DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
00248     duplicate(rhs);
00249     DBG(cerr << " bye." << endl);
00250 }
00251 
00252 DDS::~DDS()
00253 {
00254     // delete all the variables in this DDS
00255     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00256         BaseType *btp = *i ;
00257         delete btp ; btp = 0;
00258     }
00259 }
00260 
00261 DDS &
00262 DDS::operator=(const DDS &rhs)
00263 {
00264     DBG(cerr << "Entering DDS::operator= ..." << endl);
00265     if (this == &rhs)
00266         return *this;
00267 
00268     duplicate(rhs);
00269 
00270     DBG(cerr << " bye." << endl);
00271     return *this;
00272 }
00273 
00287 void DDS::transfer_attributes(DAS *das)
00288 {
00289     // If there is a container set in the DDS then check the container from
00290     // the DAS. If they are not the same container, then throw an exception
00291     // (should be working on the same container). If the container does not
00292     // exist in the DAS, then throw an exception
00293     if (d_container && das->container_name() != d_container_name)
00294         throw InternalErr(__FILE__, __LINE__,
00295                 "Error transferring attributes: working on a container in dds, but not das");
00296 
00297     // Give each variable a chance to claim its attributes.
00298     AttrTable *top = das->get_top_level_attributes();
00299 
00300     for (DDS::Vars_iter i = var_begin(), e = var_end(); i != e; i++) {
00301         (*i)->transfer_attributes(top);
00302     }
00303 #if 0
00304     Vars_iter var = var_begin();
00305     while (var != var_end()) {
00306         try {
00307             DBG(cerr << "Processing the attributes for: " << (*var)->d_name() << " a " << (*var)->type_name() << endl);
00308             (*var)->transfer_attributes(top);
00309             var++;
00310         }
00311         catch (Error &e) {
00312             DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
00313             var++;
00314             throw e;
00315         }
00316     }
00317 #endif
00318     // Now we transfer all of the attributes still marked as global to the
00319     // global container in the DDS.
00320     for (AttrTable::Attr_iter i = top->attr_begin(), e = top->attr_end(); i != e; ++i) {
00321         if ((*i)->type == Attr_container && (*i)->attributes->is_global_attribute()) {
00322             // copy the source container so that the DAS passed in can be
00323             // deleted after calling this method.
00324             AttrTable *at = new AttrTable(*(*i)->attributes);
00325             d_attr.append_container(at, at->get_name());
00326         }
00327     }
00328 #if 0
00329     AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
00330     while (at_cont_p != top_level->attr_end()) {
00331         // In truth, all of the top level attributes should be containers, but
00332         // this test handles the abnormal case where somehow someone makes a
00333         // top level attribute that is not a container by silently dropping it.
00334         if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
00335             DBG(cerr << (*at_cont_p)->d_name << " is a global attribute." << endl);
00336             // copy the source container so that the DAS passed in can be
00337             // deleted after calling this method.
00338             AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
00339             d_attr.append_container(at, at->get_name());
00340         }
00341 
00342         at_cont_p++;
00343     }
00344 #endif
00345 }
00346 
00354 
00356 string
00357 DDS::get_dataset_name() const
00358 {
00359     return d_name;
00360 }
00361 
00363 void
00364 DDS::set_dataset_name(const string &n)
00365 {
00366     d_name = n;
00367 }
00368 
00370 
00372 AttrTable &
00373 DDS::get_attr_table()
00374 {
00375     return d_attr;
00376 }
00377 
00387 string
00388 DDS::filename() const
00389 {
00390     return d_filename;
00391 }
00392 
00394 void
00395 DDS::filename(const string &fn)
00396 {
00397     d_filename = fn;
00398 }
00400 
00404 void
00405 DDS::set_dap_major(int p)
00406 {
00407     d_dap_major = p;
00408 
00409     // This works because regardless of the order set_dap_major and set_dap_minor
00410     // are called, once they both are called, the value in the string is
00411     // correct. I protect against negative numbers because that would be
00412     // nonsensical.
00413     if (d_dap_minor >= 0) {
00414         ostringstream oss;
00415         oss << d_dap_major << "." << d_dap_minor;
00416         d_dap_version = oss.str();
00417     }
00418 }
00419 
00423 void
00424 DDS::set_dap_minor(int p)
00425 {
00426     d_dap_minor = p;
00427 
00428     if (d_dap_major >= 0) {
00429         ostringstream oss;
00430         oss << d_dap_major << "." << d_dap_minor;
00431         d_dap_version = oss.str();
00432     }
00433 }
00434 
00440 void
00441 DDS::set_dap_version(const string &v /* = "2.0" */)
00442 {
00443     istringstream iss(v);
00444 
00445     int major = -1, minor = -1;
00446     char dot;
00447     if (!iss.eof() && !iss.fail())
00448         iss >> major;
00449     if (!iss.eof() && !iss.fail())
00450         iss >> dot;
00451     if (!iss.eof() && !iss.fail())
00452         iss >> minor;
00453 
00454     if (major == -1 || minor == -1 or dot != '.')
00455         throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
00456 
00457     d_dap_version = v;
00458 
00459     d_dap_major = major;
00460     d_dap_minor = minor;
00461 
00462     // Now set the related XML constants. These might be overwritten if
00463     // the DDS instance is being built from a document parse, but if it's
00464     // being constructed by a server the code to generate the XML document
00465     // needs these values to match the DAP version information.
00466     switch (d_dap_major) {
00467         case 2:
00468             d_namespace = c_dap20_namespace;
00469             break;
00470         case 3:
00471             d_namespace = c_dap32_namespace;
00472             break;
00473         case 4:
00474             d_namespace = c_dap40_namespace;
00475             break;
00476         default:
00477             throw InternalErr(__FILE__, __LINE__, "Unknown DAP version.");
00478     }
00479 }
00480 
00488 void
00489 DDS::set_dap_version(double d)
00490 {
00491     int major = floor(d);
00492     int minor = (d-major)*10;
00493 
00494     DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
00495 
00496     ostringstream oss;
00497     oss << major << "." << minor;
00498 
00499     set_dap_version(oss.str());
00500 }
00501 
00511 string
00512 DDS::container_name()
00513 {
00514     return d_container_name;
00515 }
00516 
00519 void
00520 DDS::container_name(const string &cn)
00521 {
00522     // we want to search the DDS for the top level structure with the given
00523     // d_name. Set the container to null so that we don't search some previous
00524     // container.
00525     d_container = 0 ;
00526     if( !cn.empty() )
00527     {
00528         d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00529         if( !d_container )
00530         {
00531             // create a structure for this container. Calling add_var
00532             // while_container is null will add the new structure to DDS and
00533             // not some sub structure. Adding the new structure makes a copy
00534             // of it.  So after adding it, go get it and set d_container.
00535             Structure *s = new Structure( cn ) ;
00536             add_var( s ) ;
00537             delete s ;
00538             s = 0 ;
00539             d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00540         }
00541     }
00542     d_container_name = cn;
00543 
00544 }
00545 
00547 Structure *
00548 DDS::container()
00549 {
00550     return d_container ;
00551 }
00552 
00554 
00565 int
00566 DDS::get_request_size(bool constrained)
00567 {
00568         int w = 0;
00569     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00570         if (constrained) {
00571                 if ((*i)->send_p())
00572                         w += (*i)->width(constrained);
00573         }
00574         else {
00575                 w += (*i)->width(constrained);
00576         }
00577     }
00578 
00579     return w;
00580 }
00581 
00587 void DDS::add_var(BaseType *bt) {
00588     if (!bt)
00589         throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
00590 #if 0
00591     if (bt->is_dap4_only_type())
00592         throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
00593 #endif
00594     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00595 
00596     BaseType *btp = bt->ptr_duplicate();
00597     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00598     if (d_container) {
00599         // Mem leak fix [mjohnson nov 2009]
00600         // Structure::add_var() creates ANOTHER copy.
00601         d_container->add_var(bt);
00602         // So we need to delete btp or else it leaks
00603         delete btp;
00604         btp = 0;
00605     }
00606     else {
00607         vars.push_back(btp);
00608     }
00609 }
00610 
00613 void
00614 DDS::add_var_nocopy(BaseType *bt)
00615 {
00616     if (!bt)
00617         throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
00618 #if 0
00619     //FIXME There's no longer a DAP2 and DAP4 DDS
00620     if (bt->is_dap4_only_type())
00621         throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
00622 #endif
00623 
00624     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00625 
00626     if (d_container) {
00627         d_container->add_var_nocopy(bt);
00628     }
00629     else {
00630         vars.push_back(bt);
00631     }
00632 }
00633 
00634 
00641 void
00642 DDS::del_var(const string &n)
00643 {
00644     if( d_container )
00645     {
00646         d_container->del_var( n ) ;
00647         return ;
00648     }
00649 
00650     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00651         if ((*i)->name() == n) {
00652             BaseType *bt = *i ;
00653             vars.erase(i) ;
00654             delete bt ; bt = 0;
00655             return;
00656         }
00657     }
00658 }
00659 
00664 void
00665 DDS::del_var(Vars_iter i)
00666 {
00667     if (i != vars.end()) {
00668         BaseType *bt = *i ;
00669         vars.erase(i) ;
00670         delete bt ; bt = 0;
00671     }
00672 }
00673 
00680 void
00681 DDS::del_var(Vars_iter i1, Vars_iter i2)
00682 {
00683     for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
00684         BaseType *bt = *i_tmp ;
00685         delete bt ; bt = 0;
00686     }
00687     vars.erase(i1, i2) ;
00688 }
00689 
00697 BaseType *
00698 DDS::var(const string &n, BaseType::btp_stack &s)
00699 {
00700     return var(n, &s);
00701 }
00721 BaseType *
00722 DDS::var(const string &n, BaseType::btp_stack *s)
00723 {
00724     string name = www2id(n);
00725     if( d_container )
00726         return d_container->var( name, false, s ) ;
00727 
00728     BaseType *v = exact_match(name, s);
00729     if (v)
00730         return v;
00731 
00732     return leaf_match(name, s);
00733 }
00734 
00735 BaseType *
00736 DDS::leaf_match(const string &n, BaseType::btp_stack *s)
00737 {
00738     DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
00739 
00740     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00741         BaseType *btp = *i;
00742         DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->d_name() << endl);
00743         // Look for the d_name in the dataset's top-level
00744         if (btp->name() == n) {
00745             DBG(cerr << "Found " << n << " in: " << btp->d_name() << endl);
00746             return btp;
00747         }
00748 
00749         if (btp->is_constructor_type()) {
00750             BaseType *found = btp->var(n, false, s);
00751             if (found) {
00752                 DBG(cerr << "Found " << n << " in: " << btp->d_name() << endl);
00753                 return found;
00754             }
00755         }
00756 #if STRUCTURE_ARRAY_SYNTAX_OLD
00757         if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
00758             s->push(btp);
00759             BaseType *found = btp->var()->var(n, false, s);
00760             if (found) {
00761                 DBG(cerr << "Found " << n << " in: " << btp->var()->d_name() << endl);
00762                 return found;
00763             }
00764         }
00765 #endif
00766     }
00767 
00768     return 0;   // It is not here.
00769 }
00770 
00771 BaseType *
00772 DDS::exact_match(const string &name, BaseType::btp_stack *s)
00773 {
00774     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00775         BaseType *btp = *i;
00776         DBG2(cerr << "Looking for " << d_name << " in: " << btp << endl);
00777         // Look for the d_name in the current ctor type or the top level
00778         if (btp->name() == name) {
00779             DBG2(cerr << "Found " << d_name << " in: " << btp << endl);
00780             return btp;
00781         }
00782     }
00783 
00784     string::size_type dot_pos = name.find(".");
00785     if (dot_pos != string::npos) {
00786         string aggregate = name.substr(0, dot_pos);
00787         string field = name.substr(dot_pos + 1);
00788 
00789         BaseType *agg_ptr = var(aggregate, s);
00790         if (agg_ptr) {
00791             DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
00792             return agg_ptr->var(field, true, s);
00793         }
00794         else
00795             return 0;  // qualified names must be *fully* qualified
00796     }
00797 
00798     return 0;   // It is not here.
00799 }
00800 
00801 
00804 DDS::Vars_iter
00805 DDS::var_begin()
00806 {
00807     return vars.begin();
00808 }
00809 
00810 DDS::Vars_riter
00811 DDS::var_rbegin()
00812 {
00813     return vars.rbegin();
00814 }
00815 
00816 DDS::Vars_iter
00817 DDS::var_end()
00818 {
00819     return vars.end() ;
00820 }
00821 
00822 DDS::Vars_riter
00823 DDS::var_rend()
00824 {
00825     return vars.rend() ;
00826 }
00827 
00831 DDS::Vars_iter
00832 DDS::get_vars_iter(int i)
00833 {
00834     return vars.begin() + i;
00835 }
00836 
00840 BaseType *
00841 DDS::get_var_index(int i)
00842 {
00843     return *(vars.begin() + i);
00844 }
00845 
00850 void
00851 DDS::insert_var(Vars_iter i, BaseType *ptr)
00852 {
00853 #if 0
00854     if (ptr->is_dap4_only_type())
00855         throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
00856 #endif
00857     vars.insert(i, ptr->ptr_duplicate());
00858 }
00859 
00867 void
00868 DDS::insert_var_nocopy(Vars_iter i, BaseType *ptr)
00869 {
00870 #if 0
00871     if (ptr->is_dap4_only_type())
00872         throw InternalErr(__FILE__, __LINE__, "Attempt to add a DAP4 type to a DAP2 DDS.");
00873 #endif
00874     vars.insert(i, ptr);
00875 }
00876 
00878 int
00879 DDS::num_var()
00880 {
00881     return vars.size();
00882 }
00883 
00884 void
00885 DDS::timeout_on()
00886 {
00887 #if USE_LOCAL_TIMEOUT_SCHEME
00888 #ifndef WIN32
00889     alarm(d_timeout);
00890 #endif
00891 #endif
00892 }
00893 
00894 void
00895 DDS::timeout_off()
00896 {
00897 #if USE_LOCAL_TIMEOUT_SCHEME
00898 #ifndef WIN32
00899     // Old behavior commented out. I think it is an error to change the value
00900     // of d_timeout. The way this will likely be used is to set the timeout
00901     // value once and then 'turn on' or turn off' that timeout as the situation
00902     // dictates. The initeded use for the DDS timeout is so that timeouts for
00903     // data responses will include the CPU resources needed to build the response
00904     // but not the time spent transmitting the response. This may change when
00905     // more parallelism is added to the server... These methods are called from
00906     // BESDapResponseBuilder in bes/dap. jhrg 12/22/15
00907 
00908     // d_timeout = alarm(0);
00909 
00910     alarm(0);
00911 #endif
00912 #endif
00913 }
00914 
00915 void
00916 DDS::set_timeout(int t)
00917 {
00918 #if USE_LOCAL_TIMEOUT_SCHEME
00919     //  Has no effect under win32
00920     d_timeout = t;
00921 #endif
00922 }
00923 
00924 int
00925 DDS::get_timeout()
00926 {
00927 #if USE_LOCAL_TIMEOUT_SCHEME
00928     //  Has to effect under win32
00929     return d_timeout;
00930 #endif
00931     return 0;
00932 }
00933 
00935 void
00936 DDS::tag_nested_sequences()
00937 {
00938     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00939         if ((*i)->type() == dods_sequence_c)
00940             dynamic_cast<Sequence&>(**i).set_leaf_sequence();
00941         else if ((*i)->type() == dods_structure_c)
00942             dynamic_cast<Structure&>(**i).set_leaf_sequence();
00943     }
00944 }
00945 
00947 void
00948 DDS::parse(string fname)
00949 {
00950     FILE *in = fopen(fname.c_str(), "r");
00951 
00952     if (!in) {
00953         throw Error(cannot_read_file, "Could not open: " + fname);
00954     }
00955 
00956     try {
00957         parse(in);
00958         fclose(in);
00959     }
00960     catch (Error &e) {
00961         fclose(in);
00962         throw ;
00963     }
00964 }
00965 
00966 
00968 void
00969 DDS::parse(int fd)
00970 {
00971 #ifdef WIN32
00972     int new_fd = _dup(fd);
00973 #else
00974     int new_fd = dup(fd);
00975 #endif
00976 
00977     if (new_fd < 0)
00978         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00979     FILE *in = fdopen(new_fd, "r");
00980 
00981     if (!in) {
00982         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00983     }
00984 
00985     try {
00986         parse(in);
00987         fclose(in);
00988     }
00989     catch (Error &e) {
00990         fclose(in);
00991         throw ;
00992     }
00993 }
00994 
01001 void
01002 DDS::parse(FILE *in)
01003 {
01004     if (!in) {
01005         throw InternalErr(__FILE__, __LINE__, "Null input stream.");
01006     }
01007 
01008     void *buffer = dds_buffer(in);
01009     dds_switch_to_buffer(buffer);
01010 
01011     parser_arg arg(this);
01012 
01013     bool status = ddsparse(&arg) == 0;
01014 
01015     dds_delete_buffer(buffer);
01016 
01017     DBG2(cout << "Status from parser: " << status << endl);
01018 
01019     //  STATUS is the result of the parser function; if a recoverable error
01020     //  was found it will be true but arg.status() will be false.
01021     if (!status || !arg.status()) {// Check parse result
01022         if (arg.error())
01023             throw *arg.error();
01024     }
01025 }
01026 
01028 void
01029 DDS::print(FILE *out)
01030 {
01031     ostringstream oss;
01032     print(oss);
01033     fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
01034 }
01035 
01037 void
01038 DDS::print(ostream &out)
01039 {
01040     out << "Dataset {\n" ;
01041 
01042     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
01043         (*i)->print_decl(out) ;
01044     }
01045 
01046     out << "} " << id2www(d_name) << ";\n" ;
01047 
01048     return ;
01049 }
01050 
01060 void
01061 DDS::print_das(ostream &out)
01062 {
01063     out << "Attributes {\n" ;
01064 
01065     d_attr.print(out, "    ");
01066     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
01067         (*i)->get_attr_table().print(out, "    ");
01068     }
01069 
01070     out << "}\n" ;
01071 }
01072 
01083 void
01084 DDS::print_constrained(FILE *out)
01085 {
01086     ostringstream oss;
01087     print_constrained(oss);
01088     fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
01089 }
01090 
01101 void
01102 DDS::print_constrained(ostream &out)
01103 {
01104     out << "Dataset {\n" ;
01105 
01106     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
01107         // for each variable, indent with four spaces, print a trailing
01108         // semicolon, do not print debugging information, print only
01109         // variables in the current projection.
01110         (*i)->print_decl(out, "    ", true, false, true) ;
01111     }
01112 
01113     out << "} " << id2www(d_name) << ";\n" ;
01114 
01115     return;
01116 }
01117 
01129 void
01130 DDS::print_xml(FILE *out, bool constrained, const string &blob)
01131 {
01132     ostringstream oss;
01133     print_xml_writer(oss, constrained, blob);
01134     fwrite(oss.str().data(), 1, oss.str().length(), out);
01135 }
01136 
01148 void
01149 DDS::print_xml(ostream &out, bool constrained, const string &blob)
01150 {
01151     print_xml_writer(out, constrained, blob);
01152 }
01153 
01154 class VariablePrintXMLWriter : public unary_function<BaseType *, void>
01155 {
01156     XMLWriter &d_xml;
01157     bool d_constrained;
01158 public:
01159     VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
01160             : d_xml(xml), d_constrained(constrained)
01161     {}
01162     void operator()(BaseType *bt)
01163     {
01164         bt->print_xml_writer(d_xml, d_constrained);
01165     }
01166 };
01167 
01184 void
01185 DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
01186 {
01187     XMLWriter xml("    ");
01188 
01189     // Stamp and repeat for these sections; trying to economize is makes it
01190     // even more confusing
01191     if (get_dap_major() >= 4) {
01192         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
01193             throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
01194         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
01195             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01196 
01197         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)get_dap_version().c_str()) < 0)
01198             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
01199 
01200         if (!get_request_xml_base().empty()) {
01201             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
01202                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
01203 
01204             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
01205                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
01206         }
01207         if (!get_namespace().empty()) {
01208             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)get_namespace().c_str()) < 0)
01209                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
01210         }
01211     }
01212     else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
01213         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
01214             throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
01215         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
01216             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01217         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
01218             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
01219 
01220         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
01221             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
01222 
01223         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
01224             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
01225 
01226         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
01227             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
01228 
01229         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
01230             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
01231         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
01232             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
01233 
01234         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
01235             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
01236 
01237         if (!get_request_xml_base().empty()) {
01238             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
01239                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
01240 
01241             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
01242                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
01243         }
01244     }
01245     else { // dap2
01246         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
01247             throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
01248         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)d_name.c_str()) < 0)
01249             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
01250         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
01251             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
01252 
01253         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
01254             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
01255 
01256         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
01257             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
01258     }
01259 
01260     // Print the global attributes
01261     d_attr.print_xml_writer(xml);
01262 
01263     // Print each variable
01264     for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
01265 
01266     // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
01267     // the CID of the MIME part that holds the data. For DAP2 (which includes
01268     // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
01269     // given.
01270     if (get_dap_major() >= 4) {
01271         if (!blob.empty()) {
01272             if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
01273                 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
01274             string cid = "cid:" + blob;
01275             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
01276                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
01277             if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01278                 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
01279         }
01280     }
01281     else if (get_dap_major() == 3 && get_dap_minor() >= 2) {
01282         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
01283             throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
01284         string cid = "cid:" + blob;
01285         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
01286             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
01287         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01288             throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
01289     }
01290     else { // dap2
01291         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
01292             throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
01293         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) "") < 0)
01294             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
01295         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01296             throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
01297     }
01298 
01299     if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01300         throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
01301 
01302     out << xml.get_doc();// << ends;// << endl;
01303 }
01304 
01317 void
01318 DDS::print_dmr(ostream &out, bool constrained)
01319 {
01320     if (get_dap_major() < 4)
01321         throw InternalErr(__FILE__, __LINE__, "Tried to print a DMR with DAP major version less than 4");
01322 
01323     XMLWriter xml("    ");
01324 
01325     // DAP4 wraps a dataset in a top-level Group element.
01326     if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Group") < 0)
01327         throw InternalErr(__FILE__, __LINE__, "Could not write Group element");
01328 
01329     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
01330             (const xmlChar*) c_xml_namespace.c_str()) < 0)
01331         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
01332 
01333     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
01334             < 0)
01335         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
01336 
01337     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
01338             (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
01339         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
01340 
01341     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns",
01342             (const xmlChar*) get_namespace().c_str()) < 0)
01343         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
01344 
01345     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",
01346             (const xmlChar*) get_dap_version().c_str()) < 0)
01347         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
01348 
01349     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*) get_dmr_version().c_str()) < 0)
01350         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
01351 
01352     if (!get_request_xml_base().empty()) {
01353         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
01354                 (const xmlChar*) get_request_xml_base().c_str()) < 0)
01355             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
01356     }
01357 
01358     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*) d_name.c_str()) < 0)
01359         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01360 
01361     // Print the global attributes
01362     d_attr.print_xml_writer(xml);
01363 
01364     // Print each variable
01365     for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
01366 
01367 #if 0
01368     // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
01369     // the CID of the MIME part that holds the data. For DAP2 (which includes
01370     // 3.0 and 3.1), the blob is an href. For DAP4, only write the CID if it's
01371     // given.
01372     if (get_dap_major() >= 4) {
01373         if (!blob.empty()) {
01374             if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
01375                 throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
01376             string cid = "cid:" + blob;
01377             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*) cid.c_str()) < 0)
01378                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for d_name");
01379             if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01380                 throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
01381         }
01382     }
01383 #endif
01384 
01385     if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01386         throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
01387 
01388     out << xml.get_doc();
01389 }
01390 
01391 // Used by DDS::send() when returning data from a function call.
01406 bool
01407 DDS::check_semantics(bool all)
01408 {
01409     // The dataset must have a d_name
01410     if (d_name == "") {
01411         cerr << "A dataset must have a d_name" << endl;
01412         return false;
01413     }
01414 
01415     string msg;
01416     if (!unique_names(vars, d_name, "Dataset", msg))
01417         return false;
01418 
01419     if (all)
01420         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01421             if (!(*i)->check_semantics(msg, true))
01422                 return false;
01423 
01424     return true;
01425 }
01426 
01452 bool
01453 DDS::mark(const string &n, bool state)
01454 {
01455     // TODO use auto_ptr
01456     BaseType::btp_stack *s = new BaseType::btp_stack;
01457 
01458     DBG2(cerr << "DDS::mark: Looking for " << n << endl);
01459 
01460     BaseType *variable = var(n, s);
01461     if (!variable) {
01462         DBG2(cerr << "Could not find variable " << n << endl);
01463         delete s; s = 0;
01464         return false;
01465     }
01466     variable->set_send_p(state);
01467 
01468     DBG2(cerr << "DDS::mark: Set variable " << variable->d_name()
01469             << " (a " << variable->type_name() << ")" << endl);
01470 
01471     // Now check the btp_stack and run BaseType::set_send_p for every
01472     // BaseType pointer on the stack. Using BaseType::set_send_p() will
01473     // set the property for a Constructor but not its contained variables
01474     // which preserves the semantics of projecting just one field.
01475     while (!s->empty()) {
01476         s->top()->BaseType::set_send_p(state);
01477 
01478         DBG2(cerr << "DDS::mark: Set variable " << s->top()->d_name()
01479                 << " (a " << s->top()->type_name() << ")" << endl);
01480         // FIXME get_parent() hosed?
01481 #if 1
01482         string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
01483         string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
01484         DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
01485 #endif
01486         s->pop();
01487     }
01488 
01489     delete s ; s = 0;
01490 
01491     return true;
01492 }
01493 
01499 void
01500 DDS::mark_all(bool state)
01501 {
01502     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01503         (*i)->set_send_p(state);
01504 }
01505 
01513 void
01514 DDS::dump(ostream &strm) const
01515 {
01516     strm << DapIndent::LMarg << "DDS::dump - ("
01517     << (void *)this << ")" << endl ;
01518     DapIndent::Indent() ;
01519     strm << DapIndent::LMarg << "d_name: " << d_name << endl ;
01520     strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
01521     strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
01522     strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
01523     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
01524 
01525     strm << DapIndent::LMarg << "global attributes:" << endl ;
01526     DapIndent::Indent() ;
01527     d_attr.dump(strm) ;
01528     DapIndent::UnIndent() ;
01529 
01530     if (vars.size()) {
01531         strm << DapIndent::LMarg << "vars:" << endl ;
01532         DapIndent::Indent() ;
01533         Vars_citer i = vars.begin() ;
01534         Vars_citer ie = vars.end() ;
01535         for (; i != ie; i++) {
01536             (*i)->dump(strm) ;
01537         }
01538         DapIndent::UnIndent() ;
01539     }
01540     else {
01541         strm << DapIndent::LMarg << "vars: none" << endl ;
01542     }
01543 
01544     DapIndent::UnIndent() ;
01545 }
01546 
01547 } // namespace libdap