;;; 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.6A - gfn3 routine restored to version 4.5 - ; 4.6 revision did not handle eight char. filenames. ; I could not reproduce the error reported by cml when ; copying ufn.. (CHS) 4/30/81 ; ; Modified to VER. 4.6 to strip off $R/O attribute ; in output filename. If source was R/O then cp/m ; gave a "Bdos error on $R/O file" when an attempt was ; made to write to the newly created file. ; ; Changed 'jz gfn4' in rtn. gfn3 ; to 'jz gfn3' in order to ignore spaces ; in the file type. Before, whenever an extension ; was '.' multiple copies of the file ; name were built in the ifnt. ; ; Added equate 'nosys' and associated rtn. in section ; 'cfnt3:' in order to ignore all files with a 'sys' ; attribute. This will allow the user to mask-off ; any file(s) he doesn't want to copy. ; cml 4/10/81 ; ; ------------------------- ; ; 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 6 ; entry equ 0005H ;bdos entry point tfcb equ 005CH ;system file control block dbuf equ 0080H ;system disk buffer ; true equ 0ffh false equ 0h ; nosys equ false ;true to ignore all $SYS files ; 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: lxi sp,stack+64 lxi h,msg1 ;print 'MFT V4.0' call wasc xra a ;clear break flags sta ibflg sta obflg STA NDFLG ;CLEAR NO DUP FLAG ; LDA TFCB+1 ;If no FCB specified CPI ' ' ;then say so JNZ OK LXI H,MSGK ;and bail out CALL WASC ;here JMP 0H ; ; calculate buffer size = fwa(BDOS) - fwa(MBUF) ; OK lhld entry+1 ;hl = (entry+1) - 6 lxi d,-6 dad d mov a,l ani 80H ;hl = hl mod 128 mov l,a lxi d,mbuf ;hl = hl - fwa(MBUF) mov a,l sub e mov l,a mov a,h sbb d mov h,a dad h ;hl = hl / 128 mov l,h mvi a,0 aci 0 mov h,a dcx h ;subtract one shld space ;save as buffer size lxi h,msg2 ;write 'Buffer size = ' call wasc lhld space ;write size of buffer call wdwc lxi h,msg3 ;write ' sectors' call wasc ; ; ask user to mount input disk ; mft1: lxi h,msg4 ;write 'Mount input disk, type CR' call wasc call racc ;read response CPI 03 ;CTL-C ? JZ MFTL ;ABORT WITH MESSAGE cpi CR ;loop if anything but CR jnz mft1 call weolc ;echo CR,LF CALL RESET ;adjust density lda ibflg ;jump if ibflg set ora a jnz mft2a ; ; copy command line into cbuf ; lxi h,dbuf ;fwa of command line image lxi d,cbuf ;fwa of command buffer mov b,m ;fetch command line image length inx h mft2: mov a,m ;fetch next byte from cli inx h stax d ;store in dbuf inx d dcr b ;decrement count jnz mft2 ;loop until zero xra a ;store zero byte at end stax d lxi h,cbuf ;reset cbufp shld cbufp call cfnt ;create file name table lxi h,fnt ;reset fnt pointers shld ifntp shld ofntp mft2a: lxi h,mbuf ;reset mbuf pointer shld mbufp lhld space ;reset msize shld msize lda ibflg ;jump if ibflg not set ora a jz mft3 lxi h,ifcb ;copy IFCB into TFCB lxi d,tfcb mvi b,33 call move xra a ;clear ibflg sta ibflg inr a ;set obflg sta obflg lhld ifntp ;back ifntp up 4 bytes lxi d,-4 dad d shld ifntp lxi h,tfcb+fn ;write filename call wfnc lxi h,msg6 ;write ' - ' call wasc lhld ifntp ;DE = ifntp xchg jmp mft4 ;continue reading previous file ; ; parse off next name from cbuf ; mft3: lhld ifntp ;fetch input fnt pointer mov a,m ;jump if end of table cpi 0FFH jz mft9 mvi m,1 ;set 'file read' flag inx h lxi d,tfcb+fn ;copy filename into tfcb mvi b,11 call move shld ifntp ;save input fnt pointer lxi h,tfcb+fn ;write filename call wfnc lxi h,msg6 ;write ' - ' call wasc xra a ;setup tfcb sta tfcb sta tfcb+ex sta tfcb+nr call open ;open file lhld ifntp xchg mft4: lhld mbufp mov a,h ;copy into fnt entry stax d inx d mov a,l stax d inx d xchg ;save fnt pointer shld ifntp lxi h,0 ;file size (in sectors) = 0 shld fsize ; ; read next file from input disk ; mft6: lhld mbufp xchg call setdma call read ;read next sector ora a ;jump if normal transfer jz mft7 cpi 1 ;jump if EOF jz mft8 lxi h,msg8 ;write 'read error - ' call wasc jmp mft8 ;continue as if EOF mft7: lhld mbufp ;mbufp = mbufp + 128 lxi d,128 dad d shld mbufp lhld fsize ;fsize = fsize + 1 inx h shld fsize lhld msize ;decrement msize dcx h shld msize mov a,h ;loop if still positive ora l jnz mft6 lxi h,tfcb ;copy tfcb into ifcb lxi d,ifcb mvi b,33 call move mvi a,1 ;set ibflg sta ibflg mft8: lxi d,dbuf ;reset dma pointer call setdma call close ;close file lhld fsize ;write file size call wdwc lxi h,msg9 ;write ' sectors read' call wasc ; ; update fnt, loop ; lhld fsize ;DE = file size xchg lhld ifntp ;store file size in fnt entry mov m,d inx h mov m,e inx h shld ifntp ;save fnt pointer lda ibflg ;loop if ibflg not set ora a jz mft3 ; ; FLAG THAT THE MEMORY BUFFER HAS BEEN EXCEEDED, AND ; TELL USER THAT DUPLICATE COPIES CANNOT BE MADE LDA NDFLG ;TOLD HIM ALREADY? ORA A JNZ MFT9 ;JUMP IF SO LXI H,MSGH ;IF NOT, TELL HIM CALL WASC MVI A,1 ;SET NDFLG THIS TIME STA NDFLG ; ; Ask user to mount output disk ; mft9: lxi h,msgA ;write 'Mount output disk, type CR' call wasc call racc ;read response CPI 03 ;CTL-C? JZ MFTL ;ABORT WITH MESSAGE IF SO cpi CR ;loop if anything but CR jnz mft9 call weolc ;echo CR,LF call reset ;reset disk system ;make r/w and check density lda obflg ;jump if obflg not set ora a jz mftA lxi h,ofcb ;copy ofcb into tfcb lxi d,tfcb mvi b,33 call move call open ;open previous file lhld ofntp ;backup output fnt pointer 4 bytes lxi d,-4 dad d shld ofntp lxi h,tfcb+fn ;write file name call wfnc lxi h,msg6 ;write ' - ' call wasc jmp mftb ;continue writing previous file ; ; write next file to output disk ; mftA: lhld ofntp mov a,m ora a jz mftF cpi 0FFH jz mftF inx h lxi d,tfcb+fn mvi b,11 call move shld ofntp lxi h,tfcb+ft ;pt to $R/O byte mov a,m ;get it from storage ani 7fh ;force it to $R/W mov m,a ;put it back lxi h,tfcb+fn call wfnc lxi h,msg6 call wasc xra a sta tfcb sta tfcb+ex sta tfcb+nr call delt ;try to create output file call make cpi 255 ;jump if ok jnz mftB lxi h,msgB ;write 'unable to create' call wasc jmp mftG mftB: lhld ofntp mov d,m ;fetch fwa of file from fnt inx h mov e,m inx h xchg shld mbufp ;save it xchg mov d,m ;fetch size of file from fnt inx h mov e,m inx h xchg shld fsize ;save it shld xsize ;save for printout xchg shld ofntp lhld fsize ;jump if fsize=0 mov a,h ora l jz mftDA mftC: lhld mbufp ;set dma address to mbufp xchg call setdma call write ;write next sector ora a ;jump if ok jz mftD lxi h,msgC ;write 'error writing file' call wasc jmp mftG mftD: lhld mbufp ;mbufp = mbufp + 128 lxi d,128 dad d shld mbufp lhld fsize ;fsize = fsize - 1 dcx h shld fsize mov a,h ;loop until zero ora l jnz mftC mftDA: lxi h,tfcb ;copy tfcb into ofcb lxi d,ofcb mvi b,33 call move lxi d,dbuf ;reset dma pointer call setdma call close ;try to close file cpi 255 ;jump if ok jnz mftE lxi h,msgD ;write 'unable to close' call wasc mftE: lhld xsize ;write number of sectors written call wdwc lxi h,msgE ;write ' sectors written' call wasc jmp mftA mftF: lda ibflg ;loop if ibflg set ora a jnz 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: LXI H,MSGF ;SEE IF OPTION IS ALLOWED LDA NDFLG ORA A JNZ MFTH ;JUMP IF NOT ALLOWED CALL WASC ;ELSE TELL ABOUT OPTION MFTH: LXI H,MSGG ;ASK FOR SYSTEM DISK call wasc call racc ;wait for response CPI 03H ;WARM BOOT IF ^C JZ 0 CPI CR ;ATTEMPT REPEAT IF JZ MFTJ JMP MFTG ;ELSE LOOP TILL GOOD RESPONSE ; MFTJ: CALL WEOLC ;ACKNOWLEDGE COMMAND LDA NDFLG ;REPEAT ALLOWED? ORA A JNZ MFTK ;JUMP IF NOT LXI H,FNT ;ELSE RESET FNT POINTER SHLD OFNTP LXI H,MBUF ;RESET MEM BUF POINTER SHLD MBUFP XRA A ;RESET OUTPUT INTERRUPTED FLAG STA OBFLG JMP MFT9 ;AND DO AGAIN ; MFTK: LXI H,MSGH ;CANNOT REPEAT, TELL HIM AGAIN CALL WASC JMP MFTG ;AND WAIT FOR SYSTEM DISK ; MFTL: LXI H,MSGJ ;ABORT MESSAGE CALL WASC JMP 0H ;WARM BOOT ; subroutines ; move: mov a,m inx h stax d inx d dcr b jnz move ret ; ;; gfn - get file name ; ; gfn: mov a,m ora a rz cpi ' ' jnz gfn0 inx h jmp gfn gfn0: lxi d,xfcb xra a stax d inx d push d mvi b,11 mvi a,' ' gfn6: stax d inx d dcr b jnz gfn6 pop d mvi b,9 gfn1: mov a,m ora a jz gfn4 inx h cpi ' ' jz gfn4 cpi '.' jz gfn2 cpi '*' jz gfn7 stax d inx d dcr b jz gfn5 jmp gfn1 gfn7: dcr b jz gfn9 mvi a,'?' stax d inx d jmp gfn7 gfn9: mov a,m cpi '.' jnz gfn4 inx h gfn2: lxi d,xfcb+ft mvi b,4 gfn3: mov a,m ora a jz gfn4 inx h cpi ' ' jz gfn4 cpi '*' jz gfn8 stax d inx d dcr b jz gfn5 jmp gfn3 gfn8: dcr b jz gfn4 mvi a,'?' stax d inx d jmp gfn8 gfn4: xra a ret gfn5: stc ret ; ;; cfnt - create file name table ; ; cfnt: lxi h,fnt ;reset ifntp shld ifntp MVI M,0FFH ;VER 4.2 BUG FIX cfnt1: lhld cbufp ;get cbufp mov a,m ;exit if end of list ora a rz call gfn ;get next afn shld cbufp ;save command buffer ptr jnc cfnt2 ;jump if filename ok lxi h,msg5 ;write 'Syntax error in filename' call wasc jmp cfnt1 ;loop cfnt2: xra a ;clear xfcb extent field sta xfcb+ex lxi d,xfcb ;search for first occurance call srchf cpi 255 ;jump if found jnz cfnt3 lxi h,xfcb+fn ;write filename call wfnc lxi h,msg7 ;write ' not found' call wasc jmp cfnt1 ;loop cfnt3: ani 3 ;index into cbuf mov l,a mvi h,0 dad h dad h dad h dad h dad h lxi d,dbuf dad d ; if nosys push h push d lxi d,10 dad d mov a,m ;get 't2' ani 80h ;look at sys bit pop d pop h jnz cfnt4 ;'sys file'-ignore endif ; xchg ;copy filename into fnt lhld ifntp xchg mvi b,12 call move lxi h,zeros ;zero fill rest of entry mvi b,4 call move xchg shld ifntp ;save input fnt pointer mvi m,0FFH ;insure FF byte at end cfnt4: lxi d,xfcb ;search for next occurance call srchn cpi 255 ;jump if found jnz cfnt3 jmp cfnt1 ;go get next afn ; ;; wasc - write ascii string to console ; ; wasc: mov a,m ora a rz call wacc inx h jmp 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: mov a,m ora a ;0=thru rz cpi 20h ;skip print if < space jc wfnc1 call wacc wfnc1 inx h jmp wfnc ; ;; weolc - write end of line to console ; ; weolc: mvi a,CR call wacc mvi a,LF jmp wacc ; ;; wdwc - write decimal word to console ; ; wdwc: push h push d push b mvi b,0 ;clear 'digit written' flag lxi d,10000 ;write 1st digit call wndd lxi d,1000 ;write 2nd digit call wndd lxi d,100 ;write 3rd digit call wndd lxi d,10 ;write 4th digit call wndd lxi d,1 ;write 5th digit mvi b,1 ;force last digit to print call wndd pop b pop d pop h ret ; wndd: mvi c,0 ;c=0 wndd1: mov a,l ;hl = hl - de sub e mov l,a mov a,h sbb d mov h,a jc wndd2 ;jump if < 0 inr c ;c = c + 1 jmp wndd1 ;loop wndd2: dad d ;hl = hl + de mov a,c ;jump if c non-zero ora c jnz wndd4 mov a,b ;jump if digit written ora b jnz wndd4 mvi a,' ' ;write one space jmp wacc wndd4: mvi b,1 ;set 'digit written' flag mov a,c ;encode c into decimal ascii adi '0' jmp wacc ;go write it ; ;; wacc - write ascii character to console ; ; wacc: push h push d push b push psw mvi c,wcfc mov e,a call entry pop psw pop b pop d pop h ret ; ;; racc - read ascii character from console ; ; racc: push h push d push b mvi c,rcfc call entry pop b pop d pop h ret ; ;; reset - reset disk system ; ; reset: push h push d push b mvi c,rdfc call entry pop b pop d pop h ret ; ;; open - open disk file ; ; open: push h push d push b lxi d,tfcb mvi c,offc call entry pop b pop d pop h ret ; ;; read - read record from disk file ; ; read: push h push d push b lxi d,tfcb mvi c,rrfc call entry pop b pop d pop h ret ; ;; close - close disk file ; ; close: push h push d push b lxi d,tfcb mvi c,cffc call entry pop b pop d pop h ret ; ;; delt - delete disk file ; ; delt: push h push d push b lxi d,tfcb mvi c,dffc call entry pop b pop d pop h ret ; ;; make - make new disk file ; ; make: push h push d push b lxi d,tfcb mvi c,mffc call entry pop b pop d pop h ret ; ;; write - write record to file ; ; write: push h push d push b ; ;; REVISION 4.3 MODS ; LDA tfcb+nr ;LAST RECORD IN EXTENT? CPI 7FH JNZ WRITE1 ;NO, CONTINUE LHLD mbufp ;EXISTING DATA AREA LXI D,dbuf ;POINT TO SAFE AREA CALL SETDMA ;TELL CP/M WHERE TO GET DATA MVI 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: lxi d,tfcb mvi c,wrfc call entry pop b pop d pop h ret ; ;; setdma - set dma address ; ; setdma: push h push d push b mvi c,safc call entry pop b pop d pop h ret ; ;; srchf - search for first occurance of afn ; ; srchf: push h push d push b mvi c,sffc call entry pop b pop d pop h ret ; ;; srchn - search for next occurance of afn ; ; srchn: push h push d push b mvi c,snfc call entry pop b pop d pop h ret ; msg1: db CR,LF,'MFT V' DB VERSION+'0' ;VERSION # DB '.',MODLEV+'0' ;MODIFICATION LEVEL DB CR,LF db 'Multi-File-Transfer for single disk,',CR,LF db 'With multiple-copy option.',CR,LF,LF,0 msg2: db 'Buffer size = ',0 msg3: db ' sectors',CR,LF,LF,0 msg4: db 'Mount INPUT disk, type RETURN (or ^C to reboot)',0 msg5: db 'Syntax error in filename',CR,LF,0 msg6: db ' - ',0 msg7: db ' not found',CR,LF,0 msg8: db 'read error - ',0 msg9: db ' sectors read',CR,LF,0 msgA: db 'Mount OUTPUT disk, type RETURN (or ^C to reboot)',0 msgB: db 'unable to create',CR,LF,0 msgC: db 'error writing file',CR,LF,0 msgD: db 'unable to close',CR,LF,0 msgE: db ' sectors written',CR,LF,0 MSGF: db CR,LF,'Completed. ' db 'Type RETURN for another copy, OR...',0 MSGG: db CR,LF,'type ^C to reboot.',CR,LF,0 MSGH: db CR,LF,'++Memory buffer exceeded, cannot ',CR,LF db 'make duplicate copies this time;',CR,LF DB 'last ouput file is incomplete++',CR,LF,LF,0 MSGJ DB CR,LF,'++PROGRAM ABORTED++',CR,LF,0 MSGK DB CR,LF,'No file name specified',CR,LF,0 ; ; zeros: db 0,0,0,0 ; org ($+15)/16*16 ; fnt: ds 16*64+1 ; stack: ds 64 space: ds 2 ;available space msize: ds 2 ;memory size cbuf: ds 80 ;command buffer cbufp: ds 2 ;command buffer pointer fsize: ds 2 ;file size in sectors xsize: ds 2 ;file size for printout ifntp: ds 2 ;input fnt pointer ofntp: ds 2 ;output fnt pointer mbufp: ds 2 ;memory buffer pointer ifcb: ds 33 ;input fcb ofcb: ds 33 ;output fcb xfcb: ds 33 ;temporary fcb ibflg: ds 1 ;input break flag obflg: ds 1 ;output break flag NDFLG: DS 1 ;NO DUPLICATE ALLOWED FLAG ; mbuf equ $ ; end mft