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)
{
}
/**
* Destroy a value.
*/
-FGValue::~FGValue ()
+SGValue::~SGValue ()
{
}
* Return a raw boolean value (no type coercion).
*/
bool
-FGValue::getRawBool () const
+SGValue::getRawBool () const
{
if (_tied) {
if (_value.bool_func.getter != 0)
* Return a raw integer value (no type coercion).
*/
int
-FGValue::getRawInt () const
+SGValue::getRawInt () const
{
if (_tied) {
if (_value.int_func.getter != 0)
* Return a raw floating-point value (no type coercion).
*/
float
-FGValue::getRawFloat () const
+SGValue::getRawFloat () const
{
if (_tied) {
if (_value.float_func.getter != 0)
* 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)
* 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))();
* 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) {
* 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) {
* 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) {
* 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) {
* 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) {
* If the native type is not boolean, attempt to coerce it.
*/
bool
-FGValue::getBoolValue () const
+SGValue::getBoolValue () const
{
switch (_type) {
case BOOL:
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;
}
* If the native type is not integer, attempt to coerce it.
*/
int
-FGValue::getIntValue () const
+SGValue::getIntValue () const
{
switch (_type) {
case BOOL:
* 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:
return getRawFloat();
case DOUBLE:
return (float)(getRawDouble());
+ case UNKNOWN:
case STRING:
return (float)atof(getRawString().c_str());
}
* 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:
return (double)(getRawFloat());
case DOUBLE:
return getRawDouble();
+ case UNKNOWN:
case STRING:
return atof(getRawString().c_str());
}
* 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";
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();
}
* 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;
}
* 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;
}
* 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;
}
* 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;
}
* 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;
}
* 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;
}
* 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;
* 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;
* 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;
* 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;
* 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;
* Returns true on success (i.e. the value had been tied).
*/
bool
-FGValue::untie ()
+SGValue::untie ()
{
if (!_tied)
return false;
\f
////////////////////////////////////////////////////////////////////////
-// Implementation of FGPropertyList.
+// Implementation of SGPropertyList.
////////////////////////////////////////////////////////////////////////
/**
* Constructor.
*/
-FGPropertyList::FGPropertyList ()
+SGPropertyList::SGPropertyList ()
{
}
/**
* 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()) {
/**
* 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())
* 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();
}
* 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();
}
* 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();
}
* 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();
}
* 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();
}
* 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);
}
* 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);
}
* 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);
}
* 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);
}
* 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);
}
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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);
}
/**
* 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();
\f
////////////////////////////////////////////////////////////////////////
-// Implementation of FGPropertyNode.
+// Implementation of SGPropertyNode.
////////////////////////////////////////////////////////////////////////
basename = child.substr(parent.size());
- int pos = basename.find('/');
+ string::size_type pos = basename.find('/');
if (pos != string::npos) {
basename.resize(pos);
}
/**
* Constructor.
*/
-FGPropertyNode::FGPropertyNode (const string &path = "",
- FGPropertyList * props = 0)
- : _props(props)
+SGPropertyNode::SGPropertyNode (const string &path,
+ SGPropertyList * props)
+ : _props(props), _node(0)
{
setPath(path);
}
/**
* Destructor.
*/
-FGPropertyNode::~FGPropertyNode ()
+SGPropertyNode::~SGPropertyNode ()
{
+ delete _node;
+ _node = 0;
}
* Strip the trailing '/', if any.
*/
void
-FGPropertyNode::setPath (const string &path)
+SGPropertyNode::setPath (const string &path)
{
_path = 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;
}
-/**
- * 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;
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++;
* 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;
}
* 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;
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;
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