;
; PROGRAM: MCHECK
; AUTHOR: RICHARD CONN
; VERSION: 1.1
; DATE: 6 Jan 83
; PREVIOUS VERSIONS: 1.0 (12 Dec 82)
;
VERS EQU 11 ;VERSION NUMBER
;
; 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.
;
;
; MCHECK is used to check the syntax of a MENU.CPR file for the ZCPR2
; menu processor, MENU. MENU was optimized for size and runtime speed, and
; I tried to keep the size under 2K (and succeeded, for that matter). In
; keeping MENU small, the error diagnostics it gives are quite limited, with
; a variety of errors producing the message "Str Err" for MENU.CPR
; structure error.
;
; MCHECK is intended to be used to check the syntax and other features
; of a user's MENU.CPR before allowing MENU to run with it. In this way,
; many errors may be caught before the MENU.CPR file comes into common use,
; and there is plenty of space for informative diagnostics.
;
;
;******************************************************************
;
; 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 000H ; MAX USER/DISK?
UDREQD:
DB 000H ; ALLOW USER/DISK CHANGE?
PUREQD:
DB 000H ; PRIVILEGED USER?
CDREQD:
DB 000H ; 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 ;place zero at end of input buffer
mov a,m ;get char count
inx h ;pt to first char
push h ;save ptr
add l
mov l,a
mov a,h
aci 0
mov h,a
mvi m,0 ;store ending zero
pop h ;pt to first char
call sblank ;skip over blanks
lxi d,inbuf ;copy into input line buffer
push d ;save ptr to first char
start0:
mov a,m ;get byte
stax d ;put it
inx h ;pt to next
inx d
ora a ;end of string?
jnz start0
call print
db 'MCHECK Version '
db (vers/10)+'0','.',(vers mod 10)+'0',0
pop h ;HL pts to first non-blank char
mov a,m ;get it
ora a ;EOL?
jz help
cpi '/' ;option?
jnz start1
;
; Print Help Message
;
help:
call print
db cr,lf,' MCHECK is used to perform a syntax check on a MENU.CPR'
db cr,lf,'file. It is invoked with the following forms:'
db cr,lf,' MCHECK or MCHECK // <-- Print this Help'
db cr,lf,' MCHECK dir:filename.typ <-- Check File'
db cr,lf,' MCHECK dir:filename <-- Check filename.CPR'
db cr,lf,0
ret
;
; Begin serious processing -- locate the file pted to by HL
;
start1:
call retud ;get current user/disk
mov a,b ;save disk
sta cdisk
mov a,c ;save user
sta cuser
lxi d,mfcb ;pt to FCB
call zfname ;look for file
jnz start2
call print
db cr,lf,'Error in Disk or User Number -- Aborting',0
ret
;
; Set File Type to CPR if not specified
;
start2:
lxi h,mtyp ;pt to file type
mov a,m ;get first char
cpi ' ' ;set type if <SP>
jnz start3
push b ;save BC
lxi d,cprtyp ;set type to CPR
xchg
mvi b,3 ;3 bytes
call moveb
pop b ;get BC
;
; Set User and Disk in C and B
;
start3:
mvi a,0ffh ;get current disk indicator
cmp b ;B=indicator?
jnz start4
lda cdisk ;select current disk
mov b,a ;... in B
inr b ;in range 1-16
start4:
dcr b ;adjust disk to 0-15
mvi a,0ffh ;get current user indicator
cmp c ;C=indicator?
jz start5
mvi a,'?' ;if C=All Users, default to current
cmp c
jnz start6
start5:
lda cuser ;select current user
mov c,a
start6:
call logud ;log in user and disk
lxi d,mfcb ;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,'Error in Opening File -- Aborting',0
ret
;
; Read in File
;
readfile:
call codend ;get address of first block
readloop:
lxi d,mfcb ;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 -- MENU.CPR File is Too Big -- Aborting',0
ret
;
; Read is Done -- Store Ending ^Z and Set Initial Values
;
readdone:
mvi m,EOF ;Store ^Z to ensure EOF
lxi d,mfcb ;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 ;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 'Error -- 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 'Error -- Premature EOF Encountered -- Aborting',0
jmp errxit
nm2a:
cpi MINDIC ;Menu Indicator?
jnz nm2 ;Continue
;
; Move Thru Menu Commands
;
nm3:
call nxtline ;skip to next 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
;
; 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
lda gopt ;global option?
ora a ;0=no
mov a,b ;get char
jnz optcl1 ;skip RSM test if it is global
cpi RSM ;System Menu?
jz optclp
optcl1:
cpi COPTION ;check options
jz optclp
cpi DOPTION
jz optclp
cpi POPTION
jz optclp
cpi XOPTION
jz optclp
call newerr ;increment error count
call lprint
db 'Error -- 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 'Error -- 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
inbuf:
ds 250 ;input line buffer
cdisk:
ds 1 ;current disk
cuser:
ds 1 ;current user
mfcb:
db 0
ds 8 ;file name
mtyp:
ds 3 ;file type
ds 4
ds 16
ds 4
cprtyp:
db 'CPR'
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