;
;  PROGRAM:  MENU
;  AUTHOR:  RICHARD CONN
;  VERSION:  3.2
;  DATE:  10 June 84
;  PREVIOUS VERSIONS:  3.1 (28 Mar 84), 3.0 (18 Mar 84)
;  DERIVATION. MENU 1.4 for ZCPR2
;
VERS	EQU	32

;
;	MENU is the ZCPR3 Menu Processor.  It loads, looks for the MENU.MNU
; file, and then displays it to the user (optionally) and prompts him for
; a single-character command.  The ZCPR3 Multiple Command Line Buffer must
; be installed for MENU to work, and MENU uses this buffer to chain to the
; programs selected by the user and return to itself at the proper place.
;
;	MENU supports multiple menus within one MENU.MNU file.  When a command
; is invoked, MENU returns to the menu the command came from.
;
;	MENU will ONLY RUN on ZCPR3 systems with the Multiple Command Line
; Buffer Option enabled.
;

;
;  Menu Constants
;
sysmenu		equ	0		;System Menu Enabled? 0=no, 1=yes

;  1 Special Menu Command Chars
RNM		EQU	'>'		;NEXT MENU
RNMP		EQU	'.'		;NEXT MENU PRIME (ALTERNATE)
RLM		EQU	'<'		;LAST MENU
RLMP		EQU	','		;LAST MENU PRIME (ALTERNATE)
RFM		EQU	'*'		;FIRST MENU
;
	if	sysmenu
RSM		EQU	'$'		;SYSTEM MENU (PASSWORD REQUIRED)
					; THIS IS SAME AS CONTROL CHAR
	endif		;sysmenu

;  2 Internal Menu Control Chars
MCMD		EQU	':'		;COMMAND TO JUMP TO ANOTHER MENU
PCHAR		EQU	'"'		;INDICATES AUTO PROMPT FOR SPECIFIC CMD
MINDIC		EQU	'#'		;MENU SECTION INDICATOR
MFIRST		EQU	'%'		;FIRST MENU INDICATOR
GOPTION		EQU	'-'		;GLOBAL OPTION INDICATOR
WOPTION		EQU	'!'		;ACTIVATES WAIT UPON RETURN

;  3 Menu Option Chars
COPTION		EQU	'C'		;DISPLAY COMMAND LINE TO USER
DOPTION		EQU	'D'		;DISPLAY MENU TO USER
POPTION		EQU	'P'		;PAGE OUT MENU DISPLAY TO USER
XOPTION		EQU	'X'		;DISABLE ZCPR3 RETURN

;  4 Miscellaneous
IBUFSZ		EQU	254		;SIZE OF INPUT LINE BUFFER
VARFLAG		EQU	'$'		;VARIABLE FLAG
					;(FOLLOWED BY D,U,Fn,Nn,Tn)
CMDSEP		EQU	';'		;ZCPR3 COMMAND SEPARATOR

;
;  Enter/Exit Standout Mode (Recommended that these values not be changed)
;
DIM			EQU	'A'-'@'	; ^A TO ENTER STANDOUT
NOTDIM			EQU	'B'-'@'	; ^B TO EXIT STANDOUT

;
;  MACRO Library of Definitions
;
	MACLIB	Z3BASE.LIB

;
;  ZCPR3 CONSTANTS
;
wboot	equ	0
bentry	equ	5
fcb	equ	5ch
tbuff	equ	80h
BEL	equ	7
CR	equ	0dh
LF	equ	0ah
CTRLC	equ	'C'-'@'
TAB	equ	'I'-'@'
CTRLZ	equ	'Z'-'@'

;
; MACROS TO PROVIDE Z80 EXTENSIONS
;   MACROS INCLUDE:
;
;	BR	- JUMP RELATIVE
;	BRC	- JUMP RELATIVE IF CARRY
;	BRNC	- JUMP RELATIVE IF NO CARRY
;	BRZ	- JUMP RELATIVE IF ZERO
;	BRNZ	- JUMP RELATIVE IF NO ZERO
;	BJNZ	- DECREMENT B AND JUMP RELATIVE IF NO ZERO
;	PUTRG	- SAVE REGISTERS
;	GETRG	- RESTORE REGISTERS
;

;
;
; Z80 MACRO EXTENSIONS
;
BR	MACRO	?N	;;JUMP RELATIVE
	IF	I8080	;;8080/8085
	JMP	?N
	ELSE		;;Z80
	.Z80
	JR	?N
	.8080
	ENDIF		;;I8080
	ENDM
;
BRC	MACRO	?N	;;JUMP RELATIVE ON CARRY
	IF	I8080	;;8080/8085
	JC	?N
	ELSE		;;Z80
	.Z80
	JR	C,?N
	.8080
	ENDIF		;;I8080
	ENDM
;
BRNC	MACRO	?N	;;JUMP RELATIVE ON NO CARRY
	IF	I8080	;;8080/8085
	JNC	?N
	ELSE		;;Z80
	.Z80
	JR	NC,?N
	.8080
	ENDIF		;;I8080
	ENDM
