Google
 

Trailing-Edge - PDP-10 Archives - BB-KL11L-BM_1990 - 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>