crds@ncoast.UUCP (Glenn A. Emelko) (10/11/88)
Posting-number: Volume 4, Issue 119 Submitted-by: "Glenn A. Emelko" <crds@ncoast.UUCP> Archive-name: dos2coco Based upon the response in the past week regarding my MSDOS<->COCO file utilities, I've decided to post it to the net for all to see. It's not elegant by any means, and you'll probably find my assembler the easiest to follow of all of it, but it does all work. I submit this for use as public domain, with the only restriction that it not be used for profit by anyone in part or in whole without first contacting myself. This is in the true spirit of public domain, and I scoff at all of those people who post "shareware," so there. Glenn A. Emelko crds@ncoast snail-mail address: 305 Mentor Ave. Painesville, OH 44077 Allright, here it is... Have fun... #!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # dirc.asm # dirc.c # fromc.c # toc.c # This archive created: Sat Oct 8 08:06:14 1988 export PATH; PATH=/bin:$PATH if test -f 'dirc.asm' then echo shar: over-writing existing file "'dirc.asm'" fi cat << \SHAR_EOF > 'dirc.asm' CSEG SEGMENT PARA PUBLIC 'CODE' ;--------------- ; ; DIRC.COM -- all segments set to CSEG upon entry ; ; USAGE: ; DIRC [filename[.ext]]<CR> ; ; [filename[.ext]] is used to specify the file(s) whose ; directory you want to list. ; ; The information provided includes the free space on the disk. ; The freespace is listed both in Granules and Bytes. ; The display for each file includes its size in bytes, ; the number of granules it occupies, the file ; type, and the file mode. ; ; You may use the global characters ? and * in the filename and ; extention parameters. ; ; If you do not specify a filename, it defaults to *.* ; ; If you do not specify a filename extention, it defaults to *. ; ; ; To assemble this program, do the following: ; ; ; masm dirc; ; link dirc; ; exe2bin dirc.exe dirc.com ; erase dirc.exe ; ;--------------- ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:CSEG ORG 100H ;--------------- ; ; ENTRY -- Link to start of program (past variables) ; ;--------------- ENTRY: JMP START ;--------------- ; ; TEXT -- Directory listing header ; ;--------------- DRIVENAME EQU 'A' TEXT DB ' Volume in drive ',DRIVENAME,' is COCO disk',13,10 DB ' Directory of COCO disk',13,10,10,'$' DRIVENO EQU DRIVENAME-'A' ;--------------- ; ; TYPETAB, TYPEn -- Types for COCO directory entries ; ;--------------- TYPETAB DW TYPE0 DW TYPE1 DW TYPE2 DW TYPE3 TYPE0 DB 'BASIC $' TYPE1 DB 'Data $' TYPE2 DB 'Program $' TYPE3 DB 'Text $' ;--------------- ; ; ASCII, ASCIIn -- File modes for COCO directory entries ; ;--------------- ASCII DW ASCII0 DW ASCII1 ASCII0 DB 'Binary$' ASCII1 DB 'ASCII$' ;--------------- ; ; NUMFILES, GRANSFREE, BYTESFREE -- Text for directory ending printout ; ;--------------- NUMFILES DB ' File(s)$' GRANSFREE DB ' Grans, $' BYTESFREE DB ' Bytes free$' ;--------------- ; ; NUMBUF -- Expansion buffer for binary to decinal conversions ; ;--------------- NUMBUF DB 6 DUP (?) ;--------------- ; ; FCOUNT, GCOUNT -- File count and Granule count for dir info ; ;--------------- FCOUNT DW 0 GCOUNT DW 0 ;--------------- ; ; FILAOK, FILOK -- For wildcarding, File always ok and this file ok ; ;--------------- FILAOK DB 0 FILOK DB 0 ;--------------- ; ; GRANS, GSIZE, SECSIZE -- Number of grans on the disk, number of ; bytes per gran, and sector size ; ;--------------- GRANS DW 68 GSIZE DW 2304 SECSIZE DW 256 ;--------------- ; ; NBSEC -- Save area for MSDOS bytes per sector (changed, must restore) ; ;--------------- NBSEC DB 0 ;--------------- ; ; FAT -- FAT information buffer read from COCO disk ; ;--------------- FAT DB 256 DUP (?) ;--------------- ; ; DIRBUF -- Directory sector buffer read from COCO disk ; ;--------------- DIRBUF DB 256 DUP (?) ;--------------- ; ; START -- Start of DIRC.COM ; ;--------------- START: CALL CHECKAOK ;Set filaok if all files are ;to be listed MOV DX,OFFSET TEXT ;Print out directory header MOV AH,9 INT 21H XOR AX,AX ;Get MSDOS disk info pointer MOV ES,AX LES BX,ES:[78H] MOV AL,ES:[BX+3] ;Get MSDOS bytes per sector MOV NBSEC,AL ;and save it MOV BYTE PTR ES:[BX+3],1 ;Set bytes per sector to 256 PUSH CS ;Restore ES to CSEG POP ES ;--------------- ; ; Do disk FAT read, 1 sector, buffer=FAT, track 17, sector 2, side 0 ; disk B: ; ;--------------- MOV AX,0201H MOV BX,OFFSET FAT MOV CX,1102H MOV DX,DRIVENO INT 13H MOV CX,9 ;# of directory sectors ;--------------- ; ; RLOOP -- Main loop for directory read ; ;--------------- RLOOP: PUSH CX ;Save loop counter MOV AX,12 ;Calc sector number (3-11) SUB AX,CX MOV CX,AX MOV CH,17 ;Track number 17 MOV BX,OFFSET DIRBUF ;Buffer=DIRBUF MOV AX,0201H ;Read 1 sector MOV DX,DRIVENO ;Head 0, disk B: INT 13H ;Do BIOS read MOV CX,8 ;Number of entries in sector ;--------------- ; ; PNEXT -- Secondary loop, for each file within directory sector ; ;--------------- PNEXT: MOV AL,[BX] ;Get entry first byte OR AL,AL ;Zero, file has been killed JZ NEXTENT CMP AL,0FFH ;0FFh, no more in sector JZ LASTENT CALL CHECKFIL ;Check if entry is ok to list ;result: filok=1, yes PUSH CX ;Save count and buffer pointer PUSH BX ADD BX,11 ;Offset to file info CMP FILOK,1 ;This file to be listed ? JNZ NODISP1 ;No, skip display SUB BX,11 ;Point to file name again INC FCOUNT ;Count one more file listed MOV CX,8 ;Print out file name, 1 space, CALL PSTRING ;File extention, and 4 more MOV CX,1 ;Spaces. Adjust BX to file CALL SPACES ;Info MOV CX,3 CALL PSTRING MOV CX,4 CALL SPACES NODISP1: MOV AX,[BX+1] ;AL=file mode, AH=first gran # MOV CX,[BX+3] ;CX=# of bytes in last sector XCHG CH,CL ;6809 format (HIGH, LOW) MOV BL,[BX] ;BL is file type PUSH AX ;Save mode, gran, and type PUSH BX CALL CALCDISP ;Calc file size, and display POP BX ;Restore mode, gran, and type CMP FILOK,1 ;File ok to use? JNZ NODISP2 ;No, dont display XOR BH,BH ;Find text for file type SHL BX,1 MOV DX,TYPETAB[BX] MOV AH,9 ;Print text INT 21H POP BX ;BL=file mode PUSH BX ;Maintain stack integrety XOR BH,BH ;Z=nonascii file type OR BL,BL JZ NONASCII MOV BL,2 ;Offset for ASCII message NONASCII: MOV DX,ASCII[BX] ;Get message and print it MOV AH,9 INT 21H CALL CRLF ;Followed by CRLF NODISP2: POP AX ;Pop stack information POP BX POP CX ;Restore count for entries NEXTENT: ADD BX,20H ;Point to next entry LOOP PNEXT ;Loop for all 8 in sector LASTENT: POP CX ;Restore outer loop count LOOP RLOOPX ;Loop for all 9 sectors MOV CX,3 ;Last line, print disk info CALL SPACES ;3 spaces in MOV AX,FCOUNT ;Number of files CALL MAKENUM ;Make numeric and print MOV DX,OFFSET NUMFILES ;Print "File(s)" message MOV AH,9 INT 21H MOV AX,GRANS ;Number of grans free CALL MAKENUM ;Make numeric and print MOV DX,OFFSET GRANSFREE ;Print "Grans" message MOV AH,9 INT 21H MOV AX,GRANS ;Number of grans free MOV CX,2304 ;Compute bytes free MUL CX CALL MAKEBNUM ;Make big numeric and print MOV DX,OFFSET BYTESFREE ;Print "Bytes" message MOV AH,9 INT 21H CALL CRLF ;Do a CRLF XOR AX,AX ;Point to MSDOS disk info MOV ES,AX LES BX,ES:[78H] MOV AL,NBSEC ;Get MSDOS bytes per sector MOV ES:[BX+3],AL ;Restore to old value MOV AX,4C00H ;Exit to DOS, no errors INT 21H RLOOPX: JMP RLOOP ;Vector for loop (too far) ;--------------- ; ; SPACES -- print CX spaces on screen ; ;--------------- SPACES: MOV AH,2 MOV DL,' ' INT 21H LOOP SPACES RET ;--------------- ; ; PSTRING -- print string at BX with length CX, return BX=BX+CX ; ;--------------- PSTRING: MOV DL,[BX] INC BX MOV AH,2 INT 21H LOOP PSTRING RET ;--------------- ; ; CRLF -- Do CRLF to screen, dont use any registers ; ;--------------- CRLF: PUSH AX PUSH DX MOV AH,2 MOV DL,13 INT 21H MOV DL,10 INT 21H POP DX POP AX RET ;--------------- ; ; CALCDISP -- calculate file size, and display if necessary ; ;--------------- CALCDISP: MOV GCOUNT,0 ;File currently has no grans JMP CALCDISP1 ;Initialized, continue... NEXTGRAN: ADD CX,GSIZE ;Count more bytes in file CALCDISP1: MOV AL,AH ;Get gran number in AX XOR AH,AH DEC GRANS ;Drop gran from free space INC GCOUNT ;And add gran to file size MOV BX,OFFSET FAT ;Point to FAT info ADD BX,AX ;Point to GRAN entry for file MOV AH,[BX] ;Get next gran number or end OR AH,AH ;Sign set, last gran in file JNS NEXTGRAN XOR AL,AL ;Compute number of bytes left AND AH,3FH ;AH is number of sects, so DEC AH ;AX is number of bytes. Dont JS NOADD ;Count last (CX had it) ADD CX,AX ;More than 1 left, add 256*AH NOADD: MOV AX,CX ;Get number of bytes in file CMP FILOK,1 ;Do we print this? JNZ NODISP3 ;No... CALL MAKENUM ;Make numeric and print MOV AX,GCOUNT ;Get gran count for file CALL MAKENUM ;Make numeric and print MOV CX,2 ;Print 2 spaces CALL SPACES NODISP3: RET ;Done with calcdisp ;--------------- ; ; MAKENUM -- Make AX a decimal value, and print it to the screen ; ;--------------- MAKENUM: MOV BX,OFFSET NUMBUF ;NUMBUF is area for conversion XOR DX,DX ;DX:AX is number MOV CX,10000 ;Initial divisor DIVLP1: DIV CX ;AX=AX/CX, DX is remainder ADD AL,30H ;Convert it to ASCII MOV [BX],AL ;And put it in buffer INC BX MOV AX,CX ;Divide divisor by 10 PUSH DX ;Save remainder MOV CX,10 XOR DX,DX ;DX:AX is divisor DIV CX MOV CX,AX ;New divisor in CX POP AX ;Old remainder in AX CMP CX,1 ;Divisor=1 (done indicator) JNZ DIVLP1 ;No, loop for next character MOV CX,4 ;# of possible leading 0's ;--------------- ; ; LZDROPCOM -- Drop leading zero's (change to spaces) for CX counts ; Also puts last character in buffer at [BX] for callers ; ;--------------- LZDROPCOM: PUSH CX ;Save number of possible 0's ADD AL,30H ;Put last character in buffer MOV [BX],AL MOV BX,OFFSET NUMBUF ;Point to head of buffer LZDROP: CMP BYTE PTR [BX],30H ;Is this character a 0? JNZ DONE ;No, finished MOV BYTE PTR [BX],' ' ;Blank it INC BX LOOP LZDROP ;Go for CX characters DONE: MOV BX,OFFSET NUMBUF ;Print NUMBUF for CX+1 chars POP CX INC CX CALL PSTRING RET ;--------------- ; ; MAKENUM -- Make DX:AX a decimal value, and print it to the screen ; Max value is 199999 ;--------------- MAKEBNUM: MOV BX,OFFSET NUMBUF ;Output buffer MOV CX,10000 ;Initial divisor BDIVLP1: DIV CX ;AX DX:AX/CX, DX is remainder CMP CX,10000 ;If first division, make 2 dig JNZ DDD1 ;Not first... MOV AH,30H ;Set first digit to 0 CMP AL,10 ;2nd digit >9? JB NOAH ;No MOV AH,31H ;First digit=1 SUB AL,10 ;2nd digit is AL-10 NOAH: MOV [BX],AH ;Place first digit INC BX ;Position to second DDD1: ADD AL,30H ;Convert this digit to ASCII MOV [BX],AL ;Place digit in buffer INC BX MOV AX,CX ;Divisor=divisor/10 PUSH DX ;Save old remainder MOV CX,10 XOR DX,DX ;DX:AX is divisor DIV CX MOV CX,AX ;CX is new divisor POP AX ;AX is old remainder CMP CX,1 ;Divisor=1? JNZ BDIVLP1 ;No, continue MOV CX,5 ;Max number of leading zeros JMP LZDROPCOM ;Go drop any leading zeros ;--------------- ; ; CHECKAOK -- check if all are ok, and if not, set up compare buffer for ; comparisons ; ;--------------- CHECKAOK: MOV DI,5DH ;Command line filespec MOV CX,11 ;Number of characters to scan MOV FILAOK,1 ;Preset value for true MOV AX,3F20H ;Use both ? and space until it ;Is determined what it is CHECKAOK1: CMP BYTE PTR [DI],AL ;Is it the same as last? JZ CHECK1 ;Yes, ok so far CMP BYTE PTR [DI],AH ;Alternate for ? JZ CHECK1A ;Yes, ok so far MOV FILAOK,0 ;File is not always ok RET ;Done CHECK1: MOV AH,AL ;Copy char, we know what they ;All must be INC DI ;Point to next char LOOP CHECKAOK1 ;Go for all 11 characters RET ;Done, file always ok CHECK1A: MOV AL,AH ;Copy char, we know what they INC DI ;All must be. point to next LOOP CHECKAOK1 ;And go for all 11 characters RET ;Done, file always ok ;--------------- ; ; CHECKFIL -- check a file to see if it matches comparison value ; ;--------------- CHECKFIL: MOV FILOK,1 ;Set to true for now CMP FILAOK,1 ;Always ok? JNZ CHECKFIL1 ;No, check this one RET ;Yes, return with this one ok CHECKFIL1: PUSH BX ;Save important regs PUSH CX MOV CX,11 ;File spec length MOV DI,5DH ;Offset to comparison string CHECKF2: MOV AL,[DI] ;Get first char to compare CMP AL,'?' ;Wildcard? JZ CHECKN ;Yes, this character always ok CMP AL,[BX] ;No, check with current value JZ CHECKN ;Yes, ok so far POP CX ;No, restore registers POP BX MOV FILOK,0 ;File is not ok RET ;Done CHECKN: INC BX ;Point to next character INC DI LOOP CHECKF2 ;Go for all 11 characters POP CX ;Restore important registers POP BX RET ;Done, file is ok CSEG ENDS END ENTRY SHAR_EOF chmod +x 'dirc.asm' if test -f 'dirc.c' then echo shar: over-writing existing file "'dirc.c'" fi cat << \SHAR_EOF > 'dirc.c' #include <dos.h> #include <stdlib.h> /* | | DIRC.EXE | | USAGE: | DIRC [filename[.ext]]<CR> | | [filename[.ext]] is used to specify the file(s) whose | directory you want to list. | | The information provided includes the free space on the disk. | The freespace is listed both in Granules and Bytes. | The display for each file includes its size in bytes, | the number of granules it occupies, the file | type, and the file mode. | | You may use the global characters ? and * in the filename and | extention parameters. | | If you do not specify a filename, it defaults to *.* | | If you do not specify a filename extention, it defaults to *. | | Notes: Currently sector errors are not dealt with very well, but | then again, I've never seen one. The funtions do return | error values, but they are not checked. Also note that | this program was very closely based on my working assembler | from about two years ago, and I just did a quick translation | without doing much careful thought about improvements, of | which there are probably many. */ #define DRIVENAME 'A' #define DRIVENO (DRIVENAME-'A') char *typetab[4] = { /* Types for COCO directory entries */ "BASIC ", "Data ", "Program ", "Text " }; char *asciitab[2] = { /* File modes for COCO directory entries */ "Binary", "ASCII" }; int fcount, gcount; /* File/Granule count for dir info */ int filaok, filok; /* For wildcarding, always ok and this ok */ int grans; #define GRANS 68 /* Number of grans on the disk */ #define GSIZE 2304 /* Number of bytes per granule */ #define SECSIZE 256 /* Number of bytes per sector */ #define DIRENT 32 /* Number of bytes per directory entry */ int nbsec; /* Save area for MSDOS value (must restore)*/ char far *thisseg = " ";/* used to find data segment */ char fat[SECSIZE]; /* FAT information buffer from COCO disk */ char dirbuf[SECSIZE]; /* Directory sector buffer from COCO disk */ char fbuf[11] = /* file buffer for comparison to fspec given*/ "???????????"; union REGS inregs; union REGS outregs; struct SREGS segregs; main(argc,argv) /* main -- Start of DIRC.EXE execution */ int argc; /* I did not use argc/argv in lieu of DOS's */ char *argv[]; /* PSP for sake of easy wildcard expansions */ { char far *(far *vec78h); /* We need to play with the disk */ char far *bpsvec; /* control block area */ int scnt, ecnt; /* sector count and entry count */ int mode, gran, lbytes, type; unsigned char *bufp; checkaok(); /* a little parsing on the PSP */ printf(" Volume in drive %c is COCO disk\n",DRIVENAME); printf(" Directory of COCO disk\n\n"); vec78h = (char far *(far *))(0x78); /* 0000:0078, MSDOS disk info pointer */ bpsvec = 3 + *vec78h; /* Get MSDOS bytes per sector ptr */ nbsec = (int) *bpsvec; /* Save byte for restore later */ *bpsvec = (char) 1; /* Set byte to 1 (256 bytes/sector) */ fcount = 0; /* initialize */ grans = GRANS; /* will be used to count down available */ cread(17,2,fat,1); /* Read coco sector, track 17 sec 2 */ for(scnt=0;scnt<9;scnt++) { /* Main loop for directory read */ cread(17,scnt+3,dirbuf,1); /* Read directory sectors */ bufp = dirbuf; for(ecnt=0;ecnt<8;ecnt++) if (*bufp!=0xff) { /* entries per sector = 8 */ /* ...for each file entry: */ if (*bufp) { checkfil(bufp); /* Check if it's ok to list */ /* result: filok=1, yes */ if (filok) { fcount++; /* count it, and print name */ printf("%.8s %.3s ",bufp,(char *) bufp+8); } mode = (int) *(bufp+12); gran = (int) *(bufp+13); lbytes = ( (256 * (int)(*(bufp+14))) + (int)(*(bufp+15)) );/* Count is in 6809 format */ /* high, then low byte */ type = (int) *(bufp+11); calcdisp(mode,gran,lbytes,type); if (filok) { printf("%s",typetab[type]); if (mode!=0) mode=1; /* now simply ascii or not */ printf("%s\n",asciitab[mode]); } } bufp += DIRENT; } } printf(" %5d File(s)%5d Grans, %6ld Bytes free\n", fcount, grans,(long) grans*GSIZE); *bpsvec = (char) nbsec; /* Set byte to MSDOS value */ } /* calcdisp -- calculate file size, and display if necessary */ calcdisp(mode,gran,lbytes,type) int mode,gran,lbytes,type; { int bytecnt; gcount = 0; bytecnt = lbytes; do { grans--; /* one less granule avail */ gcount++; /* one more allocated here */ gran = (int) *(fat+gran); /* point to next granule */ if (gran & 0x80) { /* if high bit set, last */ gran = (gran & 0x3f)-1; /* find remaining sectors */ if (gran>0) bytecnt += gran*SECSIZE; break; /* done */ } bytecnt += GSIZE; /* add gran length */ } while (gran>=0); /* we'll actually break */ if (filok) printf("%5d%5d ",bytecnt,gcount); /* print if needed */ } /* check if all are ok, and if not, set up compare buffer for comparisons */ checkaok() { char far *pspfspec; int cnt; char chk1; char *nbuf; FP_SEG(pspfspec) = _psp; /* Use the PSP, dos is nice */ FP_OFF(pspfspec) = 0x5d; /* to us on wildcards */ chk1 = *pspfspec; /* get first character */ nbuf=fbuf; if (chk1==' ' || chk1=='?') { filaok=1; /* if all blank or all '?' */ for(cnt=0;cnt<11;cnt++) { *nbuf = *pspfspec++; if (*nbuf++!=chk1) filaok = 0; } /* if filaok then ALL files */ } else filaok=0; } /* checkfil -- check a file to see if it matches comparison value */ checkfil(nbuf) char *nbuf; { int cnt; filok = 1; if (filaok) return; for (cnt=0;cnt<11;cnt++) if ((*(fbuf+cnt) != '?') && (*(fbuf+cnt) != *(nbuf+cnt))) filok=0; return; } int cread(trk,sec,buf,cnt) int trk,sec; char *buf; int cnt; { int errcnt; char *temp; errcnt = 0; for(temp=buf;temp<buf+SECSIZE*cnt;temp++) *temp=0; /* zero buff */ if (trk>39 || sec>18) return(-1); /* don't read bad ptr's */ while (errcnt<4) { inregs.x.ax = 0x0200+(cnt & 0xff);/* 2 = read, Count=cnt */ inregs.x.bx = (int) buf; /* pointer to buffer */ inregs.x.cx = (int) (trk & 0xff)*256 +(sec & 0xff);/* Track , Sector */ inregs.x.dx = DRIVENO; /* Drive select byte */ segregs.ds = FP_SEG(thisseg); segregs.es = FP_SEG(thisseg); int86x(0x13,&inregs,&outregs,&segregs); if (outregs.x.cflag==0) break; creset(); errcnt++; } return(errcnt); } int creset() { inregs.x.ax = 0x0000; /* 2 = read function, Count=cnt */ inregs.x.dx = DRIVENO; /* Drive select byte */ segregs.ds = FP_SEG(thisseg); segregs.es = FP_SEG(thisseg); int86x(0x13,&inregs,&outregs,&segregs); return(outregs.x.cflag); } SHAR_EOF chmod +x 'dirc.c' if test -f 'fromc.c' then echo shar: over-writing existing file "'fromc.c'" fi cat << \SHAR_EOF > 'fromc.c' #include <dos.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> /* | | FROMC.EXE | | USAGE: | FROMC [filename[.ext]]<CR> | | [filename[.ext]] is used to specify the file(s) which | you want to get from COCO disks. | | This function also has the side effect of giving you | directory information as it copies (an added | benefit). | | The information provided includes the free space on the disk. | The freespace is listed both in Granules and Bytes. | The display for each file includes its size in bytes, | the number of granules it occupies, the file | type, and the file mode. | | You may use the global characters ? and * in the filename and | extention parameters. | | If you do not specify a filename, it defaults to *.* | | If you do not specify a filename extention, it defaults to *. | */ #define DRIVENAME 'A' #define DRIVENO (DRIVENAME-'A') char *typetab[4] = { /* Types for COCO directory entries */ "BASIC ", "Data ", "Program ", "Text " }; char *asciitab[2] = { /* File modes for COCO directory entries */ "Binary", "ASCII" }; int fcount, gcount; /* File/Granule count for dir info */ int filaok, filok; /* For wildcarding, always ok and this ok */ int grans; #define GRANS 68 /* Number of grans on the disk */ #define GSIZE 2304 /* Number of bytes per granule */ #define SECSIZE 256 /* Number of bytes per sector */ #define DIRENT 32 /* Number of bytes per directory entry */ int lastsec; FILE *filptr; char *fname = " \r"; int nbsec; /* Save area for MSDOS value (must restore)*/ char far *thisseg = " ";/* used to find data segment */ char fat[SECSIZE]; /* FAT information buffer from COCO disk */ char dirbuf[SECSIZE]; /* Directory sector buffer from COCO disk */ char fbuf[11] = /* file buffer for comparison to fspec given*/ "???????????"; char inbuff[GSIZE]; /* Input buffer for granules */ union REGS inregs; union REGS outregs; struct SREGS segregs; main(argc,argv) /* main -- Start of DIRC.EXE execution */ int argc; char *argv[]; { char far *(far *vec78h); char far *bpsvec; int scnt, ecnt; int mode, gran, lbytes, type; unsigned char *bufp; checkaok(); printf(" Volume in drive %c is COCO disk\n",DRIVENAME); printf(" Copying files from COCO disk\n\n"); vec78h = (char far *(far *))(0x78); /* 0000:0078, MSDOS disk info pointer */ bpsvec = 3 + *vec78h; /* Get MSDOS bytes per sector ptr */ nbsec = (int) *bpsvec; /* Save byte for restore later */ *bpsvec = (char) 1; /* Set byte to 1 (256 bytes/sector) */ fcount = 0; /* initialize */ grans = GRANS; cread(17,2,fat,1); for(scnt=0;scnt<9;scnt++) { /* Main loop for directory read */ cread(17,scnt+3,dirbuf,1); bufp = dirbuf; for(ecnt=0;ecnt<8;ecnt++) if (*bufp!=0xff) { /* entries per sector = 8 */ /* ...for each file entry: */ if (*bufp) { checkfil(bufp); /* Check if it's ok to list */ /* result: filok=1, yes */ if (filok) { fcount++; /* count it, and print name */ printf("Copying %.8s %.3s ",bufp,(char *) bufp+8); } mode = (int) *(bufp+12); gran = (int) *(bufp+13); lbytes = ( (256 * (int)(*(bufp+14))) + (int)(*(bufp+15)) );/* Count is in 6809 format */ /* high, then low byte */ type = (int) *(bufp+11); calcdisp(mode,gran,lbytes,type,bufp); if (filok) { printf("%s",typetab[type]); if (mode!=0) mode=1; /* now simply ascii or not */ printf("%s\n",asciitab[mode]); } } bufp += DIRENT; } } printf("Done: %5d File(s) copied\n",fcount); *bpsvec = (char) nbsec; /* Set byte to MSDOS value */ } /* calcdisp -- calculate file size, and display if necessary */ calcdisp(mode,gran,lbytes,type,name) int mode,gran,lbytes,type; char *name; { int bytecnt,tgran; gcount = 0; bytecnt = lbytes; if (filok) openfile(name); lastsec = lbytes; do { tgran = gran; grans--; gcount++; gran = (int) *(fat+gran); if (gran & 0x80) { if (filok) copylast(tgran,gran & 0x3f); gran = (gran & 0x3f)-1; if (gran>0) bytecnt += gran*SECSIZE; gran=-1; break; } if (filok) copygran(tgran); bytecnt += (int) GSIZE; } while (gran>=0); if (filok) printf("%5d%5d ",bytecnt,gcount); } /* check if all are ok, and if not, set up compare buffer for comparisons */ checkaok() { char far *pspfspec; int cnt; char chk1; char *nbuf; FP_SEG(pspfspec) = _psp; FP_OFF(pspfspec) = 0x5d; chk1 = *pspfspec; nbuf=fbuf; if (chk1==' ' || chk1=='?') filaok=1; else filaok=0; for(cnt=0;cnt<11;cnt++) { *nbuf = *pspfspec++; if (*nbuf++!=chk1) filaok = 0; } } /* CHECKFIL -- check a file to see if it matches comparison value */ checkfil(nbuf) char *nbuf; { int cnt; filok = 1; if (filaok) return; for (cnt=0;cnt<11;cnt++) if ((*(fbuf+cnt) != '?') && (*(fbuf+cnt) != *(nbuf+cnt))) filok=0; return; } openfile(name) char *name; { int cnt; char *fptr; fptr = fname; for(cnt=0;cnt<8;cnt++) *fptr++ = *(name+cnt); while (*(fptr-1)==' ' && fptr>fname) fptr--; *fptr++ = '.'; for(cnt=8;cnt<11;cnt++) *fptr++ = *(name+cnt); while ((*(fptr-1)==' ' || *(fptr-1)=='.') && fptr>fname) fptr--; *fptr = 0; filptr = fopen(fname,"w+b"); } copygran(gran) int gran; { int secstart; if (gran>=34) gran += 2; secstart = (gran & 1)*9+1; gran /= 2; cread(gran,secstart,inbuff,9); fwrite(inbuff,GSIZE,1,filptr); } copylast(gran,nsec) int gran,nsec; { int secstart; if (gran>=34) gran+=2; secstart = (gran & 1)*9+1; gran /= 2; cread(gran,secstart,inbuff,9); nsec -= 1; if (nsec<0) nsec=0; fwrite(inbuff,SECSIZE*nsec+lastsec,1,filptr); fclose(filptr); } int cread(trk,sec,buf,cnt) int trk,sec; char *buf; int cnt; { int errcnt; char *temp; errcnt = 0; for(temp=buf;temp<buf+SECSIZE*cnt;temp++) *temp=0; if (trk>39 || sec>18) return(-1); while (errcnt<4) { inregs.x.ax = 0x0200+(cnt & 0xff);/* 2 = read, Count=cnt */ inregs.x.bx = (int) buf; /* pointer to buffer */ inregs.x.cx = (int) (trk & 0xff)*256 +(sec & 0xff);/* Track , Sector */ inregs.x.dx = DRIVENO; /* Drive select byte */ segregs.ds = FP_SEG(thisseg); segregs.es = FP_SEG(thisseg); int86x(0x13,&inregs,&outregs,&segregs); if (outregs.x.cflag==0) break; creset(); errcnt++; } return(errcnt); } int creset() { inregs.x.ax = 0x0000; /* 2 = read function, Count=cnt */ inregs.x.dx = DRIVENO; /* Drive select byte */ segregs.ds = FP_SEG(thisseg); segregs.es = FP_SEG(thisseg); int86x(0x13,&inregs,&outregs,&segregs); return(outregs.x.cflag); } SHAR_EOF chmod +x 'fromc.c' if test -f 'toc.c' then echo shar: over-writing existing file "'toc.c'" fi cat << \SHAR_EOF > 'toc.c' #include <dos.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <io.h> /* | | TOC.EXE | | USAGE: | TOC filename.ext {BDPT} {AB}<CR> | | filename.ext is used to specify the file which you want | to transfer. NO wildcards are supported, and you | MUST include a file type and mode. | | This is a derivitive of DIRC.C (can you tell?) */ #define DRIVENAME 'A' #define DRIVENO (DRIVENAME-'A') char *typetab[4] = { /* Types for COCO directory entries */ "BASIC ", "Data ", "Program ", "Text " }; char *asciitab[2] = { /* File modes for COCO directory entries */ "Binary", "ASCII" }; int fcount, gcount; /* File/Granule count for dir info */ int filaok, filok; /* For wildcarding, always ok and this ok */ int grans; #define GRANS 68 /* Number of grans on the disk */ #define GSIZE 2304 /* Number of bytes per granule */ #define SECSIZE 256 /* Number of bytes per sector */ #define DIRENT 32 /* Number of bytes per directory entry */ int lastsec; FILE *filptr; char *fname = " \r"; int nbsec; /* Save area for MSDOS value (must restore)*/ char far *thisseg = " ";/* used to find data segment */ char fat[SECSIZE]; /* FAT information buffer from COCO disk */ char dirbuf[SECSIZE]; /* Directory sector buffer from COCO disk */ char fbuf[11] = /* file buffer for comparison to fspec given*/ "???????????"; char inbuff[GSIZE]; /* Input buffer for granules */ union REGS inregs; union REGS outregs; struct SREGS segregs; unsigned long int numb; unsigned int numg,numrs,numrb; main(argc,argv) /* main -- Start of DIRC.EXE execution */ int argc; char *argv[]; { char far *(far *vec78h); char far *bpsvec; int scnt, ecnt, cnt, lcnt; unsigned int mode, gran, lbytes, type; unsigned char *bufp; if (argc!=4) { printf("Usage: toc (fspec) {BDPT} {AB}\n"); exit(1); } switch (*argv[2]) { case 'b': case 'B': { type = 0; break; } case 'd': case 'D': { type = 1; break; } case 'p': case 'P': { type = 2; break; } case 't': case 'T': { type = 3; break; } default: { printf("Bad parameter: %c\n",*argv[2]); exit(1); } } switch (*argv[3]) { case 'a': case 'A': { mode = 1; break; } case 'b': case 'B': { mode = 0; break; } default: { printf("Bad parameter: %c\n",*argv[3]); exit(1); } } checkaok(); openfile(fbuf); numb = filelength(fileno(filptr)); numg = (int) (numb/GSIZE)+1; numrb = numb - (numg-1)*GSIZE; numrs = (int) (numrb/SECSIZE)+1; numrb -= (numrs-1)*SECSIZE; printf(" Copying %s to COCO disk in drive %c\n",fname,DRIVENAME); printf(" Type = %s",typetab[type]); printf(" Mode = %s",asciitab[mode]); printf(" %d Grans\n\n",numg); vec78h = (char far *(far *))(0x78); /* 0000:0078, MSDOS disk info pointer */ bpsvec = 3 + *vec78h; /* Get MSDOS bytes per sector ptr */ nbsec = (int) *bpsvec; /* Save byte for restore later */ *bpsvec = (char) 1; /* Set byte to 1 (256 bytes/sector) */ fcount = 0; /* initialize */ grans = GRANS; cread(17,2,fat,1); for(cnt=0;cnt<GRANS;cnt++) if (*(fat+cnt)!=(char) 0xff) grans--; if (grans<numg) { printf(" Not enough space: Only %d grans free\n\n",grans); } else { for(scnt=0;scnt<9;scnt++) { /* Main loop for directory read */ cread(17,scnt+3,dirbuf,1); bufp = dirbuf; for(ecnt=0;ecnt<8;ecnt++) if (*bufp!=0xff) { if (*bufp==0) *bufp=0xff; else bufp+=DIRENT; } if (*bufp==0xff) break; } if (*bufp!=0xff) { printf("No more directory entries left.\n\n"); exit(1); } lcnt = -1; for(cnt=0;cnt<11;cnt++) *(bufp+cnt) = *(fbuf+cnt); for(cnt=11;cnt<DIRENT;cnt++) *(bufp+cnt) = (char) 0; *(bufp+11) = (char) type; *(bufp+12) = (char) mode*0xff; *(bufp+15) = (char) numrb; for(cnt=0;cnt<GRANS;cnt++) if (*(fat+cnt)==(char) 0xff) { if (lcnt<0) *(bufp+13)=(char) cnt; else *(fat+lcnt)=(char) cnt; lcnt=cnt; if (numg > 1) { copygran(cnt); } else { copylast(cnt,numrs); break; } numg--; } *(fat+cnt)=(char) 0xc0+numrs; cwrite(17,scnt+3,dirbuf,1); cwrite(17,2,fat,1); fclose(filptr); } *bpsvec = (char) nbsec; /* Set byte to MSDOS value */ } /* check if all are ok, and if not, set up compare buffer for comparisons */ checkaok() { char far *pspfspec; int cnt; char *nbuf; FP_SEG(pspfspec) = _psp; FP_OFF(pspfspec) = 0x5d; filok = 0; filaok = 1; nbuf=fbuf; for(cnt=0;cnt<11;cnt++) { *nbuf = *pspfspec++; if (*nbuf!=' ') filok = 1; if (*nbuf++=='?') filaok = 0; } if (filaok==0) { printf("Wildcards not currently supported\n"); exit(1); } if (filok==0) { printf("No file name given\n"); exit(1); } } int cwrite(trk,sec,buf,cnt) int trk,sec; char *buf; int cnt; { int errcnt,seccnt; if (trk>39 || sec>18) return(-1); for(seccnt=0;seccnt<cnt;seccnt++) { errcnt = 0; while (errcnt<4) { inregs.x.ax = 0x0301; /* 3 = write, Count=cnt */ inregs.x.bx = (int) buf+SECSIZE*seccnt; /* pointer to buffer */ inregs.x.cx = (int) (trk & 0xff)*256 +((sec+seccnt) & 0xff); /* Track , Sector */ inregs.x.dx = DRIVENO; /* Drive select byte */ segregs.ds = FP_SEG(thisseg); segregs.es = FP_SEG(thisseg); int86x(0x13,&inregs,&outregs,&segregs); if (outregs.x.cflag==0) break; creset(); errcnt++; } if (errcnt==4) printf(" Error writing track %d sector %d\n",trk,sec+seccnt); } return(0); } int cread(trk,sec,buf,cnt) int trk,sec; char *buf; int cnt; { int errcnt; char *temp; errcnt = 0; for(temp=buf;temp<buf+SECSIZE*cnt;temp++) *temp=0; /* zero buff */ if (trk>39 || sec>18) return(-1); while (errcnt<4) { inregs.x.ax = 0x0200+(cnt & 0xff);/* 2 = read, Count=cnt */ inregs.x.bx = (int) buf; /* pointer to buffer */ inregs.x.cx = (int) (trk & 0xff)*256 +(sec & 0xff);/* Track , Sector */ inregs.x.dx = DRIVENO; /* Drive select byte */ segregs.ds = FP_SEG(thisseg); segregs.es = FP_SEG(thisseg); int86x(0x13,&inregs,&outregs,&segregs); if (outregs.x.cflag==0) break; creset(); errcnt++; } return(errcnt); } int creset() { inregs.x.ax = 0x0000; /* 2 = read function, Count=cnt */ inregs.x.dx = DRIVENO; /* Drive select byte */ segregs.ds = FP_SEG(thisseg); segregs.es = FP_SEG(thisseg); int86x(0x13,&inregs,&outregs,&segregs); return(outregs.x.cflag); } openfile(name) char *name; { int cnt; char *fptr; fptr = fname; for(cnt=0;cnt<8;cnt++) *fptr++ = *(name+cnt); /* parse filename */ while (*(fptr-1)==' ' && fptr>fname) fptr--; *fptr++ = '.'; /* put in '.' */ for(cnt=8;cnt<11;cnt++) *fptr++ = *(name+cnt); while ((*(fptr-1)==' ' || *(fptr-1)=='.') && fptr>fname) fptr--; *fptr = 0; if ((filptr = fopen(fname,"rb"))==NULL) { printf("File not found\n"); exit(1); } } copygran(gran) int gran; { int secstart; if (gran>=34) gran += 2; /* adjust around directory */ secstart = (gran & 1)*9+1; /* Find start sector */ gran /= 2; /* Now is track pointer */ fread(inbuff,GSIZE,1,filptr); /* read in file from DOS */ cwrite(gran,secstart,inbuff,9); /* write out file to coco */ cwrite(gran,secstart,inbuff,9); /* I did have some write */ /* errors and this does */ /* cure them, probably the */ /* lack of delay on first */ /* write causes a problem */ /* anyone else? */ } copylast(gran,nsec) int gran,nsec; { int secstart; if (gran>=34) gran+=2; /* skip directory */ secstart = (gran & 1)*9+1; /* find sector */ gran /= 2; /* find track */ fread(inbuff,GSIZE,1,filptr); /* read source */ cwrite(gran,secstart,inbuff,9); /* write destination */ } SHAR_EOF chmod +x 'toc.c' # End of shell archive exit 0