From d8d68d0bd4c45af6f0dc69b4fc33d37d961aca85 Mon Sep 17 00:00:00 2001 From: Jason Self Date: Mon, 17 May 2021 18:15:42 -0700 Subject: [PATCH] Update to commit e33eef4f8fab800eaf4a32b2d159cde6c4bbb38e Dated May 15 2021. These changes are similiarly relicensed to GPL per Section 4(c)(ii) of the Artistic License 2.0. --- src/arrays.c | 3 - src/asm.c | 10 +- src/bpatch.c | 1 + src/directs.c | 22 +++-- src/errors.c | 47 +++++++++- src/expressc.c | 12 ++- src/expressp.c | 9 +- src/files.c | 53 +++++++++-- src/header.h | 25 ++++- src/inform.c | 51 +++++++--- src/linker.c | 2 +- src/memory.c | 59 ++++++++++++ src/objects.c | 7 +- src/states.c | 27 ++++-- src/symbols.c | 88 ++++++++++++++--- src/tables.c | 2 +- src/text.c | 250 ++++++++++++++++++++++++++++++++++++++----------- src/verbs.c | 15 ++- 18 files changed, 548 insertions(+), 135 deletions(-) diff --git a/src/arrays.c b/src/arrays.c index 4c8f56f..9c001cc 100644 --- a/src/arrays.c +++ b/src/arrays.c @@ -294,7 +294,6 @@ extern void make_global(int array_flag, int name_only) assembly_operand AO; int extraspace; - int orig_area_size; int32 global_symbol; const char *global_name; @@ -535,12 +534,10 @@ extern void make_global(int array_flag, int name_only) extraspace += WORDSIZE; if (!is_static) { - orig_area_size = dynamic_array_area_size; array_base = dynamic_array_area_size; dynamic_array_area_size += extraspace; } else { - orig_area_size = static_array_area_size; array_base = static_array_area_size; static_array_area_size += extraspace; } diff --git a/src/asm.c b/src/asm.c index faace9c..6a263a3 100644 --- a/src/asm.c +++ b/src/asm.c @@ -867,7 +867,7 @@ extern void assemblez_instruction(assembly_instruction *AI) if (operand_rules==TEXT) { int32 i; - uchar *tmp = translate_text(zcode_holding_area + zcode_ha_size, zcode_holding_area+MAX_ZCODE_SIZE, AI->text); + uchar *tmp = translate_text(zcode_holding_area + zcode_ha_size, zcode_holding_area+MAX_ZCODE_SIZE, AI->text, STRCTX_GAMEOPC); if (!tmp) memoryerror("MAX_ZCODE_SIZE", MAX_ZCODE_SIZE); j = subtract_pointers(tmp, (zcode_holding_area + zcode_ha_size)); @@ -1575,7 +1575,7 @@ extern int32 assemble_routine_header(int no_locals, sprintf(fnt, "[ %s(", name); AO.marker = STRING_MV; AO.type = CONSTANT_OT; - AO.value = compile_string(fnt, FALSE, FALSE); + AO.value = compile_string(fnt, STRCTX_INFIX); assembleg_1(streamstr_gc, AO); if (!stackargs) { @@ -1583,7 +1583,7 @@ extern int32 assemble_routine_header(int no_locals, sprintf(fnt, "%s%s = ", (ix==1)?"":", ", variable_name(ix)); AO.marker = STRING_MV; AO.type = CONSTANT_OT; - AO.value = compile_string(fnt, FALSE, FALSE); + AO.value = compile_string(fnt, STRCTX_INFIX); assembleg_1(streamstr_gc, AO); AO.marker = 0; AO.type = LOCALVAR_OT; @@ -1596,7 +1596,7 @@ extern int32 assemble_routine_header(int no_locals, sprintf(fnt, "%s = ", variable_name(1)); AO.marker = STRING_MV; AO.type = CONSTANT_OT; - AO.value = compile_string(fnt, FALSE, FALSE); + AO.value = compile_string(fnt, STRCTX_INFIX); assembleg_1(streamstr_gc, AO); AO.marker = 0; AO.type = LOCALVAR_OT; @@ -1630,7 +1630,7 @@ extern int32 assemble_routine_header(int no_locals, AO.marker = STRING_MV; AO.type = CONSTANT_OT; - AO.value = compile_string(") ]^", FALSE, FALSE); + AO.value = compile_string(") ]^", STRCTX_INFIX); assembleg_1(streamstr_gc, AO); } } diff --git a/src/bpatch.c b/src/bpatch.c index b3a467e..daca6fb 100644 --- a/src/bpatch.c +++ b/src/bpatch.c @@ -320,6 +320,7 @@ static int32 backpatch_value_g(int32 value) break; case CONSTANT_T: case INDIVIDUAL_PROPERTY_T: + case PROPERTY_T: /* value is unchanged */ break; default: diff --git a/src/directs.c b/src/directs.c index 5df6b0b..1583172 100644 --- a/src/directs.c +++ b/src/directs.c @@ -34,7 +34,8 @@ brief_location routine_starts_line; /* Source code location where the current static int constant_made_yet; /* Have any constants been defined yet? */ -static int ifdef_stack[32], ifdef_sp; +#define MAX_IFDEF_STACK (32) +static int ifdef_stack[MAX_IFDEF_STACK], ifdef_sp; /* ------------------------------------------------------------------------- */ @@ -315,7 +316,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); assembly_operand AO; put_token_back(); AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) error("A definite value must be given as a Dictionary flag"); else val1 = AO.value; @@ -328,7 +329,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); assembly_operand AO; put_token_back(); AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) error("A definite value must be given as a Dictionary flag"); else val3 = AO.value; @@ -472,7 +473,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); case IFTRUE_CODE: { assembly_operand AO; AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) { error("This condition can't be determined"); flag = 0; } @@ -483,7 +484,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); case IFFALSE_CODE: { assembly_operand AO; AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) { error("This condition can't be determined"); flag = 1; } @@ -496,6 +497,11 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); if (!((token_type == SEP_TT) && (token_value == SEMICOLON_SEP))) return ebf_error_recover("semicolon after 'If...' condition", token_text); + if (ifdef_sp >= MAX_IFDEF_STACK) { + error("'If' directives nested too deeply"); + panic_mode_error_recovery(); return FALSE; + } + if (flag) { ifdef_stack[ifdef_sp++] = TRUE; return FALSE; } else @@ -621,7 +627,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); if (token_type != DQ_TT) return ebf_error_recover("literal string in double-quotes", token_text); - assign_symbol(i, compile_string(token_text, TRUE, TRUE), CONSTANT_T); + assign_symbol(i, compile_string(token_text, STRCTX_LOWSTRING), CONSTANT_T); break; /* --------------------------------------------------------------------- */ @@ -767,7 +773,7 @@ Fake_Action directives to a point after the inclusion of \"Parser\".)"); case RELEASE_CODE: { assembly_operand AO; AO = parse_expression(CONSTANT_CONTEXT); - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) error("A definite value must be given as release number"); else release_number = AO.value; @@ -1081,7 +1087,7 @@ the first constant definition"); break; } - if (module_switch && (AO.marker != 0)) + if (AO.marker != 0) error("A definite value must be given as version number"); else if (glulx_mode) diff --git a/src/errors.c b/src/errors.c index 08dd87e..195bfe9 100644 --- a/src/errors.c +++ b/src/errors.c @@ -56,6 +56,7 @@ static void print_preamble(void) if (!(ErrorReport.main_flag)) printf("\"%s\", ", p); printf("line %d: ", ErrorReport.line_number); + if (ErrorReport.orig_file) { char *op; if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files) @@ -81,12 +82,48 @@ static void print_preamble(void) } printf("%s", p); if (with_extension_flag) printf("%s", Source_Extension); - printf("(%d): ", ErrorReport.line_number); + printf("(%d)", ErrorReport.line_number); + + if (ErrorReport.orig_file) { + char *op; + if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files) + op = ErrorReport.orig_source; + else + op = InputFiles[ErrorReport.orig_file-1].filename; + printf("|%s", op); + if (ErrorReport.orig_line) { + printf("(%d", ErrorReport.orig_line); + if (ErrorReport.orig_char) { + printf(":%d", ErrorReport.orig_char); + } + printf(")"); + } + } + + printf(": "); break; case 2: /* Macintosh Programmer's Workshop error message format */ - printf("File \"%s\"; Line %d\t# ", p, ErrorReport.line_number); + printf("File \"%s\"; Line %d", p, ErrorReport.line_number); + + if (ErrorReport.orig_file) { + char *op; + if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files) + op = ErrorReport.orig_source; + else + op = InputFiles[ErrorReport.orig_file-1].filename; + printf(": (\"%s\"", op); + if (ErrorReport.orig_line) { + printf("; Line %d", ErrorReport.orig_line); + if (ErrorReport.orig_char) { + printf("; Char %d", ErrorReport.orig_char); + } + } + printf(")"); + } + + printf("\t# "); break; } } @@ -113,6 +150,12 @@ static char *location_text(brief_location report_line) if (j <= 0 || j > total_files) p = errpos.source; else p = InputFiles[j-1].filename; + if (!p && errpos.line_number == 0) { + /* Special case */ + strcpy(other_pos_buff, "compiler setup"); + return other_pos_buff; + } + if (!p) p = ""; len = 0; diff --git a/src/expressc.c b/src/expressc.c index 378582e..6651547 100644 --- a/src/expressc.c +++ b/src/expressc.c @@ -450,10 +450,12 @@ static void access_memory_z(int oc, assembly_operand AO1, assembly_operand AO2, index_ao; int x = 0, y = 0, byte_flag = FALSE, read_flag = FALSE, from_module = FALSE; + INITAO(&zero_ao); + INITAO(&size_ao); + INITAO(&type_ao); + if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV) { - INITAO(&zero_ao); - if ((oc == loadb_zc) || (oc == storeb_zc)) byte_flag=TRUE; else byte_flag = FALSE; if ((oc == loadb_zc) || (oc == loadw_zc)) read_flag=TRUE; @@ -821,10 +823,12 @@ static void access_memory_g(int oc, assembly_operand AO1, assembly_operand AO2, else read_flag = FALSE; + INITAO(&zero_ao); + INITAO(&size_ao); + INITAO(&type_ao); + if (AO1.marker == ARRAY_MV || AO1.marker == STATIC_ARRAY_MV) { - INITAO(&zero_ao); - size_ao = zero_ao; size_ao.value = -1; for (x=0; xtype = LONG_CONSTANT_OT; else o->type = CONSTANT_OT; - o->value = compile_string(t.text, FALSE, FALSE); + o->value = compile_string(t.text, STRCTX_GAME); return(TRUE); case VARIABLE_TT: if (!glulx_mode) { @@ -1464,11 +1465,15 @@ static void check_property_operator(int from_node) if ((below != -1) && (ET[below].right != -1)) { int n = ET[below].right, flag = FALSE; + /* Can we handle this dot operator as a native @get_prop (etc) + opcode? Only if we recognize the property value as a declared + common property constant. */ if ((ET[n].down == -1) && ((ET[n].value.type == LONG_CONSTANT_OT) || (ET[n].value.type == SHORT_CONSTANT_OT)) && ((ET[n].value.value > 0) && (ET[n].value.value < 64)) - && ((!module_switch) || (ET[n].value.marker == 0))) + && (!module_switch) + && (ET[n].value.marker == 0)) flag = TRUE; if (!flag) diff --git a/src/files.c b/src/files.c index 70cfc90..b027dd4 100644 --- a/src/files.c +++ b/src/files.c @@ -1303,8 +1303,38 @@ extern void output_file(void) FILE *transcript_file_handle; int transcript_open; -extern void write_to_transcript_file(char *text) -{ fputs(text, transcript_file_handle); +extern void write_to_transcript_file(char *text, int linetype) +{ + if (TRANSCRIPT_FORMAT == 1) { + char ch = '?'; + switch (linetype) { + case STRCTX_INFO: + ch = 'I'; break; + case STRCTX_GAME: + ch = 'G'; break; + case STRCTX_GAMEOPC: + ch = 'H'; break; + case STRCTX_VENEER: + ch = 'V'; break; + case STRCTX_VENEEROPC: + ch = 'W'; break; + case STRCTX_LOWSTRING: + ch = 'L'; break; + case STRCTX_ABBREV: + ch = 'A'; break; + case STRCTX_DICT: + ch = 'D'; break; + case STRCTX_OBJNAME: + ch = 'O'; break; + case STRCTX_SYMBOL: + ch = 'S'; break; + case STRCTX_INFIX: + ch = 'X'; break; + } + fputc(ch, transcript_file_handle); + fputs(": ", transcript_file_handle); + } + fputs(text, transcript_file_handle); fputc('\n', transcript_file_handle); } @@ -1318,9 +1348,16 @@ extern void open_transcript_file(char *what_of) transcript_open = TRUE; - sprintf(topline_buffer, "Transcript of the text of \"%s\"\n\ -[From %s]\n", what_of, banner_line); - write_to_transcript_file(topline_buffer); + sprintf(topline_buffer, "Transcript of the text of \"%s\"", what_of); + write_to_transcript_file(topline_buffer, STRCTX_INFO); + sprintf(topline_buffer, "[From %s]", banner_line); + write_to_transcript_file(topline_buffer, STRCTX_INFO); + if (TRANSCRIPT_FORMAT == 1) { + write_to_transcript_file("[I:info, G:game text, V:veneer text, L:lowmem string, A:abbreviation, D:dict word, O:object name, S:symbol, X:infix]", STRCTX_INFO); + if (!glulx_mode) + write_to_transcript_file("[H:game text inline in opcode, W:veneer text inline in opcode]", STRCTX_INFO); + } + write_to_transcript_file("", STRCTX_INFO); } extern void abort_transcript_file(void) @@ -1334,9 +1371,11 @@ extern void close_transcript_file(void) char sn_buffer[7]; write_serial_number(sn_buffer); - sprintf(botline_buffer, "\n[End of transcript: release %d.%s]\n", + sprintf(botline_buffer, "[End of transcript: release %d, serial %s]", release_number, sn_buffer); - write_to_transcript_file(botline_buffer); + write_to_transcript_file("", STRCTX_INFO); + write_to_transcript_file(botline_buffer, STRCTX_INFO); + write_to_transcript_file("", STRCTX_INFO); if (ferror(transcript_file_handle)) fatalerror("I/O failure: couldn't write to transcript file"); diff --git a/src/header.h b/src/header.h index 82d0644..8b05f26 100644 --- a/src/header.h +++ b/src/header.h @@ -1945,6 +1945,23 @@ typedef struct operator_s how far back from the label to go to find the opmode byte to modify. */ +/* ------------------------------------------------------------------------- */ +/* "String contexts"; the purpose for a given string. This info gets */ +/* written to the transcript file (gametext.txt). */ +/* ------------------------------------------------------------------------- */ + +#define STRCTX_INFO 0 /* comment; not stored in game file */ +#define STRCTX_GAME 1 /* strings area */ +#define STRCTX_GAMEOPC 2 /* inline text in opcode (Z-code only) */ +#define STRCTX_VENEER 3 /* strings area, from veneer code */ +#define STRCTX_VENEEROPC 4 /* inline text, veneer code (Z-code only) */ +#define STRCTX_LOWSTRING 5 /* lowmem (Z-code); also dynamic-str literals */ +#define STRCTX_ABBREV 6 /* abbreviation */ +#define STRCTX_DICT 7 /* dictionary word */ +#define STRCTX_OBJNAME 8 /* object "hardware name" */ +#define STRCTX_SYMBOL 9 /* prop/attr/etc names */ +#define STRCTX_INFIX 10 /* text printed in asterisk traces */ + /* ========================================================================= */ /* Initialisation extern definitions */ /* */ @@ -2357,7 +2374,7 @@ extern void check_temp_files(void); extern void remove_temp_files(void); extern void open_transcript_file(char *what_of); -extern void write_to_transcript_file(char *text); +extern void write_to_transcript_file(char *text, int linetype); extern void close_transcript_file(void); extern void abort_transcript_file(void); @@ -2551,6 +2568,7 @@ extern int DICT_WORD_SIZE, DICT_CHAR_SIZE, DICT_WORD_BYTES; extern int ZCODE_HEADER_EXT_WORDS, ZCODE_HEADER_FLAGS_3; extern int NUM_ATTR_BYTES, GLULX_OBJECT_EXT_BYTES; extern int WARN_UNUSED_ROUTINES, OMIT_UNUSED_ROUTINES; +extern int TRANSCRIPT_FORMAT; /* These macros define offsets that depend on the value of NUM_ATTR_BYTES. (Meaningful only for Glulx.) */ @@ -2649,6 +2667,7 @@ extern void list_symbols(int level); extern void assign_marked_symbol(int index, int marker, int32 value, int type); extern void assign_symbol(int index, int32 value, int type); extern void issue_unused_warnings(void); +extern void add_config_symbol_definition(char *symbol, int32 value); extern void add_symbol_replacement_mapping(int original, int renamed); extern int find_symbol_replacement(int *value); extern void df_note_function_start(char *name, uint32 address, @@ -2787,8 +2806,8 @@ extern void compress_game_text(void); /* end of the Glulx string compression stuff */ extern void ao_free_arrays(void); -extern int32 compile_string(char *b, int in_low_memory, int is_abbrev); -extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text); +extern int32 compile_string(char *b, int strctx); +extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text, int strctx); extern void optimise_abbreviations(void); extern void make_abbreviation(char *text); extern void show_dictionary(void); diff --git a/src/inform.c b/src/inform.c index 9b30ad3..a72d81e 100644 --- a/src/inform.c +++ b/src/inform.c @@ -195,6 +195,12 @@ static void select_target(int targ) /* MAX_NUM_ATTR_BYTES can be increased in header.h without fear. */ } + if (MAX_ADJECTIVES > 255) { + MAX_ADJECTIVES = 255; + warning("MAX_ADJECTIVES cannot exceed 255; resetting to 255"); + /* Only used under Grammar__Version 1, which is obsolete. */ + } + /* Set up a few more variables that depend on the above values */ if (!targ) { @@ -1078,6 +1084,7 @@ extern void translate_temp_filename(int i) { case 1: p=Temp1_Name; break; case 2: p=Temp2_Name; break; case 3: p=Temp3_Name; break; + default: return; } if (strlen(Temporary_Path)+strlen(Temporary_File)+6 >= PATHLEN) { printf ("Temporary_Path is too long.\n"); @@ -1292,15 +1299,16 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ ++dir add this directory to Include_Path\n\ +PATH=dir change the PATH to this directory\n\ ++PATH=dir add this directory to the PATH\n\n\ - $... one of the following memory commands:\n"); + $... one of the following configuration commands:\n"); printf( -" $list list current memory allocation settings\n\ +" $list list current settings\n\ $huge make standard \"huge game\" settings %s\n\ $large make standard \"large game\" settings %s\n\ $small make standard \"small game\" settings %s\n\ $?SETTING explain briefly what SETTING is for\n\ - $SETTING=number change SETTING to given number\n\n", + $SETTING=number change SETTING to given number\n\ + $#SYMBOL=number define SYMBOL as a constant in the story\n\n", (DEFAULT_MEMORY_SIZE==HUGE_SIZE)?"(default)":"", (DEFAULT_MEMORY_SIZE==LARGE_SIZE)?"(default)":"", (DEFAULT_MEMORY_SIZE==SMALL_SIZE)?"(default)":""); @@ -1317,6 +1325,7 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ --size huge, --size large, --size small\n\ --helpopt SETTING\n\ --opt SETTING=number\n\ + --define SETTING=number\n\ --config filename (setup file)\n\n"); #ifndef PROMPT_INPUT @@ -1341,15 +1350,18 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ printf("\ f frequencies mode: show how useful abbreviations are\n\ - g traces calls to functions (except in the library)\n\ - g2 traces calls to all functions\n\ - h print this information\n"); + g traces calls to all game functions\n\ + g2 traces calls to all game and library functions\n\ + g3 traces calls to all functions (including veneer)\n\ + h print general help information\n\ + h1 print help information on filenames and path options\n\ + h2 print help information on switches (this page)\n"); printf("\ i ignore default switches set within the file\n\ j list objects as constructed\n\ - k output Infix debugging information to \"%s\" (and switch -D on)\n\ - l list every statement run through Inform\n\ + k output debugging information to \"%s\"\n\ + l list every statement run through Inform (not implemented)\n\ m say how much memory has been allocated\n\ n print numbers of properties, attributes and actions\n", Debugging_Name); @@ -1364,10 +1376,11 @@ One or more words can be supplied as \"commands\". These may be:\n\n\ printf("\ u work out most useful abbreviations (very very slowly)\n\ - v3 compile to version-3 (\"Standard\") story file\n\ - v4 compile to version-4 (\"Plus\") story file\n\ - v5 compile to version-5 (\"Advanced\") story file: the default\n\ - v6 compile to version-6 (graphical) story file\n\ + v3 compile to version-3 (\"Standard\"/\"ZIP\") story file\n\ + v4 compile to version-4 (\"Plus\"/\"EZIP\") story file\n\ + v5 compile to version-5 (\"Advanced\"/\"XZIP\") story file: the default\n\ + v6 compile to version-6 (graphical/\"YZIP\") story file\n\ + v7 compile to version-7 (expanded \"Advanced\") story file\n\ v8 compile to version-8 (expanded \"Advanced\") story file\n\ w disable warning messages\n\ x print # for every 100 lines compiled\n\ @@ -1447,6 +1460,7 @@ extern void switches(char *p, int cmode) case 'g': switch(p[i+1]) { case '1': trace_fns_setting=1; s=2; break; case '2': trace_fns_setting=2; s=2; break; + case '3': trace_fns_setting=3; s=2; break; default: trace_fns_setting=1; break; } break; @@ -1462,9 +1476,7 @@ extern void switches(char *p, int cmode) case 'k': if (cmode == 0) error("The switch '-k' can't be set with 'Switches'"); else - { debugfile_switch = state; - if (state) define_DEBUG_switch = TRUE; - } + debugfile_switch = state; break; case 'l': listing_switch = state; break; case 'm': memout_switch = state; break; @@ -1857,6 +1869,15 @@ static int execute_dashdash_command(char *p, char *p2) strcpy(cli_buff, "$?"); strcpyupper(cli_buff+2, p2, CMD_BUF_SIZE-2); } + else if (!strcmp(p, "define")) { + consumed2 = TRUE; + if (!p2) { + printf("--define must be followed by \"symbol=number\"\n"); + return consumed2; + } + strcpy(cli_buff, "$#"); + strcpyupper(cli_buff+2, p2, CMD_BUF_SIZE-2); + } else if (!strcmp(p, "path")) { consumed2 = TRUE; if (!p2 || !strchr(p2, '=')) { diff --git a/src/linker.c b/src/linker.c index d05310a..6ee0418 100644 --- a/src/linker.c +++ b/src/linker.c @@ -645,7 +645,7 @@ of the Inform 6 compiler knows about: it may not link in correctly", filename); filename, module_size/1024); if (linker_trace_level >= 1) printf("%s\n", link_banner); if (transcript_switch) - write_to_transcript_file(link_banner); + write_to_transcript_file(link_banner, STRCTX_INFO); } /* (4) Merge in the dictionary */ diff --git a/src/memory.c b/src/memory.c index 6b81727..a160788 100644 --- a/src/memory.c +++ b/src/memory.c @@ -288,6 +288,7 @@ int32 MEMORY_MAP_EXTENSION; int ALLOC_CHUNK_SIZE; int WARN_UNUSED_ROUTINES; /* 0: no, 1: yes except in system files, 2: yes always */ int OMIT_UNUSED_ROUTINES; /* 0: no, 1: yes */ +int TRANSCRIPT_FORMAT; /* 0: classic, 1: prefixed */ /* The way memory sizes are set causes great nuisance for those parameters which have different defaults under Z-code and Glulx. We have to get @@ -365,6 +366,7 @@ static void list_memory_sizes(void) (long int) MAX_STATIC_STRINGS); printf("| %25s = %-7d |\n","MAX_SYMBOLS",MAX_SYMBOLS); printf("| %25s = %-7d |\n","SYMBOLS_CHUNK_SIZE",SYMBOLS_CHUNK_SIZE); + printf("| %25s = %-7d |\n","TRANSCRIPT_FORMAT",TRANSCRIPT_FORMAT); printf("| %25s = %-7ld |\n","MAX_TRANSCRIPT_SIZE", (long int) MAX_TRANSCRIPT_SIZE); if (glulx_mode) @@ -555,6 +557,7 @@ extern void set_memory_sizes(int size_flag) MAX_STACK_SIZE = 4096; OMIT_UNUSED_ROUTINES = 0; WARN_UNUSED_ROUTINES = 0; + TRANSCRIPT_FORMAT = 0; adjust_memory_sizes(); } @@ -878,6 +881,13 @@ static void explain_parameter(char *command) memory after the game file. (Glulx only)\n"); return; } + if (strcmp(command,"TRANSCRIPT_FORMAT")==0) + { + printf( +" TRANSCRIPT_FORMAT, if set to 1, adjusts the gametext.txt transcript for \n\ + easier machine processing; each line will be prefixed by its context.\n"); + return; + } if (strcmp(command,"WARN_UNUSED_ROUTINES")==0) { printf( @@ -960,6 +970,48 @@ static int parse_memory_setting(char *str, char *label, int32 *result) return 1; } +static void add_predefined_symbol(char *command) +{ + int ix; + + int value = 0; + char *valpos = NULL; + + for (ix=0; command[ix]; ix++) { + if (command[ix] == '=') { + valpos = command+(ix+1); + command[ix] = '\0'; + break; + } + } + + for (ix=0; command[ix]; ix++) { + if ((ix == 0 && isdigit(command[ix])) + || !(isalnum(command[ix]) || command[ix] == '_')) { + printf("Attempt to define invalid symbol: %s\n", command); + return; + } + } + + if (valpos) { + if (!parse_memory_setting(valpos, command, &value)) { + return; + }; + } + + add_config_symbol_definition(command, value); +} + +/* Handle a dollar-sign command option: $LIST, $FOO=VAL, and so on. + The option may come from the command line, an ICL file, or a header + comment. + + (Unix-style command-line options are converted to dollar-sign format + before being sent here.) + + The name of this function is outdated. Many of these settings are not + really about memory allocation. +*/ extern void memory_command(char *command) { int i, k, flag=0; int32 j; @@ -967,6 +1019,7 @@ extern void memory_command(char *command) if (islower(command[k])) command[k]=toupper(command[k]); if (command[0]=='?') { explain_parameter(command+1); return; } + if (command[0]=='#') { add_predefined_symbol(command+1); return; } if (strcmp(command, "HUGE")==0) { set_memory_sizes(HUGE_SIZE); return; } if (strcmp(command, "LARGE")==0) { set_memory_sizes(LARGE_SIZE); return; } @@ -1114,6 +1167,12 @@ extern void memory_command(char *command) /* Adjust up to a 256-byte boundary. */ MEMORY_MAP_EXTENSION = (MEMORY_MAP_EXTENSION + 0xFF) & (~0xFF); } + if (strcmp(command,"TRANSCRIPT_FORMAT")==0) + { + TRANSCRIPT_FORMAT=j, flag=1; + if (TRANSCRIPT_FORMAT > 1 || TRANSCRIPT_FORMAT < 0) + TRANSCRIPT_FORMAT = 1; + } if (strcmp(command,"WARN_UNUSED_ROUTINES")==0) { WARN_UNUSED_ROUTINES=j, flag=1; diff --git a/src/objects.c b/src/objects.c index 242ec3c..b957073 100644 --- a/src/objects.c +++ b/src/objects.c @@ -809,7 +809,7 @@ static int write_property_block_z(char *shortname) { uchar *tmp; if (mark+1+510 >= MAX_PROP_TABLE_SIZE) memoryerror("MAX_PROP_TABLE_SIZE",MAX_PROP_TABLE_SIZE); - tmp = translate_text(p+mark+1,p+mark+1+510,shortname); + tmp = translate_text(p+mark+1,p+mark+1+510,shortname,STRCTX_OBJNAME); if (!tmp) error ("Short name of object exceeded 765 Z-characters"); i = subtract_pointers(tmp,(p+mark+1)); p[mark] = i/2; @@ -1002,7 +1002,7 @@ static void manufacture_object_g(void) } objectsg[no_objects].shortname = compile_string(shortname_buffer, - FALSE, FALSE); + STRCTX_OBJNAME); /* The properties table consists simply of a sequence of property blocks, one for each object in order of definition, exactly as @@ -1756,7 +1756,6 @@ extern void make_class(char * metaclass_name) { int n, duplicates_to_make = 0, class_number = no_objects+1, metaclass_flag = (metaclass_name != NULL); char duplicate_name[128]; - int class_symbol; debug_location_beginning beginning_debug_location = get_token_location_beginning(); @@ -1847,8 +1846,6 @@ inconvenience, please contact the maintainers."); full_object_g.propdata[0].marker = OBJECT_MV; } - class_symbol = token_value; - if (!metaclass_flag) { get_next_token(); if ((token_type == SEP_TT) && (token_value == OPENB_SEP)) diff --git a/src/states.c b/src/states.c index 3f0e874..b569fb2 100644 --- a/src/states.c +++ b/src/states.c @@ -308,7 +308,7 @@ static void parse_print_z(int finally_return) if (strlen(token_text) > 32) { INITAOT(&AO, LONG_CONSTANT_OT); AO.marker = STRING_MV; - AO.value = compile_string(token_text, FALSE, FALSE); + AO.value = compile_string(token_text, STRCTX_GAME); assemblez_1(print_paddr_zc, AO); if (finally_return) { get_next_token(); @@ -537,7 +537,7 @@ static void parse_print_g(int finally_return) so this always goes into the string area. */ { INITAOT(&AO, CONSTANT_OT); AO.marker = STRING_MV; - AO.value = compile_string(token_text, FALSE, FALSE); + AO.value = compile_string(token_text, STRCTX_GAME); assembleg_1(streamstr_gc, AO); if (finally_return) { get_next_token(); @@ -974,6 +974,10 @@ static void parse_statement_z(int break_label, int continue_label) get_next_token(); /* Initialisation code */ + AO.type = OMITTED_OT; + spare_debug_location1 = statement_debug_location; + AO2.type = OMITTED_OT; flag = 0; + spare_debug_location2 = statement_debug_location; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); @@ -996,7 +1000,6 @@ static void parse_statement_z(int break_label, int continue_label) assemble_label_no(ln2); return; } - AO.type = OMITTED_OT; goto ParseUpdate; } put_token_back(); @@ -1004,7 +1007,6 @@ static void parse_statement_z(int break_label, int continue_label) } get_next_token(); - AO.type = OMITTED_OT; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); spare_debug_location1 = get_token_location(); @@ -1014,7 +1016,6 @@ static void parse_statement_z(int break_label, int continue_label) get_next_token(); ParseUpdate: - AO2.type = OMITTED_OT; flag = 0; if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP))) { put_token_back(); spare_debug_location2 = get_token_location(); @@ -1609,7 +1610,9 @@ static void parse_statement_z(int break_label, int continue_label) get_next_token(); if (token_type == DQ_TT) { INITAOT(&AO4, LONG_CONSTANT_OT); - AO4.value = compile_string(token_text, TRUE, TRUE); + /* This string must be in low memory so that the + dynamic string table can refer to it. */ + AO4.value = compile_string(token_text, STRCTX_LOWSTRING); } else { put_token_back(); @@ -1932,6 +1935,10 @@ static void parse_statement_g(int break_label, int continue_label) get_next_token(); /* Initialisation code */ + AO.type = OMITTED_OT; + spare_debug_location1 = statement_debug_location; + AO2.type = OMITTED_OT; flag = 0; + spare_debug_location2 = statement_debug_location; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); @@ -1954,7 +1961,6 @@ static void parse_statement_g(int break_label, int continue_label) assemble_label_no(ln2); return; } - AO.type = OMITTED_OT; goto ParseUpdate; } put_token_back(); @@ -1962,7 +1968,6 @@ static void parse_statement_g(int break_label, int continue_label) } get_next_token(); - AO.type = OMITTED_OT; if (!((token_type==SEP_TT)&&(token_value==COLON_SEP))) { put_token_back(); spare_debug_location1 = get_token_location(); @@ -1972,7 +1977,6 @@ static void parse_statement_g(int break_label, int continue_label) get_next_token(); ParseUpdate: - AO2.type = OMITTED_OT; flag = 0; if (!((token_type==SEP_TT)&&(token_value==CLOSEB_SEP))) { put_token_back(); spare_debug_location2 = get_token_location(); @@ -2546,7 +2550,10 @@ static void parse_statement_g(int break_label, int continue_label) get_next_token(); if (token_type == DQ_TT) { INITAOT(&AO4, CONSTANT_OT); - AO4.value = compile_string(token_text, TRUE, TRUE); + /* This is not actually placed in low memory; Glulx + has no such concept. We use the LOWSTRING flag + for compatibility with older compiler behavior. */ + AO4.value = compile_string(token_text, STRCTX_LOWSTRING); AO4.marker = STRING_MV; } else diff --git a/src/symbols.c b/src/symbols.c index 90ec3bf..6d736e9 100644 --- a/src/symbols.c +++ b/src/symbols.c @@ -89,6 +89,8 @@ static char** symbol_name_space_chunks; /* For chunks of memory used to hold the name strings of symbols */ static int no_symbol_name_space_chunks; +/* Symbol replacements (used by the "Replace X Y" directive). */ + typedef struct value_pair_struct { int original_symbol; int renamed_symbol; @@ -97,6 +99,18 @@ static value_pair_t *symbol_replacements; static int symbol_replacements_count; static int symbol_replacements_size; /* calloced size */ +/* Symbol definitions requested at compile time. (There may not be any.) + These are set up at command-line parse time, not in init_symbols_vars(). + Similarly, they are not cleaned up by symbols_free_arrays(). */ + +typedef struct keyvalue_pair_struct { + char *symbol; + int32 value; +} keyvalue_pair_t; +static keyvalue_pair_t *symbol_definitions = NULL; +static int symbol_definitions_count = 0; +static int symbol_definitions_size = 0; /* calloced size */ + /* ------------------------------------------------------------------------- */ /* The symbols table is "hash-coded" into a disjoint union of linked */ /* lists, so that for any symbol i, next_entry[i] is either -1 (meaning */ @@ -170,6 +184,28 @@ extern int strcmpcis(char *p, char *q) return -qc; } +/* ------------------------------------------------------------------------- */ + +extern void add_config_symbol_definition(char *symbol, int32 value) +{ + if (symbol_definitions_count == symbol_definitions_size) { + int oldsize = symbol_definitions_size; + if (symbol_definitions_size == 0) + symbol_definitions_size = 4; + else + symbol_definitions_size *= 2; + my_recalloc(&symbol_definitions, sizeof(keyvalue_pair_t), oldsize, + symbol_definitions_size, "symbol definition table"); + } + + char *str = my_malloc(strlen(symbol)+1, "symbol name"); + strcpy(str, symbol); + + symbol_definitions[symbol_definitions_count].symbol = str; + symbol_definitions[symbol_definitions_count].value = value; + symbol_definitions_count++; +} + /* ------------------------------------------------------------------------- */ /* Symbol finding, creating, and removing. */ /* ------------------------------------------------------------------------- */ @@ -391,7 +427,7 @@ extern void write_the_identifier_names(void) veneer_mode = TRUE; - null_value = compile_string(unknown_attribute, FALSE, FALSE); + null_value = compile_string(unknown_attribute, STRCTX_SYMBOL); for (i=0; iaddress != DF_NOT_IN_FUNCTION) + if (!func || func->address != DF_NOT_IN_FUNCTION) { compiler_error("DF: Global namespace entry is not at the head of the chain."); + return; + } for (ent = func->refs; ent; ent=ent->refsnext) { uint32 addr; diff --git a/src/tables.c b/src/tables.c index 1f7ba01..4158253 100644 --- a/src/tables.c +++ b/src/tables.c @@ -1242,7 +1242,7 @@ static void construct_storyfile_g(void) "array name strings"); write_the_identifier_names(); - threespaces = compile_string(" ", FALSE, FALSE); + threespaces = compile_string(" ", STRCTX_GAME); compress_game_text(); diff --git a/src/text.c b/src/text.c index 064a5da..88ceaec 100644 --- a/src/text.c +++ b/src/text.c @@ -38,10 +38,7 @@ char *all_text, *all_text_top; /* Start and next byte free in (large) text buffer holding the entire text of the game, when it is being recorded */ -int is_abbreviation, /* When TRUE, the string being trans - is itself an abbreviation string - so can't make use of abbreviations */ - abbrevs_lookup_table_made, /* The abbreviations lookup table is +int abbrevs_lookup_table_made, /* The abbreviations lookup table is constructed when the first non- abbreviation string is translated: this flag is TRUE after that */ @@ -213,9 +210,7 @@ extern void make_abbreviation(char *text) strcpy((char *)abbreviations_at + no_abbreviations*MAX_ABBREV_LENGTH, text); - is_abbreviation = TRUE; - abbrev_values[no_abbreviations] = compile_string(text, TRUE, TRUE); - is_abbreviation = FALSE; + abbrev_values[no_abbreviations] = compile_string(text, STRCTX_ABBREV); /* The quality is the number of Z-chars saved by using this */ /* abbreviation: note that it takes 2 Z-chars to print it. */ @@ -224,30 +219,32 @@ extern void make_abbreviation(char *text) } /* ------------------------------------------------------------------------- */ -/* The front end routine for text translation */ +/* The front end routine for text translation. */ +/* strctx indicates the purpose of the string. This is mostly used for */ +/* informational output (gametext.txt), but we treat some string contexts */ +/* specially during compilation. */ /* ------------------------------------------------------------------------- */ -extern int32 compile_string(char *b, int in_low_memory, int is_abbrev) +extern int32 compile_string(char *b, int strctx) { int i, j; uchar *c; - is_abbreviation = is_abbrev; - - /* Put into the low memory pool (at 0x100 in the Z-machine) of strings */ - /* which may be wanted as possible entries in the abbreviations table */ + /* In Z-code, abbreviations go in the low memory pool (0x100). So + do strings explicitly defined with the Lowstring directive. + (In Glulx, the in_low_memory flag is ignored.) */ + int in_low_memory = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING); if (!glulx_mode && in_low_memory) { j=subtract_pointers(low_strings_top,low_strings); - low_strings_top=translate_text(low_strings_top, low_strings+MAX_LOW_STRINGS, b); + low_strings_top=translate_text(low_strings_top, low_strings+MAX_LOW_STRINGS, b, strctx); if (!low_strings_top) memoryerror("MAX_LOW_STRINGS", MAX_LOW_STRINGS); - is_abbreviation = FALSE; return(0x21+(j/2)); } if (glulx_mode && done_compression) compiler_error("Tried to add a string after compression was done."); - c = translate_text(strings_holding_area, strings_holding_area+MAX_STATIC_STRINGS, b); + c = translate_text(strings_holding_area, strings_holding_area+MAX_STATIC_STRINGS, b, strctx); if (!c) memoryerror("MAX_STATIC_STRINGS",MAX_STATIC_STRINGS); @@ -282,8 +279,6 @@ extern int32 compile_string(char *b, int in_low_memory, int is_abbrev) write_byte_to_memory_block(&static_strings_area, static_strings_extent, *c); - is_abbreviation = FALSE; - if (!glulx_mode) { return(j/scale_factor); } @@ -378,11 +373,20 @@ static void write_z_char_g(int i) /* Note that the source text may be corrupted by this routine. */ /* ------------------------------------------------------------------------- */ -extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text) +extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text, int strctx) { int i, j, k, in_alphabet, lookup_value; int32 unicode; int zscii; unsigned char *text_in; + /* For STRCTX_ABBREV, the string being translated is itself an + abbreviation string, so it can't make use of abbreviations. Set + the is_abbreviation flag to indicate this. + The compiler has historically set this flag for the Lowstring + directive as well -- the in_low_memory and is_abbreviation flag were + always the same. I am preserving that convention. */ + int is_abbreviation = (strctx == STRCTX_ABBREV || strctx == STRCTX_LOWSTRING); + + /* Cast the input and output streams to unsigned char: text_out_pc will advance as bytes of Z-coded text are written, but text_in doesn't */ @@ -421,9 +425,20 @@ extern uchar *translate_text(uchar *p, uchar *p_limit, char *s_text) all_text_top += strlen(all_text_top); } - if (transcript_switch && (!veneer_mode)) - write_to_transcript_file(s_text); - + if (transcript_switch) { + /* Omit veneer strings, unless we're using the new transcript format, which includes everything. */ + if ((!veneer_mode) || TRANSCRIPT_FORMAT == 1) { + int label = strctx; + if (veneer_mode) { + if (label == STRCTX_GAME) + label = STRCTX_VENEER; + else if (label == STRCTX_GAMEOPC) + label = STRCTX_VENEEROPC; + } + write_to_transcript_file(s_text, label); + } + } + if (!glulx_mode) { /* The empty string of Z-text is illegal, since it can't carry an end @@ -1495,8 +1510,8 @@ extern void optimise_abbreviations(void) /* For Glulx, the form is instead: (But see below about Unicode-valued */ /* dictionaries and my heinie.) */ /* */ -/* */ -/* DICT_WORD_SIZE short short short */ +/* */ +/* $60 DICT_WORD_SIZE short short short */ /* */ /* These records are stored in "accession order" (i.e. in order of their */ /* first being received by these routines) and only alphabetically sorted */ @@ -1646,7 +1661,7 @@ apostrophe in", dword); for (; i<9; i++) wd[i]=5; - /* The array of Z-chars is converted to three 2-byte blocks */ + /* The array of Z-chars is converted to two or three 2-byte blocks */ tot = wd[2] + wd[1]*(1<<5) + wd[0]*(1<<10); prepared_sort[1]=tot%0x100; @@ -1654,7 +1669,10 @@ apostrophe in", dword); tot = wd[5] + wd[4]*(1<<5) + wd[3]*(1<<10); prepared_sort[3]=tot%0x100; prepared_sort[2]=(tot/0x100)%0x100; - tot = wd[8] + wd[7]*(1<<5) + wd[6]*(1<<10); + if (version_number==3) + tot = 0; + else + tot = wd[8] + wd[7]*(1<<5) + wd[6]*(1<<10); prepared_sort[5]=tot%0x100; prepared_sort[4]=(tot/0x100)%0x100; @@ -2050,17 +2068,81 @@ extern void dictionary_set_verb_number(char *dword, int to) /* by the linker. */ /* ------------------------------------------------------------------------- */ -static char *d_show_to; -static int d_show_total; +/* In the dictionary-showing code, if d_show_buf is NULL, the text is + printed directly. (The "Trace dictionary" directive does this.) + If d_show_buf is not NULL, we add words to it (reallocing if necessary) + until it's a page-width. +*/ +static char *d_show_buf = NULL; +static int d_show_size; /* allocated size */ +static int d_show_len; /* current length */ static void show_char(char c) -{ if (d_show_to == NULL) printf("%c", c); - else - { int i = strlen(d_show_to); - d_show_to[i] = c; d_show_to[i+1] = 0; +{ + if (d_show_buf == NULL) { + printf("%c", c); + } + else { + if (d_show_len+2 >= d_show_size) { + int newsize = 2 * d_show_len + 16; + my_realloc(&d_show_buf, d_show_size, newsize, "dictionary display buffer"); + d_show_size = newsize; + } + d_show_buf[d_show_len++] = c; + d_show_buf[d_show_len] = '\0'; } } +/* Display a Unicode character in user-readable form. This uses the same + character encoding as the source code. */ +static void show_uchar(uint32 c) +{ + char buf[16]; + int ix; + + if (c < 0x80) { + /* ASCII always works */ + show_char(c); + return; + } + if (character_set_unicode) { + /* UTF-8 the character */ + if (c < 0x80) { + show_char(c); + } + else if (c < 0x800) { + show_char((0xC0 | ((c & 0x7C0) >> 6))); + show_char((0x80 | (c & 0x03F) )); + } + else if (c < 0x10000) { + show_char((0xE0 | ((c & 0xF000) >> 12))); + show_char((0x80 | ((c & 0x0FC0) >> 6))); + show_char((0x80 | (c & 0x003F) )); + } + else if (c < 0x200000) { + show_char((0xF0 | ((c & 0x1C0000) >> 18))); + show_char((0x80 | ((c & 0x03F000) >> 12))); + show_char((0x80 | ((c & 0x000FC0) >> 6))); + show_char((0x80 | (c & 0x00003F) )); + } + else { + show_char('?'); + } + return; + } + if (character_set_setting == 1 && c < 0x100) { + /* Fits in Latin-1 */ + show_char(c); + return; + } + /* Supporting other character_set_setting is harder; not currently implemented. */ + + /* Use the escaped form */ + sprintf(buf, "@{%x}", c); + for (ix=0; buf[ix]; ix++) + show_char(buf[ix]); +} + extern void word_to_ascii(uchar *p, char *results) { int i, shift, cc, zchar; uchar encoded_word[9]; encoded_word[0] = (((int) p[0])&0x7c)/4; @@ -2106,7 +2188,7 @@ extern void word_to_ascii(uchar *p, char *results) static void recursively_show_z(int node) { int i, cprinted, flags; uchar *p; char textual_form[32]; - int res = (version_number == 3)?4:6; + int res = (version_number == 3)?4:6; /* byte length of encoded text */ if (dtree[node].branch[0] != VACANT) recursively_show_z(dtree[node].branch[0]); @@ -2120,7 +2202,7 @@ static void recursively_show_z(int node) for (; cprinted < 4 + ((version_number==3)?6:9); cprinted++) show_char(' '); - if (d_show_to == NULL) + if (d_show_buf == NULL) { for (i=0; i<3+res; i++) printf("%02x ",p[i]); flags = (int) p[res]; @@ -2141,12 +2223,11 @@ static void recursively_show_z(int node) printf("\n"); } - if (d_show_total++ == 5) - { d_show_total = 0; - if (d_show_to != NULL) - { write_to_transcript_file(d_show_to); - d_show_to[0] = 0; - } + /* Show five words per line in classic TRANSCRIPT_FORMAT; one per line in the new format. */ + if (d_show_buf && (d_show_len >= 64 || TRANSCRIPT_FORMAT == 1)) + { + write_to_transcript_file(d_show_buf, STRCTX_DICT); + d_show_len = 0; } if (dtree[node].branch[1] != VACANT) @@ -2154,8 +2235,56 @@ static void recursively_show_z(int node) } static void recursively_show_g(int node) -{ - warning("### Glulx dictionary-show not yet implemented.\n"); +{ int i, cprinted; + uchar *p; + + if (dtree[node].branch[0] != VACANT) + recursively_show_g(dtree[node].branch[0]); + + p = (uchar *)dictionary + 4 + DICT_ENTRY_BYTE_LENGTH*node; + + for (cprinted = 0; cprinted= 64 || TRANSCRIPT_FORMAT == 1)) + { + write_to_transcript_file(d_show_buf, STRCTX_DICT); + d_show_len = 0; + } + + if (dtree[node].branch[1] != VACANT) + recursively_show_g(dtree[node].branch[1]); } static void show_alphabet(int i) @@ -2177,33 +2306,43 @@ static void show_alphabet(int i) extern void show_dictionary(void) { printf("Dictionary contains %d entries:\n",dict_entries); if (dict_entries != 0) - { d_show_total = 0; d_show_to = NULL; + { d_show_len = 0; d_show_buf = NULL; if (!glulx_mode) recursively_show_z(root); else recursively_show_g(root); } - printf("\nZ-machine alphabet entries:\n"); - show_alphabet(0); - show_alphabet(1); - show_alphabet(2); + if (!glulx_mode) + { + printf("\nZ-machine alphabet entries:\n"); + show_alphabet(0); + show_alphabet(1); + show_alphabet(2); + } } extern void write_dictionary_to_transcript(void) -{ char d_buffer[81]; - - sprintf(d_buffer, "\n[Dictionary contains %d entries:]\n", dict_entries); +{ + d_show_size = 80; /* initial size */ + d_show_buf = my_malloc(d_show_size, "dictionary display buffer"); - d_buffer[0] = 0; write_to_transcript_file(d_buffer); + write_to_transcript_file("", STRCTX_INFO); + sprintf(d_show_buf, "[Dictionary contains %d entries:]", dict_entries); + write_to_transcript_file(d_show_buf, STRCTX_INFO); + + d_show_len = 0; if (dict_entries != 0) - { d_show_total = 0; d_show_to = d_buffer; + { if (!glulx_mode) recursively_show_z(root); else recursively_show_g(root); } - if (d_show_total != 0) write_to_transcript_file(d_buffer); + if (d_show_len != 0) write_to_transcript_file(d_show_buf, STRCTX_DICT); + + my_free(&d_show_buf, "dictionary display buffer"); + d_show_len = 0; d_show_buf = NULL; } /* ========================================================================= */ @@ -2218,7 +2357,6 @@ extern void init_text_vars(void) grandtable = NULL; grandflags = NULL; no_chars_transcribed = 0; - is_abbreviation = FALSE; for (j=0; j<256; j++) abbrevs_lookup[j] = -1; @@ -2273,6 +2411,10 @@ extern void text_allocate_arrays(void) = my_malloc(MAX_STATIC_STRINGS,"static strings holding area"); low_strings = my_malloc(MAX_LOW_STRINGS,"low (abbreviation) strings"); + d_show_buf = NULL; + d_show_size = 0; + d_show_len = 0; + huff_entities = NULL; hufflist = NULL; unicode_usage_entries = NULL; diff --git a/src/verbs.c b/src/verbs.c index 2caa67c..962b32f 100644 --- a/src/verbs.c +++ b/src/verbs.c @@ -61,6 +61,8 @@ int no_adjectives; /* Number of adjectives made so far */ /* for example the English verbs "take" and "drop" both normally */ /* correspond in a game's dictionary to the same Inform verb. An */ /* Inform verb is essentially a list of grammar lines. */ +/* (Calling them "English verbs" is of course out of date. Read */ +/* this as jargon for "dict words which are verbs". */ /* ------------------------------------------------------------------------- */ /* Arrays defined below: */ /* */ @@ -91,6 +93,9 @@ static char *English_verb_list, /* First byte of first record */ static int English_verb_list_size; /* Size of the list in bytes (redundant but convenient) */ +/* Maximum synonyms in a single Verb/Extend directive */ +#define MAX_VERB_SYNONYMS (32) + /* ------------------------------------------------------------------------- */ /* Arrays used by this file */ /* ------------------------------------------------------------------------- */ @@ -726,7 +731,8 @@ extern void make_verb(void) int Inform_verb, meta_verb_flag=FALSE, verb_equals_form=FALSE; - char *English_verbs_given[32]; int no_given = 0, i; + char *English_verbs_given[MAX_VERB_SYNONYMS]; + int no_given = 0, i; directive_keywords.enabled = TRUE; @@ -738,7 +744,12 @@ extern void make_verb(void) } while ((token_type == DQ_TT) || (token_type == SQ_TT)) - { English_verbs_given[no_given++] = token_text; + { + if (no_given >= MAX_VERB_SYNONYMS) { + error("Too many synonyms in a Verb directive."); + panic_mode_error_recovery(); return; + } + English_verbs_given[no_given++] = token_text; get_next_token(); } -- 2.31.1