;
BRZ	MACRO	?N	;;JUMP RELATIVE ON ZERO
	IF	I8080	;;8080/8085
	JZ	?N
	ELSE		;;Z80
	.Z80
	JR	Z,?N
	.8080
	ENDIF		;;I8080
	ENDM
;
BRNZ	MACRO	?N	;;JUMP RELATIVE ON NO ZERO
	IF	I8080	;;8080/8085
	JNZ	?N
	ELSE		;;Z80
	.Z80
	JR	NZ,?N
	.8080
	ENDIF		;;I8080
	ENDM
;
BJNZ	MACRO	?N	;;DECREMENT B AND JUMP RELATIVE ON NO ZERO
	IF	I8080	;;8080/8085
	DCR	B
	JNZ	?N
	ELSE		;;Z80
	.Z80
	DJNZ	?N
	.8080
	ENDIF		;;I8080
	ENDM
;
PUTRG	MACRO
	PUSH	H	;;SAVE REGISTERS IN ORDER
	PUSH	D
	PUSH	B
	ENDM
;
GETRG	MACRO
	POP	B	;;RESTORE REGISTERS IN ORDER
	POP	D
	POP	H
	ENDM
;
; END OF Z80 MACRO EXTENSIONS
;

;
;  Externals from SYSLIB
;
	ext	z3vinit,cls,stndout,stndend
	ext	getcl1,putcl,getsh2,qshell,retud,getefcb,shpush,shpop
	ext	getshm,putshm,moveb,getfn2,pfn1,getcrt,getzrun,putzex,putcst
	ext	eprint,cin,cout,caps,crlf,pafdc,madc,bline,initfcb,sksp
	ext	f$open,f$close,f$read,codend,hmovb

;
; 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	SYSENV.LIB
z3eadr:
	jmp	start
	SYSENV
start:
	lxi	h,z3eadr	;pt to ZCPR3 environment
	endif

;
; Start of Program -- Initialize ZCPR3 Environment
;
	call	z3vinit	;initialize the ZCPR3 Env and the VLIB Env
	jmp	strt
;
;  This is the FCB which defines the default name of the MENU.MNU file
;
	if	sysmenu
ppass:
	db	'SYSTEM          ',0	;system password
	endif		;sysmenu
;
menufcb:
	db	0		;FCB for MENU.MNU
	db	'MENU    '
	db	'MNU'
	ds	4
scratch:			;this doubles as a scratch area
	ds	16		;buffer definition is at end of program
	ds	4		;36 bytes total

;
;  Start of Program
;
strt:
;
; Check for Shell Stack
;
	call	getsh2	;get shell status
	brnz	strt0	;skip over shell init
	call	eprint
	db	' No Shell Stack',0
	ret
;
; See if Command Line Available
;
strt0:
	call	getcl1	;get line
	brnz	strt01
	call	eprint
	db	' No Command Line',0
	ret
;
; See if this program was invoked as a shell
;
strt01:
	call	qshell	;find out from ZCPR3 environment
	push	psw	;save status
	xra	a	;A=0
	call	putcst	;put command status (normal = 0)
	pop	psw	;restore status
	jz	menu	;do not push onto stack if invoked as a shell
;
; Set Name of Shell from External FCB if Possible or From Default if Not
;
setshn:
	call	retud	;get run 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
	brc	setshn2
	inr	d	;increment digit
	br	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
	brz	strt02	;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
;
; Check for File Name and Set It If Given
;
strt02:
	lxi	h,fcb+1	;pt to file name
	lxi	d,menufcb+1
	mvi	b,11	;11 chars
	mov	a,m	;get first char
	cpi	' '
	cnz	moveb	;copy if one present
;
; Set File Name in MENUFCB into Line
;
	lxi	h,menufcb+1	;set shell file name
	lxi	d,shfile	;pt to shell file
	mvi	b,8	;8 chars
strt03:
	mov	a,m	;get next char
	cpi	' '	;done?
	brz	strt04
	stax	d	;put char
	inx	d	;pt to next
strt04:
	inx	h	;pt to next
	bjnz	strt03
	mvi	a,'.'	;put dot
	stax	d
	inx	d	;pt to next
	mvi	b,3	;file type
strt05:
	mov	a,m	;copy
	stax	d
	inx	h	;pt to next
	inx	d
	bjnz	strt05
	xra	a	;store zero
	stax	d

;
; Set Menu Number
;
	mvi	b,1	;shell message 1
	xra	a	;menu 0
	call	putshm	;set message

;
; Push Name of Shell onto Stack
;
	lxi	h,shdisk	;pt to name of shell
	call	shpush	;push shell onto stack
	brnz	strt2
;
; Shell Successfully Installed
;
	call	eprint
	db	' Shell Installed',0
	ret
;
; Shell Stack Push Error
;
strt2:
	cpi	2	;shell stack full?
	brnz	strt3
;
; Shell Stack is Full
;
	call	eprint
	db	' Shell Stack Full',0
	ret
;
; Shell Stack Entry Size is too small for command line
;
strt3:
	call	eprint
	db	' Shell Stack Entry Size',0
	ret
;
; Check for ZEX Execution and Pass ZEX if So
;
menu:
	call	getzrun		;is ZEX running?
	brz	runmenu		;process menu if not
	br	menuz1		;skip new line
