// $Id$
#include <simgear/compiler.h>
+#include <simgear/debug/logstream.hxx>
#include <stdio.h>
#include <stdlib.h>
#define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
#define TEST_WRITE if (!getAttribute(WRITE)) return false
+#define DO_TRACE_READ(type) if(getAttribute(TRACE_READ)) trace_read(type)
+#define DO_TRACE_WRITE(type) if (getAttribute(TRACE_WRITE)) trace_write(type)
+
#define GET_BOOL (_value.bool_val->getValue())
#define GET_INT (_value.int_val->getValue())
#define GET_LONG (_value.long_val->getValue())
: _name(""),
_index(0),
_parent(0),
+ _path_cache(0),
_type(NONE),
_tied(false),
_attr(READ|WRITE)
: _name(node._name),
_index(node._index),
_parent(0), // don't copy the parent
+ _path_cache(0),
_type(node._type),
_tied(node._tied),
_attr(node._attr)
*/
SGPropertyNode::SGPropertyNode (const string &name,
int index, SGPropertyNode * parent)
- : _name(name), _index(index), _parent(parent), _type(NONE),
- _tied(false), _attr(READ|WRITE)
+ : _name(name),
+ _index(index),
+ _parent(parent),
+ _path_cache(0),
+ _type(NONE),
+ _tied(false),
+ _attr(READ|WRITE)
{
}
*/
SGPropertyNode::~SGPropertyNode ()
{
- for (int i = 0; i < (int)_children.size(); i++)
+ for (int i = 0; i < (int)_children.size(); i++) {
delete _children[i];
+ }
+ delete _path_cache;
clear_value();
}
}
+/**
+ * Get the value as a string.
+ */
+string
+SGPropertyNode::get_string () const
+{
+ TEST_READ("");
+ char buf[128];
+
+ switch (_type) {
+ case ALIAS:
+ return _value.alias->getStringValue();
+ case BOOL:
+ if (GET_BOOL)
+ return "true";
+ else
+ return "false";
+ case INT:
+ sprintf(buf, "%d", GET_INT);
+ return buf;
+ case LONG:
+ sprintf(buf, "%ld", GET_LONG);
+ return buf;
+ case FLOAT:
+ sprintf(buf, "%f", GET_FLOAT);
+ return buf;
+ case DOUBLE:
+ sprintf(buf, "%f", GET_DOUBLE);
+ return buf;
+ case STRING:
+ case UNSPECIFIED:
+ return GET_STRING;
+ case NONE:
+ default:
+ return "";
+ }
+}
+
+
+/**
+ * Trace a read access for a property.
+ */
+void
+SGPropertyNode::trace_read (SGPropertyNode::Type accessType) const
+{
+ SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
+ << ", value \"" << get_string() << '"');
+}
+
+
+/**
+ * Trace a write access for a property.
+ */
+void
+SGPropertyNode::trace_write (SGPropertyNode::Type accessType) const
+{
+ SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
+ << ", value\"" << get_string() << '"');
+}
+
+
/**
* Alias to another node.
*/
bool
SGPropertyNode::getBoolValue () const
{
+ DO_TRACE_READ(BOOL);
TEST_READ(false);
switch (_type) {
case ALIAS:
case STRING:
case UNSPECIFIED:
return (GET_STRING == "true" || getDoubleValue() != 0.0L);
+ case NONE:
+ default:
+ return false;
}
-
- return false; // if NONE
}
int
SGPropertyNode::getIntValue () const
{
+ DO_TRACE_READ(INT);
TEST_READ(0);
switch (_type) {
case ALIAS:
case STRING:
case UNSPECIFIED:
return atoi(GET_STRING.c_str());
+ case NONE:
+ default:
+ return 0;
}
-
- return 0; // if NONE
}
long
SGPropertyNode::getLongValue () const
{
+ DO_TRACE_READ(LONG);
TEST_READ(0L);
switch (_type) {
case ALIAS:
case STRING:
case UNSPECIFIED:
return strtol(GET_STRING.c_str(), 0, 0);
+ case NONE:
+ default:
+ return 0L;
}
-
- return 0L; // if NONE
}
float
SGPropertyNode::getFloatValue () const
{
+ DO_TRACE_READ(FLOAT);
TEST_READ(0.0);
switch (_type) {
case ALIAS:
case STRING:
case UNSPECIFIED:
return atof(GET_STRING.c_str());
+ case NONE:
+ default:
+ return 0.0;
}
-
- return 0.0; // if NONE
}
double
SGPropertyNode::getDoubleValue () const
{
+ DO_TRACE_READ(DOUBLE);
TEST_READ(0.0L);
switch (_type) {
case ALIAS:
case STRING:
case UNSPECIFIED:
return strtod(GET_STRING.c_str(), 0);
+ case NONE:
+ default:
+ return 0.0L;
}
-
- return 0.0L; // if NONE
}
string
SGPropertyNode::getStringValue () const
{
- TEST_READ("");
- char buf[128];
-
- switch (_type) {
- case ALIAS:
- return _value.alias->getStringValue();
- case BOOL:
- if (GET_BOOL)
- return "true";
- else
- return "false";
- case INT:
- sprintf(buf, "%d", GET_INT);
- return buf;
- case LONG:
- sprintf(buf, "%ld", GET_LONG);
- return buf;
- case FLOAT:
- sprintf(buf, "%f", GET_FLOAT);
- return buf;
- case DOUBLE:
- sprintf(buf, "%f", GET_DOUBLE);
- return buf;
- case STRING:
- case UNSPECIFIED:
- return GET_STRING;
- }
-
- return ""; // if NONE
+ DO_TRACE_READ(STRING);
+ return get_string();
}
bool
SGPropertyNode::setBoolValue (bool value)
{
+ bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
switch (_type) {
case ALIAS:
- return _value.alias->setBoolValue(value);
+ result = _value.alias->setBoolValue(value);
+ break;
case BOOL:
- return SET_BOOL(value);
+ result = SET_BOOL(value);
+ break;
case INT:
- return SET_INT(int(value));
+ result = SET_INT(int(value));
+ break;
case LONG:
- return SET_LONG(long(value));
+ result = SET_LONG(long(value));
+ break;
case FLOAT:
- return SET_FLOAT(float(value));
+ result = SET_FLOAT(float(value));
+ break;
case DOUBLE:
- return SET_DOUBLE(double(value));
+ result = SET_DOUBLE(double(value));
+ break;
case STRING:
- return SET_STRING(value ? "true" : "false");
+ case UNSPECIFIED:
+ result = SET_STRING(value ? "true" : "false");
+ break;
+ case NONE:
+ default:
+ break;
}
- return false; // should never happen
+ DO_TRACE_WRITE(BOOL);
+ return result;
}
bool
SGPropertyNode::setIntValue (int value)
{
+ bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
switch (_type) {
case ALIAS:
- return _value.alias->setIntValue(value);
+ result = _value.alias->setIntValue(value);
+ break;
case BOOL:
- return SET_BOOL(value == 0 ? false : true);
+ result = SET_BOOL(value == 0 ? false : true);
+ break;
case INT:
- return SET_INT(value);
+ result = SET_INT(value);
+ break;
case LONG:
- return SET_LONG(long(value));
+ result = SET_LONG(long(value));
+ break;
case FLOAT:
- return SET_FLOAT(float(value));
+ result = SET_FLOAT(float(value));
+ break;
case DOUBLE:
- return SET_DOUBLE(double(value));
- case STRING: {
+ result = SET_DOUBLE(double(value));
+ break;
+ case STRING:
+ case UNSPECIFIED: {
char buf[128];
sprintf(buf, "%d", value);
- return SET_STRING(buf);
+ result = SET_STRING(buf);
+ break;
}
+ case NONE:
+ default:
+ break;
}
- return false; // should never happen
+ DO_TRACE_WRITE(INT);
+ return result;
}
bool
SGPropertyNode::setLongValue (long value)
{
+ bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
switch (_type) {
case ALIAS:
- return _value.alias->setLongValue(value);
+ result = _value.alias->setLongValue(value);
+ break;
case BOOL:
- return SET_BOOL(value == 0L ? false : true);
+ result = SET_BOOL(value == 0L ? false : true);
+ break;
case INT:
- return SET_INT(int(value));
+ result = SET_INT(int(value));
+ break;
case LONG:
- return SET_LONG(value);
+ result = SET_LONG(value);
+ break;
case FLOAT:
- return SET_FLOAT(float(value));
+ result = SET_FLOAT(float(value));
+ break;
case DOUBLE:
- return SET_DOUBLE(double(value));
- case STRING: {
+ result = SET_DOUBLE(double(value));
+ break;
+ case STRING:
+ case UNSPECIFIED: {
char buf[128];
- sprintf(buf, "%d", value);
- return SET_STRING(buf);
+ sprintf(buf, "%ld", value);
+ result = SET_STRING(buf);
+ break;
}
+ case NONE:
+ default:
+ break;
}
- return false; // should never happen
+ DO_TRACE_WRITE(LONG);
+ return result;
}
bool
SGPropertyNode::setFloatValue (float value)
{
+ bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
switch (_type) {
case ALIAS:
- return _value.alias->setFloatValue(value);
+ result = _value.alias->setFloatValue(value);
+ break;
case BOOL:
- return SET_BOOL(value == 0.0 ? false : true);
+ result = SET_BOOL(value == 0.0 ? false : true);
+ break;
case INT:
- return SET_INT(int(value));
+ result = SET_INT(int(value));
+ break;
case LONG:
- return SET_LONG(long(value));
+ result = SET_LONG(long(value));
+ break;
case FLOAT:
- return SET_FLOAT(value);
+ result = SET_FLOAT(value);
+ break;
case DOUBLE:
- return SET_DOUBLE(double(value));
- case STRING: {
+ result = SET_DOUBLE(double(value));
+ break;
+ case STRING:
+ case UNSPECIFIED: {
char buf[128];
sprintf(buf, "%f", value);
- return SET_STRING(buf);
+ result = SET_STRING(buf);
+ break;
}
+ case NONE:
+ default:
+ break;
}
- return false; // should never happen
+ DO_TRACE_WRITE(FLOAT);
+ return result;
}
bool
SGPropertyNode::setDoubleValue (double value)
{
+ bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
switch (_type) {
case ALIAS:
- return _value.alias->setDoubleValue(value);
+ result = _value.alias->setDoubleValue(value);
+ break;
case BOOL:
- return SET_BOOL(value == 0.0L ? false : true);
+ result = SET_BOOL(value == 0.0L ? false : true);
+ break;
case INT:
- return SET_INT(int(value));
+ result = SET_INT(int(value));
+ break;
case LONG:
- return SET_LONG(long(value));
+ result = SET_LONG(long(value));
+ break;
case FLOAT:
- return SET_FLOAT(float(value));
+ result = SET_FLOAT(float(value));
+ break;
case DOUBLE:
- return SET_DOUBLE(value);
- case STRING: {
+ result = SET_DOUBLE(value);
+ break;
+ case STRING:
+ case UNSPECIFIED: {
char buf[128];
- sprintf(buf, "%lf", value);
- return SET_STRING(buf);
+ sprintf(buf, "%f", value);
+ result = SET_STRING(buf);
+ break;
}
+ case NONE:
+ default:
+ break;
}
- return false; // should never happen
+ DO_TRACE_WRITE(DOUBLE);
+ return result;
}
bool
SGPropertyNode::setStringValue (string value)
{
+ bool result = false;
TEST_WRITE;
if (_type == NONE || _type == UNSPECIFIED) {
clear_value();
switch (_type) {
case ALIAS:
- return _value.alias->setStringValue(value);
+ result = _value.alias->setStringValue(value);
+ break;
case BOOL:
- return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
+ result = SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
+ break;
case INT:
- return SET_INT(atoi(value.c_str()));
+ result = SET_INT(atoi(value.c_str()));
+ break;
case LONG:
- return SET_LONG(strtol(value.c_str(), 0, 0));
+ result = SET_LONG(strtol(value.c_str(), 0, 0));
+ break;
case FLOAT:
- return SET_FLOAT(atof(value.c_str()));
+ result = SET_FLOAT(atof(value.c_str()));
+ break;
case DOUBLE:
- return SET_DOUBLE(strtod(value.c_str(), 0));
+ result = SET_DOUBLE(strtod(value.c_str(), 0));
+ break;
case STRING:
- return SET_STRING(value);
+ case UNSPECIFIED:
+ result = SET_STRING(value);
+ break;
+ case NONE:
+ default:
+ break;
}
- return false; // should never happen
+ DO_TRACE_WRITE(STRING);
+ return result;
}
bool
SGPropertyNode::setUnspecifiedValue (string value)
{
+ bool result = false;
TEST_WRITE;
if (_type == NONE) {
clear_value();
switch (_type) {
case ALIAS:
- return _value.alias->setUnspecifiedValue(value);
+ result = _value.alias->setUnspecifiedValue(value);
+ break;
case BOOL:
- return SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
+ result = SET_BOOL((value == "true" || atoi(value.c_str())) ? true : false);
+ break;
case INT:
- return SET_INT(atoi(value.c_str()));
+ result = SET_INT(atoi(value.c_str()));
+ break;
case LONG:
- return SET_LONG(strtol(value.c_str(), 0, 0));
+ result = SET_LONG(strtol(value.c_str(), 0, 0));
+ break;
case FLOAT:
- return SET_FLOAT(atof(value.c_str()));
+ result = SET_FLOAT(atof(value.c_str()));
+ break;
case DOUBLE:
- return SET_DOUBLE(strtod(value.c_str(), 0));
+ result = SET_DOUBLE(strtod(value.c_str(), 0));
+ break;
case STRING:
case UNSPECIFIED:
- return SET_STRING(value);
+ result = SET_STRING(value);
+ break;
+ case NONE:
+ default:
+ break;
}
- return false; // should never happen
+ DO_TRACE_WRITE(UNSPECIFIED);
+ return result;
}
bool
SET_DOUBLE(val);
break;
}
- case STRING: {
+ case STRING:
+ case UNSPECIFIED: {
string val = getStringValue();
clear_value();
_type = STRING;
SET_STRING(val);
break;
}
+ case NONE:
+ default:
+ break;
}
_tied = false;
SGPropertyNode *
SGPropertyNode::getNode (const string &relative_path, bool create)
+{
+ if (_path_cache == 0)
+ _path_cache = new cache_map;
+
+ SGPropertyNode * result = (*_path_cache)[relative_path];
+ if (result == 0) {
+ vector<PathComponent> components;
+ parse_path(relative_path, components);
+ result = find_node(this, components, 0, create);
+ (*_path_cache)[relative_path] = result;
+ }
+
+ return result;
+}
+
+SGPropertyNode *
+SGPropertyNode::getNode (const string &relative_path, int index, bool create)
{
vector<PathComponent> components;
parse_path(relative_path, components);
+ if (components.size() > 0)
+ components[components.size()-1].index = index;
return find_node(this, components, 0, create);
}
const SGPropertyNode *
SGPropertyNode::getNode (const string &relative_path) const
{
- vector<PathComponent> components;
- parse_path(relative_path, components);
- // FIXME: cast away const
- return find_node((SGPropertyNode *)this, components, 0, false);
+ return ((SGPropertyNode *)this)->getNode(relative_path, false);
}
+const SGPropertyNode *
+SGPropertyNode::getNode (const string &relative_path, int index) const
+{
+ return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
+}
\f
////////////////////////////////////////////////////////////////////////