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