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 - 2020 */
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_EXPRESSION_NODES;
263 int32 MAX_STATIC_STRINGS;
264 int32 MAX_ZCODE_SIZE;
266 int32 MAX_TRANSCRIPT_SIZE;
268 int32 MAX_LINK_DATA_SIZE;
269 int MAX_INCLUSION_DEPTH;
270 int MAX_SOURCE_FILES;
271 int32 MAX_INDIV_PROP_TABLE_SIZE;
272 int32 MAX_OBJ_PROP_TABLE_SIZE;
273 int MAX_OBJ_PROP_COUNT;
274 int MAX_LOCAL_VARIABLES;
275 int MAX_GLOBAL_VARIABLES;
276 int DICT_WORD_SIZE; /* number of characters in a dict word */
277 int DICT_CHAR_SIZE; /* (glulx) 1 for one-byte chars, 4 for Unicode chars */
278 int DICT_WORD_BYTES; /* DICT_WORD_SIZE*DICT_CHAR_SIZE */
279 int ZCODE_HEADER_EXT_WORDS; /* (zcode 1.0) requested header extension size */
280 int ZCODE_HEADER_FLAGS_3; /* (zcode 1.1) value to place in Flags 3 word */
282 int GLULX_OBJECT_EXT_BYTES; /* (glulx) extra bytes for each object record */
283 int32 MAX_NUM_STATIC_STRINGS;
284 int32 MAX_UNICODE_CHARS;
285 int32 MAX_STACK_SIZE;
286 int32 MEMORY_MAP_EXTENSION;
287 int ALLOC_CHUNK_SIZE;
288 int WARN_UNUSED_ROUTINES; /* 0: no, 1: yes except in system files, 2: yes always */
289 int OMIT_UNUSED_ROUTINES; /* 0: no, 1: yes */
291 /* The way memory sizes are set causes great nuisance for those parameters
292 which have different defaults under Z-code and Glulx. We have to get
293 the defaults right whether the user sets "-G $HUGE" or "$HUGE -G".
294 And an explicit value set by the user should override both defaults. */
295 static int32 MAX_ZCODE_SIZE_z, MAX_ZCODE_SIZE_g;
296 static int MAX_PROP_TABLE_SIZE_z, MAX_PROP_TABLE_SIZE_g;
297 static int MAX_GLOBAL_VARIABLES_z, MAX_GLOBAL_VARIABLES_g;
298 static int MAX_LOCAL_VARIABLES_z, MAX_LOCAL_VARIABLES_g;
299 static int DICT_WORD_SIZE_z, DICT_WORD_SIZE_g;
300 static int NUM_ATTR_BYTES_z, NUM_ATTR_BYTES_g;
301 static int ALLOC_CHUNK_SIZE_z, ALLOC_CHUNK_SIZE_g;
303 /* ------------------------------------------------------------------------- */
304 /* Memory control from the command line */
305 /* ------------------------------------------------------------------------- */
307 static void list_memory_sizes(void)
308 { printf("+--------------------------------------+\n");
309 printf("| %25s = %-7s |\n","Memory setting","Value");
310 printf("+--------------------------------------+\n");
311 printf("| %25s = %-7d |\n","MAX_ABBREVS",MAX_ABBREVS);
312 printf("| %25s = %-7d |\n","MAX_ACTIONS",MAX_ACTIONS);
313 printf("| %25s = %-7d |\n","MAX_ADJECTIVES",MAX_ADJECTIVES);
314 printf("| %25s = %-7d |\n","ALLOC_CHUNK_SIZE",ALLOC_CHUNK_SIZE);
315 printf("| %25s = %-7d |\n","MAX_ARRAYS",MAX_ARRAYS);
316 printf("| %25s = %-7d |\n","NUM_ATTR_BYTES",NUM_ATTR_BYTES);
317 printf("| %25s = %-7d |\n","MAX_CLASSES",MAX_CLASSES);
318 printf("| %25s = %-7d |\n","MAX_DICT_ENTRIES",MAX_DICT_ENTRIES);
319 printf("| %25s = %-7d |\n","DICT_WORD_SIZE",DICT_WORD_SIZE);
321 printf("| %25s = %-7d |\n","DICT_CHAR_SIZE",DICT_CHAR_SIZE);
322 printf("| %25s = %-7d |\n","MAX_EXPRESSION_NODES",MAX_EXPRESSION_NODES);
323 printf("| %25s = %-7d |\n","MAX_GLOBAL_VARIABLES",MAX_GLOBAL_VARIABLES);
324 printf("| %25s = %-7d |\n","HASH_TAB_SIZE",HASH_TAB_SIZE);
326 printf("| %25s = %-7d |\n","ZCODE_HEADER_EXT_WORDS",ZCODE_HEADER_EXT_WORDS);
328 printf("| %25s = %-7d |\n","ZCODE_HEADER_FLAGS_3",ZCODE_HEADER_FLAGS_3);
329 printf("| %25s = %-7d |\n","MAX_INCLUSION_DEPTH",MAX_INCLUSION_DEPTH);
330 printf("| %25s = %-7d |\n","MAX_INDIV_PROP_TABLE_SIZE", MAX_INDIV_PROP_TABLE_SIZE);
331 printf("| %25s = %-7d |\n","INDIV_PROP_START", INDIV_PROP_START);
332 printf("| %25s = %-7d |\n","MAX_LABELS",MAX_LABELS);
333 printf("| %25s = %-7d |\n","MAX_LINESPACE",MAX_LINESPACE);
334 printf("| %25s = %-7d |\n","MAX_LINK_DATA_SIZE",MAX_LINK_DATA_SIZE);
336 printf("| %25s = %-7d |\n","MAX_LOCAL_VARIABLES",MAX_LOCAL_VARIABLES);
337 printf("| %25s = %-7d |\n","MAX_LOW_STRINGS",MAX_LOW_STRINGS);
339 printf("| %25s = %-7d |\n","MEMORY_MAP_EXTENSION",
340 MEMORY_MAP_EXTENSION);
342 printf("| %25s = %-7d |\n","MAX_NUM_STATIC_STRINGS",
343 MAX_NUM_STATIC_STRINGS);
344 printf("| %25s = %-7d |\n","MAX_OBJECTS",MAX_OBJECTS);
346 printf("| %25s = %-7d |\n","GLULX_OBJECT_EXT_BYTES",
347 GLULX_OBJECT_EXT_BYTES);
349 printf("| %25s = %-7d |\n","MAX_OBJ_PROP_COUNT",
352 printf("| %25s = %-7d |\n","MAX_OBJ_PROP_TABLE_SIZE",
353 MAX_OBJ_PROP_TABLE_SIZE);
354 printf("| %25s = %-7d |\n","MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE);
355 printf("| %25s = %-7d |\n","MAX_QTEXT_SIZE",MAX_QTEXT_SIZE);
356 printf("| %25s = %-7d |\n","MAX_SOURCE_FILES",MAX_SOURCE_FILES);
358 printf("| %25s = %-7ld |\n","MAX_STACK_SIZE",
359 (long int) MAX_STACK_SIZE);
360 printf("| %25s = %-7d |\n","MAX_STATIC_DATA",MAX_STATIC_DATA);
361 printf("| %25s = %-7ld |\n","MAX_STATIC_STRINGS",
362 (long int) MAX_STATIC_STRINGS);
363 printf("| %25s = %-7d |\n","MAX_SYMBOLS",MAX_SYMBOLS);
364 printf("| %25s = %-7d |\n","SYMBOLS_CHUNK_SIZE",SYMBOLS_CHUNK_SIZE);
365 printf("| %25s = %-7ld |\n","MAX_TRANSCRIPT_SIZE",
366 (long int) MAX_TRANSCRIPT_SIZE);
368 printf("| %25s = %-7ld |\n","MAX_UNICODE_CHARS",
369 (long int) MAX_UNICODE_CHARS);
370 printf("| %25s = %-7d |\n","WARN_UNUSED_ROUTINES",WARN_UNUSED_ROUTINES);
371 printf("| %25s = %-7d |\n","OMIT_UNUSED_ROUTINES",OMIT_UNUSED_ROUTINES);
372 printf("| %25s = %-7d |\n","MAX_VERBS",MAX_VERBS);
373 printf("| %25s = %-7d |\n","MAX_VERBSPACE",MAX_VERBSPACE);
374 printf("| %25s = %-7ld |\n","MAX_ZCODE_SIZE",
375 (long int) MAX_ZCODE_SIZE);
376 printf("+--------------------------------------+\n");
379 extern void set_memory_sizes(int size_flag)
381 if (size_flag == HUGE_SIZE)
383 MAX_QTEXT_SIZE = 4000;
386 SYMBOLS_CHUNK_SIZE = 5000;
393 MAX_DICT_ENTRIES = 2000;
394 MAX_STATIC_DATA = 10000;
396 MAX_PROP_TABLE_SIZE_z = 30000;
397 MAX_PROP_TABLE_SIZE_g = 60000;
401 MAX_EXPRESSION_NODES = 100;
403 MAX_VERBSPACE = 4096;
405 MAX_LINESPACE = 16000;
407 MAX_STATIC_STRINGS = 8000;
408 MAX_ZCODE_SIZE_z = 20000;
409 MAX_ZCODE_SIZE_g = 40000;
410 MAX_LINK_DATA_SIZE = 2000;
412 MAX_LOW_STRINGS = 2048;
414 MAX_TRANSCRIPT_SIZE = 200000;
415 MAX_NUM_STATIC_STRINGS = 20000;
419 MAX_OBJ_PROP_COUNT = 128;
420 MAX_OBJ_PROP_TABLE_SIZE = 4096;
422 MAX_INDIV_PROP_TABLE_SIZE = 15000;
425 MAX_GLOBAL_VARIABLES_z = 240;
426 MAX_GLOBAL_VARIABLES_g = 512;
428 ALLOC_CHUNK_SIZE_z = 8192;
429 ALLOC_CHUNK_SIZE_g = 32768;
431 if (size_flag == LARGE_SIZE)
433 MAX_QTEXT_SIZE = 4000;
436 SYMBOLS_CHUNK_SIZE = 5000;
443 MAX_DICT_ENTRIES = 1300;
444 MAX_STATIC_DATA = 10000;
446 MAX_PROP_TABLE_SIZE_z = 15000;
447 MAX_PROP_TABLE_SIZE_g = 30000;
451 MAX_EXPRESSION_NODES = 100;
453 MAX_VERBSPACE = 4096;
454 MAX_LINESPACE = 10000;
457 MAX_STATIC_STRINGS = 8000;
458 MAX_ZCODE_SIZE_z = 20000;
459 MAX_ZCODE_SIZE_g = 40000;
460 MAX_LINK_DATA_SIZE = 2000;
462 MAX_LOW_STRINGS = 2048;
464 MAX_TRANSCRIPT_SIZE = 200000;
465 MAX_NUM_STATIC_STRINGS = 20000;
469 MAX_OBJ_PROP_COUNT = 64;
470 MAX_OBJ_PROP_TABLE_SIZE = 2048;
472 MAX_INDIV_PROP_TABLE_SIZE = 10000;
475 MAX_GLOBAL_VARIABLES_z = 240;
476 MAX_GLOBAL_VARIABLES_g = 512;
478 ALLOC_CHUNK_SIZE_z = 8192;
479 ALLOC_CHUNK_SIZE_g = 16384;
481 if (size_flag == SMALL_SIZE)
483 MAX_QTEXT_SIZE = 4000;
486 SYMBOLS_CHUNK_SIZE = 2500;
493 MAX_DICT_ENTRIES = 700;
494 MAX_STATIC_DATA = 10000;
496 MAX_PROP_TABLE_SIZE_z = 8000;
497 MAX_PROP_TABLE_SIZE_g = 16000;
501 MAX_EXPRESSION_NODES = 40;
503 MAX_VERBSPACE = 2048;
504 MAX_LINESPACE = 10000;
507 MAX_STATIC_STRINGS = 8000;
508 MAX_ZCODE_SIZE_z = 10000;
509 MAX_ZCODE_SIZE_g = 20000;
510 MAX_LINK_DATA_SIZE = 1000;
512 MAX_LOW_STRINGS = 1024;
514 MAX_TRANSCRIPT_SIZE = 100000;
515 MAX_NUM_STATIC_STRINGS = 10000;
519 MAX_OBJ_PROP_COUNT = 64;
520 MAX_OBJ_PROP_TABLE_SIZE = 1024;
522 MAX_INDIV_PROP_TABLE_SIZE = 5000;
525 MAX_GLOBAL_VARIABLES_z = 240;
526 MAX_GLOBAL_VARIABLES_g = 256;
528 ALLOC_CHUNK_SIZE_z = 8192;
529 ALLOC_CHUNK_SIZE_g = 8192;
532 /* Regardless of size_flag... */
533 MAX_SOURCE_FILES = 256;
534 MAX_INCLUSION_DEPTH = 5;
535 MAX_LOCAL_VARIABLES_z = 16;
536 MAX_LOCAL_VARIABLES_g = 32;
538 DICT_WORD_SIZE_z = 6;
539 DICT_WORD_SIZE_g = 9;
540 NUM_ATTR_BYTES_z = 6;
541 NUM_ATTR_BYTES_g = 7;
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 INDIV_PROP_START = 64;
575 MAX_ZCODE_SIZE = MAX_ZCODE_SIZE_g;
576 MAX_PROP_TABLE_SIZE = MAX_PROP_TABLE_SIZE_g;
577 MAX_GLOBAL_VARIABLES = MAX_GLOBAL_VARIABLES_g;
578 MAX_LOCAL_VARIABLES = MAX_LOCAL_VARIABLES_g;
579 DICT_WORD_SIZE = DICT_WORD_SIZE_g;
580 NUM_ATTR_BYTES = NUM_ATTR_BYTES_g;
581 ALLOC_CHUNK_SIZE = ALLOC_CHUNK_SIZE_g;
582 INDIV_PROP_START = 256;
586 static void explain_parameter(char *command)
588 if (strcmp(command,"MAX_QTEXT_SIZE")==0)
590 " MAX_QTEXT_SIZE is the maximum length of a quoted string. Increasing\n\
591 by 1 costs 5 bytes (for lexical analysis memory). Inform automatically\n\
592 ensures that MAX_STATIC_STRINGS is at least twice the size of this.");
595 if (strcmp(command,"MAX_SYMBOLS")==0)
597 " MAX_SYMBOLS is the maximum number of symbols - names of variables, \n\
598 objects, routines, the many internal Inform-generated names and so on.\n");
601 if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
603 " The symbols names are stored in memory which is allocated in chunks \n\
604 of size SYMBOLS_CHUNK_SIZE.\n");
607 if (strcmp(command,"HASH_TAB_SIZE")==0)
609 " HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
613 if (strcmp(command,"MAX_OBJECTS")==0)
615 " MAX_OBJECTS is the maximum number of objects. (If compiling a version-3 \n\
616 game, 255 is an absolute maximum in any event.)\n");
619 if (strcmp(command,"MAX_ACTIONS")==0)
621 " MAX_ACTIONS is the maximum number of actions - that is, routines such as \n\
622 TakeSub which are referenced in the grammar table.\n");
625 if (strcmp(command,"MAX_ADJECTIVES")==0)
627 " MAX_ADJECTIVES is the maximum number of different \"adjectives\" in the \n\
628 grammar table. Adjectives are misleadingly named: they are words such as \n\
629 \"in\", \"under\" and the like.\n");
632 if (strcmp(command,"MAX_DICT_ENTRIES")==0)
634 " MAX_DICT_ENTRIES is the maximum number of words which can be entered \n\
635 into the game's dictionary. It costs 29 bytes to increase this by one.\n");
638 if (strcmp(command,"DICT_WORD_SIZE")==0)
640 " DICT_WORD_SIZE is the number of characters in a dictionary word. In \n\
641 Z-code this is always 6 (only 4 are used in v3 games). In Glulx it \n\
642 can be any number.\n");
645 if (strcmp(command,"DICT_CHAR_SIZE")==0)
647 " DICT_CHAR_SIZE is the byte size of one character in the dictionary. \n\
648 (This is only meaningful in Glulx, since Z-code has compressed dictionary \n\
649 words.) It can be either 1 (the default) or 4 (to enable full Unicode \n\
653 if (strcmp(command,"NUM_ATTR_BYTES")==0)
655 " NUM_ATTR_BYTES is the space used to store attribute flags. Each byte \n\
656 stores eight attributes. In Z-code this is always 6 (only 4 are used in \n\
657 v3 games). In Glulx it can be any number which is a multiple of four, \n\
661 if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
663 " ZCODE_HEADER_EXT_WORDS is the number of words in the Z-code header \n\
664 extension table (Z-Spec 1.0). The -W switch also sets this. It defaults \n\
665 to 3, but can be set higher. (It can be set lower if no Unicode \n\
666 translation table is created.)\n");
669 if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
671 " ZCODE_HEADER_FLAGS_3 is the value to store in the Flags 3 word of the \n\
672 header extension table (Z-Spec 1.1).\n");
675 if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
677 " GLULX_OBJECT_EXT_BYTES is an amount of additional space to add to each \n\
678 object record. It is initialized to zero bytes, and the game is free to \n\
679 use it as desired. (This is only meaningful in Glulx, since Z-code \n\
680 specifies the object structure.)\n");
683 if (strcmp(command,"MAX_STATIC_DATA")==0)
685 " MAX_STATIC_DATA is the size of an array of integers holding initial \n\
686 values for arrays and strings stored as ASCII inside the Z-machine. It \n\
687 should be at least 1024 but seldom needs much more.\n");
690 if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
692 " MAX_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
693 properties table.\n");
696 if (strcmp(command,"MAX_ABBREVS")==0)
698 " MAX_ABBREVS is the maximum number of declared abbreviations. It is not \n\
699 allowed to exceed 64.\n");
702 if (strcmp(command,"MAX_ARRAYS")==0)
704 " MAX_ARRAYS is the maximum number of declared arrays.\n");
707 if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
709 " MAX_EXPRESSION_NODES is the maximum number of nodes in the expression \n\
710 evaluator's storage for parse trees. In effect, it measures how \n\
711 complicated algebraic expressions are allowed to be. Increasing it by \n\
712 one costs about 80 bytes.\n");
715 if (strcmp(command,"MAX_VERBS")==0)
717 " MAX_VERBS is the maximum number of verbs (such as \"take\") which can be \n\
718 defined, each with its own grammar. To increase it by one costs about\n\
719 128 bytes. A full game will contain at least 100.\n");
722 if (strcmp(command,"MAX_VERBSPACE")==0)
724 " MAX_VERBSPACE is the size of workspace used to store verb words, so may\n\
725 need increasing in games with many synonyms: unlikely to exceed 4K.\n");
728 if (strcmp(command,"MAX_LABELS")==0)
730 " MAX_LABELS is the maximum number of label points in any one routine.\n\
731 (If the -k debugging information switch is set, MAX_LABELS is raised to\n\
732 a minimum level of 2000, as about twice the normal number of label points\n\
733 are needed to generate tables of how source code corresponds to positions\n\
734 in compiled code.)");
737 if (strcmp(command,"MAX_LINESPACE")==0)
739 " MAX_LINESPACE is the size of workspace used to store grammar lines, so \n\
740 may need increasing in games with complex or extensive grammars.\n");
743 if (strcmp(command,"MAX_STATIC_STRINGS")==0)
746 " MAX_STATIC_STRINGS is the size in bytes of a buffer to hold compiled\n\
747 strings before they're written into longer-term storage. 2000 bytes is \n\
748 plenty, allowing string constants of up to about 3000 characters long.\n\
749 Inform automatically ensures that this is at least twice the size of\n\
750 MAX_QTEXT_SIZE, to be on the safe side.");
753 if (strcmp(command,"MAX_ZCODE_SIZE")==0)
756 " MAX_ZCODE_SIZE is the size in bytes of a buffer to hold compiled \n\
757 code for a single routine. (It applies to both Z-code and Glulx, \n\
758 despite the name.) As a guide, the longest library routine is \n\
759 about 6500 bytes long in Z-code; about twice that in Glulx.");
762 if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
765 " MAX_LINK_DATA_SIZE is the size in bytes of a buffer to hold module \n\
766 link data before it's written into longer-term storage. 2000 bytes \n\
770 if (strcmp(command,"MAX_LOW_STRINGS")==0)
772 " MAX_LOW_STRINGS is the size in bytes of a buffer to hold all the \n\
773 compiled \"low strings\" which are to be written above the synonyms table \n\
774 in the Z-machine. 1024 is plenty.\n");
777 if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
779 " MAX_TRANSCRIPT_SIZE is only allocated for the abbreviations optimisation \n\
780 switch, and has the size in bytes of a buffer to hold the entire text of\n\
781 the game being compiled: it has to be enormous, say 100000 to 200000.\n");
784 if (strcmp(command,"MAX_CLASSES")==0)
786 " MAX_CLASSES maximum number of object classes which can be defined. This\n\
787 is cheap to increase.\n");
790 if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
792 " MAX_INCLUSION_DEPTH is the number of nested includes permitted.\n");
795 if (strcmp(command,"MAX_SOURCE_FILES")==0)
797 " MAX_SOURCE_FILES is the number of source files that can be read in the \n\
801 if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
803 " MAX_INDIV_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
804 table of ..variable values.\n");
807 if (strcmp(command,"INDIV_PROP_START")==0)
809 " Properties 1 to INDIV_PROP_START-1 are common properties; individual\n\
810 properties are numbered INDIV_PROP_START and up.\n");
813 if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
815 " MAX_OBJ_PROP_COUNT is the maximum number of properties a single object \n\
816 can have. (Glulx only)\n");
819 if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
821 " MAX_OBJ_PROP_TABLE_SIZE is the number of words allocated to hold a \n\
822 single object's properties. (Glulx only)\n");
825 if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
827 " MAX_LOCAL_VARIABLES is the number of local variables (including \n\
828 arguments) allowed in a procedure. (Glulx only)\n");
831 if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
833 " MAX_GLOBAL_VARIABLES is the number of global variables allowed in the \n\
834 program. (Glulx only)\n");
837 if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
840 " MAX_NUM_STATIC_STRINGS is the maximum number of compiled strings \n\
841 allowed in the program. (Glulx only)\n");
844 if (strcmp(command,"MAX_UNICODE_CHARS")==0)
847 " MAX_UNICODE_CHARS is the maximum number of different Unicode characters \n\
848 (beyond the Latin-1 range, $00..$FF) which the game text can use. \n\
852 if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
855 " ALLOC_CHUNK_SIZE is a base unit of Inform's internal memory allocation \n\
856 for various structures.\n");
859 if (strcmp(command,"MAX_STACK_SIZE")==0)
862 " MAX_STACK_SIZE is the maximum size (in bytes) of the interpreter stack \n\
863 during gameplay. (Glulx only)\n");
866 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
869 " MEMORY_MAP_EXTENSION is the number of bytes (all zeroes) to map into \n\
870 memory after the game file. (Glulx only)\n");
873 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
876 " WARN_UNUSED_ROUTINES, if set to 2, will display a warning for each \n\
877 routine in the game file which is never called. (This includes \n\
878 routines called only from uncalled routines, etc.) If set to 1, will warn \n\
879 only about functions in game code, not in the system library.\n");
882 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
885 " OMIT_UNUSED_ROUTINES, if set to 1, will avoid compiling unused routines \n\
886 into the game file.\n");
889 if (strcmp(command,"SERIAL")==0)
892 " SERIAL, if set, will be used as the six digit serial number written into \n\
893 the header of the output file.\n");
897 printf("No such memory setting as \"%s\"\n",command);
902 /* Parse a decimal number as an int32. Return true if a valid number
903 was found; otherwise print a warning and return false.
905 Anything over nine digits is considered an overflow; we report a
906 warning but return +/- 999999999 (and true). This is not entirely
907 clever about leading zeroes ("0000000001" is treated as an
908 overflow) but this is better than trying to detect genuine
911 (Some Glulx settings might conceivably want to go up to $7FFFFFFF,
912 which is a ten-digit number, but we're not going to allow that
915 This used to rely on atoi(), and we retain the atoi() behavior of
916 ignoring garbage characters after a valid decimal number.
918 static int parse_memory_setting(char *str, char *label, int32 *result)
926 while (*cx == ' ') cx++;
928 val = strtol(cx, &ex, 10);
931 printf("Bad numerical setting in $ command \"%s=%s\"\n",
939 printf("Numerical setting underflowed in $ command \"%s=%s\" (limiting to %ld)\n",
946 printf("Numerical setting overflowed in $ command \"%s=%s\" (limiting to %ld)\n",
951 *result = (int32)val;
955 extern void memory_command(char *command)
956 { int i, k, flag=0; int32 j;
958 for (k=0; command[k]!=0; k++)
959 if (islower(command[k])) command[k]=toupper(command[k]);
961 if (command[0]=='?') { explain_parameter(command+1); return; }
963 if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; }
964 if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; }
965 if (strcmp(command, "SMALL")==0) { set_memory_sizes(SMALL_SIZE); return; }
966 if (strcmp(command, "LIST")==0) { list_memory_sizes(); return; }
967 for (i=0; command[i]!=0; i++)
968 { if (command[i]=='=')
970 if (!parse_memory_setting(command+i+1, command, &j)) {
973 if (strcmp(command,"BUFFER_LENGTH")==0)
975 if (strcmp(command,"MAX_QTEXT_SIZE")==0)
976 { MAX_QTEXT_SIZE=j, flag=1;
977 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
978 MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
980 if (strcmp(command,"MAX_SYMBOLS")==0)
981 MAX_SYMBOLS=j, flag=1;
982 if (strcmp(command,"MAX_BANK_SIZE")==0)
984 if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
985 SYMBOLS_CHUNK_SIZE=j, flag=1;
986 if (strcmp(command,"BANK_CHUNK_SIZE")==0)
988 if (strcmp(command,"HASH_TAB_SIZE")==0)
989 HASH_TAB_SIZE=j, flag=1;
990 if (strcmp(command,"MAX_OBJECTS")==0)
991 MAX_OBJECTS=j, flag=1;
992 if (strcmp(command,"MAX_ACTIONS")==0)
993 MAX_ACTIONS=j, flag=1;
994 if (strcmp(command,"MAX_ADJECTIVES")==0)
995 MAX_ADJECTIVES=j, flag=1;
996 if (strcmp(command,"MAX_DICT_ENTRIES")==0)
997 MAX_DICT_ENTRIES=j, flag=1;
998 if (strcmp(command,"DICT_WORD_SIZE")==0)
999 { DICT_WORD_SIZE=j, flag=1;
1000 DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j;
1002 if (strcmp(command,"DICT_CHAR_SIZE")==0)
1003 DICT_CHAR_SIZE=j, flag=1;
1004 if (strcmp(command,"NUM_ATTR_BYTES")==0)
1005 { NUM_ATTR_BYTES=j, flag=1;
1006 NUM_ATTR_BYTES_g=NUM_ATTR_BYTES_z=j;
1008 if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
1009 ZCODE_HEADER_EXT_WORDS=j, flag=1;
1010 if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
1011 ZCODE_HEADER_FLAGS_3=j, flag=1;
1012 if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
1013 GLULX_OBJECT_EXT_BYTES=j, flag=1;
1014 if (strcmp(command,"MAX_STATIC_DATA")==0)
1015 MAX_STATIC_DATA=j, flag=1;
1016 if (strcmp(command,"MAX_OLDEPTH")==0)
1018 if (strcmp(command,"MAX_ROUTINES")==0)
1020 if (strcmp(command,"MAX_GCONSTANTS")==0)
1022 if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
1023 { MAX_PROP_TABLE_SIZE=j, flag=1;
1024 MAX_PROP_TABLE_SIZE_g=MAX_PROP_TABLE_SIZE_z=j;
1026 if (strcmp(command,"MAX_FORWARD_REFS")==0)
1028 if (strcmp(command,"STACK_SIZE")==0)
1030 if (strcmp(command,"STACK_LONG_SLOTS")==0)
1032 if (strcmp(command,"STACK_SHORT_LENGTH")==0)
1034 if (strcmp(command,"MAX_ABBREVS")==0)
1035 MAX_ABBREVS=j, flag=1;
1036 if (strcmp(command,"MAX_ARRAYS")==0)
1037 MAX_ARRAYS=j, flag=1;
1038 if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
1039 MAX_EXPRESSION_NODES=j, flag=1;
1040 if (strcmp(command,"MAX_VERBS")==0)
1041 MAX_VERBS=j, flag=1;
1042 if (strcmp(command,"MAX_VERBSPACE")==0)
1043 MAX_VERBSPACE=j, flag=1;
1044 if (strcmp(command,"MAX_LABELS")==0)
1045 MAX_LABELS=j, flag=1;
1046 if (strcmp(command,"MAX_LINESPACE")==0)
1047 MAX_LINESPACE=j, flag=1;
1048 if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
1049 MAX_NUM_STATIC_STRINGS=j, flag=1;
1050 if (strcmp(command,"MAX_STATIC_STRINGS")==0)
1051 { MAX_STATIC_STRINGS=j, flag=1;
1052 if (2*MAX_QTEXT_SIZE > MAX_STATIC_STRINGS)
1053 MAX_STATIC_STRINGS = 2*MAX_QTEXT_SIZE;
1055 if (strcmp(command,"MAX_ZCODE_SIZE")==0)
1056 { MAX_ZCODE_SIZE=j, flag=1;
1057 MAX_ZCODE_SIZE_g=MAX_ZCODE_SIZE_z=j;
1059 if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
1060 MAX_LINK_DATA_SIZE=j, flag=1;
1061 if (strcmp(command,"MAX_LOW_STRINGS")==0)
1062 MAX_LOW_STRINGS=j, flag=1;
1063 if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
1064 MAX_TRANSCRIPT_SIZE=j, flag=1;
1065 if (strcmp(command,"MAX_CLASSES")==0)
1066 MAX_CLASSES=j, flag=1;
1067 if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
1068 MAX_INCLUSION_DEPTH=j, flag=1;
1069 if (strcmp(command,"MAX_SOURCE_FILES")==0)
1070 MAX_SOURCE_FILES=j, flag=1;
1071 if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
1072 MAX_INDIV_PROP_TABLE_SIZE=j, flag=1;
1073 if (strcmp(command,"INDIV_PROP_START")==0)
1074 INDIV_PROP_START=j, flag=1;
1075 if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
1076 MAX_OBJ_PROP_TABLE_SIZE=j, flag=1;
1077 if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
1078 MAX_OBJ_PROP_COUNT=j, flag=1;
1079 if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
1080 { MAX_LOCAL_VARIABLES=j, flag=1;
1081 MAX_LOCAL_VARIABLES_g=MAX_LOCAL_VARIABLES_z=j;
1083 if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
1084 { MAX_GLOBAL_VARIABLES=j, flag=1;
1085 MAX_GLOBAL_VARIABLES_g=MAX_GLOBAL_VARIABLES_z=j;
1087 if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
1088 { ALLOC_CHUNK_SIZE=j, flag=1;
1089 ALLOC_CHUNK_SIZE_g=ALLOC_CHUNK_SIZE_z=j;
1091 if (strcmp(command,"MAX_UNICODE_CHARS")==0)
1092 MAX_UNICODE_CHARS=j, flag=1;
1093 if (strcmp(command,"MAX_STACK_SIZE")==0)
1095 MAX_STACK_SIZE=j, flag=1;
1096 /* Adjust up to a 256-byte boundary. */
1097 MAX_STACK_SIZE = (MAX_STACK_SIZE + 0xFF) & (~0xFF);
1099 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
1101 MEMORY_MAP_EXTENSION=j, flag=1;
1102 /* Adjust up to a 256-byte boundary. */
1103 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
1105 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
1107 WARN_UNUSED_ROUTINES=j, flag=1;
1108 if (WARN_UNUSED_ROUTINES > 2 || WARN_UNUSED_ROUTINES < 0)
1109 WARN_UNUSED_ROUTINES = 2;
1111 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
1113 OMIT_UNUSED_ROUTINES=j, flag=1;
1114 if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
1115 OMIT_UNUSED_ROUTINES = 1;
1117 if (strcmp(command,"SERIAL")==0)
1119 if (j >= 0 && j <= 999999)
1121 sprintf(serial_code_buffer,"%06d",j);
1122 serial_code_given_in_program = TRUE;
1128 printf("No such memory setting as \"%s\"\n", command);
1130 printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n\
1131 It should be safe to omit it (putting nothing in its place).\n", command);
1135 printf("No such memory $ command as \"%s\"\n",command);
1138 extern void print_memory_usage(void)
1140 printf("Properties table used %d\n",
1141 properties_table_size);
1142 printf("Allocated a total of %ld bytes of memory\n",
1143 (long int) malloced_bytes);
1146 /* ========================================================================= */
1147 /* Data structure management routines */
1148 /* ------------------------------------------------------------------------- */
1150 extern void init_memory_vars(void)
1151 { malloced_bytes = 0;
1154 extern void memory_begin_pass(void) { }
1156 extern void memory_allocate_arrays(void) { }
1158 extern void memory_free_arrays(void) { }
1160 /* ========================================================================= */