]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
Significant improvements to the change-listener support. There are
[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   return path.c_str();
935 }
936
937 SGPropertyNode::Type
938 SGPropertyNode::getType () const
939 {
940   if (_type == ALIAS)
941     return _value.alias->getType();
942   else
943     return _type;
944 }
945
946
947 bool 
948 SGPropertyNode::getBoolValue () const
949 {
950                                 // Shortcut for common case
951   if (_attr == (READ|WRITE) && _type == BOOL)
952     return get_bool();
953
954   if (getAttribute(TRACE_READ))
955     trace_read();
956   if (!getAttribute(READ))
957     return SGRawValue<bool>::DefaultValue;
958   switch (_type) {
959   case ALIAS:
960     return _value.alias->getBoolValue();
961   case BOOL:
962     return get_bool();
963   case INT:
964     return get_int() == 0 ? false : true;
965   case LONG:
966     return get_long() == 0L ? false : true;
967   case FLOAT:
968     return get_float() == 0.0 ? false : true;
969   case DOUBLE:
970     return get_double() == 0.0L ? false : true;
971   case STRING:
972   case UNSPECIFIED:
973     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
974   case NONE:
975   default:
976     return SGRawValue<bool>::DefaultValue;
977   }
978 }
979
980 int 
981 SGPropertyNode::getIntValue () const
982 {
983                                 // Shortcut for common case
984   if (_attr == (READ|WRITE) && _type == INT)
985     return get_int();
986
987   if (getAttribute(TRACE_READ))
988     trace_read();
989   if (!getAttribute(READ))
990     return SGRawValue<int>::DefaultValue;
991   switch (_type) {
992   case ALIAS:
993     return _value.alias->getIntValue();
994   case BOOL:
995     return int(get_bool());
996   case INT:
997     return get_int();
998   case LONG:
999     return int(get_long());
1000   case FLOAT:
1001     return int(get_float());
1002   case DOUBLE:
1003     return int(get_double());
1004   case STRING:
1005   case UNSPECIFIED:
1006     return atoi(get_string());
1007   case NONE:
1008   default:
1009     return SGRawValue<int>::DefaultValue;
1010   }
1011 }
1012
1013 long 
1014 SGPropertyNode::getLongValue () const
1015 {
1016                                 // Shortcut for common case
1017   if (_attr == (READ|WRITE) && _type == LONG)
1018     return get_long();
1019
1020   if (getAttribute(TRACE_READ))
1021     trace_read();
1022   if (!getAttribute(READ))
1023     return SGRawValue<long>::DefaultValue;
1024   switch (_type) {
1025   case ALIAS:
1026     return _value.alias->getLongValue();
1027   case BOOL:
1028     return long(get_bool());
1029   case INT:
1030     return long(get_int());
1031   case LONG:
1032     return get_long();
1033   case FLOAT:
1034     return long(get_float());
1035   case DOUBLE:
1036     return long(get_double());
1037   case STRING:
1038   case UNSPECIFIED:
1039     return strtol(get_string(), 0, 0);
1040   case NONE:
1041   default:
1042     return SGRawValue<long>::DefaultValue;
1043   }
1044 }
1045
1046 float 
1047 SGPropertyNode::getFloatValue () const
1048 {
1049                                 // Shortcut for common case
1050   if (_attr == (READ|WRITE) && _type == FLOAT)
1051     return get_float();
1052
1053   if (getAttribute(TRACE_READ))
1054     trace_read();
1055   if (!getAttribute(READ))
1056     return SGRawValue<float>::DefaultValue;
1057   switch (_type) {
1058   case ALIAS:
1059     return _value.alias->getFloatValue();
1060   case BOOL:
1061     return float(get_bool());
1062   case INT:
1063     return float(get_int());
1064   case LONG:
1065     return float(get_long());
1066   case FLOAT:
1067     return get_float();
1068   case DOUBLE:
1069     return float(get_double());
1070   case STRING:
1071   case UNSPECIFIED:
1072     return atof(get_string());
1073   case NONE:
1074   default:
1075     return SGRawValue<float>::DefaultValue;
1076   }
1077 }
1078
1079 double 
1080 SGPropertyNode::getDoubleValue () const
1081 {
1082                                 // Shortcut for common case
1083   if (_attr == (READ|WRITE) && _type == DOUBLE)
1084     return get_double();
1085
1086   if (getAttribute(TRACE_READ))
1087     trace_read();
1088   if (!getAttribute(READ))
1089     return SGRawValue<double>::DefaultValue;
1090
1091   switch (_type) {
1092   case ALIAS:
1093     return _value.alias->getDoubleValue();
1094   case BOOL:
1095     return double(get_bool());
1096   case INT:
1097     return double(get_int());
1098   case LONG:
1099     return double(get_long());
1100   case FLOAT:
1101     return double(get_float());
1102   case DOUBLE:
1103     return get_double();
1104   case STRING:
1105   case UNSPECIFIED:
1106     return strtod(get_string(), 0);
1107   case NONE:
1108   default:
1109     return SGRawValue<double>::DefaultValue;
1110   }
1111 }
1112
1113 const char *
1114 SGPropertyNode::getStringValue () const
1115 {
1116                                 // Shortcut for common case
1117   if (_attr == (READ|WRITE) && _type == STRING)
1118     return get_string();
1119
1120   if (getAttribute(TRACE_READ))
1121     trace_read();
1122   if (!getAttribute(READ))
1123     return SGRawValue<const char *>::DefaultValue;
1124   return make_string();
1125 }
1126
1127 bool
1128 SGPropertyNode::setBoolValue (bool value)
1129 {
1130                                 // Shortcut for common case
1131   if (_attr == (READ|WRITE) && _type == BOOL)
1132     return set_bool(value);
1133
1134   bool result = false;
1135   TEST_WRITE;
1136   if (_type == NONE || _type == UNSPECIFIED) {
1137     clear_value();
1138     _tied = false;
1139     _type = BOOL;
1140   }
1141
1142   switch (_type) {
1143   case ALIAS:
1144     result = _value.alias->setBoolValue(value);
1145     break;
1146   case BOOL:
1147     result = set_bool(value);
1148     break;
1149   case INT:
1150     result = set_int(int(value));
1151     break;
1152   case LONG:
1153     result = set_long(long(value));
1154     break;
1155   case FLOAT:
1156     result = set_float(float(value));
1157     break;
1158   case DOUBLE:
1159     result = set_double(double(value));
1160     break;
1161   case STRING:
1162   case UNSPECIFIED:
1163     result = set_string(value ? "true" : "false");
1164     break;
1165   case NONE:
1166   default:
1167     break;
1168   }
1169
1170   if (getAttribute(TRACE_WRITE))
1171     trace_write();
1172   return result;
1173 }
1174
1175 bool
1176 SGPropertyNode::setIntValue (int value)
1177 {
1178                                 // Shortcut for common case
1179   if (_attr == (READ|WRITE) && _type == INT)
1180     return set_int(value);
1181
1182   bool result = false;
1183   TEST_WRITE;
1184   if (_type == NONE || _type == UNSPECIFIED) {
1185     clear_value();
1186     _type = INT;
1187     _local_val.int_val = 0;
1188   }
1189
1190   switch (_type) {
1191   case ALIAS:
1192     result = _value.alias->setIntValue(value);
1193     break;
1194   case BOOL:
1195     result = set_bool(value == 0 ? false : true);
1196     break;
1197   case INT:
1198     result = set_int(value);
1199     break;
1200   case LONG:
1201     result = set_long(long(value));
1202     break;
1203   case FLOAT:
1204     result = set_float(float(value));
1205     break;
1206   case DOUBLE:
1207     result = set_double(double(value));
1208     break;
1209   case STRING:
1210   case UNSPECIFIED: {
1211     char buf[128];
1212     sprintf(buf, "%d", value);
1213     result = set_string(buf);
1214     break;
1215   }
1216   case NONE:
1217   default:
1218     break;
1219   }
1220
1221   if (getAttribute(TRACE_WRITE))
1222     trace_write();
1223   return result;
1224 }
1225
1226 bool
1227 SGPropertyNode::setLongValue (long value)
1228 {
1229                                 // Shortcut for common case
1230   if (_attr == (READ|WRITE) && _type == LONG)
1231     return set_long(value);
1232
1233   bool result = false;
1234   TEST_WRITE;
1235   if (_type == NONE || _type == UNSPECIFIED) {
1236     clear_value();
1237     _type = LONG;
1238     _local_val.long_val = 0L;
1239   }
1240
1241   switch (_type) {
1242   case ALIAS:
1243     result = _value.alias->setLongValue(value);
1244     break;
1245   case BOOL:
1246     result = set_bool(value == 0L ? false : true);
1247     break;
1248   case INT:
1249     result = set_int(int(value));
1250     break;
1251   case LONG:
1252     result = set_long(value);
1253     break;
1254   case FLOAT:
1255     result = set_float(float(value));
1256     break;
1257   case DOUBLE:
1258     result = set_double(double(value));
1259     break;
1260   case STRING:
1261   case UNSPECIFIED: {
1262     char buf[128];
1263     sprintf(buf, "%ld", value);
1264     result = set_string(buf);
1265     break;
1266   }
1267   case NONE:
1268   default:
1269     break;
1270   }
1271
1272   if (getAttribute(TRACE_WRITE))
1273     trace_write();
1274   return result;
1275 }
1276
1277 bool
1278 SGPropertyNode::setFloatValue (float value)
1279 {
1280                                 // Shortcut for common case
1281   if (_attr == (READ|WRITE) && _type == FLOAT)
1282     return set_float(value);
1283
1284   bool result = false;
1285   TEST_WRITE;
1286   if (_type == NONE || _type == UNSPECIFIED) {
1287     clear_value();
1288     _type = FLOAT;
1289     _local_val.float_val = 0;
1290   }
1291
1292   switch (_type) {
1293   case ALIAS:
1294     result = _value.alias->setFloatValue(value);
1295     break;
1296   case BOOL:
1297     result = set_bool(value == 0.0 ? false : true);
1298     break;
1299   case INT:
1300     result = set_int(int(value));
1301     break;
1302   case LONG:
1303     result = set_long(long(value));
1304     break;
1305   case FLOAT:
1306     result = set_float(value);
1307     break;
1308   case DOUBLE:
1309     result = set_double(double(value));
1310     break;
1311   case STRING:
1312   case UNSPECIFIED: {
1313     char buf[128];
1314     sprintf(buf, "%f", value);
1315     result = set_string(buf);
1316     break;
1317   }
1318   case NONE:
1319   default:
1320     break;
1321   }
1322
1323   if (getAttribute(TRACE_WRITE))
1324     trace_write();
1325   return result;
1326 }
1327
1328 bool
1329 SGPropertyNode::setDoubleValue (double value)
1330 {
1331                                 // Shortcut for common case
1332   if (_attr == (READ|WRITE) && _type == DOUBLE)
1333     return set_double(value);
1334
1335   bool result = false;
1336   TEST_WRITE;
1337   if (_type == NONE || _type == UNSPECIFIED) {
1338     clear_value();
1339     _local_val.double_val = value;
1340     _type = DOUBLE;
1341   }
1342
1343   switch (_type) {
1344   case ALIAS:
1345     result = _value.alias->setDoubleValue(value);
1346     break;
1347   case BOOL:
1348     result = set_bool(value == 0.0L ? false : true);
1349     break;
1350   case INT:
1351     result = set_int(int(value));
1352     break;
1353   case LONG:
1354     result = set_long(long(value));
1355     break;
1356   case FLOAT:
1357     result = set_float(float(value));
1358     break;
1359   case DOUBLE:
1360     result = set_double(value);
1361     break;
1362   case STRING:
1363   case UNSPECIFIED: {
1364     char buf[128];
1365     sprintf(buf, "%f", value);
1366     result = set_string(buf);
1367     break;
1368   }
1369   case NONE:
1370   default:
1371     break;
1372   }
1373
1374   if (getAttribute(TRACE_WRITE))
1375     trace_write();
1376   return result;
1377 }
1378
1379 bool
1380 SGPropertyNode::setStringValue (const char * value)
1381 {
1382                                 // Shortcut for common case
1383   if (_attr == (READ|WRITE) && _type == STRING)
1384     return set_string(value);
1385
1386   bool result = false;
1387   TEST_WRITE;
1388   if (_type == NONE || _type == UNSPECIFIED) {
1389     clear_value();
1390     _type = STRING;
1391   }
1392
1393   switch (_type) {
1394   case ALIAS:
1395     result = _value.alias->setStringValue(value);
1396     break;
1397   case BOOL:
1398     result = set_bool((compare_strings(value, "true")
1399                        || atoi(value)) ? true : false);
1400     break;
1401   case INT:
1402     result = set_int(atoi(value));
1403     break;
1404   case LONG:
1405     result = set_long(strtol(value, 0, 0));
1406     break;
1407   case FLOAT:
1408     result = set_float(atof(value));
1409     break;
1410   case DOUBLE:
1411     result = set_double(strtod(value, 0));
1412     break;
1413   case STRING:
1414   case UNSPECIFIED:
1415     result = set_string(value);
1416     break;
1417   case NONE:
1418   default:
1419     break;
1420   }
1421
1422   if (getAttribute(TRACE_WRITE))
1423     trace_write();
1424   return result;
1425 }
1426
1427 bool
1428 SGPropertyNode::setUnspecifiedValue (const char * value)
1429 {
1430   bool result = false;
1431   TEST_WRITE;
1432   if (_type == NONE) {
1433     clear_value();
1434     _type = UNSPECIFIED;
1435   }
1436
1437   switch (_type) {
1438   case ALIAS:
1439     result = _value.alias->setUnspecifiedValue(value);
1440     break;
1441   case BOOL:
1442     result = set_bool((compare_strings(value, "true")
1443                        || atoi(value)) ? true : false);
1444     break;
1445   case INT:
1446     result = set_int(atoi(value));
1447     break;
1448   case LONG:
1449     result = set_long(strtol(value, 0, 0));
1450     break;
1451   case FLOAT:
1452     result = set_float(atof(value));
1453     break;
1454   case DOUBLE:
1455     result = set_double(strtod(value, 0));
1456     break;
1457   case STRING:
1458   case UNSPECIFIED:
1459     result = set_string(value);
1460     break;
1461   case NONE:
1462   default:
1463     break;
1464   }
1465
1466   if (getAttribute(TRACE_WRITE))
1467     trace_write();
1468   return result;
1469 }
1470
1471 bool
1472 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1473 {
1474   if (_type == ALIAS || _tied)
1475     return false;
1476
1477   useDefault = useDefault && hasValue();
1478   bool old_val = false;
1479   if (useDefault)
1480     old_val = getBoolValue();
1481
1482   clear_value();
1483   _type = BOOL;
1484   _tied = true;
1485   _value.bool_val = rawValue.clone();
1486
1487   if (useDefault)
1488     setBoolValue(old_val);
1489
1490   return true;
1491 }
1492
1493 bool
1494 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1495 {
1496   if (_type == ALIAS || _tied)
1497     return false;
1498
1499   useDefault = useDefault && hasValue();
1500   int old_val = 0;
1501   if (useDefault)
1502     old_val = getIntValue();
1503
1504   clear_value();
1505   _type = INT;
1506   _tied = true;
1507   _value.int_val = rawValue.clone();
1508
1509   if (useDefault)
1510     setIntValue(old_val);
1511
1512   return true;
1513 }
1514
1515 bool
1516 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1517 {
1518   if (_type == ALIAS || _tied)
1519     return false;
1520
1521   useDefault = useDefault && hasValue();
1522   long old_val = 0;
1523   if (useDefault)
1524     old_val = getLongValue();
1525
1526   clear_value();
1527   _type = LONG;
1528   _tied = true;
1529   _value.long_val = rawValue.clone();
1530
1531   if (useDefault)
1532     setLongValue(old_val);
1533
1534   return true;
1535 }
1536
1537 bool
1538 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1539 {
1540   if (_type == ALIAS || _tied)
1541     return false;
1542
1543   useDefault = useDefault && hasValue();
1544   float old_val = 0.0;
1545   if (useDefault)
1546     old_val = getFloatValue();
1547
1548   clear_value();
1549   _type = FLOAT;
1550   _tied = true;
1551   _value.float_val = rawValue.clone();
1552
1553   if (useDefault)
1554     setFloatValue(old_val);
1555
1556   return true;
1557 }
1558
1559 bool
1560 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1561 {
1562   if (_type == ALIAS || _tied)
1563     return false;
1564
1565   useDefault = useDefault && hasValue();
1566   double old_val = 0.0;
1567   if (useDefault)
1568     old_val = getDoubleValue();
1569
1570   clear_value();
1571   _type = DOUBLE;
1572   _tied = true;
1573   _value.double_val = rawValue.clone();
1574
1575   if (useDefault)
1576     setDoubleValue(old_val);
1577
1578   return true;
1579
1580 }
1581
1582 bool
1583 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1584 {
1585   if (_type == ALIAS || _tied)
1586     return false;
1587
1588   useDefault = useDefault && hasValue();
1589   string old_val;
1590   if (useDefault)
1591     old_val = getStringValue();
1592
1593   clear_value();
1594   _type = STRING;
1595   _tied = true;
1596   _value.string_val = rawValue.clone();
1597
1598   if (useDefault)
1599     setStringValue(old_val.c_str());
1600
1601   return true;
1602 }
1603
1604 bool
1605 SGPropertyNode::untie ()
1606 {
1607   if (!_tied)
1608     return false;
1609
1610   switch (_type) {
1611   case BOOL: {
1612     bool val = getBoolValue();
1613     clear_value();
1614     _type = BOOL;
1615     _local_val.bool_val = val;
1616     break;
1617   }
1618   case INT: {
1619     int val = getIntValue();
1620     clear_value();
1621     _type = INT;
1622     _local_val.int_val = val;
1623     break;
1624   }
1625   case LONG: {
1626     long val = getLongValue();
1627     clear_value();
1628     _type = LONG;
1629     _local_val.long_val = val;
1630     break;
1631   }
1632   case FLOAT: {
1633     float val = getFloatValue();
1634     clear_value();
1635     _type = FLOAT;
1636     _local_val.float_val = val;
1637     break;
1638   }
1639   case DOUBLE: {
1640     double val = getDoubleValue();
1641     clear_value();
1642     _type = DOUBLE;
1643     _local_val.double_val = val;
1644     break;
1645   }
1646   case STRING:
1647   case UNSPECIFIED: {
1648     string val = getStringValue();
1649     clear_value();
1650     _type = STRING;
1651     _local_val.string_val = copy_string(val.c_str());
1652     break;
1653   }
1654   case NONE:
1655   default:
1656     break;
1657   }
1658
1659   _tied = false;
1660   return true;
1661 }
1662
1663 SGPropertyNode *
1664 SGPropertyNode::getRootNode ()
1665 {
1666   if (_parent == 0)
1667     return this;
1668   else
1669     return _parent->getRootNode();
1670 }
1671
1672 const SGPropertyNode *
1673 SGPropertyNode::getRootNode () const
1674 {
1675   if (_parent == 0)
1676     return this;
1677   else
1678     return _parent->getRootNode();
1679 }
1680
1681 SGPropertyNode *
1682 SGPropertyNode::getNode (const char * relative_path, bool create)
1683 {
1684   if (_path_cache == 0)
1685     _path_cache = new hash_table;
1686
1687   SGPropertyNode * result = _path_cache->get(relative_path);
1688   if (result == 0) {
1689     vector<PathComponent> components;
1690     parse_path(relative_path, components);
1691     result = find_node(this, components, 0, create);
1692     if (result != 0)
1693       _path_cache->put(relative_path, result);
1694   }
1695   
1696   return result;
1697 }
1698
1699 SGPropertyNode *
1700 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1701 {
1702   vector<PathComponent> components;
1703   parse_path(relative_path, components);
1704   if (components.size() > 0)
1705     components[components.size()-1].index = index;
1706   return find_node(this, components, 0, create);
1707 }
1708
1709 const SGPropertyNode *
1710 SGPropertyNode::getNode (const char * relative_path) const
1711 {
1712   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1713 }
1714
1715 const SGPropertyNode *
1716 SGPropertyNode::getNode (const char * relative_path, int index) const
1717 {
1718   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1719 }
1720
1721 \f
1722 ////////////////////////////////////////////////////////////////////////
1723 // Convenience methods using relative paths.
1724 ////////////////////////////////////////////////////////////////////////
1725
1726
1727 /**
1728  * Test whether another node has a value attached.
1729  */
1730 bool
1731 SGPropertyNode::hasValue (const char * relative_path) const
1732 {
1733   const SGPropertyNode * node = getNode(relative_path);
1734   return (node == 0 ? false : node->hasValue());
1735 }
1736
1737
1738 /**
1739  * Get the value type for another node.
1740  */
1741 SGPropertyNode::Type
1742 SGPropertyNode::getType (const char * relative_path) const
1743 {
1744   const SGPropertyNode * node = getNode(relative_path);
1745   return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1746 }
1747
1748
1749 /**
1750  * Get a bool value for another node.
1751  */
1752 bool
1753 SGPropertyNode::getBoolValue (const char * relative_path,
1754                               bool defaultValue) const
1755 {
1756   const SGPropertyNode * node = getNode(relative_path);
1757   return (node == 0 ? defaultValue : node->getBoolValue());
1758 }
1759
1760
1761 /**
1762  * Get an int value for another node.
1763  */
1764 int
1765 SGPropertyNode::getIntValue (const char * relative_path,
1766                              int defaultValue) const
1767 {
1768   const SGPropertyNode * node = getNode(relative_path);
1769   return (node == 0 ? defaultValue : node->getIntValue());
1770 }
1771
1772
1773 /**
1774  * Get a long value for another node.
1775  */
1776 long
1777 SGPropertyNode::getLongValue (const char * relative_path,
1778                               long defaultValue) const
1779 {
1780   const SGPropertyNode * node = getNode(relative_path);
1781   return (node == 0 ? defaultValue : node->getLongValue());
1782 }
1783
1784
1785 /**
1786  * Get a float value for another node.
1787  */
1788 float
1789 SGPropertyNode::getFloatValue (const char * relative_path,
1790                                float defaultValue) const
1791 {
1792   const SGPropertyNode * node = getNode(relative_path);
1793   return (node == 0 ? defaultValue : node->getFloatValue());
1794 }
1795
1796
1797 /**
1798  * Get a double value for another node.
1799  */
1800 double
1801 SGPropertyNode::getDoubleValue (const char * relative_path,
1802                                 double defaultValue) const
1803 {
1804   const SGPropertyNode * node = getNode(relative_path);
1805   return (node == 0 ? defaultValue : node->getDoubleValue());
1806 }
1807
1808
1809 /**
1810  * Get a string value for another node.
1811  */
1812 const char *
1813 SGPropertyNode::getStringValue (const char * relative_path,
1814                                 const char * defaultValue) const
1815 {
1816   const SGPropertyNode * node = getNode(relative_path);
1817   return (node == 0 ? defaultValue : node->getStringValue());
1818 }
1819
1820
1821 /**
1822  * Set a bool value for another node.
1823  */
1824 bool
1825 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1826 {
1827   return getNode(relative_path, true)->setBoolValue(value);
1828 }
1829
1830
1831 /**
1832  * Set an int value for another node.
1833  */
1834 bool
1835 SGPropertyNode::setIntValue (const char * relative_path, int value)
1836 {
1837   return getNode(relative_path, true)->setIntValue(value);
1838 }
1839
1840
1841 /**
1842  * Set a long value for another node.
1843  */
1844 bool
1845 SGPropertyNode::setLongValue (const char * relative_path, long value)
1846 {
1847   return getNode(relative_path, true)->setLongValue(value);
1848 }
1849
1850
1851 /**
1852  * Set a float value for another node.
1853  */
1854 bool
1855 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1856 {
1857   return getNode(relative_path, true)->setFloatValue(value);
1858 }
1859
1860
1861 /**
1862  * Set a double value for another node.
1863  */
1864 bool
1865 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1866 {
1867   return getNode(relative_path, true)->setDoubleValue(value);
1868 }
1869
1870
1871 /**
1872  * Set a string value for another node.
1873  */
1874 bool
1875 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1876 {
1877   return getNode(relative_path, true)->setStringValue(value);
1878 }
1879
1880
1881 /**
1882  * Set an unknown value for another node.
1883  */
1884 bool
1885 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1886                                      const char * value)
1887 {
1888   return getNode(relative_path, true)->setUnspecifiedValue(value);
1889 }
1890
1891
1892 /**
1893  * Test whether another node is tied.
1894  */
1895 bool
1896 SGPropertyNode::isTied (const char * relative_path) const
1897 {
1898   const SGPropertyNode * node = getNode(relative_path);
1899   return (node == 0 ? false : node->isTied());
1900 }
1901
1902
1903 /**
1904  * Tie a node reached by a relative path, creating it if necessary.
1905  */
1906 bool
1907 SGPropertyNode::tie (const char * relative_path,
1908                      const SGRawValue<bool> &rawValue,
1909                      bool useDefault)
1910 {
1911   return getNode(relative_path, true)->tie(rawValue, useDefault);
1912 }
1913
1914
1915 /**
1916  * Tie a node reached by a relative path, creating it if necessary.
1917  */
1918 bool
1919 SGPropertyNode::tie (const char * relative_path,
1920                      const SGRawValue<int> &rawValue,
1921                      bool useDefault)
1922 {
1923   return getNode(relative_path, true)->tie(rawValue, useDefault);
1924 }
1925
1926
1927 /**
1928  * Tie a node reached by a relative path, creating it if necessary.
1929  */
1930 bool
1931 SGPropertyNode::tie (const char * relative_path,
1932                      const SGRawValue<long> &rawValue,
1933                      bool useDefault)
1934 {
1935   return getNode(relative_path, true)->tie(rawValue, useDefault);
1936 }
1937
1938
1939 /**
1940  * Tie a node reached by a relative path, creating it if necessary.
1941  */
1942 bool
1943 SGPropertyNode::tie (const char * relative_path,
1944                      const SGRawValue<float> &rawValue,
1945                      bool useDefault)
1946 {
1947   return getNode(relative_path, true)->tie(rawValue, useDefault);
1948 }
1949
1950
1951 /**
1952  * Tie a node reached by a relative path, creating it if necessary.
1953  */
1954 bool
1955 SGPropertyNode::tie (const char * relative_path,
1956                      const SGRawValue<double> &rawValue,
1957                      bool useDefault)
1958 {
1959   return getNode(relative_path, true)->tie(rawValue, useDefault);
1960 }
1961
1962
1963 /**
1964  * Tie a node reached by a relative path, creating it if necessary.
1965  */
1966 bool
1967 SGPropertyNode::tie (const char * relative_path,
1968                      const SGRawValue<const char *> &rawValue,
1969                      bool useDefault)
1970 {
1971   return getNode(relative_path, true)->tie(rawValue, useDefault);
1972 }
1973
1974
1975 /**
1976  * Attempt to untie another node reached by a relative path.
1977  */
1978 bool
1979 SGPropertyNode::untie (const char * relative_path)
1980 {
1981   SGPropertyNode * node = getNode(relative_path);
1982   return (node == 0 ? false : node->untie());
1983 }
1984
1985 void
1986 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener)
1987 {
1988   if (_listeners == 0)
1989     _listeners = new vector<SGPropertyChangeListener *>;
1990   _listeners->push_back(listener);
1991   listener->register_property(this);
1992 }
1993
1994 void
1995 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
1996 {
1997   vector<SGPropertyChangeListener *>::iterator it =
1998     find(_listeners->begin(), _listeners->end(), listener);
1999   if (it != _listeners->end()) {
2000     _listeners->erase(it);
2001     listener->unregister_property(this);
2002     if (_listeners->empty()) {
2003       vector<SGPropertyChangeListener *> * tmp = _listeners;
2004       _listeners = 0;
2005       delete tmp;
2006     }
2007   }
2008 }
2009
2010 void
2011 SGPropertyNode::fireValueChanged ()
2012 {
2013   fireValueChanged(this);
2014 }
2015
2016 void
2017 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2018 {
2019   fireChildAdded(this, child);
2020 }
2021
2022 void
2023 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2024 {
2025   fireChildRemoved(this, child);
2026 }
2027
2028 void
2029 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2030 {
2031   if (_listeners != 0) {
2032     for (int i = 0; i < _listeners->size(); i++) {
2033       (*_listeners)[i]->valueChanged(node);
2034     }
2035   }
2036   if (_parent != 0)
2037     _parent->fireValueChanged(node);
2038 }
2039
2040 void
2041 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2042                                 SGPropertyNode * child)
2043 {
2044   if (_listeners != 0) {
2045     for (int i = 0; i < _listeners->size(); i++) {
2046       (*_listeners)[i]->childAdded(parent, child);
2047     }
2048   }
2049   if (_parent != 0)
2050     _parent->fireChildAdded(parent, child);
2051 }
2052
2053 void
2054 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2055                                   SGPropertyNode * child)
2056 {
2057   if (_listeners != 0) {
2058     for (int i = 0; i < _listeners->size(); i++) {
2059       (*_listeners)[i]->childRemoved(parent, child);
2060     }
2061   }
2062   if (_parent != 0)
2063     _parent->fireChildRemoved(parent, child);
2064 }
2065
2066
2067 \f
2068 ////////////////////////////////////////////////////////////////////////
2069 // Simplified hash table for caching paths.
2070 ////////////////////////////////////////////////////////////////////////
2071
2072 #define HASH_TABLE_SIZE 199
2073
2074 SGPropertyNode::hash_table::entry::entry ()
2075   : _key(0),
2076     _value(0)
2077 {
2078 }
2079
2080 SGPropertyNode::hash_table::entry::~entry ()
2081 {
2082                                 // Don't delete the value; we don't own
2083                                 // the pointer.
2084   delete [] _key;
2085 }
2086
2087 void
2088 SGPropertyNode::hash_table::entry::set_key (const char * key)
2089 {
2090   _key = copy_string(key);
2091 }
2092
2093 void
2094 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2095 {
2096   _value = value;
2097 }
2098
2099 SGPropertyNode::hash_table::bucket::bucket ()
2100   : _length(0),
2101     _entries(0)
2102 {
2103 }
2104
2105 SGPropertyNode::hash_table::bucket::~bucket ()
2106 {
2107   for (int i = 0; i < _length; i++)
2108     delete _entries[i];
2109 }
2110
2111 SGPropertyNode::hash_table::entry *
2112 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2113 {
2114   int i;
2115   for (i = 0; i < _length; i++) {
2116     if (!strcmp(_entries[i]->get_key(), key))
2117       return _entries[i];
2118   }
2119   if (create) {
2120     entry ** new_entries = new entry*[_length+1];
2121     for (i = 0; i < _length; i++) {
2122       new_entries[i] = _entries[i];
2123     }
2124     delete [] _entries;
2125     _entries = new_entries;
2126     _entries[_length] = new entry;
2127     _entries[_length]->set_key(key);
2128     _length++;
2129     return _entries[_length - 1];
2130   } else {
2131     return 0;
2132   }
2133 }
2134
2135
2136 SGPropertyNode::hash_table::hash_table ()
2137   : _data_length(0),
2138     _data(0)
2139 {
2140 }
2141
2142 SGPropertyNode::hash_table::~hash_table ()
2143 {
2144   for (unsigned int i = 0; i < _data_length; i++)
2145     delete _data[i];
2146 }
2147
2148 SGPropertyNode *
2149 SGPropertyNode::hash_table::get (const char * key)
2150 {
2151   if (_data_length == 0)
2152     return 0;
2153   unsigned int index = hashcode(key) % _data_length;
2154   if (_data[index] == 0)
2155     return 0;
2156   entry * e = _data[index]->get_entry(key);
2157   if (e == 0)
2158     return 0;
2159   else
2160     return e->get_value();
2161 }
2162
2163 void
2164 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2165 {
2166   if (_data_length == 0) {
2167     _data = new bucket*[HASH_TABLE_SIZE];
2168     _data_length = HASH_TABLE_SIZE;
2169     for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2170       _data[i] = 0;
2171   }
2172   unsigned int index = hashcode(key) % _data_length;
2173   if (_data[index] == 0) {
2174     _data[index] = new bucket;
2175   }
2176   entry * e = _data[index]->get_entry(key, true);
2177   e->set_value(value);
2178 }
2179
2180 unsigned int
2181 SGPropertyNode::hash_table::hashcode (const char * key)
2182 {
2183   unsigned int hash = 0;
2184   while (*key != 0) {
2185     hash = 31 * hash + *key;
2186     key++;
2187   }
2188   return hash;
2189 }
2190
2191
2192
2193 /**
2194  * Default constructor
2195  */
2196 SGPropertyNode_ptr::SGPropertyNode_ptr()
2197 {
2198   _ptr = 0;
2199 }
2200
2201 /**
2202  * Copy constructor
2203  */
2204 SGPropertyNode_ptr::SGPropertyNode_ptr( const SGPropertyNode_ptr &r )
2205 {
2206   _ptr = r._ptr;
2207   if (_ptr)
2208      _ptr->incrementRef();
2209 }
2210
2211 /**
2212  * Constructor from a pointer to a node
2213  */
2214 SGPropertyNode_ptr::SGPropertyNode_ptr( SGPropertyNode *p )
2215 {
2216   _ptr = p;
2217   if (_ptr)
2218      _ptr->incrementRef();
2219 }
2220
2221 /**
2222  * Destructor
2223  */
2224 SGPropertyNode_ptr::~SGPropertyNode_ptr()
2225 {
2226   if (_ptr && _ptr->decrementRef() == 0)
2227     delete _ptr;
2228 }
2229
2230 /**
2231  * Assignement operator
2232  */
2233 SGPropertyNode_ptr &
2234 SGPropertyNode_ptr::operator=( const SGPropertyNode_ptr &r )
2235 {
2236   if (_ptr && _ptr->decrementRef() == 0)
2237     delete _ptr;
2238   _ptr = r._ptr;
2239   if (_ptr)
2240      _ptr->incrementRef();
2241
2242   return *this;
2243 }
2244
2245 /**
2246  * Pointer access operator
2247  */
2248 SGPropertyNode *
2249 SGPropertyNode_ptr::operator->()
2250 {
2251   return _ptr;
2252 }
2253
2254 /**
2255  * Pointer access operator (const)
2256  */
2257 const SGPropertyNode *
2258 SGPropertyNode_ptr::operator->() const
2259 {
2260   return _ptr;
2261 }
2262
2263 /**
2264  * Conversion to SGPropertyNode * operator
2265  */
2266 SGPropertyNode_ptr::operator SGPropertyNode *()
2267 {
2268   return _ptr;
2269 }
2270
2271 /**
2272  * Conversion to const SGPropertyNode * operator
2273  */
2274 SGPropertyNode_ptr::operator const SGPropertyNode *() const
2275 {
2276   return _ptr;
2277 }
2278
2279 /**
2280  * Validity test
2281  */
2282 bool 
2283 SGPropertyNode_ptr::valid() const
2284 {
2285   return _ptr != 0;
2286 }
2287
2288
2289 \f
2290 ////////////////////////////////////////////////////////////////////////
2291 // Implementation of SGPropertyChangeListener.
2292 ////////////////////////////////////////////////////////////////////////
2293
2294 SGPropertyChangeListener::~SGPropertyChangeListener ()
2295 {
2296                                 // This will come back and remove
2297                                 // the current item each time.  Is
2298                                 // that OK?
2299   vector<SGPropertyNode *>::iterator it;
2300   for (it = _properties.begin(); it != _properties.end(); it++)
2301     (*it)->removeChangeListener(this);
2302 }
2303
2304 void
2305 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2306 {
2307   // NO-OP
2308 }
2309
2310 void
2311 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2312                                       SGPropertyNode * child)
2313 {
2314   // NO-OP
2315 }
2316
2317 void
2318 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2319                                         SGPropertyNode * child)
2320 {
2321   // NO-OP
2322 }
2323
2324 void
2325 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2326 {
2327   _properties.push_back(node);
2328 }
2329
2330 void
2331 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2332 {
2333   vector<SGPropertyNode *>::iterator it =
2334     find(_properties.begin(), _properties.end(), node);
2335   if (it != _properties.end())
2336     _properties.erase(it);
2337 }
2338
2339
2340 // end of props.cxx