]> git.mxchange.org Git - simgear.git/blob - simgear/props/props.cxx
722dfee93b2b3e91b5e961a730a280a71c528dec
[simgear.git] / simgear / props / props.cxx
1 // props.cxx - implementation of a property list.
2 // Started Fall 2000 by David Megginson, david@megginson.com
3 // This code is released into the Public Domain.
4 //
5 // See props.html for documentation [replace with URL when available].
6 //
7 // $Id$
8
9 #include "props.hxx"
10
11 #include <algorithm>
12 #include <sstream>
13 #include <stdio.h>
14 #include <string.h>
15
16 #if PROPS_STANDALONE
17
18 #include <iostream>
19 using std::cerr;
20 using std::endl;
21 using std::find;
22 using std::sort;
23 using std::vector;
24 using std::stringstream;
25
26 #else
27
28 #include <simgear/compiler.h>
29 #include <simgear/debug/logstream.hxx>
30
31 SG_USING_STD(sort);
32 SG_USING_STD(find);
33 SG_USING_STD(vector);
34 SG_USING_STD(stringstream);
35
36 #if ( _MSC_VER == 1200 )
37 // MSVC 6 is buggy, and needs something strange here
38 SG_USING_STD(vector<SGPropertyNode_ptr>);
39 SG_USING_STD(vector<SGPropertyChangeListener *>);
40 SG_USING_STD(vector<SGPropertyNode *>);
41 #endif
42
43 #endif
44
45
46 \f
47 ////////////////////////////////////////////////////////////////////////
48 // Local classes.
49 ////////////////////////////////////////////////////////////////////////
50
51 /**
52  * Comparator class for sorting by index.
53  */
54 class CompareIndices
55 {
56 public:
57   int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
58     return (n1->getIndex() < n2->getIndex());
59   }
60 };
61
62
63 \f
64 ////////////////////////////////////////////////////////////////////////
65 // Convenience macros for value access.
66 ////////////////////////////////////////////////////////////////////////
67
68 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
69 #define TEST_WRITE if (!getAttribute(WRITE)) return false
70
71
72 \f
73 ////////////////////////////////////////////////////////////////////////
74 // Default values for every type.
75 ////////////////////////////////////////////////////////////////////////
76
77 template<> const bool SGRawValue<bool>::DefaultValue = false;
78 template<> const int SGRawValue<int>::DefaultValue = 0;
79 template<> const long SGRawValue<long>::DefaultValue = 0L;
80 template<> const float SGRawValue<float>::DefaultValue = 0.0;
81 template<> const double SGRawValue<double>::DefaultValue = 0.0L;
82 template<> const char * const SGRawValue<const char *>::DefaultValue = "";
83
84
85 \f
86 ////////////////////////////////////////////////////////////////////////
87 // Local path normalization code.
88 ////////////////////////////////////////////////////////////////////////
89
90 /**
91  * A component in a path.
92  */
93 struct PathComponent
94 {
95   string name;
96   int index;
97 };
98
99 /**
100  * Parse the name for a path component.
101  *
102  * Name: [_a-zA-Z][-._a-zA-Z0-9]*
103  */
104 static inline const string
105 parse_name (const string &path, int &i)
106 {
107   string name = "";
108   int max = path.size();
109
110   if (path[i] == '.') {
111     i++;
112     if (i < max && path[i] == '.') {
113       i++;
114       name = "..";
115     } else {
116       name = ".";
117     }
118     if (i < max && path[i] != '/')
119       throw string("Illegal character after " + name);
120   }
121
122   else if (isalpha(path[i]) || path[i] == '_') {
123     name += path[i];
124     i++;
125
126                                 // The rules inside a name are a little
127                                 // less restrictive.
128     while (i < max) {
129       if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
130           path[i] == '-' || path[i] == '.') {
131         name += path[i];
132       } else if (path[i] == '[' || path[i] == '/') {
133         break;
134       } else {
135         throw string("name may contain only ._- and alphanumeric characters");
136       }
137       i++;
138     }
139   }
140
141   else {
142     if (name.size() == 0)
143       throw string("name must begin with alpha or '_'");
144   }
145
146   return name;
147 }
148
149
150 /**
151  * Parse the optional integer index for a path component.
152  *
153  * Index: "[" [0-9]+ "]"
154  */
155 static inline int
156 parse_index (const string &path, int &i)
157 {
158   int index = 0;
159
160   if (path[i] != '[')
161     return 0;
162   else
163     i++;
164
165   for (int max = path.size(); i < max; i++) {
166     if (isdigit(path[i])) {
167       index = (index * 10) + (path[i] - '0');
168     } else if (path[i] == ']') {
169       i++;
170       return index;
171     } else {
172       break;
173     }
174   }
175
176   throw string("unterminated index (looking for ']')");
177 }
178
179
180 /**
181  * Parse a single path component.
182  *
183  * Component: Name Index?
184  */
185 static inline PathComponent
186 parse_component (const string &path, int &i)
187 {
188   PathComponent component;
189   component.name = parse_name(path, i);
190   if (component.name[0] != '.')
191     component.index = parse_index(path, i);
192   else
193     component.index = -1;
194   return component;
195 }
196
197
198 /**
199  * Parse a path into its components.
200  */
201 static void
202 parse_path (const string &path, vector<PathComponent> &components)
203 {
204   int pos = 0;
205   int max = path.size();
206
207                                 // Check for initial '/'
208   if (path[pos] == '/') {
209     PathComponent root;
210     root.name = "";
211     root.index = -1;
212     components.push_back(root);
213     pos++;
214     while (pos < max && path[pos] == '/')
215       pos++;
216   }
217
218   while (pos < max) {
219     components.push_back(parse_component(path, pos));
220     while (pos < max && path[pos] == '/')
221       pos++;
222   }
223 }
224
225
226 \f
227 ////////////////////////////////////////////////////////////////////////
228 // Other static utility functions.
229 ////////////////////////////////////////////////////////////////////////
230
231
232 static char *
233 copy_string (const char * s)
234 {
235                                 // FIXME: potential buffer overflow.
236                                 // For some reason, strnlen and
237                                 // strncpy cause all kinds of crashes.
238   char * copy = new char[strlen(s) + 1];
239   strcpy(copy, s);
240   return copy;
241 }
242
243 static bool
244 compare_strings (const char * s1, const char * s2)
245 {
246   return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
247 }
248
249 /**
250  * Locate a child node by name and index.
251  */
252 static int
253 find_child (const char * name, int index, const vector<SGPropertyNode_ptr>& nodes)
254 {
255   int nNodes = nodes.size();
256   for (int i = 0; i < nNodes; i++) {
257     SGPropertyNode * node = nodes[i];
258     if (compare_strings(node->getName(), name) && node->getIndex() == index)
259       return i;
260   }
261   return -1;
262 }
263
264
265 /**
266  * Locate another node, given a relative path.
267  */
268 static SGPropertyNode *
269 find_node (SGPropertyNode * current,
270            const vector<PathComponent> &components,
271            int position,
272            bool create)
273 {
274                                 // Run off the end of the list
275   if (current == 0) {
276     return 0;
277   }
278
279                                 // Success! This is the one we want.
280   else if (position >= (int)components.size()) {
281     return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
282   }
283
284                                 // Empty component means root.
285   else if (components[position].name == "") {
286     return find_node(current->getRootNode(), components, position + 1, create);
287   }
288
289                                 // . means current directory
290   else if (components[position].name == ".") {
291     return find_node(current, components, position + 1, create);
292   }
293
294                                 // .. means parent directory
295   else if (components[position].name == "..") {
296     SGPropertyNode * parent = current->getParent();
297     if (parent == 0)
298       throw string("Attempt to move past root with '..'");
299     else
300       return find_node(parent, components, position + 1, create);
301   }
302
303                                 // Otherwise, a child name
304   else {
305     SGPropertyNode * child =
306       current->getChild(components[position].name.c_str(),
307                         components[position].index,
308                         create);
309     return find_node(child, components, position + 1, create);
310   }
311 }
312
313
314 \f
315 ////////////////////////////////////////////////////////////////////////
316 // Private methods from SGPropertyNode (may be inlined for speed).
317 ////////////////////////////////////////////////////////////////////////
318
319 inline bool
320 SGPropertyNode::get_bool () const
321 {
322   if (_tied)
323     return _value.bool_val->getValue();
324   else
325     return _local_val.bool_val;
326 }
327
328 inline int
329 SGPropertyNode::get_int () const
330 {
331   if (_tied)
332     return _value.int_val->getValue();
333   else
334     return _local_val.int_val;
335 }
336
337 inline long
338 SGPropertyNode::get_long () const
339 {
340   if (_tied)
341     return _value.long_val->getValue();
342   else
343     return _local_val.long_val;
344 }
345
346 inline float
347 SGPropertyNode::get_float () const
348 {
349   if (_tied)
350     return _value.float_val->getValue();
351   else
352     return _local_val.float_val;
353 }
354
355 inline double
356 SGPropertyNode::get_double () const
357 {
358   if (_tied)
359     return _value.double_val->getValue();
360   else
361     return _local_val.double_val;
362 }
363
364 inline const char *
365 SGPropertyNode::get_string () const
366 {
367   if (_tied)
368     return _value.string_val->getValue();
369   else
370     return _local_val.string_val;
371 }
372
373 inline bool
374 SGPropertyNode::set_bool (bool val)
375 {
376   if (_tied) {
377     if (_value.bool_val->setValue(val)) {
378       fireValueChanged();
379       return true;
380     } else {
381       return false;
382     }
383   } else {
384     _local_val.bool_val = val;
385     fireValueChanged();
386     return true;
387   }
388 }
389
390 inline bool
391 SGPropertyNode::set_int (int val)
392 {
393   if (_tied) {
394     if (_value.int_val->setValue(val)) {
395       fireValueChanged();
396       return true;
397     } else {
398       return false;
399     }
400   } else {
401     _local_val.int_val = val;
402     fireValueChanged();
403     return true;
404   }
405 }
406
407 inline bool
408 SGPropertyNode::set_long (long val)
409 {
410   if (_tied) {
411     if (_value.long_val->setValue(val)) {
412       fireValueChanged();
413       return true;
414     } else {
415       return false;
416     }
417   } else {
418     _local_val.long_val = val;
419     fireValueChanged();
420     return true;
421   }
422 }
423
424 inline bool
425 SGPropertyNode::set_float (float val)
426 {
427   if (_tied) {
428     if (_value.float_val->setValue(val)) {
429       fireValueChanged();
430       return true;
431     } else {
432       return false;
433     }
434   } else {
435     _local_val.float_val = val;
436     fireValueChanged();
437     return true;
438   }
439 }
440
441 inline bool
442 SGPropertyNode::set_double (double val)
443 {
444   if (_tied) {
445     if (_value.double_val->setValue(val)) {
446       fireValueChanged();
447       return true;
448     } else {
449       return false;
450     }
451   } else {
452     _local_val.double_val = val;
453     fireValueChanged();
454     return true;
455   }
456 }
457
458 inline bool
459 SGPropertyNode::set_string (const char * val)
460 {
461   if (_tied) {
462     if (_value.string_val->setValue(val)) {
463       fireValueChanged();
464       return true;
465     } else {
466       return false;
467     }
468   } else {
469     delete [] _local_val.string_val;
470     _local_val.string_val = copy_string(val);
471     fireValueChanged();
472     return true;
473   }
474 }
475
476 void
477 SGPropertyNode::clearValue ()
478 {
479   switch (_type) {
480   case NONE:
481     break;
482   case ALIAS:
483     _value.alias = 0;
484     break;
485   case BOOL:
486     if (_tied) {
487       delete _value.bool_val;
488       _value.bool_val = 0;
489     }
490     _local_val.bool_val = SGRawValue<bool>::DefaultValue;
491     break;
492   case INT:
493     if (_tied) {
494       delete _value.int_val;
495       _value.int_val = 0;
496     }
497     _local_val.int_val = SGRawValue<int>::DefaultValue;
498     break;
499   case LONG:
500     if (_tied) {
501       delete _value.long_val;
502       _value.long_val = 0L;
503     }
504     _local_val.long_val = SGRawValue<long>::DefaultValue;
505     break;
506   case FLOAT:
507     if (_tied) {
508       delete _value.float_val;
509       _value.float_val = 0;
510     }
511     _local_val.float_val = SGRawValue<float>::DefaultValue;
512     break;
513   case DOUBLE:
514     if (_tied) {
515       delete _value.double_val;
516       _value.double_val = 0;
517     }
518     _local_val.double_val = SGRawValue<double>::DefaultValue;
519     break;
520   case STRING:
521   case UNSPECIFIED:
522     if (_tied) {
523       delete _value.string_val;
524       _value.string_val = 0;
525     } else {
526       delete [] _local_val.string_val;
527     }
528     _local_val.string_val = 0;
529     break;
530   }
531   _tied = false;
532   _type = NONE;
533 }
534
535
536 /**
537  * Get the value as a string.
538  */
539 const char *
540 SGPropertyNode::make_string () const
541 {
542   if (!getAttribute(READ))
543     return "";
544
545   switch (_type) {
546   case ALIAS:
547     return _value.alias->getStringValue();
548   case BOOL:
549     if (get_bool())
550       return "true";
551     else
552       return "false";
553   case INT:
554     {
555       stringstream sstr;
556       sstr << get_int();
557       _buffer = sstr.str();
558       return _buffer.c_str();
559     }
560   case LONG:
561     {
562       stringstream sstr;
563       sstr << get_long();
564       _buffer = sstr.str();
565       return _buffer.c_str();
566     }
567   case FLOAT:
568     {
569       stringstream sstr;
570       sstr << get_float();
571       _buffer = sstr.str();
572       return _buffer.c_str();
573     }
574   case DOUBLE:
575     {
576       stringstream sstr;
577       sstr.precision( 10 );
578       sstr << get_double();
579       _buffer = sstr.str();
580       return _buffer.c_str();
581     }
582   case STRING:
583   case UNSPECIFIED:
584     return get_string();
585   case NONE:
586   default:
587     return "";
588   }
589 }
590
591 /**
592  * Trace a write access for a property.
593  */
594 void
595 SGPropertyNode::trace_write () const
596 {
597 #if PROPS_STANDALONE
598   cerr << "TRACE: Write node " << getPath () << ", value\""
599        << make_string() << '"' << endl;
600 #else
601   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
602          << ", value\"" << make_string() << '"');
603 #endif
604 }
605
606 /**
607  * Trace a read access for a property.
608  */
609 void
610 SGPropertyNode::trace_read () const
611 {
612 #if PROPS_STANDALONE
613   cerr << "TRACE: Write node " << getPath () << ", value \""
614        << make_string() << '"' << endl;
615 #else
616   SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
617          << ", value \"" << make_string() << '"');
618 #endif
619 }
620
621 \f
622 ////////////////////////////////////////////////////////////////////////
623 // Public methods from SGPropertyNode.
624 ////////////////////////////////////////////////////////////////////////
625
626 /**
627  * Last used attribute
628  * Update as needed when enum Attribute is changed
629  */
630 const int SGPropertyNode::LAST_USED_ATTRIBUTE = TRACE_WRITE;
631
632 /**
633  * Default constructor: always creates a root node.
634  */
635 SGPropertyNode::SGPropertyNode ()
636   : _index(0),
637     _parent(0),
638     _path_cache(0),
639     _type(NONE),
640     _tied(false),
641     _attr(READ|WRITE),
642     _listeners(0)
643 {
644   _local_val.string_val = 0;
645 }
646
647
648 /**
649  * Copy constructor.
650  */
651 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
652   : _index(node._index),
653     _name(node._name),
654     _parent(0),                 // don't copy the parent
655     _path_cache(0),
656     _type(node._type),
657     _tied(node._tied),
658     _attr(node._attr),
659     _listeners(0)               // CHECK!!
660 {
661   _local_val.string_val = 0;
662   switch (_type) {
663   case NONE:
664     break;
665   case ALIAS:
666     _value.alias = node._value.alias;
667     _tied = false;
668     break;
669   case BOOL:
670     if (_tied) {
671       _tied = true;
672       _value.bool_val = node._value.bool_val->clone();
673     } else {
674       _tied = false;
675       set_bool(node.get_bool());
676     }
677     break;
678   case INT:
679     if (_tied) {
680       _tied = true;
681       _value.int_val = node._value.int_val->clone();
682     } else {
683       _tied = false;
684       set_int(node.get_int());
685     }
686     break;
687   case LONG:
688     if (_tied) {
689       _tied = true;
690       _value.long_val = node._value.long_val->clone();
691     } else {
692       _tied = false;
693       set_long(node.get_long());
694     }
695     break;
696   case FLOAT:
697     if (_tied) {
698       _tied = true;
699       _value.float_val = node._value.float_val->clone();
700     } else {
701       _tied = false;
702       set_float(node.get_float());
703     }
704     break;
705   case DOUBLE:
706     if (_tied) {
707       _tied = true;
708       _value.double_val = node._value.double_val->clone();
709     } else {
710       _tied = false;
711       set_double(node.get_double());
712     }
713     break;
714   case STRING:
715   case UNSPECIFIED:
716     if (_tied) {
717       _tied = true;
718       _value.string_val = node._value.string_val->clone();
719     } else {
720       _tied = false;
721       set_string(node.get_string());
722     }
723     break;
724   }
725 }
726
727
728 /**
729  * Convenience constructor.
730  */
731 SGPropertyNode::SGPropertyNode (const char * name,
732                                 int index,
733                                 SGPropertyNode * parent)
734   : _index(index),
735     _parent(parent),
736     _path_cache(0),
737     _type(NONE),
738     _tied(false),
739     _attr(READ|WRITE),
740     _listeners(0)
741 {
742   _name = name;
743   _local_val.string_val = 0;
744 }
745
746
747 /**
748  * Destructor.
749  */
750 SGPropertyNode::~SGPropertyNode ()
751 {
752   // zero out all parent pointers, else they might be dangling
753   for (unsigned i = 0; i < _children.size(); ++i)
754     _children[i]->_parent = 0;
755   for (unsigned i = 0; i < _removedChildren.size(); ++i)
756     _removedChildren[i]->_parent = 0;
757   delete _path_cache;
758   clearValue();
759   delete _listeners;
760 }
761
762
763 /**
764  * Alias to another node.
765  */
766 bool
767 SGPropertyNode::alias (SGPropertyNode * target)
768 {
769   if (target == 0 || _type == ALIAS || _tied)
770     return false;
771   clearValue();
772   _value.alias = target;
773   _type = ALIAS;
774   return true;
775 }
776
777
778 /**
779  * Alias to another node by path.
780  */
781 bool
782 SGPropertyNode::alias (const char * path)
783 {
784   return alias(getNode(path, true));
785 }
786
787
788 /**
789  * Remove an alias.
790  */
791 bool
792 SGPropertyNode::unalias ()
793 {
794   if (_type != ALIAS)
795     return false;
796   _type = NONE;
797   _value.alias = 0;
798   return true;
799 }
800
801
802 /**
803  * Get the target of an alias.
804  */
805 SGPropertyNode *
806 SGPropertyNode::getAliasTarget ()
807 {
808   return (_type == ALIAS ? _value.alias : 0);
809 }
810
811
812 const SGPropertyNode *
813 SGPropertyNode::getAliasTarget () const
814 {
815   return (_type == ALIAS ? _value.alias : 0);
816 }
817
818
819 /**
820  * Get a non-const child by index.
821  */
822 SGPropertyNode *
823 SGPropertyNode::getChild (int position)
824 {
825   if (position >= 0 && position < nChildren())
826     return _children[position];
827   else
828     return 0;
829 }
830
831
832 /**
833  * Get a const child by index.
834  */
835 const SGPropertyNode *
836 SGPropertyNode::getChild (int position) const
837 {
838   if (position >= 0 && position < nChildren())
839     return _children[position];
840   else
841     return 0;
842 }
843
844
845 /**
846  * Get a non-const child by name and index, creating if necessary.
847  */
848 SGPropertyNode *
849 SGPropertyNode::getChild (const char * name, int index, bool create)
850 {
851   int pos = find_child(name, index, _children);
852   if (pos >= 0) {
853     return _children[pos];
854   } else if (create) {
855     SGPropertyNode_ptr node;
856     pos = find_child(name, index, _removedChildren);
857     if (pos >= 0) {
858       vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
859       it += pos;
860       node = _removedChildren[pos];
861       _removedChildren.erase(it);
862       node->setAttribute(REMOVED, false);
863     } else {
864       node = new SGPropertyNode(name, index, this);
865     }
866     _children.push_back(node);
867     fireChildAdded(node);
868     return node;
869   } else {
870     return 0;
871   }
872 }
873
874
875 /**
876  * Get a const child by name and index.
877  */
878 const SGPropertyNode *
879 SGPropertyNode::getChild (const char * name, int index) const
880 {
881   int pos = find_child(name, index, _children);
882   if (pos >= 0)
883     return _children[pos];
884   else
885     return 0;
886 }
887
888
889 /**
890  * Get all children with the same name (but different indices).
891  */
892 vector<SGPropertyNode_ptr>
893 SGPropertyNode::getChildren (const char * name) const
894 {
895   vector<SGPropertyNode_ptr> children;
896   int max = _children.size();
897
898   for (int i = 0; i < max; i++)
899     if (compare_strings(_children[i]->getName(), name))
900       children.push_back(_children[i]);
901
902   sort(children.begin(), children.end(), CompareIndices());
903   return children;
904 }
905
906
907 /**
908  * Remove child by position.
909  */
910 SGPropertyNode_ptr
911 SGPropertyNode::removeChild (int pos, bool keep)
912 {
913   SGPropertyNode_ptr node;
914   if (pos < 0 || pos >= (int)_children.size())
915     return node;
916
917   vector<SGPropertyNode_ptr>::iterator it = _children.begin();
918   it += pos;
919   node = _children[pos];
920   _children.erase(it);
921   if (keep) {
922     _removedChildren.push_back(node);
923   }
924   if (_path_cache)
925      _path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
926   node->setAttribute(REMOVED, true);
927   node->clearValue();
928   fireChildRemoved(node);
929   return node;
930 }
931
932
933 /**
934  * Remove a child node
935  */
936 SGPropertyNode_ptr 
937 SGPropertyNode::removeChild (const char * name, int index, bool keep)
938 {
939   SGPropertyNode_ptr ret;
940   int pos = find_child(name, index, _children);
941   if (pos >= 0)
942     ret = removeChild(pos, keep);
943   return ret;
944 }
945
946
947 /**
948   * Remove all children with the specified name.
949   */
950 vector<SGPropertyNode_ptr>
951 SGPropertyNode::removeChildren (const char * name, bool keep)
952 {
953   vector<SGPropertyNode_ptr> children;
954
955   for (int pos = _children.size() - 1; pos >= 0; pos--)
956     if (compare_strings(_children[pos]->getName(), name))
957       children.push_back(removeChild(pos, keep));
958
959   sort(children.begin(), children.end(), CompareIndices());
960   return children;
961 }
962
963
964 const char *
965 SGPropertyNode::getDisplayName (bool simplify) const
966 {
967   _display_name = _name;
968   if (_index != 0 || !simplify) {
969     stringstream sstr;
970     sstr << '[' << _index << ']';
971     _display_name += sstr.str();
972   }
973   return _display_name.c_str();
974 }
975
976
977 const char *
978 SGPropertyNode::getPath (bool simplify) const
979 {
980   // Calculate the complete path only once.
981   if (_parent != 0 && _path.empty()) {
982     _path = _parent->getPath(simplify);
983     _path += '/';
984     _path += getDisplayName(simplify);
985   }
986
987   return _path.c_str();
988 }
989
990 SGPropertyNode::Type
991 SGPropertyNode::getType () const
992 {
993   if (_type == ALIAS)
994     return _value.alias->getType();
995   else
996     return _type;
997 }
998
999
1000 bool 
1001 SGPropertyNode::getBoolValue () const
1002 {
1003                                 // Shortcut for common case
1004   if (_attr == (READ|WRITE) && _type == BOOL)
1005     return get_bool();
1006
1007   if (getAttribute(TRACE_READ))
1008     trace_read();
1009   if (!getAttribute(READ))
1010     return SGRawValue<bool>::DefaultValue;
1011   switch (_type) {
1012   case ALIAS:
1013     return _value.alias->getBoolValue();
1014   case BOOL:
1015     return get_bool();
1016   case INT:
1017     return get_int() == 0 ? false : true;
1018   case LONG:
1019     return get_long() == 0L ? false : true;
1020   case FLOAT:
1021     return get_float() == 0.0 ? false : true;
1022   case DOUBLE:
1023     return get_double() == 0.0L ? false : true;
1024   case STRING:
1025   case UNSPECIFIED:
1026     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1027   case NONE:
1028   default:
1029     return SGRawValue<bool>::DefaultValue;
1030   }
1031 }
1032
1033 int 
1034 SGPropertyNode::getIntValue () const
1035 {
1036                                 // Shortcut for common case
1037   if (_attr == (READ|WRITE) && _type == INT)
1038     return get_int();
1039
1040   if (getAttribute(TRACE_READ))
1041     trace_read();
1042   if (!getAttribute(READ))
1043     return SGRawValue<int>::DefaultValue;
1044   switch (_type) {
1045   case ALIAS:
1046     return _value.alias->getIntValue();
1047   case BOOL:
1048     return int(get_bool());
1049   case INT:
1050     return get_int();
1051   case LONG:
1052     return int(get_long());
1053   case FLOAT:
1054     return int(get_float());
1055   case DOUBLE:
1056     return int(get_double());
1057   case STRING:
1058   case UNSPECIFIED:
1059     return atoi(get_string());
1060   case NONE:
1061   default:
1062     return SGRawValue<int>::DefaultValue;
1063   }
1064 }
1065
1066 long 
1067 SGPropertyNode::getLongValue () const
1068 {
1069                                 // Shortcut for common case
1070   if (_attr == (READ|WRITE) && _type == LONG)
1071     return get_long();
1072
1073   if (getAttribute(TRACE_READ))
1074     trace_read();
1075   if (!getAttribute(READ))
1076     return SGRawValue<long>::DefaultValue;
1077   switch (_type) {
1078   case ALIAS:
1079     return _value.alias->getLongValue();
1080   case BOOL:
1081     return long(get_bool());
1082   case INT:
1083     return long(get_int());
1084   case LONG:
1085     return get_long();
1086   case FLOAT:
1087     return long(get_float());
1088   case DOUBLE:
1089     return long(get_double());
1090   case STRING:
1091   case UNSPECIFIED:
1092     return strtol(get_string(), 0, 0);
1093   case NONE:
1094   default:
1095     return SGRawValue<long>::DefaultValue;
1096   }
1097 }
1098
1099 float 
1100 SGPropertyNode::getFloatValue () const
1101 {
1102                                 // Shortcut for common case
1103   if (_attr == (READ|WRITE) && _type == FLOAT)
1104     return get_float();
1105
1106   if (getAttribute(TRACE_READ))
1107     trace_read();
1108   if (!getAttribute(READ))
1109     return SGRawValue<float>::DefaultValue;
1110   switch (_type) {
1111   case ALIAS:
1112     return _value.alias->getFloatValue();
1113   case BOOL:
1114     return float(get_bool());
1115   case INT:
1116     return float(get_int());
1117   case LONG:
1118     return float(get_long());
1119   case FLOAT:
1120     return get_float();
1121   case DOUBLE:
1122     return float(get_double());
1123   case STRING:
1124   case UNSPECIFIED:
1125     return atof(get_string());
1126   case NONE:
1127   default:
1128     return SGRawValue<float>::DefaultValue;
1129   }
1130 }
1131
1132 double 
1133 SGPropertyNode::getDoubleValue () const
1134 {
1135                                 // Shortcut for common case
1136   if (_attr == (READ|WRITE) && _type == DOUBLE)
1137     return get_double();
1138
1139   if (getAttribute(TRACE_READ))
1140     trace_read();
1141   if (!getAttribute(READ))
1142     return SGRawValue<double>::DefaultValue;
1143
1144   switch (_type) {
1145   case ALIAS:
1146     return _value.alias->getDoubleValue();
1147   case BOOL:
1148     return double(get_bool());
1149   case INT:
1150     return double(get_int());
1151   case LONG:
1152     return double(get_long());
1153   case FLOAT:
1154     return double(get_float());
1155   case DOUBLE:
1156     return get_double();
1157   case STRING:
1158   case UNSPECIFIED:
1159     return strtod(get_string(), 0);
1160   case NONE:
1161   default:
1162     return SGRawValue<double>::DefaultValue;
1163   }
1164 }
1165
1166 const char *
1167 SGPropertyNode::getStringValue () const
1168 {
1169                                 // Shortcut for common case
1170   if (_attr == (READ|WRITE) && _type == STRING)
1171     return get_string();
1172
1173   if (getAttribute(TRACE_READ))
1174     trace_read();
1175   if (!getAttribute(READ))
1176     return SGRawValue<const char *>::DefaultValue;
1177   return make_string();
1178 }
1179
1180 bool
1181 SGPropertyNode::setBoolValue (bool value)
1182 {
1183                                 // Shortcut for common case
1184   if (_attr == (READ|WRITE) && _type == BOOL)
1185     return set_bool(value);
1186
1187   bool result = false;
1188   TEST_WRITE;
1189   if (_type == NONE || _type == UNSPECIFIED) {
1190     clearValue();
1191     _tied = false;
1192     _type = BOOL;
1193   }
1194
1195   switch (_type) {
1196   case ALIAS:
1197     result = _value.alias->setBoolValue(value);
1198     break;
1199   case BOOL:
1200     result = set_bool(value);
1201     break;
1202   case INT:
1203     result = set_int(int(value));
1204     break;
1205   case LONG:
1206     result = set_long(long(value));
1207     break;
1208   case FLOAT:
1209     result = set_float(float(value));
1210     break;
1211   case DOUBLE:
1212     result = set_double(double(value));
1213     break;
1214   case STRING:
1215   case UNSPECIFIED:
1216     result = set_string(value ? "true" : "false");
1217     break;
1218   case NONE:
1219   default:
1220     break;
1221   }
1222
1223   if (getAttribute(TRACE_WRITE))
1224     trace_write();
1225   return result;
1226 }
1227
1228 bool
1229 SGPropertyNode::setIntValue (int value)
1230 {
1231                                 // Shortcut for common case
1232   if (_attr == (READ|WRITE) && _type == INT)
1233     return set_int(value);
1234
1235   bool result = false;
1236   TEST_WRITE;
1237   if (_type == NONE || _type == UNSPECIFIED) {
1238     clearValue();
1239     _type = INT;
1240     _local_val.int_val = 0;
1241   }
1242
1243   switch (_type) {
1244   case ALIAS:
1245     result = _value.alias->setIntValue(value);
1246     break;
1247   case BOOL:
1248     result = set_bool(value == 0 ? false : true);
1249     break;
1250   case INT:
1251     result = set_int(value);
1252     break;
1253   case LONG:
1254     result = set_long(long(value));
1255     break;
1256   case FLOAT:
1257     result = set_float(float(value));
1258     break;
1259   case DOUBLE:
1260     result = set_double(double(value));
1261     break;
1262   case STRING:
1263   case UNSPECIFIED: {
1264     char buf[128];
1265     sprintf(buf, "%d", value);
1266     result = set_string(buf);
1267     break;
1268   }
1269   case NONE:
1270   default:
1271     break;
1272   }
1273
1274   if (getAttribute(TRACE_WRITE))
1275     trace_write();
1276   return result;
1277 }
1278
1279 bool
1280 SGPropertyNode::setLongValue (long value)
1281 {
1282                                 // Shortcut for common case
1283   if (_attr == (READ|WRITE) && _type == LONG)
1284     return set_long(value);
1285
1286   bool result = false;
1287   TEST_WRITE;
1288   if (_type == NONE || _type == UNSPECIFIED) {
1289     clearValue();
1290     _type = LONG;
1291     _local_val.long_val = 0L;
1292   }
1293
1294   switch (_type) {
1295   case ALIAS:
1296     result = _value.alias->setLongValue(value);
1297     break;
1298   case BOOL:
1299     result = set_bool(value == 0L ? false : true);
1300     break;
1301   case INT:
1302     result = set_int(int(value));
1303     break;
1304   case LONG:
1305     result = set_long(value);
1306     break;
1307   case FLOAT:
1308     result = set_float(float(value));
1309     break;
1310   case DOUBLE:
1311     result = set_double(double(value));
1312     break;
1313   case STRING:
1314   case UNSPECIFIED: {
1315     char buf[128];
1316     sprintf(buf, "%ld", value);
1317     result = set_string(buf);
1318     break;
1319   }
1320   case NONE:
1321   default:
1322     break;
1323   }
1324
1325   if (getAttribute(TRACE_WRITE))
1326     trace_write();
1327   return result;
1328 }
1329
1330 bool
1331 SGPropertyNode::setFloatValue (float value)
1332 {
1333                                 // Shortcut for common case
1334   if (_attr == (READ|WRITE) && _type == FLOAT)
1335     return set_float(value);
1336
1337   bool result = false;
1338   TEST_WRITE;
1339   if (_type == NONE || _type == UNSPECIFIED) {
1340     clearValue();
1341     _type = FLOAT;
1342     _local_val.float_val = 0;
1343   }
1344
1345   switch (_type) {
1346   case ALIAS:
1347     result = _value.alias->setFloatValue(value);
1348     break;
1349   case BOOL:
1350     result = set_bool(value == 0.0 ? false : true);
1351     break;
1352   case INT:
1353     result = set_int(int(value));
1354     break;
1355   case LONG:
1356     result = set_long(long(value));
1357     break;
1358   case FLOAT:
1359     result = set_float(value);
1360     break;
1361   case DOUBLE:
1362     result = set_double(double(value));
1363     break;
1364   case STRING:
1365   case UNSPECIFIED: {
1366     char buf[128];
1367     sprintf(buf, "%f", value);
1368     result = set_string(buf);
1369     break;
1370   }
1371   case NONE:
1372   default:
1373     break;
1374   }
1375
1376   if (getAttribute(TRACE_WRITE))
1377     trace_write();
1378   return result;
1379 }
1380
1381 bool
1382 SGPropertyNode::setDoubleValue (double value)
1383 {
1384                                 // Shortcut for common case
1385   if (_attr == (READ|WRITE) && _type == DOUBLE)
1386     return set_double(value);
1387
1388   bool result = false;
1389   TEST_WRITE;
1390   if (_type == NONE || _type == UNSPECIFIED) {
1391     clearValue();
1392     _local_val.double_val = value;
1393     _type = DOUBLE;
1394   }
1395
1396   switch (_type) {
1397   case ALIAS:
1398     result = _value.alias->setDoubleValue(value);
1399     break;
1400   case BOOL:
1401     result = set_bool(value == 0.0L ? false : true);
1402     break;
1403   case INT:
1404     result = set_int(int(value));
1405     break;
1406   case LONG:
1407     result = set_long(long(value));
1408     break;
1409   case FLOAT:
1410     result = set_float(float(value));
1411     break;
1412   case DOUBLE:
1413     result = set_double(value);
1414     break;
1415   case STRING:
1416   case UNSPECIFIED: {
1417     char buf[128];
1418     sprintf(buf, "%f", value);
1419     result = set_string(buf);
1420     break;
1421   }
1422   case NONE:
1423   default:
1424     break;
1425   }
1426
1427   if (getAttribute(TRACE_WRITE))
1428     trace_write();
1429   return result;
1430 }
1431
1432 bool
1433 SGPropertyNode::setStringValue (const char * value)
1434 {
1435                                 // Shortcut for common case
1436   if (_attr == (READ|WRITE) && _type == STRING)
1437     return set_string(value);
1438
1439   bool result = false;
1440   TEST_WRITE;
1441   if (_type == NONE || _type == UNSPECIFIED) {
1442     clearValue();
1443     _type = STRING;
1444   }
1445
1446   switch (_type) {
1447   case ALIAS:
1448     result = _value.alias->setStringValue(value);
1449     break;
1450   case BOOL:
1451     result = set_bool((compare_strings(value, "true")
1452                        || atoi(value)) ? true : false);
1453     break;
1454   case INT:
1455     result = set_int(atoi(value));
1456     break;
1457   case LONG:
1458     result = set_long(strtol(value, 0, 0));
1459     break;
1460   case FLOAT:
1461     result = set_float(atof(value));
1462     break;
1463   case DOUBLE:
1464     result = set_double(strtod(value, 0));
1465     break;
1466   case STRING:
1467   case UNSPECIFIED:
1468     result = set_string(value);
1469     break;
1470   case NONE:
1471   default:
1472     break;
1473   }
1474
1475   if (getAttribute(TRACE_WRITE))
1476     trace_write();
1477   return result;
1478 }
1479
1480 bool
1481 SGPropertyNode::setUnspecifiedValue (const char * value)
1482 {
1483   bool result = false;
1484   TEST_WRITE;
1485   if (_type == NONE) {
1486     clearValue();
1487     _type = UNSPECIFIED;
1488   }
1489
1490   switch (_type) {
1491   case ALIAS:
1492     result = _value.alias->setUnspecifiedValue(value);
1493     break;
1494   case BOOL:
1495     result = set_bool((compare_strings(value, "true")
1496                        || atoi(value)) ? true : false);
1497     break;
1498   case INT:
1499     result = set_int(atoi(value));
1500     break;
1501   case LONG:
1502     result = set_long(strtol(value, 0, 0));
1503     break;
1504   case FLOAT:
1505     result = set_float(atof(value));
1506     break;
1507   case DOUBLE:
1508     result = set_double(strtod(value, 0));
1509     break;
1510   case STRING:
1511   case UNSPECIFIED:
1512     result = set_string(value);
1513     break;
1514   case NONE:
1515   default:
1516     break;
1517   }
1518
1519   if (getAttribute(TRACE_WRITE))
1520     trace_write();
1521   return result;
1522 }
1523
1524 bool
1525 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1526 {
1527   if (_type == ALIAS || _tied)
1528     return false;
1529
1530   useDefault = useDefault && hasValue();
1531   bool old_val = false;
1532   if (useDefault)
1533     old_val = getBoolValue();
1534
1535   clearValue();
1536   _type = BOOL;
1537   _tied = true;
1538   _value.bool_val = rawValue.clone();
1539
1540   if (useDefault)
1541     setBoolValue(old_val);
1542
1543   return true;
1544 }
1545
1546 bool
1547 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1548 {
1549   if (_type == ALIAS || _tied)
1550     return false;
1551
1552   useDefault = useDefault && hasValue();
1553   int old_val = 0;
1554   if (useDefault)
1555     old_val = getIntValue();
1556
1557   clearValue();
1558   _type = INT;
1559   _tied = true;
1560   _value.int_val = rawValue.clone();
1561
1562   if (useDefault)
1563     setIntValue(old_val);
1564
1565   return true;
1566 }
1567
1568 bool
1569 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1570 {
1571   if (_type == ALIAS || _tied)
1572     return false;
1573
1574   useDefault = useDefault && hasValue();
1575   long old_val = 0;
1576   if (useDefault)
1577     old_val = getLongValue();
1578
1579   clearValue();
1580   _type = LONG;
1581   _tied = true;
1582   _value.long_val = rawValue.clone();
1583
1584   if (useDefault)
1585     setLongValue(old_val);
1586
1587   return true;
1588 }
1589
1590 bool
1591 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1592 {
1593   if (_type == ALIAS || _tied)
1594     return false;
1595
1596   useDefault = useDefault && hasValue();
1597   float old_val = 0.0;
1598   if (useDefault)
1599     old_val = getFloatValue();
1600
1601   clearValue();
1602   _type = FLOAT;
1603   _tied = true;
1604   _value.float_val = rawValue.clone();
1605
1606   if (useDefault)
1607     setFloatValue(old_val);
1608
1609   return true;
1610 }
1611
1612 bool
1613 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1614 {
1615   if (_type == ALIAS || _tied)
1616     return false;
1617
1618   useDefault = useDefault && hasValue();
1619   double old_val = 0.0;
1620   if (useDefault)
1621     old_val = getDoubleValue();
1622
1623   clearValue();
1624   _type = DOUBLE;
1625   _tied = true;
1626   _value.double_val = rawValue.clone();
1627
1628   if (useDefault)
1629     setDoubleValue(old_val);
1630
1631   return true;
1632
1633 }
1634
1635 bool
1636 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1637 {
1638   if (_type == ALIAS || _tied)
1639     return false;
1640
1641   useDefault = useDefault && hasValue();
1642   string old_val;
1643   if (useDefault)
1644     old_val = getStringValue();
1645
1646   clearValue();
1647   _type = STRING;
1648   _tied = true;
1649   _value.string_val = rawValue.clone();
1650
1651   if (useDefault)
1652     setStringValue(old_val.c_str());
1653
1654   return true;
1655 }
1656
1657 bool
1658 SGPropertyNode::untie ()
1659 {
1660   if (!_tied)
1661     return false;
1662
1663   switch (_type) {
1664   case BOOL: {
1665     bool val = getBoolValue();
1666     clearValue();
1667     _type = BOOL;
1668     _local_val.bool_val = val;
1669     break;
1670   }
1671   case INT: {
1672     int val = getIntValue();
1673     clearValue();
1674     _type = INT;
1675     _local_val.int_val = val;
1676     break;
1677   }
1678   case LONG: {
1679     long val = getLongValue();
1680     clearValue();
1681     _type = LONG;
1682     _local_val.long_val = val;
1683     break;
1684   }
1685   case FLOAT: {
1686     float val = getFloatValue();
1687     clearValue();
1688     _type = FLOAT;
1689     _local_val.float_val = val;
1690     break;
1691   }
1692   case DOUBLE: {
1693     double val = getDoubleValue();
1694     clearValue();
1695     _type = DOUBLE;
1696     _local_val.double_val = val;
1697     break;
1698   }
1699   case STRING:
1700   case UNSPECIFIED: {
1701     string val = getStringValue();
1702     clearValue();
1703     _type = STRING;
1704     _local_val.string_val = copy_string(val.c_str());
1705     break;
1706   }
1707   case NONE:
1708   default:
1709     break;
1710   }
1711
1712   _tied = false;
1713   return true;
1714 }
1715
1716 SGPropertyNode *
1717 SGPropertyNode::getRootNode ()
1718 {
1719   if (_parent == 0)
1720     return this;
1721   else
1722     return _parent->getRootNode();
1723 }
1724
1725 const SGPropertyNode *
1726 SGPropertyNode::getRootNode () const
1727 {
1728   if (_parent == 0)
1729     return this;
1730   else
1731     return _parent->getRootNode();
1732 }
1733
1734 SGPropertyNode *
1735 SGPropertyNode::getNode (const char * relative_path, bool create)
1736 {
1737   if (_path_cache == 0)
1738     _path_cache = new hash_table;
1739
1740   SGPropertyNode * result = _path_cache->get(relative_path);
1741   if (result == 0) {
1742     vector<PathComponent> components;
1743     parse_path(relative_path, components);
1744     result = find_node(this, components, 0, create);
1745     if (result != 0)
1746       _path_cache->put(relative_path, result);
1747   }
1748
1749   return result;
1750 }
1751
1752 SGPropertyNode *
1753 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1754 {
1755   vector<PathComponent> components;
1756   parse_path(relative_path, components);
1757   if (components.size() > 0)
1758     components.back().index = index;
1759   return find_node(this, components, 0, create);
1760 }
1761
1762 const SGPropertyNode *
1763 SGPropertyNode::getNode (const char * relative_path) const
1764 {
1765   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1766 }
1767
1768 const SGPropertyNode *
1769 SGPropertyNode::getNode (const char * relative_path, int index) const
1770 {
1771   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1772 }
1773
1774 \f
1775 ////////////////////////////////////////////////////////////////////////
1776 // Convenience methods using relative paths.
1777 ////////////////////////////////////////////////////////////////////////
1778
1779
1780 /**
1781  * Test whether another node has a value attached.
1782  */
1783 bool
1784 SGPropertyNode::hasValue (const char * relative_path) const
1785 {
1786   const SGPropertyNode * node = getNode(relative_path);
1787   return (node == 0 ? false : node->hasValue());
1788 }
1789
1790
1791 /**
1792  * Get the value type for another node.
1793  */
1794 SGPropertyNode::Type
1795 SGPropertyNode::getType (const char * relative_path) const
1796 {
1797   const SGPropertyNode * node = getNode(relative_path);
1798   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1799 }
1800
1801
1802 /**
1803  * Get a bool value for another node.
1804  */
1805 bool
1806 SGPropertyNode::getBoolValue (const char * relative_path,
1807                               bool defaultValue) const
1808 {
1809   const SGPropertyNode * node = getNode(relative_path);
1810   return (node == 0 ? defaultValue : node->getBoolValue());
1811 }
1812
1813
1814 /**
1815  * Get an int value for another node.
1816  */
1817 int
1818 SGPropertyNode::getIntValue (const char * relative_path,
1819                              int defaultValue) const
1820 {
1821   const SGPropertyNode * node = getNode(relative_path);
1822   return (node == 0 ? defaultValue : node->getIntValue());
1823 }
1824
1825
1826 /**
1827  * Get a long value for another node.
1828  */
1829 long
1830 SGPropertyNode::getLongValue (const char * relative_path,
1831                               long defaultValue) const
1832 {
1833   const SGPropertyNode * node = getNode(relative_path);
1834   return (node == 0 ? defaultValue : node->getLongValue());
1835 }
1836
1837
1838 /**
1839  * Get a float value for another node.
1840  */
1841 float
1842 SGPropertyNode::getFloatValue (const char * relative_path,
1843                                float defaultValue) const
1844 {
1845   const SGPropertyNode * node = getNode(relative_path);
1846   return (node == 0 ? defaultValue : node->getFloatValue());
1847 }
1848
1849
1850 /**
1851  * Get a double value for another node.
1852  */
1853 double
1854 SGPropertyNode::getDoubleValue (const char * relative_path,
1855                                 double defaultValue) const
1856 {
1857   const SGPropertyNode * node = getNode(relative_path);
1858   return (node == 0 ? defaultValue : node->getDoubleValue());
1859 }
1860
1861
1862 /**
1863  * Get a string value for another node.
1864  */
1865 const char *
1866 SGPropertyNode::getStringValue (const char * relative_path,
1867                                 const char * defaultValue) const
1868 {
1869   const SGPropertyNode * node = getNode(relative_path);
1870   return (node == 0 ? defaultValue : node->getStringValue());
1871 }
1872
1873
1874 /**
1875  * Set a bool value for another node.
1876  */
1877 bool
1878 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1879 {
1880   return getNode(relative_path, true)->setBoolValue(value);
1881 }
1882
1883
1884 /**
1885  * Set an int value for another node.
1886  */
1887 bool
1888 SGPropertyNode::setIntValue (const char * relative_path, int value)
1889 {
1890   return getNode(relative_path, true)->setIntValue(value);
1891 }
1892
1893
1894 /**
1895  * Set a long value for another node.
1896  */
1897 bool
1898 SGPropertyNode::setLongValue (const char * relative_path, long value)
1899 {
1900   return getNode(relative_path, true)->setLongValue(value);
1901 }
1902
1903
1904 /**
1905  * Set a float value for another node.
1906  */
1907 bool
1908 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1909 {
1910   return getNode(relative_path, true)->setFloatValue(value);
1911 }
1912
1913
1914 /**
1915  * Set a double value for another node.
1916  */
1917 bool
1918 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1919 {
1920   return getNode(relative_path, true)->setDoubleValue(value);
1921 }
1922
1923
1924 /**
1925  * Set a string value for another node.
1926  */
1927 bool
1928 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1929 {
1930   return getNode(relative_path, true)->setStringValue(value);
1931 }
1932
1933
1934 /**
1935  * Set an unknown value for another node.
1936  */
1937 bool
1938 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1939                                      const char * value)
1940 {
1941   return getNode(relative_path, true)->setUnspecifiedValue(value);
1942 }
1943
1944
1945 /**
1946  * Test whether another node is tied.
1947  */
1948 bool
1949 SGPropertyNode::isTied (const char * relative_path) const
1950 {
1951   const SGPropertyNode * node = getNode(relative_path);
1952   return (node == 0 ? false : node->isTied());
1953 }
1954
1955
1956 /**
1957  * Tie a node reached by a relative path, creating it if necessary.
1958  */
1959 bool
1960 SGPropertyNode::tie (const char * relative_path,
1961                      const SGRawValue<bool> &rawValue,
1962                      bool useDefault)
1963 {
1964   return getNode(relative_path, true)->tie(rawValue, useDefault);
1965 }
1966
1967
1968 /**
1969  * Tie a node reached by a relative path, creating it if necessary.
1970  */
1971 bool
1972 SGPropertyNode::tie (const char * relative_path,
1973                      const SGRawValue<int> &rawValue,
1974                      bool useDefault)
1975 {
1976   return getNode(relative_path, true)->tie(rawValue, useDefault);
1977 }
1978
1979
1980 /**
1981  * Tie a node reached by a relative path, creating it if necessary.
1982  */
1983 bool
1984 SGPropertyNode::tie (const char * relative_path,
1985                      const SGRawValue<long> &rawValue,
1986                      bool useDefault)
1987 {
1988   return getNode(relative_path, true)->tie(rawValue, useDefault);
1989 }
1990
1991
1992 /**
1993  * Tie a node reached by a relative path, creating it if necessary.
1994  */
1995 bool
1996 SGPropertyNode::tie (const char * relative_path,
1997                      const SGRawValue<float> &rawValue,
1998                      bool useDefault)
1999 {
2000   return getNode(relative_path, true)->tie(rawValue, useDefault);
2001 }
2002
2003
2004 /**
2005  * Tie a node reached by a relative path, creating it if necessary.
2006  */
2007 bool
2008 SGPropertyNode::tie (const char * relative_path,
2009                      const SGRawValue<double> &rawValue,
2010                      bool useDefault)
2011 {
2012   return getNode(relative_path, true)->tie(rawValue, useDefault);
2013 }
2014
2015
2016 /**
2017  * Tie a node reached by a relative path, creating it if necessary.
2018  */
2019 bool
2020 SGPropertyNode::tie (const char * relative_path,
2021                      const SGRawValue<const char *> &rawValue,
2022                      bool useDefault)
2023 {
2024   return getNode(relative_path, true)->tie(rawValue, useDefault);
2025 }
2026
2027
2028 /**
2029  * Attempt to untie another node reached by a relative path.
2030  */
2031 bool
2032 SGPropertyNode::untie (const char * relative_path)
2033 {
2034   SGPropertyNode * node = getNode(relative_path);
2035   return (node == 0 ? false : node->untie());
2036 }
2037
2038 void
2039 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2040                                    bool initial)
2041 {
2042   if (_listeners == 0)
2043     _listeners = new vector<SGPropertyChangeListener*>;
2044   _listeners->push_back(listener);
2045   listener->register_property(this);
2046   if (initial)
2047     listener->valueChanged(this);
2048 }
2049
2050 void
2051 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2052 {
2053   vector<SGPropertyChangeListener*>::iterator it =
2054     find(_listeners->begin(), _listeners->end(), listener);
2055   if (it != _listeners->end()) {
2056     _listeners->erase(it);
2057     listener->unregister_property(this);
2058     if (_listeners->empty()) {
2059       vector<SGPropertyChangeListener*>* tmp = _listeners;
2060       _listeners = 0;
2061       delete tmp;
2062     }
2063   }
2064 }
2065
2066 void
2067 SGPropertyNode::fireValueChanged ()
2068 {
2069   fireValueChanged(this);
2070 }
2071
2072 void
2073 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2074 {
2075   fireChildAdded(this, child);
2076 }
2077
2078 void
2079 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2080 {
2081   fireChildRemoved(this, child);
2082 }
2083
2084 void
2085 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2086 {
2087   if (_listeners != 0) {
2088     for (unsigned int i = 0; i < _listeners->size(); i++) {
2089       (*_listeners)[i]->valueChanged(node);
2090     }
2091   }
2092   if (_parent != 0)
2093     _parent->fireValueChanged(node);
2094 }
2095
2096 void
2097 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2098                                 SGPropertyNode * child)
2099 {
2100   if (_listeners != 0) {
2101     for (unsigned int i = 0; i < _listeners->size(); i++) {
2102       (*_listeners)[i]->childAdded(parent, child);
2103     }
2104   }
2105   if (_parent != 0)
2106     _parent->fireChildAdded(parent, child);
2107 }
2108
2109 void
2110 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2111                                   SGPropertyNode * child)
2112 {
2113   if (_listeners != 0) {
2114     for (unsigned int i = 0; i < _listeners->size(); i++) {
2115       (*_listeners)[i]->childRemoved(parent, child);
2116     }
2117   }
2118   if (_parent != 0)
2119     _parent->fireChildRemoved(parent, child);
2120 }
2121
2122
2123 \f
2124 ////////////////////////////////////////////////////////////////////////
2125 // Simplified hash table for caching paths.
2126 ////////////////////////////////////////////////////////////////////////
2127
2128 #define HASH_TABLE_SIZE 199
2129
2130 SGPropertyNode::hash_table::entry::entry ()
2131   : _value(0)
2132 {
2133 }
2134
2135 SGPropertyNode::hash_table::entry::~entry ()
2136 {
2137                                 // Don't delete the value; we don't own
2138                                 // the pointer.
2139 }
2140
2141 void
2142 SGPropertyNode::hash_table::entry::set_key (const char * key)
2143 {
2144   _key = key;
2145 }
2146
2147 void
2148 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2149 {
2150   _value = value;
2151 }
2152
2153 SGPropertyNode::hash_table::bucket::bucket ()
2154   : _length(0),
2155     _entries(0)
2156 {
2157 }
2158
2159 SGPropertyNode::hash_table::bucket::~bucket ()
2160 {
2161   for (int i = 0; i < _length; i++)
2162     delete _entries[i];
2163   delete [] _entries;
2164 }
2165
2166 SGPropertyNode::hash_table::entry *
2167 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2168 {
2169   int i;
2170   for (i = 0; i < _length; i++) {
2171     if (!strcmp(_entries[i]->get_key(), key))
2172       return _entries[i];
2173   }
2174   if (create) {
2175     entry ** new_entries = new entry*[_length+1];
2176     for (i = 0; i < _length; i++) {
2177       new_entries[i] = _entries[i];
2178     }
2179     delete [] _entries;
2180     _entries = new_entries;
2181     _entries[_length] = new entry;
2182     _entries[_length]->set_key(key);
2183     _length++;
2184     return _entries[_length - 1];
2185   } else {
2186     return 0;
2187   }
2188 }
2189
2190 void
2191 SGPropertyNode::hash_table::bucket::erase (const char * key)
2192 {
2193   int i;
2194   for (i = 0; i < _length; i++) {
2195     if (!strcmp(_entries[i]->get_key(), key))
2196        break;
2197   }
2198
2199   if (i < _length) {
2200     for (++i; i < _length; i++) {
2201       _entries[i-1] = _entries[i];
2202     }
2203      _length--;
2204   }
2205 }
2206
2207
2208 SGPropertyNode::hash_table::hash_table ()
2209   : _data_length(0),
2210     _data(0)
2211 {
2212 }
2213
2214 SGPropertyNode::hash_table::~hash_table ()
2215 {
2216   for (unsigned int i = 0; i < _data_length; i++)
2217     delete _data[i];
2218   delete [] _data;
2219 }
2220
2221 SGPropertyNode *
2222 SGPropertyNode::hash_table::get (const char * key)
2223 {
2224   if (_data_length == 0)
2225     return 0;
2226   unsigned int index = hashcode(key) % _data_length;
2227   if (_data[index] == 0)
2228     return 0;
2229   entry * e = _data[index]->get_entry(key);
2230   if (e == 0)
2231     return 0;
2232   else
2233     return e->get_value();
2234 }
2235
2236 void
2237 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2238 {
2239   if (_data_length == 0) {
2240     _data = new bucket*[HASH_TABLE_SIZE];
2241     _data_length = HASH_TABLE_SIZE;
2242     for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2243       _data[i] = 0;
2244   }
2245   unsigned int index = hashcode(key) % _data_length;
2246   if (_data[index] == 0) {
2247     _data[index] = new bucket;
2248   }
2249   entry * e = _data[index]->get_entry(key, true);
2250   e->set_value(value);
2251 }
2252
2253 void
2254 SGPropertyNode::hash_table::erase (const char * key)
2255 {
2256    if (_data_length == 0)
2257     return;
2258   unsigned int index = hashcode(key) % _data_length;
2259   if (_data[index] == 0)
2260     return;
2261   _data[index]->erase(key);
2262 }
2263
2264 unsigned int
2265 SGPropertyNode::hash_table::hashcode (const char * key)
2266 {
2267   unsigned int hash = 0;
2268   while (*key != 0) {
2269     hash = 31 * hash + *key;
2270     key++;
2271   }
2272   return hash;
2273 }
2274
2275
2276 \f
2277 ////////////////////////////////////////////////////////////////////////
2278 // Implementation of SGPropertyChangeListener.
2279 ////////////////////////////////////////////////////////////////////////
2280
2281 SGPropertyChangeListener::~SGPropertyChangeListener ()
2282 {
2283                                 // This will come back and remove
2284                                 // the current item each time.  Is
2285                                 // that OK?
2286   vector<SGPropertyNode *>::iterator it;
2287   for (it = _properties.begin(); it != _properties.end(); it++)
2288     (*it)->removeChangeListener(this);
2289 }
2290
2291 void
2292 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2293 {
2294   // NO-OP
2295 }
2296
2297 void
2298 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2299                                       SGPropertyNode * child)
2300 {
2301   // NO-OP
2302 }
2303
2304 void
2305 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2306                                         SGPropertyNode * child)
2307 {
2308   // NO-OP
2309 }
2310
2311 void
2312 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2313 {
2314   _properties.push_back(node);
2315 }
2316
2317 void
2318 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2319 {
2320   vector<SGPropertyNode *>::iterator it =
2321     find(_properties.begin(), _properties.end(), node);
2322   if (it != _properties.end())
2323     _properties.erase(it);
2324 }
2325
2326
2327 // end of props.cxx