diff options
Diffstat (limited to 'listbas.c')
-rw-r--r-- | listbas.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/listbas.c b/listbas.c new file mode 100644 index 0000000..a278bd7 --- /dev/null +++ b/listbas.c @@ -0,0 +1,211 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <time.h> + +#include <math.h> +#include <errno.h> + +#include "bas.h" +#include "bcdfp.h" +#include "tokens.h" + +int immediate = 0, a8utf8 = 0, a8eol = 1; + +FILE *outfh; + +void print_help(void) { + printf("Usage: %s [-v] [-i] [-a|-u] <inputfile>\n", self); + printf(" -v: verbose.\n"); + printf(" -i: show immediate mode command (line 32768).\n"); + printf(" -a: output raw ATASCII.\n"); + printf(" -u: output Unicode.\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + + while( (opt = getopt(argc, argv, "viau")) != -1) { + switch(opt) { + case 'v': verbose = 1; break; + case 'i': immediate = 1; break; + case 'a': a8utf8 = a8eol = 0; break; + case 'u': a8utf8 = 1; a8eol = 0; break; + default: + print_help(); + exit(1); + } + } + + if(optind >= argc) + die("No input file given (use - for stdin)."); + else + open_input(argv[optind]); +} + +void setup_outfh(void) { + const char *cmd; + + /* search current dir before PATH. no easy way to detect errors here, + have to wait until we call pclose(). */ + if(a8eol) { + cmd = "./a8eol -u -c 2>/dev/null || a8eol -u -c 2>/dev/null || exit 1"; + } else if(a8utf8) { + cmd = "./a8utf8 2>/dev/null || a8utf8 2>/dev/null || exit 1"; + } else { + if(isatty(fileno(stdout))) { + die("Refusing to write ATASCII data to the terminal."); + } + outfh = stdout; + return; + } + + outfh = popen(cmd, "w"); + if(!outfh) { + /* fork() or pipe() failed. does NOT detect if the command + wasn't found. */ + perror(self); + exit(1); + } +} + +void close_outfh(void) { + if(a8eol || a8utf8) { + if(pclose(outfh)) { + die("output filter failed; a8eol or a8utf8 not in current dir or $PATH."); + } + } +} + +void outchr(char c) { + putc(c, outfh); +} + +/* this should probably be moved to bcdfp.c */ +double bcd2double(const unsigned char *num) { + double result = 0, sign; + int exp, i; + + exp = *num; + if(!exp) { + return 0.0; + } + + sign = (exp & 0x80 ? -1.0 : 1.0); + exp &= 0x7f; + exp -= 0x40; + + for(i = 1; i < 6; i++) { + result *= 100.0; + result += bcd2int(num[i]); + } + + result *= pow(100, exp - 4); + result *= sign; + + return result; +} + +void print_number(unsigned int pos) { + fprintf(outfh, "%G", bcd2double(program + pos)); +} + +void print_string(unsigned int pos, unsigned int len) { + outchr('"'); + while(len--) outchr(program[pos++]); + outchr('"'); +} + +CALLBACK(print_lineno) { + fprintf(outfh, "%d ", lineno); +} + +CALLBACK(print_cmd) { + const char *name; + + if(tok == CMD_ILET) return; + + if(tok > last_command || (!(name = commands[tok]))) + fprintf(outfh, "(bad cmd token $%02x) ", tok); + else + fprintf(outfh, "%s ", name); +} + +CALLBACK(print_op) { + const char *name; + + switch(tok) { + case OP_NUMCONST: + print_number(pos + 1); + return; + case OP_STRCONST: + print_string(pos + 2, program[pos + 1]); + return; + case OP_EOL: + return; + default: break; + } + + if(tok > last_operator || (!(name = operators[tok]))) + fprintf(outfh, "(bad op token $%02x)", tok); + else + fprintf(outfh, "%s", name); +} + +CALLBACK(print_varname) { + int i, count; + unsigned char c; + + tok &= 0x7f; + for(i = vnstart, count = 0; count < tok; i++) { + if(program[i] & 0x80) count++; + } + do { + outchr( (c = program[i++]) & 0x7f); + } while (c < 0x80); +} + +CALLBACK(print_text) { + while(program[pos] != 0x9b) outchr(program[pos++]); +} + +CALLBACK(print_newline) { + outchr(0x9b); +} + +CALLBACK(code_prot) { + fprintf(stderr, "%s: Program is code-protected, stopping at line %d.\n", self, lineno); + close_outfh(); + exit(0); +} + +void list(void) { + on_start_line = print_lineno; + on_cmd_token = print_cmd; + on_exp_token = print_op; + on_var_token = print_varname; + on_end_line = print_newline; + on_text = print_text; + on_bad_line_length = code_prot; + walk_code(0, 32767 + immediate); +} + +int main(int argc, char **argv) { + set_self(*argv); + parse_general_args(argc, argv, print_help); + parse_args(argc, argv); + + readfile(); + parse_header(); + + if(!vntable_ok()) + die("Program is variable-protected; unprotect it first."); + + setup_outfh(); + list(); + close_outfh(); + + return 0; +} |