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