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 18315 2008-03-03 20:14:44Z 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 <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 namespace libdap {
00084 
00085 void
00086 DDS::duplicate(const DDS &dds)
00087 {
00088     name = dds.name;
00089     d_factory = dds.d_factory;
00090 
00091     DDS &dds_tmp = const_cast<DDS &>(dds);
00092 
00093     // copy the things pointed to by the list, not just the pointers
00094     for (Vars_iter i = dds_tmp.var_begin(); i != dds_tmp.var_end(); i++) {
00095         add_var(*i); // add_var() dups the BaseType.
00096     }
00097 }
00098 
00109 DDS::DDS(BaseTypeFactory *factory, const string &n)
00110         : d_factory(factory), name(n), d_timeout(0)
00111 {}
00112 
00114 DDS::DDS(const DDS &rhs) : DapObj()
00115 {
00116     duplicate(rhs);
00117 }
00118 
00119 DDS::~DDS()
00120 {
00121     // delete all the variables in this DDS
00122     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00123         BaseType *btp = *i ;
00124         delete btp ; btp = 0;
00125     }
00126 }
00127 
00128 DDS &
00129 DDS::operator=(const DDS &rhs)
00130 {
00131     if (this == &rhs)
00132         return *this;
00133 
00134     duplicate(rhs);
00135 
00136     return *this;
00137 }
00138 
00154 BaseType *
00155 DDS::find_hdf4_dimension_attribute_home(AttrTable::entry *source)
00156 {
00157     BaseType *btp;
00158     string::size_type i = source->name.find("_dim_");
00159     if (i != string::npos && (btp = var(source->name.substr(0, i)))) {
00160         if (btp->is_vector_type()) {
00161             return btp;
00162         }
00163         else if (btp->type() == dods_grid_c) {
00164             // For a Grid, the hdf4 handler uses _dim_n for the n-th Map
00165             // i+5 points to the character holding 'n'
00166             int n = atoi(source->name.substr(i + 5).c_str());
00167             DBG(cerr << "Found a Grid (" << btp->name() << ") and "
00168                 << source->name.substr(i) << ", extracted n: " << n << endl);
00169             return *(dynamic_cast<Grid&>(*btp).map_begin() + n);
00170         }
00171     }
00172 
00173     return 0;
00174 }
00175 
00181 AttrTable *
00182 DDS::find_matching_container(AttrTable::entry *source, BaseType **dest_variable)
00183 {
00184     // The attribute entry 'source' must be a container
00185     if (source->type != Attr_container)
00186         throw InternalErr(__FILE__, __LINE__, "DDS::find_matching_container");
00187 
00188     // Use the name of the attribute container 'source' to figure out where
00189     // to put its contents.
00190     BaseType *btp;
00191     if ((btp = var(source->name))) {
00192         // ... matches a variable name? Use var's table
00193         *dest_variable = btp;
00194         return &btp->get_attr_table();
00195     }
00196     else if ((btp = find_hdf4_dimension_attribute_home(source))) {
00197         // ... hdf4 dimension attribute? Make a sub table and use that.
00198         // btp can only be an Array or a Grid Map (which is an array)
00199         if (btp->get_parent() && btp->get_parent()->type() == dods_grid_c) {
00200             DBG(cerr << "Found a Grid, assigning to the map" << endl);
00201             *dest_variable = btp;
00202             return &btp->get_attr_table();
00203         }
00204         else { // must ba a plain Array
00205             string::size_type i = source->name.find("_dim_");
00206             string ext = source->name.substr(i + 1);
00207             *dest_variable = btp;
00208             return btp->get_attr_table().append_container(ext);
00209         }
00210     }
00211     else {
00212         // ... otherwise assume it's a global attribute.
00213         AttrTable *at = d_attr.find_container(source->name);
00214         if (!at) {
00215             at = new AttrTable();       // Make a new global table if needed
00216             d_attr.append_container(at, source->name);
00217         }
00218 
00219         *dest_variable = 0;
00220         return at;
00221     }
00222 }
00223 
00245 void
00246 DDS::transfer_attributes(DAS * das)
00247 {
00248     // foreach container at the outer level
00249     AttrTable::Attr_iter das_i = das->attr_begin();
00250     while (das_i != das->attr_end()) {
00251         DBG(cerr << "Working on the '" << (*das_i)->name << "' container."
00252             << endl);
00253 
00254         AttrTable *source = (*das_i)->attributes;
00255         // Variable that holds 'dest'; null for a global attribute.
00256         BaseType *dest_variable = 0;
00257         AttrTable *dest = find_matching_container(*das_i, &dest_variable);
00258 
00259         // foreach source attribute in the das_i container
00260         AttrTable::Attr_iter source_p = source->attr_begin();
00261         while (source_p != source->attr_end()) {
00262             DBG(cerr << "Working on the '" << (*source_p)->name << "' attribute"
00263                 << endl);
00264 
00265             // If this is container, we must have a container (this one) within
00266             // a container (the 'source'). Look and see if the variable is a
00267             // Constructor. If so, pass that container into
00268             // Constructor::transfer_attributes()
00269             if ((*source_p)->type == Attr_container) {
00270                 if (dest_variable && dest_variable->is_constructor_type()) {
00271                     dynamic_cast<Constructor&>(*dest_variable).transfer_attributes(*source_p);
00272                 }
00273                 else {
00274                     dest->append_container(new AttrTable(*(*source_p)->attributes),
00275                                            (*source_p)->name);
00276                 }
00277             }
00278             else {
00279                 dest->append_attr(source->get_name(source_p),
00280                                   source->get_type(source_p),
00281                                   source->get_attr_vector(source_p));
00282             }
00283 
00284             ++source_p;
00285         }
00286 
00287         ++das_i;
00288     }
00289 }
00290 
00298 
00300 string
00301 DDS::get_dataset_name() const
00302 {
00303     return name;
00304 }
00305 
00307 void
00308 DDS::set_dataset_name(const string &n)
00309 {
00310     name = n;
00311 }
00312 
00314 
00316 AttrTable &
00317 DDS::get_attr_table()
00318 {
00319     return d_attr;
00320 }
00321 
00331 string
00332 DDS::filename()
00333 {
00334     return _filename;
00335 }
00336 
00338 void
00339 DDS::filename(const string &fn)
00340 {
00341     _filename = fn;
00342 }
00344 
00350 void
00351 DDS::add_var(BaseType *bt)
00352 {
00353     if (!bt)
00354         throw InternalErr(__FILE__, __LINE__,
00355                           "Trying to add a BaseType object with a NULL pointer.");
00356 
00357     DBG2(cerr << "In DDS::add_var(), bt's address is: " << bt << endl);
00358 
00359     BaseType *btp = bt->ptr_duplicate();
00360     DBG2(cerr << "In DDS::add_var(), btp's address is: " << btp << endl);
00361     vars.push_back(btp);
00362 }
00363 
00370 void
00371 DDS::del_var(const string &n)
00372 {
00373     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00374         if ((*i)->name() == n) {
00375             BaseType *bt = *i ;
00376             vars.erase(i) ;
00377             delete bt ; bt = 0;
00378             return;
00379         }
00380     }
00381 }
00382 
00387 void
00388 DDS::del_var(Vars_iter i)
00389 {
00390     if (i != vars.end()) {
00391         BaseType *bt = *i ;
00392         vars.erase(i) ;
00393         delete bt ; bt = 0;
00394     }
00395 }
00396 
00403 void
00404 DDS::del_var(Vars_iter i1, Vars_iter i2)
00405 {
00406     for (Vars_iter i_tmp = i1; i_tmp != i2; i_tmp++) {
00407         BaseType *bt = *i_tmp ;
00408         delete bt ; bt = 0;
00409     }
00410     vars.erase(i1, i2) ;
00411 }
00412 
00420 BaseType *
00421 DDS::var(const string &n, BaseType::btp_stack &s)
00422 {
00423     return var(n, &s);
00424 }
00444 BaseType *
00445 DDS::var(const string &n, BaseType::btp_stack *s)
00446 {
00447     string name = www2id(n);
00448     BaseType *v = exact_match(name, s);
00449     if (v)
00450         return v;
00451 
00452     return leaf_match(name, s);
00453 }
00454 
00455 BaseType *
00456 DDS::leaf_match(const string &n, BaseType::btp_stack *s)
00457 {
00458     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00459         BaseType *btp = *i;
00460         DBG2(cerr << "Looking at " << n << " in: " << btp << endl);
00461         // Look for the name in the dataset's top-level
00462         if (btp->name() == n) {
00463             DBG2(cerr << "Found " << n << " in: " << btp << endl);
00464             return btp;
00465         }
00466         if (btp->is_constructor_type() && (btp = btp->var(n, false, s))) {
00467             return btp;
00468         }
00469     }
00470 
00471     return 0;   // It is not here.
00472 }
00473 
00474 BaseType *
00475 DDS::exact_match(const string &name, BaseType::btp_stack *s)
00476 {
00477     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00478         BaseType *btp = *i;
00479         DBG2(cerr << "Looking for " << name << " in: " << btp << endl);
00480         // Look for the name in the current ctor type or the top level
00481         if (btp->name() == name) {
00482             DBG2(cerr << "Found " << name << " in: " << btp << endl);
00483             return btp;
00484         }
00485     }
00486 
00487     string::size_type dot_pos = name.find(".");
00488     if (dot_pos != string::npos) {
00489         string aggregate = name.substr(0, dot_pos);
00490         string field = name.substr(dot_pos + 1);
00491 
00492         BaseType *agg_ptr = var(aggregate, s);
00493         if (agg_ptr) {
00494             DBG2(cerr << "Descending into " << agg_ptr->name() << endl);
00495             return agg_ptr->var(field, true, s);
00496         }
00497         else
00498             return 0;  // qualified names must be *fully* qualified
00499     }
00500 
00501     return 0;   // It is not here.
00502 }
00503 
00504 
00507 DDS::Vars_iter
00508 DDS::var_begin()
00509 {
00510     return vars.begin();
00511 }
00512 
00513 DDS::Vars_riter
00514 DDS::var_rbegin()
00515 {
00516     return vars.rbegin();
00517 }
00518 
00519 DDS::Vars_iter
00520 DDS::var_end()
00521 {
00522     return vars.end() ;
00523 }
00524 
00525 DDS::Vars_riter
00526 DDS::var_rend()
00527 {
00528     return vars.rend() ;
00529 }
00530 
00534 DDS::Vars_iter
00535 DDS::get_vars_iter(int i)
00536 {
00537     return vars.begin() + i;
00538 }
00539 
00543 BaseType *
00544 DDS::get_var_index(int i)
00545 {
00546     return *(vars.begin() + i);
00547 }
00548 
00550 int
00551 DDS::num_var()
00552 {
00553     return vars.size();
00554 }
00555 
00556 void
00557 DDS::timeout_on()
00558 {
00559 #ifndef WIN32
00560     alarm(d_timeout);
00561 #endif
00562 }
00563 
00564 void
00565 DDS::timeout_off()
00566 {
00567 #ifndef WIN32
00568     d_timeout = alarm(0);
00569 #endif
00570 }
00571 
00572 void
00573 DDS::set_timeout(int t)
00574 {
00575     //  Has no effect under win32
00576     d_timeout = t;
00577 }
00578 
00579 int
00580 DDS::get_timeout()
00581 {
00582     //  Has to effect under win32
00583     return d_timeout;
00584 }
00585 
00587 void
00588 DDS::tag_nested_sequences()
00589 {
00590     for (Vars_iter i = vars.begin(); i != vars.end(); i++) {
00591         if ((*i)->type() == dods_sequence_c)
00592             dynamic_cast<Sequence&>(**i).set_leaf_sequence();
00593         else if ((*i)->type() == dods_structure_c)
00594             dynamic_cast<Structure&>(**i).set_leaf_sequence();
00595     }
00596 }
00597 
00599 void
00600 DDS::parse(string fname)
00601 {
00602     FILE *in = fopen(fname.c_str(), "r");
00603 
00604     if (!in) {
00605         throw Error(cannot_read_file, "Could not open: " + fname);
00606     }
00607 
00608     try {
00609         parse(in);
00610         fclose(in);
00611     }
00612     catch (Error &e) {
00613         fclose(in);
00614         throw e;
00615     }
00616 }
00617 
00618 
00620 void
00621 DDS::parse(int fd)
00622 {
00623 #ifdef WIN32
00624     FILE *in = fdopen(_dup(fd), "r");
00625 #else
00626     FILE *in = fdopen(dup(fd), "r");
00627 #endif
00628 
00629     if (!in) {
00630         throw InternalErr(__FILE__, __LINE__, "Could not access file.");
00631     }
00632 
00633     try {
00634         parse(in);
00635         fclose(in);
00636     }
00637     catch (Error &e) {
00638         fclose(in);
00639         throw e;
00640     }
00641 }
00642 
00649 void
00650 DDS::parse(FILE *in)
00651 {
00652     if (!in) {
00653         throw InternalErr(__FILE__, __LINE__, "Null input stream.");
00654     }
00655 
00656     void *buffer = dds_buffer(in);
00657     dds_switch_to_buffer(buffer);
00658 
00659     parser_arg arg(this);
00660 
00661     bool status = ddsparse((void *) & arg) == 0;
00662 
00663     dds_delete_buffer(buffer);
00664 
00665     DBG2(cout << "Status from parser: " << status << endl);
00666 
00667     //  STATUS is the result of the parser function; if a recoverable error
00668     //  was found it will be true but arg.status() will be false.
00669     if (!status || !arg.status()) {// Check parse result
00670         if (arg.error())
00671             throw *arg.error();
00672     }
00673 }
00674 
00676 void
00677 DDS::print(FILE *out)
00678 {
00679     fprintf(out, "Dataset {\n") ;
00680 
00681     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00682         (*i)->print_decl(out) ;
00683     }
00684 
00685     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00686 
00687     return ;
00688 }
00689 
00691 void
00692 DDS::print(ostream &out)
00693 {
00694     out << "Dataset {\n" ;
00695 
00696     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00697         (*i)->print_decl(out) ;
00698     }
00699 
00700     out << "} " << id2www(name) << ";\n" ;
00701 
00702     return ;
00703 }
00704 
00715 void
00716 DDS::print_constrained(FILE *out)
00717 {
00718     fprintf(out, "Dataset {\n") ;
00719 
00720     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00721         // for each variable, indent with four spaces, print a trailing
00722         // semi-colon, do not print debugging information, print only
00723         // variables in the current projection.
00724         (*i)->print_decl(out, "    ", true, false, true) ;
00725     }
00726 
00727     fprintf(out, "} %s;\n", id2www(name).c_str()) ;
00728 
00729     return;
00730 }
00731 
00742 void
00743 DDS::print_constrained(ostream &out)
00744 {
00745     out << "Dataset {\n" ;
00746 
00747     for (Vars_citer i = vars.begin(); i != vars.end(); i++) {
00748         // for each variable, indent with four spaces, print a trailing
00749         // semi-colon, do not print debugging information, print only
00750         // variables in the current projection.
00751         (*i)->print_decl(out, "    ", true, false, true) ;
00752     }
00753 
00754     out << "} " << id2www(name) << ";\n" ;
00755 
00756     return;
00757 }
00758 
00759 class VariablePrintXML : public unary_function<BaseType *, void>
00760 {
00761     FILE *d_out;
00762     bool d_constrained;
00763 public:
00764     VariablePrintXML(FILE *out, bool constrained)
00765             : d_out(out), d_constrained(constrained)
00766     {}
00767     void operator()(BaseType *bt)
00768     {
00769         bt->print_xml(d_out, "    ", d_constrained);
00770     }
00771 };
00772 
00783 void
00784 DDS::print_xml(FILE *out, bool constrained, const string &)
00785 {
00786     fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
00787 
00788     fprintf(out, "<Dataset name=\"%s\"\n", id2xml(name).c_str());
00789 
00790     fprintf(out, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
00791     fprintf(out, "xmlns=\"%s\"\n", dods_namespace.c_str());
00792     fprintf(out, "xsi:schemaLocation=\"%s  %s\">\n\n",
00793             dods_namespace.c_str(), default_schema_location.c_str());
00794 
00795     d_attr.print_xml(out, "    ", constrained);
00796 
00797     fprintf(out, "\n");
00798 
00799     for_each(var_begin(), var_end(), VariablePrintXML(out, constrained));
00800 
00801     fprintf(out, "\n");
00802 
00803     fprintf(out, "    <dataBLOB href=\"\"/>\n");
00804 
00805     fprintf(out, "</Dataset>\n");
00806 }
00807 
00808 class VariablePrintXMLStrm : public unary_function<BaseType *, void>
00809 {
00810     ostream &d_out;
00811     bool d_constrained;
00812 public:
00813     VariablePrintXMLStrm(ostream &out, bool constrained)
00814             : d_out(out), d_constrained(constrained)
00815     {}
00816     void operator()(BaseType *bt)
00817     {
00818         bt->print_xml(d_out, "    ", d_constrained);
00819     }
00820 };
00821 
00832 void
00833 DDS::print_xml(ostream &out, bool constrained, const string &)
00834 {
00835     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ;
00836 
00837     out << "<Dataset name=\"" << id2xml(name) << "\"\n" ;
00838 
00839     out << "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" ;
00840     out << "xmlns=\"" << dods_namespace << "\"\n" ;
00841     out << "xsi:schemaLocation=\"" << dods_namespace
00842         << "  " << default_schema_location << "\">\n\n" ;
00843 
00844     d_attr.print_xml(out, "    ", constrained);
00845 
00846     out << "\n" ;
00847 
00848     for_each(var_begin(), var_end(), VariablePrintXMLStrm(out, constrained));
00849 
00850     out << "\n" ;
00851 
00852     out << "    <dataBLOB href=\"\"/>\n" ;
00853 
00854     out << "</Dataset>\n" ;
00855 }
00856 
00857 // Used by DDS::send() when returning data from a function call.
00872 bool
00873 DDS::check_semantics(bool all)
00874 {
00875     // The dataset must have a name
00876     if (name == "") {
00877         cerr << "A dataset must have a name" << endl;
00878         return false;
00879     }
00880 
00881     string msg;
00882     if (!unique_names(vars, name, "Dataset", msg))
00883         return false;
00884 
00885     if (all)
00886         for (Vars_iter i = vars.begin(); i != vars.end(); i++)
00887             if (!(*i)->check_semantics(msg, true))
00888                 return false;
00889 
00890     return true;
00891 }
00892 
00918 bool
00919 DDS::mark(const string &n, bool state)
00920 {
00921     BaseType::btp_stack *s = new BaseType::btp_stack;
00922 
00923     DBG2(cerr << "Looking for " << n << endl);
00924 
00925     BaseType *variable = var(n, s);
00926     if (!variable) {
00927         DBG2(cerr << "Could not find variable " << n << endl);
00928         delete s; s = 0;
00929         return false;
00930     }
00931     variable->set_send_p(state);
00932     DBG2(cerr << "Set variable " << variable->name() << endl);
00933 
00934     // Now check the btp_stack and run BaseType::set_send_p for every
00935     // BaseType pointer on the stack.
00936     while (!s->empty()) {
00937         s->top()->BaseType::set_send_p(state);
00938         DBG2(cerr << "Set variable " << s->top()->name() << endl);
00939         s->pop();
00940     }
00941 
00942     delete s ; s = 0;
00943 
00944     return true;
00945 }
00946 
00952 void
00953 DDS::mark_all(bool state)
00954 {
00955     for (Vars_iter i = vars.begin(); i != vars.end(); i++)
00956         (*i)->set_send_p(state);
00957 }
00958 
00966 void
00967 DDS::dump(ostream &strm) const
00968 {
00969     strm << DapIndent::LMarg << "DDS::dump - ("
00970     << (void *)this << ")" << endl ;
00971     DapIndent::Indent() ;
00972     strm << DapIndent::LMarg << "name: " << name << endl ;
00973     strm << DapIndent::LMarg << "filename: " << _filename << endl ;
00974     strm << DapIndent::LMarg << "protocol major: " << d_protocol_major << endl;
00975     strm << DapIndent::LMarg << "protocol minor: " << d_protocol_minor << endl;
00976     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
00977 
00978     strm << DapIndent::LMarg << "global attributes:" << endl ;
00979     DapIndent::Indent() ;
00980     d_attr.dump(strm) ;
00981     DapIndent::UnIndent() ;
00982 
00983     if (vars.size()) {
00984         strm << DapIndent::LMarg << "vars:" << endl ;
00985         DapIndent::Indent() ;
00986         Vars_citer i = vars.begin() ;
00987         Vars_citer ie = vars.end() ;
00988         for (; i != ie; i++) {
00989             (*i)->dump(strm) ;
00990         }
00991         DapIndent::UnIndent() ;
00992     }
00993     else {
00994         strm << DapIndent::LMarg << "vars: none" << endl ;
00995     }
00996 
00997     DapIndent::UnIndent() ;
00998 }
00999 
01001 
01002 
01003 // Old content of the transfer_attributes() method
01004 #if 0
01005 AttrTable::Attr_iter i = das->attr_begin();
01006 while (i != das->attr_end())
01007 {
01008     // NB: (*i) == AttrTable::entry*;
01009 
01010     // This code should be making the <name>_dim_0, ..., attributes
01011     // into 'dim_0' containers within the <name> container. Let specific
01012     // clients handle the nested attributes however they want to. See
01013     // ticket #480.
01014 #if 0
01015     string::size_type dim_pos = (*i)->name.find("_dim_");
01016 #endif
01017     string sub_table = "";
01018 #if 0
01019     if (dim_pos != string::npos) {
01020         sub_table = (*i)->name.substr(dim_pos);
01021         (*i)->name = (*i)->name.substr(0, dim_pos);
01022     }
01023 #endif
01024     DBG(cerr << "DDS::transfer_attributes(DAS * das): sub table: "
01025         << sub_table << endl);
01026 
01027     BaseType *btp = var((*i)->name);
01028     if (btp)
01029         transfer_attr(das, (*i), btp, sub_table);
01030     else
01031         add_global_attribute(*i);
01032 
01033     ++i;
01034 }
01035 #endif
01036 
01037 
01038 #if 0
01039 
01051 void
01052 DDS::transfer_attr(DAS *das, const AttrTable::entry *ep, BaseType *btp,
01053                    const string &sub_table)
01054 {
01055     DBG(cerr << "DDS::transfer_attr: sub_table: " << sub_table << endl);
01056 
01057     if (ep->is_alias) {
01058         AttrTable *source_table = das->get_attr_table(ep->aliased_to);
01059         AttrTable &dest = btp->get_attr_table();
01060         if (source_table)
01061             dest.add_container_alias(ep->name /*+ sub_table*/, source_table);
01062         else
01063             dest.add_value_alias(das, ep->name /*+ sub_table*/, ep->aliased_to);
01064     }
01065     else if (ep->type == Attr_container) {
01066         DBG(cerr << "ep-type == container, ep-<name: " << ep->name << endl);
01067         //use sub_table here to make the new stuff a 'sub table'. I think this
01068         // is wrong. jhrg 10/24/06
01069         ep->attributes->set_name(ep->name);
01070         Constructor *c = dynamic_cast<Constructor*>(btp);
01071         if (c)
01072             transfer_attr_table(das, ep->attributes, c, sub_table);
01073         else
01074             transfer_attr_table(das, ep->attributes, btp, sub_table);
01075     }
01076     else {
01077         btp->get_attr_table().append_attr(ep->name, AttrType_to_String(ep->type),
01078                                           ep->attr);
01079 #if 0
01080         AttrTable &at = btp->get_attr_table();
01081         string n = ep->name /*+ sub_table*/;
01082         string t = AttrType_to_String(ep->type);
01083         vector<string> *attrs = ep->attr;
01084         for (vector<string>::iterator i = attrs->begin(); i != attrs->end(); ++i)
01085             at.append_attr(n, t, *i);
01086 #endif
01087     }
01088 }
01089 
01103 void
01104 DDS::transfer_attr_table(DAS *das, AttrTable *at, BaseType *btp,
01105                          const string &sub_table)
01106 {
01107     DBG(cerr << "DDS::transfer_attr_table (BseType): sub_table: " << sub_table << endl);
01108 
01109     if (at->get_name() == btp->name()) {
01110         // If the name matches and sub_table is not null, make a new table
01111         // called 'sub_table' and add that to btp's table.
01112         if (!sub_table.empty()) {
01113             string tsub_table = sub_table;
01114             AttrTable *new_at = new AttrTable(*at); //clone; see below
01115             // If the sub_table has a leading undescore, remove it.
01116             if (sub_table.find('_') != string::npos) {
01117                 tsub_table = tsub_table.substr(tsub_table.find('_') + 1);
01118             }
01119             btp->get_attr_table().append_container(new_at, tsub_table);
01120         }
01121         else {
01122             // for each entry in the table, call transfer_attr()
01123             for (AttrTable::Attr_iter i = at->attr_begin(); i != at->attr_end(); ++i)
01124                 transfer_attr(das, *i, btp, "");
01125         }
01126     }
01127     else {
01128         // Clone at because append_container does not and at may be deleted
01129         // before we're done with it. 05/22/03 jhrg
01130         AttrTable *new_at = new AttrTable(*at);
01131         btp->get_attr_table().append_container(new_at, at->get_name());
01132     }
01133 }
01134 
01136 void
01137 DDS::transfer_attr_table(DAS *das, AttrTable *at, Constructor *c,
01138                          const string &sub_table)
01139 {
01140     DBG(cerr << "DDS::transfer_attr_table: (Constructor) sub_table: "
01141         << sub_table << endl);
01142     for (AttrTable::Attr_iter i = at->attr_begin(); i != at->attr_end(); ++i) {
01143         AttrTable::entry *ep = *i;
01144         string n = ep->name;
01145         bool found = false;
01146 
01147         switch (c->type()) {
01148         case dods_structure_c:
01149         case dods_sequence_c: {
01150                 for (Constructor::Vars_iter j = c->var_begin(); j != c->var_end();
01151                      ++j) {
01152                     if (n == (*j)->name()) { // found match
01153                         found = true;
01154                         transfer_attr(das, ep, *j, sub_table);
01155                     }
01156                 }
01157                 break;
01158             }
01159 
01160         case dods_grid_c: {
01161                 Grid *g = dynamic_cast<Grid*>(c);
01162                 if (n == g->get_array()->name()) { // found match
01163                     found = true;
01164                     transfer_attr(das, ep, g->get_array(), sub_table);
01165                 }
01166 
01167                 for (Grid::Map_iter j = g->map_begin(); j != g->map_end(); ++j) {
01168                     if (n == (*j)->name()) { // found match
01169                         found = true;
01170                         transfer_attr(das, ep, *j, sub_table);
01171                     }
01172                 }
01173                 break;
01174             }
01175 
01176         default:
01177             throw InternalErr(__FILE__, __LINE__, "Unknown type.");
01178         }
01179 
01180         if (!found) {
01181             DBG(cerr << "Could not find a place in a constructor for " << sub_table
01182                 << ", calling transfer_attr() without it." << endl);
01183             transfer_attr(das, ep, c);
01184         }
01185     }
01186 }
01187 #endif
01188 #if 0
01189 
01197 bool
01198 DDS::is_global_attr(string name)
01199 {
01200     for (Vars_iter i = var_begin(); i != var_end(); ++i)
01201         if ((*i)->name() == name)
01202             return false;
01203 
01204     return true;
01205 }
01206 
01212 static inline bool
01213 is_in_kill_file(const string &name)
01214 {
01215     static Regex dim(".*_dim_[0-9]*"); // HDF `dimension' attributes.
01216 
01217     return dim.match(name.c_str(), name.length()) != -1;
01218 }
01219 
01226 void
01227 DDS::add_global_attribute(AttrTable::entry *entry)
01228 {
01229     string name = entry->name;
01230 
01231     if (is_global_attr(name) && !is_in_kill_file(name)) {
01232         if (entry->type == Attr_container) {
01233             try {
01234                 // Force the clone of table entry->attributes.
01235                 // append_container just copies the pointer and
01236                 // entry->attributes may be deleted before we're done with
01237                 // it! 05/22/03 jhrg
01238                 AttrTable *new_at = new AttrTable(*(entry->attributes));
01239                 d_attr.append_container(new_at, name);
01240             }
01241             catch (Error &e) {
01242                 DBG(cerr << "Error in DDS::global_attribute: "
01243                     << e.get_error_message() << endl);
01244                 // *** Ignore this error for now. We should probably merge
01245                 // the attributes and this really is something we should for
01246                 // before hand instead of letting an exception signal the
01247                 // condition... 05/22/03 jhrg
01248             }
01249         }
01250     }
01251 }
01252 #endif
01253 
01254 // This code should be making the <name>_dim_0, ..., attributes
01255 // into 'dim_0' containers within the <name> container. Let specific
01256 // clients handle the nested attributes however they want to. See
01257 // ticket #480.
01258 //
01259 // Refactor: Instead of matching each table to variable, adopt the
01260 // opposite approach. Scan the DDS (this) and for each variable,
01261 // look for its matching attribute table. Once that code works, add
01262 // special cases for things like the HDF4 _dim_? attribute tables.
01263 // One approach is to use the existing AttrTable::find methods to
01264 // locate tables and remove them from the DAS once they have been
01265 // transferred. Then the remaining AttrTable objects can be made the
01266 // Global attributes. Between those two operations, special cases can
01267 // be considered. jhrg 8/16/06
01268 
01269 // The AttrTable::find_container() method (which is what
01270 // DAS::get_attr_table(string) uses) will look in the current table only
01271 // unless the 'dot notation' is used. Since each variable must have an
01272 // AttrTable, we can scan the DDS for attributes at the top level and do the
01273 // same for the DAS. When a variable is not a simple type
01274 //(!BaseType::is_simple_type()), we can recur.
01275 
01276 // Instead of adding a method to BaseType and then to the Constructor and
01277 // Grid classes, use functions/private methods here to keep the DAS object
01278 // Out of the BaseType interface.
01279 
01280 #if 0
01281 // This is a failed attempt to rewrite the transfer_attributes() method.
01282 // Instead I fixed the original code; a better fix is to build servers that
01283 // use the DDX object.
01284 
01293 static AttrTable *
01294 search_for_attributes(const string &name, AttrTable *at, DAS *das)
01295 {
01296     // if 'at' is null, set ptable to null.
01297     AttrTable *ptable = (at) ? at->find_container(name) : 0;
01298     if (!ptable && das)
01299         ptable = das->get_attr_table(name);
01300 
01301     return ptable;
01302 }
01303 
01311 void
01312 DDS::transfer_attr_to_constructor(Constructor *cp, AttrTable *at, DAS *das)
01313 {
01314     if (cp->type() != dods_grid_c) {
01315         // Look at each variable held in the Constructor
01316         for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end(); ++i) {
01317             AttrTable *ptable = search_for_attributes((*i)->name(), at, das);
01318             if (!ptable)
01319                 continue;
01320 
01321             if ((*i)->is_simple_type() || (*i)->is_vector_type()) {
01322                 (*i)->set_attr_table(*ptable);  // Performs a deep copy
01323             }
01324             else { // a constructor
01325                 transfer_attr_to_constructor(dynamic_cast<Constructor*>(*i), ptable, das);
01326             }
01327         }
01328 
01329         // Now transfer all the regular attributes in 'at' to the Constructor.
01330         if (at) {
01331             AttrTable tmp;
01332             for (AttrTable::Attr_iter p = at->attr_begin(); p != at->attr_end(); ++p) {
01333                 if (!at->is_container(p)) {
01334                     cp->get_attr_table().append_attr(at->get_name(p),
01335                                                      at->get_type(p),
01336                                                      at->get_attr_vector(p));
01337                 }
01338             }
01339         }
01340     }
01341     else { // it's a grid, first special case for the Array
01342         Grid *g = dynamic_cast<Grid*>(cp);
01343         AttrTable *ptable = search_for_attributes(g->get_array()->name(), at, das);
01344         if (ptable)
01345             g->get_array()->set_attr_table(*ptable);  // Performs a deep copy
01346         // Look at each map in the
01347         for (Grid::Map_iter i = g->map_begin(); i != g->map_end(); ++i) {
01348             AttrTable *ptable = search_for_attributes((*i)->name(), at, das);
01349             if (!ptable)
01350                 continue;
01351             // Since this is a map inside a Grid, it must be an array
01352             (*i)->set_attr_table(*ptable);  // Performs a deep copy
01353         }
01354 
01355         // Now transfer all the regular attributes in at to the Grid.
01356         if (at) {
01357             AttrTable tmp;
01358             for (AttrTable::Attr_iter p = at->attr_begin(); p != at->attr_end(); ++p) {
01359                 if (!at->is_container(p)) {
01360                     cp->get_attr_table().append_attr(at->get_name(p),
01361                                                      at->get_type(p),
01362                                                      at->get_attr_vector(p));
01363                 }
01364             }
01365         }
01366     }
01367 }
01368 
01369 void
01370 DDS::new_transfer_attributes(DAS * das)
01371 {
01372     for (Vars_iter i = var_begin(); i != var_end(); ++i) {
01373         AttrTable *at = das->get_attr_table((*i)->name());
01374 
01375         // There is always supposed to be an attribute table for each variable,
01376         // but sometimes servers goof. That's why the code below tests 'at'.
01377 
01378         // Now we have the table that matches the top-level variable.
01379         // Decide how to add it to the variable. This will depend on
01380         // The type of variable.
01381         if (at && ((*i)->is_simple_type() || (*i)->is_vector_type())) {
01382             // *** Does not take into account vectors of constructors.
01383             // The same this is true in the above method. jhrg 8/17/06
01384             (*i)->set_attr_table(*at);  // Performs a deep copy
01385         }
01386         else { // a constructor; transfer_attr_to_constructor can deal with a
01387             // null 'at'.
01388             transfer_attr_to_constructor(dynamic_cast<Constructor*>(*i), at, das);
01389         }
01390     }
01391 }
01392 #endif
01393 
01394 } // namespace libdap

Generated on Tue Mar 4 18:01:54 2008 for libdap++ by  doxygen 1.5.1