2!		PROGRAM		: BATRUN.BAS
5!		VERSION		: V10.1
6!		EDIT		: B
7!		EDIT DATE	: 21-JUN-91
8!
10		EXTEND
11	! &
	&
	&
	!		  C O P Y R I G H T &
	&
	&
  !		      Copyright (C) 1976, 1991 by &
  !	        Digital Equipment Corporation, Maynard, Mass. &
  !	&
  !	&
  !	This software is furnished under a license and may be used and &
  !	copied  only  in accordance with the terms of such license and &
  !	with the  inclusion  of  the  above  copyright  notice.   This &
  !	software  or  any  other copies thereof may not be provided or &
  !	otherwise made available to any other person.  No title to and &
  !	ownership of the software is hereby transferred. &
  !	&
  !	The information in this software is subject to change  without &
  !	notice  and should not be construed as a commitment by Digital &
  !	Equipment Corporation. &
  !	&
  !	DIGITAL assumes no responsibility for the use  or  reliability &
  !	of its software on equipment that is not supplied by DIGITAL. &
  !	&
  !*******************************************************************
20	! &
	&
	&
	!	M O D I F I C A T I O N    H I S T O R Y &
	&
	&

21	! VER/ED	EDIT DATE	REASON &
	! KMF 01	04-APR-84	NEW FEATURE FOR SPAWN DIRECTIVE &
	! REG		23-OCT-86	FIX SPAWN ERROR HANDLING &
	! REG		02-MAR-87	FIX CVT00$ BUG (BATRUN HB's IF RUN &
	!				 FROM DISK OTHER THAN SY:) &
	! REG		25-JUL-87	RUN [0,1]LOGIN.COM WHEN SPAWNED, AND &
	!				SET JOB/KEYBOARD=RSX IF IT EXISTS, OR &
	!				RT11 OTHERWISE. &
	! REG		06-OCT-87	SET JOB TO DCL IF "/DCL" ON $JOB CARD. &
	!				IF LOGIN.COM LEAVES JOB IN DCL, THEN &
	!				IF RSX IS INSTALLED THEN SW JOB TO &
	!				RSX, ELSE SW JOB TO RT11.  IF JOB IS &
	!				NOT IN DCL, THEN LEAVE IT ALONE. &
	! REG		20-OCT-87	ADD A WAIT FOR PK INPUT WAIT BEFORE &
	!				SYS CALL TO FIND JOBKBM. &
	! REG		10-MAY-88	ADD STEERING FLAG TO PREVENT UNWANTED &
	!				REQUEUING OF KILLED JOBS. &
	! REG		17-MAY-89	SPAWN $LOGIN.TSK, NOT [0,1]LOGIN.COM. &
	! REG		16-OCT-89	ADD BLANK LINE BEFORE SETTING KBM TO &
	!				ALLOW FOR DETACHED JOB QUESTION. &
	! REG	V10.1	02-Nov-90	Look at both PK and BATRUN job times &
	!				for /LIMIT and /CPU timeouts in FNW% &
	!				at 17100. &
	! REG	V10.1	20-MAR-91	Before killing a job, send the PK two &
	!				CTRL-Z's and two CTRL-C's to get it &
	!				out of BP2 and into a ^C state. &
	! &

100	! &
	&
	&
	!	G E N E R A L    D E S C R I P T I O N &
	&
	&
	&
	! THIS PROGRAM TAKES THE CONTROL FILE CREATED BY BATDEC AND &
	! ACTUALLY SENDS THE DATA TO THE PSUEDO KEYBOARD. &
	&

300	! &
	&
	&
	!	I / O    C H A N N E L S &
	&
	&
	&
   !	CHANNEL #		USED FOR &
!	   1			WORK FILE &
!	   2			LOG FILE &
!	   11			CONTROL FILE &
	&
	&
	&
	&
	&

400	! &
	&
	&
	!	V A R I A B L E    D E F I N I T I O N S &
	&
	&
	&
   !	NAME		USED FOR &
	&
!	A$		ACCOUNT NUMBER. &
!	A%		ACCOUNT NUMBER. &
!	B0%		FREE LIST POINTER. &
!	C$		GENERAL COMMAND DECODE STRING. &
!	C8$		BELL &
!	C9$		'CRLF' &
!	C%()		PROGRAM STATUS ARRAY. &
!	C()		PROGRAM STATUS ARRAY. &
!	C1%		CHANNEL NUMBER. &
!	D8%		DENSITY/PARITY WORD FOR MAGTAPE MOUNT. &
!	D9$		TODAYS DATE. &
!	DTA%		$DATA STATEMENT IN EFFECT FLAG. &
!	DEVICE$()	MOUNTED DEVICE TABLE. &
!	DEVOKB%		FROM MONITOR TABLES. &
!	DEVPTR%		FROM MONITOR TABLES. &
!	DEN$		DENSITY FOR MAGTAPE MOUNT. &
!	E%		ERROR VARIABLE. &
!	E0%		ENTRY TYPE. &
!	ERLEV%		ERROR LEVEL FLAG. &
!	E8%		RUNNING IN LOCAL ERROR STATE FLAG. &
!	E9%		RUNNING IN ERROR STATE FLAG. &
!	F%		FOUND FLAG. &
!	FATAL.ERR%	SOME FATAL ERROR HAS BEEN DETECTED IN PACKAGE. &
!	F1%		EVENT WORD. &
!	F2%		EVENT WORD. &
!	I$		VERSION-EDIT. &
!	I%		DELIMETER POINTER. &
!	J$		JOB NUMBER. &
!	J%		JOB NUMBER. &
!	JJ%		DELIMETER POINTER. &
!	J1%		JOB DATA BLOCK 1. &
!	J9%		CURRENT JOB RECORD POINTER. &
!	JOBMOD%		JOB MODIFICATION RECEIVED FLAG. &
!	JOB$		BATCH JOB NAME. &
!	JOB%		BATCH JOB NUMBER. &
!	JOBTBL%		JOB TABLE FORM MONITOR. &
!	K%		KB: NUMBER OF BATCH UNIT IF ATTACHED. &
!	K0%		I/O BLOCK. &
!	K1%		KB: LIST FILE FLAG. &
!	KB%		BATCH JOB'S KEYBOARD NUMBER*2. &
!	KBDDB%		CONTROLLED JOB'S KB DDB. &
!	L0%		COMMAND DISPATCH VAR. &
!	L9%		VALID JOB CARD RECEIVED OR LOGGED IN FLAG. &
!	LG%		LOG FILE OPEN FLAG. &
!	M0%()		CHANGE ARRAY. &
!	M%()		MESSAGE LIST HEAD AND TAIL POINTER ARRAY. &
!	N%		UTILITY VAR. &
!	O$		OUTPUT FROM PSUEDO KEYBOARD. &
!	PKG.LOC$	DEVICE/PPN OF PACKAGE. &
!	P$		CHAIN MODULE NAME. &
!	P%		POSITION POINTER FOR COMMAND STRING. &
!	P0%		CURRENT RECORD POINTER. &
!	P1%		RECORD POINTER. &
!	PAR$		PARITY FOR MAGTAPE MOUNTS. &
!	PHY$		PHYSICAL DEVICE FOR MOUNT. &
!	PK%		PSUEDO KEYBOARD NUMBER. &
!	Q9%		DESTINATION VOLUME RECORD POINTER. &
!	QUE%		QUEUE/NOQUEUE FLAG. &
!	R%		PACKAGE STATUS WORD. &
!	R$		COLLECTS OUTPUT OF PK. &
!	RO%		READ ONLY FLAG FOR DISK MOUNTS. &
!	RQ%		TEMPORARY HOLDER FOR JOB STATUS WHILE QUEING LOG &
!	S$		MODULE NAME. &
!	S%()		STACK. &
!	S%		STACK POINTER. &
!	S0%		SWITCH VALUE AND SLEEP TIMER. &
!	S8%		MAGTAPE STATUS VARIABLE. &
!	SVE$		STACK FOR C$ OVER POLLING CALLS. &
!	T$		TEXT TO SEND TO OPERATOR. &
!	TYPE%		TYPE OF DEVICE TO MOUNT. &
!	VID$		VOLUME ID. &
!	W$		WORK FILE NAME. &
!	WRI$		WRITE ENABLE/DISABLE VALUE FOR MOUNTS. &
!	ALL Z'S		TEMPORARY LOCAL WORK VARIABLES. &

800	! &
	&
	&
!		F U N C T I O N / S U B R O U T I N E    D E S C . &
	&
	&
!	NAME		LINE	USE &
!	11000			GET ANY WAITING OUTPUT. &
!	11500			PROCESS THE CONTROL FILE. &
!	12000			PROCESS PURE DATA. &
!	12100			LOGIN ROUTINE. &
!	12200			SET ERROR LEVEL. &
!	12300			SET QUE/DELETE VALUES. &
!	12400			SET ELAPSED TIME LIMIT. &
!	12500			SET CPU TIME LIMIT. &
!	12600			PRINT OR SEND DATA. &
!	12700			SET PRIORITY. &
!	12800			PRINT TO LOG. &
!	12900			SEND CTRL/Z IF NECESSARY. &
!	13000			LOG OUT OR KILL JOB. &
!	13100			MESSAGE TO OPERATOR. &
!	13200			MOUNT. &
!	13300			DISMOUNT. &
!	13400			GET TO COMMAND AND SEND DATA. &
!	13500			SET DATA INDICATOR. &
!	FNM0$		15000	BUILD STATUS STRING. &
!	FNC%		15100	CTRL/C NEEDED CHECK. &
!	FNE%		15200	ERROR STATUS CHECK. &
!	FNP9%		15400	SET MAGTAPE DENSITY/PARITY. &
!	FNE0%		15500	PRINT ERROR MESSAGE TO LOG. &
!	FNF%		15800	FORCE DATA TO PK. &
!	FNH%		16000	HALT JOB IN PROGRESS. &
!	FNI%		16100	INPUT WAIT CHECK. &
!	FNK%		16200	KILL JOB. &
!	FNP6%		16600	PUT DATA TO PK. &
!	FNS%		16800	SEND DATA TO PK. &
!	FNT$		17000	BUILD TIME OF DAY STRING. &
!	FNW%		17100	WAIT FOR INPUT WAIT. &
!	FNZ%		17300	SEND CTRL/Z. &
!	FNP$		17400	PRINT TO LOG FILE . &

830	! &
	&
	!	P A C K A G E    S U B R O U T I N E S &
	&
	! Line		Use &
	! 20000		INITIALIZE FOR POLLINT ROUTINES &
	! 20200		SEND A MESSAGE TO QUEMAN. &
	! 20300		ONLINE TO QUEMAN. &
	! 20340		REQUEST NEW JOB FROM QUEMAN. &
	! 20360		REQUEST NEXT PACKET FROM QUEMAN. &
	! 20420		REQUEST REQUE FROM QUEMAN. &
	! 20440		TELL QUEMAN ABOUT END OF JOB. &
	! 20460		REQUEST DEFERRAL OF JOB BY QUEMAN. &
	! 20900		REQUEST A NEW JOB. &
	! 21000		POLLING ROUTINES. &
	! 23050		ENTER RECEIVER TO OPSER. &
	! 23100		SEND ONLINE TO OPSER. &
	! 23140		DELETE LAST MESSAGE TO OPSER. &
	! 23500		SEND TO OPERATOR. &
	! 23600		STORE A MESSAGE INTO THE WORK FILE. &
	! 24010		NEWJOB PACKET RECEIVED. &
	! 24100		FILE PACKET RECEIVED. &
	! 24200		ENDJOB PACKET RECEIVED. &
	! 24300		KILL JOB RECEIVED FROM QUEMAN.
840	! &
	&
	!	P A C K A G E    F U N C T I O N S &
	&
	! Name			Lines		Use &
	! FNR%(S$,L%)		25200-25250	Match a  keyword. &
	! FNF0%(P0%,N$,D$)	25500-25690	Apply null default or &
	!					default string to a File &
	!					Descriptor Record. &
	! FNP%(P0%,P%,S$,Y0%,Y1%) &
	!			25800-25890	Turn a filename string &
	!					into a File Descriptor &
	!					Record. &
	! FNU$(P0%,C$,Z%,Z0%)	25900-25970	Turn a File Descriptor &
	!					Record into a filename &
	!					string, with switches. &
	! FNU0$(L%)		25980-25990	Return the NUM1$ of the &
	!					low byte of L%, or &
	!					'*', if the low byte is &
	!					255. &
	! FNO%(P0%,A0%,C0%)	26000-26090	Open the file described &
	!					in (work-file) record &
	!					P0% - drops and regains &
	!					temporary privs. &
	! FNA%			26100-26130 	Get the next free-list &
	!					record. &
	! FNA0%(P0%)		26200-26230	Put record P0% back &
	!					into the free-list. &
	! FNCHNGE%(S$)		27000-27020	CHANGE THE STRING S$ &
	!					INTO THE INTEGER ARRAY &
	!					Z%(), PADDING TO 30 CHRS &
	!					WITH 0'S AND CONVERT &
	!					EACH TWO BYTES TO ONE &
	!					INTEGER IN THE ODD &
	!					WORDS. &
	! FNN%			27200-27250	RETURN THE UNSIGNED &
	!					INTEGER IN THE STRING C$ &
	!					AT POSITION P%+1%. &
	! FNPUSH%		27400		PUSH A VARIABLE ONTO &
	!					THE STACK. &
	&
	! FNPOP%		27410		POP A VARIABLE FROM &
	!					THE STACK. &
	! FNUNPACK$		27300		UNPACK A STRING OUT OF &
	! 					THE WORK FILE. &
	&
	&

900	&
	&
	&
	!	D I M E N S I O N    S T A T E M E N T S &

901	DIM #1%,Z0%(32767%,63%) &
	\ DIM #1%,Z0$(32767%)=128% &
				! WORK-FILE, PRIMARY. &
	\ DIM S%(30%)		! INTERNAL STACK. &
	&
	\ DIM DEVICE$(12%)	! DEVICE NAME TABLE. &
	&
	&
	!	DIMENSION STATEMENTS FOR STANDARD ROUTINES &
	\ DIM Z%(30%)		! USED BY FNP%() FOR RETURN OF DATA &
	\ DIM M%(5%)		! USED BY THE POLLING ROUTINES TO HOLD &
				!  THE HEAD AND TAIL POINTERS FOR THE &
				!  FOLLOWING LISTS : &
				!	M%(0%)	- HEAD OF INCOMPLETE &
				!		   LIST &
				!	   1%	- TAIL OF LIST &
				!	   2%	- HEAD OF COMPLETE LIST &
				!	   3%	- TAIL OF LIST &
				!	   4%	- HEAD OF UNPROCESSED &
				!		   LIST &
				!	   5%	- TAIL OF LIST &
	&

999	&
	&
	&
	!	M A I N    C O D E &

1000	ON ERROR GOTO 19000 &
	\ UU0$=CHR$(6%)+CHR$(26%)+CHR$(0%)+CHR$(0%) &
	\ UU1$=CHR$(6%)+CHR$(26%)+CHR$(0%)+CHR$(1%) &
		! SET UP STANDARD ERROR TRAP. &

1010	I$="V10.1-B" &
	\ PRINT "BATRUN	"+I$ UNLESS E0% &
		! SET UP HEADER LINE. &
		! PRINT THE HEADER LINE PREPARATORY TO GIVING &
		! AN ERROR. &

1020	CHANGE SYS(CHR$(12%)) TO Z% &
	\ PKG.LOC$="OPSER$:" &
	\ IF Z%(3%)+SWAP%(Z%(4%))<>15%*2% THEN &
		PRINT "?BATRUN must be COMPILED" &
	\	GOTO 32767 &
		! USE LOGICAL FOR PACKAGE LOCATION &
		! ISSUE ERROR IF IT WAS NOT A COMPILED FILE. &

1030	IF E0%<>2% THEN &
		PRINT "?Illegal entry - Please 'RUN " + PKG.LOC$ + "BATCH'" &
	\	GOTO 32767 &
		! THE ONLY LEGAL ENTRY TO THIS PROGRAM IS A CHAIN ENTRY, &
		! SO GIVE AN ERROR IF THAT WASN'T THE WAY WE ENTERED. &
	&

1050	S% = -1% &
	\ S$="BATRUN	"+I$ &
	\ CHR0$   = CHR$(  0%) &
	\ CHRM1$  = CHR$( -1%) &
	\ CHR6$   = CHR$(  6%) &
	\ CHR7$	  = CHR$(  7%) &
	\ CHR9$   = CHR$(  9%) &
	\ CHR10$  = CHR$( 10%) &
	\ CHRM10$ = CHR$(-10%) &
	\ CHR12$  = CHR$( 12%) &
	\ CHR13$  = CHR$( 13%) &
	\ CHR18$  = CHR$( 18%) &
	\ CHRM21$ = CHR$(-21%) &
	\ CHR6.9$	= CHR6$+CHR9$ &
	\ CHR6.M10$	= CHR6$+CHRM10$ &
	\ CHR6.18$	= CHR6$+CHR18$ &
	\ CHR6.M21.0$	= CHR6$+CHRM21$+CHR0$ &
	\ CHR6.M21.M1$	= CHR6$+CHRM21$+CHRM1$ &
	\ CVT4.0$ = STRING$(4%,0%) &
	\ NULSTG$="" &
	\ NOREQUE%=0% &
	&
	! INITIALIZE STACK POINTER &
	! USEFUL LITERAL STRINGS &

