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