]> git.mxchange.org Git - simgear.git/blob - simgear/props/props.cxx
Compile under MSVC 9
[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   : SGReferenced(node),
668     _index(node._index),
669     _name(node._name),
670     _parent(0),                 // don't copy the parent
671     _type(node._type),
672     _tied(node._tied),
673     _attr(node._attr),
674     _listeners(0)               // CHECK!!
675 {
676   _local_val.string_val = 0;
677   _value.val = 0;
678   if (_type == props::NONE)
679     return;
680   if (_type == props::ALIAS) {
681     _value.alias = node._value.alias;
682     get(_value.alias);
683     _tied = false;
684     return;
685   }
686   if (_tied || _type == props::EXTENDED) {
687     _value.val = node._value.val->clone();
688     return;
689   }
690   switch (_type) {
691   case props::BOOL:
692     set_bool(node.get_bool());    
693     break;
694   case props::INT:
695     set_int(node.get_int());
696     break;
697   case props::LONG:
698     set_long(node.get_long());
699     break;
700   case props::FLOAT:
701     set_float(node.get_float());
702     break;
703   case props::DOUBLE:
704     set_double(node.get_double());
705     break;
706   case props::STRING:
707   case props::UNSPECIFIED:
708     set_string(node.get_string());
709     break;
710   default:
711     break;
712   }
713 }
714
715
716 /**
717  * Convenience constructor.
718  */
719 template<typename Itr>
720 SGPropertyNode::SGPropertyNode (Itr begin, Itr end,
721                                 int index,
722                                 SGPropertyNode * parent)
723   : _index(index),
724     _name(begin, end),
725     _parent(parent),
726     _type(props::NONE),
727     _tied(false),
728     _attr(READ|WRITE),
729     _listeners(0)
730 {
731   _local_val.string_val = 0;
732   _value.val = 0;
733   if (!validateName(_name))
734     throw string("plain name expected instead of '") + _name + '\'';
735 }
736
737 SGPropertyNode::SGPropertyNode (const string& name,
738                                 int index,
739                                 SGPropertyNode * parent)
740   : _index(index),
741     _name(name),
742     _parent(parent),
743     _type(props::NONE),
744     _tied(false),
745     _attr(READ|WRITE),
746     _listeners(0)
747 {
748   _local_val.string_val = 0;
749   _value.val = 0;
750   if (!validateName(name))
751     throw string("plain name expected instead of '") + _name + '\'';
752 }
753
754 /**
755  * Destructor.
756  */
757 SGPropertyNode::~SGPropertyNode ()
758 {
759   // zero out all parent pointers, else they might be dangling
760   for (unsigned i = 0; i < _children.size(); ++i)
761     _children[i]->_parent = 0;
762   for (unsigned i = 0; i < _removedChildren.size(); ++i)
763     _removedChildren[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 == 0 || _type == props::ALIAS || _tied)
782     return false;
783   clearValue();
784   get(target);
785   _value.alias = target;
786   _type = props::ALIAS;
787   return true;
788 }
789
790
791 /**
792  * Alias to another node by path.
793  */
794 bool
795 SGPropertyNode::alias (const char * path)
796 {
797   return alias(getNode(path, true));
798 }
799
800
801 /**
802  * Remove an alias.
803  */
804 bool
805 SGPropertyNode::unalias ()
806 {
807   if (_type != props::ALIAS)
808     return false;
809   clearValue();
810   return true;
811 }
812
813
814 /**
815  * Get the target of an alias.
816  */
817 SGPropertyNode *
818 SGPropertyNode::getAliasTarget ()
819 {
820   return (_type == props::ALIAS ? _value.alias : 0);
821 }
822
823
824 const SGPropertyNode *
825 SGPropertyNode::getAliasTarget () const
826 {
827   return (_type == props::ALIAS ? _value.alias : 0);
828 }
829
830 /**
831  * create a non-const child by name after the last node with the same name.
832  */
833 SGPropertyNode *
834 SGPropertyNode::addChild (const char * name)
835 {
836   int pos = find_last_child(name, _children)+1;
837
838   SGPropertyNode_ptr node;
839   node = new SGPropertyNode(name, name + strlen(name), pos, this);
840   _children.push_back(node);
841   fireChildAdded(node);
842   return node;
843 }
844
845
846 /**
847  * Get a non-const child by index.
848  */
849 SGPropertyNode *
850 SGPropertyNode::getChild (int position)
851 {
852   if (position >= 0 && position < nChildren())
853     return _children[position];
854   else
855     return 0;
856 }
857
858
859 /**
860  * Get a const child by index.
861  */
862 const SGPropertyNode *
863 SGPropertyNode::getChild (int position) const
864 {
865   if (position >= 0 && position < nChildren())
866     return _children[position];
867   else
868     return 0;
869 }
870
871
872 /**
873  * Get a non-const child by name and index, creating if necessary.
874  */
875
876 SGPropertyNode *
877 SGPropertyNode::getChild (const char * name, int index, bool create)
878 {
879   return getChildImpl(name, name + strlen(name), index, create);
880 }
881
882 SGPropertyNode *
883 SGPropertyNode::getChild (const string& name, int index, bool create)
884 {
885   SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index,
886                                           create);
887   if (node) {
888       return node;
889     } else if (create) {
890       node = new SGPropertyNode(name, index, this);
891       _children.push_back(node);
892       fireChildAdded(node);
893       return node;
894     } else {
895       return 0;
896     }
897 }
898
899 /**
900  * Get a const child by name and index.
901  */
902 const SGPropertyNode *
903 SGPropertyNode::getChild (const char * name, int index) const
904 {
905   int pos = find_child(name, name + strlen(name), index, _children);
906   if (pos >= 0)
907     return _children[pos];
908   else
909     return 0;
910 }
911
912
913 /**
914  * Get all children with the same name (but different indices).
915  */
916 PropertyList
917 SGPropertyNode::getChildren (const char * name) const
918 {
919   PropertyList children;
920   int max = _children.size();
921
922   for (int i = 0; i < max; i++)
923     if (compare_strings(_children[i]->getName(), name))
924       children.push_back(_children[i]);
925
926   sort(children.begin(), children.end(), CompareIndices());
927   return children;
928 }
929
930
931 /**
932  * Remove child by position.
933  */
934 SGPropertyNode_ptr
935 SGPropertyNode::removeChild (int pos, bool keep)
936 {
937   SGPropertyNode_ptr node;
938   if (pos < 0 || pos >= (int)_children.size())
939     return node;
940
941   PropertyList::iterator it = _children.begin();
942   it += pos;
943   node = _children[pos];
944   _children.erase(it);
945   if (keep) {
946     _removedChildren.push_back(node);
947   }
948
949   node->setAttribute(REMOVED, true);
950   node->clearValue();
951   fireChildRemoved(node);
952   return node;
953 }
954
955
956 /**
957  * Remove a child node
958  */
959 SGPropertyNode_ptr
960 SGPropertyNode::removeChild (const char * name, int index, bool keep)
961 {
962   SGPropertyNode_ptr ret;
963   int pos = find_child(name, name + strlen(name), index, _children);
964   if (pos >= 0)
965     ret = removeChild(pos, keep);
966   return ret;
967 }
968
969
970 /**
971   * Remove all children with the specified name.
972   */
973 PropertyList
974 SGPropertyNode::removeChildren (const char * name, bool keep)
975 {
976   PropertyList children;
977
978   for (int pos = _children.size() - 1; pos >= 0; pos--)
979     if (compare_strings(_children[pos]->getName(), name))
980       children.push_back(removeChild(pos, keep));
981
982   sort(children.begin(), children.end(), CompareIndices());
983   return children;
984 }
985
986 string
987 SGPropertyNode::getDisplayName (bool simplify) const
988 {
989   string display_name = _name;
990   if (_index != 0 || !simplify) {
991     stringstream sstr;
992     sstr << '[' << _index << ']';
993     display_name += sstr.str();
994   }
995   return display_name;
996 }
997
998 string
999 SGPropertyNode::getPath (bool simplify) const
1000 {
1001   typedef std::vector<SGConstPropertyNode_ptr> PList;
1002   PList pathList;
1003   for (const SGPropertyNode* node = this; node->_parent; node = node->_parent)
1004     pathList.push_back(node);
1005   string result;
1006   for (PList::reverse_iterator itr = pathList.rbegin(),
1007          rend = pathList.rend();
1008        itr != rend;
1009        ++itr) {
1010     result += '/';
1011     result += (*itr)->getDisplayName(simplify);
1012   }
1013   return result;
1014 }
1015
1016 props::Type
1017 SGPropertyNode::getType () const
1018 {
1019   if (_type == props::ALIAS)
1020     return _value.alias->getType();
1021   else if (_type == props::EXTENDED)
1022       return _value.val->getType();
1023   else
1024     return _type;
1025 }
1026
1027
1028 bool 
1029 SGPropertyNode::getBoolValue () const
1030 {
1031                                 // Shortcut for common case
1032   if (_attr == (READ|WRITE) && _type == props::BOOL)
1033     return get_bool();
1034
1035   if (getAttribute(TRACE_READ))
1036     trace_read();
1037   if (!getAttribute(READ))
1038     return SGRawValue<bool>::DefaultValue();
1039   switch (_type) {
1040   case props::ALIAS:
1041     return _value.alias->getBoolValue();
1042   case props::BOOL:
1043     return get_bool();
1044   case props::INT:
1045     return get_int() == 0 ? false : true;
1046   case props::LONG:
1047     return get_long() == 0L ? false : true;
1048   case props::FLOAT:
1049     return get_float() == 0.0 ? false : true;
1050   case props::DOUBLE:
1051     return get_double() == 0.0L ? false : true;
1052   case props::STRING:
1053   case props::UNSPECIFIED:
1054     return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1055   case props::NONE:
1056   default:
1057     return SGRawValue<bool>::DefaultValue();
1058   }
1059 }
1060
1061 int 
1062 SGPropertyNode::getIntValue () const
1063 {
1064                                 // Shortcut for common case
1065   if (_attr == (READ|WRITE) && _type == props::INT)
1066     return get_int();
1067
1068   if (getAttribute(TRACE_READ))
1069     trace_read();
1070   if (!getAttribute(READ))
1071     return SGRawValue<int>::DefaultValue();
1072   switch (_type) {
1073   case props::ALIAS:
1074     return _value.alias->getIntValue();
1075   case props::BOOL:
1076     return int(get_bool());
1077   case props::INT:
1078     return get_int();
1079   case props::LONG:
1080     return int(get_long());
1081   case props::FLOAT:
1082     return int(get_float());
1083   case props::DOUBLE:
1084     return int(get_double());
1085   case props::STRING:
1086   case props::UNSPECIFIED:
1087     return atoi(get_string());
1088   case props::NONE:
1089   default:
1090     return SGRawValue<int>::DefaultValue();
1091   }
1092 }
1093
1094 long 
1095 SGPropertyNode::getLongValue () const
1096 {
1097                                 // Shortcut for common case
1098   if (_attr == (READ|WRITE) && _type == props::LONG)
1099     return get_long();
1100
1101   if (getAttribute(TRACE_READ))
1102     trace_read();
1103   if (!getAttribute(READ))
1104     return SGRawValue<long>::DefaultValue();
1105   switch (_type) {
1106   case props::ALIAS:
1107     return _value.alias->getLongValue();
1108   case props::BOOL:
1109     return long(get_bool());
1110   case props::INT:
1111     return long(get_int());
1112   case props::LONG:
1113     return get_long();
1114   case props::FLOAT:
1115     return long(get_float());
1116   case props::DOUBLE:
1117     return long(get_double());
1118   case props::STRING:
1119   case props::UNSPECIFIED:
1120     return strtol(get_string(), 0, 0);
1121   case props::NONE:
1122   default:
1123     return SGRawValue<long>::DefaultValue();
1124   }
1125 }
1126
1127 float 
1128 SGPropertyNode::getFloatValue () const
1129 {
1130                                 // Shortcut for common case
1131   if (_attr == (READ|WRITE) && _type == props::FLOAT)
1132     return get_float();
1133
1134   if (getAttribute(TRACE_READ))
1135     trace_read();
1136   if (!getAttribute(READ))
1137     return SGRawValue<float>::DefaultValue();
1138   switch (_type) {
1139   case props::ALIAS:
1140     return _value.alias->getFloatValue();
1141   case props::BOOL:
1142     return float(get_bool());
1143   case props::INT:
1144     return float(get_int());
1145   case props::LONG:
1146     return float(get_long());
1147   case props::FLOAT:
1148     return get_float();
1149   case props::DOUBLE:
1150     return float(get_double());
1151   case props::STRING:
1152   case props::UNSPECIFIED:
1153     return atof(get_string());
1154   case props::NONE:
1155   default:
1156     return SGRawValue<float>::DefaultValue();
1157   }
1158 }
1159
1160 double 
1161 SGPropertyNode::getDoubleValue () const
1162 {
1163                                 // Shortcut for common case
1164   if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1165     return get_double();
1166
1167   if (getAttribute(TRACE_READ))
1168     trace_read();
1169   if (!getAttribute(READ))
1170     return SGRawValue<double>::DefaultValue();
1171
1172   switch (_type) {
1173   case props::ALIAS:
1174     return _value.alias->getDoubleValue();
1175   case props::BOOL:
1176     return double(get_bool());
1177   case props::INT:
1178     return double(get_int());
1179   case props::LONG:
1180     return double(get_long());
1181   case props::FLOAT:
1182     return double(get_float());
1183   case props::DOUBLE:
1184     return get_double();
1185   case props::STRING:
1186   case props::UNSPECIFIED:
1187     return strtod(get_string(), 0);
1188   case props::NONE:
1189   default:
1190     return SGRawValue<double>::DefaultValue();
1191   }
1192 }
1193
1194 const char *
1195 SGPropertyNode::getStringValue () const
1196 {
1197                                 // Shortcut for common case
1198   if (_attr == (READ|WRITE) && _type == props::STRING)
1199     return get_string();
1200
1201   if (getAttribute(TRACE_READ))
1202     trace_read();
1203   if (!getAttribute(READ))
1204     return SGRawValue<const char *>::DefaultValue();
1205   return make_string();
1206 }
1207
1208 bool
1209 SGPropertyNode::setBoolValue (bool value)
1210 {
1211                                 // Shortcut for common case
1212   if (_attr == (READ|WRITE) && _type == props::BOOL)
1213     return set_bool(value);
1214
1215   bool result = false;
1216   TEST_WRITE;
1217   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1218     clearValue();
1219     _tied = false;
1220     _type = props::BOOL;
1221   }
1222
1223   switch (_type) {
1224   case props::ALIAS:
1225     result = _value.alias->setBoolValue(value);
1226     break;
1227   case props::BOOL:
1228     result = set_bool(value);
1229     break;
1230   case props::INT:
1231     result = set_int(int(value));
1232     break;
1233   case props::LONG:
1234     result = set_long(long(value));
1235     break;
1236   case props::FLOAT:
1237     result = set_float(float(value));
1238     break;
1239   case props::DOUBLE:
1240     result = set_double(double(value));
1241     break;
1242   case props::STRING:
1243   case props::UNSPECIFIED:
1244     result = set_string(value ? "true" : "false");
1245     break;
1246   case props::NONE:
1247   default:
1248     break;
1249   }
1250
1251   if (getAttribute(TRACE_WRITE))
1252     trace_write();
1253   return result;
1254 }
1255
1256 bool
1257 SGPropertyNode::setIntValue (int value)
1258 {
1259                                 // Shortcut for common case
1260   if (_attr == (READ|WRITE) && _type == props::INT)
1261     return set_int(value);
1262
1263   bool result = false;
1264   TEST_WRITE;
1265   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1266     clearValue();
1267     _type = props::INT;
1268     _local_val.int_val = 0;
1269   }
1270
1271   switch (_type) {
1272   case props::ALIAS:
1273     result = _value.alias->setIntValue(value);
1274     break;
1275   case props::BOOL:
1276     result = set_bool(value == 0 ? false : true);
1277     break;
1278   case props::INT:
1279     result = set_int(value);
1280     break;
1281   case props::LONG:
1282     result = set_long(long(value));
1283     break;
1284   case props::FLOAT:
1285     result = set_float(float(value));
1286     break;
1287   case props::DOUBLE:
1288     result = set_double(double(value));
1289     break;
1290   case props::STRING:
1291   case props::UNSPECIFIED: {
1292     char buf[128];
1293     sprintf(buf, "%d", value);
1294     result = set_string(buf);
1295     break;
1296   }
1297   case props::NONE:
1298   default:
1299     break;
1300   }
1301
1302   if (getAttribute(TRACE_WRITE))
1303     trace_write();
1304   return result;
1305 }
1306
1307 bool
1308 SGPropertyNode::setLongValue (long value)
1309 {
1310                                 // Shortcut for common case
1311   if (_attr == (READ|WRITE) && _type == props::LONG)
1312     return set_long(value);
1313
1314   bool result = false;
1315   TEST_WRITE;
1316   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1317     clearValue();
1318     _type = props::LONG;
1319     _local_val.long_val = 0L;
1320   }
1321
1322   switch (_type) {
1323   case props::ALIAS:
1324     result = _value.alias->setLongValue(value);
1325     break;
1326   case props::BOOL:
1327     result = set_bool(value == 0L ? false : true);
1328     break;
1329   case props::INT:
1330     result = set_int(int(value));
1331     break;
1332   case props::LONG:
1333     result = set_long(value);
1334     break;
1335   case props::FLOAT:
1336     result = set_float(float(value));
1337     break;
1338   case props::DOUBLE:
1339     result = set_double(double(value));
1340     break;
1341   case props::STRING:
1342   case props::UNSPECIFIED: {
1343     char buf[128];
1344     sprintf(buf, "%ld", value);
1345     result = set_string(buf);
1346     break;
1347   }
1348   case props::NONE:
1349   default:
1350     break;
1351   }
1352
1353   if (getAttribute(TRACE_WRITE))
1354     trace_write();
1355   return result;
1356 }
1357
1358 bool
1359 SGPropertyNode::setFloatValue (float value)
1360 {
1361                                 // Shortcut for common case
1362   if (_attr == (READ|WRITE) && _type == props::FLOAT)
1363     return set_float(value);
1364
1365   bool result = false;
1366   TEST_WRITE;
1367   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1368     clearValue();
1369     _type = props::FLOAT;
1370     _local_val.float_val = 0;
1371   }
1372
1373   switch (_type) {
1374   case props::ALIAS:
1375     result = _value.alias->setFloatValue(value);
1376     break;
1377   case props::BOOL:
1378     result = set_bool(value == 0.0 ? false : true);
1379     break;
1380   case props::INT:
1381     result = set_int(int(value));
1382     break;
1383   case props::LONG:
1384     result = set_long(long(value));
1385     break;
1386   case props::FLOAT:
1387     result = set_float(value);
1388     break;
1389   case props::DOUBLE:
1390     result = set_double(double(value));
1391     break;
1392   case props::STRING:
1393   case props::UNSPECIFIED: {
1394     char buf[128];
1395     sprintf(buf, "%f", value);
1396     result = set_string(buf);
1397     break;
1398   }
1399   case props::NONE:
1400   default:
1401     break;
1402   }
1403
1404   if (getAttribute(TRACE_WRITE))
1405     trace_write();
1406   return result;
1407 }
1408
1409 bool
1410 SGPropertyNode::setDoubleValue (double value)
1411 {
1412                                 // Shortcut for common case
1413   if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1414     return set_double(value);
1415
1416   bool result = false;
1417   TEST_WRITE;
1418   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1419     clearValue();
1420     _local_val.double_val = value;
1421     _type = props::DOUBLE;
1422   }
1423
1424   switch (_type) {
1425   case props::ALIAS:
1426     result = _value.alias->setDoubleValue(value);
1427     break;
1428   case props::BOOL:
1429     result = set_bool(value == 0.0L ? false : true);
1430     break;
1431   case props::INT:
1432     result = set_int(int(value));
1433     break;
1434   case props::LONG:
1435     result = set_long(long(value));
1436     break;
1437   case props::FLOAT:
1438     result = set_float(float(value));
1439     break;
1440   case props::DOUBLE:
1441     result = set_double(value);
1442     break;
1443   case props::STRING:
1444   case props::UNSPECIFIED: {
1445     char buf[128];
1446     sprintf(buf, "%f", value);
1447     result = set_string(buf);
1448     break;
1449   }
1450   case props::NONE:
1451   default:
1452     break;
1453   }
1454
1455   if (getAttribute(TRACE_WRITE))
1456     trace_write();
1457   return result;
1458 }
1459
1460 bool
1461 SGPropertyNode::setStringValue (const char * value)
1462 {
1463                                 // Shortcut for common case
1464   if (_attr == (READ|WRITE) && _type == props::STRING)
1465     return set_string(value);
1466
1467   bool result = false;
1468   TEST_WRITE;
1469   if (_type == props::NONE || _type == props::UNSPECIFIED) {
1470     clearValue();
1471     _type = props::STRING;
1472   }
1473
1474   switch (_type) {
1475   case props::ALIAS:
1476     result = _value.alias->setStringValue(value);
1477     break;
1478   case props::BOOL:
1479     result = set_bool((compare_strings(value, "true")
1480                        || atoi(value)) ? true : false);
1481     break;
1482   case props::INT:
1483     result = set_int(atoi(value));
1484     break;
1485   case props::LONG:
1486     result = set_long(strtol(value, 0, 0));
1487     break;
1488   case props::FLOAT:
1489     result = set_float(atof(value));
1490     break;
1491   case props::DOUBLE:
1492     result = set_double(strtod(value, 0));
1493     break;
1494   case props::STRING:
1495   case props::UNSPECIFIED:
1496     result = set_string(value);
1497     break;
1498   case props::EXTENDED:
1499   {
1500     stringstream sstr(value);
1501     static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1502   }
1503   break;
1504   case props::NONE:
1505   default:
1506     break;
1507   }
1508
1509   if (getAttribute(TRACE_WRITE))
1510     trace_write();
1511   return result;
1512 }
1513
1514 bool
1515 SGPropertyNode::setUnspecifiedValue (const char * value)
1516 {
1517   bool result = false;
1518   TEST_WRITE;
1519   if (_type == props::NONE) {
1520     clearValue();
1521     _type = props::UNSPECIFIED;
1522   }
1523   props::Type type = _type;
1524   if (type == props::EXTENDED)
1525       type = _value.val->getType();
1526   switch (type) {
1527   case props::ALIAS:
1528     result = _value.alias->setUnspecifiedValue(value);
1529     break;
1530   case props::BOOL:
1531     result = set_bool((compare_strings(value, "true")
1532                        || atoi(value)) ? true : false);
1533     break;
1534   case props::INT:
1535     result = set_int(atoi(value));
1536     break;
1537   case props::LONG:
1538     result = set_long(strtol(value, 0, 0));
1539     break;
1540   case props::FLOAT:
1541     result = set_float(atof(value));
1542     break;
1543   case props::DOUBLE:
1544     result = set_double(strtod(value, 0));
1545     break;
1546   case props::STRING:
1547   case props::UNSPECIFIED:
1548     result = set_string(value);
1549     break;
1550   case props::VEC3D:
1551       result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1552       break;
1553   case props::VEC4D:
1554       result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1555       break;
1556   case props::NONE:
1557   default:
1558     break;
1559   }
1560
1561   if (getAttribute(TRACE_WRITE))
1562     trace_write();
1563   return result;
1564 }
1565
1566 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1567 {
1568     if (!getAttribute(READ))
1569         return stream;
1570     switch (_type) {
1571     case props::ALIAS:
1572         return _value.alias->printOn(stream);
1573     case props::BOOL:
1574         stream << (get_bool() ? "true" : "false");
1575         break;
1576     case props::INT:
1577         stream << get_int();
1578         break;
1579     case props::LONG:
1580         stream << get_long();
1581         break;
1582     case props::FLOAT:
1583         stream << get_float();
1584         break;
1585     case props::DOUBLE:
1586         stream << get_double();
1587         break;
1588     case props::STRING:
1589     case props::UNSPECIFIED:
1590         stream << get_string();
1591         break;
1592     case props::EXTENDED:
1593         static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1594         break;
1595     case props::NONE:
1596         break;
1597     default: // avoid compiler warning
1598         break;
1599     }
1600     return stream;
1601 }
1602
1603 template<>
1604 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1605                           bool useDefault)
1606 {
1607     if (_type == props::ALIAS || _tied)
1608         return false;
1609
1610     useDefault = useDefault && hasValue();
1611     std::string old_val;
1612     if (useDefault)
1613         old_val = getStringValue();
1614     clearValue();
1615     _type = props::STRING;
1616     _tied = true;
1617     _value.val = rawValue.clone();
1618
1619     if (useDefault) {
1620         int save_attributes = getAttributes();
1621         setAttribute( WRITE, true );
1622         setStringValue(old_val.c_str());
1623         setAttributes( save_attributes );
1624     }
1625
1626     return true;
1627 }
1628 bool
1629 SGPropertyNode::untie ()
1630 {
1631   if (!_tied)
1632     return false;
1633
1634   switch (_type) {
1635   case props::BOOL: {
1636     bool val = getBoolValue();
1637     clearValue();
1638     _type = props::BOOL;
1639     _local_val.bool_val = val;
1640     break;
1641   }
1642   case props::INT: {
1643     int val = getIntValue();
1644     clearValue();
1645     _type = props::INT;
1646     _local_val.int_val = val;
1647     break;
1648   }
1649   case props::LONG: {
1650     long val = getLongValue();
1651     clearValue();
1652     _type = props::LONG;
1653     _local_val.long_val = val;
1654     break;
1655   }
1656   case props::FLOAT: {
1657     float val = getFloatValue();
1658     clearValue();
1659     _type = props::FLOAT;
1660     _local_val.float_val = val;
1661     break;
1662   }
1663   case props::DOUBLE: {
1664     double val = getDoubleValue();
1665     clearValue();
1666     _type = props::DOUBLE;
1667     _local_val.double_val = val;
1668     break;
1669   }
1670   case props::STRING:
1671   case props::UNSPECIFIED: {
1672     string val = getStringValue();
1673     clearValue();
1674     _type = props::STRING;
1675     _local_val.string_val = copy_string(val.c_str());
1676     break;
1677   }
1678   case props::EXTENDED: {
1679     SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1680     _value.val = 0;             // Prevent clearValue() from deleting
1681     clearValue();
1682     _type = props::EXTENDED;
1683     _value.val = val->makeContainer();
1684     delete val;
1685     break;
1686   }
1687   case props::NONE:
1688   default:
1689     break;
1690   }
1691
1692   _tied = false;
1693   return true;
1694 }
1695
1696 SGPropertyNode *
1697 SGPropertyNode::getRootNode ()
1698 {
1699   if (_parent == 0)
1700     return this;
1701   else
1702     return _parent->getRootNode();
1703 }
1704
1705 const SGPropertyNode *
1706 SGPropertyNode::getRootNode () const
1707 {
1708   if (_parent == 0)
1709     return this;
1710   else
1711     return _parent->getRootNode();
1712 }
1713
1714 SGPropertyNode *
1715 SGPropertyNode::getNode (const char * relative_path, bool create)
1716 {
1717   using namespace boost;
1718
1719   return find_node(this, make_iterator_range(relative_path, relative_path
1720                                              + strlen(relative_path)),
1721                    create);
1722 }
1723
1724 SGPropertyNode *
1725 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1726 {
1727   using namespace boost;
1728   return find_node(this, make_iterator_range(relative_path, relative_path
1729                                              + strlen(relative_path)),
1730                    create, index);
1731 }
1732
1733 const SGPropertyNode *
1734 SGPropertyNode::getNode (const char * relative_path) const
1735 {
1736   return ((SGPropertyNode *)this)->getNode(relative_path, false);
1737 }
1738
1739 const SGPropertyNode *
1740 SGPropertyNode::getNode (const char * relative_path, int index) const
1741 {
1742   return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1743 }
1744
1745 \f
1746 ////////////////////////////////////////////////////////////////////////
1747 // Convenience methods using relative paths.
1748 ////////////////////////////////////////////////////////////////////////
1749
1750
1751 /**
1752  * Test whether another node has a value attached.
1753  */
1754 bool
1755 SGPropertyNode::hasValue (const char * relative_path) const
1756 {
1757   const SGPropertyNode * node = getNode(relative_path);
1758   return (node == 0 ? false : node->hasValue());
1759 }
1760
1761
1762 /**
1763  * Get the value type for another node.
1764  */
1765 props::Type
1766 SGPropertyNode::getType (const char * relative_path) const
1767 {
1768   const SGPropertyNode * node = getNode(relative_path);
1769   return (node == 0 ? props::UNSPECIFIED : node->getType());
1770 }
1771
1772
1773 /**
1774  * Get a bool value for another node.
1775  */
1776 bool
1777 SGPropertyNode::getBoolValue (const char * relative_path,
1778                               bool defaultValue) const
1779 {
1780   const SGPropertyNode * node = getNode(relative_path);
1781   return (node == 0 ? defaultValue : node->getBoolValue());
1782 }
1783
1784
1785 /**
1786  * Get an int value for another node.
1787  */
1788 int
1789 SGPropertyNode::getIntValue (const char * relative_path,
1790                              int defaultValue) const
1791 {
1792   const SGPropertyNode * node = getNode(relative_path);
1793   return (node == 0 ? defaultValue : node->getIntValue());
1794 }
1795
1796
1797 /**
1798  * Get a long value for another node.
1799  */
1800 long
1801 SGPropertyNode::getLongValue (const char * relative_path,
1802                               long defaultValue) const
1803 {
1804   const SGPropertyNode * node = getNode(relative_path);
1805   return (node == 0 ? defaultValue : node->getLongValue());
1806 }
1807
1808
1809 /**
1810  * Get a float value for another node.
1811  */
1812 float
1813 SGPropertyNode::getFloatValue (const char * relative_path,
1814                                float defaultValue) const
1815 {
1816   const SGPropertyNode * node = getNode(relative_path);
1817   return (node == 0 ? defaultValue : node->getFloatValue());
1818 }
1819
1820
1821 /**
1822  * Get a double value for another node.
1823  */
1824 double
1825 SGPropertyNode::getDoubleValue (const char * relative_path,
1826                                 double defaultValue) const
1827 {
1828   const SGPropertyNode * node = getNode(relative_path);
1829   return (node == 0 ? defaultValue : node->getDoubleValue());
1830 }
1831
1832
1833 /**
1834  * Get a string value for another node.
1835  */
1836 const char *
1837 SGPropertyNode::getStringValue (const char * relative_path,
1838                                 const char * defaultValue) const
1839 {
1840   const SGPropertyNode * node = getNode(relative_path);
1841   return (node == 0 ? defaultValue : node->getStringValue());
1842 }
1843
1844
1845 /**
1846  * Set a bool value for another node.
1847  */
1848 bool
1849 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1850 {
1851   return getNode(relative_path, true)->setBoolValue(value);
1852 }
1853
1854
1855 /**
1856  * Set an int value for another node.
1857  */
1858 bool
1859 SGPropertyNode::setIntValue (const char * relative_path, int value)
1860 {
1861   return getNode(relative_path, true)->setIntValue(value);
1862 }
1863
1864
1865 /**
1866  * Set a long value for another node.
1867  */
1868 bool
1869 SGPropertyNode::setLongValue (const char * relative_path, long value)
1870 {
1871   return getNode(relative_path, true)->setLongValue(value);
1872 }
1873
1874
1875 /**
1876  * Set a float value for another node.
1877  */
1878 bool
1879 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1880 {
1881   return getNode(relative_path, true)->setFloatValue(value);
1882 }
1883
1884
1885 /**
1886  * Set a double value for another node.
1887  */
1888 bool
1889 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1890 {
1891   return getNode(relative_path, true)->setDoubleValue(value);
1892 }
1893
1894
1895 /**
1896  * Set a string value for another node.
1897  */
1898 bool
1899 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1900 {
1901   return getNode(relative_path, true)->setStringValue(value);
1902 }
1903
1904
1905 /**
1906  * Set an unknown value for another node.
1907  */
1908 bool
1909 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1910                                      const char * value)
1911 {
1912   return getNode(relative_path, true)->setUnspecifiedValue(value);
1913 }
1914
1915
1916 /**
1917  * Test whether another node is tied.
1918  */
1919 bool
1920 SGPropertyNode::isTied (const char * relative_path) const
1921 {
1922   const SGPropertyNode * node = getNode(relative_path);
1923   return (node == 0 ? false : node->isTied());
1924 }
1925
1926
1927 /**
1928  * Tie a node reached by a relative path, creating it if necessary.
1929  */
1930 bool
1931 SGPropertyNode::tie (const char * relative_path,
1932                      const SGRawValue<bool> &rawValue,
1933                      bool useDefault)
1934 {
1935   return getNode(relative_path, true)->tie(rawValue, useDefault);
1936 }
1937
1938
1939 /**
1940  * Tie a node reached by a relative path, creating it if necessary.
1941  */
1942 bool
1943 SGPropertyNode::tie (const char * relative_path,
1944                      const SGRawValue<int> &rawValue,
1945                      bool useDefault)
1946 {
1947   return getNode(relative_path, true)->tie(rawValue, useDefault);
1948 }
1949
1950
1951 /**
1952  * Tie a node reached by a relative path, creating it if necessary.
1953  */
1954 bool
1955 SGPropertyNode::tie (const char * relative_path,
1956                      const SGRawValue<long> &rawValue,
1957                      bool useDefault)
1958 {
1959   return getNode(relative_path, true)->tie(rawValue, useDefault);
1960 }
1961
1962
1963 /**
1964  * Tie a node reached by a relative path, creating it if necessary.
1965  */
1966 bool
1967 SGPropertyNode::tie (const char * relative_path,
1968                      const SGRawValue<float> &rawValue,
1969                      bool useDefault)
1970 {
1971   return getNode(relative_path, true)->tie(rawValue, useDefault);
1972 }
1973
1974
1975 /**
1976  * Tie a node reached by a relative path, creating it if necessary.
1977  */
1978 bool
1979 SGPropertyNode::tie (const char * relative_path,
1980                      const SGRawValue<double> &rawValue,
1981                      bool useDefault)
1982 {
1983   return getNode(relative_path, true)->tie(rawValue, useDefault);
1984 }
1985
1986
1987 /**
1988  * Tie a node reached by a relative path, creating it if necessary.
1989  */
1990 bool
1991 SGPropertyNode::tie (const char * relative_path,
1992                      const SGRawValue<const char *> &rawValue,
1993                      bool useDefault)
1994 {
1995   return getNode(relative_path, true)->tie(rawValue, useDefault);
1996 }
1997
1998
1999 /**
2000  * Attempt to untie another node reached by a relative path.
2001  */
2002 bool
2003 SGPropertyNode::untie (const char * relative_path)
2004 {
2005   SGPropertyNode * node = getNode(relative_path);
2006   return (node == 0 ? false : node->untie());
2007 }
2008
2009 void
2010 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2011                                    bool initial)
2012 {
2013   if (_listeners == 0)
2014     _listeners = new vector<SGPropertyChangeListener*>;
2015   _listeners->push_back(listener);
2016   listener->register_property(this);
2017   if (initial)
2018     listener->valueChanged(this);
2019 }
2020
2021 void
2022 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2023 {
2024   if (_listeners == 0)
2025     return;
2026   vector<SGPropertyChangeListener*>::iterator it =
2027     find(_listeners->begin(), _listeners->end(), listener);
2028   if (it != _listeners->end()) {
2029     _listeners->erase(it);
2030     listener->unregister_property(this);
2031     if (_listeners->empty()) {
2032       vector<SGPropertyChangeListener*>* tmp = _listeners;
2033       _listeners = 0;
2034       delete tmp;
2035     }
2036   }
2037 }
2038
2039 void
2040 SGPropertyNode::fireValueChanged ()
2041 {
2042   fireValueChanged(this);
2043 }
2044
2045 void
2046 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2047 {
2048   fireChildAdded(this, child);
2049 }
2050
2051 void
2052 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2053 {
2054   fireChildRemoved(this, child);
2055 }
2056
2057 void
2058 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2059 {
2060   if (_listeners != 0) {
2061     for (unsigned int i = 0; i < _listeners->size(); i++) {
2062       (*_listeners)[i]->valueChanged(node);
2063     }
2064   }
2065   if (_parent != 0)
2066     _parent->fireValueChanged(node);
2067 }
2068
2069 void
2070 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2071                                 SGPropertyNode * child)
2072 {
2073   if (_listeners != 0) {
2074     for (unsigned int i = 0; i < _listeners->size(); i++) {
2075       (*_listeners)[i]->childAdded(parent, child);
2076     }
2077   }
2078   if (_parent != 0)
2079     _parent->fireChildAdded(parent, child);
2080 }
2081
2082 void
2083 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2084                                   SGPropertyNode * child)
2085 {
2086   if (_listeners != 0) {
2087     for (unsigned int i = 0; i < _listeners->size(); i++) {
2088       (*_listeners)[i]->childRemoved(parent, child);
2089     }
2090   }
2091   if (_parent != 0)
2092     _parent->fireChildRemoved(parent, child);
2093 }
2094
2095 \f
2096 ////////////////////////////////////////////////////////////////////////
2097 // Implementation of SGPropertyChangeListener.
2098 ////////////////////////////////////////////////////////////////////////
2099
2100 SGPropertyChangeListener::~SGPropertyChangeListener ()
2101 {
2102   for (int i = _properties.size() - 1; i >= 0; i--)
2103     _properties[i]->removeChangeListener(this);
2104 }
2105
2106 void
2107 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2108 {
2109   // NO-OP
2110 }
2111
2112 void
2113 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2114                                       SGPropertyNode * child)
2115 {
2116   // NO-OP
2117 }
2118
2119 void
2120 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2121                                         SGPropertyNode * child)
2122 {
2123   // NO-OP
2124 }
2125
2126 void
2127 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2128 {
2129   _properties.push_back(node);
2130 }
2131
2132 void
2133 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2134 {
2135   vector<SGPropertyNode *>::iterator it =
2136     find(_properties.begin(), _properties.end(), node);
2137   if (it != _properties.end())
2138     _properties.erase(it);
2139 }
2140
2141 template<>
2142 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2143 {
2144     const SGVec3d vec
2145         = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2146     for (int i = 0; i < 3; ++i) {
2147         stream << vec[i];
2148         if (i < 2)
2149             stream << ' ';
2150     }
2151     return stream;
2152 }
2153
2154 namespace simgear
2155 {
2156 template<>
2157 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2158 {
2159     for (int i = 0; i < 3; ++i) {
2160         stream >> result[i];
2161     }
2162     return stream;
2163 }
2164 }
2165 template<>
2166 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2167 {
2168     const SGVec4d vec
2169         = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();    
2170     for (int i = 0; i < 4; ++i) {
2171         stream << vec[i];
2172         if (i < 3)
2173             stream << ' ';
2174     }
2175     return stream;
2176 }
2177
2178 namespace simgear
2179 {
2180 template<>
2181 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2182 {
2183     for (int i = 0; i < 4; ++i) {
2184         stream >> result[i];
2185     }
2186     return stream;
2187 }
2188
2189 namespace
2190 {
2191 bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
2192 {
2193     props::Type ltype = lhs.getType();
2194     props::Type rtype = rhs.getType();
2195     if (ltype != rtype)
2196         return false;
2197     switch (ltype) {
2198     case props::NONE:
2199         return true;
2200     case props::ALIAS:
2201         return false;           // XXX Should we look in aliases?
2202     case props::BOOL:
2203         return lhs.getValue<bool>() == rhs.getValue<bool>();
2204     case props::INT:
2205         return lhs.getValue<int>() == rhs.getValue<int>();
2206     case props::LONG:
2207         return lhs.getValue<long>() == rhs.getValue<long>();
2208     case props::FLOAT:
2209         return lhs.getValue<float>() == rhs.getValue<float>();
2210     case props::DOUBLE:
2211         return lhs.getValue<double>() == rhs.getValue<double>();
2212     case props::STRING:
2213     case props::UNSPECIFIED:
2214         return !strcmp(lhs.getStringValue(), rhs.getStringValue());
2215     case props::VEC3D:
2216         return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
2217     case props::VEC4D:
2218         return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
2219     default:
2220         return false;
2221     }
2222 }
2223 }
2224 }
2225
2226 bool SGPropertyNode::compare(const SGPropertyNode& lhs,
2227                              const SGPropertyNode& rhs)
2228 {
2229     if (&lhs == &rhs)
2230         return true;
2231     int lhsChildren = lhs.nChildren();
2232     int rhsChildren = rhs.nChildren();
2233     if (lhsChildren != rhsChildren)
2234         return false;
2235     if (lhsChildren == 0)
2236         return compareNodeValue(lhs, rhs);
2237     for (size_t i = 0; i < lhs._children.size(); ++i) {
2238         const SGPropertyNode* lchild = lhs._children[i];
2239         const SGPropertyNode* rchild = rhs._children[i];
2240         // I'm guessing that the nodes will usually be in the same
2241         // order.
2242         if (lchild->getIndex() != rchild->getIndex()
2243             || lchild->getNameString() != rchild->getNameString()) {
2244             rchild = 0;
2245             for (PropertyList::const_iterator itr = rhs._children.begin(),
2246                      end = rhs._children.end();
2247                  itr != end;
2248                 ++itr)
2249                 if (lchild->getIndex() == (*itr)->getIndex()
2250                     && lchild->getNameString() == (*itr)->getNameString()) {
2251                     rchild = *itr;
2252                     break;
2253                 }
2254             if (!rchild)
2255                 return false;
2256         }
2257         if (!compare(*lchild, *rchild))
2258             return false;
2259     }
2260     return true;
2261 }
2262
2263 struct PropertyPlaceLess {
2264     typedef bool result_type;
2265     bool operator()(SGPropertyNode_ptr lhs, SGPropertyNode_ptr rhs) const
2266     {
2267         int comp = lhs->getNameString().compare(rhs->getNameString());
2268         if (comp == 0)
2269             return lhs->getIndex() < rhs->getIndex();
2270         else
2271             return comp < 0;
2272     }
2273 };
2274
2275 size_t hash_value(const SGPropertyNode& node)
2276 {
2277     using namespace boost;
2278
2279     if (node.nChildren() == 0) {
2280         switch (node.getType()) {
2281         case props::NONE:
2282             return 0;
2283
2284         case props::BOOL:
2285             return hash_value(node.getValue<bool>());
2286         case props::INT:
2287             return hash_value(node.getValue<int>());
2288         case props::LONG:
2289             return hash_value(node.getValue<long>());
2290         case props::FLOAT:
2291             return hash_value(node.getValue<float>());
2292         case props::DOUBLE:
2293             return hash_value(node.getValue<double>());
2294         case props::STRING:
2295         case props::UNSPECIFIED:
2296         {
2297             const char *val = node.getStringValue();
2298             return hash_range(val, val + strlen(val));
2299         }
2300         case props::VEC3D:
2301         {
2302             const SGVec3d val = node.getValue<SGVec3d>();
2303             return hash_range(&val[0], &val[3]);
2304         }
2305         case props::VEC4D:
2306         {
2307             const SGVec4d val = node.getValue<SGVec4d>();
2308             return hash_range(&val[0], &val[4]);
2309         }
2310         case props::ALIAS:      // XXX Should we look in aliases?
2311         default:
2312             return 0;
2313         }
2314     } else {
2315         size_t seed = 0;
2316         PropertyList children(node._children.begin(), node._children.end());
2317         sort(children.begin(), children.end(), PropertyPlaceLess());
2318         for (PropertyList::const_iterator itr  = children.begin(),
2319                  end = children.end();
2320              itr != end;
2321              ++itr) {
2322             hash_combine(seed, (*itr)->_name);
2323             hash_combine(seed, (*itr)->_index);
2324             hash_combine(seed, hash_value(**itr));
2325         }
2326         return seed;
2327     }
2328 }
2329
2330 // end of props.cxx