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