libdap++ Updated for version 3.8.2
|
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