-// props.cxx -- implementation of FGFS global properties.
+// props.cxx -- implementation of SimGear Property Manager.
//
-// Copyright (C) 2000 David Megginson - david@megginson.com
+// Written by David Megginson - david@megginson.com
//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
+// This module is in the PUBLIC DOMAIN.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+// See props.html for documentation [replace with URL when available].
//
// $Id$
*/
FGValue::~FGValue ()
{
- if (!_tied && _type == STRING) {
- delete _value.string_val;
- _value.string_val = 0;
- }
}
+/**
+ * Return a raw boolean value (no type coercion).
+ */
bool
FGValue::getRawBool () const
{
}
+/**
+ * Return a raw integer value (no type coercion).
+ */
int
FGValue::getRawInt () const
{
}
+/**
+ * Return a raw floating-point value (no type coercion).
+ */
float
FGValue::getRawFloat () const
{
}
+/**
+ * Return a raw double-precision floating-point value (no type coercion).
+ */
double
FGValue::getRawDouble () const
{
}
+/**
+ * Return a raw string value (no type coercion).
+ */
const string &
FGValue::getRawString () const
{
- if (_tied) {
- if (_value.string_func.getter != 0)
- return (*(_value.string_func.getter))();
- else
- return empty_string;
- } else {
- return *_value.string_val;
- }
+ if (_tied && _value.string_func.getter != 0)
+ return (*(_value.string_func.getter))();
+ else
+ return string_val;
}
+/**
+ * Set a raw boolean value (no type coercion).
+ *
+ * Return false if the value could not be set, true otherwise.
+ */
bool
FGValue::setRawBool (bool value)
{
}
+/**
+ * Set a raw integer value (no type coercion).
+ *
+ * Return false if the value could not be set, true otherwise.
+ */
bool
FGValue::setRawInt (int value)
{
}
+/**
+ * Set a raw floating-point value (no type coercion).
+ *
+ * Return false if the value could not be set, true otherwise.
+ */
bool
FGValue::setRawFloat (float value)
{
}
+/**
+ * Set a raw double-precision floating-point value (no type coercion).
+ *
+ * Return false if the value could not be set, true otherwise.
+ */
bool
FGValue::setRawDouble (double value)
{
}
+/**
+ * Set a raw string value (no type coercion).
+ *
+ * Return false if the value could not be set, true otherwise.
+ */
bool
FGValue::setRawString (const string &value)
{
return false;
}
} else {
- if (_value.string_val == 0)
- _value.string_val = new string;
- *(_value.string_val) = value;
+ string_val = value;
return true;
}
}
/**
- * Attempt to get the boolean value of a property.
+ * Get the boolean value of a property.
+ *
+ * If the native type is not boolean, attempt to coerce it.
*/
bool
FGValue::getBoolValue () const
{
switch (_type) {
- case UNKNOWN:
- return false;
case BOOL:
return getRawBool();
case INT:
return (getRawFloat() == 0.0 ? false : true);
case DOUBLE:
return (getRawDouble() == 0.0 ? false : true);
+ case UNKNOWN:
case STRING:
- return (getRawString() == "false" ? false : true);
+ return ((getRawString() == "false" || getIntValue() == 0) ? false : true);
}
-
return false;
}
/**
- * Attempt to get the integer value of a property.
+ * Get the integer value of a property.
+ *
+ * If the native type is not integer, attempt to coerce it.
*/
int
FGValue::getIntValue () const
{
switch (_type) {
- case UNKNOWN:
- return 0;
case BOOL:
return getRawBool();
case INT:
return (int)(getRawFloat());
case DOUBLE:
return (int)(getRawDouble());
+ case UNKNOWN:
case STRING:
return atoi(getRawString().c_str());
}
-
- return 0;
+ return false;
}
/**
- * Attempt to get the float value of a property.
+ * Get the floating-point value of a property.
+ *
+ * If the native type is not float, attempt to coerce it.
*/
float
FGValue::getFloatValue () const
case STRING:
return (float)atof(getRawString().c_str());
}
-
- return 0.0;
+ return false;
}
/**
- * Attempt to get the double value of a property.
+ * Get the double-precision floating-point value of a property.
+ *
+ * If the native type is not double, attempt to coerce it.
*/
double
FGValue::getDoubleValue () const
case STRING:
return atof(getRawString().c_str());
}
-
- return 0.0;
+ return false;
}
/**
- * Attempt to get the string value of a property.
+ * Get the string value of a property.
+ *
+ * If the native type is not string, attempt to coerce it.
*/
const string &
FGValue::getStringValue () const
{
+ char buf[512];
switch (_type) {
case UNKNOWN:
+ return getRawString();
case BOOL:
+ if (getRawBool())
+ string_val = "true";
+ else
+ string_val = "false";
+ return string_val;
case INT:
+ sprintf(buf, "%d", getRawInt());
+ string_val = buf;
+ return string_val;
case FLOAT:
+ sprintf(buf, "%f", getRawFloat());
+ string_val = buf;
+ return string_val;
case DOUBLE:
- return empty_string;
+ sprintf(buf, "%lf", getRawDouble());
+ string_val = buf;
+ return string_val;
case STRING:
return getRawString();
}
-
return empty_string;
}
+/**
+ * Set the boolean value and change the type if unknown.
+ *
+ * Returns true on success.
+ */
bool
FGValue::setBoolValue (bool value)
{
}
+/**
+ * Set the integer value and change the type if unknown.
+ *
+ * Returns true on success.
+ */
bool
FGValue::setIntValue (int value)
{
}
+/**
+ * Set the floating-point value and change the type if unknown.
+ *
+ * Returns true on success.
+ */
bool
FGValue::setFloatValue (float value)
{
}
+/**
+ * Set the double-precision value and change the type if unknown.
+ *
+ * Returns true on success.
+ */
bool
FGValue::setDoubleValue (double value)
{
}
+/**
+ * Set the string value and change the type if unknown.
+ *
+ * Returns true on success.
+ */
bool
FGValue::setStringValue (const string &value)
{
}
+/**
+ * Set a string value and don't modify the type.
+ *
+ * Returns true on success.
+ */
+bool
+FGValue::setUnknownValue (const string &value)
+{
+ if (_type == UNKNOWN || _type == STRING) {
+ return setRawString(value);
+ } else {
+ return false;
+ }
+}
+
+
+/**
+ * Tie a boolean value to external functions.
+ *
+ * If useDefault is true, attempt the assign the current value
+ * (if any) after tying the functions.
+ *
+ * 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)
}
+/**
+ * Tie an integer value to external functions.
+ *
+ * If useDefault is true, attempt the assign the current value
+ * (if any) after tying the functions.
+ *
+ * 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)
}
+/**
+ * Tie a floating-point value to external functions.
+ *
+ * If useDefault is true, attempt the assign the current value
+ * (if any) after tying the functions.
+ *
+ * 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)
}
+/**
+ * Tie a double-precision floating-point value to external functions.
+ *
+ * If useDefault is true, attempt the assign the current value
+ * (if any) after tying the functions.
+ *
+ * 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)
}
+/**
+ * Tie a string value to external functions.
+ *
+ * If useDefault is true, attempt the assign the current value
+ * (if any) after tying the functions.
+ *
+ * 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)
} else {
if (useDefault && setter && _type != UNKNOWN)
(*setter)(getStringValue());
- if (_type == STRING)
- delete _value.string_val;
_tied = true;
_type = STRING;
_value.string_func.getter = getter;
}
+/**
+ * Untie a value from external functions.
+ *
+ * Will always attempt to intialize the internal value from
+ * the getter before untying.
+ *
+ * Returns true on success (i.e. the value had been tied).
+ */
bool
-FGValue::untieBool ()
+FGValue::untie ()
{
- if (_tied && _type == BOOL) {
+ if (!_tied)
+ return false;
+
+ switch (_type) {
+ case BOOL: {
bool value = getRawBool();
- _value.bool_val = value;
_tied = false;
- return true;
- } else {
- return false;
+ setRawBool(value);
+ break;
}
-}
-
-
-bool
-FGValue::untieInt ()
-{
- if (_tied && _type == INT) {
+ case INT: {
int value = getRawInt();
- _value.int_val = value;
_tied = false;
- return true;
- } else {
- return false;
+ setRawInt(value);
+ break;
}
-}
-
-
-bool
-FGValue::untieFloat ()
-{
- if (_tied && _type == FLOAT) {
+ case FLOAT: {
float value = getRawFloat();
- _value.float_val = value;
_tied = false;
- return true;
- } else {
- return false;
+ setRawFloat(value);
+ break;
}
-}
-
-
-bool
-FGValue::untieDouble ()
-{
- if (_tied && _type == DOUBLE) {
+ case DOUBLE: {
double value = getRawDouble();
- _value.double_val = value;
_tied = false;
- return true;
- } else {
- return false;
+ setRawDouble(value);
+ break;
}
-}
-
-
-bool
-FGValue::untieString ()
-{
- if (_tied && _type == STRING) {
- const string &value = getRawString();
- _value.string_val = new string(value);
+ case STRING: {
+ string value = getRawString();
_tied = false;
- return true;
- } else {
- return false;
+ setRawString(value);
+ break;
}
+ }
+
+ return true;
}
// Implementation of FGPropertyList.
////////////////////////////////////////////////////////////////////////
+
+/**
+ * Constructor.
+ */
FGPropertyList::FGPropertyList ()
{
}
+
+/**
+ * Destructor.
+ */
FGPropertyList::~FGPropertyList ()
{
}
+/**
+ * Look up the FGValue 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)
{
return 0;
else {
FG_LOG(FG_GENERAL, FG_INFO, "Creating new property '" << name << '\'');
+ if (name.size() == 0 ||
+ name[0] != '/' ||
+ name[name.size()-1] == '/' ||
+ name.find("//") != string::npos) {
+ FG_LOG(FG_GENERAL, FG_ALERT, "Illegal property name: '"
+ << name << '\'');
+ return 0;
+ }
}
}
return &(_props[name]);
}
+/**
+ * Look up a const value (never created).
+ */
const FGValue *
FGPropertyList::getValue (const string &name) const
{
value_map::const_iterator el = _props.find(name);
- return &(el->second);
+ if (el == _props.end())
+ return 0;
+ else
+ return &(el->second);
}
+/**
+ * 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.
+ */
bool
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.
+ */
int
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.
+ */
float
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.
+ */
double
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.
+ */
const string &
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.
+ *
+ * Returns true on success.
+ */
bool
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.
+ *
+ * Returns true on success.
+ */
bool
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.
+ *
+ * Returns true on success.
+ */
bool
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.
+ *
+ * Returns true on success.
+ */
bool
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.
+ *
+ * Returns true on success.
+ */
bool
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.
+ *
+ * Returns true on success.
+ */
+bool
+FGPropertyList::setUnknownValue (const string &name, const string &value)
+{
+ return getValue(name, true)->setUnknownValue(value);
+}
+
+
+/**
+ * Tie a boolean value to external functions.
+ *
+ * Invokes FGValue::tieBool
+ */
bool
FGPropertyList::tieBool (const string &name,
bool_getter getter,
}
+/**
+ * Tie an integer value to external functions.
+ *
+ * Invokes FGValue::tieInt
+ */
bool
FGPropertyList::tieInt (const string &name,
int_getter getter,
}
+/**
+ * Tie a float value to external functions.
+ *
+ * Invokes FGValue::tieFloat
+ */
bool
FGPropertyList::tieFloat (const string &name,
float_getter getter,
}
+/**
+ * Tie a double value to external functions.
+ *
+ * Invokes FGValue::tieDouble
+ */
bool
FGPropertyList::tieDouble (const string &name,
double_getter getter,
}
+/**
+ * Tie a string value to external functions.
+ *
+ * Invokes FGValue::tieString
+ */
bool
FGPropertyList::tieString (const string &name,
string_getter getter,
}
+/**
+ * Untie a value from external functions.
+ *
+ * Invokes FGValue::untie
+ */
bool
-FGPropertyList::untieBool (const string &name)
+FGPropertyList::untie (const string &name)
{
- FG_LOG(FG_GENERAL, FG_INFO, "Untying bool property '" << name << '\'');
- return getValue(name, true)->untieBool();
+ FG_LOG(FG_GENERAL, FG_INFO, "Untying property '" << name << '\'');
+ return getValue(name, true)->untie();
}
-bool
-FGPropertyList::untieInt (const string &name)
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FGPropertyNode.
+////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Extract the base name of the next level down from the parent.
+ *
+ * The parent must have a '/' appended. Note that basename may
+ * be modified even if the test fails.
+ */
+static bool
+get_base (const string &parent, const string &child,
+ string &basename)
{
- FG_LOG(FG_GENERAL, FG_INFO, "Untying int property '" << name << '\'');
- return getValue(name, true)->untieInt();
+ // First, check that the parent name
+ // is a prefix of the child name, and
+ // extract the remainder
+ if (child.find(parent) != 0)
+ return false;
+
+ basename = child.substr(parent.size());
+
+ int pos = basename.find('/');
+ if (pos != string::npos) {
+ basename.resize(pos);
+ }
+
+ if (basename.size() == 0)
+ return false;
+ else
+ return true;
}
-bool
-FGPropertyList::untieFloat (const string &name)
+/**
+ * Constructor.
+ */
+FGPropertyNode::FGPropertyNode (const string &path = "",
+ FGPropertyList * props = 0)
+ : _props(props)
{
- FG_LOG(FG_GENERAL, FG_INFO, "Untying float property '" << name << '\'');
- return getValue(name, true)->untieFloat();
+ setPath(path);
}
-bool
-FGPropertyList::untieDouble (const string &name)
+/**
+ * Destructor.
+ */
+FGPropertyNode::~FGPropertyNode ()
{
- FG_LOG(FG_GENERAL, FG_INFO, "Untying double property '" << name << '\'');
- return getValue(name, true)->untieDouble();
}
-bool
-FGPropertyList::untieString (const string &name)
+/**
+ * Set the path.
+ *
+ * Strip the trailing '/', if any.
+ */
+void
+FGPropertyNode::setPath (const string &path)
{
- FG_LOG(FG_GENERAL, FG_INFO, "Untying string property '" << name << '\'');
- return getValue(name, true)->untieString();
+ _path = path;
+
+ // Chop the final '/', if present.
+ if (_path.size() > 0 && _path[_path.size()-1] == '/')
+ _path.resize(_path.size()-1);
}
-void
-FGPropertyList::dumpToLog () const
+/**
+ * Return the local name of the property.
+ *
+ * The local name is just everything after the last slash.
+ */
+const string &
+FGPropertyNode::getName () const
+{
+ int pos = _path.rfind('/');
+ if (pos != string::npos) {
+ _name = _path.substr(pos+1);
+ return _name;
+ } else {
+ return empty_string;
+ }
+}
+
+
+/**
+ * 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
{
- const_iterator it = FGPropertyList::begin();
- FG_LOG(FG_GENERAL, FG_INFO, "Begin property list dump...");
- while (it != end()) {
- FG_LOG(FG_GENERAL, FG_INFO, "Property: " << it->first);
+ if (_props == 0)
+ return 0;
+
+ int s = 0;
+
+ string base;
+ string lastBase;
+ string pattern = _path;
+ pattern += '/';
+
+ FGPropertyList::const_iterator it = _props->begin();
+ FGPropertyList::const_iterator end = _props->end();
+ while (it != end) {
+ if (get_base(pattern, it->first, base) && base != lastBase) {
+ s++;
+ lastBase = base;
+ }
it++;
}
- FG_LOG(FG_GENERAL, FG_INFO, "...End property list dump");
+
+ return s;
}
+/**
+ * Initialize a node to represent this node's parent.
+ *
+ * A return value of true means success; otherwise, the node supplied
+ * is unmodified.
+ */
+bool
+FGPropertyNode::getParent (FGPropertyNode &parent) const
+{
+ int pos = _path.rfind('/');
+ if (pos != string::npos) {
+ parent.setPath(_path.substr(0, pos-1));
+ parent.setPropertyList(_props);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+/**
+ * Initialize a node to represent this node's nth child.
+ *
+ * A return value of true means success; otherwise, the node supplied
+ * is unmodified.
+ */
+bool
+FGPropertyNode::getChild (FGPropertyNode &child, int n) const
+{
+ if (_props == 0)
+ return false;
+
+ int s = 0;
+ string base;
+ string lastBase;
+ string pattern = _path;
+ pattern += '/';
+
+ FGPropertyList::const_iterator it = _props->begin();
+ FGPropertyList::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;
+ } else {
+ s++;
+ lastBase = base;
+ }
+ }
+ it++;
+ }
+
+ return false;
+}
// end of props.cxx
-// props.hxx -- class to manage global FlightGear properties.
+// props.hxx -- declaration of SimGear Property Manager.
//
-// Copyright (C) 2000 David Megginson - david@megginson.com
+// Written by David Megginson - david@megginson.com
//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
+// This module is in the PUBLIC DOMAIN.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+// See props.html for documentation [replace with URL when available].
//
// $Id$
-
#ifndef __PROPS_HXX
#define __PROPS_HXX
+#include <stdio.h>
+
#include <string>
#include <map>
virtual bool setFloatValue (float value);
virtual bool setDoubleValue (double value);
virtual bool setStringValue (const string &value);
+ virtual bool setUnknownValue (const string &value);
// Tie to external variables.
virtual bool tieBool (bool_getter getter,
bool useDefault = true);
// Untie from external variables.
- virtual bool untieBool ();
- virtual bool untieInt ();
- virtual bool untieFloat ();
- virtual bool untieDouble ();
- virtual bool untieString ();
+ virtual bool untie ();
protected:
Type _type;
bool _tied;
+ mutable string string_val;
+
// The value is one of the following...
union {
int int_val;
float float_val;
double double_val;
- string * string_val;
struct {
bool_setter setter;
virtual bool setFloatValue (const string &name, float value);
virtual bool setDoubleValue (const string &name, double value);
virtual bool setStringValue (const string &name, const string &value);
+ virtual bool setUnknownValue (const string &name, const string &value);
virtual bool tieBool (const string &name,
bool_getter getter,
string_setter setter = 0,
bool useDefault = true);
- virtual bool untieBool (const string &name);
- virtual bool untieInt (const string &name);
- virtual bool untieFloat (const string &name);
- virtual bool untieDouble (const string &name);
- virtual bool untieString (const string &name);
-
- virtual void dumpToLog () const;
+ virtual bool untie (const string &name);
private:
value_map _props;
};
+\f
+////////////////////////////////////////////////////////////////////////
+// Tree/node/directory view.
+////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Tree view of a property list.
+ *
+ * This class provides a virtual tree view of a property list, without
+ * actually constructing a tree -- the view always stays in sync with
+ * the property list itself.
+ *
+ * This class is designed to be used for setup and configuration; it is
+ * optimized for ease of use rather than performance, and shouldn't be
+ * used inside a tight loop.
+ *
+ * Every node is actually just a path together with a pointer to
+ * the real property list and a few convenient operations; to the
+ * user, however, it looks like a node in a tree or a file system,
+ * with the regular operations such as getChild and getParent.
+ *
+ * Note that a node may be both a branch and a leaf -- that is, it
+ * may have a value itself and it may have children. Here is a simple
+ * example that prints the names of all of the different nodes inside
+ * "/controls":
+ *
+ * FGPropertyNode controls("/controls", current_property_list);
+ * FGPropertyNode child;
+ * int size = controls.size();
+ * for (int i = 0; i < size; i++) {
+ * if (controls.getChild(child, i))
+ * cout << child.getName() << endl;
+ * else
+ * cerr << "Failed to read child " << i << endl;
+ * }
+ */
+class FGPropertyNode
+{
+public:
+ // Constructor and destructor
+ FGPropertyNode (const string &path = "", FGPropertyList * props = 0);
+ virtual ~FGPropertyNode ();
+
+ // Accessor and setter for the internal
+ // path.
+ virtual const string &getPath () const { return _path; }
+ virtual void setPath (const string &path);
+
+ // Accessor and setter for the real
+ // property list.
+ virtual FGPropertyList * getPropertyList () { return _props; }
+ virtual void setPropertyList (FGPropertyList * props) {
+ _props = props;
+ }
+
+ // Accessors for derived information.
+ virtual int size () const;
+ virtual const string &getName () const;
+ virtual FGValue * getValue ();
+ virtual bool getParent (FGPropertyNode &parent) const;
+ virtual bool getChild (FGPropertyNode &child, int n) const;
+
+private:
+ string _path;
+ mutable string _name; // for pointer persistence only
+ FGPropertyList * _props;
+};
+
+
\f
////////////////////////////////////////////////////////////////////////
// Global property manager.
#endif __PROPS_HXX
+
+// end of props.hxx