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

;
;  PROTECT Command --
;       PROTECT is used to set the file protection and tag attribute bits
; for CP/M 2.x files in the ZCPR3 environment.  It is invoked via command
; lines of the following forms:
;               PROTECT dir:afn1,dir:afn2,... keys      <-- Set unconditionally
;               PROTECT dir:afn1,... keys I             <-- Inspect Mode
;               PROTECT dir:afn1,... C                  <-- Set each ufn
;
;       In the above examples, the reference 'keys' is a string of zero or
; more characters which may be any of the following:
;
;               A <-- Set AR Attribute
;               R <-- Set R/O Attribute (no R sets R/W)
;               S <-- Set SYS Attribute (no S sets Non-System)
;               n <-- Set Tag Attribute (1 <= n <= 8)
;
;       Examples:
;               PROTECT *.COM RS        <-- Sets all COM files to R/O SYStem
;               PROTECT *.COM RSI       <-- Same, with user approval
;               PROTECT *.COM C         <-- Allows user to specify for each
;               PROTECT MYPROG.COM 1R   <-- Sets Tag Bit 1 and R/O Attribute
;

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   ; LOG INTO Z3 DU

       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  ; DETERMINE FREE SPACE
       SHLD    CMDLNE  ; COMMAND LINE BUFFER
       LXI     D,100H  ; BUFFER SIZE
       DAD     D
       SHLD    DIRBUF  ; DIR BUFFER
       SPHL            ; SET SP
       CALL    PUTUD   ; SAVE CURRENT USER/DISK AWAY

       CALL    PRINT
       DB      'PROTECT  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,'    PROTECT dir:filename.typ,dir:fn.ft,... o...'
       DB      CR,LF,'Options:'
       DB      CR,LF,'  C -- Control Mode (Allow user to set each file)'
       DB      CR,LF,'  I -- Inspect Mode (Give user option to set att)'
       DB      CR,LF,'  n -- 1 <= n <= 8; Set Tag Attribute'
       DB      CR,LF,'  A -- Set AR (Archive) Attribute'
       DB      CR,LF,'  R -- Set R/O Attribute (no R sets R/W)'
       DB      CR,LF,'  S -- Set SYS Attribute (no S sets Non-System)'
       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 CMDLNE BUFFER
       XCHG
       LXI     H,BUFF+1        ; PT TO BUFFER
       MVI     B,80H   ; ARBITRARY
       CALL    MOVEB   ; COPY INTO COMMAND LINE BUFFER

;  EXTRACT FLAGS IF PRESENT
       XRA     A       ; SET NO INSPECT, NO R/O, NO ARCH, AND NO SYSTEM FILES
       STA     INSPECT
       STA     READONLY
       STA     SYSTEM
       STA     ARCHIVE
       STA     CONTROL ; SET NO CONTROL MODE
       MVI     B,8     ; CLEAR TAG BITS
       LXI     H,TAGS
       CALL    FILLB
       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     '1'     ; DIGIT?
       JC      HELP
       CPI     '8'+1   ; IN RANGE?
       JC      OPTNUM
       CPI     'C'     ; CONTROL?
       JZ      OPTCTRL
       CPI     'I'     ; INSPECT?
       JZ      OPTINS
       CPI     'A'     ; ARCHIVE
       JZ      OPTAR
       CPI     'R'     ; READ/ONLY?
       JZ      OPTRO
       CPI     'S'     ; SYSTEM FILES?
       JNZ     HELP
       MVI     A,80H   ; SET FOR SYS FILES
       STA     SYSTEM
       JMP     OPTION
OPTNUM:
       SUI     '1'     ; ADJUST '1' TO '8' TO 0-7
       PUSH    H       ; SAVE PTR
       MOV     E,A     ; VALUE IN DE
       MVI     D,0
       LXI     H,TAGS  ; PT TO TAG BUFFER
       DAD     D       ; PT TO ELEMENT
       MVI     M,80H   ; SELECT ELEMENT
       POP     H       ; GET PTR TO NEXT CHAR
       JMP     OPTION
OPTCTRL:
       MVI     A,0FFH  ; CONTROL MODE
       STA     CONTROL
       JMP     OPTION
OPTINS:
       MVI     A,0FFH  ; INSPECT
       STA     INSPECT
       JMP     OPTION
OPTAR:
       MVI     A,80H   ; SET ARCHIVE
       STA     ARCHIVE
       JMP     OPTION
OPTRO:
       MVI     A,80H   ; SET R/O
       STA     READONLY
       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
       LXI     D,FCB   ; PT TO FCB IN DE, PT TO FIRST CHAR OF FILE NAME IN HL
       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
       LXI     D,FCB   ; PT TO FCB
       CALL    Z3LOG   ; LOG INTO DU

