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