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;
46 using namespace simgear::props;
49 ////////////////////////////////////////////////////////////////////////
51 ////////////////////////////////////////////////////////////////////////
54 * Comparator class for sorting by index.
59 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
60 return (n1->getIndex() < n2->getIndex());
66 ////////////////////////////////////////////////////////////////////////
67 // Convenience macros for value access.
68 ////////////////////////////////////////////////////////////////////////
70 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
71 #define TEST_WRITE if (!getAttribute(WRITE)) return false
73 ////////////////////////////////////////////////////////////////////////
74 // Default values for every type.
75 ////////////////////////////////////////////////////////////////////////
77 template<> const bool SGRawValue<bool>::DefaultValue = false;
78 template<> const int SGRawValue<int>::DefaultValue = 0;
79 template<> const long SGRawValue<long>::DefaultValue = 0L;
80 template<> const float SGRawValue<float>::DefaultValue = 0.0;
81 template<> const double SGRawValue<double>::DefaultValue = 0.0L;
82 template<> const char * const SGRawValue<const char *>::DefaultValue = "";
83 template<> const SGVec3d SGRawValue<SGVec3d>::DefaultValue = SGVec3d();
84 template<> const SGVec4d SGRawValue<SGVec4d>::DefaultValue = SGVec4d();
86 ////////////////////////////////////////////////////////////////////////
87 // Local path normalization code.
88 ////////////////////////////////////////////////////////////////////////
91 * A component in a path.
100 * Parse the name for a path component.
102 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
104 static inline const string
105 parse_name (const string &path, int &i)
108 int max = path.size();
110 if (path[i] == '.') {
112 if (i < max && path[i] == '.') {
118 if (i < max && path[i] != '/')
119 throw string("illegal character after " + name);
122 else if (isalpha(path[i]) || path[i] == '_') {
126 // The rules inside a name are a little
129 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
130 path[i] == '-' || path[i] == '.') {
132 } else if (path[i] == '[' || path[i] == '/') {
135 throw string("name may contain only ._- and alphanumeric characters");
142 if (name.size() == 0)
143 throw string("name must begin with alpha or '_'");
151 * Parse the optional integer index for a path component.
153 * Index: "[" [0-9]+ "]"
156 parse_index (const string &path, int &i)
165 for (int max = path.size(); i < max; i++) {
166 if (isdigit(path[i])) {
167 index = (index * 10) + (path[i] - '0');
168 } else if (path[i] == ']') {
176 throw string("unterminated index (looking for ']')");
181 * Parse a single path component.
183 * Component: Name Index?
185 static inline PathComponent
186 parse_component (const string &path, int &i)
188 PathComponent component;
189 component.name = parse_name(path, i);
190 if (component.name[0] != '.')
191 component.index = parse_index(path, i);
193 component.index = -1;
199 * Parse a path into its components.
202 parse_path (const string &path, vector<PathComponent> &components)
205 int max = path.size();
207 // Check for initial '/'
208 if (path[pos] == '/') {
212 components.push_back(root);
214 while (pos < max && path[pos] == '/')
219 components.push_back(parse_component(path, pos));
220 while (pos < max && path[pos] == '/')
227 ////////////////////////////////////////////////////////////////////////
228 // Other static utility functions.
229 ////////////////////////////////////////////////////////////////////////
233 copy_string (const char * s)
235 unsigned long int slen = strlen(s);
236 char * copy = new char[slen + 1];
238 // the source string length is known so no need to check for '\0'
239 // when copying every single character
240 memcpy(copy, s, slen);
241 *(copy + slen) = '\0';
246 compare_strings (const char * s1, const char * s2)
248 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
252 * Locate a child node by name and index.
255 find_child (const char * name, int index, const vector<SGPropertyNode_ptr>& nodes)
257 int nNodes = nodes.size();
258 for (int i = 0; i < nNodes; i++) {
259 SGPropertyNode * node = nodes[i];
261 // searching for a mathing index is a lot less time consuming than
262 // comparing two strings so do that first.
263 if (node->getIndex() == index && compare_strings(node->getName(), name))
270 * Locate the child node with the highest index of the same name
273 find_last_child (const char * name, const vector<SGPropertyNode_ptr>& nodes)
275 int nNodes = nodes.size();
278 for (int i = 0; i < nNodes; i++) {
279 SGPropertyNode * node = nodes[i];
280 if (compare_strings(node->getName(), name))
282 int idx = node->getIndex();
283 if (idx > index) index = idx;
291 * Locate another node, given a relative path.
293 static SGPropertyNode *
294 find_node (SGPropertyNode * current,
295 const vector<PathComponent> &components,
299 // Run off the end of the list
304 // Success! This is the one we want.
305 else if (position >= (int)components.size()) {
306 return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
309 // Empty component means root.
310 else if (components[position].name == "") {
311 return find_node(current->getRootNode(), components, position + 1, create);
314 // . means current directory
315 else if (components[position].name == ".") {
316 return find_node(current, components, position + 1, create);
319 // .. means parent directory
320 else if (components[position].name == "..") {
321 SGPropertyNode * parent = current->getParent();
323 throw string("attempt to move past root with '..'");
325 return find_node(parent, components, position + 1, create);
328 // Otherwise, a child name
330 SGPropertyNode * child =
331 current->getChild(components[position].name.c_str(),
332 components[position].index,
334 return find_node(child, components, position + 1, create);
340 ////////////////////////////////////////////////////////////////////////
341 // Private methods from SGPropertyNode (may be inlined for speed).
342 ////////////////////////////////////////////////////////////////////////
345 SGPropertyNode::get_bool () const
348 return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
350 return _local_val.bool_val;
354 SGPropertyNode::get_int () const
357 return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
359 return _local_val.int_val;
363 SGPropertyNode::get_long () const
366 return static_cast<SGRawValue<long>*>(_value.val)->getValue();
368 return _local_val.long_val;
372 SGPropertyNode::get_float () const
375 return static_cast<SGRawValue<float>*>(_value.val)->getValue();
377 return _local_val.float_val;
381 SGPropertyNode::get_double () const
384 return static_cast<SGRawValue<double>*>(_value.val)->getValue();
386 return _local_val.double_val;
390 SGPropertyNode::get_string () const
393 return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
395 return _local_val.string_val;
399 SGPropertyNode::set_bool (bool val)
402 if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
409 _local_val.bool_val = val;
416 SGPropertyNode::set_int (int val)
419 if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
426 _local_val.int_val = val;
433 SGPropertyNode::set_long (long val)
436 if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
443 _local_val.long_val = val;
450 SGPropertyNode::set_float (float val)
453 if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
460 _local_val.float_val = val;
467 SGPropertyNode::set_double (double val)
470 if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
477 _local_val.double_val = val;
484 SGPropertyNode::set_string (const char * val)
487 if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
494 delete [] _local_val.string_val;
495 _local_val.string_val = copy_string(val);
502 SGPropertyNode::clearValue ()
504 if (_type == ALIAS) {
507 } else if (_type != NONE) {
510 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
513 _local_val.int_val = SGRawValue<int>::DefaultValue;
516 _local_val.long_val = SGRawValue<long>::DefaultValue;
519 _local_val.float_val = SGRawValue<float>::DefaultValue;
522 _local_val.double_val = SGRawValue<double>::DefaultValue;
527 delete [] _local_val.string_val;
529 _local_val.string_val = 0;
541 * Get the value as a string.
544 SGPropertyNode::make_string () const
546 if (!getAttribute(READ))
550 return _value.alias->getStringValue();
552 return get_bool() ? "true" : "false";
573 sstr << std::setprecision(10) << get_double();
577 Type realType = _value.val->getType();
578 // Perhaps this should be done for all types?
579 if (realType == VEC3D || realType == VEC4D)
581 static_cast<SGRawExtended*>(_value.val)->printOn(sstr);
587 _buffer = sstr.str();
588 return _buffer.c_str();
592 * Trace a write access for a property.
595 SGPropertyNode::trace_write () const
598 cerr << "TRACE: Write node " << getPath () << ", value \""
599 << make_string() << '"' << endl;
601 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
602 << ", value \"" << make_string() << '"');
607 * Trace a read access for a property.
610 SGPropertyNode::trace_read () const
613 cerr << "TRACE: Write node " << getPath () << ", value \""
614 << make_string() << '"' << endl;
616 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
617 << ", value \"" << make_string() << '"');
622 ////////////////////////////////////////////////////////////////////////
623 // Public methods from SGPropertyNode.
624 ////////////////////////////////////////////////////////////////////////
627 * Last used attribute
628 * Update as needed when enum Attribute is changed
630 const int SGPropertyNode::LAST_USED_ATTRIBUTE = USERARCHIVE;
633 * Default constructor: always creates a root node.
635 SGPropertyNode::SGPropertyNode ()
644 _local_val.string_val = 0;
652 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
653 : _index(node._index),
655 _parent(0), // don't copy the parent
660 _listeners(0) // CHECK!!
662 _local_val.string_val = 0;
666 if (_type == ALIAS) {
667 _value.alias = node._value.alias;
672 if (_tied || _type == EXTENDED) {
673 _value.val = node._value.val->clone();
678 set_bool(node.get_bool());
681 set_int(node.get_int());
684 set_long(node.get_long());
687 set_float(node.get_float());
690 set_double(node.get_double());
694 set_string(node.get_string());
703 * Convenience constructor.
705 SGPropertyNode::SGPropertyNode (const char * name,
707 SGPropertyNode * parent)
717 _local_val.string_val = 0;
719 _name = parse_name(name, i);
720 if (i != int(strlen(name)) || name[0] == '.')
721 throw string("plain name expected instead of '") + name + '\'';
728 SGPropertyNode::~SGPropertyNode ()
730 // zero out all parent pointers, else they might be dangling
731 for (unsigned i = 0; i < _children.size(); ++i)
732 _children[i]->_parent = 0;
733 for (unsigned i = 0; i < _removedChildren.size(); ++i)
734 _removedChildren[i]->_parent = 0;
739 vector<SGPropertyChangeListener*>::iterator it;
740 for (it = _listeners->begin(); it != _listeners->end(); ++it)
741 (*it)->unregister_property(this);
748 * Alias to another node.
751 SGPropertyNode::alias (SGPropertyNode * target)
753 if (target == 0 || _type == ALIAS || _tied)
757 _value.alias = target;
764 * Alias to another node by path.
767 SGPropertyNode::alias (const char * path)
769 return alias(getNode(path, true));
777 SGPropertyNode::unalias ()
787 * Get the target of an alias.
790 SGPropertyNode::getAliasTarget ()
792 return (_type == ALIAS ? _value.alias : 0);
796 const SGPropertyNode *
797 SGPropertyNode::getAliasTarget () const
799 return (_type == ALIAS ? _value.alias : 0);
803 * create a non-const child by name after the last node with the same name.
806 SGPropertyNode::addChild (const char * name)
808 int pos = find_last_child(name, _children)+1;
810 SGPropertyNode_ptr node;
811 node = new SGPropertyNode(name, pos, this);
812 _children.push_back(node);
813 fireChildAdded(node);
819 * Get a non-const child by index.
822 SGPropertyNode::getChild (int position)
824 if (position >= 0 && position < nChildren())
825 return _children[position];
832 * Get a const child by index.
834 const SGPropertyNode *
835 SGPropertyNode::getChild (int position) const
837 if (position >= 0 && position < nChildren())
838 return _children[position];
845 * Get a non-const child by name and index, creating if necessary.
848 SGPropertyNode::getChild (const char * name, int index, bool create)
850 int pos = find_child(name, index, _children);
852 return _children[pos];
854 SGPropertyNode_ptr node;
855 pos = find_child(name, index, _removedChildren);
857 vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
859 node = _removedChildren[pos];
860 _removedChildren.erase(it);
861 node->setAttribute(REMOVED, false);
863 node = new SGPropertyNode(name, index, this);
865 _children.push_back(node);
866 fireChildAdded(node);
875 * Get a const child by name and index.
877 const SGPropertyNode *
878 SGPropertyNode::getChild (const char * name, int index) const
880 int pos = find_child(name, index, _children);
882 return _children[pos];
889 * Get all children with the same name (but different indices).
891 vector<SGPropertyNode_ptr>
892 SGPropertyNode::getChildren (const char * name) const
894 vector<SGPropertyNode_ptr> children;
895 int max = _children.size();
897 for (int i = 0; i < max; i++)
898 if (compare_strings(_children[i]->getName(), name))
899 children.push_back(_children[i]);
901 sort(children.begin(), children.end(), CompareIndices());
907 * Remove this node and all children from nodes that link to them
908 * in their path cache.
911 SGPropertyNode::remove_from_path_caches ()
913 for (unsigned int i = 0; i < _children.size(); ++i)
914 _children[i]->remove_from_path_caches();
916 for (unsigned int i = 0; i < _linkedNodes.size(); i++)
917 _linkedNodes[i]->erase(this);
918 _linkedNodes.clear();
923 * Remove child by position.
926 SGPropertyNode::removeChild (int pos, bool keep)
928 SGPropertyNode_ptr node;
929 if (pos < 0 || pos >= (int)_children.size())
932 vector<SGPropertyNode_ptr>::iterator it = _children.begin();
934 node = _children[pos];
937 _removedChildren.push_back(node);
940 node->remove_from_path_caches();
941 node->setAttribute(REMOVED, true);
943 fireChildRemoved(node);
949 * Remove a child node
952 SGPropertyNode::removeChild (const char * name, int index, bool keep)
954 SGPropertyNode_ptr ret;
955 int pos = find_child(name, index, _children);
957 ret = removeChild(pos, keep);
963 * Remove all children with the specified name.
965 vector<SGPropertyNode_ptr>
966 SGPropertyNode::removeChildren (const char * name, bool keep)
968 vector<SGPropertyNode_ptr> children;
970 for (int pos = _children.size() - 1; pos >= 0; pos--)
971 if (compare_strings(_children[pos]->getName(), name))
972 children.push_back(removeChild(pos, keep));
974 sort(children.begin(), children.end(), CompareIndices());
980 * Remove a linked node.
983 SGPropertyNode::remove_linked_node (hash_table * node)
985 for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
986 if (_linkedNodes[i] == node) {
987 vector<hash_table *>::iterator it = _linkedNodes.begin();
989 _linkedNodes.erase(it);
998 SGPropertyNode::getDisplayName (bool simplify) const
1000 _display_name = _name;
1001 if (_index != 0 || !simplify) {
1003 sstr << '[' << _index << ']';
1004 _display_name += sstr.str();
1006 return _display_name.c_str();
1011 SGPropertyNode::getPath (bool simplify) const
1013 // Calculate the complete path only once.
1014 if (_parent != 0 && _path.empty()) {
1015 _path = _parent->getPath(simplify);
1017 _path += getDisplayName(simplify);
1020 return _path.c_str();
1024 SGPropertyNode::getType () const
1027 return _value.alias->getType();
1028 else if (_type == EXTENDED)
1029 return _value.val->getType();
1036 SGPropertyNode::getBoolValue () const
1038 // Shortcut for common case
1039 if (_attr == (READ|WRITE) && _type == BOOL)
1042 if (getAttribute(TRACE_READ))
1044 if (!getAttribute(READ))
1045 return SGRawValue<bool>::DefaultValue;
1048 return _value.alias->getBoolValue();
1052 return get_int() == 0 ? false : true;
1054 return get_long() == 0L ? false : true;
1056 return get_float() == 0.0 ? false : true;
1058 return get_double() == 0.0L ? false : true;
1061 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1064 return SGRawValue<bool>::DefaultValue;
1069 SGPropertyNode::getIntValue () const
1071 // Shortcut for common case
1072 if (_attr == (READ|WRITE) && _type == INT)
1075 if (getAttribute(TRACE_READ))
1077 if (!getAttribute(READ))
1078 return SGRawValue<int>::DefaultValue;
1081 return _value.alias->getIntValue();
1083 return int(get_bool());
1087 return int(get_long());
1089 return int(get_float());
1091 return int(get_double());
1094 return atoi(get_string());
1097 return SGRawValue<int>::DefaultValue;
1102 SGPropertyNode::getLongValue () const
1104 // Shortcut for common case
1105 if (_attr == (READ|WRITE) && _type == LONG)
1108 if (getAttribute(TRACE_READ))
1110 if (!getAttribute(READ))
1111 return SGRawValue<long>::DefaultValue;
1114 return _value.alias->getLongValue();
1116 return long(get_bool());
1118 return long(get_int());
1122 return long(get_float());
1124 return long(get_double());
1127 return strtol(get_string(), 0, 0);
1130 return SGRawValue<long>::DefaultValue;
1135 SGPropertyNode::getFloatValue () const
1137 // Shortcut for common case
1138 if (_attr == (READ|WRITE) && _type == FLOAT)
1141 if (getAttribute(TRACE_READ))
1143 if (!getAttribute(READ))
1144 return SGRawValue<float>::DefaultValue;
1147 return _value.alias->getFloatValue();
1149 return float(get_bool());
1151 return float(get_int());
1153 return float(get_long());
1157 return float(get_double());
1160 return atof(get_string());
1163 return SGRawValue<float>::DefaultValue;
1168 SGPropertyNode::getDoubleValue () const
1170 // Shortcut for common case
1171 if (_attr == (READ|WRITE) && _type == DOUBLE)
1172 return get_double();
1174 if (getAttribute(TRACE_READ))
1176 if (!getAttribute(READ))
1177 return SGRawValue<double>::DefaultValue;
1181 return _value.alias->getDoubleValue();
1183 return double(get_bool());
1185 return double(get_int());
1187 return double(get_long());
1189 return double(get_float());
1191 return get_double();
1194 return strtod(get_string(), 0);
1197 return SGRawValue<double>::DefaultValue;
1202 SGPropertyNode::getStringValue () const
1204 // Shortcut for common case
1205 if (_attr == (READ|WRITE) && _type == STRING)
1206 return get_string();
1208 if (getAttribute(TRACE_READ))
1210 if (!getAttribute(READ))
1211 return SGRawValue<const char *>::DefaultValue;
1212 return make_string();
1216 SGPropertyNode::setBoolValue (bool value)
1218 // Shortcut for common case
1219 if (_attr == (READ|WRITE) && _type == BOOL)
1220 return set_bool(value);
1222 bool result = false;
1224 if (_type == NONE || _type == UNSPECIFIED) {
1232 result = _value.alias->setBoolValue(value);
1235 result = set_bool(value);
1238 result = set_int(int(value));
1241 result = set_long(long(value));
1244 result = set_float(float(value));
1247 result = set_double(double(value));
1251 result = set_string(value ? "true" : "false");
1258 if (getAttribute(TRACE_WRITE))
1264 SGPropertyNode::setIntValue (int value)
1266 // Shortcut for common case
1267 if (_attr == (READ|WRITE) && _type == INT)
1268 return set_int(value);
1270 bool result = false;
1272 if (_type == NONE || _type == UNSPECIFIED) {
1275 _local_val.int_val = 0;
1280 result = _value.alias->setIntValue(value);
1283 result = set_bool(value == 0 ? false : true);
1286 result = set_int(value);
1289 result = set_long(long(value));
1292 result = set_float(float(value));
1295 result = set_double(double(value));
1300 sprintf(buf, "%d", value);
1301 result = set_string(buf);
1309 if (getAttribute(TRACE_WRITE))
1315 SGPropertyNode::setLongValue (long value)
1317 // Shortcut for common case
1318 if (_attr == (READ|WRITE) && _type == LONG)
1319 return set_long(value);
1321 bool result = false;
1323 if (_type == NONE || _type == UNSPECIFIED) {
1326 _local_val.long_val = 0L;
1331 result = _value.alias->setLongValue(value);
1334 result = set_bool(value == 0L ? false : true);
1337 result = set_int(int(value));
1340 result = set_long(value);
1343 result = set_float(float(value));
1346 result = set_double(double(value));
1351 sprintf(buf, "%ld", value);
1352 result = set_string(buf);
1360 if (getAttribute(TRACE_WRITE))
1366 SGPropertyNode::setFloatValue (float value)
1368 // Shortcut for common case
1369 if (_attr == (READ|WRITE) && _type == FLOAT)
1370 return set_float(value);
1372 bool result = false;
1374 if (_type == NONE || _type == UNSPECIFIED) {
1377 _local_val.float_val = 0;
1382 result = _value.alias->setFloatValue(value);
1385 result = set_bool(value == 0.0 ? false : true);
1388 result = set_int(int(value));
1391 result = set_long(long(value));
1394 result = set_float(value);
1397 result = set_double(double(value));
1402 sprintf(buf, "%f", value);
1403 result = set_string(buf);
1411 if (getAttribute(TRACE_WRITE))
1417 SGPropertyNode::setDoubleValue (double value)
1419 // Shortcut for common case
1420 if (_attr == (READ|WRITE) && _type == DOUBLE)
1421 return set_double(value);
1423 bool result = false;
1425 if (_type == NONE || _type == UNSPECIFIED) {
1427 _local_val.double_val = value;
1433 result = _value.alias->setDoubleValue(value);
1436 result = set_bool(value == 0.0L ? false : true);
1439 result = set_int(int(value));
1442 result = set_long(long(value));
1445 result = set_float(float(value));
1448 result = set_double(value);
1453 sprintf(buf, "%f", value);
1454 result = set_string(buf);
1462 if (getAttribute(TRACE_WRITE))
1468 SGPropertyNode::setStringValue (const char * value)
1470 // Shortcut for common case
1471 if (_attr == (READ|WRITE) && _type == STRING)
1472 return set_string(value);
1474 bool result = false;
1476 if (_type == NONE || _type == UNSPECIFIED) {
1483 result = _value.alias->setStringValue(value);
1486 result = set_bool((compare_strings(value, "true")
1487 || atoi(value)) ? true : false);
1490 result = set_int(atoi(value));
1493 result = set_long(strtol(value, 0, 0));
1496 result = set_float(atof(value));
1499 result = set_double(strtod(value, 0));
1503 result = set_string(value);
1507 stringstream sstr(value);
1508 static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1516 if (getAttribute(TRACE_WRITE))
1522 SGPropertyNode::setUnspecifiedValue (const char * value)
1524 bool result = false;
1526 if (_type == NONE) {
1528 _type = UNSPECIFIED;
1531 if (type == EXTENDED)
1532 type = _value.val->getType();
1535 result = _value.alias->setUnspecifiedValue(value);
1538 result = set_bool((compare_strings(value, "true")
1539 || atoi(value)) ? true : false);
1542 result = set_int(atoi(value));
1545 result = set_long(strtol(value, 0, 0));
1548 result = set_float(atof(value));
1551 result = set_double(strtod(value, 0));
1555 result = set_string(value);
1558 result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1561 result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1568 if (getAttribute(TRACE_WRITE))
1573 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1575 if (!getAttribute(READ))
1579 return _value.alias->printOn(stream);
1581 stream << (get_bool() ? "true" : "false");
1584 stream << get_int();
1587 stream << get_long();
1590 stream << get_float();
1593 stream << get_double();
1597 stream << get_string();
1600 static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1609 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1612 if (_type == ALIAS || _tied)
1615 useDefault = useDefault && hasValue();
1616 std::string old_val;
1618 old_val = getStringValue();
1622 _value.val = rawValue.clone();
1625 setStringValue(old_val.c_str());
1630 SGPropertyNode::untie ()
1637 bool val = getBoolValue();
1640 _local_val.bool_val = val;
1644 int val = getIntValue();
1647 _local_val.int_val = val;
1651 long val = getLongValue();
1654 _local_val.long_val = val;
1658 float val = getFloatValue();
1661 _local_val.float_val = val;
1665 double val = getDoubleValue();
1668 _local_val.double_val = val;
1673 string val = getStringValue();
1676 _local_val.string_val = copy_string(val.c_str());
1680 SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1681 _value.val = 0; // Prevent clearValue() from deleting
1684 _value.val = val->makeContainer();
1698 SGPropertyNode::getRootNode ()
1703 return _parent->getRootNode();
1706 const SGPropertyNode *
1707 SGPropertyNode::getRootNode () const
1712 return _parent->getRootNode();
1716 SGPropertyNode::getNode (const char * relative_path, bool create)
1718 if (_path_cache == 0)
1719 _path_cache = new hash_table;
1721 SGPropertyNode * result = _path_cache->get(relative_path);
1723 vector<PathComponent> components;
1724 parse_path(relative_path, components);
1725 result = find_node(this, components, 0, create);
1727 _path_cache->put(relative_path, result);
1734 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1736 vector<PathComponent> components;
1737 parse_path(relative_path, components);
1738 if (components.size() > 0)
1739 components.back().index = index;
1740 return find_node(this, components, 0, create);
1743 const SGPropertyNode *
1744 SGPropertyNode::getNode (const char * relative_path) const
1746 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1749 const SGPropertyNode *
1750 SGPropertyNode::getNode (const char * relative_path, int index) const
1752 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1756 ////////////////////////////////////////////////////////////////////////
1757 // Convenience methods using relative paths.
1758 ////////////////////////////////////////////////////////////////////////
1762 * Test whether another node has a value attached.
1765 SGPropertyNode::hasValue (const char * relative_path) const
1767 const SGPropertyNode * node = getNode(relative_path);
1768 return (node == 0 ? false : node->hasValue());
1773 * Get the value type for another node.
1776 SGPropertyNode::getType (const char * relative_path) const
1778 const SGPropertyNode * node = getNode(relative_path);
1779 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1784 * Get a bool value for another node.
1787 SGPropertyNode::getBoolValue (const char * relative_path,
1788 bool defaultValue) const
1790 const SGPropertyNode * node = getNode(relative_path);
1791 return (node == 0 ? defaultValue : node->getBoolValue());
1796 * Get an int value for another node.
1799 SGPropertyNode::getIntValue (const char * relative_path,
1800 int defaultValue) const
1802 const SGPropertyNode * node = getNode(relative_path);
1803 return (node == 0 ? defaultValue : node->getIntValue());
1808 * Get a long value for another node.
1811 SGPropertyNode::getLongValue (const char * relative_path,
1812 long defaultValue) const
1814 const SGPropertyNode * node = getNode(relative_path);
1815 return (node == 0 ? defaultValue : node->getLongValue());
1820 * Get a float value for another node.
1823 SGPropertyNode::getFloatValue (const char * relative_path,
1824 float defaultValue) const
1826 const SGPropertyNode * node = getNode(relative_path);
1827 return (node == 0 ? defaultValue : node->getFloatValue());
1832 * Get a double value for another node.
1835 SGPropertyNode::getDoubleValue (const char * relative_path,
1836 double defaultValue) const
1838 const SGPropertyNode * node = getNode(relative_path);
1839 return (node == 0 ? defaultValue : node->getDoubleValue());
1844 * Get a string value for another node.
1847 SGPropertyNode::getStringValue (const char * relative_path,
1848 const char * defaultValue) const
1850 const SGPropertyNode * node = getNode(relative_path);
1851 return (node == 0 ? defaultValue : node->getStringValue());
1856 * Set a bool value for another node.
1859 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1861 return getNode(relative_path, true)->setBoolValue(value);
1866 * Set an int value for another node.
1869 SGPropertyNode::setIntValue (const char * relative_path, int value)
1871 return getNode(relative_path, true)->setIntValue(value);
1876 * Set a long value for another node.
1879 SGPropertyNode::setLongValue (const char * relative_path, long value)
1881 return getNode(relative_path, true)->setLongValue(value);
1886 * Set a float value for another node.
1889 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1891 return getNode(relative_path, true)->setFloatValue(value);
1896 * Set a double value for another node.
1899 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1901 return getNode(relative_path, true)->setDoubleValue(value);
1906 * Set a string value for another node.
1909 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1911 return getNode(relative_path, true)->setStringValue(value);
1916 * Set an unknown value for another node.
1919 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1922 return getNode(relative_path, true)->setUnspecifiedValue(value);
1927 * Test whether another node is tied.
1930 SGPropertyNode::isTied (const char * relative_path) const
1932 const SGPropertyNode * node = getNode(relative_path);
1933 return (node == 0 ? false : node->isTied());
1938 * Tie a node reached by a relative path, creating it if necessary.
1941 SGPropertyNode::tie (const char * relative_path,
1942 const SGRawValue<bool> &rawValue,
1945 return getNode(relative_path, true)->tie(rawValue, useDefault);
1950 * Tie a node reached by a relative path, creating it if necessary.
1953 SGPropertyNode::tie (const char * relative_path,
1954 const SGRawValue<int> &rawValue,
1957 return getNode(relative_path, true)->tie(rawValue, useDefault);
1962 * Tie a node reached by a relative path, creating it if necessary.
1965 SGPropertyNode::tie (const char * relative_path,
1966 const SGRawValue<long> &rawValue,
1969 return getNode(relative_path, true)->tie(rawValue, useDefault);
1974 * Tie a node reached by a relative path, creating it if necessary.
1977 SGPropertyNode::tie (const char * relative_path,
1978 const SGRawValue<float> &rawValue,
1981 return getNode(relative_path, true)->tie(rawValue, useDefault);
1986 * Tie a node reached by a relative path, creating it if necessary.
1989 SGPropertyNode::tie (const char * relative_path,
1990 const SGRawValue<double> &rawValue,
1993 return getNode(relative_path, true)->tie(rawValue, useDefault);
1998 * Tie a node reached by a relative path, creating it if necessary.
2001 SGPropertyNode::tie (const char * relative_path,
2002 const SGRawValue<const char *> &rawValue,
2005 return getNode(relative_path, true)->tie(rawValue, useDefault);
2010 * Attempt to untie another node reached by a relative path.
2013 SGPropertyNode::untie (const char * relative_path)
2015 SGPropertyNode * node = getNode(relative_path);
2016 return (node == 0 ? false : node->untie());
2020 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2023 if (_listeners == 0)
2024 _listeners = new vector<SGPropertyChangeListener*>;
2025 _listeners->push_back(listener);
2026 listener->register_property(this);
2028 listener->valueChanged(this);
2032 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2034 vector<SGPropertyChangeListener*>::iterator it =
2035 find(_listeners->begin(), _listeners->end(), listener);
2036 if (it != _listeners->end()) {
2037 _listeners->erase(it);
2038 listener->unregister_property(this);
2039 if (_listeners->empty()) {
2040 vector<SGPropertyChangeListener*>* tmp = _listeners;
2048 SGPropertyNode::fireValueChanged ()
2050 fireValueChanged(this);
2054 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2056 fireChildAdded(this, child);
2060 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2062 fireChildRemoved(this, child);
2066 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2068 if (_listeners != 0) {
2069 for (unsigned int i = 0; i < _listeners->size(); i++) {
2070 (*_listeners)[i]->valueChanged(node);
2074 _parent->fireValueChanged(node);
2078 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2079 SGPropertyNode * child)
2081 if (_listeners != 0) {
2082 for (unsigned int i = 0; i < _listeners->size(); i++) {
2083 (*_listeners)[i]->childAdded(parent, child);
2087 _parent->fireChildAdded(parent, child);
2091 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2092 SGPropertyNode * child)
2094 if (_listeners != 0) {
2095 for (unsigned int i = 0; i < _listeners->size(); i++) {
2096 (*_listeners)[i]->childRemoved(parent, child);
2100 _parent->fireChildRemoved(parent, child);
2105 ////////////////////////////////////////////////////////////////////////
2106 // Simplified hash table for caching paths.
2107 ////////////////////////////////////////////////////////////////////////
2109 #define HASH_TABLE_SIZE 199
2111 SGPropertyNode::hash_table::entry::entry ()
2116 SGPropertyNode::hash_table::entry::~entry ()
2118 // Don't delete the value; we don't own
2123 SGPropertyNode::hash_table::entry::set_key (const char * key)
2129 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2134 SGPropertyNode::hash_table::bucket::bucket ()
2140 SGPropertyNode::hash_table::bucket::~bucket ()
2142 for (int i = 0; i < _length; i++)
2147 SGPropertyNode::hash_table::entry *
2148 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2151 for (i = 0; i < _length; i++) {
2152 if (!strcmp(_entries[i]->get_key(), key))
2156 entry ** new_entries = new entry*[_length+1];
2157 for (i = 0; i < _length; i++) {
2158 new_entries[i] = _entries[i];
2161 _entries = new_entries;
2162 _entries[_length] = new entry;
2163 _entries[_length]->set_key(key);
2165 return _entries[_length - 1];
2172 SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
2174 for (int i = 0; i < _length; i++) {
2175 if (_entries[i]->get_value() == node) {
2177 for (++i; i < _length; i++) {
2178 _entries[i-1] = _entries[i];
2188 SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
2190 for (int i = 0; i < _length; i++) {
2191 SGPropertyNode * node = _entries[i]->get_value();
2193 node->remove_linked_node(owner);
2197 SGPropertyNode::hash_table::hash_table ()
2203 SGPropertyNode::hash_table::~hash_table ()
2205 for (unsigned int i = 0; i < _data_length; i++) {
2207 _data[i]->clear(this);
2215 SGPropertyNode::hash_table::get (const char * key)
2217 if (_data_length == 0)
2219 unsigned int index = hashcode(key) % _data_length;
2220 if (_data[index] == 0)
2222 entry * e = _data[index]->get_entry(key);
2226 return e->get_value();
2230 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2232 if (_data_length == 0) {
2233 _data = new bucket*[HASH_TABLE_SIZE];
2234 _data_length = HASH_TABLE_SIZE;
2235 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2238 unsigned int index = hashcode(key) % _data_length;
2239 if (_data[index] == 0) {
2240 _data[index] = new bucket;
2242 entry * e = _data[index]->get_entry(key, true);
2243 e->set_value(value);
2244 value->add_linked_node(this);
2248 SGPropertyNode::hash_table::erase (SGPropertyNode * node)
2250 for (unsigned int i = 0; i < _data_length; i++)
2251 if (_data[i] && _data[i]->erase(node))
2258 SGPropertyNode::hash_table::hashcode (const char * key)
2260 unsigned int hash = 0;
2262 hash = 31 * hash + *key;
2270 ////////////////////////////////////////////////////////////////////////
2271 // Implementation of SGPropertyChangeListener.
2272 ////////////////////////////////////////////////////////////////////////
2274 SGPropertyChangeListener::~SGPropertyChangeListener ()
2276 for (int i = _properties.size() - 1; i >= 0; i--)
2277 _properties[i]->removeChangeListener(this);
2281 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2287 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2288 SGPropertyNode * child)
2294 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2295 SGPropertyNode * child)
2301 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2303 _properties.push_back(node);
2307 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2309 vector<SGPropertyNode *>::iterator it =
2310 find(_properties.begin(), _properties.end(), node);
2311 if (it != _properties.end())
2312 _properties.erase(it);
2318 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2321 = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2322 for (int i = 0; i < 3; ++i) {
2331 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2333 for (int i = 0; i < 3; ++i) {
2334 stream >> result[i];
2340 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2343 = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();
2344 for (int i = 0; i < 4; ++i) {
2353 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2355 for (int i = 0; i < 4; ++i) {
2356 stream >> result[i];