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 17002 2007-08-27 19:16:51Z pwest $"
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(cannot_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 
00689 void
00690 DDS::print(ostream &out)
00691 {
00692     out << "Dataset {\n" ;
00693 
00694     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00695         (*i)->print_decl(out) ;
00696     }
00697 
00698     out << "} " << id2www(name) << ";\n" ;
00699 
00700     return ;
00701 }
00702 
00713 void
00714 DDS::print_constrained(FILE *out)
00715 {
00716     fprintf(out, "Dataset {\n") ;
00717 
00718     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00719         // for each variable, indent with four spaces, print a trailing
00720         // semi-colon, do not print debugging information, print only
00721         // variables in the current projection.
00722         (*i)->print_decl(out, "    ", true, false, true) ;
00723     }
00724 
00725     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00726 
00727     return;
00728 }
00729 
00740 void
00741 DDS::print_constrained(ostream &out)
00742 {
00743     out << "Dataset {\n" ;
00744 
00745     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00746         // for each variable, indent with four spaces, print a trailing
00747         // semi-colon, do not print debugging information, print only
00748         // variables in the current projection.
00749         (*i)->print_decl(out, "    ", true, false, true) ;
00750     }
00751 
00752     out << "} " << id2www(name) << ";\n" ;
00753 
00754     return;
00755 }
00756 
00757 class VariablePrintXML : public unary_function<BaseType *, void>
00758 {
00759     FILE *d_out;
00760     bool d_constrained;
00761 public:
00762     VariablePrintXML(FILE *out, bool constrained)
00763             : d_out(out), d_constrained(constrained)
00764     {}
00765     void operator()(BaseType *bt)
00766     {
00767         bt->print_xml(d_out, "    ", d_constrained);
00768     }
00769 };
00770 
00781 void
00782 DDS::print_xml(FILE *out, bool constrained, const string &)
00783 {
00784     fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00785 
00786     fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
00787 
00788     fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
00789     fprintf(out, "xmlns=\"%s\"\n", dods_namespace.c_str());
00790     fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
00791             dods_namespace.c_str(), default_schema_location.c_str());
00792 
00793     d_attr.print_xml(out, "    ", constrained);
00794 
00795     fprintf(out, "\n");
00796 
00797     for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
00798 
00799     fprintf(out, "\n");
00800 
00801     fprintf(out, "    <dataBLOB href=\"\"/>\n");
00802 
00803     fprintf(out, "</Dataset>\n");
00804 }
00805 
00806 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
00807 {
00808     ostream &d_out;
00809     bool d_constrained;
00810 public:
00811     VariablePrintXMLStrm(ostream &out, bool constrained)
00812             : d_out(out), d_constrained(constrained)
00813     {}
00814     void operator()(BaseType *bt)
00815     {
00816         bt->print_xml(d_out, "    ", d_constrained);
00817     }
00818 };
00819 
00830 void
00831 DDS::print_xml(ostream &out, bool constrained, const string &)
00832 {
00833     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
00834 
00835     out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
00836 
00837     out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
00838     out << "xmlns=\"" << dods_namespace << "\"\n" ;
00839     out << "xsi:schemaLocation=\"" << dods_namespace
00840         << "  " << default_schema_location << "\">\n\n" ;
00841 
00842     d_attr.print_xml(out, "    ", constrained);
00843 
00844     out << "\n" ;
00845 
00846     for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
00847 
00848     out << "\n" ;
00849 
00850     out << "    <dataBLOB href=\"\"/>\n" ;
00851 
00852     out << "</Dataset>\n" ;
00853 }
00854 
00855 // Used by DDS::send() when returning data from a function call.
00870 bool
00871 DDS::check_semantics(bool all)
00872 {
00873     // The dataset must have a name
00874     if (name == "") {
00875         cerr << "A dataset must have a name" << endl;
00876         return false;
00877     }
00878 
00879     string msg;
00880     if (!unique_names(vars, name, "Dataset", msg))
00881         return false;
00882 
00883     if (all)
00884         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
00885             if (!(*i)->check_semantics(msg, true))
00886                 return false;
00887 
00888     return true;
00889 }
00890 
00916 bool
00917 DDS::mark(const string &n, bool state)
00918 {
00919     btp_stack *s = new btp_stack;
00920 
00921     DBG2(cerr << "Looking for " << n << endl);
00922 
00923     BaseType *variable = var(n, s);
00924     if (!variable) {
00925         DBG2(cerr << "Could not find variable " << n << endl);
00926         return false;
00927     }
00928     variable->set_send_p(state);
00929     DBG2(cerr << "Set variable " << variable->name() << endl);
00930 
00931     // Now check the btp_stack and run BaseType::set_send_p for every
00932     // BaseType pointer on the stack.
00933     while (!s->empty()) {
00934         s->top()->BaseType::set_send_p(state);
00935         DBG2(cerr << "Set variable " << s->top()->name() << endl);
00936         s->pop();
00937     }
00938 
00939     delete s ; s = 0;
00940 
00941     return true;
00942 }
00943 
00949 void
00950 DDS::mark_all(bool state)
00951 {
00952     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
00953         (*i)->set_send_p(state);
00954 }
00955 
00963 void
00964 DDS::dump(ostream &strm) const
00965 {
00966     strm << DapIndent::LMarg << "DDS::dump - ("
00967     << (void *)this << ")" << endl ;
00968     DapIndent::Indent() ;
00969     strm << DapIndent::LMarg << "name: " << name << endl ;
00970     strm << DapIndent::LMarg << "filename: " << _filename << endl ;
00971     strm << DapIndent::LMarg << "protocol major: " << d_protocol_major << endl;
00972     strm << DapIndent::LMarg << "protocol minor: " << d_protocol_minor << endl;
00973     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
00974 
00975     strm << DapIndent::LMarg << "global attributes:" << endl ;
00976     DapIndent::Indent() ;
00977     d_attr.dump(strm) ;
00978     DapIndent::UnIndent() ;
00979 
00980     if (vars.size()) {
00981         strm << DapIndent::LMarg << "vars:" << endl ;
00982         DapIndent::Indent() ;
00983         Vars_citer i = vars.begin() ;
00984         Vars_citer ie = vars.end() ;
00985         for (; i != ie; i++) {
00986             (*i)->dump(strm) ;
00987         }
00988         DapIndent::UnIndent() ;
00989     }
00990     else {
00991         strm << DapIndent::LMarg << "vars: none" << endl ;
00992     }
00993 
00994     DapIndent::UnIndent() ;
00995 }
00996 
00998 
00999 
01000 // Old content of the transfer_attributes() method
01001 #if 0
01002 AttrTable::Attr_iter i = das->attr_begin();
01003 while (i != das->attr_end())
01004 {
01005     // NB: (*i) == AttrTable::entry*;
01006 
01007     // This code should be making the <name>_dim_0, ..., attributes
01008     // into 'dim_0' containers within the <name> container. Let specific
01009     // clients handle the nested attributes however they want to. See
01010     // ticket #480.
01011 #if 0
01012     string::size_type dim_pos = (*i)->name.find("_dim_");
01013 #endif
01014     string sub_table = "";
01015 #if 0
01016     if (dim_pos != string::npos) {
01017         sub_table = (*i)->name.substr(dim_pos);
01018         (*i)->name = (*i)->name.substr(0, dim_pos);
01019     }
01020 #endif
01021     DBG(cerr << "DDS::transfer_attributes(DAS * das): sub table: "
01022         << sub_table << endl);
01023 
01024     BaseType *btp = var((*i)->name);
01025     if (btp)
01026         transfer_attr(das, (*i), btp, sub_table);
01027     else
01028         add_global_attribute(*i);
01029 
01030     ++i;
01031 }
01032 #endif
01033 
01034 
01035 #if 0
01036 
01048 void
01049 DDS::transfer_attr(DAS *das, const AttrTable::entry *ep, BaseType *btp,
01050                    const string &sub_table)
01051 {
01052     DBG(cerr << "DDS::transfer_attr: sub_table: " << sub_table << endl);
01053 
01054     if (ep->is_alias) {
01055         AttrTable *source_table = das->get_attr_table(ep->aliased_to);
01056         AttrTable &dest = btp->get_attr_table();
01057         if (source_table)
01058             dest.add_container_alias(ep->name /*+ sub_table*/, source_table);
01059         else
01060             dest.add_value_alias(das, ep->name /*+ sub_table*/, ep->aliased_to);
01061     }
01062     else if (ep->type == Attr_container) {
01063         DBG(cerr << "ep-type == container, ep-<name: " << ep->name << endl);
01064         //use sub_table here to make the new stuff a 'sub table'. I think this
01065         // is wrong. jhrg 10/24/06
01066         ep->attributes->set_name(ep->name);
01067         Constructor *c = dynamic_cast<Constructor*>(btp);
01068         if (c)
01069             transfer_attr_table(das, ep->attributes, c, sub_table);
01070         else
01071             transfer_attr_table(das, ep->attributes, btp, sub_table);
01072     }
01073     else {
01074         btp->get_attr_table().append_attr(ep->name, AttrType_to_String(ep->type),
01075                                           ep->attr);
01076 #if 0
01077         AttrTable &at = btp->get_attr_table();
01078         string n = ep->name /*+ sub_table*/;
01079         string t = AttrType_to_String(ep->type);
01080         vector<string> *attrs = ep->attr;
01081         for (vector<string>::iterator i = attrs->begin(); i != attrs->end(); ++i)
01082             at.append_attr(n, t, *i);
01083 #endif
01084     }
01085 }
01086 
01100 void
01101 DDS::transfer_attr_table(DAS *das, AttrTable *at, BaseType *btp,
01102                          const string &sub_table)
01103 {
01104     DBG(cerr << "DDS::transfer_attr_table (BseType): sub_table: " << sub_table << endl);
01105 
01106     if (at->get_name() == btp->name()) {
01107         // If the name matches and sub_table is not null, make a new table
01108         // called 'sub_table' and add that to btp's table.
01109         if (!sub_table.empty()) {
01110             string tsub_table = sub_table;
01111             AttrTable *new_at = new AttrTable(*at); //clone; see below
01112             // If the sub_table has a leading undescore, remove it.
01113             if (sub_table.find('_') != string::npos) {
01114                 tsub_table = tsub_table.substr(tsub_table.find('_') + 1);
01115             }
01116             btp->get_attr_table().append_container(new_at, tsub_table);
01117         }
01118         else {
01119             // for each entry in the table, call transfer_attr()
01120             for (AttrTable::Attr_iter i = at->attr_begin(); i != at->attr_end(); ++i)
01121                 transfer_attr(das, *i, btp, "");
01122         }
01123     }
01124     else {
01125         // Clone at because append_container does not and at may be deleted
01126         // before we're done with it. 05/22/03 jhrg
01127         AttrTable *new_at = new AttrTable(*at);
01128         btp->get_attr_table().append_container(new_at, at->get_name());
01129     }
01130 }
01131 
01133 void
01134 DDS::transfer_attr_table(DAS *das, AttrTable *at, Constructor *c,
01135                          const string &sub_table)
01136 {
01137     DBG(cerr << "DDS::transfer_attr_table: (Constructor) sub_table: "
01138         << sub_table << endl);
01139     for (AttrTable::Attr_iter i = at->attr_begin(); i != at->attr_end(); ++i) {
01140         AttrTable::entry *ep = *i;
01141         string n = ep->name;
01142         bool found = false;
01143 
01144         switch (c->type()) {
01145         case dods_structure_c:
01146         case dods_sequence_c: {
01147                 for (Constructor::Vars_iter j = c->var_begin(); j != c->var_end();
01148                      ++j) {
01149                     if (n == (*j)->name()) { // found match
01150                         found = true;
01151                         transfer_attr(das, ep, *j, sub_table);
01152                     }
01153                 }
01154                 break;
01155             }
01156 
01157         case dods_grid_c: {
01158                 Grid *g = dynamic_cast<Grid*>(c);
01159                 if (n == g->get_array()->name()) { // found match
01160                     found = true;
01161                     transfer_attr(das, ep, g->get_array(), sub_table);
01162                 }
01163 
01164                 for (Grid::Map_iter j = g->map_begin(); j != g->map_end(); ++j) {
01165                     if (n == (*j)->name()) { // found match
01166                         found = true;
01167                         transfer_attr(das, ep, *j, sub_table);
01168                     }
01169                 }
01170                 break;
01171             }
01172 
01173         default:
01174             throw InternalErr(__FILE__, __LINE__, "Unknown type.");
01175         }
01176 
01177         if (!found) {
01178             DBG(cerr << "Could not find a place in a constructor for " << sub_table
01179                 << ", calling transfer_attr() without it." << endl);
01180             transfer_attr(das, ep, c);
01181         }
01182     }
01183 }
01184 #endif
01185 #if 0
01186 
01194 bool
01195 DDS::is_global_attr(string name)
01196 {
01197     for (Vars_iter i = var_begin(); i != var_end(); ++i)
01198         if ((*i)->name() == name)
01199             return false;
01200 
01201     return true;
01202 }
01203 
01209 static inline bool
01210 is_in_kill_file(const string &name)
01211 {
01212     static Regex dim(".*_dim_[0-9]*"); // HDF `dimension' attributes.
01213 
01214     return dim.match(name.c_str(), name.length()) != -1;
01215 }
01216 
01223 void
01224 DDS::add_global_attribute(AttrTable::entry *entry)
01225 {
01226     string name = entry->name;
01227 
01228     if (is_global_attr(name) && !is_in_kill_file(name)) {
01229         if (entry->type == Attr_container) {
01230             try {
01231                 // Force the clone of table entry->attributes.
01232                 // append_container just copies the pointer and
01233                 // entry->attributes may be deleted before we're done with
01234                 // it! 05/22/03 jhrg
01235                 AttrTable *new_at = new AttrTable(*(entry->attributes));
01236                 d_attr.append_container(new_at, name);
01237             }
01238             catch (Error &e) {
01239                 DBG(cerr << "Error in DDS::global_attribute: "
01240                     << e.get_error_message() << endl);
01241                 // *** Ignore this error for now. We should probably merge
01242                 // the attributes and this really is something we should for
01243                 // before hand instead of letting an exception signal the
01244                 // condition... 05/22/03 jhrg
01245             }
01246         }
01247     }
01248 }
01249 #endif
01250 
01251 // This code should be making the <name>_dim_0, ..., attributes
01252 // into 'dim_0' containers within the <name> container. Let specific
01253 // clients handle the nested attributes however they want to. See
01254 // ticket #480.
01255 //
01256 // Refactor: Instead of matching each table to variable, adopt the
01257 // opposite approach. Scan the DDS (this) and for each variable,
01258 // look for its matching attribute table. Once that code works, add
01259 // special cases for things like the HDF4 _dim_? attribute tables.
01260 // One approach is to use the existing AttrTable::find methods to
01261 // locate tables and remove them from the DAS once they have been
01262 // transferred. Then the remaining AttrTable objects can be made the
01263 // Global attributes. Between those two operations, special cases can
01264 // be considered. jhrg 8/16/06
01265 
01266 // The AttrTable::find_container() method (which is what
01267 // DAS::get_attr_table(string) uses) will look in the current table only
01268 // unless the 'dot notation' is used. Since each variable must have an
01269 // AttrTable, we can scan the DDS for attributes at the top level and do the
01270 // same for the DAS. When a variable is not a simple type
01271 //(!BaseType::is_simple_type()), we can recur.
01272 
01273 // Instead of adding a method to BaseType and then to the Constructor and
01274 // Grid classes, use functions/private methods here to keep the DAS object
01275 // Out of the BaseType interface.
01276 
01277 #if 0
01278 // This is a failed attempt to rewrite the transfer_attributes() method.
01279 // Instead I fixed the original code; a better fix is to build servers that
01280 // use the DDX object.
01281 
01290 static AttrTable *
01291 search_for_attributes(const string &name, AttrTable *at, DAS *das)
01292 {
01293     // if 'at' is null, set ptable to null.
01294     AttrTable *ptable = (at) ? at->find_container(name) : 0;
01295     if (!ptable && das)
01296         ptable = das->get_attr_table(name);
01297 
01298     return ptable;
01299 }
01300 
01308 void
01309 DDS::transfer_attr_to_constructor(Constructor *cp, AttrTable *at, DAS *das)
01310 {
01311     if (cp->type() != dods_grid_c) {
01312         // Look at each variable held in the Constructor
01313         for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end(); ++i) {
01314             AttrTable *ptable = search_for_attributes((*i)->name(), at, das);
01315             if (!ptable)
01316                 continue;
01317 
01318             if ((*i)->is_simple_type() || (*i)->is_vector_type()) {
01319                 (*i)->set_attr_table(*ptable);  // Performs a deep copy
01320             }
01321             else { // a constructor
01322                 transfer_attr_to_constructor(dynamic_cast<Constructor*>(*i), ptable, das);
01323             }
01324         }
01325 
01326         // Now transfer all the regular attributes in 'at' to the Constructor.
01327         if (at) {
01328             AttrTable tmp;
01329             for (AttrTable::Attr_iter p = at->attr_begin(); p != at->attr_end(); ++p) {
01330                 if (!at->is_container(p)) {
01331                     cp->get_attr_table().append_attr(at->get_name(p),
01332                                                      at->get_type(p),
01333                                                      at->get_attr_vector(p));
01334                 }
01335             }
01336         }
01337     }
01338     else { // it's a grid, first special case for the Array
01339         Grid *g = dynamic_cast<Grid*>(cp);
01340         AttrTable *ptable = search_for_attributes(g->get_array()->name(), at, das);
01341         if (ptable)
01342             g->get_array()->set_attr_table(*ptable);  // Performs a deep copy
01343         // Look at each map in the
01344         for (Grid::Map_iter i = g->map_begin(); i != g->map_end(); ++i) {
01345             AttrTable *ptable = search_for_attributes((*i)->name(), at, das);
01346             if (!ptable)
01347                 continue;
01348             // Since this is a map inside a Grid, it must be an array
01349             (*i)->set_attr_table(*ptable);  // Performs a deep copy
01350         }
01351 
01352         // Now transfer all the regular attributes in at to the Grid.
01353         if (at) {
01354             AttrTable tmp;
01355             for (AttrTable::Attr_iter p = at->attr_begin(); p != at->attr_end(); ++p) {
01356                 if (!at->is_container(p)) {
01357                     cp->get_attr_table().append_attr(at->get_name(p),
01358                                                      at->get_type(p),
01359                                                      at->get_attr_vector(p));
01360                 }
01361             }
01362         }
01363     }
01364 }
01365 
01366 void
01367 DDS::new_transfer_attributes(DAS * das)
01368 {
01369     for (Vars_iter i = var_begin(); i != var_end(); ++i) {
01370         AttrTable *at = das->get_attr_table((*i)->name());
01371 
01372         // There is always supposed to be an attribute table for each variable,
01373         // but sometimes servers goof. That's why the code below tests 'at'.
01374 
01375         // Now we have the table that matches the top-level variable.
01376         // Decide how to add it to the variable. This will depend on
01377         // The type of variable.
01378         if (at && ((*i)->is_simple_type() || (*i)->is_vector_type())) {
01379             // *** Does not take into account vectors of constructors.
01380             // The same this is true in the above method. jhrg 8/17/06
01381             (*i)->set_attr_table(*at);  // Performs a deep copy
01382         }
01383         else { // a constructor; transfer_attr_to_constructor can deal with a
01384             // null 'at'.
01385             transfer_attr_to_constructor(dynamic_cast<Constructor*>(*i), at, das);
01386         }
01387     }
01388 }
01389 #endif

Generated on Sat Jan 19 04:05:26 2008 for libdap++ by  doxygen 1.5.4