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