menuzex:
	call	crlf		;new line
menuz1:
	call	eprint
	db	'Menu> ',0
	mvi	a,1		;tell ZEX that it is prompted
	call	putzex
	call	codend		;set up buffer
	mvi	m,ibufsz	;set size
	mvi	a,0FFH		;capitalize
	call	bline		;get line from ZEX
	xra	a		;A=0
	call	putzex		;resume ZEX normally
	call	sksp		;skip over leading spaces
	mov	a,m		;check for comment
	cpi	';'
	brz	menuzex
	xchg			;DE pts to command line
	xra	a		;don't display command
	sta	cpflag
	jmp	runcmnd		;run command pted to by DE
;
; Begin Menu Processing
;
runmenu:
	call	eprint
	db	'MENU  Version '
	db	(vers/10)+'0','.',(vers mod 10)+'0',0
;
; Check for Wait Flag and Wait if So
;
	mvi	b,0		;get shell message 0
	call	getshm
	ani	80h		;check for wait flag
	cnz	sak		;Strike Any Key
;
; Open Menu File
;
	lxi	h,fcb		;copy FCB into MENU FCB
	lxi	d,menufcb
	mvi	b,36		;36 bytes
	push	d		;save ptr
	call	moveb
	pop	d		;pt to MENU.MNU FCB
	call	initfcb		;init fcb
	call	f$open		;open file
	brz	menu1		;abort if no menu
	call	eprint
	db	CR,LF,' File ',0
	lxi	d,menufcb+1
	call	pfn1
	call	eprint
	db	' Not Found',0
	jmp	shpop
;
;  Load MENU.MNU from disk
;
menu1:
	call	codend		;get address of buffer for menu load
mload:
	lxi	d,menufcb	;pt to FCB
	call	f$read		;read in next block
	ora	a		;error?
	brnz	mloaddn		;load done if error
	lxi	d,tbuff		;copy from TBUFF into memory pted to by HL
	xchg			;HL is source, DE is dest
	mvi	b,128		;128 bytes
	call	hmovb
	lhld	bentry+1	;get address of top of TPA
	mov	a,h		;set to bottom of ZCPR3
	sui	10
	cmp	d		;about to overflow ZCPR3?
	brnc	mload1	;continue if not
	call	eprint
	db	CR,LF,' TPA Full',0
	ret
mload1:
	xchg			;HL pts to next byte to load to
	br	mload		;continue load


;
;  Init Flags and Clear MSB of all bytes in Menu File
;
mloaddn:
	call	f$close		;close input file
	mvi	m,CTRLZ		;ensure EOF mark
	lxi	d,80H		;pt to next block
	dad	d
	shld	ibuff		;set ptr to input line buffer
	mvi	m,ibufsz	;set size
	dad	d		;allow 256 bytes
	dad	d
	shld	expline		;set ptr to expand line
	xra	a		;A=0
	sta	cflag		;turn off command display
	sta	dflag		;turn off menu display
	sta	pflag		;disallow paging
	sta	cpmok		;turn off ZCPR3 return flag
	call	codend		;pt to beginning of file
	push	h		;save ptr
menul1:
	mov	a,m		;get byte
	ani	7FH		;mask out MSB
	mov	m,a		;put byte
	inx	h		;pt to next
	cpi	CTRLZ		;EOF?
	brnz	menul1		;continue if not
;
;  Mark all Menu Sections
;
	pop	h		;HL pts to first byte of menu
	mvi	b,0FFH		;set menu counter
;
;  Skip to Next Menu
;
menul2:
	mov	a,m		;get byte
	cpi	CTRLZ		;error?
	jz	mstrerr		;structure error if so
	cpi	MINDIC		;menu indicator (start of menu?)
	brnz	menul4
	ori	80H		;beginning of menu found -- set MSB
	mov	m,a		;put byte
	inr	b		;increment menu count
	inx	h		;pt to next
	mov	a,m		;get byte
	cpi	MINDIC		;menu indicator (end of menu?)
	brz	menul5		;done if so
	cpi	CTRLZ		;error?
	jz	mstrerr
;
	if	sysmenu
	cpi	RSM		;system menu indicator?
	brnz	menul3
	mov	a,b		;set system menu number
	sta	smeno
	mvi	a,0FFH		;set flag
	sta	smenfl		;system menu present
	dcx	h		;back up to beginning of menu
	shld	smenadr		;start address
	inx	h		;pt to RSM
	endif		;sysmenu
;
;  Skip out Menu Display
;
menul3:
	call	lskipt		;skip to beginning of next line
	brz	menul4		;found menu indicator
	cpi	CTRLZ		;error?
	jz	mstrerr
	br	menul3		;continue if not
;
;  Skip to Next Menu
;
menul4:
	call	lskip		;skip to beginning of next menu
	br	menul2
;
;  Check Menu Options
;
menul5:
	call	codend		;pt to beginning of file
	mov	a,m		;check for option
	cpi	GOPTION		;global option char?
	jnz	mfile		;if no global option, scan for menu files
	inx	h		;pt to option char
