Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_3_19910112 - utilities/date.mac
There is 1 other file named date.mac in the archive. Click here to see a list.
;[SRI-NIC]SRC:<UTILITIES>DATE.MAC.117, 20-Oct-83 11:53:05, Edit by SATZ
;[NIC] Make EX a legal abbreviation for EXIT
;<UTILITIES>DATE.MAC.116,  9-Aug-83 12:11:32, Edit by MRC
;ERROR.SYS now lives on SERR
;<UTILITIES>DATE.MAC.115, 28-Jan-83 18:51:23, Edit by ADMIN.MRC
;Set CR%CAP in TTYULK+5
;<UTILITIES>DATE.MAC.114,  2-Jan-83 19:22:22, Edit by ADMIN.MRC
;Remove edit 113
;<UTILITIES>DATE.MAC.113,  2-Jan-83 17:49:01, Edit by ADMIN.MRC
;Restrict our TTY JFN so inferiors can't close it on us
;<UTILITIES>DATE.MAC.112, 13-Dec-82 21:07:16, Edit by ADMIN.MRC
;<UTILITIES>DATE.MAC.111, 13-Dec-82 21:02:39, Edit by ADMIN.MRC
;Kludge patch to avoid blowing up on bugs
;<UTILITIES>DATE.MAC.110,  3-Jun-82 14:44:17, Edit by ADMIN.MRC
;Output RETURN before linefeed
;Teach it about Heaths
;<UTILITIES>DATE.MAC.109, 12-Mar-82 19:04:24, Edit by ADMIN.MRC
;Don't try to enable privs we can't get
;SNARK:<V-SOURCES>DATE.MAC.108  8-Jan-81 15:17:05, Edit by OSMAN
;Don't try to go to bottom of screen if length is 0.
;<V-SOURCES>DATE.MAC.101 11-Dec-80 15:12:15, Edit by OSMAN
;On ^D, show what processing is going on and for how long
;SNARK:<V-SOURCES>DATE.MAC.100  2-Dec-80 11:26:56, Edit by OSMAN
;Use DUMP.EXE instead of DUMP.CPY since DUMP.CPY may be deleted
;SNARK:<V-SOURCES>DATE.MAC.97 30-Oct-80 14:07:45, Edit by OSMAN
;Check terminal type every time a new announcement is starting
;Make announcements at bottom of screen so it doesn't mix with EMACS text
;<V-SOURCES>DATE.MAC.67, 28-Jul-80 14:41:01, EDIT BY OSMAN
;Don't preview the mail if the user is in MS.
;<V-SOURCES>DATE.MAC.66, 19-Jun-80 10:05:24, EDIT BY OSMAN
;Don't announce batch background jobs
;<V-SOURCES>DATE.NEW.2, 15-May-80 16:09:56, EDIT BY OSMAN
;Make STATISTICS selectable
;<V-SOURCES>DATE.MAC.53, 30-Apr-80 10:14:05, EDIT BY OSMAN
;Avoid "illegal to manipulate superior" error during ^D jfn scan
;<V-SOURCES>DATE.MAC.41, 31-Mar-80 15:02:25, EDIT BY OSMAN
;Display percentage through file
;<V-SOURCES>DATE.MAC.40, 26-Mar-80 10:46:28, EDIT BY OSMAN
;Prevent entire grump form from coming out when several grumps at once
;<V-SOURCES>DATE.MAC.37, 26-Mar-80 09:03:17, EDIT BY OSMAN
;Make sure first message gets displayed after MS deletes mail file.
;<V-SOURCES>DATE.MAC.36, 11-Mar-80 10:31:02, EDIT BY OSMAN
;Don't do all the MONRD's for hogs being excluded
;<OSMAN.SOURCES>DATE.MAC.3, 31-Jan-80 13:42:33, EDIT BY OSMAN
;Clear exclusion table on restart.  Make JSBOMB say where from.
;<V-SOURCES>DATE.MAC.33, 17-Jan-80 10:51:38, EDIT BY OSMAN
;Add SHOW LOGIN-TIME
;<V-SOURCES>DATE.MAC.22, 19-Dec-79 10:27:56, EDIT BY OSMAN
;Add EXCLUDE/INCLUDE HOG
;<V-SOURCES>DATE.MAC.21, 27-Nov-79 09:32:24, EDIT BY OSMAN
;Speed up ERROR.SYS reading by making guess as to first page to read
;<V-SOURCES>DATE.MAC.19,  6-Nov-79 10:35:05, EDIT BY OSMAN
;Don't put the bells in the log file
;<V-SOURCES>DATE.MAC.16,  2-Nov-79 13:52:54, EDIT BY OSMAN
;PRINT ENTIRE FILESPEC WHEN AN UPDATE HAPPENS
;<V-SOURCES>DATE.MAC.10,  2-Nov-79 09:33:27, EDIT BY OSMAN
;ADD ENABLE/DISABLE LOGGING
;<V-SOURCES>DATE.MAC.6,  1-Nov-79 15:55:11, EDIT BY OSMAN
;Put in ENABLE UPDATE-FILE-CHECKING (FOR FILES)
;<V-SOURCES>DATE.MAC.4, 22-Oct-79 14:43:47, EDIT BY OSMAN
;DON'T CLOBBER "SHOW VALUE" DATA WHEN DOING GRUMP OR MAIL
;<GUNN.DEVELOPMENT>DATE.MAC.25,  3-Oct-79 11:45:33, Edit by GUNN
;[V5.0] Replaced IGNORE-BUGCHK command by EXCLUDE command
;	which allows wildcarding of bug names. 
;	Added INCLUDE command to complement EXCLUDE.
;	Added TEXT option to SHOW command to type out text string
;	for a BUG.
;	Changed code which read in BUGSTRINGS to not set invisible
;	bit for BUGHLT's.
;	Changed code which printed out BUGCHK's to also print out
;	BUGINF's as they occur since user can now more easily 
;	control which BUG's get reported.
;	Changed code for SHOW SETTINGS command to print out the
;	ignored BUG's in ascending order.
;	Increased size of BIGTAB so all bugs may be excluded
;Note:	For future the code should be changed so only one table is
;	used for both functions.
;<OSMAN.SOURCES>DATE.MAC.196, 19-Sep-79 09:18:18, EDIT BY OSMAN
;Tell people who accidentally hit CTRL/Y how to get out
;<OSMAN.SOURCES>DATE.MAC.195, 21-Aug-79 16:02:33, EDIT BY OSMAN
;forgot to call PION in path where fork IS a ^P exec!
;<OSMAN.SOURCES>DATE.MAC.194, 10-Aug-79 17:09:58, EDIT BY OSMAN
;Don't try to release fork handles of ^P execs
;<OSMAN.SOURCES>DATE.MAC.193, 10-Aug-79 13:18:45, EDIT BY OSMAN
;If can't make output fork, wait
;<OSMAN.SOURCES>DATE.MAC.184,  9-Aug-79 14:53:22, EDIT BY OSMAN
;Flush the output fork when done with it, to save forks
;<OSMAN.SOURCES>DATE.MAC.183,  8-Aug-79 14:09:57, EDIT BY OSMAN
;Don't print entire grump form sheet when several grumps come in at once
;Shorten hog message to fit on one line
;<OSMAN.SOURCES>DATE.MAC.182,  1-Aug-79 08:50:43, EDIT BY OSMAN
;DON'T MISS FIRST GRUMP IN FILE
;<OSMAN.SOURCES>DATE.MAC.178, 31-Jul-79 11:16:56, EDIT BY OSMAN
;ALLOW SETTING THE INTERRUPT CHARACTER
;<OSMAN.SOURCES>DATE.MAC.175, 24-Jul-79 09:21:43, EDIT BY OSMAN
;INVALID PROCESS HANDLE" BOMBOUT, WHICH OCCURED IF USER ^C'ED
;FROM DATE, DID "INFO PROG", AND THEN CONTINUED DATE AND DID ^D.  (RFRKH
;WITH -1 RELEASED OUR FORK HANDLES!)
;<OSMAN.SOURCES>DATE.MAC.173, 20-Jul-79 11:10:29, EDIT BY OSMAN
;ADD ENABLE MAIL-PREVIEWING
;<OSMAN.SOURCES>DATE.MAC.172, 25-Jun-79 09:54:17, EDIT BY OSMAN
;USE SYSTEM: INSTEAD OF SYS: FOR BUGSTRINGS TO AVOID "Can't find Message for Bug"
;<OSMAN.SOURCES>DATE.MAC.170, 19-Jun-79 10:10:07, EDIT BY OSMAN
;FIX "ILLEGAL MEMORY READ" DURING GRUMP PROCESSING
;<OSMAN.SOURCES>DATE.MAC.168, 18-Jun-79 14:28:46, EDIT BY OSMAN
;FIX SIXASC SO WE DON'T SAY "CAN'T FIND MESSAGE FOR BUG" SO OFTEN
;<OSMAN.SOURCES>DATE.MAC.167, 23-May-79 10:53:58, EDIT BY OSMAN
;add DISABLE SPY-PROTECTION
;<OSMAN.SOURCES>DATE.MAC.163, 17-May-79 15:13:09, EDIT BY OSMAN
;add SHOW SETTINGS
;<OSMAN.SOURCES>DATE.MAC.161, 14-May-79 11:01:59, EDIT BY OSMAN
;only freeze exec while reading command
;<OSMAN.SOURCES>DATE.MAC.160,  4-May-79 13:19:38, EDIT BY OSMAN
;IF GET TO .POP BEFORE TTYFRK SET UP, QUIETLY TOLERATE.
;<OSMAN.SOURCES>DATE.MAC.159,  2-May-79 16:07:22, EDIT BY OSMAN
;HANDLE CASE WHERE OPERATOR INITIALIZES GRUMP FILE
;<OSMAN.SOURCES>DATE.MAC.158, 30-Apr-79 10:47:21, EDIT BY OSMAN
;fix PERR1 to not clobber error code
;<OSMAN.SOURCES>DATE.MAC.151, 13-Apr-79 16:13:22, EDIT BY OSMAN
;ENABLE ALL PANIC INTERRUPT CHANNELS
;<OSMAN.SOURCES>DATE.MAC.149, 13-Apr-79 15:15:30, EDIT BY OSMAN
;Fix ILLEGAL MEMORY READ problem with grump system
;<OSMAN.SOURCES>DATE.MAC.128, 11-Apr-79 14:15:18, EDIT BY OSMAN
;SPEED UP BUGCHK/BUGHLT STUFF BY NOT RUNNING SYSERR
;TAKE JOB RANGE ON "WHO" COMMAND
;ALLOW INTERRUPTING ONE COMMAND AND STARTING ANOTHER
;IMPLEMENT THE WHO'S-USING COMMAND
;When scanning page table for open file, check for PA1050
;<OSMAN.SOURCES>DATE.MAC.88, 30-Mar-79 15:15:57, EDIT BY OSMAN
;IF USER "POP"S AND WE'RE ALREADY SICK, THEN HALT!
;<OSMAN.SOURCES>DATE.MAC.86, 28-Mar-79 09:47:07, EDIT BY OSMAN
;SAVE COMND STATE TO ALLOW BUGINI OR CTRL/Y DURING DATE.CMD
;ON FATAL ERROR, PRINT MESSAGE BUT DON'T BOMB OUT GUY'S EXEC
;<OSMAN.SOURCES>DATE.MAC.77, 26-Mar-79 14:04:06, EDIT BY OSMAN
;SPEED UP STARTUP BY NOT CALLING BUGINI UNTIL NEEDED
;ADD STANDARD VERSION NUMBER STUFF
;<OSMAN.SOURCES>DATE.MAC.68, 23-Mar-79 10:37:19, EDIT BY OSMAN
;ENABLE HOG-CHECKING
;DEFAULT EVERYTHING TO OFF, SO USERS CAN SELECT WHICH FEATURES THEY WANT
;<OSMAN.SOURCES>DATE.MAC.62, 22-Mar-79 15:01:28, EDIT BY OSMAN
;FREEZE EXEC WHILE DOING COMMANDS
;<OSMAN.SOURCES>DATE.MAC.59, 22-Mar-79 14:32:10, EDIT BY OSMAN
;ALWAYS RUN EXEC UNDER DATE
;RUN EXEC AS LOWER FORK INSTEAD OF REQUIRING "CONTINUE STAY"
;<OSMAN.SOURCES>DATE.MAC.57, 21-Mar-79 10:43:44, EDIT BY OSMAN
;TRY TO FIX A GRUMP BUG BY REMOVING RANSET
;<OSMAN.SOURCES>DATE.MAC.56, 20-Mar-79 09:53:38, EDIT BY OSMAN
;FIX BUG REPORTER TO NOT SAY "?INVALID TIME FORMAT"
;<OSMAN.SOURCES>DATE.MAC.54, 13-Mar-79 16:38:17, EDIT BY OSMAN
;announce death due to PDLOV, and increase stack size
;<OSMAN.SOURCES>DATE.MAC.53, 13-Mar-79 13:29:52, EDIT BY OSMAN
;TRY TO SPEED UP BUG REPORTING BY USING /BRIEF
;<OSMAN.SOURCES>DATE.MAC.52, 12-Mar-79 14:22:43, EDIT BY OSMAN
;FIX IGNORE FEATURE
;<OSMAN.SOURCES>DATE.MAC.51,  8-Mar-79 14:17:05, EDIT BY OSMAN
;change ttylck to use DIR, since mere AOS can cause deadlock if higher interrupt also tries to get lock
;<OSMAN.SOURCES>DATE.MAC.50,  7-Mar-79 09:51:54, EDIT BY OSMAN
;use DIR instead of TTYLCK for TOTRUN
;<OSMAN.SOURCES>DATE.MAC.49,  5-Mar-79 10:13:28, EDIT BY OSMAN
;PREVENT SEEING PERCENTAGES GT 100.  (LOCK TOTRUN WITH TTYLCK)
;<OSMAN.SOURCES>DATE.MAC.46, 27-Feb-79 14:08:54, EDIT BY OSMAN
;DO BUGCHKS WITH SPECIAL TIMER SO THEY DON'T TIE UP REST OF FUNCTIONS
;<OSMAN.SOURCES>DATE.MAC.44, 26-Feb-79 15:49:15, EDIT BY OSMAN
;FIX BUGCHK EXECUTE-NOT-DURING-INTERRUPT STUFF
;<OSMAN.SOURCES>DATE.MAC.43, 26-Feb-79 15:35:47, EDIT BY OSMAN
;FIX "IGNORE BUGCHK MUMBLE" COMMAND
;<OSMAN.SOURCES>DATE.MAC.42, 26-Feb-79 13:59:22, EDIT BY OSMAN
;SEARCH MONITOR SYMBOLS FASTER
;<OSMAN.SOURCES>DATE.MAC.38, 23-Feb-79 14:55:52, EDIT BY OSMAN
;SPEED UP SYMBOL TABLE INITIALIZATION
;<OSMAN.SOURCES>DATE.MAC.32, 22-Feb-79 16:10:42, EDIT BY OSMAN
;READ DATE.CMD DURING LOGIN
;<OSMAN.SOURCES>DATE.MAC.30, 21-Feb-79 09:39:45, EDIT BY OSMAN
;FIX BUGCHK STUFF WHICH BROKE
;Don't ever bitch about job 0 hogging system
;Implement checking for users that are running with special scheduler priority
;<OSMAN.SOURCES>DATE.MAC.11,  2-Feb-79 13:27:36, EDIT BY OSMAN
;set up LSTTIM before trying TIMER JSYS
;<OSMAN.SOURCES>DATE.MAC.10, 31-Jan-79 15:36:04, EDIT BY OSMAN
;<OSMAN.SOURCES>DATE.MAC.9, 31-Jan-79 14:48:51, EDIT BY OSMAN
;BE MORE SPECIFIC WHEN INTERRUPT IS OVERDUE
;<OSMAN.SOURCES>DATE.MAC.7, 31-Jan-79 10:23:34, EDIT BY OSMAN
;SPEED UP BUG REPORTING BY NOT KILLING THE SYSERR FORK
;<OSMAN.SOURCES>DATE.MAC.6, 30-Jan-79 10:54:17, EDIT BY OSMAN
;PRINT ALL BUGHLTS SINCE PREVIOUS LOGIN, RATHER THAN SINCE .CPY CREATION
;MAKE BUGCHK CODE NOT BE INTERRUPT LEVEL
;<OSMAN>DATE.MAC.89, 22-Jan-79 08:44:37, EDIT BY OSMAN
;CATCH FAILING GTFDB AT WRTDAT
;<OSMAN>DATE.MAC.88, 16-Jan-79 11:20:02, EDIT BY OSMAN
;FIX SIXBIT OUTPUT ROUTINE TO NOT STOP ON FIRST NULL (LEADING SPACES!)
;<OSMAN>DATE.MAC.87,  4-Jan-79 15:43:45, EDIT BY OSMAN
;REMOVE PP, FIX GETPTY
;<OSMAN>DATE.MAC.86,  4-Jan-79 15:08:25, EDIT BY OSMAN
;TEMPORARILY PUT IN PP TO FIND OUT WHERE D IS GETTING CLOBBERED
;<OSMAN>DATE.MAC.85,  3-Jan-79 15:45:06, EDIT BY OSMAN
;CORRECTLY RESTORE AC'S AFTER ERROR MESSAGE AT ILL
;<OSMAN>DATE.MAC.84,  8-Dec-78 15:38:20, EDIT BY OSMAN
;DON'T SEND CR AFTER ###
;<OSMAN>DATE.MAC.73,  7-Nov-78 15:10:03, EDIT BY OSMAN
;RECOVER IF NO RESOURCES FOR TIMER ENTRY
;<OSMAN>DATE.MAC.72,  7-Nov-78 10:58:42, EDIT BY OSMAN
;CHANGE INTERVAL TO 10 SECONDS, MAKE ^D SHOW IF INTERRUPT OVERDUE
;<OSMAN>DATE.MAC.70,  6-Nov-78 17:12:21, EDIT BY OSMAN
;USE SAVACS/RESACS INSTEAD OF SAVIAC
;<OSMAN>DATE.MAC.65,  6-Nov-78 16:22:06, EDIT BY OSMAN
;Fix GRUMP logic to not get upset if FB%PGC is wrong
;PMAP the entire BUGSTRINGS.TXT instead of having COMND do lots of BINs!
;<OSMAN>DATE.MAC.15,  3-Nov-78 13:46:14, EDIT BY OSMAN
;Use ERROR.SYS instead of monitor for BUGs.  Now non-wheels can enjoy!
;<OSMAN>DATE.MAC.13,  2-Nov-78 10:54:29, EDIT BY OSMAN
;TEACH IT TO PRINT BUGHLT
;<OSMAN>DATE.MAC.10, 17-Oct-78 14:33:01, EDIT BY OSMAN
;ALLOW BUGCHK NAMES TO BE ENTERED IN LOWERCASE IN "IGNORE" COMMAND
;ALSO, MAKE "?" AND RECOGNITION WORK
;<OSMAN>DATE.MAC.4,  3-Oct-78 17:01:36, EDIT BY OSMAN
;MAKE BOTH FORKS BEFORE HALTING SO "FORK 2" POINTS AT CORRECT DUMMY FORK
;<OSMAN>DATE.MAC.188, 29-Sep-78 13:58:04, EDIT BY OSMAN
;FIX "ERROR AT 7062  INVALID PROCESS HANDLE"
;<OSMAN>DATE.MAC.187, 12-Sep-78 13:11:41, EDIT BY OSMAN
;make grumps get printed in correct case
;CHANGE DATE CHARACTER TO CTRL/D (CTRL/A - CTRL/B ARE NOW TV CASE CONTROL IN INSERTS)
;<OSMAN>DATE.MAC.184,  7-Sep-78 14:20:54, EDIT BY OSMAN
;ALLOW % AND . IN SYMBOL NAMES (YEAH, FINALLY!).  ALSO, DON'T HAVE A TIZZY
;WHEN JOB GETS DETACHED AND REATTACHED.
;<OSMAN>DATE.MAC.183, 28-Aug-78 09:16:16, EDIT BY OSMAN
;FIX GRUMP FAILURE HANDLING
;<OSMAN>DATE.MAC.181, 24-Aug-78 15:37:04, EDIT BY OSMAN
;MAKE GRUMP JFN BE RESTRICTED
;<OSMAN>DATE.MAC.177, 23-Aug-78 11:32:14, EDIT BY OSMAN
;GET ^A WORKING BEFORE INITIALIZING EVERYTHING ELSE
;ONLY PRINT HOGS, INSTEAD OF N JOBS
;<OSMAN>DATE.MAC.172, 22-Aug-78 16:51:49, EDIT BY OSMAN
;PRINT PERCENTAGES
;PROVIDE FOR "[FOO]"IN BUGSTRINGS FILE
;<OSMAN>DATE.MAC.168, 27-Jul-78 09:49:06, EDIT BY OSMAN
;FIX BUGSTRING TYPEOUT
;<OSMAN>DATE.MAC.167, 25-Jul-78 10:20:36, EDIT BY OSMAN
;PUT IN WHEELF TO SHOW IF WHEEL OR NOT
;<OSMAN>DATE.MAC.156,  5-Jun-78 14:09:14, EDIT BY OSMAN
;ADD EXIT COMMAND
;<OSMAN>DATE.MAC.154, 18-May-78 10:22:58, EDIT BY OSMAN
;MAKE ^A SHOW FILES BEING WRITTEN WITH PMAP
;<OSMAN>DATE.MAC.148, 17-May-78 14:27:28, EDIT BY OSMAN
;SIMPLIFY CODE
;<OSMAN>DATE.MAC.147, 16-May-78 16:22:04, EDIT BY OSMAN
;FIX CASE WHERE USER NAME CROSSES PAGE BOUNDARY
;<OSMAN>DATE.MAC.143, 16-May-78 15:25:55, EDIT BY OSMAN
;GUARD AGAINST TTY BUFFER OVERFLOW
;<OSMAN>DATE.MAC.142, 26-Apr-78 15:08:47, EDIT BY OSMAN
;PRINT "NOT LOGGED IN" FOR UNLOGGED IN JOBS ON ^A (INSTEAD OF ERROR!)
;<OSMAN>DATE.MAC.141, 21-Apr-78 14:35:12, EDIT BY OSMAN
;<OSMAN>DATE.MAC.140, 21-Apr-78 14:28:46, EDIT BY OSMAN
;MAKE OUTPUT COME SOONER AFTER EVENT
;<OSMAN>DATE.MAC.139, 21-Apr-78 13:12:30, EDIT BY OSMAN
;<OSMAN>DATE.MAC.138, 21-Apr-78 13:11:08, EDIT BY OSMAN
;PRINT PROGRAM NAME FOR BUGCHKS
;<OSMAN>DATE.MAC.135, 10-Apr-78 15:50:23, EDIT BY OSMAN
;SHOW WHO'S SLOWING DOWN THE SYSTEM
;<OSMAN>DATE.MAC.126, 28-Mar-78 15:37:30, EDIT BY OSMAN
;ADD IGNORE COMMAND
;<OSMAN>TILE.MAC.63, 22-Mar-78 14:24:44, Edit by OSMAN
;USE STANDARD COMND JSYS ERROR ROUTINE
;<OSMAN>DATE.MAC.118, 20-Mar-78 11:41:45, Edit by OSMAN
;PUT IN INFORMATIVE ERROR MESSAGE WHEN DYING
;<OSMAN>DATE.MAC.115, 13-Mar-78 16:50:56, Edit by OSMAN
;DON'T USE TBADD.  IT TAKES TOO LONG.
;<OSMAN>DATE.MAC.88,  3-Mar-78 15:11:05, Edit by OSMAN
;ADD VALUE COMMAND
;ADD SYMBOL COMMAND
;ADD ^Y FEATURE TO TYPE IN COMMANDS.
;<OSMAN>DATE.MAC.86,  3-Mar-78 14:34:09, Edit by OSMAN
;<OSMAN>DATE.MAC.74, 28-Feb-78 11:41:00, Edit by OSMAN
;<OSMAN>DATE.MAC.73, 21-Feb-78 15:16:40, Edit by OSMAN
;PREVENT EXTRA NULLS FROM BEING PRINTED AT END OF GRUMP
;<OSMAN>DATE.MAC.72, 21-Feb-78 14:41:05, Edit by OSMAN
;PREVENT BOMBOUT IF OPERATOR DELETES GRUMP.LOG
;<OSMAN>DATE.MAC.71,  3-Feb-78 14:00:32, Edit by OSMAN
;PMAP DATA FROM GRUMP FILE INSTEAD OF BKJFN/BIN
;<OSMAN>DATE.MAC.56,  3-Jan-78 15:53:42, EDIT BY OSMAN
;TRY TO RECOVER IF GRUMP.LOG GETS RECREATED BY OPERATOR
;<OSMAN>DATE.MAC.55, 12-Dec-77 14:46:59, EDIT BY OSMAN
;END USERNAME BUFFER WITH NULL IN GRUMP LOGIC
;<OSMAN>DATE.MAC.54, 29-Nov-77 09:36:26, EDIT BY OSMAN
;<OSMAN>DATE.MAC.3, 10-Nov-77 22:12:59, EDIT BY OSMAN
;DON'T TRY TO LOCK TTY TWICE! (LIKE BY USING XTMSG AFTER TTYLCK)
;<OSMAN>DATE.MAC.52, 10-Nov-77 13:42:24, EDIT BY OSMAN
;UPDATED SOURCE POINTER AFTER SOUT IS LDB POINTER TO NULL!!
;<OSMAN>DATE.MAC.51, 10-Nov-77 13:09:04, EDIT BY OSMAN
;DON'T LOSE INFORMATION DUE TO AUTO-^S
;<OSMAN>DATE.MAC.47, 27-Sep-77 15:18:15, EDIT BY OSMAN
;FIX IT SO THAT IF USER ISN'T A WHEEL, NON-WHEEL FEATURES STILL WORK
;<OSMAN>DATE.MAC.45, 23-Sep-77 15:00:52, EDIT BY OSMAN
;PUT IN JFN UPDATE FEATURE
;<OSMAN>DATE.MAC.42, 20-Sep-77 15:21:24, EDIT BY OSMAN
;MAKE PROGRAM NOT GET CONFUSED IF WE DETACH AND REATTACH TO DIFFERENT TERMINAL
;<OSMAN>DATE.MAC.41, 12-Sep-77 17:23:41, EDIT BY OSMAN
;PREVENT INFINITE LOOP WHEN SEARCHING FOR BEGINNING OF GRUMP
;<OSMAN>DATE.MAC.40,  8-Sep-77 12:17:29, EDIT BY OSMAN
;MAKE DATE PROGRAM PRINT OUT GRUMPS AS THEY GET SUBMITTED
;<OSMAN>DATE.MAC.32,  3-Sep-77 12:46:52, EDIT BY OSMAN
;REMOVE "CLOSF" AT TERMINATION OF "POP"
;<OSMAN>DATE.MAC.31, 26-Aug-77 16:39:26, EDIT BY OSMAN
;PUT IN AUTO-PUSH
;<OSMAN>DATE.MAC.27, 24-Aug-77 16:06:48, EDIT BY OSMAN
;MAKE SURE TIMINT DOESN'T CLOBBER AC'S
;<OSMAN>DATE.MAC.23, 24-Aug-77 14:50:35, EDIT BY OSMAN
;MAKE THIS PROGRAM ANNOUNCE BUGCHKS!
;<OSMAN>DATE.MAC.13, 19-Aug-77 16:37:36, EDIT BY OSMAN
;MAKE THIS THING SHOW WHEN SOMEONE SPYS OR UNSPIES ON US
;<OSMAN>DATE.MAC.9, 15-Aug-77 17:05:25, EDIT BY OSMAN
;ONLY ENABLE CHANNEL FOR INTERRUPT CHARACTER.
;WAS ENABLING ALL, BUT MONITOR "BUG" CAUSES FORK TERMINATION
;INTERRUPT UNEXPECTEDLY
;<OSMAN>DATE.MAC.8, 15-Aug-77 16:56:46, EDIT BY OSMAN
;<OSMAN>DATE.MAC.7, 15-Aug-77 16:55:28, EDIT BY OSMAN
;<OSMAN>DATE.MAC.6, 15-Aug-77 16:51:34, EDIT BY OSMAN
;MAKE AN INFERIOR FORK, SO WE CAN RUN IN BACKGROUND

TITLE DATE
EXTERNAL .JBSYM,.RLEND

WH==0
VR==5				;MAJOR VERSION #
RV==0				;REVISION #
ED==26				;EDIT NUMBER

%%RH==ED			;RHS FOR LINK
%%LH==<WH>B20+<VR>B29+RV 	;LHS

SEARCH MONSYM,MACSYM,CMD,SERCOD
.REQUIRE SYS:MONSYM,SYS:CMD,SYS:MACREL
SALL				;CAUSE NON-UGLY LISTING PRINTOUT

A=1
B=2
C=3
D=4
Q1=5
Q2=6
Q3=7

P=17

JMAGIC==FLD(.JSAOF,JS%DEV)!FLD(.JSAOF,JS%DIR)!FLD(.JSAOF,JS%NAM)!FLD(.JSAOF,JS%TYP)!FLD(.JSAOF,JS%GEN)!JS%PAF	;BITS TO PRINT ALL FIELDS

DEFINE TYPE (MESSAGE)		;(IN ONE INSTRUCTION AND WITHOUT CLOBBERING ANYTHING)
<	CALL [
	PUSH P,A
	HRROI A,[ASCIZ /Message/]
	PSOUT
	POP P,A
	RET
	]
>

SPLESC==.CHCNN			;ESCAPE CODE FOR OUTPUT
CTRLY=="Y"-100			;INPUT A COMMAND ON CTRL/Y
PDLLEN==5000			;large stack, because all of CMDSTG must fit on it!

NUFKS==30			;NUMBER OF FORKS ALLOWED PER JOB
HGHFPN==37777			;HIGHEST FORK PAGE NUMBER
FILWDS==200			;NUMBER OF WORDS FOR REAL LONG FILESPEC

;DEFINITIONS FOR MONRD% JSYS

OPDEF MONRD% [JSYS 717]

.RDTST==0			;FUNCTION CODE TO TEST FOR EXISTENCE
.RDJSB==2			;READ JSB DATA
.RDPSB==3			;READ PSB DATA

;MACRO TO DO SPECIAL TERMINAL OUTPUT (WITHOUT BLOCKING ON AUTO-^S)

DEFINE XTMSG(WHAT)
<	HRROI A,[ASCIZ WHAT]
	CALL STRNG
>

CMDBEG==.			;DELIMIT COMND STORAGE
CMDSTG				;PUT IN COMND STORAGE
CMDLEN==.-CMDBEG		;SINCE INTERRUPT ROUTINES SAVE CMDSTG ON THE STACK

INITF:	0			;-1 WHEN DATABASES INITIALIZED
INCMDF:	0			;-1 WHEN IN A COMMAND
SICKF:	0			;-1 IF WE GET FATAL ERROR
BUSYF:	0			;0 OR BYE POINTER TO EVENT BEING PROCESSED
SYMF:	0			;-1 WHEN SYMBOL TABLE INITIALIZED
ICHAR:	0			;INTERRUPT CHARACTER
BUGIF:	0			;-1 WHEN BUGCHK MESSAGE TABLE INITIALIZED
LSTTIM:	0			;SYSTEM UPTIME IN MILLISECONDS AT TIME OF LAST INTERRUPT
LDAV:	0			;LOAD AVERAGE
TOTRUN:	0			;TOTAL RUNTIME USED BY JOBS IN LAST INTERVAL
GOBFLG:	0			;-1 WHEN SPECIAL MONITOR SYMBOLS READ

POVLEN==50			;STACK FOR PDLOV HANDLER
POVSTK:	BLOCK POVLEN
PDL:	BLOCK PDLLEN
EFNLEN==50			;MOST NUMBER OF PUSH'S WE CAN HANDLE
EFNTAB:	BLOCK EFNLEN		;EFNTAB+N HOLDS JFN OF FORK 40000N
BNAME:	0			;NAME OF BUGCHK IN SIXBIT
FORKH:	0			;FORK HANDLE
MAXBGN==1500			;NUMBER OF DIFFERENT BUGCHKS THAT CAN BE IGNORED
BIGTAB:	BLOCK MAXBGN+1		;BUGCHKS BEING IGNORED
TIMEX==^D10000			;INTERRUPT EVERY THIS MANY SECONDS
IPC==""			;CHARACTER FOR INSTANT PUSH
STC==""			;STATISTICS CHARACTER
HANGT==^D50			;MILLISECONDS TO WASTE WHILE WAITING FOR CONDITION
TTYPNT:	0			;CURRENT OUTPUT POINTER

NBCHARS==300			;NUMBER OF CHARACTERS TO BUFFER
BUFFER:	BLOCK NBCHARS/5+1	;ROOM FOR THE CHARACTERS
BROOM:	0			;ROOM LEFT IN BUFFER BEFORE DUMP NEEDED
HEIGHT:	0			;NUMBER OF PAPER ROWS TO USE
WIDTH:	0			;NUMBER OF PAPER COLUMNS TO USE
SCRNF:	0			;-1 IF ON SCREEN
TTYJFN:	0			;BINARY CHANNEL FOR SCREENS
BPTR:	0			;OUTPUT BUFFER POINTER
X:	0			;X COORDINATE WE'RE GOING TO
Y:	0			;LIKEWISE
SX:	0			;SCREEN COLUMN
SY:	0			;SCREEN LINE
CRR:	0			;NUMBER OF CHARACTERS FOR CR THEN SPACE OVER
HOM:	0			;NUMBER OF CHARACTERS FOR HOMEUP THEN SPACE OVER
OX:	0			;OLD SCREEN COLUMN
OY:	0			;OLD SCREEN LINE
OLDX:	0			;LAST X WE MOVED TO
OLDY:	0			;LAST Y WE MOVED TO
TRMTYP:	0			;TERMINAL TYPE

TTBSIZ==3000
JMAXLN==200				;MAXIMUM NUMBER OF JOBS WE CAN HANDLE
HOGMAX==30

EXHGMX==30			;MAXIMUM SPECIFIC HOGS WE CAN EXCLUDE
EXHTAB:	0			;TABLE OF HOGS BEING EXCLUDED
	BLOCK EXHGMX		;ADDRESS OF STRING,,0

HOGTAB:	BLOCK HOGMAX		;LIST OF JOB NUMBERS OF JOBS EATING THE SYSTEM
HMX==10			;MAXIMUM HOGS WE CAN FOLLOW
HOGLST:	BLOCK HMX		;LIST OF JOBS HOGGING THE SYSTEM

PERCNT==177B17			;FIELD THAT CONTAINS GUARANTEED PERCENTAGE
LQP1==77B35			;FIELD THAT CONTAINS WORST QUEUE PLUS 1
JRINTB:	BLOCK JMAXLN		;AMOUNT OF RUNTIME IN LAST SEGMENT
OLDRUN:	BLOCK JMAXLN		;TOTAL RUNTIME AT LAST SNAPSHOT
JTLEN:	0			;ACTUAL LENGTH OF JOB TABLES
;*** KEEP NEXT TWO ENTRIES CONSECUTIVE!
TTYBUF:	BLOCK TTBSIZ		;TTY OUTPUT BUFFER
DEAD:	BLOCK 50		;DEAD SPACE FOR TTY BUFFER TO OVERFLOW INTO
;*** KEEP TTYBUF AND DEAD CONSECUTIVE
TTYFLG:	0			;-1 WHEN TTY DATABASE FREE
OUTFLG:	0			;OUTPUT READY FLAG
MIDPNT:	0			;RESULTANT POINTER OF PSOUT
TTYPLN==200			;LENGTH OF OUTPUT SERVER STACK
TTYPDL:	BLOCK TTYPLN		;STACK FOR OUTPUT SERVER
TTYFRK:	0			;HANDLE OF TTY FORK
GRERRF:	0			;SET IF GRUMP ERROR, OR MAIL ERROR
HOGERF:	0			;-1 IF ERRORS REPORTING HOGGERS
SPYERF:	0			;-1 IF ERRORS CHECKING SPYING
HGHJFN==777			;HIGHEST LEGAL JFN
GRUSER:	BLOCK 30		;HOLDS USER NAME WHO SUBMITTED LAST GRUMP
GRPTR:	0			;POINTER TO GRUMP BUFFER
GRPGN:	0			;GRUMP FILE PAGE NUMBER CURRENTLY MAPPED
BACKF:	0			;-1 IF READING BACKWARDS
GEOFDA:	0			;0 OR GRUMP END OF FILE DISPATCH ADDRESS
GPP:	0			;STACK POINTER SAVED DURING GRUMP PROCESSING
LPIG:	0			;LAST PAGE IN GRUMP FILE
EOG:	0			;BYTE POINTER TO END OF GRUMP
GRJFN:	0			;JFN OF GRUMP FILE
GRSIZE:	0			;NUMBER OF BYTES IN GRUMP FILE
OGRSIZ:	0			;OLD NUMBER OF BYTES
GREOL:	0			;POSITION IN GRUMP FILE OF LAST EOL

