]> git.mxchange.org Git - simgear.git/blobdiff - simgear/misc/props.cxx
Updates from David Megginson:
[simgear.git] / simgear / misc / props.cxx
index d5164226248be48f86e49f8c862bd1df442e2e9e..fdabb24ca44bd2f5afdd868f93908e6a0e2fcce9 100644 (file)
 
 using std::string;
 
-FGPropertyList current_properties;
+SGPropertyList current_properties;
 
 static string empty_string;
 
 
 \f
 ////////////////////////////////////////////////////////////////////////
-// Implementation of FGValue.
+// Implementation of SGValue.
 ////////////////////////////////////////////////////////////////////////
 
 
 /**
  * Construct a new value.
  */
-FGValue::FGValue ()
+SGValue::SGValue ()
   : _type(UNKNOWN), _tied(false)
 {
 }
@@ -49,7 +49,7 @@ FGValue::FGValue ()
 /**
  * Destroy a value.
  */
-FGValue::~FGValue ()
+SGValue::~SGValue ()
 {
 }
 
@@ -58,7 +58,7 @@ FGValue::~FGValue ()
  * Return a raw boolean value (no type coercion).
  */
 bool
-FGValue::getRawBool () const
+SGValue::getRawBool () const
 {
   if (_tied) {
     if (_value.bool_func.getter != 0)
@@ -75,7 +75,7 @@ FGValue::getRawBool () const
  * Return a raw integer value (no type coercion).
  */
 int
-FGValue::getRawInt () const
+SGValue::getRawInt () const
 {
   if (_tied) {
     if (_value.int_func.getter != 0)
@@ -92,7 +92,7 @@ FGValue::getRawInt () const
  * Return a raw floating-point value (no type coercion).
  */
 float
-FGValue::getRawFloat () const
+SGValue::getRawFloat () const
 {
   if (_tied) {
     if (_value.float_func.getter != 0)
@@ -109,7 +109,7 @@ FGValue::getRawFloat () const
  * Return a raw double-precision floating-point value (no type coercion).
  */
 double
-FGValue::getRawDouble () const
+SGValue::getRawDouble () const
 {
   if (_tied) {
     if (_value.double_func.getter != 0)
@@ -126,7 +126,7 @@ FGValue::getRawDouble () const
  * Return a raw string value (no type coercion).
  */
 const string &
-FGValue::getRawString () const
+SGValue::getRawString () const
 {
   if (_tied && _value.string_func.getter != 0)
     return (*(_value.string_func.getter))();
@@ -141,7 +141,7 @@ FGValue::getRawString () const
  * Return false if the value could not be set, true otherwise.
  */
 bool
-FGValue::setRawBool (bool value)
+SGValue::setRawBool (bool value)
 {
   if (_tied) {
     if (_value.bool_func.setter != 0) {
@@ -163,7 +163,7 @@ FGValue::setRawBool (bool value)
  * Return false if the value could not be set, true otherwise.
  */
 bool
-FGValue::setRawInt (int value)
+SGValue::setRawInt (int value)
 {
   if (_tied) {
     if (_value.int_func.setter != 0) {
@@ -185,7 +185,7 @@ FGValue::setRawInt (int value)
  * Return false if the value could not be set, true otherwise.
  */
 bool
-FGValue::setRawFloat (float value)
+SGValue::setRawFloat (float value)
 {
   if (_tied) {
     if (_value.float_func.setter != 0) {
@@ -207,7 +207,7 @@ FGValue::setRawFloat (float value)
  * Return false if the value could not be set, true otherwise.
  */
 bool
-FGValue::setRawDouble (double value)
+SGValue::setRawDouble (double value)
 {
   if (_tied) {
     if (_value.double_func.setter != 0) {
@@ -229,7 +229,7 @@ FGValue::setRawDouble (double value)
  * Return false if the value could not be set, true otherwise.
  */
 bool
-FGValue::setRawString (const string &value)
+SGValue::setRawString (const string &value)
 {
   if (_tied) {
     if (_value.string_func.setter != 0) {
@@ -251,7 +251,7 @@ FGValue::setRawString (const string &value)
  * If the native type is not boolean, attempt to coerce it.
  */
 bool
-FGValue::getBoolValue () const
+SGValue::getBoolValue () const
 {
   switch (_type) {
   case BOOL:
@@ -264,7 +264,7 @@ FGValue::getBoolValue () const
     return (getRawDouble() == 0.0 ? false : true);
   case UNKNOWN:
   case STRING:
-    return ((getRawString() == "false" || getIntValue() == 0) ? false : true);
+    return ((getRawString() == "true" || getIntValue() != 0) ? true : false);
   }
   return false;
 }
@@ -276,7 +276,7 @@ FGValue::getBoolValue () const
  * If the native type is not integer, attempt to coerce it.
  */
 int
-FGValue::getIntValue () const
+SGValue::getIntValue () const
 {
   switch (_type) {
   case BOOL:
@@ -301,11 +301,9 @@ FGValue::getIntValue () const
  * If the native type is not float, attempt to coerce it.
  */
 float
-FGValue::getFloatValue () const
+SGValue::getFloatValue () const
 {
   switch (_type) {
-  case UNKNOWN:
-    return 0.0;
   case BOOL:
     return (float)(getRawBool());
   case INT:
@@ -314,6 +312,7 @@ FGValue::getFloatValue () const
     return getRawFloat();
   case DOUBLE:
     return (float)(getRawDouble());
+  case UNKNOWN:
   case STRING:
     return (float)atof(getRawString().c_str());
   }
@@ -327,11 +326,9 @@ FGValue::getFloatValue () const
  * If the native type is not double, attempt to coerce it.
  */
 double
-FGValue::getDoubleValue () const
+SGValue::getDoubleValue () const
 {
   switch (_type) {
-  case UNKNOWN:
-    return 0.0;
   case BOOL:
     return (double)(getRawBool());
   case INT:
@@ -340,6 +337,7 @@ FGValue::getDoubleValue () const
     return (double)(getRawFloat());
   case DOUBLE:
     return getRawDouble();
+  case UNKNOWN:
   case STRING:
     return atof(getRawString().c_str());
   }
@@ -353,12 +351,10 @@ FGValue::getDoubleValue () const
  * If the native type is not string, attempt to coerce it.
  */
 const string &
-FGValue::getStringValue () const
+SGValue::getStringValue () const
 {
   char buf[512];
   switch (_type) {
-  case UNKNOWN:
-    return getRawString();
   case BOOL:
     if (getRawBool())
       string_val = "true";
@@ -374,9 +370,10 @@ FGValue::getStringValue () const
     string_val = buf;
     return string_val;
   case DOUBLE:
-    sprintf(buf, "%lf", getRawDouble());
+    sprintf(buf, "%f", getRawDouble());
     string_val = buf;
     return string_val;
+  case UNKNOWN:
   case STRING:
     return getRawString();
   }
@@ -390,14 +387,26 @@ FGValue::getStringValue () const
  * Returns true on success.
  */
 bool
-FGValue::setBoolValue (bool value)
+SGValue::setBoolValue (bool value)
 {
-  if (_type == UNKNOWN || _type == BOOL) {
-    _type = BOOL;
+  if (_type == UNKNOWN)
+    _type = INT;
+  switch (_type) {
+  case BOOL:
     return setRawBool(value);
-  } else {
-    return false;
+  case INT:
+    return setRawInt((int)value);
+  case FLOAT:
+    return setRawFloat((float)value);
+  case DOUBLE:
+    return setRawDouble((double)value);
+  case STRING:
+    if (value)
+      return setRawString("true");
+    else
+      return setRawString("false");
   }
+  return false;
 }
 
 
@@ -407,14 +416,28 @@ FGValue::setBoolValue (bool value)
  * Returns true on success.
  */
 bool
-FGValue::setIntValue (int value)
+SGValue::setIntValue (int value)
 {
-  if (_type == UNKNOWN || _type == INT) {
+  if (_type == UNKNOWN)
     _type = INT;
+  switch (_type) {
+  case BOOL:
+    if (value == 0)
+      return setRawBool(false);
+    else
+      return setRawBool(true);
+  case INT:
     return setRawInt(value);
-  } else {
-    return false;
+  case FLOAT:
+    return setRawFloat((float)value);
+  case DOUBLE:
+    return setRawDouble((double)value);
+  case STRING:
+    char buf[128];
+    sprintf(buf, "%d", value);
+    return setRawString(buf);
   }
+  return false;
 }
 
 
@@ -424,14 +447,28 @@ FGValue::setIntValue (int value)
  * Returns true on success.
  */
 bool
-FGValue::setFloatValue (float value)
+SGValue::setFloatValue (float value)
 {
-  if (_type == UNKNOWN || _type == FLOAT) {
+  if (_type == UNKNOWN)
     _type = FLOAT;
+  switch (_type) {
+  case BOOL:
+    if (value == 0.0)
+      return setRawBool(false);
+    else
+      return setRawBool(true);
+  case INT:
+    return setRawInt((int)value);
+  case FLOAT:
     return setRawFloat(value);
-  } else {
-    return false;
+  case DOUBLE:
+    return setRawDouble((double)value);
+  case STRING:
+    char buf[128];
+    sprintf(buf, "%f", value);
+    return setRawString(buf);
   }
+  return false;
 }
 
 
@@ -441,14 +478,28 @@ FGValue::setFloatValue (float value)
  * Returns true on success.
  */
 bool
-FGValue::setDoubleValue (double value)
+SGValue::setDoubleValue (double value)
 {
-  if (_type == UNKNOWN || _type == DOUBLE) {
+  if (_type == UNKNOWN)
     _type = DOUBLE;
+  switch (_type) {
+  case BOOL:
+    if (value == 0.0L)
+      return setRawBool(false);
+    else
+      return setRawBool(true);
+  case INT:
+    return setRawInt((int)value);
+  case FLOAT:
+    return setRawFloat((float)value);
+  case DOUBLE:
     return setRawDouble(value);
-  } else {
-    return false;
+  case STRING:
+    char buf[128];
+    sprintf(buf, "%lf", value);
+    return setRawString(buf);
   }
+  return false;
 }
 
 
@@ -458,14 +509,27 @@ FGValue::setDoubleValue (double value)
  * Returns true on success.
  */
 bool
-FGValue::setStringValue (const string &value)
+SGValue::setStringValue (const string &value)
 {
-  if (_type == UNKNOWN || _type == STRING) {
+  if (_type == UNKNOWN)
     _type = STRING;
+
+  switch (_type) {
+  case BOOL:
+    if (value == "true" || atoi(value.c_str()) != 0)
+      return setRawBool(true);
+    else
+      return setRawBool(false);
+  case INT:
+    return setRawInt(atoi(value.c_str()));
+  case FLOAT:
+    return setRawFloat(atof(value.c_str()));
+  case DOUBLE:
+    return setRawDouble(atof(value.c_str()));
+  case STRING:
     return setRawString(value);
-  } else {
-    return false;
   }
+  return false;
 }
 
 
@@ -475,13 +539,25 @@ FGValue::setStringValue (const string &value)
  * Returns true on success.
  */
 bool
-FGValue::setUnknownValue (const string &value)
+SGValue::setUnknownValue (const string &value)
 {
-  if (_type == UNKNOWN || _type == STRING) {
+  switch (_type) {
+  case BOOL:
+    if (value == "true" || atoi(value.c_str()) != 0)
+      return setRawBool(true);
+    else
+      return setRawBool(false);
+  case INT:
+    return setRawInt(atoi(value.c_str()));
+  case FLOAT:
+    return setRawFloat(atof(value.c_str()));
+  case DOUBLE:
+    return setRawDouble(atof(value.c_str()));
+  case STRING:
+  case UNKNOWN:
     return setRawString(value);
-  } else {
-    return false;
   }
+  return false;
 }
 
 
@@ -494,13 +570,13 @@ FGValue::setUnknownValue (const string &value)
  * Returns true on success (i.e. the value is not currently tied).
  */
 bool
-FGValue::tieBool (bool_getter getter, bool_setter setter = 0,
-                 bool useDefault = true)
+SGValue::tieBool (bool_getter getter, bool_setter setter,
+                 bool useDefault)
 {
   if (_tied) {
     return false;
   } else {
-    if (useDefault && setter && _type != UNKNOWN)
+    if (useDefault && setter)
       (*setter)(getBoolValue());
     _tied = true;
     _type = BOOL;
@@ -520,13 +596,13 @@ FGValue::tieBool (bool_getter getter, bool_setter setter = 0,
  * Returns true on success (i.e. the value is not currently tied).
  */
 bool
-FGValue::tieInt (int_getter getter, int_setter setter = 0,
-                bool useDefault = true)
+SGValue::tieInt (int_getter getter, int_setter setter,
+                bool useDefault)
 {
   if (_tied) {
     return false;
   } else {
-    if (useDefault && setter && _type != UNKNOWN)
+    if (useDefault && setter)
       (*setter)(getIntValue());
     _tied = true;
     _type = INT;
@@ -546,13 +622,13 @@ FGValue::tieInt (int_getter getter, int_setter setter = 0,
  * Returns true on success (i.e. the value is not currently tied).
  */
 bool
-FGValue::tieFloat (float_getter getter, float_setter setter = 0,
-                  bool useDefault = true)
+SGValue::tieFloat (float_getter getter, float_setter setter,
+                  bool useDefault)
 {
   if (_tied) {
     return false;
   } else {
-    if (useDefault && setter && _type != UNKNOWN)
+    if (useDefault && setter)
       (*setter)(getFloatValue());
     _tied = true;
     _type = FLOAT;
@@ -572,13 +648,13 @@ FGValue::tieFloat (float_getter getter, float_setter setter = 0,
  * Returns true on success (i.e. the value is not currently tied).
  */
 bool
-FGValue::tieDouble (double_getter getter, double_setter setter = 0,
-                   bool useDefault = true)
+SGValue::tieDouble (double_getter getter, double_setter setter,
+                   bool useDefault)
 {
   if (_tied) {
     return false;
   } else {
-    if (useDefault && setter && _type != UNKNOWN)
+    if (useDefault && setter)
       (*setter)(getDoubleValue());
     _tied = true;
     _type = DOUBLE;
@@ -598,13 +674,13 @@ FGValue::tieDouble (double_getter getter, double_setter setter = 0,
  * Returns true on success (i.e. the value is not currently tied).
  */
 bool
-FGValue::tieString (string_getter getter, string_setter setter = 0,
-                   bool useDefault = true)
+SGValue::tieString (string_getter getter, string_setter setter,
+                   bool useDefault)
 {
   if (_tied) {
     return false;
   } else {
-    if (useDefault && setter && _type != UNKNOWN)
+    if (useDefault && setter)
       (*setter)(getStringValue());
     _tied = true;
     _type = STRING;
@@ -624,7 +700,7 @@ FGValue::tieString (string_getter getter, string_setter setter = 0,
  * Returns true on success (i.e. the value had been tied).
  */
 bool
-FGValue::untie ()
+SGValue::untie ()
 {
   if (!_tied)
     return false;
@@ -668,14 +744,14 @@ FGValue::untie ()
 
 \f
 ////////////////////////////////////////////////////////////////////////
-// Implementation of FGPropertyList.
+// Implementation of SGPropertyList.
 ////////////////////////////////////////////////////////////////////////
 
 
 /**
  * Constructor.
  */
-FGPropertyList::FGPropertyList ()
+SGPropertyList::SGPropertyList ()
 {
 }
 
@@ -683,20 +759,34 @@ FGPropertyList::FGPropertyList ()
 /**
  * Destructor.
  */
-FGPropertyList::~FGPropertyList ()
+SGPropertyList::~SGPropertyList ()
 {
 }
 
 
 /**
- * Look up the FGValue structure associated with a property.
+ * Return true if a value is present.
+ */
+bool
+SGPropertyList::hasValue (const string &name) const
+{
+  const_iterator el = _props.find(name);
+  if (el == _props.end())
+    return false;
+  else
+    return true;
+}
+
+
+/**
+ * Look up the SGValue structure associated with a property.
  *
  * Run some basic validity checks on the property name: it must
  * not be empty, must begin with '/', must never have two '//' in a row,
  * and must not end with '/'.
  */
-FGValue *
-FGPropertyList::getValue (const string &name, bool create = false)
+SGValue *
+SGPropertyList::getValue (const string &name, bool create)
 {
   const_iterator el = _props.find(name);
   if (el == _props.end()) {
@@ -721,8 +811,8 @@ FGPropertyList::getValue (const string &name, bool create = false)
 /**
  * Look up a const value (never created).
  */
-const FGValue *
-FGPropertyList::getValue (const string &name) const
+const SGValue *
+SGPropertyList::getValue (const string &name) const
 {
   value_map::const_iterator el = _props.find(name);
   if (el == _props.end())
@@ -736,14 +826,14 @@ FGPropertyList::getValue (const string &name) const
  * Extract a boolean from the value.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to get the FGValue and query it repeatedly.
+ * better to get the SGValue and query it repeatedly.
  */
 bool
-FGPropertyList::getBoolValue (const string &name) const
+SGPropertyList::getBoolValue (const string &name, bool defaultValue) const
 {
-  const FGValue * val = getValue(name);
+  const SGValue * val = getValue(name);
   if (val == 0)
-    return false;
+    return defaultValue;
   else
     return val->getBoolValue();
 }
@@ -753,14 +843,14 @@ FGPropertyList::getBoolValue (const string &name) const
  * Extract an integer from the value.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to get the FGValue and query it repeatedly.
+ * better to get the SGValue and query it repeatedly.
  */
 int
-FGPropertyList::getIntValue (const string &name) const
+SGPropertyList::getIntValue (const string &name, int defaultValue) const
 {
-  const FGValue * val = getValue(name);
+  const SGValue * val = getValue(name);
   if (val == 0)
-    return 0;
+    return defaultValue;
   else
     return val->getIntValue();
 }
@@ -770,14 +860,14 @@ FGPropertyList::getIntValue (const string &name) const
  * Extract a float from the value.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to get the FGValue and query it repeatedly.
+ * better to get the SGValue and query it repeatedly.
  */
 float
-FGPropertyList::getFloatValue (const string &name) const
+SGPropertyList::getFloatValue (const string &name, float defaultValue) const
 {
-  const FGValue * val = getValue(name);
+  const SGValue * val = getValue(name);
   if (val == 0)
-    return 0.0;
+    return defaultValue;
   else
     return val->getFloatValue();
 }
@@ -787,14 +877,14 @@ FGPropertyList::getFloatValue (const string &name) const
  * Extract a double from the value.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to get the FGValue and query it repeatedly.
+ * better to get the SGValue and query it repeatedly.
  */
 double
-FGPropertyList::getDoubleValue (const string &name) const
+SGPropertyList::getDoubleValue (const string &name, double defaultValue) const
 {
-  const FGValue * val = getValue(name);
+  const SGValue * val = getValue(name);
   if (val == 0)
-    return 0.0;
+    return defaultValue;
   else
     return val->getDoubleValue();
 }
@@ -804,14 +894,15 @@ FGPropertyList::getDoubleValue (const string &name) const
  * Extract a string from the value.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to save the FGValue and query it repeatedly.
+ * better to save the SGValue and query it repeatedly.
  */
 const string &
-FGPropertyList::getStringValue (const string &name) const
+SGPropertyList::getStringValue (const string &name,
+                               const string &defaultValue) const
 {
-  const FGValue * val = getValue(name);
+  const SGValue * val = getValue(name);
   if (val == 0)
-    return empty_string;
+    return defaultValue;
   else
     return val->getStringValue();
 }
@@ -821,12 +912,12 @@ FGPropertyList::getStringValue (const string &name) const
  * Assign a bool to the value and change the type if unknown.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to save the FGValue and modify it repeatedly.
+ * better to save the SGValue and modify it repeatedly.
  *
  * Returns true on success.
  */
 bool
-FGPropertyList::setBoolValue (const string &name, bool value)
+SGPropertyList::setBoolValue (const string &name, bool value)
 {
   return getValue(name, true)->setBoolValue(value);
 }
@@ -836,12 +927,12 @@ FGPropertyList::setBoolValue (const string &name, bool value)
  * Assign an integer to the value and change the type if unknown.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to save the FGValue and modify it repeatedly.
+ * better to save the SGValue and modify it repeatedly.
  *
  * Returns true on success.
  */
 bool
-FGPropertyList::setIntValue (const string &name, int value)
+SGPropertyList::setIntValue (const string &name, int value)
 {
   return getValue(name, true)->setIntValue(value);
 }
@@ -851,12 +942,12 @@ FGPropertyList::setIntValue (const string &name, int value)
  * Assign a float to the value and change the type if unknown.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to save the FGValue and modify it repeatedly.
+ * better to save the SGValue and modify it repeatedly.
  *
  * Returns true on success.
  */
 bool
-FGPropertyList::setFloatValue (const string &name, float value)
+SGPropertyList::setFloatValue (const string &name, float value)
 {
   return getValue(name, true)->setFloatValue(value);
 }
@@ -866,12 +957,12 @@ FGPropertyList::setFloatValue (const string &name, float value)
  * Assign a double to the value and change the type if unknown.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to save the FGValue and modify it repeatedly.
+ * better to save the SGValue and modify it repeatedly.
  *
  * Returns true on success.
  */
 bool
-FGPropertyList::setDoubleValue (const string &name, double value)
+SGPropertyList::setDoubleValue (const string &name, double value)
 {
   return getValue(name, true)->setDoubleValue(value);
 }
@@ -881,12 +972,12 @@ FGPropertyList::setDoubleValue (const string &name, double value)
  * Assign a string to the value and change the type if unknown.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to save the FGValue and modify it repeatedly.
+ * better to save the SGValue and modify it repeatedly.
  *
  * Returns true on success.
  */
 bool
-FGPropertyList::setStringValue (const string &name, const string &value)
+SGPropertyList::setStringValue (const string &name, const string &value)
 {
   return getValue(name, true)->setStringValue(value);
 }
@@ -896,12 +987,12 @@ FGPropertyList::setStringValue (const string &name, const string &value)
  * Assign a string to the value, but don't change the type.
  *
  * Note that this is inefficient for use in a tight loop: it is
- * better to save the FGValue and modify it repeatedly.
+ * better to save the SGValue and modify it repeatedly.
  *
  * Returns true on success.
  */
 bool
-FGPropertyList::setUnknownValue (const string &name, const string &value)
+SGPropertyList::setUnknownValue (const string &name, const string &value)
 {
   return getValue(name, true)->setUnknownValue(value);
 }
@@ -910,15 +1001,16 @@ FGPropertyList::setUnknownValue (const string &name, const string &value)
 /**
  * Tie a boolean value to external functions.
  *
- * Invokes FGValue::tieBool
+ * Invokes SGValue::tieBool
  */
 bool
-FGPropertyList::tieBool (const string &name, 
+SGPropertyList::tieBool (const string &name, 
                         bool_getter getter,
                         bool_setter setter,
-                        bool useDefault = true)
+                        bool useDefault)
 {
   FG_LOG(FG_GENERAL, FG_INFO, "Tying bool property '" << name << '\'');
+  useDefault = useDefault && hasValue(name);
   return getValue(name, true)->tieBool(getter, setter, useDefault);
 }
 
@@ -926,15 +1018,16 @@ FGPropertyList::tieBool (const string &name,
 /**
  * Tie an integer value to external functions.
  *
- * Invokes FGValue::tieInt
+ * Invokes SGValue::tieInt
  */
 bool
-FGPropertyList::tieInt (const string &name, 
+SGPropertyList::tieInt (const string &name, 
                        int_getter getter,
                        int_setter setter,
-                       bool useDefault = true)
+                       bool useDefault)
 {
   FG_LOG(FG_GENERAL, FG_INFO, "Tying int property '" << name << '\'');
+  useDefault = useDefault && hasValue(name);
   return getValue(name, true)->tieInt(getter, setter, useDefault);
 }
 
@@ -942,15 +1035,16 @@ FGPropertyList::tieInt (const string &name,
 /**
  * Tie a float value to external functions.
  *
- * Invokes FGValue::tieFloat
+ * Invokes SGValue::tieFloat
  */
 bool
-FGPropertyList::tieFloat (const string &name, 
+SGPropertyList::tieFloat (const string &name, 
                          float_getter getter,
                          float_setter setter,
-                         bool useDefault = true)
+                         bool useDefault)
 {
   FG_LOG(FG_GENERAL, FG_INFO, "Tying float property '" << name << '\'');
+  useDefault = useDefault && hasValue(name);
   return getValue(name, true)->tieFloat(getter, setter, useDefault);
 }
 
@@ -958,15 +1052,16 @@ FGPropertyList::tieFloat (const string &name,
 /**
  * Tie a double value to external functions.
  *
- * Invokes FGValue::tieDouble
+ * Invokes SGValue::tieDouble
  */
 bool
-FGPropertyList::tieDouble (const string &name, 
+SGPropertyList::tieDouble (const string &name, 
                           double_getter getter,
                           double_setter setter,
-                          bool useDefault = true)
+                          bool useDefault)
 {
   FG_LOG(FG_GENERAL, FG_INFO, "Tying double property '" << name << '\'');
+  useDefault = useDefault && hasValue(name);
   return getValue(name, true)->tieDouble(getter, setter, useDefault);
 }
 
@@ -974,15 +1069,16 @@ FGPropertyList::tieDouble (const string &name,
 /**
  * Tie a string value to external functions.
  *
- * Invokes FGValue::tieString
+ * Invokes SGValue::tieString
  */
 bool
-FGPropertyList::tieString (const string &name, 
+SGPropertyList::tieString (const string &name, 
                           string_getter getter,
                           string_setter setter,
-                          bool useDefault = true)
+                          bool useDefault)
 {
   FG_LOG(FG_GENERAL, FG_INFO, "Tying string property '" << name << '\'');
+  useDefault = useDefault && hasValue(name);
   return getValue(name, true)->tieString(getter, setter, useDefault);
 }
 
@@ -990,10 +1086,10 @@ FGPropertyList::tieString (const string &name,
 /**
  * Untie a value from external functions.
  *
- * Invokes FGValue::untie
+ * Invokes SGValue::untie
  */
 bool
-FGPropertyList::untie (const string &name)
+SGPropertyList::untie (const string &name)
 {
   FG_LOG(FG_GENERAL, FG_INFO, "Untying property '" << name << '\'');
   return getValue(name, true)->untie();
@@ -1002,7 +1098,7 @@ FGPropertyList::untie (const string &name)
 
 \f
 ////////////////////////////////////////////////////////////////////////
-// Implementation of FGPropertyNode.
+// Implementation of SGPropertyNode.
 ////////////////////////////////////////////////////////////////////////
 
 
@@ -1024,7 +1120,7 @@ get_base (const string &parent, const string &child,
 
   basename = child.substr(parent.size());
 
-  int pos = basename.find('/');
+  string::size_type pos = basename.find('/');
   if (pos != string::npos) {
     basename.resize(pos);
   }
@@ -1039,9 +1135,9 @@ get_base (const string &parent, const string &child,
 /**
  * Constructor.
  */
-FGPropertyNode::FGPropertyNode (const string &path = "",
-                               FGPropertyList * props = 0)
-  : _props(props)
+SGPropertyNode::SGPropertyNode (const string &path,
+                               SGPropertyList * props)
+  : _props(props), _node(0)
 {
   setPath(path);
 }
@@ -1050,8 +1146,10 @@ FGPropertyNode::FGPropertyNode (const string &path = "",
 /**
  * Destructor.
  */
-FGPropertyNode::~FGPropertyNode ()
+SGPropertyNode::~SGPropertyNode ()
 {
+  delete _node;
+  _node = 0;
 }
 
 
@@ -1061,7 +1159,7 @@ FGPropertyNode::~FGPropertyNode ()
  * Strip the trailing '/', if any.
  */
 void
-FGPropertyNode::setPath (const string &path)
+SGPropertyNode::setPath (const string &path)
 {
   _path = path;
 
@@ -1077,9 +1175,9 @@ FGPropertyNode::setPath (const string &path)
  * The local name is just everything after the last slash.
  */
 const string &
-FGPropertyNode::getName () const
+SGPropertyNode::getName () const
 {
-  int pos = _path.rfind('/');
+  string::size_type pos = _path.rfind('/');
   if (pos != string::npos) {
     _name = _path.substr(pos+1);
     return _name;
@@ -1089,29 +1187,11 @@ FGPropertyNode::getName () const
 }
 
 
-/**
- * Return the value of the current node.
- *
- * Currently, this does a lookup each time, but we could cache the
- * value safely as long as it's non-zero.
- *
- * Note that this will not create the value if it doesn't already exist.
- */
-FGValue *
-FGPropertyNode::getValue ()
-{
-  if (_props == 0 || _path.size() == 0)
-    return 0;
-  else
-    return _props->getValue(_path);
-}
-
-
 /**
  * Return the number of children for the current node.
  */
 int
-FGPropertyNode::size () const
+SGPropertyNode::size () const
 {
   if (_props == 0)
     return 0;
@@ -1123,8 +1203,8 @@ FGPropertyNode::size () const
   string pattern = _path;
   pattern += '/';
 
-  FGPropertyList::const_iterator it = _props->begin();
-  FGPropertyList::const_iterator end = _props->end();
+  SGPropertyList::const_iterator it = _props->begin();
+  SGPropertyList::const_iterator end = _props->end();
   while (it != end) {
     if (get_base(pattern, it->first, base) && base != lastBase) {
       s++;
@@ -1143,17 +1223,18 @@ FGPropertyNode::size () const
  * A return value of true means success; otherwise, the node supplied
  * is unmodified.
  */
-bool
-FGPropertyNode::getParent (FGPropertyNode &parent) const
+SGPropertyNode &
+SGPropertyNode::getParent () const
 {
-  int pos = _path.rfind('/');
+  if (_node == 0)
+    _node = new SGPropertyNode();
+
+  string::size_type pos = _path.rfind('/');
   if (pos != string::npos) {
-    parent.setPath(_path.substr(0, pos-1));
-    parent.setPropertyList(_props);
-    return true;
-  } else {
-    return false;
+    _node->setPropertyList(_props);
+    _node->setPath(_path.substr(0, pos-1));
   }
+  return *_node;
 }
 
 
@@ -1163,11 +1244,14 @@ FGPropertyNode::getParent (FGPropertyNode &parent) const
  * A return value of true means success; otherwise, the node supplied
  * is unmodified.
  */
-bool
-FGPropertyNode::getChild (FGPropertyNode &child, int n) const
+SGPropertyNode &
+SGPropertyNode::getChild (int n) const
 {
+  if (_node == 0)
+    _node = new SGPropertyNode();
+
   if (_props == 0)
-    return false;
+    return *_node;
 
   int s = 0;
   string base;
@@ -1175,17 +1259,14 @@ FGPropertyNode::getChild (FGPropertyNode &child, int n) const
   string pattern = _path;
   pattern += '/';
 
-  FGPropertyList::const_iterator it = _props->begin();
-  FGPropertyList::const_iterator end = _props->end();
+  SGPropertyList::const_iterator it = _props->begin();
+  SGPropertyList::const_iterator end = _props->end();
   while (it != end) {
     if (get_base(pattern, it->first, base) && base != lastBase) {
       if (s == n) {
-       string path = _path;
-       path += '/';
-       path += base;
-       child.setPath(path);
-       child.setPropertyList(_props);
-       return true;
+       _node->setPropertyList(_props);
+       _node->setPath(_path + string("/") + base);
+       return *_node;
       } else {
        s++;
        lastBase = base;
@@ -1194,7 +1275,149 @@ FGPropertyNode::getChild (FGPropertyNode &child, int n) const
     it++;
   }
 
-  return false;
+  return *_node;
+}
+
+
+/**
+ * Return a node for an arbitrary subpath.
+ *
+ * Never returns 0.
+ */
+SGPropertyNode &
+SGPropertyNode::getSubNode (const string &subpath) const
+{
+  if (_node == 0)
+    _node = new SGPropertyNode();
+
+  _node->setPropertyList(_props);
+  _node->setPath(_path + string("/") + subpath);
+  return *_node;
+}
+
+
+/**
+ * Test whether the specified subpath has a value.
+ */
+bool
+SGPropertyNode::hasValue (const string &subpath) const
+{
+  if (_props == 0)
+    return false;
+
+  if (subpath.size() == 0)
+    return _props->hasValue(_path);
+  else
+    return _props->hasValue(_path + string("/") + subpath);
+}
+
+
+/**
+ * Return the value of the current node.
+ *
+ * Currently, this does a lookup each time, but we could cache the
+ * value safely as long as it's non-zero.
+ *
+ * Note that this will not create the value if it doesn't already exist.
+ */
+SGValue *
+SGPropertyNode::getValue (const string &subpath)
+{
+  if (_props == 0)
+    return 0;
+
+  if (subpath.size() == 0)
+    return _props->getValue(_path);
+  else
+    return _props->getValue(_path + string("/") + subpath);
+}
+
+
+/**
+ * Return a bool value.
+ */
+bool
+SGPropertyNode::getBoolValue (const string &subpath, bool defaultValue) const
+{
+  if (_props == 0)
+    return defaultValue;
+
+  if (subpath == "")
+    return _props->getBoolValue(_path, defaultValue);
+  else
+    return _props->getBoolValue(_path + string("/") + subpath,
+                               defaultValue);
 }
 
+
+/**
+ * Return an int value.
+ */
+int
+SGPropertyNode::getIntValue (const string &subpath, int defaultValue) const
+{
+  if (_props == 0)
+    return defaultValue;
+
+  if (subpath == "")
+    return _props->getIntValue(_path, defaultValue);
+  else
+    return _props->getIntValue(_path + string("/") + subpath,
+                              defaultValue);
+}
+
+
+/**
+ * Return a float value.
+ */
+float
+SGPropertyNode::getFloatValue (const string &subpath, float defaultValue) const
+{
+  if (_props == 0)
+    return defaultValue;
+
+  if (subpath == "")
+    return _props->getFloatValue(_path, defaultValue);
+  else
+    return _props->getFloatValue(_path + string("/") + subpath,
+                                defaultValue);
+}
+
+
+/**
+ * Return a double value.
+ */
+double
+SGPropertyNode::getDoubleValue (const string &subpath,
+                               double defaultValue) const
+{
+  if (_props == 0)
+    return defaultValue;
+
+  if (subpath == "")
+    return _props->getDoubleValue(_path, defaultValue);
+  else
+    return _props->getDoubleValue(_path + string("/") + subpath,
+                                 defaultValue);
+}
+
+
+/**
+ * Return a string value.
+ */
+const string &
+SGPropertyNode::getStringValue (const string &subpath,
+                               const string &defaultValue) const
+{
+  if (_props == 0)
+    return defaultValue;
+
+  if (subpath == "")
+    return _props->getStringValue(_path, defaultValue);
+  else
+    return _props->getStringValue(_path + string("/") + subpath,
+                                 defaultValue);
+}
+
+
 // end of props.cxx