.TITLE VTLIO - VTL I/O Routines .IDENT /1.7/ .ENABL LC ;+ ; ; Free software BY ; Project Software & Development, Inc. ; ; This software is furnished for free and may be used and copied as ; desired. This software or any other copies thereof may be provided or ; otherwise made available to any other person. No title to and ; ownership of the software is hereby transferred or allowed. ; ; The information in this software is subject to change without notice ; and should not be construed as a commitment by PROJECT SOFTWARE ; AND DEVELOPMENT, INC. ; ; PROJECT SOFTWARE assumes no responsibility for the use or reliability ; of this software on any equipment whatsoever. ; ; Project Software & Development, Inc. ; 14 Story St. ; Cambridge, Ma. 02138 ; 617-661-1444 ; ; ; Title: VTLIO.MAC ; Author: Robin Miller ; Date: June 30, 1983 ; ; Description: ; ; This module contains the routines for the terminal I/O. ; ;- .ENABL AMA .NLIST BEX .MCALL DIR$, QIOW$S, GET$ ;+ ; ; Modification History: ; ; November 26, 1985 by Robin Miller. Edit (06), Version 1.7 ; Correctly check for an escape sequence arriving. Previously, ; another character had to be typed after the escape character. ; ; August 14, 1985 by Robin Miller. Edit (05), Version 1.6 ; Change the method used to read an escape sequence. We now ; check the typeahead buffer every clock tick up to a maximum ; limit so response is better. Although this adds overhead, ; I prefer this rather than the long delay previously used. ; ; March 8, 1985 by Robin Miller. Edit (04), Version 1.5 ; Increase the number of clock ticks used when waiting for the ; rest an escape sequence after reading the initial escape. The ; original value was too short for systems with a front-end. ; ; February 13, 1985 by Robin Miller. Edit (03), Version 1.4. ; Add routine to check for and read an escape sequence. We must ; do our own check since we've disabled read with escape sequences. ; ; June 14, 1984 by Robin Miller. Edit (02), Version 1.3 ; Added routine WABIT to wait for a little while after an invalid ; or partial escape sequence error is detected before clearing ; the typeahead buffer. This is needed for VT102 terminals. ; ; June 12, 1984 by Robin Miller. Version 1.2 ; Use read with termination table (IO.RTT) function to simulate ; the control keys used by EDT. Rewrote GETCMD routine for this. ; ; June 2, 1984 by Robin Miller. Edit (01), Version 1.1 ; Add GETM routine to get and mark the next record. ; ;- ; Local definitions: ESCDLY = 15. ; Escape clock ticks delay. (04) ; Local messages: DELSEQ: .BYTE BS,SPACE,BS,0 ; Delete character from screen. ; ; The Read-with-termination table function (IO.RTT) allows control ; characters and space to terminate the read. ; TTABLE: .WORD -1 ; Terminate on all (00-15) .WORD -1 ; control characters (16-31) .WORD 1 ; (32-47) .WORD 0 ; (48-63) .WORD 0 ; (64-79) .WORD 0 ; (80-95) .WORD 0 ; (96-111) .WORD 100000 ; and the delete key. (112-127) .BLKW 8. ; Remaining table zero. BUFCNT: .WORD 0 ; Accumulated buffer byte count. BUFSAV: .WORD 0 ; Saved starting buffer address. BUFSIZ: .WORD 0 ; Original input buffer size. .SBTTL GETCMD - Get a command from the user. ;+ ; ; GETCMD - Gets a command from the user. ; ; This routine is used to read a command from the user. The string input ; is terminated by a null and if exact search string input is disabled, ; the string input is converted to upper case. If the first character ; input is a control character, then we call a routine to determine if the ; control key is defined. If not, the key acts as the terminator. If ; we're prompting for a search string, the control characters are inserted ; as part of the search string (except for ^C, ^U, and ^Z). ; ; Inputs: ; R0 = The buffer address. ; R1 = The buffer size. ; ; Outputs: ; C bit clear/set = success/failure (error or exit). ; ; R0 = The buffer address (string terminated by NULL). ; R1 = The input byte count. ; Includes escape sequence size (if any). ; ; All other registers are preserved. ; ;- GETCMD::JSR R5,$SAVRG ; Save R3 - R5. MOV R0,BUFSAV ; Save starting buffer address. MOV R1,BUFSIZ ; Save the original buffer size. CLR BUFCNT ; Initialize the input count. 10$: QIOW$S #IO.RTT,#TOLUN,#TOEFN,,#TIOSB,, CALL CHKDIR ; Check/report any errors. BCS 100$ ; If CS, we had an error. MOV BUFSAV,R0 ; Set the starting buffer address. ADD TIOSB+2,BUFCNT ; Accumulate the byte count. MOV BUFCNT,R1 ; Copy the current byte count. TSTB TIOSB ; Did we have any I/O errors ? BMI 90$ ; If MI, yes (check for EOF). ; ; On VMS, the terminator is stored in the buffer. On RSX, it isn't. ; MOV R0,R5 ; Copy the input buffer address.(03) ADD R1,R5 ; Point to end of input buffer. (03) MOVB TIOSB+1,(R5) ; Store terminator in buffer. (03) ; Check for the various control keys. MOVB (R5),R3 ; Copy the terminating byte. (03) ; Check for abort characters: CTRL/C or CTRL/U. BIT #B.CTRC,STATUS ; Was CTRL/C typed during read ? BNE 20$ ; If NE, yes (convert to CTRL/U)(03) CMPB #CTRLC,R3 ; Was control/C typed to abort? (03) BNE 25$ ; If NE, no. (03) 20$: MOV #CTRLU,R3 ; Make CTRL/C look like CTRL/U. (03) MOVB R3,TIOSB+1 ; Store in the I/O status block.(03) 25$: CMPB #CTRLU,R3 ; Aborting the command line ? BEQ 120$ ; If EQ, yes. ; Check for start of an escape sequence. CMPB #ESC,R3 ; Is this an escape character ? (03) BNE 30$ ; If NE, no (continue ...) (03) CALL CHKESQ ; Check for an escape sequence. (03) BCC 60$ ; If CC, we found one. (03) ; Check for deleting a character. 30$: CMPB #DEL,R3 ; Are we deleting a character ? BNE 40$ ; If NE, no. CALL DELCHR ; Yes, delete character on screen. BR 55$ ; And continue ... ; ; If searching, only a keypad key terminates the read. If we're ; in command mode, then a keypad key or RETURN terminates the read. ; 40$: BIT #B.SRCH,STATUS ; Prompting for a search string ? BNE 50$ ; If NE, yes (insert into string). CMPB #CR,R3 ; Carriage return the terminator ? BEQ 60$ ; If EQ, yes (this terminates input). ; ; If the first character is a space, treat it like carriage return ; to simulate the UNIX MORE program. Otherwise, see if the control ; character typed is defined to an ASCII command. If it is, we'll ; return that command, otherwise simply display the character. ; TST R1 ; Is this the first character ? BNE 50$ ; If NE, no (skip next check). CMPB #SPACE,R3 ; Is first character a space ? BEQ 60$ ; If EQ, yes (treat like a ). CALL CTRKEY ; Check the control key in (R0). BCC 65$ ; If CC, the key is defined. 50$: CALL TYPCHR ; Display the control character. INC R1 ; Include control key in byte count. 55$: CMP R1,BUFSIZ ; Terminated by buffer full ? BGE 60$ ; If GE, yes (end of this read). MOV R1,BUFCNT ; Set the new buffer byte count. ADD R1,R0 ; Set the next input buffer address. BR 10$ ; And get some more input. ; ; Terminate the input string with a NULL. If an escape sequence ; was entered, the ESCAPE character is overwritten thus preventing ; CUPPER from converting escape sequence bytes to upper case. ; 60$: CLRB (R5) ; Terminate input with a null. 65$: BIT #B.SRCH,STATUS ; Prompting for a search string ? BEQ 70$ ; If EQ, no. BIT #B.XACT,SWMASK ; Are we doing an exact search ? BNE 80$ ; If NE, yes (don't do conversion). 70$: CALL CUPPER ; Convert string in R0 to upper case. 80$: CLC ; Show successful input. BR 130$ ; And use common return ... ; ; We come here on errors. ; 90$: CMPB TIOSB,#IE.EOF ; Was the error "End of file" ? BNE 95$ ; If NE, no (report the error). BIS #B.EXIT,STATUS ; Yes, show we should exit now. BR 120$ ; And return with no input. 95$: CLC ; Show there's no directive error. CALL CHKERR ; Report the I/O status error. 100$: CALL WABIT ; Wait for a little while first. (02) CALL CTYPAH ; Clear the typeahead buffer. ; ; We come here if CTRL/C or CTRL/U typed. ; 120$: CLRB (R0) ; Terminate buffer with null. CLR R1 ; Show nothing was input. SEC ; Show command is being aborted. 130$: RETURN .SBTTL CHKESQ - Check for an escape sequence. ;+ ; ; CHKESQ - Check for an escape sequence. ; ; This routine is called after an escape character is detected. The ; routine calls the wait-a-bit routine to wait for additional characters ; to indicate whether this is an escape sequence. If there are, we read ; the next two characters and set the status code to indicate an escape ; sequence was read. This method appears to work on RSX-11M/M+ & VMS. ; ; Inputs: ; R1 = The total byte count. ; R5 = The ending buffer address. ; ; Outputs: ; C bit clear/set = escape sequence/no escape sequence. ; ; TIOSB = Filled with IS.ESQ for escape sequence. ; R1 = Adjusted to include escape sequence size. ; ; All other registers are preserved. ; ;- CHKESQ::CALL $SAVAL ; Save all registers. MOV R1,R4 ; Save the input byte count. ; Sit in a delay loop waiting for escape sequence. MOV #ESCDLY,R2 ; Retry up to this limit. (05) 10$: MOV #1,R0 ; Wait for 1 (05) MOV #TICKS,R1 ; clock tick. (05) CALL DELAY ; Do the delay. (05) CALL GTYPAH ; Get the typeahead count -> R1.(05) BCS 20$ ; If CS, nothing in typeahead. (06) CMP R1,#2 ; Do we have remaining bytes ? (05) BHIS 30$ ; If HIS, yes. (06) 20$: SOB R2,10$ ; Loop until limit reached. (06) SEC ; Show no escape sequence read. (05) BR 100$ ; Use common return ... (05) ; Got the escape sequence, now go read it. 30$: MOV #2,R1 ; Only read one escape sequence.(06) ADD R1,R4 ; Adjust the buffer byte count. INC R4 ; Also include escape character. CLRB (R5)+ ; Clear the escape character. QIOW$S #IO.RNE,#TOLUN,#TOEFN,,#TIOSB,, ; Read escape seq. CALL CHKERR ; Check/report any errors. BCS 100$ ; If CS, we had an error. MOV #IS.ESQ,TIOSB ; Show escape sequence read. 100$: MOV R4,4(SP) ; Pass back byte count in R1. (05) RETURN .SBTTL DELCHR - Delete character from the screen. ;+ ; ; DELCHR - Delete a character from the screen. ; ; Inputs: ; R1 = The total byte count. ; R5 = The ending buffer address. ; ; Outputs: ; R1 = The adjusted byte count. ; ; All other registers are preserved. ; ;- DELCHR: JSR R5,$SAVRG ; Save R3 - R5. TST R1 ; Anymore characters to delete ? BEQ 100$ ; If EQ, no. MOV #DELSEQ,R4 ; Set delete sequence address. CALL WRITE ; Write the delete sequence. DEC R1 ; Adjust the input byte count. MOV R5,R3 ; Copy the buffer address. DEC R3 ; Point to the last character. CMPB (R3),#SPACE ; Deleting a control character ? BHIS 100$ ; If HIS, no. CALL CHKGRA ; Character displayed in graphics ? BCC 100$ ; If CC, yes. CALL WRITE ; Yes, delete the up arrow. 100$: RETURN .SBTTL TYPCHR - Display a control character. ;+ ; ; TYPCHR - Display a control character. ; ; Inputs: ; R3 = The control character to display. ; ; Outputs: ; All registers are preserved. ; ;- TYPCHR::CALL $SAVAL ; Save all registers. MOV #FMTBUF,R0 ; Set the output buffer address. CALL DOCHAR ; Copy/format this character. JMP VTYPE ; And display at the terminal. .SBTTL WABIT - Wait for a little while. ;+ ; ; WABIT - Wait for a little while. ; ; This routine is called after an invalid or partial escape sequence is ; detected to wait for additional characters arriving from the escape ; sequence. If we don't wait for a short while on VT102 terminals, the ; clearing of the typeahead buffer doesn't discard the extra characters. ; It appears the VT102 terminals send the escape sequence at a slower ; rate than a normal VT100 terminal. ; ; Inputs: ; None. ; ; Outputs: ; All registers are preserved. ; ;- WABIT:: JSR R2,$SAVVR ; Save R0 - R2. MOV #ESCDLY,R0 ; Wait a few (04) MOV #TICKS,R1 ; clock ticks. JMP DELAY ; Do delay and return. .SBTTL WRITE - Write a message to the terminal. ;+ ; ; WRITE - Write a message to the terminal. ; ; This routine is used to write a message terminated by null to the ; terminal. It also makes sure that writes do not exceed 512 bytes ; in length. This is done becuase one of the VMS sysgen parameters ; prevents us from writing the entire message all at once. RSX-11M ; allows us to write up to 8128 bytes in length with one QIO. ; ; Inputs: ; R4 = Message address terminated by NULL. ; ; Outputs: ; All registers are preserved. ; ;- WRITE:: CALL $SAVAL ; Save all registers. MOV R4,R0 ; Copy the buffer address. CALL GETLEN ; Calculate the length --> R1. MOV #8128.,R3 ; Setup the maximum write size. TST VAXFLG ; Are we running on VAX/VMS ? BEQ 10$ ; If EQ, no (presume RSX-11M). MOV #512.,R3 ; Else, set smaller write size. 10$: CLR R2 ; Presume a single write. CMP R1,R3 ; Is the length too large ? BLE 20$ ; If LE, no (write it). ; The length is too big, adjust into 512 bytes length. MOV R1,R2 ; Save the message length. MOV R3,R1 ; Set the maximum message length. 20$: CALL WRITIT ; Write the message. BCS 100$ ; If CS, we had an error. TST R2 ; Is there any more to write ? BEQ 100$ ; If EQ, no (we're all done). ; Adjust the buffer address and the message length. ADD R1,R0 ; Yes, adjust the buffer address SUB R1,R2 ; and the message length. MOV R2,R1 ; Set the new message length. BR 10$ ; And continue ... 100$: RETURN .SBTTL WRITIT - Write a message to the terminal. ;+ ; ; WRITIT - Write a message to the terminal. ; ; Inputs: ; R0 = The buffer address. ; R1 = The buffer byte count. ; ; Outputs: ; Carry clear/set = success/failure. ; ; All registers are preserved. ; ;- WRITIT::QIOW$S #IO.WAL!TF.CCO,#TOLUN,#TOEFN,,#TIOSB,, CALL CHKERR ; Check/report any errors. RETURN .SBTTL GET - Get record from the input file. ;+ ; ; GET - Get next record from the input file. ; ; This routine gets the next record from the input file. If end of file ; is encountered, then the end of file flag is set in the status word. ; ; Inputs: ; R5 = The file entry address. ; ; Outputs: ; C bit clear/set = success/failure. ; ; All registers are preserved. ; ;- GET:: JSR R2,$SAVVR ; Save R0 - R2. MOV O.FDB(R5),R0 ; Copy the FDB address. GET$ R0 ; Get the next record. BCC 30$ ; If CC, success. CMPB F.ERR(R0),#IE.EOF ; Was the error end of file ? BNE 10$ ; If NE, no (report the error). BIS #S.EOF,(R5) ; Yes, show we're at end of file. BR 20$ ; And continue ... 10$: CALL FCSERR ; Report the error message. 20$: SEC ; Show failure ... 30$: RETURN .SBTTL GETM - Get/Mark the next input record. ;+ ; ; GETM - Get and mark the next input record. (01) ; ; This routine is used to mark and then get (read) the next input record. ; The record is marked first because the virtual block number and the byte ; displacement will be pointing to the next record instead of the current ; after we get the next record. ; ; Implicit Inputs: ; IENTRY = The active file entry address. ; ; Outputs: ; C bit clear/set = success/failure (from GET routine). ; ; All registers are preserved. ; ;- GETM:: JSR R5,$SAVRG ; Save R3 - R5. MOV IENTRY,R5 ; Copy the file entry address. CALL MARKER ; Mark the record position. CALL GET ; Get the next input record. BCC 100$ ; If CC, success ... BIT #S.EOF,(R5) ; Did we run into end of file ? BEQ 90$ ; If EQ, no. SUB #1,O.CREC+2(R5) ; Yes, backup the SBC O.CREC(R5) ; current record number. 90$: SEC ; Show failure ... 100$: RETURN .END