X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fprops%2Fprops.cxx;h=9524e78e47a90ed6194965c2f9f0ec401e8dd2e3;hb=efa2876e29305717103765e37fe19eb9cba30fd6;hp=f73e773e02577527387536758494aed5ea4b81bf;hpb=3c312c55f1f474a1da1850af0027be460744daa4;p=simgear.git diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index f73e773e..9524e78e 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -6,14 +6,21 @@ // // $Id$ +#ifdef HAVE_CONFIG_H +# include +#endif + #include "props.hxx" #include #include +#include #include #include +#include + #if PROPS_STANDALONE #include #else @@ -39,6 +46,7 @@ using std::string; using std::vector; using std::stringstream; +using namespace simgear; //////////////////////////////////////////////////////////////////////// @@ -64,22 +72,8 @@ public: #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt #define TEST_WRITE if (!getAttribute(WRITE)) return false - - -//////////////////////////////////////////////////////////////////////// -// Default values for every type. -//////////////////////////////////////////////////////////////////////// - -template<> const bool SGRawValue::DefaultValue = false; -template<> const int SGRawValue::DefaultValue = 0; -template<> const long SGRawValue::DefaultValue = 0L; -template<> const float SGRawValue::DefaultValue = 0.0; -template<> const double SGRawValue::DefaultValue = 0.0L; -template<> const char * const SGRawValue::DefaultValue = ""; - - //////////////////////////////////////////////////////////////////////// // Local path normalization code. //////////////////////////////////////////////////////////////////////// @@ -229,11 +223,13 @@ parse_path (const string &path, vector &components) static char * copy_string (const char * s) { - // FIXME: potential buffer overflow. - // For some reason, strnlen and - // strncpy cause all kinds of crashes. - char * copy = new char[strlen(s) + 1]; - strcpy(copy, s); + unsigned long int slen = strlen(s); + char * copy = new char[slen + 1]; + + // the source string length is known so no need to check for '\0' + // when copying every single character + memcpy(copy, s, slen); + *(copy + slen) = '\0'; return copy; } @@ -247,17 +243,40 @@ compare_strings (const char * s1, const char * s2) * Locate a child node by name and index. */ static int -find_child (const char * name, int index, const vector& nodes) +find_child (const char * name, int index, const PropertyList& nodes) { int nNodes = nodes.size(); for (int i = 0; i < nNodes; i++) { SGPropertyNode * node = nodes[i]; - if (compare_strings(node->getName(), name) && node->getIndex() == index) + + // searching for a mathing index is a lot less time consuming than + // comparing two strings so do that first. + if (node->getIndex() == index && compare_strings(node->getName(), name)) return i; } return -1; } +/** + * Locate the child node with the highest index of the same name + */ +static int +find_last_child (const char * name, const PropertyList& nodes) +{ + int nNodes = nodes.size(); + int index = 0; + + for (int i = 0; i < nNodes; i++) { + SGPropertyNode * node = nodes[i]; + if (compare_strings(node->getName(), name)) + { + int idx = node->getIndex(); + if (idx > index) index = idx; + } + } + return index; +} + /** * Locate another node, given a relative path. @@ -317,7 +336,7 @@ inline bool SGPropertyNode::get_bool () const { if (_tied) - return _value.bool_val->getValue(); + return static_cast*>(_value.val)->getValue(); else return _local_val.bool_val; } @@ -326,7 +345,7 @@ inline int SGPropertyNode::get_int () const { if (_tied) - return _value.int_val->getValue(); + return (static_cast*>(_value.val))->getValue(); else return _local_val.int_val; } @@ -335,7 +354,7 @@ inline long SGPropertyNode::get_long () const { if (_tied) - return _value.long_val->getValue(); + return static_cast*>(_value.val)->getValue(); else return _local_val.long_val; } @@ -344,7 +363,7 @@ inline float SGPropertyNode::get_float () const { if (_tied) - return _value.float_val->getValue(); + return static_cast*>(_value.val)->getValue(); else return _local_val.float_val; } @@ -353,7 +372,7 @@ inline double SGPropertyNode::get_double () const { if (_tied) - return _value.double_val->getValue(); + return static_cast*>(_value.val)->getValue(); else return _local_val.double_val; } @@ -362,7 +381,7 @@ inline const char * SGPropertyNode::get_string () const { if (_tied) - return _value.string_val->getValue(); + return static_cast*>(_value.val)->getValue(); else return _local_val.string_val; } @@ -371,7 +390,7 @@ inline bool SGPropertyNode::set_bool (bool val) { if (_tied) { - if (_value.bool_val->setValue(val)) { + if (static_cast*>(_value.val)->setValue(val)) { fireValueChanged(); return true; } else { @@ -388,7 +407,7 @@ inline bool SGPropertyNode::set_int (int val) { if (_tied) { - if (_value.int_val->setValue(val)) { + if (static_cast*>(_value.val)->setValue(val)) { fireValueChanged(); return true; } else { @@ -405,7 +424,7 @@ inline bool SGPropertyNode::set_long (long val) { if (_tied) { - if (_value.long_val->setValue(val)) { + if (static_cast*>(_value.val)->setValue(val)) { fireValueChanged(); return true; } else { @@ -422,7 +441,7 @@ inline bool SGPropertyNode::set_float (float val) { if (_tied) { - if (_value.float_val->setValue(val)) { + if (static_cast*>(_value.val)->setValue(val)) { fireValueChanged(); return true; } else { @@ -439,7 +458,7 @@ inline bool SGPropertyNode::set_double (double val) { if (_tied) { - if (_value.double_val->setValue(val)) { + if (static_cast*>(_value.val)->setValue(val)) { fireValueChanged(); return true; } else { @@ -456,7 +475,7 @@ inline bool SGPropertyNode::set_string (const char * val) { if (_tied) { - if (_value.string_val->setValue(val)) { + if (static_cast*>(_value.val)->setValue(val)) { fireValueChanged(); return true; } else { @@ -473,61 +492,39 @@ SGPropertyNode::set_string (const char * val) void SGPropertyNode::clearValue () { - switch (_type) { - case NONE: - break; - case ALIAS: - put(_value.alias); - _value.alias = 0; - break; - case BOOL: - if (_tied) { - delete _value.bool_val; - _value.bool_val = 0; - } - _local_val.bool_val = SGRawValue::DefaultValue; - break; - case INT: - if (_tied) { - delete _value.int_val; - _value.int_val = 0; - } - _local_val.int_val = SGRawValue::DefaultValue; - break; - case LONG: - if (_tied) { - delete _value.long_val; - _value.long_val = 0L; + if (_type == props::ALIAS) { + put(_value.alias); + _value.alias = 0; + } else if (_type != props::NONE) { + switch (_type) { + case props::BOOL: + _local_val.bool_val = SGRawValue::DefaultValue(); + break; + case props::INT: + _local_val.int_val = SGRawValue::DefaultValue(); + break; + case props::LONG: + _local_val.long_val = SGRawValue::DefaultValue(); + break; + case props::FLOAT: + _local_val.float_val = SGRawValue::DefaultValue(); + break; + case props::DOUBLE: + _local_val.double_val = SGRawValue::DefaultValue(); + break; + case props::STRING: + case props::UNSPECIFIED: + if (!_tied) { + delete [] _local_val.string_val; + } + _local_val.string_val = 0; + break; + } + delete _value.val; + _value.val = 0; } - _local_val.long_val = SGRawValue::DefaultValue; - break; - case FLOAT: - if (_tied) { - delete _value.float_val; - _value.float_val = 0; - } - _local_val.float_val = SGRawValue::DefaultValue; - break; - case DOUBLE: - if (_tied) { - delete _value.double_val; - _value.double_val = 0; - } - _local_val.double_val = SGRawValue::DefaultValue; - break; - case STRING: - case UNSPECIFIED: - if (_tied) { - delete _value.string_val; - _value.string_val = 0; - } else { - delete [] _local_val.string_val; - } - _local_val.string_val = 0; - break; - } - _tied = false; - _type = NONE; + _tied = false; + _type = props::NONE; } @@ -537,53 +534,49 @@ SGPropertyNode::clearValue () const char * SGPropertyNode::make_string () const { - if (!getAttribute(READ)) - return ""; - - switch (_type) { - case ALIAS: - return _value.alias->getStringValue(); - case BOOL: - if (get_bool()) - return "true"; - else - return "false"; - case INT: - { - stringstream sstr; - sstr << get_int(); - _buffer = sstr.str(); - return _buffer.c_str(); + if (!getAttribute(READ)) + return ""; + switch (_type) { + case props::ALIAS: + return _value.alias->getStringValue(); + case props::BOOL: + return get_bool() ? "true" : "false"; + case props::STRING: + case props::UNSPECIFIED: + return get_string(); + case props::NONE: + return ""; + default: + break; } - case LONG: - { - stringstream sstr; - sstr << get_long(); - _buffer = sstr.str(); - return _buffer.c_str(); - } - case FLOAT: + stringstream sstr; + switch (_type) { + case props::INT: + sstr << get_int(); + break; + case props::LONG: + sstr << get_long(); + break; + case props::FLOAT: + sstr << get_float(); + break; + case props::DOUBLE: + sstr << std::setprecision(10) << get_double(); + break; + case props::EXTENDED: { - stringstream sstr; - sstr << get_float(); - _buffer = sstr.str(); - return _buffer.c_str(); + props::Type realType = _value.val->getType(); + // Perhaps this should be done for all types? + if (realType == props::VEC3D || realType == props::VEC4D) + sstr.precision(10); + static_cast(_value.val)->printOn(sstr); } - case DOUBLE: - { - stringstream sstr; - sstr.precision( 10 ); - sstr << get_double(); - _buffer = sstr.str(); - return _buffer.c_str(); + break; + default: + return ""; } - case STRING: - case UNSPECIFIED: - return get_string(); - case NONE: - default: - return ""; - } + _buffer = sstr.str(); + return _buffer.c_str(); } /** @@ -634,12 +627,13 @@ SGPropertyNode::SGPropertyNode () : _index(0), _parent(0), _path_cache(0), - _type(NONE), + _type(props::NONE), _tied(false), _attr(READ|WRITE), _listeners(0) { _local_val.string_val = 0; + _value.val = 0; } @@ -657,68 +651,40 @@ SGPropertyNode::SGPropertyNode (const SGPropertyNode &node) _listeners(0) // CHECK!! { _local_val.string_val = 0; - switch (_type) { - case NONE: - break; - case ALIAS: + _value.val = 0; + if (_type == props::NONE) + return; + if (_type == props::ALIAS) { _value.alias = node._value.alias; get(_value.alias); _tied = false; + return; + } + if (_tied || _type == props::EXTENDED) { + _value.val = node._value.val->clone(); + return; + } + switch (_type) { + case props::BOOL: + set_bool(node.get_bool()); break; - case BOOL: - if (_tied) { - _tied = true; - _value.bool_val = node._value.bool_val->clone(); - } else { - _tied = false; - set_bool(node.get_bool()); - } + case props::INT: + set_int(node.get_int()); break; - case INT: - if (_tied) { - _tied = true; - _value.int_val = node._value.int_val->clone(); - } else { - _tied = false; - set_int(node.get_int()); - } + case props::LONG: + set_long(node.get_long()); break; - case LONG: - if (_tied) { - _tied = true; - _value.long_val = node._value.long_val->clone(); - } else { - _tied = false; - set_long(node.get_long()); - } + case props::FLOAT: + set_float(node.get_float()); break; - case FLOAT: - if (_tied) { - _tied = true; - _value.float_val = node._value.float_val->clone(); - } else { - _tied = false; - set_float(node.get_float()); - } + case props::DOUBLE: + set_double(node.get_double()); break; - case DOUBLE: - if (_tied) { - _tied = true; - _value.double_val = node._value.double_val->clone(); - } else { - _tied = false; - set_double(node.get_double()); - } + case props::STRING: + case props::UNSPECIFIED: + set_string(node.get_string()); break; - case STRING: - case UNSPECIFIED: - if (_tied) { - _tied = true; - _value.string_val = node._value.string_val->clone(); - } else { - _tied = false; - set_string(node.get_string()); - } + default: break; } } @@ -733,17 +699,17 @@ SGPropertyNode::SGPropertyNode (const char * name, : _index(index), _parent(parent), _path_cache(0), - _type(NONE), + _type(props::NONE), _tied(false), _attr(READ|WRITE), _listeners(0) { int i = 0; + _local_val.string_val = 0; + _value.val = 0; _name = parse_name(name, i); if (i != int(strlen(name)) || name[0] == '.') throw string("plain name expected instead of '") + name + '\''; - - _local_val.string_val = 0; } @@ -775,12 +741,12 @@ SGPropertyNode::~SGPropertyNode () bool SGPropertyNode::alias (SGPropertyNode * target) { - if (target == 0 || _type == ALIAS || _tied) + if (target == 0 || _type == props::ALIAS || _tied) return false; clearValue(); get(target); _value.alias = target; - _type = ALIAS; + _type = props::ALIAS; return true; } @@ -801,7 +767,7 @@ SGPropertyNode::alias (const char * path) bool SGPropertyNode::unalias () { - if (_type != ALIAS) + if (_type != props::ALIAS) return false; clearValue(); return true; @@ -814,14 +780,29 @@ SGPropertyNode::unalias () SGPropertyNode * SGPropertyNode::getAliasTarget () { - return (_type == ALIAS ? _value.alias : 0); + return (_type == props::ALIAS ? _value.alias : 0); } const SGPropertyNode * SGPropertyNode::getAliasTarget () const { - return (_type == ALIAS ? _value.alias : 0); + return (_type == props::ALIAS ? _value.alias : 0); +} + +/** + * create a non-const child by name after the last node with the same name. + */ +SGPropertyNode * +SGPropertyNode::addChild (const char * name) +{ + int pos = find_last_child(name, _children)+1; + + SGPropertyNode_ptr node; + node = new SGPropertyNode(name, pos, this); + _children.push_back(node); + fireChildAdded(node); + return node; } @@ -864,7 +845,7 @@ SGPropertyNode::getChild (const char * name, int index, bool create) SGPropertyNode_ptr node; pos = find_child(name, index, _removedChildren); if (pos >= 0) { - vector::iterator it = _removedChildren.begin(); + PropertyList::iterator it = _removedChildren.begin(); it += pos; node = _removedChildren[pos]; _removedChildren.erase(it); @@ -898,10 +879,10 @@ SGPropertyNode::getChild (const char * name, int index) const /** * Get all children with the same name (but different indices). */ -vector +PropertyList SGPropertyNode::getChildren (const char * name) const { - vector children; + PropertyList children; int max = _children.size(); for (int i = 0; i < max; i++) @@ -939,7 +920,7 @@ SGPropertyNode::removeChild (int pos, bool keep) if (pos < 0 || pos >= (int)_children.size()) return node; - vector::iterator it = _children.begin(); + PropertyList::iterator it = _children.begin(); it += pos; node = _children[pos]; _children.erase(it); @@ -972,10 +953,10 @@ SGPropertyNode::removeChild (const char * name, int index, bool keep) /** * Remove all children with the specified name. */ -vector +PropertyList SGPropertyNode::removeChildren (const char * name, bool keep) { - vector children; + PropertyList children; for (int pos = _children.size() - 1; pos >= 0; pos--) if (compare_strings(_children[pos]->getName(), name)) @@ -1004,16 +985,16 @@ SGPropertyNode::remove_linked_node (hash_table * node) } -const char * +string SGPropertyNode::getDisplayName (bool simplify) const { - _display_name = _name; + string display_name = _name; if (_index != 0 || !simplify) { stringstream sstr; sstr << '[' << _index << ']'; - _display_name += sstr.str(); + display_name += sstr.str(); } - return _display_name.c_str(); + return display_name; } @@ -1030,11 +1011,13 @@ SGPropertyNode::getPath (bool simplify) const return _path.c_str(); } -SGPropertyNode::Type +props::Type SGPropertyNode::getType () const { - if (_type == ALIAS) + if (_type == props::ALIAS) return _value.alias->getType(); + else if (_type == props::EXTENDED) + return _value.val->getType(); else return _type; } @@ -1044,32 +1027,32 @@ bool SGPropertyNode::getBoolValue () const { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == BOOL) + if (_attr == (READ|WRITE) && _type == props::BOOL) return get_bool(); if (getAttribute(TRACE_READ)) trace_read(); if (!getAttribute(READ)) - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); switch (_type) { - case ALIAS: + case props::ALIAS: return _value.alias->getBoolValue(); - case BOOL: + case props::BOOL: return get_bool(); - case INT: + case props::INT: return get_int() == 0 ? false : true; - case LONG: + case props::LONG: return get_long() == 0L ? false : true; - case FLOAT: + case props::FLOAT: return get_float() == 0.0 ? false : true; - case DOUBLE: + case props::DOUBLE: return get_double() == 0.0L ? false : true; - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L); - case NONE: + case props::NONE: default: - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); } } @@ -1077,32 +1060,32 @@ int SGPropertyNode::getIntValue () const { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == INT) + if (_attr == (READ|WRITE) && _type == props::INT) return get_int(); if (getAttribute(TRACE_READ)) trace_read(); if (!getAttribute(READ)) - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); switch (_type) { - case ALIAS: + case props::ALIAS: return _value.alias->getIntValue(); - case BOOL: + case props::BOOL: return int(get_bool()); - case INT: + case props::INT: return get_int(); - case LONG: + case props::LONG: return int(get_long()); - case FLOAT: + case props::FLOAT: return int(get_float()); - case DOUBLE: + case props::DOUBLE: return int(get_double()); - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: return atoi(get_string()); - case NONE: + case props::NONE: default: - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); } } @@ -1110,32 +1093,32 @@ long SGPropertyNode::getLongValue () const { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == LONG) + if (_attr == (READ|WRITE) && _type == props::LONG) return get_long(); if (getAttribute(TRACE_READ)) trace_read(); if (!getAttribute(READ)) - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); switch (_type) { - case ALIAS: + case props::ALIAS: return _value.alias->getLongValue(); - case BOOL: + case props::BOOL: return long(get_bool()); - case INT: + case props::INT: return long(get_int()); - case LONG: + case props::LONG: return get_long(); - case FLOAT: + case props::FLOAT: return long(get_float()); - case DOUBLE: + case props::DOUBLE: return long(get_double()); - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: return strtol(get_string(), 0, 0); - case NONE: + case props::NONE: default: - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); } } @@ -1143,32 +1126,32 @@ float SGPropertyNode::getFloatValue () const { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == FLOAT) + if (_attr == (READ|WRITE) && _type == props::FLOAT) return get_float(); if (getAttribute(TRACE_READ)) trace_read(); if (!getAttribute(READ)) - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); switch (_type) { - case ALIAS: + case props::ALIAS: return _value.alias->getFloatValue(); - case BOOL: + case props::BOOL: return float(get_bool()); - case INT: + case props::INT: return float(get_int()); - case LONG: + case props::LONG: return float(get_long()); - case FLOAT: + case props::FLOAT: return get_float(); - case DOUBLE: + case props::DOUBLE: return float(get_double()); - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: return atof(get_string()); - case NONE: + case props::NONE: default: - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); } } @@ -1176,33 +1159,33 @@ double SGPropertyNode::getDoubleValue () const { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == DOUBLE) + if (_attr == (READ|WRITE) && _type == props::DOUBLE) return get_double(); if (getAttribute(TRACE_READ)) trace_read(); if (!getAttribute(READ)) - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); switch (_type) { - case ALIAS: + case props::ALIAS: return _value.alias->getDoubleValue(); - case BOOL: + case props::BOOL: return double(get_bool()); - case INT: + case props::INT: return double(get_int()); - case LONG: + case props::LONG: return double(get_long()); - case FLOAT: + case props::FLOAT: return double(get_float()); - case DOUBLE: + case props::DOUBLE: return get_double(); - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: return strtod(get_string(), 0); - case NONE: + case props::NONE: default: - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); } } @@ -1210,13 +1193,13 @@ const char * SGPropertyNode::getStringValue () const { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == STRING) + if (_attr == (READ|WRITE) && _type == props::STRING) return get_string(); if (getAttribute(TRACE_READ)) trace_read(); if (!getAttribute(READ)) - return SGRawValue::DefaultValue; + return SGRawValue::DefaultValue(); return make_string(); } @@ -1224,41 +1207,41 @@ bool SGPropertyNode::setBoolValue (bool value) { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == BOOL) + if (_attr == (READ|WRITE) && _type == props::BOOL) return set_bool(value); bool result = false; TEST_WRITE; - if (_type == NONE || _type == UNSPECIFIED) { + if (_type == props::NONE || _type == props::UNSPECIFIED) { clearValue(); _tied = false; - _type = BOOL; + _type = props::BOOL; } switch (_type) { - case ALIAS: + case props::ALIAS: result = _value.alias->setBoolValue(value); break; - case BOOL: + case props::BOOL: result = set_bool(value); break; - case INT: + case props::INT: result = set_int(int(value)); break; - case LONG: + case props::LONG: result = set_long(long(value)); break; - case FLOAT: + case props::FLOAT: result = set_float(float(value)); break; - case DOUBLE: + case props::DOUBLE: result = set_double(double(value)); break; - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: result = set_string(value ? "true" : "false"); break; - case NONE: + case props::NONE: default: break; } @@ -1272,44 +1255,44 @@ bool SGPropertyNode::setIntValue (int value) { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == INT) + if (_attr == (READ|WRITE) && _type == props::INT) return set_int(value); bool result = false; TEST_WRITE; - if (_type == NONE || _type == UNSPECIFIED) { + if (_type == props::NONE || _type == props::UNSPECIFIED) { clearValue(); - _type = INT; + _type = props::INT; _local_val.int_val = 0; } switch (_type) { - case ALIAS: + case props::ALIAS: result = _value.alias->setIntValue(value); break; - case BOOL: + case props::BOOL: result = set_bool(value == 0 ? false : true); break; - case INT: + case props::INT: result = set_int(value); break; - case LONG: + case props::LONG: result = set_long(long(value)); break; - case FLOAT: + case props::FLOAT: result = set_float(float(value)); break; - case DOUBLE: + case props::DOUBLE: result = set_double(double(value)); break; - case STRING: - case UNSPECIFIED: { + case props::STRING: + case props::UNSPECIFIED: { char buf[128]; sprintf(buf, "%d", value); result = set_string(buf); break; } - case NONE: + case props::NONE: default: break; } @@ -1323,44 +1306,44 @@ bool SGPropertyNode::setLongValue (long value) { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == LONG) + if (_attr == (READ|WRITE) && _type == props::LONG) return set_long(value); bool result = false; TEST_WRITE; - if (_type == NONE || _type == UNSPECIFIED) { + if (_type == props::NONE || _type == props::UNSPECIFIED) { clearValue(); - _type = LONG; + _type = props::LONG; _local_val.long_val = 0L; } switch (_type) { - case ALIAS: + case props::ALIAS: result = _value.alias->setLongValue(value); break; - case BOOL: + case props::BOOL: result = set_bool(value == 0L ? false : true); break; - case INT: + case props::INT: result = set_int(int(value)); break; - case LONG: + case props::LONG: result = set_long(value); break; - case FLOAT: + case props::FLOAT: result = set_float(float(value)); break; - case DOUBLE: + case props::DOUBLE: result = set_double(double(value)); break; - case STRING: - case UNSPECIFIED: { + case props::STRING: + case props::UNSPECIFIED: { char buf[128]; sprintf(buf, "%ld", value); result = set_string(buf); break; } - case NONE: + case props::NONE: default: break; } @@ -1374,44 +1357,44 @@ bool SGPropertyNode::setFloatValue (float value) { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == FLOAT) + if (_attr == (READ|WRITE) && _type == props::FLOAT) return set_float(value); bool result = false; TEST_WRITE; - if (_type == NONE || _type == UNSPECIFIED) { + if (_type == props::NONE || _type == props::UNSPECIFIED) { clearValue(); - _type = FLOAT; + _type = props::FLOAT; _local_val.float_val = 0; } switch (_type) { - case ALIAS: + case props::ALIAS: result = _value.alias->setFloatValue(value); break; - case BOOL: + case props::BOOL: result = set_bool(value == 0.0 ? false : true); break; - case INT: + case props::INT: result = set_int(int(value)); break; - case LONG: + case props::LONG: result = set_long(long(value)); break; - case FLOAT: + case props::FLOAT: result = set_float(value); break; - case DOUBLE: + case props::DOUBLE: result = set_double(double(value)); break; - case STRING: - case UNSPECIFIED: { + case props::STRING: + case props::UNSPECIFIED: { char buf[128]; sprintf(buf, "%f", value); result = set_string(buf); break; } - case NONE: + case props::NONE: default: break; } @@ -1425,44 +1408,44 @@ bool SGPropertyNode::setDoubleValue (double value) { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == DOUBLE) + if (_attr == (READ|WRITE) && _type == props::DOUBLE) return set_double(value); bool result = false; TEST_WRITE; - if (_type == NONE || _type == UNSPECIFIED) { + if (_type == props::NONE || _type == props::UNSPECIFIED) { clearValue(); _local_val.double_val = value; - _type = DOUBLE; + _type = props::DOUBLE; } switch (_type) { - case ALIAS: + case props::ALIAS: result = _value.alias->setDoubleValue(value); break; - case BOOL: + case props::BOOL: result = set_bool(value == 0.0L ? false : true); break; - case INT: + case props::INT: result = set_int(int(value)); break; - case LONG: + case props::LONG: result = set_long(long(value)); break; - case FLOAT: + case props::FLOAT: result = set_float(float(value)); break; - case DOUBLE: + case props::DOUBLE: result = set_double(value); break; - case STRING: - case UNSPECIFIED: { + case props::STRING: + case props::UNSPECIFIED: { char buf[128]; sprintf(buf, "%f", value); result = set_string(buf); break; } - case NONE: + case props::NONE: default: break; } @@ -1476,41 +1459,47 @@ bool SGPropertyNode::setStringValue (const char * value) { // Shortcut for common case - if (_attr == (READ|WRITE) && _type == STRING) + if (_attr == (READ|WRITE) && _type == props::STRING) return set_string(value); bool result = false; TEST_WRITE; - if (_type == NONE || _type == UNSPECIFIED) { + if (_type == props::NONE || _type == props::UNSPECIFIED) { clearValue(); - _type = STRING; + _type = props::STRING; } switch (_type) { - case ALIAS: + case props::ALIAS: result = _value.alias->setStringValue(value); break; - case BOOL: + case props::BOOL: result = set_bool((compare_strings(value, "true") || atoi(value)) ? true : false); break; - case INT: + case props::INT: result = set_int(atoi(value)); break; - case LONG: + case props::LONG: result = set_long(strtol(value, 0, 0)); break; - case FLOAT: + case props::FLOAT: result = set_float(atof(value)); break; - case DOUBLE: + case props::DOUBLE: result = set_double(strtod(value, 0)); break; - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: result = set_string(value); break; - case NONE: + case props::EXTENDED: + { + stringstream sstr(value); + static_cast(_value.val)->readFrom(sstr); + } + break; + case props::NONE: default: break; } @@ -1525,36 +1514,44 @@ SGPropertyNode::setUnspecifiedValue (const char * value) { bool result = false; TEST_WRITE; - if (_type == NONE) { + if (_type == props::NONE) { clearValue(); - _type = UNSPECIFIED; + _type = props::UNSPECIFIED; } - - switch (_type) { - case ALIAS: + props::Type type = _type; + if (type == props::EXTENDED) + type = _value.val->getType(); + switch (type) { + case props::ALIAS: result = _value.alias->setUnspecifiedValue(value); break; - case BOOL: + case props::BOOL: result = set_bool((compare_strings(value, "true") || atoi(value)) ? true : false); break; - case INT: + case props::INT: result = set_int(atoi(value)); break; - case LONG: + case props::LONG: result = set_long(strtol(value, 0, 0)); break; - case FLOAT: + case props::FLOAT: result = set_float(atof(value)); break; - case DOUBLE: + case props::DOUBLE: result = set_double(strtod(value, 0)); break; - case STRING: - case UNSPECIFIED: + case props::STRING: + case props::UNSPECIFIED: result = set_string(value); break; - case NONE: + case props::VEC3D: + result = static_cast*>(_value.val)->setValue(parseString(value)); + break; + case props::VEC4D: + result = static_cast*>(_value.val)->setValue(parseString(value)); + break; + case props::NONE: default: break; } @@ -1564,139 +1561,62 @@ SGPropertyNode::setUnspecifiedValue (const char * value) return result; } -bool -SGPropertyNode::tie (const SGRawValue &rawValue, bool useDefault) -{ - if (_type == ALIAS || _tied) - return false; - - useDefault = useDefault && hasValue(); - bool old_val = false; - if (useDefault) - old_val = getBoolValue(); - - clearValue(); - _type = BOOL; - _tied = true; - _value.bool_val = rawValue.clone(); - - if (useDefault) - setBoolValue(old_val); - - return true; -} - -bool -SGPropertyNode::tie (const SGRawValue &rawValue, bool useDefault) -{ - if (_type == ALIAS || _tied) - return false; - - useDefault = useDefault && hasValue(); - int old_val = 0; - if (useDefault) - old_val = getIntValue(); - - clearValue(); - _type = INT; - _tied = true; - _value.int_val = rawValue.clone(); - - if (useDefault) - setIntValue(old_val); - - return true; -} - -bool -SGPropertyNode::tie (const SGRawValue &rawValue, bool useDefault) -{ - if (_type == ALIAS || _tied) - return false; - - useDefault = useDefault && hasValue(); - long old_val = 0; - if (useDefault) - old_val = getLongValue(); - - clearValue(); - _type = LONG; - _tied = true; - _value.long_val = rawValue.clone(); - - if (useDefault) - setLongValue(old_val); - - return true; -} - -bool -SGPropertyNode::tie (const SGRawValue &rawValue, bool useDefault) -{ - if (_type == ALIAS || _tied) - return false; - - useDefault = useDefault && hasValue(); - float old_val = 0.0; - if (useDefault) - old_val = getFloatValue(); - - clearValue(); - _type = FLOAT; - _tied = true; - _value.float_val = rawValue.clone(); - - if (useDefault) - setFloatValue(old_val); - - return true; -} - -bool -SGPropertyNode::tie (const SGRawValue &rawValue, bool useDefault) -{ - if (_type == ALIAS || _tied) - return false; - - useDefault = useDefault && hasValue(); - double old_val = 0.0; - if (useDefault) - old_val = getDoubleValue(); - - clearValue(); - _type = DOUBLE; - _tied = true; - _value.double_val = rawValue.clone(); - - if (useDefault) - setDoubleValue(old_val); - - return true; - +std::ostream& SGPropertyNode::printOn(std::ostream& stream) const +{ + if (!getAttribute(READ)) + return stream; + switch (_type) { + case props::ALIAS: + return _value.alias->printOn(stream); + case props::BOOL: + stream << (get_bool() ? "true" : "false"); + break; + case props::INT: + stream << get_int(); + break; + case props::LONG: + stream << get_long(); + break; + case props::FLOAT: + stream << get_float(); + break; + case props::DOUBLE: + stream << get_double(); + break; + case props::STRING: + case props::UNSPECIFIED: + stream << get_string(); + break; + case props::EXTENDED: + static_cast(_value.val)->printOn(stream); + break; + case props::NONE: + break; + } + return stream; } -bool -SGPropertyNode::tie (const SGRawValue &rawValue, bool useDefault) +template<> +bool SGPropertyNode::tie (const SGRawValue &rawValue, + bool useDefault) { - if (_type == ALIAS || _tied) - return false; + if (_type == props::ALIAS || _tied) + return false; - useDefault = useDefault && hasValue(); - string old_val; - if (useDefault) - old_val = getStringValue(); - - clearValue(); - _type = STRING; - _tied = true; - _value.string_val = rawValue.clone(); + useDefault = useDefault && hasValue(); + std::string old_val; + if (useDefault) + old_val = getStringValue(); + clearValue(); + _type = props::STRING; + _tied = true; + _value.val = rawValue.clone(); - if (useDefault) - setStringValue(old_val.c_str()); + if (useDefault) + setStringValue(old_val.c_str()); - return true; + return true; } - bool SGPropertyNode::untie () { @@ -1704,50 +1624,59 @@ SGPropertyNode::untie () return false; switch (_type) { - case BOOL: { + case props::BOOL: { bool val = getBoolValue(); clearValue(); - _type = BOOL; + _type = props::BOOL; _local_val.bool_val = val; break; } - case INT: { + case props::INT: { int val = getIntValue(); clearValue(); - _type = INT; + _type = props::INT; _local_val.int_val = val; break; } - case LONG: { + case props::LONG: { long val = getLongValue(); clearValue(); - _type = LONG; + _type = props::LONG; _local_val.long_val = val; break; } - case FLOAT: { + case props::FLOAT: { float val = getFloatValue(); clearValue(); - _type = FLOAT; + _type = props::FLOAT; _local_val.float_val = val; break; } - case DOUBLE: { + case props::DOUBLE: { double val = getDoubleValue(); clearValue(); - _type = DOUBLE; + _type = props::DOUBLE; _local_val.double_val = val; break; } - case STRING: - case UNSPECIFIED: { + case props::STRING: + case props::UNSPECIFIED: { string val = getStringValue(); clearValue(); - _type = STRING; + _type = props::STRING; _local_val.string_val = copy_string(val.c_str()); break; } - case NONE: + case props::EXTENDED: { + SGRawExtended* val = static_cast(_value.val); + _value.val = 0; // Prevent clearValue() from deleting + clearValue(); + _type = props::EXTENDED; + _value.val = val->makeContainer(); + delete val; + break; + } + case props::NONE: default: break; } @@ -1834,11 +1763,11 @@ SGPropertyNode::hasValue (const char * relative_path) const /** * Get the value type for another node. */ -SGPropertyNode::Type +props::Type SGPropertyNode::getType (const char * relative_path) const { const SGPropertyNode * node = getNode(relative_path); - return (node == 0 ? UNSPECIFIED : (Type)(node->getType())); + return (node == 0 ? props::UNSPECIFIED : node->getType()); } @@ -2374,5 +2303,53 @@ SGPropertyChangeListener::unregister_property (SGPropertyNode * node) _properties.erase(it); } +template<> +std::ostream& SGRawBase::printOn(std::ostream& stream) const +{ + const SGVec3d vec + = static_cast*>(this)->getValue(); + for (int i = 0; i < 3; ++i) { + stream << vec[i]; + if (i < 2) + stream << ' '; + } + return stream; +} + +namespace simgear +{ +template<> +std::istream& readFrom(std::istream& stream, SGVec3d& result) +{ + for (int i = 0; i < 3; ++i) { + stream >> result[i]; + } + return stream; +} +} +template<> +std::ostream& SGRawBase::printOn(std::ostream& stream) const +{ + const SGVec4d vec + = static_cast*>(this)->getValue(); + for (int i = 0; i < 4; ++i) { + stream << vec[i]; + if (i < 3) + stream << ' '; + } + return stream; +} + +namespace simgear +{ +template<> +std::istream& readFrom(std::istream& stream, SGVec4d& result) +{ + for (int i = 0; i < 4; ++i) { + stream >> result[i]; + } + return stream; +} +} // end of props.cxx