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