/* search.c: Glulxe code for built-in search opcodes Designed by Andrew Plotkin http://eblong.com/zarf/glulx/index.html */ #include "glk.h" #include "glulxe.h" #define serop_KeyIndirect (0x01) #define serop_ZeroKeyTerminates (0x02) #define serop_ReturnIndex (0x04) /* ### KeyZeroBounded? variants? */ /* ### LowerBoundKey? */ /* In general, these search functions look through a bunch of structures in memory, searching for one whose key (a fixed-size sequence of bytes within the structure) matches a given key. The result can indicate a particular structure within the bunch, or it can be NULL ("not found".) Any or all of these options can be applied: KeyIndirect: If this is true, the key argument is taken to be the start of an array of bytes in memory (whose length is keysize). If it is false, the key argument contains the key itself. In this case, keysize *must* be 1, 2, or 4. The key is stored in the lower bytes of the key argument, big-endian. (The upper bytes are ignored.) ZeroKeyTerminates: If this is true, when the search reaches a struct whose key is all zeroes, the search terminates (and returns NULL). If the searched-for key happens to also be zeroes, the key-match (returning the struct) takes precedence over the zero-match (returning NULL.) ReturnIndex: If this is false, the return value is the memory address of the matching struct, or 0 to indicate NULL. If true, the return value is the array index of the matching struct, or -1 to indicate NULL. */ static void fetchkey(unsigned char *keybuf, glui32 key, glui32 keysize, glui32 options); /* linear_search(): An array of data structures is stored in memory, beginning at start, each structure being structsize bytes. Within each struct, there is a key value keysize bytes long, starting at position keyoffset (from the start of the structure.) Search through these in order. If one is found whose key matches, return it. If numstructs are searched with no result, return NULL. numstructs may be -1 (0xFFFFFFFF) to indicate no upper limit to the number of structures to search. The search will continue until a match is found, or (if ZeroKeyTerminates is set) a zero key. The KeyIndirect, ZeroKeyTerminates, and ReturnIndex options may be used. */ glui32 linear_search(glui32 key, glui32 keysize, glui32 start, glui32 structsize, glui32 numstructs, glui32 keyoffset, glui32 options) { unsigned char keybuf[4]; glui32 count; int ix; int retindex = ((options & serop_ReturnIndex) != 0); int zeroterm = ((options & serop_ZeroKeyTerminates) != 0); fetchkey(keybuf, key, keysize, options); for (count=0; count byte2) cmp = 1; } } else { for (ix=0; (!cmp) && ix byte2) cmp = 1; } } if (!cmp) { if (retindex) return val; else return addr; } if (cmp < 0) { bot = val+1; } else { top = val; } } if (retindex) return -1; else return 0; } /* linked_search(): The structures may be anywhere in memory, in any order. They are linked by a four-byte address field, which is found in each struct at position nextoffset. If this field contains zero, it indicates the end of the linked list. The KeyIndirect and ZeroKeyTerminates options may be used. */ glui32 linked_search(glui32 key, glui32 keysize, glui32 start, glui32 keyoffset, glui32 nextoffset, glui32 options) { unsigned char keybuf[4]; int ix; glui32 val; int zeroterm = ((options & serop_ZeroKeyTerminates) != 0); fetchkey(keybuf, key, keysize, options); while (start != 0) { int match = TRUE; if (keysize <= 4) { for (ix=0; match && ix