; Program: MOVE ; Author: Joe Wright ; Date: 28 February 1986 ; Version: 2.0 vers equ 22 ; Fixed bug in handling of large ; files. Needed to set S2, not s1 wild. ; Modified move algorithm for increased ; speed. Now uses "search next" and ; does only one write per directory ; sector per file instead of possibly ; four. ; Cleaned up command line parsing code. ; Removed special handling for stand- ; alone user numbers as DUSCAN seems ; to do it right. Shortened code in ; SCANER: and fixed IFCBG: to work with ; extended environment. Shortened code ; in several other places as well. ; Added a call to FRESET just before ; deleting a file in the destination ; area to avoid problems when running ; under DRI BDOS. ; Added conditional assembly for type 4. ; December 4, 1989 Howard Goldstein ; ;vers equ 21 ; "B" version, one Bridger hint, one bug fix. ; Wildcard to both extent bytes before file ; existence test in "mainloop:", clear carry ; flag before the "sbc hl,de" a little after ; the call to "eval10". ; December 31, 1987 Bruce Morgen ; "A" version, incorporated Bridger's FRESET ; December 30, 1987 Bruce Morgen ; ZCPR33 Type 3 format with safety header, search ; for an empty user area instead of bombing out ; everything in user 31, established DSEG - with ; initialization to assure predictable re-entrance. ; Fixed wildcard FCB (had too many "?"s). Allow ; legitimate DU/DIR destination specs without ; colons, ditto standalone user numbers. Added ; intelligent help message (change name to MAKE or ; MV, help also changes). Scanning code ATTEMPTS ; to following all Z33/BGii stipulations where ; applicable.... ; December 28, 1987 Bruce Morgen ;vers equ 20 ; Fixed drive selection bug. Add Query as default ; option. Report directories in DU:DIR form. ; 28 Feb 86 jww z3env equ 0 .accept 'Program type (3 or 4) ',type biosv equ 001h fcb1 equ 05ch usr1 equ fcb1+13 fcb2 equ 06ch usr2 equ fcb2+13 tbuf equ 080h tab equ 9 cr equ 13 lf equ 10 ext z33chk,getccp,freset ext z3init,cout,dutdir,dnscan,duscan,dirscan,getefcb ext pafdc,prttype,eprint,pfn1,bdos ext caps,cin,hfilb,fillb,@fncmp ; TYPE 3 HEADER ; Code modified as suggested by Charles Irvine to function correctly with ; interrupts enabled. Program will abort with an error message when not ; loaded to the correct address (attempt to run it under CP/M or Z30). entry: if type eq 3 jr start0 ; Must use relative jump nop ; Filler else rst 0 dw start endif db 'Z3ENV' z3type: db type z3eadr: dw z3env ; Filled in by Z33 dw entry ; Intended load address if type eq 3 start0: ld hl,0 ; Point to warmboot entry ld a,(hl) ; Save the byte there di ; Protect against interrupts ld (hl),0c9h ; Replace warmboot with a return opcode rst 0 ; Call address 0, pushing RETADDR ; onto stack retaddr: ld (hl),a ; Restore byte at 0 dec sp ; Get stack pointer to point dec sp ; To the value of RETADDR pop hl ; Get it into HL and restore stack ei ; We can allow interrupts again ld de,retaddr ; This is where we should be xor a ; Clear carry flag push hl ; Save address again sbc hl,de ; Subtract -- we should have 0 now pop hl ; Restore value of RETADDR jr z,start ; If addresses matched, begin real code ld de,notz33msg-retaddr ; Offset to message add hl,de ex de,hl ; Switch pointer to message into DE ld c,9 jp 0005h ; Return via BDOS print string function notz33msg: db 'Not Z33+$' ; Abort message if not Z33-compatible endif start: ld (stack),sp ld sp,stack ld a,'Q' ld (option),a ld a,32 ld (empusr),a ld hl,fcbwild ld (hl),0 inc hl ld b,11 ld a,'?' call hfilb xor a ld b,4 call fillb ld c,12 ; Get dos version call bdos cp 30h jp z,baddos ; Cant run under CP/M+ ld hl,(z3eadr) LD A,H OR L JP Z,BADDOS ; Must have a Z3 environment call z3init ; initialize the environment ; ; Turn off PUBLIC ; ld de,126 add hl,de ; point to PUBLIC bytes ld e,(hl) inc hl ld d,(hl) ld (public),de ; save them xor a ld (hl),a dec hl ld (hl),a ; Turn public off ld hl,fcb1+1 ld a,(hl) cp ' ' jp z,help ; Invoked without command tail cp '/' jr nz,gotname inc hl ld a,(hl) cp '/' jp z,help ; Help is asked for ; ; Search for options ; gotname: ld hl,tbuf+2 ; Beginning of command tail gotloop: ld a,(hl) ; Get the character inc hl ; Point to next or a jr z,got0 ; Use default options cp '/' jr nz,gotloop ; Try again ld a,(hl) ; Get option character cp 'O' ; Overwrite option jr z,setopt cp 'S' ; Skip option jr z,setopt cp 'Q' jp nz,invopt ; Invalid option selected setopt: ld (option),a ; ; Resolve Drive/User with ZCPR3 constructs ; got0: ld a,(fcb2+15) ; Check for valid z33 parse or a jr nz,jpinvdu ; Complain immediately if we detect it ld a,(fcb1+15) or a jr nz,jpinvdu ld a,(fcb1) ; Source dec a ; 0ffh if current drive, otherwise drvno. call m,getdsk ; Return selected disk ld (drvno),a ; Save drive number ld hl,fcb2+1 ; Point second FCB name area ld a,' ' cp (hl) ; Is it blank? jr nz,doscan ; If not, go parse possible DU dec hl ; Point back to drive byte ld a,(hl) dec a call m,getdsk ; Via BDOS if necessary ld b,a ; Stow in B ld a,(usr2) ; Get CCP-parsed user code ld c,a ; Into C got1: ld a,(usr1) ld (srcusr),a cp c jr z,jpinvdu ; Users must be different ld a,c ld (desusr),a ld a,(drvno) cp b jr nz,jpinvdu ; Drives must be the same ld c,14 ; Select drive ld e,a call bdos jr search0 ; doscan: call scaner ; Parse du or dir jr nz,got1 ; Use that if successful jpinvdu: jp invdu ; search0: ; ; Find a scratchpad user area ; ld hl,desusr ld a,(empusr) search1: dec a jp m,usfail cp (hl) jr z,search1 ld (empusr),a call gsuser ld de,fcbwild ; All wildcards call searchf jr nz,search0 ; ; Confirm file existence ; userok: ld a,(srcusr) call gsuser ld de,fcb1 call searchf jp z,nofile ld a,(fcb1+7) ; Get "found via ZDOS public" flag bit 7,a jp nz,nofile ; File considered not found if so ; ; Check for CON: abort, then do per-file main loop ; mainloop: ld c,6 ; Direct console input ld e,0ffh call bdos cp 3 ; Control C? jp z,abort ld de,fcb1 call searchf ; Search First function jp z,quit ; No more found call findir ; Point to specific entry in tbuf ld bc,16 ; Move 16 bytes ld de,fcbdrv ldir ld a,(desusr) call gsuser ld a,(fcb1) ; Drive number ld (fcbdrv),a ; Replace user number from BDOS ld a,'?' ; Wild card ld (fcb1+12),a ld (fcb1+14),a ld (fcbext),a ; Make extents wild ld (fcbs2),a ld de,fcbdrv call searchf jp nz,filexists ; Bail out if file exists in destination call eprint db cr,lf,' Moving ',0 ld a,(srcusr) call pdir ld de,fcbname ; Point to name call pfn1 call eprint db ' to ',0 ld a,(desusr) call pdir ld a,(srcusr) call gsuser call moveit jr mainloop moveit: ld c,17 ; Start with "search first" ld de,fcbdrv ; ; At this point, de points to fcb and c contains function code ; mvt0: call search ; Find matching entry ret z ; Not this one, try again ld b,0 ; Init counter call findir ; point hl to dir entry mvt1: ld a,(desusr) ld (hl),a ; Replace current with destination inc b ; Bump count of entries changed in this sector ; ; Check for additional matches in current dir sector ; mvt2: ld a,20h add a,l ; Point to next entry jr z,mvt3 ; No more entries; write sector ld l,a ld a,(srcusr) ; Source user cp (hl) ; Compare with user in dir entry jr nz,mvt2 push hl ; Save regs push de push bc inc hl ; Point to filename inc de ld b,11 ; Compare 11 bytes (file name and type) call @fncmp pop bc pop de ; restore pointers pop hl jr z,mvt1 ; Match. Fix user number and check next jr mvt2 ; No match. Check next entry mvt3: call write ; Write the buffer back to disk call sync ; Do "search nexts" to keep in sync jr mvt0 ; ; SYNC does "search next" calls to keep BDOS in sync with ; additional changes we might have made in the directory sector. On ; entry, DE contains pointer to FCB and B contains the count of ; searches necessary plus 1. On exit DE still has the FCB pointer and ; C contains 18, the function code for "search next" to be used by ; the call to SEARCH at MVT0. ; SYNC: LD C,18 ; Search next code syncloop: dec b ; Count down ret z ; Exit if no more call bdos ; Do function jr syncloop ; ..and loop back ; ; PDIR prints the drive, user and directory name ; pdir: ld c,a ; Store user number in c ld a,(drvno) ; Get drive ld b,a ; ..and store in b add a,'A' call cout ld a,c call pafdc ld a,':' call cout call dutdir ; Attempt to find directory name jr nz,name ; Found it call eprint db 'Noname- ',0 ret name: ld b,8 ; Print 8 chars max name1: ld a,(hl) ; Get dir name char call cout ; Print it cp ' ' ; Was it a space? ret z ; Return if so inc hl djnz name1 ld a,' ' jp cout ; ; Return current disk in A ; getdsk: ld c,25 jp bdos ; ; Get/Set user function ; gsuser: ld c,32 ld e,a jp bdos ; ; Search For First function ; searchf: ld c,17 search: call bdos cp 0ffh ret ; ; Point hl to the found directory entry ; findir: rrca rrca rrca add a,tbuf ld l,a ld h,0 ret ; ; Bios Write function, preserve regs ; write: push bc push de call wrt1 pop de pop bc ret wrt1: ld hl,(biosv) ld l,42 ; Bios write entry ld c,1 ; Directory write jp (hl) ; Jump to bios, return to syncloop ; ; Convert D, U, DU, or named DIR to drive in B, user in C scaner: call ifcbg ; Running BGii? (Returns a=0 if so) jr z,scanjp ; BG is always DU before DIR call z33chk ; Running Z33 or later? (a=0 if so) jr nz,scanjp ; If not Z33, assume dir first push hl ; Save pointer call getccp ; Get start of CCP ld de,7 ; Offset to the option flag add hl,de ld a,(hl) ; Option flag to a pop hl ; Restore pointer bit 0,a ; Do we take DU prefixes at all? jr nz,chkdir ; If so, see if DIRs are also OK and 10b ; If not, DIR is our only hope jp nz,dirscan ; OK, scan for DIR only ret ; Otherwise return Z for failure chkdir: bit 1,a ; Let's see if both DIR and DU jp z,duscan ; If not, scan for DU only and 100b ; Isolate du-first bit xor 100b ; Invert (0 = du first) scanjp: jp dnscan ; Central JP so we can use JRs ; Adapted from Jay Sage's COMIF: ; ; Condition: BG (BackGrounder) ; ; This option tests for the presence of the 'BGii' ID string that ; shows that BackGrounder ii is running. The code looks for the ; ID at an offset of IDOFF from the beginning of the CPR code. The ; value of IDOFF was determined by examination. idoff equ 5bh ifcbg: push hl call getccp ; Point to beginning of ccp ld de,idoff ; Offset to 'BGii' ID string in BG CPR add hl,de ld de,idstr ; Point to reference ID string ld b,idlen ; Length of ID string bgchk1: ld a,(de) ; Get reference character sub (hl) ; Compare to actual character jr nz,bgfals ; Set false if mismatch inc hl ; Move to next characters inc de djnz bgchk1 ; Loop through all characters bgfals: pop hl ret idstr: db 'BGii' idlen equ [$-idstr] ; Error message routines invopt: call eprint db cr,lf,tab,'-- Invalid Option --',0 jp help invdu: call eprint db cr,lf,'-- Invalid Drive/User Selection --',0 jp help baddos: call eprint db '-- CP/M 2.2-compatible Z System required!' db cr,lf,0 jp exit1 abort: call eprint db cr,lf,tab,'-- Aborted --',0 jp quit nofile: call eprint db cr,lf,tab,'-- No Source File --',0 jp exit usfail: call eprint db cr,lf,'-- No Empty User Area On Drive --',0 jp exit filexists: call eprint db cr,lf,' ',0 ld a,(desusr) call pdir ld de,fcbname call pfn1 ld a,(option) cp 'O' ; Overwrite jr z,overwr cp 'S' jr z,filex1 call eprint db ' exists. Move anyway? (Y or N)',0 call cin ; Wait for response call caps cp 'Y' jr z,overwr ; ; Move temporarily to scratchpad user area ; filex1: ld a,(desusr) push af ; save it on the stack ld a,(empusr) ld (desusr),a ; temporarily ld a,(srcusr) call gsuser call moveit pop af ld (desusr),a call eprint db ' NOT moved.',0 ld a,255 ld (wrflag),a jr filexex overwr: ; ; Reset drive and delete the destination file ; ld a,(drvno) call freset ld de,fcbdrv ld c,19 call bdos call eprint db ' Erased',0 filexex: ld a,(srcusr) call gsuser jp mainloop ; ; Main and ONLY program exit ; quit: ld a,(wrflag) or a jr z,quit5 ; ; Move any files in scratchpad user area back to source ; ld a,(empusr) call gsuser ld c,17 ; Start with "search first" ld de,fcb1 ; use ambiguous fcb quit1: call search jr z,quit5 ; No entries left ld b,0 ; Init counter call findir ; point hl to dir entry quit2: ld a,(srcusr) ld (hl),a ; Replace current with destination inc b ; Bump count of entries changed in this sector quit3: ld a,20h add a,l ; Point to next entry jr z,quit4 ; No more entries; write sector ld l,a ld a,(empusr) ; Scratch pad user cp (hl) ; Compare with user in dir entry jr z,quit2 ; Match. Fix user number and check next jr quit3 ; No match. Check next entry quit4: call write ; Write the buffer back to disk call sync ; Do "search nexts" to keep in sync jr quit1 quit5: ld a,(drvno) call freset exit: ; ; Turn PUBLIC on again ; ld hl,(z3eadr) ld de,126 add hl,de ; Point to PUBLIC area ld de,(public) ; Get original bytes ld (hl),e inc hl ld (hl),d exit1: ld sp,(stack) ret help: call eprint db cr,lf,'MOVE Version ' db vers/10+'0','.',vers mod 10+'0' db ' ',0 ld hl,entry ld a,type call prttype call eprint db cr,lf,'Syntax:',cr,lf,' ',0 call comnam call eprint db ' [dir1:]afn [dir2[:]] [/o]',cr,lf,lf,' ',0 call comnam call eprint db ' afn dir[:] Moves from current to dir:' db cr,lf,' ',0 call comnam call eprint db ' dir:afn dir1[:] Moves from dir: to dir1:' db cr,lf,' ',0 call comnam call eprint db ' dir:afn Moves from dir: to current.' db cr,lf,lf,'All directories must reference the same drive.' db cr,lf,'Options are: "Q"uery, "S"kip or "O"verwrite.' db cr,lf,'Duplicate entries will be Queried by default.' db cr,lf,lf,'Example: ',0 call comnam call eprint db ' dir:afn dir1: /o to overwrite.' db cr,lf,0 jp exit ; Print actual COMfile name if we can, ; otherwise print "MOVE" comnam: call getefcb jr z,noefcb ld b,8 comnml: inc hl ld a,(hl) and 7fh cp ' ' call nz,cout djnz comnml ret ; noefcb: call eprint db 'MOVE',0 ret ; ; The following line is included so that the PRTTYPE routine will use ; EPRINT rather than causing PRINT to be linked in as well. print:: jp eprint ;___________________________ ; dseg wrflag: ds 1 empusr: ds 1 srcusr: ds 1 drvno: ds 1 ; Drive number desusr: ds 1 fcbwild: ds 16 fcbdrv: ds 16 fcbname equ fcbdrv+1 fcbext equ fcbdrv+12 fcbs2 equ fcbdrv+14 option: ds 1 ; Default to Query duplicate files public: ds 2 ds 48 ; Stack area stack: ds 2 ; ZCPR3's stack end