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