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