inform.c: Update the copyright year that gets printed out in light of the change...
[inform.git] / 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 - 2016                                   */
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",
323         MAX_INDIV_PROP_TABLE_SIZE);
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   }
565   else {
566     MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_g;
567     MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_g;
568     MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_g;
569     MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_g;
570     DICT_WORD_SIZE = DICT_WORD_SIZE_g;
571     NUM_ATTR_BYTES = NUM_ATTR_BYTES_g;
572     ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_g;
573   }
574 }
575
576 static void explain_parameter(char *command)
577 {   printf("\n");
578     if (strcmp(command,"MAX_QTEXT_SIZE")==0)
579     {   printf(
580 "  MAX_QTEXT_SIZE is the maximum length of a quoted string.  Increasing\n\
581    by 1 costs 5 bytes (for lexical analysis memory).  Inform automatically\n\
582    ensures that MAX_STATIC_STRINGS is at least twice the size of this.");
583         return;
584     }
585     if (strcmp(command,"MAX_SYMBOLS")==0)
586     {   printf(
587 "  MAX_SYMBOLS is the maximum number of symbols - names of variables, \n\
588   objects, routines, the many internal Inform-generated names and so on.\n");
589         return;
590     }
591     if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
592     {   printf(
593 "  The symbols names are stored in memory which is allocated in chunks \n\
594   of size SYMBOLS_CHUNK_SIZE.\n");
595         return;
596     }
597     if (strcmp(command,"HASH_TAB_SIZE")==0)
598     {   printf(
599 "  HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
600   symbols banks.\n");
601         return;
602     }
603     if (strcmp(command,"MAX_OBJECTS")==0)
604     {   printf(
605 "  MAX_OBJECTS is the maximum number of objects.  (If compiling a version-3 \n\
606   game, 255 is an absolute maximum in any event.)\n");
607         return;
608     }
609     if (strcmp(command,"MAX_ACTIONS")==0)
610     {   printf(
611 "  MAX_ACTIONS is the maximum number of actions - that is, routines such as \n\
612   TakeSub which are referenced in the grammar table.\n");
613         return;
614     }
615     if (strcmp(command,"MAX_ADJECTIVES")==0)
616     {   printf(
617 "  MAX_ADJECTIVES is the maximum number of different \"adjectives\" in the \n\
618   grammar table.  Adjectives are misleadingly named: they are words such as \n\
619   \"in\", \"under\" and the like.\n");
620         return;
621     }
622     if (strcmp(command,"MAX_DICT_ENTRIES")==0)
623     {   printf(
624 "  MAX_DICT_ENTRIES is the maximum number of words which can be entered \n\
625   into the game's dictionary.  It costs 29 bytes to increase this by one.\n");
626         return;
627     }
628     if (strcmp(command,"DICT_WORD_SIZE")==0)
629     {   printf(
630 "  DICT_WORD_SIZE is the number of characters in a dictionary word. In \n\
631   Z-code this is always 6 (only 4 are used in v3 games). In Glulx it \n\
632   can be any number.\n");
633         return;
634     }
635     if (strcmp(command,"DICT_CHAR_SIZE")==0)
636     {   printf(
637 "  DICT_CHAR_SIZE is the byte size of one character in the dictionary. \n\
638   (This is only meaningful in Glulx, since Z-code has compressed dictionary \n\
639   words.) It can be either 1 (the default) or 4 (to enable full Unicode \n\
640   input.)\n");
641         return;
642     }
643     if (strcmp(command,"NUM_ATTR_BYTES")==0)
644     {   printf(
645 "  NUM_ATTR_BYTES is the space used to store attribute flags. Each byte \n\
646   stores eight attributes. In Z-code this is always 6 (only 4 are used in \n\
647   v3 games). In Glulx it can be any number which is a multiple of four, \n\
648   plus three.\n");
649         return;
650     }
651     if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
652     {   printf(
653 "  ZCODE_HEADER_EXT_WORDS is the number of words in the Z-code header \n\
654   extension table (Z-Spec 1.0). The -W switch also sets this. It defaults \n\
655   to 3, but can be set higher. (It can be set lower if no Unicode \n\
656   translation table is created.)\n");
657         return;
658     }
659     if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
660     {   printf(
661 "  ZCODE_HEADER_FLAGS_3 is the value to store in the Flags 3 word of the \n\
662   header extension table (Z-Spec 1.1).\n");
663         return;
664     }
665     if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
666     {   printf(
667 "  GLULX_OBJECT_EXT_BYTES is an amount of additional space to add to each \n\
668   object record. It is initialized to zero bytes, and the game is free to \n\
669   use it as desired. (This is only meaningful in Glulx, since Z-code \n\
670   specifies the object structure.)\n");
671         return;
672     }
673     if (strcmp(command,"MAX_STATIC_DATA")==0)
674     {   printf(
675 "  MAX_STATIC_DATA is the size of an array of integers holding initial \n\
676   values for arrays and strings stored as ASCII inside the Z-machine.  It \n\
677   should be at least 1024 but seldom needs much more.\n");
678         return;
679     }
680     if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
681     {   printf(
682 "  MAX_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
683   properties table.\n");
684         return;
685     }
686     if (strcmp(command,"MAX_ABBREVS")==0)
687     {   printf(
688 "  MAX_ABBREVS is the maximum number of declared abbreviations.  It is not \n\
689   allowed to exceed 64.\n");
690         return;
691     }
692     if (strcmp(command,"MAX_ARRAYS")==0)
693     {   printf(
694 "  MAX_ARRAYS is the maximum number of declared arrays.\n");
695         return;
696     }
697     if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
698     {   printf(
699 "  MAX_EXPRESSION_NODES is the maximum number of nodes in the expression \n\
700   evaluator's storage for parse trees.  In effect, it measures how \n\
701   complicated algebraic expressions are allowed to be.  Increasing it by \n\
702   one costs about 80 bytes.\n");
703         return;
704     }
705     if (strcmp(command,"MAX_VERBS")==0)
706     {   printf(
707 "  MAX_VERBS is the maximum number of verbs (such as \"take\") which can be \n\
708   defined, each with its own grammar.  To increase it by one costs about\n\
709   128 bytes.  A full game will contain at least 100.\n");
710         return;
711     }
712     if (strcmp(command,"MAX_VERBSPACE")==0)
713     {   printf(
714 "  MAX_VERBSPACE is the size of workspace used to store verb words, so may\n\
715   need increasing in games with many synonyms: unlikely to exceed 4K.\n");
716         return;
717     }
718     if (strcmp(command,"MAX_LABELS")==0)
719     {   printf(
720 "  MAX_LABELS is the maximum number of label points in any one routine.\n\
721   (If the -k debugging information switch is set, MAX_LABELS is raised to\n\
722   a minimum level of 2000, as about twice the normal number of label points\n\
723   are needed to generate tables of how source code corresponds to positions\n\
724   in compiled code.)");
725         return;
726     }
727     if (strcmp(command,"MAX_LINESPACE")==0)
728     {   printf(
729 "  MAX_LINESPACE is the size of workspace used to store grammar lines, so \n\
730   may need increasing in games with complex or extensive grammars.\n");
731         return;
732     }
733     if (strcmp(command,"MAX_STATIC_STRINGS")==0)
734     {
735         printf(
736 "  MAX_STATIC_STRINGS is the size in bytes of a buffer to hold compiled\n\
737   strings before they're written into longer-term storage.  2000 bytes is \n\
738   plenty, allowing string constants of up to about 3000 characters long.\n\
739   Inform automatically ensures that this is at least twice the size of\n\
740   MAX_QTEXT_SIZE, to be on the safe side.");
741         return;
742     }
743     if (strcmp(command,"MAX_ZCODE_SIZE")==0)
744     {
745         printf(
746 "  MAX_ZCODE_SIZE is the size in bytes of a buffer to hold compiled \n\
747   code for a single routine.  (It applies to both Z-code and Glulx, \n\
748   despite the name.)  As a guide, the longest library routine is \n\
749   about 6500 bytes long in Z-code; about twice that in Glulx.");
750         return;
751     }
752     if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
753     {
754         printf(
755 "  MAX_LINK_DATA_SIZE is the size in bytes of a buffer to hold module \n\
756   link data before it's written into longer-term storage.  2000 bytes \n\
757   is plenty.");
758         return;
759     }
760     if (strcmp(command,"MAX_LOW_STRINGS")==0)
761     {   printf(
762 "  MAX_LOW_STRINGS is the size in bytes of a buffer to hold all the \n\
763   compiled \"low strings\" which are to be written above the synonyms table \n\
764   in the Z-machine.  1024 is plenty.\n");
765         return;
766     }
767     if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
768     {   printf(
769 "  MAX_TRANSCRIPT_SIZE is only allocated for the abbreviations optimisation \n\
770   switch, and has the size in bytes of a buffer to hold the entire text of\n\
771   the game being compiled: it has to be enormous, say 100000 to 200000.\n");
772         return;
773     }
774     if (strcmp(command,"MAX_CLASSES")==0)
775     {   printf(
776 "  MAX_CLASSES maximum number of object classes which can be defined.  This\n\
777   is cheap to increase.\n");
778         return;
779     }
780     if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
781     {   printf(
782 "  MAX_INCLUSION_DEPTH is the number of nested includes permitted.\n");
783         return;
784     }
785     if (strcmp(command,"MAX_SOURCE_FILES")==0)
786     {   printf(
787 "  MAX_SOURCE_FILES is the number of source files that can be read in the \n\
788   compilation.\n");
789         return;
790     }
791     if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
792     {   printf(
793 "  MAX_INDIV_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
794   table of ..variable values.\n");
795         return;
796     }
797     if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
798     {   printf(
799 "  MAX_OBJ_PROP_COUNT is the maximum number of properties a single object \n\
800   can have. (Glulx only)\n");
801         return;
802     }
803     if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
804     {   printf(
805 "  MAX_OBJ_PROP_TABLE_SIZE is the number of words allocated to hold a \n\
806   single object's properties. (Glulx only)\n");
807         return;
808     }
809     if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
810     {   printf(
811 "  MAX_LOCAL_VARIABLES is the number of local variables (including \n\
812   arguments) allowed in a procedure. (Glulx only)\n");
813         return;
814     }
815     if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
816     {   printf(
817 "  MAX_GLOBAL_VARIABLES is the number of global variables allowed in the \n\
818   program. (Glulx only)\n");
819         return;
820     }
821     if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
822     {
823         printf(
824 "  MAX_NUM_STATIC_STRINGS is the maximum number of compiled strings \n\
825   allowed in the program. (Glulx only)\n");
826         return;
827     }
828     if (strcmp(command,"MAX_UNICODE_CHARS")==0)
829     {
830         printf(
831 "  MAX_UNICODE_CHARS is the maximum number of different Unicode characters \n\
832   (beyond the Latin-1 range, $00..$FF) which the game text can use. \n\
833   (Glulx only)\n");
834         return;
835     }
836     if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
837     {
838         printf(
839 "  ALLOC_CHUNK_SIZE is a base unit of Inform's internal memory allocation \n\
840   for various structures.\n");
841         return;
842     }
843     if (strcmp(command,"MAX_STACK_SIZE")==0)
844     {
845         printf(
846 "  MAX_STACK_SIZE is the maximum size (in bytes) of the interpreter stack \n\
847   during gameplay. (Glulx only)\n");
848         return;
849     }
850     if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
851     {
852         printf(
853 "  MEMORY_MAP_EXTENSION is the number of bytes (all zeroes) to map into \n\
854   memory after the game file. (Glulx only)\n");
855         return;
856     }
857     if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
858     {
859         printf(
860 "  WARN_UNUSED_ROUTINES, if set to 2, will display a warning for each \n\
861   routine in the game file which is never called. (This includes \n\
862   routines called only from uncalled routines, etc.) If set to 1, will warn \n\
863   only about functions in game code, not in the system library.\n");
864         return;
865     }
866     if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
867     {
868         printf(
869 "  OMIT_UNUSED_ROUTINES, if set to 1, will avoid compiling unused routines \n\
870   into the game file.\n");
871         return;
872     }
873     if (strcmp(command,"SERIAL")==0)
874     {
875         printf(
876 "  SERIAL, if set, will be used as the six digit serial number written into \n\
877   the header of the output file.\n");
878         return;
879     }
880
881     printf("No such memory setting as \"%s\"\n",command);
882
883     return;
884 }
885
886 /* Parse a decimal number as an int32. Return true if a valid number
887    was found; otherwise print a warning and return false.
888
889    Anything over nine digits is considered an overflow; we report a
890    warning but return +/- 999999999 (and true). This is not entirely
891    clever about leading zeroes ("0000000001" is treated as an
892    overflow) but this is better than trying to detect genuine
893    overflows in a long.
894
895    (Some Glulx settings might conceivably want to go up to $7FFFFFFF,
896    which is a ten-digit number, but we're not going to allow that
897    today.)
898
899    This used to rely on atoi(), and we retain the atoi() behavior of
900    ignoring garbage characters after a valid decimal number.
901  */
902 static int parse_memory_setting(char *str, char *label, int32 *result)
903 {
904     char *cx = str;
905     char *ex;
906     long val;
907
908     *result = 0;
909
910     while (*cx == ' ') cx++;
911
912     val = strtol(cx, &ex, 10);    
913
914     if (ex == cx) {
915         printf("Bad numerical setting in $ command \"%s=%s\"\n",
916             label, str);
917         return 0;
918     }
919
920     if (*cx == '-') {
921         if (ex > cx+10) {
922             val = -999999999;
923             printf("Numerical setting underflowed in $ command \"%s=%s\" (limiting to %ld)\n",
924                 label, str, val);
925         }
926     }
927     else {
928         if (ex > cx+9) {
929             val = 999999999;
930             printf("Numerical setting overflowed in $ command \"%s=%s\" (limiting to %ld)\n",
931                 label, str, val);
932         }
933     }
934
935     *result = (int32)val;
936     return 1;
937 }
938
939 extern void memory_command(char *command)
940 {   int i, k, flag=0; int32 j;
941
942     for (k=0; command[k]!=0; k++)
943         if (islower(command[k])) command[k]=toupper(command[k]);
944
945     if (command[0]=='?') { explain_parameter(command+1); return; }
946
947     if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; }
948     if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; }
949     if (strcmp(command, "SMALL")==0) { set_memory_sizes(SMALL_SIZE); return; }
950     if (strcmp(command, "LIST")==0)  { list_memory_sizes(); return; }
951     for (i=0; command[i]!=0; i++)
952     {   if (command[i]=='=')
953         {   command[i]=0;
954             if (!parse_memory_setting(command+i+1, command, &j)) {
955                 return;
956             }
957             if (strcmp(command,"BUFFER_LENGTH")==0)
958                 flag=2;
959             if (strcmp(command,"MAX_QTEXT_SIZE")==0)
960             {   MAX_QTEXT_SIZE=j, flag=1;
961                 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
962                     MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
963             }
964             if (strcmp(command,"MAX_SYMBOLS")==0)
965                 MAX_SYMBOLS=j, flag=1;
966             if (strcmp(command,"MAX_BANK_SIZE")==0)
967                 flag=2;
968             if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
969                 SYMBOLS_CHUNK_SIZE=j, flag=1;
970             if (strcmp(command,"BANK_CHUNK_SIZE")==0)
971                 flag=2;
972             if (strcmp(command,"HASH_TAB_SIZE")==0)
973                 HASH_TAB_SIZE=j, flag=1;
974             if (strcmp(command,"MAX_OBJECTS")==0)
975                 MAX_OBJECTS=j, flag=1;
976             if (strcmp(command,"MAX_ACTIONS")==0)
977                 MAX_ACTIONS=j, flag=1;
978             if (strcmp(command,"MAX_ADJECTIVES")==0)
979                 MAX_ADJECTIVES=j, flag=1;
980             if (strcmp(command,"MAX_DICT_ENTRIES")==0)
981                 MAX_DICT_ENTRIES=j, flag=1;
982             if (strcmp(command,"DICT_WORD_SIZE")==0) 
983             {   DICT_WORD_SIZE=j, flag=1;
984                 DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j;
985             }
986             if (strcmp(command,"DICT_CHAR_SIZE")==0)
987                 DICT_CHAR_SIZE=j, flag=1;
988             if (strcmp(command,"NUM_ATTR_BYTES")==0) 
989             {   NUM_ATTR_BYTES=j, flag=1;
990                 NUM_ATTR_BYTES_g=NUM_ATTR_BYTES_z=j;
991             }
992             if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
993                 ZCODE_HEADER_EXT_WORDS=j, flag=1;
994             if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
995                 ZCODE_HEADER_FLAGS_3=j, flag=1;
996             if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
997                 GLULX_OBJECT_EXT_BYTES=j, flag=1;
998             if (strcmp(command,"MAX_STATIC_DATA")==0)
999                 MAX_STATIC_DATA=j, flag=1;
1000             if (strcmp(command,"MAX_OLDEPTH")==0)
1001                 flag=2;
1002             if (strcmp(command,"MAX_ROUTINES")==0)
1003                 flag=2;
1004             if (strcmp(command,"MAX_GCONSTANTS")==0)
1005                 flag=2;
1006             if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
1007             {   MAX_PROP_TABLE_SIZE=j, flag=1;
1008                 MAX_PROP_TABLE_SIZE_g=MAX_PROP_TABLE_SIZE_z=j;
1009             }
1010             if (strcmp(command,"MAX_FORWARD_REFS")==0)
1011                 flag=2;
1012             if (strcmp(command,"STACK_SIZE")==0)
1013                 flag=2;
1014             if (strcmp(command,"STACK_LONG_SLOTS")==0)
1015                 flag=2;
1016             if (strcmp(command,"STACK_SHORT_LENGTH")==0)
1017                 flag=2;
1018             if (strcmp(command,"MAX_ABBREVS")==0)
1019                 MAX_ABBREVS=j, flag=1;
1020             if (strcmp(command,"MAX_ARRAYS")==0)
1021                 MAX_ARRAYS=j, flag=1;
1022             if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
1023                 MAX_EXPRESSION_NODES=j, flag=1;
1024             if (strcmp(command,"MAX_VERBS")==0)
1025                 MAX_VERBS=j, flag=1;
1026             if (strcmp(command,"MAX_VERBSPACE")==0)
1027                 MAX_VERBSPACE=j, flag=1;
1028             if (strcmp(command,"MAX_LABELS")==0)
1029                 MAX_LABELS=j, flag=1;
1030             if (strcmp(command,"MAX_LINESPACE")==0)
1031                 MAX_LINESPACE=j, flag=1;
1032             if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
1033                 MAX_NUM_STATIC_STRINGS=j, flag=1;
1034             if (strcmp(command,"MAX_STATIC_STRINGS")==0)
1035             {   MAX_STATIC_STRINGS=j, flag=1;
1036                 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
1037                     MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
1038             }
1039             if (strcmp(command,"MAX_ZCODE_SIZE")==0)
1040             {   MAX_ZCODE_SIZE=j, flag=1;
1041                 MAX_ZCODE_SIZE_g=MAX_ZCODE_SIZE_z=j;
1042             }
1043             if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
1044                 MAX_LINK_DATA_SIZE=j, flag=1;
1045             if (strcmp(command,"MAX_LOW_STRINGS")==0)
1046                 MAX_LOW_STRINGS=j, flag=1;
1047             if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
1048                 MAX_TRANSCRIPT_SIZE=j, flag=1;
1049             if (strcmp(command,"MAX_CLASSES")==0)
1050                 MAX_CLASSES=j, flag=1;
1051             if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
1052                 MAX_INCLUSION_DEPTH=j, flag=1;
1053             if (strcmp(command,"MAX_SOURCE_FILES")==0)
1054                 MAX_SOURCE_FILES=j, flag=1;
1055             if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
1056                 MAX_INDIV_PROP_TABLE_SIZE=j, flag=1;
1057             if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
1058                 MAX_OBJ_PROP_TABLE_SIZE=j, flag=1;
1059             if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
1060                 MAX_OBJ_PROP_COUNT=j, flag=1;
1061             if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
1062             {   MAX_LOCAL_VARIABLES=j, flag=1;
1063                 MAX_LOCAL_VARIABLES_g=MAX_LOCAL_VARIABLES_z=j;
1064             }
1065             if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
1066             {   MAX_GLOBAL_VARIABLES=j, flag=1;
1067                 MAX_GLOBAL_VARIABLES_g=MAX_GLOBAL_VARIABLES_z=j;
1068             }
1069             if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
1070             {   ALLOC_CHUNK_SIZE=j, flag=1;
1071                 ALLOC_CHUNK_SIZE_g=ALLOC_CHUNK_SIZE_z=j;
1072             }
1073             if (strcmp(command,"MAX_UNICODE_CHARS")==0)
1074                 MAX_UNICODE_CHARS=j, flag=1;
1075             if (strcmp(command,"MAX_STACK_SIZE")==0)
1076             {
1077                 MAX_STACK_SIZE=j, flag=1;
1078                 /* Adjust up to a 256-byte boundary. */
1079                 MAX_STACK_SIZE = (MAX_STACK_SIZE + 0xFF) & (~0xFF);
1080             }
1081             if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
1082             {
1083                 MEMORY_MAP_EXTENSION=j, flag=1;
1084                 /* Adjust up to a 256-byte boundary. */
1085                 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
1086             }
1087             if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
1088             {
1089                 WARN_UNUSED_ROUTINES=j, flag=1;
1090                 if (WARN_UNUSED_ROUTINES > 2 || WARN_UNUSED_ROUTINES < 0)
1091                     WARN_UNUSED_ROUTINES = 2;
1092             }
1093             if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
1094             {
1095                 OMIT_UNUSED_ROUTINES=j, flag=1;
1096                 if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
1097                     OMIT_UNUSED_ROUTINES = 1;
1098             }
1099             if (strcmp(command,"SERIAL")==0)
1100             {
1101                 if (j >= 0 && j <= 999999)
1102                 {
1103                     sprintf(serial_code_buffer,"%06d",j);
1104                     serial_code_given_in_program = TRUE;
1105                     flag=1;
1106                 }
1107             }
1108
1109             if (flag==0)
1110                 printf("No such memory setting as \"%s\"\n", command);
1111             if (flag==2)
1112             printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n\
1113 It should be safe to omit it (putting nothing in its place).\n", command);
1114             return;
1115         }
1116     }
1117     printf("No such memory $ command as \"%s\"\n",command);
1118 }
1119
1120 extern void print_memory_usage(void)
1121 {
1122     printf("Properties table used %d\n",
1123         properties_table_size);
1124     printf("Allocated a total of %ld bytes of memory\n",
1125         (long int) malloced_bytes);
1126 }
1127
1128 /* ========================================================================= */
1129 /*   Data structure management routines                                      */
1130 /* ------------------------------------------------------------------------- */
1131
1132 extern void init_memory_vars(void)
1133 {   malloced_bytes = 0;
1134 }
1135
1136 extern void memory_begin_pass(void) { }
1137
1138 extern void memory_allocate_arrays(void) { }
1139
1140 extern void memory_free_arrays(void) { }
1141
1142 /* ========================================================================= */