; Copy file 1 to file 2. By C.B. Falconer. ; ; This illustrates use of the .BFSWAP routine for single ; buffering, and fast file to file copying, and separated ; parsing of input/output files. Note the use of .DRVLOCK ; to ensure that input and output files are different. ; ; d>FCOPY [-v] [d[u]:]afnin.aft [d[u]:]afnout.aft ; copies afnin.aft to afnout.aft ; (with full du addressing, across users, drives) ; the (optional) -v causes the output file to be CRC checked. ; ; 1.2 86/12/2 Minor change (options) to use BUFFLIB v1.4 up ; 1.1 86/5/14 Rewrite for wild card expansion. Need BUFFLIB v1.2 up ; 1.0 86/1/29 Original version ; ; ASSEMBLY (rmac is not usable) ; A>m80 fcopy,=fcopy ; or ; A>slrmac fcopy/r (much faster) ; ; CAUTION - nnnn/mmmm numbers below are examples, can change ; ; LINKING with L80 (slowest by far) ; ; A>l80 /p:100,/d:4000,fcopy,bufflib/s,/u,/r ; ; Link-80 3.44 . . . . ; Data 4000 405A < 90> ; Program 0100 0ADD < dddd> ; ; */p:100,/d:nnnn,fcopy,bufflib/s,fcopy/n,/e ; ^ using nnnn = 0ADD from above line (example only) ; ; LINKING with SLRNK ; ; A>slrnk /p:100,/d:4000,fcopy,bufflib/s,/u,/r ; ; Superlinker . . . . ; 0100-0ADC (09DD) 973E left ; Superlinker . . . . ; ; %/p:100,/d:mmmm,fcopy,bufflib/s,fcopy/n,/e ; ^ using mmmm = 0ADD, i.e. 0ADC + 1 (example only) ; ; LINKING with SLRNK+ (fastest and easiest, no copying numbers) ; ; A>slrnk+ /a:100,/j,fcopy,bufflib/s,fcopy/n,/e ; (does it all) ; ; Externals in BUFFLIB. See BUFFERS.DOC extrn .getusr, .xltusr, .setusr; user parsing extrn .wildx, .wldck, .pfnmdu; file parsing extrn .nextch, .skipblks; command parsing extrn .fncpy, .nxtout, .nxtfn; fname operations extrn .dos; bdos(a), save regs extrn .tdzs, .tfnam, .crlf; utility extrn .initfcb, .drvlock extrn .fopnw, .bfclose, .bfropen; file r/w opens extrn .fopnr, .bflush; and flushing extrn .bload, .bdump, .bfswap; file i/o extrn b.wflg; ext. constants extrn .bcrc; crc calculation extrn .bver; library version extrn .endata; Mark end of data seg. ; ver equ 12 buflibver equ 14; minimum to link stkmargin equ 128; bytes, incl. b.ohead ; boot equ 0 bdos equ boot+5 tfcb equ boot+05ch; used to hold outname template defdma equ boot+080h ; cr equ 0dh lf equ 0ah ; ; errors xhelp equ 0; no error, give help xwild equ 1; incompatible wildcards xtoself equ 2; copying into self xnofile equ 3; input file not found xnodir equ 4; fcreate failure xwrterr equ 5; write error xvererr equ 6; verify failure xusrabt equ 7; user abort xbadlib equ 8; linked to wrong library xok equ 9; done, without errors ; ; Dos function calls cin equ 1 pstrg equ 9 csta equ 11 ; ; Initialize begin: lhld bdos+1 mvi l,0; set stack at top of memory sphl call .getusr sta entryusr call .bver; This also ensures the lib version cpi buflibver; module is linked and identified mvi a,xbadlib jc exeunt; linked to wrong library lxi h,0 shld filesdone; zero count of files processed lxi d,defdma call markeol; of input command line inx d call options; from de^ ; " " ; parse in/out file names lxi h,fcbout call .initfcb lxi h,fcbin call .initfcb; init in and out fcbs call .pfnmdu mov a,b; is 0 for default, else usr+1 sta inuser lxi h,tfcb call .initfcb call .pfnmdu mov a,b sta outuser lxi d,fcbin; ensure locked to drive for compare call .drvlock; else default and specific drives lxi d,tfcb; may erroneously appear different call .drvlock ldax d sta fcbout; set output drive id lda fcbin+1 sui ' ' jz exeunt; a=0, help message lxi h,fcbin lxi d,tfcb call sdefault; if no output, make same as input call .wldck; Check wild cards compatible mvi a,xwild jc exeunt; Incompatible wildcards ; " " ; Expand any wild cards lxi h,.endata shld fnptr lda inuser call .xltusr; 0 means use default call .setusr lxi d,fcbin call .wildx; expand fcbin into wild list shld @inbuff; mark available memory xchg mov l,c mov h,b shld fncount; number of files matched lda entryusr call .setusr; restore entry user id ; " " ; Calculate space available for buffers lxi h,-stkmargin dad sp mov a,l sub e mov l,a mov a,h sbb d mov h,a; form buffer size available shld bufsize ; " " ; Now tfcb holds output file pattern, fnptr points to next ; input file name, and fncount holds file count to process. ; @inbuff points just above the file list, and the remainder ; of memory, less an allowance for stack use, is available. copy: lhld fncount mov a,h ora l dcx h shld fncount jz done; no more files call setfiles; setup input/output file names call show; file names set up lhld outuser; to l lda inuser call .xltusr mov h,a mov a,l call .xltusr; in case default and specified same cmp h lxi h,fcbout lxi d,fcbin cz cmpfns; users same, compare file names/drv mvi a,xtoself jz exeunt; can't copy to self lhld bufsize mov c,l mov b,h lhld @inbuff lxi d,fcbin lda inuser call .bfropen; open buffered input system mvi a,xnofile jc exeunt; input file not found lxi d,fcbout lda outuser call .xltusr; needs absolute user # call .fopnw; open output file mvi a,xnodir jc exeunt; fopen error lda verify mov b,a lda outuser call .xltusr; set user # for writes lxi h,0ffffh shld cksum; init cksum for verification lhld @inbuff lxi d,fcbout call copyfile; hl^ (buffer) to de^ (fcb) user a mvi a,xwrterr jc exeunt; write or fclose error lda outuser call .xltusr; in case verify inr b dcr b lxi d,fcbout cnz chkcksum; file de, user a, buffer hl^ mvi a,xvererr jnz exeunt; verify error lhld filesdone inx h shld filesdone jmp copy ; done: lhld filesdone mov a,h ora l mvi a,xnofile jz exeunt; no files found call .tdzs mvi a,xok ; " " ; output message index (a) and exit exeunt: lxi h,errtbl add a add l mov l,a; point to msgtable entry (a) adc h sub l mov h,a mov e,m; get pointer to message inx h mov d,m ; " " exit: mvi a,pstrg call .dos ; " " lda entryusr; restore user at entry call .setusr jmp boot ; ; messages for error codes 0 up errtbl: dw helpmsg, wildmsg; xhelp, xwild dw selfmsg, nofind; xtoself, xnofile dw nodirmsg, wrterrmsg; xnodir, xwrterr dw vererrmsg, abtmsg; xvererr, xusrabt dw badlibmsg, filesmsg; xbadlib, xok ; helpmsg: db 'FCOPY v', ver/10 + '0', '.', ver MOD 10 + '0' db ' by C.B. Falconer',cr,lf,cr,lf db 'usage: FCOPY [-v] [d[u]:]afnin.aft [d[u]:][afnout.aft]',cr,lf db ' default destination is source name if d or u different',cr,lf db ' optional -v causes CRC16 checksum validation of copy',cr,lf db 'ex: FCOPY -v b5:fcopy.* c6: (copies to C6: and verifies)$' wildmsg: db 'Incompatible wild cards, from/to$' selfmsg: db 'Can''t copy file to itself$' nofind: db 'Input file not found$' nodirmsg: db 'Can''t create, directory full?$' wrterrmsg: db 'Write error, disk full?$' vererrmsg: db 'Verification failure$' abtmsg: db '..ABORTED..$' badlibmsg: db 'Linked to obsolete library$' filesmsg: db ' files copied$' ; ; mark end-of-line with nul, text buffer de^ ; a,f,h,l markeol: ldax d mov l,a xra a mov h,a dad d inx h mov m,a; mark eol ret ; ; Parse any options from text line de^. Advance de if found ; a,f,d,e options: xra a sta verify; default no verify call .skipblks rz; end of line, no options cpi '-' rnz; not an option, back up call .nextch cpi 'V' jnz o3; not an option, back up sta verify; set verify flag jmp .nextch; and advance past option field o3: dcx d; back past bad option char ret ; ; make file de^ same name as hl^ (name/ext only) if no spec ; a,f sdefault: inx d ldax d dcx d cpi ' ' cz .fncpy; no specification, copy it ret ; ; copy (opened) file buffer hl^ to fcb de^, user (a). ; If (b) non-zero verify is set and cksum is computed ; At normal exit de points to input file and buffer hl^ is ; attached to the output file (closed). ; Carry for error. ; a,f,d,e copyfile: ori b.wflg; setup for write operations cpyf1: push psw; save write flags on stack call .bload jc cpyf4; eof on input, nothing loaded inr b dcr b cnz chkbuf; compute checksum on input pop psw call .bfswap; shift to write to fcb de^ push psw; save read flags call .bdump; write buffer out jc cpyf8; write error call ckabt; user abort during long files? pop psw call .bfswap; back to read. Trades de value jmp cpyf1 cpyf4: pop psw; write flags call .bfswap; back to output file jmp .bfclose; close and exit. cy for close error ; cpyf8: pop psw; write error occured stc ret ; ; Update the crc over the buffer hl^ ; a,f chkbuf: push b push h lhld cksum mov c,l mov b,h pop h call .bcrc; update crc over buffer push h mov l,c mov h,b shld cksum pop h pop b ret ; ; re-read buffer hl^, file de^, user a and check cksum ; z flag for match, non-z for mismatch ; a,f,d,e,h,l chkcksum: push h lhld cksum shld cksumr; save input version lxi h,0ffffh shld cksum; reset initial cksum push psw lxi d,fcbout call .fopnr; open output file for read pop psw pop h call .bfswap; to get the flags reset ckck1: call .bflush; make sure we start at bottom call .bload jc ckck2 call chkbuf jmp ckck1 ckck2: lhld cksumr xchg lhld cksum mov a,d sub h rnz mov a,e sub l ret ; ; setup input/output file names in fcbin/fcbout ; using the globals fnptr, tfcb ; a,f,b,c,d,e,h,l setfiles: lxi d,fcbin lhld fnptr call .nxtfn; load the next file name lxi d,16 dad d shld fnptr; advance source name pointer lxi d,fcbout; setup fcbout by lxi h,tfcb; copying template lxi b,fcbin; and replacing wild loc'ns call .nxtout ret ; ; show file to be transferred ; a,f,b,c,d,e,h,l show: lda inuser call .xltusr lxi d,fcbin call .tfnam; input file id lxi d,xfrtomsg mvi a,pstrg call .dos; '==>' lda outuser call .xltusr lxi d,fcbout call .tfnam; output file id lxi d,vmsg lda verify ora a mvi a,pstrg cnz .dos; '(verifying)' if so call .crlf ; " " ; Check for user abort ; a,f ckabt: mvi a,csta call .dos rz; no console interrupt mvi a,cin call .dos cpi 3 mvi a,xusrabt jz exeunt; user abort ret ; xfrtomsg: db ' ==> $' vmsg: db ' (verifying)$' ; ; check fcbs de^ and hl^ are different names, else zero flag ; a,f cmpfns: push b push d push h dcx h; pre-decrement dcx d mvi b,12; names and drive ids cmpfn1: inx h inx d ldax d xra m ani 07fh; ignore attributes jnz cmpfn2 dcr b jnz cmpfn1 cmpfn2: pop h pop d pop b ret ; dseg; LINK AFTER all code areas verify: ds 1; Flag for copy verification entryusr: ds 1; User in effect at startup ; ; inuser/outuser are 0 for current user, user+1 if specified inuser: ds 1; User # for fcbin outuser: ds 1; User # for fcbout ; fcbin: ds 36; Input fcb fcbout: ds 36; Output fcb bufsize: ds 2; space available for buffers @inbuff: ds 2; pointer to input buffer cksum: ds 2; CRC16 checksum for verify cksumr: ds 2; Save during readback filesdone: ds 2; count of files processed fncount: ds 2; count of files to process fnptr: ds 2; pointer to NEXT file to process ; ; Supplied as external by BUFFLIB ;.endata: ds 0; Actually rest of memory. Holds ; a list of file names to process, ; 16 bytes per name, for fncount ; entries. i/o buffers above this ; end