;Program: PIPE.COM Fast File Transfer Utility ;Purpose: Small RAM disk resident, ambiguous file names and rename OK ;Author: Rob Friefeld, Long Beach CA ;Usage: PIPE [du:] [du:][afn] [/o] ;Version: 1.8 1/11/88 ; ;VERSION 1.8 ; Command line option "/" allows inspection or attribute selection ; before copy. May specify multiple options: [F]1..[F]4,W,S,R,A,I,N ; I = Inspect before copy, N = NO query before erase ; May negate options (except I and N) with "~" or "-" ; Copies meet emerging standard on attributes: if the destination exists, ; its attributes are maintained, else source attributes used. vers equ 18 topm defl 80h ; Use tpa up to 8000h topm defl topm-2 ; SYSTEM EQUATES INCLUDE SYSDEF.LIB start: ld (stksav),sp ; Set up local stack ld sp,stack ; ; Find top of TPA ; ; ld hl,(bdos+1) ; BDOS location ; ld a,(2) ; Get BIOS page ; sub h ; Get offset ; cp 0eh ; Test for standard offset ; jr nz,peep1 ; NZ means CCP protected ; ld a,h ; BDOS page in A ; sub 9 ; Leave room for CCP ;peep1: sub 1 ; Leave room for 1 record over read ; ld h,a ; ld (topmem),hl call cmdscan ; Scan command line call savspecs ; Save destination filename, users, drives call logsu ; Log source user for search function ld de,buf ; Address of file name list call search ; Get list of afn matches jp z,nofile ; No matches ld (filadr),de ; End of list, start of file buffer ld hl,buf ; Pointer to list of matches loop: push hl ; Save list position ld de,fcb+1 ; Move name to source fcb ld bc,11 ldir call zfcb ; Zero out rest of fcb pop hl ; Restore list postion ld de,destfcb+1 ; Copy same name to dest fcb ld bc,11 ldir push hl ; Save list position (now points to next name) call zfcb call rename ; If dest to be renamed, do it call specs ; File att selection option? jr nz,lp21 ; Yes, and this one ain't it call pfil ; Display file name call opfiles ; Open source and dest files jr z,lp2 ; Z = dest file exists AND don't erase it lp1: call r$wfile ; Read and write ld a,(cflag) ; Is entire file copied or a jr nz,lp1 ; No ld c,closef call bdosde ld a,(roflag) ; Check R/O status of dest or a jr z,lp11 ; Not R/O ld hl,destfcb+9 ; Set t1 attribute set 7,(hl) lp11: ld c,attrf ; Set attributes call bdosde lp2: call print db cr,lf+80h lp21: call pbreak ; Abort? pop hl ; Restore pointer ld a,(hl) ; Check for list terminator or a jr nz,loop exit: ld sp,(stksav) ret ; To CCP ; ; Subroutines ; quit: call print db ' PIPE ',vers/10+'0','.',vers mod 10+'0' db 0 jr exit nodir: call print db 'Dir Ful','l'+80h jr exit nofile: ; ld de,fcb ; Print source du:filname and message ; call pdsk ; ld a,(susr) ; call pusr ; ld de,fcb ; call pfn call print db ' No Fil','e'+80h jr exit full: ld c,erasef call bdosde ld c,resetdkf ; Reset disk system call bdos call print db cr,lf,'Disk ful','l'+80h jr exit ; Check command line for options cmdscan: ld a,(fcb+1) ; File name input? cp ' ' jr z,quit ; Print message and quit cp '/' jr z,quit ; Save destination filename. Set renaming flag. savdest: ld hl,fcb2+1 ; Destination filename sd00: ld a,(hl) ; First char cp '/' ; Don't confuse option trigger for name jr nz,sd01 ld a,' ' ; Replace '/' with a blank sd01: sub ' ' ld (rflag),a ; Rename flag: Z = don't, NZ = do ld bc,11 ; Dest name -> savfcb, used for rename ld de,savfcb ldir ; Reset flag table ld b,4 ; Four flags ld de,aflag ; Address of first flag call zfill ; Zero fill ; xor a ; ld (sflag),a ; SYS flag ; ld (aflag),a ; ATT flag ; ld (iflag),a ; INSP flag ; ld (nflag),a ; NO QUERY flag ; Command tail scan ld hl,tbuf ; Start of tail ld c,0 ; Accumulate flag bits in C call fspec1 ; Do the scan ld a,c ; Save C in AFLAG ld (aflag),a ret ; Scan command tail for '/' fspec1: inc hl ld a,(hl) or a ret z ; Not found, no options cp '/' jr nz,fspec1 ; What follows '/' ? ; Skip anything not significant until end of command line tail ; AFLAG is loaded with a bit set for each att selected: ; msb> A S R W 4 3 2 1 fspec2: inc hl ; Next char ld a,(hl) or a ret z ; End of tail cp '~' jr z,fspecN ; Negate cp '-' jr z,fspecN ; Negate cp 'S' jr z,fspecS ; SYS/DIR cp 'W' jr z,fspecW ; Wheel cp 'R' jr z,fspecR ; R/O, R/W cp 'A' jr z,fspecA ; ARC cp 'I' jr z,fspecI ; Inspect cp 'N' jr z,fspecX ; NO query sub '0' ; Check for number 1-4 cp 1 jr c,fspec2 ; Skip cp 5 jr nc,fspec2 ; Skip fspec21: ld b,a ; Save number ld a,80h ; MSB only rlca ; Rotate it to appropriate position djnz $-1 or c ; Merge it with flag ld c,a jr fspec2 ; Continue fspecW: ld a,5 jr fspec21 fspecR: ld a,6 jr fspec21 fspecS: ld a,7 jr fspec21 fspecA: ld a,8 jr fspec21 fspecN: ld (sflag),a ; Sense flag is NZ jr fspec2 fspecI: ld (iflag),a jr fspec2 fspecX: ld (nflag),a jr fspec2 ; ; Selection by attribute ; AFLAG bits are set for attributes F1..F4,WP,SYS,R/O,ARC ; SFLAG Z = normal sense, NZ = reverse sense ; Return Z = OK, NZ = skip ; Logic: ; s+ exit Z ; att+ < ; flag+ < s- exit NZ ; att- ; \ s+ skip ; flag- < ; s- OK so far specs: ld a,(aflag) ; Get flag bits or a ret z ; None set, copy all ld c,a ; Save bits ld d,a ; OK so far flag: Any NZ value = NOT OK ld a,(sflag) ; Sense flag or a ex af,af' ; Save in AF' ld hl,destfcb ; -> matched file name ld b,4 ; Loop for F1..F4 call specs01 ; Look for flags inc hl ; Skip f5..f7 inc hl inc hl ; W/P is f8 ld b,4 ; Loop for W,S,R,A call specs01 xor a or d ; Z = OK (so far, and we are done) ret ; Implement above logic tree specs01: rr c ; LSB to carry inc hl ; -> char with attr jr c,specs03 ; Bit set ; Flag bit NOT set specs02: ex af,af' ; Sense jr z,specs021 ; +, skip ld d,0 ; -, OK so far specs021: ex af,af' ; Save sense flag djnz specs01 ; Continue loop ret ; Flag bit set - sudden death on this test specs03: ld a,80h ; Check this attr bit and (hl) ; Mask char @ HL jr z,specs02 ; Att - ex af,af' ; Sense? pop bc ; Lift stack ret ; Exit ; ; ENTRY FROM MAIN LOOP ; savspecs: ; Save the drives and users of source + destination savdu: ld a,(fcb+13) ; Get and store user #'s ld (susr),a ld a,(fcb2+13) ld (dusr),a ld hl,fcb ; If drive is default, make it explicit ld a,(hl) or a call z,getdefdrive ld hl,destfcb ld a,(fcb2) ld (hl),a or a ret nz getdefdrive: ; Load default drive into @HL push hl ld c,inqdiskf call bdos pop hl inc a ld (hl),a ret ; Rename destination file rename: ld a,(rflag) ; Rename wanted? or a ret z ld b,11 ; Matched source name has been copied ld hl,savfcb ; Use template to overwrite unambig chars ld de,destfcb+1 ren1: ld a,(hl) cp '?' ; Leave wild card parts alone jr z,ren2 ld (de),a ; Rename other parts ren2: inc hl inc de djnz ren1 ret ; Zero out rest of an FCB zfcb: ld b,24 zfill: xor a ; Zero fill entry zfcb1: ld (de),a inc de djnz zfcb1 ret ; Log source or dest user logsu: ld a,(susr) jr log logdu: ld a,(dusr) log: ld e,a ld c,sguserf jp bdos ; ; ENTRY FROM MAIN LOOP ; opfiles: ; Open source file opsrc: call logsu ld de,fcb ld c,openf call bdos inc a jp z,nofile ; Open file fails ; Open destination file opdest: ld de,tbuf ; Restore DMA to 80h ld c,setdmaf call bdos call logdu ; Log dest user call roset ; Set or reset r/o flag from source ld c,srchff ; Check existence of destination call bdosde cp 0ffh ; Preserve offset to matched file in A jr nz,od0 ; File exists (inspection redundant) ld a,(iflag) ; Inspection flag? or a jr z,od1 ; Not this time call print db ' -',' '+80h call query ; Copy? jr z,od1 ; Do it xor a ; Don't do it ret od0: call file$exists ; Deal with existence of file ret z ; Copy aborted od1: ld c,makef ; Make new file call bdosde inc a jp z,nodir ; Unable to make new file ret ; Normal exit returns NZ ; Destination file exists: ; Locate file name in tbuf ; Make sure file is not being copied to itself ; Find out if file is R/O and warn user ; Copy match to dest fcb to maintain destination attributes ; Finally, do we want to erase it? file$exists: call sfind ; Find entry into TBUF dec hl ; Now pointing to user number of entry ld a,(rflag) ; Renaming? or a jr nz,fil$ex2 ; Yes, skip self-copy test ld a,(susr) ; Compare users cp (hl) jr nz,fil$ex2 ; Different ld a,(fcb) ; Compare drives ld c,a ld a,(destfcb) cp c jr nz,fil$ex2 ; Different call print ; Don't do copy db ' ??','?'+80h xor a ret fil$ex2: inc hl ; Move name ld de,destfcb+1 ld bc,11 ldir call roset ; Set or reset r/o flag by destination or a jr z,erase ; File not R/O call print ; Warn user db bel,' R/','O'+80h erase: ld a,(nflag) ; Erase without prompt? or a jr nz,erase1 ; Yes call print db ' - Eras','e'+80h call query jr z,erase1 xor a ret erase1: ld c,attrf ; Take care of R/O status call bdosde ld c,erasef ; Erase the file call bdosde or a,-1 ; NZ return means we said "YES" ret roset: xor a ; Set or reset r/o flag ld hl,destfcb+9 ; Offset of R/O bit bit 7,(hl) ; Test it (NZ=set) jr z,roset1 res 7,(hl) ; Reset it for now dec a ; Set flag for later roset1: ld (roflag),a ret pfil: ; Routine to display file names call print db ' Copying -->',' '+80h ld de,fcb call pdsk ld a,(susr) call pusr call pfn call print db ' to',' '+80h ld de,destfcb call pdsk ld a,(dusr) call pusr ld a,(rflag) ; If not renaming, don't repeat name display or a ret z pfn: ld b,8 ; Print file name DE -> fcb inc de call pfn0 call print db '.'+80h ld b,3 pfn0: ld a,(de) call conout inc de djnz pfn0 ret pdsk: ld a,(de) ; Print file drive DE -> fcb add 'A'-1 pdsk0: jp conout pusr: cp 10 ; Print user number in A jr c,pusr1 ld c,'0' pusr00: inc c sub 10 cp 10 jr nc,pusr00 push af ld a,c call conout pop af pusr0: add '0' call conout ld a,':' jr pdsk0 pusr1: call pusr0 ld a,' ' jr pdsk0 query: call print db '? (y/N/q)',' '+80h call getc ; Get user's response and 5fh ; Upcase it cp 'Q' ; Quit jp z,exit cp 'Y' jp z,conout call print ; RET with NZ on any response but 'Y' db 'N'+80h or -1 ret r$wfile: ; READ THE SOURCE FILE INTO MEMORY getfil: call logsu ; Log source user # xor a ld (cflag),a ; Reset copy flag ld b,a ; Zero count of records read ld c,a ld hl,(filadr) ; Location of file buffer getlp: push bc ; Save count push hl ex de,hl ; Set address for read ld c,setdmaf call bdos ld de,fcb ld c,readf ; Note that readf returns A <> 0 call bdos ; when reading record after EOF. or a ; Hence RCOUNT = 1 on one rec file pop hl pop bc jr nz,get0 ; EOF encountered, exit loop call pbreak ; Permit ^C abort inc bc ld de,128 add hl,de ; ld a,(topmem+1) ; Check remaining room ld a,topm cp h jr nc,getlp ; Still room ; ld a,0ffh ; Out of room ld (cflag),a ; Set flag copy get0: ; WRITE THE DESTINATION TO DISK wrtfil: ld a,b ; Test for 0 length file or c ret z push bc call logdu pop bc ld hl,(filadr) wrtlp: push bc push hl ex de,hl ld c,setdmaf call bdos ld c,writef call bdosde or a pop hl pop bc jp nz,full ; Disk full error call pbreak ; Permit ^C abort ld de,128 ; Move pointer along 128 bytes add hl,de dec bc ld a,b or c jr nz,wrtlp ; And get next record or a,0ffh ; Force NZ on normal return ret bdosde: ld de,destfcb jp bdos ; Abort program if ^C entered pbreak: push hl push bc push de ld c,constf call bdos or a jr z,pbrkx ld c,rdconf call bdos cp ctrlc jp z,exit pbrkx: pop de pop bc pop hl ret conout: push hl ; Print char in A push de push bc push af and 7fh ld e,a ld c,wrconf call bdos pop af pop bc pop de pop hl ret print: ex (sp),hl ; Sends following DB to cons until 0 or MSB set ld a,(hl) inc hl ex (sp),hl or a ret z call conout ret m jr print getc: ld e,0ffh ; Get a character without screen echo ld c,dirconf call bdos or a jr z,getc ret ; Routine finds matches for ambiguous file spec ; Call: ; FCB1 with name to match, DE -> start of list buffer ; Return: ; Z if no match, DE -> next free address ; No registers preserved ; Buffer terminates with 0 search: ld c,srchff ; Find first match push de ; Save original address sloop: push de ; Pointer ld de,fcb call bdos cp 0ffh jr z,sex ; Exit when no more matches call sfind ; Point to match in tbuf ld bc,11 ; Move matched filename into buffer pop de ; List pointer ldir ld c,srchnf ; Search next jr sloop sfind: rrca ; A * 2**5 is offset into tbuf rrca rrca add a,tbuf+1 ; LSB of actual name address ld l,a ld h,0 ; HL now -> beginning of matched filename ret sex: pop de ; End of list pointer pop hl ; Start of list pointer xor a ld (de),a ; 0 list terminator sbc hl,de ; Z = haven't made any entries inc de ; Return with next free address ret ; ; Uninitialized Data Area ; aflag ds 1 ; Check att bit before transfer iflag: ds 1 ; Inspect before transfer flag sflag: ds 1 ; Sense flag nflag: ds 1 ; NO ask erase flag rflag: ds 1 ; Wild card rename flag roflag: ds 1 ; Dest was R/O savfcb: ds 11 ; Destination name template susr: ds 1 ; Source user # dusr: ds 1 ; Dest user # rcount: ds 2 ; Record count cflag: ds 1 ; Copy not done flag filadr: ds 2 ; Address of file buffer ;topmem: ds 2 ; Top of memory address destfcb: ds 36 ; Temp storage for destination FCB stksav: ds 60 ; Stack space stack: equ $ buf: equ $ ; Initial file buffer location end