Files
erkyrath.infocom-zcode-terps/ibm/readio.ezp
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

938 lines
24 KiB
Plaintext

SUBTTL READIO - I/O OPERATIONS
PAGE +
PUBLIC GETLIN
GETLIN PROC
MOV AX,CX ; (A0) AX HAS NUMBER OF ARGS TO READ
PUSH BX
MOV SCRHLD,1 ; (7n) HOLD SCRIPTING
PUSH SI
MOV CL,ES:[SI]
MOV BX,OFFSET INBUF
MOV BYTE PTR [BX],CL
CMP CL,MAXLIN ; (7r) DON'T EXCEED BUFFER LENGTH
JBE GTLN0 ; (7r) FIX IF ABOVE
MOV BYTE PTR [BX],MAXLIN ; (7r) WITH OUR NEW MAXIMUM
GTLN0: MOV DX,BX
CMP AX,2 ; (A0) TIME OUT VERSION?
JBE GTLNA ; (A0) TWO TABLES, GET NORMALLY
MOV BX,OFFSET ARGBLK ; (A0) GET ADDR OF ARGBLK
MOV AX,[BX+4] ; (A0) GET THE DELAY COUNT
MOV BX,[BX+6] ; (A0) AND THE TIMEOUT FUNCTION
PUSH SI ; (A0) SI IS GETTING WRECKED???
CALL LININP ; (A0) CALL TIMEOUT INPUT ROUTINE
POP SI ; (A0) SO I PRESERVED IT
JMP GTLNB ; (A0) SKIP NORMAL CALL
;GTLNA: MOV AH,CRDLIN
; INT 21H
GTLNA: CALL RDLIN ;(A9)
GTLNB: TEST SCROLL,1 ;(7) WHAT KIND OF SCROLLING
JNZ GTLN1
MOV AH,SCROLLUP ;(7) USE A VIDEO BIOS SCROLL
MOV AL,1 ;(7) ONLY 1 LINE
MOV CX,TOPLIN ;(7) ALWAYS FREEZE TOP LINE
MOV DH,SLPP ;(7) GET SCREEN LENGTH
MOV DL,SCPL ;(7) GET THE WIDTH OF THE SCREEN
DEC DL ; (7v) COORDINATES ARE ZERO BASED
MOV BH,SCRATR ;(7) GET THE SCREEN ATTRIBUTE
INT 10H ;(7) CALL THE VIDEO
JMP GTLN2 ;(7) SKIP LINE FEED OUTPUT
GTLN1: MOV AH,CCONIO
MOV DL,10
INT 21H
GTLN2: POP DX
MOV BX,OFFSET INBUF
MOV CL,BYTE PTR [BX+1]
SUB CH,CH
INC BX
CMP CL,0
JE GETLEM
GETLLP: INC SI
INC BX
MOV AL,BYTE PTR [BX]
CMP AL,"A"
JL GETLLC
CMP AL,"Z"
JG GETLLC
ADD AL,32
GETLLC: MOV ES:[SI],AL
LOOP GETLLP
GETLEM: INC SI
SUB AL,AL
MOV ES:[SI],AL
MOV SCRHLD,0 ; (7n) TURN OFF SCRIPT HOLD
POP BX
RET
GETLIN ENDP
PUBLIC PRTOUT
PRTOUT PROC
PUSH AX
PUSH BX
PUSH CX
PUSH DX ; (7) SAVE THIS, USING STD PRT
TEST WORD PTR ES:[PFLAGS],SCRPTBT ; (A17) SCRIPTING ON?
JZ POUT2 ; (A17) NOPE
TEST CMDLIN,16 ; (7n) DO WE WANT IBM PRINTER
JZ POUT1 ; (7n) GUESS NOT
POUT0: MOV AH,0 ; (7) FUNCTION TO PRINT
MOV DX,0 ; (7) TO THE FIRST PRINTER
INT 17H ; (7) TRY IT
TEST AH,RDYBIT ; (7) TIME OUT?
JZ POUT2 ; (7) WORKED, RETURN
CALL PRNRDY ; (7)
JC POUT2
JMP POUT0 ; (7) RETRY
POUT1: MOV DL,AL ; (7n) GET CHARACTER TO PRINT
MOV AH,CPROUT ; (7n) PRINT IT
INT 21H
POUT2: POP DX ; (7n) FORGET THIS AND BREAK...
POP CX
POP BX
POP AX
RET
PRTOUT ENDP
PUBLIC PRNRDY
PRNRDY PROC
OR WORD PTR ES:[PFLAGS],REFRESH ;(E0) REFRESH THE STATUS LINE
PUSH AX
MOV SCRHLD,1 ; (7n) HOLD OFF SCRIPTING
PRINT PRNNRDY ; (7) ASK USER ABOUT ACTION
RDY1: CALL MCHRI ; (7) GET A RESPONSE
CALL MTTYO ; (7u) ECHO THE CHARACTER
AND AL,5FH ; (7) UPPPER CASIFY
CMP AL,'A' ; (7) SHOULD WE ABORT
JNZ RDY2 ; (7) ATTEMPTING RETRY
MOV SCRFLG,0 ; (7) TURN OFF SCRIPTING
; (A10) COMMENTED OUT LINE
; AND ES:[PFLAGS],SCRMSK ; (7) AND IN THE MODE WORD
MOV SCRHLD,0 ; (7n) TURN OFF BAN ON SCRIPTING
STC ; (7) SET CARRY FOR NO RETRY
PUSHF ; (7) SAVE THESE
JMP RDY3 ; (7) CR LF ON EXIT
RDY2: CMP AL,'R' ; (7) RETRY???
JNZ RDY1 ; (7) WRONG CHARACTER
CLC ; (7) CLEAR CARRY FOR RETRY
PUSHF ; (7) SAVE FLAGS
RDY3: CALL MCRLF ; (7) DO A <CR><LF>
MOV SCRHLD,0 ; (7n) TURN OFF BAN ON SCRIPTING
POPF ; (7) RESTORE FLAGS AND
POP AX ; (7) CHARACTER TO PRINT
RET
PRNRDY ENDP
SCRCHK PROC
PUSH AX
PUSH BX
PUSH DX
TEST SCRFLG,1 ; (A11) IS SCRIPTING ENABLED?
JNZ SCR0L$ ; (7x) ....YES, CONTINUE
JMP SCREX$ ; (A11)....NO
; MOV SCRFLG,1 ; (7n) TURN ON SCRIPT FLAG
; CMP SCROLL,0 ; (7) SHOULD WE BE DOING THIS?
; JNZ SCR0L$ ; (7) NOPE...
; TEST CMDLIN,16 ; (7n) DID WE REALLY REQUEST IBM
; JZ SCR0L$
;SCR_1$: MOV DX,0 ; (7) TRY TO INIT THE PRINTER
; MOV AH,1
; INT 17H ; (7) SO THAT WE WILL TIME OUT FAST
; TEST AH,PRTMSK ; (7) TEST FOR TIME OUT
; JZ SCR0L$ ; (7) NO PROBLEM, WE'RE FINE
; CALL PRNRDY ; (7) INFORM USER OF PROBLEM
; JNC SCR_1$
; JMP SCRNN$ ; (7) TURN OFF SCRIPTING
SCR0L$: SUB CX,CX
MOV BP,DX
INC BP
SCR1L$: MOV AL,ES:[BP]
INC BP
CMP BP,SI
JLE SCR2L$
CALL PRTCRL
JMP SCREX$
SCR2L$: CALL PRTOUT
INC CX
CMP CL,SCPL
JNE SCR1L$
CALL PRTCRL
JC SCREX$
SUB CX,CX
JMP SCR1L$
SCRNN$: MOV SCRFLG,0
SCREX$: POP DX
POP BX
POP AX
RET
SCRCHK ENDP
PUBLIC PRTCRL
PRTCRL PROC
TEST WORD PTR ES:[PFLAGS],SCRPTBT ;(A18) DON'T SCRIPT READ
JNZ PRTC1
RET
PRTC1: MOV AL,13 ;FINISH UP WITH CRLF
CALL PRTOUT
MOV AL,10
CALL PRTOUT
; OR WORD PTR ES:[PFLAGS],REFRESH ; (A17) SET THE REFRESH BIT
RET
PRTCRL ENDP
;READ (A LINE OF INPUT & PARSE IT, LINE BUF IN ES:AX,
;RETURN BUF IN ES:BX)
PUBLIC OPREAD,ORD1$,ORDNS$,ORD8$,ORD9$,ORD10$,ORD1A$,ORD11$,ORD12$
; PUBLIC ORD13$,ORD14$,ORD15$,ORD16$,ORD17$,ORD18$,ORD19$,ORD20$
; PUBLIC ORD21$,ORD22$,ORD23$
OPREAD PROC
NOP ; (A0) GET ARGS IN ARGBLK
MOV CX,AX ; (A0) GET # OF ARGS
MOV BX,OFFSET ARGBLK
MOV AX,[BX] ; (A0) GET FIRST TWO ARGS INTO AX & BX
MOV BX,[BX+2]
PUSH AX ;SAVE LINE BUF
MOV BP,CHRPTR ;NEXT CHARACTER POSITION
MOV BYTE PTR DS:[BP],80H ;(6)DON'T END OUTPUT, IF ANY, WITH CRLF
ORD1$: PRINT OUTBUF ;FORCE OUT ANY QUEUED TEXT
MOV CHRPTR,OFFSET OUTBUF ;RESET CHARACTER POINTER
POP SI ;INPUT BUFFER POINTER
MOV MORLIN,0 ;RE-INITIALIZE MORE COUNT FROM HERE
MOV CHRCNT,BUFLEN ; (A15) RE-INITIALIZE THE CHAR COUNTER
CALL GETLIN ;GET SOME CHARACTERS
CALL SCRCHK ;PRINT THE BUFFER IF SCRIPTING IS ON
ORDNS$: PUSH DI
MOV RDBOS,DX ;INITIALIZE RDBOS
MOV RDEOS,SI ;AND RDEOS
MOV RDRET,BX ;STORE RET POINTER
MOV RDNWDS,0 ;NO WORDS SO FAR
INC DX ;SKIP LENGTH BYTE
MOV DI,BX ;THIS WILL BE WORD ENTRY POINTER
INC DI ;SKIP MAX WORDS & NWORDS BYTES
INC DI
ORD8$: MOV CX,OFFSET RDWSTR;HERE FOR NEXT WORD, POINT TO WORD STRING
MOV BX,DX ;AND SAVE BEGINNING OF WORD POINTER
ORD9$: CMP DX,RDEOS ;END OF STRING?
JNE ORD10$ ;NO
CMP CX,OFFSET RDWSTR;YES, WAS A WORD FOUND?
JNE ORD15$ ;YES, WE STILL HAVE TO LOOKUP WORD
JMP ORD23$ ;NO, WE'RE DONE
ORD10$: MOV BP,DX ;GET NEXT CHARACTER FROM BUFFER
MOV AL,ES:[BP]
CMP AL,"A"
JL ORD1A$
CMP AL,"Z"
JG ORD1A$
ADD AL,32 ;LOWERCASIFY ALPHABETICS
ORD1A$: INC DX
MOV SI,OFFSET RBRKS ;LIST OF READ BREAK CHARACTERS
ORD11$: INC SI
CMP AL,[SI-1] ;SEARCH LIST FOR THIS ONE
JE ORD12$ ;FOUND IT
CMP BYTE PTR [SI],0 ;END OF LIST?
JNE ORD11$ ;NO, CONTINUE SEARCH
CMP CX,OFFSET RDWSTR[9] ;YES, NOT A BREAK, WORD STRING FULL?
JE ORD9$ ;YES, LOOP UNTIL END OF WORD
MOV BP,CX ;NO, TACK THIS CHARACTER ONTO STRING
MOV DS:[BP],AL
INC CX
JMP ORD9$ ;AND LOOP
ORD12$: CMP CX,OFFSET RDWSTR;WORD READ BEFORE THIS BREAK?
JNE ORD14$ ;YES
CMP SI,ESIBKS ;NO, BUT IS IT A SELF-INSERTING BREAK?
JBE ORD13$ ;YES
INC BX ;NO, UPDATE BEGINNING OF WORD TO SKIP BREAK
JMP ORD9$ ;AND RETURN TO LOOP TO FIND A WORD
ORD13$: MOV BP,CX ;STORE THE BREAK IN WORD STRING
MOV DS:[BP],AL
INC CX
JMP ORD15$ ;AND GO FOR THE WORD
ORD14$: DEC DX ;UNREAD TERMINATING BREAK IN CASE IT WAS SI
ORD15$: INC RDNWDS ;INCREMENT FOUND WORD COUNT
MOV BP,BX ;GREATER THAN MAX ALLOWED?
MOV BX,RDRET
MOV BL,ES:[BX]
CMP BL,59 ; (7w) GAME FIX
JBE ORD15A ; (7w) FIX NUMBER OF TOKENS ALLOWED
MOV BL,59 ; (7w) OTHERWISE WE OVERRUN A TABLE
ORD15A: CMP RDNWDS,BL
MOV BX,BP
JLE ORD16$ ;NO
PRINT ERR2 ;YES, INFORM LOSER
MOV AX,BX ;BEGINNING OF THIS WORD
MOV BP,RDEOS ;SAVE BYTE AFTER EOS
MOV BL,ES:[BP]
MOV BYTE PTR ES:[BP],0 ; ZERO IT TO MAKE STRING ASCIZ
PUSH BX ; (7w) SAVE THIS ADDRESS
MOV BX,DS ; (7w) FIGURE WHERE STRING IS IN DS
NEG BX ; (7w) SUBTRACT DS FROM ES
ADD BX,GAMESEG ; (7w) BX HAS PARAGRAPHS OF DIFFERENCE
MOV CL,4 ; (7w) CONVERT TO AN OFFSET
SHL BX,CL ; (7w) TO ADD IN WITH AX
ADD AX,BX ; (7w) NOW DS:AX SHOULD EQUAL PREV ES:AX
POP BX ; (7w) RESTORE BX
CALL MPRNT ;PRINT IT
MOV ES:[BP],BL ; AND RESTORE OLD BYTE
DEC RDNWDS ;REMEMBER THAT WE FLUSHED THIS WORD
JMP ORD23$ ;AND WE'RE DONE
ORD16$: MOV AX,BX ;CALCULATE NUMBER OF CHARACTERS IN WORD
NEG AX
ADD AX,DX
MOV ES:[DI+2],AL ;(6)SAVE THE NUMBER IN RET TABLE
SUB BX,RDBOS ;BYTE OFFSET FOR BEGINNING OF WORD
MOV ES:[DI+3],BL ;(6)STORE IT, TOO
MOV BP,CX ;MAKE WORD STRING ASCIZ
MOV BYTE PTR DS:[BP],0 ;(6) REMOVED SEG OVERRIDE (DS)
MOV AX,OFFSET RDWSTR;POINT TO IT
CALL ZWORD ;AND CONVERT TO (2-WORD) ZWORD
MOV ZTHIRD,CX ; (A0) SAVE THIRD WORD
PUSH DX ;SAVE CHAR & WORD ENTRY POINTERS
PUSH DI
MOV DI,AX ;FIRST ZWORD WORD
MOV SI,VWORDS ;NUMBER OF VOCABULARY WORDS
MOV AX,SI
DEC AX ;WE WANT TO POINT TO LAST WORD
MUL VWLEN ;MULTIPLY BY WORD LENGTH IN BYTES
ADD AX,VOCBEG ;ADD POINTER TO BEGINNING TO FIND LAST WORD
MOV CX,AX ;POINTER TO LAST WORD
MOV DX,DI ;FIRST ZWORD WORD
MOV DI,BX ;SECOND ZWORD WORD
MOV BX,VWLEN ;CALCULATE INITIAL OFFSET FOR BINARY SEARCH
SAR SI,1
ORD17$: SAL BX,1
SAR SI,1
CMP SI,0
JNE ORD17$
MOV SI,VOCBEG ;BEGINNING OF WORD TABLE
ADD SI,BX ;ADD CURRENT OFFSET(HALF OF POWER-OF-2 TABLE)
PUSH AX ;SAVE
MOV AX,VWLEN ;AVOID FENCEPOST BUG FOR EXACT POWER-OF-2 TBL
SUB SI,AX
POP AX ;RESTORE
ORD18$: SAR BX,1 ;NEXT OFFSET WILL BE HALF OF PREVIOUS ONE
GTAWRD A,[SI] ;GET FIRST HALF OF CURRENT ZWORD
CMP DX,AX ;COMPARE DESIRED ONE TO IT
JA ORD19$ ;GREATER, WE'LL HAVE TO MOVE UP
JB ORD20$ ;LESS, WE'LL HAVE TO MOVE DOWN
MOV BP,SI ;SAME, GET SECOND HALF
ADD BP,2 ; (A0) LOOK AT SECOND WORD
GTAWRD A,[BP]
CMP DI,AX ;COMPARE DESIRED WORD WITH IT
JA ORD19$ ;GREATER, WE'LL HAVE TO MOVE UP
JB ORD20$ ;LESS, WE'LL HAVE TO MOVE DOWN
MOV BP,SI ; (A0) SAME, GET SECOND HALF
ADD BP,4 ; (A0) LOOK AT THIRD WORD
GTAWRD A,[BP] ; (A0)
CMP ZTHIRD,AX ; (A0) COMPARE DESIRED WORD WITH IT
JA ORD19$ ; (A0) GREATER, WE'LL HAVE TO MOVE UP
JB ORD20$ ; (A0) LESS, WE'LL HAVE TO MOVE DOWN
JMP ORD22$ ;SAME, WE'VE FOUND IT, RETURN IT
ORD19$: ADD SI,BX ;TO MOVE UP, ADD CURRENT OFFSET
jc ORD24$ ; overflowed a segment, set back to end
CMP SI,CX ;HAVE WE MOVED PAST END OF TABLE?
JBE ORD21$ ;NO
ORD24$: MOV SI,CX ;YES, POINT TO END OF TABLE INSTEAD
JMP ORD21$
ORD20$: SUB SI,BX ;TO MOVE DOWN, SIMPLY SUBTRACT OFFSET
ORD21$: CMP BX,VWLEN ;IS OFFSET RESOLUTION BELOW ONE WORD?
JGE ORD18$ ;NO, CONTINUE LOOP
SUB SI,SI ;YES, WORD NOT FOUND, RETURN ZERO
ORD22$: POP DI ;RESTORE WORD ENTRY POINTER
MOV DX,SI ;POINTER TO WORD FOUND
XCHG DH,DL
MOV ES:[DI],DX ;(6) STORE IT
POP DX ;RESTORE CHAR POINTER
ADD DI,4 ;UPDATE POINTER FOR NEXT WORD ENTRY
JMP ORD8$ ;GO FOR IT
ORD23$: INC RDRET ;DONE, STORE NUMBER OF WORDS FOUND
MOV BP,RDRET
MOVM ES:[BP],RDNWDS,DL ; REMOVED ES OVERRIDE
POP DI ;RESTORE USER STACK POINTER
RET ;AND RETURN
OPREAD ENDP
PUBLIC OPBFOUT
OPBFOUT PROC
CMP AX,0 ; (A0) WHAT DO WE WANT?
JNZ BUFFED ; (A0) TURN OFF BUFFERED INPUT
MOV BUFBIT,0 ; (A0) SET FLAG
PUSH BX
MOV BX,CHRPTR ; (A0) LOCATION FOR NEXT CHAR
MOV BYTE PTR [BX],80H ; (A0) INDICATE END OF STRING
PRINT OUTBUF ; (A0) FLUSH THE BUFFER
MOV BX,OFFSET OUTBUF ; (A0) GET BUFFER ADDR
MOV CHRPTR,BX ; (A0) RESET THE CHRPTR
POP BX ; (A0) RESTORE BX
RET
BUFFED: MOV BUFBIT,1 ; (A0) TURN BUFFERING BACK ON
RET
OPBFOUT ENDP
PUBLIC OPDIRIN
OPDIRIN PROC
RET
OPDIRIN ENDP
;
; SELECT OR DESELECT A VIRTUAL OUTPUT DEVICE
;
PUBLIC OPDIROU
OPDIROU PROC
OR AL,AL ; (A10) ENABLE OR DISABLE A DEVICE
JNS ODIR0 ; (A10) IF (+) IT'S ENABLE
JMP ODIR5 ; (A10) IF (-) IT'S DISABLE
; {CASE} DEVICE ENABLE HANDLER
ODIR0: CMP AL,1 ; (A10) IS IT THE SCREEN?
JNE ODIR1 ; (A10) NOPE
; {SUBCASE} SCREEN HANDLER
MOV VIDFLG,1 ; (A10) TURN SCREEN ON
RET
ODIR1: CMP AL,2 ; (A10) IS IT THE SCRIPT DEVICE?
JNE ODIR2 ; (A10) NOPE
; {SUBCASE} SCRIPT HANDLER
PUSH AX
PUSH BX
PUSH DX
TEST SCRFLG,1 ; (A11) IS SCRIPTING ALREADY ENABLED?
JNZ ODIR1B ; (A11) ....YES
;
OR WORD PTR ES:[PFLAGS],SCRPTBT ;(A18) TURN ON SCRIPT FOR HI
MOV SCRFLG,1 ; (A18) TURN ON ZIP FLAG
TEST CMDLIN,16 ; (A11) DID WE REALLY REQUEST IBM?
JZ ODIR1B ; (A11) ....YES
; INITIALIZE PRINTER
ODIR1A: MOV DX,0 ; TRY TO INIT THE PRINTER
MOV AH,1
INT 17H ; SO THAT WE WILL TIME OUT FAST
TEST AH,PRTMSK ; TEST FOR TIME OUT
JZ ODIR1B ; NO PROBLEM, WE'RE FINE
CALL PRNRDY ; INFORM USER OF PROBLEM
JNC ODIR1A
; THE PRINTER WOULDN'T INITIALIZE
XOR AH,AH ; (A13) DISABLE SCRIPTING
MOV SCRFLG,AH ; (A13)
OR AH,STSBIT ; (A13) TURN ON STATUS LINE REFRESH BIT
XOR AL,AL ; (A13)
XCHG AH,AL ; (A18) BYTE SWAP
MOV WORD PTR ES:[PFLAGS],AX ; (A13) LET HIGH LEVEL KNOW
ODIR1B: POP DX
POP BX
POP AX
RET
ODIR2: CMP AL,3 ; (A10) IS IT THE TABLE DEVICE?
JNE ODIR3 ; (A10) NOPE
; {SUBCASE} TABLE HANDLER
MOV AL,BUFBIT ; (A0) GET STATE OF BUFBIT
MOV PREVBUF,AL ; (A0) AND SAVE IT FOR LATER
; (B0) Dirout should not flush the buffer
; MOV AX,0 ; (A0) USE TO CALL BUFOUT
; CALL OPBFOUT ; (A0) TURN OFF BUFBIT AND FLUSH
MOV BUFBIT,0 ; (B0) TURN OFF BUFBIT
MOV RDIR,1 ; (A0) STORE REDIRECTION FLAG
MOV RTABLE,BX ; (A0) ZEROTH ELEMENT OF TABLE
MOV RDIROUT,0 ; (A0) ZERO THE NUMBER OF BYTES READ
ADD BX,2 ; (A0) THIS IS TABLE+2
MOV RTABLE2,BX ; (A0) AND TABLE LOCATION (IF INT IS <> 1)
RET
ODIR3: CMP AL,4 ; (A10) IS IT A FILE?
JNE ODIR4 ; (A10) NOPE, DON'T HANDLE IT
; {SUBCASE} FILE HANDLER
; NOT IMPLIMENTED
ODIR4: RET
;
; {CASE} DEVICE DISABLE HANDLER
ODIR5: CMP AL,0FFH ; (A10) IS IT THE SCREEN?
JNE ODIR6 ; (A10) NOPE
; {SUBCASE} SCREEN HANDLER
MOV VIDFLG,0 ; (A10) TURN SCREEN OFF
RET
ODIR6: CMP AL,0FEH ; (A10) IS IT THE SCRIPT DEVICE?
JNE ODIR7 ; (A10) NOPE
; {SUBCASE} SCRIPT HANDLER
MOV SCRFLG,0 ; (A18) TURN OFF SCRIPTING
AND WORD PTR ES:[PFLAGS],SCRMSK
; XOR AH,AH ; (A13) DISABLE SCRIPTING
; MOV SCRFLG,AH ; (A13)
; OR AH,STSBIT ; (A13) TURN ON STATUS LINE REFRESH T
; XOR AL,AL ; (A13)
; MOV ES:[PFLAGS],AX ; (A13) LET HIGH LEVEL KNOW
RET
ODIR7: CMP AL,0FDH ; (A10) IS IT THE TABLE DEVICE?
JNE ODIR8 ; (A10) NOPE
; {SUBCASE} TABLE HANDLER
CMP RDIR,0 ; (C0) IF ALREADY OFF
JE OUT7 ; (C0) LEAVE AS IS
MOV AL,PREVBUF ; (A0) GET PREVIOUS STATE OF BUFFER
MOV BUFBIT,AL ; (A0) AND RESTORE THAT STATE
MOV RDIR,0 ; (A0) AND RESTORE REDIRECTION TO SCREEN
MOV AX,RDIROUT ; (A0) GET NUMBER OF CHARS WRITTEN
MOV BX,RTABLE ; (A0) GET ADDR OF ZEROTH ELEMENT
PTAWRD ES:[BX],A ; (A0) PUT THE WORD INTO THE TABLE
MOV BX,RTABLE2 ; (A18) GET FIRST ELEMENT
MOV BYTE PTR ES:[BX],0 ; (A18) DROP IN A NULL
OUT7: RET ; (C0)
ODIR8: CMP AL,0FCH ; (A10) IS IT A FILE?
JNE ODIR9 ; (A10) NOPE, DON'T HANDLE IT
; {SUBCASE} FILE HANDLER
; NOT IMPLIMENTED
ODIR9: RET
OPDIROU ENDP
SUBTTL OPINPUT
PAGE
; -------
; OPINPUT
; -------
;
; PURPOSE: THIS ROUTINE IS USED TO PERFORM A TIMED CHARACTER REQUEST
;
; IF [ARG1] = 1, THEN THIS IS A TIMED INPUT KEYBOARD REQUEST
; AND THE TIME LIMIT IS PROVIDED IN [ARG2].
;
; IF A KEY IS DETECTED BEFORE TIMEOUT, THEN WE RETURN THE
; CHARACTER VIA PUTBYTE.
;
;IF A FUNCTION IS PROVIDED [ARG3] IT IS INTERNALLY CALLED AFTER
; TIMEOUT. IF THE VALUE RETURNED BY THE FUNCTION = 0, THEN
; WE KEEP LOOPING.
;
; IF A TIMEOUT OCCURS AND WE HAVE NO FUNCTION TO CALL, OR THE
; VALUE RETURNED FROM THE INTERNAL FUNCTION CALL NE. 0, THEN
; WE RETURN A "0" VIA RET0.
;
; INPUTS: [NARGS],[ARG1],[ARG2]opt,[ARG3]opt
;
; OUTPUTS: EITHER A ASCII CHAR RETURNED VIA PUTBYTE
; OR "0" VIA RET0
;
; REGISTERS DESTROYED: AX,DX
;
; EXTERNAL REFERENCES: INCALL
;
PUBLIC OPINPUT,ZTIMLP,NOZFCN,ZIN
OPINPUT PROC
NOP ; (A0) GET ARGS IN ARGBLK
PUSH BX ;(A0) SAVE REGISTERS
PUSH CX
MOV MORLIN,0 ; (A8) RESET THIS VAR
MOV CHRCNT,BUFLEN ; (A15) RESET INPUT CHAR COUNT
MOV BX,ARGBLK ; (A0) GET ARG1
CMP BX,1 ; (A0) KEYBOARD?
JNE NOZFCN ;....NO INVALID REQUEST
CMP AX,3 ;(A0) IS THIS A TIMED INPUT
JB ZIN ;(A0) ....NO
;
; TIMED INPUT
;
ZTIMLP: MOV AX,ARGBLK[2] ; (A0) GET DELAY COUNT
IDIV RADIX
MOV DLYCNT,AX
MOV BX,ARGBLK[4] ; (A0) GET FUNCTION ADDR
CALL TIMLP1 ; (A0) GET A CHAR [+ TIMEOUT]
JNC ZIN ; (A0) GET THE CHAR READY
TEST AL,AL ; (A0) WHAT DID INCALL RETURN
JZ ZIN ; (A0) A ZERO MEANS CONTINUE ANYWAY
NOZFCN: POP CX ; (A0) RESTORE REGISTERS
POP BX
MOV AX,0 ; (A0) RETURN A NULL
JMP BYTVAL ; (A0) IS THIS RIGHT?
; GET A CHARACTER FROM THE KEYBOARD
ZIN: CALL GETKEY
POP CX ; (A0) RESTORE REGISTERS
POP BX
JMP BYTVAL ; (A0) RETURN THE BYTE
OPINPUT ENDP
SUBTTL LINE INPUT FOR GETLIN
PAGE
; ------
; LININP
; ------
;
; PURPOSE: THIS ROUTINE IS USED BY GETLIN TO FETCH A LINE OF INPUT
; FROM THE KEYBOARD AND PLACE IT IN THE INPUT BUFFER (INBUFF)
; IN ADDITION, IT HAS THE RESPONSIBILITY TO TACKLE TIMED LINE
; INPUT REQUESTS.
;
; {CASE TIMED INPUT}
; IF NARGS GE. 3, THEN THIS IS A TIMED INPUT
; IF A KEY IS DETECTED BEFORE TIMEOUT, THEN WE DROP INTO
; LINE INPUT PROCESSING.
;
; IF NARGS EQ. 4, THEN UPON TIMEOUT THE FUNCTION [ARG4] IS
; INTERNALLY CALLED. IF THE VALUE RETURNED BY THE FUNCTION = 0,
; THEN WE KEEP LOOPING.
;
;IF NARGS NE. 4 OR THE VALUE RETURNED FROM THE INTERNAL FUNCTION
; CALL NE. 0, THEN WE RETURN A "FALSE" IN [AX] TO {GETLIN}.
;
; {CASE LINE INPUT PROCESSING}
; GET A LINE OF INPUT AND RETURN A "TRUE" IN [AX] TO {GETLIN}.
;
; INPUTS: [NARGS],[ARG3]opt,[AGR4]opt
;
; OUTPUTS: DX = ADDRESS OF INBUF, AX = TRUE OR FALSE (see above)
;
; REGISTERS DESTROYED: AX,DX
;
; EXTERNAL REFERENCES: INCALL,CHROUT
;
PUBLIC LININP
LININP PROC
PUSH BX ; (A0) SAVE FCN ADDRESS
MOV BX,OFFSET INBUF ; (A0) POINT AT INPUT BUFFER
MOV BYTE PTR [BX],MAXLIN ; (A0) MAXIMUM NUMBER OF CHARACTERS
MOV BYTE PTR [BX+1],0 ; (A0) RESET THE CHARACTER COUNT
;
; TIMED INPUT
;
TIMELP: IDIV RADIX
MOV DLYCNT,AX ; (A0) AX HAS DELAY COUNT
POP BX ; (A0) RESTORE FCN ADDRESS
CALL TIMLP1 ; (A0) SEE IF CHAR IS READY
JNC ENTIN ; (A0) YES, NO TIMEOUT, GET IT
TEST AL,AL ; (A0) SEE WHAT INCALL RETURNED
JZ ENTIN ; (A0) CONTINUE NORMALLY
MOV BX,OFFSET INBUF+2 ;POINT THE START OF THE ACTUAL BUFFER
ADD BX,CX ;(A0) POINT AT THE CHARACTER SLOT
MOV [BX],AL ;(A0) SAVE THE EOL
CALL MTTYO ;(A0) AND OUTPUT IT TO THE CONSOLE
RET
ENTIN: JMP INLOOP
LININP ENDP
;
; GET A LINE OF INPUT
;
PUBLIC INLOOP
INLOOP PROC
CALL GETKEY
CMP AL,14 ;(A0) CLEAR OFF ARROWS
JE INBAD
CMP AL,7
JE INBAD
CMP AL,EOL ;(A0) CARRIAGE RETURN?
JE ENDLIN ;(A0) ....YES. WE'RE DONE
CMP AL,7FH ;(A0) REGULAR DELETE
JE BACKUP ;(A0) ....YES
CMP AL,BACKSP ;(A0) BACKSPACE (DELETE)?
JE BACKUP ;(A0) ....YES
CMP AL,11 ;(A0) LEFT ARROW (DELETE)?
JE BACKUP ;(A0) ....YES
; PUT THE CHARACTER IN THE INPUT BUFFER, IF POSSIBLE
SUB CH,CH
MOV CL,INBUF+1 ;(A0) GET NUMBER OF CHARACTERS ALREADY
;(A0) IN THE BUFFER
; CMP CL,INBUF ;(A0) IS THE BUFFER FULL?
MOV BL,INBUF ;(A9) GET THE MAXIMUM NO. OF CHARACTERS
DEC BL ;(A9) <CR> ENDS ALL INPUT - LEAVE ROOM
DEC BL ;(B0) bl/Length, not ptr
CMP CL,BL ;(A9) IS THE BUFFER FULL?
JE NOMO ;(A0) ....YES
; THERE'S ROOM IN THE BUFFER
INC BYTE PTR INBUF+1 ;(A0) UPDATE NUMBER OF CHARACTERS
;(A0) IN THE BUFFER
MOV BX,OFFSET INBUF+2 ;POINT THE START OF THE ACTUAL BUFFER
ADD BX,CX ;(A0) POINT AT THE CHARACTER SLOT
MOV [BX],AL ;(A0) SAVE THE CHARACTER
;DISPLAY THE CHARACTER ON THE SCREEN
SHOWIT: CALL MTTYO ;(A0) DISPLAY IT
JMP INLOOP ;(A0) AND GET ANOTHER
;
; LINE OVERFLOW
;
NOMORE: CALL GETKEY ;(A0) GET A KEY
CMP AL,EOL ;(A0) <CR>?
JE ENDLIN ;(A0) ....YES, WE'RE DONE
CMP AL,7FH ;(A0) REGULAR DELETE
JE BACKUP ;(A0) ....YES
CMP AL,BACKSP ;(A0) BACKSPACE (DELETE)?
JE BACKUP ;(A0) ....YES
CMP AL,11 ;(A0) LEFT ARROW (DELETE)?
JE BACKUP ;(A0) ....YES
NOMO: CALL FEEP ;(A0) CAN' DO IT, SO COMPLAIN
JMP NOMORE ;(A0) AND DON'T LET THEM OFF THE HOOK
;
; BACKUP (DELETE A CHARACTER)
;
BACKUP: CMP BYTE PTR INBUF+1,0 ;(A0) CAN WE REALLY DELETE A CHARACTER?
JE INBAD ;(A0) ....NO, WE HAVE NONE TO DELETE
; ACTUAL DELETE
DEC BYTE PTR INBUF+1 ;(A0) ONE LESS IN THE BUFFER
MOV AL,BACKSP ;(A0) BACKUP A CHARACTER POSITION
CALL MTTYO ;(A0) ON THE SCREEN
MOV AL,SPACE ;(A0) ERASE CHARACTER
CALL MTTYO ;(A0) BY REPLACING IT WITH A SPACE
MOV AL,BACKSP ;(A0) BACKUP A CHARACTER POSITION
JMP SHOWIT ;(A0) ON THE SCREEN AND LOOP
INBAD: CALL FEEP ;(A0) CAN' DO IT, SO COMPLAIN
JMP INLOOP ;(A0) AND DON'T LET THEM OFF THE HOOK
;
; LINE TERMINATED BY A EOL <CR>
;
ENDLIN: MOV BX,OFFSET INBUF+2 ;POINT THE START OF THE ACTUAL BUFFER
SUB CX,CX
MOV CL,INBUF+1 ;(B1) Point at 1st unused byte
ADD BX,CX ;(A0) POINT AT THE CHARACTER SLOT
; INC BX ;(A9)(b1 2 entry pts w/different conditions;fixed cx)
MOV [BX],AL ;(A0) SAVE THE EOL
CALL MTTYO ;(A0) AND OUTPUT IT TO THE CONSOLE
LINRET: RET
INLOOP ENDP
; ----------------------
; FETCH AN ASCII KEYCODE
; ----------------------
;
; PURPOSE: GETKEY WAITS FOR A KEY TO BE DEPRESSED ON THE CONSOLE.
; WHEN A KEY IS DEPRESSED, IT'S ASCII VALUE IS RETURNED
; FROM THE DOS FUNCTION.THE ASCII VALUE IS THEN PREPROCESSED
; SO THAT CERTAIN KEYS ARE TRANSLATED INTO EZIP ASCII VALUES
;
; OTHER KEYS ARE CONSIDERED ILLEGAL AND IF DETECTED CAUSE A
; BEEP SOUND TO BE HEARD, THE KEYPRESS IS IGNORED, AND THE
; ROUTINE CONTINUES TO WAIT FOR A VALID KEY.
;
; INPUTS: NONE
;
; OUTPUTS: [AL] = A 7-BIT ASCII CODE
;
; REGISTERS DESTROYED:
; AX,BX,CX
;
; EXTERNAL REFERENCES: FEEP
;
PUBLIC GETKEY,GK0,GK1,GK2,GK3,GK4,KEYOK,CHKKEY
GETKEY PROC
GK0: MOV AH,CNOECHO ;(A0) WAIT FOR KEYPRESS, NO ECHO
INT 21H ;(A0) MSDOS FUNCTION CALL
AND AL,7FH ;(A0) 7-BIT ASCII ONLY
; EXTENDED SPECIAL FUNCTIONS
CMP AL,0 ;(A0) IF AL=0,THIS IS AN EXTENDED KEY
JNE CHKKEY ;(A0) THANK GOODNESS, IT ISN'T
; PROCESS EXTENDED KEYS
; DO A SECOND READ
MOV AH,CNOECHO ;(A0) WAIT FOR KEYPRESS, NO ECHO
INT 21H ;(A0) MSDOS FUNCTION CALL
CMP AL,72 ;(A0) UP ARROW
JNE GK1
MOV AL,14
JMP KEYOK
GK1: CMP AL,75 ;(A0) LEFT ARROW
JNE GK2
MOV AL,11
JMP KEYOK
GK2: CMP AL,77 ;(A0) RIGHT ARROW
JNE GK3
MOV AL,7
JMP KEYOK
GK3: CMP AL,80 ;(A0) DOWN ARROW
JNE GK4
MOV AL,13
JMP KEYOK
GK4: CMP AL,83 ;(A0) DEL KEY
JNE GK0 ;(A0) IT'S BAD, TRY AGAIN
MOV AL,7FH
JMP KEYOK ;(A9)
;
; WE'RE RECEIVED A NON-EXTENDED KEY
; SO, NATURALLY ENOUGH, WE'RE GOING TO RUN IT THROUGH
; AN ASCII FILTER TO REMOVE THOSE KEYS THAT WE DON'T
; (THROUGH NO FAULT OF THEIR OWN) LIKE.
;
CHKKEY: CMP AL,08H ;(A9) BACKSPACE IS OK
JE KEYOK ;(A9)
CMP AL,0DH ;(A9) <CR>
JE KEYOK ;(A9)
CMP AL,20H ;(A9) AND SO ARE KEYS .GE SPACE
JAE KEYOK ;(A9)
JMP GK0 ;(A9)
KEYOK: MOV IOCHAR,AL ; (LD1) HOLD A SEC
ADC AX,RSEED1 ; (LD1) PLAY WITH RANDOM BYTES
MOV RSEED1,AX ; (LD1) EACH TIME THRU HERE
XOR RSEED2,AX ; (LD1)
MOV AL,IOCHAR ; (LD1) THANKS FOR WAITING
RET
GETKEY ENDP
; POLL THE KEYBOARD FOR 1/nTH SEC
; NOTE: THIS ROUTINE DOES IT IN 0.11 SEC WITH A FAIR DEGREE
; OF PRECISION, INDEPENDENT OF SYSTEM CLOCK (AT+, PC, ETC.)
TIMLP1 PROC
PUSH DI
TRESET: MOV DI,DLYCNT
TIMIN: MOV AH,CTIME ;(A0) GET TIME FROM REAL TIME CLOCK
INT 21H ;(A0) MSDOS FUNCTION CALL
MOV CLKLOW,DX ;(A0) SAVE 1/100 SEC COUNT
; IS A KEY AVAILABLE
TRY: MOV AH,CINSTAT ;(A0) CHECK STANDARD INPUT STATUS
INT 21H ;(A0) MSDOS FUNCTION CALL
OR AL,AL ;(A0) IS A CHARACTER AVAILABLE
JZ TRY1 ;(A0) NO
POP DI
CLC ; (A0) CLEAR TO SIGNAL A CHAR
RET
; NOKEY
TRY1: MOV AH,CTIME ;(A0) GET TIME FROM REAL TIME CLOCK
INT 21H ;(A0) MSDOS FUNCTION CALL
MOV AX,DX ; (A0) SAVE IT
SUB DX,CLKLOW ;(A0) IF EQUAL TO SAVED TIME
CMP DX,100H
JB TRY ;(A0) .1 SECS HASN'T EXPIRED YET
NEG DX
CMP DX,100H
JB TRY
MOV CLKLOW,AX ;(A0) SAVE 1/100 SEC COUNT
DEC DI ;(A0) DECREMENT DELAY TIMER
JNZ TIMIN ;(A0) IF TIME IS LEFT, TRY AGAIN
; TIME OUT, CHECK FOR A FUNCTION
MOV AX,BX ;(A0) GET ORIGINAL BX (FCN) INTO AX
CALL INCALL ;(A0) ....YES, CALL THE FUNCTION
CMP AX,0 ; IF VALUE RETURNED=0
JNZ INFAIL ;(A0) THEN TRY AGAIN
JMP TRESET
INFAIL: POP DI ; (A0) RESTORE THIS ONE
STC ; (A0) INDICATE A TIMEOUT
RET ; (A0) RETURN WITH TIMEOUT RET IN AX
TIMLP1 ENDP
SUBTTL RDLIN
PAGE
; ------
; RDLIN
; ------
;
; PURPOSE: THIS ROUTINE PROVIDES BUFFERED KEYBOARD INPUT
;
;
; NOTE: NORMALLY LINE INPUT IS PROVIDED BY USING DOS
; INT 21H FUNCTION CALLS WITH [AH]=0AH. BECAUSE WE
; WANT TO INTERCEPT AND IGNORE MANY POSSIBLE KEYS, THIS
; ROUTINE IS NECESSARY.
;
;
; INPUTS: [AH]=0AH, DS:DX ^ INPUT BUFFER. THE FIRST BYTE
; SPECIFIES THE NUMBER OF BYTES THE BUFFER CAN HOLD
; (MUST BE .NE 0). THE SECOND BYTE IS SET TO THE
; NUMBER OF CHARACTERS RECEIVED.
;
; OUTPUTS: THE INPUT BUFFER WILL CONTAIN A FILTERED ASCII STRING
; TERMINATED BY <CR>.
;
; REGISTERS DESTROYED: NONE?
;
;
RDLIN PROC
PUSH AX ;(A9)
PUSH BX ;(A9)
PUSH CX ;(A9)
PUSH DX ;(A9)
PUSH DX ;(A9)
POP BX ;(A9)
MOV BYTE PTR [BX+1],0 ;(A9) RESET THE CHARACTER COUNT
CALL INLOOP ;(A9)
POP DX ;(A9)
POP CX ;(A9)
POP BX ;(A9)
POP AX ;(A9)
RET
RDLIN ENDP