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 25066 2011-11-30 18:39:37Z jimg $"
00038     };
00039 
00040 #include <cstdio>
00041 #include <sys/types.h>
00042 
00043 #ifdef WIN32
00044 #include <io.h>
00045 #include <process.h>
00046 #include <fstream>
00047 #else
00048 #include <unistd.h>    // for alarm and dup
00049 #include <sys/wait.h>
00050 #endif
00051 
00052 #include <iostream>
00053 #include <sstream>
00054 #include <algorithm>
00055 #include <functional>
00056 
00057 //#define DODS_DEBUG
00058 //#define DODS_DEBUG2
00059 
00060 #include "GNURegex.h"
00061 
00062 #include "DAS.h"
00063 #include "Clause.h"
00064 #include "Error.h"
00065 #include "InternalErr.h"
00066 #include "Keywords2.h"
00067 
00068 #include "parser.h"
00069 #include "debug.h"
00070 #include "util.h"
00071 
00072 #include "Byte.h"
00073 #include "Int16.h"
00074 #include "UInt16.h"
00075 #include "Int32.h"
00076 #include "UInt32.h"
00077 #include "Float32.h"
00078 #include "Float64.h"
00079 #include "Str.h"
00080 #include "Url.h"
00081 #include "Array.h"
00082 #include "Structure.h"
00083 #include "Sequence.h"
00084 #include "Grid.h"
00085 
00086 #include "escaping.h"
00087 
00088 const string c_default_dap20_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
00089 const string c_default_dap32_schema_location = "http://xml.opendap.org/dap/dap3.2.xsd";
00090 
00091 const string c_dap20_namespace = "http://xml.opendap.org/ns/DAP2";
00092 const string c_dap32_namespace = "http://xml.opendap.org/ns/DAP/3.2#";
00093 
00094 const string c_dap_20_n_sl = c_dap20_namespace + " " + c_default_dap20_schema_location;
00095 const string c_dap_32_n_sl = c_dap32_namespace + " " + c_default_dap32_schema_location;
00096 
00097 const string grddl_transformation_dap32 = "http://xml.opendap.org/transforms/ddxToRdfTriples.xsl";
00098 
00099 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
00100 
00101 using namespace std;
00102 
00103 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
00104 int ddsparse(void *arg);
00105 
00106 // Glue for the DDS parser defined in dds.lex
00107 void dds_switch_to_buffer(void *new_buffer);
00108 void dds_delete_buffer(void * buffer);
00109 void *dds_buffer(FILE *fp);
00110 
00111 namespace libdap {
00112 
00113 void
00114 DDS::duplicate(const DDS &dds)
00115 {
00116     DBG(cerr << "Entering DDS::duplicate... " <<endl);
00117     name = dds.name;
00118     d_filename = dds.d_filename;
00119     d_container_name = dds.d_container_name;
00120     d_timeout = dds.d_timeout;
00121     d_attr = dds.d_attr;
00122 
00123     d_factory = dds.d_factory;
00124     d_container = dds.d_container;
00125     d_dap_major = dds.d_dap_major;
00126     d_dap_minor = dds.d_dap_minor;
00127 
00128     d_keywords = dds.d_keywords; // value copy; Keywords contains no pointers
00129 
00130     DDS &dds_tmp = const_cast<DDS &>(dds);
00131 
00132     // copy the things pointed to by the list, not just the pointers
00133     for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
00134         add_var(*i); // add_var() dups the BaseType.
00135     }
00136 }
00137 
00148 DDS::DDS(BaseTypeFactory *factory, const string &n)
00149         : d_factory(factory), name(n), d_container(0),
00150           d_dap_major(2), d_dap_minor(0),
00151           d_request_xml_base(""), d_timeout(0), d_keywords(),
00152           d_max_response_size(0)
00153 {
00154     DBG(cerr << "Building a DDS with client major/minor: "
00155             << d_dap_major << "." << d_dap_minor << endl);
00156 }
00157 
00159 DDS::DDS(const DDS &rhs) : DapObj()
00160 {
00161     DBG(cerr << "Entering DDS(const DDS &rhs) ..." << endl);
00162     duplicate(rhs);
00163     DBG(cerr << " bye." << endl);
00164 }
00165 
00166 DDS::~DDS()
00167 {
00168     // delete all the variables in this DDS
00169     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00170         BaseType *btp = *i ;
00171         delete btp ; btp = 0;
00172     }
00173 }
00174 
00175 DDS &
00176 DDS::operator=(const DDS &rhs)
00177 {
00178     DBG(cerr << "Entering DDS::operator= ..." << endl);
00179     if (this == &rhs)
00180         return *this;
00181 
00182     duplicate(rhs);
00183 
00184     DBG(cerr << " bye." << endl);
00185     return *this;
00186 }
00187 
00201 void DDS::transfer_attributes(DAS *das) {
00202         // If there is a container set in the DDS then get the container from
00203         // the DAS. If they are not the same container, then throw an exception
00204         // (should be working on the same container). If the container does not
00205         // exist in the DAS, then throw an exception
00206         if (d_container) {
00207                 if (das->container_name() != d_container_name)
00208                         throw InternalErr(__FILE__, __LINE__,
00209                                         "Error transferring attributes: working on a container in dds, but not das");
00210         }
00211 
00212         // Give each variable a chance to claim its attributes.
00213         AttrTable *top_level = das->get_top_level_attributes();
00214 
00215         Vars_iter var = var_begin();
00216         while (var != var_end()) {
00217                 try {
00218                         DBG(cerr << "Processing the attributes for: " << (*var)->name() << " a " << (*var)->type_name() << endl);
00219                         (*var)->transfer_attributes(top_level);
00220                         var++;
00221                 } catch (Error &e) {
00222                         DBG(cerr << "Got this exception: " << e.get_error_message() << endl);
00223                         var++;
00224                         throw e;
00225                 }
00226         }
00227 
00228         // Now we transfer all of the attributes still marked as global to the
00229         // global container in the DDS.
00230 
00231         AttrTable::Attr_iter at_cont_p = top_level->attr_begin();
00232         while (at_cont_p != top_level->attr_end()) {
00233                 // In truth, all of the top level attributes should be containers, but
00234                 // this test handles the abnormal case where somehow someone makes a
00235                 // top level attribute that is not a container by silently dropping it.
00236                 if ((*at_cont_p)->type == Attr_container && (*at_cont_p)->attributes->is_global_attribute()) {
00237                         DBG(cerr << (*at_cont_p)->name << " is a global attribute." << endl);
00238                         // copy the source container so that the DAS passed in can be
00239                         // deleted after calling this method.
00240                         AttrTable *at = new AttrTable(*(*at_cont_p)->attributes);
00241                         d_attr.append_container(at, at->get_name());
00242                 }
00243 
00244                 at_cont_p++;
00245         }
00246 }
00247 
00255 
00257 string
00258 DDS::get_dataset_name() const
00259 {
00260     return name;
00261 }
00262 
00264 void
00265 DDS::set_dataset_name(const string &n)
00266 {
00267     name = n;
00268 }
00269 
00271 
00273 AttrTable &
00274 DDS::get_attr_table()
00275 {
00276     return d_attr;
00277 }
00278 
00288 string
00289 DDS::filename()
00290 {
00291     return d_filename;
00292 }
00293 
00295 void
00296 DDS::filename(const string &fn)
00297 {
00298     d_filename = fn;
00299 }
00301 
00302 void
00303 DDS::set_dap_major(int p)
00304 {
00305     d_dap_major = p;
00306 
00307     // This works because regardless of the order set_dap_major and set_dap_minor
00308     // are called, once they both are called, the value in the string is
00309     // correct. I protect against negative numbers because that would be
00310     // nonsensical.
00311     if (d_dap_minor >= 0) {
00312         ostringstream oss;
00313         oss << d_dap_major << "." << d_dap_minor;
00314         d_dap_version = oss.str();
00315     }
00316 }
00317 
00318 void
00319 DDS::set_dap_minor(int p)
00320 {
00321     d_dap_minor = p;
00322 
00323     if (d_dap_major >= 0) {
00324         ostringstream oss;
00325         oss << d_dap_major << "." << d_dap_minor;
00326         d_dap_version = oss.str();
00327     }
00328 }
00329 
00336 void
00337 DDS::set_dap_version(const string &version_string)
00338 {
00339     istringstream iss(version_string);
00340 
00341     int major = -1, minor = -1;
00342     char dot;
00343     if (!iss.eof() && !iss.fail())
00344         iss >> major;
00345     if (!iss.eof() && !iss.fail())
00346         iss >> dot;
00347     if (!iss.eof() && !iss.fail())
00348         iss >> minor;
00349 
00350     DBG(cerr << "Major: " << major << ", dot: " << dot <<", Minor: " << minor << endl);
00351 #if 0
00352     if (major == -1 || minor == -1)
00353         throw Error("Could not parse the client dap (XDAP-Accept header) value");
00354 #endif
00355 
00356     d_dap_version = version_string;
00357 
00358     set_dap_major(major == -1 ? 2 : major);
00359     set_dap_minor(minor == -1 ? 0 : minor);
00360 }
00361 
00369 void
00370 DDS::set_dap_version(double d)
00371 {
00372     int major = d;
00373     int minor = (d-major)*10;
00374 
00375     DBG(cerr << "Major: " << major << ", Minor: " << minor << endl);
00376 
00377     ostringstream oss;
00378     oss << major << "." << minor;
00379     d_dap_version = oss.str();
00380 
00381     set_dap_major(major);
00382     set_dap_minor(minor);
00383 }
00384 
00394 string
00395 DDS::container_name()
00396 {
00397     return d_container_name;
00398 }
00399 
00402 void
00403 DDS::container_name(const string &cn)
00404 {
00405     // we want to search the DDS for the top level structure with the given
00406     // name. Set the container to null so that we don't search some previous
00407     // container.
00408     d_container = 0 ;
00409     if( !cn.empty() )
00410     {
00411         d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00412         if( !d_container )
00413         {
00414             // create a structure for this container. Calling add_var
00415             // while_container is null will add the new structure to DDS and
00416             // not some sub structure. Adding the new structure makes a copy
00417             // of it.  So after adding it, go get it and set d_container.
00418             Structure *s = new Structure( cn ) ;
00419             add_var( s ) ;
00420             delete s ;
00421             s = 0 ;
00422             d_container = dynamic_cast<Structure *>( var( cn ) ) ;
00423         }
00424     }
00425     d_container_name = cn;
00426 
00427 }
00428 
00430 Structure *
00431 DDS::container()
00432 {
00433     return d_container ;
00434 }
00435 
00437 
00448 int
00449 DDS::get_request_size(bool constrained)
00450 {
00451         int w = 0;
00452     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00453         if (constrained) {
00454                 if ((*i)->send_p())
00455                         w += (*i)->width(constrained);
00456         }
00457         else {
00458                 w += (*i)->width(constrained);
00459         }
00460     }
00461 
00462     return w;
00463 }
00464 
00470 void DDS::add_var(BaseType *bt) {
00471     if (!bt)
00472         throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
00473 
00474     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00475 
00476     BaseType *btp = bt->ptr_duplicate();
00477     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00478     if (d_container) {
00479         // Mem leak fix [mjohnson nov 2009]
00480         // Structure::add_var() creates ANOTHER copy.
00481         d_container->add_var(bt);
00482         // So we need to delete btp or else it leaks
00483         delete btp;
00484         btp = 0;
00485     }
00486     else {
00487         vars.push_back(btp);
00488     }
00489 }
00490 
00493 void DDS::add_var_nocopy(BaseType *bt) {
00494     if (!bt)
00495         throw InternalErr(__FILE__, __LINE__, "Trying to add a BaseType object with a NULL pointer.");
00496 
00497     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00498 
00499     BaseType *btp = bt->ptr_duplicate();
00500     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00501     if (d_container) {
00502         // Mem leak fix [mjohnson nov 2009]
00503         // Structure::add_var() creates ANOTHER copy.
00504         d_container->add_var(bt);
00505         // So we need to delete btp or else it leaks
00506         delete btp;
00507         btp = 0;
00508     }
00509     else {
00510         vars.push_back(btp);
00511     }
00512 }
00513 
00514 
00521 void
00522 DDS::del_var(const string &n)
00523 {
00524     if( d_container )
00525     {
00526         d_container->del_var( n ) ;
00527         return ;
00528     }
00529 
00530     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00531         if ((*i)->name() == n) {
00532             BaseType *bt = *i ;
00533             vars.erase(i) ;
00534             delete bt ; bt = 0;
00535             return;
00536         }
00537     }
00538 }
00539 
00544 void
00545 DDS::del_var(Vars_iter i)
00546 {
00547     if (i != vars.end()) {
00548         BaseType *bt = *i ;
00549         vars.erase(i) ;
00550         delete bt ; bt = 0;
00551     }
00552 }
00553 
00560 void
00561 DDS::del_var(Vars_iter i1, Vars_iter i2)
00562 {
00563     for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
00564         BaseType *bt = *i_tmp ;
00565         delete bt ; bt = 0;
00566     }
00567     vars.erase(i1, i2) ;
00568 }
00569 
00577 BaseType *
00578 DDS::var(const string &n, BaseType::btp_stack &s)
00579 {
00580     return var(n, &s);
00581 }
00601 BaseType *
00602 DDS::var(const string &n, BaseType::btp_stack *s)
00603 {
00604     string name = www2id(n);
00605     if( d_container )
00606         return d_container->var( name, false, s ) ;
00607 
00608     BaseType *v = exact_match(name, s);
00609     if (v)
00610         return v;
00611 
00612     return leaf_match(name, s);
00613 }
00614 
00615 BaseType *
00616 DDS::leaf_match(const string &n, BaseType::btp_stack *s)
00617 {
00618     DBG(cerr << "DDS::leaf_match: Looking for " << n << endl);
00619 
00620     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00621         BaseType *btp = *i;
00622         DBG(cerr << "DDS::leaf_match: Looking for " << n << " in: " << btp->name() << endl);
00623         // Look for the name in the dataset's top-level
00624         if (btp->name() == n) {
00625             DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00626             return btp;
00627         }
00628 
00629         if (btp->is_constructor_type()) {
00630             BaseType *found = btp->var(n, false, s);
00631             if (found) {
00632                 DBG(cerr << "Found " << n << " in: " << btp->name() << endl);
00633                 return found;
00634             }
00635         }
00636 #if STRUCTURE_ARRAY_SYNTAX_OLD
00637         if (btp->is_vector_type() && btp->var()->is_constructor_type()) {
00638             s->push(btp);
00639             BaseType *found = btp->var()->var(n, false, s);
00640             if (found) {
00641                 DBG(cerr << "Found " << n << " in: " << btp->var()->name() << endl);
00642                 return found;
00643             }
00644         }
00645 #endif
00646     }
00647 
00648     return 0;   // It is not here.
00649 }
00650 
00651 BaseType *
00652 DDS::exact_match(const string &name, BaseType::btp_stack *s)
00653 {
00654     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00655         BaseType *btp = *i;
00656         DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
00657         // Look for the name in the current ctor type or the top level
00658         if (btp->name() == name) {
00659             DBG2(cerr << "Found " << name << " in: " << btp << endl);
00660             return btp;
00661         }
00662     }
00663 
00664     string::size_type dot_pos = name.find(".");
00665     if (dot_pos != string::npos) {
00666         string aggregate = name.substr(0, dot_pos);
00667         string field = name.substr(dot_pos + 1);
00668 
00669         BaseType *agg_ptr = var(aggregate, s);
00670         if (agg_ptr) {
00671             DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
00672             return agg_ptr->var(field, true, s);
00673         }
00674         else
00675             return 0;  // qualified names must be *fully* qualified
00676     }
00677 
00678     return 0;   // It is not here.
00679 }
00680 
00681 
00684 DDS::Vars_iter
00685 DDS::var_begin()
00686 {
00687     return vars.begin();
00688 }
00689 
00690 DDS::Vars_riter
00691 DDS::var_rbegin()
00692 {
00693     return vars.rbegin();
00694 }
00695 
00696 DDS::Vars_iter
00697 DDS::var_end()
00698 {
00699     return vars.end() ;
00700 }
00701 
00702 DDS::Vars_riter
00703 DDS::var_rend()
00704 {
00705     return vars.rend() ;
00706 }
00707 
00711 DDS::Vars_iter
00712 DDS::get_vars_iter(int i)
00713 {
00714     return vars.begin() + i;
00715 }
00716 
00720 BaseType *
00721 DDS::get_var_index(int i)
00722 {
00723     return *(vars.begin() + i);
00724 }
00725 
00730 void
00731 DDS::insert_var(Vars_iter i, BaseType *ptr)
00732 {
00733     vars.insert(i, ptr->ptr_duplicate());
00734 }
00735 
00743 void
00744 DDS::insert_var_nocopy(Vars_iter i, BaseType *ptr)
00745 {
00746     vars.insert(i, ptr);
00747 }
00748 
00750 int
00751 DDS::num_var()
00752 {
00753     return vars.size();
00754 }
00755 
00756 void
00757 DDS::timeout_on()
00758 {
00759 #ifndef WIN32
00760     alarm(d_timeout);
00761 #endif
00762 }
00763 
00764 void
00765 DDS::timeout_off()
00766 {
00767 #ifndef WIN32
00768     d_timeout = alarm(0);
00769 #endif
00770 }
00771 
00772 void
00773 DDS::set_timeout(int t)
00774 {
00775     //  Has no effect under win32
00776     d_timeout = t;
00777 }
00778 
00779 int
00780 DDS::get_timeout()
00781 {
00782     //  Has to effect under win32
00783     return d_timeout;
00784 }
00785 
00787 void
00788 DDS::tag_nested_sequences()
00789 {
00790     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00791         if ((*i)->type() == dods_sequence_c)
00792             dynamic_cast<Sequence&>(**i).set_leaf_sequence();
00793         else if ((*i)->type() == dods_structure_c)
00794             dynamic_cast<Structure&>(**i).set_leaf_sequence();
00795     }
00796 }
00797 
00799 void
00800 DDS::parse(string fname)
00801 {
00802     FILE *in = fopen(fname.c_str(), "r");
00803 
00804     if (!in) {
00805         throw Error(cannot_read_file, "Could not open: " + fname);
00806     }
00807 
00808     try {
00809         parse(in);
00810         fclose(in);
00811     }
00812     catch (Error &e) {
00813         fclose(in);
00814         throw ;
00815     }
00816 }
00817 
00818 
00820 void
00821 DDS::parse(int fd)
00822 {
00823 #ifdef WIN32
00824     FILE *in = fdopen(_dup(fd), "r");
00825 #else
00826     FILE *in = fdopen(dup(fd), "r");
00827 #endif
00828 
00829     if (!in) {
00830         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00831     }
00832 
00833     try {
00834         parse(in);
00835         fclose(in);
00836     }
00837     catch (Error &e) {
00838         fclose(in);
00839         throw ;
00840     }
00841 }
00842 
00849 void
00850 DDS::parse(FILE *in)
00851 {
00852     if (!in) {
00853         throw InternalErr(__FILE__, __LINE__, "Null input stream.");
00854     }
00855 
00856     void *buffer = dds_buffer(in);
00857     dds_switch_to_buffer(buffer);
00858 
00859     parser_arg arg(this);
00860 
00861     bool status = ddsparse((void *) & arg) == 0;
00862 
00863     dds_delete_buffer(buffer);
00864 
00865     DBG2(cout << "Status from parser: " << status << endl);
00866 
00867     //  STATUS is the result of the parser function; if a recoverable error
00868     //  was found it will be true but arg.status() will be false.
00869     if (!status || !arg.status()) {// Check parse result
00870         if (arg.error())
00871             throw *arg.error();
00872     }
00873 }
00874 
00875 #if FILE_METHODS
00876 
00877 void
00878 DDS::print(FILE *out)
00879 {
00880 #if 0
00881     ostringstream oss;
00882     print(oss);
00883 
00884     fwrite(oss.str().c_str(), oss.str().length(), 1, out);
00885 #else
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 #endif
00896 }
00897 #endif
00898 
00900 void
00901 DDS::print(ostream &out)
00902 {
00903     out << "Dataset {\n" ;
00904 
00905     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00906         (*i)->print_decl(out) ;
00907     }
00908 
00909     out << "} " << id2www(name) << ";\n" ;
00910 
00911     return ;
00912 }
00913 
00914 #if FILE_METHODS
00915 
00925 void
00926 DDS::print_constrained(FILE *out)
00927 {
00928     fprintf(out, "Dataset {\n") ;
00929 
00930     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00931         // for each variable, indent with four spaces, print a trailing
00932         // semicolon, do not print debugging information, print only
00933         // variables in the current projection.
00934         (*i)->print_decl(out, "    ", true, false, true) ;
00935     }
00936 
00937     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00938 
00939     return;
00940 }
00941 #endif
00942 
00953 void
00954 DDS::print_constrained(ostream &out)
00955 {
00956     out << "Dataset {\n" ;
00957 
00958     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00959         // for each variable, indent with four spaces, print a trailing
00960         // semicolon, do not print debugging information, print only
00961         // variables in the current projection.
00962         (*i)->print_decl(out, "    ", true, false, true) ;
00963     }
00964 
00965     out << "} " << id2www(name) << ";\n" ;
00966 
00967     return;
00968 }
00969 
00970 #if FILE_METHODS
00971 class VariablePrintXML : public unary_function<BaseType *, void>
00972 {
00973     FILE *d_out;
00974     bool d_constrained;
00975 public:
00976     VariablePrintXML(FILE *out, bool constrained)
00977             : d_out(out), d_constrained(constrained)
00978     {}
00979     void operator()(BaseType *bt)
00980     {
00981         bt->print_xml(d_out, "    ", d_constrained);
00982     }
00983 };
00984 
00996 void
00997 DDS::print_xml(FILE *out, bool constrained, const string &blob)
00998 {
00999     ostringstream oss;
01000     print_xml_writer(oss, constrained, blob);
01001 
01002     string doc = oss.str();
01003     fwrite(doc.data(), 1, doc.length(), out);
01004 
01005 #if 0
01006     fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
01007 
01008     fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
01009 
01010     fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
01011 
01012     fprintf(out,"method=\"FILE*\"\n");
01013     fprintf(out, "dap_major=\"%d\"\n", get_dap_major());
01014     fprintf(out, "dap_minor=\"%d\"\n", get_dap_minor());
01015 
01016     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01017     // this at some point... jhrg
01018     if (get_dap_major() == 3 && get_dap_minor() == 2) {
01019     fprintf(out, "xmlns=\"%s\"\n", c_dap32_namespace.c_str());
01020 
01021     fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
01022             c_dap32_namespace.c_str(), c_default_dap32_schema_location.c_str());
01023     }
01024     else {
01025         fprintf(out, "xmlns=\"%s\"\n", c_dap20_namespace.c_str());
01026         fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
01027                 c_dap20_namespace.c_str(), c_default_dap20_schema_location.c_str());
01028     }
01029 
01030 
01031     d_attr.print_xml(out, "    ", constrained);
01032 
01033     fprintf(out, "\n");
01034 
01035     for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
01036 
01037     fprintf(out, "\n");
01038 
01039     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01040     // the same. jhrg
01041     if (get_dap_major() == 2 && get_dap_minor() == 0) {
01042         fprintf(out, "    <dataBLOB href=\"\"/>\n");
01043     }
01044     else if (!blob.empty()
01045              && (get_dap_major() == 3 && get_dap_minor() >= 2)
01046              || get_dap_major() >= 4) {
01047         fprintf(out, "    <blob href=\"cid:%s\"/>\n", blob.c_str());
01048     }
01049 
01050 
01051     fprintf(out, "</Dataset>\n");
01052 #endif
01053 }
01054 #endif
01055 
01056 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
01057 {
01058     ostream &d_out;
01059     bool d_constrained;
01060 public:
01061     VariablePrintXMLStrm(ostream &out, bool constrained)
01062             : d_out(out), d_constrained(constrained)
01063     {}
01064     void operator()(BaseType *bt)
01065     {
01066         bt->print_xml(d_out, "    ", d_constrained);
01067     }
01068 };
01069 
01081 void
01082 DDS::print_xml(ostream &out, bool constrained, const string &blob)
01083 {
01084     print_xml_writer(out, constrained, blob);
01085 
01086 #if 0
01087     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
01088 
01089     out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
01090 
01091     out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
01092 
01093     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01094     // this at some point... jhrg
01095     if (get_dap_major() == 3 && get_dap_minor() == 2) {
01096         out << "xsi:schemaLocation=\"" << c_dap32_namespace
01097             << "  " << c_default_dap32_schema_location << "\"\n" ;
01098 
01099         out << "xmlns:grddl=\"http://www.w3.org/2003/g/data-view#\"\n";
01100         out << "grddl:transformation=\"" << grddl_transformation_dap32 <<"\"\n";
01101 
01102         out << "xmlns=\"" << c_dap32_namespace << "\"\n" ;
01103         out << "xmlns:dap=\"" << c_dap32_namespace << "\"\n" ;
01104 
01105         out << "dapVersion=\"" << get_dap_major() << "."
01106             << get_dap_minor() << "\"";
01107 
01108         if (!get_request_xml_base().empty()) {
01109             out << "\n";
01110             out << "xmlns:xml=\"" << c_xml_namespace << "\"\n";
01111             out << "xml:base=\"" << get_request_xml_base() << "\"";
01112         }
01113 
01114         // Close the Dataset element
01115         out << ">\n";
01116     }
01117     else {
01118         out << "xmlns=\"" << c_dap20_namespace << "\"\n" ;
01119         out << "xsi:schemaLocation=\"" << c_dap20_namespace
01120             << "  " << c_default_dap20_schema_location << "\">\n\n" ;
01121     }
01122 
01123     d_attr.print_xml(out, "    ", constrained);
01124 
01125     out << "\n" ;
01126 
01127     for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
01128 
01129     out << "\n" ;
01130 
01131     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01132     // the same.
01133     // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
01134     // actually the CID of the MIME part that holds the data.
01135     if (get_dap_major() == 2 && get_dap_minor() == 0) {
01136         out << "    <dataBLOB href=\"\"/>\n" ;
01137     }
01138     else if (!blob.empty()
01139          && (get_dap_major() == 3 && get_dap_minor() >= 2)
01140          || get_dap_major() >= 4) {
01141     out << "    <blob href=\"cid:" << blob << "\"/>\n";
01142     }
01143 
01144     out << "</Dataset>\n" ;
01145 #endif
01146 }
01147 
01148 class VariablePrintXMLWriter : public unary_function<BaseType *, void>
01149 {
01150     XMLWriter &d_xml;
01151     bool d_constrained;
01152 public:
01153     VariablePrintXMLWriter(XMLWriter &xml, bool constrained)
01154             : d_xml(xml), d_constrained(constrained)
01155     {}
01156     void operator()(BaseType *bt)
01157     {
01158         bt->print_xml_writer(d_xml, d_constrained);
01159     }
01160 };
01161 
01162 
01163 void
01164 DDS::print_xml_writer(ostream &out, bool constrained, const string &blob)
01165 {
01166     XMLWriter xml("    ");
01167 
01168     if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
01169         throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
01170     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name.c_str()) < 0)
01171         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01172     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*)"http://www.w3.org/2001/XMLSchema-instance") < 0)
01173         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
01174 
01175     // Are we responding to a 3.2 or 2.0 client? We will have to improve on
01176     // this at some point... jhrg
01177     if (get_dap_major() == 3 && get_dap_minor() == 2) {
01178         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_32_n_sl.c_str()) < 0)
01179             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
01180 
01181         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:grddl", (const xmlChar*)"http://www.w3.org/2003/g/data-view#") < 0)
01182             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:grddl");
01183 
01184         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "grddl:transformation", (const xmlChar*)grddl_transformation_dap32.c_str()) < 0)
01185             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:transformation");
01186 
01187         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
01188             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
01189         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:dap", (const xmlChar*)c_dap32_namespace.c_str()) < 0)
01190             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:dap");
01191 
01192         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)"3.2") < 0)
01193             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
01194 
01195         if (!get_request_xml_base().empty()) {
01196             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml", (const xmlChar*)c_xml_namespace.c_str()) < 0)
01197                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
01198 
01199             if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base", (const xmlChar*)get_request_xml_base().c_str()) < 0)
01200                 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
01201         }
01202     }
01203     else {
01204         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*)c_dap20_namespace.c_str()) < 0)
01205             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
01206 
01207         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation", (const xmlChar*)c_dap_20_n_sl.c_str()) < 0)
01208             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
01209     }
01210 
01211     // Print the global attributes
01212     d_attr.print_xml_writer(xml);
01213 
01214     // Print each variable
01215     for_each(var_begin(), var_end(), VariablePrintXMLWriter(xml, constrained));
01216 
01217     // Only print this for the 2.0, 3.0 and 3.1 versions - which are essentially
01218     // the same.
01219     // For DAP 3.2 and greater, use the new syntax and value. The 'blob' is
01220     // actually the CID of the MIME part that holds the data.
01221     if (get_dap_major() == 2 && get_dap_minor() == 0) {
01222         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "dataBLOB") < 0)
01223             throw InternalErr(__FILE__, __LINE__, "Could not write dataBLOB element");
01224         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)"") < 0)
01225             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01226         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01227             throw InternalErr(__FILE__, __LINE__, "Could not end dataBLOB element");
01228     }
01229     else if (!blob.empty() && (get_dap_major() == 3 && get_dap_minor() >= 2)  || get_dap_major() >= 4) {
01230         if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "blob") < 0)
01231             throw InternalErr(__FILE__, __LINE__, "Could not write blob element");
01232         string cid="cid:" + blob;
01233         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "href", (const xmlChar*)cid.c_str()) < 0)
01234             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
01235         if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01236             throw InternalErr(__FILE__, __LINE__, "Could not end blob element");
01237     }
01238 
01239     if (xmlTextWriterEndElement(xml.get_writer()) < 0)
01240         throw InternalErr(__FILE__, __LINE__, "Could not end Dataset element");
01241 
01242     out << xml.get_doc();// << ends;// << endl;
01243 }
01244 
01245 // Used by DDS::send() when returning data from a function call.
01260 bool
01261 DDS::check_semantics(bool all)
01262 {
01263     // The dataset must have a name
01264     if (name == "") {
01265         cerr << "A dataset must have a name" << endl;
01266         return false;
01267     }
01268 
01269     string msg;
01270     if (!unique_names(vars, name, "Dataset", msg))
01271         return false;
01272 
01273     if (all)
01274         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01275             if (!(*i)->check_semantics(msg, true))
01276                 return false;
01277 
01278     return true;
01279 }
01280 
01306 bool
01307 DDS::mark(const string &n, bool state)
01308 {
01309     BaseType::btp_stack *s = new BaseType::btp_stack;
01310 
01311     DBG2(cerr << "DDS::mark: Looking for " << n << endl);
01312 
01313     BaseType *variable = var(n, s);
01314     if (!variable) {
01315         DBG2(cerr << "Could not find variable " << n << endl);
01316         delete s; s = 0;
01317         return false;
01318     }
01319     variable->set_send_p(state);
01320 
01321     DBG2(cerr << "DDS::mark: Set variable " << variable->name()
01322             << " (a " << variable->type_name() << ")" << endl);
01323 
01324     // Now check the btp_stack and run BaseType::set_send_p for every
01325     // BaseType pointer on the stack. Using BaseType::set_send_p() will
01326     // set the property for a Constructor but not its contained variables
01327     // which preserves the semantics of projecting just one field.
01328     while (!s->empty()) {
01329         s->top()->BaseType::set_send_p(state);
01330 
01331         DBG2(cerr << "DDS::mark: Set variable " << s->top()->name()
01332                 << " (a " << s->top()->type_name() << ")" << endl);
01333         string parent_name = (s->top()->get_parent()) ? s->top()->get_parent()->name(): "none";
01334         string parent_type = (s->top()->get_parent()) ? s->top()->get_parent()->type_name(): "none";
01335         DBG2(cerr << "DDS::mark: Parent variable " << parent_name << " (a " << parent_type << ")" << endl);
01336 
01337         s->pop();
01338     }
01339 
01340     delete s ; s = 0;
01341 
01342     return true;
01343 }
01344 
01350 void
01351 DDS::mark_all(bool state)
01352 {
01353     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
01354         (*i)->set_send_p(state);
01355 }
01356 
01364 void
01365 DDS::dump(ostream &strm) const
01366 {
01367     strm << DapIndent::LMarg << "DDS::dump - ("
01368     << (void *)this << ")" << endl ;
01369     DapIndent::Indent() ;
01370     strm << DapIndent::LMarg << "name: " << name << endl ;
01371     strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
01372     strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
01373     strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
01374     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
01375 
01376     strm << DapIndent::LMarg << "global attributes:" << endl ;
01377     DapIndent::Indent() ;
01378     d_attr.dump(strm) ;
01379     DapIndent::UnIndent() ;
01380 
01381     if (vars.size()) {
01382         strm << DapIndent::LMarg << "vars:" << endl ;
01383         DapIndent::Indent() ;
01384         Vars_citer i = vars.begin() ;
01385         Vars_citer ie = vars.end() ;
01386         for (; i != ie; i++) {
01387             (*i)->dump(strm) ;
01388         }
01389         DapIndent::UnIndent() ;
01390     }
01391     else {
01392         strm << DapIndent::LMarg << "vars: none" << endl ;
01393     }
01394 
01395     DapIndent::UnIndent() ;
01396 }
01397 
01398 } // namespace libdap