1 /* ------------------------------------------------------------------------- */
2 /* "memory" : Memory management and ICL memory setting commands */
4 /* Part of Inform 6.42 */
5 /* copyright (c) Graham Nelson 1993 - 2024 */
7 /* Inform is free software: you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation, either version 3 of the License, or */
10 /* (at your option) any later version. */
12 /* Inform is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
15 /* GNU General Public License for more details. */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with Inform. If not, see https://gnu.org/licenses/ */
20 /* ------------------------------------------------------------------------- */
24 size_t malloced_bytes=0; /* Total amount of memory allocated */
26 /* Wrappers for malloc(), realloc(), etc.
28 Note that all of these functions call fatalerror_memory_out() on failure.
29 This is a fatal error and does not return. However, we check my_malloc()
30 return values anyway as a matter of good habit.
35 extern void *my_malloc(size_t size, char *whatfor)
38 printf("Allocating %ld bytes for %s\n",size,whatfor);
39 if (size==0) return(NULL);
40 c=(char _huge *)halloc(size,1);
42 if (c==0) fatalerror_memory_out(size, 1, whatfor);
46 extern void my_realloc(void *pointer, size_t oldsize, size_t size,
50 my_free(pointer, whatfor);
54 malloced_bytes+=(size-oldsize);
55 if (c==0) fatalerror_memory_out(size, 1, whatfor);
57 printf("Increasing allocation from %ld to %ld bytes for %s was (%08lx) now (%08lx)\n",
58 (long int) oldsize, (long int) size, whatfor,
59 (long int) (*(int **)pointer),
61 memcpy(c, *(int **)pointer, MIN(oldsize, size));
62 hfree(*(int **)pointer);
66 extern void *my_calloc(size_t size, size_t howmany, char *whatfor)
69 printf("Allocating %d bytes: array (%ld entries size %ld) for %s\n",
70 size*howmany,howmany,size,whatfor);
71 if ((size*howmany) == 0) return(NULL);
72 c=(void _huge *)halloc(howmany*size,1);
73 malloced_bytes+=size*howmany;
74 if (c==0) fatalerror_memory_out(size, howmany, whatfor);
78 extern void my_recalloc(void *pointer, size_t size, size_t oldhowmany,
79 int32 howmany, char *whatfor)
81 if (size*howmany==0) {
82 my_free(pointer, whatfor);
85 c=(void _huge *)halloc(size*howmany,1);
86 malloced_bytes+=size*(howmany-oldhowmany);
87 if (c==0) fatalerror_memory_out(size, howmany, whatfor);
89 printf("Increasing allocation from %ld to %ld bytes: array (%ld entries size %ld) for %s was (%08lx) now (%08lx)\n",
90 ((long int)size) * ((long int)oldhowmany),
91 ((long int)size) * ((long int)howmany),
92 (long int)howmany, (long int)size, whatfor,
93 (long int) *(int **)pointer, (long int) c);
94 memcpy(c, *(int **)pointer, MIN(size*oldhowmany, size*howmany));
95 hfree(*(int **)pointer);
101 extern void *my_malloc(size_t size, char *whatfor)
103 if (size==0) return(NULL);
105 malloced_bytes+=size;
106 if (c==0) fatalerror_memory_out(size, 1, whatfor);
108 printf("Allocating %ld bytes for %s at (%p)\n",
109 (long int) size, whatfor, c);
113 extern void my_realloc(void *pointer, size_t oldsize, size_t size,
117 my_free(pointer, whatfor);
120 c=realloc(*(int **)pointer, size);
121 malloced_bytes+=(size-oldsize);
122 if (c==0) fatalerror_memory_out(size, 1, whatfor);
124 printf("Increasing allocation from %ld to %ld bytes for %s was (%p) now (%p)\n",
125 (long int) oldsize, (long int) size, whatfor, pointer, c);
126 *(int **)pointer = c;
129 extern void *my_calloc(size_t size, size_t howmany, char *whatfor)
131 if (size*howmany==0) return(NULL);
132 c=calloc(howmany, size);
133 malloced_bytes+=size*howmany;
134 if (c==0) fatalerror_memory_out(size, howmany, whatfor);
136 printf("Allocating %ld bytes: array (%ld entries size %ld) \
138 ((long int)size) * ((long int)howmany),
139 (long int)howmany,(long int)size, whatfor, c);
143 extern void my_recalloc(void *pointer, size_t size, size_t oldhowmany,
144 size_t howmany, char *whatfor)
146 if (size*howmany==0) {
147 my_free(pointer, whatfor);
150 c=realloc(*(int **)pointer, size*howmany);
151 malloced_bytes+=size*(howmany-oldhowmany);
152 if (c==0) fatalerror_memory_out(size, howmany, whatfor);
154 printf("Increasing allocation from %ld to %ld bytes: array (%ld entries size %ld) for %s was (%p) now (%p)\n",
155 ((long int)size) * ((long int)oldhowmany),
156 ((long int)size) * ((long int)howmany),
157 (long int)howmany, (long int)size, whatfor,
159 *(int **)pointer = c;
164 extern void my_free(void *pointer, char *whatitwas)
166 if (*(int **)pointer != NULL)
168 printf("Freeing memory for %s at (%p)\n",
171 hfree(*(int **)pointer);
173 free(*(int **)pointer);
175 *(int **)pointer = NULL;
179 /* ------------------------------------------------------------------------- */
180 /* A dynamic memory array. This grows as needed (but never shrinks). */
181 /* Call ensure_memory_list_available(N) before accessing array item N-1. */
183 /* whatfor must be a static string describing the list. initalloc is */
184 /* (optionally) the number of items to allocate right away. */
186 /* You typically initialise this with extpointer referring to an array of */
187 /* structs or whatever type you need. Whenever the memory list grows, the */
188 /* external array will be updated to refer to the new data. */
190 /* Add "#define DEBUG_MEMLISTS" to allocate exactly the number of items */
191 /* needed, rather than increasing allocations exponentially. This is very */
192 /* slow but it lets us track down array overruns. */
193 /* ------------------------------------------------------------------------- */
195 void initialise_memory_list(memory_list *ML, size_t itemsize, size_t initalloc, void **extpointer, char *whatfor)
197 #ifdef DEBUG_MEMLISTS
198 initalloc = 0; /* No initial allocation */
201 ML->whatfor = whatfor;
202 ML->itemsize = itemsize;
205 ML->extpointer = extpointer;
208 ML->count = initalloc;
209 ML->data = my_calloc(ML->itemsize, ML->count, ML->whatfor);
210 if (ML->data == NULL) return;
214 *(ML->extpointer) = ML->data;
217 void deallocate_memory_list(memory_list *ML)
223 my_free(&(ML->data), ML->whatfor);
226 *(ML->extpointer) = NULL;
227 ML->extpointer = NULL;
230 /* After this is called, at least count items will be available in the list.
231 That is, you can freely access array[0] through array[count-1]. */
232 void ensure_memory_list_available(memory_list *ML, size_t count)
236 if (ML->itemsize == 0) {
237 /* whatfor is also null! */
238 compiler_error("memory: attempt to access uninitialized memory_list");
242 if (ML->count >= count) {
246 oldcount = ML->count;
247 ML->count = 2*count+8; /* Allow headroom for future growth */
249 #ifdef DEBUG_MEMLISTS
250 ML->count = count; /* No headroom */
253 if (ML->data == NULL)
254 ML->data = my_calloc(ML->itemsize, ML->count, ML->whatfor);
256 my_recalloc(&(ML->data), ML->itemsize, oldcount, ML->count, ML->whatfor);
257 if (ML->data == NULL) return;
260 *(ML->extpointer) = ML->data;
263 /* ------------------------------------------------------------------------- */
264 /* Where the memory settings are declared as variables */
265 /* ------------------------------------------------------------------------- */
269 int MAX_DYNAMIC_STRINGS;
270 int MAX_LOCAL_VARIABLES;
271 int DICT_WORD_SIZE; /* number of characters in a dict word */
272 int DICT_CHAR_SIZE; /* (glulx) 1 for one-byte chars, 4 for Unicode chars */
273 int DICT_WORD_BYTES; /* DICT_WORD_SIZE*DICT_CHAR_SIZE */
274 int ZCODE_HEADER_EXT_WORDS; /* (zcode 1.0) requested header extension size */
275 int ZCODE_HEADER_FLAGS_3; /* (zcode 1.1) value to place in Flags 3 word */
276 int ZCODE_LESS_DICT_DATA; /* (zcode) use 2 data bytes per dict word instead of 3 */
277 int ZCODE_MAX_INLINE_STRING; /* (zcode) length of string literals that can be inlined */
279 int GLULX_OBJECT_EXT_BYTES; /* (glulx) extra bytes for each object record */
280 int32 MAX_STACK_SIZE;
281 int32 MEMORY_MAP_EXTENSION;
282 int WARN_UNUSED_ROUTINES; /* 0: no, 1: yes except in system files, 2: yes always */
283 int OMIT_UNUSED_ROUTINES; /* 0: no, 1: yes */
284 int STRIP_UNREACHABLE_LABELS; /* 0: no, 1: yes (default) */
285 int OMIT_SYMBOL_TABLE; /* 0: no, 1: yes */
286 int LONG_DICT_FLAG_BUG; /* 0: no bug, 1: bug (default for historic reasons) */
287 int TRANSCRIPT_FORMAT; /* 0: classic, 1: prefixed */
289 /* The way memory sizes are set causes great nuisance for those parameters
290 which have different defaults under Z-code and Glulx. We have to get
291 the defaults right whether the user sets "-G $HUGE" or "$HUGE -G".
292 And an explicit value set by the user should override both defaults. */
293 static int DICT_WORD_SIZE_z, DICT_WORD_SIZE_g;
294 static int NUM_ATTR_BYTES_z, NUM_ATTR_BYTES_g;
295 static int MAX_DYNAMIC_STRINGS_z, MAX_DYNAMIC_STRINGS_g;
297 /* ------------------------------------------------------------------------- */
298 /* Memory control from the command line */
299 /* ------------------------------------------------------------------------- */
301 static void list_memory_sizes(void)
302 { printf("+--------------------------------------+\n");
303 printf("| %25s = %-7s |\n","Memory setting","Value");
304 printf("+--------------------------------------+\n");
305 printf("| %25s = %-7d |\n","MAX_ABBREVS",MAX_ABBREVS);
306 printf("| %25s = %-7d |\n","NUM_ATTR_BYTES",NUM_ATTR_BYTES);
307 printf("| %25s = %-7d |\n","DICT_WORD_SIZE",DICT_WORD_SIZE);
309 printf("| %25s = %-7d |\n","DICT_CHAR_SIZE",DICT_CHAR_SIZE);
310 printf("| %25s = %-7d |\n","MAX_DYNAMIC_STRINGS",MAX_DYNAMIC_STRINGS);
311 printf("| %25s = %-7d |\n","HASH_TAB_SIZE",HASH_TAB_SIZE);
313 printf("| %25s = %-7d |\n","ZCODE_HEADER_EXT_WORDS",ZCODE_HEADER_EXT_WORDS);
315 printf("| %25s = %-7d |\n","ZCODE_HEADER_FLAGS_3",ZCODE_HEADER_FLAGS_3);
317 printf("| %25s = %-7d |\n","ZCODE_LESS_DICT_DATA",ZCODE_LESS_DICT_DATA);
319 printf("| %25s = %-7d |\n","ZCODE_MAX_INLINE_STRING",ZCODE_MAX_INLINE_STRING);
320 printf("| %25s = %-7d |\n","INDIV_PROP_START", INDIV_PROP_START);
322 printf("| %25s = %-7d |\n","MEMORY_MAP_EXTENSION",
323 MEMORY_MAP_EXTENSION);
325 printf("| %25s = %-7d |\n","GLULX_OBJECT_EXT_BYTES",
326 GLULX_OBJECT_EXT_BYTES);
328 printf("| %25s = %-7ld |\n","MAX_STACK_SIZE",
329 (long int) MAX_STACK_SIZE);
330 printf("| %25s = %-7d |\n","TRANSCRIPT_FORMAT",TRANSCRIPT_FORMAT);
331 printf("| %25s = %-7d |\n","WARN_UNUSED_ROUTINES",WARN_UNUSED_ROUTINES);
332 printf("| %25s = %-7d |\n","OMIT_UNUSED_ROUTINES",OMIT_UNUSED_ROUTINES);
333 printf("| %25s = %-7d |\n","STRIP_UNREACHABLE_LABELS",STRIP_UNREACHABLE_LABELS);
334 printf("| %25s = %-7d |\n","OMIT_SYMBOL_TABLE",OMIT_SYMBOL_TABLE);
335 printf("| %25s = %-7d |\n","LONG_DICT_FLAG_BUG",LONG_DICT_FLAG_BUG);
336 printf("+--------------------------------------+\n");
339 extern void set_memory_sizes(void)
343 DICT_WORD_SIZE_z = 6;
344 DICT_WORD_SIZE_g = 9;
345 NUM_ATTR_BYTES_z = 6;
346 NUM_ATTR_BYTES_g = 7;
348 MAX_DYNAMIC_STRINGS_z = 32;
349 MAX_DYNAMIC_STRINGS_g = 100;
350 /* Backwards-compatible behavior: allow for a unicode table
351 whether we need one or not. The user can set this to zero if
352 there's no unicode table. */
353 ZCODE_HEADER_EXT_WORDS = 3;
354 ZCODE_HEADER_FLAGS_3 = 0;
355 ZCODE_LESS_DICT_DATA = 0;
356 ZCODE_MAX_INLINE_STRING = 32;
357 GLULX_OBJECT_EXT_BYTES = 0;
358 MEMORY_MAP_EXTENSION = 0;
359 /* We estimate the default Glulx stack size at 4096. That's about
360 enough for 90 nested function calls with 8 locals each -- the
361 same capacity as the Z-Spec's suggestion for Z-machine stack
362 size. Note that Inform 7 wants more stack; I7-generated code
363 sets MAX_STACK_SIZE to 65536 by default. */
364 MAX_STACK_SIZE = 4096;
365 OMIT_UNUSED_ROUTINES = 0;
366 WARN_UNUSED_ROUTINES = 0;
367 STRIP_UNREACHABLE_LABELS = 1;
368 OMIT_SYMBOL_TABLE = 0;
369 LONG_DICT_FLAG_BUG = 1;
370 TRANSCRIPT_FORMAT = 0;
372 adjust_memory_sizes();
375 extern void adjust_memory_sizes()
378 DICT_WORD_SIZE = DICT_WORD_SIZE_z;
379 NUM_ATTR_BYTES = NUM_ATTR_BYTES_z;
380 MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_z;
381 INDIV_PROP_START = 64;
384 DICT_WORD_SIZE = DICT_WORD_SIZE_g;
385 NUM_ATTR_BYTES = NUM_ATTR_BYTES_g;
386 MAX_DYNAMIC_STRINGS = MAX_DYNAMIC_STRINGS_g;
387 INDIV_PROP_START = 256;
391 static void explain_parameter(char *command)
393 if (strcmp(command,"HASH_TAB_SIZE")==0)
395 " HASH_TAB_SIZE is the size of the hash tables used for the heaviest \n\
399 if (strcmp(command,"DICT_WORD_SIZE")==0)
401 " DICT_WORD_SIZE is the number of characters in a dictionary word. In \n\
402 Z-code this is always 6 (only 4 are used in v3 games). In Glulx it \n\
403 can be any number.\n");
406 if (strcmp(command,"DICT_CHAR_SIZE")==0)
408 " DICT_CHAR_SIZE is the byte size of one character in the dictionary. \n\
409 (This is only meaningful in Glulx, since Z-code has compressed dictionary \n\
410 words.) It can be either 1 (the default) or 4 (to enable full Unicode \n\
414 if (strcmp(command,"NUM_ATTR_BYTES")==0)
416 " NUM_ATTR_BYTES is the space used to store attribute flags. Each byte \n\
417 stores eight attributes. In Z-code this is always 6 (only 4 are used in \n\
418 v3 games). In Glulx it can be any number which is a multiple of four, \n\
422 if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
424 " ZCODE_HEADER_EXT_WORDS is the number of words in the Z-code header \n\
425 extension table (Z-Spec 1.0). The -W switch also sets this. It defaults \n\
426 to 3, but can be set higher. (It can be set lower if no Unicode \n\
427 translation table is created.)\n");
430 if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
432 " ZCODE_HEADER_FLAGS_3 is the value to store in the Flags 3 word of the \n\
433 header extension table (Z-Spec 1.1).\n");
436 if (strcmp(command,"ZCODE_LESS_DICT_DATA")==0)
438 " ZCODE_LESS_DICT_DATA, if set, provides each dict word with two data bytes\n\
439 rather than three. (Z-code only.)\n");
442 if (strcmp(command,"ZCODE_MAX_INLINE_STRING")==0)
444 " ZCODE_MAX_INLINE_STRING is the length beyond which string literals cannot\n\
445 be inlined in assembly opcodes. (Z-code only.)\n");
448 if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
450 " GLULX_OBJECT_EXT_BYTES is an amount of additional space to add to each \n\
451 object record. It is initialized to zero bytes, and the game is free to \n\
452 use it as desired. (This is only meaningful in Glulx, since Z-code \n\
453 specifies the object structure.)\n");
456 if (strcmp(command,"MAX_ABBREVS")==0)
458 " MAX_ABBREVS is the maximum number of declared abbreviations. It is not \n\
459 allowed to exceed 96 in Z-code. (This is not meaningful in Glulx, where \n\
460 there is no limit on abbreviations.)\n");
463 if (strcmp(command,"MAX_DYNAMIC_STRINGS")==0)
465 " MAX_DYNAMIC_STRINGS is the maximum number of string substitution variables\n\
466 (\"@00\" or \"@(0)\"). It is not allowed to exceed 96 in Z-code.\n");
469 if (strcmp(command,"INDIV_PROP_START")==0)
471 " Properties 1 to INDIV_PROP_START-1 are common properties; individual\n\
472 properties are numbered INDIV_PROP_START and up.\n");
475 if (strcmp(command,"MAX_STACK_SIZE")==0)
478 " MAX_STACK_SIZE is the maximum size (in bytes) of the interpreter stack \n\
479 during gameplay. (Glulx only)\n");
482 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
485 " MEMORY_MAP_EXTENSION is the number of bytes (all zeroes) to map into \n\
486 memory after the game file. (Glulx only)\n");
489 if (strcmp(command,"TRANSCRIPT_FORMAT")==0)
492 " TRANSCRIPT_FORMAT, if set to 1, adjusts the gametext.txt transcript for \n\
493 easier machine processing; each line will be prefixed by its context.\n");
496 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
499 " WARN_UNUSED_ROUTINES, if set to 2, will display a warning for each \n\
500 routine in the game file which is never called. (This includes \n\
501 routines called only from uncalled routines, etc.) If set to 1, will warn \n\
502 only about functions in game code, not in the system library.\n");
505 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
508 " OMIT_UNUSED_ROUTINES, if set to 1, will avoid compiling unused routines \n\
509 into the game file.\n");
512 if (strcmp(command,"STRIP_UNREACHABLE_LABELS")==0)
515 " STRIP_UNREACHABLE_LABELS, if set to 1, will skip labels in unreachable \n\
516 statements. Jumping to a skipped label is an error. If 0, all labels \n\
517 will be compiled, at the cost of less optimized code. The default is 1.\n");
520 if (strcmp(command,"OMIT_SYMBOL_TABLE")==0)
523 " OMIT_SYMBOL_TABLE, if set to 1, will skip compiling debug symbol names \n\
524 into the game file.\n");
527 if (strcmp(command,"LONG_DICT_FLAG_BUG")==0)
530 " LONG_DICT_FLAG_BUG, if set to 0, will fix the old bug which ignores \n\
531 the '//p' flag in long dictionary words. If 1, the buggy behavior is \n\
535 if (strcmp(command,"SERIAL")==0)
538 " SERIAL, if set, will be used as the six digit serial number written into \n\
539 the header of the output file.\n");
543 printf("No such memory setting as \"%s\"\n",command);
548 /* Parse a decimal number as an int32. Return true if a valid number
549 was found; otherwise print a warning and return false.
551 Anything over nine digits is considered an overflow; we report a
552 warning but return +/- 999999999 (and true). This is not entirely
553 clever about leading zeroes ("0000000001" is treated as an
554 overflow) but this is better than trying to detect genuine
557 (Some Glulx settings might conceivably want to go up to $7FFFFFFF,
558 which is a ten-digit number, but we're not going to allow that
561 This used to rely on atoi(), and we retain the atoi() behavior of
562 ignoring garbage characters after a valid decimal number.
564 static int parse_memory_setting(char *str, char *label, int32 *result)
572 while (*cx == ' ') cx++;
574 val = strtol(cx, &ex, 10);
577 printf("Bad numerical setting in $ command \"%s=%s\"\n",
585 printf("Numerical setting underflowed in $ command \"%s=%s\" (limiting to %ld)\n",
592 printf("Numerical setting overflowed in $ command \"%s=%s\" (limiting to %ld)\n",
597 *result = (int32)val;
601 static void add_predefined_symbol(char *command)
608 for (ix=0; command[ix]; ix++) {
609 if (command[ix] == '=') {
610 valpos = command+(ix+1);
616 for (ix=0; command[ix]; ix++) {
617 if ((ix == 0 && isdigit(command[ix]))
618 || !(isalnum(command[ix]) || command[ix] == '_')) {
619 printf("Attempt to define invalid symbol: %s\n", command);
625 if (!parse_memory_setting(valpos, command, &value)) {
630 add_config_symbol_definition(command, value);
633 static void set_trace_option(char *command)
638 /* Parse options of the form STRING or STRING=NUM. (The $! has already been eaten.) If the string is null or empty, show help. */
640 if (!command || *command == '\0') {
641 printf("The full list of trace options:\n\n");
642 printf(" ACTIONS: show actions defined\n");
643 printf(" ASM: trace assembly (same as -a)\n");
644 printf(" ASM=2: also show hex dumps\n");
645 printf(" ASM=3: also show branch optimization info\n");
646 printf(" ASM=4: more verbose branch info\n");
647 printf(" BPATCH: show backpatch results\n");
648 printf(" BPATCH=2: also show markers added\n");
649 printf(" DICT: display the dictionary table\n");
650 printf(" DICT=2: also the byte encoding of entries\n");
651 printf(" EXPR: show expression trees\n");
652 printf(" EXPR=2: more verbose\n");
653 printf(" EXPR=3: even more verbose\n");
654 printf(" FILES: show files opened\n");
655 printf(" FINDABBREVS: show selection decisions during abbreviation optimization\n (only meaningful with -u)\n");
656 printf(" FINDABBREVS=2: also show three-letter-block decisions\n");
657 printf(" FREQ: show how efficient abbreviations were (same as -f)\n (only meaningful with -e)\n");
658 printf(" MAP: print memory map of the virtual machine (same as -z)\n");
659 printf(" MAP=2: also show percentage of VM that each segment occupies\n");
660 printf(" MAP=3: also show number of bytes that each segment occupies\n");
661 printf(" MEM: show internal memory allocations\n");
662 printf(" OBJECTS: display the object table\n");
663 printf(" PROPS: show attributes and properties defined\n");
664 printf(" RUNTIME: show game function calls at runtime (same as -g)\n");
665 printf(" RUNTIME=2: also show library calls (not supported in Glulx)\n");
666 printf(" RUNTIME=3: also show veneer calls (not supported in Glulx)\n");
667 printf(" STATS: give compilation statistics (same as -s)\n");
668 printf(" SYMBOLS: display the symbol table\n");
669 printf(" SYMBOLS=2: also show compiler-defined symbols\n");
670 printf(" SYMDEF: show when symbols are noticed and defined\n");
671 printf(" TOKENS: show token lexing\n");
672 printf(" TOKENS=2: also show token types\n");
673 printf(" TOKENS=3: also show lexical context\n");
674 printf(" VERBS: display the verb grammar table\n");
678 for (cx=command; *cx && *cx != '='; cx++) {
679 if (!(*cx >= 'A' && *cx <= 'Z')) {
680 printf("Invalid $! trace command \"%s\"\n", command);
688 value = strtol(cx+1, &ex, 10);
690 if (ex == cx+1 || *ex != '\0' || value < 0) {
691 printf("Bad numerical setting in $! trace command \"%s\"\n", command);
698 /* We accept some reasonable synonyms, including plausible singular/plural confusion. */
700 if (strcmp(command, "ASSEMBLY")==0 || strcmp(command, "ASM")==0) {
701 asm_trace_setting = value;
703 else if (strcmp(command, "ACTION")==0 || strcmp(command, "ACTIONS")==0) {
704 printactions_switch = value;
706 else if (strcmp(command, "BPATCH")==0 || strcmp(command, "BACKPATCH")==0) {
707 bpatch_trace_setting = value;
709 else if (strcmp(command, "DICTIONARY")==0 || strcmp(command, "DICT")==0) {
710 list_dict_setting = value;
712 else if (strcmp(command, "EXPR")==0 || strcmp(command, "EXPRESSION")==0 || strcmp(command, "EXPRESSIONS")==0) {
713 expr_trace_setting = value;
715 else if (strcmp(command, "FILE")==0 || strcmp(command, "FILES")==0) {
716 files_trace_setting = value;
718 else if (strcmp(command, "FINDABBREV")==0 || strcmp(command, "FINDABBREVS")==0) {
719 optabbrevs_trace_setting = value;
721 else if (strcmp(command, "FREQUENCY")==0 || strcmp(command, "FREQUENCIES")==0 || strcmp(command, "FREQ")==0) {
722 frequencies_setting = value;
724 else if (strcmp(command, "MAP")==0) {
725 memory_map_setting = value;
727 else if (strcmp(command, "MEM")==0 || strcmp(command, "MEMORY")==0) {
728 memout_switch = value;
730 else if (strcmp(command, "OBJECTS")==0 || strcmp(command, "OBJECT")==0 || strcmp(command, "OBJS")==0 || strcmp(command, "OBJ")==0) {
731 list_objects_setting = value;
733 else if (strcmp(command, "PROP")==0 || strcmp(command, "PROPERTY")==0 || strcmp(command, "PROPS")==0 || strcmp(command, "PROPERTIES")==0) {
734 printprops_switch = value;
736 else if (strcmp(command, "RUNTIME")==0) {
737 trace_fns_setting = value;
739 else if (strcmp(command, "STATISTICS")==0 || strcmp(command, "STATS")==0 || strcmp(command, "STAT")==0) {
740 statistics_switch = value;
742 else if (strcmp(command, "SYMBOLS")==0 || strcmp(command, "SYMBOL")==0) {
743 list_symbols_setting = value;
745 else if (strcmp(command, "SYMDEF")==0 || strcmp(command, "SYMBOLDEF")==0) {
746 symdef_trace_setting = value;
748 else if (strcmp(command, "TOKEN")==0 || strcmp(command, "TOKENS")==0) {
749 tokens_trace_setting = value;
751 else if (strcmp(command, "VERBS")==0 || strcmp(command, "VERB")==0) {
752 list_verbs_setting = value;
755 printf("Unrecognized $! trace command \"%s\"\n", command);
759 /* Handle a dollar-sign command option: $LIST, $FOO=VAL, and so on.
760 The option may come from the command line, an ICL file, or a header
763 (Unix-style command-line options are converted to dollar-sign format
764 before being sent here.)
766 The name of this function is outdated. Many of these settings are not
767 really about memory allocation.
769 extern void memory_command(char *command)
770 { int i, k, flag=0; int32 j;
772 for (k=0; command[k]!=0; k++)
773 if (islower(command[k])) command[k]=toupper(command[k]);
775 if (command[0]=='?') { explain_parameter(command+1); return; }
776 if (command[0]=='#') { add_predefined_symbol(command+1); return; }
777 if (command[0]=='!') { set_trace_option(command+1); return; }
779 if (strcmp(command, "HUGE")==0
780 || strcmp(command, "LARGE")==0
781 || strcmp(command, "SMALL")==0) {
782 if (!nowarnings_switch)
783 printf("The Inform 6 memory size commands (\"SMALL, LARGE, HUGE\") are no longer needed and has been withdrawn.\n");
787 if (strcmp(command, "LIST")==0) { list_memory_sizes(); return; }
789 for (i=0; command[i]!=0; i++)
790 { if (command[i]=='=')
792 if (!parse_memory_setting(command+i+1, command, &j)) {
795 if (strcmp(command,"BUFFER_LENGTH")==0)
797 if (strcmp(command,"MAX_QTEXT_SIZE")==0)
799 if (strcmp(command,"MAX_SYMBOLS")==0)
801 if (strcmp(command,"MAX_BANK_SIZE")==0)
803 if (strcmp(command,"SYMBOLS_CHUNK_SIZE")==0)
805 if (strcmp(command,"BANK_CHUNK_SIZE")==0)
807 if (strcmp(command,"HASH_TAB_SIZE")==0)
808 HASH_TAB_SIZE=j, flag=1;
809 if (strcmp(command,"MAX_OBJECTS")==0)
811 if (strcmp(command,"MAX_ACTIONS")==0)
813 if (strcmp(command,"MAX_ADJECTIVES")==0)
815 if (strcmp(command,"MAX_DICT_ENTRIES")==0)
817 if (strcmp(command,"DICT_WORD_SIZE")==0)
818 { DICT_WORD_SIZE=j, flag=1;
819 DICT_WORD_SIZE_g=DICT_WORD_SIZE_z=j;
821 if (strcmp(command,"DICT_CHAR_SIZE")==0)
822 DICT_CHAR_SIZE=j, flag=1;
823 if (strcmp(command,"NUM_ATTR_BYTES")==0)
824 { NUM_ATTR_BYTES=j, flag=1;
825 NUM_ATTR_BYTES_g=NUM_ATTR_BYTES_z=j;
827 if (strcmp(command,"ZCODE_HEADER_EXT_WORDS")==0)
828 ZCODE_HEADER_EXT_WORDS=j, flag=1;
829 if (strcmp(command,"ZCODE_HEADER_FLAGS_3")==0)
830 ZCODE_HEADER_FLAGS_3=j, flag=1;
831 if (strcmp(command,"ZCODE_LESS_DICT_DATA")==0)
832 ZCODE_LESS_DICT_DATA=j, flag=1;
833 if (strcmp(command,"ZCODE_MAX_INLINE_STRING")==0)
834 ZCODE_MAX_INLINE_STRING=j, flag=1;
835 if (strcmp(command,"GLULX_OBJECT_EXT_BYTES")==0)
836 GLULX_OBJECT_EXT_BYTES=j, flag=1;
837 if (strcmp(command,"MAX_STATIC_DATA")==0)
839 if (strcmp(command,"MAX_OLDEPTH")==0)
841 if (strcmp(command,"MAX_ROUTINES")==0)
843 if (strcmp(command,"MAX_GCONSTANTS")==0)
845 if (strcmp(command,"MAX_PROP_TABLE_SIZE")==0)
847 if (strcmp(command,"MAX_FORWARD_REFS")==0)
849 if (strcmp(command,"STACK_SIZE")==0)
851 if (strcmp(command,"STACK_LONG_SLOTS")==0)
853 if (strcmp(command,"STACK_SHORT_LENGTH")==0)
855 if (strcmp(command,"MAX_ABBREVS")==0)
856 MAX_ABBREVS=j, flag=1;
857 if (strcmp(command,"MAX_DYNAMIC_STRINGS")==0)
858 { MAX_DYNAMIC_STRINGS=j, flag=1;
859 MAX_DYNAMIC_STRINGS_g=MAX_DYNAMIC_STRINGS_z=j;
861 if (strcmp(command,"MAX_ARRAYS")==0)
863 if (strcmp(command,"MAX_EXPRESSION_NODES")==0)
865 if (strcmp(command,"MAX_VERBS")==0)
867 if (strcmp(command,"MAX_VERBSPACE")==0)
869 if (strcmp(command,"MAX_LABELS")==0)
871 if (strcmp(command,"MAX_LINESPACE")==0)
873 if (strcmp(command,"MAX_NUM_STATIC_STRINGS")==0)
875 if (strcmp(command,"MAX_STATIC_STRINGS")==0)
877 if (strcmp(command,"MAX_ZCODE_SIZE")==0)
879 if (strcmp(command,"MAX_LINK_DATA_SIZE")==0)
881 if (strcmp(command,"MAX_LOW_STRINGS")==0)
883 if (strcmp(command,"MAX_TRANSCRIPT_SIZE")==0)
885 if (strcmp(command,"MAX_CLASSES")==0)
887 if (strcmp(command,"MAX_INCLUSION_DEPTH")==0)
889 if (strcmp(command,"MAX_SOURCE_FILES")==0)
891 if (strcmp(command,"MAX_INDIV_PROP_TABLE_SIZE")==0)
893 if (strcmp(command,"INDIV_PROP_START")==0)
894 INDIV_PROP_START=j, flag=1;
895 if (strcmp(command,"MAX_OBJ_PROP_TABLE_SIZE")==0)
897 if (strcmp(command,"MAX_OBJ_PROP_COUNT")==0)
899 if (strcmp(command,"MAX_LOCAL_VARIABLES")==0)
901 if (strcmp(command,"MAX_GLOBAL_VARIABLES")==0)
903 if (strcmp(command,"ALLOC_CHUNK_SIZE")==0)
905 if (strcmp(command,"MAX_UNICODE_CHARS")==0)
907 if (strcmp(command,"MAX_STACK_SIZE")==0)
909 MAX_STACK_SIZE=j, flag=1;
910 /* Adjust up to a 256-byte boundary. */
911 MAX_STACK_SIZE = (MAX_STACK_SIZE + 0xFF) & (~0xFF);
913 if (strcmp(command,"MEMORY_MAP_EXTENSION")==0)
915 MEMORY_MAP_EXTENSION=j, flag=1;
916 /* Adjust up to a 256-byte boundary. */
917 MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF);
919 if (strcmp(command,"TRANSCRIPT_FORMAT")==0)
921 TRANSCRIPT_FORMAT=j, flag=1;
922 if (TRANSCRIPT_FORMAT > 1 || TRANSCRIPT_FORMAT < 0)
923 TRANSCRIPT_FORMAT = 1;
925 if (strcmp(command,"WARN_UNUSED_ROUTINES")==0)
927 WARN_UNUSED_ROUTINES=j, flag=1;
928 if (WARN_UNUSED_ROUTINES > 2 || WARN_UNUSED_ROUTINES < 0)
929 WARN_UNUSED_ROUTINES = 2;
931 if (strcmp(command,"OMIT_UNUSED_ROUTINES")==0)
933 OMIT_UNUSED_ROUTINES=j, flag=1;
934 if (OMIT_UNUSED_ROUTINES > 1 || OMIT_UNUSED_ROUTINES < 0)
935 OMIT_UNUSED_ROUTINES = 1;
937 if (strcmp(command,"STRIP_UNREACHABLE_LABELS")==0)
939 STRIP_UNREACHABLE_LABELS=j, flag=1;
940 if (STRIP_UNREACHABLE_LABELS > 1 || STRIP_UNREACHABLE_LABELS < 0)
941 STRIP_UNREACHABLE_LABELS = 1;
943 if (strcmp(command,"OMIT_SYMBOL_TABLE")==0)
945 OMIT_SYMBOL_TABLE=j, flag=1;
946 if (OMIT_SYMBOL_TABLE > 1 || OMIT_SYMBOL_TABLE < 0)
947 OMIT_SYMBOL_TABLE = 1;
949 if (strcmp(command,"LONG_DICT_FLAG_BUG")==0)
951 LONG_DICT_FLAG_BUG=j, flag=1;
952 if (LONG_DICT_FLAG_BUG > 1 || LONG_DICT_FLAG_BUG < 0)
953 LONG_DICT_FLAG_BUG = 1;
955 if (strcmp(command,"SERIAL")==0)
957 if (j >= 0 && j <= 999999)
959 sprintf(serial_code_buffer,"%06d",j);
960 serial_code_given_in_program = TRUE;
966 printf("No such memory setting as \"%s\"\n", command);
967 if (flag==2 && !nowarnings_switch)
968 printf("The Inform 5 memory setting \"%s\" has been withdrawn.\n", command);
969 if (flag==3 && !nowarnings_switch)
970 printf("The Inform 6 memory setting \"%s\" is no longer needed and has been withdrawn.\n", command);
974 printf("No such memory $ command as \"%s\"\n",command);
977 extern void print_memory_usage(void)
979 printf("Properties table used %d\n",
980 properties_table_size);
981 printf("Allocated a total of %ld bytes of memory\n",
982 (long int) malloced_bytes);
985 /* ========================================================================= */
986 /* Data structure management routines */
987 /* ------------------------------------------------------------------------- */
989 extern void init_memory_vars(void)
990 { malloced_bytes = 0;
993 extern void memory_begin_pass(void) { }
995 extern void memory_allocate_arrays(void) { }
997 extern void memory_free_arrays(void) { }
999 /* ========================================================================= */