1 /* ------------------------------------------------------------------------- */
2 /* "memory" : Memory management and ICL memory setting commands */
3 /* (For "memoryerror", see "errors.c") */
5 /* Part of Inform 6.35 */
6 /* copyright (c) Graham Nelson 1993 - 2021 */
8 /* Inform is free software: you can redistribute it and/or modify */
9 /* it under the terms of the GNU General Public License as published by */
10 /* the Free Software Foundation, either version 3 of the License, or */
11 /* (at your option) any later version. */
13 /* Inform is distributed in the hope that it will be useful, */
14 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
15 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
16 /* GNU General Public License for more details. */
18 /* You should have received a copy of the GNU General Public License */
19 /* along with Inform. If not, see https://gnu.org/licenses/ *
21 /* ------------------------------------------------------------------------- */
25 int32 malloced_bytes=0; /* Total amount of memory allocated */
29 extern void *my_malloc(int32 size, char *whatfor)
32 printf("Allocating %ld bytes for %s\n",size,whatfor);
33 if (size==0) return(NULL);
34 c=(char _huge *)halloc(size,1); malloced_bytes+=size;
35 if (c==0) memory_out_error(size, 1, whatfor);
39 extern void my_realloc(void *pointer, int32 oldsize, int32 size,
43 my_free(pointer, whatfor);
46 c=halloc(size,1); malloced_bytes+=size;
47 if (c==0) memory_out_error(size, 1, whatfor);
49 printf("Increasing allocation to %ld bytes for %s was (%08lx) \
51 (long int) size,whatfor,(long int) (*(int **)pointer),
53 memcpy(c, *(int **)pointer, MIN(oldsize, size));
54 hfree(*(int **)pointer);
58 extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
61 printf("Allocating %d bytes: array (%ld entries size %ld) for %s\n",
62 size*howmany,howmany,size,whatfor);
63 if ((size*howmany) == 0) return(NULL);
64 c=(void _huge *)halloc(howmany*size,1); malloced_bytes+=size*howmany;
65 if (c==0) memory_out_error(size, howmany, whatfor);
69 extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany,
70 int32 howmany, char *whatfor)
72 if (size*howmany==0) {
73 my_free(pointer, whatfor);
76 c=(void _huge *)halloc(size*howmany,1); malloced_bytes+=size*howmany;
77 if (c==0) memory_out_error(size, howmany, whatfor);
79 printf("Increasing allocation to %ld bytes: array (%ld entries size %ld) \
80 for %s was (%08lx) now (%08lx)\n",
81 ((long int)size) * ((long int)howmany),
82 (long int)howmany,(long int)size,whatfor,
83 (long int) *(int **)pointer, (long int) c);
84 memcpy(c, *(int **)pointer, MIN(size*oldhowmany, size*howmany));
85 hfree(*(int **)pointer);
91 extern void *my_malloc(int32 size, char *whatfor)
93 if (size==0) return(NULL);
94 c=malloc((size_t) size); malloced_bytes+=size;
95 if (c==0) memory_out_error(size, 1, whatfor);
97 printf("Allocating %ld bytes for %s at (%08lx)\n",
98 (long int) size,whatfor,(long int) c);
102 extern void my_realloc(void *pointer, int32 oldsize, int32 size,
106 my_free(pointer, whatfor);
109 c=realloc(*(int **)pointer, (size_t) size); malloced_bytes+=size;
110 if (c==0) memory_out_error(size, 1, whatfor);
112 printf("Increasing allocation to %ld bytes for %s was (%08lx) \
114 (long int) size,whatfor,(long int) (*(int **)pointer),
116 *(int **)pointer = c;
119 extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
121 if (size*howmany==0) return(NULL);
122 c=calloc(howmany,(size_t) size); malloced_bytes+=size*howmany;
123 if (c==0) memory_out_error(size, howmany, whatfor);
125 printf("Allocating %ld bytes: array (%ld entries size %ld) \
126 for %s at (%08lx)\n",
127 ((long int)size) * ((long int)howmany),
128 (long int)howmany,(long int)size,whatfor,
133 extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany,
134 int32 howmany, char *whatfor)
136 if (size*howmany==0) {
137 my_free(pointer, whatfor);
140 c=realloc(*(int **)pointer, (size_t)size*(size_t)howmany);
141 malloced_bytes+=size*howmany;
142 if (c==0) memory_out_error(size, howmany, whatfor);
144 printf("Increasing allocation to %ld bytes: array (%ld entries size %ld) \
145 for %s was (%08lx) now (%08lx)\n",
146 ((long int)size) * ((long int)howmany),
147 (long int)howmany,(long int)size,whatfor,
148 (long int) *(int **)pointer, (long int) c);
149 *(int **)pointer = c;
154 extern void my_free(void *pointer, char *whatitwas)
156 if (*(int **)pointer != NULL)
158 printf("Freeing memory for %s at (%08lx)\n",
159 whatitwas, (long int) (*(int **)pointer));
161 hfree(*(int **)pointer);
163 free(*(int **)pointer);
165 *(int **)pointer = NULL;
169 /* ------------------------------------------------------------------------- */
170 /* Extensible blocks of memory, providing a kind of RAM disc as an */
171 /* alternative to the temporary files option */
173 /* The allocation is slightly confusing. A block can store up to 72 */
174 /* chunks, which are allocated as needed when data is written. (Data does */
175 /* not have to be written in order, but you should not try to read a byte */
176 /* before writing it.) The size of a chunk is defined by ALLOC_CHUNK_SIZE. */
177 /* So any block can store any amount of data, but you increase the limit */
178 /* (for all blocks) by increasing ALLOC_CHUNK_SIZE, not the number of */
180 /* ------------------------------------------------------------------------- */
182 static char chunk_name_buffer[60];
183 static char *chunk_name(memory_block *MB, int no)
184 { char *p = "(unknown)";
185 if (MB == &static_strings_area) p = "static strings area";
186 if (MB == &zcode_area) p = "Z-code area";
187 if (MB == &link_data_area) p = "link data area";
188 if (MB == &zcode_backpatch_table) p = "Z-code backpatch table";
189 if (MB == &staticarray_backpatch_table) p = "Static array backpatch table";
190 if (MB == &zmachine_backpatch_table) p = "Z-machine backpatch table";
191 sprintf(chunk_name_buffer, "%s chunk %d", p, no);
192 return(chunk_name_buffer);
195 extern void initialise_memory_block(memory_block *MB)
198 for (i=0; i<72; i++) MB->chunk[i] = NULL;
199 MB->extent_of_last = 0;
203 extern void deallocate_memory_block(memory_block *MB)
206 if (MB->chunk[i] != NULL)
207 my_free(&(MB->chunk[i]), chunk_name(MB, i));
209 MB->extent_of_last = 0;
212 extern int read_byte_from_memory_block(memory_block *MB, int32 index)
214 p = MB->chunk[index/ALLOC_CHUNK_SIZE];
216 { compiler_error_named("memory: read from unwritten byte in",
217 chunk_name(MB, index/ALLOC_CHUNK_SIZE));
220 return p[index % ALLOC_CHUNK_SIZE];
223 extern void write_byte_to_memory_block(memory_block *MB, int32 index, int value)
224 { uchar *p; int ch = index/ALLOC_CHUNK_SIZE;
226 { compiler_error_named("memory: negative index to", chunk_name(MB, 0));
229 if (ch >= 72) memoryerror("ALLOC_CHUNK_SIZE", ALLOC_CHUNK_SIZE);
231 if (MB->chunk[ch] == NULL)
233 MB->chunk[ch] = my_malloc(ALLOC_CHUNK_SIZE, chunk_name(MB, ch));
235 for (i=0; i<ALLOC_CHUNK_SIZE; i++) p[i] = 255;
239 p[index % ALLOC_CHUNK_SIZE] = value;
242 /* ------------------------------------------------------------------------- */
243 /* Where the memory settings are declared as variables */
244 /* ------------------------------------------------------------------------- */
248 int SYMBOLS_CHUNK_SIZE;
254 int MAX_DICT_ENTRIES;
256 int MAX_PROP_TABLE_SIZE;
258 int MAX_DYNAMIC_STRINGS;
259 int MAX_EXPRESSION_NODES;
264 int32 MAX_STATIC_STRINGS;
265 int32 MAX_ZCODE_SIZE;
267 int32 MAX_TRANSCRIPT_SIZE;
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 */
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 */
292 /* The way memory sizes are set causes great nuisance for those parameters
293 which have different defaults under Z-code and Glulx. We have to get
294 the defaults right whether the user sets "-G $HUGE" or "$HUGE -G".
295 And an explicit value set by the user should override both defaults. */
296 static int32 MAX_ZCODE_SIZE_z, MAX_ZCODE_SIZE_g;
297 static int MAX_PROP_TABLE_SIZE_z, MAX_PROP_TABLE_SIZE_g;
298 static int MAX_GLOBAL_VARIABLES_z, MAX_GLOBAL_VARIABLES_g;
299 static int MAX_LOCAL_VARIABLES_z, MAX_LOCAL_VARIABLES_g;
300 static int DICT_WORD_SIZE_z, DICT_WORD_SIZE_g;
301 static int NUM_ATTR_BYTES_z, NUM_ATTR_BYTES_g;
302 static int ALLOC_CHUNK_SIZE_z, ALLOC_CHUNK_SIZE_g;
303 static int MAX_DYNAMIC_STRINGS_z, MAX_DYNAMIC_STRINGS_g;
305 /* ------------------------------------------------------------------------- */
306 /* Memory control from the command line */
307 /* ------------------------------------------------------------------------- */
309 static void list_memory_sizes(void)
310 { printf("+--------------------------------------+\n");
311 printf("| %25s = %-7s |\n","Memory setting","Value");
312 printf("+--------------------------------------+\n");
313 printf("| %25s = %-7d |\n","MAX_ABBREVS",MAX_ABBREVS);
314 printf("| %25s = %-7d |\n","MAX_ACTIONS",MAX_ACTIONS);
315 printf("| %25s = %-7d |\n","MAX_ADJECTIVES",MAX_ADJECTIVES);
316 printf("| %25s = %-7d |\n","ALLOC_CHUNK_SIZE",ALLOC_CHUNK_SIZE);
317 printf("| %25s = %-7d |\n","MAX_ARRAYS",MAX_ARRAYS);
318 printf("| %25s = %-7d |\n","NUM_ATTR_BYTES",NUM_ATTR_BYTES);
319 printf("| %25s = %-7d |\n","MAX_CLASSES",MAX_CLASSES);
320 printf("| %25s = %-7d |\n","MAX_DICT_ENTRIES",MAX_DICT_ENTRIES);
321 printf("| %25s = %-7d |\n","DICT_WORD_SIZE",DICT_WORD_SIZE);
323 printf("| %25s = %-7d |\n","DICT_CHAR_SIZE",DICT_CHAR_SIZE);
324 printf("| %25s = %-7d |\n","MAX_DYNAMIC_STRINGS",MAX_DYNAMIC_STRINGS);
325 printf("| %25s = %-7d |\n","MAX_EXPRESSION_NODES",MAX_EXPRESSION_NODES);
326 printf("| %25s = %-7d |\n","MAX_GLOBAL_VARIABLES",MAX_GLOBAL_VARIABLES);
327 printf("| %25s = %-7d |\n","HASH_TAB_SIZE",HASH_TAB_SIZE);
329 printf("| %25s = %-7d |\n","ZCODE_HEADER_EXT_WORDS",ZCODE_HEADER_EXT_WORDS);
331 printf("| %25s = %-7d |\n","ZCODE_HEADER_FLAGS_3",ZCODE_HEADER_FLAGS_3);
332 printf("| %25s = %-7d |\n","MAX_INCLUSION_DEPTH",MAX_INCLUSION_DEPTH);
333 printf("| %25s = %-7d |\n","MAX_INDIV_PROP_TABLE_SIZE", MAX_INDIV_PROP_TABLE_SIZE);
334 printf("| %25s = %-7d |\n","INDIV_PROP_START", INDIV_PROP_START);
335 printf("| %25s = %-7d |\n","MAX_LABELS",MAX_LABELS);
336 printf("| %25s = %-7d |\n","MAX_LINESPACE",MAX_LINESPACE);
337 printf("| %25s = %-7d |\n","MAX_LINK_DATA_SIZE",MAX_LINK_DATA_SIZE);
339 printf("| %25s = %-7d |\n","MAX_LOCAL_VARIABLES",MAX_LOCAL_VARIABLES);
340 printf("| %25s = %-7d |\n","MAX_LOW_STRINGS",MAX_LOW_STRINGS);
342 printf("| %25s = %-7d |\n","MEMORY_MAP_EXTENSION",
343 MEMORY_MAP_EXTENSION);
345 printf("| %25s = %-7d |\n","MAX_NUM_STATIC_STRINGS",
346 MAX_NUM_STATIC_STRINGS);
347 printf("| %25s = %-7d |\n","MAX_OBJECTS",MAX_OBJECTS);
349 printf("| %25s = %-7d |\n","GLULX_OBJECT_EXT_BYTES",
350 GLULX_OBJECT_EXT_BYTES);
352 printf("| %25s = %-7d |\n","MAX_OBJ_PROP_COUNT",
355 printf("| %25s = %-7d |\n","MAX_OBJ_PROP_TABLE_SIZE",
356 MAX_OBJ_PROP_TABLE_SIZE);
357 printf("| %25s = %-7d |\n","MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
358 printf("| %25s = %-7d |\n","MAX_QTEXT_SIZE",MAX_QTEXT_SIZE);
359 printf("| %25s = %-7d |\n","MAX_SOURCE_FILES",MAX_SOURCE_FILES);
361 printf("| %25s = %-7ld |\n","MAX_STACK_SIZE",
362 (long int) MAX_STACK_SIZE);
363 printf("| %25s = %-7d |\n","MAX_STATIC_DATA",MAX_STATIC_DATA);
364 printf("| %25s = %-7ld |\n","MAX_STATIC_STRINGS",
365 (long int) MAX_STATIC_STRINGS);
366 printf("| %25s = %-7d |\n","MAX_SYMBOLS",MAX_SYMBOLS);
367 printf("| %25s = %-7d |\n","SYMBOLS_CHUNK_SIZE",SYMBOLS_CHUNK_SIZE);
368 printf("| %25s = %-7ld |\n","MAX_TRANSCRIPT_SIZE",
369 (long int) MAX_TRANSCRIPT_SIZE);
371 printf("| %25s = %-7ld |\n","MAX_UNICODE_CHARS",
372 (long int) MAX_UNICODE_CHARS);
373 printf("| %25s = %-7d |\n","WARN_UNUSED_ROUTINES",WARN_UNUSED_ROUTINES);
374 printf("| %25s = %-7d |\n","OMIT_UNUSED_ROUTINES",OMIT_UNUSED_ROUTINES);
375 printf("| %25s = %-7d |\n","MAX_VERBS",MAX_VERBS);
376 printf("| %25s = %-7d |\n","MAX_VERBSPACE",MAX_VERBSPACE);
377 printf("| %25s = %-7ld |\n","MAX_ZCODE_SIZE",
378 (long int) MAX_ZCODE_SIZE);
379 printf("+--------------------------------------+\n");
382 extern void set_memory_sizes(int size_flag)
384 if (size_flag == HUGE_SIZE)
386 MAX_QTEXT_SIZE = 4000;
389 SYMBOLS_CHUNK_SIZE = 5000;
396 MAX_DICT_ENTRIES = 2000;
397 MAX_STATIC_DATA = 10000;
399 MAX_PROP_TABLE_SIZE_z = 30000;
400 MAX_PROP_TABLE_SIZE_g = 60000;
402 MAX_EXPRESSION_NODES = 100;
404 MAX_VERBSPACE = 4096;
406 MAX_LINESPACE = 16000;
408 MAX_STATIC_STRINGS = 8000;
409 MAX_ZCODE_SIZE_z = 20000;
410 MAX_ZCODE_SIZE_g = 40000;
411 MAX_LINK_DATA_SIZE = 2000;
413 MAX_LOW_STRINGS = 2048;
415 MAX_TRANSCRIPT_SIZE = 200000;
416 MAX_NUM_STATIC_STRINGS = 20000;
420 MAX_OBJ_PROP_COUNT = 128;
421 MAX_OBJ_PROP_TABLE_SIZE = 4096;
423 MAX_INDIV_PROP_TABLE_SIZE = 15000;
426 MAX_GLOBAL_VARIABLES_z = 240;
427 MAX_GLOBAL_VARIABLES_g = 512;
429 ALLOC_CHUNK_SIZE_z = 8192;
430 ALLOC_CHUNK_SIZE_g = 32768;
432 if (size_flag == LARGE_SIZE)
434 MAX_QTEXT_SIZE = 4000;
437 SYMBOLS_CHUNK_SIZE = 5000;
444 MAX_DICT_ENTRIES = 1300;
445 MAX_STATIC_DATA = 10000;
447 MAX_PROP_TABLE_SIZE_z = 15000;
448 MAX_PROP_TABLE_SIZE_g = 30000;
450 MAX_EXPRESSION_NODES = 100;
452 MAX_VERBSPACE = 4096;
453 MAX_LINESPACE = 10000;
456 MAX_STATIC_STRINGS = 8000;
457 MAX_ZCODE_SIZE_z = 20000;
458 MAX_ZCODE_SIZE_g = 40000;
459 MAX_LINK_DATA_SIZE = 2000;
461 MAX_LOW_STRINGS = 2048;
463 MAX_TRANSCRIPT_SIZE = 200000;
464 MAX_NUM_STATIC_STRINGS = 20000;
468 MAX_OBJ_PROP_COUNT = 64;
469 MAX_OBJ_PROP_TABLE_SIZE = 2048;
471 MAX_INDIV_PROP_TABLE_SIZE = 10000;
474 MAX_GLOBAL_VARIABLES_z = 240;
475 MAX_GLOBAL_VARIABLES_g = 512;
477 ALLOC_CHUNK_SIZE_z = 8192;
478 ALLOC_CHUNK_SIZE_g = 16384;
480 if (size_flag == SMALL_SIZE)
482 MAX_QTEXT_SIZE = 4000;
485 SYMBOLS_CHUNK_SIZE = 2500;
492 MAX_DICT_ENTRIES = 700;
493 MAX_STATIC_DATA = 10000;
495 MAX_PROP_TABLE_SIZE_z = 8000;
496 MAX_PROP_TABLE_SIZE_g = 16000;
498 MAX_EXPRESSION_NODES = 40;
500 MAX_VERBSPACE = 2048;
501 MAX_LINESPACE = 10000;
504 MAX_STATIC_STRINGS = 8000;
505 MAX_ZCODE_SIZE_z = 10000;
506 MAX_ZCODE_SIZE_g = 20000;
507 MAX_LINK_DATA_SIZE = 1000;
509 MAX_LOW_STRINGS = 1024;
511 MAX_TRANSCRIPT_SIZE = 100000;
512 MAX_NUM_STATIC_STRINGS = 10000;
516 MAX_OBJ_PROP_COUNT = 64;
517 MAX_OBJ_PROP_TABLE_SIZE = 1024;
519 MAX_INDIV_PROP_TABLE_SIZE = 5000;
522 MAX_GLOBAL_VARIABLES_z = 240;
523 MAX_GLOBAL_VARIABLES_g = 256;
525 ALLOC_CHUNK_SIZE_z = 8192;
526 ALLOC_CHUNK_SIZE_g = 8192;
529 /* Regardless of size_flag... */
530 MAX_SOURCE_FILES = 256;
531 MAX_INCLUSION_DEPTH = 5;
532 MAX_LOCAL_VARIABLES_z = 16;
533 MAX_LOCAL_VARIABLES_g = 32;
535 DICT_WORD_SIZE_z = 6;
536 DICT_WORD_SIZE_g = 9;
537 NUM_ATTR_BYTES_z = 6;
538 NUM_ATTR_BYTES_g = 7;
540 MAX_DYNAMIC_STRINGS_z = 32;
541 MAX_DYNAMIC_STRINGS_g = 64;
542 /* Backwards-compatible behavior: allow for a unicode table
543 whether we need one or not. The user can set this to zero if
544 there's no unicode table. */
545 ZCODE_HEADER_EXT_WORDS = 3;
546 ZCODE_HEADER_FLAGS_3 = 0;
547 GLULX_OBJECT_EXT_BYTES = 0;
548 MAX_UNICODE_CHARS = 64;
549 MEMORY_MAP_EXTENSION = 0;
550 /* We estimate the default Glulx stack size at 4096. That's about
551 enough for 90 nested function calls with 8 locals each -- the
552 same capacity as the Z-Spec's suggestion for Z-machine stack
553 size. Note that Inform 7 wants more stack; I7-generated code
554 sets MAX_STACK_SIZE to 65536 by default. */
555 MAX_STACK_SIZE = 4096;
556 OMIT_UNUSED_ROUTINES = 0;
557 WARN_UNUSED_ROUTINES = 0;
559 adjust_memory_sizes();
562 extern void adjust_memory_sizes()
565 MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_z;
566 MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_z;
567 MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_z;
568 MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_z;
569 DICT_WORD_SIZE = DICT_WORD_SIZE_z;
570 NUM_ATTR_BYTES = NUM_ATTR_BYTES_z;
571 ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_z;
572 MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_z;
573 INDIV_PROP_START = 64;
576 MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_g;
577 MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_g;
578 MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_g;
579 MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_g;
580 DICT_WORD_SIZE = DICT_WORD_SIZE_g;
581 NUM_ATTR_BYTES = NUM_ATTR_BYTES_g;
582 ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_g;
583 MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_g;
584 INDIV_PROP_START = 256;
588 static void explain_parameter(char *command)
590 if (strcmp(command,"MAX_QTEXT_SIZE")==0)
592 " MAX_QTEXT_SIZE is the maximum length of a quoted string. Increasing\n\
593 by 1 costs 5 bytes (for lexical analysis memory). Inform automatically\n\
594 ensures that MAX_STATIC_STRINGS is at least twice the size of this.");
597 if (strcmp(command,"MAX_SYMBOLS")==0)
599 " MAX_SYMBOLS is the maximum number of symbols - names of variables, \n\
600 objects, routines, the many internal Inform-generated names and so on.\n");
603 if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
605 " The symbols names are stored in memory which is allocated in chunks \n\
606 of size SYMBOLS_CHUNK_SIZE.\n");
609 if (strcmp(command,"HASH_TAB_SIZE")==0)
611 " HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
615 if (strcmp(command,"MAX_OBJECTS")==0)
617 " MAX_OBJECTS is the maximum number of objects. (If compiling a version-3 \n\
618 game, 255 is an absolute maximum in any event.)\n");
621 if (strcmp(command,"MAX_ACTIONS")==0)
623 " MAX_ACTIONS is the maximum number of actions - that is, routines such as \n\
624 TakeSub which are referenced in the grammar table.\n");
627 if (strcmp(command,"MAX_ADJECTIVES")==0)
629 " MAX_ADJECTIVES is the maximum number of different \"adjectives\" in the \n\
630 grammar table. Adjectives are misleadingly named: they are words such as \n\
631 \"in\", \"under\" and the like.\n");
634 if (strcmp(command,"MAX_DICT_ENTRIES")==0)
636 " MAX_DICT_ENTRIES is the maximum number of words which can be entered \n\
637 into the game's dictionary. It costs 29 bytes to increase this by one.\n");
640 if (strcmp(command,"DICT_WORD_SIZE")==0)
642 " DICT_WORD_SIZE is the number of characters in a dictionary word. In \n\
643 Z-code this is always 6 (only 4 are used in v3 games). In Glulx it \n\
644 can be any number.\n");
647 if (strcmp(command,"DICT_CHAR_SIZE")==0)
649 " DICT_CHAR_SIZE is the byte size of one character in the dictionary. \n\
650 (This is only meaningful in Glulx, since Z-code has compressed dictionary \n\
651 words.) It can be either 1 (the default) or 4 (to enable full Unicode \n\
655 if (strcmp(command,"NUM_ATTR_BYTES")==0)
657 " NUM_ATTR_BYTES is the space used to store attribute flags. Each byte \n\
658 stores eight attributes. In Z-code this is always 6 (only 4 are used in \n\
659 v3 games). In Glulx it can be any number which is a multiple of four, \n\
663 if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
665 " ZCODE_HEADER_EXT_WORDS is the number of words in the Z-code header \n\
666 extension table (Z-Spec 1.0). The -W switch also sets this. It defaults \n\
667 to 3, but can be set higher. (It can be set lower if no Unicode \n\
668 translation table is created.)\n");
671 if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
673 " ZCODE_HEADER_FLAGS_3 is the value to store in the Flags 3 word of the \n\
674 header extension table (Z-Spec 1.1).\n");
677 if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
679 " GLULX_OBJECT_EXT_BYTES is an amount of additional space to add to each \n\
680 object record. It is initialized to zero bytes, and the game is free to \n\
681 use it as desired. (This is only meaningful in Glulx, since Z-code \n\
682 specifies the object structure.)\n");
685 if (strcmp(command,"MAX_STATIC_DATA")==0)
687 " MAX_STATIC_DATA is the size of an array of integers holding initial \n\
688 values for arrays and strings stored as ASCII inside the Z-machine. It \n\
689 should be at least 1024 but seldom needs much more.\n");
692 if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
694 " MAX_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
695 properties table.\n");
698 if (strcmp(command,"MAX_ABBREVS")==0)
700 " MAX_ABBREVS is the maximum number of declared abbreviations. It is not \n\
701 allowed to exceed 96 in Z-code.\n");
704 if (strcmp(command,"MAX_DYNAMIC_STRINGS")==0)
706 " MAX_DYNAMIC_STRINGS is the maximum number of string substitution variables\n\
707 (\"@00\"). It is not allowed to exceed 96 in Z-code or 100 in Glulx.\n");
710 if (strcmp(command,"MAX_ARRAYS")==0)
712 " MAX_ARRAYS is the maximum number of declared arrays.\n");
715 if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
717 " MAX_EXPRESSION_NODES is the maximum number of nodes in the expression \n\
718 evaluator's storage for parse trees. In effect, it measures how \n\
719 complicated algebraic expressions are allowed to be. Increasing it by \n\
720 one costs about 80 bytes.\n");
723 if (strcmp(command,"MAX_VERBS")==0)
725 " MAX_VERBS is the maximum number of verbs (such as \"take\") which can be \n\
726 defined, each with its own grammar. To increase it by one costs about\n\
727 128 bytes. A full game will contain at least 100.\n");
730 if (strcmp(command,"MAX_VERBSPACE")==0)
732 " MAX_VERBSPACE is the size of workspace used to store verb words, so may\n\
733 need increasing in games with many synonyms: unlikely to exceed 4K.\n");
736 if (strcmp(command,"MAX_LABELS")==0)
738 " MAX_LABELS is the maximum number of label points in any one routine.\n\
739 (If the -k debugging information switch is set, MAX_LABELS is raised to\n\
740 a minimum level of 2000, as about twice the normal number of label points\n\
741 are needed to generate tables of how source code corresponds to positions\n\
742 in compiled code.)");
745 if (strcmp(command,"MAX_LINESPACE")==0)
747 " MAX_LINESPACE is the size of workspace used to store grammar lines, so \n\
748 may need increasing in games with complex or extensive grammars.\n");
751 if (strcmp(command,"MAX_STATIC_STRINGS")==0)
754 " MAX_STATIC_STRINGS is the size in bytes of a buffer to hold compiled\n\
755 strings before they're written into longer-term storage. 2000 bytes is \n\
756 plenty, allowing string constants of up to about 3000 characters long.\n\
757 Inform automatically ensures that this is at least twice the size of\n\
758 MAX_QTEXT_SIZE, to be on the safe side.");
761 if (strcmp(command,"MAX_ZCODE_SIZE")==0)
764 " MAX_ZCODE_SIZE is the size in bytes of a buffer to hold compiled \n\
765 code for a single routine. (It applies to both Z-code and Glulx, \n\
766 despite the name.) As a guide, the longest library routine is \n\
767 about 6500 bytes long in Z-code; about twice that in Glulx.");
770 if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
773 " MAX_LINK_DATA_SIZE is the size in bytes of a buffer to hold module \n\
774 link data before it's written into longer-term storage. 2000 bytes \n\
778 if (strcmp(command,"MAX_LOW_STRINGS")==0)
780 " MAX_LOW_STRINGS is the size in bytes of a buffer to hold all the \n\
781 compiled \"low strings\" which are to be written above the synonyms table \n\
782 in the Z-machine. 1024 is plenty.\n");
785 if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
787 " MAX_TRANSCRIPT_SIZE is only allocated for the abbreviations optimisation \n\
788 switch, and has the size in bytes of a buffer to hold the entire text of\n\
789 the game being compiled: it has to be enormous, say 100000 to 200000.\n");
792 if (strcmp(command,"MAX_CLASSES")==0)
794 " MAX_CLASSES maximum number of object classes which can be defined. This\n\
795 is cheap to increase.\n");
798 if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
800 " MAX_INCLUSION_DEPTH is the number of nested includes permitted.\n");
803 if (strcmp(command,"MAX_SOURCE_FILES")==0)
805 " MAX_SOURCE_FILES is the number of source files that can be read in the \n\
809 if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
811 " MAX_INDIV_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
812 table of ..variable values.\n");
815 if (strcmp(command,"INDIV_PROP_START")==0)
817 " Properties 1 to INDIV_PROP_START-1 are common properties; individual\n\
818 properties are numbered INDIV_PROP_START and up.\n");
821 if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
823 " MAX_OBJ_PROP_COUNT is the maximum number of properties a single object \n\
824 can have. (Glulx only)\n");
827 if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
829 " MAX_OBJ_PROP_TABLE_SIZE is the number of words allocated to hold a \n\
830 single object's properties. (Glulx only)\n");
833 if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
835 " MAX_LOCAL_VARIABLES is the number of local variables (including \n\
836 arguments) allowed in a procedure. (Glulx only)\n");
839 if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
841 " MAX_GLOBAL_VARIABLES is the number of global variables allowed in the \n\
842 program. (Glulx only)\n");
845 if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
848 " MAX_NUM_STATIC_STRINGS is the maximum number of compiled strings \n\
849 allowed in the program. (Glulx only)\n");
852 if (strcmp(command,"MAX_UNICODE_CHARS")==0)
855 " MAX_UNICODE_CHARS is the maximum number of different Unicode characters \n\
856 (beyond the Latin-1 range, $00..$FF) which the game text can use. \n\
860 if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
863 " ALLOC_CHUNK_SIZE is a base unit of Inform's internal memory allocation \n\
864 for various structures.\n");
867 if (strcmp(command,"MAX_STACK_SIZE")==0)
870 " MAX_STACK_SIZE is the maximum size (in bytes) of the interpreter stack \n\
871 during gameplay. (Glulx only)\n");
874 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
877 " MEMORY_MAP_EXTENSION is the number of bytes (all zeroes) to map into \n\
878 memory after the game file. (Glulx only)\n");
881 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
884 " WARN_UNUSED_ROUTINES, if set to 2, will display a warning for each \n\
885 routine in the game file which is never called. (This includes \n\
886 routines called only from uncalled routines, etc.) If set to 1, will warn \n\
887 only about functions in game code, not in the system library.\n");
890 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
893 " OMIT_UNUSED_ROUTINES, if set to 1, will avoid compiling unused routines \n\
894 into the game file.\n");
897 if (strcmp(command,"SERIAL")==0)
900 " SERIAL, if set, will be used as the six digit serial number written into \n\
901 the header of the output file.\n");
905 printf("No such memory setting as \"%s\"\n",command);
910 /* Parse a decimal number as an int32. Return true if a valid number
911 was found; otherwise print a warning and return false.
913 Anything over nine digits is considered an overflow; we report a
914 warning but return +/- 999999999 (and true). This is not entirely
915 clever about leading zeroes ("0000000001" is treated as an
916 overflow) but this is better than trying to detect genuine
919 (Some Glulx settings might conceivably want to go up to $7FFFFFFF,
920 which is a ten-digit number, but we're not going to allow that
923 This used to rely on atoi(), and we retain the atoi() behavior of
924 ignoring garbage characters after a valid decimal number.
926 static int parse_memory_setting(char *str, char *label, int32 *result)
934 while (*cx == ' ') cx++;
936 val = strtol(cx, &ex, 10);
939 printf("Bad numerical setting in $ command \"%s=%s\"\n",
947 printf("Numerical setting underflowed in $ command \"%s=%s\" (limiting to %ld)\n",
954 printf("Numerical setting overflowed in $ command \"%s=%s\" (limiting to %ld)\n",
959 *result = (int32)val;
963 extern void memory_command(char *command)
964 { int i, k, flag=0; int32 j;
966 for (k=0; command[k]!=0; k++)
967 if (islower(command[k])) command[k]=toupper(command[k]);
969 if (command[0]=='?') { explain_parameter(command+1); return; }
971 if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; }
972 if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; }
973 if (strcmp(command, "SMALL")==0) { set_memory_sizes(SMALL_SIZE); return; }
974 if (strcmp(command, "LIST")==0) { list_memory_sizes(); return; }
975 for (i=0; command[i]!=0; i++)
976 { if (command[i]=='=')
978 if (!parse_memory_setting(command+i+1, command, &j)) {
981 if (strcmp(command,"BUFFER_LENGTH")==0)
983 if (strcmp(command,"MAX_QTEXT_SIZE")==0)
984 { MAX_QTEXT_SIZE=j, flag=1;
985 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
986 MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
988 if (strcmp(command,"MAX_SYMBOLS")==0)
989 MAX_SYMBOLS=j, flag=1;
990 if (strcmp(command,"MAX_BANK_SIZE")==0)
992 if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
993 SYMBOLS_CHUNK_SIZE=j, flag=1;
994 if (strcmp(command,"BANK_CHUNK_SIZE")==0)
996 if (strcmp(command,"HASH_TAB_SIZE")==0)
997 HASH_TAB_SIZE=j, flag=1;
998 if (strcmp(command,"MAX_OBJECTS")==0)
999 MAX_OBJECTS=j, flag=1;
1000 if (strcmp(command,"MAX_ACTIONS")==0)
1001 MAX_ACTIONS=j, flag=1;
1002 if (strcmp(command,"MAX_ADJECTIVES")==0)
1003 MAX_ADJECTIVES=j, flag=1;
1004 if (strcmp(command,"MAX_DICT_ENTRIES")==0)
1005 MAX_DICT_ENTRIES=j, flag=1;
1006 if (strcmp(command,"DICT_WORD_SIZE")==0)
1007 { DICT_WORD_SIZE=j, flag=1;
1008 DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j;
1010 if (strcmp(command,"DICT_CHAR_SIZE")==0)
1011 DICT_CHAR_SIZE=j, flag=1;
1012 if (strcmp(command,"NUM_ATTR_BYTES")==0)
1013 { NUM_ATTR_BYTES=j, flag=1;
1014 NUM_ATTR_BYTES_g=NUM_ATTR_BYTES_z=j;
1016 if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
1017 ZCODE_HEADER_EXT_WORDS=j, flag=1;
1018 if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
1019 ZCODE_HEADER_FLAGS_3=j, flag=1;
1020 if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
1021 GLULX_OBJECT_EXT_BYTES=j, flag=1;
1022 if (strcmp(command,"MAX_STATIC_DATA")==0)
1023 MAX_STATIC_DATA=j, flag=1;
1024 if (strcmp(command,"MAX_OLDEPTH")==0)
1026 if (strcmp(command,"MAX_ROUTINES")==0)
1028 if (strcmp(command,"MAX_GCONSTANTS")==0)
1030 if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
1031 { MAX_PROP_TABLE_SIZE=j, flag=1;
1032 MAX_PROP_TABLE_SIZE_g=MAX_PROP_TABLE_SIZE_z=j;
1034 if (strcmp(command,"MAX_FORWARD_REFS")==0)
1036 if (strcmp(command,"STACK_SIZE")==0)
1038 if (strcmp(command,"STACK_LONG_SLOTS")==0)
1040 if (strcmp(command,"STACK_SHORT_LENGTH")==0)
1042 if (strcmp(command,"MAX_ABBREVS")==0)
1043 MAX_ABBREVS=j, flag=1;
1044 if (strcmp(command,"MAX_DYNAMIC_STRINGS")==0)
1045 { MAX_DYNAMIC_STRINGS=j, flag=1;
1046 MAX_DYNAMIC_STRINGS_g=MAX_DYNAMIC_STRINGS_z=j;
1048 if (strcmp(command,"MAX_ARRAYS")==0)
1049 MAX_ARRAYS=j, flag=1;
1050 if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
1051 MAX_EXPRESSION_NODES=j, flag=1;
1052 if (strcmp(command,"MAX_VERBS")==0)
1053 MAX_VERBS=j, flag=1;
1054 if (strcmp(command,"MAX_VERBSPACE")==0)
1055 MAX_VERBSPACE=j, flag=1;
1056 if (strcmp(command,"MAX_LABELS")==0)
1057 MAX_LABELS=j, flag=1;
1058 if (strcmp(command,"MAX_LINESPACE")==0)
1059 MAX_LINESPACE=j, flag=1;
1060 if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
1061 MAX_NUM_STATIC_STRINGS=j, flag=1;
1062 if (strcmp(command,"MAX_STATIC_STRINGS")==0)
1063 { MAX_STATIC_STRINGS=j, flag=1;
1064 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
1065 MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
1067 if (strcmp(command,"MAX_ZCODE_SIZE")==0)
1068 { MAX_ZCODE_SIZE=j, flag=1;
1069 MAX_ZCODE_SIZE_g=MAX_ZCODE_SIZE_z=j;
1071 if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
1072 MAX_LINK_DATA_SIZE=j, flag=1;
1073 if (strcmp(command,"MAX_LOW_STRINGS")==0)
1074 MAX_LOW_STRINGS=j, flag=1;
1075 if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
1076 MAX_TRANSCRIPT_SIZE=j, flag=1;
1077 if (strcmp(command,"MAX_CLASSES")==0)
1078 MAX_CLASSES=j, flag=1;
1079 if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
1080 MAX_INCLUSION_DEPTH=j, flag=1;
1081 if (strcmp(command,"MAX_SOURCE_FILES")==0)
1082 MAX_SOURCE_FILES=j, flag=1;
1083 if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
1084 MAX_INDIV_PROP_TABLE_SIZE=j, flag=1;
1085 if (strcmp(command,"INDIV_PROP_START")==0)
1086 INDIV_PROP_START=j, flag=1;
1087 if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
1088 MAX_OBJ_PROP_TABLE_SIZE=j, flag=1;
1089 if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
1090 MAX_OBJ_PROP_COUNT=j, flag=1;
1091 if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
1092 { MAX_LOCAL_VARIABLES=j, flag=1;
1093 MAX_LOCAL_VARIABLES_g=MAX_LOCAL_VARIABLES_z=j;
1095 if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
1096 { MAX_GLOBAL_VARIABLES=j, flag=1;
1097 MAX_GLOBAL_VARIABLES_g=MAX_GLOBAL_VARIABLES_z=j;
1099 if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
1100 { ALLOC_CHUNK_SIZE=j, flag=1;
1101 ALLOC_CHUNK_SIZE_g=ALLOC_CHUNK_SIZE_z=j;
1103 if (strcmp(command,"MAX_UNICODE_CHARS")==0)
1104 MAX_UNICODE_CHARS=j, flag=1;
1105 if (strcmp(command,"MAX_STACK_SIZE")==0)
1107 MAX_STACK_SIZE=j, flag=1;
1108 /* Adjust up to a 256-byte boundary. */
1109 MAX_STACK_SIZE = (MAX_STACK_SIZE + 0xFF) & (~0xFF);
1111 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
1113 MEMORY_MAP_EXTENSION=j, flag=1;
1114 /* Adjust up to a 256-byte boundary. */
1115 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
1117 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
1119 WARN_UNUSED_ROUTINES=j, flag=1;
1120 if (WARN_UNUSED_ROUTINES > 2 || WARN_UNUSED_ROUTINES < 0)
1121 WARN_UNUSED_ROUTINES = 2;
1123 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
1125 OMIT_UNUSED_ROUTINES=j, flag=1;
1126 if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
1127 OMIT_UNUSED_ROUTINES = 1;
1129 if (strcmp(command,"SERIAL")==0)
1131 if (j >= 0 && j <= 999999)
1133 sprintf(serial_code_buffer,"%06d",j);
1134 serial_code_given_in_program = TRUE;
1140 printf("No such memory setting as \"%s\"\n", command);
1142 printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n\
1143 It should be safe to omit it (putting nothing in its place).\n", command);
1147 printf("No such memory $ command as \"%s\"\n",command);
1150 extern void print_memory_usage(void)
1152 printf("Properties table used %d\n",
1153 properties_table_size);
1154 printf("Allocated a total of %ld bytes of memory\n",
1155 (long int) malloced_bytes);
1158 /* ========================================================================= */
1159 /* Data structure management routines */
1160 /* ------------------------------------------------------------------------- */
1162 extern void init_memory_vars(void)
1163 { malloced_bytes = 0;
1166 extern void memory_begin_pass(void) { }
1168 extern void memory_allocate_arrays(void) { }
1170 extern void memory_free_arrays(void) { }
1172 /* ========================================================================= */