/* txd.c V7/3 * * Z code disassembler for Infocom game files * * Requires txio.c, getopt.c, showverb.c and tx.h. * * Works for all V1, V2, V3, V4, V5, V6, V7 and V8 games. * * Usage: txd story-file-name * * Mark Howell 25 August 1992 howell_ma@movies.enet.dec.com * * History: * Merge separate disassemblers for each type into one program * Fix logic error in low routine scan * Force PC past start PC in middle routine scan * Update opcodes * Add pre-action and action verb names to routines * Add print mode descriptions * Wrap long lines of text * Cleanup for 16 bit machines * Change JGE and JLE to JG and JL * Add support for V1 and V2 games * Fix bug in printing of last string * Add symbolic names for routines and labels * Add verb syntax * Improve verb formatting * Add command line options * Fix check for low address * Add a switch to turn off grammar * Add support for V6 games * Make start of code for low scan the end of dictionary data * Generate Inform style syntax as an option * Add dump style and width option * Fix lint warnings * Fix inter-routine backward jumps * Update operand names * Add support for V7 and V8 games * Limit cache size to MAX_CACHE pages * Improve translation of constants to symbols * Distinguish between pre-actions and Inform parsing routines * Introduce indirect operands, eg. load [sp] sp * Fix object 0 problem * Add support for European characters (codes up to 223) * Add support for Inform 6 (helped by Matthew T. Russotto) * Add support for GV2 (MTR) * Add support for Infocom V6 games * Fix dependencies on sizeof(int) == 2 (mostly cosmetic) NOT DONE * Add -S dump-strings at address option * Remove GV2A support * Add unicode disassembly support * Add Inform and user symbol table support */ #include "tx.h" #define MAX_PCS 100 #define ROUND_CODE(address) ((address + (code_scaler - 1)) & ~(code_scaler - 1))#define ROUND_DATA(address) ((address + (story_scaler - 1)) & ~(story_scaler - 1)) #ifndef HAS_GETOPT#ifdef __STDC__extern int getopt (int, char *[], const char *);#elseextern int getopt ();#endif#endif #ifdef __STDC__static void process_story (const char *);static void decode_program (void);static int decode_routine (void);static int decode_code (void);static int decode_opcode (void);static int decode_operands (const char *, int, int, int, int, int, int);static int decode_parameters (int *);static int decode_parameter (int, int);static int decode_extra (void);static void decode_strings (unsigned long);static void scan_strings (unsigned long);static int lookup_string (unsigned long);static void lookup_verb (unsigned long);static void setup_dictionary (void);static int in_dictionary (unsigned long);static void add_label (unsigned long);static void add_routine (unsigned long);static int lookup_label (unsigned long, int);static int lookup_routine (unsigned long, int);static void renumber_cref (cref_item_t *);static void free_cref (cref_item_t *);static int print_object_desc (unsigned int);static void print_text (unsigned long *);static void print_integer (unsigned int, int);static void dump_data (unsigned long, unsigned long);static void dump_opcode (unsigned long, int, int, int *, int);static void dump_operand (unsigned long *, int, int, int *, int *);static void print_variable (int);#elsestatic void process_story ();static void decode_program ();static int decode_routine ();static int decode_code ();static int decode_opcode ();static int decode_operands ();static int decode_parameters ();static int decode_parameter ();static int decode_extra ();static void decode_strings ();static void scan_strings ();static int lookup_string ();static void lookup_verb ();static void setup_dictionary ();static int in_dictionary ();static void add_label ();static void add_routine ();static int lookup_label ();static int lookup_routine ();static void renumber_cref ();static void free_cref ();static int print_object_desc ();static void print_text ();static void print_integer ();static void dump_data ();static void dump_opcode ();static void dump_operand ();static void print_variable ();#endif static unsigned long pctable[MAX_PCS];static int pcindex = 0; static unsigned long start_data_pc, end_data_pc; static decode_t decode;static opcode_t opcode; static cref_item_t *strings_base = NULL;static cref_item_t *routines_base = NULL;static cref_item_t *current_routine = NULL; static int locals_count = 0;static unsigned long start_of_routine = 0; static unsigned int verb_count = 0;static unsigned int action_count = 0;static unsigned int parse_count = 0;static unsigned int parser_type = 0;static unsigned int prep_type = 0;static unsigned long verb_table_base = 0;static unsigned long verb_data_base = 0;static unsigned long action_table_base = 0;static unsigned long preact_table_base = 0;static unsigned long prep_table_base = 0;static unsigned long prep_table_end = 0; static const int verb_sizes[4] = { 2, 4, 7, 7 }; static unsigned long dict_start = 0;static unsigned long dict_end = 0;static unsigned long word_size = 0;static unsigned long word_count = 0; static unsigned long code_base = 0; static unsigned int obj_count = 0;static unsigned long obj_table_base = 0, obj_table_end = 0, obj_data_base = 0, obj_data_end = 0;static unsigned short inform_version = 0;static unsigned long class_numbers_base = 0, class_numbers_end = 0;static unsigned long property_names_base = 0, property_names_end = 0;static unsigned long attr_names_base = 0, attr_names_end = 0; #ifndef HAS_GETOPT/* getopt linkages */ extern int optind;extern const char *optarg;#endif static int option_labels = 1;static int option_grammar = 1;static int option_dump = 0;static int option_width = 79;static int option_symbols = 0;static unsigned long string_location = 0; #ifdef __STDC__int main (int argc, char *argv [])#elseint main (argc, argv)int argc;char *argv [];#endif{ int c, errflg = 0; /* Parse the options */ while ((c = getopt (argc, argv, "abdghnsw:S:u:")) != EOF) { switch (c) { case 'a': option_inform = 6; break; case 'd': option_dump = 1; break; case 'g': option_grammar = 0; break; case 'n': option_labels = 0; break; case 'w': option_width = atoi (optarg); break; case 'u': init_symbols(optarg); /*FALLTHRU*/ case 's': option_symbols = 1; break; case 'S':#ifdef HAS_STRTOUL string_location = strtoul(optarg, (char **)NULL, 0);#else string_location = atoi(optarg);#endif break; case 'h': case '?': default: errflg++; } } /* Display usage if unknown flag or no story file */ if (errflg || optind >= argc) { (void) fprintf (stderr, "usage: %s [options...] story-file [story-file...]\n\n", argv[0]); (void) fprintf (stderr, "TXD version 7/3 - disassemble Infocom story files. By Mark Howell\n"); (void) fprintf (stderr, "Works with V1 to V8 Infocom games.\n\n"); (void) fprintf (stderr, "\t-a generate alternate syntax used by Inform\n"); (void) fprintf (stderr, "\t-d dump hex of opcodes and data\n"); (void) fprintf (stderr, "\t-g turn off grammar for action routines\n"); (void) fprintf (stderr, "\t-n use addresses instead of labels\n"); (void) fprintf (stderr, "\t-w n display width (0 = no wrap)\n"); (void) fprintf (stderr, "\t-s Symbolic mode (Inform 6+ only)\n"); (void) fprintf (stderr, "\t-u <file> Read user symbol table, implies -s for Inform games\n"); (void) fprintf (stderr, "\t-S n Dump high strings only, starting at address n\n"); exit (EXIT_FAILURE); } /* Process any story files on the command line */ for (; optind < argc; optind++) process_story (argv[optind]); exit (EXIT_SUCCESS); return (0); }/* main */ #ifdef __STDC__static void process_story (const char *file_name)#elsestatic void process_story (file_name)const char *file_name;#endif{ tx_set_width (option_width); open_story (file_name); configure (V1, V8); load_cache (); setup_dictionary (); if (option_grammar) configure_parse_tables (&verb_count, &action_count, &parse_count, &parser_type, &prep_type, &verb_table_base, &verb_data_base, &action_table_base, &preact_table_base, &prep_table_base, &prep_table_end); if (option_symbols && (parser_type >= inform_gv1)) { configure_object_tables (&obj_count, &obj_table_base, &obj_table_end, &obj_data_base, &obj_data_end); configure_inform_tables(obj_data_end, &inform_version, &class_numbers_base, &class_numbers_end, &property_names_base, &property_names_end, &attr_names_base, &attr_names_end); } if (header.version != V6 && header.version != V7) { decode.pc = code_base = dict_end; decode.initial_pc = (unsigned long) header.start_pc - 1; } else { decode.pc = code_base = (unsigned long) header.routines_offset * story_scaler; decode.initial_pc = decode.pc + (unsigned long) header.start_pc * code_scaler; } tx_printf ("Resident data ends at %lx, program starts at %lx, file ends at %lx\n", (unsigned long) header.resident_size, (unsigned long) decode.initial_pc, (unsigned long) file_size); tx_printf ("\nStarting analysis pass at address %lx\n", (unsigned long) decode.pc); #if defined(TXD_DEBUG) decode.first_pass = 0; decode.low_address = decode.initial_pc; decode.high_address = file_size;#if 0 decode.low_address = atoi (getenv ("LOW_ADDRESS")); decode.high_address = atoi (getenv ("HIGH_ADDRESS"));#endif#else decode.first_pass = 1;#endif if (string_location) { decode_strings (string_location); exit(0); } decode_program (); scan_strings (decode.pc); #if !defined(TXD_DEBUG) tx_printf ("\nEnd of analysis pass, low address = %lx, high address = %lx\n", (unsigned long) decode.low_address, (unsigned long) decode.high_address); if (start_data_pc) tx_printf ("\n%ld bytes of data in code from %lx to %lx\n", (unsigned long) (end_data_pc - start_data_pc), (unsigned long) start_data_pc, (unsigned long) end_data_pc); if ((decode.low_address - code_base) >= story_scaler) { tx_printf ("\n%ld bytes of data before code from %lx to %lx\n", (unsigned long) (decode.low_address - code_base), (unsigned long) code_base, (unsigned long) decode.low_address); if (option_dump) { tx_printf ("\n[Start of data"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) code_base); tx_printf ("]\n\n"); dump_data (code_base, decode.low_address - 1); tx_printf ("\n[End of data"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) (decode.low_address - 1)); tx_printf ("]\n"); } } if (option_labels) renumber_cref (routines_base); decode.first_pass = 0; decode_program (); decode_strings (decode.pc);#endif close_story (); }/* process_story */ /* decode_program - Decode Z code in two passes */ #ifdef __STDC__static void decode_program (void)#elsestatic void decode_program ()#endif{ unsigned long pc, low_pc, high_pc, prev_low_pc, prev_high_pc; int i, flag, vars; if (decode.first_pass) { if (decode.pc < decode.initial_pc) { /* Scan for low routines */ decode.pc = ROUND_CODE (decode.pc); for (pc = decode.pc, flag = 0; pc < decode.initial_pc && flag == 0; pc += code_scaler) { for (vars = (char) read_data_byte (&pc); vars < 0 || vars > 15; vars = (char) read_data_byte (&pc)) pc = ROUND_CODE (pc); decode.pc = pc - 1; for (i = 0, flag = 1; i < 3 && flag; i++) { pcindex = 0; decode.pc = ROUND_CODE (decode.pc); if (decode_routine () != END_OF_ROUTINE || pcindex) flag = 0; } decode.pc = pc - 1; } if (flag && (unsigned int) header.version < V5) { pc = decode.pc; vars = (char) read_data_byte (&pc); low_pc = decode.pc; for (pc = pc + (vars * 2) - 1, flag = 0; pc >= low_pc && flag == 0; pc -= story_scaler) { decode.pc = pc; for (i = 0, flag = 1; i < 3 && flag; i++) { pcindex = 0; decode.pc = ROUND_CODE (decode.pc); if (decode_routine () != END_OF_ROUTINE || pcindex) flag = 0; } decode.pc = pc; } } if (flag == 0 || decode.pc > decode.initial_pc) decode.pc = decode.initial_pc; } /* Fill in middle routines */ decode.low_address = decode.pc; decode.high_address = decode.pc; start_data_pc = 0; end_data_pc = 0; do { if (option_labels) { free_cref (routines_base); routines_base = NULL; } prev_low_pc = decode.low_address; prev_high_pc = decode.high_address; flag = 0; pcindex = 0; low_pc = decode.low_address; high_pc = decode.high_address; pc = decode.pc = decode.low_address; while (decode.pc <= high_pc || decode.pc <= decode.initial_pc) { if (start_data_pc == decode.pc) decode.pc = end_data_pc; if (decode_routine () != END_OF_ROUTINE) { if (start_data_pc == 0) start_data_pc = decode.pc; flag = 1; end_data_pc = 0; pcindex = 0; pc = ROUND_CODE (pc); do { pc += code_scaler; vars = (char) read_data_byte (&pc); pc--; } while (vars < 0 || vars > 15); decode.pc = pc; } else { if (pc < decode.initial_pc && decode.pc > decode.initial_pc) { pc = decode.pc = decode.initial_pc; decode.low_address = low_pc; decode.high_address = high_pc; } else { if (start_data_pc && end_data_pc == 0) end_data_pc = pc; pc = ROUND_CODE (decode.pc); if (flag == 0) { low_pc = decode.low_address; high_pc = decode.high_address; } } } } decode.low_address = low_pc; decode.high_address = high_pc; } while (low_pc < prev_low_pc || high_pc > prev_high_pc); /* Scan for high routines */ pc = decode.pc; while (decode_routine () == END_OF_ROUTINE) { decode.high_address = pc; pc = decode.pc; } } else { tx_printf ("\n[Start of code"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) decode.low_address); tx_printf ("]\n"); for (decode.pc = decode.low_address; decode.pc <= decode.high_address; ) (void) decode_routine (); tx_printf ("\n[End of code"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) decode.pc); tx_printf ("]\n"); } }/* decode_program */ /* decode_routine - Decode a routine from start address to last instruction */ #ifdef __STDC__static int decode_routine (void)#elsestatic int decode_routine ()#endif{ unsigned long old_pc, old_start; cref_item_t *cref_item; int vars, status, i, locals; if (decode.first_pass) { cref_item = NULL; if (option_labels) cref_item = current_routine; old_start = start_of_routine; locals = locals_count; old_pc = decode.pc;Lines 1–500 of 2068. Load more
/* txd.c V7/3 * * Z code disassembler for Infocom game files * * Requires txio.c, getopt.c, showverb.c and tx.h. * * Works for all V1, V2, V3, V4, V5, V6, V7 and V8 games. * * Usage: txd story-file-name * * Mark Howell 25 August 1992 howell_ma@movies.enet.dec.com * * History: * Merge separate disassemblers for each type into one program * Fix logic error in low routine scan * Force PC past start PC in middle routine scan * Update opcodes * Add pre-action and action verb names to routines * Add print mode descriptions * Wrap long lines of text * Cleanup for 16 bit machines * Change JGE and JLE to JG and JL * Add support for V1 and V2 games * Fix bug in printing of last string * Add symbolic names for routines and labels * Add verb syntax * Improve verb formatting * Add command line options * Fix check for low address * Add a switch to turn off grammar * Add support for V6 games * Make start of code for low scan the end of dictionary data * Generate Inform style syntax as an option * Add dump style and width option * Fix lint warnings * Fix inter-routine backward jumps * Update operand names * Add support for V7 and V8 games * Limit cache size to MAX_CACHE pages * Improve translation of constants to symbols * Distinguish between pre-actions and Inform parsing routines * Introduce indirect operands, eg. load [sp] sp * Fix object 0 problem * Add support for European characters (codes up to 223) * Add support for Inform 6 (helped by Matthew T. Russotto) * Add support for GV2 (MTR) * Add support for Infocom V6 games * Fix dependencies on sizeof(int) == 2 (mostly cosmetic) NOT DONE * Add -S dump-strings at address option * Remove GV2A support * Add unicode disassembly support * Add Inform and user symbol table support */ #include "tx.h" #define MAX_PCS 100 #define ROUND_CODE(address) ((address + (code_scaler - 1)) & ~(code_scaler - 1)) #define ROUND_DATA(address) ((address + (story_scaler - 1)) & ~(story_scaler - 1)) #ifndef HAS_GETOPT #ifdef __STDC__ extern int getopt (int, char *[], const char *); #else extern int getopt (); #endif #endif #ifdef __STDC__ static void process_story (const char *); static void decode_program (void); static int decode_routine (void); static int decode_code (void); static int decode_opcode (void); static int decode_operands (const char *, int, int, int, int, int, int); static int decode_parameters (int *); static int decode_parameter (int, int); static int decode_extra (void); static void decode_strings (unsigned long); static void scan_strings (unsigned long); static int lookup_string (unsigned long); static void lookup_verb (unsigned long); static void setup_dictionary (void); static int in_dictionary (unsigned long); static void add_label (unsigned long); static void add_routine (unsigned long); static int lookup_label (unsigned long, int); static int lookup_routine (unsigned long, int); static void renumber_cref (cref_item_t *); static void free_cref (cref_item_t *); static int print_object_desc (unsigned int); static void print_text (unsigned long *); static void print_integer (unsigned int, int); static void dump_data (unsigned long, unsigned long); static void dump_opcode (unsigned long, int, int, int *, int); static void dump_operand (unsigned long *, int, int, int *, int *); static void print_variable (int); #else static void process_story (); static void decode_program (); static int decode_routine (); static int decode_code (); static int decode_opcode (); static int decode_operands (); static int decode_parameters (); static int decode_parameter (); static int decode_extra (); static void decode_strings (); static void scan_strings (); static int lookup_string (); static void lookup_verb (); static void setup_dictionary (); static int in_dictionary (); static void add_label (); static void add_routine (); static int lookup_label (); static int lookup_routine (); static void renumber_cref (); static void free_cref (); static int print_object_desc (); static void print_text (); static void print_integer (); static void dump_data (); static void dump_opcode (); static void dump_operand (); static void print_variable (); #endif static unsigned long pctable[MAX_PCS]; static int pcindex = 0; static unsigned long start_data_pc, end_data_pc; static decode_t decode; static opcode_t opcode; static cref_item_t *strings_base = NULL; static cref_item_t *routines_base = NULL; static cref_item_t *current_routine = NULL; static int locals_count = 0; static unsigned long start_of_routine = 0; static unsigned int verb_count = 0; static unsigned int action_count = 0; static unsigned int parse_count = 0; static unsigned int parser_type = 0; static unsigned int prep_type = 0; static unsigned long verb_table_base = 0; static unsigned long verb_data_base = 0; static unsigned long action_table_base = 0; static unsigned long preact_table_base = 0; static unsigned long prep_table_base = 0; static unsigned long prep_table_end = 0; static const int verb_sizes[4] = { 2, 4, 7, 7 }; static unsigned long dict_start = 0; static unsigned long dict_end = 0; static unsigned long word_size = 0; static unsigned long word_count = 0; static unsigned long code_base = 0; static unsigned int obj_count = 0; static unsigned long obj_table_base = 0, obj_table_end = 0, obj_data_base = 0, obj_data_end = 0; static unsigned short inform_version = 0; static unsigned long class_numbers_base = 0, class_numbers_end = 0; static unsigned long property_names_base = 0, property_names_end = 0; static unsigned long attr_names_base = 0, attr_names_end = 0; #ifndef HAS_GETOPT /* getopt linkages */ extern int optind; extern const char *optarg; #endif static int option_labels = 1; static int option_grammar = 1; static int option_dump = 0; static int option_width = 79; static int option_symbols = 0; static unsigned long string_location = 0; #ifdef __STDC__ int main (int argc, char *argv []) #else int main (argc, argv) int argc; char *argv []; #endif { int c, errflg = 0; /* Parse the options */ while ((c = getopt (argc, argv, "abdghnsw:S:u:")) != EOF) { switch (c) { case 'a': option_inform = 6; break; case 'd': option_dump = 1; break; case 'g': option_grammar = 0; break; case 'n': option_labels = 0; break; case 'w': option_width = atoi (optarg); break; case 'u': init_symbols(optarg); /*FALLTHRU*/ case 's': option_symbols = 1; break; case 'S': #ifdef HAS_STRTOUL string_location = strtoul(optarg, (char **)NULL, 0); #else string_location = atoi(optarg); #endif break; case 'h': case '?': default: errflg++; } } /* Display usage if unknown flag or no story file */ if (errflg || optind >= argc) { (void) fprintf (stderr, "usage: %s [options...] story-file [story-file...]\n\n", argv[0]); (void) fprintf (stderr, "TXD version 7/3 - disassemble Infocom story files. By Mark Howell\n"); (void) fprintf (stderr, "Works with V1 to V8 Infocom games.\n\n"); (void) fprintf (stderr, "\t-a generate alternate syntax used by Inform\n"); (void) fprintf (stderr, "\t-d dump hex of opcodes and data\n"); (void) fprintf (stderr, "\t-g turn off grammar for action routines\n"); (void) fprintf (stderr, "\t-n use addresses instead of labels\n"); (void) fprintf (stderr, "\t-w n display width (0 = no wrap)\n"); (void) fprintf (stderr, "\t-s Symbolic mode (Inform 6+ only)\n"); (void) fprintf (stderr, "\t-u <file> Read user symbol table, implies -s for Inform games\n"); (void) fprintf (stderr, "\t-S n Dump high strings only, starting at address n\n"); exit (EXIT_FAILURE); } /* Process any story files on the command line */ for (; optind < argc; optind++) process_story (argv[optind]); exit (EXIT_SUCCESS); return (0); }/* main */ #ifdef __STDC__ static void process_story (const char *file_name) #else static void process_story (file_name) const char *file_name; #endif { tx_set_width (option_width); open_story (file_name); configure (V1, V8); load_cache (); setup_dictionary (); if (option_grammar) configure_parse_tables (&verb_count, &action_count, &parse_count, &parser_type, &prep_type, &verb_table_base, &verb_data_base, &action_table_base, &preact_table_base, &prep_table_base, &prep_table_end); if (option_symbols && (parser_type >= inform_gv1)) { configure_object_tables (&obj_count, &obj_table_base, &obj_table_end, &obj_data_base, &obj_data_end); configure_inform_tables(obj_data_end, &inform_version, &class_numbers_base, &class_numbers_end, &property_names_base, &property_names_end, &attr_names_base, &attr_names_end); } if (header.version != V6 && header.version != V7) { decode.pc = code_base = dict_end; decode.initial_pc = (unsigned long) header.start_pc - 1; } else { decode.pc = code_base = (unsigned long) header.routines_offset * story_scaler; decode.initial_pc = decode.pc + (unsigned long) header.start_pc * code_scaler; } tx_printf ("Resident data ends at %lx, program starts at %lx, file ends at %lx\n", (unsigned long) header.resident_size, (unsigned long) decode.initial_pc, (unsigned long) file_size); tx_printf ("\nStarting analysis pass at address %lx\n", (unsigned long) decode.pc); #if defined(TXD_DEBUG) decode.first_pass = 0; decode.low_address = decode.initial_pc; decode.high_address = file_size; #if 0 decode.low_address = atoi (getenv ("LOW_ADDRESS")); decode.high_address = atoi (getenv ("HIGH_ADDRESS")); #endif #else decode.first_pass = 1; #endif if (string_location) { decode_strings (string_location); exit(0); } decode_program (); scan_strings (decode.pc); #if !defined(TXD_DEBUG) tx_printf ("\nEnd of analysis pass, low address = %lx, high address = %lx\n", (unsigned long) decode.low_address, (unsigned long) decode.high_address); if (start_data_pc) tx_printf ("\n%ld bytes of data in code from %lx to %lx\n", (unsigned long) (end_data_pc - start_data_pc), (unsigned long) start_data_pc, (unsigned long) end_data_pc); if ((decode.low_address - code_base) >= story_scaler) { tx_printf ("\n%ld bytes of data before code from %lx to %lx\n", (unsigned long) (decode.low_address - code_base), (unsigned long) code_base, (unsigned long) decode.low_address); if (option_dump) { tx_printf ("\n[Start of data"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) code_base); tx_printf ("]\n\n"); dump_data (code_base, decode.low_address - 1); tx_printf ("\n[End of data"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) (decode.low_address - 1)); tx_printf ("]\n"); } } if (option_labels) renumber_cref (routines_base); decode.first_pass = 0; decode_program (); decode_strings (decode.pc); #endif close_story (); }/* process_story */ /* decode_program - Decode Z code in two passes */ #ifdef __STDC__ static void decode_program (void) #else static void decode_program () #endif { unsigned long pc, low_pc, high_pc, prev_low_pc, prev_high_pc; int i, flag, vars; if (decode.first_pass) { if (decode.pc < decode.initial_pc) { /* Scan for low routines */ decode.pc = ROUND_CODE (decode.pc); for (pc = decode.pc, flag = 0; pc < decode.initial_pc && flag == 0; pc += code_scaler) { for (vars = (char) read_data_byte (&pc); vars < 0 || vars > 15; vars = (char) read_data_byte (&pc)) pc = ROUND_CODE (pc); decode.pc = pc - 1; for (i = 0, flag = 1; i < 3 && flag; i++) { pcindex = 0; decode.pc = ROUND_CODE (decode.pc); if (decode_routine () != END_OF_ROUTINE || pcindex) flag = 0; } decode.pc = pc - 1; } if (flag && (unsigned int) header.version < V5) { pc = decode.pc; vars = (char) read_data_byte (&pc); low_pc = decode.pc; for (pc = pc + (vars * 2) - 1, flag = 0; pc >= low_pc && flag == 0; pc -= story_scaler) { decode.pc = pc; for (i = 0, flag = 1; i < 3 && flag; i++) { pcindex = 0; decode.pc = ROUND_CODE (decode.pc); if (decode_routine () != END_OF_ROUTINE || pcindex) flag = 0; } decode.pc = pc; } } if (flag == 0 || decode.pc > decode.initial_pc) decode.pc = decode.initial_pc; } /* Fill in middle routines */ decode.low_address = decode.pc; decode.high_address = decode.pc; start_data_pc = 0; end_data_pc = 0; do { if (option_labels) { free_cref (routines_base); routines_base = NULL; } prev_low_pc = decode.low_address; prev_high_pc = decode.high_address; flag = 0; pcindex = 0; low_pc = decode.low_address; high_pc = decode.high_address; pc = decode.pc = decode.low_address; while (decode.pc <= high_pc || decode.pc <= decode.initial_pc) { if (start_data_pc == decode.pc) decode.pc = end_data_pc; if (decode_routine () != END_OF_ROUTINE) { if (start_data_pc == 0) start_data_pc = decode.pc; flag = 1; end_data_pc = 0; pcindex = 0; pc = ROUND_CODE (pc); do { pc += code_scaler; vars = (char) read_data_byte (&pc); pc--; } while (vars < 0 || vars > 15); decode.pc = pc; } else { if (pc < decode.initial_pc && decode.pc > decode.initial_pc) { pc = decode.pc = decode.initial_pc; decode.low_address = low_pc; decode.high_address = high_pc; } else { if (start_data_pc && end_data_pc == 0) end_data_pc = pc; pc = ROUND_CODE (decode.pc); if (flag == 0) { low_pc = decode.low_address; high_pc = decode.high_address; } } } } decode.low_address = low_pc; decode.high_address = high_pc; } while (low_pc < prev_low_pc || high_pc > prev_high_pc); /* Scan for high routines */ pc = decode.pc; while (decode_routine () == END_OF_ROUTINE) { decode.high_address = pc; pc = decode.pc; } } else { tx_printf ("\n[Start of code"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) decode.low_address); tx_printf ("]\n"); for (decode.pc = decode.low_address; decode.pc <= decode.high_address; ) (void) decode_routine (); tx_printf ("\n[End of code"); if (option_labels == 0) tx_printf (" at %lx", (unsigned long) decode.pc); tx_printf ("]\n"); } }/* decode_program */ /* decode_routine - Decode a routine from start address to last instruction */ #ifdef __STDC__ static int decode_routine (void) #else static int decode_routine () #endif { unsigned long old_pc, old_start; cref_item_t *cref_item; int vars, status, i, locals; if (decode.first_pass) { cref_item = NULL; if (option_labels) cref_item = current_routine; old_start = start_of_routine; locals = locals_count; old_pc = decode.pc;