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