1 // $Id: search.c,v 1.1 2003/10/18 20:06:41 iain Exp $
3 // search.c: Glulxe code for built-in search opcodes
4 // Designed by Andrew Plotkin <erkyrath@eblong.com>
5 // http://www.eblong.com/zarf/glulx/index.html
18 #define serop_KeyIndirect (0x01)
19 #define serop_ZeroKeyTerminates (0x02)
20 #define serop_ReturnIndex (0x04)
21 /* ### KeyZeroBounded? variants? */
22 /* ### LowerBoundKey? */
24 /* In general, these search functions look through a bunch of structures
25 in memory, searching for one whose key (a fixed-size sequence of bytes
26 within the structure) matches a given key. The result can indicate a
27 particular structure within the bunch, or it can be NULL ("not found".)
29 Any or all of these options can be applied:
31 KeyIndirect: If this is true, the key argument is taken to be the
32 start of an array of bytes in memory (whose length is keysize).
33 If it is false, the key argument contains the key itself. In
34 this case, keysize *must* be 1, 2, or 4. The key is stored in the
35 lower bytes of the key argument, big-endian. (The upper bytes are
38 ZeroKeyTerminates: If this is true, when the search reaches a struct
39 whose key is all zeroes, the search terminates (and returns NULL).
40 If the searched-for key happens to also be zeroes, the key-match
41 (returning the struct) takes precedence over the zero-match (returning
44 ReturnIndex: If this is false, the return value is the memory address
45 of the matching struct, or 0 to indicate NULL. If true, the return value
46 is the array index of the matching struct, or -1 to indicate NULL.
49 static void fetchkey(unsigned char *keybuf, glui32 key, glui32 keysize,
53 An array of data structures is stored in memory, beginning at start,
54 each structure being structsize bytes. Within each struct, there is
55 a key value keysize bytes long, starting at position keyoffset (from
56 the start of the structure.) Search through these in order. If one
57 is found whose key matches, return it. If numstructs are searched
58 with no result, return NULL.
60 numstructs may be -1 (0xFFFFFFFF) to indicate no upper limit to the
61 number of structures to search. The search will continue until a match
62 is found, or (if ZeroKeyTerminates is set) a zero key.
64 The KeyIndirect, ZeroKeyTerminates, and ReturnIndex options may be
67 glui32 git_linear_search(glui32 key, glui32 keysize,
68 glui32 start, glui32 structsize, glui32 numstructs,
69 glui32 keyoffset, glui32 options)
71 unsigned char keybuf[4];
74 int retindex = ((options & serop_ReturnIndex) != 0);
75 int zeroterm = ((options & serop_ZeroKeyTerminates) != 0);
77 fetchkey(keybuf, key, keysize, options);
79 for (count=0; count<numstructs; count++, start+=structsize) {
82 for (ix=0; match && ix<keysize; ix++) {
83 if (memRead8(start + keyoffset + ix) != keybuf[ix])
88 for (ix=0; match && ix<keysize; ix++) {
89 if (memRead8(start + keyoffset + ix) != memRead8(key + ix))
103 for (ix=0; match && ix<keysize; ix++) {
104 if (memRead8(start + keyoffset + ix) != 0)
120 An array of data structures is in memory, as above. However, the
121 structs must be stored in forward order of their keys (taking each key
122 to be a multibyte unsigned integer.) There can be no duplicate keys.
123 numstructs must indicate the exact length of the array; it cannot
126 The KeyIndirect and ReturnIndex options may be used.
128 glui32 git_binary_search(glui32 key, glui32 keysize,
129 glui32 start, glui32 structsize, glui32 numstructs,
130 glui32 keyoffset, glui32 options)
132 unsigned char keybuf[4];
133 unsigned char byte, byte2;
134 glui32 top, bot, val, addr;
136 int retindex = ((options & serop_ReturnIndex) != 0);
138 fetchkey(keybuf, key, keysize, options);
145 addr = start + val * structsize;
148 for (ix=0; (!cmp) && ix<keysize; ix++) {
149 byte = memRead8(addr + keyoffset + ix);
153 else if (byte > byte2)
158 for (ix=0; (!cmp) && ix<keysize; ix++) {
159 byte = memRead8(addr + keyoffset + ix);
160 byte2 = memRead8(key + ix);
163 else if (byte > byte2)
190 The structures may be anywhere in memory, in any order. They are
191 linked by a four-byte address field, which is found in each struct
192 at position nextoffset. If this field contains zero, it indicates
193 the end of the linked list.
195 The KeyIndirect and ZeroKeyTerminates options may be used.
197 glui32 git_linked_search(glui32 key, glui32 keysize,
198 glui32 start, glui32 keyoffset, glui32 nextoffset, glui32 options)
200 unsigned char keybuf[4];
203 int zeroterm = ((options & serop_ZeroKeyTerminates) != 0);
205 fetchkey(keybuf, key, keysize, options);
210 for (ix=0; match && ix<keysize; ix++) {
211 if (memRead8(start + keyoffset + ix) != keybuf[ix])
216 for (ix=0; match && ix<keysize; ix++) {
217 if (memRead8(start + keyoffset + ix) != memRead8(key + ix))
228 for (ix=0; match && ix<keysize; ix++) {
229 if (memRead8(start + keyoffset + ix) != 0)
237 val = start + nextoffset;
238 start = memRead32(val);
245 This massages the key into a form that's easier to handle. When it
246 returns, the key will be stored in keybuf if keysize <= 4; otherwise,
247 it will be in memory.
249 static void fetchkey(unsigned char *keybuf, glui32 key, glui32 keysize,
254 if (options & serop_KeyIndirect) {
256 for (ix=0; ix<keysize; ix++)
257 keybuf[ix] = memRead8(key+ix);
263 write32(keybuf, key);
266 write16(keybuf, key);
272 fatalError("Direct search key must hold one, two, or four bytes.");