diff options
Diffstat (limited to 'listamsb.c')
-rw-r--r-- | listamsb.c | 111 |
1 files changed, 106 insertions, 5 deletions
@@ -81,6 +81,7 @@ int startline = 0; /* -r */ int endline = 65536; /* -r */ int unlock_mode = 0; /* -l */ int initial_eol = 1; /* -n */ +int crunch = 0; /* -C */ int locked = 0; int need_pclose = 0; @@ -439,7 +440,7 @@ int next_line(void) { if(last_ptr != -1) { int plen = ptr - last_ptr; if(len != plen) { - warn("line %d: EOL address doesn't match actual line length %d", lineno, len); + warn("line %d: EOL address doesn't match actual line length %d (should be %d)", lineno, len, plen); } } @@ -477,12 +478,106 @@ void unlock_program(void) { exit(0); } +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; + static int addr = 0x700; /* doesn't really matter where */ + + ptr = read_prog_word(); + if(!ptr) return -1; + lineno = read_prog_word(); + + verbose(2, "crunching line %d", lineno); + + while(1) { + if(codelen >= MAX_LINE_LEN_HARD) + die("line %d too long, crunching failed", lineno); + byte = read_prog_byte(); + + if(byte != 0) { + if(in_string) { + if(byte == '|') + in_string = 0; + } else if(in_comment) { + continue; + } else { + if(byte == '"') + in_string = 1; + else if(byte == TOK_REM || byte == TOK_SQUOTE || byte == TOK_BANG) { + in_comment = 1; + commentstart = codelen; + } + else if(byte == ' ') + continue; + } + } + + code[codelen++] = byte; + if(byte == 0) break; + } + + /* omit comment-only lines */ + if(code[0] == TOK_REM) return 0; + if(code[0] == ':') { + if(code[1] == TOK_SQUOTE || code[1] == TOK_BANG) + return 0; + } + + /* omit trailing comments */ + if(commentstart) { + code[commentstart - 1] = 0; /* null out the colon before the comment */ + codelen = commentstart; + } + + 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; + + fputc(0x00, outfile); /* signature (0 = not locked) */ + fputc(0x00, outfile); /* length LSB (fill in later) */ + fputc(0x00, outfile); /* length MSB */ + + while((linelen = crunch_line()) != -1) + newproglen += linelen; + + /* trailing $00 $00 */ + fputc(0x00, outfile); + fputc(0x00, outfile); + + if(fseek(outfile, 1L, SEEK_SET) < 0) + os_err("fseek() failed"); + + newproglen += 2; /* account for trailing $00 $00 */ + fputc(newproglen & 0xff, outfile); + fputc((newproglen >> 8) & 0xff, outfile); + fclose(outfile); + + newproglen += 3; + verbose(1, "crunched %d byte program to %d bytes (%.1f%% savings)", + bytes_read, + newproglen, + 100.0 * (1.0 - (float)newproglen / (float)proglen)); +} + void print_help(void) { printf("%s v" VERSION " - detokenize Atari Microsoft BASIC files\n", self); puts("By B. Watson <urchlay@slackware.uk>, released under the WTFPL"); - printf("Usage: %s [[-l] | [-[avhinutms] ... ] [-r *start,end*]] <file> <outfile>\n", self); + printf("Usage: %s [[-l] | [-[acClnviutms] ... ] [-r *start,end*]] <file> <outfile>\n", self); puts(" -a: raw ATASCII output"); puts(" -c: check only (no listing)"); + puts(" -C: crunch program"); puts(" -l: lock or unlock program"); puts(" -n: no blank line at start of listing"); puts(" -v: verbosity"); @@ -543,8 +638,9 @@ void parse_args(int argc, char **argv) { } } - while( (opt = getopt(argc, argv, "nlr:cvaiutmsh")) != -1) { + while( (opt = getopt(argc, argv, "Cnlr:cvaiutmsh")) != -1) { switch(opt) { + case 'C': crunch = 1; break; case 'l': unlock_mode = 1; break; case 'c': check_only = 1; break; case 'a': raw_output = 1; break; @@ -589,6 +685,8 @@ void parse_args(int argc, char **argv) { if(!freopen(outname, "wb", stdout)) os_err("%s: %s", outname, strerror(errno)); verbose(1, "redirected stdout to %s", outname); + } else if(crunch) { + os_err("can't use stdout with -C, must give an output filename"); } } @@ -599,10 +697,10 @@ void open_output() { os_err("/dev/null: %s", strerror(errno)); } verbose(1, "using /dev/null for output (check_only)"); - } else if(raw_output || unlock_mode) { + } else if(raw_output || unlock_mode || crunch) { if(isatty(fileno(stdout))) { os_err("refusing to write %s to a terminal", - (unlock_mode ? "tokenized BASIC" : "raw ATASCII")); + (raw_output ? "raw ATASCII" : "tokenized BASIC")); } outfile = stdout; verbose(1, "using stdout for output"); @@ -630,6 +728,9 @@ int main(int argc, char **argv) { if(unlock_mode) { unlock_program(); exit(0); /* don't need finish() here, no parsing done */ + } else if(crunch) { + crunch_program(); + exit(0); } start_listing(); |