1 /* Nitfol - z-machine interpreter using Glk for output.
2 Copyright (C) 1999 Evin Robertson
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
18 The author can be reached at nitfol@deja.com
31 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;
33 typedef struct z_typed z_typed;
35 zword v; /* The value stored */
38 zword o, p; /* location of value (if t is appropriate) */
46 glui32 *line_locations;
53 const char *func_name;
68 #define FAKE_ACTION_DBR 7
71 #define LINEREF_DBR 10
72 #define ROUTINE_DBR 11
75 #define ROUTINE_END_DBR 14
78 static unsigned record_info[][9] = {
79 { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* eof_dbr */
80 { 1, 0x8000, 0x8000, 0, 0, 0, 0, 0, 0 }, /* file_dbr */
81 { 0x8000, 1, 2, 1, 1, 2, 1, 0, 0 }, /* class_dbr */
82 { 2, 0x8000, 1, 2, 1, 1, 2, 1, 0 }, /* object_dbr */
83 { 1, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* global_dbr */
84 { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* attr_dbr */
85 { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* prop_dbr */
86 { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* fake_action_dbr */
87 { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* action_dbr */
88 { 64, 0, 0, 0, 0, 0, 0, 0, 0 }, /* header_dbr */
89 { 2, 2, 0, 0, 0, 0, 0, 0, 0 }, /* lineref_dbr */
90 { 2, 1, 2, 1, 3, 0x8000, 0, 0, 0 }, /* routine_dbr */
91 { 2, 0x8000, 0, 0, 0, 0, 0, 0, 0 }, /* array_dbr */
92 { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* map_dbr */
93 { 2, 1, 2, 1, 3, 0, 0, 0, 0 } /* routine_end_dbr */
97 offset infix_get_routine_PC(zword routine)
99 offset destPC = UNPACKR(routine);
100 unsigned num_local = HIBYTE(destPC);
103 destPC += num_local * ZWORD_SIZE;
108 static infix_file infix_load_file_info(const char *filename)
112 int lines_allocated = 0;
114 r.filename = filename;
116 r.line_locations = NULL;
118 r.stream = n_file_name(fileusage_Data | fileusage_TextMode,
119 filemode_Read, filename);
124 lines_allocated = 256;
125 r.line_locations = (glui32 *) n_malloc(lines_allocated * sizeof(*r.line_locations));
126 r.line_locations[r.num_lines] = 0;
129 while((c = glk_get_char_stream(r.stream)) != GLK_EOF) {
131 if(r.num_lines >= lines_allocated) {
132 glui32 *new_locations;
134 lines_allocated *= 2;
135 new_locations = (glui32 *) n_realloc(r.line_locations,
136 lines_allocated * sizeof(*r.line_locations));
137 r.line_locations = new_locations;
139 r.line_locations[r.num_lines] = glk_stream_get_position(r.stream);
147 static void infix_unload_file_info(infix_file *f)
149 if(f->line_locations)
150 n_free(f->line_locations);
151 f->line_locations = 0;
156 void infix_file_print_line(infix_file *f, int line)
160 if(!(f && f->stream && f->num_lines && f->line_locations))
165 if(line > f->num_lines)
168 if(fullname) { /* Running as a subprocess under emacs */
169 infix_print_char(26);
170 infix_print_char(26);
171 infix_print_string(f->filename);
172 infix_print_char(':');
173 infix_print_number(line);
174 infix_print_char(':');
175 infix_print_number(f->line_locations[line-1] + 0);
176 infix_print_string(":beg:0x00000000");
178 infix_print_number(line);
179 infix_print_char('\t');
181 glk_stream_set_position(f->stream, f->line_locations[line-1], seekmode_Start);
183 while((c = glk_get_char_stream(f->stream)) != GLK_EOF) {
190 infix_print_char(10);
194 static unsigned local_names_info[] = { 0x8000, 0 };
195 static unsigned sequence_point_info[] ={ 1, 2, 1, 2, 0 };
196 static unsigned map_info[] = { 0x8000, 3, 0 };
198 static glui32 infix_strlen;
199 static char *infix_stringdata;
201 static glui32 infix_add_string(strid_t infix)
204 glui32 return_offset = infix_strlen;
206 while((ch = glk_get_char_stream(infix)) != 0) {
208 infix_stringdata[infix_strlen] = ch;
213 infix_stringdata[infix_strlen] = 0;
216 return return_offset;
219 static void infix_add_stringchar(int c)
221 /* Really inefficient to call realloc for every character, but oh well... */
222 infix_stringdata = n_realloc(infix_stringdata, infix_strlen+1);
223 infix_stringdata[infix_strlen++] = c;
226 static glui32 infix_add_zstring(zword paddr)
229 glui32 return_offset = infix_strlen;
230 offset addr = UNPACKS(paddr);
231 if(addr+2 < total_size) {
232 decodezscii(addr, infix_add_stringchar);
233 infix_add_stringchar(0);
234 return return_offset;
241 static infix_file *infix_files;
242 static unsigned infix_filescount;
244 static char **infix_objects;
245 static unsigned infix_objectscount;
247 static char **infix_globals;
248 static unsigned infix_globalscount;
255 static infix_arrayref *infix_arrays;
256 static unsigned infix_arrayscount;
258 static char **infix_attrs;
259 static unsigned infix_attrscount;
261 static char **infix_props;
262 static unsigned infix_propscount;
270 const char *localnames[15];
276 static routineref *infix_routines;
277 static unsigned infix_routinescount;
287 static infix_sequence *infix_linerefs;
288 static unsigned infix_linerefscount;
291 static offset code_start = 0;
292 static offset string_start = 0;
294 static int infix_compare_linerefs(const void *a, const void *b)
296 const infix_sequence *A = (const infix_sequence *) a;
297 const infix_sequence *B = (const infix_sequence *) b;
303 if(A->line < B->line)
305 if(A->line > B->line)
310 static BOOL infix_load_records(strid_t infix)
315 glui32 record_type = glk_get_char_stream(infix);
316 glui32 record_data[64];
318 if(record_type > MAX_DBR) {
319 glk_stream_close(infix, NULL);
320 n_show_error(E_DEBUG, "unknown record type", record_type);
324 fillstruct(infix, record_info[record_type], record_data, infix_add_string);
326 switch(record_type) {
328 if(infix_linerefs && infix_routines && code_start) {
329 for(n = 0; n < infix_routinescount; n++) {
330 infix_routines[n].start_PC += code_start;
331 infix_routines[n].end_PC += code_start;
334 n_qsort(infix_linerefs, infix_linerefscount, sizeof(*infix_linerefs),
335 infix_compare_linerefs);
337 for(n = 0; n < infix_linerefscount; n++)
338 infix_linerefs[n].PC += code_start;
343 infix_files[record_data[0]] = infix_load_file_info(infix_stringdata + record_data[2]);
345 if(record_data[0] >= infix_filescount)
346 infix_filescount = record_data[0] + 1;
352 infix_objects[record_data[0]] = infix_stringdata + record_data[1];
354 if(record_data[0] >= infix_objectscount)
355 infix_objectscount = record_data[0] + 1;
359 infix_globals[record_data[0]] = infix_stringdata + record_data[1];
361 if(record_data[0] >= infix_globalscount)
362 infix_globalscount = record_data[0] + 1;
371 infix_attrs[record_data[0]] = infix_stringdata + record_data[1];
373 if(record_data[0] >= infix_attrscount)
374 infix_attrscount = record_data[0] + 1;
378 infix_props[record_data[0]] = infix_stringdata + record_data[1];
380 if(record_data[0] >= infix_propscount)
381 infix_propscount = record_data[0] + 1;
383 case FAKE_ACTION_DBR:
388 glk_stream_set_position(current_zfile, 0, seekmode_Start);
389 for(n = 0; n < 64; n++) {
390 unsigned c = (unsigned char) glk_get_char_stream(current_zfile);
391 if(record_data[n] != c) {
392 n_show_error(E_DEBUG, "infix file does not match current file", n);
399 infix_routines[record_data[0]].filenum = record_data[1];
400 infix_routines[record_data[0]].startline = record_data[2];
401 infix_routines[record_data[0]].start_x = record_data[3];
402 infix_routines[record_data[0]].start_PC = record_data[4];
403 infix_routines[record_data[0]].name = infix_stringdata +
408 for(n = 0; n < 15; n++)
409 infix_routines[record_data[0]].localnames[n] = NULL;
411 for(n = 0; n < 16; n++) {
412 if(!glk_get_char_stream(infix))
416 glk_stream_set_position(infix, -1, seekmode_Current);
417 fillstruct(infix, local_names_info, more_data, infix_add_string);
419 infix_routines[record_data[0]].localnames[n] = infix_stringdata +
423 if(record_data[0] >= infix_routinescount)
424 infix_routinescount = record_data[0] + 1;
427 for(n = 0; n < record_data[1]; n++) {
428 fillstruct(infix, sequence_point_info, more_data, NULL);
430 infix_linerefs[infix_linerefscount].routine = record_data[0];
431 infix_linerefs[infix_linerefscount].filenum = more_data[0];
432 infix_linerefs[infix_linerefscount].line = more_data[1];
433 infix_linerefs[infix_linerefscount].x = more_data[2];
434 infix_linerefs[infix_linerefscount].PC = more_data[3] +
435 infix_routines[record_data[0]].start_PC;
437 infix_linerefscount++;
440 case ROUTINE_END_DBR:
442 infix_routines[record_data[0]].end_line = record_data[2];
443 infix_routines[record_data[0]].end_x = record_data[3];
444 infix_routines[record_data[0]].end_PC = record_data[4];
446 if(record_data[0] >= infix_routinescount)
447 infix_routinescount = record_data[0] + 1;
451 if(!glk_get_char_stream(infix))
453 glk_stream_set_position(infix, -1, seekmode_Current);
454 fillstruct(infix, map_info, more_data, infix_add_string);
455 if(infix_stringdata) {
456 if(n_strcmp(infix_stringdata + more_data[0], "code area") == 0)
457 code_start = more_data[1];
458 if(n_strcmp(infix_stringdata + more_data[0], "strings area") == 0)
459 string_start = more_data[1];
468 BOOL init_infix(strid_t infix)
470 if(!infix && (infix_props || infix_attrs))
475 /* Inform 6.10+ has run-time symbols (techman 9.6) */
476 if(!infix && z_memory && prop_table_end
477 && (z_memory[HD_INFORMVER] == '6' && z_memory[HD_INFORMVER + 2] >= '1')) {
480 glui32 *prop_names, *attr_names;
482 /* Assume no strings before end of property table */
483 string_start = prop_table_end;
485 for(addr = prop_table_end+1; LOWORD(addr); addr+=ZWORD_SIZE)
489 infix_propscount = LOWORD(addr) - 1; addr+=ZWORD_SIZE;
490 prop_names = (glui32 *) n_calloc(sizeof(*prop_names), infix_propscount+1);
491 for(i = 1; i <= infix_propscount; i++) {
492 prop_names[i] = infix_add_zstring(LOWORD(addr));
496 infix_attrscount = 48;
497 attr_names = (glui32 *) n_calloc(sizeof(*prop_names), infix_propscount);
498 for(i = 0; i <= 47; i++) {
499 attr_names[i] = infix_add_zstring(LOWORD(addr));
503 infix_props = (char **) n_calloc(sizeof(*infix_props), infix_propscount+1);
504 infix_attrs = (char **) n_calloc(sizeof(*infix_attrs), infix_attrscount);
505 for(i = 1; i <= infix_propscount; i++) {
506 if(prop_names[i] != 0xffffffffL)
507 infix_props[i] = infix_stringdata + prop_names[i];
509 for(i = 0; i <= 47; i++) {
510 if(attr_names[i] != 0xffffffffL)
511 infix_attrs[i] = infix_stringdata + attr_names[i];
523 glk_stream_set_position(infix, 0, seekmode_Start);
524 if((glk_get_char_stream(infix) != 0xDE) ||
525 (glk_get_char_stream(infix) != 0xBF) ||
526 (glk_get_char_stream(infix) != 0x00) ||
527 (glk_get_char_stream(infix) != 0x00)) {
528 glk_stream_close(infix, NULL);
529 n_show_error(E_DEBUG, "unknown version or not an infix file", 0);
533 /* ignore inform version number */
534 glk_stream_set_position(infix, 6, seekmode_Start);
536 /* Calculate space requirements */
537 infix_load_records(infix);
539 /* Malloc required memory */
540 infix_stringdata = (char *) n_calloc(sizeof(*infix_stringdata),
543 infix_files = (infix_file *) n_calloc(sizeof(*infix_files),
545 infix_filescount = 0;
546 infix_objects = (char **) n_calloc(sizeof(*infix_objects),
548 infix_objectscount = 0;
549 infix_globals = (char **) n_calloc(sizeof(*infix_globals),
551 infix_globalscount = 0;
552 infix_attrs = (char **) n_calloc(sizeof(*infix_attrs),
554 infix_attrscount = 0;
555 infix_props = (char **) n_calloc(sizeof(*infix_props),
557 infix_propscount = 0;
558 infix_routines = (routineref *) n_calloc(sizeof(*infix_routines),
559 infix_routinescount);
560 infix_routinescount= 0;
561 infix_linerefs = (infix_sequence *) n_calloc(sizeof(*infix_linerefs),
562 infix_linerefscount);
563 infix_linerefscount= 0;
565 glk_stream_set_position(infix, 6, seekmode_Start);
566 infix_load_records(infix);
572 void kill_infix(void)
576 n_free(infix_stringdata);
577 infix_stringdata = 0;
581 for(i = 0; i < infix_filescount; i++)
582 infix_unload_file_info(&infix_files[i]);
586 infix_filescount = 0;
588 n_free(infix_objects);
590 infix_objectscount = 0;
592 n_free(infix_globals);
594 infix_globalscount = 0;
598 infix_attrscount = 0;
602 infix_propscount = 0;
604 n_free(infix_routines);
606 infix_routinescount = 0;
608 n_free(infix_linerefs);
610 infix_linerefscount = 0;
614 void infix_print_znumber(zword blah)
616 set_glk_stream_current();
617 g_print_znumber(blah);
620 void infix_print_offset(zword blah)
622 set_glk_stream_current();
623 g_print_number(blah);
626 void infix_print_number(zword blah)
628 set_glk_stream_current();
629 g_print_number(blah);
632 void infix_print_char(int blah)
639 set_glk_stream_current();
640 /* We don't do a style-set because of bugs in zarf Glks */
641 glk_put_char((unsigned char) blah);
645 void infix_print_fixed_char(int blah)
652 set_glk_stream_current();
653 glk_set_style(style_Preformatted);
654 glk_put_char((unsigned char) blah);
655 glk_set_style(style_Normal);
659 void infix_print_string(const char *blah)
662 infix_print_char(*blah++);
665 void infix_print_fixed_string(const char *blah)
668 infix_print_fixed_char(*blah++);
671 void infix_get_string(char *dest, int maxlen)
674 fgets(dest, maxlen, stdin);
678 len = z_read(0, dest, maxlen - 1, 0, 0, 0, 0, &t);
683 void infix_get_val(z_typed *val)
686 case Z_LOCAL: val->v = frame_get_var(val->o, val->p + 1); break;
687 case Z_GLOBAL: val->v = get_var(val->o + 0x10); break;
688 case Z_BYTEARRAY: val->v = LOBYTE(val->o + val->p); break;
689 case Z_WORDARRAY: val->v = LOWORD(val->o + ZWORD_SIZE * val->p); break;
690 case Z_OBJPROP: val->v = infix_get_prop(val->o, val->p); break;
695 void infix_assign(z_typed *dest, zword val)
698 case Z_LOCAL: frame_set_var(dest->o, dest->p + 1, val); break;
699 case Z_BYTEARRAY: LOBYTEwrite(dest->o + dest->p, val); break;
700 case Z_WORDARRAY: LOWORDwrite(dest->o + ZWORD_SIZE * dest->p, val); break;
701 case Z_OBJPROP: infix_put_prop(dest->o, dest->p, val); break;
702 default: infix_print_string("assigning to non-lvalue\n"); break;
707 void infix_display(z_typed val)
714 infix_print_znumber(val.v);
719 infix_print_string("true");
721 infix_print_string("false");
728 name = debug_decode_number(val.v);
731 infix_print_char(' ');
732 infix_print_char('(');
733 infix_print_string(name);
734 infix_print_char(')');
739 infix_object_display(val.v);
743 infix_print_char('\"');
744 decodezscii(UNPACKS(val.v), infix_print_char);
745 infix_print_char('\"');
752 for(i = 0; i < infix_routinescount; i++) {
753 if(infix_routines[i].start_PC == UNPACKR(val.v)) {
755 infix_print_char('{');
756 for(n = 0; n < 15; n++) {
757 if(infix_routines[i].localnames[n]) {
758 infix_print_string(infix_routines[i].localnames[n]);
759 if(n < 14 && infix_routines[i].localnames[n+1])
760 infix_print_string(", ");
763 infix_print_string("} ");
765 infix_print_offset(infix_routines[i].start_PC);
766 infix_print_string(" <");
767 infix_print_string(infix_routines[i].name);
768 infix_print_char('>');
773 infix_print_char('\n');
777 int infix_find_file(infix_file **dest, const char *name)
781 for(n = 0; n < infix_filescount; n++) {
782 if(infix_files[n].filename) {
783 unsigned len = n_strlen(infix_files[n].filename);
785 n_strncasecmp(infix_files[n].filename, name, len) == 0 &&
786 (name[len] == ' ' || name[len] == ':' || name[len] == 0)) {
787 *dest = &infix_files[n];
797 BOOL infix_find_symbol(z_typed *val, const char *name, int len)
801 infix_location location;
802 if(infix_decode_PC(&location, frame_get_PC(infix_selected_frame))) {
803 for(n = 0; n < 15; n++) {
804 if(n_strmatch(infix_routines[location.func_num].localnames[n], name, len)) {
806 val->o = infix_selected_frame;
815 for(n = 0; n < infix_objectscount; n++) {
816 if(n_strmatch(infix_objects[n], name, len)) {
823 for(n = 0; n < infix_globalscount; n++) {
824 if(n_strmatch(infix_globals[n], name, len)) {
825 val->t = Z_WORDARRAY;
826 val->o = z_globaltable;
833 for(n = 0; n < infix_arrayscount; n++) {
834 if(n_strmatch(infix_arrays[n].name, name, len)) {
841 for(n = 0; n < infix_attrscount; n++) {
842 if(n_strmatch(infix_attrs[n], name, len)) {
849 for(n = 0; n < infix_propscount; n++) {
850 if(n_strmatch(infix_props[n], name, len)) {
857 for(n = 0; n < infix_routinescount; n++) {
858 if(n_strmatch(infix_routines[n].name, name, len)) {
860 val->v = PACKR(infix_routines[n].start_PC);
867 static char infix_temp_string_buffer[45];
868 static unsigned infix_temp_strlen;
870 static void infix_temp_string_build(int ch)
872 infix_temp_string_buffer[infix_temp_strlen] = ch;
874 if(infix_temp_strlen > 40) {
875 infix_temp_strlen = 43;
876 infix_temp_string_buffer[40] = '.';
877 infix_temp_string_buffer[41] = '.';
878 infix_temp_string_buffer[42] = '.';
883 const char *infix_get_name(z_typed val)
886 if(!infix_stringdata)
890 if(val.o < infix_globalscount)
891 return infix_globals[val.o];
894 if(val.v < infix_objectscount)
895 return infix_objects[val.v];
898 if(val.v < infix_attrscount)
899 return infix_attrs[val.v];
902 if(val.v < infix_propscount)
903 return infix_props[val.v];
906 for(i = 0; i < infix_routinescount; i++) {
907 if(infix_routines[i].start_PC == UNPACKR(val.v))
908 return infix_routines[i].name;
912 if(UNPACKS(val.v) < string_start)
914 if(string_start < code_start && UNPACKS(val.v) >= code_start)
916 if(UNPACKS(val.v) >= total_size)
919 /* Assume every string except the first is preceded by zeroed padding until
920 an end-of-string marker */
921 if(UNPACKS(val.v) != string_start) {
922 offset addr = UNPACKS(val.v) - 2;
924 while((s = HIWORD(addr)) == 0)
930 infix_temp_string_buffer[0] = '\"';
931 infix_temp_strlen = 1;
932 testing_string = TRUE; string_bad = FALSE;
933 decodezscii(UNPACKS(val.v), infix_temp_string_build);
934 testing_string = FALSE;
937 infix_temp_string_buffer[infix_temp_strlen] = '\"';
938 infix_temp_string_buffer[infix_temp_strlen + 1] = 0;
939 return infix_temp_string_buffer;
941 if(val.v < infix_arrayscount)
942 return infix_arrays[val.v].name;
951 /* We search through linerefs very often so use binary search for speed */
953 static infix_sequence *infix_search_linerefs(offset thisPC)
957 int bottom = infix_linerefscount-1;
958 int middle = (top + bottom) / 2;
964 middle = (top + bottom) / 2;
965 if(thisPC < infix_linerefs[middle].PC)
967 else if(thisPC > infix_linerefs[middle].PC)
971 } while(top <= bottom);
973 /* If the PC is in the middle of a line, we want to display that line. In
974 this case, PC will be greater than infix_linerefs[middle].PC, so just let
975 it go. Otherwise, we want to look at the previous lineref, so subtract
979 while(middle && thisPC < infix_linerefs[middle].PC)
983 /* Make sure PC is inside the function the lineref says it is; if so, then
986 n = infix_linerefs[middle].routine;
987 if(thisPC >= infix_routines[n].start_PC &&
988 thisPC <= infix_routines[n].end_PC)
989 return &infix_linerefs[middle];
995 BOOL infix_decode_PC(infix_location *dest, offset thisPC)
997 infix_sequence *n = infix_search_linerefs(thisPC);
999 if(!n) { /* No sequence point found - return a function */
1005 for(i = 0; i < infix_routinescount; i++) {
1006 if(thisPC >= infix_routines[i].start_PC &&
1007 thisPC <= infix_routines[i].end_PC) {
1009 routineref *r = &infix_routines[i];
1010 dest->file = &infix_files[r->filenum];
1011 dest->line_num = r->startline;
1012 dest->line_x = r->start_x;
1013 dest->func_name = r->name;
1015 dest->thisPC = r->start_PC;
1021 /* Not in a function. Give up. */
1026 dest->file = &infix_files[n->filenum];
1027 dest->line_num = n->line;
1028 dest->line_x = n->x;
1029 dest->func_name = infix_routines[n->routine].name;
1030 dest->func_num = n->routine;
1031 dest->thisPC = n->PC;
1037 BOOL infix_decode_fileloc(infix_location *dest, const char *filename,
1043 for(n = 0; n < infix_linerefscount; n++) {
1044 if(infix_linerefs[n].line == line_num &&
1045 n_strcmp(infix_files[infix_linerefs[n].filenum].filename, filename) == 0) {
1047 dest->file = &infix_files[infix_linerefs[n].filenum];
1048 dest->line_num = infix_linerefs[n].line;
1049 dest->line_x = infix_linerefs[n].x;
1050 dest->func_name = infix_routines[infix_linerefs[n].routine].name;
1051 dest->func_num = infix_linerefs[n].routine;
1052 dest->thisPC = infix_linerefs[n].PC;
1061 BOOL infix_decode_func_name(infix_location *dest, const char *file_name,
1062 const char *func_name)
1067 for(n = 0; n < infix_linerefscount; n++) {
1068 if(n_strcmp(infix_files[infix_linerefs[n].filenum].filename, file_name) == 0) {
1069 if(!file_name || n_strcmp(infix_routines[infix_linerefs[n].filenum].name,
1072 dest->file = &infix_files[infix_linerefs[n].filenum];
1073 dest->line_num = infix_linerefs[n].line;
1074 dest->line_x = infix_linerefs[n].x;
1075 dest->func_name = infix_routines[infix_linerefs[n].routine].name;
1076 dest->func_num = infix_linerefs[n].routine;
1077 dest->thisPC = infix_linerefs[n].PC;
1086 void infix_gprint_loc(int frame, offset thisPC)
1095 loc = frame_get_PC(frame);
1096 numlocals = stack_get_numlocals(frame);
1102 found_frame = infix_decode_PC(&boo, loc);
1104 infix_print_offset(loc);
1107 infix_print_string(" in ");
1108 infix_print_string(boo.func_name);
1112 infix_print_string(" (");
1114 for(n = 0; n < numlocals; n++) {
1117 infix_print_string(", ");
1119 infix_print_string(infix_routines[boo.func_num].localnames[n]);
1120 infix_print_char('=');
1122 infix_print_znumber(frame_get_var(frame, n + 1));
1123 name = debug_decode_number(frame_get_var(frame, n + 1));
1125 infix_print_char(' ');
1126 infix_print_string(name);
1130 infix_print_string(")");
1134 infix_print_string(" at ");
1135 if(boo.file->filename)
1136 infix_print_string(boo.file->filename);
1138 infix_print_string("<No file>");
1139 infix_print_char(':');
1140 infix_print_number(boo.line_num);
1143 infix_print_char('\n');
1145 if(found_frame && !thisPC)
1146 infix_file_print_line(boo.file, boo.line_num);
1150 void infix_list_files(void)
1153 for(i = 0; i < infix_filescount; i++) {
1155 infix_print_string(", ");
1156 infix_print_string(infix_files[i].filename);
1162 BOOL init_infix(strid_t unused)
1164 n_show_error(E_DEBUG, "debugging code not compiled in", 0);