X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=interpreters%2Fnitfol%2Finfix.c;fp=interpreters%2Fnitfol%2Finfix.c;h=47b208d9664ce5550970aa11c6b38d2a465495aa;hb=b1f1dc50b22b30c4d7176e1ff7c0805e80fe0724;hp=0000000000000000000000000000000000000000;hpb=50176172d18ae72d019181725c5629d45d21c548;p=projects%2Fchimara%2Fchimara.git diff --git a/interpreters/nitfol/infix.c b/interpreters/nitfol/infix.c new file mode 100644 index 0000000..47b208d --- /dev/null +++ b/interpreters/nitfol/infix.c @@ -0,0 +1,1170 @@ +/* Nitfol - z-machine interpreter using Glk for output. + Copyright (C) 1999 Evin Robertson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + + The author can be reached at nitfol@deja.com +*/ +#include "nitfol.h" +#ifdef STDOUT_DEBUG +#include +#endif + + +#ifdef DEBUGGING + + +#ifdef HEADER + +typedef enum { Z_UNKNOWN, Z_BOOLEAN, Z_NUMBER, Z_OBJECT, Z_ROUTINE, Z_STRING, Z_GLOBAL, Z_LOCAL, Z_BYTEARRAY, Z_WORDARRAY, Z_OBJPROP, Z_ATTR, Z_PROP, Z_ARRAY } z_type; + +typedef struct z_typed z_typed; +struct z_typed { + zword v; /* The value stored */ + z_type t; + + zword o, p; /* location of value (if t is appropriate) */ +}; + + +typedef struct { + const char *filename; + strid_t stream; + int num_lines; + glui32 *line_locations; +} infix_file; + +typedef struct { + infix_file *file; + int line_num; + int line_x; + const char *func_name; + unsigned func_num; + offset thisPC; +} infix_location; + +#endif + + +#define EOF_DBR 0 +#define FILE_DBR 1 +#define CLASS_DBR 2 +#define OBJECT_DBR 3 +#define GLOBAL_DBR 4 +#define ATTR_DBR 5 +#define PROP_DBR 6 +#define FAKE_ACTION_DBR 7 +#define ACTION_DBR 8 +#define HEADER_DBR 9 +#define LINEREF_DBR 10 +#define ROUTINE_DBR 11 +#define ARRAY_DBR 12 +#define MAP_DBR 13 +#define ROUTINE_END_DBR 14 +#define MAX_DBR 14 + +static unsigned record_info[][9] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* eof_dbr */ + { 1, 0x8000, 0x8000, 0, 0, 0, 0, 0, 0 }, /* file_dbr */ + { 0x8000, 1, 2, 1, 1, 2, 1, 0, 0 }, /* class_dbr */ + { 2, 0x8000, 1, 2, 1, 1, 2, 1, 0 }, /* object_dbr */ + { 1, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* global_dbr */ + { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* attr_dbr */ + { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* prop_dbr */ + { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* fake_action_dbr */ + { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* action_dbr */ + { 64, 0, 0, 0, 0, 0, 0, 0, 0 }, /* header_dbr */ + { 2, 2, 0, 0, 0, 0, 0, 0, 0 }, /* lineref_dbr */ + { 2, 1, 2, 1, 3, 0x8000, 0, 0, 0 }, /* routine_dbr */ + { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* array_dbr */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* map_dbr */ + { 2, 1, 2, 1, 3, 0, 0, 0, 0 } /* routine_end_dbr */ +}; + + +offset infix_get_routine_PC(zword routine) +{ + offset destPC = UNPACKR(routine); + unsigned num_local = HIBYTE(destPC); + destPC++; + if(zversion < 5) + destPC += num_local * ZWORD_SIZE; + return destPC; +} + + +static infix_file infix_load_file_info(const char *filename) +{ + infix_file r; + glsi32 c; + int lines_allocated = 0; + + r.filename = filename; + r.num_lines = 0; + r.line_locations = NULL; + + r.stream = n_file_name(fileusage_Data | fileusage_TextMode, + filemode_Read, filename); + + if(!r.stream) + return r; + + lines_allocated = 256; + r.line_locations = (glui32 *) n_malloc(lines_allocated * sizeof(*r.line_locations)); + r.line_locations[r.num_lines] = 0; + r.num_lines++; + + while((c = glk_get_char_stream(r.stream)) != GLK_EOF) { + if(c == 10) { + if(r.num_lines >= lines_allocated) { + glui32 *new_locations; + + lines_allocated *= 2; + new_locations = (glui32 *) n_realloc(r.line_locations, + lines_allocated * sizeof(*r.line_locations)); + r.line_locations = new_locations; + } + r.line_locations[r.num_lines] = glk_stream_get_position(r.stream); + r.num_lines++; + } + } + return r; +} + + +static void infix_unload_file_info(infix_file *f) +{ + if(f->line_locations) + n_free(f->line_locations); + f->line_locations = 0; + return; +} + + +void infix_file_print_line(infix_file *f, int line) +{ + glsi32 c; + + if(!(f && f->stream && f->num_lines && f->line_locations)) + return; + + if(line <= 0) + line = 1; + if(line > f->num_lines) + line = f->num_lines; + + if(fullname) { /* Running as a subprocess under emacs */ + infix_print_char(26); + infix_print_char(26); + infix_print_string(f->filename); + infix_print_char(':'); + infix_print_number(line); + infix_print_char(':'); + infix_print_number(f->line_locations[line-1] + 0); + infix_print_string(":beg:0x00000000"); + } else { + infix_print_number(line); + infix_print_char('\t'); + + glk_stream_set_position(f->stream, f->line_locations[line-1], seekmode_Start); + + while((c = glk_get_char_stream(f->stream)) != GLK_EOF) { + if(c == 10) + break; + infix_print_char(c); + } + } + + infix_print_char(10); +} + + +static unsigned local_names_info[] = { 0x8000, 0 }; +static unsigned sequence_point_info[] ={ 1, 2, 1, 2, 0 }; +static unsigned map_info[] = { 0x8000, 3, 0 }; + +static glui32 infix_strlen; +static char *infix_stringdata; + +static glui32 infix_add_string(strid_t infix) +{ + glui32 ch; + glui32 return_offset = infix_strlen; + + while((ch = glk_get_char_stream(infix)) != 0) { + if(infix_stringdata) + infix_stringdata[infix_strlen] = ch; + infix_strlen++; + } + + if(infix_stringdata) + infix_stringdata[infix_strlen] = 0; + infix_strlen++; + + return return_offset; +} + +static void infix_add_stringchar(int c) +{ + /* Really inefficient to call realloc for every character, but oh well... */ + infix_stringdata = n_realloc(infix_stringdata, infix_strlen+1); + infix_stringdata[infix_strlen++] = c; +} + +static glui32 infix_add_zstring(zword paddr) +{ + if(paddr) { + glui32 return_offset = infix_strlen; + offset addr = UNPACKS(paddr); + if(addr+2 < total_size) { + decodezscii(addr, infix_add_stringchar); + infix_add_stringchar(0); + return return_offset; + } + } + return 0xffffffffL; +} + + +static infix_file *infix_files; +static unsigned infix_filescount; + +static char **infix_objects; +static unsigned infix_objectscount; + +static char **infix_globals; +static unsigned infix_globalscount; + +typedef struct { + zword address; + const char *name; +} infix_arrayref; + +static infix_arrayref *infix_arrays; +static unsigned infix_arrayscount; + +static char **infix_attrs; +static unsigned infix_attrscount; + +static char **infix_props; +static unsigned infix_propscount; + +typedef struct { + const char *name; + unsigned filenum; + unsigned startline; + unsigned start_x; + offset start_PC; + const char *localnames[15]; + unsigned end_line; + unsigned end_x; + offset end_PC; +} routineref; + +static routineref *infix_routines; +static unsigned infix_routinescount; + +typedef struct { + unsigned routine; + unsigned filenum; + unsigned line; + unsigned x; + offset PC; +} infix_sequence; + +static infix_sequence *infix_linerefs; +static unsigned infix_linerefscount; + + +static offset code_start = 0; +static offset string_start = 0; + +static int infix_compare_linerefs(const void *a, const void *b) +{ + const infix_sequence *A = (const infix_sequence *) a; + const infix_sequence *B = (const infix_sequence *) b; + if(A->PC < B->PC) + return -1; + if(A->PC > B->PC) + return 1; + + if(A->line < B->line) + return -1; + if(A->line > B->line) + return 1; + return 0; +} + +static BOOL infix_load_records(strid_t infix) +{ + unsigned n; + + for(;;) { + glui32 record_type = glk_get_char_stream(infix); + glui32 record_data[64]; + glui32 more_data[4]; + if(record_type > MAX_DBR) { + glk_stream_close(infix, NULL); + n_show_error(E_DEBUG, "unknown record type", record_type); + return FALSE; + } + + fillstruct(infix, record_info[record_type], record_data, infix_add_string); + + switch(record_type) { + case EOF_DBR: + if(infix_linerefs && infix_routines && code_start) { + for(n = 0; n < infix_routinescount; n++) { + infix_routines[n].start_PC += code_start; + infix_routines[n].end_PC += code_start; + } + + n_qsort(infix_linerefs, infix_linerefscount, sizeof(*infix_linerefs), + infix_compare_linerefs); + + for(n = 0; n < infix_linerefscount; n++) + infix_linerefs[n].PC += code_start; + } + return TRUE; + case FILE_DBR: + if(infix_files) { + infix_files[record_data[0]] = infix_load_file_info(infix_stringdata + record_data[2]); + } + if(record_data[0] >= infix_filescount) + infix_filescount = record_data[0] + 1; + break; + case CLASS_DBR: + break; + case OBJECT_DBR: + if(infix_objects) { + infix_objects[record_data[0]] = infix_stringdata + record_data[1]; + } + if(record_data[0] >= infix_objectscount) + infix_objectscount = record_data[0] + 1; + break; + case GLOBAL_DBR: + if(infix_globals) { + infix_globals[record_data[0]] = infix_stringdata + record_data[1]; + } + if(record_data[0] >= infix_globalscount) + infix_globalscount = record_data[0] + 1; + break; + case ARRAY_DBR: + if(infix_arrays) { + } + infix_arrayscount++; + break; + case ATTR_DBR: + if(infix_attrs) { + infix_attrs[record_data[0]] = infix_stringdata + record_data[1]; + } + if(record_data[0] >= infix_attrscount) + infix_attrscount = record_data[0] + 1; + break; + case PROP_DBR: + if(infix_props) { + infix_props[record_data[0]] = infix_stringdata + record_data[1]; + } + if(record_data[0] >= infix_propscount) + infix_propscount = record_data[0] + 1; + break; + case FAKE_ACTION_DBR: + break; + case ACTION_DBR: + break; + case HEADER_DBR: + glk_stream_set_position(current_zfile, 0, seekmode_Start); + for(n = 0; n < 64; n++) { + unsigned c = (unsigned char) glk_get_char_stream(current_zfile); + if(record_data[n] != c) { + n_show_error(E_DEBUG, "infix file does not match current file", n); + return FALSE; + } + } + break; + case ROUTINE_DBR: + if(infix_routines) { + infix_routines[record_data[0]].filenum = record_data[1]; + infix_routines[record_data[0]].startline = record_data[2]; + infix_routines[record_data[0]].start_x = record_data[3]; + infix_routines[record_data[0]].start_PC = record_data[4]; + infix_routines[record_data[0]].name = infix_stringdata + + record_data[5]; + } + + if(infix_routines) + for(n = 0; n < 15; n++) + infix_routines[record_data[0]].localnames[n] = NULL; + + for(n = 0; n < 16; n++) { + if(!glk_get_char_stream(infix)) + break; + if(n == 15) + return FALSE; + glk_stream_set_position(infix, -1, seekmode_Current); + fillstruct(infix, local_names_info, more_data, infix_add_string); + if(infix_routines) { + infix_routines[record_data[0]].localnames[n] = infix_stringdata + + more_data[0]; + } + } + if(record_data[0] >= infix_routinescount) + infix_routinescount = record_data[0] + 1; + break; + case LINEREF_DBR: + for(n = 0; n < record_data[1]; n++) { + fillstruct(infix, sequence_point_info, more_data, NULL); + if(infix_linerefs) { + infix_linerefs[infix_linerefscount].routine = record_data[0]; + infix_linerefs[infix_linerefscount].filenum = more_data[0]; + infix_linerefs[infix_linerefscount].line = more_data[1]; + infix_linerefs[infix_linerefscount].x = more_data[2]; + infix_linerefs[infix_linerefscount].PC = more_data[3] + + infix_routines[record_data[0]].start_PC; + } + infix_linerefscount++; + } + break; + case ROUTINE_END_DBR: + if(infix_routines) { + infix_routines[record_data[0]].end_line = record_data[2]; + infix_routines[record_data[0]].end_x = record_data[3]; + infix_routines[record_data[0]].end_PC = record_data[4]; + } + if(record_data[0] >= infix_routinescount) + infix_routinescount = record_data[0] + 1; + break; + case MAP_DBR: + for(;;) { + if(!glk_get_char_stream(infix)) + break; + glk_stream_set_position(infix, -1, seekmode_Current); + fillstruct(infix, map_info, more_data, infix_add_string); + if(infix_stringdata) { + if(n_strcmp(infix_stringdata + more_data[0], "code area") == 0) + code_start = more_data[1]; + if(n_strcmp(infix_stringdata + more_data[0], "strings area") == 0) + string_start = more_data[1]; + } + } + break; + } + } +} + + +BOOL init_infix(strid_t infix) +{ + if(!infix && (infix_props || infix_attrs)) + return FALSE; + + kill_infix(); + + /* Inform 6.10+ has run-time symbols (techman 9.6) */ + if(!infix && z_memory && prop_table_end + && (z_memory[HD_INFORMVER] == '6' && z_memory[HD_INFORMVER + 2] >= '1')) { + zword addr; + unsigned i; + glui32 *prop_names, *attr_names; + + /* Assume no strings before end of property table */ + string_start = prop_table_end; + + for(addr = prop_table_end+1; LOWORD(addr); addr+=ZWORD_SIZE) + ; + addr+=ZWORD_SIZE; + + infix_propscount = LOWORD(addr) - 1; addr+=ZWORD_SIZE; + prop_names = (glui32 *) n_calloc(sizeof(*prop_names), infix_propscount+1); + for(i = 1; i <= infix_propscount; i++) { + prop_names[i] = infix_add_zstring(LOWORD(addr)); + addr += ZWORD_SIZE; + } + + infix_attrscount = 48; + attr_names = (glui32 *) n_calloc(sizeof(*prop_names), infix_propscount); + for(i = 0; i <= 47; i++) { + attr_names[i] = infix_add_zstring(LOWORD(addr)); + addr += ZWORD_SIZE; + } + + infix_props = (char **) n_calloc(sizeof(*infix_props), infix_propscount+1); + infix_attrs = (char **) n_calloc(sizeof(*infix_attrs), infix_attrscount); + for(i = 1; i <= infix_propscount; i++) { + if(prop_names[i] != 0xffffffffL) + infix_props[i] = infix_stringdata + prop_names[i]; + } + for(i = 0; i <= 47; i++) { + if(attr_names[i] != 0xffffffffL) + infix_attrs[i] = infix_stringdata + attr_names[i]; + } + + n_free(prop_names); + n_free(attr_names); + + return TRUE; + } + + if(!infix) + return FALSE; + + glk_stream_set_position(infix, 0, seekmode_Start); + if((glk_get_char_stream(infix) != 0xDE) || + (glk_get_char_stream(infix) != 0xBF) || + (glk_get_char_stream(infix) != 0x00) || + (glk_get_char_stream(infix) != 0x00)) { + glk_stream_close(infix, NULL); + n_show_error(E_DEBUG, "unknown version or not an infix file", 0); + return FALSE; + } + + /* ignore inform version number */ + glk_stream_set_position(infix, 6, seekmode_Start); + + /* Calculate space requirements */ + infix_load_records(infix); + + /* Malloc required memory */ + infix_stringdata = (char *) n_calloc(sizeof(*infix_stringdata), + infix_strlen); + infix_strlen = 0; + infix_files = (infix_file *) n_calloc(sizeof(*infix_files), + infix_filescount); + infix_filescount = 0; + infix_objects = (char **) n_calloc(sizeof(*infix_objects), + infix_objectscount); + infix_objectscount = 0; + infix_globals = (char **) n_calloc(sizeof(*infix_globals), + infix_globalscount); + infix_globalscount = 0; + infix_attrs = (char **) n_calloc(sizeof(*infix_attrs), + infix_attrscount); + infix_attrscount = 0; + infix_props = (char **) n_calloc(sizeof(*infix_props), + infix_propscount); + infix_propscount = 0; + infix_routines = (routineref *) n_calloc(sizeof(*infix_routines), + infix_routinescount); + infix_routinescount= 0; + infix_linerefs = (infix_sequence *) n_calloc(sizeof(*infix_linerefs), + infix_linerefscount); + infix_linerefscount= 0; + + glk_stream_set_position(infix, 6, seekmode_Start); + infix_load_records(infix); + + return TRUE; +} + + +void kill_infix(void) +{ + unsigned i; + + n_free(infix_stringdata); + infix_stringdata = 0; + infix_strlen = 0; + + if(infix_files) { + for(i = 0; i < infix_filescount; i++) + infix_unload_file_info(&infix_files[i]); + n_free(infix_files); + } + infix_files = 0; + infix_filescount = 0; + + n_free(infix_objects); + infix_objects = 0; + infix_objectscount = 0; + + n_free(infix_globals); + infix_globals = 0; + infix_globalscount = 0; + + n_free(infix_attrs); + infix_attrs = 0; + infix_attrscount = 0; + + n_free(infix_props); + infix_props = 0; + infix_propscount = 0; + + n_free(infix_routines); + infix_routines = 0; + infix_routinescount = 0; + + n_free(infix_linerefs); + infix_linerefs = 0; + infix_linerefscount = 0; +} + + +void infix_print_znumber(zword blah) +{ + set_glk_stream_current(); + g_print_znumber(blah); +} + +void infix_print_offset(zword blah) +{ + set_glk_stream_current(); + g_print_number(blah); +} + +void infix_print_number(zword blah) +{ + set_glk_stream_current(); + g_print_number(blah); +} + +void infix_print_char(int blah) +{ + if(blah == 13) + blah = 10; +#ifdef STDOUT_DEBUG + fputc(blah, stdout); +#else + set_glk_stream_current(); + /* We don't do a style-set because of bugs in zarf Glks */ + glk_put_char((unsigned char) blah); +#endif +} + +void infix_print_fixed_char(int blah) +{ + if(blah == 13) + blah = 10; +#ifdef STDOUT_DEBUG + fputc(blah, stdout); +#else + set_glk_stream_current(); + glk_set_style(style_Preformatted); + glk_put_char((unsigned char) blah); + glk_set_style(style_Normal); +#endif +} + +void infix_print_string(const char *blah) +{ + while(*blah) + infix_print_char(*blah++); +} + +void infix_print_fixed_string(const char *blah) +{ + while(*blah) + infix_print_fixed_char(*blah++); +} + +void infix_get_string(char *dest, int maxlen) +{ +#ifdef STDOUT_DEBUG + fgets(dest, maxlen, stdin); +#else + unsigned char t; + int len; + len = z_read(0, dest, maxlen - 1, 0, 0, 0, 0, &t); + dest[len] = 0; +#endif +} + +void infix_get_val(z_typed *val) +{ + switch(val->t) { + case Z_LOCAL: val->v = frame_get_var(val->o, val->p + 1); break; + case Z_GLOBAL: val->v = get_var(val->o + 0x10); break; + case Z_BYTEARRAY: val->v = LOBYTE(val->o + val->p); break; + case Z_WORDARRAY: val->v = LOWORD(val->o + ZWORD_SIZE * val->p); break; + case Z_OBJPROP: val->v = infix_get_prop(val->o, val->p); break; + default: ; + } +} + +void infix_assign(z_typed *dest, zword val) +{ + switch(dest->t) { + case Z_LOCAL: frame_set_var(dest->o, dest->p + 1, val); break; + case Z_BYTEARRAY: LOBYTEwrite(dest->o + dest->p, val); break; + case Z_WORDARRAY: LOWORDwrite(dest->o + ZWORD_SIZE * dest->p, val); break; + case Z_OBJPROP: infix_put_prop(dest->o, dest->p, val); break; + default: infix_print_string("assigning to non-lvalue\n"); break; + } + dest->v = val; +} + +void infix_display(z_typed val) +{ + unsigned n, i; + const char *name; + + switch(val.t) { + default: + infix_print_znumber(val.v); + break; + + case Z_BOOLEAN: + if(val.v) + infix_print_string("true"); + else + infix_print_string("false"); + break; + + case Z_UNKNOWN: + val.t = Z_NUMBER; + infix_display(val); + + name = debug_decode_number(val.v); + + if(name) { + infix_print_char(' '); + infix_print_char('('); + infix_print_string(name); + infix_print_char(')'); + } + break; + + case Z_OBJECT: + infix_object_display(val.v); + break; + + case Z_STRING: + infix_print_char('\"'); + decodezscii(UNPACKS(val.v), infix_print_char); + infix_print_char('\"'); + break; + + case Z_ROUTINE: + if(!infix_routines) + return; + + for(i = 0; i < infix_routinescount; i++) { + if(infix_routines[i].start_PC == UNPACKR(val.v)) { + + infix_print_char('{'); + for(n = 0; n < 15; n++) { + if(infix_routines[i].localnames[n]) { + infix_print_string(infix_routines[i].localnames[n]); + if(n < 14 && infix_routines[i].localnames[n+1]) + infix_print_string(", "); + } + } + infix_print_string("} "); + + infix_print_offset(infix_routines[i].start_PC); + infix_print_string(" <"); + infix_print_string(infix_routines[i].name); + infix_print_char('>'); + break; + } + } + } + infix_print_char('\n'); +} + + +int infix_find_file(infix_file **dest, const char *name) +{ + unsigned n; + if(infix_files) { + for(n = 0; n < infix_filescount; n++) { + if(infix_files[n].filename) { + unsigned len = n_strlen(infix_files[n].filename); + if(len && + n_strncasecmp(infix_files[n].filename, name, len) == 0 && + (name[len] == ' ' || name[len] == ':' || name[len] == 0)) { + *dest = &infix_files[n]; + return len; + } + } + } + } + return 0; +} + + +BOOL infix_find_symbol(z_typed *val, const char *name, int len) +{ + unsigned n; + if(infix_routines) { + infix_location location; + if(infix_decode_PC(&location, frame_get_PC(infix_selected_frame))) { + for(n = 0; n < 15; n++) { + if(n_strmatch(infix_routines[location.func_num].localnames[n], name, len)) { + val->t = Z_LOCAL; + val->o = infix_selected_frame; + val->p = n; + infix_get_val(val); + return TRUE; + } + } + } + } + if(infix_objects) + for(n = 0; n < infix_objectscount; n++) { + if(n_strmatch(infix_objects[n], name, len)) { + val->t = Z_OBJECT; + val->v = n; + return TRUE; + } + } + if(infix_globals) + for(n = 0; n < infix_globalscount; n++) { + if(n_strmatch(infix_globals[n], name, len)) { + val->t = Z_WORDARRAY; + val->o = z_globaltable; + val->p = n; + infix_get_val(val); + return TRUE; + } + } + if(infix_arrays) + for(n = 0; n < infix_arrayscount; n++) { + if(n_strmatch(infix_arrays[n].name, name, len)) { + val->t = Z_NUMBER; + val->v = n; + return TRUE; + } + } + if(infix_attrs) + for(n = 0; n < infix_attrscount; n++) { + if(n_strmatch(infix_attrs[n], name, len)) { + val->t = Z_NUMBER; + val->v = n; + return TRUE; + } + } + if(infix_props) + for(n = 0; n < infix_propscount; n++) { + if(n_strmatch(infix_props[n], name, len)) { + val->t = Z_NUMBER; + val->v = n; + return TRUE; + } + } + if(infix_routines) + for(n = 0; n < infix_routinescount; n++) { + if(n_strmatch(infix_routines[n].name, name, len)) { + val->t = Z_ROUTINE; + val->v = PACKR(infix_routines[n].start_PC); + return TRUE; + } + } + return FALSE; +} + +static char infix_temp_string_buffer[45]; +static unsigned infix_temp_strlen; + +static void infix_temp_string_build(int ch) +{ + infix_temp_string_buffer[infix_temp_strlen] = ch; + infix_temp_strlen++; + if(infix_temp_strlen > 40) { + infix_temp_strlen = 43; + infix_temp_string_buffer[40] = '.'; + infix_temp_string_buffer[41] = '.'; + infix_temp_string_buffer[42] = '.'; + } +} + + +const char *infix_get_name(z_typed val) +{ + unsigned i; + if(!infix_stringdata) + return NULL; + switch(val.t) { + case Z_GLOBAL: + if(val.o < infix_globalscount) + return infix_globals[val.o]; + break; + case Z_OBJECT: + if(val.v < infix_objectscount) + return infix_objects[val.v]; + break; + case Z_ATTR: + if(val.v < infix_attrscount) + return infix_attrs[val.v]; + break; + case Z_PROP: + if(val.v < infix_propscount) + return infix_props[val.v]; + break; + case Z_ROUTINE: + for(i = 0; i < infix_routinescount; i++) { + if(infix_routines[i].start_PC == UNPACKR(val.v)) + return infix_routines[i].name; + } + break; + case Z_STRING: + if(UNPACKS(val.v) < string_start) + break; + if(string_start < code_start && UNPACKS(val.v) >= code_start) + break; + if(UNPACKS(val.v) >= total_size) + break; + + /* Assume every string except the first is preceded by zeroed padding until + an end-of-string marker */ + if(UNPACKS(val.v) != string_start) { + offset addr = UNPACKS(val.v) - 2; + zword s; + while((s = HIWORD(addr)) == 0) + addr -= 2; + if(!(s & 0x8000)) + break; + } + + infix_temp_string_buffer[0] = '\"'; + infix_temp_strlen = 1; + testing_string = TRUE; string_bad = FALSE; + decodezscii(UNPACKS(val.v), infix_temp_string_build); + testing_string = FALSE; + if(string_bad) + break; + infix_temp_string_buffer[infix_temp_strlen] = '\"'; + infix_temp_string_buffer[infix_temp_strlen + 1] = 0; + return infix_temp_string_buffer; + case Z_ARRAY: + if(val.v < infix_arrayscount) + return infix_arrays[val.v].name; + break; + + default: ; + } + return NULL; +} + + +/* We search through linerefs very often so use binary search for speed */ + +static infix_sequence *infix_search_linerefs(offset thisPC) +{ + unsigned n; + int top = 0; + int bottom = infix_linerefscount-1; + int middle = (top + bottom) / 2; + + if(!infix_linerefs) + return NULL; + + do { + middle = (top + bottom) / 2; + if(thisPC < infix_linerefs[middle].PC) + bottom = middle - 1; + else if(thisPC > infix_linerefs[middle].PC) + top = middle + 1; + else + break; + } while(top <= bottom); + + /* If the PC is in the middle of a line, we want to display that line. In + this case, PC will be greater than infix_linerefs[middle].PC, so just let + it go. Otherwise, we want to look at the previous lineref, so subtract + one (or more) + */ + + while(middle && thisPC < infix_linerefs[middle].PC) + middle--; + + + /* Make sure PC is inside the function the lineref says it is; if so, then + we're done */ + + n = infix_linerefs[middle].routine; + if(thisPC >= infix_routines[n].start_PC && + thisPC <= infix_routines[n].end_PC) + return &infix_linerefs[middle]; + + return NULL; +} + + +BOOL infix_decode_PC(infix_location *dest, offset thisPC) +{ + infix_sequence *n = infix_search_linerefs(thisPC); + + if(!n) { /* No sequence point found - return a function */ + unsigned i; + + if(!infix_routines) + return FALSE; + + for(i = 0; i < infix_routinescount; i++) { + if(thisPC >= infix_routines[i].start_PC && + thisPC <= infix_routines[i].end_PC) { + + routineref *r = &infix_routines[i]; + dest->file = &infix_files[r->filenum]; + dest->line_num = r->startline; + dest->line_x = r->start_x; + dest->func_name = r->name; + dest->func_num = i; + dest->thisPC = r->start_PC; + + return TRUE; + } + } + + /* Not in a function. Give up. */ + return FALSE; + } + + + dest->file = &infix_files[n->filenum]; + dest->line_num = n->line; + dest->line_x = n->x; + dest->func_name = infix_routines[n->routine].name; + dest->func_num = n->routine; + dest->thisPC = n->PC; + + return TRUE; +} + + +BOOL infix_decode_fileloc(infix_location *dest, const char *filename, + unsigned line_num) +{ + unsigned n; + if(!infix_linerefs) + return FALSE; + for(n = 0; n < infix_linerefscount; n++) { + if(infix_linerefs[n].line == line_num && + n_strcmp(infix_files[infix_linerefs[n].filenum].filename, filename) == 0) { + + dest->file = &infix_files[infix_linerefs[n].filenum]; + dest->line_num = infix_linerefs[n].line; + dest->line_x = infix_linerefs[n].x; + dest->func_name = infix_routines[infix_linerefs[n].routine].name; + dest->func_num = infix_linerefs[n].routine; + dest->thisPC = infix_linerefs[n].PC; + return TRUE; + } + } + dest->thisPC = 0; + return FALSE; +} + + +BOOL infix_decode_func_name(infix_location *dest, const char *file_name, + const char *func_name) +{ + unsigned n; + if(!infix_linerefs) + return FALSE; + for(n = 0; n < infix_linerefscount; n++) { + if(n_strcmp(infix_files[infix_linerefs[n].filenum].filename, file_name) == 0) { + if(!file_name || n_strcmp(infix_routines[infix_linerefs[n].filenum].name, + func_name) == 0) { + + dest->file = &infix_files[infix_linerefs[n].filenum]; + dest->line_num = infix_linerefs[n].line; + dest->line_x = infix_linerefs[n].x; + dest->func_name = infix_routines[infix_linerefs[n].routine].name; + dest->func_num = infix_linerefs[n].routine; + dest->thisPC = infix_linerefs[n].PC; + return TRUE; + } + } + } + return FALSE; +} + + +void infix_gprint_loc(int frame, offset thisPC) +{ + infix_location boo; + offset loc; + BOOL found_frame; + unsigned numlocals; + unsigned n; + + if(!thisPC) { + loc = frame_get_PC(frame); + numlocals = stack_get_numlocals(frame); + } else { + loc = thisPC; + numlocals = 0; + } + + found_frame = infix_decode_PC(&boo, loc); + + infix_print_offset(loc); + + if(found_frame) { + infix_print_string(" in "); + infix_print_string(boo.func_name); + } + + if(!thisPC) { + infix_print_string(" ("); + + for(n = 0; n < numlocals; n++) { + const char *name; + if(n) + infix_print_string(", "); + if(found_frame) { + infix_print_string(infix_routines[boo.func_num].localnames[n]); + infix_print_char('='); + } + infix_print_znumber(frame_get_var(frame, n + 1)); + name = debug_decode_number(frame_get_var(frame, n + 1)); + if(name) { + infix_print_char(' '); + infix_print_string(name); + } + } + + infix_print_string(")"); + } + + if(found_frame) { + infix_print_string(" at "); + if(boo.file->filename) + infix_print_string(boo.file->filename); + else + infix_print_string(""); + infix_print_char(':'); + infix_print_number(boo.line_num); + } + + infix_print_char('\n'); + + if(found_frame && !thisPC) + infix_file_print_line(boo.file, boo.line_num); +} + + +void infix_list_files(void) +{ + unsigned i; + for(i = 0; i < infix_filescount; i++) { + if(i) + infix_print_string(", "); + infix_print_string(infix_files[i].filename); + } +} + +#else + +BOOL init_infix(strid_t unused) +{ + n_show_error(E_DEBUG, "debugging code not compiled in", 0); + return FALSE; +} + + +#endif +