libdap++ Updated for version 3.8.2
AttrTable.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 // jhrg 7/29/94
00032 
00033 #include "config.h"
00034 
00035 // #define DODS_DEBUG
00036 
00037 static char rcsid[]not_used =
00038         "$Id: AttrTable.cc 24370 2011-03-28 16:21:32Z jimg $";
00039 
00040 #include <cassert>
00041 
00042 #include "AttrTable.h"
00043 
00044 #include "util.h"
00045 #include "escaping.h"
00046 
00047 #include "debug.h"
00048 
00049 using std::cerr;
00050 using std::string;
00051 using std::endl;
00052 using std::vector;
00053 
00054 namespace libdap {
00055 
00059 string AttrType_to_String(const AttrType at)
00060 {
00061     switch (at) {
00062         case Attr_container:
00063             return "Container";
00064         case Attr_byte:
00065             return "Byte";
00066         case Attr_int16:
00067             return "Int16";
00068         case Attr_uint16:
00069             return "UInt16";
00070         case Attr_int32:
00071             return "Int32";
00072         case Attr_uint32:
00073             return "UInt32";
00074         case Attr_float32:
00075             return "Float32";
00076         case Attr_float64:
00077             return "Float64";
00078         case Attr_string:
00079             return "String";
00080         case Attr_url:
00081             return "Url";
00082         case Attr_other_xml:
00083             return "OtherXML";
00084         default:
00085             return "";
00086     }
00087 }
00088 
00089 AttrType String_to_AttrType(const string &s)
00090 {
00091     string s2 = s;
00092     downcase(s2);
00093 
00094     if (s2 == "container")
00095         return Attr_container;
00096     else if (s2 == "byte")
00097         return Attr_byte;
00098     else if (s2 == "int16")
00099         return Attr_int16;
00100     else if (s2 == "uint16")
00101         return Attr_uint16;
00102     else if (s2 == "int32")
00103         return Attr_int32;
00104     else if (s2 == "uint32")
00105         return Attr_uint32;
00106     else if (s2 == "float32")
00107         return Attr_float32;
00108     else if (s2 == "float64")
00109         return Attr_float64;
00110     else if (s2 == "string")
00111         return Attr_string;
00112     else if (s2 == "url")
00113         return Attr_url;
00114     else if (s2 == "otherxml")
00115         return Attr_other_xml;
00116     else
00117         return Attr_unknown;
00118 }
00119 
00122 void AttrTable::clone(const AttrTable &at)
00123 {
00124     d_name = at.d_name;
00125     d_is_global_attribute = at.d_is_global_attribute;
00126 
00127     // Set the parent to null (no parent, not in container)
00128     // since using at.d_parent is semantically incorrect
00129     // and potentially dangerous.
00130     d_parent = 0;
00131 
00132     Attr_citer i = at.attr_map.begin();
00133     Attr_citer ie = at.attr_map.end();
00134     for (; i != ie; ++i) {
00135         // this deep-copies containers recursively
00136         entry *e = new entry(*(*i));
00137         attr_map.push_back(e);
00138 
00139         // If the entry being added was a container,
00140         // set its parent to this to maintain invariant.
00141         if (e->type == Attr_container) {
00142           assert(e->attributes);
00143           e->attributes->d_parent = this;
00144         }
00145     }
00146 }
00147 
00151 AttrTable::AttrTable()
00152   : DapObj()
00153   , d_name("")
00154   , d_parent(0)
00155   , attr_map()
00156   , d_is_global_attribute(true)
00157 {
00158 }
00159 
00160 AttrTable::AttrTable(const AttrTable &rhs)
00161 : DapObj()
00162 {
00163     clone(rhs);
00164 }
00165 
00166 // Private
00167 void AttrTable::delete_attr_table()
00168 {
00169     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
00170         delete *i;
00171         *i = 0;
00172     }
00173     attr_map.clear();
00174 }
00175 
00176 AttrTable::~AttrTable()
00177 {
00178     DBG(cerr << "Entering ~AttrTable (" << this << ")" << endl);
00179     delete_attr_table();DBG(cerr << "Exiting ~AttrTable" << endl);
00180 }
00181 
00182 AttrTable &
00183 AttrTable::operator=(const AttrTable &rhs)
00184 {
00185     if (this != &rhs) {
00186         delete_attr_table();
00187         clone(rhs);
00188     }
00189 
00190     return *this;
00191 }
00193 
00199 unsigned int
00200 AttrTable::get_size() const
00201 {
00202     return attr_map.size();
00203 }
00204 
00207 string
00208 AttrTable::get_name() const
00209 {
00210     return d_name;
00211 }
00212 
00215 void
00216 AttrTable::set_name(const string &n)
00217 {
00218     d_name = www2id(n);
00219 }
00220 
00238 unsigned int
00239 AttrTable::append_attr(const string &name, const string &type,
00240         const string &attribute)
00241 {
00242     DBG(cerr << "Entering AttrTable::append_attr" << endl);
00243     string lname = www2id(name);
00244 
00245     Attr_iter iter = simple_find(lname);
00246 
00247     // If the types don't match OR this attribute is a container, calling
00248     // this mfunc is an error!
00249     if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
00250     throw Error(string("An attribute called `") + name
00251             + string("' already exists but is of a different type"));
00252     if (iter != attr_map.end() && (get_type(iter) == "Container"))
00253     throw Error(string("An attribute called `") + name
00254             + string("' already exists but is a container."));
00255 
00256     if (iter != attr_map.end()) { // Must be a new attribute value; add it.
00257         (*iter)->attr->push_back(attribute);
00258         return (*iter)->attr->size();
00259     }
00260     else { // Must be a completely new attribute; add it
00261         entry *e = new entry;
00262 
00263         e->name = lname;
00264         e->is_alias = false;
00265         e->type = String_to_AttrType(type); // Record type using standard names.
00266         e->attr = new vector<string>;
00267         e->attr->push_back(attribute);
00268 
00269         attr_map.push_back(e);
00270 
00271         return e->attr->size(); // return the length of the attr vector
00272     }
00273 }
00274 
00293 unsigned int
00294 AttrTable::append_attr(const string &name, const string &type,
00295         vector<string> *values)
00296 {
00297     DBG(cerr << "Entering AttrTable::append_attr(..., vector)" << endl);
00298     string lname = www2id(name);
00299 
00300     Attr_iter iter = simple_find(lname);
00301 
00302     // If the types don't match OR this attribute is a container, calling
00303     // this mfunc is an error!
00304     if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
00305     throw Error(string("An attribute called `") + name
00306             + string("' already exists but is of a different type"));
00307     if (iter != attr_map.end() && (get_type(iter) == "Container"))
00308     throw Error(string("An attribute called `") + name
00309             + string("' already exists but is a container."));
00310 
00311     if (iter != attr_map.end()) { // Must be new attribute values; add.
00312         vector<string>::iterator i = values->begin();
00313         while (i != values->end())
00314         (*iter)->attr->push_back(*i++);
00315 
00316         return (*iter)->attr->size();
00317     }
00318     else { // Must be a completely new attribute; add it
00319         entry *e = new entry;
00320 
00321         e->name = lname;
00322         e->is_alias = false;
00323         e->type = String_to_AttrType(type); // Record type using standard names.
00324         e->attr = new vector<string>(*values);
00325 
00326         attr_map.push_back(e);
00327 
00328         return e->attr->size(); // return the length of the attr vector
00329     }
00330 }
00331 
00341 AttrTable *
00342 AttrTable::append_container(const string &name)
00343 {
00344     AttrTable *new_at = new AttrTable;
00345     AttrTable *ret = NULL;
00346     try {
00347         ret = append_container(new_at, name);
00348     }
00349     catch (Error &e) {
00350         // an error occurred, attribute with that name already exists
00351         delete new_at; new_at = 0;
00352         throw ;
00353     }
00354     return ret;
00355 }
00356 
00371 AttrTable *
00372 AttrTable::append_container(AttrTable *at, const string &name)
00373 {
00374     string lname = www2id(name);
00375 
00376     if (simple_find(name) != attr_end())
00377     throw Error(string("There already exists a container called `")
00378             + name + string("' in this attribute table."));
00379     DBG(cerr << "Setting appended attribute container name to: "
00380             << lname << endl);
00381     at->set_name(lname);
00382 
00383     entry *e = new entry;
00384     e->name = lname;
00385     e->is_alias = false;
00386     e->type = Attr_container;
00387     e->attributes = at;
00388 
00389     attr_map.push_back(e);
00390 
00391     at->d_parent = this;
00392 
00393     return e->attributes;
00394 }
00395 
00410 void
00411 AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter)
00412 {
00413     string::size_type dotpos = target.rfind('.');
00414     if (dotpos != string::npos) {
00415         string container = target.substr(0, dotpos);
00416         string field = target.substr(dotpos + 1);
00417 
00418         *at = find_container(container);
00419         if (*at) {
00420             *iter = (*at)->simple_find(field);
00421         }
00422         else {
00423             *iter = attr_map.end();
00424         }
00425     }
00426     else {
00427         *at = recurrsive_find(target, iter);
00428     }
00429 }
00430 
00442 AttrTable *
00443 AttrTable::recurrsive_find(const string &target, Attr_iter *location)
00444 {
00445     //*location = attr_begin();
00446     Attr_iter i = attr_begin();
00447     while (i != attr_end()) {
00448         if (target == (*i)->name) {
00449             *location = i;
00450             return this;
00451         }
00452         else if ((*i)->type == Attr_container) {
00453             AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
00454             if (at)
00455             return at;
00456         }
00457 
00458         ++i;
00459     }
00460 
00461     *location = i;
00462     return 0;
00463 }
00464 
00465 // Made public for callers that want non-recursive find.  [mjohnson 6 oct 09]
00472 AttrTable::Attr_iter
00473 AttrTable::simple_find(const string &target)
00474 {
00475     Attr_iter i;
00476     for (i = attr_map.begin(); i != attr_map.end(); ++i) {
00477         if (target == (*i)->name) {
00478             break;
00479         }
00480     }
00481     return i;
00482 }
00483 
00497 AttrTable *
00498 AttrTable::find_container(const string &target)
00499 {
00500     string::size_type dotpos = target.find('.');
00501     if (dotpos != string::npos) {
00502         string container = target.substr(0, dotpos);
00503         string field = target.substr(dotpos + 1);
00504 
00505         AttrTable *at = simple_find_container(container);
00506         return (at) ? at->find_container(field) : 0;
00507     }
00508     else {
00509         return simple_find_container(target);
00510     }
00511 }
00512 
00513 // Made public for callers that want non-recursive find.  [mjohnson 6 oct 09]
00514 AttrTable *
00515 AttrTable::simple_find_container(const string &target)
00516 {
00517     if (get_name() == target)
00518     return this;
00519 
00520     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
00521         if (is_container(i) && target == (*i)->name) {
00522             return (*i)->attributes;
00523         }
00524     }
00525 
00526     return 0;
00527 }
00528 
00536 
00538 AttrTable *
00539 AttrTable::get_attr_table(const string &name)
00540 {
00541     return find_container(name);
00542 }
00543 
00545 string
00546 AttrTable::get_type(const string &name)
00547 {
00548     Attr_iter p = simple_find(name);
00549     return (p != attr_map.end()) ? get_type(p) : (string)"";
00550 }
00551 
00554 AttrType
00555 AttrTable::get_attr_type(const string &name)
00556 {
00557     Attr_iter p = simple_find(name);
00558     return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
00559 }
00560 
00568 unsigned int
00569 AttrTable::get_attr_num(const string &name)
00570 {
00571     Attr_iter iter = simple_find(name);
00572     return (iter != attr_map.end()) ? get_attr_num(iter) : 0;
00573 }
00574 
00587 vector<string> *
00588 AttrTable::get_attr_vector(const string &name)
00589 {
00590     Attr_iter p = simple_find(name);
00591     return (p != attr_map.end()) ? get_attr_vector(p) : 0;
00592 }
00593 
00610 void
00611 AttrTable::del_attr(const string &name, int i)
00612 {
00613     string lname = www2id(name);
00614 
00615     Attr_iter iter = simple_find(lname);
00616     if (iter != attr_map.end()) {
00617         if (i == -1) { // Delete the whole attribute
00618             entry *e = *iter;
00619             attr_map.erase(iter);
00620             delete e; e = 0;
00621         }
00622         else { // Delete one element from attribute array
00623             // Don't try to delete elements from the vector of values if the
00624             // map is a container!
00625             if ((*iter)->type == Attr_container)
00626             return;
00627 
00628             vector<string> *sxp = (*iter)->attr;
00629 
00630             assert(i >= 0 && i < (int)sxp->size());
00631             sxp->erase(sxp->begin() + i); // rm the element
00632         }
00633     }
00634 }
00635 
00637 
00642 AttrTable::Attr_iter
00643 AttrTable::attr_begin()
00644 {
00645     return attr_map.begin();
00646 }
00647 
00651 AttrTable::Attr_iter
00652 AttrTable::attr_end()
00653 {
00654     return attr_map.end();
00655 }
00656 
00665 AttrTable::Attr_iter
00666 AttrTable::get_attr_iter(int i)
00667 {
00668     return attr_map.begin() + i;
00669 }
00670 
00672 string
00673 AttrTable::get_name(Attr_iter iter)
00674 {
00675     assert(iter != attr_map.end());
00676 
00677     return (*iter)->name;
00678 }
00679 
00681 bool
00682 AttrTable::is_container(Attr_iter i)
00683 {
00684     return (*i)->type == Attr_container;
00685 }
00686 
00692 AttrTable *
00693 AttrTable::get_attr_table(Attr_iter iter)
00694 {
00695     assert(iter != attr_map.end());
00696     return (*iter)->type == Attr_container ? (*iter)->attributes : 0;
00697 }
00698 
00707 AttrTable::Attr_iter
00708 AttrTable::del_attr_table(Attr_iter iter)
00709 {
00710     if ((*iter)->type != Attr_container)
00711     return ++iter;
00712 
00713     // the caller intends to delete/reuse the contained AttrTable,
00714     // so zero it out so it doesn't get deleted before we delete the entry
00715     // [mjohnson]
00716     struct entry* e = *iter;
00717     // container no longer has a parent.
00718     if (e->attributes) {
00719       e->attributes->d_parent = 0;
00720     }
00721     e->attributes = 0;
00722     delete e;
00723 
00724     return attr_map.erase(iter);
00725 }
00726 
00730 string
00731 AttrTable::get_type(Attr_iter iter)
00732 {
00733     assert(iter != attr_map.end());
00734     return AttrType_to_String((*iter)->type);
00735 }
00736 
00740 AttrType
00741 AttrTable::get_attr_type(Attr_iter iter)
00742 {
00743     return (*iter)->type;
00744 }
00745 
00753 unsigned int
00754 AttrTable::get_attr_num(Attr_iter iter)
00755 {
00756     assert(iter != attr_map.end());
00757     return ((*iter)->type == Attr_container)
00758     ? (*iter)->attributes->get_size()
00759     : (*iter)->attr->size();
00760 }
00761 
00778 string
00779 AttrTable::get_attr(Attr_iter iter, unsigned int i)
00780 {
00781     assert(iter != attr_map.end());
00782 #if 1
00783     return (*iter)->type == Attr_container ? (string)"None" : (*(*iter)->attr)[i];
00784 #else
00785     if ((*iter)->type == Attr_container) {
00786         return "None";
00787     }
00788     else {
00789         cerr << "(*iter)->attr: " << (*iter)->attr << endl;
00790         cerr << "(*iter)->name: " << (*iter)->name << endl;
00791         cerr << "(*iter)->type: " << (*iter)->type << endl;
00792         //cerr << "get_attr: return value: [" << i << "]: " << (*(*iter)->attr)[i]<< endl;
00793         if ((*iter)->name == "SIS_ID")
00794         return "SIS_ID_value";
00795         else
00796         return (*(*iter)->attr)[i];
00797     }
00798 #endif
00799 }
00800 
00801 string
00802 AttrTable::get_attr(const string &name, unsigned int i)
00803 {
00804     Attr_iter p = simple_find(name);
00805     return (p != attr_map.end()) ? get_attr(p, i) : (string)"";
00806 }
00807 
00819 vector<string> *
00820 AttrTable::get_attr_vector(Attr_iter iter)
00821 {
00822     assert(iter != attr_map.end());
00823     return (*iter)->type != Attr_container ? (*iter)->attr : 0;
00824 }
00825 
00826 bool
00827 AttrTable::is_global_attribute(Attr_iter iter)
00828 {
00829     assert(iter != attr_map.end());
00830     if ((*iter)->type == Attr_container)
00831         return (*iter)->attributes->is_global_attribute();
00832     else
00833         return (*iter)->is_global;
00834 }
00835 
00836 void
00837 AttrTable::set_is_global_attribute(Attr_iter iter, bool ga)
00838 {
00839     assert(iter != attr_map.end());
00840     if ((*iter)->type == Attr_container)
00841         (*iter)->attributes->set_is_global_attribute(ga);
00842     else
00843         (*iter)->is_global = ga;
00844 }
00845 
00847 
00848 // Alias an attribute table. The alias should be added to this object.
00854 void
00855 AttrTable::add_container_alias(const string &name, AttrTable *src)
00856 {
00857     string lname = www2id(name);
00858 
00859     if (simple_find(lname) != attr_end())
00860     throw Error(string("There already exists a container called `")
00861             + name + string("in this attribute table."));
00862 
00863     entry *e = new entry;
00864     e->name = lname;
00865     e->is_alias = true;
00866     e->aliased_to = src->get_name();
00867     e->type = Attr_container;
00868 
00869     e->attributes = src;
00870 
00871     attr_map.push_back(e);
00872 }
00873 
00886 void
00887 AttrTable::add_value_alias(AttrTable *das, const string &name,
00888         const string &source)
00889 {
00890     string lname = www2id(name);
00891     string lsource = www2id(source);
00892 
00893     // find the container that holds source and its (sources's) iterator
00894     // within that container. Search at the uppermost level of the attribute
00895     // object to find values defined `above' the current container.
00896     AttrTable *at;
00897     Attr_iter iter;
00898     das->find(lsource, &at, &iter);
00899 
00900     // If source is not found by looking at the topmost level, look in the
00901     // current table (i.e., alias z x where x is in the current container
00902     // won't be found by looking for `x' at the top level). See test case 26
00903     // in das-testsuite.
00904     if (!at || (iter == at->attr_end()) || !*iter) {
00905         find(lsource, &at, &iter);
00906         if (!at || (iter == at->attr_end()) || !*iter)
00907         throw Error(string("Could not find the attribute `")
00908                 + source + string("' in the attribute object."));
00909     }
00910 
00911     // If we've got a value to alias and it's being added at the top level of
00912     // the DAS, that's an error.
00913     if (at && !at->is_container(iter) && this == das)
00914     throw Error(string("A value cannot be aliased to the top level of the DAS;\nOnly containers may be present at that level of the DAS."));
00915 
00916     if (simple_find(lname) != attr_end())
00917     throw Error(string("There already exists a container called `")
00918             + name + string("in this attribute table."));
00919 
00920     entry *e = new entry;
00921     e->name = lname;
00922     e->is_alias = true;
00923     e->aliased_to = lsource;
00924     e->type = get_attr_type(iter);
00925     if (at && e->type == Attr_container)
00926     e->attributes = at->get_attr_table(iter);
00927     else
00928     e->attr = (*iter)->attr;
00929 
00930     attr_map.push_back(e);
00931 }
00932 
00933 // Deprecated
00952 bool
00953 AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
00954 {
00955     add_value_alias(at, alias, name);
00956     return true;
00957 }
00958 
00966 bool
00967 AttrTable::attr_alias(const string &alias, const string &name)
00968 {
00969     return attr_alias(alias, this, name);
00970 }
00971 
00975 void
00976 AttrTable::erase()
00977 {
00978     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
00979         delete *i; *i = 0;
00980     }
00981 
00982     attr_map.erase(attr_map.begin(), attr_map.end());
00983 
00984     d_name = "";
00985 }
00986 
00987 const string double_quote = "\"";
00988 
00989 // This is here as a result of the problem described in ticket #1163 where
00990 // the data handlers are adding quotes to string attributes so the DAS will
00991 // be printed correctly. But that has the affect of adding the quotes to the
00992 // attribute's _value_ not just it's print representation. As part of the fix
00993 // I made the code here add the quotes if the handlers are fixed (but not if
00994 // handlers are still adding them). The other part of 1163 is to fix all of
00995 // the handlers... What this fix means is that attributes whose values really
00996 // do contain bracketing quotes might be misunderstood, since we're assuming
00997 // those quotes were added by the handlers as a hack to get the output
00998 // formatting correct for the DAS. jhrg 7/30/08
00999 
01000 static void
01001 write_string_attribute_for_das(ostream &out, const string &value, const string &term)
01002 {
01003     if (is_quoted(value))
01004     out << value << term;
01005     else
01006     out << double_quote << value << double_quote << term;
01007 }
01008 
01009 static void
01010 write_string_attribute_for_das(FILE *out, const string &value, const string &term)
01011 {
01012     if (is_quoted(value))
01013     fprintf(out, "%s%s", value.c_str(), term.c_str());
01014     else
01015     fprintf(out, "\"%s\"%s", value.c_str(), term.c_str());
01016 }
01017 
01018 // Special treatment for XML: Make sure to escape double quotes when XML is
01019 // printed in a DAS.
01020 static void
01021 write_xml_attribute_for_das(ostream &out, const string &value, const string &term)
01022 {
01023     if (is_quoted(value))
01024     out << escape_double_quotes(value) << term;
01025     else
01026     out << double_quote << escape_double_quotes(value) << double_quote << term;
01027 }
01028 
01029 static void
01030 write_xml_attribute_for_das(FILE *out, const string &value, const string &term)
01031 {
01032     if (is_quoted(value))
01033     fprintf(out, "%s%s", escape_double_quotes(value).c_str(), term.c_str());
01034     else
01035     fprintf(out, "\"%s\"%s", escape_double_quotes(value).c_str(), term.c_str());
01036 }
01037 
01040 void
01041 AttrTable::simple_print(FILE *out, string pad, Attr_iter i,
01042         bool dereference)
01043 {
01044     switch ((*i)->type) {
01045         case Attr_container:
01046         fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str());
01047 
01048         (*i)->attributes->print(out, pad + "    ", dereference);
01049 
01050         fprintf(out, "%s}\n", pad.c_str());
01051         break;
01052 
01053         case Attr_string: {
01054             fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(),
01055                     id2www(get_name(i)).c_str());
01056 
01057             vector<string> *sxp = (*i)->attr;
01058             vector<string>::iterator last = sxp->end() - 1;
01059             for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
01060                 write_string_attribute_for_das(out, *i, ", ");
01061             }
01062             write_string_attribute_for_das(out, *last, ";\n");
01063         }
01064         break;
01065 
01066         case Attr_other_xml: {
01067             fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(),
01068                     id2www(get_name(i)).c_str());
01069 
01070             vector<string> *sxp = (*i)->attr;
01071             vector<string>::iterator last = sxp->end() - 1;
01072             for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
01073                 write_xml_attribute_for_das(out, *i, ", ");
01074             }
01075             write_xml_attribute_for_das(out, *last, ";\n");
01076         }
01077         break;
01078 
01079         default: {
01080             fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(),
01081                     id2www(get_name(i)).c_str());
01082 
01083             vector<string> *sxp = (*i)->attr;
01084             vector<string>::iterator last = sxp->end() - 1;
01085             for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
01086                 fprintf(out, "%s%s", (*i).c_str(), ", ");
01087             }
01088             fprintf(out, "%s%s", (*last).c_str(), ";\n");
01089         }
01090         break;
01091     }
01092 }
01093 
01096 void
01097 AttrTable::simple_print(ostream &out, string pad, Attr_iter i,
01098         bool dereference)
01099 {
01100     switch ((*i)->type) {
01101         case Attr_container:
01102         out << pad << id2www(get_name(i)) << " {\n";
01103 
01104         (*i)->attributes->print(out, pad + "    ", dereference);
01105 
01106         out << pad << "}\n";
01107         break;
01108 
01109         case Attr_string: {
01110             out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
01111 
01112             vector<string> *sxp = (*i)->attr;
01113             vector<string>::iterator last = sxp->end() - 1;
01114             for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
01115                 write_string_attribute_for_das(out, *i, ", ");
01116             }
01117             write_string_attribute_for_das(out, *last, ";\n");
01118         }
01119         break;
01120 
01121         case Attr_other_xml: {
01122             out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
01123 
01124             vector<string> *sxp = (*i)->attr;
01125             vector<string>::iterator last = sxp->end() - 1;
01126             for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
01127                 write_xml_attribute_for_das(out, *i, ", ");
01128             }
01129             write_xml_attribute_for_das(out, *last, ";\n");
01130         }
01131         break;
01132 
01133         default: {
01134             out << pad << get_type(i) << " " << id2www(get_name(i)) << " ";
01135 
01136             vector<string> *sxp = (*i)->attr;
01137             vector<string>::iterator last = sxp->end() - 1;
01138             for (vector<string>::iterator i = sxp->begin(); i != last; ++i) {
01139                 out << *i <<", ";
01140             }
01141             out << *last << ";\n";
01142         }
01143         break;
01144     }
01145 }
01146 
01157 void
01158 AttrTable::print(FILE *out, string pad, bool dereference)
01159 {
01160     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
01161         if ((*i)->is_alias) {
01162             if (dereference) {
01163                 simple_print(out, pad, i, dereference);
01164             }
01165             else {
01166                 fprintf(out, "%sAlias %s %s;\n",
01167                         pad.c_str(),
01168                         id2www(get_name(i)).c_str(),
01169                         id2www((*i)->aliased_to).c_str());
01170             }
01171         }
01172         else {
01173             simple_print(out, pad, i, dereference);
01174         }
01175     }
01176 }
01177 
01188 void
01189 AttrTable::print(ostream &out, string pad, bool dereference)
01190 {
01191     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); ++i) {
01192         if ((*i)->is_alias) {
01193             if (dereference) {
01194                 simple_print(out, pad, i, dereference);
01195             }
01196             else {
01197                 out << pad << "Alias " << id2www(get_name(i))
01198                 << " " << id2www((*i)->aliased_to) << ";\n";
01199             }
01200         }
01201         else {
01202             simple_print(out, pad, i, dereference);
01203         }
01204     }
01205 }
01206 
01211 void
01212 AttrTable::print_xml(FILE *out, string pad, bool /*constrained*/)
01213 {
01214     // Why this works: AttrTable is really a hacked class that used to
01215     // implement a single-level set of attributes. Containers
01216     // were added several years later by dropping in the 'entry' structure.
01217     // It's not a class in its own right; instead accessors from AttrTable
01218     // are used to access information from entry. So... the loop below
01219     // actually iterates over the entries of *this* (which is an instance of
01220     // AttrTable). A container is an entry whose sole value is an AttrTable
01221     // instance. 05/19/03 jhrg
01222     for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
01223         if ((*i)->is_alias) {
01224             fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\"/>\n",
01225                     pad.c_str(), id2xml(get_name(i)).c_str(),
01226                     (*i)->aliased_to.c_str());
01227 
01228         }
01229         else if (is_container(i)) {
01230             fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
01231                     pad.c_str(), id2xml(get_name(i)).c_str(),
01232                     get_type(i).c_str());
01233 
01234             get_attr_table(i)->print_xml(out, pad + "    "/*, constrained*/);
01235 
01236             fprintf(out, "%s</Attribute>\n", pad.c_str());
01237         }
01238         else {
01239             fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
01240                     pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
01241 
01242             string value_pad = pad + "    ";
01243             // Special handling for the OtherXML attribute type - don't escape
01244             // the XML and don't include the <value> element. Note that there
01245             // cannot be an vector of XML things as can be with the other types.
01246             if (get_attr_type(i) == Attr_other_xml) {
01247                 if (get_attr_num(i) != 1)
01248                     throw Error("OtherXML attributes cannot be vector-valued.");
01249                 fprintf(out, "%s%s\n", value_pad.c_str(), get_attr(i, 0).c_str());
01250             }
01251             else {
01252                 for (unsigned j = 0; j < get_attr_num(i); ++j) {
01253                     fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
01254                             id2xml(get_attr(i, j)).c_str());
01255                 }
01256             }
01257             fprintf(out, "%s</Attribute>\n", pad.c_str());
01258         }
01259     }
01260 }
01261 
01266 void
01267 AttrTable::print_xml(ostream &out, string pad, bool /*constrained*/)
01268 {
01269     for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
01270         if ((*i)->is_alias) {
01271             out << pad << "<Alias name=\"" << id2xml(get_name(i))
01272             << "\" Attribute=\"" << (*i)->aliased_to << "\"/>\n";
01273 
01274         }
01275         else if (is_container(i)) {
01276             out << pad << "<Attribute name=\"" << id2xml(get_name(i))
01277             << "\" type=\"" << get_type(i) << "\">\n";
01278 
01279             get_attr_table(i)->print_xml(out, pad + "    "/*, constrained*/);
01280 
01281             out << pad << "</Attribute>\n";
01282         }
01283         else {
01284             out << pad << "<Attribute name=\"" << id2xml(get_name(i))
01285             << "\" type=\"" << get_type(i) << "\">\n";
01286 
01287             string value_pad = pad + "    ";
01288             if (get_attr_type(i) == Attr_other_xml) {
01289                 if (get_attr_num(i) != 1)
01290                     throw Error("OtherXML attributes cannot be vector-valued.");
01291                 out << value_pad << get_attr(i, 0) << "\n";
01292             }
01293             else {
01294                 string value_pad = pad + "    ";
01295                 for (unsigned j = 0; j < get_attr_num(i); ++j) {
01296                     out << value_pad << "<value>" << id2xml(get_attr(i, j)) << "</value>\n";
01297                 }
01298             }
01299             out << pad << "</Attribute>\n";
01300         }
01301     }
01302 }
01303 
01311 void
01312 AttrTable::dump(ostream &strm) const
01313 {
01314     strm << DapIndent::LMarg << "AttrTable::dump - ("
01315     << (void *)this << ")" << endl;
01316     DapIndent::Indent();
01317     strm << DapIndent::LMarg << "table name: " << d_name << endl;
01318     if (attr_map.size()) {
01319         strm << DapIndent::LMarg << "attributes: " << endl;
01320         DapIndent::Indent();
01321         Attr_citer i = attr_map.begin();
01322         Attr_citer ie = attr_map.end();
01323         for (; i != ie; ++i) {
01324             entry *e = (*i);
01325             string type = AttrType_to_String(e->type);
01326             if (e->is_alias) {
01327                 strm << DapIndent::LMarg << "alias: " << e->name
01328                 << " aliased to: " << e->aliased_to
01329                 << endl;
01330             }
01331             else if (e->type == Attr_container) {
01332                 strm << DapIndent::LMarg << "attr: " << e->name
01333                 << " of type " << type
01334                 << endl;
01335                 DapIndent::Indent();
01336                 e->attributes->dump(strm);
01337                 DapIndent::UnIndent();
01338             }
01339             else {
01340                 strm << DapIndent::LMarg << "attr: " << e->name
01341                 << " of type " << type
01342                 << endl;
01343                 DapIndent::Indent();
01344                 strm << DapIndent::LMarg;
01345                 vector<string>::const_iterator iter = e->attr->begin();
01346                 vector<string>::const_iterator last = e->attr->end() - 1;
01347                 for (; iter != last; ++iter) {
01348                     strm << (*iter) << ", ";
01349                 }
01350                 strm << (*(e->attr->end() - 1)) << endl;
01351                 DapIndent::UnIndent();
01352             }
01353         }
01354         DapIndent::UnIndent();
01355     }
01356     else {
01357         strm << DapIndent::LMarg << "attributes: empty" << endl;
01358     }
01359     if (d_parent) {
01360         strm << DapIndent::LMarg << "parent table:"
01361         << d_name << ":" << (void *)d_parent << endl;
01362     }
01363     else {
01364         strm << DapIndent::LMarg << "parent table: none" << d_name << endl;
01365     }
01366     DapIndent::UnIndent();
01367 }
01368 
01369 } // namespace libdap
01370