From fc5c53e5b73eeadafb20a5a02184642b9fcc8344 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Fri, 7 Mar 2025 16:12:32 -0500 Subject: listamsb: add -D (decrunch) option. --- listamsb.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 3 deletions(-) (limited to 'listamsb.c') diff --git a/listamsb.c b/listamsb.c index 9acc300..be6b307 100644 --- a/listamsb.c +++ b/listamsb.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "amsbtok.h" @@ -81,7 +82,8 @@ int startline = 0; /* -r */ int endline = 65536; /* -r */ int unlock_mode = 0; /* -l */ int initial_eol = 1; /* -n */ -int crunch = 0; /* -C */ +int crunch = 0; /* -C, -D */ +int decrunch = 0; /* -D */ int locked = 0; int need_pclose = 0; @@ -478,6 +480,10 @@ void unlock_program(void) { exit(0); } +void write_code(int ptr, int lineno, const char *code) { + /* TODO */ +} + int crunch_line(void) { unsigned char code[MAX_LINE_LEN_HARD + 1], byte; int lineno, ptr, codelen = 0, in_string = 0, in_comment = 0, commentstart = 0; @@ -542,6 +548,89 @@ int crunch_line(void) { return codelen; } +void expand_token(unsigned char t, unsigned char *buf) { + if(t < 0x80) { + buf[0] = t; + buf[1] = 0; + return; + } + + strcpy((char *)buf, std_tokens[t - MIN_STD_TOK]); +} + +int need_space_between(unsigned char t1, unsigned char t2) { + unsigned char tok1[10], tok2[10]; + unsigned char t1last, t2first; + + if(!t1) return 0; /* start of line */ + if(!t2) return 0; /* end of line */ + if(t1 < 0x80 && t2 < 0x80) return 0; /* 2 ASCII chars */ + + expand_token(t1, tok1); + expand_token(t2, tok2); + t1last = tok1[strlen((char *)tok1) - 1]; /* "PRINT" => "T" */ + t2first = tok2[0]; /* "PRINT" => "P" */ + + return(isalnum(t1last) && isalnum(t2first)); +} + +int decrunch_line(void) { + unsigned char code[MAX_LINE_LEN_HARD + 1], byte = 0, prev; + int lineno, ptr, codelen = 0, in_string = 0, in_comment = 0; + static int addr = 0x700; /* doesn't really matter where */ + + ptr = read_prog_word(); + if(!ptr) return -1; + lineno = read_prog_word(); + + verbose(2, "decrunching line %d", lineno); + + while(1) { + if(codelen >= MAX_LINE_LEN_HARD) + die("line %d too long, decrunching failed", lineno); + prev = byte; + byte = read_prog_byte(); + + if(byte != 0) { + if(in_string) { + if(byte == '|') + in_string = 0; + } else if(in_comment) { + /* NOP */ + } else { + if(byte == '"') { + in_string = 1; + } else if(byte == TOK_REM || byte == TOK_SQUOTE || byte == TOK_BANG) { + in_comment = 1; + } else if(byte == 0xff) { + /* extended/function tokens never need a space before/after them */ + code[codelen++] = byte; + byte = read_prog_byte(); + code[codelen++] = byte; + byte = read_prog_byte(); + } else if(need_space_between(prev, byte)) { + code[codelen++] = ' '; + } + } + } + + code[codelen++] = byte; + if(byte == 0) break; + } + + codelen += 4; /* account for ptr and lineno */ + addr += codelen; + + fputc(addr & 0xff, outfile); + fputc((addr >> 8) & 0xff, outfile); + fputc(lineno & 0xff, outfile); + fputc((lineno >> 8) & 0xff, outfile); + fputs((char *)code, outfile); + fputc(0x00, outfile); + + return codelen; +} + void crunch_program(void) { int newproglen = 0, linelen = 0; @@ -549,7 +638,7 @@ void crunch_program(void) { fputc(0x00, outfile); /* length LSB (fill in later) */ fputc(0x00, outfile); /* length MSB */ - while((linelen = crunch_line()) != -1) + while((linelen = decrunch ? decrunch_line() : crunch_line()) != -1) newproglen += linelen; /* trailing $00 $00 */ @@ -578,6 +667,7 @@ void print_help(void) { puts(" -a: raw ATASCII output"); puts(" -c: check only (no listing)"); puts(" -C: crunch program"); + puts(" -D: decrunch program"); puts(" -l: lock or unlock program"); puts(" -n: no blank line at start of listing"); puts(" -v: verbosity"); @@ -638,8 +728,9 @@ void parse_args(int argc, char **argv) { } } - while( (opt = getopt(argc, argv, "Cnlr:cvaiutmsh")) != -1) { + while( (opt = getopt(argc, argv, "DCnlr:cvaiutmsh")) != -1) { switch(opt) { + case 'D': crunch = decrunch = 1; break; case 'C': crunch = 1; break; case 'l': unlock_mode = 1; break; case 'c': check_only = 1; break; -- cgit v1.2.3