aboutsummaryrefslogtreecommitdiff
path: root/unprotbas.c
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-05-22 05:24:11 -0400
committerB. Watson <urchlay@slackware.uk>2024-05-22 05:24:11 -0400
commita1144de8efebc414c33a0df9b8fccd758a242586 (patch)
tree3e111124ca2a001400af86ece1885b52ee29a8d0 /unprotbas.c
parent2f3bd55966eb27f6ffc40f5f534c196bc5e1ce98 (diff)
downloadbw-atari8-tools-a1144de8efebc414c33a0df9b8fccd758a242586.tar.gz
unprotbas: implement -r option (needs more testing though).
Diffstat (limited to 'unprotbas.c')
-rw-r--r--unprotbas.c187
1 files changed, 178 insertions, 9 deletions
diff --git a/unprotbas.c b/unprotbas.c
index 9964d39..5ad483b 100644
--- a/unprotbas.c
+++ b/unprotbas.c
@@ -2,6 +2,7 @@
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
/* attempt to fix a "list-protected" Atari 8-bit BASIC program.
we don't fully detokenize, so this won't fix truly corrupted
@@ -22,9 +23,16 @@
can't process. */
#define MIN_PROG_SIZE 21
+#define MAP_FILE "varnames.txt"
+
/* entire file gets read into memory (for now) */
unsigned char data[65536];
+/* for the -r option */
+unsigned char varnames[65536];
+unsigned char *varmap[128];
+int varmap_count;
+
/* BASIC 14-byte header values */
unsigned short lomem;
unsigned short vntp;
@@ -51,6 +59,8 @@ int keepgarbage = 1;
int checkonly = 0;
int was_protected = 0;
int verbose = 0;
+int readmap = 0;
+int writemap = 0;
/* file handles */
FILE *input_file = NULL;
@@ -306,9 +316,8 @@ int rebuild_vntable(int write) {
/* fprintf(stderr, "%04x: %04x, %d\n", vv, data[vv], type); */
if(varnum != data[vv+1]) {
- fprintf(stderr, "Warning: variable value is corrupt!\n");
+ fprintf(stderr, "Warning: variable #%d value is corrupt!\n", varnum);
}
- varnum++;
switch(type) {
case 1: varname = arrays++; sigil = 0xa8; break;
@@ -338,6 +347,7 @@ int rebuild_vntable(int write) {
}
vv += 8;
+ varnum++;
}
/* there's supposed to be a null byte at the end of the table, unless
@@ -381,13 +391,160 @@ int fixvars(void) {
return 1;
}
+void write_var_map(void) {
+ FILE *f;
+ int vp, count = 0;
+
+ if(verbose) fprintf(stderr, "Writing variable names to " MAP_FILE "\n");
+ f = fopen(MAP_FILE, "w");
+ if(!f) {
+ perror(MAP_FILE);
+ die("Can't create map file for -w option.");
+ }
+
+ for(vp = vnstart; (vp < vntd) && (data[vp] != 0); vp++) {
+ unsigned char c = data[vp];
+ if(c < 0x80) {
+ fputc(c, f);
+ } else {
+ fputc(c & 0x7f, f);
+ fputc('\n', f);
+ count++;
+ }
+ }
+
+ fclose(f);
+
+ if(verbose) fprintf(stderr, "Wrote %d variable names to " MAP_FILE "\n", count);
+}
+
+void die_mapfile(char *msg, int num) {
+ fprintf(stderr, MAP_FILE ": line %d: %s.\n", num, msg);
+ exit(1);
+}
+
+void check_varname(const unsigned char *name, int line) {
+ int len = strlen((char *)name);
+ int i;
+ unsigned char c = 0, type;
+
+ /* fprintf(stderr, "check_varname(\"%s\", %d)\n", name, line); */
+
+ if(len < 1) die_mapfile("blank variable name", line);
+ if(len > 128) die_mapfile("variable name >128 characters", line);
+ if(name[0] < 'A' || name[0] > 'Z')
+ die_mapfile("invalid variable name (first character must be a letter)", line);
+
+ for(i = 1; i < len; i++) {
+ c = name[i];
+ if(c >= 'A' && c <= 'Z') continue;
+ if(c >= '0' && c <= '9') continue;
+ if(i == (len - 1) && ((c == '$') || (c == '('))) continue;
+ die_mapfile("invalid character in variable name", line);
+ }
+
+ if(c == 0) c = name[0];
+
+ /* c now has the last char of the name, make sure it matches the variable type */
+ type = data[vvstart + 8 * (line - 1)] >> 6;
+ /* type: scalar = 0, array = 1, string = 2 */
+ if(type == 0) {
+ if(c == '$')
+ die_mapfile("type mismatch: numeric variable may not end with $", line);
+ else if(c == '(')
+ die_mapfile("type mismatch: numeric variable may not end with (", line);
+ } else if(type == 1) {
+ if(c != '(')
+ die_mapfile("type mismatch: array variable must end with (", line);
+ } else if(type == 2) {
+ if(c != '$')
+ die_mapfile("type mismatch: string variable must end with $", line);
+ } else {
+ fprintf(stderr, "Warning: variable value table is corrupt (invalid type)\n");
+ }
+
+ /* check for dups */
+ for(i = 0; i < line - 1; i++) {
+ if(strcmp((char *)name, (char *)varmap[i]) == 0)
+ die_mapfile("duplicate variable name", line);
+ }
+}
+
+void read_var_map(void) {
+ FILE *f;
+ unsigned char *p = varnames, *curname = varnames;
+ int count = 0, vvcount = (codestart - vvstart) / 8;
+
+ if(verbose) fprintf(stderr, "Reading variable names from " MAP_FILE "\n");
+ f = fopen(MAP_FILE, "r");
+ if(!f) {
+ perror(MAP_FILE);
+ die("Can't read map file for -r option.");
+ }
+
+ while(!feof(f)) {
+ *p = toupper(fgetc(f)); /* allow lowercase */
+
+ if(*p == ' ' || *p == '\t' || *p == '\r')
+ continue; /* ignore whitespace */
+
+ if(*p == '\n') {
+ *p = '\0';
+ varmap[count++] = curname;
+ check_varname(curname, count);
+ curname = p + 1;
+ }
+ p++;
+ }
+
+ if(verbose) fprintf(stderr, "Read %d variable names from " MAP_FILE "\n", count);
+
+ if(vvcount > count) {
+ fprintf(stderr, MAP_FILE ": not enough variables (have %d, need %d).\n", count, vvcount);
+ exit(1);
+ } else if(count > vvcount) {
+ fprintf(stderr, MAP_FILE ": too many variables (have %d, need %d).\n", count, vvcount);
+ exit(1);
+ }
+ #if 0
+ for(count = 0; varmap[count] != NULL; count++) {
+ fprintf(stderr, "\t%02d %s\n", count, varmap[count]);
+ }
+ #endif
+
+ varmap_count = count;
+}
+
+void apply_var_map(void) {
+ unsigned char new_vntable[65536];
+ int i, newp = 0;
+ unsigned char *v;
+
+ for(i = 0; i < varmap_count; i++) {
+ v = varmap[i];
+ while(*v) {
+ new_vntable[newp++] = *v;
+ v++;
+ }
+ new_vntable[newp - 1] |= 0x80;
+ }
+
+ if(varmap_count < 128) new_vntable[newp++] = '\0';
+
+ i = vvstart - vnstart;
+ adjust_vntable_size(i, newp);
+ memmove(data + vnstart, new_vntable, newp);
+}
+
void print_help(void) {
- fprintf(stderr, "Usage: %s [-v] [-f] [-n] [-g] <inputfile> <outputfile>\n", self);
+ fprintf(stderr, "Usage: %s [-v] [-f] [-n] [-g] [-c] [-r|-w] <inputfile> <outputfile>\n", self);
fprintf(stderr, "-v: verbose\n");
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, "-w: write variable names to varnames.txt\n");
+ fprintf(stderr, "-r: read variable names from varnames.txt\n");
fprintf(stderr, "Use - as a filename to read from stdin and/or write to stdout\n");
}
@@ -451,6 +608,8 @@ void parse_args(int argc, char **argv) {
case 'n': keepvars++; break;
case 'g': keepgarbage = 0; break;
case 'c': checkonly = 1; break;
+ case 'r': readmap = 1; break;
+ case 'w': writemap = 1; break;
case 0:
if(!input_file)
open_input(NULL);
@@ -474,6 +633,8 @@ void parse_args(int argc, char **argv) {
if(!input_file) die("no input file given (use - for stdin)");
if(!checkonly && !output_file) die("no output file given (use - for stdout)");
if(keepvars && forcevars) die("-f and -n are mutually exclusive");
+ if(readmap && writemap) die("-r and -w are mutually exclusive");
+ if(readmap && keepvars) die("-r and -n are mutually exclusive (maybe you want -w?)");
}
int main(int argc, char **argv) {
@@ -484,12 +645,18 @@ int main(int argc, char **argv) {
if(lomem) die("This doesn't look like an Atari BASIC program (no $0000 signature)");
- if(!keepvars) {
- if(fixvars()) {
- was_protected = 1;
- if(verbose) fprintf(stderr, "Variable names replaced\n");
- } else {
- if(verbose) fprintf(stderr, "Variable names were already OK\n");
+ if(readmap) {
+ was_protected = !vntable_ok();
+ read_var_map();
+ apply_var_map();
+ } else {
+ if(!keepvars) {
+ if(fixvars()) {
+ was_protected = 1;
+ if(verbose) fprintf(stderr, "Variable names replaced\n");
+ } else {
+ if(verbose) fprintf(stderr, "Variable names were already OK\n");
+ }
}
}
@@ -519,5 +686,7 @@ int main(int argc, char **argv) {
fclose(output_file);
if(verbose) fprintf(stderr, "wrote %d bytes\n", got);
+ if(writemap) write_var_map();
+
return 0;
}