; ; PROGRAM: ZEX ; AUTHOR: RICHARD CONN (DERIVED FROM EX, WHICH WAS WRITTEN BY SOMEONE ELSE) ; VERSION: 3.1 ; DATE: 24 Oct 84 ; PREVIOUS VERSIONS: 3.0 (8 Mar 84) ; VERS EQU 31 Z3ENV EQU 0F400H ; ; ZEX 3.1 -- Richard Conn ; Does not require to be reassembled for a target system; Z3INS ; installation is sufficient ; ZEX 3.0 -- Derived from ZEX 1.3 for ZCPR3 by Richard Conn ; Extensions to ZEX 1.3 are: ; ZCPR3 Message Passing Employed ; ZCPR3 Structure ; Omitted Parameters Allowed ; Print Suppression During FALSE IFs (^&) ; ; ZEX 1.0 -- EX 1.2.1 implemented for ZCPR2 by Richard Conn ; DATE: 12 NOV 82 ; Extensions to EX are: ; Multiple command buffer is preserved, and any commands ; following the ZEX command are executed after ; the ZEX command file is completed (ZEX T;DIR ; will execute commands in T.SUB and then run DIR) ; ZCPR3 Search Path is following when looking for the ; file specified to ZEX ; Command File Type may be SUB or ZEX ; Added ^* form to simply ring the bell ; Added ^/ form to act like ^? but ring bell periodically ; Added ^" form to allow user input in the middle of a ; command file operation ; Major rewrite of EX to improve readability and to impose ; a structured organization on the code for maintenance ; purposes ; Major change in the abort system so that the multiple command ; line buffer of ZCPR3 will be properly cleared on ; abort; without this change, ZEX would crash the system ; in attempting to abort out of the ^/ and ^? forms; ; EX will probably always crash a ZCPR3 system with ; multiple commands enabled if an abort from ^? is ; attempted ; ; EX12.ASM - An enhanced version of EXEC and EX. ; ; START 05-09-82 ; ; DATE 08-11-82 *LAST MAJOR CHANGE ; ; HISTORY: ; ; ZEX 1.0 11-12-82 modify for use under ZCPR2; main change is to place ; rest of multiple command line at end of SUB file ; ; 1.2.1 09-16-82 fix for MBASIC execution under EX 1.2 . ; ; 1.2 08-11-82 added '^:' EX runtime re-execute logic function, ; '^?' EX runtime wait for carriage return, ; logic to prevent input/EX buffer overlap, ; logic to insure (Xsub Already Present), ; logic to prevent EX runtime recursion loop, ; and prompt character logic [Larry Steeger] ; ; 1.1 08-06-82 added ';;' EX comment's support, ; '^.' print suppression function, ; '^<...^>' immediate display support, ; '^#' EX message suppression function, ; '^$' default parameter support, ; and '^|' cr,lf generation function [Larry Steeger] ; ; 1.0 08-03-82 corrected $^ error and ^ error [Larry Steeger] ; ; ? 06-19-82 added missing TRUE and FALSE equates [Ron Fowler] ; ; ? 05-17-82 corrected last cold boot no active message ; ; ; EX12.COM IS AN ENHANCEMENT OF EXEC.COM AND EX.COM ; ; OPTIONS: ; ; EX cr ; ; EX cr ; ; ^ WILL GIVE CONTROL CHARACTER ; ; | WILL BE CR ; ; ^| WILL BE CR,LF ; ; ^: WILL CAUSE ZEX TO RE-EXECUTE THE .SUB FILE FROM THE BEGINNING ; ; ^? WILL CAUSE ZEX TO WAIT FOR A CARRIAGE RETURN ; (^C WILL ABORT ZEX AT THIS POINT ALSO) ; ; ^/ WILL CAUSE ZEX TO RING THE BELL AND WAIT FOR A CARRIAGE RETURN ; (^C WILL ABORT ZEX AT THIS POINT ALSO) ; ; ^* WILL CAUSE ZEX TO RING THE BELL ; ; ^" WILL CAUSE ZEX TO STOP PROVIDING INPUT UNTIL THE ZCPR3 MESSAGE ; CONTROLLING ZEX IS CHANGED TO PERMIT CONTINUATION ; ; ^$ WILL CAUSE THE REST OF THE LINE TO BE TREATED AS A ; SET OF DEFAULT PARAMETERS SEPARATED BY BLANKS TO BE ; USED IF THE USER HAS NOT PROVIDED ONE ON ZEX'S COMMAND LINE. ; ; ^# WILL TOGGLE PRINT SUPPRESSION OF ZEX MESSAGES ; ; ^. WILL START PRINT SUPPRESSION OF ALL CHARACTERS ; FROM .SUB FILE UNTIL A SUBSEQUENT ^. IS ENCOUNTERED ; ; ^& WILL INSTRUCT ZEX TO SUPPRESS PRINT IF WITHIN A FALSE IF ; ; ;; WILL INDICATE THAT THE ;; AND ALL CHARACTERS FOLLOWING IT ; UNTIL A LF IS ENCOUNTERED ARE NOT INCLUDED IN ZEX'S ; TEXT BUFFER ; (I.E. A ZEX ONLY COMMENT) ; ; ^< WILL START IMMEDIATE DISPLAY OF CHARACTERS FROM ; THE .SUB FILE UNTIL ^> IS ENCOUNTERED ; (I.E. DISPLAY ONLY .SUB INPUT) ; ; $<1-9> WILL REPLACE PARAMETER<1-9> IN TEXT FROM THE COMMAND LINE ; ; $$ WILL GIVE $ ; ; $^ WILL GIVE ^ ; ; $| WILL GIVE | ; ; |,cr,lf,1ah will eat last from | to end of buffer ; ; ^C FROM CONSOLE WILL ABORT ZEX ; FALSE EQU 0 TRUE EQU NOT FALSE ; ; OFFSETS TO ZCPR3 ENVIRONMENT DESCRIPTOR ELEMENTS ; EPOFF EQU 9 ;EXTERNAL PATH DATA MCOFF EQU 24 ;COMMAND LINE DATA Z3MOFF EQU 34 ;MESSAGE BUFFER ; ; GENERAL EQUATES ; BELL EQU 7 CTRLZ EQU 1AH ;^Z DELAY EQU 6000H ;DELAY CONSTANT FOR TIMER LOOP BS EQU 'H'-'@' ;BACKSPACE CR EQU 0DH LF EQU 0AH ; ; ZEX MONITOR COMMAND BYTES ; PSUP EQU 80H ;^. PRINT SUPPRESS FLAG IMON EQU 81H ;^< IMMEDIATE MODE START IMOFF EQU 82H ;^> IMMEDIATE MODE STOP MSUP EQU 83H ;^# ZEX MESSAGE SUPPRESS FLAG CRWAIT EQU 84H ;^? ZEX RUNTIME WAIT FOR CR FLAG REXEC EQU 85H ;^: ZEX RUNTIME RE-EXECUTE FLAG CRBWAIT EQU 86H ;^/ ZEX RUNTIME RING BELL AND WAIT FOR CR FLAG RNG EQU 87H ;^* ZEX RUNTIME RING BELL UICH EQU 88H ;^" USER INPUT COMMAND CHAR SEQUENCE IPS EQU 89H ;^& FALSE IF PRINT SUPPRESS ; ; CP/M CONSTANTS ; WARM EQU 0 BDISK EQU 4 BDOS EQU 5 DFCB EQU 5CH BUFF EQU 80H ; ; NOTE: ZEX30.LIB IS CREATED BY THE ZEX30.ZEX GENERATION PROCESS ; MACLIB ZEX30 ; $-PRINT IF ZEXBASE $+PRINT ; ; START OF ZEX INITIATOR CODE SEGMENT ; ORG 100H ; ; 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 z3init ;initialize the ZCPR3 Env JMP START0 ; ; INITIAL COMMAND LINE AREA ; DB 0FFH ;SIZE OF COMMAND LINE DBUFF EQU $ DB 0FFH ;SIZE OF BUFFER DS 100H ;SPACE FOR COMMAND LINE ; ; START OF ZEX ; START0: NOP ;REPLACED WITH RET TO PREVENT REENTRY LDA DFCB+1 ;CHECK FOR HELP REQUEST CPI '/' ;HELP? JZ HELP LXI H,0 DAD SP SHLD CCPSTK ;CCP STACK PTR LXI SP,CCPSTK ;USER STACK AREA MVI A,0C9H ; (8080 RET) STA START ;PREVENT RE-ENTRANCE BY ZCPR LXI H,BUFF ;COPY INPUT LINE INTO DBUFF LXI D,DBUFF MVI B,128 ;SIZE OF BUFFER CALL MOVE LXI D,SIGNON ;LOGO CALL PRINT CALL ZEXACTV ;CHECK FOR RECURSION CALL ZRELOC ;RELOCATE ZEX MODULE CALL ZPARMS ;EXTRACT PARAMETERS FROM COMMAND LINE LDA DFCB+1 ;CHECK TO SEE IF SUB FILE PRESENT CPI ' ' ;=NO PUSH PSW ;SAVE FLAG CNZ OPENSB ;OPEN AND LOAD ZEX FILE IF PRESENT OR ABORT POP PSW ;GET FLAG CZ INPUTSB ;INPUT COMMANDS FROM USER ; ; HL NOW POINTS TO BYTE AFTER LOADED TEXT ; CALL ZMCL ;STORE REST OF MULTIPLE COMMAND LINE CALL ZLINES ;COPY AND PROCESS COMMAND LINES ; ; SET UP FOR ZEX EXECUTION AND RUN; HL PTS TO BOTTOM OF DATA AREA ; PUSH H ;SAVE PTR TO END OF DATA LHLD RELSTRT ;GET PTR TO START OF ZEX SHLD GOADR ;SET ADDRESS TO RUN TO DCX H ;PT TO START OF DATA AREA MVI B,09H ;MESSAGE OFFSET CALL MSHLD ;STORE HL THERE (NEXT CHAR FOR ZEX) MVI B,0BH ;MESSAGE OFFSET CALL MSHLD ;STORE HL THERE (FIRST CHAR FOR ZEX) MVI A,0FFH ;SET ZEX RUNNING FLAG MVI B,08H ;MESSAGE OFFSET CALL MSTA ;STORE A THERE (ZEX IS RUNNING) POP H ;HL IS PTR TO END OF DATA MOV M,A ;SET UP END OF DATA DCX H LDA BDOS+2 ;SET UP BDOS JUMP TO PROTECT DATA MOV M,A DCX H LDA BDOS+1 MOV M,A DCX H MVI M,JMP SHLD BDOS+1 ;SET NEW BDOS ADDRESS LXI H,0 ;ASSUME NO MULTIPLE COMMANDS LDA MCAVAIL ;GET FLAG ORA A ;0=NONE JZ GOTOZEX ;NO MULTIPLE COMMANDS, SO BC=0 LHLD MCADR ;GET ADDRESS OF MULTIPLE COMMAND BUFFER ; ; ZEX MONITOR ENTRY PARAMETERS -- ; HL ADDRESS OF MULTIPLE COMMAND BUFFER OR 0 IF NONE ; GOTOZEX: XCHG ;SAVE HL LHLD Z3MSGA ;GET ADDRESS OF MESSAGES ... XCHG ; ... IN DE GOADR EQU $+1 JMP $ ; ; INIT ZCPR3 ENVIRONMENT ; Z3INIT: PUSH H ;SAVE PTR TO ENVIRONMENT PUSH H LXI D,Z3MOFF ;OFFSET TO MESSAGE BUFFER DAD D MOV A,M ;GET LOW INX H MOV H,M ;GET HIGH MOV L,A ;HL IS ADDRESS OF MESSAGES SHLD Z3MSGA ;SAVE ADDRESS POP H LXI D,MCOFF ;OFFSET TO CL DATA DAD D MOV E,M ;GET CL ADDRESS INX H MOV D,M INX H ;GET CL SIZE MOV A,M ORA D ;IF ALL THREE VALUES ARE 0, THEN NO COMMAND LINE ORA E STA MCAVAIL ;SET AVAILABLE FLAG XCHG ;HL PTS TO CL SHLD MCADR POP H ;GET PTR TO ENVIRONMENT LXI D,EPOFF ;OFFSET TO EXTERNAL PATH DATA DAD D MOV E,M ;GET EXTERNAL PATH ADDRESS INX H MOV D,M MOV A,D ;CHECK FOR ANY ORA E STA EPAVAIL ;SET AVAILABLE FLAG XCHG SHLD EPADR ;SET ADDRESS RET ; ; Z3INIT BUFFERS ; INTPATH: ;INTERNAL PATH DB 1,0 ;DISK A, USER 0 DB 0,0 ;END OF PATH Z3MSGA: ;ADDRESS OF MESSAGES DW 0 MCAVAIL: ;MULTIPLE COMMAND LINE DATA DB 0 MCADR: DW 0 EPAVAIL: ;EXTERNAL PATH DATA DB 0 EPADR: DW 0 ; ; PRINT HELP MESSAGE FOR ZEX ; HELP: LXI D,SIGNON ;PRINT BANNER CALL PRINT LXI H,HMSG ;PRINT MESSAGE CALL HPRINT MVI C,1 ;GET CHAR CALL BDOS CPI 'C'-'@' ;^C? RZ LXI D,CRLFS CALL PRINT LXI D,SIGNON CALL PRINT LXI H,HMSG1 HPRINT: MOV A,M ;GET CHAR ORA A ;DONE? RZ INX H ;PT TO NEXT PUSH H ;SAVE PTR MOV E,A ;CHAR IN E MVI C,2 ;CONSOLE OUTPUT CALL BDOS POP H ;GET PTR JMP HPRINT HMSG: DB CR,LF,'ZEX Syntax:' DB CR,LF,' ZEX ' DB CR,LF,'or' DB CR,LF,' ZEX' DB CR,LF DB CR,LF,'The first form executes the indicated command file' DB CR,LF,'( may be of type ZEX or SUB, and if a ZEX and' DB CR,LF,'SUB both exist, the ZEX file is used), passing to it' DB CR,LF,'the parameters, similar to the way SUBMIT is used.' DB CR,LF DB CR,LF,'The second form allows the user to enter commands.' DB CR,LF,'ZEX presents the user with a prompt like "n:", where' DB CR,LF,'n is a line number, and the user may type in a command' DB CR,LF,'line. Input is terminated by simply striking the' DB CR,LF,'RETURN key (empty input line).' DB CR,LF DB CR,LF,'ZEX can be aborted by ^C from console.' DB CR,LF DB CR,LF,' Strike Any Key to Continue, ^C to Abort - ',0 HMSG1: DB CR,LF DB CR,LF,'ZEX supports an enhanced command processing facility' DB CR,LF,'which recognizes the following commands. These may be' DB CR,LF,'embedded in the text of the command file or user' DB CR,LF,'input and will be executed after processing begins.' DB CR,LF DB CR,LF,' Cmd Meaning Cmd Meaning' DB CR,LF,' | insert ^| insert ' DB CR,LF,' ^: rerun command file ^. suppress print of chars' DB CR,LF,' ^# toggle ZEX msgs ^$ define default params' DB CR,LF,' ^? wait for user ^/ ring and wait for ' DB CR,LF,' ^* ring bell ^" allow user input' DB CR,LF,' ^< display chars only ^> stop display' DB CR,LF,' ;; ZEX comment $n 1<=n<=9 for param' DB CR,LF,' $$ =$ $^ =^' DB CR,LF,' $| =| ^c insert ctrl char c' DB CR,LF,CR,LF,0 ; ; RELOCATE ZEX MODULE INTO HIGH MEMORY JUST BELOW ZCPR3 ; ZRELOC: LHLD RELOCL ;GET RELOC PROGRAM LENGTH MOV B,H ;BC=HL=RELOC PROGRAM LENGTH MOV C,L PUSH B ;SAVE LENGTH FOR FUTURE USE LHLD BDOS+1 ;GET BASE LXI D,-806H ;GET BEFORE CCP DAD D MOV A,L ;SUBTRACT RELOC LENGTH SUB C MOV E,A MOV A,H SBB B MOV D,A PUSH D ;SAVE NEW TOP/START TO MOVE TO LXI H,BEGREL ;START OF MOVE OMOVE: MOV A,B ORA C JZ MOVEND DCX B MOV A,M STAX D INX D INX H JMP OMOVE ; MOVEND: POP D ;GET START OF MOVED PROGRAM POP B ;LENGTH OF MOVE PROGRAM PUSH D ;SAVE PTR TO START OF PROGRAM PUSH H ;START OF BIT MAP MOV H,D ;MSB OFFSET MOV L,E ;LSB OFFSET OFFLUP: MOV A,B ;TEST LENGTH ORA C ;IF 0 JZ GOTO ;JUMP TO RELOCATED PROGRAM DCX B ;DECREMENT COUNT LDA COUNT INR A STA COUNT ANI 07H JNZ OFFBIT ;NO XTHL ;YES, GET BIT MAP MOV A,M ;GET NEXT BYTE INX H ;INCREMENT BIT MAP POINTER XTHL ;SAVE FOR LATER STA BITMAP ;KEEP BIT OFFSET OFFBIT: LDA BITMAP RAL ;TEST FOR OFFSET STA BITMAP ;SAVE NEW BYTE JNC NOFSET ;NO DCX D ;GET BACK TO LSB LDAX D ADD L STAX D INX D ;MSB LDAX D ;YES ADC H ;ADD IN OFFSET STAX D ;PUT IN MOVED PLACE NOFSET: INX D ;INCREMENT MOVED POINTER JMP OFFLUP ;CONTINUE WITH RELOCATE ; GOTO: POP D ;RESTORE STACK POP H ;PT TO FIRST BYTE OF PROGRAM SHLD RELSTRT ;SAVE PTR DCX H ;RELOCATE PROGRAM-1 SHLD OUTBUF ;SAVE PTR TO BYTE IN FRONT OF RELOCATED PROGRAM RET ; ; GET PARAMETERS FROM COMMAND LINE ; TERMINATE EACH PARAMETER WITH A BINARY ZERO, AND SET POINTERS ; TO EACH PARAMETER ; ZPARMS: LXI D,DBUFF ;TERMINATE COMMAND LINE WITH CR LDAX D ;GET CHAR COUNT INX D ;PT TO FIRST CHAR PUSH D MOV L,A ;HL = NUMBER OF CHARS IN LINE MVI H,0 DAD D ;PT TO AFTER LAST CHAR MVI M,CR ;STORE LXI H,PRMDMY ;START AT DUMMY PARAMETER FOR .SUB FILE SPEC PUSH H LXI B,PRMPNL+2 XRA A CALL FILL ;CLEAR PTR AREA POP H ;GET PTR TO POINTER FOR PARAMETER 0 POP D ;GET PTR TO FIRST CHAR IN LINE MVI A,(PRMPNL/2)+1 ;NUMBER OF PARAMETERS POSSIBLE, MAX STA PRMMAX ;HIGHEST PARAMETER # + 1 for .SUB SPEC ; ; PARAMETER EXTRACTION ROUTINE; HL PTS TO FIRST PARAM PTR, DE PTS TO LINE ; PARMS: MVI B,0 ;CLEAR PARAMETER COUNTER XCHG SHLD ERRLNE ;SAVE IN CASE OF ERROR XCHG ; PARMSL: LDAX D ;IGNORE LEADING SPACES INX D CPI CR JZ ENDLNE CPI ' ' JZ PARMSL DCX D ;BACK UP TO 1ST CHAR MOV M,E ;SAVE ADDRESS IN TABLE INX H MOV M,D INX H INR B ;COUNT+1 LDA PRMMAX CMP B JC PRMTOO ;TOO MANY ARGUMENTS ; ENDPRM: LDAX D ;GO TO END OF PARAMETER INX D CPI CR JZ ENDLNE CPI ' ' ;SKIP UNTIL JNZ ENDPRM XRA A ;A=0 TO TERMINATE PARAM DCX D ;PT TO FOLLOWING PARAM STAX D ;TERMINATE PARAMETER INX D ;PT TO CHAR AFTER JMP PARMSL ;IGNORE SPACES BETWEEN PARAMETERS ENDLNE: XRA A ;STORE ZERO AFTER LAST PARAMETER DCX D ;PT TO CR STAX D ;TERMINATE LAST PARAMETER INX D ;PT TO AFTER LAST PARAM MVI A,CR ;STORE ENDING CR STAX D RET ; ; INPUT COMMAND LINES FROM USER ; INPUTSB: LXI H,0 SHLD LINES ;START LINE COUNTER MVI A,0FFH ;SET BUFFER LENGTH STA DBUFF-1 LXI H,BEGREL ;SET UP OUTPUT BUFFER SHLD INBUF GETLIN: CALL CRLF LHLD LINES INX H SHLD LINES CALL DECOUT ;PRINT LINE # MVI E,':' ;GET PROMPT CALL OUTCHR MVI E,' ' CALL OUTCHR LXI D,DBUFF-1 MVI C,10 ;READ CONSOLE BUFFER CALL BDOS LXI D,DBUFF LDAX D ;GET LENGTH MOV B,A INX D LHLD INBUF ;GET INPUT POINTER ORA A ;SEE IF END RZ ;DONE WITH INPUT XCHG CALL MOVE ;MOVE TO INPUT BUFFER XCHG MVI M,CR INX H MVI M,LF INX H SHLD INBUF JMP GETLIN ; ; OPEN AND LOAD SUB FILE ; OPENSB: CALL PUTUD ;SAVE USER/DISK ; ; SET UP TO READ ZEX FILE ; LXI D,DFCB+9 LXI H,ZEXNAM ;MOVE 'SUB' TO DFCB FILE TYPE MVI B,3 CALL MOVE XRA A ;ZERO CR FIELD STA DFCB+32 LXI D,BUFF ;SET DMA ADDRESS MVI C,26 ;SET DMA CALL BDOS LXI D,DFCB LXI H,INTPATH ;PT TO INTERNAL PATH LDA EPAVAIL ;EXTERNAL PATHS AVAILABLE? ORA A ;0=NO JZ OSB1 ;USE INTERNAL PATH LHLD EPADR ;PT TO EXTERNAL PATH OSB1: PUSH H ;SAVE PATH PTR CALL FNDFILE ;LOOK FOR FILE ALONG PATH AND SAY IF IT IS FOUND POP H ;GET PATH PTR JNZ READSB ; ; ZEX FILE NOT FOUND -- SET UP TO READ SUB FILE ; PUSH H ;SAVE PATH PTR CALL GETUD ;RESTORE USER/DISK LXI D,DFCB+9 ;SET TYPE TO SUB LXI H,SUBNAM MVI B,3 CALL MOVE XRA A ;ZERO CR FIELD STA DFCB+32 POP H ;PT TO PATH LXI D,DFCB ;PT TO FCB CALL FNDFILE ;LOOK FOR FILE JNZ READSB RSBERR: CALL GETUD ;RESTORE USER/DISK LXI H,NOSBF2 LXI D,DFCB+1 MVI B,8 ;NAME LENGTH CALL MOVEFN ;MOVE FILE NAME MVI B,3 ;TYPE LENGTH MVI M,'.' INX H LXI D,DFCB+9;FILE TYPE POINTER CALL MOVEFN ;MOVE FILE TYPE MVI M,'$' ;END TERMINATER JMP NOSUB * * FNDFILE -- LOOK FOR FILE ALONG ZCPR3 PATH * INPUT PARAMETERS: HL = BASE ADDRESS OF PATH, DE = PTR TO FCB OF FILE * OUTPUT PARAMETERS: A=0 AND ZERO FLAG SET IF NOT FOUND, NZ IF FOUND * FNDFILE: SHLD PATH ;SAVE PATH BASE ADDRESS MVI C,17 ;SEARCH FOR FIRST CALL BENTRY ;LOOK FOR FILE INR A ;SET FLAG JNZ FF5 ;FOUND IT -- RETURN FOUND FLAG XCHG ;HL=FCB PTR SHLD FCBPTR ;SAVE IT LHLD PATH ;PT TO PATH FOR FAILURE POSSIBILITY MVI C,32 ;GET CURRENT USER MVI E,0FFH CALL BENTRY STA TMPUSR ;SAVE IT FOR LATER ; ; MAIN SEARCH LOOP ; FF1: MOV A,M ;GET DRIVE ANI 7FH ;MASK MSB ORA A ;0=DONE=COMMAND NOT FOUND JNZ FF2 ;NO ERROR ABORT? ; ; FILE NOT FOUND ERROR ; XRA A ;ZERO FLAG MEANS NOT FOUND RET ; ; LOOK FOR COMMAND IN DIRECTORY PTED TO BY HL; DRIVE IN A ; FF2: MOV E,A ;DISK IN E CPI '$' ;CURRENT DISK? JNZ FF3 ;SKIP DEFAULT DRIVE SELECTION IF SO LDA BDISK ;GET DEFAULT USER/DISK ANI 0FH ;MASK FOR DEFAULT DISK INR A ;PREP FOR FOLLOWING DCR A MOV E,A ;DISK NUMBER IN E FF3: DCR E ;ADJUST PATH 1 TO 0 FOR A, ETC MVI C,14 ;SELECT DISK FCT CALL BENTRY ;SELECT DRIVE INX H ;PT TO USER NUMBER MOV A,M ;GET USER NUMBER ANI 7FH ;MASK OUT MSB INX H ;PT TO NEXT ENTRY IN PATH PUSH H ;SAVE PTR MOV E,A ;SAVE IN E CPI '$' ;MATCH? JNZ FF4 ;DO NOT SELECT CURRENT USER IF SO LDA TMPUSR ;GET ORIGINAL USER NUMBER MOV E,A ;SELECT USER FF4: MVI C,32 CALL BENTRY LHLD FCBPTR ;GET PTR TO FCB XCHG ;... IN DE MVI C,17 ;SEARCH FOR FIRST CALL BENTRY ;LOOK FOR FILE POP H ;GET PTR TO NEXT PATH ENTRY INR A ;SET FLAG JZ FF1 ;CONTINUE PATH SEARCH IF SEARCH FAILED ; ; FILE FOUND -- PERFORM SYSTEM TEST AND PROCEED IF APPROVED ; FF5: MVI A,0FFH ;SET OK RETURN ORA A RET ; ; BDOS ROUTINE ; BENTRY: PUSH H ;SAVE REGS PUSH D PUSH B CALL BDOS POP B ;GET REGS POP D POP H RET * BUFFERS FCBPTR: DS 2 ;POINTER TO FCB FOR FILE SEARCH TMPUSR: DS 1 ;CURRENT USER NUMBER PATH: DS 2 ;BASE ADDRESS OF PATH ; ; PUTUD -- SAVE AWAY CURRENT USER/DISK ; GETUD -- RESTORE CURRENT USER/DISK ; PUTUD: MVI E,0FFH ;GET CURRENT USER MVI C,32 ;BDOS CALL BDOS STA CUSER ;SAVE CURRENT USER AWAY MVI C,25 ;GET CURRENT DISK CALL BDOS STA CDISK RET GETUD: LDA CDISK ;GET CURRENT DISK MOV E,A ;... IN E MVI C,14 ;SELECT DISK CALL BDOS LDA CUSER ;GET CURRENT USER MOV E,A ;... IN E MVI C,32 ;SELECT USER CALL BDOS RET CDISK: DS 1 ;CURRENT DISK NUMBER CUSER: DS 1 ;CURRENT USER NUMBER ; ; OPEN AND READ SUB FILE ; READSB: MVI C,15 ;OPEN FILE CALL BDOS ;BDOS INR A ;ERROR? JZ RSBERR ; ; READ IN AND STORE SUB FILE ; READTX: LHLD INBUF ;GET PTR TO NEXT BYTE XCHG ;SET PTR IN DE LXI H,80H ;GET SECTOR OFFSET DAD D ;HL PTS TO FOLLOWING BLOCK TO BE READ, DE PTS TO SHLD INBUF ; BLOCK TO READ; SAVE PTR TO FOLLOWING BLOCK MVI C,26 ;SET DMA ADDRESS CALL BDOS LXI D,DFCB MVI C,20 ;READ SEQUENTIAL CALL BDOS ORA A JZ READTX ;READ COMPLETE .SUB FILE CALL GETUD ;RESTORE CURRENT USER/DISK LHLD INBUF ;MAKE SURE BUFFER'S TERMINATED LXI D,-100H ;PT TO FIRST BYTE OF LAST BLOCK READ DAD D MVI B,80H ;LOOK AT AT MOST 80H BYTES SKIP1A: MOV A,M ;GET BYTE CPI CTRLZ ;EOF? JZ SKIP1B INX H ;PT TO NEXT DCR B ;COUNT DOWN JNZ SKIP1A ; HL NOW POINTS TO AFTER LAST VALID CHAR IN FILE SKIP1B: SHLD INBUF ;SET PTR RET ;DONE WITH NO ERROR ; ; THIS PART OF THE CODE STORES THE REST OF THE COMMAND LINE AS PART OF THE ; COMMAND FILE FOR ZCPR3; ON ENTRY, HL PTS TO NEXT AVAILABLE BYTE ; ZMCL: XCHG ;BUFFER PTED TO BY DE LHLD MCADR ;GET BASE ADDRESS OF MULTIPLE COMMAND LINE MOV A,M ;GET LOW INX H MOV H,M ;GET HIGH MOV L,A ;HL PTS TO NEXT CHAR IN MULTIPLE COMMAND LINE XCHG ;DE PTS TO NEXT CHAR IN COMMAND LINE, HL PTS TO BUF END LDA MCAVAIL ;MULTIPLE COMMANDS ENABLED? ORA A ;0=NO JZ ENDSTR ;TERMINATE FILE; HL PTS TO NEXT BYTE LDAX D ;GET FIRST BYTE MOV B,A ;SAVE FIRST BYTE IN B XRA A ;A=0 STAX D ;CLEAR COMMAND LINE INX D ;PT TO NEXT BYTE MOV A,B ;GET FIRST BYTE CPI ';' ;SEPARATION CHAR? JNZ CMCMD1 ;PROCESS IF NOT ; ; LOOP TO STORE REST OF MULTIPLE COMMAND LINE INTO LOADED FILE ; CMCMD: LDAX D ;GET BYTE FROM LINE CMCMD1: ORA A ;EOL IF ZERO JZ CMEND ;READ IN FILE; HL PTS TO NEXT AVAILABLE BYTE MOV M,A ;STORE BYTE INX H ;PT TO NEXT INX D JMP CMCMD CMEND: MVI M,CR ;STORE INX H MVI M,LF INX H ;PT TO NEXT AVAILABLE BYTE ; ; MARK END OF BUFFER AND CONTINUE ; ENDSTR: MVI M,1AH ;EOF CHARACTER SHLD ENDBUF ;EOB ADDRESS MOV A,L SUI LOW BEGREL+1 ;SEE IF BUFFER'S EMPTY MOV A,H SBI HIGH BEGREL JC BUFLOW RET ; ; COPY AND PROCESS COMMAND LINES, PLACING FINAL COMMAND LINE FORM UNDER ZEX ; RETURN WITH HL PTING TO NEXT AVAILABLE BYTE IN MEMORY BUFFER UNDER ZEX ; ZLINES: XRA A STA IMFLG1 STA IMFLG2 STA PRTFLG STA OUTCNT LXI H,1 SHLD LINES ;SET LINE COUNT LHLD OUTBUF ;PT TO BYTE JUST BELOW LOADED ZEX SHLD OUTLNE SHLD BUFSTR LXI D,BEGREL ;PT TO FIRST BYTE OF COMMAND BUFFER ; ; MAIN COPY LOOP TO COPY BUFFER AT BEGREL TO JUST UNDER ZEX WITH PROCESSING ; MOVSTR: LDAX D ;GET NEXT COMMAND BYTE INX D ;PT TO FOLLOWING ANI 7FH ;MAKE SURE NO PARITY CPI LF ;NEW LINE? JNZ MOVST0 ; ; NEW LINE -- DON'T STORE AND INCREMENT LINE COUNT ; MOVSTX: CALL INCR ;INCREMENT LINE COUNT JMP MOVSTR ;CONTINUE ; ; BEGIN CHARACTER PROCESSING ; A CONTAINS CHAR, DE PTS TO BYTE AFTER CHAR, HL PTS TO NEXT BUFFER POS ; MOVST0: CPI 1AH ;END OF INPUT? RZ ;DONE IF SO CPI '|' ;CARRIAGE RETURN? JNZ MOVST1 ;NOPE ; ; PROCESS CARRIAGE RETURN FORM (|) ; PUSH D ;SAVE OLD POINTER INX D ;LOOK FOR EOF AFTER | (PT TO LF) INX D ;PT TO POSSIBLE EOF LDAX D ;GET PRESENT LOCATION+2 POP D ;GET OLD POINTER CPI 1AH ;END OF BUFFER RZ ;END, SO NO FOLLOWING MVI A,CR ;MAKE CHAR A CALL INCR ;INCREMENT LINES FOR ERRORS JMP MOVST4 ;STORE IN A ; ; CHECK FOR NON-CR FORMS ; AT THIS POINT, DE PTS TO NEXT CHAR IN LINE AND HL PTS TO NEXT ; BYTE IN BUFFER (MOVING DOWN) ; MOVST1: MOV C,A ;SAVE CHAR IN C LDA IMFLG1 CPI IMON ;IMMEDIATE MODE ON ? MOV A,C ;GET CHAR BACK JZ MOVST2 ;YES..SKIP ZEX COMMENT PROCESSING CPI ';' ;FIRST ';'? JZ EXCOMM ;PROCESS POSSIBLE ZEX COMMENT MOVST2: CPI '^' ;CONTROL CHAR? JZ MOVST5 ;CONVERT CONTROL CHARACTERS CPI '$' ;PARAMETER OR CONTROL CHAR? CZ GTPARM ;SUBSTITUTE COMMAND PARAMETER OR CONTROL CHAR. MOVST3: STA LCHR ;SAVE LAST CHAR ENTERED CPI CR ;=CR? JNZ MOVST4 MOV C,A ;SAVE CHAR TEMPORARILY LDA OUTCNT ;GET CHAR OUTPUT FLAG ORA A ;ANY CHAR? MOV A,C JZ MOVSTR ;NO..USE INPUT CR ONLY IF OTHER NON-CONTROL ; CHARACTERS IN CURRENT LINE ; PLACE CHAR IN BUFFER ; CHAR IN A, HL PTS TO BUFFER LOC ; MOVST4: CALL CHRSTR ;ADD TO BUFFER CALL CNTINC ;INCREMENT COUNT JMP MOVSTR ; ; PREFIX WAS AN UPARROW (^), SO PROCESS CONTROL CHARS ; MOVST5: CALL GETCMD ;VALIDATE CONTROL CHARACTERS CPI ':' JZ REXC ;RE-EXECUTE CPI '?' JZ GCRW ;CR WAIT CPI '/' JZ GCRBW ;RING BELL AND WAIT FOR CPI '"' JZ UISET ;USER INPUT CPI '*' JZ GRNG ;CONTINUALLY RING BELL WHILE WAITING FOR CPI '|' JZ GCRLF ;CR,LF GENERATION CPI '$' JZ PRMDEF ;DEFAULT PARAMETERS' LINE CPI '.' JZ PRTSUP ;PRINT SUPPRESS TOGGLE CPI '#' JZ MSGSUP ;MESSAGE SUPPRESS TOGGLE CPI '<' JZ IMPRTY ;IMMEDIATE MODE START CPI '>' JZ IMPRTN ;IMMEDIATE MODE STOP CPI '&' JZ IFPSUP ;PRINT SUPPRESS DURING FALSE IF JMP MOVST3 ;OTHER CONTROL CODES ; IFPSUP: MVI A,IPS ;CONVERT '^&' TO IF PRINT SUPPRESS FLAG JMP MOVST3 ; REXC: MVI A,REXEC ;CONVERT '^:' TO RE-EXECUTE FLAG JMP MOVST3 ; GCRW: MVI A,CRWAIT ;CONVERT '^?' TO CRWAIT FLAG JMP MOVST3 ; GCRBW: MVI A,CRBWAIT ;CONVERT '^/' TO CRBWAIT FLAG JMP MOVST3 ; ; ALLOW USER INPUT FROM NOW ON, BUT FIRST SKIP OUT REST OF LINE ; UISET: LDAX D ;GET NEXT CHAR ANI 7FH ;MASK IT CPI LF ;DONE? JZ UISET1 CPI 1AH ;EOF? JZ UISET1 INX D ;PT TO NEXT CHAR JMP UISET ;CONTINUE SKIPPING UISET1: MVI A,UICH ;CONTROL CHAR JMP MOVST3 ; GRNG: MVI A,RNG ;CONVERT '^*' TO RNG FLAG JMP MOVST3 ; GCRLF: MVI A,CR ;GENERATE CR & LF CALL CHRSTR MVI A,LF CALL CHRSTR STA LCHR JMP MOVSTR ; PRMDEF: PUSH H LXI H,PRMDFP PUSH H LXI B,PRMDFL XRA A CALL FILL ;CLEAR PTR TABLE POP H MVI A,PRMDFL/2 STA PRMMAX ;HIGHEST PARAMETER # CALL PARMS ;BUILD DEFAULT PARAMETERS PTRS POP H INX D ;SKIP CR MVI A,LF JMP MOVSTX ;CONTINUE AT EOL ; ; CHECK TO SEE IF PREVIOUS CHAR WAS ALSO A ; AND FLUSH AS ZEX COMMENT IF SO ; EXCOMM: PUSH H LXI H,LCHR ;PT TO PREVIOUS CHAR CMP M ; DOUBLE ;? MOV M,A ;STORE CURRENT CHAR AS PREVIOUS CHAR POP H JNZ MOVST3 ;NO...CONTINUE MOV C,A ;SAVE CHAR LDA PRTFLG CPI PSUP MOV A,C JZ MOVST3 ;PRINT SUPPRESS LDA IMFLG1 CPI IMON MOV A,C JZ MOVST3 ;IMMEDIATE MODE INX H ;YES..IGNORE PREVIOUS ; PUSH H LXI H,LCHR LDA OUTCNT DCR A ;DROP 1 CHAR. STA OUTCNT EXCOML: LDAX D ;IGNORE CHARACTERS UNTIL EOF OR LF INX D CPI 1AH ;EOF JZ EXCOMX CPI LF ;LINE FEED JNZ EXCOML MOV M,A LDA OUTCNT ORA A ;ANY CHAR. ON THIS LINE? JZ EXCOM2 ;NO...SKIP CR EXCOM1: POP H ;YES..FORCE CR MVI A,CR CALL CHRSTR MVI A,LF JMP MOVSTX ;CONTINUE ; EXCOM2: POP H MVI A,LF JMP MOVSTX ;CONTINUE ; EXCOMX: POP H RET ;RETURN TO MAIN FLOW, WITH HL PTING TO NEXT BYTE ; MSGSUP: MVI A,MSUP ;CONVERT '^#' TO MESSAGE SUPPRESS FLAG JMP MOVST3 ; PRTSUP: MVI A,PSUP ;CONVERT '^.' TO PRINT SUPPRESS FLAG PUSH H LXI H,PRTFLG CMP M ;ALREADY ON? JNZ PRTSST ;NO...SET FLAG XRA A ;YES..CLEAR FLAG PRTSST: MOV M,A ;SET/RESET FLAG POP H MVI A,PSUP JMP MOVST3 ; IMPRTY: MVI A,IMON ;CONVERT '^<' TO IMMEDIATE MODE START STA LCHR PUSH H LXI H,IMFLG1 CMP M ;ALREADY ON? POP H JZ MOVSTR ;YES.. STA IMFLG1 STA IMFLG2 JMP MOVST3 ;NO... ; IMPRTN: MVI A,IMOFF ;CONVERT '^>' TO IMMEDIATE MODE STOP STA LCHR PUSH H LXI H,IMFLG2 CMP M ;ALREADY OFF? POP H JZ MOVSTR ;YES.. STA IMFLG2 STA IMFLG1 JMP MOVST3 ;NO... ; ; PLACE CHAR IN BUFFER; A=CHAR, HL PTS TO BUFFER LOC ; CHRSTR: PUSH PSW ;CHECK FOR INPUT/ZEX BUFFER OVERLAP PUSH D PUSH H LHLD ENDBUF XCHG POP H MOV A,L CMP E JNZ CHRSTX ;LSB<> MOV A,H CMP D JZ OVERL ;MSB=, OVERLAP WILL OCCUR/ABORT ZEX ; ; ADD CHAR TO ZEX'S BUFFER ; CHRSTX: POP D ;ADD CHAR. TO ZEX'S BUFFER POP PSW MOV M,A ;STORE CHAR DCX H ;PT TO NEXT LOCATION (MOVING DOWN) RET ; ; CHECK TO SEE IF ZEX IS ALREADY ACTIVE, AND ABORT IF SO ; ZEXACTV: MVI B,08H ;MESSAGE OFFSET CALL MLDA ;GET VALUE IN A ORA A ;0 IF NO RZ LXI D,ZEXACT CALL PRINT ;ZEX ALREADY PRESENT ; ; ABORT AND RETURN TO ZCPR3 ; CCPRET: LHLD CCPSTK ;RESTORE STACK SPHL RET ;RETURN TO CCP ; ; ZCPR3 MESSAGE BUFFER ACCESS ROUTINES ; ; ; GETZ3MSG RETURNS HL POINTING TO DESIRED MESSAGE (OFFSET IN B) ; GETZ3MSG: PUSH D ;SAVE DE LHLD Z3MSGA ;GET ADDRESS OF MESSAGES MOV E,B ;GET OFFSET MVI D,0 DAD D ;HL PTS TO MESSAGE OF INTEREST POP D RET MSHLD: PUSH D ;SAVE DE XCHG CALL GETZ3MSG ;MAKE HL PT TO MESSAGE MOV M,E ;STORE LOW INX H MOV M,D ;STORE HIGH XCHG ;RESTORE HL POP D ;RESTORE DE RET MSTA: PUSH H ;SAVE HL CALL GETZ3MSG ;PT TO MESSAGE WITH HL MOV M,A ;STORE MESSAGE POP H RET MLDA: PUSH H ;SAVE HL CALL GETZ3MSG ;PT TO MESSAGE WITH HL MOV A,M ;GET MESSAGE POP H RET ; ; END OF Z3MSG ACCESS ROUTINES ; ; ; ERROR EXITS ; GETERR: LXI D,CMDER ;CONTROL CHARACTER INVALID CALL PRINT JMP LINE ;PRINT LINE # AND LINE AND EXIT ; NUMERR: LXI D,NONUM ;EXCESSIVE NUMBER CALL PRINT JMP LINE ;PRINT LINE # AND LINE AND EXIT ; PRMERR: LXI D,PMERR CALL PRINT JMP LINE ;PRINT LINE # AND LINE AND EXIT ; PRMTOO: LXI D,TOOARG;TOO MANY PARAMETER ARGUMENTS CALL PRINT LHLD ERRLNE CALL EPRT ;PRINT PARAMETER LINE JMP CCPRET ; BUFLOW: LXI D,BUFMTY;TEXT BUFFER EMPTY CALL PRINT JMP CCPRET ; NOSUB: LXI D,NOSBF1;.SUB FILE NOT FOUND CALL PRINT LXI D,NOTHER CALL PRINT JMP CCPRET ; OVERL: LXI D,OVERLP;INPUT/ZEX BUFFER OVERLAP CALL PRINT JMP LINE ; ; SUBROUTINES ; ; CONTROL CODES 0-1FH ; WITH SUPPORT FOR $ . # < > ; GETCMD: LDAX D ;GET NEXT CHARACTER INX D ;INCREMENT POINTER CPI '|' RZ ;CR,LF GENERATION CPI 'a'-1 ;LOWERCASE? JC GETUPR ;NOPE CPI 'z'+1 ;a-z? JNC GETERR ;NOPE sui 'a'-'A' ;GET TO UPPERCASE GETUPR: CPI '@' ;0-1FH CONTROL CODE? JNC GETCC CPI ':' RZ ;RE-EXECUTE CPI '?' RZ ;CR WAIT CPI '/' RZ ;CR WAIT AND RING BELL CPI '*' RZ ;RING BELL CPI '"' RZ ;USER INPUT CPI '$' RZ ;DEFAULT PARAMETERS' LINE CPI '.' RZ ;PRINT SUPPRESS TOGGLE CPI '#' RZ ;MESSAGE SUPPRESS TOGGLE CPI '<' RZ ;IMMEDIATE MODE START CPI '>' RZ ;IMMEDIATE MODE STOP CPI '&' RZ ;FALSE IF PRINT SUPPRESS JMP GETERR GETCC: SUI '@' ;GET CONTROL CODE RNC JMP GETERR ; ; EXTRACT PARAMETER ELEMENT WHOSE $N SPECIFICATION IS POINTED TO BY DE ; DE PTS TO CHAR AFTER THE $ ; BUFFER TO PLACE RESULTING PARAMETER IS PTED TO BY HL ; GTPARM: LDAX D ;GET CHAR AFTER THE $ INX D ;PT TO NEXT CHAR CPI '$' ;IF DOUBLE $, THEN STORE AS $ RZ CPI '^' ;UP ARROW RZ CPI '|' ;CARRIAGE RETURN RZ CPI '1' ;CHECK FOR VALID DIGIT (1-9) JC PRMERR CPI '9'+1 ;RANGE ERROR? JNC PRMERR SUI '1' ;GET ACTUAL # (ZERO RELATIVE) ADD A ;DOUBLE FOR OFFSET STA PRMNUM PUSH D ;SAVE PTRS PUSH H LXI H,PRMPNT ;PT TO PARAMETER PTR TABLE CPI PRMPNL-1 ;PARAMETER NUMBER WITHIN RANGE? JNC NOPARM ;> HIGHEST # MOV E,A MVI D,0 DAD D MOV E,M ;GET PARAMETER POINTER INX H MOV D,M POP H ;RESTORE PTR TO NEXT BYTE IN OUTPUT BUFFER BELOW ZEX MOV A,E ;ANY PARAM? ORA D JZ NOPARM ;NO PARAMETER PRESENT, TRY DEFAULTS ; ; MOVE PARAMETER PTED TO BY DE INTO BUFFER BELOW ZEX, 1ST BYTE PTED TO BY HL ; MOVPRM: LDAX D ;GET PARAMETER CHAR INX D ;PT TO NEXT ORA A ;DONE? JZ ENDPAR CALL CHRSTR ;STORE CHARS JMP MOVPRM ; ; PARAMETER PLACED IN MEMORY -- CONTINUE ; ENDPAR: POP D ;GET PTR TO NEXT CHAR IN LINE POP PSW ;CLEAR STACK JMP MOVSTR ;RESUME PROCESSING ; ; NO PARAMETER PTED TO ; NOPARM: PUSH H ;SAVE PTR TO NEXT BYTE IN BUFFER BELOW ZEX LXI H,PRMDFP ;TRY DEFAULT PARAMETERS LDA PRMNUM CPI PRMDFL-1 JNC NUMERR ;> HIGHEST # MOV E,A MVI D,0 DAD D MOV E,M ;GET PARAMETER POINTER INX H MOV D,M POP H MOV A,E ORA D JNZ MOVPRM ;MOVE PARAMETER INTO BUFFER JMP ENDPAR ;RESUME WITH NO PARAMETER ; MOVEFN: LDAX D CPI ' ' ;SEE IF SPACE RZ MOV M,A INX D ;INCREMENT POINTERS INX H DCR B JNZ MOVEFN RET ; ; INCREMENT LINE COUNT, AND AFFECT ONLY HL (MUST NOT AFFECT A) ; INCR: PUSH H ;SAVE OUTPUT POINTER LHLD LINES INX H ;INCREMENT LINE COUNTER SHLD LINES LXI H,LCHR ;CLEAR LAST CHARACTER MVI M,0 LXI H,OUTCNT;CLEAR CHARACTER COUNT MVI M,0 MOV L,E ;DE=HL MOV H,D SHLD BEGLIN POP H SHLD OUTLNE ;SAVE NEW OUTPUT LINE RET ; CNTINC: CPI ' ' ;CONTROL CHARACTER? RC ;YES.. CPI UICH ;USER INPUT CHAR? JZ CNTIN1 ANI 80H ;SPECIAL CONTROL? RNZ ;YES.. LDA PRTFLG CPI PSUP ;PRINT SUPPRESS FLAG? RZ ;YES.. LDA IMFLG1 CPI IMON ;IMMEDIATE MODE? RZ ;YES.. CNTIN1: LDA OUTCNT INR A STA OUTCNT RET ; PRINT: MVI C,9 ;PRINT STRING AT (DE) JMP BDOS ; EPRT: MOV A,M ;PRINT PARAMETER LINE AT (HL) CPI CR RZ CPI 0 JNZ EPRT1 MVI A,' ' EPRT1: INX H PUSH H MOV E,A MVI C,2 CALL BDOS POP H JMP EPRT ; CRLF: LXI D,CRLFS ;PRINT CR/LF JMP PRINT ; LINE: LXI D,LINEM ;PRINT LINE # AND LINE IN ERROR AND EXIT CALL PRINT LHLD LINES CALL DECOUT ;PRINT LINE # CALL CRLF LHLD BEGLIN PUSH H ;SAVE BEGGING POINTER FINDCR: MOV A,M INX H CPI 1AH ;END OF BUFFER JZ FOUND CPI CR JNZ FINDCR FOUND: MVI M,0 ;END OF STRING POP H ;START OF STRING CALL PRNTHL ;PRINT BAD LINE JMP CCPRET ;THATS ALL FOLKS ; PRNTHL: MOV A,M ;PRINT LINE AT (HL) INX H ORA A RZ MOV E,A PUSH H ;SAVE POINTER CALL OUTCHR POP H ;GET POINTER BACK JMP PRNTHL ; OUTCHR: MVI C,2 ;PRINT CHARACTER IN E JMP BDOS ; DECOUT: PUSH H ;PRINT DECIMAL LINE NUMBER PUSH D PUSH B LXI B,-10 ;RADIX FOR CONVERSION LXI D,-1 ;THIS BECOMES NO DIVIDED BY RADIX DX: DAD B ;SUBTRACT 10 INX D JC DX LXI B,10 DAD B ;ADD RADIX BACK IN ONCE XCHG MOV A,H ORA L ;TEST FOR ZERO CNZ DECOUT ;RECURSIVE CALL MOV A,E ADI '0' ;CONVERT FROM BCD TO HEX MOV E,A ;TO E FOR OUTPUT MVI C,2 CALL BDOS POP B ;RESTORE REGISTERS POP D POP H RET ; MOVE: MOV A,M ;MOVE STRING AT (HL) TO (DE) FOR LENGTH IN B INX H STAX D INX D DCR B JNZ MOVE RET ; FILL: PUSH D ; FILL STORAGE AT (HL) WITH CHARACTER IN A MOV E,A ; FOR LENGTH IN BC MOV A,B ORA C MOV A,E POP D RZ DCX B MOV M,A INX H JMP FILL ; ; WORKING STORAGE AREA ; SUBNAM: DB 'SUB' ZEXNAM: DB 'ZEX' LINEM: DB ' Error Line # $' ZEXACT: DB CR,LF,' ZEX Already Present$' BUFMTY: DB CR,LF,'Text Buffer Empty$' OVERLP: DB CR,LF,'Input/ZEX Buffer Overlap$' NONUM: DB CR,LF,'Parameter Number out of range$' NOPRM: DB CR,LF,'No Parameter or Default Parameter$' PMERR: DB CR,LF,'Parameter$' NOSBF1: DB CR,LF,'File ' NOSBF2: DB 'filename.typ$' NOTHER: DB ' not there$' CMDER: DB CR,LF,'Control character$' TOOARG: DB CR,LF,'Too many arguments - $' SIGNON: DB 'ZEX, Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0','$' CRLFS: DB CR,LF,'$' ; DS 80 ;STACK SPACE CCPSTK: DW 0 ;CCP STACK PTR IMFLG1: DB 0 ;=IMON ENCOUNTERED IMFLG2: DB 0 ;=IMOFF ENCOUNTERED PRTFLG: DB 0 ;=PSUP ON LCHR: DB 0 ;LAST CHARACTER READ PRMMAX: DB 0 ;HIGHEST PARAMETER # PRMNUM: DB 0 ;CURRENT $<1-9> NUMBER * 2 (ZERO RELATIVE) ERRLNE: DW 0 BITMAP: DB 0 ;PRESENT OFFSET BIT'S COUNT: DB 0FFH ;PRESENT OFFSET BIT COUNT BEGLIN: DW BEGREL ;BEGINNING OF OLD LINE POINTER LINES: DW 1 INBUF: DW BEGREL ENDBUF: DW 0 ;END OF INPUT BUFFER OUTCNT: DB 0 OUTLNE: DW 0 RELSTRT: DW 0 OUTBUF: DW 0 BUFSTR: DW 0 RELOCL: DW 0 ;LENGTH OF RELOC PROGRAM (FILLED IN BY SID) PRMDFP: ;DEFAULT PARAMETER PTRS REPT 9 DW 0 ENDM PRMDFL EQU $-PRMDFP PRMDMY: DW 0 ;DUMMY PARAMETER FOR .SUB FILE SPEC. PRMPNT: ;COMMAND LINE PARAMETER PTRS REPT 9 DW 0 ENDM PRMPNL EQU $-PRMPNT PATCH: ;PATCH AREA REPT 32 DB 'p' ENDM REPT 30 DW 0 ENDM ; ; INSURE 8 BYTE BOUNDARY FOR REL.UTL(RELS.UTL) ; ?PLOC SET $ IF (?PLOC MOD 8) GT 0 ?PLOC SET (?PLOC AND 0FFF8H)+8 ;GET NEXT 8 BYTE BOUNDARY ORG ?PLOC ENDIF ; BEGREL: DS 0 ;RELOC PROGRAM STARTS HERE (ALSO USED AS BUFFER) ; ENDIF ; ; END OF ZEX INITIATOR CODE SEGMENT ; $-PRINT IF NOT ZEXBASE $+PRINT ; ; START OF ZEX RELOCATED CODE SEGMENT ; HL PTS TO MULTIPLE COMMAND BUFFER ; OR HL=0 IF NO MULTIPLE COMMANDS ; ORG ZEXREL ; ZEX: SHLD EXMBASE ;SAVE ADDRESS OF MCL BUFFER XCHG ;HL=ADDRESS OF ZCPR3 MESSAGES SHLD Z3MSGA ;SAVE ADDRESS MVI B,09H ;MESSAGE OFFSET CALL MLHLD ;GET ADDRESS OF NEXT CHAR MOV A,M ;GET 1ST CHAR CPI MSUP ;1ST CHAR=MESSAGE SUPPRESS? JNZ ZEX1 ;NO... DCX H ;YES..SKIP CHARACTER MVI B,09H ;MESSAGE OFFSET CALL MSHLD ;SET PTR TO NEXT CHAR STA MSUPFL ;SET INITIAL FLAG ZEX1: LXI SP,MEMTOP LHLD BDOS+1 ;GET WARM JUMP FOR STANDARD CCP SHLD MEMTOP ;SET PTR TO TOP OF MEMORY INX H MOV E,M ;DE = ADDRESS OF ACTUAL BDOS INX H MOV D,M XCHG ;HL PTS TO ACTUAL BDOS MOV A,H ;SUBTRACT 8 FOR CCP ENTRY POINT SUI 8 MOV H,A MVI L,3 ;SET UP FOR WARM CCP JUMP SHLD CCPJMP LHLD WARM+1 ;SAVE WARM BOOT ADDRESS SHLD WARMPT LXI D,BSWARM ;SAVE OLD BIOS JUMPS MVI B,12 CALL MOVE ;MOVE BIOS JUMPS LHLD WARMPT XCHG LXI H,LOCJMP ;STORE NEW BIOS JUMPS MVI B,12 CALL MOVE ;MOVE NEW BIOS JUMPS TO BIOS AREA ; ; ZEX RUNTIME BIOS INTERCEPT ROUTINES ; NWARM: LXI SP,MEMTOP MVI B,09H ;MESSAGE OFFSET CALL MLHLD ;GET ADDRESS OF NEXT CHAR MOV A,M CPI 0FFH ;TEST IT JZ WARMX ;WARM RETURN LHLD WARMPT ;SET WARM BOOT ADDRESS SHLD WARM+1 LHLD MEMTOP ;SET BDOS ENTRY ADDRESS SHLD BDOS+1 LXI D,BUFF ;DMA ADDRESS MVI C,26 ;SET DMA CALL BDOS LDA BDISK MOV C,A LHLD CCPJMP PCHL ;GOTO CONSOLE PROCESSOR ; ; JMP TABLE TO OVERLAY BIOS WITH NEW ZEX-BASED JUMPS ; LOCJMP: JMP NWARM ;WARM JMP BCONST ;CONST JMP NCONIN ;CONIN JMP NCONOT ;CONOT ; ; ZCPR3 MESSAGE BUFFER ACCESS ROUTINES ; ; ; GETZ3MSG RETURNS HL POINTING TO DESIRED MESSAGE (OFFSET IN B) ; Z3MSGA: DW 0 ;MESSAGES ADDRESS GETZ3MSG: PUSH D ;SAVE DE LHLD Z3MSGA ;GET ADDRESS OF MESSAGES MOV E,B ;GET OFFSET MVI D,0 DAD D ;HL PTS TO MESSAGE OF INTEREST POP D RET MSHLD: PUSH D ;SAVE DE XCHG CALL GETZ3MSG ;MAKE HL PT TO MESSAGE MOV M,E ;STORE LOW INX H MOV M,D ;STORE HIGH XCHG ;RESTORE HL POP D ;RESTORE DE RET MLHLD: PUSH PSW ;SAVE A CALL GETZ3MSG ;MAKE HL PT TO MESSAGE MOV A,M ;GET LOW INX H MOV H,M ;GET HIGH MOV L,A ;PUT LOW POP PSW ;RESTORE A RET MSTA: PUSH H ;SAVE HL CALL GETZ3MSG ;PT TO MESSAGE WITH HL MOV M,A ;STORE MESSAGE POP H RET MLDA: PUSH H ;SAVE HL CALL GETZ3MSG ;PT TO MESSAGE WITH HL MOV A,M ;GET MESSAGE POP H RET ; ; END OF Z3MSG ACCESS ROUTINES ; ; ; CONSOLE INPUT INTERCEPT ROUTINE ; NCONIN: MVI B,07H ;MESSAGE OFFSET CALL GETZ3MSG ;PT TO ZEX MESSAGE BYTE MOV A,M ;GET ZEX MESSAGE CPI 2 ;SUSPEND INTERCEPT? JZ BCONIN ;GET INPUT VIA BIOS IF USER INPUT ACTIVE CPI 1 ;PROMPT JUST PRINTED? JNZ NCONNP MVI M,0 ;CLEAR ZEX MESSAGE LXI H,STARTM ;PRINT MESSAGE CALL PMSG ; LDA PMCHR ;PRINT PROMPT CHAR ; MOV C,A ; CALL BCONOT NCONNP: MVI B,08H ;MESSAGE OFFSET CALL MLDA ;GET ZEX RUNNING MESSAGE ORA A ;0=NO JZ WARMX ;ABORT ZEX IF NOT LXI H,0 DAD SP ;SAVE RETURN STACK LEVEL SHLD CONSTK LXI SP,MEMTOP ;SET USER STACK NCONNL: CALL BCONST ;GET CONSOLE STATUS ORA A JZ GETBUF ;GET CHARACTER FROM BUFFER CALL BCONIN ;GET CHARACTER CPI 'C'-'@' ;SEE IF TERMINATE CHARACTER JZ ZEXABRT CPI 'S'-'@' ;13H JNZ NCONEX CALL BCONIN ;WAIT FOR NEXT CHARACTER ANI 7FH MVI B,09H ;MESSAGE OFFSET CALL MLHLD ;PT TO NEXT CHAR INX H MOV M,A MVI B,09H ;MESSAGE OFFSET CALL MSHLD ;RESET PTR TO NEXT CHAR MVI A,'S'-'@' ;13H NCONEX: LHLD CONSTK ;RESTORE CALLER'S STACK SPHL RET ; ; RETURN NEXT CHAR FROM INPUT BUFFER ; GETBUF: LDA IPSUPFL ;COMBINE PSUPFL AND IPSUPFL TO SET PRINT FLAG ORA A ;0=NO SUPPRESS JZ GBUF0 MVI B,01H ;OFFSET TO IF FLAG CALL GETZ3MSG ;PT TO IF FLAG MOV A,M ;GET IF FLAG ORA A ;NO IF? JZ GBUF0 INX H ANA M ;SET IF STATE JNZ GBUF0 ;CURRENT IF IS TRUE MVI A,0FFH ;SUPPRESS PRINT STA OUTFLG JMP GBUF1 GBUF0: LDA PSUPFL ;SET PRINT SUPPRESS FLAG FOR NCONOT STA OUTFLG GBUF1: CALL GETCHR ;GET NEXT CHARACTER CPI UICH ;USER INPUT? JZ UISTRT ;YES..SET USER INPUT PENDING FLAG CPI REXEC ;RE-EXECUTE? JZ REXECR ;YES..RESET BUFFER PTR CPI CRWAIT ;CR WAIT? JZ CRWRTN ;YES..WAIT FOR CR CPI CRBWAIT ;CR WAIT WITH RING BELL? JZ CRBWRTN ;YES..WAIT FOR CR AND RING BELL CPI RNG ;RING BELL? JZ RNGBELL ;YES..JUST RING THE BELL CPI MSUP ;MESSAGE SUPPRESS FLAG? JZ MSUPCK ;YES..TOGGLE FLAG CPI PSUP ;PRINT SUPPRESS ? JZ PSUPCK ;YES..TOGGLE FLAG CPI IPS ;FALSE IF PRINT SUPPRESS? JZ IPSUPCK CPI IMON ;IMMEDIATE MODE START ? JZ IMFLGS ;YES..SET FLAG CPI IMOFF ;IMMEDIATE MODE STOP? JZ IMFLGS ;YES..RESET FLAG CPI CR ;CR? JNZ GETEXT ;NO...EXIT ; ; CR, SO RESET PRINT SUPPRESSION BASED ONLY ON IPSUPFL ; LDA IPSUPFL ;COMBINE PSUPFL AND IPSUPFL TO SET PRINT FLAG ORA A ;0=NO SUPPRESS JZ GBUF2 MVI B,01H ;MESSAGE OFFSET TO IF FLAG CALL GETZ3MSG ;PT TO IF FLAG MOV A,M ;GET IF FLAG ORA A ;NO IF? JZ GBUF2 INX H ANA M ;SET IF STATE JNZ GBUF2 ;CURRENT IF IS TRUE MVI A,0FFH ;SUPPRESS PRINT STA OUTFLG MVI A,CR JMP GETEXT GBUF2: XRA A STA OUTFLG ;YES..RESET PRINT SUPPRESSION MVI A,CR GETEXT: MOV C,A LDA IMFLG CPI IMON ;IMMEDIATE MODE ? MOV A,C JNZ NCONEX ;NO...RETURN TO CALLER WITH CHAR CALL BCONOT ;YES..IMMEDIATE ECHO TO CONSOLE JMP NCONNL ;...LOOP UNTIL IMOFF ; ; ^" COMMAND ; UISTRT: MVI A,2 ;SET MESSAGE TO SUSPEND INTERCEPT MVI B,07H ;MESSAGE OFFSET CALL MSTA ;SET MESSAGE LHLD CONSTK ;RESTORE CALLER'S STACK SPHL JMP NCONIN ;GET CHAR FROM USER FOR NOW ; ; ^: COMMAND ; REXECR: MVI B,0BH ;MESSAGE OFFSET CALL MLHLD ;PT TO FIRST CHAR IN BUFFER MVI B,09H ;MESSAGE OFFSET CALL MSHLD ;SET PTR TO NEXT CHAR XRA A STA IMFLG ;RESET ALL FLAGS STA PSUPFL STA IPSUPFL STA MSUPFL JMP NCONNL ;...LOOP UNTIL ^C ; ; ^? COMMAND ; CRWRTN: CALL BCONIN ;GET INPUT CHAR CPI 'C'-'@' JZ ZEXABRT ;=^C CPI CR JZ CRWRTX ;= CPI ' ' JZ CRWRTX ;= MVI C,BELL CALL BCONOT ;<>CR JMP CRWRTN ; ; ^/ COMMAND ; CRBWRTN: LXI H,DELAY ;SET COUNTER CRBWR1: PUSH H ;SAVE COUNTER CALL BCONST ;CHECK STATUS POP H ;GET COUNTER ORA A ;SET FLAGS JNZ CRBWR2 DCX H ;COUNT DOWN MOV A,H ;DONE? ORA L JNZ CRBWR1 MVI C,BELL ;RING BELL CALL BCONOT JMP CRBWRTN CRBWR2: CALL BCONIN ;GET CHAR CPI 'C'-'@' ;ABORT? JZ ZEXABRT CPI CR ;CONT IF JNZ CRBWRTN ; ; ^| COMMAND ; CRWRTX: MOV C,A ;ECHO CR/LF CALL NCONOT MVI C,LF CALL NCONOT JMP GETBUF ; ; ^* COMMAND ; RNGBELL: MVI C,BELL ;RING BELL CALL NCONOT JMP GETBUF ; ; ^. COMMAND ; PSUPCK: LXI H,PSUPFL CMP M JNZ PSUPST ;SET FLAGS IF NOT EQUAL XRA A ;ELSE RESET FLAGS PSUPST: MOV M,A ;SET/RESET SAVED FLAG JMP GETBUF ;AND GET NEXT CHARACTER (SETS EXEC FLAG) ; ; ^& COMMAND ; IPSUPCK: LXI H,IPSUPFL CMP M JNZ PSUPST ;SET FLAGS IF NOT EQUAL XRA A ;ELSE RESET FLAGS JMP PSUPST ;SET/RESET FLAG IN A ; ; ^# COMMAND ; MSUPCK: LXI H,MSUPFL CMP M JNZ MSUPST ;SET FLAGS IF NOT EQUAL XRA A ;ELSE RESET FLAG MSUPST: MOV M,A ;SET/RESET FLAG JMP GETBUF ;AND GET NEXT CHARACTER ; ; ^< AND ^> COMMANDS ; IMFLGS: STA IMFLG ;SET/RESET IMMEDIATE MODE FLAG JMP GETBUF ;GET NEXT CHARACTER ; ; CONSOLE OUTPUT INTERCEPT ROUTINE ; NCONOT: LDA OUTFLG ;PRINT SUPPRESSION? ORA A RNZ ;YES...IGNORE ECHO MOV A,C STA PMCHR ;SET LAST CHAR OUTPUT JMP BCONOT ; ; GET NEXT CHAR FROM BUFFER AND TERMINATE ZEX IF END OF BUFFER ; GETCHR: MVI B,09H ;MESSAGE OFFSET CALL MLHLD ;PT TO NEXT CHAR MOV A,M ;GET IT DCX H ;PT TO FOLLOWING MVI B,09H ;MESSAGE OFFSET CALL MSHLD ;SET PTR TO NEXT CHAR CPI 0FFH ;EOB? RNZ ;NO...RETURN ; LHLD Z3MSG+09H ;PT TO EOB INX H ;POINT TO EOB MVI B,09H ;MESSAGE OFFSET CALL MSHLD ;SET PTR TO NEXT CHAR (LAST CHAR) CALL MOVBAK ;MOVE JUMPS BACK CALL BDOSRST ;RESTORE BDOS ADDRESS CALL PRDONEM XRA A ;TURN OFF ZEX MVI B,08H ;MESSAGE OFFSET CALL MSTA ;TURN OFF ZEX LHLD CONSTK ;GET OLD STACK SPHL MVI A,CR ;RETURN CARRIAGE RETURN RET ; ; PRINT DONE MESSAGE WITH FOLLOWING PROMPT CHAR ; PRDONEM: LXI H,DONEM ;PRINT MESSAGE CALL PMSG LDA PMCHR ;PRINT PROMPT CHAR MOV C,A ;IN C FOR BIOS JMP BCONOT ; ; RESTORE BDOS JMP IF NECESSARY ; BDOSRST: LHLD MEMTOP ;SEE IF BDOS+1=MEMTOP XCHG LHLD BDOS+1 MOV A,E SUB L MOV A,D SBB H RNZ ;DON'T REPLACE BDOS JUMP INX D ;PT TO BDOS JUMP LDAX D ;GET LOW ADDRESS MOV L,A ;... IN L INX D LDAX D ;GET HIGH ADDRESS MOV H,A ;... IN H SHLD BDOS+1 ;RESET BDOS JUMP RET ; ; ^C ABORT EXIT ; ZEXABRT: LXI SP,MEMTOP ;^C ABORTS ZEX LXI H,ABORTD ;ABORT CALL PMSG JMP WARMX1 ;DON'T PRINT DONE MESSAGE ; ; ABORT ZEX AND RETURN TO ZCPR3 ; WARMX: CALL PRDONEM ;PRINT DONE MESSAGE ; ; ENTRY POINT TO ABORT ZEX WITHOUT MESSAGE ; WARMX1: XRA A ;SAY THAT ZEX IS NOT RUNNING MVI B,08H ;MESSAGE OFFSET CALL MSTA ;SET NOT RUNNING CALL MOVBAK ;MOVE JUMPS BACK CALL BDOSRST ;RESTORE BDOS JUMPS LHLD EXMBASE ;MULTIPLE COMMAND LINES ENABLED? MOV A,H ;ANY ON? ORA L JZ WARM ;NONE ON IF ADDRESS IS ZERO, SO JUST WARM BOOT ; ; THIS SECTION OF CODE CLEARS THE MULTIPLE COMMAND LINE BUFFER ; MOV D,H ;DE PTS TO MULTIPLE COMMAND BUFFER ALSO MOV E,L PUSH H ;SAVE PTR LXI H,4 ;PT TO FIRST CHAR OF LINE DAD D MVI M,0 ;SET FIRST CHAR OF LINE TO ZERO FOR EOL XCHG ;DE PTS TO FIRST CHAR OF LINE POP H ;GET PTR MOV M,E ;STORE ADDRESS OF EMPTY COMMAND (EOL) INX H MOV M,D JMP WARM ; ; SUBROUTINES ; MOVBAK: LHLD WARMPT ;MOVE OLD JUMP TABLE BACK TO BIOS XCHG LXI H,BSWARM MVI B,12 CALL MOVE JMP F121 ;CALL 1.2.1 FIX FOR MBASIC 1.1.2 ; MOVE: MOV A,M ;MOVE STRING FROM (HL) TO (DE) FOR LENGTH IN B INX H STAX D INX D DCR B JNZ MOVE RET ; PMSG: PUSH H LDA IPSUPFL ;COMBINE PSUPFL AND IPSUPFL TO SET PRINT FLAG ORA A ;0=NO SUPPRESS JZ PMSG0 MVI B,01H ;MESSAGE OFFSET TO IF FLAG CALL GETZ3MSG ;PT TO IF FLAG MOV A,M ;GET IF FLAG ORA A ;NO IF? JZ PMSG0 INX H ANA M ;SET IF STATE POP H ;IN CASE OF RETURN RZ ;SKIP MESSAGE IF SUPPRESSED PUSH H PMSG0: POP H LDA MSUPFL ;PRINT MESSAGE AT (HL) CPI MSUP ;MESSAGES SUPPRESSED? RZ ;YES..EXIT PMSGL: MOV A,M ;GET NEXT CHAR ORA A ;END OF MESSAGE? RZ ;YES..EXIT INX H ;PT TO NEXT CHAR PUSH H ;SAVE PTR MOV C,A ;OUTPUT CHAR CALL BCONOT POP H ;RESTORE PTR JMP PMSGL ; ; REPLACE ZEX ROUTINE JUMPS WITH BIOS JUMPS ; F121: LXI H,BSWARM ; INSURE ONLY BIOS 1.1.2 LXI D,NWARM ; CALLS FROM NOW ON 1.1.2 MVI B,3 ; FOR PROGRAMS 1.1.2 CALL MOVE ; THAT MAY HAVE 1.1.2 LXI H,BCONIN ; COPIED OUR 1.1.2 LXI D,NCONIN ; ADDRESSES AS 1.1.2 MVI B,3 ; IF THEY WERE 1.1.2 CALL MOVE ; IN THE BIOS. 1.1.2 LXI H,BCONOT ; (MBASIC DOES THIS) 1.1.2 LXI D,NCONOT ; 1.1.2 MVI B,3 ; 1.1.2 JMP MOVE ; 1.1.2 ; ; WORKING STORAGE AREA ; ABORTD: DB CR,LF,'[ZEX Aborted]',CR,LF,0 STARTM: DB ' ZEX: ',0 DONEM: DB 'Done',0 ; REPT 12 ;12 ELT STACK DW 0 ENDM MEMTOP: DW 0 EXMBASE: DW 0 CCPJMP: DW 0 WARMPT: DW 0 ; ; ORIGINAL BIOS JMP TABLE ; BSWARM: JMP $ BCONST: JMP $ BCONIN: JMP $ BCONOT: JMP $ ; PMCHR: DB 0 PSUPFL: DB 0 IPSUPFL: DB 0 OUTFLG: DB 0 NUICH: DB 0 IMFLG: DB 0 MSUPFL: DB 0 CONSTK: DW 0 ; ?PLEN SET $ IF (?PLEN MOD 8) GT 0 ?PLEN SET (?PLEN AND 0FFF8H)+8;GET NEXT BOUNDARY ENDIF ; DRVERL EQU ?PLEN ; DRVL8 EQU DRVERL/8 ;LENGTH OF RELOCATION BIT MAP ORG DRVERL ; ENDIF ; ; END OF ZEX RELOCATED CODE SEGMENT ; END