9b4a6693994ca37d54a323e6401bd1c197297423
[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 - 2020                                 */
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_EXPRESSION_NODES;
259 int MAX_VERBS;
260 int MAX_VERBSPACE;
261 int MAX_LABELS;
262 int MAX_LINESPACE;
263 int32 MAX_STATIC_STRINGS;
264 int32 MAX_ZCODE_SIZE;
265 int MAX_LOW_STRINGS;
266 int32 MAX_TRANSCRIPT_SIZE;
267 int MAX_CLASSES;
268 int32 MAX_LINK_DATA_SIZE;
269 int MAX_INCLUSION_DEPTH;
270 int MAX_SOURCE_FILES;
271 int32 MAX_INDIV_PROP_TABLE_SIZE;
272 int32 MAX_OBJ_PROP_TABLE_SIZE;
273 int MAX_OBJ_PROP_COUNT;
274 int MAX_LOCAL_VARIABLES;
275 int MAX_GLOBAL_VARIABLES;
276 int DICT_WORD_SIZE; /* number of characters in a dict word */
277 int DICT_CHAR_SIZE; /* (glulx) 1 for one-byte chars, 4 for Unicode chars */
278 int DICT_WORD_BYTES; /* DICT_WORD_SIZE*DICT_CHAR_SIZE */
279 int ZCODE_HEADER_EXT_WORDS; /* (zcode 1.0) requested header extension size */
280 int ZCODE_HEADER_FLAGS_3; /* (zcode 1.1) value to place in Flags 3 word */
281 int NUM_ATTR_BYTES;
282 int GLULX_OBJECT_EXT_BYTES; /* (glulx) extra bytes for each object record */
283 int32 MAX_NUM_STATIC_STRINGS;
284 int32 MAX_UNICODE_CHARS;
285 int32 MAX_STACK_SIZE;
286 int32 MEMORY_MAP_EXTENSION;
287 int ALLOC_CHUNK_SIZE;
288 int WARN_UNUSED_ROUTINES; /* 0: no, 1: yes except in system files, 2: yes always */
289 int OMIT_UNUSED_ROUTINES; /* 0: no, 1: yes */
290
291 /* The way memory sizes are set causes great nuisance for those parameters
292    which have different defaults under Z-code and Glulx. We have to get
293    the defaults right whether the user sets "-G $HUGE" or "$HUGE -G". 
294    And an explicit value set by the user should override both defaults. */
295 static int32 MAX_ZCODE_SIZE_z, MAX_ZCODE_SIZE_g;
296 static int MAX_PROP_TABLE_SIZE_z, MAX_PROP_TABLE_SIZE_g;
297 static int MAX_GLOBAL_VARIABLES_z, MAX_GLOBAL_VARIABLES_g;
298 static int MAX_LOCAL_VARIABLES_z, MAX_LOCAL_VARIABLES_g;
299 static int DICT_WORD_SIZE_z, DICT_WORD_SIZE_g;
300 static int NUM_ATTR_BYTES_z, NUM_ATTR_BYTES_g;
301 static int ALLOC_CHUNK_SIZE_z, ALLOC_CHUNK_SIZE_g;
302
303 /* ------------------------------------------------------------------------- */
304 /*   Memory control from the command line                                    */
305 /* ------------------------------------------------------------------------- */
306
307 static void list_memory_sizes(void)
308 {   printf("+--------------------------------------+\n");
309     printf("|  %25s = %-7s |\n","Memory setting","Value");
310     printf("+--------------------------------------+\n");
311     printf("|  %25s = %-7d |\n","MAX_ABBREVS",MAX_ABBREVS);
312     printf("|  %25s = %-7d |\n","MAX_ACTIONS",MAX_ACTIONS);
313     printf("|  %25s = %-7d |\n","MAX_ADJECTIVES",MAX_ADJECTIVES);
314     printf("|  %25s = %-7d |\n","ALLOC_CHUNK_SIZE",ALLOC_CHUNK_SIZE);
315     printf("|  %25s = %-7d |\n","MAX_ARRAYS",MAX_ARRAYS);
316     printf("|  %25s = %-7d |\n","NUM_ATTR_BYTES",NUM_ATTR_BYTES);
317     printf("|  %25s = %-7d |\n","MAX_CLASSES",MAX_CLASSES);
318     printf("|  %25s = %-7d |\n","MAX_DICT_ENTRIES",MAX_DICT_ENTRIES);
319     printf("|  %25s = %-7d |\n","DICT_WORD_SIZE",DICT_WORD_SIZE);
320     if (glulx_mode)
321       printf("|  %25s = %-7d |\n","DICT_CHAR_SIZE",DICT_CHAR_SIZE);
322     printf("|  %25s = %-7d |\n","MAX_EXPRESSION_NODES",MAX_EXPRESSION_NODES);
323     printf("|  %25s = %-7d |\n","MAX_GLOBAL_VARIABLES",MAX_GLOBAL_VARIABLES);
324     printf("|  %25s = %-7d |\n","HASH_TAB_SIZE",HASH_TAB_SIZE);
325     if (!glulx_mode)
326       printf("|  %25s = %-7d |\n","ZCODE_HEADER_EXT_WORDS",ZCODE_HEADER_EXT_WORDS);
327     if (!glulx_mode)
328       printf("|  %25s = %-7d |\n","ZCODE_HEADER_FLAGS_3",ZCODE_HEADER_FLAGS_3);
329     printf("|  %25s = %-7d |\n","MAX_INCLUSION_DEPTH",MAX_INCLUSION_DEPTH);
330     printf("|  %25s = %-7d |\n","MAX_INDIV_PROP_TABLE_SIZE", MAX_INDIV_PROP_TABLE_SIZE);
331     printf("|  %25s = %-7d |\n","INDIV_PROP_START", INDIV_PROP_START);
332     printf("|  %25s = %-7d |\n","MAX_LABELS",MAX_LABELS);
333     printf("|  %25s = %-7d |\n","MAX_LINESPACE",MAX_LINESPACE);
334     printf("|  %25s = %-7d |\n","MAX_LINK_DATA_SIZE",MAX_LINK_DATA_SIZE);
335     if (glulx_mode)
336       printf("|  %25s = %-7d |\n","MAX_LOCAL_VARIABLES",MAX_LOCAL_VARIABLES);
337     printf("|  %25s = %-7d |\n","MAX_LOW_STRINGS",MAX_LOW_STRINGS);
338     if (glulx_mode)
339       printf("|  %25s = %-7d |\n","MEMORY_MAP_EXTENSION",
340         MEMORY_MAP_EXTENSION);
341     if (glulx_mode)
342       printf("|  %25s = %-7d |\n","MAX_NUM_STATIC_STRINGS",
343         MAX_NUM_STATIC_STRINGS);
344     printf("|  %25s = %-7d |\n","MAX_OBJECTS",MAX_OBJECTS);
345     if (glulx_mode)
346       printf("|  %25s = %-7d |\n","GLULX_OBJECT_EXT_BYTES",
347         GLULX_OBJECT_EXT_BYTES);
348     if (glulx_mode)
349       printf("|  %25s = %-7d |\n","MAX_OBJ_PROP_COUNT",
350         MAX_OBJ_PROP_COUNT);
351     if (glulx_mode)
352       printf("|  %25s = %-7d |\n","MAX_OBJ_PROP_TABLE_SIZE",
353         MAX_OBJ_PROP_TABLE_SIZE);
354     printf("|  %25s = %-7d |\n","MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
355     printf("|  %25s = %-7d |\n","MAX_QTEXT_SIZE",MAX_QTEXT_SIZE);
356     printf("|  %25s = %-7d |\n","MAX_SOURCE_FILES",MAX_SOURCE_FILES);
357     if (glulx_mode)
358       printf("|  %25s = %-7ld |\n","MAX_STACK_SIZE",
359            (long int) MAX_STACK_SIZE);
360     printf("|  %25s = %-7d |\n","MAX_STATIC_DATA",MAX_STATIC_DATA);
361     printf("|  %25s = %-7ld |\n","MAX_STATIC_STRINGS",
362            (long int) MAX_STATIC_STRINGS);
363     printf("|  %25s = %-7d |\n","MAX_SYMBOLS",MAX_SYMBOLS);
364     printf("|  %25s = %-7d |\n","SYMBOLS_CHUNK_SIZE",SYMBOLS_CHUNK_SIZE);
365     printf("|  %25s = %-7ld |\n","MAX_TRANSCRIPT_SIZE",
366            (long int) MAX_TRANSCRIPT_SIZE);
367     if (glulx_mode)
368       printf("|  %25s = %-7ld |\n","MAX_UNICODE_CHARS",
369            (long int) MAX_UNICODE_CHARS);
370     printf("|  %25s = %-7d |\n","WARN_UNUSED_ROUTINES",WARN_UNUSED_ROUTINES);
371     printf("|  %25s = %-7d |\n","OMIT_UNUSED_ROUTINES",OMIT_UNUSED_ROUTINES);
372     printf("|  %25s = %-7d |\n","MAX_VERBS",MAX_VERBS);
373     printf("|  %25s = %-7d |\n","MAX_VERBSPACE",MAX_VERBSPACE);
374     printf("|  %25s = %-7ld |\n","MAX_ZCODE_SIZE",
375            (long int) MAX_ZCODE_SIZE);
376     printf("+--------------------------------------+\n");
377 }
378
379 extern void set_memory_sizes(int size_flag)
380 {
381     if (size_flag == HUGE_SIZE)
382     {
383         MAX_QTEXT_SIZE  = 4000;
384         MAX_SYMBOLS     = 10000;
385
386         SYMBOLS_CHUNK_SIZE = 5000;
387         HASH_TAB_SIZE      = 512;
388
389         MAX_OBJECTS = 640;
390
391         MAX_ACTIONS      = 200;
392         MAX_ADJECTIVES   = 50;
393         MAX_DICT_ENTRIES = 2000;
394         MAX_STATIC_DATA  = 10000;
395
396         MAX_PROP_TABLE_SIZE_z = 30000;
397         MAX_PROP_TABLE_SIZE_g = 60000;
398
399         MAX_ABBREVS = 64;
400
401         MAX_EXPRESSION_NODES = 100;
402         MAX_VERBS = 200;
403         MAX_VERBSPACE = 4096;
404         MAX_LABELS = 1000;
405         MAX_LINESPACE = 16000;
406
407         MAX_STATIC_STRINGS = 8000;
408         MAX_ZCODE_SIZE_z = 20000;
409         MAX_ZCODE_SIZE_g = 40000;
410         MAX_LINK_DATA_SIZE = 2000;
411
412         MAX_LOW_STRINGS = 2048;
413
414         MAX_TRANSCRIPT_SIZE = 200000;
415         MAX_NUM_STATIC_STRINGS = 20000;
416
417         MAX_CLASSES = 64;
418
419         MAX_OBJ_PROP_COUNT = 128;
420         MAX_OBJ_PROP_TABLE_SIZE = 4096;
421
422         MAX_INDIV_PROP_TABLE_SIZE = 15000;
423         MAX_ARRAYS = 128;
424
425         MAX_GLOBAL_VARIABLES_z = 240;
426         MAX_GLOBAL_VARIABLES_g = 512;
427         
428         ALLOC_CHUNK_SIZE_z = 8192;
429         ALLOC_CHUNK_SIZE_g = 32768;
430     }
431     if (size_flag == LARGE_SIZE)
432     {
433         MAX_QTEXT_SIZE  = 4000;
434         MAX_SYMBOLS     = 6400;
435
436         SYMBOLS_CHUNK_SIZE = 5000;
437         HASH_TAB_SIZE      = 512;
438
439         MAX_OBJECTS = 512;
440
441         MAX_ACTIONS      = 200;
442         MAX_ADJECTIVES   = 50;
443         MAX_DICT_ENTRIES = 1300;
444         MAX_STATIC_DATA  = 10000;
445
446         MAX_PROP_TABLE_SIZE_z = 15000;
447         MAX_PROP_TABLE_SIZE_g = 30000;
448
449         MAX_ABBREVS = 64;
450
451         MAX_EXPRESSION_NODES = 100;
452         MAX_VERBS = 140;
453         MAX_VERBSPACE = 4096;
454         MAX_LINESPACE = 10000;
455
456         MAX_LABELS = 1000;
457         MAX_STATIC_STRINGS = 8000;
458         MAX_ZCODE_SIZE_z = 20000;
459         MAX_ZCODE_SIZE_g = 40000;
460         MAX_LINK_DATA_SIZE = 2000;
461
462         MAX_LOW_STRINGS = 2048;
463
464         MAX_TRANSCRIPT_SIZE = 200000;
465         MAX_NUM_STATIC_STRINGS = 20000;
466
467         MAX_CLASSES = 64;
468
469         MAX_OBJ_PROP_COUNT = 64;
470         MAX_OBJ_PROP_TABLE_SIZE = 2048;
471
472         MAX_INDIV_PROP_TABLE_SIZE = 10000;
473         MAX_ARRAYS = 128;
474
475         MAX_GLOBAL_VARIABLES_z = 240;
476         MAX_GLOBAL_VARIABLES_g = 512;
477         
478         ALLOC_CHUNK_SIZE_z = 8192;
479         ALLOC_CHUNK_SIZE_g = 16384;
480     }
481     if (size_flag == SMALL_SIZE)
482     {
483         MAX_QTEXT_SIZE  = 4000;
484         MAX_SYMBOLS     = 3000;
485
486         SYMBOLS_CHUNK_SIZE = 2500;
487         HASH_TAB_SIZE      = 512;
488
489         MAX_OBJECTS = 300;
490
491         MAX_ACTIONS      = 200;
492         MAX_ADJECTIVES   = 50;
493         MAX_DICT_ENTRIES = 700;
494         MAX_STATIC_DATA  = 10000;
495
496         MAX_PROP_TABLE_SIZE_z = 8000;
497         MAX_PROP_TABLE_SIZE_g = 16000;
498
499         MAX_ABBREVS = 64;
500
501         MAX_EXPRESSION_NODES = 40;
502         MAX_VERBS = 110;
503         MAX_VERBSPACE = 2048;
504         MAX_LINESPACE = 10000;
505         MAX_LABELS = 1000;
506
507         MAX_STATIC_STRINGS = 8000;
508         MAX_ZCODE_SIZE_z = 10000;
509         MAX_ZCODE_SIZE_g = 20000;
510         MAX_LINK_DATA_SIZE = 1000;
511
512         MAX_LOW_STRINGS = 1024;
513
514         MAX_TRANSCRIPT_SIZE = 100000;
515         MAX_NUM_STATIC_STRINGS = 10000;
516
517         MAX_CLASSES = 32;
518
519         MAX_OBJ_PROP_COUNT = 64;
520         MAX_OBJ_PROP_TABLE_SIZE = 1024;
521
522         MAX_INDIV_PROP_TABLE_SIZE = 5000;
523         MAX_ARRAYS = 64;
524
525         MAX_GLOBAL_VARIABLES_z = 240;
526         MAX_GLOBAL_VARIABLES_g = 256;
527         
528         ALLOC_CHUNK_SIZE_z = 8192;
529         ALLOC_CHUNK_SIZE_g = 8192;
530     }
531
532     /* Regardless of size_flag... */
533     MAX_SOURCE_FILES = 256;
534     MAX_INCLUSION_DEPTH = 5;
535     MAX_LOCAL_VARIABLES_z = 16;
536     MAX_LOCAL_VARIABLES_g = 32;
537     DICT_CHAR_SIZE = 1;
538     DICT_WORD_SIZE_z = 6;
539     DICT_WORD_SIZE_g = 9;
540     NUM_ATTR_BYTES_z = 6;
541     NUM_ATTR_BYTES_g = 7;
542     /* Backwards-compatible behavior: allow for a unicode table
543        whether we need one or not. The user can set this to zero if
544        there's no unicode table. */
545     ZCODE_HEADER_EXT_WORDS = 3;
546     ZCODE_HEADER_FLAGS_3 = 0;
547     GLULX_OBJECT_EXT_BYTES = 0;
548     MAX_UNICODE_CHARS = 64;
549     MEMORY_MAP_EXTENSION = 0;
550     /* We estimate the default Glulx stack size at 4096. That's about
551        enough for 90 nested function calls with 8 locals each -- the
552        same capacity as the Z-Spec's suggestion for Z-machine stack
553        size. Note that Inform 7 wants more stack; I7-generated code
554        sets MAX_STACK_SIZE to 65536 by default. */
555     MAX_STACK_SIZE = 4096;
556     OMIT_UNUSED_ROUTINES = 0;
557     WARN_UNUSED_ROUTINES = 0;
558
559     adjust_memory_sizes();
560 }
561
562 extern void adjust_memory_sizes()
563 {
564   if (!glulx_mode) {
565     MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_z;
566     MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_z;
567     MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_z;
568     MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_z;
569     DICT_WORD_SIZE = DICT_WORD_SIZE_z;
570     NUM_ATTR_BYTES = NUM_ATTR_BYTES_z;
571     ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_z;
572     INDIV_PROP_START = 64;
573   }
574   else {
575     MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_g;
576     MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_g;
577     MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_g;
578     MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_g;
579     DICT_WORD_SIZE = DICT_WORD_SIZE_g;
580     NUM_ATTR_BYTES = NUM_ATTR_BYTES_g;
581     ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_g;
582     INDIV_PROP_START = 256;
583   }
584 }
585
586 static void explain_parameter(char *command)
587 {   printf("\n");
588     if (strcmp(command,"MAX_QTEXT_SIZE")==0)
589     {   printf(
590 "  MAX_QTEXT_SIZE is the maximum length of a quoted string.  Increasing\n\
591    by 1 costs 5 bytes (for lexical analysis memory).  Inform automatically\n\
592    ensures that MAX_STATIC_STRINGS is at least twice the size of this.");
593         return;
594     }
595     if (strcmp(command,"MAX_SYMBOLS")==0)
596     {   printf(
597 "  MAX_SYMBOLS is the maximum number of symbols - names of variables, \n\
598   objects, routines, the many internal Inform-generated names and so on.\n");
599         return;
600     }
601     if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
602     {   printf(
603 "  The symbols names are stored in memory which is allocated in chunks \n\
604   of size SYMBOLS_CHUNK_SIZE.\n");
605         return;
606     }
607     if (strcmp(command,"HASH_TAB_SIZE")==0)
608     {   printf(
609 "  HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
610   symbols banks.\n");
611         return;
612     }
613     if (strcmp(command,"MAX_OBJECTS")==0)
614     {   printf(
615 "  MAX_OBJECTS is the maximum number of objects.  (If compiling a version-3 \n\
616   game, 255 is an absolute maximum in any event.)\n");
617         return;
618     }
619     if (strcmp(command,"MAX_ACTIONS")==0)
620     {   printf(
621 "  MAX_ACTIONS is the maximum number of actions - that is, routines such as \n\
622   TakeSub which are referenced in the grammar table.\n");
623         return;
624     }
625     if (strcmp(command,"MAX_ADJECTIVES")==0)
626     {   printf(
627 "  MAX_ADJECTIVES is the maximum number of different \"adjectives\" in the \n\
628   grammar table.  Adjectives are misleadingly named: they are words such as \n\
629   \"in\", \"under\" and the like.\n");
630         return;
631     }
632     if (strcmp(command,"MAX_DICT_ENTRIES")==0)
633     {   printf(
634 "  MAX_DICT_ENTRIES is the maximum number of words which can be entered \n\
635   into the game's dictionary.  It costs 29 bytes to increase this by one.\n");
636         return;
637     }
638     if (strcmp(command,"DICT_WORD_SIZE")==0)
639     {   printf(
640 "  DICT_WORD_SIZE is the number of characters in a dictionary word. In \n\
641   Z-code this is always 6 (only 4 are used in v3 games). In Glulx it \n\
642   can be any number.\n");
643         return;
644     }
645     if (strcmp(command,"DICT_CHAR_SIZE")==0)
646     {   printf(
647 "  DICT_CHAR_SIZE is the byte size of one character in the dictionary. \n\
648   (This is only meaningful in Glulx, since Z-code has compressed dictionary \n\
649   words.) It can be either 1 (the default) or 4 (to enable full Unicode \n\
650   input.)\n");
651         return;
652     }
653     if (strcmp(command,"NUM_ATTR_BYTES")==0)
654     {   printf(
655 "  NUM_ATTR_BYTES is the space used to store attribute flags. Each byte \n\
656   stores eight attributes. In Z-code this is always 6 (only 4 are used in \n\
657   v3 games). In Glulx it can be any number which is a multiple of four, \n\
658   plus three.\n");
659         return;
660     }
661     if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
662     {   printf(
663 "  ZCODE_HEADER_EXT_WORDS is the number of words in the Z-code header \n\
664   extension table (Z-Spec 1.0). The -W switch also sets this. It defaults \n\
665   to 3, but can be set higher. (It can be set lower if no Unicode \n\
666   translation table is created.)\n");
667         return;
668     }
669     if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
670     {   printf(
671 "  ZCODE_HEADER_FLAGS_3 is the value to store in the Flags 3 word of the \n\
672   header extension table (Z-Spec 1.1).\n");
673         return;
674     }
675     if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
676     {   printf(
677 "  GLULX_OBJECT_EXT_BYTES is an amount of additional space to add to each \n\
678   object record. It is initialized to zero bytes, and the game is free to \n\
679   use it as desired. (This is only meaningful in Glulx, since Z-code \n\
680   specifies the object structure.)\n");
681         return;
682     }
683     if (strcmp(command,"MAX_STATIC_DATA")==0)
684     {   printf(
685 "  MAX_STATIC_DATA is the size of an array of integers holding initial \n\
686   values for arrays and strings stored as ASCII inside the Z-machine.  It \n\
687   should be at least 1024 but seldom needs much more.\n");
688         return;
689     }
690     if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
691     {   printf(
692 "  MAX_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
693   properties table.\n");
694         return;
695     }
696     if (strcmp(command,"MAX_ABBREVS")==0)
697     {   printf(
698 "  MAX_ABBREVS is the maximum number of declared abbreviations.  It is not \n\
699   allowed to exceed 64.\n");
700         return;
701     }
702     if (strcmp(command,"MAX_ARRAYS")==0)
703     {   printf(
704 "  MAX_ARRAYS is the maximum number of declared arrays.\n");
705         return;
706     }
707     if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
708     {   printf(
709 "  MAX_EXPRESSION_NODES is the maximum number of nodes in the expression \n\
710   evaluator's storage for parse trees.  In effect, it measures how \n\
711   complicated algebraic expressions are allowed to be.  Increasing it by \n\
712   one costs about 80 bytes.\n");
713         return;
714     }
715     if (strcmp(command,"MAX_VERBS")==0)
716     {   printf(
717 "  MAX_VERBS is the maximum number of verbs (such as \"take\") which can be \n\
718   defined, each with its own grammar.  To increase it by one costs about\n\
719   128 bytes.  A full game will contain at least 100.\n");
720         return;
721     }
722     if (strcmp(command,"MAX_VERBSPACE")==0)
723     {   printf(
724 "  MAX_VERBSPACE is the size of workspace used to store verb words, so may\n\
725   need increasing in games with many synonyms: unlikely to exceed 4K.\n");
726         return;
727     }
728     if (strcmp(command,"MAX_LABELS")==0)
729     {   printf(
730 "  MAX_LABELS is the maximum number of label points in any one routine.\n\
731   (If the -k debugging information switch is set, MAX_LABELS is raised to\n\
732   a minimum level of 2000, as about twice the normal number of label points\n\
733   are needed to generate tables of how source code corresponds to positions\n\
734   in compiled code.)");
735         return;
736     }
737     if (strcmp(command,"MAX_LINESPACE")==0)
738     {   printf(
739 "  MAX_LINESPACE is the size of workspace used to store grammar lines, so \n\
740   may need increasing in games with complex or extensive grammars.\n");
741         return;
742     }
743     if (strcmp(command,"MAX_STATIC_STRINGS")==0)
744     {
745         printf(
746 "  MAX_STATIC_STRINGS is the size in bytes of a buffer to hold compiled\n\
747   strings before they're written into longer-term storage.  2000 bytes is \n\
748   plenty, allowing string constants of up to about 3000 characters long.\n\
749   Inform automatically ensures that this is at least twice the size of\n\
750   MAX_QTEXT_SIZE, to be on the safe side.");
751         return;
752     }
753     if (strcmp(command,"MAX_ZCODE_SIZE")==0)
754     {
755         printf(
756 "  MAX_ZCODE_SIZE is the size in bytes of a buffer to hold compiled \n\
757   code for a single routine.  (It applies to both Z-code and Glulx, \n\
758   despite the name.)  As a guide, the longest library routine is \n\
759   about 6500 bytes long in Z-code; about twice that in Glulx.");
760         return;
761     }
762     if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
763     {
764         printf(
765 "  MAX_LINK_DATA_SIZE is the size in bytes of a buffer to hold module \n\
766   link data before it's written into longer-term storage.  2000 bytes \n\
767   is plenty.");
768         return;
769     }
770     if (strcmp(command,"MAX_LOW_STRINGS")==0)
771     {   printf(
772 "  MAX_LOW_STRINGS is the size in bytes of a buffer to hold all the \n\
773   compiled \"low strings\" which are to be written above the synonyms table \n\
774   in the Z-machine.  1024 is plenty.\n");
775         return;
776     }
777     if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
778     {   printf(
779 "  MAX_TRANSCRIPT_SIZE is only allocated for the abbreviations optimisation \n\
780   switch, and has the size in bytes of a buffer to hold the entire text of\n\
781   the game being compiled: it has to be enormous, say 100000 to 200000.\n");
782         return;
783     }
784     if (strcmp(command,"MAX_CLASSES")==0)
785     {   printf(
786 "  MAX_CLASSES maximum number of object classes which can be defined.  This\n\
787   is cheap to increase.\n");
788         return;
789     }
790     if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
791     {   printf(
792 "  MAX_INCLUSION_DEPTH is the number of nested includes permitted.\n");
793         return;
794     }
795     if (strcmp(command,"MAX_SOURCE_FILES")==0)
796     {   printf(
797 "  MAX_SOURCE_FILES is the number of source files that can be read in the \n\
798   compilation.\n");
799         return;
800     }
801     if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
802     {   printf(
803 "  MAX_INDIV_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
804   table of ..variable values.\n");
805         return;
806     }
807     if (strcmp(command,"INDIV_PROP_START")==0)
808     {   printf(
809 "  Properties 1 to INDIV_PROP_START-1 are common properties; individual\n\
810   properties are numbered INDIV_PROP_START and up.\n");
811         return;
812     }
813     if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
814     {   printf(
815 "  MAX_OBJ_PROP_COUNT is the maximum number of properties a single object \n\
816   can have. (Glulx only)\n");
817         return;
818     }
819     if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
820     {   printf(
821 "  MAX_OBJ_PROP_TABLE_SIZE is the number of words allocated to hold a \n\
822   single object's properties. (Glulx only)\n");
823         return;
824     }
825     if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
826     {   printf(
827 "  MAX_LOCAL_VARIABLES is the number of local variables (including \n\
828   arguments) allowed in a procedure. (Glulx only)\n");
829         return;
830     }
831     if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
832     {   printf(
833 "  MAX_GLOBAL_VARIABLES is the number of global variables allowed in the \n\
834   program. (Glulx only)\n");
835         return;
836     }
837     if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
838     {
839         printf(
840 "  MAX_NUM_STATIC_STRINGS is the maximum number of compiled strings \n\
841   allowed in the program. (Glulx only)\n");
842         return;
843     }
844     if (strcmp(command,"MAX_UNICODE_CHARS")==0)
845     {
846         printf(
847 "  MAX_UNICODE_CHARS is the maximum number of different Unicode characters \n\
848   (beyond the Latin-1 range, $00..$FF) which the game text can use. \n\
849   (Glulx only)\n");
850         return;
851     }
852     if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
853     {
854         printf(
855 "  ALLOC_CHUNK_SIZE is a base unit of Inform's internal memory allocation \n\
856   for various structures.\n");
857         return;
858     }
859     if (strcmp(command,"MAX_STACK_SIZE")==0)
860     {
861         printf(
862 "  MAX_STACK_SIZE is the maximum size (in bytes) of the interpreter stack \n\
863   during gameplay. (Glulx only)\n");
864         return;
865     }
866     if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
867     {
868         printf(
869 "  MEMORY_MAP_EXTENSION is the number of bytes (all zeroes) to map into \n\
870   memory after the game file. (Glulx only)\n");
871         return;
872     }
873     if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
874     {
875         printf(
876 "  WARN_UNUSED_ROUTINES, if set to 2, will display a warning for each \n\
877   routine in the game file which is never called. (This includes \n\
878   routines called only from uncalled routines, etc.) If set to 1, will warn \n\
879   only about functions in game code, not in the system library.\n");
880         return;
881     }
882     if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
883     {
884         printf(
885 "  OMIT_UNUSED_ROUTINES, if set to 1, will avoid compiling unused routines \n\
886   into the game file.\n");
887         return;
888     }
889     if (strcmp(command,"SERIAL")==0)
890     {
891         printf(
892 "  SERIAL, if set, will be used as the six digit serial number written into \n\
893   the header of the output file.\n");
894         return;
895     }
896
897     printf("No such memory setting as \"%s\"\n",command);
898
899     return;
900 }
901
902 /* Parse a decimal number as an int32. Return true if a valid number
903    was found; otherwise print a warning and return false.
904
905    Anything over nine digits is considered an overflow; we report a
906    warning but return +/- 999999999 (and true). This is not entirely
907    clever about leading zeroes ("0000000001" is treated as an
908    overflow) but this is better than trying to detect genuine
909    overflows in a long.
910
911    (Some Glulx settings might conceivably want to go up to $7FFFFFFF,
912    which is a ten-digit number, but we're not going to allow that
913    today.)
914
915    This used to rely on atoi(), and we retain the atoi() behavior of
916    ignoring garbage characters after a valid decimal number.
917  */
918 static int parse_memory_setting(char *str, char *label, int32 *result)
919 {
920     char *cx = str;
921     char *ex;
922     long val;
923
924     *result = 0;
925
926     while (*cx == ' ') cx++;
927
928     val = strtol(cx, &ex, 10);    
929
930     if (ex == cx) {
931         printf("Bad numerical setting in $ command \"%s=%s\"\n",
932             label, str);
933         return 0;
934     }
935
936     if (*cx == '-') {
937         if (ex > cx+10) {
938             val = -999999999;
939             printf("Numerical setting underflowed in $ command \"%s=%s\" (limiting to %ld)\n",
940                 label, str, val);
941         }
942     }
943     else {
944         if (ex > cx+9) {
945             val = 999999999;
946             printf("Numerical setting overflowed in $ command \"%s=%s\" (limiting to %ld)\n",
947                 label, str, val);
948         }
949     }
950
951     *result = (int32)val;
952     return 1;
953 }
954
955 extern void memory_command(char *command)
956 {   int i, k, flag=0; int32 j;
957
958     for (k=0; command[k]!=0; k++)
959         if (islower(command[k])) command[k]=toupper(command[k]);
960
961     if (command[0]=='?') { explain_parameter(command+1); return; }
962
963     if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; }
964     if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; }
965     if (strcmp(command, "SMALL")==0) { set_memory_sizes(SMALL_SIZE); return; }
966     if (strcmp(command, "LIST")==0)  { list_memory_sizes(); return; }
967     for (i=0; command[i]!=0; i++)
968     {   if (command[i]=='=')
969         {   command[i]=0;
970             if (!parse_memory_setting(command+i+1, command, &j)) {
971                 return;
972             }
973             if (strcmp(command,"BUFFER_LENGTH")==0)
974                 flag=2;
975             if (strcmp(command,"MAX_QTEXT_SIZE")==0)
976             {   MAX_QTEXT_SIZE=j, flag=1;
977                 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
978                     MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
979             }
980             if (strcmp(command,"MAX_SYMBOLS")==0)
981                 MAX_SYMBOLS=j, flag=1;
982             if (strcmp(command,"MAX_BANK_SIZE")==0)
983                 flag=2;
984             if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
985                 SYMBOLS_CHUNK_SIZE=j, flag=1;
986             if (strcmp(command,"BANK_CHUNK_SIZE")==0)
987                 flag=2;
988             if (strcmp(command,"HASH_TAB_SIZE")==0)
989                 HASH_TAB_SIZE=j, flag=1;
990             if (strcmp(command,"MAX_OBJECTS")==0)
991                 MAX_OBJECTS=j, flag=1;
992             if (strcmp(command,"MAX_ACTIONS")==0)
993                 MAX_ACTIONS=j, flag=1;
994             if (strcmp(command,"MAX_ADJECTIVES")==0)
995                 MAX_ADJECTIVES=j, flag=1;
996             if (strcmp(command,"MAX_DICT_ENTRIES")==0)
997                 MAX_DICT_ENTRIES=j, flag=1;
998             if (strcmp(command,"DICT_WORD_SIZE")==0) 
999             {   DICT_WORD_SIZE=j, flag=1;
1000                 DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j;
1001             }
1002             if (strcmp(command,"DICT_CHAR_SIZE")==0)
1003                 DICT_CHAR_SIZE=j, flag=1;
1004             if (strcmp(command,"NUM_ATTR_BYTES")==0) 
1005             {   NUM_ATTR_BYTES=j, flag=1;
1006                 NUM_ATTR_BYTES_g=NUM_ATTR_BYTES_z=j;
1007             }
1008             if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
1009                 ZCODE_HEADER_EXT_WORDS=j, flag=1;
1010             if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
1011                 ZCODE_HEADER_FLAGS_3=j, flag=1;
1012             if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
1013                 GLULX_OBJECT_EXT_BYTES=j, flag=1;
1014             if (strcmp(command,"MAX_STATIC_DATA")==0)
1015                 MAX_STATIC_DATA=j, flag=1;
1016             if (strcmp(command,"MAX_OLDEPTH")==0)
1017                 flag=2;
1018             if (strcmp(command,"MAX_ROUTINES")==0)
1019                 flag=2;
1020             if (strcmp(command,"MAX_GCONSTANTS")==0)
1021                 flag=2;
1022             if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
1023             {   MAX_PROP_TABLE_SIZE=j, flag=1;
1024                 MAX_PROP_TABLE_SIZE_g=MAX_PROP_TABLE_SIZE_z=j;
1025             }
1026             if (strcmp(command,"MAX_FORWARD_REFS")==0)
1027                 flag=2;
1028             if (strcmp(command,"STACK_SIZE")==0)
1029                 flag=2;
1030             if (strcmp(command,"STACK_LONG_SLOTS")==0)
1031                 flag=2;
1032             if (strcmp(command,"STACK_SHORT_LENGTH")==0)
1033                 flag=2;
1034             if (strcmp(command,"MAX_ABBREVS")==0)
1035                 MAX_ABBREVS=j, flag=1;
1036             if (strcmp(command,"MAX_ARRAYS")==0)
1037                 MAX_ARRAYS=j, flag=1;
1038             if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
1039                 MAX_EXPRESSION_NODES=j, flag=1;
1040             if (strcmp(command,"MAX_VERBS")==0)
1041                 MAX_VERBS=j, flag=1;
1042             if (strcmp(command,"MAX_VERBSPACE")==0)
1043                 MAX_VERBSPACE=j, flag=1;
1044             if (strcmp(command,"MAX_LABELS")==0)
1045                 MAX_LABELS=j, flag=1;
1046             if (strcmp(command,"MAX_LINESPACE")==0)
1047                 MAX_LINESPACE=j, flag=1;
1048             if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
1049                 MAX_NUM_STATIC_STRINGS=j, flag=1;
1050             if (strcmp(command,"MAX_STATIC_STRINGS")==0)
1051             {   MAX_STATIC_STRINGS=j, flag=1;
1052                 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
1053                     MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
1054             }
1055             if (strcmp(command,"MAX_ZCODE_SIZE")==0)
1056             {   MAX_ZCODE_SIZE=j, flag=1;
1057                 MAX_ZCODE_SIZE_g=MAX_ZCODE_SIZE_z=j;
1058             }
1059             if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
1060                 MAX_LINK_DATA_SIZE=j, flag=1;
1061             if (strcmp(command,"MAX_LOW_STRINGS")==0)
1062                 MAX_LOW_STRINGS=j, flag=1;
1063             if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
1064                 MAX_TRANSCRIPT_SIZE=j, flag=1;
1065             if (strcmp(command,"MAX_CLASSES")==0)
1066                 MAX_CLASSES=j, flag=1;
1067             if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
1068                 MAX_INCLUSION_DEPTH=j, flag=1;
1069             if (strcmp(command,"MAX_SOURCE_FILES")==0)
1070                 MAX_SOURCE_FILES=j, flag=1;
1071             if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
1072                 MAX_INDIV_PROP_TABLE_SIZE=j, flag=1;
1073             if (strcmp(command,"INDIV_PROP_START")==0)
1074                 INDIV_PROP_START=j, flag=1;
1075             if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
1076                 MAX_OBJ_PROP_TABLE_SIZE=j, flag=1;
1077             if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
1078                 MAX_OBJ_PROP_COUNT=j, flag=1;
1079             if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
1080             {   MAX_LOCAL_VARIABLES=j, flag=1;
1081                 MAX_LOCAL_VARIABLES_g=MAX_LOCAL_VARIABLES_z=j;
1082             }
1083             if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
1084             {   MAX_GLOBAL_VARIABLES=j, flag=1;
1085                 MAX_GLOBAL_VARIABLES_g=MAX_GLOBAL_VARIABLES_z=j;
1086             }
1087             if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
1088             {   ALLOC_CHUNK_SIZE=j, flag=1;
1089                 ALLOC_CHUNK_SIZE_g=ALLOC_CHUNK_SIZE_z=j;
1090             }
1091             if (strcmp(command,"MAX_UNICODE_CHARS")==0)
1092                 MAX_UNICODE_CHARS=j, flag=1;
1093             if (strcmp(command,"MAX_STACK_SIZE")==0)
1094             {
1095                 MAX_STACK_SIZE=j, flag=1;
1096                 /* Adjust up to a 256-byte boundary. */
1097                 MAX_STACK_SIZE = (MAX_STACK_SIZE + 0xFF) & (~0xFF);
1098             }
1099             if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
1100             {
1101                 MEMORY_MAP_EXTENSION=j, flag=1;
1102                 /* Adjust up to a 256-byte boundary. */
1103                 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
1104             }
1105             if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
1106             {
1107                 WARN_UNUSED_ROUTINES=j, flag=1;
1108                 if (WARN_UNUSED_ROUTINES > 2 || WARN_UNUSED_ROUTINES < 0)
1109                     WARN_UNUSED_ROUTINES = 2;
1110             }
1111             if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
1112             {
1113                 OMIT_UNUSED_ROUTINES=j, flag=1;
1114                 if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
1115                     OMIT_UNUSED_ROUTINES = 1;
1116             }
1117             if (strcmp(command,"SERIAL")==0)
1118             {
1119                 if (j >= 0 && j <= 999999)
1120                 {
1121                     sprintf(serial_code_buffer,"%06d",j);
1122                     serial_code_given_in_program = TRUE;
1123                     flag=1;
1124                 }
1125             }
1126
1127             if (flag==0)
1128                 printf("No such memory setting as \"%s\"\n", command);
1129             if (flag==2)
1130             printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n\
1131 It should be safe to omit it (putting nothing in its place).\n", command);
1132             return;
1133         }
1134     }
1135     printf("No such memory $ command as \"%s\"\n",command);
1136 }
1137
1138 extern void print_memory_usage(void)
1139 {
1140     printf("Properties table used %d\n",
1141         properties_table_size);
1142     printf("Allocated a total of %ld bytes of memory\n",
1143         (long int) malloced_bytes);
1144 }
1145
1146 /* ========================================================================= */
1147 /*   Data structure management routines                                      */
1148 /* ------------------------------------------------------------------------- */
1149
1150 extern void init_memory_vars(void)
1151 {   malloced_bytes = 0;
1152 }
1153
1154 extern void memory_begin_pass(void) { }
1155
1156 extern void memory_allocate_arrays(void) { }
1157
1158 extern void memory_free_arrays(void) { }
1159
1160 /* ========================================================================= */