Fix insert_object to remove from old parent before inserting

The old code inserted the object into the new parent first, then
tried to remove it from the old parent. This corrupted the sibling
chain because the object's sibling pointer was already modified.

The Z-spec says "if O already has a parent, it is first removed."
Now delegates to remove_object() before inserting.
This commit is contained in:
Jared Miller 2026-02-10 13:47:58 -05:00
parent e61dcc3ac4
commit 38e60ae40c
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

View file

@ -330,40 +330,21 @@ class ZObjectParser:
self.set_sibling(objectnum, 0) self.set_sibling(objectnum, 0)
def insert_object(self, parent_object, new_child): def insert_object(self, parent_object, new_child):
"""Prepend object NEW_CHILD to the list of PARENT_OBJECT's children.""" """Prepend object NEW_CHILD to the list of PARENT_OBJECT's children.
# Remember all the original pointers within the new_child Per the Z-spec: if new_child already has a parent, it is first
[p, s, c] = self._get_parent_sibling_child(new_child) removed from that parent's child list, then made the first child
of parent_object."""
# First insert new_child intto the parent_object # Remove from old parent first (spec says "first removed")
self.remove_object(new_child)
# Now insert as first child of parent_object
original_child = self.get_child(parent_object) original_child = self.get_child(parent_object)
self.set_sibling(new_child, original_child) self.set_sibling(new_child, original_child)
self.set_parent(new_child, parent_object) self.set_parent(new_child, parent_object)
self.set_child(parent_object, new_child) self.set_child(parent_object, new_child)
if p == 0: # no need to 'remove' new_child, since it wasn't in a tree
return
# Hunt down and remove the new_child from its old location
item = self.get_child(p)
if item == 0:
# new_object claimed to have parent p, but p has no children!?
raise ZObjectMalformedTree
elif item == new_child: # done! new_object was head of list
self.set_child(p, s) # note that s might be 0, that's fine.
else: # walk across list of sibling links
prev = item
current = self.get_sibling(item)
while current != 0:
if current == new_child:
self.set_sibling(prev, s) # s might be 0, that's fine.
break
prev = current
current = self.get_sibling(current)
else:
# we reached the end of the list, never got a match
raise ZObjectMalformedTree
def get_shortname(self, objectnum): def get_shortname(self, objectnum):
"""Return 'short name' of object number OBJECTNUM as ascii string.""" """Return 'short name' of object number OBJECTNUM as ascii string."""