1 /*
2  *  A Z-Machine
3  *  Copyright (C) 2000 Andrew Hunter
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library 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 GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 /*
21  * Data types that describe the Z-Machine
22  */
23 
24 #ifndef __ZMACHINE_H
25 #define __ZMACHINE_H
26 
27 #include <stdio.h>
28 
29 #include "ztypes.h"
30 #include "hash.h"
31 #include "file.h"
32 #include "display.h"
33 #include "blorb.h"
34 
35 /*
36  * You can #define the following definitions to alter how your version
37  * of Zoom is compiled.
38  *
39  * DEBUG does produce rather a lot of debugging information (~15Mb
40  * from advent.z5, just to open the grate...). However, if you know
41  * what you're doing, you may find this useful to fix problems in your
42  * games (or locate problems in Zoom)
43  *
44  * Undefining SAFE will turn off bounds checking in any operations
45  * that use it.
46  *
47  * GLOBAL_PC will make the program counter be stored in a global
48  * variable - this creates a very slight slowdown, but means warnings
49  * and errors can give the PC that they occured at
50  *
51  * CAN_UNDO means that the undo commands are supported
52  *
53  * SQUEEZEUNDO will cause the undo buffer to be compressed (which is slow)
54  *
55  * SPEC_10 will cause the interpreter to indicate that it is
56  * conformant to the v1.0 specification.
57  *
58  * GRAPHICAL causes the interpreter to run version 5 games in
59  * 'graphical' mode. Beyond Zork supports this, Inform games do
60  * not. The v1.0 specification indicates that you shouldn't do this,
61  * but games that do not support this mode do not have the 'pictures'
62  * bit set, Beyond Zork being the only v5 game that I know of that has
63  * this bit set. This doesn't actually do a lot any more.
64  */
65 
66 #undef  DEBUG        /* Lots of debugging crap */
67 #define SAFE         /* Perform more bounds checking */
68 #undef  PAGED_MEMORY /* Not implemented, anyway ;-) */
69 #define GLOBAL_PC    /* Set to make the program counter global */
70 #define CAN_UNDO     /* Support the undo commands */
71 #define UNDO_LEVEL 5 /* Number of levels of undo that we support */
72 #undef  SQUEEZEUNDO  /* Store undo information in a compressed format (slow) */
73 #undef  TRACKING     /* Enable object tracking options */
74 #define SPEC_10      /*
75 		      * Unset if you don`t believe me when I say this
76                       * interpreter is conformant to the ZMachine
77 		      * specification v1.0
78 		      */
79 #define SPEC_11      /* Define to implement spec 1.1 (draft 6) */
80 #undef  GRAPHICAL    /*
81 		      * Define to set the default behaviour to mimic
82 		      * that of the Beyond Zork interpreter
83 		      */
84 #define V6ASSERT     /*
85 		      * Performs sanity checks to ensure that non-v6
86 		      * display functions are not called from a v6 game
87 		      */
88 #undef  CUTE_STARTUP /* 'Adventure-style' warranty message */
89 
90 #ifndef REMOTE_BREAKPOINT
91 #undef REMOTE_BREAKPOINT /* Send SIGUSR1 to force a breakpoint at the next execution point */
92 #endif
93 
94 /*
95  * Versions to support (note that support for version 5 includes
96  * support for versions 7 and 8 as well
97  */
98 #define SUPPORT_VERSION_3
99 #define SUPPORT_VERSION_4
100 #define SUPPORT_VERSION_5
101 #define SUPPORT_VERSION_6
102 
103 /* File format */
104 
105 enum ZHeader_bytes
106 {
107   ZH_version   = 0x00,
108   ZH_flags,
109   ZH_release   = 0x02,
110   ZH_base_high = 0x04,
111   ZH_initpc    = 0x06,
112   ZH_dict      = 0x08,
113   ZH_objs      = 0x0a,
114   ZH_globals   = 0x0c,
115   ZH_static    = 0x0e,
116   ZH_flags2    = 0x10,
117   ZH_serial    = 0x12,
118   ZH_abbrevs   = 0x18,
119   ZH_filelen   = 0x1a,
120   ZH_checksum  = 0x1c,
121   ZH_intnumber = 0x1e,
122   ZH_intvers,
123   ZH_lines,
124   ZH_columns,
125   ZH_width         = 0x22,
126   ZH_height        = 0x24,
127   ZH_fontwidth     = 0x26, /* height in v6 */
128   ZH_fontheight,           /* width in v6 */
129   ZH_routines,
130   ZH_staticstrings = 0x2a,
131   ZH_defback       = 0x2c,
132   ZH_deffore,
133   ZH_termtable,
134   ZH_widthos3      = 0x30,
135   ZH_revnumber     = 0x32,
136   ZH_alphatable    = 0x34,
137   ZH_extntable     = 0x36
138 };
139 
140 enum ZHEB_bytes
141 {
142   ZHEB_len      = 0,
143   ZHEB_xmouse   = 2,
144   ZHEB_ymouse   = 4,
145   ZHEB_unitable = 6,
146   ZHEB_flags3   = 8,
147   ZHEB_truefore = 10,
148   ZHEB_trueback = 12
149 };
150 
151 /* Internal data structures */
152 
153 typedef struct ZMap
154 {
155   ZDWord  actual_size;
156   ZByte*  mapped_pages;
157   ZByte** pages;
158 } ZMap;
159 
160 struct ZStack;
161 
162 typedef struct ZArgblock
163 {
164   int n_args;
165   ZWord arg[8];
166 } ZArgblock;
167 
168 typedef struct ZFrame
169 {
170   /* Return address */
171   ZDWord ret;
172 
173   ZByte  nlocals;    /* Number of locals */
174   ZByte  flags;      /* Arguments supplied */
175   ZByte  storevar;   /* Variable to store result in on return */
176   ZByte  discard;    /* Nonzero if result should be discarded */
177 
178   ZWord  frame_size; /* Evaluation size */
179 
180   ZWord  local[16];
181   ZUWord frame_num;
182 
183   int break_on_return; /* Used by the debugger */
184 
185   void (*v4read)(ZDWord*, struct ZStack*, ZArgblock*);
186   void (*v5read)(ZDWord*, struct ZStack*, ZArgblock*, int);
187   int  end_func;
188   ZArgblock readblock;
189   int       readstore;
190 
191   struct ZFrame* last_frame;
192 } ZFrame;
193 
194 typedef struct ZStack
195 {
196   ZDWord  stack_total;
197   ZDWord  stack_size;
198   ZWord*  stack;
199   ZWord*  stack_top;
200   ZFrame* current_frame;
201 } ZStack;
202 
203 typedef struct ZMachine
204 {
205   ZUWord   static_ceiling;
206   ZUWord   dynamic_ceiling;
207   ZDWord   high_start;
208   ZDWord   story_offset;
209   ZDWord   story_length;
210 
211   ZByte*   header;
212   ZByte*   dynamic_memory;
213 
214   ZFile*   file;
215   char*    story_file;
216 
217   ZByte* undo    [UNDO_LEVEL];
218   ZDWord undo_len[UNDO_LEVEL];
219 
220   ZByte  version;
221 
222 #ifdef PAGED_MEMORY
223   ZMap     memory; /* Still not implemented */
224 #else
225   ZByte*   memory;
226 #endif
227 
228   ZByte*   globals;
229 
230   ZStack   stack;
231 
232   int*     abbrev     [96];
233   int      abbrev_addr[96];
234 
235   ZByte*   dict;
236 
237   hash     cached_dictionaries;
238 
239   enum {
240     packed_v3,
241     packed_v4,
242     packed_v6,
243     packed_v8
244   } packtype;
245 
246   ZDWord routine_offset;
247   ZDWord string_offset;
248 
249   int display_active;
250   ZDisplay* dinfo;
251 
252   int graphical;
253 
254   /* Header extension block */
255   ZByte* heb;
256   ZUWord heblen;
257 
258   /* Output streams */
259   int    mouse_on;
260   int    screen_on;
261   int    transcript_on;
262   int    transcript_commands;
263   ZFile* transcript_file;
264 
265   int    memory_on;
266   ZUWord memory_pos  [16];
267   int    memory_width[16];
268 
269   int    buffering;
270 
271   /* Input streams */
272   int    script_on;
273   ZFile* script_file;
274 
275 #ifdef GLOBAL_PC
276   ZDWord zpc;
277 #endif
278 
279   /* Autosaving */
280   ZDWord autosave_pc;
281 
282   /* Commandline options */
283   int warning_level;
284 
285 #ifdef TRACKING
286   int track_objects;
287   int track_properties;
288   int track_attributes;
289 #endif
290 
291   ZFile*     blorb_file;
292   IffFile*   blorb_tokens;
293   BlorbFile* blorb;
294 
295   int force_breakpoint;
296 } ZMachine;
297 
298 typedef struct ZDictionary
299 {
300   char sep[256];
301   hash words;
302 } ZDictionary;
303 
304 extern void  zmachine_load_story    (char* filename, ZMachine* machine);
305 extern void  zmachine_load_file     (ZFile* file, ZMachine* machine);
306 extern void  zmachine_setup_header  (void);
307 extern void  zmachine_resize_display(ZDisplay* dis);
308 extern void  zmachine_fatal         (char* format, ...);
309 extern void  zmachine_warning       (char* format, ...);
310 extern void  zmachine_info          (char* format, ...);
311 extern void  zmachine_mark_statusbar(void);
312 extern char* zmachine_get_serial    (void);
313 extern void  zmachine_dump_stack    (ZStack* stack);
314 
315 extern ZWord   pop         (ZStack*);
316 extern ZWord   top         (ZStack*);
317 extern ZFrame* call_routine(ZDWord* pc, ZStack* stack, ZDWord start);
318 
319 /* Utility macros */
320 
321 #ifdef DEBUG
322 extern ZWord debug_print_var(ZWord val, int var);
323 #define DebugVar(x, y) debug_print_var(x, y)
324 #else
325 #define DebugVar(x, y) x
326 #endif
327 
328 #define GetVar(y)  DebugVar(((y)==0?pop(stack):(((unsigned char) (y))<16?stack->current_frame->local[(y)]:(machine.globals[((y)<<1)-32]<<8)|machine.globals[((y)<<1)-31])), y)
329 #define GetVarNoPop(y) DebugVar(((y)==0?top(stack):(((unsigned char) (y))<16?stack->current_frame->local[(y)]:(machine.globals[((y)<<1)-32]<<8)|machine.globals[((y)<<1)-31])), y)
330 #define GetCode(x)  machine.memory[(x)]
331 #define Word(x)     ((machine.memory[(x)]<<8)|machine.memory[(x)+1])
332 #define ReadByte(x) (machine.memory[(x)])
333 #define GetWord(m, x) ((m[x]<<8)|(m[x+1]))
334 #define Address(x) (machine.memory + (x))
335 
336 extern ZMachine machine;
337 
338 #endif
339