2 * Copyright 2009-2012 Chris Spiegel.
4 * This file is part of Bocfel.
6 * Bocfel is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version
8 * 2 or 3, as published by the Free Software Foundation.
10 * Bocfel is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Bocfel. If not, see <http://www.gnu.org/licenses/>.
30 static uint16_t OBJECT(uint16_t n)
32 /* Use 32-bit arithmetic to detect 16-bit overflow. */
33 uint32_t base = header.objects, obj = n, addr;
38 ZASSERT(n <= 255, "illegal object %u referenced", (unsigned)n);
39 addr = base + (31 * 2) + (9 * (obj - 1));
44 addr = base + (63 * 2) + (14 * (obj - 1));
48 ZASSERT(addr + objsize < header.static_start, "object %u out of range", (unsigned)n);
53 #define OFFSET_PARENT (zversion <= 3 ? 4 : 6)
54 #define OFFSET_SIBLING (zversion <= 3 ? 5 : 8)
55 #define OFFSET_CHILD (zversion <= 3 ? 6 : 10)
56 #define OFFSET_PROP (zversion <= 3 ? 7 : 12)
58 #define PARENT(object) RELATION(object, OFFSET_PARENT)
59 #define SIBLING(object) RELATION(object, OFFSET_SIBLING)
60 #define CHILD(object) RELATION(object, OFFSET_CHILD)
62 #define SET_PARENT(obj1, obj2) SET_OBJECT(obj1, obj2, OFFSET_PARENT)
63 #define SET_SIBLING(obj1, obj2) SET_OBJECT(obj1, obj2, OFFSET_SIBLING)
64 #define SET_CHILD(obj1, obj2) SET_OBJECT(obj1, obj2, OFFSET_CHILD)
66 static uint16_t PROPADDR(uint16_t n)
68 return WORD(OBJECT(n) + OFFSET_PROP);
71 static uint16_t RELATION(uint16_t object, int offset)
73 return zversion <= 3 ? BYTE(OBJECT(object) + offset) : WORD(OBJECT(object) + offset);
77 * the 32 attribute flags parent sibling child properties
78 * ---32 bits in 4 bytes--- ---3 bytes------------------ ---2 bytes--
80 * the 48 attribute flags parent sibling child properties
81 * ---48 bits in 6 bytes--- ---3 words, i.e. 6 bytes---- ---2 bytes--
83 static void SET_OBJECT(uint16_t obj1, uint16_t obj2, int offset)
85 if(zversion <= 3) STORE_BYTE(OBJECT(obj1) + offset, obj2);
86 else STORE_WORD(OBJECT(obj1) + offset, obj2);
89 static void remove_obj(uint16_t object)
91 uint16_t parent = PARENT(object);
95 uint16_t child = CHILD(parent);
100 /* parent->child = parent->child->sibling */
101 SET_CHILD(parent, SIBLING(child));
105 while(SIBLING(child) != object)
107 /* child = child->sibling */
108 child = SIBLING(child);
111 /* Now the sibling of child is the object to remove. */
113 /* child->sibling = child->sibling->sibling */
114 SET_SIBLING(child, SIBLING(SIBLING(child)));
117 /* object->parent = 0 */
118 SET_PARENT(object, 0);
120 /* object->sibling = 0 */
121 SET_SIBLING(object, 0);
125 static uint16_t property_length(uint16_t propaddr)
128 /* The address is to the data; the size byte is right before. */
129 uint8_t byte = user_byte(propaddr - 1);
133 length = (byte >> 5) + 1;
139 length = byte & 0x3f;
140 if(length == 0) length = 64;
144 length = (byte & 0x40) ? 2 : 1;
151 static uint8_t PROPERTY(uint16_t addr)
157 propnum = user_byte(addr - 1) & 0x1f;
161 if(user_byte(addr - 1) & 0x80) propnum = user_byte(addr - 2) & 0x3f;
162 else propnum = user_byte(addr - 1) & 0x3f;
168 static uint16_t advance_prop_addr(uint16_t propaddr)
172 size = user_byte(propaddr++);
174 if(size == 0) return 0;
176 if(zversion >= 4 && (size & 0x80)) propaddr++;
181 static uint16_t first_property(uint16_t object)
183 uint16_t propaddr = PROPADDR(object);
185 propaddr += (2 * user_byte(propaddr)) + 1;
187 return advance_prop_addr(propaddr);
190 static uint16_t next_property(uint16_t propaddr)
192 propaddr += property_length(propaddr);
194 return advance_prop_addr(propaddr);
197 #define FOR_EACH_PROPERTY(object, addr) for(uint16_t addr = first_property(object); addr != 0; addr = next_property(addr))
199 static int find_prop(uint16_t object, uint16_t property, uint16_t *propaddr, uint16_t *length)
201 FOR_EACH_PROPERTY(object, addr)
203 if(PROPERTY(addr) == property)
206 *length = property_length(addr);
214 static void check_attr(uint16_t attr)
216 ZASSERT(attr <= (zversion <= 3 ? 31 : 47), "invalid attribute: %u", (unsigned)attr);
219 static int is_zero(int is_store, int is_jump)
223 if(is_store) store(0);
224 if(is_jump) branch_if(0);
232 #define check_zero(store, jump) do { if(is_zero(store, jump)) return; } while(0)
234 /* Attributes are stored at the very beginning of an object, so the
235 * address OBJECT() returns refers directly to the attributes. The
236 * leftmost bit is attribute 0. Thus these attribute functions need to
237 * find out first which byte of the attributes to look at; this is done
238 * by dividing by 8. Attributes 0-7 will be in byte 0, 8-15 in byte 1,
239 * and so on. Then the particular bit is found. Attributes 0..7 are
240 * bits 7..0, attributes 8..15 are 7..0, and so on. Taking the
241 * remainder of the attribute divided by 8 gives the bit position,
242 * counting from the left, of the attribute.
244 #define ATTR_BIT(num) (0x80U >> ((num) % 8))
245 void ztest_attr(void)
248 check_attr(zargs[1]);
250 uint16_t addr = OBJECT(zargs[0]) + (zargs[1] / 8);
252 branch_if(BYTE(addr) & ATTR_BIT(zargs[1]));
258 check_attr(zargs[1]);
260 uint16_t addr = OBJECT(zargs[0]) + (zargs[1] / 8);
262 STORE_BYTE(addr, BYTE(addr) | ATTR_BIT(zargs[1]));
265 void zclear_attr(void)
268 check_attr(zargs[1]);
270 uint16_t addr = OBJECT(zargs[0]) + (zargs[1] / 8);
272 STORE_BYTE(addr, BYTE(addr) & ~ATTR_BIT(zargs[1]));
276 void zremove_obj(void)
280 remove_obj(zargs[0]);
283 void zinsert_obj(void)
287 remove_obj(zargs[0]);
289 SET_SIBLING(zargs[0], CHILD(zargs[1]));
290 SET_CHILD(zargs[1], zargs[0]);
291 SET_PARENT(zargs[0], zargs[1]);
294 void zget_sibling(void)
298 uint16_t sibling = SIBLING(zargs[0]);
301 branch_if(sibling != 0);
304 void zget_child(void)
308 uint16_t child = CHILD(zargs[0]);
311 branch_if(child != 0);
314 void zget_parent(void)
318 store(PARENT(zargs[0]));
325 uint16_t propaddr, length;
328 found = find_prop(zargs[0], zargs[1], &propaddr, &length);
330 ZASSERT(found, "broken story: no prop");
331 ZASSERT(length == 1 || length == 2, "broken story: property too long: %u", (unsigned)length);
333 if(length == 1) user_store_byte(propaddr, zargs[2] & 0xff);
334 else user_store_word(propaddr, zargs[2]);
341 uint16_t propaddr, length;
343 if(find_prop(zargs[0], zargs[1], &propaddr, &length))
345 if (length == 1) store(user_byte(propaddr));
346 else if(length == 2) store(user_word(propaddr));
348 /* If the length is > 2, the story file is misbehaving. At least
349 * Christminster does this, and Frotz and Nitfol allow it, reading a
350 * word, so do that here.
352 else store(user_word(propaddr));
358 ZASSERT(zargs[1] < (zversion <= 3 ? 32 : 64), "invalid property: %u", (unsigned)zargs[1]);
360 i = header.objects + (2 * (zargs[1] - 1));
365 void zget_prop_len(void)
367 /* Z-spec 1.1 says @get_prop_len 0 must yield 0. */
368 if(zargs[0] == 0) store(0);
369 else store(property_length(zargs[0]));
372 void zget_prop_addr(void)
376 uint16_t propaddr, length;
378 if(find_prop(zargs[0], zargs[1], &propaddr, &length)) store(propaddr);
382 void zget_next_prop(void)
386 uint16_t object = zargs[0], property = zargs[1];
390 FOR_EACH_PROPERTY(object, propaddr)
392 uint8_t propnum = PROPERTY(propaddr);
394 if(property == 0 || next)
396 found_prop = propnum;
400 if(propnum == property) next = 1;
408 /* @jin 0 0 is not defined, since @jin requires an object (§15) and
409 * object 0 is not actually an object (§12.3). However, many
410 * interpreters yield a true value for this, and Torbjorn Andersson’s
411 * strictz tester expects it to be true, so go with the flow.
413 if(zargs[0] == 0 && zargs[1] == 0)
421 branch_if(PARENT(zargs[0]) == zargs[1]);
424 void print_object(uint16_t obj, void (*outc)(uint8_t))
428 print_handler(PROPADDR(obj) + 1, outc);
431 void zprint_obj(void)
435 print_object(zargs[0], NULL);