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].
10 # include <simgear_config.h>
14 #include "vectorPropTemplates.hxx"
26 #include <boost/algorithm/string/find_iterator.hpp>
27 #include <boost/algorithm/string/predicate.hpp>
28 #include <boost/algorithm/string/classification.hpp>
29 #include <boost/bind.hpp>
30 #include <boost/functional/hash.hpp>
31 #include <boost/range.hpp>
37 #include <simgear/compiler.h>
38 #include <simgear/debug/logstream.hxx>
40 #if ( _MSC_VER == 1200 )
41 // MSVC 6 is buggy, and needs something strange here
42 using std::vector<SGPropertyNode_ptr>;
43 using std::vector<SGPropertyChangeListener *>;
44 using std::vector<SGPropertyNode *>;
56 using std::stringstream;
58 using namespace simgear;
60 ////////////////////////////////////////////////////////////////////////
62 ////////////////////////////////////////////////////////////////////////
65 * Comparator class for sorting by index.
70 int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
71 return (n1->getIndex() < n2->getIndex());
76 ////////////////////////////////////////////////////////////////////////
77 // Convenience macros for value access.
78 ////////////////////////////////////////////////////////////////////////
80 #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
81 #define TEST_WRITE if (!getAttribute(WRITE)) return false
83 ////////////////////////////////////////////////////////////////////////
84 // Local path normalization code.
85 ////////////////////////////////////////////////////////////////////////
88 * Parse the name for a path component.
90 * Name: [_a-zA-Z][-._a-zA-Z0-9]*
93 template<typename Range>
95 parse_name (const SGPropertyNode *node, const Range &path)
97 typename Range::iterator i = path.begin();
98 typename Range::iterator max = path.end();
102 if (i != path.end() && *i == '.') {
105 if (i != max && *i != '/')
106 throw string("illegal character after . or ..");
107 } else if (isalpha(*i) || *i == '_') {
110 // The rules inside a name are a little
113 if (isalpha(*i) || isdigit(*i) || *i == '_' ||
114 *i == '-' || *i == '.') {
116 } else if (*i == '[' || *i == '/') {
121 err.append("' found in propertyname after '"+node->getNameString()+"'");
122 err.append("\nname may contain only ._- and alphanumeric characters");
130 if (path.begin() == i) {
133 err.append("' found in propertyname after '"+node->getNameString()+"'");
134 err.append("\nname must begin with alpha or '_'");
138 return Range(path.begin(), i);
141 // Validate the name of a single node
142 inline bool validateName(const string& name)
144 using namespace boost;
147 if (!isalpha(name[0]) && name[0] != '_')
149 return all(make_iterator_range(name.begin(), name.end()),
150 is_alnum() || is_any_of("_-."));
153 ////////////////////////////////////////////////////////////////////////
154 // Other static utility functions.
155 ////////////////////////////////////////////////////////////////////////
159 copy_string (const char * s)
161 unsigned long int slen = strlen(s);
162 char * copy = new char[slen + 1];
164 // the source string length is known so no need to check for '\0'
165 // when copying every single character
166 memcpy(copy, s, slen);
167 *(copy + slen) = '\0';
172 compare_strings (const char * s1, const char * s2)
174 return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
178 * Locate a child node by name and index.
180 template<typename Itr>
182 find_child (Itr begin, Itr end, int index, const PropertyList& nodes)
184 int nNodes = nodes.size();
185 boost::iterator_range<Itr> name(begin, end);
186 for (int i = 0; i < nNodes; i++) {
187 SGPropertyNode * node = nodes[i];
189 // searching for a mathing index is a lot less time consuming than
190 // comparing two strings so do that first.
191 if (node->getIndex() == index && boost::equals(node->getName(), name))
198 * Locate the child node with the highest index of the same name
201 find_last_child (const char * name, const PropertyList& nodes)
203 int nNodes = nodes.size();
206 for (int i = 0; i < nNodes; i++) {
207 SGPropertyNode * node = nodes[i];
208 if (compare_strings(node->getName(), name))
210 int idx = node->getIndex();
211 if (idx > index) index = idx;
218 * Get first unused index for child nodes with the given name
221 first_unused_index( const char * name,
222 const PropertyList& nodes,
225 const char* nameEnd = name + strlen(name);
227 for( int index = min_index; index < std::numeric_limits<int>::max(); ++index )
229 if( find_child(name, nameEnd, index, nodes) < 0 )
233 SG_LOG(SG_GENERAL, SG_ALERT, "Too much nodes: " << name);
237 template<typename Itr>
238 inline SGPropertyNode*
239 SGPropertyNode::getExistingChild (Itr begin, Itr end, int index, bool create)
241 int pos = find_child(begin, end, index, _children);
243 return _children[pos];
245 SGPropertyNode_ptr node;
246 pos = find_child(begin, end, index, _removedChildren);
248 PropertyList::iterator it = _removedChildren.begin();
250 node = _removedChildren[pos];
251 _removedChildren.erase(it);
252 node->setAttribute(REMOVED, false);
253 _children.push_back(node);
254 fireChildAdded(node);
261 template<typename Itr>
263 SGPropertyNode::getChildImpl (Itr begin, Itr end, int index, bool create)
265 SGPropertyNode* node = getExistingChild(begin, end, index, create);
270 node = new SGPropertyNode(begin, end, index, this);
271 _children.push_back(node);
272 fireChildAdded(node);
279 template<typename SplitItr>
281 find_node_aux(SGPropertyNode * current, SplitItr& itr, bool create,
284 typedef typename SplitItr::value_type Range;
285 // Run off the end of the list
290 // Success! This is the one we want.
294 // Empty name at this point is empty, not root.
296 return find_node_aux(current, ++itr, create, last_index);
297 Range name = parse_name(current, token);
298 if (equals(name, "."))
299 return find_node_aux(current, ++itr, create, last_index);
300 if (equals(name, "..")) {
301 SGPropertyNode * parent = current->getParent();
303 throw string("attempt to move past root with '..'");
304 return find_node_aux(parent, ++itr, create, last_index);
307 if (last_index >= 0) {
308 // If we are at the last token and last_index is valid, use
309 // last_index as the index value
311 while (!(++itr).eof()) {
325 if (name.end() != token.end()) {
326 if (*name.end() == '[') {
327 typename Range::iterator i = name.end() + 1, end = token.end();
328 for (;i != end; ++i) {
330 index = (index * 10) + (*i - '0');
335 if (i == token.end() || *i != ']')
336 throw string("unterminated index (looking for ']')");
338 throw string("illegal characters in token: ")
339 + string(name.begin(), name.end());
343 return find_node_aux(current->getChildImpl(name.begin(), name.end(),
344 index, create), itr, create,
348 // Internal function for parsing property paths. last_index provides
349 // and index value for the last node name token, if supplied.
350 template<typename Range>
352 find_node (SGPropertyNode * current,
357 using namespace boost;
358 typedef split_iterator<typename range_result_iterator<Range>::type>
361 PathSplitIterator itr
362 = make_split_iterator(path, first_finder("/", is_equal()));
363 if (*path.begin() == '/')
364 return find_node_aux(current->getRootNode(), itr, create, last_index);
366 return find_node_aux(current, itr, create, last_index);
369 ////////////////////////////////////////////////////////////////////////
370 // Private methods from SGPropertyNode (may be inlined for speed).
371 ////////////////////////////////////////////////////////////////////////
374 SGPropertyNode::get_bool () const
377 return static_cast<SGRawValue<bool>*>(_value.val)->getValue();
379 return _local_val.bool_val;
383 SGPropertyNode::get_int () const
386 return (static_cast<SGRawValue<int>*>(_value.val))->getValue();
388 return _local_val.int_val;
392 SGPropertyNode::get_long () const
395 return static_cast<SGRawValue<long>*>(_value.val)->getValue();
397 return _local_val.long_val;
401 SGPropertyNode::get_float () const
404 return static_cast<SGRawValue<float>*>(_value.val)->getValue();
406 return _local_val.float_val;
410 SGPropertyNode::get_double () const
413 return static_cast<SGRawValue<double>*>(_value.val)->getValue();
415 return _local_val.double_val;
419 SGPropertyNode::get_string () const
422 return static_cast<SGRawValue<const char*>*>(_value.val)->getValue();
424 return _local_val.string_val;
428 SGPropertyNode::set_bool (bool val)
431 if (static_cast<SGRawValue<bool>*>(_value.val)->setValue(val)) {
438 _local_val.bool_val = val;
445 SGPropertyNode::set_int (int val)
448 if (static_cast<SGRawValue<int>*>(_value.val)->setValue(val)) {
455 _local_val.int_val = val;
462 SGPropertyNode::set_long (long val)
465 if (static_cast<SGRawValue<long>*>(_value.val)->setValue(val)) {
472 _local_val.long_val = val;
479 SGPropertyNode::set_float (float val)
482 if (static_cast<SGRawValue<float>*>(_value.val)->setValue(val)) {
489 _local_val.float_val = val;
496 SGPropertyNode::set_double (double val)
499 if (static_cast<SGRawValue<double>*>(_value.val)->setValue(val)) {
506 _local_val.double_val = val;
513 SGPropertyNode::set_string (const char * val)
516 if (static_cast<SGRawValue<const char*>*>(_value.val)->setValue(val)) {
523 delete [] _local_val.string_val;
524 _local_val.string_val = copy_string(val);
531 SGPropertyNode::clearValue ()
533 if (_type == props::ALIAS) {
536 } else if (_type != props::NONE) {
539 _local_val.bool_val = SGRawValue<bool>::DefaultValue();
542 _local_val.int_val = SGRawValue<int>::DefaultValue();
545 _local_val.long_val = SGRawValue<long>::DefaultValue();
548 _local_val.float_val = SGRawValue<float>::DefaultValue();
551 _local_val.double_val = SGRawValue<double>::DefaultValue();
554 case props::UNSPECIFIED:
556 delete [] _local_val.string_val;
558 _local_val.string_val = 0;
560 default: // avoid compiler warning
572 * Get the value as a string.
575 SGPropertyNode::make_string () const
577 if (!getAttribute(READ))
581 return _value.alias->getStringValue();
583 return get_bool() ? "true" : "false";
585 case props::UNSPECIFIED:
604 sstr << std::setprecision(10) << get_double();
606 case props::EXTENDED:
608 props::Type realType = _value.val->getType();
609 // Perhaps this should be done for all types?
610 if (realType == props::VEC3D || realType == props::VEC4D)
612 static_cast<SGRawExtended*>(_value.val)->printOn(sstr);
618 _buffer = sstr.str();
619 return _buffer.c_str();
623 * Trace a write access for a property.
626 SGPropertyNode::trace_write () const
629 cerr << "TRACE: Write node " << getPath () << ", value \""
630 << make_string() << '"' << endl;
632 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
633 << ", value \"" << make_string() << '"');
638 * Trace a read access for a property.
641 SGPropertyNode::trace_read () const
644 cerr << "TRACE: Write node " << getPath () << ", value \""
645 << make_string() << '"' << endl;
647 SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
648 << ", value \"" << make_string() << '"');
652 ////////////////////////////////////////////////////////////////////////
653 // Public methods from SGPropertyNode.
654 ////////////////////////////////////////////////////////////////////////
657 * Last used attribute
658 * Update as needed when enum Attribute is changed
660 const int SGPropertyNode::LAST_USED_ATTRIBUTE = PRESERVE;
663 * Default constructor: always creates a root node.
665 SGPropertyNode::SGPropertyNode ()
673 _local_val.string_val = 0;
681 SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
682 : SGReferenced(node),
685 _parent(0), // don't copy the parent
689 _listeners(0) // CHECK!!
691 _local_val.string_val = 0;
693 if (_type == props::NONE)
695 if (_type == props::ALIAS) {
696 _value.alias = node._value.alias;
701 if (_tied || _type == props::EXTENDED) {
702 _value.val = node._value.val->clone();
707 set_bool(node.get_bool());
710 set_int(node.get_int());
713 set_long(node.get_long());
716 set_float(node.get_float());
719 set_double(node.get_double());
722 case props::UNSPECIFIED:
723 set_string(node.get_string());
732 * Convenience constructor.
734 template<typename Itr>
735 SGPropertyNode::SGPropertyNode (Itr begin, Itr end,
737 SGPropertyNode * parent)
746 _local_val.string_val = 0;
748 if (!validateName(_name))
749 throw string("plain name expected instead of '") + _name + '\'';
752 SGPropertyNode::SGPropertyNode (const string& name,
754 SGPropertyNode * parent)
763 _local_val.string_val = 0;
765 if (!validateName(name))
766 throw string("plain name expected instead of '") + _name + '\'';
772 SGPropertyNode::~SGPropertyNode ()
774 // zero out all parent pointers, else they might be dangling
775 for (unsigned i = 0; i < _children.size(); ++i)
776 _children[i]->_parent = 0;
777 for (unsigned i = 0; i < _removedChildren.size(); ++i)
778 _removedChildren[i]->_parent = 0;
782 vector<SGPropertyChangeListener*>::iterator it;
783 for (it = _listeners->begin(); it != _listeners->end(); ++it)
784 (*it)->unregister_property(this);
791 * Alias to another node.
794 SGPropertyNode::alias (SGPropertyNode * target)
796 if (target && (_type != props::ALIAS) && (!_tied))
800 _value.alias = target;
801 _type = props::ALIAS;
809 SG_LOG(SG_GENERAL, SG_ALERT,
810 "Failed to create alias for " << getPath() << ". "
811 "The target property does not exist.");
814 if (_type == props::ALIAS)
816 if (_value.alias == target)
817 return true; // ok, identical alias requested
818 SG_LOG(SG_GENERAL, SG_ALERT,
819 "Failed to create alias at " << target->getPath() << ". "
820 "Source "<< getPath() << " is already aliasing another property.");
825 SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". "
826 "Source " << getPath() << " is a tied property.");
835 * Alias to another node by path.
838 SGPropertyNode::alias (const char * path)
840 return alias(getNode(path, true));
848 SGPropertyNode::unalias ()
850 if (_type != props::ALIAS)
858 * Get the target of an alias.
861 SGPropertyNode::getAliasTarget ()
863 return (_type == props::ALIAS ? _value.alias : 0);
867 const SGPropertyNode *
868 SGPropertyNode::getAliasTarget () const
870 return (_type == props::ALIAS ? _value.alias : 0);
874 * create a non-const child by name after the last node with the same name.
877 SGPropertyNode::addChild(const char * name, int min_index, bool append)
880 ? std::max(find_last_child(name, _children) + 1, min_index)
881 : first_unused_index(name, _children, min_index);
883 SGPropertyNode_ptr node;
884 node = new SGPropertyNode(name, name + strlen(name), pos, this);
885 _children.push_back(node);
886 fireChildAdded(node);
891 * Create multiple children with unused indices
893 simgear::PropertyList
894 SGPropertyNode::addChildren( const std::string& name,
899 simgear::PropertyList nodes;
900 std::set<int> used_indices;
904 // First grab all used indices. This saves us of testing every index if it
905 // is used for every element to be created
906 for( size_t i = 0; i < nodes.size(); i++ )
908 const SGPropertyNode* node = nodes[i];
910 if( node->getNameString() == name && node->getIndex() >= min_index )
911 used_indices.insert(node->getIndex());
916 // If we don't want to fill the holes just find last node
917 min_index = std::max(find_last_child(name.c_str(), _children) + 1, min_index);
920 for( int index = min_index;
921 index < std::numeric_limits<int>::max() && nodes.size() < count;
924 if( used_indices.find(index) == used_indices.end() )
926 SGPropertyNode_ptr node;
927 node = new SGPropertyNode(name, index, this);
928 _children.push_back(node);
929 fireChildAdded(node);
930 nodes.push_back(node);
938 * Get a non-const child by index.
941 SGPropertyNode::getChild (int position)
943 if (position >= 0 && position < nChildren())
944 return _children[position];
951 * Get a const child by index.
953 const SGPropertyNode *
954 SGPropertyNode::getChild (int position) const
956 if (position >= 0 && position < nChildren())
957 return _children[position];
964 * Get a non-const child by name and index, creating if necessary.
968 SGPropertyNode::getChild (const char * name, int index, bool create)
970 return getChildImpl(name, name + strlen(name), index, create);
974 SGPropertyNode::getChild (const string& name, int index, bool create)
976 SGPropertyNode* node = getExistingChild(name.begin(), name.end(), index,
981 node = new SGPropertyNode(name, index, this);
982 _children.push_back(node);
983 fireChildAdded(node);
991 * Get a const child by name and index.
993 const SGPropertyNode *
994 SGPropertyNode::getChild (const char * name, int index) const
996 int pos = find_child(name, name + strlen(name), index, _children);
998 return _children[pos];
1005 * Get all children with the same name (but different indices).
1008 SGPropertyNode::getChildren (const char * name) const
1010 PropertyList children;
1011 int max = _children.size();
1013 for (int i = 0; i < max; i++)
1014 if (compare_strings(_children[i]->getName(), name))
1015 children.push_back(_children[i]);
1017 sort(children.begin(), children.end(), CompareIndices());
1023 * Remove child by position.
1026 SGPropertyNode::removeChild (int pos, bool keep)
1028 SGPropertyNode_ptr node;
1029 if (pos < 0 || pos >= (int)_children.size())
1032 PropertyList::iterator it = _children.begin();
1034 node = _children[pos];
1035 _children.erase(it);
1037 _removedChildren.push_back(node);
1040 node->setAttribute(REMOVED, true);
1042 fireChildRemoved(node);
1048 * Remove a child node
1051 SGPropertyNode::removeChild (const char * name, int index, bool keep)
1053 SGPropertyNode_ptr ret;
1054 int pos = find_child(name, name + strlen(name), index, _children);
1056 ret = removeChild(pos, keep);
1062 * Remove all children with the specified name.
1065 SGPropertyNode::removeChildren (const char * name, bool keep)
1067 PropertyList children;
1069 for (int pos = _children.size() - 1; pos >= 0; pos--)
1070 if (compare_strings(_children[pos]->getName(), name))
1071 children.push_back(removeChild(pos, keep));
1073 sort(children.begin(), children.end(), CompareIndices());
1078 SGPropertyNode::getDisplayName (bool simplify) const
1080 string display_name = _name;
1081 if (_index != 0 || !simplify) {
1083 sstr << '[' << _index << ']';
1084 display_name += sstr.str();
1086 return display_name;
1090 SGPropertyNode::getPath (bool simplify) const
1092 typedef std::vector<SGConstPropertyNode_ptr> PList;
1094 for (const SGPropertyNode* node = this; node->_parent; node = node->_parent)
1095 pathList.push_back(node);
1097 for (PList::reverse_iterator itr = pathList.rbegin(),
1098 rend = pathList.rend();
1102 result += (*itr)->getDisplayName(simplify);
1108 SGPropertyNode::getType () const
1110 if (_type == props::ALIAS)
1111 return _value.alias->getType();
1112 else if (_type == props::EXTENDED)
1113 return _value.val->getType();
1120 SGPropertyNode::getBoolValue () const
1122 // Shortcut for common case
1123 if (_attr == (READ|WRITE) && _type == props::BOOL)
1126 if (getAttribute(TRACE_READ))
1128 if (!getAttribute(READ))
1129 return SGRawValue<bool>::DefaultValue();
1132 return _value.alias->getBoolValue();
1136 return get_int() == 0 ? false : true;
1138 return get_long() == 0L ? false : true;
1140 return get_float() == 0.0 ? false : true;
1142 return get_double() == 0.0L ? false : true;
1144 case props::UNSPECIFIED:
1145 return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1148 return SGRawValue<bool>::DefaultValue();
1153 SGPropertyNode::getIntValue () const
1155 // Shortcut for common case
1156 if (_attr == (READ|WRITE) && _type == props::INT)
1159 if (getAttribute(TRACE_READ))
1161 if (!getAttribute(READ))
1162 return SGRawValue<int>::DefaultValue();
1165 return _value.alias->getIntValue();
1167 return int(get_bool());
1171 return int(get_long());
1173 return int(get_float());
1175 return int(get_double());
1177 case props::UNSPECIFIED:
1178 return atoi(get_string());
1181 return SGRawValue<int>::DefaultValue();
1186 SGPropertyNode::getLongValue () const
1188 // Shortcut for common case
1189 if (_attr == (READ|WRITE) && _type == props::LONG)
1192 if (getAttribute(TRACE_READ))
1194 if (!getAttribute(READ))
1195 return SGRawValue<long>::DefaultValue();
1198 return _value.alias->getLongValue();
1200 return long(get_bool());
1202 return long(get_int());
1206 return long(get_float());
1208 return long(get_double());
1210 case props::UNSPECIFIED:
1211 return strtol(get_string(), 0, 0);
1214 return SGRawValue<long>::DefaultValue();
1219 SGPropertyNode::getFloatValue () const
1221 // Shortcut for common case
1222 if (_attr == (READ|WRITE) && _type == props::FLOAT)
1225 if (getAttribute(TRACE_READ))
1227 if (!getAttribute(READ))
1228 return SGRawValue<float>::DefaultValue();
1231 return _value.alias->getFloatValue();
1233 return float(get_bool());
1235 return float(get_int());
1237 return float(get_long());
1241 return float(get_double());
1243 case props::UNSPECIFIED:
1244 return atof(get_string());
1247 return SGRawValue<float>::DefaultValue();
1252 SGPropertyNode::getDoubleValue () const
1254 // Shortcut for common case
1255 if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1256 return get_double();
1258 if (getAttribute(TRACE_READ))
1260 if (!getAttribute(READ))
1261 return SGRawValue<double>::DefaultValue();
1265 return _value.alias->getDoubleValue();
1267 return double(get_bool());
1269 return double(get_int());
1271 return double(get_long());
1273 return double(get_float());
1275 return get_double();
1277 case props::UNSPECIFIED:
1278 return strtod(get_string(), 0);
1281 return SGRawValue<double>::DefaultValue();
1286 SGPropertyNode::getStringValue () const
1288 // Shortcut for common case
1289 if (_attr == (READ|WRITE) && _type == props::STRING)
1290 return get_string();
1292 if (getAttribute(TRACE_READ))
1294 if (!getAttribute(READ))
1295 return SGRawValue<const char *>::DefaultValue();
1296 return make_string();
1300 SGPropertyNode::setBoolValue (bool value)
1302 // Shortcut for common case
1303 if (_attr == (READ|WRITE) && _type == props::BOOL)
1304 return set_bool(value);
1306 bool result = false;
1308 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1311 _type = props::BOOL;
1316 result = _value.alias->setBoolValue(value);
1319 result = set_bool(value);
1322 result = set_int(int(value));
1325 result = set_long(long(value));
1328 result = set_float(float(value));
1331 result = set_double(double(value));
1334 case props::UNSPECIFIED:
1335 result = set_string(value ? "true" : "false");
1342 if (getAttribute(TRACE_WRITE))
1348 SGPropertyNode::setIntValue (int value)
1350 // Shortcut for common case
1351 if (_attr == (READ|WRITE) && _type == props::INT)
1352 return set_int(value);
1354 bool result = false;
1356 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1359 _local_val.int_val = 0;
1364 result = _value.alias->setIntValue(value);
1367 result = set_bool(value == 0 ? false : true);
1370 result = set_int(value);
1373 result = set_long(long(value));
1376 result = set_float(float(value));
1379 result = set_double(double(value));
1382 case props::UNSPECIFIED: {
1384 sprintf(buf, "%d", value);
1385 result = set_string(buf);
1393 if (getAttribute(TRACE_WRITE))
1399 SGPropertyNode::setLongValue (long value)
1401 // Shortcut for common case
1402 if (_attr == (READ|WRITE) && _type == props::LONG)
1403 return set_long(value);
1405 bool result = false;
1407 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1409 _type = props::LONG;
1410 _local_val.long_val = 0L;
1415 result = _value.alias->setLongValue(value);
1418 result = set_bool(value == 0L ? false : true);
1421 result = set_int(int(value));
1424 result = set_long(value);
1427 result = set_float(float(value));
1430 result = set_double(double(value));
1433 case props::UNSPECIFIED: {
1435 sprintf(buf, "%ld", value);
1436 result = set_string(buf);
1444 if (getAttribute(TRACE_WRITE))
1450 SGPropertyNode::setFloatValue (float value)
1452 // Shortcut for common case
1453 if (_attr == (READ|WRITE) && _type == props::FLOAT)
1454 return set_float(value);
1456 bool result = false;
1458 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1460 _type = props::FLOAT;
1461 _local_val.float_val = 0;
1466 result = _value.alias->setFloatValue(value);
1469 result = set_bool(value == 0.0 ? false : true);
1472 result = set_int(int(value));
1475 result = set_long(long(value));
1478 result = set_float(value);
1481 result = set_double(double(value));
1484 case props::UNSPECIFIED: {
1486 sprintf(buf, "%f", value);
1487 result = set_string(buf);
1495 if (getAttribute(TRACE_WRITE))
1501 SGPropertyNode::setDoubleValue (double value)
1503 // Shortcut for common case
1504 if (_attr == (READ|WRITE) && _type == props::DOUBLE)
1505 return set_double(value);
1507 bool result = false;
1509 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1511 _local_val.double_val = value;
1512 _type = props::DOUBLE;
1517 result = _value.alias->setDoubleValue(value);
1520 result = set_bool(value == 0.0L ? false : true);
1523 result = set_int(int(value));
1526 result = set_long(long(value));
1529 result = set_float(float(value));
1532 result = set_double(value);
1535 case props::UNSPECIFIED: {
1537 sprintf(buf, "%f", value);
1538 result = set_string(buf);
1546 if (getAttribute(TRACE_WRITE))
1552 SGPropertyNode::setStringValue (const char * value)
1554 // Shortcut for common case
1555 if (_attr == (READ|WRITE) && _type == props::STRING)
1556 return set_string(value);
1558 bool result = false;
1560 if (_type == props::NONE || _type == props::UNSPECIFIED) {
1562 _type = props::STRING;
1567 result = _value.alias->setStringValue(value);
1570 result = set_bool((compare_strings(value, "true")
1571 || atoi(value)) ? true : false);
1574 result = set_int(atoi(value));
1577 result = set_long(strtol(value, 0, 0));
1580 result = set_float(atof(value));
1583 result = set_double(strtod(value, 0));
1586 case props::UNSPECIFIED:
1587 result = set_string(value);
1589 case props::EXTENDED:
1591 stringstream sstr(value);
1592 static_cast<SGRawExtended*>(_value.val)->readFrom(sstr);
1600 if (getAttribute(TRACE_WRITE))
1606 SGPropertyNode::setUnspecifiedValue (const char * value)
1608 bool result = false;
1610 if (_type == props::NONE) {
1612 _type = props::UNSPECIFIED;
1614 props::Type type = _type;
1615 if (type == props::EXTENDED)
1616 type = _value.val->getType();
1619 result = _value.alias->setUnspecifiedValue(value);
1622 result = set_bool((compare_strings(value, "true")
1623 || atoi(value)) ? true : false);
1626 result = set_int(atoi(value));
1629 result = set_long(strtol(value, 0, 0));
1632 result = set_float(atof(value));
1635 result = set_double(strtod(value, 0));
1638 case props::UNSPECIFIED:
1639 result = set_string(value);
1642 result = static_cast<SGRawValue<SGVec3d>*>(_value.val)->setValue(parseString<SGVec3d>(value));
1645 result = static_cast<SGRawValue<SGVec4d>*>(_value.val)->setValue(parseString<SGVec4d>(value));
1652 if (getAttribute(TRACE_WRITE))
1657 std::ostream& SGPropertyNode::printOn(std::ostream& stream) const
1659 if (!getAttribute(READ))
1663 return _value.alias->printOn(stream);
1665 stream << (get_bool() ? "true" : "false");
1668 stream << get_int();
1671 stream << get_long();
1674 stream << get_float();
1677 stream << get_double();
1680 case props::UNSPECIFIED:
1681 stream << get_string();
1683 case props::EXTENDED:
1684 static_cast<SGRawExtended*>(_value.val)->printOn(stream);
1688 default: // avoid compiler warning
1695 bool SGPropertyNode::tie (const SGRawValue<const char *> &rawValue,
1698 if (_type == props::ALIAS || _tied)
1701 useDefault = useDefault && hasValue();
1702 std::string old_val;
1704 old_val = getStringValue();
1706 _type = props::STRING;
1708 _value.val = rawValue.clone();
1711 int save_attributes = getAttributes();
1712 setAttribute( WRITE, true );
1713 setStringValue(old_val.c_str());
1714 setAttributes( save_attributes );
1720 SGPropertyNode::untie ()
1727 bool val = getBoolValue();
1729 _type = props::BOOL;
1730 _local_val.bool_val = val;
1734 int val = getIntValue();
1737 _local_val.int_val = val;
1741 long val = getLongValue();
1743 _type = props::LONG;
1744 _local_val.long_val = val;
1747 case props::FLOAT: {
1748 float val = getFloatValue();
1750 _type = props::FLOAT;
1751 _local_val.float_val = val;
1754 case props::DOUBLE: {
1755 double val = getDoubleValue();
1757 _type = props::DOUBLE;
1758 _local_val.double_val = val;
1762 case props::UNSPECIFIED: {
1763 string val = getStringValue();
1765 _type = props::STRING;
1766 _local_val.string_val = copy_string(val.c_str());
1769 case props::EXTENDED: {
1770 SGRawExtended* val = static_cast<SGRawExtended*>(_value.val);
1771 _value.val = 0; // Prevent clearValue() from deleting
1773 _type = props::EXTENDED;
1774 _value.val = val->makeContainer();
1788 SGPropertyNode::getRootNode ()
1793 return _parent->getRootNode();
1796 const SGPropertyNode *
1797 SGPropertyNode::getRootNode () const
1802 return _parent->getRootNode();
1806 SGPropertyNode::getNode (const char * relative_path, bool create)
1808 using namespace boost;
1810 return find_node(this, make_iterator_range(relative_path, relative_path
1811 + strlen(relative_path)),
1816 SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1818 using namespace boost;
1819 return find_node(this, make_iterator_range(relative_path, relative_path
1820 + strlen(relative_path)),
1824 const SGPropertyNode *
1825 SGPropertyNode::getNode (const char * relative_path) const
1827 return ((SGPropertyNode *)this)->getNode(relative_path, false);
1830 const SGPropertyNode *
1831 SGPropertyNode::getNode (const char * relative_path, int index) const
1833 return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1836 ////////////////////////////////////////////////////////////////////////
1837 // Convenience methods using relative paths.
1838 ////////////////////////////////////////////////////////////////////////
1842 * Test whether another node has a value attached.
1845 SGPropertyNode::hasValue (const char * relative_path) const
1847 const SGPropertyNode * node = getNode(relative_path);
1848 return (node == 0 ? false : node->hasValue());
1853 * Get the value type for another node.
1856 SGPropertyNode::getType (const char * relative_path) const
1858 const SGPropertyNode * node = getNode(relative_path);
1859 return (node == 0 ? props::UNSPECIFIED : node->getType());
1864 * Get a bool value for another node.
1867 SGPropertyNode::getBoolValue (const char * relative_path,
1868 bool defaultValue) const
1870 const SGPropertyNode * node = getNode(relative_path);
1871 return (node == 0 ? defaultValue : node->getBoolValue());
1876 * Get an int value for another node.
1879 SGPropertyNode::getIntValue (const char * relative_path,
1880 int defaultValue) const
1882 const SGPropertyNode * node = getNode(relative_path);
1883 return (node == 0 ? defaultValue : node->getIntValue());
1888 * Get a long value for another node.
1891 SGPropertyNode::getLongValue (const char * relative_path,
1892 long defaultValue) const
1894 const SGPropertyNode * node = getNode(relative_path);
1895 return (node == 0 ? defaultValue : node->getLongValue());
1900 * Get a float value for another node.
1903 SGPropertyNode::getFloatValue (const char * relative_path,
1904 float defaultValue) const
1906 const SGPropertyNode * node = getNode(relative_path);
1907 return (node == 0 ? defaultValue : node->getFloatValue());
1912 * Get a double value for another node.
1915 SGPropertyNode::getDoubleValue (const char * relative_path,
1916 double defaultValue) const
1918 const SGPropertyNode * node = getNode(relative_path);
1919 return (node == 0 ? defaultValue : node->getDoubleValue());
1924 * Get a string value for another node.
1927 SGPropertyNode::getStringValue (const char * relative_path,
1928 const char * defaultValue) const
1930 const SGPropertyNode * node = getNode(relative_path);
1931 return (node == 0 ? defaultValue : node->getStringValue());
1936 * Set a bool value for another node.
1939 SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1941 return getNode(relative_path, true)->setBoolValue(value);
1946 * Set an int value for another node.
1949 SGPropertyNode::setIntValue (const char * relative_path, int value)
1951 return getNode(relative_path, true)->setIntValue(value);
1956 * Set a long value for another node.
1959 SGPropertyNode::setLongValue (const char * relative_path, long value)
1961 return getNode(relative_path, true)->setLongValue(value);
1966 * Set a float value for another node.
1969 SGPropertyNode::setFloatValue (const char * relative_path, float value)
1971 return getNode(relative_path, true)->setFloatValue(value);
1976 * Set a double value for another node.
1979 SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1981 return getNode(relative_path, true)->setDoubleValue(value);
1986 * Set a string value for another node.
1989 SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1991 return getNode(relative_path, true)->setStringValue(value);
1996 * Set an unknown value for another node.
1999 SGPropertyNode::setUnspecifiedValue (const char * relative_path,
2002 return getNode(relative_path, true)->setUnspecifiedValue(value);
2007 * Test whether another node is tied.
2010 SGPropertyNode::isTied (const char * relative_path) const
2012 const SGPropertyNode * node = getNode(relative_path);
2013 return (node == 0 ? false : node->isTied());
2018 * Tie a node reached by a relative path, creating it if necessary.
2021 SGPropertyNode::tie (const char * relative_path,
2022 const SGRawValue<bool> &rawValue,
2025 return getNode(relative_path, true)->tie(rawValue, useDefault);
2030 * Tie a node reached by a relative path, creating it if necessary.
2033 SGPropertyNode::tie (const char * relative_path,
2034 const SGRawValue<int> &rawValue,
2037 return getNode(relative_path, true)->tie(rawValue, useDefault);
2042 * Tie a node reached by a relative path, creating it if necessary.
2045 SGPropertyNode::tie (const char * relative_path,
2046 const SGRawValue<long> &rawValue,
2049 return getNode(relative_path, true)->tie(rawValue, useDefault);
2054 * Tie a node reached by a relative path, creating it if necessary.
2057 SGPropertyNode::tie (const char * relative_path,
2058 const SGRawValue<float> &rawValue,
2061 return getNode(relative_path, true)->tie(rawValue, useDefault);
2066 * Tie a node reached by a relative path, creating it if necessary.
2069 SGPropertyNode::tie (const char * relative_path,
2070 const SGRawValue<double> &rawValue,
2073 return getNode(relative_path, true)->tie(rawValue, useDefault);
2078 * Tie a node reached by a relative path, creating it if necessary.
2081 SGPropertyNode::tie (const char * relative_path,
2082 const SGRawValue<const char *> &rawValue,
2085 return getNode(relative_path, true)->tie(rawValue, useDefault);
2090 * Attempt to untie another node reached by a relative path.
2093 SGPropertyNode::untie (const char * relative_path)
2095 SGPropertyNode * node = getNode(relative_path);
2096 return (node == 0 ? false : node->untie());
2100 SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2103 if (_listeners == 0)
2104 _listeners = new vector<SGPropertyChangeListener*>;
2105 _listeners->push_back(listener);
2106 listener->register_property(this);
2108 listener->valueChanged(this);
2112 SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2114 if (_listeners == 0)
2116 vector<SGPropertyChangeListener*>::iterator it =
2117 find(_listeners->begin(), _listeners->end(), listener);
2118 if (it != _listeners->end()) {
2119 _listeners->erase(it);
2120 listener->unregister_property(this);
2121 if (_listeners->empty()) {
2122 vector<SGPropertyChangeListener*>* tmp = _listeners;
2130 SGPropertyNode::fireValueChanged ()
2132 fireValueChanged(this);
2136 SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2138 fireChildAdded(this, child);
2142 SGPropertyNode::fireCreatedRecursive()
2144 _parent->fireChildAdded(this);
2146 if( _children.empty() && getType() != simgear::props::NONE )
2147 return fireValueChanged();
2149 for(size_t i = 0; i < _children.size(); ++i)
2150 _children[i]->fireCreatedRecursive();
2154 SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2156 fireChildRemoved(this, child);
2160 SGPropertyNode::fireChildrenRemovedRecursive()
2162 for(size_t i = 0; i < _children.size(); ++i)
2164 SGPropertyNode* child = _children[i];
2165 fireChildRemoved(this, child);
2166 child->fireChildrenRemovedRecursive();
2171 SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2173 if (_listeners != 0) {
2174 for (unsigned int i = 0; i < _listeners->size(); i++) {
2175 (*_listeners)[i]->valueChanged(node);
2179 _parent->fireValueChanged(node);
2183 SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2184 SGPropertyNode * child)
2186 if (_listeners != 0) {
2187 for (unsigned int i = 0; i < _listeners->size(); i++) {
2188 (*_listeners)[i]->childAdded(parent, child);
2192 _parent->fireChildAdded(parent, child);
2196 SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2197 SGPropertyNode * child)
2199 if (_listeners != 0) {
2200 for (unsigned int i = 0; i < _listeners->size(); i++) {
2201 (*_listeners)[i]->childRemoved(parent, child);
2205 _parent->fireChildRemoved(parent, child);
2208 ////////////////////////////////////////////////////////////////////////
2209 // Implementation of SGPropertyChangeListener.
2210 ////////////////////////////////////////////////////////////////////////
2212 SGPropertyChangeListener::~SGPropertyChangeListener ()
2214 for (int i = _properties.size() - 1; i >= 0; i--)
2215 _properties[i]->removeChangeListener(this);
2219 SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2225 SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2226 SGPropertyNode * child)
2232 SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2233 SGPropertyNode * child)
2239 SGPropertyChangeListener::register_property (SGPropertyNode * node)
2241 _properties.push_back(node);
2245 SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2247 vector<SGPropertyNode *>::iterator it =
2248 find(_properties.begin(), _properties.end(), node);
2249 if (it != _properties.end())
2250 _properties.erase(it);
2254 std::ostream& SGRawBase<SGVec3d>::printOn(std::ostream& stream) const
2257 = static_cast<const SGRawValue<SGVec3d>*>(this)->getValue();
2258 for (int i = 0; i < 3; ++i) {
2269 std::istream& readFrom<SGVec3d>(std::istream& stream, SGVec3d& result)
2271 for (int i = 0; i < 3; ++i) {
2272 stream >> result[i];
2278 std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
2281 = static_cast<const SGRawValue<SGVec4d>*>(this)->getValue();
2282 for (int i = 0; i < 4; ++i) {
2293 std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
2295 for (int i = 0; i < 4; ++i) {
2296 stream >> result[i];
2303 bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
2305 props::Type ltype = lhs.getType();
2306 props::Type rtype = rhs.getType();
2313 return false; // XXX Should we look in aliases?
2315 return lhs.getValue<bool>() == rhs.getValue<bool>();
2317 return lhs.getValue<int>() == rhs.getValue<int>();
2319 return lhs.getValue<long>() == rhs.getValue<long>();
2321 return lhs.getValue<float>() == rhs.getValue<float>();
2323 return lhs.getValue<double>() == rhs.getValue<double>();
2325 case props::UNSPECIFIED:
2326 return !strcmp(lhs.getStringValue(), rhs.getStringValue());
2328 return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
2330 return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
2338 bool SGPropertyNode::compare(const SGPropertyNode& lhs,
2339 const SGPropertyNode& rhs)
2343 int lhsChildren = lhs.nChildren();
2344 int rhsChildren = rhs.nChildren();
2345 if (lhsChildren != rhsChildren)
2347 if (lhsChildren == 0)
2348 return compareNodeValue(lhs, rhs);
2349 for (size_t i = 0; i < lhs._children.size(); ++i) {
2350 const SGPropertyNode* lchild = lhs._children[i];
2351 const SGPropertyNode* rchild = rhs._children[i];
2352 // I'm guessing that the nodes will usually be in the same
2354 if (lchild->getIndex() != rchild->getIndex()
2355 || lchild->getNameString() != rchild->getNameString()) {
2357 for (PropertyList::const_iterator itr = rhs._children.begin(),
2358 end = rhs._children.end();
2361 if (lchild->getIndex() == (*itr)->getIndex()
2362 && lchild->getNameString() == (*itr)->getNameString()) {
2369 if (!compare(*lchild, *rchild))
2375 struct PropertyPlaceLess {
2376 typedef bool result_type;
2377 bool operator()(SGPropertyNode_ptr lhs, SGPropertyNode_ptr rhs) const
2379 int comp = lhs->getNameString().compare(rhs->getNameString());
2381 return lhs->getIndex() < rhs->getIndex();
2387 size_t hash_value(const SGPropertyNode& node)
2389 using namespace boost;
2391 if (node.nChildren() == 0) {
2392 switch (node.getType()) {
2397 return hash_value(node.getValue<bool>());
2399 return hash_value(node.getValue<int>());
2401 return hash_value(node.getValue<long>());
2403 return hash_value(node.getValue<float>());
2405 return hash_value(node.getValue<double>());
2407 case props::UNSPECIFIED:
2409 const char *val = node.getStringValue();
2410 return hash_range(val, val + strlen(val));
2414 const SGVec3d val = node.getValue<SGVec3d>();
2415 return hash_range(&val[0], &val[3]);
2419 const SGVec4d val = node.getValue<SGVec4d>();
2420 return hash_range(&val[0], &val[4]);
2422 case props::ALIAS: // XXX Should we look in aliases?
2428 PropertyList children(node._children.begin(), node._children.end());
2429 sort(children.begin(), children.end(), PropertyPlaceLess());
2430 for (PropertyList::const_iterator itr = children.begin(),
2431 end = children.end();
2434 hash_combine(seed, (*itr)->_name);
2435 hash_combine(seed, (*itr)->_index);
2436 hash_combine(seed, hash_value(**itr));