Google
 

Trailing-Edge - PDP-10 Archives - cuspjul86upd_bb-jf24a-bb - 10,7/galaxy/lptspl/lptspl.mac
There are 45 other files named lptspl.mac in the archive. Click here to see a list.
	TITLE	LPTSPL - TOPS10 LINE PRINTER DRIVER

;
;
;		COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION
;	1975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,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	GLXMAC			;SEARCH GALAXY PARAMETERS
	SEARCH	QSRMAC			;SEARCH QUASAR PARAMETERS
	SEARCH	ORNMAC			;SEARCH ORION/OPR PARAMETERS
	SEARCH	LPTMAC			;LPTSPL PARAMETERS
	PROLOGUE(LPTSPL)

	.DIRECT	FLBLST

IF2,<
TOPS20 <PRINTX ASSEMBLING GALAXY-20 LPTSPL>
TOPS10 <PRINTX ASSEMBLING GALAXY-10 LPTSPL>
>  ;END IF2

	SALL				;SUPPRESS MACRO EXPANSIONS

	SPLEDT==13			;EDIT LEVEL

;STORE VERSION NUMBER IN JOBVER
	LOC	137
.JBVER::EXP	%LPT
	RELOC	0

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

	DEFINE	FACT,<IFN FTFACT>
SUBTTL	Table of Contents
SUBTTL	Special Forms Handling Parameters

;FORMS SWITCHES:
;	BANNER:NN	NUMBER OF JOB HEADERS
;	TRAILER:NN	NUMBER OF JOB TRAILERS
;	HEADER:NN	NUMBER OF FILE HEADERS (PICTURE PAGES)
;	LINES:NN	NUMBER OF LINES PER PAGE
;	WIDTH:NN	NUMBER OF CHARACTERS PER LINE
;	ALIGN:SS	NAME OF ALIGN FILE
;	ALCNT:NN	NUMBER OF TIMES TO PRINT ALIGN FILE
;	ALSLP:NN	NUMBER OF SECS TO SLEEP BETWEEN COPIES OF ALIGN
;	RIBBON:SS	RIBBON TYPE
;	TAPE:SS		VFU CONTROL TAPE
;	VFU:SS		(SAME AS /TAPE)
;	RAM:SS		TRANSLATION RAM TO USE
;	DRUM:SS		DRUM TYPE
;	CHAIN:SS	CHAIN TYPE (DRUM/CHAIN ARE THE SAME)
;	NOTE:AA		TYPE NOTE TO THE OPERATOR


;IN THE ABOVE AND BELOW EXPLANATIONS:
;	NN	IS A DECIMAL NUMBER
;	SS	IS A 1-6 CHARACTER STRING
;	AA	IS A STRING OF 1 TO 50 CHARACTERS
;	OO	IS AN OCTAL NUMBER



;LOCATION SPECIFIERS
;	ALL		ALL LINEPRINTERS
;	CENTRAL		ALL LINEPRINTERS AT THE CENTRAL SITE
;	REMOTE		ALL REMOTE LINEPRINTERS
;	LPTOOO		LINEPRINTER OOO ONLY

;NOTE:  LPTSPL WILL USE THE FIRST ENTRY WHICH MEETS THE LOCATION
;	SPECIFICATION FOR ITS LINEPRINTER.
SUBTTL	Generate table of switch names

;*Note* FF is used in macro F defined in LPTMAC.

DEFINE FF(A,C),<
	XLIST
	<<SIXBIT /A/>&777777B17>+S$'A
	LIST
	SALL
>

FFNAMS:	F

;GENERATE TABLE OF DEFAULT PARAMTERS
DEFINE FF(X,Y),<
	XLIST
D$'X::	EXP	Y
	LIST
	SALL
>

FFDEFS:	F
	F$NSW==.-FFDEFS
	PURGE	D$VFU,D$CHAI

	F$WCL1==^D60	;WIDTH CLASS ONE IS 1 TO F$WCL1
	F$WCL2==^D100	;WIDTH CLASS TWO IS F$WCL1 TO F$WCL2
	F$LCL1==^D41	;Length class one is 1 to F$LCL1
	F$LCL2==^D55	;Length class two is F$LCL1 to F$LCL2
;NOW GENERATE A BIT TABLE OF WHICH WORDS IN THE JOB DATA PAGE TO ZERO
;	ON A NEW JOB

ZTABLE:					;PUT TABLE HERE

DEFINE ZTAB(A),<
	IFNDEF ..Z'A,<..Z'A==0>
	EXP	..Z'A
>  ;END DEFINE ZTAB

	ZZ==0
REPEAT <J$$LEN+^D35>/^D36,<
	XLIST
	ZTAB(\ZZ)
	ZZ==ZZ+1
	LIST
>  ;END REPEAT

SUBTTL	Random Impure Storage

PDL:	BLOCK	PDSIZE		;PUSHDOWN LIST

MESSAG::BLOCK	1		;ADDRESS OF MESSAGE JUST RECEIVED
BLKADR::BLOCK	1		;IPCF MSG BLK ADDR SAVE AREA
TEXTBP::BLOCK	1		;BYTE POINTER FOR DEPBP
SAB::	BLOCK	SAB.SZ		;A SEND ARGUMENT BLOCK
MSGBLK::BLOCK	MSBSIZ		;A BLOCK TO BUILD MESSAGES IN.
FOB::	BLOCK	FOB.SZ		;A FILE OPEN BLOCK

FMOPN:	BLOCK	1		;SET TO -1 WHEN LPFORM IN OPEN
FMIFN:	BLOCK	1		;THE IFN FOR LPFORM.INI
IMESS:	BLOCK	1		;IPCF message -1=one to be released
LPCNF::	BLOCK	11		;SYSNAME
LPJOB:	BLOCK	1		;LPTSPL'S JOB NUMBER
LPTRM:	BLOCK	1		;TERMINAL DESIGNATOR
LPCON:	BLOCK	1		;CONNECT TIME
LPLNO:	BLOCK	1		;LINE NUMBER
JOBITS::BLOCK	1		;SAVE JOB STATUS BITS FLAG.
STRSEQ:	EXP	4000		;STREAM SEQ #'S (START AT 4000)
SCHEDL:	-NPRINT,,0		;STREAM SCHEDULING DATA
FNTLST::BLOCK	1		;DEVICE SPECIFIC FONT LISTS

SLEEPT::BLOCK   1		;SLEEP TIME FOR SCHEDULING.
				;This is always the min. amount to sleep
				;-1 if no sleep time specified

CNTSTA::BLOCK	1		;NUMBER OF THE CENTRAL STATION

RUTINE:	BLOCK	1		;MESSAGE PROCESSING ROUTINE ADDRESS.

STRTAB:	BLOCK	STRLEN		;STRUCTURE TABLE
STRBLK:	BLOCK	STRSLS		;ARGUMENT BLOCK FOR BUILDING SEARCH LISTS

TOPS10	<
DCHBLK:	BLOCK	.DCSNM+1	;DSKCHR BLOCK
>

TOPS20 <
SPLDIR:	BLOCK	1		;DIRECTORY NUMBER OF PS:<SPOOL>
>  ;END TOPS20 CONDITIONAL


; INIT FILE DATA STORAGE
INIFOB:	BLOCK	FOB.SZ		;FILE OPEN BLOCK
INIFD:	BLOCK	FDXSIZ		;FILE DESCRIPTOR BLOCK
INIIFN:	BLOCK	1		;INTERNAL FILE NUMBER
INITMP:	BLOCK	1		;TEMP STORAGE USED DURING I/O ERROR REPORTING
INIEPC:	BLOCK	1		;CALLER'S PC FOR I/O ERROR RECOVERY
INIPDP:	BLOCK	1		;PDL POINTER FOR I/O ERROR RECOVERY
INILIN:	BLOCK	1		;LINE NUMBER WITHIN FILE
INISAV:	BLOCK	1		;SAVED CHARACTER
INIATM:	BLOCK	INIWDS		;ATOM BUFFER
SUBTTL	Resident JOB Database

STREAM::BLOCK	1		;CURRENT STREAM NUMBER

JOBPAG::BLOCK	NPRINT		;ADDRESS OF A FOUR PAGE BLOCK
				; ONE FOR REQUEST, ONE FOR JOB PARAMS
				; ONE FOR LPT BUFFER, ONE FOR LOG BUFFER

JOBOBA::BLOCK	NPRINT		;TABLE OF OBJECT BLOCK ADDRESSES

JOBSTW::BLOCK	NPRINT		;JOB STATUS WORD

JOBACT::BLOCK	NPRINT		;-1 IF STREAM IS ACTIVE, 0 OTHERWISE

JOBOBJ::BLOCK	3*NPRINT	;LIST OF SETUP OBJECTS

JOBWKT::BLOCK	NPRINT		;JOB WAKE TIME (FOR ALIGN)

JOBCHK::BLOCK	NPRINT		;STREAM CHECKPOINT INDICATOR
				;Contains the time for the next checkpoint
				;  or 0 if one is requested

JOBUPD::BLOCK	NPRINT		;Stream update indicator
				;  if set, update is indicated for the stream

JOBWAC::BLOCK	NPRINT		;STREAM WTOR ACK CODE.
SUBTTL	IB and HELLO message blocks


	TOPS10	<INTVEC==VECTOR>

	TOPS20	<INTVEC==:LEVTAB,,CHNTAB>



IB:	$BUILD	IB.SZ				;
	 $SET(IB.PRG,,%%.MOD)			;SET UP PROGRAM NAME
	 $SET(IB.INT,,INTVEC)			;SET UP INTERRUPT VECTOR ADDRESS
	 $SET(IB.PIB,,PIB)			;SET UP PIB ADDRESS
	 $SET(IB.FLG,IP.STP,1)			;STOPCODES TO ORION
	$EOB					;


PIB:	$BUILD	PB.MNS				;
	 $SET(PB.HDR,PB.LEN,PB.MNS)		;PIB LENGTH,,0
	 $SET(PB.FLG,IP.PSI,1)			;PSI ON
	 $SET(PB.INT,IP.CHN,0)			;INTERRUPT CHANNEL
	 $SET(PB.SYS,IP.BQT,-1)			;MAX SEND/RECIEVE IPCF QUOTAS
	$EOB					;


HELLO:	$BUILD	HEL.SZ				;
	  $SET(.MSTYP,MS.TYP,.QOHEL)		;MESSAGE TYPE
	  $SET(.MSTYP,MS.CNT,HEL.SZ)		;MESSAGE LENGTH
	  $SET(HEL.NM,,<'LPTSPL'>)		;PROGRAM NAME
	  $SET(HEL.FL,HEFVER,%%.QSR)		;QUASAR VERSION
	  $SET(HEL.NO,HENNOT,1)			;NUMBER OF OBJ TYPES
	  $SET(HEL.NO,HENMAX,NPRINT)		;MAX NUMBER OF JOBS
	  $SET(HEL.OB,,.OTLPT)			;LPT OBJECT TYPE
	$EOB					;

OACERR:	BLOCK	1			;'OUTGET' ROUTINE RETURN CODE

SETMSG:	[ASCIZ/Started/]
	[ASCIZ/Not available right now/]
	[ASCIZ/Does not exist/]


LIMSG:	ASCIZ/
Type 'RESPOND <number> ABORT' to terminate the job now
Type 'RESPOND <number> PROCEED' to allow the job to continue printing/
SUBTTL	$TEXT Utilities


DEPBP::	IDPB	S1,TEXTBP		;DEPOSIT THE BYTE
	$RETT				;AND RETURN


;OPERATING SYSTEM DEPENDENT ITEXTS


;LOG FILE STAMPS
LPMSG::	ITEXT(<^C/[-1]/ LPMSG	>)
LPDAT::	ITEXT(<^C/[-1]/ LPDAT	>)
LPOPR::	ITEXT(<^C/[-1]/ LPOPR	>)
LPEND::	ITEXT(<^C/[-1]/ LPEND	>)
LPERR::	ITEXT(<^C/[-1]/ LPERR	? >)
DATMON:	ITEXT(<  Date ^H/[-1]/ Monitor: ^T/LPCNF/ ^T7C*/0(T4)/>)

SUBTTL	Device table

DEFINE	LL(DEVNAM)<.TEXT \'DEVNAM/LOCALS\>
	G..LPT				;CAUSE DRIVERS TO LOAD
	.TEXT	",LPTLP5/LOCALS"	;ALWAYS LOAD THE LP05 CLASS DRIVER
	.TEXT	",LPTMTA/LOCALS"	;ALWAYS LOAD THE MAGTAPE DRIVER
	.TEXT	",LPTD60/LOCALS"	;ALWAYS LOAD THE DN60 DRIVER

	.LNKEN	DEVLNK,DEVLST		;DEFINE HEAD OF DEVICE DRIVER CHAIN
DEVLST::BLOCK	1			;START OF DEVICE DRIVER CHAIN
SUBTTL 	LPTSPL - Multiple Line Printer Spooler.

LPTSPL:	RESET				;AS USUAL.
	MOVE	P,[IOWD PDSIZE,PDL]	;SET UP THE STACK.
	MOVEI	S1,IB.SZ		;GET THE IB SIZE.
	MOVEI	S2,IB			;ADDRESS OF THE IB.
	PUSHJ	P,I%INIT		;SET UP THE WORLD.
	PUSHJ	P,INTINI		;SET UP THE INTERRUPT SYSTEM.
	PUSHJ	P,OPDINI		;GET OPERATING SYSTEM INFO.
	PUSHJ	P,I%ION			;TURN ON INTERRUPTS.
	MOVEI	T1,HELLO		;GET ADDRESS OF HELLO MESSAGE.
	PUSHJ	P,SNDQSR		;SAY HI TO QUASAR.
	MOVSI	P1,-NPRINT		;SET UP STREAM COUNTER.

	;FALL THROUGH TO MAIN LOOP.
SUBTTL	Idle Loop

MAIN:	SKIPE	J,JOBPAG(P1)		;Stream setup?
	PUSHJ	P,@J$SCHD(J)		;CALL DRIVER
	SKIPN	JOBACT(P1)		;IS THE STREAM ACTIVE ???
	JRST	MAIN.2			;NO, GET THE NEXT STREAM.
	HRRZM	P1,STREAM		;RUNNABLE STREAM!!!
	MOVE	J,JOBPAG(P1)		;YES, GET JOB PAGE
	PUSHJ	P,CHKTIM		;Adjust sleep time if needed
	$CALL	DSTATUS			;Do any status stuff
	SKIPE	JOBSTW(P1)		;IS THE STREAM BLOCKED ???
	JRST	MAIN.2			;YES, GET THE NEXT STREAM.
	MOVEM	P1,SCHEDL		;SAVE THE SCHEDULING STREAM.
	MOVSI	0,J$RACS+1(J)		;Setup first source address for BLT
	HRRI	0,1			;Setup first destination address
	BLT	0,17			;GET SOME ACS
	POPJ	P,			;AND RETURN

MAIN.1:	MOVE	P1,SCHEDL		;GET THE LAST SCHEDULED STREAM.
	$CALL	DSTATUS			;Do any status stuff
	PUSHJ	P,CHKTIM		;SET THE WAKEUP TIMER

MAIN.2:	AOBJN	P1,MAIN			;LOOP BACK FOR SOME MORE.
	PUSHJ	P,CHKQUE		;CHECK FOR INCOMMING MESSAGES.
	SKIPE	MESSAGE			;DID WE PROCESS A MESSAGE ???
	JRST	MAIN.3			;YES, CONTINUE PROCESSING
	MOVE	S1,SLEEPT		;NO, PICK UP SLEEP TIME.
	JUMPE	S1,MAIN.3		;Don't sleep if 0 sleep specified
	SKIPG	S1			;Any time specified?
	SETZ	S1,			;No, set to sleep forever
TOPS20 <
	SKIPE	JOBACT			;CHECK IF STREAM ACTIVE..
	SKIPE	JOBSTW			;ANY BLOCKING CONDITIONS
>;END TOPS20 CONDITIONAL

	PUSHJ	P,I%SLP			;ELSE,,GO WAIT

MAIN.3:	MOVE	P,[IOWD PDSIZE,PDL]	;RESET THE STACK POINTER.
	SETOM	SLEEPT			;Start fresh
	MOVSI	P1,-NPRINT		;GET LOOP AC.
	JRST	MAIN			;KEEP ON PROCESSING.

SUBTTL	CHKTIM - ROUTINE TO CHECK WAKEUP TIME BASED ON CURRENT STREAM

;  The purpose of this routine is to check and set the sleep time based
;  on current conditions.  The sleeptime is checked based on the stream's
;  wakeup time and the console wakeup time (on DN60).  Whoever wants to
;  wakeup the earliest sets the sleeptime if the time is less than the
;  current.

;  Returns:	False if it is not time to wake up this stream
;		True  if it is time to wakeup this stream

CHKTIM::PUSHJ	P,I%NOW			;GET CURRENT TIME INTO S1
	MOVE	T1,STREAM		;GET OUR STREAM NUMBER
	MOVE	S2,JOBWKT(T1)		;GET WAKEUP TIME OF JOB
	PUSHJ	P,@J$WAKE(J)		;DO WAKEUP TIMER CHECKING
	JUMPE	S2,.RETF		;NO TIME SET, THIS IS IRRELEVANT
	SUB	S2,S1			;CALCULATE THE NUMBER
	IDIVI	S2,3			;   OF SECONDS TO WAKE-UP.
	JUMPLE	S2,CHKT.1		;IF TIME IS UP,,WAKE UP STREAM.
	CAILE	S2,^D60			;IF WAKE UP TIME IS GREATER THEN
	MOVEI	S2,^D60			;   60 SECS,, THEN MAKE IT 60 SECS.
	SKIPL	SLEEPT			;IF -1 THEN NONE SET - GO SET
	CAMGE	S2,SLEEPT		;IF WAKE UP TIME IS LESS THEN
	MOVEM	S2,SLEEPT		;CURRENT WAKE UP TIME,,THEN RESET IT.
	$RETF				;DO NOT WAKE UP THE JOB.
CHKT.1:	SETZM	SLEEPT			;NO SLEEP TIME NEEDED
	MOVX	S1,PSF%AL		;PICK UP ALIGN BLOCK BIT.
	MOVE	T1,STREAM		;GET STREAM NUMBER AGAIN
	ANDCAM	S1,JOBSTW(T1)		;CLEAR ALIGN BIT
	MOVE	T1,STREAM		;GET THE STREAM NUMBER
	SKIPF				;SKIP IF DRIVER SAID DON'T ZERO JOBWKT
	SETZM	JOBWKT(T1)		;CLEAR JOB WAKE TIME
	$RETT				;WAKE UP THE STREAM.
SUBTTL DSCHD -- Deschedule process

; The purpose of this routine is to provide a generalized blocking
; mechanism.  It differs from the old DSCHD in that it will block
; whether in stream context or not.

; DSCHD is called by the $DSCHD macro where the call is:

;	$DSCHD (flags)	where flags are flags and/or a number of seconds
;			to sleep

; ASSUMPTIONS. . .

; 1.  STREAM is assumed to be correct.

; 2.  If not in stream context, it is assumed that J contains the
;     address of the jobpage.  This has a side problem.  If J indicates
;     a jobpage of an already existing stream with a context and
;     the stream is in the overhead context, the old stream context
;     will be destroyed which must be avoided by the caller.

; 3.  If called with an IPCF message currently in use, it is assumed
;     that the user has everything needed from the message and the
;     message will be released.  This assumption is necessary to
;     prevent another message being received before the old message
;     is released.

; All registers are preserved in the JOBPAG.
; Only AC's S1, S2 and T1 are touched before jumping to MAIN.

;     parameters:
;         J / Address of the current jobpage  (if not, expect a stopcd)

;Save the AC's in any case

DSCHD::	MOVEM	0,J$RACS(J)		;Save AC0
	MOVEI	0,J$RACS+1(J)		;Place to put AC1
	HRLI	0,1			;Setup the BLT pointer
	BLT	0,J$RACS+17(J)		;Save the AC's

	MOVE 	T1,STREAM		;Get the current stream number

;Take care of the flags passed

	HRRZ	S2,0(P)			;Get address of JUMP [FLAGS]
	HLLZ	S1,@0(S2)		;Get the flags
	HRRZ	S2,@0(S2)		;Get the sleep time
	IORM	S1,JOBSTW(T1)		;set only the flags

	JUMPE	S2,DSCH.D		;No sleep time to worry about
	$CALL	I%NOW			;Get the current time
	IMULI	S2,3			;Seconds to jiffies
	ADD	S1,S2			;Build wake-up time
	MOVEM	S1,JOBWKT(T1)		;Save the wake-up time

;Check to see our current context

DSCH.D:	HRRZ	S1,P			;Get current address of PDL
	CAIL	S1,J$RPDL(J)		;Less than beginning of current PDL
	CAILE	S1,PDSIZE+J$RPDL(J)	;or Greater than end?
	SKIPA				;No not in stream context
	JRST	DSCH.Z			;Yes - already in stream context

;Since we have to make a stream context, we must do the following:
;   1. Release any IPCF messages
;   2. Given then the stream number:
;	Save JOBACT for this stream and info needed to restore JOBACT
;	Set JOBACT for this stream so it can be selected to run
;   3. Save PDL and AC17

	SKIPE	IMESS			;Any IPCF messages?
	$CALL	C%REL			;Yes, release it
	SETZM	IMESS			;Set no IPCF messages

	SKIPN	JOBACT(T1)		;Stream already active?
	PUSH	P,[EXP FIXACT]		;no - remember to fix JOBACT
	SETOM	JOBACT(T1)		;pretend we are active now in any case

	PUSH	P,[EXP FIXPDL]		;Remember to fix up the stack later
	MOVEI	S1,J$RPDL(J)		;Get stream's PDL location
	HRLI	S1,PDL			;Get beginning of PDL
	HRRZ	T1,P			;Get current PDL pointer
	SUBI	T1,PDL			;Find current length
	ADDI	T1,J$RPDL(J)		;Add stream's base
	HRR	P,T1			;Set new pointer
	BLT	S1,(T1)			;Save PDL
	MOVEM	P,J$RACS+P(J)		;Save new PDL pointer

	JRST	MAIN.3			;Return to restart main loop

DSCH.Z:	MOVE	P,[IOWD PDSIZE,PDL]	;Reset stack pointer
	JRST	MAIN.1			;Return to main loop
SUBTTL	FIXPDL -- Fix PDL routine

;The purpose of this subroutine is to return the pseudo stream
;context back to overhead context.  (See DSCHD)

FIXPDL:	MOVEI	S1,PDL			;Get overhead PDL
	HRLI	S1,J$RPDL(J)		;Get beginning of stream's PDL
	HRRZ	S2,P			;Get current pointer
	SUBI	S2,J$RPDL(J)		;Find the current length
	ADDI	S2,PDL			;Add the base of the PDL
	HRR	P,S2			;Set the new pointer
	BLT	S1,(S2)			;Restore PDL
	MOVE	S1,J$RACS+S1		;Restore S1
	MOVE	S2,J$RACS+S2		;Restore S2
	$RET				;Continue on
SUBTTL FIXACT - Routine to set stream to inactive

;This routine is use to return a stream to an inactive state when
;the stream was descheduled when not in stream context.  It is
; "called" by DSCHD pushing FIXACT on the stack when the need is
;determined.

FIXACT:	$SAVE	<S1>			;Save a register
	MOVE	S1,STREAM		;Get the stream #
	SETZM	JOBACT(S1)		;Make it inactive
	$RET				;Don't change anything
SUBTTL	FORFOR -- Force Forms change mess.

; This routine causes a forms change to occur even if there is no
; job currently scheduled for the printer.

;  Assumes J contains the pointer to the job data base
;	   M contains a pointer to the message
;	   The object block has already been parsed correctly

FORFOR:	MOVE	S1,.OFLAG(M)		;Get the forms type
	MOVEM	S1,.EQLIM(J)		;Save it where NXTJOB does

	MOVE	S1,STREAM		;Get the stream number
	SETOM 	JOBACT(S1)		;Set the stream active

	MOVX	S2,PSF%OB+PSF%ST+PSF%OR+PSF%AL
					;Get a bunch of bits
	ANDCAM	S2,JOBSTW(S1)		;And clear them

	MOVEI	S1,J$RPDL-1(J)		;Point to the context PDL
	HRLI	S1,-PDSIZE		;And the length
	PUSH	S1,[EXP	DOFFOR]		;Push address of the stack
	MOVEM	S1,J$RACS+P(J)		;And save the PDL

	$CALL	TBFINI			;Init the buffer
	$CALL	CHKLPT			;Check for online
	$RET
SUBTTL	DOFFOR -- Do the force forms

; This forces the forms change to occur in stream context.  Is called
; implicitly by being placed on the stream's stack by FORFOR.

; Simply calls the routine to set the forms, sends a reset status message
; to notify QUASAR that the forms change has been effected, and returns
; to the scheduler.

DOFFOR:	$CALL	FORMS			;Try to set the forms

	SKIPF				;Did we succeed?
	$CALL	CHKALN			;Yes, do an alignment if needed

	MOVE	S1,STREAM		;Get the stream number
	SETOM	JOBUPD(S1)		;Say we want an update message
	SETZM	JOBSTW(S1)		;Say we want reset message
					;  defaults since no bits set
	$CALL	DSTATUS			;Tell QUASAR we are done

	SETZM	J$RACS+S(J)		;Clear status bits
	MOVE	S1,STREAM		;Get the stream number
	SETZM	JOBACT(S1)		;No longer active
	PJRST	MAIN.3			;Go back to the scheduler
SUBTTL	NXTJOB -- NEXTJOB Message from QUASAR

NXTJOB:	HRR	S1,J			;GET 0,,DEST
	HRL	S1,M			;GET SOURCE,,DEST
	LOAD	S2,.MSTYP(M),MS.CNT	;GET LENGTH OF MESSAGE
	ADDI	S2,-1(J)		;GET ADR OF END OF BLT
	BLT	S1,(S2)			;BLT THE DATA
	MOVE	S1,STREAM		;GET STREAM NUMBER
	SETOM	JOBACT(S1)		;MAKE THE STREAM ACTIVE
	SETZM	JOBCHK(S1)		;CHECKPOINT FIRST CHANCE WE GET !!!
	SETOM	JOBUPD(S1)		;Send update also.
	MOVX	S2,PSF%OB+PSF%ST+PSF%OR+PSF%AL ;GET LOTS OF BITS
	ANDCAM	S2,JOBSTW(S1)		;CLEAR THEM
	MOVEI	S1,J$RPDL-1(J)		;POINT TO CONTEXT PDL
	HRLI	S1,-PDSIZE		;AND THE LENGTH
	PUSH	S1,[EXP DOJOB]		;PUSH THE FIRST ADR ON THE STACK
	MOVEM	S1,J$RACS+P(J)		;AND STORE THE PDL
	SETZB	S,J$RACS+S(J)		;CLEAR FLAGS AC
	LOAD	S1,.EQSPC(J),EQ.NUM	;GET NUMBER OF FILES
	MOVEM	S1,J$RFLN(J)		;STORE IT
	MOVEI	S1,J$$BEG(J)		;PREPARE TO ZERO SELECTED WORDS JOB AREA
	MOVSI	S2,-<J$$LEN+^D35>/^D36	;AOBJN POINTER TO BIT TABLE
NXTJ.2:	MOVEI	T1,^D36			;BIT COUNTER FOR THIS WORD
	MOVE	T2,ZTABLE(S2)		;GET A WORD FROM BIT TABLE
NXTJ.3:	JUMPE	T2,NXTJ.4		;DONE IF REST OF WORD IS ZERO
	JFFO	T2,.+1			;FIND THE FIRST 1 BIT
	ADD	S1,T3			;MOVE UP TO THE CORRESPONDING WORD
	SETZM	0(S1)			;AND ZERO IT
	SUB	T1,T3			;REDUCE BITS LEFT IN THIS WORD
	LSH	T2,0(T3)		;SHIFT OFFENDING BIT TO BIT 0
	TLZ	T2,(1B0)		;AND GET RID OF IT
	JRST	NXTJ.3			;AND LOOP
NXTJ.4:	ADD	S1,T1			;ACCOUNT FOR THE REST OF THE WORD
	AOBJN	S2,NXTJ.2		;AND LOOP
	$TEXT(LOGCHR,<^M^J^I/LPDAT/LPTSPL version ^V/[%LPT]/	^T/LPCNF/>)
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$TEXT(LOGCHR,<^I/LPDAT/Job ^W/.EQJOB(J)/ sequence #^D/.EQSEQ(J),EQ.SEQ/ on ^B/@JOBOBA(S1)/ at ^H/[-1]/>)
	SKIPN	T2,.EQCHK+CKFLG(J)	;GET THE CHECKPOINT FLAGS
	JRST	NXTJ.5			;AND JUMP IF NEW JOB
	MOVEI	T1,[ASCIZ /system failure/]
	TXNE	T2,CKFREQ		;WAS IT A REQUEUE
	MOVEI	T1,[ASCIZ /requeue by operator/]
	$TEXT(LOGCHR,<^I/LPMSG/Job being restarted after ^T/0(T1)/>)

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

NXTJ.5:	PUSHJ	P,LPTTXT		;GENERATE "OUTPUT TO ..." TEXT
	SKIPL	J$LCHN(J)		;KNOW WHERE THE OUTPUT IS GOING?
	$TEXT	(LOGCHR,<^I/LPDAT/^T/J$LOUT(J)/>) ;STUFF IN THE RUN LOG
	LOAD	S1,.EQSEQ(J),EQ.IAS	;IS THIS AN INVALID REQUEST ???
	SKIPE	S1			;IS THIS AN INVALID REQUEST ???
	$TEXT	(LOGCHR,<^I/LPERR/Invalid Account String Specified (^T/.EQACT(J)/)>)
	SKIPE	S1			;CHECK AGAIN
	$TEXT	(<-1,,J$WTOR(J)>,<Invalid account string specified^0>)
	GETLIM	T1,.EQLIM(J),OLIM	;GET PAGE LIMIT
	MOVEM	T1,J$RLIM(J)		;SAVE IT
	PUSHJ	P,ACTBEG		;GO SETUP THE ACCOUNTING PARMS
	PUSHJ	P,I%NOW			;GET TIME OF DAY
	MOVEM	S1,J$RTIM(J)		;SAVE IT AWAY
	MOVE	S1,STREAM		;GET STREAM NUMBER.
	$WTOJ  (Begin,<^R/.EQJBB(J)/>,@JOBOBA(S1))
	PUSHJ	P,TBFINI		;INITIALIZE THE BUFFER
	PUSHJ	P,CHKLPT		;GO MAKE SURE THE DEVICE IS ONLINE
	$RETT				;AND RETURN

SUBTTL	DOJOB -- Do the Job

DOJOB:	PUSHJ	P,FORMS			;GET FORMS MOUNTED
	JUMPF	ENDREQ			;CANT DO IT,,END THE REQUEST
	$CALL	CHKALN			;DO AN ALIGNMENT IF NEEDED
	PUSHJ	P,@J$BJOB(J)		;DO POSSIBLE FONT LOADS
	TXNE	S,RQB+ABORT		;JOB ABORTED?
	JRST	ENDJOB			;YES, FINISH UP
	LOAD	S1,.EQSEQ(J),EQ.IAS	;GET INVALID ACCOUNT STRING BIT
	STORE	S1,S,ABORT		;SAVE IT AS THE ABORT BIT
	TXO	S,BANHDR		;LITE 'PRINTING BANNERS' FLAG
	PUSHJ	P,JOBHDR		;PRINT THE BANNER
	TXZ	S,BANHDR		;CLEAR 'PRINTING BANNERS' FLAG
	LOAD	E,.EQLEN(J),EQ.LOH	;GET LENGTH OF HEADER
	ADD	E,J			;POINT TO FIRST FILE
	SETZM	J$RNFP(J)		;ZAP THE # OF FILES PRINTED
	TXO	S,INJOB			;We are in a job now
	SKIPN	.EQCHK+CKFLG(J)		;IS THIS A RESTARTED JOB?
	JRST	DOJO.4			;NO, SKIP ALL THIS STUFF
	MOVE	T1,.EQCHK+CKFIL(J)	;YES, GET NUMBER OF FILES DONE
	MOVEM	T1,J$RNFP(J)		;STORE FOR NEXT CHECKPOINT

DOJO.1:	SOJL	T1,DOJO.2		;DECREMENT AND JUMP IF SKIPED ENUF
	LOAD	S1,.FPINF(E),FP.FCY	;GET THE COPIES IN THIS REQUEST
	ADDM	S1,J$AFXC(J)		;ADD TO THE TOTAL COUNT
	PUSHJ	P,NXTFIL		;BUMP E TO NEXT SPEC
	JUMPF	DOJO.7			;FINISH OFF IF DONE
	JRST	DOJO.1			;LOOP SOME MORE

DOJO.2:	MOVE	S1,.EQCHK+CKCOP(J)	;GET NUMBER OF COPIES PRINTED
	MOVEM	S1,J$RNCP(J)		;SAVE FOR NEXT CHECKPOINT
	ADDM	S1,J$AFXC(J)		;ADD TO THE TOTAL FILE COUNT
	MOVE	S1,.EQCHK+CKTPP(J)	;GET THE TOTAL PAGES PRINTED.
	SUBI	S1,5			;MAKE SURE WE DONT SCREW THINGS UP
	SKIPGE	S1			;ALSO MAKE SURE WE ARE NOT NEGATIVE
	SETZM	S1			;YES, MAKE IT 0
	MOVEM	S1,J$APRT(J)		;AND SAVE IT
	MOVE	S1,.EQCHK+CKPAG(J)	;GET CHKPNT'ED PAGE
	SUBI	S1,5			;MAKE SURE WE DONT MISS ANYTHING !!
	SKIPGE	S1			;ALSO MAKE SURE WE ARE NOT NEGATIVE
	SETZM	S1			;YES, MAKE IT 0
	TXZE	S,BCKFIL		;WERE WE BACKSPACED DURING HEADERS ???
	TXZ	S,SKPFIL		;YES, CLEAR THE SKIP FILE BIT
	SKIPA				;Never use the /START param that follows

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

DOJO.4:	LOAD	S1,.FPFST(E)		;GET /START PARAMETER
	MOVEM	S1,J$FPIG(J)		;SAVE FOR FIRST COPY
	PUSHJ	P,FILE			;NO, PRINT THE FILE
	TXNE	S,RQB			;HAVE WE BEEN REQUEUED?
	JRST	ENDJOB			;YES, END NOW!!
	AOS	J$RNFP(J)		;BUMP THE FILE COUNT BY 1.
	MOVE	S1,STREAM		;Get the stream number
	SETZM	JOBCHK(S1)		;Want a checkpoint soon
	TXZE	S,BCKFIL		;BACKSPACING A FILE?
	JRST	DOJO.4			;YES
	PUSHJ	P,NXTFIL		;BUMP TO NEXT FILE
	JUMPT	DOJO.4			;AND LOOP

DOJO.7:	SKIPN	E,J$RLFS(J)		;GET ADR OF LOG-SPEC
	JRST	ENDJOB			;NO, FINISH JOB
	MOVE	S1,J$APRT(J)		;GET NUMBER OF PAGES PRINTED
	ADDI	S1,LOGPAG		;ADD IN GUARANTEED LOG LIMIT
	CAMLE	S1,J$RLIM(J)		;DOES HE HAVE AT LEAST THAT MANY?
	MOVEM	S1,J$RLIM(J)		;NO, GIVE HIM THAT MANY
	TXZ	S,ABORT			;CLEAR ABORT FLAG
	PUSHJ	P,FILE			;PRINT THE FILE
	JRST	ENDJOB			;AND FINISH UP

SUBTTL	NXTFIL -- FIND AND RETURN THE NEXT FILE IN THE NEXTJOB MSG


NXTFIL:	SETZM	J$RNCP(J)		;CLEAR COPIES PRINTED
	SOSG	J$RFLN(J)		;DECREMENT FILE COUNT
	$RETF				;NO MORE, DONE
	LOAD	S1,.FPLEN(E),FP.LEN	;GET THE FP LENGTH
	ADD	E,S1			;BUMP TO THE FD
	LOAD	S1,.FDLEN(E),FD.LEN	;GET THE FD LENGTH
	ADD	E,S1			;BUMP TO THE NEXT FP
	LOAD	S1,.FPINF(E),FP.FLG	;GET LOG FILE FLAG
	JUMPE	S1,.RETT		;RETURN IF NOT THE LOG FILE
	MOVEM	E,J$RLFS(J)		;SAVE ADDRESS OF LOG FILE SPEC
	JRST	NXTFIL			;AND LOOP
FILDIS:	LOAD	E,.EQLEN(J),EQ.LOH	;GET THE HEADER LENGTH.
	ADD	E,J			;POINT TO FIRST FILE .
	LOAD	T1,.EQSPC(J),EQ.NUM	;GET THE NUMBER OF FILES.
FILD.1:	MOVE	T2,.FPINF(E)		;GET THE FILE INFO BITS.
	LOAD	S2,.FPLEN(E),FP.LEN	;GET THE FILE INFO LENGTH.
	ADD	E,S2			;POINT TO FILE SPEC.
	MOVEM	E,J$XFOB+FOB.FD(J)	;SAVE THE FD ADDRESS IN THE FOB
	LOAD	S2,.FPLEN(E),FD.LEN	;GET THE FD LENGTH.
	ADD	E,S2			;POINT 'E' AT NEXT FILE.
	SETZM	J$XFOB+FOB.US(J)	;DEFAULT TO NO ACCESS CHECKING
	SETZM	J$XFOB+FOB.CD(J)	;HERE ALSO
	LOAD	S1,.EQSEQ(J),EQ.PRV	;GET THE USERS PRIVILGE BITS
	JUMPN	S1,FILD.2		;IF SET, AVOID ACCESS CHECK
	TXNE	T2,FP.SPL		;WAS IT A SPOOLED FILE ???
	JRST	FILD.2			;YES, THEN NO ACCESS CHECK
TOPS10<	MOVE	S1,.EQOID(J)		;GET THE PPN
	STORE	S1,J$XFOB+FOB.US(J)	;AND SAVE IT
>  ;END TOPS10 CONDITIONAL

TOPS20<	HRROI	S1,.EQOWN(J)		;GET THE OWNERS NAME
	STORE	S1,J$XFOB+FOB.US(J)	;SAVE IT
	HRROI	S1,.EQCON(J)		;GET CONNECTED DIRECTORY
	STORE	S1,J$XFOB+FOB.CD(J)	;AND SAVE IT
>  ;END TOPS20 CONDITIONAL

FILD.2:	MOVEI	S1,FOB.SZ		;GET THE FOB LENGTH
	MOVEI	S2,J$XFOB(J)		;AND THE FOB ADDRESS
	TXNE	T2,FP.SPL		;Spool file?
	JRST	FILD.3			;Yes, delete the file in any case
	TXNE	S,ABORT			;Is abort set?
	JRST	FILD.4			;Yes, skip deleting the file
	TXNE	T2,FP.DEL		;/delete?
FILD.3:	$CALL	F%DEL			;Yes, here to delete
FILD.4:	SOJG	T1,FILD.1		;GO PROCESS THE NEXT FILE.
	$RETT				;RETURN.

SUBTTL	FILE -- Print a File

FILE:	TXNE	S,ABORT			;ARE WE IN TROUBLE ???
	$RET				;YES, JUST RETURN.
	$CALL	LIMCHK			;Are we over limit?
	$RETIF				;Yes, just return
	PUSHJ	P,INPOPN		;OPEN THE INPUT FILE UP
	JUMPF	.POPJ			;LOSE, RETURN
	MOVE	S1,J$DFDA(J)		;GET FD ADDRESS
	PUSHJ	P,STRMNT		;MOUNT THE STR

;**;[2774] Change 1 line at FILE+8L. 26-Oct-83  /LWS
	$TEXT(LOGCHR,<^I/LPMSG/Starting File ^F/@J$DFDA(J)/^T/J$GSPL(J)/>) ;[2774]

FILE.1:	PUSHJ	P,INPREW		;REWIND THE INPUT FILE
	JUMPF	FILE.2			;DRIVER SAID NOT TO PROCESS FILE
	MOVE	S1,STREAM		;Get the stream number
	SETZM	JOBCHK(S1)		;Want a checkpoint
	$CALL	DSTATUS			;Do the status
	PUSHJ	P,SETLST		;SETUP /REPORT CODE IF NECESSARY
	TXZ	S,FORWRD		;CLEAR FORWARD SPACE BIT
	TXO	S,BANHDR		;LITE 'PRINTING HEADERS' FLAG
	PUSHJ	P,HEAD			;PRINT THE HEADER
	TXZ	S,BANHDR		;CLEAR 'PRINTING HEADERS' FLAG
	MOVEI	S1,LPTERR		;GET NUMBER OF DEVICE ERRORS ALLOWED
	MOVEM	S1,J$LERR(J)		;AND SAVE IT
	SOSLE	J$FPIG(J)		;SUBTRACT 1 PAGE FROM STARTING PAGE #.
;**;[4005]ADD 3 LINES AT FILE.1:+12L	13-MAY-85/CTK
	 JRST	[TXO	S,FORWRD	;[4005]POSITIVE,,TURN ON FORWARD BIT.
		MOVE	S1,J$FPIG(J)	;[4005]GET STARTING PAGE
		JRST	.+1]		;[4005]AND CONTINUE
	TXNE	S,ABORT!SKPFIL!RQB	;DO WE REALLY WANT TO DO THIS ???
	JRST	FILE.2			;NO, CLEAN UP THE MESS.
	PUSHJ	P,@J$BFIL(J)		;DO BEGINING OF FILE PROCESSING
	JUMPF	FILE.2			;ERROR MEANS WE SHOULD ABORT THE FILE
	PUSHJ	P,FILOUT		;PRINT THE FILE
	TXNE	S,ABORT!SKPFIL!RQB	;ABORTED OR SKIPPED OR REQUEUED?
	JRST	FILE.2			;YES, CONTINUE ON
	LOAD	T1,.FPFST(E)		;GET /START PARAMETER.
	MOVEM	T1,J$FPIG(J)		;SAVE STARTING POINT FOR THIS COPY.
	AOS	S1,J$RNCP(J)		;INCREMENT AND LOAD COPIES WORD
	AOS	J$AFXC(J)		;ADD 1 TO THE TOTAL FILE COUNT
	PUSHJ	P,@J$EFIL(J)		;DO END OF FILE PROCESSING
	JUMPF	FILE.2			;DRIVER SAID NO MORE
	LOAD	S2,.FPINF(E),FP.FCY	;GET TOTAL NUMBER TO PRINT
	CAML	S1,S2			;PRINTED ENOUGH?
	JRST	FILE.2			;Yes, go finish
	$CALL	LIMCHK			;Check to see if over limit
	JUMPT	FILE.1			;If not, loop

FILE.2:	SKIPE	S1,J$DIFN(J)		;GET THE IFN
	PUSHJ	P,F%REL			;RELEASE IT
	SETZM	J$DIFN(J)		;Clear the IFN
;**;[2774] Changed 1 line at FILE.2+3L. 25-Oct-83  /LWS
	$TEXT (LOGCHR,<^I/LPMSG/Finished File ^F/@J$DFDA(J)/^T/J$GSPL(J)/>) ;[2774]
	MOVE	S1,J$DFDA(J)		;GET FD ADDRESS
	PUSHJ	P,STRDMO		;DISMOUNT THE STR
	TXNE	S,SUPFIL		;Are we suppressing forms/file?
	SETZM	J$XTOP(J)		;Yes, set we are not at top of page.
	TXZ	S,SKPFIL+SUPFIL		;CLEAR LOTS OF BITS
	POPJ	P,			;AND RETURN

SUBTTL	ENDJOB -- END OF JOB PROCESSOR.

ENDJOB:	TXO	S,GOODBY		;FLAG EOJ SEQUENCE
	TXZ	S,FORWRD		;TURN OFF THE FORWARD SPACING BIT.
	$TEXT	(LOGCHR,<^I/LPEND/Summary:^D5/J$APRT(J)/ Pages of Output>)
	$TEXT	(LOGCHR,<^I/LPEND/        ^D5/J$ADRD(J)/ Disk Blocks Read>)
	PUSHJ	P,@J$EJOB(J)		;DO END OF JOB PROCESSING
	PUSHJ	P,JOBTRL		;PRINT THE JOB TRAILERS.
	PUSHJ	P,@J$EOF(J)		;FORCE ALL DATA OUT

ENDREQ:	PUSHJ	P,QRELEASE		;GO SEND THE RELEASE/REQUEUE MSG.
	SETZM	J$RACS+S(J)		;CLEAR ALL THE STATUS BITS.
	MOVE	S1,STREAM		;GET STREAM NUMBER
	SETZM	JOBACT(S1)		;NOT BUSY
	JRST	MAIN.3			;RETURN TO THE SCHEDULER.

SUBTTL	QRELEASE -- ROUTINE TO SEND A REQUEUE/RELEASE MSG TO QUASAR.

QRELEA:	MOVE	S1,STREAM		;GET THE STREAM NUMBER.
	$WTOJ	(End,<^R/.EQJBB(J)/>,@JOBOBA(S1)) ;TELL THE OPERATOR.
	$LOG	(Printed ^D/J$APRT(J)/ Pages,,@JOBOBA(S1)) ;LOG # OF PAGES
	MOVEI	S1,MSBSIZ		;GET BLOCK LENGTH
	MOVEI	S2,MSGBLK		;AND THE ADDRESS
	PUSHJ	P,.ZCHNK		;ZERO THE BLOCK
	TXNE	S,RQB			;IS THIS A REQUEUE?
	JRST	RELE.1			;YES
	PUSHJ	P,FILDIS		;GO CLEAN UP THE SPOOL FILES.
	PUSHJ	P,ACTEND		;GO DO THE ACCOUNTING
	MOVEI	T1,MSGBLK		;GET ADDRESS OF THE BLOCK
	LOAD	S1,.EQITN(J)		;GET THE ITN
	STORE	S1,REL.IT(T1)		;STORE IT
	MOVEI	S1,0			;CLEAR FLAGS
	TXNE	S,ABORT			;ABORTING JOB?
	TXO	S1,RF.ABO		;YES--TELL QUASAR
	MOVEM	S1,REL.FL(T1)		;SAVE IN MESSAGE
	TXNE	S,ABORT			;CHECK AGAIN
	$TEXT	(<-1,,REL.TX(T1)>,<^T/J$WTOR(J)/^0>) ;ADD OPR TEXT FOR /NOTIFY
	MOVX	S1,REL.SZ		;NO, GET RELEASE MESSAGE SIZE
	MOVX	S2,.QOREL		;AND FUNCTION
	JRST	RELE.2			;AND MEET AT THE PASS

RELE.1:	MOVEI	T1,MSGBLK		;GET ADDRESS OF THE BLOCK
	LOAD	S1,.EQITN(J)		;GET THE ITN
	STORE	S1,REQ.IT(T1)		;STORE IT
	LOAD	S1,J$RNFP(J)		;GET NUMBER OF FILES PRINTED
	STORE	S1,REQ.IN+CKFIL(T1)	;STORE IT
	LOAD	S1,J$RNCP(J)		;GET COPIES PRINTED
	STORE	S1,REQ.IN+CKCOP(T1)	;STORE IT
	LOAD	S1,J$RNPP(J)		;GET PAGES PRINTED
	STORE	S1,REQ.IN+CKPAG(T1)	;AND STORE IT
	LOAD	S1,J$APRT(J)		;GET TOTAL PAGES PRINTED.
	STORE	S1,REQ.IN+CKTPP(T1)	;STORE IT
	MOVX	S1,CKFREQ		;GET REQEUE BIT
	STORE	S1,REQ.IN+CKFLG(T1)	;STORE IT
	MOVX	S1,RQ.HBO		;GET HOLD BY OPERATOR
	STORE	S1,REQ.FL(T1)		;STORE IN FLAG WORD
	MOVX	S1,REQ.SZ		;GET SIZE
	MOVX	S2,.QOREQ		;AND FUNCTION

RELE.2:	STORE	S1,.MSTYP(T1),MS.CNT	;STORE SIZE
	STORE	S2,.MSTYP(T1),MS.TYP	;AND CODE
	PUSHJ	P,SNDQSR		;SEND IT TO QUASAR
	$RETT				;AND RETURN.

SUBTTL	CHKQUE -- ROUTINE TO RECIEVE AND SCHEDULE IPCF MESSAGES

CHKQUE:	SETZM	MESSAG			;NO MESSAGE YET
	PUSHJ	P,C%RECV		;RECEIVE A MESSAGE
	JUMPF	.POPJ			;RETURN,,NOTHING THERE.
	SETOM	IMESS			;Have a message
	SETZM	BLKADR			;CLEAR THE IPCF MSG BLK ADDR SAVE AREA
	LOAD	S2,MDB.SI(S1)		;GET SPECIAL INDEX WORD
	TXNN	S2,SI.FLG		;IS THERE AN INDEX THERE?
	JRST	CHKQ.7			;NO, IGNORE IT
	ANDX	S2,SI.IDX		;AND OUT THE INDEX
	CAIE	S2,SP.OPR		;IS IT FROM OPR?
	CAIN	S2,SP.QSR		;IS IT FROM QUASAR?
	SKIPA				;Yes, continue on
	JRST	CHKQ.7			;Go to release the message
CHKQ.2:	LOAD	M,MDB.MS(S1),MD.ADR	;GET THE MESSAGE ADDRESS
	MOVEM	M,MESSAG		;SAVE IT AWAY
	LOAD	S2,.MSTYP(M),MS.TYP	;GET THE MESSAGE TYPE
	MOVSI	S1,-NMSGT		;MAKE AOBJN POINTER FOR MSG TYPES
CHKQ.3:	HRRZ	T1,MSGTAB(S1)		;GET A MESSAGE TYPE
	CAMN	S2,T1			;MATCH?
	JRST	CHKQ.6			;YES, WIN
	AOBJN	S1,CHKQ.3		;NO, LOOP
	PUSH	P,P1			;SAVE P1
	MOVE	P1,DEVLST		;POINT TO START OF DEVICE DRIVER CHAIN
CHKQ.4:	PUSHJ	P,@J$IPCF-J$$DEV(P1)	;TRY TO PROCESS THE MESSAGE
	JUMPT	CHKQ.5			;JUMP IF PROCESSED OK
	SKIPE	P1,0(P1)		;POINT TO NEXT DRIVER
	JRST	CHKQ.4			;LOOP BACK
CHKQ.5:	POP	P,P1			;RESTORE P1
	JRST	CHKQ.7			;GO TO RELEASE THE MESSAGE
CHKQ.6:	HLRZ	T2,MSGTAB(S1)		;PICK UP THE PROCESSING ROUTINE ADDRESS
	MOVEM	T2,RUTINE		;SAVE THE ROUTINE ADDRESS.
	PUSHJ	P,CHKOBJ		;GO FIND THE OBJECT BLOCK.
	JUMPF	CHKQ.7			;NOT THERE,,JUST DELETE IT
	PUSHJ	P,@RUTINE		;DISPATCH THE MESSAGE PROCESSOR.
	SKIPN	JOBITS			;DO WE WANT TO SAVE THE STATUS BITS ??
	MOVEM	S,J$RACS+S(J)		;YES, SAVE THE STATUS BITS.
	SETZM	JOBITS			;CLEAR FLAG (DEFAULT TO ALWAYS SAVE)
CHKQ.7:	SKIPE	IMESS			;Any IPCF messages?
	$CALL	C%REL			;Yes, release it
	SETZM	IMESS			;Remember we have released it
	POPJ	P,			;RETURN TO THE SCHEDULER.

MSGTAB:	XWD	KILL,.QOABO		;ABORT MESSAGE
	XWD	DSTATUS,.QORCK		;REQUEST-FOR-CHECKPOINT
	XWD	NXTJOB,.QONEX		;NEXTJOB
	XWD	SETUP,.QOSUP		;SETUP/SHUTDOWN
	XWD	OACCON,.OMCON		;OPERATOR CONTINUE REQUEST.
	XWD	OACRSP,.OMRSP		;OPERATOR WTOR RESPONSE.
	XWD	OACREQ,.OMREQ		;OPERATOR REQUEUE REQUEST.
	XWD	OACCAN,.OMCAN		;OPERATOR CANCEL REQUEST.
	XWD	OACPAU,.OMPAU		;OPERATOR PAUSE/STOP REQUEST.
	XWD	OACFWS,.OMFWS		;OPERATOR FORWARD SPACE REQUEST.
	XWD	OACALI,.OMALI		;OPERATOR ALIGN REQUEST.
	XWD	OACSUP,.OMSUP		;OPERATOR SUPPRESS REQUEST.
	XWD	OACBKS,.OMBKS		;OPERATOR BACKSPACE REQUEST.
	XWD	QSRNWA,.QONWA		;QUASAR NODE-WENT-AWAY MESSAGE
	XWD	FORFOR,.QOFCH		;FORCE FORMS MESSAGE

	NMSGT==.-MSGTAB
SUBTTL	CHKOBJ -- ROUTINE TO VALIDATE QUASAR/ORION/OPR MSG OBJ BLKS.

	;CALL:  S1/OFFSET INTO MSGTAB
	;	S2/MESSAGE TYPE
	;
	;RET:	STREAM/STREAM NUMBER
	;	J/DATA BASE ADDRESS
	;	S/STATUS BITS


CHKOBJ:	CAIE	S2,.OMRSP		;IS THIS AN OPERATOR RESPONSE ???
	CAIN	S2,.QOSUP		;IS THIS A SETUP/SHUTDOWN MESSAGE ??
	$RETT				;YES, JUST RETURN NOW.
	CAIN	S2,.OMDSP		;IS THIS A DN60 OPERATOR RESPONSE ???
	$RETT				;YES, JUST RETURN NOW.
	CAIE	S2,.QOFCH		;Is it forms change message?
	CAIL	S2,.OMOFF		;IS THIS AN OPR/ORION MSG ??
	JRST	CHKO.1			;YES, GO SET UP THE OBJ SEARCH.
	XCT	MSGOBJ(S1)		;GET THE OBJ BLK ADDRESS.
	JRST	CHKO.2			;LETS MEET AT THE PASS.

CHKO.1:	PUSHJ	P,GETBLK		;GET A MESSAGE BLOCK
	JUMPF	.RETF			;NO MORE, THATS AN ERROR
	CAIE	T1,.OROBJ		;IS THIS THE OBJECT BLOCK ???
	JRST	CHKO.1			;NO, GET THE NEXT MSG BLOCK
	MOVE	S1,T3			;GET THE BLOCK DATA ADDRESS IN S1.

CHKO.2:	PUSHJ	P,FNDOBJ		;GO FIND THE OBJECT BLOCK.
	JUMPF	.RETF			;NOT THERE,,THATS AN ERROR.
	$RETT				;RETURN.

MSGOBJ:	MOVEI	S1,ABO.TY(M)		;GET ABORT MSG OBJ ADDRESS.
	MOVEI	S1,RCK.TY(M)		;GET CHECKPOINT MSG OBJ ADDRESS.
	MOVEI	S1,.EQROB(M)		;GET NEXTJOB MSG OBJ ADDRESS.

SUBTTL	GETBLK -- ROUTINE TO BREAK DOWN AN IPCF MSG INTO ITS DATA BLOCKS

	;CALL:	M/ MESSAGE ADDRESS
	;
	;RET:	T1/ BLOCK TYPE
	;	T2/ BLOCK LENGTH
	;	T3/ BLOCK DATA ADDRESS

GETBLK:	SOSGE	.OARGC(M)		;SUBTRACT 1 FROM THE BLOCK COUNT
	$RETF				;NO MORE, RETURN
	SKIPN	S1,BLKADR		;GET THE PREVIOUS BLOCK ADDRESS
	MOVEI	S1,.OHDRS+ARG.HD(M)	;NONE THERE,,GET FIRST 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,BLKADR		;SAVE IT FOR THE NEXT CALL
	$RETT				;RETURN TO THE CALLER

SUBTTL	KILL -- User CANCEL Request

KILL:	TXNE	S,GOODBY+ABORT		;CHECK SOME BITS
	$RETT				;IF WE LEAVING, IGNORE IT ANYWAY
	$TEXT(LOGCHR,<^I/LPMSG/Job canceled by user ^U/ABO.ID(M)/>)
	MOVE	S1,STREAM		;GET THE STREAM NUMBER.
	MOVX	S2,PSF%OR		;GET OPR RESP WAIT BIT
	TDNE	S2,JOBSTW(S1)		;ARE WE WAITING FOR THE OPERATOR ???
	$KWTOR	(JOBWAC(S1))		;YES, KILL THE WTOR
	ANDCAM	S2,JOBSTW(S1)		;ZAP THE OPR WAIT BIT
	$WTOJ	(<Canceled by User ^U/ABO.ID(M)/>,<^R/.EQJBB(J)/>,@JOBOBA(S1))
	$TEXT	(<-1,,J$WTOR(J)>,<Canceled by User ^U/ABO.ID(M)/^0>)
	TXO	S,ABORT			;LITE THE ABORT BIT
	PUSHJ	P,INPFEF		;FORCE END OF FILE
	TXNE	S,BANHDR		;ARE WE PRINTING BANNER/HEADER PAGES?
	$RETT				;YES, JUST RETURN
	PUSHJ	P,@J$FLSH(J)		;FLUSH THE OUTPUT BUFFERS
	JUMPF	SHUTND			;CANT,,SHUT IT DOWN !!!
	$RETT				;RETURN
SUBTTL	QSRNWA - ROUTINE TO SHUTDOWN A STREAM WHOSE NODE HAS DROPPED

QSRNWA:	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	MOVX	S2,PSF%OR		;GET OPR RESP WAIT BIT
	TDNE	S2,JOBSTW(S1)		;ARE WE WAITING FOR THE OPERATOR ???
	$KWTOR	(JOBWAC(S1))		;YES, KILL THE WTOR
	SKIPE	S1,J$DIFN(J)		;GET THE IFN
	PUSHJ	P,F%REL			;YES, CLOSE IT
	SETZM	J$DIFN(J)		;Clear the IFN
	MOVX	S1,%RSUNA		;GET NOT AVAILABLE RIGHT NOW BITS
	PUSHJ	P,RSETUP		;TELL QUASAR HE CAN HAVE THE OBJ BACK
	PUSHJ	P,SHUTND		;SHUT THE STREAM DOWN
	$RETT				;AND RETURN

SUBTTL	DSTATUS -- Send status info

COMMENT \
	The purpose of this routine is to provide a uniform means
of handling checkpointing within a stream.  It decides whether to
send status messages.

There are 2 kinds of messages.  UPDATE is an update status message
and is sent every time the actual status of the stream changes.
CHKPNT is a checkpoint message that describes the current state
of the job on the stream.

UPDATE is called based on JOBUPD.

CHKPNT is called based on JOBCHK or elapsed time since last CHKPNT.  The
time till next checkpoint is set if called.  If JOBCHK is 0, CHKPNT
is always called.

THIS IS THE ONLY ROUTINE THAT SHOULD CALL UPDATE OR CHKPNT!

	No parameters are passed.
	Always returns $RET.  (Cannot fail)

\	;End of comment

DSTATUS:$SAVE	<P1,P2>			;Save 2 perm. registers
	MOVE	P1,STREAM		;Get the stream number

	SKIPE	JOBUPD(P1)		;Do we need status update?
	$CALL	UPDATE			;Do the status update
	SETZM	JOBUPD(P1)		;Turn flag off

	SKIPN	JOBACT(P1)		;Nothing to checkpoint if not active!
	$RET

	$CALL	I%NOW			;Find the time
	MOVE	P2,S1			;Save the time
	SUB	S1,JOBCHK(P1)		;current time - time to checkpoint
	SKIPGE	S1			;Time to checkpoint yet?
	$RET				;No.

	TXNE	S,INJOB			;Are we in a JOB?
	$CALL	CHKPNT			;Yes, do the checkpoint
	ADDI	P2,CKPTIM*3		;Add number of 1/3s of seconds
					;  to the current time
	MOVEM	P2,JOBCHK(P1)		;Save the time to do next chkpoint
	$RET
SUBTTL	CHKPNT -- Request for Checkpoint

COMMENT	\
This routine is to checkpoint the currently active job on the current stream.
It should only be called by DSTATUS since that routine will verify that the
stream is currently active.  DSTATUS will also update the time for the next
checkpoint to occur.
\

CHKPNT:	MOVEI	T1,MSGBLK		;LOAD THE ADDRESS OF THE MESSAGE BLK.
	MOVX	S1,CH.FST		;REQUEST STATUS UPDATE
	SKIPE	J$POSF(J)		;DRIVER ALLOW FILE POSITIONING?
	TXO	S1,CH.FCH		;YES--REQUEST CHECKPOINTING TOO
	STORE	S1,CHE.FL(T1)		;AND STORE THEM
	MOVE	S1,J$RNFP(J)		;GET NUMBER OF FILES
	MOVEM	S1,CHE.IN+CKFIL(T1)	;STORE IT
	MOVE	S1,J$RNCP(J)		;GET NUMBER OF COPIES
	MOVEM	S1,CHE.IN+CKCOP(T1)	;AND STORE IT
	MOVE	S1,J$RNPP(J)		;GET NUMBER OF PAGES
	MOVEM	S1,CHE.IN+CKPAG(T1)	;AND STORE IT
	MOVE	S1,J$APRT(J)		;NUMBER OF PAGES PRINTED
	MOVEM	S1,CHE.IN+CKTPP(T1)	;AND STORE IT
	LOAD	S1,.EQITN(J)		;GET JOBS ITN
	MOVEM	S1,MSGBLK+CHE.IT	;AND STORE IT
	MOVX	S1,CKFCHK		;CHKPOINT FLAG
	MOVEM	S1,CHE.IN+CKFLG(T1)	;STORE IT

	MOVEI	S1,CHE.ST(T1)		;GET ADDRESS OF STATUS AREA
	HRLI	S1,(POINT 7,0)		;MAKE IT A BYTE POINTER
	MOVEM	S1,TEXTBP		;SAVE BYTE POINTER
	$TEXT(DEPBP,<Started at ^C/J$RTIM(J)/^A>) ;START STATUS MESSAGE
	PUSHJ	P,@J$STST(J)		;FINISH STATUS MESSAGE
	HRRZ	S1,TEXTBP		;GET THE BYTE POINTER
	SUBI	S1,MSGBLK-1		;SUBTRACT START POINT
	STORE	S1,.MSTYP(T1),MS.CNT	;SAVE THE LENGTH
	MOVX	S1,.QOCHE		;GET THE FUNCTION CODE
	STORE	S1,.MSTYP(T1),MS.TYP
	PJRST	SNDQSR			;AND SEND IT

LPTSTS::$TEXT	(DEPBP,<, printed ^D/J$APRT(J)/ of ^D/J$RLIM(J)/ pages^0>)
	POPJ	P,			;RETURN
SUBTTL	UPDATE -- ROUTINE TO SEND STATUS UPDATES TO QUASAR

COMMENT \
This routine sends a status update message to QUASAR.  It should only
be called by DSTATUS since it depends on DSTATUS to clear the status
request flag and P1 is set by DSTATUS to contain the stream number.
\

UPDATE:	MOVE	S2,JOBPAG(P1)		;Get the jobpage
	MOVE	S2,JOBSTW(P1)		;GET THE JOBS STATUS WORD
	MOVX	S1,%RESET		;DEFAULT TO RESET
	SKIPE	J$APRG(J)		;ARE WE ALIGNING FORMS ???
	MOVX	S1,%ALIGN		;YES, SAY SO
	TXNE	S2,PSF%OR		;ARE WE WAITING FOR OPR RESPONSE ???
	MOVX	S1,%OREWT		;YES, SAY SO
	TXNE	S2,PSF%ST		;ARE WE STOPPED ???
	MOVX	S1,%STOPD		;YES, SAY SO
	TXNE	S2,PSF%MW		;ARE WE IN MOUNT WAIT?
	MOVX	S1,%MWAIT		;YES, SAY SO
	TXNE	S2,PSF%DO		;ARE WE OFFLINE ???
	MOVX	S1,%OFLNE		;YES, SAY SO
	TXNE	S2,PSF%OO		;ARE WE WAITING FOR OPERATOR OUTPUT ???
	MOVX	S1,%OPRWT		;YES, SAY SO
	MOVEI	T1,MSGBLK		;GET THE MESSAGE BLOCK ADDRESS
	MOVEM	S1,STU.CD(T1)		;SAVE THE STATUS
	HRLZ	S1,JOBOBA(P1)		;GET THE OBJECT BLOCK ADDRESS
	HRRI	S1,STU.RB(T1)		;GET DESTINATION ADDRESS
	BLT	S1,STU.RB+OBJ.SZ-1(T1)	;COPY THE OBJ BLK OVER TO THE MSG
	MOVX	S1,STU.SZ		;GET THE MESSAGE LENGTH
	STORE	S1,.MSTYP(T1),MS.CNT	;SAVE IT
	MOVX	S1,.QOSTU		;GET THE MESSAGE TYPE
	STORE	S1,.MSTYP(T1),MS.TYP	;SAVE IT
	PUSHJ	P,SNDQSR		;SEND IT OFF TH QUASAR
	$RETT				;AND RETURN
SUBTTL	SETUP/SHUTDOWN Message processing

SETUP:	LOAD	S1,SUP.FL(M)		;GET THE FLAGS
	TXNE	S1,SUFSHT		;IS IT A SHUTDOWN?
	JRST	SHUTDN			;IF SO,,SHUT IT DOWN !!!
	SETZ	T2,			;CLEAR A LOOP REG

SETU.1:	SKIPN	JOBPAG(T2)		;A FREE STREAM?
	JRST	SETU.2			;YES!!
	CAIGE	T2,NPRINT-1		;NO, LOOP THRU THEM ALL?
	AOJA	T2,SETU.1		;NO, KEEP GOING
	$STOP(TMS,Too many setups)

SETU.2:	MOVEM	T2,STREAM		;SAVE THE STREAM NUMBER
	MOVEI	S1,J$$END		;GET THE LPT DATA BASE LENGTH
	ADDI	S1,PAGSIZ-1		;ROUND UP TO NEXT HIGHEST PAGE
	IDIVI	S1,PAGSIZ		;GET NUMBER OF PAGES IN S1
	PUSHJ	P,M%AQNP		;ALLOCATE THEM
	PG2ADR	S1			;CONVERT TO AN ADDRESS
	MOVEM	S1,JOBPAG(T2)		;AND SAVE IT
	MOVE	J,S1			;PUT IT IN J
	SETZM	JOBSTW(T2)		;CLEAR THE JOB STATUS WORD
	MOVEM	J,J$RACS+J(J)		;SAVE J AWAY
	MOVEI	S1,J$LBFR(J)		;LPT BUFFER ADDRESS
	MOVEM	S1,J$LBUF(J)		;STORE IT
	MOVEI	S1,J$GBFR(J)		;LOG FILE BUFFER PAGE (FIRST)
	MOVEM	S1,J$GBUF(J)		;SAVE IT AWAY
	MOVE	S2,T2			;COPY OVER THE STREAM NUMBER
	IMULI	T2,OBJ.SZ		;GET OFFSET OF OBJECT BLOCK
	ADDI	T2,JOBOBJ		;ADD IN THE BASE
	MOVEM	T2,JOBOBA(S2)		;STORE OBJECT ADDRESS
	MOVE	S2,T2			;GET DESTINATION OF BLT INTO S2
	HRLI	S2,SUP.TY(M)		;MAKE A BLT POINTER
	BLT	S2,OBJ.SZ-1(T2)		;BLT THE OBJECT BLOCK

	SETZM	J$LREM(J)		;DEFAULT TO LOCAL LPT
	MOVE	S1,SUP.NO(M)		;GET THIS GUYS NODE NAME
	CAME	S1,CNTSTA		;IS IT A LOCAL LPT ???
	SETOM  J$LREM(J)		;NO--MAYBE ANF REMOTE
	MOVSI	S1,J$DWDS(J)		;START OF DRIVER DATA
	HRRI	S1,J$DWDS+1(J)		;MAKE A BLT POINTER
	SETZM	J$DWDS(J)		;CLEAR FIRST WORD
	BLT	S1,J$DWDS+DRVWDS-1(J)	;CLEAR ENTIRE BLOCK

	;Continued on the next page
	;Continued from the previous page

SETU.3:	SETOM	J$LCHN(J)		;INDICATE NO OUTPUT CHANNEL YET.
	MOVE	P1,DEVLST		;POINT TO START OF DEVICE DRIVER CHAIN

SETU.4:	PUSHJ	P,@J$INIT-J$$DEV(P1)	;INITIALIZE
	JUMPT	SETU.6			;ALL SET
	JUMPL	S1,SETU.5		;JUMP IF NOT FOR THIS DRIVER
	PUSH	P,S1			;SAVE RESPONSE TO SETUP CODE
	JRST	SETU.7			;AND GO AWAY

SETU.5:	SKIPE	P1,(P1)			;POINT TO NEXT DRIVER
	JRST	SETU.4			;LOOP BACK
	PUSH	P,[%RSUNA]		;SAY DEVICE NOT AVAILABLE RIGHT NOW
	JRST	SETU.7			;GO CLEAN UP

SETU.6:	PUSHJ	P,@J$OPEN(J)		;OPEN CHANNEL FOR OUTPUT
	PUSH	P,S1			;SAVE RESPONSE TO SETUP CODE
	MOVE	S1,STREAM		;GET STREAM NUMBER
	AOS	S2,STRSEQ		;ADD 1 TO THE STREAM SEQ #, PUT IN S2.
	MOVEM	S2,JOBWAC(S1)		;SAVE IT AS THE OPR WTOR ACK CODE.
	MOVE	S1,(P)			;GET RESPONSE CODE BACK

SETU.7:	MOVE	S1,(P)			;GET RESPONSE TO SETUP CODE
	PUSHJ	P,RSETUP		;TELL QUASAR WHAT'S GOING ON
	MOVE	S1,STREAM		;GET STREAM NUMBER
	POP	P,S2			;AND RESPONSE CODE AGAIN
	$WTO	(<^T/@SETMSG(S2)/>,,@JOBOBA(S1))
	CAIE	S2,%RSUOK		;ALL IS OK?
	$CALL	SHUTND			;NO, SHUT IT DOWN
	$RETT
SUBTTL	SHUTDN -- ROUTINE TO SHUT DOWN A LINE-PRINTER


SHUTDN:	MOVEI	S1,SUP.TY(M)		;GET THE OBJECT BLOCK ADDRESS
	PUSHJ	P,FNDOBJ		;FIND THE OBJECT BLOCK
	JUMPF	.RETT			;NO OBJECT,,THEN NOTHING TO SHUT DOWN
SHUTND::SKIPA	T4,[EXP 0]		;INDICATE 'OUT OF STREAM' CONTEXT
SHUTIN::SETOM	T4			;INDICATE 'IN STREAM' CONTEXT
	SKIPL	J$LCHN(J)		;DO WE HAVE AN OUTPUT CHANNEL ???
	PUSHJ	P,@J$CLOS(J)		;YES, RELEASE THE OBJECT
	SKIPE	S1,J$DIFN(J)		;Get the IFN
	PUSHJ	P,F%REL			;YES, CLOSE IT
	SETZM	J$DIFN(J)		;Clear the IFN
	SKIPE	T4			;ARE WE IN STREAM CONTEXT ???
	MOVE	P,[IOWD PDSIZE,PDL]	;YES, GET A NEW STACK POINTER
	SKIPE	J$SHUT(J)		;Device initialized yet?
	PUSHJ	P,@J$SHUT(J)		;YES, HANDLE DEVICE SPECIFIC SHUTDOWN
	MOVEI	S1,J$$END		;GET THE LPT DATA BASE LENGTH
	ADDI	S1,PAGSIZ-1		;ROUND UP TO NEXT HIGHEST PAGE
	IDIVI	S1,PAGSIZ		;GET NUMBER OF PAGES IN S1
	MOVE	S2,J			;GET THE JOBPAG ADDRESS
	ADR2PG	S2			;CONVERT TO A PAGE NUMBER
	PUSHJ	P,M%RLNP		;RETURN THEM
	PUSHJ	P,M%CLNC		;GET RID OF UNWANTED PAGES.
	SETOM	JOBITS			;SAY WE DONT WANT TO SAVE STATUS BITS.
	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	SETZM	JOBPAG(S1)		;CLEAR THE PAGE WORD
	SETZM	JOBACT(S1)		;AND THE ACTIVE WORD
	MOVX	S2,PSF%OR		;GET OPR RESP WAIT BIT
	TDNE	S2,JOBSTW(S1)		;ARE WE WAITING FOR THE OPERATOR ???
	$KWTOR	(JOBWAC(S1))		;YES, KILL THE WTOR
	SETZM	JOBWAC(S1)		;Clear it just in case
	JUMPE	T4,.RETT		;'OUT OF STREAM',,JUST RETURN
	JRST	MAIN.3			;'IN STREAM',,RETURN TO THE SCHEDULER
SUBTTL	RSETUP -- ROUTINE TO SEND A RESPONSE-TO-SETUP MSG TO QUASAR

RSETUP::MOVE	T2,S1			;SAVE THE SETUP CONDITION CODE.
	MOVEI	S1,RSU.SZ		;GET MESSAGE LENGTH
	MOVEI	S2,MSGBLK		;AND THE ADDRESS OF THE BLOCK
	PUSHJ	P,.ZCHNK		;ZERO IT OUT
	MOVEI	T1,MSGBLK		;GET THE BLOCK ADDRESS
	MOVX	S1,RSU.SZ		;GET MESSAGE SIZE
	STORE	S1,.MSTYP(T1),MS.CNT	;STORE IT
	MOVX	S1,.QORSU		;GET FUNCTION CODE
	STORE	S1,.MSTYP(T1),MS.TYP	;STORE IT
	MOVE	S1,STREAM		;GET STREAM NUMBER
	MOVS	S1,JOBOBA(S1)		;GET OBJADR,,0
	HRRI	S1,RSU.TY(T1)		;AND PLACE TO MOVE IT TO
	BLT	S1,RSU.TY+OBJ.SZ-1(T1)	;AND MOVE THE OBJECT BLOCK
	STORE	T2,RSU.CO(T1)		;STORE THE RESPONSE CODE
	MOVX	S1,%LOWER		;GET LOWER-CASE BIT
	SKIPL	J$LLCL(J)		;IS PRINT LOWER CASE?
	MOVX	S1,%UPPER		;NO, LOAD THE UPPER CASE FLAG
	STORE	S1,RSU.DA(T1),RO.ATR	;STORE THE DEVICE ATRRIBUTES
	MOVE	S1,J$LTYP(J)		;GET SIXBIT UNIT TYPE
	MOVEM	S1,RSU.UT(T1)		;SAVE IN MESSAGE
	PUSHJ	P,SNDQSR		;AND SEND THE MESSAGE
	$RETT				;RETURN.

SUBTTL	OACRSP -- OPERATOR RESPONSE TO A WTOR PROCESSOR.

OACRSP:	SETOM	JOBITS			;DON'T UPDATE STATUS BITS
	MOVE	S2,.MSCOD(M)		;GET WTOR ACK CODE.
	MOVSI	S1,-NPRINT		;CREATE AOBJN AC.
RESP.1:	CAME	S2,JOBWAC(S1)		;COMPARE ACK CODES..
	JRST	[AOBJN S1,RESP.1	;NOT EQUAL,,CHECK NEXT STREAM.
		 $RETT	]		;NOT THERE,,FLUSH THE MSG.
	MOVX	S2,PSF%OR		;GET "OPERATOR-RESPONSE" WAIT BIT
	ANDCAM	S2,JOBSTW(S1)		;AND CLEAR IT
	SETOM	JOBUPD(S1)		;Update the stream's status
	MOVE	J,JOBPAG(S1)		;GET THE STREAM DB ADDRESS.
	DMOVE	S1,.OHDRS+ARG.DA(M)	;GET THE OPERATORS RESPONSE.
	DMOVEM	S1,J$RESP(J)		;AND SAVE IT.
	$RETT				;AND RETURN

SUBTTL OACCAN -- Operator CANCEL request.

OACCAN:	PUSHJ	P,.SAVE1		;SAVE P1 FOR A MINUTE
	MOVE	P1,STREAM		;GET STREAM NUMBER.
	$ACK  (Aborting,<^R/.EQJBB(J)/>,@JOBOBA(P1),.MSCOD(M)) ;TELL THE OPR.
	SETZM	J$APRG(J)		;ALIGNMENT NOT SCHEDULED,,NOT ACTIVE !!
	SETZM	JOBWKT(P1)		;SET WAKE UP TIME TO NOW.
	SETZM	RSNFLG			;SHOW NO REASON GIVEN.
	MOVX	S1,PSF%OR		;GET OPR RESP WAIT BIT
	TDNE	S1,JOBSTW(P1)		;ARE WE WAITING FOR THE OPERATOR ???
	$KWTOR	(JOBWAC(P1))		;YES, KILL THE WTOR
	ANDCAM	S1,JOBSTW(P1)		;ZAP THE OPR WAIT BIT

OACC.0:	PUSHJ	P,GETBLK		;GET A MESSAGE BLOCK
	JUMPF	OACC.2			;NO MORE, FINISH UP
	CAIN	T1,.ORREA		;IS THIS THE REASON BLOCK ???
	MOVEM	T3,RSNFLG		;YES, SAVE THE REASON ADDRESS
	CAIE	T1,.CANTY		;IS THIS THE CANCEL TYPE BLOCK ???
	JRST	OACC.0			;NO, SKIP IT AND GET NEXT BLOCK
					;YES...
	MOVE	S1,0(T3)		;LOAD THE CANCEL TYPE.
	CAIE	S1,.CNPRG		;IS IT /PURGE ???
	JRST	OACC.0			;NO, PROCESS THE NEXT MSG BLK
	SKIPE	S1,J$DIFN(J)		;GET THE FILE IFN.
	PUSHJ	P,F%REL			;ELSE,,CLOSE IT OUT.
	SETZM	J$DIFN(J)		;Clear the IFN
	MOVEM	S,J$RACS+S(J)		;SAVE THE 'S' AC WITH NEW DSKOPN BITS
;**;[3010] Delete 3 lines at OACC.0+14L and 1 line at OACC.0+19L. /LWS
	SETZM	JOBACT(P1)		;STREAM IS NO LONGER ACTIVE
	PUSHJ	P,QRELEASE 		;RELEASE THE REQUEST
	$RETT				;AND RETURN

OACC.2:	$TEXT(LOGCHR,<^I/LPOPR/Job Aborted by the Operator>)
	SKIPE	RSNFLG			;WAS A REASON GIVEN ???
	$TEXT (LOGCHR,<^I/LPOPR/ REASON: ^T/@RSNFLG/>) ;YES, SAY SO
	SKIPN	RSNFLG			;WAS A REASON GIVEN ???
	$TEXT	(LOGCHR,<^I/LPOPR/ No reason given>) ;NO, SAY SO
	$TEXT	(<-1,,J$WTOR(J)>,<Job aborted by the Operator^0>)
	TXO	S,ABORT			;TELL LPTSPL WE ARE LEAVING.
	TXNE	S,GOODBY		;ARE WE ON OUR WAY OUT ???
	$RETT				;YES, JUST RETURN
	PUSHJ	P,INPFEF		;FORCE SPOOL FILE EOF
	TXNE	S,BANHDR		;ARE WE PRINTING BANNER/HEADER PAGES?
	$RETT				;YES, JUST RETURN
	PUSHJ	P,@J$FLSH(J)		;FLUSH THE OUTPUT BUFFERS
	JUMPF	SHUTND			;CANT,,SHUT IT DOWN
	$RETT				;FUNCTION COMPLETE !!!

RSNFLG:	0,,0
SUBTTL OACSUP -- Operator SUPPRESS request.

OACSUP:	TXNE	S,ABORT+RQB+GOODBY	;ARE WE ON OUR WAY OUT ???
	PJRST	TOOBAD			;YES, SKIP THIS.

OACS.0:	PUSHJ	P,GETBLK		;GET A MESSAGE BLOCK
	JUMPF	.RETT			;NO MORE, JUST RETURN
	CAIN	T1,.SUPFL		;IS IT SUPPRESS FILE ???
	PJRST	OACS.1			;YES, THEN GO PROCESS IT AND RETURN
	CAIN	T1,.SUPJB		;IS IT SUPPRESS JOB ???
	JRST	OACS.2			;YES, THEN GO PROCESS IT AND RETURN
	CAIE	T1,.SUPST		;IS IT STOP SUPPRESSION ???
	JRST	OACS.0			;NO, GO PROCESS NEXT MSG BLOCK

	TXZ	S,SUPJOB!SUPFIL		;TURN OFF SUPPRESS FILE AND JOB BIT
	$TEXT (LOGCHR,<^I/LPOPR/Operator stopped carriage control supression>)
	MOVE	S1,STREAM		;GET STREAM NUMBER.
	$ACK  (Carriage control activated,<^R/.EQJBB(J)/>,@JOBOBA(S1),.MSCOD(M))
	$RETT				;RETURN NOW

OACS.1:	TXO	S,SUPFIL		;TURN ON SUPPRESS FILE BIT.
	TXZ	S,SUPJOB		;TURN OFF SUPPRESS JOB BIT.
	MOVEI	S1,[ASCIZ/this file/]	;GET THIS FILE MSG.
	JRST	OACS.3			;LETS MEET AT THE PASS

OACS.2:	TXO	S,SUPJOB		;TURN ON SUPPRESS JOB BIT.
	TXZ	S,SUPFIL		;TURN OFF SUPPRESS FILE BIT.
	MOVEI	S1,[ASCIZ/this job/]	;GET THIS JOB MSG.

OACS.3:	$TEXT(LOGCHR,<^I/LPOPR/Operator suppressed carriage control for rest of ^T/0(S1)/>)
	MOVE	S1,STREAM		;GET STREAM NUMBER.
	$ACK (Carriage control suppressed,<^R/.EQJBB(J)/>,@JOBOBA(S1),.MSCOD(M))
	$RETT				;RETURN NOW

SUBTTL OACPAU -- Operator PAUSE request.

OACPAU:	MOVX	S2,PSF%ST		;LOAD THE STOP BIT
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	IORM	S2,JOBSTW(S1)		;SET IT
	$ACK  (Stopped,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPERATOR.
	SETZM	JOBCHK(S1)		;SAY WE WANT A CHECKPOINT TAKEN.
	SETOM	JOBUPD(S1)		;Update the status also.
	$RETT				;AND RETURN



SUBTTL OACCON -- Operator CONTINUE request.

OACCON:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	MOVX	S2,PSF%ST!PSF%DO	;LOAD THE BITS
	ANDCAM	S2,JOBSTW(S1)		;CLEAR IT
	$ACK  (Continued,,@JOBOBA(S1),.MSCOD(M)) ;TELL THE OPERATOR.
	SETOM	JOBUPD(S1)		;Do an update
					;  don't need checkpoint
					;  did one when we stopped
	$RETT				;AND RETURN

SUBTTL	OACREQ -- Operator REQUEUE request.

OACREQ:	TXNE	S,GOODBY		;IS IT TOO LATE FOR THIS ???
	PJRST	TOOBAD			;YES, TOUGH LUCK !!!
	PUSHJ	P,INPFEF		;FORCE AN INPUT EOF
	TXO	S,RQB+ABORT		;LITE THE REQUEUE+ABORT BITS
	$TEXT(LOGCHR,<^I/LPOPR/Job requeued by the the operator>)
	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$ACK	(Requeued,<^R/.EQJBB(J)/>,@JOBOBA(S1),.MSCOD(M)) ;TELL OPR

	MOVX	S2,PSF%OR		;GET OPR RESP WAIT BIT
	TDNE	S2,JOBSTW(S1)		;ARE WE WAITING FOR THE OPERATOR ???
	$KWTOR	(JOBWAC(S1))		;YES, KILL THE WTOR
	ANDCAM	S2,JOBSTW(S1)		;ZAP THE OPR WAIT BIT

OACR.0:	PUSHJ	P,GETBLK		;GET A MESSAGE BLOCK
	JUMPF	.RETT			;NO MORE, RETURN
	CAIN	T1,.REQTY		;IS THIS THE REQUEST TYPE BLOCK ???
	JRST	OACR.1			;YES, GO PROGESS IT
	CAIN	T1,.ORREA		;IS THIS THE REASON BLOCK ???
	$TEXT (LOGCHR,<^I/LPOPR/Requeue reason is: ^T/0(T3)/.>)
	JRST	OACR.0			;PROCESS THE NEXT MSG BLOCK

OACR.1:	MOVE	S1,0(T3)		;PICK UP THE REQUEUE CODE.
	SETZ	S2,			;ZERO AC 2
	CAXN	S1,.RQCUR		;/CURRENT?
	JRST	OACR.3			;YES, DO IT
	SETZM	J$RNPP(J)		;CLEAR CURRENT PAGE NUMBER
	CAXN	S1,.RQBCP		;BEGINNING OF COPY?
	MOVEI	S2,[ASCIZ /current copy/]
	JUMPN	S2,OACR.2		;AND CONTINUE ON
	SETZM	J$RNCP(J)		;CLEAR CURRENT COPY NUMBER
	CAXN	S1,.RQBFL		;FROM BEGINING OF FILE?
	MOVEI	S2,[ASCIZ /current file/]
	JUMPN	S2,OACR.2		;AND CONTINUE ON
	SETZM	J$RNFP(J)		;CLEAR FILE COUNT
	MOVEI	S2,[ASCIZ /job/]	;FROM BEGINNING OF JOB
OACR.2:	$TEXT(LOGCHR,<^I/LPOPR/Job will restart at the beginning of the ^T/0(S2)/>)
	JRST	OACR.0			;GO PROCESS THE NEXT MSG BLOCK.

OACR.3:	$TEXT(LOGCHR,<^I/LPOPR/Job will restart at the current position>)
	MOVNI	S1,2			;LOAD -2
	ADDM	S1,J$RNPP(J)		;INSURE NO LOSSAGE OF DATA
	ADDM	S1,J$APRT(J)		;HERE ALSO
	SKIPGE	J$RNPP(J)		;MAKE SURE WE DIDN'T SCREW THINGS UP
	SETZM	J$RNPP(J)		;YES, ZERO THE PAGES PER COPY
	SKIPGE	J$APRT(J)		;CHECK HERE ALSO
	SETZM	J$APRT(J)		;NO GOOD, SET IT TO ZERO
	JRST	OACR.0			;GO PROCESS THE NEXT MSG BLOCK
SUBTTL	OACALI -- Routine to process Operator ALIGN request.

	; J$APRG(J) :: [?,,-1] = ALIGN IN PROGRESS.
	;	       [-1,,?] = ALIGN NEEDS TO BE SCHEDULED.

OACALI:	TXNE	S,ABORT+RQB+GOODBY	;ARE WE ON OUR WAY OUT ???
	PJRST	TOOBAD			;YES, SKIP THIS.
	SETZM	FDADDR			;RESET ALIGN FD ADDRESS.
	SKIPE	J$POSF(J)		;DRIVER ALLOW POSITIONING?
	JRST	OALI.0			;YES--CONTINUE
	MOVE	S1,STREAM		;GET OUR STREAM
	$ACK	(<ALIGN not valid for ^T/@J$DRIV(J)/ printers>,,@JOBOBA(S1),.MSCOD(M))
	$RETT

OALI.0:	PUSHJ	P,GETBLK		;GET A MESSAGE DATA BLOCK
	JUMPF	OALI.1			;NO MORE, CONTINUE PROCESSING
	MOVE	S1,0(T3)		;GET THE FIRST DATA WORD IN THE BLOCK
	MOVEI	T3,-1(T3)		;POINT TO THE BLOCK HEADER
	CAIN	T1,.ALPAU		;IS THIS THE /PAUSE BLOCK ???
	MOVEM	S1,J$ASLP(J)		;YES, SAVE THE SLEEP TIME
	CAIN	T1,.ALRPT		;IS THE THE /REPEAT-COUNT BLOCK ???
	MOVEM	S1,J$ACNT(J)		;YES, SAVE THE REPEAT-COUNT
	CAIN	T1,.CMIFI		;IS THIS THE FILE-SPEC BLOCK ???
	MOVEM	T3,FDADDR		;SAVE THE FD ADDRESS
	CAIN	T1,.ALSTP		;IS THIS THE /STOP BLOCK ???
	PJRST	OALI.6			;YES, GO PROCESS IT AND RETURN
	JRST	OALI.0			;NONE OF THESE,,TRY NEXT BLOCK

OALI.1:	SKIPN	J$APRG(J)		;ARE WE ALREADY ALIGNING ???
	JRST	OALI.2			;NO, THEN WE'RE OK
	MOVE	S1,STREAM		;YES, GET STREAM NUMBER.
	$ACK  (ALIGN already in progress,,@JOBOBA(S1),.MSCOD(M))
	$RETT				;RETURN NOW.

OALI.2:	MOVEI	S1,FOB.SZ		;PICK UP FOB SIZE.
	MOVEI	S2,J$XFOB(J)		;PICK UP FOB ADDRESS.
	PUSHJ	P,.ZCHNK		;ZERO OUT THE FOB BLOCK.
	MOVEI	S1,7			;PICK UP ASCII BYTE SIZE
	STORE	S1,J$XFOB+FOB.CW(J),FB.BSZ ;AND SAVE IT IN FOB.
	SKIPN	S1,FDADDR		;SKIP FD GEN IF USER SPECIFIED.
	PUSHJ	P,BLDLFD		;GO BUILD THE ALIGN FD.
	STORE	S1,J$XFOB+FOB.FD(J)	;AND SAVE ITS ADDRESS IN FOB.
	MOVEI	S1,FOB.SZ		;PICK UP THE FOB SIZE.
	MOVEI	S2,J$XFOB(J)		;PICK UP THE FOB ADDRESS.
	PUSHJ	P,F%IOPN		;OPEN THE ALIGN FILE.
	 JUMPF	OALI.3			;IF AN ERROR, RETURN WITH WTO.
	MOVEM	S1,J$AIFN(J)		;SAVE THE FILE ID.
	SKIPG	S1,J$ACNT(J)		;PICK UP USER DEFINED REPEAT-COUNT.
	SKIPLE	S1,J$FALC(J)		;ELSE PICK UP LPFORM.INI REPEAT-CNT.
	SKIPA				;SKIP DEFAULT.
	MOVE	S1,D$ALCN		;PICK UP THE DEFAULT REPEAT COUNT.
	MOVEM	S1,J$ACNT(J)		;SAVE THE REPEAT-COUNT.

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	SKIPG	S1,J$ASLP(J)		;PICK UP USER SLEEP TIME.
	SKIPLE	S1,J$FALS(J)		;ELSE, PICK UP LPFORM.INI SLEEP-TIME.
	SKIPA				;SKIP THE DEFAULT.
	MOVE	S1,D$ALSL		;PICK UP THE DEFUALT SLEEP-TIME.
	IMULI	S1,3			;CONVERT TO UNIVERSAL TIME.
	MOVEM	S1,J$ASLP(J)		;AND SAVE IT.
	SETOM	J$APRG(J)		;SHOW WE ARE DOING AN ALIGN,
					;   AND THAT IT NEEDS TO BE SCHEDULED.
	MOVE	S1,STREAM		;GET STREAM NUMBER
	$WTO  (Alignment Scheduled,,@JOBOBA(S1)) ;TELL THE OPERATOR.
	SETOM	JOBUPD(S1)		;Update the status
	$RETT				;RETURN.

OALI.3:	MOVE	S1,STREAM		;GET STREAM NUMBER
;**;[3000] Insert 1 line and change 1 line at OALI.3+1L. /LWS
	SETZM	J$APRG(J)		;[3000] AVOID CONFUSION,,CAN'T ALIGN
	$WTO  (<Alignment Not Scheduled>,<Cannot read ALIGN file ^F/@J$XFOB+FOB.FD(J)/ - ^E/[-1]/>,@JOBOBA(S1)) ;[3000]
	$RETT

OALI.6:	SKIPE	J$APRG(J)		;ARE WE ALREADY ALIGNING ???
	JRST	OALI.7			;IF SO,,CONTINUE PROCESSING.
	MOVE	S1,STREAM		;GET STREAM NUMBER
	$ACK  (</STOP Illegal>,Alignment not in Progress,@JOBOBA(S1),.MSCOD(M))
	$RETT
OALI.7:	MOVE	S1,J$AIFN(J)		;GET THE ALIGN IFN.
	SETOB	S2,J$ABYT(J)		;SET ALIGN FILE BYTE COUNT TO -1.
	PUSHJ	P,F%POS			;POSITION TO ALIGN EOF.
	SETZM	J$ACNT(J)		;SET REPEAT-COUNT TO 0.
	MOVE	S1,STREAM		;GET STREAM NUMBER
	$ACK  (Alignment Discontinued,,@JOBOBA(S1),.MSCOD(M))
	$RETT				;AND RETURN

FDADDR:	0,,0
SUBTTL	OACFWS -- OPERATOR FORWARD SPACE COMMAND PROCESSOR.

OACFWS:	TXNE	S,ABORT+RQB+GOODBY	;ARE WE ON OUR WAY OUT ???
	PJRST	TOOBAD			;YES, SKIP THIS.
	MOVE	S1,STREAM		;GET THE STREAM NUMBER.
	SETZM	JOBCHK(S1)		;SAY WE WANT TO TAKE A CHECKPOINT.
	SKIPE	J$POSF(J)		;DRIVER ALLOW POSITIONING?
	JRST	OACF.0			;YES--CONTINUE
	MOVE	S1,STREAM		;GET OUR STREAM
	$ACK	(<FORWARDSPACE not valid for ^T/@J$DRIV(J)/ printers>,,@JOBOBA(S1),.MSCOD(M))
	$RETT

OACF.0:	PUSHJ	P,GETBLK		;GET A MESSAGE BLOCK
	JUMPF	.RETT			;NO MORE, RETURN
	CAIN	T1,.SPPAG		;IS THIS FORWARD SPACE PAGES ???
	PJRST	FSPACE			;YES, DO IT
	CAIN	T1,.SPCPY		;IS THIS FORWARD SPACE COPIES ???
	PJRST	FCOPYS			;YES, DO IT
	CAIN	T1,.SPFIL		;IS THIS FORWARD SPACE 1 FILE ???
	PJRST	FFILES			;YES, DO IT
	JRST	OACF.0			;NONE OF THESE,,TRY NEXT BLOCK

FSPACE:	SKIPN	J$DIFN(J)		;IS THERE A SPOOL FILE OPEN ???
	$RETT				;NO, JUST IGNORE THIS
	TXO	S,FORWRD		;TURN ON FORWARD SPACE BIT.
	MOVE	S2,0(T3)		;PICK UP # OF PAGES TO FSPACE.
;**;[4005]INSERT 1 LINE AT FSPACE:+5L 13-MAY-85/CTK
	ADDM	S2,J$FPIG(J)		;[4005]ADD TO FORWARDSPACE PAGE CNT
	MOVE	S1,STREAM		;PICK UP THE STREAM NUMBER.
	$ACK  (<Forward spaced ^D/S2/ Pages>,,@JOBOBA(S1),.MSCOD(M))
;**;[2774] Change 1 line at FSPACE+7L. 25-Oct-83  /LWS
$TEXT (LOGCHR,<^I/LPMSG/File ^F/@J$DFDA(J)/^T/J$GSPL(J)/ Forward spaced ^D/J$FPIG(J)/ Pages>) ;[2774]
	$RETT				;AND RETURN


FCOPYS:	MOVE	S2,0(T3)		;PICK UP THE # OF COPIES TO FSPACE.
	ADDM	S2,J$RNCP(J)		;ADD TO # OF COPIES ALREADY PRINTED.
;**;[2774] Changed 1 line at FCOPYS+2L. 25-Oct-83  /LWS
	$TEXT (LOGCHR,<^I/LPMSG/File ^F/@J$DFDA(J)/^T/J$GSPL(J)/ Forward spaced ^D/S2/ Copies>) ;[2774]
	MOVE	S1,STREAM		;PICK UP THE STREAM NUMBER.
	$ACK  (<Forward Spaced ^D/S2/ Copies>,,@JOBOBA(S1),.MSCOD(M))
	PUSHJ	P,INPFEF		;FORCE AN END-OF-FILE.
	$RETT				;AND RETURN

FFILES:	MOVE	S1,STREAM		;PICK UP THE STREAM NUMBER
	$ACK	(Forward Spaced 1 File,,@JOBOBA(S1),.MSCOD(M))
;**;[2774] Changed 1 line at FFILES+2L. 25-Oct-83  /LWS
	$TEXT	(LOGCHR,<^I/LPMSG/File ^F/@J$DFDA(J)/^T/J$GSPL(J)/ Skipped by Operator>) ;[2774]
	PUSHJ	P,INPFEF		;FORCE AN END OF FILE
	TXO	S,SKPFIL		;TURN ON SKIP FILE FLAG
	$RETT				;AND RETURN

SUBTTL	OACBKS -- BACK SPACE operator action routine.

OACBKS:	TXNE	S,ABORT+RQB+GOODBY	;ARE WE ON OUR WAY OUT ???
	PJRST	TOOBAD			;YES, SKIP THIS.
	MOVE	S1,STREAM		;GET THE STREAM NUMBER.
	SETZM	JOBCHK(S1)		;SAY WE WANT TO TAKE A CHECKPOINT.
	SKIPE	J$POSF(J)		;DRIVER ALLOW POSITIONING?
	JRST	OACB.0			;YES--CONTINUE
	MOVE	S1,STREAM		;GET OUR STREAM
	$ACK	(<BACKSPACE not valid for ^T/@J$DRIV(J)/ printers>,,@JOBOBA(S1),.MSCOD(M))
	$RETT

OACB.0:	PUSHJ	P,GETBLK		;GET A MESSAGE DATA BLOCK
	JUMPF	.RETT			;NO MORE, JUST RETURN
	MOVE	S1,T3			;GET THE DATA ADDRESS IN S1.
	CAIN	T1,.SPPAG		;IS THIS BACKSPACE 'PAGES' ???
	PJRST	BSPACE			;YES, GO PROCESS IT
	CAIN	T1,.SPCPY		;IS IT BACKSPACE COPIES ???
	PJRST	BCOPYS			;YES, GO PROCESS IT
	CAIN	T1,.SPFIL		;IS IT BACKSPACE FILES ???
	PJRST	BFILES			;YES, GO PROCESS IT
	JRST	OACB.0			;NONE OF THESE,,TRY NEXT BLOCK

BSPACE:	MOVE	T1,0(S1)		;PICK UP THE NUMBER OF PAGES TO BSPACE.
	MOVE	S1,STREAM		;PICK UP STREAM NUMBER.
	$ACK (<Backspaced ^D/T1/ Pages>,,@JOBOBA(S1),.MSCOD(M))
;**;[2774] Changed 1 line at BSPACE+3L. 25-Oct-83  /LWS
	$TEXT (LOGCHR,<^I/LPMSG/File ^F/@J$DFDA(J)/^T/J$GSPL(J)/ Backspaced ^D/T1/ Pages>) ;[2774]
	SKIPN	J$DIFN(J)		;IS THERE A SPOOL FILE OPEN ???
	$RETT				;NO, JUST RETURN.

	ADDM	T1,J$RLIM(J)		;Up the limit to compensate for the
					;  backspace
	TXO	S,FCONV			;We will start next on new line
	SETOM	J$DBCT(J)		;RESET THE INPUT BYTE COUNT
	SETZM	J$FPIG(J)		;ZERO THE FORWARD SPACE PAGE COUNTER
	SETZM	J$FCBC(J)		;CLEAR THE CURRENT INPUT BUFFER BYTE CNT
	MOVE	S1,J$FLIN(J)		;GET LINES PER PAGE
	MOVEM	S1,J$XPOS(J)		;RESET THE PAGE POSITION TO TOP OF PAGE
	MOVX	S1,.CHFFD		;GET A FORM FEED
	MOVEM	S1,J$RACS+C(J)		;CONVERT NXT CHAR TO FORM FEED
	MOVE	S1,J$RNPP(J)		;GET THE # OF PAGES PRINTED SO FAR.
	SUB 	S1,T1			;CALC DESTINATION PAGE NUMBER
	SKIPGE	S1			;CAN'T BE NEGATIVE
	SETZM	S1			;IF SO,,MAKE IT ZERO
	JUMPLE	S1,BSPA.2		;MORE THEN WE PRINTED,,JUST REWIND FILE
	CAXLE	T1,PAGSIZ		;REQUESTING MORE THEN WE'RE TRACKING ??
	JRST	BSPA.2			;YES, REWIND THE FILE
	MOVE	S2,J$FBPT(J)		;GET THE PAGE TABLE ENTRY POINTER
	SUBI	S2,J$FPAG(J)		;CALC INDEX TO CURRENT PAGE
	SUBI	S2,1(T1)		;CALC INDEX TO NEW PAGE
	JUMPGE	S2,BSPA.1		;IF POSITIVE,,THEN NO PROBLEM
	TXNN	S,FBPTOV		;ELSE CHECK FOR PAGE TABLE OVERFLOW
	JRST	BSPA.2			;NO, HMMMMM,,JUST REWIND THE FILE
	ADDI	S2,J$FPAG+PAGSIZ(J)	;GET TABLE ENTRY FROM THE TOP
	SKIPA				;SKIP NON OVERFLOW PATH
BSPA.1:	ADDI	S2,J$FPAG(J)		;GET TABLE ENTRY FROM THE BOTTOM

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	MOVEM	S1,J$RNPP(J)		;RESET PAGE POINTER FOR THIS FILE
	MOVEI	S1,1(S2)		;POINT TO NEXT PAGE TBL ENTRY
	CAIL	S1,J$FPAG+PAGSIZ(J)	;Want to wrap around?
	JRST	[MOVEI	S1,J$FPAG(J)	;Yes, start at the beginning
		TXO	S,FBPTOV	;Say we overflowed
		JRST	.+1]		;And continue
	MOVEM	S1,J$FBPT(J)		;AND MAKE THIS THE CUR TBL ENTRY ADDR
	MOVE	S2,0(S2)		;PICK UP THE LISTING PAGE ADDRESS
	MOVEM	S2,J$FTBC(J)		;AND MAKE THIS THE TOTAL BUFR BYTE COUNT
	MOVE	S1,J$DIFN(J)		;GET THE SPOOL FILE IFN
	PUSHJ	P,F%POS			;POSITION TO THAT PAGE IN THE FILE
	$RETT				;AND RETURN

BSPA.2:	PUSH	P,S1			;SAVE THE DESTINATION PAGE #
	PUSHJ	P,INPREW		;REWIND THE SPOOL FILE
	POP	P,S1			;RESTORE DESTINATION PAGE NUMBER
	JUMPLE	S1,.RETT		;IF NO SLACK DATA,,SKIP FORWARD SPACE
	MOVEM	S1,J$FPIG(J)		;SAVE THE # OF PAGES TO FORWARD SPACE
	TXO	S,FORWRD		;LITE FORWARD SPACE BIT
	$RETT				;RETURN

SUBTTL	BCOPYS -- BACKSPACE 'COPIES'

BCOPYS:	MOVE	S2,J$RNCP(J)		;PICK UP # OF COPIES ALREADY PRINTED.
	MOVE	T1,0(S1)		;PICK UP # OF COPIES TO BSPACE.
	SUB	S2,T1			;SUBTRACT # OF COPIES TO BSPACE.
	MOVEM	S2,J$RNCP(J)		;SAVE THE NEW COPIES VALUE.
;**;[2774] Changed 1 line at BCOPYS+4L. 25-Oct-83 /LWS
	$TEXT (LOGCHR,<^I/LPMSG/File ^F/@J$DFDA(J)/^T/J$GSPL(J)/ Backspaced ^D/T1/ Copies>) ;[2774]
	MOVE	S1,STREAM		;PICK UP STREAM NUMBER.
	$ACK  (<Backspaced ^D/T1/ Copies>,,@JOBOBA(S1),.MSCOD(M))
	PUSHJ	P,INPFEF		;FORCE END OF FILE.
	$RETT				;RETURN.

SUBTTL	BFILES -- BACKSPACE 'FILES'

BFILES:	PUSHJ	P,INPFEF		;FORCE AN END-OF-FILE
	TXO	S,SKPFIL+BCKFIL		;LITE SKIP FILE AND BACKSPACE'ED BITS
	SETOM	J$RNFP(J)		;RESET THE FILE COUNTER
	MOVE	S1,J$RFLN(J)		;GET THE FILE COUNT
	LOAD	S2,.EQSPC(J),EQ.NUM	;GET THE NUMBER OF FILES
	MOVEM	S2,J$RFLN(J)		;SAVE IT
	SUB	S2,S1			;CALC HOW FAR WE HAVE GONE SO FAR
	LOAD	E,.EQLEN(J),EQ.LOH	;GET THE HEADER LENGTH
	ADD	E,J			;POINT TO THE FIRST FP
BFIL.1:	SOJLE	S2,BFIL.2		;LOOP THROUGH THE FP/FD'S TILL
	PUSHJ	P,NXTFIL		;WE GET TO THE CURRENT FILE
	AOS	J$RNFP(J)		;MINUS ONE
	JRST	BFIL.1			;CONTINUE TILL DONE

BFIL.2:	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	$ACK	(<Backspaced 1 File>,,@JOBOBA(S1),.MSCOD(M))
	LOAD	S1,.FPLEN(E),FP.LEN	;GET THE FP LENGTH
	ADD	S1,E			;POINT TO THE FD
	$TEXT	(LOGCHR,<^I/LPMSG/Backspaced to Beginning of ^F/0(S1)/>)
	MOVEM	E,J$RACS+E(J)		;UPDATE AC 'E' IN STREAM DATA BASE
	$RETT

PAGES:	0,,0
SUBTTL BLDL -- CREATE A 10/20 FD FOR THE ALIGN FILE.


BLDLFD:
TOPS10 <
	MOVEI	S1,FDMSIZ		;PICK UP 10 FD SIZE.
	STORE	S1,J$AFD+.FDLEN(J),FD.LEN ;SAVE IN FD.
	MOVSI	S1,'SYS'		;PICK UP STRUCTURE NAME.
	MOVEM	S1,J$AFD+.FDSTR(J)	;SAVE IN FD.
	MOVE	S1,J$FALI(J)		;PICK UP FILE NAME (FORMS TYPE).
	MOVEM	S1,J$AFD+.FDNAM(J)	;SAVE IN FD.
	MOVSI	S1,'ALP'		;PICK UP FILE EXT.
	MOVEM	S1,J$AFD+.FDEXT(J)	;SAVE IN FD.
	MOVEI	S1,J$AFD(J)		;PICK UP FD ADDRESS.
	$RETT				;RETURN. . . . . . . . . .
> ;END TOPS10 CONDITIONAL

TOPS20 <
	MOVEI	S1,AFDSIZ		;GET THE FD LENGTH
	STORE	S1,J$AFD+.FDLEN(J),FD.LEN ;SAVE IT
	$TEXT	(<-1,,J$AFD+.FDSTG(J)>,<SYS:^W/J$FALI(J)/.ALP^0>)
	MOVEI	S1,J$AFD(J)		;PICK UP FD ADDRESS.
	$RETT				;RETURN. . . . . . . . . .
> ;END TOPS20 CONDITIONAL

SUBTTL	ALIGN -- Processor.

ALIGN:	TXNE	S,GOODBY!ABORT		;ARE WE LEAVING ???
	JRST	ALIG.5			;RETURN.
	MOVE	S1,J$AIFN(J)		;GET THE IFN
	PUSHJ	P,F%REW			;REWIND THE FILE
	SETZM	J$XTOP(J)		;CLEAR TOP OF FORM FLAG
	PUSHJ	P,SENDFF		;SEND A FORM-FEED

ALIG.1:	SOSGE	J$ABYT(J)		;DECREMENT THE BYTE COUNT
	JRST	ALIG.3			;IF BUFFER EMPTY,,GET NEXT BUFFER.
	ILDB	C,J$APTR(J)		;PICK UP THE ALIGN BYTE.
	PUSHJ	P,DEVOUT		;PUT IT OUT....
	JRST	ALIG.1			;GO GET NEXT BYTE.

ALIG.2:	PUSHJ	P,OUTDMP		;FORCE OUT THE BUFFER
	SOSLE	J$ACNT(J)		;COUNT DOWN
	JRST	ALIG.4			;IF AGAIN,,SET UP SLEEP TIME.
	SETZM	J$XTOP(J)		;CLEAR TOP OF FORM
	PUSHJ	P,SENDFF		;GO TO TOP OF FORM
ALIG.5:	MOVE	S1,J$AIFN(J)		;PICK UP ALIGN IFN.
	PUSHJ	P,F%REL			;CLOSE THE ALIGN FILE.
	SETZM	J$APRG(J)		;INDICATE NO ALIGN IN PROGRESS.
	SETZM	J$ASLP(J)		;CLEAR THIS SLEEP TIME
	SETZM	J$ACNT(J)		;AND THIS REPEAT COUNT
	MOVE	S1,STREAM		;GET THE STREAM NUMBER.
	SETZM	JOBCHK(S1)		;SAY WE WANT TO CHECKPOINT.
	SETOM	JOBUPD(S1)		;  send update message also
	$RETT				;AND RETURN

ALIG.3:	MOVE	S1,J$AIFN(J)		;GET ALIGN IFN.
	PUSHJ	P,F%IBUF		;GET AN ALIGN BUFFER.
	JUMPF	ALIG.2			;IF NO MORE,,SLEEP A WHILE.
	MOVEM	S1,J$ABYT(J)		;SAVE THE # OF BYTES.
	MOVEM	S2,J$APTR(J)		;SAVE THE BYTE POINTER.
	JRST	ALIG.1			;KEEP ON PROCESSING.

ALIG.4:	MOVE	S2,STREAM		;PICK UP STREAM NUMBER.
	PUSHJ	P,I%NOW			;GET CURRENT TIME.
	ADD	S1,J$ASLP(J)		;ADD /PAUSE VALUE.
	MOVEM	S1,JOBWKT(S2)		;SAVE WAKE UP TIME FOR STREAM.
	$DSCHD	(PSF%AL)		;SHOW STREAM BLOCKED FOR ALIGNMENT.
	JRST	ALIGN			;WHEN RETURN,,CONTINUE.

SUBTTL	FNDOBJ -- ROUTINE TO FIND THE OBJ BLK IN THE DATA BASE.

FNDOBJ::MOVE	T1,.ROBTY(S1)		;GET OBJECT TYPE
	MOVE	T2,.ROBAT(S1)		;GET UNIT NUMBER
	MOVE	T3,.ROBND(S1)		;AND NODE NUMBER
	SETZ	T4,			;CLEAR AN INDEX REGISTER

FNDO.1:	MOVE	S2,T4			;GET THE INDEX
	IMULI	S2,3			;MULTIPLY BY OBJECT BLCK SIZE
	CAMN	T1,JOBOBJ+OBJ.TY(S2)	;COMPARE
	CAME	T2,JOBOBJ+OBJ.UN(S2)	;COMPARE
	JRST	FNDO.2			;NOPE
	CAMN	T3,JOBOBJ+OBJ.ND(S2)	;COMPARE
	JRST	FNDO.3			;WIN, SETUP THE CONTEXT
FNDO.2:	ADDI	T4,1			;INCREMENT
	CAIL	T4,NPRINT		;THE END OF THE LINE?
	$RETF				;YES, RETURN 'OBJECT NOT THERE'
	JRST	FNDO.1			;OK, LOOP

FNDO.3:	MOVEM	T4,STREAM		;SAVE STREAM NUMBER
	SKIPN	J,JOBPAG(T4)		;GET ADDRESS OF DATA
	$RETF				;UNLESS ITS NOT REALLY SETUP THEN RETURN
	MOVE	S,J$RACS+S(J)		;GET HIS 'S'
	$RETT				;AND RETURN

SUBTTL	SNDQSR -- ROUTINE TO SEND A MESASGE TO QUASAR.

SNDQSR::MOVX	S1,SP.QSR		;GET QUASAR FLAG
	TXO	S1,SI.FLG		;SET SPECIAL INDEX FLAG
	STORE	S1,SAB+SAB.SI		;AND STORE IT
	SETZM	SAB+SAB.PD		;CLEAR THE PID WORD
	LOAD	S1,.MSTYP(T1),MS.CNT	;GET THE MESSAGE LENGTH
	STORE	S1,SAB+SAB.LN		;SAVE IT
	STORE	T1,SAB+SAB.MS		;SAVE THE MESSAGE ADDRESS
	MOVEI	S1,SAB.SZ		;LOAD THE SIZE
	MOVEI	S2,SAB			;AND THE ADDRESS
	PUSHJ	P,C%SEND		;SEND THE MESSAGE
	JUMPT	.RETT			;AND RETURN

	$STOP(QSF,Send to QUASAR FAILED)



SUBTTL	CHKLPT -- ROUTINE TO MAKE SURE THE DEVICE IS ONLINE

CHKLPT:

TOPS20 <
	SKIPE	S1,JOBSTW		;ARE ANY STATUS BITS SET ???
	TXNN	S1,PSF%DO		;IF SO,,IS IT DEVICE OFFLINE ???
	$RETT				;NO TO EITHER,,JUST RETURN
	$WTO	(<^T/BELL/>,,@JOBOBA)	;TELL OPR DEVICE IS OFFLINE
	MOVE	S1,STREAM		;Get the stream number
	SETOM	JOBUPD(S1)		;Say we want a status update
	$CALL	DSTATUS			;Do it
	SETZM	JOBCHK			;INDICATE WE WANT ANOTHER WHEN WE CAN
> ;END TOPS20 CONDITIONAL

	$RETT				;RETURN


SUBTTL	TOOBAD -- ROUTINE TO RESPOND TO THE OPERATOR IF HIS REQUEST IS TOO LATE.


TOOBAD:	MOVE	S1,STREAM		;GET THE STREAM NUMBER.
	$ACK	(Print Request Completed,<^R/.EQJBB(J)/>,@JOBOBA(S1),.MSCOD(M))
	$RETT

SUBTTL	LOGCHR  --  Type a character in the log file


LOGCHR::CAIE	S1,.CHLFD		;IS IT A LINE-FEED
	CAIN	S1,23			;OR A DC 3?
	AOS	J$GNLN(J)		;YES, COUNT ANOTHER LINE
LOGC.1:	SOSGE	J$GIBC(J)		;IS THERE ROOM?
	JRST	LOGC.2			;NO, GET ANOTHER PAGE
	IDPB	S1,J$GIBP(J)		;YES, DEPOSIT THE CHARACTER
	$RETT				;AND RETURN

LOGC.2:	PUSH	P,S1			;SAVE THE CHARACTER FOR A MINUTE
	PUSHJ	P,LOGBUF		;GET ANOTHER PAGE
	POP	P,S1			;RESTORE THE CHARACTER
	JRST	LOGC.1			;AND TRY AGAIN


SUBTTL	LOGBUF  --  Get a buffer page for LOG

LOGBUF:	PUSHJ	P,.SAVE1		;SAVE P1
	AOS	P1,J$GINP(J)		;INCREMENT BUFFER PAGE COUNT
	CAIN	P1,1			;IS THIS THE FIRST PAGE?
	JRST	[MOVE S1,J$GBUF(J)	;YES, USE THE PRE-ALLOCATED PAGE
		$CALL	.ZPAGA		; Make sure page is zeroed of residue
		 JRST LOGB.1]		;AND CONTINUE ON
	CAIL	P1,^D10			;NO, WITHIN RANGE?
	$STOP(TML,TOO MANY LOG BUFFERS REQUIRED) ;NO, COMMIT SUICIDE
	PUSHJ	P,M%GPAG		;GET A PAGE
	ADDI	P1,-1(J)		;POINT TO LOCATION IN J$GBUF
	MOVEM	S1,J$GBUF(P1)		;STORE THE ADDRESS
LOGB.1:	HRLI	S1,(POINT 7,0)		;MAKE A BYTE POINTER
	MOVEM	S1,J$GIBP(J)		;AND STORE IT
	MOVEI	S1,<5*1000>-1		;GET A COUNT
	MOVEM	S1,J$GIBC(J)		;STORE IT
	POPJ	P,			;AND RETURN
SUBTTL	ACTBEG -- ACCOUNTING INITIALIZATION ROUTINE

ACTBEG:	LOAD	S1,.EQSEQ(J),EQ.SEQ	;GET SEQUENCE NUMBER
	STORE	S1,J$ASEQ(J)		;STORE IT
	LOAD	S1,.EQSEQ(J),EQ.PRI	;GET EXTERNAL PRIORITY
	STORE	S1,J$APRI(J)		;STORE IT

TOPS20<	MOVX	S1,.FHSLF		;GET FORK HANDLE
	RUNTM   >			;GET MY RUNTIME

TOPS10<
  IFG <NPRINT-1>,<			;If more than one printer
	MOVEI	S1,0			;Dont account for runtime
  >
  IFE <NPRINT-1>,<			;If just one printer
	MOVEI	S1,0			;Get runtime for this job
	RUNTIM	S1,			;from the monitor
  >
>;END TOPS10

	MOVNM	S1,J$ARTM(J)  		;REMEMBER IT NEGATED
	$RETT				;RETURN
SUBTTL	ACTEND -- ACCOUNTING SUMMARY ROUTINE

ACTEND:	SKIPN	S1,DEBUGW		;SKIP IF DEBUGGING
	LOAD	S1,.EQSEQ(J),EQ.IAS	;GET THE INVALID ACCT STRING BIT
	JUMPN	S1,.RETT		;IF LIT,,THEN JUST RETURN

IFN FTACNT,<
TOPS20<	MOVX	S1,.FHSLF		;LOAD FORK HANDLE
	RUNTM				;GET RUNTIME
	ADDM	S1,J$ARTM(J)		;STORE IT
	MOVX	S1,.USENT		;WRITE AN ENTRY
	MOVEI	S2,ACTLST		;POINT TO THE LIST
	USAGE				;DO THE JSYS
	 ERJMP	ACTE.1			;ON AN ERROR,,TELL THE OPERATOR
> ;END TOPS20 ACCOUNTING

TOPS10<
  IFG <NPRINT-1>,<			;If more than one printer
	SETZM	J$ARTM(J)		;Zap the runtime
  >
  IFE <NPRINT-1>,<			;If just one printer
	SETZM	S1			;Get the runtime for this job
	RUNTIM	S1,			;Ask monitor
	ADDM	S1,J$ARTM(J)		;Calc run time to process the request
  >
	PUSHJ	P,I%NOW			;GET THE CURRENT TIME
	SUB	S1,J$RTIM(J)		;GET JIFFIES OF CONNECT TIME
	IDIVI	S1,3			;GET NUMBER OF SECONDS
	MOVEM	S1,LPCON		;SAVE THE CONNECT TIME
	MOVE	S1,[.NDRNN,,S2]		;GET CONVERT TO NAME FCT CODE
	MOVEI	S2,2			;A BLOCK LENGTH OF 2
	MOVE	T1,.EQROB+.ROBND(J)	;GET THE NODE NUMBER

FACT<	HRLZM	T1,FACTBL+3 >		;STORE NODE NUMBER NOW

	NODE.	S1,			;CONVERT IT
	 SKIPA				;SKIP ON AN ERROR
	MOVEM	S1,.EQROB+.ROBND(J)	;SAVE THE NODE NAME
	MOVE	S1,[ACTLEN,,ACTLST]	;GET THE PARM BLOCK LENGTH,,ADDRESS
	QUEUE.	S1,			;REQUEST ACCOUNTING BE DONE
	 TRNA				;ERROR, ANALYZE THE CODE
	JRST	ACTE.A			;GOOD RETURN, CONTINUE
	CAIE	S1,QUCNR%		;IS ERROR DUE TO COMPONENT NOT RUNNING?
	 PUSHJ	P,ACTE.1		;NO, FAILED,,TELL OPR
ACTE.A:
FACT<	MOVE	S1,LPLNO		;GET LINE NUMBER
	LDB	S2,[POINT 7,LPTRM,6]	;GET TERMINAL DESIGNATOR
	CAIN	S2,"C"			;ON THE CTY
	MOVEI	S1,7777			;YES, CTY DESIGNATOR
	CAIN	S2,"D"			;DETACHED
	MOVEI	S1,7776			;YES, FLAG THAT INSTEAD OF LINE NUMBER
	LSH	S1,6			;PUT IN BITS 18-29
	HRL	S1,LPJOB		;INSERT JOB NUMBER
	IOR	S1,[251000,,13]		;ADD FACT TYPE AND NUMBER OF WORDS
	MOVEM	S1,FACTBL+0		;STORE IN BLOCK
	MOVE	S1,.EQOID(J)		;GET PPN
	MOVEM	S1,FACTBL+1		;STORE
	SETZM	FACTBL+2		;DAEMON FILLS IN THE DATE/TIME
	MOVE	S1,[%CNSER]		;CPU SERIAL NUMBER
	GETTAB	S1,			;ASK FOR IT
	  SETZ	S1,			;USE 0 IF CAN'T FIND IT
	TLO	S1,'LP '		;QUEUE NAME = LPTSPL
	IORM	S1,FACTBL+3		;NODE NUMBER ALREADY STORED FROM ABOVE

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	MOVE	S1,J$ARTM(J)		;RUN TIME IN MILLISECONDS
	MOVEM	S1,FACTBL+4		;STORE
	SETZM	FACTBL+5		;*** CORE TIME INTERGRAL
	MOVE	S1,J$ADRD(J)		;DISK READS
	MOVEM	S1,FACTBL+6		;STORE
	SETZM	FACTBL+7		;NO DISK WRITES
	MOVE	S1,J$LDEV(J)		;DEVICE NAME
	MOVEM	S1,FACTBL+10		;STORE
	MOVE	S1,J$ASEQ(J)		;SEQUENCE NUMBER
	MOVEM	S1,FACTBL+11		;STORE
	MOVE	S1,J$APRT(J)		;NUMBER OF PAGES PRINTED
	MOVEM	S1,FACTBL+12		;STORE
	MOVE	S1,[FACSIZ+1,,FACTBL-1]	;DAEMON ARGUMENT
	DAEMON	S1,			;MAKE THE FACT ENTRY
	  JRST	ACTE.1			;REPORT THE FAILURE
> ;END FACT ACCOUNTING
> ;END TOPS10 ACCOUNTING
	$RETT				;IF OK,,RETURN

ACTE.1:	MOVE	S1,STREAM		;GET THIS STREAM NUMBER
	$WTO	(System Accounting Failure,<^R/.EQJBB(J)/>,@JOBOBA(S1))
> ;END IFN FTACNT

	$RETT				;RETURN

SUBTTL	ACTLST -- SPOOLER ACCOUNTING RECORD

IFN FTACNT,< SEARCH	ACTSYM		;SEARCH THE ACCOUNTING UNV

ACTLST:	USENT.	(.UTOUT,1,1,0)
	USTAD.	(-1)			;CURRENT DATE/TIME
	USPNM.	(<SIXBIT/LPTSPL/>,US%IMM) ;PROGRAM NAME
	USPVR.	(%LPT,US%IMM)		;PROGRAM VERSION
	USAMV.	(-1)			;ACCOUNTING MODULE VERSION
	USNOD.	(.EQROB+.ROBND(J))	;NODE NAME
	USSRT.	(J$ARTM(J))		;RUN TIME
	USSDR.	(J$ADRD(J))		;DISK READS
	USSDW.	(0,US%IMM)		;DISK WRITES
	USJNM.	(.EQJOB(J))		;JOB NAME
	USQNM.	(<SIXBIT /LPT/>,US%IMM)	;QUEUE NAME
	USSDV.	(J$LDEV(J))		;DEVICE NAME
	USSSN.	(J$ASEQ(J))		;JOB SEQUENCE NUMBER
	USSUN.	(J$APRT(J))		;TOTAL PAGES PRINTED
	USSNF.	(J$AFXC(J))		;TOTAL FILES PROCESSED
	USCRT.	(.EQAFT(J))		;CREATION DATE/TIME OF REQUEST
	USSCD.	(J$RTIM(J))		;SCHEDULED DATE/TIME
	USFRM.	(J$FORM(J))		;FORMS TYPE
	USDSP.	(<SIXBIT/NORMAL/>,US%IMM) ;DISPOSITION
	USPRI.	(J$APRI(J))		;JOB PRIORITY

TOPS20<	USJNO.	(-1)			;JOB NUMBER
	USTRM.	(-1)			;TERMINAL DESIGNATOR
	USLNO.	(-1)			;TTY LINE NUMBER
	USTXT.	(<-1,,[ASCIZ / /]>)	;SYSTEM TEXT
	USNM2.	(<POINT 7,.EQOWN(J) >)  ;USER NAME (TOPS20)
	USACT.	(<POINT 7,.EQACT(J) >)	;ACCOUNT STRING POINTER
	0				;END OF LIST
> ;END TOPS20 ACCOUNTING

TOPS10<	USNM1.	(.EQOWN(J))		;USER NAME 1 (TOPS10)
	USNM3.	(.EQOWN+1(J))		;USER NAME 1 (TOPS10)
	USORI.	(.EQRID(J))		;USER REQUEST ID
	USPPN.	(.EQOID(J))		;USER PPN
	USJNO.	(LPJOB)			;JOB NUMBER
	USTRM.	(LPTRM)			;TERMINAL DESIGNATOR
	USLNO.	(LPLNO)			;TTY LINE NUMBER
	USOCN.	(LPCON)			;CONNECT TIME
	USOAC.	(<POINT 7,.EQACT(J) >)	;ACCOUNT STRING POINTER
> ;END TOPS10 ACCOUNTING

	ACTLEN==.-ACTLST		;ACCOUNTING BLOCK LENGTH

FACT<	FACSIZ==13			;Size of fact accounting block
	EXP	.FACT			;DAEMON WRITE FACT FILE FUNCTION
FACTBL:	BLOCK	FACSIZ  >		;FACT BLOCK FILLED IN

> ;END IFN FTACNT
SUBTTL	INPOPN  --  Routine to open the input file

;INPOPN IS CALLED WITH AC "E" POINTING TO THE FP AREA FOR THE FILE
;	TO BE OPENED.

INPOPN:	MOVEI	S1,FOB.SZ		;GET THE FOB SIZE
	MOVEI	S2,J$XFOB(J)		;AND THE FOR ADDRESS
	PUSHJ	P,.ZCHNK		;ZERO IT OUT
	LOAD	S1,.FPLEN(E),FP.LEN	;GET THE FP LENGTH
	ADD	S1,E			;GET THE FD ADDRESS
	MOVEM	S1,J$DFDA(J)		;SAVE THE ADDRESS
	STORE	S1,J$XFOB+FOB.FD(J)	;SAVE IN THE FOB
	MOVEI	S1,7			;LOAD PROBABLE (7 BIT) BYTE SIZE
	LOAD	T1,.FPINF(E),FP.FFF	;GET /FILE:
	LOAD	T2,.FPINF(E),FP.FPF	;GET /PRINT:
	CAXN	T1,.FPF8B		;WAS IT /FILE:8-BIT???
	MOVEI	S1,^D8			;YES, LOAD 8 BIT BYTE SIZE
	CAXN	T1,.FPF11		;WAS IT /FILE:ELEVEN???
	MOVEI	S1,^D36			;YES, LOAD 36 BIT BYTE SIZE
	CAIE	T1,.FPFCO		;/FILE:COBOL?
	CAIN	T2,%FPLOC		;OR /PRINT:OCTAL?
	MOVEI	S1,^D36			;YES, USE FULL WORDS
	STORE	S1,J$XFOB+FOB.CW(J),FB.BSZ  ;AND SAVE THE BYTE SIZE
	SETZM	J$XFOB+FOB.US(J)	;DEFAULT TO NO ACCESS CHECKING
	SETZM	J$XFOB+FOB.CD(J)	;HERE ALSO
	LOAD	S1,.EQSEQ(J),EQ.PRV	;GET THE USERS PRIVILGE BITS
	JUMPN	S1,INPO.1		;IF SET, AVOID ACCESS CHECK
	LOAD	S1,.FPINF(E),FP.SPL	;LIKEWISE IF SPOOLED
	JUMPN	S1,INPO.1		; ...

TOPS10 <
	MOVE	S1,.EQOID(J)		;GET THE PPN
	STORE	S1,J$XFOB+FOB.US(J)	;AND SAVE IT
>  ;END TOPS10 CONDITIONAL

TOPS20 <
	HRROI	S1,.EQOWN(J)		;GET THE OWNERS NAME
	STORE	S1,J$XFOB+FOB.US(J)	;SAVE IT
	HRROI	S1,.EQCON(J)		;GET CONNECTED DIRECTORY
	STORE	S1,J$XFOB+FOB.CD(J)	;AND SAVE IT
>  ;END TOPS20 CONDITIONAL

INPO.1:	MOVEI	S1,FOB.SZ		;GET FOB SIZE
	MOVEI	S2,J$XFOB(J)		;AND ADDRESS
	PUSHJ	P,F%IOPN		;OPEN THE FILE
	JUMPF	INPO.2			;JUMP IF FAILED
	MOVEM	S1,J$DIFN(J)		;ELSE, SAVE THE IFN
;**;[2774] Insert 7 lines after INPO.1+4L. 25-Oct-83  /LWS
	SETZM	J$GSPL(J)		;[2774] ASSUME NOT SPOOLED
	LOAD	S2,.FPINF(E),FP.SPL	;[2774] GET SPOOLED FILE BIT
	JUMPE	S2,.RETT		;[2774] RETURN IF NOT SPOOLED
	MOVX	S2,FI.SPL		;[2774] GET ATTRIBUTE WE WANT
	$CALL	F%INFO			;[2774] ASK FOR SPOOLED FILE NAME
	JUMPE	S1,.RETT		;[2774] RETURN IF NONE
	$TEXT(<-1,,J$GSPL(J)>,< ^W/S1/^0>) ;[2774] SAVE NAME AS ASCIZ STRING
					; (WITH LEADING SPACE)
	$RETT				;AND RETURN

INPO.2:	ZERO	.FPINF(E),FP.DEL	;CLEAR THE 'DELETE FILE' BIT
	PUSHJ	P,@J$FLER(J)		;DO FILE LOOKUP ERROR PROCESSING
	$RETF				;RETURN

LPTLER::$TEXT(LOGCHR,<^I/LPERR/Can't access file ^F/@J$DFDA(J)/, ^E/[-1]/>)
	$RETF				;AND RETURN

SUBTTL	INPBUF  --  Read a buffer from the input file

INPBUF:	MOVE	S1,J$DIFN(J)		;GET THE IFN
	PUSHJ	P,F%IBUF		;GET A BUFFERFUL
	JUMPF	INPERR			;LOSE
	MOVEM	S1,J$DBCT(J)		;SAVE THE BYTE COUNT
	MOVEM	S2,J$DBPT(J)		;AND THE BYTE POINTER
	AOS	J$ADRD(J)		;ADD 1 TO BUFFER READ COUNT.
	EXCH	S1,J$FCBC(J)		;GET OLD BUFR BYTE CNT AND SAVE NEW
	ADDM	S1,J$FTBC(J)		;BUMP TOTAL BYTES PROCESSED
	$RETT				;THEN RETURN.

SUBTTL	INPBYT  --  Read a byte from the input file

INPBYT::SOSGE	J$DBCT(J)		;MAKE SURE THERE IS DATA IN THE BUFFER.
	JRST	INPB.1			;IF NOT, GET ANOTHER BUFFER.
	ILDB	C,J$DBPT(J)		;PICK UP A BYTE FROM THE BUFFER.
	$RETT				;AND RETURN.
INPB.1:	PUSHJ	P,INPBUF		;READ THE NEXT BUFFER.
	JUMPF	.RETF			;NO MORE, RETURN.
	JRST	INPBYT			;ELSE GET THE NEXT BYTE.

SUBTTL	INPERR  --  Handle an input failure

INPERR:	CAXN	S1,EREOF$		;WAS IT EOF?
	$RETF				;WAS JUST RETURN
	TXO	S,SKPFIL		;SKIP THE REST OF THE FILE
	PUSHJ	P,@J$FIER(J)		;DO FILE INPUT ERROR PROCESSING
	$RETF				;RETURN

LPTIER::$TEXT(LOGCHR,<^I/LPERR/Error reading input file; ^E/[-1]/>)
	$RETF				;AND RETURN
SUBTTL	INPFEF  --  Force end-of-file on next input

INPFEF::SKIPN	S1,J$DIFN(J)		;IS THE SPOOL FILE OPEN ???
	$RETT				;NO, JUST RETURN
	SETOB	S2,J$DBCT(J)		;CLEAR BYTE COUNT AND SET EOF POS
	PUSHJ	P,F%POS			;AND POSITION IT
	$RETT				;AND RETURN

SUBTTL	INPREW  --  Rewind the input file

INPREW:	MOVE	S1,J$DIFN(J)		;GET THE IFN
	PUSHJ	P,F%REW			;REWIND IT
	SETOM	J$DBCT(J)		;AND SET THE BYTE COUNT
	SETZM	J$RNPP(J)		;AND SET PAGE 0
	MOVEI	S1,J$FPAG(J)		;GET THE PAGE COUNTER TABLE ADDRESS
	MOVEM	S1,J$FBPT(J)		;AND SAVE IT.
	SETZM	J$FCBC(J)		;CLEAR CURRENT INPUT BUFFER BYTE COUNT
	SETZM	J$FTBC(J)		;CLEAR TOTAL INPUT BYTE COUNT
	TXZ	S,FBPTOV		;CLEAR PAGE TABLE OVERFLOW BIT
	MOVX	S1,PAGSIZ		;GET THE TABLE LENGTH.
	MOVEI	S2,J$FPAG(J)		;GET THE START ADDRESS.
	PJRST	.ZCHNK			;RETURN, ZEROING THE PAGE TABLE
SUBTTL	FORMS   --  Setup Forms for a job

FORMS:	TXNE	S,ABORT			;ARE WE ABORTING?
	$RETF				;YES, END THE REQUEST
	GETLIM	S1,.EQLIM(J),FORM	;GET THE FORMS TYPE
	CAMN	S1,J$FORM(J)		;OR ARE FORMS EXACTLY THE SAME?
;**;[3012] Replace one line at FORMS+4L. /LWS
	JRST	FORM4A			;[3012] YES, GO CHECK RAM AND VFU
	HRLZI	S2,J$WTOR(J)		;Get the start address of the buffer
	HRRI	S2,J$WTOR+1(J)		; and +1
	SETZM	J$WTOR(J)		;Want to zero it all
	BLT	S2,J$WTOR+^D50-1(J)	;Zap it
	MOVE	S2,[POINT 7,J$WTOR(J)]	;GET POINTER TO WTOR BUFFER.
	MOVEM	S2,TEXTBP		;AND SAVE IT FOR DEPBP.
	SKIPN	S2,J$FORM(J)		;GET FORMS TYPE
	MOVX	S2,FRMNOR		;USE NORMAL IF NULL
	XOR	S1,S2			;GET COMMON PART
	AND	S1,[EXP FRMSK1]		;AND IT WITH THE IMPORTANT PART
	GETLIM	S2,.EQLIM(J),FORM	;GET FORMS TYPE
	EXCH	S2,J$FORM(J)		;SAVE IT
	MOVEM	S2,J$FPFM(J)		;SAVE OLD ONES
	SKIPE	S1			;NO NEED TO CHANGE FORMS.
	$TEXT	(DEPBP,<Please load forms type '^W/J$FORM(J)/'>)

FORM.1:	MOVE	S1,J$FDRU(J)		;GET THE CURRENT DRUM TYPE
	MOVEM	S1,J$PDRU(J)		;AND SAVE IT
	MOVE	S1,J$FRIB(J)		;GET THE CURRENT RIBBON TYPE
	MOVEM	S1,J$PRIB(J)		;AND SAVE IT
	MOVE	S1,J$FTAP(J)		;GET THE CURRENT CARRIAGE CONTROL TAPE
	MOVEM	S1,J$PTAP(J)		;AND SAVE IT
	MOVE	S1,J$LRAM(J)		;GET THE DEFAULT RAM FILE NAME
	MOVEM	S1,J$FRAM(J)		;AND MAKE IT THE CURRENT RAM TYPE
	HRLZI	S1,-F$NSW		;GET NEGATIVE SWITCH TABLE LEN
	MOVEI	T1,J$FCUR(J)		;POINT TO CURRENT FORMS PARAMS

FORM.2:	MOVE	S2,FFDEFS(S1)		;GET A DEFAULT
	CAME	S2,[-1]			;IS THIS SUPPOSED TO BE DEFAULTED ???
	MOVEM	S2,(T1)			;YES, SAVE IT
	ADDI	T1,1			;INCREMENT NEW PARAM STORE CTR
	AOBJN	S1,FORM.2		;AND LOOP

	GETLIM	T1,.EQLIM(J),FORM	;FORMS NAME
	MOVEM	T1,J$FALI(J)		;SAVE IT AS DEFAULT ALIGN FILE NAME

	PUSHJ	P,FRMINI		;READ THE LPFORM.INI FILE.
	JUMPT	FORM.3			;Skip the message if ok
	SKIPN	J$MNTF(J)		;DEVICE SUPPORT MOUNTABLE FORMS?
	JRST	FORM.3			;NO--IGNORE NOT FOUND ERROR
FRM.2A:	MOVE	S1,STREAM		;Get the stream number
	GETLIM	S2,.EQLIM(J),FORM	;Get forms type
	SETZM	JOBCHK(S1)		;SAY WE WANT TO TAKE A CHECKPOINT.
	SETOM	JOBUPD(S1)		;  update status also
	$WTOR	(<Form ^W/S2/ not found, defaults being used>,<^R/.EQJBB(J)/^T/FORMSG/>,@JOBOBA(S1),JOBWAC(S1))		;Tell the operator
	$DSCHD	(PSF%OR)		;WAIT FOR OPERATOR RESPONSE
	TXNE	S,ABORT+RQB		;HAVE WE BEEN CANCELED OR REQUEUED ???
	JRST	FORM.7			;YES, IGNORE THE ERROR
	MOVEI	S1,FRMANS		;POINT TO THE LIMIT ANSWER BLOCK
	HRROI	S2,J$RESP(J)		;POINT TO THE ANSWER
	PUSHJ	P,S%TBLK		;DO WE MATCH ???
	TXNE	S2,TL%NOM+TL%AMB	;DID WE FIND IT OK ???
	JRST	FRM.2A			;NO, STUPID OPERATOR SO TRY AGAIN
	HRRZ	S1,0(S1)		;GET THE ROUTINE ADDRESS
	JRST	0(S1)			;AND PROCESS THE RESPONSE

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

;  Set up the width and length classes

FORM.3:	MOVEI	S1,3			;START AT THREE FOR BOTH
	MOVEM	S1,J$FWCL(J)		;STORE IT
	MOVEM	S1,J$FLCL(J)		;STORE IT AGAIN
	MOVE	S1,J$FWID(J)		;GET THE WIDTH
	CAIG	S1,F$WCL2		;LE CLASS 2 LIMIT?
	SOS	J$FWCL(J)		;YES, SOS ONCE
	CAIG	S1,F$WCL1		;LE CLASS 1 LIMIT
	SOS	J$FWCL(J)		;YES, SOS AGAIN
	MOVE	S1,J$FLIN(J)		;Get the length
	CAIG	S1,F$LCL2		;LE class 2 limit?
	SOS	J$FLCL(J)		;Yes, sos once
	CAIG	S1,F$LCL1		;LE class 1 limit?
	SOS	J$FLCL(J)		;Yes, sos again

	SKIPN	J$MNTF(J)		;DEVICE SUPPORT MOUNTABLE FORMS?
	$RETT				;NO, JUST RETURN NOW !!
	MOVE	S1,TEXTBP		;GET THE WTOR BYTE POINTER.
	TXNE	S,FRMFND		;Were the forms found?
	 CAMN	S1,[POINT 7,J$WTOR(J)]	;IS THERE A MESSAGE FOR THE OPERATOR ??
	  JRST	FORM.5			;NO, TRY LOADING VFU AND RAM
	$TEXT	(DEPBP,<^T/ENDRSP/^0>)	;ADD THE RESPONSE TO THE END

FORM.4:	MOVE	S1,STREAM		;GET STREAM NUMBER
	$WTOR  (,<^T/J$WTOR(J)/>,@JOBOBA(S1),JOBWAC(S1)) ;SEND THE WTOR.
	SETZM	JOBCHK(S1)		;SAY WE WANT TO TAKE A CHECKPOINT.
	SETOM	JOBUPD(S1)		;  update status also
	$DSCHD	(PSF%OR)		;WAIT FOR OPERATOR RESPONSE.
	TXNE	S,ABORT+RQB		;HAVE WE BEEN CANCELED OR REQUEUED ???
	JRST	FORM.7			;Go replace the old forms
	MOVEI	S1,CONANS		;POINT TO THE CONTINUE ANSWER BLOCK
	HRROI	S2,J$RESP(J)		;POINT TO THE ANSWER
	PUSHJ	P,S%TBLK		;DO WE MATCH ???
	TXNE	S2,TL%NOM+TL%AMB	;DID WE FIND IT OK ???
	JRST	FORM.4			;NO, STUPID OPERATOR SO TRY AGAIN

;**;[3012] Add code at FORM.4+12L. /LWS
;Here to check the status of the VFU. If bad, load RAM and VFU.

FORM4A:	PUSHJ	P,VFUCHK		;CHECK VFU STATUS
	JUMPT	FORM.5			;[3014] IF OK, DON'T FORCE LOADS
	SETZM	J$FLRM(J)		;[3012] LOAD RAM AND VFU TO BE SAFE
	SETZM	J$FLVT(J)		;[3012]
	MOVE	S2,STREAM		;[3012] GET CURRENT STREAM
	$WTO	(VFU error,<Reloading RAM and VFU>,@JOBOBA(S2)) ;[3012]

FORM.5:	PUSHJ	P,LODRAM		;GET THE RAM LOADED
	TXNE	S,ABORT+RQB		;HAVE WE BEEN CANCELED ???
	$RETF				;YES, RETURN NOW
	PUSHJ	P,LODVFU		;LOAD VFU
	TXNE	S,ABORT+RQB		;HAVE WE BEEN CANCELED ???
	$RETF				;YES, RETURN NOW
	$RETT				;NO, HE WINS SO FAR !!!

FORM.6:	TXO	S,RQB			;Requeue the job
FORM.7:	MOVE	S1,J$FPFM(J)		;Get old forms
	MOVEM	S1,J$FORM(J)		;Restore it
	$RETF				;And return

ENDRSP:	ASCIZ	/Type 'RESPOND <number> PROCEED' when ready/

FRMANS:	$STAB
	 KEYTAB	(FORM.6,ABORT)		;ABORT
	 KEYTAB	(FORM.3,PROCEED)	;PROCEED
	$ETAB

FORMSG:	ASCIZ/
Type 'RESPOND <number> ABORT' to terminate the job now
Type 'RESPOND <number> PROCEED' after mounting correct forms, to allow the job to continue printing/
FMFD:	$BUILD	(FDXSIZ)		;BLOCK LENGTH
	  $SET	(.FDLEN,FD.LEN,FDXSIZ)	  ;LENGTH OF FILESPEC
	  $SET	(.FDLEN,FD.TYP,.FDNAT)	  ;NATIVE MODE FILESPEC
	  $SET	(.FDSTR,FWMASK,'SYS   ')  ;DEVICE NAME
	  $SET	(.FDNAM,FWMASK,'LPFORM')  ;FILE NAME
	  $SET	(.FDEXT,LHMASK,'INI')	  ;EXTENSION
	$EOB				;END OF BLOCK

FRMINI:	TXZ	S,FRMFND		;CLEAR THE FORMS FOUND FLAG
	SETZM	J$APRG(J)		;CLEAR ALIGNMENT NEEDED FLAG
	MOVEI	S1,FMFD			;FD FOR LPFORM.INI
	MOVEI	S2,0			;FOR NOW DON'T DO DATE/TIME CHECKING
	PUSHJ	P,FH$INI		;INIT FILE PROCESSING
	$RETIF				;RETURN ON ERRORS

FRMIN1:	PUSHJ	P,FH$SIX		;GET THE FORMS NAME
	JUMPT	FRMI1B			;Found something (No EOF)
	TXNE	S,FRMFND		;Have we found a match somewhere?
	 $RETT				;Yes, return good
	  $RETF				;No, do otherwise
FRMI1B:	MOVE	T1,S1			;GET RESULT
	GETLIM	T2,.EQLIM(J),FORM	;GET FORMS
	CAMN	T1,T2			;MATCH??
	JRST	FRMIN2			;YES!!
FRMI1A:	PUSHJ	P,FH$EOL		;NO, FIND NEXT LINE
	$RETIF				;EOF without finding the forms
	JRST	FRMIN1			;AND LOOP


FRMIN2:	TXO	S,FRMFND		;Remember we've found it
	CAIN	C," "			; Break on a space?
	 PUSHJ	P,FH$SKP		; Allow spaces, get non-blank char.
;**;[2777] Insert 2 lines at FRMIN2+2L. /LWS
	PUSHJ	P,FH$COM		;FLUSH COMMENT
	$RETIF				;CHECK FOR ERRORS
	CAIN	C,"/"			;BEGINNING OF SWITCH?
	JRST	FRMIN5			;YES, LOCATOR IS "ALL"
	CAIN	C,":"			;BEGINNING OF LOCATOR?
	JRST	FRMIN3			;YES, GO GET IT
	CAIN	C,.CHLFD		;EOL?
	JRST	FRMIN1			;YES, GO THE NEXT LINE
	PUSHJ	P,FH$CVT		;ELSE, GET A CHARACTER
	JUMPT	FRMIN2			;AND LOOP IF WE HAVE A CHARACTER

FRMINX:	PUSHJ	P,FH$XIT		;TERMINATE I/O
	SKIPGE	J$APRG(J)		;NEED ALIGMENT ???
	PUSHJ	P,OALI.2		;YES--DO IT NOW
	$RETT				;RETURN

FRMIN3:	PUSHJ	P,FH$SIX		;GET A LOCATOR
	JUMPF	FRMINX			;EOF!!
	SKIPN	T1,S1			;GET RESULT
	JRST	FRMI3A			;MAYBE PAREN??
	JRST	FRMIN4			;PROCESS THE LOCATOR

FRMI3A:	CAIN	C,"/"			;A SWITCH?
	JRST	FRMIN5			;YES!
	CAIE	C,"("			;A LIST?
	JRST	FRMIN9			;NO, ERROR
FRMIN4:	HLRZ	T2,T1			;GET THE FIRST THREE CHARS
	CAIN	T2,'ALL'		;IS IT "ALL"?
	JRST	FRMIN5			;YES, STOP CHECKING
	CAIN	T2,'LOC'		;IS IT LOCAL?
	SKIPGE	J$LREM(J)		;YES, ARE WE?
	  SKIPA				;NO, NO
	JRST	FRMIN5			;YES, YES!
	CAIN	T2,'REM'		;DOES IT SAY "REMOTE"?
	SKIPL	J$LREM(J)		;YES, ARE WE REMOTE
	  SKIPA				;NO!!!
	JRST	FRMIN5			;YES!!
	CAMN	T1,J$LDEV(J)		;COMPARE TO OUR DEVNAM
	JRST	FRMIN5			;MATCH!!

	CAIN	C,.CHLFD		;BREAK ON EOL?
	JRST	FRMIN1			;YES, GET NEXT LINE
	CAIE	C,"/"			;IS IT A SLASH?
	CAIN	C,")"			;NO, CLOSE PAREN?
	JRST	FRMI1A			;YES, GET THE NEXT LINE
	CAIN	C," "			; Break on space?
	 JRST	FRMI1A			; Yes, get the next line
	PUSHJ	P,FH$SIX		;ELSE, GET THE NEXT LOCATOR
	JUMPF	FRMINX			;EOF, FINISH UP
	SKIPN	T1,S1			;GET RESULT
	JRST	FRMIN9			;BAD FORMAT
	JRST	FRMIN4			;AND LOOP AROUND
;GET HERE IF THIS LINE IS FOR US

FRMIN5:	PUSHJ	P,FH$COM		;FLUSH COMMENT, CHECK LINE CONTINUATION
	$RETIF				;CHECK FOR ERRORS
	CAIN	C,.CHLFD	;WAS THE LAST CHARACTER A LINEFEED?
	JRST	FRMINX		;YES, FINISH UP
	CAIN	C,"/"		;ARE WE AT THE BEGINNING OF A SWITCH?
	JRST	FRMI5A		;YES, DO IT!
	PUSHJ	P,FH$CVT	;NO, GET A CHARACTER
	JUMPF	FRMINX		;EOF!!
	JRST	FRMIN5		;AND LOOP AROUND
FRMI5A:	PUSHJ	P,FH$SIX	;GET THE SWITCH
	JUMPF	FRMINX		;EOF!!
	SKIPE	T1,S1		;GET RESULT
	JRST	FRMIN6		;JUMP IF WE'VE GOT SOMETHING
	CAIN	C,.CHLFD	;EOL?
	JRST	FRMINX		;YES, FINISH UP
	JRST	FRMIN5		;ELSE, KEEP TRYING

FRMIN6:	MOVE	T4,T1		;SAVE SWITCH NAME FOR LATTER
	HLLZS	T1		;GET FIRST THREE CHARACTERS OF SWITCH
	MOVSI	T2,-F$NSW	;MAKE AOBJN POINTER

FRMIN7:	HLLZ	T3,FFNAMS(T2)	;GET A SWITCH NAME
	CAMN	T3,T1		;MATCH??
	JRST	FRMIN8		;YES, DISPATCH
	AOBJN	T2,FRMIN7	;NO, LOOP
	MOVEI	S1,[ITEXT (<Unknown switch ^W/T4/ in line ^D/INILIN/>)]
	MOVEI	S2,[ITEXT (<Unknown switch ^W/T4/ reading ^F/@INIFOB+FOB.FD/>)]
	PJRST	FH$ERR		;REPORT ERROR AND RETURN

FRMIN8:	HRRZ	T3,FFNAMS(T2)	;GET DISPATCH ADDRESS
	PUSHJ	P,(T3)		;GO!!
	JRST	FRMIN5		;AND LOOP

FRMIN9:	MOVEI	S1,[ITEXT (<File format error encountered in line ^D/INILIN/>)]
	MOVEI	S2,[ITEXT (<File format error reading ^F/@INIFOB+FOB.FD/>)]
	PJRST	FH$ERR		;REPORT ERROR AND RETURN
SUBTTL	Forms Switch Subroutines


S$BANN:	CAIE	C,":"			;ARGUMENT FOLLOWING?
	SKIPA	S1,D$BANN		;GET DEFAULT
	PUSHJ	P,FH$DEC		;READ IT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FBAN(J)		;STORE IT
	$RETT				;AND RETURN

S$TRAI:	CAIE	C,":"			;ARGUMENT FOLLOWING?
	SKIPA	S1,D$TRAI		;GET DEFAULT
	PUSHJ	P,FH$DEC		;READ IT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FTRA(J)		;STORE IT
	$RETT				;AND RETURN

S$HEAD:	CAIE	C,":"			;ARGUMENT FOLLOWING?
	SKIPA	S1,D$HEAD		;GET DEFAULT
	PUSHJ	P,FH$DEC		;READ IT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FHEA(J)		;STORE IT
	$RETT				;AND RETURN

S$LINE:	CAIE	C,":"			;ARGUMENT FOLLOWING?
	SKIPA	S1,D$LINE		;GET DEFAULT
	PUSHJ	P,FH$DEC		;READ IT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FLIN(J)		;STORE IT
	POPJ	P,			;AND RETURN

S$WIDT:	CAIE	C,":"			;ARGUMENT FOLLOWING?
	SKIPA	S1,D$WIDT		;GET DEFAULT
	PUSHJ	P,FH$DEC		;READ IT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FWID(J)		;SAVE IT
	POPJ	P,			;AND RETURN

S$RIBB:	PUSHJ	P,FH$SIX		;GET SIXBIT ARGUMENT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FRIB(J)		;SAVE IT
	CAME	S1,J$PRIB(J)		;SKIP IF NOT CHANGED
	$TEXT	(DEPBP,<Load Ribbon type '^W/J$FRIB(J)/'>)
	POPJ	P,			;AND RETURN

S$DRUM:
S$CHAI:	PUSHJ	P,FH$SIX		;GET SIXBIT ARG
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FDRU(J)		;SAVE IT
	CAME	S1,J$PDRU(J)		;SKIP IF NOT CHANGED
	$TEXT	(DEPBP,<Load DRUM (CHAIN) type '^W/J$FDRU(J)/'>)
	POPJ	P,			;AND RETURN

S$NOTE:	SETZM	J$FNBK(J)		;INIT STORAGE
	PUSHJ	P,FH$QST		;GET POSSIBLY QUOTED STRING
	JUMPF	S$NOT1			;EOF
	SKIPN	(S1)			;ANY TEXT RETURNED?
	JRST	S$NOT1			;NO
	HRLZS	S1			;GET ADDR OF RESULT IN LH
	HRRI	S1,J$FNBK(J)		;MAKE A BLT POINTER
	ADDI	S2,J$FNBK(J)		;COMPUTE END OF BLT
	BLT	S1,-1(S2)		;COPY TEXT

S$NOT1:	$TEXT	(DEPBP,<Note: ^T/J$FNBK(J)/>) ;ADD THE MSG TO WTOR.
	$RETT				;RETURN.

S$ALCN:	CAIE	C,":"			;ARGUMENT FOLLOWING?
	SKIPA	S1,D$ALCN		;GET DEFAULT
	PUSHJ	P,FH$DEC		;READ IT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FALC(J)		;STORE IT
	SETOM	J$APRG(J)		;FLAG ALIGNMENT NEEDED
	$RETT				;AND RETURN

S$ALSL:	CAIE	C,":"			;ARGUMENT FOLLOWING?
	SKIPA	S1,D$ALSL		;GET DEFAULT
	PUSHJ	P,FH$DEC		;READ IT
	$RETIF				;CHECK FOR ERRORS
	MOVEM	S1,J$FALS(J)		;SAVE IT
	SETOM	J$APRG(J)		;FLAG ALIGNMENT NEEDED
	$RETT				;AND RETURN

S$ALIG:	PUSHJ	P,FH$SIX		;GET THE ALIGN FILENAME ARGUMENT
	$RETIF				;CHECK FOR ERRORS
	SKIPE	S1			;SKIP IF NOTHING THERE
	MOVEM	S1,J$FALI(J)		;SAVE THE ALIGN FILENAME
	SETOM	J$APRG(J)		;FLAG ALIGNMENT NEEDED
	POPJ	P,			;AND RETURN

S$VFU:
S$TAPE:	PUSHJ	P,FH$SIX		;GET SIXBIT ARGUMENT
	JUMPF	.RETT			;EOF
	MOVEM	S1,J$FTAP(J)		;SAVE IT
	CAME	S1,J$PTAP(J)		;ARE OLD AND NEW THE SAME?
	SKIPE	J$LDVF(J)		;OR DOES DEVICE HAVE A DAVFU?
	$RETT				;OLD=NEW OR SOFTWARE VFU,,RETURN
	$TEXT	(DEPBP,<Load CARRIAGE CONTROL TAPE '^W/J$FTAP(J)/'>)
	$RETT

S$RAM:	PUSHJ	P,FH$SIX		;GET THE SIXBIT ARGUMENT
	JUMPF	.RETT			;EOF
	MOVEM	S1,J$FRAM(J)		;SAVE IT
	$RETT				;AND RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTOPR - ASK FOR OPERATOR ACTION


; ROUTINE TO ASK THE OPERATOR FOR HELP
; CALL:	MOVE	T1, WTO TYPE TEXT ADDRESS
;	MOVE	T2, WTO MESSAGE TEXT ADDRESS
;	MOVE	T3, KEYWORD TABLE ADDRESS
;	PUSHJ	P,LPTOPR
;
; TRUE RETURN:	S1 WILL CONTAIN THE KEYWORD TABLE OFFSET
; FALSE RETURN:	STREAM CANCELED OR REQUEUED

LPTOPR::MOVE	T4,STREAM		;GET STREAM NUMBER
	SETOM	JOBCHK(T4)		;FORCE A CHECKPOINT
	$WTOR	(<^I/(T1)/>,<^I/(T2)/>,@JOBOBA(T4),JOBWAC(T4))
	$DSCHD	(PSF%OR)		;WAIT FOR OPERATOR RESPONSE
	TXNE	S,ABORT+RQB		;STREAM CANCELED?
	$RETF				;YES
	MOVEI	S1,(T3)			;POINT TO KEYWORD TABLE
	HRROI	S2,J$RESP(J)		;AND TO OPERATOR RESPONSE
	PUSHJ	P,S%TBLK		;SCAN THE TABLE
	TXNE	S2,TL%NOM!TL%AMB	;NO MATCH OR AMBIGUOUS?
	JRST	LPTOPR			;GO TRY AGAIN
	HRRZ	S1,(S1)			;GET KEYWORD DATA FROM TABLE
	$RETT				;RETURN WITH ANSWER IN S1
SUBTTL	RANDOM DEVICE CONTROL -- LODVFU - LOAD GENERIC VFU

LODVFU:	SKIPN	J$LDVF(J)		;IS VFU LOADABLE?
	 $RETT				;NOPE, PRETEND ALL IS WELL
VFU.1:	MOVE	S1,J$FTAP(J)		;GET NECESSARY VFU TYPE
	CAMN	S1,J$FLVT(J)		;IS IT IN THERE ALREADY?
	$RETT				;YES, RETURN
	MOVE	S1,STREAM		;GET STREAM NUMBER
	$WTO  (Loading VFU with '^W/J$FTAP(J)/',,@JOBOBA(S1))
	PUSHJ	P,@J$FLSH(J)		;FLUSH THE OUTPUT BUFFERS
	JUMPF	SHUTIN			;CANT,,SHUT IT DOWN
	TXO	S,VFULOD		;FLAG THE FACT WE'RE LOADING THE VFU

;ON SYSTEM STARTUP, SEE IF THE VFU IS VALID AND IF SO THROW OUT A
;FORM FEED. IF NOT, ASK OPR TO ALIGN FORMS BEFORE LOADING VFU.
	SKIPE	J$LVFF(J)		;IS THIS THE FIRST TIME THROUGH ???
	JRST	VFU.3			;NO, SKIP THIS
	SETOM	J$LVFF(J)		;RESET THE FIRST TIME THROUGH FLAG
	PUSHJ	P,VFUCHK		;CHECK VFU STATUS
	JUMPF	VFU.2			;DONT OUTPUT FORM FEED IF BAD
	MOVX	C,.CHFFD		;GET FORM FEED CODE
	PUSHJ	P,DEVOUT		;PUT IT OUT
	PUSHJ	P,OUTDMP		;ALIGN THE FORMS ON THE PRINTER
	JRST	VFU.3			;AND GO RELOAD THE VFU

VFU.2:	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	$WTOR(<Align Forms and Put Online>,<^T/ENDRSP/>,@JOBOBA(S1),JOBWAC(S1))
	SETZM	JOBCHK(S1)		;TAKE A CHECKPOINT WHEN WE CAN
	SETOM	JOBUPD(S1)		;  update status also
	$DSCHD	(PSF%OR)		;WAIT FOR THE OPERATOR RESPONSE
	TXNE	S,ABORT+RQB		;ARE WE STILL IN BUSINESS ???
	JRST	[SETZM J$FORM(J)	;NO, ZAP THE LOADED FORMS TYPE
		 TXZ   S,VFULOD		;CLEAR THE VFU LOAD FLAG
		 $RETT ]		;AND RETURN
	MOVEI	S1,CONANS		;GET THE ANSWER BLOCK ADDRESS
	HRROI	S2,J$RESP(J)		;POINT TO THE OPERATORS RESPONSE
	$CALL	S%TBLK			;CHECK ONE AGAINST THE OTHER
	TXNE	S2,TL%NOM+TL%AMB	;DO THEY MATCH ???
	JRST	VFU.2			;NO, STUPID OPERATOR -- TRY AGAIN !!

VFU.3:	MOVEI	S1,1			;CODE TO LOAD VFU
	PUSHJ	P,@J$VFU(J)		;TRY TO LOAD THE VFU
	JUMPF	@[IFIW	HDWVFU		;(0) VFU FILE NOT FOUND, HDW VFU LOADED
		  IFIW	VFUFAI		;(1) LOAD FAILED, OPR ACTION REQUEST
		  IFIW	NODAVF](S1)	;(2) NO DAVFU AFTER ALL
	MOVE	S1,J$FTAP(J)		;GET THE VFU TYPE WE JUST LOADED
	MOVEM	S1,J$FLVT(J)		;SAVE IT AS LOADED VFU TYPE
	TXZ	S,VFULOD		;CLEAR THE VFU LOAD FLAG
	PUSHJ	P,@J$FLSH(J)		;FLUSH THE OUTPUT BUFFERS
	JUMPF	SHUTIN			;CANT,,SHUT IT DOWN
	$RETT
SUBTTL	RANDOM DEVICE CONTROL -- LODRAM - LOAD GENERIC RAM

LODRAM:	MOVE	S1,J$FRAM(J)		;GET THE RAM WE WANT
	 SKIPE	J$LDRM(J)		;IF NOT LOADABLE, 
	CAMN	S1,J$FLRM(J)		;  OR ALREADY LOADED
	 $RETT				;YES, RETURN NOW !!!
	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	$WTO	(Loading RAM with '^W/J$FRAM(J)/',,@JOBOBA(S1))
	PUSHJ	P,@J$RAM(J)		;DO DEVICE DEPENDENT LOAD
	 JUMPF	@[IFIW	HDWRAM		;(0) RAM LOAD FAILED, HARDWARE RAM USED
		  IFIW	NORAM		;(1) RAM LOAD FAILED, NEED OPR ACTION
		  IFIW	NOTRAM](S1)	;(2) RAM LOAD FAILED, NOT PRESENT
	MOVE	S1,J$FRAM(J)		;GET THE RAM TYPE WE JUST LOADED
	MOVEM	S1,J$FLRM(J)		;SAVE IT AS LOADED RAM TYPE
	POPJ	P,			;LOAD SUCCEEDED

HDWRAM:	MOVE	T1,D$RAM		;GET NAME OF NORMAL
	MOVEM	T1,J$FLVT(J)		;STORE IT
	MOVE	S1,STREAM		;GET STREAM NUMBER
	$WTO  (Error loading RAM, Loaded hardware RAM instead.,@JOBOBA(S1))
	$RETT

NORAM:	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	$WTOR	(,<^I/RAMI1/^J^M^T/RAMI2/>,@JOBOBA(S1),JOBWAC(S1))
	SETZM	JOBCHK(S1)		;WE WANT A CHECKPOINT TAKEN
	SETOM	JOBUPD(S1)		;  Update also
	$DSCHD	(PSF%OR)		;WAIT FOR THE OPERATOR RESPONSE
	TXNE	S,ABORT+RQB		;CANCELED OR REQUEUED ???
	JRST	[SETZM J$FORM(J)	;YES, ZAP THE LOADED FORMS TYPE
		 $RETT ]		;AND RETURN
	HRROI	S1,J$RESP(J)		;GET THE RESPONSE ADDRESS
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVEM	S2,J$FRAM(J)		;SAVE THE NEW RAM TYPE
	JRST	LODRAM			;AND TRY AGAIN

RAMI1:	ITEXT	(<RAM Error, Can't Load RAM '^W/J$FRAM(J)/'>)
RAMI2:	ASCIZ	/Respond With RAM Type to Continue/


NOTRAM:	SETZM	J$LDRM(J)		;NOT LOADABLE AFTER ALL
	$RETT
SUBTTL	COMMON DEVICE CONTROL -- LPTDVN - GENERATE DEVICE NAME


; ROUTINE TO GENERATE A DEVICE NAME
; CALL:	MOVE	S1,[SIXBIT /DEV/]
;	PUSHJ	P,GENDEV

LPTDVN::MOVEM	S1,J$LDEV(J)		;SAVE DEVICE
	TRNE	S1,-1			;GIVEN FULL NAME?
	POPJ	P,			;YES--DONE
	MOVE	T1,STREAM		;PICK UP STREAM NUMBER.
	MOVE	T1,JOBOBA(T1)		;PICK UP OBJECT BLOCK ADDRESS.
	MOVE	T2,OBJ.ND(T1)		;PICK UP THE NODE NUMBER.
	IDIVI	T2,10			;SPLIT NODE NUMBER IN HALF.
	IMULI	T2,100			;SHIFT LEFT 2 DIGITS.
	ADD	T2,T3			;ADD SECOND NODE DIGIT.
	IMULI	T2,100			;SHIFT LEFT ANOTHER 2 DIGITS.
	ADD	T2,OBJ.UN(T1)		;ADD THE UNIT NUMBER.
	ADDI	T2,'000'		;MAKE SIXBIT
	IORB	T2,J$LDEV(J)		;AND SAVE IT
	IONDX.	T2,UU.PHY		;GET I/O INDEX
	  SETZ	T2,			;???
	MOVEM	T2,J$LION(J)		;SAVE IT
	POPJ	P,			;RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTLIN - GENERATE ANF-10 TTY NAME


; RESOLVE SYSTEM-WIDE TTY NAME TO A SPECIFIC TTY ON A GIVEN
; ANF-10 STATION, CONNECT LINE, AND RUN INITIA
; CALL:	MOVE	S1, SIXBIT/TTYNNN/
;	PUSHJ	P,LPTLIN
;
; TRUE RETURN:	TTY NAME UPDATED IN J$LDEV, I/O INDEX IN J$LION
; FALSE RETURN:	NOT A TTY, NO SUCH TTY, OR CAN'T CONNECT LINE

LPTLIN::MOVE	T1,S1			;COPY TTY NAME
	MOVE	T4,T1			;SAVE DEVICE NAME
	HLRZ	T2,T1			;GET DEVICE MNEMONIC
	CAIN	T2,'TTY'		;BETTER BE TTY
	TRNN	T1,777777		;AND A UNIT NUMBER
	$RETF				;CAN'T HANDLE ANYTHING ELSE
	HRRZS	T1			;REMOVE JUNK
	MOVSI	T3,-3			;LOOP COUNT

LINE.1:	TRNE	T1,77			;DIGIT PRESENT?
	JRST	LINE.2			;YES--GO ENTER LOOP
	LSH	T1,-6			;RIGHT JUSTIFY
	TRO	T3,-1			;INCASE WE JUMP OUT NEXT TIME
	AOBJN	T3,LINE.1		;AND CHECK AGAIN

LINE.2:	SUBI	T1,'0'			;CONVERT TO OCTAL
	LSHC	T1,-3			;SAVE DIGIT
	LSH	T1,-3			;REMOVE JUNK
	AOBJN	T3,LINE.2		;LOOP
	LSHC	T1,3			;SHIFT IN A DIGIT
	SOJG	T3,.-1			;DO THEM ALL
	MOVE	T2,STREAM		;GET STREAM NUMBER
	MOVE	T2,JOBOBA(T2)		;AND THE OBJECT BLOCK
	MOVE	T2,OBJ.ND(T2)		;GET STATION NUMBER
	HRL	T1,T2			;MAKE IT NODE,,LINE
	MOVE	T3,T1			;COPY FOR NODE. UUO
	CAMN	T2,CNTSTA		;LOCAL?
	JRST	LINE.3			;YES
	MOVE	T1,[.NDTCN,,T2]		;SET UP UUO AC
	MOVEI	T2,2			;TWO WORDS
	NODE.	T1,			;TRY TO CONNECT THE LINE
	  SKIPA				;FAILED
	JRST	LINE.4			;LINE CONNECTED
	CAMN	T1,T2			;AC UNCHANGED (NO NETWORK SUPPORT)?
	$RETF				;NO SUCH LINE

LINE.3:	SKIPA	T1,T4			;USE ORIGINAL TTY NAME

LINE.4:	MOVE	T4,T1			;PRESERVE TTY NAME WE HAVE NOW
	DEVCHR	T1,UU.PHY		;GET INTERESTING BITS
	TXNN	T1,DV.TTY		;REALLY A TTY?
	$RETF				;NOPE
	MOVEM	T4,J$LDEV(J)		;SAVE AS DEVICE NAME
	IONDX.	T4,UU.PHY		;TRANSLATE TO I/O INDEX
	  $RETF				;CAN'T
	MOVEM	T4,J$LION(J)		;SAVE
	MOVE	T1,STREAM		;GET STREAM NUMBER
	MOVE	T1,JOBOBA(T1)		;AND THE OBJECT BLOCK
	MOVE	T1,OBJ.ND(T1)		;GET STATION NUMBER
	CAMN	T1,CNTSTA		;CENTRAL?
	$RETT				;YES--NO NEED TO RUN INITIA
	MOVE	T2,[2,,T3]		;SET UP UUO AC
	MOVE	T3,['INITIA']		;FORCED COMMAND NAME
	FRCUUO	T2,			;RUN INITIA SO TTY PARAMETERS GET SET
	  JFCL				;HOPE FOR THE BEST
	MOVEI	T1,^D30			;WAIT UP TO 30 SECONDS

LINE.5:	MOVEI	T2,1			;GET SLEEP TIME
	SLEEP	T2,			;WAIT FOR INITIA TO FINISH RUNNING
	MOVE	T2,J$LDEV(J)		;GET DEVICE NAME
	DEVCHR	T2,UU.PHY		;AND ITS CHARACTERISTICS
	TXNN	T2,DV.ASP		;ASSIGNED TO SOME OTHER JOB?
	TXNN	T2,DV.AVL		;NO--AVAILABLE TO OUR JOB?
	SOJG	T1,LINE.5		;MUST TRY AGAIN
	JUMPLE	T1,.RETF		;IF TIMED OUT, THEN SAY NOT AVAILABLE
	$RETT				;ELSE RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTOPN - OPEN DEVICE


; SET UP FOR I/O
; THIS ROUTINE WILL INIT A CHANNEL AND BUILD BUFFERS

LPTOPN::MOVE	S1,J$LDEV(J)		;GET DEVICE NAME
	DEVCHR	S1,			;GET CHARACTERISTICS
	MOVEM	S1,J$DCHR(J)		;SAVE FOR LATER
	TXNN	S1,DV.ASP		;ASSIGNED TO SOME OTHER JOB?
	TXNN	S1,DV.AVL		;NO--AVAILABLE TO OUR JOB?
	$RETF				;NOT RIGHT NOW, RESTORE OPEN BITS
	MOVE	S1,STREAM		;GET OUR STREAM NUMBER
	MOVEM	S1,J$LCHN(J)		;SAVE IT AS THE CHANNEL NUMBER
	MOVX	S2,PSF%DO+PSF%OB	;GET OFFLINE+OUTPUT BLOCKED BITS
	ANDCAM	S2,JOBSTW(S1)		;AND CLEAR THE SCHEDULING BITS
	LSH	S1,^D23			;SHIFT CHANNEL # TO RIGHT PLACE
	IOR	S1,[OPEN T1]		;MAKE IT AN INSTRUCTION
	TXO	T1,UU.AIO		;ASYNCH I/O
	MOVE	T2,J$LDEV(J)		;OUTPUT DEVICE NAME
	MOVSI	T3,J$LBRH(J)		;BUFFER HEADER
	XCT	S1			;AND EXECUTE IT
	  $RETF				;FAILED

OPEN.1:	SKIPGE	J$LREM(J)		;SKIP IF LOCAL PRINTER
	JRST	OPEN.4			;SETUP REGULAR BFRS FOR REMOTE
	MOVE	T1,J$LBUF(J)		;GET ADDRESS OF BUFFER PAGE
	SUBI	T1,BUFSIZ		;BACK UP ONE BUFFER
	SETZ	T2,			;CLEAR A COUNTER

OPEN.2:	ADDI	T1,BUFSIZ		;POINT TO NEXT BUFFER
	MOVEI	S1,BUFSIZ+1(T1)		;GET LINK TO NEXT BUFFER
	HRLI	S1,BUFSIZ-2		;AND NUMBER DATAWORDS+1
	MOVEM	S1,1(T1)		;AND STORE IT AWAY IN BUFFER
	CAIGE	T2,BUFNUM-1		;GOT THEM ALL?
	AOJA	T2,OPEN.2		;NO, LOOP AROUND

OPEN.3:	MOVNI	T2,BUFSIZ*BUFNUM	;LOAD -<COMPLETE BUFFER SIZE>
	ADDM	T2,1(T1)		;MAKE LAST BUFFER POINT TO FIRST
	MOVE	T1,J$LBUF(J)		;GET ADDRESS OF BUFFER PAGE BACK
	ADDI	T1,1			;POINT TO WORD 1
	TXO	T1,BF.VBR		;MAKE IT A VIRGIN RING
	MOVEM	T1,J$LBRH(J)		;AND PUT IT WHERE MONITOR WILL FIND IT
	$RETT				;RETURN

OPEN.4:	MOVE	S1,J$LBUF(J)		;GET ADR OF BUFFER PAGE
	EXCH	S1,.JBFF		;SWAP IT WITH JOBFF
	MOVE	S2,J$LCHN(J)		;GET THE CHANNEL NUMBER
	LSH	S2,^D23			;POSITION IT
	IOR	S2,[OUTBUF 1]		;MAKE AN INSTRUCTION
	XCT	S2			;AND EXECUTE IT
	MOVEM	S1,.JBFF		;RESTORE JOBFF
	$RETT				;RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTCLS - CLOSE DEVICE


LPTCLS::TXZE	S,INTRPT		;ARE WE CONNECTED TO INTRPT SYSTEM?
	PUSHJ	P,INTDCL		;YES, RELEASE THE INTERRUPTS
	MOVE	S1,J$LCHN(J)		;GET THE CHANNEL
	SKIPE	J$LREM(J)		;NO, ARE WE USING A REMOTE PRINTER?
	JRST	CLOS.1			;YES TO EITHER, ISSUE A CLOSE/RELEASE
	RESDV.	S1,			;RESET THE CHANNEL
	  JFCL				;IGNORE ANY ERRORS
	$RETT				;AND RETURN

CLOS.1:	LSH	S1,^D23			;POSITION THE CHANNEL NUMBER
	TLO	S1,(CLOSE 0,0)		;MAKE IT A CLOSE UUO
	XCT	S1			;CLOSE THE MAG TAPE
	MOVE	S1,J$LCHN(J)		;GET THE CHANNEL NUMBER AGAIN
	LSH	S1,^D23			;POSITION IT
	TLO	S1,(RELEASE 0,0)	;MAKE IT A RELEASE UUO
	XCT	S1			;RELEASE THE DEVICE
	$RETT				;AND RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTHDW - SETUP HARDWARE CHARACTERISTICS


LPTHDW::MOVE	T1,[2,,T2]		;ARG POINTER
	MOVX	T2,.DFHCW		;HARDWARE CHARACTERISTICS WORD
	MOVE	T3,J$LCHN(J)		;GET CHANNEL NUMBER
	DEVOP.	T1,			;READ THE CHARS
	  SETZ	T1,			;SHOULDN'T HAPPEN
	TXNE	T1,DF.LCP		;IS IT A LOWER-CASE PRINTER?
	SETOM	J$LLCL(J)		;YES, SET THE FLAG
	MOVE	S1,[SIXBIT/LP64/]	;DEFAULT RAM TO 64 CHARACTER
	SKIPE	J$LLCL(J)		;UNLESS ITS LOWER CASE
	MOVE	S1,[SIXBIT/LP96/]	;THEN DEFAULT TO 96 CHARACTER SET
	MOVEM	S1,J$LRAM(J)		;SAVE THE DEFAULT RAM FILE NAME
	MOVE	S1,D$TAPE		;GET THE DEFAULT VFU TYPE.
	SKIPN	J$FTAP(J)		;HAS THE VFU ALREADY BEEN DEFAULTED ???
	MOVEM	S1,J$FTAP(J)		;NO, SAVE AS THE VFU DEFAULT.
	LDB	S1,[POINTR(T1,DF.CLS)]	;GET THE CONTROLLER TYPE
	MOVEM	S1,J$LCLS(J)		;SAVE IT FOR LATER
	CAIN	S1,.DFS20		;LP20 CLASS DEVICE?
	 SETOM	J$LDRM(J)		;YES, ASSUME LOADABLE RAM
	SKIPE	J$LREM(J)		;OR IF THIS IS A REMOTE LPT
	 SETZM	J$LDRM(J)		;IT ISN'T LOADABLE AFTER ALL

	SETZM	J$LDVF(J)		;DON'T LOAD VFU (FOR NOW)
	LDB	T1,[POINTR(T1,DF.VFT)]	;GET VFU TYPE
	CAIN	T1,.DFVTD		;IS IT A DAVFU?
	SETOM	J$LDVF(J)		;YES, SET THE FLAG
	$RETT				;RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTVFU - LOAD/CHECK VFU

VFUCHK:	SKIPN	J$LDVF(J)		;[3012] IS THERE A VFU TO LOAD?
	$RETT				;[3012] NOTHING TO DO
	MOVEI	S1,0			;CHECK STATUS FUNCTION
	JRST	@J$VFU(J)		;TRY IT
SUBTTL	HARDWARE VFU LOADED INSTEAD OF REQUESTED VFU

HDWVFU:	MOVE	T1,D$TAPE		;GET NAME OF NORMAL
	MOVEM	T1,J$FLVT(J)		;STORE IT
	MOVE	S1,STREAM		;GET STREAM NUMBER
	$WTO  (Error loading VFU, Loaded hardware VFU instead.,@JOBOBA(S1))
	TXZ	S,VFULOD		;CLEAR THE VFU LOAD FLAG
	$RETT				;AND RETURN

;HERE WHEN DEVOP FAILS...CLEAR DAVFU FLAG AND RETURN

NODAVF:	SETZM	J$LDVF(J)		;CLEAR THE FLAG
	MOVE	S1,J$FTAP(J)		;GET THE FORMS TYPE.
	MOVEM	S1,J$FLVT(J)		;   AND SAVE THEM AS LAST USED.
	POPJ	P,			;AND RETURN

VFUFAI:	MOVE	S1,STREAM		;GET STREAM NUMBER
	$WTOR	(,<^I/VFUI1/^J^M^T/VFUI2/>,@JOBOBA(S1),JOBWAC(S1))
	SETZM	JOBCHK(S1)		;SAY WE WANT TO TAKE A CHECKPOINT.
	SETOM	JOBUPD(S1)		;  update status also
	$DSCHD	(PSF%OR)		;WAIT FOR THE REPLY.
	TXNE	S,ABORT+RQB		;HAVE WE BEEN CANCELED OR REQUEUED ??
	JRST	[SETZM J$FORM(J)	;YES, ZAP THE LOADED FORMS TYPE
		 TXZ   S,VFULOD		;CLEAR THE VFU LOAD FLAG
		 $RETT ]		;AND RETURN
	HRROI	S1,J$RESP(J)		;GET THE OPERATORS RESPONSE
	PUSHJ	P,S%SIXB		;CONVERT IT TO SIXBIT
	MOVEM	S2,J$FTAP(J)		;SAVE THE FORMS TYPE
	JRST	VFU.1			;TRY LOADING AGAIN.

VFUI1:	ITEXT	(<VFU Error, can't load VFU '^W/J$FTAP(J)/'>)
VFUI2:	ASCIZ	/Respond with VFU type to continue/
SUBTTL	COMMON DEVICE CONTROL -- LPTFLS - FLUSH A JOB


LPTFLS::SKIPE	J$LREM(J)		;SKIP IF LOCAL
	$RETT				;DO NOTHING SINCE ONLY 1 BUFFER
	PUSHJ	P,INTDCL		;DISCONNECT PRINTER INTERRUPTS
	MOVE	S1,J$LCHN(J)		;LOAD THE CHANNEL NUMBER
	RESDV.	S1,			;RESET THE CHANNEL
	  JFCL				;??
	PUSHJ	P,@J$OPEN(J)		;RE-INIT THE DEVICE
	CAIN	S1,%RSUOK		;ARE WE ALL RIGHT ???
	$RETT				;YES, JUST RETURN
	PUSHJ	P,RSETUP		;NO, SEND RESPONSE TO SETUP MSG
	$RETF				;AND RETURN
SUBTTL	COMMON DEVICE CONTROL - LPTOUT - OUTPUT A BUFFER


; NOTE:	The 'Output-Blocked' bit is set here in order to avoid a
; race condition which would allow LPTSPL to miss the 'Output-Done'
; interrupt. In particular, this avoids the problem of getting the
; 'Output-Done' interrupt before LPTSPL has set the 'Output-Blocked'
; bit when ; de-scheduling the stream. This situation would cause
; the stream to block forever, waiting for an interrupt which it had
; already received.

LPTOUT::MOVE	S1,STREAM		;GET THE STREAM NUMBER
	MOVX	S2,PSF%OB		;GET THE 'OUTPUT-BLOCKED' BIT
	IORM	S2,JOBSTW(S1)		;TURN ON THE 'OUTPUT-BLOCKED' BIT
	MOVE	S1,J$LIOS(J)		;GET I/O STATUS BITS
	HRL	S1,J$XIOS(J)		;AND POSSIBLE EXTENDED STATUS
	TDNE	S1,[-1,,IO.ERR]		;ANYTHING SET?
	JRST	OUT.1			;YES--MUST BE PSEUDO DEVICE NONSENSE
	ANDCAM	S1,J$LIOS(J)		;CLEAR I/O STATUS
	SETZM	J$XIOS(J)		;HERE TOO
	MOVE	S1,J$LCHN(J)		;GET THE CHANNEL NUMBER
	LSH	S1,^D23			;POSITION IT
	TLO	S1,(OUT 0,0)		;MAKE IT AN OUTPUT UUO
	XCT	S1			;OUTPUT THE BUFFER
	JRST	[MOVE   S1,STREAM	;NO ERROR,,GET OUR STREAM NUMBER
		 ANDCAM S2,JOBSTW(S1)	;   AND CLEAR THE OUTPUT BLOCKED BITS
		 $RETT	]		;      NOW WE CAN RETURN
OUT.1:	MOVE	S1,J$LCHN(J)		;GET THE CHANNEL NUMBER
	LSH	S1,^D23			;POSITION IT
	IOR	S1,[GETSTS J$LIOS(J)]	;MAKE IT AN INSTRUCTION
	XCT	S1			;AND EXECUTE IT
	MOVE	S1,J$LIOS(J)		;GET THE I/O STATUS BITS
	TRC	S1,IO.ERR		;MUST SEE IF
	TRCN	S1,IO.ERR		; EXTENDED STATUS NEEDED TOO
	JRST	OUT.2			;NO
	MOVE	TF,[2,,S1]		;PREPARE FOR DEVOP. UUO
	MOVEI	S1,.DFRES		;READ EXTENDED ERROR STATUS
	MOVE	S2,J$LCHN(J)		;GET CHANNEL NUMBER
	DEVOP.	TF,
	  SETZ	TF,			;???
	MOVEM	TF,J$XIOS(J)		;SAVE FOR POSTERITY
OUT.2:	MOVE	S1,J$LIOS(J)		;GET I/O STATUS
	MOVE	S2,J$XIOS(J)		;AND EXTENDED STATUS
	PUSHJ	P,@J$OUTE(J)		;DO DEVICE SPECIFIC ERROR PROCESSING
	JUMPF	LPTOEX			;JUMP IF UNRECOVERABLE ERROR
	$DSCHD(0)			;BLOCK FOR OUTPUT DONE (See Above)
	PJRST	@J$OUTP(J)		;AND TRY AGAIN
SUBTTL	COMMON DEVICE CONTROL -- LPTOER - OUTPUT ERROR PROCESSING


LPTOER::MOVE	S1,J$LIOS(J)		;GET I/O STATUS
	TRNE	S1,IO.ERR		;ANY ERROR BITS ON?
	JRST	OUTE.1			;YES--MUST INVESTIGATE
	$RETT				;Return good, (Output blocked)

OUTE.1:	PUSHJ	P,.SAVET		;SAVE ALL THE 'T' ACS
	MOVE	T4,STREAM		;GET THE STREAM NUMBER
	MOVX	S1,PSF%OB		;GET OUTPUT BLOCKED BIT
	ANDCAM	S1,JOBSTW(T4)		;CLEAR STATE
	MOVE	S1,J$LIOS(J)		;GET THE ERROR STATUS
	TRC	S1,IO.ERR		;TEST FOR ALL FOUR ERROR BITS
	TRCE	S1,IO.ERR		;BEING SET.
	JRST	OUTE.2			;AND THEY ARE NOT
	MOVE	T1,J$XIOS(J)		;GET EXTENDED STATUS
	CAIN	T1,IOVFE%		;IS THE ERROR BAD VFU ?
	JRST	VFUOER			;YES, DO SOME SPECIAL PROCESSING
	CAIN	T1,IOPAR%		;RAM PARITY ERROR?
	JRST	RAMOER			;YES
	CAIN	T1,IOUNC%		;UNDEFINED CHARACTER INTERRUPT?
	JRST	UNCOER			;YES

OUTE.2:	HRRZ	S1,J$LIOS(J)		;GET I/O STATUS
	MOVEI	S2,[ITEXT (<>)]		;ASSUME NO EXTENDED STATUS
	SKIPE	J$XIOS(J)		;IS THERE ONE?
	MOVEI	S2,[ITEXT (<Extended error status ^O/J$XIOS(J)/>)]
	$WTO  (<I/O error ^O6R0/S1/>,<^I/(S2)/>,@JOBOBA(T4))
	PJRST	LPTOEX			;GO FINISH UP
; OUTPUT ERROR -- UNDEFINED CHARACTER TRANSLATION
UNCOER:	$WTO	(<Undefined character interrupt>,<Requeueing job>,@JOBOBA(T4))
	SETZM	J$LERR(J)		;NO MORE ERRORS ALLOWED
	TXO	S,ABORT+RQB		;DONE WITH THIS JOB
	MOVE	S1,J$FRAM(J)		;GET RAM NAME
	CAME	S1,['LP64  ']		;NORMAL?
	CAMN	S1,['LP96  ']		;...
	PJRST	LPTDIE			;GO CROAK STREAM
	$RETT				;RETURN

; OUTPUT ERROR -- RAM PARITY
RAMOER:	$WTO	(RAM Parity Error,,@JOBOBA(T4)) ;YES, TELL OPERATOR
	PUSHJ	P,LPTOEX		;PERFORM SOME PRELIMINARY PROCESSING
	SETZM	J$FLRM(J)		;FORCE A RAM RELOAD
	PUSHJ	P,LODRAM		;DO A RELOAD
	SETZM	J$FLVT(J)		;[3012] LOAD THE VFU TOO, TO BE SAFE
	PUSHJ	P,LODVFU		;LOAD VFU
	$RETT				;AND RETURN


; OUTPUT ERROR -- VFU
VFUOER:	TXZN	S,VFULOD		;ARE WE ALREADY LOADING VFU?
	JRST	VFUOE1			;NO...
	$WTO	(VFU error while loading VFU,,@JOBOBA(T4)) ;YES
	MOVEI	S1,2			;ERROR, DISABLE LOAD
	PUSHJ	P,@J$VFU(J)		;DEVICE DEPENDENTLY
	PUSHJ	P,@J$FLSH(J)		;GO RESET THE DEVICE
	SETZM	J$FORM(J)		;SAY FORMS NOT LOADED
	MOVX	S1,%RSUNA		;GET "DEVICE NOT AVAILABLE"
	PUSHJ	P,RSETUP		;TELL QUASAR TO FORGET US FOR NOW
	PJRST	SHUTIN			;SHUTDOWN THE STREAM

VFUOE1:	$WTOR  (VFU error,<Re-align forms and put on-line^M^J^T/ENDRSP/>,@JOBOBA(T4),JOBWAC(T4))
	SETZM	JOBCHK(T4)		;SAY WE WANT A CHECKPOINT TAKEN
	SETOM	JOBUPD(T4)		;  update the status also
	$DSCHD(PSF%OR)			;WAIT FOR THE OPERATOR RESPONSE
	TXNE	S,ABORT+RQB		;HAVE WE BEEN CANCELED OR REQUEUED ???
	$RETT				;YES, JUST RETURN
	MOVEI	S1,CONANS		;POINT TO THE CONTINUE ANSWER BLOCK
	HRROI	S2,J$RESP(J)		;POINT TO THE ANSWER
	PUSHJ	P,S%TBLK		;DO WE MATCH ???
	TXNE	S2,TL%NOM+TL%AMB	;DID WE FIND IT OK ???
	JRST	VFUOER			;NO, STUPID OPERATOR SO TRY AGAIN
	PUSHJ	P,LPTOEX		;GO PERFORM SOME PRELIMINARY PROCESSING
	SETZM	J$FLRM(J)		;LOAD THE RAM FIRST, ESPECIALLY
	PUSHJ	P,LODRAM		;RELOAD THE RAM
	SETZM	J$FLVT(J)		;FORCE A VFU RELOAD
	PUSHJ	P,LODVFU		;LOAD THE VFU
	$RETT				;AND RETURN

CONANS:	$STAB
	 KEYTAB	(0,PROCEED)
	$ETAB
SUBTTL	COMMON DEVICE CONTROL -- LPTOEX - OUTPUT ERROR EXIT


LPTOEX:	PUSHJ	P,LPTDIE		;SEE IF TOO MANY ERRORS
	PUSHJ	P,@J$FLSH(J)		;RESET THE OUTPUT CHANNEL
	JUMPT	OEX.1			;GO FINISH UP
	MOVX	S1,%RSUNA		;GET 'DEVICE NOT AVAILABLE' ERROR
	PUSHJ	P,RSETUP		;TELL QUASAR TO RESET THE OBJECT
	PJRST	SHUTIN			;SHUT DOWN THE DEVICE

OEX.1:	TXNN	S,VFULOD+BANHDR		;IF LOADING VFU OR PRINTING HDRS
	SKIPN	J$DIFN(J)		;   OR IF WE ARE NOT IN A FILE?
	$RETT				;THEN JUST RETURN
	MOVE	S1,J$RNCP(J)		;GET NUMBER OF COPIES PRINTED
	AOS	S1			;MAKE INTO CURRENCT COPY NUMBER
	$TEXT	(LOGCHR,<^I/LPERR/I/O Error occurred during ^F/@J$DFDA(J)/^T/J$GSPL(J)/, Copy:^D/S1/, Page:^D/J$RNPP(J)/; Status is: ^O/J$LIOS(J)/>)
	MOVEI	S1,[EXP 5]		;PREPARE TO BACKSPACE 5 PAGES
	PUSHJ	P,BSPACE		;BACKSPACE 5 PAGES
	$RETT				;RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTRES - RESET OUTPUT BUFFERS


LPTRES::MOVEI	S1,BUFCHR		;GET CHARACTERS PER BUFFER
	MOVEM	S1,J$LBCT(J)		;SAVE AS BUFFER BYTE COUNT
	MOVEM	S1,J$LIBC(J)		;HERE ALSO
	MOVE	S1,J$LBUF(J)		;GET THE BUFFER ADDRESS
	ADD	S1,J$LBTZ(J)		;ADD THE BYTE PTR (LEFT HALF)
	MOVEM	S1,J$LBPT(J)		;SAVE AS BUFFER BYTE POINTER
	MOVEM	S1,J$LIBP(J)		;HERE ALSO
	$RETT				;AND RETURN
SUBTTL	COMMON DEVICE CONTROL - LPTDIE - STOP ON TOO MANY I/O ERRORS


LPTDIE::SOSL	J$LERR(J)		;COUNT DOWN ERRORS
	POPJ	P,			;STILL ALIVE
	MOVE	S1,STREAM		;GET STREAM NUMBER
	$WTO	 (<Too many device errors>,,@JOBOBA(S1))
	MOVEI	S1,%RSUDE		;GET DEVICE DOES NOT EXIST BIT.
	PUSHJ	P,RSETUP		;TELL QUASAR PRINTER IS OUT TO LUNCH.
	PJRST	SHUTIN			;AND SHUT IT DOWN
SUBTTL	COMMON DEVICE CONTROL -- LPTANF - CHECK ANF-10 STATION


; ROUTINE TO CHECK ANF-10 STATION
; CALL:	MOVE	S1, STATION NUMBER/NAME
;	PUSHJ	P,LPTANF

LPTANF::MOVE	T1,[.NDRNN,,T2]		;SET UP UUO AC
	MOVEI	T2,2			;TWO WORDS FOLLOWING
	MOVE	T3,S1			;ARGUMENT
	NODE.	T1,			;CHECK FOR ANF-10
	  CAMN	T1,[.NDRNN,,T2]		;MAYBE NO NETWORK SUPPORT?
	$RETT				;RETURN
	$RETF				;NOT ANF-10
SUBTTL	COMMON DEVICE CONTROL -- LPTDCN - CHECK DECNET NODE


; ROUTINE TO CHECK DECNET NODE
; CALL:	MOVE	S1, NODE NAME
;	MOVE	S2, KNOWN/REACHABLE/EXECUTOR FLAGS
;	PUSHJ	P,LPTDCN

LPTDCN::TDNN	S1,[-1,,777600]		;NODE NAME?
	$RETF				;NO
	MOVEI	T1,T2			;SET UP UUO AC
	MOVE	T2,[.DNNDI,,2]		;FUNCTION,,LENGTH
	IOR	T2,S2			;INCLUDE INTERESTING FLAGS
	MOVE	T3,S1			;ARGUMENT
	DNET.	T1,			;CHECK STATUS
	  $RETF				;NO SUCH NODE OF NODE DOWN
	$RETT				;RETURN
	$RETF				;NOT DECNET
SUBTTL	COMMON DEVICE CONTROL -- LPTRUL - PRINT A RULER


LPTRUL::$SAVE	<P1,P2,P3>		;SAVE SOME ACS
	MOVSI	P1,-3			;GET COUNTER

RULER1:	MOVE	P2,STARS(P1)		;GET ADDRESS OF TEXT STRING
	MOVE	P3,J$FWID(J)		;GET THE WIDTH
	CAILE	P3,^D132		;IS IT REASONABLE?
	MOVEI	P3,^D132		;NOW IT IS

RULER2:	ILDB	C,P2			;GET A CHARACTER
	PUSHJ	P,DEVOUT		;PUT A CHARACTER
	SOJG	P3,RULER2		;LOOP
	PUSHJ	P,CR23			;SEND LF OR DC3
	AOBJN	P1,RULER1		;LOOP FOR ALL RULER LINES
	POPJ	P,			;AND RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTLOG - PRINT LPTSPL RUN LOG


LPTLOG::SKIPN	J$GNLN(J)		;ANYTHING IN THE INTERNAL LOG?
	POPJ	P,			;NO, RETURN
	PUSHJ	P,PLPBUF		;YES, PRINT A LINE
	PUSHJ	P,PLPBUF		;AND ANOTHER LINE
	MOVEI	C,.CHTAB		;LOAD A TAB
	MOVE	T1,J$FWCL(J)		;GET THE WIDTH CLASS
	PUSHJ	P,DEVOUT		;PRINT A TAB
	SOJG	T1,.-1			;PRINT N OF THEM
	MOVEI	S1,[ASCIZ /* * * L P T S P L  R u n  L o g * * *

/]
	PUSHJ	P,STGOUT		;AND DUMP IT
	MOVE	T2,J			;COPY OVER J
	MOVE	T3,J$GINP(J)		;GET NUMBER OF PAGES

RLOG.1:	MOVE	S1,J$GBUF(T2)		;GET ADR OF BUFFER
	PUSHJ	P,STGOUT		;AND DUMP IT OUT
	MOVE	S1,J$GBUF(T2)		;GET THE PAGE ADDRESS
	CAME	T2,J			;SKIP IF THIS IS THE PRE-ALLOCATED PAGE
	PUSHJ	P,M%RPAG		;AND RELEASE IT
	SOSLE	T3			;DECREMENT COUNT
	AOJA	T2,RLOG.1		;AND LOOP IF NOT DONE
	PUSHJ	P,CRLF			;PRINT 1 CRLF
	PUSHJ	P,CRLF			;AND ANOTHER
	PUSHJ	P,CRLF			;AND ANOTHER
	MOVE	T1,J$GNLN(J)		;GET NUMBER OF LOG LINES
	ADDI	T1,5			;ADD IN THE OVERHEAD
	ADD	T1,J$XPOS(J)		;AND ACCUMULATE VERTICAL POSITION
	IDIV	T1,J$FLIN(J)		;DID WE OVERFLW A PAGE?
	MOVEM	T2,J$XPOS(J)		;SAVE CURRENT POSITION
	SETZM	J$GNLN(J)		;AND DON'T PRINT IT AGAIN
	SUB	P3,T1			;REDUCE PAGES TO PRINT
	POPJ	P,			;AND RETURN
SUBTTL	COMMON DEVICE CONTROL -- LPTTXT - GENERATE "OUTPUT TO ..." TEXT


LPTTXT::SETZM	J$LOUT(J)		;INIT NODE/DEVICE/UNIT TEXT
	MOVE	S1,STREAM		;GET STREAM NUMBER
	MOVE	S1,JOBOBA(S1)		;PICK UP OBJECT BLOCK ADDRESS.
	MOVE	S1,OBJ.ND(S1)		;GET NODE NAME/NUMBER
	MOVEI	T1,[ITEXT (<node ^N/S1/ >)]
	SKIPN	S1			;HAVE A NODE?
	MOVEI	T1,[ITEXT (<>)]		;NO
	MOVEI	T2,[ITEXT (<device ^W/T4/ >)]
	SKIPL	T4,J$LCHN(J)		;GET CHANNEL IN USE
	DEVNAM	T4,			;CONVERT TO PHYSICAL DEVICE NAME
	  MOVE	T4,J$LDEV(J)		;USE WHAT'S THERE
	SKIPN	T4			;HAVE A DEVICE NAME?
	MOVEI	T2,[ITEXT (<>)]		;NO
	MOVEI	T3,[ITEXT (<unit type ^W/J$LTYP(J)/ >)]
	SKIPN	J$LTYP(J)		;HAVE A UNIT TYPE?
	MOVEI	T3,[ITEXT (<>)]		;NO
	MOVE	S2,S1			;GET NODE NAME/NUMBER
	IOR	S2,T4			; PLUS DEVICE
	IOR	S2,J$LTYP(J)		;  PLUS UNIT TYPE
	JUMPE	S2,.RETT		;CHECK FOR NOTHING
	$TEXT	(<-1,,J$LOUT(J)>,<Output to ^I/(T1)/^I/(T2)/^I/(T3)/^0>)
	$RETT				;RETURN
SUBTTL	INIT FILE ROUTINES -- FH$ANY/FH$CHR/FH$CVT - READ A CHARACTER


; READ A CHARACTER FROM THE INITIALIZATION FILE
; CALL:	PUSHJ	P,FH$ANY/FH$CHR/FH$CVT
;
; TRUE RETURN:	C CONTAINS CHARACTER.  LOWER CASE AND TAB CONVERSIONS
;		ARE PERFORMED IF CALLED AT THE FH$CVT ENTRY POINT.
; FALSE RETURN:	EOF, IFN RELEASED.

FH$ANY::MOVNI	S1,1			;ACCEPT ANY CHARACTER
	JRST	CHR.1			;ENTER COMMON CODE
FH$CHR::TDZA	S1,S1			;NO CONVERSION
FH$CVT::MOVEI	S1,1			;CONVERT

CHR.1:	PUSH	P,S1			;SAVE FLAG
	SKIPGE	C,INISAV		;GET SAVED CHARACTER (IF ANY)
	JRST	CHR.2			;THERE ISN'T ONE
	SETOM	INISAV			;SAVED CHARACTER INVALID NOW
	JRST	CHR.3			;ENTER COMMON CODE

CHR.2:	MOVE	S1,INIIFN		;IFN
	PUSHJ	P,F%IBYT		;READ A CHARACTER
	JUMPF	CHR.5			;CHECK FOR ERRORS

CHR.3:	SKIPGE	(P)			;ACCEPT ANY CHARACTER?
	JRST	CHR.4			;YES
	MOVEI	C,(S2)			;COPY CHARACTER
	CAIN	C,.CHCRT		;CARRIAGE RETURN?
	JRST	CHR.2			;IGNORE IT
	CAIE	C,.CHFFD		;CONVERT FORM FEEDS
	CAIN	C,.CHVTB		;AND VERTICAL TABS
	MOVEI	C,.CHLFD		;INTO LINEFEED

CHR.4:	SKIPE	INILIN			;COUNTING LINES?
	CAIE	C,.CHLFD		;AND AT EOL?
	SKIPA				;NO TO EITHER
	AOS	INILIN			;COUNT THE LINE
	POP	P,S1			;GET CONVERION FLAG BACK
	JUMPLE	S1,.RETT		;RETURN IF NO CONVERSION WANTED
	CAIN	C,.CHTAB		;TAB?
	MOVEI	C," "			;MAKE IT A SPACE
	CAIL	C,"A"+400		;LOWER
	CAILE	C,"Z"+40		; CASE?
	SKIPA				;NO
	SUBI	C," "			;MAKE UPPER CASE
	$RETT				;RETURN

CHR.5:	MOVEM	S1,(P)			;SAVE ERROR CODE
	CAIN	S1,EREOF$		;EOF?
	JRST	CHR.6			;YES
	MOVEI	S1,CHRION		;ASSUME NON-LINE ORIENTED FILE
	SKIPLE	INILIN			;LINE NUMBERED?
	MOVEI	S1,CHRIOL		;YES
	MOVEI	S2,CHRRTX		;RUN LOG/REASON TEXT
	PJRST	FH$ERR			;REPORT ERROR AND RETURN TO CALLER

CHR.6:	PUSHJ	P,FH$XIT		;TERMINATE I/O
	POP	P,S1			;GET ERROR CODE BACK
	$RETF				;RETURN EOF

CHRION:	ITEXT	(<I/O error reading ^F/@INIFOB+FOB.FD/
Error: ^E/[-1]/>)

CHRIOL:	ITEXT	(<I/O error reading line ^D/INILIN/
File:  ^F/@INIFOB+FOB.FD/
Error: ^E/[-1]/>)

CHRRTX:	ITEXT	(<I/O error reading ^F/@INIFOB+FOB.FD/>)
SUBTTL	INIT FILE ROUTINES -- FH$BKP - BACKUP ONE CHARACTER


; BACKUP (REEAT) ONE CHARACTER
; CALL:	MOVE	C, CHARACTER
;	PUSHJ	P,FH$BKP
;
; TRUE RETURN:	ALWAYS
; FALSE RETURN:	NEVER

FH$BKP::MOVEM	C,INISAV		;SAVE THE CHARACTER
	$RETT				;RETURN
SUBTTL	INIT FILE ROUTINES -- FH$COM - COMMENT PROCESSING


; CHECK FOR A COMMENT AND FLUSH REMAINDER OF LINE IF NECESSARY
; CALL:	PUSHJ	P,FH$COM
;
; TRUE RETURN:	COMMENT FLUSHED (IF ANY)
; FALSE RETURN:	EOF

FH$COM::CAIE	C,.CHTAB		;TAB?
	CAIN	C," "			;SPACE?
	PUSHJ	P,FH$SKP		;SKIP THEM
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	CAIE	C,";"			;COMMENT?
	CAIN	C,"!"			;NEW-STYLE?
	PJRST	FH$EOL			;YES--FLUSH REMAINDER OF LINE
	$RETT				;ELSE JUST RETURN
SUBTTL	INIT FILE ROUTINES -- FH$CON - LINE CONTINUATION PROCESSING


; HANDLE LINE CONTINUATION
; CALL:	PUSHJ	P,FH$CON
;
; TRUE RETURN:	NOT LINE CONTINUATION OR POSITIONED FOR I/O
;		AT THE START OF THE NEXT LINE FOR INPUT
; FALSE RETURN:	EOF

FH$CON::CAIE	C,"-"			;SITTING ON A DASH?
	$RETT				;NO--CAN'T BE LINE CONTINUATION
	MOVE	S1,INIIFN		;IFN
	PUSHJ	P,F%CHKP		;CHECKPOINT POSITION
	JUMPF	CON.2			;CHECK FOR ERRORS
	PUSH	P,S1			;REMEMBER POSITION FOR LATER
	PUSH	P,INILIN		;SAVE LINE NUMBER
	PUSHJ	P,CONSKP		;SKIP TABS AND SPACES
	JUMPF	CON.1			;CAN'T BE CONTINUATION IF EOF
	CAIE	C,";"			;COMMENT?
	CAIN	C,"!"			;NEW-STYLE?
	PUSHJ	P,CONEOL		;FLUSH REMAINDER OF LINE
	$RETIF				;CHECK FOR ERRORS
	CAIE	C,.CHLFD		;EOL?
	JRST	CON.1			;NOT LINE CONTINUATION
	ADJSP	P,-2			;PHASE STACK
	PUSHJ	P,CONSKP		;SKIP SPACES AT START OF NEXT LINE
	$RETIF				;CHECK FOR ERRORS
	JRST	FH$CON			;SEE IF MULTIPLE CONTINATION LINES

CON.1:	MOVE	S1,INIIFN		;IFN
	POP	P,INILIN		;RESTORE ORIGINAL LINE NUMBER
	POP	P,S2			;GET ORIGINAL POSITION BACK
	PUSHJ	P,F%POS			;REPOSITION FOR I/O
	JUMPF	CON.3			;CHECK FOR ERRORS
	MOVEI	C,"-"			;GET BACK ORIGINAL CHARACTER
	$RETT				;AND RETURN

CON.2:	SKIPA	S2,[CONCPE]		;CHECKPOINT ERROR
CON.3:	MOVEI	S2,CONPSE		;POSITIONING ERROR
	PUSH	P,S1			;SAVE ERROR CODE
	MOVE	S1,S2			;GET MESSAGE TEXT ADDRESS
	MOVEI	S2,CONRTX		;RUN LOG/REASON TEXT
	PJRST	FH$ERR			;REPORT ERROR AND RETURN TO CALLER
CONEOL:	PUSHJ	P,FH$CHR		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	CAIE	C,.CHLFD		;EOL?
	JRST	FH$EOL			;TRY AGAIN
	$RETT				;RETURN


CONSKP:	PUSHJ	P,FH$CVT		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	CAIN	C," "			;SPACE?
	JRST	FH$SKP			;KEEP SEARCHING
	$RETT				;RETURN


CONCPE:	ITEXT	(<Checkpoint failed
File:  ^F/@INIFOB+FOB.FD/
Error: ^E/[-1]/>)

CONPSE:	ITEXT	(<Positioning failed
File:  ^F/@INIFOB+FOB.FD/
Error: ^E/[-1]/>)

CONRTX:	ITEXT	(<Checkpoint/positioning error on ^F/@INIFOB+FOB.FD/>)
SUBTTL	INIT FILE ROUTINES -- FH$EOL - READ UNTIL EOL


; READ UNTIL END OF LINE ENCOUNTERED
; CALL:	PUSHJ	P,FH$EOL
;
; TRUE RETURN:	EOL FOUND
; FALSE RETURN:	EOF

FH$EOL::PUSHJ	P,FH$CHR		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	CAIN	C,"-"			;POSSIBLE LINE CONTINUATION?
	PUSHJ	P,FH$CON		;YES
	$RETIF				;CHECK FOR ERRORS
	CAIE	C,.CHLFD		;EOL?
	JRST	FH$EOL			;TRY AGAIN
	$RETT				;RETURN
SUBTTL	INIT FILE ROUTINES -- FH$ERR - ERROR REPORTING


; REPORT INIT FILE ERROR AND DO ALL APPROPRIATE ERROR LOGGING
; CALL:	PUSH	P,  ERROR CODE TO RETURN TO CALLER (FH$ERR ONLY)
;	MOVE	S1, ADDRESS OF ITEXT BLOCK FOR WTO MESSAGE
;	MOVE	S2, ADDRESS OF ITEXT BLOCK FOR RUN LOG AND REASON TEXT
;	PUSHJ	P,FH$ERR/FH$RPT
;
; TRUE RETURN:	NEVER
; FALSE RETURN:	ONLY IF CALLED AT FH$RPT ENTRY POINT.  S1 WILL CONTAIN
;		THE ERROR CODE PASSED AND THE STACK WILL BE PHASED
;		CORRECTLY FOR FUTURE POPJS.

FH$ERR::TDZA	TF,TF			;REPORT ERROR AND UNWIND
FH$RPT::MOVNI	TF,1			;REPORT ERROR ONLY
	MOVEM	S1,INITMP		;SAVE S1
	MOVE	S1,STREAM		;GET STREAM NUMBER
	ADDI	S1,JOBOBA		;OFFSET TO OBJECT BLOCK
	EXCH	S1,INITMP		;SAVE ADDRESS AND RESTORE S1
	HLLM	TF,INITMP		;SAVE FLAG
	$WTO	(<Initialization file error>,<^I/(S1)/>,@INITMP)
	$TEXT	(LOGCHR,<^I/LPERR/^I/(S2)/>) ;MAKE RUN LOG ENTRY
	$TEXT	(<-1,,J$WTOR(J)>,<^I/(S2)/^0>) ;SET REASON TEXT FOR NOTIFY
	PUSHJ	P,FH$XIT		;TERMINATE I/O
	SKIPGE	INITMP			;CALLER WANT CONTROL?
	$RETF				;YES--RETURN
	POP	P,S1			;GET ERROR CODE BACK
	MOVE	P,INIPDP		;GET SAVED PDL POINTER
	PUSH	P,INIEPC		;SET RETURN PC
	$RETF				;RETURN TO CALLER
SUBTTL	INIT FILE ROUTINES -- FH$INI - INITIALIZE I/O


; INITIALIZE I/O
; CALL:	MOVE	S1, FD ADDRESS
;	MOVE	S2, ADDRESS OF DATE/TIME WORD FOR COMPARRISON
;	PUSHJ	P,FH$INI
;
; TRUE RETURN:	S1 CONTAINS A POSITIVE GALAXY IFN IF THE FILE NEEDS
;		TO BE RE-READ.  REGARDLESS OF THE CONTENTS OF S1, S2
;		WILL CONTAIN THE ADDRESS OF AN UPDATED FD BLOCK FOR THE
;		FILE JUST OPENED.  ALSO, A COPY OF THE PDL POINTER
;		IS SAVED FOR FATAL I/O ERROR RECOVERY.  WHEN AN I/O
;		ERROR IS DETECTED, ALL THE APPROPRIATE ERROR LOGGING
;		WILL HAPPEN, THE IFN WILL BE RELEASED, AND CONTROL
;		RETURNED TO THE FH$INI CALL +1.  THIS SHOULD BE SOME
;		SORT OF GALAXY ERROR CHECKING INSTRUCTION (JUMPF, SKIPF,
;		ETC.).  AT THIS TIME, S1 WILL CONTAIN THE SPECIFIC GALAXY
;		ERROR CODE.
; FALSE RETURN:	ERROR REPORTED TO OPERATOR, IFN RELEASED.

FH$INI::MOVE	TF,P			;COPY PDL POINTER
	POP	TF,INIEPC		;SAVE RETURN PC FOR ERROR RECOVERY
	MOVEM	TF,INIPDP		;SAVE PDL POINTER FOR SAME
	PUSH	P,S2			;SAVE DATE/TIME WORD ADDRESS
	PUSH	P,S1			;SAVE FD ADDRESS
	MOVE	S1,[PFOB,,INIFOB]	;SET UP BLT	
	BLT	S1,INIFOB+FOB.SZ-1	;COPY PROTOTYPE BLOCK
	POP	P,S1			;GET FD ADDRESS BACK
	HRLZS	S1			;PUT IN LH
	HRRI	S1,INIFD		;MAKE A BLT POINTER
	BLT	S1,INIFD+FDXSIZ-1	;COPY PROTOTYPE FILE DESCRIPTOR
	SETOM	INIIFN			;INDICATE FILE NOT OPENED YET
	SETOM	INISAV			;SAVED CHARACTER IS INVALID
	SETZM	INILIN			;THEREFORE NO LINE NUMBER EITHER
	MOVEI	S1,FOB.SZ		;FOB LENGTH
	MOVEI	S2,INIFOB		;FOB ADDRESS
	PUSHJ	P,F%IOPN		;OPEN FILE FOR INPUT
	JUMPF	INI.2			;CHECK FOR ERRORS
	MOVEM	S1,INIIFN		;SAVE IFN
	MOVNI	S2,1			;-1 FOR ACTUAL FILESPEC
	PUSHJ	P,F%FD			;GET FILESPEC
	JUMPF	INI.2			;CHECK FOR ERRORS
	LOAD	S2,.FDLEN(S1),FD.LEN	;GET RETURNED FD LENGTH
	HRLZS	S1			;POINT FD IN LH
	HRRI	S1,INIFD		;AND TO OUR STORAGE
	ADDI	S2,INIFD		;COMPUTE END OF BLT
	BLT	S1,-1(S2)		;COPY RETURNED FD
	MOVE	S1,INIIFN		;IFN FOR INPUT
	MOVEI	S2,FI.CRE		;FUNCTION CODE
	PUSHJ	P,F%INFO		;READ FILE CREATION DATE/TIME
	JUMPF	INI.2			;CHECK FOR ERRORS
	MOVE	S2,S1			;GET CREATION DATE/TIME
	EXCH	S2,(P)			;SWAP WITH STORAGE ADDRESS
	XOR	S1,(S2)			;COMPARE NEW DATE/TIME WITH OLD
	CAIN	S2,0			;WAS AN ADDRESS REALLY SUPPLIED?
	MOVEI	S2,S1			;INSURE S1 IS NON-ZERO TO FORCE RE-READ
	POP	P,(S2)			;UPDATE DATE/TIME FOR CALLER
	JUMPN	S1,INI.1		;JUMP IF FILE HAS CHANGED
	PUSHJ	P,FH$XIT		;TERMINATE I/O
	SETZ	S1,			;INDICATE FILE HAS NOT CHANGED
	MOVEI	S1,INIFD		;POINT TO FILESPEC
	$RETT				;RETURN

INI.1:	AOS	INILIN			;LINE
	MOVE	S1,INIIFN		;CALLER MIGHT WANT THE IFN
	MOVEI	S2,INIFD		;AND MAYBE THE REAL FILESPEC TOO
	$RETT				;RETURN

INI.2:	SKIPA	S2,[INI.4]		;OPEN ERROR
INI.3:	MOVEI	S2,INI.5		;CAN'T READ PARAMETERS
	MOVEM	S1,(P)			;SAVE ERROR CODE
	MOVE	S1,S2			;GET MESSAGE TEXT ADDRESS
	MOVEI	S2,INI.6		;RUN LOG/REASON TEXT
	PJRST	FH$ERR			;REPORT ERROR AND RETURN TO CALLER

INI.4:	ITEXT	(<Open failed for ^F/@INIFOB+FOB.FD/
Error: ^E/[-1]/>)

INI.5:	ITEXT	(<Cannot read file parameters
File:  ^F/@INIFOB+FOB.FD/
Error: ^E/[-1]/>)

INI.6:	ITEXT	(<Initialization failed for ^F/@INIFOB+FOB.FD/>)


; PROTOTYPE FILE OPEN BLOCK
PFOB:	$BUILD	(FOB.SZ)		;BLOCK LENGTH
	  $SET	(FOB.FD,FWMASK,INIFD)	  ;FD POINTER
	  $SET	(FOB.CW,FB.PHY,1)	  ;PHYSICAL OPEN
	  $SET	(FOB.CW,FB.LSN,1)	  ;STRIP OFF LINE SEQUENCE NUMBERS
	  $SET	(FOB.CW,FB.BSZ,7)	  ;7-BIT BYTES
	$EOB				;END OF BLOCK
SUBTTL	INIT FILE ROUTINES -- FH$KEY - READ A POSSIBLY QUOTED STRING


; READ A KEYWORD INTO THE ATOM BUFFER AND COMPARE AGAINST A TABLE OF KEYWORDS
; CALL:	MOVE	S1, KEYWORD TABLE ADDRESS OR ZERO
;	PUSHJ	P,FH$KEY
;
; TRUE RETURN:	S1 CONTAINS ADDRESS OF KEYWORD, S2 CONTAINS DATA FROM
;		KEYWORD TABLE, AND C CONTAINS TERMINATING CHARACTER
; FALSE RETURN:	S1 CONTAINS -1 IF NO INPUT OR ILLEGAL KEYWORD, OR EOF
;		S2 IS INDETERMINATE
;
; *** NOTE *** KEYWORD TEXT MAY NOT BEGIN OR END WITH A DASH

FH$KEY::PUSHJ	P,.SAVE3		;SAVE SOME ACS
	MOVE	P3,S1			;SAVE KEYWORD TABLE ADDRESS
	MOVE	S1,[INIATM,,INIATM+1]	;SET UP BLT
	SETZM	INIATM			;CLEAR FIRST WORD
	BLT	S1,INIATM+INIWDS-1	;CLEAR ATOM BUFFER
	MOVE	P1,[POINT 7,INIATM]	;BYTE POINTER TO STORAGE
	MOVEI	P2,0			;CLEAR COUNT

KEY.1:	PUSHJ	P,FH$CVT		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	CAIN	C,"-"			;DASH IN MIDDLE OF KEYWORD?
	JRST	KEY.3			;YES--WASN'T LINE CONTINUATION

KEY.2:	CAIL	C,"0"			;NUMERIC
	CAILE	C,"9"			; CHARACTER?
	CAIL	C,"A"			;UPPER
	CAILE	C,"Z"			; CASE?
	CAIL	C,"A"+40		;LOWER
	CAILE	C,"Z"+40		; CASE?
	JRST	KEY.4			;NO GOOD

KEY.3:	CAIGE	P2,INISIZ		;BUFFER OVERFLOW?
	IDPB	C,P1			;STORE CHARACTER
	AOJA	P2,KEY.1		;LOOP BACK

KEY.4:	SKIPN	S1,P2			;GET CHARACTER COUNT
	SOJA	S1,.RETF		;RETURN IF NO INPUT
	SKIPE	S1,P3			;GET TABLE ADDRESS
	JRST	KEY.5			;GOT ONE
	MOVEI	S1,INIATM		;ELSE JUST POINT TO PARSED TEXT
	$RETT				;AND RETURN

KEY.5:	HRROI	S2,INIATM		;POINT TO ATOM BUFFER
	PUSHJ	P,S%TBLK		;SCAN THE TABLE FOR A MATCH
	MOVE	TF,S2			;COPY RESULTING FLAGS
	MOVE	S2,S1			;COPY TABLE ADDRESS (IF ANY)
	MOVEI	S1,INIATM		;POINT CALLER AT KEYWORD TEXT
	TXNN	TF,TL%EXM		;MUST HAVE AN EXACT MATCH
	$RETF				;OR IT'S NO GOOD
	HRRZ	S2,(S2)			;GET DATA ASSOCIATED WITH KEYWORD
	$RETT				;RETURN
SUBTTL	INIT FILE ROUTINES -- FH$NUM/FH$DEC/FH$OCT - READ NUMBERS


; READ A NUMBER
; CALL:	MOVE	S1, RADIX
;	PUSHJ	P,FH$NUM
;
; TRUE RETURN:	S1 CONTAINS NUMBER, C CONTAINS TERMINATING CHARACTER
; FALSE RETURN:	EOF

FH$OCT::SKIPA	S1,[EXP 10]		;RADIX 8
FH$DEC::MOVEI	S1,12			;RADIX 10
FH$NUM::PUSHJ	P,.SAVE4		;SAVE SOME ACS
	MOVEI	P1,(S1)			;SAVE RADIX
	SETZB	P2,P3			;CLEAR RESULT, CHARACTER COUNT
	MOVNI	P4,1			;ASSUME NEGATIVE
	PUSHJ	P,FH$CVT		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINATION?
	$RETIF				;CHECK FOR ERRORS
	CAIE	C,"-"			;NEGATIVE?
	TDZA	P4,P4			;NO

NUM.1:	PUSHJ	P,FH$CVT		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	CAIL	C,"0"			;RANGE
	CAILE	C,"0"(P1)		; CHECK
	JRST	NUM.2			;NO GOOD
	IMULI	P2,(P1)			;SHIFT RESULT
	ADDI	P2,-"0"(C)		;ADD DIGIT
	AOJA	P3,NUM.1		;LOOP BACK

NUM.2:	CAIE	P1,12			;RADIX 10?
	JRST	NUM.3			;NO
	CAIN	C,"."			;TRAILING DECIMAL POINT?
	PUSHJ	P,FH$CVT		;YES--READ NEXT CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
NUM.3:	CAIE	P1,10			;OCTAL?
	CAIN	P1,12			;DECIMAL?
	TDZA	S1,S1			;INIT MULTIPLIER SEARCH
	$RETT				;ELSE JUST RETURN NOW
	MOVE	TF,MULPTR		;GET BYTE POINTER TO MULTIPLIERS

NUM.4:	ILDB	S2,TF			;GET A CHARACTER
	JUMPE	S2,NUM.5		;DONE?
	CAIE	S2,(C)			;MATCH?
	AOJA	S1,NUM.4		;NO
	MOVEI	S2,MUL8			;ASSUME OCTAL
	CAIN	P1,12			;DECIMAL?
	MOVEI	S2,MUL10		;YES
	ADDI	S2,(S1)			;INDEX
	IMUL	P2,(S2)			;SHIFT RESULT
	PUSHJ	P,FH$CVT		;GET NEXT CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS

NUM.5:	SKIPGE	P4			;NEGATIVE QUANTITY?
	MOVNS	P2			;YES
	MOVE	S1,P2			;GET RESULT
	$RETT				;AND RETURN


MULSUF:	ASCIZ	/KMG/			;MULTIPLIER SUFFIX CHARACTERS
MULPTR:	POINT	7,MULSUF		;BYTE POINTER TO SUFFIX CHARACTERS
MUL8:	OCT	1K,	1M,	1G	;OCTAL MULTIPLIERS
MUL10:	DEC	1K,	1M,	1G	;DECIMAL MULTIPLIERS
SUBTTL	INIT FILE ROUTINES -- FH$QST - READ A POSSIBLY QUOTED STRING


; READ A POSSIBLY QUOTED STRING INTO THE ATOM BUFFER
; CALL:	PUSHJ	P,FH$QST
;
; TRUE RETURN:	S1 CONTAINS ADDRESS OF STRING, S2 CONTAINS THE LENGTH IN WORDS
;		C CONTAINS TERMINATING CHARACTER
; FALSE RETURN:	S1 CONTAINS -1 IF NO INPUT OR EOF, S2 IS INDETERMINATE

FH$QST::PUSHJ	P,.SAVE3		;SAVE SOME ACS
	MOVE	S1,[INIATM,,INIATM+1]	;SET UP BLT
	SETZM	INIATM			;CLEAR FIRST WORD
	BLT	S1,INIATM+INIWDS-1	;CLEAR ATOM BUFFER
	MOVE	P1,[POINT 7,INIATM]	;BYTE POINTER TO STORAGE
	SETZB	P2,P3			;CLEAR COUNT, QUOTE FLAG
	PUSHJ	P,FH$CHR		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	CAIE	C,"'"			;SINGLE QUOTES?
	CAIN	C,""""			;DOUBLE QUOTES?
	SKIPA	P3,C			;YES--REMEMBER FOR LATER
	JRST	QST.2			;ENTER LOOP

QST.1:	PUSHJ	P,FH$CHR		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS

QST.2:	JUMPE	P3,QST.3		;QUOTED STRING?
	CAIE	C,(P3)			;CLOSING QUOTE?
	JRST	QST.4			;NO--GO STORE
	PUSHJ	P,FH$CHR		;READ NEXT CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	JRST	QST.5			;GO RETURN TO CALLER

QST.3:	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	CAIN	C,"-"			;DASH?
	JRST	QST.4			;GO STORE
	CAIL	C,"0"			;NUMERIC
	CAILE	C,"9"			; CHARACTER?
	CAIL	C,"A"			;UPPER
	CAILE	C,"Z"			; CASE?
	CAIL	C,"A"+40		;LOWER
	CAILE	C,"Z"+40		; CASE?
	JRST	QST.5			;NO GOOD

QST.4:	CAIGE	P2,INISIZ		;BUFFER OVERFLOW?
	IDPB	C,P1			;STORE CHARACTER
	AOJA	P2,QST.1		;LOOP BACK

QST.5:	MOVE	S1,P2			;GET CHARACTER COUNT
	ADDI	S1,5			;ROUND UP
	IDIVI	S1,5			;COMPUTE WORDS
	MOVEI	S2,(S1)			;GET COUNT
	MOVEI	S1,INIATM		;GET BUFFER ADDRESS
	$RETT				;ELSE RETURN GOODNESS
SUBTTL	INIT FILE ROUTINES -- FH$SIX - READ A SIXBIT WORD


; READ A SIXBIT QUANTITY
; CALL:	PUSHJ	P,FH$SIX
;
; TRUE RETURN:	S1 CONTAINS RESULT AND C CONTAINS TERMINATING CHARACTER
; FALSE RETURN:	EOF

FH$SIX::PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	MOVE	P1,[POINT 6,P2]		;BYTE POINTER TO RESULT
	SETZ	P2,			;INIT RESULT

SIX.1:	PUSHJ	P,FH$CVT		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	CAIL	C,"0"			;RANGE
	CAILE	C,"9"			; CHECK
	CAIL	C,"A"			;  THE
	CAILE	C,"Z"			;   CHARACTER
	JRST	SIX.3			;NO GOOD--FINISH UP

SIX.2:	TRNE	P2,77			;OVERFLOW?
	JRST	SIX.1			;YES--IGNORE THE REST
	SUBI	C," "			;CONVERT ASCII TO SIXBIT
	IDPB	C,P1			;STORE CHARACTER
	JRST	SIX.1			;LOOP FOR MORE

SIX.3:	MOVE	S1,P2			;GET RESULT
	$RETT				;ELSE RETURN GOODNESS
SUBTTL	INIT FILE ROUTINES -- FH$SKP - SKIP TABS AND SPACES


; SKIP TABS AND SPACES
; CALL:	PUSHJ	P,FH$SKP
;
; TRUE RETURN:	C CONTAINS THE FIRST NON-TAB/SPACE CHARACTER
; FALSE RETURN:	EOF

FH$SKP::PUSHJ	P,FH$CVT		;READ A CHARACTER
	$RETIF				;CHECK FOR ERRORS
	PUSHJ	P,FH$CON		;LINE CONTINUATION?
	$RETIF				;CHECK FOR ERRORS
	CAIN	C," "			;SPACE?
	JRST	FH$SKP			;KEEP SEARCHING
	$RETT				;RETURN
SUBTTL	INIT FILE ROUTINES -- FH$XIT - EXIT FILE PROCESSING


; THIS ROUTINE IS CALLED TO PREMATURELY (BEFORE EOF) TERMINATE
; FILE PROCESSING.
; CALL:	PUSHJ	P,FH$XIT
;
; TRUE RETURN:	ALWAYS
; FALSE RETURN:	NEVER

FH$XIT::SKIPLE	S1,INIIFN		;GET IFN
	PUSHJ	P,F%RREL		;RELEASE IT
	$RETT				;RETURN
SUBTTL	OUTGET Exit Subroutines


OUTDDE:	MOVX	S1,%RSUDE		;NEVER AVAILABLE
	$RETF				;RETURN
SUBTTL	OUTWON  --  Wait for on-line

;On the -10, this routine should only be gotten to by DEBRKing to it
;	on a device off-line interrupt.  On the -20, it can be called
;	from anywhere.
;	NOTE: The ONLINE/OFFLINE (PSF%DO) status bits are set and cleared
;	      at interrupt level. This pervents a race condition from
;	      occuring where the device comes online while we are still
;	      processing the device offline interrupt. In this case
;	      it was possible for LPTSPL to miss the on-line
;	      change-of-state, and sleep forever waiting for the
;	      online interrupt.


TOPS10 <
OUTWON:	PUSH	P,S1			;SAVE S1
	PUSH	P,S2			;SAVE S2
;**;[3007] Change code at OUTWON+2L
	PUSH	P,P1			;[3007] SAVE P1 TOO
	MOVSI	P1,-NPRINT		;[3007] MAKE AOBJN POINTER
OUTW.1:	MOVE	S1,JOBSTW(P1)		;[3007] GET STREAM STATUS
	TXNE	S1,PSF%DO		;[3007] PRINTER OFFLINE?
	$WTO  (<^T/BELL/>,,@JOBOBA(P1))	;[3007] YES, TELL THE OPERATOR.
	AOBJN	P1,OUTW.1		;[3007] CHECK ALL PRINTERS
	POP	P,P1			;[3007] RESTORE P1
	POP	P,S2			;[3007] RESTORE S2
	POP	P,S1			;[3007] RESTORE S1
	$DSCHD(0)			;[3007] BLOCK THE PROCESS
	JRST	@J$LIOA(J)		;AND CONTINUE ON
>  ;END TOPS10 CONDITIONAL

TOPS20 <
OUTWON:	MOVX	S2,PSF%DO		;DEVICE OFFLINE FLAG
	MOVE	S1,STREAM		;AND THE STREAM NUMBER
	TDNN	S2,JOBSTW(S1)		;IS IT OFF-LINE?
	POPJ	P,			;NO, JUST RETURN
	$WTO	(<^T/BELL/>,,@JOBOBA(S1))	;TELL THE OPERATOR.
	$DSCHD(0)			;BLOCK FOR DEVICE ONLINE
	POPJ	P,			;NO, RETURN
>  ;END TOPS20 CONDITIONAL

BELL:	BYTE(7) 07,07,117,146,146
	ASCIZ/line/
SUBTTL	OUTDMP  --  Dump out buffers and wait


OUTDMP::
REPEAT BUFNUM+1,<
	PUSHJ	P,@J$OUTP(J)		;DUMP THE BUFFER
>  ;END REPEAT BUFNUM
	POPJ	P,			;AND RETURN
SUBTTL LPT CONTROL ROUTINES


;CONTROL CHARACTER TABLE
	NCLRFF==1B0		;DON'T CLEAR FORMFEED FLAG
	SUPRCH==1B1		;SUPPRESSABLE CHARACTER
	EOLCHR==1B2		;CHARACTER IS AN EOL (IN REPORT FILES)

CHTAB:	EXP	<NCLRFF+.POPJ>		   ;(00) NULL
	EXP	CHKARO			   ;(01) CONTROL-A
	EXP	CHKARO			   ;(02) CONTROL-B
	EXP	CHKARO			   ;(03) CONTROL-C
	EXP	CHKARO			   ;(04) CONTROL-D
	EXP	CHKARO			   ;(05) CONTROL-E
	EXP	CHKARO			   ;(06) CONTROL-F
	EXP	CHKARO			   ;(07) CONTROL-G
	EXP	CHKARO			   ;(10) CONTROL-H
	EXP	NCLRFF+DEVOUT		   ;(11) THIS IS A TAB
	EXP	SUPRCH+EOLCHR+DOLF	   ;(12) THIS IS A LINE FEED
	EXP	SUPRCH+EOLCHR+<3>B17+DOFRAC ;(13) THIS SKIPS 1/3 PAGE (VERT TAB)
	EXP	SUPRCH+NCLRFF+EOLCHR+DOFORM   ;(14) THIS IS A FORM-FEED
	EXP	NCLRFF+EOLCHR+DEVOUT	   ;(15) CARRIAGE RETURN
	EXP	CHKARO			   ;(16) CONTROL-N
	EXP	CHKARO			   ;(17) CONTROL-O
	EXP	SUPRCH+EOLCHR+<2>B17+DOFRAC ;(20) THIS SKIPS 1/2 PAGE
	EXP	SUPRCH+EOLCHR+DODC1	   ;(21) THIS SKIPS 2 LINES (DC1)
	EXP	SUPRCH+EOLCHR+DODC2	   ;(22) THIS SKIPS 3 LINES (DC2)
	EXP	SUPRCH+EOLCHR+DODC3	   ;(23) DC3 SKIPS 1 LINE
	EXP	SUPRCH+EOLCHR+<6>B17+DOFRAC ;(24) THIS SKIPS 1/6 OF A PAGE (DC4)
	EXP	CHKARO			   ;(25) CONTROL-U
	EXP	CHKARO			   ;(26) CONTROL-OL-V
	EXP	CHKARO			   ;(27) CONTROL-W
	EXP	CHKARO			   ;(30) CONTROL-X
	EXP	CHKARO			   ;(31) CONTROL-Y
	EXP	CHKARO			   ;(32) CONTROL-Z
	EXP	CHKARO			   ;(33) ESCAPE
	EXP	CHKARO			   ;(34) CONTROL-\
	EXP	CHKARO			   ;(35) CONTROL-]
	EXP	CHKARO			   ;(36) CONTROL-^
	EXP	CHKARO			   ;(37) CONTROL-
;FORTRAN CONTROL CHARACTOR TRANSLATION TABLE

DEFINE FORCHR(CHR,TRANS,N),<
	EXP	<CHR>B17+<N>B26+TRANS
>  ;END DEFINE FORCHR

FORTAB:	FORCHR	" ",.CHLFD,1
	FORCHR	"0",.CHLFD,2
	FORCHR	"1",.CHFFD,1
	FORCHR	"2",20,1
	FORCHR	"3",13,1
	FORCHR	"/",24,1
	FORCHR	"*",23,1
	FORCHR	"+",.CHCRT,1
	FORCHR	54,21,1
	FORCHR	"-",.CHLFD,3
	FORCHR	".",22,1
		NFORCH==.-FORTAB
SUBTTL FILOUT -- SUBROUTINE TO SET UP FOR LPTIN AND LPTOUT

;	CALL WITH:
;		PUSHJ	P,FILOUT
;		RETURN HERE
;

FILOUT:	MOVE	T1,J$FLIN(J)		;START AT TOP OF PAGE
	MOVEM	T1,J$XPOS(J)		;SAVE IT
	PUSHJ	P,SETPFT		;SETUP FILE TYPE
	MOVEM	T1,J$FTYP(J)		;STORE IT
	PUSHJ	P,FILCHR		;AND GO PROCESS THE FILE
	TXNN	S,RQB			;HAVE WE BEEN REQUEUED ???
	SKIPE	J$XTOP(J)		;OR ARE WE AT TOP-OF-FORM?
	POPJ	P,			;YES TO EITHER,,JUST RETURN
	AOS	J$APRT(J)		;NO, CHARGE HIM FOR THE REST
	AOS	J$RNPP(J)		;HERE ALSO
	POPJ	P,			;AND RETURN

SUBTTL	FILCHR -- INTERPRET ALL CHARACTERS IN A FILE

;	This routine will parse the file character by character until
;calling the appropriate routines depending on wether the character is
;a special break character that is device dependent, and will call the
;file type dependent routine.

FILCHR:	SKIPN	J$FASC(J)		;ASCII FILE?
	 JRST	@J$FTYP(J)		;Yes, special handling
FILCH1:	PUSHJ	P,INPBYT		;GET A BYTE FROM THE FILE
	 JUMPF	.RETT			;ALL DONE
FILCH2:	SKIPL	J$FASC(J)		;Allowing special interpretations?
	 SKIPN	T3,J$DBRK(J)		;YES, GET THE ADDRESS OF THE BREAK MASK
	  JRST	FILCH3			;No, just process as normal
	MOVEI	T1,(C)			;COPY IT
	IDIVI	T1,^D32			;CALCULATE WETHER IT IS A BREAK CHAR
	ADDI	T3,(T1)			;AND ADD THE WORD OFFSET TO IT
	MOVEI	T1,1			;GET A BIT
	MOVNS	T2			;MAKE CHARACTER NEGATIVE
	LSH	T1,^D35(T2)		;SHIFT IT OVER BY THE MOD(CHR,32) VALUE
	TDNN	T1,(T3)			;IS THIS CHARACTER A BREAK?
	 JRST	FILCH3			;NO CONTINUE TO PROCESS THIS FILE
	PUSHJ	P,@J$BKPR(J)		;ELSE CALL THE HANDLER
	 JUMPF	.RETT			;ERROR RETURNS NOW (Fatal errors given)
	JRST	FILCH1			;LOOP FOR THE WHOLE FILE
FILCH3:	PUSHJ	P,@J$FTYP(J)		;CALL THE FILE CHARACTER PROCESSOR
	JRST	FILCH1			;AND LOOP FOR THE WHOLE FILE
SUBTTL	SETLST -- SUBROUTINE TO COMPILE CODE TO TEST EACH LINE FOR A MATCH AGAINST

;	 THE /REPORT VALUE.
;	CALL WITH:
;		PUSHJ	P,SETLST
;		RETURN HERE
;



SETLST:	SETZM	J$XCOD(J)		;CLEAR EXISTING REPORT CODE
	MOVEI	T2,J$XCOD-1(J)		;SET UP PDP TO COMPILED CODE
	SKIPN	.FPFR1(E)		;WAS /REPORT SPECIFIED?
	$RETT				;NO, JUST RETURN
STLST1:	MOVE	T3,[POINT 6,.FPFR1(E)] 	;POINTER TO LIST
	MOVEI	T4,^D12			;ABSOLUTE LIMIT
STLST2:	ILDB	T1,T3			;GET A CHAR
	JUMPE	T1,STLSC		;JUMP IF DONE
	ADDI	T1,"A"-'A'		;CONVERT TO ASCII
	CAIN	T4,^D12			;1ST TIME THRU, WE'VE GOT A CHARACTER
	JRST	STLST4			;YES--CHAR ALRADY IN C
	PUSH	T2,SETLSA		;COMPILE A PUSHJ
	PUSH	T2,SETLSB		;WE HAVE AN ERROR RETURN THEN
STLST4:	HLL	T1,SETLSC		;PLACE CHAR IN CAIE
	PUSH	T2,T1			;COMPILE THE CAIE
	PUSH	T2,SETLSD		;COMPILE THE JRST TO FLUSH7
	SOJG	T4,STLST2		;LOOP FOR WHOLE STRING
STLSC:	PUSH	T2,[POPJ P,]		;AND PROCESS THE CHARACTER
	POPJ	P,			;RETURN


;THE INSTRUCTIONS WHICH ARE GENERATED:
SETLSA:	PUSHJ	P,INPBYT
SETLSB:	JUMPF	.RETT
SETLSC:	CAIE	C,0
SETLSD:	JRST	FLUSH7


SUBTTL	SETPFT  --  Setup file processing type

;CALLED TO DETERMINE WHICH TYPE OF PROCESSING SHOULD BE DONE ON THE
;	INPUT FILE.
;
;RETURNS WITH T1 CONTAINING  ADDRESS OF PROCESSING ROUTINE AS FOLLOWS:
;
;	LPTOCT	<-->	/PRINT:OCTAL
;	LPTCOB	<-->	/FILE:COBOL
;	LPTFOR	<-->	/FILE:FORTRAN /PRINT:(ARROW,ASCII,SUPPRESS)
;	LPTRPT	<-->	/FILE:ASCII /REPORT:XXX /PRINT:(ARROW,ASCII,SUP)
;	LPTASC	<-->	/FILE:ASCII /PRINT:(ARROW,ASCII,SUPPRESS)
;	LPTELV	<-->	/FILE:ELEVEN

;THE DETERMINATION IS DONE IN THE ABOVE ORDER


SETPFT:	LOAD	S1,.FPINF(E),FP.FFF	;GET /FILE
	JUMPN	S1,SETPFB		;USER SPECIFIED, IGNORE RIB ATTRIBUTES
	MOVE	S1,J$DIFN(J)		;GET THE IFN OF THE OUTPUT FILE
	MOVEI	S2,FI.DCC		;WE WANT THE DATA CARRIAGE CONTROL CODE
	$CALL	F%INFO			;TRY TO GET IT
	JUMPF	SETPFC			;RIB BITS NOT VALID,,EVALUATE EXTENSION
	CAXN	S1,.RBCFO		;FORTRAN CARRIAGE CONTROL?
	 JRST	SETFFO			;YES, GO SET FILE FORTRAN
SETPFC:	MOVE	S1,J$XFOB+FOB.FD(J)	;GET ADDRESS OF OUTPUT FILE DESCRIPTOR
	HLRZ	S1,.FDEXT(S1)		;GET THE EXTENSION OF THE FILE
	CAIN	S1,'DAT'		;DATA FILE?
	 JRST	SETFFO			;YES, GO SET FORTRAN
	MOVE	S1,J$DIFN(J)		;GET BACK THE FILE IFN
	MOVX	S2,FI.MCY		;SEE IF IT IS A MACY11 FILE
	$CALL	F%INFO			;GET THE INFO
	JUMPE	S1,SETPFA		;NOT, GO EVALUATE SWITCHES
	MOVX	S1,.FPF11		;GET MACY11 VALUE
	JRST	SETPFB			;AND GO TO COMMON CODE

SETFFO:	SKIPA	S1,[EXP .FPFFO]		;MAKE LIKE /FILE:FORTRA
	JRST	SETPFB			;AND ACT LIKE THE USER TYPED IT
SETPFA:	LOAD	S1,.FPINF(E),FP.FFF	;GET /FILE
SETPFB:	LOAD	S2,.FPINF(E),FP.FPF	;GET /PRINT
	TXZ	S,ARROW			;CLEAR SOME INITIAL FLAGS
	TXO	S,NEWLIN!FCONV		;AND SET SOME OTHERS

	SETZM	J$FASC(J)		;ASSUME NON-ASCII FILE
	MOVEI	T1,LPTOCT		;ASSUME /PRINT:OCTAL
	CAIN	S2,%FPLOC		;IS IT?
	POPJ	P,			;YES, RETURN

	MOVEI	T1,LPTCOB		;NO, ASSUME /FILE:COBOL
	CAIN	S1,.FPFCO		;IS IT?
	POPJ	P,			;YES, RETURN

	CAIN	S2,%FPLAR		;/PRINT:ARROW?
	TXO	S,ARROW			;YES, LIGHT A FLAG
	CAIN	S2,%FPLSU		;/PRINT:SUPPRESS?
	TXO	S,SUPFIL!ARROW		;YES, LIGHT A BIT, (for arrow mode too)

	MOVEI	T1,LPTFOR		;ASSUME /FILE:FORTRAN
	CAIN	S1,.FPFFO		;IS IT?
	JRST	SETASC			;ALLOW ASCII PROCESSING FOR FONT FILES

	MOVEI	T1,LPTELV		;ASSUME /FILE:ELEVEN
	CAIN	S1,.FPF11		;IS IT?
	POPJ	P,			;YES, RETURN

	MOVEI	T1,LPTRPT		;USE REPORT ROUTINE
	SKIPE	.FPFR1(E)		;UNLESS /REPORT WAS NOT SPECIFIED
	POPJ	P,
	MOVEI	T1,LPTASC		;ASSUME STANDARD ASCII
SETASC:	SETOM	J$FASC(J)		;Flag ascii file type
	CAIN	S2,%FPGRF		;ALLOW GRAPHICS SUPPORT?
	 MOVNS	J$FASC(J)		; YES, ALLOW FONT SPECS
	POPJ	P,			;AND RETURN
SUBTTL	LPTASC  --  Print Regular ASCII on LPT

LPTASC:	CAIGE	C,40			;PRINTABLE ASCII?
	JRST	LPTA.1			;NO, GO HANDLE SPECIAL CHARS
	TXNE	S,FORWRD		;ARE WE FORWARD SPACING ???
	$RET				;YES, RETURN NOW
	SETZM	J$XTOP(J)		;CLEAR TOF FLAG
	JRST	DEVOUT			;Output the character
LPTA.1:	PUSHJ	P,CHKSP			;GO HANDLE SPECIAL CHARS
	$RET
SUBTTL	LPTELV  --  Print MACY11 file as regular ASCII


LPTELV:	PUSHJ	P,.SAVE1		;PRESERVE P1
LPTE.1:	SOSL	J$DBCT(J)		;COUNT DOWN AND JUMP IF DATA IS THERE.
	JRST	LPTE.2			;GO GET A DATA BYTE.
	PUSHJ	P,INPBUF		;ELSE, GET A BUFFER FULL
	JUMPT	LPTE.1			;IF OK,,GET NEXT FOUR BYTES
	$RETT				;ELSE RETURN.

LPTE.2:	ILDB	P1,J$DBPT(J)		;GET 4 BYTES TO PRINT
	LDB	C,[POINT 8,P1,17]	;GET THE FIRST BYTE
	PUSHJ	P,LPTE.3		;PRINT IT
	LDB	C,[POINT 8,P1,9]	;GET SECOND BYTE
	PUSHJ	P,LPTE.3		;PRINT IT
	LDB	C,[POINT 8,P1,35]	;GET THIRD BYTE
	PUSHJ	P,LPTE.3		;PRINT IT
	LDB	C,[POINT 8,P1,27]	;GET FOURTH BYTE
	PUSHJ	P,LPTE.3		;PRINT IT
	JRST	LPTE.1			;GET THE NEXT FOUR BYTES

LPTE.3:	CAIGE	C,40			;PRINTABLE ASCII?
	JRST	LPTE.6			;NO, GO HANDLE SPECIAL CHARS
	TXNE	S,FORWRD		;ARE WE FORWARD SPACING ???
	POPJ	P,			;YES, SKIP THIS.
	SETZM	J$XTOP(J)		;CLEAR TOF FLAG
LPTE.4:	SOSGE	J$LBCT(J)		;ANY ROOM IN BUFFER?
	JRST	LPTE.5			;NO, FILL IT
	IDPB	C,J$LBPT(J)		;YES, DEPOSIT IN BUFFER
	POPJ	P,			;AND GET ANOTHER

LPTE.5:	PUSHJ	P,@J$OUTP(J)		;GET A BUFFER
	JRST	LPTE.4			;AND LOOP

LPTE.6:	PUSHJ	P,CHKSP			;GO HANDLE SPECIAL CHARS
	POPJ	P,			;AND LOOP AROUND
SUBTTL	LPTFOR  --  Process FORTRAN data files

LPTFOR:	JUMPE	C,.POPJ			;IGNORE NULLS
	TXZE	S,FCONV			;CHECK FOR CTL CHAR
	JRST	FORCNV			;GO DO IT
	CAIN	C,.CHLFD		;LINEFEED?
	TXOA	S,FCONV			;FLAG NEXT CHAR AS CTL CHAR
	JRST	LPTCHR			;OTHERWISE PRINT IT
	$RET

FORCNV:	MOVSI	T1,-NFORCH		;MAKE AN AOBJN POINTER
FORC.1:	HLRZ	T2,FORTAB(T1)		;GET CHAR FROM TABLE
	CAMN	C,T2			;MATCH?
	JRST	FORC.2			;YES, GO TRANSLATE
	AOBJN	T1,FORC.1		;NO, LOOP
	MOVEI	C,.CHLFD		;DIDN'T FIND A MATCH, SO LOAD
	JRST	LPTCHR			; A LINEFEED, SEND IT
	
FORC.2:	HRRZ	C,FORTAB(T1)		;GET TRANS CHAR AND REPEAT COUNT
	LDB	T1,[POINT 9,C,26] 	;GET REPEAT COUNT IN T1
	MOVEM	T1,J$XFRC(J)		;SAVE THE REPEAT COUNT
	ANDI	C,177			;AND DOWN TO CHARACTER
FORC.3:	PUSHJ	P,LPTCHR		;SEND THE CHARACTER
	SOSLE	J$XFRC(J)		;COUNT DOWN THE REPEAT COUNTER
	JRST	FORC.3			;AND LOOP
	$RET
SUBTTL	LPTRPT  --  Process REPORT files

LPTRPT:	PUSHJ	P,INPBYT		;GET A BYTE FROM THE FILE
	JUMPF	.RETT			;AND RETURN WHEN DONE
	PUSHJ	P,LPTCHR		;DO ALL THE CHECKING
	JRST	LPTRPT			;AND GET ANOTHER
SUBTTL	LPTOCT  --  Give an Octal Dump

LPTOCT:	PUSHJ	P,.SAVE3		;SAVE P1 -- P3
	LOAD	T1,.FPINF(E),FP.FSP	;GET THE SPACING CODE
	CAIE	T1,1			;SINGLE SPACE?
	SKIPA	P2,[22,,1]		;NO--THEN TRIPLE SPACE, DOUBLE SPACE
					;IS UGLY --DO NOT ALLOW IT
	MOVE	P2,[12,,3]		;SINGLE SPACE THE LISTING
OCT1:	MOVEI	T1,(P2)			;BLOCK PER PAGE
OCT2:	MOVEI	T2,^D16			;LINES PER BLOCK
OCT3:	MOVEI	T3,^D8			;WORDS PER LINE
	MOVE	P1,J$FWCL(J)		;GET THE WIDTH CLASS
	CAIN	P1,2			;IS IT 2?
	MOVEI	T3,4			;YES, USE 4 WORDS/LINE
	CAIN	P1,1			;IS IT 1?
	MOVEI	T3,2			;YES, USE 2 WORDS/LINE
OCT4:	MOVEI	T4,^D12			;DIGITS PER WORD
	MOVEI	C," "			;EACH WORD BEGINS WITH 3 BLANKS
	PUSHJ	P,DEVOUT		;ONE
	PUSHJ	P,DEVOUT		;TWO
	PUSHJ	P,DEVOUT		;THREE
	PUSHJ	P,INPBYT		;GET A WORD
	JUMPF	.RETT			;DONE!!
	MOVE	P3,C			;COPY WORD
	SETZM	J$XTOP(J)		;FLAG MIDDLE OF FORM
	MOVE	P1,[POINT 3,P3]		;LOAD BYTE POINTER
OCT5:	ILDB	C,P1			;GET NEXT DIGIT
	MOVEI	C,60(C)			;MAKE ASCII
	PUSHJ	P,DEVOUT		;PRINT CHAR
	SOJG	T4,OCT5			;END OF WORD?
	SOJG	T3,OCT4			;END OF LINE?
	HLRZ	C,P2			;GET MOTION CHARACTER
	PUSHJ	P,DEVOUT		; ..
	SOJG	T2,OCT3			;END OF BLOCK?
	PUSHJ	P,DEVOUT		;YES--2 EXTRA LINE FEEDS
	PUSHJ	P,DEVOUT		; ..
	SOJG	T1,OCT2			;END OF PAGE?
	MOVEI	C,.CHFFD		;PRINT A FORM FEED
	PUSHJ	P,DOFORM		;AND ENFORCE QUOTA ETC.
	JRST	OCT1			;PRINT NEXT PAGE
SUBTTL	LPTCOB  --  Process COBOL Sixbit Files

LPTCOB:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	SETZM	J$XTOP(J)		;CAUSE A FORM FEED AT END
	PUSHJ	P,INPBYT		;GET THE FIRST WORD OF THE FILE
	JUMPF	.RETT			;NULL FILE
	HLRZ	T1,C			;COPY THE FIRST 3 LETERS
	CAIE	T1,'HDR'		;IS IT A HDR
	JRST	COBOL2			;NO--NORMAL INPUT
	MOVEI	T1,15			;FLUSH TAPE HEADER
	PUSHJ	P,INPBYT		;GET A WORD
	JUMPF	COBOL5			;EOF
	SOJG	T1,.-2			;LOOP FOR MORE


COBOL1:	PUSHJ	P,INPBYT		;GET A WORD
	JUMPF	COBOL5			;THE LAST WORD HAS COME
COBOL2:	ANDI	C,7777			;MASK TO 12 BITS
	JUMPLE	C,COBOL1		;IGNORE 0 COUNTS FOR OBVIOUS REASON
	MOVEI	P1,(C)			;COPY THE COUNT

	MOVEI	S1,-1(P1)		;GET COUNT-1 IN S1
	SUB	S1,J$FWID(J)		;ROUND DOWN TO A LINE
	IDIV	S1,J$FWID(J)		;CONVERT TO # LINES
	MOVNS	S1			;NEGATE IT
	ADDM	S1,J$XPOS(J)		;AND DECREMENT POSITION

COBOL3:	PUSHJ	P,INPBYT		;GET A DATA WORD
	JUMPF	.RETT			;END OF FILE-- ACTUALY THIS SHOULD
					; NEVER HAPPEN SINCE THE COUNT IS EXACT.
	MOVEI	T1,6			;CHARS PER WORD.
	CAIG	P1,6			;ARE WE DOWN TO LAST DREGS?
	MOVEI	T1,(P1)			;YES--USE EXACT COUNT TO AVOID FREE
					; CRLF ON EXTRA BLANKS.
	MOVE	T2,C			;COPY WORD
	MOVE	P2,[POINT 6,T2]		;POINT TO WORD
COBOL4:	ILDB	C,P2			;AND GET THE CHARACTER
	MOVEI	C,40(C)			;MAKE ASCII
	PUSHJ	P,DEVOUT		;PRINT
	SOJG	T1,COBOL4		;LOOP FOR NEXT CHAR
	SUBI	P1,6			;COUNT 6 MORE CHARS
	JUMPG	P1,COBOL3		;GET MORE
	MOVEI	C,.CHCRT		;LOAD A CARRIAGE RETURN
	PUSHJ	P,DEVOUT		;PRINT IT
	MOVEI	C,.CHLFD		;LOAD A LINE FEED
	PUSHJ	P,DOLF			;AND SEND EOL
	JRST	COBOL1			;LOOP FOR MORE.

COBOL5:	MOVEI	C,.CHFFD		;GET A FORM FEED.
	PUSHJ	P,DEVOUT		;PUT IT OUT.
	$RETT				;AND RETURN.
SUBTTL	Character Interrogation Routines

;SUBROUTINE TO PLACE A CHAR ON THE LINE PRINTER
;CALL WITH:
;	PUSHJ	P,LPTCHR
;	RETURN HERE (EOF SET IF OVER LIMIT)

LPTCHR:	CAIGE	C,40			;VISABLE ASCII
	JRST	CHKSP			;NO--SEE IF SPACE
	TXZE	S,NEWLIN		;AND THIS IS A NEW LINE
	SKIPN	J$XCOD(J)		;LETS NOT DO A /REPORT IS THERE IS NO CODE.
	SKIPA				;DONT GO DOWN THE TUBES.
	JRST	J$XCOD(J)		;SEE IF REPORT LINE MATCHES
	SETZM	J$XTOP(J)		;CLEAR FORM FEED FLAG
	PJRST	DEVOUT			;PRINT IT

CHKSP:	MOVE	S1,CHTAB(C)		;GET THE DISPATCH
	TXNE	S1,EOLCHR		;IS THIS AN END OF LINE CHARACTER ???
	TXO	S,NEWLIN		;YES, LITE NEW LINE BIT
	TXNE	S,SUPFIL!SUPJOB		;IN SUPPRESS MODE?
	TXNN	S1,SUPRCH		;YES, IS THIS CHARACTER SUPPRESSABLE?
	SKIPA				;Skip the suppress stuff
	JRST	DOSUP			;SUPPRESS THE CHARACTER
	TXNN	S1,NCLRFF		;CLEAR FORMFEED FLAG?
	SETZM	J$XTOP(J)		;YES
	JRST	(S1)			;Dispatch the character




;HERE TO THROW AWAY A LINE

FLUSH7:	PUSHJ	P,INPBYT	;GET A BYTE
	JUMPF	.RETT		;RETURN ON EOF
	PUSHJ	P,ISEOL		;END OF LINE?
	JUMPF	FLUSH7		;NO--LOOP FOR REST OF LINE
FLUSH8:	PUSHJ	P,INPBYT	;GET A BYTE
	JUMPF	.RETT		;RETURN ON EOF
	PUSHJ	P,ISEOL		;GOT EOL CHARACTER?
	JUMPF	LPTCHR		;NO, NEW LINE, DO THE MATCH
	JRST	FLUSH8		;YES, LOOP AGAIN


ISEOL:	CAIL	C," "			;IS IT PRINTABLE?
	$RETF				;YES, ITS NOT AN EOL
	MOVE	S1,CHTAB(C)		;NO, GET TABLE ENTRY
	TXNN	S1,EOLCHR		;IS IT AN EOL?
	$RETF				;NO, JUST RETURN
	TXO	S,NEWLIN		;YES, SET NEW LINE
	$RETT				;AND RETURN
;HERE ON A LINE FEED
DOLF:	LOAD	T1,.FPINF(E),FP.FSP	;GET SPACING PARAMETER
	SETO	S1,			;START WITH 1 LINE
DOLF1:	SOJLE	T1,CNTDWN		;ANY MORE?
	MOVEI	C,.CHLFD		;LOAD A LINE-FEED
	PUSHJ	P,DEVOUT		;YES--GIVE IT
	SOJA	S1,DOLF1		;AND SUBTRACT FROM QUOTA

;HERE TO PROCESS A FORM FEED
DOFORM:	SKIPE	J$XTOP(J)		;SKIP IF NOT AT TOP OF FORM
	POPJ	P,			;DO NOT PRINT BLANK PAGES
	MOVN	S1,J$XPOS(J)		;THIS TAKES ALL WE HAVE ON PAGE
	SKIPL	S1			;WAS VPOS NEGATIVE?
	CLEAR	S1,			;DONT CHARGE FOR ANYTHING THEN.
					;THIS MIGHT GIVE THE USER A
					;BONUS OF 1-3 FREE LINES.
	JRST	CNTDWN			;COUNT DOWN THE LIMIT

;HERE IF /PRINT:SUPPRESS
DOSUP:	MOVEI	C,.CHLFD		;MAKE IT A LINEFEED, REGARDLESS
	SKIPE	J$XTOP(J)		;SKIP IF NOT TOP
	POPJ	P,			;ONLY 1 LINE FEED IN A ROW
	SETOM	J$XTOP(J)		;AND SET TOP
	SETO	S1,
	JRST	CNTDWN			;CHARGE FOR THE LINE

;HERE TO DO ARROW MODE STUFF IF NEEDED
CHKARO:	TXNN	S,ARROW!SUPJOB		;ARROW MODE (From OPR SUPPRESS comd
	JRST	DEVOUT			;NO--JUST PRINT
DOARO:	PUSH	P,C			;SAVE C
	MOVEI	C,"^"			;LOAD A ^
	PUSHJ	P,DEVOUT		;PRINT THE ^
	POP	P,C			;RESTORE C
	MOVEI	C,100(C)		;MAKE INTO REAL LETTER
	PJRST	DEVOUT			;PRINT

;HERE ON A DC1
DODC1:	MOVNI	S1,2			;DC1 SKIPS 2 LINES
	JRST	CNTDWN			;AND COUNT DOWN

;HERE ON A DC2
DODC2:	MOVNI	S1,3			;DC2 SKIPS 3 LINES
	JRST	CNTDWN			;AND COUNT DOWN

;HERE ON A DC3
DODC3:	SETOM	S1			;DC3 SKIPS 1 LINE
	JRST	CNTDWN			;AND COUNT DOWN

;HERE IF SPECIAL CHARACTER SKIPS A FRACTION OF A PAGE
DOFRAC:	HLRZS	S1			;GET 0,,FRACTION
	ANDI	S1,777			;AND OUT FLAGS
	MOVE	T1,J$FLIN(J)		;GET CURRENT PAGE SIZE
	IDIVI	T1,(S1)			;FIND THE RIGHT PART
	MOVE	T2,J$XPOS(J)		;GET CURRENT POSITION
	SOJL	T2,[MOVN S1,J$XPOS(J)	;COPY VPOS
		    SUBI S1,3		;SUBTRACT 3
		    JRST CNTDWN]	;AND CHARGE HIM
	IDIVI	T2,(T1)			;GET RESIDUE MOD SKIPSIZE
	MOVNI	S1,1(T3)		;AND MAKE IT NEGATIVE
	JRST	CNTDWN			;GO CHECK QUOTA

SUBTTL	CNTDWN -- COUNT DOWN LINE FEEDS AND PAGE FEEDS

	;CALL:	S1/ Line Count Modifier
	;	C/  The Character Being Printed
	;
	;RET:	TRUE ALWAYS

CNTDWN:	CAIL	C,12			;MAKE SURE THIS IS A CARRIAGE CONTROL
	CAILE	C,24			;   CHARACTER.
	PJRST	DEVOUT			;IF NOT, JUST DUMP IT OUT.
	CAIN	C,.CHFFD		;IS IT A FORM FEED ???
	JRST	CNTDW1			;YES, SKIP THIS.
	ADDB	S1,J$XPOS(J)		;REDUCE VERTICAL POSITION
	JUMPG	S1,DEVOUT		;JUMP IF STILL ON PAGE
	CAIN	C,23			;WAS IT A DC3?
	CAMG	S1,[-3]			;YES, GIVE HIM 3 EXTRA LINES
	JRST	CNTDW1			;OFF PAGE ANYWAY
	PJRST	DEVOUT			;HE WINS!!

CNTDW1:	MOVE	S1,J$FLIN(J)		;BACK TO TOP OF PAGE
	MOVEM	S1,J$XPOS(J)		;SAVE POSITION
	SOSG	J$FPIG(J)		;DECREMENT THE FORWARD SPACING COUNT.
;**;[4005]ADD 6 LINES AT CNTDW1:+3L	13-MAY-85/CTK
	JRST	[TXZ	S,FORWRD	;[4005]TURN OFF FORWARD SPACE BIT
		 SKIPE	J$FPIG(J)	;[4005]JUST FINISH FORWARDSPACE
		 JRST	.+1		;[4005]NEVER DID
		 PUSHJ	P,SENDFF	;[4005]YES, SEND A FORM FEED
		 SETZM	C		;[4005]ZAP THE CHARACTER
		 JRST	.+1]		;[4005]CONTINUE
	AOS	J$RNPP(J)		;ADD 1 TO PAGES PER COPY COUNTER
	TXNE	S,FORWRD		;FORWARD SPACING ???
	JRST	[			;Yes
TOPS10<		MOVE	S1,J$RNPP(J)	;Get pages printed per copy
		IDIVI	S1,FRWSKP	;Divide by DSCHD factor
		SKIPE	S2		;Are we on an evenly divisible page?
		JRST	CNTDW2		;No, skip this
		SETZM	SLEEPT		;No sleeptime wanted
		$DSCHD(0)		;Let the other streams try
> ; End of TOPS10
		JRST	CNTDW2]		;Continue on
	AOS	J$APRT(J)		;NO, ADD 1 TO TOTAL PAGES COUNTER

	;Here we keep track of where we are for backspaceing

CNTDW2:	MOVE	S1,J$FCBC(J)		;GET NUMBER OF BYTES IN THIS BUFFER
	SUB	S1,J$DBCT(J)		;CALC BYT POS OF THIS PAGE IN THIS BUFR
	ADD	S1,J$FTBC(J)		;CALC BYT POS OF THIS PAGE IN THIS FILE
	MOVEM	S1,@J$FBPT(J)		;SAVE THE PAGE ADDRESS IN THE PAGE TABLE
	AOS	S1,J$FBPT(J)		;BUMP TO NEXT PAGE TABLE ENTRY
	CAIG	S1,J$FPAG+PAGSIZ-1(J)	;ARE WE AT THE END OF THE PAGE TABLE ???
	JRST	CNTDW3			;NO, CONTINUE ON
	TXO	S,FBPTOV		;YES, LITE PAGE TABLE OVERFLOW FLAG
	MOVEI	S1,J$FPAG(J)		;AND WRAP THE
	MOVEM	S1,J$FBPT(J)		;   PAGE TABLE AROUND ITSELF

CNTDW3:	PUSH	P,C			;SAVE THE CURRENT CHAR
	PUSHJ	P,CHKALN		;CHECK FOR ALIGNMENT
	POP	P,C			;RESTORE THE OLD CHARACTER
	MOVEI	S1,3			;LOAD A 3
	CAIN	C,23			;GET HERE VIA DC3?
	ADDM	S1,J$XPOS(J)		;YES, GIVE HIM 3 XTRA LINES
	CAIE	C,23			;WAS IT A DC3
;**;[4005]REVAMP CODE AT CNTDW3:+8L	13-MAY-85/CTK
	JRST	[SKIPG	J$FPIG(J)	;[4005]ARE WE FORWARD SPACING
		 SETOM	J$XTOP(J)	;[4005]NO, SET TOP OF FORM
		 JRST	.+1]		;[4005]CONTINUE
	$CALL	LIMCHK			;Go check the limit
	JUMPT	DEVOUT			;Output character and return (not here)
	$CALL	INPFEF			;Error -- force an EOF
	$RET
SUBTTL	LIMCHK -- Check on page limits

Comment\
  The purpose of this routine is to check and see if the current page limit
for the job has been exceeded.  If so, then check with the operator to see
if the job should proceed.  If ignore then set the bit and return.  If the
jobe is to be aborted, then set that bit.  In any case, if the job can be
continued, return true.
\
LIMCHK:	MOVE	S1,J$RLIM(J)		;GET LIMIT
	SUB	S1,J$APRT(J)		;GET AMOUNT PRINTED
;**;[4005]ADD 2 LINES AT LIMCHK:+2L	13-MAY-85/CTK
	SKIPGE	J$FPIG(J)		;[4005]ZERO FORWRD SPACE PAGES?
	SETZM	J$FPIG(J)		;[4005]YES, SET IT
	TXNN	S,ABORT+GOODBY		;ARE WE ON OUR WAY OUT OR
	SKIPL	S1			;   STILL UNDER QUOTA ???
	JRST	LIMC.5			;Yes, return true
	GETLIM	S1,.EQLIM(J),FLEA	;GET FORMS-LIMIT-EXCEED ACTION
	CAIN	S1,.STCAN		;SEE IF CANCEL
	JRST	LIMC.4			;IT WAS, DO IT
	CAIN	S1,.STIGN		;SEE IF IGNORE
	JRST	LIMC.5			;Yes, return true

	;DEFAULT TO ASK IF NOT IGNORE OR CANCEL

LIMC.1:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	SETZM	JOBCHK(S1)		;SAY WE WANT TO TAKE A CHECKPOINT
	SETOM	JOBUPD(S1)		;  update the status also
	$WTOR	(Page Limit Exceeded,<^R/.EQJBB(J)/^T/LIMSG/>,@JOBOBA(S1),JOBWAC(S1))
	$DSCHD	(PSF%OR)		;WAIT FOR OPERATOR RESPONSE
	TXNE	S,ABORT+RQB		;HAVE WE BEEN CANCELED OR REQUEUED ???
	JRST	LIMC.2			;YES, IGNORE THE ERROR
	MOVEI	S1,LIMANS		;POINT TO THE LIMIT ANSWER BLOCK
	HRROI	S2,J$RESP(J)		;POINT TO THE ANSWER
	PUSHJ	P,S%TBLK		;DO WE MATCH ???
	TXNE	S2,TL%NOM+TL%AMB	;DID WE FIND IT OK ???
	JRST	LIMC.1			;NO, STUPID OPERATOR SO TRY AGAIN
	HRRZ	S1,0(S1)		;GET THE ROUTINE ADDRESS
	JRST	0(S1)			;AND PROCESS THE RESPONSE

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	;IF ANSWER WAS 'PROCEED' COME HERE

LIMC.2:	MOVX	S1,.STIGN		;YES, GET THE IGNORE BITS
	STOLIM	S1,.EQLIM(J),FLEA	;SAVE IT AS NEW LIMIT EX ACTION
	JRST	LIMC.5			;Return true

	;IF ANSWER WAS 'ABORT' COME HERE

LIMC.3:	MOVE	S1,STREAM		;GET THE STREAM NUMBER
	$WTO	(Aborting,<^R/.EQJBB(J)/>,@JOBOBA(S1)) ;TELL THE OPERATOR

LIMC.4:	$TEXT(LOGCHR,<^I/LPERR/Page Limit Exceeded>)
	SETZM	J$XTOP(J)		;CLEAR TOP-OF-FORM FLAG
	PUSHJ	P,SENDFF		;SEND A FORM FEED
	TXO	S,ABORT			;LIGHT THE ABORT BIT
	$TEXT	(<-1,,J$WTOR(J)>,<Page limit exceeded^0>)
	$RETF				;Limit exceeded, don't continue

LIMC.5:	$RETT				;OK to proceed

LIMANS:	$STAB
	 KEYTAB	(LIMC.3,ABORT)		;ABORT
	 KEYTAB	(LIMC.2,PROCEED)	;PROCEED
	$ETAB
SUBTTL	DEVOUT - Subroutine to output one char on selected device

;Call DEVOUT with a character to be output on the virtual device.
;Call PHSOUT only from a device driver which is bypassing its own
;character translation RAM or VFU simulations.
; Call:
;	C/	Character to output
;	PUSHJ	P,DEVOUT
;	Return here (HALTs if error)
;

DEVOUT::TXNE	S,FORWRD		;ARE WE FORWRD SPACING ???
	POPJ	P,			;YES, RETURN.
	PUSHJ	P,@J$CHRO(J)		;SEE IF DRIVER NEEDS TO TRANSLATE
	 $RETIF				;IF DRIVER CHOOSES NOT TO, DON'T
PHSOUT::SOSGE	J$LBCT(J)		;DECREMENT THE BYTE COUT
	JRST	DEVO.1			;LOSE, GO DUMP THE BUFFER
	IDPB	C,J$LBPT(J)		;DEPOSIT A BYTE
	POPJ	P,			;AND RETURN

DEVO.1:	PUSH	P,S1			;SAVE S1
	PUSHJ	P,@J$OUTP(J)		;DUMP THE BUFFER
	POP	P,S1			;RESTORE S1
	JRST	PHSOUT			;AND TRY AGAIN

;SENDFF - ROUTINE TO SEND A FF IF J$XTOP IS OFF
;
SENDFF::SKIPN	J$FFDF(J)		;DRIVER HANDLE FORM FEEDS?
	POPJ	P,			;NO
	MOVEI	C,.CHFFD		;LOAD A FF
	SKIPN	J$XTOP(J)		;SKIP IF ALREADY AT TOP
	PUSHJ	P,DEVOUT		;NO, SEND IT
	SETOM	J$XTOP(J)		;SET THE FLAG
	POPJ	P,			;RETURN


CHKALN:	SKIPL	J$APRG(J)		;YES, IS AN ALIGNMENT SCHEDULED ???
	POPJ	P,			;NO, RETURN.
	PUSHJ	P,ALIGN			;YES, THEN DO IT.
	$RETT				;RETURN TO HIS CALLER.
SUBTTL	Subroutines to send messages to the output device

;Since output to the output-device is interruptable $TEXT calls which
;	send characters directly to the device cannot be done.
;
;A per-context buffer (J$XTBF) is defined to store $TEXT'ed characters
;	in and the following set of subroutines exist to initialize,
;	deposit characters in, and dump this buffer to the output device.


;TBFINI initializes the byte-pointer to J$XTBF
TBFINI:	MOVEI	S1,J$XTBF(J)		;GET THE ADDRESS OF THE BUFFER
	HRLI	S1,(POINT 7,0)		;MAKE IT A BYTE POINTER
	MOVEM	S1,J$XTBP(J)		;STORE IT
	MOVEI	S2,0			;LOAD A NULL
	IDPB	S2,S1			;AND INITIALIZE THE BUFFER
	$RETT				;AND RETURN


;TBFCHR is the $TEXT subroutine to deposit characters in the text buffer.
TBFCHR:	IDPB	S1,J$XTBP(J)		;DEPOSIT THE CHARACTER
	$RETT				;RETURN


;TBFDMP dumps the text buffer to output device and re-initializes the buffer
TBFDMP:	SETZ	S1,			;CLEAR THE AC
	IDPB	S1,J$XTBP(J)		;DEPOSIT THE BYTE
	MOVEI	S1,J$XTBF(J)		;GET ADDRESS OF BUFFER
	PUSHJ	P,BFRDMP		;DUMP THE BUFFER
	PJRST	TBFINI			;RE-INIT THE BUFFER AND RETURN

;STGOUT is included to allow dumping of any arbitrary buffer of characters
;	Call with S1 containing either a byte pointer or the address of the buffer
STGOUT::PUSH	P,S1			;SAVE S1
	PUSHJ	P,TBFDMP		;FORCE ANY BUFFERED STUFF OUT
	POP	P,S1			;RESTORE S1
					;AND FALL INTO BFRDMP

;BFRDMP to dump the buffer pointed to by S1
BFRDMP:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;PUT THE POINTER IN P1
	TLNN	P1,-1			;IS LEFT HALF ZERO
	HRLI	P1,(POINT 7,0)		;YES, MAKE IT A BYTE POINTER

BFRD.1:	ILDB	C,P1			;GET A CHARACTER
	JUMPE	C,.RETT			;RETURN WHEN DONE
	SETZM	J$XTOP(J)		;CLEAR THE TOP-OF-FORM FLAG
	CAIN	C,.CHFFD		;IS IT A FORMFEED?
	SETOM	J$XTOP(J)		;YES, SET IT
	PUSHJ	P,DEVOUT		;OUTPUT THE CHARACTER
	JRST	BFRD.1			;AND LOOP
SUBTTL	ROUTINES TO GENERATE HEADERS AND TRAILERS

	;JOB HEADERS AND TRAILERS
JOBTRL:	MOVEI	T4,[ASCIZ /END/]	;ADDRESS OF END TEXT
	TXNE	S,RQB			;CLEAR REQUE AND SKIP IF NOT SET
	MOVEI	T4,[ASCIZ /REQUE/] 	;SAY SO
	PUSHJ	P,GIVHDR		;GO SETUP THE LINE
	JRST	TRAILR			;AND NOW GO PRINT THE TRAILER

JOBHDR:	MOVEI	T4,LPTERR		;ALLOW FOR LPT ERRORS HERE
	MOVEM	T4,J$LERR(J)		;STORE COUNTER
	MOVEI	T4,[ASCIZ /START/]	;ADDRESS OF START TEXT
	PUSHJ	P,GIVHDR		;GO SET THE LINE
	JRST	BANNER			;AND GO PRINT THE BANNER PAGES

GIVHDR:	$TEXT	(<-1,,J$XHBF(J)>,<^T7C*/0(T4)/ ^R/.EQJBB(J)/  ^I/DATMON/^0>)

	PUSHJ	P,@J$HDRW(J)		;SET UP HEADER WIDTHS FOR THIS PRINTER
	MOVE	S1,J$FWID(J)		;GET THE PAGE WIDTH
	IDIVI	S1,5			;GET WORDS/BYTES TO THE END OF THE LINE
	ADDI	S1,J$XHBF(J)		;POINT TO THE LOGICAL END OF THE LINE
	LOAD	S2,PTRS(S2)		;GET BYTE PTR FOR END OF LINE
	SETZM	T1			;GET A NULL BYTE
	IDPB	T1,S2			;CUT THE HEADER OFF HERE !!!

	$RETT				;RETURN.

PTRS:	POINT	7,0(S1)
	POINT	7,0(S1),6
	POINT	7,0(S1),13
	POINT	7,0(S1),20
	POINT	7,0(S1),27
	POINT	7,0(S1),34

SUBTTL	BANNER  --  Routine to print a banner

BANNER:	PUSHJ	P,.SAVE3		;SAVE P1 THRU P3
	SKIPN	P3,J$FBAN(J)		;GET NUMBER OF BANNER PAGES
	POPJ	P,			;RETURN WHEN DONE
	SKIPN	.EQUSR(J)		;USER NAME GIVEN?
	JRST	BANN.0			;NO
	MOVEI	S1,.EQUSR(J)		;POINT TO NAME
	HRLI	S1,(POINT 8,)		;8-BIT ASCIZ
	$TEXT	(<-1,,J$PUSR(J)>,<^Q/S1/^0>)
	JRST	BANN.1			;ONWARD

BANN.0:
TOPS10 <
	$TEXT(<-1,,J$PUSR(J)>,<^W6/.EQOWN(J)/^W/.EQOWN+1(J)/^0>)
>  ;END TOPS10 CONDITIONAL

TOPS20 <
	$TEXT(<-1,,J$PUSR(J)>,<^T/.EQOWN(J)/^0>)
>  ;END TOPS20 CONDITIONAL

BANN.1:	SKIPN	J$ALNF(J)		;PRINTER NEEDS FORMFEEDS?
	PUSHJ	P,SENDFF		;SEND A FORM FEED
	PUSHJ	P,@J$BNRI(J)		;INIT BANNER PAGES (POSSIBLE FONTS)
	JUMPF	.RETT			;THAT'S ALL IF NO BANNERS DESIRED
	SETZM	J$XPOS(J)		;AND SET 0 POSITION
	MOVEI	T1,4			;LOAD AN OFFSET
	CAIN	P3,1			;IS THIS THE LAST BANNER?
	ADDM	T1,J$XPOS(J)		;YES, DON'T PRINT OVER CREASE
	PUSHJ	P,BANN.2		;PRINT A BANNER PAGE
	SOJG	P3,BANN.1		;AND LOOP
	POPJ	P,			;RETURN

BANN.2:	PUSHJ	P,PLPBUF		;PRINT A LINE
	PUSHJ	P,PLPBUF		;PRINT ANOTHER LINE
	PUSHJ	P,CRLF			;TYPE A CRLF
	MOVEI	S1,1			;LOAD THE BLOCKSIZE
	MOVEI	S2,J$PUSR(J)		;AND THE STRING ADDRESS
	PUSHJ	P,PICTUR		;AND PRINT A PICTURE
	MOVEI	T1,^D12			;COUNT'EM
	ADDM	T1,J$XPOS(J)		;...
	PUSHJ	P,PLPBUF		;PRINT A LINE
	PUSHJ	P,PLPBUF		;AND ANOTHER

BANN.3:	SKIPN	.EQBOX(J)		;DISTRIBUTION BOX SPECIFIED?
	JRST	BANN.4			;NO
	MOVEI	S1,.EQBOX(J)		;POINT TO STRING
	HRLI	S1,(POINT 8,)		;8-BIT ASCIZ
	$TEXT	(<-1,,J$PDST(J)>,<^Q/S1/^0>)
	MOVEI	S1,1			;GET THE BLOCKSIZE
	MOVEI	S2,J$PDST(J)		;GET THE ADDRESS
	PUSHJ	P,PICTUR		;AND SEND IT OUT
	MOVEI	S1,^D11			;ACCOUNT FOR LINES
	ADDM	S1,J$XPOS(J)		; JUST WRITTEN

BANN.4:	PUSHJ	P,PLPBUF		;PRINT A LINE
	PUSHJ	P,PLPBUF		;AND ANOTHER
	MOVEI	T1,[0,,0]		;LOAD A NULL.
	MOVE	S1,J$FWCL(J)		;GET THE WIDTH CLASS
	CAIN	S1,3			;ROOM ENOUGH FOR THE TITLE?
	MOVEI	T1,[ASCIZ /Note:/]	;YES, LOAD IT
	GETLIM	T2,.EQLIM(J),NOT1	;GET FIRST HALF OF NOTE
	JUMPE	T2,PLINES		;NO NOTE, FINISH THE PAGE
	GETLIM	T3,.EQLIM(J),NOT2	;AND THE SECOND HALF
	$TEXT(<-1,,J$PNOT(J)>,<^T/0(T1)/^W6/T2/^W/T3/^0>)
	MOVEI	S1,1			;GET THE BLOCKSIZE
	MOVEI	S2,J$PNOT(J)		;GET THE ADDRESS
	PUSHJ	P,PICTUR		;AND SEND IT OUT
	MOVEI	S1,^D11			;LOAD NUMBER OF LINES
	ADDM	S1,J$XPOS(J)		;AND MOVE DOWN THE PAGE
	PJRST	PLINES			;GO TO EOP AND RETURN
SUBTTL	TRAILR  --  Routine to Print a Trailer

TRAILR:	PUSHJ	P,.SAVE3		;SAVE P1 - P3
	MOVE	P3,J$FTRA(J)		;AND THE NUMBER OF TRAILERS
	TXNE	S,SUPFIL!SUPJOB		;Are we suppressing forms?
	SETZM	J$XTOP(J)		;Don't believe we are at top of forms.
	PUSHJ	P,SENDFF		;SEND A FORMFEED
	JUMPE	P3,OUTDMP		;RETURN IF ZERO
	JRST	TRAI.2			;SKIP FORMFEED SEND,,ALREADY DID IT

TRAI.1:	SKIPN	J$ALNF(J)		;PRINTER NEEDS FORM-FEEDS?
	PUSHJ	P,SENDFF		;SEND A FORMFEED
TRAI.2:	PUSHJ	P,@J$BNRI(J)		;GO SET UP FOR BANNER PAGES
	SETZM	J$XPOS(J)		;CLEAR THE VERTICAL POSITION
	JUMPF	.RETT			;THAT'S ALL IF NO BANNERS DESIRED
	PUSHJ	P,LPTLOG		;PRINT THE INTERNAL LOG
	PUSHJ	P,PLINES		;PRINT TILL END OF PAGE
	SOJG	P3,TRAI.1		;LOOP UNTIL DONE
	PJRST	OUTDMP			;AND DUMP BUFFERS AND RETURN
SUBTTL	UTILITY ROUTINES

PLPBUF:	MOVEI	S1,J$XHBF(J)		;GET ADDRESS OF THE LINE
	PUSHJ	P,STGOUT		;AND DUMP IT
	PUSHJ	P,CR23			;END THE LINE WITH A CR23
	PUSHJ	P,CR23			;PRINT A CR23
	PUSHJ	P,CR23			;AND ANOTHER
	PUSHJ	P,CR23			;AND ANOTHER
	MOVEI	S1,4			;WE PRINT 4 LINES
	ADDM	S1,J$XPOS(J)		;ADD TO COUNT
	POPJ	P,



PLINES:	MOVE	T2,J$FLIN(J)		;GET LINES/PAGE
	ADDI	T2,1			;ACCOUNT FOR MARGIN
	SUB	T2,J$XPOS(J)		;SUBTRACT AMOUNT PRINTED
	JUMPLE	T2,PEOP			;JUMP IF DONE
	IDIVI	T2,4			;ELSE GET NUMBER OF LINES TO PRINT
PLINE1:	SOJL	T2,PEOP			;JUMP IF DONE
	PUSHJ	P,PLPBUF		;PRINT A LINE (4 LINES)
	JRST	PLINE1			;AND LOOP

PEOP:	MOVE	T2,J$FLIN(J)		;GET NUMBER OF LINES/PAGE
	SUB	T2,J$XPOS(J)		;SUBTRACT THOSE PRINTED
	ADDI	T2,1			;COUNT THE MARGIN
PEOP1:	JUMPLE	T2,PEOP2		;GO FINISH OFF
	PUSHJ	P,CR23			;PRINT A CR23
	SOJA	T2,PEOP1		;AND LOOP
PEOP2:	PUSHJ	P,@J$RULR(J)		;DRAW A RULER IF APPROPRIATE
	POPJ	P,

;**;[3004] Change code at CR23. /LWS
CR23:	SKIPE	J$DC3F(J)		;SKIP IF DC3 NOT SUPPORTED
	SKIPA	S1,[[BYTE (7) 15,23,0,0,0]] ;[3004] PRINT OUT CR23
CRLF:	MOVEI	S1,[BYTE (7) 15,12,0,0,0] ;PRINT AT CRLF
	PUSHJ	P,STGOUT		;PUT IT OUT
	$RET				;AND RETURN
SUBTTL	HEAD  --  Generate File-header pages

HEAD:	PUSHJ	P,.SAVE3		;SAVE SOME ACS
	TXNE	S,SUPFIL!SUPJOB		;Are we suppressing forms?
	SETZM	J$XTOP(J)		;Don't believe we are at top of forms.
;**;[4005]ADD AND REVAMP CODE AT HEAD:+3L	13-MAY-85/CTK
	LOAD	P1,.FPINF(E),FP.NFH	;[4005]GET THE NO HEADER BIT
	SKIPE	P1			;[4005]SKIP IF WE WANT HEADERS
	JRST	[MOVE	S1,J$FPIG(J)	;[4005]GET PAGE TO FORWARD SPACE
		CAIG	S1,1		;[4005]FORWARD SPACING ???
		PUSHJ	P,SENDFF	;[4005]NO, SEND FORM FEED
		PJRST	OUTDMP]		;[4005]DUMP BUFFERS AND RETURN
	PUSHJ	P,SENDFF		;[4005]SEND A FORM FEED
	SKIPN	P3,J$FHEA(J)		;GET NUMBER OF PICTURE PAGES
	PJRST	OUTDMP			;DUMP BUFFERS AND RETURN
	PUSHJ	P,@J$HDRW(J)		;Set up the widths for the headers
	PUSHJ	P,SETHDR		;SETUP THE FILENAME FOR BLOCK LETTERS
	PUSHJ	P,HEAD.1		;PRINT THE HEADER
	SOJG	P3,.-1			;LOOP FOR THE WHOLE WORKS
	PJRST	OUTDMP			;FORCE EVERYTHING OUT, AND RETURN

HEAD.1:	PUSHJ	P,@J$HDRI(J)		;SET POSSIBLE HEADER FONTS
	JUMPF	.RETT			;THAT'S ALL IF NO BANNERS DESIRED
	MOVE	S1,J$PFLS(J)		;GET BLOCKSIZE
	MOVEI	S2,J$PFL1(J)		;AND ADDRESS OF FIRST LINE
	PUSHJ	P,PICTUR		;PRINT THE LINE
	MOVE	S1,J$PFLS(J)		;GET BLOCKSIZE
	MOVEI	S2,J$PFL2(J)		;AND ADDRESS OF SECOND LINE
	PUSHJ	P,PICTUR		;AND PRINT THE SECOND LINE
	MOVE	P1,J$FWCL(J)		;LOAD THE WIDTH CLASS
	MOVEI	S1,J$XHBF(J)		;LOAD ADDRESS OF BANNER LINE
	PUSHJ	P,STGOUT		;AND SEND IT
	MOVE	S1,J$DIFN(J)		;GET THE IFN
	MOVX	S2,FI.CRE		;WANT CREATION TIME
	PUSHJ	P,F%INFO		;GET IT
	MOVEI	S2,[ASCIZ / /]		;GET A STRING
	CAIE	P1,3			;WIDTH CLASS 3?
	MOVEI	S2,[BYTE (7) .CHCRT,.CHLFD,.CHTAB,0]
	MOVE	P1,S2			;Remember for short or long lines
;**;[2774] Changed 1 line at HEAD.1+16L. 26-Oct-83 /LWS
	$TEXT(TBFCHR,<^M^JFile ^F/@J$DFDA(J)/^T/J$GSPL(J)/, created: ^H/S1/,^T/(P1)/printed: ^H/[-1]/>) ;[2774]
	PUSHJ	P,TBFDMP		;AND DUMP THE BUFFER

	MOVEI	S1,J$LOUT(J)		;POINT TO NODE/DEVICE/UNIT TEXT
	SKIPN	(S1)			;HAVE SOMETHING?
	JRST	HEAD.2			;NO
	$TEXT	(TBFCHR,<^T/(S1)/>)	;COPY TEXT
	PUSHJ	P,TBFDMP		;AND DUMP THE BUFFER

HEAD.2:	GETLIM	S1,.EQLIM(J),FORM	;GET FORMS NAME
	$TEXT(TBFCHR,<Job parameters: Request created:^H/.EQAFT(J)/   Page limit:^D/J$RLIM(J)/^T/(P1)/  Forms:^W/S1/  Account:^T/.EQACT(J)/^A>)
	GETLIM	S1,.EQLIM(J),NOT1	;GET FIRST HALF OF NOTE
	GETLIM	S2,.EQLIM(J),NOT2	;GET SECOND HALF OF NOTE
	SKIPE	S1			;IS THERE A NOTE?
	$TEXT(TBFCHR,<   Note:^W6/S1/^W/S2/^A>)
	PUSHJ	P,CRLF			;END THE LINE
	PUSHJ	P,TBFDMP		;AND DUMP IT
	LOAD	S1,.FPINF(E),FP.FSP	;GET /SPACING
	LOAD	S2,.FPINF(E),FP.FCY	;GET THE TOTAL COPY COUNT
	LOAD	T1,J$RNCP(J)		;GET THE COPIES DONE SO FAR
	ADDI	T1,1			;MAKE THIS THE CURRENT COPY
	$TEXT(TBFCHR,<File parameters: Copy: ^D/T1/ of ^D/S2/   Spacing:^W/SPCTAB-1(S1)/^A>)

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

	PUSHJ	P,TBFDMP		;SEND THE LINE
	LOAD	S1,.FPINF(E),FP.FPF	;GET /PRINT
	LOAD	S2,.FPINF(E),FP.FFF	;GET /FILE
	CAXN	S2,.FPF8B		;/FILE:8-BIT?
	MOVEI	S2,4			;YES, RECORD THE VALUE
	CAXN	S2,.FPF11		;/FILE:ELEVEN?
	MOVEI	S2,5			;YES, RECODE THE VALUE
	$TEXT(TBFCHR,<^T/(P1)/  File format:^W/FFMTAB-1(S2)/   Print mode:^W/FMTAB-1(S1)/^A>)
	LOAD	S1,.FPINF(E),FP.DEL	;GET /DELETE BIT
	SKIPE	S1			;IS IT SET?
	$TEXT(TBFCHR,<   /DELETE^A>)	;YES, SAY SO
TOPS10	<
	LOAD	S1,.FPINF(E),FP.REN	;GET /DISPOSE:RENAME BIT
	SKIPE	S1			;IS IT SET?
	$TEXT(TBFCHR,<   /DISPOSE:RENAME^A>)	;YES, SAY SO
>;END TOPS10
	PUSHJ	P,CRLF			;END THE LINE
	MOVE	S1,J$FPIG(J)		;GET STARTING PAGE
	CAILE	S1,1			;SKIP IF 0 OR 1
;**;[4005]ADD 4 LINES AT HEAD.1:+58L	13-MAY-85/CTK
	JRST	[$TEXT(TBFCHR,<^M^JPrinting will start at page ^D/J$FPIG(J)/>)
		CAIN	P3,1		;[4005]LAST HEADER ???
		PJRST	TBFDMP		;[4005]YES, DUMP THE BUFFER
		JRST	.+1]		;[4005]NO, CONTINUE
	PUSHJ	P,TBFDMP		;DUMP THE BUFFER
	SKIPN	J$ALNF(J)		;PRINTER NEED A FORMFEED
	PJRST	SENDFF			;SEND A FORM FEED
	$RETT				;NO, RETURN NOW


FMTAB:	SIXBIT	/ARROW/
	SIXBIT	/ASCII/
	SIXBIT	/OCTAL/
	SIXBIT	/SUPRES/
	SIXBIT	/GRAPHI/

FFMTAB:	SIXBIT	/ASCII/
	SIXBIT	/FORT/
	SIXBIT	/COBOL/
	SIXBIT	/8-BIT/
	SIXBIT	/ELEVEN/



SPCTAB:	SIXBIT	/SINGLE/
	SIXBIT	/DOUBLE/
	SIXBIT	/TRIPLE/
SUBTTL	SETHDR  --  Setup header name for file

;SETHDR is called to setup the strings to be used for the two lines of
;	block letters on the file header pages.
;
;Call:	E/  address of the file's FP
;
;T Ret:	always

SETHDR:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	SETZM	J$PFL1+1(J)		;CLEAR THE 2ND WORD OF FIRST BUFFER
	SETZM	J$PFL2+1(J)		; AND 2ND BUFFER, (SEE SETH.W)

	SKIPN	.FPFR1(E)		;IS THERE A /REPORT KEY?
	JRST	SETH.1			;NO, CONTINUE ON
	$TEXT(<-1,,J$PFL1(J)>,<Report:^0>)	;FIRST LINE
	$TEXT(<-1,,J$PFL2(J)>,< ^W6/.FPFR1(E)/^W/.FPFR2(E)/^0>)
	JRST	SETH.W			;SET BLOCKSIZE AND RETURN

SETH.1:	LOAD	S1,.FPINF(E)		;GET FLAGS FOR FILE
TOPS10	<
	TXNE	S1,FP.REN		;IS IT /DISPOSE:RENAME?
	JRST	SETH.4			;YES, PROCESS THAT
>;END TOPS10
	TXNN	S1,FP.SPL		;IS IT A SPOOLED FILE?
	JRST	SETH.3			;NO, CONTINUE ON
	TXNN	S1,FP.FLG		;YES, IS IT ALSO THE LOG FILE?
	JRST	SETH.2			;NO, JUST A PLAIN SPOOLED FILE
	$TEXT(<-1,,J$PFL1(J)>,<Batch^0>) ;SPOOLED LOGS HAVE NO REASONABLE NAME
	$TEXT(<-1,,J$PFL2(J)>,< Log File^0>) 	;SO USE SOMETHING DESCRIPTIVE
	JRST	SETH.W			;AND FINISH UP

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

TOPS20 <
SETH.2:
SETH.3:	MOVE	P1,[POINT 7,J$PFL1(J)]	;GET THE FILENAME BYTE PTR
	MOVE	P2,[POINT 7,J$PFL2(J)]	;GET THE EXTEN BYTE PTR
	MOVX	S1,GJ%SHT!GJ%OFG	;PARSE-ONLY + SHORT-GTJFN
	MOVE	S2,J$DFDA(J)		;GET THE FD ADDRESS
	HRROI	S2,.FDFIL(S2)		;AND POINT TO THE FILESPEC
	GTJFN				;GET A JFN FOR THE FILE
	 ERJMP	SETH.S			;ERROR,,GIVE NON-DESCRIPT NAME
	EXCH	S1,P1			;SAVE JFN IN P1, GET POINTER IN S1
	MOVE	S2,P1			;GET JFN IN S2
	MOVX	T1,1B8			;FILENAME ONLY
	JFNS				;GET IT
	MOVE	S1,P2			;GET THE 2ND LINE POINTER
	MOVE	S2,P1			;GET THE JFN
	MOVX	T1,1B11			;EXTENSION ONLY
	JFNS				;GET THE EXTENSION
	MOVEI	T2,"."			;FIRST, LOAD A BLANK
	IDPB	T2,S1			;AND DEPOSIT IT
	MOVX	T1,1B14			;GET THE GENERATION NUMBER
	JFNS				;DO IT!!
	MOVE	S1,P1			;GET THE JFN
	RLJFN				;RELEASE IT
	ERJMP	.+1			;IGNORE THE ERROR
	LOAD	S1,.FPINF(E),FP.SPL	;GET THE SPOOL BIT
	JUMPE	S1,SETH.W		;IF NOT SPOOLED, THERE WE'RE DONE

	MOVE	P1,[POINT 7,J$PFL1(J)]	;RESTORE THE FILENAME BYTE PTR.
	MOVEI	S1,3			;HOW MANY DASHES TO LOOK FOR
	MOVE	S2,P1			;AND AN INPUT POINTER

SETH.4:	ILDB	T1,S2			;GET A CHARACTER
	JUMPE	T1,SETH.S		;NO, SPOOLED NAME IF NULL
	CAIE	T1,"-"			;A DASH?
	JRST	SETH.4			;NO, LOOP
	SOJG	S1,SETH.4		;YES, LOOP UNTIL 4TH FIELD
	MOVE	S1,P1			;GET A NEW POINTER TO SET DOWN CHARS

SETH.5:	ILDB	T1,S2			;GET A CHARACTER
	IDPB	T1,S1			;DEPOSIT IT
	JUMPN	T1,SETH.5		;AND LOOP UNTIL A NULL
	MOVEI	S2,6			;LOAD A COUNTER
	IDPB	T1,S1			;AND DEPOSIT MORE NULLS
	SOJG	S2,.-1			;FOR WIDTH CALCULATION
	MOVE	T1,J$PFL1(J)		;GET THE FIRST WORD ON 1ST LINE
	TLNN	T1,774000		;IS THERE AT LEAST ONE CHARACTER?
	JRST	SETH.S			;NO, NO NAME
	JRST	SETH.W			;YES, FILL IN WIDTH AND RETURN
>  ;END TOPS20 CONDITIONAL

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE

TOPS10 <
SETH.2:	MOVE	S1,J$DIFN(J)		;GET THE FILE'S IFN
	MOVX	S2,FI.SPL		;GET THE SPOOL NAME INFO CODE
	PUSHJ	P,F%INFO		;GET THE SPOOLED NAME (.RBSPL)
	JUMPE	S1,SETH.S		;NO SPOOLED NAME
	$TEXT(<-1,,J$PFL1(J)>,<^W/S1/^0>) ;GENERATE THE SPOOLED NAME
	SETZM	J$PFL2(J)	 	;AND NO EXTENSION
	JRST	SETH.W			;AND FINISH UP

SETH.3:	MOVE	P1,J$DFDA(J)		;GET THE FD ADDRESS
	$TEXT(<-1,,J$PFL1(J)>,<^W/.FDNAM(P1)/^0>)
	$TEXT(<-1,,J$PFL2(J)>,<^W3/.FDEXT(P1)/^0>)
	JRST	SETH.W			;FINISH UP AND RETURN

SETH.4:	$TEXT(<-1,,J$PFL1(J)>,<^W/.FPONM(E)/^0>) ;OUTPUT ORIGINAL NAME
	$TEXT(<-1,,J$PFL2(J)>,<^W3/.FPOXT(E)/^0>) ;AND EXTENSION
	JRST	SETH.W			;FINISH UP AND RETURN
>  ;END TOPS10 CONDITIONAL

;COMMON SUBROUTINES

;SETH.S is used to setup a non-descript name if we can't do any better

SETH.S:	$TEXT(<-1,,J$PFL1(J)>,<Spooled^0>)
	$TEXT(<-1,,J$PFL2(J)>,< Printer File^0>)
					;AND FALL INTO SETH.W

;SETH.W is called to figure out the blocksize to use, set it, and return.
;	If both lines are 6 characters or less, the current width-class is
;	used as the blocksize, else, blocksize of 1 is used.

SETH.W:	MOVE	S1,J$FWCL(J)		;GET THE WIDTH CLASS
	CAMLE	S1,J$FLCL(J)		;Compare with the length class
	MOVE	S1,J$FLCL(J)		;Use the min. of the two.
	MOVE	S2,J$PFL1+1(J)		;GET 2ND WORD OF LINE 1
	IOR	S2,J$PFL2+1(J)		;OR IN SECOND WORD OF LINE 2
	TLNE	S2,003760		;IS THE 7TH CHARACTER THERE IN EITHER?
	MOVEI	S1,1			;YES, USE BLOCKSIZE 1
	MOVEM	S1,J$PFLS(J)		;SAVE IT
	$RETT				;AND RETURN
SUBTTL	PICTUR  --  Routine to print block letters

;Call:	S1/  blocksize of letters
;	S2/  pointer to string (left half can be 0 or byte-pointer)

PICTUR:	PUSHJ	P,.SAVE3		;SAVE P1 THRU P3
	PUSHJ	P,.SAVET		;AND SAVE T1 THRU T4
	DMOVE	P1,S1			;SAVE THE INPUT ARGUMENTS
	MOVNI	P3,^D35			;GET A BIT COUNTER

PICT.1:	MOVE	T4,P1			;COPY OVER THE BLOCK SIZE
	PUSHJ	P,PICT.2		;PRINT A LINE
	SOJG	T4,.-1			;AND DO IT "BLOCKSIZE" TIMES
	ADDI	P3,5			;BUMP TO NEXT SEGMENT OF CHARACTER
	JUMPL	P3,PICT.1		;AND LOOP FOR NEXT SEGMENT

	MOVEI	S1,[BYTE (7) 15,12,12,12,12,0,0]
	PJRST	STGOUT			;SEND FOUR BLANK LINES AND RETURN

;HERE TO PRINT ONE LINE OF THE CURRENT SEGMENT
PICT.2:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	PUSH	P,T4			;SAVE T4
	TLNN	P2,-1			;MAKE SURE ITS A BYTE POINTER
	HRLI	P2,(POINT 7,0)		;MAKE IT ONE
	MOVE	T2,J$FWID(J)		;GET LINEWIDTH
	IDIV	T2,[EXP 7,^D14,^D21]-1(P1) ;AND DIVIDE BY CHARACTER SIZE
	MOVE	T4,T2			;SAVE MAX NUMBER OF CHARS/LINE

PICT.3:	ILDB	T2,P2			;GET A CHARACTER
	JUMPE	T2,PICT.6		;LAST CHARACTER, DONE
	CAIGE	T2,40			;MUST BE GREATER THEN ' '
	JRST	PICT.3			;ELSE GET THE NEXT CHAR
	MOVE	T1,CHRTAB-40(T2)	;GET THE WORD FROM THE TABLE
	ROT	T1,^D35(P3)		;POSITION TO CORRECT SEGMENT
	TLZ	T1,017777		;ZERO BITS FOR SPACE BETWEEN CHARS
	MOVE	T3,P2			;COPY POINTER TO TEXT
	ILDB	T3,T3			;GET FOLLOWING CHARACTER
	SKIPN	T3			;IF AT END OF STRING,
	SKIPA	T3,[5]			; DON'T NEED THE 2 SPACES
	MOVEI	T3,7			;PRINT 5 CHARS + 2 SPACES

PICT.4:	MOVEI	C," "			;LOAD A SPACE
	TLNE	T1,(1B0)		;SEE IF HIGH BIT IS ONE
	LDB	C,P2			;IT IS, GET THE CHARACTER
	CAIN	C,":"			;IS IT A COLON ???
	MOVEI	C,"#"			;MAKE IT A # SIGN.
	PUSHJ	P,PICT.5		;PRINT IT THE CORRECT NUMBER OF TIMES
	ROT	T1,1			;ROTATE WORD 1 BIT
	SOJG	T3,PICT.4		;AND LOOP THE CORRECT NUMBER OF TIMES
	SOJG	T4,PICT.3		;AND GET THE NEXT CHARACTER
	JRST	PICT.6			;NO MORE ROOM, DONE

PICT.5:	MOVE	T2,P1			;GET THE BLOCKSIZE
	PUSHJ	P,DEVOUT		;PRINT IT
	SOJG	T2,.-1			;LOOP
	POPJ	P,			;AND RETURN

PICT.6:	POP	P,T4			;RESTORE T4
	PJRST	CRLF			;TYPE A CR AND RETURN
CHRTAB:	BYTE (5) 00,00,00,00,00,00,00	;SP
	BYTE (5) 04,04,04,04,04,00,04	;!
	BYTE (5) 12,12,00,00,00,00,00	;"
	BYTE (5) 12,12,37,12,37,12,12	;#
	BYTE (5) 04,37,24,37,05,37,04	;$
	BYTE (5) 31,31,02,04,10,23,23	;%
	BYTE (5) 10,24,10,24,23,22,15	;&
	BYTE (5) 06,02,00,00,00,00,00	;'
	BYTE (5) 04,10,20,20,20,10,04	;(
	BYTE (5) 04,02,01,01,01,02,04	;)
	BYTE (5) 00,25,16,33,16,25,00	;*
	BYTE (5) 00,04,04,37,04,04,00	;+
	BYTE (5) 00,00,00,00,00,06,02	;,
	BYTE (5) 00,00,00,37,00,00,00	;-
	BYTE (5) 00,00,00,00,00,06,06	;.
	BYTE (5) 00,00,01,02,04,10,20	;/

	BYTE (5) 16,21,23,25,31,21,16	;0
	BYTE (5) 04,14,04,04,04,04,16	;1
	BYTE (5) 16,21,01,02,04,10,37	;2
	BYTE (5) 16,21,01,02,01,21,16	;3
	BYTE (5) 22,22,22,37,02,02,02	;4
	BYTE (5) 37,20,34,02,01,21,16	;5
	BYTE (5) 16,20,20,36,21,21,16	;6
	BYTE (5) 37,01,01,02,04,10,20	;7
	BYTE (5) 16,21,21,16,21,21,16	;8
	BYTE (5) 16,21,21,17,01,01,16	;9
	BYTE (5) 00,00,06,06,00,06,06	;:
	BYTE (5) 00,06,06,00,06,06,02	;;
	BYTE (5) 02,04,10,20,10,04,02	;<
	BYTE (5) 00,00,37,00,37,00,00	;=
	BYTE (5) 10,04,02,01,02,04,10	;>
	BYTE (5) 16,21,01,02,04,00,04	;?

	BYTE (5) 16,21,21,27,25,25,07	;@
	BYTE (5) 16,21,21,21,37,21,21	;A
	BYTE (5) 36,21,21,36,21,21,36	;B
	BYTE (5) 17,20,20,20,20,20,17	;C
	BYTE (5) 36,21,21,21,21,21,36	;D
	BYTE (5) 37,20,20,36,20,20,37	;E
	BYTE (5) 37,20,20,36,20,20,20	;F
	BYTE (5) 17,20,20,20,27,21,16	;G
	BYTE (5) 21,21,21,37,21,21,21	;H
	BYTE (5) 16,04,04,04,04,04,16	;I
	BYTE (5) 01,01,01,01,21,21,16	;J
	BYTE (5) 21,21,22,34,22,21,21	;K
	BYTE (5) 20,20,20,20,20,20,37	;L
	BYTE (5) 21,33,25,21,21,21,21	;M
	BYTE (5) 21,21,31,25,23,21,21	;N
	BYTE (5) 16,21,21,21,21,21,16	;O

	BYTE (5) 36,21,21,36,20,20,20	;P
	BYTE (5) 16,21,21,21,25,22,15	;Q
	BYTE (5) 36,21,21,36,24,22,21	;R
	BYTE (5) 17,20,20,16,01,01,36	;S
	BYTE (5) 37,04,04,04,04,04,04	;T
	BYTE (5) 21,21,21,21,21,21,37	;U
	BYTE (5) 21,21,21,21,21,12,04	;V
	BYTE (5) 21,21,21,21,25,33,21	;W
	BYTE (5) 21,21,12,04,12,21,21	;X
	BYTE (5) 21,21,12,04,04,04,04	;Y
	BYTE (5) 37,01,02,04,10,20,37	;Z
	BYTE (5) 14,10,10,10,10,10,14	;[
	BYTE (5) 00,00,20,10,04,02,01	;\
	BYTE (5) 06,02,02,02,02,02,06	;]
	BYTE (5) 04,12,21,00,00,00,00	;^
	BYTE (5) 00,00,00,00,00,00,37	;_

	BYTE (5) 14,10,00,00,00,00,00	;ACCENT GRAVE
	BYTE (5) 00,00,36,01,17,21,17	;LC A
	BYTE (5) 20,20,20,36,21,21,36	;LC B
	BYTE (5) 00,00,17,20,20,20,17	;LC C
	BYTE (5) 01,01,01,17,21,21,17	;LC D
	BYTE (5) 00,00,16,21,36,20,17	;LC E
	BYTE (5) 16,21,20,34,20,20,20	;LC F
	BYTE (5) 00,00,16,21,17,01,37	;LC G
	BYTE (5) 20,20,20,36,21,21,21	;LC H
	BYTE (5) 00,04,00,04,04,04,04	;LC I
	BYTE (5) 00,04,00,04,04,24,10	;LC J
	BYTE (5) 20,22,22,24,30,24,22	;LC K
	BYTE (5) 04,04,04,04,04,04,04	;LC L
	BYTE (5) 00,00,24,37,25,25,25	;LC M
	BYTE (5) 00,00,20,36,21,21,21	;LC N
	BYTE (5) 00,00,16,21,21,21,16	;LC O
	BYTE (5) 00,00,36,21,36,20,20	;LC P
	BYTE (5) 00,00,17,21,17,01,01	;LC Q
	BYTE (5) 00,00,26,31,20,20,20	;LC R
	BYTE (5) 00,00,17,20,16,01,36	;LC S
	BYTE (5) 00,10,34,10,10,10,06	;LC T
	BYTE (5) 00,00,21,21,21,21,16	;LC U
	BYTE (5) 00,00,21,21,12,12,04	;LC V
	BYTE (5) 00,00,21,21,25,25,12	;LC W
	BYTE (5) 00,00,21,12,04,12,21	;LC X
	BYTE (5) 00,00,21,12,04,04,30	;LC Y
	BYTE (5) 00,00,37,02,04,10,37	;LC Z

	BYTE (5) 04,10,10,20,10,10,04	;OPEN BRACE
	BYTE (5) 04,04,04,00,04,04,04	;VERTICAL BAR
	BYTE (5) 04,02,02,01,02,02,04	;CLOSE BRACE
	BYTE (5) 00,10,25,02,00,00,00	;TILDE
	BYTE (5) 00,00,00,00,00,00,00	;RUBOUT
SUBTTL	SYSTEM INITIALIZATION FUNCTIONS

TOPS10 <
OPDINI:	MOVEI	T3,4			;NUMBER OF WORDS IN SYSNAM - 1
	MOVS	T1,[%CNFG0]		;ADR OF FIRST WORD
GETSYN:	MOVS	T2,T1			;GET THE GETTAB ADR
	GETTAB	T2,			;GET THE WORD
	  JFCL				;IGNORE THIS
	MOVEM	T2,LPCNF(T1)		;SAVE NAME
	CAILE	T3,(T1)			;DONE?
	AOJA	T1,GETSYN		;NO, LOOP

	PUSHJ	P,I%HOST		;GET THE HOST NAME AND NUMBER
	MOVEM	S2,CNTSTA		;SAVE THE NUMBER
	MOVSI	S1,.STSPL		;ISSUE 'SETUUO' TO
	SETUUO	S1,			;   CLEAR SPOOLING BITS
	  JFCL				;IGNORE THE ERROR
	PJOB	S1,			;GET OUR JOB NUMBER
	MOVEM	S1,LPJOB		;SAVE IT
	MOVE	S1,[ASCII/D/]		;DEFAULT TO DETACHED
	MOVEM	S1,LPTRM		;SAVE THE DESIGNATOR
	GETLIN	S1,			;GET OUR TTY NUMBER
	TLNN	S1,-1			;ARE WE DEATCHED ???
	JRST	OPDI.1			;YES, SKIP THIS
	GTNTN.	S1,			;GET OUR LINE NUMBER
	 JRST	OPDI.1			;FAILED,,WE ARE DETACHED
	SETOM	S2			;GET A -1
	TRMNO.	S2,			;GET OUR TTY NUMBER
	 JRST	OPDI.1			;FAILED,,WE ARE DETACHED !!!
	GETLCH	S2			;GET OUR LINE CHARACTERISTICS
	MOVE	TF,[ASCII/T/]		;DEFAULT TO A TTY
	TXNE	S2,GL.ITY		;ARE WE A PTY ???
	MOVE	TF,[ASCII/P/]		;YES, MAKE US 'PTY'
	TXNE	S2,GL.CTY		;ARE WE THE CTY ???
	MOVE	TF,[ASCII/C/]		;YES, MAKE US 'CTY'
	MOVEM	TF,LPTRM		;SAVE THE TERMINAL DESIGNATOR
	HRRZM	S1,LPLNO		;SAVE THE LINE NUMBER
	JRST	OPDI.1			;CONTINUE
>  ;END TOPS10 CONDITIONAL

	;CONTINUED ON THE NEXT PAGE
	;CONTINUED FROM THE PREVIOUS PAGE


TOPS20 <
OPDINI:	PUSHJ	P,I%HOST		;GET THE HOST NAME
	MOVEM	S1,CNTSTA		;SAVE IT
	MOVX	S1,.MSIIC		;GET 'IGNORE STR ACCTING' FUNCTION
	MSTR				;WE WANT TO IGNORE STRUCTURE ACCOUNTING
	ERJMP	.+1			;IGNORE ANY ERROR
	MOVX	S1,'SYSVER'		;NAME OF GETTAB FOR SYSNAME
	SYSGT				;GET IT
	HRLZ	T1,S2			;GET TABLE#,,0
	MOVEI	T2,10			;AND LOAD LOOP COUNTER
GETSYN:	MOVS	S1,T1			;GET N,,TABLE#
	GETAB				;GET THE ENTRY
	  MOVEI	S1,0			;USE ZERO IF LOSING
	MOVEM	S1,LPCNF(T1)		;STORE THE RESULT
	CAILE	T2,(T1)			;DONE ENUF?
	AOJA	T1,GETSYN		;NO, LOOP

	MOVX	S1,RC%EMO		;EXACT MATCH
	HRROI	S2,[ASCIZ /PS:<SPOOL>/]	;DIRECTORY NAME
	RCDIR				;GET THE NUMBER
	MOVEM	T1,SPLDIR		;SAVE IT
>  ;END TOPS20 CONDITIONAL

OPDI.1:	SETZ	M,			;CLEAR MESSAGE ADDRESS
	MOVE	P1,DEVLST		;POINT TO START OF DEVICE DRIVER CHAIN

OPDI.2:	PUSHJ	P,@J$INIT-J$$DEV(P1)	;INITIALIZE
	SKIPE	P1,(P1)			;POINT TO NEXT DRIVER
	JRST	OPDI.2			;LOOP BACK
	SETZM	FMOPN			;CLEAR FORMS.INI OPEN FLAG
	$RETT				;AND RETURN

SUBTTL	Mount and dismount structures -- Entry point


; Here to mount and dismount structures for each file being processed.
; Call:	MOVE	S1, FD address
;	PUSHJ	P,STRMNT	;TO MOUNT
;	PUSHJ	P,STRDMO	;TO DISMOUNT
;
; Note:	Under TOPS-10, the number of structures that may be mounted is
;	limited to the size of a search list. It is conceivable that we
;	could be driving up to 15 devices. When a structure can't be
;	mounted, the operator will be notified.
;
STRMNT:	TDZA	TF,TF			;REMEMBER MOUNT ENTRY POINT
STRDMO:	MOVEI	TF,1			;REMEMBER DISMOUNT ENTRY POINT
TOPS20	<POPJ	P,>
TOPS10<
	$SAVE	<P1,P2>			;SAVE SOME ACS
	MOVE	P1,TF			;SAVE MOUNT/DISMOUNT FLAG
	PUSHJ	P,STRXTR		;EXTRACT THE STRUCTURE NAME
	MOVE	P2,S1			;SAVE FOR LATER
	MOVE	S1,[-STRLEN,,STRTAB]	;GET AOBJN POINTER TO STRUCTURE TABLE
	SETZ	S2,			;CLEAR EMPTY SLOT POINTER

STR.1:	CAMN	P2,0(S1)		;FOUND THE STR?
	JRST	@STRDSP(P1)		;DISPATCH
	SKIPN	0(S1)			;THIS ENTRY IN USE?
	SKIPE	S2			;NO - FOUND AN EMPTY SLOT YET?
	SKIPA				;DO NOTHING
	MOVE	S2,S1			;REMEMBER THE EMPTY SLOT
	ADD	S1,[1,,1]		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	S1,STR.1		;LOOP THROUGH STRUCTURE TABLE
	JRST	@STRDSP(P1)		;DISPATCH

STRDSP:	EXP	STRADD			;DISPATCH FOR MOUNT
	EXP	STRREM			;DISPATCH FOR DISMOUNT
SUBTTL	Mount and dismount structures -- Add and remove structures


; Add a structure to our search list
;
STRADD:	SKIPGE	S1			;AOBJN POINTER RUN OUT?
	CAME	P2,0(S1)		;ALREADY HAVE THIS STR MOUNTED?
	JRST	STRA.1			;NEED TO MAKE A NEW ENTRY
	AOS	1(S1)			;INCREMENT USE COUNT
	POPJ	P,			;AND RETURN CUZ IT'S ALREADY MOUNTED

STRA.1:	JUMPE	S2,STRERR		;CHECK FOR NO ROOM IN STRUCTURE TABLE
	MOVE	S1,S2			;GET ADDRESS OF EMPTY SLOT IN TABLE
	MOVEM	P2,0(S1)		;STASH STR NAME
	AOS	1(S1)			;GIVE IT A USE COUNT OF ONE
	PUSHJ	P,STRCHK		;CHECK EXISTANCE OF ALL STRS
	PJRST	STRJSL			;SET NEW JOB SEARCH LIST AND RETURN


; Remove a structure from our search list
;
STRREM:	SKIPGE	S1			;AOBJN POINTER RUN OUT?
	SOSE	1(S1)			;DECREMENT USE COUNT
	POPJ	P,			;STR STILL IN USE
	SETZM	0(S1)			;ZAP STR NAME
	PUSHJ	P,STRCHK		;CHECK EXISTANCE OF STRS
	PJRST	STRJSL			;SET NEW JOB SEARCH LIST AND RETURN
>
SUBTTL	Mount and dismount structures -- Extract structre from FD


; Extract a structure name from an FD
; Call:	MOVE	S1, FD address
;	PUSHJ	P,STRXTR
;
; On return, S1:= sixbit structure name
;
STRXTR:
TOPS10	<
	MOVE	S1,.FDSTR(S1)		;GET STRUCTURE NAME
	MOVEM	S1,DCHBLK+.DCNAM	;PUT IN DSKCHR BLOCK
	MOVE	S1,[.DCSNM+1,,DCHBLK]	;SET UP UUO
	DSKCHR	S1,			;GET THE DISK CHARACTERISTICS
	  SKIPA	S1,.FDSTR(S1)		;CAN'T - ASSUME IT'S OK
	MOVE	S1,DCHBLK+.DCSNM	;GET STRUCTURE NAME
	POPJ	P,			;AND RETURN
> ;END TOPS-10 CONDITIONAL

REPEAT 0,<
TOPS20	<
	HRROI	S1,.FDSTG(S1)		;MAKE IT -1,,ADDR
	$CALL	S%SIXB			;CONVERT ASCII TO SIXBIT
	MOVE	S1,S2			;GET THE NAME
	POPJ	P,			;RETURN
> ;END TOPS-20 CONDITIONAL
>
SUBTTL	Mount and dismount structures -- Check structure existance


; Check the existance of all structures in the structure table. This
; turns out to e cheaper and easier than reading our existing search list
; and then modifying it to accomodate our needs.
; Call:	PUSHJ	P,STRCHK
;
STRCHK:
TOPS10	<
	MOVE	S1,[-STRLEN,,STRTAB]	;GTE AOBJN POINTER

STRC.1:	HRRZ	S2,S1			;POINT TO STR NAME
	SKIPE	(S1)			;AVOID A UUO IF NO STR
	DSKCHR	S2,			;MAKE SURE IT'S STILL THERE
	  SKIPA				;LOSE
	JRST	STRC.2			;ONWARD
	SETZM	0(S1)			;ZAP STR NAME
	SETZM	1(S1)			;AND THE USE COUNT

STRC.2:	ADD	S1,[1,,1]		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	S1,STRC.1		;LOOP THROUGH TABLE
	POPJ	P,			;RETURN
> ; END TOPS-10 CONDITIONAL

TOPS20	<POPJ	P,>			;NO-OP FOR THE -20
SUBTTL	Mount and dismount structures -- Change job search list


; Here to build a new job search list
; Call:	PUSHJ	P,STRJSL
;
STRJSL:
TOPS10	<
	MOVEI	S1,.FSDSL		;GET FUNCTION CODE
	MOVEM	S1,STRBLK+.FSFCN	;SAVE IT
	SETOM	STRBLK+.FSDJN		;SET JOB NUMBER TO -1 (US)
	SETOM	STRBLK+.FSDPP		;SET PPN TO -1 (US)
	MOVEI	S1,DF.SRM		;GET A BIT
	MOVEM	S1,STRBLK+.FSDFL	;REMOVE STRS NOT IN NEW S/L
	MOVE	S1,[-STRLEN,,STRTAB]	;GTE AOBJN POINTER
	MOVEI	S2,STRBLK+.FSDSO	;POINT TO FIRST FREE WORD

STRJ.1:	MOVE	TF,0(S1)		;GET A STR NAME
	JUMPE	TF,STRJ.2		;SKIP EMPTY SLOTS
	MOVEM	TF,.DFJNM(S2)		;SAVE IT
	SETZM	.DFJDR(S2)		;CLEAR DIRECTORY
	SETZM	.DFJST(S2)		;NO SPECIAL STATUS BITS
	ADDI	S2,.DFJBL		;POINT TO NEXT FREE ENTRY

STRJ.2:	ADD	S1,[1,,1]		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	S1,STRJ.1		;LOOP
	SETOM	.DFJNM(S2)		;MARK THE FENCE
	SUBI	S2,STRBLK		;COMPUTE LENGTH OF S/L BLOCK
	HRLI	S2,STRBLK		;POINT TO S/L BLOCK
	MOVSS	S2			;MAKE IT -LEN,,ADDR
	STRUUO	S2,			;DEFINE OUR NEW S/L
	  JRST	STRERR			;CAN'T
	POPJ	P,			;RETURN
> ;END OF TOPS-10 CONDITIONAL

REPEAT 0,<
TOPS20	<
	MOVEM	P2,STRBLK		;SAVE STR NAME
	SETZM	STRBLK+1		;TERMINATE IT
	MOVE	S1,[POINT 6,STRBLK]	;BYTE POINTER TO SIXBIT STR NAME
	HRROI	S2,STRBLK+3		;GET -1,,ADDRESS
	MOVEM	S2,STRBLK+2		;SAVE IT
	MOVE	S2,[POINT 7,STRBLK+3]	;BYTE POINTER TO ASCIZ STR NAME

STRJ.1:	ILDB	TF,S1			;GET A CHARACTER
	SKIPE	TF			;END?
	ADDI	TF," "			;CONVERT SIXBIT TO ASCII
	IDPB	TF,S2			;PUT A CHARACTR
	JUMPN	TF,STRJ.1		;LOOP
	MOVE	S1,[1,,.MSIMC		;MOUNT FUNCTION
		    1,,.MSDMC](P1)	;DISMOUNT FUNCTION
	MOVEI	S2,STRBLK+2		;POINT TO ASCIZ STR NAME
	MSTR				;CHANGE THE MOUNT COUNT
	  ERJMP	STRERR			;CAN'T
	POPJ	P,			;RETURN
> ;END OF TOPS-20 CONDITIONAL
>
; Here on all STRUUO errors
; We'll try to correct our database so we don't get out of
; synch with the real world. If we ever get here, there's
; a good chance the monitor is F@#$%ed up anyway, so maybe
; it's not so important...
;
STRERR:	MOVE	S1,[[ASCIZ |mount|]	;ASSUME MOUNTING
		    [ASCIZ |dismount|]](P1) ;GET CORRECT TEXT
	$WTO	(<LPTSPL error>,<Cannot ^T/(S1)/ structure ^W/P2/>,,$WTFLG(WT.SJI))
	JUMPN	P1,.POPJ		;RETURN IF A DISMOUNT
	MOVE	S1,[-STRLEN,,STRTAB]	;GET AOBJN POINTER TO STRUCTURE TABLE

STRE.1:	CAME	P2,0(S1)		;[3003] FOUND THE STR?
	JRST	STRE.2			;NOPE
	SOSN	1(S1)			;DECREMENT USE COUNT
	SETZM	0(S1)			;ZAP STR NAME IF COUNT = ZERO
	POPJ	P,			;RETURN

STRE.2:	ADD	S1,[1,,1]		;ACCOUNT FOR TWO WORD ENTRIES
	AOBJN	S1,STRE.1		;LOOP THROUGH TABLE
	POPJ	P,			;REALLY SICK
SUBTTL	Interrupt Module

;		INTINI		INITIALIZE INTERRUPT SYSTEM
;		INTON		ENABLE INTERRUPTS
;		INTOFF		DISABLE INTERRUPTS
;		INTCNL		CONNECT THE LINEPRINTER
;		INTDCL		DISCONNECT THE LINEPRINTER
;		INTIPC		INTERRUPT ROUTINE  --  IPCF
;		INTDEV		INTERRUPT ROUTINE  --  LPT OFF-LINE


SUBTTL	INTERRUPT SYSTEM DATABASE

TOPS10 <

VECTOR:	BLOCK	0			;BEGINNING OF INTERRUPT VECTOR
VECIPC:	BLOCK	4			;IPCF INTERRUPT BLOCK
VECDEV:	BLOCK	4*NPRINT		;DEVICE INTERRUPT BLK
	ENDVEC==.-1			;END OF INTERRUPT VECTOR

>  ;END TOPS10 CONDITIONAL

TOPS20 <

LEVTAB:	EXP	LEV1PC			;WHERE TO STORE LEVEL 1 INT PC
	EXP	LEV2PC			;WHERE TO STORE LEVEL 2 INT PC
	EXP	LEV3PC			;WHERE TO STORE LEVEL 3 INT PC

CHNTAB:	XWD	1,INTIPC		;IPCF INT - LEVEL 1
	XWD	1,INTDEV		;DEV OFF LINE INT - LEVEL 1
	BLOCK	^D34			;RESTORE OF THE TABLE

LEV1PC:	BLOCK	1			;LVL 1 INTERRUPT PC STORED HERE
LEV2PC:	BLOCK	1			;LVL 2 INTERRUPT PC STORED HERE
LEV3PC:	BLOCK	1			;LVL 3 INTERRUPT PC STORED HERE
>  ;END TOPS20 CONDITIONAL


TOPS10 <
DEFINE LPINHD(Z),<
	XLIST
	$BGINT	1,
	MOVEI	S1,Z
	MOVEI	S2,VECDEV+<4*Z>
	JRST	LPINTR
	LPHDSZ==4
	LIST
>  ;END DEFINE LPINHD
>  ;END TOPS10 CONDITIONAL
TOPS10 <
INTINI:	MOVEI	S1,INTIPC		;GET ADDRESS OF IPCF INT RTN
	MOVEM	S1,VECIPC+.PSVNP	;SAVE IN VECTOR

	ZZ==0
REPEAT	NPRINT,<
	MOVEI	S1,INTDEV+<LPHDSZ*ZZ>	;GET ADDRESS OF LPT HEADER
	MOVEM	S1,VECDEV+<4*ZZ>+.PSVNP	;STORE IN THE VECTOR
	ZZ==ZZ+1
>  ;END REPEAT NPRINT

	POPJ	P,			;AND RETURN
>  ;END TOPS10 CONDITIONAL


TOPS20 <
INTINI:	MOVX	S1,.FHSLF		;LOAD MY FORK HANDLE
	MOVX	S2,1B0!1B1		;CHANNELS 0 AND 1
	AIC				;ACTIVATE THE CHANNELS
	POPJ	P,			;AND RETURN
>  ;END TOPS20 CONDITIONAL
TOPS10 <

INTDCL::SKIPA	S1,[PS.FRC+T1]		;REMOVE CONDITION USINGS ARGS IN T1
INTCNL::MOVX	S1,PS.FAC+T1		;ADD CONDITION USING ARGS IN T1
	MOVE	T1,J$LCHN(J)		;USE CHANNEL AS CONDTION
	MOVE	T2,STREAM		;GET STREAM NUMBER
	IMULI	T2,4			;GET BLOCK OFFSET
	ADDI	T2,VECDEV-VECTOR	;GET OFFSET FROM BEGINNING
	HRLZS	T2			;GET OFFSET,,0
	HRRI	T2,PS.RDO+PS.ROD+PS.ROL+PS.RDH ;AND CONDITIONS
	SETZ	T3,			;ZERO T3
	PISYS.	S1,			;TO THE INTERRUPT SYSTEM
	 $RETF				;WE FAILED !!!
	$RETT				;RETURN OK.
>  ;END TOPS10 CONDITIONAL

TOPS20 <
INTCNL:	MOVE	S1,J$LCHN(J)		;GET THE LPT JFN
	MOVX	S2,.MOPSI		;GET MTOPR FUNCTION
	MOVEI	T1,T2			;AND ADDRESS OF ARGS
	MOVEI	T2,3			;1ST ARG IS # ARGS
	MOVEI	T3,1			;2ND ARG IS INT CHANNEL NUMBER
	MOVX	T4,MO%MSG		;DON'T TYPE THE MESSAGE
	PUSHJ	P,$MTOPR		;CONNECT IT
	 JUMPF	.RETF			;IF AN ERROR,,RETURN ERROR
	$RETT				;ELSE RETURN OK
>  ;END TOPS20 CONDITIONAL


	;INTERRUPT ROUTINES

INTIPC:	$BGINT	1,			;SETUP FOR THE INTERRUPT.
	PUSHJ	P,C%INTR		;FLAG THE INTERRUPT.

TOPS10 <
	$DEBRK				;DISMISS THE INTERRUPT.
>  ;END TOPS10 CONDITIONAL

TOPS20 <
	SKIPN	J,JOBPAG		;DOES A STREAM EXIST ??
	$DEBRK				;NO, JUST FINISH UP HERE.
	JRST	INTDON			;FINISH UP -20 INTERRUPT PROCESSING.
>  ;END TOPS20 CONDITIONAL
;Here on device interrupts on the -10.  This routine consists of multiple
;	interrupt headers (one for each stream) which load S1 and S2 and
;	call the main interrupt body, LPINTR.  Note that on the -10, while
;	it is assumed that 'output done' and 'on-line' interrupts can happen
;	anytime and anywhere, it is also assumed that 'device off-line'
;	interrupts ONLY HAPPEN IN THE STREAM CONTEXT.

TOPS10 <
INTDEV:	ZZ==0
	REPEAT NPRINT,<
	LPINHD(ZZ)
	ZZ==ZZ+1 	      >

LPINTR:	MOVE	J,JOBPAG(S1)		;GET THE JOB PARAMETER PAGE
	HRRZ	T1,.PSVFL(S2)		;GET I/O REASON FLAGS
	ANDCAM	T1,.PSVFL(S2)		;AND CLEAR THEM
	SETZ	T2,			;CLEAR AN AC
	TXNE	T1,PS.ROL+PS.RDO	;IS IT DEVICE ONLINE OR OFFLINE ???
	JRST	[SETZM	JOBCHK(S1)	;YES, SAY WE WANT A CHECKPOINT
		SETOM	JOBUPD(S1)	;  update the status also
		JRST	LPIN.1]		;Go continue
LPIN.1:	TXNE	T1,PS.RDH		;DEVICE HUNG?
	JRST	LPIN.3			;YES
	TXNE	T1,PS.ROL		;IS IT ON-LINE?
;**;[3007] Change code at LPIN.1+3L
	JRST	[MOVX	T2,PSF%DO+PSF%OB ;YES, CLEAR ON-LINE & OUTPUT-BLOCKED
		 SETZM	J$LBCT(J)	;[3007] MAKE SURE WE DON'T USE BUFFER
		 JRST	.+1]		;[3007] CONTINUE
	TXNE	T1,PS.ROD		;IS IT OUTPUT DONE?
	TXO	T2,PSF%OB		;YES, GET SCHEDULER BIT
	ANDCAM	T2,JOBSTW(S1)		;CLEAR THE SCHEDULER FLAGS
	TXNN	T1,PS.RDO		;IS IT DEVICE OFF-LINE?
	$DEBRK				;NO, DISMISS THE INTERRUPT.
	TXNE	T1,PS.ROL		;IF BOTH OFFLINE AND ONLINE,
	$DEBRK				;DISMISS THE INTERRUPT.
	MOVX	T2,PSF%DO		;GET OFF-LINE BIT.
	IORM	T2,JOBSTW(S1)		;   AND SET IT.
	MOVE	T2,.PSVIS(S2)		;[3005] GET THE FILE STATUS BITS
	TXC	T2,IO.ERR		;[3005] CHECK TO SEE IF ALL ERROR BITS ARE LIT
	TXNN	T2,IO.ERR		;[3005] ARE THEY ???
	SKIPL	J$LREM(J)		;YES, IS THIS A REMOTE LPT ???
	SKIPA				;NOT ALL BITS LIT OR NOT REMOTE,,SKIP
	$DEBRK				;ELSE REMOTE WENT DOWN,,RETURN NOW !!!
	TXC	T1,PS.RIE!PS.ROE!PS.RDO	;[3005] JUST THE ONES WE WANT
	TXNN	T1,PS.RIE!PS.ROE!PS.RDO	;[3005] CPU CROAK OR JUST LPT OFF-LINE?
	JRST	LPIN.2			;DEAD CPU
	MOVEI	T1,OUTWON		;LPT OFFLINE,,LOAD RESTART ADDR
	EXCH	T1,.PSVOP(S2)		;STORE FOR DEBRK AND GET OLD ADRESS
;**;[3013] Insert 2 lines and change 1 line after LPIN.1+25L. /LWS
	MOVE	T2,STREAM		;[3013] GET ACTIVE STREAM
	MOVE	T2,JOBPAG(T2)		;[3013] GET JOB PAGE ADDR OF ACTIVE STREAM
	MOVEM	T1,J$LIOA(T2)		;[3013] STORE OLD-ADDRESS FOR DEVICE ON AGAIN
	$DEBRK				;DISMISS THE INTERRUPT

;**;[3001] Rework CPU failure and hung device interrupt code.  /LWS
LPIN.2:	SKIPA	T2,[CPUFAI]		;[3001] GET ROUTINE ADDR FOR CPU FAILURE

LPIN.3:	MOVEI	T2,HNGDEV		;[3001] GET ROUTINE ADDR FOR HUNG DEVICE
;**;[2776] Change 1 line at LPTIN.3+0L. 21-Dec-83 /LWS
	SETZM	JOBSTW(S1)		;MAKE JOB RUNABLE
	MOVE	T1,J$RACS+P(J)		;GET STREAM STACK
	PUSH	T1,T2			;[3001] AVOID RACES,,T2 HAS ROUTINE ADDR
	MOVEM	T1,J$RACS+P(J)		;REPLACE PDL POINTER
	CAMN	S1,STREAM		;HUNG DEVICE IN STREAM CONTEXT?
	MOVEM	T2,.PSVOP(S2)		;[3001] SET RETURN ADDRESS
	$DEBRK				;DISMISS THE INTERRUPT
>  ;END TOPS10 CONDITIONAL
SUBTTL	CPU failure and Hung device code


TOPS10	<
CPUFAI:	TDZA	P2,P2			;INDICATE CPU FAILURE
HNGDEV:	MOVEI	P2,1			;INDICATE HUNG DEVICE
	MOVE	P1,STREAM		;GET THE STREAM NUMBER
	MOVE	J,JOBPAG(P1)		;SET UP JOB DATA BASE RELOCATION
	MOVE	S,J$RACS+S(J)		;GET THE STREAM STATUS BITS.
	TXO	S,GOODBY!RQB!ABORT	;ON OUR WAY OUT
	MOVEM	S,J$RACS+S(J)		;UPDATE FLAGS
	MOVE	S1,[[ASCIZ |CPU failure|]
		    [ASCIZ |Hung device|]](P2) ;GET TEXT
	$WTO	(<^T/(S1)/; job requeued>,<^R/.EQJBB(J)/>,@JOBOBA(P1))

HNGD.1:	MOVNI	S1,2			;LOAD -2
	ADDM	S1,J$RNPP(J)		;INSURE NO LOSSAGE OF DATA
	ADDM	S1,J$APRT(J)		;HERE ALSO
	SKIPGE	J$RNPP(J)		;MAKE SURE WE DIDN'T SCREW THINGS UP
	SETZM	J$RNPP(J)		;YES, ZERO THE PAGES PER COPY
	SKIPGE	J$APRT(J)		;CHECK HERE ALSO
	SETZM	J$APRT(J)		;NO GOOD, SET IT TO ZERO

HNGD.2:	SKIPE	S1,J$DIFN(J)		;GET IFN
	PUSHJ	P,F%REL			;CLOSE FILE
	SETZM	J$DIFN(J)		;CLEAR IT
	MOVEM	S,J$RACS+S(J)		;SAVE UPDATED AC 'S'
	SETZM	JOBACT(P1)		;MAKE JOB RUNABLE
	PUSHJ	P,QRELEASE 		;RELEASE THE REQUEST
	MOVX	S1,%RSUDE		;GET NON-EXISTANT DEVICE CODE
	PUSHJ	P,RSETUP		;TELL QUASAR WE'RE DONE
	PJRST	SHUTIN			;SHUT DOWN AND RETURN TO SCHEDULER
> ;END TOPS10 CONDITIONAL
SUBTTL	STARS - Job definition/separation line definitions


STARS::	POINT	7,STARS1		;LINE 1
	POINT	7,STARS2		;LINE 2
	POINT	7,STARS3		;LINE 3


;**;[2770]CHANGE 3 LINES AFTER STARS1:	15-FEB-83/CTK
STARS1:	ASCII	/000000000000000000000000000000000000000000000000000000000000/
	ASCII	/000000000000000000000000000000000000000111111111111111111111/
	ASCII	/111111111111/		;[2770]

STARS2:	ASCII	/000000000111111111122222222223333333333444444444455555555556/
	ASCII	/666666666777777777788888888889999999999000000000011111111112/
	ASCII	/222222222333/		;[2770]

STARS3:	ASCII	/123456789012345678901234567890123456789012345678901234567890/
	ASCII	/123456789012345678901234567890123456789012345678901234567890/
	ASCII	/123456789012/		;[2770]
LPTEND::PRGEND	LPTSPL
TITLE	LPTVFU - LP20 VFU and RAM Simulator for LPTSPL-10
SUBTTL	T. Litt/TL	30-Dec-85

;
;
;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1985,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	GLXMAC			;SEARCH GALAXY PARAMETERS
	SEARCH	QSRMAC			;SEARCH QUASAR PARAMETERS
	SEARCH	ORNMAC			;SEARCH ORION/OPR PARAMETERS
	SEARCH	LPTMAC			;SEARCH LPTSPL PARAMETERS
	PROLOG	(LPTVFU)

IF2,<PRINTX Assembling GALAXY-10 LPTVFU>


	SALL				;FOR CLEAN LISTINGS
	.DIRECT	FLBLST			;FOR CLEANER LISTINGS

LPTVFU:	ENTRY	LPTVFU			;LOAD IF LIBRARY SEARCH
SUBTTL	VFUINX - VFU Simulator Initialization


; Device initialization.  This routine is called by the
; Device driver's initialization routine (xxxINX).  Ordinarily, 
; the driver can PJRST here instead of returning %RSUOK.
;
; Call:	MOVE	J, job data base address
;	MOVE	M, Page containing SETUP message or 0 if LPTSPL startup
;	PUSHJ	P,VFUINX
;
; TRUE return:	Initialization complete
; FALSE return:	Never

	ENTRY	VFUINX
VFUINX::JUMPE	M,.RETT			;RETURN IF LPTSPL INITIALIZATION
	SETOM	J$FFDF(J)		;VFU Simulator DOES FORM FEEDS
	SETOM	J$DC3F(J)		;VFU Simulator DOES DC3S
	SETOM	J$MNTF(J)		;VFU Simulator SUPPORTS MOUNTABLE FORMS
	MOVEI	S1,%RSUOK		;LOAD THE CODE
	$RETT				;RETURN
SUBTTL	VFUOPX - OPEN device

; This routine will setup device specific information for an OPEN.
; This routine is called by the Device Driver's xxxOPX routine to
; setup the VFU database for an OPEN.
;
; Call:	MOVE	J, job data base address
;	PUSHJ	P,VFUOPX
;
; TRUE return:	Always
; FALSE return:	Never

	ENTRY	VFUOPX
VFUOPX::MOVE	S1,[SIXBIT /LP64/]	;DEFAULT THE RAM TO 64 CHARACTERS
	SKIPE	J$LLCL(J)		;UNLESS ITS LOWER CASE
	MOVE	S1,[SIXBIT/LP96/]	;THEN DEFAULT TO 96 CHARACTER SET
	MOVEM	S1,J$LRAM(J)		;SAVE THE DEFAULT RAM FILE NAME
	MOVE	S1,D$TAPE##		;GET THE DEFAULT VFU TYPE.
	SKIPN	J$FTAP(J)		;HAS THE VFU ALREADY BEEN DEFAULTED ???
	MOVEM	S1,J$FTAP(J)		;NO, SAVE AS THE VFU DEFAULT.
	SETOM	J$LDVF(J)		;OUR VFU IS ALWAYS LOADABLE
	SETOM	J$LDRM(J)		;AND SO IS OUR RAM
	$RETT
SUBTTL	VFUFVU - Load VFU

; This routine is called to load the VFU for a printer.
; 
; This routine is called by the Device Driver's xxxVFU routine.
; Ordinarily, the device driver routine consists only of a PJRST.
;
; Call:	MOVE	J, job data base address
;	MOVEI	S1,function
;	PUSHJ	P,VFUVFU
;
; TRUE return:	VFU loaded or no VFU needed, C/ LP20 START CODE OF LOADED VFU
; FALSE return:	VFU load failed, error code in S1

	ENTRY	VFUVFU
VFUVFU::JRST	@[IFIW	CHKVFU		;(0) CHECK VFU STATUS
		  IFIW	LODVFU		;(1) LOAD VFU
		  IFIW	.RETT](S1)	;(2) OUTPUT ERROR DURING LOAD

LODVFU:	HLLZS	J$VLIN(J)		;RELOADING VFU SETS IT TO LINE 0
	MOVE	S1,J$FTAP(J)		;GET FILENAME
	STORE	S1,VFUFD+.FDNAM		;AND STORE IN THE FD
	MOVEI	S1,FOB.SZ		;GET THE FOB SIZE
	MOVEI	S2,FOB##		;AND FOB ADDRESS
	PUSHJ	P,.ZCHNK		;AND ZERO IT
	MOVEI	S1,VFUFD		;GET FD ADDRESS
	STORE	S1,FOB##+FOB.FD		;STORE
	MOVEI	S1,7			;GET 7 BIT BYTE SIZE
	STORE	S1,FOB##+FOB.CW,FB.BSZ	;AND STORE
	MOVEI	S1,FOB.SZ		;GET FOB SIZE
	MOVEI	S2,FOB##		;AND FOB ADDRESS
	PUSHJ	P,F%IOPN		;SETUP TO READ IT
	 JUMPF	HDWVF0			;FILE NOT FOUND, TRY HARDWARE VFU
	MOVEM	S1,J$FVIF(J)		;ELSE,,SAVE THE IFN
	MOVEI	S1,V$$LEN		;SIZE OF A VFU
	SKIPE	S2,J$VVFU(J)		;ADDRESS
	 $CALL	M%RMEM			;GET RID OF IT
	SETZM	J$VVFU(J)
	MOVE	S1,J$FVIF(J)		;GET THE IFN
	MOVX	S2,FI.SIZ		;FILE SIZE
	$CALL	F%INFO
	CAILE	S1,<V$$LEN-V$DATA>*5	;BETTER FIT
	 JRST	HDWVFU			;OOPS.
	MOVX	S1,V$$LEN		;ALLOCATE FOR THE MAX
	$CALL	M%GMEM			;ALLOCATE SPACE FOR THE VFU
	MOVEM	S2,J$VVFU(J)		;REMEMBER IT
	MOVE	S1,STDVFU+V$PTR		;GET A STANDARD POINTER
	ADDI	S1,-<STDVFU>(S2)	;RELOCATE ADDRESS
	MOVEM	S1,V$PTR(S2)		;SAVE BYTE POINTER TO VFU
	PUSH	P,S1			;HM

VFU.4:	SOSGE	J$FBYT(J)		;CHECK AND SEE IF DATA IS IN BUFFER.
	 JRST	VFU.6			;IF NOT, GET NEXT BUFFER.
	ILDB	C,J$FPTR(J)		;PICK UP A BYTE.
	DPB	C,(P)			;SAVE A BYTE
	IBP	(P)
	JRST	VFU.4			;GO GET ANOTHER.

VFU.6:	MOVE	S1,J$FVIF(J)		;GET VFU IFN.
	PUSHJ	P,F%IBUF		;GET ANOTHER BUFFER.
	 JUMPF	VFU.5			;IF NO MORE,,RETURN
	MOVEM	S1,J$FBYT(J)		;SAVE THE BYTE COUNT
	MOVEM	S2,J$FPTR(J)		;SAVE THE BYTE POINTER.
	JRST	VFU.4			;CONTINUE PROCESSING.

VFUFD:	$BUILD	FDMSIZ
	 $SET(.FDLEN,FD.LEN,VFUFDL)	;FD LENGTH
	 $SET(.FDEXT,,<SIXBIT/VFU/>)	;FILENAME EXTENSION
	 $SET(.FDSTR,,<SIXBIT/SYS/>)	;FILE STRUCTURE
	$EOB

	VFUFDL==.-VFUFD			;FD LENGTH
	;HERE IF VFU FILE IS NOT AROUND, TRY TO RECOVER BY LOADING THE
	;HARDWARE VFU
HDWVFU:	MOVE	S1,J$FVIF(J)		;GET IFN OF VFU FILE
	PUSHJ	P,F%REL			;RELEASE FILE

HDWVF0:	MOVEI	S1,V$$LEN		;SIZE OF A VFU
	SKIPE	S2,J$VVFU(J)		;ADDRESS
	 $CALL	M%RMEM			;GET RID OF IT
	SETZM	J$VVFU(J)
	MOVE	T1,J$FTAP(J)		;TYPE WE TRIED TO LOAD
	 CAMN	T1,D$TAPE##		;IS IT THE DEFAULT
VFUHVL:	TDZA	S1,S1			;HARDWARE VFU LOADED INSTEAD
VFUFAI:	 MOVEI	S1,1			;VFU LOAD FAILED
	$RETF
VFU.5:	ADJSP	P,-1			;BYE (TE) POINTER

	;CHECK FOR VALID STOP CODE AND LENGTH??

	MOVE	T1,J$VVFU(J)		;GET ADDRESS OF OUR NEW VFU
	LDB	C,V$PTR(T1)		;FETCH THE FIRST BYTE
	CAIN	C,25			;IF SIMPLE START
	 MOVEI	C,356			;CONVERT TO LP20 SIMPLE START
	CAIN	C,356			;IF SIMPLE START
	 JRST	VFU.5A			;IT'S VALID
	
	CAIN	C,26			;6-LPI START?
	 MOVEI	C,354			;YES, MAKE LP20
	CAIN	C,27			;8-LPI START?
	 MOVEI	C,355			;YES, MAKE LP20

	 CAIE	C,354			;6-LPI?
	CAIN	C,355			;8-LPI?
	 CAIA				;VALID START CODE
	PJRST	HDWVFU			;INVALID START CODE

VFU.5A:	MOVE	S1,J$FVIF(J)		;GET VFU'S IFN
	$CALL	F%REL			;RELEASE THE FILE
	$RETT				;OK,,JUST RETURN

CHKVFU:	SKIPN	J$VVFU(J)		;IS VFU LOADED?
	 $RETF				;NO
	$RETT				;YES
SUBTTL	VFURAM - Load RAM


; This routine is called to load the character translation
; RAM for a printer.  This routine is called from the 
; Device driver's xxxRAM routine, which ordinarily consists only
; of a PJRST.

;
; Call:	MOVE	J, job data base address
;	PUSHJ	P,VFURAM
;
; TRUE return:	RAM loaded or no RAM needed
; FALSE return:	RAM load failed

	ENTRY	VFURAM
VFURAM::OPEN	17,RAMFOB		;OPEN THE STRUCTURE
	  JRST	NORAM			;CANT,TRY SOMETHING ELSE
	MOVE	S1,J$FRAM(J)		;GET THE RAM WE WANT
	MOVEM	S1,RLKUP+0		;SAVE IN THE LOOKUP BLOCK
	MOVSI	S1,'RAM'		;GET THE EXTENSION
	MOVEM	S1,RLKUP+1		;SAVE IN THE LOOKUP BLOCK
	SETZM	RLKUP+2			;CLEAR 3'RD WORD OF LOOKUP BLOCK
	SETZM	RLKUP+3			;CLEAR 4'TH WORD OF LOOKUP BLOCK
	SETO	T2,			;FLAG FOR RAM.2 SAYING "FAILED"
	LOOKUP	17,RLKUP		;FIND THE FILE WE WANT
	  JRST	RAM.2			;NOT THERE,,TRY SOMETHING ELSE
	MOVEI	S1,R$$LEN		;SIZE OF A RAM
	SKIPE	S2,J$VRAM(J)		;ADDRESS
	 $CALL	M%RMEM			;GET RID OF IT
	SETZM	J$VRAM(J)
	HLRO	T3,RLKUP+3		;GET -FILE LENGTH
	MOVMS	T3			;WANT POSITIVE LENGTH
	SETOM	T1,			;IF FAIL, WE NEED OPR ACTION
	CAILE	T3,R$$LEN		;BETTER FIT
	 JRST	RAM.2			;OOPS.
	MOVEI	S1,R$$LEN		;ALLOCATE FOR THE MAX
	$CALL	M%GMEM			;ALLOCATE SPACE FOR THE RAM
	MOVEM	S2,J$VRAM(J)		;REMEMBER IT
	MOVE	S1,LP64RM+R$PTR		;GET A STANDARD POINTER
	ADDI	S1,-<LP64RM>(S2)	;RELOCATE ADDRESS
	MOVEM	S1,R$PTR(S2)		;SETUP POINTER
	MOVEI	T1,R$DATA-1(S2)		;GET BUFFER ADDRESS-1
	HLL	T1,RLKUP+3		;GET -FILE LENGTH,,BUFFER ADDR-1
	SETZM	T2			;END CCW
	IN	17,T1			;READ THE RAM FILE
	TDZA	S2,S2			;CONTINUE ON SUCCESSFUL RETURN

RAM.1:	  SETOM	S2			;INDICATE RAM LOAD ERROR
	MOVE	T1,S2			;SAVE THE RAM LOAD FLAG
	JUMPE	S2,RAM.2		;JUMP IF LOADED OK
	MOVEI	S1,R$$LEN		;SIZE OF BUFFER
	SETZ	S2,			;IT'S (TO BE) GONE
	EXCH	S2,J$VRAM(J)		;BYE
	$CALL	M%RMEM			;DEALLOCATE BUFFER
	SETZM	J$VRAM(J)
	PUSHJ	P,RAM.2			;DEASSIGN THE STUFF
	SETZ	S1,			;RAM LOAD FAILED, HDW RAM LOADED
	$RETF

RAM.2:	MOVEI	S1,17			;GET OUR CHANNEL NUMBER
	RESDV.	S1,			;WIPE IT OUT
	  JFCL				;IGNORE ANY ERROR RELEASING THE DEVICE
	JUMPN	T1,NORAM		;IF AN ERROR, GO TRY SOMETHING ELSE
	$RETT				;AND RETURN

NORAM:	MOVEI	S1,1			;RAM LOAD FAILED, OPR ACTION
	$RETF

RAMFOB:	.IODMP				;DUMP MODE I/O
	SIXBIT/SYS/			;FILE ON SYS:
	0,,0				;DUMP MODE (NO BUFFERS)

RLKUP:	BLOCK	4			;LOOKUP BLOCK
SUBTTL	VFUOER - Output error processing


; This routine provides for driver or device-specific I/O error
; processing.  This routine is called by a device driver's xxxOER entry, 
; which may consist solely of a PJRST.  
;
; Call:	MOVE	S1,J$LIOS(J)	;Justed updated with physical GETSTS
;	MOVE	S2,J$XIOS(J)	;Just updated with physical DEVOP.
;	PUSHJ	P,VFUOER
;

	ENTRY	VFUOER
VFUOER::MOVX	S1,VF.UDC		;UNDEFINED CHARACTER PENDING?
	TDNN	S1,J$VFLG(J)		; ...
	 JRST	VFUOE1			;NO - PROCEED NORMALLY
	ANDCAM	S1,J$VFLG(J)		;WELL, WE ARE HANDLING IT NOW
	PUSHJ	P,SETUDC		;SETUP FOR ERROR
	JRST	VFUOE2			;ONLY HANDLE ONE AT A TIME

VFUOE1:	MOVX	S1,VF.PCZ		;PAGE COUNTER INTERRUPT?
	TDNN	S1,J$VFLG(J)		; ...
	 JRST	VFUOE2			;NO - PROCEED NORMALLY
	ANDCAM	S1,J$VFLG(J)		;HANDLING IT NOW
	PUSHJ	P,SETPLE		;SETUP FOR ERROR

VFUOE2:	MOVE	S1,J$LIOS(J)		;GET THE NEW IOS FOR CALLER
	MOVE	S2,J$XIOS(J)		;AND THE XIOS
	$RETT

SETUDC:	SKIPA	S1,[IOUNC%]		;THE DEVOP. ERROR
SETPLE:	 MOVX	S1,IOPLE%		;THE DEVOP. ERROR
SETDVP:	MOVEM	S1,J$XIOS(J)		;A PSEUDO-DEVOP. ERROR
	MOVX	S1,IO.ERR		;SET ALL THE ERROR BITS
	IORM	S1,J$LIOS(J)		;FOR LPFOOL TO SEE LATER
	POPJ	P,
SUBTTL	VFUSHT - Stream shutdown


; This routine is called when a stream is shutdown, just
; prior to releasing the job data page.  This routine is called by device 
; driver's xxxSHT entry point.
;
; Call:	MOVE	J, job data base address
;	PUSHJ	P,VFUSHT
;
; TRUE return:	Always
; FALSE return:	Never

	ENTRY	VFUSHT
VFUSHT::MOVEI	S1,V$$LEN		;SIZE OF A VFU
	SKIPE	S2,J$VVFU(J)		;ADDRESS
	 $CALL	M%RMEM			;GET RID OF IT
	SETZM	J$VVFU(J)
	MOVEI	S1,R$$LEN		;SIZE OF A RAM
	SKIPE	S2,J$VRAM(J)		;ADDRESS
	 $CALL	M%RMEM			;GET RID OF IT
	SETZM	J$VRAM(J)
	$RETT				;RETURN
SUBTTL	VFUCHO - Character translator


; This routine will handle character translation.  Called when a character
; is about to be sent to what everyone else thinks is the physical device.
; It simulates a hardware translation RAM, activating the imaginary VFU 
; as necessary.  Called by the device driver's xxxCHO routine, which may
; simply PJRST here.
;
; Call:	MOVE	J, job data base address
;	MOVE	C, intercepted character
;	PUSHJ	P,VFUCHO
; TRUE return:	Character translated if necessary, caller to output
; FALSE return:	Character processed here, nothing to output

	ENTRY	VFUCHO
VFUCHO::PUSHJ	P,.SAVET		;SAFER THAN SORRY

	SKIPN	T2,J$VRAM(J)		;GET ADDRESS OF SIMULATED RAM
	 MOVEI	T2,LP64RM		;NONE, USE LP64.RAM

	MOVE	T1,C			;GET THE CHARACTER TO BE OUTPUT
	ADJBP	T1,R$PTR(T2)		;INDEX INTO THE RAM
	LDB	T1,T1			;GET THE RAM ENTRY FOR THIS CHAR

	;HERE, DEAL WITH THE "DELIMITER" AND "DELIMITER HOLD" STUFF
	MOVE	S1,J$VFLG(J)		;GET SIMULATION FLAGS
	TXZE	S1,VF.DLH		;IS DELIMITER/HOLD SET FROM LAST CHAR?
	 TXO	T1,RD.DLH		;YES, FORCE TRANSLATE WITH FAKE BIT
	TXNE	T1,RD.DEL		;IS DELIMITER SET FOR THIS CHAR?
	 TXO	S1,VF.DLH		;YES, SET DELIMITER/HOLD FOR NEXT CHAR
	MOVEM	S1,J$VFLG(J)		;SAVE SIMULATION FLAGS

	;NEXT, TRY TO DEAL SIMPLY WITH ORDINARY DATA
	TXNE	T1,RD.INT!RD.PMC	;SPECIAL CONDITION?
	 JRST	VFUCH2			;YES, HANDLE SLOWLY
	TXNE	T1,RD.XLT!RD.DEL!RD.DLH	;NO, TRANSLATE ?
VFUR2P:	 LDB	C,[POINTR T1,RD.DAT]	; SIMPLE TRANSLATION, DO SO
	$RETT				;RETURN
	;HERE WITH AN UNUSUAL RAM CONDITION
VFUCH2:	TXNN	T1,RD.INT		;INTERRUPT?
	 JRST	VFUCH3			;NO

	;INTERRUPT IF NO TRANSLATE, OR (TRANSLATE AND DELIM/HOLD)
	TXNE	T1,RD.XLT		;IS TRANSLATE SET?
	 TXNE	T1,RD.DLH		;YES, INTERRUPT ONLY IF DELIM/HOLD
	JRST	VFUCHI			;GENERATE INTERRUPT

	TXNE	T1,RD.DEL		;IF DELIMITER IS SET
	 JRST	VFUCHI			; GENERATE INTERRUPT

	;INTERRUPT BIT IS SET, BUT WE DON'T INTERRUPT.  PRINT OR MOVE.
	TXNE	T1,RD.PMC		;PAPER MOTION?
	 JRST	VFUVFC			;YES, DATA GOES TO VFU
	JRST	VFUR2P			;RAM (XLATED CHAR) TO PRINTER

	;HERE TO GENERATE AN INTERRUPT
VFUCHI:	LDB	S1,[POINTR T1,RD.DAT]	;GET TRANSLATION OF CHARACTER
	HRL	C,S1			;SAVE THAT FOR INTERRUPT ROUTINE
	CAIE	S1,^O136		;IS IT THE MAGIC CODE -20F DOES?
	 JRST	[PUSHJ	P,SETUDC	; MAKE STATUS "UNDEFINED CHAR"
		 MOVX	S1,VF.UDC	; REMEMBER UDC ERROR PENDING
		 IORM	S1,J$VFLG(J)	; FOR ERROR HANDLING
		 $RETF]			; DON'T OUTPUT ANYTHING
	PUSH	P,C			;SAVE THE ACTUAL CHARACTER
	MOVEI	C,"^"			;GET AN UP-ARROW
	PUSHJ	P,DEVOUT##		;PRINT THAT
	POP	P,C			;RESTORE ORIGINAL CHAR
	TRO	C,100			;MAKE IT A PRINTING CHARACTER
	ANDI	C,177			;GET RID OF ANY GARBAGE BITS
	$RETT				;LET DRIVER OUTPUT IT
	;INTERRUPT IS NOT SET
VFUCH3:
;	TXNN	T1,RD.PMC		;PAPER MOTION COMMAND?
;	 HALT	.			;???
	TXNE	T1,RD.DEL!RD.XLT!RD.DLH	;PAPER MOTION ONLY IF TRANSLATE 
	 JRST	VFUVFC			;PAPER MOTION COMMAND, GIVE TO DAVFU
	$RETT				;NO TRANSLATE, JUST PRINT IT

	;HERE TO PASS DATA TO THE VFU
VFUVFC:	MOVEI	C,.CHCRT		;ALL COMMANDS MUST FLUSH BUFFER
	PUSHJ	P,PHSOUT##		;AND RESET COLUMN COUNTER...
	LDB	C,[POINTR T1,RD.DAT]	;GET TRANSLATION OF CHAR
	TXNN	C,RD.SKP		;SKIP OR SLEW?
	 JRST	VFUCHS			;CHANNEL SKIP
	ANDI	C,RD.SKC		;SLEW, GET NUMBER OF LINES
	PUSH	P,C			;SAVE THAT
VFUSL1:	SOSGE	(P)			;SKIP IF MORE TO SLEW
	 JRST	VFUSL2			;DONE, CHARACTER PROCESSED
	MOVEI	C,.CHLFD		;CHARACTER TO SLEW WITH
	PUSHJ	P,PHSOUT##		;PRINT THAT
	PUSHJ	P,VFULIN		;ADVANCE VFU AND TEST PAGE COUNTER
	JRST VFUSL1			;CONTINUE

VFUSL2:	ADJSP	P,-1			;TOSS CONTROL COUNT
	$RETF				;SLEW COMPLETE - NO CALLER OUTPUT

	;HERE TO PERFORM A CHANNEL SKIP
VFUCHS:	ANDI	C,RD.SKC		;GET CHANNEL NUMBER TO SKIP TO
	CAILE	C,^D12-1		;MAKE SURE IT'S LEGAL
	 MOVEI	C,^D8-1			;CHANNEL GT TAPE CHN 12, USE CHANNEL 8
	MOVE	C,VFUBIT(C)		;CONVERT TO VFU BIT
	PUSH	P,C			;SAVE BIT FOR DESTINATION CHANNEL
VFUSK1:	MOVEI	C,.CHLFD		;CHARACTER TO SKIP WITH
	PUSHJ	P,PHSOUT##		;ADVANCE ONE LINE
	PUSHJ	P,VFULIN		;ADVANCE AND GET VFU DATA FOR NEW LINE
	TDNN	T1,(P)			;SEE IF DESIRED HOLE IS PUNCHED
	 JRST	VFUSK1			;IT IS NOT, SKIP ANOTHER LINE

	ADJSP	P,-1			;TOSS DESTINATION CHANNEL
	$RETF				;CHANNEL SKIP COMPLETE - NO CALLER OUTPUT
SUBTTL	VFULIN - ADVANCE VFU AND RETURN DATA

	;SUBROUTINE TO ADVANCE A LINE AND RETURN VFU DATA FOR NEW LINE
	;ACCOUNTS FOR PAGE COUNTER
	;TRASHES T1, T2, RETURNS VFU DATA IN T1
VFULIN:	AOS	T1,J$VLIN(J)		;ADVANCE TO NEXT LINE
	TLZ	T1,-1			;REMOVE PAGE COUNTER
	ASH	T1,1			;THERE ARE 2 NIBBLES/VFU LINE
	SKIPN	T2,J$VVFU(J)		;GET ADDRESS OF SIMULATED VFU
	 MOVEI	T2,STDVFU		;NONE, USE STANDARD VFU
	ADJBP	T1,V$PTR(T2)		;POINT TO THE FIRST
VFULN2:	ILDB	S1,T1			;GET THE FIRST NIBBLE
	CAIN	S1,126			;AN OLD STOP BYTE?
	 MOVEI	S1,357			;YES, CONVERT TO LP20 FORMAT
	CAIN	S1,357			;NOW SEE IF LP20 STOP BYTE
	 JRST	[HLLZS	J$VLIN(J)	;YES - BACK TO LINE ZERO
		 MOVE	T1,V$PTR(T2)	;RESET VFU DATA POINTER
		 JRST	VFULN2]		;AND TRY AGAIN
	ILDB	T1,T1			;GET THE SECOND
	LSH	T1,^D8			;THE SECOND NIBBLE HAS THE HIGH 6 CHNS
	IOR	T1,S1			;THE FIRST HAD THE LOW 6 CHANNELS
	 SKIPGE	S1,J$VLIN(J)		;PAGE COUNTER ENABLED?
	TDNN	T1,VFUBIT+^D1-1		;IF HIT TOP OF FORM (CHANNEL 1)
	 POPJ	P,			;NOT ENABLED OR NOT TOF, RETURN
	LDB	S1,[POINT 17,S1,17]	;AT TOF, GET PAGE COUNTER VALUE
;	ANDI	S1,7777			;LP20 IS 12 BIT COUNTER, MONITOR IS 36
	SOS	S1			;DECREMENT THE PAGE COUNTER
	DPB	S1,[POINT 17,J$VLIN(J),17] ;STORE NEW VALUE
	SKIPE	S1			;PAGE COUNTER = ZERO?
	 POPJ	P,			;NO, MORE TO GO
	MOVX	S1,VF.PCZ		;YES, PAGE COUNTER IS ZERO
	IORM	S1,J$VFLG(J)		;REMEMBER THE ERROR
	PJRST	SETPLE			;SET PAGE LIMIT EXCEEDED AND RETURN
SUBTTL	LP64.RAM

	;RAM Data is 12 bits wide.  Courtesy of the strange behavior
	;of PDP-11s, DTEs, and such, the .RAM file has 12 bits / 1/2 word.
	;Each data byte corresponds to one character code:
	RD.DLH==10000			;DELIM/HOLD (FAKE BIT)
	RD.INT==4000			;INTERRUPT
	RD.DEL==2000			;DELIMITER
	RD.XLT==1000			;TRANSLATE
	RD.PMC==0400			;PAPER MOTION COMMAND
	RD.DAT==0377			;CHARACTER DATA
		RD.SKP==20		;;VFU - SKIP 0-15 LINES
		RD.SKC==17		;;VFU - SKIP COUNT OR CHANNEL #

LP64RM:	PHASE	0
R$PTR:!	POINT	18,LP64RM+R$DATA,17	;BYTE POINTER TO RAM DATA
R$DATA:!				;DATA FOR LP64.RAM
	XLIST			;YOU REALLY DON'T WANT TO KNOW...
	OCT	001000004136		;CHARACTER CODES 0 & 1
	OCT	004136004136		;CHARACTER CODES 2 & 3
	OCT	004136004136		;CHARACTER CODES 4 & 5
	OCT	004136004136		;CHARACTER CODES 6 & 7
	OCT	004136001011		;CHARACTER CODES 10 & 11
	OCT	001407001406		;CHARACTER CODES 12 & 13
	OCT	001400001420		;CHARACTER CODES 14 & 15
	OCT	004136004136		;CHARACTER CODES 16 & 17
	OCT	001401001402		;CHARACTER CODES 20 & 21
	OCT	001403001404		;CHARACTER CODES 22 & 23
	OCT	001405004136		;CHARACTER CODES 24 & 25
	OCT	004136004136		;CHARACTER CODES 26 & 27
	OCT	004136004136		;CHARACTER CODES 30 & 31
	OCT	004136001044		;CHARACTER CODES 32 & 33
	OCT	004136004136		;CHARACTER CODES 34 & 35
	OCT	004136004136		;CHARACTER CODES 36 & 37
	OCT	001040001041		;CHARACTER CODES 40 & 41
	OCT	001042001043		;CHARACTER CODES 42 & 43
	OCT	001044001045		;CHARACTER CODES 44 & 45
	OCT	001046001047		;CHARACTER CODES 46 & 47
	OCT	001050001051		;CHARACTER CODES 50 & 51
	OCT	001052001053		;CHARACTER CODES 52 & 53
	OCT	001054001055		;CHARACTER CODES 54 & 55
	OCT	001056001057		;CHARACTER CODES 56 & 57
	OCT	001060001061		;CHARACTER CODES 60 & 61
	OCT	001062001063		;CHARACTER CODES 62 & 63
	OCT	001064001065		;CHARACTER CODES 64 & 65
	OCT	001066001067		;CHARACTER CODES 66 & 67
	OCT	001070001071		;CHARACTER CODES 70 & 71
	OCT	001072001073		;CHARACTER CODES 72 & 73
	OCT	001074001075		;CHARACTER CODES 74 & 75
	OCT	001076001077		;CHARACTER CODES 76 & 77
	OCT	001100001101		;CHARACTER CODES 100 & 101
	OCT	001102001103		;CHARACTER CODES 102 & 103
	OCT	001104001105		;CHARACTER CODES 104 & 105
	OCT	001106001107		;CHARACTER CODES 106 & 107
	OCT	001110001111		;CHARACTER CODES 110 & 111
	OCT	001112001113		;CHARACTER CODES 112 & 113
	OCT	001114001115		;CHARACTER CODES 114 & 115
	OCT	001116001117		;CHARACTER CODES 116 & 117
	OCT	001120001121		;CHARACTER CODES 120 & 121
	OCT	001122001123		;CHARACTER CODES 122 & 123
	OCT	001124001125		;CHARACTER CODES 124 & 125
	OCT	001126001127		;CHARACTER CODES 126 & 127
	OCT	001130001131		;CHARACTER CODES 130 & 131
	OCT	001132001133		;CHARACTER CODES 132 & 133
	OCT	001134001135		;CHARACTER CODES 134 & 135
	OCT	001136001137		;CHARACTER CODES 136 & 137
	OCT	001100001101		;CHARACTER CODES 140 & 141
	OCT	001102001103		;CHARACTER CODES 142 & 143
	OCT	001104001105		;CHARACTER CODES 144 & 145
	OCT	001106001107		;CHARACTER CODES 146 & 147
	OCT	001110001111		;CHARACTER CODES 150 & 151
	OCT	001112001113		;CHARACTER CODES 152 & 153
	OCT	001114001115		;CHARACTER CODES 154 & 155
	OCT	001116001117		;CHARACTER CODES 156 & 157
	OCT	001120001121		;CHARACTER CODES 160 & 161
	OCT	001122001123		;CHARACTER CODES 162 & 163
	OCT	001124001125		;CHARACTER CODES 164 & 165
	OCT	001126001127		;CHARACTER CODES 166 & 167
	OCT	001130001131		;CHARACTER CODES 170 & 171
	OCT	001132001133		;CHARACTER CODES 172 & 173
	OCT	001134001135		;CHARACTER CODES 174 & 175
	OCT	001136001000		;CHARACTER CODES 176 & 177
	OCT	001000004136		;CHARACTER CODES 200 & 201
	OCT	004136004136		;CHARACTER CODES 202 & 203
	OCT	004136004136		;CHARACTER CODES 204 & 205
	OCT	004136004136		;CHARACTER CODES 206 & 207
	OCT	004136001011		;CHARACTER CODES 210 & 211
	OCT	001407001406		;CHARACTER CODES 212 & 213
	OCT	001400001420		;CHARACTER CODES 214 & 215
	OCT	004136004136		;CHARACTER CODES 216 & 217
	OCT	001401001402		;CHARACTER CODES 220 & 221
	OCT	001403001404		;CHARACTER CODES 222 & 223
	OCT	001405004136		;CHARACTER CODES 224 & 225
	OCT	004136004136		;CHARACTER CODES 226 & 227
	OCT	004136004136		;CHARACTER CODES 230 & 231
	OCT	004136001044		;CHARACTER CODES 232 & 233
	OCT	004136004136		;CHARACTER CODES 234 & 235
	OCT	004136004136		;CHARACTER CODES 236 & 237
	OCT	001040001041		;CHARACTER CODES 240 & 241
	OCT	001042001043		;CHARACTER CODES 242 & 243
	OCT	001044001045		;CHARACTER CODES 244 & 245
	OCT	001046001047		;CHARACTER CODES 246 & 247
	OCT	001050001051		;CHARACTER CODES 250 & 251
	OCT	001052001053		;CHARACTER CODES 252 & 253
	OCT	001054001055		;CHARACTER CODES 254 & 255
	OCT	001056001057		;CHARACTER CODES 256 & 257
	OCT	001060001061		;CHARACTER CODES 260 & 261
	OCT	001062001063		;CHARACTER CODES 262 & 263
	OCT	001064001065		;CHARACTER CODES 264 & 265
	OCT	001066001067		;CHARACTER CODES 266 & 267
	OCT	001070001071		;CHARACTER CODES 270 & 271
	OCT	001072001073		;CHARACTER CODES 272 & 273
	OCT	001074001075		;CHARACTER CODES 274 & 275
	OCT	001076001077		;CHARACTER CODES 276 & 277
	OCT	001100001101		;CHARACTER CODES 300 & 301
	OCT	001102001103		;CHARACTER CODES 302 & 303
	OCT	001104001105		;CHARACTER CODES 304 & 305
	OCT	001106001107		;CHARACTER CODES 306 & 307
	OCT	001110001111		;CHARACTER CODES 310 & 311
	OCT	001112001113		;CHARACTER CODES 312 & 313
	OCT	001114001115		;CHARACTER CODES 314 & 315
	OCT	001116001117		;CHARACTER CODES 316 & 317
	OCT	001120001121		;CHARACTER CODES 320 & 321
	OCT	001122001123		;CHARACTER CODES 322 & 323
	OCT	001124001125		;CHARACTER CODES 324 & 325
	OCT	001126001127		;CHARACTER CODES 326 & 327
	OCT	001130001131		;CHARACTER CODES 330 & 331
	OCT	001132001133		;CHARACTER CODES 332 & 333
	OCT	001134001135		;CHARACTER CODES 334 & 335
	OCT	001136001137		;CHARACTER CODES 336 & 337
	OCT	001100001101		;CHARACTER CODES 340 & 341
	OCT	001102001103		;CHARACTER CODES 342 & 343
	OCT	001104001105		;CHARACTER CODES 344 & 345
	OCT	001106001107		;CHARACTER CODES 346 & 347
	OCT	001110001111		;CHARACTER CODES 350 & 351
	OCT	001112001113		;CHARACTER CODES 352 & 353
	OCT	001114001115		;CHARACTER CODES 354 & 355
	OCT	001116001117		;CHARACTER CODES 356 & 357
	OCT	001120001121		;CHARACTER CODES 360 & 361
	OCT	001122001123		;CHARACTER CODES 362 & 363
	OCT	001124001125		;CHARACTER CODES 364 & 365
	OCT	001126001127		;CHARACTER CODES 366 & 367
	OCT	001130001131		;CHARACTER CODES 370 & 371
	OCT	001132001133		;CHARACTER CODES 372 & 373
	OCT	001134001135		;CHARACTER CODES 374 & 375
	OCT	001136001000		;CHARACTER CODES 376 & 377
	LIST

R$$LEN:!
	DEPHASE
SUBTTL	NORMAL.VFU

VFUBIT:	EXP	00001			;TAPE CHANNEL 1, OUR 0
	EXP	00002
	EXP	00004
	EXP	00010
	EXP	00020
	EXP	00040
	EXP	00400			;TAPE CHANNEL 7, OUR 6
	EXP	01000
	EXP	02000
	EXP	04000
	EXP	10000
	EXP	20000			;TAPE CHANNEL 12, OUR 11

STDVFU:	PHASE	0
V$PTR:!	POINT	7,STDVFU+V$DATA,6	;POINT TO BEFORE FIRST VFU DATA NIBBLE
V$DATA:!			;DATA FOR NORMAL.VFU
	XLIST			;YOU REALLY DON'T WANT TO KNOW
	OCT	125760310004		;START, LINE 1A,1B, 2A,2B
	OCT	120043001050		;LINE 3A, 3B, 4A, 4B, 5A
	OCT	010400216004		;LINE 5B, 6A, 6B, 7A, 7B
	OCT	100042401060		;LINE 8A, 8B, 9A, 9B, 10A
	OCT	011500210004		;LINE 10B, 11A, 11B, 12A, 12B
	OCT	160042001050		;LINE 13A, 13B, 14A, 14B, 15A
	OCT	010600212004		;LINE 15B, 16A, 16B, 17A, 17B
	OCT	100043401040		;LINE 18A, 18B, 19A, 19B, 20A
	OCT	011500314004		;LINE 20B, 21A, 21B, 22A, 22B
	OCT	120042001070		;LINE 23A, 23B, 24A, 24B, 25A
	OCT	010400212004		;LINE 25B, 26A, 26B, 27A, 27B
	OCT	140042401040		;LINE 28A, 28B, 29A, 29B, 30A
	OCT	011740210004		;LINE 30B, 31A, 31B, 32A, 32B
	OCT	120043001050		;LINE 33A, 33B, 34A, 34B, 35A
	OCT	010400216004		;LINE 35B, 36A, 36B, 37A, 37B
	OCT	100042401060		;LINE 38A, 38B, 39A, 39B, 40A
	OCT	011500310004		;LINE 40B, 41A, 41B, 42A, 42B
	OCT	160042001050		;LINE 43A, 43B, 44A, 44B, 45A
	OCT	010600212004		;LINE 45B, 46A, 46B, 47A, 47B
	OCT	100043401040		;LINE 48A, 48B, 49A, 49B, 50A
	OCT	011500214004		;LINE 50B, 51A, 51B, 52A, 52B
	OCT	120042001070		;LINE 53A, 53B, 54A, 54B, 55A
	OCT	010400212004		;LINE 55B, 56A, 56B, 57A, 57B
	OCT	140042401040		;LINE 58A, 58B, 59A, 59B, 60A
	OCT	010400010000		;LINE 60B, 61A, 61B, 62A, 62B
	OCT	100002000040		;LINE 63A, 63B, 64A, 64B, 65A
	OCT	000400053000		;LINE 65B, 66A, 66B, STOP, 67A
	OCT	000000000000		;LINE 67B, 68A, 68B, 69A, 69B
	OCT	000000000000		;LINE 70A, 70B, 71A, 71B, 72A
	OCT	000000000000		;LINE 72B, 73A, 73B, 74A, 74B
	OCT	000000000000		;LINE 75A, 75B, 76A, 76B, 77A
	OCT	000000000000		;LINE 77B, 78A, 78B, 79A, 79B
	OCT	000000000000		;LINE 80A, 80B, 81A, 81B, 82A
	OCT	000000000000		;LINE 82B, 83A, 83B, 84A, 84B
	OCT	000000000000		;LINE 85A, 85B, 86A, 86B, 87A
	OCT	000000000000		;LINE 87B, 88A, 88B, 89A, 89B
	OCT	000000000000		;LINE 90A, 90B, 91A, 91B, 92A
	OCT	000000000000		;LINE 92B, 93A, 93B, 94A, 94B
	OCT	000000000000		;LINE 95A, 95B, 96A, 96B, 97A
	OCT	000000000000		;LINE 97B, 98A, 98B, 99A, 99B
	OCT	000000000000		;LINE 100A, 100B, 101A, 101B, 102A
	OCT	000000000000		;LINE 102B, 103A, 103B, 104A, 104B
	OCT	000000000000		;LINE 105A, 105B, 106A, 106B, 107A
	OCT	000000000000		;LINE 107B, 108A, 108B, 109A, 109B
	OCT	000000000000		;LINE 110A, 110B, 111A, 111B, 112A
	OCT	000000000000		;LINE 112B, 113A, 113B, 114A, 114B
	OCT	000000000000		;LINE 115A, 115B, 116A, 116B, 117A
	OCT	000000000000		;LINE 117B, 118A, 118B, 119A, 119B
	OCT	000000000000		;LINE 120A, 120B, 121A, 121B, 122A
	OCT	000000000000		;LINE 122B, 123A, 123B, 124A, 124B
	OCT	000000000000		;LINE 125A, 125B, 126A, 126B, 127A
	OCT	000000000000		;LINE 127B, 128A, 128B, 129A, 129B
	OCT	000000000000		;LINE 130A, 130B, 131A, 131B, 132A
	OCT	000000000000		;LINE 132B, 133A, 133B, 134A, 134B
	OCT	000000000000		;LINE 135A, 135B, 136A, 136B, 137A
	OCT	000000000000		;LINE 137B, 138A, 138B, 139A, 139B
	OCT	000000000000		;LINE 140A, 140B, 141A, 141B, 142A
	OCT	000000000000		;LINE 142B, 143A, 143B

V$$LEN:!		;LENGTH OF LONGEST POSSIBLE VFU
	DEPHASE
SUBTTL	Literal pool


VFULIT:	LIT

VFUEND::!END