#include #define SECSIZE 256 /* Change this to handle 1050 dbl density disks */ #if SECSIZE == 256 #define SECCODE 1 #define SECTORS 18 #else #define SECCODE 0 #define SECTORS 26 #endif int ls_file(); int cat_file(); int dup_file(); char *dmainit(); FILE *fopen(), *bopen(); struct dta { char reserved[21]; char attr; int utime; int udate; long len; char name[13]; char dummy[3]; } fdata; int drive, cmd; int first; int save[5]; char seq[27] = {6,12,18,5,11,17,4,10,16,3,9,15,2,8,14,1,7,13,0xFF}; int bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; unsigned char *bp; int *seccnt; int tracks; int track_offset, sector_offset; unsigned int bpp = 0; unsigned int sectormask; int bin_flag = 0; int eofflag = 0; char dirname[100]; unsigned char buf[1024]; unsigned char map[1280]; unsigned char dirbuf[1024]; unsigned char wkbuf[8192]; unsigned char dosbuf[10240]; main(argc, argv) int argc; char *argv[]; { int sec, ct; char *p, *argp; bp = dmainit(buf); #ifdef DEBUG if (bp != buf) printf("Buffer base moved from %x to %x\n", buf, bp); #endif seccnt = (int *) &map[3]; for (ct=0; ct<1280; ct++) map[ct] = 0; first = '\t'; dirname[0] = '\0'; drive = 0; track_offset = -40; tracks = 40; sector_offset = -1; while (--argc >= 0) { argp = *++argv; if ((argp[0] == '/' || argp[0] == '-')) { if (argp[2] == '\0') { /* Ascii/Binary/Command */ if (argp[1] == 'B' || argp[1] == 'b') bin_flag = 1; else if (argp[1] == 'A' || argp[1] == 'a') bin_flag = 0; else /* Command */ cmd = argp[1] & 0xDF; } else if (stricmp(argp+1, "boot") == 0) { cmd = 'F'; } else if (argp[1] == 'T' || argp[1] == 't') { /* ATR format */ track_offset = - atoi(&argp[2]); tracks = (track_offset > -60)? 40: 80; } else if (argp[1] == 'P' || argp[1] == 'p') { /* Percom format */ track_offset = atoi(&argp[2]); tracks = (track_offset < 60)? 40: 80; } else if (argp[1] == 'S' || argp[1] == 's') { /* Initial sector # */ sector_offset = atoi(&argp[2]); } } else if (argp[1] == ':' && argp[2] == '\0') { /* Drive specifier */ drive = (argp[0]-'A') & 0x1F; break; } else if (argp[1] == '\0') { cmd = argp[0] & 0xDF; break; } else { argv--; argp++; break; } } #ifdef DEBUG printf ("Binary flag = %s\n", bin_flag? "on": "off"); printf ("Tracks = %d, offset = %d, sector offset = %d\n", tracks, track_offset, sector_offset); printf("CMD=%c, DRIVE=%c:\n", cmd, drive+'A'); #endif savefb(SECCODE,SECTORS,save); #ifdef DEBUG printf("SAVE=0x%04X.0x%04X.0x%04X.0x%04X.0x%04X\n", save[0], save[1], save[2], save[3], save[4]); #endif switch (cmd) { case 'W': /* Write directories or files(from MSDOS) */ getmap(drive); msdir(argc,&argv[1]); putmap(drive); break; case 'I': /* Initialize (Format) an Atari Disk */ fmtdisk(drive); break; case 'L': /* List an Atari Directory */ listdir(361, ls_file); break; case 'P': /* Display/Print Atari (printable) files */ listdir(361, cat_file); break; case 'R': /* Read Atari formatted disk files(to MSDOS)*/ listdir(361, dup_file); break; case 'F': /* Fetch the boot sectors from the disk */ fetchboot(argv[1], drive); break; default: printf ("Invalid switch: only L/istDir, P/rintFiles, R/eadFiles,\n"); printf (" W/riteFiles or I/nitializeDisk\n"); printf ("Usage: util /L|/P|/R|/I [/B|/A] [/T80|/P80] [A|B|C|D]: or\n"); printf (" util /W [A|B|C|D]: file [file ... ]\n"); printf ("\n"); printf (" L = list directory(s) of a MYDOS format diskette\n"); printf (" P = print files from a MYDOS format diskette\n"); printf (" R = read files from a MYDOS format diskette\n"); printf (" I = initialize MYDOS format double density disk\n"); printf (" W = write listed files to a MYDOS format diskette\n"); printf ("\n"); printf (" B = transfer data as a binary file (no translation)\n"); printf (" A = perform ATASCII to/from ASCII translation (default)\n"); printf ("\n"); printf (" Tn = double sided (ATR8000) diskettes have \"n\" tracks\n"); printf (" Pn = double sided (Percom) diskettes have \"n\" tracks\n"); printf (" Sn = nonstandard diskettes have \"n\" as the first\n"); printf (" sector (usually 0), the default value is 1\n"); } restfb(save); } dump() { int ct; char *p; for (p=bp, ct=0; ct != 256; p += 16, ct += 16) { printf ("%03X %02X%02X %02X%02X %02X%02X %02X%02X", ct, p[0]&0xFF, p[1]&0xFF, p[2]&0xFF, p[3]&0xFF, p[4]&0xFF, p[5]&0xFF, p[6]&0xFF, p[7]&0xFF); printf (" %02X%02X %02X%02X %02X%02X %02X%02X\n", p[8]&0xFF, p[9]&0xFF, p[10]&0xFF, p[11]&0xFF, p[12]&0xFF, p[13]&0xFF, p[14]&0xFF, p[15]&0xFF); } } listdir(sec, filefunc) int sec; int (*filefunc)(); { int k, j, i, *num; unsigned char *p, *tp, *dp; char text[30]; printf("Files in \"%c:%s\"\n", drive+'A', dirname); for (j=0; j<1024; sec++) { if (aread(sec, drive, bp)) { printf("Failure reading directory! Operation aborted!\n"); return; } #ifdef TRACE dump(); #endif for (i=0; i < 128;) dirbuf[j++] = bp[i++]; } #ifdef DEBUG printf("Directory read:\n"); #endif for (p=dirbuf; p < dirbuf+1024; p+=16) { if (*p == 0) { #ifdef DEBUG printf("End of directory at byte %d\n", p-dirbuf); #endif break; } #ifndef DEBUG if ((*p & 0x91) != 0x00) continue; #endif for (tp=text, dp=p+5; *dp > ' ' && dp != p+13;) *tp++ = *dp++; if (p[13] > ' ') { *tp++ = '.'; *tp++ = p[13]; if (p[14] > ' ') { *tp++ = p[14]; if (p[15] > ' ') *tp++ = p[15]; } } *tp = '\0'; num = (int *) (p+1); (*filefunc)(text, num[1], num[0], *p); } if (first == '\n') { putchar('\n'); first = '\t'; } for (p=dirbuf; p < dirbuf+1024; p+=16) { if (*p == 0) return; if ((*p & 0x91) != 0x10) continue; for (tp=text, dp=p+5; *dp > ' ' && dp != p+13;) *tp++ = *dp++; if (p[13] > ' ') { *tp++ = '.'; *tp++ = p[13]; if (p[14] > ' ') { *tp++ = p[14]; if (p[15] > ' ') *tp++ = p[15]; } } *tp = '\0'; #ifdef DEBUG printf("Subdirectory :%s!\n", text); #endif num = (int *) (p+1); k = strlen(dirname); dirname[k] = '\\'; dirname[k+1] = '\0'; strcat(dirname, text); if (cmd = 'D') if (cd(text) != 0) if (md(text) != 0) { printf("Cannot use or create directory \"%s\"\n", text); return; } listdir(num[1], filefunc); if (cmd == 'D') cd(".."); dirname[k] = '\0'; } } ls_file(name, at, size, flags) char *name; int at, size, flags; { printf ("%c%c%c%-12s[%04X] %d secs%c", flags&0x20?'*':' ', flags&0x10?':':' ', flags&0x04?'!':flags&0x02?' ':'#', name, at, size, first); first ^= '\n' ^ '\t'; } cat_file(name, at, size, flags) char *name; int at, size, flags; { int x, ct; unsigned char *p; printf("Print %s(%ld bytes, f=%02X)?", name, size*((long)SECSIZE-3L), flags); x = getchar() & 0xDF; if (x != '\n') while (getchar() != '\n') ; if (x == 'Y') { for (x = at; x != 0; x = ((bp[SECSIZE-3]<<8)+bp[SECSIZE-2]) & 0x03FF) { while (aread(x, drive, bp)) printf ("5 Failures reading sector on Atari disk\n"); for (ct=bp[SECSIZE-1], p=bp; ct > 0; ct--, p++) { if (*p == 0x7F) putchar('\t'); else if (*p == 0x9B) putchar('\n'); else putchar(*p); } } } } dup_file(name, at, size, flags) char *name; int at, size, flags; { int x, ct, mask; char binary_copy; unsigned char *p; FILE *outf; binary_copy = bin_flag; printf("Copy %s(%ld bytes, f=%02X)?", name, size*((long)SECSIZE-3L), flags); mask = (flags & 0x04)? 0xFF: 0x03; x = getchar() & 0xDF; if (x != '\n') while (getchar() != '\n') ; if (x == 'Y' || x == 'A' || x == 'B') { if (x == 'A') binary_copy = 0; else if (x == 'B') binary_copy = 1; outf = bopen(name, "wb"); if (outf == NULL) { printf ("Cannot create file \"%s\"", name); return; } for (x = at; x != 0; x = ((bp[SECSIZE-3]&mask) << 8)+(bp[SECSIZE-2] & 0xFF)) { while (aread(x, drive, bp)) printf ("5 Failures reading sector on Atari disk\n"); #ifdef DEBUG printf ("Link data = %02x, %02x, %02x\n", bp[SECSIZE-3], bp[SECSIZE-2], bp[SECSIZE-1]); #endif for (ct=bp[SECSIZE-1], p=bp; ct > 0; ct--, p++) { #ifdef TRACE putchar(*p); #endif if (binary_copy) bput(*p, outf); else if (*p == 0x7F) bput('\t', outf); else if (*p == 0x9B) { bput('\r', outf); bput('\n', outf); } else bput(*p, outf); } } bclose(outf); } } getmap(drive) int drive; { int p, n, k; char *mp; for (mp = map, n=0; n++ < sizeof(map);) *mp++ = 0; mp = map; n = 360; p = 3; do { if (aread (n--, drive, bp)) { printf ("Unable to read the Atari disk VTOC/Bit Map! Program aborted!\n"); exit(1); } for (k=0; k<256; k++) *mp++ = bp[k]; if (map[0] > (sizeof(map)/256 + 2)) { printf ("Invalid drive, more than %d sectors\n", (sizeof(map) - 10)*8); exit(1); } } while (++p <= map[0]); #ifdef DEBUG printf ("Drive %c: map header: <%02X> %02x%02x %02x%02x ", drive+'A', map[0], map[2], map[1], map[4], map[3]); printf ("%02x %02x %02x %02x %02x\n", map[5], map[6], map[7], map[8], map[9]); #endif if (map[0] >= 4) sectormask = 0xFFFF; else sectormask = 0x03FF; } putmap(drive) int drive; { int p, n, k; char *mp; mp = map; n = 360; p = map[0]; do { for (k=0; k<256; k++) bp[k] = *mp++; awrite (n--, drive, bp); } while (--p >= 3); #ifdef DEBUG printf ("Drive %c: map header: <%02X> %02x%02x %02x%02x ", drive+'A', map[0], map[2], map[1], map[4], map[3]); printf ("%02x %02x %02x %02x %02x\n", map[5], map[6], map[7], map[8], map[9]); #endif } msdir(argc,argv) int argc; char *argv[]; { int rc, k, sc, fno, bk, bk0, bkn; int base; FILE *inf; restfb(save); bkn = -1; while (--argc > 0) { #ifdef DEBUG printf ("Argument <<%s>>\n", *argv); #endif if ((rc = ffirst(&fdata, *argv)) == 0) { do { printf ("Copying <<%s>>, Length = %ld\n", fdata.name, fdata.len); inf = fopen(fdata.name, (bin_flag? "rb": "r")); savefb(SECCODE,SECTORS,save); fno = dirfnd(fdata.name); k = (fno<<4) & 0x0070; bk0 = bp[k+3] | (bp[k+4]<<8); if (bp[0] != 0 && (bp[0] & 0x80) == 0) { if (bk0 != 0) { #ifdef DEBUG printf(" Freeing %d\n", bk0); #endif dealloc(bk0); } } else bk0 = 0; bk = alloc(); bp[k+3] = bk; bp[k+4] = bk>>8; k = (fno>>3) + 361; #ifdef DEBUG printf (" Writing dir bk. %d, drive %c:\n", k, drive+'A'); printf (" First block = %d (FNO=%d)", bk, fno); if (bk0 != 0) printf(", replacing %d\n", bk0); else printf ("\n"); #endif awrite(k, drive, bp); if (bk0 != 0) { while (1) { aread(bk0, drive, bp); bk0 = (bp[SECSIZE-2] | (bp[SECSIZE-3] << 8)) & sectormask; if (bk0 == 0) break; #ifdef DEBUG printf(" Freeing %d\n", bk0); #endif dealloc(bk0); } } restfb(save); sc = 1; fno <<= 2; eofflag = k = 0; while (!eofflag && (rc = dosinput(k, inf))) { savefb(SECCODE,SECTORS,save); base = 0; while (base < rc - (SECSIZE-3)) { bkn = alloc(); if (bkn <= 0) { printf ("No more sectors available\n"); break; } #ifdef DEBUG printf (" Writing block %d (fno=%02X/%d,link=%d)\n", bk, fno, fno >> 2, bkn); #endif for (k=0; k>8); bp[SECSIZE-2] = bkn & 0xFF; bp[SECSIZE-1] = SECSIZE-3; awrite(bk, drive, bp); bk = bkn; base += SECSIZE-3; sc++; } for (k=0; k+base= 0) bp[k] = dosbuf[k]; awrite(bk, drive, bp); bk = bk0; dirup(sc, 0x42, fno>>2); restfb(save); fclose(inf); } while (fnext(&fdata) == 0 && bkn != 0); } else printf ("%s <<%s>>\n", rc<18? "Invalid path for": "No matching file", *argv); argv++; } savefb(SECCODE,SECTORS,save); } dirfnd(name) char *name; { char *name0, *cp; char namev[12]; int j, k, first; k = 0; for (j=0; j<11; j++) namev[j] = ' '; namev[11] = '\0'; while (*name != '.' && *name != '\0') { namev[k++] = *name++; if (k >= 11) break; } if (k < 11 && *name == '.') { k = 8; while (*++name != '\0' && k < 11) { if (*name == '\n') break; namev[k++] = *name; } } first = -1; for (k=361; k<369; k++) { if (aread(k, drive, bp)) { printf ("Unable to read ROOT directory for updating! Program aborted!\n"); exit(1); } for (j=0; j<0x80; j += 0x10) { if (namecomp(&bp[j+5], namev)) { first = ((k-361)<<3) + (j>>4); #ifdef DEBUG printf(" Replaced file no. = %d\n", first); #endif return (first); } if (bp[j] == 0) { if (first < 0) first = ((k-361)<<3) + (j>>4); goto allcf; } if ((bp[j] & 0x80) && first < 0) first = ((k-361)<<3) + (j>>4); } } allcf: #ifdef DEBUG printf ("allocated file no. = %d\n", first); #endif if (first < 0) { printf ("No directory entries free\n"); exit(1); } if ((first>>3) != (k-361)) while (aread((first>>3)+361, drive, bp)) ; cp = &bp[(first & 0x07)<<4]; *cp = 0x03; cp += 5; for (k=0; k<11; k++) *cp++ = namev[k]; #ifdef DEBUG printf ("%s==>%s(FNO=%d)\n", name0, namev, first); #endif return (first); } dirup(cnt, attr, indx) int cnt, attr, indx; { int k; while (aread(361+(indx>>3), drive, bp)) ; k = (indx<<4) & 0x0070; bp[k] = attr; *(int *)(&bp[k+1]) = cnt; awrite(361+(indx>>3), drive, bp); } alloc() { int p, x, mask; for (x=10; map[x] == 0; x++) if (x >= 1280) return(0); p = (x-10)<<3; mask = 0x80; while ((map[x] & mask) == 0) { mask >>= 1; p++; } map[x] &= ~mask; --*seccnt; return (p); } dealloc(sec) int sec; { map[(sec >> 3) + 10] |= bitmask[sec & 0x07]; ++*seccnt; } namecomp(a, b) char *a, *b; { int i; for (i=0; i<11; i++) if (*a++ != *b++) return(0); return (1); } FILE *bopen(name, mode) char *name, *mode; { FILE *val; restfb(save); val = fopen(name, mode); savefb(SECCODE,SECTORS,save); return (val); } bput(data, out) int data; FILE *out; { int len; if (bpp >= sizeof(dosbuf)) { restfb(save); len = fwrite (dosbuf, 1, sizeof(dosbuf), out); if (len != sizeof(dosbuf)) printf ("Error writing to DOS file, %d bytes not written\n", sizeof(dosbuf) - len); #ifdef DEBUG printf("Writing block of %d bytes to DOS file\n", sizeof(dosbuf)); #endif bpp = 0; savefb(SECCODE,SECTORS,save); } dosbuf[bpp++] = data; } bclose(out) FILE *out; { int len; restfb(save); if (bpp != 0) { len = fwrite(dosbuf, 1, bpp, out); if (len != bpp) printf ("Error closing file, %d bytes not written\n", bpp - len); } #ifdef DEBUG printf ("Last file block contains %d bytes\n", bpp); #endif bpp = 0; fclose(out); savefb(SECCODE,SECTORS,save); } fmtdisk(drive) int drive; { int ct; for (ct=0; ct<40; ct++) { if (aformat(ct, drive, bp, seq) < 0) printf ("Error formatting track %d\n", ct); } for (ct=0; ct<512; ct++) map[ct] = 0; map[0] = 2; map[1] = map[3] = 0xc4; map[2] = map[4] = 0x02; for (ct=4; ct<360; ct++) dealloc(ct); for (ct=369; ct<720; ct++) dealloc(ct); for (ct=0; ct<1024; ct++) dirbuf[ct] = 0; putmap(drive); for (ct=361; ct < 369; ct++) awrite(ct, drive, dirbuf); } dosinput(beg, fd) int beg; /* first free byte in buffer */ FILE *fd; { int k, rc; for (k=beg; k<10240; k++) { if ((rc = fgetc(fd)) < 0) { eofflag = 1; break; } if (!bin_flag) { if (rc == '\t') rc = 0x7F; else if (rc == '\n') rc = 0x9B; } dosbuf[k] = rc; } return k; } fetchboot(file, drive) char *file; int drive; { FILE *outf; aread(1, drive, dosbuf); aread(2, drive, dosbuf+0x80); aread(3, drive, dosbuf+0x100); restfb(save); outf = fopen(file, "wb"); fwrite (dosbuf, 1, 0x180, outf); fclose(outf); exit(0); }