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