aboutsummaryrefslogtreecommitdiff
path: root/axelib.c
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2022-08-29 16:11:13 -0400
committerB. Watson <urchlay@slackware.uk>2022-08-29 16:11:13 -0400
commite2ba8458a5cfdfacfaf103e7ba97d610afa6c970 (patch)
treecd665e602e6e2b636578a7d3d7894380605dafcc /axelib.c
downloadbw-atari8-tools-e2ba8458a5cfdfacfaf103e7ba97d610afa6c970.tar.gz
initial commit
Diffstat (limited to 'axelib.c')
-rw-r--r--axelib.c546
1 files changed, 546 insertions, 0 deletions
diff --git a/axelib.c b/axelib.c
new file mode 100644
index 0000000..2b6e66b
--- /dev/null
+++ b/axelib.c
@@ -0,0 +1,546 @@
+#include "axe.h"
+
+extern int all, total_sec, translate;
+
+static int atr_offset;
+
+int load_disk(unsigned char *diskbuf, char *filename) {
+ FILE *file;
+ int vtoc_sec;
+ unsigned char tmpbuf[16];
+ char tmp[128];
+
+ if((file = fopen(filename, "r")) == NULL) {
+ sprintf(tmp, "load_disk(): %s", filename);
+ perror(tmp);
+ exit(1);
+ }
+ fread(tmpbuf, 16, 1, file);
+ atr_offset = 16;
+ memcpy(diskbuf, tmpbuf, 16);
+ if((tmpbuf[0] != 0x96) || (tmpbuf[1] != 0x02)) { /* not an atr */
+ atr_offset = 0;
+ rewind(file);
+ total_sec = 720;
+ }
+
+ /* do some sanity checking of images: */
+ if(atr_offset) {
+ total_sec = (diskbuf[2] + 256 * diskbuf[3]) >> 3;
+ if(!total_sec)
+ total_sec = (diskbuf[6] + 256 * diskbuf[7]) * 8192;
+ if(total_sec < 720) {
+ printf("Total sectors (%d) < 720 - aborting\n", total_sec);
+ exit(1);
+ }
+ if(total_sec > 720) {
+ printf
+ ("Warning: Total sectors (%d) > 720 - only reading first 720 sectors\n",
+ total_sec);
+ }
+ if((diskbuf[4] + 256 * diskbuf[5]) != 128) {
+ printf("Fatal: sector size not 128 bytes!\n");
+ exit(1);
+ }
+ } else {
+ printf
+ ("Warning: blindly assuming xfd image is 720 sectors, 128 bytes/sector!\n");
+ }
+
+ if((total_sec = fread(diskbuf + atr_offset, 128, 720, file)) < 720) {
+ printf("Error reading image file, only got %d sectors, aborting\n", total_sec);
+ perror("fread");
+ exit(1);
+ }
+
+ vtoc_sec =
+ diskbuf[atr_offset + 128 * 359 + 1] + 256 * diskbuf[atr_offset +
+ 128 * 359 + 2];
+ if(vtoc_sec != 707)
+ printf
+ ("Warning: VTOC sector count (%d) not 707, are you sure this is an AtariDOS 2.0 image?\n",
+ vtoc_sec);
+ return 0;
+}
+
+int write_disk(unsigned char *diskbuf, char *filename) {
+ FILE *file;
+ unsigned char tmpbuf[16];
+
+ file = fopen(filename, "w");
+ memcpy(tmpbuf, diskbuf, 16);
+ atr_offset = 0;
+ if((tmpbuf[0] == 0x96) && (tmpbuf[1] == 0x02)) { /* is an atr */
+ fwrite(tmpbuf, 16, 1, file);
+ atr_offset = 16;
+ }
+ fwrite(diskbuf + atr_offset, 128, 720, file);
+ fclose(file);
+ return 0;
+}
+
+
+void usage(char *name) {
+ printf
+ ("Usage: %s [options] [-D filename] [-w filename] [-e filename]\n\t\t [-b filename] [-c dirname] [-d sector] disk_image\n\n",
+ name);
+
+ printf("\t-a\tlist all dir entries, even deleted/empty ones\n");
+ printf("\t-l\ttrace & print links for all files on disk\n");
+ printf("\t-v\tdump VTOC (sector 360) in decimal, hex, and binary\n");
+ printf
+ ("\t-t\t'tar xf' style - create dir filled with files in image\n");
+ printf("\t-u\tUn*x <-> Atari newline/EOL translation\n");
+ printf("\t-D\tdelete file from image\n");
+ printf("\t-w\twrite file to image\n");
+ printf("\t-c\tcreate new image from directory\n");
+ printf("\t-x\textract (read) file from image, write to current dir\n");
+ printf("\t-b\tcreate blank image called 'filename'\n");
+ printf("\t-d\tdump a sector in decimal, hex, and binary\n");
+ printf
+ ("\ndisk_image must be a 720 sector, single density .atr or .xfd image\n");
+ printf("\tin Atari DOS 2.0 or compatible format\n");
+ printf
+ ("\nAll UN*X filenames must conform to Atari 8.3 filename.ext format\n");
+ printf("\t(though they are NOT treated case-sensitively)\n");
+ printf("\nEnjoy!\n\n");
+ exit(1);
+}
+
+void print_entry(unsigned char *buf) {
+#ifdef DEBUG
+ static int ents;
+ int i;
+#endif
+ int s;
+ unsigned char tmpbuf[32];
+
+ memcpy(tmpbuf, buf, 16);
+ tmpbuf[16] = '\0';
+#ifdef DEBUG
+ printf("successfully read dir. entry #%d\n", ents++);
+#endif
+ if((tmpbuf[0] & 64) || all) {
+#ifdef DEBUG
+ for (i = 0; i < 16; i++) {
+ printf(" 0x%X", tmpbuf[i]);
+ }
+#endif
+ total_sec += (s = tmpbuf[1] + 256 * tmpbuf[2]);
+ printf("%c %s\t%03d\n", (tmpbuf[0] & 32) ? '*' : ' ', tmpbuf + 5,
+ s);
+ }
+}
+
+void read_sector(unsigned char *disk, int sector, unsigned char *buf) {
+ memcpy(buf, disk + (sector - 1) * 128 + atr_offset, 128);
+}
+
+void write_sector(unsigned char *disk, int sector, unsigned char *buf) {
+ memcpy(disk + (sector - 1) * 128 + atr_offset, buf, 128);
+}
+
+void traverse_file(unsigned char *disk, unsigned char *ent, int action) {
+ int i, next_sec, data_bytes, curfile;
+ unsigned char buf[128];
+ unsigned char vtoc[128];
+
+#ifdef DEBUG
+ printf("traverse_file called with %s\n",
+ (action - 1) ? "TF_DELETE" : "TF_PRINT");
+#endif
+
+ if(action == TF_DELETE)
+ read_sector(disk, 360, vtoc);
+
+ next_sec = ent[3] + 256 * ent[4];
+ while(next_sec) {
+ if(action == TF_DELETE)
+ mark_free(vtoc, next_sec);
+ if(action == TF_PRINT)
+ printf("%d: ", next_sec);
+ read_sector(disk, next_sec, buf);
+ data_bytes = buf[127];
+ curfile = buf[125] >> 2;
+ next_sec = buf[126] + 256 * (buf[125] & 3);
+ if(action == TF_PRINT)
+ printf("data_bytes=%d filenum=%d next_sec=%d\n", data_bytes,
+ curfile, next_sec);
+ }
+ if(action == TF_DELETE) {
+ i = (vtoc[3] + 256 * vtoc[4]);
+#ifdef DEBUG
+ printf("deleting file, old vtoc free count=%d", i);
+#endif
+ i += ent[1] + 256 * ent[2];
+#ifdef DEBUG
+ printf(", new=%d\n", i);
+#endif
+ vtoc[3] = i % 256;
+ vtoc[4] = i / 256;
+ write_sector(disk, 360, vtoc);
+ if(action == TF_DELETE) {
+ printf("Deleted file, now %d free sectors on image\n", i);
+ }
+ }
+}
+
+void dump_file(unsigned char *disk, unsigned char *ent, char *outfile) {
+#ifdef DEBUG
+ int curfile;
+#endif
+ int i, next_sec, data_bytes, total_written = 0;
+ unsigned char buf[128];
+ FILE *out;
+
+/* fseek(handle,atr_seek(361)+16*filenum,SEEK_SET);
+ fread(buf,16,1,handle); */
+ next_sec = ent[3] + 256 * ent[4];
+ out = fopen(outfile, "wb");
+/* #ifdef DEBUG
+ printf("First sector of filenum %d, ",filenum);
+ #endif */
+ while(next_sec) {
+#ifdef DEBUG
+ printf("%d: ", next_sec);
+#endif
+ read_sector(disk, next_sec, buf);
+ data_bytes = buf[127];
+ next_sec = buf[126] + 256 * (buf[125] & 3);
+#ifdef DEBUG
+ curfile = buf[125] >> 2;
+ printf("data_bytes=%d filenum=%d next_sec=%d\n", data_bytes, curfile,
+ next_sec);
+#endif
+ if(translate)
+ for (i = 0; i <= data_bytes; i++)
+ if(buf[i] == 0x9b)
+ buf[i] = '\n';
+ fwrite(buf, data_bytes, 1, out);
+ total_written += data_bytes;
+ fflush(out);
+ }
+ printf("Wrote %d bytes to file %s\n", total_written, outfile);
+}
+
+
+int parse_filename(char *filename, char *result) {
+ int i = 0, j = 0;
+ char ext[4] = " \0";
+ char fn[9] = " \0";
+#ifdef DEBUG
+ printf("parse_filename called, filename=%s\n", filename);
+#endif
+ if(strlen(filename) > 12) {
+ printf("filename too long: %s\n", filename);
+ exit(1);
+ }
+/* if(strlen(strstr(filename,"."))>4) {
+ printf("extension too long: %s\n",filename);
+ exit(1);
+ } */
+ while((filename[i]) && (filename[i] != '.')) {
+ fn[i++] = toupper(filename[i]);
+ }
+ if(filename[i] == '.')
+ while(filename[++i]) {
+ ext[j++] = toupper(filename[i]);
+ }
+
+ strcpy(result, fn);
+ strncat(result, ext, 3);
+#ifdef DEBUG
+ printf("parse_filename exiting, result=%s\n", result);
+#endif
+ return (0);
+}
+
+int make_filename(char *filename, char *result) {
+ int i = 0, j = 8;
+ char fn[13] = { '\0' };
+
+ while((filename[i] && filename[i] != ' ') && (i < 8)) {
+ fn[i++] = tolower(filename[i]);
+ }
+ if(filename[j] != ' ') {
+ fn[i++] = '.';
+ while(filename[j]) {
+ fn[i++] = tolower(filename[j++]);
+ }
+ }
+#ifdef DEBUG
+ printf("made filename %s from %s\n", fn, filename);
+#endif
+ strcpy(result, fn);
+ return 0;
+}
+
+int make_dir(char *filename) {
+ char tmp[15] = { '\0' };
+ char *p;
+
+ strcpy(tmp, filename);
+ if(!(p = strrchr(tmp, '.'))) {
+ strcat(tmp, ".dir");
+ } else {
+ *p = '\0';
+ }
+#ifdef DEBUG
+ printf("made dir: %s\n", tmp);
+#endif
+ if(mkdir(tmp, 0777)) {
+ perror("Can't make directory: ");
+ exit(1);
+ }
+ chdir(tmp);
+ return 0;
+}
+
+void dump_sector(unsigned char *disk, int sector) {
+ unsigned char buf[256];
+ int i, j, k;
+ printf("Dump of sector %d in decimal:\n", sector);
+ read_sector(disk, sector, buf);
+ for (i = 0; i < 128; i += 16) {
+ printf("%03d: ", i);
+ for (j = 0; j < 16; j++) {
+ printf("%03d ", buf[i + j]);
+ }
+ printf("\n");
+ }
+ printf("Dump of sector %d in hex:\n", sector);
+ for (i = 0; i < 128; i += 16) {
+ printf("%03x: ", i);
+ for (j = 0; j < 16; j++) {
+ printf(" %02x ", buf[i + j]);
+ }
+ printf("\n");
+ }
+ printf("Dump of sector %d in binary:\n", sector);
+ for (i = 0; i < 128; i += 16) {
+ printf("%03x: ", i);
+ for (j = 0; j < 16; j++) {
+ for (k = 7; k > -1; k--) {
+ if(buf[i + j] & (1 << k))
+ printf("1");
+ else
+ printf("0");
+ }
+ printf(" ");
+ if(j == 7)
+ printf("\n ");
+ }
+ printf("\n");
+ }
+}
+
+
+/* please, ignore the ugliness of this function:*/
+void write_blank_disk(char *filename) {
+ unsigned char atr_header[16] = { 0x96, 0x02, 0x80, 0x16, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ unsigned char disk[128 * 720 + 16] = { '\0' };
+ int i;
+ unsigned char vtoc[128] =
+ { 0x02, 0xc3, 0x02, 0xc3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f
+ };
+
+ for (i = 11; i < 100; i++)
+ vtoc[i] = 0xff;
+ vtoc[55] = 0x00;
+ vtoc[56] = 0x7f;
+ for (i = 100; i < 128; i++)
+ vtoc[i] = 0x00;
+ atr_offset = 16;
+ memcpy(disk, atr_header, 16);
+ write_sector(disk, 360, vtoc);
+ write_disk(disk, filename);
+ printf("Wrote formatted blank image to %s\n", filename);
+}
+
+static void xlate_eofs(unsigned char *buf, int len) {
+ int i;
+ for (i = 0; i < len; i++)
+ if(buf[i] == '\n')
+ buf[i] = 0x9b;
+}
+
+void write_file(unsigned char *disk, char *filename) {
+ unsigned char vtoc[128];
+ unsigned char buf[128];
+ char fnbuf[15];
+/* unsigned char dentry[16];*/
+ unsigned char *dindex;
+ int i, dentryno, first_sec, secno, next_sec, count = 0, bytes;
+ FILE *handle;
+
+ printf("Writing %s to image...", filename);
+ parse_filename(filename, fnbuf);
+ if((handle = fopen(filename, "r")) == NULL) {
+ perror("write_file::fopen");
+ exit(1);
+ }
+#ifdef DEBUG
+ printf("write_file: parsed %s as \"%s\"\n", filename, fnbuf);
+#endif
+ if((dentryno = get_dentry(disk)) == -1) {
+ printf("write_file: no free directory entries on image\n");
+ exit(1);
+ }
+#ifdef DEBUG
+ printf("dentryno=%d\n", dentryno);
+#endif
+ read_sector(disk, 360, vtoc);
+ if(!(first_sec = secno = get_free_sector(vtoc))) {
+ printf("write_file: no free sectors in image\n");
+ exit(1);
+ }
+#ifdef DEBUG
+ printf("first_sec=%d\n", first_sec);
+#endif
+ do {
+ int tmp, eof = 0;
+ count++;
+ bytes = fread(buf, 1, 125, handle);
+
+ if(bytes == 125) {
+ /* test for EOF on handle */
+ tmp = fgetc(handle);
+ if(tmp == EOF)
+ eof = 1;
+ else
+ ungetc(tmp, handle);
+ }
+
+ if(translate) xlate_eofs(buf, 125);
+ mark_used(vtoc, secno);
+
+ if(bytes == 125 && !eof) {
+ /* full sector, not at EOF */
+ next_sec = get_free_sector(vtoc);
+ buf[125] = (dentryno << 2) | (next_sec >> 8);
+ buf[126] = next_sec & 255;
+ buf[127] = 125;
+ write_sector(disk, secno, buf);
+ secno = next_sec;
+ } else {
+ /* partial sector or full sector at EOF */
+ buf[125] = dentryno << 2;
+ buf[126] = 0;
+ buf[127] = bytes;
+ write_sector(disk, secno, buf);
+ next_sec = 0;
+ }
+ } while(next_sec);
+ /* update dentry */
+ read_sector(disk, 361 + (dentryno / 8), buf);
+ dindex = buf + (dentryno % 8) * 16;
+ dindex[0] = 66; /* taken from a dos 2.0s disk, hope its right */
+ dindex[1] = count & 255;
+ dindex[2] = count / 256;
+ dindex[3] = first_sec & 255;
+ dindex[4] = first_sec / 256;
+ memcpy(dindex + 5, fnbuf, 11);
+ write_sector(disk, 361 + (dentryno / 8), buf);
+ /*all thats left to do is update free sector count in vtoc: */
+ i = (vtoc[3] + 256 * vtoc[4]) - count;
+ vtoc[3] = i & 255;
+ vtoc[4] = i / 256;
+ write_sector(disk, 360, vtoc);
+ printf("Wrote %d sectors.\n", count);
+}
+
+int get_dentry(unsigned char *disk) {
+ int i = 361, j, dentryno = 0, done = 0;
+ unsigned char buf[128];
+
+ while(!done) {
+ read_sector(disk, i, buf);
+ for (j = 0; j < 128; j += 16) {
+ if((buf[j] == 0) || (buf[j] & 128)) {
+ return dentryno;
+ }
+ dentryno++;
+ }
+ done = (++i == 369);
+ }
+ return -1;
+}
+
+int get_free_sector(unsigned char *vtoc) {
+ int i;
+
+ for (i = 1; i < 720; i++) { /* atari DOS doesn't use sector 720 */
+ if(vtoc[vtoc_byte(i)] & vtoc_bit(i))
+ return i;
+ }
+
+ return 0;
+}
+
+int vtoc_byte(int sector) {
+ return 10 + (sector) / 8;
+}
+
+int vtoc_bit(int sector) {
+ return 128 >> ((sector) % 8);
+}
+
+void mark_used(unsigned char *vtoc_sector, int sector) {
+ vtoc_sector[vtoc_byte(sector)] &= ~vtoc_bit(sector);
+}
+
+void mark_free(unsigned char *vtoc_sector, int sector) {
+ vtoc_sector[vtoc_byte(sector)] |= vtoc_bit(sector);
+}
+
+/*int get_confirm(char *prompt) {
+ printf("%s[y/N]? ",prompt);
+ return ((toupper(getc(stdin)))=='Y');
+}*/
+
+int check_dir(unsigned char *disk, char *filename) {
+ int i = 361, j, done = 0, dentryno = 0;
+ unsigned char buf[128];
+
+ printf("check_dir: passed %s\n", filename);
+ while(!done) {
+ read_sector(disk, i, buf);
+ for (j = 0; j < 128; j += 16) {
+ if((strncmp(filename, (char*)(buf + j + 5), 11) == 0)) {
+ return dentryno;
+ }
+ dentryno++;
+ }
+ done = (++i == 369);
+ }
+
+ return -1;
+}
+
+/* these routines suck, and are not actually used any more.
+ * maybe someday they'll become useful again.
+ *
+ int delete_file(unsigned char *disk,char *filename) {
+ int first_sec,next_sec,i,dentryno;
+ char fnbuf[15];
+ char buf[128];
+ char *debuf;
+ char vtoc[128];
+
+ printf("delete_file doesn't work yet. passed: %s\n",filename);
+ parse_filename(filename,fnbuf);
+ if((dentryno=check_dir(disk,fnbuf))==-1) {
+ printf("delete_file: file %s not found on image\n",fnbuf);
+ exit(1);
+ }
+ printf("delete_file: would delete %s\n",fnbuf);
+ read_sector(disk,361+dentryno/8,buf);
+ read_sector(disk,360,vtoc);
+ debuf=buf+(dentryno%8)*16;
+ next_sec=debuf[3]+256*debuf[4];
+ traverse_file(disk,debuf,TF_DELETE);
+ return 0;
+}
+*/