diff options
Diffstat (limited to 'dumpbas.c')
-rw-r--r-- | dumpbas.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/dumpbas.c b/dumpbas.c new file mode 100644 index 0000000..087e5b1 --- /dev/null +++ b/dumpbas.c @@ -0,0 +1,310 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> + +#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) { + printf("Usage: %s [-v] [-s start-lineno] [-e end-lineno] <inputfile>\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 |