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].
25 #include <simgear/compiler.h>
26 #include <simgear/debug/logstream.hxx>
36 ////////////////////////////////////////////////////////////////////////
38 ////////////////////////////////////////////////////////////////////////
41 * Comparator class for sorting by index.
46 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
47 return (n1->getIndex() < n2->getIndex());
53 ////////////////////////////////////////////////////////////////////////
54 // Convenience macros for value access.
55 ////////////////////////////////////////////////////////////////////////
57 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
58 #define TEST_WRITE if (!getAttribute(WRITE)) return false
62 ////////////////////////////////////////////////////////////////////////
63 // Default values for every type.
64 ////////////////////////////////////////////////////////////////////////
66 const bool SGRawValue<bool>::DefaultValue = false;
67 const int SGRawValue<int>::DefaultValue = 0;
68 const long SGRawValue<long>::DefaultValue = 0L;
69 const float SGRawValue<float>::DefaultValue = 0.0;
70 const double SGRawValue<double>::DefaultValue = 0.0L;
71 const char * const SGRawValue<const char *>::DefaultValue = "";
75 ////////////////////////////////////////////////////////////////////////
76 // Local path normalization code.
77 ////////////////////////////////////////////////////////////////////////
80 * A component in a path.
89 * Parse the name for a path component.
91 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
93 static inline const string
94 parse_name (const string &path, int &i)
97 int max = path.size();
101 if (i < max && path[i] == '.') {
107 if (i < max && path[i] != '/')
108 throw string(string("Illegal character after ") + name);
111 else if (isalpha(path[i]) || path[i] == '_') {
115 // The rules inside a name are a little
118 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
119 path[i] == '-' || path[i] == '.') {
121 } else if (path[i] == '[' || path[i] == '/') {
124 throw string("name may contain only ._- and alphanumeric characters");
131 if (name.size() == 0)
132 throw string("name must begin with alpha or '_'");
140 * Parse the optional integer index for a path component.
142 * Index: "[" [0-9]+ "]"
145 parse_index (const string &path, int &i)
154 for (int max = path.size(); i < max; i++) {
155 if (isdigit(path[i])) {
156 index = (index * 10) + (path[i] - '0');
157 } else if (path[i] == ']') {
165 throw string("unterminated index (looking for ']')");
170 * Parse a single path component.
172 * Component: Name Index?
174 static inline PathComponent
175 parse_component (const string &path, int &i)
177 PathComponent component;
178 component.name = parse_name(path, i);
179 if (component.name[0] != '.')
180 component.index = parse_index(path, i);
182 component.index = -1;
188 * Parse a path into its components.
191 parse_path (const string &path, vector<PathComponent> &components)
194 int max = path.size();
196 // Check for initial '/'
197 if (path[pos] == '/') {
201 components.push_back(root);
203 while (pos < max && path[pos] == '/')
208 components.push_back(parse_component(path, pos));
209 while (pos < max && path[pos] == '/')
216 ////////////////////////////////////////////////////////////////////////
217 // Other static utility functions.
218 ////////////////////////////////////////////////////////////////////////
222 copy_string (const char * s)
224 // FIXME: potential buffer overflow.
225 // For some reason, strnlen and
226 // strncpy cause all kinds of crashes.
227 char * copy = new char[strlen(s) + 1];
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, vector<SGPropertyNode_ptr> nodes)
244 int nNodes = nodes.size();
245 for (int i = 0; i < nNodes; i++) {
246 SGPropertyNode * node = nodes[i];
247 if (compare_strings(node->getName(), name) && node->getIndex() == index)
255 * Locate another node, given a relative path.
257 static SGPropertyNode *
258 find_node (SGPropertyNode * current,
259 const vector<PathComponent> &components,
263 // Run off the end of the list
268 // Success! This is the one we want.
269 else if (position >= (int)components.size()) {
273 // Empty component means root.
274 else if (components[position].name == "") {
275 return find_node(current->getRootNode(), components, position + 1, create);
278 // . means current directory
279 else if (components[position].name == ".") {
280 return find_node(current, components, position + 1, create);
283 // .. means parent directory
284 else if (components[position].name == "..") {
285 SGPropertyNode * parent = current->getParent();
287 throw string("Attempt to move past root with '..'");
289 return find_node(parent, components, position + 1, create);
292 // Otherwise, a child name
294 SGPropertyNode * child =
295 current->getChild(components[position].name.c_str(),
296 components[position].index,
298 return find_node(child, components, position + 1, create);
304 ////////////////////////////////////////////////////////////////////////
305 // Private methods from SGPropertyNode (may be inlined for speed).
306 ////////////////////////////////////////////////////////////////////////
309 SGPropertyNode::get_bool () const
312 return _value.bool_val->getValue();
314 return _local_val.bool_val;
318 SGPropertyNode::get_int () const
321 return _value.int_val->getValue();
323 return _local_val.int_val;
327 SGPropertyNode::get_long () const
330 return _value.long_val->getValue();
332 return _local_val.long_val;
336 SGPropertyNode::get_float () const
339 return _value.float_val->getValue();
341 return _local_val.float_val;
345 SGPropertyNode::get_double () const
348 return _value.double_val->getValue();
350 return _local_val.double_val;
354 SGPropertyNode::get_string () const
357 return _value.string_val->getValue();
359 return _local_val.string_val;
363 SGPropertyNode::set_bool (bool val)
366 if (_value.bool_val->setValue(val)) {
373 _local_val.bool_val = val;
380 SGPropertyNode::set_int (int val)
383 if (_value.int_val->setValue(val)) {
390 _local_val.int_val = val;
397 SGPropertyNode::set_long (long val)
400 if (_value.long_val->setValue(val)) {
407 _local_val.long_val = val;
414 SGPropertyNode::set_float (float val)
417 if (_value.float_val->setValue(val)) {
424 _local_val.float_val = val;
431 SGPropertyNode::set_double (double val)
434 if (_value.double_val->setValue(val)) {
441 _local_val.double_val = val;
448 SGPropertyNode::set_string (const char * val)
451 if (_value.string_val->setValue(val)) {
458 delete [] _local_val.string_val;
459 _local_val.string_val = copy_string(val);
466 SGPropertyNode::clear_value ()
476 delete _value.bool_val;
479 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
483 delete _value.int_val;
486 _local_val.int_val = SGRawValue<int>::DefaultValue;
490 delete _value.long_val;
491 _value.long_val = 0L;
493 _local_val.long_val = SGRawValue<long>::DefaultValue;
497 delete _value.float_val;
498 _value.float_val = 0;
500 _local_val.float_val = SGRawValue<float>::DefaultValue;
504 delete _value.double_val;
505 _value.double_val = 0;
507 _local_val.double_val = SGRawValue<double>::DefaultValue;
512 delete _value.string_val;
513 _value.string_val = 0;
515 delete [] _local_val.string_val;
517 _local_val.string_val = 0;
526 * Get the value as a string.
529 SGPropertyNode::make_string () const
531 if (!getAttribute(READ))
536 return _value.alias->getStringValue();
543 sprintf(_buffer, "%d", get_int());
546 sprintf(_buffer, "%ld", get_long());
549 sprintf(_buffer, "%f", get_float());
552 sprintf(_buffer, "%f", get_double());
564 * Trace a write access for a property.
567 SGPropertyNode::trace_write () const
570 cerr << "TRACE: Write node " << getPath () << ", value\""
571 << make_string() << '"' << endl;
573 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
574 << ", value\"" << make_string() << '"');
579 * Trace a read access for a property.
582 SGPropertyNode::trace_read () const
585 cerr << "TRACE: Write node " << getPath () << ", value \""
586 << make_string() << '"' << endl;
588 SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
589 << ", value \"" << make_string() << '"');
594 * Increment reference counter
597 SGPropertyNode::incrementRef()
603 * Decrement reference counter
606 SGPropertyNode::decrementRef()
613 ////////////////////////////////////////////////////////////////////////
614 // Public methods from SGPropertyNode.
615 ////////////////////////////////////////////////////////////////////////
618 * Last used attribute
619 * Update as needed when enum Attribute is changed
621 const int SGPropertyNode::LAST_USED_ATTRIBUTE = TRACE_WRITE;
624 * Default constructor: always creates a root node.
626 SGPropertyNode::SGPropertyNode ()
627 : _name(copy_string("")),
637 _local_val.string_val = 0;
644 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
645 : _index(node._index),
646 _parent(0), // don't copy the parent
652 _listeners(0) // CHECK!!
654 _name = copy_string(node._name);
655 _local_val.string_val = 0;
660 _value.alias = node._value.alias;
666 _value.bool_val = node._value.bool_val->clone();
669 set_bool(node.get_bool());
675 _value.int_val = node._value.int_val->clone();
678 set_int(node.get_int());
684 _value.long_val = node._value.long_val->clone();
687 set_long(node.get_long());
693 _value.float_val = node._value.float_val->clone();
696 set_float(node.get_float());
702 _value.double_val = node._value.double_val->clone();
705 set_double(node.get_double());
712 _value.string_val = node._value.string_val->clone();
715 set_string(node.get_string());
723 * Convenience constructor.
725 SGPropertyNode::SGPropertyNode (const char * name,
727 SGPropertyNode * parent)
737 _name = copy_string(name);
738 _local_val.string_val = 0;
745 SGPropertyNode::~SGPropertyNode ()
755 * Alias to another node.
758 SGPropertyNode::alias (SGPropertyNode * target)
760 if (target == 0 || _type == ALIAS || _tied)
763 _value.alias = target;
770 * Alias to another node by path.
773 SGPropertyNode::alias (const char * path)
775 return alias(getNode(path, true));
783 SGPropertyNode::unalias ()
794 * Get the target of an alias.
797 SGPropertyNode::getAliasTarget ()
799 return (_type == ALIAS ? _value.alias : 0);
803 const SGPropertyNode *
804 SGPropertyNode::getAliasTarget () const
806 return (_type == ALIAS ? _value.alias : 0);
811 * Get a non-const child by index.
814 SGPropertyNode::getChild (int position)
816 if (position >= 0 && position < nChildren())
817 return _children[position];
824 * Get a const child by index.
826 const SGPropertyNode *
827 SGPropertyNode::getChild (int position) const
829 if (position >= 0 && position < nChildren())
830 return _children[position];
837 * Get a non-const child by name and index, creating if necessary.
840 SGPropertyNode::getChild (const char * name, int index, bool create)
842 int pos = find_child(name, index, _children);
844 return _children[pos];
846 SGPropertyNode_ptr node;
847 pos = find_child(name, index, _removedChildren);
849 vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
851 node = _removedChildren[pos];
852 _removedChildren.erase(it);
853 node->setAttribute(REMOVED, false);
855 node = new SGPropertyNode(name, index, this);
857 _children.push_back(node);
858 fireChildAdded(node);
867 * Get a const child by name and index.
869 const SGPropertyNode *
870 SGPropertyNode::getChild (const char * name, int index) const
872 int pos = find_child(name, index, _children);
874 return _children[pos];
881 * Get all children with the same name (but different indices).
883 vector<SGPropertyNode_ptr>
884 SGPropertyNode::getChildren (const char * name) const
886 vector<SGPropertyNode_ptr> children;
887 int max = _children.size();
889 for (int i = 0; i < max; i++)
890 if (compare_strings(_children[i]->getName(), name))
891 children.push_back(_children[i]);
893 sort(children.begin(), children.end(), CompareIndices());
899 * Remove a child node
902 SGPropertyNode::removeChild (const char * name, int index, bool keep)
904 SGPropertyNode_ptr ret;
905 int pos = find_child(name, index, _children);
907 vector<SGPropertyNode_ptr>::iterator it = _children.begin();
909 SGPropertyNode_ptr node = _children[pos];
912 _removedChildren.push_back(node);
914 node->setAttribute(REMOVED, true);
916 fireChildRemoved(node);
923 SGPropertyNode::getPath (bool simplify) const
928 string path = _parent->getPath(simplify);
931 if (_index != 0 || !simplify) {
933 sprintf(buffer, "[%d]", _index);
936 strncpy(_buffer, path.c_str(), MAX_STRING_LEN);
941 SGPropertyNode::getType () const
944 return _value.alias->getType();
951 SGPropertyNode::getBoolValue () const
953 // Shortcut for common case
954 if (_attr == (READ|WRITE) && _type == BOOL)
957 if (getAttribute(TRACE_READ))
959 if (!getAttribute(READ))
960 return SGRawValue<bool>::DefaultValue;
963 return _value.alias->getBoolValue();
967 return get_int() == 0 ? false : true;
969 return get_long() == 0L ? false : true;
971 return get_float() == 0.0 ? false : true;
973 return get_double() == 0.0L ? false : true;
976 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
979 return SGRawValue<bool>::DefaultValue;
984 SGPropertyNode::getIntValue () const
986 // Shortcut for common case
987 if (_attr == (READ|WRITE) && _type == INT)
990 if (getAttribute(TRACE_READ))
992 if (!getAttribute(READ))
993 return SGRawValue<int>::DefaultValue;
996 return _value.alias->getIntValue();
998 return int(get_bool());
1002 return int(get_long());
1004 return int(get_float());
1006 return int(get_double());
1009 return atoi(get_string());
1012 return SGRawValue<int>::DefaultValue;
1017 SGPropertyNode::getLongValue () const
1019 // Shortcut for common case
1020 if (_attr == (READ|WRITE) && _type == LONG)
1023 if (getAttribute(TRACE_READ))
1025 if (!getAttribute(READ))
1026 return SGRawValue<long>::DefaultValue;
1029 return _value.alias->getLongValue();
1031 return long(get_bool());
1033 return long(get_int());
1037 return long(get_float());
1039 return long(get_double());
1042 return strtol(get_string(), 0, 0);
1045 return SGRawValue<long>::DefaultValue;
1050 SGPropertyNode::getFloatValue () const
1052 // Shortcut for common case
1053 if (_attr == (READ|WRITE) && _type == FLOAT)
1056 if (getAttribute(TRACE_READ))
1058 if (!getAttribute(READ))
1059 return SGRawValue<float>::DefaultValue;
1062 return _value.alias->getFloatValue();
1064 return float(get_bool());
1066 return float(get_int());
1068 return float(get_long());
1072 return float(get_double());
1075 return atof(get_string());
1078 return SGRawValue<float>::DefaultValue;
1083 SGPropertyNode::getDoubleValue () const
1085 // Shortcut for common case
1086 if (_attr == (READ|WRITE) && _type == DOUBLE)
1087 return get_double();
1089 if (getAttribute(TRACE_READ))
1091 if (!getAttribute(READ))
1092 return SGRawValue<double>::DefaultValue;
1096 return _value.alias->getDoubleValue();
1098 return double(get_bool());
1100 return double(get_int());
1102 return double(get_long());
1104 return double(get_float());
1106 return get_double();
1109 return strtod(get_string(), 0);
1112 return SGRawValue<double>::DefaultValue;
1117 SGPropertyNode::getStringValue () const
1119 // Shortcut for common case
1120 if (_attr == (READ|WRITE) && _type == STRING)
1121 return get_string();
1123 if (getAttribute(TRACE_READ))
1125 if (!getAttribute(READ))
1126 return SGRawValue<const char *>::DefaultValue;
1127 return make_string();
1131 SGPropertyNode::setBoolValue (bool value)
1133 // Shortcut for common case
1134 if (_attr == (READ|WRITE) && _type == BOOL)
1135 return set_bool(value);
1137 bool result = false;
1139 if (_type == NONE || _type == UNSPECIFIED) {
1147 result = _value.alias->setBoolValue(value);
1150 result = set_bool(value);
1153 result = set_int(int(value));
1156 result = set_long(long(value));
1159 result = set_float(float(value));
1162 result = set_double(double(value));
1166 result = set_string(value ? "true" : "false");
1173 if (getAttribute(TRACE_WRITE))
1179 SGPropertyNode::setIntValue (int value)
1181 // Shortcut for common case
1182 if (_attr == (READ|WRITE) && _type == INT)
1183 return set_int(value);
1185 bool result = false;
1187 if (_type == NONE || _type == UNSPECIFIED) {
1190 _local_val.int_val = 0;
1195 result = _value.alias->setIntValue(value);
1198 result = set_bool(value == 0 ? false : true);
1201 result = set_int(value);
1204 result = set_long(long(value));
1207 result = set_float(float(value));
1210 result = set_double(double(value));
1215 sprintf(buf, "%d", value);
1216 result = set_string(buf);
1224 if (getAttribute(TRACE_WRITE))
1230 SGPropertyNode::setLongValue (long value)
1232 // Shortcut for common case
1233 if (_attr == (READ|WRITE) && _type == LONG)
1234 return set_long(value);
1236 bool result = false;
1238 if (_type == NONE || _type == UNSPECIFIED) {
1241 _local_val.long_val = 0L;
1246 result = _value.alias->setLongValue(value);
1249 result = set_bool(value == 0L ? false : true);
1252 result = set_int(int(value));
1255 result = set_long(value);
1258 result = set_float(float(value));
1261 result = set_double(double(value));
1266 sprintf(buf, "%ld", value);
1267 result = set_string(buf);
1275 if (getAttribute(TRACE_WRITE))
1281 SGPropertyNode::setFloatValue (float value)
1283 // Shortcut for common case
1284 if (_attr == (READ|WRITE) && _type == FLOAT)
1285 return set_float(value);
1287 bool result = false;
1289 if (_type == NONE || _type == UNSPECIFIED) {
1292 _local_val.float_val = 0;
1297 result = _value.alias->setFloatValue(value);
1300 result = set_bool(value == 0.0 ? false : true);
1303 result = set_int(int(value));
1306 result = set_long(long(value));
1309 result = set_float(value);
1312 result = set_double(double(value));
1317 sprintf(buf, "%f", value);
1318 result = set_string(buf);
1326 if (getAttribute(TRACE_WRITE))
1332 SGPropertyNode::setDoubleValue (double value)
1334 // Shortcut for common case
1335 if (_attr == (READ|WRITE) && _type == DOUBLE)
1336 return set_double(value);
1338 bool result = false;
1340 if (_type == NONE || _type == UNSPECIFIED) {
1342 _local_val.double_val = value;
1348 result = _value.alias->setDoubleValue(value);
1351 result = set_bool(value == 0.0L ? false : true);
1354 result = set_int(int(value));
1357 result = set_long(long(value));
1360 result = set_float(float(value));
1363 result = set_double(value);
1368 sprintf(buf, "%f", value);
1369 result = set_string(buf);
1377 if (getAttribute(TRACE_WRITE))
1383 SGPropertyNode::setStringValue (const char * value)
1385 // Shortcut for common case
1386 if (_attr == (READ|WRITE) && _type == STRING)
1387 return set_string(value);
1389 bool result = false;
1391 if (_type == NONE || _type == UNSPECIFIED) {
1398 result = _value.alias->setStringValue(value);
1401 result = set_bool((compare_strings(value, "true")
1402 || atoi(value)) ? true : false);
1405 result = set_int(atoi(value));
1408 result = set_long(strtol(value, 0, 0));
1411 result = set_float(atof(value));
1414 result = set_double(strtod(value, 0));
1418 result = set_string(value);
1425 if (getAttribute(TRACE_WRITE))
1431 SGPropertyNode::setUnspecifiedValue (const char * value)
1433 bool result = false;
1435 if (_type == NONE) {
1437 _type = UNSPECIFIED;
1442 result = _value.alias->setUnspecifiedValue(value);
1445 result = set_bool((compare_strings(value, "true")
1446 || atoi(value)) ? true : false);
1449 result = set_int(atoi(value));
1452 result = set_long(strtol(value, 0, 0));
1455 result = set_float(atof(value));
1458 result = set_double(strtod(value, 0));
1462 result = set_string(value);
1469 if (getAttribute(TRACE_WRITE))
1475 SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1477 if (_type == ALIAS || _tied)
1480 useDefault = useDefault && hasValue();
1481 bool old_val = false;
1483 old_val = getBoolValue();
1488 _value.bool_val = rawValue.clone();
1491 setBoolValue(old_val);
1497 SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1499 if (_type == ALIAS || _tied)
1502 useDefault = useDefault && hasValue();
1505 old_val = getIntValue();
1510 _value.int_val = rawValue.clone();
1513 setIntValue(old_val);
1519 SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1521 if (_type == ALIAS || _tied)
1524 useDefault = useDefault && hasValue();
1527 old_val = getLongValue();
1532 _value.long_val = rawValue.clone();
1535 setLongValue(old_val);
1541 SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1543 if (_type == ALIAS || _tied)
1546 useDefault = useDefault && hasValue();
1547 float old_val = 0.0;
1549 old_val = getFloatValue();
1554 _value.float_val = rawValue.clone();
1557 setFloatValue(old_val);
1563 SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1565 if (_type == ALIAS || _tied)
1568 useDefault = useDefault && hasValue();
1569 double old_val = 0.0;
1571 old_val = getDoubleValue();
1576 _value.double_val = rawValue.clone();
1579 setDoubleValue(old_val);
1586 SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1588 if (_type == ALIAS || _tied)
1591 useDefault = useDefault && hasValue();
1594 old_val = getStringValue();
1599 _value.string_val = rawValue.clone();
1602 setStringValue(old_val.c_str());
1608 SGPropertyNode::untie ()
1615 bool val = getBoolValue();
1618 _local_val.bool_val = val;
1622 int val = getIntValue();
1625 _local_val.int_val = val;
1629 long val = getLongValue();
1632 _local_val.long_val = val;
1636 float val = getFloatValue();
1639 _local_val.float_val = val;
1643 double val = getDoubleValue();
1646 _local_val.double_val = val;
1651 string val = getStringValue();
1654 _local_val.string_val = copy_string(val.c_str());
1667 SGPropertyNode::getRootNode ()
1672 return _parent->getRootNode();
1675 const SGPropertyNode *
1676 SGPropertyNode::getRootNode () const
1681 return _parent->getRootNode();
1685 SGPropertyNode::getNode (const char * relative_path, bool create)
1687 if (_path_cache == 0)
1688 _path_cache = new hash_table;
1690 SGPropertyNode * result = _path_cache->get(relative_path);
1692 vector<PathComponent> components;
1693 parse_path(relative_path, components);
1694 result = find_node(this, components, 0, create);
1696 _path_cache->put(relative_path, result);
1703 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1705 vector<PathComponent> components;
1706 parse_path(relative_path, components);
1707 if (components.size() > 0)
1708 components[components.size()-1].index = index;
1709 return find_node(this, components, 0, create);
1712 const SGPropertyNode *
1713 SGPropertyNode::getNode (const char * relative_path) const
1715 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1718 const SGPropertyNode *
1719 SGPropertyNode::getNode (const char * relative_path, int index) const
1721 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1725 ////////////////////////////////////////////////////////////////////////
1726 // Convenience methods using relative paths.
1727 ////////////////////////////////////////////////////////////////////////
1731 * Test whether another node has a value attached.
1734 SGPropertyNode::hasValue (const char * relative_path) const
1736 const SGPropertyNode * node = getNode(relative_path);
1737 return (node == 0 ? false : node->hasValue());
1742 * Get the value type for another node.
1744 SGPropertyNode::Type
1745 SGPropertyNode::getType (const char * relative_path) const
1747 const SGPropertyNode * node = getNode(relative_path);
1748 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1753 * Get a bool value for another node.
1756 SGPropertyNode::getBoolValue (const char * relative_path,
1757 bool defaultValue) const
1759 const SGPropertyNode * node = getNode(relative_path);
1760 return (node == 0 ? defaultValue : node->getBoolValue());
1765 * Get an int value for another node.
1768 SGPropertyNode::getIntValue (const char * relative_path,
1769 int defaultValue) const
1771 const SGPropertyNode * node = getNode(relative_path);
1772 return (node == 0 ? defaultValue : node->getIntValue());
1777 * Get a long value for another node.
1780 SGPropertyNode::getLongValue (const char * relative_path,
1781 long defaultValue) const
1783 const SGPropertyNode * node = getNode(relative_path);
1784 return (node == 0 ? defaultValue : node->getLongValue());
1789 * Get a float value for another node.
1792 SGPropertyNode::getFloatValue (const char * relative_path,
1793 float defaultValue) const
1795 const SGPropertyNode * node = getNode(relative_path);
1796 return (node == 0 ? defaultValue : node->getFloatValue());
1801 * Get a double value for another node.
1804 SGPropertyNode::getDoubleValue (const char * relative_path,
1805 double defaultValue) const
1807 const SGPropertyNode * node = getNode(relative_path);
1808 return (node == 0 ? defaultValue : node->getDoubleValue());
1813 * Get a string value for another node.
1816 SGPropertyNode::getStringValue (const char * relative_path,
1817 const char * defaultValue) const
1819 const SGPropertyNode * node = getNode(relative_path);
1820 return (node == 0 ? defaultValue : node->getStringValue());
1825 * Set a bool value for another node.
1828 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1830 return getNode(relative_path, true)->setBoolValue(value);
1835 * Set an int value for another node.
1838 SGPropertyNode::setIntValue (const char * relative_path, int value)
1840 return getNode(relative_path, true)->setIntValue(value);
1845 * Set a long value for another node.
1848 SGPropertyNode::setLongValue (const char * relative_path, long value)
1850 return getNode(relative_path, true)->setLongValue(value);
1855 * Set a float value for another node.
1858 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1860 return getNode(relative_path, true)->setFloatValue(value);
1865 * Set a double value for another node.
1868 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1870 return getNode(relative_path, true)->setDoubleValue(value);
1875 * Set a string value for another node.
1878 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1880 return getNode(relative_path, true)->setStringValue(value);
1885 * Set an unknown value for another node.
1888 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1891 return getNode(relative_path, true)->setUnspecifiedValue(value);
1896 * Test whether another node is tied.
1899 SGPropertyNode::isTied (const char * relative_path) const
1901 const SGPropertyNode * node = getNode(relative_path);
1902 return (node == 0 ? false : node->isTied());
1907 * Tie a node reached by a relative path, creating it if necessary.
1910 SGPropertyNode::tie (const char * relative_path,
1911 const SGRawValue<bool> &rawValue,
1914 return getNode(relative_path, true)->tie(rawValue, useDefault);
1919 * Tie a node reached by a relative path, creating it if necessary.
1922 SGPropertyNode::tie (const char * relative_path,
1923 const SGRawValue<int> &rawValue,
1926 return getNode(relative_path, true)->tie(rawValue, useDefault);
1931 * Tie a node reached by a relative path, creating it if necessary.
1934 SGPropertyNode::tie (const char * relative_path,
1935 const SGRawValue<long> &rawValue,
1938 return getNode(relative_path, true)->tie(rawValue, useDefault);
1943 * Tie a node reached by a relative path, creating it if necessary.
1946 SGPropertyNode::tie (const char * relative_path,
1947 const SGRawValue<float> &rawValue,
1950 return getNode(relative_path, true)->tie(rawValue, useDefault);
1955 * Tie a node reached by a relative path, creating it if necessary.
1958 SGPropertyNode::tie (const char * relative_path,
1959 const SGRawValue<double> &rawValue,
1962 return getNode(relative_path, true)->tie(rawValue, useDefault);
1967 * Tie a node reached by a relative path, creating it if necessary.
1970 SGPropertyNode::tie (const char * relative_path,
1971 const SGRawValue<const char *> &rawValue,
1974 return getNode(relative_path, true)->tie(rawValue, useDefault);
1979 * Attempt to untie another node reached by a relative path.
1982 SGPropertyNode::untie (const char * relative_path)
1984 SGPropertyNode * node = getNode(relative_path);
1985 return (node == 0 ? false : node->untie());
1989 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener)
1991 if (_listeners == 0)
1992 _listeners = new vector<SGPropertyChangeListener *>;
1993 _listeners->push_back(listener);
1994 listener->register_property(this);
1998 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2000 vector<SGPropertyChangeListener *>::iterator it =
2001 find(_listeners->begin(), _listeners->end(), listener);
2002 if (it != _listeners->end()) {
2003 _listeners->erase(it);
2004 listener->unregister_property(this);
2005 if (_listeners->empty()) {
2006 vector<SGPropertyChangeListener *> * tmp = _listeners;
2014 SGPropertyNode::fireValueChanged ()
2016 fireValueChanged(this);
2020 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2022 fireChildAdded(this, child);
2026 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2028 fireChildRemoved(this, child);
2032 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2034 if (_listeners != 0) {
2035 for (int i = 0; i < _listeners->size(); i++) {
2036 (*_listeners)[i]->valueChanged(node);
2040 _parent->fireValueChanged(node);
2044 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2045 SGPropertyNode * child)
2047 if (_listeners != 0) {
2048 for (int i = 0; i < _listeners->size(); i++) {
2049 (*_listeners)[i]->childAdded(parent, child);
2053 _parent->fireChildAdded(parent, child);
2057 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2058 SGPropertyNode * child)
2060 if (_listeners != 0) {
2061 for (int i = 0; i < _listeners->size(); i++) {
2062 (*_listeners)[i]->childRemoved(parent, child);
2066 _parent->fireChildRemoved(parent, child);
2071 ////////////////////////////////////////////////////////////////////////
2072 // Simplified hash table for caching paths.
2073 ////////////////////////////////////////////////////////////////////////
2075 #define HASH_TABLE_SIZE 199
2077 SGPropertyNode::hash_table::entry::entry ()
2083 SGPropertyNode::hash_table::entry::~entry ()
2085 // Don't delete the value; we don't own
2091 SGPropertyNode::hash_table::entry::set_key (const char * key)
2093 _key = copy_string(key);
2097 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2102 SGPropertyNode::hash_table::bucket::bucket ()
2108 SGPropertyNode::hash_table::bucket::~bucket ()
2110 for (int i = 0; i < _length; i++)
2114 SGPropertyNode::hash_table::entry *
2115 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2118 for (i = 0; i < _length; i++) {
2119 if (!strcmp(_entries[i]->get_key(), key))
2123 entry ** new_entries = new entry*[_length+1];
2124 for (i = 0; i < _length; i++) {
2125 new_entries[i] = _entries[i];
2128 _entries = new_entries;
2129 _entries[_length] = new entry;
2130 _entries[_length]->set_key(key);
2132 return _entries[_length - 1];
2139 SGPropertyNode::hash_table::hash_table ()
2145 SGPropertyNode::hash_table::~hash_table ()
2147 for (unsigned int i = 0; i < _data_length; i++)
2152 SGPropertyNode::hash_table::get (const char * key)
2154 if (_data_length == 0)
2156 unsigned int index = hashcode(key) % _data_length;
2157 if (_data[index] == 0)
2159 entry * e = _data[index]->get_entry(key);
2163 return e->get_value();
2167 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2169 if (_data_length == 0) {
2170 _data = new bucket*[HASH_TABLE_SIZE];
2171 _data_length = HASH_TABLE_SIZE;
2172 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2175 unsigned int index = hashcode(key) % _data_length;
2176 if (_data[index] == 0) {
2177 _data[index] = new bucket;
2179 entry * e = _data[index]->get_entry(key, true);
2180 e->set_value(value);
2184 SGPropertyNode::hash_table::hashcode (const char * key)
2186 unsigned int hash = 0;
2188 hash = 31 * hash + *key;
2197 * Default constructor
2199 SGPropertyNode_ptr::SGPropertyNode_ptr()
2207 SGPropertyNode_ptr::SGPropertyNode_ptr( const SGPropertyNode_ptr &r )
2211 _ptr->incrementRef();
2215 * Constructor from a pointer to a node
2217 SGPropertyNode_ptr::SGPropertyNode_ptr( SGPropertyNode *p )
2221 _ptr->incrementRef();
2227 SGPropertyNode_ptr::~SGPropertyNode_ptr()
2229 if (_ptr && _ptr->decrementRef() == 0)
2234 * Assignement operator
2236 SGPropertyNode_ptr &
2237 SGPropertyNode_ptr::operator=( const SGPropertyNode_ptr &r )
2239 if (_ptr && _ptr->decrementRef() == 0)
2243 _ptr->incrementRef();
2249 * Pointer access operator
2252 SGPropertyNode_ptr::operator->()
2258 * Pointer access operator (const)
2260 const SGPropertyNode *
2261 SGPropertyNode_ptr::operator->() const
2267 * Conversion to SGPropertyNode * operator
2269 SGPropertyNode_ptr::operator SGPropertyNode *()
2275 * Conversion to const SGPropertyNode * operator
2277 SGPropertyNode_ptr::operator const SGPropertyNode *() const
2286 SGPropertyNode_ptr::valid() const
2293 ////////////////////////////////////////////////////////////////////////
2294 // Implementation of SGPropertyChangeListener.
2295 ////////////////////////////////////////////////////////////////////////
2297 SGPropertyChangeListener::~SGPropertyChangeListener ()
2299 // This will come back and remove
2300 // the current item each time. Is
2302 vector<SGPropertyNode *>::iterator it;
2303 for (it = _properties.begin(); it != _properties.end(); it++)
2304 (*it)->removeChangeListener(this);
2308 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2314 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2315 SGPropertyNode * child)
2321 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2322 SGPropertyNode * child)
2328 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2330 _properties.push_back(node);
2334 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2336 vector<SGPropertyNode *>::iterator it =
2337 find(_properties.begin(), _properties.end(), node);
2338 if (it != _properties.end())
2339 _properties.erase(it);