;;; mft - multiple file transfer (for single drive systems) ; ; **Based on article in Dr. Dobbs Journal of Computer** ; **Calisthenics & Orthodontia #49, Box E, Menlo Park, Ca. 94025** ; ; Version 4.5 - 10/29/80 - Deleted system disk request of V4.0 ; to shorten messages, minor changes in abort options and ; other messages. Moved disk reset of V4.1 to point ; before directory search. (CHS) ; ; Version 4.4 - 10/28/80 - Modified to bail out with message ; if no FCB is specified. Updates rearranged with most ; recent first for reader convenience. (Charles H. Strom) ; ; VERSION 4.3 BY LEWIS MOSELEY, JR. 3/22/80 ; FIXED BUG WHICH SHOWED UP WHEN MULTIPLE COPIES WERE ; MADE OF A MULTIPLE EXTENT FILE, IN THAT CP/M OPEN ; THE NEXT EXTENT USING THE DATA AREA TO SEARCH THE ; DIRECTORY, SCREWING UP THE DATA BLOCK THAT IS THERE. ; ; VERSION 4.2 BY LEWIS MOSELEY, JR. 2/23/80 ; FIXED BUG THAT OCCURRED WHEN ONLY A SINGLE FILE ; WAS SPECIFIED AND THAT FILE WAS NOT FOUND: ; PROGRAM HUNG IN A LOOP ; ; VERSION 4.1 BY LES FREED AND LEWIS MOSELEY 2/11/80 ; ADDED DISK RESET ON DISK CHANGE TO ALLOW ; CHANGING DENSITY BETWEEN DISKS ; ADDED CTL-C ABORT ; ; VERSION 4.0 BY LEWIS MOSELEY, JR. 12/79 ; ADDED OPTION FOR MULTIPLE OUTPUT COPIES ; ADDED REQUEST FOR SYSTEM DISK BEFORE REBOOT ; ; l.e. hughes 9/79 ; mycroft labs ; atlanta, ga ; MODIFIED FOR SOL & COMPATABLE COMPUTERS BY ; LEWIS MOSELEY, JR. - ATLANTA,GA. version equ 4 modlev equ 5 ; entry equ 0005h ; Bdos entry point tfcb equ 005ch ; System file control block dbuf equ 0080h ; System disk buffer ; cr equ 0dh lf equ 0ah ; rcfc equ 01 ; Read console wcfc equ 02 ; Write console rdfc equ 13 ; Reset disk offc equ 15 ; Open file cffc equ 16 ; Close file sffc equ 17 ; Search first snfc equ 18 ; Search next dffc equ 19 ; Delete file rrfc equ 20 ; Read record wrfc equ 21 ; Write record mffc equ 22 ; Make file safc equ 26 ; Set address ; fn equ 01 ; File name offset ft equ 09 ; File type offset ex equ 12 ; Extent number offset nr equ 32 ; Next record offset ; org 100h mft: ld sp,stack+64 ld hl,msg1 ; Print 'MFT V4.0' call wasc xor a ; Clear break flags ld (ibflg),a ld (obflg),a ld (ndflg),a ; CLEAR NO DUP FLAG ; ld a,(tfcb+1) ; If no FCB specified cp ' ' ; Then say so jp nz,ok ld hl,msgk ; And bail out call wasc ; Here jp 0h ; ; calculate buffer size = fwa(BDOS) - fwa(MBUF) ; ok: ld hl,(entry+1) ; Hl = (entry+1) - 6 ld de,-6 add hl,de ld a,l and 80h ; Hl = hl mod 128 ld l,a ld de,mbuf ; Hl = hl - fwa(MBUF) ld a,l sub e ld l,a ld a,h sbc a,d ld h,a add hl,hl ; Hl = hl / 128 ld l,h ld a,0 adc a,0 ld h,a dec hl ; Subtract one ld (space),hl ; Save as buffer size ld hl,msg2 ; Write 'Buffer size = ' call wasc ld hl,(space) ; Write size of buffer call wdwc ld hl,msg3 ; Write ' sectors' call wasc ; ; ask user to mount input disk ; mft1: ld hl,msg4 ; Write 'Mount input disk, type CR' call wasc call racc ; Read response cp 03 ; CTL-C ? jp z,mftl ; ABORT WITH MESSAGE cp cr ; Loop if anything but CR jp nz,mft1 call weolc ; Echo CR,LF call reset ; Adjust density ld a,(ibflg) ; Jump if ibflg set or a jp nz,mft2a ; ; copy command line into cbuf ; ld hl,dbuf ; Fwa of command line image ld de,cbuf ; Fwa of command buffer ld b,(hl) ; Fetch command line image length inc hl mft2: ld a,(hl) ; Fetch next byte from cli inc hl ld (de),a ; Store in dbuf inc de dec b ; Decrement count jp nz,mft2 ; Loop until zero xor a ; Store zero byte at end ld (de),a ld hl,cbuf ; Reset cbufp ld (cbufp),hl call cfnt ; Create file name table ld hl,fnt ; Reset fnt pointers ld (ifntp),hl ld (ofntp),hl mft2a: ld hl,mbuf ; Reset mbuf pointer ld (mbufp),hl ld hl,(space) ; Reset msize ld (msize),hl ld a,(ibflg) ; Jump if ibflg not set or a jp z,mft3 ld hl,ifcb ; Copy IFCB into TFCB ld de,tfcb ld b,33 call move xor a ; Clear ibflg ld (ibflg),a inc a ; Set obflg ld (obflg),a ld hl,(ifntp) ; Back ifntp up 4 bytes ld de,-4 add hl,de ld (ifntp),hl ld hl,tfcb+fn ; Write filename call wfnc ld hl,msg6 ; Write ' - ' call wasc ld hl,(ifntp) ; DE = ifntp ex de,hl jp mft4 ; Continue reading previous file ; ; parse off next name from cbuf ; mft3: ld hl,(ifntp) ; Fetch input fnt pointer ld a,(hl) ; Jump if end of table cp 0ffh jp z,mft9 ld (hl),1 ; Set 'file read' flag inc hl ld de,tfcb+fn ; Copy filename into tfcb ld b,11 call move ld (ifntp),hl ; Save input fnt pointer ld hl,tfcb+fn ; Write filename call wfnc ld hl,msg6 ; Write ' - ' call wasc xor a ; Setup tfcb ld (tfcb),a ld (tfcb+ex),a ld (tfcb+nr),a call open ; Open file ld hl,(ifntp) ex de,hl mft4: ld hl,(mbufp) ld a,h ; Copy into fnt entry ld (de),a inc de ld a,l ld (de),a inc de ex de,hl ; Save fnt pointer ld (ifntp),hl ld hl,0 ; File size (in sectors) = 0 ld (fsize),hl ; ; read next file from input disk ; mft6: ld hl,(mbufp) ex de,hl call setdma call read ; Read next sector or a ; Jump if normal transfer jp z,mft7 cp 1 ; Jump if EOF jp z,mft8 ld hl,msg8 ; Write 'read error - ' call wasc jp mft8 ; Continue as if EOF mft7: ld hl,(mbufp) ; Mbufp = mbufp + 128 ld de,128 add hl,de ld (mbufp),hl ld hl,(fsize) ; Fsize = fsize + 1 inc hl ld (fsize),hl ld hl,(msize) ; Decrement msize dec hl ld (msize),hl ld a,h ; Loop if still positive or l jp nz,mft6 ld hl,tfcb ; Copy tfcb into ifcb ld de,ifcb ld b,33 call move ld a,1 ; Set ibflg ld (ibflg),a mft8: ld de,dbuf ; Reset dma pointer call setdma call close ; Close file ld hl,(fsize) ; Write file size call wdwc ld hl,msg9 ; Write ' sectors read' call wasc ; ; update fnt, loop ; ld hl,(fsize) ; DE = file size ex de,hl ld hl,(ifntp) ; Store file size in fnt entry ld (hl),d inc hl ld (hl),e inc hl ld (ifntp),hl ; Save fnt pointer ld a,(ibflg) ; Loop if ibflg not set or a jp z,mft3 ; ; FLAG THAT THE MEMORY BUFFER HAS BEEN EXCEEDED, AND ; TELL USER THAT DUPLICATE COPIES CANNOT BE MADE ld a,(ndflg) ; TOLD HIM ALREADY? or a jp nz,mft9 ; JUMP IF SO ld hl,msgh ; IF NOT, TELL HIM call wasc ld a,1 ; SET NDFLG THIS TIME ld (ndflg),a ; ; Ask user to mount output disk ; mft9: ld hl,msga ; Write 'Mount output disk, type CR' call wasc call racc ; Read response cp 03 ; CTL-C? jp z,mftl ; ABORT WITH MESSAGE IF SO cp cr ; Loop if anything but CR jp nz,mft9 call weolc ; Echo CR,LF call reset ; Reset disk system ; Make r/w and check density ld a,(obflg) ; Jump if obflg not set or a jp z,mfta ld hl,ofcb ; Copy ofcb into tfcb ld de,tfcb ld b,33 call move call open ; Open previous file ld hl,(ofntp) ; Backup output fnt pointer 4 bytes ld de,-4 add hl,de ld (ofntp),hl ld hl,tfcb+fn ; Write file name call wfnc ld hl,msg6 ; Write ' - ' call wasc jp mftb ; Continue writing previous file ; ; write next file to output disk ; mfta: ld hl,(ofntp) ld a,(hl) or a jp z,mftf cp 0ffh jp z,mftf inc hl ld de,tfcb+fn ld b,11 call move ld (ofntp),hl ld hl,tfcb+fn call wfnc ld hl,msg6 call wasc xor a ld (tfcb),a ld (tfcb+ex),a ld (tfcb+nr),a call delt ; Try to create output file call make cp 255 ; Jump if ok jp nz,mftb ld hl,msgb ; Write 'unable to create' call wasc jp mftg mftb: ld hl,(ofntp) ld d,(hl) ; Fetch fwa of file from fnt inc hl ld e,(hl) inc hl ex de,hl ld (mbufp),hl ; Save it ex de,hl ld d,(hl) ; Fetch size of file from fnt inc hl ld e,(hl) inc hl ex de,hl ld (fsize),hl ; Save it ld (xsize),hl ; Save for printout ex de,hl ld (ofntp),hl ld hl,(fsize) ; Jump if fsize=0 ld a,h or l jp z,mftda mftc: ld hl,(mbufp) ; Set dma address to mbufp ex de,hl call setdma call write ; Write next sector or a ; Jump if ok jp z,mftd ld hl,msgc ; Write 'error writing file' call wasc jp mftg mftd: ld hl,(mbufp) ; Mbufp = mbufp + 128 ld de,128 add hl,de ld (mbufp),hl ld hl,(fsize) ; Fsize = fsize - 1 dec hl ld (fsize),hl ld a,h ; Loop until zero or l jp nz,mftc mftda: ld hl,tfcb ; Copy tfcb into ofcb ld de,ofcb ld b,33 call move ld de,dbuf ; Reset dma pointer call setdma call close ; Try to close file cp 255 ; Jump if ok jp nz,mfte ld hl,msgd ; Write 'unable to close' call wasc mfte: ld hl,(xsize) ; Write number of sectors written call wdwc ld hl,msge ; Write ' sectors written' call wasc jp mfta mftf: ld a,(ibflg) ; Loop if ibflg set or a jp nz,mft1 ;Terminate program here on irrecoverable error or ;when all files have been copied. Must reload system ;disk to avoid crash when copying to someone else's disk. ;If normal end, and if buffer has not been exceeded, give ;user the option of making another copy of the same ;set of files. mftg: ld hl,msgf ; SEE IF OPTION IS ALLOWED ld a,(ndflg) or a jp nz,mfth ; JUMP IF NOT ALLOWED call wasc ; ELSE TELL ABOUT OPTION mfth: ld hl,msgg ; ASK FOR SYSTEM DISK call wasc call racc ; Wait for response cp 03h ; WARM BOOT IF ^C jp z,0 cp cr ; ATTEMPT REPEAT IF jp z,mftj jp mftg ; ELSE LOOP TILL GOOD RESPONSE ; mftj: call weolc ; ACKNOWLEDGE COMMAND ld a,(ndflg) ; REPEAT ALLOWED? or a jp nz,mftk ; JUMP IF NOT ld hl,fnt ; ELSE RESET FNT POINTER ld (ofntp),hl ld hl,mbuf ; RESET MEM BUF POINTER ld (mbufp),hl xor a ; RESET OUTPUT INTERRUPTED FLAG ld (obflg),a jp mft9 ; AND DO AGAIN ; mftk: ld hl,msgh ; CANNOT REPEAT, TELL HIM AGAIN call wasc jp mftg ; AND WAIT FOR SYSTEM DISK ; mftl: ld hl,msgj ; ABORT MESSAGE call wasc jp 0h ; WARM BOOT ; subroutines ; move: ld a,(hl) inc hl ld (de),a inc de dec b jp nz,move ret ; ;; gfn - get file name ; ; gfn: ld a,(hl) or a ret z cp ' ' jp nz,gfn0 inc hl jp gfn gfn0: ld de,xfcb xor a ld (de),a inc de push de ld b,11 ld a,' ' gfn6: ld (de),a inc de dec b jp nz,gfn6 pop de ld b,9 gfn1: ld a,(hl) or a jp z,gfn4 inc hl cp ' ' jp z,gfn4 cp '.' jp z,gfn2 cp '*' jp z,gfn7 ld (de),a inc de dec b jp z,gfn5 jp gfn1 gfn7: dec b jp z,gfn9 ld a,'?' ld (de),a inc de jp gfn7 gfn9: ld a,(hl) cp '.' jp nz,gfn4 inc hl gfn2: ld de,xfcb+ft ld b,4 gfn3: ld a,(hl) or a jp z,gfn4 inc hl cp ' ' jp z,gfn4 cp '*' jp z,gfn8 ld (de),a inc de dec b jp z,gfn5 jp gfn3 gfn8: dec b jp z,gfn4 ld a,'?' ld (de),a inc de jp gfn8 gfn4: xor a ret gfn5: scf ret ; ;; cfnt - create file name table ; ; cfnt: ld hl,fnt ; Reset ifntp ld (ifntp),hl ld (hl),0ffh ; VER 4.2 BUG FIX cfnt1: ld hl,(cbufp) ; Get cbufp ld a,(hl) ; Exit if end of list or a ret z call gfn ; Get next afn ld (cbufp),hl ; Save command buffer ptr jp nc,cfnt2 ; Jump if filename ok ld hl,msg5 ; Write 'Syntax error in filename' call wasc jp cfnt1 ; Loop cfnt2: xor a ; Clear xfcb extent field ld (xfcb+ex),a ld de,xfcb ; Search for first occurance call srchf cp 255 ; Jump if found jp nz,cfnt3 ld hl,xfcb+fn ; Write filename call wfnc ld hl,msg7 ; Write ' not found' call wasc jp cfnt1 ; Loop cfnt3: and 3 ; Index into cbuf ld l,a ld h,0 add hl,hl add hl,hl add hl,hl add hl,hl add hl,hl ld de,dbuf add hl,de ex de,hl ; Copy filename into fnt ld hl,(ifntp) ex de,hl ld b,12 call move ld hl,zeros ; Zero fill rest of entry ld b,4 call move ex de,hl ld (ifntp),hl ; Save input fnt pointer ld (hl),0ffh ; Insure FF byte at end ld de,xfcb ; Search for next occurance call srchn cp 255 ; Jump if found jp nz,cfnt3 jp cfnt1 ; Go get next afn ; ;; wasc - write ascii string to console ; ; wasc: ld a,(hl) or a ret z call wacc inc hl jp wasc ; ; ;; wfnc - write file name to console ;Note: Under SOLOS and CUTER, 01 is the cursor-left character. ;When MFTing a multi-extent file, the extent character must ;be filtered out of the file-name-block to avoid wierd ;console output. ; wfnc: ld a,(hl) or a ; 0=thru ret z cp 20h ; Skip print if < space jp c,wfnc1 call wacc wfnc1: inc hl jp wfnc ; ;; weolc - write end of line to console ; ; weolc: ld a,cr call wacc ld a,lf jp wacc ; ;; wdwc - write decimal word to console ; ; wdwc: push hl push de push bc ld b,0 ; Clear 'digit written' flag ld de,10000 ; Write 1st digit call wndd ld de,1000 ; Write 2nd digit call wndd ld de,100 ; Write 3rd digit call wndd ld de,10 ; Write 4th digit call wndd ld de,1 ; Write 5th digit ld b,1 ; Force last digit to print call wndd pop bc pop de pop hl ret ; wndd: ld c,0 ; C=0 wndd1: ld a,l ; Hl = hl - de sub e ld l,a ld a,h sbc a,d ld h,a jp c,wndd2 ; Jump if < 0 inc c ; C = c + 1 jp wndd1 ; Loop wndd2: add hl,de ; Hl = hl + de ld a,c ; Jump if c non-zero or c jp nz,wndd4 ld a,b ; Jump if digit written or b jp nz,wndd4 ld a,' ' ; Write one space jp wacc wndd4: ld b,1 ; Set 'digit written' flag ld a,c ; Encode c into decimal ascii add a,'0' jp wacc ; Go write it ; ;; wacc - write ascii character to console ; ; wacc: push hl push de push bc push af ld c,wcfc ld e,a call entry pop af pop bc pop de pop hl ret ; ;; racc - read ascii character from console ; ; racc: push hl push de push bc ld c,rcfc call entry pop bc pop de pop hl ret ; ;; reset - reset disk system ; ; reset: push hl push de push bc ld c,rdfc call entry pop bc pop de pop hl ret ; ;; open - open disk file ; ; open: push hl push de push bc ld de,tfcb ld c,offc call entry pop bc pop de pop hl ret ; ;; read - read record from disk file ; ; read: push hl push de push bc ld de,tfcb ld c,rrfc call entry pop bc pop de pop hl ret ; ;; close - close disk file ; ; close: push hl push de push bc ld de,tfcb ld c,cffc call entry pop bc pop de pop hl ret ; ;; delt - delete disk file ; ; delt: push hl push de push bc ld de,tfcb ld c,dffc call entry pop bc pop de pop hl ret ; ;; make - make new disk file ; ; make: push hl push de push bc ld de,tfcb ld c,mffc call entry pop bc pop de pop hl ret ; ;; write - write record to file ; ; write: push hl push de push bc ; ;REVISION 4.3 MODS ld a,(tfcb+nr) ; LAST RECORD IN EXTENT? cp 7fh jp nz,write1 ; NO, CONTINUE ld hl,(mbufp) ; EXISTING DATA AREA ld de,dbuf ; POINT TO SAFE AREA call setdma ; TELL CP/M WHERE TO GET DATA ld b,80h ; LENGTH TO MOVE call move ; MOVE DATA AWAY SO... ;CP/M DOESN'T OVERWRITE THE REAL DATA IN OPENING NEXT EXTENT ;END REVISION 4.3 MODS write1: ld de,tfcb ld c,wrfc call entry pop bc pop de pop hl ret ; ;; setdma - set dma address ; ; setdma: push hl push de push bc ld c,safc call entry pop bc pop de pop hl ret ; ;; srchf - search for first occurance of afn ; ; srchf: push hl push de push bc ld c,sffc call entry pop bc pop de pop hl ret ; ;; srchn - search for next occurance of afn ; ; srchn: push hl push de push bc ld c,snfc call entry pop bc pop de pop hl ret ; msg1: defb cr,lf,'MFT V' defb version+'0' ; VERSION # defb '.',modlev+'0' ; MODIFICATION LEVEL defb cr,lf defb 'Multi-File-Transfer for single disk,',cr,lf defb 'With multiple-copy option.',cr,lf,lf,0 msg2: defb 'Buffer size = ',0 msg3: defb ' sectors',cr,lf,lf,0 msg4: defb 'Mount INPUT disk, type RETURN (or ^C to reboot)',0 msg5: defb 'Syntax error in filename',cr,lf,0 msg6: defb ' - ',0 msg7: defb ' not found',cr,lf,0 msg8: defb 'read error - ',0 msg9: defb ' sectors read',cr,lf,0 msga: defb 'Mount OUTPUT disk, type RETURN (or ^C to reboot)',0 msgb: defb 'unable to create',cr,lf,0 msgc: defb 'error writing file',cr,lf,0 msgd: defb 'unable to close',cr,lf,0 msge: defb ' sectors written',cr,lf,0 msgf: defb cr,lf,'Completed. ' defb 'Type RETURN for another copy, OR...',0 msgg: defb cr,lf,'type ^C to reboot.',cr,lf,0 msgh: defb cr,lf,'++Memory buffer exceeded, cannot ',cr,lf defb 'make duplicate copies this time;',cr,lf defb 'last ouput file is defective++',cr,lf,lf,0 msgj: defb cr,lf,'++PROGRAM ABORTED++',cr,lf,0 msgk: defb cr,lf,'No file name specified',cr,lf,0 ; ; zeros: defb 0,0,0,0 ; org ($+15)/16*16 ; fnt: defs 16*64+1 ; stack: defs 64 space: defs 2 ; Available space msize: defs 2 ; Memory size cbuf: defs 80 ; Command buffer cbufp: defs 2 ; Command buffer pointer fsize: defs 2 ; File size in sectors xsize: defs 2 ; File size for printout ifntp: defs 2 ; Input fnt pointer ofntp: defs 2 ; Output fnt pointer mbufp: defs 2 ; Memory buffer pointer ifcb: defs 33 ; Input fcb ofcb: defs 33 ; Output fcb xfcb: defs 33 ; Temporary fcb ibflg: defs 1 ; Input break flag obflg: defs 1 ; Output break flag ndflg: defs 1 ; NO DUPLICATE ALLOWED FLAG ; mbuf equ $ ; end mft