Google
 

Trailing-Edge - PDP-10 Archives - cuspjul86upd_bb-jf24a-bb - 10,7/galaxy/batcon/batcon.mac
There are 39 other files named batcon.mac in the archive. Click here to see a list.
TITLE	BATCON	- GALAXY-10 Batch controller
SUBTTL	C.D.O'Toole, D.P.Mastrovito /CDO/DPM 12-SEP-85


;
;
;	      COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
;     1974,1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1986.
;			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  WHICH  IS  NOT SUPPLIED BY
;     DIGITAL.


	SEARCH	BATMAC			;BATCON SYMBOLS
	SEARCH	GLXMAC			;GALAXY SYMBOLS
	SEARCH	QSRMAC			;QUASAR SYMBOLS
	SEARCH	ORNMAC			;ORION SYMBOLS

	PROLOG	(BATCON)		;SET UP

	%%.BAT==:%%.BAT			;FORCE VERSION INTO SYMBOL TABLE


TOPS10	<IF1,<PRINTX [Assembling GALAXY-10 BATCON]>>
TOPS20	<IF1,<PRINTX [Assembling GALAXY-20 BATCON]>>

	GLOB	<LOGERR>

	LOC	<.JBVER==:137>
	EXP	%%.BAT			;BATCON VERSION NUMBER

	RELOC	0

COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1971,1986. ALL RIGHTS RESERVED.
\;END COPYRIGHT MACRO


SUBTTL	Table of contents


;               TABLE OF CONTENTS FOR BATCON
;
;
;                        SECTION                                   PAGE
;    1. Table of contents.........................................   2
;    2. BATCON Data Base..........................................   3
;    3. Popular ITEXT blocks......................................   4
;    4. Program initialization and reentry........................   5
;    5. Job scheduler
;         5.1   Toplevel..........................................   6
;         5.2   Fast batch shutdown...............................   8
;         5.3   Clock queue control...............................   9
;         5.4   Checkpoint........................................  12
;         5.5   Message processing................................  14
;    6. IPCF/Operator/QUASAR interface
;         6.1   IPCF interrupts...................................  15
;         6.2   Hello and goodbye.................................  16
;         6.3   IPCF message processing...........................  17
;         6.4   Message tables....................................  18
;         6.5   Validate messages.................................  20
;         6.6   Initialize stream block...........................  21
;         6.7   Message block processing..........................  22
;         6.8   QUASAR communication..............................  23
;         6.9   Ask for operator response.........................  25
;         6.10  Unknown message...................................  26
;         6.11  QUASAR message #5 (NEXTJOB).......................  27
;         6.12  QUASAR message #6 (ABORT).........................  29
;         6.13  QUASAR message #22 (SETUP)........................  30
;         6.14  QUASAR message #60 (ALLOCATION)...................  33
;         6.15  ORION message #200004 (PAUSE).....................  34
;         6.16  ORION message #200005 (CONTINUE)..................  35
;         6.17  ORION message #200012 (RESPONSE)..................  36
;         6.18  ORION message #200025 (REQUEUE)...................  37
;         6.19  ORION message #200026 (CANCEL)....................  38
;         6.20  ORION message #200035 (SEND)......................  40
;         6.21  ORION message #200036 (EXAMINE)...................  41
;         6.22  ACK message #700000...............................  42
;    7. STPPRC - Batch step processor.............................  44
;    8. JOBPRC - Process a Batch stream...........................  45
;    9. BATCON initialization
;         9.1   System independant code...........................  46
;         9.2   TOPS-10 code......................................  47
;         9.3   TOPS-20 code......................................  48
;   10. Batch generated commands
;        10.1   Buffer management.................................  49
;        10.2   TOPS-10 Login.....................................  51
;        10.3   TOPS-20 Login.....................................  54
;        10.4   Kill a job........................................  56
;        10.5   CLOSE/DUMP........................................  58
;   11. Batch WTO/WTOR
;        11.1   Initialization and character storage..............  59
;        11.2   IPCF page setup...................................  60
;        11.3   Write To OPR (WTO)................................  61
;        11.4   Write To OPR with a Response (WTOR)...............  62
;        11.5   Get operator response to a WTOR...................  63
;   12. Response buffer support...................................  64
;   13. Batch error handling
;        13.1   Error, operator, dialogue, or quote checking......  65
;        13.2   LOGIN error analysis..............................  66
;   14. MDA interface.............................................  67
;   15. MODIFY interface..........................................  68
;   16. End of job processing.....................................  69
;   17. JOBINI - Initialize job processing........................  70
;   18. TIMERR - Time limit exceeded..............................  71
;   19. Stream termination
;        19.1   Dismiss job.......................................  73
;        19.2   Build release message.............................  74
;        19.3   Data base cleanup.................................  75
;   20. IOWAIT - Wait for I/O completion..........................  76
;   21. Random Little Routines....................................  77
;   22. DELSPL - Delete spooled input files.......................  78
;   23. Get job status............................................  79
;   24. LUUO handler..............................................  80
;   25. PTY interrupt handler.....................................  81
;   26. ERRTAB  EXPAND ERROR TABLE VALUES.........................  82
;   27. Literals..................................................  83
;   28. End.......................................................  84
SUBTTL	BATCON Data Base


; Global data
;
LOWDAT:!				;BEGINING OF BLOCK TO CLEAR ON START UP

G$PDL:: BLOCK	TPSIZE			;TOP LEVEL PUSH DOWN LIST
G$IB::	 BLOCK	IB.SZ			;GLXLIB INITIALIZATION BLOCK
G$PIB::  BLOCK	PB.MNS			;GLXLIB PID BLOCK
G$SAB::	 BLOCK	SAB.SZ			;GLXLIB IPCF SEND ARGUMENT BLOCK
G$MDA::	 BLOCK	1			;MDA FLAG
G$UDT::	 BLOCK	1			;DATE/TIME OF LAST SCHEDULER PASS
G$CPU::	 BLOCK	1			;CPU TYPE CODE
G$MADR:: BLOCK	1			;MESSAGE ADDRESS
G$MIDX:: BLOCK	1			;INDEX INTO MESSAGE TABLES
G$MBLK:: BLOCK	1			;MESSAGE BLOCK POINTER
G$MARG:: BLOCK	1			;MESSAGE ARGUMENT COUNT
G$CORE:: BLOCK	1			;FLAG WORD FOR CORE CHECKING
G$NODE:: BLOCK	1			;BATCON'S NODE
G$SPLD:: BLOCK	1			;SPOOLED PPN OR DIRECTORY NUMBER
G$PTYF:: BLOCK	1			;FIRST PTY IN THE SYSTEM
G$PTYN:: BLOCK	1			;NUMBER OF PTYS IN THE SYSTEM
G$TIME:: BLOCK	2			;ASCIZ TIME FOR TIME STAMPS
G$STRM:: BLOCK	JOBMAX			;STREAM INDEX BLOCK
G$BASE:: BLOCK	JOBMAX			;STREAM DATA BASE POINTERS
G$FAIR:: BLOCK	1			;FAIRNESS COUNT
G$FFLG:: BLOCK	1			;FAIRNESS COUNT EXPIRED FLAG
G$KILL:: BLOCK	1			;KILL ALL JOBS FLAG
G$PSCN:: BLOCK	1			;PRESCAN FLAG
G$HACT:: BLOCK	1			;HIGHEST STREAM NUMBER ACTIVE
G$SACT:: BLOCK	1			;NUMBER OF ACTIVE STREAMS
G$TMTX:: BLOCK	2			;ASCIZ TIME TEXT BUFFER
G$TPTR:: BLOCK	1			;TEMPORARY BYTE POINTER
G$TCTR:: BLOCK	1			;TEMPORARY BYTE COUNT
G$KSYS:: BLOCK	1			;NON-ZERO IF KSYS IN PROGRESS


; Local data
;
WTOCNT:	BLOCK	1			;WTO BYTE COUNTER
WTOPTR:	BLOCK	1			;WTO BYTE POINTER
	MAX <RSU.SZ!REL.BL!STU.SZ!REQ.SZ!CHE.SZ>
MSGADR:	BLOCK	MAXSIZ			;MESSAGE DATA AREA
SLPTIM:	BLOCK	1			;TIME TO SLEEP
CLKQUE:	BLOCK	1			;CLOCK REQUEST QUEUE ID
CLKEID:	BLOCK	1			;CLOCK QUEUE ENTRY ID COUNTER

TOPS10	<				;TOPS-10 ONLY
VECTOR:!				;BEGINING OF INTERRUPT VECTOR BLOCKS
VECIPC:	BLOCK	4			;IPCF INTERRUPT BLOCK
ENDVEC==.-1				;END OF INTERRUPT VECTORS
OPRPPN:	BLOCK	1			;OPERATOR PPN

KSYZBG:!				;START OF KSYS DATA TO ZERO
KSYCNT:	BLOCK	1			;COUNT OF JOBS TO KILL
KSYSSC:	BLOCK	1			;COUNT OF KSYS STREAMS SETUP
KSYUSE:	BLOCK	1			;COUNT OF KSYS STREAMS IN USE
KSYREQ:	BLOCK	1			;FAKE REQUEST-ID
KSYNAM:	BLOCK	1			;LAST LOG FILE NAME
KSYJLO:	BLOCK	1			;COUNT OF JOBS LOGGED OFF
KSYJLE:	BLOCK	1			;COUNT OF JOBS LOGGED OFF WITH ERRORS
KSYMAP:	BLOCK	<^D512/^D36>		;KSYS BIT MAP
KSYLEN==.-KSYMAP			;LENGTH OF BIT MAP
KSYZND:!				;END OF KSYS DATA TO ZERO
>					;END OF TOPS-10 CONDITIONAL

TOPS20	<				;TOPS-20 ONLY
LEVTAB:	BLOCK	3			;INTERRUPT LEVEL PCS
CHNTAB:	BLOCK	^D36			;INTERRUPT CHANNEL TABLE
INTRP1:	BLOCK	1			;INTERRUPT LEVEL 1 PC
INTRP2:	BLOCK	1			;INTERRUPT LEVEL 2 PC
INTRP3:	BLOCK	1			;INTERRUPT LEVEL 3 PC
JSTBLK:	BLOCK	.JIMAX			;GETJI JSYS JOB STATUS BLOCK
>					;END OF TOPS-20 CONDITIONAL

LASLOW:!				;END OF BLOCK TO CLEAR ON START UP
SUBTTL	Popular ITEXT blocks


; Output job information contained in .JQJBB(R)
;
JIBTXT:: ITEXT	(<^R/.JQJBB(R)/^M^J>)


; Output <number> for WTOR messages
;
NUMBER:: ITEXT	(<^7/[.CHLAB]/number^7/[.CHRAB]/>)
SUBTTL	Program initialization and reentry


BATCON:	JFCL				;NO CCL ENTRY
	RESET				;STOP I/O
	MOVE	P,[IOWD TPSIZE,G$PDL]	;SET UP THE PDL
	SETZM	LOWDAT			;CLEAR THE FIRST DATA WORD
	MOVE	S1,[LOWDAT,,LOWDAT+1]	;SET UP BLT
	BLT	S1,LASLOW-1		;CLEAR THE REST OF THE DATA SECTION

; Build the IB
;
	MOVE	S1,['BATCON']		;OUR NAME
	MOVEM	S1,G$IB+IB.PRG		;STORE IT
	MOVX	S1,IP.STP		;SEND STOPCODES TO ORION
	SKIPE	DEBUGW			;DEBUGGING?
	MOVX	S1,IB.NPF		;YES - NO STOPCODES TO ORION, NO PFH
	MOVEM	S1,G$IB+IB.FLG		;STORE IN FLAG WORD
	MOVEI	S1,G$PIB		;POINT TO PID BLOCK
	MOVEM	S1,G$IB+IB.PIB		;STORE IT
TOPS10	<MOVEI	S1,VECTOR>		;TOPS-10 PSI INTERRUPT VECTOR ADDRESS
TOPS20	<MOVE	S1,[LEVTAB,,CHNTAB]>	;TOPS-20 PSI INTERRUPT TABLES
	MOVEM	S1,G$IB+IB.INT		;STORE IT

; Build the PIB
;
	MOVX	S1,INSVL.(PB.MNS,PB.LEN) ;GET BLOCK LENGTH
	MOVEM	S1,G$PIB+PB.HDR		;STORE IT
	MOVX	S1,IP.PSI		;ENABLE FOR IPCF PSI
	MOVEM	S1,G$PIB+PB.FLG		;SET FLAGS
	MOVX	S1,<INSVL.(SNDMAX,IP.SQT)!INSVL.(RCVMAX,IP.RQT)> ;IPCF QUOTAS
	MOVEM	S1,G$PIB+PB.SYS		;STORE THEM
TOPS10	<MOVX	S1,INSVL.(VECIPC-VECTOR,IP.CHN)> ;TOPS-10 IPCF PSI VECTOR
TOPS20	<MOVX	S1,INSVL.(IPCCHN,IP.CHN)> ;TOPS-20 IPCF INTERRUPT CHANNEL
	MOVEM	S1,G$PIB+PB.INT		;STORE IT

	MOVEI	S1,IB.SZ		;GET LENGTH OF BLOCK
	MOVEI	S2,G$IB			;GET ADDRESS OF BLOCK
	PUSHJ	P,I%INIT##		;INITIALIZE GLXLIB
	PUSHJ	P,B$INIT		;INITIALIZE BATCON
	PUSHJ	P,U$INIT##		;INITIALIZE CUSTOMER CODE
	JRST	TOPLVL			;ENTER JOB SCHEDULER


REENTER:SETOM	G$KILL			;SHUTDOWN BATCH SYSTEM
TOPS10	<JRSTF	@.JBOPC##>		;RETURN
TOPS20	<JRST	TOPLVL>			;HOPE WE WERE STOPPED IN A SAFE PLACE
SUBTTL	Job scheduler -- Toplevel


TOPLVL:	PUSHJ	P,KILCHK		;SEE IF WE MUST KILL ALL JOBS
	PUSHJ	P,U$SCHD##		;PROCESS CUSTOMER SCHEDULER STUFF
	PUSHJ	P,IPCF			;PROCESS IPCF MESSAGES

TOPL.1:	SETZM	G$FFLG			;CLEAR FAIRNESS EXPIRED FLAG
	SKIPLE	KSYCNT			;KSYS IN PROGRESS?
	PUSHJ	P,KSYSCD		;YES--SCHEDULE SOME JOBS
	MOVX	S,.INFIN		;A LARGE NUMBER INCASE NONE ACTIVE
	SKIPN	G$SACT			;ANY STREAMS ACTIVE?
	JRST	STEXIT			;NO - WAIT A WHILE
	PUSHJ	P,CLKCHK		;COUNTDOWN THE CLOCK REQUEST QUEUE
	SETZ	S,			;START WITH STREAM 0

TOPL.2:	SKIPL	R,G$BASE(S)		;GET DATA BASE ADDRESS AND STREAM FLAGS
	JRST	STEXIT			;STREAM NOT ACTIVE
	MOVE	F,.JREGS+F(R)		;LOAD STREAM FLAGS
	PUSHJ	P,JOBCHK		;CHECK FOR JOB'S EXISTANCE
	PUSHJ	P,CHKPNT		;DO CHECKPOINT IF NEEDED
	PUSHJ	P,PROMES		;PROCESS ANY OPERATION MESSAGES
	MOVEM	F,.JREGS+F(R)		;UPDATE FLAG WORD
	MOVEM	R,G$BASE(S)		;FLAGS HERE TOO
	TXZE	R,RL.MSP		;MESSAGE TO PROCESS?
	JRST	TOPL.3			;YES - THEN PROCESS IT NOW
	TXNE	R,RL.STP!RL.OPR!RL.NSC!RL.ACK ;STOPPED, OPR/ACK WAIT, NO SCHED?
	JRST	STEXIT			;YES TO EITHER - IGNORE STREAM
	MOVEM	R,G$BASE(S)		;UPDATE RELOCATION

TOPL.3:	HRLZI	0,.JREGS+1(R)		;SET UP BLT
	HRRI	0,1			;START WITH AC 1
	BLT	0,14			;LOAD ACS 1 - 14
	MOVE	0,.JREGS(R)		;LOAD AC 0
	MOVE	17,.JREGS+17(R)		;RELOAD AC 17
	POPJ	P,			;RETURN TO INTERRUPTED PROCESS
