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