]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
#includes based off of srcdir rather than builddir.
[simgear.git] / simgear / misc / props.cxx
1 // props.cxx -- implementation of SimGear Property Manager.
2 //
3 // Written by David Megginson - david@megginson.com
4 //
5 // This module is in the PUBLIC DOMAIN.
6 //
7 // This program is distributed in the hope that it will be useful, but
8 // WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 //
11 // See props.html for documentation [replace with URL when available].
12 //
13 // $Id$
14
15 #ifdef HAVE_CONFIG_H
16 #  include <config.h>
17 #endif
18
19 #include <simgear/debug/logstream.hxx>
20
21 #include "props.hxx"
22
23 #include <stdlib.h>
24
25 #include <string>
26
27 using std::string;
28
29 SGPropertyList current_properties;
30
31 static string empty_string;
32
33
34 \f
35 ////////////////////////////////////////////////////////////////////////
36 // Implementation of SGValue.
37 ////////////////////////////////////////////////////////////////////////
38
39
40 /**
41  * Construct a new value.
42  */
43 SGValue::SGValue ()
44   : _type(UNKNOWN), _tied(false)
45 {
46 }
47
48
49 /**
50  * Destroy a value.
51  */
52 SGValue::~SGValue ()
53 {
54 }
55
56
57 /**
58  * Return a raw boolean value (no type coercion).
59  */
60 bool
61 SGValue::getRawBool () const
62 {
63   if (_tied) {
64     if (_value.bool_func.getter != 0)
65       return (*(_value.bool_func.getter))();
66     else
67       return false;
68   } else {
69     return _value.bool_val;
70   }
71 }
72
73
74 /**
75  * Return a raw integer value (no type coercion).
76  */
77 int
78 SGValue::getRawInt () const
79 {
80   if (_tied) {
81     if (_value.int_func.getter != 0)
82       return (*(_value.int_func.getter))();
83     else
84       return 0;
85   } else {
86     return _value.int_val;
87   }
88 }
89
90
91 /**
92  * Return a raw floating-point value (no type coercion).
93  */
94 float
95 SGValue::getRawFloat () const
96 {
97   if (_tied) {
98     if (_value.float_func.getter != 0)
99       return (*(_value.float_func.getter))();
100     else
101       return 0.0;
102   } else {
103     return _value.float_val;
104   }
105 }
106
107
108 /**
109  * Return a raw double-precision floating-point value (no type coercion).
110  */
111 double
112 SGValue::getRawDouble () const
113 {
114   if (_tied) {
115     if (_value.double_func.getter != 0)
116       return (*(_value.double_func.getter))();
117     else
118       return 0.0L;
119   } else {
120     return _value.double_val;
121   }
122 }
123
124
125 /**
126  * Return a raw string value (no type coercion).
127  */
128 const string &
129 SGValue::getRawString () const
130 {
131   if (_tied && _value.string_func.getter != 0)
132     return (*(_value.string_func.getter))();
133   else
134     return string_val;
135 }
136
137
138 /**
139  * Set a raw boolean value (no type coercion).
140  *
141  * Return false if the value could not be set, true otherwise.
142  */
143 bool
144 SGValue::setRawBool (bool value)
145 {
146   if (_tied) {
147     if (_value.bool_func.setter != 0) {
148       (*_value.bool_func.setter)(value);
149       return true;
150     } else {
151       return false;
152     }
153   } else {
154     _value.bool_val = value;
155     return true;
156   }
157 }
158
159
160 /**
161  * Set a raw integer value (no type coercion).
162  *
163  * Return false if the value could not be set, true otherwise.
164  */
165 bool
166 SGValue::setRawInt (int value)
167 {
168   if (_tied) {
169     if (_value.int_func.setter != 0) {
170       (*_value.int_func.setter)(value);
171       return true;
172     } else {
173       return false;
174     }
175   } else {
176     _value.int_val = value;
177     return true;
178   }
179 }
180
181
182 /**
183  * Set a raw floating-point value (no type coercion).
184  *
185  * Return false if the value could not be set, true otherwise.
186  */
187 bool
188 SGValue::setRawFloat (float value)
189 {
190   if (_tied) {
191     if (_value.float_func.setter != 0) {
192       (*_value.float_func.setter)(value);
193       return true;
194     } else {
195       return false;
196     }
197   } else {
198     _value.float_val = value;
199     return true;
200   }
201 }
202
203
204 /**
205  * Set a raw double-precision floating-point value (no type coercion).
206  *
207  * Return false if the value could not be set, true otherwise.
208  */
209 bool
210 SGValue::setRawDouble (double value)
211 {
212   if (_tied) {
213     if (_value.double_func.setter != 0) {
214       (*_value.double_func.setter)(value);
215       return true;
216     } else {
217       return false;
218     }
219   } else {
220     _value.double_val = value;
221     return true;
222   }
223 }
224
225
226 /**
227  * Set a raw string value (no type coercion).
228  *
229  * Return false if the value could not be set, true otherwise.
230  */
231 bool
232 SGValue::setRawString (const string &value)
233 {
234   if (_tied) {
235     if (_value.string_func.setter != 0) {
236       (*_value.string_func.setter)(value);
237       return true;
238     } else {
239       return false;
240     }
241   } else {
242     string_val = value;
243     return true;
244   }
245 }
246
247
248 /**
249  * Get the boolean value of a property.
250  *
251  * If the native type is not boolean, attempt to coerce it.
252  */
253 bool
254 SGValue::getBoolValue () const
255 {
256   switch (_type) {
257   case BOOL:
258     return getRawBool();
259   case INT:
260     return (getRawInt() == 0 ? false : true);
261   case FLOAT:
262     return (getRawFloat() == 0.0 ? false : true);
263   case DOUBLE:
264     return (getRawDouble() == 0.0 ? false : true);
265   case UNKNOWN:
266   case STRING:
267     return ((getRawString() == "false" || getIntValue() == 0) ? false : true);
268   }
269   return false;
270 }
271
272
273 /**
274  * Get the integer value of a property.
275  *
276  * If the native type is not integer, attempt to coerce it.
277  */
278 int
279 SGValue::getIntValue () const
280 {
281   switch (_type) {
282   case BOOL:
283     return getRawBool();
284   case INT:
285     return getRawInt();
286   case FLOAT:
287     return (int)(getRawFloat());
288   case DOUBLE:
289     return (int)(getRawDouble());
290   case UNKNOWN:
291   case STRING:
292     return atoi(getRawString().c_str());
293   }
294   return false;
295 }
296
297
298 /**
299  * Get the floating-point value of a property.
300  *
301  * If the native type is not float, attempt to coerce it.
302  */
303 float
304 SGValue::getFloatValue () const
305 {
306   switch (_type) {
307   case BOOL:
308     return (float)(getRawBool());
309   case INT:
310     return (float)(getRawInt());
311   case FLOAT:
312     return getRawFloat();
313   case DOUBLE:
314     return (float)(getRawDouble());
315   case UNKNOWN:
316   case STRING:
317     return (float)atof(getRawString().c_str());
318   }
319   return false;
320 }
321
322
323 /**
324  * Get the double-precision floating-point value of a property.
325  *
326  * If the native type is not double, attempt to coerce it.
327  */
328 double
329 SGValue::getDoubleValue () const
330 {
331   switch (_type) {
332   case BOOL:
333     return (double)(getRawBool());
334   case INT:
335     return (double)(getRawInt());
336   case FLOAT:
337     return (double)(getRawFloat());
338   case DOUBLE:
339     return getRawDouble();
340   case UNKNOWN:
341   case STRING:
342     return atof(getRawString().c_str());
343   }
344   return false;
345 }
346
347
348 /**
349  * Get the string value of a property.
350  *
351  * If the native type is not string, attempt to coerce it.
352  */
353 const string &
354 SGValue::getStringValue () const
355 {
356   char buf[512];
357   switch (_type) {
358   case BOOL:
359     if (getRawBool())
360       string_val = "true";
361     else
362       string_val = "false";
363     return string_val;
364   case INT:
365     sprintf(buf, "%d", getRawInt());
366     string_val = buf;
367     return string_val;
368   case FLOAT:
369     sprintf(buf, "%f", getRawFloat());
370     string_val = buf;
371     return string_val;
372   case DOUBLE:
373     sprintf(buf, "%f", getRawDouble());
374     string_val = buf;
375     return string_val;
376   case UNKNOWN:
377   case STRING:
378     return getRawString();
379   }
380   return empty_string;
381 }
382
383
384 /**
385  * Set the boolean value and change the type if unknown.
386  *
387  * Returns true on success.
388  */
389 bool
390 SGValue::setBoolValue (bool value)
391 {
392   if (_type == UNKNOWN || _type == BOOL) {
393     _type = BOOL;
394     return setRawBool(value);
395   } else {
396     return false;
397   }
398 }
399
400
401 /**
402  * Set the integer value and change the type if unknown.
403  *
404  * Returns true on success.
405  */
406 bool
407 SGValue::setIntValue (int value)
408 {
409   if (_type == UNKNOWN || _type == INT) {
410     _type = INT;
411     return setRawInt(value);
412   } else {
413     return false;
414   }
415 }
416
417
418 /**
419  * Set the floating-point value and change the type if unknown.
420  *
421  * Returns true on success.
422  */
423 bool
424 SGValue::setFloatValue (float value)
425 {
426   if (_type == UNKNOWN || _type == FLOAT) {
427     _type = FLOAT;
428     return setRawFloat(value);
429   } else {
430     return false;
431   }
432 }
433
434
435 /**
436  * Set the double-precision value and change the type if unknown.
437  *
438  * Returns true on success.
439  */
440 bool
441 SGValue::setDoubleValue (double value)
442 {
443   if (_type == UNKNOWN || _type == DOUBLE) {
444     _type = DOUBLE;
445     return setRawDouble(value);
446   } else {
447     return false;
448   }
449 }
450
451
452 /**
453  * Set the string value and change the type if unknown.
454  *
455  * Returns true on success.
456  */
457 bool
458 SGValue::setStringValue (const string &value)
459 {
460   if (_type == UNKNOWN || _type == STRING) {
461     _type = STRING;
462     return setRawString(value);
463   } else {
464     return false;
465   }
466 }
467
468
469 /**
470  * Set a string value and don't modify the type.
471  *
472  * Returns true on success.
473  */
474 bool
475 SGValue::setUnknownValue (const string &value)
476 {
477   if (_type == UNKNOWN || _type == STRING) {
478     return setRawString(value);
479   } else {
480     return false;
481   }
482 }
483
484
485 /**
486  * Tie a boolean value to external functions.
487  *
488  * If useDefault is true, attempt the assign the current value
489  * (if any) after tying the functions.
490  *
491  * Returns true on success (i.e. the value is not currently tied).
492  */
493 bool
494 SGValue::tieBool (bool_getter getter, bool_setter setter,
495                   bool useDefault)
496 {
497   if (_tied) {
498     return false;
499   } else {
500     if (useDefault && setter && _type != UNKNOWN)
501       (*setter)(getBoolValue());
502     _tied = true;
503     _type = BOOL;
504     _value.bool_func.getter = getter;
505     _value.bool_func.setter = setter;
506     return true;
507   }
508 }
509
510
511 /**
512  * Tie an integer value to external functions.
513  *
514  * If useDefault is true, attempt the assign the current value
515  * (if any) after tying the functions.
516  *
517  * Returns true on success (i.e. the value is not currently tied).
518  */
519 bool
520 SGValue::tieInt (int_getter getter, int_setter setter,
521                  bool useDefault)
522 {
523   if (_tied) {
524     return false;
525   } else {
526     if (useDefault && setter && _type != UNKNOWN)
527       (*setter)(getIntValue());
528     _tied = true;
529     _type = INT;
530     _value.int_func.getter = getter;
531     _value.int_func.setter = setter;
532     return true;
533   }
534 }
535
536
537 /**
538  * Tie a floating-point value to external functions.
539  *
540  * If useDefault is true, attempt the assign the current value
541  * (if any) after tying the functions.
542  *
543  * Returns true on success (i.e. the value is not currently tied).
544  */
545 bool
546 SGValue::tieFloat (float_getter getter, float_setter setter,
547                    bool useDefault)
548 {
549   if (_tied) {
550     return false;
551   } else {
552     if (useDefault && setter && _type != UNKNOWN)
553       (*setter)(getFloatValue());
554     _tied = true;
555     _type = FLOAT;
556     _value.float_func.getter = getter;
557     _value.float_func.setter = setter;
558     return true;
559   }
560 }
561
562
563 /**
564  * Tie a double-precision floating-point value to external functions.
565  *
566  * If useDefault is true, attempt the assign the current value
567  * (if any) after tying the functions.
568  *
569  * Returns true on success (i.e. the value is not currently tied).
570  */
571 bool
572 SGValue::tieDouble (double_getter getter, double_setter setter,
573                     bool useDefault)
574 {
575   if (_tied) {
576     return false;
577   } else {
578     if (useDefault && setter && _type != UNKNOWN)
579       (*setter)(getDoubleValue());
580     _tied = true;
581     _type = DOUBLE;
582     _value.double_func.getter = getter;
583     _value.double_func.setter = setter;
584     return true;
585   }
586 }
587
588
589 /**
590  * Tie a string value to external functions.
591  *
592  * If useDefault is true, attempt the assign the current value
593  * (if any) after tying the functions.
594  *
595  * Returns true on success (i.e. the value is not currently tied).
596  */
597 bool
598 SGValue::tieString (string_getter getter, string_setter setter,
599                     bool useDefault)
600 {
601   if (_tied) {
602     return false;
603   } else {
604     if (useDefault && setter && _type != UNKNOWN)
605       (*setter)(getStringValue());
606     _tied = true;
607     _type = STRING;
608     _value.string_func.getter = getter;
609     _value.string_func.setter = setter;
610     return true;
611   }
612 }
613
614
615 /**
616  * Untie a value from external functions.
617  *
618  * Will always attempt to intialize the internal value from
619  * the getter before untying.
620  *
621  * Returns true on success (i.e. the value had been tied).
622  */
623 bool
624 SGValue::untie ()
625 {
626   if (!_tied)
627     return false;
628
629   switch (_type) {
630   case BOOL: {
631     bool value = getRawBool();
632     _tied = false;
633     setRawBool(value);
634     break;
635   }
636   case INT: {
637     int value = getRawInt();
638     _tied = false;
639     setRawInt(value);
640     break;
641   }
642   case FLOAT: {
643     float value = getRawFloat();
644     _tied = false;
645     setRawFloat(value);
646     break;
647   }
648   case DOUBLE: {
649     double value = getRawDouble();
650     _tied = false;
651     setRawDouble(value);
652     break;
653   }
654   case STRING: {
655     string value = getRawString();
656     _tied = false;
657     setRawString(value);
658     break;
659   }
660   }
661
662   return true;
663 }
664
665
666 \f
667 ////////////////////////////////////////////////////////////////////////
668 // Implementation of SGPropertyList.
669 ////////////////////////////////////////////////////////////////////////
670
671
672 /**
673  * Constructor.
674  */
675 SGPropertyList::SGPropertyList ()
676 {
677 }
678
679
680 /**
681  * Destructor.
682  */
683 SGPropertyList::~SGPropertyList ()
684 {
685 }
686
687
688 /**
689  * Look up the SGValue structure associated with a property.
690  *
691  * Run some basic validity checks on the property name: it must
692  * not be empty, must begin with '/', must never have two '//' in a row,
693  * and must not end with '/'.
694  */
695 SGValue *
696 SGPropertyList::getValue (const string &name, bool create)
697 {
698   const_iterator el = _props.find(name);
699   if (el == _props.end()) {
700     if (!create)
701       return 0;
702     else {
703       FG_LOG(FG_GENERAL, FG_INFO, "Creating new property '" << name << '\'');
704       if (name.size() == 0 ||
705           name[0] != '/' ||
706           name[name.size()-1] == '/' ||
707           name.find("//") != string::npos) {
708         FG_LOG(FG_GENERAL, FG_ALERT, "Illegal property name: '"
709                << name << '\'');
710         return 0;
711       }
712     }
713   }
714   return &(_props[name]);
715 }
716
717
718 /**
719  * Look up a const value (never created).
720  */
721 const SGValue *
722 SGPropertyList::getValue (const string &name) const
723 {
724   value_map::const_iterator el = _props.find(name);
725   if (el == _props.end())
726     return 0;
727   else
728     return &(el->second);
729 }
730
731
732 /**
733  * Extract a boolean from the value.
734  *
735  * Note that this is inefficient for use in a tight loop: it is
736  * better to get the SGValue and query it repeatedly.
737  */
738 bool
739 SGPropertyList::getBoolValue (const string &name, bool defaultValue) const
740 {
741   const SGValue * val = getValue(name);
742   if (val == 0)
743     return defaultValue;
744   else
745     return val->getBoolValue();
746 }
747
748
749 /**
750  * Extract an integer from the value.
751  *
752  * Note that this is inefficient for use in a tight loop: it is
753  * better to get the SGValue and query it repeatedly.
754  */
755 int
756 SGPropertyList::getIntValue (const string &name, int defaultValue) const
757 {
758   const SGValue * val = getValue(name);
759   if (val == 0)
760     return defaultValue;
761   else
762     return val->getIntValue();
763 }
764
765
766 /**
767  * Extract a float from the value.
768  *
769  * Note that this is inefficient for use in a tight loop: it is
770  * better to get the SGValue and query it repeatedly.
771  */
772 float
773 SGPropertyList::getFloatValue (const string &name, float defaultValue) const
774 {
775   const SGValue * val = getValue(name);
776   if (val == 0)
777     return defaultValue;
778   else
779     return val->getFloatValue();
780 }
781
782
783 /**
784  * Extract a double from the value.
785  *
786  * Note that this is inefficient for use in a tight loop: it is
787  * better to get the SGValue and query it repeatedly.
788  */
789 double
790 SGPropertyList::getDoubleValue (const string &name, double defaultValue) const
791 {
792   const SGValue * val = getValue(name);
793   if (val == 0)
794     return defaultValue;
795   else
796     return val->getDoubleValue();
797 }
798
799
800 /**
801  * Extract a string from the value.
802  *
803  * Note that this is inefficient for use in a tight loop: it is
804  * better to save the SGValue and query it repeatedly.
805  */
806 const string &
807 SGPropertyList::getStringValue (const string &name,
808                                 const string &defaultValue) const
809 {
810   const SGValue * val = getValue(name);
811   if (val == 0)
812     return defaultValue;
813   else
814     return val->getStringValue();
815 }
816
817
818 /**
819  * Assign a bool to the value and change the type if unknown.
820  *
821  * Note that this is inefficient for use in a tight loop: it is
822  * better to save the SGValue and modify it repeatedly.
823  *
824  * Returns true on success.
825  */
826 bool
827 SGPropertyList::setBoolValue (const string &name, bool value)
828 {
829   return getValue(name, true)->setBoolValue(value);
830 }
831
832
833 /**
834  * Assign an integer to the value and change the type if unknown.
835  *
836  * Note that this is inefficient for use in a tight loop: it is
837  * better to save the SGValue and modify it repeatedly.
838  *
839  * Returns true on success.
840  */
841 bool
842 SGPropertyList::setIntValue (const string &name, int value)
843 {
844   return getValue(name, true)->setIntValue(value);
845 }
846
847
848 /**
849  * Assign a float to the value and change the type if unknown.
850  *
851  * Note that this is inefficient for use in a tight loop: it is
852  * better to save the SGValue and modify it repeatedly.
853  *
854  * Returns true on success.
855  */
856 bool
857 SGPropertyList::setFloatValue (const string &name, float value)
858 {
859   return getValue(name, true)->setFloatValue(value);
860 }
861
862
863 /**
864  * Assign a double to the value and change the type if unknown.
865  *
866  * Note that this is inefficient for use in a tight loop: it is
867  * better to save the SGValue and modify it repeatedly.
868  *
869  * Returns true on success.
870  */
871 bool
872 SGPropertyList::setDoubleValue (const string &name, double value)
873 {
874   return getValue(name, true)->setDoubleValue(value);
875 }
876
877
878 /**
879  * Assign a string to the value and change the type if unknown.
880  *
881  * Note that this is inefficient for use in a tight loop: it is
882  * better to save the SGValue and modify it repeatedly.
883  *
884  * Returns true on success.
885  */
886 bool
887 SGPropertyList::setStringValue (const string &name, const string &value)
888 {
889   return getValue(name, true)->setStringValue(value);
890 }
891
892
893 /**
894  * Assign a string to the value, but don't change the type.
895  *
896  * Note that this is inefficient for use in a tight loop: it is
897  * better to save the SGValue and modify it repeatedly.
898  *
899  * Returns true on success.
900  */
901 bool
902 SGPropertyList::setUnknownValue (const string &name, const string &value)
903 {
904   return getValue(name, true)->setUnknownValue(value);
905 }
906
907
908 /**
909  * Tie a boolean value to external functions.
910  *
911  * Invokes SGValue::tieBool
912  */
913 bool
914 SGPropertyList::tieBool (const string &name, 
915                          bool_getter getter,
916                          bool_setter setter,
917                          bool useDefault)
918 {
919   FG_LOG(FG_GENERAL, FG_INFO, "Tying bool property '" << name << '\'');
920   return getValue(name, true)->tieBool(getter, setter, useDefault);
921 }
922
923
924 /**
925  * Tie an integer value to external functions.
926  *
927  * Invokes SGValue::tieInt
928  */
929 bool
930 SGPropertyList::tieInt (const string &name, 
931                         int_getter getter,
932                         int_setter setter,
933                         bool useDefault)
934 {
935   FG_LOG(FG_GENERAL, FG_INFO, "Tying int property '" << name << '\'');
936   return getValue(name, true)->tieInt(getter, setter, useDefault);
937 }
938
939
940 /**
941  * Tie a float value to external functions.
942  *
943  * Invokes SGValue::tieFloat
944  */
945 bool
946 SGPropertyList::tieFloat (const string &name, 
947                           float_getter getter,
948                           float_setter setter,
949                           bool useDefault)
950 {
951   FG_LOG(FG_GENERAL, FG_INFO, "Tying float property '" << name << '\'');
952   return getValue(name, true)->tieFloat(getter, setter, useDefault);
953 }
954
955
956 /**
957  * Tie a double value to external functions.
958  *
959  * Invokes SGValue::tieDouble
960  */
961 bool
962 SGPropertyList::tieDouble (const string &name, 
963                            double_getter getter,
964                            double_setter setter,
965                            bool useDefault)
966 {
967   FG_LOG(FG_GENERAL, FG_INFO, "Tying double property '" << name << '\'');
968   return getValue(name, true)->tieDouble(getter, setter, useDefault);
969 }
970
971
972 /**
973  * Tie a string value to external functions.
974  *
975  * Invokes SGValue::tieString
976  */
977 bool
978 SGPropertyList::tieString (const string &name, 
979                            string_getter getter,
980                            string_setter setter,
981                            bool useDefault)
982 {
983   FG_LOG(FG_GENERAL, FG_INFO, "Tying string property '" << name << '\'');
984   return getValue(name, true)->tieString(getter, setter, useDefault);
985 }
986
987
988 /**
989  * Untie a value from external functions.
990  *
991  * Invokes SGValue::untie
992  */
993 bool
994 SGPropertyList::untie (const string &name)
995 {
996   FG_LOG(FG_GENERAL, FG_INFO, "Untying property '" << name << '\'');
997   return getValue(name, true)->untie();
998 }
999
1000
1001 \f
1002 ////////////////////////////////////////////////////////////////////////
1003 // Implementation of SGPropertyNode.
1004 ////////////////////////////////////////////////////////////////////////
1005
1006
1007 /**
1008  * Extract the base name of the next level down from the parent.
1009  *
1010  * The parent must have a '/' appended.  Note that basename may
1011  * be modified even if the test fails.
1012  */
1013 static bool
1014 get_base (const string &parent, const string &child,
1015              string &basename)
1016 {
1017                                 // First, check that the parent name
1018                                 // is a prefix of the child name, and
1019                                 // extract the remainder
1020   if (child.find(parent) != 0)
1021     return false;
1022
1023   basename = child.substr(parent.size());
1024
1025   string::size_type pos = basename.find('/');
1026   if (pos != string::npos) {
1027     basename.resize(pos);
1028   }
1029
1030   if (basename.size() == 0)
1031     return false;
1032   else
1033     return true;
1034 }
1035
1036
1037 /**
1038  * Constructor.
1039  */
1040 SGPropertyNode::SGPropertyNode (const string &path,
1041                                 SGPropertyList * props)
1042   : _props(props), _node(0)
1043 {
1044   setPath(path);
1045 }
1046
1047
1048 /**
1049  * Destructor.
1050  */
1051 SGPropertyNode::~SGPropertyNode ()
1052 {
1053   delete _node;
1054   _node = 0;
1055 }
1056
1057
1058 /**
1059  * Set the path.
1060  *
1061  * Strip the trailing '/', if any.
1062  */
1063 void
1064 SGPropertyNode::setPath (const string &path)
1065 {
1066   _path = path;
1067
1068                                 // Chop the final '/', if present.
1069   if (_path.size() > 0 && _path[_path.size()-1] == '/')
1070     _path.resize(_path.size()-1);
1071 }
1072
1073
1074 /**
1075  * Return the local name of the property.
1076  *
1077  * The local name is just everything after the last slash.
1078  */
1079 const string &
1080 SGPropertyNode::getName () const
1081 {
1082   string::size_type pos = _path.rfind('/');
1083   if (pos != string::npos) {
1084     _name = _path.substr(pos+1);
1085     return _name;
1086   } else {
1087     return empty_string;
1088   }
1089 }
1090
1091
1092 /**
1093  * Return the number of children for the current node.
1094  */
1095 int
1096 SGPropertyNode::size () const
1097 {
1098   if (_props == 0)
1099     return 0;
1100
1101   int s = 0;
1102
1103   string base;
1104   string lastBase;
1105   string pattern = _path;
1106   pattern += '/';
1107
1108   SGPropertyList::const_iterator it = _props->begin();
1109   SGPropertyList::const_iterator end = _props->end();
1110   while (it != end) {
1111     if (get_base(pattern, it->first, base) && base != lastBase) {
1112       s++;
1113       lastBase = base;
1114     }
1115     it++;
1116   }
1117
1118   return s;
1119 }
1120
1121
1122 /**
1123  * Initialize a node to represent this node's parent.
1124  *
1125  * A return value of true means success; otherwise, the node supplied
1126  * is unmodified.
1127  */
1128 SGPropertyNode &
1129 SGPropertyNode::getParent () const
1130 {
1131   if (_node == 0)
1132     _node = new SGPropertyNode();
1133
1134   string::size_type pos = _path.rfind('/');
1135   if (pos != string::npos) {
1136     _node->setPropertyList(_props);
1137     _node->setPath(_path.substr(0, pos-1));
1138   }
1139   return *_node;
1140 }
1141
1142
1143 /**
1144  * Initialize a node to represent this node's nth child.
1145  *
1146  * A return value of true means success; otherwise, the node supplied
1147  * is unmodified.
1148  */
1149 SGPropertyNode &
1150 SGPropertyNode::getChild (int n) const
1151 {
1152   if (_node == 0)
1153     _node = new SGPropertyNode();
1154
1155   if (_props == 0)
1156     return *_node;
1157
1158   int s = 0;
1159   string base;
1160   string lastBase;
1161   string pattern = _path;
1162   pattern += '/';
1163
1164   SGPropertyList::const_iterator it = _props->begin();
1165   SGPropertyList::const_iterator end = _props->end();
1166   while (it != end) {
1167     if (get_base(pattern, it->first, base) && base != lastBase) {
1168       if (s == n) {
1169         _node->setPropertyList(_props);
1170         _node->setPath(_path + string("/") + base);
1171         return *_node;
1172       } else {
1173         s++;
1174         lastBase = base;
1175       }
1176     }
1177     it++;
1178   }
1179
1180   return *_node;
1181 }
1182
1183
1184 /**
1185  * Return a node for an arbitrary subpath.
1186  *
1187  * Never returns 0.
1188  */
1189 SGPropertyNode &
1190 SGPropertyNode::getSubNode (const string &subpath) const
1191 {
1192   if (_node == 0)
1193     _node = new SGPropertyNode();
1194
1195   _node->setPropertyList(_props);
1196   _node->setPath(_path + string("/") + subpath);
1197   return *_node;
1198 }
1199
1200
1201 /**
1202  * Return the value of the current node.
1203  *
1204  * Currently, this does a lookup each time, but we could cache the
1205  * value safely as long as it's non-zero.
1206  *
1207  * Note that this will not create the value if it doesn't already exist.
1208  */
1209 SGValue *
1210 SGPropertyNode::getValue (const string &subpath)
1211 {
1212   if (_props == 0)
1213     return 0;
1214
1215   if (subpath.size() == 0)
1216     return _props->getValue(_path);
1217   else
1218     return _props->getValue(_path + string("/") + subpath);
1219 }
1220
1221
1222 /**
1223  * Return a bool value.
1224  */
1225 bool
1226 SGPropertyNode::getBoolValue (const string &subpath, bool defaultValue) const
1227 {
1228   if (_props == 0)
1229     return defaultValue;
1230
1231   if (subpath == "")
1232     return _props->getBoolValue(_path, defaultValue);
1233   else
1234     return _props->getBoolValue(_path + string("/") + subpath,
1235                                 defaultValue);
1236 }
1237
1238
1239 /**
1240  * Return an int value.
1241  */
1242 int
1243 SGPropertyNode::getIntValue (const string &subpath, int defaultValue) const
1244 {
1245   if (_props == 0)
1246     return defaultValue;
1247
1248   if (subpath == "")
1249     return _props->getIntValue(_path, defaultValue);
1250   else
1251     return _props->getIntValue(_path + string("/") + subpath,
1252                                defaultValue);
1253 }
1254
1255
1256 /**
1257  * Return a float value.
1258  */
1259 float
1260 SGPropertyNode::getFloatValue (const string &subpath, float defaultValue) const
1261 {
1262   if (_props == 0)
1263     return defaultValue;
1264
1265   if (subpath == "")
1266     return _props->getFloatValue(_path, defaultValue);
1267   else
1268     return _props->getFloatValue(_path + string("/") + subpath,
1269                                  defaultValue);
1270 }
1271
1272
1273 /**
1274  * Return a double value.
1275  */
1276 double
1277 SGPropertyNode::getDoubleValue (const string &subpath,
1278                                 double defaultValue) const
1279 {
1280   if (_props == 0)
1281     return defaultValue;
1282
1283   if (subpath == "")
1284     return _props->getDoubleValue(_path, defaultValue);
1285   else
1286     return _props->getDoubleValue(_path + string("/") + subpath,
1287                                   defaultValue);
1288 }
1289
1290
1291 /**
1292  * Return a string value.
1293  */
1294 const string &
1295 SGPropertyNode::getStringValue (const string &subpath,
1296                                 const string &defaultValue) const
1297 {
1298   if (_props == 0)
1299     return defaultValue;
1300
1301   if (subpath == "")
1302     return _props->getStringValue(_path, defaultValue);
1303   else
1304     return _props->getStringValue(_path + string("/") + subpath,
1305                                   defaultValue);
1306 }
1307
1308
1309 // end of props.cxx