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