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