]> git.mxchange.org Git - simgear.git/blob - simgear/misc/props.cxx
73a8b5e4c540f0cb04a530923db1fc80d85e7f53
[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 FGPropertyList current_properties;
30
31 static string empty_string;
32
33
34 \f
35 ////////////////////////////////////////////////////////////////////////
36 // Implementation of FGValue.
37 ////////////////////////////////////////////////////////////////////////
38
39
40 /**
41  * Construct a new value.
42  */
43 FGValue::FGValue ()
44   : _type(UNKNOWN), _tied(false)
45 {
46 }
47
48
49 /**
50  * Destroy a value.
51  */
52 FGValue::~FGValue ()
53 {
54 }
55
56
57 /**
58  * Return a raw boolean value (no type coercion).
59  */
60 bool
61 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::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 FGValue::getFloatValue () const
305 {
306   switch (_type) {
307   case UNKNOWN:
308     return 0.0;
309   case BOOL:
310     return (float)(getRawBool());
311   case INT:
312     return (float)(getRawInt());
313   case FLOAT:
314     return getRawFloat();
315   case DOUBLE:
316     return (float)(getRawDouble());
317   case STRING:
318     return (float)atof(getRawString().c_str());
319   }
320   return false;
321 }
322
323
324 /**
325  * Get the double-precision floating-point value of a property.
326  *
327  * If the native type is not double, attempt to coerce it.
328  */
329 double
330 FGValue::getDoubleValue () const
331 {
332   switch (_type) {
333   case UNKNOWN:
334     return 0.0;
335   case BOOL:
336     return (double)(getRawBool());
337   case INT:
338     return (double)(getRawInt());
339   case FLOAT:
340     return (double)(getRawFloat());
341   case DOUBLE:
342     return getRawDouble();
343   case STRING:
344     return atof(getRawString().c_str());
345   }
346   return false;
347 }
348
349
350 /**
351  * Get the string value of a property.
352  *
353  * If the native type is not string, attempt to coerce it.
354  */
355 const string &
356 FGValue::getStringValue () const
357 {
358   char buf[512];
359   switch (_type) {
360   case UNKNOWN:
361     return getRawString();
362   case BOOL:
363     if (getRawBool())
364       string_val = "true";
365     else
366       string_val = "false";
367     return string_val;
368   case INT:
369     sprintf(buf, "%d", getRawInt());
370     string_val = buf;
371     return string_val;
372   case FLOAT:
373     sprintf(buf, "%f", getRawFloat());
374     string_val = buf;
375     return string_val;
376   case DOUBLE:
377     sprintf(buf, "%f", getRawDouble());
378     string_val = buf;
379     return string_val;
380   case STRING:
381     return getRawString();
382   }
383   return empty_string;
384 }
385
386
387 /**
388  * Set the boolean value and change the type if unknown.
389  *
390  * Returns true on success.
391  */
392 bool
393 FGValue::setBoolValue (bool value)
394 {
395   if (_type == UNKNOWN || _type == BOOL) {
396     _type = BOOL;
397     return setRawBool(value);
398   } else {
399     return false;
400   }
401 }
402
403
404 /**
405  * Set the integer value and change the type if unknown.
406  *
407  * Returns true on success.
408  */
409 bool
410 FGValue::setIntValue (int value)
411 {
412   if (_type == UNKNOWN || _type == INT) {
413     _type = INT;
414     return setRawInt(value);
415   } else {
416     return false;
417   }
418 }
419
420
421 /**
422  * Set the floating-point value and change the type if unknown.
423  *
424  * Returns true on success.
425  */
426 bool
427 FGValue::setFloatValue (float value)
428 {
429   if (_type == UNKNOWN || _type == FLOAT) {
430     _type = FLOAT;
431     return setRawFloat(value);
432   } else {
433     return false;
434   }
435 }
436
437
438 /**
439  * Set the double-precision value and change the type if unknown.
440  *
441  * Returns true on success.
442  */
443 bool
444 FGValue::setDoubleValue (double value)
445 {
446   if (_type == UNKNOWN || _type == DOUBLE) {
447     _type = DOUBLE;
448     return setRawDouble(value);
449   } else {
450     return false;
451   }
452 }
453
454
455 /**
456  * Set the string value and change the type if unknown.
457  *
458  * Returns true on success.
459  */
460 bool
461 FGValue::setStringValue (const string &value)
462 {
463   if (_type == UNKNOWN || _type == STRING) {
464     _type = STRING;
465     return setRawString(value);
466   } else {
467     return false;
468   }
469 }
470
471
472 /**
473  * Set a string value and don't modify the type.
474  *
475  * Returns true on success.
476  */
477 bool
478 FGValue::setUnknownValue (const string &value)
479 {
480   if (_type == UNKNOWN || _type == STRING) {
481     return setRawString(value);
482   } else {
483     return false;
484   }
485 }
486
487
488 /**
489  * Tie a boolean value to external functions.
490  *
491  * If useDefault is true, attempt the assign the current value
492  * (if any) after tying the functions.
493  *
494  * Returns true on success (i.e. the value is not currently tied).
495  */
496 bool
497 FGValue::tieBool (bool_getter getter, bool_setter setter = 0,
498                   bool useDefault = true)
499 {
500   if (_tied) {
501     return false;
502   } else {
503     if (useDefault && setter && _type != UNKNOWN)
504       (*setter)(getBoolValue());
505     _tied = true;
506     _type = BOOL;
507     _value.bool_func.getter = getter;
508     _value.bool_func.setter = setter;
509     return true;
510   }
511 }
512
513
514 /**
515  * Tie an integer value to external functions.
516  *
517  * If useDefault is true, attempt the assign the current value
518  * (if any) after tying the functions.
519  *
520  * Returns true on success (i.e. the value is not currently tied).
521  */
522 bool
523 FGValue::tieInt (int_getter getter, int_setter setter = 0,
524                  bool useDefault = true)
525 {
526   if (_tied) {
527     return false;
528   } else {
529     if (useDefault && setter && _type != UNKNOWN)
530       (*setter)(getIntValue());
531     _tied = true;
532     _type = INT;
533     _value.int_func.getter = getter;
534     _value.int_func.setter = setter;
535     return true;
536   }
537 }
538
539
540 /**
541  * Tie a floating-point value to external functions.
542  *
543  * If useDefault is true, attempt the assign the current value
544  * (if any) after tying the functions.
545  *
546  * Returns true on success (i.e. the value is not currently tied).
547  */
548 bool
549 FGValue::tieFloat (float_getter getter, float_setter setter = 0,
550                    bool useDefault = true)
551 {
552   if (_tied) {
553     return false;
554   } else {
555     if (useDefault && setter && _type != UNKNOWN)
556       (*setter)(getFloatValue());
557     _tied = true;
558     _type = FLOAT;
559     _value.float_func.getter = getter;
560     _value.float_func.setter = setter;
561     return true;
562   }
563 }
564
565
566 /**
567  * Tie a double-precision floating-point value to external functions.
568  *
569  * If useDefault is true, attempt the assign the current value
570  * (if any) after tying the functions.
571  *
572  * Returns true on success (i.e. the value is not currently tied).
573  */
574 bool
575 FGValue::tieDouble (double_getter getter, double_setter setter = 0,
576                     bool useDefault = true)
577 {
578   if (_tied) {
579     return false;
580   } else {
581     if (useDefault && setter && _type != UNKNOWN)
582       (*setter)(getDoubleValue());
583     _tied = true;
584     _type = DOUBLE;
585     _value.double_func.getter = getter;
586     _value.double_func.setter = setter;
587     return true;
588   }
589 }
590
591
592 /**
593  * Tie a string value to external functions.
594  *
595  * If useDefault is true, attempt the assign the current value
596  * (if any) after tying the functions.
597  *
598  * Returns true on success (i.e. the value is not currently tied).
599  */
600 bool
601 FGValue::tieString (string_getter getter, string_setter setter = 0,
602                     bool useDefault = true)
603 {
604   if (_tied) {
605     return false;
606   } else {
607     if (useDefault && setter && _type != UNKNOWN)
608       (*setter)(getStringValue());
609     _tied = true;
610     _type = STRING;
611     _value.string_func.getter = getter;
612     _value.string_func.setter = setter;
613     return true;
614   }
615 }
616
617
618 /**
619  * Untie a value from external functions.
620  *
621  * Will always attempt to intialize the internal value from
622  * the getter before untying.
623  *
624  * Returns true on success (i.e. the value had been tied).
625  */
626 bool
627 FGValue::untie ()
628 {
629   if (!_tied)
630     return false;
631
632   switch (_type) {
633   case BOOL: {
634     bool value = getRawBool();
635     _tied = false;
636     setRawBool(value);
637     break;
638   }
639   case INT: {
640     int value = getRawInt();
641     _tied = false;
642     setRawInt(value);
643     break;
644   }
645   case FLOAT: {
646     float value = getRawFloat();
647     _tied = false;
648     setRawFloat(value);
649     break;
650   }
651   case DOUBLE: {
652     double value = getRawDouble();
653     _tied = false;
654     setRawDouble(value);
655     break;
656   }
657   case STRING: {
658     string value = getRawString();
659     _tied = false;
660     setRawString(value);
661     break;
662   }
663   }
664
665   return true;
666 }
667
668
669 \f
670 ////////////////////////////////////////////////////////////////////////
671 // Implementation of FGPropertyList.
672 ////////////////////////////////////////////////////////////////////////
673
674
675 /**
676  * Constructor.
677  */
678 FGPropertyList::FGPropertyList ()
679 {
680 }
681
682
683 /**
684  * Destructor.
685  */
686 FGPropertyList::~FGPropertyList ()
687 {
688 }
689
690
691 /**
692  * Look up the FGValue structure associated with a property.
693  *
694  * Run some basic validity checks on the property name: it must
695  * not be empty, must begin with '/', must never have two '//' in a row,
696  * and must not end with '/'.
697  */
698 FGValue *
699 FGPropertyList::getValue (const string &name, bool create = false)
700 {
701   const_iterator el = _props.find(name);
702   if (el == _props.end()) {
703     if (!create)
704       return 0;
705     else {
706       FG_LOG(FG_GENERAL, FG_INFO, "Creating new property '" << name << '\'');
707       if (name.size() == 0 ||
708           name[0] != '/' ||
709           name[name.size()-1] == '/' ||
710           name.find("//") != string::npos) {
711         FG_LOG(FG_GENERAL, FG_ALERT, "Illegal property name: '"
712                << name << '\'');
713         return 0;
714       }
715     }
716   }
717   return &(_props[name]);
718 }
719
720
721 /**
722  * Look up a const value (never created).
723  */
724 const FGValue *
725 FGPropertyList::getValue (const string &name) const
726 {
727   value_map::const_iterator el = _props.find(name);
728   if (el == _props.end())
729     return 0;
730   else
731     return &(el->second);
732 }
733
734
735 /**
736  * Extract a boolean from the value.
737  *
738  * Note that this is inefficient for use in a tight loop: it is
739  * better to get the FGValue and query it repeatedly.
740  */
741 bool
742 FGPropertyList::getBoolValue (const string &name) const
743 {
744   const FGValue * val = getValue(name);
745   if (val == 0)
746     return false;
747   else
748     return val->getBoolValue();
749 }
750
751
752 /**
753  * Extract an integer from the value.
754  *
755  * Note that this is inefficient for use in a tight loop: it is
756  * better to get the FGValue and query it repeatedly.
757  */
758 int
759 FGPropertyList::getIntValue (const string &name) const
760 {
761   const FGValue * val = getValue(name);
762   if (val == 0)
763     return 0;
764   else
765     return val->getIntValue();
766 }
767
768
769 /**
770  * Extract a float from the value.
771  *
772  * Note that this is inefficient for use in a tight loop: it is
773  * better to get the FGValue and query it repeatedly.
774  */
775 float
776 FGPropertyList::getFloatValue (const string &name) const
777 {
778   const FGValue * val = getValue(name);
779   if (val == 0)
780     return 0.0;
781   else
782     return val->getFloatValue();
783 }
784
785
786 /**
787  * Extract a double from the value.
788  *
789  * Note that this is inefficient for use in a tight loop: it is
790  * better to get the FGValue and query it repeatedly.
791  */
792 double
793 FGPropertyList::getDoubleValue (const string &name) const
794 {
795   const FGValue * val = getValue(name);
796   if (val == 0)
797     return 0.0;
798   else
799     return val->getDoubleValue();
800 }
801
802
803 /**
804  * Extract a string from the value.
805  *
806  * Note that this is inefficient for use in a tight loop: it is
807  * better to save the FGValue and query it repeatedly.
808  */
809 const string &
810 FGPropertyList::getStringValue (const string &name) const
811 {
812   const FGValue * val = getValue(name);
813   if (val == 0)
814     return empty_string;
815   else
816     return val->getStringValue();
817 }
818
819
820 /**
821  * Assign a bool to the value and change the type if unknown.
822  *
823  * Note that this is inefficient for use in a tight loop: it is
824  * better to save the FGValue and modify it repeatedly.
825  *
826  * Returns true on success.
827  */
828 bool
829 FGPropertyList::setBoolValue (const string &name, bool value)
830 {
831   return getValue(name, true)->setBoolValue(value);
832 }
833
834
835 /**
836  * Assign an integer to the value and change the type if unknown.
837  *
838  * Note that this is inefficient for use in a tight loop: it is
839  * better to save the FGValue and modify it repeatedly.
840  *
841  * Returns true on success.
842  */
843 bool
844 FGPropertyList::setIntValue (const string &name, int value)
845 {
846   return getValue(name, true)->setIntValue(value);
847 }
848
849
850 /**
851  * Assign a float to the value and change the type if unknown.
852  *
853  * Note that this is inefficient for use in a tight loop: it is
854  * better to save the FGValue and modify it repeatedly.
855  *
856  * Returns true on success.
857  */
858 bool
859 FGPropertyList::setFloatValue (const string &name, float value)
860 {
861   return getValue(name, true)->setFloatValue(value);
862 }
863
864
865 /**
866  * Assign a double to the value and change the type if unknown.
867  *
868  * Note that this is inefficient for use in a tight loop: it is
869  * better to save the FGValue and modify it repeatedly.
870  *
871  * Returns true on success.
872  */
873 bool
874 FGPropertyList::setDoubleValue (const string &name, double value)
875 {
876   return getValue(name, true)->setDoubleValue(value);
877 }
878
879
880 /**
881  * Assign a string to the value and change the type if unknown.
882  *
883  * Note that this is inefficient for use in a tight loop: it is
884  * better to save the FGValue and modify it repeatedly.
885  *
886  * Returns true on success.
887  */
888 bool
889 FGPropertyList::setStringValue (const string &name, const string &value)
890 {
891   return getValue(name, true)->setStringValue(value);
892 }
893
894
895 /**
896  * Assign a string to the value, but don't change the type.
897  *
898  * Note that this is inefficient for use in a tight loop: it is
899  * better to save the FGValue and modify it repeatedly.
900  *
901  * Returns true on success.
902  */
903 bool
904 FGPropertyList::setUnknownValue (const string &name, const string &value)
905 {
906   return getValue(name, true)->setUnknownValue(value);
907 }
908
909
910 /**
911  * Tie a boolean value to external functions.
912  *
913  * Invokes FGValue::tieBool
914  */
915 bool
916 FGPropertyList::tieBool (const string &name, 
917                          bool_getter getter,
918                          bool_setter setter,
919                          bool useDefault = true)
920 {
921   FG_LOG(FG_GENERAL, FG_INFO, "Tying bool property '" << name << '\'');
922   return getValue(name, true)->tieBool(getter, setter, useDefault);
923 }
924
925
926 /**
927  * Tie an integer value to external functions.
928  *
929  * Invokes FGValue::tieInt
930  */
931 bool
932 FGPropertyList::tieInt (const string &name, 
933                         int_getter getter,
934                         int_setter setter,
935                         bool useDefault = true)
936 {
937   FG_LOG(FG_GENERAL, FG_INFO, "Tying int property '" << name << '\'');
938   return getValue(name, true)->tieInt(getter, setter, useDefault);
939 }
940
941
942 /**
943  * Tie a float value to external functions.
944  *
945  * Invokes FGValue::tieFloat
946  */
947 bool
948 FGPropertyList::tieFloat (const string &name, 
949                           float_getter getter,
950                           float_setter setter,
951                           bool useDefault = true)
952 {
953   FG_LOG(FG_GENERAL, FG_INFO, "Tying float property '" << name << '\'');
954   return getValue(name, true)->tieFloat(getter, setter, useDefault);
955 }
956
957
958 /**
959  * Tie a double value to external functions.
960  *
961  * Invokes FGValue::tieDouble
962  */
963 bool
964 FGPropertyList::tieDouble (const string &name, 
965                            double_getter getter,
966                            double_setter setter,
967                            bool useDefault = true)
968 {
969   FG_LOG(FG_GENERAL, FG_INFO, "Tying double property '" << name << '\'');
970   return getValue(name, true)->tieDouble(getter, setter, useDefault);
971 }
972
973
974 /**
975  * Tie a string value to external functions.
976  *
977  * Invokes FGValue::tieString
978  */
979 bool
980 FGPropertyList::tieString (const string &name, 
981                            string_getter getter,
982                            string_setter setter,
983                            bool useDefault = true)
984 {
985   FG_LOG(FG_GENERAL, FG_INFO, "Tying string property '" << name << '\'');
986   return getValue(name, true)->tieString(getter, setter, useDefault);
987 }
988
989
990 /**
991  * Untie a value from external functions.
992  *
993  * Invokes FGValue::untie
994  */
995 bool
996 FGPropertyList::untie (const string &name)
997 {
998   FG_LOG(FG_GENERAL, FG_INFO, "Untying property '" << name << '\'');
999   return getValue(name, true)->untie();
1000 }
1001
1002
1003 \f
1004 ////////////////////////////////////////////////////////////////////////
1005 // Implementation of FGPropertyNode.
1006 ////////////////////////////////////////////////////////////////////////
1007
1008
1009 /**
1010  * Extract the base name of the next level down from the parent.
1011  *
1012  * The parent must have a '/' appended.  Note that basename may
1013  * be modified even if the test fails.
1014  */
1015 static bool
1016 get_base (const string &parent, const string &child,
1017              string &basename)
1018 {
1019                                 // First, check that the parent name
1020                                 // is a prefix of the child name, and
1021                                 // extract the remainder
1022   if (child.find(parent) != 0)
1023     return false;
1024
1025   basename = child.substr(parent.size());
1026
1027   string::size_type pos = basename.find('/');
1028   if (pos != string::npos) {
1029     basename.resize(pos);
1030   }
1031
1032   if (basename.size() == 0)
1033     return false;
1034   else
1035     return true;
1036 }
1037
1038
1039 /**
1040  * Constructor.
1041  */
1042 FGPropertyNode::FGPropertyNode (const string &path = "",
1043                                 FGPropertyList * props = 0)
1044   : _props(props)
1045 {
1046   setPath(path);
1047 }
1048
1049
1050 /**
1051  * Destructor.
1052  */
1053 FGPropertyNode::~FGPropertyNode ()
1054 {
1055 }
1056
1057
1058 /**
1059  * Set the path.
1060  *
1061  * Strip the trailing '/', if any.
1062  */
1063 void
1064 FGPropertyNode::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 FGPropertyNode::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 value of the current node.
1094  *
1095  * Currently, this does a lookup each time, but we could cache the
1096  * value safely as long as it's non-zero.
1097  *
1098  * Note that this will not create the value if it doesn't already exist.
1099  */
1100 FGValue *
1101 FGPropertyNode::getValue ()
1102 {
1103   if (_props == 0 || _path.size() == 0)
1104     return 0;
1105   else
1106     return _props->getValue(_path);
1107 }
1108
1109
1110 /**
1111  * Return the number of children for the current node.
1112  */
1113 int
1114 FGPropertyNode::size () const
1115 {
1116   if (_props == 0)
1117     return 0;
1118
1119   int s = 0;
1120
1121   string base;
1122   string lastBase;
1123   string pattern = _path;
1124   pattern += '/';
1125
1126   FGPropertyList::const_iterator it = _props->begin();
1127   FGPropertyList::const_iterator end = _props->end();
1128   while (it != end) {
1129     if (get_base(pattern, it->first, base) && base != lastBase) {
1130       s++;
1131       lastBase = base;
1132     }
1133     it++;
1134   }
1135
1136   return s;
1137 }
1138
1139
1140 /**
1141  * Initialize a node to represent this node's parent.
1142  *
1143  * A return value of true means success; otherwise, the node supplied
1144  * is unmodified.
1145  */
1146 bool
1147 FGPropertyNode::getParent (FGPropertyNode &parent) const
1148 {
1149   string::size_type pos = _path.rfind('/');
1150   if (pos != string::npos) {
1151     parent.setPath(_path.substr(0, pos-1));
1152     parent.setPropertyList(_props);
1153     return true;
1154   } else {
1155     return false;
1156   }
1157 }
1158
1159
1160 /**
1161  * Initialize a node to represent this node's nth child.
1162  *
1163  * A return value of true means success; otherwise, the node supplied
1164  * is unmodified.
1165  */
1166 bool
1167 FGPropertyNode::getChild (FGPropertyNode &child, int n) const
1168 {
1169   if (_props == 0)
1170     return false;
1171
1172   int s = 0;
1173   string base;
1174   string lastBase;
1175   string pattern = _path;
1176   pattern += '/';
1177
1178   FGPropertyList::const_iterator it = _props->begin();
1179   FGPropertyList::const_iterator end = _props->end();
1180   while (it != end) {
1181     if (get_base(pattern, it->first, base) && base != lastBase) {
1182       if (s == n) {
1183         string path = _path;
1184         path += '/';
1185         path += base;
1186         child.setPath(path);
1187         child.setPropertyList(_props);
1188         return true;
1189       } else {
1190         s++;
1191         lastBase = base;
1192       }
1193     }
1194     it++;
1195   }
1196
1197   return false;
1198 }
1199
1200 // end of props.cxx