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].
21 #include <simgear/compiler.h>
22 #include <simgear/debug/logstream.hxx>
24 #if ( _MSC_VER == 1200 )
25 // MSVC 6 is buggy, and needs something strange here
26 using std::vector<SGPropertyNode_ptr>;
27 using std::vector<SGPropertyChangeListener *>;
28 using std::vector<SGPropertyNode *>;
40 using std::stringstream;
42 using namespace simgear;
43 using namespace simgear::props;
46 ////////////////////////////////////////////////////////////////////////
48 ////////////////////////////////////////////////////////////////////////
51 * Comparator class for sorting by index.
56 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
57 return (n1->getIndex() < n2->getIndex());
63 ////////////////////////////////////////////////////////////////////////
64 // Convenience macros for value access.
65 ////////////////////////////////////////////////////////////////////////
67 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
68 #define TEST_WRITE if (!getAttribute(WRITE)) return false
70 ////////////////////////////////////////////////////////////////////////
71 // Default values for every type.
72 ////////////////////////////////////////////////////////////////////////
74 template<> const bool SGRawValue<bool>::DefaultValue = false;
75 template<> const int SGRawValue<int>::DefaultValue = 0;
76 template<> const long SGRawValue<long>::DefaultValue = 0L;
77 template<> const float SGRawValue<float>::DefaultValue = 0.0;
78 template<> const double SGRawValue<double>::DefaultValue = 0.0L;
79 template<> const char * const SGRawValue<const char *>::DefaultValue = "";
81 ////////////////////////////////////////////////////////////////////////
82 // Local path normalization code.
83 ////////////////////////////////////////////////////////////////////////
86 * A component in a path.
95 * Parse the name for a path component.
97 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
99 static inline const string
100 parse_name (const string &path, int &i)
103 int max = path.size();
105 if (path[i] == '.') {
107 if (i < max && path[i] == '.') {
113 if (i < max && path[i] != '/')
114 throw string("illegal character after " + name);
117 else if (isalpha(path[i]) || path[i] == '_') {
121 // The rules inside a name are a little
124 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
125 path[i] == '-' || path[i] == '.') {
127 } else if (path[i] == '[' || path[i] == '/') {
130 throw string("name may contain only ._- and alphanumeric characters");
137 if (name.size() == 0)
138 throw string("name must begin with alpha or '_'");
146 * Parse the optional integer index for a path component.
148 * Index: "[" [0-9]+ "]"
151 parse_index (const string &path, int &i)
160 for (int max = path.size(); i < max; i++) {
161 if (isdigit(path[i])) {
162 index = (index * 10) + (path[i] - '0');
163 } else if (path[i] == ']') {
171 throw string("unterminated index (looking for ']')");
176 * Parse a single path component.
178 * Component: Name Index?
180 static inline PathComponent
181 parse_component (const string &path, int &i)
183 PathComponent component;
184 component.name = parse_name(path, i);
185 if (component.name[0] != '.')
186 component.index = parse_index(path, i);
188 component.index = -1;
194 * Parse a path into its components.
197 parse_path (const string &path, vector<PathComponent> &components)
200 int max = path.size();
202 // Check for initial '/'
203 if (path[pos] == '/') {
207 components.push_back(root);
209 while (pos < max && path[pos] == '/')
214 components.push_back(parse_component(path, pos));
215 while (pos < max && path[pos] == '/')
222 ////////////////////////////////////////////////////////////////////////
223 // Other static utility functions.
224 ////////////////////////////////////////////////////////////////////////
228 copy_string (const char * s)
230 unsigned long int slen = strlen(s);
231 char * copy = new char[slen + 1];
233 // the source string length is known so no need to check for '\0'
234 // when copying every single character
235 memcpy(copy, s, slen);
236 *(copy + slen) = '\0';
241 compare_strings (const char * s1, const char * s2)
243 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
247 * Locate a child node by name and index.
250 find_child (const char * name, int index, const vector<SGPropertyNode_ptr>& nodes)
252 int nNodes = nodes.size();
253 for (int i = 0; i < nNodes; i++) {
254 SGPropertyNode * node = nodes[i];
256 // searching for a mathing index is a lot less time consuming than
257 // comparing two strings so do that first.
258 if (node->getIndex() == index && compare_strings(node->getName(), name))
265 * Locate the child node with the highest index of the same name
268 find_last_child (const char * name, const vector<SGPropertyNode_ptr>& nodes)
270 int nNodes = nodes.size();
273 for (int i = 0; i < nNodes; i++) {
274 SGPropertyNode * node = nodes[i];
275 if (compare_strings(node->getName(), name))
277 int idx = node->getIndex();
278 if (idx > index) index = idx;
286 * Locate another node, given a relative path.
288 static SGPropertyNode *
289 find_node (SGPropertyNode * current,
290 const vector<PathComponent> &components,
294 // Run off the end of the list
299 // Success! This is the one we want.
300 else if (position >= (int)components.size()) {
301 return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
304 // Empty component means root.
305 else if (components[position].name == "") {
306 return find_node(current->getRootNode(), components, position + 1, create);
309 // . means current directory
310 else if (components[position].name == ".") {
311 return find_node(current, components, position + 1, create);
314 // .. means parent directory
315 else if (components[position].name == "..") {
316 SGPropertyNode * parent = current->getParent();
318 throw string("attempt to move past root with '..'");
320 return find_node(parent, components, position + 1, create);
323 // Otherwise, a child name
325 SGPropertyNode * child =
326 current->getChild(components[position].name.c_str(),
327 components[position].index,
329 return find_node(child, components, position + 1, create);
335 ////////////////////////////////////////////////////////////////////////
336 // Private methods from SGPropertyNode (may be inlined for speed).
337 ////////////////////////////////////////////////////////////////////////
340 SGPropertyNode::get_bool () const
343 return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
345 return _local_val.bool_val;
349 SGPropertyNode::get_int () const
352 return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
354 return _local_val.int_val;
358 SGPropertyNode::get_long () const
361 return static_cast<SGRawValue<long>*>(_value.val)->getValue();
363 return _local_val.long_val;
367 SGPropertyNode::get_float () const
370 return static_cast<SGRawValue<float>*>(_value.val)->getValue();
372 return _local_val.float_val;
376 SGPropertyNode::get_double () const
379 return static_cast<SGRawValue<double>*>(_value.val)->getValue();
381 return _local_val.double_val;
385 SGPropertyNode::get_string () const
388 return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
390 return _local_val.string_val;
394 SGPropertyNode::set_bool (bool val)
397 if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
404 _local_val.bool_val = val;
411 SGPropertyNode::set_int (int val)
414 if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
421 _local_val.int_val = val;
428 SGPropertyNode::set_long (long val)
431 if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
438 _local_val.long_val = val;
445 SGPropertyNode::set_float (float val)
448 if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
455 _local_val.float_val = val;
462 SGPropertyNode::set_double (double val)
465 if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
472 _local_val.double_val = val;
479 SGPropertyNode::set_string (const char * val)
482 if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
489 delete [] _local_val.string_val;
490 _local_val.string_val = copy_string(val);
497 SGPropertyNode::clearValue ()
499 if (_type == ALIAS) {
502 } else if (_type != NONE) {
505 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
508 _local_val.int_val = SGRawValue<int>::DefaultValue;
511 _local_val.long_val = SGRawValue<long>::DefaultValue;
514 _local_val.float_val = SGRawValue<float>::DefaultValue;
517 _local_val.double_val = SGRawValue<double>::DefaultValue;
522 delete [] _local_val.string_val;
524 _local_val.string_val = 0;
536 * Get the value as a string.
539 SGPropertyNode::make_string () const
541 if (!getAttribute(READ))
546 return _value.alias->getStringValue();
556 _buffer = sstr.str();
557 return _buffer.c_str();
563 _buffer = sstr.str();
564 return _buffer.c_str();
570 _buffer = sstr.str();
571 return _buffer.c_str();
576 sstr.precision( 10 );
577 sstr << get_double();
578 _buffer = sstr.str();
579 return _buffer.c_str();
591 * Trace a write access for a property.
594 SGPropertyNode::trace_write () const
597 cerr << "TRACE: Write node " << getPath () << ", value \""
598 << make_string() << '"' << endl;
600 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
601 << ", value \"" << make_string() << '"');
606 * Trace a read access for a property.
609 SGPropertyNode::trace_read () const
612 cerr << "TRACE: Write node " << getPath () << ", value \""
613 << make_string() << '"' << endl;
615 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
616 << ", value \"" << make_string() << '"');
621 ////////////////////////////////////////////////////////////////////////
622 // Public methods from SGPropertyNode.
623 ////////////////////////////////////////////////////////////////////////
626 * Last used attribute
627 * Update as needed when enum Attribute is changed
629 const int SGPropertyNode::LAST_USED_ATTRIBUTE = USERARCHIVE;
632 * Default constructor: always creates a root node.
634 SGPropertyNode::SGPropertyNode ()
643 _local_val.string_val = 0;
651 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
652 : _index(node._index),
654 _parent(0), // don't copy the parent
659 _listeners(0) // CHECK!!
661 _local_val.string_val = 0;
667 _value.alias = node._value.alias;
674 _value.val = static_cast<SGRawValue<bool>*>(node._value.val)->clone();
677 set_bool(node.get_bool());
683 _value.val = static_cast<SGRawValue<int>*>(node._value.val)->clone();
686 set_int(node.get_int());
692 _value.val = static_cast<SGRawValue<long>*>(node._value.val)->clone();
695 set_long(node.get_long());
701 _value.val = static_cast<SGRawValue<float>*>(node._value.val)->clone();
704 set_float(node.get_float());
710 _value.val = static_cast<SGRawValue<double>*>(node._value.val)->clone();
713 set_double(node.get_double());
720 _value.val = static_cast<SGRawValue<const char*>*>(node._value.val)->clone();
723 set_string(node.get_string());
731 * Convenience constructor.
733 SGPropertyNode::SGPropertyNode (const char * name,
735 SGPropertyNode * parent)
745 _local_val.string_val = 0;
747 _name = parse_name(name, i);
748 if (i != int(strlen(name)) || name[0] == '.')
749 throw string("plain name expected instead of '") + name + '\'';
756 SGPropertyNode::~SGPropertyNode ()
758 // zero out all parent pointers, else they might be dangling
759 for (unsigned i = 0; i < _children.size(); ++i)
760 _children[i]->_parent = 0;
761 for (unsigned i = 0; i < _removedChildren.size(); ++i)
762 _removedChildren[i]->_parent = 0;
767 vector<SGPropertyChangeListener*>::iterator it;
768 for (it = _listeners->begin(); it != _listeners->end(); ++it)
769 (*it)->unregister_property(this);
776 * Alias to another node.
779 SGPropertyNode::alias (SGPropertyNode * target)
781 if (target == 0 || _type == ALIAS || _tied)
785 _value.alias = target;
792 * Alias to another node by path.
795 SGPropertyNode::alias (const char * path)
797 return alias(getNode(path, true));
805 SGPropertyNode::unalias ()
815 * Get the target of an alias.
818 SGPropertyNode::getAliasTarget ()
820 return (_type == ALIAS ? _value.alias : 0);
824 const SGPropertyNode *
825 SGPropertyNode::getAliasTarget () const
827 return (_type == ALIAS ? _value.alias : 0);
831 * create a non-const child by name after the last node with the same name.
834 SGPropertyNode::addChild (const char * name)
836 int pos = find_last_child(name, _children)+1;
838 SGPropertyNode_ptr node;
839 node = new SGPropertyNode(name, pos, this);
840 _children.push_back(node);
841 fireChildAdded(node);
847 * Get a non-const child by index.
850 SGPropertyNode::getChild (int position)
852 if (position >= 0 && position < nChildren())
853 return _children[position];
860 * Get a const child by index.
862 const SGPropertyNode *
863 SGPropertyNode::getChild (int position) const
865 if (position >= 0 && position < nChildren())
866 return _children[position];
873 * Get a non-const child by name and index, creating if necessary.
876 SGPropertyNode::getChild (const char * name, int index, bool create)
878 int pos = find_child(name, index, _children);
880 return _children[pos];
882 SGPropertyNode_ptr node;
883 pos = find_child(name, index, _removedChildren);
885 vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
887 node = _removedChildren[pos];
888 _removedChildren.erase(it);
889 node->setAttribute(REMOVED, false);
891 node = new SGPropertyNode(name, index, this);
893 _children.push_back(node);
894 fireChildAdded(node);
903 * Get a const child by name and index.
905 const SGPropertyNode *
906 SGPropertyNode::getChild (const char * name, int index) const
908 int pos = find_child(name, index, _children);
910 return _children[pos];
917 * Get all children with the same name (but different indices).
919 vector<SGPropertyNode_ptr>
920 SGPropertyNode::getChildren (const char * name) const
922 vector<SGPropertyNode_ptr> children;
923 int max = _children.size();
925 for (int i = 0; i < max; i++)
926 if (compare_strings(_children[i]->getName(), name))
927 children.push_back(_children[i]);
929 sort(children.begin(), children.end(), CompareIndices());
935 * Remove this node and all children from nodes that link to them
936 * in their path cache.
939 SGPropertyNode::remove_from_path_caches ()
941 for (unsigned int i = 0; i < _children.size(); ++i)
942 _children[i]->remove_from_path_caches();
944 for (unsigned int i = 0; i < _linkedNodes.size(); i++)
945 _linkedNodes[i]->erase(this);
946 _linkedNodes.clear();
951 * Remove child by position.
954 SGPropertyNode::removeChild (int pos, bool keep)
956 SGPropertyNode_ptr node;
957 if (pos < 0 || pos >= (int)_children.size())
960 vector<SGPropertyNode_ptr>::iterator it = _children.begin();
962 node = _children[pos];
965 _removedChildren.push_back(node);
968 node->remove_from_path_caches();
969 node->setAttribute(REMOVED, true);
971 fireChildRemoved(node);
977 * Remove a child node
980 SGPropertyNode::removeChild (const char * name, int index, bool keep)
982 SGPropertyNode_ptr ret;
983 int pos = find_child(name, index, _children);
985 ret = removeChild(pos, keep);
991 * Remove all children with the specified name.
993 vector<SGPropertyNode_ptr>
994 SGPropertyNode::removeChildren (const char * name, bool keep)
996 vector<SGPropertyNode_ptr> children;
998 for (int pos = _children.size() - 1; pos >= 0; pos--)
999 if (compare_strings(_children[pos]->getName(), name))
1000 children.push_back(removeChild(pos, keep));
1002 sort(children.begin(), children.end(), CompareIndices());
1008 * Remove a linked node.
1011 SGPropertyNode::remove_linked_node (hash_table * node)
1013 for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
1014 if (_linkedNodes[i] == node) {
1015 vector<hash_table *>::iterator it = _linkedNodes.begin();
1017 _linkedNodes.erase(it);
1026 SGPropertyNode::getDisplayName (bool simplify) const
1028 _display_name = _name;
1029 if (_index != 0 || !simplify) {
1031 sstr << '[' << _index << ']';
1032 _display_name += sstr.str();
1034 return _display_name.c_str();
1039 SGPropertyNode::getPath (bool simplify) const
1041 // Calculate the complete path only once.
1042 if (_parent != 0 && _path.empty()) {
1043 _path = _parent->getPath(simplify);
1045 _path += getDisplayName(simplify);
1048 return _path.c_str();
1052 SGPropertyNode::getType () const
1055 return _value.alias->getType();
1062 SGPropertyNode::getBoolValue () const
1064 // Shortcut for common case
1065 if (_attr == (READ|WRITE) && _type == BOOL)
1068 if (getAttribute(TRACE_READ))
1070 if (!getAttribute(READ))
1071 return SGRawValue<bool>::DefaultValue;
1074 return _value.alias->getBoolValue();
1078 return get_int() == 0 ? false : true;
1080 return get_long() == 0L ? false : true;
1082 return get_float() == 0.0 ? false : true;
1084 return get_double() == 0.0L ? false : true;
1087 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1090 return SGRawValue<bool>::DefaultValue;
1095 SGPropertyNode::getIntValue () const
1097 // Shortcut for common case
1098 if (_attr == (READ|WRITE) && _type == INT)
1101 if (getAttribute(TRACE_READ))
1103 if (!getAttribute(READ))
1104 return SGRawValue<int>::DefaultValue;
1107 return _value.alias->getIntValue();
1109 return int(get_bool());
1113 return int(get_long());
1115 return int(get_float());
1117 return int(get_double());
1120 return atoi(get_string());
1123 return SGRawValue<int>::DefaultValue;
1128 SGPropertyNode::getLongValue () const
1130 // Shortcut for common case
1131 if (_attr == (READ|WRITE) && _type == LONG)
1134 if (getAttribute(TRACE_READ))
1136 if (!getAttribute(READ))
1137 return SGRawValue<long>::DefaultValue;
1140 return _value.alias->getLongValue();
1142 return long(get_bool());
1144 return long(get_int());
1148 return long(get_float());
1150 return long(get_double());
1153 return strtol(get_string(), 0, 0);
1156 return SGRawValue<long>::DefaultValue;
1161 SGPropertyNode::getFloatValue () const
1163 // Shortcut for common case
1164 if (_attr == (READ|WRITE) && _type == FLOAT)
1167 if (getAttribute(TRACE_READ))
1169 if (!getAttribute(READ))
1170 return SGRawValue<float>::DefaultValue;
1173 return _value.alias->getFloatValue();
1175 return float(get_bool());
1177 return float(get_int());
1179 return float(get_long());
1183 return float(get_double());
1186 return atof(get_string());
1189 return SGRawValue<float>::DefaultValue;
1194 SGPropertyNode::getDoubleValue () const
1196 // Shortcut for common case
1197 if (_attr == (READ|WRITE) && _type == DOUBLE)
1198 return get_double();
1200 if (getAttribute(TRACE_READ))
1202 if (!getAttribute(READ))
1203 return SGRawValue<double>::DefaultValue;
1207 return _value.alias->getDoubleValue();
1209 return double(get_bool());
1211 return double(get_int());
1213 return double(get_long());
1215 return double(get_float());
1217 return get_double();
1220 return strtod(get_string(), 0);
1223 return SGRawValue<double>::DefaultValue;
1228 SGPropertyNode::getStringValue () const
1230 // Shortcut for common case
1231 if (_attr == (READ|WRITE) && _type == STRING)
1232 return get_string();
1234 if (getAttribute(TRACE_READ))
1236 if (!getAttribute(READ))
1237 return SGRawValue<const char *>::DefaultValue;
1238 return make_string();
1242 SGPropertyNode::setBoolValue (bool value)
1244 // Shortcut for common case
1245 if (_attr == (READ|WRITE) && _type == BOOL)
1246 return set_bool(value);
1248 bool result = false;
1250 if (_type == NONE || _type == UNSPECIFIED) {
1258 result = _value.alias->setBoolValue(value);
1261 result = set_bool(value);
1264 result = set_int(int(value));
1267 result = set_long(long(value));
1270 result = set_float(float(value));
1273 result = set_double(double(value));
1277 result = set_string(value ? "true" : "false");
1284 if (getAttribute(TRACE_WRITE))
1290 SGPropertyNode::setIntValue (int value)
1292 // Shortcut for common case
1293 if (_attr == (READ|WRITE) && _type == INT)
1294 return set_int(value);
1296 bool result = false;
1298 if (_type == NONE || _type == UNSPECIFIED) {
1301 _local_val.int_val = 0;
1306 result = _value.alias->setIntValue(value);
1309 result = set_bool(value == 0 ? false : true);
1312 result = set_int(value);
1315 result = set_long(long(value));
1318 result = set_float(float(value));
1321 result = set_double(double(value));
1326 sprintf(buf, "%d", value);
1327 result = set_string(buf);
1335 if (getAttribute(TRACE_WRITE))
1341 SGPropertyNode::setLongValue (long value)
1343 // Shortcut for common case
1344 if (_attr == (READ|WRITE) && _type == LONG)
1345 return set_long(value);
1347 bool result = false;
1349 if (_type == NONE || _type == UNSPECIFIED) {
1352 _local_val.long_val = 0L;
1357 result = _value.alias->setLongValue(value);
1360 result = set_bool(value == 0L ? false : true);
1363 result = set_int(int(value));
1366 result = set_long(value);
1369 result = set_float(float(value));
1372 result = set_double(double(value));
1377 sprintf(buf, "%ld", value);
1378 result = set_string(buf);
1386 if (getAttribute(TRACE_WRITE))
1392 SGPropertyNode::setFloatValue (float value)
1394 // Shortcut for common case
1395 if (_attr == (READ|WRITE) && _type == FLOAT)
1396 return set_float(value);
1398 bool result = false;
1400 if (_type == NONE || _type == UNSPECIFIED) {
1403 _local_val.float_val = 0;
1408 result = _value.alias->setFloatValue(value);
1411 result = set_bool(value == 0.0 ? false : true);
1414 result = set_int(int(value));
1417 result = set_long(long(value));
1420 result = set_float(value);
1423 result = set_double(double(value));
1428 sprintf(buf, "%f", value);
1429 result = set_string(buf);
1437 if (getAttribute(TRACE_WRITE))
1443 SGPropertyNode::setDoubleValue (double value)
1445 // Shortcut for common case
1446 if (_attr == (READ|WRITE) && _type == DOUBLE)
1447 return set_double(value);
1449 bool result = false;
1451 if (_type == NONE || _type == UNSPECIFIED) {
1453 _local_val.double_val = value;
1459 result = _value.alias->setDoubleValue(value);
1462 result = set_bool(value == 0.0L ? false : true);
1465 result = set_int(int(value));
1468 result = set_long(long(value));
1471 result = set_float(float(value));
1474 result = set_double(value);
1479 sprintf(buf, "%f", value);
1480 result = set_string(buf);
1488 if (getAttribute(TRACE_WRITE))
1494 SGPropertyNode::setStringValue (const char * value)
1496 // Shortcut for common case
1497 if (_attr == (READ|WRITE) && _type == STRING)
1498 return set_string(value);
1500 bool result = false;
1502 if (_type == NONE || _type == UNSPECIFIED) {
1509 result = _value.alias->setStringValue(value);
1512 result = set_bool((compare_strings(value, "true")
1513 || atoi(value)) ? true : false);
1516 result = set_int(atoi(value));
1519 result = set_long(strtol(value, 0, 0));
1522 result = set_float(atof(value));
1525 result = set_double(strtod(value, 0));
1529 result = set_string(value);
1536 if (getAttribute(TRACE_WRITE))
1542 SGPropertyNode::setUnspecifiedValue (const char * value)
1544 bool result = false;
1546 if (_type == NONE) {
1548 _type = UNSPECIFIED;
1553 result = _value.alias->setUnspecifiedValue(value);
1556 result = set_bool((compare_strings(value, "true")
1557 || atoi(value)) ? true : false);
1560 result = set_int(atoi(value));
1563 result = set_long(strtol(value, 0, 0));
1566 result = set_float(atof(value));
1569 result = set_double(strtod(value, 0));
1573 result = set_string(value);
1580 if (getAttribute(TRACE_WRITE))
1586 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1589 if (_type == ALIAS || _tied)
1592 useDefault = useDefault && hasValue();
1593 std::string old_val;
1595 old_val = getStringValue();
1599 _value.val = rawValue.clone();
1602 setStringValue(old_val.c_str());
1607 SGPropertyNode::untie ()
1614 bool val = getBoolValue();
1617 _local_val.bool_val = val;
1621 int val = getIntValue();
1624 _local_val.int_val = val;
1628 long val = getLongValue();
1631 _local_val.long_val = val;
1635 float val = getFloatValue();
1638 _local_val.float_val = val;
1642 double val = getDoubleValue();
1645 _local_val.double_val = val;
1650 string val = getStringValue();
1653 _local_val.string_val = copy_string(val.c_str());
1666 SGPropertyNode::getRootNode ()
1671 return _parent->getRootNode();
1674 const SGPropertyNode *
1675 SGPropertyNode::getRootNode () const
1680 return _parent->getRootNode();
1684 SGPropertyNode::getNode (const char * relative_path, bool create)
1686 if (_path_cache == 0)
1687 _path_cache = new hash_table;
1689 SGPropertyNode * result = _path_cache->get(relative_path);
1691 vector<PathComponent> components;
1692 parse_path(relative_path, components);
1693 result = find_node(this, components, 0, create);
1695 _path_cache->put(relative_path, result);
1702 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1704 vector<PathComponent> components;
1705 parse_path(relative_path, components);
1706 if (components.size() > 0)
1707 components.back().index = index;
1708 return find_node(this, components, 0, create);
1711 const SGPropertyNode *
1712 SGPropertyNode::getNode (const char * relative_path) const
1714 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1717 const SGPropertyNode *
1718 SGPropertyNode::getNode (const char * relative_path, int index) const
1720 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1724 ////////////////////////////////////////////////////////////////////////
1725 // Convenience methods using relative paths.
1726 ////////////////////////////////////////////////////////////////////////
1730 * Test whether another node has a value attached.
1733 SGPropertyNode::hasValue (const char * relative_path) const
1735 const SGPropertyNode * node = getNode(relative_path);
1736 return (node == 0 ? false : node->hasValue());
1741 * Get the value type for another node.
1744 SGPropertyNode::getType (const char * relative_path) const
1746 const SGPropertyNode * node = getNode(relative_path);
1747 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1752 * Get a bool value for another node.
1755 SGPropertyNode::getBoolValue (const char * relative_path,
1756 bool defaultValue) const
1758 const SGPropertyNode * node = getNode(relative_path);
1759 return (node == 0 ? defaultValue : node->getBoolValue());
1764 * Get an int value for another node.
1767 SGPropertyNode::getIntValue (const char * relative_path,
1768 int defaultValue) const
1770 const SGPropertyNode * node = getNode(relative_path);
1771 return (node == 0 ? defaultValue : node->getIntValue());
1776 * Get a long value for another node.
1779 SGPropertyNode::getLongValue (const char * relative_path,
1780 long defaultValue) const
1782 const SGPropertyNode * node = getNode(relative_path);
1783 return (node == 0 ? defaultValue : node->getLongValue());
1788 * Get a float value for another node.
1791 SGPropertyNode::getFloatValue (const char * relative_path,
1792 float defaultValue) const
1794 const SGPropertyNode * node = getNode(relative_path);
1795 return (node == 0 ? defaultValue : node->getFloatValue());
1800 * Get a double value for another node.
1803 SGPropertyNode::getDoubleValue (const char * relative_path,
1804 double defaultValue) const
1806 const SGPropertyNode * node = getNode(relative_path);
1807 return (node == 0 ? defaultValue : node->getDoubleValue());
1812 * Get a string value for another node.
1815 SGPropertyNode::getStringValue (const char * relative_path,
1816 const char * defaultValue) const
1818 const SGPropertyNode * node = getNode(relative_path);
1819 return (node == 0 ? defaultValue : node->getStringValue());
1824 * Set a bool value for another node.
1827 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1829 return getNode(relative_path, true)->setBoolValue(value);
1834 * Set an int value for another node.
1837 SGPropertyNode::setIntValue (const char * relative_path, int value)
1839 return getNode(relative_path, true)->setIntValue(value);
1844 * Set a long value for another node.
1847 SGPropertyNode::setLongValue (const char * relative_path, long value)
1849 return getNode(relative_path, true)->setLongValue(value);
1854 * Set a float value for another node.
1857 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1859 return getNode(relative_path, true)->setFloatValue(value);
1864 * Set a double value for another node.
1867 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1869 return getNode(relative_path, true)->setDoubleValue(value);
1874 * Set a string value for another node.
1877 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1879 return getNode(relative_path, true)->setStringValue(value);
1884 * Set an unknown value for another node.
1887 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1890 return getNode(relative_path, true)->setUnspecifiedValue(value);
1895 * Test whether another node is tied.
1898 SGPropertyNode::isTied (const char * relative_path) const
1900 const SGPropertyNode * node = getNode(relative_path);
1901 return (node == 0 ? false : node->isTied());
1906 * Tie a node reached by a relative path, creating it if necessary.
1909 SGPropertyNode::tie (const char * relative_path,
1910 const SGRawValue<bool> &rawValue,
1913 return getNode(relative_path, true)->tie(rawValue, useDefault);
1918 * Tie a node reached by a relative path, creating it if necessary.
1921 SGPropertyNode::tie (const char * relative_path,
1922 const SGRawValue<int> &rawValue,
1925 return getNode(relative_path, true)->tie(rawValue, useDefault);
1930 * Tie a node reached by a relative path, creating it if necessary.
1933 SGPropertyNode::tie (const char * relative_path,
1934 const SGRawValue<long> &rawValue,
1937 return getNode(relative_path, true)->tie(rawValue, useDefault);
1942 * Tie a node reached by a relative path, creating it if necessary.
1945 SGPropertyNode::tie (const char * relative_path,
1946 const SGRawValue<float> &rawValue,
1949 return getNode(relative_path, true)->tie(rawValue, useDefault);
1954 * Tie a node reached by a relative path, creating it if necessary.
1957 SGPropertyNode::tie (const char * relative_path,
1958 const SGRawValue<double> &rawValue,
1961 return getNode(relative_path, true)->tie(rawValue, useDefault);
1966 * Tie a node reached by a relative path, creating it if necessary.
1969 SGPropertyNode::tie (const char * relative_path,
1970 const SGRawValue<const char *> &rawValue,
1973 return getNode(relative_path, true)->tie(rawValue, useDefault);
1978 * Attempt to untie another node reached by a relative path.
1981 SGPropertyNode::untie (const char * relative_path)
1983 SGPropertyNode * node = getNode(relative_path);
1984 return (node == 0 ? false : node->untie());
1988 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
1991 if (_listeners == 0)
1992 _listeners = new vector<SGPropertyChangeListener*>;
1993 _listeners->push_back(listener);
1994 listener->register_property(this);
1996 listener->valueChanged(this);
2000 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2002 vector<SGPropertyChangeListener*>::iterator it =
2003 find(_listeners->begin(), _listeners->end(), listener);
2004 if (it != _listeners->end()) {
2005 _listeners->erase(it);
2006 listener->unregister_property(this);
2007 if (_listeners->empty()) {
2008 vector<SGPropertyChangeListener*>* tmp = _listeners;
2016 SGPropertyNode::fireValueChanged ()
2018 fireValueChanged(this);
2022 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2024 fireChildAdded(this, child);
2028 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2030 fireChildRemoved(this, child);
2034 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2036 if (_listeners != 0) {
2037 for (unsigned int i = 0; i < _listeners->size(); i++) {
2038 (*_listeners)[i]->valueChanged(node);
2042 _parent->fireValueChanged(node);
2046 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2047 SGPropertyNode * child)
2049 if (_listeners != 0) {
2050 for (unsigned int i = 0; i < _listeners->size(); i++) {
2051 (*_listeners)[i]->childAdded(parent, child);
2055 _parent->fireChildAdded(parent, child);
2059 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2060 SGPropertyNode * child)
2062 if (_listeners != 0) {
2063 for (unsigned int i = 0; i < _listeners->size(); i++) {
2064 (*_listeners)[i]->childRemoved(parent, child);
2068 _parent->fireChildRemoved(parent, child);
2073 ////////////////////////////////////////////////////////////////////////
2074 // Simplified hash table for caching paths.
2075 ////////////////////////////////////////////////////////////////////////
2077 #define HASH_TABLE_SIZE 199
2079 SGPropertyNode::hash_table::entry::entry ()
2084 SGPropertyNode::hash_table::entry::~entry ()
2086 // Don't delete the value; we don't own
2091 SGPropertyNode::hash_table::entry::set_key (const char * 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++)
2115 SGPropertyNode::hash_table::entry *
2116 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2119 for (i = 0; i < _length; i++) {
2120 if (!strcmp(_entries[i]->get_key(), key))
2124 entry ** new_entries = new entry*[_length+1];
2125 for (i = 0; i < _length; i++) {
2126 new_entries[i] = _entries[i];
2129 _entries = new_entries;
2130 _entries[_length] = new entry;
2131 _entries[_length]->set_key(key);
2133 return _entries[_length - 1];
2140 SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
2142 for (int i = 0; i < _length; i++) {
2143 if (_entries[i]->get_value() == node) {
2145 for (++i; i < _length; i++) {
2146 _entries[i-1] = _entries[i];
2156 SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
2158 for (int i = 0; i < _length; i++) {
2159 SGPropertyNode * node = _entries[i]->get_value();
2161 node->remove_linked_node(owner);
2165 SGPropertyNode::hash_table::hash_table ()
2171 SGPropertyNode::hash_table::~hash_table ()
2173 for (unsigned int i = 0; i < _data_length; i++) {
2175 _data[i]->clear(this);
2183 SGPropertyNode::hash_table::get (const char * key)
2185 if (_data_length == 0)
2187 unsigned int index = hashcode(key) % _data_length;
2188 if (_data[index] == 0)
2190 entry * e = _data[index]->get_entry(key);
2194 return e->get_value();
2198 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2200 if (_data_length == 0) {
2201 _data = new bucket*[HASH_TABLE_SIZE];
2202 _data_length = HASH_TABLE_SIZE;
2203 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2206 unsigned int index = hashcode(key) % _data_length;
2207 if (_data[index] == 0) {
2208 _data[index] = new bucket;
2210 entry * e = _data[index]->get_entry(key, true);
2211 e->set_value(value);
2212 value->add_linked_node(this);
2216 SGPropertyNode::hash_table::erase (SGPropertyNode * node)
2218 for (unsigned int i = 0; i < _data_length; i++)
2219 if (_data[i] && _data[i]->erase(node))
2226 SGPropertyNode::hash_table::hashcode (const char * key)
2228 unsigned int hash = 0;
2230 hash = 31 * hash + *key;
2238 ////////////////////////////////////////////////////////////////////////
2239 // Implementation of SGPropertyChangeListener.
2240 ////////////////////////////////////////////////////////////////////////
2242 SGPropertyChangeListener::~SGPropertyChangeListener ()
2244 for (int i = _properties.size() - 1; i >= 0; i--)
2245 _properties[i]->removeChangeListener(this);
2249 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2255 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2256 SGPropertyNode * child)
2262 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2263 SGPropertyNode * child)
2269 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2271 _properties.push_back(node);
2275 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2277 vector<SGPropertyNode *>::iterator it =
2278 find(_properties.begin(), _properties.end(), node);
2279 if (it != _properties.end())
2280 _properties.erase(it);