; NOTE: This is a copyrighted program released for private, ; non-commercial use ONLY. Please read copyright statement ; starting on line number 74 for details. ;Program: VREN (Visual RENamer) ;Author: Bruce Morgen (contact via DHN* @ 215-623-4040) ;Version: 1.1 ;Date: June 5, 1991 ; ;Modified/pruned VREN and MYSORT, created WILDEN module to ;replace WILDEX with the addition of Type 4 compatibility. ;If the program type is 4, the filename buffer is built ;below the program, if not it is above the program as in ;version 1.0. With the "short" equate set true, the Type 4 ;VREN 1.1 is just under 32 records (4K) in size. No ;operational changes, VREN is either perfect or nobody but ;Bob Dean and myself use it -- there have been no bug ;reports whatsoever in the nearly three years since the ;initial release.... ;Program: VREN (Visual RENamer) ;Author: Bruce Morgen (contact via DHN* @ 215-623-4040 or ;Version: 1.0 Lillipute Z-Node @ 312-649-1730) ;Date: August 8, 1988 ;Purpose: ; Interactive renaming of files with format checking. ; VREN takes a single wildcard filespec from the command ; (if none given, "*.*" assumed). It then allows the ; user to step through the file names and change them ; using the WordStar(tm) diamond and/or the TCAP-defined ; arrow keys for cursor movement. This includes the WS ; control-A/control-F end-of-line commands. VREN always ; operates in an overwrite mode - there is no control-V ; mode toggle. Typing a period (.) moves the cursor to ; the first character of the file extension, wiping out ; any remaining filename characters to properly ; attributed blanks, unless the cursor is over the first ; character of the extension, in which case it moves to ; the last character of the filename. Otherwise editing ; behavior is quite predictable. There is a rubout ; function closely resembling WS response and the WS ; control-G (gobble) also works, although both treat the ; filename and extension as distinct fields. A carriage ; return initiates the actual renaming of the file. VREN ; toggles file attributes using control-T as the trigger, ; but, as with a rename, nothing changes until a RET. ; Any attributed characters are shown in alternate video ; or lower case if possible. Unless VREN is "quieted" ; there is a "12345678|rsa" header for clarity. There ; is protection against setting attribute #2, the home ; of the Plu*Perfect-style "PUBlic" tag, if more than ; one file of the name in question exist on the same ; drive. To disable this feature for non-PUBlic BDOS ; or vanilla ZRDOS, see "Patching" below. ;_______________________________________________________________ ; ; Patching: VREN obeys the ZCPR3 Quiet Flag unless the ; low (0) bit of the byte at origin+2 (102h in DDT) is ; patched to a non-zero value - in that case VREN is ; always "quiet." The high (7) bit of this byte ; controls the attribute #2 protection scheme for ; Plu*Perfect-compatible DOSs described above. Set ; this bit if you know what you're doing and want to be ; able to set attribute #2 at will. ; ; Value at origin+2 Results in: ; ----------------- ----------- ; 00h "loud" & PUBlic protected ; 01h "quiet" & PUBlic protected ; 80h "loud" & PUBlic unprotected ; 81h "quiet" & PUBlic unprotected ;_______________________________________________________________ ; ; [ N O T I C E O F P R O G R A M O W N E R S H I P ] ; VREN is copyright 1988 by the author. It is released to ; the user community in source and/or object form for non- ; commercial use only. Permission is hereby given to use ; and/or modify it in any way that you see fit. The author ; retains exclusive rights to public release of VREN and ; asks that any improvements to the program or adaptations ; for other operating environments not be distributed in ; any way without his consent. Furthermore, any commercial ; use of VREN, including its internal algorithms and screen ; presentation, without the express written agreement of ; the author is specifically prohibited. This prohibition ; includes sale of the program in any form except as part ; a user group library disk selling for not more than $20 ; copying and handling fee or as a download offering on ; remote access systems with no fee charged beyond normal ; subscription and/or access rates. VREN may not be sold ; or licensed by any person other than the author or his ; authorized agent(s). As of August 8, 1988, there have ; been no such agents appointed. ; ; The author warrants that VREN comprises his original ; work and as such is protected by the copyright laws of ; The United States of America and applicable international ; copyright regulations. No other warranty is expressed or ; implied. ; ; (signed) Bruce Morgen August 8, 1988 ;_______________________________________________________________ false equ 0 true equ not false short equ true ; Omit safety header ; fcb equ 5ch ; First default FCB renbuf equ fcb ; Page 0 address for simplicity pubbit equ renbuf+2 tbuff equ 80h ; Default disk I/O buffer schnxt equ 18 ; BDOS search for next function getdpb equ 31 ; " get D.P.B. function spc equ 20h ; ASCII cr equ 13 ; " lf equ 10 ; " bel equ 7 ; " bs equ 8 ; " esc equ 1bh ; " delete equ 7fh ; " ctrlt equ 'T'-'@' ; Attribute toggle command ctrlc equ 3 ; CP/M-ish abort character ctrlg equ bel ; WS "gobble" character ctrld equ 4 ; WS diamond > ctrle equ 5 ; " " ^ ctrls equ 'S'-'@' ; " " < ctrlx equ 'X'-'@' ; " " v ctrla equ 1 ; " " far < ctrlf equ 6 ; " " far > z3env equ 0000 ; Dummy value, CCP fills it in public $memry,entry,z3eadr,cout extrn wilden,sort,z3vinit,tinit,dinit,stndout,stndend extrn getwhl,getefcb,getquiet,z3log,dutdir extrn f$rename,f$exist,f$delete,initfcb,sfa,bdos extrn fillb,moveb,retud,logud,compb,@fncmp extrn isalpha,isalnum,isprint,caps,pafdc,cin,bout ; 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: jr start0 ; Must use relative jump flagb: db 0 ; Local flag, see "Patching:" db 'Z3ENV',3 ; Type-3 environment z3eadr: dw z3env ; Filled in by Z33 dw entry ; Intended load address start0: if not short 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 sbc hl,de ; Subtract -- we should have 0 now jr z,start ; If addresses matched, begin real code add hl,de ; Restore value of RETADDR ld de,notz33msg-retaddr; Offset to message add hl,de ex de,hl ; Switch pointer to message into DE dosprt: ld c,9 jp 0005h ; Return via BDOS print string function notz33msg: db 'Not Z33+$' ; Abort message if not Z33-compatible endif ;not short start: ld hl,(z3eadr) ; Get Z3 environment pointer call z3vinit ; Pass to VLIB & Z3LIB first ld de,80h+16 ; Offset to arrow key defs. add hl,de ; Compute pointer ld (keys),hl ; Store it locally call tinit ld a,((z3eadr-1)) add a,'0' ld (asctyp),a ld hl,fcb+1 ; Point FCB filename ld a,(hl) ; Get first character cp '/' ; Help query? jp z,help ; Then honor it cp spc ; No filename specified? ld a,'?' ; Set up to build wildcard ld b,11 call z,fillb ; Do it if Z ex de,hl ; FCB+1 to DE dec de ; Adjust to FCB call z3log ; Log in call initfcb ; Clean up call wilden ; Expand jp z,nofile ; Give up if nothing ld (count),hl ; Store count ld (tcount),hl ; 2x ld (acount),hl ; 3x ld b,h ; Count to BC ld c,l ld de,16 ; Offset between entries to DE ld hl,($memry) ; Buffer again in HL ld a,c ; Test for only one file dec a or b call nz,sort ; Sort if required call lgqui jr nz,quiety ld de,instrc ; Print instruction header call dosprt ; Using DOS call dispdu ; Display directory information quiety: ld hl,($memry) ; Recover buffer start call getwhl ; Privileged users see all files call z,pack ; Otherwise tag $SYS & R/O files jp z,nofile ; & bail out if no visible file loop: ld de,renbuf ; Scratch filename buffer (FCB) ld (hl),d ; Zero the drive byte position ld b,12 ; Copy 12 bytes call moveb ; Do it inc de inc de ; Point PUBlic flag bit position ld a,(de) ; Get char. and 80h ; Isolate attribit ld (pubflg),a ; Will be non-zero if PUBlic dec de ; Point filename start frbklp: call movovr ; Cursor to left margin call prnfn ; Print filename w/spaces call movovr ; To margin again ld a,'[' call cout mvloop: ld a,(de) ; Get char. and 80h ; Extract attribit ld c,a ; Store in C inloop: call cin ; Console input char. ld ix,(keys) ; Get pointer to arrow key defs. cp cr ; Done? jp z,doren ; Then do renaming cp ctrlc ; Abort? jp z,dinit ; & return via vlib deinit code cp esc ; Restore current name? jr z,loop ; Restore filename and loop cp delete ; WS-style destructive BS? jp z,rubout ; We can do that cp ctrlg ; WS-style ^G char.-delete? jp z,gobble ; We support that too... cp ctrlt ; Flip the attribit? jp z,toggle ; Why not... cp ctrle ; Go to previous? jp z,prvios ; Then do that cp (ix+0) ; Go to previous? jp z,prvios ; Then do that cp ctrlx ; Go to next? jp z,next ; Then do that cp lf ; Go to next? jp z,next ; Then do that cp (ix+1) ; Go to next? jp z,next ; Then do that cp ctrld ; Cursor forward? jp z,forwrd ; That's legit cp (ix+2) ; Cursor forward? jp z,forwrd ; That's legit cp ctrlf jp z,farfor cp ctrls ; Cursor backward jp z,bckwrd ; So's that cp bs ; Cursor backward jp z,bckwrd ; So's that cp (ix+3) ; Cursor backward jp z,bckwrd ; So's that cp ctrla jp z,farbak call caps ; Capitalize call isalnum ; Number or letter? jr z,gotspc ; Always OK call isprint ; Printable? jr nz,inloop cp '?' ; Filter illegal chars. jr z,inloop cp '*' jr z,inloop cp ';' jr z,inloop cp ':' jp z,inloop cp '.' jr nz,gotspc ; Process a period. If the current pointer position is within the ; filename portion of the work buffer, replace all remaining filename ; characters with properly attributed blanks. If the pointer is on ; the very first character of the buffer or within the filetype ; portion, simply put the pointer and cursor in the appropriate ; positions (RENBUF+9 and just after the period) and loop. period: ld a,renbuf+1 ; Special treatment for "." cp e ; Are we on first char.? jr z,nospcs ; Then just move cursor ld a,renbuf+9 ; Already somewhere in ext.? sub e ; Compute space count jp z,goback ; Go left if right at ext jr nc,eratoe ; Branch ahead if not in ext ld e,renbuf+1 ; Otherwise point to filename nospcs: call movovr ; To left margin of CRT call prnfn ; Print entire filename.typ ld b,3 ; Backspace counter in B ld a,bs ; Char. in A bs3lp: call cout ; Print it djnz bs3lp ; Loop until done ld e,renbuf+9 ; Point at ext. jr mvlpjp ; & loop eratoe: ld b,a ; Space count to B as counter ploop: ld a,(de) ; Get char. and 80h ; Get attribit or spc ; Mask in a space ld (de),a ; Put that in char. place and 7fh ; Strip hi bit inc de ; Bump pointer call cout ; Print it djnz ploop ; Loop until all are printed prndot: ld a,'.' ; Print the "." call cout jr mvlpjp ; Loop, DE pointing to 9th char. ; Process a legal input character, sending its pure ASCII equivalent ; to the CRT and a properly attributed equivalent to the work buffer ; while advancing the pointer and cursor by one position (right) gotspc: push af call stndend bit 7,c call nz,stndout pop af call cout ; Print ASCII char. or c ; Mask in attribit ld (de),a ; Put character in buffer name inc de ; Bump pointer bit 7,c call nz,stndend ld a,e ; Test location cp renbuf+9 ; At ext.? jr z,prndot ; Print "." and loop if Z cp renbuf+12 ; Beyond end of name buffer? jr nz,mvlpjp ; All done if not beyond the end dec de ; Otherwise adjust pointer ld a,bs ; Load a backspace call cout ; Print contents of A mvlpjp: jp mvloop ; Get the next char. ; WordStar(tm)-like response for DEL and control-G input rubout: ld a,renbuf+9 ; No can do if 1st ext. position cp e ; Test jp z,fbbel ; Bitch 'n barf if detected ld a,renbuf+1 ; Must be 2nd or later char. cp e ; Test jp nc,fbbel ; Go on if OK, else ding & loop rubgob: dec de ; Decrement pointer to "left" ; Fall through to GOBBLE, the control-G entry point gobble: ld a,e ; Save RENBUF position in A push hl ; Save WILDEN position on stack ld hl,renbuf ; Copy of RENBUF ld de,fcbbuf ; To FCBBUF ld bc,12 ; 12 chars. ldir ; Do it ld c,a ; RENBUF position to C ex de,hl ; Swap RENBUF+12 with FCBBUF+12 dec hl ; Adjust both to buffer+11 dec de ld a,renbuf+8 ; Highest filename position in A cp c ; Compare actual position jr c,rbstrt ; If NC, we're in ext. ld e,a ; So reset the pointers dec hl dec hl dec hl rbstrt: ld b,80h ; Hi bit isolation mask in B ld a,(de) ; Get RENBUF char. and b ; Isolate attribit or spc ; Mask in a space ld (de),a ; Put it in ld a,c ; Get our actual position cp renbuf+8 ; Filename end? jr z,rubret ; Then we're done cp renbuf+11 ; Filetype end? jr z,rubret ; Then we're done rbloop: dec de ; Otherwise decrement RENBUF ptr ld a,e ; Into A cp renbuf+1 ; Test for start jr nz,not1st ; Proceed if not ld a,(hl) ; Otherwise get candidate char. and 7fh ; Mask to ASCII cp spc ; Is it a space? jr nz,not1st ; Proceed if not ld a,bel ; Otherwise bitch 'n barf 'cuz call cout ; 1st char. can't be space jr rubret not1st: ld a,(de) ; Get current char. and b ; Isolate attribit res 7,(hl) ; Strip new char.'s attribit or (hl) ; Mask in new char. ld (de),a ; Put it into RENBUF position dec hl ; Decrement FCBBUF pointer ld a,c ; Test for end of move cp e jr nz,rbloop ; Loop until done rubret: pop hl ; Get back WILDEN pointer ld e,renbuf+1 ; Point to altered RENBUF_+_1 call movovr ; To left margin of CRT call prnfn ; Print the new name ld e,c ; Restore actual RENBUF pointer ld a,renbuf+12 ; Compute backspace count sub e ld b,a ; To B as counter cp 4 ; Cursor in filename area (NC)? ld a,bs ; Load the backspace call nc,cout ; Print an extra if needed rbbslp: call cout ; Then loop through the rest djnz rbbslp jr mvlpjp ; & THEN to the big loop around ; Go to the next file listed in the sorted WILDEN buffer, ; wrapping around to the buffer start if required. next: ld de,16 ; Offset to next filename add hl,de ; Add it in ld de,(count) ; Get count dec de ; Less 1 ld (count),de ; Put it back ld a,e ; Test for zero or d jr z,nxwrap ; Wrap around if zero ld a,(hl) ; Otherwise test for visibility inc a ; Invisible if Z jp nz,loop ; Not Z, do the big loop jr next ; Otherwise try next entry ; Wrap around to start of WILDEN buffer nxwrap: ld bc,(tcount) ; Reset count ld (count),bc ld hl,($memry) ; & buffer pointer ld de,16 ; Offset between entries in DE nxloop: ld a,(hl) ; Get visibility tag inc a ; Test jr nz,belnb2 ; All done if NZ add hl,de ; Otherwise bump entry pointer dec bc ; Decrement count jr nxloop ; & do our local loop ; Go to the previous file listed in the sorted WILDEN buffer ; wrapping around to the buffer's end if required. prvios: ld de,16 ; Offset to previous entry sbc hl,de ; Subtract it (carry is clear) ex de,hl ; Result to DE ld hl,(count) ; Count to HL inc hl ; Bump by one ld (count),hl ; Save it away ld bc,(tcount) ; Get original total count inc bc ; +1 for comparison xor a ; Clear carry sbc hl,bc ; Compare via subtraction ex de,hl ; Pointer back to HL jr z,prwrap ; Go to wrap around if equal ld a,(hl) ; Otherwise get visibility tag cpl ; This test for 0FFh also or a ; ensures cleared carry flag jp nz,loop ; Not Z, do the big loop around jr prvios ; Otherwise go to previous entry ; Wrap around to end of the WILDEN buffer prwrap: inc de ; Bump DE to 0001h ld (count),de ; Stow that as new count ld hl,($memry) ; Point buffer ld e,16 ; Entry offset in DE (D = 0) dec bc ; Adjust total file count dec bc bfloop: dec bc ; Compute last entry add hl,de ld a,c or b jr nz,bfloop ld bc,(count) ; Restore stowed count bflp2: ld a,(hl) ; Get visibility tag cpl ; This test for 0FFh also or a ; ensures cleared carry flag jr nz,belnb2 ; Not Z, do the big loop around inc bc ; Otherwise bump count sbc hl,de ; Point to next entry "down" jr bflp2 ; & do our local loop belnb2: ld (count),bc ; Store correct count belnbk: ld a,bel ; Console bell call cout ; Ding... jp loop ; & THEN loop... toggle: ld a,(flagb) rla jr c,oktogg ld a,renbuf+2 ; We only care about PUBlic (#2) cp e jr nz,oktogg ; Anything else is OK ld a,(de) ; We only care about a SET rla ld a,d ; D = 0 jr c,oktog2 call pubchk jr nc,fbbel ; Abort TOGGLE on PUBlic peril ld a,80h ; Otherwise set the PUBlic flag oktog2: ld (pubflg),a ; oktogg: ld a,(de) ; Get char. rla ; Roll attribit into carry ccf ; Flip it rra ; Roll it back ld (de),a ; Back into RENBUF and 80h ; Extract new attribit ld c,a ; Into C ld a,e ; Get position cp renbuf+11 ; Very last one? jr nz,gofrwd ; No, go forward call stndend ; Otherwise assure normal video bit 7,c ; Test attribute jr z,noatta ; Branch ahead if none call stndout ; Standout video if required jr nz,noatta ; Branch ahead if STNDOUT OK ld a,(de) ; Otherwise get char. and 7fh ; ASCII it call isalpha ; Is it a letter? jr nz,noattb ; Nope, can't show attribute add a,spc ; Otherwise to lower case jr noattb ; & THEN print it noatta: ld a,(de) and 7fh noattb: call cout bit 7,c call nz,stndend ld a,bs call cout jp mvlpjp2 farfor: ld a,e cp renbuf+11 jr z,fbbel ld e,renbuf+1 call movovr call prnfn ld a,bs call cout ld e,renbuf+11 jr inlpjp ; Move the pointer and cursor to the next (right) character forwrd: ld a,e ; Get position pointer cp renbuf+11 ; Off the edge? jr nz,gofrwd ; Nope, proceed fbbel: ld a,bel ; Otherwise complain call cout inlpjp: jp inloop ; Then no action... gofrwd: call stndend bit 7,c jr z,nlcase call stndout ld a,(de) ; Get pointed char. jr nz,nlcas1 and 7fh ; Strip to ASCII call isalpha jr nz,nlcas2 add a,spc jr nlcas2 nlcase: ld a,(de) nlcas1: and 7fh ; Strip to ASCII nlcas2: call cout ; To CRT inc de ; Bump pointer bit 7,c call nz,stndend ld a,e cp renbuf+9 ; Test for filetype position jp z,prndot ; Print dot & loop if there mvlpjp2: jp mvloop ; Otherwise just loop farbak: ld a,renbuf+1 cp e jr z,fbbel ld e,a jp frbklp ; Move the pointer and cursor to the last (left) character bckwrd: ld a,e ; Get position pointer cp renbuf+1 ; Left margin? jr z,fbbel ; Then just loop with no action cp renbuf+9 ; Filetype position? goback: ld a,bs ; Backspace in A call z,cout ; Print an extra if required call cout ; But always print at least one dec de ; Decrement pointer regardless jr mvlpjp2 ; & THEN loop ; This is the actual renaming routine. It starts with code to ; find format errors in the FCB-style buffer that points the ; cursor at the first detected error, followed by a file ; existence test and erase-or-abort option query, finally ; performing the renaming via SYSLIB's handy F$RENAME call. doren: ld bc,0720h ; ["filename"_range - 1] in B, ; 20h in C ld de,renbuf ; Point at RENBUF's "drive byte" push de ; Save RENBUF start inc de ; Bump pointer ld a,(de) ; Handle first char. specially inc de ; Bump pointer to jump into loop and 7fh ; Strip to ASCII cp c ; Is it a space? jr nz,splp1 ; If not, jump into loop inc de ; Otherwise bump pointer again jp notok ; & branch to failure code sploop: ld a,(de) ; Get filename char. inc de ; Bump pointer and 7fh ; Strip hi bit cp c ; Blank? jr z,nsloop ; Then do further checking splp1: djnz sploop ; Otherwise keep scanning jr oktype ; No blanks, go check ext nsloop: ld a,(de) ; Get filename char. inc de ; Bump pointer and 7fh ; Strip hi bit cp c ; Blank? jp nz,notok ; If not, there's a problem djnz nsloop ; Otherwise keep scanning oktype: ld e,renbuf+9 ; Point to ext (H = 0) ld b,2 ; Need to check 3 chars. in ext oktylp: ld a,(de) ; Get ext character inc de ; Bump pointer and 7fh ; Strip hi bit cp c ; Blank? jr z,oktyp2 ; Then do further checking djnz oktylp ; Otherwise keep scanning jr okren ; Kosher if we land here oktyp2: ld a,(de) ; Get ext character inc de ; Bump pointer and 7fh ; Strip hi bit cp c ; Is it blank? jp nz,notok ; If not, there's a problem djnz oktyp2 okren: ld a,(flagb) rla jr c,pubbok ld a,(pubflg) or a jr z,pubbok call pubchk jr c,pubbok ld e,renbuf+4 jr notok pubbok: pop de ; Get back RENBUF (FCB) call initfcb call f$exist ; File with same name exists? jr z,nfound ; Doesn't exist if Z, proceed push de ; Save regs. push hl inc de ; Bump to filenames inc hl ld b,11 ; Test filenametyp call compb ; Do compare via SYSLIB code jr z,samnam ; No action if same name as old call @fncmp ; Just an attribute change? jr nz,doask ; No, so ask about erasure pop hl ; Yes, get back regs. pop de jr atrent doask: call movovr ld de,askera ; Point to user prompt call dosprt ; Let DOS print it or 0ffh ; Assure NZ flag samnam: pop hl ; Restore regs. pop de jr z,loopjp ; No action if same name call cin ; Get user input call caps ; Capitalize if required cp 'Y' ; Positive response? jr nz,loopjp ; Give up if not call cout ; Print the "Y" xor a ; Kill R/O for erasure call sfa ; Call it in call f$delete ; SYSLIB's file delete call call bfrera ; Delete any duplicate entries nfound: push de ; Save RENBUF again ld de,fcbbuf ; Scatch FCB as dest. ld b,12 ; 12-byte move, (HL) to (DE) call moveb ; Do it xor a ; Kill R/O for renaming call sfa ; Call it in pop de ; Restore RENBUF into DE ex de,hl ; HL & DE set for SYSLIB rename call f$rename ; Do it ex de,hl ; Re-swap regs. atrent: push de ; Get RENBUF pointer into IX pop ix xor a ; Start out non-$SYS and R/W bit 7,(ix+9) ; Are we $SYS? jr z,notroa ; If not, branch ahead inc a ; A = 00000001B if here notroa: bit 7,(ix+10) ; Are we R/O? jr z,notsyf ; If not, branch ahead add a,80h ; A = 10000000B or 10000001B notsyf: call sfa ; Call in one possibility ex de,hl ; Swap pointers ld b,12 ; 12-byte move (HL) to (DE) call moveb ; Do it ex de,hl ; Re-swap loopjp: jp loop ; & THEN loop notok: pop af ; Throw away RENBUF start call movovr ; To left margin of CRT ld b,e ; Save our RENBUF pointer ld e,renbuf+1 ; Print the weird filename call prnfn ld e,b ; Get back pointer dec de ; Adjust pointer to errant space dec de ld a,renbuf+12 ; End of RENBUF in A sub e ; Compute how far from end ld b,a ; Stow in B as BS counter cp 4 ; 4 or more BSs (NC)? ld a,bs ; Load BS call nc,cout ; Print one for period if needed bsloop: call cout ; Then loop through the rest djnz bsloop dec a ; Cheap "BEL" ("BS-1") call cout ; Wake up the user jp mvloop ; Rejoin mainline ; Displays du/dir (subroutine) dispdu: call retud ; Get current DU in BC reg. call dutdir ; Find corresponding NDR entry push af ld a,mwidth-8 call z,spaces push bc push hl ld de,direct ; Print "Current Directory is " call dosprt ; Via DOS pop hl pop bc ld a,b ; Drive in A add a,'A' ; ASCII it call cout ; Print it ld a,c ; User in A call pafdc ; Print in decimal pop af jr z,nondr ; Branch ahead if none ld a,'\' ; Print a backslash call cout ld b,8 ; Counter in B dloop: ld a,(hl) ; Print directory name call cout inc hl djnz dloop nondr: ld de,crlflf call dosprt call movovr call stndout ld de,attmsg ; Two new lines & attr. banner call dosprt ; Print & return to caller jp stndend ; Tag $SYS and $W/P (R/O) files (subroutine) pack: ld bc,(count) pkloop: ld (hl),0 push hl ; Entry pointer to IX pop ix bit 7,(ix+10) ; Do we have a $SYS file? jr nz,subcnt ; Yes, adjust count bit 7,(ix+9) ; Is it R/O then? jr z,nosubc ; No, so no special treatment subcnt: dec (hl) ; Tag as invisible ld de,(acount) ; Get "actual" file count dec de ; -1 ld a,e ; Test for zero or d ret z ; Returned failed, none visible ld (acount),de ; Otherwise store revised count nosubc: ld de,16 ; Offset to next entry add hl,de ; Add it in dec bc ; Decrement counter ld a,c ; Test for zero or b jr nz,pkloop ; Loop until done ld hl,($memry) ; Retrieve buffer start ld bc,(count) ; Get full file count pklp2: ld a,(hl) ; Get tag byte inc a ; Visible? jr z,oneles ; Not if (HL)=0FFh ld (count),bc ; Yes, stow current count ret ; Return NZ for success oneles: dec bc ; Decrement counter add hl,de ; Bump pointer to next entry jr pklp2 ; Loop to test next tag ; Filename printing routine, uses alternate video if available, ; otherwise uses lower case if applicable, otherwise isn't all ; that helpful but whatcha gonna do when both the terminal AND ; the filename itself don't want to show attributes? prnfn: call stndend ; Assure normal video ld a,'[' ; Prefix char. call cout ; Print it push bc ; Save incoming regs. push de ld b,8 ; Filename counter in B pfloop: call vpcout ; Print the char at DE & bump DE djnz pfloop ; 8 times ld a,'.' ; Printadot call cout ld b,3 ; Filetype counter in B peloop: call vpcout ; Print the char at DE & bump DE djnz peloop ; 3 times pop de ; Get back incoming regs. pop bc ld a,']' ; Suffix char. call cout ; Print it ld a,bs ; Align cursor cout: jp bout ; Print the backspace & return vpcout: ld a,(de) ; Our char. in A inc de ; Bump pointer ld c,a ; Copy in C rla ; Roll into carry ld a,c ; Overwrite A with C jr nc,notatt ; If no carry, no attribute call stndout ; Try standout video ld a,c ; Overwrite A with C jr nz,notatt ; NZ means STNDOUT works, branch and 7fh ; Otherwise strip char. to ASCII call isalpha ; Test if it's a letter jr nz,prnlow ; If not, we can't highlight it add a,spc ; Otherwise lowercase it jr prnlow ; & THEN finish up notatt: and 7fh ; Mask to ASCII prnlow: call cout ; Print char. on CRT ld a,c ; Getacopy rla ; Roll attribit into carry ret nc ; Return if not set jpstend: jp stndend ; Otherwise normalize CRT first ; Align start of filename (subroutine) movovr: ld a,cr ; To left edge of CRT call cout ld a,mwidth ; Alternate entry point to print "A" spaces spaces: push bc ; Save incoming BC ld b,a ; Count to B ld a,spc ; Space to A movelp: call cout ; To CRT djnz movelp ; Loop until done pop bc ; Restore BC ret ; & return to caller ; ; Dual "quiet" query routine: if local flag at FLAGB is zero, ; consult and obey ZCPR3 quiet flag, otherwise run "quietly". ; lgqui: ld a,(flagb) ; Check local flag first bit 0,a jp z,getquiet ; Test Z3's flag if local is 0 ret ; Otherwise return NZ ; Test to see whether there is a duplicate filename in the ; WILDEN buffer after an erase operation, tag it as invisible ; if so. bfrera: push hl ; Save incoming HL +2 ld hl,(tcount) ; Get total file count push hl ; Save it on stack +4 ld hl,($memry) ; Buffer start to HL inc hl ; Point buffer filename bfrelp: push de ; Copy of RENBUF on stack +6 inc de ; RENBUF+1 in DE push hl ; Save buffer filename pointer +8 ld b,11 ; Compare 11 chars. call @fncmp ; Do it pop hl ; Otherwise recover pointer +6 pop de ; & RENBUF +4 jr z,found ; Branch ahead if matched samone: ld bc,16 ; Offset to next entry in BC add hl,bc ; Add it in pop bc ; Get back local counter +2 dec bc ; Decrement by one ld a,c ; Test for zero or b jr z,done ; All done if Z push bc ; Otherwise re-save local count +4 jr bfrelp ; & do local loop found: pop bc ; Local counter in BC +2 push hl ; Buffer pointer to stack +4 ld hl,(count) ; Current count in HL xor a ; Clear carry, A = 0 sbc hl,bc ; Compare via subtraction pop hl ; Get back buffer pointer +2 jr nz,nosame ; It's a dupe if NZ push bc ; Otherwise resave local counter +4 jr samone ; & rejoin BFRERA loop nosame: dec hl ; Pointer to entry "drive byte" cpl ; A = FFh ld (hl),a ; Mark as invisible done: pop hl ; Get back incoming HL +0 ret ; Return to caller ; Support routines for Plu*Perfect-style PUBlic files ; (Very loosely adapted from PUBLIC.COM, v1.1) ; The major improvement here is that the search operation ; is called off as early as possible, i.e., at the very ; instant that a second file with the candidate name turns ; up. PUBLIC.COM continues to search even though this sole ; criterion for illegality has already been met. VREN is ; therefore faster in any case where there is more than ; one match, although it isn't any better at deducing a safe ; condition than PUBLIC.COM. To be fair, it should be ; pointed out that PUBLIC.COM lists all the copies to the ; CRT, something it could not do accurately using VREN's ; variation of the algorithm. ; pubchk: push hl ; Very speeded up compared to push de ; PUBLIC.COM v1.1, which always ld e,renbuf ; searches the entire directory ld a,'?' ; Specify all user codes ld (de),a call f$exist ; This is SEARCH_FOR_1ST & INC A scf ; Set carry jr z,pubdon ; No problem if no such file dec a ; Adjust index back to BDOSese ld (indx),a ; Store it ld c,getdpb ; To get pointer to DPB call bdos ; Call DOS (SYSLIB preserves DE) inc hl ; Bump to extent mask inc hl inc hl inc hl ld a,(hl) ; Get it cpl ; Flip (why do it every CHKNXT?) ld (extmsk),a ; & store it ld a,2 ; Init. counter to two ld (pubcnt),a ; (We can only have one copy) findal: call chknxt ; Check for a match ld de,renbuf ; Re-point to FCB jr nz,fndnxt ; Don't count a non-match ld hl,pubcnt ; Otherwise point to counter xor a ; Clear carry, A = 0 dec (hl) ; & decrement the counter jr z,pubdon ; [Carry unaffected by DEC (HL)] fndnxt: ld c,schnxt ; Search_for_next function # call bdos ; Call DOS (SYSLIB preserves DE) ld (indx),a ; Stow index inc a ; Test for FFh (No file) jr nz,findal ; & loop through everything scf pubdon: ld (de),a ; C flag has result, A = 0 pop de pop hl ret chknxt: call fndent ; Point to entry in TBUFF jr nc,docnxt ; Overflowed into TPA(!?) if C cretnz: or 0ffh ; Assure NZ ret ; & return to caller docnxt: ld a,(hl) ; Get user code byte cp 0e5h ; Erased? jr z,cretnz ; Keep going if not chkno: inc hl ; Point to first char. inc de ; & source FCB filenametyp ld b,11 ; Range in B chklp: ld a,(de) sub (hl) and 7fh inc hl inc de ret nz ; Return if no match djnz chklp ld a,(extmsk) ; Get flipped extent mask in A ld b,a ; Stow in B ld a,(hl) ; Current extent byte in A and b ; Mask it ld c,a ; Stow in C xor a ; Zero in A and b ; Mask it sub c ; Subtract and 1fh ; Mask off insignificant bits ret nz ; Return NZ if not the same inc hl ; Point to S2 (overflow) byte inc hl ld a,(hl) ; Get it and 7fh ; Mask off high bit ret ; & return fndent: ld a,(indx) ; Get BDOS indicator add a,a ; Make into the offset (x 20h) add a,a add a,a add a,a add a,a ld hl,tbuff ; Default disk buffer address add a,l ; Add start of buffer to A ld l,a ; Put back into L ret ; Return (carry set if into TPA) ; "No files to rename" error routine nofile: ld de,nfmsg jr jpdosp ; Help screen routine using the program's actual name ; (if the ZCPR3 implementation supports the external FCB) help: call lgqui ld de,instrc call nz,dosprt ld de,syntax ; Help message start call dosprt ; Let DOS print it call getefcb ; Find out our name jr nz,comnam ; Assume "VREN" if we don't know ld hl,help2 comnam: ld b,8 ; 8-char. limit in B as counter comnml: inc hl ; Bump pointer ld a,(hl) ; Get char. and 7fh ; Strip hi bit cp spc ; Blank? call nz,cout ; To CRT if it's not djnz comnml ; Count down, loop if not done ld de,help2 ; Point rest of help message if short jpdosp: dosprt: ld c,9 jp 0005h ; DOS print and go home else ;if not short jpdosp: jp dosprt ; DOS print and go home endif ;short ; ASCII strings printable via DOS function #9 syntax: db 'VREN, Version 1.1 (Type ' asctyp: db bel,')',cr,lf ; Poked at this label to Type db 'Syntax:',cr,lf,' $' help1: db 'VREN ' help2: db ' [dir:][afn.typ]',cr,lf db ' Allows enhanced line editing',cr,lf db ' of file names and attributes.',cr,lf,lf instrc: db 'DEL: del.left, ^G: del.right, ".": del.',cr,lf db 'to filetype, ^T: Toggle attribute, RET:',cr,lf db 'do rename, ESC: abort rename, ^C: exit.',cr,lf db ' ^E: prev.file',cr,lf db ' ^',cr,lf db ' ^S: prev.char.<-+-> ^D: next char.',cr,lf db ' v',cr,lf ovr: db ' ' ovrend: db '^X: next file',cr,lf db '$' mwidth equ ovrend-ovr crlflf: db cr,lf,lf,'$' direct: db ' Current Directory is $' nfmsg: db bel,'No files to rename$' askera: db bel,'[Exists, ERA?',bs,'$' attmsg: db ' 12345678|rsa',lf,'$' $memry: ds 2 ; This space in CSEG for safety dseg count: ds 2 ; Current file's count tcount: ds 2 ; Total count acount: ds 2 ; Actual total count (less $SYS) keys: ds 2 ; Pointer to TCAP arrow key defs ; These buffers needed for PUBlic file safety routines indx: ds 1 extmsk: ds 1 pubcnt: ds 1 pubflg: ds 1 ; Scratch FCB fcbbuf: ds 36 ; Utility FCB space end