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