aboutsummaryrefslogtreecommitdiff
path: root/listamsb.c
diff options
context:
space:
mode:
Diffstat (limited to 'listamsb.c')
-rw-r--r--listamsb.c111
1 files changed, 106 insertions, 5 deletions
diff --git a/listamsb.c b/listamsb.c
index ed2f813..9acc300 100644
--- a/listamsb.c
+++ b/listamsb.c
@@ -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();