Trailing-Edge
-
PDP-10 Archives
-
bb-kl11m-bm
-
t20src/ptycon.mac
There are 31 other files named ptycon.mac in the archive. Click here to see a list.
; Edit= 35 to PTYCON.MAC on 7-Oct-88 by GSCOTT
;Avoid losing commands due to a small window when interrupt are turned on in
;and we are processing a command file.
; Edit= 34 to PTYCON.MAC on 22-Jun-88 by GSCOTT
;This edit greatly cleans up PTYCON code to fix bugs and small enhancements.
;Cleanup connect code and have it display output from other subjobs one once
;every 5 seconds instead of while it happens. Go back to a WAIT JSYS instead
;of a BIN when connected to a subjob. Change TRYLOG and CONFIRM macros to
;subroutines. Instead of sprinkling COMNDs all over, have common routine
;handle COMND calls. Remove code in GETSJB that wrote into the literal pool.
;Allow for up to 9 character subjob names, including proper and complete
;validity checks for their names. Don't force uppercase for all PTYCON
;commands. Make single line commands sent to subjobs not eat any escapes and
;rework strange control-C trap. Don't leave TTY JFN open when exiting.
;Cleanup and enhance HELP command. Output version number in help command, log
;file, and saved input file. Repaginate and insert TOC. Update copyright
;notice.
; *** Edit 33 to PTYCON.MAC by GSCOTT on 13-Aug-87, for SPR #21652
; After installing edit 32, PTYCON doesn't go back into terminal input wait
; properly if a command is being typed in at the same time that output from a
; subjob is being displayed. This edit also makes PTYCON check for subjob
; output to be displayed after each "subjob-text" command.
; *** Edit 32 to PTYCON.MAC by GSCOTT on 14-Apr-87, for SPR #21346
; Fix PTYCON not to generate extra PTYOPC interrupts, not to enable PTYOPC when
; connected to a subjob, and to reenter a WAIT JSYS instead of going back to
; COMND when PTYOPC interrupts us causing a PTY Hungry interrupt.
; *** Edit 31 to PTYCON.MAC by LOMARTIRE on 31-Mar-86, for SPR #20838
; Prevent PDL overflow after CONTROL-C processing
; UPD ID= 143, SNARK:<6.1.UTILITIES>PTYCON.MAC.11, 14-Jun-85 13:22:02 by EVANS
;TCO 6.1.1450 - Make PUSH know about DEFAULT-EXEC:
; UPD ID= 118, SNARK:<6.1.UTILITIES>PTYCON.MAC.10, 30-Apr-85 14:53:44 by LOMARTIRE
;TCO 6.1.1349 - In PTYINT, restore the ACs in the right place to avoid panic
; UPD ID= 617, SNARK:<6.UTILITIES>PTYCON.MAC.9, 23-Oct-84 16:23:25 by LOMARTIRE
;TCO 6.2248 - Make the fields of the WHAT command line up in columns.
; UPD ID= 545, SNARK:<6.UTILITIES>PTYCON.MAC.8, 6-Jun-84 15:28:49 by LOMARTIRE
;TCO 6.2079 - Change order of command parse and fix subjob name parsing
; UPD ID= 473, SNARK:<6.UTILITIES>PTYCON.MAC.7, 8-Feb-84 10:38:41 by EVANS
;Add flag to edit number so I VER will display it in decimal.
; UPD ID= 349, SNARK:<6.UTILITIES>PTYCON.MAC.6, 7-Sep-83 16:32:09 by LOMARTIRE
;More TCO 6.1566 - Clean up comments and error messages
; UPD ID= 286, SNARK:<6.UTILITIES>PTYCON.MAC.5, 20-May-83 13:50:46 by LOMARTIRE
;More TCO 6.1566 - Don't append CR and LF to end of one-liner; only append CR
; UPD ID= 256, SNARK:<6.UTILITIES>PTYCON.MAC.4, 12-Apr-83 15:56:19 by LOMARTIRE
;TCO 6.1595 - Fix hanging while processing commands from .ATO file
; UPD ID= 255, SNARK:<6.UTILITIES>PTYCON.MAC.3, 12-Apr-83 12:58:33 by LOMARTIRE
;More TCO 6.1566 - Fix problem with printing of subjob output header
; UPD ID= 243, SNARK:<6.UTILITIES>PTYCON.MAC.2, 1-Apr-83 09:07:34 by LOMARTIRE
;TCO 6.1566 - Convert command parsing routines to COMND JSYS
; UPD ID= 65, FARK:<5-1-WORKING-SOURCES.UTILITIES>PTYCON.MAC.4, 2-Dec-82 11:53:20 by LOMARTIRE
;Edit 16 - Restrict access to PTY JFNs so that lower EXECs don't CLOSE them
; UPD ID= 18, FARK:<5-WORKING-SOURCES.UTILITIES>PTYCON.MAC.3, 5-May-82 13:15:16 by MOSER
;EDIT 15 - CHANGE EDIT NUMBER TO 15.
; UPD ID= 5, FARK:<5-WORKING-SOURCES.UTILITIES>PTYCON.MAC.2, 5-Apr-82 09:14:41 by DONAHUE
;Edit 8 - Release log file at exit so LPT files printed
;<5.UTILITIES>PTYCON.MAC.7, 28-Oct-81 15:34:11, EDIT BY GRANT
;Change major version to 5
; UPD ID= 23, SNARK:<5.UTILITIES>PTYCON.MAC.6, 13-Aug-81 09:40:16 by DONAHUE
;TCO 5.1452 - Log the filename to a GET command into the log file
; UPD ID= 20, SNARK:<5.UTILITIES>PTYCON.MAC.5, 6-Aug-81 15:27:30 by DONAHUE
;TCO 5.1445 - If <esc> terminates jobname in DEFINE command, wait for more input
; UPD ID= 1768, SNARK:<5.UTILITIES>PTYCON.MAC.4, 25-Mar-81 17:48:44 by GRANT
;Update Copyright
; UPD ID= 1500, SNARK:<5.UTILITIES>PTYCON.MAC.3, 26-Jan-81 16:53:59 by MURPHY
;UPDATE LOG FILE LESS OFTEN
;IMPLEMENT SAVE (INPUT TO FILE) COMMAND
; UPD ID= 997, SNARK:<5.UTILITIES>PTYCON.MAC.2, 11-Sep-80 10:55:07 by SCHMITT
;TCO 5.1143 - Replace DING fork with a TIMER mechanism for dinging terminal
; UPD ID= 379, SNARK:<4.1.UTILITIES>PTYCON.MAC.3, 26-Mar-80 15:49:52 by KONEN
;TCO 4.1.1125 -- Correct PTY buffers overlapping each other
; UPD ID= 243, SNARK:<4.1.UTILITIES>PTYCON.MAC.2, 4-Feb-80 14:53:28 by MURPHY
;PREVENT HANG WHEN HIGH OUTPUT RATE FROM SUBJOB ON 2020 (TIMING PROB)
;<4.UTILITIES>PTYCON.MAC.9, 24-Oct-79 15:38:07, EDIT BY ENGEL
;ADD CODE TO AT PTYOU3 TO CHECK FOR PTY BUFFER FULL. DO DIBE IF IT IS FULL.
;<4.UTILITIES>PTYCON.MAC.8, 9-Oct-79 17:12:38, Edit by SCHMITT
;TCO 4.2522 - Remove RLJFN after GET for push to EXEC and supporting changes
;<4.UTILITIES>PTYCON.MAC.7, 27-Sep-79 18:10:48, EDIT BY SCHMITT
;TCO 4.2497 - Cure ghost characters from appearing in PTY's input buffer
;<4.UTILITIES>PTYCON.MAC.6, 13-May-79 13:38:16, EDIT BY MILLER
;<4.UTILITIES>PTYCON.MAC.5, 12-May-79 13:12:46, EDIT BY MILLER
;<4.UTILITIES>PTYCON.MAC.4, 12-May-79 13:11:59, EDIT BY MILLER
;<4.UTILITIES>PTYCON.MAC.3, 12-May-79 13:09:56, EDIT BY MILLER
;MORE
;<4.UTILITIES>PTYCON.MAC.2, 11-May-79 15:45:23, EDIT BY MILLER
;MAKE VARIOUS FIXES TO INSURE THAT CHARACTERS TYPED ON THE TTY
; HAVE THE CORRECT PARITY.
;<4.UTILITIES>PTYCON.MAC.1, 12-Mar-79 14:13:24, EDIT BY KONEN
;UPDATE COPYRIGHT FOR RELEASE 4
; COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1976, 1988.
; ALL RIGHTS RESERVED.
;
; THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
; ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
; INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
; COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
; OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
; TRANSFERRED.
;
; THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
; AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
; CORPORATION.
;
; DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
; SOFTWARE ON EQUIPMENT THAT IS NOT SUPPLIED BY DIGITAL.
TITLE PTYCON - Controller For Jobs On PTYs
SUBTTL PETER M. HURLEY APRIL 18,1974
SEARCH MONSYM,MACSYM
SALL
.CPYRT <<1976, 1988>>
IFNDEF .PSECT,<.DIRECT .XTABM>
Subttl Table of Contents
; Table of Contents for PTYCON
;
; Section Page
;
;
; 1. Definitions
; 1.1 Version and Entry Vector . . . . . . . . . . . 5
; 1.2 ACs and Flags . . . . . . . . . . . . . . . . 7
; 1.3 Static Storage Sizes . . . . . . . . . . . . . 8
; 1.4 Macros . . . . . . . . . . . . . . . . . . . . 9
; 2. Initialization . . . . . . . . . . . . . . . . . . . . 11
; 3. Commands
; 3.1 Command Level Parsing . . . . . . . . . . . . 14
; 3.2 Command Tables . . . . . . . . . . . . . . . . 18
; 3.3 Single Line to Subjob Command . . . . . . . . 20
; 3.4 Accept Command . . . . . . . . . . . . . . . . 22
; 3.5 Bell Command . . . . . . . . . . . . . . . . . 23
; 3.6 Connect Command . . . . . . . . . . . . . . . 24
; 3.7 Define Command . . . . . . . . . . . . . . . . 25
; 3.8 Discard Command . . . . . . . . . . . . . . . 28
; 3.9 Exit Command . . . . . . . . . . . . . . . . . 29
; 3.10 Get Command . . . . . . . . . . . . . . . . . 30
; 3.11 Help Command . . . . . . . . . . . . . . . . . 31
; 3.12 Kill Command . . . . . . . . . . . . . . . . . 32
; 3.13 Log Command . . . . . . . . . . . . . . . . . 33
; 3.14 No Command . . . . . . . . . . . . . . . . . . 34
; 3.15 Push Command . . . . . . . . . . . . . . . . . 35
; 3.16 Redefine Command . . . . . . . . . . . . . . . 37
; 3.17 Refuse Command . . . . . . . . . . . . . . . . 39
; 3.18 Save Command . . . . . . . . . . . . . . . . . 40
; 3.19 Silence Command . . . . . . . . . . . . . . . 41
; 3.20 What Command . . . . . . . . . . . . . . . . . 42
; 4. Parsing Routines
; 4.1 Perform COMND JSYS . . . . . . . . . . . . . . 46
; 4.2 Common Parsing Errors . . . . . . . . . . . . 47
; 4.3 Parse Comma or Confirm . . . . . . . . . . . . 49
; 4.4 Parse Filename . . . . . . . . . . . . . . . . 50
; 4.5 Parse Subjob Name or Number . . . . . . . . . 51
; 4.6 Parse List of Subjob Names or Numbers . . . . 52
; 4.7 Add/Delete/Find Subjob Name . . . . . . . . . 53
; 5. Connect to PTY
; 5.1 Main Loop . . . . . . . . . . . . . . . . . . 54
; 5.2 Get Character from TTY . . . . . . . . . . . . 57
; 5.3 Get Character from File . . . . . . . . . . . 58
; 6. TTY Input Routines
; 6.1 Open/Close Binary TTY JFN . . . . . . . . . . 59
; 6.2 Set/Reset TTY Modes . . . . . . . . . . . . . 60
; 6.3 Escape (Trap) Character Interrupt . . . . . . 61
; 6.4 Control-C Interrupt . . . . . . . . . . . . . 62
; 6.5 TTY Input Interrupt . . . . . . . . . . . . . 64
; 6.6 Set up Binary or Primary JFN . . . . . . . . . 65
Subttl Table of Contents (page 2)
; Table of Contents for PTYCON
;
; Section Page
;
;
; 7. Command File Input Routines
; 7.1 Command Level Read . . . . . . . . . . . . . . 66
; 7.2 Read Character From Command File . . . . . . . 68
; 7.3 Get More Command File Characters . . . . . . . 69
; 7.4 Close Command File . . . . . . . . . . . . . . 70
; 7.5 Echo Command Line . . . . . . . . . . . . . . 71
; 8. PTY Output Routines
; 8.1 Main Loop . . . . . . . . . . . . . . . . . . 72
; 8.2 Display Standard Header . . . . . . . . . . . 73
; 8.3 Display One Subjob Output . . . . . . . . . . 74
; 8.4 Periodic Check . . . . . . . . . . . . . . . . 75
; 9. TTY Output Routines
; 9.1 Output CRLF . . . . . . . . . . . . . . . . . 76
; 9.2 Output Character to TTY . . . . . . . . . . . 77
; 9.3 Output String to TTY . . . . . . . . . . . . . 78
; 10. Log File Output Routines
; 10.1 Open Log File . . . . . . . . . . . . . . . . 79
; 10.2 Start Log File . . . . . . . . . . . . . . . . 80
; 10.3 Write Errors and Close Log File . . . . . . . 81
; 10.4 Checkpoint Log File . . . . . . . . . . . . . 82
; 10.5 Output Character to Log File . . . . . . . . . 83
; 10.6 Send String to Log File . . . . . . . . . . . 84
; 11. Saved Input Routines
; 11.1 Open Saved Input File . . . . . . . . . . . . 85
; 11.2 Start Saved Input File . . . . . . . . . . . . 86
; 11.3 Write Errors and Close File . . . . . . . . . 87
; 11.4 Checkpoint Saved Input File . . . . . . . . . 88
; 11.5 Save PTY Typescript In File . . . . . . . . . 89
; 12. PTY Related Routines
; 12.1 New Subjob Number . . . . . . . . . . . . . . 90
; 12.2 Get PTY JFN . . . . . . . . . . . . . . . . . 91
; 12.3 Initialize PTY Line . . . . . . . . . . . . . 93
; 12.4 Kill a Subjob . . . . . . . . . . . . . . . . 94
; 12.5 Check PTY Hunger . . . . . . . . . . . . . . . 95
; 12.6 Send Character to PTY . . . . . . . . . . . . 96
; 12.7 Read and Buffer Output From PTY . . . . . . . 98
; 12.8 Buffer Character From PTY . . . . . . . . . . 99
; 12.9 Get Buffered Character . . . . . . . . . . . . 100
; 12.10 Flush Output From PTY . . . . . . . . . . . . 101
; 12.11 PTY Interrupt Routines . . . . . . . . . . . . 102
; 13. Error Handling Routines
; 13.1 Panic Channel Interrupt . . . . . . . . . . . 104
; 13.2 Error Macro Handling Routines . . . . . . . . 105
; 13.3 JSYS Error Handler . . . . . . . . . . . . . . 106
; 14. Bell Ringing Routines
; 14.1 Start/Stop Bell . . . . . . . . . . . . . . . 107
; 14.2 Bell Timer Interrupt . . . . . . . . . . . . . 108
Subttl Table of Contents (page 3)
; Table of Contents for PTYCON
;
; Section Page
;
;
; 15. Subroutines
; 15.1 Display Subjob Name and/or Number . . . . . . 109
; 15.2 Manipulate PI System . . . . . . . . . . . . . 110
; 15.3 Check if any Subjobs Logged In . . . . . . . . 111
; 15.4 Save and Restore ACs . . . . . . . . . . . . . 112
; 16. Tables
; 16.1 Interrupt System . . . . . . . . . . . . . . . 113
; 16.2 Command Parsing . . . . . . . . . . . . . . . 114
; 17. General Storage . . . . . . . . . . . . . . . . . . . 116
; 18. End of PTYCON . . . . . . . . . . . . . . . . . . . . 119
SUBTTL Definitions -- Version and Entry Vector
;Version number definitions
VMAJOR==7 ;Major version of PTYCON
VMINOR==0 ;Minor version number
VEDIT==^D35 ;Edit number
VWHO==0 ;Who last edited program (0=DEC Development)
VPTYCN==<VWHO>B2+<VMAJOR>B11+<VMINOR>B17+VI%DEC+VEDIT
;[34] Program entry vector
ENTVEC: JRST PTYSRT ;Starting location
JRST PTYCON ;Reenter location
VPTYCN ;Version number
EVLEN==.-ENTVEC ;Entry vector length
;[34] ASCIZ version for output in HELP command. Since MACRO doesn't convert
;binary to decimal for us, we have to do it this slow way.
DEFINE ADDCHR(A),< ;Add one character to string
IFE ...,..==35 ;If zero mask set shift to far left of word
...==...+<A>_.. ;Shift then combine character with mask
IFE ..-1,< ;If we have a full word now
EXP ... ;Generate it
...==0> ; and reset the mask
..==..-7 ;Don't shift quite so far next time
> ;End of ADDCHR
DEFINE ADDSTR(STR),< ;Output string
IRPC <STR>,<ADDCHR <"STR">>
> ;End of ADDSTR
DEFINE ADDNUM(NUM,%S1,%S2),< ;Output decimal number
%S1==NUM/^D10 ;Divide furnished number by ten
%S2==NUM-<%S1*^D10> ;Get units digit of that number
IFN %S1,<ADDNUM %S1> ;Recurse if more to do
ADDCHR (<"0"+%S2>) ;Add that units digit in
> ;End of ADDNUM
;Now ready to make PTYCON version string.
...==0 ;Start with zero mask
SVN: ADDSTR (<PTYCON >) ;Program's name and a space
ADDNUM (VMAJOR) ;Program's major version
IFN VMINOR,< ;If there is a minor version
ADDCHR (".") ; add in a dot
ADDNUM (VMINOR) ; and that minor version
> ;End of IFN VMINOR
ADDCHR (<"(">) ;Open up paren for edit number
ADDNUM (VEDIT) ;Add the edit number
ADDCHR (<")">) ;Close thesis
IFN VWHO,< ;If someone fooling with PTYCON today
ADDCHR ("-") ;Add a hyphen
ADDNUM (VWHO) ; and the who field
> ;End of IFN VWHO
ADDCHR (0) ;Append a null to end string
EXP ... ;Generate last word on this subject
SUBTTL Definitions -- ACs and Flags
;ACs we will use today
F=0 ;[34] Flags
A=1 ;Temporary AC, not saved by subroutines
B=2 ;Temp
C=3 ;Temp
D=4 ;Temp
E=5 ;Temp
Q1=6 ;Preserved ACs, must be saved
Q2=7 ;Preserved AC
Q3=10 ;Preserved AC
P1=11 ;Preserved AC
P2=12 ;Preserved AC
P3=13 ;Preserved AC
P4=14 ;Preserved AC
I=15 ;Preserved, holds current subjob index
CX=16 ;Supertemp for use by macros
P=17 ;Push down AC
;Flags in F
NOFLAG==1B1 ;"NO" was typed in a command if set
TIFLAG==1B2 ;Set when we have been into TI recently
TOFLAG==1B3 ;Set whenever a char is displayed on TTY
PTWATF==1B4 ;Waiting for a PTY interrupt if set
TTWATF==1B5 ;Waiting for a TTY interrupt if set
NOINTF==1B6 ;Not ok to display PTY output now if set
IGNORF==1B8 ;Discard output from this subjob if set
SILNCF==1B9 ;Turn off echoing of command file if set
PUSHF==1B10 ;Set when pushed down to EXEC
REFALF==1B11 ;REFUSE ALL command was typed if set
DISALF==1B12 ;DISCARD ALL command was typed if set
NOBELF==1B13 ;Disable bell flag if set
DINGF==1B14 ;Ding fork on if set
PEEKF==1B15 ;Peeked at next character if set
;Flags in PTYSTS.
PTDISF==1B1 ;Discard output from this PTY
PTREFF==1B2 ;Refuse output from this PTY
;Default escape character.
STDECH=="X"-100 ;Standard escape character
STDESC==1B0_<-STDECH> ;Channel mask for escape character
SUBTTL Definitions -- Static Storage Sizes
;Static storage area definitions.
LC=300000 ;Local storage starts here
PDLEN==30 ;Size of the stack
CBUFSZ==400 ;[32] Command buffer size
ABUFSZ==50 ;[32] Atom buffer size
STRNGL==50 ;Typical string length in words
MAXSTC==STRNGL*5-1 ;Typical string length in characters
JITBLN==.JIBAT+1 ;Size of GETJI block used in WHAT command
;Subjob related storage, don't change these unless you are real careful.
MAXPTY==30 ;Maximum number of subjobs allowed
MAXPTC==^D80 ;Size of the PTY buffer
PTYNCH==6 ;# of interrupt channels for PTYs
PTYCHN==^D24 ;Starting at 24, 2 channels per PTY
PTYBUF=400000 ;Start of PTY buffers
PTYBSZ==10000 ;Size of buffer for each PTY
PTYMXC==PTYBSZ*4 ;Number of characters in a buffer
SUBTTL Definitions -- Macros
;[34] BUG macro is used to output a fatal PTYCON error. The bug type can can
;be either HLT (which does a HALTF and will not allow user to continue) or CHK
;(which just outputs the message and returns).
DEFINE BUG(X,Y)<
IFIDN <X><CHK>,<
CALL [ JSP CX,DOBUG
ASCIZ \
? Unexpected PTYCON error - Y
\]
>
IFIDN <X><HLT>,<
CALL [ JSP CX,DOBUGH
ASCIZ \
? Unexpected PTYCON error - Y
\]
>
>
;[34] The ERRMES macro is used to output a user fatal type error message.
DEFINE ERRMES (MESSAGE)<
CALL [ JSP CX,DOERRM
ASCIZ \MESSAGE
\]>
;[34] The JERMES macro is used to output a user fatal type error message and
;the last TOPS-20 JSYS error.
DEFINE JERMES (MESSAGE)<
CALL [ JSP CX,DOJERM
ASCIZ \MESSAGE - \]>
;[34] The WRNMES and TMSG macros are identical and cause just the message to be
;printed on the terminal.
DEFINE WRNMES (MESSAGE)<
CALL [ JSP CX,DOWRNM
ASCIZ/MESSAGE/]>
DEFINE TMSG (MESSAGE)<
CALL [ JSP CX,DOWRNM
ASCIZ \MESSAGE\]>
;[34] The SYSGET macro is used in PTYCON initialization to get some information
;stored about the system configuration.
DEFINE SYSGET(X)<
MOVE A,[SIXBIT/X/]
SYSGT
HRRZM B,X>
;Macro to parse noise words
DEFINE NOISE (GWRD) <
MOVEI B,[FLDDB. .CMNOI,,<-1,,[ASCIZ /GWRD/]>]
CALL COMANE>
;Macro to allocate storage space
DEFINE ALC (NAM,SIZ)<
NAM=LC
LC=LC+SIZ>
SUBTTL Initialization
;Program initialization
PTYSRT: RESET ;FRESH START
PTYCON: MOVE P,[IOWD PDLEN,PDL] ;SET UP STACK
MOVX F,NOINTF ;[34] Clear all flags except NOINTF
SETZM EXECFK ;[34] No lower fork
HRRZS NAMTBL ;[34] Clear subjob name table
SETZM LOGJFN ;[34] No log file
SETZM SVIJFN ;[34] No saved input file
SETZM JFNIP ;[34] No temp JFN right now
;Get parameters from the monitor
MOVE A,[SIXBIT/PTYPAR/] ;Get number of PTYs in system,,first PTY
SYSGT ; from the monitor
HRRZM A,FIRPTY ;Store TTY correspondence for PTYs
HLRZS A ;Get number of PTYs in system
MOVEM A,SYSPTY ;Remember the number of PTYs on system
CAILE A,MAXPTY ;Is it more than we can handle?
MOVEI A,MAXPTY ;Yes, load our maximum
MOVEM A,NUMPTY ;Remember number of PTYs we can handle
SYSGET (TTYJOB) ;Get and store table number of GETAB entries
SYSGET (JOBPNM) ; for these
SYSGET (SNAMES) ; four critical
SYSGET (JOBRT) ; monitor tables
;Set up interrupt system
SKIPN A,ESCMSK ;Terminal interrupt word for connect set up?
MOVX A,STDESC!1B<.TICTI> ;No, load default one
MOVEM A,ESCMSK ;Set up enable mask for use when connected
SKIPN A,TIMASK ;Terminal interrupt word for commands set up?
MOVX A,STDESC!1B<.TICTI>!1B<.TICCC>!1B<.TICCO> ;No, load default
MOVEM A,TIMASK ;Set up terminal interrupt word for cmd level
SKIPN A,TRPCHR ;Trap character set up yet?
MOVEI A,STDECH ;No, get default escape character
MOVEM A,TRPCHR ;Set trap character
MOVEI A,.FHSLF ;Set up capabilities of this fork
RPCAP% ;Get current capabilities
TXNN B,SC%CTC ;Can we enable Control-C intercept?
BUG(HLT,<Cannot enable for CONTROL-C intercept>) ;No
TXON C,SC%CTC ;Yes, then do it if not enabled
EPCAP% ;Set this enable bit
MOVEI A,.FHSLF ;Now initialize the interrupt system
DIR ;First turn it off
SETOM PICNT ;Initialize level of PIOFFs
MOVE B,[LEVTAB,,CHNTAB] ;Set up PI system's
SIR ; channel and level table address
HRLZ A,TRPCHR ;Enable escape character
HRRI A,TRPCHN ; on its own channel
ATI ;Attach Terminal Interrupt character
MOVE A,[.TICCC,,CTLCHN] ;[34] Set up control C interrupt channel
ATI ;Assign control-c to channel
MOVE A,[.TICTI,,TINCHN] ;[34] Assign tty input channel
ATI ;Assign TTY interrupts to channel
MOVEI A,.FHSLF ;For this fork
MOVE B,ONCHNS ; and these channels
AIC ; activate all desired interrupt channels
EIR ;Enable PI system
MOVX B,1B<PTYOCN> ;Start up PTY output check
IIC ; by causing that first interrupt now
;Get and set terminal modes, open binary channel for terminal
MOVEI A,.PRIIN ;For this terminal
GDSTS ;Get the device status bits
ERCAL [ SETZM B ;Error?
RET] ; Yes, no parity
ANDX B,GD%PAR ;Isolate interesting bit
MOVEM B,ADDPAR ;Remember it for later
CALL ASCTER ;[34] Use non-binary channel for now
CALL OPNTTY ;[34] Open the TTY for binary (8 bit)
; JRST COMLVL ;Go to command level
SUBTTL Commands -- Command Level Parsing
;Command level parsing begins here. Can come here from all over, so we need
;to reset the stack. Insures that terminal is in correct mode for parsing
;commands. Closes LOG file and reopens it if needed.
COMLVL: MOVE P,[IOWD PDLEN,PDL] ;[34] Set up a fresh stack pointer
TXO F,NOINTF ;[34] Don't display PTY output now
MOVE A,CMDSBK+.CMRTY ;[34] Print prompt
CALL TTSOUT ;[34] on the terminal
TXZ F,TIFLAG!TOFLAG ;[34] Need TI just once now, no output done yet
SETZM CMDBUF
HRLI A,CMDBUF ;CLEAR COMMAND AND ATOM BUFFERS
HRRI A,CMDBUF+1
BLT A,GTJBLK-1
MOVEI A,CBUFSZ*5-1 ;RESET BUFFER SIZE
MOVEM A,CMDSBK+.CMCNT
SKIPE RDJFN ;Reading from file?
CALL GCNVT ;Yes, read and convert command from file
;[34] Here to restart or wait for a command. We come back here to COMSTR if we
;have been interrupted to check for PTY typeout and there was nothing to type
;out, so we have to reset the stack here. The TIWAIT routine will return soon
;as a character is typed by the user for us to read as a command.
COMSTR: MOVE P,[IOWD PDLEN,PDL] ;[34] Get new stack in case here from interrupt
CALL RELJFN ;[34] Release any temp JFN used in parse
CALL CKPLOG ;[34] Check if time to checkpoint log file
CALL CKPSVI ;[34] Check if fime to checkpoint saved input
SKIPL CURENT ;[34] Been doing commands recently?
CALL SETTTY ;[34] Nope
SETOB I,LSTHDR ;Always clear subjob index
MOVEM I,CURENT ;Save current index of job (no current one)
MOVEI A,.NULIO ;Don't print prompt again
HRRM A,CMDSBK+.CMIOJ ; by setting COMND's output JFN to null
SKIPN RDJFN ;[35] Are we reading from a file?
TXZ F,NOINTF ;[35] Yes, all PTY ints to display text for us
CALL TIWAIT ;[34] Wait for terminal input to happen
;[32] Here when ready to read a command from file or terminal.
COM1: MOVEI B,[FLDDB. .CMINI] ;Get initialization function block address
CALL COMAND ;[34] Do that CMINI function
JRST COMERR ;[34] Should never happen
SKIPN RDJFN ;[34] Reading from file?
JRST COM0 ;[34] Nope, nothing fancy to do
MOVE A,CMDCNT ;[34] Get character count
MOVEM A,CMDSBK+.CMINC ;[34] Set as number of unparsed chars
;Here on a reparse, reset the stack, release any temp JFNs, clear flags,
;indicate we are at command level by settin CURENT to -1, set up the COMND
;I/O JFNs properly, clear the control-O bit.
COM0: MOVE P,[IOWD PDLEN,PDL] ;Set up a fresh push down list
CALL RELJFN ;[34] Release any temp JFN obtained
TXZ F,TTWATF!PTWATF!NOFLAG!IGNORF ;[34] Clear all waits and modes
SETOB I,LSTHDR ;Always clear subjob index
MOVEM I,CURENT ;We are not connected right now
SETOM LMFLAG ;Use RFPOS to see if on left margin
MOVEI A,.PRIOU ;Setup initial output JFN
SKIPE RDJFN ;Reading from a file?
MOVEI A,.NULIO ;Yes, reset output jfn
HRRM A,CMDSBK+.CMIOJ ;Set output output JFN for command parsing
MOVEI A,.PRIIN ;Initialize mode of controlling TTY
MOVE B,SAVMOD ;Get saved terminal mode
TXZ B,TT%OSP ;Clear the output suppress (control-O) bit
SFMOD ;Normalize terminal mode bits
MOVX A,CM%WKF ;Load the parse as you go bit
IORM A,CMDSBK+.CMFLG ; and set it in the command state block
; JRST COM2 ;OK, we are ready to parse now!
;Here when all things are set up to parse a new top level command.
COM2: MOVEI B,CBLK ;[34] Function block for top level parse
CALL COMAND ;[34] Parse top level keyword
JRST COMERR ;[34] Bad command
TXO F,NOINTF ;[34] Disallow PTY display now
TLZ C,-1 ;[34] Isolate command function block used today
CAIE C,CBLK ;[34] Command keyword?
JRST COM4 ;[34] No
;[34] Fall through to command keyword stuff
;Fall through here if we parsed a PTYCON command (as opposed to a command like
;"subjob-text"). It could be that the user has named a subjob with a name that
;is a legal abbreviation for a subjob name. If this is the case we will get
;here, check for this case and dispatch to it properly.
MOVE A,CMDSBK+.CMPTR ;[34] Load pointer to unparsed characters
ILDB A,A ;[34] Get first unparsed character
CAIN A,"-" ;[34] Is it "subjob-" rather than a command?
JRST COM3 ;[34] Yes, handle ugly case
MOVX A,CM%WKF ;[34] Load parse as you go bit
ANDCAM A,CMDSBK+.CMFLG ;[34] and turn it off
HRRZ B,(B) ;Get dispatch address from table
JRST (B) ;Dispatch to command routine
;Here when "subjob-text" was specified but it parsed as "commandkeyword-". An
;example of this would be a user defining a subjob A, then typing "A-text".
;The "A" would be taken as an ACCEPT command since the keyword table is first,
;and the "-" would be taken as the start of a subjob number of zero (thanks
;COMND).
COM3: SETZ B, ;[34] Start with counter of zero
MOVE A,CMDSBK+.CMBFP ;[34] Load pointer to whole buffer
COM3A: CAMN A,CMDSBK+.CMPTR ;[34] Counted all characters yet?
JRST COM3B ;[34] Yes!
ILDB C,A ;[34] Load next character
CAIE C,"-" ;[34] Hyphen?
AOJA B,COM3A ;[34] Nope count another one
COM3B: ADDM B,CMDSBK+.CMINC ;[34] Count parsed characters as unparsed
MOVE A,CMDSBK+.CMBFP ;[34] Point to whole buffer
MOVEM A,CMDSBK+.CMPTR ;[34] Whole buffer is unparsed
MOVEI A,CBUFSZ*5-1 ;[34] Reset buffer size
MOVEM A,CMDSBK+.CMCNT ;[34] to whole buffer
MOVEI B,SBLK ;[34] Parse this as a subjob-whatever
CALL COMAND ;[34] Try and parse it
JRST COMERR ;[34] Big owie!
TLZ C,-1 ;[34] Get just the parsed function block in C
;Here when not command keyword, must be subjob-text.
COM4: CAIN C,ABLK ;[34] All-text?
JRST COM6 ;[34] Yes
CAIN C,NBLK ;[34] number-text?
JRST COM5 ;[34] Yes
HRRZ I,(B) ;[34] name-text, get subjob index
JRST SINGLE ;[34] and parse rest of text
COM5: MOVEI I,(B) ;[34] Copy number to I
IMULI I,PTYLEN ;[34] then convert to subjob index
JRST SINGLE ;[34] and parse rest of command
COM6: SETO I, ;[34] Indicate that all typed
JRST SINGLE ;[34] and parse rest of command
SUBTTL Commands -- Command Tables
;[34] Command table - must be in alphabetical order
; One entry for each command in the table
; CMND(name,help,routine,noflag)
DEFINE COMGEN<
XLIST
CMND(ACCEPT,<(OUTPUT FROM SUBJOBS) subjob,subjob,... or ALL>,ACCEP,1)
CMND(BELL,<(WHEN OUTPUT WAITING)>,BELL,1)
CMND(CONNECT,<(TO SUBJOB) lastsubjob>,CONPTY,0)
CMND(DEFINE,<(SUBJOB #) number (AS) name>,DEFPTY,0)
CMND(DISCARD,<(OUTPUT FROM SUBJOB) subjob,subjob,... or ALL>,DISCA,1)
CMND(EXIT,<(FROM PTYCON)>,EXIT,0)
CMND(GET,<(COMMANDS FROM FILE) ptycon.ato>,READ,0)
CMND(HELP,<(MESSAGE)>,HELP,0)
CMND(KILL,<(SUBJOB) subjob,subjob,... or ALL>,KILL,0)
CMND(LOG,<(OUTPUT TO FILE) ptycon.log>,LOG,1)
CMND(NO,,NOCOMM,0)
CMND(PUSH,<(EXEC LEVEL)>,PUSHE,0)
CMND(REDEFINE,<(PTYCON ESCAPE CHARACTER TO BE) controlcharacter>,CHANGE,0)
CMND(REFUSE,<(OUTPUT FROM SUBJOBS) subjob,subjob,... or ALL>,REFPTY,1)
CMND(SAVE,<(INPUT IN FILE) saved-input.txt>,SAVINP,1)
CMND(SILENCE,<(ALL OUTPUT TO TERMINAL)>,SILNCE,1)
CMND(WHAT,<(IS STATE OF SUBJOB) subjob or ALL>,WHATPT,0)
LIST
>
;Command table suitable for use from COMND.
DEFINE CMND(A,B,C,D)<
XWD [ASCIZ/A/],C
>
CMDTBL: XWD COMNUM,COMNUM ;Table header
COMGEN ;Generate top level keywords
COMNUM==.-CMDTBL-1 ;Compute number of keywords
;Table keywords suitable for use with the NO command.
DEFINE CMND(A,B,C,D)<
IFN D,<XWD [ASCIZ/A/],C>
>
NOTBL: XWD NONUM,NONUM ;Table header
COMGEN ;Generate NO commands
NONUM==.-NOTBL-1 ;Length of NO command table
;Table of keywords for HELP command.
DEFINE CMND(A,B,C,D)<IFNB <B>,<
IFE D,<[ASCIZ\ A 'B'
\]>
IFN D,<[ASCIZ\* A 'B'
\]>
>>
COMHLP: COMGEN ;Generate help text
HLPNUM==.-COMHLP ;Set number of entries
SUBTTL Commands -- Single Line to Subjob Command
;Here on a "subjobname-text" or "subjobnumber-text" command. [34] Here from
;top level parse with I/ subjob index or -1 for ALL. If the hyphen is followed
;by an escape, the escape properly gets turned into a space by COMND, but user
;really wants an escape, so change it back into a real escape for sending to
;the subjob(s).
SINGLE: MOVEI B,[FLDDB. .CMTOK,CM%HPP,<-1,,[ASCIZ "-"]>,<a dash>] ;[34]
MOVX A,CM%WKF ;[34] Load parse as you go bit
IORM A,CMDSBK+.CMFLG ;[34] Parse after each field is terminated
CALL COMAND ;[34] Parse the hyphen
JRST COMERR ;[34] Owie command
MOVE B,CMDSBK+.CMPTR ;[34] Get pointer to next input
MOVEM B,LNEPTR ;[34] Save pointer to start of subjob text
TXNN A,CM%ESC ;[34] Did user type escape after this field?
JRST SINCC ;[34] Nope
MOVEI B,.CHESC ;[34] Load an escape
IDPB B,CMDSBK+.CMPTR ;[34] Store it in the text
SOS CMDSBK+.CMCNT ;[34] Count character as past
SETZM CMDSBK+.CMINC ;[34] No unparsed characters in buffer now
SINCC: MOVEI B,OLBLK ;[34] Function block
MOVX A,CM%WKF ;[34] Load the parse as you got bit
ANDCAM A,CMDSBK+.CMFLG ;[34] Turn it off
CALL COMAND ;[34] Parse the text
JRST COMERR ;[34] Text should always parse, right?
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
;Command is parsed, set up the string to send to the subjob.
SETZM LNESTR ;CLEAR STRING
MOVE A,LNEPTR ;GET POINTER TO LINE TEXT
HRROI B,LNESTR ;PLACE IN LINE STRING
SETZ C, ;STOP AT ZERO
SIN ;GET STRING
ERJMP .+1 ;IGNORE ERROR
MOVEI A,0 ;END WITH NULL
DPB A,B ;MASK OFF LF - LEAVE ONLY CR
;[34] Subjob text all set up, find out if doing all or just one. If just one
;see if new highest subjob specified and if so call routine to handle that.
;Then simply send line to subjob and return for more commands.
JUMPL I,SENALL ;[34] If I/ -1 then sending to all
CALL NEWHGH ;[34] Possibly adjust if new highest PTY number
MOVEM I,LSTCON ;Save last single subjob for connect default
CALL SNGOUT ;Send line out to desired subjob
JRST CHKPTY ;[33] Finish up by dumping PTY output now
;[34] Here when I/ -1 which means send to all activated subjobs.
SENALL: PUSH P,P1 ;Save a AC for loop index
MOVE P1,PTYHGH ;Set up to loop for all defined subjobs
SETZ I, ;INITIALIZE INDEX
SNGALL: SKIPE PTYJFN(I) ;IS THERE A PTY INITIALIZED HERE?
PUSHJ P,SNGOUT ;YES, SEND OUT LINE
ADDI I,PTYLEN ;GO TO NEXT PTY
SOJGE P1,SNGALL ;LOOP FOR ALL LINES
POP P,P1 ;RESTORE PRESERVED AC
JRST CHKPTY ;[33] Check PTY output now please
;Local routine to send the line of text in LNESTR to the PTY specified by I
SNGOUT: PUSHJ P,PTYFIL ;FIRST MAKE SURE OUTPUT BUFFER IS EMPTY
PUSH P,P1 ;SAVE PRESERVED AC
MOVE P1,[POINT 7,LNESTR];POINT TO TEXT
SINLOP: ILDB A,P1 ;GET NEXT CHARACTER TO GO OUT
JUMPE A,SINLPD ;IF ZERO, THEN DONE
PUSHJ P,PTYOUT ;SEND IT OUT
JRST SINLOP ;LOOP FOR ALL CHARACTERS
SINLPD: POP P,P1 ;RESTORE PRESERVED AC
POPJ P, ;AND RETURN
SUBTTL Commands -- Accept Command
;[NO] ACCEPT (OUTPUT FROM SUBJOB) subjob, subjob, ...
ACCEP: TXNE F,NOFLAG ;[34] User type no?
JRST NOREC ;Yes, turn it into refuse
NOREFU: NOISE (OUTPUT FROM SUBJOBS) ;[34] Parse noise
HRROI A,[ASCIZ/ALL/] ;[34] Allow ALL for default
CALL GETSJL ;[34] Get list of subjobs to work on
JRST ILLSJB ;No match, command error
JRST ACCEP1 ;User said ALL
ACCEP3: MOVE I,ARGS(D) ;GET SUBJOB INDEX
MOVX B,PTREFF ;[34] Set up to clear refuse flag
ANDCAM B,PTYSTS(I) ;ALLOW TYPE OUT
AOBJN D,ACCEP3 ;[34] Loop for all specified subjobs
JRST COMLVL ;[34] Get a new command
ACCEP1: CALL CONFIR ;[34] Confirm the command, maybe log or echo it
MOVE C,PTYHGH ;GET HIGHEST PTY NUMBER
MOVEI I,0 ;START WITH NUMBER 0
MOVX B,PTREFF ;[34] Get flag to clear
ACCEP2: ANDCAM B,PTYSTS(I) ;CLEAR REFUSE FLAG
ADDI I,PTYLEN ;STEP TO NEXT PTY
SOJGE C,ACCEP2 ;LOOP BACK FOR ALL PTY'S
TXZ F,REFALF ;[34] Mark that a ACCEPT ALL was done
JRST COMLVL ;ALL THROUGH
SUBTTL Commands -- Bell Command
;[NO] BELL (WHEN OUTPUT WAITING)
BELL: NOISE (WHEN OUTPUT WAITING) ;Parse noise words
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
TXNN F,NOFLAG ;[34] NO typed?
TXZA F,NOBELF ;[34] Nope, enable bell
TXO F,NOBELF ;[34] Yep, disable bell
CALL STDING ;Turn off bell to start with
JRST CHKPTY ;[34] Go turn it on or off by checking output
SUBTTL Commands -- Connect Command
;CONNECT (TO SUBJOB) subjob Command
CONPTY: NOISE (TO SUBJOB) ;Parse noise
SETZ A, ;[34] Assume no default subjob
SKIPGE I,LSTCON ;[34] Get last connected subjob if any
JRST CONPT4 ;[34] Go parse subjob to connect to
HRROI A,PTYNAM(I) ;[34] Point to connected name
SKIPE PTYNAM(I) ;[34] Does default have a defined name?
JRST CONPT4 ;[34] Yes, store it and parse subjob name
MOVEI B,(I) ;[34] Get subjob number from index
IDIVI B,PTYLEN ;[34] Get subjob number
HRROI A,STRING ;[34] Store in default string address
MOVEI C,^D10 ;[34] Decimal number
NOUT% ;[34] Place number as default
ERJMP .+1 ;[34] Error, continue anyway
HRROI A,STRING ;[34] Point to default
CONPT4: CALL GETSJB ;Get subjob index in I, A/ default
JRST ILLSJB ;No match, command error
JRST ILLSJB ;[34] Can't connect to ALL
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
MOVEM I,LSTHDR ;Save subjob index as new last connected
MOVEM I,LSTCON ; and suppress header typeout from subjob
HRROI A,[ASCIZ/[Connected to subjob /] ;Tell user
CALL TTSOUT ; which subjob
CALL TYPNAM ; he is connecting to
HRROI A,[ASCIZ/]
/] ;End with a close bracket and crlf
CALL TTSOUT ;Finish up string
JRST PTYLOP ;Go enter the connect loop
SUBTTL Commands -- Define Command
;DEFINE (SUBJOB #) number (AS) name
DEFPTY: NOISE (SUBJOB #) ;Parse noise
MOVNI I,PTYLEN ;Find first free subjob number
MOVE C,NUMPTY ;Loop for all PTYs
DEFPT1: ADDI I,PTYLEN ;Go to next subjob
SKIPE PTYJFN(I) ;Initialized?
SOJG C,DEFPT1 ;Yes, try next one
MOVE D,DNUBLK+.CMFNP ;[34] Load the flags word for our block
TXZ D,CM%DPP ;[34] Assume no free found
JUMPLE C,DEFPT2 ;[34] Jump if no free one
TXO D,CM%DPP ;[34] There was a free one found, set flag
HRROI A,STRING ;Destination default string
MOVEM A,DNUBLK+.CMDEF ;Store as default string pointer
MOVEI B,(I) ;Get subjob index
IDIVI B,PTYLEN ;Convert to subjob number
MOVEI C,^D10 ;Output in decimal
NOUT% ;Output number into string
ERJMP .+1 ;Ignore error
DEFPT2: MOVEM D,DNUBLK+.CMFNP ;[34] Replace flags word in function block
MOVEI B,DNUBLK ;[34] Point to the block we just set up
CALL COMAND ;[34] Parse the number with default next free
JRST ILLSJB ;[34] Illegal subjob
JUMPL B,ILLSJB ;[34] -ive subjob is illegal
CAML B,NUMPTY ;[34] Within bounds?
JRST ILLSJB ;[34] No, output error
MOVEM B,ARGS ;[34] Remember that number
MOVEI I,(B) ;[34] Copy subjob number
IMULI I,PTYLEN ;[34] Compute subjob index
SETZM ARGS+1 ;[34] Initialize "no message" flag
MOVEM I,ARGS+2 ;[34] Remember subjob offset for later use
;Parse subjob name or a confirm to remove name from subjob.
NOISE (AS) ;Parse noise
SETZM ATMBUF ;[34] Clear atom buffer for easy test later
MOVEI B,DNMBLK ;[34] Point to confirm or field block
CALL COMAND ;[34] Parse the name or a confirm
JRST ILLSJB ;[34] Illegal subjob?
TLZ C,-1 ;[34] Get function parsed
CAIN C,DNMBLK ;[34] Was it the confirm?
JRST DEFPT6 ;[34] Yes, we want to erase the name if any
;We have a subjob name in the atom buffer, check for legal length, that it is
;not "ALL", that it is not a number, that it is not a command name.
MOVE A,[POINT 7,ATMBUF] ;[34] Point to atom buffer
SETZB B,D ;[34] Clear counter of characters, numeric flag
DEFPT3: ILDB C,A ;[34] Get a subjob name character
JUMPE C,DEFPT4 ;[34] If a null, this name is OK
CAIL C,"0" ;[34] Is it a
CAILE C,"9" ;[34] number?
SETO D, ;[34] No, set non-number flag
CAIL C,"a" ;[34] Is it
CAILE C,"z" ;[34] lowercase?
AOJA B,DEFPT3 ;[34] No, count character and continue
SUBI C,"a"-"A" ;[34] Convert lower case to upper case
DPB C,A ;[34] Reeat character
AOJA B,DEFPT3 ;[34] Loop for more
DEFPT4: JUMPE D,SJNALP ;[34] Jump if name numeric
CAILE B,^D9 ;[34] Is name too long?
JRST SJNLNG ;[34] Yes
MOVEI A,ALLTBL ;[34] Point to keyword table of "ALL"
HRROI B,ATMBUF ;[34] Point to suspected subjob name
TBLUK% ;[34] Look for that keyword
TXNE B,TL%EXM ;[34] Is it ALL?
JRST SJNNAL ;[34] Yes, this is illegal
MOVEI A,CMDTBL ;[34] Point to toplevel command table
HRROI B,ATMBUF ;[34] Point to atom buffer
TBLUK% ;[34] Look up subjob name against command
TXNE B,TL%EXM ;[34] Match command name?
JRST SJNNCN ;[34] Yes, illegal
;Subjob name appears to be pretty legal. Before we do anything else, confirm
;the command. Then see if another subjob has this name already. If so, remove
;the old definition and set a flag for later typeout.
CALL CONFIR ;[34] Confirm the command please
HRROI B,ATMBUF ;[34] Point to atom buffer
CALL LUKNAM ;[34] Look for that name
JRST DEFPT5 ;[34] Its not there, go on please
HRRZ I,(A) ;[34] Name found, get subjob index
CALL DELNAM ;[34] Delete that name
SETOM ARGS+1 ;[34] Set the message flag
MOVE I,ARGS+2 ;[34] Reload subjob index and fall through
;Here when ready to add subjob name in ATMBUF to subjob name specified by
;subjob index in I. Confirm the command then add the name to the table.
DEFPT5: MOVEI A,ATMBUF ;[34] Point to the name
CALL ADDNAM ;[34] Add that name to that table
SKIPE ARGS+1 ;[34] Was name already in use?
WRNMES (<% Name already in use, reassigned to this subjob
>) ;Yes, print warning message
JRST DEFPT7 ;[34] Continue below
;[34] Here when deleting a subjob's name, delete name if it has a name
DEFPT6: SKIPE PTYNAM(I) ;[34] Subjob has a name?
CALL DELNAM ;[34] Yes, delete name from table
;[34] Subjob's name taken care of, see if it exists if not make it then return.
DEFPT7: SKIPN PTYJFN(I) ;Is PTY opened yet?
CALL PTINIT ;No, go initialize it
CALL NEWHGH ;Possibly adjust if new highest PTY number
MOVEM I,LSTCON ;Define sets connect default
JRST COMLVL ; and return
SUBTTL Commands -- Discard Command
;[NO] DISCARD (OUTPUT FROM SUBJOB) subjob, subjob, ...
DISCA: NOISE (OUTPUT FROM SUBJOB) ;PARSE NOISE WORDS
HRROI A,[ASCIZ/ALL/] ;[34] Load default string of ALL
CALL GETSJL ;[34] Get list of subjobs to work on
JRST ILLSJB ;No match, command error
JRST DISCA1 ;User tried "ALL"
DISCA3: MOVE I,ARGS(D) ;GET SUBJOB INDEX
MOVX B,PTDISF ;[34] User gave a legal subjob, load bit
TXNN F,NOFLAG ;[34] NO typed to clear the flag?
SKIPA C,[IORM B,PTYSTS(I)] ;[34] Set the bit
MOVE C,[ANDCAM B,PTYSTS(I)] ;[34] Clear the bit (NO typed)
XCT C ;SET OR CLEAR THE IGNORE FLAG
AOBJN D,DISCA3 ;[34] Loop for all arguments
JRST COMLVL ;[34] and get a new command
DISCA1: CALL CONFIR ;[34] Confirm the command, maybe log or echo it
TXNN F,NOFLAG ;[34] NO typed to clear the flag?
SKIPA C,[IORM B,PTYSTS(I)] ;[34] Set the bit
MOVE C,[ANDCAM B,PTYSTS(I)] ;[34] Clear the bit (NO typed)
MOVX B,PTDISF ;[34] Set up to set or clear discard bit
MOVE D,PTYHGH ;LOOP FOR ALL SUBJOBS
MOVEI I,0 ;STARTING AT 0
DISCA2: XCT C ;SET OR CLEAR THE IGNORE BIT
ADDI I,PTYLEN ;STEP TO NEXT SUBJOB
SOJGE D,DISCA2 ;LOOP BACK FOR ALL SUBJOBS
TXNE F,NOFLAG ;[34] NO typed?
TXZA F,DISALF ;[34] NO DISALLOW ALL
TXO F,DISALF ;[34] Not no, DISALLOW ALL
JRST COMLVL ;THEN RETURN TO COMMAND LEVEL
SUBTTL Commands -- Exit Command
;EXIT (FROM PTYCON) Command
EXIT: NOISE (FROM PTYCON) ;PARSE NOISE
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
PUSHJ P,CHKLOG ;SEE IF ANY ACTIVE SUBJOBS
JRST EXIT1 ;NONE, GO EXIT
HRROI A,[ASCIZ/Caution: Exiting may log out the still active subjobs!
Confirm: (type CONTROL-/]
PUSHJ P,TTSOUT
MOVE A,TRPCHR ;TYPE OUT THE ESCAPE CHAR
TRO A,100
PUSHJ P,TTBOUT
HRROI A,[ASCIZ/ to get back to PTYCON) /]
PUSHJ P,TTSOUT ;ISSUE WARNING
MOVEI B,[FLDDB. .CMCFM] ;FUNCTION BLOCK
CALL COMAND ;[34] Parse a confirm (can't use CONFIR rtn)
JRST COMLVL ;[34] Didn't get a confirm
EXIT1: CALL RESTTY ;[34] Reset TTY parameters
CALL CLSLOG ;[34] Close the log file
CALL CLSSVI ;[34] Close saved input file
CALL CLSTTY ;[34] Close TTY
HALTF% ;Stop
;Here if sophisticated user typed CONTINUE after an EXIT command
CALL OPNTTY ;[34] Open back up the terminal
CALL SETTTY ;[34] Set TTY mode
CALL ROPLOG ;[34] Reopen LOG file if needed
CALL ROPSVI ;[34] Reopen saved input file if needed
JRST COMLVL ;[34] Get a new command
SUBTTL Commands -- Get Command
;GET (COMMANDS FROM FILE) ptycon.ato
READ: NOISE (COMMANDS FROM FILE) ;Parse noise
SKIPE RDJFN ;Reading already?
JRST READ2 ;Yep
MOVX A,GJ%OLD ;GTJFN flags
MOVEM A,GTJBLK ;Place in GTJFN block
MOVE A,[POINT 7,[ASCIZ "PTYCON"]] ;Default filename
MOVEM A,GTJBLK+.GJNAM ;Place in GTJFN block
MOVE A,[POINT 7,[ASCIZ "ATO"]] ;Default extension
MOVEM A,GTJBLK+.GJEXT ;Store in GTJFN block
CALL GETFIL ;Parse filespec
HRRZM A,RDJFN ;Save JFN
MOVX B,FLD(7,OF%BSZ)!OF%RD ;Reading 7 bit bytes today
OPENF ;Pry it open
JRST READ4 ;Failed
MOVEI A,.NULIO ;Don't read from TTY anymore
HRLM A,CMDSBK+.CMIOJ ;Setup input JFN for comnd
JRST COMLVL ;Return and start processing file
READ2: CALL TRYLOG ;[34] Log command, echo if command file
ERRMES (<? Doing a "GET" within a "GET" is illegal>) ;[34] Owie!
JRST COMLVL ;[34]
;Here if can't open the command file, releases the JFN then as is the custom,
;prints out the last TOPS-20 JSYS error.
READ4: JERMES (<? Can't open command file>) ;[34] Output message
CALL TYPERR ;[34] Output error to terminal
MOVE A,RDJFN ;Get the JFN back
RLJFN ;Release it
ERJMP .+1 ;Ignore error
SETZM RDJFN ;Not processing command file
JRST COMLVL ;Return to get another command
SUBTTL Commands -- Help Command
;HELP (MESSAGE)
HELP: NOISE (MESSAGE) ;PARSE NOISE WORD
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
CALL ASCTER ;INSURE ASCII TERMINAL
CALL CRLF ;[34] Output one
CALL CRLF ;[34] two crlfs
HRROI A,SVN ;[34] Point to version string
CALL TTSOUT ;[34] Type out header
HRROI A,[ASCIZ/ commands:
/] ;[34] Tell him what we are doing
CALL TTSOUT ;[34] nad make it look good
MOVSI C,-HLPNUM ;[34] Get number of elements in table
HELPLP: HRRO A,COMHLP(C) ;[34] Get pointer to help text
CALL TTSOUT ;[34] Type it out with its noise words
AOBJN C,HELPLP ;LOOP FOR ALL COMMANDS
HRROI A,[ASCIZ/
"subjob,subjob,..." means a list of subjobs or ALL for all active subjobs.
"*" means the command can be preceded by "NO" to reverse its meaning.
The escape character to return to command level is: ^/] ;[34]
CALL TTSOUT ;Output that mess
MOVE A,TRPCHR ;GET ESCAPE CHARACTER
ADDI A,"A"-1 ;[34] Convert to printable uppercase
PUSHJ P,TTBOUT ;TYPE IT OUT
PUSHJ P,CRLF ;END LINE
JRST COMLVL ;DONE
SUBTTL Commands -- Kill Command
;KILL (SUBJOB) subjob, subjob, ...
KILL: NOISE (SUBJOB) ;Parse noise
SETZ A, ;[34] No default allowed
CALL GETSJL ;[34] Parse a list of subjobs
JRST ILLSJB ;No match, command error
JRST KILL2 ;User typed ALL
KILL3: MOVE I,ARGS(D) ;Get subjob index from list
CALL DELNAM ;Delete subjob name from table
CALL KILJOB ;Kill the job and the PTY
AOBJN D,KILL3 ;[34] Loop for all subjobs specified
JRST COMLVL ;[34] Get another command
KILL2: CALL CONFIR ;[34] Confirm the command, maybe log or echo it
PUSH P,P1 ;Save permanent ac
MOVE P1,PTYHGH ;Set up to scan all subjobs
MOVEI I,0 ;Start at subjob 0
KILLLP: CALL DELNAM ;Delete subjob name from table
CALL KILJOB ;Kill each one
ADDI I,PTYLEN ;Go to next subjob
SOJGE P1,KILLLP ;Loop for all subjobs
POP P,P1 ;Restore permanent ac
JRST COMLVL ;Go back to command level
SUBTTL Commands -- Log Command
;[NO] LOG (OUTPUT TO FILE) ptycon.log
LOG: NOISE (OUTPUT TO FILE) ;Parse noise words
TXNE F,NOFLAG ;[34] User just say "NO"?
JRST NOLOG ;Yes, go turn off logging
SETZM GTJBLK ;Clear GTJFN flags
MOVE A,[POINT 7,[ASCIZ "PTYCON"]] ;Default filename
MOVEM A,GTJBLK+.GJNAM ;Place in GTJFN block
MOVE A,[POINT 7,[ASCIZ "LOG"]] ;Default extension
MOVEM A,GTJBLK+.GJEXT ;Place in GTJFN block
CALL GETFIL ;Get file JFN
PUSH P,A ;[34] Save new log file JFN
CALL CLSLOG ;[34] Close current log file if any
POP P,A ;[34] Get new log file JFN back
CALL OPNLOG ;[34] Open new log file
CALL STRLOG ;[34] Start new log file
JRST COMLVL ;[34] Done
;Here for NO LOG command.
NOLOG: CALL CONFIR ;[34] Confirm the command, maybe log or echo it
CALL CLSLOG ;[34] Close log file
SETZM LOGBUF ;[34] Don't reopen the log file
JRST COMLVL ;ALL THROUGH
SUBTTL Commands -- No Command
;Here for the "NO" command
NOCOMM: MOVEI B,[FLDDB. .CMKEY,,NOTBL] ;We want to parse table of NO keywords
CALL COMAND ;[34] Parse keyword after "NO"
JRST COMERR ;[34] Owie command
TXO F,NOFLAG ;[34] Set the NO flag
HRRZ B,(B) ;Get dispatch address
JRST (B) ;Dispatch to routine
SUBTTL Commands -- Push Command
;PUSH (EXEC LEVEL)
PUSHE: NOISE (EXEC LEVEL) ;PARSE NOISE WORDS
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
;Use any old fork that is around
SKIPE A,EXECFK ;[34] Old EXEC around?
JRST PUSHE2 ;[34] Yes, use it
;Get a fork to run the EXEC in and then get a JFN on the EXEC to use.
MOVX A,CR%CAP ;[34] Create a lower fork for EXEC
CFORK ;[34] with same caps as us
JRST NOFORK ;[34] No more forks?
MOVEM A,EXECFK ;[34] Save fork handle
MOVX A,GJ%SHT!GJ%OLD ;[34] Get a JFN for the EXEC
HRROI B,[ASCIZ/DEFAULT-EXEC:/] ;Push to the default EXEC
GTJFN ;Try to get a JFN on it
CAIA ;[34] Error, try SYSTEM:
JRST PUSHE1 ;[34] It worked, go for it
MOVX A,GJ%SHT!GJ%OLD ;[34] Old file short form
HRROI B,[ASCIZ/SYSTEM:EXEC.EXE/] ;This filename
GTJFN ;Try for old filename
JRST NOEXEC ;Failed again - no exec found
PUSHE1: HRL A,EXECFK ;Make fork handle,,JFN
GET ;Now get the EXEC into the lower fork
MOVEI A,.FHSLF ;Get privs for
RPCAP ; this fork
TXZ B,SC%LOG ;Don't allow lower fork to log out
SETZ C, ;No privs enabled
MOVE A,EXECFK ;Get lower fork handle
EPCAP ;Set its capabilities
;EXEC all ready to go, start it, wait for it to finish.
PUSHE2: MOVEI A,.FHSLF ;[32] Load this fork's handle
MOVX B,1B<TRPCHN>+1B<CTLCHN> ;[34] Load channels to disable
DIC ;[32] Disable control c and escape char
CALL RESTTY ;[34] Reset TTY modes
SETZM SAVMOD ;Modes may be set in lower EXEC, clear them
SETO A, ;For this job
MOVE B,[-2,,NAMES] ;Get both names
MOVEI C,.JISNM ;From the monitor
GETJI ;Remember our name to restore it later
JFCL ;Can't fail
MOVE A,EXECFK ;Reload EXEC fork handle
SETZ B, ;At position offset zero
TXO F,PUSHF ;[34] Mark that we are pushed down
SFRKV ;Start the EXEC
WFORK ;Wait for it to halt
TXZ F,PUSHF ;[34] Out of exec
;Here to clean up after fork is halted (or after no fork can be created).
;Reenable interrupts on the control-C and escape character channels, set the
;terminal the waie we like it, and get another command.
DMOVE A,NAMES ;Get saved names
SETSN ;Restore name of program
JFCL ;Ignore errors for a change
MOVEI A,.FHSLF ;[32] Load this fork's handle
MOVX B,1B<TRPCHN>+1B<CTLCHN> ;[32] Channels to enable
AIC ;[32] Activate ^C and ^X channels
CALL SETTTY ;[34] Set TTY modes for our use
JRST CHKPTY ;[34] Check PTY output then get new command
;Here if GTJFN failed on SYSTEM:EXEC.EXE and DEFAULT-EXEC:.
NOEXEC: JERMES (<? No EXEC>) ;[34] Can't run an exec today
MOVE A,EXECFK ;Load fork handle
KFORK ;Kill it
JFCL ;Ignore error
JRST COMLVL ;Get new command
;Here if no forks available (CFORK failed).
NOFORK: JERMES (<? No lower forks available>) ;[34] Out of forks!
JRST COMLVL ;New command
SUBTTL Commands -- Redefine Command
;REDEFINE (PTYCON ESCAPE CHARACTER TO BE) character
CHANGE: NOISE (PTYCON ESCAPE CHARACTER TO BE) ;Parse noise
MOVEI B,[FLDBK. .CMFLD,CM%HPP,,<a single control character>,,BMSK]
CALL COMAND ;[34] Parse the field for a the break character
JRST CHNGIL ;[34] Illegal
MOVE A,[POINT 7,ATMBUF] ;[34] Point to the atom buffer
ILDB B,A ;[34] Get first character in buffer
JUMPE B,CHNGIL ;[34] Jump if illegal null
ILDB C,A ;[34] Get next character in atom buffer
JUMPN C,CHNGIL ;[34] It must be a null
CAILE B,"Z"-100 ;[34] and it must be a control character
JRST CHNGIL ;[34] It is not legal
MOVEM B,ARGS ;[34] Save new trap character
MOVX C,1B0 ;[34] Load initial mask
MOVN A,B ;[34] Load -ive shift factor
LSH C,(A) ;[34] Shift to right to get bit mask
TDNE C,BMSK ;[34] Legal character?
JRST CHNGIL ;[34] Nope
MOVEM C,ARGS+1 ;[34] Store new bit mask
;Character is OK, confirm the command and do the work.
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
MOVE B,ARGS ;[34] Load the trap character back
EXCH B,TRPCHR ;Get old trap character
DTI ;Deassign it
ERJMP .+1 ;Ignore error
MOVE A,ARGS+1 ;[34] Load new escape mask
TXO A,1B<.TICTI> ;[34] Include the all typein bit
MOVEM A,ESCMSK ;[34] Save this mask for subjob level
TXO A,1B<.TICCC>!1B<.TICCO>!1B<.TICTI> ;[34] Include controls O and C
MOVEM A,TIMASK ;Save mask for command level
HRLZ A,TRPCHR ;[34] Enable escape character
HRRI A,TRPCHN ;[34] on its own channel
ATI ;[34] Attach Terminal Interrupt character
CALL SETTTY ;[34] Set terminal interrupt word and so on
JRST COMLVL ;[34] All done
;Here if bad character specified
CHNGIL: CALL TRYLOG ;[34] Try to log this command please
ERRMES (<? Illegal PTYCON escape character>) ;Can't make it that
JRST COMLVL ;[34] Get a new command
;Break mask to allow only legal characters to be typed, breaks on everything
;else but the legal characters.
BMSK: 446665,,670760 ;ALLOW ONLY CERTAIN CONTROL
777777,,777760 ;CHARACTERS TO BE ENTERED
777777,,777760 ;FOR
777777,,777760 ;REDEFINE
SUBTTL Commands -- Refuse Command
;[NO] REFUSE (OUTPUT FROM SUBJOBS) subjob, subjob, ...
REFPTY: TXNE F,NOFLAG ;[34] Did user type NO?
JRST NOREFU ;[34] Yes, turn it into an ACCEPT
NOREC: NOISE (OUTPUT FROM SUBJOBS) ;PARSE NOISE WORDS
SETZ A, ;[34] No default string
CALL GETSJL ;[34] Get list of subjobs
JRST ILLSJB ;Illegal subjob specified
JRST REFPT1 ;User typed "ALL"
REFPT3: MOVE I,ARGS(D) ;GET SUBJOB INDEX
MOVX B,PTREFF ;[34] Get refuse flag mask
IORM B,PTYSTS(I) ;SET REFUSE FLAG
AOBJN D,REFPT3 ;[34] Loop for all arguments stored
JRST COMLVL ;[34] Time for another command
REFPT1: CALL CONFIR ;[34] Confirm the command, maybe log or echo it
MOVE C,PTYHGH ;GET NUMBER OF PTYS OPEN
MOVEI I,0 ;START AT # 0
MOVX B,PTREFF ;[34] Prepare to set flag by loading mask
REFPT2: IORM B,PTYSTS(I) ;SET REFUSE FLAG
ADDI I,PTYLEN ;STEP TO NEXT PTY
SOJGE C,REFPT2 ;LOOP FOR ALL
TXO F,REFALF ;[34] Remember refuse all command
JRST COMLVL ;ALL THROUGH
SUBTTL Commands -- Save Command
;SAVE (INPUT IN FILE) saved-input.txt
SAVINP: NOISE (INPUT IN FILE) ;Parse noise words
TXNE F,NOFLAG ;[34] Just say "NO"?
JRST NOSAVI ;Yes, go turn off logging
SETZM GTJBLK ;Clear GTJFN flags
MOVE A,[POINT 7,[ASCIZ "SAVED-INPUT"]] ;Default filename
MOVEM A,GTJBLK+.GJNAM ;Save in GTJFN block
MOVE A,[POINT 7,[ASCIZ "TXT"]] ;Default extension
MOVEM A,GTJBLK+.GJEXT ;Save in GTJFN block
CALL GETFIL ;Get file JFN
PUSH P,A ;Save any old JFN
CALL CLSSVI ;Close it
POP P,A ;Get new JFN back
CALL OPNSVI ;Open new saved input file
CALL STRSVI ;Get it started with header,
JRST COMLVL ; and return
;Here for NO SAVE Command
NOSAVI: CALL CONFIR ;[34] Confirm the command, maybe log or echo it
CALL CLSSVI ;[34] Close saved input file
SETZM SVIBUF ;[34] Don't try to reopen it
JRST COMLVL ;ALL THROUGH
SUBTTL Commands -- Silence Command
;[NO] SILENCE (ALL OUTPUT TO TERMINAL)
SILNCE: NOISE (ALL OUTPUT TO TERMINAL) ;PARSE NOISE WORDS
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
TXNN F,NOFLAG ;[34] Just say NO?
TXOA F,SILNCF ;[34] Silence command, toss the output from GET
TXZ F,SILNCF ;[34] Don't silence output fron get (default)
SKIPN RDJFN ;Processing a get command?
JRST SILNC1 ;[34] Nope
MOVEI A,.PRIOU ;[34] Assume "NO SILENCE"
TXNE F,SILNCF ;[34] True?
MOVEI A,.NULIO ;[34] "SILENCE", don't print prompt
HRRM A,CMDSBK+.CMIOJ ;PLACE IN COMMAND STATE BLOCK
JRST COMLVL
SILNC1: WRNMES (<% This is only effective from within a command file
>) ;[34] Yes, give a message
JRST COMLVL ;[34]
SUBTTL Commands -- What Command
;WHAT (IS STATE OF SUBJOB) subjob|ALL
WHATPT: NOISE (IS STATE OF SUBJOB) ;Parse noise words
HRROI A,[ASCIZ/ALL/] ;[34] Allow ALL as default string
CALL GETSJB ;Get a subjob number in I
JRST ILLSJB ;No match, command error
JRST WHAT5 ;User typed "ALL"
;Type out information on a particular subjob.
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
TXZ F,TOFLAG ;[34] Initialize type out flag
SKIPN PTYJFN(I) ;Does this job exist?
JRST [HRROI A,[ASCIZ/? subjob "/] ;No
PUSHJ P,TTSOUT ;Type "? Subjob x not in use"
PUSHJ P,TYPNUM ;Type subjob number
HRROI A,[ASCIZ/" not in use/]
PUSHJ P,TTSOUT
TXO F,TOFLAG ;[34] Set the typeout occured flag
JRST WATDON] ; and exit
PUSHJ P,TYPSYS ;Go type out SYSTAT for this job
JRST WATDON ; and exit
;Type out information on all subjobs.
WHAT5: CALL CONFIR ;[34] Confirm the command, maybe log or echo it
SETOM LMFLAG ;Use RFPOS to find our position
PUSH P,P1 ;Save P1
PUSH P,I ; and I
MOVEI I,0 ;Start at subjob number 0
MOVE P1,PTYHGH ; and loop for all jobs
TXZ F,TOFLAG ;[34] Init type out flag for "NONE ACTIVE"
WHATLP: PUSHJ P,TYPSYS ;Go type SYSTAT for each job
ADDI I,PTYLEN ;Step to next job
SOJGE P1,WHATLP ;Loop back for all jobs
POP P,I ;Restore I
POP P,P1 ; and P1
;Here to finish up WHAT command
WATDON: TXNE F,TOFLAG ;Was anything typed?
JRST [PUSHJ P,CRLF ;Yes, end line
JRST CHKPTY] ;[34] Check for PTY output and return
HRROI A,[ASCIZ/None active
/] ;No, no active subjobs
CALL TTSOUT ; so tell user something
JRST CHKPTY ;[34] Check for PTY output available
;Routine to display a SYSTAT of job
;Call with I/ subjob index
;Returns +1 always
TYPSYS: CALL ASCTER ;Setup as ASCII terminal
SKIPN PTYJFN(I) ;Is there a job here?
RET ;No, type nothing
TXO F,TOFLAG ;[34] Say something was typed
CALL GETLM ;[34] Get to left margin
CALL TYPNAM ;Start with name and number of subjob
MOVEI B,^D14 ;Get to this column
CALL TYPTAB ; using spaces
HRLZ A,PTYTTD(I) ;Get tty designator for this subjob
TLZ A,.TTDES ;Make it just the terminal numbber
HRR A,TTYJOB ;Get table number for GETAB
GETAB% ;Get job number on that terminal
JRST TYPSNJ ;Failed!
HLRE B,A ;GET TSS JOB NUMBER
JUMPL B,TYPSNJ ;IF -1 OR -2, THEN NOT LOGGED IN
MOVEM B,ARGS ;Save job number
CALL TTNOUT ;Output job number
MOVEI B,^D19 ;Column to get to is next
CALL TYPTAB ;Get there
MOVE A,ARGS ;Get the job number
MOVE B,[-JITBLN,,JITAB] ;Get info about this job
SETZ C, ; starting at offset zero
GETJI ; from the monitor
ERJMP CPOPJ ;Return if this fails
MOVE B,JITAB+.JIUNO ;Get user number
JUMPN B,TYPSY0 ;Jump if logged in
HRROI A,[ASCIZ/Not logged in/] ;Not logged in
CALL TTSOUT ;Output that
JRST TYPSY1 ; and continue
TYPSY0: HRROI A,STRING ;Output name to string
DIRST ;Asciize the usernumber to a string
JFCL ;Killed the directory?
HRROI A,STRING ;Point to that string
CALL TTSOUT ;Now type out username
MOVEI B,^D40 ;Load column to get to
CALL TYPTAB ;Get there
MOVE A,JITAB+.JIPNM ;Get program name
CALL TYPSIX ;Type it out in ASCII
TYPSY1: MOVEI B,^D47 ;Load column to get to
CALL TYPTAB ;Get there
CALL HUNGRY ;[34] Is this PTY hungry?
SKIPA A,[XWD -1,[ASCIZ/TI/]] ;[34] Yes
HRROI A,[ASCIZ/RN/] ;[34] No, not hungry
SKIPE PTYCNT(I) ;If job has output waiting,
HRROI A,[ASCIZ/TO/] ; then always say "TO"
CALL TTSOUT ;Type out state of subjob
CALL TYPSYD ;Output (R) or (D)
MOVEI B,^D53 ;Load column to get to
CALL TYPTAB ; and get there
MOVE A,JITAB+.JIRT ;Get run time of the job
IDIVI A,^D1000 ;Turn it into seconds
IDIVI A,^D60 ;Get seconds
PUSH P,B ;Save seconds
IDIVI A,^D60 ;Get minutes
PUSH P,B ;Save minutes
MOVE B,A ;Get hours into B
CALL TTNOUT ;Type out the decimal hours of runtime
MOVEI A,":" ;Followed by ":"
CALL TTBOUT ; as a seperator
POP P,B ;Get minutes of runtime
CALL TTDNUM ;Output as two columns
MOVEI A,":" ;Load a colon
CALL TTBOUT ; and send that out
POP P,B ;Now get the seconds
JRST TTDNUM ; and output them and return
;Here if no job number assigned.
TYPSNJ: HRROI A,[ASCIZ/No job number assigned TI/]
CALL TTSOUT
CALL TYPSYD ;Type out i or r if necessary
RET
;Local routine to output if subjob is being refused (R) or discarded (D).
TYPSYD: SETZ A, ;Assume not refused or discarded
MOVE D,PTYSTS(I) ;Get flags word for this PTY
TXNE D,PTREFF ;[34] Refused flag set?
HRROI A,[ASCIZ/(R)/] ;Yes, say so
TXNE D,PTDISF ;[34] Line being ignored?
HRROI A,[ASCIZ/(D)/] ;Yes, this overrides refused flag
SKIPE A ;Anything to print
CALL TTSOUT ;Print out state if ON
RET ;Return
;Local routine to output spaces and tabs to get to the specified column.
;Depends on LMFLAG holding number of characters on this line.
;Call with B/ desired column
;Returns +1 always
TYPTAB: MOVEI A," " ;Load a space to print
TYPTA1: CAMG B,LMFLAG ;Time to stop?
RET ;Yes
CALL TTBOUT ;Nope, output another space
JRST TYPTA1 ;Loop for all of them
;Local routine to print program name.
TYPSIX: MOVE D,A ;SAVE ARG
MOVEI C,6 ;TYPE A MAX OF 6 CHARS
MOVE B,[POINT 6,D] ;SET UP BYTE POINTER
TYPSXL: ILDB A,B ;GET NEXT CHAR
ADDI A,40 ;CONVERT TO ASCII
CALL TTBOUT ;TYPE IT OUT
SOJG C,TYPSXL ;LOOP FOR 6 CHARS
POPJ P,
;Local routine to do a NOUT to temp area called STRING.
TTDNUM: MOVX C,NO%LFL!NO%ZRO!FLD(2,NO%COL)!12 ;Decimal output two columns
HRROI A,STRING ;Get number to a string
NOUT ;Output number to memory
ERJMP .+1 ;Can't fail
HRROI A,STRING ;Now output the answer
CALLRET TTSOUT ; to the terminal and return
SUBTTL Parsing Routines -- Perform COMND JSYS
;[34] Here to parse something using COMND JSYS.
;Call with B/ address of command function block chain
;Returns +1 if no parse
;Returns +2 if parsed OK
COMAND: MOVEI A,CMDSBK ;Point to command state block
COMND% ;Parse that function please
ERJMP FJERR ;Owie, maybe end of file
TXNN A,CM%NOP ;Error during confirm parse?
AOS (P) ;Nope, give skip return
RET ;Nope, return OK
;[34] Here to perform a COMND JSYS function and go to COMERR if error.
;Call with B/ function block
;Returns +1 always (goes to COMERR if there is a problem).
COMANE: CALL COMAND ;Do the function
JRST COMERR ;Give error message
RET ;Return
;Here on JSYS error from COMND JSYS. Makes check for end of file and
;dispatches to end of command file routine. Makes check for two COMND errors
;and handles those seperately. Otherwise, outputs a generic error message and
;enters exit code.
FJERR: MOVX A,.FHSLF ;Set process to self
GETER ;Get last error
ERJMP .+1 ;Error, continue anyway
HRRZ B,B ;Get rid of process handle
CAIE B,IOX4 ;End of file reached?
CAIN B,COMNX9 ;End of input file reached?
JRST GETMOR ;Yes, handle condition
PUSH P,B ;Save error code
CALL TRYLOG ;[34] Log command, echo if command file
POP P,B ;Get error code back
CAIE B,COMNX2 ;Field too long?
CAIN B,COMNX3 ;Command too long?
JRST TOOLNG ;Output appropriate error message
WRNMES (<? Fatal JSYS error - >) ;Print first part of message
CALL TYPERR ;Print rest of error message
JRST EXIT1 ;Exit from PTYCON
SUBTTL Parsing Routines -- Common Parsing Errors
;Here when top level command didn't parse.
COMERR: CALL TRYLOG ;Log command, echo if command file
JERMES (<? Unrecognized PTYCON command>) ;Command error
JRST COMLVL ; and return to command level for new command
;[34] Here when command line is too long.
TOOLNG: CALL TRYLOG ;[34] Log command, echo if command file
ERRMES (<? Line too long>) ;OUTPUT ERROR MESSAGE
JRST COMLVL ;GET ANOTHER COMMAND
;[34] Here when an illeal subjob designator is used in a command.
ILLSJB: CALL TRYLOG ;[34] Try and log command
MOVE A,[POINT 7,ATMBUF,6] ;Point to first character of argument
LDB B,A ;Get the first character
JUMPE B,TOOFEW ;Jump if null
ERRMES (<? Illegal subjob designator>) ;Illegal subjob designator
JRST COMLVL ;Get a new command
;[34] Here when not enouh subjob arguments are specified.
TOOFEW: ERRMES (<? Too few arguments>) ;No argument!
JRST COMLVL ;Get a new command
;[34] Here if too many subjob arguments are specified.
TOOARG: CALL TRYLOG ;[34] Log command, echo if command file
ERRMES (<? Too many arguments>) ;Too many subjob arguments!
JRST COMLVL ;Get a new command
;[34] Here if subjob name is too long.
SJNLNG: CALL TRYLOG ;Log command
ERRMES (<? Subjob name must be from 1 to 9 alphanumeric characters>)
JRST COMLVL ;Get new command
;[34] Here if subjob name is all numeric.
SJNALP: CALL TRYLOG ;Try to log command
ERRMES (<? Subjob name must have at least one non-numeric character>)
JRST COMLVL ;Get (yet) another new command
;[34] Here of trying to define a subjob name of ALL
SJNNAL: CALL TRYLOG ;Try to log the foolish command
ERRMES (<? Subjob name cannot be "ALL">)
JRST COMLVL ;I can't believe he tried this
;[34] Here if attempt made to define subjob name same as a command name.
SJNNCN: CALL TRYLOG ;[34] Try to log this gark
ERRMES (<? Subjob name cannot be the same as PTYCON command name>)
JRST COMLVL ;[34] What a Bozo
SUBTTL Parsing Routines -- Parse Comma or Confirm
;Routine to parse a comma or a carriage return
;Returns +1 if confirm typed
;Returns +2 if comma typed
COMACR: MOVEI B,[FLDDB. .CMCMA,<CM%HPP+CM%SDH>,,<comma for additional subjobs>,,[ ;[34]
FLDDB. .CMCFM]] ;[34] Comma and then return
CALL COMAND ;[34] Parse comma or confirm
JRST ILLSJB ;[34] Illegal subjob designator
LDB C,[POINT 9,(C),8] ;[34] Get function parsed
CAIE C,.CMCFM ;[34] Confirm?
JRST CPOPJ1 ;[34] No, comma it was, skip return
CALLRET TRYLOG ;[34] Log command, echo if command file, return
;[34] Here to parse a confirm
;Returns+1 if confirm typed, if confirm not typed will give error.
CONFIR: MOVEI B,[FLDDB. .CMCFM] ;Point to confirm function
CALL COMAND ;Parse that confirm please
JRST COMERR ;Didn't parse
CALLRET TRYLOG ;Success, try to log command and return
SUBTTL Parsing Routines -- Parse Filename
;Here to parse the filename for the GET command or the LOG command. Call with
;long for GTJFN block set up with defaults and modes, gets file's JFN and
;confirms command.
;Returns +1: always with A/ JFN
GETFIL: CALL RELJFN ;Release any temp JFN obtained
MOVEI B,[FLDDB. .CMFIL,<CM%HPP+CM%SDH>,,<filespec>] ;FDB
CALL COMAND ;[34] Parse the command file
JRST ILLSPC ;[34] Illegal filespec
MOVEM B,JFNIP ;Save JFN
CALL CONFIR ;[34] Confirm the command, maybe log or echo it
MOVE A,JFNIP ;Place JFN in A
SETZM JFNIP ;Clear saved JFN flag
RET ;Return
;Here when a bad filespec is typed.
ILLSPC: CALL TRYLOG ;Log command, echo if command file
WRNMES (<? Bad file - >) ;Command error
CALL TYPERR ;Type last JSYS error message
MOVEI A,.PRIIN ;Clear typeahead
CFIBF ; from the terminal
JRST COMLVL ; and return to command level for new command
;Local routine to release JFN in A, returns +1 always, JFNIP cleared.
RELJFN: SKIPN A,JFNIP ;[34] Do we have a temp JFN?
RET ;[34] Nope, return
RLJFN% ;Release the JFN
ERJMP .+1 ;Error, continue anyway
SETZM JFNIP ;Clear stored JFN since it is gone now
RET ;Return
SUBTTL Parsing Routines -- Parse Subjob Name or Number
;[34] Routine to read in a subjob number or name.
;Call with A/ default string pointer or 0 for no default
;Returns +1 if no subjob match
;Returns +2 if user said "ALL", I/ -1
;Returns +3 if user specified subjob, I/ subjob index
GETSJB: MOVEM A,SJNBLK+.CMDEF ;Store default string pointer or 0
MOVE B,SJNBLK+.CMFNP ;Load flags word
SKIPE A ;Any default supplied?
TXOA B,CM%DPP ;Yes, we will have a default
TXZ B,CM%DPP ;No, we will not have a default
MOVEM B,SJNBLK+.CMFNP ;Load flags word
MOVEI B,SJNBLK ;Point to block for field parse
CALL COMAND ;Parse subjob field
RET ;No match!
TLZ C,-1 ;Command parsed, get block that parsed
CAIE C,SJABLK ;Was it ALL?
JRST GETSJ1 ;Nope
SETO I, ;Indicate that ALL was typed
JRST CPOPJ1 ;Give +1 return
GETSJ1: CAIN C,SJNBLK ;Subjob name typed?
JRST GETSJ2 ;Nope
MOVEI I,(B) ;Get number typed
CAML I,NUMPTY ;Out of range for subjob number?
RET ;Yes, give +1 return
IMULI I,PTYLEN ;Compute subjob index
JRST CPOPJ2 ;Give +2 return
GETSJ2: HRRZ I,(B) ;Subjob name typed, get index
CPOPJ2: AOS (P) ;Give a double skip return
JRST CPOPJ1 ; back to the caller
SUBTTL Parsing Routines -- Parse List of Subjob Names or Numbers
;Routine to get list of subjob names, stored into ARGS
;Call with A/ pointer to default string or 0 for no default
;Returns +1 if no subjob match or other parse error
;Returns +2 if user said "ALL", I/ -1
;Returns +3 if user specified subjob list, D/ -count,,0
GETSJL: SETZM ARGCNT ;Initialize argument count to zero
CALL GETSJB ;Get subjob number or whatever A/ default
RET ;No match, command error
JRST CPOPJ1 ;User said "ALL"
GETSJ4: CALL SAVARG ;Save subjob index of just parsed subjob
CALL COMACR ;User typed subjob name, parse comma or confirm
JRST GETSJ6 ;Confirm, give +2 return
MOVEI B,SJRBLK ;Point to block for name or number
CALL COMAND ;Parse subjob field name or number
RET ;No match, return +1
TLZ C,-1 ;Name or number parsed, get block that parsed
CAIN C,SJRBLK ;Subjob name typed?
JRST GETSJ5 ;Nope
MOVEI I,(B) ;Get number typed
CAML I,NUMPTY ;Out of range for subjob number?
RET ;Yes, give +1 return
IMULI I,PTYLEN ;Compute subjob index
JRST GETSJ4 ;Store that one and loop
GETSJ5: HRRZ I,(B) ;Subjob name typed, get index
JRST GETSJ4 ;Loop for all of them
GETSJ6: MOVE D,ARGCNT ;Get argument count
IMUL D,[-1,,0] ;Convert to -count,,0
JRST CPOPJ2 ;Give +2 return, D/ -count,,0
;[34] Here to save a subjob argument in the ARGS array, if too many will give
;an error message. Call with I/ subjob argument, smashes D, returns+1 always.
SAVARG: MOVE D,ARGCNT ;Get number of arguments
CAILE D,MAXPTY ;Is there room for another argument?
JRST TOOARG ;No, too many arguments
MOVEM I,ARGS(D) ;Save index value
AOS ARGCNT ;Increment argument count
RET ;Return
SUBTTL Parsing Routines -- Add/Delete/Find Subjob Name
;[34] Here to add subjob name to subjob name table
; A/ addr of subjob name
; I/ subjob index
;Returns +1 always
ADDNAM: DMOVE A,(A) ;Load the subjob's new name
DMOVEM A,PTYNAM(I) ;Store it in the PTY database
MOVEI A,NAMTBL ;Point to name table
HRLI B,PTYNAM(I) ;Get subjob's name
HRR B,I ; and subjob's index
TBADD% ;Add that to the table
ERJMP SJTBER ;Fatal error
RET ;Return with name added
;[34] Here to delete subjob name from subjob name table
; I/ subjob index
;Returns +1 always
DELNAM: SKIPN PTYNAM(I) ;Any name for subjob?
RET ;Nope, return
HRROI B,PTYNAM(I) ;Point to name to find in table
CALL LUKNAM ;Look for it
JRST SJTBER ;Not there!
MOVE B,A ;Move address of name
MOVEI A,NAMTBL ;Address of name table
TBDEL% ;Delete entry from table
ERJMP SJTBER ;Well something has a big owie
SETZM PTYNAM(I) ;Clear the old subjob name
RET ;Return to caller
;[34] Here to look for a subjob name in the subjob name table
; B/ pointer to name
;Returns +1 if name not found
;Returns +1 if name found, A/ entry in table
LUKNAM: MOVEI A,NAMTBL ;Address of subjob name table
TBLUK% ;Find name in table please
ERJMP CPOPJ ;Something is really wrong here, return
TXNE B,TL%EXM ;An exact match found?
AOS (P) ;Yes, skip return
RET ;Return
;[34] Here when problem with TBADD or TBDEL.
SJTBER: BUG(CHK,<Internal confusion with subjob name table>) ;Owie
JRST COMLVL ;Get another command anyway
SUBTTL Connect to PTY -- Main Loop
;Main loop for talking with a PTY. Can come here after interrupt or on CONNECT
;command. If not already connected, sets whatever subjob index in I as the
;current job, insures that this PTY exists, set TTY JFN modes.
PTYLOP: MOVE P,[IOWD PDLEN,PDL] ;[34] Get new stack in case here from interrupt
TXO F,NOINTF ;[34] No other PTY typeout to be displayed now
SKIPL CURENT ;[34] Come here from CONNECT?
JRST PTYLP0 ;[34] Nope, just continue quickly
HRRZM I,CURENT ;[34] We now have a current subjob
SKIPN PTYJFN(I) ;Is there a PTY opened for this job?
CALL PTINIT ;No, go init one
MOVNI A,5 ;Set just escape and all typin for interrupt
MOVE B,ESCMSK ;Get escape mask
STIW ;So Control-O is passed down
CALL BINTER ;[34] Use binary channel for now
TXZ F,TIFLAG ;[34] Go into TI please
SKIPE RDJFN ;[34] Reading from command file?
JRST PTYLF1 ;[34] Yes, start off the command file read
;Here to restart the subjob connect loop (after an interrupt).
PTYLP0: SKIPE RDJFN ;[34] Reading from command file?
JRST PTYLF3 ;[34] Yes, reenter the file loop
;Here to start the connect loop if not procedding a command file. This loop
;waits for (1) characters available in TTY input buffer or (2) characters
;available in PTY output buffer. If characters available in TTY input buffer
;send them to the PTY. If characters available in PTY output buffer, send them
;to the TTY.
PTYLP1: TXO F,NOINTF ;[34] No other subjob output right now
CALL PTYTYP ;[34] Display anything for current job
JFCL ;[34] Typein waiting, we will catch it
PTYLP2: TXZ F,NOINTF ;[34] OK for pty interrupts now
CALL TTYGET ;[34] Get a character from the TTY
JRST PTYLP1 ;[34] None there
TXZ F,TIFLAG ;[34] Go into TI wait next time please
CALL PTYOUT ;[34] Send character in A to the connected PTY
JRST PTYLP1 ;[34] Loop for more
;This is the top of the loop that handles the connect loop when connected to a
;subjob. [34] The top of the loop resets the maximum characters that we try to
;send to the PTY in one shot. This is kept in CHRCNT and is counted down to 0.
PTYLF1: MOVEI A,MAXPTC ;[34] Init the PTY buffer counter
MOVEM A,CHRCNT ;[34] Initialize the count of chars seen
;Here when we are ready to send a character to the PTY. First, see if there is
;any echoing or other output from the PTY. After that, get a character from
;the command file and transmit it to the subjob.
PTYLF2: TXO F,NOINTF ;[34] Don't allow other subjobs typeout
CALL PTYTYP ;[34] Display anything for current job
JFCL ;[34] Don't care if input there
CALL FILGET ;[34] Get a character from file
SOS CHRCNT ;Count down the number of characters
PUSH P,A ;Save character
CALL PTYOUT ;Send it to the PTY
POP P,A ;Get back character
;If the character we just send to the subjob is a return or linefeed, we are
;done with this line. If not we check to see if we have sent the maximum
;number of characters to the PTY. If so, we just wait a little bit and then
;try to send more.
CAIE A,.CHLFD ;Was it a linefeed
CAIN A,.CHCRT ; or a carriage return?
JRST PTYLF3 ;Yes, go read in any echoes please
TXZ F,NOINTF ;[34] OK to have PTY typeout now
SKIPLE CHRCNT ;Have we send too many characters to PTY?
JRST PTYLF2 ;[34] If PTY buffer not full, go get more
MOVEI A,^D20 ;Buffer full, let subjob eat them
DISMS% ;Drum our fingers for a little bit
JRST PTYLF2 ;Loop back to check for more stuff
;[34] Here after we have transmitted a CR or LF to the subjob. We also get
;here after resuming a subjob output display interrupt. First try to display
;any characters the PTY has for us. Then see if it is hungry and if so feed it
;some more characters. If it is not hungry, wait for an interrupt (PTY output
;available to display or PTY hungry) or 1 second.
PTYLF3: TXZ F,PEEKF ;Clear the "peeked at next character" flag
PTYLF4: TXO F,NOINTF ;No typeout from other subjobs now
CALL PTYTYP ;Try to display stuff from PTY
JFCL ;Don't care if TTY input available
TXZ F,NOINTF ;OK for other subjob typeout now
CALL HUNGRY ;Is the PTY hungry?
JRST PTYLF1 ;Yes, feed it
CALL IOWAIT ;Wait for one second's time or interrupt
TXOE F,PEEKF ;Have we peeked at next character yet?
JRST PTYLF4 ;Yep, just continue waiting
;[34] Check the next character of file and if it is a trap character process
;the trap character by looping back above. We read the next character from the
;file and then reeat it. This makes a ^X after R PROGRAM work properly.
MOVE A,RDJFN ;Reload the file's JFN
BIN% ;Get a character
ERJMP PTYLF2 ;Find out what's wrong later
BKJFN% ;Reeat the character please
ERJMP PTYLF2 ;What happened? Find out later
CAIN B,"^" ;Is it an uparrow?
JRST PTYLF2 ;Yep, don't care if PTY is not hungry yet
JRST PTYLF4 ;Loop for more
SUBTTL Connect to PTY -- Get Character from TTY
;Routine to get a character from TTY - used only when connected. Waits until
;one of three things happens: a character appears in TTY input buffer,
;connected PTY is hungry, or any PTY has output to display.
;
;Returns +1: got PTY interrupt while waiting for character
;Returns +2: got a character A/ character
TTYGET: CALL TTGETW ;[34] Wait for characters on PTY or TTY
TXNN F,TTWATF ;[34] TTY input available?
JRST TTGET2 ;[34] Yes, please enjoy reading them
TXZ F,TTWATF ;[34] It was a PTY interrupt, don't get TTY
RET ;[34] Return +1 for PTY interrupt
;Here when we suspect that the terminal input buffer is empty.
TTGET2: TXZ F,PTWATF ;[34] Not waiting for PTY IO now, reading char
MOVE A,TERJFN ;[34] Load the terminal JFN again
BIN% ;[34] Read character we think is there
ERJMP CPOPJ ;[34] Return if error (!)
MOVE A,B ;[34] Copy character to A
ANDI A,177 ;[34] Strip any parity crap off of character
JRST CPOPJ1 ;[34] Return +2 with A/ character
;Local routine to wait for activity, either a character typed on the terminal
;or a PTY is hungry or PTY has output for us to display.
TTGETW: TXON F,TIFLAG ;[34] Set TI done flag, skip if already set
RET ;[34] Return now, going into TI as requested
MOVE A,TERJFN ;[34] Load designator for our controlling TTY
TXZ F,TTWATF!PTWATF ;[34] We are not in I/O wait for TTY or PTY
SIBE% ;[34] Is the input buffer empty?
RET ;[34] No, return now
TXO F,TTWATF!PTWATF ;[34] We are in I/O wait for TTY or PTY
WAIT% ;[34] No, its OK to wait
SUBTTL Connect to PTY -- Get Character from File
;[34] Here to get a character from the command file, used only while connected.
;Returns: +1 always A/character
;Goes to PTYLOP if EOF detected, COMLVL if trap character detected
FILGET: CALL RDBIN ;Get a character in B from file
JRST FILGE7 ;EOF
MOVE A,B ;We got a character, make a copy of it
CAMN A,TRPCHR ;Was it the escape character?
JRST FILGE5 ;Yes
CAIE A,.CHCRT ;Return?
RET ;Return A/ character
;Return seen, eat any linefeed after it.
CALL RDBIN ;Get next character
JRST FILGE3 ;EOF
CAIE B,.CHLFD ;Return followed by linefeed?
BKJFN ;Nope, reeat the character
ERJMP .+1 ;Ignore error
FILGE3: MOVEI A,.CHCRT ;Load a return
RET ;Return it
;Here if trap character.
FILGE5: MOVEI A,"^" ;Output an uparrow
PUSHJ P,TTBOUT ; on the TTY
MOVE A,TRPCHR ;Get the trap character back
ADDI A,"A"-.CHCNA ;Convert it to printable ASCII
CALL TTBOUT ;Send that to the terminal
CALL CRLF ;End line
JRST COMLVL ; and return to command level
;Here if EOF.
FILGE7: TXZ F,TIFLAG ;Insure that we enter TI wait next time
JRST PTYLOP ;Restart pipeline
SUBTTL TTY Input Routines -- Open/Close Binary TTY JFN
;[34] Here to open binary TTY JFN.
OPNTTY: CALL CLSTTY ;Close it first
MOVX A,GJ%SHT ;Prepare to open binary channel on TTY
HRROI B,[ASCIZ/TTY:/] ; for pipeline for subjobs
GTJFN% ;Get JFN on TTY
BUG(HLT,<couldn't get handle on TTY for binary channel>)
MOVEM A,BINTTY ;Save the binary channel
MOVX B,FLD(10,OF%BSZ)!OF%WR!OF%RD ;Open 8 bit, read, write
OPENF% ;Open it in binary mode (implied by 8 bit byte)
BUG(HLT,<couldn't open the TTY in binary for PTY communication>)
RET ;Return to caller
;[34] Here to close TTY JFN.
CLSTTY: SKIPE A,BINTTY ;Get any previous binary channel
CLOSF% ;Close it
JFCL ;Failure probably because it was never open
SETZM BINTTY ;No longer a JFN
RET ;Return
SUBTTL TTY Input Routines -- Set/Reset TTY Modes
;[34] Here to set usual TTY modes for PTYCON, remembering current modes.
SETTTY: MOVEI A,.PRIIN ;For the controlling terminal
SKIPN B,SAVMOD ;Was it saved before?
RFMOD ;Get current mode
MOVEM B,SAVMOD ;No, this is first time through
MOVE B,SAVMOD ;Get original mode
TXO B,TT%WKF!TT%WKN!TT%WKP!TT%WKA!FLD(.TTATE,TT%DAM) ;Break on all
SFMOD ;Set JFN mode word
STPAR ;Set TTY parameters
MOVNI A,5 ;Now grab all terminal interrupt chars
SKIPN B,SAVTIW ;Was it saved already?
RTIW ;Read current
MOVEM B,SAVTIW ;No, save it for exiting
MOVE B,TIMASK ;Get special interrupt characters
STIW ;Set terminal interrupt word
RET ;Return
;[34] Here to reset TTY modes for pushing or exiting.
;Returns +1 always.
RESTTY: MOVEI A,.PRIIN ;For the controlling terminal
MOVE B,SAVMOD ;Get original mode
SFMOD ;Set JFN mode word
STPAR ;Set TTY parameters
MOVNI A,5 ;For the world
MOVE B,SAVTIW ;Get saved terminal interrupt words
STIW ;Set them
RET ;Return
SUBTTL TTY Input Routines -- Escape (Trap) Character Interrupt
;Here on interrupt when the trap character typed (usually Control-X).
TRAP: TXO F,NOINTF ;[34] No typeout for a little bit please
CALL ASCTER ;Get ASCII terminal set up
MOVEI A,"^" ;First output an uparrow
CALL TTBOUT ; on the TTY
MOVE A,TRPCHR ;Get the trap character
TRO A,100 ;Make it into the ASCII counterpart
CALL TTBOUT ;Print it
CALL CRLF ;Type crlf
;Here when we want to return to command level (by escape character or panic
;interrupt), abort any command file in progress, set command level as address
;to resume, and dismiss interrupt.
TRAP1: CALL GCLOSE ;[34] Close the command file, set cmds to tty
TXZ F,TTWATF!PTWATF ;[34] Not waiting for PTY or TTY interrupt
SETOM CURENT ;[34] No longer connected to a subjob
MOVEI A,.PRIIN ;Clear typeahead
CFIBF ; of unread junk
MOVEI A,COMLVL ;[34] Get another command
MOVEM A,RETSAV ;[34] after DEBRK
DEBRK% ;[34] Dismiss the interrupt
JRST COMLVL ;[34] Not at interrupt level(!)
SUBTTL TTY Input Routines -- Control-C Interrupt
;Control-C interrupt handler. Control-C at top level PTYCON prompt is illegal,
;but commands of the form "subjob-^C" are legal. At this time the command text
;up to the control-C is in the command buffer.
COMCC: HRROI A,[ASCIZ "^C"] ;Echo the Control-C
PSOUT ;Print without logging for now
;There is a command in the command buffer. Parse it to see if it is a
;"subjob-text" type command. If so, stick a ^C on end of command and reparse.
MOVE A,CMDSBK+.CMBFP ;[34] Get byte pointer to start of command
MOVEM A,CMDSBK+.CMPTR ;[34] and save it as start of unparsed chars
MOVEI C,5*CBUFSZ-1 ;[34] Load size of that buffer in characters
MOVEM C,CMDSBK+.CMCNT ;[34] Entire buffer is free right now
COMCC0: ILDB B,A ;[34] Get a character from the command
SOJL C,COMC1 ;[34] Jump if off end of buffer
JUMPE B,COMC1 ;[34] No hyphen seen yet, ^C is illegal
CAIE B,"-" ;[34] Is it a hyphen?
JRST COMCC0 ;[34] Nope keep looking
COMCC1: ILDB B,A ;[34] Get next character of string
SOJL C,COMC1 ;[34] Jump if off end of the buffer
JUMPN B,COMCC1 ;[34] Jump if not a null
COMCC2: MOVEI B,.CHCNC ;[34] Load a control-C
DPB B,A ;[34] Store that in the buffer
MOVEI B,0 ;[34] Load a null
IDPB B,A ;[34] Insure null at end of string (2nd ^C?)
SUBI C,5*CBUFSZ-1 ;[34] Subtract size of buffer to get -ive count
MOVMM C,CMDSBK+.CMINC ;[34] and save count (including the Control-C)
TXZ F,TTWATF!PTWATF ;[34] Not waiting for PTY or TTY interrupt
MOVEI A,COM0 ;[34] Load reparse address
MOVEM A,RETSAV ;[34] Save it as place to go
DEBRK% ;[34] Reparse the command
;Here if ^C typed at PTYCON command level or in the middle of a command. Log
;the "^C" string, and give an appropriate error message.
COMC1: SKIPE A,LOGJFN ;LOGGING THIS?
JRST [ HRROI B,[ASCIZ "^C"] ;STRING TO WRITE
SETZM C ;WRITE IT ALL
SOUT ;WRITE TO LOG FILE
ERJMP .+1 ;IGNORE ERROR
JRST .+1] ;CONTINUE
PUSHJ P,CHKLOG ;SEE IF ANY JOBS LOGGED IN
JRST [ERRMES (<? Type "EXIT" to exit from PTYCON>)
JRST COMC2] ;NO ACTIVE SUBJOBS
ERRMES (<? Subjobs active, use "PUSH" command>)
;If there is a command file in progress, terminate it, and reset terminal
;modes. Return to command level from the interrupt, ready for the next
;command.
COMC2: CALL GCLOSE ;[34] Close cmd file JFN, set cmds to tty
CALL SETTTY ;[34] Set TTY back to the way we like it
TXZ F,TTWATF!PTWATF ;[34] Not waiting for PTY or TTY interrupt
MOVEI A,COMLVL ;Restart fresh
MOVEM A,RETSAV ; after dismiss
DEBRK% ;Dismiss interrupt, returning to COMLL
SUBTTL TTY Input Routines -- TTY Input Interrupt
;Terminal type in interrupt handler. Here on TINCHN interrupts when any
;character has been typed on the controlling terminal. This code also causes
;the top level to get out of the WAIT% JSYS if it is in one.
TYPIN: SKIPE RDJFN ;READING FROM FILE?
DEBRK% ;YES, DISMISS INTERRUPT
;[34] TXNE F,TOFLAG ;Typout in progress?
;[34] TXZ F,NOINTF ;Typeout in progress, allow more output display
TXZE F,TTWATF ;[34] Currently waiting for typin?
POP P,RETSAV ;[34] Yes, return from the wait routine
DEBRK% ;[34] Dismiss interrupt, returning back
;[34] Here to wait for terminal input only, returns with some available. Uses
;above routine to get out of the WAIT% JSYS. The TTWATF flag is zero when we
;do not want to wait (something was typed). The TTWATF flag is zero when we
;are not stuck in the WAIT% JSYS. To avoid race conditions, we check the to
;see if there are any characters in the buffer after we set TTWATF. The TIFLAG
;is set to zero when we want to go into TI wait. It is set each time through
;here so that the second through Nth time through here we actually wait rather
;than going into TI. All of this is needed for the case of SYSJOB running
;PTYCON (or PTYCON running PTYCON while processing a command file).
TIWAIT: TXON F,TIFLAG ;Set TI done flag, skip if already set
RET ;Return now, going into TI as requested
MOVE A,TERJFN ;Point to the controlling terminal
TXNE F,TTWATF ;Get here with this on?
BUG(HLT,<TIWAIT called when in wait state>) ;Somethin's hittin the fan
SIBE% ;Is the input buffer empty?
RET ;No, return now
TXO F,TTWATF ;We are in I/O wait for TTY
WAIT% ;No, its OK to wait forever
SUBTTL TTY Input Routines -- Set up Binary or Primary JFN
;Call ASCTER to set up ASCII terminal
;Call BINTER to set up binary (8 bit) terminal
BINTER: SKIPA A,BINTTY ;[34] Load the binary TTY JFN
ASCTER: MOVEI A,.PRIOU ;[34] Load the usual primary I/O designator
MOVEM A,TERJFN ;SET IT
RET ;AND DONE
SUBTTL Command File Input Routines -- Command Level Read
;[34] Routine to read in and convert command file, used only from command
;level. Reads until escape or linefeed seen. Eats leading spaces, comments
;embedded by "!" at the start of a line, and entire comment lines preceeded by
;a semicolon. Returns +1 always.
GCNVT: SETZB C,CMDCNT ;No characters yet
MOVE D,CMDSBK+.CMBFP ;Point to command buffer
RCONV: MOVE C,CMDCNT ;Load count of characters in line
RCONV0: CALL RDBIN ;Get a character into A
JRST RCONV7 ;End of command file
CAIE B,.CHTAB ;Is it a tab
CAIN B," " ; or a space?
JUMPE C,RCONV0 ;Yes, if no characters so far eat leading space
CAIE B,"!" ;Is it the start of an embedded comment
CAIN B,.CHSEM ; or is it the start of a one line comment?
JUMPE C,RCONV2 ;Yes, we will have to eat it if at BOL
IDPB B,D ;Write it to the command buffer
AOS C,CMDCNT ;One more unparsed character
CAMN B,TRPCHR ;Was it the escape character?
JRST RCONV7 ;Yep
CAIE B,.CHLFD ;Was character a linefeed?
CAIN B,.CHESC ;Was character an escape?
RET ;Yes, parse command so far
CAIN B,.CHCRT ;Was character a CR?
JRST RCONV4 ;Yes
JRST RCONV0 ;No, process next character
;Character was the start of a comment on a line, eat entire line.
RCONV2: MOVE C,B ;Copy comment character start to C
CALL RDBIN ;Get a character
JRST RCONV7 ;None there, probably EOF
CAIN C,"!" ;Is it en embedded comment?
CAIE B,"!" ;Yes, another character ends it
CAIN B,.CHLFD ;Line feed which always ends comment?
JRST RCONV ;Yes, start with a new line now and reload C
JRST RCONV2 ;No, eat all of them
;Character was a return, check for LF after it and if so put in buffer.
RCONV4: CALL RDBIN ;Read next character
JRST RCONV7 ;End of file
CAIE B,.CHLFD ;Character a line feed
JRST RCONV6 ;Nope, reeat it and return
CAIN C,1 ;Just a CR followed by LF in file?
JRST GCNVT ;Yes, restart this mess
IDPB B,D ;It was a linefeed, store it in buffer
AOS CMDCNT ;Count this one
RET ;Return
;Character after the return was not a linefeed(!) reeat it and return.
RCONV6: BKJFN ;Put character back
ERJMP .+1 ;Ignore error
RET ;Return
;Here if trap character seen or end of file.
RCONV7: SETZ B, ;Load a null
IDPB A,D ;End command line
CALL TRYLOG ;Log command, echo if command file
CALL CRLF ;Output a CRLF
CALL SETTTY ;Insure TTY set
JRST COMLVL ; and return to command level
SUBTTL Command File Input Routines -- Read Character From Command File
;[34] Here when character needed from command file. Uparrow followed by some
;character is converted to the control character. Uparrow followed by
;dollarsign (^$) is converted to escape. Uparrow followed by uparrow is
;converted to uparrow.
;
;Returns +1 if EOF
;Returns +2 with A/ JFN, B/ converted control character
RDBIN: MOVE A,RDJFN ;Load command file JFN
BIN ;Get character from file
ERJMP RDBIN7 ;Owie, check to see if it is EOF
CAIE B,"^" ;Uparrow?
JRST CPOPJ1 ;Yes, skip return B/ uparrow
BIN ;Get next character
ERJMP RDBIN7 ;EOF probably
CAIN B,"^" ;Another uparrow?
RET ;Yes, return it
CAIN B,"$" ;Dollar sign?
SKIPA B,[.CHESC] ;Yes, load an escape and skip
TRZ B,140 ;Convert upper/lower case to control whatever
JRST CPOPJ1 ;Return with B/ control character
;Here on error on the BIN, probably its EOF.
RDBIN7: MOVE A,RDJFN ;Get original JFN
GTSTS ;Get status
ERJMP RDBIN8 ;Ignore error
TXNN B,GS%EOF ;End of file?
RDBIN8: JERMES(<? Error while reading command file>) ;Some kind of error
SETOM LMFLAG ;Indicate we should use RFPOS now
CALLRET GCLOSE ;Close the command file and return +1
SUBTTL Command File Input Routines -- Get More Command File Characters
;[34] Here to get more from command file when EOF reached during COMND JSYS.
;We can get here when an escape is in the middle of a command line from the
;command file (since RCONV breaks on a return and escape). We will fill the
;command buffer (until escape or return seen) then go to the reparse address to
;parse the command.
GETMOR: MOVE A,CMDSBK+.CMBFP ;Point to the command buffer
SETZ C, ;Clear count of characters in buffer
GETMO1: ILDB B,A ;Get a character from buffer
JUMPE B,GETMO2 ;If null we are at end of buffer
AOJA C,GETMO1 ;Loop, counting each non-null character
GETMO2: MOVEM C,CMDCNT ;Store count of useful characters in buffer
MOVNI D,1 ;Load a -1
ADJBP D,A ;Back up the byte pointer just one
CALL RCONV ;Fill until escape or return seen, D/ pointer
MOVE A,CMDCNT ;Load number of characters put in buffer
MOVEM A,CMDSBK+.CMINC ;Save as unparsed character count
MOVE A,CMDSBK+.CMBFP ;Load pointer to start of buffer
MOVEM A,CMDSBK+.CMPTR ; and save that as start of characters to parse
MOVEI A,CBUFSZ*5-1 ;Reset space after the CMPTR pointer
MOVEM A,CMDSBK+.CMCNT ; to be entire buffer full
JRST COM0 ;Go to reparse address and try command again
SUBTTL Command File Input Routines -- Close Command File
;[34] Here to close the command file JFN, resets I/O JFNS for command parsing.
;Returns +1 always.
GCLOSE: TXZ F,SILNCF ;[34] Clear silence flag
MOVE A,[.PRIIN,,.PRIOU] ;Reset TTY
MOVEM A,CMDSBK+.CMIOJ ;as input and output JFN
SKIPE A,RDJFN ;Any JFN there?
CLOSF% ;Dump the JFN
ERCAL GCLOSR ;Can't close it?
SETZM RDJFN ;JFN not open now
RET ; and return
GCLOSR: SKIPN A,RDJFN ;Load the file's JFN
RLJFN% ;Release it
ERJMP .+1 ;Ignore any errors for now
RET ; and return to above code
repeat 0,< ;Not currently used
;[34] Small routine to print current command filename on terminal.
;Returns +1 always, uses STRING.
RDJFNS: CALL RTJFNS ;Return A/ pointer to filename
CALLRET TTSOUT ;Output to terminal and return
;[34] Small routine to ASCIIze the filename indicated by RDJFN.
;Returns +1 always, uses STRING, A/ pointer to STRING
RTJFNS: SETZM STRING ;Clear the string easily
HRROI A,STRING ;Point to temp area to output
MOVX C,0 ;Default format
SKIPE B,RDJFN ;Is there a file?
JFNS ;JFN to String
ERJMP CPOPJ ;Return now if error
HRROI A,STRING ;Point to string area again
RET ;Return to caller
>;end of repeat 0
SUBTTL Command File Input Routines -- Echo Command Line
;Routine to print command line during processing of command file.
PRTCMD: HRROI A,CMDBUF ;No, print command buffer
TXNN F,SILNCF ;[34] Was output silenced?
PSOUT ; to terminal
ERJMP .+1 ;Ignore error(!)
RET ;Return
SUBTTL PTY Output Routines -- Main Loop
;Routine to do output from PTYs. Dumps output from all subjobs that are not
;discarded or refused. Should be called with NOINTF set. Outputs new header
;if needed. Returns+1 always.
PTOCHK: PUSH P,P2 ;Save AC for count of lines waiting
PUSH P,P1 ;Save AC for subjob counter
PUSH P,I ;Save current subjob index
SETZB I,P2 ;Start at 0 for subjob, no lines waiting
MOVE P1,PTYHGH ; and do all defined subjobs
PTOCK1: CAME I,CURENT ;[34] Connected? Let other loop output chars
SKIPN PTYCNT(I) ;Is there anything waiting to be displayed?
JRST PTOCK2 ;No, go on to next subjob
MOVE A,PTYSTS(I) ;Yes, get status of subjob
TXNE A,PTREFF ;[34] Is subjob being refused?
TXNE A,PTDISF ;[34] and not ignored?
SKIPA ;No, OK to type it out
JRST [ CALL DINGGO ;Yes, start ding fork up
AOJA P2,PTOCK2] ;Mark that one was found waiting
CALL PTYTYP ;Type out header and text from subjob
JRST PTOCK3 ;Uh oh, type in pending on TTY, return now
PTOCK2: ADDI I,PTYLEN ;Step to next subjob index
SOJGE P1,PTOCK1 ;Loop back for all lines
SKIPN P2 ;Were any lines waiting still?
CALL STDING ;No, then stop the dinging now
PTOCK3: POP P,I ;Restore current subjob index
POP P,P1 ;Restore P1
POP P,P2 ; and P2
SKIPL CURENT ;[34] If connected
CALL PTYHDR ;[34] output header if needed
RET ;[34] Return to caller
SUBTTL PTY Output Routines -- Display Standard Header
;Here to typeout a standard header if needed before or after display of subjob
;output, returns +1 always with header typed if needed and IGNORF and LSTHDR
;set up properly.
PTYHDR: TXZ F,IGNORF ;[34] Initialize ignore flag to off
CAMN I,CURENT ;[34] Not reading from file, are we connected?
TDZA A,A ;[34] Yep insure ignore flag off when connected
MOVE A,PTYSTS(I) ;Get PTY status
TXNE A,PTDISF ;[34] Ignoring type out?
TXO F,IGNORF ;[34] Silent running or discarded subjob
CAMN I,LSTHDR ;Is it same as last header typed?
RET ;[34] Yes, don't output a header
MOVEI A,.PRIOU ;Primary I/O designator
DOBE ;Wait for TTY to be quiet
RFMOD ;Now get the JFN mode word
TXZE B,TT%OSP ;[34] Output suppress on?
SFMOD ;Yes, clear it
CALL PIOFF ;Prevent interrupts in the middle of header
PUSH P,TERJFN ;Save present TTY JFN (binary or not)
CALL ASCTER ;Get ASCII terminal JFN set up
CALL GETLM ;[34] Get to left margin
HRROI A,[ASCIZ/**** /] ;Begin header
CALL TTSOUT ; with four stars and a space
CALL TYPNAM ;Type job name and number next
MOVEI A," " ;Seperate that with
CALL TTBOUT ; a space
HRROI A,STRING ;Point to temp area to store time
SETO B, ; current time
MOVX C,OT%NDA ;[34] Do not output date
ODTIM ;[34] Just output time
HRROI A,STRING ;Point to that string of time
CALL TTSOUT ;Output as a time stamp
HRROI A,[ASCIZ/ ****
/] ;Close off the
CALL TTSOUT ; header with stars and a return
POP P,TERJFN ;Restore TTY JFN designator
CALL PION ;Enable interrupts again
TXNN F,IGNORF ;If being ignored, don't store I
MOVEM I,LSTHDR ;Remember this job index as last header typed
RET ;[34] Return to caller
SUBTTL PTY Output Routines -- Display One Subjob Output
;[34] Routine to output for a particular PTY including header. Eats output
;from discarded subjobs. Calls usual header routine, which sets up IGNORF,
;should come here with NOINTF set.
;Returns +1 if TTY input is available, all possible characters output
;Returns +2 if no TTY input available, all possible characters output
PTYTYP: SKIPN PTYCNT(I) ;Anything to type out for connected PTY?
JRST PTYTP9 ;Nope, return
CALL PTYHDR ;Typeout header, set up IGNORF
CALL BINTER ;Set binary terminal mode
PTYTP2: SKIPGE CURENT ;At command level?
JRST PTYTP3 ;Yes, check for TTY input always
CAME I,CURENT ;See if this is the current job
JRST PTYTP4 ;No, don't check TTY
PTYTP3: SKIPE RDJFN ;Reading from file?
JRST PTYTP4 ;Yes, disregard TTY for now
MOVE A,TERJFN ;Load terminal JFN
SIBE ;Any characters in TTY input buffer?
JRST PTYTP8 ;Yep, give +1 return
PTYTP4: CALL PTYGET ;Get a character from buffer
JRST PTYTP7 ;No more left
PTYTP5: CALL TTBOUT ;Yep, output to tty and possibly log
JRST PTYTP2 ;Loop back for more
PTYTP7: MOVEI A,.PRIOU ;Get I/O designator for controlling TTY
DOBE ;Wait for output to finish on the TTY
CALL PTYGET ;See if any more characters arrived
JRST PTYTP9 ;Nope, all done
JRST PTYTP5 ;Yes, go type these out
PTYTP9: AOS (P) ;Give skip return
PTYTP8: CAME I,CURENT ;Unless current subjob
CALL GETLM ;Get to left margin
TXZE F,IGNORF ;If ignoring use RFPOS to figure out where
SETOM LMFLAG ; we are, can cause one extra CRLF in log
RET ; and return
SUBTTL PTY Output Routines -- Periodic Check
;Check for PTY output available, here from DEBRK in PTYOPC interrupt code
;(CHKPTO) or from end of command that manipulates subjobs (CHKPTY). Prints
;output then goes back to whatever we were doing earlier (command level or
;subjob level). DANGER Will Robinson! Don't go anywhere from this routine
;that doesn't reload the stack pointer or you will get PDL overflows!
CHKPTY: TXOA F,NOINTF!TOFLAG ;[34] Don't nest, always want to get to COMLVL
CHKPTO: TXZ F,TOFLAG ;[33] Initialize typeout flag
SKIPGE CURENT ;[34] If not connected
SETOB I,LSTHDR ;[33] make sure a header is printed
CALL PTOCHK ;[33] (I/) Print out any PTY output
SKIPL CURENT ;[34] Connected?
JRST PTYLOP ;[34] Yep, resume the connection
TXNE F,TOFLAG ;[33] Anything typed to terminal?
JRST COMLVL ;[33] Yes, go home and get a new command
JRST COMSTR ;[33] Restart command without prompting
;Here on TIMER interrupt to check for PTY output to display. DEBRKs to CHKPTO
;if there is output to display, and NOINTF is not set, and the operator is not
;typing in a commmand. Always makes just one more TIMER interrupt for the next
;time.
PTYOPC: PUSHJ P,ACSAVE ;SAVE ACS
TXNE F,NOINTF ;[34] OK to display PTY output now?
JRST PTYOP1 ;No, not OK to display PTY output now
MOVE A,CMDSBK+.CMBFP ;Check first character in command
ILDB B,A ; buffer to see if anything typed yet
SKIPGE CURENT ;Do it no matter what if subjob level
JUMPN B,PTYOP1 ;There was a char, don't display PTY output
TXZ F,TTWATF!PTWATF ;[34] Not waiting for PTY or TTY interrupt
MOVEI A,CHKPTO ;OK for PTY output check,
MOVEM A,RETSAV ; store continuation address
PTYOP1: TXO F,NOINTF ;[34] No interrupts until current one done
MOVE A,[XWD .FHSLF,.TIMEL] ;Need elapsed time interrupt this fork
MOVEI B,^D5000 ;Five seconds till next check
MOVEI C,PTYOCN ;Interrupt on check channel
TIMER ;Ask monitor to tap us in five seconds
ERJMP .+1 ;Ignore error, shouldn't happen
CALL ACLOAD ;Restore acs
DEBRK% ;Dismiss interrupt
SUBTTL TTY Output Routines -- Output CRLF
;[34] Here to get to left margin if needed, outputs a CRLF conditionally
GETLM: SKIPL LMFLAG ;Do we know where we are?
JRST GETLM1 ;Yep
MOVEI A,.PRIIN ;Point input to primary
RFPOS ;Read position now
HRRZM B,LMFLAG ;Save it here
GETLM1: SKIPG LMFLAG ;At left margin?
RET ;Yes, return now
;No, fall through to CRLF
;Here to output CRLF to terminal.
CRLF: HRROI A,[ASCIZ/
/] ;Point to a CRLF string
;[34] SETOM LMFLAG ;Use RFPOS to find our position
CALLRET TTSOUT ;Type out cr-lf, return to caller
SUBTTL TTY Output Routines -- Output Character to TTY
;Here to output the character in A to the terminal using either binary or
;normal JFN with logging to file as needed.
TTBOUT: EXCH A,LSTCHR ;Get last character typed
CAIE A,.CHCRT ;Was it a CR?
SKIPA ;No
CAME A,LSTCHR ;Yes, is this character a CR also?
SKIPA A,LSTCHR ;No, then type it
RET ;Yes, dont type two in a row
CAIL A," " ;If it is a printing character
AOS LMFLAG ; we are not not at left margin, count it
CAIE A,.CHLFD ;If its a line feed or
CAIN A,.CHCRT ; a carriage return
SETZM LMFLAG ; then reset counter for carriage return
SKIPE RDJFN ;[34] Are we reading a command file
TXNN F,SILNCF ;[34] and are we silenced?
TXNE F,IGNORF ;[34] Ignoring this PTY?
JRST TTBLOG ;Silenced or discarded subjob, just log char
PUSH P,B ;No no no, don't clobber B
MOVE B,A ;Put character in B
MOVE A,TERJFN ;Get appropriate TTY JFN (binary or regular)
BOUT ;Type the character on the terminal
MOVE A,B ;Restore A as the character
POP P,B ;And whatever was in B
CAIE A,.CHBEL ;Bell?
TXO F,TOFLAG ;No, set type out occurred flag
JRST TTBLOG ;Try to log the character and return
SUBTTL TTY Output Routines -- Output String to TTY
;Here to output string to terminal, on non-binary channel only
TTSOUT: PUSH P,TERJFN ;Save the TTY channel
PUSH P,A ; and the string pointer
CALL ASCTER ;[34] Use non-binary channel for now
POP P,A ;Retrieve the pointer to the message
CALL TTSOU1 ;Print it
POP P,TERJFN ;Restore the TTY channel
RET ; and return
TTSOU1: TLC A,-1 ;Do we need to convert -1,,address
TLCN A,-1 ; into a byte pointer?
HRLI A,(POINT 7,0) ;Yes, set up byte pointer
PUSH P,B ;Save B
MOVE B,A ;Get string pointer out of A
TTSOUL: ILDB A,B ;Get next char of string
JUMPE A,TTSOUD ;If null, then done
CALL TTBOUT ;Type out char on terminal
JRST TTSOUL ;Loop till null found
TTSOUD: MOVE A,B ;Return updated string pointer in A
POP P,B ;Restore B
RET ; and return
SUBTTL Log File Output Routines -- Open Log File
;[34] Here to open the log file, call with A/ JFN
;Returns +1 always, LOGJFN set up if it worked.
OPNLOG: PUSH P,A ;Save the JFN
MOVX B,FLD(7,OF%BSZ)!OF%WR!OF%APP ;Pry it open again in append mode
OPENF% ;Crrreeeaaakk
ERJMP OPNLG1 ;Failed!
POP P,LOGJFN ;Return log JFN
RET ;Return
OPNLG1: JERMES (<? Error opening PTYCON log file>) ;Give me an error
POP P,JFNIP ;Put JFN where it will be released
JRST COMLVL ;Back for another command please
;[34] Here to reopen the log file (after EXIT then CONTINUE).
;Returns +1 always, log file reopened if needed.
ROPLOG: SKIPN LOGBUF ;Was there a log file?
RET ;Nope, return
HRROI B,LOGBUF ;Get name of last log file
MOVX A,GJ%SHT ;Short form
GTJFN ;Get JFN for the existing log file
ERJMP ROPLO1 ;Error, output message and return
CALL OPNLOG ;Open the log file again
CALLRET STRLOG ;Start like a new log file and return
ROPLO1: JERMES (<? Error reopening PTYCON log file>) ;Give error
RET ;Return to caller
SUBTTL Log File Output Routines -- Start Log File
;[34] Here to start new log file, writes header and saved log filename.
;Returns +1 always
STRLOG: HRROI B,[ASCIZ/
************************************************************************
/] ;Point to string of stars
SETZ C, ;Stop on null
SOUT ;Output header to file
ERJMP ERRLOG ;Error, could be disk full
HRROI B,SVN ;Point to version string
SOUT ; output it
ERJMP ERRLOG ;Error, could be disk full
HRROI B,[ASCIZ/ Log File /] ;What kinda file?
SOUT ;Send out header
ERJMP ERRLOG ;Error, could be disk full
SETO B, ;Now send out the date
ODTIM% ;Output Date and TIMe
ERJMP ERRLOG ;Error, could be disk full
HRROI B,[ASCIZ/
/] ;Make it look neat
SOUT ; by sticking a blank line in there
ERJMP ERRLOG ;Error, could be disk full
MOVE B,LOGJFN ;Get JFN
HRROI A,LOGBUF ;Point to log name buffer
MOVX C,JS%SPC ;Want entire filespec
SETZ D, ;Clear unused register
JFNS ;JFN to String
ERJMP .+1 ;Ignore error
RET ;Return
SUBTTL Log File Output Routines -- Write Errors and Close Log File
;[34] Here to close log file.
;Returns +1 always, LOGJFN cleared
CLSLOG: SKIPE A,LOGJFN ;Skip if a JFN on LOG file right now
CLOSF% ;Close it please
ERCAL ECLLOG ;Error in closing log file
SETZM LOGJFN ;Clear the JFN
RET ; and return
;[34] Here if error in closing log file, publish a little message then return
;CAUTION: Don't write to log file in this routine!
ECLLOG: HRROI A,[ASCIZ/ Error in closing PTYCON log file - /] ;Load error mess
ESOUT% ;Output it to terminal
CALL RTNERR ;Return pointer to error code
PSOUT% ;Output to terminal alone
SETZM LOGBUF ;Don't try to reopen this again
MOVE A,LOGJFN ;Load the logging file JFN yet again
TXO A,CZ%ABT ;Abort the JFN please
CLOSF% ;Crunch!
ERJMP .+1 ;Ignore errors
RET ;Return
;[34] Here if output failed to log file. CAUTION: Don't write to log file
;in this routine!
ERRLOG: HRROI A,[ASCIZ/Error while writing PTYCON log file - /] ;Start error
ESOUT% ;Output that error string please
CALL RTNERR ;Return last error string pointer in A
PSOUT% ;Output that too
CALL CLSLOG ;Close the log file
JRST COMLVL ;Abort what we were doing
SUBTTL Log File Output Routines -- Checkpoint Log File
;[34] Here to see if we should checkpoint the log file. This is determined by
;checking if enough time has elapsed since the last output to the file.
;Returns +1 always
CKPLOG: SKIPN LOGJFN ;Any log file open?
RET ;No, return now
TIME% ;Get system uptime in milliseconds
CAMGE A,NXLOGC ;Time to update log file?
RET ;Nope
ADDI A,^D60000 ;Compute time for next update (next minute)
MOVEM A,NXLOGC ;Remember this for next time
CALL PIOFF ;Don't allow interrupts here
MOVE A,LOGJFN ;Get logging JFN
TXO A,CO%NRJ ;Close it but keep the JFN
CLOSF% ;Slam
ERJMP CKPLO2 ;Owie!
MOVE A,LOGJFN ;Reload just the JFN
CALL OPNLOG ;Reopen the log file
CALLRET PION ;Turn pi system back on and return
CKPLO2: CALL ECLLOG ;Had a problem, go type message, etc.
SETZM LOGJFN ;Clear JFN for log file
CALLRET PION ;Turn on PI system and return
SUBTTL Log File Output Routines -- Output Character to Log File
;Here to log the character in A if the log file is open unless it is escape.
;Called only from TTBOUT.
TTBLOG: SKIPN LOGJFN ;Logging this?
RET ;No, return
PUSH P,B ;Save B
MOVE B,A ;Get charafter into B
MOVE A,LOGJFN ;Get logging JFN into A
CAIE B,.CHESC ;Don't send altmodes to file
BOUT ;Send out character to log file
ERJMP ERRLOG ;[34] Handle error
MOVE A,B ;Put character back into A
POP P,B ;Restore B
RET ;Return
SUBTTL Log File Output Routines -- Send String to Log File
;[34] Here to try to send a command to the log file. Also echoes any command
;file command to the terminal.
;Returns+1 always
TRYLOG: HRROI A,CMDBUF ;Point to command buffer
CALL TTSLOG ;Send it to the log file
SKIPE RDJFN ;Processing a command file?
CALL PRTCMD ;Yes, print command line
RET ;Return
;Here to send a string to log file only, call with A/ string pointer
TTSLOG: SKIPN B,LOGJFN ;Logging?
RET ;Nope, return
MOVEI C,0 ;Stop on a null
EXCH B,A ;Get string pointer and JFN swapped
SOUT ;Send it to the log file
ERJMP ERRLOG ;[34] Handle error if any
RET ;Return
SUBTTL Saved Input Routines -- Open Saved Input File
;[34] Here to open the saved input file, call with A/ JFN
;Returns +1 always, SVIJFN set up if it worked.
OPNSVI: PUSH P,A ;Save the JFN
MOVX B,FLD(7,OF%BSZ)!OF%WR!OF%APP ;Pry it open again in append mode
OPENF% ;Crrreeeaaakk
ERJMP OPNSV1 ;Failed!
POP P,SVIJFN ;Return JFN
RET ;Return
OPNSV1: JERMES (<? Error opening PTYCON saved input file>) ;Owie
POP P,JFNIP ;Put JFN where it will be released
JRST COMLVL ;Back for another command please
;[34] Here to reopen the saved input file (after EXIT then CONTINUE).
;Returns +1 always, saved input file reopened if needed.
ROPSVI: SKIPN SVIBUF ;Was there a saved input file?
RET ;Nope, return
HRROI B,SVIBUF ;Get name of last saved input file
MOVX A,GJ%SHT ;Short form
GTJFN ;Get JFN for the existing log file
ERJMP ROPSV1 ;Error, output message and return
CALL OPNSVI ;Open the saved input file again
CALLRET STRSVI ;Start like a new saved input file and return
ROPSV1: JERMES (<? Error reopening PTYCON saved input file>) ;Owie
RET ;Losing
SUBTTL Saved Input Routines -- Start Saved Input File
;[34] Here to start a new saved input file, writes header and saves new saved
;input filename. Returns +1 always.
STRSVI: HRROI B,[ASCIZ/
************************************************************************
/] ;Point to string of stars
SETZ C, ;Stop on null
SOUT ;Output header to file
ERJMP ERRSVI ;Error, could be disk full
HRROI B,SVN ;Point to version string
SOUT ; output it
ERJMP ERRSVI ;Error, could be disk full
HRROI B,[ASCIZ/ Saved Input File /] ;What kinda file?
SOUT ;Send out header
ERJMP ERRSVI ;Error, could be disk full
SETO B, ;Now send out the date
ODTIM% ;Output Date and TIMe
ERJMP ERRSVI ;Error, could be disk full
HRROI B,[ASCIZ/
/] ;Make it look neat
SOUT ; by sticking a blank line in there
ERJMP ERRSVI ;Error, could be disk full
MOVE B,SVIJFN ;Get JFN
HRROI A,SVIBUF ;Point to saved input name buffer
MOVX C,JS%SPC ;Want entire filespec
SETZ D, ;Clear unused register
JFNS ;JFN to String
ERJMP .+1 ;Ignore error
RET ;Return
SUBTTL Saved Input Routines -- Write Errors and Close File
;[34] Here to close saved input file.
;Returns +1 always, SVIJFN cleared
CLSSVI: SKIPE A,SVIJFN ;Skip if a JFN on saved input right now
CLOSF% ;Close it please
ERCAL ECLSVI ;Error in closing saved input file
SETZM SVIJFN ;Clear the JFN
RET ; and return
;[34] Here if error in closing saved input file, publish a message then return
ECLSVI: JERMES (<? Error in closing PTYCON saved input file>) ;Load error mess
SETZM SVIBUF ;Don't try to reopen this again
MOVE A,SVIJFN ;Load the saved input file JFN yet again
TXO A,CZ%ABT ;Abort the JFN please
CLOSF% ;Crunch!
ERJMP .+1 ;Ignore errors
RET ;Return
;[34] Here if output failed to saved input file. Closes file, returns to
;top level.
ERRSVI: JERMES (<? Error while writing PTYCON saved input file>) ;Ow!
CALL CLSSVI ;Close the saved input file
JRST COMLVL ;Abort what we were doing
SUBTTL Saved Input Routines -- Checkpoint Saved Input File
;[34] Here to see if we should checkpoint the saved input file. This is
;determined by checking if enough time has elapsed since the last output to the
;file. Returns +1 always.
CKPSVI: SKIPN SVIJFN ;Any saved input file open?
RET ;No, return now
TIME% ;Get system uptime in milliseconds
CAMGE A,NXSVIC ;Time to update log file?
RET ;Nope
ADDI A,^D60000 ;Compute time for next update (next minute)
MOVEM A,NXSVIC ;Remember this for next time
CALL PIOFF ;Don't allow interrupts here
MOVE A,SVIJFN ;Get saved input JFN
TXO A,CO%NRJ ;Close it but keep the JFN
CLOSF% ;Slam
ERJMP CKPSV2 ;Owie!
MOVE A,SVIJFN ;Reload just the JFN
CALL OPNSVI ;Reopen the log file
CALLRET PION ;Turn pi system back on and return
CKPSV2: CALL ECLSVI ;Had a problem, go type message, etc.
SETZM SVIJFN ;Clear JFN for log file
CALLRET PION ;Turn on PI system and return
SUBTTL Saved Input Routines -- Save PTY Typescript In File
;SAVE INPUT IN FILE IF ONE HAS BEEN SPECIFIED
LOGINP: SAVEAC <A,B,C>
SKIPN A,SVIJFN ;HAVE A JFN?
RET ;NO
CAIN B,.CHESC ;CHECK SPECIAL CHARACTERS, ESC
JRST [ MOVEI B,"^"
BOUT
MOVEI B,"$"
JRST SAVIP1]
CAIN B,.CHCRT ;CR
JRST [ BOUT ;PUT IN LF TOO
MOVEI B,.CHLFD
JRST SAVIP1]
CAIN B,.CHDEL ;A RUBOUT?
JRST [ BKJFN ;YES, TRY TO DELETE LAST CHAR FROM FILE
SKIPA A,SVIJFN ;COULDN'T, GET JFN BACK
RET ;OK, DON'T NEED TO PUT RUBOUT IN FILE
MOVEI B,.CHDEL ;MUST PUT RUBOUT IN FILE
JRST SAVIP1]
CAIGE B,40 ;PRINTING CHAR
CAIN B,.CHTAB ;OR TAB
JRST SAVIP1 ;YES, SEND AS IS
MOVE C,B ;CONTROL CHAR, SAVE IT
MOVEI B,"^"
BOUT ;SEND ESCAPE CHAR
MOVEI B,100(C) ;CONVERT CONTROL TO PRINTING EQUIV
SAVIP1: BOUT
RET
SUBTTL PTY Related Routines -- New Subjob Number
;[34] Routine to set up PTYSTS when a new subjob number comes into being.
;Call with I/ newly created highest subjob number
;Returns: +1 always
NEWHGH: MOVEI B,(I) ;Copy subjob index
IDIVI B,PTYLEN ;Get PTY number in B
CAMGE B,PTYHGH ;Is this a new high?
RET ;Nope
MOVE C,PTYHGH ;Get current high
IMULI C,PTYLEN ;Get index
MOVE A,B ;Get new high
SUB A,PTYHGH ;Get number of jobs needing initializing
SETZ D, ;Start with 0 for status
TXNE F,REFALF ;[34] Refusing all?
TXO D,PTREFF ;[34] Yes, set bit
TXNE F,DISALF ;[34] Discarding all?
TXO D,PTDISF ;[34] Yes, set bit
NEWHG1: ADDI C,PTYLEN ;Go to next subjob index
MOVEM D,PTYSTS(C) ;Store initial status word
SOJG A,NEWHG1 ;Loop for all jobs
MOVEM B,PTYHGH ;Store new high value
RET ;Return
SUBTTL PTY Related Routines -- Get PTY JFN
;Routine to get a PTY JFN.
;Returns +1 if error, error message already output
;Returns +2 if OK, PTYJFN(I) and PTYTTD(I) are set up
GETPTY: MOVN D,SYSPTY ;Get number of PTYs in system
HRLZS D ; starting at PTY0:
GETPT1: MOVSI A,.DVDES+.DVPTY ;Get PTY device designator
HRRI A,(D) ;Try to get next PTY number
DVCHR ;Get characteristics of this PTY
TXNN B,DV%AV ;Is it available?
JRST GETPT2 ;No, try nxt one
MOVE B,A ;Copy defice designator to B
HRROI A,STRING ;Point to place to build device name
DEVST ;Turn device designator into an ASCII string
JRST GETPT2 ;Oops, try next one
MOVEI B,":" ;Make the device name terminated
IDPB B,A ; by a colon
MOVEI B,0 ; and a null
IDPB B,A ; so we can get a JFN on it
MOVX A,GJ%SHT!GJ%ACC ;Short form GTJFN, no access by inferiors
HRROI B,STRING ;Point to device we want to get
GTJFN ;Try to get that JFN
JRST GETPT2 ;Not available, try next one
MOVX B,FLD(10,OF%BSZ)!OF%RD!OF%WR ;We want to read and write 8 bit
PUSH P,A ;Save the JFN
OPENF ;Pry it open
JRST GETPT3 ;Not available, release JFN and try next
POP P,A ;Get back JFN
ADD D,FIRPTY ;Turn pty unit number into TTY number
TRO D,.TTDES ;Make it a TTY designator please
HRRZM D,PTYTTD(I) ;Store TTY designator for later use
HRRZM A,PTYJFN(I) ;Store the JFN also
MOVEI A,.PRIOU ;Refer to the terminal we are on
GTTYP ;Ask the system what type we are
MOVE A,PTYTTD(I) ;Reference the PTY
STTYP ;Set the PTY type to the same as ourself
CPOPJ1: AOS (P) ;Give +2 return (label here to be jumped to)
CPOPJ: RET ;(label here to be jumped to)
GETPT3: CAIN A,MONX05 ;Was error from OPENF no resident free space?
JRST NORFSE ;Yes, give up now
POP P,A ;Get back the JFN
RLJFN ; and release it
ERJMP .+1 ;Ignore errors
GETPT2: AOBJN D,GETPT1 ;Try for next PTY number
ERRMES (<? No more PTYs available>) ;[34] Output error message
RET ;[34] None left, give +1 return
NORFSE: ERRMES (<? Insufficient system resources - No resident free space>)
RET ;[34] Return error
SUBTTL PTY Related Routines -- Initialize PTY Line
;Routine to initialize a PTY line.
;Returns to command level if no PTYs available
;Returns+1 with everything set up
PTINIT: CALL GETPTY ;Go open a PTY
JRST COMLVL ;[34] Return to get next command
SETZM PTYCNT(I) ;Initialize data base for this PTY
MOVEI A,(I) ;Get subjob index
IDIVI A,PTYLEN ;Turn it into subjob number
IMULI A,PTYBSZ ;Get start of output buffer area
ADDI A,PTYBUF ;Point to start of buffer for this PTY
HRLI A,(POINT 8,0) ;Set up byte pointers to buffer
MOVEM A,PTYIBP(I) ;Set initial buffer pointer
MOVEM A,PTYGBP(I) ;Set getter buffer pointer
MOVEM A,PTYPBP(I) ;Set putter buffer pointer
ADDI A,PTYBSZ-1 ;Now get byte pointer
HRLI A,(POINT 8,0,31) ; to end of buffer
MOVEM A,PTYEBP(I) ; and store it for end checking
HRRZ A,PTYJFN(I) ;Now put the PTY on a interrupt channel
MOVEI B,(I) ;Get subjob index
IDIVI B,PTYLEN ; convert that to get subjob number
IDIVI B,PTYNCH ;Get subjob number modulo channel number
ASH C,1 ;Divide by 2
HRLI B,PTYCHN(C) ; and get actual channel number for this PTY
TXO B,MO%WFI!MO%OIR ;Want to wake on hungry and output wait
HRRI B,.MOAPI ;Assign PTY interrupt channels
MTOPR ;Put PTY on software channel for interrupts
RET ;Return to caller
SUBTTL PTY Related Routines -- Kill a Subjob
;Here to murder an unsuspecting subjob, call with PTY index in I.
;Returns +1 always
KILJOB: SKIPN A,PTYTTD(I) ;Is there a job started here?
RET ;No, nothing to kill
HRLZS A ;Get TTY number
TLZ A,.TTDES ;Turn off TTY designator
HRR A,TTYJOB ;Get TTYJOB table number for GETAB
GETAB ;Get job number associated with TTY
JRST KILJB1 ;Failed, assume no job there
HLRES A ;Get the job number, sign extended
JUMPL A,KILJB1 ;If -1 or -2, then no job
LGOUT ;Log this job out
JRST KILJB2 ;Owie!
KILJB1: HRRZ A,PTYJFN(I) ;Then release JFN of PTY
CLOSF ;Job will become detached if logged in
JFCL ;Ignore error
SETZM PTYTAB(I) ;Mark that subjob was killed
HRLI A,PTYTAB(I) ;Clear up all information
HRRI A,PTYTAB+1(I) ; in the subjob database
BLT A,PTYTAB+PTYLEN-1(I) ; for this subjob
RET ;Murder complete
KILJB2: HRROI A,[ASCIZ/Could not kill subjob /] ;Here if LGOUT failed
CALL TTSOUT ;Tell user about failure
CALL TYPNAM ;Output name of that subjob
CALLRET CRLF ;Output CRLF and return
SUBTTL PTY Related Routines -- Check PTY Hunger
;[34] Here to see if subjob is hungry.
;Returns +1 if hungry
;Returns +2 if not hungry
HUNGRY: MOVE A,PTYJFN(I) ;Load PTY JFN
MOVX B,.MOPIH ;Get the check hunger function
MTOPR% ;See if PTY is hungry for characters
SKIPN B ;Is it hungry?
AOS (P) ;Skip return
RET ;Return
SUBTTL PTY Related Routines -- Send Character to PTY
;Routine to output a character to a PTY
;Call with A/ character, I/ subjob index
;Makes new PTY if needed
PTYOUT: PUSH P,A ;Save character for a moment
SKIPN PTYJFN(I) ;Is there a JFN for this PTY?
CALL PTINIT ;No, go get one started
CALL PTYPRM ;Does this line need priming?
JRST PTYOU0 ;Yes, do ti
JRST PTYOU1 ;Yes, waiting for ^C to take effect
JRST PTYOU3 ;No, send out character
;Here if ^C needs to be sent to this PTY to get it started
PTYOU0: MOVE A,0(P) ;Get character to be sent
CAIN A,.CHCNC ;Is it a control-C?
JRST PTYOU3 ;Yes, just send it directly
HRRZ A,PTYJFN(I) ;Get JFN
MOVEI B,.CHCNC ;Send a Control-C to prime line
BOUT ;Wham
ERJMP PTYOU5 ;Owie
;Here to wait for PTY to become active after ^C sent to it.
PTYOU1: MOVEI A,^D500 ;Drum our fingers for about a half second
DISMS ; for Control-C to take effect
PUSHJ P,PTYPRM ;Is the PTY primed yet?
JRST PTYOU0 ;No, go send character anyway
JRST PTYOU1 ;Wait some more
;Fall through to PTYOU3 if we are ready to go
;Here if line doesn't need a ^C to get it started, transmit the character.
PTYOU3: POP P,B ;All primed, get character again
PTYOU4: HRRZ A,PTYJFN(I) ;Get PTY JFN
BOUT ;Send out the character to that PTY
ERJMP PTYOU5 ;[34] Jump if lossage
;Character transmitted to PTY OK, perform housekeeping before returning
PTYOU8: CAIN B,"O"-100 ;Control-O?
CALL PTYFLU ;Yes, flush internal buffer of PTY output
CALL LOGINP ;Save input maybe
EXCH B,PTYLCH(I) ;Save last character
CAIE B,.CHCNC ;Control-C as last char?
RET ;No, then done
CAMN B,PTYLCH(I) ;Is this a Control-C also (two in a row?)
CALL PTYFLU ;Yes, flush internal buffer on two ^Cs
RET ;Return
;[34] Here if error sending character to the PTY.
PTYOU5: PUSH P,A ;Save the JFN
PUSH P,B ; and character to transmit
MOVX A,.FHSLF ;Get the last error code
GETER% ; for this fork
HRRZ B,B ;Get rid of process handle
CAIE B,IOX33 ;Buffer full?
JRST PTYOU7 ;Nope, print error
MOVE A,PTYTTD(I) ;Yes, get TTY descriptor
SOBE% ;Is there TTY output pending?
CALL PTYFIL ;Yes, read in one line
CALL IOWAIT ;Wait for a little bit
POP P,B ;Restore character to send
POP P,A ; and restore PTY JFN
JRST PTYOU4 ; and try again
;Here if not IOX33 error
PTYOU7: CALL GETLM ;[34] Get to left margin
CALL TYPERR ;Tell user about error
POP P,B ;Restore character
POP P,A ; and restore JFN
JRST PTYOU8 ;And continue character checks
;Local routine to see if PTY needs priming.
;Returns +1 if no job on PTY yet (needs priming)
;Returns +2 if job on PTY is not (yet) ready
;Returns +3 if already primed and ready to go
PTYPRM: HRLZ A,PTYTTD(I) ;Get TTY devce designator
HRR A,TTYJOB ; and table number
TLZ A,.TTDES ;Make TTY number from device designator
GETAB ;Get job number for this TTY
JRST CPOPJ1 ;No job on this PTY
JUMPGE A,CPOPJ2 ;Positive means job already logged in
TLC A,-1 ;See if -1 was returned
TLCE A,-1 ; which means job is not logged in
JRST CPOPJ1 ;-2 is in process of getting job, return +2
RET ;Needs priming, return +1
SUBTTL PTY Related Routines -- Read and Buffer Output From PTY
;Routine to fill a PTY buffer if any room. Loads characters into our buffer if
;they fit. Reads only one line at a time for a PTY to avoid runaways. Starts
;bell if user is pushed or this PTY is set refused.
PTYFIL: SKIPN PTYJFN(I) ;Is there a JFN for this PTY?
RET ;Nope
CALL PIOFF ;Turn off PI system for now
PTYFL0: MOVE A,PTYCNT(I) ;Get character count
CAIL A,PTYMXC ;Buffer full?
JRST PTYFL1 ;Yes, don't get any more
MOVE A,PTYTTD(I) ;Get device designator for this PTY
SOBE ;Any characters waiting?
SKIPA ;Yes, get them
JRST PTYFL1 ;No, all done
HRRZ A,PTYJFN(I) ;Get JFN again
BIN ;Read in character from the PTY
MOVE A,B ;Copy the character to A
PUSHJ P,PTYPUT ;Store character in buffer
JFCL ;SNH, we know that there is room and PI off
ANDI A,177 ;Zap the junk parity
CAIN A,.CHLFD ;End of a line?
JRST PTYFL1 ;Yes, stop here in case something else to DO
MOVE A,PTYSTS(I) ;Get current status of this PTY
TXNE A,PTDISF ;[34] Output being ignored?
JRST PTYFL0 ;Yes, don't start the bell
TXNE F,PUSHF ;Is user in lower EXEC?
CALL DINGGO ;Yes, start dinger
JRST PTYFL0 ;Loop for rest of characters
PTYFL1: CALL PION ;Turn interrupts back on
RET ; and return
SUBTTL PTY Related Routines -- Buffer Character From PTY
;Routine to store a character into a PTY buffer
;Call with A/ character
;Returns +1 if no room
;Returns +2 if character stored
PTYPUT: MOVE B,PTYCNT(I) ;GET COUNT OF CHARS IN BUFFER
CAIL B,PTYMXC ;IS BUFFER FULL
POPJ P, ;YES, DONT OVERFILL IT
SKIPN ADDPAR ;ALLOW PARITY?
ANDI A,177 ;NO
IDPB A,PTYPBP(I) ;STORE CHARACTER
MOVE B,PTYPBP(I) ;GET NEW POINTER
CAMN B,PTYEBP(I) ;IS IT TIME TO WRAP AROUND?
MOVE B,PTYIBP(I) ;YES, WRAP IT AROUND TO BEGINING
MOVEM B,PTYPBP(I) ;STORE UPDATED POINTER
AOS PTYCNT(I) ;INCREMENT COUNT
JRST CPOPJ1 ;GIVE SUCCESSFUL RETURN
SUBTTL PTY Related Routines -- Get Buffered Character
;Routine to get a character from a PTY buffer.
;Returns +1 no more characters to get
;Returns +2 if character there, character in A
PTYGET: SKIPG PTYCNT(I) ;Any characters there?
JRST PTYGT1 ;No, check for lossage
SOS PTYCNT(I) ;Count down count of characters
ILDB A,PTYGBP(I) ;Get the charcter
MOVE B,PTYGBP(I) ;Load the getter pointer
CAMN B,PTYEBP(I) ;Is it now the end of the buffer?
MOVE B,PTYIBP(I) ;Yes, wrap it around to beginning
MOVEM B,PTYGBP(I) ;Store (possibly) new pointer
PUSH P,A ;Save character we just got
SKIPG PTYCNT(I) ;Decrement count of characters in buffer
CALL PTYFIL ;If now zero, go try to fill it
POP P,A ;Get back character
JRST CPOPJ1 ; and give successful return
PTYGT1: MOVE B,PTYGBP(I) ;Is the getter pointer out of sync
CAMN B,PTYPBP(I) ; with the putter pointer?
RET ;No, return +1
PUSH P,A ;Possibly, save A for a little bit
PUSHJ P,PIOFF ;Touchy code
MOVE B,PTYPBP(I) ;Get output pointer
SKIPG PTYCNT(I) ;Out of sync really?
MOVEM B,PTYGBP(I) ;Yes, fix this problem
PUSHJ P,PION ;All done, restore interrupts
POP P,A ;Restore A
RET ; and return
SUBTTL PTY Related Routines -- Flush Output From PTY
;Routine to flush output from a PTY, I/ subjob index to flush
;Returns +1 always
PTYFLU: PUSH P,A ;Save an AC please
PUSHJ P,PIOFF ;Touchy code again
SETZM PTYCNT(I) ;Delete all character in buffer
MOVE A,PTYPBP(I) ;Make putter byte pointer
MOVEM A,PTYGBP(I) ; the same as getter byte pointer
SETZM PTYLCH(I) ;Clear last character also
PUSHJ P,PION ;OK for interrupts again
POP P,A ;Restore the AC
RET ; and return
SUBTTL PTY Related Routines -- PTY Interrupt Routines
;PTY interrupt level routines. Since there are a limited number of channels
;available, we assign more than one subjob per channel (number of subjobs
;modulo PTYNCH). Each possible PTY interrupting on this channel is then
;checked upon an interrupt. The following MACRO builds the interrupt tables
;used for this purpose.
DEFINE BLDCHN(A)<
PTYCH'A:
CALL ACSAVE ;;Save the ACs
MOVEI I,A*PTYLEN ;;Load index for first PTY assigned to channel
JRST PTYINT ;;Go process the interrupt
> ;End of DEFINE BLDCHN
ZZ==0
REPEAT PTYNCH,<BLDCHN(\ZZ) ;;Generate table of PTYNCH interrupt routines
ZZ==ZZ+1>
;Here on PTY interrupt, I/ subjob index, ACs already saved
PTYINT: SKIPE PTYJFN(I) ;Is there a JFN for this PTY?
CALL PTYFIL ;Yes, go see if it has characters ready
ADDI I,PTYNCH*PTYLEN ;Step to next PTY assigned to this channel
MOVE A,PTYHGH ;Get highest PTY
IMULI A,PTYLEN ;Calculate its index
CAMG I,A ;Have we reached the end yet?
JRST PTYINT ;No, try this PTY
PTYIN0: CALL ACLOAD ;Restore the acs
TXZE F,PTWATF ;[34] Is lower level waiting?
POP P,RETSAV ;Yes, wake it up
DEBRK% ;Dismiss the interrupt
;Routine to wait for 1 second or PTY input/output interrupt.
;Returns +1 always.
IOWAIT: TXO F,PTWATF ;[34] Set flag for PTY interrupt routine
MOVEI A,^D1000 ;[34] One thousand milliseconds is one second
DISMS% ;[34] Sleep for a little while
TXZ F,PTWATF ;[34] Clear wait flag
RET ;[34] and then return
SUBTTL Error Handling Routines -- Panic Channel Interrupt
;Here on a panic interrupt
PANIC: CALL ASCTER ;Get ASCII terminal set up (in case binary)
BUG(CHK,<panic level interrupt occurred>) ;Report the owie
HRROI A,[ASCIZ/ at PC /] ;[34] We want to label
CALL TTSOUT ;[34] the next number
HRRZ B,RETSAV ;[34] Get the interrupt PC
CALL TTNOCT ;[34] Output that in octal please
HRROI A,[ASCIZ/: /] ;[34] We want to seperate the
CALL TTSOUT ;[34] PC from the error string
CALL TYPERR ;[34] Publish error next
MOVEI A,.PRIOU
DOBE ;WAIT FOR IT TO GO OUT
JRST TRAP1 ; AND GO TO COMMAND LEVEL
SUBTTL Error Handling Routines -- Error Macro Handling Routines
;[34] Come to DOBUGH on BUG(HLT,text) macro, with CX/ address of ASCIZ text
;Halts the program, user cannot continue program.
DOBUGH: CALL DOBUG ;Output message
HALTF% ;Stop
JRST .-1 ;Can't continue
;[34] Come to DOBUG on BUG(CHK,text) macro, with CX/ address of ASCIZ text
;Publish the message and return.
DOBUG: PUSH P,A ;Preserve A
HRRO A,CX ;Get -1,,address
CALL TTSOUT ;Output that string
POP P,A ;Restore A
RET
;[34] Here on JERMES (text) macro, CX/ address of error message.
DOJERM: CALL DOERRM ;Publish error message
CALLRET TYPERR ;Type last JSYS error and a CRLF then return
;[34] Here on ERRMES (text) macro, with CX/ address of error message.
DOERRM: PUSH P,CX ;Save address of string
MOVEI A,.PRIIN ;Clear typeahead
CFIBF% ;From terminal input buffer
CALL GETLM ;[34] Get to the left margin please
POP P,A ;Get pointer to message
TLO A,-1 ;Make it into a string pointer
CALLRET TTSOUT ;Output it and return
;[34] Here on WRNMES (message) or TMSG macro, with CX/ address of ASCIZ.
DOWRNM: HRRO A,CX ;Point to error message
CALLRET TTSOUT ;Output and return
SUBTTL Error Handling Routines -- JSYS Error Handler
;Here to output last JSYS error to controlling terminal and possibly log file.
TYPERR: CALL RTNERR ;[34] Return the last error string
CALL TTSOUT ;[34] Type out string on terminal and log file
JRST CRLF ;[34] End line and return
;Here to get last TOPS-20 error code Asciized
;Returns +1 always, A/ pointer to error string
RTNERR: HRROI A,ERRSTR ;PUT MESSAGE INTO A STRING
MOVX B,<.FHSLF,,-1> ;[34] This fork's last error
MOVX C,<-MAXSTC,,0> ;[34] -maxsize,,0
ERSTR% ;Convert ERror to STRing
JRST [ HRROI A,[ASCIZ/Unknown error code/] ;[34] Unknown error
RET] ;[34] Return that
SKIPA A,[XWD -1,[ASCIZ/String size out of bounds/]] ;[34] Owie!
HRROI A,ERRSTR ;[34] It worked, point to error string
RET ;[34] Return
SUBTTL Bell Ringing Routines -- Start/Stop Bell
;Here to start bell ringing. TIMER interrupts are used to output a bell
;indicating that refuseds subjob output is ready to be displayed.
DINGGO: TXNN F,NOBELF ;[34] Is bell disabled
TXNE F,DINGF ;[34] or already on?
RET ;Yes, do nothing
MOVEI A,.FHSLF ;Get our process handle
MOVX B,1B<.DNGCH> ;Get ding channel
AIC ;Activate the channel
IIC ;Initiate the interrupt routine
TXO F,DINGF ;[34] And mark that the bell is now ringing
RET ; then return
;Here to stop the bell from ringing any more.
STDING: MOVEI A,.FHSLF ;Get our process handle
MOVX B,1B<.DNGCH> ;Get the ding channel number
DIC ;Deactivate the interrupt channel
TXZ F,DINGF ;[34] Mark that it is stopped for our reference
RET ; and return to caller
SUBTTL Bell Ringing Routines -- Bell Timer Interrupt
;Here to handle bell interrupt.
DING: CALL DING0 ;Do the work to ring that bell
DEBRK ; and return from interrupt
DING0: SAVEAC <A,B,C,I> ;Save these acs
MOVEI I,0 ;Start with subjob number 0
MOVE A,PTYHGH ;Look at this many subjobs
DINGLP: SKIPE PTYCNT(I) ;Any characters waiting?
JRST DINGER ;Yes, ring it
ADDI I,PTYLEN ;Step to next line
SOJGE A,DINGLP ;Loop for all jobs
JRST DINGWT ;Wait for 10 seconds
DINGER: MOVEI A,.CHBEL ;Output a bell
PBOUT ; to the terminal
DINGWT: MOVE A,[XWD .FHSLF,.TIMEL] ;Elapsed time for our fork
MOVEI B,^D10000 ;Ten seconds till next interrupt
MOVEI C,.DNGCH ;Generate it on the ding channel
TIMER ;Request the timer interrupt
JFCL ;Ignore any error
RET ;Return to caller
SUBTTL Subroutines -- Display Subjob Name and/or Number
;Here to display subjob name or number, call with I/ subjob index
;Returns +1 always
TYPNAM: SKIPN PTYNAM(I) ;[34] Is there a name for this subjob?
JRST TYPNUM ;[34] No, just use number
HRROI A,PTYNAM(I) ;Yes, point to the name
CALL TTSOUT ;Send it to terminal
MOVEI A,"(" ;Load a paren
CALL TTBOUT ; and type it out
CALL TYPNUM ;Type out the subjob number
MOVEI A,")" ;Load a thesis
CALLRET TTBOUT ;Output it and return
;Enter at TYPNUM type out subjob number from index in I.
;[34] Enter at TTNOUT to type out decimal number from B.
;[34] Enter at TTNOCT to type out decimal number from B.
;Returns +1 always
TYPNUM: MOVEI B,(I) ;Type subjob number from index
IDIVI B,PTYLEN ;Get subjob number from index and fall thru
TTNOUT: SKIPA C,[DEC 10] ;Decimal radix
TTNOCT: MOVEI C,10 ;Octal radix
HRROI A,STRING ;Put number in STRING
NOUT ;Type out number
JFCL ;HFO
HRROI A,STRING ;Now type out the STRING
JRST TTSOUT ; and return
SUBTTL Subroutines -- Manipulate PI System
;Here to turn off PI system.
PIOFF: MOVEI A,.FHSLF ;This fork please
DIR ;Disable interrupts
AOS PICNT ;Count number of times done
RET ; and return
;Here to turn on PI system.
PION: SOSL PICNT ;Nested PIOFFs?
RET ;Yes, don't enable PI system this time
SETOM PICNT ;No, ok to turn back on
MOVEI A,.FHSLF ;This fork again
EIR ;Turn on PI system
RET ; and return
SUBTTL Subroutines -- Check if any Subjobs Logged In
;Routine to check if any jobs are logged in
;Returns +1 if no jobs logged in
;Returns +2 if jobs logged in
CHKLOG: MOVE E,PTYHGH ;Get highest PTY job
SETZ I, ;Start at subjob index 0
CHKLG1: SKIPN PTYJFN(I) ;Is there a job on this line?
JRST CHKLG2 ;No, check other subjobs
HRRZ A,PTYTTD(I) ;Get TTY designator for this subjob
MOVX B,<-1,,D> ;We need one item stored in ac D
MOVEI C,.JIUNO ;Get logged-in directory numbern
SETZ D, ;Start with zeroth offset
GETJI ;GET Job Information
SETZ D, ;Assume 0 if failure
JUMPN D,CPOPJ1 ;Job is logged in, return +2
CHKLG2: ADDI I,PTYLEN ;Go to next subjob index
SOJGE E,CHKLG1 ;Loop back for all subjobs
RET ;No active jobs, return +1
SUBTTL Subroutines -- Save and Restore ACs
;Here to save critical ACs before starting PTY output
ACSAVE: EXCH A,0(P) ;Save A and get return PC in A
PUSH P,B ;Save B
PUSH P,C ;Save C
PUSH P,D ;Save D
PUSH P,I ;Save I
JRST (A) ;Return to caller
;Here to restore ACs saved by ACSAVE
ACLOAD: POP P,A ;Load ac A with return address
POP P,I ;Restore I
POP P,D ;Restore D
POP P,C ;Restore C
POP P,B ;Restore B
EXCH A,0(P) ;Restore A and put return on stack
POPJ P, ;Return to caller
SUBTTL Tables -- Interrupt System
LEVTAB: RETSAV ;Where to save level 1 interrupt PC
0 ;No level 2 interrupts
0 ;No level 3 interrupts
CHNTAB: 0 ;0 not used
.DNGCH==1 ;DING CHANNEL FROM TIMER INTERRUPT
1,,DING ;1 ding channel
1,,COMCC ;2 control-C channel
CTLCHN==2 ;CONTROL-C CHANNEL
1,,TYPIN ;3 terminal input interrupt channel
TINCHN==3
1,,PTYOPC ;4 PTY outout check channel
PTYOCN==4 ;PTY OUTPUT CHECK CHANNEL
1,,TRAP ;5 Trap character channel
TRPCHN==5
0 ;6 not used
0 ;7 not used
0 ;8 not used
XWD 1,PANIC ;9 Panic for pdl overflow
0 ;10 not used
XWD 1,PANIC ;11 Panic for data error
0 ;12 not used
0 ;13 not used
0 ;14 not used
XWD 1,PANIC ;15 Panic for illegal instruction
XWD 1,PANIC ;16 Panic for illegal memory read
XWD 1,PANIC ;17 Panic for illegal memory write
XWD 1,PANIC ;18 Panic for illegal memory execute
0 ;19 not used
XWD 1,PANIC ;20 Panic for machine size exceeded
0 ;21 not used
0 ;22 not used
0 ;23 not used
DEFINE CHNBLD(A)<
XLIST
XWD 1,PTYCH'A
XWD 1,PTYCH'A
LIST>
ZZ==0
REPEAT PTYNCH,<CHNBLD(\ZZ) ;24-36 PTY interrupts
ZZ==ZZ+1>
ONCHNS: 1B<CTLCHN>+1B<TINCHN>+1B<TRPCHN>+1B<PTYOCN>+1B9+1B11+1B15+1B16+1B17+1B18+1B20+7777
SUBTTL Tables -- Command Parsing
;Command state block
CMDSBK: CM%XIF!COM0 ;[34] (.CMFLG) No "@" allowed, reparse at COM0
.PRIIN,,.PRIOU ;(.CMIOJ) Input and output JFNs
POINT 7,[ASCIZ "PTYCON> "] ;[32] (.CMRTY) Pointer to prompt string
POINT 7,CMDBUF ;[32] (.CMBFP) Pointer to start of buffer
POINT 7,CMDBUF ;[32] (.CMPTR) Pointer to next input
5*CBUFSZ-1 ;(.CMCNT) Count of space remaining after .CMPTR
0 ;(.CMINC) Number of unparsed chars after .CMPTR
-1,,ATMBUF ;(.CMABP) Atom buffer pointer
5*ABUFSZ-1 ;(.CMABC) Atom buffer size in characters
GTJBLK ;(.CMGJB) Address of long form GTJFN block
;Top level command function blocks, one of the following:
; command, subjob name, ALL, subjob number
CBLK: FLDBK. (.CMKEY,CM%HPP,CMDTBL,<a command,>,,[
BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,,<->)],SBLK)
SBLK: FLDBK. (.CMKEY,CM%HPP,NAMTBL,<a subjob name,>,,[
BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,,<->)],ABLK)
ABLK: FLDBK. (.CMKEY,CM%HPP!CM%SDH,ALLTBL,<ALL for all subjobs>,,[
BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,,<->)],NBLK)
NBLK: FLDDB. (.CMNUX,CM%HPP!CM%SDH,^D10,<a subjob number>)
;[34] Block to parse one line of text for subjob-text commands.
OLBLK: FLDDB. (.CMUQS,,<[EXP 1B10+1B12+1B13,0,0,0]>)
;[34] Blocks needed for DEFINE command, not literals since they are modified
DNUBLK: FLDBK. (.CMNUX,<CM%HPP+CM%SDH>,^D10,<subjob number>,0)
DNMBLK: FLDDB. (.CMCFM,CM%HPP!CM%SDH,,<Confirm to delete subjob name>,,[
FLDBK. (.CMFLD,CM%HPP,,<subjob name, up to 9 characters>,,[
BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,,<->)])])
;[34] Subjob parsing block, first one modified as needed for subjob parsing
SJNBLK: FLDBK. (.CMKEY,CM%HPP,NAMTBL,<subjob name,>,ALL,[
BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,,<->)],SJABLK)
SJABLK: FLDBK. (.CMKEY,CM%HPP!CM%SDH,ALLTBL,<ALL for all subjobs>,,[
BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,,<->)],[
FLDDB. (.CMNUX,<CM%HPP+CM%SDH>,^D10,<a subjob number>)])
SJRBLK: FLDBK. (.CMKEY,CM%HPP,NAMTBL,<subjob name,>,,[
BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,,<->)],[
FLDDB. (.CMNUX,<CM%HPP+CM%SDH>,^D10,<a subjob number>)])
;[34] Table for having a keyword of ALL.
ALLTBL: XWD 1,1 ;[34] Keyword table with just one entry
[ASCIZ/ALL/],,-1 ;[34] a keyword of ALL
;[34] Table of subjob names, initially blank.
NAMTBL: XWD 0,MAXPTY ;Size of table
BLOCK MAXPTY ;Table of subjob names
SUBTTL General Storage
;Places to store current program states
ALC CURENT,1 ;Index of current job, -1 if at command level
ALC LSTHDR,1 ;Index of last job a header was typed for
ALC LSTCON,1 ;Index of last job connected to
ALC PICNT,1 ;Number of PIOFFs done
ALC PTYHGH,1 ;Highest subjob in use now
;Configuration information gathered from monitor
ALC ADDPAR,1 ;Add parity bit for real terminal
ALC FIRPTY,1 ;TTY number of first PTY
ALC NUMPTY,1 ;Number of PTY lines available for PTYCON
ALC SYSPTY,1 ;Number of PTYs in system
ALC TTYJOB,1 ;Table number of TTYJOB for GETAB
ALC JOBPNM,1 ;GETAB table number of JOBNAM
ALC SNAMES,1 ;GETAB table number of SNAMES
ALC JOBRT,1 ;GETAB table number of JOBRT
ALC NAMES,2 ;PTYCON's program names to restore
;Command parsing storage
ALC JFNIP,1 ;JFN acquired in parse that we need to release
ALC CMDBUF,CBUFSZ ;[32] Command buffer
ALC ATMBUF,ABUFSZ ;[32] Atom buffer
ALC GTJBLK,.GJATR+1 ;[32] GTJFN block
ALC ARGCNT,1 ;Number of arguments in ARGS
ALC ARGS,MAXPTY+1 ;List of subjobs argument block
;Miscellaneous storage
ALC JITAB,JITBLN ;GETJI info for jobs during "WHAT"
ALC ERRSTR,STRNGL ;Block for ERSTR strings
ALC STRING,STRNGL ;Temp string, used all over in parsing
ALC LNEPTR,1 ;Byte pointer to start of text in LNESTR
ALC LNESTR,STRNGL ;String for single line command
ALC RETSAV,1 ;Interrupt PC
ALC EXECFK,1 ;[34] Saved EXEC fork handle
ALC PDL,PDLEN ;The stack
;Terminal related storage
ALC SAVMOD,1 ;Original TTY mode
ALC SAVTIW,1 ;Original terminal interrupt word
ALC TIMASK,1 ;Terminal interrupt mask when at command level
ALC ESCMSK,1 ;Terminal interrupt mask when at subjob level
ALC TRPCHR,1 ;Trap character to get back to command level
ALC BINTTY,1 ;JFN of binary channel for TTY
ALC TERJFN,1 ;Holds TTY JFN currently in use
ALC LSTCHR,1 ;Last character typed on terminal
ALC LMFLAG,1 ;0 if at left margin, -1 if RFPOS needed
;Command file storage
ALC CHRCNT,1 ;Count of characters in subjob line so far
ALC CMDCNT,1 ;Count of characters in command line so far
ALC RDJFN,1 ;JFN of auto command file
;Saved input file storage
ALC SVIJFN,1 ;JFN of save input file
ALC NXSVIC,1 ;[34] Next time for saved input checkpoint
ALC SVIBUF,200 ;[34] Saved input filename kept here
;Log file storage
ALC LOGJFN,1 ;JFN of logging file
ALC NXLOGC,1 ;Uptime when next log file update needed
ALC LOGBUF,200 ;[32] Log filename kept here
;Subjob storage area, one per subjob active, pointed to by subjob index. This
;storage is grown up from here, must be last space assigned , do not seperate
;following.
ALC PTYTAB,0 ;PTY storage area, must be last space assigned
PTYTTD=0+PTYTAB ;TTY designator
PTYJFN=1+PTYTAB ;JFN of PTY
PTYCNT=2+PTYTAB ;Count of characters in buffer
PTYIBP=3+PTYTAB ;Initial buffer pointer
PTYEBP=4+PTYTAB ;End of buffer pointer
PTYPBP=5+PTYTAB ;Putter pointer
PTYGBP=6+PTYTAB ;Getter pointer
PTYNAM=7+PTYTAB ;[34] Subjob name (9 ASCII Characters)
PTYSTS=11+PTYTAB ;Status of subjob
PTYLCH=12+PTYTAB ;Last char sent to this subjob
PTYLEN==13 ;Length of per subjob area
SUBTTL End of PTYCON
;Literals dumped here
LIT..: XLIST
LIT
LIST
;End of program
END <EVLEN,,ENTVEC>