option:
	mov	a,m		;get option char
	call	caps		;capitalize
	inx	h		;pt to next
	cpi	CR		;done?
	brz	optdn
	cpi	COPTION		;display command?
	brz	optc
	cpi	DOPTION		;display menu?
	brz	optd
	cpi	POPTION		;paging?
	brz	optp
	cpi	XOPTION		;exit OK?
	jnz	mstrerr		;option error if not
;
;  Disable Exit to ZCPR3
;
	mvi	a,0FFH		;turn flag off
	sta	cpmok
	br	option
;
;  Process Paging Option
;
optp:
	mvi	a,0FFH		;set flag
	sta	pflag
	br	option
;
;  Process Display Menu Option
;
optd:
	mvi	a,0FFH		;set flag
	sta	dflag
	br	option
;
;  Process Display Command Option
;
optc:
	mvi	a,0FFH		;set flag
	sta	cflag
	br	option

;
;  Option Processing Done
;
optdn:
	inx	h		;skip LF

;
;  Check for Menu Display
;
mfile:
	mov	a,m		;get first byte
	ani	7FH		;mask
	cpi	MINDIC		;start of menu?
	jnz	mstrerr

;
;  Check and Set First Menu
;
	shld	mstart		;save start address of first menu item
	mvi	m,MFIRST+80H	;set first char of first menu

;
;  Entry Point for Menu Display
;	On entry, HL pts to first byte of current menu
;
dmenu:
	mvi	b,1		;shell message 1 contains menu number
	call	getshm		;get menu number flag
	cnz	mchc0		;skip to proper menu
	shld	cstart		;save start address of current menu
	lda	cflag		;copy display command flag for temp use
	sta	cpflag
	lda	dflag		;copy display menu flag for temp use
	sta	dpflag
	lda	pflag		;copy paging flag for temp use
	sta	ppflag
	inx	h		;pt to first char after menu indicator char
dispm1:
	mov	a,m		;get char
	call	caps		;capitalize
	inx	h		;pt to next
	cpi	CR		;end of options?
	brz	dispm2
;
	if	sysmenu
	cpi	RSM		;system menu?
	brz	dispm1		;ok if so
	endif		;sysmenu
;
	cpi	COPTION		;command display?
	brz	dispmc
	cpi	DOPTION		;display?
	brz	dispmd
	cpi	POPTION		;paging?
	brz	dispmp
	cpi	XOPTION		;ZCPR3 return?
	jnz	mstrerr		;error if not
;
;  Toggle ZCPR3 Return Option
;
	lda	cpmok		;get flag
	cma			;toggle
	sta	cpmok
	br	dispm1
;
;  Toggle Paging Option
;
dispmp:
	lda	ppflag		;get flag
	cma			;toggle
	sta	ppflag
	br	dispm1
;
;  Toggle Display Menu Option
;
dispmd:
	lda	dpflag		;get flag
	cma			;toggle
	sta	dpflag
	br	dispm1
;
;  Toggle Display Command Option
;
dispmc:
	lda	cpflag		;get flag
	cma			;toggle
	sta	cpflag
	br	dispm1
;
;  Done with Menu-Specific Option Processing
;
dispm2:
	call	lskip		;skip to LF
	lda	dpflag		;display menu?
	ora	a		;0=no
	brz	dispm8		;skip over menu if not
	call	getnlines	;get line count in A
	sta	pagcnt		;set count
	lda	ppflag		;paging?
	ora	a		;0=no
	push	psw		;save flag
	cnz	cls		;clear screen if so
	pop	psw		;get flag
	cz	crlf		;else new line
;
;  Print Next Line of Menu if not Starting with ESCAPE Char (MINDIC)
;
dispm3:
	mov	a,m		;get first char of line
	ani	7FH		;mask
	cpi	MINDIC		;done?
	brz	dispm4
	call	expand		;expand line pted to by HL
	push	h		;save ptr to next line
	xchg			;HL pts to expanded line
	call	lprintx		;print line pted to by HL ending in <CR>
	pop	h		;pt to next line
	br	dispm3
;
;  Done with Menu Display -- Page it out
;
dispm4:
	call	lskip		;skip to first char of next line (option char)
	shld	optstrt		;set start address of options
	lda	pagcnt		;number of remaining lines
	mov	b,a		;count in B
	ora	a		;ok?
	brz	dispm6		;don't do anything if already there
	lda	ppflag		;page?
	ora	a		;0=No
	brz	dispm6
;
;  Page Loop for Menu Display
;
dispm5:
	call	crlf		;new line
	bjnz	dispm5
;
;  Determine if Another Menu Follows
;
dispm6:
	xra	a		;A=0
	sta	nmenfl		;set for no next menu
	mov	a,m		;ok?
	ani	7FH		;mask
	cpi	CTRLZ		;error if EOF
	jz	mstrerr
	cpi	MINDIC		;next menu?
	brnz	dispm7
	inx	h		;double indicator if end
	mov	a,m
	cpi	MINDIC		;end?
	brz	dispm9
;
	if	sysmenu
	cpi	RSM		;system menu = no next menu
	brz	dispm9
	endif		;sysmenu