1060	GOSUB 20000 &
	\ GOTO 9000 IF R% AND 8% &
		! GO DO THE STANDARD STARTUP AND CHECK FOR END JOB. &
	&

1500	GOSUB 21000 &
	\ JOB$=RAD$(Z0%(J9%,9%))+RAD$(Z0%(J9%,10%)) &
	\ JOB$=FNU$(J9%,NL$,129%,0%) IF R% AND 1% &
	\ T$=JOB$+": STARTED AT "+FNT$ &
	\ GOSUB 23500 &
	\ IF Z0%(J9%,51%) THEN Z0%(J9%,9%),Z0%(Z0%(J9%,38%),9%)= &
						Z0%(J9%,51%) &
			\ Z0%(J9%,10%),Z0%(Z0%(J9%,38%),10%)= &
						Z0%(J9%,52%) &
			\ Z$=RAD$(Z0%(J9%,51%))+RAD$(Z0%(J9%,52%)) &
			\ T$=JOB$+": RENAMED '"+Z$+"'" &
			\ JOB$=FNU$(J9%,NL$,128%,0%)+Z$ &
			\ GOSUB 23500 &
		! SET UP THE JOB NAME AND SEND THE STARTED MESSAGE. &
		! IF A NAME CHANGE HAS BEEN REQUESTED, CHANGE THE NAME, &
		! AND SEND THE MESSAGE INFORMING THE OPERATOR OF THE &
		! CHANGE. &

1510	Z%=FNO%(Z0%(J9%,38%),2%,2%,0%) &
	\ LG%=-1% UNLESS E% &
	\ IF E% THEN T$=JOB$+": "+RIGHT(SYS(CHR6$+CHR9$+ &
			CHR$(E% AND 63%)),3%)+" ON LOG FILE OPEN."+ &
			"  JOB ABORTED." &
			\ E%=0% &
			\ GOSUB 23500 &
			\ GOSUB 21740 &
		! TRY TO OPEN THE LOG FILE. IF IT FAILS, THE JOB DIES. &

1520	GOTO 8020 IF (JOBMOD%) OR (Z0%(J9%,31%) AND 5%) &
	\ Z%=FNO%(Z0%(0%,37%),3%,11%,0%)
1525	IF E% THEN T$=JOB$+": "+RIGHT(SYS(CHR6$+CHR9$+ &
			CHR$(E% AND 63%)),3%)+" ON CONTROL FILE OPEN."+ &
			"  JOB REQUEUED." &
			\ E%=0% &
			\ GOSUB 23500 &
			\ R%=R% OR 8% &
			\ Z0%(J9%,31%)=Z0%(J9%,31%) OR 4% &
			\ JOBMOD%=-1% &
		! TRY TO OPEN THE CONTROL FILE. IF IT FAILS THE JOB IS &
		! REQUEUED. THIS IS BECAUSE IT IS NOT THE JOB'S FAULT. &

1530	GOTO 8020 IF JOBMOD% &
	\ Z%=FNO%(Q9%,16%,6%,0%) &
	\ IF E% THEN GOTO 1525 &
		ELSE E9%=Z0%(J9%,50%) &
			\ PK%=Z0%(Q9%,11%) AND 255% &
	\ T9,C9=4294970000. &
	\ QUE%=Z0%(0%,41%) &
	\ ERLEV%=Z0%(0%,40%) &
	\ GOSUB 11500 &
	\ GOSUB 23150 IF JOBMOD% &
	\ T$=JOB$+": COMPLETED AT "+FNT$ UNLESS JOB.ERR% &
	\ T$=JOB$+": COMPLETED (IN ERROR) AT "+FNT$ IF JOB.ERR% &
	\ GOSUB 23500 &
	\ GOTO 8000 &
		! GO DO EVERYTHING THAT THE CONTROL FILE WANTS. &
		! WE ARE DONE WHEN WE COME BACK FROM THERE, WHETHER &
		! EVERYTHING WAS COOL OR NOT. SO WE PRINT OUT THE JOB &
		! COMPLETED MESSAGE AND GET OUT. &
	&
	&
	&
	&

2000	GOTO 9000 &
		! FATAL ERROR. &
	&

8000	Z%=FNE0%("JOB ABORTED***********************************",-1%) IF &
			Z0%(J9%,31%) AND 1% &
	\ Z%=FNE0%("JOB REQUEUED*************************************",0%) IF &
			Z0%(J9%,31%) AND 4% &
	\ GOSUB 13000 &
	\ N%=Z0%(J9%,5%) &
	\ WHILE N% &
		\ N$=FNUNPACK$(N%,26%) &
		\ N$=RIGHT(N$,INSTR(1%,N$," ")) &
		\ Z$=FNP$("NOTICE FROM OPERATOR:"+N$+C9$) IF LG% &
		\ N%=Z0%(N%,1%) &
	\ NEXT &
	\ CLOSE 2% \ LG%=0% &
	\ GOTO 8020 UNLESS QUE% AND 1% &
		! LOG OUT THE JOB IF NECESSARY. &
		! PROCESS ANY NOTICES. &
		! END UP IF WE DON'T HAVE TO QUE OR WE GOT AN ERROR &
		! ON THE CONTROL FILE. &

8010	INPUT LINE #11%, C$ &
	\ GOTO 8020 IF LEFT(C$,2%)<>"$1" &
	\ E9%=0% &
	\ NOREQUE%=-1% &
	\ RQ%=Z0%(J9%,31%) &
	\ GOSUB 12100 &
	\ Z0%(J9%,31%)=RQ% &
	\ C$="RUN $QUE"+CHR13$+"Q " &
	\ C$=C$+RAD$(Z0%(0%,32%))+RAD$(Z0%(0%,33%))+":=" IF Z0%(0%,32%) &
	\ C$=C$+FNU$(Z0%(J9%,38%),NULSTG$,4233%,0%) &
	\ C$=C$+"/DE" IF QUE% AND 4% &
	\ C$=C$+CHR13$ &
	\ GOSUB 13400 &
	\ GOSUB 12900 &
	\ GOSUB 13000 &
		! SET UP THE FILE TO QUE AND LOG IN, QUE IT AND LOG OUT. &

8020	ON ERROR GOTO 8030 &
	\ Z$=ACC$+"BATUN"+CHR$((Z0%(Q9%,11%) AND 255%)+48%) &
	\ Z$=ACC$+"BATUN"+CHR$(0%) IF (Z0%(Q9%,11%) AND 255%)=255% &
	\ KILL Z$+".OBJ"
8025	KILL Z$+".EXE" &
	\ GOTO 9000 &
		! KILL THE TEMP FILES IF NECESSARY. &

8030	RESUME 8025 IF ERL=8020% &
	\ RESUME 9000 IF ERL=8025% &
		! HANDLE THE CAN'T FIND FILE ERRORS. &
	&

9000	&
	&
	&
	!	C L O S E O U T    A N D    E X I T &
	&

9005	R%=R% OR 8% &
		! SET THE END JOB FLAG. &

9010	Z0%(0%,11%)=FNA0%(Z0%(0%,11%)) IF Z0%(0%,11%) &
	\ P0%=Z0%(0%,13%) &
	\ IF P0% THEN &
		P$=FNU$(P0%,NULSTG$,-1%,0%) &
	\	Z0%(0%,13%)=Z0%(P0%,1%) &
	\	Z0%(P0%,1%)=0% &
	\	Z%=FNA0%(P0%) &
		! GET RID OF THE INDIRECT COMMAND LIST; &
		! SET UP THE NEXT ONE TO CHAIN TO IF ONE IS IN THE LIST. &

9020	WHILE M%(4%) &
	\	Z0%(M%(5%),1%)=M%(2%) &
	\	Z0%(M%(2%),0%)=M%(5%) IF M%(2%) &
	\	M%(2%)=M%(4%) &
	\	M%(4%)=0% &
	\ NEXT &
	\ Z0%(0%,9%)=M%(2%) &
	\ Z0%(0%,19%)=M%(0%) &
	&
	\ Z0%(0%,0%)=B0% &
	\ Z0%(0%,26%)=R% &
	\ Z0%(0%,27%)=J9% &
	\ Z0%(0%,49%)=FATAL.ERR% &
	&
	\ W$=SYS(CHR$(8%)+CVT%$(0%)+FNU$(Z0%(0%,12%),NULSTG$,-1%, &
		-1%)) IF P0% &
	\ CLOSE Z% FOR Z% = 1% TO 12% &
	\ ON ERROR GOTO 19000 &
	\ IF P0% THEN &
		CHAIN P$ LINE 31000 &
	  ELSE	STOP &
	\	GOTO 32767 &
	&
		! THIS LINE PLACES THE HEAD POINTERS OF THE COMPLETE &
		!  MESSAGE AND INCOMPLETE MESSAGE LISTS INTO THE WORK- &
		!  FILE FOR RETRIEVAL BY THE NEXT MODULE.  IF ANY &
		!  'UNPROCESSED' REQUESTS ARE PRESENT, THEY ARE PUT AT &
		!  THE FRONT OF THE 'COMPLETED' MESSAGES LIST. &
	&
		! REPLACE THE FREE-LIST POINTER, THE PACKAGE STATUS, AND &
		!  THE CURRENT JOB NUMBER IN THE FILE HEADER RECORD. &
	&
		! PUT THE WORK-FILE NAME INTO CORE COMMON IF A CHAIN IS &
		!  TO BE DONE; &
		! CLOSE THE FILES; &
		! IF THERE WAS A CHAIN RECORD, THEN &
		!	DO THE CHAIN; &
		! ELSE	GO DO THE FINAL CLOSE OUT. &
	&
	&
	&
	&

11000	! GET ANY WAITING OUTPUT. &

11010	ON ERROR GOTO 11095 &
	\ GET #6% &
	\ ON ERROR GOTO 19000 &
	\ FIELD #6%, RECOUNT AS O$ &
	\ OUTPUT$=OUTPUT$+O$ &
		! SET UP ERROR TRAP FOR GET. &
		! GET DATA FROM PK. &
		! FIELD THE BUFFER WITH O$ &
		! OUTPUT$ HOLDS THE CURRENT OUTPUT STRING. &

11020	I%=INSTR(1%,OUTPUT$,CHR10$) &
	\ I%=32760% UNLESS I% &
	\ JJ%=INSTR(1%,OUTPUT$,CHR12$) &
	\ I%=JJ% IF JJ% AND JJ%<I% &
	\ JJ%=INSTR(1%,OUTPUT$,CHR13$) &
	\ IF JJ% AND JJ%+1%<I% THEN &
		IF LEN(CVT$$(MID(OUTPUT$,JJ%,I%-JJ%),4%))=0% THEN &
			GOTO 11010 IF I%>LEN(OUTPUT$) &
		ELSE	O$=LEFT(OUTPUT$,JJ%) &
	\		OUTPUT$=RIGHT(OUTPUT$,JJ%+1%) &
	\		Z$=FNP$(SPACE$(13%)+O$) IF LG% &
	\		GOTO 11040 &
		! LOOK FOR A LF AND FLAG IT IF FOUND. &
		! LOOK FOR A FF AND FLAG IT IF BEFORE THE LINE FEED. &
		! IF THE FIRST THING WE ENCOUNTER IS A CR AND IT IS &
		! NOT FOLLOWED BY A LF OR FF, WE MAY HAVE OVERPRINTING. &
		! SEE IF THERE ARE ANY PRINTABLE CHARACTERS BETWEEN THE &
		! CR AND THE NEXT LF OR FF.  IF WE DON'T KNOW YET, GO &
		! BACK AND GET MORE OUTPUT.  IF THERE WON'T BE, WE DON'T &
		! HAVE OVERPRINTING (AT LEAST YET), SO DON'T WORY. &
		! IF THERE WILL BE OVERPRINTING, LOG THE MESSAGE &
		! UP TO THE CR, LOGGING SPACES IN INSTEAD OF THE TIME. &
		! THEN GO CHECK FOR ERRORS IN WHAT WE LOGGED. &

11030	I%=I%+2% IF CVT$%(MID(OUTPUT$,I%+1%,2%))=3328% &
	\ OUT.FLG%=0% UNLESS I%=32760% &
	\ GOTO 11035 IF I%<=LEN(OUTPUT$) &
	\ GOTO 11010 UNLESS I%=32760% AND LEN(OUTPUT$)>=512% &
	\ OUT.FLG%=-1% &
	\ OUTPUT$=OUTPUT$+CHR13$+CHR10$ &
	\ I%=LEN(OUTPUT$) &
		! &
		! IF "CR" AND "NULL" FOLLOWS THE LF OR FF, IT'S PART &
		! OF THE LINE TERMINATOR. &
		! CLEAR FLAG AND OUTPUT RECORD IF TERMINATOR IS FOUND. &
		! GET MORE OUTPUT UNLESS NO TERMINATOR IS FOUND AND &
		! THE OUTPUT STRING HAS REACHED 512 BYTES. &
		! POSSIBLE FILE WITH NO LINE TERMINATORS, SET FLAG AND &
		! OUTPUT WHAT WE HAVE. &

11035	O$=LEFT(OUTPUT$,I%) &
	\ OUTPUT$=RIGHT(OUTPUT$,I%+1%) &
	\ Z$=FNP$(FNT$+"  ") IF LEN(CVT$$(O$,4%)) IF LG% &
	\ Z$=FNP$(O$) IF LG% &
		! IF WE HAVE LOG THE OUTPUT UP THROUGH THE TERMINATOR. &

11040	Z%=ASCII(O$) &
	\ IF Z%=0% AND LEN(O$) THEN &
		O$=RIGHT(O$,2%) &
	\	GOTO 11040 &
		! STRIP OFF ANY LEADING NULLS THAT MAY BE PRESENT &
		! BEFORE WE LOOK FOR ERRORS. &

11050	Z1%=(CVT$%(O$) AND 255%) &
	\ O$=NULSTG$ &
	\ E9%,E8%,Z0%(J9%,50%)=FNE0%("ERROR LEVEL EXCEEDED",-1%) IF &
		((Z%=37%) OR (Z%=63%)) AND (Z%>ERLEV%) AND (Z1%<>32%) &
	\ C$=C9$ IF E9% UNLESS LG% &
	\ C$=C$+C9$ IF E9% AND LG% &
	\ GOTO 11020 &
		! IF WE ARE CHECKING FOR ERRORS AND HAVE A LINE STARTING &
		! WITH A "?" (FATAL) OR "%" (WARNING) FOLLOWED BY ANY &
		! CHARACTER EXCEPT A SPACE, WE HAVE AN ERROR. &

11090	ON ERROR GOTO 19000 &
	\ RETURN &
		! RESET AND RETURN. &

11095	GOTO 11090 UNLESS ERR=11% &
	\ RESUME 11090 UNLESS OUT.FLG% &
	\ RESUME 11090 IF LEN(OUTPUT$)=0% &
	\ Z$=FNP$(FNT$+"  ") IF LG% &
	\ Z$=FNP$(OUTPUT$+CHR13$+CHR10$) IF LG% &
	\ OUTPUT$=NULSTG$ &
	\ RESUME 11090 &
		! &
		! UNEXPECTED ERROR IF NOT END OF FILE. &
		! RESUME UNLESS FILE WITHOUT LINE TERMINATORS. &
		! OUTPUT REMAINING TEXT IF WE HAVE ANY. &
	&

11500	! THIS SUBROUTINE READS THE CONTROL FILE AND DISPATCHES TO ALL &
	! THE LITTLE ROUTINES TO GET THE WORK DONE. THE CONTROL FILE &
	! HAS BEEN SET UP SO THIS ROUTINE DOESN'T HAVE TO BE TOO SMART. &

11510	ON ERROR GOTO 11595 &
	\ INPUT LINE #11%, C$ &
	\ ON ERROR GOTO 19000 &
	\ GOTO 11590 IF LEFT(C$,13%)="?????????????" &
	\ L0%,P%=0% &
	\ Z%=-1% \ Z%=FNR%(CHR13$,1%) WHILE Z% &
	\ Z%=FNR%("$",1%) &
	\ L0%=FNN% IF Z% &
	\ C$=RIGHT(C$,P%+2%) IF L0% &
	\ C$=CVT$$(C$,4%)+CHR13$ UNLESS L0%=6% &
	\ P%=0% &
	\ DTA%=0% UNLESS L0%=6%