;  LOAD DIRECTORY AND PROTECT FILES
PROT:
       LHLD    DIRBUF  ; PT TO END OF CODE
       MVI     A,0C0H  ; SELECT NON-SYS AND SYS FILES
       LXI     D,FCB   ; PT TO FCB
       CALL    DIRQ    ; LOAD DIR, SELECT FILES, PACK, AND ALPHABETIZE

;  PROT DIR FILES; HL PTS TO FIRST FILE, BC=FILE COUNT
       CALL    PROTFILES

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

;  PROT COMPLETE -- PRINT COUNT AND EXIT
PROTDONE:
       CALL    PRCOUNT ; PRINT FILE COUNT
       JMP     RETURN

;  PROT SELECTED FILES
PROTFILES:
       MOV     A,B     ; CHECK FOR ANY FILES LOADED
       ORA     C
       RZ

;  PRINT FILE NAME
PROTLP:
       PUSH    B       ; SAVE ENTRY COUNT
       CALL    CRLF    ; NEW LINE
       PUSH    H       ; SAVE PTR TO FCB
       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
       POP     H       ; GET PTR

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

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

;  PROMPT USER FOR PROTECT
       CALL    PROTQ   ; PROT QUESTION
       CPI     'Q'     ; QUIT?
       JZ      QUIT
       CPI     'Y'     ; YES?
       JZ      DOIT

;  DON'T PROTECT FILE
NODO:
       CALL    PRINT
       DB      '  ++ NO Attribute Change ++',0
       JMP     PROTTEST

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

;  CONTROL FUNCTION -- ALLOW USER TO SET BITS AS HE DESIRES
PROTCTRL:
       PUSH    H       ; SAVE PTR TO FILE
       XRA     A       ; A=0
       STA     READONLY        ; CLEAR R/O, SYS, ARCHIVE, AND TAGS
       STA     SYSTEM
       STA     ARCHIVE
       LXI     H,TAGS
       MVI     B,8
       CALL    FILLB
       CALL    PRINT
       DB      ' -- Attributes (? for Help)? ',0
       MVI     A,0FFH  ; CAPITALIZE
       CALL    BBLINE  ; INPUT LINE FROM USER
       CALL    CRLF    ; NEW LINE
       MVI     B,80H   ; MSB SET
PCTRL:
       MOV     A,M     ; GET ATTRIBUTE FLAG
       ORA     A       ; DONE?
       JZ      PDOIT   ; DO PROTECTION THEN
       INX     H       ; PT TO NEXT
       CPI     ' '     ; SKIP <SP>
       JZ      PCTRL
       CPI     'Q'     ; QUIT?
       JZ      QUIT
       CPI     'A'     ; ARCHIVE?
       JZ      PCTRLA
       CPI     'S'     ; SYSTEM?
       JZ      PCTRLS
       CPI     'R'     ; R/O?
       JZ      PCTRLR
       CPI     '1'     ; DIGIT?
       JC      PCTRLH  ; HELP IF NOT
       CPI     '8'+1   ; RANGE?
       JC      PCTRLN  ; DO NUMBER
PCTRLH:
       CALL    PRINT
       DB      CR,LF,'  Attributes may be specified as follows --'
       DB      CR,LF,'    A = Archive, R = R/O, S = SYS, 1-8 = Tags'
       DB      CR,LF,'  The command Q exits'
       DB      CR,LF,0
       POP     H       ; GET FCB PTR
       POP     B       ; GET ENTRY COUNT
       JMP     PROTLP  ; PROCESS AGAIN
PCTRLA:
       MOV     A,B     ; GET FLAG
       STA     ARCHIVE ; SET FLAG
       JMP     PCTRL
PCTRLS:
       MOV     A,B     ; GET FLAG
       STA     SYSTEM  ; SET FLAG
       JMP     PCTRL
PCTRLR:
       MOV     A,B     ; GET AND SET FLAG
       STA     READONLY
       JMP     PCTRL
PCTRLN:
       PUSH    H
       SUI     '1'     ; CONVERT TO OFFSET
       MOV     E,A     ; OFFSET IN DE
       MVI     D,0
       LXI     H,TAGS  ; SET TAG
       DAD     D
       MOV     M,B     ; SET BIT
       POP     H
       JMP     PCTRL   ; CONTINUE

;  QUIT PROTECT PROGRAM
QUIT:
       CALL    PRCOUNT ; PRINT COUNT OF FILES PROTECTED
       CALL    PRINT
       DB      CR,LF,'  QUIT',0
       JMP     RETURN

;  PROT FILE, BUT GET PTR FIRST
PDOIT:
       POP     H       ; GET PTR

;  PROT FILE
DOIT:
       PUSH    H
       LXI     D,PROTFCB       ; COPY TARGET FILE INTO PROTECT'S FCB
       MVI     B,16    ; 16 BYTES
       CALL    MOVEB   ; COPY
       LXI     H,TAGS  ; SET TAG BITS NOW
       INX     D       ; PT TO FIRST TAG BIT
       MVI     B,8     ; 8 TAG BITS
