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