11520	E%=0% &
	\ ON L0%+1% GOSUB 	12000,12100,12200,12300,12400, &
				12500,12600,12700,12800,12900, &
				13000,13100,13200,13300,13400, &
				13500 UNLESS (E9%) AND &
			 ((L0%<>6%) AND (L0%<>8%) AND (L0%<>10%)) &
	\ L0%=-3% IF JOBMOD% &
	\ GOTO 11510 UNLESS L0%=-3% &
	\ GOSUB 13000 \ GOTO 11510 UNLESS JOBMOD% &
		! SET THE END OF FILE ERROR TRAP. &
		! INPUT A LINE FROM THE CONTROL FILE. &
		! INITIALIZE THE DISPATCH CODE AND CHARACTER POINTER. &
		! IT IS A DISPATCH CODE IF THE FIRST CHAR IS $. &
		! GET THE DISPATCH CODE. &
		! STRIP OFF THE DISPATCH CODE IF NECESSARY. &
		! CHARACTER POINTER IS ZERO. &
		! NOT DATA UNLESS DISPATCH CODE IS 6. &
		! GOTO THE PROPER ROUTINE DEPENDING DISPATCH CODE. &
		! GET OUT IF A JOBMODIFICATION WAS REQUESTED. &
		! GET ANOTHER LINE UNLESS WE ARE GETTING OUT. &
		! LOG OUT IF WE ARE GETTING OUT. &
		! IF WE ARE GETTING OUT BECAUSE OF AN ERROR WE PRINT &
		! THE REST OF THE LINES AT LEAST. &

11590	ON ERROR GOTO 19000 &
	\ RETURN &
		! RESET AND RETURN. &

11595	E%=ERR &
	\ RESUME 11590 &
		! IF TIS NOT AN EOF ERROR WE DON'T KNOW WHAT IT IS. &
	&

12000	! PURE DATA &

12010	Z%=FNS%(C$) &
	\ RETURN &
		! SEND THE DATA AND RETURN. &
	&

12100	! LOGIN ROUTINE. &

12110  L9%,KBDDB%=0% &
	\ L9%=FNW% IF FNE%=3% &
	\ GOTO 12140 IF L9% &
	\ Z%=FNF%(CHR$(3%)) IF FNC%=28% &
	\ GOSUB 13000 UNLESS FNE%=5% &
	\ Z%=ASCII(MID(SYS(CHR6$+CHR$(-8%)+CHR$(6%)),11%,1%))/2% &
	\ INPUT #11%, PROJ$,PROG$ &
	\ PROJ%=VAL(CVT$$(PROJ$,4%)) &
	\ PROG%=VAL(CVT$$(PROG$,4%)) &
	\ INPUT LINE #11%, Z$ &
	\ Z$=MID(SYS(CHR6$+CHR$(-10%)+Z$),7%,4%) &
	\ REQRTS$=RAD$(SWAP%(CVT$%(Z$)))+RAD$(SWAP%(CVT$%(RIGHT(Z$,3%)))) &
	\ PRIRTS%=PEEK(SWAP%(CVT$%(MID(SYS(CHR6$+CHR$(-12%)),15%,2%)))) &
	\ GOTO 12115 IF REQRTS$<>"RT11  " &
		\ WHILE PRIRTS% <> 0% &
		\ PRIRTS$=RAD$(PEEK(PRIRTS%+2%))+RAD$(PEEK(PRIRTS%+4%)) &
		\ REQRTS$="RSX   " IF PRIRTS$="RSX   " &
		\ PRIRTS%=PEEK(PRIRTS%) &
		\ NEXT &
	! INITIALIZE LOGGED IN FLAG. &
	! WAIT FOR INPUT WAIT IF SOMETHING IS ALREADY RUNNING. &
	! IF WE DIDN'T GET IT WE FAIL. &
	! FORCE A CTRL/C IF NEEDED. &
	! LOG THE CURRENT JOB OUT UNLESS THERE IS NO JOB ON THE &
	! KEYBOARD. &
	! OBTAIN KB NUMBER FOR THE PK: &
	! GET PPN, DESIRED RTS FROM INPUT FILE &
	! REQRTS$ IS GOING TO BE EITHER "DCL" OR "RT11".  IF IT IS "DCL" &
	! THEN WE DON'T NEED TO CHANGE IT, BUT IF NOT, THEN WE WANT TO &
	! SWITCH TO RSX IF IT IS INSTALLED, OR LEAVE IT RT11 IF RSX IS NOT &
	! INSTALLED &

12115	ON ERROR GOTO 12150 &
	\ LOGIN$=SYS(CHR$(6%)+CHR$(-10%)+"[1,2]LOGIN.TSK") &
	\ Z$=	SYS(CHR6$+CHR$(24%)	! SPAWN A JOB LOGGED IN &
		+CHR$(64%+32%+2%)	! RUN A PROGRAM &
		+CHR$(Z%)		! AT KEYBOARD # &
		+MID(LOGIN$,5%,8%)	! RUN [1,2]LOGIN.TSK &
		+CHR$(PROG%)+CHR$(PROJ%)! RUN JOB IN ACCOUNT # &
		+STRING$(3%,0%)+CHR$(1%))! PRIORITY, RUN BURST, MAX SIZE &
	\ ON ERROR GOTO 19000 &
	\ L9%=-1% &

12120	Z$=SYS(CHR6$+CHR$(-3%)) &
	\ DEVPTR%=SWAP%(CVT$%(RIGHT(Z$,7%))) &
	\ JOBTBL%=SWAP%(CVT$%(RIGHT(Z$,11%))) &
	\ Z$=SYS(CHR6$+CHR$(-12%)) &
	\ DEVOKB%=SWAP%(CVT$%(RIGHT(Z$,9%))) &
	\ Z$=SYS(CHR6$+CHR$(-8%)+CHR6$) &
	\ KB%=SWAP%(CVT$%(RIGHT(Z$,11%))) AND 255% &
	\ JOB%=(PEEK(PEEK(PEEK(DEVPTR%+DEVOKB%)+KB%)+2%) AND 255%)/2% &
	\ KBDDB%=PEEK(PEEK(DEVPTR%+DEVOKB%)+KB%) &
	\ ON ERROR GOTO 12190 &
	\ Z$=MID(SYS(CHR6$+CHR$(26%)+CHR$(JOB%)),21%,2%) &
	\ ON ERROR GOTO 19000 &
	\ IF ASCII(Z$)=0% AND ASCII(RIGHT(Z$,2%))=0% THEN &
				R0%,Z0%(J9%,31%)=R0% OR 1% &
	\			L9%=0% &
	\			NOREQUE%=-1% &
	\			GOTO 12140 &
		! SPAWN A JOB AT THE PK, IN THE SPECIFIED PPN, &
		! TO RUN [1,2]LOGIN.TSK, &
		! MARKED AS BATCH ORIGIN JOB &
		! IF ANY OF THESE FAILS THIS PROCEDURE FAILS. &
		! SET THE LOGGED IN FLAG. &
		! GET THE JOB NUMBER, KB DDB, JOB KBM. &
		! IF THERE IS NO PPN, THEN THE JOB FAILED TO LOG ITSELF &
		! IN. SET THE ABORT BIT IN THE STATUS WORD AND ISSUE AN &
		! ERROR. &

12125	GOTO 12130 IF KILLING% &
	\ GOTO 12140 IF FNW%<>0% &
	\ ON ERROR GOTO 12190 &
	\ JUNK$=MID(SYS(CHR6$+CHR$(26%)+CHR$(JOB%)+CHR$(0%)),23%,4%) &
	\ ON ERROR GOTO 19000 &
	\ JOBKBM$=RAD$(SWAP%(CVT$%(LEFT(JUNK$,2%)))) &
		+RAD$(SWAP%(CVT$%(RIGHT(JUNK$,3%)))) &
	\ IF (REQRTS$="DCL   ") OR (JOBKBM$="DCL   ") THEN &
		Z%=FNS%(CHR$(13%)+"$ _SET JOB/KEYBOARD="+REQRTS$+CHR$(13%)) &
	! WAIT FOR PK INPUT WAIT STATE SO IT IS PAST LOGIN.COM, &
	! THEN FIND OUT ITS KBM. &
	! &
	! ENTRY CONDITIONS: &
	! REQRTS$ WILL = "DCL   " IF "/DCL" WAS FOUND ON $JOB CARD, &
	! REQRTS$ WILL = "RT11  " IF NO "$JOB/DCL" AND RSX.RTS NOT INSTALLED &
	! REQRTS$ WILL = "RSX   " IF NO "$JOB/DCL" AND RSX.RTS IS INSTALLED &
	! JOBKBM$ WILL = THE JOB'S KBM AFTER EXECUTING LOGIN.COM. &
	! &
	! ACTION TO TAKE: &
	! IF "/DCL" WAS FOUND ON THE $JOB CARD, THEN SWITCH JOB TO DCL. &
	! OTHERWISE, IF JOB'S KBM = "DCL" THEN SWITCH IT TO RT11 UNLESS &
	!	RSX IS INSTALLED, IN WHICH CASE SWITCH IT TO RSX. &
	! FINALLY, IF JOB'S KBM = ANYTHING BUT DCL, THEN LEAVE IT ALONE. &

12130	ON ERROR GOTO 19000 &
	\ RETURN &
	! EXIT FROM THIS ROUTINE &

12140	E9%,Z0%(J9%,50%)=FNE0%("UNABLE TO LOGIN BATCH JOB",0%) &
	\ R0%,Z0%(J9%,31%)=R0% OR 4% UNLESS NOREQUE% &
	\ GOTO 12130 &
		! PRINT THE ERROR, SET THE REQUE BIT UNLESS NOREQUE% &
		! IS SET AND EXIT. &

12150	NOREQUE%=-1% IF ERR=5% &
	\ RESUME 12140 &
		! SPAWN JOB FAILED, RESUME TO 12140 &

12190	R0%,Z0%(J9%,31%)=R0% OR 1% &
	\ RESUME 12130 &
		! SET THE ABORT BIT IF ANY ERRORS OCCURRED. &
	&

12200	! ERROR LEVEL. &

12210	ERLEV%=FNN% &
	\ RETURN &
		! SET THE ERROR LEVEL AND RETURN. &
	&

12300	! QUEUE/NOQUEUE - DELETE/NODELETE &

12310	P%=0% &
	\ QUE%=FNN% &
	\ RETURN &
		! GET QUE VALUE. &
	&

12400	! ELAPSED TIME LIMIT. &

12410	T9=VAL(CVT$$(C$,4%)) &
	\ RETURN &
		! SET UP THE TIME FROM NOW WHEN THIS JOB SHOULD &
		! TIME OUT. &
	&

12500	! CPU TIME LIMIT. &

12510	C9=VAL(CVT$$(C$,4%)) &
	\ RETURN &
		! SET THE LIMIT AND RETURN. &
	&

12600	! PRINT OR SEND  DATA. &

12610	C$=CVT$$(C$,4%) IF E9% &
	\ Z$=FNP$(C$+C9$) IF E9% IF LG% &
	\ GOTO 12690 IF E9% &
	\ GOTO 12690 IF FNW% &
	\ N%=FNC% &
	\ GOTO 12690 IF (N%=0%) AND DTA% &
	\ Z%=ASCII(RIGHT(C$,LEN(C$))) &
	\ C$=LEFT(C$,LEN(C$)-1%) UNLESS (Z%=27% OR Z%=12%) &
	\ C$=LEFT(C$,LEN(C$)-1%) UNLESS Z% &
	\ N%=FNS%(C$) IF L9% &
		! PRINT THIS LINE TO THE LOG IF WE ARE AT ERROR LEVEL. &
		! RETURN IF WE ARE AT ERROR LEVEL. &
		! WAIT FOR INPUT WAIT. &
		! CHECK WHAT KIND OF WAIT IT IS. &
		! RETURN IF IT IS EDITOR WAIT AND WE ARE SENDING DATA. &
		! OTHERWISE TRY TO SEND THE STRING. &

12690	RETURN &
	&

12700	!  PRIORITY CHANGE. &

12710	N%=ASCII(C$)=45% &
	\ N%=1% UNLESS N% &
	\ P%=P%+1% IF N%<0% &
	\ N%=N%*FNN% &
	\ Z$=SYS(CHR6$+CHR$(-13%)+CHR$(JOB%)+CHR$(-1%)+CHR$(N%)) &
	\ RETURN &
		! SET UP THE PRIORITY VALUE AND SET IT AND RETURN. &
	&

12800	! PRINT LINE. &

12810	Z%=FNW% &
	\ C$=CVT$$(C$,4%) &
	\ Z$=FNP$(C$+C9$) IF LG% &
	\ RETURN &
		! PRINT THE LINE AND RETURN. &
	&

12900	! SEND CONTROL Z IF NECESSARY. &

12910	Z%=FNZ% UNLESS FNW% &
	\ RETURN &
		! DO THE FUNCTION CALL AND RETURN. &
	&

13000	! LOGOUT JOB OR KILL IT IF NECESSARY. &

13010	E8%=0% &
	\ L9%=0% &
	\ Z%=FNH% &
	\ FOR DEV%=1% TO D8% &
		\ PHY$=LEFT(DEVICE$(DEV%),INSTR(1%,DEVICE$(DEV%),":")) &
		\ GOSUB 13340 &
	\ NEXT DEV% &
	\ D8%=0% \ DEVICE$(DEV%)=NULSTG$ FOR DEV%=1% TO 12% &
	\ Z%=FNK% &
	\ RETURN &
		! DISMOUNT AND DEASSIGN ALL DEVICES. &
		! TRY LOGOUT OR KILL. &
		! RETURN &
	&

13100	! MESSAGE. &

13110	N%=0% &
	\ P%=1% IF ASCII(C$)=36% &
	\ N%=FNN% IF P% &
	\ C$=RIGHT(C$,P%+2%) IF P% &
	\ C$=CVT$$(C$,4%) &
	\ RETURN IF L0%=13% &
	\ T$=C$ &
	\ T$=T$+" - OPERATOR RESPONSE NECESSARY." IF N%=1% &
	\ T$=T$+C9$+CHR9$+CHR9$+"From JOB: "+JOB$ &
	\ GOSUB 23500 &
	\ F1%=16402% AND (N%=1%) &
	\ GOSUB 21000 &
	\ F1%=0% &
	\ F2%=F2% AND (NOT 16384%) &
	\ RETURN &
		! FIND OUT IF WE HAVE TO WAIT. &
		! SET UP THE MESSAGE STRING. &
		! SEND IT AND PAUSE IF WE HAVE TO. &
	&

13200	! MOUNT COMMAND. &

13210	E9%,Z0%(J9%,50%)=FNE0%("TOO MANY MOUNTED DEVICES",-1%) IF D8%>=12% &
	\ GOTO 13290 IF E9% &
	\ D8%=D8%+1% &
	\ FOR Z%=1% TO 5% &
		\ N%=INSTR(1%,C$,",") &
		\ PHY$=LEFT(C$,N%-1%) IF Z%=1% &
		\ CHANGE SYS(CHR6$+CHR$(-10%)+PHY$) TO Z% &
		\ TYPE%=STATUS AND 255% IF Z%=1% &
		\ TYPE%=14% IF TYPE%=0% AND ASCII(PHY$)=77% AND &
			Z%(29%)+SWAP%(Z%(30%))<0% AND Z%=1% &
		\ TYPE%=6% IF TYPE%=0% AND ASCII(PHY$)=76% AND &
			Z%(29%)+SWAP%(Z%(30%))<0% AND Z%=1% &
		\ TYPE%=-1% IF TYPE%=0% AND &
			Z%(29%)+SWAP%(Z%(30%))<0% AND Z%=1% &
		\ LOGI$=LEFT(C$,N%-1%) IF Z%=2% &
		\ VID$ =LEFT(C$,N%-1%) IF Z%=3% &
		\ WRI$ =LEFT(C$,N%-1%) IF Z%=4% &
		\ DEN$ =LEFT(C$,N%-1%) IF Z%=5% &
		\ C$=RIGHT(C$,N%+1%) &
	\ NEXT Z% &
	\ Z%=INSTR(1%,LOGI$,":") &
	\ LOGI$=LEFT(LOGI$,Z%-1%)+RIGHT(LOGI$,Z%+1%) IF Z% &
	\ PAR$=CVT$$(C$,4%) &
	\ RO%=0% &
	\ RO%=128%+32% IF LEN(WRI$) &
	\ WRI$="WRITE ENABLED" UNLESS LEN(WRI$) &
	\ R$=NULSTG$ &
		! IF THIS WOULD BE THE 13TH MOUNT, WE ISSUE AN ERROR AND &
		! RETURN. &
		! GET ALL THE PARAMETERS OUT OF THE STRING. &

