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