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