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