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