;  PROGRAM:  RENAME
;  VERSION:  3.0
;  DATE:  18 MAY 84
;  AUTHOR:  RICHARD CONN
;  PREVIOUS VERSIONS:  2.0 (16 JAN 83)
;  PREVIOUS VERSIONS:  1.4 (6 JAN 83), 1.3 (7 DEC 82), 1.2 (10 NOV 82)
;  PREVIOUS VERSION:  RENAME.ASM Version 1.1 (26 OCT 81)
VERS    equ     30
z3env   SET     0f400h

;
;  RENAME Command --
;       RENAME is used to change the name of one or more files.  Unlike
; the ZCPR2-resident REN function, RENAME permits ambiguous file names
; and supports an Inspect mode that allows the user to confirm each
; rename before it is done.  Additionally, there is a Control Mode which
; allows the user to manually specify the name for each file as it is
; presented to him.
;
;       The RENAME command may be of the following forms:
;               RENAME dir:afn1=afn2,dir:afn3=afn4,... o
;               RENAME dir:afn,dir:afn1=afn2,... o
;       The first form shows elements of the form
;                       dir:afn1=afn2
; while the second form shows elements of the form
;                       dir:afn
; which is the same as
;                       dir:afn=afn
; and only makes sense if Control Mode is used.
;
;       The option characters (o) are none or more of the following:
;               C -- Control Mode; manually specify each new name
;               I -- Inspect and approve each rename
;               S -- Include SYStem files
;
;       Examples:
;               RENAME *.MAC=*.ASM      <-- Rename all ASM files to MAC
;               RENAME *.MAC C          <-- Rename all MAC files to names
;                                               input by the user
;               RENAME *.OBJ=*.COM SI   <-- Rename all COM files to OBJ
;                                               and include SYStem files
;                                               and Inspect and approve each
;                                               change
;

FALSE   EQU     0
TRUE    EQU     NOT FALSE

ESIZE   EQU     16      ; SIZE OF DIR ENTRY (FROM SYSLIB DIRF ROUTINE)

       EXT     DIRQ    ; DIRECTORY PROCESSOR

       EXT     Z3INIT  ; INIT BUFFERS
       EXT     ZFNAME  ; FILE NAME PROCESSOR
       EXT     Z3LOG   ; Z3 DU LOG

       EXT     F$DELETE        ; DELETE FILE
       EXT     F$RENAME        ; RENAME FILE
       EXT     BBLINE  ; INPUT LINE EDITOR
       EXT     INITFCB ; INIT FCB
       EXT     BDOS    ; BDOS ENTRY
       EXT     PUTUD   ; SAVE CURRENT USER/DISK
       EXT     GETUD   ; RESTORE CURRENT USER/DISK
       EXT     MOVEB   ; COPY ROUTINE
       EXT     PHLDC   ; PRINT HL AS DECIMAL CHARS
       EXT     PRINT   ; PRINT ROUTINE
       EXT     COUT    ; CONSOLE OUTPUT ROUTINE
       EXT     CIN     ; CONSOLE INPUT ROUTINE
       EXT     CAPS    ; CAPITALIZE ROUTINE
       EXT     CRLF    ; NEW LINE ROUTINE
       EXT     FILLB   ; FILL ROUTINE
       EXT     CODEND  ; CODE END COMPUTATION ROUTINE

;
;  CP/M EQUATES
;
CPM     EQU     0       ; WARM BOOT
FCB     EQU     5CH     ; FCB
BUFF    EQU     80H     ; INPUT LINE BUFFER
CR      EQU     13      ; <CR>
LF      EQU     10      ; <LF>

;
; Environment Definition
;
       if      z3env ne 0
;
; External ZCPR3 Environment Descriptor
;
       jmp     start
       db      'Z3ENV' ;This is a ZCPR3 Utility
       db      1       ;External Environment Descriptor
z3eadr:
       dw      z3env
start:
       lhld    z3eadr  ;pt to ZCPR3 environment
;
       else