13220	T$="INVALID DEVICE - TRY AGAIN" IF LEN(R$) &
	\ GOSUB 23500 IF LEN(R$) &
	\ GOTO 13290 IF (PHY$="SY:") OR (PHY$="PS:") OR (JOBMOD%) &
	\ T$="MOUNT "+PHY$+LOGI$ &
	\ T$=T$+"/IDENT:"+VID$ IF LEN(VID$) &
	\ T$=T$+"/"+WRI$ IF LEN(WRI$) &
	&
	\ T$=T$+"/DEN:"+DEN$ IF LEN(DEN$) &
	\ T$=T$+"/PAR:"+PAR$ IF LEN(PAR$) &
	\ T$=T$+C9$+"DEVICE ? " &
	\ T$=T$+C9$+CHR9$+CHR9$+"For JOB: "+JOB$ &
	\ F2%=F2% AND 32767% &
	\ F1%=NOT32767%+2%+16% &
	\ GOSUB 23500 &
	\ GOSUB 21000 &
	\ F1%=0% &
	\ F2%=F2% AND 32767% &
	\ GOTO 13220 UNLESS LEN(R$) &
	\ ON ERROR GOTO 13240 &
	\ CHANGE SYS(CHR6$+CHR$(-10%)+R$) TO Z% &
	\ GOTO 13220 UNLESS (TYPE%=(STATUS AND 255%)) OR TYPE%<0% &
	\ GOTO 13220 IF (((Z%(29%)+SWAP%(Z%(30%))) AND -31079%)	OR &
		(Z%(29%)+SWAP%(Z%(30%)) AND 8192%)=0%)		AND &
			 (JOBMOD%=0%) &
		! -31079%=1%+8%+16%+128%+512%+1024% EQV 32767% &
	\ R$=R$+LOGI$ &
	\ GOTO 13290 IF JOBMOD% &
	\ TYPE%=STATUS AND 255% &
		! BUILD THE STRING AND SEND THE MESSAGE EXPECTING A &
		! RESPONSE. &
		! IF IT IS AN INVALID RESPONSE, GO BACK. &
		! IF JOBMODIFICATION WAS REQUESTED, GET OUT. &

13230	PHY$=R$ &
	\ GOTO 13260 IF TYPE% &
	\ ON ERROR GOTO 13240 &
	\ CHANGE SYS(CHR6$+CHR$(-10%)+PHY$) TO Z% &
	\ Z%(1%)=6% &
	\ Z%(2%)=3% &
	\ Z%(3%)=0% &
	\ Z%(I%)=0% FOR I%=11% TO 22% &
	\ Z%(18%)=RO% &
	\ CHANGE Z% TO Z$ &
	\ Z1$=SYS(Z$)
13235	Z%(2%)=3% &
	\ Z%(3%)=6% &
	\ CHANGE Z% TO Z$ &
	\ Z1$=SYS(Z$) &
	\ GOTO 13280 &
		! THE PHYSICAL DEVICE BECOMES THE PHY$+LOGI$. &
		! IF ITS NOT A DISK, GOTO 13260. &
		! OTHERWISE SET THE READ ONLY BYTE AND TRY THE MOUNT &
		! AND UNLOCK. &

13240	RESUME 13220 IF ERL=13220% &
	\ E%=ERR &
	\ RESUME 13245 &

13245	E9%,Z0%(J9%,50%)=FNE0%("DISK MOUNT FAILURE - " &
		+CVT$$(RIGHT(SYS(CHR6$+CHR$(9%)+CHR$(E%)),3%),4%),-2%) &
		IF (E%<>18%) AND (E%<>8%) &
			! GET THE RSTS TEXT STRING FOR THE ERROR &
			!  8% = ?Device not available &
			! 18% = ?Illegal SYS() usage &
	\ E%=0% &
	\ GOTO 13290 &
		! OTHERWISE QUIT. &

13260	GOTO 13280 UNLESS TYPE%=14% &
	\ GOTO 13280 UNLESS (DEN$<>NULSTG$) OR (PAR$<>NULSTG$) OR &
						INSTR(1%,PHY$,".") &
	\ ON ERROR GOTO 13270 &
	\ Z$=SYS(CHR6$+CHR$(-10%)+PHY$) &
	\ Z1$=SYS(CHR6$+CHR10$+STRING$(20%,0%)+RIGHT(Z$,23%))
13265	OPEN LEFT(PHY$,INSTR(1%,PHY$,":")) AS FILE 9% &
	\ DEN%=800% &
	\ DEN%=VAL(DEN$) IF LEN(DEN$) &
	\ DEN%=DEN% OR 16384% IF PAR$="EVEN" &
	\ N%=FNP9%(DEN%,9%) &
	\ Z%=FNE0%("CAN'T SET PARITY/DENSITY ON MAGTAPE",0%) UNLESS N% &
	\ CLOSE 9% &
	\ GOTO 13275 UNLESS N% &
	\ Z$=SYS(CHR6$+CHR$(-10%)+PHY$) &
	\ Z1$=SYS(CHR6$+CHR10$+CVT4.0$+CHR$(JOB%)+CHR0$+RIGHT(Z$,9%)) &
	\ GOTO 13280 &
		! ASSIGN THE MAGTAPE. &
		! OPEN THEN MAGTAPE. &
		! SET THE DENSITY PARITY. &
		! CLOSE THE MAGTAPE. &
		! REASSIGN THE MAGTAPE. &

13270	N%=-1% &
	\ RESUME 13275 &

13275	GOTO 13280 IF ERL=13260% &
	\ Z$=SYS(CHR6$+CHR$(-10%)+PHY$) &
	\ Z1$=SYS(CHR6$+CHR$(11%)+STRING$(20%,0%)+RIGHT(Z$,23%)) IF &
			(ERL=13265%) OR ((E9%) AND (N%=0%)) &
		! CAN'T ASSIGN, LET HIM/HER DO THE SAME. &
		! CAN'T OPEN, SET PARITY/DENSITY, OR REASSIGN, THEN &
		!      DEASSIGN. &

13280	DEVICE$(D8%)=PHY$ &
	\ DEVICE$(D8%)=LEFT(PHY$,INSTR(1%,PHY$,".")-1%) IF INSTR(1%,PHY$,".") &
	\ C$="ASSIGN "+LEFT(PHY$,INSTR(1%,PHY$,":")) &
	\ C$=C$+RIGHT(PHY$,INSTR(1%,PHY$,".")) IF INSTR(1%,PHY$,".") &
	\ C$=C$+CHR13$ &
	\ GOSUB 13400 IF TYPE% &
	\ C$="ASSIGN "+LEFT(PHY$,INSTR(1%,PHY$,".")-1%) &
	\ C$=C$+PHY$ UNLESS INSTR(1%,PHY$,".") &
	\ C$=C$+CHR13$ &
	\ GOSUB 13400 &
		! PUT THE DEVICE NAME INTO THE TABLES. &
		! ASSIGN THE DEVICE AND RETURN. &

13290	ON ERROR GOTO 19000 &
	\ RETURN &
	&
	&

13300	! DISMOUNT COMMAND. &

13310	GOSUB 13110 &
	\ Z%=INSTR(1%,C$,":") &
	\ C$=LEFT(C$,Z%-1%)+RIGHT(C$,Z%+1%) IF Z% &
	\ FOR Z%=1% TO D8% &
		\ GOTO 13320 IF &
		   C$=RIGHT(DEVICE$(Z%),INSTR(1%,DEVICE$(Z%),":")+1%) &
	\ NEXT Z% &
	\ GOTO 13390 &
		! IF WE DON'T FIND THE NAME IN THE TABLES ITS A NOOP. &

13320	PHY$=LEFT(DEVICE$(Z%),INSTR(1%,DEVICE$(Z%),":")) &
	\ LOGI$=RIGHT(DEVICE$(Z%),INSTR(1%,DEVICE$(Z%),":")+1%) &
	\ D8%=D8%-1% &
	\ DEVICE$(Z%)=DEVICE$(Z%+1%) FOR Z%=Z% TO D8% &
		! GET THE NAME OF THE DEVICE TO DISMOUNT. &
		! TAKE ITS NAME OUT OF THE TABLES. &

13340	GOTO 13390 UNLESS LEN(PHY$) &
	\ Z$=SYS(CHR6$+CHR$(-10%)+PHY$) &
	\ TYPE%=STATUS AND 255% &
	\ ON ERROR GOTO 13350 &
	\ Z1$=SYS(CHR6$+CHR10$+STRING$(14%,0%)+CVT%$(SWAP%(-32767%))+ &
		STRING$(4%,0%)+RIGHT(Z$,23%)) IF TYPE%=14% &
	\ C$="DEASSIGN "+LOGI$+CHR13$ &
	\ GOSUB 13400 &
	\ C$="DEASSIGN "+PHY$+CHR13$ &
	\ GOSUB 13400 IF TYPE% &
	\ ON ERROR GOTO 13350 &
	\ OPEN PHY$ AS FILE 9% IF TYPE%=14% &
	\ I%=MAGTAPE(1%,0%,9%) IF TYPE%=14% &
	\ CLOSE 9% IF TYPE%=14% &
	\ Z$=SYS(CHR6$+CHR$(-10%)+PHY$) &
	\ Z1$=SYS(CHR6$+CHR$(11%)+STRING$(20%,0%)+RIGHT(Z$,23%)) IF TYPE%=14% &
	\ GOTO 13360 IF TYPE% &
	\ Z1$=SYS(CHR6$+CHR$(3%)+CHR$(4%)+RIGHT(Z$,4%)) &
	\ Z$=SYS(CHR6$+CHR$(3%)+CHR$(2%)+RIGHT(Z$,4%)) &
	\ GOTO 13360 &
		! DO A FILENAME STRING SCAN ON THE DEVICE. &
		! DEASSIGN THE DEVICE. &
		! IF ITS A MAGTAP REWIND AND OFF-LINE. &
		! IF ITS A DISK TRY TO DISMOUNT IT. &

13350	Z$=SYS(CHR6$+CHR$(-10%)+PHY$) &
	\ Z1$=SYS(CHR6$+CHR$(11%)+STRING$(20%,0%)+RIGHT(Z$,23%)) IF TYPE%=14% &
	\ RESUME 13360 &
		! LET'S BE SURE WE DON'T OWN THE DEVICE. &
		! CONTINUE ON DISMOUNT ERROR. &

13360	T$="DISMOUNT "+PHY$ &
	\ T$=T$+" - OPERATOR RESPONSE NECESSARY." IF N%=1% &
	\ T$=T$+C9$+CHR9$+CHR9$+"For JOB: "+JOB$ &
	\ GOSUB 23500 &
	\ F1%=16402% AND (N%=1%) &
	\ GOSUB 21000 &
	\ F1%=0% &
	\ F2%=F2% AND (NOT 16384%) &
		! AND NOTIFY THE OPERATOR. &

13390	ON ERROR GOTO 19000 &
	\ RETURN &
	&

13400	! EDITOR WAIT NEEDED BEFORE SENDING COMMAND. &

13410	Z%=FNS%(C$) UNLESS FNH% &
	\ RETURN &
		! SEND THE COMMAND IF WE CAN GET EDITOR WAIT. &
	&

13500	! DATA INDICATOR NEEDS SETTING. &

13510	DTA%=-1% &
	\ RETURN &
		! SET AND RETURN. &
	&

15000	DEF* FNM0$(T$,J9%,P0%,E%,PGEFLG%) &

15010	T$=T$+" - " IF LEN(T$) &
	\ IF J9% THEN &
		T$=T$+" JOB : "+FNU$(J9%,NULSTG$,129%,0%) &
	\	IF P0% THEN &
			T$=T$+"	FILE - "+FNU$(P0%,NULSTG$,-1%,0%) &
	\		IF PGECNT% THEN &
				T$=T$+C9$ &
	\			T$=T$+"PAGE : "+NUM1$(PGECNT%)+ &
				 "	" IF PGEFLG% &
	\			T$=T$+"BLOCK : "+NUM1$(BLKCNT%) &

15090	T$=T$+C9$+ &
		CVT$$(RIGHT(SYS(CHR6.9$+CHR$(E%)),3%), &
			4%) IF E% &
	&
	\ FNM0$=T$ &
	&
	\ FNEND &
		! AND EXIT. &
	&

15100	DEF* FNC% &
	\FNC%,Z%=FNP6%(6%,"?") &
	\FNC%=-1% IF Z%<>0% AND Z%<>3% AND Z%<>28% &
	\FNEND &
		! CONTROL/C NEEDED CHECK &
		!  0=EDITOR WAIT &
		!  3=NOT WAIT &
		! 28=INPUT WAIT, NOT EDITOR &
		! -1=ERROR(NO JOB ON PK) &

15200	DEF* FNE%=FNP6%(4%,"?") &
		! ERROR STATUS CHECK &
		! 5=NO JOB ON PK &
		! 3=DEVICE IN USE &
		! 0=INPUT WAIT &
	&

15400	DEF* FNP9%(DEN%,C1%) &
	\ FNP9%=0% &
		! SET THE DENSITY AND PARITY ON CHANNEL C1% TO DEN%. &
		! RETURNS:	0% IF SETTING IS ILLEGAL FOR THE DRIVE. &
		!		-1% IF DENSITY AND PARITY HAS BEEN SET. &
		!		S8% AS MAGTAPE STATUS WORD (ALWAYS). &

15410	Z2%=0% &
	\ S8%=MAGTAPE(7%,0%,C1%) &
	\ Z2%=-1% IF DEN%=1600% AND (S8% AND 16%)=0% &
	\ Z1%=((DEN% AND 16384%)/16384%)+8192% &
	\ DEN%=DEN% AND (NOT 16384%) &
	\ Z1%=Z1%+4% IF (S8% AND 4096%)<>0% AND DEN%=556% &
	\ Z1%=Z1%+8% IF (S8% AND 4096%)<>0% AND DEN%=800% &
	\ Z1%=Z1%+256% IF DEN%=1600% &
	\ Z1%=Z1%+12% IF (S8% AND 4096%)=0% AND DEN%=800% &
	\ S8%=MAGTAPE(6%,Z1%,C1%) &
	\ S8%=MAGTAPE(7%,0%,C1%) &
	\ GOTO 15450 IF Z1%<>((S8% AND 24576%)/8192%)*4%+ &
			(S8% AND 2048%)/2048% &
		UNLESS (Z1% AND 256%)=(S8% AND 8%)*32% &
	\ FNP9%=-1% UNLESS Z2% &
		! GET THE MAGTAPE STATUS INTO S8%. &
		! IF THE DENSITY IS ILLEGAL FOR THE DRIVE, EXIT. &
		! IF OK, CALCULATE THE 'MODE' VALUE AND SET THE DENSITY/ &
		! PARITY. SET THE RETURN VALUE AND EXIT. &

15450	FNEND &
	&

15500	DEF* FNE0%(M$,ABO%) &
	\ FNE0%,JOB.ERR%=-1% &
	\ Z$=FNP$("?????????????"+M$+C9$) IF LG% &
	\ Z$=FNP$(FNT$+"??"+C9$) IF LG% &
	\ R0%,Z0%(J9%,31%)=R0% OR 1% IF ABO% &
	\ FNEND &
		! PRINT ERROR MESSAGE TO LOG &
		! -1% IS ALWAYS RETURNED &

15800	DEF* FNF%(D$)=FNP6%(9%,D$) &
		! FORCE DATA TO PSUEDO KEYBOARD. DATA MUST GO. &
	&

16000	DEF* FNH% &
	\ FNH%=-1% &
		! GET US TO COMMAND MODE USING CTRL/C IF NECESSARY. &

16010	Z%=FNF%(CHR$(3%)+CHR$(3%)) IF L0%=-3% &
	\ GOTO 16030 IF FNW%
16015	Z%=FNC% &
	\ GOTO 16020 UNLESS Z% &
	\ GOTO 16030 IF Z%<0% &
	\ Z%=FNZ% &
	\ Z%=FNZ% &
	\ Z%=FNC% &
	\ GOTO 16020 UNLESS Z% &
	\ GOTO 16010 IF FNS%(CHR$(3%)+CHR$(3%)) &
	\ Z%=FNW% &
	\ GOTO 16015 &
		! IF WE ARE ENDING UP SEND TWO CONTROL C'S WITHOUT TESTS &
		! FAIL IF WE CAN'T GET AN INPUT WAIT. &
		! DO CONTROL C NEEDED CHECK. &
		! SUCCEED IF EDITOR WAIT. &
		! FAIL IF NO JOB ON PK. &
		! Send 2 CTRL-Z's in case we're in BP2. &
		! OTHERWISE TRY TO SEND A CONTROL C. &

16020	FNH%=0% &
		! SUCCESS (I.E. WE ARE AT COMMAND MODE.) &

16030	FNEND &

16100	DEF* FNI% &
	\FNI%,Z%=FNE% &
	\FNI%=-1% IF Z%<>0% AND Z%<>3% &
	\FNEND &
		! INPUT WAIT CHECK &
		!  0=INPUT WAIT &
		!  3=NOT WAIT &
		! -1%=ERROR(NO JOB ON PK) &
	&

16200	DEF* FNK% &
	\FNK%=-1% &
	\IF FNH% GOTO 16250 &
		! INITIALIZE FUNCTION, IF WE CAN'T SEND A CTRL/C 16250 &

16210	IF FNS%("BYE"+CHR13$) GOTO 16250 &
	ELSE IF FNW% GOTO 16250 &
		ELSE IF FNS%("YES"+CHR13$) GOTO 16250 &
		! TRY USING LOGOUT TO GET OUT. &

