1 // props.cxx - implementation of a property list.
2 // Started Fall 2000 by David Megginson, david@megginson.com
3 // This code is released into the Public Domain.
5 // See props.html for documentation [replace with URL when available].
18 #include <simgear/math/SGMath.hxx>
24 #include <simgear/compiler.h>
25 #include <simgear/debug/logstream.hxx>
27 #if ( _MSC_VER == 1200 )
28 // MSVC 6 is buggy, and needs something strange here
29 using std::vector<SGPropertyNode_ptr>;
30 using std::vector<SGPropertyChangeListener *>;
31 using std::vector<SGPropertyNode *>;
43 using std::stringstream;
45 using namespace simgear;
48 ////////////////////////////////////////////////////////////////////////
50 ////////////////////////////////////////////////////////////////////////
53 * Comparator class for sorting by index.
58 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
59 return (n1->getIndex() < n2->getIndex());
65 ////////////////////////////////////////////////////////////////////////
66 // Convenience macros for value access.
67 ////////////////////////////////////////////////////////////////////////
69 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
70 #define TEST_WRITE if (!getAttribute(WRITE)) return false
73 ////////////////////////////////////////////////////////////////////////
74 // Local path normalization code.
75 ////////////////////////////////////////////////////////////////////////
78 * A component in a path.
87 * Parse the name for a path component.
89 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
91 static inline const string
92 parse_name (const string &path, int &i)
95 int max = path.size();
99 if (i < max && path[i] == '.') {
105 if (i < max && path[i] != '/')
106 throw string("illegal character after " + name);
109 else if (isalpha(path[i]) || path[i] == '_') {
113 // The rules inside a name are a little
116 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
117 path[i] == '-' || path[i] == '.') {
119 } else if (path[i] == '[' || path[i] == '/') {
122 throw string("name may contain only ._- and alphanumeric characters");
129 if (name.size() == 0)
130 throw string("name must begin with alpha or '_'");
138 * Parse the optional integer index for a path component.
140 * Index: "[" [0-9]+ "]"
143 parse_index (const string &path, int &i)
152 for (int max = path.size(); i < max; i++) {
153 if (isdigit(path[i])) {
154 index = (index * 10) + (path[i] - '0');
155 } else if (path[i] == ']') {
163 throw string("unterminated index (looking for ']')");
168 * Parse a single path component.
170 * Component: Name Index?
172 static inline PathComponent
173 parse_component (const string &path, int &i)
175 PathComponent component;
176 component.name = parse_name(path, i);
177 if (component.name[0] != '.')
178 component.index = parse_index(path, i);
180 component.index = -1;
186 * Parse a path into its components.
189 parse_path (const string &path, vector<PathComponent> &components)
192 int max = path.size();
194 // Check for initial '/'
195 if (path[pos] == '/') {
199 components.push_back(root);
201 while (pos < max && path[pos] == '/')
206 components.push_back(parse_component(path, pos));
207 while (pos < max && path[pos] == '/')
214 ////////////////////////////////////////////////////////////////////////
215 // Other static utility functions.
216 ////////////////////////////////////////////////////////////////////////
220 copy_string (const char * s)
222 unsigned long int slen = strlen(s);
223 char * copy = new char[slen + 1];
225 // the source string length is known so no need to check for '\0'
226 // when copying every single character
227 memcpy(copy, s, slen);
228 *(copy + slen) = '\0';
233 compare_strings (const char * s1, const char * s2)
235 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
239 * Locate a child node by name and index.
242 find_child (const char * name, int index, const PropertyList& nodes)
244 int nNodes = nodes.size();
245 for (int i = 0; i < nNodes; i++) {
246 SGPropertyNode * node = nodes[i];
248 // searching for a mathing index is a lot less time consuming than
249 // comparing two strings so do that first.
250 if (node->getIndex() == index && compare_strings(node->getName(), name))
257 * Locate the child node with the highest index of the same name
260 find_last_child (const char * name, const PropertyList& nodes)
262 int nNodes = nodes.size();
265 for (int i = 0; i < nNodes; i++) {
266 SGPropertyNode * node = nodes[i];
267 if (compare_strings(node->getName(), name))
269 int idx = node->getIndex();
270 if (idx > index) index = idx;
278 * Locate another node, given a relative path.
280 static SGPropertyNode *
281 find_node (SGPropertyNode * current,
282 const vector<PathComponent> &components,
286 // Run off the end of the list
291 // Success! This is the one we want.
292 else if (position >= (int)components.size()) {
293 return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
296 // Empty component means root.
297 else if (components[position].name == "") {
298 return find_node(current->getRootNode(), components, position + 1, create);
301 // . means current directory
302 else if (components[position].name == ".") {
303 return find_node(current, components, position + 1, create);
306 // .. means parent directory
307 else if (components[position].name == "..") {
308 SGPropertyNode * parent = current->getParent();
310 throw string("attempt to move past root with '..'");
312 return find_node(parent, components, position + 1, create);
315 // Otherwise, a child name
317 SGPropertyNode * child =
318 current->getChild(components[position].name.c_str(),
319 components[position].index,
321 return find_node(child, components, position + 1, create);
327 ////////////////////////////////////////////////////////////////////////
328 // Private methods from SGPropertyNode (may be inlined for speed).
329 ////////////////////////////////////////////////////////////////////////
332 SGPropertyNode::get_bool () const
335 return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
337 return _local_val.bool_val;
341 SGPropertyNode::get_int () const
344 return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
346 return _local_val.int_val;
350 SGPropertyNode::get_long () const
353 return static_cast<SGRawValue<long>*>(_value.val)->getValue();
355 return _local_val.long_val;
359 SGPropertyNode::get_float () const
362 return static_cast<SGRawValue<float>*>(_value.val)->getValue();
364 return _local_val.float_val;
368 SGPropertyNode::get_double () const
371 return static_cast<SGRawValue<double>*>(_value.val)->getValue();
373 return _local_val.double_val;
377 SGPropertyNode::get_string () const
380 return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
382 return _local_val.string_val;
386 SGPropertyNode::set_bool (bool val)
389 if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
396 _local_val.bool_val = val;
403 SGPropertyNode::set_int (int val)
406 if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
413 _local_val.int_val = val;
420 SGPropertyNode::set_long (long val)
423 if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
430 _local_val.long_val = val;
437 SGPropertyNode::set_float (float val)
440 if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
447 _local_val.float_val = val;
454 SGPropertyNode::set_double (double val)
457 if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
464 _local_val.double_val = val;
471 SGPropertyNode::set_string (const char * val)
474 if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
481 delete [] _local_val.string_val;
482 _local_val.string_val = copy_string(val);
489 SGPropertyNode::clearValue ()
491 if (_type == props::ALIAS) {
494 } else if (_type != props::NONE) {
497 _local_val.bool_val = SGRawValue<bool>::DefaultValue();
500 _local_val.int_val = SGRawValue<int>::DefaultValue();
503 _local_val.long_val = SGRawValue<long>::DefaultValue();
506 _local_val.float_val = SGRawValue<float>::DefaultValue();
509 _local_val.double_val = SGRawValue<double>::DefaultValue();
512 case props::UNSPECIFIED:
514 delete [] _local_val.string_val;
516 _local_val.string_val = 0;
528 * Get the value as a string.
531 SGPropertyNode::make_string () const
533 if (!getAttribute(READ))
537 return _value.alias->getStringValue();
539 return get_bool() ? "true" : "false";
541 case props::UNSPECIFIED:
560 sstr << std::setprecision(10) << get_double();
562 case props::EXTENDED:
564 props::Type realType = _value.val->getType();
565 // Perhaps this should be done for all types?
566 if (realType == props::VEC3D || realType == props::VEC4D)
568 static_cast<SGRawExtended*>(_value.val)->printOn(sstr);
574 _buffer = sstr.str();
575 return _buffer.c_str();
579 * Trace a write access for a property.
582 SGPropertyNode::trace_write () const
585 cerr << "TRACE: Write node " << getPath () << ", value \""
586 << make_string() << '"' << endl;
588 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
589 << ", value \"" << make_string() << '"');
594 * Trace a read access for a property.
597 SGPropertyNode::trace_read () const
600 cerr << "TRACE: Write node " << getPath () << ", value \""
601 << make_string() << '"' << endl;
603 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
604 << ", value \"" << make_string() << '"');
609 ////////////////////////////////////////////////////////////////////////
610 // Public methods from SGPropertyNode.
611 ////////////////////////////////////////////////////////////////////////
614 * Last used attribute
615 * Update as needed when enum Attribute is changed
617 const int SGPropertyNode::LAST_USED_ATTRIBUTE = USERARCHIVE;
620 * Default constructor: always creates a root node.
622 SGPropertyNode::SGPropertyNode ()
631 _local_val.string_val = 0;
639 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
640 : _index(node._index),
642 _parent(0), // don't copy the parent
647 _listeners(0) // CHECK!!
649 _local_val.string_val = 0;
651 if (_type == props::NONE)
653 if (_type == props::ALIAS) {
654 _value.alias = node._value.alias;
659 if (_tied || _type == props::EXTENDED) {
660 _value.val = node._value.val->clone();
665 set_bool(node.get_bool());
668 set_int(node.get_int());
671 set_long(node.get_long());
674 set_float(node.get_float());
677 set_double(node.get_double());
680 case props::UNSPECIFIED:
681 set_string(node.get_string());
690 * Convenience constructor.
692 SGPropertyNode::SGPropertyNode (const char * name,
694 SGPropertyNode * parent)
704 _local_val.string_val = 0;
706 _name = parse_name(name, i);
707 if (i != int(strlen(name)) || name[0] == '.')
708 throw string("plain name expected instead of '") + name + '\'';
715 SGPropertyNode::~SGPropertyNode ()
717 // zero out all parent pointers, else they might be dangling
718 for (unsigned i = 0; i < _children.size(); ++i)
719 _children[i]->_parent = 0;
720 for (unsigned i = 0; i < _removedChildren.size(); ++i)
721 _removedChildren[i]->_parent = 0;
726 vector<SGPropertyChangeListener*>::iterator it;
727 for (it = _listeners->begin(); it != _listeners->end(); ++it)
728 (*it)->unregister_property(this);
735 * Alias to another node.
738 SGPropertyNode::alias (SGPropertyNode * target)
740 if (target == 0 || _type == props::ALIAS || _tied)
744 _value.alias = target;
745 _type = props::ALIAS;
751 * Alias to another node by path.
754 SGPropertyNode::alias (const char * path)
756 return alias(getNode(path, true));
764 SGPropertyNode::unalias ()
766 if (_type != props::ALIAS)
774 * Get the target of an alias.
777 SGPropertyNode::getAliasTarget ()
779 return (_type == props::ALIAS ? _value.alias : 0);
783 const SGPropertyNode *
784 SGPropertyNode::getAliasTarget () const
786 return (_type == props::ALIAS ? _value.alias : 0);
790 * create a non-const child by name after the last node with the same name.
793 SGPropertyNode::addChild (const char * name)
795 int pos = find_last_child(name, _children)+1;
797 SGPropertyNode_ptr node;
798 node = new SGPropertyNode(name, pos, this);
799 _children.push_back(node);
800 fireChildAdded(node);
806 * Get a non-const child by index.
809 SGPropertyNode::getChild (int position)
811 if (position >= 0 && position < nChildren())
812 return _children[position];
819 * Get a const child by index.
821 const SGPropertyNode *
822 SGPropertyNode::getChild (int position) const
824 if (position >= 0 && position < nChildren())
825 return _children[position];
832 * Get a non-const child by name and index, creating if necessary.
835 SGPropertyNode::getChild (const char * name, int index, bool create)
837 int pos = find_child(name, index, _children);
839 return _children[pos];
841 SGPropertyNode_ptr node;
842 pos = find_child(name, index, _removedChildren);
844 PropertyList::iterator it = _removedChildren.begin();
846 node = _removedChildren[pos];
847 _removedChildren.erase(it);
848 node->setAttribute(REMOVED, false);
850 node = new SGPropertyNode(name, index, this);
852 _children.push_back(node);
853 fireChildAdded(node);
862 * Get a const child by name and index.
864 const SGPropertyNode *
865 SGPropertyNode::getChild (const char * name, int index) const
867 int pos = find_child(name, index, _children);
869 return _children[pos];
876 * Get all children with the same name (but different indices).
879 SGPropertyNode::getChildren (const char * name) const
881 PropertyList children;
882 int max = _children.size();
884 for (int i = 0; i < max; i++)
885 if (compare_strings(_children[i]->getName(), name))
886 children.push_back(_children[i]);
888 sort(children.begin(), children.end(), CompareIndices());
894 * Remove this node and all children from nodes that link to them
895 * in their path cache.
898 SGPropertyNode::remove_from_path_caches ()
900 for (unsigned int i = 0; i < _children.size(); ++i)
901 _children[i]->remove_from_path_caches();
903 for (unsigned int i = 0; i < _linkedNodes.size(); i++)
904 _linkedNodes[i]->erase(this);
905 _linkedNodes.clear();
910 * Remove child by position.
913 SGPropertyNode::removeChild (int pos, bool keep)
915 SGPropertyNode_ptr node;
916 if (pos < 0 || pos >= (int)_children.size())
919 PropertyList::iterator it = _children.begin();
921 node = _children[pos];
924 _removedChildren.push_back(node);
927 node->remove_from_path_caches();
928 node->setAttribute(REMOVED, true);
930 fireChildRemoved(node);
936 * Remove a child node
939 SGPropertyNode::removeChild (const char * name, int index, bool keep)
941 SGPropertyNode_ptr ret;
942 int pos = find_child(name, index, _children);
944 ret = removeChild(pos, keep);
950 * Remove all children with the specified name.
953 SGPropertyNode::removeChildren (const char * name, bool keep)
955 PropertyList children;
957 for (int pos = _children.size() - 1; pos >= 0; pos--)
958 if (compare_strings(_children[pos]->getName(), name))
959 children.push_back(removeChild(pos, keep));
961 sort(children.begin(), children.end(), CompareIndices());
967 * Remove a linked node.
970 SGPropertyNode::remove_linked_node (hash_table * node)
972 for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
973 if (_linkedNodes[i] == node) {
974 vector<hash_table *>::iterator it = _linkedNodes.begin();
976 _linkedNodes.erase(it);
985 SGPropertyNode::getDisplayName (bool simplify) const
987 string display_name = _name;
988 if (_index != 0 || !simplify) {
990 sstr << '[' << _index << ']';
991 display_name += sstr.str();
998 SGPropertyNode::getPath (bool simplify) const
1000 // Calculate the complete path only once.
1001 if (_parent != 0 && _path.empty()) {
1002 _path = _parent->getPath(simplify);
1004 _path += getDisplayName(simplify);
1007 return _path.c_str();
1011 SGPropertyNode::getType () const
1013 if (_type == props::ALIAS)
1014 return _value.alias->getType();
1015 else if (_type == props::EXTENDED)
1016 return _value.val->getType();
1023 SGPropertyNode::getBoolValue () const
1025 // Shortcut for common case
1026 if (_attr == (READ|WRITE) && _type == props::BOOL)
1029 if (getAttribute(TRACE_READ))
1031 if (!getAttribute(READ))
1032 return SGRawValue<bool>::DefaultValue();
1035 return _value.alias->getBoolValue();
1039 return get_int() == 0 ? false : true;
1041 return get_long() == 0L ? false : true;
1043 return get_float() == 0.0 ? false : true;
1045 return get_double() == 0.0L ? false : true;
1047 case props::UNSPECIFIED:
1048 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1051 return SGRawValue<bool>::DefaultValue();
1056 SGPropertyNode::getIntValue () const
1058 // Shortcut for common case
1059 if (_attr == (READ|WRITE) && _type == props::INT)
1062 if (getAttribute(TRACE_READ))
1064 if (!getAttribute(READ))
1065 return SGRawValue<int>::DefaultValue();
1068 return _value.alias->getIntValue();
1070 return int(get_bool());
1074 return int(get_long());
1076 return int(get_float());
1078 return int(get_double());
1080 case props::UNSPECIFIED:
1081 return atoi(get_string());
1084 return SGRawValue<int>::DefaultValue();
1089 SGPropertyNode::getLongValue () const
1091 // Shortcut for common case
1092 if (_attr == (READ|WRITE) && _type == props::LONG)
1095 if (getAttribute(TRACE_READ))
1097 if (!getAttribute(READ))
1098 return SGRawValue<long>::DefaultValue();
1101 return _value.alias->getLongValue();
1103 return long(get_bool());
1105 return long(get_int());
1109 return long(get_float());
1111 return long(get_double());
1113 case props::UNSPECIFIED:
1114 return strtol(get_string(), 0, 0);
1117 return SGRawValue<long>::DefaultValue();
1122 SGPropertyNode::getFloatValue () const
1124 // Shortcut for common case
1125 if (_attr == (READ|WRITE) && _type == props::FLOAT)
1128 if (getAttribute(TRACE_READ))
1130 if (!getAttribute(READ))
1131 return SGRawValue<float>::DefaultValue();
1134 return _value.alias->getFloatValue();
1136 return float(get_bool());
1138 return float(get_int());
1140 return float(get_long());
1144 return float(get_double());
1146 case props::UNSPECIFIED:
1147 return atof(get_string());
1150 return SGRawValue<float>::DefaultValue();
1155 SGPropertyNode::getDoubleValue () const
1157 // Shortcut for common case
1158 if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1159 return get_double();
1161 if (getAttribute(TRACE_READ))
1163 if (!getAttribute(READ))
1164 return SGRawValue<double>::DefaultValue();
1168 return _value.alias->getDoubleValue();
1170 return double(get_bool());
1172 return double(get_int());
1174 return double(get_long());
1176 return double(get_float());
1178 return get_double();
1180 case props::UNSPECIFIED:
1181 return strtod(get_string(), 0);
1184 return SGRawValue<double>::DefaultValue();
1189 SGPropertyNode::getStringValue () const
1191 // Shortcut for common case
1192 if (_attr == (READ|WRITE) && _type == props::STRING)
1193 return get_string();
1195 if (getAttribute(TRACE_READ))
1197 if (!getAttribute(READ))
1198 return SGRawValue<const char *>::DefaultValue();
1199 return make_string();
1203 SGPropertyNode::setBoolValue (bool value)
1205 // Shortcut for common case
1206 if (_attr == (READ|WRITE) && _type == props::BOOL)
1207 return set_bool(value);
1209 bool result = false;
1211 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1214 _type = props::BOOL;
1219 result = _value.alias->setBoolValue(value);
1222 result = set_bool(value);
1225 result = set_int(int(value));
1228 result = set_long(long(value));
1231 result = set_float(float(value));
1234 result = set_double(double(value));
1237 case props::UNSPECIFIED:
1238 result = set_string(value ? "true" : "false");
1245 if (getAttribute(TRACE_WRITE))
1251 SGPropertyNode::setIntValue (int value)
1253 // Shortcut for common case
1254 if (_attr == (READ|WRITE) && _type == props::INT)
1255 return set_int(value);
1257 bool result = false;
1259 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1262 _local_val.int_val = 0;
1267 result = _value.alias->setIntValue(value);
1270 result = set_bool(value == 0 ? false : true);
1273 result = set_int(value);
1276 result = set_long(long(value));
1279 result = set_float(float(value));
1282 result = set_double(double(value));
1285 case props::UNSPECIFIED: {
1287 sprintf(buf, "%d", value);
1288 result = set_string(buf);
1296 if (getAttribute(TRACE_WRITE))
1302 SGPropertyNode::setLongValue (long value)
1304 // Shortcut for common case
1305 if (_attr == (READ|WRITE) && _type == props::LONG)
1306 return set_long(value);
1308 bool result = false;
1310 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1312 _type = props::LONG;
1313 _local_val.long_val = 0L;
1318 result = _value.alias->setLongValue(value);
1321 result = set_bool(value == 0L ? false : true);
1324 result = set_int(int(value));
1327 result = set_long(value);
1330 result = set_float(float(value));
1333 result = set_double(double(value));
1336 case props::UNSPECIFIED: {
1338 sprintf(buf, "%ld", value);
1339 result = set_string(buf);
1347 if (getAttribute(TRACE_WRITE))
1353 SGPropertyNode::setFloatValue (float value)
1355 // Shortcut for common case
1356 if (_attr == (READ|WRITE) && _type == props::FLOAT)
1357 return set_float(value);
1359 bool result = false;
1361 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1363 _type = props::FLOAT;
1364 _local_val.float_val = 0;
1369 result = _value.alias->setFloatValue(value);
1372 result = set_bool(value == 0.0 ? false : true);
1375 result = set_int(int(value));
1378 result = set_long(long(value));
1381 result = set_float(value);
1384 result = set_double(double(value));
1387 case props::UNSPECIFIED: {
1389 sprintf(buf, "%f", value);
1390 result = set_string(buf);
1398 if (getAttribute(TRACE_WRITE))
1404 SGPropertyNode::setDoubleValue (double value)
1406 // Shortcut for common case
1407 if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1408 return set_double(value);
1410 bool result = false;
1412 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1414 _local_val.double_val = value;
1415 _type = props::DOUBLE;
1420 result = _value.alias->setDoubleValue(value);
1423 result = set_bool(value == 0.0L ? false : true);
1426 result = set_int(int(value));
1429 result = set_long(long(value));
1432 result = set_float(float(value));
1435 result = set_double(value);
1438 case props::UNSPECIFIED: {
1440 sprintf(buf, "%f", value);
1441 result = set_string(buf);
1449 if (getAttribute(TRACE_WRITE))
1455 SGPropertyNode::setStringValue (const char * value)
1457 // Shortcut for common case
1458 if (_attr == (READ|WRITE) && _type == props::STRING)
1459 return set_string(value);
1461 bool result = false;
1463 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1465 _type = props::STRING;
1470 result = _value.alias->setStringValue(value);
1473 result = set_bool((compare_strings(value, "true")
1474 || atoi(value)) ? true : false);
1477 result = set_int(atoi(value));
1480 result = set_long(strtol(value, 0, 0));
1483 result = set_float(atof(value));
1486 result = set_double(strtod(value, 0));
1489 case props::UNSPECIFIED:
1490 result = set_string(value);
1492 case props::EXTENDED:
1494 stringstream sstr(value);
1495 static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1503 if (getAttribute(TRACE_WRITE))
1509 SGPropertyNode::setUnspecifiedValue (const char * value)
1511 bool result = false;
1513 if (_type == props::NONE) {
1515 _type = props::UNSPECIFIED;
1517 props::Type type = _type;
1518 if (type == props::EXTENDED)
1519 type = _value.val->getType();
1522 result = _value.alias->setUnspecifiedValue(value);
1525 result = set_bool((compare_strings(value, "true")
1526 || atoi(value)) ? true : false);
1529 result = set_int(atoi(value));
1532 result = set_long(strtol(value, 0, 0));
1535 result = set_float(atof(value));
1538 result = set_double(strtod(value, 0));
1541 case props::UNSPECIFIED:
1542 result = set_string(value);
1545 result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1548 result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1555 if (getAttribute(TRACE_WRITE))
1560 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1562 if (!getAttribute(READ))
1566 return _value.alias->printOn(stream);
1568 stream << (get_bool() ? "true" : "false");
1571 stream << get_int();
1574 stream << get_long();
1577 stream << get_float();
1580 stream << get_double();
1583 case props::UNSPECIFIED:
1584 stream << get_string();
1586 case props::EXTENDED:
1587 static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1596 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1599 if (_type == props::ALIAS || _tied)
1602 useDefault = useDefault && hasValue();
1603 std::string old_val;
1605 old_val = getStringValue();
1607 _type = props::STRING;
1609 _value.val = rawValue.clone();
1612 setStringValue(old_val.c_str());
1617 SGPropertyNode::untie ()
1624 bool val = getBoolValue();
1626 _type = props::BOOL;
1627 _local_val.bool_val = val;
1631 int val = getIntValue();
1634 _local_val.int_val = val;
1638 long val = getLongValue();
1640 _type = props::LONG;
1641 _local_val.long_val = val;
1644 case props::FLOAT: {
1645 float val = getFloatValue();
1647 _type = props::FLOAT;
1648 _local_val.float_val = val;
1651 case props::DOUBLE: {
1652 double val = getDoubleValue();
1654 _type = props::DOUBLE;
1655 _local_val.double_val = val;
1659 case props::UNSPECIFIED: {
1660 string val = getStringValue();
1662 _type = props::STRING;
1663 _local_val.string_val = copy_string(val.c_str());
1666 case props::EXTENDED: {
1667 SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1668 _value.val = 0; // Prevent clearValue() from deleting
1670 _type = props::EXTENDED;
1671 _value.val = val->makeContainer();
1685 SGPropertyNode::getRootNode ()
1690 return _parent->getRootNode();
1693 const SGPropertyNode *
1694 SGPropertyNode::getRootNode () const
1699 return _parent->getRootNode();
1703 SGPropertyNode::getNode (const char * relative_path, bool create)
1705 if (_path_cache == 0)
1706 _path_cache = new hash_table;
1708 SGPropertyNode * result = _path_cache->get(relative_path);
1710 vector<PathComponent> components;
1711 parse_path(relative_path, components);
1712 result = find_node(this, components, 0, create);
1714 _path_cache->put(relative_path, result);
1721 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1723 vector<PathComponent> components;
1724 parse_path(relative_path, components);
1725 if (components.size() > 0)
1726 components.back().index = index;
1727 return find_node(this, components, 0, create);
1730 const SGPropertyNode *
1731 SGPropertyNode::getNode (const char * relative_path) const
1733 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1736 const SGPropertyNode *
1737 SGPropertyNode::getNode (const char * relative_path, int index) const
1739 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1743 ////////////////////////////////////////////////////////////////////////
1744 // Convenience methods using relative paths.
1745 ////////////////////////////////////////////////////////////////////////
1749 * Test whether another node has a value attached.
1752 SGPropertyNode::hasValue (const char * relative_path) const
1754 const SGPropertyNode * node = getNode(relative_path);
1755 return (node == 0 ? false : node->hasValue());
1760 * Get the value type for another node.
1763 SGPropertyNode::getType (const char * relative_path) const
1765 const SGPropertyNode * node = getNode(relative_path);
1766 return (node == 0 ? props::UNSPECIFIED : node->getType());
1771 * Get a bool value for another node.
1774 SGPropertyNode::getBoolValue (const char * relative_path,
1775 bool defaultValue) const
1777 const SGPropertyNode * node = getNode(relative_path);
1778 return (node == 0 ? defaultValue : node->getBoolValue());
1783 * Get an int value for another node.
1786 SGPropertyNode::getIntValue (const char * relative_path,
1787 int defaultValue) const
1789 const SGPropertyNode * node = getNode(relative_path);
1790 return (node == 0 ? defaultValue : node->getIntValue());
1795 * Get a long value for another node.
1798 SGPropertyNode::getLongValue (const char * relative_path,
1799 long defaultValue) const
1801 const SGPropertyNode * node = getNode(relative_path);
1802 return (node == 0 ? defaultValue : node->getLongValue());
1807 * Get a float value for another node.
1810 SGPropertyNode::getFloatValue (const char * relative_path,
1811 float defaultValue) const
1813 const SGPropertyNode * node = getNode(relative_path);
1814 return (node == 0 ? defaultValue : node->getFloatValue());
1819 * Get a double value for another node.
1822 SGPropertyNode::getDoubleValue (const char * relative_path,
1823 double defaultValue) const
1825 const SGPropertyNode * node = getNode(relative_path);
1826 return (node == 0 ? defaultValue : node->getDoubleValue());
1831 * Get a string value for another node.
1834 SGPropertyNode::getStringValue (const char * relative_path,
1835 const char * defaultValue) const
1837 const SGPropertyNode * node = getNode(relative_path);
1838 return (node == 0 ? defaultValue : node->getStringValue());
1843 * Set a bool value for another node.
1846 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1848 return getNode(relative_path, true)->setBoolValue(value);
1853 * Set an int value for another node.
1856 SGPropertyNode::setIntValue (const char * relative_path, int value)
1858 return getNode(relative_path, true)->setIntValue(value);
1863 * Set a long value for another node.
1866 SGPropertyNode::setLongValue (const char * relative_path, long value)
1868 return getNode(relative_path, true)->setLongValue(value);
1873 * Set a float value for another node.
1876 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1878 return getNode(relative_path, true)->setFloatValue(value);
1883 * Set a double value for another node.
1886 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1888 return getNode(relative_path, true)->setDoubleValue(value);
1893 * Set a string value for another node.
1896 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1898 return getNode(relative_path, true)->setStringValue(value);
1903 * Set an unknown value for another node.
1906 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1909 return getNode(relative_path, true)->setUnspecifiedValue(value);
1914 * Test whether another node is tied.
1917 SGPropertyNode::isTied (const char * relative_path) const
1919 const SGPropertyNode * node = getNode(relative_path);
1920 return (node == 0 ? false : node->isTied());
1925 * Tie a node reached by a relative path, creating it if necessary.
1928 SGPropertyNode::tie (const char * relative_path,
1929 const SGRawValue<bool> &rawValue,
1932 return getNode(relative_path, true)->tie(rawValue, useDefault);
1937 * Tie a node reached by a relative path, creating it if necessary.
1940 SGPropertyNode::tie (const char * relative_path,
1941 const SGRawValue<int> &rawValue,
1944 return getNode(relative_path, true)->tie(rawValue, useDefault);
1949 * Tie a node reached by a relative path, creating it if necessary.
1952 SGPropertyNode::tie (const char * relative_path,
1953 const SGRawValue<long> &rawValue,
1956 return getNode(relative_path, true)->tie(rawValue, useDefault);
1961 * Tie a node reached by a relative path, creating it if necessary.
1964 SGPropertyNode::tie (const char * relative_path,
1965 const SGRawValue<float> &rawValue,
1968 return getNode(relative_path, true)->tie(rawValue, useDefault);
1973 * Tie a node reached by a relative path, creating it if necessary.
1976 SGPropertyNode::tie (const char * relative_path,
1977 const SGRawValue<double> &rawValue,
1980 return getNode(relative_path, true)->tie(rawValue, useDefault);
1985 * Tie a node reached by a relative path, creating it if necessary.
1988 SGPropertyNode::tie (const char * relative_path,
1989 const SGRawValue<const char *> &rawValue,
1992 return getNode(relative_path, true)->tie(rawValue, useDefault);
1997 * Attempt to untie another node reached by a relative path.
2000 SGPropertyNode::untie (const char * relative_path)
2002 SGPropertyNode * node = getNode(relative_path);
2003 return (node == 0 ? false : node->untie());
2007 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2010 if (_listeners == 0)
2011 _listeners = new vector<SGPropertyChangeListener*>;
2012 _listeners->push_back(listener);
2013 listener->register_property(this);
2015 listener->valueChanged(this);
2019 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2021 vector<SGPropertyChangeListener*>::iterator it =
2022 find(_listeners->begin(), _listeners->end(), listener);
2023 if (it != _listeners->end()) {
2024 _listeners->erase(it);
2025 listener->unregister_property(this);
2026 if (_listeners->empty()) {
2027 vector<SGPropertyChangeListener*>* tmp = _listeners;
2035 SGPropertyNode::fireValueChanged ()
2037 fireValueChanged(this);
2041 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2043 fireChildAdded(this, child);
2047 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2049 fireChildRemoved(this, child);
2053 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2055 if (_listeners != 0) {
2056 for (unsigned int i = 0; i < _listeners->size(); i++) {
2057 (*_listeners)[i]->valueChanged(node);
2061 _parent->fireValueChanged(node);
2065 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2066 SGPropertyNode * child)
2068 if (_listeners != 0) {
2069 for (unsigned int i = 0; i < _listeners->size(); i++) {
2070 (*_listeners)[i]->childAdded(parent, child);
2074 _parent->fireChildAdded(parent, child);
2078 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2079 SGPropertyNode * child)
2081 if (_listeners != 0) {
2082 for (unsigned int i = 0; i < _listeners->size(); i++) {
2083 (*_listeners)[i]->childRemoved(parent, child);
2087 _parent->fireChildRemoved(parent, child);
2092 ////////////////////////////////////////////////////////////////////////
2093 // Simplified hash table for caching paths.
2094 ////////////////////////////////////////////////////////////////////////
2096 #define HASH_TABLE_SIZE 199
2098 SGPropertyNode::hash_table::entry::entry ()
2103 SGPropertyNode::hash_table::entry::~entry ()
2105 // Don't delete the value; we don't own
2110 SGPropertyNode::hash_table::entry::set_key (const char * key)
2116 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2121 SGPropertyNode::hash_table::bucket::bucket ()
2127 SGPropertyNode::hash_table::bucket::~bucket ()
2129 for (int i = 0; i < _length; i++)
2134 SGPropertyNode::hash_table::entry *
2135 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2138 for (i = 0; i < _length; i++) {
2139 if (!strcmp(_entries[i]->get_key(), key))
2143 entry ** new_entries = new entry*[_length+1];
2144 for (i = 0; i < _length; i++) {
2145 new_entries[i] = _entries[i];
2148 _entries = new_entries;
2149 _entries[_length] = new entry;
2150 _entries[_length]->set_key(key);
2152 return _entries[_length - 1];
2159 SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
2161 for (int i = 0; i < _length; i++) {
2162 if (_entries[i]->get_value() == node) {
2164 for (++i; i < _length; i++) {
2165 _entries[i-1] = _entries[i];
2175 SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
2177 for (int i = 0; i < _length; i++) {
2178 SGPropertyNode * node = _entries[i]->get_value();
2180 node->remove_linked_node(owner);
2184 SGPropertyNode::hash_table::hash_table ()
2190 SGPropertyNode::hash_table::~hash_table ()
2192 for (unsigned int i = 0; i < _data_length; i++) {
2194 _data[i]->clear(this);
2202 SGPropertyNode::hash_table::get (const char * key)
2204 if (_data_length == 0)
2206 unsigned int index = hashcode(key) % _data_length;
2207 if (_data[index] == 0)
2209 entry * e = _data[index]->get_entry(key);
2213 return e->get_value();
2217 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2219 if (_data_length == 0) {
2220 _data = new bucket*[HASH_TABLE_SIZE];
2221 _data_length = HASH_TABLE_SIZE;
2222 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2225 unsigned int index = hashcode(key) % _data_length;
2226 if (_data[index] == 0) {
2227 _data[index] = new bucket;
2229 entry * e = _data[index]->get_entry(key, true);
2230 e->set_value(value);
2231 value->add_linked_node(this);
2235 SGPropertyNode::hash_table::erase (SGPropertyNode * node)
2237 for (unsigned int i = 0; i < _data_length; i++)
2238 if (_data[i] && _data[i]->erase(node))
2245 SGPropertyNode::hash_table::hashcode (const char * key)
2247 unsigned int hash = 0;
2249 hash = 31 * hash + *key;
2257 ////////////////////////////////////////////////////////////////////////
2258 // Implementation of SGPropertyChangeListener.
2259 ////////////////////////////////////////////////////////////////////////
2261 SGPropertyChangeListener::~SGPropertyChangeListener ()
2263 for (int i = _properties.size() - 1; i >= 0; i--)
2264 _properties[i]->removeChangeListener(this);
2268 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2274 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2275 SGPropertyNode * child)
2281 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2282 SGPropertyNode * child)
2288 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2290 _properties.push_back(node);
2294 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2296 vector<SGPropertyNode *>::iterator it =
2297 find(_properties.begin(), _properties.end(), node);
2298 if (it != _properties.end())
2299 _properties.erase(it);
2303 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2306 = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2307 for (int i = 0; i < 3; ++i) {
2318 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2320 for (int i = 0; i < 3; ++i) {
2321 stream >> result[i];
2327 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2330 = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();
2331 for (int i = 0; i < 4; ++i) {
2342 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2344 for (int i = 0; i < 4; ++i) {
2345 stream >> result[i];