;
; Internal ZCPR3 Environment Descriptor
;
       MACLIB  Z3BASE.LIB
       MACLIB  SYSENV.LIB
z3eadr:
       jmp     start
       SYSENV
start:
       lxi     h,z3eadr        ;pt to ZCPR3 environment
       endif

;
; Start of Program -- Initialize ZCPR3 Environment
;
       call    z3init  ;initialize the ZCPR3 Env and the VLIB Env
       LXI     H,0     ; GET STACK PTR
       DAD     SP
       SHLD    STACK   ; SAVE IT
       CALL    CODEND
       SHLD    CMDLNE  ; SETUP COMMAND LINE BUFFER
       LXI     D,100H  ; BUFFER SIZE
       DAD     D
       SHLD    NTFCB   ; SET TEMP FCB
       DAD     D
       SHLD    DIRBUF  ; PTR TO DIR BUFFER
       SPHL            ; NEW SP
       LHLD    NTFCB   ; SET 2ND FCB
       LXI     D,40
       DAD     D
       SHLD    OFCB

       CALL    PUTUD   ; SAVE CURRENT USER/DISK AWAY

       CALL    PRINT
       DB      'RENAME  Version '
       DB      VERS/10+'0','.',(VERS MOD 10)+'0',0
       LDA     FCB+1   ; GET FIRST CHAR OF FILE NAME
       CPI     ' '     ; NO FILE SPEC?
       JZ      HELP
       CPI     '/'     ; OPTION CAUGHT?
       JNZ     ECONT

;  PRINT HELP INFORMATION
HELP:
       CALL    PRINT
       DB      CR,LF,'Syntax:'
       DB      CR,LF,'    RENAME dir:afn1=afn2,afn3=afn4,... o...'
       DB      CR,LF,'Options:'
       DB      CR,LF,'  C -- Control Mode (Allow user to manually name each '
       DB      'file)'
       DB      CR,LF,'  I -- Inspect Mode (Give user approval option)'
       DB      CR,LF,'  S -- Include SYS files'
       DB      CR,LF
       DB      0

;  RETURN TO OS
RETURN:
       LHLD    STACK   ; GET OLD STACK
       SPHL            ; SET IT
       RET

;  COPY BUFFER INTO TEMP BUFFER
ECONT:
       LHLD    CMDLNE  ; PT TO COMMAND LINE SAVE BUFFER
       XCHG            ; ... IN DE
       LXI     H,BUFF+1        ; PT TO BUFFER
       MVI     B,80H   ; BUFFER SIZE
       CALL    MOVEB   ; COPY INTO COMMAND LINE BUFFER

;  EXTRACT FLAGS IF PRESENT
       XRA     A       ; SET NO INSPECT, NO R/O, AND NO SYSTEM FILES
       STA     INSPECT
       STA     CONTROL ; SET NO CONTROL MODE
       MVI     A,80H   ; SELECT NON-SYS FILES ONLY
       STA     SYSTEM
       LXI     H,0     ; SET FILE COUNT
       SHLD    FILECNT
       LHLD    CMDLNE  ; PT TO BUFFER
;  SKIP TO FILE NAME STRING
SBLANK:
       MOV     A,M     ; SKIP TO NON-BLANK
       CPI     ' '     ; <SP>?
       JNZ     SBL1
       INX     H       ; PT TO NEXT CHAR
       JMP     SBLANK
;  SKIP TO END OF FILE NAME STRING
SBL1:
       MOV     A,M     ; SKIP TO <SP> OR EOL
       ORA     A       ; DONE?
       JZ      OPT
       CPI     ' '     ; <SP>
       JZ      OPT
       INX     H       ; PT TO NEXT
       JMP     SBL1
;  CHECK FOR LEADING SLASH ON OPTION AND SKIP IT IF SO
OPT:
       CPI     '/'     ; OPTION CHAR?
       JNZ     OPTION
       INX     H       ; SKIP SLASH
