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