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