;  PROCESS LIST OF OPTIONS
OPTION:
       MOV     A,M     ; GET BYTE
       ORA     A       ; DONE?
       JZ      DSPEC
       INX     H       ; PT TO NEXT CHAR
       CPI     ' '     ; SKIP OVER SPACES
       JZ      OPTION
       CPI     '/'     ; IF OPTION LETTER, OBVIOUS ERROR, SO HELP
       JZ      HELP
       CPI     'C'     ; CONTROL?
       JZ      OPTCTRL
       CPI     'I'     ; INSPECT?
       JZ      OPTINS
       CPI     'S'     ; SYSTEM FILES?
       JNZ     HELP
       MVI     A,0C0H  ; SET FOR SYS FILES
       STA     SYSTEM
       JMP     OPTION
OPTCTRL:
       MVI     A,0FFH  ; CONTROL MODE
       STA     CONTROL
       JMP     OPTION
OPTINS:
       MVI     A,0FFH  ; INSPECT
       STA     INSPECT
       JMP     OPTION

;  EXTRACT DISK, USER, AND FILE NAME INFORMATION
DSPEC:
       LHLD    CMDLNE  ; PT TO BEFORE FIRST BYTE
       DCX     H
DSPEC0:
       INX     H       ; PT TO BYTE
       MOV     A,M     ; GET BYTE
       ORA     A       ; DONE?
       JZ      HELP
       CPI     ' '     ; <SP>?
       JZ      DSPEC0
;
;  MAJOR REENTRY POINT WHEN FILE SPECS ARE SEPARATED BY COMMAS
;    HL PTS TO FIRST BYTE OF NEXT FILE SPEC
;
DSPEC1:
       CALL    GETUD   ; RESET USER IF NECESSARY
       PUSH    H
       LHLD    NTFCB
       XCHG            ; PT TO FCB IN DE
       POP     H
       MVI     A,0     ; DIR BEFORE DU
       CALL    ZFNAME  ; EXTRACT FILE NAME INTO FCB, AND GET DISK AND USER
       SHLD    NEXTCH  ; SAVE PTR TO DELIMITER WHICH ENDED SCAN
       PUSH    H
       LHLD    NTFCB
       XCHG            ; PT TO FCB IN DE
       POP     H
       CALL    Z3LOG   ; LOG INTO DU

;  FIRST NAME IS NOW EXTRACTED -- EXTRACT POSSIBLE SECOND NAME
NAME2:
       LHLD    OFCB    ; PT TO FCB FOR 2ND NAME
       XCHG
       LHLD    NTFCB   ; PT TO FIRST NAME
       MVI     B,16    ; COPY 16 BYTES
       CALL    MOVEB
       LHLD    NEXTCH  ; PT TO CHAR WHICH ENDED PARSE
       MOV     A,M     ; GET IT
       CPI     '='     ; ASSIGNMENT?
       JNZ     RENAME  ; GO AHEAD IF NOT
       INX     H       ; PT TO CHAR AFTER '='
       PUSH    H
       LHLD    OFCB    ; PT TO TEMP FCB
       XCHG            ; ... IN DE
       POP     H
       MVI     A,0     ; DIR BEFORE DU
       CALL    ZFNAME  ; EXTRACT FILE NAME INTO FCB, AND GET DISK AND USER
       SHLD    NEXTCH  ; SAVE PTR TO DELIMITER WHICH ENDED SCAN

;  LOAD DIRECTORY AND RENAME FILES
RENAME:
       LHLD    OFCB
       XCHG            ; PT TO FCB
       LHLD    DIRBUF  ; PT TO END OF CODE
       CALL    INITFCB ; INIT THE FCB
       LDA     SYSTEM  ; SET FLAGS
       CALL    DIRQ    ; LOAD DIR, SELECT FILES, PACK, AND ALPHABETIZE

;  REN DIR FILES; HL PTS TO FIRST FILE, BC=FILE COUNT
       CALL    RENFILES

