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