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