aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-05-19 02:13:29 -0400
committerB. Watson <urchlay@slackware.uk>2024-05-19 02:13:29 -0400
commit3419a47eaa9ce7bbccb6e6028b9b0835b1f8f288 (patch)
treeec0a8bb3ae5d71975911de5edd2a9505a99af7fe
parent60dd1bb5f3b3c95787043a9057d01d60740d85ce (diff)
downloadbw-atari8-tools-3419a47eaa9ce7bbccb6e6028b9b0835b1f8f288.tar.gz
unprotbas: smarter variable name table resizing.
-rw-r--r--unprotbas.c148
1 files changed, 144 insertions, 4 deletions
diff --git a/unprotbas.c b/unprotbas.c
index 70741e3..a367502 100644
--- a/unprotbas.c
+++ b/unprotbas.c
@@ -199,11 +199,12 @@ int fixcode(void) {
}
/* sometimes the variable name table isn't large enough to hold
- the generated variable names. move_code_up() makes more space,
+ the generated variable names. move_code() makes more space,
by moving the rest of the program (including the variable value
table) up in memory. */
-void move_code_up(int offset) {
+void move_code(int offset) {
memmove(data + vvstart + offset, data + vvstart, filelen);
+ vntd += offset;
vvtp += offset;
stmtab += offset;
stmcur += offset;
@@ -229,7 +230,7 @@ void move_code_up(int offset) {
We can find the actual table size in the file by subtracting VNTP
(start of variable name table) from VNTD (end of variable name table).
It's possible that the table size is too small for the generated
- variable names, in which case we have to call move_code_up() to
+ variable names, in which case we have to call move_code() to
make more room.
The maximum number of variable names is 128. If all 128 vars are in
@@ -238,7 +239,145 @@ void move_code_up(int offset) {
*/
+int vntable_ok(void) {
+ int vp, bad;
+
+ if(vntp == vntd) {
+ fprintf(stderr, "No variables\n");
+ return 1;
+ }
+
+ /* first pass: bad = 1 if all the bytes in the table have the same
+ value, no matter what it is. */
+ vp = vnstart + 1;
+ bad = 1;
+ while(vp < vvstart - 1) {
+ if(data[vp] != data[vnstart]) {
+ bad = 0;
+ break;
+ }
+ vp++;
+ }
+ if(bad) return 0;
+
+ /* 2nd pass: bad = 1 if there's any invalid character in the table. */
+ vp = vnstart;
+ while(vp < vvstart) {
+ unsigned char c = data[vp];
+
+ /* treat a null byte as end-of-table, ignore any junk between it and VNTP. */
+ if(c == 0) break;
+
+ vp++;
+
+ /* inverse $ or ( is OK */
+ if(c == 0xa4 || c == 0xa8) continue;
+
+ /* numbers and letters are allowed, inverse or normal. */
+ c &= 0x7f;
+ if(c >= 0x30 && c <= 0x39) continue;
+ if(c >= 0x41 && c <= 0x5a) continue;
+
+ bad++;
+ break;
+ }
+
+ return !bad;
+}
+
+/* walk the variable value table, generating variable names.
+ if write is 0, just return the size the table will be.
+ if write is 1, actually write the names to memory. */
+int rebuild_vntable(int write) {
+ int vp = vnstart;
+ int vv = vvstart;
+ int size = 0;
+ int strings = 0, arrays = 0, scalars = 0, varname = 0, varnum = 0;
+
+ while(vv < codestart) {
+ unsigned char sigil = 0;
+ /* type: scalar = 0, array = 1, string = 2 */
+ unsigned char type = data[vv] >> 6;
+ /* fprintf(stderr, "%04x: %04x, %d\n", vv, data[vv], type); */
+
+ if(varnum != data[vv+1]) {
+ fprintf(stderr, "Warning: variable value is corrupt!\n");
+ }
+ varnum++;
+
+ switch(type) {
+ case 1: varname = arrays++; sigil = 0xa8; break;
+ case 2: varname = strings++; sigil = 0xa4; break;
+ default: varname = scalars++; break;
+ }
+
+ if(varname < 26) {
+ if(write) data[vp] = ('A' + varname);
+ size++;
+ } else {
+ varname -= 26;
+ if(write) {
+ data[vp++] = 'A' + ((varname - 26) / 9);
+ data[vp] = ('1' + ((varname - 26) % 9));
+ }
+ size += 2;
+ }
+
+ if(sigil) {
+ size++;
+ vp++;
+ if(write) data[vp++] = sigil;
+ } else {
+ if(write) data[vp] |= 0x80;
+ vp++;
+ }
+
+ vv += 8;
+ }
+
+ /* there's supposed to be a null byte at the end of the table, unless
+ all 128 table slots are used. */
+ if(write) {
+ if(varnum < 128) data[vp] = 0;
+ /* fixup the VNTD pointer */
+ /*
+ vntd = vntp + (vp - vnstart);
+ fprintf(stderr, "%04x\n", vntd);
+ data[4] = vntd & 0xff;
+ data[5] = vntd >> 8;
+ */
+ }
+
+ return size;
+}
+
+void adjust_vntable_size(int oldsize, int newsize) {
+ int move_by;
+ if(oldsize != newsize) {
+ move_by = newsize - oldsize;
+ fprintf(stderr, "need %d bytes for vntable, have %d, moving VVTP by %d to %04x\n",
+ newsize, oldsize, move_by, vvtp + move_by);
+ move_code(move_by);
+ }
+}
+
int fixvars(void) {
+ int old_vntable_size, new_vntable_size;
+
+ if(vntable_ok() && !forcevars)
+ return 0;
+
+ old_vntable_size = vvstart - vnstart;
+ new_vntable_size = rebuild_vntable(0);
+
+ adjust_vntable_size(old_vntable_size, new_vntable_size);
+
+ rebuild_vntable(1);
+ return 1;
+}
+
+#if 0
+int old_fixvars(void) {
int vp = vnstart, vv = vvstart;
int strings = 0, arrays = 0, scalars = 0, varname = 0, varnum = 0;
int bad = 0;
@@ -310,7 +449,7 @@ int fixvars(void) {
move_up_by = neededsize - vntblsize;
fprintf(stderr, "need %d bytes for vntable, only have %d, moving up by %d to %04x\n",
neededsize, vntblsize, move_up_by, vvtp + move_up_by);
- move_code_up(move_up_by);
+ move_code(move_up_by);
}
}
@@ -364,6 +503,7 @@ int fixvars(void) {
fprintf(stderr, "%d variables, VNTD adjusted to %04x\n", varnum, vntd);
return 1;
}
+#endif
void print_help(void) {
fprintf(stderr, "Usage: %s [-v] [-f] [-n] [-g] <inputfile> <outputfile>\n", self);