name = ".";
}
if (i < max && path[i] != '/')
- throw string("Illegal character after " + name);
+ throw string("illegal character after " + name);
}
else if (isalpha(path[i]) || path[i] == '_') {
* Locate a child node by name and index.
*/
static int
-find_child (const char * name, int index, vector<SGPropertyNode_ptr> nodes)
+find_child (const char * name, int index, const vector<SGPropertyNode_ptr>& nodes)
{
int nNodes = nodes.size();
for (int i = 0; i < nNodes; i++) {
else if (components[position].name == "..") {
SGPropertyNode * parent = current->getParent();
if (parent == 0)
- throw string("Attempt to move past root with '..'");
+ throw string("attempt to move past root with '..'");
else
return find_node(parent, components, position + 1, create);
}
SGPropertyNode::trace_write () const
{
#if PROPS_STANDALONE
- cerr << "TRACE: Write node " << getPath () << ", value\""
+ cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl;
#else
- SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
- << ", value\"" << make_string() << '"');
+ SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Write node " << getPath()
+ << ", value \"" << make_string() << '"');
#endif
}
cerr << "TRACE: Write node " << getPath () << ", value \""
<< make_string() << '"' << endl;
#else
- SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
+ SG_LOG(SG_GENERAL, SG_ALERT, "TRACE: Read node " << getPath()
<< ", value \"" << make_string() << '"');
#endif
}
_attr(READ|WRITE),
_listeners(0)
{
- _name = name;
+ int i = 0;
+ _name = parse_name(name, i);
+ if (i != int(strlen(name)) || name[0] == '.')
+ throw string("plain name expected instead of '") + name + '\'';
+
_local_val.string_val = 0;
}
*/
SGPropertyNode::~SGPropertyNode ()
{
+ // zero out all parent pointers, else they might be dangling
+ for (unsigned i = 0; i < _children.size(); ++i)
+ _children[i]->_parent = 0;
+ for (unsigned i = 0; i < _removedChildren.size(); ++i)
+ _removedChildren[i]->_parent = 0;
delete _path_cache;
clearValue();
- delete _listeners;
+
+ if (_listeners) {
+ vector<SGPropertyChangeListener*>::iterator it;
+ for (it = _listeners->begin(); it != _listeners->end(); ++it)
+ (*it)->unregister_property(this);
+ delete _listeners;
+ }
}
}
+/**
+ * Remove this node and all children from nodes that link to them
+ * in their path cache.
+ */
+void
+SGPropertyNode::remove_from_path_caches ()
+{
+ for (unsigned int i = 0; i < _children.size(); ++i)
+ _children[i]->remove_from_path_caches();
+
+ for (unsigned int i = 0; i < _linkedNodes.size(); i++)
+ _linkedNodes[i]->erase(this);
+ _linkedNodes.clear();
+}
+
+
/**
* Remove child by position.
*/
SGPropertyNode::removeChild (int pos, bool keep)
{
SGPropertyNode_ptr node;
- if (pos < 0 || pos >= _children.size())
+ if (pos < 0 || pos >= (int)_children.size())
return node;
vector<SGPropertyNode_ptr>::iterator it = _children.begin();
if (keep) {
_removedChildren.push_back(node);
}
- if (_path_cache)
- _path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
+
+ node->remove_from_path_caches();
node->setAttribute(REMOVED, true);
node->clearValue();
fireChildRemoved(node);
/**
* Remove a child node
*/
-SGPropertyNode_ptr
+SGPropertyNode_ptr
SGPropertyNode::removeChild (const char * name, int index, bool keep)
{
SGPropertyNode_ptr ret;
}
+/**
+ * Remove a linked node.
+ */
+bool
+SGPropertyNode::remove_linked_node (hash_table * node)
+{
+ for (unsigned int i = 0; i < _linkedNodes.size(); i++) {
+ if (_linkedNodes[i] == node) {
+ vector<hash_table *>::iterator it = _linkedNodes.begin();
+ it += i;
+ _linkedNodes.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+
const char *
SGPropertyNode::getDisplayName (bool simplify) const
{
}
}
-void
-SGPropertyNode::hash_table::bucket::erase (const char * key)
+bool
+SGPropertyNode::hash_table::bucket::erase (SGPropertyNode * node)
{
- int i;
- for (i = 0; i < _length; i++) {
- if (!strcmp(_entries[i]->get_key(), key))
- break;
- }
-
- if (i < _length) {
- for (++i; i < _length; i++) {
- _entries[i-1] = _entries[i];
+ for (int i = 0; i < _length; i++) {
+ if (_entries[i]->get_value() == node) {
+ delete _entries[i];
+ for (++i; i < _length; i++) {
+ _entries[i-1] = _entries[i];
+ }
+ _length--;
+ return true;
}
- _length--;
}
+ return false;
}
+void
+SGPropertyNode::hash_table::bucket::clear (SGPropertyNode::hash_table * owner)
+{
+ for (int i = 0; i < _length; i++) {
+ SGPropertyNode * node = _entries[i]->get_value();
+ if (node)
+ node->remove_linked_node(owner);
+ }
+}
SGPropertyNode::hash_table::hash_table ()
: _data_length(0),
SGPropertyNode::hash_table::~hash_table ()
{
- for (unsigned int i = 0; i < _data_length; i++)
- delete _data[i];
+ for (unsigned int i = 0; i < _data_length; i++) {
+ if (_data[i]) {
+ _data[i]->clear(this);
+ delete _data[i];
+ }
+ }
delete [] _data;
}
}
entry * e = _data[index]->get_entry(key, true);
e->set_value(value);
+ value->add_linked_node(this);
}
-void
-SGPropertyNode::hash_table::erase (const char * key)
+bool
+SGPropertyNode::hash_table::erase (SGPropertyNode * node)
{
- if (_data_length == 0)
- return;
- unsigned int index = hashcode(key) % _data_length;
- if (_data[index] == 0)
- return;
- _data[index]->erase(key);
+ for (unsigned int i = 0; i < _data_length; i++)
+ if (_data[i] && _data[i]->erase(node))
+ return true;
+
+ return false;
}
unsigned int
SGPropertyChangeListener::~SGPropertyChangeListener ()
{
- // This will come back and remove
- // the current item each time. Is
- // that OK?
- vector<SGPropertyNode *>::iterator it;
- for (it = _properties.begin(); it != _properties.end(); it++)
- (*it)->removeChangeListener(this);
+ for (int i = _properties.size() - 1; i >= 0; i--)
+ _properties[i]->removeChangeListener(this);
}
void