; Return from process (switch to BATCON's context).
;
QTS::	MOVEM	R,G$BASE(S)		;STORE STREAM RELOCATION
	MOVEM	0,.JREGS(R)		;SAVE AC 0
	HRLZI	0,1			;START WITH AC 1
	HRRI	0,.JREGS+1(R)		;SET UP BLT
	BLT	0,.JREGS+17(R)		;SAVE THE ACS
	MOVE	P,[IOWD	TPSIZE,G$PDL]	;RESET BATCON'S PDL


; Here to exit from the stream
; *** Note ***
; STEXIT must be called by JRST STEXIT after CLRSTR is called since the
; stream stack (and data base) has been destroyed.
;
STEXIT:	CAMGE	S,G$HACT		;CHECKED ALL STREAMS YET?
	AOJA	S,TOPL.2		;NO - TRY THE NEXT
	AOSG	G$PSCN			;DONE WITH A PRESCAN?
	JRST	TOPLVL			;YES - THEN NO TIME TO REST
	SETZM	G$PSCN			;INSURE WE DON'T ATTEMPT A PRESCAN
	SKIPG	G$FFLG			;FAIRNESS COUNT EXPIRE DURING JOB SCAN?
	PUSHJ	P,TSLEEP		;ZZZZZZ
	JRST	TOPLVL			;BACK TO TOP LEVEL
SUBTTL	Job scheduler -- Fast batch shutdown


; Set up to kill all jobs if necessary (G$KILL non-zero).
; This routine will set the fast KJOB bit (RL.FKJ) and cause BATCON to
; kill the stream on the next pass. No attempt is made to send release
; messages to QUASAR, nor is any attempt made to recover from batch errors
; such as a job not in monitor mode or not logging out.
;
KILCHK:	SKIPN	G$KILL			;WANT TO KILL ALL JOBS?
	POPJ	P,			;NO - JUST RETURN
	MOVEI	S,0			;START WITH STREAM 0

KILC.1:	SKIPGE	R,G$BASE(S)		;GET DATA BASE ADDRESS AND STREAM FLAGS
	TXOE	R,RL.FKJ		;NEED TO DO ANYTHING?
	JRST	KILC.2			;NO - ON TO THE NEXT ONE
	HRLI	T1,-.JPSIZ		;RESET THE STREAM PDL
	HRRI	T1,.JPLST-1(R)		;...
	PUSH	T1,[B$CLOS]		;POINT TO THE CLOSE JOB ROUTINE
	MOVEM	T1,.JREGS+P(R)		;SAVE AS STREAM AC 'P'
	TXZ	R,RL.OPR!RL.STP!RL.JIE!RL.DIA ;CLEAR BATCH STREAM FLAGS
	MOVX	T1,FL.NER		;GET NOERROR BIT
	IORM	T1,.JREGS+F(R)		;SET IT
	TXZ	R,RL.OPR!RL.STP!RL.JIE!RL.DIA!RL.NLG ;CLEAR LOTS OF FLAGS
	MOVEM	R,G$BASE(S)		;UPDATE STATUS

KILC.2:	CAMGE	S,G$HACT		;CHECKED ALL STREAMS YET?
	AOJA	S,KILC.1		;NO - LOOP
	SETZM	G$PSCN			;FORGET ANY PRESCAN REQUESTS
	POPJ	P,			;RETURN
SUBTTL	Job scheduler -- Clock queue control


; Create a clock request
; Call:	MOVE	T1,event code,,time in seconds
;	MOVE	T2,dispatch address
;	MOVE	T3,context
;	PUSHJ	P,B$CLKR
;	PUSHJ	P,B$CLKB	;AUTOMATICALLY SET UP T3 WITH  -1  (BATCON)
;	PUSHJ	P,B$CLKS	;AUTOMATICALLY SET UP T3 WITH C(S) (STREAM)
;
; On return, .JBCLK(R):= event code,,clock queue entry ID
;
B$CLKS::SKIPA	T3,S			;INDICATE STREAM CONTEXT
B$CLKB::HRLOI	T3,-1			;INDICATE BATCON'S CONTEXT
B$CLKR::MOVE	T4,T1			;GET EVENT CODE AND SLEEP TIME
	LOAD	S1,T1,CQ.TIM		;GET TIME IN SECONDS
	ASHC	S1,-21			;POSITION FRACTION
	DIV	S1,[^D24*^D60*^D60]	;DIVIDE BY SECONDS PER DAY
	CAILE	S2,<^D24*^D60*^D60>/2	;OVER HALF TO THE NEXT?
	AOS	S1			;YES - INCREMENT THE UDT
	MOVE	T1,S1			;SAVE UDT IN A SAFE PLACE
	$CALL	I%NOW			;GET CURRENT DATE/TIME
	ADD	T1,S1			;MAKE IT THE WAKEUP DATE/TIME
	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	$CALL	L%FIRST			;GET THE FIRST ENTRY
	JRST	CLKR.2			;JUMP THE FIRST TIME THROUGH

CLKR.1:	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	$CALL	L%NEXT			;GET THE NEXT ENTRY

CLKR.2:	JUMPT	CLKR.3			;ONWARD IF NO ERRORS
	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	MOVEI	S2,.CQLEN		;GET CLOCK QUEUE ENTRY LENGTH
	$CALL	L%CENT			;CREATE AN ENTRY AFTER THE CURRENT ONE
	JRST	CLKR.4			;CONTINUE

CLKR.3:	CAML	T1,.CQTIM(S2)		;LESS THAN THE CURRENT ENTRY?
	JRST	CLKR.1			;YES - TRY THE NEXT ENTRY
	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	MOVEI	S2,.CQLEN		;GET CLOCK QUEUE ENTRY LENGTH
	$CALL	L%CBFR			;CREATE AN ENTRY BEFORE THE CURRENT ONE

CLKR.4:	MOVEM	T1,.CQTIM(S2)		;SAVE UDT WAKEUP TIME
	MOVEM	T2,.CQADR(S2)		;SAVE DISPATCH ADDRESS
	MOVEM	T3,.CQCTX(S2)		;SAVE CONTEXT AFTER WAKEUP
	MOVEM	T4,.CQEVN(S2)		;SAVE EVENT CODE AND SLEEP TIME
	AOS	S1,CLKEID		;GET A NEW CLOCK QUEUE ENTRY ID
	HRRZM	S1,.CQEID(S2)		;SAVE IT
	JUMPL	T3,CLKR.5		;CHECK FOR BATCON'S CONTEXT
	MOVE	S1,T4			;GET THE EVENT CODE
	HRR	S1,.CQEID(S2)		;GET THE ENTRY ID
	SKIPGE	T4,G$BASE(T3)		;GET STREAM RELOCATION
	MOVEM	S1,.JBCLK(T4)		;SET UP CLOCK QUEUE DATA WORD
	TXNN	S1,CQ.NSC		;TURN OFF SCHEDULING FOR THIS STREAM?
	JRST	CLKR.5			;NO
	MOVX	S1,RL.NSC		;GET NO SCHEDULE FLAG
	IORM	S1,G$BASE(T3)		;UPDATE RELOCATION WORD
	CAMN	T3,S			;CURRENT STREAM?
	TXO	R,RL.NSC		;YES

CLKR.5:	PUSHJ	P,CLKTIM		;COMPUTE NEW SLEEP TIME
	POPJ	P,			;RETURN
; Kill a clock request
; Call:	MOVE	T1,clock queue entry ID
;	PUSHJ	P,B$CLKK
;
B$CLKK::HRRZS	T1			;MAKE SURE IT'S ONLY THE ENTRY ID
	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	$CALL	L%FIRST			;GET THE FIRST ENTRY
	JRST	CLKK.2			;JUMP THE FIRST TIME THROUGH

CLKK.1:	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	$CALL	L%NEXT			;GET THE NEXT ENTRY

CLKK.2:	JUMPF	.POPJ			;RETURN OF END OF LINKED LIST
	CAME	T1,.CQEID(S2)		;FOUND THE ENTRY?
	JRST	CLKK.1			;NO - TRY ANOTHER ONE

CLKDEL:	SKIPGE	S1,.CQCTX(S2)		;STREAM CONTEXT?
	JRST	CLKK.3			;NO
	SKIPGE	S2,G$BASE(S1)		;GET STREAM RELOCATION
	SETZM	.JBCLK(S2)		;CLEAR CLOCK QUEUE DATA WORD
	TXZ	S2,RL.NSC		;CLEAR NO SCHEDULE FLAG
	MOVEM	S2,G$BASE(S1)		;UPDATE RELOCATION WORD

CLKK.3:	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	$CALL	L%DENT			;DELETE THE ENTRY
	POPJ	P,			;RETURN
CLKCHK:	SETZM	SLPTIM			;CLEAR SLEEP TIME
	$CALL	I%NOW			;GET CURRENT UDT
	MOVEM	S1,G$UDT		;SAVE IT
	$TEXT	(<-1,,G$TIME>,<^C/G$UDT/^0>) ;CREATE ASCIZ TIME STAMP
	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	$CALL	L%FIRST			;GET THE FIRST ENTRY
	JRST	CLKC.2			;ONWARD

CLKC.1:	MOVE	S1,CLKQUE		;GET THE CLOCK QUEUE ID
	$CALL	L%NEXT			;GET THE NEXT ENTRY

CLKC.2:	JUMPF	.POPJ			;END OF LINKED LIST
	MOVE	S1,.CQTIM(S2)		;GET UDT FOR THIS ENTRY
	CAMG	S1,G$UDT		;TIME TO PROCESS THIS REQUEST?
	HRRZS	.CQEVN(S2)		;YES - CLEAR PENDING EVENT CODE
	LOAD	S1,.CQEVN(S2),CQ.EVN	;GET THE PENDING EVENT CODE
	CAIL	S1,.CQMIN		;RANGE CHECK
	CAILE	S1,.CQMAX		; THE EVENT TYPE
	JRST	CLKC.6			;ILLEGAL - DON'T DO EVENT CHECKING
	SKIPGE	S,.CQCTX(S2)		;NEED TO SETUP STREAM STATUS?
	JRST	CLKC.3			;NO
	SKIPL	R,G$BASE(S)		;SET UP STREAM RELOCATION
	JRST	CLKC.5			;NOT ACTIVE
	PUSHJ	P,P$STAT##		;UPDATE JOB STATUS
	MOVEM	J,.JREGS+J(R)		;SAVE FOR LATER

CLKC.3:	PUSHJ	P,@CLKTAB(S1)		;CHECK IT OUT
	  JRST	CLKC.6			;EVENT NOT SATISFIED YET
	JUMPL	S,CLKC.4		;CHECK FOR BATCON'S CONTEXT
	MOVE	S1,.JREGS+P(R)		;GET STREAM'S STACK
	SKIPE	.CQADR(S2)		;NEED TO PUSH A DISPATCH ADDRESS?
	PUSH	S1,.CQADR(S2)		;YES - DO IT
	MOVEM	S1,.JREGS+P(R)		;UPDATE STREAM'S STACK POINTER
	JRST	CLKC.5			;ONWARD

CLKC.4:	PUSH	P,S2			;SAVE FROM DESTRUCTION
	PUSHJ	P,@.CQADR(S2)		;DISPATCH IN BATCON'S CONTEXT
	POP	P,S2			;RESTORE CLOCK QUEUE ENTRY ADDRESS

CLKC.5:	PUSHJ	P,CLKDEL		;DELETE THE ENTRY
	JRST	CLKC.1			;TRY THE NEXT ONE

CLKC.6:	SKIPN	SLPTIM			;COMPUTED A SLEEP TIME YET?
	PUSHJ	P,CLKTIM		;NO - DO IT NOW
	JRST	CLKC.1			;YES
; Clock queue event dispatch table
;
CLKTAB:	EXP	EVNHNG			;(00) HUNG TIMER
	EXP	EVNLGI			;(01) LOGIN
	EXP	EVNLGO			;(02) LOGOUT
	EXP	EVNHLT			;(03) HALT

EVNHNG:	MOVE	S1,.CQTIM(S2)		;GET UDT FOR THIS ENTRY
	CAMG	S1,G$UDT		;TIME TO PROCESS IT?
	AOS	(P)			;YES
	POPJ	P,			;RETURN

EVNLGI:	TXNE	J,JL.ULI		;IS A JOB LOGGED IN?
EVNHLT:	TXNN	J,JL.UML		;IN MONITOR MODE?
	AOS	(P)			;YES
	POPJ	P,			;RETURN

EVNLGO:	TXNN	R,RL.FKJ		;FAST KJOB?
	TXNN	J,JL.ULI		;LOGGED OUT?
	AOS	(P)			;YES
	POPJ	P,			;RETURN
; Compute the time to sleep
; Call:	MOVE	S2, clock queue entry address
;	PUSHJ	P,CLKTIM
;
; On return, SLPTIM:= updated sleep time
;
CLKTIM:	PUSH	P,S2			;SAVE FROM DESTRUCTION
	MOVE	S1,.CQTIM(S2)		;GET WAKEUP UDT
	SUB	S1,G$UDT		;GET OFFSET FROM NOW
	MULI	S1,<^D24*^D60*^D60>	;MULTIPLY BY NUMBER OF SECS/DAY
	ASHC	S1,21			;POSITION RESULT
	SKIPE	SLPTIM			;ZERO?
	CAMG	S1,SLPTIM		;GREATER THAN THE CURRENT ONE?
	MOVEM	S1,SLPTIM		;SAVE IT
	POP	P,S2			;RESTORE S2
	POPJ	P,			;RETURN
SUBTTL	Job scheduler -- Timed sleep


TSLEEP:	MOVEI	S1,IZTIME		;GET INACTIVE SLEEP TIME MAXIMUM
	SKIPE	G$SACT			;ANY ACTIVE STREAMS?
	MOVEI	S1,AZTIME		;USE ACTIVE SLEEP TIME MAXIMUM
	SKIPN	S2,SLPTIM		;GET COMPUTED SLEEP TIME
	MOVE	S2,S1			;NO CLOCK REQUESTS
	CAMLE	S1,S2			;WHICH IS SMALLER?
	MOVE	S1,S2			;USE THE COMPUTED VALUE

TOPS10	<TXO	S1,HB.RPT>		;WAKE ON PTY ACTIVITY

	$CALL	I%SLP			;ZZZZZZ
	POPJ	P,			;RETURN
SUBTTL	Job scheduler -- Job check


JOBCHK:	TXNN	R,RL.LGI!RL.KJB		;LOGGING IN OR OUT?
	TXNE	F,FL.UKJ		;USER REQUEST KJOB?
	POPJ	P,			;MAYBE THERE ISN'T A JOB (THATS OK)
	PUSHJ	P,P$STAT##		;GET JOB STATUS
	TXNE	J,JL.ULI!JL.UJA		;JOB STILL THERE?
	POPJ	P,			;ALL'S WELL
	TXZ	R,RL.STP!RL.OPR!RL.NSC!RL.ACK ;MAKE JOB RUNABLE
	MOVE	S1,.JREGS+P(R)		;GET STREAM'S STACK
	PUSH	S1,[B$GONE]		;START STREAM HERE
	MOVEM	S1,.JREGS+P(R)		;REPLACE STACK
	POPJ	P,			;RETURN
SUBTTL	Job scheduler -- Checkpoint


CHKPNT:	TXNE	F,FL.KST		;KSYS STREAM?
	POPJ	P,			;YES--DON'T TALK TO QUASAR
	SKIPN	.JBSPS(R)		;IGNORE IF STEP HEADER SCAN
	TXNE	R,RL.KJB!RL.ACK!RL.OPR	;LOGGING OUT OR ACKS PENDING?
	POPJ	P,			;THEN DO NOTHING
	SKIPL	S1,.JBCHK(R)		;STREAM REQUEST CHECKPOINTING?
	CAML	S1,G$UDT		;BATCON REQUEST CHECKPOINTING?
	POPJ	P,			;NO TO EITHER - RETURN
	PUSHJ	P,L$CHKP##		;CHECKPOINT THE LOG
	PUSHJ	P,CHKINI		;INITIALIZE CHECKPOINT MESSAGE
	PUSHJ	P,CHKJOB		;CHECK JOB STATUS
	  JRST	CHKP.S			;NO NEED TO GO ON
	MOVE	S1,.JBJNO(R)		;GET THE JOB NUMBER
	MOVX	S2,JI.PRG		;GET PROGRAM NAME
	PUSHJ	P,I%JINF		;GET JOB INFO
	SKIPE	S2			;NO NAME..IGNORE THIS STATUS
	$TEXT	(CHKTYO,< Running ^W/S2/^A>)
	SKIPE	S1,.JLLBL(R)		;CHECK IF HAD LABEL
	TLNN	S1,770000		;WAS IT A LABEL
	SKIPA				;NO..IGNORE LABEL
	$TEXT	(CHKTYO,< Last label: ^W/S1/^A>)
	MOVE	S1,.JBJNO(R)		;GET JOB NUMBER
	MOVX	S2,JI.RTM		;GET THE RUNTIME
	PUSHJ	P,I%JINF		;GET THE JOB INFO
	MOVE	S1,S2			;PLACE VALUE IN S1
	PUSHJ	P,B$MTIM		;CONVERT TO READABLE TEXT
	$TEXT	(CHKTYO,< Runtime ^T/G$TMTX/^A>)

CHKP.S:	MOVX	S1,.CHNUL		;GET A <NUL>
	PUSHJ	P,CHKTYO		;STORE IT
	HRRZ	S1,.JBSPW(R)		;GET LAST ADDRESS
	SUBI	S1,-1(P1)		;COMPUTE THE LENGTH
	STORE	S1,.MSTYP(P1),MS.CNT	;SAVE THE MESSAGE COUNT
	PJRST	B$SEND			;SEND MESSAGE TO QUASAR AND RETURN
; INITIALIZE CHECKPOINT MESSAGE AND TEXT POINTERS
;
CHKINI:	MOVEI	S1,CHE.SZ		;GET MESSAGE SIZE
	PUSHJ	P,B$SQSR		;SET UP MESSAGE
	MOVE	P1,S2			;PLACE MESSAGE ADDRESS IN P1
	MOVX	S1,.QOCHE		;MESSAGE TYPE
	STORE	S1,.MSTYP(P1),MS.TYP	;SAVE TYPE IN MESSAGE
	TXNN	F,FL.CHK		;STREAM REQUEST CHECKPOINTING?
	JRST	CHKI.1			;NO
	MOVE	S1,.JQITN(R)		;GET STREAM'S ITN
	MOVEM	S1,.JOACK(R)		;USE IT AS THE ACK CODE
	MOVEM	S1,.MSCOD(P1)		;SAVE IN MESSAGE TO QUASAR TOO
	MOVX	S1,MF.ACK		;GET THE ACK BIT
	MOVEM	S1,.MSFLG(P1)		;STORE IN FLAG WORD
	TXO	R,RL.ACK		;REMEMBER TO WAIT FOR AN ACK

CHKI.1:	XMOVEI	S1,CHE.ST(P1)		;POINT TO STATUS AREA
	TXO	S1,<POINT 7,0>		;MAKE A BYTE POINTER
	MOVEM	S1,.JBSPW(R)		;STORE FOR LATER
	MOVX	S1,CH.FST		;SEND STATUS CODE
	TXZE	F,FL.CHK		;WANT CHECKPOINT UPDATED ON DISK?
	TXO	S1,CH.FCH		;YES - TELL QUASAR
	MOVEM	S1,CHE.FL(P1)		;UPDATE FLAG WORD
	MOVE	S1,.JQITN(R)		;THE TASK NAME
	MOVEM	S1,CHE.IT(P1)		;STORE
	HRLI	S1,.JBCRQ(R)		;CHECKPOINT/REQUEUE INFORMATION
	HRRI	S1,CHE.IN(P1)		;INTO THE MESSAGE
	BLT	S1,CHE.IN+<EQCKSZ-1>(P1)  ;MOVE ALL THE WORDS
	MOVE	S1,G$UDT		;GET CURRENT TIME
	ADDI	S1,CKTIME*3		;GET NEXT TIME TO CHECKPOINT
	MOVEM	S1,.JBCHK(R)		;REMEMBER IT
	POPJ	P,			;RETURN


; CHECK JOB STATUS
;
CHKJOB:	MOVEI	S1,[ITEXT (<Job ^D/.JBJNO(R)/>)] ;DEFAULT
	SKIPG	S2,.JBJNO(R)		;GET JOB NUMBER (IF ANY)
	MOVEI	S1,[ITEXT (<Job being set up by BATCON>)]
	STORE	S2,CHE.FL(P1),CH.JBN	;STORE IT
	$TEXT	(CHKTYO,< ^I/(S1)/^A>)	;DISPLAY SOMETHING
	SKIPLE	.JBJNO(R)		;HAVE A JOB?
	AOS	(P)			;YES
	POPJ	P,			;RETURN


; STORE AN ASCII CHARACTER IN THE CHECKPOINT MESSAGE
;
CHKTYO:	IDPB	S1,.JBSPW(R)		;STORE CHARACTER
	$RETT				;RETURN
SUBTTL	Job scheduler -- Message processing


; Process operator action messages
;
PROMES:	SKIPE	.JOVAL(R)		;HAVE AN OPERATOR/QUASAR MESSAGE?
	TXNE	R,RL.KJB!RL.MIP		;LOGGING OUT OR MESSAGE IN PROGRESS?
	POPJ	P,			;YES - THEN ALL DONE
	TXO	R,RL.MIP		;FLAG MESSAGE IN PROGRESS

PROM.1:	MOVE	S1,.JOFLG(R)		;GET FLAGS
	TXNE	S1,B.STCN		;STOP OR CONTINUE?
	JRST	PROM.4			;YES - SPECIAL CASE OF DEFER REQUEST
	TXNE	S1,B.DEFR		;DEFER FOR STREAM CONTEXT?
	JRST	PROM.3			;YES

PROM.2:	PUSHJ	P,@.JOPRC(R)		;PROCESS MESSAGE
	TXZ	R,RL.MIP		;CLEAR MESSAGE IN PROGRESS
	SETZM	.JOVAL(R)		;INDICATE MESSAGE PROCESSED
	POPJ	P,			;RETURN

PROM.3:	TXZ	R,RL.OPR!RL.STP!RL.JIE!RL.DIA ;CLEAR LOTS OF FLAGS
	TXZ	F,FL.NER!FL.SIL		;CLEAR MORE FLAGS

PROM.4:	TXO	R,RL.MIP!RL.MSP		;SET MESSAGE IN PROGRESS
	MOVEM	F,.JREGS+F(R)		;RESTORE FLAG AC
	MOVEM	R,G$BASE(S)		;RESTORE DATA BASE AC
	MOVE	S1,.JREGS+P(R)		;GET PROCESS STACK AC
	PUSH	S1,.JOPRC(R)		;PLACE ROUTINE ADDR ON STACK
	MOVEM	S1,.JREGS+P(R)		;SAVE STACK FOR PROCESS
	POPJ	P,			;RETURN
SUBTTL	Job scheduler -- KSYS routines


TOPS10	<

; Schedule jobs for KSYS
; Call:	PUSHJ	P,KSYSCD

KSYSCD:	SKIPG	KSYCNT			;COUNT EXPIRED?
	POPJ	P,			;YES--NOTHING TO DO
	$SAVE	<P1,P2,P3,P4>		;SAVE SOME ACS
	MOVSI	P1,-KSYLEN		;START WITH FIRST WORD IN BIT MAP

KSYSC1:	SKIPN	P2,KSYMAP(P1)		;GET A MAP ENTRY
	JRST	KSYSC4			;EMPTY
	JFFO	P2,.+1			;FIND FIRST
	MOVN	P4,P3			;NEGATE
	MOVSI	P2,400000		;GET A BIT
	LSH	P2,(P4)			;POSITION
	HRRZ	S1,P1			;GET MAP INDEX
	IMULI	S1,^D36			;COMPUTE STARTING JOB NUMBER IN WORD
	ADDI	S1,(P3)			;PLUS REMAINDER GETS JOB NUMBER
	MOVE	S,[-JOBMAX+KSYSTR,,KSYSTR] ;POINTER TO START OF KSYS STREAMS

KSYSC2:	SKIPLE	R,G$BASE(S)		;ACTIVE?
	JRST	KSYSC3			;NO--USE THIS ONE
	AOBJN	S,KSYSC2		;KEEP SEARCHING
	POPJ	P,			;NONE AVAILABLE RIGHT NOW

KSYSC3:	HRRZS	S			;KEEP ONLY STREAM NUMBER
	MOVEM	S1,.JBJNO(R)		;SAVE
	ANDCAM	P2,KSYMAP(P1)		;CLEAR BIT IN MAP FOR THIS JOB
	SOS	KSYCNT			;COUNT DOWN NUMBER OF JOBS TO KILL
	AOS	KSYUSE			;COUNT THE KSYS STREAM IN USE
	PUSHJ	P,KSYFIR		;FIREUP THE STREAM
	POPJ	P,			;RETURN

KSYSC4:	AOBJN	P1,KSYSC1		;LOOP
	POPJ	P,			;RETURN
	
; Fireup a KSYS stream

KSYFIR:	$SAVE	<P1>			;SAVE P1
	MOVE	T1,.JQOBJ+OBJ.TY(R)	;SAVE OBJECT TYPE
	MOVE	T2,.JQOBJ+OBJ.UN(R)	;SAVE UNIT/STREAM NUMBER
	MOVE	T3,.JQOBJ+OBJ.ND(R)	;SAVE NODE NUMBER OR NAME
	MOVE	T4,.JBJNO(R)		;SAVE JOB NUMBER
	HRLZ	S1,R			;GET START ADDRESS OF DATA BASE
	HRRI	S1,1(R)			;MAKE A BLT POINTER
	SETZM	(R)			;CLEAR THE FIRST WORD
	BLT	S1,.JSIZE-1(R)		;CLEAR THE DATA BASE
	MOVEM	T1,.JQOBJ+OBJ.TY(R)	;RESTORE OBJECT TYPE
	MOVEM	T2,.JQOBJ+OBJ.UN(R)	;RESTORE UNIT/STREAM NUMBER
	MOVEM	T3,.JQOBJ+OBJ.ND(R)	;RESTORE NODE NUMBER OR NAME
	MOVEM	T4,.JBJNO(R)		;RESTORE JOB NUMBER
	$CALL	M%GPAG			;GET A PAGE
	MOVEM	S1,.JSCMD(R)		;STORE FOR COMMAND PARSING


; Internal job name
	MOVE	S1,G$UDT		;A GOOR RANDOM NUMBER
	MOVEM	S1,.JQITN(R)		;SAVE


; Job information block
	MOVE	S1,['KSYS  ']		;JOB NAME
	MOVEM	S1,.JQJBB+JIB.JN(R)	;SAVE
	MOVE	S1,.JQITN(R)		;GET ITN
	ADDI	S1,1			;DON'T ALLOW ZERO
	ANDI	S1,7777			;MASK DOWN INTO LEGAL RANGE
	STORE	S1,.JQJBB+JIB.SQ(R),EQ.SEQ ;SET SEQUENCE NUMBER
	MOVE	S1,.JBJNO(R)		;GET JOB NUMBER
	MOVEI	S2,JI.USR		;WANT THE PPN
	$CALL	I%JINF			;ASK THE GLXLIB
	JUMPF	KSYJ.X			;JOB GONE AWAY
	MOVEM	S2,.JQJBB+JIB.US(R)	;SAVE PPN
	AOS	S1,KSYREQ		;GET FAKE REQUEST-ID
	MOVEM	S1,.JQJBB+JIB.ID(R)	;SAVE
	HRLZ	S1,.JBJNO(R)		;GET JOB NUMBER
	HRRI	S1,.GTNM1		;WANT FIRST HALF OF NAME
	GETTAB	S1,			;ASK MONITOR
	  SETZ	S1,			;???
	MOVEM	S1,.JQJBB+JIB.NM+0(R)	;SAVE WORD 1
	HRLZ	S1,.JBJNO(R)		;GET JOB NUMBER
	HRRI	S1,.GTNM2		;WANT SECOND HALF OF NAME
	GETTAB	S1,			;ASK MONITOR
	  SETZ	S1,			;???
	MOVEM	S1,.JQJBB+JIB.NM+1(R)	;SAVE WORD 2


; Limit words
	MOVEI	S1,%EQUNO		;/UNIQUE:NO
	STOLIM	S1,.JQLIM(R),UNIQ
	MOVEI	S1,%EQRNO		;/RESTART:NO
	STOLIM	S1,.JQLIM(R),REST
	MOVEI	S1,1			;/OPRINT:YES
	STOLIM	S1,.JQLIM(R),OINT
	MOVEI	S1,%EQOLE		;/OUTPUT:ERROR
	STOLIM	S1,.JQLIM(R),OUTP
	MOVEI	S1,0			;/DEPEND:0
	STOLIM	S1,.JQLIM(R),DEPN
	MOVX	S1,INPCOR		;/CORE
	STOLIM	S1,.JQLIM(R),CORE
	MOVEI	S1,<^D5*^D60>		;/TIME
	STOLIM	S1,.JQLIM(R),TIME
	MOVE	S1,G$NODE		;/DESTINATION
	STOLIM	S1,.JQLIM(R),ONOD
	MOVEI	S1,%BSPOL		;/BATLOG:SPOOL
	STOLIM	S1,.JQLIM(R),BLOG


; Output location
	MOVE	S1,G$NODE		;USE BATCON'S NODE
	MOVEM	S1,.JQLOC(R)		;SAVE IT


; Checkpoint information
	MOVSI	S1,.JBCRQ(R)		;START ADDRESS
	HRRI	S1,.JBCRQ+1(R)		;BUILD BLT AC
	SETZM	.JBCRQ(R)		;CLEAR FIRST WORD
	BLT	S1,.JBCRQ+EQCKSZ-1(R)	;CLEAR ENTIRE BLOCK


; Account string
	MOVE	S1,[.ACTRD,,T1]		;SET UP UUO AC
	MOVEI	T1,2			;TWO WORDS FOLLOWING
	MOVE	T2,.JBJNO(R)		;COPY JOB NUMBER
	MOVEI	T3,.JQACT(R)		;WHERE TO PUT IT
	ACCT.	S1,			;READ ACCOUNT STRING
	  SETZM	.JQACT(R)		;IGNORE ERRORS


; PPN
	MOVE	S1,.JQJBB+JIB.US(R)	;GET FROM JIB BLOCK
	MOVEM	S1,.JQPPN(R)		;COPY IT


; Path
	MOVEM	S1,.JQPAT+0(R)		;SAVE PPN AS PATH


; Control file


; Log file
	MOVSI	S1,KSYLFP		;POINT TO PROTOTYPE FP
	HRRI	S1,.JQLFP(R)		;WHERE TO PUT IT
	BLT	S1,.JQLFP+FPXSIZ-1(R)	;COPY
KSYF.1:	PUSHJ	P,L$GENL##		;GENERATE A LOG FILE NAME
	MOVE	S1,.JQLFD+.FDNAM(R)	;GET LOG FILE NAME
	CAMN	S1,KSYNAM		;SAME AS LAST (NOT UNIQUE)?
	JRST	KSYF.1			;TRY AGAIN
	MOVEM	S1,KSYNAM		;SAVE FOR NEXT TIME


; Miscellaneous
	MOVX	F,FL.INI+FL.KST		;SET INITIAL F FLAGS
	PUSHJ	P,U$FIRE##		;DO CUSTOMER STUFF
	HRRZS	R			;MAKE SURE NO JUNK IN LH
	IORX	R,RL.INI		;SET INITIAL BATCH STREAM FLAGS
	MOVEM	R,G$BASE(S)		;STORE JOB RELOCATION AC
	MOVEM	F,.JREGS+F(R)		;STORE IT
	PUSHJ	P,P$OPEN##		;OPEN A PTY
	JUMPF	KSYF.2			;DID WE DO IT?
	CAMLE	S,G$HACT		;IS THIS NOW THE HIGHEST ACTIVE STREAM
	  MOVEM	S,G$HACT		;YES, SET NEW VALUE
	HRLI	T1,-.JPSIZ		;BUILD PDL FOR THE STREAM
	HRRI	T1,.JPLST-1(R)
	PUSH	T1,[JOBPRC]		;START STREAM AT THE JOB PROCESSOR
	MOVEM	T1,.JREGS+P(R)		;SAVE AS PROCESSOR REGISTER P
	AOS	G$SACT			;ADD ANOTHER JOB
	POPJ	P,			;RETURN TO DISPATCHER

KSYF.2:	$WTO	(<Batch error>,<No PTYs available>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	MOVX	T1,%RSUNA		;SET UP 'STREAM UNAVAILABLE'
	MOVEI	T2,E.NJOB		;NO JOBS AVAILABLE CODE
	MOVX	T3,%SFULL		;SYSTEM FULL
	TXO	R,RL.SHT		;LITE THE SHUTDOWN AT EOJ BIT
	PUSHJ	P,SETUPR		;SEND RESPONSE TO QUASAR
	JRST	B$CLOS			;DISMISS JOB
; Prototype KSYS log file FP
KSYLFP:	$BUILD	(FPXSIZ)		;SIZE OF BLOCK
	  $SET	(.FPLEN,FPMSIZ)		;LENGTH
	  $SET	(.FPINF,FP.FFF,.FPFAS)	;/FILE:ASCII
	  $SET	(.FPINF,FP.FPF,%FPLAS)	;/PRINT:ASCII
	  $SET	(.FPINF,FP.FSP,1)	;/SPACING:1
	  $SET	(.FPINF,FP.DEL,1)	;/DISPOSE:DELETE
	  $SET	(.FPINF,FP.SPL,1)	;SPOOLED FILE
	  $SET	(.FPONM,,0)		;ORIGINAL FILE NAME
	  $SET	(.FPOXT,,0)		;ORIGINAL EXTENSION
	$EOB				;END OF BLOCK
KSYFIN:	MOVEI	T1,KSYFT1		;POINT TO NORMAL COMPLETION TEXT
	MOVEI	T2,[ASCIZ |jobs|]	;ASSUME MORE THAN ONE
	MOVE	S1,KSYJLO		;GET COUNT
	CAIN	S1,1			;JUST ONE?
	MOVEI	T2,[ASCIZ |job|]	;YES
	MOVEI	T3,[ASCIZ |errors|]	;ASSUME MORE THAN ONE
	MOVE	S2,KSYJLE		;GET COUNT
	CAIN	T3,1			;JUST ONE?
	MOVEI	T2,[ASCIZ |error|]	;YES
	SKIPE	T3			;ANY ERRORS?
	MOVEI	T1,KSYFT2		;YES--USE DIFFERENT TEXT
	$WTO	(<KSYS processing completed>,,,<$WTFLG(WT.SJI)>)
	SETZM	G$KSYS			;CLEAR KSYS IN PROGRESS
	POPJ	P,			;RETURN

KSYFT1:	ITEXT	(<^D/KSYJLO/ ^T/(T2)/ logged off>)
KSYFT2:	ITEXT	(<^D/KSYJLO/ ^T/(T2)/ logged off; ^D/KSYJLE/ ^T/(T3)/ had errors>)

> ;END TOPS-10 CONDITIONAL
SUBTTL	IPCF/Operator/QUASAR interface -- IPCF interrupts


; IPCF interrupt level handler
;
IPCINT:	$BGINT IPCLVL			;SWITCH TO IPCF INTERRUPT LEVEL
	$CALL	C%INTR			;NOTIFY THE LIBRARY WE HAVE A MESSAGE
	$DEBRK				;RETURN FROM INTERRUPT
SUBTTL	IPCF/Operator/QUASAR interface -- Hello and goodbye


; Send GOODBYE message to QUASAR
;
GOODBY:	TDZA	T1,T1			;INDICATE SIGNING OFF


; Send HELLO message to QUASAR
;
HELLO:	SETO	T1,			;INDICATE SIGNING ON
	MOVEI	S1,HEL.SZ		;GET MESSAGE SIZE
	PUSHJ	P,B$SQSR		;SETUP QUASAR MESSAGE
	MOVX	S1,<INSVL.(.QOHEL,MS.TYP)!INSVL.(HEL.SZ,MS.CNT)>
	MOVEM	S1,.MSTYP(S2)		;STORE MESSAGE TYPE AND SIZE
	MOVE	S1,['BATCON']		;GET OUR NAME
	MOVEM	S1,HEL.NM(S2)		;STORE IT
	MOVX	S1,<INSVL.(%%.QSR,HEFVER)> ;GET QUASAR VERSION NUMBER
	SKIPN	T1			;WHAT ARE WE DOING?
	TXO	S1,HEFBYE		;SIGNING OFF
	MOVEM	S1,HEL.FL(S2)		;STORE IT
	MOVX	S1,<INSVL.(1,HENNOT)!INSVL.(DEFMJB,HENMAX)>
	MOVEM	S1,HEL.NO(S2)		;STORE # OBJECT TYPES AND UNITS/STREAMS
	MOVX	S1,.OTBAT		;GET BATCH OBJECT TYPE
	MOVEM	S1,HEL.OB(S2)		;STORE IT
	PUSHJ	P,B$SEND		;GREET QUASAR
	POPJ	P,			;AND RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- IPCF message processing


IPCF:	$CALL	C%RECV			;TRY TO RECEIVE A MESSAGE
	  JUMPF	.POPJ			;NONE THERE - RETURN
	LOAD	S2,MDB.SI(S1)		;GET SYSTEM PID INFO
	TXZN	S2,SI.FLG		;FROM SYSTEM PID
	JRST	IPCF.X			;NOT FROM SYSTEM PID - IGNORE IT
	LOAD	T1,S2,SI.IDX		;GET SYSTEM PID INDEX
	CAIE	T1,SP.QSR		;IS IT FROM QUASAR
	CAIN	T1,SP.OPR		;IS IT FROM ORION
	SKIPA				;YES
	JRST	IPCF.X			;NOT FROM QUASAR OR ORION - IGNORE IT
	LOAD	S1,MDB.MS(S1),MD.ADR	;GET MESSAGE ADDRESS
	PUSHJ	P,B$SBLK		;SET UP FOR MESSAGE BLOCK PROCESSING
	LOAD	T1,.MSTYP(S1),MS.TYP	;GET MESSAGE TYPE
	MOVSI	S1,-NUMMSG		;NUMBER OF MESSAGES

IPCF.1:	CAMN	T1,MSGTAB(S1)		;A MATCH?
	JRST	IPCF.2			;YES
	AOBJN	S1,IPCF.1		;LOOP AND TRY ANOTHER
	MOVEI	S1,0			;NO MATCH - MAYBE AN ACK

IPCF.2:	HRRZM	S1,G$MIDX		;SAVE INDEX FOR LATER
	PUSHJ	P,U$IPCF##		;CALL CUSTOMER USER EXIT ROUTINES
	  JRST	IPCF.X			;FAILED - ABORT PROCESSING
	PUSHJ	P,VALMSG		;VALIDATE MESSAGE
	  JRST	IPCF.X			;BAD MESSAGE
	MOVE	S1,G$MIDX		;GET INDEX INTO MESSAGE TABLES
	PUSHJ	P,@MSGPRC(S1)		;PROCESS THE MESSAGE

IPCF.X:	$CALL	C%REL			;RELEASE THE MESSAGE
	SKIPN	G$PSCN			;NEED TO PROCESS PRESCAN STREAM?
	JRST	IPCF			;NO - GET ANOTHER MESSAGE
	POPJ	P,			;RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- Message tables


; Macros to build the paralell message tables
; The arguments to the $ macro are used in the following ways:
;	TYPE	message type
;	SUBR	subroutine to process the message
;	OBJ	index into the message of the object block (-1 means no check)
;
DEFINE	$MSG,<
$ (     0, UNKMSG,     -1)		;??????	UNKNOWN MESSAGES

$ (.QONEX, NEXTJB, .EQROB)		;QUASAR	NEXTJOB
$ (.QOABO, ABORT , ABO.TY)		;QUASAR	USER CANCEL
$ (.QOSUP, SETUP ,     -1)		;QUASAR	SETUP JOB
$ (.QOALC, ALLOC ,     -1)		;QUASAR	PRE-ALLOCATION
TOPS10 <
$ (.QOKSY, KSYS  ,     -1)		;QUASAR KSYS
>

$ (.OMPAU, PAUSE , .OROBJ)		;ORION	STOP
$ (.OMCON, CONTIN, .OROBJ)		;ORION	CONTINUE
$ (.OMRSP, RESPON,     -1)		;ORION	RESPONSE TO WTOR
$ (.OMREQ, REQUE , .OROBJ)		;ORION	REQUEUE
$ (.OMCAN, CANCEL, .OROBJ)		;ORION	CANCEL
$ (.OMSND, SEND  , .OROBJ)		;ORION	SEND
$ (.OMSHC, EXAMIN, .OROBJ)		;ORION	EXAMINE

$ (MT.TXT, ACK   ,     -1)		;ACKS
>
DEFINE	$ (TYPE,SUBR,OBJ),<EXP	TYPE>
MSGTAB::$MSG
NUMMSG==.-MSGTAB

DEFINE	$ (TYPE,SUBR,OBJ),<EXP	SUBR>
MSGPRC::$MSG

DEFINE	$ (TYPE,SUBR,OBJ),<EXP	OBJ>
MSGOBJ::$MSG
SUBTTL	IPCF/Operator/QUASAR interface -- Validate messages


; Validate IPCF messages
; Call:	PUSHJ	P,VALMSG
;	<NON-SKIP>			;ILLEGAL MESSAGE
;	<SKIP>				;MESSAGE OK
;
; On sucessful return, S:= stream index and R:= stream relocation
;
VALMSG:	MOVE	S1,G$MIDX		;GET MESSAGE INDEX
	SKIPGE	MSGOBJ(S1)		;NEED TO VALIDATE MESSAGE?
	JRST	.POPJ1			;NO
	MOVE	S2,MSGTAB(S1)		;GET MESSAGE TYPE
	CAIGE	S2,.OMTXT		;RANGE CHECK
	CAIGE	S2,.OMOFF		;FOR ORION MESSAGE TYPE
	JRST	VALM.2			;NO

VALM.1:	PUSHJ	P,B$GBLK		;GET A MESSAGE BLOCK
	  JRST	VALM.E			;NO MORE - ERROR
	CAIE	T1,.OROBJ		;IS THIS THE OBJECT BLOCK???
	JRST	VALM.1			;NO - GET THE NEXT MSG BLOCK
	MOVE	S2,T3			;GET THE BLOCK DATA ADDRESS IN S1.
	JRST	VALM.3			;GO FIND THE OBJECT BLOCK

VALM.2:	MOVE	S2,MSGOBJ(S1)		;GET OBJECT BLOCK OFFSET
	ADD	S2,G$MADR		;ADD MESSAGE ADDRESS

VALM.3:	MOVE	T1,.ROBTY(S2)		;GET OBJECT TYPE
	MOVE	T2,.ROBAT(S2)		;GET UNIT NUMBER
	MOVE	T3,.ROBND(S2)		;AND NODE NUMBER
	MOVEI	S,0			;CLEAR STREAM INDEX

VALM.4:	SKIPN	R,G$BASE(S)		;GET STREAM RELOCATION
	JRST	VALM.5			;NOT SETUP
	CAMN	T1,.JQOBJ+.ROBTY(R)	;COMPARE OBJECT TYPE
	CAME	T2,.JQOBJ+.ROBAT(R)	;COMPARE UNIT NUMBER
	JRST	VALM.5			;NO MATCH
	CAMN	T3,.JQOBJ+.ROBND(R)	;COMPARE NODE NUMBER
	JRST	.POPJ1			;MESSAGE SEEMS OK - RETURN

VALM.5:	CAIGE	S,DEFMJB		;CHECKED ALL STREAMS YET?
	AOJA	S,VALM.4		;NO - LOOP

VALM.E:	$WTO	(<BATCON Error>,<Invalid object block: type = ^O/T1/, unit/stream = ^O/T2/, node = ^N/T3/>)
	POPJ	P,			;TAKE ERROR RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- Initialize stream block


; Initialize operator/QUASAR message block in stream data base
; Call:	MOVEI	S1,[ASCIZ |message text|]
;	MOVE	S2,processor address
;	PUSHJ	P,B$IMSG
;	<NON-SKIP>			;MESSAGE PENDING
;	<SKIP>				;MESSAGE BLOCK SETUP
;
B$IMSG::SKIPN	.JOVAL(R)		;HAVE A VALID MESSAGE?
	JRST	IMSG.1			;NO
	$WTO	(<^T/@.JONAM(R)/ pending; ^T/(S1)/ ignored>,,.JQOBJ(R))
	POPJ	P,			;RETURN

IMSG.1:	SETOM	.JOVAL(R)		;INDICATE A VALID MESSAGE
	SETZM	.JOFLG(R)		;CLEAR FLAG WORD
	MOVEM	S1,.JONAM(R)		;STORE TEXT ADDRESS
	MOVEM	S2,.JOPRC(R)		;STORE PROCESSOR ADDRESS
	MOVSI	S1,.JOMSG(R)		;START OF MESSAGE BUFFER
	HRRI	S1,.JOMSG+1(R)		;MAKE A BLT POINTER
	SETZM	.JOMSG(R)		;CLEAR FIRST WORD
	BLT	S1,.JOMSG+IPCSIZ-1(R)	;CLEAR ENTIRE BUFFER
	MOVE	S1,G$MADR		;GET MESSAGE ADDRESS
	LOAD	S2,.MSTYP(S1),MS.CNT	;GET MESSAGE LENGTH
	CAILE	S2,IPCSIZ-1		;OVERFLOW?
	MOVEI	S2,IPCSIZ-1		;YES
	STORE	S2,.MSTYP(S1),MS.CNT	;UPDATE
	HRLZ	S1,G$MADR		;GET MESSAGE ADDRESS
	HRRI	S1,.JOMSG(R)		;PUT IT THERE
	ADDI	S2,.JOMSG(R)		;COMPUTE END ADDRESS
	BLT	S1,-1(S2)		;COPY MESSAGE
	JRST	.POPJ1			;RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- Message block processing


; Set up message block processing
; Call:	MOVE	S1,message address
;	PUSHJ	P,B$SETM
;
; On return, G$MADR and G$MBLK will be set up and B$GBLK may be called.
;
; All ACs preserved
;
B$SBLK::$SAVE	<P1>			;SAVE P1
	MOVEM	S1,G$MADR		;REMEMBER MESSAGE ADDRESS FOR LATER
	MOVEI	P1,.OHDRS+ARG.HD(S1)	;POINT TO FIRST BLOCK ADDRESS
	MOVEM	P1,G$MBLK		;REMEMBER IT TOO
	MOVE	P1,.OARGC(S1)		;GET ARGUMENT COUNT
	MOVEM	P1,G$MARG		;STORE IT
	POPJ	P,			;RETURN


; Get the next block of a message
; Call:	PUSHJ	P,B$GBLK
;	<NON-SKIP>		;END OF MESSAGE
;	<SKIP>			;NEXT BLOCK FOUND
;
; On error return, T1, T2 and T3 left unchanged
; On sucessful return, T1:= type, T2:= length, T3:= data address
;
; AC usage:	Destroys S1
;
B$GBLK::MOVE	S1,G$MADR		;GET MESSAGE ADDRESS
	SOSGE	G$MARG			;SUBTRACT 1 FROM THE BLOCK COUNT
	POPJ	P,			;ERROR RETURN IF NO MORE
	MOVE	S1,G$MBLK		;GET THE PREVIOUS BLOCK ADDRESS
	LOAD	T1,ARG.HD(S1),AR.TYP	;GET THE BLOCK TYPE
	LOAD	T2,ARG.HD(S1),AR.LEN	;GET THE BLOCK LENGTH
	MOVEI	T3,ARG.DA(S1)		;GET THE BLOCK DATA ADDRESS
	ADD	S1,T2			;POINT TO THE NEXT MESSAGE BLOCK
	MOVEM	S1,G$MBLK		;SAVE IT FOR THE NEXT CALL
	JRST	.POPJ1			;RETURN SUCESSFUL
SUBTTL	IPCF/Operator/QUASAR interface -- QUASAR communication


; Setup message to QUASAR
; Call:	MOVE	S1,# words
;	PUSHJ	P,B$SQSR
;
; On return, S2:= message address
;
B$SQSR::MOVE	S2,[MSGADR,,MSGADR+1]	;SET UP BLT
	SETZM	MSGADR			;CLEAR THE FIRST WORD
	BLT	S2,MSGADR-1(S1)		;CLEAR THE ENTIRE BLOCK
	MOVEI	S2,MSGADR		;GET MESSAGE ADDRESS AGAIN
	STORE	S2,G$SAB+SAB.MS		;STORE THE MESSAGE ADDRESS IN SAB
	POPJ	P,			;RETURN


; Send an IPCF message to QUASAR
; Call:	PUSHJ	P,B$SEND
;
B$SEND::SETZM	G$SAB+SAB.PD		;NO PID
	LOAD	S1,@G$SAB+SAB.MS,MS.CNT	;GET THE MESSAGE COUNT
	STORE	S1,G$SAB+SAB.LN		;STORE IT
	MOVX	S1,<SI.FLG+<INSVL.(SI.IDX,SP.QSR)>> ;USE SPECIAL PID INDEX
	MOVEM	S1,G$SAB+SAB.SI		;STORE IT
	MOVEI	S1,SAB.SZ		;SIZE OF BLOCK IN S1
	MOVEI	S2,G$SAB		;ADDRESS OF BLOCK
	$CALL	C%SEND			;SEND TO QUASAR
	  SKIPT				;CHECK FOR ERRORS
	SKIPN	G$KILL			;KILLING ALL JOBS?
	POPJ	P,			;RETURN
	$STOP	(SQF,<Send failure to QUASAR>)
; Update stream status in QUASAR
; Call:	MOVE	T1,status code
;	PUSHJ	P,B$UPDA
;
B$UPDA::MOVEI	S1,STU.SZ		;GET STATUS SIZE
	PUSHJ	P,B$SQSR		;SETUP MESSAGE TO QUASAR
	MOVEM	T1,STU.CD(S2)		;SAVE THE CODE
	MOVE	S1,[STU.SZ,,.QOSTU]	;GET HEADER WORD
	MOVEM	S1,.MSTYP(S2)		;STORE IN MESSAGE
	MOVSI	S1,.JQOBJ(R)		;GET SOURCE TYPE FROM STREAM
	HRRI	S1,STU.RB(S2)		;DESTINATION,,RESPONSE TYPE
	BLT	S1,STU.RB+OBJ.SZ-1(S2)	;MOVE TYPE,UNIT,NUMBER
	PJRST	B$SEND			;SEND TO QUASAR AND RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- Ask for operator response


; Ask for operator response
; Call:	MOVE	S1,address of type ITEXT block
;	MOVE	S2,address of main ITEXT block
;	MOVE	T1,address of table of responses
;	PUSHJ	P,B$OPER
;
; On return, S1:= index into response table
;
B$OPER::MOVEM	S1,.JOTYP(R)		;STORE TYPE ITEXT BLOCK ADDRESS
	MOVEM	S2,.JOTXT(R)		;STORE MAIN ITEXT BLOCK ADDRESS
	MOVEM	T1,.JOTBL(R)		;STORE RESPONSE TABLE POINTER
	MOVEI	T1,%OREWT		;GET OPERATOR RESPONSE WAIT CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR

OPER.1:	MOVE	S1,.JQITN(R)		;GET THE REQUEST ITN
	MOVEM	S1,.JOACK(R)		;SAVE AS THE ACK CODE
	$WTOR	(<^I/@.JOTYP(R)/>,<^I/JIBTXT/^I/@.JOTXT(R)/>,.JQOBJ(R),.JOACK(R),<$WTNOD(.JQLOC(R))>)
	TXO	R,RL.OPR		;MARK AS WAITING FOR OPERATOR RESPONSE
	PUSHJ	P,QTS			;WAIT FOR OEPRATOR TO ANSWER
	SKIPN	S1,.JOTBL(R)		;POINT TO RESPONSE TABLE (IF ONE GIVEN)
	POPJ	P,			;WILL ACCEPT ANY TEXT - RETURN
	HRROI	S2,.JORSP(R)		;POINT TO RESPONSE FROM OPERATOR
	$CALL	S%TBLK			;SCAN THE TABLE FOR A MATCH
	TXNE	S2,TL%NOM		;GOT ONE?
	JRST	OPER.1			;NO - TRY AGAIN
	PUSH	P,S1			;SAVE INDEX
	MOVX	T1,%RESET		;GET NORMAL OPERATION CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	POP	P,S1			;RESTORE S1
	POPJ	P,			;RETURN WITH TABLE INDEX IN S1
SUBTTL	IPCF/Operator/QUASAR interface -- Unknown message


UNKMSG:	MOVE	S1,G$MADR		;GET MESSAGE ADDRESS
	$WTO	(<BATCON Error>,<^I/UNKTXT/>)
	POPJ	P,			;RETURN

UNKTXT:	ITEXT	(<                  Unknown IPCF message
Message header: ^O12R0/.MSTYP(S1)/, ^O12R0/.MSFLG(S1)/, ^O12R0/.MSCOD(S1)/>)
SUBTTL	IPCF/Operator/QUASAR interface -- QUASAR message #5 (NEXTJOB)


NEXTJB:	TXNN	R,RL.ACT		;STREAM ALREADY ACTIVE?
	JRST	NEXT.1			;GOT IT
	MOVX	T1,%RSUNA		;NOT SETUP..TRY AGAIN
	MOVEI	T2,E.STRA		;STREAM ALREADY ACTIVE
	SETZM	T3			;CLEAR STATUS CODE AC
	PJRST	SETUPF			;NOTIFY QUASAR OF THE SETUP FAILURE

NEXT.1:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	PUSHJ	P,FIREUP		;FIREUP STREAM
	POPJ	P,			;RETURN
; Fireup a job for processing
;
FIREUP:	MOVE	T1,.JQOBJ+OBJ.TY(R)	;SAVE OBJECT TYPE
	MOVE	T2,.JQOBJ+OBJ.UN(R)	;SAVE UNIT/STREAM NUMBER
	MOVE	T3,.JQOBJ+OBJ.ND(R)	;SAVE NODE NUMBER OR NAME
	HRLZ	S1,R			;GET START ADDRESS OF DATA BASE
	HRRI	S1,1(R)			;MAKE A BLT POINTER
	SETZM	(R)			;CLEAR THE FIRST WORD
	BLT	S1,.JSIZE-1(R)		;CLEAR THE DATA BASE
	MOVEM	T1,.JQOBJ+OBJ.TY(R)	;RESTORE OBJECT TYPE
	MOVEM	T2,.JQOBJ+OBJ.UN(R)	;RESTORE UNIT/STREAM NUMBER
	MOVEM	T3,.JQOBJ+OBJ.ND(R)	;RESTORE NODE NUMBER OR NAME
	$CALL	M%GPAG			;GET A PAGE
	MOVEM	S1,.JSCMD(R)		;STORE FOR COMMAND PARSING


; Internal job name
	MOVE	S1,.EQITN(P1)		;GET THE ITN FOR THE JOB
	MOVEM	S1,.JQITN(R)		;PLACE IN DATA BASE


; Job information block
	HRLI	S1,.EQJBB(P1)		;START OF JOB INFO BLOCK
	HRRI	S1,.JQJBB(R)		;END OF JOB INFO BLOCK
	BLT	S1,.JQJBB+JIBSIZ-1(R)	;MOVE THE BLOCK


; Limit words
	HRLI	S1,.EQLIM(P1)		;GET START OF LIMIT WORDS
	HRRI	S1,.JQLIM(R)		;GET DESTINATION OF LIMIT WORDS
	BLT	S1,.JQLIM+EQLMSZ-1(R)	;MOVE THE LIMIT WORDS


; Output location
	GETLIM	S1,.JQLIM(R),ONOD	;GET THE OUTPUT/LOCATION NODE
	MOVEM	S1,.JQLOC(R)		;SAVE AS THE LOCATION


; Checkpoint information
	HRLI	S1,.EQCHK(P1)		;GET ADDRESS OF CHECKPOINT WORDS
	HRRI	S1,.JBCRQ(R)		;GET DESTINATION FOR WORDS
	BLT	S1,.JBCRQ+EQCKSZ-1(R)	;SAVE THEM IN DATA BASE


; Account string
	HRLI	S1,.EQACT(P1)		;GET ADDRESS OF ACCOUNT STRING
	HRRI	S1,.JQACT(R)		;GET DESTINATION FOR STRING
	BLT	S1,.JQACT+10-1(R)	;SAVE ACCOUNT STRING
	LOAD	T2,.EQLEN(P1),EQ.LOH	;GET LENGTH OF THE REQUEST HEADER


TOPS20	<				;TOPS-20 ONLY
; SPRINT input set handle
	MOVE	S1,.EQSIS(P1)		;GET SPRINT SPOOL WORD
	MOVEM	S1,.JQSIS(R)		;SAVE WORD


; User name
	HRLI	S1,.EQOWN(P1)		;GET USER NAME
	HRRI	S1,.JQNAM(R)		;DESTINATION FOR USER NAME
	BLT	S1,.JQNAM+10-1(R)	;MOVE THE NAME


; Connected directory
	HRLI	S1,.EQCON(P1)		;GET CONNECTED DIRECTORY
	HRRI	S1,.JQCON(R)		;DESTINATION FOR CONN. DIR
	BLT	S1,.JQCON+12-1(R)	;SAVE CONNECTED DIRECTORY
>					;END OF TOPS-20 CONDITIONAL


TOPS10	<				;TOPS-10 ONLY
; User PPN
	MOVE	S1,.EQOID(P1)		;GET PPN INFO
	MOVEM	S1,.JQPPN(R)		;SAVE PPN


; Path
	CAIGE	T2,.EQPSZ		;ENOUGH ROOM FOR THE PATH SPEC
	  JRST	FIRE.0			;NO, DON'T BOTHER COPYING IT
	HRLI	S1,.EQPAT(P1)		;WHERE IT IS IF PRESENT
	HRRI	S1,.JQPAT(R)		;INTO INTERNAL BLOCK
	BLT	S1,.JQPAT+5(R)		;MOVE IT ALL
>					;END OF TOPS-10 CONDITIONAL

; Control file
FIRE.0:	ADDI	T2,(P1)			;FIND FILE PARAMETERS FOR THE CTL FILE
	HRLZ	S1,T2			;GET FP ADDRESS IN THE EQ
	HRRI	S1,.JQCFP(R)		;GET FP ADDRESS IN THE JOB DATA BASE
	LOAD	S2,.FPLEN(T2),FP.LEN	;GET LENGTH OF FP IN THE EQ
	ADDI	S2,.JQCFP(R)		;COMPUTE END ADDRESS TO BLT
	BLT	S1,-1(S2)		;COPY THE CONTROL FILE FP
	LOAD	T3,.FPLEN(T2),FP.LEN	;FIND THE FILE DESCRIPTOR
	ADDI	T3,(T2)			;AS MESSAGE+LENGTH OF HEADER+LENGTH OF PARMS
	LOAD	T4,.FDLEN(T3),FD.LEN	;SIZE OF THE DESCRIPTOR
	ADDI	T4,.JQCFD-1(R)		;END OF THE BLT
	HRLI	T1,0(T3)		;THE CTL FILE STRUCTURE
	HRRI	T1,.JQCFD(R)		;WHERE FNDCTL WANTS IT
	BLT	T1,0(T4)		;COPY ALL AND SFD'S IF THERE
	LOAD	T4,.FDLEN(T3),FD.LEN	;GET FD SIZE AGAIN
	ADDI	T3,(T4)			;C = LOG FILE PARAMETERS


; Log file
	HRLZ	S1,T3			;GET FP ADDRESS IN THE EQ
	HRRI	S1,.JQLFP(R)		;GET FP ADDRESS IN THE JOB DATA BASE
	LOAD	S2,.FPLEN(T3),FP.LEN	;GET LENGTH OF FP IN THE EQ
	ADDI	S2,.JQLFP(R)		;COMPUTE END ADDRESS TO BLT
	BLT	S1,-1(S2)		;COPY THE CONTROL FILE FP
	LOAD	T4,.FPLEN(T3),FP.LEN	;SIZE OF LOG FILE PARM HEADER
	ADDI	T4,(T3)			;POINT TO LOG FILE DESCRIPTOR
	LOAD	T3,.FDLEN(T4),FD.LEN	;SIZE OF LOG FILE FD
	ADDI	T3,.JQLFD-1(R)		;LAST LOCATION TO MOVE TO
	HRLI	T1,0(T4)		;THE LOG FILE NOW
	HRRI	T1,.JQLFD(R)		;WHERE THE ROUTINES WANT IT
	BLT	T1,0(T3)		;MOVE THE FULL SPEC


; Miscellaneous
	PUSHJ	P,U$FIRE##		;DO CUSTOMER STUFF
	HRRZS	R			;MAKE SURE NO JUNK IN LH
	IORX	R,RL.INI		;SET INITIAL BATCH STREAM FLAGS
	MOVEM	R,G$BASE(S)		;STORE JOB RELOCATION AC
	MOVX	F,FL.INI		;SET INITIAL F FLAGS
	MOVEM	F,.JREGS+F(R)		;STORE IT
	SETOM	.JBJNO(R)		;MARK NO JOB YET
	MOVE	S1,G$STRM(S)		;GET THE STREAM NUMBER
	CAIN	S1,PSCSTR		;IS IT THE PRESCAN STREAM?
	POPJ	P,			;YES - JUST RETURN


FIRE.1:	AOS	G$SACT			;ANOTHER STREAM IN USE
	PUSHJ	P,P$OPEN##		;OPEN A PTY
	JUMPF	FIRE.2			;DID WE DO IT?
	CAMLE	S,G$HACT		;IS THIS NOW THE HIGHEST ACTIVE STREAM
	  MOVEM	S,G$HACT		;YES, SET NEW VALUE
	HRLI	T1,-.JPSIZ		;BUILD PDL FOR THE STREAM
	HRRI	T1,.JPLST-1(R)
	PUSH	T1,[JOBPRC]		;START STREAM AT THE JOB PROCESSOR
	MOVEM	T1,.JREGS+P(R)		;SAVE AS PROCESSOR REGISTER P
	POPJ	P,			;RETURN TO DISPATCHER

FIRE.2:	$WTO	(<Batch error>,<No PTYs available - job requeued>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	MOVX	T1,%RSUNA		;SET UP 'STREAM UNAVAILABLE'
	MOVEI	T2,E.NJOB		;NO JOBS AVAILABLE CODE
	MOVX	T3,%SFULL		;SYSTEM FULL
	TXO	R,RL.SHT		;LITE THE SHUTDOWN AT EOJ BIT
	PUSHJ	P,SETUPR		;SEND RESPONSE TO QUASAR
	SETOM	.JBCHK(R)		;NO CHECKPOINT NEEDED
	JRST	B$CLOS			;DISMISS JOB
SUBTTL	IPCF/Operator/QUASAR interface -- QUASAR message #6 (ABORT)


ABORT:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	MOVE	S1,ABO.IT(P1)		;GET ITN FOR STREAM
	CAME	S1,.JQITN(R)		;IS IT SAME JOB
	POPJ	P,			;NO,,IGNORE IT
	MOVEI	S1,[ASCIZ |CANCEL|]	;MESSAGE NAME
	MOVEI	S2,ABOJOB		;PROCESSOR ADDRESS
	PUSHJ	P,B$IMSG		;SET UP OPERATOR/QUASAR MESSAGE
	  POPJ	P,			;ONE ALREADY THERE - RETURN
	MOVX	S1,B.DEFR		;GET DEFERRED FLAG
	IORM	S1,.JOFLG(R)		;STORE IT
	MOVX	T1,%CNCLG		;GET CANCEL CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	$WTOJ	(<Cancel request queued by user ^P/ABO.ID(P1)/>,<^R/.JQJBB(R)/>,.JQOBJ(R))
	POPJ	P,			;RETURN


; Routine executed in stream context to abort the job.
;
ABOJOB:	PUSHJ	P,P$STOP##		;STOP THE PTY
	MOVEI	S1,.JOMSG(R)		;GET MESSAGE ADDRESS
	$IDENT	(CANCEL,<? Job canceled by user ^P/ABO.ID(S1)/>)
	PUSHJ	P,B$RTYO		;ECHO THE RESPONSE BUFFER
	TXZ	R,RL.JIE		;AVOID THE CLOSE/DUMP
	TXO	F,FL.UHE!FL.TXT		;AN UNEXPECTED CONDITION, TEXT AVAIL
	$TEXT	(<-1,,.JWTOP(R)>,<Job canceled by user ^P/ABO.ID(S1)/^0>)
	JRST	CLOSJB			;DISMISS THE JOB
SUBTTL	IPCF/Operator/QUASAR interface -- QUASAR message #22 (SETUP)


SETUP:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	LOAD	S1,SUP.FL(P1)		;GET FLAGS
	TXNE	S1,SUFSHT		;SHUTTING DOWN STREAM?
	JRST	SHUTDN			;YES
	MOVX	S1,-1			;-1 MEANS WE WANT A FREE STREAM
	PUSHJ	P,FSTREA		;SEE IF CAN FIND ONE
	  JUMPF	SETE.1			;NONE AVAILABLE
	MOVE	S,S1			;GET STREAM
	LOAD	S1,SUP.UN(P1),RO.UNI	;GET UNIT/STREAM NUMBER
	MOVEM	S1,G$STRM(S)		;SAVE STREAM NUMBER IN TABLE
	MOVEI	S1,.JPAGS		;# PAGES NEEDED FOR THE DATA BASE
	$CALL	M%AQNP			;GET A PAGE FOR THE DATA BASE
	MOVEI	R,(S1)			;PUT THE PAGE NUMBER IN R
	PG2ADR	R			;CONVERT PAGE TO ADDRESS
	HRRZM	R,G$BASE(S)		;SAVE FOR THE DISPATCHER
	MOVSI	S1,SUP.TY(P1)		;BATCH OBJECT TYPE
	HRRI	S1,.JQOBJ(R)		;PLACE IN DATA BASE
	BLT	S1,.JQOBJ+OBJ.SZ-1(R)	;MOVE THE BLOCK
	MOVX	T1,%RSUOK		;GOOD RETURN FOR SETUP
	SETZB	T2,T3			;CLEAR MESSAGE AND STATUS CODE
	PUSHJ	P,SETUPS		;SEND SUCESSFUL SETUP MESSAGE TO QUASAR
	POPJ	P,			;RETURN


SETE.1:	MOVX	T1,%RSUDE		;CAN NOT SETUP,,DO NOT TRY AGAIN
	MOVEI	T2,E.NSTR		;NO FREE STREAMS
	SETZM	T3			;CLEAR STATUS CODE AC
	PJRST	SETUPF			;NOTIFY QUASAR OF THE SETUP FAILURE

; Shutdown message
;
SHUTDN:	LOAD	S1,SUP.UN(P1),RO.UNI	;GET STREAM NUMBER
	PUSHJ	P,FSTREA		;FIND THE STREAM
	  JUMPF	.POPJ			;EH?
	MOVE	S,S1			;GET STREAM INDEX
SHUT.1:	SETOM	G$STRM(S)		;MARK STREAM AVAILABLE
	HRRZ	S2,G$BASE(S)		;GET STREAM RELOCATION ADDRESS
	SETZM	G$BASE(S)		;CLEAR STREAM ENTRY
	ADR2PG	S2			;CONVERT TO PAGE NUMBER
	MOVEI	S1,.JPAGS		;NUMBER TO RELEASE
	$CALL	M%RLNP			;RELEASE IT
	TXNE	F,FL.KST		;KSYS STREAM?
	SOS	KSYSSC			;YES--COUNT DOWN # STREAMS SETUP
	POPJ	P,			;AND RETURN
; Here on SETUP failure
;
SETUPF:	$WTO	(<BATCON error>,<^I/JIBTXT/^I/@ERRTAB(T2)/>,.JQOBJ(R))
	TXO	R,RL.SHT		;LITE THE SHUTDOWN AT EOJ BIT
	JRST	SETUPR			;SEND RESPONSE TO QUASAR


; Here on sucessful SETUP
;
SETUPS:	$WTO	(<Started>,,.JQOBJ(R))

SETUPR:	TXNE	F,FL.KST		;KSYS STREAM
	POPJ	P,			;YES--DON'T TALK TO QUASAR
	MOVEI	S1,RSU.SZ		;GET THE MESSAGE SIZE
	PUSHJ	P,B$SQSR		;SETUP MESSAGE TO QUASAR
	MOVEM	T3,RSU.CD(S2)		;SAVE THE CODE
	MOVEM	T1,RSU.CO(S2)		;STORE IN MESSAGE
	MOVE	S1,[RSU.SZ,,.QORSU]	;GET HEADER WORD
	MOVEM	S1,.MSTYP(S2)		;STORE IN MESSAGE
	MOVSI	S1,.JQOBJ(R)		;GET SOURCE TYPE FROM STREAM
	HRRI	S1,RSU.TY(S2)		;DESTINATION,,RESPONSE TYPE
	BLT	S1,RSU.NO(S2)		;MOVE TYPE,UNIT,NUMBER
	PUSHJ	P,B$SEND		;SEND TO QUASAR
	POPJ	P,			;RETURN
;FIND A STREAM ROUTINE
;CALLED WITH S1 STREAM TO LOCATE  ....-1...FREE STREAM

FSTREA:	MOVSI	S2,-JOBMAX		;GET MAX NUMBER OF JOBS
FSTR.1:	MOVE	T1,G$STRM(S2)		;GET FIRST STREAM VALUE
	CAMN	T1,S1			;CHECK IF MATCH
	JRST	FSTR.2			;YES ,,,MATCH
	AOBJN	S2,FSTR.1		;TRY NEXT ENTRY
	$RETF				;CAN'T FIND ENTRY
FSTR.2:	HRRZ	S1,S2			;RELATIVE STREAM INDEX
	$RETT				;RETURN TRUE
	POPJ	P,			;RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- QUASAR message #60 (ALLOCATION)


ALLOC:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	MOVEI	S,PSCSTR		;GET PRESCAN STREAM NUMBER
	SKIPL	G$STRM(S)		;DATA BASE ALLOCATED YET?
	JRST	ALLO.1			;YES
	MOVX	S1,.JPAGS		;NUMBER OF PAGES IN A JOB'S DATA BASE
	$CALL	M%AQNP			;GET SOME PAGES
	MOVEI	R,(S1)			;PUT THE PAGE NUMBER IN R
	PG2ADR	R			;CONVERT TO ADDRESS
	HRRZM	R,G$BASE(S)		;STORE PAGE POINTER
	MOVE	S1,.EQROB+.ROBTY(P1)	;GET OBJECT TYPE
	MOVEM	S1,.JQOBJ+OBJ.TY(R)	;STORE IT
	MOVEI	S1,PSCSTR		;PRESCAN STREAM NUMBER
	MOVEM	S1,G$STRM(S)		;STORE IT
	MOVE	S1,.EQROB+.ROBND(P1)	;GET NODE
	MOVEM	S1,.JQOBJ+OBJ.ND(R)	;STORE IT
	JRST	ALLO.2			;ONWARD

ALLO.1:	HRRZ	R,G$BASE(S)		;GET RELOCATION

ALLO.2:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	MOVE	S1,.EQROB+.ROBTY(P1)	;GET OBJECT TYPE
	MOVEI	S,PSCSTR		;GET PRESCAN STREAM NUMBER
	HRRZ	R,G$BASE(S)		;GET RELOCATION FOR STREAM
	PUSHJ	P,FIREUP		;FIRE UP A BATCH STREAM
	HRLI	S1,-.JPSIZ		;BUILD THE PDL FOR THE STREAM
	HRRI	S1,.JPLST-1(R)		;STACK STARTS HERE
	PUSH	S1,[STPPRC]		;BEGIN AT THE STEP PROCESSOR
	MOVEM	S1,.JREGS+P(R)		;STORE STREAM'S AC 'P'
	SETOM	.JBSPS(R)		;INDICATE STEP HEADER SCAN ONLY
	AOS	G$SACT			;ADD ANOTHER JOB
	CAMLE	S,G$HACT		;COULD THIS STREAM BE THE NEW G$HACT?
	MOVEM	S,G$HACT		;YES - STORE STREAM INDEX
	SETOM	G$PSCN			;INDICATE PRESCAN SETUP
	POPJ	P,			;RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- QUASAR message #66 (KSYS)


TOPS10	<

KSYS:	MOVE	S1,[KSYZBG,,KSYZBG+1]	;SET UP BLT
	SETZM	KSYZBG			;CLEAR FIRST WORD
	BLT	S1,KSYZND		;CLEAR ALL KSYS DATA
	MOVEI	S1,777777-^D512		;STARTING FAKE REQUEST-ID
	MOVEM	S1,KSYREQ		;SAVE
	SETOM	G$KSYS			;FLAG KSYS IN PROGRESS
	PUSHJ	P,KSYJOB		;FIND ALL THE JOBS TO KILL
	SKIPN	KSYCNT			;ANY JOBS?
	PJRST	KSYFIN			;NO--TYPE COMPLETION TEXT AND RETURN
	PUSHJ	P,KSYSET		;SETUP ALL KSYS STREAMS
	POPJ	P,			;LET THE SCHEDULER DO THE REST
; Here to find all the jobs to kill
; Call:	PUSHJ	P,KSYJOB
;
; On return all jobs to be killed will be marked in the bit map
; (KSYMAP) and the number of jobs marked will be set in KSYCNT.

KSYJOB:	$SAVE	<P1,P2>			;SAVE SOME ACS
	MOVE	T1,[KSYMAP,,KSYMAP+1]	;SET UP BLT
	SETZM	KSYMAP			;CLEAR FIRST WORD
	BLT	T1,KSYMAP+KSYLEN-1	;CLEAR OUT BIT MAP
	SETZM	KSYCNT			;INIT COUNT OF JOBS TO KILL
	SETZM	KSYJLO			;CLEAR COUNT OF JOBS LOGGED OFF
	MOVE	P1,[%NSHJB]		;START WITH THE HIGHEST
	GETTAB	P1,			; LOGGED IN JOB
	  MOVEI	P1,^D511		;ASSUME THE MAX

KSYJ.1:
; CHECK THE PPN
	MOVEI	S1,(P1)			;GET JOB NUMBER
	MOVEI	S2,JI.USR		;WANT THE PPN
	$CALL	I%JINF			;ASK THE GLXLIB
	JUMPF	KSYJ.X			;JOB GONE AWAY
	CAMN	S2,OPRPPN		;OPERATOR?
	JRST	KSYJ.X			;YES--LEAVE HIM ALONE

; CHECK THE LINE
	MOVEI	S1,(P1)			;GET JOB NUMBER
	MOVEI	S2,JI.TNO		;WANT LINE NUMBER
	$CALL	I%JINF			;ASK THE GLXLIB
	JUMPF	KSYJ.X			;JOB GONE AWAY
	JUMPL	S2,KSYJ.3		;ALREADY DETACHED
	TRO	S2,.UXTRM		;ADD UDX OFFSET
	GETLCH	S2			;GET LINE CHARACTERISTICS
	TXNN	S2,GL.ITY		;PTY?
	JRST	KSYJ.2			;NO

; CHECK FOR BATCON OR MIC CONTROLLED PTYS
	MOVEI	S1,.GTLIM		;BATCH LIMIT TABLE
	HRL	S1,P			;INCLUDE JOB NUMBER
	GETTAB	S1,			;GET BAT LIMIT WORD
	  MOVEI	S1,0			;SHOULDNT FAIL
	TXNE	S1,JB.LBT		;BATCH (BATCON OR MIC)?
	JRST	KSYJ.X			;YES--LEAVE THEM ALONE

KSYJ.2:	TXNN	S2,GL.DSL!GL.REM	;DATASET OR REMOTE?
	JRST	KSYJ.X			;NO--TRY SOMEONE ELSE
	ANDI	S2,UX.UNT		;KEEP ONLY THE LINE NUMBER
	HRLZS	S2			;MAKE IT LINE#,,JOB 0
	ATTACH	S2,			;DETACH JOB
	  JRST	KSYJ.X			;??

KSYJ.3:	MOVSI	T1,400000		;GET A BIT
	MOVEI	T2,(P1)			;AND THE JOB IN QUESTION
	IDIVI	T2,^D36			;COMPUTE BIT MAP WORD
	MOVNS	T3			;NEGATE
	LSH	T1,(T3)			;POSITION BIT
	IORM	T1,KSYMAP(T2)		;SAVE IT AWAY
	AOS	KSYCNT			;COUNT THE JOB

KSYJ.X:	SOJG	P1,KSYJ.1		;LOOP FOR ALL JOBS
	POPJ	P,			;AND RETURN
; Routine to do a special KSYS stream setup
; Call:	PUSHJ	P,KSYSET
;	  <NON-SKIP>			;NONE AVAILABLE RIGHT NOW
;	<SKIP>				;STREAM SETUP

KSYSET:	$SAVE	<P1,P2>			;SAVE P1 AND P2
	MOVE	P1,[-JOBMAX+KSYSTR,,KSYSTR] ;POINTER TO START OF KSYS STREAMS
	MOVE	P2,KSYCNT		;GET NUMBER IF JOBS TO KILL

KSYSE1:	SKIPL	G$STRM(P1)		;STREAM IN USE?
	JRST	KSYSE2			;YES--KEEP LOOKING
	HRRZ	S,P1			;GET STREAM NUMBER IN S
	MOVEM	S,G$STRM(S)		;SAVE IN TABLE
	MOVEI	S1,.JPAGS		;# PAGES NEEDED FOR THE DATA BASE
	$CALL	M%AQNP			;GET A PAGE FOR THE DATA BASE
	MOVEI	R,(S1)			;PUT THE PAGE NUMBER IN R
	PG2ADR	R			;CONVERT PAGE TO ADDRESS
	HRRZM	R,G$BASE(S)		;SAVE FOR THE DISPATCHER
	MOVEI	S1,.OTBAT		;OBJECT TYPE = BATCH STREAM
	MOVEM	S1,.JQOBJ+OBJ.TY(R)	;SAVE
	MOVE	S1,G$STRM(S)		;GET STREAM NUMBER
	MOVEM	S1,.JQOBJ+OBJ.UN(R)	;SAVE
	MOVE	S1,G$NODE		;GET BATCON'S NODE
	MOVEM	S1,.JQOBJ+OBJ.ND(R)	;SAVE
	AOS	KSYSSC			;COUNT THE STREAM SETUP
	$WTO	(<KSYS stream started>,,.JQOBJ(R))
;	MOVX	T1,%RSUOK		;GOOD RETURN FOR SETUP
;	SETZB	T2,T3			;CLEAR MESSAGE AND STATUS CODE
;	PUSHJ	P,SETUPR		;SEND SUCESSFUL SETUP MESSAGE TO QUASAR
	SOSLE	P2			;COUNT DOWN

KSYSE2:	AOBJN	P1,KSYSE1		;LOOP UNTIL ALL KSYS STREAMS SETUP
	POPJ	P,			;RETURN

; Routine to simply queue up the log file
KSYQUE:	$SAVE	<P1,P2>			;SAVE P1 AND P2
	$CALL	M%GPAG			;GET A PAGE FOR MESSAGE
	MOVE	P1,S1			;COPY TO A SAFE PLACE
	MOVEI	S1,.QOCQE		;MESSAGE TYPE IS SHORT CREATE
	STORE	S1,.MSTYP(P1),MS.TYP	;STORE IT
	MOVEI	P2,.OHDRS(P1)		;POINT TO EMPTY SLOT

; Queue type
	MOVE	S1,[2,,.QCQUE]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	MOVEI	S1,.OTLPT		;OBJECT TYPE LPT
	MOVEM	S1,ARG.DA(P2)		;SAVE
	ADDI	P2,2			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; Filespec
	MOVSI	S1,.JQLFD+ARG.DA(R)	;ADDRESS OF FD
	HRRI	S1,ARG.DA(P2)		;WHERE TO PUT IT
	BLT	S1,FDXSIZ-ARG.DA-1(P2)	;COPY FD
	MOVE	S1,[FDXSIZ-ARG.DA,,.QCFIL] ;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	HLRZS	S1			;GET BLOCK LENGTH
	ADDI	P2,(S1)			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; File format
	MOVE	S1,[2,,.QCPTP]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	MOVEI	S1,.FPFAS		;ASCII
	MOVEM	S1,ARG.DA(P2)		;SAVE
	ADDI	P2,2			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; Output disposition
	MOVE	S1,[2,,.QCODP]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	MOVEI	S1,%DELETE		;DELETE AFTER PRINTING
	MOVEM	S1,ARG.DA(P2)		;SAVE
	ADDI	P2,2			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; Account string
	MOVE	S1,[10,,.QCACT]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	MOVSI	S1,.JQACT(R)		;POINT TO ACCT STRING
	HRRI	S1,ARG.DA(P2)		;WHERE TO PUT IT
	BLT	S1,ARG.DA+10-1(P2)	;COPY
	ADDI	P2,10			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; User name
	MOVE	S1,[3,,.QCNAM]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	DMOVE	S1,.JQJBB+JIB.NM(R)	;GET TWO WORDS
	DMOVEM	S1,ARG.DA(P2)		;SAVE
	ADDI	P2,3			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; PPN
	MOVE	S1,[2,,.QCOID]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	MOVE	S1,.JQPPN(R)		;GET THE PPN
	MOVEM	S1,ARG.DA(P2)		;SAVE
	ADDI	P2,2			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; Job name
	MOVE	S1,[2,,.QCJBN]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	MOVE	S1,['KSYS  ']		;GET OBVIOUS NAME
	MOVEM	S1,ARG.DA(P2)		;SAVE
	ADDI	P2,2			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; Note
	MOVE	S1,[3,,.QCNTE]		;LENGTH,,BLOCK TYPE
	MOVEM	S1,ARG.HD(P2)		;SAVE
	MOVE	S1,['LOGOUT']		;WORD 1
	MOVE	S2,[' ERROR']		;WORD 2
	DMOVEM	S1,ARG.DA(P2)		;SAVE
	ADDI	P2,3			;ADVANCE
	AOS	.OARGC(P1)		;COUNT ARGUMENTS

; Finish up
	MOVEI	S1,(P2)			;GET LAST FREE ADDR IN MESSAGE
	SUBI	S1,(P1)			;COMPUTE LENGTH
	STORE	S1,.MSTYP(P1),MS.CNT	;STORE IN MESSAGE
	MOVEM	P1,G$SAB+SAB.MS		;STORE PAGE ADDRESS
	MOVEI	S1,PAGSIZ		;GET THE MESSAGE SIZE
	STORE	S1,G$SAB+SAB.LN		;STORE IT
	MOVEI	S1,SAB.SZ		;GET SAB SIZE
	MOVEI	S2,G$SAB		;GET SAB ADDRESS
	$CALL	C%SEND			;SEND MESSAGE TO QUASAR
	JUMPT	.POPJ			;RETURN IF NO ERRORS
	MOVE	S1,G$SAB+SAB.MS		;ELSE GET BACK PAGE ADDRESS
	$CALL	M%RPAG			;DESTROY THE PAGE
	$WTO	(<BATCON error>,<^I/KSYQTX/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	POPJ	P,			;AND RETURN

KSYQTX:	ITEXT	(<Can't spool KSYS log file: ^F/.JQLFD(R)/>)

> ;END TOPS-10 CONDITIONAL
SUBTTL	IPCF/Operator/QUASAR interface -- ORION message #200004 (PAUSE)


PAUSE:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	SETZ	S1,			;CLEAR AC
	TXNE	R,RL.STP		;ALREADY STOPPED?
	MOVEI	S1,[ASCIZ |Already stopped|] ;YES
	TXNE	R,RL.LGI		;LOGGING IN
	MOVEI	S1,[ASCIZ |Logging in|]	;YES
	TXNE	R,RL.KJB		;LOGGING OUT?
	MOVEI	S1,[ASCIZ |Logging out|] ;YES
	JUMPE	S1,PAUS.1		;CHECK FOR ERRORS
	$ACK	(<^T/(S1)/>,,<.JQOBJ(R)>,<.MSCOD(P1)>) ;COMPLAIN
	POPJ	P,			;RETURN

PAUS.1:	MOVEI	S1,[ASCIZ |STOP|]	;MESSAGE NAME
	MOVEI	S2,STOPJB		;PROCESSOR ADDRESS
	PUSHJ	P,B$IMSG		;SET UP OPERATOR/QUASAR MESSAGE
	  POPJ	P,			;ONE ALREADY THERE - RETURN
	MOVX	S1,B.STCN!B.DEFR	;GET SOME FLAGS
	IORM	S1,.JOFLG(R)		;STORE IT
	$ACK	(<Stop request queued>,,<.JQOBJ(R)>,.MSCOD(P1))
	POPJ	P,			;RETURN


; Routine executed in stream context to stop the job.
;
STOPJB:	TXO	F,FL.SCC		;SEND ^C TO STOP THE JOB
	PUSHJ	P,P$STOP##		;PUT AT MONITOR LEVEL
	$IDENT	(OPERAT,<[Job stopped by the operator]>)
	SETOM	.JLTIM(R)		;MARK TIME STAMP NEEDED
	MOVX	T1,%STOPD		;GET STOPPED CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	$WTOJ	(<Stopped>,<^R/.JQJBB(R)/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	TXO	R,RL.STP		;STREAM STOPPED
	TXZ	R,RL.MIP		;CLEAR MESSAGE IN PROGRESS
	SETZM	.JOVAL(R)		;CLEAR VALID MESSAGE FLAG
	JRST	QTS			;WAIT FOR CONTINUE
SUBTTL	IPCF/Operator/QUASAR interface -- ORION message #200005 (CONTINUE)


CONTIN:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	TXNE	R,RL.STP		;JOB STOPPED?
	JRST	CONT.1			;YES
	$ACK	(<Not stopped>,,<.JQOBJ(R)>,<.MSCOD(P1)>) ;COMPLAIN
	POPJ	P,			;RETURN

CONT.1:	MOVEI	S1,[ASCIZ |CONTINUE|]	;MESSAGE NAME
	MOVEI	S2,CONTJB		;PROCESSOR ADDRESS
	PUSHJ	P,B$IMSG		;SET UP OPERATOR/QUASAR MESSAGE
	  POPJ	P,			;ONE ALREADY THERE - RETURN
	MOVX	S1,B.STCN!B.DEFR	;GET SOME FLAGS
	IORM	S1,.JOFLG(R)		;STORE IT
	POPJ	P,			;RETURN


; Routine executed in stream context to continue the job.
;
CONTJB:	TXZE	R,RL.STP		;SHOULE WE CONTINUE JOB?
	TXNN	F,FL.SCC		;SENT ^C TO JOB?
	JRST	CONTJ1			;NO TO EITHER
	$IDENT	(OPERAT,<[Job continued by the operator]>)
	PUSHJ	P,L$LSTP##		;PUT A TIME STAMP IN THE LOG FILE
	MOVX	S1,MONCHR		;GET THE MONITOR PROMPT CHARACTER
	PUSHJ	P,L$OUTC##		;LOG IT
	PUSHJ	P,B$CINI		;SET UP THE COMMAND BUFFER
	$TEXT	(B$CPUT,<CONTINUE^M>)	;CONTINUE THE JOB
	PUSHJ	P,B$SETB		;RESET THE BYTE POINTER
	PUSHJ	P,B$XFER		;TRANSFER THE LINE TO THE PTY

CONTJ1:	MOVX	T1,%RESET		;GET NORMAL OPERATION CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	$ACK	(<Continued>,,<.JQOBJ(R)>,<.JOMSG+.MSCOD(R)>)
	TXZ	R,RL.MIP		;CLEAR MESSAGE IN PROGRESS
	SETZM	.JOVAL(R)		;CLEAR VALID MESSAGE FLAG
	JRST	QTS			;CONTEXT SWITCH INCASE IN OPERATOR WAIT
SUBTTL	IPCF/Operator/QUASAR interface -- ORION message #200012 (RESPONSE)


RESPON:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	MOVE	S1,.MSCOD(P1)		;GET ACK CODE (STREAM ITN)
	MOVEI	S,0			;CLEAR STREAM INDEX

RESP.1:	SKIPL	R,G$BASE(S)		;GET STREAM RELOCATION
	JRST	RESP.2			;NOT SETUP
	CAMN	S1,.JOACK(R)		;CHECK THE ACK CODE
	JRST	RESP.3			;FOUND IT

RESP.2:	CAMGE	S,G$HACT		;CHECKED ALL STREAMS YET?
	AOJA	S,RESP.1		;NO - LOOP
	POPJ	P,			;RETURN

RESP.3:	SETZM	.JOACK(R)		;CLEAR ACK CODE
	TXZN	R,RL.OPR!RL.DIA		;CLEAR OPR RESPONSE WAIT, DIALOGUE MODE
	POPJ	P,			;NOT WAITING
	MOVE	S1,P1			;POINT TO MESSAGE
	PUSHJ	P,B$SBLK		;SETUP FOR BLOCK PARSING

RESP.4:	PUSHJ	P,B$GBLK		;GET A BLOCK
	  POPJ	P,			;CAN'T
	CAIE	T1,.CMTXT		;LOOKING FOR TEXT
	JRST	RESP.4			;TRY ANOTHER
	HRLZ	S1,T3			;GET ADDRESS OF TEXT
	HRRI	S1,.JORSP(R)		;WANT IT TO GO HERE
	MOVE	S2,T2			;GET SIZE OF BLOCK
	CAILE	S2,<RSPSIZ/5>+1		;WILL IT FIT IN THE BUFFER?
	MOVEI	S2,<RSPSIZ/5>+1		;NO - TAKE ONLY WHAT WE CAN HANDLE
	ADDI	S2,.JORSP(R)		;COMPUTE END ADDRESS
	BLT	S1,-1(S2)		;COPY TEXT
	MOVEM	R,G$BASE(S)		;RESTORE R
	POPJ	P,			;RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- ORION message #200025 (REQUEUE)


REQUE:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	MOVEI	S1,[ASCIZ |REQUEUE|]	;MESSAGE NAME
	MOVEI	S2,REQJOB		;PROCESSOR ADDRESS
	PUSHJ	P,B$IMSG		;SET UP OPERATOR/QUASAR MESSAGE
	  POPJ	P,			;ONE ALREADY THERE - RETURN
	MOVX	S1,B.DEFR		;GET DEFERRED FLAG
	IORM	S1,.JOFLG(R)		;STORE IT
	MOVX	T1,%REQUE		;GET REQUEUE CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	$ACK	(<Requeue request queued>,,<.JQOBJ(R)>,.MSCOD(P1))
	POPJ	P,			;RETURN


; Routine executed in stream context to requeue the job.
;
REQJOB:	TXO	R,RL.REQ		;MARK JOB AS REQUEUED
	MOVEI	P1,[ASCIZ |No reason given|] ;DEFAULT REASON
	MOVEI	S1,.JOMSG(R)		;GET MESSAGE ADDRESS
	PUSHJ	P,B$SBLK		;SET UP BLOCK STUFF

REQJ.1:	PUSHJ	P,B$GBLK		;GET A BLOCK
	  JRST	REQJ.2			;NO MORE
	CAIE	T1,.ORREA		;REASON FIELD
	JRST	REQJ.1			;NO - KEEP LOOKING
	MOVE	P1,T3			;GET ADDRESS OF REASON
	JRST	REQJ.1			;CHECK NEXT ARGUMENT

REQJ.2:	$IDENT	(OPERAT,<[Job requeued by the operator]>)
	MOVE	S1,[$IDENT (OPERAT,<; ^A>)] ;GET INSTRUCTION TO STAMP LINE
	MOVE	S2,P1			;GET BYTE POINTER
	PUSHJ	P,L$COPY##		;COPY TEXT INTO THE LOG FILE
	PUSHJ	P,L$CRLF##		;ADD A CRLF
	MOVX	S1,RQ.HBO		;HELD BY OPERATOR FOR REQUEUE
	MOVEM	S1,.JBRQF(R)		;SAVE REQUEUE FLAG WORD
	MOVX	S1,<BA.ORQ!BA.JOB>	;OPERATOR REQUEUE
	IORM	S1,.JBCRQ(R)		;SAVE IN CHECKPOINT WORDS
	PJRST	B$CLOS			;DISMISS JOB
SUBTTL	IPCF/Operator/QUASAR interface -- ORION message #200026 (CANCEL)


CANCEL:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	MOVEI	S1,[ASCIZ |ABORT|]	;MESSAGE NAME
	MOVEI	S2,CANJOB		;PROCESSOR ADDRESS
	PUSHJ	P,B$IMSG		;SET UP OPERATOR/QUASAR MESSAGE
	  POPJ	P,			;ONE ALREADY THERE - RETURN
	MOVX	S1,B.DEFR		;GET DEFERRED FLAG
	IORM	S1,.JOFLG(R)		;STORE IT
	MOVX	T1,%CNCLG		;GET CANCEL CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	$ACK	(<Abort request queued>,,<.JQOBJ(R)>,.MSCOD(P1))
	POPJ	P,			;RETURN


; Routine executed in stream context to cancel the job.
;
CANJOB:	PUSHJ	P,P$STOP##		;^C THE PTY
	MOVX	P1,.CNERR		;DEFAULT TO ERROR PROCESSING
	MOVEI	P2,[ASCIZ |No reason given|] ;DEFAULT REASON
	MOVEI	S1,.JOMSG(R)		;GET MESSAGE ADDRESS
	PUSHJ	P,B$SBLK		;SET UP BLOCK STUFF

CANJ.1:	PUSHJ	P,B$GBLK		;GET A BLOCK
	  JRST	CANJ.2			;NO MORE
	CAIN	T1,.CANTY		;TYPE FIELD
	JRST	CANJ.5			;YES..PROCESS TYPE
	CAIN	T1,.ORREA		;REASON FIELD
	JRST	CANJ.6			;YES..SETUP POINTER
	JRST	CANJ.1			;KEEP LOOKING

CANJ.2:	HRRZ	S1,CANCTB-1(P1)		;GET THE TEXT FOR ERROR TYPE
	$IDENT	(OPERAT,<? Job aborted by the operator (^T/(S1)/)>)
	MOVE	S1,[$IDENT (OPERAT,<; ^A>)] ;GET INSTRUCTION TO STAMP LINE
	MOVE	S2,P2			;GET BYTE POINTER
	PUSHJ	P,L$COPY##		;COPY TEXT INTO THE LOG FILE
	PUSHJ	P,L$CRLF##		;ADD A CRLF
	TXO	F,FL.TXT		;MESSAGE TEXT AVAILABLE
	$TEXT	(<-1,,.JWTOP(R)>,<Job aborted by the operator; ^T/(P2)/^0>)
	TXZ	R,RL.JIE!RL.FLS		;CLEAR JOB IN ERROR AND FLUSH JOB
	CAIE	P1,.CNERR		;/ERROR?
	JRST	CANJ.3			;NO
	TXZ	R,RL.MSP!RL.MIP		;CLEAR MESSAGE FLAGS
	SETZM	.JOVAL(R)		;CLEAR VALID MESSAGE INDICATOR
	TXO	R,RL.JIE		;SET JOB IN ERROR
	MOVX	T1,%RESET		;GET NEW STATUS
	PUSHJ	P,B$UPDA		;TELL QUASAR
	POPJ	P,			;AND RETURN TO NORMAL JOB LOOP

CANJ.3:	CAIE	P1,.CNNER		;/NOERROR?
	JRST	CANJ.4			;NO
	TXO	R,RL.FLS		;SET FLUSH JOB BIT
	TXZA	F,FL.UHE		;CLEAR UNHANDLED ERROR CONDITION

CANJ.4:	TXO	F,FL.UHE		;/PURGE - SET UNHANDLED ERROR CONDITION
	JRST	B$CLOS			;DISMISS THE JOB
; Process disposition type
;
CANJ.5:	SKIPLE	P1,(T3)			;GET DISPOSITION TYPE
	CAILE	P1,.CNPRG		;IS IT WITHIN RANGE?
	MOVEI	P1,.CNERR		;ASSUME ERROR PROCESSING
	JRST	CANJ.1			;CHECK NEXT ARGUMENT


; Process /REASON
;
CANJ.6:	MOVE	P2,T3			;GET ADDRESS OF REASON
	JRST	CANJ.1			;CHECK NEXT ARGUMENT


; Table of cancel options and flags
;
CANCTB:	EXP	[ASCIZ/with error processing/]
	EXP	[ASCIZ/with no error processing/]
	EXP	[ASCIZ/purged/]
SUBTTL	IPCF/Operator/QUASAR interface -- ORION message #200035 (SEND)


SEND:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	PUSHJ	P,B$GBLK		;FIND A BLOCK
	  JRST	SEND.1			;CAN'T
	CAIE	T1,.CMTXT		;IS IT TEXT?
	  JRST	SEND.1			;NO
	MOVE	P2,T3			;COPY TO A SAFER PLACE
	HRLI	P2,(POINT 7,)		;MAKE A BYTE POINTER

SEND.1:	ILDB	S1,P2			;GET A CHARACTER, < (MATCH BRACKETS)
	JUMPE	S1,SEND.E		;END OF TEXT - BAD MESSAGE
	CAIE	S1,">"			;END OF JUNK?
	JRST	SEND.1			;NO - KEEP LOOKING
	$IDENT	(OPERAT,<[Message from operator]>) ;IDENTIFY LINE
	MOVE	S1,[$IDENT (OPERAT,<; ^A>)] ;GET INSTRUCTION TO STAMP LINE
	MOVE	S2,P2			;GET BYTE POINTER
	PUSHJ	P,L$COPY##		;COPY TEXT INTO THE LOG FILE
	MOVE	S1,[$IDENT (OPERAT,<[End of operator message]>)]
	MOVE	S2,[POINT 7,[BYTE (7) .CHCRT,.CHLFD,0,0,0]]
	PUSHJ	P,L$COPY		;PUT IN LOG FILE
	SETOM	.JLTIM(R)		;SAY WE NEED TIME STAMP
	$ACK	(<Send completed>,,<.JQOBJ(R)>,.MSCOD(P1))
	POPJ	P,			;RETURN

SEND.E:	$ACK	(<BATCON error>,<Invalid SEND message from ORION>,<.JQOBJ(R)>,.MSCOD(P1))
	POPJ	P,			;RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- ORION message #200036 (EXAMINE)


EXAMIN:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	$CALL	M%GPAG			;GET A PAGE
	MOVE	P2,S1			;SAVE THE PAGE ADDRESS
	MOVEI	S1,WTOSIZ		;GET MESSAGE SPACE LEAVING ROOM FOR ACK
	MOVEM	S1,WTOCNT		;SAVE THE COUNT
	HRRI	S1,(P2)			;POINT TO THE PAGE
	HRLI	S1,(POINT 7,)		;MAKE BYTE POINTER
	MOVEM	S1,WTOPTR		;SAVE THE POINTER
	SKIPN	.JCIFN(R)		;IS THE CONTROL FILE OPEN?
	JRST	EXAME1			;NO,,EXIT WITH ERROR
	PUSHJ	P,B$GBLK		;FIND A BLOCK
	  JRST	EXAME4			;CAN'T
	CAIE	T1,.SHCLN		;IS IT /LINES?
	  JRST	EXAME4			;NO
	MOVE	P3,(T3)			;GET /LINES VALUE
	SUBI	P3,1			;ACCOUNT FOR THE IN-CORE COMMAND LINE
	PUSHJ	P,C$SPOS##		;SAVE POSITION OF CTL FILE
	$TEXT	(WTODAT,<*** Input from ^F/.JQCFD(R)/ ***^M^J^T/.JSCTL(R)/^A>)

EXAM.1:	MOVE	S1,.JCIFN(R)		;GET IFN
	$CALL	F%IBYT			;GET A BYTE
	JUMPF	EXAME2			;EXIT EXAMIN ERROR
	JUMPE	S2,EXAM.1		;SKIP NULLS
	MOVE	S1,S2			;PLACE NUMBER IN S1
	PUSHJ	P,WTODAT		;OUTPUT BYTE TO MESSAGE
	JUMPF	EXAME3			;ERROR ..TERMINATES MESSAGE
	CAIG	S2,.CHFFD		;CHECK IF GREATER THAN FF
	CAIGE	S2,.CHLFD		;CHECK IF LINE FEED
	JRST	EXAM.1			;NO GET NEXT CHARACTER
	SOJG	P3,EXAM.1		;WANT MORE...GO TO EXAM.1
EXAM.2:	PUSHJ	P,EXAMAC		;SEND AC AND MESSAGE TO ORION
EXAM.3:	PUSHJ	P,C$RPOS##		;REPOSITION THE CTL FILE
	$RETIT				;ALL DONE IF IT WORKED
	MOVE	S1,.JREGS+P(R)		;GET THE STREAM STACK
	PUSH	S1,[B$ABORT]		;WHERE TO RESUME EXECUTION
	MOVEM	S1,.JREGS+P(R)		;SAVE UPDATED STACK POINTER
	TXZ	R,RL.STP!RL.OPR!RL.NSC!RL.ACK ;CLEAR FLAGS WHICH WOULD PREVENT
	MOVEM	R,.JREGS+R(R)		; RUNNING THIS STREAM AT TOPLVL
	POPJ	P,			;RETURN, WILL ABORT IN STREAM CONTEXT

EXAME1:	$TEXT	(WTODAT,<Control file ^F/.JQCFD(R)/ not open^A>)
	PJRST	EXAMAC			;SEND AC TO ORION
EXAME2:	$TEXT	(WTODAT,<^M^J	*** End of File ***^A>)
	JRST	EXAM.2			;FINISH OUT EXAMIN COMMAND
EXAME3:	MOVEI	S1,^D15*5		;GET EXTRA ROOM
	MOVEM	S1,WTOCNT		;SAVE THE COUNT
	$TEXT	(WTODAT,<		*** End of Show Data Page ***^A>)
	JRST	EXAM.2			;SEND AND REPOSITION
EXAME4:	$TEXT	(WTODAT,<Invalid Show Control-File command>)
	JRST	EXAM.2			;FINISH OFF THE COMMAND

EXAMAC:	$ACK	(<Show control file>,<^I/JIBTXT/^T/(P2)/>,.JQOBJ(R),.MSCOD(P1),<$WTJBN(.JBJNO(R))>)
	MOVE	S1,P2			;GET THE PAGE
	$CALL	M%RPAG			;RELEASE THE PAGE
	POPJ	P,			;RETURN

WTODAT:	SOSG	WTOCNT			;DECREMENT COUNT
	$RETF				;ABORT AND RETURN
	IDPB	S1,WTOPTR		;DEPOSIT BYTE
	$RETT				;RETURN
SUBTTL	IPCF/Operator/QUASAR interface -- ACK message #700000


ACK:	MOVE	P1,G$MADR		;GET MESSAGE ADDRESS
	MOVX	S2,MF.NOM		;GET THE 'NO MESSAGE' BIT
	SKIPE	S1,.MSCOD(P1)		;GET ACK CODE (IF ANY)
	TDNN	S2,.MSFLG(P1)		;ALL GOOD ACKS HAVE THIS BIT SET
	JRST	ACKTXT			;MUST BE SOME JUNK TEXT ACK
	MOVEI	S,0			;CLEAR STREAM INDEX

ACK.1:	SKIPL	R,G$BASE(S)		;GET STREAM RELOCATION
	JRST	ACK.2			;NOT SETUP
	CAMN	S1,.JOACK(R)		;CHECK THE ACK CODE
	JRST	ACK.3			;FOUND IT

ACK.2:	CAMGE	S,G$HACT		;CHECKED ALL STREAMS YET?
	AOJA	S,ACK.1			;NO - LOOP
	POPJ	P,			;RETURN

ACK.3:	SETZM	.JOACK(R)		;CLEAR ACK CODE
	TXZ	R,RL.ACK		;CLEAR WAITING FOR ACK BIT
	MOVEM	R,G$BASE(S)		;UPDATE STREAM FLAGS
	POPJ	P,			;RETURN


; Text ACKs
;
ACKTXT:	MOVE	S1,G$MADR		;GET MESSAGE ADDRESS
	SKIPE	.OARGC(S1)		;QUASAR SNIFFING AROUND?
	$WTO(<BATCON Error>,<Unexpected text message - ^T/.OHDRS+ARG.DA(S1)/>)
	POPJ	P,			;RETURN
; Find new G$HACT stream
;
FHIACT:	PUSH	P,S			;SAVE THE CURRENT STREAM NUMBER
	SKIPL	G$BASE(S)		;IS STREAM ACTIVE?
	SOJG	S,.-1			;NO - TRY ANOTHER
	MOVEM	S,G$HACT		;STORE STREAM NUMBER OR -1
	POP	P,S			;RESTORE CURRENT STREAM NUMBER
	$RETT				;RETURN
SUBTTL	STPPRC - Batch step processor


STPPRC::SETZM	.JSSTP(R)		;CLEAR STEP LINE COUNTER
	SKIPN	.JBSPS(R)		;DOING ONLY A STEP HEADER SCAN?
	JRST	STPP.4			;NO - CALLED FROM JOB PROCESSOR
	PUSHJ	P,C$OPEN##		;OPEN THE CONTROL FILE
	PUSHJ	P,C$READ##		;READ THE FIRST LINE
	  JUMPF	CLOSJB			;EOF
	CAXN	S1,STPCHR		;IS IT THE MAGIC STEP HEADER CHARACTER?
	JRST	STPP.4			;YES

STPP.1:	PUSHJ	P,B$EOJ			;FORCE END OF HEADER PROCESSING
	JRST	CLOSJB			;DISMISS JOB

STPP.2:	TXNE	R,RL.JIE		;JOB IN ERROR?
	JRST	HDRERR			;YES - ABORT IT
	SKIPGE	.JSSTP(R)		;END OF STEP?
	JRST	HDRXIT			;YES

STPP.3:	PUSHJ	P,C$READ##		;READ A LINE FROM THE CONTROL FILE
	  JUMPF	CLOSJB			;END OF FILE
	CAIN	S1,.CHCRT		;BLANK LINE?
	JRST	STPP.3			;YES - IGNORE IT
	CAIE	S1,";"			;OLD STYLE COMMENT?
	CAIN	S1,"!"			;NEW STYLE COMMENT?
	JRST	STPP.4			;YES
	CAXE	S1,STPCHR		;STEP DELIMITER CHARACTER?
	JRST	HDRSSE			;ERROR - GO FINISH UP

STPP.4:	PUSHJ	P,C$STEP##		;PARSE PARAMETER LINES
	  JUMPF	HDRERR			;PARSE ERRORS
	JRST	STPP.2			;BACK FOR ANOTHER COMMAND


; Header syntax error
;
HDRSSE:	$IDENT	(HEADER,<^T/.JSCTL(R)/^A>) ;ECHO THE LINE IN ERROR
	$IDENT	(BATSSE,<? Step header syntax error>)


; Common header scan error code
;
HDRERR:	TXO	F,FL.UHE		;CALL IT AN UNHANDLED ERROR CONDITION
	TXO	R,RL.JIE		;JOB IN ERROR IF IT GOT THIS FAR
	PUSHJ	P,B$EOJ			;FORCE END OF HEADER PROCESSING 
	MOVE	S1,.JLSTP(R)		;GET $STEP LABEL
	CAMN	S1,[-1]			;WAS IT A SPECIAL $STEP ERROR?
	SETZM	.JLSTP(R)		;YES
	SKIPN	S1			;WAS $STEP LINE MISSING?
	$IDENT	(BATMSL,<? Missing $STEP line in header>)
	SOSLE	.JSSTP(R)		;ADJUST COUNT OF LINES PROCESSED
	$IDENT	(HEADER,<[^D/.JSSTP(R)/ lines processed in step ^W/.JLSTP(R)/ header]>)
	$IDENT	(BATBJC,<[Batch job canceled]>)


; Header scan exit
;
HDRXIT:	TXNN	R,RL.JIE		;JOB IN ERROR?
	SKIPE	.JBSPS(R)		;OR DOING ONLY A STEP HEADER SCAN?
	JRST	CLOSJB			;YES - DISMISS THE JOB
	POPJ	P,			;NO - RETURN TO JOB PROCESSOR
SUBTTL	JOBPRC - Process a Batch stream


; JOBPRC will do the following:
;	a) Open the control file
;	b) Open the log file
;	c) Put a header on the log file
;	d) LOGIN a job
;	e) Perform post LOGIN job setup
;	f) Initialize job processing
;	g) Enter job processor loop
;
JOBPRC:	PUSHJ	P,U$STJB##		;HANDLE SPECIAL STARTUP PROCESSING
	PUSHJ	P,C$FILE##		;FIX UP THE CTL FILESPEC
	MOVEI	T1,FILTX1		;ASSUME NORMAL BATCH JOB
	TXNE	F,FL.KST		;KSYS STREAM?
	MOVEI	T1,FILTX2		;YES
	$WTOJ	(<Begin>,<^I/JIBTXT/^I/(T1)/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	PUSHJ	P,L$HEAD##		;PREPARE A LOG FILE HEADER
	PUSHJ	P,L$OPEN##		;OPEN THE LOG FILE
	PUSHJ	P,C$OPEN##		;OPEN THE CONTROL FILE
	PUSHJ	P,CHKPNT		;CHECKPOINT JOB
	PUSHJ	P,LOGINJ		;LOGIN THE JOB
	PUSHJ	P,JOBINI		;INITIALIZE JOB PROCESSING
	TXNN	F,FL.KST		;KSYS STREAM?
	JRST	HONORJ			;ENTER JOB PROCESSING LOOP
	PJRST	B$CLOS			;YES--TERMINATE NOW

FILTX1:	ITEXT	(<Control file: ^F/.JQCFD(R)/^M^JLog file:     ^F/.JQLFD(R)/>)
FILTX2:	ITEXT	(<Log file:     ^F/.JQLFD(R)/>)


; Here to honor a job's input request
;
HONORJ:	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION
	TXNN	J,JL.UJA		;IS THE JOB STILL THERE?
	PJRST	B$GONE			;NO
	TXNE	R,RL.NLG		;LOG FILE OUTPUT ERROR?
	PUSHJ	P,L$IOER##		;YES
	TXNE	F,FL.TLE		;WAS TIME LIMIT EXCEEDED?
	PUSHJ	P,TIMERR		;YES - TRY TO GIVE MORE TIME
	TXNE	R,RL.DIA		;JOB IN DIALOGUE MODE?
	PUSHJ	P,REDOPR		;YES
	PUSHJ	P,U$HNRJ##		;PROCESS SPECIAL CUSTOMER CHECKING
	  JRST	B$CLOS			;DISMISS JOB IF ERROR OCCURS
	TXZE	F,FL.RCL		;RE-EAT COMMAND LINE?
	  JRST	HONOR1			;YES
	PUSHJ	P,C$READ##		;NO - READ A LINE FROM THE CONTROL FILE
	  JUMPF	CLOSJB			;END OF FILE?
HONOR1:	PUSHJ	P,C$SCAN##		;SCAN AND PROCESS A COMMAND
	JRST	HONORJ			;LOOP
SUBTTL	BATCON initialization -- System independant code


B$INIT:	MOVE	S1,[PUSHJ P,UUOCON]	;LOCAL UUO HANDLER
	MOVEM	S1,.JB41##		;SET IT UP
	SETOM	G$STRM			;SET UP STREAM INDEX BLOCK
	MOVX	S1,<G$STRM,,G$STRM+1>	; BY PUTTING -1 IN EACH WORD
	BLT	S1,G$STRM+JOBMAX-1	;  TO INDICATE STREAM NOT IN USE
	MOVX	S1,INPCOR		;GET CORE FLAG
	MOVEM	S1,G$CORE		;REMEMBER FOR LATER
	SETZM	G$MDA			;ASSUME NO MDA SUPPORT
	$CALL	L%CLST			;CREATE A LINKED LIST
	MOVEM	S1,CLKQUE		; FOR THE CLOCK REQUEST QUEUE
	$CALL	.CPUTY			;GET CPU TYPE
	MOVEM	S1,G$CPU		;SAVE IT

; Get our node number
	SETO	S1,			;-1 MEANS US
	MOVX	S2,JI.LOC		;FUNCTION CODE
	$CALL	I%JINF			;GET OUR NODE NUMBER
	MOVEM	S2,G$NODE		;STORE IT
	PUSHJ	P,SYSINI		;DO SYSTEM DEPENDANT INITIALIZATION

; Greet QUASAR
	PUSHJ	P,HELLO			;GREET QUASAR
	MOVEI	S1,REENTER		;GET REENTER ADDRESS
	MOVEM	S1,.JBREN##		;SET IT UP
	POPJ	P,			;RETURN
SUBTTL	BATCON initialization -- TOPS-10 code


; TOPS-10 initialization
;
TOPS10	<				;TOPS-10 ONLY
SYSINI:	SETO	S1,			;-1 MEANS US
	WAKE	S1,			;THIS GUARANTEES US A OUR FIRST WAKE UP
	  JFCL				;WON'T FAIL
	MOVE	S1,[%LDFFA]		;GET OPERATOR PPN
	GETTAB	S1,			;FROM THE MONITOR
	  MOVE	S1,[1,,2]		;DEFAULT
	MOVEM	S1,OPRPPN		;SAVE
	MOVE	S1,[%LDQUE]		;GET QUEUE PPN
	GETTAB	S1,			;FROM THE MONITOR
	  MOVE	S1,[3,,3]		;DEFAULT TO THE USUAL
	MOVEM	S1,G$SPLD		;STORE IT
	MOVE	S1,[%CNPTY]		;GET SYSTEM PTY CONFIGURATION
	GETTAB	S1,			;FROM THE MONITOR
	  SETZ	S1,			;CAN'T
	HLRZM	S1,G$PTYF		;STORE FIRST PTY
	HRRZM	S1,G$PTYN		;STORE NUMBER OF PTYS

; Set up the interrupt system
	MOVX	S1,<VECTOR,,VECTOR+1>	;SET UP A BLT POINTER
	SETZM	VECTOR			;CLEAR THE FIRST WORD
	BLT	S1,ENDVEC		;CLEAR THE INTERRUPT DATA
	MOVEI	S1,IPCINT		;GET ADDRESS OF IPCF INTERRUPT ROUTINE
	MOVEM	S1,VECIPC+.PSVNP	;STORE IN VECTOR
	HRREI	T1,.PCIPC		;IPCF CONDITION CODE
	MOVSI	T2,<VECIPC-VECTOR>	;VECTOR OFFSET
	MOVSI	T3,IPCLVL		;GET IPCF PRIORITY LEVEL
	MOVX	S1,PS.FAC+T1		;FUNCTION CODE TO ADD THE CONDITION
	PISYS.	S1,			;ADD IT
	  $STOP	(CEI,<Can't enable interrupts>) ;++ CAN'T CONTINUE
	$CALL	I%ION			;TURN ON THE INTERRUPT SYSTEM
	MOVE	S1,[%CNST2]		;GET SECOND MONITOR STATES WORD
	GETTAB	S1,			;READ IT
	  SETZ	S1,			;CAN'T
	TXNE	S1,ST%MDA		;MONITOR SUPPORT MDA?
	SETOM	G$MDA			;YES
	HRROI	S1,.GTPPN		;GET OUR PPN
	GETTAB	S1,			;GET OUR PPN
	  JFCL				;CAN'T
	CAME	S1,[1,,2]		;ARE WE GODLY?
	SETZM	G$MDA			;NO - THEN NO MDA
	SKIPN	G$MDA			;ARE WE GONNA SUPPORT MDA?
	POPJ	P,			;NO - ALL DONE

SYSI.1:	MOVX	S1,SP.MDA		;GET SPECIAL PID INDEX
	$CALL	C%RPRM			;ASK THE LIBRARY FOR THE MDA PID
	JUMPT	.POPJ			;GOT IT
	MOVEI	S1,5			;5 SECONDS
	$CALL	I%SLP			;ZZZZZZ
	JRST	SYSI.1			;TRY AGAIN

>					;END OF TOPS-10 CONDITIONAL
SUBTTL	BATCON initialization -- TOPS-20 code


; TOPS-10 initialization
;
TOPS20	<				;TOPS-20 ONLY
SYSINI:	MOVX	S1,RC%EMO		;EXACT MATCH ONLY
	HRROI	S2,[ASCIZ |PS:[SPOOL]|]	;DIRECTORY NAME
	RCDIR				;GET THE DIRECTORY NUMBER
	MOVEM	T1,G$SPLD		;STORE IT
	MOVX	S1,'PTYPAR'		;GET SOME PTY PARAMETERS
	SYSGT				;FROM THE MONITOR
	HRRZM	S1,G$PTYF		;SAVE FIRST PTY NUMBER
	HLRZM	S1,G$PTYN		;SAVE THE NUMBER OF PTYS IN THE SYSTEM
	MOVX	S1,.MSIIC		;BYPASS MOUNT COUNTS
	MSTR				;DO THE FUNCTION
	  ERJMP	.+1			;IGNODE ERRORS
	MOVX	S1,.FHSLF		;GET OUR PROCESS HANDLE
	MOVEI	S2,104			;GET THE DESIRED QUEUE
	SPRIW				;SET PRIORITY WORD FOR OUR JOB
	  ERJMP	.+1			;IGNORE ERRORS

; Set up the interrupt system
	MOVEI	S1,INTRP1		;GET INTERRUPT LEVEL 1 PC
	MOVEM	S1,LEVTAB		;STORE IT
	MOVEI	S1,INTRP2		;GET INTERRUPT LEVEL 2 PC
	MOVEM	S1,LEVTAB+1		;STORE IT
	MOVEI	S1,INTRP3		;GET INTERRUPT LEVEL 3 PC
	MOVEM	S1,LEVTAB+2		;STORE IT
	MOVX	S1,<IPCLVL,,IPCINT>	;GET INTERRUPT LEVEL FOR IPCF
	MOVEM	S1,CHNTAB+IPCCHN	;SET UP CHANNEL
	MOVX	S1,<PTYLVL,,PTYINT>	;GET INTERRUPT LEVEL FOR PTYS
	MOVEM	S1,CHNTAB+PTYCHN	;SET UP CHANNEL
	MOVEM	S1,CHNTAB+PTYCHN+1	;PTYS NEED TWO
	CIS				;CLEAR INTERRUPT SYSTEM
	$CALL	I%ION			;TURN IT ON
	MOVX	S1,.FHSLF		;GET OUR PROCESS HANDLE
	MOVX	S2,INTMSK		;GET MASK OF CHANNELS TO ACTIVATE
	AIC				;ACTIVATE THOSE CHANNELS
	POPJ	P,			;RETURN

>					;END OF TOPS-20 CONDITIONAL
SUBTTL	Batch generated commands -- Buffer management


; Set up the byte pointer and byte count for Batch generated commands
;
B$CINI::MOVX	S1,CTLSIZ		;GET THE NUMBER OF CHARACTERS ALLOWED
	MOVEM	S1,.JSCTC(R)		;STORE IT
	HRLI	S1,.JSCTL(R)		;BUILD A BLT POINTER
	HRRI	S1,.JSCTL+1(R)		;TO CLEAR THE COMMAND BUFFER
	SETZM	.JSCTL(R)		;CLEAR THE FIRST WORD
	BLT	S1,.JSCTL+<CTLSIZ/5>(R)	;ZAP THE REMAINDER


; SET UP THE BYTE POINTER TO THE IN-CORE COMMAND BUFFER
;
B$SETB::MOVEM	S1,.JSCTB(R)		;SAVE S1
	MOVE	S1,[POINT 7,.JSCTL(R)]	;GET BYTE POINTER TO TEXT BUFFER
	EXCH	S1,.JSCTB(R)		;STORE IT AND RESTORE S1
	POPJ	P,			;RETURN SUCESSFUL


; Put a quoted character into the command buffer
;
B$CQUO::CAIN	S1,""""			;IS IT A DOUBLE QUOTE?
	PUSHJ	P,B$CPUT		;OUTPUT AN EXTRA - FALL INTO B$CPUT


; Put a character into the command buffer
;
B$CPUT::SOSG	.JSCTC(R)		;COUNT CHARACTERS
	  $RETF				;BUFFER FULL
	IDPB	S1,.JSCTB(R)		;STORE CHARACTER
	$RETT				;RETURN SUCESSFUL
; Transfer the contents of the command buffer pointed to by .JSCTB(R)
; to the PTY
;
B$XFER::ILDB	S1,.JSCTB(R)		;GET A CHARACTER
	JUMPE	S1,XFER.3		;DONE IF WE ENCOUNTER A <NUL>
	CAXE	S1,.CHCRT		;A CARRIAGE RETURN?
	JRST	XFER.1			;NOPE
	TXO	F,FL.CTP		;REMEMBER A <CR> SEEN
	TXZN	F,FL.SUP		;SUPRESS EOL CHARACTERS?
	JRST	XFER.1			;NO TO EITHER
	ILDB	S1,.JSCTB(R)		;EAT THE LINE FEED FOLLOWING <CR>

XFER.1:	CAXE	S1,.CHLFD		;END OF LINE?
	JRST	XFER.2			;YES - IGNORE <LF> AND FINISH UP
	TXZE	F,FL.CTP		;CARRIAGE RETURN PRECEED THE LINE FEED?
	JRST	XFER.3			;YES - IGNORE THE LINE FEED

XFER.2:	PUSHJ	P,P$OCHR##		;SEND CHARACTER TO THE PTY
	JRST	B$XFER			;LOOP UNTIL END OF LINE

XFER.3:	SETOM	.JPEOL(R)		;REMEMBER END OF LINE SENT
	TXO	F,FL.ECH		;GET READY FOR ECHO LINE
	PJRST	P$OBUF##		;FORCE OUT PTY BUFFERS AND RETURN
SUBTTL	Batch generated commands -- TOPS-10 Login


TOPS10	<				;TOPS-10 ONLY

; TOPS-10 Login
;
LOGINJ:	SETOM	.JLTIM(R)		;FORCE A TIME STAMP
	PUSHJ	P,P$CTLC##		;SEND A CONTROL-C
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION
	PUSHJ	P,P$TERM##		;SET UP PTY'S TERMINAL CHARACTERISTICS
	TXNE	F,FL.KST		;KSYS STREAM?
	JRST	ATTJOB			;YES--DO AN ATTACH INSTEAD
	PUSHJ	P,B$CINI		;SET UP THE COMMAND BUFFER
	$TEXT	(B$CPUT,<LOGIN ^A>)	;SEND LOGIN COMMAND
	MOVE	S1,.JQPPN(R)		;GET THE PPN
	SKIPN	.JQPAT(R)		;IS THERE ONE IN THE PATH SPEC?
	MOVEM	S1,.JQPAT(R)		;NO - PUT ONE THERE
	CAME	S1,.JQPAT(R)		;ARE THE PPNS THE SAME?
	$TEXT	(B$CPUT,<^O/.JQPPN(R),LHMASK/,^O/.JQPPN(R),RHMASK/ ^A>)
	$TEXT	(B$CPUT,<[^O/.JQPAT(R),LHMASK/,^O/.JQPAT(R),RHMASK/^A>)
	MOVEI	T1,.JQPAT+1(R)		;GET STARTING ADDRESS OF PATH
	HRLI	T1,-5			;SFD COUNTER
LGN1:	SKIPN	(T1)			;HAVE AN SFD?
	TDZA	T1,T1			;NO - END OF PATH
	$TEXT	(B$CPUT,<,^W/(T1)/^A>)	;SEND THE SFD
	AOBJN	T1,LGN1			;LOOP FOR ENTIRE PATH
	$TEXT	(B$CPUT,<] -^M^A>)	;TERMINATE PPN OR PATH
	PUSHJ	P,B$SETB		;RESET THE BYTE POINTER
	PUSHJ	P,B$XFER		;TRANSFER THE LINE TO THE PTY
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION AND RETURN
	PUSHJ	P,B$CINI		;SET UP THE COMMAND BUFFER

; Batch parameters
	$TEXT	(LGNCHR,</BATCH:(^A>)	;START BATCH SWITCHES
	GETLIM	T1,.JQLIM(R),OINT	;GET OPRINT VALUE
	CAIN	T1,.OPINN		;NO INTERVENTION?
	SKIPA	T1,['NO    ']		;YES - HE SAID NO
	HRLZI	T1,'YES'		;NO - HE SAID YES
	$TEXT	(LGNCHR,<INTERVENTION:^W/T1/,NAME:"^A>)
	$TEXT	(LGNQUO,<^W/.JQJBB+JIB.JN(R)/^A>)
	$TEXT	(LGNCHR,<",SEQUENCE:^D/.JQJBB+JIB.SQ(R),JB.SEQ/^A>)
	$TEXT	(LGNCHR,<,STREAM:^O/.JQOBJ+OBJ.UN(R)/^A>)
	$TEXT	(LGNCHR,<,REQUESTID:^D/.JQJBB+JIB.ID(R)/)^A>)

; Accounting parameters
	$TEXT	(LGNCHR,</ACCOUNT:"^A>)
	$TEXT	(LGNQUO,<^T/.JQACT(R)/^A>)
	$TEXT	(LGNCHR,<"/NAME:"^A>)
	$TEXT	(LGNQUO,<^W6/.JQJBB+JIB.NM(R)/^W/.JQJBB+JIB.NM+1(R)/^A>)
	MOVEI	S1,""""			;TERMINATE NAME STRING
	PUSHJ	P,LGNCHR		;TERMINATE COMMAND
; Job parameters
LGN2:	GETLIM	T1,.JQLIM(R),OPTN	;GET BATCH OPTION NAME
	SKIPE	T1			;HAVE ONE?
	$TEXT	(LGNCHR,</OPTION:^W/T1/^A>)
	GETLIM	T1,.JQLIM(R),CORE	;GET CORE LIMIT
	SKIPE	G$CORE			;CHECKING CORE LIMITS?
	$TEXT	(LGNCHR,</CORE:^D/T1/P^A>)
	GETLIM	T1,.JQLIM(R),TIME	;GET TIME LIMIT
	$TEXT	(LGNCHR,</DEFER/LOCATE:^O/.JQLOC(R)//SPOOL:ALL/TIME:^D/T1/^A>)
	PUSHJ	P,U$LOGI##		;APPEND SPECIAL CUSTOMER SWITCHES
	MOVEI	S1,.CHCRT		;GET A CARRIAGE RETURN
	PUSHJ	P,LGNCHR		;TERMINATE COMMAND
	PUSHJ	P,B$SETB		;RESET THE BYTE POINTER
	PUSHJ	P,B$XFER		;TRANSFER THE LINE TO THE PTY
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION AND RETURN
	JRST	LOGSET			;GO DO POST LOGIN SETUP

; Here to attach to the job
ATTJOB:	MOVE	S1,.JPTTY(R)		;GET PTY'S UDX
	ANDI	S1,UX.UNT		;KEEP JUST THE LINE NUMBER
	HRLZS	S1			;PUT IN LH
	HRR	S1,.JBJNO(R)		;GET JOB NUMBER
	TXO	S1,AT.UMM		;PUT IN MONITOR MODE
	ATTACH	S1,			;DO IT
	  PJRST	B$GONE			;TOO BAD
	$IDENT	(BATCH,<^7/[MONCHR]/ATTACH ^D/.JBJNO(R)/ ^P/.JQPPN(R)/>)
	MOVE	T1,['HALT  ']		;BE MEAN
	MOVE	T2,.JBJNO(R)		;GET JOB NUMBER
	MOVE	S1,[2,,T1]		;SET UP UUO AC
	FRCUUO	S1,			;STOP JOB
	  PUSHJ	P,P$CTLC##		;SEND A SINGLE CONTROL-C TO HALT JOB
	PUSHJ	P,IOWAIT		;EAT OUTPUT
	POPJ	P,			;RETURN
; TOPS-10 post LOGIN setup
;
LOGSET:	TXNE	J,JL.ULI		;IS A JOB LOGGED IN?
	TXNE	R,RL.JIE		;DID LOGIN FAIL?
	  PUSHJ	P,ANALYZ		;NOT LOGGED IN - ANALYZE THE ERROR
	PUSHJ	P,CHKPNT		;CHECKPOINT JOB
	PUSHJ	P,P$TERM##		;SET UP PTY'S TERMINAL CHARACTERISTICS
	PUSHJ	P,U$PLGN##		;DO SPECIAL POST-LOGIN PROCESSING
	  JRST	B$CLOS			;SOMETHING WRONG - DISMISS JOB
	POPJ	P,			;RETURN


; Special character sticker routines for LOGIN command line processing.
; These must be used instead of B$CPUT/B$CQUO to cause continuation line
; processing to happen.

LGNQUO:	CAIN	S1,""""			;DOUBLE QUOTE?
	PUSHJ	P,LGNCHR		;YES--OUTPUT TWO
LGNCHR:	PUSH	P,S1			;SAVE CHARACTER
	PUSH	P,S2			;SAVE JUNK
	MOVEI	S1,CTLSIZ+2		;BUFFER SIZE + "-" AND <CR>
	SUB	S1,.JSCTC(R)		;COMPUTE CHARACTERS STORED
	IDIVI	S1,^D80			;SEE HOW MANY CHARACTER ON LINE
	JUMPN	S2,LGNC.1		;TIME FOR A CONTINUATION LINE?
	MOVEI	S1,"-"			;CHARACTER
	PUSHJ	P,LGNC.2		;STORE
	MOVEI	S1,.CHCRT		;CARRIAGE RETURN
	PUSHJ	P,LGNC.2		;STORE
LGNC.1:	POP	P,S2			;RESTORE JUNK
	POP	P,S1			;RESTORE CHARACTER
LGNC.2:	SOSG	.JSCTC(R)		;COUNT CHARACTERS
	$RETF				;BUFFER FULL
	IDPB	S1,.JSCTB(R)		;STORE CHARACTER
	$RETT				;RETURN SUCESSFUL
>					;END OF TOPS-10 CONDITIONAL
SUBTTL	Batch generated commands -- TOPS-20 Login


TOPS20	<				;TOPS-20 ONLY

; TOPS-20 Login
;
LOGINJ:	SETOM	.JPEOL(R)		;FAKE OUT IN CASE OF PROBLEMS
	PUSHJ	P,P$CTLC##		;SEND A CONTROL-C
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION
	PUSHJ	P,P$TERM##		;SET UP PTY'S TERMINAL CHARACTERISTICS
	TXNE	R,RL.JIE		;JOB IN ERROR (? FULL)
	  PJRST	ANLY.2			;YES - REQUEUE THE JOB

LGN:	PUSHJ	P,B$CINI		;SET UP THE COMMAND BUFFER
	GETLIM	T1,.JQLIM(R),TIME	;GET TIME LIMIT
	$TEXT	(B$CPUT,<SET TIME-LIMIT ^D/T1/^M^A>)
	PUSHJ	P,B$SETB		;RESET THE BYTE POINTER
	PUSHJ	P,B$XFER		;TRANSFER THE LINE TO THE PTY
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION
	TXNE	R,RL.JIE		;JOB IN ERROR?
	   PUSHJ P,ANALYZ		;YES..ANALYZE THE ERROR
	PUSHJ	P,SETLOC		;SETUP LOCATION
	MOVE	S1,[POINT 7,.JQACT(R)]	;GET BYTE POINTER TO ACCT STRING

LGN1:	ILDB	S2,S1			;GET A CHARACTER
	JUMPE	S2,LGN2			;END OF STRING?
	CAIGE	S2,176			;RANGE CHECK
	CAIGE	S2," "			; IT FOR LEGALITY
	JRST	LGNERR			;NO GOOD
	JRST	LGN1			;LOOP

LGN2:	PUSHJ	P,B$CINI		;SET UP THE COMMAND BUFFER
	$TEXT	(B$CPUT,<LOGIN ^T/.JQNAM(R)/ FOO ^T/.JQACT(R)/^A>)
	PUSHJ	P,U$LOGI##		;APPEND SPECIAL CUSTOMER SWITCHES
	MOVX	S1,.CHCRT		;GET A CARRIAGE RETURN
	PUSHJ	P,B$CPUT		;TERMINATE COMMAND
	PUSHJ	P,B$SETB		;RESET THE BYTE POINTER
	PUSHJ	P,B$XFER		;TRANSFER THE LINE TO THE PTY
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION AND RETURN
	JRST	LOGSET			;DO POST LOGIN PROCESSING

LGNERR:	ANDI	S2,37			;MAKE SURE NO JUNK (SORRY RUBOUT)
	ADDI	S2,"@"			;MAKE IT READABLE
	$IDENT	(BATICA,<? ^I/LGNTXT/>)
	$WTOJ	(<Batch error>,<^R/.JQJBB(R)/^I/LGNTXT/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	JRST	B$ABORT			;DISMISS THE JOB

LGNTXT:	ITEXT	(<Illegal character "^^^7/S2/" in account string; job canceled>)
; TOPS-20 post LOGIN setup
; The following job parameters are set:
;	a) Mount count on connected directory's structure
;	b) CONNECT to requested directory
;	c) Batch stream number
;
LOGSET:	TXNE	J,JL.ULI		;IS A JOB LOGGED IN?
	TXNE	R,RL.JIE		;DID LOGIN FAIL?
	  PUSHJ	P,ANALYZ		;NOT LOGGED IN - ANALYZE THE ERROR
	PUSHJ	P,P$TERM##		;SET UP PTY'S TERMINAL CHARACTERISTICS
	TXO	R,RL.DRT		;DELAY THE RESPONSE BUFFER OUTPUT
	MOVX	S1,.MSIMC		;FUNCTION CODE TO INCREMENT MOUNT COUNT
	HRLI	S1,2			;2 WORD BLOCK
	MOVEI	S2,T1			;POINT TO BLOCK
	HRROI	T1,.JQCON(R)		;POINT TO THE CONNECTED DIRECTORY
	MOVE	T2,.JBJNO(R)		;GET THE JOB NUMBER
	MSTR				;CHANGE MOUNT COUNT
	  ERJMP	.+1			;IGNORE FOR NOW
	MOVX	S1,AC%CON+3		;FLAGS,,LENGTH IN 1
	MOVEI	S2,T1			;ADR IN 2
	HRROI	T1,.JQCON(R)		;ADR POINTS TO STR-DIR STRING
	HRROI	T2,[ASCIZ / /]		;ADR+1 POINTS TO PSW (DUMMY)
	HRRZ	T3,.JBJNO(R)		;ADR+2 POINTS TO JOB NUMBER
	ACCES				;CONNECT THE JOB
	  ERJMP	.+2			;DON'T WAIT IF IT FAILED
	PUSHJ	P,IOWAIT		;GET RESPONSE FROM ACCES JSYS
	HRRZ	S1,.JBJNO(R)		;GET THE JOB NUMBER
	MOVEI	S2,.SJDFS		;SET DEFAULT SPOOLING
	MOVEI	T1,.SJSPD		;A = S2 + 1, SET DEFERRED
	SETJB				;SET IT FOR THE JOB
	  ERJMP	.+1			;IGNORE THE ERROR..
	HRRZ	S1,.JBJNO(R)		;GET THE JOB NUMBER
	MOVEI	S2,.SJBAT		;SET BATCH INFO
	SETZM	T1			;CLEAR DATA WORD
	MOVE	T2,.JQOBJ+OBJ.UN(R)	;GET STREAM NUMBER
	STORE	T2,T1,OB%BSN		;SAVE BATCH STREAM NUMBER IN WORD
	TXO	T1,OB%BSS		;SET THE STREAM SET FLAG
	GETLIM	T2,.JQLIM(R),OINT	;GET THE OPERATOR INTERVENTION VALUE
	CAXE	T2,.OPINN		;WAS NO INTERVENTION SPECIFIED?
	JRST	LOGS.1			;NO - IGNORE THIS FUNCTION
	MOVX	T2,.OBNWR		;TURN OFF THE CAPABILITY
	STORE	T2,T1,OB%WTO		;STORE IN ARGUMENT BLOCK

LOGS.1:	SETJB				;SET BATCH PARAMETERS
	  ERJMP	.+1			;IGNORE ERRORS
	PUSHJ	P,U$PLGN##		;DO SPECIAL POST-LOGIN PROCESSING
	  JRST	B$CLOS			;SOMETHING WRONG - DISMISS JOB
	POPJ	P,			;RETURN

>					;END OF TOPS-20 CONDITIONAL
SUBTTL	Batch generated commands -- Kill a job


B$KJOB::TXNE	R,RL.DRT		;RESPONSE BUFFER OUTPUT DELAYED?
	PUSHJ	P,B$RTYO		;YES - DUMP IT NOW
	PUSHJ	P,P$STAT##		;GET JOB'S STATUS
	TXNN	J,JL.ULI		;IS JOB LOGGED IN?
	$RETT				;NO - RETURN
	TXNE	R,RL.FKJ		;FAST KJOB REQUESTED?
	$IDENT	(ABORT,<? Job aborted due to batch system shutdown>)
	TXZ	F,FL.SIL		;CLEAR SILENCE SO LOG FILE SHOWS ALL
	PUSHJ	P,P$STOP##		;PUT THE JOB IN MONITOR MODE
	PUSHJ	P,U$KJOB##		;DO ANY SPECIAL PRE-KJOB PROCESSING

KJOB.1:	PUSHJ	P,P$STOP##		;PUT THE JOB IN MONITOR MODE
	TXNN	J,JL.ULI		;IS THE JOB STILL THERE?
	$RETT				;NO - RETURN
	TXO	R,RL.KJB		;MARK ON THE WAY OUT

TOPS10	<				;TOPS-10 ONLY
	MOVEI	S1,""""			;GET A QUOTE
	MOVEM	S1,.JBOCH(R)		;SET AS DIALOGUE MODE SIGNAL
	MOVEI	S1,"?"			;GET A QUESTION MARK
	MOVEM	S1,.JBECH(R)		;SET AS ERROR CHARACTER
	PUSHJ	P,B$CINI		;SET UP THE COMMAND BUFFER
	$IDENT	(BATCH,<^7/[MONCHR]/KJOB/BATCH>) ;FAKE KJOB COMMAND IN THE LOG
	MOVE	TF,[2,,S1]		;SET UP UUO
	MOVE	S1,[SIXBIT/KJOB/]	;COMMAND TO FORCE
	MOVE	S2,.JBJNO(R)		;GET JOB NUMBER
	FRCUUO	TF,			;FORCE THE KJOB COMMAND
	  JFCL				;CAN'T
>					;END OF TOPS-10 CONDITIONAL

TOPS20	<				;TOPS-20 ONLY
	$IDENT	(BATCH,<^7/[MONCHR]/LOGOUT>) ;FAKE LOGOUT COMMAND IN THE LOG
	SETOM	.JLTIM(R)		;FORCE A TIME STAMP
	MOVE	S1,.JBJNO(R)		;GET THE JOB NUMBER
	LGOUT				;KILL THE JOB
	  JFCL				;IGNORE ERRORS FOR NOW
>					;END OF TOPS-20 CONDITIONAL

	MOVE	S1,G$CPU		;GET CPU TYPE
	MOVEI	T1,KJTIME		;GET KJOB TIME
	CAIN	S1,%KS10		;A SLOW MACHING?
	LSH	T1,1			;YES - MULTIPLY BY 2
	HRLI	T1,.CQLGO		;EVENT CODE IS LOGOUT
	MOVEI	T2,0			;NO DISPATCH
	PUSHJ	P,B$CLKS		;MAKE A CLOCK REQUEST
	PUSHJ	P,QTS			;WAIT A WHILE CUZ THE -20 IS SO SLOW

KJOB.2:	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION
	TXNN	R,RL.FKJ		;FAST KJOB?
	TXNN	J,JL.ULI		;DID THE JOB GO AWAY?
	POPJ	P,			;YES TO EITHER - RETURN
	MOVEI	S1,LGOTYP		;GET ADDRESS OF TYPE ITEXT BLOCK
	MOVEI	S2,LGOTXT		;GET ADDRESS OF MAIN ITEXT BLOCK
	MOVEI	T1,LGOTAB		;GET ADDRESS OF RESPONSE TABLE
	PUSHJ	P,B$OPER		;ASK THE OPERATOR FOR HELP
	JRST	KJOB.1			;SEE IF THE JOB IS STILL THERE
LGOTYP:	ITEXT (<Batch error>)

LGOTXT:	ITEXT	(<Unable to log out job ^D/.JBJNO(R)/.
Type 'RESPOND ^I/NUMBER/ PROCEED' to try again or kill the job>)

LGOTAB:	$STAB
	KEYTAB	(0,<PROCEED>)
	$ETAB
SUBTTL	Batch generated commands -- CLOSE/DUMP


; Check to see if CLOSE/DUMP commands are necessary
; *** Note ***
; This routine will not use B$CINI/B$XFER routines for sending the CLOSE/DUMP
; commands since this will destroy the contents of .JSCTL(R). .JSCTL(R) must
; be preserced for DUMP output.
;
B$DUMP::TXNN	R,RL.JIE		;JOB IN ERROR?
	POPJ	P,			;NO - JUST RETURN
	TXO	F,FL.UHE		;SET AN UNEXPECTED ERROR CONDITION
	TXNN	J,JL.ULI		;JOB LOGGED IN?
	POPJ	P,			;NO
	$IDENT	(BATCH,<^7/[MONCHR]/DUMP^A>) ;FAKE DUMP COMMAND IN THE LOG FILE
	PUSHJ	P,.DUMP##		;FORCE A DUMP BATCH COMMAND
	  JFCL				;IGNORE ERRORS
	PUSHJ	P,B$RTYO		;ECHO THE RESPONSE BUFFER
	PUSHJ	P,P$STOP##		;STOP THE JOB

TOPS10	<				;TOPS-10 ONLY
	PUSHJ	P,B$RTYO		;ECHO THE RESPONSE BUFFER
	$TEXT	(P$OCHR##,<CLOSE^M^A>)	;SEND THE CLOSE COMMAND
	PUSHJ	P,P$OBUF##		;FORCE OUT PTY BUFFERS
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION
	PUSHJ	P,P$STOP##		;MAKE SURE THE JOB IS STOPPED
>					;END OF TOPS-10 CONDITIONAL

	POPJ	P,			;RETURN
SUBTTL	Batch WTO/WTOR -- Initialization and character storage


; Initialize the WTO/WTOR buffer
;
B$WINI::MOVE	S1,[POINT 7,.JWTOP(R)]	;GET BYTE POINTER
	MOVEM	S1,.JWPTR(R)		;STORE IT
	MOVX	S1,CTLSIZ		;GET THE MAXIMUM NUMBER OF CHARACTERS
	MOVEM	S1,.JWCNT(R)		;STORE IT
	POPJ	P,			;RETURN


; Store a character in the WTO/WTOR buffer
;
B$WPUT::SOSLE	.JWCNT(R)		;COUNT CHARACTERS
	IDPB	S1,.JWPTR(R)		;DEPOSIT CHARACTER IF ROOM IN BUFFER
	POPJ	P,			;RETURN


; End WTO/WTOR buffer
;
B$WEOL::PUSH	P,S1			;SAVE S1
	MOVX	S1,.CHNUL		;GET A <NUL>
	IDPB	S1,.JWPTR(R)		;END THE LINE
	SETOM	.JWCNT(R)		;NO MORE ROOM IN BUFFER
	POP	P,S1			;RESTORE S1
	POPJ	P,			;RETURN
SUBTTL	Batch WTO/WTOR -- Write To OPR


; Write To OPR (WTO)
;
B$WTO::	PUSHJ	P,B$WEOL		;TERMINATE THE BUFFER
	$WTO	(<Message from batch user>,<^I/JIBTXT/^T/.JWTOP(R)/>,.JQOBJ(R),<$WTJBN(.JBJNO(R)),$WTNOD(.JQLOC(R))>)
	POPJ	P,			;RETURN


; Write To OPR with a Response (WTOR)
;
B$WTOR::PUSHJ	P,B$WEOL		;TERMINATE THE BUFFER
	MOVE	S1,.JQITN(R)		;GET OUR ITN
	MOVEM	S1,.JOACK(R)		;USE IT AS THE ACK CODE
	$WTOR	(<Message from batch user>,<^I/JIBTXT/^T/.JWTOP(R)/>,.JQOBJ(R),.JOACK(R),<$WTJBN(.JBJNO(R)),$WTNOD(.JQLOC(R))>)
	POPJ	P,			;RETURN
SUBTTL	Batch WTO/WTOR -- Get operator response to a WTOR


; Put job in operator wait and get response
;
B$WRSP::TXO	R,RL.OPR		;MARK WAITING FOR THE OPERATOR
	MOVX	T1,%OREWT		;STATUE CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	PUSHJ	P,QTS			;WAIT FOR OPERATOR RESPONSE
	MOVX	T1,%RESET		;RESET STATUS
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	SETZM	.JBCHK(R)		;FORCE A CHECKPOINT
	PUSHJ	P,P$STAT##		;GET THE JOB STATUS
	MOVE	T1,[POINT 7,.JORSP(R)]	;POINT TO RESPONSE BUFFER
	MOVE	S2,[POINT 7,.JWFOP(R)]	;BYTE POINTER TO DESTINATION

WRSP.1:	ILDB	S1,T1			;GET A CHARACTER
	IDPB	S1,S2			;PUT A CHARACTER
	CAME	S2,[POINT 7,.JWFOP+<CTLSIZ/5>(R),27] ;BUFFER FULL?
	JUMPN	S1,WRSP.1		;NO - LOOP UNLESS END OF TEXT

WRSP.2:	MOVEI	S1,.CHNUL		;END THE STRING
	IDPB	S1,S2			;STORE <NUL>
	POPJ	P,			;RETURN
SUBTTL	Response buffer support


; Store a character in the response buffer
;
B$RPUT::MOVE	S2,.JBRBP(R)		;GET BYTE POINTER
	CAME	S2,[POINT 7,.JBRSP+PTYBLK-3-1(R),27] ;BUFFER OVERFLOW?
	IDPB	S1,.JBRBP(R)		;NO - STORE CHARACTER
	POPJ	P,			;RETURN


; Mark EOL in response buffer
;
B$REOL::MOVEI	S1,.CHNUL		;GET A <NUL>
	IDPB	S1,.JBRBP(R)		;END RESPONSE BUFFER


; Reset response buffer byte pointer
;
B$RINI::MOVE	S1,[POINT 7,.JBRSP(R)]	;GET POINTER TO START OF BUFFER
	MOVEM	S1,.JBRBP(R)		;RESET BYTE POINTER
	POPJ	P,			;RETURN


; Output the response buffer to the log file
;
B$RTYO::TXNN	F,FL.SIL		;DON'T ECHO BUFFER IF SILENCE IN EFFECT
	$IDENT	(BATCH,<^T/.JBRSP(R)/^A>) ;IDENTITY AND ECHO RESPONSE BUFFER
	POPJ	P,			;RETURN
SUBTTL	Batch error handling -- Error, operator, dialogue, or quote checking


; This routine is called only when the first character in a line has been input.
; It will check for an error condition (either "?" or as set by the last ERROR
; command) or an operator signal (either a double quote or as set by the last
; OPERATOR command). In the case of an error, if (nnn) immediately follows the
; error character, nnn is stored in .JBECD(R) for later analysis.
;
B$ECHK::TXNE	J,JL.UNE		;IS THE PTY SET TO A NO ECHO STATE?
	TXZ	F,FL.ECH		;YES - READ WHAT WE THOUGHT WAS ECHO
	TXZE	F,FL.ECH		;IS THIS CHARACTER ECHO?
	POPJ	P,			;YES - THEN DON'T DO ANY CHECKING
	CAIE	S1,"?"			;IS IT THE STANDARD ERROR FLAG?
	  JRST	ECHK.1			;NO - LOOK FURTHER
	TXO	R,RL.JIE		;SET JOB IN ERROR BIT
	TXNN	R,RL.LGI		;LOGGING IN?
	TXNE	F,FL.UKJ		; OR USER REQUESTED KJOB?
	JRST	ECHK.1			;YES - SKIP TIME LIMIT EXCEEDED CHECK
	PUSHJ	P,GJTIML		;GET THE JOB'S REMAINING TIME LIMIT
	JUMPG	S2,ECHK.2		;TIME LIMIT EXCEEDED?
	TXOA	F,FL.TLE		;YES

ECHK.1:	TXNE	F,FL.NER		;IS NOERROR IN EFFECT?
	  JRST	ECHK.2			;YES - CHECK FOR OPERATOR CHARACTER
	CAMN	S1,.JBECH(R)		;OR USER ERROR CHARACTER ENCOUNTERED
	TXO	R,RL.JIE		;YES TO EITHER - MARK JOB IN ERROR

ECHK.2:	CAMN	S1,.JBOCH(R)		;WAS THE OPERATOR CHARACTER SEEN?
	TXO	R,RL.DIA		;YES - MARK DIALOGUE MODE
	CAIN	S1,""""			;Was a quote seen?
	TXO	R,RL.QTS		;YES - REMEMBER IT
	TXNE	F,FL.TLE		;WAS TIME LIMIT EXCEEDED?
	POPJ	P,			;YES - RETURN NOW
	TXNE	F,FL.NER		;IS NOERROR IN EFFECT?
	TXZ	R,RL.JIE		;YES - MAKE SURE JOB IN ERROR CLEARED
	TXNE	R,RL.JIE		;JOB IN ERROR?
	TXNN	R,RL.LGI		;AND WAS JOB LOGGING IN?
	POPJ	P,			;NO - JUST RETURN
	SKIPE	.JBECD(R)		;BEEN HERE BEFORE?
	POPJ	P,			;YES - THEN JUST RETURN

ECHK.3:	PUSHJ	P,L$PLOG##		;LOG THE ERROR CHARACTER
	PUSHJ	P,P$NXTC##		;GET THE NEXT CHARACTER
	CAIE	S1,"("			;START OF SPECIAL ERROR CODE?
	POPJ	P,			;NO - JUST RETURN

ECHK.4:	PUSHJ	P,L$PLOG##		;LOG THE CHARACTER
	PUSHJ	P,P$NXTC##		;GET THE NEXT CHARACTER
	CAIG	S1,"9"			;RANGE CHECK THE DIGIT
	CAIGE	S1,"0"			;0 THROUGH 9 ALLOWED
	  POPJ	P,			;NOT A DIGIT - EXIT LOOP
	MOVE	S2,.JBECD(R)		;GET THE ERROR CODE
	IMULI	S2,^D10			;SHIFT NUMBER
	ADDI	S2,-"0"(S1)		;ADD IN THIS DIGIT
	MOVEM	S2,.JBECD(R)		;REPLACE CODE
	JRST	ECHK.4			;LOOP FOR ANOTHER
SUBTTL	Batch error handling -- LOGIN error analysis


ANALYZ:	TXNE	J,JL.ULI		;IS THIS JOB LOGGED IN NOW?
	$RETT				;YES - THATS INCONSISTANT

TOPS10	<				;TOPS-10 ONLY
	SKIPLE	S1,.JBECD(R)		;GET THE ERROR CODE FROM LOGIN
	CAILE	S1,5			;WE ONLY KNOW ABOUT 1-5
	MOVEI	S1,5			;ASSUME RANDOM ERROR AND REQUEUE JOB
	JRST	@[ANLY.1		;(1) CANCEL JOB
		  ANLY.1		;(2) CANCEL JOB
		  ANLY.1		;(3) CANCEL JOB
		  ANLY.2		;(4) REQUEUE JOB AND SHUTDOWN STREAM
		  ANLY.3]-1(S1)		;(5) REQUEUE JOB
>					;END OF TOPS-10 CONDITIONAL

TOPS20	<				;TOPS-20 ONLY
	MOVX	S1,EQ.IAS		;GET THE INVALID ACCOUNT BIT
	TDNE	S1,.JQJBB+JIB.SQ(R)	;DID QUASAR SET IT?
	JRST	ANLY.1			;YES - CANCEL THE JOB
	JRST	ANLY.2			;NO - REQUEUE THE JOB
>					;END OF TOPS-20 CONDITIONAL


; Cancel job
;
ANLY.1:	$IDENT	(BATBJC,<? Batch job has been canceled - LOGIN failure>)
	$WTO	(<Batch error>,<LOGIN failed - job canceled>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	TXO	F,FL.UHE!FL.TXT		;CALL IT AN UNHANDLED ERROR CONDITION
	$TEXT	(<-1,,.JWTOP(R)>,<LOGIN failure^0>)
	JRST	B$ABOR			;ABORT THE JOB

; Requeue job and shutdown stream
;
ANLY.2:	$IDENT	(BATJRQ,<[Job requeued by BATCON]>)
	$WTO	(<Batch error>,<Cannot LOGIN jobs - job requeued>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	MOVX	T1,%RSUNA		;SET UP 'STREAM UNAVAILABLE'
	MOVEI	T2,E.NJOB		;NO JOBS AVAILABLE CODE
	MOVX	T3,%SFULL		;SYSTEM FULL
	TXO	R,RL.SHT		;LITE THE SHUTDOWN AT EOJ BIT
	PUSHJ	P,SETUPR		;SEND RESPONSE TO QUASAR
	JRST	B$CLOS			;DISMISS JOB


; Requeue job
;
ANLY.3:	$IDENT	(BATJRQ,<[Job requeued by BATCON]>)
	$WTO	(<Batch error>,<Requeue requested by LOGIN>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	TXO	R,RL.REQ		;MARK JOB AS BEING REQUEUED
	MOVEI	S1,REQTIM		;GET DEFAULT REQUEUE TIME
	STORE	S1,.JBRQF(R),RQ.TIM	;SAVE IT
	MOVEI	T1,%REQUE		;GET REQUEUE CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	JRST	B$CLOS			;DISMISS JOB
SUBTTL	MDA interface


; Get an MDA page if we don't already have one (S1:= page address)
;
B$MDAP::SKIPE	S1,.JMDAP(R)		;ALREADY HAVE A PAGE?
	POPJ	P,			;YES - JUST RETURN
	$CALL	M%GPAG			;GET A PAGE FOR MESSAGE
	MOVEM	S1,.JMDAP(R)		;STORE PAGE ADDRESS
	MOVX	S2,.QOPRM		;MESSAGE TYPE IS PRE-MOUNT
	STORE	S2,.MSTYP(S1),MS.TYP	;STORE IT
	MOVX	S2,.MMHSZ		;MESSAGE SIZE
	STORE	S2,.MSTYP(S1),MS.CNT	;STORE IT
	LOAD	S2,.JQJBB+JIB.ID(R)	;GET REQUEST ID
	STORE	S2,.OFLAG(S1),PR.RID	;STORE IT
	MOVEI	S2,.MMHSZ(S1)		;POINT TO EMPTY SLOT
	MOVEM	S2,.JMDAF(R)		;STORE FIRST FREE POINTER
	POPJ	P,			;RETURN


; Send any ALLOCATE/MOUNT requests to QUASAR
;
B$MDAR::PUSHJ	P,B$MDAP		;GET MDA PAGE IF NECESSADY
	MOVX	S2,PR.NON		;GET NOTHING IN MESSAGE BIT
	SKIPN	.MMARC(S1)		;ANYTHING ADDED TO THE BLOCK?
	IORM	S2,.OFLAG(S1)		;STORE BIT
	MOVEM	S1,G$SAB+SAB.MS		;STORE PAGE ADDRESS
	MOVX	S1,PAGSIZ		;GET THE MESSAGE SIZE
	STORE	S1,G$SAB+SAB.LN		;STORE IT
	MOVX	S1,SAB.SZ		;GET SAB SIZE
	MOVEI	S2,G$SAB		;GET SAB ADDRESS
	$CALL	C%SEND			;SEND MESSAGE TO QUASAR
	SKIPT				;MESSAGE SENT OK?
	$CALL	M%RPAG			;NO - DESTROY THE PAGE
	SETZM	.JMDAP(R)		;CLEAR PAGE NUMBER
	POPJ	P,			;RETURN SUCESSFUL
SUBTTL	MODIFY interface


; Get a MODIFY page if we don't already have one (S1:= page address)
;
B$MODP::SKIPE	S1,.JMODP(R)		;HAVE A MODIFY PAGE YET?
	POPJ	P,			;YES - RETURN WITH S1 SET UP
	$CALL	M%GPAG			;GET A PAGE FOR MESSAGE
	MOVEM	S1,.JMODP(R)		;STORE PAGE ADDRESS
	MOVX	S2,.QOMOD		;MESSAGE TYPE IS MODIFY QUEUE ENTRY
	STORE	S2,.MSTYP(S1),MS.TYP	;STORE IT
	MOVEI	S2,NMAJPM+NINPPM+MOD.SZ	;GET BLOCK LENGTH
	STORE 	S2,.MSTYP(S1),MS.CNT	;STORE IT
	MOVX	S2,.OTBAT		;OBJECT TYPE
	MOVEM	S2,MOD.OT(S1)		;STORE IT
	LOAD	S2,.JQJBB+JIB.ID(R)	;GET REQUEST ID
	STORE	S2,MOD.RQ+.RDBRQ(S1)	;STORE IT
	MOVEI	S1,MOD.FG(S1)		;POINT TO FIRST FREE WORD

	MOVE	S2,[.GPMAJ,,NMAJPM]	;SET UP GROUP MODIFY BLOCK
	MOVEM	S2,MOD.GN(S1)		;STORE MAJOR MODIFY HEADER
	SETOM	MOD.GE(S1)		;DEFAULT THE FIRST ENTRY
	HRLZI	S2,MOD.GE(S1)		;GET SOURCE ADDRESS
	HRRI	S2,MOD.GE+1(S1)		;GET DESTINATION ADDRESS
	BLT	S2,MOD.GE+NMAJPM(S1)	;SET THE WHOLE MESS TO -1
	ADDI	S1,NMAJPM		;POINT TO START OF NEXT BLOCK
	MOVE	S2,[.GPQUE,,NINPPM]	;SET UP GROUP MODIFY BLOCK
	MOVEM	S2,MOD.GN(S1)		;STORE QUEUE DEPENDANT MODIFY HEADER
	SETOM	MOD.GE(S1)		;DEFAULT THE FIRST ENTRY
	HRLZI	S2,MOD.GE(S1)		;GET SOURCE ADDRESS
	HRRI	S2,MOD.GE+1(S1)		;GET DESTINATION ADDRESS
	BLT	S2,MOD.GN+NINPPM-1(S1)	;SET TO -1
	MOVE	S1,.JMODP(R)		;RELOAD PAGE ADDRESS
	POPJ	P,			;RETURN


; Send MODIFY request to QUASAR
;
B$MODR::SKIPN	S1,.JMODP(R)		;GET MDA REQUEST PAGE
	$RETT				;NO MODIFY TO SEND
	SKIPN	.JMODC(R)		;ANY MODIFIES IN THIS REQUEST?
	JRST	MODR.1			;NO
	MOVEM	S1,G$SAB+SAB.MS		;STORE PAGE ADDRESS
	MOVX	S1,PAGSIZ		;GET THE MESSAGE SIZE
	STORE	S1,G$SAB+SAB.LN		;STORE IT
	MOVX	S1,SAB.SZ		;GET SAB SIZE
	MOVEI	S2,G$SAB		;GET SAB ADDRESS
	$CALL	C%SEND			;SEND MESSAGE TO QUASAR
	JUMPT	MODR.2			;ANY ERRORS?
	$WTO(<BATCON Error>,<MODIFY failed for request ^D/.JQJBB+JIB.ID(R)/>)

MODR.1:	MOVE	S1,.JMODP(R)		;GET PAGE NUMBER
	$CALL	M%RPAG			;DESTROY THE PAGE

MODR.2:	SETZM	.JMODP(R)		;CLEAR SO WE DON'T HAVE PROBLEMS LATER
	POPJ	P,			;AND RETURN
SUBTTL	End of job processing


; Here on end of job (step) header
;
B$EOJ::	TXOE	F,FL.EOJ		;PROCESS EOJ STUFF ALREADY?
	POPJ	P,			;YES - THEN JUST RETURN
	TXNN	R,RL.JIE		;IS THE JOB IN ERROR?
	SETOM	.JSSTP(R)		;NO - INDICATE END OF STEP
	SKIPN	.JBSPS(R)		;DOING ONLY STEP HEADER SCAN?
	POPJ	P,			;NO - RETURN
	PUSHJ	P,B$MODR		;PROCESS ANY MODIFY REQUESTS
	SKIPE	G$MDA			;MDA TURNED ON?
	PUSHJ	P,B$MDAR		;YES - SEND ANY MDA REQUESTS
	POPJ	P,			;RETURN
	SUBTTL	JOBINI - Initialize job processing


JOBINI:	TXNE	F,FL.KST		;KSYS STREAM?
	JRST	JOBI.K			;YES
	SETOM	.JSSPP(R)		;ALLOW US TO PROCESS ONLY 1 STEP
	TXZ	R,RL.LGI		;CLEAR LOGIN SEQUENCE NOW
	SKIPN	S1,.JBCRQ(R)		;IS THERE CHKPNT/REQUEUE INFORMATION?
	  JRST	JOBI.1			;NO - SEE IF RESTARTABLE
	TXNN	S1,BA.JOB		;BETTER BE SET
	JRST	JOBI.E			;ELSE WE'RE IN TROUBLE
	TXNE	S1,BA.ORQ!BA.URQ!BA.CHK	;ANY REQ OR CHKPNT
	  JRST	JOBI.2			;YES,,CHECK FOR CHECKPOINT RESTART
	GETLIM	S2,.JQLIM(R),REST 	;GET RESTART DATA
	CAIE	S2,%EQRNO		;IS IT RESTARTABLE
	   JRST	JOBI.2			;TREAT IT AS RESTARTABLE
					;USER MODIFIED AFTER CRASH
					; BUT BEFORE RESTART
	$IDENT	(BATJNR,<? Job canceled after a restart - it is not restartable^A>)
	$WTO	(<Batch error>,<Job canceled after a restart; it is not restartable>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	SETZM	.JBCHK(R)		;FORCE A CHECKPOINT
	TXO	F,FL.LSL		;LIST SKIPPED LINES
	PJRST	LABFIN##		;FIND %FIN AND CONTINUE FROM THERE

JOBI.1:	MOVX	S1,<BA.JOB>		;GET SEEN JOB FLAG
	IORM	S1,.JBCRQ(R)		;UPDATE FLAG WORD
	GETLIM	S2,.JQLIM(R),REST	;GET RESTART DATA
	CAIE	S2,%EQRNO		;IS IT RESTARTABLE
	  JRST	JOBI.2			;YES, GO GET STARTING POINT
	TXO	F,FL.CHK		;UPDATE CHECKPOINT

JOBI.2:	SETZM	.JBCHK(R)		;FORCE A CHECKPOINT
	PUSHJ	P,C$READ##		;READ A LINE FROM THE CONTROL FILE
	  JUMPF	CLOSJB			;END OF FILE?
	CAXE	S1,STPCHR		;START OF A STEP?
	JRST	JOBI.3			;NO - RESET TO BEGING OF FILE
	PUSHJ	P,STPPRC		;YES - CALL THE STEP HEADER PROCESSOR
	  JUMPF	CLOSJB			;ERRORS DURING SCAN?
	JRST	JOBI.4			;GO SEARCH FOR STARTING POINT

JOBI.3:	TXO	F,FL.RCL		;RE-EAT THE COMMAND LINE

JOBI.4:	PUSHJ	P,C$STRT##		;SEARCH FOR STARTING POINT IN CTL FILE
	POPJ	P,			;RETURN

JOBI.K:	$IDENT	(BATKSY,<[Beginning KSYS processing]^A>)
	POPJ	P,			;RETURN

JOBI.E:	$IDENT	(BATUJR,<? ^I/JOBTXT/>)
	$WTOJ	(<BATCON error>,<^R/.JQJBB(R)/^I/JOBTXT/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	JRST	B$ABORT			;DISMISS THE JOB

JOBTXT:	ITEXT	(<Unrecognized job restart type ^O/S1/; job canceled>)
SUBTTL	TIMERR - Time limit exceeded


; Here on time limit exceeded errors
;
TIMERR::TXON	F,FL.%XT		;EXTRA TIME ALREADY GIVEN?
	JRST	TIME.1			;NO
	$WTO	(<Batch error>,<^I/JIBTXT/^I/TIMTX0/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	$IDENT	(BATTLE,<? ^I/TIMTX0/>)	;MAKE A LOG ENTRY
	TXO	F,FL.TXT		;MESSAGE TEXT AVAILABLE
	$TEXT	(<-1,,.JWTOP(R)>,<Time limit exceeded^0>)
	JRST	B$ABOR			;ABORT THE JOB

TIME.1:	PUSHJ	P,C$READ##		;ADVANCE BEYOND LINE CAUSING THE ERROR
	PUSHJ	P,LABTER##		;SEARCH FOR LABEL %TERR
	PUSHJ	P,P$STOP##		;YES - PUT JOB IN MONITOR MODE
	TXZ	R,RL.JIE		;CLEAR ERROR CONDITION
	GETLIM	S2,.JQLIM(R),TIME	;GET TIME LIMIT
	IMULI	S2,%EXTRA		;COMPUTE EXTRA TIME TO BE GIVEN
	IDIVI	S2,^D100		;AS A PERCENTAGE OF THE ORIGINAL LIMIT
	CAIGE	S2,%EXTRA		;TOO MUCH?
	  MOVX	S2,%EXTRA		;YES - ADJUST IT
	PUSH	P,S2			;SAVE TIME
	MOVE	S1,S2			;COPY IT
	PUSHJ	P,B$STIM		;TRANSLATE TO READABLE TEXT
	POP	P,S2			;RESTORE TIME TO SET

TOPS10	<				;TOPS-10 ONLY
	MOVX	T1,<2,,S1>		;SET UP AC
	HRRZ	S1,J			;GET THE JOB NUMBER
	HRLI	S2,.STTLM		;FUNCTION TO SET TIME LIMIT
	JBSET.	T1,			;SET NEW TIME LIMIT
	JRST	TIME.E			;CAN'T
	JRST	TIME.2			;NO ERRORS
>					;END OF TOPS-10 CONDITIONAL

TOPS20	<				;TOPS-20 ONLY
	PUSH	P,S2			;SAVE TIME IN SECONDS
	PUSHJ	P,B$CINI		;SET UP THE COMMAND BUFFER
	$TEXT	(B$CPUT,<SET TIME-LIMIT ^D/S2/>) ;ISSUE COMMAND
	PUSHJ	P,B$SETB		;RESET THE BYTE POINTER
	PUSHJ	P,B$XFER		;TRANSFER THE LINE TO THE PTY
	PUSHJ	P,IOWAIT		;WAIT FOR I/O COMPLETION
	POP	P,S2			;RESTORE TIME
	TXNE	R,RL.JIE		;JOB IN ERROR?
	JRST	TIME.E			;YES
>					;END OF TOPS-20 CONDITIONAL

TIME.2:	$WTO	(<Batch error>,<^I/JIBTXT/^I/TIMTX2/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	$IDENT	(BATAXT,<[^I/TIMTX2/]>)	;MAKE A LOG ENTRY
	TXZ	F,FL.TLE		;CLEAR TIME LIMIT EXCEEDED CONDITION
	TXO	F,FL.RCL		;RE-EAT COMMAND LINE
	POPJ	P,			;RETURN


TIME.E:	$WTO	(<BATCON error>,<^I/JIBTXT/^T/TIMTX1/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	$IDENT	(BATCST,<? ^I/TIMTX1/>)	;MAKE LOG ENTRY
	JRST	B$ABOR			;ABORT JOB

TIMTX0:	ITEXT	(<Time limit exceeded after allowing extra time; job canceled>)
TIMTX1:	ITEXT	(<Cannot set time limit; job canceled>)
TIMTX2:	ITEXT	(<Time limit exceeded; allowing ^T/G$TMTX/ extra time>)
;HERE WHEN DIALOGUE MODE IS IN EFFECT, READ FROM THE OPERATOR

REDOPR:	PUSHJ	P,B$WTOR		;WRITE TO OPR AND WAIT FOR RESPONSE
	PUSHJ	P,B$WRSP		;GET THE OPERATOR RESPONSE
	TXNN	J,JL.UJA		;IS THE JOB STILL THERE?
	JRST	B$GONE			;NO
	TXNE	R,RL.DIA		;JOB STILL WAITING?
	  JRST	REDOPR			;YES - TRY AGAIN
	PUSH	P,F			;SAVE FLAGS IN CASE THE JOB IS SILENCED
	TXZ	F,FL.SIL		;CLEAR SILENCE SO LINES WILL GO TO LOG
	$IDENT	(OPERAT,<Operator response:^A>)
	PUSHJ	P,B$RTYO		;DUMP THE RESPONSE BUFFER
	MOVE	S2,[POINT 7,.JWFOP(R)]	;BYTE POINTER TO STRING
	SETZ	T1,			;CLEAR PREVIOUS CHARACTER SAVER

RDOPR1:	ILDB	S1,S2			;GET A CHARACTER
	JUMPE	S1,RDOPR2		;DONE IF ENCOUNTER A <NUL>
	CAXN	S1,.CHLFD		;A LINE FEED?
	CAXE	T1,.CHCRT		;PREVIOUS CHARACTER A CARRIAGE RETURN?
	PUSHJ	P,P$OCHR##		;SEND CHARACTER TO THE PTY
	MOVE	T1,S1			;SAVE AS PREVIOUS CHARACTER
	JRST	RDOPR1			;LOOP FOR ANOTHER

RDOPR2:	MOVX	S1,.CHCRT		;LOAD A CARRIAGE RETURN
	SKIPL	.JPEOL(R)		;END OF LINE YET?
	PUSHJ	P,P$OCHR##		;NO - FORCE ONE
	PUSHJ	P,P$OBUF##		;SEND THE TEXT TO THE PTY
	POP	P,S1			;RESTORE OLD F
	TXNE	S1,FL.SIL		;WAS SILENCE IN EFFECT?
	TXO	F,FL.SIL		;YES - SET IT AGAIN
	PUSHJ	P,P$OBUF##		;OUTPUT THE PTY BUFFER
	SETOM	.JPEOL(R)		;MARK EOL SENT
	TXO	F,FL.RCL		;RE-EAT THE COMMAND LINE
	POPJ	P,			;RETURN
SUBTTL	Stream termination -- Dismiss job


; Here to abort the job and update QUASAR
;
B$ABOR::SKIPE	.JBSPS(R)		;STEP HEADER SCAN PROCESSING ONLY?
	JRST	B$CLOS			;YES
	MOVEI	T1,%CNCLG		;GET CANCEL CODE
	PUSHJ	P,B$UPDA		;UPDATE QUASAR
	JRST	B$CLOS			;DISMISS THE JOB


; Here when the job disappears (probably some ATTACHed to it)
;
B$GONE::SKIPN	.JBSPS(R)		;STEP HEADER SCAN PROCESSING ONLY?
	TXNE	R,RL.LGI!RL.KJB		;LOGGING IN OR OUT?
	JRST	B$CLOS			;THEN IT COULD DISAPPEAR UNEXPECTEDLY
	TXNE	F,FL.UKJ		;USER REQUEST KJOB?
	JRST	B$CLOS			;YES
	$WTO	(<Batch error>,<^I/JIBTXT/^I/GONTXT/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	$IDENT	(BATNBC,<% ^I/GONTXT/>)	;LOG IT
	JRST	B$CLOS			;TERMINATE JOB

GONTXT:	ITEXT	(<Job ^D/.JBJNO(R)/ no longer under BATCON's control; job canceled>)


; Here to dismiss a job (release or requeue)
;
B$CLOS::
CLOSJB::PUSHJ	P,CHKPNT		;CHECKPOINT IF NECESSARY
	TXNE	R,RL.FKJ		;FAST KJOB?
	JRST	CLOS.0			;YES - DON'T TALK TO ANYONE
	SKIPE	.JOACK(R)		;A PENDING WTOR?
	$KWTOR	(.JOACK(R))		;KILL IT
	PUSHJ	P,B$EOJ			;PROCESS END OF JOB (STEP) HEADER

CLOS.0:	TXNN	J,JL.UJA		;IS A JOB REALLY THERE?
	  JRST	CLOS.1			;NO
	TXNE	R,RL.KJB		;WHAT ARE WE DOING HERE?
	  JRST	CLOS.2			;DON'T DO ANOTHER KJOB
	TXNN	R,RL.FKJ		;FAST KJOB?
	PUSHJ	P,B$DUMP		;NO - SEE IF A CLOSE/DUMP IS NEEDED
	PUSHJ	P,B$KJOB		;KILL THE JOB
	TXNE	F,FL.KST		;KSYS STREAM?
	TXNN	R,RL.JIE		;AND JOB IN ERROR?
	SKIPA				;NO TO EITHER
	AOS	KSYJLE			;COUNT THE ERROR

CLOS.1:	TXNE	R,RL.REQ		;JOB BEING REQUEUED?
	JRST	CLOS.2			;YES - DON'T DELETE CTL FILE
	SKIPE	.JBSPS(R)		;DOING ONLY STEP HEADER PROCESSING?
	JRST	CLOS.S			;YES
	TXNN	R,RL.FLS		;FLUSHING THE JOB?
	PUSHJ	P,C$DISP##		;DISPOSE OF THE CONTROL FILE (MAYBE)

CLOS.2:	PUSHJ	P,P$CLOS##		;CLOSE THE PTY
	PUSHJ	P,C$CLOS##		;CLOSE THE CONTROL FILE
	PUSHJ	P,L$CLOS##		;CLOSE THE LOG FILE
	PUSHJ	P,U$CLOS##		;DO ANY SPECIAL POST-KJOB PROCESSING
	TXNE	R,RL.FKJ		;FAST KJOB?
	JRST	CLOS.F			;YES - SKIP ALL OTHER STUFF
	TXNE	R,RL.REQ		;JOB BEING REQUEUED?
	JRST	CLOS.R			;YES - SEND REQUEUE MESSAGE
	PUSHJ	P,DELSPL		;DELETE SPOOLED FILES (TOPS-20 ONLY)
	PUSHJ	P,RELMSG		;BUILD RELEASE MESSAGE

CLOS.5:	$WTOJ	(<End>,<^R/.JQJBB(R)/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	PUSHJ	P,CLRSTR		;CLEAN UP STREAM
	TXNE	F,FL.KST		;KSYS STREAM?
	JRST	STEXIT			;YES--DONE
	TXNN	R,RL.SHT		;SHUTTING DOWN STREAM?
	PUSHJ	P,B$SEND		;NO - SEND RELEASE MESSAGE TO QUASAR
	JRST	STEXIT			;EXIT FROM STREAM

CLOS.S:	PUSHJ	P,C$CLOS##		;CLOSE THE CONTROL FILE
CLOS.F:	PUSHJ	P,CLRSTR		;CLEAN UP STREAM DATA BASE
	JRST	STEXIT			;EXIT FROM STREAM

CLOS.R:	MOVX	S1,REQ.SZ		;REQUEUE MESSAGE SIZE
	PUSHJ	P,B$SQSR		;SET UP MESSAGE TO QUASAR
	MOVE	S1,[REQ.SZ,,.QOREQ]	;HEADER WORD
	MOVEM	S1,.MSTYP(S2)		;SAVE IN MESSAGE
	MOVE	S1,.JBRQF(R)		;GET REQUEUE FLAG WORD
	TXNE	S1,RQ.TIM		;SAVE A TIME SET?
	TXZA	S1,RQ.HBO		;YES - MAKE SURE HOLD BIT OFF
	TXO	S1,RQ.HBO		;ELSE LITE THE HOLD BIT
	MOVEM	S1,REQ.FL(S2)		;SAVE IN REQUEUE FLAG WORD
	MOVE	S1,.JQITN(R)		;THE TASK NAME
	MOVEM	S1,REQ.IT(S2)		;STORE
	HRLI	S1,.JBCRQ(R)		;CHECKPOINT/REQUEUE INFORMATION
	HRRI	S1,REQ.IN(S2)		;INTO THE MESSAGE
	BLT	S1,REQ.IN+<EQCKSZ-1>(S2)  ;MOVE ALL THE WORDS
	PUSHJ	P,B$SEND		;SEND IT TO QUASAR
	$WTOJ	(<Requeue>,<^R/.JQJBB(R)/>,.JQOBJ(R),<$WTNOD(.JQLOC(R))>)
	PUSHJ	P,CLRSTR		;CLEAN UP STREAM
	PJRST	STEXIT			;EXIT FROM STREAM
SUBTTL	Stream termination -- Build release message


; Build release message
;
RELMSG:	TXNE	F,FL.KST		;KSYS STREAM?
	JRST	RELM.6			;YES--SKIP NORMAL RELEASE STUFF
	MOVEI	S1,REL.FD		;GET MINIMUM RELEASE MESSAGE
	PUSHJ	P,B$SQSR		;SET UP MESSAGE TO QUASAR
	MOVX	S1,<INSVL.(REL.FD,MS.CNT)!INSVL.(.QOREL,MS.TYP)>
	MOVEM	S1,.MSTYP(S2)		;STORE LENGTH AND TYPE
	MOVE	S1,.JQITN(R)		;GET ITN
	MOVEM	S1,REL.IT(S2)		;STORE IT
	MOVEI	S1,0			;CLEAR FLAG BITS
	TXNE	F,FL.UHE		;UNHANDLED ERROR?
	TXO	S1,RF.ABO		;YES--LIGHT ABORTED BIT
	MOVEM	S1,REL.FL(S2)		;STORE FLAGS
	TXNN	F,FL.TXT		;COPY .JWTOP TEXT?
	JRST	RELM.3			;NO
	MOVE	S1,[POINT 7,.JWTOP(R)]	;YES--SETUP INITIAL POINTER
	MOVE	T1,[POINT 7,REL.TX(S2)]	;AND DESTINATION

REML.1:	ILDB	T2,S1			;GET A CHAR
	CAIE	T2,.CHLFD		;STOP ON <LF>
	CAIN	T2,.CHCRT		;STOP ON <CR>
	JRST	RELM.2			;YES
	JUMPE	T2,RELM.2		;OR NULL
	IDPB	T2,T1			;STORE
	JRST	REML.1			;LOOP FOR ALL

RELM.2:	MOVEI	T2,.CHNUL		;GET A NULL
	IDPB	T2,T1			;STORE

RELM.3:	SKIPG	S1,.JBJNO(R)		;GET THE JOB NUMBER
	MOVEI	S1,0			;JOB WAS NEVER LOGGED IN
	MOVE	T1,.JQLFP+.FPINF(R)	;GET THE LOG FILE BITS
	TXNE	T1,FP.DEL		;DELETE IT?
	TXO	S1,RL.DLG		;YES
	TXNE	T1,FP.SPL		;WAS IT SPOOLED?
	TXO	S1,RL.SPL!RL.DLG 	;YES
	MOVEM	S1,REL.BJ(S2)		;STORE FLAGS AND JOB NUMBER

RELM.4:	GETLIM	S1,.JQLIM(R),OUTP	;GET /OUTPUT VALUE
	TXNN	R,RL.FLS		;FLUSHING THE JOB?
	CAIN	S1,%EQONL		;OR WAS IT /OUTPUT:NOLOG
	JRST	RELM.7			;YES TO EITHER - DON'T QUEUE LOG
	TXNE	F,FL.UHE		;WAS THERE AN UNHANDLED ERROR?
	CAIE	S1,%EQOLE		;AND /OUTPUT:ERROR SPECIFIED?
	CAIN	S1,%EQOLG		;NO TO ERROR STUFF, WAS IT /OUTPUT:LOG?
	JRST	RELM.5			;YES TO ONE OF THOSE - QUEUE LOG FILE
	JRST	RELM.7			;DON'T QUEUE LOG IF WE GET THIS FAR

RELM.5:	TXNE	F,FL.NUL		;LOG FILE WRITTEN TO NUL:?
	POPJ	P,			;YES - THEN ALL DONE
	HRLI	S1,.JQLFD(R)		;GET LOG FILE FD ADDRESS
	HRRI	S1,REL.FD(S2)		;GET DESTINATION ADDRESS
	LOAD	T1,.JQLFD+.FDLEN(R),FD.LEN ;GET FD LENGTH
	LOAD	T2,.MSTYP(S2),MS.CNT	;GET MESSAGE LENGTH
	ADD	T2,T1			;COMPUTE NEW LENGTH
	STORE	T2,.MSTYP(S2),MS.CNT	;STORE IT
	ADDI	T1,-1(S1)		;COMPUTE END ADDRESS OF BLT
	BLT	S1,0(T1)		;COPY LOG FILE FD
	POPJ	P,			;RETURN

RELM.6:	TXNE	R,RL.JIE		;JOB IN ERROR?
	PJRST	KSYQUE			;YES--QUEUE UP LOG FILE /DISP:DEL
	JRST	RELM.8			;ELSE DELETE IT

RELM.7:	MOVX	S1,RL.SPL!RL.DLG	;GET SPOOLED AND DELETE LOG FILE BIT
	TDNE	S1,REL.BJ(S2)		;DID WE SET IT?

RELM.8:	PUSHJ	P,L$DLET##		;YES - DELETE THE LOG FILE
	POPJ	P,			;RETURN
SUBTTL	Stream termination -- Data base cleanup


; This routine is called only from CLOSJB
;
CLRSTR:	TXNN	F,FL.KST		;KSYS STREAM?
	JRST	CLRS.1			;NO
	MOVE	S1,KSYSSC		;GET COUNT OF STREAMS SETUP
	SOS	S2,KSYUSE		;COUNT DOWN KSYS STREAMS IN USE
	SUBI	S1,(S2)			;COMPUTE STREAMS FREE NOW
	CAMLE	S1,KSYCNT		;ENOUGH LEFT TO HANDLE THE OVERFLOW?
	TXO	R,RL.SHT		;YES--SHUT DOWN THIS STREAM
	JUMPN	S2,CLRS.1		;SHUTTING DOWN LAST KSYS STREAM?
	PUSHJ	P,KSYFIN		;YES--TELL THE OPERATOR WE'VE FINISHED

CLRS.1:	MOVE	S1,[IOWD TPSIZE,G$PDL]	;GET TOP LEVEL PDL FIRST
	PUSH	S1,(P)			;PLACE RETURN ADDRESS ON STACK
	MOVE	P,S1			;GET NEW STACK POINTER
	SOS	G$SACT			;DECREMENT THE STREAM COUNT
	CAMN	S,G$HACT		;WAS STREAM THE HIGHEST ACTIVE
	  PUSHJ	P,FHIACT		;YES, FIND NEW G$HACT
	SKIPE	S1,.JMDAP(R)		;GET MDA PAGE (IF ANY)
	$CALL	M%RPAG			;RELEASE IT
	SKIPE	S1,.JMODP(R)		;GET MODIFY PAGE (IF ANY)
	$CALL	M%RPAG			;RELEASE IT
	MOVEI	S1,1			;1 PAGE
	MOVE	S2,.JSCMD(R)		;GET ADDRESS OF COMMAND PARSE PAGE
	ADR2PG	S2			;CONVERT TO PAGE NUMBER
	SKIPE	S2			;MAKE SURE WE REALLY HAD IT
	$CALL	M%RLNP			;RELEASE IT
	TXNE	R,RL.SHT		;SHUTTING DOWN STREAM?
	PJRST	SHUT.1			;YES - DO IT NOW
	TLZ	R,777777		;CLEAR INITIAL SETTINGS
	MOVEM	R,G$BASE(S)		;UPDATE STREAM RELOCATION AND FLAGS
	POPJ	P,			;RETURN
SUBTTL	Time text generation


; Convert time to ASCIZ text
; Call:	MOVE	S1, time
;	PUSHJ	P,B$MTIM	;TIME IN MILLISECONDS
;	PUSHJ	P,B$STIM	;TIME IN SECONDS
;
; On return, G$TMTX:= contains the ASCIZ time text
;
B$MTIM::IDIVI	S1,^D1000		;CONVERT TO SECONDS
B$STIM::$SAVE	<P1,P2,P3>		;SAVE SOME ACS
	MOVE	P1,S1			;GET TIME IN MILLISECONDS
	IDIVI	P1,^D3600		;P1:= HOURS
	IDIVI	P2,^D60			;P2:= MINUTES, P3:= SECONDS
	$TEXT	(<-1,,G$TMTX>,<^D/P1/:^D2R0/P2/:^D2R0/P3/^0>) ;HH:MM:SS
	POPJ	P,			;RETURN
SUBTTL	IOWAIT - Wait for I/O completion


IOWAIT::PUSHJ	P,P$STAT##		;GET THE JOB STATUS
	TXNE	J,JL.UOA		;OUTPUT AVAILABLE?
	JRST	IOWA.2			;YES
	TXNE	J,JL.UDI!JL.UHI		;PTY READY FOR MORE INPUT?
	JRST	IOWA.3			;YES

IOWA.1:	PUSHJ	P,QTS			;WAIT FOR SOME PTY ACTIVITY
	JRST	IOWAIT			;TRY AGAIN

IOWA.2:	PUSHJ	P,P$READ##		;READ A LINE FROM THE PTY
	JRST	IOWAIT			;GO CHECK STATUS

IOWA.3:	TXNE	F,FL.SIL		;BATCH JOB SILENCED?
	SETOM	.JLTIM(R)		;YES - KEEP OUTPUT ALIGNED
	SKIPE	.JBCLK(R)		;CLOCK/EVENT REQUEST PENDING?
	JRST	IOWA.1			;YES - WAIT A WHILE
	POPJ	P,			;RETURN
SUBTTL	Random Little Routines



; Get job's remaining time limit
;
GJTIML:
TOPS10	<				;TOPS-10 ONLY
	HRLZ	S2,.JBJNO(R)		;GET THE JOB NUMBER
	HRRI	S2,.GTLIM		;AND THE BATCH LIMIT TABLE
	GETTAB	S2,			;READ THE JOB'S LIMIT WORD
	  MOVX	S2,-1			;CAN'T - GIVE THE GUY A BREAK
	ANDX	S2,JB.LTM		;KEEP ONLY THE TIME LIMIT
	POPJ	P,			;RETURN
>					;END OF TOPS-10 CONDITIONAL

TOPS20	<				;TOPS-20 ONLY
	PUSH	P,S1			;SAVE S1
	PUSH	P,T1			;AND T1
	MOVE	S1,.JBJNO(R)		;GET THE JOB NUMBER
	MOVX	S2,<-1,,T1>		;RETURN 1 WORD IN S2
	MOVX	T1,.JIRTL		;FUNCTION CODE
	GETJI				;READ THE JOB'S TIME LIMIT
	  MOVX	S2,-1			;GIVE THE GUY A BREAK
	MOVE	S2,T1			;GET TIME LIMIT
	POP	P,T1			;RESTORE T1
	POP	P,S1			;AND S1
	POPJ	P,			;RETURN
>					;END OF TOPS-20 CONDITIONAL


; Set job location on TOPS-20
;

TOPS20	<
SETLOC:	MOVE	S1,.JQLOC(R)		;GET THE OUTPUT NODE
	CAMN	S1,G$NODE		;IS IT SAME AS MINE?
	POPJ	P,			;YES..JUST RETURN
	SETZB	T3,T4			;CLEAR T3 AND T4
	MOVE	T1,[POINT 6,.JQLOC(R)]	;GET THE LOCATION
	MOVE	T2,[POINT 7,T3]		;PLACE TO STORE STRING
	MOVEI	P1,6			;MAXIMUM LENGTH
SETL.1:	ILDB	S2,T1			;GET A BYTE
	JUMPE	S2,SETL.2		;O.K. SET THE LOCATION
	ADDI	S2,40			;CONVERT TO ASCII CHARACTER
	IDPB	S2,T2			;SAVE THE BYTE
	SOJG	P1,SETL.1		;CHECK NUMBER OF CHARACTERS
SETL.2:	MOVE	S1,.JBJNO(R)		;GET THE JOB NUMBER
	MOVX	S2,.SJLLO		;SETUP LOCATION
	HRROI	T1,T3			;GET STRING
	SETJB				;SET IT UP
	ERJMP	.+1			;IGNORE ERROR FOR NOW
	POPJ	P,			;RETURN
>;END TOPS20
SUBTTL	DELSPL - Delete spooled input files


; This routine is not needed for TOPS-10. For TOPS-20, files named
; DSK:<SPOOL>CDR-xxx.CDyyy.* are deleted. "xxx" is the user's directory
; and "yyyy" is a string maje of the job name concatenated with 4 random
; characters currently passed by SPRINT in .JQSIS(R).
;
; *** Note ***
; The call to DELSPL must follow the call to C$CLOS in CLOSJB since it uses
; .JQCFD(R) for deleting spooled files.
;
DELSPL:
TOPS10	<POPJ	P,>			;NOT NEEDED FOR TOPS-10

TOPS20	<				;TOPS-20 ONLY
	SKIPN	.JQSIS(R)		;IS THERE A SPOOLED INPUT NAME?
	POPJ	P,			;NO, JUST RETURN
	$TEXT	(<-1,,.JQCFD(R)>,<PS:[SPOOL]CDR-^O/.JQJBB+JIB.US(R),RHMASK/.^W/.JQSIS(R)/.*^0>)
	MOVX	S1,GJ%OLD!GJ%IFG!GJ%SHT	;LOAD GTJFN BITS
	HRROI	S2,.JQCFD(R)		;POINT TO FILE-NAME
	GTJFN				;GET A JFN
	  POPJ	P,			;FAILED, RETURN
	MOVE	T1,S1			;SAVE THE JFN
	JRST	DELS.2			;JUMP INTO THE LOOP

DELS.1:	GNJFN				;GET THE NEXT FILE
	  JRST	DELS.3			;DONE EXPUNGE THE AREA
DELS.2:	TLZ	S1,-1			;CLEAR LEFT HALF OF JFN WORD
	TXO	S1,DF%NRJ		;DONT RELEASE THE JFN
	DELF				;DELETE THE FILE
	  JFCL				;IGNORE THE ERROR
	MOVE	S1,T1			;RELOAD INDEXABLE JFN
	JRST	DELS.1			;GET THE NEXT ONE

DELS.3:	MOVEI	S1,0			;NO SPECIAL FLAGS
	MOVE	S2,G$SPLD		;GET DIRECTORY NUMBER OF PS:[SPOOL]
	DELDF				;EXPUNGE IT
	  ERJMP	.+1			;IGNORE ERROR..
	POPJ	P,			;AND RETURN

>					;END OF TOPS-20 CONDITIONAL
SUBTTL	LUUO handler


UUOCON:	PUSH	P,S1			;SAVE S1
	LDB	S1,[POINT 9,.JBUUO##,8]	;GET OPCODE
	CAXLE	S1,UUOMAX		;RANGE CHECK IT
	  $STOP	(IBU,Illegal BATCON UUO)
	PUSHJ	P,@UUOTAB-1(S1)		;DISPATCH
	POP	P,S1			;RESTORE S1
	POPJ	P,			;RETURN


; UUO dispatch table
;
UUOTAB:	IDENTX				;IDENTIFY A LOG FILE LINE
	IDHDRX				;IDENTIFY A LOG FILE HEADER LINE
UUOMAX==.-UUOTAB			;NUMBER OF KNOWN UUOS


; Identify a log file line
;
IDENTX:	SKIPN	.JLTIM(R)		;NEED TO END THE PREVIOUS LINE?
	PUSHJ	P,L$CRLF##		;YES - SEND A CRLF TO THE LOG
	SETZM	.JLTIM(R)		;CLEAR TIME STAMP NEEDED FLAG
	MOVE	S1,-1(P)		;GET SAVED AC CONTENTS
	$TEXT	(L$PLOG##,<^T/G$TIME/^I/@.JBUUO/>) ;OUTPUT LINE IDENTIFIER
	POPJ	P,			;RETURN

; Identify a log file header line
;
IDHDRX:	MOVE	S1,-1(P)		;GET SAVED AC CONTENTS
	$TEXT	(L$PHDR##,<^T/G$TIME/^I/@.JBUUO/>) ;OUTPUT LINE IDENTIFIER
	POPJ	P,			;RETURN
SUBTTL	PTY interrupt handler


; This seemingly useless routine will actually make the TOPS-20 DISMS JSYS
; act in a reasonable manor when a PTY interrupt is received during the sleep.
; The problem is that the DISMS JSYS doesn't get terminated when an interrupt
; is received.
;
TOPS20	<				;TOPS-20 ONLY
PTYINT:	$BGINT	PTYLVL			;SWITCH TO PTY INTERRUPT LEVEL
	$DEBRK				;RETURN FROM INTERRUPT
>					;END OF TOPS-20 CONDITIONAL
SUBTTL	ERRTAB	EXPAND ERROR TABLE VALUES

	DEFINE	X(A,B),<	EXP	[ITEXT (<B>)]>

ERRTAB:	MSGBLD			;BUILD MESSAGE TABLE
SUBTTL	Literals


	LIT
SUBTTL	End


	END	BATCON			;A GOOD PLACE TO START