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].
22 #include <simgear/compiler.h>
23 #include <simgear/debug/logstream.hxx>
25 #if ( _MSC_VER == 1200 )
26 // MSVC 6 is buggy, and needs something strange here
27 using std::vector<SGPropertyNode_ptr>;
28 using std::vector<SGPropertyChangeListener *>;
29 using std::vector<SGPropertyNode *>;
41 using std::stringstream;
43 using namespace simgear;
44 using namespace simgear::props;
47 ////////////////////////////////////////////////////////////////////////
49 ////////////////////////////////////////////////////////////////////////
52 * Comparator class for sorting by index.
57 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
58 return (n1->getIndex() < n2->getIndex());
64 ////////////////////////////////////////////////////////////////////////
65 // Convenience macros for value access.
66 ////////////////////////////////////////////////////////////////////////
68 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
69 #define TEST_WRITE if (!getAttribute(WRITE)) return false
71 ////////////////////////////////////////////////////////////////////////
72 // Default values for every type.
73 ////////////////////////////////////////////////////////////////////////
75 template<> const bool SGRawValue<bool>::DefaultValue = false;
76 template<> const int SGRawValue<int>::DefaultValue = 0;
77 template<> const long SGRawValue<long>::DefaultValue = 0L;
78 template<> const float SGRawValue<float>::DefaultValue = 0.0;
79 template<> const double SGRawValue<double>::DefaultValue = 0.0L;
80 template<> const char * const SGRawValue<const char *>::DefaultValue = "";
82 ////////////////////////////////////////////////////////////////////////
83 // Local path normalization code.
84 ////////////////////////////////////////////////////////////////////////
87 * A component in a path.
96 * Parse the name for a path component.
98 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
100 static inline const string
101 parse_name (const string &path, int &i)
104 int max = path.size();
106 if (path[i] == '.') {
108 if (i < max && path[i] == '.') {
114 if (i < max && path[i] != '/')
115 throw string("illegal character after " + name);
118 else if (isalpha(path[i]) || path[i] == '_') {
122 // The rules inside a name are a little
125 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
126 path[i] == '-' || path[i] == '.') {
128 } else if (path[i] == '[' || path[i] == '/') {
131 throw string("name may contain only ._- and alphanumeric characters");
138 if (name.size() == 0)
139 throw string("name must begin with alpha or '_'");
147 * Parse the optional integer index for a path component.
149 * Index: "[" [0-9]+ "]"
152 parse_index (const string &path, int &i)
161 for (int max = path.size(); i < max; i++) {
162 if (isdigit(path[i])) {
163 index = (index * 10) + (path[i] - '0');
164 } else if (path[i] == ']') {
172 throw string("unterminated index (looking for ']')");
177 * Parse a single path component.
179 * Component: Name Index?
181 static inline PathComponent
182 parse_component (const string &path, int &i)
184 PathComponent component;
185 component.name = parse_name(path, i);
186 if (component.name[0] != '.')
187 component.index = parse_index(path, i);
189 component.index = -1;
195 * Parse a path into its components.
198 parse_path (const string &path, vector<PathComponent> &components)
201 int max = path.size();
203 // Check for initial '/'
204 if (path[pos] == '/') {
208 components.push_back(root);
210 while (pos < max && path[pos] == '/')
215 components.push_back(parse_component(path, pos));
216 while (pos < max && path[pos] == '/')
223 ////////////////////////////////////////////////////////////////////////
224 // Other static utility functions.
225 ////////////////////////////////////////////////////////////////////////
229 copy_string (const char * s)
231 unsigned long int slen = strlen(s);
232 char * copy = new char[slen + 1];
234 // the source string length is known so no need to check for '\0'
235 // when copying every single character
236 memcpy(copy, s, slen);
237 *(copy + slen) = '\0';
242 compare_strings (const char * s1, const char * s2)
244 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
248 * Locate a child node by name and index.
251 find_child (const char * name, int index, const vector<SGPropertyNode_ptr>& nodes)
253 int nNodes = nodes.size();
254 for (int i = 0; i < nNodes; i++) {
255 SGPropertyNode * node = nodes[i];
257 // searching for a mathing index is a lot less time consuming than
258 // comparing two strings so do that first.
259 if (node->getIndex() == index && compare_strings(node->getName(), name))
266 * Locate the child node with the highest index of the same name
269 find_last_child (const char * name, const vector<SGPropertyNode_ptr>& nodes)
271 int nNodes = nodes.size();
274 for (int i = 0; i < nNodes; i++) {
275 SGPropertyNode * node = nodes[i];
276 if (compare_strings(node->getName(), name))
278 int idx = node->getIndex();
279 if (idx > index) index = idx;
287 * Locate another node, given a relative path.
289 static SGPropertyNode *
290 find_node (SGPropertyNode * current,
291 const vector<PathComponent> &components,
295 // Run off the end of the list
300 // Success! This is the one we want.
301 else if (position >= (int)components.size()) {
302 return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
305 // Empty component means root.
306 else if (components[position].name == "") {
307 return find_node(current->getRootNode(), components, position + 1, create);
310 // . means current directory
311 else if (components[position].name == ".") {
312 return find_node(current, components, position + 1, create);
315 // .. means parent directory
316 else if (components[position].name == "..") {
317 SGPropertyNode * parent = current->getParent();
319 throw string("attempt to move past root with '..'");
321 return find_node(parent, components, position + 1, create);
324 // Otherwise, a child name
326 SGPropertyNode * child =
327 current->getChild(components[position].name.c_str(),
328 components[position].index,
330 return find_node(child, components, position + 1, create);
336 ////////////////////////////////////////////////////////////////////////
337 // Private methods from SGPropertyNode (may be inlined for speed).
338 ////////////////////////////////////////////////////////////////////////
341 SGPropertyNode::get_bool () const
344 return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
346 return _local_val.bool_val;
350 SGPropertyNode::get_int () const
353 return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
355 return _local_val.int_val;
359 SGPropertyNode::get_long () const
362 return static_cast<SGRawValue<long>*>(_value.val)->getValue();
364 return _local_val.long_val;
368 SGPropertyNode::get_float () const
371 return static_cast<SGRawValue<float>*>(_value.val)->getValue();
373 return _local_val.float_val;
377 SGPropertyNode::get_double () const
380 return static_cast<SGRawValue<double>*>(_value.val)->getValue();
382 return _local_val.double_val;
386 SGPropertyNode::get_string () const
389 return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
391 return _local_val.string_val;
395 SGPropertyNode::set_bool (bool val)
398 if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
405 _local_val.bool_val = val;
412 SGPropertyNode::set_int (int val)
415 if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
422 _local_val.int_val = val;
429 SGPropertyNode::set_long (long val)
432 if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
439 _local_val.long_val = val;
446 SGPropertyNode::set_float (float val)
449 if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
456 _local_val.float_val = val;
463 SGPropertyNode::set_double (double val)
466 if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
473 _local_val.double_val = val;
480 SGPropertyNode::set_string (const char * val)
483 if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
490 delete [] _local_val.string_val;
491 _local_val.string_val = copy_string(val);
498 SGPropertyNode::clearValue ()
500 if (_type == ALIAS) {
503 } else if (_type != NONE) {
506 _local_val.bool_val = SGRawValue<bool>::DefaultValue;
509 _local_val.int_val = SGRawValue<int>::DefaultValue;
512 _local_val.long_val = SGRawValue<long>::DefaultValue;
515 _local_val.float_val = SGRawValue<float>::DefaultValue;
518 _local_val.double_val = SGRawValue<double>::DefaultValue;
523 delete [] _local_val.string_val;
525 _local_val.string_val = 0;
537 * Get the value as a string.
540 SGPropertyNode::make_string () const
542 if (!getAttribute(READ))
546 return _value.alias->getStringValue();
548 return get_bool() ? "true" : "false";
569 sstr << std::setprecision(10) << get_double();
572 static_cast<SGRawExtended*>(_value.val)->printOn(sstr);
577 _buffer = sstr.str();
578 return _buffer.c_str();
582 * Trace a write access for a property.
585 SGPropertyNode::trace_write () const
588 cerr << "TRACE: Write node " << getPath () << ", value \""
589 << make_string() << '"' << endl;
591 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
592 << ", value \"" << make_string() << '"');
597 * Trace a read access for a property.
600 SGPropertyNode::trace_read () const
603 cerr << "TRACE: Write node " << getPath () << ", value \""
604 << make_string() << '"' << endl;
606 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
607 << ", value \"" << make_string() << '"');
612 ////////////////////////////////////////////////////////////////////////
613 // Public methods from SGPropertyNode.
614 ////////////////////////////////////////////////////////////////////////
617 * Last used attribute
618 * Update as needed when enum Attribute is changed
620 const int SGPropertyNode::LAST_USED_ATTRIBUTE = USERARCHIVE;
623 * Default constructor: always creates a root node.
625 SGPropertyNode::SGPropertyNode ()
634 _local_val.string_val = 0;
642 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
643 : _index(node._index),
645 _parent(0), // don't copy the parent
650 _listeners(0) // CHECK!!
652 _local_val.string_val = 0;
656 if (_type == ALIAS) {
657 _value.alias = node._value.alias;
662 if (_tied || _type == EXTENDED) {
663 _value.val = node._value.val->clone();
668 set_bool(node.get_bool());
671 set_int(node.get_int());
674 set_long(node.get_long());
677 set_float(node.get_float());
680 set_double(node.get_double());
684 set_string(node.get_string());
693 * Convenience constructor.
695 SGPropertyNode::SGPropertyNode (const char * name,
697 SGPropertyNode * parent)
707 _local_val.string_val = 0;
709 _name = parse_name(name, i);
710 if (i != int(strlen(name)) || name[0] == '.')
711 throw string("plain name expected instead of '") + name + '\'';
718 SGPropertyNode::~SGPropertyNode ()
720 // zero out all parent pointers, else they might be dangling
721 for (unsigned i = 0; i < _children.size(); ++i)
722 _children[i]->_parent = 0;
723 for (unsigned i = 0; i < _removedChildren.size(); ++i)
724 _removedChildren[i]->_parent = 0;
729 vector<SGPropertyChangeListener*>::iterator it;
730 for (it = _listeners->begin(); it != _listeners->end(); ++it)
731 (*it)->unregister_property(this);
738 * Alias to another node.
741 SGPropertyNode::alias (SGPropertyNode * target)
743 if (target == 0 || _type == ALIAS || _tied)
747 _value.alias = target;
754 * Alias to another node by path.
757 SGPropertyNode::alias (const char * path)
759 return alias(getNode(path, true));
767 SGPropertyNode::unalias ()
777 * Get the target of an alias.
780 SGPropertyNode::getAliasTarget ()
782 return (_type == ALIAS ? _value.alias : 0);
786 const SGPropertyNode *
787 SGPropertyNode::getAliasTarget () const
789 return (_type == ALIAS ? _value.alias : 0);
793 * create a non-const child by name after the last node with the same name.
796 SGPropertyNode::addChild (const char * name)
798 int pos = find_last_child(name, _children)+1;
800 SGPropertyNode_ptr node;
801 node = new SGPropertyNode(name, pos, this);
802 _children.push_back(node);
803 fireChildAdded(node);
809 * Get a non-const child by index.
812 SGPropertyNode::getChild (int position)
814 if (position >= 0 && position < nChildren())
815 return _children[position];
822 * Get a const child by index.
824 const SGPropertyNode *
825 SGPropertyNode::getChild (int position) const
827 if (position >= 0 && position < nChildren())
828 return _children[position];
835 * Get a non-const child by name and index, creating if necessary.
838 SGPropertyNode::getChild (const char * name, int index, bool create)
840 int pos = find_child(name, index, _children);
842 return _children[pos];
844 SGPropertyNode_ptr node;
845 pos = find_child(name, index, _removedChildren);
847 vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
849 node = _removedChildren[pos];
850 _removedChildren.erase(it);
851 node->setAttribute(REMOVED, false);
853 node = new SGPropertyNode(name, index, this);
855 _children.push_back(node);
856 fireChildAdded(node);
865 * Get a const child by name and index.
867 const SGPropertyNode *
868 SGPropertyNode::getChild (const char * name, int index) const
870 int pos = find_child(name, index, _children);
872 return _children[pos];
879 * Get all children with the same name (but different indices).
881 vector<SGPropertyNode_ptr>
882 SGPropertyNode::getChildren (const char * name) const
884 vector<SGPropertyNode_ptr> children;
885 int max = _children.size();
887 for (int i = 0; i < max; i++)
888 if (compare_strings(_children[i]->getName(), name))
889 children.push_back(_children[i]);
891 sort(children.begin(), children.end(), CompareIndices());
897 * Remove this node and all children from nodes that link to them
898 * in their path cache.
901 SGPropertyNode::remove_from_path_caches ()
903 for (unsigned int i = 0; i < _children.size(); ++i)
904 _children[i]->remove_from_path_caches();
906 for (unsigned int i = 0; i < _linkedNodes.size(); i++)
907 _linkedNodes[i]->erase(this);
908 _linkedNodes.clear();
913 * Remove child by position.
916 SGPropertyNode::removeChild (int pos, bool keep)
918 SGPropertyNode_ptr node;
919 if (pos < 0 || pos >= (int)_children.size())
922 vector<SGPropertyNode_ptr>::iterator it = _children.begin();
924 node = _children[pos];
927 _removedChildren.push_back(node);
930 node->remove_from_path_caches();
931 node->setAttribute(REMOVED, true);
933 fireChildRemoved(node);
939 * Remove a child node
942 SGPropertyNode::removeChild (const char * name, int index, bool keep)
944 SGPropertyNode_ptr ret;
945 int pos = find_child(name, index, _children);
947 ret = removeChild(pos, keep);
953 * Remove all children with the specified name.
955 vector<SGPropertyNode_ptr>
956 SGPropertyNode::removeChildren (const char * name, bool keep)
958 vector<SGPropertyNode_ptr> children;
960 for (int pos = _children.size() - 1; pos >= 0; pos--)
961 if (compare_strings(_children[pos]->getName(), name))
962 children.push_back(removeChild(pos, keep));
964 sort(children.begin(), children.end(), CompareIndices());
970 * Remove a linked node.
973 SGPropertyNode::remove_linked_node (hash_table * node)
975 for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
976 if (_linkedNodes[i] == node) {
977 vector<hash_table *>::iterator it = _linkedNodes.begin();
979 _linkedNodes.erase(it);
988 SGPropertyNode::getDisplayName (bool simplify) const
990 _display_name = _name;
991 if (_index != 0 || !simplify) {
993 sstr << '[' << _index << ']';
994 _display_name += sstr.str();
996 return _display_name.c_str();
1001 SGPropertyNode::getPath (bool simplify) const
1003 // Calculate the complete path only once.
1004 if (_parent != 0 && _path.empty()) {
1005 _path = _parent->getPath(simplify);
1007 _path += getDisplayName(simplify);
1010 return _path.c_str();
1014 SGPropertyNode::getType () const
1017 return _value.alias->getType();
1018 else if (_type == EXTENDED)
1019 return _value.val->getType();
1026 SGPropertyNode::getBoolValue () const
1028 // Shortcut for common case
1029 if (_attr == (READ|WRITE) && _type == BOOL)
1032 if (getAttribute(TRACE_READ))
1034 if (!getAttribute(READ))
1035 return SGRawValue<bool>::DefaultValue;
1038 return _value.alias->getBoolValue();
1042 return get_int() == 0 ? false : true;
1044 return get_long() == 0L ? false : true;
1046 return get_float() == 0.0 ? false : true;
1048 return get_double() == 0.0L ? false : true;
1051 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1054 return SGRawValue<bool>::DefaultValue;
1059 SGPropertyNode::getIntValue () const
1061 // Shortcut for common case
1062 if (_attr == (READ|WRITE) && _type == INT)
1065 if (getAttribute(TRACE_READ))
1067 if (!getAttribute(READ))
1068 return SGRawValue<int>::DefaultValue;
1071 return _value.alias->getIntValue();
1073 return int(get_bool());
1077 return int(get_long());
1079 return int(get_float());
1081 return int(get_double());
1084 return atoi(get_string());
1087 return SGRawValue<int>::DefaultValue;
1092 SGPropertyNode::getLongValue () const
1094 // Shortcut for common case
1095 if (_attr == (READ|WRITE) && _type == LONG)
1098 if (getAttribute(TRACE_READ))
1100 if (!getAttribute(READ))
1101 return SGRawValue<long>::DefaultValue;
1104 return _value.alias->getLongValue();
1106 return long(get_bool());
1108 return long(get_int());
1112 return long(get_float());
1114 return long(get_double());
1117 return strtol(get_string(), 0, 0);
1120 return SGRawValue<long>::DefaultValue;
1125 SGPropertyNode::getFloatValue () const
1127 // Shortcut for common case
1128 if (_attr == (READ|WRITE) && _type == FLOAT)
1131 if (getAttribute(TRACE_READ))
1133 if (!getAttribute(READ))
1134 return SGRawValue<float>::DefaultValue;
1137 return _value.alias->getFloatValue();
1139 return float(get_bool());
1141 return float(get_int());
1143 return float(get_long());
1147 return float(get_double());
1150 return atof(get_string());
1153 return SGRawValue<float>::DefaultValue;
1158 SGPropertyNode::getDoubleValue () const
1160 // Shortcut for common case
1161 if (_attr == (READ|WRITE) && _type == DOUBLE)
1162 return get_double();
1164 if (getAttribute(TRACE_READ))
1166 if (!getAttribute(READ))
1167 return SGRawValue<double>::DefaultValue;
1171 return _value.alias->getDoubleValue();
1173 return double(get_bool());
1175 return double(get_int());
1177 return double(get_long());
1179 return double(get_float());
1181 return get_double();
1184 return strtod(get_string(), 0);
1187 return SGRawValue<double>::DefaultValue;
1192 SGPropertyNode::getStringValue () const
1194 // Shortcut for common case
1195 if (_attr == (READ|WRITE) && _type == STRING)
1196 return get_string();
1198 if (getAttribute(TRACE_READ))
1200 if (!getAttribute(READ))
1201 return SGRawValue<const char *>::DefaultValue;
1202 return make_string();
1206 SGPropertyNode::setBoolValue (bool value)
1208 // Shortcut for common case
1209 if (_attr == (READ|WRITE) && _type == BOOL)
1210 return set_bool(value);
1212 bool result = false;
1214 if (_type == NONE || _type == UNSPECIFIED) {
1222 result = _value.alias->setBoolValue(value);
1225 result = set_bool(value);
1228 result = set_int(int(value));
1231 result = set_long(long(value));
1234 result = set_float(float(value));
1237 result = set_double(double(value));
1241 result = set_string(value ? "true" : "false");
1248 if (getAttribute(TRACE_WRITE))
1254 SGPropertyNode::setIntValue (int value)
1256 // Shortcut for common case
1257 if (_attr == (READ|WRITE) && _type == INT)
1258 return set_int(value);
1260 bool result = false;
1262 if (_type == NONE || _type == UNSPECIFIED) {
1265 _local_val.int_val = 0;
1270 result = _value.alias->setIntValue(value);
1273 result = set_bool(value == 0 ? false : true);
1276 result = set_int(value);
1279 result = set_long(long(value));
1282 result = set_float(float(value));
1285 result = set_double(double(value));
1290 sprintf(buf, "%d", value);
1291 result = set_string(buf);
1299 if (getAttribute(TRACE_WRITE))
1305 SGPropertyNode::setLongValue (long value)
1307 // Shortcut for common case
1308 if (_attr == (READ|WRITE) && _type == LONG)
1309 return set_long(value);
1311 bool result = false;
1313 if (_type == NONE || _type == UNSPECIFIED) {
1316 _local_val.long_val = 0L;
1321 result = _value.alias->setLongValue(value);
1324 result = set_bool(value == 0L ? false : true);
1327 result = set_int(int(value));
1330 result = set_long(value);
1333 result = set_float(float(value));
1336 result = set_double(double(value));
1341 sprintf(buf, "%ld", value);
1342 result = set_string(buf);
1350 if (getAttribute(TRACE_WRITE))
1356 SGPropertyNode::setFloatValue (float value)
1358 // Shortcut for common case
1359 if (_attr == (READ|WRITE) && _type == FLOAT)
1360 return set_float(value);
1362 bool result = false;
1364 if (_type == NONE || _type == UNSPECIFIED) {
1367 _local_val.float_val = 0;
1372 result = _value.alias->setFloatValue(value);
1375 result = set_bool(value == 0.0 ? false : true);
1378 result = set_int(int(value));
1381 result = set_long(long(value));
1384 result = set_float(value);
1387 result = set_double(double(value));
1392 sprintf(buf, "%f", value);
1393 result = set_string(buf);
1401 if (getAttribute(TRACE_WRITE))
1407 SGPropertyNode::setDoubleValue (double value)
1409 // Shortcut for common case
1410 if (_attr == (READ|WRITE) && _type == DOUBLE)
1411 return set_double(value);
1413 bool result = false;
1415 if (_type == NONE || _type == UNSPECIFIED) {
1417 _local_val.double_val = value;
1423 result = _value.alias->setDoubleValue(value);
1426 result = set_bool(value == 0.0L ? false : true);
1429 result = set_int(int(value));
1432 result = set_long(long(value));
1435 result = set_float(float(value));
1438 result = set_double(value);
1443 sprintf(buf, "%f", value);
1444 result = set_string(buf);
1452 if (getAttribute(TRACE_WRITE))
1458 SGPropertyNode::setStringValue (const char * value)
1460 // Shortcut for common case
1461 if (_attr == (READ|WRITE) && _type == STRING)
1462 return set_string(value);
1464 bool result = false;
1466 if (_type == NONE || _type == UNSPECIFIED) {
1473 result = _value.alias->setStringValue(value);
1476 result = set_bool((compare_strings(value, "true")
1477 || atoi(value)) ? true : false);
1480 result = set_int(atoi(value));
1483 result = set_long(strtol(value, 0, 0));
1486 result = set_float(atof(value));
1489 result = set_double(strtod(value, 0));
1493 result = set_string(value);
1497 stringstream sstr(value);
1498 static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1506 if (getAttribute(TRACE_WRITE))
1512 SGPropertyNode::setUnspecifiedValue (const char * value)
1514 bool result = false;
1516 if (_type == NONE) {
1518 _type = UNSPECIFIED;
1521 if (type == EXTENDED)
1522 type = _value.val->getType();
1525 result = _value.alias->setUnspecifiedValue(value);
1528 result = set_bool((compare_strings(value, "true")
1529 || atoi(value)) ? true : false);
1532 result = set_int(atoi(value));
1535 result = set_long(strtol(value, 0, 0));
1538 result = set_float(atof(value));
1541 result = set_double(strtod(value, 0));
1545 result = set_string(value);
1552 if (getAttribute(TRACE_WRITE))
1557 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1559 if (!getAttribute(READ))
1563 return _value.alias->printOn(stream);
1565 stream << (get_bool() ? "true" : "false");
1568 stream << get_int();
1571 stream << get_long();
1574 stream << get_float();
1577 stream << get_double();
1581 stream << get_string();
1584 static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1593 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1596 if (_type == ALIAS || _tied)
1599 useDefault = useDefault && hasValue();
1600 std::string old_val;
1602 old_val = getStringValue();
1606 _value.val = rawValue.clone();
1609 setStringValue(old_val.c_str());
1614 SGPropertyNode::untie ()
1621 bool val = getBoolValue();
1624 _local_val.bool_val = val;
1628 int val = getIntValue();
1631 _local_val.int_val = val;
1635 long val = getLongValue();
1638 _local_val.long_val = val;
1642 float val = getFloatValue();
1645 _local_val.float_val = val;
1649 double val = getDoubleValue();
1652 _local_val.double_val = val;
1657 string val = getStringValue();
1660 _local_val.string_val = copy_string(val.c_str());
1664 SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1665 _value.val = 0; // Prevent clearValue() from deleting
1668 _value.val = val->makeContainer();
1682 SGPropertyNode::getRootNode ()
1687 return _parent->getRootNode();
1690 const SGPropertyNode *
1691 SGPropertyNode::getRootNode () const
1696 return _parent->getRootNode();
1700 SGPropertyNode::getNode (const char * relative_path, bool create)
1702 if (_path_cache == 0)
1703 _path_cache = new hash_table;
1705 SGPropertyNode * result = _path_cache->get(relative_path);
1707 vector<PathComponent> components;
1708 parse_path(relative_path, components);
1709 result = find_node(this, components, 0, create);
1711 _path_cache->put(relative_path, result);
1718 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1720 vector<PathComponent> components;
1721 parse_path(relative_path, components);
1722 if (components.size() > 0)
1723 components.back().index = index;
1724 return find_node(this, components, 0, create);
1727 const SGPropertyNode *
1728 SGPropertyNode::getNode (const char * relative_path) const
1730 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1733 const SGPropertyNode *
1734 SGPropertyNode::getNode (const char * relative_path, int index) const
1736 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1740 ////////////////////////////////////////////////////////////////////////
1741 // Convenience methods using relative paths.
1742 ////////////////////////////////////////////////////////////////////////
1746 * Test whether another node has a value attached.
1749 SGPropertyNode::hasValue (const char * relative_path) const
1751 const SGPropertyNode * node = getNode(relative_path);
1752 return (node == 0 ? false : node->hasValue());
1757 * Get the value type for another node.
1760 SGPropertyNode::getType (const char * relative_path) const
1762 const SGPropertyNode * node = getNode(relative_path);
1763 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1768 * Get a bool value for another node.
1771 SGPropertyNode::getBoolValue (const char * relative_path,
1772 bool defaultValue) const
1774 const SGPropertyNode * node = getNode(relative_path);
1775 return (node == 0 ? defaultValue : node->getBoolValue());
1780 * Get an int value for another node.
1783 SGPropertyNode::getIntValue (const char * relative_path,
1784 int defaultValue) const
1786 const SGPropertyNode * node = getNode(relative_path);
1787 return (node == 0 ? defaultValue : node->getIntValue());
1792 * Get a long value for another node.
1795 SGPropertyNode::getLongValue (const char * relative_path,
1796 long defaultValue) const
1798 const SGPropertyNode * node = getNode(relative_path);
1799 return (node == 0 ? defaultValue : node->getLongValue());
1804 * Get a float value for another node.
1807 SGPropertyNode::getFloatValue (const char * relative_path,
1808 float defaultValue) const
1810 const SGPropertyNode * node = getNode(relative_path);
1811 return (node == 0 ? defaultValue : node->getFloatValue());
1816 * Get a double value for another node.
1819 SGPropertyNode::getDoubleValue (const char * relative_path,
1820 double defaultValue) const
1822 const SGPropertyNode * node = getNode(relative_path);
1823 return (node == 0 ? defaultValue : node->getDoubleValue());
1828 * Get a string value for another node.
1831 SGPropertyNode::getStringValue (const char * relative_path,
1832 const char * defaultValue) const
1834 const SGPropertyNode * node = getNode(relative_path);
1835 return (node == 0 ? defaultValue : node->getStringValue());
1840 * Set a bool value for another node.
1843 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1845 return getNode(relative_path, true)->setBoolValue(value);
1850 * Set an int value for another node.
1853 SGPropertyNode::setIntValue (const char * relative_path, int value)
1855 return getNode(relative_path, true)->setIntValue(value);
1860 * Set a long value for another node.
1863 SGPropertyNode::setLongValue (const char * relative_path, long value)
1865 return getNode(relative_path, true)->setLongValue(value);
1870 * Set a float value for another node.
1873 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1875 return getNode(relative_path, true)->setFloatValue(value);
1880 * Set a double value for another node.
1883 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1885 return getNode(relative_path, true)->setDoubleValue(value);
1890 * Set a string value for another node.
1893 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1895 return getNode(relative_path, true)->setStringValue(value);
1900 * Set an unknown value for another node.
1903 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1906 return getNode(relative_path, true)->setUnspecifiedValue(value);
1911 * Test whether another node is tied.
1914 SGPropertyNode::isTied (const char * relative_path) const
1916 const SGPropertyNode * node = getNode(relative_path);
1917 return (node == 0 ? false : node->isTied());
1922 * Tie a node reached by a relative path, creating it if necessary.
1925 SGPropertyNode::tie (const char * relative_path,
1926 const SGRawValue<bool> &rawValue,
1929 return getNode(relative_path, true)->tie(rawValue, useDefault);
1934 * Tie a node reached by a relative path, creating it if necessary.
1937 SGPropertyNode::tie (const char * relative_path,
1938 const SGRawValue<int> &rawValue,
1941 return getNode(relative_path, true)->tie(rawValue, useDefault);
1946 * Tie a node reached by a relative path, creating it if necessary.
1949 SGPropertyNode::tie (const char * relative_path,
1950 const SGRawValue<long> &rawValue,
1953 return getNode(relative_path, true)->tie(rawValue, useDefault);
1958 * Tie a node reached by a relative path, creating it if necessary.
1961 SGPropertyNode::tie (const char * relative_path,
1962 const SGRawValue<float> &rawValue,
1965 return getNode(relative_path, true)->tie(rawValue, useDefault);
1970 * Tie a node reached by a relative path, creating it if necessary.
1973 SGPropertyNode::tie (const char * relative_path,
1974 const SGRawValue<double> &rawValue,
1977 return getNode(relative_path, true)->tie(rawValue, useDefault);
1982 * Tie a node reached by a relative path, creating it if necessary.
1985 SGPropertyNode::tie (const char * relative_path,
1986 const SGRawValue<const char *> &rawValue,
1989 return getNode(relative_path, true)->tie(rawValue, useDefault);
1994 * Attempt to untie another node reached by a relative path.
1997 SGPropertyNode::untie (const char * relative_path)
1999 SGPropertyNode * node = getNode(relative_path);
2000 return (node == 0 ? false : node->untie());
2004 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2007 if (_listeners == 0)
2008 _listeners = new vector<SGPropertyChangeListener*>;
2009 _listeners->push_back(listener);
2010 listener->register_property(this);
2012 listener->valueChanged(this);
2016 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2018 vector<SGPropertyChangeListener*>::iterator it =
2019 find(_listeners->begin(), _listeners->end(), listener);
2020 if (it != _listeners->end()) {
2021 _listeners->erase(it);
2022 listener->unregister_property(this);
2023 if (_listeners->empty()) {
2024 vector<SGPropertyChangeListener*>* tmp = _listeners;
2032 SGPropertyNode::fireValueChanged ()
2034 fireValueChanged(this);
2038 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2040 fireChildAdded(this, child);
2044 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2046 fireChildRemoved(this, child);
2050 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2052 if (_listeners != 0) {
2053 for (unsigned int i = 0; i < _listeners->size(); i++) {
2054 (*_listeners)[i]->valueChanged(node);
2058 _parent->fireValueChanged(node);
2062 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2063 SGPropertyNode * child)
2065 if (_listeners != 0) {
2066 for (unsigned int i = 0; i < _listeners->size(); i++) {
2067 (*_listeners)[i]->childAdded(parent, child);
2071 _parent->fireChildAdded(parent, child);
2075 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2076 SGPropertyNode * child)
2078 if (_listeners != 0) {
2079 for (unsigned int i = 0; i < _listeners->size(); i++) {
2080 (*_listeners)[i]->childRemoved(parent, child);
2084 _parent->fireChildRemoved(parent, child);
2089 ////////////////////////////////////////////////////////////////////////
2090 // Simplified hash table for caching paths.
2091 ////////////////////////////////////////////////////////////////////////
2093 #define HASH_TABLE_SIZE 199
2095 SGPropertyNode::hash_table::entry::entry ()
2100 SGPropertyNode::hash_table::entry::~entry ()
2102 // Don't delete the value; we don't own
2107 SGPropertyNode::hash_table::entry::set_key (const char * key)
2113 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2118 SGPropertyNode::hash_table::bucket::bucket ()
2124 SGPropertyNode::hash_table::bucket::~bucket ()
2126 for (int i = 0; i < _length; i++)
2131 SGPropertyNode::hash_table::entry *
2132 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2135 for (i = 0; i < _length; i++) {
2136 if (!strcmp(_entries[i]->get_key(), key))
2140 entry ** new_entries = new entry*[_length+1];
2141 for (i = 0; i < _length; i++) {
2142 new_entries[i] = _entries[i];
2145 _entries = new_entries;
2146 _entries[_length] = new entry;
2147 _entries[_length]->set_key(key);
2149 return _entries[_length - 1];
2156 SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
2158 for (int i = 0; i < _length; i++) {
2159 if (_entries[i]->get_value() == node) {
2161 for (++i; i < _length; i++) {
2162 _entries[i-1] = _entries[i];
2172 SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
2174 for (int i = 0; i < _length; i++) {
2175 SGPropertyNode * node = _entries[i]->get_value();
2177 node->remove_linked_node(owner);
2181 SGPropertyNode::hash_table::hash_table ()
2187 SGPropertyNode::hash_table::~hash_table ()
2189 for (unsigned int i = 0; i < _data_length; i++) {
2191 _data[i]->clear(this);
2199 SGPropertyNode::hash_table::get (const char * key)
2201 if (_data_length == 0)
2203 unsigned int index = hashcode(key) % _data_length;
2204 if (_data[index] == 0)
2206 entry * e = _data[index]->get_entry(key);
2210 return e->get_value();
2214 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2216 if (_data_length == 0) {
2217 _data = new bucket*[HASH_TABLE_SIZE];
2218 _data_length = HASH_TABLE_SIZE;
2219 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2222 unsigned int index = hashcode(key) % _data_length;
2223 if (_data[index] == 0) {
2224 _data[index] = new bucket;
2226 entry * e = _data[index]->get_entry(key, true);
2227 e->set_value(value);
2228 value->add_linked_node(this);
2232 SGPropertyNode::hash_table::erase (SGPropertyNode * node)
2234 for (unsigned int i = 0; i < _data_length; i++)
2235 if (_data[i] && _data[i]->erase(node))
2242 SGPropertyNode::hash_table::hashcode (const char * key)
2244 unsigned int hash = 0;
2246 hash = 31 * hash + *key;
2254 ////////////////////////////////////////////////////////////////////////
2255 // Implementation of SGPropertyChangeListener.
2256 ////////////////////////////////////////////////////////////////////////
2258 SGPropertyChangeListener::~SGPropertyChangeListener ()
2260 for (int i = _properties.size() - 1; i >= 0; i--)
2261 _properties[i]->removeChangeListener(this);
2265 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2271 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2272 SGPropertyNode * child)
2278 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2279 SGPropertyNode * child)
2285 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2287 _properties.push_back(node);
2291 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2293 vector<SGPropertyNode *>::iterator it =
2294 find(_properties.begin(), _properties.end(), node);
2295 if (it != _properties.end())
2296 _properties.erase(it);