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