; ; PROGRAM: PATH ; VERSION: 1.0 ; AUTHOR: RICHARD CONN ; DATE: 12 JAN 83 ; PREVIOUS VERSIONS: NONE ; VERS EQU 10 ; ; PATH allows the user to do two things -- display the current path ; and set a new path. Named directories may be used in the definition of ; the new path. ; ; PATH is invoked by the following forms: ; PATH <-- Display Path ; PATH path-expression <-- Set Path ; PATH // <-- Print Help ; ; ; CP/M Constants ; cpm equ 0 ;base bdose equ cpm+5 fcb equ cpm+5ch tbuff equ cpm+80h cr equ 0dh lf equ 0ah ; ; SYSLIB Routines ; ext cline,zgpins,zdname,print,codend,eval10 ext cout,pstr,padc,retud ; ; This program is Copyright (c) 1982, 1983 by Richard Conn ; All Rights Reserved ; ; ZCPR2 and its utilities, including this one, are released ; to the public domain. Anyone who wishes to USE them may do so with ; no strings attached. The author assumes no responsibility or ; liability for the use of ZCPR2 and its utilities. ; ; The author, Richard Conn, has sole rights to this program. ; ZCPR2 and its utilities may not be sold without the express, ; written permission of the author. ; ; ; Branch to Start of Program ; jmp start ; ;****************************************************************** ; ; SINSFORM -- ZCPR2 Utility Standard General Purpose Initialization Format ; ; This data block precisely defines the data format for ; initial features of a ZCPR2 system which are required for proper ; initialization of the ZCPR2-Specific Routines in SYSLIB. ; ; ; EXTERNAL PATH DATA ; EPAVAIL: DB 0FFH ; IS EXTERNAL PATH AVAILABLE? (0=NO, 0FFH=YES) EPADR: DW 40H ; ADDRESS OF EXTERNAL PATH IF AVAILABLE ; ; INTERNAL PATH DATA ; INTPATH: DB 0,0 ; DISK, USER FOR FIRST PATH ELEMENT ; DISK = 1 FOR A, '$' FOR CURRENT ; USER = NUMBER, '$' FOR CURRENT DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 DB 0,0 ; DISK, USER FOR 8TH PATH ELEMENT DB 0 ; END OF PATH ; ; MULTIPLE COMMAND LINE BUFFER DATA ; MCAVAIL: DB 0FFH ; IS MULTIPLE COMMAND LINE BUFFER AVAILABLE? MCADR: DW 0FF00H ; ADDRESS OF MULTIPLE COMMAND LINE BUFFER IF AVAILABLE ; ; DISK/USER LIMITS ; MDISK: DB 4 ; MAXIMUM NUMBER OF DISKS MUSER: DB 31 ; MAXIMUM USER NUMBER ; ; FLAGS TO PERMIT LOG IN FOR DIFFERENT USER AREA OR DISK ; DOK: DB 0FFH ; ALLOW DISK CHANGE? (0=NO, 0FFH=YES) UOK: DB 0FFH ; ALLOW USER CHANGE? (0=NO, 0FFH=YES) ; ; PRIVILEGED USER DATA ; PUSER: DB 10 ; BEGINNING OF PRIVILEGED USER AREAS PPASS: DB 'chdir',0 ; PASSWORD FOR MOVING INTO PRIV USER AREAS DS 41-($-PPASS) ; 40 CHARS MAX IN BUFFER + 1 for ending NULL ; ; CURRENT USER/DISK INDICATOR ; CINDIC: DB '$' ; USUAL VALUE (FOR PATH EXPRESSIONS) ; ; DMA ADDRESS FOR DISK TRANSFERS ; DMADR: DW 80H ; TBUFF AREA ; ; NAMED DIRECTORY INFORMATION ; NDRADR: DW 00000H ; ADDRESS OF MEMORY-RESIDENT NAMED DIRECTORY NDNAMES: DB 64 ; MAX NUMBER OF DIRECTORY NAMES DNFILE: DB 'NAMES ' ; NAME OF DISK NAME FILE DB 'DIR' ; TYPE OF DISK NAME FILE ; ; REQUIREMENTS FLAGS ; EPREQD: DB 0FFH ; EXTERNAL PATH? MCREQD: DB 000H ; MULTIPLE COMMAND LINE? MXREQD: DB 0FFH ; MAX USER/DISK? UDREQD: DB 000H ; ALLOW USER/DISK CHANGE? PUREQD: DB 000H ; PRIVILEGED USER? CDREQD: DB 0FFH ; CURRENT INDIC AND DMA? NDREQD: DB 0FFH ; NAMED DIRECTORIES? Z2CLASS: DB 0 ; CLASS 0 DB 'ZCPR2' DS 10 ; RESERVED ; ; END OF SINSFORM -- STANDARD DEFAULT PARAMETER DATA ; ;****************************************************************** ; ; ; Start of Program ; start: call zgpins ; init ZCPR2 buffers lxi h,tbuff ; pt to buffer call cline ; save it as string shld cmdline ; save ptr to command line call retud ; get current disk and user mov a,b sta cdisk ; set disk mov a,c sta cuser ; set user ; ; Print Banner ; call print db 'PATH Version ' db vers/10+'0','.',(vers mod 10)+'0',0 ; ; Check for Help ; lda fcb+1 ; get first char cpi '/' ; help? jnz start1 call print db cr,lf,' PATH allows the user to display his current path' db cr,lf,'and set a new path. It is invoked by one of the forms:' db cr,lf db cr,lf,' PATH <-- Display Path' db cr,lf,' PATH path-expression <-- Set Path' db cr,lf,' PATH // <-- Print Help' db cr,lf,0 ret ; ; Check for Error and Continue if not: ; Load NAMES.DIR and check for function ; start1: lda epavail ; external path available? ora a ; 0=no jnz start2 call print db cr,lf,'Error -- External Path Not Defined -- Aborting',0 ret start2: call codend ; pt to buffer call zdname ; load NAMES.DIR jnz start3 mvi c,0 ; if no NAMES.DIR or overflow, set no entries start3: shld ddir ; save ptr to disk buffer mov a,c ; set entry count sta dentry lxi h,tempath ; pt to temporary path shld pathptr ; set path ptr lhld cmdline ; check command line for text call sblank ; skip to non-blank shld cmdline ; set ptr to next element ora a ; EOL=display function jz pdisp ; ; **** Set New Path **** ; HL pts to next element ; pbuild: lhld cmdline ; pt to next element call sblank ; skip to non-blank mov a,m ; get first char of next element ora a ; EOL? jz pbdone ; done if so, store path and display shld token ; save ptr to first byte lda cindic ; get current disk indicator cmp m ; is it current? jz pbdu ; DU: form mov a,m ; get first char again sui 'A' ; convert to number jc pbdir ; DIR: form mov b,a ; save number lda mdisk ; compare to max disk number mov c,a mov a,b cmp c ; in range? jnc pbdir ; DIR: form if not inx h ; pt to next char -- may be DU or DIR lda cindic ; get current indicator mov b,a ; ... in B mov a,m ; get next part of element cmp b ; current? jz pbdu ; is a DU: form digtst: cpi ':' ; colon ends it jz pbdu ; is a DU: form cpi ' ' ; space ends it jz pbdu ora a ; EOL ends it jz pbdu cpi '0' ; must be a digit jc pbdir ; DIR: form if not in range cpi '9'+1 jnc pbdir inx h ; pt to next mov a,m ; get it jmp digtst ; ; It is a DU: form ; pbdu: lhld pathptr ; pt to path entry xchg ; ... in DE lhld token ; pt to token lda cindic ; get current indicator mov b,a mov a,m ; current? cmp b jz pbdu1 sui 'A'-1 ; convert to number from 1 to n pbdu1: stax d ; save disk element inx h ; pt to next inx d mov a,m ; current user? inx h ; pt to after user in case of match to cindic cmp b ; match cindic? jz pbdu2 dcx h ; pt to first digit push d ; save ptr to path call eval10 ; convert to number mov a,d ; range error? ora a jnz rangerr lda muser ; check for max user inr a mov b,a mov a,e cmp b jnc rangerr pop d ; get ptr to path pbdu2: stax d ; store user number inx d mov a,m ; ending with colon? cpi ':' jnz pbdu3 inx h ; skip over colon pbdu3: shld cmdline ; save ptr to next command line entry xchg shld pathptr ; save ptr to next path entry jmp pbuild ; continue processing ; ; Build DIR: form ; pbdir: lhld ndradr ; memory-based directory available? mov a,h ora l jz ddscan ; scan disk dir if not inx h ; pt to entry count mov c,m ; get entry count in C inx h ; pt to first entry call dirscan ; scan directory jnz gotud ; store disk/user ddscan: lhld ddir ; pt to disk dir lda dentry ; get entry count mov c,a ; ... in C call dirscan ; scan directory jnz gotud ; ; Entry not found ; rangerr: call print db cr,lf db cr,lf,'Invalid Path Expression Element -- Error Flagged at:' db cr,lf,' -->',0 lhld token ; print string starting at token call pstr call print db cr,lf,'This may be an invalid DU: form (disk or user out of ' db 'range)' db cr,lf,'or an undefined named directory.' db cr,lf db cr,lf,'Aborting to CP/M',0 jmp cpm ; ; Got User and Disk -- Store in Path ; gotud: lhld pathptr ; get ptr to path mov m,b ; store disk inx h mov m,c ; store user inx h ; pt to next shld pathptr lhld token ; skip over token gotud1: mov a,m ; skip to space or EOL inx h ; pt to next ora a ; EOL? jz gotud2 cpi ' ' ; space? jnz gotud1 gotud2: dcx h ; pt to EOL or space shld cmdline ; set ptr to next element jmp pbuild ; continue building ; ; Path Building is Done -- TEMPATH contains new path ; pbdone: lhld pathptr ; store ending zero in path mvi m,0 lhld epadr ; pt to external path xchg ; ... in DE lxi h,tempath ; copy tempath into external path pcopy: mov a,m ; get disk stax d ; put disk ora a ; end of path? jz pdisp ; done if so and display inx h ; pt to user inx d mov a,m ; get user stax d ; put user inx h ; pt to next disk inx d jmp pcopy ; ; **** Display Path Function **** ; pdisp: call print db cr,lf,'Current Path in Symbolic Form -- ',cr,lf,' ',0 lhld epadr ; pt to external path lda cindic ; get current indicator mov d,a ; ... in D pdisp1: mov a,m ; get disk ora a ; done? jz adisp cmp d ; current? jz pdisp2 adi '@' ; convert to letter pdisp2: call cout ; print disk letter inx h ; pt to user mov a,m ; get user number cmp d ; current? jnz pdisp3 call cout ; print cindic jmp pdisp4 pdisp3: call padc ; print user number pdisp4: mvi a,':' ; print colon call cout inx h ; pt to next element mov a,m ; done? ora a ; 0=yes jz adisp call print db ' --> ',0 jmp pdisp1 ; ; Print Absolute Path ; adisp: call print db cr,lf,'Current Path in Absolute Form --',cr,lf,' ',0 call curud ; get current user/disk lda cindic ; get current indicator mov d,a ; ... in D lhld epadr ; pt to path adisp1: mov a,m ; get disk ora a ; done? jz ndisp cmp d ; current? jnz adisp2 mov a,b ; get current disk inr a ; adjust to 1 to n adisp2: adi '@' ; convert to letter call cout ; print disk letter inx h ; pt to user mov a,m ; get user cmp d ; current? jnz adisp3 mov a,c ; get current user adisp3: call padc ; print user mvi a,':' call cout inx h ; pt to next mov a,m ; done? ora a jz ndisp call print db ' --> ',0 jmp adisp1 ; ; Print Named Path ; ndisp: call print db cr,lf,'Current Path in Named Directory Form --',cr,lf,' ',0 lhld epadr ; pt to external path ndisp1: lda cindic ; get current indicator mov d,a ; ... in D call curud ; get current user and disk in C and B mov a,m ; get disk ora a ; done? rz cmp d ; current? jz ndisp2 mov b,a ; disk in B dcr b ; adjust to 0 to n-1 ndisp2: inx h ; pt to user mov a,m ; get it cmp d ; current? jz ndisp3 mov c,a ; user in C ndisp3: inx h ; pt to next push h ; save ptr call udscan ; scan dirs for user/disk and print its name pop h ; get ptr mvi a,':' call cout mov a,m ; done? ora a rz call print db ' --> ',0 jmp ndisp1 ; ; Utilities ; ; ; Scan Memory-Based Directory for Name Pted to by TOKEN ; On entry, HL pts to first entry and C=number of entries ; On exit, return with NZ and BC=disk/user if found ; dirscan: mov a,c ; any entries? ora a rz ; error return dirsl: push h ; save ptr to entry push b ; save char count call tokscan ; check for token match pop b ; get char count pop h ; get entry ptr jz dirsfnd ; found? lxi d,10 ; skip to next entry dad d dcr c ; count down jnz dirsl ret ; return with Z if not found dirsfnd: mov b,m ; entry found, so get disk number inr b ; adjust to 1 to n inx h ; pt to user mov c,m ; get user mvi a,0ffh ; OK return ora a ret ; ; Scan entry pted to by HL to see if it contains the TOKEN ; tokscan: xchg ; save ptr in DE lhld token ; pt to token xchg ; HL pts to entry, DE pts to token inx h ; pt to entry in dir inx h mvi b,8 ; up to 8 bytes toks1: ldax d ; get token char cpi ':' ; end of token? jz toks2 cpi ' ' ; space? jz toks2 ora a ; EOL? jz toks2 cmp m ; match? rnz ; error abort if no match inx h ; pt to next inx d dcr b ; count down jnz toks1 ldax d ; full 8 chars, so token char must be a delim cpi ':' ; ok? rz cpi ' ' ; ok if space rz ora a ; ok if EOL ret toks2: mov a,m ; this must be a space for match cpi ' ' ret ; ; Skip to non-blank ; sblank: mov a,m ; get char inx h ; pt to next cpi ' ' ; space? jz sblank dcx h ; pt to non-blank ret ; ; Scan directories for user and disk in C and B ; Print name if found or Noname if not ; udscan: lhld ndradr ; check memory-based first mov a,h ora l jz udscan1 ; none inx h ; get entry count mov d,m ; ... in D inx h ; pt to first element call udndscn ; scan named dir jz udscan2 ; match udscan1: lhld ddir ; pt to disk-based dir lda dentry ; number of entries mov d,a ; entry count in D call udndscn ; scan named dir jnz udscan3 ; return no name udscan2: mvi b,8 ; 8 chars max udsprn: mov a,m ; get name char cpi ' ' ; done? rz call cout ; print char inx h ; pt to next dcr b ; count down jnz udsprn ret udscan3: call print db 'Noname',0 ret ; ; Scan dir pted to by HL for D elements ; BC=Disk/User ; Return with Z set and HL pting to name if found ; udndscn: mov a,m ; get disk inx h ; pt to user cmp b ; match so far? jnz udnd1 mov a,m ; get user cmp c ; match? jnz udnd1 inx h ; pt to name xra a ; return with zero for found ret udnd1: push d ; save count lxi d,9 ; pt to next element dad d pop d ; get count dcr d ; count down jnz udndscn mvi a,0ffh ; not found ora a ret ; ; Return Current Disk and User (in B and C) ; curud: lda cdisk ; get disk mov b,a ; ... in B lda cuser ; get user mov c,a ; ... in C ret ; ; Buffers ; cdisk: ds 1 ; current disk cuser: ds 1 ; current user cmdline: ds 2 ; ptr to next char in command line token: ds 2 ; ptr to current token pathptr: ds 2 ; ptr to next path entry ddir: ds 2 ; ptr to disk dir in memory dentry: ds 1 ; number of entries in disk dir tempath: ds 50 ; allow for 25 element path end