aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--unprotbas.133
-rw-r--r--unprotbas.c47
-rw-r--r--unprotbas.rst27
3 files changed, 78 insertions, 29 deletions
diff --git a/unprotbas.1 b/unprotbas.1
index 3b8b832..0036a30 100644
--- a/unprotbas.1
+++ b/unprotbas.1
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
-.TH "UNPROTBAS" 1 "2024-05-18" "0.2.1" "Urchlay's Atari 8-bit Tools"
+.TH "UNPROTBAS" 1 "2024-05-19" "0.2.1" "Urchlay's Atari 8-bit Tools"
.SH NAME
unprotbas \- Unprotect LIST-protected Atari 8-bit BASIC programs
.SH SYNOPSIS
@@ -51,7 +51,7 @@ the terminal).
.INDENT 0.0
.TP
.B \fB\-v\fP
-Verbose operation.
+Verbose operation. TODO: it\(aqs always verbose right now...
.TP
.B \fB\-f\fP
Force the variable name table to be rebuilt, even if it looks OK.
@@ -63,10 +63,24 @@ needed).
.B \fB\-g\fP
Remove any "garbage" data from the end of the file. By default,
it\(aqs left as\-is, in case it\(aqs actually data used by the program.
+.TP
+.B \fB\-c\fP
+Check only. Does a dry run. Loads the program, unprotects it in
+memory, but doesn\(aqt write the result anywhere. In this mode, there
+is no \fBoutput\-file\fP\&.
.UNINDENT
.SH EXIT STATUS
-.sp
-Exit status is zero for success, non\-zero for failure.
+.INDENT 0.0
+.TP
+.B 0
+\fBinput\-file\fP was protected, unprotection was successful.
+.TP
+.B 1
+I/O error, or \fBinput\-file\fP isn\(aqt a valid BASIC program.
+.TP
+.B 2
+\fBinput\-file\fP is already an unprotected BASIC program.
+.UNINDENT
.SH DETAILS
.sp
In the Atari BASIC world, it\(aqs possible to create a SAVEd (tokenized)
@@ -123,10 +137,13 @@ named A through Z, A1 through A9, B1 through B9, etc, etc. It\(aqll
require human intelligence to figure out what each variable is for,
since the names are meaningless.
.sp
-The \fBoutput\-file\fP may be larger than the \fBinput\-file\fP was, since
-some types of variable\-name scrambling shrink the variable name
-table to the minimum size (one byte per name); the rebuilt table
-will be larger.
+The \fBoutput\-file\fP may not be the exact size that the
+\fBinput\-file\fP was. Some types of variable\-name scrambling shrink
+the variable name table to the minimum size (one byte per name), so
+the rebuilt table will be larger. Other types of scrambling leave
+the variable name table at its original size, but \fBunprotbas\fP
+generates only one\- and two\-character variable names, so the rebuilt
+table might be smaller.
.TP
.B Bad next\-line pointer
Generally, this is done with line number 32768. Yes, this line
diff --git a/unprotbas.c b/unprotbas.c
index 8dc6844..845c75b 100644
--- a/unprotbas.c
+++ b/unprotbas.c
@@ -42,6 +42,8 @@ char *self;
int keepvars = 0;
int forcevars = 0;
int keepgarbage = 1;
+int checkonly = 0;
+int was_protected = 0;
int verbose = 0;
/* file handles */
@@ -57,6 +59,7 @@ void die(const char *msg) {
int readfile(void) {
int got = fread(data, 1, 65535, input_file);
fprintf(stderr, "read %d bytes\n", got);
+ fclose(input_file);
return got;
}
@@ -369,6 +372,7 @@ void print_help(void) {
fprintf(stderr, "-f: force variable name table rebuild\n");
fprintf(stderr, "-n: do not rebuild variable name table, even if it's invalid\n");
fprintf(stderr, "-g: remove trailing garbage, if present\n");
+ fprintf(stderr, "-c: check only; no output file\n");
fprintf(stderr, "Use - as a filename to read from stdin and/or write to stdout\n");
}
@@ -432,6 +436,7 @@ void parse_args(int argc, char **argv) {
case 'f': forcevars++; break;
case 'n': keepvars++; break;
case 'g': keepgarbage = 0; break;
+ case 'c': checkonly = 1; break;
case 0:
if(!input_file)
open_input(NULL);
@@ -445,7 +450,7 @@ void parse_args(int argc, char **argv) {
} else {
if(!input_file)
open_input(*argv);
- else if(!output_file)
+ else if(!checkonly && !output_file)
open_output(*argv);
else
invalid_args(*argv);
@@ -453,7 +458,7 @@ void parse_args(int argc, char **argv) {
}
if(!input_file) die("no input file given (use - for stdin)");
- if(!output_file) die("no output file given (use - for stdout)");
+ if(!checkonly && !output_file) die("no output file given (use - for stdout)");
if(keepvars && forcevars) die("-f and -n are mutually exclusive");
}
@@ -465,26 +470,38 @@ int main(int argc, char **argv) {
if(lomem) die("This doesn't look like an Atari BASIC program (no $0000 signature)");
- /*
- fprintf(stderr, "data at STMTAB (we hope):\n");
- for(int i=codestart; i<filelen; i++) {
- fprintf(stderr, "%02x ", data[i]);
- }
- fprintf(stderr, "\n");
- */
-
if(!keepvars) {
- if(fixvars())
+ if(fixvars()) {
+ was_protected = 1;
fprintf(stderr, "Variable names replaced\n");
- else
+ } else {
fprintf(stderr, "Variable names were already OK\n");
+ }
}
- if(fixcode())
+ if(fixcode()) {
fprintf(stderr, "Fixed invalid offset in code\n");
- else
+ was_protected = 1;
+ } else {
fprintf(stderr, "No invalid offsets\n");
+ }
+
+ if(was_protected)
+ fprintf(stderr, "Program was protected.\n");
+ else
+ fprintf(stderr, "Program was not protected.\n");
+
+ if(checkonly) {
+ fprintf(stderr, "Check-only mode; no output written.\n");
+ if(was_protected)
+ return 0;
+ else
+ return 2;
+ }
+
+ int got = fwrite(data, 1, filelen, output_file);
+ fclose(output_file);
+ fprintf(stderr, "wrote %d bytes\n", got);
- fwrite(data, filelen, 1, output_file);
return 0;
}
diff --git a/unprotbas.rst b/unprotbas.rst
index 557d27d..b3a9926 100644
--- a/unprotbas.rst
+++ b/unprotbas.rst
@@ -33,7 +33,7 @@ OPTIONS
=======
**-v**
- Verbose operation.
+ Verbose operation. TODO: it's always verbose right now...
**-f**
Force the variable name table to be rebuilt, even if it looks OK.
@@ -46,10 +46,22 @@ OPTIONS
Remove any "garbage" data from the end of the file. By default,
it's left as-is, in case it's actually data used by the program.
+**-c**
+ Check only. Does a dry run. Loads the program, unprotects it in
+ memory, but doesn't write the result anywhere. In this mode, there
+ is no **output-file**.
+
EXIT STATUS
===========
-Exit status is zero for success, non-zero for failure.
+0
+ **input-file** was protected, unprotection was successful.
+
+1
+ I/O error, or **input-file** isn't a valid BASIC program.
+
+2
+ **input-file** is already an unprotected BASIC program.
DETAILS
=======
@@ -99,10 +111,13 @@ Variable name table scrambling
require human intelligence to figure out what each variable is for,
since the names are meaningless.
- The **output-file** may be larger than the **input-file** was, since
- some types of variable-name scrambling shrink the variable name
- table to the minimum size (one byte per name); the rebuilt table
- will be larger.
+ The **output-file** may not be the exact size that the
+ **input-file** was. Some types of variable-name scrambling shrink
+ the variable name table to the minimum size (one byte per name), so
+ the rebuilt table will be larger. Other types of scrambling leave
+ the variable name table at its original size, but **unprotbas**
+ generates only one- and two-character variable names, so the rebuilt
+ table might be smaller.
Bad next-line pointer
Generally, this is done with line number 32768. Yes, this line