aboutsummaryrefslogtreecommitdiff
path: root/dumpbas.c
diff options
context:
space:
mode:
Diffstat (limited to 'dumpbas.c')
-rw-r--r--dumpbas.c310
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