AttrTable.cc

Go to the documentation of this file.
00001 
00002 // -*- mode: c++; c-basic-offset:4 -*-
00003 
00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00005 // Access Protocol.
00006 
00007 // Copyright (c) 2002,2003 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 // (c) COPYRIGHT URI/MIT 1994-1999
00027 // Please read the full copyright statement in the file COPYRIGHT_URI.
00028 //
00029 // Authors:
00030 //      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
00031 
00032 // jhrg 7/29/94
00033 
00034 #include "config.h"
00035 
00036 static char rcsid[] not_used = "$Id: AttrTable.cc 16726 2007-06-21 18:03:26Z jimg $";
00037 
00038 #include <assert.h>
00039 
00040 #include "AttrTable.h"
00041 
00042 #include "util.h"
00043 #include "escaping.h"
00044 
00045 #include "debug.h"
00046 
00047 using std::cerr;
00048 using std::string;
00049 using std::endl;
00050 using std::vector;
00051 
00055 string
00056 AttrType_to_String(const AttrType at)
00057 {
00058     switch (at) {
00059     case Attr_container: return "Container";
00060     case Attr_byte: return "Byte";
00061     case Attr_int16: return "Int16";
00062     case Attr_uint16: return "UInt16";
00063     case Attr_int32: return "Int32";
00064     case Attr_uint32: return "UInt32";
00065     case Attr_float32: return "Float32";
00066     case Attr_float64: return "Float64";
00067     case Attr_string: return "String";
00068     case Attr_url: return "Url";
00069     default: return "";
00070     }
00071 }
00072 
00073 AttrType
00074 String_to_AttrType(const string &s)
00075 {
00076     string s2 = s;
00077     downcase(s2);
00078 
00079     if (s2 == "container")
00080         return Attr_container;
00081     else if (s2 == "byte")
00082         return Attr_byte;
00083     else if (s2 == "int16")
00084         return Attr_int16;
00085     else if (s2 == "uint16")
00086         return Attr_uint16;
00087     else if (s2 == "int32")
00088         return Attr_int32;
00089     else if (s2 == "uint32")
00090         return Attr_uint32;
00091     else if (s2 == "float32")
00092         return Attr_float32;
00093     else if (s2 == "float64")
00094         return Attr_float64;
00095     else if (s2 == "string")
00096         return Attr_string;
00097     else if (s2 == "url")
00098         return Attr_url;
00099     else
00100         return Attr_unknown;
00101 }
00102 
00105 void
00106 AttrTable::clone(const AttrTable &at)
00107 {
00108     d_name = at.d_name;
00109 
00110     Attr_citer i = at.attr_map.begin() ;
00111     Attr_citer ie = at.attr_map.end() ;
00112     for (; i != ie; i++) {
00113         entry *e = new entry(*(*i)) ;
00114         attr_map.push_back(e) ;
00115     }
00116 
00117     d_parent = at.d_parent;
00118 }
00119 
00123 AttrTable::AttrTable() : d_name(""), d_parent(0)
00124 {}
00125 
00126 AttrTable::AttrTable(const AttrTable &rhs) : DapObj()
00127 {
00128     clone(rhs);
00129 }
00130 
00131 // Private
00132 void
00133 AttrTable::delete_attr_table()
00134 {
00135     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); i++) {
00136         delete *i; *i = 0;
00137     }
00138 }
00139 
00140 AttrTable::~AttrTable()
00141 {
00142     DBG(cerr << "Entering ~AttrTable (" << this << ")" << endl);
00143     delete_attr_table();
00144     DBG(cerr << "Exiting ~AttrTable" << endl);
00145 }
00146 
00147 AttrTable &
00148 AttrTable::operator=(const AttrTable &rhs)
00149 {
00150     if (this != &rhs) {
00151         delete_attr_table();
00152         clone(rhs);
00153     }
00154 
00155     return *this;
00156 }
00158 
00164 unsigned int
00165 AttrTable::get_size() const
00166 {
00167     return attr_map.size();
00168 }
00169 
00172 string
00173 AttrTable::get_name() const
00174 {
00175     return d_name;
00176 }
00177 
00180 void
00181 AttrTable::set_name(const string &n)
00182 {
00183     d_name = www2id(n);
00184 }
00185 
00203 unsigned int
00204 AttrTable::append_attr(const string &name, const string &type,
00205                        const string &attribute)
00206 {
00207     string lname = www2id(name);
00208 
00209     Attr_iter iter = simple_find(lname) ;
00210 
00211     // If the types don't match OR this attribute is a container, calling
00212     // this mfunc is an error!
00213     if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
00214         throw Error(string("An attribute called `") + name
00215                     + string("' already exists but is of a different type"));
00216     if (iter != attr_map.end() && (get_type(iter) == "Container"))
00217         throw Error(string("An attribute called `") + name
00218                     + string("' already exists but is a container."));
00219 
00220     if (iter != attr_map.end()) {    // Must be a new attribute value; add it.
00221         (*iter)->attr->push_back(attribute);
00222         return (*iter)->attr->size();
00223     }
00224     else {   // Must be a completely new attribute; add it
00225         entry *e = new entry;
00226 
00227         e->name = lname;
00228         e->is_alias = false;
00229         e->type = String_to_AttrType(type); // Record type using standard names.
00230         e->attr = new vector<string>;
00231         e->attr->push_back(attribute);
00232 
00233         attr_map.push_back(e);
00234 
00235         return e->attr->size(); // return the length of the attr vector
00236     }
00237 }
00238 
00256 unsigned int
00257 AttrTable::append_attr(const string &name, const string &type,
00258                        vector<string> *values)
00259 {
00260     string lname = www2id(name);
00261 
00262     Attr_iter iter = simple_find(lname) ;
00263 
00264     // If the types don't match OR this attribute is a container, calling
00265     // this mfunc is an error!
00266     if (iter != attr_map.end() && ((*iter)->type != String_to_AttrType(type)))
00267         throw Error(string("An attribute called `") + name
00268                     + string("' already exists but is of a different type"));
00269     if (iter != attr_map.end() && (get_type(iter) == "Container"))
00270         throw Error(string("An attribute called `") + name
00271                     + string("' already exists but is a container."));
00272 
00273     if (iter != attr_map.end()) {    // Must be new attribute values; add.
00274         vector<string>::iterator i = values->begin();
00275         while (i != values->end())
00276             (*iter)->attr->push_back(*i++);
00277 
00278         return (*iter)->attr->size();
00279     }
00280     else {                    // Must be a completely new attribute; add it
00281         entry *e = new entry;
00282 
00283         e->name = lname;
00284         e->is_alias = false;
00285         e->type = String_to_AttrType(type); // Record type using standard names.
00286         e->attr = new vector<string>(*values);
00287 
00288         attr_map.push_back(e);
00289 
00290         return e->attr->size(); // return the length of the attr vector
00291     }
00292 }
00293 
00302 AttrTable *
00303 AttrTable::append_container(const string &name)
00304 {
00305     AttrTable *new_at = new AttrTable ;
00306     AttrTable *ret = NULL ;
00307     try {
00308         ret = append_container(new_at, name) ;
00309     }
00310     catch (Error &e) {
00311         // an error occurred, attribute with that name already exists
00312         delete new_at; new_at = 0;
00313         throw e;
00314     }
00315     return ret;
00316 }
00317 
00330 AttrTable *
00331 AttrTable::append_container(AttrTable *at, const string &name)
00332 {
00333     string lname = www2id(name);
00334 
00335     if (simple_find(name) != attr_end())
00336         throw Error(string("There already exists a container called `")
00337                     + name + string("' in this attribute table."));
00338     DBG(cerr << "Setting appended attribute container name to: "
00339         << lname << endl);
00340     at->set_name(lname);
00341 
00342     entry *e = new entry;
00343     e->name = lname;
00344     e->is_alias = false;
00345     e->type = Attr_container;
00346     e->attributes = at;
00347 
00348     attr_map.push_back(e);
00349 
00350     at->d_parent = this;
00351 
00352     return e->attributes;
00353 }
00354 
00369 void
00370 AttrTable::find(const string &target, AttrTable **at, Attr_iter *iter)
00371 {
00372     string::size_type dotpos = target.rfind('.');
00373     if (dotpos != string::npos) {
00374         string container = target.substr(0, dotpos);
00375         string field = target.substr(dotpos + 1);
00376 
00377         *at = find_container(container) ;
00378         if (*at) {
00379             *iter = (*at)->simple_find(field) ;
00380         }
00381         else {
00382             *iter = attr_map.end() ;
00383         }
00384     }
00385     else {
00386 #if 0
00387         // Replaced this call to simple_find with the call to recursive_find
00388         // so that older code that assumes that attribute names will not need
00389         // to be FQNs works. jhrg 2/9/06
00390         *at = this;
00391         *iter = simple_find(target);
00392 #endif
00393         *at = recurrsive_find(target, iter);
00394     }
00395 }
00396 
00408 AttrTable *
00409 AttrTable::recurrsive_find(const string &target, Attr_iter *location)
00410 {
00411     //*location = attr_begin();
00412     Attr_iter i = attr_begin();
00413     while (i != attr_end()) {
00414         if (target == (*i)->name) {
00415             *location = i;
00416             return this;
00417         }
00418         else if ((*i)->type == Attr_container) {
00419             AttrTable *at = (*i)->attributes->recurrsive_find(target, location);
00420             if (at)
00421                 return at;
00422         }
00423 
00424         ++i;
00425     }
00426 
00427     *location = i;
00428     return 0;
00429 }
00430 
00431 // Private
00438 AttrTable::Attr_iter
00439 AttrTable::simple_find(const string &target)
00440 {
00441     Attr_iter i ;
00442     for (i = attr_map.begin(); i != attr_map.end(); i++) {
00443         if (target == (*i)->name) {
00444             break ;
00445         }
00446     }
00447     return i ;
00448 }
00449 
00463 AttrTable *
00464 AttrTable::find_container(const string &target)
00465 {
00466     string::size_type dotpos = target.find('.');
00467     if (dotpos != string::npos) {
00468         string container = target.substr(0, dotpos);
00469         string field = target.substr(dotpos + 1);
00470 
00471         AttrTable *at = simple_find_container(container);
00472         return (at) ? at->find_container(field) : 0;
00473     }
00474     else {
00475         return simple_find_container(target);
00476     }
00477 }
00478 
00479 // Private
00480 AttrTable *
00481 AttrTable::simple_find_container(const string &target)
00482 {
00483     if (get_name() == target)
00484         return this;
00485 
00486     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); i++) {
00487         if (is_container(i) && target == (*i)->name) {
00488             return (*i)->attributes;
00489         }
00490     }
00491 
00492     return 0;
00493 }
00494 
00502 
00504 AttrTable *
00505 AttrTable::get_attr_table(const string &name)
00506 {
00507     return find_container(name);
00508 }
00509 
00511 string
00512 AttrTable::get_type(const string &name)
00513 {
00514     Attr_iter p = simple_find(name);
00515     return (p != attr_map.end()) ? get_type(p) : (string)"";
00516 }
00517 
00520 AttrType
00521 AttrTable::get_attr_type(const string &name)
00522 {
00523     Attr_iter p = simple_find(name);
00524     return (p != attr_map.end()) ? get_attr_type(p) : Attr_unknown;
00525 }
00526 
00534 unsigned int
00535 AttrTable::get_attr_num(const string &name)
00536 {
00537     Attr_iter iter = simple_find(name);
00538     return (iter != attr_map.end()) ?  get_attr_num(iter) : 0;
00539 }
00540 
00553 vector<string> *
00554 AttrTable::get_attr_vector(const string &name)
00555 {
00556     Attr_iter p = simple_find(name);
00557     return (p != attr_map.end()) ? get_attr_vector(p) : 0;
00558 }
00559 
00576 void
00577 AttrTable::del_attr(const string &name, int i)
00578 {
00579     string lname = www2id(name);
00580 
00581     Attr_iter iter = simple_find(lname) ;
00582     if (iter != attr_map.end()) {
00583         if (i == -1) {  // Delete the whole attribute
00584             entry *e = *iter ;
00585             attr_map.erase(iter) ;
00586             delete e ; e = 0;
00587         }
00588         else {   // Delete one element from attribute array
00589             // Don't try to delete elements from the vector of values if the
00590             // map is a container!
00591             if ((*iter)->type == Attr_container)
00592                 return;
00593 
00594             vector<string> *sxp = (*iter)->attr;
00595 
00596             assert(i >= 0 && i < (int)sxp->size());
00597             sxp->erase(sxp->begin() + i); // rm the element
00598         }
00599     }
00600 }
00601 
00603 
00608 AttrTable::Attr_iter
00609 AttrTable::attr_begin()
00610 {
00611     return attr_map.begin() ;
00612 }
00613 
00617 AttrTable::Attr_iter
00618 AttrTable::attr_end()
00619 {
00620     return attr_map.end() ;
00621 }
00622 
00631 AttrTable::Attr_iter
00632 AttrTable::get_attr_iter(int i)
00633 {
00634     return attr_map.begin() + i;
00635 }
00636 
00638 string
00639 AttrTable::get_name(Attr_iter iter)
00640 {
00641     assert(iter != attr_map.end()) ;
00642 
00643     return (*iter)->name ;
00644 }
00645 
00647 bool
00648 AttrTable::is_container(Attr_iter i)
00649 {
00650     return (*i)->type == Attr_container ;
00651 }
00652 
00658 AttrTable *
00659 AttrTable::get_attr_table(Attr_iter iter)
00660 {
00661     assert(iter != attr_map.end()) ;
00662     return (*iter)->type == Attr_container ? (*iter)->attributes : 0 ;
00663 }
00664 
00672 AttrTable::Attr_iter
00673 AttrTable::del_attr_table(Attr_iter iter)
00674 {
00675     if ((*iter)->type != Attr_container)
00676         return ++iter;
00677 
00678     return attr_map.erase(iter);
00679 }
00680 
00684 string
00685 AttrTable::get_type(Attr_iter iter)
00686 {
00687     assert(iter != attr_map.end()) ;
00688     return AttrType_to_String((*iter)->type) ;
00689 }
00690 
00694 AttrType
00695 AttrTable::get_attr_type(Attr_iter iter)
00696 {
00697     return (*iter)->type ;
00698 }
00699 
00707 unsigned int
00708 AttrTable::get_attr_num(Attr_iter iter)
00709 {
00710     assert(iter != attr_map.end()) ;
00711     return ((*iter)->type == Attr_container)
00712            ? (*iter)->attributes->get_size()
00713            : (*iter)->attr->size() ;
00714 }
00715 
00732 string
00733 AttrTable::get_attr(Attr_iter iter, unsigned int i)
00734 {
00735     assert(iter != attr_map.end());
00736 #if 1
00737     return (*iter)->type == Attr_container ? (string)"None" : (*(*iter)->attr)[i];
00738 #else
00739     if ((*iter)->type == Attr_container) {
00740         return "None";
00741     }
00742     else {
00743         cerr << "(*iter)->attr: " << (*iter)->attr << endl;
00744         cerr << "(*iter)->name: " << (*iter)->name << endl;
00745         cerr << "(*iter)->type: " << (*iter)->type << endl;
00746         //cerr << "get_attr: return value: [" << i << "]: " << (*(*iter)->attr)[i]<< endl;
00747         if ((*iter)->name == "SIS_ID")
00748             return "SIS_ID_value";
00749         else
00750             return (*(*iter)->attr)[i];
00751     }
00752 #endif
00753 }
00754 
00755 string
00756 AttrTable::get_attr(const string &name, unsigned int i)
00757 {
00758     Attr_iter p = simple_find(name);
00759     return (p != attr_map.end()) ? get_attr(p, i) : (string)"";
00760 }
00761 
00773 vector<string> *
00774 AttrTable::get_attr_vector(Attr_iter iter)
00775 {
00776     assert(iter != attr_map.end());
00777     return (*iter)->type != Attr_container ? (*iter)->attr : 0;
00778 }
00779 
00781 
00782 // Alias an attribute table. The alias should be added to this object.
00788 void
00789 AttrTable::add_container_alias(const string &name, AttrTable *src)
00790 {
00791     string lname = www2id(name);
00792 
00793     if (simple_find(lname) != attr_end())
00794         throw Error(string("There already exists a container called `")
00795                     + name + string("in this attribute table."));
00796 
00797     entry *e = new entry;
00798     e->name = lname;
00799     e->is_alias = true;
00800     e->aliased_to = src->get_name();
00801     e->type = Attr_container;
00802 
00803     e->attributes = src;
00804 
00805     attr_map.push_back(e);
00806 }
00807 
00820 void
00821 AttrTable::add_value_alias(AttrTable *das, const string &name,
00822                            const string &source)
00823 {
00824     string lname = www2id(name);
00825     string lsource = www2id(source);
00826 
00827     // find the container that holds source and its (sources's) iterator
00828     // within that container. Search at the uppermost level of the attribute
00829     // object to find values defined `above' the current container.
00830     AttrTable *at;
00831     Attr_iter iter;
00832     das->find(lsource, &at, &iter);
00833 
00834     // If source is not found by looking at the topmost level, look in the
00835     // current table (i.e., alias z x where x is in the current container
00836     // won't be found by looking for `x' at the top level). See test case 26
00837     // in das-testsuite.
00838     if (!at || (iter == at->attr_end()) || !*iter) {
00839         find(lsource, &at, &iter);
00840         if (!at || (iter == at->attr_end()) || !*iter)
00841             throw Error(string("Could not find the attribute `")
00842                         + source + string("' in the attribute object."));
00843     }
00844 
00845     // If we've got a value to alias and it's being added at the top level of
00846     // the DAS, that's an error.
00847     if (!at->is_container(iter) && this == das)
00848         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."));
00849 
00850     if (simple_find(lname) != attr_end())
00851         throw Error(string("There already exists a container called `")
00852                     + name + string("in this attribute table."));
00853 
00854     entry *e = new entry;
00855     e->name = lname;
00856     e->is_alias = true;
00857     e->aliased_to = lsource;
00858     e->type = get_attr_type(iter);
00859     if (e->type == Attr_container)
00860         e->attributes = at->get_attr_table(iter);
00861     else
00862         e->attr = (*iter)->attr;
00863 
00864     attr_map.push_back(e);
00865 }
00866 
00867 // Deprecated
00886 bool
00887 AttrTable::attr_alias(const string &alias, AttrTable *at, const string &name)
00888 {
00889     add_value_alias(at, alias, name);
00890     return true;
00891 }
00892 
00900 bool
00901 AttrTable::attr_alias(const string &alias, const string &name)
00902 {
00903     return attr_alias(alias, this, name);
00904 }
00905 
00909 void
00910 AttrTable::erase()
00911 {
00912     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); i++) {
00913         delete *i; *i = 0;
00914     }
00915 
00916     attr_map.erase(attr_map.begin(), attr_map.end());
00917 
00918     d_name = "";
00919 }
00920 
00921 
00924 void
00925 AttrTable::simple_print(FILE *out, string pad, Attr_iter i,
00926                         bool dereference)
00927 {
00928     switch ((*i)->type) {
00929     case Attr_container:
00930         fprintf(out, "%s%s {\n", pad.c_str(), id2www(get_name(i)).c_str()) ;
00931 
00932         (*i)->attributes->print(out, pad + "    ", dereference);
00933 
00934         fprintf(out, "%s}\n", pad.c_str()) ;
00935         break;
00936 
00937     default: {
00938             fprintf(out, "%s%s %s ", pad.c_str(), get_type(i).c_str(),
00939                     id2www(get_name(i)).c_str()) ;
00940 
00941             vector<string> *sxp = (*i)->attr;
00942 
00943             vector<string>::iterator last = sxp->end() - 1;
00944             for (vector<string>::iterator i = sxp->begin(); i != last; ++i)
00945                 fprintf(out, "%s, ", (*i).c_str()) ;
00946 
00947             fprintf(out, "%s;\n", (*(sxp->end() - 1)).c_str()) ;
00948         }
00949         break;
00950     }
00951 }
00952 
00963 void
00964 AttrTable::print(FILE *out, string pad, bool dereference)
00965 {
00966     for (Attr_iter i = attr_map.begin(); i != attr_map.end(); i++) {
00967         if ((*i)->is_alias) {
00968             if (dereference) {
00969                 simple_print(out, pad, i, dereference);
00970             }
00971             else {
00972                 fprintf(out, "%sAlias %s %s;\n",
00973                         pad.c_str(),
00974                         id2www(get_name(i)).c_str(),
00975                         id2www((*i)->aliased_to).c_str()) ;
00976             }
00977         }
00978         else {
00979             simple_print(out, pad, i, dereference);
00980         }
00981     }
00982 }
00983 
00989 void
00990 AttrTable::print_xml(FILE *out, string pad, bool constrained)
00991 {
00992     // Why this works: AttrTable is really a hacked class that used to
00993     // implement a single level, not nested, set of attributes. Containers
00994     // were added several years later by dropping in the 'entry' structure.
00995     // It's not a class in its own right; instead accessors from AttrTable
00996     // are used to access information from entry. So... the loop below
00997     // actually iterates over the entries of *this* (which is an instance of
00998     // AttrTable). A container is an entry whose sole value is an AttrTable
00999     // instance. 05/19/03 jhrg
01000     for (Attr_iter i = attr_begin(); i != attr_end(); ++i) {
01001         // To handle aliases, if constrained, check to see if the aliased
01002         // variable is part of the current projection. If so, then the
01003         // target is going to be sent so just write out the <Alias ...> tag.
01004         // If not, don't write the alias (we should write out the complete
01005         // target AttrTable, but that's not what the Java code does)
01006         if ((*i)->is_alias) {
01007             fprintf(out, "%s<Alias name=\"%s\" Attribute=\"%s\">\n",
01008                     pad.c_str(), id2xml(get_name(i)).c_str(),
01009                     (*i)->aliased_to.c_str());
01010 
01011         }
01012         else if (is_container(i)) {
01013             fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
01014                     pad.c_str(), id2xml(get_name(i)).c_str(),
01015                     get_type(i).c_str());
01016 
01017             get_attr_table(i)->print_xml(out, pad + "    ", constrained);
01018 
01019             fprintf(out, "%s</Attribute>\n", pad.c_str());
01020         }
01021         else {
01022             fprintf(out, "%s<Attribute name=\"%s\" type=\"%s\">\n",
01023                     pad.c_str(), id2xml(get_name(i)).c_str(), get_type(i).c_str());
01024 
01025             string value_pad = pad + "    ";
01026             for (unsigned j = 0; j < get_attr_num(i); ++j) {
01027                 fprintf(out, "%s<value>%s</value>\n", value_pad.c_str(),
01028                         id2xml(get_attr(i, j)).c_str());
01029             }
01030 
01031             fprintf(out, "%s</Attribute>\n", pad.c_str());
01032         }
01033     }
01034 }
01035 
01043 void
01044 AttrTable::dump(ostream &strm) const
01045 {
01046     strm << DapIndent::LMarg << "AttrTable::dump - ("
01047     << (void *)this << ")" << endl ;
01048     DapIndent::Indent() ;
01049     strm << DapIndent::LMarg << "table name: " << d_name << endl ;
01050     if (attr_map.size()) {
01051         strm << DapIndent::LMarg << "attributes: " << endl ;
01052         DapIndent::Indent() ;
01053         Attr_citer i = attr_map.begin() ;
01054         Attr_citer ie = attr_map.end() ;
01055         for (; i != ie; i++) {
01056             entry *e = (*i) ;
01057             string type = AttrType_to_String(e->type) ;
01058             if (e->is_alias) {
01059                 strm << DapIndent::LMarg << "alias: " << e->name
01060                 << " aliased to: " << e->aliased_to
01061                 << endl ;
01062             }
01063             else if (e->type == Attr_container) {
01064                 strm << DapIndent::LMarg << "attr: " << e->name
01065                 << " of type " << type
01066                 << endl ;
01067                 DapIndent::Indent() ;
01068                 e->attributes->dump(strm) ;
01069                 DapIndent::UnIndent() ;
01070             }
01071             else {
01072                 strm << DapIndent::LMarg << "attr: " << e->name
01073                 << " of type " << type
01074                 << endl ;
01075                 DapIndent::Indent() ;
01076                 strm << DapIndent::LMarg ;
01077                 vector<string>::const_iterator iter = e->attr->begin() ;
01078                 vector<string>::const_iterator last = e->attr->end() - 1 ;
01079                 for (; iter != last; iter++) {
01080                     strm << (*iter) << ", " ;
01081                 }
01082                 strm << (*(e->attr->end() - 1)) << endl ;
01083                 DapIndent::UnIndent() ;
01084             }
01085         }
01086         DapIndent::UnIndent() ;
01087     }
01088     else {
01089         strm << DapIndent::LMarg << "attributes: empty" << endl ;
01090     }
01091     if (d_parent) {
01092         strm << DapIndent::LMarg << "parent table:"
01093         << d_name << ":" << (void *)d_parent << endl ;
01094     }
01095     else {
01096         strm << DapIndent::LMarg << "parent table: none" << d_name << endl ;
01097     }
01098     DapIndent::UnIndent() ;
01099 }
01100 

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