;
	mvi	a,0FFH		;set next menu
	sta	nmenfl
	br	dispm9
dispm7:
	call	lskip		;skip to next line
	br	dispm6

;
;  Skip over current menu so it is not displayed
;
dispm8:
	call	lskipt		;skip to beginning of command
	brnz	dispm8
	call	lskip		;skip over end of display indicator
	shld	optstrt		;set pointer to options
	br	dispm6		;determine if next menu available
dispm9:

;
;  Ready for Option Input
;    The following Flags/Values are now set:
;	CPFLAG -- Display Command Flag (0=No, 0FFH=Yes)
;	DPFLAG -- Display Menu Flag (0=No, 0FFH=Yes)
;	OPTSTRT -- Address of First Menu Option
;	NMENFL -- 0 if no next menu, 0FFH if next menu
;	MSTART -- Start Address of MINDIC Before Menu Display
;	  (MSTART)=MFIRST with MSB Set
prompt:
	call	stndout		;begin standout
	mvi	a,0ffh
	sta	pagcnt		;turn off paging
	sta	dpflag		;turn on future menu displays
	call	retud		;get DU
	mov	a,b		;print D
	adi	'A'
	call	cout
	mov	a,c		;print U
	call	pafdc
	call	eprint
	db	'> Command (CR=Menu',0
	lda	cpmok		;OK to return to ZCPR3?
	ora	a		;0=No
	cnz	prmptc
	lhld	cstart		;pt to first char
	mov	a,m		;get it
	ani	7FH		;mask
	cpi	MFIRST
	cnz	prmptf		;print previous menu prompt if not first menu
	lda	nmenfl		;next menu available?
	ora	a		;0=No
	cnz	prmptn		;print next menu prompt
	call	eprint
	db	') - ',0
	call	stndend		;end standout
prompt1:
	call	cin		;get response
	call	caps		;capitalize
	mov	b,a		;result in B

;
;  Check for CR
;
	cpi	CR		;<CR>?
	jz	dispm2		;reprint menu if so

;
;  Check for Reboot
;
	lda	cpmok		;ok to abort?
	ora	a		;0=No
	brz	prmpt0
	mov	a,b		;get command
	cpi	CTRLC		;reboot?
	jz	shpop		;pop shell stack and return to OS if so

;
;  Check for Command to Return to First Menu
;
prmpt0:
	mov	a,m		;get it
	ani	7FH		;mask
	cpi	MFIRST
	brz	prmpt1
	mov	a,b		;get command
	cpi	RFM		;return to first menu?
	brnz	prmpt1
	lhld	mstart		;pt to first menu
	mvi	b,1		;shell message 1 is menu number
	xra	a		;A=0=menu 0
	jmp	putshm		;reenter shell at first menu

;
;  Check for Command to go to Next Menu
;
prmpt1:
	lda	nmenfl		;next menu available?
	ora	a		;0=No
	brz	prmpt2
	mov	a,b		;get command
	cpi	RNMP		;goto next menu?
	brz	rnmx
	cpi	RNM		;goto next menu?
	brnz	prmpt2
rnmx:
	mvi	b,1		;shell message 1 is menu number
	call	getshm		;increment menu number
	inr	a
	jmp	putshm		;reenter menu system at new menu

;
;  Check for Command to go to Last Menu
;
prmpt2:
	mov	a,m		;get menu char
	ani	7FH		;at first menu?
	cpi	MFIRST
	brz	prmpt3		;skip if at first menu
	mov	a,b		;get command
	cpi	RLMP		;goto last menu?
	brz	lstmnu
	cpi	RLM		;goto last menu?
	brnz	prmpt3
lstmnu:
	mvi	b,1		;shell message 1 is menu number
	call	getshm		;decrement menu number
	dcr	a
	jmp	putshm		;reenter shell at last menu

;
;  Check for Command to goto System Menu
;
prmpt3:
	if	sysmenu
;
	lda	smenfl		;system menu available?
	ora	a		;0=No
	brz	prmpt4
	mov	a,b		;get command
	cpi	RSM		;system menu?
	brnz	prmpt4
	call	password	;prompt for and get password
	jnz	prompt		;reprompt if error
	lhld	smenadr		;get address of system menu
	lda	smeno		;set system menu number
	mvi	b,1		;shell message 1 is menu number
	jmp	putshm		;reenter shell at system menu
;
	endif		;sysmenu
;
;  This is where additional functions may be added
;
prmpt4:

;
;  Check for Option Letter
;
	lhld	optstrt		;pt to first option char
prmptx:
	mov	a,m		;get it
	call	caps		;capitalize
	cpi	MINDIC		;at next menu?
	brz	prmpter
	cmp	b		;match user selection?
	brz	prmptd
	call	lskip		;skip to next line
	br	prmptx

;
;  Invalid Option
;
prmpter:
	call	eprint
	db	BEL,0
	jmp	prompt1

