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