1 // props.cxx - implementation of a property list.
2 // Started Fall 2000 by David Megginson, david@megginson.com
3 // This code is released into the Public Domain.
5 // See props.html for documentation [replace with URL when available].
18 #include <simgear/math/SGMath.hxx>
24 #include <simgear/compiler.h>
25 #include <simgear/debug/logstream.hxx>
27 #if ( _MSC_VER == 1200 )
28 // MSVC 6 is buggy, and needs something strange here
29 using std::vector<SGPropertyNode_ptr>;
30 using std::vector<SGPropertyChangeListener *>;
31 using std::vector<SGPropertyNode *>;
43 using std::stringstream;
45 using namespace simgear;
46 using namespace simgear::props;
49 ////////////////////////////////////////////////////////////////////////
51 ////////////////////////////////////////////////////////////////////////
54 * Comparator class for sorting by index.
59 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
60 return (n1->getIndex() < n2->getIndex());
66 ////////////////////////////////////////////////////////////////////////
67 // Convenience macros for value access.
68 ////////////////////////////////////////////////////////////////////////
70 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
71 #define TEST_WRITE if (!getAttribute(WRITE)) return false
74 ////////////////////////////////////////////////////////////////////////
75 // Local path normalization code.
76 ////////////////////////////////////////////////////////////////////////
79 * A component in a path.
88 * Parse the name for a path component.
90 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
92 static inline const string
93 parse_name (const string &path, int &i)
96 int max = path.size();
100 if (i < max && path[i] == '.') {
106 if (i < max && path[i] != '/')
107 throw string("illegal character after " + name);
110 else if (isalpha(path[i]) || path[i] == '_') {
114 // The rules inside a name are a little
117 if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
118 path[i] == '-' || path[i] == '.') {
120 } else if (path[i] == '[' || path[i] == '/') {
123 throw string("name may contain only ._- and alphanumeric characters");
130 if (name.size() == 0)
131 throw string("name must begin with alpha or '_'");
139 * Parse the optional integer index for a path component.
141 * Index: "[" [0-9]+ "]"
144 parse_index (const string &path, int &i)
153 for (int max = path.size(); i < max; i++) {
154 if (isdigit(path[i])) {
155 index = (index * 10) + (path[i] - '0');
156 } else if (path[i] == ']') {
164 throw string("unterminated index (looking for ']')");
169 * Parse a single path component.
171 * Component: Name Index?
173 static inline PathComponent
174 parse_component (const string &path, int &i)
176 PathComponent component;
177 component.name = parse_name(path, i);
178 if (component.name[0] != '.')
179 component.index = parse_index(path, i);
181 component.index = -1;
187 * Parse a path into its components.
190 parse_path (const string &path, vector<PathComponent> &components)
193 int max = path.size();
195 // Check for initial '/'
196 if (path[pos] == '/') {
200 components.push_back(root);
202 while (pos < max && path[pos] == '/')
207 components.push_back(parse_component(path, pos));
208 while (pos < max && path[pos] == '/')
215 ////////////////////////////////////////////////////////////////////////
216 // Other static utility functions.
217 ////////////////////////////////////////////////////////////////////////
221 copy_string (const char * s)
223 unsigned long int slen = strlen(s);
224 char * copy = new char[slen + 1];
226 // the source string length is known so no need to check for '\0'
227 // when copying every single character
228 memcpy(copy, s, slen);
229 *(copy + slen) = '\0';
234 compare_strings (const char * s1, const char * s2)
236 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
240 * Locate a child node by name and index.
243 find_child (const char * name, int index, const PropertyList& nodes)
245 int nNodes = nodes.size();
246 for (int i = 0; i < nNodes; i++) {
247 SGPropertyNode * node = nodes[i];
249 // searching for a mathing index is a lot less time consuming than
250 // comparing two strings so do that first.
251 if (node->getIndex() == index && compare_strings(node->getName(), name))
258 * Locate the child node with the highest index of the same name
261 find_last_child (const char * name, const PropertyList& nodes)
263 int nNodes = nodes.size();
266 for (int i = 0; i < nNodes; i++) {
267 SGPropertyNode * node = nodes[i];
268 if (compare_strings(node->getName(), name))
270 int idx = node->getIndex();
271 if (idx > index) index = idx;
279 * Locate another node, given a relative path.
281 static SGPropertyNode *
282 find_node (SGPropertyNode * current,
283 const vector<PathComponent> &components,
287 // Run off the end of the list
292 // Success! This is the one we want.
293 else if (position >= (int)components.size()) {
294 return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
297 // Empty component means root.
298 else if (components[position].name == "") {
299 return find_node(current->getRootNode(), components, position + 1, create);
302 // . means current directory
303 else if (components[position].name == ".") {
304 return find_node(current, components, position + 1, create);
307 // .. means parent directory
308 else if (components[position].name == "..") {
309 SGPropertyNode * parent = current->getParent();
311 throw string("attempt to move past root with '..'");
313 return find_node(parent, components, position + 1, create);
316 // Otherwise, a child name
318 SGPropertyNode * child =
319 current->getChild(components[position].name.c_str(),
320 components[position].index,
322 return find_node(child, components, position + 1, create);
328 ////////////////////////////////////////////////////////////////////////
329 // Private methods from SGPropertyNode (may be inlined for speed).
330 ////////////////////////////////////////////////////////////////////////
333 SGPropertyNode::get_bool () const
336 return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
338 return _local_val.bool_val;
342 SGPropertyNode::get_int () const
345 return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
347 return _local_val.int_val;
351 SGPropertyNode::get_long () const
354 return static_cast<SGRawValue<long>*>(_value.val)->getValue();
356 return _local_val.long_val;
360 SGPropertyNode::get_float () const
363 return static_cast<SGRawValue<float>*>(_value.val)->getValue();
365 return _local_val.float_val;
369 SGPropertyNode::get_double () const
372 return static_cast<SGRawValue<double>*>(_value.val)->getValue();
374 return _local_val.double_val;
378 SGPropertyNode::get_string () const
381 return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
383 return _local_val.string_val;
387 SGPropertyNode::set_bool (bool val)
390 if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
397 _local_val.bool_val = val;
404 SGPropertyNode::set_int (int val)
407 if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
414 _local_val.int_val = val;
421 SGPropertyNode::set_long (long val)
424 if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
431 _local_val.long_val = val;
438 SGPropertyNode::set_float (float val)
441 if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
448 _local_val.float_val = val;
455 SGPropertyNode::set_double (double val)
458 if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
465 _local_val.double_val = val;
472 SGPropertyNode::set_string (const char * val)
475 if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
482 delete [] _local_val.string_val;
483 _local_val.string_val = copy_string(val);
490 SGPropertyNode::clearValue ()
492 if (_type == ALIAS) {
495 } else if (_type != NONE) {
498 _local_val.bool_val = SGRawValue<bool>::DefaultValue();
501 _local_val.int_val = SGRawValue<int>::DefaultValue();
504 _local_val.long_val = SGRawValue<long>::DefaultValue();
507 _local_val.float_val = SGRawValue<float>::DefaultValue();
510 _local_val.double_val = SGRawValue<double>::DefaultValue();
515 delete [] _local_val.string_val;
517 _local_val.string_val = 0;
529 * Get the value as a string.
532 SGPropertyNode::make_string () const
534 if (!getAttribute(READ))
538 return _value.alias->getStringValue();
540 return get_bool() ? "true" : "false";
561 sstr << std::setprecision(10) << get_double();
565 Type realType = _value.val->getType();
566 // Perhaps this should be done for all types?
567 if (realType == VEC3D || realType == VEC4D)
569 static_cast<SGRawExtended*>(_value.val)->printOn(sstr);
575 _buffer = sstr.str();
576 return _buffer.c_str();
580 * Trace a write access for a property.
583 SGPropertyNode::trace_write () const
586 cerr << "TRACE: Write node " << getPath () << ", value \""
587 << make_string() << '"' << endl;
589 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
590 << ", value \"" << make_string() << '"');
595 * Trace a read access for a property.
598 SGPropertyNode::trace_read () const
601 cerr << "TRACE: Write node " << getPath () << ", value \""
602 << make_string() << '"' << endl;
604 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
605 << ", value \"" << make_string() << '"');
610 ////////////////////////////////////////////////////////////////////////
611 // Public methods from SGPropertyNode.
612 ////////////////////////////////////////////////////////////////////////
615 * Last used attribute
616 * Update as needed when enum Attribute is changed
618 const int SGPropertyNode::LAST_USED_ATTRIBUTE = USERARCHIVE;
621 * Default constructor: always creates a root node.
623 SGPropertyNode::SGPropertyNode ()
632 _local_val.string_val = 0;
640 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
641 : _index(node._index),
643 _parent(0), // don't copy the parent
648 _listeners(0) // CHECK!!
650 _local_val.string_val = 0;
654 if (_type == ALIAS) {
655 _value.alias = node._value.alias;
660 if (_tied || _type == EXTENDED) {
661 _value.val = node._value.val->clone();
666 set_bool(node.get_bool());
669 set_int(node.get_int());
672 set_long(node.get_long());
675 set_float(node.get_float());
678 set_double(node.get_double());
682 set_string(node.get_string());
691 * Convenience constructor.
693 SGPropertyNode::SGPropertyNode (const char * name,
695 SGPropertyNode * parent)
705 _local_val.string_val = 0;
707 _name = parse_name(name, i);
708 if (i != int(strlen(name)) || name[0] == '.')
709 throw string("plain name expected instead of '") + name + '\'';
716 SGPropertyNode::~SGPropertyNode ()
718 // zero out all parent pointers, else they might be dangling
719 for (unsigned i = 0; i < _children.size(); ++i)
720 _children[i]->_parent = 0;
721 for (unsigned i = 0; i < _removedChildren.size(); ++i)
722 _removedChildren[i]->_parent = 0;
727 vector<SGPropertyChangeListener*>::iterator it;
728 for (it = _listeners->begin(); it != _listeners->end(); ++it)
729 (*it)->unregister_property(this);
736 * Alias to another node.
739 SGPropertyNode::alias (SGPropertyNode * target)
741 if (target == 0 || _type == ALIAS || _tied)
745 _value.alias = target;
752 * Alias to another node by path.
755 SGPropertyNode::alias (const char * path)
757 return alias(getNode(path, true));
765 SGPropertyNode::unalias ()
775 * Get the target of an alias.
778 SGPropertyNode::getAliasTarget ()
780 return (_type == ALIAS ? _value.alias : 0);
784 const SGPropertyNode *
785 SGPropertyNode::getAliasTarget () const
787 return (_type == ALIAS ? _value.alias : 0);
791 * create a non-const child by name after the last node with the same name.
794 SGPropertyNode::addChild (const char * name)
796 int pos = find_last_child(name, _children)+1;
798 SGPropertyNode_ptr node;
799 node = new SGPropertyNode(name, pos, this);
800 _children.push_back(node);
801 fireChildAdded(node);
807 * Get a non-const child by index.
810 SGPropertyNode::getChild (int position)
812 if (position >= 0 && position < nChildren())
813 return _children[position];
820 * Get a const child by index.
822 const SGPropertyNode *
823 SGPropertyNode::getChild (int position) const
825 if (position >= 0 && position < nChildren())
826 return _children[position];
833 * Get a non-const child by name and index, creating if necessary.
836 SGPropertyNode::getChild (const char * name, int index, bool create)
838 int pos = find_child(name, index, _children);
840 return _children[pos];
842 SGPropertyNode_ptr node;
843 pos = find_child(name, index, _removedChildren);
845 PropertyList::iterator it = _removedChildren.begin();
847 node = _removedChildren[pos];
848 _removedChildren.erase(it);
849 node->setAttribute(REMOVED, false);
851 node = new SGPropertyNode(name, index, this);
853 _children.push_back(node);
854 fireChildAdded(node);
863 * Get a const child by name and index.
865 const SGPropertyNode *
866 SGPropertyNode::getChild (const char * name, int index) const
868 int pos = find_child(name, index, _children);
870 return _children[pos];
877 * Get all children with the same name (but different indices).
880 SGPropertyNode::getChildren (const char * name) const
882 PropertyList children;
883 int max = _children.size();
885 for (int i = 0; i < max; i++)
886 if (compare_strings(_children[i]->getName(), name))
887 children.push_back(_children[i]);
889 sort(children.begin(), children.end(), CompareIndices());
895 * Remove this node and all children from nodes that link to them
896 * in their path cache.
899 SGPropertyNode::remove_from_path_caches ()
901 for (unsigned int i = 0; i < _children.size(); ++i)
902 _children[i]->remove_from_path_caches();
904 for (unsigned int i = 0; i < _linkedNodes.size(); i++)
905 _linkedNodes[i]->erase(this);
906 _linkedNodes.clear();
911 * Remove child by position.
914 SGPropertyNode::removeChild (int pos, bool keep)
916 SGPropertyNode_ptr node;
917 if (pos < 0 || pos >= (int)_children.size())
920 PropertyList::iterator it = _children.begin();
922 node = _children[pos];
925 _removedChildren.push_back(node);
928 node->remove_from_path_caches();
929 node->setAttribute(REMOVED, true);
931 fireChildRemoved(node);
937 * Remove a child node
940 SGPropertyNode::removeChild (const char * name, int index, bool keep)
942 SGPropertyNode_ptr ret;
943 int pos = find_child(name, index, _children);
945 ret = removeChild(pos, keep);
951 * Remove all children with the specified name.
954 SGPropertyNode::removeChildren (const char * name, bool keep)
956 PropertyList children;
958 for (int pos = _children.size() - 1; pos >= 0; pos--)
959 if (compare_strings(_children[pos]->getName(), name))
960 children.push_back(removeChild(pos, keep));
962 sort(children.begin(), children.end(), CompareIndices());
968 * Remove a linked node.
971 SGPropertyNode::remove_linked_node (hash_table * node)
973 for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
974 if (_linkedNodes[i] == node) {
975 vector<hash_table *>::iterator it = _linkedNodes.begin();
977 _linkedNodes.erase(it);
986 SGPropertyNode::getDisplayName (bool simplify) const
988 string display_name = _name;
989 if (_index != 0 || !simplify) {
991 sstr << '[' << _index << ']';
992 display_name += sstr.str();
999 SGPropertyNode::getPath (bool simplify) const
1001 // Calculate the complete path only once.
1002 if (_parent != 0 && _path.empty()) {
1003 _path = _parent->getPath(simplify);
1005 _path += getDisplayName(simplify);
1008 return _path.c_str();
1012 SGPropertyNode::getType () const
1015 return _value.alias->getType();
1016 else if (_type == EXTENDED)
1017 return _value.val->getType();
1024 SGPropertyNode::getBoolValue () const
1026 // Shortcut for common case
1027 if (_attr == (READ|WRITE) && _type == BOOL)
1030 if (getAttribute(TRACE_READ))
1032 if (!getAttribute(READ))
1033 return SGRawValue<bool>::DefaultValue();
1036 return _value.alias->getBoolValue();
1040 return get_int() == 0 ? false : true;
1042 return get_long() == 0L ? false : true;
1044 return get_float() == 0.0 ? false : true;
1046 return get_double() == 0.0L ? false : true;
1049 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1052 return SGRawValue<bool>::DefaultValue();
1057 SGPropertyNode::getIntValue () const
1059 // Shortcut for common case
1060 if (_attr == (READ|WRITE) && _type == INT)
1063 if (getAttribute(TRACE_READ))
1065 if (!getAttribute(READ))
1066 return SGRawValue<int>::DefaultValue();
1069 return _value.alias->getIntValue();
1071 return int(get_bool());
1075 return int(get_long());
1077 return int(get_float());
1079 return int(get_double());
1082 return atoi(get_string());
1085 return SGRawValue<int>::DefaultValue();
1090 SGPropertyNode::getLongValue () const
1092 // Shortcut for common case
1093 if (_attr == (READ|WRITE) && _type == LONG)
1096 if (getAttribute(TRACE_READ))
1098 if (!getAttribute(READ))
1099 return SGRawValue<long>::DefaultValue();
1102 return _value.alias->getLongValue();
1104 return long(get_bool());
1106 return long(get_int());
1110 return long(get_float());
1112 return long(get_double());
1115 return strtol(get_string(), 0, 0);
1118 return SGRawValue<long>::DefaultValue();
1123 SGPropertyNode::getFloatValue () const
1125 // Shortcut for common case
1126 if (_attr == (READ|WRITE) && _type == FLOAT)
1129 if (getAttribute(TRACE_READ))
1131 if (!getAttribute(READ))
1132 return SGRawValue<float>::DefaultValue();
1135 return _value.alias->getFloatValue();
1137 return float(get_bool());
1139 return float(get_int());
1141 return float(get_long());
1145 return float(get_double());
1148 return atof(get_string());
1151 return SGRawValue<float>::DefaultValue();
1156 SGPropertyNode::getDoubleValue () const
1158 // Shortcut for common case
1159 if (_attr == (READ|WRITE) && _type == DOUBLE)
1160 return get_double();
1162 if (getAttribute(TRACE_READ))
1164 if (!getAttribute(READ))
1165 return SGRawValue<double>::DefaultValue();
1169 return _value.alias->getDoubleValue();
1171 return double(get_bool());
1173 return double(get_int());
1175 return double(get_long());
1177 return double(get_float());
1179 return get_double();
1182 return strtod(get_string(), 0);
1185 return SGRawValue<double>::DefaultValue();
1190 SGPropertyNode::getStringValue () const
1192 // Shortcut for common case
1193 if (_attr == (READ|WRITE) && _type == STRING)
1194 return get_string();
1196 if (getAttribute(TRACE_READ))
1198 if (!getAttribute(READ))
1199 return SGRawValue<const char *>::DefaultValue();
1200 return make_string();
1204 SGPropertyNode::setBoolValue (bool value)
1206 // Shortcut for common case
1207 if (_attr == (READ|WRITE) && _type == BOOL)
1208 return set_bool(value);
1210 bool result = false;
1212 if (_type == NONE || _type == UNSPECIFIED) {
1220 result = _value.alias->setBoolValue(value);
1223 result = set_bool(value);
1226 result = set_int(int(value));
1229 result = set_long(long(value));
1232 result = set_float(float(value));
1235 result = set_double(double(value));
1239 result = set_string(value ? "true" : "false");
1246 if (getAttribute(TRACE_WRITE))
1252 SGPropertyNode::setIntValue (int value)
1254 // Shortcut for common case
1255 if (_attr == (READ|WRITE) && _type == INT)
1256 return set_int(value);
1258 bool result = false;
1260 if (_type == NONE || _type == UNSPECIFIED) {
1263 _local_val.int_val = 0;
1268 result = _value.alias->setIntValue(value);
1271 result = set_bool(value == 0 ? false : true);
1274 result = set_int(value);
1277 result = set_long(long(value));
1280 result = set_float(float(value));
1283 result = set_double(double(value));
1288 sprintf(buf, "%d", value);
1289 result = set_string(buf);
1297 if (getAttribute(TRACE_WRITE))
1303 SGPropertyNode::setLongValue (long value)
1305 // Shortcut for common case
1306 if (_attr == (READ|WRITE) && _type == LONG)
1307 return set_long(value);
1309 bool result = false;
1311 if (_type == NONE || _type == UNSPECIFIED) {
1314 _local_val.long_val = 0L;
1319 result = _value.alias->setLongValue(value);
1322 result = set_bool(value == 0L ? false : true);
1325 result = set_int(int(value));
1328 result = set_long(value);
1331 result = set_float(float(value));
1334 result = set_double(double(value));
1339 sprintf(buf, "%ld", value);
1340 result = set_string(buf);
1348 if (getAttribute(TRACE_WRITE))
1354 SGPropertyNode::setFloatValue (float value)
1356 // Shortcut for common case
1357 if (_attr == (READ|WRITE) && _type == FLOAT)
1358 return set_float(value);
1360 bool result = false;
1362 if (_type == NONE || _type == UNSPECIFIED) {
1365 _local_val.float_val = 0;
1370 result = _value.alias->setFloatValue(value);
1373 result = set_bool(value == 0.0 ? false : true);
1376 result = set_int(int(value));
1379 result = set_long(long(value));
1382 result = set_float(value);
1385 result = set_double(double(value));
1390 sprintf(buf, "%f", value);
1391 result = set_string(buf);
1399 if (getAttribute(TRACE_WRITE))
1405 SGPropertyNode::setDoubleValue (double value)
1407 // Shortcut for common case
1408 if (_attr == (READ|WRITE) && _type == DOUBLE)
1409 return set_double(value);
1411 bool result = false;
1413 if (_type == NONE || _type == UNSPECIFIED) {
1415 _local_val.double_val = value;
1421 result = _value.alias->setDoubleValue(value);
1424 result = set_bool(value == 0.0L ? false : true);
1427 result = set_int(int(value));
1430 result = set_long(long(value));
1433 result = set_float(float(value));
1436 result = set_double(value);
1441 sprintf(buf, "%f", value);
1442 result = set_string(buf);
1450 if (getAttribute(TRACE_WRITE))
1456 SGPropertyNode::setStringValue (const char * value)
1458 // Shortcut for common case
1459 if (_attr == (READ|WRITE) && _type == STRING)
1460 return set_string(value);
1462 bool result = false;
1464 if (_type == NONE || _type == UNSPECIFIED) {
1471 result = _value.alias->setStringValue(value);
1474 result = set_bool((compare_strings(value, "true")
1475 || atoi(value)) ? true : false);
1478 result = set_int(atoi(value));
1481 result = set_long(strtol(value, 0, 0));
1484 result = set_float(atof(value));
1487 result = set_double(strtod(value, 0));
1491 result = set_string(value);
1495 stringstream sstr(value);
1496 static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1504 if (getAttribute(TRACE_WRITE))
1510 SGPropertyNode::setUnspecifiedValue (const char * value)
1512 bool result = false;
1514 if (_type == NONE) {
1516 _type = UNSPECIFIED;
1519 if (type == EXTENDED)
1520 type = _value.val->getType();
1523 result = _value.alias->setUnspecifiedValue(value);
1526 result = set_bool((compare_strings(value, "true")
1527 || atoi(value)) ? true : false);
1530 result = set_int(atoi(value));
1533 result = set_long(strtol(value, 0, 0));
1536 result = set_float(atof(value));
1539 result = set_double(strtod(value, 0));
1543 result = set_string(value);
1546 result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1549 result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1556 if (getAttribute(TRACE_WRITE))
1561 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1563 if (!getAttribute(READ))
1567 return _value.alias->printOn(stream);
1569 stream << (get_bool() ? "true" : "false");
1572 stream << get_int();
1575 stream << get_long();
1578 stream << get_float();
1581 stream << get_double();
1585 stream << get_string();
1588 static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1597 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1600 if (_type == ALIAS || _tied)
1603 useDefault = useDefault && hasValue();
1604 std::string old_val;
1606 old_val = getStringValue();
1610 _value.val = rawValue.clone();
1613 setStringValue(old_val.c_str());
1618 SGPropertyNode::untie ()
1625 bool val = getBoolValue();
1628 _local_val.bool_val = val;
1632 int val = getIntValue();
1635 _local_val.int_val = val;
1639 long val = getLongValue();
1642 _local_val.long_val = val;
1646 float val = getFloatValue();
1649 _local_val.float_val = val;
1653 double val = getDoubleValue();
1656 _local_val.double_val = val;
1661 string val = getStringValue();
1664 _local_val.string_val = copy_string(val.c_str());
1668 SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1669 _value.val = 0; // Prevent clearValue() from deleting
1672 _value.val = val->makeContainer();
1686 SGPropertyNode::getRootNode ()
1691 return _parent->getRootNode();
1694 const SGPropertyNode *
1695 SGPropertyNode::getRootNode () const
1700 return _parent->getRootNode();
1704 SGPropertyNode::getNode (const char * relative_path, bool create)
1706 if (_path_cache == 0)
1707 _path_cache = new hash_table;
1709 SGPropertyNode * result = _path_cache->get(relative_path);
1711 vector<PathComponent> components;
1712 parse_path(relative_path, components);
1713 result = find_node(this, components, 0, create);
1715 _path_cache->put(relative_path, result);
1722 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1724 vector<PathComponent> components;
1725 parse_path(relative_path, components);
1726 if (components.size() > 0)
1727 components.back().index = index;
1728 return find_node(this, components, 0, create);
1731 const SGPropertyNode *
1732 SGPropertyNode::getNode (const char * relative_path) const
1734 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1737 const SGPropertyNode *
1738 SGPropertyNode::getNode (const char * relative_path, int index) const
1740 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1744 ////////////////////////////////////////////////////////////////////////
1745 // Convenience methods using relative paths.
1746 ////////////////////////////////////////////////////////////////////////
1750 * Test whether another node has a value attached.
1753 SGPropertyNode::hasValue (const char * relative_path) const
1755 const SGPropertyNode * node = getNode(relative_path);
1756 return (node == 0 ? false : node->hasValue());
1761 * Get the value type for another node.
1764 SGPropertyNode::getType (const char * relative_path) const
1766 const SGPropertyNode * node = getNode(relative_path);
1767 return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1772 * Get a bool value for another node.
1775 SGPropertyNode::getBoolValue (const char * relative_path,
1776 bool defaultValue) const
1778 const SGPropertyNode * node = getNode(relative_path);
1779 return (node == 0 ? defaultValue : node->getBoolValue());
1784 * Get an int value for another node.
1787 SGPropertyNode::getIntValue (const char * relative_path,
1788 int defaultValue) const
1790 const SGPropertyNode * node = getNode(relative_path);
1791 return (node == 0 ? defaultValue : node->getIntValue());
1796 * Get a long value for another node.
1799 SGPropertyNode::getLongValue (const char * relative_path,
1800 long defaultValue) const
1802 const SGPropertyNode * node = getNode(relative_path);
1803 return (node == 0 ? defaultValue : node->getLongValue());
1808 * Get a float value for another node.
1811 SGPropertyNode::getFloatValue (const char * relative_path,
1812 float defaultValue) const
1814 const SGPropertyNode * node = getNode(relative_path);
1815 return (node == 0 ? defaultValue : node->getFloatValue());
1820 * Get a double value for another node.
1823 SGPropertyNode::getDoubleValue (const char * relative_path,
1824 double defaultValue) const
1826 const SGPropertyNode * node = getNode(relative_path);
1827 return (node == 0 ? defaultValue : node->getDoubleValue());
1832 * Get a string value for another node.
1835 SGPropertyNode::getStringValue (const char * relative_path,
1836 const char * defaultValue) const
1838 const SGPropertyNode * node = getNode(relative_path);
1839 return (node == 0 ? defaultValue : node->getStringValue());
1844 * Set a bool value for another node.
1847 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1849 return getNode(relative_path, true)->setBoolValue(value);
1854 * Set an int value for another node.
1857 SGPropertyNode::setIntValue (const char * relative_path, int value)
1859 return getNode(relative_path, true)->setIntValue(value);
1864 * Set a long value for another node.
1867 SGPropertyNode::setLongValue (const char * relative_path, long value)
1869 return getNode(relative_path, true)->setLongValue(value);
1874 * Set a float value for another node.
1877 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1879 return getNode(relative_path, true)->setFloatValue(value);
1884 * Set a double value for another node.
1887 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1889 return getNode(relative_path, true)->setDoubleValue(value);
1894 * Set a string value for another node.
1897 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1899 return getNode(relative_path, true)->setStringValue(value);
1904 * Set an unknown value for another node.
1907 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1910 return getNode(relative_path, true)->setUnspecifiedValue(value);
1915 * Test whether another node is tied.
1918 SGPropertyNode::isTied (const char * relative_path) const
1920 const SGPropertyNode * node = getNode(relative_path);
1921 return (node == 0 ? false : node->isTied());
1926 * Tie a node reached by a relative path, creating it if necessary.
1929 SGPropertyNode::tie (const char * relative_path,
1930 const SGRawValue<bool> &rawValue,
1933 return getNode(relative_path, true)->tie(rawValue, useDefault);
1938 * Tie a node reached by a relative path, creating it if necessary.
1941 SGPropertyNode::tie (const char * relative_path,
1942 const SGRawValue<int> &rawValue,
1945 return getNode(relative_path, true)->tie(rawValue, useDefault);
1950 * Tie a node reached by a relative path, creating it if necessary.
1953 SGPropertyNode::tie (const char * relative_path,
1954 const SGRawValue<long> &rawValue,
1957 return getNode(relative_path, true)->tie(rawValue, useDefault);
1962 * Tie a node reached by a relative path, creating it if necessary.
1965 SGPropertyNode::tie (const char * relative_path,
1966 const SGRawValue<float> &rawValue,
1969 return getNode(relative_path, true)->tie(rawValue, useDefault);
1974 * Tie a node reached by a relative path, creating it if necessary.
1977 SGPropertyNode::tie (const char * relative_path,
1978 const SGRawValue<double> &rawValue,
1981 return getNode(relative_path, true)->tie(rawValue, useDefault);
1986 * Tie a node reached by a relative path, creating it if necessary.
1989 SGPropertyNode::tie (const char * relative_path,
1990 const SGRawValue<const char *> &rawValue,
1993 return getNode(relative_path, true)->tie(rawValue, useDefault);
1998 * Attempt to untie another node reached by a relative path.
2001 SGPropertyNode::untie (const char * relative_path)
2003 SGPropertyNode * node = getNode(relative_path);
2004 return (node == 0 ? false : node->untie());
2008 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2011 if (_listeners == 0)
2012 _listeners = new vector<SGPropertyChangeListener*>;
2013 _listeners->push_back(listener);
2014 listener->register_property(this);
2016 listener->valueChanged(this);
2020 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2022 vector<SGPropertyChangeListener*>::iterator it =
2023 find(_listeners->begin(), _listeners->end(), listener);
2024 if (it != _listeners->end()) {
2025 _listeners->erase(it);
2026 listener->unregister_property(this);
2027 if (_listeners->empty()) {
2028 vector<SGPropertyChangeListener*>* tmp = _listeners;
2036 SGPropertyNode::fireValueChanged ()
2038 fireValueChanged(this);
2042 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2044 fireChildAdded(this, child);
2048 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2050 fireChildRemoved(this, child);
2054 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2056 if (_listeners != 0) {
2057 for (unsigned int i = 0; i < _listeners->size(); i++) {
2058 (*_listeners)[i]->valueChanged(node);
2062 _parent->fireValueChanged(node);
2066 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2067 SGPropertyNode * child)
2069 if (_listeners != 0) {
2070 for (unsigned int i = 0; i < _listeners->size(); i++) {
2071 (*_listeners)[i]->childAdded(parent, child);
2075 _parent->fireChildAdded(parent, child);
2079 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2080 SGPropertyNode * child)
2082 if (_listeners != 0) {
2083 for (unsigned int i = 0; i < _listeners->size(); i++) {
2084 (*_listeners)[i]->childRemoved(parent, child);
2088 _parent->fireChildRemoved(parent, child);
2093 ////////////////////////////////////////////////////////////////////////
2094 // Simplified hash table for caching paths.
2095 ////////////////////////////////////////////////////////////////////////
2097 #define HASH_TABLE_SIZE 199
2099 SGPropertyNode::hash_table::entry::entry ()
2104 SGPropertyNode::hash_table::entry::~entry ()
2106 // Don't delete the value; we don't own
2111 SGPropertyNode::hash_table::entry::set_key (const char * key)
2117 SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2122 SGPropertyNode::hash_table::bucket::bucket ()
2128 SGPropertyNode::hash_table::bucket::~bucket ()
2130 for (int i = 0; i < _length; i++)
2135 SGPropertyNode::hash_table::entry *
2136 SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2139 for (i = 0; i < _length; i++) {
2140 if (!strcmp(_entries[i]->get_key(), key))
2144 entry ** new_entries = new entry*[_length+1];
2145 for (i = 0; i < _length; i++) {
2146 new_entries[i] = _entries[i];
2149 _entries = new_entries;
2150 _entries[_length] = new entry;
2151 _entries[_length]->set_key(key);
2153 return _entries[_length - 1];
2160 SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
2162 for (int i = 0; i < _length; i++) {
2163 if (_entries[i]->get_value() == node) {
2165 for (++i; i < _length; i++) {
2166 _entries[i-1] = _entries[i];
2176 SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
2178 for (int i = 0; i < _length; i++) {
2179 SGPropertyNode * node = _entries[i]->get_value();
2181 node->remove_linked_node(owner);
2185 SGPropertyNode::hash_table::hash_table ()
2191 SGPropertyNode::hash_table::~hash_table ()
2193 for (unsigned int i = 0; i < _data_length; i++) {
2195 _data[i]->clear(this);
2203 SGPropertyNode::hash_table::get (const char * key)
2205 if (_data_length == 0)
2207 unsigned int index = hashcode(key) % _data_length;
2208 if (_data[index] == 0)
2210 entry * e = _data[index]->get_entry(key);
2214 return e->get_value();
2218 SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2220 if (_data_length == 0) {
2221 _data = new bucket*[HASH_TABLE_SIZE];
2222 _data_length = HASH_TABLE_SIZE;
2223 for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2226 unsigned int index = hashcode(key) % _data_length;
2227 if (_data[index] == 0) {
2228 _data[index] = new bucket;
2230 entry * e = _data[index]->get_entry(key, true);
2231 e->set_value(value);
2232 value->add_linked_node(this);
2236 SGPropertyNode::hash_table::erase (SGPropertyNode * node)
2238 for (unsigned int i = 0; i < _data_length; i++)
2239 if (_data[i] && _data[i]->erase(node))
2246 SGPropertyNode::hash_table::hashcode (const char * key)
2248 unsigned int hash = 0;
2250 hash = 31 * hash + *key;
2258 ////////////////////////////////////////////////////////////////////////
2259 // Implementation of SGPropertyChangeListener.
2260 ////////////////////////////////////////////////////////////////////////
2262 SGPropertyChangeListener::~SGPropertyChangeListener ()
2264 for (int i = _properties.size() - 1; i >= 0; i--)
2265 _properties[i]->removeChangeListener(this);
2269 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2275 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2276 SGPropertyNode * child)
2282 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2283 SGPropertyNode * child)
2289 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2291 _properties.push_back(node);
2295 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2297 vector<SGPropertyNode *>::iterator it =
2298 find(_properties.begin(), _properties.end(), node);
2299 if (it != _properties.end())
2300 _properties.erase(it);
2306 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2309 = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2310 for (int i = 0; i < 3; ++i) {
2319 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2321 for (int i = 0; i < 3; ++i) {
2322 stream >> result[i];
2328 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2331 = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();
2332 for (int i = 0; i < 4; ++i) {
2341 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2343 for (int i = 0; i < 4; ++i) {
2344 stream >> result[i];