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