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