head 1.4; access; symbols; locks; strict; comment @# @; 1.4 date 2002.09.07.01.50.39; author curt; state Exp; branches; next 1.3; 1.3 date 2002.08.31.19.01.56; author curt; state Exp; branches; next 1.2; 1.2 date 2002.08.31.18.54.02; author curt; state Exp; branches; next 1.1; 1.1 date 2002.02.15.17.21.58; author curt; state Exp; branches; next ; desc @@ 1.4 log @Updated doxygen docs. @ text @
Main Page Class Hierarchy Compound List File List Compound Members File Members

# props.cxx

    00001 // props.cxx - implementation of a property list.
    00002 // Started Fall 2000 by David Megginson, david@@megginson.com
    00003 // This code is released into the Public Domain.
    00004 //
    00005 // See props.html for documentation [replace with URL when available].
    00006 //
    00007 // $Id: props.cxx,v 1.54 2002/07/18 20:30:02 david Exp $
    00008
    00009 #include "props.hxx"
    00010
    00011 #include <algorithm>
    00012 #include <stdio.h>
    00013 #include <string.h>
    00014
    00015 #if PROPS_STANDALONE
    00016
    00017 #include <iostream>
    00018 using std::cerr;
    00019 using std::endl;
    00020 using std::find;
    00021 using std::sort;
    00022 using std::vector;
    00023
    00024 #else
    00025
    00026 #include <simgear/compiler.h>
    00027 #include <simgear/debug/logstream.hxx>
    00028
    00029 SG_USING_STD(sort);
    00030 SG_USING_STD(find);
    00031 SG_USING_STD(vector);
    00032
    00033 #ifdef _MSC_VER
    00034 // MSVC is buggy, and needs something strange here
    00035 SG_USING_STD(vector<SGPropertyNode_ptr>);
    00036 SG_USING_STD(vector<SGPropertyChangeListener *>);
    00037 SG_USING_STD(vector<SGPropertyNode *>);
    00038 #endif
    00039
    00040 #endif
    00041
    00042
    00043
    00045 // Local classes.
    00047
    00051 class CompareIndices
    00052 {
    00053 public:
    00054   int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
    00055     return (n1->getIndex() < n2->getIndex());
    00056   }
    00057 };
    00058
    00059
    00060
    00062 // Convenience macros for value access.
    00064
    00065 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
    00066 #define TEST_WRITE if (!getAttribute(WRITE)) return false
    00067
    00068
    00069
    00071 // Default values for every type.
    00073
    00074 const bool SGRawValue<bool>::DefaultValue = false;
    00075 const int SGRawValue<int>::DefaultValue = 0;
    00076 const long SGRawValue<long>::DefaultValue = 0L;
    00077 const float SGRawValue<float>::DefaultValue = 0.0;
    00078 const double SGRawValue<double>::DefaultValue = 0.0L;
    00079 const char * const SGRawValue<const char *>::DefaultValue = "";
    00080
    00081
    00082
    00084 // Local path normalization code.
    00086
    00090 struct PathComponent
    00091 {
    00092   string name;
    00093   int index;
    00094 };
    00095
    00101 static inline const string
    00102 parse_name (const string &path, int &i)
    00103 {
    00104   string name = "";
    00105   int max = path.size();
    00106
    00107   if (path[i] == '.') {
    00108     i++;
    00109     if (i < max && path[i] == '.') {
    00110       i++;
    00111       name = "..";
    00112     } else {
    00113       name = ".";
    00114     }
    00115     if (i < max && path[i] != '/')
    00116       throw string(string("Illegal character after ") + name);
    00117   }
    00118
    00119   else if (isalpha(path[i]) || path[i] == '_') {
    00120     name += path[i];
    00121     i++;
    00122
    00123                                 // The rules inside a name are a little
    00124                                 // less restrictive.
    00125     while (i < max) {
    00126       if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
    00127           path[i] == '-' || path[i] == '.') {
    00128         name += path[i];
    00129       } else if (path[i] == '[' || path[i] == '/') {
    00130         break;
    00131       } else {
    00132         throw string("name may contain only ._- and alphanumeric characters");
    00133       }
    00134       i++;
    00135     }
    00136   }
    00137
    00138   else {
    00139     if (name.size() == 0)
    00140       throw string("name must begin with alpha or '_'");
    00141   }
    00142
    00143   return name;
    00144 }
    00145
    00146
    00152 static inline int
    00153 parse_index (const string &path, int &i)
    00154 {
    00155   int index = 0;
    00156
    00157   if (path[i] != '[')
    00158     return 0;
    00159   else
    00160     i++;
    00161
    00162   for (int max = path.size(); i < max; i++) {
    00163     if (isdigit(path[i])) {
    00164       index = (index * 10) + (path[i] - '0');
    00165     } else if (path[i] == ']') {
    00166       i++;
    00167       return index;
    00168     } else {
    00169       break;
    00170     }
    00171   }
    00172
    00173   throw string("unterminated index (looking for ']')");
    00174 }
    00175
    00176
    00182 static inline PathComponent
    00183 parse_component (const string &path, int &i)
    00184 {
    00185   PathComponent component;
    00186   component.name = parse_name(path, i);
    00187   if (component.name[0] != '.')
    00188     component.index = parse_index(path, i);
    00189   else
    00190     component.index = -1;
    00191   return component;
    00192 }
    00193
    00194
    00198 static void
    00199 parse_path (const string &path, vector<PathComponent> &components)
    00200 {
    00201   int pos = 0;
    00202   int max = path.size();
    00203
    00204                                 // Check for initial '/'
    00205   if (path[pos] == '/') {
    00206     PathComponent root;
    00207     root.name = "";
    00208     root.index = -1;
    00209     components.push_back(root);
    00210     pos++;
    00211     while (pos < max && path[pos] == '/')
    00212       pos++;
    00213   }
    00214
    00215   while (pos < max) {
    00216     components.push_back(parse_component(path, pos));
    00217     while (pos < max && path[pos] == '/')
    00218       pos++;
    00219   }
    00220 }
    00221
    00222
    00223
    00225 // Other static utility functions.
    00227
    00228
    00229 static char *
    00230 copy_string (const char * s)
    00231 {
    00232                                 // FIXME: potential buffer overflow.
    00233                                 // For some reason, strnlen and
    00234                                 // strncpy cause all kinds of crashes.
    00235   char * copy = new char[strlen(s) + 1];
    00236   strcpy(copy, s);
    00237   return copy;
    00238 }
    00239
    00240 static bool
    00241 compare_strings (const char * s1, const char * s2)
    00242 {
    00243   return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
    00244 }
    00245
    00249 static int
    00250 find_child (const char * name, int index, vector<SGPropertyNode_ptr> nodes)
    00251 {
    00252   int nNodes = nodes.size();
    00253   for (int i = 0; i < nNodes; i++) {
    00254     SGPropertyNode * node = nodes[i];
    00255     if (compare_strings(node->getName(), name) && node->getIndex() == index)
    00256       return i;
    00257   }
    00258   return -1;
    00259 }
    00260
    00261
    00265 static SGPropertyNode *
    00266 find_node (SGPropertyNode * current,
    00267            const vector<PathComponent> &components,
    00268            int position,
    00269            bool create)
    00270 {
    00271                                 // Run off the end of the list
    00272   if (current == 0) {
    00273     return 0;
    00274   }
    00275
    00276                                 // Success! This is the one we want.
    00277   else if (position >= (int)components.size()) {
    00278     return current;
    00279   }
    00280
    00281                                 // Empty component means root.
    00282   else if (components[position].name == "") {
    00283     return find_node(current->getRootNode(), components, position + 1, create);
    00284   }
    00285
    00286                                 // . means current directory
    00287   else if (components[position].name == ".") {
    00288     return find_node(current, components, position + 1, create);
    00289   }
    00290
    00291                                 // .. means parent directory
    00292   else if (components[position].name == "..") {
    00293     SGPropertyNode * parent = current->getParent();
    00294     if (parent == 0)
    00295       throw string("Attempt to move past root with '..'");
    00296     else
    00297       return find_node(parent, components, position + 1, create);
    00298   }
    00299
    00300                                 // Otherwise, a child name
    00301   else {
    00302     SGPropertyNode * child =
    00303       current->getChild(components[position].name.c_str(),
    00304                         components[position].index,
    00305                         create);
    00306     return find_node(child, components, position + 1, create);
    00307   }
    00308 }
    00309
    00310
    00311
    00313 // Private methods from SGPropertyNode (may be inlined for speed).
    00315
    00316 inline bool
    00317 SGPropertyNode::get_bool () const
    00318 {
    00319   if (_tied)
    00320     return _value.bool_val->getValue();
    00321   else
    00322     return _local_val.bool_val;
    00323 }
    00324
    00325 inline int
    00326 SGPropertyNode::get_int () const
    00327 {
    00328   if (_tied)
    00329     return _value.int_val->getValue();
    00330   else
    00331     return _local_val.int_val;
    00332 }
    00333
    00334 inline long
    00335 SGPropertyNode::get_long () const
    00336 {
    00337   if (_tied)
    00338     return _value.long_val->getValue();
    00339   else
    00340     return _local_val.long_val;
    00341 }
    00342
    00343 inline float
    00344 SGPropertyNode::get_float () const
    00345 {
    00346   if (_tied)
    00347     return _value.float_val->getValue();
    00348   else
    00349     return _local_val.float_val;
    00350 }
    00351
    00352 inline double
    00353 SGPropertyNode::get_double () const
    00354 {
    00355   if (_tied)
    00356     return _value.double_val->getValue();
    00357   else
    00358     return _local_val.double_val;
    00359 }
    00360
    00361 inline const char *
    00362 SGPropertyNode::get_string () const
    00363 {
    00364   if (_tied)
    00365     return _value.string_val->getValue();
    00366   else
    00367     return _local_val.string_val;
    00368 }
    00369
    00370 inline bool
    00371 SGPropertyNode::set_bool (bool val)
    00372 {
    00373   if (_tied) {
    00374     if (_value.bool_val->setValue(val)) {
    00375       fireValueChanged();
    00376       return true;
    00377     } else {
    00378       return false;
    00379     }
    00380   } else {
    00381     _local_val.bool_val = val;
    00382     fireValueChanged();
    00383     return true;
    00384   }
    00385 }
    00386
    00387 inline bool
    00388 SGPropertyNode::set_int (int val)
    00389 {
    00390   if (_tied) {
    00391     if (_value.int_val->setValue(val)) {
    00392       fireValueChanged();
    00393       return true;
    00394     } else {
    00395       return false;
    00396     }
    00397   } else {
    00398     _local_val.int_val = val;
    00399     fireValueChanged();
    00400     return true;
    00401   }
    00402 }
    00403
    00404 inline bool
    00405 SGPropertyNode::set_long (long val)
    00406 {
    00407   if (_tied) {
    00408     if (_value.long_val->setValue(val)) {
    00409       fireValueChanged();
    00410       return true;
    00411     } else {
    00412       return false;
    00413     }
    00414   } else {
    00415     _local_val.long_val = val;
    00416     fireValueChanged();
    00417     return true;
    00418   }
    00419 }
    00420
    00421 inline bool
    00422 SGPropertyNode::set_float (float val)
    00423 {
    00424   if (_tied) {
    00425     if (_value.float_val->setValue(val)) {
    00426       fireValueChanged();
    00427       return true;
    00428     } else {
    00429       return false;
    00430     }
    00431   } else {
    00432     _local_val.float_val = val;
    00433     fireValueChanged();
    00434     return true;
    00435   }
    00436 }
    00437
    00438 inline bool
    00439 SGPropertyNode::set_double (double val)
    00440 {
    00441   if (_tied) {
    00442     if (_value.double_val->setValue(val)) {
    00443       fireValueChanged();
    00444       return true;
    00445     } else {
    00446       return false;
    00447     }
    00448   } else {
    00449     _local_val.double_val = val;
    00450     fireValueChanged();
    00451     return true;
    00452   }
    00453 }
    00454
    00455 inline bool
    00456 SGPropertyNode::set_string (const char * val)
    00457 {
    00458   if (_tied) {
    00459     if (_value.string_val->setValue(val)) {
    00460       fireValueChanged();
    00461       return true;
    00462     } else {
    00463       return false;
    00464     }
    00465   } else {
    00466     delete [] _local_val.string_val;
    00467     _local_val.string_val = copy_string(val);
    00468     fireValueChanged();
    00469     return true;
    00470   }
    00471 }
    00472
    00473 void
    00474 SGPropertyNode::clear_value ()
    00475 {
    00476   switch (_type) {
    00477   case NONE:
    00478     break;
    00479   case ALIAS:
    00480     _value.alias = 0;
    00481     break;
    00482   case BOOL:
    00483     if (_tied) {
    00484       delete _value.bool_val;
    00485       _value.bool_val = 0;
    00486     }
    00487     _local_val.bool_val = SGRawValue<bool>::DefaultValue;
    00488     break;
    00489   case INT:
    00490     if (_tied) {
    00491       delete _value.int_val;
    00492       _value.int_val = 0;
    00493     }
    00494     _local_val.int_val = SGRawValue<int>::DefaultValue;
    00495     break;
    00496   case LONG:
    00497     if (_tied) {
    00498       delete _value.long_val;
    00499       _value.long_val = 0L;
    00500     }
    00501     _local_val.long_val = SGRawValue<long>::DefaultValue;
    00502     break;
    00503   case FLOAT:
    00504     if (_tied) {
    00505       delete _value.float_val;
    00506       _value.float_val = 0;
    00507     }
    00508     _local_val.float_val = SGRawValue<float>::DefaultValue;
    00509     break;
    00510   case DOUBLE:
    00511     if (_tied) {
    00512       delete _value.double_val;
    00513       _value.double_val = 0;
    00514     }
    00515     _local_val.double_val = SGRawValue<double>::DefaultValue;
    00516     break;
    00517   case STRING:
    00518   case UNSPECIFIED:
    00519     if (_tied) {
    00520       delete _value.string_val;
    00521       _value.string_val = 0;
    00522     } else {
    00523       delete [] _local_val.string_val;
    00524     }
    00525     _local_val.string_val = 0;
    00526     break;
    00527   }
    00528   _tied = false;
    00529   _type = NONE;
    00530 }
    00531
    00532
    00536 const char *
    00537 SGPropertyNode::make_string () const
    00538 {
    00539   if (!getAttribute(READ))
    00540     return "";
    00541
    00542   switch (_type) {
    00543   case ALIAS:
    00544     return _value.alias->getStringValue();
    00545   case BOOL:
    00546     if (get_bool())
    00547       return "true";
    00548     else
    00549       return "false";
    00550   case INT:
    00551     sprintf(_buffer, "%d", get_int());
    00552     return _buffer;
    00553   case LONG:
    00554     sprintf(_buffer, "%ld", get_long());
    00555     return _buffer;
    00556   case FLOAT:
    00557     sprintf(_buffer, "%f", get_float());
    00558     return _buffer;
    00559   case DOUBLE:
    00560     sprintf(_buffer, "%f", get_double());
    00561     return _buffer;
    00562   case STRING:
    00563   case UNSPECIFIED:
    00564     return get_string();
    00565   case NONE:
    00566   default:
    00567     return "";
    00568   }
    00569 }
    00570
    00574 void
    00575 SGPropertyNode::trace_write () const
    00576 {
    00577 #if PROPS_STANDALONE
    00578   cerr << "TRACE: Write node " << getPath () << ", value\""
    00579        << make_string() << '"' << endl;
    00580 #else
    00581   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
    00582          << ", value\"" << make_string() << '"');
    00583 #endif
    00584 }
    00585
    00589 void
    00590 SGPropertyNode::trace_read () const
    00591 {
    00592 #if PROPS_STANDALONE
    00593   cerr << "TRACE: Write node " << getPath () << ", value \""
    00594        << make_string() << '"' << endl;
    00595 #else
    00596   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
    00597          << ", value \"" << make_string() << '"');
    00598 #endif
    00599 }
    00600
    00604 void
    00605 SGPropertyNode::incrementRef()
    00606 {
    00607   ++_count;
    00608 }
    00609
    00613 int
    00614 SGPropertyNode::decrementRef()
    00615 {
    00616   return --_count;
    00617 }
    00618
    00619
    00620
    00622 // Public methods from SGPropertyNode.
    00624
    00629 const int SGPropertyNode::LAST_USED_ATTRIBUTE = TRACE_WRITE;
    00630
    00634 SGPropertyNode::SGPropertyNode ()
    00635   : _name(copy_string("")),
    00636     _display_name(0),
    00637     _index(0),
    00638     _parent(0),
    00639     _path(0),
    00640     _path_cache(0),
    00641     _type(NONE),
    00642     _tied(false),
    00643     _attr(READ|WRITE),
    00644     _count(0),
    00645     _listeners(0)
    00646 {
    00647   _local_val.string_val = 0;
    00648 }
    00649
    00650
    00654 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
    00655   : _display_name(0),
    00656     _index(node._index),
    00657     _parent(0),                 // don't copy the parent
    00658     _path(0),
    00659     _path_cache(0),
    00660     _type(node._type),
    00661     _tied(node._tied),
    00662     _attr(node._attr),
    00663     _count(0),
    00664     _listeners(0)               // CHECK!!
    00665 {
    00666   _name = copy_string(node._name);
    00667   _local_val.string_val = 0;
    00668   switch (_type) {
    00669   case NONE:
    00670     break;
    00671   case ALIAS:
    00672     _value.alias = node._value.alias;
    00673     _tied = false;
    00674     break;
    00675   case BOOL:
    00676     if (_tied) {
    00677       _tied = true;
    00678       _value.bool_val = node._value.bool_val->clone();
    00679     } else {
    00680       _tied = false;
    00681       set_bool(node.get_bool());
    00682     }
    00683     break;
    00684   case INT:
    00685     if (_tied) {
    00686       _tied = true;
    00687       _value.int_val = node._value.int_val->clone();
    00688     } else {
    00689       _tied = false;
    00690       set_int(node.get_int());
    00691     }
    00692     break;
    00693   case LONG:
    00694     if (_tied) {
    00695       _tied = true;
    00696       _value.long_val = node._value.long_val->clone();
    00697     } else {
    00698       _tied = false;
    00699       set_long(node.get_long());
    00700     }
    00701     break;
    00702   case FLOAT:
    00703     if (_tied) {
    00704       _tied = true;
    00705       _value.float_val = node._value.float_val->clone();
    00706     } else {
    00707       _tied = false;
    00708       set_float(node.get_float());
    00709     }
    00710     break;
    00711   case DOUBLE:
    00712     if (_tied) {
    00713       _tied = true;
    00714       _value.double_val = node._value.double_val->clone();
    00715     } else {
    00716       _tied = false;
    00717       set_double(node.get_double());
    00718     }
    00719     break;
    00720   case STRING:
    00721   case UNSPECIFIED:
    00722     if (_tied) {
    00723       _tied = true;
    00724       _value.string_val = node._value.string_val->clone();
    00725     } else {
    00726       _tied = false;
    00727       set_string(node.get_string());
    00728     }
    00729     break;
    00730   }
    00731 }
    00732
    00733
    00737 SGPropertyNode::SGPropertyNode (const char * name,
    00738                                 int index,
    00739                                 SGPropertyNode * parent)
    00740   : _display_name(0),
    00741     _index(index),
    00742     _parent(parent),
    00743     _path(0),
    00744     _path_cache(0),
    00745     _type(NONE),
    00746     _tied(false),
    00747     _attr(READ|WRITE),
    00748     _count(0),
    00749     _listeners(0)
    00750 {
    00751   _name = copy_string(name);
    00752   _local_val.string_val = 0;
    00753 }
    00754
    00755
    00759 SGPropertyNode::~SGPropertyNode ()
    00760 {
    00761   delete [] _name;
    00762   delete [] _display_name;
    00763   delete [] _path;
    00764   delete _path_cache;
    00765   clear_value();
    00766   delete _listeners;
    00767 }
    00768
    00769
    00773 bool
    00774 SGPropertyNode::alias (SGPropertyNode * target)
    00775 {
    00776   if (target == 0 || _type == ALIAS || _tied)
    00777     return false;
    00778   clear_value();
    00779   _value.alias = target;
    00780   _type = ALIAS;
    00781   return true;
    00782 }
    00783
    00784
    00788 bool
    00789 SGPropertyNode::alias (const char * path)
    00790 {
    00791   return alias(getNode(path, true));
    00792 }
    00793
    00794
    00798 bool
    00799 SGPropertyNode::unalias ()
    00800 {
    00801   if (_type != ALIAS)
    00802     return false;
    00803   _type = NONE;
    00804   _value.alias = 0;
    00805   return true;
    00806 }
    00807
    00808
    00812 SGPropertyNode *
    00813 SGPropertyNode::getAliasTarget ()
    00814 {
    00815   return (_type == ALIAS ? _value.alias : 0);
    00816 }
    00817
    00818
    00819 const SGPropertyNode *
    00820 SGPropertyNode::getAliasTarget () const
    00821 {
    00822   return (_type == ALIAS ? _value.alias : 0);
    00823 }
    00824
    00825
    00829 SGPropertyNode *
    00830 SGPropertyNode::getChild (int position)
    00831 {
    00832   if (position >= 0 && position < nChildren())
    00833     return _children[position];
    00834   else
    00835     return 0;
    00836 }
    00837
    00838
    00842 const SGPropertyNode *
    00843 SGPropertyNode::getChild (int position) const
    00844 {
    00845   if (position >= 0 && position < nChildren())
    00846     return _children[position];
    00847   else
    00848     return 0;
    00849 }
    00850
    00851
    00855 SGPropertyNode *
    00856 SGPropertyNode::getChild (const char * name, int index, bool create)
    00857 {
    00858   int pos = find_child(name, index, _children);
    00859   if (pos >= 0) {
    00860     return _children[pos];
    00861   } else if (create) {
    00862     SGPropertyNode_ptr node;
    00863     pos = find_child(name, index, _removedChildren);
    00864     if (pos >= 0) {
    00865       vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
    00866       it += pos;
    00867       node = _removedChildren[pos];
    00868       _removedChildren.erase(it);
    00869       node->setAttribute(REMOVED, false);
    00870     } else {
    00871       node = new SGPropertyNode(name, index, this);
    00872     }
    00873     _children.push_back(node);
    00874     fireChildAdded(node);
    00875     return node;
    00876   } else {
    00877     return 0;
    00878   }
    00879 }
    00880
    00881
    00885 const SGPropertyNode *
    00886 SGPropertyNode::getChild (const char * name, int index) const
    00887 {
    00888   int pos = find_child(name, index, _children);
    00889   if (pos >= 0)
    00890     return _children[pos];
    00891   else
    00892     return 0;
    00893 }
    00894
    00895
    00899 vector<SGPropertyNode_ptr>
    00900 SGPropertyNode::getChildren (const char * name) const
    00901 {
    00902   vector<SGPropertyNode_ptr> children;
    00903   int max = _children.size();
    00904
    00905   for (int i = 0; i < max; i++)
    00906     if (compare_strings(_children[i]->getName(), name))
    00907       children.push_back(_children[i]);
    00908
    00909   sort(children.begin(), children.end(), CompareIndices());
    00910   return children;
    00911 }
    00912
    00913
    00917 SGPropertyNode_ptr
    00918 SGPropertyNode::removeChild (const char * name, int index, bool keep)
    00919 {
    00920   SGPropertyNode_ptr ret;
    00921   int pos = find_child(name, index, _children);
    00922   if (pos >= 0) {
    00923     vector<SGPropertyNode_ptr>::iterator it = _children.begin();
    00924     it += pos;
    00925     SGPropertyNode_ptr node = _children[pos];
    00926     _children.erase(it);
    00927     if (keep) {
    00928       _removedChildren.push_back(node);
    00929     }
    00930     node->setAttribute(REMOVED, true);
    00931     ret = node;
    00932     fireChildRemoved(node);
    00933   }
    00934   return ret;
    00935 }
    00936
    00937
    00938 const char *
    00939 SGPropertyNode::getDisplayName (bool simplify) const
    00940 {
    00941   string display = _name;
    00942   if (_index != 0 || !simplify) {
    00943     char buffer[64];
    00944     sprintf(buffer, "[%d]", _index);
    00945     display += buffer;
    00946   }
    00947   _display_name = copy_string(display.c_str());
    00948   return _display_name;
    00949 }
    00950
    00951
    00952 const char *
    00953 SGPropertyNode::getPath (bool simplify) const
    00954 {
    00955                                 // Calculate the complete path only once.
    00956   if (_path == 0) {
    00957     string path;
    00958     if (_parent == 0) {
    00959       path = "";
    00960     } else {
    00961       path = _parent->getPath(simplify);
    00962       path += '/';
    00963       path += getDisplayName(simplify);
    00964     }
    00965     _path = copy_string(path.c_str());
    00966   }
    00967
    00968   return _path;
    00969 }
    00970
    00971 SGPropertyNode::Type
    00972 SGPropertyNode::getType () const
    00973 {
    00974   if (_type == ALIAS)
    00975     return _value.alias->getType();
    00976   else
    00977     return _type;
    00978 }
    00979
    00980
    00981 bool
    00982 SGPropertyNode::getBoolValue () const
    00983 {
    00984                                 // Shortcut for common case
    00985   if (_attr == (READ|WRITE) && _type == BOOL)
    00986     return get_bool();
    00987
    00988   if (getAttribute(TRACE_READ))
    00989     trace_read();
    00990   if (!getAttribute(READ))
    00991     return SGRawValue<bool>::DefaultValue;
    00992   switch (_type) {
    00993   case ALIAS:
    00994     return _value.alias->getBoolValue();
    00995   case BOOL:
    00996     return get_bool();
    00997   case INT:
    00998     return get_int() == 0 ? false : true;
    00999   case LONG:
    01000     return get_long() == 0L ? false : true;
    01001   case FLOAT:
    01002     return get_float() == 0.0 ? false : true;
    01003   case DOUBLE:
    01004     return get_double() == 0.0L ? false : true;
    01005   case STRING:
    01006   case UNSPECIFIED:
    01007     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
    01008   case NONE:
    01009   default:
    01010     return SGRawValue<bool>::DefaultValue;
    01011   }
    01012 }
    01013
    01014 int
    01015 SGPropertyNode::getIntValue () const
    01016 {
    01017                                 // Shortcut for common case
    01018   if (_attr == (READ|WRITE) && _type == INT)
    01019     return get_int();
    01020
    01021   if (getAttribute(TRACE_READ))
    01022     trace_read();
    01023   if (!getAttribute(READ))
    01024     return SGRawValue<int>::DefaultValue;
    01025   switch (_type) {
    01026   case ALIAS:
    01027     return _value.alias->getIntValue();
    01028   case BOOL:
    01029     return int(get_bool());
    01030   case INT:
    01031     return get_int();
    01032   case LONG:
    01033     return int(get_long());
    01034   case FLOAT:
    01035     return int(get_float());
    01036   case DOUBLE:
    01037     return int(get_double());
    01038   case STRING:
    01039   case UNSPECIFIED:
    01040     return atoi(get_string());
    01041   case NONE:
    01042   default:
    01043     return SGRawValue<int>::DefaultValue;
    01044   }
    01045 }
    01046
    01047 long
    01048 SGPropertyNode::getLongValue () const
    01049 {
    01050                                 // Shortcut for common case
    01051   if (_attr == (READ|WRITE) && _type == LONG)
    01052     return get_long();
    01053
    01054   if (getAttribute(TRACE_READ))
    01055     trace_read();
    01056   if (!getAttribute(READ))
    01057     return SGRawValue<long>::DefaultValue;
    01058   switch (_type) {
    01059   case ALIAS:
    01060     return _value.alias->getLongValue();
    01061   case BOOL:
    01062     return long(get_bool());
    01063   case INT:
    01064     return long(get_int());
    01065   case LONG:
    01066     return get_long();
    01067   case FLOAT:
    01068     return long(get_float());
    01069   case DOUBLE:
    01070     return long(get_double());
    01071   case STRING:
    01072   case UNSPECIFIED:
    01073     return strtol(get_string(), 0, 0);
    01074   case NONE:
    01075   default:
    01076     return SGRawValue<long>::DefaultValue;
    01077   }
    01078 }
    01079
    01080 float
    01081 SGPropertyNode::getFloatValue () const
    01082 {
    01083                                 // Shortcut for common case
    01084   if (_attr == (READ|WRITE) && _type == FLOAT)
    01085     return get_float();
    01086
    01087   if (getAttribute(TRACE_READ))
    01088     trace_read();
    01089   if (!getAttribute(READ))
    01090     return SGRawValue<float>::DefaultValue;
    01091   switch (_type) {
    01092   case ALIAS:
    01093     return _value.alias->getFloatValue();
    01094   case BOOL:
    01095     return float(get_bool());
    01096   case INT:
    01097     return float(get_int());
    01098   case LONG:
    01099     return float(get_long());
    01100   case FLOAT:
    01101     return get_float();
    01102   case DOUBLE:
    01103     return float(get_double());
    01104   case STRING:
    01105   case UNSPECIFIED:
    01106     return atof(get_string());
    01107   case NONE:
    01108   default:
    01109     return SGRawValue<float>::DefaultValue;
    01110   }
    01111 }
    01112
    01113 double
    01114 SGPropertyNode::getDoubleValue () const
    01115 {
    01116                                 // Shortcut for common case
    01117   if (_attr == (READ|WRITE) && _type == DOUBLE)
    01118     return get_double();
    01119
    01120   if (getAttribute(TRACE_READ))
    01121     trace_read();
    01122   if (!getAttribute(READ))
    01123     return SGRawValue<double>::DefaultValue;
    01124
    01125   switch (_type) {
    01126   case ALIAS:
    01127     return _value.alias->getDoubleValue();
    01128   case BOOL:
    01129     return double(get_bool());
    01130   case INT:
    01131     return double(get_int());
    01132   case LONG:
    01133     return double(get_long());
    01134   case FLOAT:
    01135     return double(get_float());
    01136   case DOUBLE:
    01137     return get_double();
    01138   case STRING:
    01139   case UNSPECIFIED:
    01140     return strtod(get_string(), 0);
    01141   case NONE:
    01142   default:
    01143     return SGRawValue<double>::DefaultValue;
    01144   }
    01145 }
    01146
    01147 const char *
    01148 SGPropertyNode::getStringValue () const
    01149 {
    01150                                 // Shortcut for common case
    01151   if (_attr == (READ|WRITE) && _type == STRING)
    01152     return get_string();
    01153
    01154   if (getAttribute(TRACE_READ))
    01155     trace_read();
    01156   if (!getAttribute(READ))
    01157     return SGRawValue<const char *>::DefaultValue;
    01158   return make_string();
    01159 }
    01160
    01161 bool
    01162 SGPropertyNode::setBoolValue (bool value)
    01163 {
    01164                                 // Shortcut for common case
    01165   if (_attr == (READ|WRITE) && _type == BOOL)
    01166     return set_bool(value);
    01167
    01168   bool result = false;
    01169   TEST_WRITE;
    01170   if (_type == NONE || _type == UNSPECIFIED) {
    01171     clear_value();
    01172     _tied = false;
    01173     _type = BOOL;
    01174   }
    01175
    01176   switch (_type) {
    01177   case ALIAS:
    01178     result = _value.alias->setBoolValue(value);
    01179     break;
    01180   case BOOL:
    01181     result = set_bool(value);
    01182     break;
    01183   case INT:
    01184     result = set_int(int(value));
    01185     break;
    01186   case LONG:
    01187     result = set_long(long(value));
    01188     break;
    01189   case FLOAT:
    01190     result = set_float(float(value));
    01191     break;
    01192   case DOUBLE:
    01193     result = set_double(double(value));
    01194     break;
    01195   case STRING:
    01196   case UNSPECIFIED:
    01197     result = set_string(value ? "true" : "false");
    01198     break;
    01199   case NONE:
    01200   default:
    01201     break;
    01202   }
    01203
    01204   if (getAttribute(TRACE_WRITE))
    01205     trace_write();
    01206   return result;
    01207 }
    01208
    01209 bool
    01210 SGPropertyNode::setIntValue (int value)
    01211 {
    01212                                 // Shortcut for common case
    01213   if (_attr == (READ|WRITE) && _type == INT)
    01214     return set_int(value);
    01215
    01216   bool result = false;
    01217   TEST_WRITE;
    01218   if (_type == NONE || _type == UNSPECIFIED) {
    01219     clear_value();
    01220     _type = INT;
    01221     _local_val.int_val = 0;
    01222   }
    01223
    01224   switch (_type) {
    01225   case ALIAS:
    01226     result = _value.alias->setIntValue(value);
    01227     break;
    01228   case BOOL:
    01229     result = set_bool(value == 0 ? false : true);
    01230     break;
    01231   case INT:
    01232     result = set_int(value);
    01233     break;
    01234   case LONG:
    01235     result = set_long(long(value));
    01236     break;
    01237   case FLOAT:
    01238     result = set_float(float(value));
    01239     break;
    01240   case DOUBLE:
    01241     result = set_double(double(value));
    01242     break;
    01243   case STRING:
    01244   case UNSPECIFIED: {
    01245     char buf[128];
    01246     sprintf(buf, "%d", value);
    01247     result = set_string(buf);
    01248     break;
    01249   }
    01250   case NONE:
    01251   default:
    01252     break;
    01253   }
    01254
    01255   if (getAttribute(TRACE_WRITE))
    01256     trace_write();
    01257   return result;
    01258 }
    01259
    01260 bool
    01261 SGPropertyNode::setLongValue (long value)
    01262 {
    01263                                 // Shortcut for common case
    01264   if (_attr == (READ|WRITE) && _type == LONG)
    01265     return set_long(value);
    01266
    01267   bool result = false;
    01268   TEST_WRITE;
    01269   if (_type == NONE || _type == UNSPECIFIED) {
    01270     clear_value();
    01271     _type = LONG;
    01272     _local_val.long_val = 0L;
    01273   }
    01274
    01275   switch (_type) {
    01276   case ALIAS:
    01277     result = _value.alias->setLongValue(value);
    01278     break;
    01279   case BOOL:
    01280     result = set_bool(value == 0L ? false : true);
    01281     break;
    01282   case INT:
    01283     result = set_int(int(value));
    01284     break;
    01285   case LONG:
    01286     result = set_long(value);
    01287     break;
    01288   case FLOAT:
    01289     result = set_float(float(value));
    01290     break;
    01291   case DOUBLE:
    01292     result = set_double(double(value));
    01293     break;
    01294   case STRING:
    01295   case UNSPECIFIED: {
    01296     char buf[128];
    01297     sprintf(buf, "%ld", value);
    01298     result = set_string(buf);
    01299     break;
    01300   }
    01301   case NONE:
    01302   default:
    01303     break;
    01304   }
    01305
    01306   if (getAttribute(TRACE_WRITE))
    01307     trace_write();
    01308   return result;
    01309 }
    01310
    01311 bool
    01312 SGPropertyNode::setFloatValue (float value)
    01313 {
    01314                                 // Shortcut for common case
    01315   if (_attr == (READ|WRITE) && _type == FLOAT)
    01316     return set_float(value);
    01317
    01318   bool result = false;
    01319   TEST_WRITE;
    01320   if (_type == NONE || _type == UNSPECIFIED) {
    01321     clear_value();
    01322     _type = FLOAT;
    01323     _local_val.float_val = 0;
    01324   }
    01325
    01326   switch (_type) {
    01327   case ALIAS:
    01328     result = _value.alias->setFloatValue(value);
    01329     break;
    01330   case BOOL:
    01331     result = set_bool(value == 0.0 ? false : true);
    01332     break;
    01333   case INT:
    01334     result = set_int(int(value));
    01335     break;
    01336   case LONG:
    01337     result = set_long(long(value));
    01338     break;
    01339   case FLOAT:
    01340     result = set_float(value);
    01341     break;
    01342   case DOUBLE:
    01343     result = set_double(double(value));
    01344     break;
    01345   case STRING:
    01346   case UNSPECIFIED: {
    01347     char buf[128];
    01348     sprintf(buf, "%f", value);
    01349     result = set_string(buf);
    01350     break;
    01351   }
    01352   case NONE:
    01353   default:
    01354     break;
    01355   }
    01356
    01357   if (getAttribute(TRACE_WRITE))
    01358     trace_write();
    01359   return result;
    01360 }
    01361
    01362 bool
    01363 SGPropertyNode::setDoubleValue (double value)
    01364 {
    01365                                 // Shortcut for common case
    01366   if (_attr == (READ|WRITE) && _type == DOUBLE)
    01367     return set_double(value);
    01368
    01369   bool result = false;
    01370   TEST_WRITE;
    01371   if (_type == NONE || _type == UNSPECIFIED) {
    01372     clear_value();
    01373     _local_val.double_val = value;
    01374     _type = DOUBLE;
    01375   }
    01376
    01377   switch (_type) {
    01378   case ALIAS:
    01379     result = _value.alias->setDoubleValue(value);
    01380     break;
    01381   case BOOL:
    01382     result = set_bool(value == 0.0L ? false : true);
    01383     break;
    01384   case INT:
    01385     result = set_int(int(value));
    01386     break;
    01387   case LONG:
    01388     result = set_long(long(value));
    01389     break;
    01390   case FLOAT:
    01391     result = set_float(float(value));
    01392     break;
    01393   case DOUBLE:
    01394     result = set_double(value);
    01395     break;
    01396   case STRING:
    01397   case UNSPECIFIED: {
    01398     char buf[128];
    01399     sprintf(buf, "%f", value);
    01400     result = set_string(buf);
    01401     break;
    01402   }
    01403   case NONE:
    01404   default:
    01405     break;
    01406   }
    01407
    01408   if (getAttribute(TRACE_WRITE))
    01409     trace_write();
    01410   return result;
    01411 }
    01412
    01413 bool
    01414 SGPropertyNode::setStringValue (const char * value)
    01415 {
    01416                                 // Shortcut for common case
    01417   if (_attr == (READ|WRITE) && _type == STRING)
    01418     return set_string(value);
    01419
    01420   bool result = false;
    01421   TEST_WRITE;
    01422   if (_type == NONE || _type == UNSPECIFIED) {
    01423     clear_value();
    01424     _type = STRING;
    01425   }
    01426
    01427   switch (_type) {
    01428   case ALIAS:
    01429     result = _value.alias->setStringValue(value);
    01430     break;
    01431   case BOOL:
    01432     result = set_bool((compare_strings(value, "true")
    01433                        || atoi(value)) ? true : false);
    01434     break;
    01435   case INT:
    01436     result = set_int(atoi(value));
    01437     break;
    01438   case LONG:
    01439     result = set_long(strtol(value, 0, 0));
    01440     break;
    01441   case FLOAT:
    01442     result = set_float(atof(value));
    01443     break;
    01444   case DOUBLE:
    01445     result = set_double(strtod(value, 0));
    01446     break;
    01447   case STRING:
    01448   case UNSPECIFIED:
    01449     result = set_string(value);
    01450     break;
    01451   case NONE:
    01452   default:
    01453     break;
    01454   }
    01455
    01456   if (getAttribute(TRACE_WRITE))
    01457     trace_write();
    01458   return result;
    01459 }
    01460
    01461 bool
    01462 SGPropertyNode::setUnspecifiedValue (const char * value)
    01463 {
    01464   bool result = false;
    01465   TEST_WRITE;
    01466   if (_type == NONE) {
    01467     clear_value();
    01468     _type = UNSPECIFIED;
    01469   }
    01470
    01471   switch (_type) {
    01472   case ALIAS:
    01473     result = _value.alias->setUnspecifiedValue(value);
    01474     break;
    01475   case BOOL:
    01476     result = set_bool((compare_strings(value, "true")
    01477                        || atoi(value)) ? true : false);
    01478     break;
    01479   case INT:
    01480     result = set_int(atoi(value));
    01481     break;
    01482   case LONG:
    01483     result = set_long(strtol(value, 0, 0));
    01484     break;
    01485   case FLOAT:
    01486     result = set_float(atof(value));
    01487     break;
    01488   case DOUBLE:
    01489     result = set_double(strtod(value, 0));
    01490     break;
    01491   case STRING:
    01492   case UNSPECIFIED:
    01493     result = set_string(value);
    01494     break;
    01495   case NONE:
    01496   default:
    01497     break;
    01498   }
    01499
    01500   if (getAttribute(TRACE_WRITE))
    01501     trace_write();
    01502   return result;
    01503 }
    01504
    01505 bool
    01506 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
    01507 {
    01508   if (_type == ALIAS || _tied)
    01509     return false;
    01510
    01511   useDefault = useDefault && hasValue();
    01512   bool old_val = false;
    01513   if (useDefault)
    01514     old_val = getBoolValue();
    01515
    01516   clear_value();
    01517   _type = BOOL;
    01518   _tied = true;
    01519   _value.bool_val = rawValue.clone();
    01520
    01521   if (useDefault)
    01522     setBoolValue(old_val);
    01523
    01524   return true;
    01525 }
    01526
    01527 bool
    01528 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
    01529 {
    01530   if (_type == ALIAS || _tied)
    01531     return false;
    01532
    01533   useDefault = useDefault && hasValue();
    01534   int old_val = 0;
    01535   if (useDefault)
    01536     old_val = getIntValue();
    01537
    01538   clear_value();
    01539   _type = INT;
    01540   _tied = true;
    01541   _value.int_val = rawValue.clone();
    01542
    01543   if (useDefault)
    01544     setIntValue(old_val);
    01545
    01546   return true;
    01547 }
    01548
    01549 bool
    01550 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
    01551 {
    01552   if (_type == ALIAS || _tied)
    01553     return false;
    01554
    01555   useDefault = useDefault && hasValue();
    01556   long old_val = 0;
    01557   if (useDefault)
    01558     old_val = getLongValue();
    01559
    01560   clear_value();
    01561   _type = LONG;
    01562   _tied = true;
    01563   _value.long_val = rawValue.clone();
    01564
    01565   if (useDefault)
    01566     setLongValue(old_val);
    01567
    01568   return true;
    01569 }
    01570
    01571 bool
    01572 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
    01573 {
    01574   if (_type == ALIAS || _tied)
    01575     return false;
    01576
    01577   useDefault = useDefault && hasValue();
    01578   float old_val = 0.0;
    01579   if (useDefault)
    01580     old_val = getFloatValue();
    01581
    01582   clear_value();
    01583   _type = FLOAT;
    01584   _tied = true;
    01585   _value.float_val = rawValue.clone();
    01586
    01587   if (useDefault)
    01588     setFloatValue(old_val);
    01589
    01590   return true;
    01591 }
    01592
    01593 bool
    01594 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
    01595 {
    01596   if (_type == ALIAS || _tied)
    01597     return false;
    01598
    01599   useDefault = useDefault && hasValue();
    01600   double old_val = 0.0;
    01601   if (useDefault)
    01602     old_val = getDoubleValue();
    01603
    01604   clear_value();
    01605   _type = DOUBLE;
    01606   _tied = true;
    01607   _value.double_val = rawValue.clone();
    01608
    01609   if (useDefault)
    01610     setDoubleValue(old_val);
    01611
    01612   return true;
    01613
    01614 }
    01615
    01616 bool
    01617 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
    01618 {
    01619   if (_type == ALIAS || _tied)
    01620     return false;
    01621
    01622   useDefault = useDefault && hasValue();
    01623   string old_val;
    01624   if (useDefault)
    01625     old_val = getStringValue();
    01626
    01627   clear_value();
    01628   _type = STRING;
    01629   _tied = true;
    01630   _value.string_val = rawValue.clone();
    01631
    01632   if (useDefault)
    01633     setStringValue(old_val.c_str());
    01634
    01635   return true;
    01636 }
    01637
    01638 bool
    01639 SGPropertyNode::untie ()
    01640 {
    01641   if (!_tied)
    01642     return false;
    01643
    01644   switch (_type) {
    01645   case BOOL: {
    01646     bool val = getBoolValue();
    01647     clear_value();
    01648     _type = BOOL;
    01649     _local_val.bool_val = val;
    01650     break;
    01651   }
    01652   case INT: {
    01653     int val = getIntValue();
    01654     clear_value();
    01655     _type = INT;
    01656     _local_val.int_val = val;
    01657     break;
    01658   }
    01659   case LONG: {
    01660     long val = getLongValue();
    01661     clear_value();
    01662     _type = LONG;
    01663     _local_val.long_val = val;
    01664     break;
    01665   }
    01666   case FLOAT: {
    01667     float val = getFloatValue();
    01668     clear_value();
    01669     _type = FLOAT;
    01670     _local_val.float_val = val;
    01671     break;
    01672   }
    01673   case DOUBLE: {
    01674     double val = getDoubleValue();
    01675     clear_value();
    01676     _type = DOUBLE;
    01677     _local_val.double_val = val;
    01678     break;
    01679   }
    01680   case STRING:
    01681   case UNSPECIFIED: {
    01682     string val = getStringValue();
    01683     clear_value();
    01684     _type = STRING;
    01685     _local_val.string_val = copy_string(val.c_str());
    01686     break;
    01687   }
    01688   case NONE:
    01689   default:
    01690     break;
    01691   }
    01692
    01693   _tied = false;
    01694   return true;
    01695 }
    01696
    01697 SGPropertyNode *
    01698 SGPropertyNode::getRootNode ()
    01699 {
    01700   if (_parent == 0)
    01701     return this;
    01702   else
    01703     return _parent->getRootNode();
    01704 }
    01705
    01706 const SGPropertyNode *
    01707 SGPropertyNode::getRootNode () const
    01708 {
    01709   if (_parent == 0)
    01710     return this;
    01711   else
    01712     return _parent->getRootNode();
    01713 }
    01714
    01715 SGPropertyNode *
    01716 SGPropertyNode::getNode (const char * relative_path, bool create)
    01717 {
    01718   if (_path_cache == 0)
    01719     _path_cache = new hash_table;
    01720
    01721   SGPropertyNode * result = _path_cache->get(relative_path);
    01722   if (result == 0) {
    01723     vector<PathComponent> components;
    01724     parse_path(relative_path, components);
    01725     result = find_node(this, components, 0, create);
    01726     if (result != 0)
    01727       _path_cache->put(relative_path, result);
    01728   }
    01729
    01730   return result;
    01731 }
    01732
    01733 SGPropertyNode *
    01734 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
    01735 {
    01736   vector<PathComponent> components;
    01737   parse_path(relative_path, components);
    01738   if (components.size() > 0)
    01739     components[components.size()-1].index = index;
    01740   return find_node(this, components, 0, create);
    01741 }
    01742
    01743 const SGPropertyNode *
    01744 SGPropertyNode::getNode (const char * relative_path) const
    01745 {
    01746   return ((SGPropertyNode *)this)->getNode(relative_path, false);
    01747 }
    01748
    01749 const SGPropertyNode *
    01750 SGPropertyNode::getNode (const char * relative_path, int index) const
    01751 {
    01752   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
    01753 }
    01754
    01755
    01757 // Convenience methods using relative paths.
    01759
    01760
    01764 bool
    01765 SGPropertyNode::hasValue (const char * relative_path) const
    01766 {
    01767   const SGPropertyNode * node = getNode(relative_path);
    01768   return (node == 0 ? false : node->hasValue());
    01769 }
    01770
    01771
    01775 SGPropertyNode::Type
    01776 SGPropertyNode::getType (const char * relative_path) const
    01777 {
    01778   const SGPropertyNode * node = getNode(relative_path);
    01779   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
    01780 }
    01781
    01782
    01786 bool
    01787 SGPropertyNode::getBoolValue (const char * relative_path,
    01788                               bool defaultValue) const
    01789 {
    01790   const SGPropertyNode * node = getNode(relative_path);
    01791   return (node == 0 ? defaultValue : node->getBoolValue());
    01792 }
    01793
    01794
    01798 int
    01799 SGPropertyNode::getIntValue (const char * relative_path,
    01800                              int defaultValue) const
    01801 {
    01802   const SGPropertyNode * node = getNode(relative_path);
    01803   return (node == 0 ? defaultValue : node->getIntValue());
    01804 }
    01805
    01806
    01810 long
    01811 SGPropertyNode::getLongValue (const char * relative_path,
    01812                               long defaultValue) const
    01813 {
    01814   const SGPropertyNode * node = getNode(relative_path);
    01815   return (node == 0 ? defaultValue : node->getLongValue());
    01816 }
    01817
    01818
    01822 float
    01823 SGPropertyNode::getFloatValue (const char * relative_path,
    01824                                float defaultValue) const
    01825 {
    01826   const SGPropertyNode * node = getNode(relative_path);
    01827   return (node == 0 ? defaultValue : node->getFloatValue());
    01828 }
    01829
    01830
    01834 double
    01835 SGPropertyNode::getDoubleValue (const char * relative_path,
    01836                                 double defaultValue) const
    01837 {
    01838   const SGPropertyNode * node = getNode(relative_path);
    01839   return (node == 0 ? defaultValue : node->getDoubleValue());
    01840 }
    01841
    01842
    01846 const char *
    01847 SGPropertyNode::getStringValue (const char * relative_path,
    01848                                 const char * defaultValue) const
    01849 {
    01850   const SGPropertyNode * node = getNode(relative_path);
    01851   return (node == 0 ? defaultValue : node->getStringValue());
    01852 }
    01853
    01854
    01858 bool
    01859 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
    01860 {
    01861   return getNode(relative_path, true)->setBoolValue(value);
    01862 }
    01863
    01864
    01868 bool
    01869 SGPropertyNode::setIntValue (const char * relative_path, int value)
    01870 {
    01871   return getNode(relative_path, true)->setIntValue(value);
    01872 }
    01873
    01874
    01878 bool
    01879 SGPropertyNode::setLongValue (const char * relative_path, long value)
    01880 {
    01881   return getNode(relative_path, true)->setLongValue(value);
    01882 }
    01883
    01884
    01888 bool
    01889 SGPropertyNode::setFloatValue (const char * relative_path, float value)
    01890 {
    01891   return getNode(relative_path, true)->setFloatValue(value);
    01892 }
    01893
    01894
    01898 bool
    01899 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
    01900 {
    01901   return getNode(relative_path, true)->setDoubleValue(value);
    01902 }
    01903
    01904
    01908 bool
    01909 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
    01910 {
    01911   return getNode(relative_path, true)->setStringValue(value);
    01912 }
    01913
    01914
    01918 bool
    01919 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
    01920                                      const char * value)
    01921 {
    01922   return getNode(relative_path, true)->setUnspecifiedValue(value);
    01923 }
    01924
    01925
    01929 bool
    01930 SGPropertyNode::isTied (const char * relative_path) const
    01931 {
    01932   const SGPropertyNode * node = getNode(relative_path);
    01933   return (node == 0 ? false : node->isTied());
    01934 }
    01935
    01936
    01940 bool
    01941 SGPropertyNode::tie (const char * relative_path,
    01942                      const SGRawValue<bool> &rawValue,
    01943                      bool useDefault)
    01944 {
    01945   return getNode(relative_path, true)->tie(rawValue, useDefault);
    01946 }
    01947
    01948
    01952 bool
    01953 SGPropertyNode::tie (const char * relative_path,
    01954                      const SGRawValue<int> &rawValue,
    01955                      bool useDefault)
    01956 {
    01957   return getNode(relative_path, true)->tie(rawValue, useDefault);
    01958 }
    01959
    01960
    01964 bool
    01965 SGPropertyNode::tie (const char * relative_path,
    01966                      const SGRawValue<long> &rawValue,
    01967                      bool useDefault)
    01968 {
    01969   return getNode(relative_path, true)->tie(rawValue, useDefault);
    01970 }
    01971
    01972
    01976 bool
    01977 SGPropertyNode::tie (const char * relative_path,
    01978                      const SGRawValue<float> &rawValue,
    01979                      bool useDefault)
    01980 {
    01981   return getNode(relative_path, true)->tie(rawValue, useDefault);
    01982 }
    01983
    01984
    01988 bool
    01989 SGPropertyNode::tie (const char * relative_path,
    01990                      const SGRawValue<double> &rawValue,
    01991                      bool useDefault)
    01992 {
    01993   return getNode(relative_path, true)->tie(rawValue, useDefault);
    01994 }
    01995
    01996
    02000 bool
    02001 SGPropertyNode::tie (const char * relative_path,
    02002                      const SGRawValue<const char *> &rawValue,
    02003                      bool useDefault)
    02004 {
    02005   return getNode(relative_path, true)->tie(rawValue, useDefault);
    02006 }
    02007
    02008
    02012 bool
    02013 SGPropertyNode::untie (const char * relative_path)
    02014 {
    02015   SGPropertyNode * node = getNode(relative_path);
    02016   return (node == 0 ? false : node->untie());
    02017 }
    02018
    02019 void
    02020 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener)
    02021 {
    02022   if (_listeners == 0)
    02023     _listeners = new vector<SGPropertyChangeListener *>;
    02024   _listeners->push_back(listener);
    02025   listener->register_property(this);
    02026 }
    02027
    02028 void
    02029 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
    02030 {
    02031   vector<SGPropertyChangeListener *>::iterator it =
    02032     find(_listeners->begin(), _listeners->end(), listener);
    02033   if (it != _listeners->end()) {
    02034     _listeners->erase(it);
    02035     listener->unregister_property(this);
    02036     if (_listeners->empty()) {
    02037       vector<SGPropertyChangeListener *> * tmp = _listeners;
    02038       _listeners = 0;
    02039       delete tmp;
    02040     }
    02041   }
    02042 }
    02043
    02044 void
    02045 SGPropertyNode::fireValueChanged ()
    02046 {
    02047   fireValueChanged(this);
    02048 }
    02049
    02050 void
    02051 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
    02052 {
    02053   fireChildAdded(this, child);
    02054 }
    02055
    02056 void
    02057 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
    02058 {
    02059   fireChildRemoved(this, child);
    02060 }
    02061
    02062 void
    02063 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
    02064 {
    02065   if (_listeners != 0) {
    02066     for (unsigned int i = 0; i < _listeners->size(); i++) {
    02067       (*_listeners)[i]->valueChanged(node);
    02068     }
    02069   }
    02070   if (_parent != 0)
    02071     _parent->fireValueChanged(node);
    02072 }
    02073
    02074 void
    02075 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
    02076                                 SGPropertyNode * child)
    02077 {
    02078   if (_listeners != 0) {
    02079     for (unsigned int i = 0; i < _listeners->size(); i++) {
    02080       (*_listeners)[i]->childAdded(parent, child);
    02081     }
    02082   }
    02083   if (_parent != 0)
    02084     _parent->fireChildAdded(parent, child);
    02085 }
    02086
    02087 void
    02088 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
    02089                                   SGPropertyNode * child)
    02090 {
    02091   if (_listeners != 0) {
    02092     for (unsigned int i = 0; i < _listeners->size(); i++) {
    02093       (*_listeners)[i]->childRemoved(parent, child);
    02094     }
    02095   }
    02096   if (_parent != 0)
    02097     _parent->fireChildRemoved(parent, child);
    02098 }
    02099
    02100
    02101
    02103 // Simplified hash table for caching paths.
    02105
    02106 #define HASH_TABLE_SIZE 199
    02107
    02108 SGPropertyNode::hash_table::entry::entry ()
    02109   : _key(0),
    02110     _value(0)
    02111 {
    02112 }
    02113
    02114 SGPropertyNode::hash_table::entry::~entry ()
    02115 {
    02116                                 // Don't delete the value; we don't own
    02117                                 // the pointer.
    02118   delete [] _key;
    02119 }
    02120
    02121 void
    02122 SGPropertyNode::hash_table::entry::set_key (const char * key)
    02123 {
    02124   _key = copy_string(key);
    02125 }
    02126
    02127 void
    02128 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
    02129 {
    02130   _value = value;
    02131 }
    02132
    02133 SGPropertyNode::hash_table::bucket::bucket ()
    02134   : _length(0),
    02135     _entries(0)
    02136 {
    02137 }
    02138
    02139 SGPropertyNode::hash_table::bucket::~bucket ()
    02140 {
    02141   for (int i = 0; i < _length; i++)
    02142     delete _entries[i];
    02143 }
    02144
    02145 SGPropertyNode::hash_table::entry *
    02146 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
    02147 {
    02148   int i;
    02149   for (i = 0; i < _length; i++) {
    02150     if (!strcmp(_entries[i]->get_key(), key))
    02151       return _entries[i];
    02152   }
    02153   if (create) {
    02154     entry ** new_entries = new entry*[_length+1];
    02155     for (i = 0; i < _length; i++) {
    02156       new_entries[i] = _entries[i];
    02157     }
    02158     delete [] _entries;
    02159     _entries = new_entries;
    02160     _entries[_length] = new entry;
    02161     _entries[_length]->set_key(key);
    02162     _length++;
    02163     return _entries[_length - 1];
    02164   } else {
    02165     return 0;
    02166   }
    02167 }
    02168
    02169
    02170 SGPropertyNode::hash_table::hash_table ()
    02171   : _data_length(0),
    02172     _data(0)
    02173 {
    02174 }
    02175
    02176 SGPropertyNode::hash_table::~hash_table ()
    02177 {
    02178   for (unsigned int i = 0; i < _data_length; i++)
    02179     delete _data[i];
    02180 }
    02181
    02182 SGPropertyNode *
    02183 SGPropertyNode::hash_table::get (const char * key)
    02184 {
    02185   if (_data_length == 0)
    02186     return 0;
    02187   unsigned int index = hashcode(key) % _data_length;
    02188   if (_data[index] == 0)
    02189     return 0;
    02190   entry * e = _data[index]->get_entry(key);
    02191   if (e == 0)
    02192     return 0;
    02193   else
    02194     return e->get_value();
    02195 }
    02196
    02197 void
    02198 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
    02199 {
    02200   if (_data_length == 0) {
    02201     _data = new bucket*[HASH_TABLE_SIZE];
    02202     _data_length = HASH_TABLE_SIZE;
    02203     for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
    02204       _data[i] = 0;
    02205   }
    02206   unsigned int index = hashcode(key) % _data_length;
    02207   if (_data[index] == 0) {
    02208     _data[index] = new bucket;
    02209   }
    02210   entry * e = _data[index]->get_entry(key, true);
    02211   e->set_value(value);
    02212 }
    02213
    02214 unsigned int
    02215 SGPropertyNode::hash_table::hashcode (const char * key)
    02216 {
    02217   unsigned int hash = 0;
    02218   while (*key != 0) {
    02219     hash = 31 * hash + *key;
    02220     key++;
    02221   }
    02222   return hash;
    02223 }
    02224
    02225
    02226
    02230 SGPropertyNode_ptr::SGPropertyNode_ptr()
    02231 {
    02232   _ptr = 0;
    02233 }
    02234
    02238 SGPropertyNode_ptr::SGPropertyNode_ptr( const SGPropertyNode_ptr &r )
    02239 {
    02240   _ptr = r._ptr;
    02241   if (_ptr)
    02242      _ptr->incrementRef();
    02243 }
    02244
    02248 SGPropertyNode_ptr::SGPropertyNode_ptr( SGPropertyNode *p )
    02249 {
    02250   _ptr = p;
    02251   if (_ptr)
    02252      _ptr->incrementRef();
    02253 }
    02254
    02258 SGPropertyNode_ptr::~SGPropertyNode_ptr()
    02259 {
    02260   if (_ptr && _ptr->decrementRef() == 0)
    02261     delete _ptr;
    02262 }
    02263
    02267 SGPropertyNode_ptr &
    02268 SGPropertyNode_ptr::operator=( const SGPropertyNode_ptr &r )
    02269 {
    02270   if (_ptr && _ptr->decrementRef() == 0)
    02271     delete _ptr;
    02272   _ptr = r._ptr;
    02273   if (_ptr)
    02274      _ptr->incrementRef();
    02275
    02276   return *this;
    02277 }
    02278
    02282 SGPropertyNode *
    02283 SGPropertyNode_ptr::operator->()
    02284 {
    02285   return _ptr;
    02286 }
    02287
    02291 const SGPropertyNode *
    02292 SGPropertyNode_ptr::operator->() const
    02293 {
    02294   return _ptr;
    02295 }
    02296
    02300 SGPropertyNode_ptr::operator SGPropertyNode *()
    02301 {
    02302   return _ptr;
    02303 }
    02304
    02308 SGPropertyNode_ptr::operator const SGPropertyNode *() const
    02309 {
    02310   return _ptr;
    02311 }
    02312
    02316 bool
    02317 SGPropertyNode_ptr::valid() const
    02318 {
    02319   return _ptr != 0;
    02320 }
    02321
    02322
    02323
    02325 // Implementation of SGPropertyChangeListener.
    02327
    02328 SGPropertyChangeListener::~SGPropertyChangeListener ()
    02329 {
    02330                                 // This will come back and remove
    02331                                 // the current item each time.  Is
    02332                                 // that OK?
    02333   vector<SGPropertyNode *>::iterator it;
    02334   for (it = _properties.begin(); it != _properties.end(); it++)
    02335     (*it)->removeChangeListener(this);
    02336 }
    02337
    02338 void
    02339 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
    02340 {
    02341   // NO-OP
    02342 }
    02343
    02344 void
    02345 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
    02346                                       SGPropertyNode * child)
    02347 {
    02348   // NO-OP
    02349 }
    02350
    02351 void
    02352 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
    02353                                         SGPropertyNode * child)
    02354 {
    02355   // NO-OP
    02356 }
    02357
    02358 void
    02359 SGPropertyChangeListener::register_property (SGPropertyNode * node)
    02360 {
    02361   _properties.push_back(node);
    02362 }
    02363
    02364 void
    02365 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
    02366 {
    02367   vector<SGPropertyNode *>::iterator it =
    02368     find(_properties.begin(), _properties.end(), node);
    02369   if (it != _properties.end())
    02370     _properties.erase(it);
    02371 }
    02372
    02373
    02374 // end of props.cxx

@ 1.3 log @Oops, try again. @ text @d2173 1 a2173 1