#include #include #include #include #include #include #include "bas.h" int startlineno = 0; int endlineno = 32768; /* dump tokens for each line in a BASIC program. easier to read than a plain hex dump. */ void print_help(void) { fprintf(stderr, "Usage: %s [-v] [-s start-lineno] [-e end-lineno] \n", self); } unsigned short getlineno(char opt, const char *arg) { int lineno; char *e; lineno = (int)strtol(arg, &e, 10); if(*e) { fprintf(stderr, "%s: Invalid line number for -%c option: %s is not a number.\n", self, opt, arg); exit(1); } if(lineno < 0 || lineno > 32767) { fprintf(stderr, "%s: Invalid line number for -%c option: %d > 32767.\n", self, opt, lineno); exit(1); } return ((unsigned short)lineno); } void parse_args(int argc, char **argv) { int opt; while( (opt = getopt(argc, argv, "vs:e:l:")) != -1) { switch(opt) { case 'v': verbose = 1; break; case 's': startlineno = getlineno(opt, optarg); break; case 'e': endlineno = getlineno(opt, optarg); break; case 'l': startlineno = getlineno(opt, optarg); endlineno = startlineno; break; default: print_help(); exit(1); } } if(optind >= argc) die("No input file given (use - for stdin)."); else open_input(argv[optind]); } void print_atascii(unsigned char c) { if(c & 0x80) { putchar('|'); c &= 0x7f; } if(c < 32) { putchar('^'); c += 0x40; } if(c == 0x7f) printf("del"); else putchar(c); putchar('/'); } /* REM, DATA, ERROR lines are terminated by $9B, a real EOL, not the BASIC token. Since they're strings, print them in ASCII too. */ /* int handle_text_stmt(int pos) { unsigned char c; do { c = program[pos]; print_atascii(c); printf("%02x ", c); pos++; } while(c != 0x9b); return pos; } */ CALLBACK(handle_text) { unsigned char c; do { c = program[pos]; print_atascii(c); printf("%02x ", c); pos++; } while(c != 0x9b); } CALLBACK(handle_cmd) { printf("!%02x ", tok); } /* int handle_cmd(int pos) { unsigned char tok = program[pos]; printf("!%02x ", tok); switch(tok) { case CMD_REM: case CMD_DATA: case CMD_ERROR: return handle_text_stmt(pos + 1); default: return pos + 1; } } */ /* void handle_string(int pos) { int i, len; len = program[pos + 1]; printf("$%02x =%02x \"", program[pos], len); for(i = pos; i < pos + len; i++) { unsigned char c = program[i + 2]; print_atascii(c); printf("%02x%c", c, (i == (pos + len - 1) ? '"' : ' ')); } putchar(' '); } */ /* void handle_num(int pos) { int i; printf("#%02x [", program[pos]); for(i = 0; i < 6; i++) printf("%02x%c", program[pos + 1 + i], (i == 5 ? ']' : ' ')); putchar(' '); } */ CALLBACK(handle_op) { switch(tok) { case OP_EOS: printf("%02x:", tok); return; case OP_NUMCONST: putchar('#'); break; case OP_STRCONST: putchar('$'); break; default: break; } printf("%02x ", tok); } CALLBACK(handle_var) { printf("%02x", tok); switch(get_vartype(tok)) { case TYPE_ARRAY: putchar('('); break; case TYPE_STRING: putchar('$'); break; default: break; } putchar(' '); } CALLBACK(handle_string) { int i, len; len = program[pos]; printf("=%02x \"", len); for(i = pos; i < pos + len; i++) { unsigned char c = program[i + 1]; print_atascii(c); printf("%02x%c", c, (i == (pos + len - 1) ? '"' : ' ')); } putchar(' '); } CALLBACK(handle_num) { int i; putchar('['); for(i = 0; i < 6; i++) printf("%02x%c", program[pos + i], (i == 5 ? ']' : ' ')); putchar(' '); } CALLBACK(handle_start_line) { printf("%5d @%04x (%02x %02x): ^%02x\n", lineno, pos, program[pos], program[pos + 1], program[pos + 2]); } CALLBACK(handle_end_line) { putchar('\n'); } CALLBACK(handle_start_stmt) { printf(" >%02x ", tok); } CALLBACK(handle_end_stmt) { putchar('\n'); } int main(int argc, char **argv) { set_self(*argv); parse_general_args(argc, argv, print_help); parse_args(argc, argv); readfile(); parse_header(); on_start_line = handle_start_line; on_end_line = handle_end_line; on_start_stmt = handle_start_stmt; on_end_stmt = handle_end_stmt; on_exp_token = handle_op; on_cmd_token = handle_cmd; on_num_const = handle_num; on_string_const = handle_string; on_text = handle_text; on_var_token = handle_var; walk_code(startlineno, endlineno); return 0; } /* sorry, this is horrid, more like assembly than C. */ #if 0 int main(int argc, char **argv) { int linepos, nextpos, offset, soffset, lineno, pos, end, tok; set_self(*argv); parse_general_args(argc, argv, print_help); parse_args(argc, argv); readfile(); parse_header(); linepos = codestart; while(linepos < filelen) { /* loop over lines */ lineno = getword(linepos); offset = program[linepos + 2]; nextpos = linepos + offset; if(offset < 6) die("Can't dump a protected program, unprotect it first."); if(lineno < startlineno) { linepos = nextpos; continue; } /* line header */ printf("%5d@%04x (%02x %02x): ^%02x ", lineno, linepos, program[linepos], program[linepos + 1], offset); pos = linepos + 3; while(pos < nextpos) { /* loop over statements within a line */ soffset = program[pos]; end = linepos + soffset; while(pos < end) { /* loop over tokens within a statement */ printf("\n >%02x ", program[pos++]); /* offset */ pos = handle_cmd(pos++); /* 1st token is the command */ while(pos < end) { /* loop over operators */ tok = program[pos]; switch(tok) { case OP_NUMCONST: handle_num(pos); pos += 7; break; case OP_STRCONST: handle_string(pos); pos += program[pos + 1] + 2; break; default: printf("%02x", program[pos]); if(pos == (end - 1) && tok == OP_EOS) putchar(':'); else putchar(' '); pos++; break; } } } } putchar('\n'); if(lineno == endlineno) break; linepos = nextpos; } return 0; } #endif