#include #include #include #include #include #include #include #include #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] \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++; } while(1) { c = program[i++]; outchr(c & 0x7f); if(c & 0x80) break; } } 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; }