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 16088 2007-03-28 21:42:19Z jimg $"
00038     };
00039 
00040 #include <stdio.h>
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>
00049 #include <sys/wait.h>
00050 #endif
00051 
00052 #include <iostream>
00053 #include <algorithm>
00054 #include <functional>
00055 
00056 //#define DODS_DEBUG
00057 
00058 #include "GNURegex.h"
00059 
00060 #include "DAS.h"
00061 #include "Clause.h"
00062 #include "Error.h"
00063 #include "InternalErr.h"
00064 
00065 #include "parser.h"
00066 #include "debug.h"
00067 #include "util.h"
00068 #include "escaping.h"
00069 
00070 const string default_schema_location = "http://xml.opendap.org/dap/dap2.xsd";
00071 const string dods_namespace = "http://xml.opendap.org/ns/DAP2";
00072 
00073 using namespace std;
00074 
00075 void ddsrestart(FILE *yyin); // Defined in dds.tab.c
00076 int ddsparse(void *arg);
00077 
00078 // Glue for the DDS parser defined in dds.lex
00079 void dds_switch_to_buffer(void *new_buffer);
00080 void dds_delete_buffer(void * buffer);
00081 void *dds_buffer(FILE *fp);
00082 
00083 void
00084 DDS::duplicate(const DDS &dds)
00085 {
00086     name = dds.name;
00087     d_factory = dds.d_factory;
00088 
00089     DDS &dds_tmp = const_cast<DDS &>(dds);
00090 
00091     // copy the things pointed to by the list, not just the pointers
00092     for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
00093         add_var(*i); // add_var() dups the BaseType.
00094     }
00095 }
00096 
00107 DDS::DDS(BaseTypeFactory *factory, const string &n)
00108         : d_factory(factory), name(n), d_timeout(0)
00109 {}
00110 
00112 DDS::DDS(const DDS &rhs) : DapObj()
00113 {
00114     duplicate(rhs);
00115 }
00116 
00117 DDS::~DDS()
00118 {
00119     // delete all the variables in this DDS
00120     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00121         BaseType *btp = *i ;
00122         delete btp ; btp = 0;
00123     }
00124 }
00125 
00126 DDS &
00127 DDS::operator=(const DDS &rhs)
00128 {
00129     if (this == &rhs)
00130         return *this;
00131 
00132     duplicate(rhs);
00133 
00134     return *this;
00135 }
00136 
00152 BaseType *
00153 DDS::find_hdf4_dimension_attribute_home(AttrTable::entry *source)
00154 {
00155     BaseType *btp;
00156     string::size_type i = source->name.find("_dim_");
00157     if (i != string::npos && (btp = var(source->name.substr(0, i)))) {
00158         if (btp->is_vector_type()) {
00159             return btp;
00160         }
00161         else if (btp->type() == dods_grid_c) {
00162             // For a Grid, the hdf4 handler uses _dim_n for the n-th Map
00163             // i+5 points to the character holding 'n'
00164             int n = atoi(source->name.substr(i + 5).c_str());
00165             DBG(cerr << "Found a Grid (" << btp->name() << ") and "
00166                 << source->name.substr(i) << ", extracted n: " << n << endl);
00167             return *(dynamic_cast<Grid&>(*btp).map_begin() + n);
00168         }
00169     }
00170 
00171     return 0;
00172 }
00173 
00179 AttrTable *
00180 DDS::find_matching_container(AttrTable::entry *source, BaseType **dest_variable)
00181 {
00182     // The attribute entry 'source' must be a container
00183     if (source->type != Attr_container)
00184         throw InternalErr(__FILE__, __LINE__, "DDS::find_matching_container");
00185 
00186     // Use the name of the attribute container 'source' to figure out where
00187     // to put its contents.
00188     BaseType *btp;
00189     if ((btp = var(source->name))) {
00190         // ... matches a variable name? Use var's table
00191         *dest_variable = btp;
00192         return &btp->get_attr_table();
00193     }
00194     else if ((btp = find_hdf4_dimension_attribute_home(source))) {
00195         // ... hdf4 dimension attribute? Make a sub table and use that.
00196         // btp can only be an Array or a Grid Map (which is an array)
00197         if (btp->get_parent() && btp->get_parent()->type() == dods_grid_c) {
00198             DBG(cerr << "Found a Grid, assigning to the map" << endl);
00199             *dest_variable = btp;
00200             return &btp->get_attr_table();
00201         }
00202         else { // must ba a plain Array
00203             string::size_type i = source->name.find("_dim_");
00204             string ext = source->name.substr(i + 1);
00205             *dest_variable = btp;
00206             return btp->get_attr_table().append_container(ext);
00207         }
00208     }
00209     else {
00210         // ... otherwise assume it's a global attribute.
00211         AttrTable *at = d_attr.find_container(source->name);
00212         if (!at) {
00213             at = new AttrTable();       // Make a new global table if needed
00214             d_attr.append_container(at, source->name);
00215         }
00216 
00217         *dest_variable = 0;
00218         return at;
00219     }
00220 }
00221 
00243 void
00244 DDS::transfer_attributes(DAS * das)
00245 {
00246     // foreach container at the outer level
00247     AttrTable::Attr_iter das_i = das->attr_begin();
00248     while (das_i != das->attr_end()) {
00249         DBG(cerr << "Working on the '" << (*das_i)->name << "' container."
00250             << endl);
00251 
00252         AttrTable *source = (*das_i)->attributes;
00253         // Variable that holds 'dest'; null for a global attribute.
00254         BaseType *dest_variable = 0;
00255         AttrTable *dest = find_matching_container(*das_i, &dest_variable);
00256 
00257         // foreach source attribute in the das_i container
00258         AttrTable::Attr_iter source_p = source->attr_begin();
00259         while (source_p != source->attr_end()) {
00260             DBG(cerr << "Working on the '" << (*source_p)->name << "' attribute"
00261                 << endl);
00262 
00263             // If this is container, we must have a container (this one) within
00264             // a container (the 'source'). Look and see if the variable is a
00265             // Constructor. If so, pass that container into
00266             // Constructor::transfer_attributes()
00267             if ((*source_p)->type == Attr_container) {
00268                 if (dest_variable && dest_variable->is_constructor_type()) {
00269                     dynamic_cast<Constructor&>(*dest_variable).transfer_attributes(*source_p);
00270                 }
00271                 else {
00272                     dest->append_container(new AttrTable(*(*source_p)->attributes),
00273                                            (*source_p)->name);
00274                 }
00275             }
00276             else {
00277                 dest->append_attr(source->get_name(source_p),
00278                                   source->get_type(source_p),
00279                                   source->get_attr_vector(source_p));
00280             }
00281 
00282             ++source_p;
00283         }
00284 
00285         ++das_i;
00286     }
00287 }
00288 
00296 
00298 string
00299 DDS::get_dataset_name() const
00300 {
00301     return name;
00302 }
00303 
00305 void
00306 DDS::set_dataset_name(const string &n)
00307 {
00308     name = n;
00309 }
00310 
00312 
00314 AttrTable &
00315 DDS::get_attr_table()
00316 {
00317     return d_attr;
00318 }
00319 
00329 string
00330 DDS::filename()
00331 {
00332     return _filename;
00333 }
00334 
00336 void
00337 DDS::filename(const string &fn)
00338 {
00339     _filename = fn;
00340 }
00342 
00348 void
00349 DDS::add_var(BaseType *bt)
00350 {
00351     if (!bt)
00352         throw InternalErr(__FILE__, __LINE__,
00353                           "Trying to add a BaseType object with a NULL pointer.");
00354 
00355     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00356 
00357     BaseType *btp = bt->ptr_duplicate();
00358     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00359     vars.push_back(btp);
00360 }
00361 
00368 void
00369 DDS::del_var(const string &n)
00370 {
00371     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00372         if ((*i)->name() == n) {
00373             BaseType *bt = *i ;
00374             vars.erase(i) ;
00375             delete bt ; bt = 0;
00376             return;
00377         }
00378     }
00379 }
00380 
00385 void
00386 DDS::del_var(Vars_iter i)
00387 {
00388     if (i != vars.end()) {
00389         BaseType *bt = *i ;
00390         vars.erase(i) ;
00391         delete bt ; bt = 0;
00392     }
00393 }
00394 
00401 void
00402 DDS::del_var(Vars_iter i1, Vars_iter i2)
00403 {
00404     for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
00405         BaseType *bt = *i_tmp ;
00406         delete bt ; bt = 0;
00407     }
00408     vars.erase(i1, i2) ;
00409 }
00410 
00418 BaseType *
00419 DDS::var(const string &n, btp_stack &s)
00420 {
00421     return var(n, &s);
00422 }
00442 BaseType *
00443 DDS::var(const string &n, btp_stack *s)
00444 {
00445     string name = www2id(n);
00446     BaseType *v = exact_match(name, s);
00447     if (v)
00448         return v;
00449 
00450     return leaf_match(name, s);
00451 }
00452 
00453 BaseType *
00454 DDS::leaf_match(const string &n, btp_stack *s)
00455 {
00456     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00457         BaseType *btp = *i;
00458         DBG2(cerr << "Looking at " << n << " in: " << btp << endl);
00459         // Look for the name in the dataset's top-level
00460         if (btp->name() == n) {
00461             DBG2(cerr << "Found " << n << " in: " << btp << endl);
00462             return btp;
00463         }
00464         if (btp->is_constructor_type() && (btp = btp->var(n, false, s))) {
00465             return btp;
00466         }
00467     }
00468 
00469     return 0;   // It is not here.
00470 }
00471 
00472 BaseType *
00473 DDS::exact_match(const string &name, btp_stack *s)
00474 {
00475     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00476         BaseType *btp = *i;
00477         DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
00478         // Look for the name in the current ctor type or the top level
00479         if (btp->name() == name) {
00480             DBG2(cerr << "Found " << name << " in: " << btp << endl);
00481             return btp;
00482         }
00483     }
00484 
00485     string::size_type dot_pos = name.find(".");
00486     if (dot_pos != string::npos) {
00487         string aggregate = name.substr(0, dot_pos);
00488         string field = name.substr(dot_pos + 1);
00489 
00490         BaseType *agg_ptr = var(aggregate, s);
00491         if (agg_ptr) {
00492             DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
00493             return agg_ptr->var(field, true, s);
00494         }
00495         else
00496             return 0;  // qualified names must be *fully* qualified
00497     }
00498 
00499     return 0;   // It is not here.
00500 }
00501 
00502 
00505 DDS::Vars_iter
00506 DDS::var_begin()
00507 {
00508     return vars.begin();
00509 }
00510 
00511 DDS::Vars_riter
00512 DDS::var_rbegin()
00513 {
00514     return vars.rbegin();
00515 }
00516 
00517 DDS::Vars_iter
00518 DDS::var_end()
00519 {
00520     return vars.end() ;
00521 }
00522 
00523 DDS::Vars_riter
00524 DDS::var_rend()
00525 {
00526     return vars.rend() ;
00527 }
00528 
00532 DDS::Vars_iter
00533 DDS::get_vars_iter(int i)
00534 {
00535     return vars.begin() + i;
00536 }
00537 
00541 BaseType *
00542 DDS::get_var_index(int i)
00543 {
00544     return *(vars.begin() + i);
00545 }
00546 
00548 int
00549 DDS::num_var()
00550 {
00551     return vars.size();
00552 }
00553 
00554 void
00555 DDS::timeout_on()
00556 {
00557 #ifndef WIN32
00558     alarm(d_timeout);
00559 #endif
00560 }
00561 
00562 void
00563 DDS::timeout_off()
00564 {
00565 #ifndef WIN32
00566     d_timeout = alarm(0);
00567 #endif
00568 }
00569 
00570 void
00571 DDS::set_timeout(int t)
00572 {
00573     //  Has no effect under win32
00574     d_timeout = t;
00575 }
00576 
00577 int
00578 DDS::get_timeout()
00579 {
00580     //  Has to effect under win32
00581     return d_timeout;
00582 }
00583 
00585 void
00586 DDS::tag_nested_sequences()
00587 {
00588     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00589         if ((*i)->type() == dods_sequence_c)
00590             dynamic_cast<Sequence&>(**i).set_leaf_sequence();
00591         else if ((*i)->type() == dods_structure_c)
00592             dynamic_cast<Structure&>(**i).set_leaf_sequence();
00593     }
00594 }
00595 
00597 void
00598 DDS::parse(string fname)
00599 {
00600     FILE *in = fopen(fname.c_str(), "r");
00601 
00602     if (!in) {
00603         throw Error(can_not_read_file, "Could not open: " + fname);
00604     }
00605 
00606     try {
00607         parse(in);
00608         fclose(in);
00609     }
00610     catch (Error &e) {
00611         fclose(in);
00612         throw e;
00613     }
00614 }
00615 
00616 
00618 void
00619 DDS::parse(int fd)
00620 {
00621 #ifdef WIN32
00622     FILE *in = fdopen(_dup(fd), "r");
00623 #else
00624     FILE *in = fdopen(dup(fd), "r");
00625 #endif
00626 
00627     if (!in) {
00628         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00629     }
00630 
00631     try {
00632         parse(in);
00633         fclose(in);
00634     }
00635     catch (Error &e) {
00636         fclose(in);
00637         throw e;
00638     }
00639 }
00640 
00647 void
00648 DDS::parse(FILE *in)
00649 {
00650     if (!in) {
00651         throw InternalErr(__FILE__, __LINE__, "Null input stream.");
00652     }
00653 
00654     void *buffer = dds_buffer(in);
00655     dds_switch_to_buffer(buffer);
00656 
00657     parser_arg arg(this);
00658 
00659     bool status = ddsparse((void *) & arg) == 0;
00660 
00661     dds_delete_buffer(buffer);
00662 
00663     DBG2(cout << "Status from parser: " << status << endl);
00664 
00665     //  STATUS is the result of the parser function; if a recoverable error
00666     //  was found it will be true but arg.status() will be false.
00667     if (!status || !arg.status()) {// Check parse result
00668         if (arg.error())
00669             throw *arg.error();
00670     }
00671 }
00672 
00674 void
00675 DDS::print(FILE *out)
00676 {
00677     fprintf(out, "Dataset {\n") ;
00678 
00679     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00680         (*i)->print_decl(out) ;
00681     }
00682 
00683     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00684 
00685     return ;
00686 }
00687 
00698 void
00699 DDS::print_constrained(FILE *out)
00700 {
00701     fprintf(out, "Dataset {\n") ;
00702 
00703     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00704         // for each variable, indent with four spaces, print a trailing
00705         // semi-colon, do not print debugging information, print only
00706         // variables in the current projection.
00707         (*i)->print_decl(out, "    ", true, false, true) ;
00708     }
00709 
00710     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00711 
00712     return;
00713 }
00714 
00715 class VariablePrintXML : public unary_function<BaseType *, void>
00716 {
00717     FILE *d_out;
00718     bool d_constrained;
00719 public:
00720     VariablePrintXML(FILE *out, bool constrained)
00721             : d_out(out), d_constrained(constrained)
00722     {}
00723     void operator()(BaseType *bt)
00724     {
00725         bt->print_xml(d_out, "    ", d_constrained);
00726     }
00727 };
00728 
00739 void
00740 DDS::print_xml(FILE *out, bool constrained, const string &)
00741 {
00742     fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00743 
00744     fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
00745 
00746     fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
00747     fprintf(out, "xmlns=\"%s\"\n", dods_namespace.c_str());
00748     fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
00749             dods_namespace.c_str(), default_schema_location.c_str());
00750 
00751     d_attr.print_xml(out, "    ", constrained);
00752 
00753     fprintf(out, "\n");
00754 
00755     for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
00756 
00757     fprintf(out, "\n");
00758 
00759     fprintf(out, "    <dataBLOB href=\"\"/>\n");
00760 
00761     fprintf(out, "</Dataset>\n");
00762 }
00763 
00764 // Used by DDS::send() when returning data from a function call.
00779 bool
00780 DDS::check_semantics(bool all)
00781 {
00782     // The dataset must have a name
00783     if (name == "") {
00784         cerr << "A dataset must have a name" << endl;
00785         return false;
00786     }
00787 
00788     string msg;
00789     if (!unique_names(vars, name, "Dataset", msg))
00790         return false;
00791 
00792     if (all)
00793         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
00794             if (!(*i)->check_semantics(msg, true))
00795                 return false;
00796 
00797     return true;
00798 }
00799 
00825 bool
00826 DDS::mark(const string &n, bool state)
00827 {
00828     btp_stack *s = new btp_stack;
00829 
00830     DBG2(cerr << "Looking for " << n << endl);
00831 
00832     BaseType *variable = var(n, s);
00833     if (!variable) {
00834         DBG2(cerr << "Could not find variable " << n << endl);
00835         return false;
00836     }
00837     variable->set_send_p(state);
00838     DBG2(cerr << "Set variable " << variable->name() << endl);
00839 
00840     // Now check the btp_stack and run BaseType::set_send_p for every
00841     // BaseType pointer on the stack.
00842     while (!s->empty()) {
00843         s->top()->BaseType::set_send_p(state);
00844         DBG2(cerr << "Set variable " << s->top()->name() << endl);
00845         s->pop();
00846     }
00847 
00848     delete s ; s = 0;
00849 
00850     return true;
00851 }
00852 
00858 void
00859 DDS::mark_all(bool state)
00860 {
00861     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
00862         (*i)->set_send_p(state);
00863 }
00864 
00872 void
00873 DDS::dump(ostream &strm) const
00874 {
00875     strm << DapIndent::LMarg << "DDS::dump - ("
00876     << (void *)this << ")" << endl ;
00877     DapIndent::Indent() ;
00878     strm << DapIndent::LMarg << "name: " << name << endl ;
00879     strm << DapIndent::LMarg << "filename: " << _filename << endl ;
00880     strm << DapIndent::LMarg << "protocol major: " << d_protocol_major << endl;
00881     strm << DapIndent::LMarg << "protocol minor: " << d_protocol_minor << endl;
00882     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
00883 
00884     strm << DapIndent::LMarg << "global attributes:" << endl ;
00885     DapIndent::Indent() ;
00886     d_attr.dump(strm) ;
00887     DapIndent::UnIndent() ;
00888 
00889     if (vars.size()) {
00890         strm << DapIndent::LMarg << "vars:" << endl ;
00891         DapIndent::Indent() ;
00892         Vars_citer i = vars.begin() ;
00893         Vars_citer ie = vars.end() ;
00894         for (; i != ie; i++) {
00895             (*i)->dump(strm) ;
00896         }
00897         DapIndent::UnIndent() ;
00898     }
00899     else {
00900         strm << DapIndent::LMarg << "vars: none" << endl ;
00901     }
00902 
00903     DapIndent::UnIndent() ;
00904 }
00905 
00907 
00908 
00909 // Old content of the transfer_attributes() method
00910 #if 0
00911 AttrTable::Attr_iter i = das->attr_begin();
00912 while (i != das->attr_end())
00913 {
00914     // NB: (*i) == AttrTable::entry*;
00915 
00916     // This code should be making the <name>_dim_0, ..., attributes
00917     // into 'dim_0' containers within the <name> container. Let specific
00918     // clients handle the nested attributes however they want to. See
00919     // ticket #480.
00920 #if 0
00921     string::size_type dim_pos = (*i)->name.find("_dim_");
00922 #endif
00923     string sub_table = "";
00924 #if 0
00925     if (dim_pos != string::npos) {
00926         sub_table = (*i)->name.substr(dim_pos);
00927         (*i)->name = (*i)->name.substr(0, dim_pos);
00928     }
00929 #endif
00930     DBG(cerr << "DDS::transfer_attributes(DAS * das): sub table: "
00931         << sub_table << endl);
00932 
00933     BaseType *btp = var((*i)->name);
00934     if (btp)
00935         transfer_attr(das, (*i), btp, sub_table);
00936     else
00937         add_global_attribute(*i);
00938 
00939     ++i;
00940 }
00941 #endif
00942 
00943 
00944 #if 0
00945 
00957 void
00958 DDS::transfer_attr(DAS *das, const AttrTable::entry *ep, BaseType *btp,
00959                    const string &sub_table)
00960 {
00961     DBG(cerr << "DDS::transfer_attr: sub_table: " << sub_table << endl);
00962 
00963     if (ep->is_alias) {
00964         AttrTable *source_table = das->get_attr_table(ep->aliased_to);
00965         AttrTable &dest = btp->get_attr_table();
00966         if (source_table)
00967             dest.add_container_alias(ep->name /*+ sub_table*/, source_table);
00968         else
00969             dest.add_value_alias(das, ep->name /*+ sub_table*/, ep->aliased_to);
00970     }
00971     else if (ep->type == Attr_container) {
00972         DBG(cerr << "ep-type == container, ep-<name: " << ep->name << endl);
00973         //use sub_table here to make the new stuff a 'sub table'. I think this
00974         // is wrong. jhrg 10/24/06
00975         ep->attributes->set_name(ep->name);
00976         Constructor *c = dynamic_cast<Constructor*>(btp);
00977         if (c)
00978             transfer_attr_table(das, ep->attributes, c, sub_table);
00979         else
00980             transfer_attr_table(das, ep->attributes, btp, sub_table);
00981     }
00982     else {
00983         btp->get_attr_table().append_attr(ep->name, AttrType_to_String(ep->type),
00984                                           ep->attr);
00985 #if 0
00986         AttrTable &at = btp->get_attr_table();
00987         string n = ep->name /*+ sub_table*/;
00988         string t = AttrType_to_String(ep->type);
00989         vector<string> *attrs = ep->attr;
00990         for (vector<string>::iterator i = attrs->begin(); i != attrs->end(); ++i)
00991             at.append_attr(n, t, *i);
00992 #endif
00993     }
00994 }
00995 
01009 void
01010 DDS::transfer_attr_table(DAS *das, AttrTable *at, BaseType *btp,
01011                          const string &sub_table)
01012 {
01013     DBG(cerr << "DDS::transfer_attr_table (BseType): sub_table: " << sub_table << endl);
01014 
01015     if (at->get_name() == btp->name()) {
01016         // If the name matches and sub_table is not null, make a new table
01017         // called 'sub_table' and add that to btp's table.
01018         if (!sub_table.empty()) {
01019             string tsub_table = sub_table;
01020             AttrTable *new_at = new AttrTable(*at); //clone; see below
01021             // If the sub_table has a leading undescore, remove it.
01022             if (sub_table.find('_') != string::npos) {
01023                 tsub_table = tsub_table.substr(tsub_table.find('_') + 1);
01024             }
01025             btp->get_attr_table().append_container(new_at, tsub_table);
01026         }
01027         else {
01028             // for each entry in the table, call transfer_attr()
01029             for (AttrTable::Attr_iter i = at->attr_begin(); i != at->attr_end(); ++i)
01030                 transfer_attr(das, *i, btp, "");
01031         }
01032     }
01033     else {
01034         // Clone at because append_container does not and at may be deleted
01035         // before we're done with it. 05/22/03 jhrg
01036         AttrTable *new_at = new AttrTable(*at);
01037         btp->get_attr_table().append_container(new_at, at->get_name());
01038     }
01039 }
01040 
01042 void
01043 DDS::transfer_attr_table(DAS *das, AttrTable *at, Constructor *c,
01044                          const string &sub_table)
01045 {
01046     DBG(cerr << "DDS::transfer_attr_table: (Constructor) sub_table: "
01047         << sub_table << endl);
01048     for (AttrTable::Attr_iter i = at->attr_begin(); i != at->attr_end(); ++i) {
01049         AttrTable::entry *ep = *i;
01050         string n = ep->name;
01051         bool found = false;
01052 
01053         switch (c->type()) {
01054         case dods_structure_c:
01055         case dods_sequence_c: {
01056                 for (Constructor::Vars_iter j = c->var_begin(); j != c->var_end();
01057                      ++j) {
01058                     if (n == (*j)->name()) { // found match
01059                         found = true;
01060                         transfer_attr(das, ep, *j, sub_table);
01061                     }
01062                 }
01063                 break;
01064             }
01065 
01066         case dods_grid_c: {
01067                 Grid *g = dynamic_cast<Grid*>(c);
01068                 if (n == g->get_array()->name()) { // found match
01069                     found = true;
01070                     transfer_attr(das, ep, g->get_array(), sub_table);
01071                 }
01072 
01073                 for (Grid::Map_iter j = g->map_begin(); j != g->map_end(); ++j) {
01074                     if (n == (*j)->name()) { // found match
01075                         found = true;
01076                         transfer_attr(das, ep, *j, sub_table);
01077                     }
01078                 }
01079                 break;
01080             }
01081 
01082         default:
01083             throw InternalErr(__FILE__, __LINE__, "Unknown type.");
01084         }
01085 
01086         if (!found) {
01087             DBG(cerr << "Could not find a place in a constructor for " << sub_table
01088                 << ", calling transfer_attr() without it." << endl);
01089             transfer_attr(das, ep, c);
01090         }
01091     }
01092 }
01093 #endif
01094 #if 0
01095 
01103 bool
01104 DDS::is_global_attr(string name)
01105 {
01106     for (Vars_iter i = var_begin(); i != var_end(); ++i)
01107         if ((*i)->name() == name)
01108             return false;
01109 
01110     return true;
01111 }
01112 
01118 static inline bool
01119 is_in_kill_file(const string &name)
01120 {
01121     static Regex dim(".*_dim_[0-9]*"); // HDF `dimension' attributes.
01122 
01123     return dim.match(name.c_str(), name.length()) != -1;
01124 }
01125 
01132 void
01133 DDS::add_global_attribute(AttrTable::entry *entry)
01134 {
01135     string name = entry->name;
01136 
01137     if (is_global_attr(name) && !is_in_kill_file(name)) {
01138         if (entry->type == Attr_container) {
01139             try {
01140                 // Force the clone of table entry->attributes.
01141                 // append_container just copies the pointer and
01142                 // entry->attributes may be deleted before we're done with
01143                 // it! 05/22/03 jhrg
01144                 AttrTable *new_at = new AttrTable(*(entry->attributes));
01145                 d_attr.append_container(new_at, name);
01146             }
01147             catch (Error &e) {
01148                 DBG(cerr << "Error in DDS::global_attribute: "
01149                     << e.get_error_message() << endl);
01150                 // *** Ignore this error for now. We should probably merge
01151                 // the attributes and this really is something we should for
01152                 // before hand instead of letting an exception signal the
01153                 // condition... 05/22/03 jhrg
01154             }
01155         }
01156     }
01157 }
01158 #endif
01159 
01160 // This code should be making the <name>_dim_0, ..., attributes
01161 // into 'dim_0' containers within the <name> container. Let specific
01162 // clients handle the nested attributes however they want to. See
01163 // ticket #480.
01164 //
01165 // Refactor: Instead of matching each table to variable, adopt the
01166 // opposite approach. Scan the DDS (this) and for each variable,
01167 // look for its matching attribute table. Once that code works, add
01168 // special cases for things like the HDF4 _dim_? attribute tables.
01169 // One approach is to use the existing AttrTable::find methods to
01170 // locate tables and remove them from the DAS once they have been
01171 // transferred. Then the remaining AttrTable objects can be made the
01172 // Global attributes. Between those two operations, special cases can
01173 // be considered. jhrg 8/16/06
01174 
01175 // The AttrTable::find_container() method (which is what
01176 // DAS::get_attr_table(string) uses) will look in the current table only
01177 // unless the 'dot notation' is used. Since each variable must have an
01178 // AttrTable, we can scan the DDS for attributes at the top level and do the
01179 // same for the DAS. When a variable is not a simple type
01180 //(!BaseType::is_simple_type()), we can recur.
01181 
01182 // Instead of adding a method to BaseType and then to the Constructor and
01183 // Grid classes, use functions/private methods here to keep the DAS object
01184 // Out of the BaseType interface.
01185 
01186 #if 0
01187 // This is a failed attempt to rewrite the transfer_attributes() method.
01188 // Instead I fixed the original code; a better fix is to build servers that
01189 // use the DDX object.
01190 
01199 static AttrTable *
01200 search_for_attributes(const string &name, AttrTable *at, DAS *das)
01201 {
01202     // if 'at' is null, set ptable to null.
01203     AttrTable *ptable = (at) ? at->find_container(name) : 0;
01204     if (!ptable && das)
01205         ptable = das->get_attr_table(name);
01206 
01207     return ptable;
01208 }
01209 
01217 void
01218 DDS::transfer_attr_to_constructor(Constructor *cp, AttrTable *at, DAS *das)
01219 {
01220     if (cp->type() != dods_grid_c) {
01221         // Look at each variable held in the Constructor
01222         for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end(); ++i) {
01223             AttrTable *ptable = search_for_attributes((*i)->name(), at, das);
01224             if (!ptable)
01225                 continue;
01226 
01227             if ((*i)->is_simple_type() || (*i)->is_vector_type()) {
01228                 (*i)->set_attr_table(*ptable);  // Performs a deep copy
01229             }
01230             else { // a constructor
01231                 transfer_attr_to_constructor(dynamic_cast<Constructor*>(*i), ptable, das);
01232             }
01233         }
01234 
01235         // Now transfer all the regular attributes in 'at' to the Constructor.
01236         if (at) {
01237             AttrTable tmp;
01238             for (AttrTable::Attr_iter p = at->attr_begin(); p != at->attr_end(); ++p) {
01239                 if (!at->is_container(p)) {
01240                     cp->get_attr_table().append_attr(at->get_name(p),
01241                                                      at->get_type(p),
01242                                                      at->get_attr_vector(p));
01243                 }
01244             }
01245         }
01246     }
01247     else { // it's a grid, first special case for the Array
01248         Grid *g = dynamic_cast<Grid*>(cp);
01249         AttrTable *ptable = search_for_attributes(g->get_array()->name(), at, das);
01250         if (ptable)
01251             g->get_array()->set_attr_table(*ptable);  // Performs a deep copy
01252         // Look at each map in the
01253         for (Grid::Map_iter i = g->map_begin(); i != g->map_end(); ++i) {
01254             AttrTable *ptable = search_for_attributes((*i)->name(), at, das);
01255             if (!ptable)
01256                 continue;
01257             // Since this is a map inside a Grid, it must be an array
01258             (*i)->set_attr_table(*ptable);  // Performs a deep copy
01259         }
01260 
01261         // Now transfer all the regular attributes in at to the Grid.
01262         if (at) {
01263             AttrTable tmp;
01264             for (AttrTable::Attr_iter p = at->attr_begin(); p != at->attr_end(); ++p) {
01265                 if (!at->is_container(p)) {
01266                     cp->get_attr_table().append_attr(at->get_name(p),
01267                                                      at->get_type(p),
01268                                                      at->get_attr_vector(p));
01269                 }
01270             }
01271         }
01272     }
01273 }
01274 
01275 void
01276 DDS::new_transfer_attributes(DAS * das)
01277 {
01278     for (Vars_iter i = var_begin(); i != var_end(); ++i) {
01279         AttrTable *at = das->get_attr_table((*i)->name());
01280 
01281         // There is always supposed to be an attribute table for each variable,
01282         // but sometimes servers goof. That's why the code below tests 'at'.
01283 
01284         // Now we have the table that matches the top-level variable.
01285         // Decide how to add it to the variable. This will depend on
01286         // The type of variable.
01287         if (at && ((*i)->is_simple_type() || (*i)->is_vector_type())) {
01288             // *** Does not take into account vectors of constructors.
01289             // The same this is true in the above method. jhrg 8/17/06
01290             (*i)->set_attr_table(*at);  // Performs a deep copy
01291         }
01292         else { // a constructor; transfer_attr_to_constructor can deal with a
01293             // null 'at'.
01294             transfer_attr_to_constructor(dynamic_cast<Constructor*>(*i), at, das);
01295         }
01296     }
01297 }
01298 #endif

Generated on Wed Jun 27 12:56:38 2007 for libdap++ by  doxygen 1.4.7