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