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 20697 2009-04-08 17:14:10Z 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 
00067 #include "parser.h"
00068 #include "debug.h"
00069 #include "util.h"
00070 #include "escaping.h"
00071 
00072 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
00073 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap/3.2.xsd";
00074 
00075 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
00076 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
00077 
00078 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
00079 
00080 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
00081 
00082 using namespace std;
00083 
00084 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
00085 int ddsparse(void *arg);
00086 
00087 // Glue for the DDS parser defined in dds.lex
00088 void dds_switch_to_buffer(void *new_buffer);
00089 void dds_delete_buffer(void * buffer);
00090 void *dds_buffer(FILE *fp);
00091 
00092 namespace libdap {
00093 
00094 void
00095 DDS::duplicate(const DDS &dds)
00096 {
00097     DBG(cerr << "Entering DDS::duplicate... " <<endl);
00098     name = dds.name;
00099     d_factory = dds.d_factory;
00100     d_container = dds.d_container;
00101 
00102     d_client_dap_major = dds.d_client_dap_major;
00103     d_client_dap_minor = dds.d_client_dap_minor;
00104 
00105 
00106 #if 0
00107     //fields to copy
00108     string _filename;       // File name (or other OS identifier) for
00109     string _container_name; // name of container structure
00110     int d_protocol_major;       // The protocol major version number
00111     int d_protocol_minor;       // ... and minor version number
00112 
00113     // These hold the major and minor versions of DAP that the client send in
00114     // the XDAP-Accept header. If the header is not sent, these default to 2.0
00115     int d_client_dap_major;
00116     int d_client_dap_minor;
00117 
00118     AttrTable d_attr;           // Global attributes.
00119     int d_timeout;              // alarm time in seconds. If greater than
00120 
00121 #endif
00122 
00123     DDS &dds_tmp = const_cast<DDS &>(dds);
00124 
00125     // copy the things pointed to by the list, not just the pointers
00126     for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
00127         add_var(*i); // add_var() dups the BaseType.
00128     }
00129 }
00130 
00141 DDS::DDS(BaseTypeFactory *factory, const string &n)
00142 
00143         : d_factory(factory), name(n), d_container(0), d_dap_major(2),
00144         d_dap_minor(0), d_client_dap_major(2), d_client_dap_minor(0),
00145         d_request_xml_base(""), d_timeout(0)
00146 {
00147     DBG(cerr << "Building a DDS with client major/minor: "
00148             << d_client_dap_major << "." << d_client_dap_minor << endl);
00149 }
00150 
00152 DDS::DDS(const DDS &rhs) : DapObj()
00153 {
00154     DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
00155     duplicate(rhs);
00156     DBG(cerr << " bye." << endl);
00157 }
00158 
00159 DDS::~DDS()
00160 {
00161     // delete all the variables in this DDS
00162     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00163         BaseType *btp = *i ;
00164         delete btp ; btp = 0;
00165     }
00166 }
00167 
00168 DDS &
00169 DDS::operator=(const DDS &rhs)
00170 {
00171     DBG(cerr << "Entering DDS::operator= ..." << endl);
00172     if (this == &rhs)
00173         return *this;
00174 
00175     duplicate(rhs);
00176 
00177     DBG(cerr << " bye." << endl);
00178     return *this;
00179 }
00180 
00196 BaseType *
00197 DDS::find_hdf4_dimension_attribute_home(AttrTable::entry *source)
00198 {
00199     BaseType *btp;
00200     string::size_type i = source->name.find("_dim_");
00201     if (i != string::npos && (btp = var(source->name.substr(0, i)))) {
00202         if (btp->is_vector_type()) {
00203             return btp;
00204         }
00205         else if (btp->type() == dods_grid_c) {
00206             // For a Grid, the hdf4 handler uses _dim_n for the n-th Map
00207             // i+5 points to the character holding 'n'
00208             int n = atoi(source->name.substr(i + 5).c_str());
00209             DBG(cerr << "Found a Grid (" << btp->name() << ") and "
00210                 << source->name.substr(i) << ", extracted n: " << n << endl);
00211             return *(dynamic_cast<Grid&>(*btp).map_begin() + n);
00212         }
00213     }
00214 
00215     return 0;
00216 }
00217 
00223 AttrTable *
00224 DDS::find_matching_container(AttrTable::entry *source, BaseType **dest_variable)
00225 {
00226     // The attribute entry 'source' must be a container
00227     if (source->type != Attr_container)
00228         throw InternalErr(__FILE__, __LINE__, "DDS::find_matching_container");
00229 
00230     // Use the name of the attribute container 'source' to figure out where
00231     // to put its contents.
00232     BaseType *btp;
00233     if ((btp = var(source->name))) {
00234         // ... matches a variable name? Use var's table
00235         *dest_variable = btp;
00236         return &btp->get_attr_table();
00237     }
00238     else if ((btp = find_hdf4_dimension_attribute_home(source))) {
00239         // ... hdf4 dimension attribute? Make a sub table and use that.
00240         // btp can only be an Array or a Grid Map (which is an array)
00241         if (btp->get_parent() && btp->get_parent()->type() == dods_grid_c) {
00242             DBG(cerr << "Found a Grid, assigning to the map" << endl);
00243             *dest_variable = btp;
00244             return &btp->get_attr_table();
00245         }
00246         else { // must ba a plain Array
00247             string::size_type i = source->name.find("_dim_");
00248             string ext = source->name.substr(i + 1);
00249             *dest_variable = btp;
00250             return btp->get_attr_table().append_container(ext);
00251         }
00252     }
00253     else {
00254         // ... otherwise assume it's a global attribute.
00255         AttrTable *at = d_attr.find_container(source->name);
00256         if (!at) {
00257             at = new AttrTable();       // Make a new global table if needed
00258             d_attr.append_container(at, source->name);
00259         }
00260 
00261         *dest_variable = 0;
00262         return at;
00263     }
00264 }
00265 
00287 void
00288 DDS::transfer_attributes(DAS *das)
00289 {
00290     // If there is a container set in the DDS then get the container from
00291     // the DAS. If they are not the same container, then throw an exception
00292     // (should be working on the same container). If the container does not
00293     // exist in the DAS, then throw an exception
00294     if( d_container )
00295     {
00296         if( das->container_name() != _container_name )
00297         {
00298             string err = (string)"Error transferring attributes: "
00299                          + "working on container in dds, but not das" ;
00300             throw InternalErr(__FILE__, __LINE__, err ) ;
00301         }
00302     }
00303     AttrTable *top_level = das->get_top_level_attributes() ;
00304 
00305     // foreach container at the outer level
00306     AttrTable::Attr_iter das_i = top_level->attr_begin();
00307     AttrTable::Attr_iter das_e = top_level->attr_end();
00308     while (das_i != das_e) {
00309         DBG(cerr << "Working on the '" << (*das_i)->name << "' container."
00310             << endl);
00311 
00312         AttrTable *source = (*das_i)->attributes;
00313         // Variable that holds 'dest'; null for a global attribute.
00314         BaseType *dest_variable = 0;
00315         AttrTable *dest = find_matching_container(*das_i, &dest_variable);
00316 
00317         // foreach source attribute in the das_i container
00318         AttrTable::Attr_iter source_p = source->attr_begin();
00319         while (source_p != source->attr_end()) {
00320             DBG(cerr << "Working on the '" << (*source_p)->name << "' attribute"
00321                 << endl);
00322 
00323             // If this is container, we must have a container (this one) within
00324             // a container (the 'source'). Look and see if the variable is a
00325             // Constructor. If so, pass that container into
00326             // Constructor::transfer_attributes()
00327             if ((*source_p)->type == Attr_container) {
00328                 if (dest_variable && dest_variable->is_constructor_type()) {
00329                     dynamic_cast<Constructor&>(*dest_variable).transfer_attributes(*source_p);
00330                 }
00331                 else {
00332 #if 0
00333                     // Trick:
00334                     DBG(cerr << "Is current source aliased: "
00335                             << (*source_p)->is_alias << endl);
00336                     AttrTable &local = *(*source_p)->attributes;
00337                     for (AttrTable::Attr_iter i = local.attr_begin();
00338                          i != local.attr_end(); ++i) {
00339                         cerr << "... or one of its entries: " << (*i)->is_alias << endl;
00340                     }
00341 #endif
00342                     dest->append_container(new AttrTable(*(*source_p)->attributes),
00343                                            (*source_p)->name);
00344                 }
00345             }
00346             else {
00347                 dest->append_attr(source->get_name(source_p),
00348                                   source->get_type(source_p),
00349                                   source->get_attr_vector(source_p));
00350             }
00351 
00352             ++source_p;
00353         }
00354 
00355         ++das_i;
00356     }
00357 }
00358 
00366 
00368 string
00369 DDS::get_dataset_name() const
00370 {
00371     return name;
00372 }
00373 
00375 void
00376 DDS::set_dataset_name(const string &n)
00377 {
00378     name = n;
00379 }
00380 
00382 
00384 AttrTable &
00385 DDS::get_attr_table()
00386 {
00387     return d_attr;
00388 }
00389 
00399 string
00400 DDS::filename()
00401 {
00402     return _filename;
00403 }
00404 
00406 void
00407 DDS::filename(const string &fn)
00408 {
00409     _filename = fn;
00410 }
00412 
00418 void
00419 DDS::set_dap_version(const string &version_string)
00420 {
00421     istringstream iss(version_string);
00422 
00423     int major = -1, minor = -1;
00424     char dot;
00425     iss >> major;
00426     iss >> dot;
00427     iss >> minor;
00428 
00429     DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
00430 
00431     if (major == -1 || minor == -1)
00432         throw Error("Could not parse the client dap (XDAP-Accept header) value");
00433 
00434     set_dap_major(major);
00435     set_dap_minor(minor);
00436 }
00437 
00446 void
00447 DDS::set_client_dap_version(const string &version_string)
00448 {
00449     istringstream iss(version_string);
00450 
00451     int major = -1, minor = -1;
00452     char dot;
00453     iss >> major;
00454     iss >> dot;
00455     iss >> minor;
00456 
00457     DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
00458 
00459     if (major == -1 || minor == -1)
00460         throw Error("Could not parse the client dap (XDAP-Accept header) value");
00461 
00462     set_client_dap_major(major);
00463     set_client_dap_minor(minor);
00464 }
00465 
00475 string
00476 DDS::container_name()
00477 {
00478     return _container_name;
00479 }
00480 
00483 void
00484 DDS::container_name(const string &cn)
00485 {
00486     // we want to search the DDS for the top level structure with the given
00487     // name. Set the container to null so that we don't search some previous
00488     // container.
00489     d_container = 0 ;
00490     if( !cn.empty() )
00491     {
00492         d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00493         if( !d_container )
00494         {
00495             // create a structure for this container. Calling add_var
00496             // while_container is null will add the new structure to DDS and
00497             // not some sub structure. Adding the new structure makes a copy
00498             // of it.  So after adding it, go get it and set d_container.
00499             Structure *s = new Structure( cn ) ;
00500             add_var( s ) ;
00501             delete s ;
00502             s = 0 ;
00503             d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00504         }
00505     }
00506     _container_name = cn;
00507 
00508 }
00509 
00511 Structure *
00512 DDS::container()
00513 {
00514     return d_container ;
00515 }
00516 
00518 
00524 void
00525 DDS::add_var(BaseType *bt)
00526 {
00527     if (!bt)
00528         throw InternalErr(__FILE__, __LINE__,
00529                           "Trying to add a BaseType object with a NULL pointer.");
00530 
00531     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00532 
00533     BaseType *btp = bt->ptr_duplicate();
00534     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00535     if( d_container )
00536     {
00537         d_container->add_var( bt ) ;
00538     }
00539     else
00540     {
00541         vars.push_back(btp);
00542     }
00543 }
00544 
00551 void
00552 DDS::del_var(const string &n)
00553 {
00554     if( d_container )
00555     {
00556         d_container->del_var( n ) ;
00557         return ;
00558     }
00559 
00560     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00561         if ((*i)->name() == n) {
00562             BaseType *bt = *i ;
00563             vars.erase(i) ;
00564             delete bt ; bt = 0;
00565             return;
00566         }
00567     }
00568 }
00569 
00574 void
00575 DDS::del_var(Vars_iter i)
00576 {
00577     if (i != vars.end()) {
00578         BaseType *bt = *i ;
00579         vars.erase(i) ;
00580         delete bt ; bt = 0;
00581     }
00582 }
00583 
00590 void
00591 DDS::del_var(Vars_iter i1, Vars_iter i2)
00592 {
00593     for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
00594         BaseType *bt = *i_tmp ;
00595         delete bt ; bt = 0;
00596     }
00597     vars.erase(i1, i2) ;
00598 }
00599 
00607 BaseType *
00608 DDS::var(const string &n, BaseType::btp_stack &s)
00609 {
00610     return var(n, &s);
00611 }
00631 BaseType *
00632 DDS::var(const string &n, BaseType::btp_stack *s)
00633 {
00634     string name = www2id(n);
00635     if( d_container )
00636         return d_container->var( name, false, s ) ;
00637 
00638     BaseType *v = exact_match(name, s);
00639     if (v)
00640         return v;
00641 
00642     return leaf_match(name, s);
00643 }
00644 
00645 BaseType *
00646 DDS::leaf_match(const string &n, BaseType::btp_stack *s)
00647 {
00648     DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
00649 
00650     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00651         BaseType *btp = *i;
00652         DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
00653         // Look for the name in the dataset's top-level
00654         if (btp->name() == n) {
00655             DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00656             return btp;
00657         }
00658 
00659         if (btp->is_constructor_type()) {
00660             BaseType *found = btp->var(n, false, s);
00661             if (found) {
00662                 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00663                 return found;
00664             }
00665         }
00666 #if STRUCTURE_ARRAY_SYNTAX_OLD
00667         if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
00668             s->push(btp);
00669             BaseType *found = btp->var()->var(n, false, s);
00670             if (found) {
00671                 DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
00672                 return found;
00673             }
00674         }
00675 #endif
00676     }
00677 
00678     return 0;   // It is not here.
00679 }
00680 
00681 BaseType *
00682 DDS::exact_match(const string &name, BaseType::btp_stack *s)
00683 {
00684     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00685         BaseType *btp = *i;
00686         DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
00687         // Look for the name in the current ctor type or the top level
00688         if (btp->name() == name) {
00689             DBG2(cerr << "Found " << name << " in: " << btp << endl);
00690             return btp;
00691         }
00692     }
00693 
00694     string::size_type dot_pos = name.find(".");
00695     if (dot_pos != string::npos) {
00696         string aggregate = name.substr(0, dot_pos);
00697         string field = name.substr(dot_pos + 1);
00698 
00699         BaseType *agg_ptr = var(aggregate, s);
00700         if (agg_ptr) {
00701             DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
00702             return agg_ptr->var(field, true, s);
00703         }
00704         else
00705             return 0;  // qualified names must be *fully* qualified
00706     }
00707 
00708     return 0;   // It is not here.
00709 }
00710 
00711 
00714 DDS::Vars_iter
00715 DDS::var_begin()
00716 {
00717     return vars.begin();
00718 }
00719 
00720 DDS::Vars_riter
00721 DDS::var_rbegin()
00722 {
00723     return vars.rbegin();
00724 }
00725 
00726 DDS::Vars_iter
00727 DDS::var_end()
00728 {
00729     return vars.end() ;
00730 }
00731 
00732 DDS::Vars_riter
00733 DDS::var_rend()
00734 {
00735     return vars.rend() ;
00736 }
00737 
00741 DDS::Vars_iter
00742 DDS::get_vars_iter(int i)
00743 {
00744     return vars.begin() + i;
00745 }
00746 
00750 BaseType *
00751 DDS::get_var_index(int i)
00752 {
00753     return *(vars.begin() + i);
00754 }
00755 
00757 int
00758 DDS::num_var()
00759 {
00760     return vars.size();
00761 }
00762 
00763 void
00764 DDS::timeout_on()
00765 {
00766 #ifndef WIN32
00767     alarm(d_timeout);
00768 #endif
00769 }
00770 
00771 void
00772 DDS::timeout_off()
00773 {
00774 #ifndef WIN32
00775     d_timeout = alarm(0);
00776 #endif
00777 }
00778 
00779 void
00780 DDS::set_timeout(int t)
00781 {
00782     //  Has no effect under win32
00783     d_timeout = t;
00784 }
00785 
00786 int
00787 DDS::get_timeout()
00788 {
00789     //  Has to effect under win32
00790     return d_timeout;
00791 }
00792 
00794 void
00795 DDS::tag_nested_sequences()
00796 {
00797     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00798         if ((*i)->type() == dods_sequence_c)
00799             dynamic_cast<Sequence&>(**i).set_leaf_sequence();
00800         else if ((*i)->type() == dods_structure_c)
00801             dynamic_cast<Structure&>(**i).set_leaf_sequence();
00802     }
00803 }
00804 
00806 void
00807 DDS::parse(string fname)
00808 {
00809     FILE *in = fopen(fname.c_str(), "r");
00810 
00811     if (!in) {
00812         throw Error(cannot_read_file, "Could not open: " + fname);
00813     }
00814 
00815     try {
00816         parse(in);
00817         fclose(in);
00818     }
00819     catch (Error &e) {
00820         fclose(in);
00821         throw e;
00822     }
00823 }
00824 
00825 
00827 void
00828 DDS::parse(int fd)
00829 {
00830 #ifdef WIN32
00831     FILE *in = fdopen(_dup(fd), "r");
00832 #else
00833     FILE *in = fdopen(dup(fd), "r");
00834 #endif
00835 
00836     if (!in) {
00837         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00838     }
00839 
00840     try {
00841         parse(in);
00842         fclose(in);
00843     }
00844     catch (Error &e) {
00845         fclose(in);
00846         throw e;
00847     }
00848 }
00849 
00856 void
00857 DDS::parse(FILE *in)
00858 {
00859     if (!in) {
00860         throw InternalErr(__FILE__, __LINE__, "Null input stream.");
00861     }
00862 
00863     void *buffer = dds_buffer(in);
00864     dds_switch_to_buffer(buffer);
00865 
00866     parser_arg arg(this);
00867 
00868     bool status = ddsparse((void *) & arg) == 0;
00869 
00870     dds_delete_buffer(buffer);
00871 
00872     DBG2(cout << "Status from parser: " << status << endl);
00873 
00874     //  STATUS is the result of the parser function; if a recoverable error
00875     //  was found it will be true but arg.status() will be false.
00876     if (!status || !arg.status()) {// Check parse result
00877         if (arg.error())
00878             throw *arg.error();
00879     }
00880 }
00881 //#if FILE_METHODS
00883 void
00884 DDS::print(FILE *out)
00885 {
00886     fprintf(out, "Dataset {\n") ;
00887 
00888     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00889         (*i)->print_decl(out) ;
00890     }
00891 
00892     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00893 
00894     return ;
00895 }
00896 //#endif
00898 void
00899 DDS::print(ostream &out)
00900 {
00901     out << "Dataset {\n" ;
00902 
00903     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00904         (*i)->print_decl(out) ;
00905     }
00906 
00907     out << "} " << id2www(name) << ";\n" ;
00908 
00909     return ;
00910 }
00911 //#if FILE_METHODS
00922 void
00923 DDS::print_constrained(FILE *out)
00924 {
00925     fprintf(out, "Dataset {\n") ;
00926 
00927     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00928         // for each variable, indent with four spaces, print a trailing
00929         // semicolon, do not print debugging information, print only
00930         // variables in the current projection.
00931         (*i)->print_decl(out, "    ", true, false, true) ;
00932     }
00933 
00934     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00935 
00936     return;
00937 }
00938 //#endif
00949 void
00950 DDS::print_constrained(ostream &out)
00951 {
00952     out << "Dataset {\n" ;
00953 
00954     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00955         // for each variable, indent with four spaces, print a trailing
00956         // semicolon, do not print debugging information, print only
00957         // variables in the current projection.
00958         (*i)->print_decl(out, "    ", true, false, true) ;
00959     }
00960 
00961     out << "} " << id2www(name) << ";\n" ;
00962 
00963     return;
00964 }
00965 //#if FILE_METHODS
00966 class VariablePrintXML : public unary_function<BaseType *, void>
00967 {
00968     FILE *d_out;
00969     bool d_constrained;
00970 public:
00971     VariablePrintXML(FILE *out, bool constrained)
00972             : d_out(out), d_constrained(constrained)
00973     {}
00974     void operator()(BaseType *bt)
00975     {
00976         bt->print_xml(d_out, "    ", d_constrained);
00977     }
00978 };
00979 //#endif
00980 //#if FILE_METHODS
00991 void
00992 DDS::print_xml(FILE *out, bool constrained, const string &)
00993 {
00994     fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00995 
00996     fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
00997 
00998     fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
00999 
01000     fprintf(out,"method=\"FILE*\"\n");
01001     fprintf(out, "dap_major=\"%d\"\n", get_client_dap_major());
01002     fprintf(out, "dap_minor=\"%d\"\n", get_client_dap_minor());
01003 
01004     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01005     // this at some point... jhrg
01006     if (get_client_dap_major() == 3 && get_client_dap_minor() == 2) {
01007     fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
01008 
01009     fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
01010             c_dap32_namespace.c_str(), c_default_dap32_schema_location.c_str());
01011     }
01012     else {
01013         fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
01014         fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
01015                 c_dap20_namespace.c_str(), c_default_dap20_schema_location.c_str());
01016     }
01017 
01018 
01019     d_attr.print_xml(out, "    ", constrained);
01020 
01021     fprintf(out, "\n");
01022 
01023     for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
01024 
01025     fprintf(out, "\n");
01026 
01027     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01028     // the same. jhrg
01029     if (get_client_dap_major() == 2 && get_client_dap_minor() == 0) {
01030         fprintf(out, "    <dataBLOB href=\"\"/>\n");
01031     }
01032 
01033     fprintf(out, "</Dataset>\n");
01034 }
01035 //#endif
01036 
01037 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
01038 {
01039     ostream &d_out;
01040     bool d_constrained;
01041 public:
01042     VariablePrintXMLStrm(ostream &out, bool constrained)
01043             : d_out(out), d_constrained(constrained)
01044     {}
01045     void operator()(BaseType *bt)
01046     {
01047         bt->print_xml(d_out, "    ", d_constrained);
01048     }
01049 };
01050 
01061 void
01062 DDS::print_xml(ostream &out, bool constrained, const string &)
01063 {
01064     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
01065 
01066     out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
01067 
01068     out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
01069 
01070     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01071     // this at some point... jhrg
01072     if (get_client_dap_major() == 3 && get_client_dap_minor() == 2) {
01073         out << "xsi:schemaLocation=\"" << c_dap32_namespace
01074             << "  " << c_default_dap32_schema_location << "\"\n" ;
01075 
01076         out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
01077         out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
01078 
01079         out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
01080         out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
01081 
01082         out << "dap_version=\"" << get_client_dap_major() << "."
01083             << get_client_dap_minor() << "\"\n";
01084 
01085         if (!get_request_xml_base().empty()) {
01086             out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
01087             out << "xml:base=\"" << get_request_xml_base() << "\"\n";
01088         }
01089 
01090         // Close the Dataset element
01091         out << ">\n";
01092     }
01093     else {
01094         out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
01095         out << "xsi:schemaLocation=\"" << c_dap20_namespace
01096             << "  " << c_default_dap20_schema_location << "\">\n\n" ;
01097     }
01098 
01099     d_attr.print_xml(out, "    ", constrained);
01100 
01101     out << "\n" ;
01102 
01103     for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
01104 
01105     out << "\n" ;
01106 
01107     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01108     // the same. jhrg
01109     if (get_client_dap_major() == 2 && get_client_dap_minor() == 0) {
01110         out << "    <dataBLOB href=\"\"/>\n" ;
01111     }
01112 
01113     out << "</Dataset>\n" ;
01114 }
01115 
01116 // Used by DDS::send() when returning data from a function call.
01131 bool
01132 DDS::check_semantics(bool all)
01133 {
01134     // The dataset must have a name
01135     if (name == "") {
01136         cerr << "A dataset must have a name" << endl;
01137         return false;
01138     }
01139 
01140     string msg;
01141     if (!unique_names(vars, name, "Dataset", msg))
01142         return false;
01143 
01144     if (all)
01145         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01146             if (!(*i)->check_semantics(msg, true))
01147                 return false;
01148 
01149     return true;
01150 }
01151 
01177 bool
01178 DDS::mark(const string &n, bool state)
01179 {
01180     BaseType::btp_stack *s = new BaseType::btp_stack;
01181 
01182     DBG2(cerr << "DDS::mark: Looking for " << n << endl);
01183 
01184     BaseType *variable = var(n, s);
01185     if (!variable) {
01186         DBG2(cerr << "Could not find variable " << n << endl);
01187         delete s; s = 0;
01188         return false;
01189     }
01190     variable->set_send_p(state);
01191 
01192     DBG2(cerr << "DDS::mark: Set variable " << variable->name()
01193             << " (a " << variable->type_name() << ")" << endl);
01194 
01195     // Now check the btp_stack and run BaseType::set_send_p for every
01196     // BaseType pointer on the stack. Using BaseType::set_send_p() will
01197     // set the property for a Constructor but not its contained variables
01198     // which preserves the semantics of projecting just one field.
01199     while (!s->empty()) {
01200         s->top()->BaseType::set_send_p(state);
01201 
01202         DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
01203                 << " (a " << s->top()->type_name() << ")" << endl);
01204         string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
01205         string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
01206         DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
01207 
01208         s->pop();
01209     }
01210 
01211     delete s ; s = 0;
01212 
01213     return true;
01214 }
01215 
01221 void
01222 DDS::mark_all(bool state)
01223 {
01224     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01225         (*i)->set_send_p(state);
01226 }
01227 
01235 void
01236 DDS::dump(ostream &strm) const
01237 {
01238     strm << DapIndent::LMarg << "DDS::dump - ("
01239     << (void *)this << ")" << endl ;
01240     DapIndent::Indent() ;
01241     strm << DapIndent::LMarg << "name: " << name << endl ;
01242     strm << DapIndent::LMarg << "filename: " << _filename << endl ;
01243     strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
01244     strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
01245     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
01246 
01247     strm << DapIndent::LMarg << "global attributes:" << endl ;
01248     DapIndent::Indent() ;
01249     d_attr.dump(strm) ;
01250     DapIndent::UnIndent() ;
01251 
01252     if (vars.size()) {
01253         strm << DapIndent::LMarg << "vars:" << endl ;
01254         DapIndent::Indent() ;
01255         Vars_citer i = vars.begin() ;
01256         Vars_citer ie = vars.end() ;
01257         for (; i != ie; i++) {
01258             (*i)->dump(strm) ;
01259         }
01260         DapIndent::UnIndent() ;
01261     }
01262     else {
01263         strm << DapIndent::LMarg << "vars: none" << endl ;
01264     }
01265 
01266     DapIndent::UnIndent() ;
01267 }
01268 
01269 } // namespace libdap