; ; 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. ; ; ; MENU Constants ; MCMD EQU ':' ;Menu Jump Command RSM EQU '$' ;System Menu Indic MINDIC EQU '#' ;Menu Indic GOPTION EQU '-' ;Global Option Indic COPTION EQU 'C' ;Option chars DOPTION EQU 'D' POPTION EQU 'P' XOPTION EQU 'X' ; ; 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 ; ; SYSLIB Externals ; ext caps ext crlf ext eval10 ext f$open ext f$close ext f$read ext print ext zgpins ext zfname ext retud ext logud ext moveb ext cout ext phldc ext padc ext codend ; ; 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 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 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 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 end