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