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 23577 2010-09-14 22:20:18Z 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 
00071 #include "Byte.h"
00072 #include "Int16.h"
00073 #include "UInt16.h"
00074 #include "Int32.h"
00075 #include "UInt32.h"
00076 #include "Float32.h"
00077 #include "Float64.h"
00078 #include "Str.h"
00079 #include "Url.h"
00080 #include "Array.h"
00081 #include "Structure.h"
00082 #include "Sequence.h"
00083 #include "Grid.h"
00084 
00085 #include "escaping.h"
00086 
00087 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
00088 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
00089 
00090 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
00091 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
00092 
00093 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
00094 
00095 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
00096 
00097 using namespace std;
00098 
00099 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
00100 int ddsparse(void *arg);
00101 
00102 // Glue for the DDS parser defined in dds.lex
00103 void dds_switch_to_buffer(void *new_buffer);
00104 void dds_delete_buffer(void * buffer);
00105 void *dds_buffer(FILE *fp);
00106 
00107 namespace libdap {
00108 
00109 void
00110 DDS::duplicate(const DDS &dds)
00111 {
00112     DBG(cerr << "Entering DDS::duplicate... " <<endl);
00113     name = dds.name;
00114     d_filename = dds.d_filename;
00115     d_container_name = dds.d_container_name;
00116     d_timeout = dds.d_timeout;
00117     d_attr = dds.d_attr;
00118 
00119     d_factory = dds.d_factory;
00120     d_container = dds.d_container;
00121     d_dap_major = dds.d_dap_major;
00122     d_dap_minor = dds.d_dap_minor;
00123 
00124     DDS &dds_tmp = const_cast<DDS &>(dds);
00125 
00126     // copy the things pointed to by the list, not just the pointers
00127     for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
00128         add_var(*i); // add_var() dups the BaseType.
00129     }
00130 }
00131 
00142 DDS::DDS(BaseTypeFactory *factory, const string &n)
00143 
00144         : d_factory(factory), name(n), d_container(0), d_dap_major(2),
00145         d_dap_minor(0),
00146         d_request_xml_base(""), d_timeout(0)
00147 {
00148     DBG(cerr << "Building a DDS with client major/minor: "
00149             << d_dap_major << "." << d_dap_minor << endl);
00150 }
00151 
00153 DDS::DDS(const DDS &rhs) : DapObj()
00154 {
00155     DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
00156     duplicate(rhs);
00157     DBG(cerr << " bye." << endl);
00158 }
00159 
00160 DDS::~DDS()
00161 {
00162     // delete all the variables in this DDS
00163     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00164         BaseType *btp = *i ;
00165         delete btp ; btp = 0;
00166     }
00167 }
00168 
00169 DDS &
00170 DDS::operator=(const DDS &rhs)
00171 {
00172     DBG(cerr << "Entering DDS::operator= ..." << endl);
00173     if (this == &rhs)
00174         return *this;
00175 
00176     duplicate(rhs);
00177 
00178     DBG(cerr << " bye." << endl);
00179     return *this;
00180 }
00181 
00182 #if 0
00183 
00198 BaseType *
00199 DDS::find_hdf4_dimension_attribute_home(AttrTable::entry *source)
00200 {
00201     BaseType *btp;
00202     string::size_type i = source->name.find("_dim_");
00203     if (i != string::npos && (btp = var(source->name.substr(0, i)))) {
00204         if (btp->is_vector_type()) {
00205             return btp;
00206         }
00207         else if (btp->type() == dods_grid_c) {
00208             // For a Grid, the hdf4 handler uses _dim_n for the n-th Map
00209             // i+5 points to the character holding 'n'
00210             int n = atoi(source->name.substr(i + 5).c_str());
00211             DBG(cerr << "Found a Grid (" << btp->name() << ") and "
00212                 << source->name.substr(i) << ", extracted n: " << n << endl);
00213             return *(dynamic_cast<Grid&>(*btp).map_begin() + n);
00214         }
00215     }
00216 
00217     return 0;
00218 }
00219 
00225 AttrTable *
00226 DDS::find_matching_container(AttrTable::entry *source, BaseType **dest_variable)
00227 {
00228     // The attribute entry 'source' must be a container
00229     if (source->type != Attr_container)
00230         throw InternalErr(__FILE__, __LINE__, "DDS::find_matching_container; expected 'source' to be a container.");
00231 
00232     // Use the name of the attribute container 'source' to figure out where
00233     // to put its contents.
00234     BaseType *btp;
00235     if ((btp = var(source->name))) {
00236         // ... matches a variable name? Use var's table
00237         *dest_variable = btp;
00238         return &btp->get_attr_table();
00239     }
00240     else if ((btp = find_hdf4_dimension_attribute_home(source))) {
00241         // ... hdf4 dimension attribute? Make a sub table and use that.
00242         // btp can only be an Array or a Grid Map (which is an array)
00243         if (btp->get_parent() && btp->get_parent()->type() == dods_grid_c) {
00244             DBG(cerr << "Found a Grid, assigning to the map" << endl);
00245             *dest_variable = btp;
00246             return &btp->get_attr_table();
00247         }
00248         else { // must be a plain Array
00249             string::size_type i = source->name.find("_dim_");
00250             string ext = source->name.substr(i + 1);
00251             *dest_variable = btp;
00252             return btp->get_attr_table().append_container(ext);
00253         }
00254     }
00255     else {
00256         // ... otherwise assume it's a global attribute.
00257         AttrTable *at = d_attr.find_container(source->name);
00258         if (!at) {
00259             at = new AttrTable();       // Make a new global table if needed
00260             d_attr.append_container(at, source->name);
00261         }
00262 
00263         *dest_variable = 0;
00264         return at;
00265     }
00266 }
00267 
00289 void
00290 DDS::transfer_attributes(DAS *das)
00291 {
00292     // If there is a container set in the DDS then get the container from
00293     // the DAS. If they are not the same container, then throw an exception
00294     // (should be working on the same container). If the container does not
00295     // exist in the DAS, then throw an exception
00296     if( d_container )
00297     {
00298         if( das->container_name() != d_container_name )
00299         {
00300             string err = (string)"Error transferring attributes: "
00301                          + "working on container in dds, but not das" ;
00302             throw InternalErr(__FILE__, __LINE__, err ) ;
00303         }
00304     }
00305 
00306     AttrTable *top_level = das->get_top_level_attributes() ;
00307 
00308     // foreach container at the outer level
00309     AttrTable::Attr_iter das_i = top_level->attr_begin();
00310     AttrTable::Attr_iter das_e = top_level->attr_end();
00311     while (das_i != das_e) {
00312         DBG(cerr << "Working on the '" << (*das_i)->name << "' container."
00313             << endl);
00314 
00315         AttrTable *source = (*das_i)->attributes;
00316         // Variable that holds 'dest'; null for a global attribute.
00317         BaseType *dest_variable = 0;
00318         AttrTable *dest = find_matching_container(*das_i, &dest_variable);
00319 
00320         // foreach source attribute in the das_i container
00321         AttrTable::Attr_iter source_p = source->attr_begin();
00322         while (source_p != source->attr_end()) {
00323             DBG(cerr << "Working on the '" << (*source_p)->name << "' attribute"
00324                 << endl);
00325 
00326             // If this is an attribute container, we must have a container
00327             // (this one) within a container (the 'source'). Look and see if
00328             // the variable is a Constructor. If so, pass that container into
00329             // Constructor::transfer_attributes()
00330             if ((*source_p)->type == Attr_container) {
00331                 if (dest_variable && dest_variable->is_constructor_type()) {
00332                     dynamic_cast<Constructor&>(*dest_variable).transfer_attributes(*source_p);
00333                 }
00334                 else {
00335                     dest->append_container(new AttrTable(*(*source_p)->attributes),
00336                                            (*source_p)->name);
00337                 }
00338             }
00339             else {
00340                 dest->append_attr(source->get_name(source_p),
00341                                   source->get_type(source_p),
00342                                   source->get_attr_vector(source_p));
00343             }
00344 
00345             ++source_p;
00346         }
00347 
00348         ++das_i;
00349     }
00350 }
00351 #endif
00352 
00366 void
00367 DDS::transfer_attributes(DAS *das)
00368 {
00369     // If there is a container set in the DDS then get the container from
00370     // the DAS. If they are not the same container, then throw an exception
00371     // (should be working on the same container). If the container does not
00372     // exist in the DAS, then throw an exception
00373     if( d_container )
00374     {
00375         if( das->container_name() != d_container_name )
00376             throw InternalErr(__FILE__, __LINE__, "Error transferring attributes: working on a container in dds, but not das" ) ;
00377     }
00378 
00379     // Give each variable a chance to claim its attributes.
00380     AttrTable *top_level = das->get_top_level_attributes() ;
00381 
00382     Vars_iter var = var_begin();
00383     while (var != var_end()) {
00384         (*var)->transfer_attributes(top_level);
00385         var++;
00386     }
00387 
00388     // Now we transfer all of the attributes still marked as global to the
00389     // global container in the DDS.
00390 
00391     AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
00392     while (at_cont_p != top_level->attr_end()) {
00393         // In truth, all of the top level attributes should be containers, but
00394         // this test handles the abnormal case where somehow someone makes a
00395         // top level attribute that is not a container by silently dropping it.
00396         if ((*at_cont_p)->type == Attr_container
00397                 && (*at_cont_p)->attributes->is_global_attribute()) {
00398             DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl);
00399             // copy the source container so that the DAS passed in can be
00400             // deleted after calling htis method.
00401             AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
00402             d_attr.append_container(at, at->get_name());
00403         }
00404 
00405         at_cont_p++;
00406     }
00407 }
00408 
00409 #if 0
00410     // cruft from the above method
00411 
00412             AttrTable *dest = d_attr.find_container(at->get_name());
00413             if (!dest) {
00414                 cerr << "making a new sub containter for it" << endl;
00415                 // If there's currently no top level container with this
00416                 //container's name (the typical case) make one.
00417                 dest = new AttrTable(); // Make a new global table if needed
00418                 d_attr.append_container(dest, at->get_name());
00419             }
00420 
00421             cerr << "now copying its contents to the new container" << endl;
00422             // Now copy all of the global attribute's stuff into the matching
00423             // container in the DDS.
00424             AttrTable::Attr_iter at_p = at->attr_begin();
00425             while (at_p != at->attr_end()) {
00426                 if (at->get_attr_type(at_p) == Attr_container)
00427                     dest->append_container(at->get_attr_table(at_p), at->get_name(at_p));
00428                 else
00429                     dest->append_attr(at->get_name(at_p), at->get_type(at_p), at->get_attr_vector(at_p));
00430                 at_p++;
00431             }
00432 #endif
00433 
00441 
00443 string
00444 DDS::get_dataset_name() const
00445 {
00446     return name;
00447 }
00448 
00450 void
00451 DDS::set_dataset_name(const string &n)
00452 {
00453     name = n;
00454 }
00455 
00457 
00459 AttrTable &
00460 DDS::get_attr_table()
00461 {
00462     return d_attr;
00463 }
00464 
00474 string
00475 DDS::filename()
00476 {
00477     return d_filename;
00478 }
00479 
00481 void
00482 DDS::filename(const string &fn)
00483 {
00484     d_filename = fn;
00485 }
00487 
00493 void
00494 DDS::set_dap_version(const string &version_string)
00495 {
00496     istringstream iss(version_string);
00497 
00498     int major = -1, minor = -1;
00499     char dot;
00500     iss >> major;
00501     iss >> dot;
00502     iss >> minor;
00503 
00504     DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
00505 
00506     if (major == -1 || minor == -1)
00507         throw Error("Could not parse the client dap (XDAP-Accept header) value");
00508 
00509     set_dap_major(major);
00510     set_dap_minor(minor);
00511 }
00512 
00522 string
00523 DDS::container_name()
00524 {
00525     return d_container_name;
00526 }
00527 
00530 void
00531 DDS::container_name(const string &cn)
00532 {
00533     // we want to search the DDS for the top level structure with the given
00534     // name. Set the container to null so that we don't search some previous
00535     // container.
00536     d_container = 0 ;
00537     if( !cn.empty() )
00538     {
00539         d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00540         if( !d_container )
00541         {
00542             // create a structure for this container. Calling add_var
00543             // while_container is null will add the new structure to DDS and
00544             // not some sub structure. Adding the new structure makes a copy
00545             // of it.  So after adding it, go get it and set d_container.
00546             Structure *s = new Structure( cn ) ;
00547             add_var( s ) ;
00548             delete s ;
00549             s = 0 ;
00550             d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00551         }
00552     }
00553     d_container_name = cn;
00554 
00555 }
00556 
00558 Structure *
00559 DDS::container()
00560 {
00561     return d_container ;
00562 }
00563 
00565 
00571 void
00572 DDS::add_var(BaseType *bt)
00573 {
00574     if (!bt)
00575         throw InternalErr(__FILE__, __LINE__,
00576                           "Trying to add a BaseType object with a NULL pointer.");
00577 
00578     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00579 
00580     BaseType *btp = bt->ptr_duplicate();
00581     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00582     if( d_container )
00583     {
00584         // Mem leak fix [mjohnson nov 2009]
00585         // Structure::add_var() creates ANOTHER copy.
00586         d_container->add_var( bt ) ;
00587         // So we need to delete btp or else it leaks
00588         delete btp; btp = 0;
00589     }
00590     else
00591     {
00592         vars.push_back(btp);
00593     }
00594 }
00595 
00602 void
00603 DDS::del_var(const string &n)
00604 {
00605     if( d_container )
00606     {
00607         d_container->del_var( n ) ;
00608         return ;
00609     }
00610 
00611     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00612         if ((*i)->name() == n) {
00613             BaseType *bt = *i ;
00614             vars.erase(i) ;
00615             delete bt ; bt = 0;
00616             return;
00617         }
00618     }
00619 }
00620 
00625 void
00626 DDS::del_var(Vars_iter i)
00627 {
00628     if (i != vars.end()) {
00629         BaseType *bt = *i ;
00630         vars.erase(i) ;
00631         delete bt ; bt = 0;
00632     }
00633 }
00634 
00641 void
00642 DDS::del_var(Vars_iter i1, Vars_iter i2)
00643 {
00644     for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
00645         BaseType *bt = *i_tmp ;
00646         delete bt ; bt = 0;
00647     }
00648     vars.erase(i1, i2) ;
00649 }
00650 
00658 BaseType *
00659 DDS::var(const string &n, BaseType::btp_stack &s)
00660 {
00661     return var(n, &s);
00662 }
00682 BaseType *
00683 DDS::var(const string &n, BaseType::btp_stack *s)
00684 {
00685     string name = www2id(n);
00686     if( d_container )
00687         return d_container->var( name, false, s ) ;
00688 
00689     BaseType *v = exact_match(name, s);
00690     if (v)
00691         return v;
00692 
00693     return leaf_match(name, s);
00694 }
00695 
00696 BaseType *
00697 DDS::leaf_match(const string &n, BaseType::btp_stack *s)
00698 {
00699     DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
00700 
00701     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00702         BaseType *btp = *i;
00703         DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
00704         // Look for the name in the dataset's top-level
00705         if (btp->name() == n) {
00706             DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00707             return btp;
00708         }
00709 
00710         if (btp->is_constructor_type()) {
00711             BaseType *found = btp->var(n, false, s);
00712             if (found) {
00713                 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00714                 return found;
00715             }
00716         }
00717 #if STRUCTURE_ARRAY_SYNTAX_OLD
00718         if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
00719             s->push(btp);
00720             BaseType *found = btp->var()->var(n, false, s);
00721             if (found) {
00722                 DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
00723                 return found;
00724             }
00725         }
00726 #endif
00727     }
00728 
00729     return 0;   // It is not here.
00730 }
00731 
00732 BaseType *
00733 DDS::exact_match(const string &name, BaseType::btp_stack *s)
00734 {
00735     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00736         BaseType *btp = *i;
00737         DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
00738         // Look for the name in the current ctor type or the top level
00739         if (btp->name() == name) {
00740             DBG2(cerr << "Found " << name << " in: " << btp << endl);
00741             return btp;
00742         }
00743     }
00744 
00745     string::size_type dot_pos = name.find(".");
00746     if (dot_pos != string::npos) {
00747         string aggregate = name.substr(0, dot_pos);
00748         string field = name.substr(dot_pos + 1);
00749 
00750         BaseType *agg_ptr = var(aggregate, s);
00751         if (agg_ptr) {
00752             DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
00753             return agg_ptr->var(field, true, s);
00754         }
00755         else
00756             return 0;  // qualified names must be *fully* qualified
00757     }
00758 
00759     return 0;   // It is not here.
00760 }
00761 
00762 
00765 DDS::Vars_iter
00766 DDS::var_begin()
00767 {
00768     return vars.begin();
00769 }
00770 
00771 DDS::Vars_riter
00772 DDS::var_rbegin()
00773 {
00774     return vars.rbegin();
00775 }
00776 
00777 DDS::Vars_iter
00778 DDS::var_end()
00779 {
00780     return vars.end() ;
00781 }
00782 
00783 DDS::Vars_riter
00784 DDS::var_rend()
00785 {
00786     return vars.rend() ;
00787 }
00788 
00792 DDS::Vars_iter
00793 DDS::get_vars_iter(int i)
00794 {
00795     return vars.begin() + i;
00796 }
00797 
00801 BaseType *
00802 DDS::get_var_index(int i)
00803 {
00804     return *(vars.begin() + i);
00805 }
00806 
00808 int
00809 DDS::num_var()
00810 {
00811     return vars.size();
00812 }
00813 
00814 void
00815 DDS::timeout_on()
00816 {
00817 #ifndef WIN32
00818     alarm(d_timeout);
00819 #endif
00820 }
00821 
00822 void
00823 DDS::timeout_off()
00824 {
00825 #ifndef WIN32
00826     d_timeout = alarm(0);
00827 #endif
00828 }
00829 
00830 void
00831 DDS::set_timeout(int t)
00832 {
00833     //  Has no effect under win32
00834     d_timeout = t;
00835 }
00836 
00837 int
00838 DDS::get_timeout()
00839 {
00840     //  Has to effect under win32
00841     return d_timeout;
00842 }
00843 
00845 void
00846 DDS::tag_nested_sequences()
00847 {
00848     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00849         if ((*i)->type() == dods_sequence_c)
00850             dynamic_cast<Sequence&>(**i).set_leaf_sequence();
00851         else if ((*i)->type() == dods_structure_c)
00852             dynamic_cast<Structure&>(**i).set_leaf_sequence();
00853     }
00854 }
00855 
00857 void
00858 DDS::parse(string fname)
00859 {
00860     FILE *in = fopen(fname.c_str(), "r");
00861 
00862     if (!in) {
00863         throw Error(cannot_read_file, "Could not open: " + fname);
00864     }
00865 
00866     try {
00867         parse(in);
00868         fclose(in);
00869     }
00870     catch (Error &e) {
00871         fclose(in);
00872         throw e;
00873     }
00874 }
00875 
00876 
00878 void
00879 DDS::parse(int fd)
00880 {
00881 #ifdef WIN32
00882     FILE *in = fdopen(_dup(fd), "r");
00883 #else
00884     FILE *in = fdopen(dup(fd), "r");
00885 #endif
00886 
00887     if (!in) {
00888         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00889     }
00890 
00891     try {
00892         parse(in);
00893         fclose(in);
00894     }
00895     catch (Error &e) {
00896         fclose(in);
00897         throw e;
00898     }
00899 }
00900 
00907 void
00908 DDS::parse(FILE *in)
00909 {
00910     if (!in) {
00911         throw InternalErr(__FILE__, __LINE__, "Null input stream.");
00912     }
00913 
00914     void *buffer = dds_buffer(in);
00915     dds_switch_to_buffer(buffer);
00916 
00917     parser_arg arg(this);
00918 
00919     bool status = ddsparse((void *) & arg) == 0;
00920 
00921     dds_delete_buffer(buffer);
00922 
00923     DBG2(cout << "Status from parser: " << status << endl);
00924 
00925     //  STATUS is the result of the parser function; if a recoverable error
00926     //  was found it will be true but arg.status() will be false.
00927     if (!status || !arg.status()) {// Check parse result
00928         if (arg.error())
00929             throw *arg.error();
00930     }
00931 }
00932 
00933 #if FILE_METHODS
00934 
00935 void
00936 DDS::print(FILE *out)
00937 {
00938 #if 0
00939     ostringstream oss;
00940     print(oss);
00941 
00942     fwrite(oss.str().c_str(), oss.str().length(), 1, out);
00943 #else
00944     fprintf(out, "Dataset {\n") ;
00945 
00946     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00947         (*i)->print_decl(out) ;
00948     }
00949 
00950     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00951 
00952     return ;
00953 #endif
00954 }
00955 #endif
00956 
00958 void
00959 DDS::print(ostream &out)
00960 {
00961     out << "Dataset {\n" ;
00962 
00963     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00964         (*i)->print_decl(out) ;
00965     }
00966 
00967     out << "} " << id2www(name) << ";\n" ;
00968 
00969     return ;
00970 }
00971 
00972 #if FILE_METHODS
00973 
00983 void
00984 DDS::print_constrained(FILE *out)
00985 {
00986     fprintf(out, "Dataset {\n") ;
00987 
00988     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00989         // for each variable, indent with four spaces, print a trailing
00990         // semicolon, do not print debugging information, print only
00991         // variables in the current projection.
00992         (*i)->print_decl(out, "    ", true, false, true) ;
00993     }
00994 
00995     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00996 
00997     return;
00998 }
00999 #endif
01000 
01011 void
01012 DDS::print_constrained(ostream &out)
01013 {
01014     out << "Dataset {\n" ;
01015 
01016     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
01017         // for each variable, indent with four spaces, print a trailing
01018         // semicolon, do not print debugging information, print only
01019         // variables in the current projection.
01020         (*i)->print_decl(out, "    ", true, false, true) ;
01021     }
01022 
01023     out << "} " << id2www(name) << ";\n" ;
01024 
01025     return;
01026 }
01027 
01028 #if FILE_METHODS
01029 class VariablePrintXML : public unary_function<BaseType *, void>
01030 {
01031     FILE *d_out;
01032     bool d_constrained;
01033 public:
01034     VariablePrintXML(FILE *out, bool constrained)
01035             : d_out(out), d_constrained(constrained)
01036     {}
01037     void operator()(BaseType *bt)
01038     {
01039         bt->print_xml(d_out, "    ", d_constrained);
01040     }
01041 };
01042 
01053 void
01054 DDS::print_xml(FILE *out, bool constrained, const string &blob)
01055 {
01056     fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
01057 
01058     fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
01059 
01060     fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
01061 
01062     fprintf(out,"method=\"FILE*\"\n");
01063     fprintf(out, "dap_major=\"%d\"\n", get_dap_major());
01064     fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor());
01065 
01066     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01067     // this at some point... jhrg
01068     if (get_dap_major() == 3 && get_dap_minor() == 2) {
01069     fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
01070 
01071     fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
01072             c_dap32_namespace.c_str(), c_default_dap32_schema_location.c_str());
01073     }
01074     else {
01075         fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
01076         fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
01077                 c_dap20_namespace.c_str(), c_default_dap20_schema_location.c_str());
01078     }
01079 
01080 
01081     d_attr.print_xml(out, "    ", constrained);
01082 
01083     fprintf(out, "\n");
01084 
01085     for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
01086 
01087     fprintf(out, "\n");
01088 
01089     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01090     // the same. jhrg
01091     if (get_dap_major() == 2 && get_dap_minor() == 0) {
01092         fprintf(out, "    <dataBLOB href=\"\"/>\n");
01093     }
01094     else if (!blob.empty()
01095              && (get_dap_major() == 3 && get_dap_minor() >= 2)
01096              || get_dap_major() >= 4) {
01097         fprintf(out, "    <blob href=\"cid:%s\"/>\n", blob.c_str());
01098     }
01099 
01100 
01101     fprintf(out, "</Dataset>\n");
01102 }
01103 #endif
01104 
01105 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
01106 {
01107     ostream &d_out;
01108     bool d_constrained;
01109 public:
01110     VariablePrintXMLStrm(ostream &out, bool constrained)
01111             : d_out(out), d_constrained(constrained)
01112     {}
01113     void operator()(BaseType *bt)
01114     {
01115         bt->print_xml(d_out, "    ", d_constrained);
01116     }
01117 };
01118 
01129 void
01130 DDS::print_xml(ostream &out, bool constrained, const string &blob)
01131 {
01132     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
01133 
01134     out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
01135 
01136     out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
01137 
01138     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01139     // this at some point... jhrg
01140     if (get_dap_major() == 3 && get_dap_minor() == 2) {
01141         out << "xsi:schemaLocation=\"" << c_dap32_namespace
01142             << "  " << c_default_dap32_schema_location << "\"\n" ;
01143 
01144         out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
01145         out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
01146 
01147         out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
01148         out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
01149 
01150         out << "dapVersion=\"" << get_dap_major() << "."
01151             << get_dap_minor() << "\"";
01152 
01153         if (!get_request_xml_base().empty()) {
01154             out << "\n";
01155             out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
01156             out << "xml:base=\"" << get_request_xml_base() << "\"";
01157         }
01158 
01159         // Close the Dataset element
01160         out << ">\n";
01161     }
01162     else {
01163         out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
01164         out << "xsi:schemaLocation=\"" << c_dap20_namespace
01165             << "  " << c_default_dap20_schema_location << "\">\n\n" ;
01166     }
01167 
01168     d_attr.print_xml(out, "    ", constrained);
01169 
01170     out << "\n" ;
01171 
01172     for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
01173 
01174     out << "\n" ;
01175 
01176     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01177     // the same.
01178     // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
01179     // actually the CID of the MIME part that holds the data.
01180     if (get_dap_major() == 2 && get_dap_minor() == 0) {
01181         out << "    <dataBLOB href=\"\"/>\n" ;
01182     }
01183     else if (!blob.empty()
01184              && (get_dap_major() == 3 && get_dap_minor() >= 2)
01185              || get_dap_major() >= 4) {
01186         out << "    <blob href=\"cid:" << blob << "\"/>\n";
01187     }
01188 
01189     out << "</Dataset>\n" ;
01190 }
01191 
01192 // Used by DDS::send() when returning data from a function call.
01207 bool
01208 DDS::check_semantics(bool all)
01209 {
01210     // The dataset must have a name
01211     if (name == "") {
01212         cerr << "A dataset must have a name" << endl;
01213         return false;
01214     }
01215 
01216     string msg;
01217     if (!unique_names(vars, name, "Dataset", msg))
01218         return false;
01219 
01220     if (all)
01221         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01222             if (!(*i)->check_semantics(msg, true))
01223                 return false;
01224 
01225     return true;
01226 }
01227 
01253 bool
01254 DDS::mark(const string &n, bool state)
01255 {
01256     BaseType::btp_stack *s = new BaseType::btp_stack;
01257 
01258     DBG2(cerr << "DDS::mark: Looking for " << n << endl);
01259 
01260     BaseType *variable = var(n, s);
01261     if (!variable) {
01262         DBG2(cerr << "Could not find variable " << n << endl);
01263         delete s; s = 0;
01264         return false;
01265     }
01266     variable->set_send_p(state);
01267 
01268     DBG2(cerr << "DDS::mark: Set variable " << variable->name()
01269             << " (a " << variable->type_name() << ")" << endl);
01270 
01271     // Now check the btp_stack and run BaseType::set_send_p for every
01272     // BaseType pointer on the stack. Using BaseType::set_send_p() will
01273     // set the property for a Constructor but not its contained variables
01274     // which preserves the semantics of projecting just one field.
01275     while (!s->empty()) {
01276         s->top()->BaseType::set_send_p(state);
01277 
01278         DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
01279                 << " (a " << s->top()->type_name() << ")" << endl);
01280         string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
01281         string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
01282         DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
01283 
01284         s->pop();
01285     }
01286 
01287     delete s ; s = 0;
01288 
01289     return true;
01290 }
01291 
01297 void
01298 DDS::mark_all(bool state)
01299 {
01300     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01301         (*i)->set_send_p(state);
01302 }
01303 
01311 void
01312 DDS::dump(ostream &strm) const
01313 {
01314     strm << DapIndent::LMarg << "DDS::dump - ("
01315     << (void *)this << ")" << endl ;
01316     DapIndent::Indent() ;
01317     strm << DapIndent::LMarg << "name: " << name << endl ;
01318     strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
01319     strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
01320     strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
01321     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
01322 
01323     strm << DapIndent::LMarg << "global attributes:" << endl ;
01324     DapIndent::Indent() ;
01325     d_attr.dump(strm) ;
01326     DapIndent::UnIndent() ;
01327 
01328     if (vars.size()) {
01329         strm << DapIndent::LMarg << "vars:" << endl ;
01330         DapIndent::Indent() ;
01331         Vars_citer i = vars.begin() ;
01332         Vars_citer ie = vars.end() ;
01333         for (; i != ie; i++) {
01334             (*i)->dump(strm) ;
01335         }
01336         DapIndent::UnIndent() ;
01337     }
01338     else {
01339         strm << DapIndent::LMarg << "vars: none" << endl ;
01340     }
01341 
01342     DapIndent::UnIndent() ;
01343 }
01344 
01345 } // namespace libdap