mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 14:11:48 -06:00
551 lines
11 KiB
Plaintext
551 lines
11 KiB
Plaintext
;
|
||
; PROGRAM: VMENUCK
|
||
; AUTHOR: RICHARD CONN
|
||
; VERSION: 1.0
|
||
; DATE: 22 July 84
|
||
; PREVIOUS VERSIONS: None
|
||
; DERIVATION: MENUCK 1.0 (18 May 84)
|
||
;
|
||
VERS EQU 10 ;VERSION NUMBER
|
||
z3env SET 0f400h
|
||
|
||
;
|
||
; VMENUCK is used to check the syntax of a MENU.VMN file for the ZCPR3
|
||
; menu processor, VMENU. VMENU was optimized for size and runtime speed, and
|
||
; I tried to keep the size under 2K (and succeeded, for that matter). In
|
||
; keeping VMENU small, the error diagnostics it gives are quite limited, with
|
||
; a variety of errors producing the message "Str Err" for MENU.VMN
|
||
; structure error.
|
||
;
|
||
; VMENUCK is intended to be used to check the syntax and other features
|
||
; of a user's MENU.VMN before allowing VMENU to run with it. In this way,
|
||
; many errors may be caught before the MENU.VMN file comes into common use,
|
||
; and there is plenty of space for informative diagnostics.
|
||
;
|
||
|
||
;
|
||
; MENU Constants
|
||
;
|
||
MCMD EQU ':' ;Menu Jump Command
|
||
MINDIC EQU '#' ;Menu Indic
|
||
GOPTION EQU '-' ;Global Option Indic
|
||
XOPTION EQU 'X'
|
||
VARFLAG EQU '$' ;Variable Flag
|
||
|
||
;
|
||
; CP/M Constants
|
||
;
|
||
bentry equ 5 ;BDOS Entry
|
||
fcb equ 5ch ;FCB
|
||
tbuff equ 80h ;Temp I/O Buffer
|
||
cr equ 0dh
|
||
lf equ 0ah
|
||
EOF equ 'Z'-'@' ;^Z=EOF
|
||
|
||
;
|
||
; Externals
|
||
;
|
||
ext z3init,zfname,z3log
|
||
|
||
ext caps,crlf,eval10,retud
|
||
ext f$open,f$close,f$read
|
||
ext print,cout
|
||
ext moveb
|
||
ext phldc,padc,pfn2,pafdc
|
||
ext codend
|
||
|
||
;
|
||
; 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
|
||
|
||
call print
|
||
db 'VMENUCK Version '
|
||
db (vers/10)+'0','.',(vers mod 10)+'0',0
|
||
|
||
lda fcb+1 ;get first char
|
||
cpi ' ' ;no file name?
|
||
jz help
|
||
cpi '/' ;option?
|
||
jnz start1
|
||
;
|
||
; Print Help Message
|
||
;
|
||
help:
|
||
call print
|
||
db cr,lf,'Syntax:'
|
||
db cr,lf,' VMENUCK dir:filename.typ <-- Check File'
|
||
db cr,lf,' VMENUCK dir:filename <-- Check filename.VMN'
|
||
db 0
|
||
ret
|
||
|
||
;
|
||
; Begin serious processing -- locate the file pted to by HL
|
||
;
|
||
start1:
|
||
lxi d,fcb ;pt to FCB
|
||
call z3log ;log into indicated FCB
|
||
|
||
;
|
||
; Set File Type to MNU if not specified
|
||
;
|
||
start2:
|
||
lxi h,fcb+9 ;pt to file type
|
||
mov a,m ;get first char
|
||
cpi ' ' ;set type if <SP>
|
||
jnz start3
|
||
push b ;save BC
|
||
lxi d,mnutyp ;set type to MNU
|
||
xchg
|
||
mvi b,3 ;3 bytes
|
||
call moveb
|
||
pop b ;get BC
|
||
;
|
||
; Try to Open the File
|
||
;
|
||
start3:
|
||
lxi d,fcb ;prepare to open file
|
||
xra a ;A=0 to select current disk
|
||
stax d
|
||
call f$open ;open file
|
||
jz readfile ;read in file if OK
|
||
call print
|
||
db cr,lf,' File Not Found',0
|
||
ret
|
||
;
|
||
; Read in File
|
||
;
|
||
readfile:
|
||
call codend ;get address of first block
|
||
readloop:
|
||
lxi d,fcb ;read block
|
||
call f$read ;do it
|
||
ora a ;check for error
|
||
jnz readdone
|
||
lxi d,tbuff ;pt to block just read in
|
||
mvi b,128 ;128 bytes
|
||
readmove:
|
||
ldax d ;get byte
|
||
ani 7fh ;mask MSB
|
||
mov m,a ;put byte
|
||
inx h ;pt to next
|
||
inx d
|
||
dcr b ;count down
|
||
jnz readmove
|
||
xchg ;DE pts to next block
|
||
lhld bentry+1 ;get address of BDOS
|
||
mov a,h ;check for possible overflow
|
||
sui 10 ;10 pages below BDOS is limit
|
||
cmp d ;within range?
|
||
xchg ;HL pts to next block
|
||
jnc readloop ;continue read if within range
|
||
call print
|
||
db cr,lf,' TPA Overflow -- VMENU File is Too Big',0
|
||
ret
|
||
;
|
||
; Read is Done -- Store Ending ^Z and Set Initial Values
|
||
;
|
||
readdone:
|
||
mvi m,EOF ;Store ^Z to ensure EOF
|
||
lxi d,fcb ;Close File
|
||
call f$close
|
||
mvi a,0ffh ;A = -1
|
||
sta menunum ;set menu number
|
||
sta maxnum ;set max number of all menus
|
||
lxi h,0 ;HL=0
|
||
shld errors ;Set Error Count to 0
|
||
inx h ;HL=1
|
||
shld linenum ;Set Line Number to 1
|
||
;
|
||
; Count Number of Menus
|
||
;
|
||
call codend ;Pt to First Byte
|
||
mov a,m ;get first byte
|
||
;
|
||
; Skip to Beginning of Menu Display
|
||
;
|
||
mdskip:
|
||
cpi EOF ;EOF?
|
||
jz mdone
|
||
cpi MINDIC ;beginning of display?
|
||
jz mcgo ;now go skip commands
|
||
call lskip ;skip to next line
|
||
jmp mdskip
|
||
mcgo:
|
||
inx h ;pt to char after MINDIC
|
||
mov a,m ;another MINDIC?
|
||
cpi MINDIC
|
||
jz mdone ;done if 2 in a row
|
||
lda maxnum ;get menu number count
|
||
inr a ;found another one
|
||
sta maxnum
|
||
mcskip:
|
||
call lskip ;skip to next line
|
||
jz mdone ;done if premature EOF
|
||
cpi MINDIC ;end of display?
|
||
jnz mcskip
|
||
inx h ;pt to char after MINDIC
|
||
mov a,m ;get it
|
||
jmp mdskip
|
||
;
|
||
; Check for Valid First Character
|
||
;
|
||
mdone:
|
||
call print
|
||
db cr,lf,'VMenu Syntax Check on ',0
|
||
call retud ;get dir
|
||
mov a,b ;get disk
|
||
adi 'A'
|
||
call cout
|
||
mov a,c ;get user
|
||
call pafdc
|
||
mvi a,':'
|
||
call cout
|
||
lxi d,fcb+1 ;pt to FCB
|
||
call pfn2
|
||
call print ;Print Header
|
||
db cr,lf
|
||
db cr,lf,' Line Comment/Error Message'
|
||
db cr,lf,' ---- ---------------------',0
|
||
|
||
xra a ;set no global option
|
||
sta gopt
|
||
call codend ;get address of first byte
|
||
mov a,m ;get first char
|
||
cpi GOPTION ;global options?
|
||
jnz newmenu ;process globals
|
||
mvi a,0ffh ;set global option
|
||
sta gopt
|
||
call lprint
|
||
db '** Global Options Detected **',0
|
||
call optchk ;check options
|
||
xra a ;set no global option
|
||
sta gopt
|
||
call nxtline ;advance to next line
|
||
;
|
||
; This is the main entry point for processing a menu
|
||
;
|
||
newmenu:
|
||
mov a,m ;get Menu Indicator
|
||
cpi MINDIC ;must be MINDIC
|
||
jz nm1
|
||
call newerr ;add to error count
|
||
call lprint
|
||
db ' New Menu Expected, But ',MINDIC,' NOT Found -- '
|
||
db 'Aborting',0
|
||
jmp errxit
|
||
;
|
||
; Print that we have a new menu
|
||
;
|
||
nm1:
|
||
call lprint
|
||
db '** Menu Number ',0
|
||
lda menunum ;increment menu number
|
||
inr a
|
||
sta menunum
|
||
call padc
|
||
call optchk ;check options
|
||
;
|
||
; Skip Thru Display
|
||
;
|
||
nm2:
|
||
call nxtline ;skip to next line
|
||
jnz nm2a ;continue if no EOF
|
||
earlyeof:
|
||
call newerr ;add to error count
|
||
call lprint
|
||
db ' Premature EOF Encountered',0
|
||
jmp errxit
|
||
nm2a:
|
||
cpi MINDIC ;Menu Indicator?
|
||
jnz nm2 ;Continue
|
||
;
|
||
; Move Thru Menu Commands
|
||
;
|
||
nm3:
|
||
call mcmd1 ;check Menu Command Line
|
||
jz earlyeof
|
||
call lcheck ;check line
|
||
cpi MINDIC ;check for menu indicator
|
||
jnz nm3 ;continue until menu indicator encountered
|
||
inx h ;check for 2 indicators in a row for end
|
||
mov a,m ;get 2nd char
|
||
dcx h ;back up in case it is not
|
||
cpi MINDIC ;2 in a row?
|
||
jnz newmenu ;process as new menu if not
|
||
errxit:
|
||
call lprint
|
||
db '** End of Menu Check **',cr,lf,' ',0
|
||
lhld errors ;check error count
|
||
mov a,h ;check for Zero
|
||
ora l
|
||
jnz err1
|
||
call print
|
||
db 'No',0
|
||
jmp err2
|
||
err1:
|
||
call phldc ;print as decimal
|
||
err2:
|
||
call print
|
||
db ' Errors Detected',0
|
||
ret
|
||
|
||
;
|
||
; Utilities
|
||
;
|
||
|
||
;
|
||
; LPRINT -- Print "Line # "+text
|
||
;
|
||
lprint:
|
||
call crlf ;new line
|
||
push h ;save HL
|
||
lhld linenum ;get line number
|
||
call phldc ;print as decimal
|
||
pop h ;restore HL
|
||
mvi a,' ' ;print <sp>
|
||
call cout
|
||
jmp print ;print text
|
||
;
|
||
; NXTLINE -- Advance to next line, check for EOF, and increment Line Number
|
||
; LSKIP -- Advance to next line and check for EOF
|
||
; Return with HL pting to first char of next line and Z Set if EOF
|
||
;
|
||
nxtline:
|
||
push h ;increment line count
|
||
lhld linenum ;add 1
|
||
inx h
|
||
shld linenum
|
||
pop h ;fall thru to skipping
|
||
lskip:
|
||
mov a,m ;get char
|
||
cpi EOF ;EOF?
|
||
rz
|
||
inx h ;pt to next
|
||
cpi lf ;line feed?
|
||
jnz lskip ;continue if not
|
||
mov a,m ;get first char of next line
|
||
cpi EOF ;check for EOF
|
||
ret
|
||
;
|
||
; MCMD1 -- Check Menu Line, check for EOF, and increment Line Number
|
||
; Return with HL pting to first char of next line and Z Set if EOF
|
||
;
|
||
mcmd1:
|
||
mov a,m ;get char
|
||
cpi EOF ;EOF?
|
||
jz mcmdx
|
||
inx h ;pt to next
|
||
cpi VARFLAG ;variable?
|
||
jz mcmd2
|
||
cpi lf ;line feed?
|
||
jnz mcmd1 ;continue if not
|
||
mcmdx:
|
||
push h ;increment line count
|
||
lhld linenum ;add 1
|
||
inx h
|
||
shld linenum
|
||
pop h ;fall thru to skipping
|
||
mov a,m ;get first char of next line
|
||
cpi EOF ;check for EOF
|
||
ret
|
||
;
|
||
; Check Variable
|
||
;
|
||
mcmd2:
|
||
mov a,m ;get char
|
||
ani 7fh ;mask
|
||
call caps ;capitalize
|
||
inx h ;pt to next
|
||
cpi VARFLAG ;OK if double VARFLAG
|
||
jz mcmd1
|
||
cpi 'D' ;OK if D
|
||
jz mcmd1
|
||
cpi 'U' ;OK if U
|
||
jz mcmd1
|
||
cpi 'F' ;filename.typ?
|
||
jz mcmd3
|
||
cpi 'N' ;filename?
|
||
jz mcmd3
|
||
cpi 'T' ;filetype?
|
||
jz mcmd3
|
||
cpi 'P' ;pointed-to file?
|
||
jz mcmd6
|
||
;
|
||
; Invalid Variable
|
||
;
|
||
dcx h ;pt to previous (bad char)
|
||
push psw ;save char
|
||
call lprint
|
||
db ' Variable Error (Not $, D, U, F, N, or T) - ',0
|
||
pop psw ;get char
|
||
call cout ;print it
|
||
call newerr ;increment error count
|
||
jmp mcmd1
|
||
;
|
||
; Digit from 1 to 4 should follow
|
||
;
|
||
mcmd3:
|
||
mov a,m ;get next char
|
||
inx h ;pt to next
|
||
ani 7fh ;mask and cap
|
||
call caps
|
||
cpi '1' ;must be from 1 to 4
|
||
jc mcmd4
|
||
cpi '5'
|
||
jc mcmd1
|
||
;
|
||
; Invalid Digit
|
||
;
|
||
mcmd4:
|
||
push psw
|
||
call lprint
|
||
db ' Invalid Digit for F, N, or T Variable (not 1-4) - ',0
|
||
mcmd5:
|
||
pop psw
|
||
dcx h ;pt to invalid char
|
||
call cout
|
||
call newerr ;increment error count
|
||
jmp mcmd1
|
||
|
||
;
|
||
; Check for Pointed to File
|
||
;
|
||
mcmd6:
|
||
mov a,m ;get next char
|
||
inx h ;pt to next
|
||
ani 7fh ;mask
|
||
call caps
|
||
cpi 'F'
|
||
jz mcmd1
|
||
cpi 'N'
|
||
jz mcmd1
|
||
cpi 'T'
|
||
jz mcmd1
|
||
push psw ;save char
|
||
call lprint
|
||
db ' Invalid Pointed-to File Option (not F, N, or T) - ',0
|
||
jmp mcmd5 ;process error and back up ptr
|
||
|
||
;
|
||
; OPTCHK -- Check Line Pted to by HL for Valid GOPTION and MINDIC options
|
||
; Do Not Affect HL
|
||
; Print Error Message and Character if Invalid Option Found
|
||
;
|
||
optchk:
|
||
push h ;save HL
|
||
push b
|
||
inx h ;skip indicator
|
||
optclp:
|
||
mov a,m ;get char
|
||
call caps ;capitalize
|
||
inx h ;pt to next
|
||
cpi cr ;EOL?
|
||
jz optcdn
|
||
mov b,a ;char in B
|
||
cpi XOPTION ;only exit option allowed
|
||
jz optclp
|
||
call newerr ;increment error count
|
||
call lprint
|
||
db ' Invalid Option: ',0
|
||
mov a,b ;get char
|
||
call cout ;print char
|
||
jmp optclp
|
||
optcdn:
|
||
pop b
|
||
pop h ;restore ptr
|
||
ret
|
||
;
|
||
; Increment Error Count
|
||
;
|
||
newerr:
|
||
push h ;save HL
|
||
lhld errors ;increment error count
|
||
inx h
|
||
shld errors
|
||
pop h ;restore HL
|
||
ret
|
||
;
|
||
; Check Line, especially looking for Menu Jump
|
||
;
|
||
lcheck:
|
||
push h ;save ptr to first char
|
||
inx h ;pt to 2nd char
|
||
mov a,m ;get it
|
||
cpi MCMD ;menu jump?
|
||
jnz lchk1
|
||
inx h ;pt to menu number
|
||
call eval10 ;convert to binary in DE
|
||
mov a,d ;D must be 0
|
||
ora a ;check
|
||
jz lchk0
|
||
lchker:
|
||
call newerr ;increment error count
|
||
call lprint
|
||
db ' Menu Number Out of Range',0
|
||
jmp lchk1
|
||
lchk0:
|
||
lda maxnum ;get max menu number
|
||
cmp e ;check for range
|
||
jc lchker
|
||
lchk1:
|
||
pop h ;restore ptr
|
||
mov a,m ;get first char in line
|
||
ret
|
||
;
|
||
; Skip HL over Blanks
|
||
;
|
||
sblank:
|
||
mov a,m ;get char
|
||
inx h ;pt to next
|
||
cpi ' ' ;blank?
|
||
jz sblank ;continue skipping
|
||
dcx h ;pt to non-blank
|
||
ret
|
||
|
||
;
|
||
; Buffers
|
||
;
|
||
mnutyp:
|
||
db 'VMN'
|
||
errors:
|
||
ds 2 ;error count
|
||
linenum:
|
||
ds 2 ;current line number
|
||
menunum:
|
||
ds 1 ;current menu number
|
||
maxnum:
|
||
ds 1 ;max menu number
|
||
gopt:
|
||
ds 1 ;global option flag
|
||
|
||
end
|
||
|