v04i119: MSDOS <-> COCO File Utilities
Glenn A. Emelko
crds at ncoast.UUCP
Tue Oct 11 12:19:08 AEST 1988
Posting-number: Volume 4, Issue 119
Submitted-by: "Glenn A. Emelko" <crds at 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 at 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
More information about the Comp.sources.misc
mailing list