; Program: PWD ; Original Author: Richard Conn ; Version: 1.0 ; Date: 5 Mar 84 ; PWD displays the names of the named directories. ; If the option /P is given, then the passwords ; to the directories will also be displayed IF the Wheel Byte is ; Available and Set. If the Wheel Byte is not available, the ; passwords will be displayed without question. The display may ; be limited to named directories for specified drives and/or ; drives may be excluded from the display. The display may also ; be limited to those directory names that start with a specified ; set of 1 or more characters (auto-wildcarding). These are optional ; command line arguments. Security provisions prevent non-wheel ; users from seeing Passwords and, if so configured, passworded ; directory names. In addition, the display is restricted by the ; MAXDU from the environment and by the Extended Z3 ENV drive ; vector if it is present. version equ 20 ;10/25/89 Al Hawley ; See PWD.HST for details of this and previous changes. ; This program can be assembled and linked with ; ZMAC/ZML, Z80ASM/SLRNK, and M80/L80. ; Basic Equates .xlist ; don't include sysdef in PRN listing include sysdef ; standard ASCII, Z-system definitions .list z3env defl 00h ; Address of ZCPR3 Environment z3drvec equ 34h ; offset to extended env drive vector ; Program specific equates ndrrec equ 18 ; Length of each NDR record pwoffs equ 10 ; offset of password field in the record ; bit offsets in SEMA4 byte, and in OPTION byte ckduok equ 7 ; 1=use duok flag to control DU display hpw equ 2 ; offset for hidepw ; the next ones are only present in SEMA4 pwbit equ 1 ; offset for PW requested negbit equ 0 ; offset for drive select negate ; External References .request pwdcmd ;command tail parser ext fsinit,inictp,fsm1data,mskbuf ext s04arg .request fsmach ;finite state machine ext fsmach,stm_x .request bits ;bit manipulation ext msk16,arrmanda,artstbit .request z3lib ;Z-system functions ext getndr,getwhl,getefcb,getquiet ext getcrt,getduok,getmdisk,getmuser .request vlib ext z3vinit,vprint,cls .request syslib ext crlf,padc ; us internally defined routines based on DOS Fn 6 ; to replace BIOS functions in SYSLIB public cout,cin,cst ; used by PWDCMD public incvector,negvector ; Environment Definition - 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 nop ; ..and preserve location of signature db 'Z3ENV',3 ; Type-3 environment z3eadr: dw z3env ; Filled in by Z33 dw entry ; Intended load address ;=========================================================== ; configuration options ; WARNING: The configuration file, PWD.CFG, contains the ; locations of the parameters in this block. If you delete ; or change anything here, the CFG file may not work properly ; and will need to be rebuilt. See ZCNFG.LBR for details of ; generating configuration overlays. hidepw equ 1 shl hpw ; 1 = suppress display of passworded ; directories If not a wheel, 0 = do not ; suppress display of passworded directories, ; but don't display passwords (`P' option) ; unless wheel byte is set pgmid: dc 'PWD ' ; ID to locate configuration overlay option: db hidepw ; Option byte defmus: db 31 ; Maximum user displayed for Wheels defmdr: db 16 ; Maximum drive displayed for Wheel cdrvec: dw -1 ; Drives available, superseded by ext. env. negltr: db '~' ; default negation symbol rgeltr: db '-' ; range symbol, like A-P ;=========================================================== 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 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 bdos ; Return via BDOS print string function notz33msg: db 'Not Z33+$' ; Abort message if not Z33-compatible ;=========================================================== start:: ld hl,(z3eadr) ; Pt to ZCPR3 environment call z3vinit ; Initialize the ZCPR3 Env ld (stack),sp ; save callers stack ld sp,stack ; set local stack call setup ; defaults from config, Env call optchk ; get command tail options jr c,mainx ; HELP or Bad Option call banner ; Print Banner unless Quiet call pwd ; Display NDR entries mainx:: ld sp,(stack) ; Quiet return to CPR or CCP ret ;=========================================================== ; Print Named Directory Info pwd:: call scrhdr ; print Header for NDR display ; Print Names of Directory Elements ; This is the start of a loop, each iteration ; of which skips a disallowed NDR entry or ; Transfers [DU:]DIR to the screen display ndir2:: ld hl,(curndr) ld a,(hl) ; Get table entry or a ; End of table? ret z ; NORMAL PROGRAM EXIT ; Advance display to Next Set of Entries ; if the NDR drive number changes ld bc,(cntrs) cp b ; Same disk? jr z,ndir3 ; jump if same ld b,a ; Set new disk ld a,c ; Get current entry count ld c,0 ; Reset column count ld (cntrs),bc ;the current entry count in reg A is zero ;if a line has just been completed. and a ; See if newline already given call nz,newline ; Terminate an incomplete line ld a,(entperdrv) ; total entries displayed for this drive or a call nz,newline ; blank line between disk groups xor a ld (entperdrv),a ; reinitialize total entry counter ndir3:: call hpwtest ; test for PW and skip this entry jp c,ndirle ; if (PW .AND. (NOT WHL) .AND. HIDEPW) call dutest ; Validate NDR Drive & User jp c,ndirle ; Skip this record if invalid call namtst ; check against directory mask jp nz,ndirle ; Skip this record if no match call prtdu ; Print DU if (WHL .or. DUOK) ; else print a blank field call prname ; Print name of directory call prtpw ; Print PW if required ;=========================================================== ; Print Separator after name or password ndir5:: call vprint ; Print separator db ' ',0 ;=========================================================== ; Count entries displayed in current line ; and start a new line if required. entcnt:: ld hl,entperdrv ; count total entries for inc (hl) ; the current drive ld hl,cntrs inc (hl) ; count this entry bit pwbit,(ix) ; Check for password option ld a,(npents) ; assume no password display jr z,ndir6 ; jump if correct assumption ld a,(pwents) ; get passworded entries per line ndir6:: cp (hl) ; >= entries per line yet? jr nz,ndirle ; no, skip the newline routine call newline ; New line if so, and reset counter ;=========================================================== ; this is the end of the NDR record processing loop. ; Increment the NDR pointer to the next entry and ; return to the start of the loop with the new entry. ndirle:: ld hl,(curndr) ; -> current NDR entry ld bc,ndrrec ; length of an NDR entry add hl,bc ; Make hl point to next entry ld (curndr),hl ; save pointer to current NDR record jp ndir2 ; Go back and get next entry ;=========================================================== ; Emit a CRLF to the screen, starting a new line. ; If screen is full, emit a 'more' message and wait ; for operator input. The number of lines sent to the ; screen, (SLINES), is 'text lines' from the Z3 Env. newline:: call abtchk ; check for operator abort xor a ld (cntrs),a ; reset item/line counter call crlf ld a,(scount) ; decrement screen line counter dec a ld (scount),a ret nz ; return if room left on screen ; pause at end of text area paws:: ld a,(slines) ld (scount),a ; reinitialized screen line counter call vprint db '(more)',cr,0 ; prompt for keystroke ; wait for keyboard input paws1: call cin ; console input jr z,paws1 ; if no input, keep calling push af ; save the typed character call vprint db ' ',cr,0 ; erase the prompt ; if the key was any form of Q, X, C, or ESC, ; then user wants to abort. pop af ; user input char cp '['-'@' ; ESC key? jp z,mainx ; yes, abort and 00011111b ; convert to control char cp 'C'-'@' ; C, c, or control C? jp z,mainx ; yes, abort cp 'Q'-'@' ; Q, q, or control Q? jp z,mainx ; yes, abort cp 'X'-'@' ; X, x, or control X? jp z,mainx ; yes, abort ret ;=========================================================== ;Check for User keyboard input. If present, abort. ;exit: A = 0, Flags: Z returned if not an abort ; else jump to main program exit. abtchk: call cin ; get console char or a ; Char present? ret z ; no if Z, else jp mainx ; quit on user abort ;=========================================================== ;CST, CIN, and COUT are replacements for the ;SYSLIB routines of the same name. Whereas SYSLIB ;uses BIOS calls for these functions, the replacements ;here use DOS function 6 calls for console status, ;input, and output. ;-------------------------- ; CST - console status using DOS function6 with ;Z flag inverted to agree with SYSLIB CST. cst: call cst6 ; get FN 6 console stat jr z,cstx ; invert the Z flag ld a,1 cstx: dec a ; a->0ff if z, a->0 if nz ret ; and flags are readjusted to match ;console status using DOS function 6 ;exit: Z = no character waiting ; NZ = Character waiting cst6: push de push bc push hl ld e,0feh ; console status call ld c,6 ; bdos function number call bdos and a ; anything there? pop hl pop bc pop de ret ;-------------------------- ; CIN - console input using DOS function 6 ;exit: A contains the character, and NZ ; if A=0 then there was no character ; and Z cin: push de push bc push hl ld e,0ffh ; get console input ld c,6 call bdos and a ; will be nz if present pop hl pop bc pop de ret ;-------------------------- ; COUT - console output using DOS function 6 ;entry: A = char to be output, 0-FCH ;exit: char sent to console ; AF and 8080 registers preserved cout: push de push bc push hl push af ld e,a ld c,6 call bdos pop af pop hl pop bc pop de ret ;=========================================================== ; Test this NDR entry for the presence of a Password. ; If HIDEPW option is active and the wheel byte is reset (0), ; then return with CY set indicating that the entry is ; not to be displayed. ; based on original code by Jay Sage hpwtest:: ld hl,(curndr) ; -> current NDR entry ex de,hl ; Address of NDR in DE ld hl,pwoffs ; Offset to password add hl,de ; Hl points to password ex de,hl ; Hl as before, de=password ld a,(option) bit hpw,a ; hidepw option selected? ret z ; OK to display if not call getwhl ; Is this user a WHEEL? ret nz ; OK to display if so ld a,(de) ; Check for presence of password cp ' ' ret z ; OK to display if no PW scf ; NOT WHEEL & & HIDEPW ret ; so indicate (with CY set) that ; this entry is to be skipped ;=========================================================== ; Check DU from the NDR record at HL against ; Maximum d,u allowed and the drive vector. ; Max DU and Drive vector were set up during ; program initialization and option analysis. ;entry: HL -> current NDR record ; DE -> password field ;exit: HL is preserved ; FLAGS CY is set for invalid D or U dutest:: ld a,(hl) ; Get disk (Drive A=1, etc) dec a ; make drive designator 0...15 ex de,hl ; preserve ndr address in de ld hl,dvector ; -> low byte of local drive vector bit 3,a ; is the drive > 7 (i.e. H...P) ? jr z,lobite ; skip if not, and test in the low byte inc hl ; -> high byte of local drive vector lobite:: and 7 ; make 0..7 call artstbit ; test the indicated bit in dvector ex de,hl ; recover NDR record pointer in HL scf ; in case of invalid Drive ret z ; if not set, that drive is off limits ;if here, the drive is ok. Now check user inc hl ; Let's look at user from sysndr ld b,(hl) ; Put it in b dec hl ; Restore hl ld a,(maxuser) ; Get maxuser cp b ; Compare maxuser and sysndr user ret ; If Sysndr user .GT. maxuser, then ; return CY set, else CY is reset. ;=========================================================== ;Compare up to 8 characters of the dirname ;in the ndr entry with the characters given ;as a template on the command line. If all ;template characters are matched, then return ;with Z flag set, else NZ. namtst:: ;entry: hl -> ndir entry ;exit: hl preserved ; Z = dirname selected or no selection mask ; NZ = does not match selection mask ld de,mskbuf ld a,(de) or a ret z ;no mask specified ;a mask is present. see if there is a match ;between mask and up to 8 dir name characters push hl ;preserve ndir pointer inc hl inc hl ;->ndir name ld b,8 ;counter ntst01: ld a,(de) ;char from mask or a ;no more? jr z,ntstx ;end of mask, so must match cp (hl) ;same as mask? jr nz,ntstx ;done if not. return NZ inc de inc hl djnz ntst01 ;exit from the djnz loop means all ;8 characters match ntstx: pop hl ret ;=========================================================== ; Display the DU for the current entry if the ; wheel is set OR if the DUOK flag is true. ; Else print a blank field. ;entry: HL -> Drive byte ;exit: HL -> Name field prtdu:: ;undelete the next 2 to use DUOK for non-wheels only ;this COULD be set up as an option. (aeh) ; call getwhl ; jr nz,prtdu1 prtdu0: bit ckduok,(ix) ; check for DU permitted? jr z,prtdu1 ; skip if ignoring DUOK call getduok ; get DUOK flag from environment jr z,maskdu ; skip printing DU if DUOK is false prtdu1: ld a,(hl) ; get drive byte add '@' ; Convert to letter (A to P) call cout inc hl ; Pt to user ld a,(hl) ; Get user call padc ; Print user number call vprint ; Print separator db ': ',0 inc hl ; Pt to name ret maskdu: inc hl inc hl ; -> Name field call vprint db ' ' ; empty DU field xor a ret ;=========================================================== ; Print PW if required ;entry: HL -> password field ;exit: HL undefined ; BC,DE preserved prtpw:: bit pwbit,(ix) ; Check for password option ret z call vprint db ' - ',0 ; fall through to Print name of password ; jp prname ;=========================================================== ; Print 8-char name (directory or password) ;entry: HL -> name, in a blank filled field of 8 ;exit: HL -> Password field ; DE preserved prname:: ld b,8 ; Print name prn1:: ld a,(hl) ; Get char call cout inc hl ; Pt to next djnz prn1 ; Count down xor a ; reset CY ret ;=========================================================== ; Print Screen Header if not quiet ;exit: HL, DE are preserved scrhdr:: call getquiet ret nz ; Skip header on quiet flag bit pwbit,(ix) ; See if passwords included ld a,(pwents) ; Number of passworded entries per line jr nz,ndir1p ld a,(npents) ; Print Header for Non-Password Entries ld b,a ; entries per line push bc ndir1a:: call vprint ; Print banner (optional) db ' DU : DIR Name ',0 djnz ndir1a ; Count down call newline ; New line pop bc ;recover entries per line ndir1b:: call vprint db '---- -------- ',0 djnz ndir1b ; Count down jp newline ; ..and then ret to caller ;------------------------------------------------ ; Print Header for Password Entries ndir1p:: ld b,a ; entries per line push bc ndir1c:: call vprint db ' DU : DIR Name - Password ',0 djnz ndir1c ; Count down call newline pop bc ;recover entries per line ndir1d:: call vprint db '---- -------- -------- ',0 djnz ndir1d ; Count down jp newline ; ..and then ret to caller ;=========================================================== ; Print the banner if the quiet flag is off banner:: call getquiet ret nz ;do nothing if quiet ;print banner unconditionally hlpban:: call vprint db 'PWD, Version ' db [version/10]+'0','.',[version mod 10]+'0' db cr,lf,0 ret ;=========================================================== ; Check for command line options optchk:: call fsinit ; initialize list buffer, misc variables call inictp ; set input pointer, test for empty tail ret z ; no command tail, so do PWD display ld hl,fsm1data ; data structure in PWDCMD for FSMACH use. call fsmach ; parse the command tail ex af,af' ; save the flags for return ld bc,(incvector) ; the inclusion mask ld a,b or c ; any bits set? call nz,makedv ; update dvector if so ld bc,(negvector) ; exclusion vector ld a,b or c ; anything excluded? jr z,optxchk ; done if not ld hl,0ffffh ; invert negvector sbc hl,bc ; by subtracting from a word of 1's ld b,h ld c,l ; move result back into bc call makedv optxchk: ex af,af' ; recover flags from cmd tail parse ret makedv: ld hl,dvector ; ->low byte of main drive vector ld a,c ; low byte of inclusion mask call arrmanda ; AND the two inc hl ;do the same for the high bytes ld a,b jp arrmanda ;=========================================================== ; Transfer configuration defaults to working data area. ; Get invironment parameters and combine with defaults ; to establish current display limits. ; Command tail options may further modify display ; parameters. setup:: ld hl,dvector ; initialize variables ld bc,stkbot-dvector ld de,dvector+1 ld (hl),0 ldir call pwdname ; put the invocation name in the help screen ld ix,sema4 ; IX remains pointed to SEMA4 ld a,(option) ; for use throughout the program ld (ix),a ; transfer configuration to working flags ld hl,(negltr) ; get negation & range characters ld (s04arg+2),hl ; ..and install in the state table call getcrt ; -> crt data ld e,(hl) ; screen width, characters inc hl inc hl ; -> text lines per screen ld a,(hl) ld (slines),a ; save it locally ld (scount),a ; initialize screen counter ; calculate the number of passworded and non- ; passworded entries that will fit on one ; screen line. This makes the display adapt ; to different screen widths ld a,e ld b,28 ;size of a passworded entry call idiv ;integer division, A=A/B ld (pwents),a ld a,e ld b,18 ;size of non-passworded entry call idiv ld (npents),a ld hl,(defmus) ; max drive, user for wheel ld (maxuser),hl ld hl,(cdrvec) ld (dvector),hl ; configured drive vector call getwhl ; wheel privileges? jr nz,setup2 ; skip if yes ;set up display restrictions for non-wheel user call getmuser ld (maxuser),a call getmdisk ; Non-wheels get Max DU ld (maxdrive),a ; from the environment dec a ; change range to 0...15 call msk16 ; make 16 bit drive vector in BC call bcmask ; dvector <- dvector .and. BC ; If an extended environment is present then ; get the drive vector and apply as an additional ; mask on the drives allowed in the display. ld hl,(z3eadr) ld bc,8 add hl,bc bit 7,(hl) ; extended environment? jr z,setup2 ; skip if not ld bc,z3drvec-8 ; offset to ext. env. drive vector add hl,bc ld c,(hl) inc hl ld b,(hl) ; drive vector from env in BC call bcmask ; dvector <- dvector .and. BC setup2:: ; DVECTOR now contains one bit set for each drive ; allowed to be displayed. The bits set take into ; account wheel controlled access privileges. call getndr ; Get location of directory ld (curndr),hl ; current NDR record pointer ret nz ; Setup done call vprint db ' Named Directory Buffer Not Available',0 jp mainx ; ..to the CPR ;=========================================================== ; put the name by which PWD was invoked into the HELP ; screen if it has not already been done. Doing it ; just once this way prevents its being called 'GO' ; when re-executed that way. pwdname: ld de,hlp000 ; where the name goes ld a,(de) cp spc ; first invocation? ret nz ; if nz, this has already been done call getefcb ; location of invocation name inc hl ; skip the initial 00 ld bc,8 ; 8 characters including trailing spaces ldir ; move it into the help screen ret ;=========================================================== ; Integer division, A = A/B ;entry: A = numerator ; B = divisor ;exit: B preserved ; A = C = dividend ; the remainder is not returned idiv:: ld c,0 ; dividend register div:: sub b jr c,divx ; done on overflow inc c ; count subtractions jr div divx:: ld a,c ; answer in A ret ;=========================================================== ; perform logical AND of BC with (dvector) and ; store the result at (dvector) bcmask:: ld hl,dvector ld a,c call arrmanda ; (hl) <- (hl) .and. Accumulator inc hl ld a,b jp arrmanda ; dvector now limited to maxdrive ;return to caller from arrmanda ;=========================================================== dohelp:: call cls call hlpban ; print banner, ignore quiet flag ; jr prhelp ;=========================================================== ; Print Invalid Option and then Help Messages ;invopt:: ; call vprint ; db cr,lf,'Invalid Option',cr,lf,0 ; Fall thru to PRHELP which sets carry flag to ; indicate the error condition. ; Print Help Message ; This routine returns with CY set to indicate ; that it was called. prhelp:: call vprint DB CR,LF DB 'Displays DU and Directory Names with paging. Passwords' DB ' may be included',CR,LF DB 'if WHEEL is on. Display may be limited to specified' DB ' drives and/or to',CR,LF DB 'automatically wildcarded name specifications.',CR DB LF DB CR,LF DB DIM,'SYNTAX:',BRIGHT,' ' HLP000: DB ' PWD [...] ',DIM,'(delimiters are Space/Tab/Comma)' DB BRIGHT,CR,LF DB CR,LF DB ' Auto-wildcarded names to display' DB CR,LF DB ' : Display names for drives listed in' DB ' ONLY',CR,LF DB ' ~: Exclude names for drives listed in' DB ' ',CR,LF DB ' / Honor an option or display help and' DB ' quit.',CR,LF DB ' ',CR,LF DB DIM,'EXAMPLES:',CR,LF DB ' Displays',BRIGHT,CR,LF DB ' (none) All Directory Names',CR,LF DB ' CA All Dir names starting with' DB ' "CA"',CR,LF DB ' D:CA Dir names "CA??????" for' DB ' drive D: only',CR,LF DB ' B-F: Dir names for drives B,C,D,E,' DB ' and F',CR,LF DB ' BCML: Dir names for drives B,C,M,' DB ' and L',CR,LF DB ' ~M: Dir names for all EXCEPT' DB ' drive M:',CR,LF DB 0 call getwhl jr z,hlp002 ;only wheels get to see the /P call vprint HLP001: DB ' /P Directory Names & Passwords' DB ' (WHEEL only)' ; db CR,LF DB 0 hlp002: scf ;say help was printed ret ;=========================================================== dseg ;keep these in the same order! they're accessed as a word! maxuser:: ds 1 ; from Environment for non-wheel maxdrive:: ds 1 ; From config area for wheel dvector:: ds 2 ; valid drive vector, logical AND ; of CDRVEC + + ; incvector: ds 2 ; command line drive list negvector: ds 2 ; command line excluded drive list ;drive vectors are all the same format as ;that in the extended ENVironment. sema4:: ds 1 ; bit mapped flags byte entperdrv: ds 1 ; counter for entries/NDR-drive cntrs:: ds 1 ; counter for entries/screen line ds 1 ; current NDR drive curndr:: ds 2 ; address of current NDR record slines:: ds 1 ; text lines per screen from environment scount:: ds 1 ; screen line counter pwents:: ds 1 ; Number of passworded entries per screen line npents:: ds 1 ; Number of non-passworded entries/line stkbot: ds 60 ;local stack space stack:: ds 2 ;callers stack pointer end