1 /* ------------------------------------------------------------------------- */
2 /* "memory" : Memory management and ICL memory setting commands */
3 /* (For "memoryerror", see "errors.c") */
5 /* Copyright (c) Graham Nelson 1993 - 2020 */
7 /* This file is part of Inform. */
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. */
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. */
19 /* You should have received a copy of the GNU General Public License */
20 /* along with Inform. If not, see https://gnu.org/licenses/ */
22 /* ------------------------------------------------------------------------- */
26 int32 malloced_bytes=0; /* Total amount of memory allocated */
30 extern void *my_malloc(int32 size, char *whatfor)
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);
40 extern void my_realloc(void *pointer, int32 oldsize, int32 size,
44 my_free(pointer, whatfor);
47 c=halloc(size,1); malloced_bytes+=size;
48 if (c==0) memory_out_error(size, 1, whatfor);
50 printf("Increasing allocation to %ld bytes for %s was (%08lx) \
52 (long int) size,whatfor,(long int) (*(int **)pointer),
54 memcpy(c, *(int **)pointer, MIN(oldsize, size));
55 hfree(*(int **)pointer);
59 extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
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);
70 extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany,
71 int32 howmany, char *whatfor)
73 if (size*howmany==0) {
74 my_free(pointer, whatfor);
77 c=(void _huge *)halloc(size*howmany,1); malloced_bytes+=size*howmany;
78 if (c==0) memory_out_error(size, howmany, whatfor);
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);
92 extern void *my_malloc(int32 size, char *whatfor)
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);
98 printf("Allocating %ld bytes for %s at (%08lx)\n",
99 (long int) size,whatfor,(long int) c);
103 extern void my_realloc(void *pointer, int32 oldsize, int32 size,
107 my_free(pointer, whatfor);
110 c=realloc(*(int **)pointer, (size_t) size); malloced_bytes+=size;
111 if (c==0) memory_out_error(size, 1, whatfor);
113 printf("Increasing allocation to %ld bytes for %s was (%08lx) \
115 (long int) size,whatfor,(long int) (*(int **)pointer),
117 *(int **)pointer = c;
120 extern void *my_calloc(int32 size, int32 howmany, char *whatfor)
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);
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,
134 extern void my_recalloc(void *pointer, int32 size, int32 oldhowmany,
135 int32 howmany, char *whatfor)
137 if (size*howmany==0) {
138 my_free(pointer, whatfor);
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);
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;
155 extern void my_free(void *pointer, char *whatitwas)
157 if (*(int **)pointer != NULL)
159 printf("Freeing memory for %s at (%08lx)\n",
160 whatitwas, (long int) (*(int **)pointer));
162 hfree(*(int **)pointer);
164 free(*(int **)pointer);
166 *(int **)pointer = NULL;
170 /* ------------------------------------------------------------------------- */
171 /* Extensible blocks of memory, providing a kind of RAM disc as an */
172 /* alternative to the temporary files option */
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 */
181 /* ------------------------------------------------------------------------- */
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);
196 extern void initialise_memory_block(memory_block *MB)
199 for (i=0; i<72; i++) MB->chunk[i] = NULL;
200 MB->extent_of_last = 0;
204 extern void deallocate_memory_block(memory_block *MB)
207 if (MB->chunk[i] != NULL)
208 my_free(&(MB->chunk[i]), chunk_name(MB, i));
210 MB->extent_of_last = 0;
213 extern int read_byte_from_memory_block(memory_block *MB, int32 index)
215 p = MB->chunk[index/ALLOC_CHUNK_SIZE];
217 { compiler_error_named("memory: read from unwritten byte in",
218 chunk_name(MB, index/ALLOC_CHUNK_SIZE));
221 return p[index % ALLOC_CHUNK_SIZE];
224 extern void write_byte_to_memory_block(memory_block *MB, int32 index, int value)
225 { uchar *p; int ch = index/ALLOC_CHUNK_SIZE;
227 { compiler_error_named("memory: negative index to", chunk_name(MB, 0));
230 if (ch >= 72) memoryerror("ALLOC_CHUNK_SIZE", ALLOC_CHUNK_SIZE);
232 if (MB->chunk[ch] == NULL)
234 MB->chunk[ch] = my_malloc(ALLOC_CHUNK_SIZE, chunk_name(MB, ch));
236 for (i=0; i<ALLOC_CHUNK_SIZE; i++) p[i] = 255;
240 p[index % ALLOC_CHUNK_SIZE] = value;
243 /* ------------------------------------------------------------------------- */
244 /* Where the memory settings are declared as variables */
245 /* ------------------------------------------------------------------------- */
249 int SYMBOLS_CHUNK_SIZE;
255 int MAX_DICT_ENTRIES;
257 int MAX_PROP_TABLE_SIZE;
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;
304 /* ------------------------------------------------------------------------- */
305 /* Memory control from the command line */
306 /* ------------------------------------------------------------------------- */
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);
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);
327 printf("| %25s = %-7d |\n","ZCODE_HEADER_EXT_WORDS",ZCODE_HEADER_EXT_WORDS);
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);
337 printf("| %25s = %-7d |\n","MAX_LOCAL_VARIABLES",MAX_LOCAL_VARIABLES);
338 printf("| %25s = %-7d |\n","MAX_LOW_STRINGS",MAX_LOW_STRINGS);
340 printf("| %25s = %-7d |\n","MEMORY_MAP_EXTENSION",
341 MEMORY_MAP_EXTENSION);
343 printf("| %25s = %-7d |\n","MAX_NUM_STATIC_STRINGS",
344 MAX_NUM_STATIC_STRINGS);
345 printf("| %25s = %-7d |\n","MAX_OBJECTS",MAX_OBJECTS);
347 printf("| %25s = %-7d |\n","GLULX_OBJECT_EXT_BYTES",
348 GLULX_OBJECT_EXT_BYTES);
350 printf("| %25s = %-7d |\n","MAX_OBJ_PROP_COUNT",
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);
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);
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");
380 extern void set_memory_sizes(int size_flag)
382 if (size_flag == HUGE_SIZE)
384 MAX_QTEXT_SIZE = 4000;
387 SYMBOLS_CHUNK_SIZE = 5000;
394 MAX_DICT_ENTRIES = 2000;
395 MAX_STATIC_DATA = 10000;
397 MAX_PROP_TABLE_SIZE_z = 30000;
398 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;
452 MAX_EXPRESSION_NODES = 100;
454 MAX_VERBSPACE = 4096;
455 MAX_LINESPACE = 10000;
458 MAX_STATIC_STRINGS = 8000;
459 MAX_ZCODE_SIZE_z = 20000;
460 MAX_ZCODE_SIZE_g = 40000;
461 MAX_LINK_DATA_SIZE = 2000;
463 MAX_LOW_STRINGS = 2048;
465 MAX_TRANSCRIPT_SIZE = 200000;
466 MAX_NUM_STATIC_STRINGS = 20000;
470 MAX_OBJ_PROP_COUNT = 64;
471 MAX_OBJ_PROP_TABLE_SIZE = 2048;
473 MAX_INDIV_PROP_TABLE_SIZE = 10000;
476 MAX_GLOBAL_VARIABLES_z = 240;
477 MAX_GLOBAL_VARIABLES_g = 512;
479 ALLOC_CHUNK_SIZE_z = 8192;
480 ALLOC_CHUNK_SIZE_g = 16384;
482 if (size_flag == SMALL_SIZE)
484 MAX_QTEXT_SIZE = 4000;
487 SYMBOLS_CHUNK_SIZE = 2500;
494 MAX_DICT_ENTRIES = 700;
495 MAX_STATIC_DATA = 10000;
497 MAX_PROP_TABLE_SIZE_z = 8000;
498 MAX_PROP_TABLE_SIZE_g = 16000;
502 MAX_EXPRESSION_NODES = 40;
504 MAX_VERBSPACE = 2048;
505 MAX_LINESPACE = 10000;
508 MAX_STATIC_STRINGS = 8000;
509 MAX_ZCODE_SIZE_z = 10000;
510 MAX_ZCODE_SIZE_g = 20000;
511 MAX_LINK_DATA_SIZE = 1000;
513 MAX_LOW_STRINGS = 1024;
515 MAX_TRANSCRIPT_SIZE = 100000;
516 MAX_NUM_STATIC_STRINGS = 10000;
520 MAX_OBJ_PROP_COUNT = 64;
521 MAX_OBJ_PROP_TABLE_SIZE = 1024;
523 MAX_INDIV_PROP_TABLE_SIZE = 5000;
526 MAX_GLOBAL_VARIABLES_z = 240;
527 MAX_GLOBAL_VARIABLES_g = 256;
529 ALLOC_CHUNK_SIZE_z = 8192;
530 ALLOC_CHUNK_SIZE_g = 8192;
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;
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;
560 adjust_memory_sizes();
563 extern void adjust_memory_sizes()
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;
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;
587 static void explain_parameter(char *command)
589 if (strcmp(command,"MAX_QTEXT_SIZE")==0)
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.");
596 if (strcmp(command,"MAX_SYMBOLS")==0)
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");
602 if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
604 " The symbols names are stored in memory which is allocated in chunks \n\
605 of size SYMBOLS_CHUNK_SIZE.\n");
608 if (strcmp(command,"HASH_TAB_SIZE")==0)
610 " HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
614 if (strcmp(command,"MAX_OBJECTS")==0)
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");
620 if (strcmp(command,"MAX_ACTIONS")==0)
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");
626 if (strcmp(command,"MAX_ADJECTIVES")==0)
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");
633 if (strcmp(command,"MAX_DICT_ENTRIES")==0)
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");
639 if (strcmp(command,"DICT_WORD_SIZE")==0)
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");
646 if (strcmp(command,"DICT_CHAR_SIZE")==0)
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\
654 if (strcmp(command,"NUM_ATTR_BYTES")==0)
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\
662 if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
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");
670 if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
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");
676 if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
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");
684 if (strcmp(command,"MAX_STATIC_DATA")==0)
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");
691 if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
693 " MAX_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
694 properties table.\n");
697 if (strcmp(command,"MAX_ABBREVS")==0)
699 " MAX_ABBREVS is the maximum number of declared abbreviations. It is not \n\
700 allowed to exceed 64.\n");
703 if (strcmp(command,"MAX_ARRAYS")==0)
705 " MAX_ARRAYS is the maximum number of declared arrays.\n");
708 if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
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");
716 if (strcmp(command,"MAX_VERBS")==0)
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");
723 if (strcmp(command,"MAX_VERBSPACE")==0)
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");
729 if (strcmp(command,"MAX_LABELS")==0)
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.)");
738 if (strcmp(command,"MAX_LINESPACE")==0)
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");
744 if (strcmp(command,"MAX_STATIC_STRINGS")==0)
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.");
754 if (strcmp(command,"MAX_ZCODE_SIZE")==0)
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.");
763 if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
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\
771 if (strcmp(command,"MAX_LOW_STRINGS")==0)
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");
778 if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
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");
785 if (strcmp(command,"MAX_CLASSES")==0)
787 " MAX_CLASSES maximum number of object classes which can be defined. This\n\
788 is cheap to increase.\n");
791 if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
793 " MAX_INCLUSION_DEPTH is the number of nested includes permitted.\n");
796 if (strcmp(command,"MAX_SOURCE_FILES")==0)
798 " MAX_SOURCE_FILES is the number of source files that can be read in the \n\
802 if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
804 " MAX_INDIV_PROP_TABLE_SIZE is the number of bytes allocated to hold the \n\
805 table of ..variable values.\n");
808 if (strcmp(command,"INDIV_PROP_START")==0)
810 " Properties 1 to INDIV_PROP_START-1 are common properties; individual\n\
811 properties are numbered INDIV_PROP_START and up.\n");
814 if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
816 " MAX_OBJ_PROP_COUNT is the maximum number of properties a single object \n\
817 can have. (Glulx only)\n");
820 if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
822 " MAX_OBJ_PROP_TABLE_SIZE is the number of words allocated to hold a \n\
823 single object's properties. (Glulx only)\n");
826 if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
828 " MAX_LOCAL_VARIABLES is the number of local variables (including \n\
829 arguments) allowed in a procedure. (Glulx only)\n");
832 if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
834 " MAX_GLOBAL_VARIABLES is the number of global variables allowed in the \n\
835 program. (Glulx only)\n");
838 if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
841 " MAX_NUM_STATIC_STRINGS is the maximum number of compiled strings \n\
842 allowed in the program. (Glulx only)\n");
845 if (strcmp(command,"MAX_UNICODE_CHARS")==0)
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\
853 if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
856 " ALLOC_CHUNK_SIZE is a base unit of Inform's internal memory allocation \n\
857 for various structures.\n");
860 if (strcmp(command,"MAX_STACK_SIZE")==0)
863 " MAX_STACK_SIZE is the maximum size (in bytes) of the interpreter stack \n\
864 during gameplay. (Glulx only)\n");
867 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
870 " MEMORY_MAP_EXTENSION is the number of bytes (all zeroes) to map into \n\
871 memory after the game file. (Glulx only)\n");
874 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
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");
883 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
886 " OMIT_UNUSED_ROUTINES, if set to 1, will avoid compiling unused routines \n\
887 into the game file.\n");
890 if (strcmp(command,"SERIAL")==0)
893 " SERIAL, if set, will be used as the six digit serial number written into \n\
894 the header of the output file.\n");
898 printf("No such memory setting as \"%s\"\n",command);
903 /* Parse a decimal number as an int32. Return true if a valid number
904 was found; otherwise print a warning and return false.
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
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
916 This used to rely on atoi(), and we retain the atoi() behavior of
917 ignoring garbage characters after a valid decimal number.
919 static int parse_memory_setting(char *str, char *label, int32 *result)
927 while (*cx == ' ') cx++;
929 val = strtol(cx, &ex, 10);
932 printf("Bad numerical setting in $ command \"%s=%s\"\n",
940 printf("Numerical setting underflowed in $ command \"%s=%s\" (limiting to %ld)\n",
947 printf("Numerical setting overflowed in $ command \"%s=%s\" (limiting to %ld)\n",
952 *result = (int32)val;
956 extern void memory_command(char *command)
957 { int i, k, flag=0; int32 j;
959 for (k=0; command[k]!=0; k++)
960 if (islower(command[k])) command[k]=toupper(command[k]);
962 if (command[0]=='?') { explain_parameter(command+1); return; }
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]=='=')
971 if (!parse_memory_setting(command+i+1, command, &j)) {
974 if (strcmp(command,"BUFFER_LENGTH")==0)
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;
981 if (strcmp(command,"MAX_SYMBOLS")==0)
982 MAX_SYMBOLS=j, flag=1;
983 if (strcmp(command,"MAX_BANK_SIZE")==0)
985 if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
986 SYMBOLS_CHUNK_SIZE=j, flag=1;
987 if (strcmp(command,"BANK_CHUNK_SIZE")==0)
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;
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;
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)
1019 if (strcmp(command,"MAX_ROUTINES")==0)
1021 if (strcmp(command,"MAX_GCONSTANTS")==0)
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;
1027 if (strcmp(command,"MAX_FORWARD_REFS")==0)
1029 if (strcmp(command,"STACK_SIZE")==0)
1031 if (strcmp(command,"STACK_LONG_SLOTS")==0)
1033 if (strcmp(command,"STACK_SHORT_LENGTH")==0)
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;
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;
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;
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;
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;
1092 if (strcmp(command,"MAX_UNICODE_CHARS")==0)
1093 MAX_UNICODE_CHARS=j, flag=1;
1094 if (strcmp(command,"MAX_STACK_SIZE")==0)
1096 MAX_STACK_SIZE=j, flag=1;
1097 /* Adjust up to a 256-byte boundary. */
1098 MAX_STACK_SIZE = (MAX_STACK_SIZE + 0xFF) & (~0xFF);
1100 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
1102 MEMORY_MAP_EXTENSION=j, flag=1;
1103 /* Adjust up to a 256-byte boundary. */
1104 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
1106 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
1108 WARN_UNUSED_ROUTINES=j, flag=1;
1109 if (WARN_UNUSED_ROUTINES > 2 || WARN_UNUSED_ROUTINES < 0)
1110 WARN_UNUSED_ROUTINES = 2;
1112 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
1114 OMIT_UNUSED_ROUTINES=j, flag=1;
1115 if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
1116 OMIT_UNUSED_ROUTINES = 1;
1118 if (strcmp(command,"SERIAL")==0)
1120 if (j >= 0 && j <= 999999)
1122 sprintf(serial_code_buffer,"%06d",j);
1123 serial_code_given_in_program = TRUE;
1129 printf("No such memory setting as \"%s\"\n", command);
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);
1136 printf("No such memory $ command as \"%s\"\n",command);
1139 extern void print_memory_usage(void)
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);
1147 /* ========================================================================= */
1148 /* Data structure management routines */
1149 /* ------------------------------------------------------------------------- */
1151 extern void init_memory_vars(void)
1152 { malloced_bytes = 0;
1155 extern void memory_begin_pass(void) { }
1157 extern void memory_allocate_arrays(void) { }
1159 extern void memory_free_arrays(void) { }
1161 /* ========================================================================= */