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