;  CHECK FOR NEXT FILE SPEC
       LHLD    NEXTCH  ; GET PTR
       MOV     A,M     ; GET DELIM
       CPI     ','     ; ANOTHER FILE?
       JNZ     RENDONE
       INX     H       ; PT TO CHAR AFTER COMMA
       JMP     DSPEC1  ; CONTINUE PROCESSING

;  RENAME COMPLETE -- PRINT COUNT AND EXIT
RENDONE:
       CALL    PRCOUNT ; PRINT FILE COUNT
       JMP     RETURN

;  RENAME SELECTED FILES
RENFILES:
       MOV     A,B     ; CHECK FOR ANY FILES LOADED
       ORA     C
       RZ

;  PRINT FILE NAME
RENLP:
       PUSH    B       ; SAVE ENTRY COUNT
       CALL    PRINT
       DB      CR,LF,'Rename ',0
       PUSH    H       ; SAVE PTR TO FCB
       LHLD    NTFCB   ; COPY NEW TEMPLATE INTO RENFCB
       LXI     D,RENFCB
       MVI     B,16
       CALL    MOVEB
       POP     H       ; GET PTR
       PUSH    H       ; SAVE PTR
       INX     H       ; PT TO FN OF OLD NAME
       INX     D       ; PT TO FN OF RENFCB
       MVI     B,11    ; 11 BYTES TO FN AND FT
RENLP1:
       LDAX    D       ; GET CHAR OF NEW
       CPI     '?'     ; CHANGE '?' TO OLD CHAR
       JNZ     RENLP2
       MOV     A,M     ; GET OLD CHAR
       ANI     7FH     ; MASK OLD CHAR
       STAX    D       ; STORE IT AWAY AS NEW
RENLP2:
       INX     H       ; PT TO NEXT CHAR
       INX     D
       DCR     B       ; COUNT DOWN
       JNZ     RENLP1
       LXI     H,RENFCB        ; PT TO NEW NAME
       CALL    PRFN    ; PRINT FILE NAME
       CALL    PRINT
       DB      ' from ',0
       POP     H       ; GET PTR TO OLD FILE NAME
       PUSH    H       ; SAVE IT AGAIN
       CALL    PRFN    ; PRINT FILE NAME
       POP     H       ; GET PTR

;  CHECK FOR CONTROL MODE AND PERFORM CONTROL FUNCTION IF SET
       LDA     CONTROL ; GET FLAG
       ORA     A       ; NZ=YES
       JNZ     RENCTRL

;  CHECK FOR INSPECTION AND INSPECT IF SET
       LDA     INSPECT ; GET FLAG
       ORA     A       ; 0=NO
       JZ      DOIT

;  PROMPT USER FOR RENAME
       CALL    RENQ    ; REN QUESTION
       CPI     'Q'     ; QUIT?
       JZ      QUIT
       CPI     'Y'     ; YES?
       JZ      DOIT

;  DON'T RENAME FILE
NODO:
       CALL    PRINT
       DB      CR,LF,'NO Name Change',0
       JMP     RENTEST

;  PRINT FILE NAME PTED TO BY HL
PRFN:
       INX     H       ; PT TO FILE NAME
       MVI     B,8     ; PRINT NAME
       CALL    PRNT
       MVI     A,'.'   ; DECIMAL
       CALL    COUT
       MVI     B,3     ; PRINT TYPE
       CALL    PRNT
       RET

;  PROMPT USER FOR RENAME
RENQ:
       CALL    PRINT   ; PRINT PROMPT
       DB      ' -- Rename (Y/N/Q=Quit)? ',0
       CALL    CIN     ; GET RESPONSE
       CALL    CAPS    ; CAPITALIZE
       CALL    COUT    ; ECHO
       RET

;  CONTROL FUNCTION -- ALLOW USER TO RENAME AS HE DESIRES
RENCTRL:
       PUSH    H       ; SAVE PTR TO FILE