DOITL:
       LDAX    D       ; GET BYTE FROM PROT FCB
       ANI     7FH     ; MASK OUT OLD MSB
       ORA     M       ; OR IN TAG BIT
       STAX    D       ; PUT BYTE BACK
       INX     H       ; PT TO NEXT
       INX     D
       DCR     B       ; COUNT DOWN
       JNZ     DOITL
       LDA     READONLY        ; GET R/O BIT
       MOV     B,A     ; SAVE IN B
       LDAX    D       ; GET BYTE
       ANI     7FH     ; MASK OUT OLD MSB
       ORA     B       ; OR IN NEW MSB
       STAX    D       ; PUT IT BACK
       INX     D       ; PT TO SYS BIT
       LDA     SYSTEM  ; GET SYS BIT
       MOV     B,A     ; SAVE IT
       LDAX    D       ; GET BYTE
       ANI     7FH     ; MASK OUT OLD MSB
       ORA     B       ; MASK IN NEW MSB
       STAX    D       ; PUT IT BACK
       INX     D       ; PT TO ARCHIVE BIT
       LDA     ARCHIVE ; GET ARCHIVE BIT
       MOV     B,A     ; SAVE IT
       LDAX    D       ; GET BYTE
       ANI     7FH     ; MASK OUT OLD MSB
       ORA     B       ; MASK IN NEW MSB
       STAX    D       ; PUT IT BACK
       LXI     D,PROTFCB       ; PT TO FCB
       CALL    INITFCB ; INIT IT
       MVI     C,30    ; SET FILE ATTRIBUTES
       CALL    BDOS
       CALL    PRINT
       DB      ' Set to ',0
       LXI     H,PROTFCB+1
       MVI     B,8     ; 8 TAGS
       MVI     C,'1'   ; SET DIGIT
PATTL1:
       MOV     A,M     ; GET BYTE
       ANI     80H     ; PRINT ATT?
       JZ      PATTL2
       MOV     A,C     ; GET DIGIT
       CALL    COUT
PATTL2:
       INR     C       ; INCREMENT DIGIT
       INX     H       ; PT TO NEXT
       DCR     B       ; COUNT DOWN
       JNZ     PATTL1
       MOV     A,M     ; GET R/O BYTE
       ANI     80H     ; MASK IT
       JZ      PATTL3
       CALL    PRINT
       DB      ' R/O ',0
       JMP     PATTL4
PATTL3:
       CALL    PRINT
       DB      ' R/W ',0
PATTL4:
       INX     H       ; PT TO SYS BYTE
       MOV     A,M     ; GET SYS BYTE
       ANI     80H     ; MASK IT
       JZ      PATTL5
       CALL    PRINT
       DB      'SYS',0
       JMP     PATTL6
PATTL5:
       CALL    PRINT
       DB      'DIR',0
PATTL6:
       INX     H       ; PT TO ARCHIVE BYTE
       MOV     A,M     ; GET ARCH BYTE
       ANI     80H     ; MASK IT
       JZ      PATTL7
       CALL    PRINT
       DB      ' AR',0
PATTL7:
       LHLD    FILECNT ; INCREMENT FILE COUNT
       INX     H
       SHLD    FILECNT
       POP     H       ; GET PTR TO DIRECTORY ENTRY

;  PT TO NEXT ENTRY
PROTTEST:
       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     PROTLP

;  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 PROTECTED
;
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 Protected',0
       RET
PRSING:
       CALL    PRINT
       DB      ' File  Protected',0
       RET

;
;  BUFFERS
;
INSPECT:
       DS      1       ; INSPECT FLAG (0=NO, 0FFH=YES)
CONTROL:
       DS      1       ; CONTROL FLAG (0=NO, 0FFH=YES)
ARCHIVE:
       DS      1       ; ARCHIVE FLAG (0=NO, 80H=YES)
SYSTEM:
       DS      1       ; SYSTEM FLAG (0=NO, 80H=YES)
READONLY:
       DS      1       ; READ/ONLY FLAG (0=NO, 80H=YES)
TAGS:
       DS      8       ; 8 TAG BITS
NEXTCH:
       DS      2       ; PTR TO NEXT CHAR IN MULTIFILE COMMAND LINE
FILECNT:
       DS      2       ; COUNT OF NUMBER OF FILES PROTECTED
PROTFCB:
       DS      40      ; FCB FOR PROTECT
CMDLNE:
       DS      2       ; PTR TO COMMAND LINE SAVE AREA
DIRBUF:
       DS      2       ; DIRECTORY BUFFER
STACK:
       DS      2       ; OLD STACK PTR

       END