From fe7fc036ca0f7769fd9b9b771a92a303a323e8ee Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Mon, 3 Jun 2024 15:49:02 -0400 Subject: unprotbas: split off utility functions/etc to bas.c. --- bas.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 bas.c (limited to 'bas.c') diff --git a/bas.c b/bas.c new file mode 100644 index 0000000..64c4f3f --- /dev/null +++ b/bas.c @@ -0,0 +1,183 @@ +/* bas.c - API for writing standalone programs that deal with + tokenized Atari 8-bit BASIC program. */ + +#include +#include +#include +#include +#include +#include + +#include "bas.h" + +int verbose = 0; +unsigned short lomem; +unsigned short vntp; +unsigned short vntd; +unsigned short vvtp; +unsigned short stmtab; +unsigned short stmcur; +unsigned short starp; +unsigned short codestart; +unsigned short code_end; +unsigned short vnstart; +unsigned short vvstart; +int filelen; +const char *self; +unsigned char program[BUFSIZE]; +FILE *input_file; +FILE *output_file; + +void die(const char *msg) { + fprintf(stderr, "%s: %s\n", self, msg); + exit(1); +} + +/* read entire file into memory */ +int readfile(void) { + int got = fread(program, 1, BUFSIZE - 1, input_file); + if(verbose) fprintf(stderr, "Read %d bytes.\n", got); + if(!feof(input_file)) + fprintf(stderr, "Warning: file is >64KB, way too big for a BASIC program.\n"); + else if(got > MAX_PROG_SIZE) + fprintf(stderr, "Warning: file is %d bytes, suspiciously large for a BASIC program.\n", got); + fclose(input_file); + if(got < MIN_PROG_SIZE) + die("File too short to be a BASIC program (truncated?)\n"); + return got; +} + +/* get a 16-bit value from the file, in 6502 LSB/MSB order. */ +unsigned short getword(int addr) { + return program[addr] | (program[addr + 1] << 8); +} + +void setword(int addr, int value) { + program[addr] = value & 0xff; + program[addr + 1] = value >> 8; +} + +void dump_header_vars(void) { + fprintf(stderr, "LOMEM $%04x VNTP $%04x VNTD $%04x VVTP $%04x\n", lomem, vntp, vntd, vvtp); + fprintf(stderr, "STMTAB $%04x STMCUR $%04x STARP $%04x\n", stmtab, stmcur, starp); + fprintf(stderr, "vnstart $%04x, vvstart $%04x, codestart $%04x, code_end $%04x\n", vnstart, vvstart, codestart, code_end); +} + +void parse_header(void) { + lomem = getword(0); + vntp = getword(2); + vntd = getword(4); + vvtp = getword(6); + stmtab = getword(8); + stmcur = getword(10); + starp = getword(12); + codestart = stmtab - TBL_OFFSET - (vntp - 256); + vnstart = vntp - TBL_OFFSET; + vvstart = vvtp - TBL_OFFSET; + code_end = starp - TBL_OFFSET; + + if(filelen < code_end) { + fprintf(stderr, "Warning: file is truncated: %d bytes, should be %d.\n", filelen, code_end); + } + + if(verbose) dump_header_vars(); +} + +void update_header(void) { + setword(0, lomem); + setword(2, vntp); + setword(4, vntd); + setword(6, vvtp); + setword(8, stmtab); + setword(10, stmcur); + setword(12, starp); +} + +/* sometimes the variable name table isn't large enough to hold + 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(int offset) { + unsigned char *dest = program + vvstart + offset; + + if(dest < program || ((filelen + offset) > (BUFSIZE - 1))) { + die("Attempt to move memory out of range; corrupt header bytes?\n"); + } + + memmove(dest, program + vvstart, filelen); + + vntd += offset; + vvtp += offset; + stmtab += offset; + stmcur += offset; + starp += offset; + update_header(); + parse_header(); + filelen += offset; +} + +void adjust_vntable_size(int oldsize, int newsize) { + int move_by; + if(oldsize != newsize) { + move_by = newsize - oldsize; + if(verbose) 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); + } +} + +void invalid_args(const char *arg) { + fprintf(stderr, "%s: Invalid argument '%s'.\n\n", self, arg); + exit(1); +} + +FILE *open_file(const char *name, const char *mode) { + FILE *fp; + if(!(fp = fopen(name, mode))) { + perror(name); + exit(1); + } + return fp; +} + +void open_input(const char *name) { + if(!name) { + if(isatty(fileno(stdin))) { + die("Can't read binary data from the terminal."); + } + if(freopen(NULL, "rb", stdin)) { + input_file = stdin; + return; + } else { + perror("stdin"); + exit(1); + } + } + + input_file = open_file(name, "rb"); +} + +void open_output(const char *name) { + if(!name || (strcmp(name, "-") == 0)) { + if(isatty(fileno(stdout))) { + die("Refusing to write binary data to the terminal."); + } + if(freopen(NULL, "wb", stdout)) { + output_file = stdout; + return; + } else { + perror("stdout"); + exit(1); + } + } + output_file = open_file(name, "wb"); +} + +extern void set_self(const char *argv0) { + char *p; + + self = argv0; + p = strrchr(self, '/'); + if(p) self = p + 1; +} -- cgit v1.2.3