;
;  Process Option
;
prmptd:
	mov	a,b		;output user selection
	call	cout
	mvi	b,0		;shell message 0, bit 7 = wait flag
	call	getshm
	ani	7FH		;set no wait
	call	putshm
	inx	h		;pt to first letter of command
	mov	a,m		;get it
	cpi	MCMD		;invoke other menu?
	jz	mchcmd		;menu change command
	cpi	WOPTION		;turn on wait?
	brnz	prmptg
	mvi	b,0		;shell message 0, bit 7 = wait flag
	call	getshm
	ori	80h		;set wait flag
	call	putshm		;set shell message
	inx	h		;skip option char
prmptg:
	call	expand		;expand line, DE pts to result
;
; Run Command Pted to by DE
;
runcmnd:
	call	getcl1		;get address of command buffer
	mov	b,h		;... in BC also
	mov	c,l
	mvi	a,4		;HL=HL+4 for address of first char
	add	l
	mov	l,a
	mov	a,h
	aci	0
	mov	h,a
	mov	a,l		;store address
	stax	b
	inx	b
	mov	a,h
	stax	b
;
; Copy Command Line in DE into Buffer in HL
;
cmdcpy:
	ldax	d		;get command letter
	call	caps		;capitalize it
	ora	a		;done?
	brz	ccpyd
	cpi	CR		;done?
	brz	ccpyd
	cpi	PCHAR		;prompt?
	brz	ccpyp
	mov	m,a		;store it
	inx	h		;pt to next
	inx	d
	br	cmdcpy
ccpyd:
	mvi	m,0		;store ending 0
	jmp	cmddisp		;optionally display command
;
;  Prompt User for Input and Accept It
;
ccpyp:
	inx	d		;pt to first char of prompt
	call	crlf		;new line
ccpyp1:
	ldax	d		;get char
	cpi	PCHAR		;end of prompt?
	brz	ccpyp2
	cpi	CR		;new line?
	brz	ccpyp3
	call	cout		;echo char
	inx	d		;pt to next char
	br	ccpyp1		;continue looping
ccpyp2:
	inx	d		;pt to char after closing PCHAR
ccpyp3:
	push	d		;save ptr to next char
	xchg			;DE pts to buffer
	mvi	a,0FFH		;capitalize input from user
	lhld	ibuff		;input line buffer
	call	bline		;get input from user
	xchg			;HL pts to buffer, DE pts to user input
cmdlp:
	ldax	d		;get char from user
	ora	a		;end of input?
	brz	cmdlp1		;store rest of line
	mov	m,a		;store char
	inx	h		;pt to next
	inx	d
	br	cmdlp
cmdlp1:
	pop	d		;DE pts to next char, HL pts to buffer
	br	cmdcpy		;resume copying
;
;  Check for Display of Loaded Command and Do So if Set
;
cmddisp:
	lda	cpflag		;display command?
	ora	a		;0=No
	rz			;return to OS if so to run command
	call	crlf		;new line
	call	getcl1		;pt to first char
	mov	e,m		;get low-order address
	inx	h
	mov	d,m		;get high-order address
	xchg			;HL pts to first char
cmdd1:
	mov	a,m		;get char
	cpi	CMDSEP		;done if command separator
	rz
	inx	h		;pt to next
	call	cout		;print char
	br	cmdd1

;
;  Menu Change Command -- Jump to Specified Menu
;
mchcmd:
	inx	h		;pt to menu number
	call	eval		;convert to decimal number in A
	sta	menuno		;save menu number
	call	mchc0		;skip to desired menu to check for it
	lda	menuno		;get menu number
	mvi	b,1		;menu number is shell message 1
	jmp	putshm		;set message and reenter shell

;
;  Entry Point if MENU is Reinvoked
;
mchc0:
	mov	b,a		;menu number in B
	inr	b		;add 1 for initial offset
	lhld	mstart		;pt to first menu
mchc1:
	dcr	b		;count down
	rz			;done if found
mchc2:
	call	lskipt		;skip to next line
	brnz	mchc2		;continue if not end of menu display
mchc3:
	call	lskipt		;skip to next line
	brnz	mchc3		;continue if not at end of menu commands
	inx	h		;end of MENU.MNU?
	mov	a,m		;yes if double MINDIC
	ani	7FH		;mask
	cpi	MINDIC
	brz	mchcerr		;error if so
	dcx	h		;pt to first char
	br	mchc1		;continue
;
; Premature End of Menu File
;
mchcerr:
	pop	psw		;clear stack
	jmp	mstrerr		;menu structure error

;
;  Print Line pted to by HL Ending in <CR>
;    Decrement PAGCNT
;
lprintx:
	call	lprint		;print without <CR>
	jmp	crlf		;do <CR> <LF>
;
;  Print Line Pted to by HL; Decrement PAGCNT
;
lprint:
	mvi	b,0		;set tab counter
lprnt0:
	mov	a,m		;get char
	inx	h		;pt to next
	ani	7FH		;mask MSB
	cpi	DIM		;goto standout mode?
	brz	lprnt3
	cpi	NOTDIM		;end standout mode?
	brz	lprnt4
	cpi	TAB		;tabulate?
	brz	lprnt2
	cpi	CR		;done?
	brz	lprnt1
	call	cout		;print
	inr	b		;incr tab counter
	br	lprnt0
