+
+/**
+ * Get a value, optionally creating it if not present.
+ */
+SGValue *
+SGPropertyNode::getValue (bool create)
+{
+ if (_value == 0 && create)
+ _value = new SGValue();
+ return _value;
+}
+
+
+/**
+ * Alias to another node.
+ */
+bool
+SGPropertyNode::alias (SGPropertyNode * target)
+{
+ if (_value == 0)
+ _value = new SGValue();
+ _target = target;
+ return _value->alias(target->getValue(true));
+}
+
+
+/**
+ * Alias to another node by path.
+ */
+bool
+SGPropertyNode::alias (const string &path)
+{
+ return alias(getNode(path, true));
+}
+
+
+/**
+ * Remove an alias.
+ */
+bool
+SGPropertyNode::unalias ()
+{
+ _target = 0;
+ return (_value != 0 ? _value->unalias() : false);
+}
+
+
+/**
+ * Test whether this node is aliased.
+ */
+bool
+SGPropertyNode::isAlias () const
+{
+ return (_value != 0 ? _value->isAlias() : false);
+}
+
+
+/**
+ * Get the target of an alias.
+ *
+ * This is tricky, because it is actually the value that is aliased,
+ * and someone could realias or unalias the value directly without
+ * going through the property node. The node caches its best guess,
+ * but it may have to search the whole property tree.
+ *
+ * @return The target node for the alias, or 0 if the node is not aliased.
+ */
+SGPropertyNode *
+SGPropertyNode::getAliasTarget ()
+{
+ if (_value == 0 || !_value->isAlias()) {
+ return 0;
+ } else if (_target != 0 && _target->getValue() == _value->getAlias()) {
+ return _target;
+ } else {
+ _target = find_node_by_value(getRootNode(), _value->getAlias());
+ }
+}
+
+
+const SGPropertyNode *
+SGPropertyNode::getAliasTarget () const
+{
+ if (_value == 0 || !_value->isAlias()) {
+ return 0;
+ } else if (_target != 0 && _target->getValue() == _value->getAlias()) {
+ return _target;
+ } else {
+ // FIXME: const cast
+ _target =
+ find_node_by_value((SGPropertyNode *)getRootNode(), _value->getAlias());
+ }
+}
+
+
+/**
+ * Get a non-const child by index.
+ */