16220	IF FNW% THEN &
	GOSUB 11000 &
	\ Z$=FNP$(C9$+CHR$(12%)) IF LG% &
	\ GOTO 16250 IF FNE%<>5% &
	\FNK%=0% &
	\GOTO 16260 &
		! LOGOUT WAS SUCCESSFUL. SET RETURN VALUE TO 0%, RETURN. &

16250	GOTO 16260 IF FNE%=5% &
	\ Z%=FNE0%("JOB BEING KILLED",-1%) &
	\ KILLING%=-1% &
	\ GOSUB 12120 &
	\ ON ERROR GOTO 16270 &
	\ Z$=SYS(CHR6$+CHR$(8%)+CHR$(JOB%)+SPACE$(23%)+CHR$(0%)+CHR$(255%)) &
			IF JOB% &
		! OUTRIGHT KILL THE JOB WITH A SYS(6,8) CALL &
		! IF LOGOUT WAS UNSUCCESSFUL. &

16260	ON ERROR GOTO 19000 &
	\ FNEND &

16270	RESUME 16260 &
		! IF WE GET AN ERROR ON THE KILL IGNORE IT (MEANS THE JOB &
		! PROBABLY WENT AWAY ON IT'S OWN.) &
	&

16600	DEF* FNP6%(R%,D$) &
	\FNP6%=0% &
		! THIS FUNCTION ACTUALLY PUTS DATA TO PK. &
		! 0% IS NORMAL RETURN. &

16610	ON ERROR GOTO 16620 &
	\ LEN.D%=LEN(D$) &
	\ LEN.D%=BUFSIZ(6%) IF LEN.D% > BUFSIZ(6%) &
	\ FIELD #6%,LEN.D% AS O$ &
	\ LSET O$=D$ &
	\ PUT #6%,RECORD R%,COUNT LEN.D% &
	\ GOTO 16630 IF LEN.D% = LEN(D$) &
	\ D$=RIGHT(D$,LEN.D%+1%) &
	\ GOTO 16610 &
		! SET UP AND SEND DATA, GO BACK AND SEND MORE IF MORE THAN ONE &
		! BUFFER FULL. &

16620	FNP6%=ERR &
	\ E9%,Z0%(J9%,50%)=FNE0%("CONTROLLED JOB NO LONGER LOGGED IN",0%) &
							IF L9% AND ERR=5% &
	\RESUME 16630 &
		! IF IT DIDN'T WORK SEE WHY. &

16630	ON ERROR GOTO 19000 &
	\FNEND &
	&

16800	DEF* FNS%(D$) &
	\FNS%=-1% &
	\FNS%=(FNP6%(8%,D$)<>0%) UNLESS FNW% &
	\FNEND &
		! SEND DATA TO PK &
		!  0=ALL DATA SENT &
		! -1=ERROR(NOT WAIT, NOT LOGGED IN) &
	&

16900	DEF* FNM(N,D)=N-INT(N/D)*D &
		! REMAINDER OF N/D. &
	&

17000	DEF* FNT$ &
	\ Z$=TIME$(0%) &
	\ SEC$=MID(NUM$(100%+FNM(TIME(0%),60.)),3%,2%) &
	\ Z2$=TIME$(0%) &
	\ IF Z$=Z2$ THEN &
			FNT$=LEFT(Z$,5%)+":"+SEC$+RIGHT(Z$,6%) &
	ELSE &
			FNT$=LEFT(Z2$,5%)+":00"+RIGHT(Z2$,6%)
17010	FNEND &
		! TOD IN 'HH:MM:SS AM' FORMAT. &
		! A "DOUBLE CHECK" MAKES SURE MINUTES HASN'T CHANGED. &
	&

17100	DEF* FNW% &
		! WAIT FOR INPUT WAIT. &

17110	GOSUB 11000 &
	\FNW%,H%=FNI% &
	\IF H%<=0% THEN GOTO 17130 &

17112	ON ERROR GOTO 17113 &
	\ UU0.SYS.PK$=SYS(CHR6$+CHR$(26%)+CHR$(JOB%)+CHR$(0%)) &
		! Get the PK job's times for /LIMIT and /CPU timeouts. &
	\ GOTO 17114 &

17113	RESUME 17114 &
		! In case the PK job disappeared. &
		! Note: The following code assumes that UU0.SYS.PK$ will &
		!	contain all chr$(0)'s if we come through here. &

17114	ON ERROR GOTO 19000 &
	\ UU0.SYS$=SYS(CHR6$+CHR$(26%)+CHR$(0%)+CHR$(0%)) &
		! Get BATRUN's times for /LIMIT and /CPU timeouts. &
	\ T=SWAP%(CVT$%(MID(UU0.SYS$,7%,2%))) &
		! BATRUN's CPU time LSB &
	\ T=T+65536. IF T<0. &
		! Convert it &
	\ T=T+65536.*ASCII(MID(UU0.SYS$,16%,1%)) &
		! Add in the MSB &
	\ T1=SWAP%(CVT$%(MID(UU0.SYS.PK$,7%,2%))) &
		! Get the PK job's CPU time LSB &
	\ T1=T1+65536. IF T1<0. &
		! Convert it &
	\ T1=T1+65536.*ASCII(MID(UU0.SYS.PK$,16%,1%)) &
		! Add in the MSB &
	\ T=T+T1 &
		! Time limit is based on sum of PK job's and BATRUN's times &
	\ GOTO 17120 IF T>=C9 IF L9% &
		! Time out if we exceeded the user's value &
	\ T=SWAP%(CVT$%(MID(UU0.SYS$,9%,2%)))*60. &
		! Get BATRUN's connect time in minutes * 60 &
		! (The user's /limit value was multiplied by 60 as well) &
	\ T1=SWAP%(CVT$%(MID(UU0.SYS.PK$,9%,2%)))*60. &
		! Get the PK job's connect time in minutes * 60 &
	\ T=T+T1 &
		! Add 'em up to get the total connect time. &
		! Note: There will be no BATRUN connect time unless &
		!	someone is attached to BATRUN &
	\ GOTO 17120 IF T>=T9 IF L9% &
	\ F1%=17% \ S0%=1%  \ SVE$=C$ &
	\ P%=FNPUSH%(P%) \ N%=FNPUSH%(N%) &
	\ GOSUB 21000 \ N%=FNPOP% \ P%=FNPOP% \ F1%=0% &
	\ C$=SVE$ &
	\ GOTO 17110 UNLESS JOBMOD% &
		! WAIT. &

17120	L0%=-3% &
	\ T9,C9=4294970000. &
	\ FNW%,E9%,Z0%(J9%,50%)= &
	FNE0%("Time limit exceeded",-1%) OR FNH% UNLESS JOBMOD% &
		! TIMED OUT. &

17130	GOSUB 11000 &
	\ FNW%=-1% IF E8% &
	\FNEND &
		!  0=INPUT WAIT &
		! -1=ERROR OR TIMED OUT &

17300	DEF* FNZ% &
	\FNZ%=-1% &
	\IF FNC%<0% GOTO 17330 &
	 ELSE IF FNC%=28% THEN &
		IF FNS%(CHR$(26%)) GOTO 17330 &
		! SEND CTRL/Z IF NEEDED. &

17310	FNZ%=0% &
		! INDICATE A NORMAL RETURN. &

17330	FNEND &
	&
	&

17400	DEF* FNP$(L$) &
	\ ON ERROR GOTO 17420 &
	\ PRINT #2%, L$; &
		! SET THE ERROR TRAP AND PRINT THE LINE. &

17410	ON ERROR GOTO 19000 &
	\ FNEND &

17420	E%=ERR &
	\ RESUME 17430 &

17430	LG%=0% &
	\ T$=JOB$+": "+RIGHT(SYS(CHR$(6%)+CHR$(9%)+CHR$(E%)),3%)+ &
			" ON LOG FILE -- JOB ABORTED." &
	\ E%=0% &
	\ GOSUB 23500 &
	\ GOSUB 21740 &
	\ GOTO 17410 &
		! LOG THE ERROR, ABORT THE JOB AND EXIT. &
	&

19000	&
	&
	&
	!	U N E X P E C T E D    O R    U N R E C O V E R A B L E &
	!		E R R O R    H A N D L E R &
	&

19005	IF ERL=19990% THEN &
	   T$="FATAL ERROR WHILE NO ACCESS TO WORK-FILE: ERR=" &
	     +NUM1$(E%)+"ERL="+NUM1$(E1%) &
	\  PRINT T$ &
	\  STOP &
	!  PUT THE JOB INTO HIBERNATION WHILE THE JOB IS DETACHED &

19010	E%=ERR \ E1%=ERL \ RESUME 19020 &
		! SET UP THE ERROR VALUE AND LINE; &
		! MAKE SURE OF THE RESUME. &

19020	ON ERROR GOTO 19000 &
	\ IF ERL=21160 AND (F1% AND 16384%) THEN &
		GOTO 21170 &
		! RESET ERROR TRAP. &
		! TRAP ERRORS ON RECEIVE SLEEP FOR PAUSE. &

19990	FATAL.ERR% = ERR &
	\ Z0%(0%,50%) = ERL &
	\ Z0%(0%,51%) = 3260% &
	\ Z0%(0%,52%) = 29654% &
	\ Z$ = SYS(CHR6.M10$ + MID(I$,2%,3%) + RIGHT(I$,6%)) &
	\ Z0%(0%,53%) = CVT$%(MID(Z$,7%,2%)) &
	\ Z0%(0%,54%) = CVT$%(MID(Z$,9%,2%)) &
	\ GOTO 2000 &
		! PACK IN FATAL ERROR DATA INTO WORK FILE. &
		!	ERROR CODE &
		!	ERROR LINE &
		!	"BAT" IN RAD$() FORM &
		!	"RUN" IN RAD$() FORM &
		!	VERSION/EDIT #'S IN RAD$() FORM &
		!	BACK TO MAIN CONTROL POINT. &
	&

20000	Z$=SYS(CHR6.M21.M1$) &
	\	OPEN W$ FOR INPUT AS FILE 1% &
	\	Z$=SYS(CHR6.M21.0$) &
	\ R%=Z0%(0%,26%) &
	\ B0%=Z0%(0%,0%) &
	\ J9%=Z0%(0%,27%) &
	\ Q9%=Z0%(0%,4%) &
	\ FATAL.ERR%=Z0%(0%,49%) &
	\ NOT32767%=NOT 32767% &
	&
	\ M%(0%)=Z0%(0%,19%) &
	\ M%(2%)=Z0%(0%,9%) &
	\ FOR Z%=0% TO 2% STEP 2% &
	\	Z0%=M%(Z%) &
	\	IF Z0% THEN &
			Z0%=Z0%(Z0%,1%) WHILE Z0%(Z0%,1%) &
	\		M%(Z%+1%)=Z0%
20030	  NEXT Z% &
	&
	\ J%=(PEEK(518%) AND 255%)/2% &
	\ J$=NUM1$(J%) \ J$="0"+J$ UNTIL LEN(J$)>1% &
	\ J1%=SWAP%(CVT$%(MID(SYS(UU1$),25%,2%))) &
	\ A%=SWAP%(CVT$%(MID(SYS(UU0$),21%,2%))) &
	\ Z$=NUM1$(SWAP%(A%) AND 255%) \ Z$=" "+Z$ UNTIL LEN(Z$)>2% &
	\	A$="["+Z$ \ Z$=NUM1$(A% AND 255%) &
	\	Z$=" "+Z$ UNTIL LEN(Z$)>2% \ A$=A$+","+Z$+"]" &
	\ K0%=PEEK(J1%) &
	\ K%=(SWAP%(PEEK(PEEK(K0%)+2%)) AND 255%) OR &
		(R% AND 16384%)=0% &
	&
	\ C8$=CHR7$ &
	\ C9$=CHR13$+CHR10$ &
	\ GOSUB 23050 IF (R% AND 2048%) &
	\ GOSUB 23100 IF (R% AND 4096%) &
	&
	\ RETURN &
	&
		! DROP PRIVILEGES, (TRY TO) OPEN THE WORK-FILE, AND &
		!  REGAIN PRIVILEGES; &
		! GET THE STATUS WORD OUT OF THE WORK-FILE; &
		! GET THE (WORK-FILE) FREE-LIST POINTER, THE CURRENT JOB &
		!  POINTER, AND THE OUTPUT VOLUME POINTER INTO SOME &
		!  CONVENIENT (IN-MEMORY) VARIABLES. &
	&
		! THESE TWO LINES SET UP THE HEADS AND TAILS OF THE &
		!  INCOMPLETE MESSAGES AND COMPLETED MESSAGES LISTS. &
		!  THE HEADS OF THE LISTS ARE TAKEN DIRECTLY OUT OF THE &
		!  FILE HEADER RECORD OF THE WORK-FILE; THE TAILS MUST &
		!  BE FOUND BY A SCAN, IF THE LISTS ARE NON-EMPTY. &
	&
		! SET UP PARAMETERS FROM THE EXEC : &
		!	GET THE JOB NUMBER INTO J%; &
		!	SET UP A JOB NUMBER STRING IN J$; &
		!	GET THE ACCOUNT NUMBER OF THIS JOB OUT OF THE &
		!	 JDB OF THE JOB; &
		!	TURN THE ACCOUNT NUMBER INTO AN ACCOUNT NUMBER &
		!	 STRING; &
		!	STORE IN K0% THE ADDRESS OF THE I/O BLOCK FOR &
		!	 THIS JOB, FOR LOOKING UP SUCH THINGS AS THE &
		!	 CURRENT KEYBOARD, FOR ATTACHED/DETACHED, OR THE &
		!	 STATUS OF AN OPEN CHANNEL; &
		!	AND SET UP THE KEYBOARD NUMBER OF THIS JOB'S &
		!	 KEYBOARD, UNLESS THE STATUS FLAG SHOWS THAT &
		!	 THE JOB IS DETACHED. &
	&
		! SET UP TWO USEFUL STRING CONSTANTS : &
		!	C8$	- A ^G (<BELL>) CHARACTER, FOR &
		!		   NOTIFICATION STRINGS &
		!	C9$	- A <CR><LF> STRING FOR GENERAL USE &
		! CALL THE 'ENTER' ROUTINE IF THE JOB IS ENTERED; &
		! CALL THE 'ONLINE' ROUTINE IF THE JOB IS ONLINE TO &
		!  OPSER; &
		! THESE TWO ROUTINES, ENTER, AND ONLINE, SET &
		!  UP APPROPRIATE CONSTANTS AND STRINGS TO DO THE &
		!  REQUIRED POLLING AND COMMUNICATIONS. &
	&
	&
	&
	&
	&
	&

21000	S1%,S2%,S3%=0% &
		! INIT TIMERS TO 0 TO PREVENT A SLEEP ON THE FIRST &
		! TIME THROUGH THE ROUTINE. &
		! TIMERS ARE : &
		!	S1%	- RECEIVE WITH SLEEP TIMER &
		!	S2%	- GET FROM KB: WITH SLEEP TIMER &
		!	S3%	- PLAIN OLD SLEEP TIMER, IN CASE THE &
		!			JOB IS NEITHER ATTACHED NOR A &
		!			RECEIVER. &
	&
	&

21100	TOD.=TIME(0%) &
		! STORE THE ENTRY TIME OF DAY. &

21160	IF (R% AND 2048%) THEN &
		IF (PEEK(J0%) AND -256%) OR (F1% AND 16384%) THEN &
			ON ERROR GOTO 19000 &
	\		M$=SYS(CHR6$+CHR$(18%)+CHR$(1%)) UNLESS F1% AND 16384% &
	\		M$=SYS(CHR6$+CHR$(18%)+CHR$(2%)) IF F1% AND 16384% &
	\		N1%=ASCII(MID(M$,5%,1%))/2% &
	\		N2%=CVT$%(MID(M$,7%,2%)) &
	\		N%=ASCII(MID(M$,9%,1%)) &
	\		M$=MID(M$,10%, &
			   ((N%-1%) AND N%<21%) OR (19% AND N%>20%)) &
	\		N%=(N%<21%) &
	\		GOTO 21200 &
		! IF THIS JOB IS A RECEIVER, THEN &
		!	IF A MSG IS QUEUED, THEN &
		!		GET IT; &
		!		EXTRACT FROM IT THE JOB # (N1%), PPN &
		!		  PPN (N2%); &
		!		SET UP THE 'COMPLETED' FLAG - -1% IF THE &
		!		 MESSAGE IS COMPLETE, 0 OTHERWISE; &
		!		GO STORE IT AWAY. &

21170	IF S1%=0% THEN &
		GOTO 21400 &
	ELSE	SLEEP 1% &
	\	SLEEP 60% EQV 32767% &
	\	S1%=0% &
	\	GOTO 21160 &
		! IF NO WAIT TIMER IS SET FOR A SLEEP (S1%), THEN &
		!	GO EXIT FROM THE 'GET A MESSAGE' LOOP; &
		! ELSE	SLEEP THE ALLOTTED TIME; &
		!	RESET THE TIMER, SO NO SLEEP IS DONE NEXT TIME; &
		!	GO SEE IF ANYTHING ARRIVED WHILE YOU WERE OUT. &
	&

21200	GOTO 21400 IF N1%=0% OR (LEN(M$)=0% AND F1%>=0%) &
	\ M%=M%(0%) &
	\ M%=Z0%(M%,1%) WHILE M% AND Z0%(M%,6%)<>N1% &
	\ IF M%=0% THEN &
		M%=FNA% &
	\	Z0%(M%(1%),1%)=M% IF M%(1%) &
	\	Z0%(M%,1%)=M%(1%) &
	\	M%(0%)=M% UNLESS M%(0%) &
	\	M%(1%)=M% &
	\	Z0%(M%,6%)=N1% &
	\	Z0%(M%,7%)=N2% &
	\	N7%,Z0%(M%,12%)=ASCII(M$) &
	\	IF N7%<6% AND N7%>-1% THEN &
			M$=RIGHT(M$,2%) &
		ELSE	N7%,Z0%(M%,12%)=6% &
		! SKIP THIS ROUTINE IF NO MESSAGE; &
		! FIND THE PLACE TO INSERT IN INCOMPLETE LIST; &
		! IF NO PARTIAL MESSAGE IS FOUND FOR THIS JOB, THEN &
		!	SET UP AND LINK IN A NEW MESSAGE RECORD; &
		!	SET UP THE DISPATCH CODE : &
		!	IF THE FIRST CHR IS ALREADY A DISPATCH CODE, &
		!	 THEN &
		!		REMOVE IT FROM THE RECORD; &
		!	ELSE	SET UP A DISPATCH OF 6, THE DECODE &
		!		 DISPATCH. &

21220	Z0%(M%,1%) = FNPUSH%(Z0%(M%,1%)) &
	\ Z0%(M%,1%)=Z0%(M%,2%) &
	\ M% = FNPUSH%(M%) &
	\ M0%=Z0%(M%,13%) &
	\ M1%=28% &
	\ WHILE M0%>128%-M1% &
	\	M0%=M0%-(128%-M1%) &
	\	M1%=12% &
	\	M%=Z0%(M%,1%) &
	\ NEXT &
	\ M1%=M0%+M1% &
	\ M2%=LEN(M$) &
	\ M3%=0% &

21230	Z$=Z0$(M%) &
	\ Z0$(M%)=Z$+STRING$(M1%-LEN(Z$),0%)+MID(M$,M3%+1%,128%-M1%) &
	\ M3%=M3%+128%-M1% &
	\ IF M3%<M2% THEN &
		M%,Z0%(M%,1%)=FNA% &
	\	M1%=12% &
	\	GOTO 21230 &

21240	M% = FNPOP% &
	\ Z0%(M%,13%)=Z0%(M%,13%)+LEN(M$) &
	\ Z0%(M%,2%)=Z0%(M%,1%) &
	\ Z0%(M%,1%) = FNPOP% &
	\ IF N% THEN &
		M9%=0% \ M8%=2% \ GOSUB 21300 &

21250	GOTO 21400 &
	&

21300	M0%=Z0%(M%,0%) &
	\ M1%=Z0%(M%,1%) &
	\ Z0%(M%,1%)=0% &
	\ Z0%(M0%,1%)=M1% IF M0% &
	\ Z0%(M1%,0%)=M0% IF M1% &
	\ M%(M9%)=M1% UNLESS M0% &
	\ M%(M9%+1%)=M0% UNLESS M1% &
	&
	\ WHILE M8% &
	\	M0%=M%(M8%+1%) &
	\	Z0%(M%,0%)=M0% &
	\	Z0%(M0%,1%)=M% IF M0% &
	\	M%(M8%+1%)=M% &
	\	M%(M8%)=M% UNLESS M0% &
	\	M8%=0% &
	\ NEXT &
	\ RETURN &
	&

21350	T$="Illegal command" &
	\ E%=-1% &
	\ RETURN &
		! IF THE COMMAND ENTERED WAS A RECOGNIZABLE COMMAND, BUT &
		!  WAS NOT LEGAL FOR THIS PROGRAM, THEN &
		!	SET UP AND ISSUE A MESSAGE TO THAT EFFECT; &
		!	EXIT. &
	&
	&

21400	WHILE M%(2%) &
	\	M%=M%(2%) &
	\	P% = Z0%(M%,11%) &
	\	N7%=Z0%(M%,12%) &
	\	C$=FNUNPACK$(M%,26%) &
	\	E%=0% &
	\	ON N7% GOSUB &
			23600,23600,24300,23600,23600,21600,21890,21750, &
			22420,22430,21350,21950,22000,22100,21350,23600, &
			23600,23600,21740,21350,21350,21350,21350,21350, &
			21350,21770,21350,21350,21350,23600 &
				IF N7%>0% AND N7%<31% &
	\	WHILE E% AND M%<>0% &
	\		T$="%"+T$+C9$+"'"+C$+"' Ignored" &
	\		GOSUB 23500 &
	\		E%=0% &
	\	NEXT &
	\	WHILE M% &
	\		M9%=2% \ M8%=0% \ GOSUB 21300 &
	\		Z0%(M%,1%)=0% \ M%=FNA0%(M%) &
	\	NEXT &
	\ NEXT &
	&
	\ IF S3% THEN &
		SLEEP S3% &
	\	S3%=0% &
	\	GOTO 21160 &
	&
		! WHILE THERE ARE ANY COMPLETE MESSAGES : &
		!	SET UP THE MESSAGE NUMBER IN M%; &
		!	DISPATCH TO THE PROPER ROUTINE FOR THE MESSAGE'S &
		!	 TOKEN : &
		!	1   24010	R	NEWJOB FROM QUEMAN &
		!	2   24200	R	ENDJOB FROM QUEMAN &
		!	3   24300	P	KILLJOB FROM QUEMAN &
		!	4   24100	R	NEXT (FILE) PACKET FROM &
		!				 QUEMAN &
		!	5		S	ONLINE REQUEST FROM &
		!				 QUEMAN &
		!	6   21600	P	COMMAND DECODE &
		!	7   21890	P	ONLINE FROM KB:/OPSER &
		!	8   21750	P	OFFLINE FROM OPSER &
		!	9   22420	P	PAUSE &
		!	10  22430	P	CONTINUE &
		!	11  21940	R	TRANSFER THE LOG FILE &
		!	12       	R	INSERT A NOTICE TO THE &
		!				 OUTPUT LOG &
		!	13  22000	P	RETYPE LAST MESSAGE &
		!	14  22100	P	RETURN A STATUS REPORT &
		!	15		R	DISALLOWED LEGAL COMMAND &
		!	16  21700	S	ENTER STEP MODE OR STEP &
		!				 JOB &
		!	17  21720	S	EXIT STEP MODE &
		!	18  21730	S	END OPERATIONS (IE, KILL &
		!				 YOURSELF) &
		!	19  21740	P	ABORT THE CURRENT &
		!				 PROCESS &
		!	20  22300	S	CHANGE FORMS &
		!	21  22400	P	RESTART THE CURRENT &
		!				 PROCESS &
		!	22  21760	P	REQUE THE CURRENT &
		!				 PROCESS &
		!	23  21800	R	SEND THE SPECIFIED &
		!				 FILE(S) NEXT &
		!	24  21800	R	INTERRUPT THE CURRENT &
		!				 PROCESS IN ORDER TO &
		!				 SEND THE SPECIFIED &
		!				 FILE(S) &
		!	25		R	CHANGE THE OUTPUT &
		!				 FILE(S) FOR PRINT OR &
		!				 PUNCH OUTPUT &
		!	26  21770	P	RESPONSE TO BE RETURNED &
		!				 TO CALLER &
		!	27  21900	R	TAKE THE JOB OFF LINE &
		!				 FROM OPSER &
		!	28  21910	R	PUT THE JOB ONLINE TO &
		!				 QUEMAN &
		!	29  21920	R	TAKE THE JOB OFF LINE &
		!				 FROM QUEMAN &
		!	30  		R	DETACH THE JOB &
		!	IF ANY ERROR IS SET UPON RETURN, THEN &
		!		SET UP AND PRINT AN ERROR MESSAGE; &
		!	IF, UPON RETURN FROM THE PROCESS, THE MESSAGE &
		!	 POINTER IS NON-ZERO, THEN &
		!		REMOVE THE MESSAGE FROM THE COMPLETE &
		!		 LIST AND REPLACE IT IN THE FREE-LIST; &
		! LOOP UNTIL NO MORE COMPLETED MESSAGES EXIST. &
	&
		! IN THE ABOVE TABLE, THE ANNOTATION 'S' MEANS THAT ANY &
		!  MESSAGE OF THIS FORM IS STORED IN THE WORK-FILE BY &
		!  PROGRAM FOR LATER PROCESSING BY SOME OTHER MODULE OF &
		!  THE PACKAGE; THE 'P' MEANS THAT THIS MESSAGE TYPE IS &
		!  AT LEAST PARTIALLY PROCESSED BY THIS MODULE OF THE &
		!  PACKAGE; THE 'R' MEANS THAT THE COMMAND IS NOT LEGAL &
		!  FOR THIS PACKAGE, AND HAS BEEN REMOVED FROM THE LEGAL &
		!  COMMAND LIST. &
	&
		! IF THE 'SLEEP TIMER' (S3%) IS NON-ZERO, THEN &
		!	GO INTO A SLEEP FOR MORE DATA; &
		!	RESET SLEEP TIMER SO NO SLEEP IS DONE NEXT TIME; &
		!	GO SEE IF ANYTHING ARRIVED WHILE YOU WERE OUT. &
	&
	&

21500	TOD.=TIME(0%)-TOD. &
	\ TOD.=TOD.+86400. IF TOD.<0. &
	\ IF TOD.>65535. THEN &
		T0%=S0% &
	  ELSE	T0%=TOD.-32768. &
	\	T0%=T0% EQV 32767% &
		! STORE THE ELAPSED EXECUTION TIME; &
		! ADJUST FOR DATE WRAP-AROUND, IF NECESSARY; &
		! IF THE ELAPSED TIME IS GREATER THAN WHAT CAN BE HELD &
		!  IN AN INTEGER, THEN &
		!	SET THE ELAPSED TIME TO THE REQUESTED TIME; &
		! ELSE	PUT IT IN AN INTEGER, ADJUSTING FOR THE SIGN &
		!	 BIT. &

21520	F2%=F2% AND -2% &
	\ T0%=S0%-T0% &
	\ F2%=F2% OR 1% IF T0%=0% OR (T0%<0% AND S0%>-1%) &
	\ T0%=0% IF (F2% AND 1%) &
	\ S0%=T0% &
		! RESET THE 'SLEEP TIME EXPIRED' FLAG; &
		! CALCULATE THE NEW 'SLEEP TIME' VALUE; &
		! SET THE 'SLEEP TIME EXPIRED' FLAG IF EITHER &
		!  THE NEW SLEEP TIME IS 0 &
		!	OR &
		!  THE OLD SLEEP TIME WAS POSITIVE AND THE &
		!  NEW SLEEP TIME IS NEGATIVE (IE, IT WENT THROUGH &
		!  A TRANSITION THROUGH 0); &
		! SET THE NEW SLEEP TIME TO 0 IF THE SLEEP TIME IS &
		!  EXPIRED. &

21530	S1%,S2%,S3%=0% &
	\ IF F1%=0% OR (F1% AND F2%) THEN &
		R%=R% AND -1025% &
	  ELSE	S0%=-1% UNLESS S0% &
	\	S1%=S0% IF (R% AND 4096%) &
	\	S2%=S0% IF (R% AND 20480%)=16384% &
	\	S3%=S0% UNLESS (R% AND 20480%) &
	\	GOTO 21100 &
		! GO MAKE SURE A NEW PROMPT IS PRINTED BEFORE CHECKING &
		!  FOR EXIT; &
		! IF THE EVENT REQUEST FLAG IS NON-ZERO AND NONE OF THE &
		!  EVENTS MATCH, THEN &
		!	ZERO OUT THE TIMERS, TO START WITH; &
		!	SET THE REQUESTED TIME TO INFINITE, IF IT IS NOT &
		!	 SET (IF THE EXPIRATION OF THE TIMER WAS A &
		!	 DESIRED EVENT, THEN THE EVENT FLAG SHOULD HAVE &
		!	 BEEN SET, AND THIS LINE WOULD NOT HAVE BEEN &
		!	 REACHED); &
		!	SET UP THE PROPER TIMER : &
		!		RECEIVE TIMER (S1%) IF THE PROGRAM IS &
		!		 ONLINE TO OPSER OR QUEMAN; &
		!		KEYBOARD TIMER (S2%) IF THE PROGRAM IS &
		!		 ATTACHED AND NOT ONLINE; &
		!		SLEEP TIMER (S3%) IF THE PROGRAM IS &
		!		 NEITHER ONLINE OR ATTACHED; &
		!	GO BACK AND LOOK FOR ANOTHER MESSAGE. &

21540	ON ERROR GOTO 19000 &
	\ R% = R% AND NOT 1536% &
	&
	\ RETURN &
	&
		! RESET ERROR TRAP. &
	&
		! AND EXIT. &
	&
	&

21600	Z%=0% &
	\ IF C$<>NULSTG$ OR (F1%<0% AND (F1% AND F2%)>=0%) THEN &
		RESTORE \ Z$=NULSTG$ \ READ Z$ UNTIL Z$="*STARTCOM" &
	\	P%=0% &
	\	WHILE P%=0% AND T$<>"*ENDCOM" &
	\		READ T$,N7% &
	\		Z%=FNR%(T$,N7%) &
	\		P%=0% UNLESS Z% &
	\		READ Z% &
	\	NEXT &
	\	IF P%=0% THEN &
			IF F1%<0% AND (F1% AND F2%)>=0% THEN &
				Z%=26% &
			ELSE	T$="Unrecognized command" &
	\			E%=-1% &
	\			RETURN &
		! IF THE STRING IS NON-NULL OR THE CALLER IS WAITING &
		!  FOR A RESPONSE, THEN &
		!	GET TO THE BEGINNING OF THE COMMAND TABLE; &
		!	WHILE A MATCH IS NOT FOUND AND THE TABLE IS NOT &
		!	 EMPTY : &
		!		READ THE NEXT ENTRY; &
		!		SEE IF THIS ONE MATCHES; &
		!		READ THE ROUTINE NUMBER; &
		!	LOOP ON NO MATCH; &
		!	IF NO MATCH WAS FOUND, THEN &
		!		IF A RESPONSE IS EXPECTED, THEN &
		!			ASSUME THAT THIS IS IT, AND SET &
		!			 UP TO RETURN IT; &
		!		ELSE	SET UP AN ERROR MESSAGE AND SET &
		!			 ERROR FLAG; &
		!			EXIT THE ROUTINE WITH THE &
		!			 MESSAGE POINTER STILL POINTING &
		!			 TO THIS ONE, SO IT WILL BE &
		!			 REMOVED. &

21620	Z0%(M%,12%)=Z% \ Z0%(M%,11%) = P% \ M%=0% &
	&
	\ RETURN &
	&
		! PUT THE NEW DISPATCH TOKEN INTO THE MESSAGE RECORD; &
		! RESET THE MESSAGE POINTER SO THAT THE MESSAGE IS &
		!  LEFT IN THE MESSAGE COMPLETED LIST, IF NO ERROR &
		!  OCCURRED. &
	&
		! AND EXIT. &
	&
	&

21650	DATA	"*STARTCOM", &
		ONLINE,		3,	7, &
		OFFLINE,	3,	8, &
		PAUSE,		3,	9, &
		CONTINUE,	3,	10, &
		NOTICE,		3,	12, &
		LAST,		3,	13, &
		STATUS,		3,	14, &
		STEP,		3,	16, &
		NOSTEP,		5,	17, &
		END,		3,	18, &
		ABORT,		3,	19, &
		DETACH,		3,	30 &
	&

21660	DATA "*ENDCOM",0,0,
21665		! DEFINE THE COMMANDS AND THEIR ROUTINES : &
		!	THE FORMAT IS : &
		!	  <COMMAND NAME>,<MATCH LENGTH>,<ROUTINE NUMBER> &

21740	GO TO 24970	IF (R% AND 1%) = 0% &
	\	R0%, Z0%(J9%,31%) = R0% OR 1% &
	\	F2%=F2% OR 16% &
	\	JOBMOD%=-1% &
	\	GOTO 24970 &
		! 'ABORT' - &
		! IF NO JOB IS IN PROCESS, THEN &
		!	GO ISSUE ERROR MESSAGE TO THAT EFFECT; &
		! ELSE	SET THE 'ABORT REQUESTED' FLAG ON THE JOB'S &
		!	 PROCESSES REQUESTED WORD; &
		!	SET 'SOME JOB MODIFICATION REQUESTED' STATUS; &
		!	EXIT. &

21750	GOSUB 21740 IF (R% AND 1%) &
	\ GOTO 23600 &
		! 'OFFLINE' - &
		! CALL THE 'END' ROUTINE TO SET UP AN 'END'; &
		! CALL THE 'ABORT' ROUTINE IF A JOB IS ACTIVE; &
		! EXIT. &

21770	F2%=F2% OR NOT32767% &
	\ GO SUB 23150 &
	\ R$=C$ &
	\ GOTO 24970 &
		! 'RESPONSE TO REQUEST' - &
		! SET 'RESPONSE RECEIVED' STATUS; &
		! TELL 'OPSER' WE GOT IT &
		! HOLD THE RESPONSE; &
		! EXIT. &

21890	T$="Already ON-LINE" &
	\ E%=(R% AND 4096%) &
	\ GOSUB 23050 IF (R% AND 2048%)=0% IF E%=0% &
	\ GOSUB 23100 IF E%=0% &
	\ GOTO 24970 &
		! 'ONLINE' (TO OPSER) - &
		! SET UP AND ISSUE ERROR MESSAGE IF THE JOB IS ALREADY &
		!  DECLARED; &
		! IF NO ERROR, THEN &
		!	MAKE SURE THE JOB IS ENTERED AS A RECEIVER; &
		!	GO SEND AN 'ONLINE' MESSAGE TO OPSER. &

21950	&
	&
	&
	!	N O T I C E    F R O M    O P E R A T O R &
	&

21960	GOTO 24970 UNLESS J9% &
	\ M9%=2% \ M8%=0% \ GOSUB 21300 &
	\ Z%=Z0%(J9%,5%) &
	\ IF Z%=0% THEN &
		Z0%(J9%,5%)=M% &
	  ELSE	Z%=Z0%(Z%,1%) WHILE Z0%(Z%,1%) &
	\	Z0%(Z%,1%)=M% &
		! ISSUE ERROR IF NO JOB IS ACTIVE; &
		! REMOVE THE NOTICE FROM THE 'COMPLETE MESSAGE LIST'; &
		! FIND THE END OF THE CURRENT 'NOTICE' LIST FOR THIS &
		!  JOB; &
		! PUT THE TEXT RECORD(S) INTO THE LIST. &

21970	M%=0% \ GOTO 24970 &
		! MAKE SURE THAT THE CLEAN-UP IS NOT DONE ON COMPLETION &
		!  OF THE COMMAND; &
		! EXIT. &

22000	T$="Last message was :"+C9$+R1$ &
	\ R2$=R1$ &
	\ R%=R% AND -1025% &
	\ GOSUB 23500 &
	\ R1$=R2$ &
	\ GOTO 24970 &
		! 'LAST' - &
		! SET UP TEXT STRING FOR ISSUANCE; &
		! GO ISSUE IT; &
		! TAKE OUT THE HEADING IF THE MESSAGE WAS SAVED; &
		! EXIT. &

22100	T$=S$+" STATUS"+C9$ &
	\ T$ = T$ + "CONTROLLING DEVICE = " &
		  + CVT$$(FNU$(Q9%,NULSTG$,   1%,0%),2%) + &
		": UNIT:"+FNU0$(Z0%(Q9%,11%))+" (" &
		  + FNU$(Q9%,NULSTG$,4096%,0%) +")" + C9$ &

22120	IF (R% AND 1%) THEN &
		T$=T$+C9$+FNM0$(NULSTG$,J9%,P0%,0%,PGEFLG%)+C9$ &
		! SET UP THE PART OF THE MESSAGE TELLING WHAT KIND OF &
		!  JOB OPERATION IS GOING ON. &

22140	IF JOBMOD% THEN &
		T$=T$+C9$+"Preparing to 'REQUE' job"+C9$ IF &
			(Z0%(J9%,31%) AND 4%) &
	\	T$=T$+C9$+"Preparing to 'ABORT' job"+C9$ IF &
			(Z0%(J9%,31%) AND 1%) &
		! IF SOME JOB MODIFICATION IS OUTSTANDING, THEN &
		!	SET UP THE TEXT DESCRIBING IT. &

22190	GOSUB 23500 &
	\ GOTO 24970 &

22420	T$="ALREADY IN 'PAUSE'" &
	\ E%=(F1% AND 16384%) &
	\ GO TO 24970	IF E% &
	\	F1% = FNPUSH%(F1%) &
	\	S0%=FNPUSH%(S0%) &
	\	Z%=TOD./32768. &
	\	Z0%=TOD.-Z%*32768. &
	\	Z0%=FNPUSH%(Z0%) &
	\	Z0%=FNPUSH%(Z%) &
	\	F1%=16402%+(NOT32767% AND F1%) &
	\	Z0%(M%,12%)=0% &
	\	GOSUB 21000 &
	\	TOD.=32768.*FNPOP%+FNPOP% &
	\ 	S0%=FNPOP% &
	\	F1% = FNPOP% &
	\	F2%=F2% AND -16385% &
	\	GOTO 24970 &
		! 'PAUSE' - &
		! SET UP AN ERROR IF ALREADY IN PAUSE STATE; &
		! ELSE	PUSH THE CURRENT VALUE OF THE 'EVENTS REQUESTED' &
		!	 FLAG; &
		!	SET UP THE FOLLOWING EVENTS TO RETURN FROM THE &
		!	 PAUSE : &
		!		END &
		!		FORM CHANGE &
		!		JOB INTERRUPT &
		!		OFFLINE &
		!		CONTINUE &
		!	CALL THE POLLING ROUTINE TO WAIT FOR ONE OF &
		!	 THEM; &
		!	POP THE OLD EVENT FLAG; &
		!	RESET 'CONTINUE RECEIVED' STATUS; &
		! EXIT. &

22430	T$="Not in 'PAUSE'" &
	\ E%=(F1% AND 16384%)=0% &
	\ F2%=F2% OR 16384% UNLESS E% &
	\ GOTO 24970 &
		! 'CONTINUE' - &
		! SET UP ERROR IF NOT IN PAUSE STATE; &
		! ELSE	SET 'CONTINUE RECEIVED' STATUS FLAG; &
		! EXIT. &
	&

23050	J0%=SWAP%(CVT$%(MID(SYS(UU1$),29%,2%))) &
	\ RETURN	IF J0% = 0% &
	\	J0% = J0% + 14% &
	\	R%=R% OR 2048% &
	\	RETURN &
		! TAKE THE ADDRESS OF THE MESSAGE RECEIVER ENTRY OUT OF &
		!  JDB2; &
		! IF THE ADDRESS IS 0, THEN &
		!	WE FAILED TO ENTER OURSELVES, SO GO EXIT; &
		! ELSE	SET J0% TO POINT TO THE PLACE IN THE MESSAGE &
		!	 RECEIVER ENTRY WHEREIN IS STORED THE COUNT OF &
		!	 MESSAGES QUEUED FOR THIS JOB (THE COUNT IS IN &
		!	 THE HIGH BYTE OF THIS WORD); &
		!	SET THE 'ENTERED AS RECEIVER' FLAG; &
		!	EXIT. &
	&
	&
	&

23100	T0$=CHR6.18$+CHRM1$+CHR0$+ &
		MID(SYS(CHR6.M10$+"OPSER"),7%,4%) &
	\ RETURN	IF (R% AND 4096%) &
	\	R% = FNPUSH%(R%) &
	\	R%=R% AND -16385% &
	\	T$=CHR$(192%)+"ONLINE 1" &
	\	GOSUB 23500 &
	\	R% = FNPOP% &
	\	RETURN &
		! FIRST, SET UP THE STRING TO BE USED IN THE SEND TO &
		!  OPSER, REGARDLESS OF WHETHER OR NOT THE JOB HAS &
		!  ALREADY DONE AN ONLINE TO OPSER OR NOT - THE &
		!  ROUTINE IS CALLED BY THE SET-UP ROUTINES TO ENSURE &
		!  THAT THE COMMUNICATION STRING IS BUILT PROPERLY; &
		! IF THE JOB HAS ALREADY DONE AN ONLINE, THEN &
		!	GOTO THE EXIT; &
		! ELSE	PUSH THE CURRENT PROGRAM STATUS AND RESET THE &
		!	 ATTACHED FLAG TO FORCE A SEND TO OPSER; &
		!	SET UP THE TEXT TO SEND AS 'ONLINE'; &
		!	GO ISSUE AN OPERATOR MESSAGE; &
		!	POP THE OLD VALUE OF THE STATUS WORD; &
		!	AND EXIT. &
		!	(IF THE SEND WAS SUCCESSFUL, THE SEND ROUTINE &
		!	HAS SET THE 'ONLINE' FLAG IN THE STATUS WORD.) &
	&
	&
	&
	&
	&

23150	R% = FNPUSH%(R%) &
	\	R%=R% AND -16385% &
	\	T$=CHR$(192%)+"DELETE #"+J$ &
	\	GOSUB 23500 &
	\	R% = FNPOP% &
	\ RETURN &
		! IF THE 'ONLINE TO OPSER' FLAG IS NOT SET, THEN &
		!	GOTO EXIT; &
		! ELSE	PUSH THE CURRENT STATUS; &
		!	FORCE A SEND TO OPSER OF 'DELETE #<JOB NUMBER>'; &
		!	RESTORE THE STATUS. &

23500	R%=R% AND -513% &
	\ R8%=0% &
	\ P% = FNPUSH%(P%) &
	\ P%=0% &
	\ IF (R% AND 1024%)=0% THEN &
		R1$=T$ &
	\	IF F1%<0% AND (F1% AND F2%)>=0% THEN &
			R%=R% OR 1536% &
	\		T$=C8$+T$ &
		! RESET THE <CR><LF> INHIBIT FLAG; &
		! SET THE RETRY COUNTER FOR THE 'SEND' ROUTINE TO 0; &
		! PUSH THE CURRENT VALUE OF P%, SINCE THE ROUTINE WILL &
		!  USE P% AS A POSITION POINTER; &
		! SET THE VALUE OF P%; &
		! IF A MESSAGE IS NOT CURRENTLY STORED, THEN &
		!	STORE THIS ONE; &
		!	IF THIS MESSAGE IS A REQUEST (IE, THE 'USER &
		!	 RESPONSE' FLAG IN THE EVENT WORD IS SET AND &
		!	 IT IS NOT SET IN THE STATUS WORD), THEN &
		!		SET THE 'MESSAGE STORED' AND &
		!		 <CR><LF> INHIBIT FLAGS; &
		!		PUT A <BELL> ON THE FRONT OF THIS &
		!		 MESSAGE TO SIGNIFY AN ACTION REQUEST. &

23520	RESUME 23550	IF (R% AND 16384%) &
	\	ON ERROR GO TO 23530 &
	\	WHILE P%<LEN(T$) &
	\		Z%=LEN(T$)-P%+1% &
	\		Z%=255% IF Z%>20% &
	\		Z$=SYS(T0$+CHR$(Z%)+RIGHT(T$,P%+1%)) &
	\		R8%=0% &
	\		P%=P%+19% &
	\	NEXT &
	\	R%=R% OR 4096% &
	\	GOTO 23560 &
		! IF THE JOB IS FLAGGED AS ATTACHED, THEN &
		!	GO TO THE 'PRINT' ROUTINE; &
		! ELSE	SET ERROR TRAP; &
		!	SEND THE MESSAGE TO OPSER, 19 BYTES AT A TIME, &
		!	 USING THE STRING, T0$, SET UP BY THE 'ONLINE' &
		!	 ROUTINE; &
		!	SET THE 'ONLINE' FLAG. &

23530	IF ERR=32% THEN &
		R8%=R8%+1% &
	\	IF R8%<60% THEN &
			SLEEP 5% &
	\		RESUME 23520 &
		! IF THE ERROR MEANT 'NO ROOM FOR MESSAGE', THEN &
		!	INCREMENT THE RETRY COUNTER; &
		!	IF THE COUNTER IS STILL LESS THAN 60, THEN &
		!		SLEEP AWHILE; &
		!		TRY AGAIN TO SEND THE MESSAGE. &

23540	RESUME 19000 &
		! IF THE ERROR WAS ANYTHING OTHER THAN 'NO ROOM', OR IF &
		!  THE RETRY COUNTER HAS EXPIRED, THEN &
		!	SET THE ATTACHED FLAG AND RESET THE ONLINE TO &
		!	 OPSER FLAG; &
		!	APPEND AN EXPLANATION TO THE MESSAGE; &
		!	SET AN ERROR; &
		!	GO PROCESS AS IF ATTACHED. &

23550	IF (R% AND 16384%) THEN &
		ON ERROR GOTO 0 &
	\	PRINT #0% IF CCPOS(0%) &
	\	PRINT #0%,T$; &
	\	PRINT #0% UNLESS (R% AND 512%) &
		! IF ATTACHED, THEN &
		!	RESET ERROR TRAP; &
		!	MAKE SURE THAT THE CARRIAGE IS AT THE LEFT &
		!	 MARGIN; &
		!	PRINT THE STRING WITHOUT <CR><LF>; &
		!	PRINT A <CR><LF> IF THE <CR><LF> INHIBIT FLAG IS &
		!	 NOT SET. &

23560	T$=NULSTG$ &
	\ P% = FNPOP% &
	\ R%=R% OR NOT32767% &
	&
	\ ON ERROR GOTO 19000 &
	&
	\ RETURN &
	&
		! NULL OUT THE TEXT STRING TO GET RID OF THE ROOM IT'S &
		!  TAKING; &
		! RESTORE THE ORIGINAL VALUE OF P%; &
		! SET THE 'PROMPT REQUIRED' FLAG. &
	&
		! RESET THE ERROR TRAP; &
	&
		! AND EXIT. &
	&

23600	M9%=2% \ M8%=4% \ GOSUB 21300 \ M%=0% \ RETURN &
		! SET UP THE CALL TO THE 'SHIFT A MESSAGE' ROUTINE : &
		!	TAKE FROM THE 'COMPLETED' LIST; &
		!	ENTER TO THE 'UNPROCESSED' LIST; &
		!	DO THE CALL, AND LET IT RETURN; &
		!	RESET THE 'CURRENT MESSAGE' POINTER; &
		! AND EXIT. &
	&
	&

24300	IF J9% AND Z0%(J9%,17%)=2% THEN &
		GOSUB 21740 &
	\	Z0%(J9%,31%)=Z0%(J9%,31%) OR 16% &
	\	GOTO 24970 &
		! IF A JOB IS ACTIVE AND IT CAME FROM THE QUEUE, THEN &
		!	CALL THE ABORT ROUTINE; &
		!	SET THE 'BY QUEMAN' FLAG FOR THE ABORT MESSAGE; &
		!	GO EXIT. &

24320	GOTO 23600 &
		! IF THE CURRENT JOB IS NOT FROM THE QUEUE, THEN &
		!	GO STORE THE MESSAGE AS AN UNPROCESSED MESSAGE. &
	&

24970	ON ERROR GO TO 19000 &
	\ RETURN &
	! RESET ERROR TRAP AND EXIT &

25200	DEF* FNR%(S$,L%) &
	\ FNR%,Z1%=0% &
	\ Z0%=P% &
	! FUNCTION:	KEYWORD MATCHING ROUTINE. MATCHES A STRING IN &
	!		THE COMMAND STRING C$ STARTING AT POSITION P%+1% &
	!		TO THE DUMMY STRING S$. A MATCH IS MADE WHEN THE &
	!		MINIMUM NUMBER OF CHARACTERS ARE MATCHED. THIS &
	!		MINIMUM NUMBER IS HELD IN THE DUMMY VARIABLE &
	!		L%. &
	! PARAMETERS:	S$	STRING TO MATCH TO. &
	!		L%	MINIMUM LENGTH OF MATCH. &
	! GLOBAL &
	! VARIABLES &
	! AFFECTED:	P%	POSITION POINTER POINTS TO THE LAST CHAR- &
	!			ACTER MATCHED SUCCESSFULLY. &
	! LOCAL &
	! VARIABLES &
	! USED:		Z%	TEMPORARY CHARACTER POINTER. &
	!		Z$	CHARACTER MATCHING VARIABLE FOR PROCESS- &
	!			ING BEYOND THE MINIMUM LENGTH. &
	! RETURNS:	THE NUMBER OF CHARACTERS SUCCESSFULLY MATCHED. &
	! ERRORS:	NONE EXPECTED. &

25210	Z%=ASCII(RIGHT(C$,P%+1%)) &
	\ IF Z%=32% OR Z%=9% THEN P%=P%+1% &
				\ GOTO 25210 &
		! SKIP PAST BLANKS AND TABS. &

25220	IF MID(S$,1%,L%)=MID(C$,P%+1%,L%) THEN Z%=L% &
	ELSE GOTO 25250 &
		! SEARCH FOR MINIMUM MATCH. &

25230	Z$=MID(C$,P%+Z%+1%,1%) &
	\ IF Z$<>MID(S$,Z%+1%,1%) THEN GOTO 25240 &
	  ELSE Z%=Z%+1% IF LEN(Z$) &
	  \ GOTO 25230 IF LEN(Z$) &
		! SEARCH FOR MORE MATCHING CHARACTERS. &

25240	P%=P%+Z% &
	\ FNR%,Z1%=Z% &
		! RETURN WITH P% POINTING TO THE LAST SUCCESSFULLY &
		! MATCHED CHARACTER. FUNCTION WILL RETURN AS THE NUMBER &
		! OF CHARACTERS MATCHED. &

25250	P%=Z0% UNLESS Z1% &
	\ FNEND &
	&
	&
	&

25900	DEF* FNU$(P0%,C$,Z%,Z0%) &
	! FUNCTION :	FNU$	TURN A FILE DESCRIPTOR RECORD INTO &
	!			AN OPENABLE FILENAME STRING. &
	! PARAMETERS :	P0%	RECORD IN WORK-FILE TO CHANGE &
	!		C$	DUMMY STRING TO USE IN CONSTRUCTING &
	!			THE FILENAME STRING. &
	!		Z%	FLAG WORD 2 FORMAT WORD SHOWING WHICH &
	!			FIELDS IN THE RECORD TO CONVERT. &
	!		Z0%	WORD SHOWING WHICH SWITCHES TO CONVERT &
	!			(OF /MODE, /CLU, AND /FILESIZE). &
	! RETURNS :	FUNCTION VALUE &
	!			THE STRING TO USE IN AN OPEN. &
	! USES :	FNU0$(L%) &

25910	Z%=Z% AND Z0%(P0%,14%) &
	\ Z%=Z% AND -3201% IF (Z0%(P0%,13%) AND 1914%) &
		IF Z0%(P0%,14%)>0% &
	\ C$=NULSTG$ &
		! CREATE A WORD (Z%) WHICH HAS BITS SET FOR A FIELD ONLY &
		! IF THAT FIELD IS BOTH REQUESTED AND PRESENT IN THE &
		! DATA; &
		! IF DEVICE IS NOT DISK, DT, MT, OR LOGICAL, DO NOT &
		! RETURN FILENAME, EXTENSION; &
		! INITIALIZE THE STRING TO NULL. &
	&

25920	C$=RAD$(Z0%(P0%,6%))+RAD$(Z0%(P0%,7%))+":" IF (Z% AND 4096%) &
	\ C$=C$+"["+FNU0$(SWAP%(Z0%(P0%,8%)))+","+FNU0$(Z0%(P0%,8%))+ &
		"]" IF (Z% AND 128%) &
	\ C$=C$+RAD$(Z0%(P0%,9%))+RAD$(Z0%(P0%,10%)) IF (Z% AND 1%) &
	\ C$=C$+"."+RAD$(Z0%(P0%,11%)) IF (Z% AND 8%) &
	\ C$=C$+"<"+FNU0$(SWAP%(Z0%(P0%,12%)))+">" IF (Z% AND 3072%) &
		! SET UP Z% AS BITS SET IN BOTH THE REQUESTED ENTRY &
		! WORD AND THOSE SET IN THE ACTUAL FILENAME STRING. &
		! IF DEV: REQ/EXSTS, MAKE IT; &
		! IF [PPN] REQ/EXSTS, MAKE IT; &
		! IF FILENAME REQ/EXSTS, MAKE IT; &
		! IF .EXT REQ/EXSTS, MAKE IT; &
		! IF <PROT> REQ/EXSTS, MAKE IT. &

25930	Z0%=Z0% AND Z0%(P0%,15%) AND 14336% &
	\ IF Z0% THEN &
		C$=C$+"/CL:"+NUM$(Z0%(P0%,18%)) IF (Z0% AND 2048%) &
	\	C$=C$+"/MO:"+NUM$(Z0%(P0%,16%)) IF (Z0% AND 4096%) &
	\	C$=C$+"/FI:"+NUM$(Z0%(P0%,19%)) IF (Z0% AND 8192%) &
		! SET UP Z0% TO HOLD ONLY THE FLAGS SET BOTH IN THE &
		! OPEERAND IN THE CALL AND IN THE RECORD POINTED TO; &
		! PUT THE "/SWITCH:OPERAND" STRINGS INTO THE RETURNED &
		! STRING IN THE ORDER: &
		!	2048	CLUSTERSIZE &
		!	4096	MODE &
		!	8192	FILESIZE &

25960	FNU$=C$ &
		! SET FUNCTION VALUE. &

25970	FNEND &

25980	DEF* FNU0$(L%) &
	\ L%=L% AND 255% &
	\ IF L%=255% THEN FNU0$="*" ELSE FNU0$=NUM1$(L%) &
		! TAKE THE LOW BYTE OF L%; &
		! IF THAT BYTE IS 255, THEN &
		!	RETURN '*'; &
		! ELSE	RETURN NUM1$ OR BYTE. &

25990	FNEND &
	&
	&
	&

26000	DEF* FNO%(P0%,A0%,C0%,PPN%) &
	\ FNO%=0% &
		! FUNCTION :	OPEN THE FILE WHOSE NAME IS IN RECORD &
		!		P0% OF THE WORK-FILE, ACCESS TYPE A0%, &
		!		ON CHANNEL C0%, USING SPECIFIED &
		!		CLUSTERSIZE, MODE, FILESIZE, AND &
		!		RECORDSIZE VALUES. &
		! &
		! PARAMETERS : &
		!	P0%	RECORD # OF FILE RECORD IN WORK-FILE &
		!	A0%	ACCESS TYPE : &
		!			1 - READ ONLY &
		!			2 - WRITE ONLY (SUPERSEDE) &
		!			3 - READ/WRITE &
		!			4 - \ PROTECTION &
		!			5 - \ VIOLATION &
		!			6 - OPEN, WRITE-ONLY, FOR EXTEND &
		!			7 - OPEN, READ/WRITE, FOR EXTEND &
		!			8 - OPEN FOR READ-REGARDLESS &
		!				(NO DROP OF PRIVILEGES) &
		!		       16 - OPEN FOR BATCH MODE &
		!	C0%	CHANNEL ON WHICH TO OPEN IT. &

26010	GOTO 26090 IF E% &
	\ Z0%(P0%,16%)=4096% IF A0%=8% &
	\ IF (A0% AND 4%) THEN &
		A0%=A0% AND 3% &
	\	IF (Z0%(P0%,13%) AND 137%) THEN &
			Z0%(P0%,15%)=Z0%(P0%,15%) OR 4096% &
	\		Z0%=Z0%(P0%,13%) &
	\ Z%=Z0%(P0%,16%) &
	\		Z%=2% IF (Z0% AND 1%) &
	\		Z%=Z% OR 8192% IF (Z0% AND 8%) &
	\		Z%=128% IF (Z0% AND 128%) &
	\		Z0%(P0%,16%)=Z% &
	\		A0%=3% &
		! IF THIS IS AN ATTEMPT TO SUPERSEDE A FILE ON ANOTHER &
		! ACCOUNT BY A NON-PRIVILEGED USER, GIVE HIM AN ERROR. &
		! THIS CHECK IS NECESSARY TO PREVENT A NON-PRIVILEGED &
		! USER FROM DESTROYING FILES ON OTHER ACCOUNTS TO WHICH &
		! HE HAS WRITE ACCESS. &

26012	ON ERROR GOTO 26070 &
	\ GOTO 26020	IF PPN% = 0% &
	\ PRIV.MASK$ = MID(SYS(CHR$(6%)+CHR$(-25%)+CHR$(-1%)+CHR$(2%) &
		+CVT%$(SWAP%(PPN%))),9%,8%) &
			! DROP OUT IF WE AREN'T USING 3rd PARTY PRIVS &
			! GET THE OWNER PRIV MASK FROM DISK &

26014	DUMMY$ = SYS(CHR$(6%)+CHR$(31%)+STRING$(2%,0%) &
		+CVT%$(SWAP%(PPN%))+PRIV.MASK$) &
			! INSTALL THIRD PARTY PRIV CHECK &

26020	Z$=FNU$(P0%,NULSTG$,-1%,-1%) &
	\ Z%=(Z0%(P0%,17%) AND (Z0%(P0%,15%) AND 1024%)<>0%) &
	\ OPEN Z$ FOR INPUT AS FILE C0%, RECORDSIZE Z% IF (A0% AND 9%) &
	\ OPEN Z$ FOR OUTPUT AS FILE C0%, RECORDSIZE Z% IF A0%=2% &
	\ OPEN Z$ AS FILE C0%, RECORDSIZE Z% IF A0%=3% &
	\ OPEN Z$ AS FILE C0%, RECORDSIZE Z%, MODE 2% IF A0%=16% &
		! SET UP TO TRAP AN OPEN ERROR; &
		! SET UP FILE NAME WITH SWITCHES, SET &
		! UP RECORDSIZE; &
		! GIVE HIM THE KIND OF OPEN HE ASKED FOR: &
		!	READ ONLY	OPEN FOR INPUT &
		!	WRITE ONLY	OPEN FOR OUTPUT &
		!	READ/WRITE	OPEN &
		! 	BATCH MODE (2%)	OPEN &

26030	DUMMY$ = SYS(CHR$(6%)+CHR$(31%))	IF PPN% &
			! DROP THIRD PARTY PRIV CHECK &

26050	ON ERROR GOTO 19000 &
		! RECOVER PRIVILEGES; &
		! RESET ERROR TRAP. &

26060	FNEND &
		! AND EXIT. &

26070	IF	ERL = 26012% &
	THEN	PRIV.MASK$ = STRING$(8%,0%) &
		\ RESUME 26014 &
		! TRY READING THIRD PARTY PRIVS, RETURN NULLS IF ERROR &

26080	E%=ERR \ RESUME 26090 &
		! THIS IS FOR ERRORS TRAPPED IN THE OPEN. &

26090	E%=E% OR 1024% \ GOTO 26030 &
		! SET THE FLAG BIT SAYING 'ON OPEN', AND EXIT. &
	&
	&

26100	DEF* FNA% &
		! RETURN SUBSCRIPT OF NEXT FREE INDEX ENTRY AND ZERO &
		!  THAT ENTRY. &
		! PARAMETERS:	NONE &
		! RETURNS:	SUBSCRIPT OF THE FIRST ENTRY IN THE FREE &
		!		SPACE LIST. &
		! USES:	Z%	LOOP VARIABLE FOR ZEROING &
		! NOTES:	USES FREE LIST POINTER OUT OF THE INDEX FILE &
		!		HEADER TO GET SUBSCRIPT.  IF FL POINTER IS &
		!		NEGATIVE, THAT PART OF THE FILE HAS NOT YET &
		!		BEEN INITIALIZED, AND THE ROUTINE WILL GO TO &
		!		DO IT. THEN THE ENTRY TO BE RETURNED IS ZEROED. &

26110	B0%=Z0%(0%,0%) UNLESS B0% &
	\ Z0%=B0% &
	\ IF Z0%<0% THEN &
		Z0%=-Z0% &
	\	Z0%(Z%,1%)=Z%+1% FOR Z%=Z0% TO Z0%+7% &
	\	Z0%(Z%,1%)=-Z%-1% &
		! GET NEXT FREE LIST ENTRY; &
		! IF SUBSCRIPT IS NEGATIVE, THIS ENTRY HAS NOT YET BEEN &
		! TOUCHED, SO EXTEND A FEW. &

26120	B0%=Z0%(Z0%,1%) &
	\ Z0$(Z0%)=NULSTG$ &
	\ FNA%=Z0% &
		! ZERO OUT THE RETURNED ENTRY AND SET FUNCTION VALUE. &

26130	FNEND &
		! END OF FNA%. &
	&

26200	DEF* FNA0%(P0%) &

26210	Z0%,Z2%=P0% &
	\ Z0%=Z0%(Z0%,1%) WHILE Z0%(Z0%,1%) &
	\ FOR Z%=2% TO 5% &
	\	Z2%=P0% &
	\	WHILE Z2% &
	\		IF Z0%(Z2%,Z%) THEN &
				Z3%=Z0%(Z2%,Z%) &
	\			Z0%(Z2%,Z%)=0% &
	\			Z0%,Z0%(Z0%,1%)=Z3% &
	\			Z0%=Z0%(Z0%,1%) WHILE Z0%(Z0%,1%) &

26220			Z2%=Z0%(Z2%,1%) &
	\	NEXT &
	\ NEXT Z% &
	\ Z0%(Z0%,1%)=B0% &
	\ B0%=P0% &
	\ FNA0%=0% &

26230	FNEND &
	&

27200	DEF* FNN% &
	\ FNN%,F%=0% &
	! FUNCTION:	RETURN A NUMBER ROUTINE. &
	! PARAMETERS:	NONE &
	! GLOBAL &
	! VARIABLES &
	! AFFECTED:	P%	CHARACTERS POSITION POINTER. &
	!		F%	FOUND FLAG. &
	! LOCAL &
	! VARIABLES &
	! USED:		Z%	TEMPORARY POSITION POINTER. &
	!		Z0%	ASCII CHARACTER REPRESENTATION. &
	! RETURNS:	VALUE OF NUMERIC DIGITS FOLLOWING POSITION P% &
	!		IN THE STRING C$. IF NONE ARE FOUND THE FOUND FLAG &
	!		IS RETURNED AS ZERO. &
	! ERRORS:	NONE EXPECTED. &

27210	ON ERROR GOTO 27250 &
	\ Z%=P%-1% &
	\ Z0%=-1% &
		! SET LOCAL ERROR HANDLER. &
		! SET LOCAL CHARACTER POINTER. &
		! INITIALIZE ASCII DIGIT FLAG. &

27220	WHILE (Z0%>=48% AND Z0%<=57%) OR Z0%=-1% &
		\ Z%=Z%+1% &
		\ Z0%=ASCII(RIGHT(C$,Z%+1%)) &
	\ NEXT &
		! CHECK FOR DIGITS, AND EXIT HERE WITH Z%=P% OR Z% &
		! POINTING TO THE LAST DIGIT FOUND. &

27230	IF Z%<>P% THEN FNN%=VAL(MID(C$,P%+1%,Z%-P%)) &
				\ P%=Z% &
				\ F%=-1% &
		! WE HAVE FOUND A NUMBER. SET THE FUNCTION VALUE TO &
		! THE VALUE OF THE NUMBER FOUND AND SET THE FOUND FLAG. &

27240	ON ERROR GOTO 19000 &
	\ FNEND &
		! RESET THE ERROR HANDLER. &
		! CHECK TO SEE IF THERE WAS AN ERROR. &
		! RETURN. &

27250	E%=564% IF ERR/10%=5% &
	\ RESUME 27240 &
		! TRAP ERRORS IN THE VAL FUNCTION. &
	&

27300	DEF* FNUNPACK$(P0%,P1%) &
	! FUNCTION :	FNUNPACK$	UNPACK A STRING OUT OF THE WORK- &
	!				 FILE AND RETURN THE STRING IN &
	!				 THE FUNCTION VALUE. &
	! OPERANDS :	P0%		THE HEAD RECORD OF THE LIST OF &
	!				 RECORDS CONTAINING THE STRING. &
	!		P1%		THE NUMBER OF BYTES TO SKIP AT &
	!				 THE BEGINNING OF THE FIRST &
	!				 RECORD - THESE BYTES ARE &
	!				 SKIPPED IN ORDER TO LEAVE ROOM &
	!				 FOR CONTROL INFORMATION, SUCH &
	!				 SOURCE OF MESSAGE, PPN FROM &
	!				 WHICH IT CAME, DISPATCH CODE, &
	!				 ETC. &
	! RETURNS :	THE UNPACKED STRING IN THE FUNCTION VALUE. &
	&

27310	Z%=Z0%(P0%,P1%/2%) &
	\ P1%=P1%+3% &
	\ Z9%=P0% &
	\ Z8%=Z0%(P0%,1%) &
	\ Z0%(P0%,1%)=Z0%(P0%,2%) \ Z0$=NULSTG$ &

27320	Z0%=129%-P1% \ Z0%=Z% IF Z0%>Z% &
	\ Z$=RIGHT(Z0$(P0%),P1%) &
	\ Z$=Z$+STRING$(Z0%-LEN(Z$),0%) &
	\ Z%=Z%-LEN(Z$) &
	\ Z0$=Z0$+Z$ &
	\ P1%=Z0%(P0%,1%) &
	\ IF P1% THEN &
		P0%=P1% &
	\	P1%=13% &
	\	GOTO 27320 &

27330	Z0%(Z9%,1%)=Z8% &
	\ FNUNPACK$=Z0$ &

27340	FNEND &
	&

27400	DEF* FNPUSH%(VALUE%) &
	\ S%=S%+1% \ S%(S%),FNPUSH%=VALUE% &
	\ FNEND &

27410	DEF* FNPOP% &
	\ FNPOP%=S%(S%) \ S%=S%-1% &
	\ FNEND &
	&

31000	E0%=2% &
	\ C$=SYS(CHR$(7%)) &
	\ B%=CVT$%(C$) &
	\ W$=RIGHT(C$,3%) &
	\ GOTO 1000 &
		! TAKE THE FHR AND THE WORK-FILE &
		!  NAME OUT OF CORE COMMON AND GO TO WORK. &
	&
	&
	&
	&

32767	END