lprnt1:
	inx	h		;pt to first char of next line
	lda	pagcnt		;count down pages
	dcr	a
	sta	pagcnt
	rnz
	call	getnlines	;get line count in A
	sta	pagcnt
	call	eprint
	db	CR,LF,'Pause -',0
	br	sak1
lprnt2:
	mvi	a,' '		;print <SP>
	call	cout
	inr	b		;incr tab counter
	mov	a,b		;done?
	ani	7		;every 8
	brnz	lprnt2
	br	lprnt0
lprnt3:
	call	stndout		;enter standout mode
	br	lprnt0
lprnt4:
	call	stndend		;end standout mode
	br	lprnt0
;
;  Strike Any Key Message
;
sak:
	mvi	b,0		;clear any pending wait
	call	getshm
	ani	7FH		;mask MSB
	call	putshm
sak1:
	call	stndout		;goto standout
	call	eprint
	db	' Strike Any Key - ',0
	call	stndend		;exit standout
	call	cin		;get response
	call	crlf		;new line
	ret

;
;  Prompt for, input, and check password (only one chance)
;    If accepted, return with Zero Flag Set; if not, return with NZ
;
	if	sysmenu
password:
	call	eprint
	db	CR,LF,'Pass? ',0
	lhld	ibuff		;pt to input line buffer
	xra	a		;don't capitalize user input
	call	bline		;get line from user
	lxi	d,ppass		;pt to system password
pass1:
	ldax	d		;get sys pass char
	cmp	m		;ok?
	brnz	passerr		;error if no match
	inx	h		;pt to next
	inx	d
	ora	a		;end of strings?
	brnz	pass1
	ret			;return with zero set to show match
passerr:
	call	eprint
	db	CR,LF,' Password Error',0
	call	sak1		;strike any key
	call	crlf
	mvi	a,0FFH		;set no zero
	ora	a
	ret
	endif		;sysmenu
;
;  Skip to Beginning of Next Line and Test First Char for Menu Indicator
;
lskipt:
	call	lskip		;skip
	mov	a,m		;get char
	ani	7FH		;mask
	cpi	MINDIC		;test
	ret

;
;  Skip to Beginning of Next Line
;
lskip:
	mov	a,m		;get char
	ani	7FH		;mask out MSB
	inx	h		;pt to next
	cpi	LF
	brnz	lskip
	ret

;
;  Print ZCPR3 Return Prompt
;
prmptc:
	call	eprint
	db	', ^C=Z3',0
	ret
;
;  Print First/Last Menu Chars
;
prmptf:
	call	eprint
	db	', ',RFM,'=1st Menu, ',RLM,'=Prev Menu',0
	ret
;
;  Print next menu message
;
prmptn:
	call	eprint
	db	', ',RNM,'=Next Menu',0
	ret

;
;  Menu Structure Error -- FATAL
;    This message is printed to indicate an error in the structure of
; the MENU.MNU file.
;
mstrerr:
	call	eprint
	db	CR,LF,' Structure Error',0
	jmp	shpop

;
; Expand Line Pted to by HL into Scratch Area
;	Return with HL pting to next line, DE pting to current line
;
expand:
	xchg
	lhld	expline		;pt to buffer
	xchg
exp1:
	mov	a,m		;get next char
	ani	7fh		;mask MSB
	stax	d		;store char
	cpi	CR		;end of line?
	jz	expx
	inx	h		;pt to next
	inx	d
	cpi	VARFLAG		;variable follows?
	brnz	exp1
;
; Variable Identified - Process it
;
	mov	a,m		;get next char
	inx	h		;pt to next
	cpi	VARFLAG		;one variable char?
	brz	exp1		;resume if double VARFLAG
	dcx	d		;pt to variable position
	call	caps		;capitalize variable
	cpi	'D'		;current disk?
	brz	expdisk
	cpi	'U'		;current user?
	brz	expuser
	cpi	'F'		;filename.typ?
	brz	expfile
	cpi	'N'		;filename?
	brz	expname
	cpi	'T'		;filetype?
	brz	exptype
	br	exp1		;resume expansion
;
; Expand Exit
;
expx:
	inx	h		;pt to line feed
	mov	a,m		;get it
	cpi	LF		;line feed?
	brnz	expx1
	inx	h		;pt to char after line feed
expx1:
	xchg			;DE pts to next line
	lhld	expline		;pt to expanded line
	xchg			;HL pts to next line, DE pts to expanded line
	ret

;
; Expand Disk
;
expdisk:
	call	retud		;get disk in B
	mov	a,b		;get disk number (A=0)
	adi	'A'		;convert to ASCII
	stax	d		;store letter
	inx	d		;pt to next
	br	exp1		;resume expansion
;
; Expand User
;
expuser:
	call	retud		;get user in C
	mov	a,c		;get user number
	mvi	b,10		;subtract 10's
	mvi	c,'0'		;set char
expu1:
	sub	b		;-10
	brc	expu2
	inr	c		;increment digit
	br	expu1
expu2:
	add	b		;+10
	adi	'0'		;convert 1's to ASCII
	mov	b,a		;B=1's
	mov	a,c		;get 10's
	stax	d		;store 10's
	inx	d
	mov	a,b		;get 1's
	stax	d		;store 1's
	inx	d		;pt to next
	br	exp1		;resume
