1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /* Based on Glulx intrepreter version 0.5.4 */
24 
25 #ifndef GLK_GLULXE
26 #define GLK_GLULXE
27 
28 #include "common/scummsys.h"
29 #include "common/random.h"
30 #include "glk/glk_api.h"
31 #include "glk/glulx/glulx_types.h"
32 
33 namespace Glk {
34 namespace Glulx {
35 
36 class Glulx;
37 typedef void (Glulx::*CharHandler)(unsigned char);
38 typedef void (Glulx::*UnicharHandler)(uint32);
39 
40 /**
41  * Glulx game interpreter
42  */
43 class Glulx : public GlkAPI {
44 private:
45 	/**
46 	 * \defgroup vm fields
47 	 * @{
48 	 */
49 
50 	bool vm_exited_cleanly;
51 	uint gamefile_start, gamefile_len;
52 	UnicharHandler glkio_unichar_han_ptr;
53 	char *init_err, *init_err2;
54 	CharHandler stream_char_handler;
55 
56 	byte *memmap;
57 	byte *stack;
58 	UnicharHandler stream_unichar_handler;
59 
60 	uint ramstart;
61 	uint endgamefile;
62 	uint origendmem;
63 	uint stacksize;
64 	uint startfuncaddr;
65 	uint checksum;
66 	uint stackptr;
67 	uint frameptr;
68 	uint pc;
69 	uint origstringtable;
70 	uint stringtable;
71 	uint valstackbase;
72 	uint localsbase;
73 	uint endmem;
74 	uint protectstart, protectend;
75 	uint prevpc;
76 
77 	/**@}*/
78 
79 	/**
80 	 * \defgroup main fields
81 	 * @{
82 	 */
83 
84 	/**
85 	 * The library_autorestore_hook is called right after the VM's initial setup. This is an appropriate time
86 	 * to autorestore an initial game state, if the library has that capability. (Currently, only iosglk does.)
87 	 */
88 	void(*library_autorestore_hook)(void);
89 
90 	/**@}*/
91 
92 	/**
93 	 * \defgroup accel fields
94 	 * @{
95 	 */
96 
97 	uint classes_table;     ///< class object array
98 	uint indiv_prop_start;  ///< first individual prop ID
99 	uint class_metaclass;   ///< "Class" class object
100 	uint object_metaclass;  ///< "Object" class object
101 	uint routine_metaclass; ///< "Routine" class object
102 	uint string_metaclass;  ///< "String" class object
103 	uint self;              ///< address of global "self"
104 	uint num_attr_bytes;    ///< number of attributes / 8
105 	uint cpv__start;        ///< array of common prop defaults
106 	accelentry_t **accelentries;
107 
108 	/**@}*/
109 
110 	/**
111 	 * \defgroup heap fields
112 	 * @{
113 	 */
114 
115 	uint heap_start;    ///< zero for inactive heap
116 	int alloc_count;
117 
118 	/* The heap_head/heap_tail is a doubly-linked list of blocks, both
119 	   free and allocated. It is kept in address order. It should be
120 	   complete -- that is, the first block starts at heap_start, and each
121 	   block ends at the beginning of the next block, until the last one,
122 	   which ends at endmem.
123 
124 	   (Heap_start is never the same as end_mem; if there is no heap space,
125 	   then the heap is inactive and heap_start is zero.)
126 
127 	   Adjacent free blocks may be merged at heap_alloc() time.
128 
129 	   ### To make alloc more efficient, we could keep a separate
130 	   free-list. To make free more efficient, we could keep a hash
131 	   table of allocations.
132 	 */
133 	heapblock_t *heap_head;
134 	heapblock_t *heap_tail;
135 
136 	/**@}*/
137 
138 	/**
139 	 * \defgroup operand fields
140 	 * @{
141 	 */
142 
143 	/**
144 	 * This is a handy array in which to look up operandlists quickly. It stores the operandlists
145 	 * for the first 128 opcodes, which are the ones used most frequently.
146 	 */
147 	const operandlist_t *fast_operandlist[0x80];
148 
149 	/**@}*/
150 
151 	/**
152 	 * \defgroup serial fields
153 	 * @{
154 	 */
155 
156 	/**
157 	 * This can be adjusted before startup by platform-specific startup code -- that is, preference code.
158 	 */
159 	int max_undo_level;
160 
161 	int undo_chain_size;
162 	int undo_chain_num;
163 	byte **undo_chain;
164 
165 	/**
166 	 * This will contain a copy of RAM (ramstate to endmem) as it exists in the game file.
167 	 */
168 	byte *ramcache;
169 
170 	/**@}*/
171 
172 	/**
173 	 * \defgroup string fields
174 	 * @{
175 	 */
176 
177 	uint iosys_mode;
178 	uint iosys_rock;
179 
180 	/**
181 	 * The current string-decoding tables, broken out into a fast and easy-to-use form.
182 	 */
183 	bool tablecache_valid;
184 	cacheblock_t tablecache;
185 
186 	/* This misbehaves if a Glk function has more than one S argument. */
187 #define STATIC_TEMP_BUFSIZE (127)
188 	char temp_buf[STATIC_TEMP_BUFSIZE + 1];
189 
190 	/**@}*/
191 
192 	Common::String _savegameDescription;
193 protected:
194 	/**
195 	 * \defgroup glkop fields
196 	 * @{
197 	 */
198 
199 	/**
200 	 * The library_select_hook is called every time the VM blocks for input.
201 	 * The app might take this opportunity to autosave, for example.
202 	 */
203 	void (*library_select_hook)(uint);
204 
205 	arrayref_t *arrays;
206 
207 	/**
208 	 * The list of hash tables, for the classes.
209 	 */
210 	int num_classes;
211 	classtable_t **classes;
212 
213 	/**@}*/
214 
215 	/**
216 	 * \defgroup accel support methods
217 	 * @{
218 	 */
219 
220 	void accel_error(const char *msg);
221 	uint func_1_z__region(uint argc, uint *argv);
222 
223 	/**
224 	 * The old set of accel functions (2 through 7) are deprecated; they behave badly if the Inform 6
225 	 * NUM_ATTR_BYTES option (parameter 7) is changed from its default value (7). They will not be removed,
226 	 * but new games should use functions 8 through 13 instead
227 	 */
228 	uint func_2_cp__tab(uint argc, uint *argv);
229 	uint func_3_ra__pr(uint argc, uint *argv);
230 	uint func_4_rl__pr(uint argc, uint *argv);
231 	uint func_5_oc__cl(uint argc, uint *argv);
232 	uint func_6_rv__pr(uint argc, uint *argv);
233 	uint func_7_op__pr(uint argc, uint *argv);
234 
235 	/**
236 	 * Here are the newer functions, which support changing NUM_ATTR_BYTES.
237 	   These call get_prop_new() instead of get_prop()
238 	 */
239 	uint func_8_cp__tab(uint argc, uint *argv);
240 	uint func_9_ra__pr(uint argc, uint *argv);
241 	uint func_10_rl__pr(uint argc, uint *argv);
242 	uint func_11_oc__cl(uint argc, uint *argv);
243 	uint func_12_rv__pr(uint argc, uint *argv);
244 	uint func_13_op__pr(uint argc, uint *argv);
245 	int obj_in_class(uint obj);
246 
247 	/**
248 	 * Look up a property entry.
249 	 */
250 	uint get_prop(uint obj, uint id);
251 
252 	/**
253 	 * Look up a property entry. This is part of the newer set of accel functions (8 through 13),
254 	 * which support increasing NUM_ATTR_BYTES. It is identical to get_prop() except that it calls
255 	 * the new versions of func_5 and func_2
256 	 */
257 	uint get_prop_new(uint obj, uint id);
258 
259 	/**@}*/
260 
261 	/**
262 	 * \defgroup glkop support methods
263 	 * @{
264 	 */
265 
266 	/**
267 	 * Build a hash table to hold a set of Glk objects.
268 	 */
269 	classtable_t *new_classtable(uint firstid);
270 
271 	/**
272 	 * Find a Glk object in the appropriate hash table.
273 	 */
274 	void *classes_get(int classid, uint objid);
275 
276 	/**
277 	 * Put a Glk object in the appropriate hash table. If origid is zero, invent a new
278 	 * unique ID for it.
279 	 */
280 	classref_t *classes_put(int classid, void *obj, uint origid);
281 
282 	/**
283 	 * Delete a Glk object from the appropriate hash table.
284 	 */
285 	void classes_remove(int classid, void *obj);
286 
287 	long glulxe_array_locate(void *array, uint len, char *typecode, gidispatch_rock_t objrock, int *elemsizeref);
288 	gidispatch_rock_t glulxe_array_restore(long bufkey, uint len, char *typecode, void **arrayref);
289 
290 	char *grab_temp_c_array(uint addr, uint len, int passin);
291 	void release_temp_c_array(char *arr, uint addr, uint len, int passout);
292 	uint *grab_temp_i_array(uint addr, uint len, int passin);
293 	void release_temp_i_array(uint *arr, uint addr, uint len, int passout);
294 	void **grab_temp_ptr_array(uint addr, uint len, int objclass, int passin);
295 	void release_temp_ptr_array(void **arr, uint addr, uint len, int objclass, int passout);
296 
297 	/**
298 	 * This reads through the prototype string, and pulls Floo objects off the stack. It also works out the maximal number
299 	 * of gluniversal_t objects which could be used by the Glk call in question. It then allocates space for them.
300 	 */
301 	void prepare_glk_args(const char *proto, dispatch_splot_t *splot);
302 
303 	/**
304 	 * This long and unpleasant function translates a set of Floo objects into a gluniversal_t array. It's recursive, too,
305 	 * to deal with structures.
306 	 */
307 	void parse_glk_args(dispatch_splot_t *splot, const char **proto, int depth, int *argnumptr, uint subaddress, int subpassin);
308 
309 	/**
310 	 * This is about the reverse of parse_glk_args().
311 	 */
312 	void unparse_glk_args(dispatch_splot_t *splot, const char **proto, int depth,
313 	                      int *argnumptr, uint subaddress, int subpassout);
314 
315 	/**
316 	 * Create a string identifying this game. We use the first 64 bytes of the memory map, encoded as hex,
317 	 */
318 	char *get_game_id();
319 
320 	uint ReadMemory(uint addr);
321 	void WriteMemory(uint addr, uint val);
322 	char *CaptureCArray(uint addr, uint len, int passin);
323 	void ReleaseCArray(char *ptr, uint addr, uint len, int passout);
324 	uint *CaptureIArray(uint addr, uint len, int passin);
325 	void ReleaseIArray(uint *ptr, uint addr, uint len, int passout);
326 	void **CapturePtrArray(uint addr, uint len, int objclass, int passin);
327 	void ReleasePtrArray(void **ptr, uint addr, uint len, int objclass, int passout);
328 	uint ReadStructField(uint addr, uint fieldnum);
329 	void WriteStructField(uint addr, uint fieldnum, uint val);
330 	char *DecodeVMString(uint addr);
331 	void ReleaseVMString(char *ptr);
332 	uint32 *DecodeVMUstring(uint addr);
333 	void ReleaseVMUstring(uint32 *ptr);
334 
335 	/**@}*/
336 
337 	/**
338 	 * \defgroup search support methods
339 	 * @{
340 	 */
341 
342 	/**
343 	 * This massages the key into a form that's easier to handle. When it returns, the key will
344 	 * be stored in keybuf if keysize <= 4; otherwise, it will be in memory.
345 	 */
346 	void fetchkey(unsigned char *keybuf, uint key, uint keysize, uint options);
347 
348 	/**@}*/
349 
350 	/**
351 	 * \defgroup serial support methods
352 	 * @{
353 	 */
354 
355 	uint write_memstate(dest_t *dest);
356 	uint write_heapstate(dest_t *dest, int portable);
357 	uint write_stackstate(dest_t *dest, int portable);
358 	uint read_memstate(dest_t *dest, uint chunklen);
359 	uint read_heapstate(dest_t *dest, uint chunklen, int portable, uint *sumlen, uint **summary);
360 	uint read_stackstate(dest_t *dest, uint chunklen, int portable);
361 	uint write_heapstate_sub(uint sumlen, uint *sumarray, dest_t *dest, int portable);
362 	static int sort_heap_summary(const void *p1, const void *p2);
363 
364 	int read_byte(dest_t *dest, byte *val);
365 	int read_short(dest_t *dest, uint16 *val);
366 	int read_long(dest_t *dest, uint *val);
367 
368 	int write_byte(dest_t *dest, byte val);
369 	int write_short(dest_t *dest, uint16 val);
370 	int write_long(dest_t *dest, uint val);
371 
372 	int read_buffer(dest_t *dest, byte *ptr, uint len);
373 	int reposition_write(dest_t *dest, uint pos);
374 	int write_buffer(dest_t *dest, const byte *ptr, uint len);
375 
376 	/**@}*/
377 
378 	/**
379 	 * \defgroup string support methods
380 	 * @{
381 	 */
382 
383 	void stream_setup_unichar();
384 
385 	void nopio_char_han(unsigned char ch);
386 	void filio_char_han(unsigned char ch);
387 	void nopio_unichar_han(uint32 ch);
388 	void filio_unichar_han(uint32 ch);
389 	void glkio_unichar_nouni_han(uint32 val);
390 
391 	void dropcache(cacheblock_t *cablist);
392 	void buildcache(cacheblock_t *cablist, uint nodeaddr, int depth, int mask);
393 	void dumpcache(cacheblock_t *cablist, int count, int indent);
394 
395 	/**@}*/
396 public:
397 	/**
398 	 * Constructor
399 	 */
400 	Glulx(OSystem *syst, const GlkGameDescription &gameDesc);
401 
402 	/**
403 	 * Run the game
404 	 */
405 	void runGame() override;
406 
407 	/**
408 	 * Returns the running interpreter type
409 	 */
getInterpreterType()410 	InterpreterType getInterpreterType() const override {
411 		return INTERPRETER_GLULX;
412 	}
413 
414 	/**
415 	 * Loads Quetzal chunks from the passed savegame
416 	 */
417 	Common::Error loadGameChunks(QuetzalReader &quetzal) override;
418 
419 	/**
420 	 * Writes out the Quetzal chunks within a savegame
421 	 */
422 	Common::Error saveGameChunks(QuetzalWriter &quetzal) override;
423 
424 	/**
425 	 * Load a savegame from the passed Quetzal file chunk stream
426 	 */
427 	Common::Error readSaveData(Common::SeekableReadStream *rs) override;
428 
429 	/**
430 	 * Save the game. The passed write stream represents access to the UMem chunk
431 	 * in the Quetzal save file that will be created
432 	 */
433 	Common::Error writeGameData(Common::WriteStream *ws) override;
434 
435 	/**
436 	 * \defgroup Main access methods
437 	 * @{
438 	 */
439 
440 	/**
441 	 * Display an error in the error window, and then exit.
442 	 */
443 	void NORETURN_PRE fatal_error_handler(const char *str, const char *arg, bool useVal, int val);
444 
445 	/**
446 	 * Display a warning in the error window, and then continue.
447 	 */
448 	void nonfatal_warning_handler(const char *str, const char *arg, bool useVal, int val);
449 
450 	/**
451 	 * \defgroup Files access methods
452 	 * @{
453 	 */
454 
455 	/**
456 	 * Validates the game file, and if it's invalid, displays an error dialog
457 	 */
458 	bool is_gamefile_valid();
459 
460 	/**@}*/
461 
462 	/**
463 	 * \defgroup Vm access methods
464 	 * @{
465 	 */
466 
467 	/**
468 	 * Read in the game file and build the machine, allocating all the memory necessary.
469 	*/
470 	void setup_vm();
471 
472 	/**
473 	 * Deallocate all the memory and shut down the machine.
474 	 */
475 	void finalize_vm();
476 
477 	/**
478 	 * Put the VM into a state where it's ready to begin executing the game. This is called
479 	 * both at startup time, and when the machine performs a "restart" opcode.
480 	 */
481 	void vm_restart();
482 
483 	/**
484 	 * Change the size of the memory map. This may not be available at all; #define FIXED_MEMSIZE
485 	 * if you want the interpreter to unconditionally refuse. The internal flag should be true only
486 	 * when the heap-allocation system is calling. Returns 0 for success; otherwise, the operation failed.
487 	 */
488 	uint change_memsize(uint newlen, bool internal);
489 
490 	/**
491 	 * If addr is 0, pop N arguments off the stack, and put them in an array. If non-0, take N arguments
492 	 * from that main memory address instead. This has to dynamically allocate if there are more than
493 	 * 32 arguments, but that shouldn't be a problem.
494 	 */
495 	uint *pop_arguments(uint count, uint addr);
496 
497 	/**
498 	 * Make sure that count bytes beginning with addr all fall within the current memory map.
499 	 * This is called at every memory (read) access if VERIFY_MEMORY_ACCESS is defined in the header file.
500 	*/
501 	void verify_address(uint addr, uint count);
502 
503 	/**
504 	 * Make sure that count bytes beginning with addr all fall within RAM. This is called at every memory
505 	 * write if VERIFY_MEMORY_ACCESS is defined in the header file.
506 	*/
507 	void verify_address_write(uint addr, uint count);
508 
509 	/**
510 	 * Make sure that an array of count elements (size bytes each), starting at addr, does not fall
511 	 * outside the memory map. This goes to some trouble that verify_address() does not, because we need
512 	 * to be wary of lengths near -- or beyond -- 0x7FFFFFFF.
513 	 */
514 	void verify_array_addresses(uint addr, uint count, uint size);
515 
516 	/**@}*/
517 
518 	/**
519 	 * \defgroup Exec access methods
520 	 * @{
521 	 */
522 
523 	/**
524 	 * The main interpreter loop. This repeats until the program is done
525 	 */
526 	void execute_loop();
527 
528 	/**@}*/
529 
530 	/**
531 	 * \defgroup Operand access methods
532 	 * @{
533 	 */
534 
535 	/**
536 	 * Set up the fast-lookup array of operandlists. This is called just once, when the terp starts up.
537 	 */
538 	void init_operands();
539 
540 	/**
541 	 * Return the operandlist for a given opcode. For opcodes in the range 00..7F, it's faster
542 	 * to use the array fast_operandlist[].
543 	*/
544 	const operandlist_t *lookup_operandlist(uint opcode);
545 
546 	/**
547 	 * Read the list of operands of an instruction, and put the values in args. This assumes
548 	 * that the PC is at the beginning of the operand mode list (right after an opcode number.)
549 	 * Upon return, the PC will be at the beginning of the next instruction.
550 	 *
551 	 * This also assumes that args points at an allocated array of MAX_OPERANDS oparg_t structures.
552 	*/
553 	void parse_operands(oparg_t *opargs, const operandlist_t *oplist);
554 
555 	/**
556 	 * Store a result value, according to the desttype and destaddress given. This is usually used to store
557 	 * the result of an opcode, but it's also used by any code that pulls a call-stub off the stack.
558 	 */
559 	void store_operand(uint desttype, uint destaddr, uint storeval);
560 
561 	void store_operand_s(uint desttype, uint destaddr, uint storeval);
562 	void store_operand_b(uint desttype, uint destaddr, uint storeval);
563 
564 	/**@}*/
565 
566 	/**
567 	 * \defgroup Func access methods
568 	 * @{
569 	 */
570 
571 	/**
572 	 * This writes a new call frame onto the stack, at stackptr. It leaves frameptr pointing
573 	 * to the frame (ie, the original stackptr value.) argc and argv are an array of arguments.
574 	 * Note that if argc is zero, argv may be nullptr.
575 	 */
576 	void enter_function(uint addr, uint argc, uint *argv);
577 
578 	/**
579 	 * Pop the current call frame off the stack. This is very simple.
580 	*/
581 	void leave_function();
582 
583 	/**
584 	 * Push the magic four values on the stack: result destination, PC, and frameptr.
585 	 */
586 	void push_callstub(uint desttype, uint destaddr);
587 
588 	/**
589 	 * Remove the magic four values from the stack, and use them. The returnvalue, whatever it is,
590 	 * is put at the result destination; the PC and frameptr registers are set.
591 	*/
592 	void pop_callstub(uint returnvalue);
593 
594 	/**
595 	 * Remove the magic four values, but interpret them as a string restart state.
596 	 * Returns zero if it's a termination stub, or returns the restart address. The bitnum is extra.
597 	 */
598 	uint pop_callstub_string(int *bitnum);
599 
600 	/**@}*/
601 
602 	/**
603 	 * \defgroup Heap access methods
604 	 * @{
605 	 */
606 
607 	/**
608 	 * Set the heap state to inactive, and free the block lists. This is called when the game
609 	 * starts or restarts.
610 	 */
611 	void heap_clear();
612 
613 	/**
614 	 * Returns whether the heap is active.
615 	 */
616 	int heap_is_active() const;
617 
618 	/**
619 	 * Returns the start address of the heap, or 0 if the heap is not active.
620 	 */
621 	uint heap_get_start() const;
622 
623 	/**
624 	 * Allocate a block. If necessary, activate the heap and/or extend memory. This may not be
625 	 * available at all; #define FIXED_MEMSIZE if you want the interpreter to unconditionally refuse.
626 	 * Returns the memory address of the block, or 0 if the operation failed.
627 	 */
628 	uint heap_alloc(uint len);
629 
630 	/**
631 	 * Free a heap block. If necessary, deactivate the heap.
632 	 */
633 	void heap_free(uint addr);
634 
635 	/**
636 	 * Create an array of words, in the VM serialization format:
637 	 *
638 	 *   heap_start
639 	 *   alloc_count
640 	 *   addr of first block
641 	 *   len of first block
642 	 *   ...
643 	 *
644 	 * (Note that these are uint values -- native byte ordering. Also, the blocks will be in address order,
645 	 * which is a stricter guarantee than the VM specifies; that'll help in heap_apply_summary().)
646 	 *
647 	 * If the heap is inactive, store nullptr. Return 0 for success; otherwise, the operation failed.
648 	 *
649 	 * The array returned in summary must be freed with glulx_free() after the caller uses it.
650 	 */
651 	int heap_get_summary(uint *valcount, uint **summary);
652 
653 	/**
654 	 * Given an array of words in the above format, set up the heap to contain it. As noted above,
655 	 * the caller must ensure that the blocks are in address order. When this is called, the heap
656 	 * must be inactive.
657 	 *
658 	 * Return 0 for success. Otherwise the operation failed (and, most likely, caused a fatal error).
659 	*/
660 	int heap_apply_summary(uint valcount, uint *summary);
661 
662 	/**@}*/
663 
664 	/**
665 	 * \defgroup Serial access methods
666 	 * @{
667 	 */
668 
669 	/**@}*/
670 
671 	/**
672 	 * \defgroup Search access methods
673 	 * @{
674 	 */
675 
676 
677 	/**
678 	 * An array of data structures is stored in memory, beginning at start, each structure being structsize bytes.
679 	 * Within each struct, there is a key value keysize bytes long, starting at position keyoffset (from
680 	 * the start of the structure.) Search through these in order. If one is found whose key matches, return it.
681 	 * If numstructs are searched with no result, return nullptr.
682 	 *
683 	 * numstructs may be -1 (0xFFFFFFFF) to indicate no upper limit to the number of structures to search.
684 	 * The search will continue until a match is found, or (if ZeroKeyTerminates is set) a zero key.
685 	 *
686 	 * The KeyIndirect, ZeroKeyTerminates, and ReturnIndex options may be used.
687 	 */
688 	uint linear_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
689 	                   uint keyoffset, uint options);
690 
691 	/**
692 	 * An array of data structures is in memory, as above. However, the structs must be stored in forward
693 	 * order of their keys (taking each key to be a multibyte unsigned integer.) There can be no duplicate keys.
694 	 * numstructs must indicate the exact length of the array; it cannot be -1.
695 	 *
696 	 * The KeyIndirect and ReturnIndex options may be used.
697 	 */
698 	uint binary_search(uint key, uint keysize, uint start, uint structsize, uint numstructs,
699 	                   uint keyoffset, uint options);
700 
701 	/**
702 	 * The structures may be anywhere in memory, in any order. They are linked by a four-byte address field,
703 	 * which is found in each struct at position nextoffset. If this field contains zero, it indicates
704 	 * the end of the linked list.
705 	 *
706 	 * The KeyIndirect and ZeroKeyTerminates options may be used.
707 	 */
708 	uint linked_search(uint key, uint keysize, uint start, uint keyoffset, uint nextoffset, uint options);
709 
710 	/**@}*/
711 
712 	/**
713 	 * \defgroup Osdepend access methods
714 	 * @{
715 	 */
716 
glulx_malloc(uint len)717 	inline void *glulx_malloc(uint len) {
718 		return malloc(len);
719 	}
glulx_realloc(void * ptr,uint len)720 	inline void *glulx_realloc(void *ptr, uint len) {
721 		return realloc(ptr, len);
722 	}
glulx_free(void * ptr)723 	inline void glulx_free(void *ptr) {
724 		free(ptr);
725 	}
glulx_setrandom(uint32 seed)726 	inline void glulx_setrandom(uint32 seed) {
727 		_random.setSeed(seed);
728 	}
glulx_random()729 	inline uint glulx_random() {
730 		return _random.getRandomNumber(0xfffffff);
731 	}
732 
733 	void glulx_sort(void *addr, int count, int size, int(*comparefunc)(const void *p1, const void *p2));
734 
735 	/**@}*/
736 
737 	/**
738 	 * \defgroup Gestalt access methods
739 	 * @{
740 	 */
741 
742 	uint do_gestalt(uint val, uint val2);
743 
744 	/**@}*/
745 
746 	/**
747 	 * \defgroup Glkop access methods
748 	 * @{
749 	 */
750 
751 	/**
752 	 * glkop section initialization
753 	 */
754 	void glkopInit();
755 
756 	void set_library_select_hook(void(*func)(uint));
757 
758 	/**
759 	 * Set up the class hash tables and other startup-time stuff.
760 	 */
761 	bool init_dispatch();
762 
763 	/**
764 	 * The object registration/unregistration callbacks that the library calls
765 	 * to keep the hash tables up to date.
766 	 */
767 	gidispatch_rock_t glulxe_classtable_register(void *obj, uint objclass);
768 
769 	gidispatch_rock_t glulxe_classtable_register_existing(void *obj, uint objclass, uint dispid);
770 
771 	void glulxe_classtable_unregister(void *obj, uint objclass, gidispatch_rock_t objrock);
772 
773 	gidispatch_rock_t glulxe_retained_register(void *array, uint len, const char *typecode);
774 	void glulxe_retained_unregister(void *array, uint len, const char *typecode, gidispatch_rock_t objrock);
775 
776 	/**
777 	 * Turn a list of Glulx arguments into a list of Glk arguments, dispatch the function call, and return the result.
778 	 */
779 	uint perform_glk(uint funcnum, uint numargs, uint *arglist);
780 
781 	/**
782 	 * Read the prefixes of an argument string -- the "<>&+:#!" chars.
783 	 */
784 	const char *read_prefix(const char *cx, int *isref, int *isarray, int *passin, int *passout,
785 	                        int *nullok, int *isretained, int *isreturn);
786 
787 	/**
788 	 * This is used by some interpreter code which has to, well, find a Glk stream given its ID.
789 	 */
790 	strid_t find_stream_by_id(uint objid);
791 
792 	/**
793 	 * Return the ID of a given Glk window.
794 	 */
795 	uint find_id_for_window(winid_t win);
796 
797 	/**
798 	 * Return the ID of a given Glk stream.
799 	 */
800 	uint find_id_for_stream(strid_t str);
801 
802 	/**
803 	 * Return the ID of a given Glk fileref.
804 	 */
805 	uint find_id_for_fileref(frefid_t fref);
806 
807 	/**
808 	 * Return the ID of a given Glk schannel.
809 	 */
810 	uint find_id_for_schannel(schanid_t schan);
811 
812 	/**@}*/
813 
814 	/**
815 	 * \defgroup Profile access methods
816 	 * @{
817 	 */
818 
819 	void setup_profile(strid_t stream, char *filename);
820 	int init_profile();
821 	void profile_set_call_counts(int flag);
822 
823 	#if VM_PROFILING
824 	uint profile_opcount;
825 	#define profile_tick() (profile_opcount++)
826 	int profile_profiling_active();
827 	void profile_in(uint addr, uint stackuse, int accel);
828 	void profile_out(uint stackuse);
829 	void profile_fail(const char *reason);
830 	void profile_quit();
831 	#else /* VM_PROFILING */
profile_tick()832 	void profile_tick() {}
profile_profiling_active()833 	void profile_profiling_active() {}
profile_in(uint addr,uint stackuse,int accel)834 	void profile_in(uint addr, uint stackuse, int accel) {}
profile_out(uint stackuse)835 	void profile_out(uint stackuse)  {}
profile_fail(const char * reason)836 	void profile_fail(const char *reason) {}
profile_quit()837 	void profile_quit() {}
838 	#endif /* VM_PROFILING */
839 
840 #if VM_DEBUGGER
841 	unsigned long debugger_opcount;
debugger_tick()842 	void debugger_tick() { debugger_opcount++ }
843 	int debugger_load_info_stream(strid_t stream);
844 	int debugger_load_info_chunk(strid_t stream, uint pos, uint len);
845 	void debugger_track_cpu(int flag);
846 	void debugger_set_start_trap(int flag);
847 	void debugger_set_quit_trap(int flag);
848 	void debugger_set_crash_trap(int flag);
849 	void debugger_check_story_file();
850 	void debugger_setup_start_state();
851 	int debugger_ever_invoked();
852 	int debugger_cmd_handler(char *cmd);
853 	void debugger_cycle_handler(int cycle);
854 	void debugger_check_func_breakpoint(uint addr);
855 	void debugger_block_and_debug(char *msg);
856 	void debugger_handle_crash(char *msg);
857 	void debugger_handle_quit();
858 #else /* VM_DEBUGGER */
debugger_tick()859 	void debugger_tick() {}
debugger_check_story_file()860 	void debugger_check_story_file() {}
debugger_setup_start_state()861 	void debugger_setup_start_state() {}
debugger_check_func_breakpoint(uint addr)862 	void debugger_check_func_breakpoint(uint addr) {}
debugger_handle_crash(const char * msg)863 	void debugger_handle_crash(const char *msg) {}
864 #endif /* VM_DEBUGGER */
865 
866 	/**@}*/
867 
868 	/**
869 	 * \defgroup Accel access methods
870 	 * @{
871 	 */
872 
873 	acceleration_func accel_find_func(uint index);
874 	acceleration_func accel_get_func(uint addr);
875 	void accel_set_func(uint index, uint addr);
876 	void accel_set_param(uint index, uint val);
877 
878 	uint accel_get_param_count() const;
879 	uint accel_get_param(uint index) const;
880 
881 	/**
882 	 * Iterate the entire acceleration table, calling the callback for each (non-nullptr) entry.
883 	 * This is used only for autosave.
884 	 */
885 	void accel_iterate_funcs(void(*func)(uint index, uint addr));
886 
887 	/**@}*/
888 
889 	/**
890 	 * \defgroup Float access methods
891 	 * @{
892 	 */
893 #ifdef FLOAT_SUPPORT
894 
895 	/* Uncomment this definition if your gfloat32 type is not a standard
896 	   IEEE-754 single-precision (32-bit) format. Normally, Glulx assumes
897 	   that it can reinterpret-cast IEEE-754 int values into gfloat32
898 	   values. If you uncomment this, Glulx switches to lengthier
899 	   (but safer) encoding and decoding functions. */
900 	/* #define FLOAT_NOT_NATIVE (1) */
901 
init_float()902 	int init_float() {
903 		return true;
904 	}
905 
906 	/**
907 	 * Encode floats by a lot of annoying bit manipulation.
908 	 * The function is adapted from code in Python  (Objects/floatobject.c)
909 	 */
910 	static uint encode_float(gfloat32 val);
911 
912 	/**
913 	 * Decode floats by a lot of annoying bit manipulation.
914 	 * The function is adapted from code in Python  (Objects/floatobject.c)
915 	 */
916 	static gfloat32 decode_float(uint val);
917 
918 	/* Uncomment this definition if your powf() function does not support
919 	   all the corner cases specified by C99. If you uncomment this,
920 	   osdepend.c will provide a safer implementation of glulx_powf(). */
921 	/* #define FLOAT_COMPILE_SAFER_POWF (1) */
922 
glulx_powf(gfloat32 val1,gfloat32 val2)923 	inline gfloat32 glulx_powf(gfloat32 val1, gfloat32 val2) const {
924 		return powf(val1, val2);
925 	}
926 
927 #endif /* FLOAT_SUPPORT */
928 	/**@}*/
929 
930 	/**
931 	 * \defgroup serial access methods
932 	 * @{
933 	 */
934 
935 	/**
936 	 * Set up the undo chain and anything else that needs to be set up.
937 	 */
938 	bool init_serial();
939 
940 	/**
941 	 * Clean up memory when the VM shuts down.
942 	 */
943 	void final_serial();
944 
945 	/**
946 	 * Add a state pointer to the undo chain. This returns 0 on success, 1 on failure.
947 	 */
948 	uint perform_saveundo();
949 
950 	/**
951 	 * Pull a state pointer from the undo chain. This returns 0 on success, 1 on failure.
952 	 * Note that if it succeeds, the frameptr, localsbase, and valstackbase registers are invalid;
953 	 * they must be rebuilt from the stack.
954 	 */
955 	uint perform_restoreundo();
956 
957 	uint perform_verify();
958 
959 	/**@}*/
960 
961 	/**
962 	 * \defgroup Strings access methods
963 	 * @{
964 	 */
965 
966 	/**
967 	 * Write a signed integer to the current output stream.
968 	 */
969 	void stream_num(int val, int inmiddle, int charnum);
970 
971 	/**
972 	 * Write a Glulx string object to the current output stream. inmiddle is zero if we are beginning
973 	 * a new string, or nonzero if restarting one (E0/E1/E2, as appropriate for the string type).
974 	 */
975 	void stream_string(uint addr, int inmiddle, int bitnum);
976 
977 	/**
978 	 * Get the current table address.
979 	 */
980 	uint stream_get_table();
981 
982 	/**
983 	 * Set the current table address, and rebuild decoding cache.
984 	 */
985 	void stream_set_table(uint addr);
986 
987 	void stream_get_iosys(uint *mode, uint *rock);
988 	void stream_set_iosys(uint mode, uint rock);
989 	char *make_temp_string(uint addr);
990 	uint32 *make_temp_ustring(uint addr);
991 	void free_temp_string(char *str);
992 	void free_temp_ustring(uint32 *str);
993 
994 	/**@}*/
995 };
996 
997 extern Glulx *g_vm;
998 
999 #define fatal_error(s)  (fatal_error_handler((s), nullptr, false, 0))
1000 #define fatal_error_2(s1, s2)  (fatal_error_handler((s1), (s2), false, 0))
1001 #define fatal_error_i(s, v)  (fatal_error_handler((s), nullptr, true, (v)))
1002 #define nonfatal_warning(s) (nonfatal_warning_handler((s), nullptr, false, 0))
1003 #define nonfatal_warning_2(s1, s2) (nonfatal_warning_handler((s1), (s2), false, 0))
1004 #define nonfatal_warning_i(s, v) (nonfatal_warning_handler((s), nullptr, true, (v)))
1005 
1006 } // End of namespace Glulx
1007 } // End of namespace Glk
1008 
1009 #endif
1010