RCTRL:
       CALL    PRINT
       DB      CR,LF,' -- New Name (<CR>=No Change)? ',0
       MVI     A,0FFH  ; CAPITALIZE
       CALL    BBLINE  ; INPUT LINE FROM USER
       ORA     A       ; CHECK FOR JUST <CR>
       JNZ     RCTRL0
       POP     H       ; GET PTR TO FILE
       JMP     RENTEST ; PROCEED WITH NEXT ENTRY
RCTRL0:
       LXI     D,RENFCB        ; PLACE INTO NEW NAME FCB
       CALL    ZFNAME  ; JUST EXTRACT NAME
       MVI     B,11    ; CHECK FOR ANY WILD CHARS
RCTRL1:
       INX     D       ; PT TO NEXT CHAR
       LDAX    D       ; GET IT
       CPI     '?'     ; CAN'T BE WILD
       JZ      WERR
       CPI     '*'     ; CAN'T BE WILD
       JZ      WERR
       DCR     B       ; COUNT DOWN
       JNZ     RCTRL1
       JMP     RDOIT   ; DONE -- PERFORM RENAME
WERR:
       CALL    PRINT
       DB      CR,LF,'Wild Card (?,*) in Name -- Try Again',0
       JMP     RCTRL

;  QUIT RENAME PROGRAM
QUIT:
       CALL    PRCOUNT ; PRINT COUNT OF FILES RENAMED
       CALL    PRINT
       DB      '  QUIT',0
       JMP     RETURN

;  REN FILE, BUT GET PTR FIRST
RDOIT:
       POP     H       ; GET PTR

;  RENAME FILE; OLD NAME PTED TO BY HL, NEW NAME IN RENFCB
DOIT:
       PUSH    H
;  STEP 1 -- DETERMINE IF NEW NAME ALREADY EXISTS
       LXI     D,RENFCB        ; PT TO NEW NAME
       CALL    INITFCB
       MVI     C,17    ; SEARCH FOR FIRST
       CALL    BDOS
       INR     A       ; NOT FOUND?
       JZ      DOIT1
       CALL    PRINT
       DB      CR,LF,'  -- File Exists -- Delete It (Y/N)? ',0
       CALL    CIN     ; GET RESPONSE
       CALL    CAPS
       CALL    COUT
       POP     H       ; PREP FOR ABORT
       CPI     'Y'     ; YES -- CONTINUE?
       JNZ     RENTEST ; NOT YES, SO SKIP IT
;  DELETE OLD FILE, SO SET ATTRIBUTES AND DO IT
       PUSH    H       ; SAVE PTR AGAIN
       CALL    INITFCB ; CLEAR FCB
       MVI     C,30    ; SET FILE ATTRIBUTES TO R/W IF NOT ALREADY
       CALL    BDOS
       CALL    INITFCB
       CALL    F$DELETE        ; DELETE FILE
DOIT1:
       POP     H       ; HL PTS TO OLD NAME
;  CLEAR THE OLD NAME'S ATTRIBUTES IN CASE IT WAS R/O
       PUSH    H       ; SAVE PTR TO OLD NAME
       PUSH    H
       LHLD    OFCB    ; COPY OLD NAME
       XCHG
       POP     H
       MVI     B,16
       CALL    MOVEB
       PUSH    D       ; CLEAR ATTRIBUTES
       MVI     B,11    ; 11 BYTES
       INX     D       ; PT TO FIRST
DOIT2:
       LDAX    D       ; GET CHAR
       ANI     7FH     ; CLEAR ATT
       STAX    D       ; PUT CHAR
       INX     D       ; PT TO NEXT
       DCR     B       ; COUNT DOWN
       JNZ     DOIT2
       POP     D       ; NOW SET ATTRIBUTES OF OLD NAME
       CALL    INITFCB
       MVI     C,30    ; SET ATTRIBUTES
       CALL    BDOS
       CALL    INITFCB
;  DO THE RENAME
       LXI     H,RENFCB        ; PT TO NEW NAME
       XCHG
       CALL    INITFCB ; INIT NEW FCB
       XCHG            ; HL PTS TO NEW NAME, DE PTS TO OLD NAME
       CALL    F$RENAME        ; RENAME THE FILE
