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