LOGJFN:	0			;JFN OF LOG FILE

;UPDATE-FILE STUFF

ULEN==20			;NUMBER OF FILESPECS THAT CAN BE WATCHED

UDIR:	BLOCK ULEN		;0 OR DIRECTORY TO BE WATCHED
USIZE:	BLOCK ULEN		;SIZE OF DIRECTORY USED FOR COMPARISON
UTIME:	BLOCK ULEN		;MOST RECENT FILE WRITE-DATE AT LAST CHECK
UFPTR:	BLOCK ULEN		;POINTER TO FILESPEC STRING

;MAIL PREVIEW DATA

SMJFN:	0			;SYSTEM MAIL FILE
MALJFN:	0			;MAIL FILE JFN
MALSIZ:	0			;LATEST KNOWN SIZE FOR MAIL FILE
MALSPC:	BLOCK 30		;GETS NAME OF MAIL FILE
SMSIZ:	0			;SYSTEM MAIL FILE SIZE

LOGNO:	0			;HOLDS LOGIN DIRECTORY NUMBER
EXCNAM:	BLOCK 30		;[NIC] HOLD EXEC NAME
XFORK:	0			;EXEC FORK
JFNZZZ==50			;MAXIMUM NUMBER OF JFNS WE CAN HANDLE
JFNPAG:	BLOCK JFNZZZ		;LOWEST,,HIGHEST MAPPED PAGE NUMBER
JFNLST:	BLOCK JFNZZZ		;WHICH JFNS ARE IN TABLE
JFNNN:	0			;NUMBER OF JFNS IN JFNLST

;*** KEEP LEVxPC CELLS CONSECUTIVE AND IN ORDER
LEV1PC:	0
LEV2PC:	0
LEV3PC:	0

;MACRO FOR PEEKING AT MONITOR CELL

STATF:	0			;STATISTICS BITS (ONE BIT PER ENABLED FEATURE)
	IOF==1B0		;BIT FOR FILE PROGRESS
	SHAREF==1B1		;BIT FOR USAGE REPORTING
	DATEF==1B2		;BIT FOR LOAD LINE
SPYF:	0			;-1 IF CHECKING FOR SPYERS
MAILF:	0			;-1 IF MAIL BEING PREVIEWED
GRUMPF:	0			;-1 IF GRUMPS BEING DISPLAYED
LOGGF:	0			;-1 IF LOGGING
HOGF:	0			;-1 IF CHECKING FOR REAL HOGS
BUGCHF:	0			;-1 TO WATCH FOR BUGCHKS
OLDSPY:	0			;LAST LINK WORD
SERDAT:	0			;LAST TIMESTAMP OF ERROR.SYS FILE BEING WRITTEN
LSTBUG:	0			;TIMESTAMP OF LAST BUG PRINTED
SERJFN:	0			;JFN ON SYSTEM ERROR FILE
HLTJFN:	0			;ANOTHER JFN ON SAME FILE!! (SO REPBUG IS QUASI-REENTERABLE)
OGPAG:	0			;OLD GOOD PAGE (FIRST TO TRY)
SYMEND:	0			;NEXT FREE LOCATION FOR STORING ASCII OF SYMBOL VALUE
KEYBLK:	FLDBK. .CMKEY,,SYMLST,,,[BRMSK. KEYB0.,KEYB1.,KEYB2.,KEYB3.,<%.$>,<->] ;GETS MODIFIED FOR ACTUAL TABLE
SYMTAD=KEYBLK+.CMDAT		;HOLDS TABLE STARTING ADDRESS
FREE==240000			;FREE SPACE BEGINS HERE
DICT:	0			;FREE SPACE HEADER WORD
FRESIZ==40000			;FREE SPACE ENDS AT BUGBUF
STRSIZ==400			;WORDS FOR STRING SCRATCH STORAGE
CSBUFP:	0			;POINTER TO STRING SCRATCH
BUGBUF==300000			;BUFFER FOR READING BUG FILE INTO
BUGBPN==BUGBUF_-9		;PAGE NUMBER OF BUFFER
BUGBSZ==<BUGTAB-BUGBUF>_-9	;NUMBER OF PAGES WE HAVE ROOM FOR READING BUG FILE INTO
BUGTAB==400000			;TABLE OF BUGCHKS
BUGSTR==500000			;STRINGS OF BUGCHK NAMES START HERE
BUGMAX==BUGSTR-BUGTAB-1		;MAXIMUM ENTRIES TABLE MAY HOLD
HLTPAG==600000			;ERROR.SYS BUFFER FOR BUGHLTS
HLTPNN==HLTPAG_-9		;PAGE NUMBER FOR BUGHLT BUFFER
SERPAG==601000			;ADDRESS INTO WHICH ERROR.SYS PAGE IS MAPPED
SERPNN==SERPAG_-9		;PAGE NUMBER
GRBPAG==SERPAG+1000			;GRUMP PAGE
GRBPN==GRBPAG_-9		;PAGE NUMBER
SYMLST=GRBPAG+1000		;ROOM FOR SYMBOL TABLE
	;***  NOTE:  SYMBOL TEXT FOLLOW SYMBOL TABLE!
TTLINK:	0			;VALUE OF MONITOR SYMBOL
TTACTL:	0			;VALUE OF MONITOR SYMBOL
MAXJFN:	0			;MAXIMUM JFN IN USE FOR JOB
MLJFN:	0			;SIZE OF JFN BLOCK
FILNEN:	0			;NAME,,EXT (POINTER)
FILVER:	0			;FORK,,VERSION
FILDNM:	0			;DIR,, (POINTER)
FILDDN:	0			;DEV,,DIR #
FILSTS:	0			;FILE STATUS
JOBBIT:	0			;SCHEDULER CONTROL WORD FOR PROCESS
JOBSKD:	0			;JOB'S SCHEDULER CONTROL WORD
SYSFK:	0			;FORK TABLE WITHIN JOB
JSVAR:	0			;BEGINNING OF JSB VARIABLES
PSVAR:	0			;BEGINNING OS PSB VARIABLES



DEFINE INTX (CHANNEL,LEVEL,ADDRESS)
<	%%X==.				;;REMEMBER WHERE WE ARE
	RELOC CHNTAB+CHANNEL		;;GET TO APPROPRIATE PART OF TABLE
	XWD LEVEL,ADDRES		;;TELL MONITOR PRIORITY AND WHERE TO GO
	%%CH==%%CH!1B<CHANNEL>		;;REMEMBER TO ENABLE THIS CHANNEL
	RELOC %%X			;;GET BACK TO WHERE WE WERE
>

	ILLLEV==1		;LEVEL OF ILL INST INT (MUST BE HIGHER PRIORITY THAN ALL ELSE!)
TIMCHN==1			;CHANNEL FOR TIMER INTERRUPTS
	TIMLEV==3		;LEVEL FOR TIMER INTERRUPTS
				;NOTE:  TIMER INTERRUPTS MUST BE LESS PRIORITY
				;THAN FORK TERMINATION, SINCE TTYULK STARTS
				;TTYFRK WHICH WHEN HALTS WANTS TO BE KNOWN
CMDCHN==3			;COMMAND EXECUTION CHANNEL
	CMDLEV==3		;COMMAND LEVEL
CTYCHN==5			;CHANNEL FOR COMMAND REQUEST (CTRL/Y)
	CTYLEV==2		;LEVEL FOR COMMAND REQUEST (BUT NOT COMMAND EXECUTION)
%%CH==0				;INTERESTING CHANNELS

