home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ZSYS
/
SIMTEL20
/
ZCPR3
/
SH.MAC
< prev
next >
Wrap
Text File
|
2000-06-30
|
16KB
|
807 lines
;
; Program: SH
; Author: Richard Conn
; Version: 1.0
; Date: 5 Mar 84
;
;
; This program illustrates the design of a simple shell under ZCPR3
; using Z3LIB. This program is transportable from one ZCPR3 system to another
; provided it is reassembled with the correct address for the ZCPR3
; Environment Descriptor (Z3ENV) or DDT is used to patch this address
; (which is the first two bytes after the opening JMP). If an external
; ZCPR3 Environment Descriptor is not available, one will have to be
; provided by setting the Z3ENV equate to 0 and providing SYSENV.LIB in
; the current directory at assembly time.
;
;
; Equates for Key Values
;
z3env SET 0f400h ;address of ZCPR3 environment
lecnt equ 20 ;number of pointers on String Ptr Stack
ctrlz equ 'Z'-'@' ;^Z for EOF
cmdch equ '!' ;in comment mode, invoke following text as command
cmtch equ ';' ;comment character
subch equ '%' ;substitution flag
fcb equ 5ch
tbuff equ 80h
cr equ 0dh
lf equ 0ah
;
; External Z3LIB and SYSLIB Routines
;
ext getshm,putshm
ext getud,putud,logud,initfcb,f$open,f$read,f$close
ext parser,codend,caps,fillb,hmovb,root,getfn1,pfn1
ext retud,print,pafdc,bbline,moveb,crlf,cout,sksp,dutdir
ext z3init,getsh2,shpush,shpop,qshell,getefcb,putcl,putcst,putzex
;
; 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 Environment
;
; Set Pointers
;
call codend ;find scratch area
shld intline ;set ptr to internal line buffer
lxi d,200H ;reserve 200H bytes
dad d
shld varlist ;set ptr to variable list
xra a
sta loadfl ;say variables not loaded
;
; Check for Shell Stack
;
call getsh2 ;get shell status
jnz start0 ;skip over shell init
call print
db 'No Shell Stack',0
ret
;
; See if this program was invoked as a shell
;
start0:
call qshell ;find out from ZCPR3 environment
jz shell ;do not push onto stack if invoked as a shell
start1:
;
; Clear Shell Message for Comment Flag
;
mvi b,0 ;message 0
xra a ;A=0 to clear
call putshm ;set message
;
; Set Name of Shell Variable File if One is Given
;
call getfn1 ;pt to buffer in env
lxi d,fcb+1 ;pt to name
xchg ;copy from name
mvi b,11 ;11 bytes
mov a,m ;check for name
cpi ' ' ;no name if space
jz defname
call moveb ;copy if name present
call setshdef ;set default file type
jmp setshn
;
; Set Name of SH.VAR File
;
defname:
call getfn1 ;get name
lxi d,shvfcb+1 ;pt to FCB
xchg
mvi b,11 ;11 chars
call moveb
;
; Set Name of Shell from External FCB if Possible or From Default if Not
;
setshn:
call root ;get root address
lxi h,shdisk ;pt to shell disk
mov a,b ;get disk
adi 'A' ;convert to letter
mov m,a ;set disk letter
inx h ;pt to user 10's
mov a,c ;get user number
mvi b,10 ;subtract 10's
mvi d,'0' ;set char
setshn1:
sub b ;subtract
jc setshn2
inr d ;increment digit
jmp setshn1
setshn2:
add b ;get 1's
mov m,d ;set 10's digit for user
inx h ;pt to 1's digit
adi '0' ;compute 1's digit
mov m,a ;set 1's digit
call getefcb ;get ptr to external fcb
jz start2 ;no external FCB, so use default name
inx h ;pt to program name
lxi d,shname ;pt to string
mvi b,8 ;8 chars
call moveb ;copy into buffer
;
; Push Name of Shell onto Stack
;
start2:
lxi h,shdisk ;pt to name of shell
call shpush ;push shell onto stack
jnz start3
;
; Shell Successfully Installed
;
call print
db 'Shell Installed',0
ret
;
; Shell Stack Push Error
;
start3:
cpi 2 ;shell stack full?
jnz start4
;
; Shell Stack is Full
;
call print
db 'Shell Stack Full',0
ret
;
; Shell Stack Entry Size is too small for command line
;
start4:
call print
db 'Shell Stack Entry Size',0
ret
;
; Restart on Empty Line
;
shellr:
call crlf ;new line
;
; Print Shell Prompt
;
shell:
call retud ;get current user and disk
mov a,b ;save disk
adi 'A'
call cout ;print disk letter
mov a,c ;get user
call pafdc ;print A as floating decimal
call dutdir ;convert into DIR reference if possible
jz shell1 ;no match
mvi a,':' ;print colon
call cout
mvi b,8 ;8 chars max
shell0:
mov a,m ;get char
inx h ;pt to next
cpi ' ' ;space?
cnz cout
jnz shell0
shell1:
mvi b,0 ;get shell message 0
call getshm
ani 1 ;test for prompt
jz shell2 ;print normal prompt
call print ;comment format
db '; ',0 ;comment
jmp shell3
shell2:
call print ;normal format
db '>> ',0 ;double prompt
;
; Accept User Input
;
shell3:
mvi a,1 ;tell ZEX that prompt is up
call putzex
xra a ;don't capitalize
call bbline
mvi a,0 ;say that normal processing is running now
call putcst
call putzex
call sksp ;skip over leading spaces
mvi b,0 ;get shell message 0
call getshm
ani 1 ;test for comment
jz shell4 ;process normally
;
; Process Shell Input as Comment
;
mov a,m ;get char
cpi cmdch ;command override?
jnz shellr ;continue with next line if not
inx h ;pt to command and fall thru to process
;
; Process Shell Command
;
shell4:
mov a,m ;get first char
ora a ;no line?
jz shellr
cpi cmtch ;comment line?
jz shellr
;
; Check for and Process Shell-Resident Command
;
push h ;save HL
call shcommand ;check for shell command
pop h ;restore HL
;
; Expand Shell Command Line
;
call expand ;expand line pted to by HL
jz clovfl ;abort if overflow
;
; Load Multiple Command Line
;
call putcl ;place command line pted to by HL into CL Buffer
rnz ;resume ZCPR3 processing
;
; Input Line is Longer than Command Line Buffer
;
clovfl:
call print ;command line buffer has overflowed
db cr,lf,'CL Ovfl ',0
jmp shellr
;
; Expand Shell Command Line (pted to by HL), performing variable
; Substitutions
;
; On exit, Z=command line overflow and Line Pted to by HL
;
expand:
push b ;save counter
mvi b,0 ;get shell register 0
call getshm
ani 2 ;test for echo
cnz crlf ;new line if SHECHO is ON
pop b ;get counter
xchg ;DE pts to line
;
; Init String Pointer Stack
;
mvi a,lecnt ;set local element count
sta locelt
lxi h,locstk ;set local stack
shld locadr
lxi h,0 ;set done code on stack
call locpush ;push HL
;
; Set Ptrs
;
lhld intline ;pt to internal line
xchg ;DE pts to internal line, HL pt next char
mvi b,0 ;256 chars max
;
; Analyze Next Char
;
exp1:
mov a,m ;get next char
cpi subch ;substitution char?
jnz exp2 ;handle normally
;
; Process Shell Variable
;
call expvar ;resolve variable
dcr c ;error?
jz exp1 ;resume if none
;
; Store Next Char
;
exp2:
stax d ;store char
;
; Print Char if SHECHO is ON
;
push b ;save counter
mov c,a ;save char
mvi b,0 ;get shell message 0
call getshm ;determines if display is on
ani 2 ;test for echo
jz exp3
mov a,c ;get char
ani 7FH ;mask and don't output null
cnz cout ;echo char
;
; Advance to Next Char
;
exp3:
mov a,c ;get char
pop b ;get counter
inx h ;pt to next
inx d
dcr b ;count down
jz experr ;error if at 0
ora a ;done?
jnz exp1
inr b ;increment count (not counting last 0)
dcx d ;pt to 0 in case of abort
;
; Pop String Ptr Stack and Check for Analysis Complete
;
call locpop ;get ptr to previous string
mov a,h ;done?
ora l
jnz exp1 ;resume
dcr a ;set NZ
;
; Expansion Complete
; On entry, Z Flag is Set Accordingly (Z=Error)
;
experr:
lhld intline ;pt to internal line
ret
;
; Expand Variable
; Return with HL pting to next char, A=char, C=1 if OK, C=2 if error
;
expvar:
shld varptr ;save ptr to variable
inx h ;get next char
mvi c,2 ;prep for error return
mov a,m ;get it
ora a ;EOL?
rz
cpi subch ;double sub char?
rz ;place one sub char in line if so
;
; Place Variable Into SHVAR
;
push b ;save counter
push d ;save ptr to next char
push h ;save ptr to shell variable
lxi h,shvar ;pt to shell variable buffer
mvi b,8 ;8 chars max
mvi a,' ' ;space fill
call fillb
xchg ;DE pts to shell variable buffer
pop h ;pt to shell variable
mvi b,8 ;8 chars max
;
; Place Shell Variable into Buffer
;
expv1:
mov a,m ;get char
call delck ;check for delimiter
jz expv3 ;done if delimiter
stax d ;save char
inx h ;pt to next
inx d
dcr b ;count down
jnz expv1
;
; Flush Overflow of Shell Variable
;
expv2:
mov a,m ;get char
inx h ;pt to next
call delck ;check for delimiter
jnz expv2
dcx h ;pt to delimiter
;
; Shell Variable in buffer SHVAR
; HL pts to delimiter after variable in user line
;
expv3:
call locpush ;stack ptr to next char in current string
jz expv4 ;error in stack
call varload ;load shell variable list
jz expv4 ;failure
call namer ;resolve named variable reference
mvi c,1 ;OK
jz expv5 ;name found - resolve
;
; Shell Variable Not Resolved - Restore Ptr to It
;
expv4:
call locpop ;restore ptr
mvi c,2 ;error
lhld varptr ;pt to variable
;
; Entry Point for OK Return
;
expv5:
mov a,m ;get char
pop d ;pt to target
pop b ;get counter
ret
;
; Push HL onto String Ptr Stack
; Return with Z if Stack Overflow
;
locpush:
lda locelt ;get count
dcr a ;full?
rz
sta locelt ;set count
push d ;save DE
xchg ;DE pts to old string
lhld locadr ;get ptr to top of stack
mov m,e ;store low
inx h
mov m,d ;store high
inx h ;pt to next
shld locadr
xchg ;restore HL
pop d ;restore DE
xra a ;return NZ
dcr a
ret
;
; Pop HL from String Ptr Stack
;
locpop:
push d
lda locelt ;increment element count
inr a
sta locelt
lhld locadr ;get address
dcx h ;pt to high
mov d,m ;get high
dcx h ;pt to low
mov e,m ;get low
shld locadr ;set address
xchg ;restore ptr
pop d
ret
;
; Load Shell Variable List
;
varload:
push h ;save regs
push d
push b
lda loadfl ;already loaded?
ora a ;NZ=yes
jnz varl3
lhld varlist ;clear varlist in case of error
mvi m,ctrlz
;
; Look for Variable File
;
call getfn1 ;pt to file name of SH.VAR
lxi d,shvfcb+1
mvi b,11 ;11 bytes
call moveb
call putud ;save current location
call root ;determine DU of root
call logud ;goto root
lhld varlist ;pt to named variable list
lxi d,shvfcb ;try to open file
call initfcb ;init FCB
call f$open
jz varl1
;
; Variable File Not Found
;
call getud ;return home
xra a ;set not found code
pop b ;restore regs
pop d
pop h
ret
;
; Read in Variable File
;
varl1:
lxi d,shvfcb ;read in file
call f$read
jnz varl2
lxi d,tbuff ;pt to data
xchg ;copy into memory
mvi b,128 ;128 bytes
call hmovb
xchg
jmp varl1
varl2:
lxi d,shvfcb ;close file
call f$close
call getud ;return home
;
; Say List is Already Loaded
;
varl3:
xra a ;return NZ for OK
dcr a
sta loadfl ;set loaded flag
pop b ;restore regs
pop d
pop h
ret
;
; Resolve Named Variable Reference
; On input, SHVAR contains the shell variable name and
; CODEND pts to the list of shell variables, terminated by ^Z;
; if found, return with HL pting to name and Z
;
namer:
lhld varlist ;pt to variable list
namer1:
mov a,m ;get char
cpi ctrlz ;end of list?
jz namex
lxi d,shvar ;pt to shell variable name
mvi b,8 ;8 chars
namer2:
ldax d ;get name
cmp m ;match?
jnz nomatch
inx h ;pt to next
inx d
dcr b ;count down
jnz namer2
ret ;found!
nomatch:
mov a,m ;flush to end of string
inx h ;pt to next
ora a
jnz nomatch
jmp namer1 ;resume search
;
; Search Failed
;
namex:
ora a ;return NZ (^Z in A)
ret
;
; Check to see if char in A is a delimiter
; Return with Z if so
;
delck:
push h ;pt to table
push b ;save BC
call caps ;capitalize char
mov b,a ;char in B
lxi h,dtable ;pt to delimiter table
delck1:
mov a,m ;get delimiter
ora a ;done?
jz notdel
cmp b ;compare
jz yesdel
inx h ;pt to next
jmp delck1
notdel:
mov a,b ;get char
ora a ;set Z if null, else NZ
yesdel:
mov a,b ;restore char
pop b ;restore regs
pop h
ret
;
; Delimiter Table
;
dtable:
db '<>;:,.=-_ ',0
;
; Check for Shell Command and Process if Found
; HL pts to command line
;
shcommand:
xra a ;DIR before DU
call parser ;parse command line pted to by HL
inx d ;pt to name
lxi h,ctable ;pt to command table
shcmd:
mov a,m ;get first char of next entry
ora a ;done?
rz
mvi b,8 ;commands are 8 chars long
push h ;save ptr to FCB
push d ;save ptr to table entry
shcmd1:
ldax d ;compare
cmp m
jnz shcmd2
inx h ;pt to next
inx d
dcr b ;count down
jnz shcmd1
;
; Command Found - Get Address
;
mov a,m
inx h
mov h,m
mov l,a ;HL is address
;
; Clear Stack and Run
;
pop psw ;clear stack
pop psw
pop psw ;clear return address
pop psw ;clear pushed HL
pchl ;"run" command
;
; Command Not Found Yet
;
shcmd2:
pop d ;restore ptrs
pop h
lxi b,10 ;advance to next command
dad b
jmp shcmd ;resume search
;
; If File Type not Specified, Set Default
;
setshdef:
call getfn1 ;check for file type
lxi d,8 ;pt to file byte
dad d
xchg
lxi h,shvtype ;default file type
mvi b,3 ;3 chars
ldax d ;get char
cpi ' ' ;set if space
cz moveb ;copy
ret
;
; Pop Current Shell
;
shexit:
call print
db cr,lf,'Exiting Shell',0
jmp shpop ;clear shell stack entry
;
; Toggle Shell Comment Mode
;
shcomment:
mvi b,0 ;access shell register 0
call getshm
mov c,a ;save in C
ani 0FEH ;all bits but comment bit
mov d,a
mov a,c ;get comment bit
cma ;flip comment bit (other bits are 1)
ani 1 ;select just comment bit
ora d ;OR in other bits
call putshm ;set new value
jmp shellr ;resume
;
; Toggle Shell Echo Mode
;
shecho:
call print
db cr,lf,' Echo of Shell Commands is O',0
mvi b,0 ;access shell register 0
call getshm
mov c,a ;save in C
ani 0FDH ;all bits but echo bit
mov d,a
mov a,c ;get comment bit
cma ;flip comment bit (other bits are 1)
ani 2 ;select just echo bit
ora d ;OR in other bits
call putshm ;set new value
ani 2 ;test echo bit
jz shecho1
call print
db 'N',0
jmp shellr
shecho1:
call print
db 'FF',0
jmp shellr ;resume
;
; Print Names of SH Commands
;
shhelp:
call print
db cr,lf,'SH Commands --',cr,lf,0
lxi h,ctable ;pt to table
mvi c,0 ;set count
shh1:
mov a,m ;done?
ora a
jz shellr
call print
db ' ',0
mvi b,8 ;8 chars
shh2:
mov a,m ;get char
call cout
inx h ;pt to next
dcr b ;count down
jnz shh2
inr c ;increment count
mov a,c
ani 3 ;new line?
cz crlf
inx h ;skip address
inx h
jmp shh1 ;next
;
; Command Table
;
ctable:
db '? ' ;help
dw shhelp
db 'SHCMT ' ;comment mode
dw shcomment
db 'SHECHO ' ;echo input
dw shecho
db 'SHEXIT ' ;exit shell
dw shexit
db 0 ;end of table
;
; Buffers
;
shvfcb:
db 0
db 'SH ' ;name of shell variable file
shvtype:
db 'VAR'
ds 24 ;36 bytes total
shdisk:
db 'A' ;disk letter
db '00' ;user number
db ':' ;separator
shname:
db 'SH ',0 ;name of shell to go onto stack
shvar:
db ' ' ;shell variable
locelt:
ds 1 ;string stack element count
locadr:
ds 2 ;ptr to next entry on stack
locstk:
ds lecnt*2 ;string ptr stack
varptr:
ds 2 ;ptr to current variable in line
varlist:
ds 2 ;ptr to named variable list
intline:
ds 2 ;ptr internal expansion line
loadfl:
ds 1 ;variables loaded flag
end