Update to Inform v6.35
[inform.git] / src / memory.c
1 /* ------------------------------------------------------------------------- */
2 /*   "memory" : Memory management and ICL memory setting commands            */
3 /*              (For "memoryerror", see "errors.c")                          */
4 /*                                                                           */
5 /*   Part of Inform 6.35                                                     */
6 /*   copyright (c) Graham Nelson 1993 - 2021                                 */
7 /*                                                                           */
8 /* Inform is free software: you can redistribute it and/or modify            */
9 /* it under the terms of the GNU General Public License as published by      */
10 /* the Free Software Foundation, either version 3 of the License, or         */
11 /* (at your option) any later version.                                       */
12 /*                                                                           */
13 /* Inform is distributed in the hope that it will be useful,                 */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the              */
16 /* GNU General Public License for more details.                              */
17 /*                                                                           */
18 /* You should have received a copy of the GNU General Public License         */
19 /* along with Inform. If not, see https://gnu.org/licenses/                  *
20 /*                                                                           */
21 /* ------------------------------------------------------------------------- */
22
23 #include "header.h"
24
25 int32 malloced_bytes=0;                /* Total amount of memory allocated   */
26
27 #ifdef PC_QUICKC
28
29 extern void *my_malloc(int32 size, char *whatfor)
30 {   char _huge *c;
31     if (memout_switch)
32         printf("Allocating %ld bytes for %s\n",size,whatfor);
33     if (size==0) return(NULL);
34     c=(char _huge *)halloc(size,1); malloced_bytes+=size;
35     if (c==0) memory_out_error(size, 1, whatfor);
36     return(c);
37 }
38
39 extern void my_realloc(void *pointer, int32 oldsize, int32 size, 
40     char *whatfor)
41 {   char _huge *c;
42     if (size==0) {
43         my_free(pointer, whatfor);
44         return;
45     }
46     c=halloc(size,1); malloced_bytes+=size;
47     if (c==0) memory_out_error(size, 1, whatfor);
48     if (memout_switch)
49         printf("Increasing allocation to %ld bytes for %s was (%08lx) \
50 now (%08lx)\n",
51             (long int) size,whatfor,(long int) (*(int **)pointer), 
52             (long int) c);
53     memcpy(c, *(int **)pointer, MIN(oldsize, size));
54     hfree(*(int **)pointer);
55     *(int **)pointer = c;
56 }
57
58 extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
59 {   void _huge *c;
60     if (memout_switch)
61         printf("Allocating %d bytes: array (%ld entries size %ld) for %s\n",
62             size*howmany,howmany,size,whatfor);
63     if ((size*howmany) == 0) return(NULL);
64     c=(void _huge *)halloc(howmany*size,1); malloced_bytes+=size*howmany;
65     if (c==0) memory_out_error(size, howmany, whatfor);
66     return(c);
67 }
68
69 extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany, 
70     int32 howmany, char *whatfor)
71 {   void _huge *c;
72     if (size*howmany==0) {
73         my_free(pointer, whatfor);
74         return;
75     }
76     c=(void _huge *)halloc(size*howmany,1); malloced_bytes+=size*howmany;
77     if (c==0) memory_out_error(size, howmany, whatfor);
78     if (memout_switch)
79         printf("Increasing allocation to %ld bytes: array (%ld entries size %ld) \
80 for %s was (%08lx) now (%08lx)\n",
81             ((long int)size) * ((long int)howmany),
82             (long int)howmany,(long int)size,whatfor,
83             (long int) *(int **)pointer, (long int) c);
84     memcpy(c, *(int **)pointer, MIN(size*oldhowmany, size*howmany));
85     hfree(*(int **)pointer);
86     *(int **)pointer = c;
87 }
88
89 #else
90
91 extern void *my_malloc(int32 size, char *whatfor)
92 {   char *c;
93     if (size==0) return(NULL);
94     c=malloc((size_t) size); malloced_bytes+=size;
95     if (c==0) memory_out_error(size, 1, whatfor);
96     if (memout_switch)
97         printf("Allocating %ld bytes for %s at (%08lx)\n",
98             (long int) size,whatfor,(long int) c);
99     return(c);
100 }
101
102 extern void my_realloc(void *pointer, int32 oldsize, int32 size, 
103     char *whatfor)
104 {   void *c;
105     if (size==0) {
106         my_free(pointer, whatfor);
107         return;
108     }
109     c=realloc(*(int **)pointer, (size_t) size); malloced_bytes+=size;
110     if (c==0) memory_out_error(size, 1, whatfor);
111     if (memout_switch)
112         printf("Increasing allocation to %ld bytes for %s was (%08lx) \
113 now (%08lx)\n",
114             (long int) size,whatfor,(long int) (*(int **)pointer), 
115             (long int) c);
116     *(int **)pointer = c;
117 }
118
119 extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
120 {   void *c;
121     if (size*howmany==0) return(NULL);
122     c=calloc(howmany,(size_t) size); malloced_bytes+=size*howmany;
123     if (c==0) memory_out_error(size, howmany, whatfor);
124     if (memout_switch)
125         printf("Allocating %ld bytes: array (%ld entries size %ld) \
126 for %s at (%08lx)\n",
127             ((long int)size) * ((long int)howmany),
128             (long int)howmany,(long int)size,whatfor,
129             (long int) c);
130     return(c);
131 }
132
133 extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany, 
134     int32 howmany, char *whatfor)
135 {   void *c;
136     if (size*howmany==0) {
137         my_free(pointer, whatfor);
138         return;
139     }
140     c=realloc(*(int **)pointer, (size_t)size*(size_t)howmany); 
141     malloced_bytes+=size*howmany;
142     if (c==0) memory_out_error(size, howmany, whatfor);
143     if (memout_switch)
144         printf("Increasing allocation to %ld bytes: array (%ld entries size %ld) \
145 for %s was (%08lx) now (%08lx)\n",
146             ((long int)size) * ((long int)howmany),
147             (long int)howmany,(long int)size,whatfor,
148             (long int) *(int **)pointer, (long int) c);
149     *(int **)pointer = c;
150 }
151
152 #endif
153
154 extern void my_free(void *pointer, char *whatitwas)
155 {
156     if (*(int **)pointer != NULL)
157     {   if (memout_switch)
158             printf("Freeing memory for %s at (%08lx)\n",
159                 whatitwas, (long int) (*(int **)pointer));
160 #ifdef PC_QUICKC
161         hfree(*(int **)pointer);
162 #else
163         free(*(int **)pointer);
164 #endif
165         *(int **)pointer = NULL;
166     }
167 }
168
169 /* ------------------------------------------------------------------------- */
170 /*   Extensible blocks of memory, providing a kind of RAM disc as an         */
171 /*   alternative to the temporary files option                               */
172 /*                                                                           */
173 /*   The allocation is slightly confusing. A block can store up to 72        */
174 /*   chunks, which are allocated as needed when data is written. (Data does  */
175 /*   not have to be written in order, but you should not try to read a byte  */
176 /*   before writing it.) The size of a chunk is defined by ALLOC_CHUNK_SIZE. */
177 /*   So any block can store any amount of data, but you increase the limit   */
178 /*   (for all blocks) by increasing ALLOC_CHUNK_SIZE, not the number of      */
179 /*   chunks.                                                                 */
180 /* ------------------------------------------------------------------------- */
181
182 static char chunk_name_buffer[60];
183 static char *chunk_name(memory_block *MB, int no)
184 {   char *p = "(unknown)";
185     if (MB == &static_strings_area) p = "static strings area";
186     if (MB == &zcode_area)          p = "Z-code area";
187     if (MB == &link_data_area)      p = "link data area";
188     if (MB == &zcode_backpatch_table) p = "Z-code backpatch table";
189     if (MB == &staticarray_backpatch_table) p = "Static array backpatch table";
190     if (MB == &zmachine_backpatch_table) p = "Z-machine backpatch table";
191     sprintf(chunk_name_buffer, "%s chunk %d", p, no);
192     return(chunk_name_buffer);
193 }
194
195 extern void initialise_memory_block(memory_block *MB)
196 {   int i;
197     MB->chunks = 0;
198     for (i=0; i<72; i++) MB->chunk[i] = NULL;
199     MB->extent_of_last = 0;
200     MB->write_pos = 0;
201 }
202
203 extern void deallocate_memory_block(memory_block *MB)
204 {   int i;
205     for (i=0; i<72; i++)
206         if (MB->chunk[i] != NULL)
207             my_free(&(MB->chunk[i]), chunk_name(MB, i));
208     MB->chunks = 0;
209     MB->extent_of_last = 0;
210 }
211
212 extern int read_byte_from_memory_block(memory_block *MB, int32 index)
213 {   uchar *p;
214     p = MB->chunk[index/ALLOC_CHUNK_SIZE];
215     if (p == NULL)
216     {   compiler_error_named("memory: read from unwritten byte in",
217             chunk_name(MB, index/ALLOC_CHUNK_SIZE));
218         return 0;
219     }
220     return p[index % ALLOC_CHUNK_SIZE];
221 }
222
223 extern void write_byte_to_memory_block(memory_block *MB, int32 index, int value)
224 {   uchar *p; int ch = index/ALLOC_CHUNK_SIZE;
225     if (ch < 0)
226     {   compiler_error_named("memory: negative index to", chunk_name(MB, 0));
227         return;
228     }
229     if (ch >= 72) memoryerror("ALLOC_CHUNK_SIZE", ALLOC_CHUNK_SIZE);
230
231     if (MB->chunk[ch] == NULL)
232     {   int i;
233         MB->chunk[ch] = my_malloc(ALLOC_CHUNK_SIZE, chunk_name(MB, ch));
234         p = MB->chunk[ch];
235         for (i=0; i<ALLOC_CHUNK_SIZE; i++) p[i] = 255;
236     }
237
238     p = MB->chunk[ch];
239     p[index % ALLOC_CHUNK_SIZE] = value;
240 }
241
242 /* ------------------------------------------------------------------------- */
243 /*   Where the memory settings are declared as variables                     */
244 /* ------------------------------------------------------------------------- */
245
246 int MAX_QTEXT_SIZE;
247 int MAX_SYMBOLS;
248 int SYMBOLS_CHUNK_SIZE;
249 int HASH_TAB_SIZE;
250 int MAX_OBJECTS;
251 int MAX_ARRAYS;
252 int MAX_ACTIONS;
253 int MAX_ADJECTIVES;
254 int MAX_DICT_ENTRIES;
255 int MAX_STATIC_DATA;
256 int MAX_PROP_TABLE_SIZE;
257 int MAX_ABBREVS;
258 int MAX_DYNAMIC_STRINGS;
259 int MAX_EXPRESSION_NODES;
260 int MAX_VERBS;
261 int MAX_VERBSPACE;
262 int MAX_LABELS;
263 int MAX_LINESPACE;
264 int32 MAX_STATIC_STRINGS;
265 int32 MAX_ZCODE_SIZE;
266 int MAX_LOW_STRINGS;
267 int32 MAX_TRANSCRIPT_SIZE;
268 int MAX_CLASSES;
269 int32 MAX_LINK_DATA_SIZE;
270 int MAX_INCLUSION_DEPTH;
271 int MAX_SOURCE_FILES;
272 int32 MAX_INDIV_PROP_TABLE_SIZE;
273 int32 MAX_OBJ_PROP_TABLE_SIZE;
274 int MAX_OBJ_PROP_COUNT;
275 int MAX_LOCAL_VARIABLES;
276 int MAX_GLOBAL_VARIABLES;
277 int DICT_WORD_SIZE; /* number of characters in a dict word */
278 int DICT_CHAR_SIZE; /* (glulx) 1 for one-byte chars, 4 for Unicode chars */
279 int DICT_WORD_BYTES; /* DICT_WORD_SIZE*DICT_CHAR_SIZE */
280 int ZCODE_HEADER_EXT_WORDS; /* (zcode 1.0) requested header extension size */
281 int ZCODE_HEADER_FLAGS_3; /* (zcode 1.1) value to place in Flags 3 word */
282 int NUM_ATTR_BYTES;
283 int GLULX_OBJECT_EXT_BYTES; /* (glulx) extra bytes for each object record */
284 int32 MAX_NUM_STATIC_STRINGS;
285 int32 MAX_UNICODE_CHARS;
286 int32 MAX_STACK_SIZE;
287 int32 MEMORY_MAP_EXTENSION;
288 int ALLOC_CHUNK_SIZE;
289 int WARN_UNUSED_ROUTINES; /* 0: no, 1: yes except in system files, 2: yes always */
290 int OMIT_UNUSED_ROUTINES; /* 0: no, 1: yes */
291 int TRANSCRIPT_FORMAT; /* 0: classic, 1: prefixed */
292
293 /* The way memory sizes are set causes great nuisance for those parameters
294    which have different defaults under Z-code and Glulx. We have to get
295    the defaults right whether the user sets "-G $HUGE" or "$HUGE -G". 
296    And an explicit value set by the user should override both defaults. */
297 static int32 MAX_ZCODE_SIZE_z, MAX_ZCODE_SIZE_g;
298 static int MAX_PROP_TABLE_SIZE_z, MAX_PROP_TABLE_SIZE_g;
299 static int MAX_GLOBAL_VARIABLES_z, MAX_GLOBAL_VARIABLES_g;
300 static int MAX_LOCAL_VARIABLES_z, MAX_LOCAL_VARIABLES_g;
301 static int DICT_WORD_SIZE_z, DICT_WORD_SIZE_g;
302 static int NUM_ATTR_BYTES_z, NUM_ATTR_BYTES_g;
303 static int ALLOC_CHUNK_SIZE_z, ALLOC_CHUNK_SIZE_g;
304 static int MAX_DYNAMIC_STRINGS_z, MAX_DYNAMIC_STRINGS_g;
305
306 /* ------------------------------------------------------------------------- */
307 /*   Memory control from the command line                                    */
308 /* ------------------------------------------------------------------------- */
309
310 static void list_memory_sizes(void)
311 {   printf("+--------------------------------------+\n");
312     printf("|  %25s = %-7s |\n","Memory setting","Value");
313     printf("+--------------------------------------+\n");
314     printf("|  %25s = %-7d |\n","MAX_ABBREVS",MAX_ABBREVS);
315     printf("|  %25s = %-7d |\n","MAX_ACTIONS",MAX_ACTIONS);
316     printf("|  %25s = %-7d |\n","MAX_ADJECTIVES",MAX_ADJECTIVES);
317     printf("|  %25s = %-7d |\n","ALLOC_CHUNK_SIZE",ALLOC_CHUNK_SIZE);
318     printf("|  %25s = %-7d |\n","MAX_ARRAYS",MAX_ARRAYS);
319     printf("|  %25s = %-7d |\n","NUM_ATTR_BYTES",NUM_ATTR_BYTES);
320     printf("|  %25s = %-7d |\n","MAX_CLASSES",MAX_CLASSES);
321     printf("|  %25s = %-7d |\n","MAX_DICT_ENTRIES",MAX_DICT_ENTRIES);
322     printf("|  %25s = %-7d |\n","DICT_WORD_SIZE",DICT_WORD_SIZE);
323     if (glulx_mode)
324       printf("|  %25s = %-7d |\n","DICT_CHAR_SIZE",DICT_CHAR_SIZE);
325     printf("|  %25s = %-7d |\n","MAX_DYNAMIC_STRINGS",MAX_DYNAMIC_STRINGS);
326     printf("|  %25s = %-7d |\n","MAX_EXPRESSION_NODES",MAX_EXPRESSION_NODES);
327     printf("|  %25s = %-7d |\n","MAX_GLOBAL_VARIABLES",MAX_GLOBAL_VARIABLES);
328     printf("|  %25s = %-7d |\n","HASH_TAB_SIZE",HASH_TAB_SIZE);
329     if (!glulx_mode)
330       printf("|  %25s = %-7d |\n","ZCODE_HEADER_EXT_WORDS",ZCODE_HEADER_EXT_WORDS);
331     if (!glulx_mode)
332       printf("|  %25s = %-7d |\n","ZCODE_HEADER_FLAGS_3",ZCODE_HEADER_FLAGS_3);
333     printf("|  %25s = %-7d |\n","MAX_INCLUSION_DEPTH",MAX_INCLUSION_DEPTH);
334     printf("|  %25s = %-7d |\n","MAX_INDIV_PROP_TABLE_SIZE", MAX_INDIV_PROP_TABLE_SIZE);
335     printf("|  %25s = %-7d |\n","INDIV_PROP_START", INDIV_PROP_START);
336     printf("|  %25s = %-7d |\n","MAX_LABELS",MAX_LABELS);
337     printf("|  %25s = %-7d |\n","MAX_LINESPACE",MAX_LINESPACE);
338     printf("|  %25s = %-7d |\n","MAX_LINK_DATA_SIZE",MAX_LINK_DATA_SIZE);
339     if (glulx_mode)
340       printf("|  %25s = %-7d |\n","MAX_LOCAL_VARIABLES",MAX_LOCAL_VARIABLES);
341     printf("|  %25s = %-7d |\n","MAX_LOW_STRINGS",MAX_LOW_STRINGS);
342     if (glulx_mode)
343       printf("|  %25s = %-7d |\n","MEMORY_MAP_EXTENSION",
344         MEMORY_MAP_EXTENSION);
345     if (glulx_mode)
346       printf("|  %25s = %-7d |\n","MAX_NUM_STATIC_STRINGS",
347         MAX_NUM_STATIC_STRINGS);
348     printf("|  %25s = %-7d |\n","MAX_OBJECTS",MAX_OBJECTS);
349     if (glulx_mode)
350       printf("|  %25s = %-7d |\n","GLULX_OBJECT_EXT_BYTES",
351         GLULX_OBJECT_EXT_BYTES);
352     if (glulx_mode)
353       printf("|  %25s = %-7d |\n","MAX_OBJ_PROP_COUNT",
354         MAX_OBJ_PROP_COUNT);
355     if (glulx_mode)
356       printf("|  %25s = %-7d |\n","MAX_OBJ_PROP_TABLE_SIZE",
357         MAX_OBJ_PROP_TABLE_SIZE);
358     printf("|  %25s = %-7d |\n","MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
359     printf("|  %25s = %-7d |\n","MAX_QTEXT_SIZE",MAX_QTEXT_SIZE);
360     printf("|  %25s = %-7d |\n","MAX_SOURCE_FILES",MAX_SOURCE_FILES);
361     if (glulx_mode)
362       printf("|  %25s = %-7ld |\n","MAX_STACK_SIZE",
363            (long int) MAX_STACK_SIZE);
364     printf("|  %25s = %-7d |\n","MAX_STATIC_DATA",MAX_STATIC_DATA);
365     printf("|  %25s = %-7ld |\n","MAX_STATIC_STRINGS",
366            (long int) MAX_STATIC_STRINGS);
367     printf("|  %25s = %-7d |\n","MAX_SYMBOLS",MAX_SYMBOLS);
368     printf("|  %25s = %-7d |\n","SYMBOLS_CHUNK_SIZE",SYMBOLS_CHUNK_SIZE);
369     printf("|  %25s = %-7d |\n","TRANSCRIPT_FORMAT",TRANSCRIPT_FORMAT);
370     printf("|  %25s = %-7ld |\n","MAX_TRANSCRIPT_SIZE",
371            (long int) MAX_TRANSCRIPT_SIZE);
372     if (glulx_mode)
373       printf("|  %25s = %-7ld |\n","MAX_UNICODE_CHARS",
374            (long int) MAX_UNICODE_CHARS);
375     printf("|  %25s = %-7d |\n","WARN_UNUSED_ROUTINES",WARN_UNUSED_ROUTINES);
376     printf("|  %25s = %-7d |\n","OMIT_UNUSED_ROUTINES",OMIT_UNUSED_ROUTINES);
377     printf("|  %25s = %-7d |\n","MAX_VERBS",MAX_VERBS);
378     printf("|  %25s = %-7d |\n","MAX_VERBSPACE",MAX_VERBSPACE);
379     printf("|  %25s = %-7ld |\n","MAX_ZCODE_SIZE",
380            (long int) MAX_ZCODE_SIZE);
381     printf("+--------------------------------------+\n");
382 }
383
384 extern void set_memory_sizes(int size_flag)
385 {
386     if (size_flag == HUGE_SIZE)
387     {
388         MAX_QTEXT_SIZE  = 4000;
389         MAX_SYMBOLS     = 10000;
390
391         SYMBOLS_CHUNK_SIZE = 5000;
392         HASH_TAB_SIZE      = 512;
393
394         MAX_OBJECTS = 640;
395
396         MAX_ACTIONS      = 200;
397         MAX_ADJECTIVES   = 50;
398         MAX_DICT_ENTRIES = 2000;
399         MAX_STATIC_DATA  = 10000;
400
401         MAX_PROP_TABLE_SIZE_z = 30000;
402         MAX_PROP_TABLE_SIZE_g = 60000;
403
404         MAX_EXPRESSION_NODES = 100;
405         MAX_VERBS = 200;
406         MAX_VERBSPACE = 4096;
407         MAX_LABELS = 1000;
408         MAX_LINESPACE = 16000;
409
410         MAX_STATIC_STRINGS = 8000;
411         MAX_ZCODE_SIZE_z = 20000;
412         MAX_ZCODE_SIZE_g = 40000;
413         MAX_LINK_DATA_SIZE = 2000;
414
415         MAX_LOW_STRINGS = 2048;
416
417         MAX_TRANSCRIPT_SIZE = 200000;
418         MAX_NUM_STATIC_STRINGS = 20000;
419
420         MAX_CLASSES = 64;
421
422         MAX_OBJ_PROP_COUNT = 128;
423         MAX_OBJ_PROP_TABLE_SIZE = 4096;
424
425         MAX_INDIV_PROP_TABLE_SIZE = 15000;
426         MAX_ARRAYS = 128;
427
428         MAX_GLOBAL_VARIABLES_z = 240;
429         MAX_GLOBAL_VARIABLES_g = 512;
430         
431         ALLOC_CHUNK_SIZE_z = 8192;
432         ALLOC_CHUNK_SIZE_g = 32768;
433     }
434     if (size_flag == LARGE_SIZE)
435     {
436         MAX_QTEXT_SIZE  = 4000;
437         MAX_SYMBOLS     = 6400;
438
439         SYMBOLS_CHUNK_SIZE = 5000;
440         HASH_TAB_SIZE      = 512;
441
442         MAX_OBJECTS = 512;
443
444         MAX_ACTIONS      = 200;
445         MAX_ADJECTIVES   = 50;
446         MAX_DICT_ENTRIES = 1300;
447         MAX_STATIC_DATA  = 10000;
448
449         MAX_PROP_TABLE_SIZE_z = 15000;
450         MAX_PROP_TABLE_SIZE_g = 30000;
451
452         MAX_EXPRESSION_NODES = 100;
453         MAX_VERBS = 140;
454         MAX_VERBSPACE = 4096;
455         MAX_LINESPACE = 10000;
456
457         MAX_LABELS = 1000;
458         MAX_STATIC_STRINGS = 8000;
459         MAX_ZCODE_SIZE_z = 20000;
460         MAX_ZCODE_SIZE_g = 40000;
461         MAX_LINK_DATA_SIZE = 2000;
462
463         MAX_LOW_STRINGS = 2048;
464
465         MAX_TRANSCRIPT_SIZE = 200000;
466         MAX_NUM_STATIC_STRINGS = 20000;
467
468         MAX_CLASSES = 64;
469
470         MAX_OBJ_PROP_COUNT = 64;
471         MAX_OBJ_PROP_TABLE_SIZE = 2048;
472
473         MAX_INDIV_PROP_TABLE_SIZE = 10000;
474         MAX_ARRAYS = 128;
475
476         MAX_GLOBAL_VARIABLES_z = 240;
477         MAX_GLOBAL_VARIABLES_g = 512;
478         
479         ALLOC_CHUNK_SIZE_z = 8192;
480         ALLOC_CHUNK_SIZE_g = 16384;
481     }
482     if (size_flag == SMALL_SIZE)
483     {
484         MAX_QTEXT_SIZE  = 4000;
485         MAX_SYMBOLS     = 3000;
486
487         SYMBOLS_CHUNK_SIZE = 2500;
488         HASH_TAB_SIZE      = 512;
489
490         MAX_OBJECTS = 300;
491
492         MAX_ACTIONS      = 200;
493         MAX_ADJECTIVES   = 50;
494         MAX_DICT_ENTRIES = 700;
495         MAX_STATIC_DATA  = 10000;
496
497         MAX_PROP_TABLE_SIZE_z = 8000;
498         MAX_PROP_TABLE_SIZE_g = 16000;
499
500         MAX_EXPRESSION_NODES = 40;
501         MAX_VERBS = 110;
502         MAX_VERBSPACE = 2048;
503         MAX_LINESPACE = 10000;
504         MAX_LABELS = 1000;
505
506         MAX_STATIC_STRINGS = 8000;
507         MAX_ZCODE_SIZE_z = 10000;
508         MAX_ZCODE_SIZE_g = 20000;
509         MAX_LINK_DATA_SIZE = 1000;
510
511         MAX_LOW_STRINGS = 1024;
512
513         MAX_TRANSCRIPT_SIZE = 100000;
514         MAX_NUM_STATIC_STRINGS = 10000;
515
516         MAX_CLASSES = 32;
517
518         MAX_OBJ_PROP_COUNT = 64;
519         MAX_OBJ_PROP_TABLE_SIZE = 1024;
520
521         MAX_INDIV_PROP_TABLE_SIZE = 5000;
522         MAX_ARRAYS = 64;
523
524         MAX_GLOBAL_VARIABLES_z = 240;
525         MAX_GLOBAL_VARIABLES_g = 256;
526         
527         ALLOC_CHUNK_SIZE_z = 8192;
528         ALLOC_CHUNK_SIZE_g = 8192;
529     }
530
531     /* Regardless of size_flag... */
532     MAX_SOURCE_FILES = 256;
533     MAX_INCLUSION_DEPTH = 5;
534     MAX_LOCAL_VARIABLES_z = 16;
535     MAX_LOCAL_VARIABLES_g = 32;
536     DICT_CHAR_SIZE = 1;
537     DICT_WORD_SIZE_z = 6;
538     DICT_WORD_SIZE_g = 9;
539     NUM_ATTR_BYTES_z = 6;
540     NUM_ATTR_BYTES_g = 7;
541     MAX_ABBREVS = 64;
542     MAX_DYNAMIC_STRINGS_z = 32;
543     MAX_DYNAMIC_STRINGS_g = 64;
544     /* Backwards-compatible behavior: allow for a unicode table
545        whether we need one or not. The user can set this to zero if
546        there's no unicode table. */
547     ZCODE_HEADER_EXT_WORDS = 3;
548     ZCODE_HEADER_FLAGS_3 = 0;
549     GLULX_OBJECT_EXT_BYTES = 0;
550     MAX_UNICODE_CHARS = 64;
551     MEMORY_MAP_EXTENSION = 0;
552     /* We estimate the default Glulx stack size at 4096. That's about
553        enough for 90 nested function calls with 8 locals each -- the
554        same capacity as the Z-Spec's suggestion for Z-machine stack
555        size. Note that Inform 7 wants more stack; I7-generated code
556        sets MAX_STACK_SIZE to 65536 by default. */
557     MAX_STACK_SIZE = 4096;
558     OMIT_UNUSED_ROUTINES = 0;
559     WARN_UNUSED_ROUTINES = 0;
560     TRANSCRIPT_FORMAT = 0;
561
562     adjust_memory_sizes();
563 }
564
565 extern void adjust_memory_sizes()
566 {
567   if (!glulx_mode) {
568     MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_z;
569     MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_z;
570     MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_z;
571     MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_z;
572     DICT_WORD_SIZE = DICT_WORD_SIZE_z;
573     NUM_ATTR_BYTES = NUM_ATTR_BYTES_z;
574     ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_z;
575     MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_z;
576     INDIV_PROP_START = 64;
577   }
578   else {
579     MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_g;
580     MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_g;
581     MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_g;
582     MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_g;
583     DICT_WORD_SIZE = DICT_WORD_SIZE_g;
584     NUM_ATTR_BYTES = NUM_ATTR_BYTES_g;
585     ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_g;
586     MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_g;
587     INDIV_PROP_START = 256;
588   }
589 }
590
591 static void explain_parameter(char *command)
592 {   printf("\n");
593     if (strcmp(command,"MAX_QTEXT_SIZE")==0)
594     {   printf(
595 "  MAX_QTEXT_SIZE is the maximum length of a quoted string.  Increasing\n\
596    by 1 costs 5 bytes (for lexical analysis memory).  Inform automatically\n\
597    ensures that MAX_STATIC_STRINGS is at least twice the size of this.");
598         return;
599     }
600     if (strcmp(command,"MAX_SYMBOLS")==0)
601     {   printf(
602 "  MAX_SYMBOLS is the maximum number of symbols - names of variables, \n\
603   objects, routines, the many internal Inform-generated names and so on.\n");
604         return;
605     }
606     if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
607     {   printf(
608 "  The symbols names are stored in memory which is allocated in chunks \n\
609   of size SYMBOLS_CHUNK_SIZE.\n");
610         return;
611     }
612     if (strcmp(command,"HASH_TAB_SIZE")==0)
613     {   printf(
614 "  HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
615   symbols banks.\n");
616         return;
617     }
618     if (strcmp(command,"MAX_OBJECTS")==0)
619     {   printf(
620 "  MAX_OBJECTS is the maximum number of objects.  (If compiling a version-3 \n\
621   game, 255 is an absolute maximum in any event.)\n");
622         return;
623     }
624     if (strcmp(command,"MAX_ACTIONS")==0)
625     {   printf(
626 "  MAX_ACTIONS is the maximum number of actions - that is, routines such as \n\
627   TakeSub which are referenced in the grammar table.\n");
628         return;
629     }
630     if (strcmp(command,"MAX_ADJECTIVES")==0)
631     {   printf(
632 "  MAX_ADJECTIVES is the maximum number of different \"adjectives\" in the \n\
633   grammar table.  Adjectives are misleadingly named: they are words such as \n\
634   \"in\", \"under\" and the like.\n");
635         return;
636     }
637     if (strcmp(command,"MAX_DICT_ENTRIES")==0)
638     {   printf(
639 "  MAX_DICT_ENTRIES is the maximum number of words which can be entered \n\
640   into the game's dictionary.  It costs 29 bytes to increase this by one.\n");
641         return;
642     }
643     if (strcmp(command,"DICT_WORD_SIZE")==0)
644     {   printf(
645 "  DICT_WORD_SIZE is the number of characters in a dictionary word. In \n\
646   Z-code this is always 6 (only 4 are used in v3 games). In Glulx it \n\
647   can be any number.\n");
648         return;
649     }
650     if (strcmp(command,"DICT_CHAR_SIZE")==0)
651     {   printf(
652 "  DICT_CHAR_SIZE is the byte size of one character in the dictionary. \n\
653   (This is only meaningful in Glulx, since Z-code has compressed dictionary \n\
654   words.) It can be either 1 (the default) or 4 (to enable full Unicode \n\
655   input.)\n");
656         return;
657     }
658     if (strcmp(command,"NUM_ATTR_BYTES")==0)
659     {   printf(
660 "  NUM_ATTR_BYTES is the space used to store attribute flags. Each byte \n\
661   stores eight attributes. In Z-code this is always 6 (only 4 are used in \n\
662   v3 games). In Glulx it can be any number which is a multiple of four, \n\
663   plus three.\n");
664         return;
665     }
666     if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
667     {   printf(
668 "  ZCODE_HEADER_EXT_WORDS is the number of words in the Z-code header \n\
669   extension table (Z-Spec 1.0). The -W switch also sets this. It defaults \n\
670   to 3, but can be set higher. (It can be set lower if no Unicode \n\
671   translation table is created.)\n");
672         return;
673     }
674     if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
675     {   printf(
676 "  ZCODE_HEADER_FLAGS_3 is the value to store in the Flags 3 word of the \n\
677   header extension table (Z-Spec 1.1).\n");
678         return;
679     }
680     if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
681     {   printf(
682 "  GLULX_OBJECT_EXT_BYTES is an amount of additional space to add to each \n\
683   object record. It is initialized to zero bytes, and the game is free to \n\
684   use it as desired. (This is only meaningful in Glulx, since Z-code \n\
685   specifies the object structure.)\n");
686         return;
687     }
688     if (strcmp(command,"MAX_STATIC_DATA")==0)
689     {   printf(
690 "  MAX_STATIC_DATA is the size of an array of integers holding initial \n\
691   values for arrays and strings stored as ASCII inside the Z-machine.  It \n\
692   should be at least 1024 but seldom needs much more.\n");
693         return;
694     }
695     if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
696     {   printf(
697 "  MAX_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
698   properties table.\n");
699         return;
700     }
701     if (strcmp(command,"MAX_ABBREVS")==0)
702     {   printf(
703 "  MAX_ABBREVS is the maximum number of declared abbreviations.  It is not \n\
704   allowed to exceed 96 in Z-code.\n");
705         return;
706     }
707     if (strcmp(command,"MAX_DYNAMIC_STRINGS")==0)
708     {   printf(
709 "  MAX_DYNAMIC_STRINGS is the maximum number of string substitution variables\n\
710   (\"@00\").  It is not allowed to exceed 96 in Z-code or 100 in Glulx.\n");
711         return;
712     }
713     if (strcmp(command,"MAX_ARRAYS")==0)
714     {   printf(
715 "  MAX_ARRAYS is the maximum number of declared arrays.\n");
716         return;
717     }
718     if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
719     {   printf(
720 "  MAX_EXPRESSION_NODES is the maximum number of nodes in the expression \n\
721   evaluator's storage for parse trees.  In effect, it measures how \n\
722   complicated algebraic expressions are allowed to be.  Increasing it by \n\
723   one costs about 80 bytes.\n");
724         return;
725     }
726     if (strcmp(command,"MAX_VERBS")==0)
727     {   printf(
728 "  MAX_VERBS is the maximum number of verbs (such as \"take\") which can be \n\
729   defined, each with its own grammar.  To increase it by one costs about\n\
730   128 bytes.  A full game will contain at least 100.\n");
731         return;
732     }
733     if (strcmp(command,"MAX_VERBSPACE")==0)
734     {   printf(
735 "  MAX_VERBSPACE is the size of workspace used to store verb words, so may\n\
736   need increasing in games with many synonyms: unlikely to exceed 4K.\n");
737         return;
738     }
739     if (strcmp(command,"MAX_LABELS")==0)
740     {   printf(
741 "  MAX_LABELS is the maximum number of label points in any one routine.\n\
742   (If the -k debugging information switch is set, MAX_LABELS is raised to\n\
743   a minimum level of 2000, as about twice the normal number of label points\n\
744   are needed to generate tables of how source code corresponds to positions\n\
745   in compiled code.)");
746         return;
747     }
748     if (strcmp(command,"MAX_LINESPACE")==0)
749     {   printf(
750 "  MAX_LINESPACE is the size of workspace used to store grammar lines, so \n\
751   may need increasing in games with complex or extensive grammars.\n");
752         return;
753     }
754     if (strcmp(command,"MAX_STATIC_STRINGS")==0)
755     {
756         printf(
757 "  MAX_STATIC_STRINGS is the size in bytes of a buffer to hold compiled\n\
758   strings before they're written into longer-term storage.  2000 bytes is \n\
759   plenty, allowing string constants of up to about 3000 characters long.\n\
760   Inform automatically ensures that this is at least twice the size of\n\
761   MAX_QTEXT_SIZE, to be on the safe side.");
762         return;
763     }
764     if (strcmp(command,"MAX_ZCODE_SIZE")==0)
765     {
766         printf(
767 "  MAX_ZCODE_SIZE is the size in bytes of a buffer to hold compiled \n\
768   code for a single routine.  (It applies to both Z-code and Glulx, \n\
769   despite the name.)  As a guide, the longest library routine is \n\
770   about 6500 bytes long in Z-code; about twice that in Glulx.");
771         return;
772     }
773     if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
774     {
775         printf(
776 "  MAX_LINK_DATA_SIZE is the size in bytes of a buffer to hold module \n\
777   link data before it's written into longer-term storage.  2000 bytes \n\
778   is plenty.");
779         return;
780     }
781     if (strcmp(command,"MAX_LOW_STRINGS")==0)
782     {   printf(
783 "  MAX_LOW_STRINGS is the size in bytes of a buffer to hold all the \n\
784   compiled \"low strings\" which are to be written above the synonyms table \n\
785   in the Z-machine.  1024 is plenty.\n");
786         return;
787     }
788     if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
789     {   printf(
790 "  MAX_TRANSCRIPT_SIZE is only allocated for the abbreviations optimisation \n\
791   switch, and has the size in bytes of a buffer to hold the entire text of\n\
792   the game being compiled: it has to be enormous, say 100000 to 200000.\n");
793         return;
794     }
795     if (strcmp(command,"MAX_CLASSES")==0)
796     {   printf(
797 "  MAX_CLASSES maximum number of object classes which can be defined.  This\n\
798   is cheap to increase.\n");
799         return;
800     }
801     if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
802     {   printf(
803 "  MAX_INCLUSION_DEPTH is the number of nested includes permitted.\n");
804         return;
805     }
806     if (strcmp(command,"MAX_SOURCE_FILES")==0)
807     {   printf(
808 "  MAX_SOURCE_FILES is the number of source files that can be read in the \n\
809   compilation.\n");
810         return;
811     }
812     if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
813     {   printf(
814 "  MAX_INDIV_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
815   table of ..variable values.\n");
816         return;
817     }
818     if (strcmp(command,"INDIV_PROP_START")==0)
819     {   printf(
820 "  Properties 1 to INDIV_PROP_START-1 are common properties; individual\n\
821   properties are numbered INDIV_PROP_START and up.\n");
822         return;
823     }
824     if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
825     {   printf(
826 "  MAX_OBJ_PROP_COUNT is the maximum number of properties a single object \n\
827   can have. (Glulx only)\n");
828         return;
829     }
830     if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
831     {   printf(
832 "  MAX_OBJ_PROP_TABLE_SIZE is the number of words allocated to hold a \n\
833   single object's properties. (Glulx only)\n");
834         return;
835     }
836     if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
837     {   printf(
838 "  MAX_LOCAL_VARIABLES is the number of local variables (including \n\
839   arguments) allowed in a procedure. (Glulx only)\n");
840         return;
841     }
842     if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
843     {   printf(
844 "  MAX_GLOBAL_VARIABLES is the number of global variables allowed in the \n\
845   program. (Glulx only)\n");
846         return;
847     }
848     if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
849     {
850         printf(
851 "  MAX_NUM_STATIC_STRINGS is the maximum number of compiled strings \n\
852   allowed in the program. (Glulx only)\n");
853         return;
854     }
855     if (strcmp(command,"MAX_UNICODE_CHARS")==0)
856     {
857         printf(
858 "  MAX_UNICODE_CHARS is the maximum number of different Unicode characters \n\
859   (beyond the Latin-1 range, $00..$FF) which the game text can use. \n\
860   (Glulx only)\n");
861         return;
862     }
863     if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
864     {
865         printf(
866 "  ALLOC_CHUNK_SIZE is a base unit of Inform's internal memory allocation \n\
867   for various structures.\n");
868         return;
869     }
870     if (strcmp(command,"MAX_STACK_SIZE")==0)
871     {
872         printf(
873 "  MAX_STACK_SIZE is the maximum size (in bytes) of the interpreter stack \n\
874   during gameplay. (Glulx only)\n");
875         return;
876     }
877     if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
878     {
879         printf(
880 "  MEMORY_MAP_EXTENSION is the number of bytes (all zeroes) to map into \n\
881   memory after the game file. (Glulx only)\n");
882         return;
883     }
884     if (strcmp(command,"TRANSCRIPT_FORMAT")==0)
885     {
886         printf(
887 "  TRANSCRIPT_FORMAT, if set to 1, adjusts the gametext.txt transcript for \n\
888   easier machine processing; each line will be prefixed by its context.\n");
889         return;
890     }
891     if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
892     {
893         printf(
894 "  WARN_UNUSED_ROUTINES, if set to 2, will display a warning for each \n\
895   routine in the game file which is never called. (This includes \n\
896   routines called only from uncalled routines, etc.) If set to 1, will warn \n\
897   only about functions in game code, not in the system library.\n");
898         return;
899     }
900     if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
901     {
902         printf(
903 "  OMIT_UNUSED_ROUTINES, if set to 1, will avoid compiling unused routines \n\
904   into the game file.\n");
905         return;
906     }
907     if (strcmp(command,"SERIAL")==0)
908     {
909         printf(
910 "  SERIAL, if set, will be used as the six digit serial number written into \n\
911   the header of the output file.\n");
912         return;
913     }
914
915     printf("No such memory setting as \"%s\"\n",command);
916
917     return;
918 }
919
920 /* Parse a decimal number as an int32. Return true if a valid number
921    was found; otherwise print a warning and return false.
922
923    Anything over nine digits is considered an overflow; we report a
924    warning but return +/- 999999999 (and true). This is not entirely
925    clever about leading zeroes ("0000000001" is treated as an
926    overflow) but this is better than trying to detect genuine
927    overflows in a long.
928
929    (Some Glulx settings might conceivably want to go up to $7FFFFFFF,
930    which is a ten-digit number, but we're not going to allow that
931    today.)
932
933    This used to rely on atoi(), and we retain the atoi() behavior of
934    ignoring garbage characters after a valid decimal number.
935  */
936 static int parse_memory_setting(char *str, char *label, int32 *result)
937 {
938     char *cx = str;
939     char *ex;
940     long val;
941
942     *result = 0;
943
944     while (*cx == ' ') cx++;
945
946     val = strtol(cx, &ex, 10);    
947
948     if (ex == cx) {
949         printf("Bad numerical setting in $ command \"%s=%s\"\n",
950             label, str);
951         return 0;
952     }
953
954     if (*cx == '-') {
955         if (ex > cx+10) {
956             val = -999999999;
957             printf("Numerical setting underflowed in $ command \"%s=%s\" (limiting to %ld)\n",
958                 label, str, val);
959         }
960     }
961     else {
962         if (ex > cx+9) {
963             val = 999999999;
964             printf("Numerical setting overflowed in $ command \"%s=%s\" (limiting to %ld)\n",
965                 label, str, val);
966         }
967     }
968
969     *result = (int32)val;
970     return 1;
971 }
972
973 static void add_predefined_symbol(char *command)
974 {
975     int ix;
976     
977     int value = 0;
978     char *valpos = NULL;
979     
980     for (ix=0; command[ix]; ix++) {
981         if (command[ix] == '=') {
982             valpos = command+(ix+1);
983             command[ix] = '\0';
984             break;
985         }
986     }
987     
988     for (ix=0; command[ix]; ix++) {
989         if ((ix == 0 && isdigit(command[ix]))
990             || !(isalnum(command[ix]) || command[ix] == '_')) {
991             printf("Attempt to define invalid symbol: %s\n", command);
992             return;
993         }
994     }
995
996     if (valpos) {
997         if (!parse_memory_setting(valpos, command, &value)) {
998             return;
999         };
1000     }
1001
1002     add_config_symbol_definition(command, value);
1003 }
1004
1005 /* Handle a dollar-sign command option: $LIST, $FOO=VAL, and so on.
1006    The option may come from the command line, an ICL file, or a header
1007    comment.
1008
1009    (Unix-style command-line options are converted to dollar-sign format
1010    before being sent here.)
1011
1012    The name of this function is outdated. Many of these settings are not
1013    really about memory allocation.
1014 */
1015 extern void memory_command(char *command)
1016 {   int i, k, flag=0; int32 j;
1017
1018     for (k=0; command[k]!=0; k++)
1019         if (islower(command[k])) command[k]=toupper(command[k]);
1020
1021     if (command[0]=='?') { explain_parameter(command+1); return; }
1022     if (command[0]=='#') { add_predefined_symbol(command+1); return; }
1023
1024     if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; }
1025     if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; }
1026     if (strcmp(command, "SMALL")==0) { set_memory_sizes(SMALL_SIZE); return; }
1027     if (strcmp(command, "LIST")==0)  { list_memory_sizes(); return; }
1028     for (i=0; command[i]!=0; i++)
1029     {   if (command[i]=='=')
1030         {   command[i]=0;
1031             if (!parse_memory_setting(command+i+1, command, &j)) {
1032                 return;
1033             }
1034             if (strcmp(command,"BUFFER_LENGTH")==0)
1035                 flag=2;
1036             if (strcmp(command,"MAX_QTEXT_SIZE")==0)
1037             {   MAX_QTEXT_SIZE=j, flag=1;
1038                 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
1039                     MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
1040             }
1041             if (strcmp(command,"MAX_SYMBOLS")==0)
1042                 MAX_SYMBOLS=j, flag=1;
1043             if (strcmp(command,"MAX_BANK_SIZE")==0)
1044                 flag=2;
1045             if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
1046                 SYMBOLS_CHUNK_SIZE=j, flag=1;
1047             if (strcmp(command,"BANK_CHUNK_SIZE")==0)
1048                 flag=2;
1049             if (strcmp(command,"HASH_TAB_SIZE")==0)
1050                 HASH_TAB_SIZE=j, flag=1;
1051             if (strcmp(command,"MAX_OBJECTS")==0)
1052                 MAX_OBJECTS=j, flag=1;
1053             if (strcmp(command,"MAX_ACTIONS")==0)
1054                 MAX_ACTIONS=j, flag=1;
1055             if (strcmp(command,"MAX_ADJECTIVES")==0)
1056                 MAX_ADJECTIVES=j, flag=1;
1057             if (strcmp(command,"MAX_DICT_ENTRIES")==0)
1058                 MAX_DICT_ENTRIES=j, flag=1;
1059             if (strcmp(command,"DICT_WORD_SIZE")==0) 
1060             {   DICT_WORD_SIZE=j, flag=1;
1061                 DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j;
1062             }
1063             if (strcmp(command,"DICT_CHAR_SIZE")==0)
1064                 DICT_CHAR_SIZE=j, flag=1;
1065             if (strcmp(command,"NUM_ATTR_BYTES")==0) 
1066             {   NUM_ATTR_BYTES=j, flag=1;
1067                 NUM_ATTR_BYTES_g=NUM_ATTR_BYTES_z=j;
1068             }
1069             if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
1070                 ZCODE_HEADER_EXT_WORDS=j, flag=1;
1071             if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
1072                 ZCODE_HEADER_FLAGS_3=j, flag=1;
1073             if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
1074                 GLULX_OBJECT_EXT_BYTES=j, flag=1;
1075             if (strcmp(command,"MAX_STATIC_DATA")==0)
1076                 MAX_STATIC_DATA=j, flag=1;
1077             if (strcmp(command,"MAX_OLDEPTH")==0)
1078                 flag=2;
1079             if (strcmp(command,"MAX_ROUTINES")==0)
1080                 flag=2;
1081             if (strcmp(command,"MAX_GCONSTANTS")==0)
1082                 flag=2;
1083             if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
1084             {   MAX_PROP_TABLE_SIZE=j, flag=1;
1085                 MAX_PROP_TABLE_SIZE_g=MAX_PROP_TABLE_SIZE_z=j;
1086             }
1087             if (strcmp(command,"MAX_FORWARD_REFS")==0)
1088                 flag=2;
1089             if (strcmp(command,"STACK_SIZE")==0)
1090                 flag=2;
1091             if (strcmp(command,"STACK_LONG_SLOTS")==0)
1092                 flag=2;
1093             if (strcmp(command,"STACK_SHORT_LENGTH")==0)
1094                 flag=2;
1095             if (strcmp(command,"MAX_ABBREVS")==0)
1096                 MAX_ABBREVS=j, flag=1;
1097             if (strcmp(command,"MAX_DYNAMIC_STRINGS")==0)
1098             {   MAX_DYNAMIC_STRINGS=j, flag=1;
1099                 MAX_DYNAMIC_STRINGS_g=MAX_DYNAMIC_STRINGS_z=j;
1100             }
1101             if (strcmp(command,"MAX_ARRAYS")==0)
1102                 MAX_ARRAYS=j, flag=1;
1103             if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
1104                 MAX_EXPRESSION_NODES=j, flag=1;
1105             if (strcmp(command,"MAX_VERBS")==0)
1106                 MAX_VERBS=j, flag=1;
1107             if (strcmp(command,"MAX_VERBSPACE")==0)
1108                 MAX_VERBSPACE=j, flag=1;
1109             if (strcmp(command,"MAX_LABELS")==0)
1110                 MAX_LABELS=j, flag=1;
1111             if (strcmp(command,"MAX_LINESPACE")==0)
1112                 MAX_LINESPACE=j, flag=1;
1113             if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
1114                 MAX_NUM_STATIC_STRINGS=j, flag=1;
1115             if (strcmp(command,"MAX_STATIC_STRINGS")==0)
1116             {   MAX_STATIC_STRINGS=j, flag=1;
1117                 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
1118                     MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
1119             }
1120             if (strcmp(command,"MAX_ZCODE_SIZE")==0)
1121             {   MAX_ZCODE_SIZE=j, flag=1;
1122                 MAX_ZCODE_SIZE_g=MAX_ZCODE_SIZE_z=j;
1123             }
1124             if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
1125                 MAX_LINK_DATA_SIZE=j, flag=1;
1126             if (strcmp(command,"MAX_LOW_STRINGS")==0)
1127                 MAX_LOW_STRINGS=j, flag=1;
1128             if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
1129                 MAX_TRANSCRIPT_SIZE=j, flag=1;
1130             if (strcmp(command,"MAX_CLASSES")==0)
1131                 MAX_CLASSES=j, flag=1;
1132             if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
1133                 MAX_INCLUSION_DEPTH=j, flag=1;
1134             if (strcmp(command,"MAX_SOURCE_FILES")==0)
1135                 MAX_SOURCE_FILES=j, flag=1;
1136             if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
1137                 MAX_INDIV_PROP_TABLE_SIZE=j, flag=1;
1138             if (strcmp(command,"INDIV_PROP_START")==0)
1139                 INDIV_PROP_START=j, flag=1;
1140             if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
1141                 MAX_OBJ_PROP_TABLE_SIZE=j, flag=1;
1142             if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
1143                 MAX_OBJ_PROP_COUNT=j, flag=1;
1144             if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
1145             {   MAX_LOCAL_VARIABLES=j, flag=1;
1146                 MAX_LOCAL_VARIABLES_g=MAX_LOCAL_VARIABLES_z=j;
1147             }
1148             if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
1149             {   MAX_GLOBAL_VARIABLES=j, flag=1;
1150                 MAX_GLOBAL_VARIABLES_g=MAX_GLOBAL_VARIABLES_z=j;
1151             }
1152             if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
1153             {   ALLOC_CHUNK_SIZE=j, flag=1;
1154                 ALLOC_CHUNK_SIZE_g=ALLOC_CHUNK_SIZE_z=j;
1155             }
1156             if (strcmp(command,"MAX_UNICODE_CHARS")==0)
1157                 MAX_UNICODE_CHARS=j, flag=1;
1158             if (strcmp(command,"MAX_STACK_SIZE")==0)
1159             {
1160                 MAX_STACK_SIZE=j, flag=1;
1161                 /* Adjust up to a 256-byte boundary. */
1162                 MAX_STACK_SIZE = (MAX_STACK_SIZE + 0xFF) & (~0xFF);
1163             }
1164             if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
1165             {
1166                 MEMORY_MAP_EXTENSION=j, flag=1;
1167                 /* Adjust up to a 256-byte boundary. */
1168                 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
1169             }
1170             if (strcmp(command,"TRANSCRIPT_FORMAT")==0)
1171             {
1172                 TRANSCRIPT_FORMAT=j, flag=1;
1173                 if (TRANSCRIPT_FORMAT > 1 || TRANSCRIPT_FORMAT < 0)
1174                     TRANSCRIPT_FORMAT = 1;
1175             }
1176             if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
1177             {
1178                 WARN_UNUSED_ROUTINES=j, flag=1;
1179                 if (WARN_UNUSED_ROUTINES > 2 || WARN_UNUSED_ROUTINES < 0)
1180                     WARN_UNUSED_ROUTINES = 2;
1181             }
1182             if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
1183             {
1184                 OMIT_UNUSED_ROUTINES=j, flag=1;
1185                 if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
1186                     OMIT_UNUSED_ROUTINES = 1;
1187             }
1188             if (strcmp(command,"SERIAL")==0)
1189             {
1190                 if (j >= 0 && j <= 999999)
1191                 {
1192                     sprintf(serial_code_buffer,"%06d",j);
1193                     serial_code_given_in_program = TRUE;
1194                     flag=1;
1195                 }
1196             }
1197
1198             if (flag==0)
1199                 printf("No such memory setting as \"%s\"\n", command);
1200             if (flag==2)
1201             printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n\
1202 It should be safe to omit it (putting nothing in its place).\n", command);
1203             return;
1204         }
1205     }
1206     printf("No such memory $ command as \"%s\"\n",command);
1207 }
1208
1209 extern void print_memory_usage(void)
1210 {
1211     printf("Properties table used %d\n",
1212         properties_table_size);
1213     printf("Allocated a total of %ld bytes of memory\n",
1214         (long int) malloced_bytes);
1215 }
1216
1217 /* ========================================================================= */
1218 /*   Data structure management routines                                      */
1219 /* ------------------------------------------------------------------------- */
1220
1221 extern void init_memory_vars(void)
1222 {   malloced_bytes = 0;
1223 }
1224
1225 extern void memory_begin_pass(void) { }
1226
1227 extern void memory_allocate_arrays(void) { }
1228
1229 extern void memory_free_arrays(void) { }
1230
1231 /* ========================================================================= */