;
; Expand File
;
expfile:
	call	getfnum		;get file number
	jz	exp1		;resume if error
	push	h		;save ptr to next char
	call	ptfn		;set ptr to file name
	call	putn		;put file name
	mvi	a,'.'
	stax	d		;store dot
	inx	d		;pt to next
	call	putt		;put file type
	pop	h		;restore ptr
	jmp	exp1		;resume
;
; Expand Name
;
expname:
	call	getfnum		;get file number
	jz	exp1		;resume if error
	push	h		;save ptr to next char
	call	ptfn		;set ptr to file name
	call	putn		;put file name
	pop	h		;restore ptr
	jmp	exp1		;resume
;
; Expand Type
;
exptype:
	call	getfnum		;get file number
	jz	exp1		;resume if error
	push	h		;save ptr to next char
	call	ptfn		;set ptr to file name
	mvi	a,8		;add 8
	add	l
	mov	l,a
	mov	a,h
	aci	0
	mov	h,a
	call	putt		;put file type
	pop	h
	jmp	exp1		;resume
;
; Pt to File Name whose Number (1-4) is in A
;
ptfn:
	mov	b,a		;get number in B
	call	getfn2		;pt to file name 2
	push	d		;save DE
	mov	a,b		;file 0?
	ora	a
	brz	ptfnx
	lxi	d,11		;size of file name and type
ptfn1:
	dad	d		;pt to next
	bjnz	ptfn1
ptfnx:
	pop	d		;restore DE
	ret
;
; Put File Name pted to by HL
;
putn:
	mvi	b,8		;8 chars
	br	putc
;
; Put File Type pted to by HL
;
putt:
	mvi	b,3		;3 chars
;
; Copy Chars from HL to DE for up to B bytes -- flush if space
;
putc:
	mov	a,m		;get next char
	cpi	' '		;skip spaces
	brz	putc1
	stax	d		;put next char
	inx	d		;pt to next
putc1:
	inx	h		;pt to next
	bjnz	putc
	ret

;
; Get File Number (1 to 4)
;	If valid number, return with value in A and HL pting to next char
;	If not valid, return with Z and HL pting to last char (F, N, T)
;
getfnum:
	mov	a,m		;get char
	sui	'1'		;convert
	brc	getfne		;error
	cpi	4		;range?
	brnc	getfne
	inx	h		;pt to next char
	ret			;NZ from CPI 4
getfne:
	dcx	h		;error return
	xra	a
	ret

;
;  Return Number of Lines on CRT in A
;
getnlines:
	push	h		;save HL
	call	getcrt		;get CRT info
	inx	h		;pt to number of lines
	mov	a,m		;get count
	pop	h		;restore HL
	dcr	a		;subtract 1 for footer
	ret

;
;  Convert char string pted to by HL into decimal number in A
;	On Entry, HL pts to first digit char
;	On Exit, HL pts to after last digit char and A=number
;
eval:
	push	b		;save BC
	mvi	b,0		;set value
eval1:
	mov	a,m		;get digit
	sui	'0'		;convert to binary
	brc	eval2
	cpi	10		;range?
	brnc	eval2
	inx	h		;pt to next digit
	mov	c,a		;new digit in C
	mov	a,b		;multiply B by 10
	add	a		;*2
	add	a		;*4
	add	b		;*5
	add	a		;*10
	add	c		;add in new digit
	mov	b,a		;result in B
	br	eval1
eval2:
	mov	a,b		;result in A
	pop	b		;restore ptr
	ret

;
;  These buffers overlay the scratch area to save space
;
optstrt	equ	scratch		;Address of First Option in Current Menu
mstart	equ	optstrt+2	;Address of First Menu
cstart	equ	mstart+2	;Address of Current Menu
smenfl	equ	cstart+2	;System Menu Available Flag (0=No)
smeno	equ	smenfl+1	;System Menu Number
smenadr	equ	smeno+1		;Address of First Byte of System Menu
nmenfl	equ	smenadr+2	;Next Menu Available Flag (0=No)
menuno	equ	nmenfl+1	;Number of Menu
pagcnt	equ	menuno+1	;Paging Counter
cflag	equ	pagcnt+1	;Display Command Line Flag
dflag	equ	cflag+1		;Display Menu Flag
pflag	equ	dflag+1		;Paging Flag

;
;  Buffers
;
ibuff:
	ds	2		;input line buffer
expline:
	ds	2		;scratch area to expand lines in
cpflag:
	ds	1		;Temp Display Command Line Flag
dpflag:
	ds	1		;Temp Display Menu Flag
ppflag:
	ds	1		;Temp Paging Flag
cpmok:
	ds	1		;OK to Return to ZCPR3 (0=No)
tnum:
	ds	41		;space for chars and ending 0
shdisk:
	db	'A'		;disk to return to
	db	'00'		;user to return to
	db	':;'		;log in and next command
shname:
	db	'MENU    '	;program name (filled in at installation)
shfile:
	ds	13		;file name (12) and ending 0

	end