CHNTAB:	BLOCK 6*6			;LEAVE ROOM FOR ALL CHANNELS
	INTX 0,2,DATE			;USER WANTS DATE, TIME, LOAD AVERAGE
	INTX .ICDAE,ILLLEV,ICDAE	;DATA ERROR
	INTX .ICQTA,ILLLEV,ICQTA	;QUOTA EXCEEDED
	INTX .ICIRD,ILLLEV,ICIRD	;ILLEGAL MEMORY READ
	INTX .ICIWR,ILLLEV,ICIWR	;ILLEGAL MEMORY WRITE
	INTX .ICMSE,ILLLEV,ICMSE	;SYSTEM RESOURCES EXHAUSTED
	INTX TIMCHN,TIMLEV,TIMINT	;TIMER INTERRUPTS (DON'T MOVE UNLESS TIMCHN REDEFINED!)
					;LOWER CHANNEL SO IN CASE WE HAVE TO WAIT FOR TIMER
					;TO SUCCEED, EVERYTHING ELSE WILL STILL WORK
	INTX 2,2,.PUSH			;USER WANTS TO DO AUTO-PUSH
	INTX CMDCHN,CMDLEV,COMAND	;USER WANTS TO TYPE A COMMAND
	INTX CTYCHN,CTYLEV,.CTRLY	;USER WANTS TO TYPE A COMMAND
	INTX .ICPOV,1,PDLOV		;STACK OVERFLOW
	INTX .ICILI,ILLLEV,ILL		;ILLEGAL INSTRUCTION EXECUTED
	INTX .ICIFT,2,.POP		;ONE OF OUR INFERIORS HALTED

CHNS==%%CH				;REMEMBER WHAT CHANNELS TO ACTIVATE

LEVTAB:	LEV1PC
	LEV2PC
	LEV3PC

BEG:	MOVE P,[IOWD PDLLEN,PDL]
	RESET			;DO AS LITTLE AS POSSIBLE BEFORE STARTING EXEC
	SETZM SICKF		;NOT SICK YET
	CALL FREINI		;INITIALIZE FREE SPACE
	SETZM INCMDF		;NOT IN COMMAND (MUST BE DONE BEFORE AIC)
	SETZM EFNTAB		;CLEAR FORK TABLE
	MOVE A,[EFNTAB,,EFNTAB+1]	;MUST DO THIS BEFORE ENABLING FOR FORK TERMINATION INTERRUPT
	BLT A,EFNTAB+EFNLEN-1	;EFNTAB MUST BE ENABLED BEFORE .ICIFT ACTIVATED!!
	SETZM UDIR		;NO DIRECTORIES BEING CHECKED YET
	MOVE A,[UDIR,,UDIR+1]
	BLT A,UDIR+ULEN-1
	CALL TTYIN		;INIT TTY FORK
	CALL TTYINI		;INITIALIZE TERMINAL STUFF
	MOVEI A,400000
	MOVE B,[LEVTAB,,CHNTAB]
	SIR
	EIR
	MOVX B,CHNS		;ACTIVATE INTERESTING CHANNELS
	AIC			;DO EARLY SO "POP" GETS DIAGNOSED
	CALL EXEINI		;GET EXEC SO USER CAN WORK
	 JRST [	TYPE <?DATE: Couldn't start an exec - >
		CALL PERR	;GIVE AN EXCUSE
		HALTF
		JRST BEG]	;IF CONTINUE, RETRY
	MOVEM A,XFORK		;REMEMBER HANDLE OF EXEC
	MOVEI B,0		;STANDARD STARTUP
	SFRKV			;START IT
	SETOM OLDSPY		;SO IF SPYERS WHEN WE START, WE'LL KNOW
	SETZM INITF		;SAY NOT INITIALIZED YET
	SETZM GOBFLG		;HAVEN'T READ SPECIAL MONITOR SYMBOLS YET
	MOVEI A,400000
IFE STANSW,<
	SETOB B,C		;WE WANT ALL PRIVS
>;IFE STANSW
IFN STANSW,<
	RPCAP			;GET OUR PRIVS
	IOR C,B			;WE WANT ALL PRIVS WE CAN GET
>;IFN STANSW
	EPCAP
	MOVE A,[-1,,.JOBRT]
	GETAB			;SEE HOW MANY JOBS CAN EXIST
	 JSERR
	CAMGE A,[-JMAXLN]	;MAKE SURE WE HAVE ROOM FOR THEM ALL
	MOVNI A,JMAXLN		;NO, SO ONLY USE THIS MUCH
	MOVNM A,JTLEN		;REMEMBER
	SETOM HOGLST		;NO HOGS YET
	MOVE A,[HOGLST,,HOGLST+1]
	BLT A,HOGLST+JMAXLN-1
	CALL RUPDAT		;INITIALIZE RUNTIME TABLES (NOW, SO ^D WORKS)
	SETZM BUSYF		;DO AFTER INITIAL RUPDAT, SINCE RUPDAT SETS IT
	MOVEI A,EXHGMX		;SAY NO EXCLUSIONS YET BUT EXHGMX MAX ALLOWED
	MOVEM A,EXHTAB
	SETZM GRERRF		;NOTE THAT WE MAY STILL BE ABLE TO LOG GRUMPS
	SETZM SPYERF		;NO SPY ERRORS YET
	SETZM HOGERF		;NO ERRORS CHECKING FOR HOGGERS YET
	SETZM GRJFN		;NO GRUMP JFN YET
	SETZM MALJFN		;NO MAIL JFN YET
	SETZM SMJFN		;NO SYSTEM MAIL JFN YET
	HRLOI A,377777		;SET SIZES LARGE, SO NO DISPLAY HAPPENS...
	MOVEM A,GRSIZE		;FIRST TIME, BUT WE WANT DISPLAY...
	MOVEM A,SMSIZ		;IF FILE BECOMES EXISTENT
	MOVEM A,MALSIZ
	SETZM SERJFN		;NO SYSTEM ERROR JFN YET
	SETZM CMDJFN		;NO DATE.CMD JFN YET
	SETZM GRUMPF		;INITIALLY DON'T TYPE GRUMPS
	SETZM LOGGF		;NOT LOGGING YET
	SETZM MAILF		;NOT PREVIEWING MAIL YET
	SETZM BUGCHF		;INITIALLY DON'T REPORT BUGCHKS
	SETZM STATF		;NO INSTANT STATISTICS ENABLED YET
	CALL DTIMER		;GET TIMER INTERRUPTS HAPPENING
	MOVEI A,MAXBGN
	MOVEM A,BIGTAB		;INITIALLY NO BUGCHKS BEING IGNORED
	MOVEI A,CTRLY
	CALL SETIC		;SET UP INTERRUPT CHARACTER AS CTRL/Y
	CALL NEWCMD		;NOW THAT DATABASES ARE INITIALIZED
	SETOM INITF		;MARK THAT INITIALIZATION IS OVER
	WAIT			;WAIT FOR SOMETHING TO HAPPEN

;ROUTINE TO GET WRITE DATE AND TIME OF FILE.
;ACCEPTS:	A/	POINTER TO FILENAME OR 0,,JFN
;RETURNS:	+1:	ERROR
;			A/	REASON CODE
;		+2:	SUCCESS
;			A/	JFN
;			B/	INTERNAL DATE AND TIME OF LAST WRITE

WRTDAT:	MOVEI B,.FBWRT		;WHAT GTFDB TO DO
	CALLRET DOFDB		;DO IT AND RETURN

DOFDB:	STKVAR <WHAT>
	HRLI B,1		;SAY WE WANT ONE WORD
	MOVEM B,WHAT
	MOVE B,A		;STRING POINTER IN B
	TLNN B,-1		;MAKE SURE IT IS A POINTER
	JRST WRT1		;NO, IT'S A JFN, SKIP THE GTJFN
	MOVX A,GJ%ACC!GJ%OLD!GJ%SHT	;RESTRICTED (SO OTHER FORKS DON'T SCREW US UP WITH CLOSF), OLD FILE, SHORT FORM GTJFN
	GTJFN			;GET HANDLE ON LAST FILE
	 ERJMP R		;DO NOTHING IF NO FILE
WRT1:	MOVEI C,B		;WHERE TO WRITE DATA
	MOVE B,[1,,.FBCTL]	;FIRST SEE IF FILE IS DELETED
	GTFDB
	 ERJMP R		;FAILURE RETURN IF CAN'T EVEN FIND OUT
	TXNE B,FB%DEL		;HAS FILE BEEN DELETED?
	 RET			;YES, HANDLE CASE OF MS DELETING EMPTY MAIL FILE
	MOVE B,WHAT		;SAY WHAT INFO CALLER REALLY WANTS
	GTFDB			;GET THE INFO
	 ERJMP R		;WILL FAIL IF OPERATOR EXPUNGES FILE!
	RETSKP			;SAY SUCCESS

;ROUTINE TO GET SIZE IN BYTES OF FILE.
;ACCEPTS:	A/	POINTER TO FILENAME OR 0,,JFN
;RETURNS:	+1:	ERROR
;			A/	REASON CODE
;		+2:	SUCCESS
;			A/	JFN
;			B/	NUMBER OF BYTES

GETFSZ:	MOVEI B,.FBSIZ		;SAY WHAT TO GET
	CALLRET DOFDB		;GET IT

;ROUTINE TO PRINT INFORMATION ABOUT LAST CRASH.  THIS ROUTINE TRIES TO ONLY
;GIVE THE INFO IF THIS IS YOUR FIRST LOGIN SINCE THE CRASH.

PRTHLT:	STKVAR <PRVLOG,CPYDAT>
	HRROI A,-1		;OURSELF
	HRROI B,PRVLOG		;ONE WORD, READ INTO D
	MOVEI C,.JILLN		;GET TIME OF PREVIOUS LOGIN
	GETJI
	 JSERR			;SHOULDN'T FAIL
	HRROI A,[ASCIZ /SYSTEM:DUMP.EXE/]
	CALL WRTDAT		;GET WRITE DATE OF FILE
	 RET			;COULDN'T SO MUST NOT BE ONE
	MOVEM B,CPYDAT
	RLJFN			;NO MORE NEED FOR DUMP FILE
	 JSERR			;SHOULDN'T FAIL
	MOVE D,PRVLOG
	CAML D,CPYDAT		;HAS A DUMP BEEN MADE MORE RECENTLY THAN LOGIN?
	RET			;NO, SO NO CRASH TO REPORT
	CALL GETSYS		;GET JFN ON ERROR.SYS
	 RET			;NO ERROR.SYS
	MOVEM A,HLTJFN		;REMEMBER JFN
	MOVEI A,1		;SAY WE WANT HALTS REPORTED
	MOVE B,PRVLOG		;ANY REPORTED SINCE PREVIOUS LOGIN
	CALLRET REPBUG		;REPORT THE BUGHLTS

;ROUTINE TO REPORT BUGS.
;ACCEPTS:	A/	0 FOR CHKS, 1 FOR HLTS
;		B/	STARTING LOGTIME (INTERNAL FORMAT) FOR SYSERR
;RETURNS:	+1 ALWAYS	A/	LOGTIME OF LAST ENTRY REPORTED or 0 if none

SERHLN==10			;MAXIMUM HEADER SIZE WE CAN READ
SERBLN==300			;MAXIMUM ENTRY SIZE WE CAN READ

;OFFSETS IN HEADER WORD

HDRCOD==0			;HEADER WORD
	SER%ET==777B8		;ENTRY TYPE
		SER%BG==102	;BUGCHK
		SER%ER==377	;FILE ABORTED DUE TO ERROR
		SER%EF==777	;NORMAL END OF FILE MARKER (BUT I'VE NEVER SEEN ONE!)
	SER%HL==7B26		;HEADER LENGTH FIELD
	SER%EL==777B35		;ENTRY LENGTH FIELD
HDRDAT==1			;TIME ENTRY WAS LOGGED

REPBUG:	TRVAR <WCHJFN,MIDP,SERWCH,<SERHDR,SERHLN>,<SERBLK,SERBLN>,DATLR1,<BUGFVR,2>,HLTFLG,<BUGNAM,2>,<BUGTIM,4>,<BUGPRG,2>,<BUGUSR,20>,BUGDAT,SERPN,SERFST,SERLST,SERHEL,SERLEN,SERWP,BIGP,SMLP,ENDP,SERPN0,SERPG0>
	MOVEM A,HLTFLG		;REMEMBER WHICH WE'RE LOOKING FOR
	MOVEM B,BUGDAT		;REMEMBER WHAT DATE TO USE
	MOVEI A,SERPNN		;FIRST ASSUME BUGCHKS
	MOVEI B,SERPAG
	MOVEI C,SERJFN
	SKIPE HLTFLG
	JRST [	MOVEI A,HLTPNN
		MOVEI B,HLTPAG	;DIFFERENT BUFFERS FOR BUGHLT PROCESSING
		MOVEI C,HLTJFN
		JRST .+1]
	MOVEM A,SERPN0		;REMEMBER PAGE NUMBER OF BUFFER
	MOVEM B,SERPG0		;REMEMBER ADDRESS OF BUFFER
	MOVEM C,WCHJFN		;REMEMBER WHICH JFN
	SETZM DATLR1		;NO BUG TIMESTAMP YET
	SETOM SERPN		;SAY THERE'S NO MAPPED PAGE YET
	MOVE A,@WCHJFN		;GET HANDLE ON ERROR.SYS
	MOVX B,OF%RD		;OPEN FOR READING
	OPENF			;OPEN IT
	 ERJMP [	MOVE A,@WCHJFN	;COULDN'T OPEN, MAYBE NEW ERROR.SYS FILE.
			RLJFN	;RELEASE OLD HANDLE ON IT
			 JSERR
			SETZM @WCHJFN	;FORCE GTJFN TO BE DONE AGAIN
			MOVEI A,0	;NOTE THAT NO ENTRIES REPORTED
			RET]	;WAIT TILL NEXT TIME AROUND
	FFFFP			;GET FIRST FILE PAGE
	 ERJMP PRTKF		;FILE PROBABLY GOT DELETED
	TRNN A,-1		;IS FILE NONEMPTY?
	JRST PRTKF		;NO, NOTHING TO DO
	SOJ A,			;YES, GET LAST USED PAGE NUMBER
	HRRZM A,ENDP		;REMEMBER
	CALL SERBEG		;FIGURE OUT WHICH PAGE TO START WITH
	 JRST PRTKF		;FAILED, GIVE UP FOR NOW
	CALL SERMAP		;MAP IN THE STARTING PAGE
	 JRST PRTKF		;FAILED
	MOVE A,SERPN		;SEE WHICH PAGE IS MAPPED
	LSH A,9			;MAKE AN ADDRESS
	SOJ A,			;PRETEND LAST BLOCK ENDED JUST BEFORE IT
	MOVEM A,SERLST		;SAY WHERE "LAST BLOCK" ENDED
	SUBI A,200
	MOVEM A,SERFST		;FORCE SYNCHRONIZATION ON FIRST CALL TO SERNXT
BUGLUP:	CALL SERNXT		;GET NEXT BLOCK
	 JRST PRTKF		;NO MORE BLOCKS
	LOAD A,SER%ET,HDRCOD+SERHDR	;GET ENTRY TYPE
	CAIE A,SER%EF		;END OF FILE?
	CAIN A,SER%ER		;OR FILE ABORTED DUE TO ERROR?
	JRST PRTKF		;YES, NO MORE
	CAIE A,SER%BG		;IS THIS ENTRY A BUG?
	JRST BUGLUP		;NO, SKIP IT
	MOVE A,HDRDAT+SERHDR	;GET TIME STAMP ON ENTRY
	CAMGE A,BUGDAT		;IS THIS ONE A NEW ONE?
	JRST BUGLUP		;NO, SKIP IT
	MOVEM A,DATLR1		;REMEMBER STAMP ON BUG
	MOVX B,BG%HLT		;GET BUGHLT FLAG
	SKIPE HLTFLG		;REPORTING HALTS?
	CAMN B,BG%FLG+SERBLK	;AND... IS THIS A BUGHLT ENTRY?
	SKIPA			;YES..., REPORT IT
	JRST BUGLUP		;NO..., DON'T REPORT IT
	MOVE A,BG%NAM+SERBLK	;GET SIXBIT NAME
	HRROI B,BUGNAM		;SAY WHERE TO WRITE ASCII
	CALL SIXASC		;CHANGE SIXBIT TO ASCII
	MOVE B,BG%DAT+SERBLK	;GET TIME OF BUG
	HRROI A,BUGTIM		;WRITE ASCII TIME IN BUGTIM
	MOVX C,OT%NDA		;ONLY THE TIME
	ODTIM			;GET STRING FOR THE TIME
	MOVX A,BYTE(7)"?"
	MOVEM A,BUGUSR		;USE QUESTION MARK IF NO USER NUMBER
	MOVE B,BG%USR+SERBLK	;GET USER WHO "CAUSED" THE BUG
	HRROI A,BUGUSR		;WE WANT ASCII USER NAME IN BUGUSR
	DIRST			;GET USER NAME
	 ERJMP .+1		;USE "?" IF CAN'T GET USER NAME
	MOVE A,BG%PNM+SERBLK	;GET PROGRAM NAME
	HRROI B,BUGPRG		;WRITE ASCII TO BUGPRG
	CALL SIXASC
	SKIPN HLTFLG		;NO IGNORE FEATURE FOR HALTS
	 JRST [	HRROI B,BUGNAM	;WE'RE DOING BUGCHKS, SEE WHICH ONE
		MOVEI A,BIGTAB	;LOOK AT TABLE OF ONES BEING IGNORED
		TBLUK		;SEE IF THIS ONE IS BEING IGNORED
		TXNE B,TL%EXM	;EXACT MATCH?
		JRST BUGLUP	;YES, IGNORE THIS ONE
		JRST .+1]
	CALL BUGINI		;INITIALIZE BUGCHK TABLE
	XTMSG <*[>		;BELL TO GET USER'S ATTENTION
	HRROI A,BUGTIM		;PUT TIME STAMP ON
	CALL STRNG
	HRROI A,[ASCIZ / BUG??? /] ; DEFAULT TO UNKNOWN BUG TYPE
	MOVE B,BG%FLG+SERBLK	;GET BUG TYPE FOR THIS ENTRY
	CAIN B,BG%HLT		; BUGHLT?
	HRROI A,[ASCIZ / BUGHLT /] ; YES
	CAIN B,BG%CHK		; BUGCHK?
	HRROI A,[ASCIZ / BUGCHK /] ; YES
	CAIN B,BG%INF		; BUGINF?
	HRROI A,[ASCIZ / BUGINF /] ; YES
	CALL STRNG		;DUMP STRING WITHOUT BLOCKING
	HRROI A,BUGNAM		;WE HAVE ENTIRE NAME NOW, TYPE IT OUT
	CALL STRNG
	XTMSG <: USER >
	HRROI A,BUGUSR		;GET POINTER TO USER NAME
	CALL STRNG
	XTMSG <, PROGRAM >
	HRROI A,BUGPRG
	CALL STRNG		;TYPE PROGRAM NAME
	XTMSG <
>
	MOVEI A,BUGTAB		;LOOK UP MESSAGE FOR BUG (SYSERR BLOCK MIGHT NOT HAVE MESSAGE IN IT!)
	HRROI B,BUGNAM		;POINT TO CURRENT BUGHLT
	TBLUK			;TRY TO FIND IT
	TXNN B,TL%EXM		;EXACT MATCH ON SOMETHING?
	JRST [	HRROI A,[ASCIZ /Can't find message for BUG/]
		JRST PRTMS1]
	CALL GETSTR		;GET POINTER TO STRING
PRTMS1:	CALL STRNG		;TYPE OUT BUG EXPLANATION
	XTMSG <]
>
	JRST BUGLUP		;SEE IF ANY MORE BUGS
PRTKF:	HRROI A,-1		;UNMAP PAGE OF ERROR.SYS FILE
	HRLI B,.FHSLF
	HRR B,SERPN0		;DIFFERENT PAGE NUMBER FOR BUGHLTS AND BUGCHKS
	MOVEI C,0		;NO SPECIAL BITS
	PMAP			;UNMAP IT
	MOVE A,@WCHJFN		;GET JFN
	SKIPN HLTFLG		;RELEASE FILE IF BUGHLT REPORT
	TXO A,CO%NRJ		;DON'T RELEASE THE JFN
	CLOSF			;CLOSE IT
	 JSERR			;SHOULDN'T FAIL
	MOVE A,DATLR1		;RETURN DATE-AND-TIME OF LAST ONE PRINTED
	RET

;ROUTINE TO INPUT THE NEXT ERROR BLOCK.  SERLST IS THE FILE ADDRESS OF THE
;LAST WORD OF THE PREVIOUS BLOCK

SERNXT:	SAVEAC <Q1,Q2,Q3>	;SAVE PERMANENTS!
	MOVE Q3,SERLST		;GET LAST ADDRESS OF PREVIOUS BLOCK
	AOJ Q3,			;GET FIRST ADDRESS OF BLOCK WE'RE READING
	TRNN Q3,177		;IS THIS ADDRESS OF HEADER WORD?
	AOJ Q3,			;NO, NOW IT IS.  (SKIP BLOCK SYNCH WORDS)
	MOVE A,Q3		;GET FIRST ADDRESS OF NEW ENTRY
	MOVE B,SERFST		;GET FIRST ADDRESS OF OLD ENTRY
	LSH A,-7		;ROUND TO BLOCK NUMBER
	LSH B,-7
	CAMN A,B		;IS NEW ENTRY IN A NEW BLOCK?
	JRST SERNX0		;NO
	LSH A,7			;YES, GET ADDRESS OF BEGINNING OF BLOCK
	CALL SERGET		;READ SYNCH WORD TO MAKE SURE WE'RE IN SYNCH
	 RET			;FAILURE RETURN IF CAN'T READ SYNCH WORD
	DPB A,[000700,,Q3]	;FORCE FIRST WORD OF SYSERR BLOCK TO WHAT SYNCH WORD SAYS
SERNX0:	MOVEM Q3,SERFST		;REMEMBER FIRST WORD OF SYSERR BLOCK
	MOVE A,Q3
	CALL SERGET		;GET HEADER WORD CONTAINING LENGTH OF HEADER
	 RET			;FAILED
	JUMPE A,R		;IF HEADER WORD 0, ASSUME WE'RE AT END OF FILE
	LOAD B,SER%HL,A		;GET HEADER LENGTH
	MOVE A,B
	CAILE A,SERHLN		;MAKE SURE OUR HEADER BLOCK HAS ENOUGH ROOM
	MOVEI A,SERHLN		;NO, SO READ ONLY WHAT FITS
	MOVEM A,SERHEL		;REMEMBER HOW MANY HEADER WORDS WE'RE ACTUALLY READING
	MOVN B,B		;SET UP LOOP FOR READING ENTIRE HEADER
	HRL Q1,B		;SET UP LOOP COUNTER TO DO EXACTLY AS MANY WORDS AS IN HEADER
	MOVEI Q2,0		;KEEP TRACK OF HOW MANY WORDS WE'VE READ
SERNX1:	TRNN Q3,177		;IS THIS THE FIRST WORD OF BLOCK?
	AOJ Q3,			;YES, IT'S A SYNCH WORD, SO SKIP IT
	CAML Q2,SERHEL		;READ ALL WORDS WE CAN HANDLE?
	JRST SERNX4		;YES, JUST SCAN FOR SYNCH WORDS
	MOVE A,Q3		;GET ADDRESS OF HEADER WORD WE'RE READING
	CALL SERGET		;READ WORD, SKIP SYNCH WORDS
	 RET			;FAILED
	MOVEI B,SERHDR		;GET ADDRESS OF HEADER BLOCK
	ADD B,Q2		;FIGURE OUT WHICH WORD OF HEADER WE'RE SETTING UP
	MOVEM A,(B)		;SET UP WORD OF HEADER
SERNX4:	AOJ Q2,			;REMEMBER HOW MANY WORDS READ
	AOJ Q3,			;STEP TO NEXT ADDRESS
	AOBJN Q1,SERNX1		;READ ALL WORDS OF HEADER
	LOAD A,SER%EL,HDRCOD+SERHDR	;GET LENGTH OF ENTRY
	CAILE A,SERBLN		;MAKE SURE WE HAVE ROOM FOR ENTRY OF THIS LENGTH
	MOVEI A,SERBLN		;NO, SO READ ONLY WHAT WE HAVE ROOM FOR
	MOVEM A,SERLEN		;REMEMBER ENTRY LENGTH WE'RE ACTUALLY READING
	LOAD A,SER%EL,HDRCOD+SERHDR	;SET UP LOOP TO ACTUALLY READ ENTIRE ENTRY
	MOVN A,A
	HRL Q1,A		;MAKE LOOP COUNTER FOR READING ENTRY
	MOVEI Q2,0		;REMEMBER WHICH WORD OF ENTRY WE'RE READING
SERNX2:	TRNN Q3,177		;IS THIS THE FIRST WORD OF BLOCK?
	AOJ Q3,			;YES, IT'S A SYNCH WORD, SO SKIP IT
	CAML Q2,SERLEN		;HAVE WE READ AS MANY WORDS AS WE WANT?
	JRST SERNX3		;YES, JUST SCAN REST TO CALCULATE LAST ADDRESS
	MOVE A,Q3		;GET ADDRESS OF ENTRY WE'RE READING
	CALL SERGET		;READ WORD OF ENTRY
	 RET			;FAILED
	MOVEI B,SERBLK		;GET ADDRESS OF ENTRY BLOCK
	ADD B,Q2		;CALCULATE WHICH WORD WE'RE SETTING UP
	MOVEM A,(B)		;SET UP AN ENTRY WORD
SERNX3:	AOJ Q2,			;REMEMBER WHICH WORD WE'RE READING
	AOJ Q3,			;REMEMBER ABSOLUTE WORD WE'RE READING
	AOBJN Q1,SERNX2		;LOOP FOR ENTIRE ENTRY
	SOJ Q3,			;CALCULATE LAST ADDRESS USED BY ENTRY
	MOVEM Q3,SERLST		;REMEMBER LAST ADDRESS OF ENTRY
	RETSKP			;GIVE GOOD RETURN

;ROUTINE TO MAP IN A PAGE FROM THE ERROR.SYS FILE

SERMAP:	CAMN A,SERPN		;IS THIS PAGE ALREADY MAPPED?
	RETSKP			;YES, NOTHING TO DO
	CAMLE A,ENDP		;MAKE SURE STILL IN FILE
	RET			;NO (PREVENT ILL MEM READ IF ERROR.SYS BEING UPDATED SLOWER THAN WE'RE READING IT!)
	MOVEM A,SERPN		;NO, SAY IT'S MAPPED NOW
	HRL A,@WCHJFN		;USE APPRORIATE JFN
	HRLI B,.FHSLF		;OURSELF
	HRR B,SERPN0		;DIFFERENT PAGE NUMBER FOR BUGHLTS AND BUGCHKS
	MOVX C,PM%RD		;WE WANT TO READ IT
	PMAP			;MAP IT
	 ERJMP R		;FAILED, FILE PROBABLY EXPUNGED
	RETSKP			;SKIP FOR SUCCESS

;ROUTINE TO READ WORD FROM ERROR.SYS FILE

SERGET:	MOVEM A,SERWCH		;REMEMBER WHICH WORD TO GET
	LSH A,-9		;CALCULATE PAGE NUMBER
	CALL SERMAP		;MAP IN CORRECT PAGE
	 RET			;FAILURE RETURN
	LDB A,[001100,,SERWCH]	;SEE WHICH WORD OF PAGE IS DESIRED
	MOVE B,SERPG0		;GET BASE ADDRESS
	ADD B,A			;GET ADDRESS CONTAINING DATA
	MOVE A,(B)		;GET THE DATA
	RETSKP

;ROUTINE TO FIGURE OUT WHICH PAGE IN ERROR.SYS IS THE MOST CURRENT PAGE
;STARTING WITH AN ENTRY OLDER THAN THE ONES WE'RE LOOKING FOR.

SERBEG:	SETZM SMLP		;START LOWER BOUND AT BEGINNING OF FILE
	MOVE A,ENDP
	MOVEM A,BIGP		;START HIGH BOUND AT END OF FILE
	MOVE A,OGPAG		;GET OLD GOOD PAGE AS GUESS FOR PAGE TO START WITH
	CAMG A,ENDP		;DON'T TRY TO GUESS IF GUESS IS TOO HIGH
	JRST SERI1
SERI2:	MOVE A,BIGP		;GET LARGE PAGE NUMBER
	SUB A,SMLP		;CALCULATE RANGE
	CAIG A,1		;MORE THAN ONE PAGE DIFFERENT?
	JRST [	MOVE A,SMLP	;RANGE IS REAL SMALL, RETURN WITH BEGINNING OF RANGE
		MOVEM A,OGPAG	;REMEMBER WHICH PAGE TO SEARCH FROM NEXT TIME
		RETSKP]
	ASH A,-1
	ADD A,SMLP		;CALCULATE MIDPAGE
SERI1:	MOVEM A,MIDP		;REMEMBER MIDDLE
	CALL GETLOG		;GET FIRST DATE ON THIS PAGE
	 RET			;FAILED
	CAMGE A,BUGDAT		;IS THIS ENTRY TOO RECENT TO BE FIRST GOOD ONE?
	JRST [	MOVE A,MIDP	;ENTRY IS TOO OLD, CHANGE LOW BOUND TO MIDDLE
		MOVEM A,SMLP
		JRST SERI2]	;TRY AGAIN
	MOVE A,MIDP		;ENTRY IS TOO NEW, MOVE UPPERBOUND DOWN
	MOVEM A,BIGP
	JRST SERI2

;ROUTINE TO GET LOG STAMP OF FIRST SYSERR ENTRY ON SPECIFIED PAGE

GETLOG:	LSH A,9			;MAKE ADDRESS
	MOVEM A,SERWP		;REMEMBER ADDRESS WE'RE READING
	CALL SERGET		;GET CONTENTS OF FIRST WORD OF PAGE
	 RET			;FAILED
	MOVEI A,HDRDAT(A)	;GET OFFSET FOR TIMESTAMP
	ADD A,SERWP		;GET ACTUAL ADDRESS CONTAINING TIMESTAMP
	CALL SERGET		;READ TIMESTAMP
	 RET			;FAILED
	RETSKP			;SUCCESS

;ROUTINE WHICH TAKES TABLE ADDRESS IN A, AND RETURNS POINTER OF FORM -1,,ADR
;TO THE STRING POINTED TO BY THE TABLE ENTRY

GETSTR:	HRRO A,(A)		;YES, GET POINTER TO STRING, MAYBE PRECEDED BY FLAGS
	MOVX B,177B6		;MASK FOR FIRST CHARACTER POSITION
	TDNN B,(A)		;DOES STRING START ON FIRST WORD?
	AOJ A,			;NO, FLAGS FIRST, GET TO STRING
	RET

;MACRO FOR CAUSING A COMMAND ERROR THAT WE DETECT, AS OPPOSED TO ONE THAT
;COMND JSYS DETECTS

DEFINE COMERR (TEXT)
<	CALL [	HRROI A,[ASCIZ /TEXT/]
		ESOUT
		TMSG <
>
		MOVE A,XFORK
		FFORK		;REFREEZE SINCE OURCFM MAY HAVE UNFROZEN
		JRST CMDER1]
>

;MACRO FOR GETTING MONITOR SYMBOL VALUE

DEFINE GETSYM(NAME,MODULE<STG>)
<
	MOVE A,[SQUOZE 0,NAME]
	SKIPE NAME		;DO WE ALREADY KNOW THE VALUE?
	JRST .+5		;YES, DON'T GROVEL AGAIN!
	MOVE B,[SQUOZE 0,MODULE]
	CALL SYMBOL
	 RET			;FAILED, GIVE NONSKIP
	MOVEM B,NAME
>

DEFINE TA (TEXT,ADDR)<
IFNB <ADDR>,<%%X==ADDR>
IFB <ADDR>,<%%X==.'TEXT>
	[	CM%INV!CM%ABR!CM%FW
		ASCIZ /TEXT/],,%%X
>

;ROUTINE TO GET VALUES FOR VARIOUS MONITOR SYMBOLS
;SKIPS IFF SUCCESSFUL

GOBSYM:	SKIPE GOBFLG		;HAVE WE ALREADY GOTTEN MONITOR SYMBOLS?
	RETSKP			;YES
	GETSYM TTACTL		;TABLE OF TTY DATABASE ADDRESSES
	GETSYM MLJFN		;SIZE OF JFN BLOCK
	GETSYM SYSFK
	GETSYM TTLINK,TTYSRV	;OFFSET TO SHOW WHO'S LINKED
	GETSYM MAXJFN		;MAXIMUM JFN IN USE BY JOB
	GETSYM FILSTS		;JFN STATUS
	GETSYM FILNEN		;NAME,,EXT (POINTER)
	GETSYM FILVER		;FORK,,VERSION
	GETSYM FILDNM		;DIR,, (POINTER)
	GETSYM FILDDN		;DEV,,DIR #
	GETSYM JOBSKD		;JOBWIDE SCHEDULER CONTROL WORD
	GETSYM JOBBIT
	GETSYM JSVAR,JOBDAT
	GETSYM PSVAR,JOBDAT
	SETOM GOBFLG		;MARK THAT SYMBOLS HAVE BEEN READ
	RETSKP			;MARK SUCCESS WITH SKIP

;GET TO HERE IF WE WON'T BE ABLE TO DETECT SPYERS

NOSPY:	SETOM SPYERF		;REMEMBER THAT ERROR HAPPENED
	TMSG <
%Won't be able to report who's spying!  Reason:
>
	CALLRET PERR		;PRINT SYSTEM ERROR MESSAGE

;PRINT LAST SYSTEM ERROR FOR OURSELF..

PERR:	MOVE A,[.FHSLF,,-1]	;OURSELF, MOST RECENT ERROR
PERR1:	MOVE B,A
	MOVEI A,101
	MOVEI C,0
	ERSTR
	 JFCL
	 JFCL
	TMSG <
>
	RET


DATE:	CALL SAVACS		;DON'T CLOBBER AC'S
	CALL DATEX		;DO THE WORK
	JRST .DEBRK

DATEX:	STKVAR <REALI>
	TIME			;SEE WHAT TIME IT IS NOW
	SUB A,LSTTIM		;SEE HOW LONG SINCE LAST INTERRUPT
	MOVEM A,REALI		;REMEMBER REAL INTERVAL
	SKIPN BUSYF		;IF PROCESSING, EXCUSE LONG INTERRUPT LAPSE
	CAIGE A,TIMEX*3/2	;ALLOW 50% SLOP
	CAIA
	JRST [	TYPE <
%DATE: >
		MOVEI A,TIMEX	;SHOW EXPECTED INTERVAL
		CALL PSECS
		TYPE <-sec interval expected; >
		MOVE A,REALI	;GET OBSERVED LAPSE
		CALL PSECS
		TYPE < secs passed!  Attempting to force an interrupt...
>
		MOVEI A,.FHSLF	;INTERRUPT OURSELF
		MOVX B,1B<TIMCHN>
		IIC
		JRST .+1]
	SKIPE A,BUSYF		;DOING ANYTHING?
	JRST [	TYPE <(>	;YES, PUT IN PARENTHESES
		PSOUT		;SHOW WHAT WE'RE DOING
		TYPE < >
		MOVE A,REALI	;SAY HOW LONG SINCE LAST INTERRUPT
		CALL PSECS
		TYPE <) >	;FINISH MESSAGE
		JRST .+1]
	MOVE A,[14,,.SYSTA]
	GETAB			;GET SYSTEM LOAD AVERAGE
	 JFCL
	MOVEM A,LDAV		;REMEMBER LOAD AVERAGE
	MOVE Q3,STATF		;SEE WHAT'S ENABLED
	TXNN Q3,DATEF		;SEE IF LOAD-LINE ENABLED
	JRST NODATE
	MOVEI A," "
	PBOUT
	HRROI B,-1
	MOVEI A,101
	MOVEI C,0
	ODTIM
	JFCL
	MOVEI A," "
	PBOUT
	MOVE B,LDAV		;LOAD AVERAGE IN B
	MOVEI A,101
	MOVEI C,0
	FLOUT
	 JFCL
	TMSG <
>
NODATE:	TXNE Q3,SHAREF		;PRINT SHARES IF REQUESTED
	CALL SLOHAK		;PRINT HOGS IF SYSTEM IS SLOW
	TXNE Q3,IOF		;PRINT FILE PROGRESS IF REQUESTED
	CALL PFILES		;PRINT FILE STATUS
DATEND:	TYPE <---
>				;SHOW END OF REPORT
	RET

;ROUTINE WHICH TAKES MILLISECONDS AS AN INTEGER IN A, AND TYPES IT AS
;A FLOATING POINT NUMBER OF SECONDS

PSECS:	FLTR B,A		;PRINT AS SECONDS
	FDVRI B,(1000.0)
	MOVEI A,.PRIOU
	MOVEI C,0		;NO SPECIAL FORMAT
	FLOUT
	 JSERR
	RET

;ROUTINE TO PRINT STATUS OF FILES BEING READ OR WRITTEN

PFILES:	STKVAR <FSTATS,FPTR,COMJFN,FILPOS,FPGC,PAGPOS,FNBYTS,FBSZ,BSZ,SAVED,SIDX,WJFN>
	CALL JFNINI		;INITIALIZE JFN TABLE
	SETZM WJFN		;START AT BEGINNING OF JFN'S
JLUP:	AOS A,WJFN		;STEP TO NEXT JFN
	MOVEM A,COMJFN		;FIRST ASSUME NO SPECIAL JFN
	GTSTS			;SEE WHAT'S UP WITH THIS JFN
	MOVEM B,FSTATS		;REMEMBER STATUS
	TXNN B,GS%XCF		;DON'T DO JFNS OPEN FOR EXECUTE
	TXNN B,GS%NAM		;IS JFN IN USE?
	JRST NOJFN		;NO, SKIP THIS ONE( GO MARK AS NOT IN USE)
	CALL DRFPTR		;GET FILE POSITION
	 JRST NOJFN		;IF FAILS, ASSUME JFN HAS BEEN FREED
	CAIGE B,0		;JFN IS INTERESTING IF IT HAS MAPPED PAGES
	JUMPE A,NOJFN		;SKIP PRINT ROUTINE IF ZERO FILE POSITION
	MOVE A,WJFN		;PRINT THE JFN
	CALL POCT
	MOVEI A,.PRIOU
	MOVEI B,11
	BOUT			;FOLLOWED BY A TAB
	MOVE B,WJFN		;NEXT, PRINT THE FILESEPC
	MOVEI C,0		;NO SPECIAL BITS
	JFNS
	 ERJMP JFNRAC		;ASSUME JFN JUST WENT AWAY
	MOVEI B,11
	BOUT			;ANOTHER TAB
	MOVE A,WJFN		;PUT JFN IN A
	MOVE B,FSTATS		;GET STATUS
	TXNN B,GS%NAM		;JFN STILL IN USE?
	 JRST JFNRAC		;NO
	TXNN B,GS%OPN		;MAKE SURE FILE IS OPEN
	TYPE <Not opened >
	TXNE B,GS%RDF		;FILE OPEN FOR READING?
	TYPE <Read, >
	TXNE B,GS%WRF		;WRITING?
	TYPE <Write, >
	TXNN B,GS%RND		;APPEND?
	TYPE <Append, >
	CALL DRFPTR			;GET FILE POSITION
	 JRST JFNRAC		;JFN SLIPPED OUT FROM UNDER US
	JUMPGE B,JPAGES		;PRINT PAGES MAPPED IF SO
	MOVEM A,FILPOS		;REMEMBER WHERE IN FILE WE ARE
	SETZM PAGPOS		;SAY THERE'S NO PAGE POSITION
	CALL PDEC		;PRINT FILE POSITION IN DECIMAL
	TYPE <.(>		;PUT DECIMAL POINT IN AND OPEN PAREN FOR BYTE SIZE
	MOVE A,WJFN		;GET JFN
	RFBSZ			;GET BYTE SIZE
	 ERJMP JFNRAC		;ASSUME JFN WENT AWAY IF FAILS
	MOVE A,B
	MOVEM A,BSZ		;REMEMBER BYTE SIZE
	CALL PDEC		;PRINT BYTE SIZE IN DECIMAL
	TYPE <)>				;OMIT DECIMAL POINT JUST LIKE EXEC DOES!
PPER:	MOVE A,FSTATS		;GET FILE STATUS
	TXNN A,GS%WRF		;IS FILE OPEN FOR WRITING?
	JRST PPER0		;NO, SO NO PROBLEM

;Now we know file is open for writing, so use previous generation for calculating
;how far done we are.

	MOVE A,CSBUFP		;POINT TO SOME RANDOM SPACE
	MOVE B,WJFN		;GET JFN OF FILESPEC
	MOVX C,JMAGIC&^-JS%GEN	;GET ALL BUT GENERATION FIELD
	JFNS
	 ERJMP JFNRAC		;IF THIS FAILS, ASSUME JFN DISAPPEARED
	MOVEI B,"."		;PUT DOT AFTER FILE TYPE
	IDPB B,A
	MOVEM A,FPTR		;REMEMBER POINTER TO END OF FILESPEC
	MOVE A,WJFN		;GET HANDLE ON REAL FILE AGAIN
	MOVE B,[1,,.FBGEN]	;PREPARE TO GET GENERATION
	MOVEI C,B
	GTFDB			;GET GENERATION NUMBER
	 ERJMP JFNRAC		;IF CAN'T JFN MUST HAVE GONE AWAY
	LOAD B,FB%GEN,B		;ISOLATE GENERATION NUMBER
	MOVE A,FPTR		;POINT TO FILESPEC AGAIN
	SOJ B,			;PREPARE TO LOOK UP PREVIOUS GENERATION
	MOVX C,5+5		;DECIMAL
	NOUT			;PUT GENERATION NUMBER ON FILESPEC
	 ERCAL JSBOMB		;SHOULDN'T EVER FAIL
	MOVX A,GJ%DELGJ%PHYGJ%SHT!GJ%OLD	;TRY TO GET PREVIOUS GENERATION (GJ%PHY BECAUSE JFNS RETURNED REAL DEVICE)
	MOVE B,CSBUFP		;POINT TO FILESPEC OF PREVIOUS GENERATION
	GTJFN
	 ERJMP PPER2		;IF NO PREVIOUS GENERATION, FORGET IT
	MOVEM A,COMJFN
PPER0:	MOVE A,COMJFN		;COMPARE WITH INFO FROM FILE
	MOVE B,[2,,.FBBYV]	;WE WANT BYTE SIZE AND PAGE COUNT AND BYTES
	MOVEI C,C		;READ INFO INTO C AND D
	GTFDB			;READ INFO ABOUT FILE
	 ERJMP JFNRAC		;IF CAN'T JFN PROBABLY DISAPPEARED
	MOVEM D,FNBYTS		;REMEMBER NUMBER OF BYTES
	LOAD A,FB%BSZ,C		;GET BYTE SIZE OF FILE
	MOVEM A,FBSZ		;REMEMBER FILE BYTE SIZE
	LOAD A,FB%PGC,C		;GET NUMBER OF PAGES IN FILE
	MOVEM A,FPGC		;REMEMBER FILE PAGE COUNT
	SKIPE A,PAGPOS		;ARE WE GOING BY PAGES?
	JRST [	MOVE B,FPGC	;YES, COMPARE PAGE POSITION WITH NUMBER OF PAGES
		JRST PPER1]
	MOVEI A,6*6
	IDIV A,FBSZ		;SEE HOW MANY FILE BYTES PER WORD
	MOVE B,FNBYTS		;GET NUMBER OF BYTES IN FILE
	IDIV B,A		;GET NUMBER OF WORDS IN FILE
	MOVEI C,6*6		;GET MAXIMUM BYTES PER WORD
	IDIV C,BSZ		;SEE HOW MANY BYTES PER WORD FOR CURRENT OPENING
	IMUL B,C		;GET NUMBER OF BYTES FOR CURRENT BYTE SIZE
	MOVE A,FILPOS		;GET NUMBER OF BYTES READ SO FAR
PPER1:	FLTR A,A		;MAKE FLOATING POINT NUMBERS
	FLTR B,B
	FDVR A,B		;GET FRACTION THROUGH FILE WE ARE
	FMPRI A,(100.0)		;CHANGE TO A PERCENTAGE
	FIXR A,A		;GET INTEGER PERCENTAGE
	TYPE < [>		;PUT PERCENTAGE IN BRACKETS
	CALL PDEC
	TYPE <%]>
PPER2:	TYPE <
>
NOJFN:	MOVE A,COMJFN		;GET POSSIBLE SPECIAL JFN
	CAME A,WJFN		;IS THERE ONE?
	JRST [	RLJFN		;YES, RELEASE IT
		 JSERR		;SHOULDN'T FAIL
		JRST .+1]
	MOVE A,WJFN		;SEE WHICH JFN WE JUST TRIED
	CAIGE A,HGHJFN		;JUST DID HIGHEST?
	JRST JLUP		;NO
	RET			;YES

JPAGES:	MOVE D,JFNPAG(B)	;GET LOWEST,,HIGHEST PAGE NUMBER
	MOVEM D,SAVED
	MOVEM B,SIDX		;REMEMBER INFO
	TYPE <Page>
	MOVS A,D
	CAME A,D		;SEVERAL PAGES?
	TYPE <s>		;YES
	TYPE < >
	HLRZ A,SAVED
	CALL POCT		;PRINT PAGE NUMBER IN OCTAL
	HLRZ D,SAVED
	HRRZ A,SAVED
	CAMN A,D		;RANGE?
	JRST FPA1		;NO, ONLY ONE PAGE
	TYPE <->
	CALL POCT		;PRINT HIGHEST PAGE NUMBER
FPA1:	HLRZ A,SAVED		;GET LOW PAGE NUMBER
	ADD A,SAVED		;COMPUTE AVERAGE BETWEEN HIGH AND LOW
	HRRZ A,A
	ASH A,-1
	MOVEM A,PAGPOS		;SAVE AVERAGE PAGE NUMBER AS FILE POSITION
	SETZM FILPOS		;SAY THERE'S NO FILE POSITION
	JRST PPER		;GO PRINT PERCENTAGE THROUGH THE FILE

;ROUTINE TO GET FILE POSTION
;ACCEPTS:	A/	JFN

;RETURNS+	+1	ERROR
;		+2	SUCCESS. YEY!
;		A/	RFPTR VALUE, IFF B HAS -1
;		B/	-1 OR INDEX INTO JFNPAG (FOR GETTING LOW,,HIGH PAGE NUMBER)

DRFPTR:	STKVAR <DJFN>
	MOVEM A,DJFN		;REMEMBER JFN
	MOVE B,JFNNN		;GET NUMBER OF JFNS IN LIST
DRF1:	SOJL B,DRF2		;JFN NOT MAPPED IF THIS RUNS OUT
	CAME A,JFNLST(B)	;FIND THE JFN WE'RE LOOKING FOR?
	JRST DRF1		;NOT YET
	RETSKP			;DONE, INDEX IN B

DRF2:	RFPTR			;GET FILE POSITION
	 ERJMP R		;NON-SKIP IF ERROR
	MOVE A,B		;POSITION IN A
	HRROI B,-1		;REMEMBER THAT NO PAGES MAPPED
	RETSKP			;RETURN RFPTR DATA

;ROUTINE TO SEARCH ALL FORK'S ADDRESS SPACE FOR MAPPED JFNS.  IF A PAGE
;IS MAPPED TO A JFN , THAT PAGE NUMBER
;IS REMEMBERED FOR THAT JFN IF IT'S THE HIGHEST OR LOWEST OBSERVED MAPPED PAGE

PTRELN==3*NUFKS		;ROOM FOR ENTIRE FORK STRUCTURE

JFNINI:	STKVAR <FH,SAVIX,PATFLG,PHANDL,FPAGN,JFH,<PTREE,PTRELN>>
	SETOM PTREE		;MARK TABLE SO WE'LL KNOW HOW MUCH GFRKS USES
	HRLI A,PTREE
	HRRI A,1+PTREE
	MOVEI B,PTREE
	BLT A,PTRELN-1(B)	;FILL TABLE WITH -1'S
	SETZM JFNNN		;NO JFNS STORED YET
	MOVEI A,.FHSLF		;WE WANT ALL PROCESS AT US AND BELOW
	MOVX B,GF%GFH		;WE WANT HANDLES ON THE PROCESSES
	HRRI C,PTREE		;GET TREE INTO SOME SPACE
	HRLI C,-PTRELN		;SPECIFY HOW MUCH ROOM WE HAVE
	GFRKS			;GET FORK HANDLES
	 ERCAL JSBOMB			;SHOULDN'T EVER FAIL
	MOVEI A,400000		;START WITH SMALLEST FORK HANDLE
	MOVEM A,JFH
JFNI1:	SETZM FPAGN		;START WITH PAGE 0 OF FORK
	SETZM PATFLG		;FIRST ASSUME NOT PAT
	MOVE A,JFH		;GET WHICH FORK WE'RE ON
	CALL SKPPAT		;SKIP IF COMPATIBLE FORK
	 JRST JFNI2		;NO, SO USE COMPLETE PAGE MAP
	SETOM PATFLG		;REMEMBER THAT IT'S A COMPATIBLE PROCESS
	LSH A,-9		;COMPATIBLE, GET FIRST PAGE OF PA1050
	MOVEM A,FPAGN		;START THERE (ASSUME NO MAPPED PAGES BELOW THAT!)
JFNI2:	HRL A,JFH		;GET HANDLE OF FORK WE'RE DOING
	HRR A,FPAGN		;GET PAGE NUMBER OF FORK WE'RE EXAMINING
	RMAP			;GET INFORMATION ABOUT THE PAGE
	 ERJMP [	CALL GETERR	;FAILED, SEE WHY
			CAIE A,FRKHX2	;"ILLEGAL TO MANIPULATE SUPERIOR" (SEEMS TO HAPPEN IF FORK BEING KILLED DURING RMAP)
			CAIN A,FRKHX1	;NO SUCH FORK?
			JRST JFNI5	;YES, GO TO NEXT FORK
			CAIE A,ARGX06	;NO SUCH PAGE NUMBER?
			CALL JSBOMB	;NO, BAD ERROR
			MOVE A,FPAGN	;YES, WE MUST BE IN NONEXISTENT SECTION
			IORI A,777	;PRETEND WE JUST SCANNED ENTIRE SECTION
			MOVEM A,FPAGN
			JRST JFNI3]	;TRY NEXT SECTION (UNLESS WE'RE DONE!)
	JUMPL A,JFNI3		;SKIP PAGE IF IT BELONGS TO A FORK
	TXNN B,RM%PEX		;MAKE SURE PAGE EXISTS
	JRST JFNI3		;NO, GO TO NEXT PAGE
	MOVEM A,PHANDL		;REMEMBER PAGE HANDLE
	HLRZ A,A		;ISOLATE JFN
	MOVE B,JFNNN		;SEE HOW MANY JFNS WE KNOW ABOUT YET
JFNI4:	SOJL B,[	AOS B,JFNNN	;THIS ENTRY IS NEW!
			CAILE B,JFNZZZ	;DO WE HAVE ROOM FOR ANOTHER JFN?
			JRST JFNI3	;NO, SKIP IT
			HRR C,PHANDL	;YES, GET PAGE NUMBER
			HRL C,PHANDL	;INITIALIZE SMALLEST AND LARGEST PAGE TO THIS PAGE
			MOVEM C,JFNPAG-1(B)	;STORE INITIAL VALUE
			MOVEM A,JFNLST-1(B)	;REMEMBER WE'VE GOT A NEW JFN
			JRST JFNI3]	;SCAN REST OF PAGES
	CAME A,JFNLST(B)	;HAVE WE FOUND THIS JFN IN OUR TABLE?
	JRST JFNI4		;NOT YET
	HRRZ C,JFNPAG(B)	;FOUND THIS JFN'S ENTRY, GET HIGHEST PAGE NUMBER SEEN SO FAR
	HRRZ A,PHANDL		;GET THIS PAGE NUMBER
	CAMLE A,C		;HAVE WE FOUND A NEW HIGHEST PAGE NUMBER?
	HRRM A,JFNPAG(B)	;YES, REMEMBER NEW HIGH
	HLRZ C,JFNPAG(B)	;GET PREVIOUS LOWEST PAGE NUMBER
	CAMGE A,C		;HAVE WE FOUND A NEW LOW?
	HRLM A,JFNPAG(B)	;YES, REMEMBER NEW LOW
JFNI3:	AOS A,FPAGN		;STEP TO NEXT FORK PAGE NUMBER
	SKIPE PATFLG		;COMPATIBLE PROCESS?
	JRST [	CAIG A,777	;YES, ASSUME ONLY SECTION 0 (TO BE EFFICIENT!)
		JRST JFNI2	;NOT DONE WITH SECTION 0 YET
		JRST JFNI5]	;DONE WITH SECTION 0, ON TO NEXT FORK.
	CAIG A,HGHFPN		;BEYOND HIGHEST POSSIBLE FORK PAGE NUMBER?
	JRST JFNI2		;NO, GO DO THIS PAGE
JFNI5:	AOS A,JFH		;GO TO NEXT FORK
	TRZ A,400000		;SEE WHAT FORK NUMBER THIS IS
	CAIGE A,NUFKS		;DONE AS MANY FORKS AS CAN POSSIBILY EXIST?
	JRST JFNI1		;NO, GO DO THIS FORK
	MOVEI D,PTRELN		;GET LENGTH OF FORK TABLE
JFNI6:	JUMPLE D,R		;DONE RELEASING HANDLES
	MOVEI A,-2(D)		;GET RELATIVE OFFSET FOR FORK HANDLE
	ADDI A,PTREE		;GET REAL ADDRESS OF HANDLE
	MOVE A,(A)		;GET FORK HANDLE WORD
	AOJE A,JFNI7		;IGNORE IF HIT A -1 ENTRY
	MOVEI A,-1(A)		;ISOLATE THE FORK HANDLE
	CAIN A,.FHSLF		;DON'T TRY TO RELEASE HANDLE ON SELF!
	JRST JFNI7
	MOVEM D,SAVIX
	MOVEM A,FH		;PION / PIOFF CLOBBER TEMPS
	CALL PIOFF		;DON'T LET EXEC TABLE CHANGE WHILE WE PERUSE IT
	MOVE A,FH
	MOVSI B,-EFNLEN		;PREPARE TO SCAN TABLE OF EXEC FORKS
JFNL:	SKIPN EFNTAB(B)		;IS THIS SLOT IN USE?
	JRST JFNL1		;NO
	CAIN A,400000(B)	;YES, IS HANDLE WE WANT TO FLUSH REALLY AN EXEC?
	JRST [	CALL PION	;YES, ALLOW INTERRUPTS AGAIN.
		JRST JFNI7]	;DON'T TRY TO RELEASE THIS FORK HANDLE
JFNL1:	AOBJN B,JFNL		;MAKE SURE FORK DOESN'T MATCH REST OF EXECS
	CALL PION		;ALLOW EXEC TABLE TO CHANGE AGAIN
	MOVE A,FH
	MOVE D,SAVIX
	CAME A,XFORK		;DON'T RELEASE HANDLES OF FORKS WE NEED!
	CAMN A,TTYFRK
	CAIA
	JRST [	RFRKH		;RELEASE HANDLE SO WE DON'T USE UP HANDLES
		 JSERR		;SHOULDN'T FAIL
		JRST .+1]	;NOTE THAT USING -1 IN AC1 WOULD LOSE OUR
				;SPECIAL HANDLES, IF EXEC ABOVE US ALSO HAD
				;HANDLES, AS IT WILL IF USER DOES "INFO PROG"!
JFNI7:	SUBI D,3		;STEP DOWN TO NEXT ENTRY
	JRST JFNI6

;SKPPAT SKIPS IF PROCESS IS USING THE COMPATIBILITY PACKAGE
;
;ACCEPTS:	A/	PROCESS HANDLE
;
;RETURNS:	+1:	PROCESS NOT USING COMPATIBILITY
;		+2:	IS USING IT, FIRST ADDRESS OF PACKAGE IS IN A

SKPPAT:	GCVEC			;GET COMPATIBILITY ENTRY VECTOR
	 ERJMP R		;IF NO SUCH PROCESS, THEN IT'S NOT USING COMPATIBILITY PACKAGE
	AOJE B,R		;IF WAS -1, PAT NOT AVAILABLE
	SOJE B,R		;IF WAS 0, PAT NOT IN USE (NOTE B UNCLOBBERED NOW!)
	HRRZ A,B		;ASSUME PAT STARTS AT ENTRY VECTOR
	RETSKP

;ROUTINE TO PRINT INFO ABOUT JOBS USING LOTS OF RUNTIME WHEN
;SYSTEM IS SLOW.

SLOHAK:	STKVAR <PINLEN,<JINFO,.JIPNM-.JIUNO+1>,PORTIN,LSF>
	CALL PIOFF		;DON'T LET ANYONE FIDDLE WITH TOTRUN WHILE WE LOOK
	MOVE A,[0.5]
	FDVR A,LDAV		;CALCULATE INTERESTING AMOUNT OF MACHINE
	MOVEM A,PORTIN		;REMEMBER PORTION TO USE FOR COMPARISON
	MOVN P1,JTLEN		;GET LENGTH OF JOB TABLE
	HRLZ P1,P1		;MAKE AOBJN POINTER
	SETZM PINLEN		;HAVEN'T PINPOINTED ANY YET
SLO1:	FLTR A,JRINTB(P1)	;GET A RUNTIME
	FDVR A,TOTRUN		;CALCULATE PORTION THIS JOB HAS USED
	CAMGE A,PORTIN		;ENOUGH TO BE INTERESTING?
	JRST SLO4		;NO
	AOS A,PINLEN		;YES, COUNT NUMBER WE'VE PINPOINTED
	HRRZM P1,HOGTAB-1(A)	;PINPOINT THIS ENTRY
	CAML B,JRINTB(P1)	;FOUND A GREATER OR EQUAL RUNTIME YET?
	JRST SLO4		;NO
	MOVE B,JRINTB(P1)	;YES, REMEMBER THE BETTER ONE
	MOVE C,P1		;REMEMBER ITS JOB NUMBER
SLO4:	AOBJN P1,SLO1		;SCAN REST OF LIST LOOKING FOR HOGS
SLO8:	MOVE P1,PINLEN		;NOW PRINTOUT THE OFFENDERS
	SETOM LSF		;INITIALIZE "LARGEST SO FAR"
SLO7:	SOJL P1,SLO6		;LEAVE SEARCH LOOP IF SCANNED ENTIRE TABLE
	SKIPGE A,HOGTAB(P1)	;GET JOB NUMBER
	JRST SLO7		;NONENTRY (ALREADY PRINTED)
	MOVE A,JRINTB(A)	;GET ITS RUNTIME
	CAMGE A,LSF		;MOST INTERESTING ONE NOT YET PRINTED?
	JRST SLO7		;NO
	MOVEM A,LSF		;YES, REMEMBER
	MOVE D,P1		;REMEMBER INDEX FOR THIS CANDIDATE
	JRST SLO7		;SCAN REST OF TABLE
SLO6:	SKIPGE LSF		;FIND A REAL ENTRY?
	CALLRET PION		;NO, UNLOCK TOTRUN AND RETURN
	MOVE A,HOGTAB(D)	;GET JOB NUMBER
	SETOM HOGTAB(D)		;CLOBBER ENTRY SO DOESN'T GET PRINTED AGAIN
	HRLI B,.JIUNO-.JIPNM-1		;WE WANT USER NUMBER AND PROGRAM NAME
	HRRI B,JINFO		;BLOCK INTO WHICH WE'LL READ INFO
	MOVEI C,.JIUNO		;USER NUMBER IS FIRST ITEM WANTED
	GETJI			;GET THE INFO
	 ERJMP SLO8		;IF FAILS, JOB PROBABLY LOGGED OFF
	MOVEI A,.PRIOU		;PRINT ON TERMINAL
	MOVE B,JINFO		;GET USER NUMBER
	DIRST			;PRINT USER NUMBER
	 JRST NLI		;NOT LOGGED IN
DIRS1:	TMSG <->		;PUT HYPHEN BETWEEN USER NAME AND PROG
	MOVE A,.JIPNM-.JIUNO+JINFO	;GET PROGRAM NAME
	CALL PSIXN		;PRINT IT
	TMSG < >
	FLTR A,LSF		;GET RUNTIME
	FDVR A,TOTRUN		;CALCULATE PORTION USED
	FMPRI A,(100.0)		;MAKE PERCENTAGE
	FIX A,A			;MAKE INTEGER
	CALL PDEC		;PRINT IN DECIMAL
	TMSG <%
>
	JRST SLO8		;PRINT THE REST

NLI:	TMSG <Not logged in>
	JRST DIRS1

;GET HERE IF JFN DISAPPEARS WHILE WE'RE PRINTING INFO ABOUT IT

JFNRAC:	TYPE <...[JFN has just been closed!!]
>
	JRST NOJFN		;CONTINUE WITH REST OF JFN'S

;ROUTINE TO STACK ALL THE AC'S.  THIS IS USEFUL FOR INTERRUPT
;ROUTINES THAT HAVEN'T THE SLIGHTEST IDEA WHERE THE EXEC WAS WHEN
;THE INTERRUPT OCCURED, SO THE INTERRUPT ROUTINE CALLES SAVACS TO
;SAVE ALL THE AC'S ON THE STACK.  THE INTERRUPT ROUTINE MUST CALL
;RESACS BEFORE DISMISSING THE INTERRUPT, IN ORDER TO RESTORE THE
;AC'S.
;THIS ROUTINE DOESN'T SAVE P.

SAVACS:	EXCH 0,(P)		;SAVE AC0, GET RETURN ADDRESS
	ADJSP P,17		;ALLOCATE ROOM FOR THE REST OF THE AC'S
	MOVEM 0,(P)		;STORE RETURN ADDRESS "AFTER" AC BLOCK
	HRRI 0,-16(P)		;PLACE ON STACK TO STORE AC'S
	HRLI 0,1		;STARTING FROM AC1
	BLT 0,-1(P)		;SAVE REST OF AC'S
	RET			;RETURN TO CALLER

;ROUTINE TO RESTORE AC'S

RESACS:	HRLI 0,-16(P)		;GET ADDRESS OF STORED AC'S
	HRRI 0,1		;RESTORE AC'S INTO AC1 ONWARD
	BLT 0,16		;RESTORE 1 THROUGH 16
	MOVE 0,(P)		;GET RETURN ADDRESS
	EXCH 0,-17(P)		;STORE RETURN ADDRESS, GET ORIGINAL AC0
	ADJSP P,-17		;FREE UP SPACE USED BY RETURN ADDRESS AND 1 THROUGH 16
	RET			;RETURN TO CALLER (PHYEW!)

;GET HERE EVERY SO OFTEN TO CHECK FOR SPYERS

TIMINT:	CALL SAVACS		;SAVE THE AC'S
	CALL DTIMER		;GET READY FOR ANOTHER INTERRUPT
	CALL TIM0		;DO THE WORK
	CALL RESACS		;RESTORE ACS
	DEBRK			;RETURN (EITHER TO SLEEP OR TO SOME ROUTINE)

;ROUTINE TO TYPE CHARACTER IN A.

CHAR:	STKVAR <WHATC>
	MOVEM A,WHATC
	CALL TTYLCK		;LOCK THE TERMINAL
	MOVE A,WHATC
	IDPB A,TTYPNT		;PUT CHARACTER IN OUTPUT STREAM
	CALLRET TTYULK		;UNLOCK TTY AND RETURN

;INSTANT OCTAL AND DECIMAL NUMBER ROUTINES (SEE DECNUM FOR BUFFERED NUMBER)

POCT:	MOVEI B,8		;SAY OCTAL
	CALLRET PNUM

PDEC:	MOVEI B,5+5		;SAY DECIMAL
	CALLRET PNUM

PNUM:	MOVE C,B		;RADIX IN C FOR NOUT
	MOVE B,A		;NUMBER IN B
	MOVEI A,.PRIOU		;OUTPUT TO PRIMARY
	NOUT			;PRINT NUMBER
	 JSERR			;FAILED
	RET

;TYPE OCTAL NUMBER IN A

OCTNUM:	MOVEI B,8		;RADIX
	CALLRET NUM		;DO REGULAR NUMBER

;DECIMAL NUMBER

DECNUM:	MOVEI B,5+5		;RADIX
	CALLRET NUM

;GENERAL NUMBER OUTPUT ROUTINE.  NUMBER IN A, RADIX IN B

NUM:	STKVAR <AMOUNT,BASE>
	MOVEM A,AMOUNT
	MOVEM B,BASE		;SAVE DATA
	CALL TTYLCK		;WAIT TILL BUFFER AVAILABLE
	MOVE B,AMOUNT		;NUMBER IN B
	MOVE C,BASE		;GET RADIX
	MOVE A,TTYPNT		;POINTER TO BUFFER
	NOUT			;DO THE NUMBER
	 ERJMP NOPNM		;GO HANDLE ERROR
	MOVEM A,TTYPNT		;UPDATE POINTER
	CALLRET TTYULK		;UNLOCK BUFFER

;TTYINI is called once at startup to initialize terminal.

TTYINI:	MOVE A,[440700,,BUFFER]
	MOVEM A,BPTR		;INITIALIZE OUTPUT BUFFER
	MOVEI A,NBCHARS
	MOVEM A,BROOM		;SAY THERE'S THIS MUCH ROOM LEFT
	MOVX A,GJ%SHT
	HRROI B,[ASCIZ /TTY:/]
	GTJFN			;GET HANDLE ON TERMINAL
	 JSHLT
	MOVE B,[100000,,OF%WR]	;BINARY CHANNEL FOR SCREEN STUFF
	OPENF
	 JSHLT
	MOVEM A,TTYJFN		;SAVE BINARY CHANNEL
	RET

;TERCHK should be called whenever you think terminal parameters, such as
;terminal type or height has changed.

TERCHK:	MOVE A,TTYJFN		;GET CHANNEL
	GTTYP			;GET TERMINAL TYPE
	MOVEM B,TRMTYP		;REMEMBER
	MOVEI B,.MORLL		;READ LINE LENGTH
	MTOPR
	MOVEM C,HEIGHT		;REMEMBER IT
	MOVEI B,.MORLW		;READ LINE WIDTH
	MTOPR
	MOVEM C,WIDTH
	SETZM SCRNF		;REMEMBER NOT A SCREEN
	SKIPE HOMTAB(B)		;A SCREEN?
	SETOM SCRNF		;YES, WHAT FUN!!!
	RET

;STRING WHOSE POINTER IS IN A...

STRNG:	STKVAR <SPTR>
	MOVEM A,SPTR		;REMEMBER STRING POINTER
	CALL TTYLCK		;LOCK BUFFER
	MOVE B,SPTR		;GET POINTER TO STRING
	MOVE A,TTYPNT		;POINTER TO OUTPUT BUFFER
	MOVEI C,0		;STOP ON NULL
	SOUT			;OUTPUT THE STRING
	MOVEM A,TTYPNT		;STORE UPDATED POINTER
	CALLRET TTYULK		;UNLOCK BUFFER

;ROUTINE TO PREVENT INTERRUPTS.

PIOFF:	MOVEI A,.FHSLF		;OURSELF
	DIR			;TURN OFF INTERRUPTS
	RET

;TURN INTERRUPTS ON

PION:	MOVEI A,.FHSLF		;OURSELF
	EIR			;ENABLE INTERRUPTS
	RET

;ROUTINE TO LOCK THE BUFFER WHILE IT GETS USED

TTYLCK:	CALL BUFOK		;MAKE SURE TTY BUFFER IS O.K.
	 CALL HANG		;IT'S NOT, WAIT FOR SOME TO EMPTY
TTYLCX:	AOSE TTYFLG		;IS OTHER FORK USING THE DATABASE?
	 CALL HANG		;YES, WAIT FOR IT TO FINISH
	CALL PIOFF		;TURN OFF INTERRUPTS SO NOONE ELSE USES TTY DATABASE
	RET

BUFOK:	HRRZ A,TTYPNT
	CAIL A,DEAD		;BUFFER GETTING FULL?
	RET			;YES, BUFFER NOT OK
	RETSKP			;NO, BUFFER IS OK

;ROUTINE TO UNLOCK BUFFER ONCE WE'RE DONE OUTPUTTING TO IT

TTYULK:	AOSE OUTFLG		;GONE FROM NO OUTPUT TO OUTPUT READY?
	JRST TTYUL1		;NO, OUTPUT FORK ALREADY RUNNING
	CALL [	DMOVE A,[EXP CR%ACS!CR%CAP,[IOWD TTYPLN,TTYPDL]-17]	;CREATE FORK, SET UP STACK
		CFORK			;CREATE OUTPUT FORK
		 RET		;FAILED
		RETSKP]		;SUCCEEDED
	 CALL HANG		;IF NO FORKS AVAILABLE, WAIT FOR ONE.
	MOVEM A,TTYFRK		;REMEMBER HANDLE
	MOVSI A,.FHSLF		;LET OURSELF BE SEEN...
	HRLZ B,TTYFRK		;BY THE TTY FORK.
	MOVX C,PM%CNT!PM%RD!PM%WR!<1+<.RLEND_-9>>	;COUNT, READ, WRITE, ALL OF OUR ADDRESS SPACE
	PMAP			;GIVE NECESSARY MEMORY TO TTY FORK
	MOVE A,TTYFRK
	MOVEI B,SPILL
	SFORK			;START UP TTY FORK
TTYUL1:	MOVEI A,0
	MOVE B,TTYPNT
	IDPB A,B		;MAKE SURE WE END BUFFER WITH NULL
	SETOM TTYFLG		;SAY ANOTHER FORK CAN NOW USE DATABASE
	CALL PION		;ALLOW INTERRUPTS AGAIN
	RET

;"CALL HANG" IS LIKE "JRST .-1" BUT DOESN'T LOAD DOWN THE CPU

HANG:	MOVEI A,HANGT		;GET SOME TIME TO WASTE
	DISMS			;WASTE IT
	POP P,A			;THROW AWAY OUR ADDRESS ON STACK
	JRST -2(A)		;GO BACK AND SEE IF CONDITION MET YET

TIM0:	CALL RUPDAT		;UPDATE RUNTIMES
	SKIPN INITF		;EVERYTHING INITIALIZED?
	RET			;NO, SO DO NOTHING MORE
	CALL UPFILE		;CHECK FOR UPDATED FILES
	CALL GRUMPS		;CHECK FOR GRUMPS
	CALL BUGX		;CHECK FOR BUGCHKS
	CALL NEWMAL		;CHECK FOR NEW MAIL
	CALL SPYERS		;CHECK ON SPYERS
	SETZM BUSYF		;WE'RE NOT PROCESSING ANYTHING ANYMORE
	RET			;DONE

;UPFILE gets called at interrupt level to check if update-checking is
;enabled, and if so, announce any interesting files that have been written
;recently.

UPFILE:	TRVAR <REPJFN,REPTIM,REPFTM,REPRTM>
	MOVEI Q1,ULEN		;GET NUMBER OF DIRECTORIES TO CHECK
UPF1:	SOJL Q1,R		;NO MORE TO CHECK WHEN Q1 REACHES 0
	SKIPN A,UDIR(Q1)	;GET NEXT DIRECTORY NUMBER
	JRST UPF1		;SKIP EMPTY SLOTS
	GTDAL			;SEE HOW MANY PAGES IN USE
	CAMN B,USIZE(Q1)	;DIFFERENT THAN LAST TIME?
	JRST UPF1		;NO, SO ASSUME NOTHING CHANGED (HMMM).
	HRROI A,[ASCIZ /Files/]
	MOVEM A,BUSYF		;SHOW THAT WE'RE CHECKING FILES
	MOVEM B,USIZE(Q1)	;YES, REMEMBER NEW CURRENT SIZE
	MOVEI A,UJFNBK		;POINT AT SPECIAL JFN BLOCK
	MOVE B,UFPTR(Q1)	;GET POINTER TO FILESPEC STRING FOR THIS DIR
	GTJFN			;GET HANDLE ON FIRST FILE IN SET
	 ERJMP UPF1		;NONE IN SET, SO GO ON TO NEXT SET
	MOVE B,UTIME(Q1)	;GET PREVIOUS TIME FOR THIS SET
	CALL REPFLS		;REPORT WHAT HAPPENED IN THIS DIRECTORY
	CAMLE A,UTIME(Q1)	;DON'T SHRINK THE TIME
	MOVEM A,UTIME(Q1)	;REMEMBER TIME TO USE FOR NEXT CHECK
	JRST UPF1		;LOOP FOR REST OF DIRECTORIES

;REPFLS reports which files have been updated recently.
;
;accepts:	A/	JFN (such as SNARK:<4.MONITOR>*.MAC)
;		B/	date-and-time for deciding what's recent
;
;returns +1:	A/	Most recent time-and-date any file in set was written
;
;The given JFN is stepped through, and for each file match it, if that
;file's write-time is more recent than the time given in B, that file is
;reported.

REPFLS:	MOVEM A,REPJFN		;REMEMBER THE JFN
	MOVEM B,REPTIM		;REMEMBER WHAT TIME TO USE
	SETZM REPRTM		;FORCE AT LEAST SOME TIME TO BE STORED HERE
REPFL1:	HRRZ A,REPJFN		;GET THE JFN FOR CURRENT FILE OF SET
	MOVE B,[1,,.FBCRE]	;WE WANT ONE WORD, REAL WRITE TIME
	MOVEI C,A		;GET FILE'S WRITE TIME
	GTFDB
	MOVEM A,REPFTM
	CAMLE A,REPRTM		;IS THIS THE MOST RECENT TIME SEEN SO FAR?
	MOVEM A,REPRTM		;YES, SO REMEMBER IT
	CAMG A,REPTIM		;WAS THIS FILE WRITTEN RECENTLY?
	JRST REPFL2		;NO
	XTMSG <*[DATE: File >
	CALL TTYLCK
	MOVE A,TTYPNT		;OUTPUT FILENAME TO TTY BUFFER
	HRRZ B,REPJFN		;PRINT THE CURRENT FILE OF THE SET
	MOVX C,JMAGIC		;PRINT ALL FIELDS
	JFNS
	MOVEM A,TTYPNT		;STORE UPDATED POINTER
	CALL TTYULK
	XTMSG < written by >
	CALL TTYLCK
	HRR A,REPJFN		;PREPARE TO GET USER NAME
	HRLI A,.GFLWR		;WE WANT LAST WRITER
	MOVE B,TTYPNT		;POINTER TO WHERE TO WRITE STRING
	GFUST			;GET WRITER STRING
	MOVEM B,TTYPNT		;REMEMBER UPDATED TTY POINTER
	CALL TTYULK
	XTMSG < at >
	CALL TTYLCK
	MOVE A,TTYPNT		;OUTPUT TIME TO TTY BUFFER
	MOVE B,REPFTM		;GET THIS FILE'S WRITE TIME
	MOVEI C,0		;STANDARD FORMAT
	ODTIM			;OUTPUT THE TIME
	MOVEM A,TTYPNT		;REMEMBER UPDATED POINTER
	CALL TTYULK
	XTMSG <]
>
REPFL2:	MOVE A,REPJFN		;GET THE JFN
	GNJFN			;STEP TO THE NEXT FILE
	 CAIA			;IF IT FAILS, ASSUME NO MORE FILES
	JRST REPFL1
	MOVE A,REPRTM		;RETURN MOST RECENT TIME SEEN
	RET

;CHECK FOR GRUMPS...

GRUMPS:	SKIPE GRUMPF		;DO NOTHING IF USER NOT LOOKING AT GRUMPS
	SKIPE GRERRF		;ERRORS?
	 RET			;YES, GIVE UP
	HRROI A,[ASCIZ /Grumps/]
	MOVEM A,BUSYF		;SHOW THAT WE'RE PROCESSING GRUMPS
	MOVEI A,GRJFN		;SAY WHERE JFN LIVES
	MOVEI B,GRSIZE		;SAY WHERE SIZE LIVES
	CALLRET PRE		;DO THE PREVIEWING

;CHECK FOR NEW MAIL

NEWMAL:	SKIPE MAILF		;NOTHING TO DO IF USER NOT PREVIEWING MAIL
	SKIPE GRERRF		;ERRORS?
	 RET			;YES, GIVE UP
	HRROI A,[ASCIZ /Mail/]	;SAY WE'RE EXAMINING MAIL
	MOVEM A,BUSYF
	MOVEI A,MALJFN		;CELL FOR MAIL FILE JFN
	MOVEI B,MALSIZ		;CELL FOR MAILFILE SIZE
	CALL PRE		;SEE IF NEW MAIL
	MOVEI A,SMJFN		;DO SYSTEM MAIL IN SAME WAY
	MOVEI B,SMSIZ
	CALLRET PRE

;ROUTINE TO PREVIEW A FILE.  GIVE IT ADDRESS OF WORD HOLDING JFN IN A, AND
;ADDRESS OF WORD HOLDING OLD SIZE IN B.

PRE:	TRVAR <DGRMPF,PREJFN,PRESIZ,GRADJ,DMAILF,DSMF>
	MOVEM A,PREJFN
	MOVEM B,PRESIZ
	SETZM DMAILF		;FIRST ASSUME DOING GRUMPS
	CAIN A,MALJFN		;DOING MAIL?
	SETOM DMAILF		;YES, REMEMBER.
	SETZM DSMF		;INITIALLY NOT DOING SYSTEM MAIL
	CAIN A,SMJFN		;DOING SYSTEM MAIL?
	SETOM DSMF		;YES
	SETZM DGRMPF		;INITIALLY NOT DOING GRUMPS
	CAIN A,GRJFN		;DOING GRUMPS?
	SETOM DGRMPF		;YES, REMEMBER SO
	SETZM GEOFDA		;NO SPECIAL EOF ADDRESS YET
	SKIPN A,@PREJFN		;HAVE A JFN ON GRUMP FILE YET?
	JRST [	HRROI A,[ASCIZ /PS:[REMARKS]GRUMP.LOG/]
		SKIPE DMAILF
		HRROI A,MALSPC	;DIFFERENT FILENAME FOR MAIL PREVIEWING
		SKIPE DSMF	;DOING SYSTEM MAIL?
		HRROI A,[ASCIZ /SYSTEM:MAIL.TXT.1/]
		CALL GETFSZ	;NO, GET ONE AND ITS SIZE
		 JRST [	SETZM @PRESIZ	;FILE GONE, CLEAR SIZE SO NEW FILE GETS DISPLAYED
			RET]
		MOVEM A,@PREJFN	;REMEMBER NEW JFN
		JRST PRE1]	;FILE THERE, GO DISPLAY IF JUST CREATED
	CALL GETFSZ		;ALREADY HAVE GRUMP JFN, GET ITS SIZE
	 JRST [	MOVE A,@PREJFN	;FAILED, FILE PROBABLY EXPUNGED.
		RLJFN		;SO RELEASE HANDLE ON OLD COPY
		 JSERR		;REPORT ERROR IF UNEXPECTED RELEASE FAILURE.
		SETZM @PREJFN	;CLEAR CELL, SO INITIALIZED AGAIN NEXT TIME
		SETZM @PRESIZ	;MAKE SO NEW FILE  WILL BE SEEN
		RET]		;DONE UNTIL NEXT CYCLE
PRE1:	CAMN B,@PRESIZ		;DIFFERENT THAN LAST TIME WE LOOKED?
	RET			;NO, NOTHING TO DO
	EXCH B,@PRESIZ		;SAVE NEW SIZE, GET OLD SIZE
	CAML B,@PRESIZ		;MAKE SURE OLD IS LESS THAN NEW
	RET			;FILE SHRUNK, SO DON'T ANNOUNCE ANYTHING NOW
	MOVEM B,OGRSIZ		;STORE OLD SIZE
	SKIPN DMAILF		;DOING REGULAR MAIL?
	JRST PRE2		;NO, SO DON'T WORRY WHAT USER IS RUNNING
	GETNM			;GET CURRENT PROGRAM NAME
	CAMN A,[SIXBIT /MS/]	;IS USER READING HER MAIL?
	RET			;YES, SO DON'T DISPLAY THIS NEW MESSAGE
	MOVE A,@PREJFN		;RESTORE JFN THAT GETNM CLOBBERED
PRE2:	MOVX B,OF%RD!OF%PDT	;DON'T MESS UP ACCESS DATES OF MAIL.TXT
	OPENF
	 RET			;FAILED, FILE PROBABLY CLEANED OUT BY OPERATOR.
	SETOM GRPGN		;GUARANTEE THAT FIRST PAGE CAUSES A PMAP
	FFFFP			;GET NUMBER OF PAGES (FB%PGC MIGHT LIE!)
	TRNN A,-1		;ANY PAGES IN FILE?
	JRST GDONE		;NO, RETURN IMMEDIATELY
	MOVE B,@PRESIZ		;GET NUMBER OF BYTES
	IDIVI B,5000		;GET NUMBER OF CHARACTERS ON LAST PAGE
	CAIN C,0		;IF REMAINDER IS 0,
	MOVEI C,5000		;THEN LAST PAGE IS COMPLETELY FULL
	IDIVI C,5		;CALCULATE FINAL BYTE POINTER IN FILE
	ADD C,BTAB(D)
	MOVEM C,EOG		;REMEMBER BYTE POINTER TO END OF GRUMP
	HRRZI A,-1(A)		;GET HIGHEST PAGE NUMBER IN A
	MOVEM A,LPIG		;REMEMBER LAST PAGE IN GRUMP
	SETZM BACKF		;READ FORWARDS
	MOVEI A,[	MOVE P,GPP	;CODE FOR EOF, RESTORE STACK
			JRST G1]	;FINISH GRUMP
	MOVEM A,GEOFDA		;SAY WHERE TO GO ON END OF FILE
	MOVEM P,GPP		;REMEMBER STACK LEVEL
	SETZM BACKF		;NOW READ GRUMP FORWARD
	MOVE A,OGRSIZ		;GET OLD SIZE IN BYTES
	IDIVI A,5000		;FIGURE OUT FIRST PAGE TO LOOK AT
	MOVEM B,GRADJ		;REMEMBER ADJUSTMENT FOR PROPER LOCATION
	CALL GRMAP		;SET POINTER TO CORRECT SPOT
	MOVE A,GRADJ		;GET ADJUSTMENT
	ADJBP A,GRPTR		;STEP TO CORRECT PLACE ON PAGE
	MOVEM A,GRPTR		;STORE UPDATED POINTER
	XTMSG <*>		;MARK BEGINNING
	SKIPN DSMF		;FOR SYSTEM MAIL, NOTHING TO LOOK FOR
	SKIPE DMAILF		;DOING MAIL-PREVIEWING?
	JRST GTYPE		;YES, JUST GO OUTPUT THE MAIL
GNXT:	CALL SGBEG		;FIND BEGINNING OF GRUMP
	SETZM BACKF		;READ FORWARDS (AGAIN)
	XTMSG <[Grump by user >
GRU1:	CALL GCHAR		;GET A CHARACTER
	CAIN A,12		;LINEFEED?
	JRST GRU2		;YES, END OF LINE
	CALL CHAR		;OUTPUT IT
	JRST GRU1
GRU2:	CALL CHAR		;FINISH THE LINE
	CALL FGRUMP		;FIND THE GRUMP ITSELF
GTYPE:	CALL GCHAR		;READ CHARACTER OF GRUMP ITSELF
	SKIPE DGRMPF		;DOING A GRUMP?
	CAIE A,.CHFFD		;FORM FEED, MARKS END OF GRUMP BUT NOT MAIL
	CAIA			;GET REST OF MESSAGE, ASSUME ENDS AT END OF FILE
	JRST GNXT		;END OF GRUMP, MAYBE MORE
	CALL CHAR		;OUTPUT CHARACTER TO TERMINAL
	JRST GTYPE		;LOOP UNTIL END OF MESSAGE

G1:	SKIPN DGRMPF		;NO CLOSING BRACKET FOR MAIL
	JRST GDONE
	XTMSG <]
>
GDONE:	HRROI A,-1		;WE WANT TO CLEAR MAPPED CORE PAGES
	MOVE B,[.FHSLF,,GRBPN]
	MOVEI C,0		;DOES C MATTER?
	PMAP
	MOVE A,@PREJFN
	TXO A,CO%NRJ		;WE DON'T WANT TO RELEASE THE JFN!!
	CLOSF			;CLOSE THE GRUMP FILE
	 ERJMP NOGRMP
	RET			;ALL DONE

BUGX:	SKIPN BUGCHF		;ALLOWED TO CHECK FOR BUGCHKS?
	RET			;USER DOESN'T CARE ABOUT BUGCHKS
	HRROI A,[ASCIZ /Bugchks/]
	MOVEM A,BUSYF		;SHOW WHAT WE'RE DOING
	CALL SERINI		;GET JFN ON ERROR.SYS FILE
	 RET			;NOT THERE YET
	CAMN B,SERDAT		;HAS FILE BEEN RECENTLY WRITTEN?
	RET			;NO
	MOVEM B,SERDAT		;YES, REMEMBER LATEST WRITE-DATE
	MOVEI B,2B17/^D<60*60*24>	;TWO SECONDS IN INTERNAL FORMAT
				;SYSERR SEEMS TO INSIST ON REPORTING AN ENTRY UNLESS
				;YOU ASK IT TO BEGIN TWO SECONDS BEYOND THE ENTRY
	ADD B,LSTBUG		;START NEXT PRINTOUT TWO SECONDS BEYOND PREVIOUS
	MOVEI A,0		;SAY WE WANT BUGCHKS
	CALL REPBUG		;GO REPORT ANY RECENT BUGCHKS
	CAIE A,0		;DON'T UPDATE IF NO BUGS REPORTED
	MOVEM A,LSTBUG		;REMEMBER TIMESTAMP OF LAST ONE DISPLAYED
	RET

;GET JFN ON ERROR.SYS

GETSYS:	HRROI A,[ASCIZ /SERR:ERROR.SYS/]
	CALL WRTDAT
	 RET			;FAILED
	HRLOI C,377777		;GET PAGE NUMBER GUARANTEED TOO HIGH
	MOVEM C,OGPAG		;FORCE NON-GUESS FIRST TIME THROUGH
	RETSKP			;SUCCESS

;INITIALIZE STUFF ABOUT ERROR.SYS

SERINI:	SKIPN A,SERJFN		;HAVE A HANDLE ON ERROR.SYS YET?
	JRST [	CALL GETSYS	;GET JFN
		 RET		;FAILED
		MOVEM B,SERDAT	;REMEMBER INITIAL DATE AND TIME
		MOVEM A,SERJFN	;REMEMBER JFN
		MOVEM B,LSTBUG	;PRETEND LAST BUG WAS LAST TIME FILE WAS WRITTEN
		RET]		;NOTHING TO COMPARE NOW
	CALL WRTDAT		;SEE WHEN IT WAS LAST WRITTEN
	JRST [	SETZM SERJFN	;IF FAILS, FORCE THE GTJFN TO BE DONE AGAIN
		RET]		;BUT NOT TILL NEXT TIME THROUGH!!
	RETSKP

;ROUTINE TO EXECUTE CONTENTS OF DATE.CMD ON LOGIN DIRECTORY

NEWCMD:	STKVAR <<CMDSPC,100>,CMDJFN,SAVIOJ>
	CALL CMDINI		;INITIALIZE FOR COMND JSYS
	HRROI A,-1		;CURRENT JOB
	HRROI B,C		;PUT DIRECTORY NUMBER IN C
	MOVEI C,.JILNO		;LOGIN DIRECTORY NUMBER
	GETJI
	 ERCAL JSBOMB			;SHOULDN'T FAIL
	MOVE B,C		;DIRECTORY NUMBER IN B
	MOVEM B,LOGNO		;REMEMBER OUR LOGIN DIRECTORY NUMBER
	HRROI A,CMDSPC
	DIRST			;START FORMING FILESPEC TO LOGIN DIRECTORY
	 ERCAL JSBOMB			;SHOULD ALWAYS SUCCEED
	HRROI B,[ASCIZ /DATE.CMD/]	;WE WANT DATE.CMD ON LOGIN DIRECTORY
	MOVEI C,0		;STOP ON NULL
	SOUT			;FINISH CREATING NAME
	HRROI A,CMDSPC		;POINT TO THE FILESPEC
	CALL GETFSZ		;GET JFN (IN A SLY WAY!)
	 RET			;NO DATE.CMD
	MOVEM A,CMDJFN		;REMEMBER JFN OF COMMAND FILE
	MOVE B,[70000,,OF%RD]	;OPEN FOR READING
	OPENF			;OPEN COMMAND FILE
	 ERJMP [	JSERR	;FAILED, SAY WHY
			MOVE A,CMDJFN
			RLJFN	;RELEASE JFN
			 JFCL	;IGNORE FAILURE
			RET]
	MOVE B,.CMIOJ+SBK	;GET OLD STREAM
	HRL A,A			;SET INPUT JFN TO DATE.CMD
	HRRI A,377777		;NO EDITING JFN
	MOVEM A,.CMIOJ+SBK	;SAVE NEW STREAM
	MOVEM B,SAVIOJ		;REMEMBER OLD STREAM
CMLUP:	CALL DOCMD		;DO A COMMAND FROM THE FILE
	 CAIA			;FAILED
	JRST CMLUP		;SUCCEEDED, DO REST
	MOVEI A,.FHSLF
	GETER			;FAILED, PROBABLY END OF FILE
	CAME B,[.FHSLF,,IOX4]	;END OF FILE?
	 JRST [	CALL CMDER1	;NO, PRINT ERRR
		JRST CMLUP]	;DO REST OF COMMANDS
	MOVE A,CMDJFN
	CLOSF			;CLOSE IT
	 JSERR			;SHOULDN'T EVER FAIL
	MOVE A,SAVIOJ
	MOVEM A,.CMIOJ+SBK	;RESTORE COMMAND JFNS (PROBABLY BACK TO TERMINAL)
	RET

;ROUTINE TO REPORT SPYERS

SPYERS:	SKIPE SPYF		;DON'T CHECK IF USER SAID NOT TO
	SKIPE SPYERF		;ERRORS ALREADY?
	RET			;YES SO GIVE UP NOW
	HRROI A,[ASCIZ /Spyers/]
	MOVEM A,BUSYF		;SAY WHAT WE'RE DOING
	CALL GOBSYM		;GET VALUES FOR VARIOUS MONITOR SYMBOLS
	 JRST NOSPY		;FAILED, TELL USER WHY
	CALL GETLIN		;GET OUR LINE NUMBER
	CAMN A,[-1]		;DETACHED?
	RET			;YES, NOTHING TO REPORT
	ADD A,TTACTL		;GET MON ADDRESS HOLDING TTY TABLE ADDRESS
	CALL MPEEK		;GET TTY TABLE ADDRESS
	 JRST NOSPY
	ADD B,TTLINK		;GET MON ADDRESS HOLDING LINK DATA
	MOVE A,B		;GET ADDRESS IN MONITOR
	CALL MPEEK		;SEE WHO'S SPYING
	 ERCAL JSBOMB			;CAN'T!
	CAMN B,OLDSPY		;ANYONE DIFFERENT THAN LAST TIME?
	RET			;NO, DONE
	MOVE P1,B		;SAVE NEW STATE OF SPYERS
	MOVSI P2,-4		;PREPARE TO COMPARE 4 BYTES
	MOVE P3,[441100,,P1]	;POINTER TO NEW STATUS
	MOVE P4,[441100,,OLDSPY];POINTER TO OLD STATUS
SLUP:	ILDB A,P3		;GET NEW BYTE
	ILDB B,P4		;GET OLD
	CAMN A,B		;A CHANGE?
	JRST SLUP1		;NO
	CAIE A,777		;NEW ONE A NONTERMINAL?
	CALL ARRIVE		;NO, IS A TERMINAL!
	LDB A,P3		;GET NEW AGAIN
	CAIN A,777		;IF A NONTERMINAL
	CALL LEAVE		;SAY WHO LEFT
SLUP1:	AOBJN P2,SLUP		;DO ALL FOUR BYTES
	MOVEM P1,OLDSPY		;SAVE STATUS FOR NEXT INTERRUPT
	RET

;ROUTINE TO UPDATE JOB RUNTIME TABLE.

RUPDAT:	STKVAR <HMJ,HM,JOBPRV,MAXRTM,MAXRJN>
	MOVN P1,JTLEN		;GET NEGATIVE OF LENGTH OF TABLE
	HRLZ P1,P1		;MAKE AOBJN POINTER
	CALL PIOFF		;LOCK TOTRUN SO ^D DOESN'T PRINT INCONSISTENT DATA
	HRROI A,[ASCIZ /Percentages/]
	MOVEM A,BUSYF		;SAY WHAT WE'RE DOING
	SETZM TOTRUN		;INITIALIZE TOTAL RUNTIME
	SETZM MAXRTM		;MAXIMUM RUNTIME INTERVAL SEEN
JUP:	HRRZ A,P1		;GET JOB NUMBER
	CALL RUNTIM		;GET ITS TOTAL RUNTIME
	EXCH A,OLDRUN(P1)	;SAVE TOTAL RUNTIME, GET OLD TOTAL
	SUB A,OLDRUN(P1)	;GET AMOUNT USED IN TIME INT THAT JUST ENDED
	MOVNM A,JRINTB(P1)	;REMEMBER HOW MUCH THIS JOB RAN IN LAST INTERVAL
	SKIPGE OLDRUN(P1)	;DOES THIS JOB REALLY EXIST??
	SETZM JRINTB(P1)		;NO, SO IT HASN'T USED ANY TIME IN LAST INTERVAL
	MOVE A,JRINTB(P1)	;GET RUNTIME DURING THIS SECTION
	CAML A,MAXRTM		;NEW MAXIMUM RUNTIME?
	 JRST [	HRRZM P1,MAXRJN	;YES, REMEMBER WHICH JOB HAS MAXIMUM RUNTIME
		MOVEM A,MAXRTM	;REMEMBER NEW MAXIMUM RUNTIME
		JRST .+1]
	ADDM A,TOTRUN		;ACCUMULATE TOTAL
	AOBJN P1,JUP		;UPDATE DATA FOR ALL JOBS
	FLTR A,TOTRUN		;GET FLOATING VERSION OF TOTAL RUNTIME
	MOVEM A,TOTRUN
	CALL PION		;UNLOCK TOTRUN
	SKIPN HOGERF		;ERRORS DETECTED CHECKING FOR HOGGERS?
	SKIPN HOGF		;CHECKING FOR HOGGERS?
	RET			;NOT CHECKING, OR ERRORS DETECTED
	HRROI A,[ASCIZ /Hoggers/]	;SAY WHAT WE'RE CALCULATING
	MOVEM A,BUSYF
	CALL GOBSYM		;GET VALUES FOR VARIOUS MONITOR SYMBOLS
	 JRST [	SETOM HOGERF	;REMEMBER THAT FAILURE REPORTING HOGS
		TYPE <
%DATE: Won't be able to check for hoggers - >
		CALLRET PERR]	;SAY WHY AND RETURN
	MOVEI A,HMX		;PERHAPS THIS JOB HAS ALREADY BEEN ANNOUNCED
CP6:	SOJL A,CP7		;NO IF CAN'T FIND IT
	SKIPGE B,HOGLST(A)	;FIND A USED ENTRY?
	JRST CP6		;NO, LOOK AT REST OF TABLE
	CAME B,MAXRJN		;YES, IS IT CURRENT JOB?
	JRST CP6		;NO
CP8:	SETOM MAXRJN		;YES, ALREADY RECORDED, JUST CHECK FOR UNHOGS
	JRST CP2
CP7:	MOVE A,MAXRJN		;GET JOB NUMBER
	CALL SKPINU		;DO WE CARE ABOUT THIS USER?
	 JRST CP8		;NO
	MOVE A,MAXRJN		;GET JOB NUMBER
	CALL SKPPRI		;CHECK FOR SPECIAL PRIORITY JOB
	JRST CP8		;NO, CHECK FOR UNHOGGERS
	MOVEM A,JOBPRV		;REMEMBER PRIVILEGE WORD
	LOAD A,LQP1,JOBPRV	;GET ONE PLUS LOW QUEUE
	CAILE A,3		;CRUDE CHECK TO IGNORE "BATCH BACKGROUND"
	JRST CP8		;DON'T CONFUSE BATCH BACKGROUND WITH HIGHLY PRIVILEGED
	XTMSG <*Job >
	MOVE A,MAXRJN		;GET JOB NUMBER
	MOVEI B,5+5		;PRINT IN DECIMAL
	CALL NUM		;ANNOUNCE WHICH JOB
	XTMSG <, user >
	MOVE A,MAXRJN		;GET JOB NUMBER
	CALL PNAME		;PRINT USER NAME
	MOVE B,MAXRJN		;GET JOB AGAIN
	XTMSG < is hogging the system by >
	LOAD A,PERCNT,JOBPRV	;GET PERCENTAGE BEING DEMANDED
	CAIN A,0		;SEE WHICH TYPE OF SERVICE BEING FORCED
	JRST [	XTMSG <staying above scheduler queue >
		LOAD A,LQP1,JOBPRV	;GET ONE PLUS LOW QUEUE
		MOVEI B,5+5	;PRINT IN DECIMAL
		CALL NUM
		XTMSG <!
>
		JRST CP2]
	XTMSG <demanding >
	LOAD A,PERCNT,JOBPRV	;GET PERCENTAGE
	MOVEI B,5+5		;PRINT IN DECIMAL
	CALL NUM
	XTMSG <% of the CPU!
>
CP2:	MOVEI A,HMX		;SCAN LIST OF HOGS TO ADD THIS GUY TO LIST
	MOVEM A,HM
CP3:	SOSGE A,HM		;SCAN LIST
	 RET			;NO ROOM ON LIST, OR DONE!
	SKIPL B,HOGLST(A)		;FREE SLOT?
	 JRST CP4		;NO, BUT MAYBE WE CAN FREE IT UP
CP5:	MOVE B,MAXRJN		;YES, ADD THIS JOB TO THE LIST
	MOVEM B,HOGLST(A)
	SETOM MAXRJN		;PREVENT ENTRY FROM BEING MADE TWICE
	JRST CP3		;CONTINUE TO SCAN TO REMOVE NONHOGS

CP4:	MOVE A,B		;PUT JOB NUMBER IN A OF OLD HOG
	CALL SKPPRI		;IS THIS GUY STILL A HOG?
	 CAIA			;NO, ANNOUNCE HE'S NOT
	JRST CP3		;YES, CAN'T CLEAR HIS SLOT YET
	MOVE B,HM		;GET SLOT OF GUY WHO'S NO LONGER HOGGING
	MOVE A,HOGLST(B)	;GET JOB NUMBER
	MOVEM A,HMJ		;REMEMBER JOB NUMBER
	SETOM HOGLST(B)		;FREE UP THE SLOT
	CALL SKPINU		;IS THIS USER INCLUDED?
	JRST CP3		;NO, SO SKIP ANNOUNCEMENT
	XTMSG <*Job >
	MOVE B,HM		;GET SLOT OF GUY WHO'S NO LONGER HOGGING
	MOVE A,HMJ		;GET JOB NUMBER
	MOVEI B,5+5		;PRINT IN DECIMAL
	CALL NUM		;BETTER NOT PRINT USER NAME BECAUSE MAY BE DIFFERENT OR NONEXISTENT!
	XTMSG < is no longer hogging the system.
>
	MOVE A,HM		;GET SLOT WE'RE USING
	JRST CP5		;GO USE THIS SLOT FOR THE NEW GUY

IFG NUFKS-^D35,<printx ?PRINTX: This program won't run with NUFKS .GT. 35.>

;ROUTINE WHICH INVESTIGATES THE JOB WHOSE NUMBER IS IN A TO SEE
;IF IT HAS JUST STARTED OR STOPPED HOGGING THE SYSTEM (A LA JOBBIT IN
;PSB DATABASE)
;THIS ROUTINE SKIPS IF JOB IS HOGGING THE SYSTEM, YIELDING THE PRIVILEGED
;SCHEDULER WORD IN A, AND THE FORK NUMBER IN B.  B WILL CONTAIN -1 IF JOBSKD
;IS THE OFFENDER AS OPPOSED TO A PARTICULAR FORK

SKPPRI:	TRVAR <WCHJOB,NCFK,PRVWRD>
	MOVEM A,WCHJOB		;REMEMBER WHICH JOB WE'RE DOING
	SKIPE WCHJOB		;DON'T BITCH ABOUT JOB 0
	SKIPN INITF		;DO WE HAVE MONITOR SYMBOLS YET?
	RET			;NO, SO CAN'T CHECK FOR HOGS YET
	MOVEI A,NUFKS+1		;NUMBER OF FORKS TO CHECK, +1 FOR JOB WORD TOO
	MOVEM A,NCFK
CP1:	SOSGE A,NCFK		;STEP TO NEXT FORK OF JOB
	RET			;NO MORE FORKS, JOB IS NOT A HOG
	CALL GETPRI		;GET PRIVILEGE WORD FOR THIS FORK
	 JRST CP1		;FORK DOESN'T EXIST
	MOVEM A,PRVWRD		;REMEMBER PRIVILEGE WORD IN CASE THIS IS A HOG
	CALL SKPHOG		;SKIP IF THIS FORK IS A HOG
	 JRST CP1		;NOT A HOG
	MOVE A,PRVWRD		;HE'S A HOG, GET PRIVILEGE WORD
	MOVE B,NCFK		;GET FORK NUMBER
	CAIN B,NUFKS		;MAIN JOB RATHER THAN SPECIFIC FORK?
	HRROI B,-1		;YES, SO RETURN -1
	RETSKP			;SKIP TO ANNOUNCE THIS GUY'S A HOG

;SKPHOG INTERPRETS JOBBIT WORD IN A, AND SKIPS IF THIS JOBBIT WORD
;REPRESENTS ONE FOR A FORK WHICH IS USING SPECIAL SCHEDULER QUEUES

SKPHOG:	TXNE A,PERCNT!LQP1	;CHECK FOR SPECIAL PRIVS
	RETSKP			;NON-0 MEANS HE IS
	RET			;NO

;GET JOBBIT WORD FOR FORK IN A OF JOB IN WCHJOB
;
;ACCEPTS:	A/	FORK NUMBER (0 - NUFKS-1), OR NUFKS TO READ JOBSKD
;		WCHJOB/	JOB NUMBER
;
;RETURNS:	+1	NO SUCH FORK OR NO SUCH JOB OR OTHER ERROR
;		+2	FORK EXISTS, JOBBIT WORD IN A

GETPRI:	STKVAR <FN>
	MOVEM A,FN		;REMEMBER WHICH FORK
	MOVE C,A		;SAY WHICH WORD OF FORK TABLE
	MOVEI B,SYSFK		;SAY WHICH TABLE
	CAIN A,NUFKS		;READING JOB'S WORD?
	JRST [	MOVEI B,JOBSKD	;YES, SPECIFY IT
		MOVE A,WCHJOB	;SAY WHICH JOB TO EXAMINE
		MOVEI C,0	;NO OFFSET
		CALL REDJOB	;GET JOB'S JOBSKD WORD
		 RET		;JOB DOESN'T EXIST
		RETSKP]		;RETURN JOBSKD WORD
	MOVE A,WCHJOB		;SAY WHICH JOB
	CALL REDJOB		;READ SYSTEM FORK INDEX
	 RET			;JOB DOESN'T EXIST, PROBABLY
	JUMPL A,R		;NO SUCH FORK IF NEGATIVE
	HRRZ A,A		;KEEP ONLY THE FORK NUMBER
	MOVEI B,JOBBIT		;NOW WE'LL READ SCHEDULER WORD OF THAT FORK
	MOVEI C,0		;IT'S NOT A TABLE, SO OFFSET OF 0
	CALL REDFRK
	 RET			;FAILED, GIVE NON-SKIP RETURN (NO SUCH FORK)
	RETSKP			;SKIP WITH PRIORITY WORD IN A

;REDFRK READS A WORD FROM PSB
;
;ACCEPTS:	A/	FORK #
;		B/	TABLE
;		C/	OFFSET
;RETURNS:	+1	FAILURE, NO SUCH FORK OR OTHER FAILURE
;		+2	SUCCESS, DATA IN A

REDFRK:	MOVEI D,.RDPSB		;SAY TO READ PSB
	CALLRET REDDAT

;REDJSB READS A WORD FROM THE JSB
;
;ACCEPTS:	A/	JOB #
;		B/	WORD IN JSB TO READ
;
;RETURNS:	+1	FAILURE, SUCH AS NO SUCH JOB OR MONRD FAILURE
;		+2	SUCCESS, WORD CONTENTS IN A

REDJSB:	MOVE D,A		;JOB NUMBER IN D FOR MONRD
	MOVEI A,.RDJSB		;READ FROM JSB
	MOVE C,B		;MONRD WANTS ADDRESS IN C
	MOVEI B,0		;NO SPECIAL SYMBOL
	CALL DMONRD		;DO THE MONRD JSYS
	 RET			;SINGLE RETURN IF ERROR
	MOVE A,B		;RETURN DATA IN A
	RETSKP			;SKIP IF SUCCESS

;REDJOB READS WORD FROM JSB, WHEN SYMBOL NAME KNOWN
;
;ACCEPTS:	A/	JOB #
;		B/	TABLE TO READ (MORE EXPLANATION NEEDED HERE!)
;		C/	OFFSET
;RETURNS:	+1	FAILURE, NO SUCH JOB, OR MONRD DOESN'T EXIST
;		+2	SUCCESS, DATA IN A

REDJOB:	MOVEI D,.RDJSB		;SAY READING FROM JSB
	CALLRET REDDAT		;GO READ DATA

;REDDAT READS DATA FROM JSB OR PSB
;
;ACCEPTS:	A/	JOB OR FORK #
;		B/	TABLE POINTER
;		C/	OFFSET INTO TABLE
;		D/	MONRD FUNCTION CODE
;RETURNS	+1	FAILURE
;		+2	SUCCESS, DATA WORD IN A

REDDAT:	STKVAR <JN,TABL,OST,MFC>
	MOVEM A,JN
	MOVEM B,TABL
	MOVEM C,OST
	MOVEM D,MFC		;REMEMBER MONRD FUNCTION CODE
	MOVE B,[SIXBIT /JSVAR/]	;FIRST ASSUME READING JSB VARIABLE
	MOVE D,JSVAR		;GET MONITOR VALUE OF "JSVAR"
	MOVE A,MFC		;GET FUNCTION CODE
	CAIN A,.RDPSB		;READING FROM PSB??
	JRST [	MOVE B,[SIXBIT /PSVAR/]	;YES, DIFFERENT OFFSETS
		MOVE D,PSVAR
		JRST .+1]
	SUB D,@TABL		;GET OFFSET FROM DATABASE TO SYMBOL WE WANT
	MOVN C,D		;GET POSITIVE OFFSET
	ADD C,OST		;CREATE DESIRED OFFSET INTO TABLE
	MOVE D,JN		;SAY WHICH JOB OR FORK WE'RE READING
	MOVE A,MFC		;GET FUNCTION CODE
	CALL DMONRD		;DO THE MONRD JSYS
	 RET			;FAILED, TELL CALLER
	MOVE A,B		;RETURN DATA IN A
	RETSKP

;DMONRD DOES THE MONRD JSYS.  IT SKIPS IF SUCCESSFUL

DMONRD:	MONRD%			;DO THE MONRD
	 ERJMP R		;DON'T SKIP IF JSYS FAILS
	JUMPE A,RSKP		;SKIP IF SUCCESSFUL
	RET

;ROUTINE TO RETURN RUNTIME FOR JOB.  GIVE IT JOB NUMBER IN A.

RUNTIM:	HRL A,A			;JOB NUMBER IN LEFT HALF
	HRRI A,.JOBRT		;SPECIFY THAT WE WANT RUNTIME
	GETAB			;GET THE RUNTIME
	 JSERR
	RET

;get here when some jsys critical in the grump checking system
;fails.  this routine tests a flag, so we don't get a million
;errors for the same reason.

nogrmp:	SETOM GRERRF		;SAY THERE'S BEEN ERRORS
	TMSG <
%DATE: Won't be able to type grumps or mail
>
	CALLRET PERR		;GO SAY WHY AND RETURN

;ROUTINE TO SEARCH FORWARD THROUGH GRUMP FILE FOR THE GRUMP ITSELF,
;IDENTIFIED BY THE LINE AFTER THE ONE ENDING WITH "INFORMATION:<CRLF>"

FGRUMP:	SETZM BACKF		;WE WANT TO SEARCH FORWARDS
FR1:	CALL GCHARU		;GET CHARACTER FROM FILE
FG1:	CAIE A,"I"		;WHAT WE'RE LOOKING FOR?
	JRST FR1		;NO, CHECK NEXT
	CALL GCHARU		;YES, GET NEXT
FG2:	CAIE A,"N"
	JRST FG1
	CALL GCHARU
	CAIE A,"F"
	JRST FG1
	CALL GCHARU
	CAIE A,"O"
	JRST FG1
	CALL GCHARU
	CAIE A,"R"
	JRST FG1
	CALL GCHARU
	CAIE A,"M"
	JRST FG1
	CALL GCHARU
	CAIE A,"A"
	JRST FG1
	CALL GCHARU
	CAIE A,"T"
	JRST FG1
	CALL GCHARU
	CAIE A,"I"
	JRST FR1		;DON'T CHECK "I" TWICE!
	CALL GCHARU
	CAIE A,"O"
	JRST FG2		;MIGHT BE "IN..."
	CALL GCHARU
	CAIE A,"N"
	JRST FG1
	CALL GCHARU
	CAIE A,":"
	JRST FG1
	CALL GCHARU
	CAIE A,15
	JRST FG1
	CALL GCHARU
	CAIE A,12
	JRST FG1
	RET			;FOUND "INFORMATION:<CRLF>"

;ROUTINE TO SEARCH THROUGH THE GRUMP FILE, LOOKING FOR
;THE USER NAME WHO SUBMITTED THE GRUMP.  IT ASSUMES THAT THE USER NAME
;STARTS WITH THE FIRST NON-SPACE, NON-TAB AFTER THE STRING "FROM:"

SGBEG:	CALL GCHAR		;GET A CHARACTER
SG1:	CAIE A,"F"		;FOUND F?
	JRST SGBEG		;NO, KEEP LOOKING
	CALL GCHARU		;YES, CHECK NEXT
	CAIE A,"R"		;AN R?
	JRST SG1		;NO, MAYBE F
	CALL GCHARU		;YES, LOOK AT NEXT
	CAIE A,"O"		;O?
	JRST SG1		;NO, MAYBE F
	CALL GCHARU
	CAIE A,"M"
	JRST SG1
	CALL GCHARU
	CAIE A,":"
	JRST SG1
SG2:	CALL GCHAR		;GET CHARACTERS AFTER "FROM:"
	CAIE A,11
	CAIN A,40
	JRST SG2		;LOOP UNTIL NON-SPACE SEEN
	SETOM BACKF		;GO BACKWARDS ONE CHARACTER SO FIRST USER NAME CHARACTER CAN BE REREAD
	CALLRET GCHAR		;BACK UP

;ROUTINE TO READ IN PAGE FROM GRUMP FILE.  PASS IT PAGE NUMBER IN A.
;THIS ROUTINE USES BACKF TO DECIDE WHETHER TO RESET BYTE POINTER TO
;BEGINNING OR END OF PAGE, ALWAYS SUCH THAT ILDB RETRIEVES NEXT CHARACTER
;DESIRED

GRMAP:	CAMN A,GRPGN		;MAYBE PAGE IS ALREADY MAPPED
	JRST GRM1		;YESSIR!
	MOVEM A,GRPGN		;REMEMBER WHICH PAGE WE'RE MAPPING IN
	HRL A,@PREJFN		;MAKE PAGE HANDLE TO FILE
	MOVE B,[.FHSLF,,GRBPN]	;MAP INTO OURSELF, GRUMP BUFFER PAGE NUMBER
	MOVX C,PM%CPY		;ALLOW BLT INTO THIS PAGE
	PMAP			;MAP IN THE PAGE
GRM1:	MOVE A,[100700,,GRBPAG+777]	;POINT TO LAST CHARACTER ON PAGE
	SKIPN BACKF
	MOVE A,[010700,,GRBPAG-1]	;DIFFERENT POINTER IF READING FORWARD
	MOVEM A,GRPTR		;INITIALIZE POINTER TO DATA
	RET

;TABLE OF BYTE POINTERS FOR TRANSLATING FROM BYTE ADDRESS TO BYTE POINTER

BTAB:	010700,,GRBPAG-1		;EXACT MULTIPLE OF FIVE CHARACTERS
	350700,,GRBPAG		;ONE LESS THAN MULTIPLE OF FIVE
	260700,,GRBPAG
	170700,,GRBPAG
	100700,,GRBPAG

;ROUTINE TO READ NEXT CHARACTER FROM GRUMP FILE.  MAKES ALL LETTERS
;UPPERCASE
;USES BACKF TO DECIDE WHETHER TO READ FORWARD OR BACKWARD.
;IT RETURNS B0 ON IFF END (OR BEGINNING) OF FILE SURPASSED, IF GEOFDA IS 0.
;IF GEOFDA IS NON-0, EOF TRANSFERS TO CONTENTS OF GEOFDA

GCHARU:	CALL GCHAR		;GET CHARACTER
	CAIL A,141
	CAILE A,172
	RET
	TRZ A,40		;MAKE UPPERCASE
	RET

;SAME AS ABOVE BUT RETURN CHARACTER AS IS (DON'T RAISE)

GCHAR:	SKIPE BACKF		;MAKE SURE READING FORWARD
	JRST GC1		;NO, BACKWARD!
	MOVE A,GRPTR		;MAKE SURE WE'RE NOT AT END OF PAGE
	CAMN A,EOG		;ARE WE AT END OF GRUMP?
	JRST GEOF1		;YES, MAYBE
GC5:	CAMN A,[010700,,GRBPAG+777]
	JRST GC2		;WE ARE AT END OF PAGE!
GC3:	ILDB A,GRPTR
	RET

;HERE WHEN HIT END OF PAGE READING FORWARD

GC2:	MOVE A,GRPGN		;STEP TO NEXT PAGE
	AOJ A,
	CAMLE A,LPIG		;WITHIN RANGE OF PAGES?
	JRST GEOF		;NO, SOMEONE PROBABLY GOT "OVER QUOTA" WHILE SENDING A GRUMP!
	CALL GRMAP		;MAP PAGE IN
	JRST GC3		;GO BACK AND READ CHARACTER

;HERE WHEN READING BACKWARDS

GC1:	MOVE A,GRPTR
	CAMN A,[350700,,GRBPAG]	;AT BEGINNING OF PAGE?
	JRST GC4		;YES
	MOVNI A,2		;NO, BACK UP BY TWO BYTES
	ADJBP A,GRPTR
	MOVEM A,GRPTR		;STORE UPDATED POINTER
	JRST GC3		;GO READ THE CHARACTER

;HERE WHEN HIT BEGINNING OF PAGE READING BACKWARD

GC4:	MOVE A,GRPGN		;BACK UP TO PREVIOUS PAGE
	SOJL A,GEOF		;IF PAGE HITS 0, WE'VE GOT END OF FILE
	CALL GRMAP		;MAP IT IN
	JRST GC3		;GO BACK AND READ CHARACTER

;HERE IF MAYBE END OF FILE WHEN READING FORWARD (BECAUSE BYTE POINTER
;LOOKS SUSPICIOUS)

GEOF1:	MOVE B,GRPGN		;SEE WHICH PAGE IS MAPPED
	CAMGE B,LPIG		;REACHED LAST?
	JRST GC5		;NO
	JRST GEOF		;YES, END OF GRUMP

;HERE ON END OF FILE

GEOF:	SKIPE A,GEOFDA		;SPECIAL PLACE TO GO ON END OF FILE?
	JRST (A)		;YES, GO THERE
	MOVX A,1B0		;SAY END OF FILE
	RET

;HERE TO PRINT WHO JUST STARTED LINKING

ARRIVE:	XTMSG <
[Link from >
	LDB A,P3		;GET TERMINAL NUMBER
	TRO A,400000		;MAKE A TERMINAL DESIGNATOR
	CALL PNAME		;PRINT USER NAME
	XTMSG <, line >
	LDB A,P3
	CALL OCTNUM		;PRINT LINE NUMBER
	XTMSG <]
>
	RET

;HERE TO ANNOUNCE END OF LINK

LEAVE:	XTMSG <
[Break from >
	LDB A,P4		;GET TERMINAL NUMBER
	TRO A,400000		;MAKE INTO TERMINAL DESIGNATOR
	CALL PNAME		;PRINT USER NAME
	XTMSG <, line >
	LDB A,P4
	CALL OCTNUM		;PRINT LINE NUMBER
	XTMSG <]
>
	RET

;PRINT USER NAME, GIVEN TERMINAL OR JOB NUMBER
;
;ACCEPTS:	A/	400000+TTY
;
;			OR
;
;		A/	JOB NUMBER


PNAME:	STKVAR <TERNUM>
	MOVEM A,TERNUM
	CALL TTYLCK		;GET HANDLE ON TERMINAL OUTPUT
	MOVE A,TERNUM
	CALL GUSER		;GET USER NUMBER
	 JRST NOPNM		;FAILED, PROBABLY LOGGED OUT
	MOVE B,A		;PUT IT IN B
	MOVE A,TTYPNT		;GET OUTPUT POINTER
	DIRST
	 ERJMP NOPNM
	MOVEM A,TTYPNT		;UPDATE TTY OUTPUT POINTER
	CALLRET TTYULK		;UNLOCK OUTPUT AND RETURN

NOPNM:	CALL TTYULK
	XTMSG <?>
	RET

;ROUTINE TO DO PEEK JSYS ON ADDRESS SPECIFIED IN A.

MPEEK:	HRLI A,1		;WE ONLY WANT ONE WORD
	MOVEI B,B		;WE WANT TO RETURN IT IN B
	PEEK			;GET IT
	 ERJMP R		;CAN'T
	RETSKP			;GOT IT

;SKPINU skips iff user is included from hog printout
;
;Accepts:	A/	job number
;
;Returns+1:	user is NOT being INCLUDED
;	+2:	user IS being INCLUDED

SKPINU:	CALL GUSER		;GET USER NUMBER FOR THIS JOB
	RETSKP			;ASSUME INCLUDED IF CAN'T GET IT
	MOVE B,A		;PUT USER NUMBER IN B
	MOVE A,CSBUFP		;POINT TO SCRATCH SPACE
	DIRST			;GET STRING FOR THIS USER NAME
	 ERJMP RSKP		;ASSUME INCLUDED IF CAN'T
	MOVEI A,EXHTAB		;GET TABLE OF ONES BEING EXCLUDED
	MOVE B,CSBUFP		;POINT TO ONE IN QUESTION
	TBLUK			;SEE IF IT'S EXCLUDED
	TXNE B,TL%EXM		;EXACT MATCH SOMEWHERE?
	RET			;YES, SO HE'S BEING EXCLUDED
	RETSKP			;NO, SO HE'S INCLUDED

;GET USER NUMBER FOR JOB OR TERMINAL IN A.  SKIPS IF SUCCESSFUL.

GUSER:	HRROI B,A		;WE'LL RETURN USER NUMBER IN A
	MOVEI C,.JIUNO		;WE WANT USER NUMBER
	GETJI			;GET IT
	 RET
	RETSKP

;ROUTINE TO DO SNOOP TO GET VALUE OF MONITOR SYMBOL IN A.
;PASS MODULE NAME IN B

SYMBOL:	MOVE C,B		;PROGRAM NAME IN C
	MOVE B,A		;PUT SYMBOL IN B
	MOVEI A,.SNPSY		;WE WANT SYMBOL VALUE
	SNOOP			;GET IT
	 ERJMP R		;COULDN'T
	RETSKP			;GOT IT

;ROUTINE TO GET CURRENT JOB'S LINE NUMBER

GETLIN:	GJINF
	MOVE A,D
	RET

;ROUTINE TO DO TIMER JSYS

DTIMER:	CALL DTX		;MAKE CLOCK ENTRY
	 CAIA			;FAILED
	RET			;DONE
	TYPE <%DATE: No system space for clock entry - retrying
>
DTLUP:	MOVEI A,^D3000		;WAIT A SCANT THREE SECONDS
	DISMS
	CALL DTX		;TRY AGAIN
	 JRST DTLUP		;STILL FAILED
	TYPE <%DATE: TIMER JSYS succeeded
>
	RET

DTX:	TIME			;REMEMBER WHAT TIME WE POSTED INTERRUPT
	MOVEM A,LSTTIM
	MOVE A,[400000,,.TIMEL]	;WE WANT INTERRUPTS EVERY SO OFTEN
	MOVE B,[TIMEX]		;THIS OFTEN!
	MOVEI C,TIMCHN		;SET UP APPROPRIATE CHANNEL
DOTIMR:	TIMER
	 ERJMP [	CAIE A,TIMX7	;NO SPACE FOR CLOCK?
			CAIN A,TIMX8	;USER CLOCK ALLOCATION EXCEEDED?
			RET		;YES, LET CALLER HANDLE
			CALL JSBOMB]		;NO, FAILURE
	RETSKP			;SUCCEEDED

;ROUTINE TO PRINT SIXBIT WORD IN A.
;THIS ROUTINE GUARANTEES THAT PROGRAM WON'T HANG IF TERMINAL
;IS ^S'ED.  USE PSIXN IF IMMEDIATE OUTPUT WANTED.

PSIX:	STKVAR <SIXWRD,SIXPTR>
	MOVEM A,SIXWRD
	MOVE B,[440600,,SIXWRD]	;POINTER TO WORD
	MOVEM B,SIXPTR
PSIX1:	SKIPN SIXWRD		;ANY MORE CHARACTERS?
	JRST PSD		;NO
	ILDB A,SIXPTR		;GET SIXBIT CHARACTER
	ADDI A,40		;CHANGE TO ASCII
	CALL CHAR		;PRINT CHARACTER
	MOVEI A,0		;MASK CHARACTERS DONE, TO DETECT FINISH
	DPB A,SIXPTR
	MOVE B,SIXPTR
	TLNE B,770000		;PRINTED 6 YET?
	JRST PSIX1		;NO
PSD:	RET

;CHANGE SIXBIT TO ASCII
;ACCEPTS:	A/	SIXBIT
;		B/	ASCII POINTER

SIXASC:	STKVAR <SIX,ASCPTR>
	MOVEM A,SIX		;REMEMBER SIXBIT WORD
	MOVE A,B		;GET ASCII POINTER
	CALL FIXPT		;CHECK FOR -1 IN LEFT HALF
	MOVEM A,ASCPTR
	MOVE C,SIX		;GET SIXBIT TO BE CONVERTED
SIXA1:	JUMPE C,SIXA2		;LEAVE LOOP IF NO MORE SIXBIT CHARACTERS LEFT
	MOVEI B,0		;CLEAR OUT PREVIOUS JUNK
	LSHC B,6		;THERE ARE CHARACTERS, GET THE NEXT ONE
	ADDI B,40		;CHANGE TO ASCII
	IDPB B,ASCPTR		;STORE IN ASCII STRING
	JRST SIXA1		;LOOP FOR REST OF STRING
SIXA2:	MOVEI A,.CHNUL		;GET A NULL BYTE
	IDPB A,ASCPTR		;GUARANTEE NULL AFTER ASCII
	RET

;CHANGE -1,,FOO TO 440700,,FOO

FIXPT:	TLC A,-1		;CHANGE -1 TO 0, OTHER TO OTHER OTHER
	TLCN A,-1		;CHANGE 0 BACK TO -1, FIX OTHER
	HRLI A,440700		;WAS -1, NOW IT'S 440700
	RET

;ROUTINE TO PRINT SIXBIT WORD IN A IMMEDIATELY.

PSIXN:	STKVAR <SIQWRD,SIQPTR>
	MOVEM A,SIQWRD
	MOVE B,[440600,,SIQWRD]	;POINTER TO WORD
	MOVEM B,SIQPTR
PSIQ1:	ILDB A,SIQPTR		;GET SIXBIT CHARACTER
	JUMPE A,PXD		;DONE IF NULL
	ADDI A,40		;CHANGE TO ASCII
	PBOUT
	MOVE B,SIQPTR
	TLNE B,770000		;PRINTED 6 YET?
	JRST PSIQ1		;NO
PXD:	RET

;ROUTINE TO PRINT USER NAME FOR USER NUMBER IN A.

PUSR:	STKVAR <WHOU>
	MOVEM A,WHOU
	CALL TTYLCK		;LOCK TERMINAL
	MOVE B,WHOU		;PUT NUMBER IN B
	MOVE A,TTYPNT		;GET POINTER TO BUFFER
	DIRST			;PRINT NAME
	 ERJMP NOPNM		;COULDN'T
	MOVEM A,TTYPNT		;STORE UPDATED OUTPUT POINTER
	CALLRET TTYULK

;GET HERE WHEN USER TYPES ^P.

.PUSH:	CALL SAVACS
	CALL EXEINI		;INITIALIZE AN EXEC
	 JRST NOFORK		;FAILED
	MOVEM A,FORKH		;REMEMBER FORK HANDLE
	MOVE B,FORKH		;GET FORK HANDLE
	SUBI B,400000		;MAKE INDEX INTO TABLE
	MOVEM A,EFNTAB(B)	;REMEMBER JFN AND SHOW THAT FORK IS IN USE
	TMSG <
[Pushing...use POP to get back]
>
	MOVE A,FORKH		;GET HANDLE ON EXEC
	MOVEI B,0		;WE WANT STANDARD STARTING ADDRESS
	SFRKV			;START IT
PUS1:	JRST .DEBRK		;RESTORE AC'S AND DEBRK

;ROUTINE TO INITIALIZE AN EXEC.  SKIPS IF SUCCESSFUL

EXEINI:	STKVAR <EFRK>
	MOVX A,CR%CAP		;GIVE NEW EXEC SAME CAPS AS US
	CFORK			;GET NEW FORK
	 ERJMP R		;CAN'T
	MOVEM A,EFRK		;REMEMBER EXEC FORK
	MOVX A,GJ%OLD+GJ%SHT	;EXEC MUST EXIST, SHORT FORM GTJFN
	HRROI B,[ASCIZ /SYSTEM:NEW-EXEC.EXE/]
	GTJFN			;GET HANDLE ON EXEC
	 ERJMP [	MOVE A,EFRK	;FAILED, SO CANCEL FORK
			KFORK
			RET]	;ERROR RETURN
	HRL A,EFRK		;GET FORK HANDLE
	GET			;LOAD THE EXEC
	MOVE A,EFRK		;RETURN FORK HANDLE IN A
	RETSKP			;SKIP FOR SUCCESS

;IF CAN'T DO ANOTHER PUSH...

NOFORK:	TMSG <
?Can't do another PUSH
>
	CALL PERR		;PRINT ERROR MESSAGE
	JRST PUS1		;EXIT

;WHEN SOME FORK HALTS (OR GETS CREATED!!!!) WE INTERRUPT TO HERE
;WHEN EXEC HALTS, WE INTERRUPT TO HERE

.POP:	CALL SAVACS		;PRESERVE AC'S
	MOVSI D,-EFNLEN		;PREPARE TO SCAN TABLE
POP1:	SKIPN EFNTAB(D)		;THIS FORK IN USE?
	JRST POP2		;NO
	MOVEI A,400000(D)	;YES, MAKE A FORK HANDLE
	CALL HALTED		;DID THIS EXEC HALT?
	 JRST POP2		;THIS EXEC STILL RUNNING
	MOVEI A,400000(D)	;GET HANDLE AGAIN
	KFORK			;KILL THE FORK
	SETZM EFNTAB(D)		;SHOW THAT THIS SLOT FREE AGAIN
POP2:	AOBJN D,POP1		;LOOP TO CHECK ALL EXEC'S
	SKIPE A,TTYFRK		;MAKE SURE TTY FORK STILL ALIVE
	CALL HALTED
	 CAIA			;IT'S O.K.
	CALL TTYBAD		;IT HALTED
	CALL XCHECK		;MAKE SURE MAIN EXEC IS STILL ALIVE
	JRST .DEBRK		;RESTORE AC'S AND RETURN

;CHECK ON MAIN EXEC, AND IF HALTED DUE TO HALTF, RESTART IT.  IF
;HALTED DUE TO FATAL ERROR, ASK USER WHETHER TO RESTART IT.  NOTE THAT
;THIS MEANS ^EQUIT WON'T GET ONE INTO MINI-EXEC.

XCHECK:	MOVE A,XFORK		;GET HANDLE ON EXEC
	RFSTS			;GET ITS STATUS
	LOAD A,RF%STS,A		;GET STATE
	CAIN A,.RFHLT		;HALT?
	JRST [	SKIPE SICKF	;ARE WE ALREADY SICK?
		JRST SICK1	;YES, LET EXEC HALT.  USER MAY WANT TO PLAY DOCTOR!
		TYPE <DATE: No higher exec level
>
		JRST XSTART]	;GO RESTART (USER PROBABLY POPPED TOO MANY TIMES)
	CAIE A,.RFFPT		;UNEXPECTED HALT?
	CAIN A,.RFTRP		;STRANGE JSYS TRAP HALT?
	JRST XQUERY		;YES, GO QUERY USER
	CAIN A,.RFABK		;UNEXPECTED ADDRESS BREAK HALT?
	JRST XQUERY		;YES, QUERY
XOK:	RET			;EXEC HOPEFULLY NOT SICK NOW

XSTART:	MOVE A,XFORK		;GET HANDLE ON EXEC
	MOVEI B,0		;STANDARD START
	SFRKV
	RFORK			;IN CASE IT GOT FROZEN, MELT IT
	JRST XOK

;EXEC DIED STRANGE DEATH

XQUERY:	TYPE <DATE: Your exec has died!
>
	PROMPT <Shall we try to revive it? >
	MOVEI A,[FLDDB. .CMKEY,CM%SDH,[	2,,2
					T NO,0
					T YES,1],<Type YES to try to recover>]
	CALL CFIELD		;GET ANSWER
	MOVE B,(B)		;GET TABLE WORD
	TRNE B,-1		;USER WANT TO RECOVER?
	JRST XSTART		;YES, GO RESTART EXEC
	TYPE <DATE: Halting...
>
XHALTF:	HALTF			;STOP!
	JRST BEG		;RESTART WORLD IF CONTINUE

;QUIT COMMAND COMES HERE

.QUIT:	NOISE (COMPLETELY)
	CONFRM			;CONFIRM BUT DON'T RESTART EXEC
	HALTF			;STOP
	CALLRET AFTEOL		;RESUME EXEC IF HE TYPES CONTINUE

;HERE WHEN EXEC HALTS AFTER WE BECAME SICK

SICK1:	TYPE <DATE: Your exec has halted and DATE is sick - halting...
>
	JRST XHALTF		;REALLY STOP!

;GET HERE IF LOWER FORK FOR TERMINAL DIES

TTYBAD:	CAIE A,.RFHLT		;REGULAR HALT IS EXPECTED
	JRST TTYBDX		;ALL OTHER IS REAL BAD
	MOVE A,TTYFRK		;GET FORK HANDLE
	KFORK			;FREE UP THE SYSTEM FORK SLOT
TTYIN:	SETZM TTYFRK		;REMEMBER THAT IT DOESN'T EXIST ANYMORE
	MOVE A,[440700,,TTYBUF]
	MOVEM A,MIDPNT		;INITIAL "MIDPOINT" IS BEGINNING OF BUFFER
	MOVEM A,TTYPNT		;INIT END OF BUFFER TO BEGINNING
	SETOM OUTFLG		;SAY THERE'S NO MORE OUTPUT
	CALLRET TTYUL1		;UNLOCK OUTPUT SO PROGRAM MAY DO SOME

TTYBDX:	TMSG <
?DATE: Terminal output fork died - >
	HRL A,TTYFRK
	HRRI A,-1		;MOST RECENT ERROR
	CALL PERR1		;PRINT EXCUSE
	JRST FTLWAT		;DO NOTHING MORE

;GET HERE ON UNEXPECTED JSYS FAILURE.  TRY TO KEEP GUY'S EXEC RUNNING!

JSBOMB:	TMSG <
?DATE: Unexpected JSYS failure at >
	HRRZ A,(P)		;GET WHERE WE WERE CALLED FROM
	CALL POCT		;PRINT IN OCTAL
	TYPE < - >
	CALL PERR		;GIVE EXCUSE
	JRST FTLWAT		;SLEEP, MERELY SUPPORTING EXEC

;ROUTINE WHICH SKIPS IFF FORK IN A HAS HALTED
;IF HALTED, STATUS GETS RETURNED IN A

HALTED:	RFSTS			;SEE WHAT THIS FORK IS DOING
	LDB A,[222100,,A]	;ISOLATE THE STATUS
	CAIE A,.RFHLT		;IF FORK BOMBED OUT
	CAIN A,.RFFPT		;OR HALTED
	RETSKP			;FORK HALTED
	RET			;FORK STILL RUNNING

;ROUTINE TO COMPUTE DIFFERENCE IN CHARACTERS BETWEEN BYTE POINTERS
;IN A AND B.  RETURNS DIFFERENCE IN A.

SUBBP:	HRRZ C,A		;COMPUTE 5*(A1-A2)+(P2-P1)/7
	SUBI C,0(B)
	IMULI C,5		;COMPUTE NUMBER CHARS IN THOSE WORDS
	LDB A,[POINT 6,A,5]
	LDB B,[POINT 6,B,5]
	SUBM B,A
	IDIVI A,7
	ADD A,C
	RET

;HERE TO DEBRK FROM INTERRUPT FOR WHICH ACS WERE STORED

.DEBRK:	CALL RESACS			;RESTORE AC'S
	DEBRK				;DISMISS INTERRUPT

;HERE ON STACK OVERFLOW

PDLOV:	MOVE P,[IOWD POVLEN,POVSTK]	;SPECIAL STACK
	TMSG <
?DATE: stack overflow at PC >
BAD1:	TMSG <>		;GET USER'S ATTENTION
	HRRZ A,LEV1PC		;GET PC INTERRUPTED FROM
	CALL POCT		;PRINT PC IN OCTAL
	JRST ICOMN		;COMMON CODE

;SYSTEM RESOURCES EXHAUSTED

ICMSE:	TMSG <
?DATE: System resources exhausted at PC >
	JRST BAD1

;OVER QUOTA

ICQTA:	TMSG <
?DATE: Quota exceeded at PC >
	JRST BAD1

;FILE DATA ERROR

ICDAE:	TMSG <
?DATE: File data error at PC >
	JRST BAD1

;ILLEGAL MEMORY WRITE

ICIWR:	TMSG <
?DATE: Illegal memory write at PC >
	JRST BAD1

;ILLEGAL MEMORY READ

ICIRD:	TMSG <
?DATE: Illegal memory read at PC >
	JRST BAD1		;FINISH LIKE OTHER ERRORS

;GET HERE ON ILLEGAL INSTRUCTION INTERRUPT (UNEXPECTED)

ILL:	TMSG <
?DATE:   Error at PC >
	HRRZ A,LEV1PC+ILLLEV-1		;GET PC INTERRUPTED FROM
	CALL POCT		;PRINT PC IN OCTAL
	TMSG < - >
	MOVEI A,.PRIOU
	MOVE B,[.FHSLF,,-1]		;US, LAST ERROR
	MOVEI C,0			;NO LENGTH LIMIT
	ERSTR				;PRINT SYSTEM ERROR REASON
	 JSHLT
	 JSHLT
ICOMN:	TMSG <
>
	JRST FTLWAT			;NOTHING MORE TO DO (BUT USER'S EXEC MAY STILL BE RUNNING!)

;GET HERE WHEN WE HAVE A FATAL ERROR OTHER THAN THE EXEC HALTING.  THIS
;PLACE TRIES TO KEEP OURSELF ALIVE JUST ENOUGH TO ALLOW THE USER'S PROGRAMS
;TO CONTINUE RUNNING

FTLWAT:	SETOM SICKF		;REMEMBER THAT WE'RE SICK
	CALL PIOFF			;TURN OFF PI SYSTEM WHILE WE DISABLE STUFF
	MOVEI A,.FHSLF			;OURSELF
	HRROI B,-1			;ALL CHANNELS
	DIC				;DISABLE ALL CHANNELS
	MOVX B,1B<.ICIFT>		;ONLY RECEIVE EXEC TERMINATION INTERRUPTS
	AIC				;ACTIVATE EXEC TERMINATION
	CIS				;CLEAR ALL OTHER INTERRUPT LEVELS
	CALL PION			;TURN INTERRUPT SYSTEM BACK ON
	MOVE A,XFORK		;RESUME EXEC IN CASE WE DIED AFTER FREEZING IT
	RFORK
	WAIT				;DO NOTHING!

;COME HERE IF USER TYPES ^Y
;USE HIGH CHANNEL FOR READING CTRL/Y AND LOWER CHANNEL FOR EXECUTING COMMAND.
;THIS ALLOWS COMMANDS TO BE ABORTED WITH A SECOND CTRL/Y

.CTRLY:	CALL SAVACS		;DON'T CLOBBER AC'S
	MOVEI A,.FHSLF		;REQUEST COMMAND STARTUP
	MOVX B,1B<CMDCHN>
	MOVEI C,UNCMD		;PREPARE TO ABORT INTERRUPTED COMMAND
	SKIPE D,INCMDF		;DID WE REALLY INTERRUPT ANOTHER COMMAND?
	JRST [	MOVE P,D	;UNWIND STACK FROM INTERRUPTED COMMAND
		MOVEM C,LEV1PC+CTYLEV-1	;CAUSE PREVIOUS COMMAND TO IMMEDIATELY CLEAN UP AND EXIT
		IIC	;CAUSE COMMAND EXECUTION AFTER OLD COMMAND CLEAN'S UP
		DEBRK]	;LET NEW COMMAND START AFTER CLEAN UP
	IIC
	JRST .DEBRK		;START NEW COMMAND

COMAND:	CALL SAVACS		;DON'T CLOBBER AC'S
	CALL SAVCMD		;SAVE COMND IN CASE WE INTERRUPTED OUT OF COMND (HAPPENS IF CTRL/Y WHILE DATE.CMD BEING READ!)
	MOVEM P,INCMDF		;NOTE THAT DOING COMMAND AND SAVE STACK POINTER
	CALL CMDINI		;DO THIS AFTER SAVCMD TO AVOID OVERFLOWING CMDPDL (SEE CMD.MAC)
	MOVE A,XFORK			;GET HANDLE ON OUR EXEC
	FFORK			;FREEZE IT SO IT OR ITS PROGRAMS DON'T MIX INPUT WITH US
	TMSG <
[DATE: Type EXIT to resume >
	GETNM			;GET CURRENT PROGRAM NAME
	CALL PSIXN		;TYPE IT
	TMSG <]
>
	CALL DOCMD			;DO A COMMAND
	 JRST CMDERR		;FAILED, PRINT ERROR
UNCMD:	CALL RESCMD		;RESTORE COMND JSYS STUFF
	CALL RESACS		;FIX AC'S
	SETZM INCMDF		;SAY NOT IN COMMAND ANYMORE
	DEBRK			;DONE WITH INTERRUPT

;ROUTINE TO EXECUTE ONE COMMAND

DOCMD:	PROMPT (DATE>)
	MOVEI A,[FLDBK. .CMKEY,,COMLST]
	CALL RFLDE			;READ KEYWORD AT BEGINNING OF LINE
	 RET				;FAILED, PROBABLY END OF FILE
	MOVE A,(B)			;GET TABLE WORD
	CALL (A)			;GO HANDLE SPECIFIC COMMAND
	RETSKP				;GOOD COMMAND, SKIP RETURN

;LOGSKP REPORTS ABOUT LOGGING.
;
;RETURNS:	+1	LOGGING DISABLED
;		+3	ENABLED AND ANNOUNCED ALREADY

LOGSKP:	SKIPN LOGGF		;ENABLED?
	RET			;NO, SO RETURN TO SAY SO
	TMSG <* ENABLE LOGGING (ON FILE) >
	MOVEI A,.PRIOU		;OUTPUT TO PRIMARY
	MOVE B,LOGJFN		;PRINT FILESPEC
	MOVEI C,0		;STANDARD FORMAT
	JFNS
	TMSG <
>
	JRST R2SKP		;TWO SKIPS TO SAY WE'RE DONE

;LJFNBK CONTAINS DEFAULTS FOR LOGGING FILESPEC

LJFNBK:	0			;APPEND TO EXISTING FILE IF THERE.
	0			;COMND WILL FILL IN SOURCE/DES JFNS
	0			;NO DEFAULT DEVICE, DIRECTORY
	0
	-1,,[ASCIZ /DATE/]	;DEFAULT NAME TO DATE.LOG
	-1,,[ASCIZ /LOG/]
	BLOCK CJFNLN-.+LJFNBK	;LEAVE 0'S IN REST OF BLOCK

;.DLOG DISABLES LOGGING

.DLOG:	CALL OURCFM		;GET CONFIRMATION
	SKIPN LOGGF		;WERE WE LOGGING?
	JRST [	TMSG <% Logging was already disabled
>
		RET]
	SETZM LOGGF		;SAY WE'RE NOT LOGGING ANYMORE
	MOVE A,LOGJFN		;YES, RELEASE JFN
	RLJFN
	 ERJMP .+1		;IGNORE FAILURE
	RET

;.ELOG ENABLES LOGGING ON SPECIFIED FILESPEC

.ELOG:	NOISE (ON FILE)
	MOVE A,[LJFNBK,,CJFNBK]
	BLT A,CJFNBK+CJFNLN-1	;SET UP OUR GTJFN PARAMETERS
	MOVEI A,[FLDDB. .CMFIL,CM%SDH,,<File to receive DATE output>]
	CALL OURCFD		;READ JFN
	SKIPE LOGGF		;WAS LOGGING ENABLED ON ANOTHER FILE?
	JRST [	MOVE A,LOGJFN	;YES, GET RID OF OLD ONE
		RLJFN
		 ERJMP .+1	;SHOULDN'T FAIL
		JRST .+1]
	MOVEM B,LOGJFN		;REMEMBER THE JFN
	SETOM LOGGF		;REMEMBER THAT WE'RE NOW LOGGING
	RET

;UFLSKP REPORTS WHICH FILES ARE BEING CHECKED AND TAKES A DOUBLE SKIP TO
;TELL .SETTI THAT IT DID ALL THE WORK

UFLSKP:	MOVEI Q1,ULEN		;SCAN ENTIRE LIST
UFLS1:	SOJL Q1,R2SKP		;DONE WHEN COUNT RUNS OUT
	SKIPN UDIR(Q1)		;THIS SLOT IN USE?
	JRST UFLS1		;NO
	TMSG <* ENABLE UPDATE-FILE-CHECKING >
	MOVE A,UFPTR(Q1)	;GET POINTER TO FILESPEC
	PSOUT			;PRINT IT
	TMSG <
>
	JRST UFLS1		;PRINT THE REST

;DISABLE UPDATE-FILE-CHECKING (FOR FILES)

.DUFIL:	STKVAR <EUJFN>
	NOISE (FOR FILES)
	MOVE A,[UJFNBK,,CJFNBK]
	BLT A,CJFNBK+CJFNLN-1	;SET UP OUR SPECIAL DEFAULTS
	MOVEI A,[FLDDB. .CMFIL,CM%SDH,,<File set to check>]
	CALL OURCFD		;GET JFN AND CONFIRMATION
	TXNE B,GJ%DEV!GJ%UNT!GJ%DIR	;CAN'T ALLOW THESE SINCE GTDAL USED
	COMERR <Wildcarding only allowed after directory name>
	MOVEM B,EUJFN		;REMEMBER THE JFN
	MOVE A,CSBUFP		;POINT TO STRING SPACE
	MOVX C,JMAGIC		;BITS TO PRINT ALL FIELDS
	JFNS			;GET ALL FIELDS THAT CONTROL WHICH FILES ARE SELECTED
	MOVEI Q1,ULEN		;FIND SLOT WITH CORRECT VALUE
EUF1:	SOJL Q1,[	TMSG <% No ENABLE UPDATE-FILE-CHECKING was done for that file set
>
			RET]
	SKIPN UDIR(Q1)		;FIND A USED SLOT?
	JRST EUF1		;NO, KEEP LOOKING
	MOVE A,CSBUFP		;POINT TO SPEC BEING REMOVED
	MOVE B,UFPTR(Q1)	;POINT TO ONE IN TABLE
	STCMP			;COMPARE THEM
	JUMPN A,EUF1		;KEEP LOOKING IF DOESN'T MATCH
	MOVE A,UFPTR(Q1)	;MATCHED, GET POINTER TO ONE BEING REMOVED
	CALL STREM		;RETURN STRING SPACE TO FREE POOL
	SETZM UDIR(Q1)		;MATCHES, SO REMOVE IT
	RET

;ENABLE UPDATE-FILE-CHECKING

.EUFIL:	STKVAR <EUJFN>
	NOISE (FOR FILES)
	MOVEI Q1,ULEN		;FIND A FREE SLOT
EUF11:	SOJL Q1,[COMERR <Can't check more files - use DISABLE UPDATE-FILE-CHECKING>]
	SKIPE UDIR(Q1)		;FIND A FREE SLOT?
	JRST EUF11		;NO, KEEP LOOKING
	MOVE A,[UJFNBK,,CJFNBK]
	BLT A,CJFNBK+CJFNLN-1	;SET UP OUR SPECIAL DEFAULTS
	MOVEI A,[FLDDB. .CMFIL,CM%SDH,,<File set to check>]
	CALL OURCFD		;GET JFN AND CONFIRMATION
	TXNE B,GJ%DEV!GJ%UNT!GJ%DIR	;CAN'T ALLOW THESE SINCE GTDAL USED
	COMERR <Wildcarding only allowed after directory name>
	MOVEM B,EUJFN		;REMEMBER THE JFN
	MOVE A,CSBUFP		;POINT TO STRING SPACE
	MOVX C,JMAGIC		;GET SPECIAL BITS FOR GETTING ALL FIELDS
	JFNS			;ASK MONITOR FOR FILESPEC
	MOVEI Q2,ULEN		;MAKE SURE THIS ISN'T A DUPLICATE
EUF2:	SOJL Q2,EUF3		;NOT A DUPLICATE IF CAN'T FIND IT
	SKIPN UDIR(Q2)		;FIND AN INTERESTING SLOT?
	JRST EUF2		;NOT YET
	MOVE A,CSBUFP		;YES, GET NEW FILESPEC
	MOVE B,UFPTR(Q2)	;GET ONE FROM TABLE
	STCMP			;COMPARE THEM
	JUMPN A,EUF2		;NO MATCH SO DON'T WORRY
	TMSG <% ENABLE UPDATE-FILE-CHECKING for that file set is already in affect
>
	JRST EUF4

EUF3:	MOVE A,CSBUFP
	CALL BUFFS		;BUFFER UP THE FILESPEC STRING
	MOVEM A,UFPTR(Q1)	;REMEMBER POINTER TO FILESPEC STRING
	HRRZ B,EUJFN		;PREPARE TO GET DIRECTORY NUMBER
	MOVX A,RC%EMO		;WE WANT EXACT MATCH
	RCDIR			;GET THE DIRECTORY
	MOVEM C,UDIR(Q1)	;REMEMBER THE DIRECTORY NUMBER
	MOVE A,C
	GTDAL			;GET INITIAL ALLOCATION
	MOVEM B,USIZE(Q1)
	GTAD
	MOVEM A,UTIME(Q1)	;FIND UPDATES STARTING NOW
EUF4:	HRRZ A,EUJFN
	RLJFN			;RELEASE THE JFN
	 JFCL
	RET

;READ-ONLY JFN BLOCK FOR UPDATE-FILE-CHECKING

UJFNBK:	GJ%IFG!.GJALL		;ALLOW STARS, DEFAULT TO ALL GENERATIONS
	377777,,377777		;NO MORE INPUT OR OUTPUT NEEDED
	0
	0			;NO DEFAULT DEVICE AND DIRECTORY
	-1,,[ASCIZ /*/]		;DEFAULT TO ALL FILES IN DIRECTORY
	-1,,[ASCIZ /*/]		;DEFAULT TO ALL FILE TYPES
	-1,,[ASCIZ /*/]		;DEFAULT TO ALL GENERATIONS
	BLOCK CJFNLN-.+UJFNBK

;INSTANT PUSH FEATURE.

.EINST:	CALL OURCFM
	MOVE A,[IPC,,2]	;PUT ^P ON CHANNEL 2
	ATI
	RET

;ROUTINE TO SKIP IF INSTANT-PUSH IS ENABLED.

INSSKP:	MOVEI A,.FHSLF		;OURSELF
	RTIW			;SEE WHICH CHARACTERS ARE ENABLED
	TXNE B,1B<IPC>		;IS INSTANT PUSH ENABLED?
	RETSKP			;YES
	RET			;NO

.DINSTA:	CALL OURCFM
	MOVEI A,""
	DTI			;TURN OFF INSTANT-PUSH
	RET

;EXIT FROM PROGRAM

.EXIT:	NOISE (BACK TO PROGRAM AND EXEC)
	CALLRET OURCFM

;SYMBOL (NAME) NAME
;GIVES VALUE OF SYMBOL

.VALUE:	STKVAR <SD0,WHICH>
	CALL SYMINI		;GENERATE SYMBOL TABLE
	NOISE (OF SYMBOL)
	MOVEI A,KEYBLK			;KEY FUNCTION BLOCK
	CALL OURCFD
	MOVEM B,WHICH
	HLRO A,@WHICH			;GET POINTER TO SYMBOL NAME
	PSOUT				;TYPE NAME
	TMSG < = >
	MOVE B,@WHICH			;GET ADDRESS HOLDING VALUE
	MOVE D,(B)			;GET VALUE
	MOVEM D,SD0
	HLRZ A,SD0			;GET LEFT HALF
	CALL POCT		;PRINT IN OCTAL
	TMSG <,,>
	HRRZ A,SD0
	CALL POCT		;RIGHT HALF
	TMSG <
>
	RET

;VALUE (IN OCTAL)
;TELLS WHAT SYMBOLS MATCH THE VALUE

.SYMBO:	STKVAR <MATCHN>
	SETZM MATCHN			;NO MATCHES YET
	NOISE (WITH VALUE)
	MOVEI A,[FLDDB. .CMNUM,,8]
	CALL RFIELD
	MOVE P1,B			;USE AC FOR VALUE TO SAVE INST IN LOOP
	MOVEI A,[FLDDB. .CMCFM,,,,,[
		 FLDDB. .CMTOK,CM%SDH,<-1,,[ASCIZ /,,/]>,<two commas for halfword format>]]
	CALL RFIELD			;GET EITHER COMMAS OR CR
	LOAD C,CM%FNC,.CMFNP(C)		;SEE WHAT FUNCTION WAS TYPED
	CAIE C,.CMCFM			;CARRIAGE RETURN?
	JRST COMMAS			;NO, COMMAS
	CALL AFTEOL		;DO END-OF-COMMAND-LINE STUFF
SLUUP:	CALL SYMINI		;GENERATE SYMBOL TABLE
	HLRZ D,@SYMTAD			;GET NUMBER OF SYMBOLS TO LOOK UP
	MOVN D,D
	HRLZ D,D			;MAKE AOBJN POINTER
	HRR D,SYMTAD			;GET ADDRESS OF TABLE
SLOOP:	MOVE A,1(D)			;GET ADDRESS OF VALUE
	CAMN P1,(A)			;SKIP IF DOESN'T MATCH
	JRST SMATCH			;DOES!
SLOP1:	AOBJN D,SLOOP			;LOOP FOR REST OF SYMBOLS
	HRROI A,[ASCIZ /
/]
	SKIPN MATCHN			;ANY MATCH?
	HRROI A,[ASCIZ /No symbols match that value.
/]	;NO
	PSOUT
	RET

;HERE WHEN N,, SEEN

COMMAS:	MOVEI A,[FLDDB. .CMNUM,CM%SDH,8,<Octal value for right half>,0]
	CALL OURCFD
	HRL P1,P1			;NUMBER SEEN, SO FIRST ONE IS LEFT HALF
	HRR P1,B			;AND THIS ONE IS RIGHT HALF
	JRST SLUUP			;JOIN COMMON CODE

SMATCH:	AOS MATCHN			;KEEP TRACK OF NUMBER OF MATCHES
	MOVEI A,11
	PBOUT				;PRINT A TAB
	HLRO A,1(D)			;GET POINTER TO SYMBOL NAME
	PSOUT				;PRINT IT
	JRST SLOP1			;GO TO NEXT SYMBOL

;LOGTIM prints out last time of login for specified user

LOGTIM:	STKVAR <<LLBLK,.CDLLD+1>,LLDIR>
	NOISE (for user)
	MOVEI A,[FLDDB. .CMUSR]
	CALL OURCFD		;GET USER DESIRED
	MOVEI A,0		;NO SPECIAL RCDIR BITS
	RCDIR			;GET DIRECTORY NUMBER
	 ERJMP [COMERR <Unrecognizable user name>]
	MOVEM C,LLDIR		;REMEMBER DIRECTORY NUMBER
	MOVEI A,1+.CDLLD	;JUST READ ENOUGH TO GET THE TIME AND DATE
	MOVEM A,.CDLEN+LLBLK	;TELL GTDIR HOW MUCH TO READ
	MOVE A,LLDIR		;DIRECTORY NUMBER IN A
	MOVEI B,LLBLK		;SAY WHERE TO PUT INFO
	MOVEI C,0		;WE DON'T NEED PASSWORD
	GTDIR			;GET THE INFO
	 ERJMP [COMERR <Couldn't read last login time for that user>]
	SKIPN B,.CDLLD+LLBLK	;GET LAST LOGIN TIME
	JRST [	TYPE <That user has never logged in.
>
		RET]
	TYPE <Last LOGIN >
	MOVEI A,.PRIOU		;SEND OUTPUT TO PRIMARY
	ODTIM			;PRINT IT
	TYPE <
>
	RET

;HERE TO PRINT OUT TEXT STRING FOR A BUG

.BUGST:	NOISE (For BUG name)
	CALL BUGINI		;ENSURE BUG TABLE INITIALIZED
	MOVEI A,[FLDBK. (.CMKEY,,BUGTAB)] ;KEYWORD FROM BUG TABLE
	CALL OURCFD		;PARSE IT
	MOVE Q1,B		;SAVE ADDRESS OF TABLE ENTRY FOUND
	TYPE <Text for BUG name (>
	HLRO A,(Q1)		;GET POINTER TO BUG NAME
	LDB B,[341000,,(A)]	;SEE IF FLAG WORD
	CAIN B,1
	AOJ A,			;YES, SKIP IT
	PSOUT
	TYPE <): >
	HRRO A,(Q1)		;MAKE POINTER TO TEXT STRING
	PSOUT			;OUTPUT IT
	TYPE <
>				;FOLLOW BY CARRIAGE RETURN
	RET
	
;HERE TO EXCLUDE A BUGCHK FROM BEING REPORTED (SAME AS IGNORE)

BUGMSK:	BRMSK. (KEYB0.,KEYB1.,KEYB2.,KEYB3.,<%*>,<->)
BUGKEY:	FLDBK. (.CMKEY,,BUGTAB,,,BUGMSK,BUGFLD)
BUGFLD:	FLDBK. (.CMFLD,,,BUG name wildcarded with *'s and %'s,,BUGMSK)

.EXCLU:	NOISE (category)
	MOVEI A,[FLDDB. .CMKEY,,EXCTAB]
	CALL RFIELD		;SEE WHAT'S BEING EXCLUDED
	MOVE B,(B)
	CALLRET (B)		;HANDLE IT

EXCTAB:	EXCN,,EXCN
	T BUG,.EXBUG
	T HOG,.EXHOG
	EXCN==.-EXCTAB-1

;Here to exclude particular hogs

.EXHOG:	NOISE (user)
	HLRZ A,EXHTAB		;GET NUMBER ALREADY EXCLUDED
	CAIL A,EXHGMX		;MAXIMUM ALREADY BEING EXCLUDED?
	COMERR <Maximum already being excluded - try INCLUDEing some first>
	MOVEI A,[FLDDB. .CMUSR,CM%SDH,,<User name of hog you don't want to hear about>]
	CALL OURCFD		;GET USER NAME
	CALL BUFFF		;BUFFER THE USER NAME
	HRLZ B,A		;MAKE TABLE ENTRY
	MOVEI A,EXHTAB		;POINT TO TABLE
	TBADD			;ADD THIS ENTRY
	 ERJMP [	HLRO A,B	;COULDN'T ADD IT, GET BUFFERED STRING
			CALL STREM	;RELEASE ITS FREE SPACE
			CALL GETERR	;GET REASON FOR FAILURE
			CAIN A,TADDX2	;ALREADY IN TABLE?
			TYPE <% That user was already being excluded
>
			CAIE A,TADDX2
			JSERR		;PRINT JSYS ERROR FOR STRANGE FAILURE
			JRST .+1]
	RET			;DONE

;Here to include particular hog

.INHOG:	STKVAR <ININ>
	NOISE (user)
	MOVEI A,[FLDDB. .CMUSR,CM%SDH,CM%DWC,<User name, wildcarding O.K., of hog you want to hear about>]
	CALL OURCFD		;GET NAME HE WANTS TO HEAR ABOUT
	HLRZ A,EXHTAB		;GET NUMBER OF ENTRIES TO SCAN
	MOVEM A,ININ
INLP:	SOSGE A,ININ		;ANYMORE TO SCAN?
	RET			;NO
	HLRO C,1+EXHTAB(A)	;YES, GET POINTER TO NEXT ONE
	HRROI B,ATMBUF		;POINT TO USER'S TYPED STRING
	MOVX A,.WLSTR		;SAY COMPARE STRINGS
	WILD%			;COMPARE THE ENTRY
	TXNE A,WL%NOM		;IS IT A MATCH?
	JRST INLP		;NO, SO LOOP TO NEXT
	MOVE A,ININ		;YES, GET INDEX AGAIN
	HLRO A,1+EXHTAB(A)	;GET POINTER TO STRING
	CALL STREM		;FREE UP SPACE USED BY STRING
	MOVE B,ININ
	ADDI B,1+EXHTAB		;SAY ADDRESS OF ENTRY BEING DELETED
	MOVEI A,EXHTAB		;TELL SYSTEM WHERE TABLE IS
	TBDEL			;REMOVE THE ENTRY
	JRST INLP		;CHECK REST FOR MORE MATCHES

;Here to exclude particular bugs

.EXBUG:	NOISE (name)		;HINT AT WHAT THIS DOES
	CALL BUGINI		;INITIALIZE BUGCHK TABLE
	MOVEI A,BUGKEY
	CALL OURCFD
	MOVEI A,(C)		;GET ADDRESS OF FDB PARSED
	CAIN A,BUGKEY		;KEYWORD ENTERED?
	JRST .EXCL2		;YES...
				;NO..., HAS TO BE FIELD
	HLRZ D,BUGTAB		;GET NUMBER OF CURRENT BUGS IN TABLE
	ADDI D,1		;+1 TO LOOP FOR ALL
	MOVNS C,D		;MAKE IT NEGATIVE
	MOVEI D,BUGTAB		;ADDRESS OF BUG TABLE
	HRL D,C			;-COUNT,,ADDR IN D FOR LOOP COUNTER
.EXCL1:	AOBJP D,[RET]		;BUMP TO NEXT TABLE ENTRY, RETURN WHEN DONE
	HRROI B,ATMBUF		;POINTER TO WILD STRING
	HLRO C,(D)		;GET THIS ENTRY, LH HAS ADDR OF KEYWORD
	ADDI C,1		; BYPASS FLAG WORD
	MOVX A,<.WLSTR>		;WILD STRING FUNCTION CODE
	WILD%			;IS THIS A MATCH?
	TXNE A,WL%NOM
	JRST .EXCL1		;NO..., TRY NEXT ENTRY
	MOVE B,D
	CALL .EXCL2		;YES..., PUT IT IN TABLE OF IGNORED ENTRIES
	JRST .EXCL1		;TRY NEXT ENTRY

.EXCL2:	MOVEI A,BIGTAB		;POINT TO TABLE OF THINGS BEING IGNORED
	MOVE B,(B)		;GET ENTRY BEING ADDED
	TBADD			;TRY TO ADD NEW ENTRY
	 ERJMP [CALL GETERR		;SEE WHY FAILED
		CAIN A,TADDX1		;TABLE FULL?
		JRST .EXCL3		;YES
		TYPE <%BUG name already excluded
>
		RET]
	RET

.EXCL3:	HRROI A,[ASCIZ /No room to exclude another BUG/]
	ESOUT
	TMSG <
>
	RET

;HERE TO INCLUDE A BUGCHK WHICH HAS ALREADY BEEN EXCLUDED

IBGKEY:	FLDBK. (.CMKEY,,BIGTAB,,,BUGMSK,BUGFLD)

.INCLU:	NOISE (category)
	MOVEI A,[FLDDB. .CMKEY,,INCTAB]
	CALL RFIELD		;SEE WHAT'S BEING INCLUDED
	MOVE B,(B)
	CALLRET (B)		;HANDLE IT

INCTAB:	INCN,,INCN
	T BUG,.INBUG
	T HOG,.INHOG
	INCN==.-INCTAB-1

;Here to include bugs in printout

.INBUG:	NOISE (name)		;HINT AT WHAT THIS DOES
	CALL BUGINI		;INITIALIZE BUGCHK TABLE
	MOVEI A,IBGKEY		;FIND WHAT IS TO BE INCLUDED
	CALL OURCFD
	MOVEI A,(C)		;GET ADDRESS OF FDB PARSED
	CAIN A,IBGKEY		;KEYWORD ENTERED?
	JRST .INCL2		;YES...
				;NO..., HAS TO BE FIELD
	HLRZ D,BIGTAB		;GET NUMBER OF CURRENT BUGS IN TABLE
	ADDI D,1		;+1 TO LOOP FOR ALL
	MOVNS C,D		;MAKE IT NEGATIVE
	MOVEI D,BIGTAB		;ADDRESS OF BUG TABLE
	HRL D,C			;-COUNT,,ADDR IN D FOR LOOP COUNTER
.INCL1:	AOBJP D,[RET]		;BUMP TO NEXT TABLE ENTRY, RETURN WHEN DONE
	HRROI B,ATMBUF		;POINTER TO WILD STRING
	HLRO C,(D)		;GET THIS ENTRY, LH HAS ADDR OF KEYWORD
	ADDI C,1		; BYPASS FLAG WORD
	MOVX A,<.WLSTR>		;WILD STRING FUNCTION CODE
	WILD%			;IS THIS A MATCH?
	TXNE A,WL%NOM
	JRST .INCL1		;NO..., TRY NEXT ENTRY
	MOVEI B,(D)		;MAKE B HAVE ADDRESS OF ENTRY
	CALL .INCL2		;YES..., PUT IT IN TABLE OF IGNORED ENTRIES
	SUBI D,1		;ACCOUNT FOR ENTRY REMOVED
	JRST .INCL1		;TRY NEXT ENTRY

.INCL2:	HLRZ A,BIGTAB		;GET NUMBER OF ENTRIES IN TABLE
	CAIN A,0		;ANY ENTRIES IN TABLE?
	JRST   [TYPE <%No BUG's are currently excluded
>
		RET]
	MOVEI A,BIGTAB		;POINT TO TABLE OF THINGS BEING IGNORED
	TBDEL			;TRY TO DELETE ENTRY
	 ERJMP [HRROI A,[ASCIZ /Could not include BUG: /]
		ESOUT
		CALL GETERR	;SEE WHY FAILED
		HRLI A,.FHSLF
		CALL PERR1	;PRINT ERROR STRING
		RET]
	RET
	
;Show which hogs are excluded

INFHOG:	STKVAR <NN>
	HLRZ A,EXHTAB		;GET NUMBER OF HOGS BEING EXCLUDED
	MOVEM A,NN		;REMEMBER HOW MANY TO PRINT OUT
IH1:	SOSGE A,NN		;ANYMORE?
	RET			;NO, DONE
	TYPE <  EXCLUDE HOG >
	HLRO A,EXHTAB+1(A)	;GET POINTER TO NEXT ONE
	PSOUT			;TYPE THE USER NAME
	TYPE <
>				;FINISH LINE
	JRST IH1		;LOOP FOR REST

;SHOW WHICH BUGCHKS ARE BEING IGNORED

INFBUG:	SKIPN BUGCHF		;DOING BUGCHK REPORTING?
	RET			;NO, SO DON'T TELL ABOUT IGNORED BUGCHKS
	STKVAR <BIGN>
	HLRZ A,BIGTAB		;SEE HOW MANY BEING IGNORED
	MOVEM A,BIGN
	JUMPE A,R		;IF NONE, RETURN NOW
	TYPE <BUG's excluded:>
INFBLP:	SOSGE A,BIGN		;SEE WHICH ONE TO PRINT NEXT
	JRST [	TYPE <
>
		RET]		;PUT END OF LINE AFTER LAST ONE
	TRNN A,3		;START A NEW LINE?
	TYPE <
>				;YES, SINCE LIST MAY BE LONG!
	TYPE <	>		;PUT TAB IN FRONT OF NAME
	HLRZ B,BIGTAB		; GET NUMBER OF ENTRIES
	MOVEI B,BIGTAB+1(B)	; ADDRESS OF LAST
	SUBI B,1(A)		; MINUS CURRENT OFFSET
	HLRO A,(B)		;GET ASCII POINTER TO NAME
	LDB B,[341000,,(A)]	;SEE IF FLAG WORD
	CAIN B,1
	AOJ A,			;YES, SKIP IT
	PSOUT			;TYPE THE NAME
	JRST INFBLP		;DO THE REST.

;ROUTINE TO GET LAST ERROR IN A.

GETERR:	MOVEI A,.FHSLF		;OURSELF
	GETER			;GET ERROR CODE
	HRRZ A,B		;RETURN IN A
	RET

;HOG CONTROL

.EHOG:	NOISE (CHECK FOR USERS RECEIVING SPECIAL SCHEDULER PRIORITY)
	CALL OURCFM
	SETOM HOGF
	RET

HOGSKP:	SKIPN HOGF		;ENABLED?
	RET			;NO
	TYPE <* ENABLE HOG-CHECKING
>
	CALL INFHOG		;SAY WHICH HOGS ARE BEING EXCLUDED
	JRST R2SKP

.DHOG:	CALL OURCFM
	SETZM HOGF
	RET

;HERE TO DISABLE GRUMP-CHECKING

.DGRUM:	CALL OURCFM
	SETZM GRUMPF
	RET

GRUSKP:	SKIPE GRUMPF
	RETSKP			;ENABLED
	RET			;DISABLED

.DMAIL:	CALL OURCFM
	SETZM MAILF
	RET

MALSKP:	SKIPE MAILF
	RETSKP
	RET

;HERE TO ENABLE MAIL-PREVIEWING

.EMAIL:	CALL OURCFM
	SETOM MAILF
	HRROI A,MALSPC		;CREATE FILESPEC FOR MAIL FILE
	MOVE B,LOGNO
	DIRST			;START WITH LOGIN DIRECTORY NAME
	 HRROI A,MALSPC		;SHOULDN'T FAIL, BUT IF DOES, A IS CLOBBERED!
	HRROI B,[ASCIZ /MAIL.TXT.1/]
	MOVEI C,0
	SOUT			;FINISH SPEC
	RET

;HERE TO ENABLE GRUMP-CHECKING

.EGRUM:	CALL OURCFM
	SETOM GRUMPF
	RET

;ENABLE AND DISABLE STATISTICS

.DSTAT:	TDZA A,A		;0 MEANS DISABLE
.ESTAT:	MOVEI A,1		;1 MEANS ENABLE
	STKVAR <ENAF>
	MOVEM A,ENAF		;REMEMBER WHETHER ENABLING OR DISABLING
	NOISE (OF)
	MOVEI A,[FLDDB. .CMKEY,,[	1,,1
					T ALL-FEATURES,0],,<ALL>,[
		 FLDDB. .CMKEY,,STALST]]
	CALL OURCFD		;SEE WHICH THINGS ARE BEING ENABLED
	MOVE B,(B)		;GET TABLE WORD
	TRNN B,-1		;IS IT "ALL"?
	JRST ESALL		;YES
	MOVE B,(B)		;GET FLAGS TO BE TURNED ON OR OFF
	SKIPE ENAF		;ENABLING?
	IORM B,STATF		;SET THE SPECIFIED FLAG
	SKIPN ENAF
	ANDCAM B,STATF		;TURN BIT OFF IF DISABLING
	JRST ES1		;GO MAKE SURE CHARACTER ACTIVATED

ESALL:	MOVEI A,STAN		;PREPARE TO SET ALL FLAGS
ES2:	SOJL A,ES1		;GO TEST CHARACTER IF DONE
	HRRZ B,STALST+1(A)	;GET ADDRESS OF FLAGS
	MOVE B,(B)		;GET FLAGS
	SKIPE ENAF
	IORM B,STATF		;SET OR CLEAR FLAG
	SKIPN ENAF
	ANDCAM B,STATF
	JRST ES2		;DO REST OF FLAGS

;TABLE OF WHAT STATISTICAL INFORMATION CAN BE ENABLED

STALST:	STAN,,STAN
	T FILE-PROGRESS,[IOF]
	T TIME-AND-LOAD,[DATEF]
	T USAGES,[SHAREF]
	STAN==.-STALST-1

;Here after enabling or disabling some statistics feature.  If any
;statistics features are still enabled, assign the interrupt character.
;If none are assigned anymore, disable the flag.

ES1:	SKIPN A,STATF		;ANY FLAGS ON?
	JRST ES3		;NO, GO DISABLE CHARACTER
	MOVE A,[STC,,0]
	ATI			;CALL DTIMER FIRST TO SET UP LSTTIM!
	RET

;Routine to print what's enabled and what's disabled under STATISTICS.

STASKP:	SKIPN A,STATF		;ANY FLAGS SET?
	JRST [	TYPE <* DISABLE STATISTICS-REPORTING (OF) ALL-FEATURES
>
		JRST R2SKP]	;TELL CALLER WE'VE DONE ALL THE WORK
	MOVEI D,STAN		;PREPARE TO SCAN ENTIRE TABLE
STAS1:	SOJL D,R2SKP		;DOUBLE SKIP TO SAY WE'VE DONE THE WORK
	MOVE B,STALST+1(D)	;GET TABLE WORD
	HLRO A,B		;GET POINTER TO STRING
	MOVE B,(B)		;GET BIT IN QUESTION
	TDNE B,STATF		;DECIDE IF FEATURE IS ENABLED
	TYPE <* ENABLE STATISTICS-REPORTING (OF) >
	TDNN B,STATF
	TYPE <  DISABLE STATISTICS-REPORTING (OF) >
	PSOUT			;TYPE OF WHAT!
	TYPE <
>
	JRST STAS1		;DO REST

ES3:	MOVEI A,STC
	DTI
	RET

;HERE TO CONTROL SPY PROTECTION

.ESPY:	CALL OURCFM
	SETOM SPYF
	RET

SPYSKP:	SKIPE SPYF		;SPY CHECKING ENABLED?
	RETSKP			;YES
	RET			;NO

.DSPY:	CALL OURCFM
	SETZM SPYF
	RET

;HERE TO ENABLE AND DISABLE BUGCHK REPORTING

.EBUGC:	CALL OURCFM
	SETOM BUGCHF		;SAY WE'RE ALLOWED TO PRINT BUGCHKS
	RET

BUGSKP:	SKIPE BUGCHF		;DOING BUGCHK REPORTING?
	RETSKP			;YES
	RET			;NO

.DBUGC:	CALL OURCFM
	SETZM BUGCHF		;DON'T REPORT BUGCHKS
	RET

COMLST:	COMLN,,COMLN
	T DISABLE		;DISABLE FEATURES
	T ENABLE		;ENABLE FEATURES
	TA EX			;[NIC] ABBREVIATION
	T EXCLUDE		;EXCLUDE SOMETHING FROM PRINTOUT
.EX:	T EXIT			;EXIT
	T INCLUDE		;INCLUDE SOMETHING IN OUTPUT
	T QUIT			;QUIT COMPLETELY
	T SET			;SET PARAMETERS
	T SHOW
COMLN==.-COMLST-1

SETLST:	SETLN,,SETLN
	T INTERRUPT-CHARACTER,.INTC	;CHANGE ^Y TO SOMETHING ELSE
SETLN==.-SETLST-1

.INTC:	STKVAR <NCHAR,OCHAR>
	NOISE (TO)
	MOVEI A,[FLDDB. .CMTXT,CM%SDH,,<New character for getting to DATE command level>]
	CALL RFIELD		;GET CHARACTER IN ATOM BUFFER
	LDB A,[261600,,ATMBUF]	;GET CHARACTER AND TERMINATING NULL
	TRNE A,177		;MAKE SURE ONLY ONE CHARACTER TYPED
	COMERR <Only single character allowed>
	LSH A,-7		;GET THE CHARACTER ITSELF
	MOVEM A,NCHAR		;REMEMBER NEW CHARACTER
	CALL OURCFM		;MAKE SURE HE MEANS IT
	MOVE A,ICHAR
	MOVEM A,OCHAR		;REMEMBER CHARACTER TO CANCEL
	MOVE A,NCHAR		;SET UP CHARACTER AS NEW ONE
	CALL SETIC
	MOVE A,OCHAR		;CANCEL THE OLD CHARACTER
	DTI
	MOVX D,1B0
	MOVN B,OCHAR		;GET BIT POSITION FOR OLD CHARACTER
	LSH D,(B)
	MOVX A,RT%DIM!.FHSLF
	RTIW			;GET CURRENT SETTINGS
	TDZ C,D			;MAKE OLD CHARACTER NOT DEFERRED ANYMORE
	STIW
	RET

;ROUTINE TO SET UP CHARACTER IN A AS INTERRUPT CHARACTER.

SETIC:	HRL A,A			;PUT CHARACTER IN LEFT HALF
	HRRI A,CTYCHN		;SAY WHICH CHANNEL TO ASSOCIATE IT WITH
	ATI			;TRY TO MAKE THE ASSOCIATION
	 ERCAL [COMERR <Invalid interrupt control-character>]
	HLRZM A,ICHAR		;REMEMBER NEW CHARACTER
	MOVX D,1B0		;SET INTERRUPT CHARACTER TO BE DEFERRED
	MOVN B,ICHAR
	LSH D,(B)		;GET CORRECT BIT
	MOVX A,RT%DIM!.FHSLF	;GET DEFERRED, OURSELF
	RTIW			;READ TERMINAL MASK
	IOR C,D			;INCLUDE NEW CHARACTER IN MASK OF DEFERRED CHARACTERS
	STIW			;TELL THE SYSTEM
	RET

SHOLST:	SHOLN,,SHOLN
	T BUG-STRING,.BUGST	;SHOW TEXT FOR BUG NAME
	T BUGHLTS		;SHOW BUGHLTS SINCE PREVIOUS LOGIN
	T LOGIN-TIME,LOGTIM	;SHOW TIME USER LAST LOGGED IN
	T SETTINGS		;SHOW WHAT'S BEEN SET
	T SYMBOLS		;SHOW SYMBOLS MATCHING PARTICULAR VALUE
	T VALUE			;SHOW VALUE OF SYMBOL
	T WHO'S-USING,.WHO	;SHOW WHO'S USING FILE
SHOLN==.-SHOLST-1

FLBLEN==10			;LENGTH OF FDB

.WHO:	TRVAR <LSTJOB,WJOBZ,<FLBNUM,FLBLEN>,<DEFNUM,3>,NXTWRD,JJFN,ANYFS,JNAM,JTYP,<WHOLE,FILWDS>,WSTK,WJOB,WJCTR,WHLPTR,WJFNZ,WJFN>
	NOISE (FILE)
	SETZM ANYFS		;COUNT HOW MANY FILESPECS PRINTED
	SETOM LSTJOB		;GUARANTEE JOB NUMBER PRINTOUT FIRST TIME
	SETZM CJFNBK		;INITIALIZE JFN BLOCK
	MOVE A,[CJFNBK,,CJFNBK+1]
	BLT A,CJFNBK+CJFNLN-1	;START WITH NOTHING IN THE BLOCK
	MOVX A,.GJALL!GJ%IFG!GJ%OFG	;ALL GENERATIONS (DEFAULT), RECOGNIZE UNTIL WILDCARDS SEEN
	MOVEM A,.GJGEN+CJFNBK
	HRROI A,[ASCIZ /DSK*/]	;MONITOR DEFICIENCY WON'T ALLOW *:
	MOVEM A,.GJDEV+CJFNBK	;DEVICE
	HRROI A,[ASCIZ /*/]	;DEFAULT ALL FIELDS TO WILD
	MOVEM A,.GJDIR+CJFNBK	;DIRECTORY
	MOVEM A,.GJNAM+CJFNBK	;NAME
	MOVEM A,.GJEXT+CJFNBK	;TYPE
	MOVEI A,[FLDDB. .CMFIL]
	CALL RFIELD		;GET FILESPEC
	MOVEM B,WJFN		;REMEMBER JFN
	NOISE (FROM JOB NUMBER)
	MOVEI A,[FLDDB. .CMNUM,CM%SDH,5+5,<Job number to start with>,<0>]
	CALL RFIELD		;READ STARTING JOB NUMBER
	MOVEM B,WJOB		;REMEMBER WHICH JOB TO START WITH
	NOISE (THROUGH JOB NUMBER)
	HRLI A,[FLDDB. .CMNUM,CM%DPP!CM%SDH,5+5,<Highest job number to search>]
	HRRI A,FLBNUM
	BLT A,-1+FLBLEN+FLBNUM	;COPY FDB FOR FIXING
	HRROI A,DEFNUM		;CREATE DEFAULT FOR SECOND ARG
	MOVEM A,.CMDEF+FLBNUM	;STORE DEFAULT POINTER
	MOVEI B,JMAXLN-1		;DEFAULT IS THROUGH ALL POSSIBLE JOBS ON SYSTEM
	MOVEI C,5+5		;DECIMAL NUMBER
	NOUT
	 JSERR
	MOVEI A,FLBNUM		;POINT TO OUR CREATED FDB
	CALL OURCFD		;READ ENDING JOB NUMBER
	MOVEM B,WJOBZ
	CALL GOBSYM		;GET SYMBOLS NEEDED
	 JRST [	HRROI A,[ASCIZ /DATE: Couldn't read monitor symbol definitions/]
		ESOUT
		RET]		;GIVE UP
	MOVEM P,WSTK		;REMEMBER WHERE TO UNWIND STACK TO IF ERROR ON A JFN
WJLUP:	MOVE A,WJOB		;SAY WHICH JOB
	MOVEI B,MAXJFN		;SEE WHICH JFN IS HIGHEST IN USE FOR JOB
	MOVEI C,0		;NO OFFSET
	CALL REDJOB
	 JRST WJDON		;IF CAN'T, SKIP THIS JOB
	MOVEM A,WJFNZ		;REMEMBER HIGHEST JFN IN USE
	MOVEI A,1		;FIRST LEGAL JFN IS 1
	MOVEM A,WJCTR
JJLUP:	MOVE A,WJCTR		;GET JFN WE'RE ON
	CAMLE A,WJFNZ		;MAKE SURE WE HAVEN'T EXCEEDED MAXIMUM JFN IN USE
	JRST WJDON		;YES, SO GO ON TO NEXT JOB
	MOVE A,FILSTS		;SAY WE WANT STATUS
	CALL REDJFN		;READ STATUS FOR THIS JFN
	TXNE A,GS%NAM		;IF NO FILESPEC FOR THIS JFN, SKIP IT
	TXNE A,GS%AST!GS%ASG	;IF WILDCARD JFN OR BEING ASSIGNED, SKIP IT
	JRST WJFD
	MOVEI A,WHOLE		;INITIALIZE POINTER TO ENTIRE FILESPEC
	HRLI A,440700		;MAKE LEGAL BYTE POINTER
	MOVEM A,WHLPTR
	MOVE A,FILDDN
	CALL REDJFN		;GET POINTER TO DEVICE NAME
	HLRZ A,A		;DEVICE POINTER IS IN LEFT HALF
	CALL JSTRING		;GET STRING FOR DEVICE NAME
	MOVEI A,":"
	IDPB A,WHLPTR		;PUT COLON AFTER DEVICE
	MOVEI A,"["		;START OF DIRECTORY
	IDPB A,WHLPTR
	MOVE A,FILDNM
	CALL REDJFN		;GET POINTER TO DIRECTORY
	HLRZ A,A		;POINTER IS IN LEFT HALT
	CALL JSTRING
	MOVEI A,"]"		;END OF DIRECTORY
	IDPB A,WHLPTR
	MOVE A,FILNEN
	CALL REDJFN		;GET POINTERS TO NAME AND EXTENSION
	HLRZM A,JNAM		;STORE POINTER IN JNAM FOR NOW
	HRRZM A,JTYP		;STORE POINTER TO TYPE IN JTYPE
	MOVE A,JNAM		;GET POINTER TO NAME
	CALL JSTRING		;GET NAME
	MOVEI A,"."
	IDPB A,WHLPTR		;PUT DOT AFTER NAME
	MOVE A,JTYP		;GET POINTER TO FILE TYPE
	CALL JSTRING
	MOVEI A,"."
	IDPB A,WHLPTR		;PUT DOT AFTER FILE TYPE
	MOVE A,FILVER
	CALL REDJFN		;READ VERSION NUMBER
	HRRZ B,A		;PUT VERSION WHERE NOUT WANTS IT
	MOVE A,WHLPTR		;GET CURRENT POINTER TO ENTIRE STRING
	MOVEI C,5+5		;CREATE DECIMAL VERSION NUMBER
	NOUT			;WRITE VERSION NUMBER ONTO FILESPEC
	 JSERR			;SHOULDN'T FAIL
	MOVEM A,WHLPTR		;UPDATE POINTER TO CURRENT END OF ENTIRE FILESPEC
	MOVEI A,.CHNUL		;PUT NULL AT END OF FILESPEC
	IDPB A,WHLPTR
	HRROI B,WHOLE		;GET POINTER TO ENTIRE FILESPEC
	MOVX A,GJ%SHT!GJ%OFG	;SHORT FORM GTJFN, PARSE ONLY
	GTJFN			;GET A HANDLE ON THE STRING
	 ERJMP WJFD		;SKIP THIS ONE IF FAILS (WHY SHOULD IT THOUGH?)
	MOVEM A,JJFN		;REMEMBER JFN ON THIS FILESPEC
	MOVEI A,.WLJFN		;COMPARE THIS JFN WITH ONE THE USER TYPED
	MOVE B,WJFN		;GET JFN AND FLAGS THAT USER SUPPLIED
	HRRZ C,JJFN		;GET JFN OF FILE THE JOB IS USING (WITHOUT FLAGS)
	WILD%			;SEE IF THE FILE MATCHES WHAT WE'RE LOOKING FOR
	TXNN A,WL%DEV!WL%DIR!WL%NAM!WL%EXT!WL%GEN	;MAKE SURE ALL FIELDS MATCH
	CALL PJFN		;MATCH, SO PRINT OUT THIS ONE
	HRRZ A,JJFN		;NO FURTHER NEED FOR JFN ON FILESPEC WE JUST LOOKED AT
	RLJFN
	 JSERR			;SHOULDN'T FAIL CLOSING IT
WJFD:	AOS WJCTR		;STEP TO NEXT JFN FOR THIS JOB
	JRST JJLUP		;SEE IF THIS JFN IS INTERESTING

WJDON:	AOS A,WJOB		;GO ON TO NEXT JOB
	CAMG A,WJOBZ		;DONE ALL JOBS YET?
	JRST WJLUP		;NO, GO DO THIS JOB
	HRRZ A,WJFN		;RELEASE JFN USED FOR COMMAND
	RLJFN
	 JSERR			;SHOULDN'T FAIL
	MOVE A,ANYFS		;SAY HOW MANY FILES FOUND
	CALL PDEC
	TYPE < file>
	CAIE B,1
	TYPE <s>
	TYPE < found.
>
	RET			;YES, DONE

;PRINT OUT A GOOD ONE

PJFN:	AOS ANYFS		;COUNT FILESPECS
	MOVE B,WJOB		;PRINT JOB NUMBER
	CAMN B,LSTJOB		;NEW JOB?
	JRST PJ1		;NO, SKIP JOB NUMBER AND NAME
	MOVEM B,LSTJOB		;YES, REMEMBER
	MOVEI A,.PRIOU		;TO PRIMARY OUTPUT
	MOVX C,NO%LFL!FLD(3,NO%COL)!FLD(5+5,NO%RDX)	;LEADING FILLER, 3 COLUMNS, DECIMAL
	NOUT
	 JSERR
	TMSG < >		;SPACE
	MOVE A,B
	CALL GUSER		;GET USER NAME
	 JRST [	TMSG <?>
		JRST PJ1]	;GUY PROBABLY LOGGED OUT
	MOVE B,A
	MOVEI A,.PRIOU
	DIRST			;PRINT USER NAME
	 TMSG <?>		;TYPE QUESTION MARK IF HE LOGGED OUT
PJ1:	MOVEI A,^D25
	CALL GETHER		;GET TO COLUMN 25
	MOVEI A,.PRIOU		;FAILING DIRST MAY HAVE CLOBBER A
	MOVE B,JJFN		;FILESPEC
	MOVEI C,0		;NO SPECIAL BITS
	JFNS
	HRROI B,[ASCIZ /
/]
	SOUT			;END OF LINE
	RET

;ROUTINE TO GET TO COLUMN OF TERMINAL LINE SPECIFIED IN A.

GETHER:	STKVAR <WHERE2>
	MOVEM A,WHERE2		;REMEMBER WHERE WE'RE GOING
GETH1:	MOVEI A,.PRIOU		;PRIMARY OUTPUT
	RFPOS			;SEE WHERE WE ARE NOW
	HRRZ D,B		;REMEMBER COLUMN IN D
	CAMLE D,WHERE2		;MAKE SURE THERE'S SPACE
	JRST [	TMSG <
>				;THERE'S NOT, SO GO TO NEXT LINE
		JRST GETH1]	;TRY AGAIN
	MOVEI B," "
G2:	CAML D,WHERE2		;MORE TO DO?
	RET			;NO, DONE
	BOUT			;YES, TYPE A SPACE
	AOJA D,G2			;LOOP UNTIL WE'RE THERE

;HERE WHEN FAILURE DURING A JFN

JJBAD:	MOVE P,WSTK		;GET OUT OF SUBROUTINE IN WHICH FAILURE OCCURED
	JRST WJFD		;GO ON TO NEXT JFN

;GET CONTENTS OF JFN DATA CELL

REDJFN:	MOVE B,WJCTR		;SEE WHICH JFN WE'RE LOOKING AT
	IMUL B,MLJFN		;COMPENSATE DUE TO SIZE OF JFN BLOCK
	ADD B,A			;GET JSB ADDRESS WE WANT TO READ
	MOVE A,WJOB		;SAY WHICH JOB WE WANT TO LOOK AT
	CALL REDJSB		;READ WORD FROM JSB
	 JRST JJBAD		;FORGET THIS JFN IF FAILS
	RET

;GET PORTION OF FILESPEC

JSTRING:
	MOVEM A,NXTWRD		;REMEMBER ADDRESS OF NEXT WORD OF TEXT
JS1:	AOS B,NXTWRD		;GET ADDRESS CONTAINING NEXT PORTION OF STRING
	MOVE A,WJOB		;SAY WHICH JOB'S JSB TO READ
	CALL REDJSB		;READ WORD FROM JSB
	 JRST JJBAD		;ASSUME JFN NO GOOD IF FAILS
	MOVSI C,-5		;DO AT MOST 5 CHARACTERS
	MOVEI B,.CHCNV		;GET QUOTING CHARACTER
JS2:	ROT A,7		;GET NEXT ASCII CHARACTER
	TRNN A,177		;DONE IF NULL FOUND
	JRST JS3
	IDPB B,WHLPTR		;PUT IN QUOTE IN CASE FUNNY CHARACTER
	IDPB A,WHLPTR		;PUT IN REAL CHARACTER
	AOBJN C,JS2		;LOOP UNLESS ALL FIVE CHARACTERS DONE
	JRST JS1		;NO NULL YET, GO BACK AND GET NEXT WORD

JS3:	RET

;SET PARAMETERS

.SET:	MOVEI A,[FLDDB. .CMKEY,,SETLST]
	JRST SHOW1		;REST LIKE SHOW

;SHOW VARIOUS THINGS IMMEDIATELY

.SHOW:	MOVEI A,[FLDBK. .CMKEY,,SHOLST,,,[BRMSK. FLDB0.,FLDB1.,FLDB2.,FLDB3.,<'>]]
SHOW1:	CALL RFIELD
	MOVE B,(B)
	CALLRET (B)		;DO WHATEVER

.BUGHL:	NOISE (SINCE YOUR PREVIOUS LOGIN)
	CALL OURCFM
	CALLRET PRTHLT		;DO THE WORK

;TABLE OF ENABLABLE FEATURES

ENALST:	ELSTN,,ELSTN
	T BUGCHK-REPORTING,[BUGSKP,,.EBUGC]
	T GRUMP-CHECKING,[GRUSKP,,.EGRUM]
	T HOG-CHECKING,[HOGSKP,,.EHOG]
	T INSTANT-PUSH,[INSSKP,,.EINST]
	T LOGGING,[LOGSKP,,.ELOG]
	T MAIL-PREVIEWING,[MALSKP,,.EMAIL]
	T SPY-PROTECTION,[SPYSKP,,.ESPY]
	T STATISTICS-REPORTING,[STASKP,,.ESTAT]
	T UPDATE-FILE-CHECKING,[UFLSKP,,.EUFIL]
ELSTN==.-ENALST-1

;ROUTINE TO DISPLAY SETTINGS

.SETTI:	CALL OURCFM			;MAKE SURE HE MEANS IT
	STKVAR <NOI,TRA,ENAS>
	HLRZ A,ENALST		;SEE HOW MANY TO DO
	MOVEM A,ENAS
SETLUP:	SOSGE A,ENAS		;MORE ITEMS TO DISPLAY?
	JRST [	CALL INFBUG	;REPORT IGNORED BUGCGHKS
		TYPE <---
>				;SEPARATE LIST FROM NEXT LINE ON TERMINAL
		RET]
	HRRZ B,1+ENALST(A)	;GET ADDRESS CONTAINING CONTROL ADDRESSES
	HLRZ B,(B)		;GET TEST ROUTINE ADDRESS
	MOVEM B,TRA		;REMEMBER IT
	HLRO B,1+ENALST(A)	;GET POINTER TO NAME OF ITEM
	MOVEM B,NOI		;REMEMBER IT
	CALL @TRA		;SKIP IF ITEM ENABLED
	 JRST SETDIS		;DISABLED
	 JRST SETENA		;ENABLED
	 JRST SETLUP		;THE "SKP" ROUTINE DID ALL THE WORK

SETENA:	TYPE <* ENABLE >
	JRST SETFLN		;DO REST OF LINE

SETDIS:	TYPE <  DISABLE >
SETFLN:	MOVE A,NOI		;GET NAME OF ITEM
	PSOUT			;TYPE IT
	TYPE <
>
	JRST SETLUP		;LOOP TO SHOW REST OF SETTINGS

;TABLE OF DISABLABLE FEATURES

DISLST:	DLSTN,,DLSTN
	T BUGCHK-REPORTING,.DBUGC
	T GRUMP-CHECKING,.DGRUM
	T HOG-CHECKING,.DHOG
	T INSTANT-PUSH,.DINST
	T LOGGING,.DLOG
	T MAIL-PREVIEWING,.DMAIL
	T SPY-PROTECTION,.DSPY
	T STATISTICS-REPORTING,.DSTAT
	T UPDATE-FILE-CHECKING,.DUFIL
DLSTN==.-DISLST-1

;DISABLE THINGS

.DISAB:	NOISE (FEATURE)
	MOVEI A,[FLDDB. .CMKEY,,DISLST]
	CALL RFIELD		;SEE WHAT'S BEING DISABLED
	MOVE B,(B)		;GET TABLE WORD
	CALLRET (B)		;DISABLE WHAT HE REQUESTED

;ENABLE VARIOUS FEATURES

.ENABL:	NOISE (FEATURE)
	MOVEI A,[FLDDB. .CMKEY,,ENALST]
	CALL RFIELD
	MOVE B,(B)		;GET TABLE WORD
	MOVE B,(B)		;GET CONTROL WORD
	CALLRET (B)		;DO THE ENABLING

;INITIALIZATION ROUTINE WHICH GENERATES ASCII SYMBOL TABLE

SYMINI:	TRVAR <BLTPTR,WSYM,NSYMS>
	SKIPE SYMF		;HAVE WE ALREADY DONE THIS?
	RET			;YES
	HLRE A,.JBSYM			;GET NEG NUMBER OF WORDS IN SYMBOL TABLE
	ASH A,-1			;DIVIDE BY 2 TO GET NEGATIVE NUMBER OF SYMBOLS
	MOVN A,A			;GET POSITIVE SYMBOLS
	HRRZ P1,A			;REMEMBER HOW MANY SYMBOLS TO DO
	ADDI A,SYMLST+1			;CALCULATE FIRST ADDRESS BEYOND TABLE
	HRRZM A,SYMEND			;MARK BEGINNING OF TEXT SPACE
	MOVEM P1,-1(A)			;START WITH LENGTH 0 TABLE
	HRLI A,-1(A)			;MAKE LEFT HALF OF BLT POINTER
	SUBI A,2			;FINISH BLT POINTER
	MOVEM A,BLTPTR			;REMEMBER IT FOR INSERTING ENTRIES
	MOVEM P1,NSYMS			;REMEMBER NUMBER OF SYMBOLS
	MOVEI A,0			;FIRST DO ALPHABETICS (IDEA IS TO REDUCE TOTAL WORDS MOVED VIA BLT BELOW)
	CALL DOSYMS
	MOVE P1,NSYMS			;RESTORE NUMBER OF SYMBOLS
	MOVEI A,1			;DO SYMBOLS STARTING WITH FUNNY CHARACTERS
	CALL DOSYMS
	HLRZ A,BLTPTR			;GET ADDRESS OF ACTUAL TABLE BEGINNING
	MOVEM A,SYMTAD			;REMEMBER WHERE TABLE BEGINS
	SETOM SYMF		;REMEMBER THAT WE'VE INITIALIZED SYMBOL TABLE
	RET				;DONE

DOSYMS:	MOVEM A,WSYM			;REMEMBER WHETHER DOING FUNNY SYMBOLS
	HRRZ P2,.JBSYM			;GET ADDRESS OF FIRST SYMBOL
SYMLUP:	SOJL P1,R			;LEAVE LOOP WHEN ALL SYMBOLS DONE
	MOVE A,(P2)			;GET NAME OF SYMBOL IN RADIX-50
	TLZ A,740000			;GET RID OF FLAGS
	IDIVI A,50			;FIND FIRST CHARACTER
	JUMPN A,.-1
	MOVE A,WSYM			;0 FOR ALPHABETIC, NON-0 FOR FUNNY
	CAIL B,45			;DOES SYMBOL START WITH DOT, PERCENT ETC.?
	JUMPE A,SYMLP1			;YES, SKIP IF DOING ALPHABETIC.
	CAIGE B,45			;ALPHABETIC?
	JUMPN A,SYMLP1			;YES, SKIP IF DOING FUNNY SYMBOLS
	MOVE A,(P2)			;DOING THE SYMBOL, GET IT AGAIN
	CALL R50TAS			;CHANGE TO ASCII
	DMOVEM A,@SYMEND		;STORE THE ASCII
	HLRZ A,BLTPTR			;GET CURRENT BEGINNING OF TABLE
	HRRO B,SYMEND			;GET POINTER TO NEW STRING
	TBLUK				;SEE WHERE IT GOES
	TXNE B,TL%EXM			;ALREADY IN TABLE?
	JRST SYMLP1			;YES, SKIP IT.
	MOVE D,BLTPTR			;GET BLT POINTER
	BLT D,-2(A)			;MAKE ROOM FOR ENTRY
	MOVE D,BLTPTR
	ADJSP D,-1			;FIX BLT POINTER FOR NEXT TIME
	MOVEM D,BLTPTR
	HRL B,SYMEND			;POINTER TO NAME IN LEFT HALF
	HRRI B,1(P2)			;ADDRESS OF VALUE IN RIGHT HALF
	MOVEM B,-1(A)			;STORE NEW ENTRY IN TABLE
	MOVSI B,1			;CONSTANT TO UPDATE HEADER
	ADDM B,1(D)			;FIX HEADER TO ACCOUNT FOR NEW ENTRY
	AOS SYMEND
	AOS SYMEND			;STEP TO NEXT SLOT FOR NAME
SYMLP1:	ADDI P2,2			;STEP TO NEXT DDT SYMBOL SLOT
	JRST SYMLUP			;DO REST OF SYMBOLS

;ROUTINE CHANGING RADIX50 IN A TO ASCIZ IN A AND B

R50TAS:	TLZ A,740000		;CLEAR JUNK PART
	MOVE D,[440700,,A]	;MAKE ASCIZ POINTER
	CALL R50OUL		;DO THE SYMBOL
	MOVEI C,0		;END WITH NULL
	IDPB C,D
	RET			;DONE

R50OUL:	IDIVI A,50		;GET A DIGIT SPLIT OFF
	JUMPE A,R50FIN		;DONE IF HAVE A ZERO
	HRLM B,(P)		;NO, SAVE THIS DIGIT
	CALL R50OUL		;AND LOOP
	HLRZ B,(P)		;GET BACK SAVED DIGIT
R50FIN:	MOVEI C," "		;IF NOTHING ELSE SET FOR SPACE
	CAIN B,47		;CODE FOR PERCENT SIGN?
	MOVEI C,"%"		;YES, GET IT
	CAIN B,46		;CODE FOR A DOLLAR SIGN?
	MOVEI C,"$"		;YES, GET IT
	CAIN B,45		;CODE FOR A PERIOD?
	MOVEI C,"."		;YES, GET IT
	CAIL B,13		;IN RANGE OF A LETTER?
	CAILE B,44		;WELL?
	SKIPA 			;NO
	MOVEI C,"A"-13(B)	;YES, GET IT
	CAIGE B,13		;FINALLY, IN RANGE OF A NUMBER?
	MOVEI C,"0"-1(B)	;YES, GET IT
	IDPB C,D		;OUTPUT THE CHAR
	RET			;AND RETURN

;ROUTINE TO INITIALIZE TABLE OF BUG STRINGS

BUGINI:	CALL SAVCMD		;SAVE COMND STATE WHICH WE MAY HAVE INTERRUPTED OUT OF
	CALL BUGI0		;DO THE WORK
	CALL RESCMD		;RESTORE COMND STATE
	RET

BUGI0:	STKVAR <BUGJFN,BUGADD,BUGENT,<BUGPCW,2>>
	SKIPE BUGIF		;ALREADY INITIALIZED TABLE?
	RET			;YES, NO NEED TO DO ANYTHING NOW
	MOVEI A,BUGMAX		;GET MAXIMUM ENTRIES
	MOVEM A,BUGTAB		;INITIALIZE TABLE
	MOVEI A,BUGSTR		;GET ADDRESS OF STRING AREA
	MOVEM A,BUGADD		;INITIALIZE STRING ADDRESS
	CALL CMDINI		;INITIALIZE FOR COMND JSYS
	MOVEI A,.NULIO		;FORCE ERROR ON INPUT FROM FILE, AND DON'T DO ANY OUTPUT DURING .CMINI
	MOVEM A,.CMIOJ+SBK
	PROMPT ()		;TYPE NULL PROMPT
	MOVX A,GJ%OLD+GJ%SHT	;OLD, SHORT FORM
	HRROI B,[ASCIZ /SYSTEM:BUGSTRINGS.TXT/]
	GTJFN			;GET HANDLE ON BUGCHKS TABLE
	 JRST NOBUGS		;COULDN'T
	MOVEM A,BUGJFN		;REMEMBER THE JFN
	MOVE B,[70000,,200000]	;ASCII, READ
	OPENF			;OPEN FOR READING
	 JRST NOBUG1
	MOVE B,[2,,.FBBYV]	;WE WANT SIZE PARAMETERS OF FILE
	MOVEI C,BUGPCW		;WHERE TO READ DATA INTO
	GTFDB
	LOAD C,FB%PGC,BUGPCW	;GET PAGE COUNT
	CAILE C,BUGBSZ		;HAVE WE ALLOCATED ENOUGH ROOM FOR IT?
	JRST [	TYPE <%DATE: Not enough room allocated for complete BUG table
>
		MOVEI C,BUGBSZ	;TRIM TO MAXIMUM SIZE WE CAN HANDLE
		JRST .+1]
IFE STANSW,<
	TXO C,PM%PLD!PM%CNT!PM%RD	;PRELOAD, REPEATE COUNT, READ ACCESS
>;IFE STANSW
IFN STANSW,<
	TXO C,PM%PLD!PM%CNT!PM%RD!PM%CPY ;PRELOAD, REPEATE COUNT, READ ACCESS
>;IFN STANSW
	MOVE B,[.FHSLF,,BUGBPN]
	HRLZ A,A		;START MAPPING FROM PAGE 0
	PMAP			;GET THE DATA
	LOAD A,FB%BSZ,BUGPCW	;GET BYTE SIZE OF FILE
	IMUL A,1+BUGPCW		;MULTIPLY BY NUMBER OF BYTES TO GET NUMBER OF BITS
	IDIVI A,7		;GET NUMBER OF ASCII BYTES
	MOVEM A,.CMINC+SBK	;TELL COMND HOW MANY CHARACTERS ARE LEFT TO READ
	HRROI A,BUGBUF		;POINT TO BUFFER OF BUGS
	MOVEM A,.CMBFP+SBK	;SAY COMMAND BUFFER BEGINS THERE
	MOVEM A,.CMPTR+SBK	;NEXT INPUT TO BE PARSED ALSO BEGINS THERE
BUG1:	MOVEI A,[FLDDB. .CMFLD]	;PREPARE TO READ BUGCHK NAME
	CALL RFLDE		;READ IT, SKIP IF SUCCESSFUL
	 JRST BUGEOF		;COULDN'T
	HRRO A,BUGADD		;MAKE POINTER TO WHERE NEXT NAME GOES
	MOVEM A,BUGENT		;REMEMBER THIS ENTRY
	MOVX B,CM%FW		;DECLARE FLAG WORD
	MOVEM B,(A)
	AOJ A,			;LEAVE ROOM FOR FLAG WORD
	HRROI B,ATMBUF		;POINTER TO NAME JUST READ
	MOVEI C,0		;STOP ON NULL
	SOUT			;WRITE THE BUGCHK NAME
	IBP A			;LEAVE NULL AFTER NAME
	AOJ A,			;GET ADDRESS OF WHERE NEXT STRING GOES
	MOVEM A,BUGADD		;REMEMBER NEXT ADDRESS
	MOVEI A,BUGTAB		;POINT TO TABLE
	HRL B,BUGENT		;GET ENTRY
	TBADD			;ADD IT TO TABLE
	MOVEM A,BUGENT		;REMEMBER ADDRESS OF ENTRY
	MOVEI A,[FLDBK. .CMFLD,,,,,[BRMSK. FLDB0.,FLDB1.,FLDB2.,FLDB3.,<[]>]]
	CALL RFIELD		;READ ITEM OF FORM "[FOO]"
IFN STANSW,<
; I DON'T KNOW WHY THIS IS NECESSARY, BECAUSE .CMTXT SHOULD BE SMART.
; BUT IT ISN'T.
	MOVE A,.CMPTR+SBK	;NEXT INPUT TO BE PARSED ALSO BEGINS THERE
BUG699:	ILDB B,A		;GET BYTE OF THIS INPUT
	JUMPE B,BUG69
	CAIE B,.CHCRT
	 CAIN B,.CHLFD
	  JRST BUG69
	CAIE B,"?"		;SCREW CASE?
	 JRST BUG699
	MOVEI B,"."
	DPB B,A
	JRST BUG699

BUG69:
>;IFN STANSW
	MOVEI A,[FLDDB. .CMTXT]
	CALL RFLDE		;READ TEXT OF BUGCHK
	 JRST NOBUG2		;COULDN'T
	HRRO A,BUGADD		;GET ADDRESS FOR STRING
	HRRM A,@BUGENT		;STORE ADDRESS OF TEXT IN RIGHT HALF OF TABLE ENTRY
	HRROI B,ATMBUF		;POINT TO TEXT
	MOVEI C,0		;COPY THE STRING
	SOUT
	IBP A			;KEEP THE NULL
	AOJ A,			;GET NEXT STRING ADDRESS
	MOVEM A,BUGADD
	MOVEI A,[FLDDB. .CMCFM]
	CALL RFLDE		;GET TO NEXT LINE FOR NEXT BUG
	 JRST NOBUG2		;FAILED (MUST BE OTHER TEXT ON THE LINE!)
	JRST BUG1		;LOOP FOR REST OF BUGCHKS

BUGEOF:	HRROI A,-1		;WE WANT TO CLEAR OUR BUFFER
	MOVE B,[.FHSLF,,BUGBPN]
	MOVX C,PM%CNT+BUGBSZ	;CLEAR ENTIRE BUFFER (OTHERWISE CLOSF WILL FAIL)
	PMAP
	MOVE A,BUGJFN		;GET JFN ON BUG FILE
	CLOSF			;CLOSE THE FILE
	 JSERR			;SHOULDN'T FAIL
BUGDON:	SETOM BUGIF		;REMEMBER THAT WE'VE BEEN THROUGH HERE
	RET

NOBUGS:	TYPE <
% DATE: Can't get bugstrings - >
	HRLI A,.FHSLF		;OURSELF, ERROR CODE ALREADY IN A
	CALL PERR1		;SAY WHY
	JRST BUGDON

NOBUG1:	MOVE C,A		;OPENF ERROR CODE IN C
	MOVE A,BUGJFN
	RLJFN			;RELEASE THE JFN WE COULDN'T OPEN
	 JFCL			;IGNORE FAILURE
	MOVE A,C
	JRST NOBUGS		;GO PRINT REASON

NOBUG2:	MOVE A,B		;ERROR IN C
	JRST NOBUGS

;ROUTINE TO SAVE COMND STATE ON THE STACK - NECESSARY WHEN WE WANT
;TO USE COMND JSYS AT SOME LEVEL DEEPER THAN ONE IN WHICH COMND MAY ALREADY
;BE BEING USED

SAVCMD:	POP P,C			;GET RETURN ADDRESS
	HRLI A,CMDBEG		;SAVE COMND JSYS DATABASE, SINCE WE MAY HAVE INTERRUPTED OUT OF OTHER COMND STUFF!
	HRRI A,1(P)
	ADJSP P,CMDLEN		;LEAVE ROOM FOR IT ALL ON THE STACK
	MOVEI B,CMDLEN-1(A)	;CALCULATE END OF AREA INTO WHICH STUFF BEING SAVED
	BLT A,(B)		;SAVE THE COMND STUFF
	JRST (C)		;RETURN

;UNDO THE MESS THAT SAVCMD MADE...

RESCMD:	POP P,B			;GET RETURN ADDRESS
	HRLI A,1-CMDLEN(P)
	HRRI A,CMDBEG
	BLT A,CMDBEG+CMDLEN-1	;RESTORE COMND STORAGE
	ADJSP P,-CMDLEN		;RELEASE STACK STORAGE USED FOR COMND
	JRST (B)		;RETURN

;ROUTINE TO GET A PTY JFN
;returns:	+1		error (probably no PTY's available)
;		+2	A/	pty jfn
;			B/	terminal designator for pty's terminal

GETPTY:	STKVAR <PTYJFN,<DEVNAM,2>,FIRPTY,NUMPTY>
	MOVEI A,.PTYPA
	GETAB
	 ERCAL JSBOMB
	HRRZM A,FIRPTY		;STORE TTY CORRESPONDENCE FOR PTY'S
	HLRZ D,A		;GET NUMBER OF PTY'S
	MOVN D,D		;GET # OF PTYS IN SYSTEM
	HRLZS D
GETPT1:	MOVSI A,600013		;GET PTY DESIGNATOR
	HRRI A,(D)		;TRY TO GET NEXT PTY
	DVCHR			;GET CHARACTERISTICS OF THIS PTY
	TLNN B,(1B5)		;IS IT AVAILABLE?
	  JRST GETPT2		;NO
	MOVE B,A
	HRROI A,DEVNAM		;TURN IT INTO AN ASCII STRING
	DEVST
	  JRST GETPT2
	MOVEI B,":"		;TERMINATED BY A COLON
	IDPB B,A
	MOVEI B,0
	IDPB B,A		;ENDED WITH A 0 BYTE
	MOVSI A,1		;SHORT FORM GTJFN
	HRROI B,DEVNAM
	GTJFN
	  JRST GETPT2		;NOT AVAILABLE
	MOVE B,[7B5+1B19+1B20]	;NOW TRY TO OPEN IT
	MOVEM A,PTYJFN
	OPENF
	  JRST GETPT3		;NOT AVAILABLE
	ADD D,FIRPTY		;TURN PTY UNIT # INTO TTY #
	TRO D,(1B0)		;MAKE LEGAL TERMINAL DESIGNATOR
	HRRZ B,D		;RETURN DESIGNATOR IN B
	RETSKP

GETPT3:	MOVE A,PTYJFN		;RELEASE BAD PTY
	RLJFN			;AND RELEASE IT
	 JSERR
GETPT2:	AOBJN D,GETPT1		;TRY FOR ANOTHER PTY
	RET			;FAILURE RETURN

;ROUTINE TO CALL CFIELD AND THEN RESUME EXEC

OURCFD:	CALL CFIELD
	CALLRET AFTEOL		;RESUME EXEC

;ROUTINE TO FINISH COMMAND, AND RESUME EXEC, SO PROGRAM RUNS WHILE WE
;THINK

OURCFM:	CONFRM			;GET COMMAND CONFIRMATION
	CALLRET AFTEOL		;RESUME EXEC, ETC.

AFTEOL:	SAVEAC <A,B,C,D>	;DON'T CLOBBER WHAT COMND RETURNS
	MOVE A,XFORK		;GET HANDLE ON EXEC
	RFORK			;RESUME IT
	RET

;TABLE WHICH WHEN INDEXED WITH n YIELDS A WORD WITH ONLY BIT n ON.

BITS:	%%X==0
	REPEAT ^D36,<	1B<%%X>
			%%X==%%X+1
			>

;ROUTINES TO BUFFER A STRING.  GIVE IT POINTER TO STRING IN A.
;ROUTINE RETURNS POINTER TO BUFFERED STRING IN A.
;THE STRING ALWAYS BEGINS ON A WORD BOUNDARY.  (SOME CALLERS ASSUME SO!)

BUFFS:	MOVEI B,DICT		;SAY WHERE POOL STARTS
	CALL READNM		;COPY STRING INTO FREE SPACE
	 COMERR <String space exhausted>
	RET

;BUFFF buffers the atom buffer
;
;Returns +1:	A/	pointer to buffered atom

BUFFF:	HRROI A,ATMBUF		;POINT TO THE ATOM
	CALLRET BUFFS		;BUFFER IT AND RETURN

;ROUTINE TAKING A STRING POINTER IN A.  IT COPIES THE STRING TO FREE SPACE
;AND TAKES A SKIP RETURN, YIELDING THE POINTER TO THE STRING IN
;A.  IF NO ROOM FOR THE STRING, A NON-SKIP RETURN IS TAKEN AND CONTENTS
;OF A IS INDETERMINATE
;GIVE IT FREE POOL HEADER ADDRESS IN B

READNM:	STKVAR <FPA,RPTR,NEWPTR>
	MOVEM A,RPTR		;REMEMBER POINTER
	MOVEM B,FPA		;REMEMBER FREE POOL ADDRESS
	CALL BCOUNT		;HOW MANY WORDS IN THIS STRING?
	MOVE B,FPA		;SAY WHICH FREE POOL TO USE
	CALL GETMEM		;GET THAT MANY
	 JRST NOREAD		;COULDN'T, SO TAKE NON-SKIP RETURN
	HRLI B,440700		;MAKE BYTE POINTER TO SPACE OBTAINED
	MOVEM B,NEWPTR		;REMEMBER NEW POINTER
	MOVE A,B
	MOVE B,RPTR		;GET POINTER TO STRING
	MOVEI C,0		;STORE NULL AT END OF STRING
	SOUT			;COPY THE STRING
	MOVE A,NEWPTR		;GET ADDRESS WHERE STRING GOT PUT
	RETSKP			;SUCCESFUL RETURN
NOREAD:	RET			;NO ROOM FOR STRING

;ROUTINE TO GET MEMORY BLOCK.  RETURNS +1 ALWAYS WITH ADDRESS OF BLOCK
;IN A.  GIVE IT NUMBER OF WORDS DESIRED IN A.

GETBUF:	MOVEI B,DICT	;USE CORRECT POOL
	CALL GETMEM	;GET THE MEMORY
	 COMERR <DATE free space exhausted>
	MOVE A,B		;RETURN ADDRESS IN A
	RET

; /GETMEM/ - ROUTINE TO ASSIGN MEMORY AS REQUESTED
; INPUTS:	A - CONTAINS NUMBER OF WORDS WANTED
;		B - FREE SPACE HEADER ADDRESS
; OUTPUTS:	A - NUMBER OF WORDS OBTAINED
;		B - CONTAINS ADDRESS OF WORDS GOTTEN
; RETURNS:	SKIPS IF SUCCESSFUL, NON-SKIP IF NO ROOM

GETMEM:	STKVAR <<SAVSTF,2>,DADR>
	MOVEM B,DADR		;REMEMBER HEADER ADDRESS
GETM2:	MOVE C,B			;REMEMBER WHO POINTS TO CURRENT
	HRRZ B,0(C)		;B IS NOW CURRENT BLOCK
	JUMPE B,R			;IF 0, WE HAVE REACHED END OF THE ROAD
	HLRZ D,0(B)		;GET SIZE OF CURRENT BLOCK
	CAMGE D,A			;IS IT SUFFICIENT FOR REQUEST?
	JRST GETM2			;NO, SO TRY NEXT BLOCK
GETM3:	HRL B,0(B)		;GET LINK OF CURRENT BLOCK
	HLRM B,0(C)		;MAKE PREV LINK BE WHAT WAS OUR LINK
	HRRZS B			;ISOLATE CURRENT BLOCKS ADDRESS
	CAMN D,A			;IS THIS AN EXACT MATCH ON SIZE?
	RETSKP				;SUCCESS, SKIP RETURN
	DMOVEM A,SAVSTF		;SAVE NUMBER OF WORDS AND ADDRESS
	ADD B,A			;GET FIRST WORD TO RETURN
	SUBM D,A			;NUMBER OF WORDS TO RETURN
	MOVE C,DADR		;GET ADDRESS OF CONTROL WORD
	CALL RETMEM		;RETURN THE EXTRA WORDS
	DMOVE A,SAVSTF		;RESTORE NUMBER OF WORDS AND ADDRESS
	RETSKP				;SUCCESS, SKIP RETURN

;STREM ROUTINE TAKES POINTER TO STRING IN A, AND "REMOVES" THE STRING
;FROM THE STRING STORAGE SPACE.  THE SPACE WHERE THE STRING WAS IS
;RETURNED TO FREE SPACE

STREM:	SAVEAC <A,B,C,D>	; NEED TO BE TRANSPARENT
	STKVAR <SPT000>
	MOVEM A,SPT000		;REMEMBER POINTER
	CALL BCOUNT		;COUNT NUMBER OF WORDS IN THE STRING
	HRRZ B,SPT000		;GET RID OF BYTE POINTER P AND S
	CALLRET RETBUF		;RETURN THE BUFFER

;RETBUF RETURNS A BUFFER TO FREE STORAGE
;	A/	SIZE BEING RETURNED
;	B/	ADDRESS OF BLOCK BEING RETURNED

RETBUF:	MOVEI C,DICT		;SAY WHERE FREE SPACE IS
	CALLRET RETMEM		;RETURN THE SPACE TO THE FREE POOL

; /RETMEM/ - ROUTINE TO DE-ALLOCATE MEMORY WHEN WE ARE THROUGH WITH IT
; INPUT:	A - CONTAINS SIZE OF BLOCK TO RETURN
;		B - CONTAINS ADDRESS OF BLOCK BEING RETURNED
;		C - FREE SPACE HEADER ADDRESS
; OUTPUT:	NONE
; RETURNS: ALWAYS CPOPJ
;

RETMEM:	HRRZ D,0(C)		;GET PREV'S LINK
	SKIPE	D			;IF CURRENT IS 0 OR
	CAIL D,0(B)		;  ITS ADDRESS IS PAST ADDR OF RETURN BLK
	JRST RETM4			; THEN RETURN BLOCK HERE
	MOVE C,D			;MAKE PREV=CURRENT
	JRST RETMEM			;CONTINUE

RETM4:	HRRM D,0(B)		;FORWARD PTR OF RETURNED BLOCK
	HRRM B,0(C)		;FORWARD PTR OF PREV BLOCK
	HRLM A,0(B)		;STORE SIZE OF THIS BLOCK
	ADD A,B			;ADD ADDR+SIZE
	CAIE A,0(D)		;ARE WE RIGHT UP AGAINST NEXT BLOCK?
	JRST RETM5			;NO, CANT COMBINE
	HRRZ A,0(D)		;GET NEXT GUYS FORWARD LINK
	HRRM A,0(B)		;MAKE IT OURS. IE POINT PAST HIM
	HLRZ A,0(B)		;GET OUR SIZE
	HLRZ D,0(D)		;GET HIS SIZE
	ADD A,D			;GET OUR NEW COMBINED SIZE
	HRLM A,0(B)		;STORE INTO RETURNED BLOCK
	HRRZ D,0(B)		;GET LINK OF CURRENT BLOCK
RETM5:	HLRZ A,0(C)		;GET PREV BLOCKS SIZE
	ADDI A,0(C)		;ADD HIS ADDRESS AND SIZE
	CAIE A,0(B)		;DOES HE BUTT RIGHT UP AGAINST US?
	RET			;NO, RETURN WITH NO COMBINATION
	HRRM D,0(C)		;MAKE PREV POINT TO OUR NEXT
	HLRZ A,0(C)		;GET HIS SIZE
	HLRZ B,0(B)		;AND OUR SIZE
	ADD A,B			;COMBINE THE SIZES
	HRLM A,0(C)		;STORE COMBINED SIZE
	RET			;RETURN

;ROUTINE TO INITIALIZE FREE SPACE STORAGE.

FREINI:	SETZM DICT		;INITIALIZE FREE SPACE SYSTEM
	MOVEI A,FRESIZ		;FREE UP THIS MUCH FREE SPACE (ALL OF IT!)
	MOVEI B,FREE		;STARTS AT ADDRESS IN B
	CALL RETBUF		;FREE IT UP IN STANDARD WAY
	MOVEI A,STRSIZ		;ALLOCATE SOME SPACE FOR STRINGS
	CALL GETBUF
	HRLI A,440700		;MAKE POINTER TO STRING STORAGE
	MOVEM A,CSBUFP		;REMEMBER POINTER TO STRING STORAGE
	RET

;BCOUNT MEASURES AN ASCIZ STRING.
;
;ACCEPTS:	A/	POINTER (-1,,FOO O.K.!)
;
;RETURNS+1:	A/	NUMBER OF WORDS NEEDED IN A
;		B/	NUMBER OF CHARACTERS

BCOUNT:	CALL FIXPT		;CHANGE -1 TO 440700
	MOVEI B,0		;B WILL ACCUMULATE COUNT OF BYTES
BC1:	ILDB C,A		;READ NEXT BYTE
	CAIE C,0		;DONE COUNTING IF NULL SEEN
	AOJA B,BC1		;NOT DONE, KEEP COUNTING
	MOVE D,B		;REMEMBER EXACT COUNT IN D
	AOJ B,			;LEAVE ROOM FOR NULL
	IDIVI B,5		;GET NUMBER OF WORDS
	CAIE C,0		;EXTRA CHARACTERS?
	AOJ B,			;YES, THEY TAKE A WHOLE WORD
	MOVE A,B
	MOVE B,D		;RETURN BYTE COUNT IN B
	RET

;USE R2SKP TO TAKE DOUBLE SKIP RETURN

R2SKP:	AOS (P)
	RETSKP

;ROUTINE WHICH RUNS AS LOWER FORK TO OUTPUT DATA TO TERMINAL THAT'S
;BEEN BUFFERED UP.  IF THE TERMINAL OUTPUT EVER CATCHES UP WITH THE
;OUTPUT BUFFER POINTER, THE POINTER IS RESET TO THE BEGINNING OF THE
;BUFFER
;THE PURPOSE OF USING ANOTHER FORK IS SO THAT WE DON'T LOSE ANY
;INFORMATION DUE TO OUTPUT BEING BLOCKED ON THE TERMINAL
;THIS ROUTINE MUST BE LAST IN THE SOURCE CODE, AND CONTIGUOUSLY FOLLOWED
;BY .REQUIRE SYS:MACREL

SPILL:	TRVAR <CHRCNT,CAFTER>
	CALL TTYLCX		;DON'T ACCEPT MORE OUTPUT UNTIL WE TALLY.
SPILL1:	MOVE A,TTYPNT
	MOVE B,MIDPNT		;GET POINTER TO BEGINNING OF OUTPUT
	CALL SUBBP		;FIGURE HOW MANY CHARACTERS TO OUTPUT
	MOVNM A,CHRCNT		;REMEMBER NEGATIVE NUMBER TO PRINT
	CALL TTYUL1		;DON'T LEAVE TERMINAL LOCKED.  MORE OUTPUT MIGHT COME WHILE WE'RE IN ^Q-WAIT
	SETZM CAFTER		;NO ESCAPE CODES SEEN YET
SMORE:	MOVE A,MIDPNT		;GET POINTER TO DATA
	CALL FIXPT		;MAKE SURE IT'S A REAL BYTE POINTER
	MOVE B,CHRCNT		;GET NEGATIVE CHARACTER COUNT
SMO1:	AOJG B,SMO2		;LEAVE LOOP IF EVERYTHING SCANNED
	ILDB C,A		;AT LEAST ONE MORE CHARACTER, LOOK AT IT
	CAIE C,SPLESC		;ESCAPE CODE?
	JRST SMO1		;NO, KEEP LOOKING
	AOJG B,SMO2		;YES, MAKE SURE THERE'S ANOTHER CHARACTER AFTER IT
	ILDB C,A		;YES, SEE WHAT THE NEXT CHARACTER IS
	CAIE C,"*"		;SPECIAL DIRECTIVE?
	JRST SMO1		;NO, KEEP LOOKING
	MOVEM B,CAFTER		;REMEMBER COUNT TO USE AFTER ESCAPE SEQUENCE
	SUB B,CHRCNT		;GET NUMBER OF CHARACTERS WE SCANNED
	SUBI B,2		;DON'T PRINT ESCAPE OR CODE
	MOVNM B,CHRCNT		;SET UP COUNT FOR FIRST SECTION OF TEXT
SMO2:	SKIPN CHRCNT		;ANYTHING TO PRINT
	JRST SMO3		;NO.  SOUT GOES BONKERS WITH 0-LENGTH!
	SKIPE LOGGF		;LOGGING?
	CALL SPLOG		;YES, DO IT.
	MOVEI A,.PRIOU		;USE PRIMARY OUTPUT
	MOVE B,MIDPNT		;GET PLACE TO START OUTPUTTING FROM
	MOVE C,CHRCNT		;GET NEGATIVE NUMBER OF CHARS
	DOBE			;TRY NOT TO INTERFERE WITH OTHER OUTPUT
	SOUT			;TYPE THEM (MIGHT HANG FOR AWHILE)
	MOVEM B,MIDPNT		;SAVE POINTER SHOWING HOW MUCH WE OUTPUT
SMO3:	SKIPE A,CAFTER		;IS THERE AN ESCAPE CODE?
	JRST [	MOVEM A,CHRCNT	;YES, SET UP NEW COUNT
		CALL OURHOM	;DO THE ESCAPE CODE
		IBP MIDPNT	;DON'T DISPLAY THE ESCAPE SEQUENCE
		IBP MIDPNT
		SETZM CAFTER	;NO MORE ESCAPE CODES SEEN YET
		JRST SMORE]	;GO CHECK FOR MORE ESCAPE CODES
	CALL TTYLCX		;LOCK OUTPUT SO NONE HAPPENS
	MOVE A,TTYPNT		;GET POINTER TO LAST CHAR IN BUFFER
	CAME A,MIDPNT		;DID MORE COME IN DURING THE SOUT?
	JRST SPILL1		;YES, GO BACK AND CONTINUE EMPTYING BUFFER
SPILL3:	HALTF			;HALT TO SIGNAL THAT WE CAN BE FLUSHED NOW

;OURHOM is called to home up during typeout of announcements
;This gives them a chance of being seen even during EMACS editing

OURHOM:	CALL TERCHK		;GET CURRENT TERMINAL TYPE
	SKIPN A,HEIGHT
	JRST OURH1		;DON'T TRY TO GO TO BOTTOM OF 0-LENGTH SCREEN
	MOVEM A,OLDX		;FORCE MOVEMENT
	CALL HOLSCN		;CAUSE WHOLE SCREEN TO BE USED
	MOVEI A,0		;FIRST GET TO BOTTOM OF SCREEN INTERNALLY
	CALL PPOINT
OURH1:
IFN STANSW,<
	MOVEI A,.CHCRT		;DO CR FIRST
	CALL TYO
>;IFN STANSW
	MOVEI A,.CHLFD		;NOW DO LINEFEED TO GET CLEAN LINE
	CALL TYO
	CALLRET FORCE		;MAKE SURE OUTPUT GETS SEEN NOW

;SPLOG UPDATES THE LOG FILE IF LOGGING IS ENABLED

SPLOG:	MOVE A,LOGJFN		;GET CHANNEL ON LOG FILE
	MOVE B,[FLD(7,OF%BSZ)!OF%WR!OF%RD]	;APPEND BUT ALLOW BKJFN
	OPENF			;OPEN THE LOG FILE
	 ERJMP SPLERR		;FAILED, GIVE UP
	HRROI B,-1		;GET TO END OF FILE
	SFPTR
	 ERJMP SPLERC		;FAILED, SO BOMB OUT
	MOVE B,MIDPNT		;GET PLACE TO START OUTPUTTING FROM
	MOVN C,CHRCNT		;GET POSITIVE COUNT TO CATCH BELL
	MOVEI D,.CHBEL		;STOP AFTER BELL
SPSOUT:	SOUT			;WRITE THE DATA
	 ERJMP SPLERC		;FAILED, PROBABLY OVER QUOTA
	LDB D,B			;GET LAST CHARACTER OUTPUT
	CAIN D,.CHBEL		;WAS IT A BELL?
	JRST [	BKJFN		;YES, BACK UP POINTER TO GET RID OF IT
		 ERJMP SPLERC	;COULDN'T BACK UP, SO DIE
		JUMPN C,SPSOUT	;IF MORE TO DO, DO IT
		JRST .+1]
	TXO A,CO%NRJ		;SUCCESSFUL, SO DON'T RELEASE JFN
	CLOSF
	 ERJMP SPLERR		;WHOOPS, THIS CLOSF IS IMPORTANT.
	RET

SPLERC:	TXO A,CO%NRJ		;PREVENT RACE OF SOMEONE ELSE GETTING JFN AND THEN WE RLEASE IT!
	CLOSF			;CLOSE THE FILE
	 JFCL			;CLOSF SHOULDN'T FAIL
SPLERR:	HRROI A,[ASCIZ /DATE: Logging failure - /]
	ESOUT			;START ERROR MESSAGE
	CALL PERR		;FINISH ERROR MESSAGE
	TMSG <Logging being disabled.
>
	SETZM LOGGF		;TURN OFF LOGGING
	MOVE A,LOGJFN
	RLJFN			;RELEASE THE JFN
	 ERJMP .+1		;IGNORE FAILURE.
	RET

DEFINE SCREEN (TABLE)
<
	MOVE D,TRMTYP
	JUMPL D,.+5
	CAIL D,TRMLEN
	JRST .+3
	SKIPE TABLE(D)
	CALL @TABLE(D)
>

TRMLEN==50			;ASSUMED LARGEST NUMBER OF TERMINAL TYPES

DEFINE TERINI (TABNAM)
<
TABNAM:	BLOCK TRMLEN
DEFINE TER (TYPE,ADDRES)
<
	%%Z==.
	RELOC TABNAM+TYPE
	ADDRES
	RELOC %%Z
>>

;DISPLAY CODE...

ALPHA:	CALL TYO
	AOS A,OLDX
	CAML A,WIDTH
	SOS OLDX		;TYPING AT RIGHT MARGIN DOESN'T MOVE CURSOR!
	RET

PPOINT:	HLRZM A,X
	HRRZM A,Y
	MOVE A,X
	MOVEM A,SX		;REMEMBER IT
	MOVE A,Y
	CALL NORMY
	MOVEM B,SY
	MOVE A,OLDX
	MOVEM A,OX
	MOVE A,OLDY
	CALL NORMY
	MOVEM B,OY
	MOVE A,OLDX		;GET WHERE WE ARE NOW
	SUB A,X
	JUMPN A,PP2		;IF NON-0 X DISTANCE, CHECK FOR SPECIAL CASE OF "BACK 2"
	MOVE A,Y		;CORRECT COLUMN, GET ROW
	SUB A,OLDY
	JUMPE A,R		;NOTHING TO DO IF WE'RE AT EXACTLY CORRECT SPOT
	AOJN A,PP1		;DO REGULAR POSITIONING IF LINEFEED ISN'T SUFFICIENT
PP5:	MOVEI A,.CHLFD
	CALL TYO			;GO DOWN A LINE
	CALL FILL		;SOME TERMINALS NEED FILLERS AFTER LINEFEED
	JRST PP3		;GO UPDATE CURRENT POSITION
PP1:	MOVE A,X
	MOVE B,Y
	SCREEN <PNTTAB>
PP3:	MOVE A,X
	MOVEM A,OLDX		;REMEMBER WHERE WE ARE NOW
	MOVE A,Y
	MOVEM A,OLDY
	RET

PP2:	CAIE A,2		;SPECIAL CASE OF BACKSPACING?
	JRST PP4		;NO, MAYBE DROPPING VERTICALLY
	MOVE A,OLDY		;MAYBE, MAKE SURE NOT MOVING VERTICALLY
	SUB A,Y
	JUMPN A,PP1
	MOVEI A,.CHBSP		;YES, JUST BACKSPACE TWO
	CALL TYO
	CALL TYO
	JRST PP3		;GO UPDATE CURRENT POSITION

PP4:	CAIE A,1		;GOING BACK JUST ONE (LIKE FOR DROPPING!)
	JRST PP1		;NO, DO STANDARD STUFF
	MOVE A,OLDY		;YES, SEE IF DROPPING EXACTLY ONE POSITION
	SUB A,Y
	SOJN A,PP1		;GO TO PP1 IF NOT
	MOVEI A,.CHBSP		;BACKSPACE ONE (DUE TO DISPLAYED CHARACTER)
	CALL TYO
	JRST PP5		;FALL INTO CODE THAT DOES LINEFEED

TERINI PNTTAB
	TER .TTV05,DCA
	TER .TTV50,V50PNT
	TER .TTV52,DCA
	TER .TT100,V100PT
IFN STANSW,<
	TER .TTH19,DCA
>;IFN STANSW

V50PNT:	JRST STEPTO

;WHEN STEPPING ACROSS AND DOWN IS BEST...

STEPTO:	MOVE A,SY		;WHAT LINE WE WANT?
	SUB A,OY		;CALCULATE VERTICAL DROP
	CALL V50DWN		;DO DOWN RIGHT NUMBER OF LINES
	MOVE A,SX		;GET POSITION WE WANT ON LINE
	SUB A,OX		;CALCULATE DISTANCE RIGHT TO MOVE
	CALLRET V50RIT		;STEP LEFT APPROPRIATE NUMBER OF SPACES

V50DWN:	JUMPE A,R		;IF 0, WE'RE THERE
	MOVE B,A
	JUMPG A,VDWN		;DOWN IF POSITIVE
ULUP:	MOVEI A,33
	CALL TYO
	MOVEI A,101
	CALL TYO
	AOJL B,ULUP
	RET

VDWN:	MOVEI A,33
	CALL TYO
	MOVEI A,102
	CALL TYO
	SOJG B,VDWN
	RET

V50RIT:	JUMPE A,R		;NOTHING TO DO IF 0
	JUMPG A,V50R2		;IF POSITIVE, REALLY RIGHT
	MOVE B,A		;SAVE NUMBER OR LEFTS
	MOVEI A,10		;BACKSPACE CHARACTER
LLUP:	CALL TYO		;DO A BACKSPACE
	AOJL B,LLUP		;FINISH
	RET

V50R2:	MOVE B,OX		;GET OLD X POSITION
	MOVEI A,11		;GET A TAB
	TRZ B,7
	MOVEI C,0		;TAB COUNTER
TABLUP:	ADDI B,8		;SEE WHERE TAB WOULD BRING US
	CAMLE B,SX		;ROOM FOR SOME MORE TABS?
	JRST CLUP1		;NO
	CALL TYO		;YES, TYPE ONE
	AOJA C,TABLUP		;COUNT TABS AND LOOP FOR POSSIBLY ANOTHER
CLUP1:	SUBI B,8		;WE ADDED ONE TOO MANY 8'S
	CAIN C,0		;DID WE TYPE ANY TABS?
	MOVE B,OX		;NO, SO START WITH OLD POSITION AGAIN
CLUP:	CAML B,SX		;ARE WE WHERE WE WANT TO BE YET?
	JRST CLEND		;YES
	MOVEI A,33		;NO, SPACE OVER
	CALL TYO
	MOVEI A,103
	CALL TYO
	AOJA B,CLUP
CLEND:	RET

;VT100 DIRECT CURSOR ADDRESSING

V100PT:	CALL V100XX		;SEND GARBAGE
	MOVE A,SY		;SAY WHICH LINE
	AOJ A,			;VT100 REGARDS 0 AND 1 BOTH AS TOP LINE
	CALL DISNUM		;DISPLAY NUMBER
	MOVEI A,"		;"		;SEMI-COLON BETWEEN ARGS
	CALL TYO
	MOVE A,SX		;SAY WHICH COLUMN
	CALL DISNUM
	MOVEI A,"H"		;FINISH SEQUENCE
	CALLRET TYO

;DISNUM displays a number
;
;Accepts:	A/	number

DISNUM:	STKVAR <DNPTR>
	MOVE B,A		;NUMBER INTO B
	MOVE A,CSBUFP		;WRITE NUMBER TO SCRATCH SPACE
	MOVEI C,5+5		;DECIMAL
	NOUT
	 JSHLT
	MOVE A,CSBUFP		;RESET POINTER TO NUMBER
	MOVEM A,DNPTR		;REMEMBER POINTER
DISNLP:	ILDB A,DNPTR		;GET NEXT CHARACTER OF NUMBER
	JUMPE A,R		;NULL MEANS END OF NUMBER
	CALL TYO		;TYPE A DIGIT
	JRST DISNLP		;DO REST OF NUMBER

;THIS ROUTINE FOR TERMINALS THAT ARE CAPABLE OF DIRECT CURSOR ADDRESSING

DCA:	MOVE A,SY
	CALL DISY
	MOVE A,SX
	CALL DISX
	RET

;NORMALIZE POINT FROM QUADRANT 1 TO FUNNY SCREEN SYSTEM (Q4)

NORMY:	MOVE B,HEIGHT
	SUBI B,1(A)
	RET

DEFINE NUM(X,Y)
<
	TER X,[	MOVEI C,Y
		RET]
>
;DEFAULT NUMBER OF LINES

TERINI DEFLEN
	NUM .TTV05,^D20
	NUM .TTV50,^D12
	NUM .TTV52,^D24
	NUM .TT100,^D24
IFN STANSW,<
	NUM .TTH19,^D24
>;IFN STANSW

DISX:	CALLRET DOX

DOX:	ADDI A,40
	CALLRET TYO		;GO TO X COORDINATE

DISY:	PUSH P,A		;SAVE COORDINATE
	CALL ESCAPE		;ESCAPE SEQUENCE
	POP P,A			;RESTORE COORDINATE
	ADDI A,40
	CALL TYO		;GO TO COORDINATE
	CALLRET FILL		;PUT IN FILLERS

ESCAPE:	SCREEN <ESC1>		;DO APPRORIATE ESCAPE SEQUENCE FOR TERMINAL
	RET

TERINI ESC1
	TER .TTV05,V05ESC
	TER .TTV52,V52ESC
IFN STANSW,<
	TER .TTH19,V52ESC
>;IFN STANSW

;ESCAPE SEQUENCE FOR VT52 DIRECT CURSOR ADDRESSING

V52ESC:	MOVEI A,33
	CALL TYO
	MOVEI A,"Y"
	CALLRET TYO

;ESCAPE SEQUENCE FOR VT05 DIRECT CURSOR ADDRESSING

V05ESC:	MOVEI A,""		;CURSOR ADDRESSING CHARACTER
	CALLRET TYO		;TYPE IT OUT

FILL:	SCREEN <FILTAB>
	RET

TERINI FILTAB
TER .TTV05,V05FIL
TER .TTG40,G40FIL

V05FIL:	MOVEI A,0
	CALL TYO
	CALL TYO
	CALL TYO
	CALLRET TYO

;GT40 "SEEMS TO" ONLY NEED ONE FILLER AT 9600 BAUD.

G40FIL:	MOVEI A,0
	CALLRET TYO

;HOLSCN causes the whole screen to be the scrolling region

HOLSCN:	SCREEN <HOLTAB>
	RET

V100HL:	CALL V100XX		;STANDARD VT100 ESCAPE SEQUENCE
	MOVEI A,"r"		;SAY WE'RE SETTING SCROLLING REGION
	CALLRET TYO

CLRSCN:	CALL HOME		;HOME UP
	CALL EOS		;CLEAR TO END OF SCREEN
	CALLRET FORCE		;FORCE THE CLEARING TO BE SEEN IMMEDIATELY

HOME:	SETZM OLDX
	MOVEI A,0		;SCREEN Y-COORDINATE 0
	CALL NORMY
	MOVEM B,OLDY
	MOVE A,TTYJFN
	MOVEI B,0
	SFPOS			;TELL SYSTEM WHERE WE ARE
	SCREEN <HOMTAB>
	RET

V05HOM:	MOVEI A,""		;HOMEUP CHARACTER
	CALL TYO
	CALLRET FILL

V100HM:	CALL V100XX
	MOVEI A,"H"
	CALLRET TYO

V50HOM:	MOVEI A,33
	CALL TYO
	MOVEI A,110
	CALLRET TYO

V50EOS:	MOVEI A,33
	CALL TYO
	MOVEI A,112
	CALLRET TYO

EOS:	SCREEN <EOSTAB>		;DISPATCH TO APPROPRIATE ROUTINE
	RET

TERINI EOSTAB
	TER .TTV05,V05EOS
	TER .TTV50,V50EOS
	TER .TTV52,V50EOS
	TER .TT100,V100ES
IFN STANSW,<
	TER .TTH19,V50EOS
>;IFN STANSW

TERINI HOLTAB			;Make entire screen be scrolling region
	TER .TT100,V100HL

TERINI HOMTAB
	TER .TTV05,V05HOM
	TER .TTV50,V50HOM
	TER .TTV52,V50HOM
	TER .TT100,V100HM
IFN STANSW,<
	TER .TTH19,V50HOM
>;IFN STANSW

V100ES:	CALL V100XX
	MOVEI A,"J"
	CALLRET TYO

V100XX:	MOVEI A,""
	CALL TYO
	MOVEI A,"["			;SEND VT100 ESCAPE SEQUENCE
	CALLRET TYO

V05EOS:	MOVEI A,""		;END OF SCREEN CHARACTER
	CALL TYO
	CALLRET FILL

TYO:	SAVEAC <A,B,C>		;DON'T CLOBBER CHARACTER
	STKVAR <THECHR>
	MOVEM A,THECHR		;SAVE THE CHARACTER
	SKIPG BROOM		;ROOM IN BUFFER FOR ANOTHER CHARACTER?
	CALL FORCE		;NO, FORCE OUT THE BUFFER
	MOVE A,THECHR
	IDPB A,BPTR		;STORE CHARACTER IN BUFFER
	SOS BROOM		;SAY THERE'S LESS ROOM NOW
	RET			;ALL DONE

;ROUTINE TO FORCE BUFFERED OUTPUT OUT

FORCE:	MOVE A,TTYJFN		;NO, GET OUTPUT CHANNEL
	HRROI B,BUFFER		;POINT TO OUTPUT BUFFER
	MOVNI C,NBCHARS		;GET EXACT NUMBER OF CHARACTERS TO SEND
	ADD C,BROOM		;ADJUST COUNT FOR EXACTLY WHAT'S IN IN BUFFER
	CAIE C,0		;0 ISN'T 0 TO SOUT!
	SOUT			;WRITE THE CHARACTERS AS SO FAR
FRESET:	MOVEI C,NBCHARS		;RESET BUFFER COUNT
	MOVEM C,BROOM
	MOVE A,[440700,,BUFFER]
	MOVEM A,BPTR		;RESET BUFFER POINTER
	RET

.REQUIRE SYS:MACREL		;MUST BE LAST FOR PMAP OF TTYFRK
END <3,,[	JRST BEG	;START ADDRESS IS BEG
		JRST BEG	;NO SPECIAL REENTER, JUST START FOR NOW
		%%LH,,%%RH]>	;VERSION NUMBER