;  RESTORE THE ORIGINAL ATTRIBUTE BITS
       POP     H       ; GET PTR TO OLD NAME
       LXI     D,RENFCB+1      ; PT TO NEW NAME
       PUSH    H       ; SAVE PTR TO OLD NAME
       INX     H       ; PT TO FN OF OLD NAME
       XCHG            ; HL PTS TO NEW NAME, DE PTS TO OLD NAME
       MVI     B,11    ; 11 BYTES
DOIT3:
       LDAX    D       ; GET ATTRIBUTE BIT OF OLD NAME
       ANI     80H     ; LOOK ONLY AT ATTRIBUTE BIT
       ORA     M       ; MASK IN NEW NAME BYTE
       MOV     M,A     ; STORE IT AWAY
       INX     H       ; PT TO NEXT
       INX     D
       DCR     B       ; COUNT DOWN
       JNZ     DOIT3
;  SET THE ORIGINAL ATTRIBUTES INTO THE NEW FILE
       LXI     D,RENFCB        ; PT TO FCB
       CALL    INITFCB
       MVI     C,30    ; SET ATTRIBUTES
       CALL    BDOS
       LHLD    FILECNT ; INCREMENT FILE COUNT
       INX     H
       SHLD    FILECNT
       POP     H       ; GET PTR TO DIRECTORY ENTRY

;  PT TO NEXT ENTRY
RENTEST:
       LXI     D,ESIZE ; PT TO NEXT ENTRY
       DAD     D
       POP     B       ; GET COUNT
       DCX     B       ; COUNT DOWN
       MOV     A,B     ; CHECK FOR ZERO
       ORA     C
       JNZ     RENLP

;  RETURN TO CALLER
       RET

;
;  PRINT CHARS PTED TO BY HL FOR B BYTES
;
PRNT:
       MOV     A,M     ; GET CHAR
       CALL    COUT
       INX     H       ; PT TO NEXT
       DCR     B       ; COUNT DOWN
       JNZ     PRNT
       RET

;
;  PRINT COUNT OF NUMBER OF FILES RENAMED
;
PRCOUNT:
       CALL    CRLF    ; NEW LINE
       LHLD    FILECNT ; GET COUNT
       MOV     A,L     ; CHECK FOR NONE
       ORA     H
       JZ      PRNO
       CALL    PHLDC   ; PRINT DECIMAL COUNT
       JMP     PRMS
PRNO:
       CALL    PRINT
       DB      'No ',0
PRMS:
       LHLD    FILECNT ; 1 FILE PROTECTED?
       MOV     A,H     ; HIGH ZERO?
       ORA     A
       JNZ     PRMULT
       MOV     A,L     ; LOW ONE?
       CPI     1
       JZ      PRSING
PRMULT:
       CALL    PRINT
       DB      ' Files Renamed',0
       RET
PRSING:
       CALL    PRINT
       DB      ' File  Renamed',0
       RET

;
;  BUFFERS
;
INSPECT:
       DS      1       ; INSPECT FLAG (0=NO, 0FFH=YES)
CONTROL:
       DS      1       ; CONTROL FLAG (0=NO, 0FFH=YES)
SYSTEM:
       DS      1       ; SYSTEM FLAG (80H=NON-SYS, 0C0H=SYS/NON-SYS)
NEXTCH:
       DS      2       ; PTR TO NEXT CHAR IN MULTIFILE COMMAND LINE
FILECNT:
       DS      2       ; COUNT OF NUMBER OF FILES RENAMED
RENFCB:
       DS      40      ; FCB FOR RENAME
OFCB:
       DS      2       ; FCB FOR OLD FILE NAME AND OLD FILE TEMPLATE
NTFCB:
       DS      2       ; FCB FOR NEW FILE TEMPLATE
CMDLNE:
       DS      2       ; PTR TO COMMAND LINE BUFFER
DIRBUF:
       DS      2       ; PTR TO DIRECTORY BUFFER
STACK:
       DS      2       ; OLD STACK PTR

       END