Google
 

Trailing-Edge - PDP-10 Archives - BB-X116A-BB_1984 - nrt.mac
There are 4 other files named nrt.mac in the archive. Click here to see a list.
	TITLE	NRT - DECnet Intersystem Remote Terminal service
	SUBTTL Anthony J. Rizzolo/AJR/VB/WGN/KBY	17-Jun-82
	SUBTTL	Program to talk to 10, 20, RSTS, RSX, or VMS
	SUBTTL	Source Copyright notice

IF2,<
PLM
;+
;.control
;.lm 5.rm 75.autop
;.fig 20
;.center 80;PLM for NRT.MAC
;.nonum
;.page
;.nsl
.lit
COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1984.

Digital Equipment Corporation, Maynard, Massachusetts, U.S.A.

This software is furnished under a license and may be used and copied only
in accordance with the terms of such license and with the inclusion of the
above copyright notice.  This software or any other copies thereof may not
be provided or otherwise made available to any other person.   No title to
and ownership of the software is hereby transferred.

The information in this software is subject to change  without  notice and
should not be construed as a commitment by Digital Equipment Corporation.

Digital  assumes  no  responsibility  for  the  use  or reliability of its
software on equipment which is not supplied by Digital.
.el .select ;&+-
PLM
;+
;.page
;.nm 1
;.Chapter Introduction
;	This is the PLM for NRT.MAC.  It is intended to document the
;purpose of each section of code in the NRT program.  It is ^&NOT\&
;intended to give the general flow through NRT.  For the general flow,
;the reader is referred to the NRT.MAN file.
;.Chapter Operating System Independent Support
;	This first section of source is to set up all the definitions.
;The following are defined here:
;.list 1
;.le
;UUO and monitor interface symbols
;.le
;Flag bits
;.le
;AC definitions
;.le
;Feature tests
;.le
;Assembly parameters
;.end list
;.hl 1 AC definitions
;	The ACs are defined with two sets of 4: T1 through T4 (the "temporary"
;ACs) and P1 through P4 (the "preserved" ACs).  The names "temporary" and
;"preserved" are somewhat of misnomers, as they are in the monitor, although
;the convention is generally followed.  These are defined as ACs 1-4 and
;ACs 5-10 (octal) respectively.  They may be moved, but should be kept so
;that the T ACs are consecutive and the P ACs are also consecutive.  CX,
;defined as AC 11 (octal) is a temporary AC used by macros and a general
;scratch AC.  It is never preserved.  ACs 12 through 16 are used as NSP.
;UUO argument blocks.  Each AC takes its name from the corresponding
;_.NSxxx offset in a NSP. UUO argument block, minus the leading ".".
;These ACs are not considered to be preserved, except NSACH once the
;link is up and running; and only the channel part of it, not the status.
;AC 17 is the pushdown pointer, P.  AC 0 is used for flag bits.
;Bits in AC F are defined with symbols of the form F$xxxx.
;Note that NRT has four sets of ACs:  the "UUO level" ACs, the TTY: service
;ACs, the NSP service ACs, and the timer service ACs.  NRT also has four
;PDLs to correspond to the four AC sets.  Upon entry to each of the interrupt
;service routines, NRT exchanges the current set of ACs for the set which
;is to be used for the current interrupt routine.  Note therefore that interrupt
;routines are ^&NOT\& reentrant.  Note also that AC F is global and is ^&NOT\&
;exchanged as are the other ACs.
;-
MLP
>
	SUBTTL	SEARCHes, et al.

	SEARCH	JOBDAT		;For Job data area locations
	SEARCH	MACTEN		;For DEC-10 Definitions
	SEARCH	UUOSYM		;For UUO definitions
	SEARCH	MACSYM		;For break mask definitions


	;.Requires

	.TEXT "/LOCALS/SYMSEG:HIGH"

	;.Directives

	.DIREC	.XTABM		;Supress tabs from macro expansions
	.DIREC	 FLBLST		;List first line of binary only
	.DIREC	SFCOND		;Supress failing conditionals
	SALL			;Supress all macro expansiosn

	;Defaults and Feature tests


	IFNDEF DEFESC,<DEFESC==.CHCNP>	;Set Default escape character
	IFNDEF	MAXPMR,<MAXPMR==7>	;Maximum number of nodes in PMR string
	IFNDEF	LSTPLM,<LSTPLM==0>	;Don't list the PLM in the source
	IFNDEF	OUTQUO,<OUTQUO==200>	;Number of outstanding output buffers
	IFNDEF FTFUNCTION,<FTFUNCTION==0> ;Don't type out function code
	IFNDEF FTPERF,<FTPERF==0>	;Default to no performance stuff
	IFNDEF FTPMR,<FTPMR==0>		;PMR off.
	IFNDEF	FTDBUG,<FTDBUG==0>	;Special debugging features
	IFNDEF	FTPARANOID,<
		IFE	FTDBUG,<FTPARANOID==0>
		IFN	FTDBUG,<FTPARANOID==-1>
			>		;Special checks
	IFNDEF	FTCROCK,<
		FTCROCK==-1
			>		;Code 'cause other systems don't work
	IFNDEF FTPSECT,<FTPSECT==0>	;PSECTs still lose
	.HIGH.=:400000
	IFE FTPSECT,<TWOSEG .HIGH.>


;Additional stuff:

	IFN	FTPMR,<
		SEARCH		PMR
		.REQUEST	PMR
	>
	IFN	FTPERF,<
		.PRCOM==1		;Comment record in file
		.PRDAT==2		;Data record in file
	>

	;Version Information

	DRTWHO==0		;WHO EDITED LAST
	DRTVER==4		;MAJOR VERSION NUMBER
	DRTMIN==0		;MINOR VERSION NUMBER
	DRTEDT==212		;EDIT NUMBER
	IF2,<
		IFN FTPERF,<PRINTX [NRT - Performance diagnostic tool.]>
		IFN FTPMR,<PRINTX [NRT - Poor Mans Routing (PMR) code.]>
	> ;End IF2

	LOC	<.JBVER>	;GO TO THE VERSION NUMBER
	VRSN.	DRT		;ASSEMBLE IN THE VERSION NUMBER


	PURGE	DRTWHO, DRTVER, DRTMIN, DRTEDT

IFE FTPSECT,<RELOC	.HIGH.>
IFN FTPSECT,<.PSECT	.HIGH.>	;Hiseg starts here
	SUBTTL Revision History

COMMENT	|

7	Fix TECO to VMS.

10	Re-add character queing for VMS.  This is because VMS
	does not respond rapidly to ^C and does not in fact 
	allow any characters to be input until a read QIO is
	recieved.  When we recieve a Read QIO, set a new flag
	F$RQIO (This was better than using the fact that we had
	a Message ID that was non zero.  Also clear the flag
	when we send the message out.  Also fix a problem with
	VMS <CRLF> so that it does not mess up and delete a line 
	feed when it shouldn't be.

11	Fix problem with when you ^C out of the prompt routine.
	It will now call the TTYRST routine to reset the TTY
	parameters to there saved values at start up.

12	Fix the routine ECHON, so that it uses the right registers.
	It was doing the GETLCH in CX and the SETLCH on T1.  My
	Fault about that.  Also remove code to set the Terminal type
	As it is no longer neccesary.

13	Add a CLRBFI at the exit (NSPER1) from the error routine
	so that user type ahead is not seen by the -10.

14	?

15	Fix a problem with local links hanging during the config message
	transmission.  This is because on local links it is possible
	for the link to already have data.  In this case the hiber did not 
	wake up.  So you must check the status of the link to see if there
	is valid data available.  If there is, just read it and don't sleep,
	If there is none, then HIBER until we are awakened.

16	Fix a problem with NRT hanging because when GETCFG does not
	have enough data it used to skip return to the calling routine.  Now,
	it should just loop back to GETCFG and wait for all the data to 
	become available.

17	Fix a problem in using the TO command.

20	Restructure program to be PSI driven as much as possible.
	Implement output buffer queueing to the network to prevent
	infinite loops waiting for network I/O.  Restructure the
	VMS support to fix various problems with ^C, ^Z, etc.
	Implement the new VMS 3.0+ protocol.  Fix various problems
	with carriage control to VMS.  Implement usage of the
	break mask feature for VMS.  Version 3A(20).

21	Fix ^C/^Y loops if VAX doesn't respond before user types
	another character (we'd keep finding it as a special character
	but never could send the AST because it really wasn't special
	any more as the ASTs are one-time enables and the VAX hadn't
	reset them).  Partially fix character drops on 10/20 seemingly
	caused by not retrying the OUT immediately after it fails.

22	Restructure RSX section.  Fix a few minor bugs in VMS; in
	particular change the free line feed logic to not give such
	if the terminal is no-echo and no prompt is given, or
	if there is a <LF> anywhere in the last write operation.
	Implement broadcast mailboxes for VMS.  Fix bugs in setting
	second characteristics word for VMS.  Fix sending extra
	zero length data messages to 10/20 which at best is clogs up
	the network line and at worst really confuses PSTHRU tasks.
	Version 3B(22).

23	Repair RSTS code.  Fix MONITO so it doesn't reset the TTY:
	status until after typing out messages.  This prevents user
	from messing himself up with CCONT.

24	Update version number to reflect new code.  Fix command scanner so
	that it doesn't wait forever for a node name to be typed.
	Implement escape sequence processing (VMS).  Fix routine
	handling PMR NAKs so that it doesn't get an illegal UUO.
	Fix sending null messages to VMS on a BROADCAST if no broadcast
	mailbox is enabled.
	Version 4(24).

25	Implement minimal SWITCH.INI support and EXPERT mode.

26	Implement automatic Poor Man's Routing (under FTPMR) which
	will use file DNHOST.TXT on SYS:.

27	Implement /MODE:NOTIFY and make /MODE:EXPERT not beep terminal
	on entering command mode.  Make either of those be in character mode
	and also accept the break character twice as equivalent to the "P"
	command.  Fix certain SETLCHable bits getting turned off caused by
	not giving GETLCH a line number.

30	Implement ^X to RSX.  Fix ^X to VMS not to echo ^U unless
	in input wait.

31	Do fancier rubouts when possible.

32	Implement segment size code for slow terminals

33	Make independent AC sets and PDLs for each level.  This is implemented
	so that if the network gets sick, you can't get stuck on a blocking
	input (since you are in EW at PSI level, you cannot get the
	break character through at this point).

34	VMS sometimes sends (at least) BROADCAST messages with identifiers
	of zero or some which come out negative.  We used to use negative
	ones to indicate that the message had already been ACKd; that is
	no longer necessary so just remove the crock.  In the case of
	zero, just don't ACK the message.  VMS.AK does this anyway; VMS.BC
	does it's ACKing by hand and should do likewise (until we understand
	this problem better).

35	Fix up the performance analysis tool.

36	Make NRT more resistant to running out of output buffer room:
	implement to queue an incomplete buffer without EOM.

37	Fix RSX unsolicited input:  it is not supposed to take effect if
	the terminal is "attached" (in the RSX sense).

40	Implement FTCROCK for that code which has to be in because
	other operating systems don't behave as expected.  This is
	currently for RSX11, which will hang if the monitor ever
	tells the link to turn off.  The FTCROCK code sets the
	goal to 0 so that we don't do optimistic buffering and won't
	ever turn the link ff.

41	Implement F$USRV:  "UUO level" service.  This makes it so
	that spurious wakeups to the main level don't force us into
	TTY: service.  May be required if SCNSER doesn't get fixed
	correctly to handle some deferred echo bugs.

42	For FTPMR on, make PMR use device DCN: instead of SYS: so
	it is a little harder to get automatic PMR as we don't support it.

43	Implement doing VMS free line feeds more correctly:  use flag
	F$CLF (Cancel Line Feed) if ending an echoing read line with <CR>
	then echo as <CR><LF> and eat the "free" line feed (explicit or
	implied) in the next read.

44	Begin implementation of noticing "permanent" characteristics
	for terminals on VAX.  Implementation starts with observing
	no-echo and passall properly.

45	Fix it so we break on each character after part of a buffer has
	been eaten.  This makes ^R, ^U work as advertised correctly after
	a ^T to VAX.  This was caused by the TRMOP. failing due to a zero
	field width.  Make TTYSST more defensive to use a field width
	of one if zero was specified.  Also, make VM.STT maximize the mask
	size rather than ANDIing it so that 1000 doesn't turn into zero.

46	Fix numerous bugs in RSX Read Single Characters mode.  These
	were not able to be tested before due to lack of test case;
	it was found that TECO exercises things to some degree.

47	RSX expects a terminator even if the request is satisfied not
	by terminator, but by character count.  Give him a <NUL> for
	a terminator in those cases.

50	VMS count of lines in postfix/prefix carriage control are
	supposed to be new lines (=<CR><LF>).  They have previously
	been interpreted as <LF> only.  Do only one <CR> as that is
	all that really makes sense.  Also set F$CLF for ^Z to see
	if that eliminates extra <LF>s.

51	VMS ^U/^R broken after ^U after ^T.  We still have the field
	width set to one so all characters get eaten by the prog and,
	although the monitor is doing the ^U, there aren't any characters
	left for it to process.

52	VMS doesn't give a free line feed after a broadcast which ends
	in <CR> iff there is no prompt.  This can cause characters to
	over-write.  This is probably somewhat of a bug in VMS, but
	we will "duplicate" it here since that is a fairly easy thing
	to do anyway.  To fix it "right" requires a lot of interesting
	logic (to prevent you from necessarily getting extra <LF>s) and
	should be done when one knows exactly how VMS has decided it wants
	the line to look in such cases.  Note that there is still a <CR><LF>
	generated by SOS on ^R after ^T.  This should be considered a
	feature rather than bug since it makes the retyped line NOT
	overwrite the ^T output.  This is not, however, what happens
	on a VMS hardwired terminal.

53	VMS actually does give one a zero length read, occasionally.  Right
	now, zero length read gets treated as a length one read so that a
	character gets tossed.  Fix it for VMS and RSX.

54	For TOPS-10/20:  Implement F$EOMN which means never send an EOM
	on a message unless this is the last buffer to be output.  This
	will cause LLINKS to buffer up more characters and use the line
	more efficiently when it is backed up.  If response looks too slow
	for this, we may have to implement a timer or counter to force EOM
	to be sent more frequently.

55	Add a CLRBFI after the MONRT. for prompt dialogue option "M"
	(return to monitor mode leaving link open).  This is so the
	<LF> which seems to get left lying around doesn't confuse things.

56	Try to make RSX <CR><LF>s right.  Do not echo break characters
	even on real read, if read single characters (F$PALL) in effect.
	Echo terminator otherwise, even if no-echo.  Change the default
	break mask to include most control characters.  If
	the request contains no characters but the break the the break
	is not a <CR>, then toss the characters.

57	Make VMS free line feed logic apply to broadcast data too.

60	Fix TTYSST to set <CR> as a break character even if it
	isn't if we are on a system that NEVER wants <CR> to generate
	<CR><LF>.  This is so we don't get an extra <LF>.
	Set the bit for VMS, RSX at initialization.  Don't clear F$CLF
	and F$FLF for VMS after outputting a prompt if the read is for
	zero characters.

61	Phase IV VAXen don't like small seg sizes.  Since it's not
	really important for VAXen anyway (since ^O etc. are handled
	locally), make a subroutine called by TOPS-10/TOPS-20
	(or anyone else that wants to) to affect the link quotas.
	Since one can't change segment size after the link comes up,
	change the percentage of buffers allocated for input.
	size stuff to be a subroutine.  Call only during TOPS-10/TOPS-20
	initialization.  This is where it is needed the most anyway.

62	After processing an out-of-band character for VMS, don't set
	^R, ^U, and <RUB> processing unless there are actually some
	characters in the internal input buffers (i.e. already read).

63	Range check the number of characters in the comment string for
	the performance analysis feature.

64	Update for new format for DNET. UUO.  Clean up code a little;
	get rid of parameter MAXQUE and affiliated variables as they
	are no longer used.  Make /MODE:EXPERT and /MODE:NOTIFY consistent
	even if the help text is typed.

65	Change SWITCH.INI support to us .LKNAM so that switches can
	be abbreviated to uniqueness.  Change .LKNAM and routines
	that call it to use AOBJN pointers instead of IOWDs.  Change
	.LKNAM and routines that use it so that .LKNAM can return
	an offset into the found table entry instead of an absolute
	address.  Tidy up command tables.  Change MONITO to
	use .LKNAM command tables.

66	Add PLM to file.  Make code slightly prettier.  Change
	RET/RETSKP/CALL to POPJ P,/JRST CPOPJ1/PUSHJ P, for consistency
	(no other reason).

67	RSX needs to do rubouts, ^U, and ^R in the special circumstance
	of unsolicited input (due to edit 56).  Make the VMS routines
	general and move them out of the VMS section to the operating
	system independent section.  Implement the required RSX routines
	to use them.

70	RSTS also needs rubout processing if user types break character
	in the middle of a line.  VMS doesn't handle this particular
	case either.  Fix them.

71	Add more table entries to the terminal type and rubout tables.

72	One of the cleanup edits fiddled around with ^C trapping and moved
	the point ^C trapping was actually turned on to before the
	connect was done.  This is bad if we get hung in the connect.  Even
	though we aren't slaved, we are in EW and the monitor won't let us out
	until the UUO finishes.

73	Move the initial turning off of ^C trapping to after label RESTRT
	so if user types "CONTINUE" after an exit, it gets turned off
	correctly.  Move the turning ON of ^C to after slaving the
	user doesn't accidently kill the link after it just gets started up.

74	Somebody (VAXen related) doesn't like NRT to use a Format-1
	block with "Tops-10 NRT-SERVER" as the source block anymore.
	Change it to use Format-0 with the same object (.OBHTH) as
	the destination PDB.

75	Make NSP argument blocks prototypes BLTed to the low segment
	instead of pure.  This is so the PMR can do aliasing correctly.

76	Change EKOBRK to echo printing characters as themselves if not
	in the echo table.  Move range checking of mask width for TRMOP.
	function .TOSBS into TTYSST so it will always get done, instead
	of in VM.STT.  Make VM.COB check for mask to set
	even if the ID=0.

77	Fix control-U putting user into an infinite loop on VMS if it
	is set as a break character in the mask, but F$RALL or F$PALL
	is not set or read physical isn't done.

100	Make VMS write check to see if a read snuck in while we did
	^O so that if satisfying a read request, ^O flag goes off.

101	Change VMS.BC to do a free line feed if not noecho and set F$CLF
	if it had to do one.  This only applies of nothing is done
	previously in VMS.BC to alter the F$FLF/F$CLF settings.  Don't
	change F$FLF/F$CLF on read completion, only after doing prompts
	and stuff if not a zero-length read.

102	Change VAX timeout stuff to empty the chunks into the stream.
	Implement the IO$M_TYPEAHDCNT and IO$M_MODEM modifiers to the
	IO$_SENSMODE functions on the VAX.

103	Implement unsupported functions return for VAX.  Return it for
	IO$_SETMODE with IO$M_MODEM modifiers.

104	Change TTYPSI to not go through buffer allocation if F$FRC is
	on; this can cause characters to be read twice.

105	Change VM.ETI to clear F$NEOM when testing it.  Otherwise, we
	can get into an infinite loop because it thinks there is still
	output to eat, but NSPIN returned because the buffer was full.
	NSPIN won't re-initialize the buffer unless F$NEOM is off.

106	Since VMS has become more tolerant, re-implement the segment
	size code.

107	Trap for ATTACH/DETACH so we can change the UDX and release
	the old TTY: correctly.

110	For "UUO level" service, don't just call TTYPSI with PIs turned
	off.  Instead, trap for WAKE UUOs so we get to PSI level.  This
	is so that we can actually get an ATTACH/DETACH PSI at any
	time it is important, as that is also made to have a higher
	priority.  Make TTY: service wait on output if TTYUDX is
	negative, implying a DETACH was done.

111	Make VMS.KI ACK messages - they actually have non-zero
	REFIDs.  Causes VMS jobs to hang in MWAIT.

112	Make RSX unsolicited input type ahead work right.

113	(VAX) Don't echo type-ahead until it is known the character is not
	a break character.

114	Add copyright notice.

115	Give DOCTR another argument:  a routine to call after outputting
	the "^R<CR><LF>".  This is so that VMS can output the prompt again.
	Pass a zero if there is no routine.

116	Give RSX the prompt stuff of edit 115.

117	Implement flush output routine for TOPS-10/20 to make things
	a little faster.

120	Convert to non-blocking buffer TTY: output so can respond
	to commands faster (make 117 work better).

121	Move clearing of F$FLF and F$CLF yet again to just before
	setting it for last character echoed being a <CR> echoed
	as <CRLF>.  Don't change setting if only stuff read is an
	escape sequen, which is supposed to be invisible.  This
	keeps $SET TERMINAL/INQUIRE on VMS from giving an extra line
	feed.

122	Begin using F$CLF in RSX to prevent double <LF>s in, say, PIP,
	which uses "regular" I/O.

123	Fix ^H to work for RSX and VMS.  It is not a break character nor
	does it perform the function of <RUB>.

124	Make TTYSST wait for output to complete before blasting buffers.

125	Fix VMS Kill I/O once and for all.  The REFID is the REFID of the
	request is to be killed.  If it exists (read request are really only
	relevent here) it should be completed with SS$_ABORT status.  Otherwise
	the Kill I/O is ignored.  The Kill I/O itself is never ACKed.

126	Make typed ahead <RUB> work better - set IO.LEM so the monitor won't
	jump on them for us.  Depending on what the user wants when a request
	actually gets queued, do the "right" thing.

127	Make NSPERR save the function done so that if it does have
	to output it, it won't always come out as .NSFRS.

130	Read/save/transmit the WRAP (complement of the .TONFC) bit for VMS.
	Don't clear it automatically.  Change TTY: type and WRAP bit for
	Set Characteristics/Mode.

131	Implement a number of minor improvements to speed up ^O type things.
	Make DCNPSI check and grant a TTY: input if one is pending before
	looping back to NEWNET.  Make TOOUT defer the out if LDBECC (read
	by TRMOP. function .TOECC) is non-zero so that "echo" will get done
	and we can get input interrupts.

132	Change VMS Unsolicited input to go into character mode if no
	read request is enabled.

133	Make VMS Write Physical actually write things in image mode.

134	Make the RC.CTA function work for RSX Set/Get terminal characteristics.

135	Make ^Q/^S excepted from break masks unless in some flavour of
	passall mode.  In that case, always include them.

136	Make type-ahead echoing and prompt echoing immune to the output
	queue clearing effects of ^O (doesn't affect if it is in the chunks).
	Implement a break (escape) character count instead of the flag.

137	Make "read active shuts off write" for VAX.  This has the problem
	of using too much core if the other side keeps sending.

140	Change HIBER loop in WATOUT to use WAIT UUO.  Put output
	quota on number of buffers which can be queued before the
	program physically will block in TO state.  The number is
	determined by assembly parameter OUTQUO.

141	Change the WAIT back to a HIBER as WAIT seems to cause loss of
	PSI interrupts (WAIT turns of DEVAIO).  Let ^O be done
	by the monitor and try to follow the monitor's bit.

142	Change the connect back to Format 1, object 0, process name
	"TOPS-10 NRT".  Object type 23 is now privileged and VAXen don't
	seem to care again.

143	Make GETCFG able to type out multi-line PMR NAK messages.

144	Re-do handling of special characters for RSX when a Read Single
	is also active.

145	Make VMS and RSX continue scanning if we get an "ignore" return
	from their respective special character handlers.

146	Make ^W always in IMASK (only 10/20s support it and their in PIM).

147	Set correct value for RC.CCT in config message since we are really
	trying to do postfixing.

150	In the check for non-zero LDBECC, check first to see if there
	is a non-zero LDBBKC to prevent hanging while we have a pending
	PSI.

151	Always light IO.ABS in the SETSTS word.  Although it has no effect
	in PIM, it does make .TOSOP skip correctly.

152	Implement $TOICL and $TOOIN for RSX write-breaks-through-read
	vs. those writes which don't.

153	Implement minimal IAS support as a special case of RSX.

154	Change TOHIBR to use SLEEP so pending PSIs don't bother us.
	Set SLPFLG to one (will be AOSEd by TTYDFR) if to be "woken"
	on output done (actually, we just set queue a one tic clock
	request then).

155	Clear F$PALL before calling RX.SPC so things really get done.

156	Break WATOUT into WATDEQ, which waits for all buffers queued for
	output to be output, and WATIDL, which waits for the line to become
	idle.  Call WATOUT only for things like when preceding an ^O bit
	change, or doing a FRCUUO.  Call WATDEQ when all we care about is
	that our buffers are empty.  WATOUT can cause the terminal to
	look hung for 60 seconds if the user is using ^S, since we don't
	get an I/O done interrupt if the user's buffer was empty but
	characters were still in the chunks.  This means the sleep request
	is never cancelled.  **This is a heuristic solution**

157	Don't echo RSTS break characters if no-echoed (obvious!)

160	SETICH sets the count to be greater than or equal to zero
	so the count returned by VMS sense won't be wrong if
	SETICH was negative (a timeout was previously processed).

161	Segment size table forgot about 1800 baud.

162	Change DATPSI to do a SLEEP for zero instead of a WAKE (since
	TOHIBR called by DATPSI uses sleep).  If we really happen to be
	HIBERing, it won't conceptually make a difference.

163	Clear PS.REF in TTYSTS on doing an IN:  it must have been cleared
	by the time we finish an IN UUO.  Causes F$USRV to get stuck
	on otherwise.

164	PJRST TTYSST doesn't necessarily do the right thing:  we may
	not get an interrupt.  Most PJRST TTYSSTs change to
	PUSHJ P,TTYSST followed by PJRST FRCTTI to be sure we see
	the changes correctly.  Ones which are left the same:
	(1) those preceded by a call 	to FRCTTI; (2) those in the
	initialization routines since FRCTTI gets called anyway);
	(3) those that don't change the mask.

165	Occasionally, a TTY: PSI seems to get lost.  The scenario
	involves calling TTYPS1 from network PSI level (this is an
	optimization) so that some TTY: messages can get in over
	long network messages).  However, nothing happens (not really
	an unusual circumstance, since F$USRV just means we should look
	because something unusual MAY have happened) but we do not
	get a PSI when things are done and although the WAKE PSI
	from the original setting of F$USRV isn't set, we don't
	do anything.  Don't clear F$USRV and remember TTYSTS over
	the call, restoring (IORM) the original bits if calling
	at network level.  This means unecessary calls to TTYPS1, but
	is less serious than missed PSIs.  This will hopefully change
	when full support for break masks, character PSIs, and PSI
	on input available is implemented in SCNSER.  The times we loop
	at network level for a flood of network messages should
	be few enough that this has relatively little effect in
	reality.  The NETCHR routine used only for TOPS-10/20 will
	continue to clear the bit as this is not a real problem for
	transparent protocols (typing an additional character will
	force a PSI).

166	Add TTY BLANK to the setup and save characteristics tables;
	setting TTY NO BLANK does interesting things on VMS and RSX
	in particular.

167	Remove edit 165; it doesn't work.  Look for the problem elsewhere.

170	Another possibility for the bug which is the source of the
	last few edits is a change in and out of PIM for image
	mode output.  After changing back via TTYSST, do a .TOSIP
	to kick the terminal and call FRCTTI as well.

171	Fix CHKCTH to use $TOOIN.  Put ^H into IMASK for all VAX requests.

172	Remove edit 170.  The actual problem is in the monitor:  if one
	of the FRCUUOs is done at exactly the right moment, and LDBCMR
	is up when the break count (LDBBKC) gets incremented, then
	PSIIOD doesn't get called.

173	VMS Broadcast really doesn't override ^O.  Remove code to do so.
	Clean up broadcast code in light of this change.

174	Even if in EXPERT or NOTIFY modes, wait for the controlling TTY:
	to go to user level (or detach) before continuing so user can't
	mess himself up with CCONT.  Make DATPSI reset TTY mode to
	ASCII and wait if in monitor mode.

175	Make T10/T20 scan input stream for command character if F$XPT
	is set and the controlling terminal is the same as the I/O terminal.
	This allows ALL command characters to be done correctly in EXPERT
	and NOTIFY modes instead of just the double escape-character
	case.   New entry to MONITO:  MONITC, which allows the character
	to be passed in T3.

176	Change CHKPRM to cancel F$CLF if first character is not a <CR> or
	<LF>.  Shown by NCP SHOW<CR> on the VAX.

177	Light F$ACO when setting VMS out-of-band if ^O is in the mask.
	Shown by EMACS on the VAX.  OR the new bits into IMASK and call
	TTYSST then too.  Note that some old bits might be left over,
	but we know how to handle this anyway.

200	Turn on/off page mode when it changes on the VAX.  EMACS on
	the VAX again.

201	Fix the out-of-band VAX stuff to handle ^S/^Q right; add special
	character routines to handle ^S/^Q if we get them.

202	Fix bug in VMS FORTRAN type carriage control.

203	Change VMS.BC to clear F$CLF and F$FLF if a read request is active
	(actually, present) and then set F$FLF if there is input or a
	prompt present.

204	More free LF bugs:  make CHKPRM parse for ESCAPE sequences
	if F$ESC is set and treat them as "invisible" characters (which
	don't check/affect the settings of F$FLF and F$CLF).

205	Turn on RC.CRT in the RSX configuration mask.  Update for
	new NSP. error code format.

206	Do appropriate things for setting of terminal types for RSX.
	This allows EDT to run on RSX-11.  Still needed:  way to turn
	off auto-crlf.

207	Fix copyrights.

210	Make no lower case default for RSX (that's what the -11 defaults
	to anyway).  Allow SET TERMINAL CHARACTERISTICS to do the TRMOPs
	where possible.

211	Put range checker on OS type we get back so we won't get PC
	Out of Bounds for some system which returns a bum configuration
	message.  Fix comments about what is being checked
	as a PMR NAK.  Note that the code here is slightly different
	than the code in the PMR subroutine.

212	Fix bug in ^U routine DOCTU which causes extra character to be
	erased.

|				;End comment
	SUBTTL	Table of Contents
;               Table of Contents for NRT
;
;
;                        SECTION                                   PAGE
;    1. Program to talk to 10, 20, RSTS, RSX, or VMS..............   1
;    2. Source Copyright notice...................................   1
;    3. SEARCHes, et al...........................................   2
;    4. Revision History..........................................   3
;    5. Table of Contents.........................................   5
;    6. .EXE File Copyright.......................................   5
;    7. AC Definitions............................................   6
;    8. Flag definitions in F.....................................   7
;    9. Operating System (Returned in CONFIG message).............   8
;   10. Constant definitions......................................   9
;   11. Device channel definitions................................  10
;   12. Internal input and output buffer block definitions........  11
;   13. UUO definitions...........................................  12
;   14. MACRO Definitions
;        14.1   PLM MACROs........................................  13
;        14.2   FALL (Address)....................................  14
;        14.3   PJRST(X)..........................................  15
;        14.4   ERR(PRE,MSG)......................................  16
;        14.5   ERRMAC(code,pre,text).............................  17
;        14.6   FCNMAC - Table of NSP. function codes and text....  18
;        14.7   Typeout MACROS....................................  19
;        14.8   AC saving MACROS..................................  20
;        14.9   Break masks.......................................  21
;        14.10  ASSUME............................................  22
;        14.11  NETOCH macro - output character to network........  23
;        14.12  NETALC - Allocate contiguous buffer space.........  24
;        14.13  OSDSP.............................................  25
;        14.14  NAMTAB............................................  26
;        14.15  TRMCHR............................................  27
;        14.16  VTTCHR............................................  28
;        14.17  ASCII8............................................  29
;   15. Start the Program.........................................  30
;   16. LPROMPT - Long Dialogue...................................  31
;   17. PROMPT - Short initialization dialogue....................  32
;   18. Check for Poor Man's Routing in User's String.............  33
;   19. DOPMR - Subroutine to do the Poor mans routine string.....  34
;   20. BLDPMR - Builds the PMR string............................  35
;   21. DOCONN - Initiatiate a DECnet connection..................  36
;   22. MAIN - Main wait loop for all systems.....................  37
;   23. FRCTTY - Force a look at the TTY:.........................  38
;   24. OSJMP - Dispatch table for systems........................  39
;   25. Initialization subroutines
;        25.1   Initialize the Data Base..........................  40
;        25.2   Process RESCAN Input..............................  41
;   26. FNDFNC - Find function routine............................  43
;   27. NETCHR - Output a stream of network data to TTY...........  44
;   28. Exit Routines
;        28.1   MONITO (Exit Dialogue)............................  45
;        28.2   Dispatch Table....................................  46
;        28.3   Help Routine......................................  47
;        28.4   Flush Network Messages............................  48
;        28.5   Return to Monitor.................................  49
;   29. Continue Remote Session...................................  50
;   30. REENTR - REENTR code......................................  51
;   31. Performance analysis
;        31.1   Start session.....................................  52
;        31.2   Start a response measurement......................  53
;        31.3   Record a response.................................  54
;        31.4   End of session....................................  55
;        31.5   Performance string and length.....................  56
;        31.6   Get ASCIZ string (for comment)....................  57
;        31.7   Get character from string.........................  58
;        31.8   Get a decimal number..............................  59
;        31.9   Output a comment to the file......................  60
;        31.10  Output a data record to the file..................  61
;        31.11  Output any record to the file.....................  62
;   32. NETICH - Get a network character from the network buffer..  63
;   33. RBYTEC - Get a byte from the network......................  64
;   34. CONECT - Routine to set up the connection.................  65
;   35. SNDPMR - Send the PMR string to the remote system.........  66
;   36. Error Routines
;        36.1   SETNER - Set up NSPECD with error code............  67
;        36.2   NSPERR - Give an NSP. error message...............  68
;        36.3   DOERR - Output an error message...................  69
;   37. NSPERC - NSP. Error message table.........................  70
;   38. FCNTAB - NSP. function text table.........................  71
;   39. XMTMSG -  Transmit network message........................  72
;   40. TTYOPN - Routine to OPEN the TTY..........................  73
;   41. Routine to set desired TTY: characterstics................  74
;   42. Routine to reset the TTY: characteristics.................  75
;   43. TTY: Output and Echo Routines.............................  76
;   44. Set Horizontal Position...................................  77
;   45. Miscellaneous terminal routines...........................  80
;   46. TTY Input Routines
;        46.1   INCHR - Get terminal character....................  81
;   47. Output SIXBIT argument to controlling TTY:................  82
;   48. Node Name Output Routines.................................  83
;   49. SIXBIT Input..............................................  84
;   50. Scanning Routines
;        50.1   .LKNAM............................................  85
;        50.2   .MKMSK............................................  86
;   51. Memory manglement
;        51.1   Core allocator....................................  87
;        51.2   Core De-allocator.................................  88
;   52. SWITCH.INI support
;        52.1   Read SWITCH.INI...................................  89
;        52.2   Switch handling routines..........................  90
;        52.3   I/O Routines......................................  91
;        52.4   Switch tables.....................................  92
;   53. FILHGH - Prototype FILOP. UUO block.......................  93
;   54. GETCFG - Get the configuration message for the system.....  94
;   55. Compute mask bit & word for ESCCHR........................  95
;   56. Fatal errors in job.......................................  96
;   57. ATTACH/DETACH PSI routine.................................  97
;   58. DECnet interrupt routine..................................  98
;   59. TMR PSI routine...........................................  99
;   60. WAKE PSI Service.......................................... 100
;   61. TTY: PSI Service.......................................... 101
;   62. TTY: Service
;        62.1   Flush all type-ahead.............................. 102
;        62.2   Set Data Mode and Mask............................ 103
;        62.3   Check for line editing............................ 104
;        62.4   Check/Set ^O bit.................................. 105
;        62.5   Wait for output to finish......................... 106
;        62.6   Wait for available buffer......................... 107
;        62.7   Scan input for special characters................. 108
;        62.8   Count number of escape characters................. 109
;        62.9   Input scan routines............................... 110
;        62.10  Check for break character......................... 111
;        62.11  Control-H Routine................................. 112
;        62.12  Escape Sequence processing........................ 113
;        62.13  Escape sequence processing tables................. 114
;        62.14  Echo type-ahead................................... 115
;        62.15  Rubout processing................................. 116
;        62.16  Routine to do display for <RUB>................... 117
;        62.17  Handle Control-U.................................. 118
;        62.18  Handle Control-R.................................. 119
;        62.19  Set to handle ^U, ^R, <RUB>....................... 120
;        62.20  Clear Handling of ^U, ^R, <RUB>................... 121
;   63. PSION/OFF - Turn on/off the software interrupt system..... 122
;   64. NSP. Routines
;        64.1   NSPEA - Make an active connection................. 123
;        64.2   Set Link Quotas................................... 124
;        64.3   NSPIN - NSP. Input routine........................ 125
;        64.4   NSPOUT - Outputs OTPBUF to the network............ 126
;   65. SETNOD - Sets up node name in ASCNOD in the connect block. 128
;   66. SIX2SB - Store SIXBIT T1 in string block pointed to by T2. 129
;   67. INIOBF - Initialize OBUF and IBUF......................... 130
;   68. BPLENG - Compute length of byte pointer in T1............. 131
;   69. Miscellaneous support - Digest a mask..................... 132
;   70. Miscellaneous Support
;        70.1   GET & PUT word routines........................... 133
;   71. Miscellaneous Routines.................................... 134
;   72. Returns................................................... 135
;   73. EXCACS.................................................... 136
;   74. Operating System Specific Support......................... 137
;   75. RSTS Support
;        75.1   Protocol definitions.............................. 138
;        75.2   RSTS network input................................ 139
;        75.3   TTY: input........................................ 140
;        75.4   RST.IN - Initialization Routine................... 141
;        75.5   RST.CT - RSTS control Message..................... 142
;        75.6   RST.DA - Recieve Data message..................... 143
;        75.7   Handle special characters......................... 144
;        75.8   Check Set/Clear of Local ^U/^R/<RUB>.............. 145
;        75.9   Break Echo Table.................................. 146
;   76. RSX Support
;        76.1   Protocol defintions............................... 147
;        76.2   RSX.IN - Initialization........................... 149
;        76.3   Network interrupt................................. 150
;        76.4   TTY: input........................................ 151
;        76.5   NOP function...................................... 154
;        76.6   Set unsolicited characters........................ 155
;        76.7   Kill I/O.......................................... 156
;        76.8   Disconnect link................................... 157
;        76.9   Single character mode............................. 158
;        76.10  ATTACH/DETACH..................................... 159
;        76.11  Get terminal characteristics...................... 160
;        76.12  Set terminal characteristics...................... 161
;        76.13  Read data, Read with prompt....................... 162
;        76.14  Output prompt string.............................. 164
;        76.15  Handle special characters......................... 165
;        76.16  Check about ^U/^R/<RUB> processing................ 166
;        76.17  Count ^Cs......................................... 167
;        76.18  Set TTY: up....................................... 168
;        76.19  handle timed requests............................. 169
;        76.20  Write data........................................ 170
;        76.21  Eat common header................................. 171
;        76.22  Build header for output message................... 172
;        76.23  Queue read request................................ 173
;   77. VMS Support
;        77.1   Protocol definitions.............................. 174
;        77.2   VAX/VMS network input routine..................... 176
;        77.3   VMS TTY: input routine............................ 177
;        77.4   VMS.DA - Recieve VMS data......................... 178
;        77.5   Routine to do carriage control.................... 180
;        77.6   Routine to actually write the record.............. 181
;        77.7   Check to see if REFRESH needed.................... 182
;        77.8   Read and Read with prompt......................... 183
;        77.9   Routine to output prompt.......................... 185
;        77.10  Break echo string table........................... 186
;        77.11  Routine to queue a read request for VMS........... 187
;        77.12  Eat and store common header....................... 188
;        77.13  Handle Control-O.................................. 189
;        77.14  VMS.KI - Kill I/O................................. 190
;        77.15  VMS.AK - Write complete and Acknowledge........... 191
;        77.16  VMS.BH - Build Header............................. 192
;        77.17  VMS.IN - Initialization message................... 193
;        77.18  VM.STM - timed requests........................... 194
;        77.19  Set TTY: up for this read......................... 195
;        77.20  Set Unsolicited mode.............................. 196
;        77.21  Set CHRTAB........................................ 197
;        77.22  Handle special characters......................... 198
;        77.23  VMS.AT - Send Attention........................... 199
;        77.24  VMS.ST - Set characteristics/mode................. 200
;        77.25  VMS.NI - Unsolicited Data Message................. 201
;        77.26  Checkout-of-band character........................ 202
;        77.27  Check ^R, ^U, and <RUB>........................... 203
;        77.28  Out-of-band ATTN.................................. 204
;        77.29  VMS.BC - Broadcast data........................... 205
;        77.30  VMS.SN - Sense Mode message....................... 206
;        77.31  Return unsupported................................ 207
;   78. TOPS-10/20 support
;        78.1   Network service................................... 208
;        78.2   TTY: service...................................... 209
;        78.3   Timer service..................................... 210
;        78.4   Initialization.................................... 211
;   79. Unsupported System support................................ 212
;   80. O/S Name table............................................ 213
;   81. Protocal Dispatch Blocks
;        81.1   RSTS.............................................. 214
;        81.2   RSX............................................... 215
;        81.3   VMS............................................... 216
;   82. Lowseg Initializers Stored in Hiseg....................... 217
;   83. NSP. Connect Block........................................ 218
;   84. Special stuff for VAX..................................... 222
;   85. Special stuff for RSX..................................... 223
;   86. Useful break masks........................................ 224
;   87. Terminal information tables............................... 225
;   88. Terminal strings for <RUB>................................ 226
;   89. Literal storage........................................... 227
;   90. STORAGE................................................... 228
;   91. NSP. UUO DSTPDB Block..................................... 230
;   92. Configuration & Control Messages.......................... 231
;   93. Performance analysis low segment.......................... 232
;   94. Low segment for Interrupt system.......................... 233
;   95. .JBINT stuff.............................................. 234
;   96. Data base for timed I/O requests.......................... 235
;   97. Low segment for core manager.............................. 236
;   98. Low segment AC blocks and PDLs............................ 237
;   99. End of Program............................................ 238
	SUBTTL	.EXE File Copyright

COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1984.
	SUBTTL	AC Definitions



	F=0			;Flag register

	T1=1			;THE TEMPS
	T2=2
	T3=3
	T4=4

	P1=5			;THE (NEVER) PRESERVED
	P2=6
	P3=7
	P4=10


	CX==11			;SCRATCH AC
			

;The following ACS are for use with NSP. argument blocks.

	NSAFN=12		;Function Type
	NSACH=13		;Channel Number
	NSAA1=14		;First argument word
	NSAA2=15		;Second argument word
	NSAA3=16		;Third argument word

	P=17			;STACK POINTER
	SUBTTL Flag definitions in F

	F$IOQ==1B0	;Inhibit queueing of output buffers
	F$UAST==1B1	;User wants unsolicted input
	F$NEC==1B2	;No-echo
	F$LEM==1B3	;(VMS) Nofilter=set IO.LEM
	F$ESC==1B4	;User wants escape sequence processing (VMS, RSX)
	F$ESA==1B5	;Escape sequence being processed
	F$PIM==1B6	;Set TTY: to PIM mode
	F$XPT==1B7	;EXPerT mode
	F$IEC==1B8	;Ignore LDBECC at TOOUT
	F$NEOM==1B9	;Not EOM on NSP.
	F$PERF==1B10	;We are doing a performance test
	F$PION==1B11	;PSISER is on
	F$BRK==1B12	;Saw a break character (SCNSPC)
	F$CTO==1B13	;Control-O in effect
	F$P2==1B14	;General PASS2 flag (core allocator, SCNLCH)
	F$CAST==1B15	;VMS user wants to see ^C
	F$YAST==1B16	;VMS user wants to see ^Y
	F$READ==1B17	;Read request outstanding (mostly VMS)
	F$TMR==1B18	;Timeout active (RSX)
	F$PALL==1B19	;Passall (even if in line mode)
	F$RALL==1B20	;Temporary passall (READALL, VMS)
	F$FLF==1B21	;(VMS)Free <LF> may be needed
	F$ICO==1B22	;Ignore setting of ^O bit (one time)
	F$RUB==1B23	;I need to process rubout,^R, and ^U
	F$ACO==1B24	;Allow ^O in mask (for RSTS)
	F$TEX==1B25	;Timeout expired (RSX)
	F$SCM==1B26	;(RSX) Single character mode
	F$CVL==1B27	;Temporary CVTLOW.  **MUST=VAX CVTLOW**
	F$BAD==1B28	;Terminating due to bad escape sequence
	F$NDB==1B29	;Don't do a DEBRK. (TTY: service)
	F$USRV==1B30	;TTY service call requested at non-PSI level
	F$CLF==1B31	;(VMS, RSX) Free <LF> already given
	F$EOMN==1B32	;(T10/20) Don't put EOM except on last message
	F$RU1==1B33	;First time through unsolicited code (after request
			;is enabled)
	F$NLF==1B34	;Don't allow extra <LF> on <CR> to be generated
	F$FRC==1B35	;TTY: service wants to be called even if no chars
	SUBTTL Operating System (Returned in CONFIG message)

	OST10==11		;TOPS-10
	OST20==10		;TOPS-20
	OSVMS==7		;VAX/VMS
	OSRST==2		;RSTS
	OS11M==4		;RSX-11M
	OSIAS==6		;IAS
	MAXOS==11		;Maximum value for an OS type

	SUBTTL Constant definitions

	PDLLEN==100		;STACK LENGTH
	TTBFSZ==100		;TTY OUTPUT BUFFER SIZE.
	SUBTTL Device channel definitions


	$TTY==6			;Devices
	$SWI==7			;SWITCH.INI
IFN	FTPERF,<
	$PRF==7			;Performance analysis (can't read SWITCH.INI then)
>
	SUBTTL	Internal input and output buffer block definitions

	PHASE	0

IBF.LK:	BLOCK	1			;Length,,Link to next buffer
					;Note that the length is NEGATIVE
					;if this is the last block in the chain
IBF.CT:	BLOCK	1			;Count of characters in buffer
IBF.PT:	BLOCK	1			;Pointer into buffer
IBF.DT:					;Data starts here

	DEPHASE

	IF2,<
		IFL	OBUFSZ-%MINBF,<
	PRINTX	?Output buffer size is too small
		>
	>
	IFNDEF	OBUFSZ,<OBUFSZ==200>	;Be able to do a big request
	PHASE	0

OBF.CT:					;Current count to outputin LH,
OBF.LK:	BLOCK	1			;Link to next in RH
OBF.PT:	BLOCK	1			;Byte pointer
OBF.DT:	BLOCK	OBUFSZ			;Output buffer size

	DEPHASE

	PHASE	0

TOB.CT:
TOB.FL:
	$TOICL==1B0			;Immune to output queue flush
	$TOOIN==1B1			;Override inhibit output
	$TOCNT==777B17			;Count
TOB.LK:	BLOCK	1			;flags+Count,,link.

TOB.DT:					;Start of data area (run time determined size)

	DEPHASE
	SUBTTL UUO definitions

IFN	FTDBUG,<
	OPDEF	PJ	[260B8]
>
	SUBTTL	MACRO Definitions -- PLM MACROs

;PLM affiliated MACROs:

	DEFINE	PLM,<IF1,<>
		     IF2,<IFE LSTPLM,<XLIST>>>

	DEFINE	MLP,<IF1,<>
		     IF2,<IFE LSTPLM,<LIST>>>

	IF1,<
	DEFINE	.LIT	<
			MLP
			COMMENT	->
				>		;End IF1
	IF2,<
	DEFINE	.LIT	<>
	>					;End IF2

PLM
;+
MLP
;	The following MACROS are defined for use in NRT:
;.list 1
;.le
;The PLM MACRO controls listing of the PLM in the source listing, as
;dictated by feature test switch LSTPLM.  The MLP MACRO reverts normal listing
;if necessary.  The .LIT and .EL MACROs are defined for the copyright notice
;at the beginning.

PLM
;-
MLP
	SUBTTL MACRO Definitions -- FALL (Address)

PLM
;+
;.le
MLP
;The FALL MACRO is used to insure that the contiguity assumptions
;about routine addresses (so that the extra JRST is not required) are correct.
;FALL will print an error message if the assumption is incorrect.
PLM
;-
MLP

	DEFINE FALL(ADDRESS),<
	IF2,<IFN .-ADDRESS,<PRINTX ?Cannot fall into Routine 'ADDRESS>>
  > ;End FALL
	SUBTTL MACRO Definitions -- PJRST(X)
PLM
;+
;.le
MLP
;PJRST is defined elsewhere with an OPDEF unless FTDBUG is turned on.
;This is so that PJRSTs become traceable in a dump if a problem is being
;debugged.  The PJRST macro turns off the optimization of turning a PUSHJ
;followed by a POPJ into a JRST.
PLM
;-
MLP

;PJRST is defined here only if FTDBUG is on so that PC stack tracing
;becomes easier

IFN	FTDBUG,<				;For debugging only
DEFINE	PJRST(X)<PUSHJ	P,[PUSHJ	P,X
				   POP		P,(P)
				   POPJ		P,]
>
>
	SUBTTL MACRO Definitions -- ERR(PRE,MSG)

PLM
;+
;.le
MLP
;The ERR MACRO is used to define a fatal error condition for NRT.
;It assembles with a three letter mneumonic which expands the location
;calling the ERR MACRO into the symbol "E..sym".  It calls the error
;routine specifying a prefix and a message for output.  The error routine
;saves context for a possible dump and exits.
PLM
;-
MLP

DEFINE	ERR(PRE,MSG,CONTIN<JRST NSPER1>)<
E..'PRE::PUSHJ	P,[PUSHJ	P,DOERR	;; Do an error message
		   CAI	[ASCIZ |PRE|]
		   CAI	[ASCIZ |MSG|]
		   CONTIN	]>

	SUBTTL MACRO Definitions -- ERRMAC(code,pre,text)

PLM
;+
;.le
MLP
;ERRMAC is used to make the standard DECnet error message table.
PLM
;-
MLP

DEFINE ERRMAC(code,pre,text),<
	IF1,<IFN code*2-<.-NSPERC>,<
		PRINTX ?NSP. error code out of order in NSPERC table>>
	[ASCIZ |pre|]
	ERRMC1(\code,text)
>
DEFINE ERRMC1(code,text),<[ASCIZ |code; text|]>
	SUBTTL MACRO Definitions -- FCNMAC - Table of NSP. function codes and text
PLM
;+
;.le
MLP
;FCNMAC is called to make the NSP. UUO function description table.
PLM
;-
MLP

DEFINE FCNMAC(code,text),<
	IFN code-<.-FCNTAB>,<PRINTX ?NSP. function code out of order>
	[ASCIZ /text/]
>
;MAX MACRO
DEFINE MAX(A,B)<
		IFN <<A-B>&400000000000><B>
		IFE <<A-B>&400000000000><A>
		>

DEFINE SAVE(ACS)<
	IRP <ACS><PUSH P,ACS>
	>

DEFINE RESTORE(ACS)<
	IRP <ACS><POP P,ACS>
	>
	SUBTTL	MACRO Definitions -- Typeout MACROS

PLM
;+
;.le
MLP
;There are three MACROS for various forms of typeout:
;.list 1
;.le
;TYPE is called to output an ASCIZ string to the controlling terminal.
;.le
;TYPCRLF is called to output a carriage return-line feed to the controlling
;terminal.
;.le
;TSIX is called to output a SIXBIT string to the controlling
;terminal.
;.end list
PLM
;-
MLP

DEFINE TYPE(STR)<OUTSTR [ASCIZ `STR`]>

DEFINE TYPCRLF<OUTSTR [ASCIZ `
`]>

DEFINE TSIX(STR)<
	PUSH	P,STR
	PUSHJ	P,.TSIX
	ADJSP	P,-1
	>
	SUBTTL	MACRO Definitions -- AC saving MACROS

PLM
;+
;.le
MLP
;There are many AC saving MACROS which call the appropriate routines.
;All of these macros use AC CX as a temporary AC:
;.list 1
;.le
;SAVE1 saves P1
;.le
;SAVE2 saves P1 and P2
;.le
;SAVE4 saves P1 through P4
;.le
;SAVET1 saves T1
;.end list
;There is also a routine, not called by a MACRO, to save all T ACs (SAVT).
PLM
;-
MLP

DEFINE SAVE1,<JSP CX,.SAV1>
DEFINE SAVE2,<JSP CX,.SAV2>
DEFINE	SAVE4,<JSP CX,.SAV4>
DEFINE SAVET1,<JSP CX,.SAVT1>
	SUBTTL	MACRO Definitions -- Break masks

PLM
;+
;.le
MLP
;The BRKMSK MACRO is used to define a break mask for usage by NRT.
;The two arguments are a string of control characters to use as the mask
;(except for convenience the user types in the string with all the characters
;"uncontrolified", e.g., to put "^A" in the break mask, specify "A" as
;a character of the first argument to the MACRO) and the "regular" character
;string, which inclues all characters which are not control characters.
PLM
;-
MLP

	DEFINE	CTLMSK(STRING)<...BRK==0
	IRPC	STRING,<...BRK==...BRK!1B<"STRING"&^O37>>
	>
	DEFINE	BRKMSK(CTLSTR,REGSTR)<
		CTLMSK(CTLSTR)
		BRMSK.	(...BRK,,,,,'REGSTR')
	>
	SUBTTL	MACRO Definitions -- ASSUME

PLM
;+
;.le
MLP
;The ASSUME MACRO is analagous to the FALL MACRO but is used for values
;rather than addresses.
PLM
;-
MLP

	DEFINE	ASSUME	(A,B)<IF2	<

		IFN	<A-B>,<
	PRINTX	%Assumption wrong:  'A does not equal 'B
		>
	>
	>
	SUBTTL	MACRO Definitions -- NETOCH macro - output character to network

PLM
;+
;.le
MLP
;The NETOCH MACRO is used to output one character to the network.  It takes
;as arguments the AC containing the character and the address of the error
;routine if there is insufficient room in the current buffer.  The default
;action taken if no error address is given is to queue the network buffer
;without outputting it and allocate a new buffer in which to continue
;depositing characters.
PLM
;-
MLP

	DEFINE	NETOCH	(AC,ERRADR<[PUSHJ	P,NETQUE
				    JRST	.-1]>)<
		PUSHJ	P,[SOSGE	OBFCTR
			      JRST	ERRADR
			   IDPB		AC,OBFPTR
			   POPJ		P,	 ]
	>
	SUBTTL	MACRO Definitions -- NETALC - Allocate contiguous buffer space

PLM
;+
;.le
MLP
;The NETALC MACRO is used to allocate space in the network output buffer
;without actually outputting anything.  If the requested amount cannot be
;allocated in the current buffer, it is queued for output (but not output)
;and a new buffer is allocated.  The requested allocated space is taken
;from the new buffer.  Note that NETALC should not be called with a size
;bigger than the maximum buffer size.  If this occurs, an error
;message will be output.
PLM
;-
MLP

	DEFINE	NETALC	(SIZE)<
	IFNDEF	%MINBF,<
			%MINBF==SIZE
		>
	IFG	SIZE-%MINBF,<
			%MINBF==SIZE
		>
		MOVEI	CX,SIZE		;;How much he wants
		SUBM	CX,OBFCTR	;;Will it fit?
		SKIPL	OBFCTR		;;(Negative if so
		  JRST	[PUSHJ	P,NETQUE
			 JRST	.-3]	;;Try allocate new buffer
		MOVNS	OBFCTR		;;Make right sign
		ADJBP	CX,OBFPTR
		MOVEM	CX,OBFPTR
	>
	SUBTTL	MACRO Definitions -- OSDSP

PLM
;+
;.le
MLP
;The OSDSP MACRO is used to create a dispatch vector for the OSJMP table.
;The arguments to the OSDSP MACRO include the addresses of the operating
;specific initialization routine, network service routine, and TTY:
;service routine.
PLM
;-
MLP

	DEFINE	OSDSP	(INIT,NETWORK,TTY)<
	INIT,,[TTY,,NETWORK]
>
	SUBTTL	MACRO Definitions -- NAMTAB

PLM
;+
;.le
MLP
;The NAMTAB MACRO is used to generate a table of SIXBIT names with appropriate
;symbols for the beginning and length of the list (in words).  It is used
;to generate tables for use by the .LKNAM routine.  This routine is called
;when RESCANning the command line (to parse the possible commands
;by which NRT can be run), the SWITCH.INI support (to parse switches),
;and the exit dialogue in NOVICE mode.
PLM
;-
MLP

	DEFINE NAMTAB(name,list),<
		name'L==0
name'A:
	IRP list,<	name'L==name'L+1
		EXP <SIXBIT |list|>>
	>
	SUBTTL	MACRO Definitions -- TRMCHR

PLM
;+
;.le
MLP
;The TRMCHR MACRO is used to define a table of TTY: characteristics to
;save/restore/set.
;-
MLP

	DEFINE	TRMCHR	(CHR,VAL,MNEU<SV>)<
T'MNEU'CHR:	VAL,,.TO'CHR
	>
	SUBTTL	MACRO Definitions -- VTTCHR

PLM
;+
;.le
MLP
;The VTTCHR MACRO is used to define a VAX terminal characteristic word.
;This word consists of the terminal type in the right half and the
;high order byte of the TT2 characteristics word in the left half.
;This assumes the ANSI/DEC CRT bit is in that byte.  The args for the
;MACRO are the ANSI/DEC CRT bit to use and the (up to) three character
;suffix to the DT$xxx symbol for the terminal type.
PLM
;-
MLP
	DEFINE	VTTCHR	(CRTBIT,TYPE)<

	ASSUME	T2ACRT,100000000
	ASSUME	T2DCRT,4000000000

		CRTBIT_-^D24,,DT$'TYPE

	>
	SUBTTL	MACRO Definitions -- ASCII8

PLM
;+
;.le
MLP
;ASCII8 makes eight-bit ASCII strings.
PLM
;-
MLP
DEFINE	ASCII8	(TEXT),<
	%%%LEN==0
	%%%WRD==0

	IRPC TEXT,<
		%%%WRD==<%%%WRD_10>+<"TEXT"_4>
		%%%LEN==%%%LEN+1
		IFE %%%LEN-4,<
			EXP %%%WRD
			%%%WRD==0
			%%%LEN==0
		>
	>

	IFN %%%LEN,<
		%%%WRD==%%%WRD_<<4-%%%LEN>*10>
		EXP %%%WRD
	>
>
PLM
;+
;.end list
;-
MLP
	SUBTTL	Start the Program
PLM
;+
;.HL 2 Section from GO to LPROMPT
MLP
;	This section contains the first part of the initialization logic.
;It first sets up basic defaults and flags that this is the first time
;through (sets variable RSTFLG to -1).  It then enters RESTRT, which is
;where the program restarts itself if fatal errors occur or the user
;attempts to continue the program from a non-continuable state.  RESTRT
;(the label where restarting begins) sets up the pushdown list and reads
;the user's SWITCH.INI file (if present), resetting any defaults to
;those values.  If restarting, we then go to label PROMPT for the short
;dialogue, otherwise we attempt to rescan the line and either take arguments
;from the rescanned line if successful or go to LPROMPT for the long
;dialogue if not.  If the rescan is successful, we call
;INITDB to initialize NRT's database here and proceed directly to CHKPMR to
;attempt to set up the connection.
PLM
;-
MLP

GO:	JFCL				;Ignore CCL entry
	SETOM	RSTFLG			;Use long dialogue if necessary
	SETZ	F,
RESTRT:	MOVX	T1,ER.ICC		;Turn of any left-over ^C
	ANDCAM	T1,ERRBLK+.ERCLS	;..
	MOVEI	T1,DEFESC		;Default escape char
	MOVEM	T1,ESCCHR		;
	MOVE	P,[IOWD PDLLEN,PDL]	;Set up A Stack
	PUSHJ	P,SWTINI		;Read SWITCH.INI
	AOSE	RSTFLG			;If restarting
	  JRST	PROMPT			;Use short dialogue
	RESCAN	1			;Rescan the command line
	PUSHJ	P,DORSCN		;Go process the RESCAN line
	  JRST	LPROMPT			;Error or no node name
	PUSHJ	P,INITDB		;Set up the data base
	JRST	CHKPMR			;Note that T2 still has first node name
	SUBTTL LPROMPT - Long Dialogue

PLM
;+
;.hl Routine LPROMPT
MLP
;	Routine LPROMPT is resposible for the long dialogue.  Upon
;displaying the current "escape character" (which may be the assembled
;default or the default as obtained from the user's SWITCH.INI) and
;accepting a new one (if requested to by the user by typing a character
;other than <CR> to the question), we proceed to fall into the short
;dialogue (routine PROMPT).
PLM
;-
MLP
LPROMPT:
	OUTSTR	[ASCIZ /DECnet Intersystem Remote Terminal service
Escape character (/]
	MOVE	T1,ESCCHR		;Get escape character
	CAIL	T1," "			;Control?
	  JRST	LPR0			;No
	OUTCHR	["^"]
	MOVEI	T1,100(T1)
LPR0:	OUTCHR	T1
	OUTSTR	[ASCIZ/): /]
LPR1:	INCHRW	T1			;Get new character
	CAIN	T1,.CHCRT		;Carriage Return?
	 JRST	LPR1			;Get the LF
	CAIE	T1,.CHLFD		;Line feed?
	 MOVEM	T1,ESCCHR		;Store escape character
	PUSHJ	P,CMPESC		;Compute mask for interrupt level
LPROM1:	TYPCRLF				;Be friendly
	FALL	PROMPT			;Put out the normal prompt

	SUBTTL	PROMPT - Short initialization dialogue

PLM
;+
;.hl Routine PROMPT
MLP
;	Routine PROMPT handles the short initialization dialogue.  Note that
;the short dialogue is a subset of the long dialogue (which falls into here).
;After requesting the desired remote host's name from the user and inputting
;it, we fall into CHKPMR which establishes the connection.  Note that we also
;initialize NRT's data base here.
PLM
;-
MLP

PROMPT:	PUSHJ	P,INITDB		;Init the data base
	TYPE <Node Name: >
PRM2:	PUSHJ	P,SIXINW			;Get node name user wants
	CAIN	T1,.CHCNZ		;User want out?
	  JRST	NSPER1			;OK to continue
	JUMPE	T2,PROMPT		;Ignore null node name
	FALL	CHKPMR
	SUBTTL	Check for Poor Man's Routing in User's String
PLM
;+
;.hl Section from CHKPMR to DOPMR
MLP
;	We enter this section from a number of points; most obviously by
;falling in from the short dialogue.  However, we come here with the
;data base initialize and all values for escape character and
;initial node name set up.  We check for Poor Man's Routing here;
;if the user specified it we go and parse the string before
;establishing the connection, otherwise we just establish the connection.
;We cue on the user having actually specified a double colon
;as the key to whether he specified PMR or not.  The special case
;of the user specifying a double colon followed by a <CR> is checked
;for at DOPMR if FTPMR is turned off so that we don't bomb out
;the user on this special case.  This routine is entered
;with T2 containing the name of the first remote node.
PLM
;-
MLP

CHKPMR:	MOVEM	T2,RNODE		;Save first node
	CAIN	T1,":"			;Is it a ":"?
	INCHSL	T1			;Yes, get a character
	 JRST	DOCONN			;Not PMR if no more characters
	CAIE	T1,":"			;Second colon?
	  JRST	DOCONN			;Do the connect
	FALL	DOPMR			;Fall into appropriate PMR routine
	SUBTTL DOPMR - Subroutine to do the Poor mans routine string

PLM
;+
;.hl Routine DOPMR
MLP
;	Routine DOPMR is fallen into when CHKPMR decides that the
;user may have specified Poor Man's routing.  If NRT has been assembled with
;FTPMR turned off, we check for the special case of the user
;typing a double colon followed by a carriage return.  If this is the
;case, we proceed with the connection; if not we output an error
;message and exit.
;FTPMR is turned on, we parse the node names in the string and
;store them as sixbit values, one to a word, in the table starting
;at location RNODE.  After parsing the string, we proceed to BLDPMR to actually
;build the string to send to the remote PSTHRU task.
PLM
;-
MLP

DOPMR:
IFE	FTPMR,<
	INCHSL	T1
	  JRST	DOCONN			;Nope
	CAIN	T1,.CHCRT		;<CR>?
	  JRST	DOCONN			;Yes, then do the connect
	CLRBFI				;Clear the input buffer
	ERR	NPM,<Version not compiled with Poor Man's Routing>
 > ;End IFE FTPMR

IFN	FTPMR,<
	MOVE	P1,[-<MAXPMR-1>,,1]	;Already have first node
PMRL1:	SKPINL				;Anything inputable?
	  SOJA	P1,BLDPMR		;Index
	PUSHJ	P,SIXIN			;Get the next name
	JUMPE	T2,.-2			;If really nothing
	MOVEM	T2,RNODE(P1)		;Store the first one
	CAIGE	T1," "			;Printing?
	  JRST	BLDPMR			;No, must be done
	CAIE	T1,":"			;Correct break?
	 ERR	EDC,<Expecting Double colon in PMR string>
	INCHSL	T1			;Get character
	  JRST	E..EDC			;Oops
	CAIE	T1,":"
	  JRST	E..EDC			;Oops again
	AOBJN	P1,PMRL1
	 ERR	TMN,<Too many nodes in PMR string>

> ;End IFN FTPMR

	SUBTTL BLDPMR - Builds the PMR string
PLM
;+
;.hl Routine BLDPMR
MLP
;	Routine BLDPMR translates the node string which was parsed by
;DOPMR and stored as SIXBIT nodes in the RNODE table into an eight-bit
;ASCII string suitable for sending to the first node's PSTHRU task.
;It is entered from DOPMR only with P1 containing the maximum index
;into the RNODE table at which a node name was stored.  This is
;equivalent to the number of nodes in the string minus one.
PLM
;-
MLP

IFN FTPMR,<
BLDPMR:	HRRZM	P1,NODCNT		;Store
	MOVE	P1,[POINT 8,PMRMSG]	;Get the PMR message
	SETZ	P3,			;Clear out a count
	MOVEI	T1,1			;Start of PMR
	AOS	P3			;Increment number of bytes
	IDPB	T1,P1			;Put it into the string

	MOVE	P2,[POINT 6,RNODE+1]	;Get the pointer
BLD0:	MOVEI	T3,^D6			;Six character maximum
BLD1:	ILDB	T1,P2			;Get a byte from the node list
	JUMPE	T1,EATBLD		;Eat the rest and finish this one
BLD11:	MOVEI	T1," "(T1)		;Make it ASCII
	AOS	P3			;Increment byte count
	IDPB	T1,P1			;Store it
	SOJG	T3,BLD1			;Loop for all of them

BLD2:	MOVEI	T1,":"			;Get the break
	IDPB	T1,P1
	IDPB	T1,P1			;"::"
	ADDI	P3,2			;Increment byte count by 2

BLD3:	MOVEI	T3,^D6			;Get the number left
	ILDB	T1,P2			;Get the first character
	JUMPE	T1,ENDPMR		;End of the string
	JRST	BLD11			;Loop around to store this one too

EATBLD:	SOJLE	T3,BLD2			;Put the break
	ILDB	T1,P2			;Get the next byte
	JRST	EATBLD			;End check

ENDPMR:	MOVE	P2,[POINT 7,[ASCIZ |"23="|]] ;Get the ending string
ENDPM1:	ILDB	T1,P2			;Get the byte
	JUMPE	T1,ENDPM2		;Do the connect if done
	IDPB	T1,P1			;Put it intot he string
	AOS	P3			;Increment the byte count
	JRST	ENDPM1			;Loop around

ENDPM2:	MOVEM	P3,PMRMSG-1		;Save the count
	FALL	DOCONN
> ;End IFN FTPMR
	SUBTTL DOCONN - Initiatiate a DECnet connection

PLM
;+
;.hl Section from DOCONN to MAIN
MLP
;	We enter here with all of NRT's data base set up to do final
;initialization and initiate the connection to the remote system.
;We first OPEN device TT: and initialize the core manager.
;We check to see if the user is attempting to connect
;to the same node on which he is running; if so we issue a warning before
;proceeding.  We set up the network I/O buffers and call CONECT to initiate
;the connection to the remote node.  After a [successful] return from
;CONECT, we read the configuration message.  We add all the appropriate
;things the software interrupt system, set up ^C trapping through .JBINT
;(we actually trap on any job error or control-C; although the terminal
;is slaved one can use a FRCUUO function of .HALT to force the program
;to trap in case it gets stuck; this is useful for debugging purposes).
;We then use the information from the remote host's configuration message
;(in particular the operating system type) to set the
;addresses of the operating system specific network and TTY: routines.
;We then call the operating system specific initialization routine
;and call FRCTTY to get things started.
PLM
;-
MLP

DOCONN:	PUSHJ	P,TTYOPN		;OPEN the TTY: now
	HRRZ	T1,.JBFF
	SOJ	T1,
	IORI	T1,777			;Round to page boundary
	MOVEM	T1,HICORE		;For core allocator
	SETZM	FRELST			;Clear free core pointer
	MOVX	T2,<DN.FLE!<.DNLNN,,.DNNMS+1>>
	MOVEM	T2,NODBLK+.DNFFL
	MOVEI	T2,NODBLK		;Get the argument pointer
	DNET.	T2,			;Do the UUO
	 JRST	DOCN1			;Do the connect anyway
IFN	FTPMR,<
	MOVE	T2,NODCNT		;If PMR, get last node
	MOVE	T2,RNODE(T2)
>
IFE	FTPMR,<
	MOVE	T2,RNODE
>
	CAME	T2,NODBLK+.DNNMS	;Is it this node?
	  JRST	DOCN1			;No, no warning
	OUTSTR	[ASCIZ |
%Already at node |]			;Give a message
	PUSHJ	P,TNODE1		;Type it out
	OUTSTR	[ASCIZ | - Proceeding with connection anyway.
|]
DOCN1:	PUSHJ	P,INIOBF		;INITIALIZE THE FAKE BUFFERS
	PUSHJ	P,CONECT		;SET UP THE CONNECTION

OPTTY:	MOVEI	T1,REENTR		;Get routine to handle
	MOVEM	T1,.JBREN		;Save it
	PUSHJ	P,GETCFG		;Get the configuration stuff
	MOVE	T1,OSTYPE		;Get the Operating system type
	MOVE	T1,OSJMP(T1)		;Point to proper routine
	MOVE	T2,(T1)			;Get TTY routine,,NETWORK routine
	HRRZM	T2,OSNET		;Save address of network routine
	HLRZM	T2,OSTTY		;And TTY: routine
	HLRZ	T1,T1			;Point to initialization routine
	PUSHJ	P,(T1)			;Call it this time
	MOVE	CX,[PS.FAC!PSYNSP]
	PISYS.	CX,
	  ERR	CDP,<Can't add DECnet NSP. traps to PSISER>
	MOVE	NSAFN,[.NSFPI,,.NSAA1+1] ;Now set psi mask
	MOVEI	NSAA1,(NS.NDA!NS.STA!NS.NDR)	;Just tell me when things can be read
	MOVEI	T1,NSAFN
	NSP.	T1,
	  ERR	NPI,<NSP. UUO to set PSI mask failed>
	MOVE	CX,[PS.FAC!PSYTMR]	;Add timer traps too
	PISYS.	CX,
	  ERR	CAT,<Can't add TIMER traps to PSISER>
	PUSHJ	P,SETTTY		;Slave the TTY:
	MOVEI	T1,ER.ICC		;Trap now
	IORM	T1,ERRBLK+.ERCLS	;..
	PUSHJ	P,TTYSST		;Set TTY: up
	MOVEI	T1,.TOCIB
	MOVE	CX,[2,,T1]
	MOVE	T2,TTYUDX
	TRMOP.	CX,
	  JFCL				;Try to make PIM happy
	PUSHJ	P,FRCTTI		;Wake us up
	PUSHJ	P,PSION			;Turn on the PI
	SUBTTL	MAIN - Main wait loop for all systems
PLM
;+
;.hl MAIN loop (section from MAIN to FRCTTY)
MLP
;	The MAIN loop is simply a HIBER UUO.  We expect to be woken by
;PSI interrupts when any events of any significance occur.
;	The exception to this is a break mask change.  This most
;often occurs at network interrupt level.  Unfortunately, if type-ahead
;in the input buffer does not satisfy the current break mask, but the break
;mask is then changed so that the existing type-ahead now fulfils the
;current break mask, the monitor does not grant a PSI interrupt.  Therefore,
;NRT traps for WAKE UUOs as well as any other conditions and WAKEs itself
;and sets F$USRV (via a call to FRCTTY) if it wishes to force a TTY: interrupt.
;MAIN always returns to sleep if woken.
PLM
;-
MLP

MAIN:	MOVSI	T1,(HB.RWJ)		;Defend against others
	HIBER	T1,			;OR UNTIL SOMETHING HAPPENS
	 JFCL
	JRST	MAIN			;Go look for more to do
	SUBTTL	FRCTTY - Force a look at the TTY:

PLM
;+
;.hl Routines FRCTTY and FRCTTI
MLP
;	As mentioned above, since changing the break mask doesn't
;cause a PSI interrupt if input is done, we need to wake ourselves
;and set F$USRV.  Routine FRCTTY is called to do this, or any
;other time we wish to act as if a TTY: service PSI occured.  Enter
;at label FRCTTI to be sure PS.RID gets set in TTYSTS, or call
;FRCTTO to be sure PS.ROD gets set in TTYSTS.  It uses T1.
PLM
;-

FRCTTO:	SKIPA	T1,[PS.ROD]
FRCTTI:	MOVEI	T1,PS.RID
	IORM	T1,TTYSTS		;Set the bit
FRCTTY:	TXOE	F,F$USRV		;Set flag
	  POPJ	P,			;Already done
	SETO	T1,			;Wake ourselves
	WAKE	T1,			;..
	 TXZ	F,F$USRV		;Oops
	POPJ	P,			;Return

	SUBTTL OSJMP - Dispatch table for systems

PLM
;+
;.hl OSJMP table
MLP
;	The OSJMP table uses the OSDSP MACRO to define the transfer
;vectors for each type of operating system.  See the documentation of
;the OSDSP MACRO for further details.  The OSJMP table is a table of
;OSDSP vectors indexed by operating system type.
PLM
;-
MLP

OSJMP:	OSDSP	RST.IN,RST.NT,RST.TT	;RSTS/E
	OSDSP	DORT11,DORT11,DORT11	;RT-11
	OSDSP	RST.IN,RST.NT,RST.TT	;RSTS-E
	OSDSP	RSX.IN,RX.NET,RSX.TT	;RSX11-S
	OSDSP	RSX.IN,RX.NET,RSX.TT	;RSX11-M
	OSDSP	RSX.IN,RX.NET,RSX.TT	;RSX11-D
	OSDSP	RSX.IN,RX.NET,RSX.TT	;IAS
	OSDSP	VMS.IN,VMS.NT,VMS.TT	;VAX/VMS
	OSDSP	T10.IN,T20.NT,T20.TT	;TOPS-20
	OSDSP	T10.IN,T10.NT,T10.TT	;TOPS-10
	OSDSP	DORTS8,DORTS8,DORTS8	;RTS-8
	OSDSP	DOOS8,DOOS8,DOOS8	;OS-8
	OSDSP	DORXMP,DORXMP,DORXMP	;RSX-M+
	OSDSP	DOCOPOS,DOCOPOS,DOCOPOS		;COPOS

	SUBTTL	Initialization subroutines -- Initialize the Data Base

PLM
;+
;.hl Routine INITDB
MLP
;	The INITDB subroutine is called at initialization time to
;initializae the low segment data base.
;It is also this routine's responsiblity to intialize the software
;interrupt system.  It sets up the AC sets and pushdown
;lists for the interrupt level routines.  It turns of control-C trapping
;(in case this was a restart) so that the user can easily exit
;at this time.  It figures the bit mask position and word for the
;escape character so that it can be added easily to any break mask
;at interrupt level.  It destroys only AC CX.
PLM
;-
MLP


INITDB:	PUSHJ	P,SAVT			;Save everything
	SETZM	TIBUF			;So won't try to reset
	RESET				;Clear the world now
	MOVEI	T1,VECBAS		;Get the base of the block
	PIINI.	T1,			;Error
	 ERR	PIF,<PIINI. UUO failed>
	SETZM	OSTMR			;No timer stuff yet
	SETZM	ERRBLK+.EROPC		;Be sure we trap again
	STORE	T1,FSTZER,LSTZER,0	;Clear out the zeroable low segment
	MOVE	T1,[HILOST,,LOLOST]	;Setup Nonzero stuff in loseg
	BLT	T1,LOLOND		;
	SETOM	INTLVL			;Interrupt level is available
	SETOM	LICHCT			;For those who use it
	MOVEI	T1,.NSDOB+1		;Get the length of a PDB
	MOVEM	T1,DSTPDB+.NSDFL	;Store it
	SETZM	DSTPDB+.NSDFM		;This is the format type
	PUSHJ	P,CMPESC		;Compute escape bit and mask
	SETZM	.JBREN			;Tell REENTER its not OK to REENTER
	MOVE	T1,[IOWD PDLLEN,TTYPDL]	;TTY: PDL pointer
	MOVEM	T1,TTYACS+P		;Set up all interrupt stacks
	MOVE	T1,[IOWD PDLLEN,NSPPDL]	;NSP pointer
	MOVEM	T1,NSPACS+P
	MOVE	T1,[IOWD PDLLEN,TMRPDL]
	MOVEM	T1,TMRACS+P
	MOVE	T1,[PS.FAC![	.PCDAT
			    DATVEC-VECBAS,,0
				   2,,0	  ]]	;Higher priority
	PISYS.	T1,
	  JFCL
	MOVE	T1,[PS.FAC![	.PCWAK
			    WAKVEC-VECBAS,,0
				  Z		]]
	PISYS.	T1,
	  ERR	CWT,<Can't add PSI WAKE. Traps>
	POPJ	P,			;Only return
	SUBTTL	Initialization subroutines -- Process RESCAN Input

PLM
;+
;.hl Routine DORSCN
MLP
;	The DORSCN routine parses input as RESCANed from the command line.
;NRT may be run with a variety of command forms; this is so that those
;used to different conventions may find it easy to HOST out to another system.
;The exact commands which may be used are defined with the NAMTAB MACRO.
PLM
;The ways NRT may be run include:
;.list 1
;.le
;SET HOSTESS node
;.le
;HOST node
;.le
;NRT node
;.le
;TO node
;.le
;R or RUN NRT
;.le
;START
;.end list
;-
MLP

NAMTAB LIST1,<SET,RUN,START,NRT,HOST,TO> ;FIRST TOKEN
NAMTAB LIST2,<HOSTESS>			   ;AFTER "SET"

DORSCN:	SAVE1			;Save P1
	PUSHJ	P,SIXIN		;Get SIXBIT Token From INCHRL
	JUMPE	T2,DORSCE	;If Nothing There, Error Return
	MOVE	P1,T1		;Save Delimiter in P1
	MOVE	T1,[-LIST1L,,LIST1A]
	PUSHJ	P,.LKNAM		;See If T2 Holds One of these names
	  JRST	DORSCE		;No, Eat rest of line
	JRST @[	DORSC1		;"SET"
		DORSC2		;"RUN"
		DORSC2		;"START"
		DORSC3		;"NRT"
		DORSC3		;"HOST"
		DORSC3](T1)	;"TO"
;Here if the first token was "SET", delimiter in P1

DORSC1:	PUSHJ	P,SIXIN		;Get "HOSTESS"
	JUMPE	T2,DORSCE	;No?
	MOVE	P1,T1		;Save delimiter for DORSCE
	MOVE	T1,[-LIST2L,,LIST2A]
	PUSHJ	P,.LKNAM	;Is it HOSTESS or Some Abbrev?
	  JRST	DORSCE		;No
	JRST	DORSC3		;Yes, Get node name now

;Here if the first token was "RUN", delimiter in P1

DORSC2:	CAIE	P1,"-"		;Was Program name defaulted
	 CAIN	P1,"("		;with Either - OR (?
	  JRST	DORSC3		;Yes, Go get Node name
	CAIGE	P1," "		;If control
	  JRST	DORSCE		;Error return
	PUSHJ	P,SIXIN		;No, get program name
	MOVE	P1,T1		;Get delimiter again (For DORSCE Too)
	JUMPE	T2,DORSCE	;Error return if None
	JRST	DORSC2		;Ignore node name, try again for delimiter

;Here if the next token is the node name we're after

DORSC3:	PUSHJ	P,SIXIN		;Get node name
	MOVE	P1,T1		;SAVE DELIMITER FOR DORSCE
	JUMPN	T2,CPOPJ1	;SUCCESS RETURN IF NAME IS THERE
	JRST	DORSCE		;NONE, ERROR RETURN

;Here if we had an error in the RESCAN, eat rest of line & return

DORSCE:	MOVE	T1,P1		;SET UP FOR DORSE1
DORSE1:	CAIE	T1,.CHCRT	;CRLF YET?
	CAIN	T1,.CHESC	;OR ESCAPE?
	  POPJ	P,		;Yes, error return now
	CAIE	T1,.CHLFD	;LF?
	PUSHJ	P,INCHR		;NO, GET NEXT CHAR
	  POPJ	P,		;Return now if no more chars to read
	JRST	DORSE1		;LOOP UNTIL EOL

	SUBTTL FNDFNC - Find function routine
PLM
;+
;.hl Routine FNDFNC
MLP
;	The FNDFNC routine is provided to dispatch to an address based
;on a value which must not be consecutive.  It is called with the table's
;base address in P1 and the value to match on in T1.  The format of the
;table it uses is:
PLM
;.lm 20.nofill.noautop.tp 7.bl 1
MLP

;	TABLE:	value,,address
;		value,,address
;		    .
;		    .
;		    .
;		    0

PLM
;.just.autop.lm 5.bl 1
MLP
;It returns CPOPJ if the function was not found or CPOPJ1 (after
;dispatching) if it was.
PLM
;-
MLP

FNDFNC:	SKIPN	CX,(P1)			;Anything?
	 POPJ	P,			;Yes, then give unsupported return
	CAIE	T1,(CX)			;Are they the same?
	 AOJA	P1,FNDFNC		;Loop for all of them
	HLRZS	CX
	PUSHJ	P,(CX)			;Go handle it
	  JFCL				;Skip return is possible but not error
	JRST	CPOPJ1			;And skip return when done
	SUBTTL NETCHR - Output a stream of network data to TTY

PLM
;+
;.hl Routine NETCHR
MLP
;	The NETCHR routine is used by the TOPS-10 and TOPS-20 network
;service.  It takes all characters from the network input buffer
;and outputs then on the TTY:.  It also calls RECRSP to record
;response times if the user is running a performance analysis experiment.
;It exits through DOOUT1 to force out the last buffer to the TTY:.
;It uses T1, CX, and the NSP. ACs.  NETCHR will grant a TTY: interrupt
;via TTYPS1 if it notices F$USRV is on.

PLM
;-
MLP

NETCHR:
IFN	FTPERF,<
	TXNE	F,F$PERF		;Doing perf analysis?
	  PUSHJ	P,RECRSP		;Yes, record response time
>					;End FTPERF
NETCH1:	PUSHJ	P,NETICH		;Read 1 byte from remote
	  PJRST	DOOUT1			;Finish up
	TXZE	F,F$USRV		;Want an interrupt?
	  PUSHJ	P,TTYPS1		;Grant a TTY: interrupt
	TXNN	F,F$CTO			;If supposed to flush
	PUSHJ	P,OUTTTY		;Output character to TTY
	JRST	NETCH1			;Go see if there are more chars

	SUBTTL	Exit Routines -- MONITO (Exit Dialogue)

PLM
;+
;.hl Routine MONITO
MLP
;	MONITO is responsible for handling the exit dialogue.  It uses
;all T ACs and CX.  It is called by the operating system dependent
;TTY: service routine when the user types the break character.  It outputs
;the appropriate exit dialogue based on the setting of the user's /MODE
;switch (which translates into flag F$XPT and location NOTICH:  F$XPT only is
;non-zero for /MODE:EXPERT and both F$XPT and NOTICH are non-zero for
;/MODE:NOTIFY, and both are zero for /MODE:NOVICE).
;In the case of the "M[onitor]/(CONTINue,REENTEr)", "P[ass]", "O[bscure]",
;"R[econnect]", or "C[hange]" commands, MONITO returns to the caller
;with the escape character in T1.  For the "P[ass]" command,
;MONITO returns CPOPJ1 to flag to the caller
;to pass the escape character through to the remote host.  For the other
;commands, MONITO returns CPOPJ to inform the caller to proceed as
;if the escape character had not been typed.  It is, however, the
;caller's responsibility to remove the break character from any internal
;input stream if that is applicable.
;	MONITO has an additional entry point, MONITC, which can be used
;to pass the command character (assuming expert or notify modes) which
;will be "input" to the command parser.  The character is passed in T3
;or is passed as zero if there is none.
PLM
;-
MLP

MONITO:	SETZ	T3,			;No character input
MONITC:	PUSHJ	P,PIOSAV		;Turn off the PI
	PUSH	P,T3			;Save character, if any
	PUSHJ	P,TTYRST		;Reset the TTY
	POP	P,T3			;Restore character

IFN FTPERF,<
	TXZ	F,F$PERF		;Clear the performance flag
	SETZM	TSTPTR			;Zero out the pointer
> ;End IFN FTPERF
	TXNN	F,F$XPT			;Expert mode?
	  JRST	MONIT0			;Below only for experts
	SETO	T1,			;Controlling TTY:
	GETLCH	T1			;Get TTY: characteristics
	TXO	T1,GL.NEC		;Turn off echo
	SETLCH	T1			;..
	JRST	EXCT0			;Skip typeout
MONIT0:	TYPE	<
[Connection broken, Back at node >	;Type out the header
	MOVE	T2,NODBLK+.DNNMS	;Get the sixbit local node name
	PUSHJ	P,TNODE1		;Type out the node name
	TYPE	<::]>			;Type this out
EXCOPT:	TXNN	F,F$XPT			;Want message?
	 OUTSTR	[ASCIZ/
NRT_EXIT> /]				;Yes
EXCT0:	SKIPE	T1,NOTICH		;Want notification?
	 OUTSTR	(T1)			;Output the string
EXCT1:	TXNE	F,F$XPT			;Expert?
	  SKIPA	T2,[INCHRW	T1]	;Yes
	SKIPA	T2,[INCHWL	T1]	;No
	  SKIPN	T1,T3			;If any character
	XCT	T2			;Get the character
	TXNE	F,F$XPT			;Expert mode?
	CAME	T1,ESCCHR		;Yes, is this escape character?
	  TRNA				;No or no
	MOVEI	T1,"P"			;Make "P" command then
	CAIN	T1,.CHCRT		;Have a CRLF?
	INCHSL	1(P)			;Eat LF
	CAIGE	T1," "			;Printing?
	  JRST	NSPER1			;No, exit
EXCT2:
	CAIL	T1,"a"			;Lower case?
	 SUBI	T1,"a"-"A"		;Make it UC

EXCOP1:	MOVEI	T2,-<" "-' '>(T1)	;Convert to SIXBIT
	LSH	T2,5*6			;Left justify
	TXNE	F,F$XPT			;No eats in expert mode
	  JRST	EXCOP2			;No eats nor SIXIN
	PUSHJ	P,SIXINA		;Input token
EXCOPX:	CAIE	T1,.CHCRT		;CR?
	CAILE	T1," "			;Noise?
	INCHSL	T1			;Must eat more
	  JRST	EXCOP2			;No more to eat
	JRST	EXCOPX			;Continue
EXCOP2:	MOVE	T1,[-EXITL,,EXITA]	;Exit function table
	PUSHJ	P,.LKNAM		;Lookup
	  JRST	EXCP2A			;Not found
	SKIPL	T1,EXITDS(T1)		;Change status? Get entry.
	TXNN	F,F$XPT			;Expert mode?
	  JRST	(T1)			;Don't bother if no-echo anyway
	SETO	T3,			;Controlling TTY:
	GETLCH	T3
	TXZ	T3,GL.NEC
	SETLCH	T3
	JRST	(T1)			;Dispatch
EXCP2A:	TXNN	F,F$XPT			;Expert?
	 OUTSTR	[ASCIZ/
%Illegal command, type "H"<CR> for Help/]
	JRST	EXCOPT			;Ask again
	SUBTTL	Exit Routines -- Dispatch Table
PLM
;+
;.hl Exit Routine Dispatch Tables
MLP
;	This set of tables associates the exit routine keywords with
;the appropriate dispatch vectors.  It is assembled to be scanned
;via .LKNAM.  The dispatch vectors table entries consist of the
;address of the routine in the right half, and the sign bit in the
;left half iff the routine does not want the echo mode changed
;before execution of the actual command (the echo mode may have
;been explicitly turned off due to the setting of F$XPT).
PLM
;-
MLP

	NAMTAB	EXIT,<EXIT,REENTER,PASS,CHANGE,MONITOR,HELP,OBSCURE>

EXITDS:	NSPER1				;Exit
	G0				;Reenter
	GX				;Pass
	REENTR				;Change
	EXCOP3				;Monitor
	400000,,EXCHLP			;Help
	FLUSH				;Flush network messages
IFN	.-EXITDS-EXITL,<
	PRINTX	%Wrong number of EXIT functions
>
	SUBTTL	Exit Routines -- Help Routine

PLM
;+
;.hl Routine EXCHLP
MLP
;	This routine outputs the appropriate help text ("H[elp]" command)
;and re-enters the exit dialogue.
PLM
;-
MLP

EXCHLP:
IFN	FTPERF,<
	OUTSTR	[ASCIZ |
E    - To exit to monitor and close the current link.
H    - To type this text.
M    - To Exit to monitor and leave link open.
P    - To continue and pass the break character to the system.
R    - To reconnect to remote system
O    - To flush network output (TOPS-10/TOPS-20 only).
C    - To change break character and continue or enter performance mode.|]

>					;Performance text
IFE	FTPERF,<
	OUTSTR	[ASCIZ |
E    - To exit to monitor and close the current link.
H    - To type this text.
M    - To Exit to monitor and leave link open.
P    - To continue and pass the break character to the system.
R    - To reconnect to remote system
O    - To flush network output (TOPS-10/TOPS-20 only).
C    - To change break character and continue.|] ;End of text message

>					;No performance test
	TXNE	F,F$XPT
	TYPCRLF				;Look pretty
	JRST	EXCOPT			;And back to the question
	SUBTTL	Exit Routines -- Flush Network Messages

PLM
;+
;.hl Routine FLUSH
MLP
;	FLUSH is called to flush network messages ("O[bscure]" command;
;TOPS-10/20 only).  This is in lieu of ^O working "correctly" for TOPS-10/20
;connections.
PLM
;-
MLP

FLUSH:	MOVE	T1,OSTYPE			;Get the OS type
	CAIE	T1,OST10			;TOPS-10?
	CAIN	T1,OST20			;or TOPS-20?
	  JRST	DOFLSH				;Yes
	ERR	N10,<Not connected to TOPS-10 or TOPS-20, command ignored>,<POPJ	P,>
	PJRST	G0				;Toss it
DOFLSH:	PUSHJ	P,CLRTOQ			;Clear the TO queue etc.
	MOVEI	T1,T10.TM			;Set the routine
	MOVEM	T1,OSTMR			;..
	TXO	F,F$CTO				;Set flag
	MOVEI	T4,[ASCIZ/[^O]
/]
	MOVE	T1,[3,,T2]
	MOVEI	T2,.TOOUS
	MOVE	T3,TTYUDX
	TRMOP.	T1,
	  JFCL					;In case I/O mode was different
	PUSHJ	P,T10.TM			;Boot it up
	PJRST	G0				;And reconnect
	SUBTTL	Exit Routines -- Return to Monitor

PLM
;+
;.hl Routine EXCOP3
MLP
;	EXCOP3 is used to return to monitor level ("M[onitor]" command).
PLM
;-
MLP

EXCOP3:	OUTSTR	[ASCIZ |
[CONTINUE to resume connection, REENTER to change escape character]
|]
	MONRT.				;CALL THE MONITOR
	CLRBFI				;Eat junk
	FALL	G0			;Continue the session
	SUBTTL	Continue Remote Session
PLM
;+
;.hl Section from G0 to REENTR
MLP
;	This section is entered when the user wishes to continue
;the program from the exit dialogue.  Enter at label G0 with F$PERF set
;appropriately for entering performance analysis mode.  Enter at GX
;to pass the break character through to the host (i.e. to give skip
;return to the caller).  This routine outputs the necessary messages
;and returns to the caller (of MONITO) with T1 containing the escape
;character.
PLM
;-
MLP

G0:
IFN FTPERF,<
	TXNN	F,F$PERF		;Are we doing performance testing
>
	  JRST	G1			;No
IFN	FTPERF,<
	MOVEI	T1,[ASCIZ/
[Performance testing for /]
	JRST	G2			;Tell him what we're doing
> ;End IFN FTPERF
GX:	AOS	(P)			;Flag to pass character
G1:	TXNE	F,F$XPT			;Expert mode?
	  JRST	G3			;Return
	MOVEI	T1,[ASCIZ/
[Reconnected to /]

G2:	OUTSTR	(T1)
	MOVE	T3,OSTYPE		;Type it out right
	TSIX	OSNAME(T3)		;Type out the operating system
	TYPE	< system >

IFE FTPMR,SETZ	T2,			;Zero if not using PMR
IFN FTPMR,MOVE	T2,NODCNT		;Get the number of nodes
	MOVE	T2,RNODE(T2)		;Get the last node name
	PUSHJ	P,TNODE1			;And type that out
	TYPE	<::]>			;And the close
	TYPCRLF
G3:	PJOB	T1,			;Get current job
	MOVNS	T1			;For JOBSTS
	JOBSTS	T1,			;Get word
	  SETZ	T1,
	SKIPL	TTYUDX			;Detached?
	TLNN	T1,(JB.UML)		;No, at monitor level?
	  JRST	G4			;Detached or at user level, proceed
	SETZ	T1,
	OUTCHR	T1			;(We couldn't have reset PIM yet)
	CLRBFI				;Make PIM happy
G4:	SETSTS	$TTY,@TTYBLK		;TTYSST will do this, but could get
					;confused if we were in PIM and output
					;can get garbled.
	PUSHJ	P,TTYSST		;Reset TTY: status
	PUSHJ	P,SETTTY		;Slave TTY:
	MOVE	T1,ESCCHR		;Get the escape character
	TXNE	F,F$PIM
	  POPJ	P,			;No ^O if PIM
	TXZ	F,F$ICO
	PJRST	SETCTO			;Set ^O and return



	SUBTTL REENTR - REENTR code

;PLM
;+
;.hl Routine REENTR
MLP
;	This section is entered when the user wishes to change the escape
;character.  This is if the user either enters the "C[hange]" command
;to the exit dialogue or REENTErs after a "M[onitor]" command to the
;exit dialogue.  We output the correct prompt here and perhaps the
;option of entering performance analysis mode, if the user is logged
;in and NRT is assembled with FTPERF turned on.  We exit with
;the new escape character set to label G0 (or through DOPERF if the
;user requests performance analysis).  If the escape character is changed,
;we compute the new bit mask and word position here.
PLM
;-
MLP

REENTR:	OUTSTR	[ASCIZ /Enter new escape character/]

IFN FTPERF,<
	PJOB	T2,			;Me
	MOVNI	T2,(T2)
	JOBSTS	T2,			;Am I logged in?
	  SETO	T2,			;Assume I am
	TXNE	T2,JB.ULI		;?
	 OUTSTR	[ASCIZ | or [P] to enter performance test mode|]
	> ;End IFN FTPERF

REN1:	OUTSTR	[ASCIZ |: |]		;And the close
	INCHRW	T1			;Get new character
	TYPCRLF
	JUMPE	T1,REENTR		;Start over if <NUL>
IFN	FTPERF,<
	TXNN	T2,JB.ULI		;Only if logged in
	  JRST	REN2
	CAIE	T1,"p"			;Lower case OK
	CAIN	T1,"P"			;Is this the performance stuff
	 JRST	DOPERF			;Yes, then do it
>
REN2:	CAIN	T1,15			;Carriage Return?
	  JRST [INCHRS T1		;Yes, get its LF
		  JFCL			;(What? no LF)
		JRST REENT1]		;and leave old escape chr
	MOVEM	T1,ESCCHR		;Store escape character
	PUSHJ	P,CMPESC
REENT1:	TYPCRLF				;Yes, Add a CRLF
	PUSHJ	P,TYPESC		;Say what the escape is
	JRST	G0			;Continue where ^C interrupted
	SUBTTL	Performance analysis -- Start session

PLM
;+
;.hl Routine DOPERF
MLP
;	This routine is entered when performance analysis has been requested.
;It opens the file DSK:NETRSP.DAT for append access and asks the user
;for the comment string for the record and the number of times to
;send the performance analysis string.  It checks to be sure we are
;talking to a TOPS-10 or TOPS-20 remote host and returns to the exit
;dialogue if so as performance analysis only works to those types of systems.
;We output the comment string and various environmental information
;to the data file, set F$PERF and return to G0 to continue the link.
PLM
;-
MLP

IFN FTPERF,<
DOPERF:
	MOVE	T2,OSTYPE		;Get what we are
	CAIE	T2,OST10		;Must be -10
	CAIN	T2,OST20		;Or -20
	  JRST	PERFOK			;Is, let him do it
	OUTSTR	[ASCIZ/
%Performance analysis only works to TOPS-10 or TOPS-20 nodes
/]
	JRST	EXCOPT
PERFOK:	INCHSL	T1			;Eat
	  JRST	DOPR0
	CAIN	T1,.CHCRT		;Carraige return?
	 JRST	PERFOK			;Loop then
	CAIE	T1,.CHLFD		;Line feed?
	 JRST	PERFOK			;Go till we get one
DOPR0:	OUTSTR	[ASCIZ |
NRT Performance Diagnostic tool
|]					;Output a header
	MOVX	T1,<XWD FILHGH,FILBLK>	;BLT pointer for block
	BLT	T1,FILBLK+^D6		;set it all up
	MOVX	T1,<SIXBIT |DAT|>	;Get the extension
	MOVEM	T1,PRFFIL+1		;Save it
	SETZM	PRFFIL+2		;Clear out the rest of the block
	SETZM	PRFFIL+3		;For good measure
	SETZM	PRFFIL+4
	SETZM	FILBLK+.FOPAT		;No path block
	MOVE	T1,[XWD 7,FILBLK]	;Length,,pointer
	FILOP.	T1,			;get the file
	 ERR	FUF,<FILOP. UUO failed to open performance file>
GETCOM:	OUTSTR	[ASCIZ |
Comment string for this record (<CR> when done): 
|]					;Ask for a string
	PUSHJ	P,GETSTR		;Get the string
	MOVE	P2,[POINT 7,COMREC]	;Get byte pointer
	PUSHJ	P,COMOUT		;Output comment record to file
	OUTSTR	[ASCIZ |Number of times to send string: |]
	PUSHJ	P,GETDEC		;Get a decimal number
	MOVEM	P1,TSTREP		;Number of repetitions
	MOVE	T1,[POINT 7,PRFSTR]	;Get a pointer to the test string
	MOVEM	T1,TSTPTR
	MOVE	T1,PRFLEN		;Get the length
	MOVEM	T1,TSTLFT		;Save it
	TXO	F,F$PERF		;Set the flag
	JRST	G0			;And go back to it
	SUBTTL	Performance analysis -- Start a response measurement

PLM
;+
;.hl Routine STTRSP
MLP
;	This routine is called to record a beginning time for a performance
;analysis measurement.  It records the current daytime in UDT format
;and the current MSTIME in variables TSTTIM and TSTBEG, respectively.
PLM
;-
MLP

STTRSP:	MOVX	T1,%CNDTM		;Get the UDT
	GETTAB	T1,			;From the monitor
	 JFCL
	MOVEM	T1,TSTTIM		;Save it
	MSTIME	T1,			;Get the MSTIME for the CPU
	MOVEM	T1,TSTBEG		;Save it
	POPJ	P,			;Return
	SUBTTL	Performance analysis -- Record a response

PLM
;+
;.hl Routine RECRSP
MLP
;	RECRSP gets the current MSTIME and stores the difference
;between it and the MSTIME taken at the time STTRSP was called
;(from variable TSTBEG) in variable TSTTOT.
PLM
;-
MLP

RECRSP:	MSTIME	T1,			;Get the MSTIME at the end
	MOVEM	T1,TSTEND		;Save it
	SUB	T1,TSTBEG		;Get how long it took
	MOVEM	T1,TSTTOT		;Save the time it took him
	PJRST	DATOUT			;Output this delay

	SUBTTL	Performance analysis -- End of session

PLM
;+
;.hl Routine TSTRET
MLP
;	TSTRET is called either when the performance string has been
;sent the specified number of times, or when the user aborts the
;performance analysis experiment by typing the escape character.
;It closes the performance analysis file and proceeds to MONITO to
;enter the exit dialogue again.
PLM
;-
MLP

;Still under FTPERF

TSTRET:	OUTSTR	[ASCIZ |
End of NRT network performance test
|]					;Say that this is the end
	CLOSE	$PRF,			;Close the file
	JRST	MONITO			;Go back to monitor
	SUBTTL	Performance analysis -- Performance string and length

PLM
;+
;.hl Performance string
MLP
;	The performance string is a simple thirty character string which
;is sent to the remote host.  It begins with an exclamation point, which
;is a comment character on TOPS-10 and TOPS-20.
PLM
;-
MLP

;Still under FTPERF

PRFSTR:	ASCIZ	/!1234567890123456789012345678
/
PRFLEN:	EXP	^D30			;Length of PRFSTR in characters
	SUBTTL	Performance analysis -- Get ASCIZ string (for comment)
PLM
;+
;.hl Routine GETSTR
MLP
;	GETSTR reads the comment string for the performance analysis record
;from the controlling TTY:.  The maximum length of a comment string is 250
;(decimal) characters (this is hard coded).  The string is stored
;at location COMREC; P1 contains the number of characters in the record.
PLM
;-
MLP

;Still under FTPERF

GETSTR:	STORE	P1,COMREC,COMREC+^D50-1,0 ;Clear out the record
	MOVSI	P1,-^D250		;Range check it
	MOVE	P2,[POINT 7,COMREC]	;Point to the storage place
GETS1:	INCHWL	T1			;Wait for a character
	CAIN	T1,12			;Is it a LF?
	  JRST	GETS2
	CAIN	T1,15			;<CR>
	 JRST	GETS1			;Eat the LF and end
	IDPB	T1,P2			;Put into the record
	AOBJN	P1,GETS1		;Loop for the next one
	OUTSTR	[ASCIZ/
%Comment string too long, try again
/]
	JRST	GETSTR			;And try again

GETS2:	HRRZS	P1			;Clear left half
	POPJ	P,
	SUBTTL	Performance analysis -- Get character from string

PLM
;+
;.hl Routine GETPRC
MLP
;	GETPRC is called to begin a response measurement and return with
;the next character from the performance analysis string.  It calls STTRSP
;to begin the measurement.  The character is returned in AC T1.  It
;uses only T1.  It returns CPOPJ with the character or CPOPJ1 if no more
;characters are to be sent.
PLM
;-
MLP

;Still under FTPERF

GETPRC:	PUSHJ	P,STTRSP		;Start response measurement
	SOSGE	TSTLFT			;Any characters left?
	 JRST	NXTTST			;No, then repeat the test again
	ILDB	T1,TSTPTR		;Get the character
	POPJ	P,

NXTTST:	SOSG	TSTREP			;Any more left to do?
	  JRST	CPOPJ1			;Skip return, we're done
	MOVE	T1,[POINT 7,PRFSTR]	;Get a pointer to the test string
	MOVEM	T1,TSTPTR
	MOVE	T1,PRFLEN		;Get the length
	MOVEM	T1,TSTLFT		;Save it
	JRST	GETPRC			;And do it again
	SUBTTL	Performance analysis -- Get a decimal number

PLM
;+
;.hl Routine GETDEC
MLP
;	GETDEC is called to input a decimal number from the controlling TTY:.
;It returns with the number in P1 and waits until one is typed.  It uses
;T1, T2, and P1.
PLM
;-
MLP

;Still under FTPERF

GETDEC:	SETZ	P1,			;Zero the count
GETD1:	INCHWL	T1			;Get the digit
	CAIN	T1,.CHCRT		;<CR>
	INCHSL	T1
	  JFCL
	CAIGE	T1," "			;Control?
	CAIN	T1,"	"		;Except <TAB>
	  TRNA
	JRST	GETDE
	SUBI	T1,"0"			;Make it a real number
	CAIL	T1,0			;Legal?
	 CAILE	T1,9			;number
	JRST	GETDER			;Give an error and start over
	IMULI	P1,^D10			;Make this the next one in line
	ADDI	P1,(T1)			;Add into the low part
	JRST	GETD1			;And do the next one

GETDE:	JUMPN	P1,CPOPJ		;Have one
	MOVEI	P1,^D10			;Default is ^D10
	POPJ	P,			;And return

GETDER:	ERR	ILD,<Illegal digit in number - re-input number>,<POPJ P,>
	CLRBFI				;Eat junk
	JRST	GETDEC
	SUBTTL	Performance analysis -- Output a comment to the file

PLM
;+
;.hl Routine COMOUT
MLP
;	COMOUT is called to output a comment record to the performance
;analysis file.  It is called with P1 containing the number of bytes in
;the record and P2 containing the byte pointer ot the string.  Uses T1,
;P1, and P2.
PLM
;-
MLP

;Still under FTPERF

COMOUT:	MOVEI	T1,.PRCOM		;Header type
	PUSHJ	P,OUTPRF		;Output it
	MOVE	T1,P1			;Get the count
	PUSHJ	P,OUTPRF		;And put it into the file
COML:	ILDB	T1,P2			;Get a byte for the file
	ROT	T1,-^D7			;Put it in the high order 7 bits
	PUSHJ	P,OUTPRF		;Output it
	SOJG	P1,COML			;Go to the end

	POPJ	P,			;And return
	SUBTTL	Performance analysis -- Output a data record to the file
PLM
;+
;.hl Routine DATOUT
MLP
;	DATOUT is called to output data to the performance file.  It outputs
;the contents of TSTTIM and TSTTOT to the file (the time the character was
;sent and the time it took for the response).
PLM
;-
MLP

;Still under FTPERF

DATOUT:	MOVEI	T1,.PRDAT		;Get a header item
	PUSHJ	P,OUTPRF		;Output it
	MOVE	T1,TSTTIM		;UDT type
	PUSHJ	P,OUTPRF		;To the file
	MOVE	T1,TSTTOT		;And the differance
	PUSHJ	P,OUTPRF		;Output that also
	POPJ	P,			;And return
	SUBTTL	Performance analysis -- Output any record to the file

PLM
;+
;.hl Routine OUTPRF
MLP
;	OUTPRF outputs a single character (in T1) to the performance
;analysis file.
PLM
;-
MLP

;Still under FTPERF

OUTPRF:	SOSGE	FOBUF+.BFCTR		;Anything left in buffer
	 JRST	PRFOUT			;Then output the buffer
	IDPB	T1,FOBUF+.BFPTR		;Into the buffer with it
	POPJ	P,			;And return now

PRFOUT:	OUT	$PRF,			;The file is on channel $PRF
	 JRST	OUTPRF			;Good return
	GETSTS	$PRF,T1			;For the dump
	ERR	POF,<Performance file output failure>

> ;End IFN FTPERF
	SUBTTL NETICH - Get a network character from the network buffer

PLM
;+
;.hl Routine NETICH
MLP
;	NETICH is called to get one character (returned in T1) from the
;network.  It returns CPOPJ1 with the character if there is one.  If there
;are no remaining characters, the action taken depends on the setting of
;F$NEOM (F$NEOM is cleared regardless of which action is taken).  If
;F$NEOM was clear, we take the error return (CPOPJ).  If F$NEOM was set,
;we call NSPIN which will dismiss any interrupt we are in until data
;is actually available, at which point it will return to us with the new
;buffer.
PLM
;-
MLP

NETICH:	SOSGE	IBFCNT			;Any characters left in the buffer?
	 JRST	ENDBUF			;No, then check for end of message set
	ILDB	T1,IBFPTR		;Get a character
	JRST	CPOPJ1			;And skip return

ENDBUF:	TXZN	F,F$NEOM		;Did we have End of Message?
	  POPJ	P,			;Yes, then just return
	PUSHJ	P,NSPIN			;No, then get the next buffer
	  JRST	NSPERR			;Error return for NSP.
	JRST	NETICH			;And continue on as before

	SUBTTL RBYTEC - Get a byte from the network

PLM
;+
;.hl Routine RBYTEC
MLP
;	RBYTEC is called to input one character from the network and stop
;if none is available.  It calls NETICH and stops with a UED stopcode
;if NETICH takes the error return.
PLM
;-
MLP

RBYTEC:	PUSHJ	P,NETICH		;Read byte with end an error
	 ERR	UED,<Unexpected end to netork data>
	POPJ	P,			;Return
	SUBTTL	CONECT - Routine to set up the connection

;PLM
;+
;.hl Routine CONECT
MLP
;	CONECT is called at initialization time to set up a connection
;to the remote host.  It will first call SETNOD to set up the node name
;to connect to in the destination process descriptor block.  It will
;call NSPEA to decide whether to enter object .OBHTH or .OBPST and do
;the NSP. UUO to perform the enter active function.  It will then send
;the PMR string by exitting through SNDPMR if that is required.
PLM
;-
MLP

CONECT:	PUSHJ	P,SETNOD		;SET UP THE NODE NAME IN THE DEST PDB
	PUSHJ	P,NSPEA			;DO THE ENTER ACTIVE
	  JRST NSPERR
IFN FTPMR,<
	SKIPG	NODCNT			;Doing PMR?
> ;End IFN FTPMR
	  POPJ	P,			;No
IFN	FTPMR,<
	FALL	SNDPMR
>
	SUBTTL SNDPMR - Send the PMR string to the remote system

PLM
;+
;.HL Routine SNDPMR
MLP
;	SNDPMR is entered from CONECT if a PMR string must be sent.
;The PMR message has already been assembled by DOPMR at location PMRMSG.
PLM
;-
MLP

IFN FTPMR,<

SNDPMR:	MOVE	NSAFN,[NS.WAI!NS.EOM!<.NSFDS,,.NSAA2+1>]
	MOVE	NSAA1,PMRCNT
	MOVE	NSAA2,[POINT 8,PMRMSG,]
	MOVEI	T1,NSAFN
	NSP.	T1,
	  ERR	PMR,<Can't send PMR string>
	POPJ	P,

> ;End IFN FTPMR
	SUBTTL	Error Routines -- SETNER - Set up NSPECD with error code

PLM
;+
;.hl Routine SETNER
MLP
;	SETNER is called with a NSP. UUO error code in T1 to store it
;for later analysis by the NSPERR routine.
PLM
;-
MLP

SETNER:	MOVEM	T1,NSPECD	;Store NSP. error code for NSPERR
	POPJ	P,		;Only return

	SUBTTL Error Routines -- NSPERR - Give an NSP. error message

PLM
;+
;.hl Routine NSPERR
MLP
;	NSPERR is called when any NSP. UUO error code is encountered.  The
;code has been previously stored in location NSPECD, probably by the SETNER
;routine.  If the current state of the connection in DR, we output the
;message "[Connection to remote node aborted]"; otherwise we output a
;standard DECnet error message with the numeric code of the error.  The
;program is exitted and set up to not continue.
PLM
;-
MLP

NSPERR:
	PUSH	P,NSAFN			;Save the current function
	PUSHJ	P,WATDEQ		;Wait for output to quiet down
	MOVE	NSAFN,[NS.WAI!<.NSFRS,,.NSACH+1>]
	MOVEI	T1,NSAFN
	NSP.	T1,
	  JFCL
	LDB	T1,[POINT 6,NSACH,^L<NS.STA>+5]
	CAIN	T1,.NSSDR		;State Disconnect Received?
	  JRST	[OUTSTR	[ASCIZ/
[Connection to remote node aborted]/]	;Output nice message instead
		 JRST	NSPER1]		;Finish nicely
	POP	P,NSAFN			;Restore the failing function now
	MOVE	T1,NSPECD		;Get the error code
IFN	FTPMR,<
	JUMPE	T1,NSPER1		;If PMR, assume zero is routing failure
>
	OUTSTR	[ASCIZ/
?NRT/]
	IMULI	T1,2			;prefix & text
	OUTSTR	@NSPERC(T1)		;Output the refix
	LDB	T1,[POINTR(NSAFN,NS.AFN)] ;GET FUNCTION CODE FROM ARGS
	CAILE	T1,FCNTBL	;OFFSET OK?
	MOVEI	T1,0		;NO, CALL IT ILLEGAL
	MOVE	T2,[-1,,.GTWCH]		;Get the watch bits for this job
	GETTAB	T2,			;Do the GETTAB
	 SETOM	T2			;Set them all
	LDB	T2,[POINTR (T2,JW.WMS)]	;Get the level bits
	TXNE	T2,.JWWPR		;Prefix only?
	 JRST	NSPER1			;Finished with error message
	OUTSTR	[ASCIZ | Network |] ;Make it sound bad
	OUTSTR	@FCNTAB(T1)		;Output the text
	OUTSTR	[ASCIZ | failure |]	;And the failure part
	MOVE	T1,NSPECD	;GET ERROR CODE SET UP BY SETNER
	IMULI	T1,2		;allow for prefix
	CAIG	T1,MAXERR	;DO WE KNOW THIS ERROR CODE?
	SKIPA	T1,NSPERC(T1)	;GET THE POINTER TO THE ERROR TEXT
	MOVEI	T1,[ASCIZ/Out of range/]-1
	OUTSTR	1(T1)		;GIVE THE ERROR CODE
IFN FTFUNCTION,<
	OUTSTR	[ASCIZ /, function /]
	LDB	T1,[POINTR(NSAFN,NS.AFN)] ;GET FUNCTION CODE FROM ARGS
	CAILE	T1,FCNTBL	;OFFSET OK?
	MOVEI	T1,0		;NO, CALL IT ILLEGAL
	MOVE	T1,FCNTAB(T1)	;GET PTR TO ASCIZ STRING
	OUTSTR (T1)		;OUTPUT THE STRING
>;END OF IFN FTFUNCTION
	TYPCRLF
NSPER1:	PUSHJ	P,TTYRST	;Be sure the TTY: gets unslaved
	SETZM	.JBREN		;Tell REENTER its not OK to REENTER
	CLRBFI			;Clear out his input buffer in case of type ahead
	PJOB	T1,		;Get the job number
	MOVNS	T1		;Set up for JOBSTS
	JOBSTS	T1,		;Do the JOBSTS
	 JRST	TYPDOT		;Then type out a DOT
	TXNN	T1,JB.ULI	;Is job logged in?
TYPDOT:	OUTSTR	[ASCIZ |
.|]				;Type out the dot
	SETZM	TIBUF		;Be sure we don't reset again.
	RESET			;Clear the world
	EXIT	1,		;Polite return to monitor
	JRST	RESTRT		;Restart on CONTINUE

	SUBTTL Error Routines -- DOERR - Output an error message
PLM
;+
;.hl Routine DOERR
MLP
;	DOERR is called via the ERR MACRO.  Its purpose is to output the
;text and prefix part of the message.  DOERR is responsible for observing
;the user's verbosity bit settings.  It is called with text of the error
;at (P)+1 and the prefix at (P)+2.  The program cannot be continued.
PLM
;-
MLP

DOERR:	ASSUME	P,17			;P must be last for code to work
	MOVEM	P,CRSACS+P
	MOVEI	P,CRSACS
	BLT	P,CRSACS+P-1		;Save error ACs
	MOVE	P,CRSACS+P		;Restore old P
	HRRZ	T1,(P)			;Get return address
	HRRZ	T1,(T1)			;Get the address
	OUTSTR	[ASCIZ |
?NRT|]
	OUTSTR	(T1)			;and the text
	OUTCHR	[11]			;Output a tab
	MOVE	T2,[-1,,.GTWCH]		;Get the watch bits for this job
	GETTAB	T2,			;Do the GETTAB
	 SETOM	T2			;Set them all
	LDB	T2,[POINTR (T2,JW.WMS)]	;Get the level bits
	HRRZ	T1,(P)			;Get 1+return address
	HRRZ	T1,1(T1)		;And the message
	TXNN	T2,.JWWPR		;Prefix only?
	 OUTSTR	(T1)			;and the message
	TYPCRLF
	POPJ	P,			;Return to finish up

	SUBTTL NSPERC - NSP. Error message table

PLM
;+
;.hl Table NSPERC
MLP
;	The NSPERC table uses the ERRMAC MACRO to assemble a table
;of text and prefixes for standard DECnet error codes.
PLM
;-
MLP

NSPERC:	ERRMAC 0,UEC,<Unknown Error Code>
	ERRMAC NSABE%,ABE,<Argument Block Format Error>
	ERRMAC NSALF%,ALF,<Allocation failure>
	ERRMAC NSBCN%,BCN,<Bad channel number>
	ERRMAC NSBFT%,BFT,<Bad format type in process block>
	ERRMAC NSCFE%,CBE,<Connect Block format error>
	ERRMAC NSIDL%,IDL,<Interrupt data too long>
	ERRMAC NSIFM%,IFM,<Illegal flow control mode>
	ERRMAC NSILF%,ILF,<Illegal function>
	ERRMAC NSJQX%,JQE,<Job quota exhausted>
	ERRMAC NSLQX%,LQE,<Link quota exhausted>
	ERRMAC NSNCD%,NCD,<No connect data to read>
	ERRMAC NSPIO%,POB,<Percentage input out of bounds>
	ERRMAC NSPRV%,NEP,<No Privileges to Perform Function>
	ERRMAC NSSTB%,OBS,<Obsolete>
	ERRMAC NSUKN%,UNN,<Unknown node name>
	ERRMAC NSUXS%,UNS,<Unexpected State: Unspecified>
	ERRMAC NSWNA%,WNA,<Wrong number of arguments>
	ERRMAC NSWRS%,FWS,<Function called in wrong state>

;New error codes (to be re-ordered):

	ERRMAC NSCBL%,CBL,<Connect block length error>
	ERRMAC NSPBL%,PBL,<Process block length error>
	ERRMAC NSSBL%,SBL,<String block length error>
	ERRMAC NSUDS%,DSN,<Unexpected State: Disconnect Sent>
	ERRMAC NSUDC%,DCN,<Remote node not accepting connects>
	ERRMAC NSUCF%,RNR,<Remote node not responding>
	ERRMAC NSULK%,RBL,<Remote Node broke link to local node>
	ERRMAC NSUCM%,NNR,<Network Node not currently reachable>
	ERRMAC NSUNR%,RSR,<Remote system out of resources>

;Error codes which correspond to DECnet disconnect codes.

	ERRMAC NSRBO%,RTR,<Remote terminal server rejected connection>
	ERRMAC NSDBO%,RTB,<Remote terminal server broke link>
	ERRMAC NSRES%,NRR,<No Resources at Remote Node>
	ERRMAC NSUNN%,UNN,<Unrecognized Node Name>
	ERRMAC NSRNS%,RNS,<Remote Node Shut Down>
	ERRMAC NSURO%,NRT,<No remote terminal server at node>
	ERRMAC NSIOF%,ION,<Invalid Object Name Format>
	ERRMAC NSOTB%,OTB,<Object Too Busy>
	ERRMAC NSABM%,NMA,<Network Management aborted connection>
	ERRMAC NSABO%,RTA,<Remote terminal server aborted connection>
	ERRMAC NSINF%,INN,<Invalid Node Name Format>
	ERRMAC NSLNS%,LNS,<Local Node Shut Down>
	ERRMAC NSACR%,SPR,<System Password rejected>
	ERRMAC NSNRO%,RTO,<Remote Terminal server did not reply in time>
	ERRMAC NSNUR%,NNR,<Node Unreachable>
	ERRMAC NSNLK%,NLN,<No Link>
	ERRMAC NSDSC%,DCM,<Disconnect Complete>
	ERRMAC NSIMG%,IFL,<Image Field Too Long>
	ERRMAC NSREJ%,URR,<Unspecified Reject Reason>

	ERRMAC NSBCF%,BCF,<Bad combination of NS.EOM & NS.WAI flags>
	ERRMAC NSADE%,ADE,<Address Error>

MAXERR==.-NSPERC-1

	SUBTTL FCNTAB - NSP. function text table

PLM
;+
;.hl Table FCNTAB
MLP
;	FCNTAB is the table of text descriptions of each function
;to the NSP. UUO.  Its primary purpose is for the typeout of
;functions if NRT is assembled with FTFUNCTION turned on; however,
;the maximum offset is also considered to be the maximum NSP. function
;we should be doing and is used as a legality check in the error routines.
PLM
;-
MLP

FCNTAB:	FCNMAC 0, <Illegal function code>
	FCNMAC .NSFEA,<Connection>
	FCNMAC .NSFEP,<Enter Passive>
	FCNMAC .NSFRI,<Connection>
	FCNMAC .NSFAC,<Accept Connect>
	FCNMAC .NSFRJ,<Reject Connect>
	FCNMAC .NSFRC,<Connection>
	FCNMAC .NSFSD,<Synchronous Disconnect>
	FCNMAC .NSFAB,<Abort>
	FCNMAC .NSFRD,<Read Disconnect Data>
	FCNMAC .NSFRL,<Release Channel>
	FCNMAC .NSFRS,<Read Channel Status>
	FCNMAC .NSFIS,<Send Interrupt Data>
	FCNMAC .NSFIR,<Receive Interrupt Data>
	FCNMAC .NSFDS,<Send>
	FCNMAC .NSFDR,<Receive>
	FCNMAC .NSFSQ,<Set Quotas>
	FCNMAC .NSFRQ,<Read Quotas>
	FCNMAC .NSFJS,<Set Job Quotas>
	FCNMAC .NSFJR,<Read Job Quotas>
	FCNMAC .NSFPI,<Set PSI Reasons>
FCNTBL==.-FCNTAB

	SUBTTL	XMTMSG -  Transmit network message
PLM
;+
;.hl Routines XMTMSG and XMTMSS
MLP
;	These routines are called to send output to the network.
;XMTMSG is called with T1 pointing to a message block which consists
;of the number of bytes in the message located in the first word, followed
;by the message.  XMTMSS is used to force out current network output.
;XMTMSS merely calls NSPOUT and stopcodes on any error.
PLM
;-
MLP

XMTMSG:	SKIPN	P4,(T1)			;Get char count
	  POPJ	P,
	HRLI	T1,(POINT 8,,35)	;8-BIT BYTES
XMTMS1:	ILDB	P3,T1			;get
	NETOCH	P3			;Output a network character
	SOJG	P4,XMTMS1		;Copy it
XMTMSS:	PUSHJ	P,NSPOUT		;SEND OUT THE BUFFER
	  JRST	[PUSHJ	P,NSPERR	;Report the error
		 JRST	XMTMSS]		;..
	POPJ	P,

	SUBTTL TTYOPN - Routine to OPEN the TTY

PLM
;+
;.hl Routine TTYOPN
MLP
;	TTYOPN is called to open device TT:.  This is normally the same as
;device TTY:, except it can be reassigned away to another terminal to
;aid debugging.  Note that the feature of hitting the break twice
;can have inconsistent results if TT: is assigned to a terminal other than
;TTY:.  We remember the UDX of the terminal here in the variable
;TTYUDX and the UDX position in various other TRMOP. blocks.
;The TTY: is OPENed in ASCII line mode with asynchronous I/O.
;The TTY: is added to the sofware interrupt system at this point.
;We also save the TTY: characteristics specified in table TTYSAV here.
;We also read the TTY: baud rate here so we can do the fancy
;segment size and quotas/goals code later for those systems which want it.
;Finally, we read the type of TTY: this is and save it for any
;fancy configuration messages which may have to be sent (e.g. VMS).
PLM
;-
MLP

TTYOPN:	MOVE	T1,[BMASK,,IMASK]	;Set up default break mask
	BLT	T1,ENDMSK		;Set default mask up
	MOVE	T1,[BMASK+1,,LMASK]	;Set the logical mask too	
	BLT	T1,ELMASK
	MOVE	T1,[UU.AIO!.IOASL]	;Set line mode
	MOVEM	T1,TTYBLK
	SETO	T2,			;Ourselves
	TRMNO.	T2,			;Get controlling TTY:
	  SETO	T2,
	MOVEM	T2,CTLTTY		;In case different from I/O TTY:
	MOVE	T2,TTYBLK+.OPDEV	;Get device
	IONDX.	T2,
	  SETO	T2,
	MOVEM	T2,TTYUDX
	MOVEM	T2,HPSUDX		;For horizontal position
	MOVEM	T2,LEDUDX		;For checking line editing stuff
	MOVEM	T2,ECCUDX		;For checking echo count
	MOVEM	T2,BKCUDX		;Count or break characters
	MOVEM	T2,CTOUDX		;For checking ^O bit
	MOVEM	T2,COSUDX		;For setting ^O
	MOVEM	T2,PAGUDX		;For checking the page bit
	OPEN	$TTY,TTYBLK		;Open the TTY:
	 ERR	ODT,<OPEN of device TTY failed>
	INBUF	$TTY,1			;One input buffer
	OUTBUF	$TTY,10			;Get the buffers
	MOVEI	T1,TTYBLK		;Point to the block
	DEVSIZ	T1,			;...
	  ERR	DSF,<DEVSIZ for device TTY: failed>
	MOVEI	T1,-3(T1)		;Subtract header
	HLL	T1,TOBFH+.BFPTR		;Left half of pointer
	MOVEM	T1,BUFCHR		;Save the characteristics
	SOJ	T1,			;Last word of a buffer
	HRLI	T1,T2			;Indexed by T2
	MOVEM	T1,LASTT2		;Save it
	MOVEI	T1,1(T1)		;Increment back, clear left half
	IMULI	T1,5			;We're starting in ASCII
	MOVEM	T1,CHPBUF		;Characters per buffer
	MOVEI	T1,5
	MOVEM	T1,BYTPWD		;Save it
	MOVSI	T4,-TSVNUM		;Read TTY: characteristics
TSVLP:	HRRZ	T1,TTYSAV(T4)		;Get characteristic
	MOVE	CX,[2,,T1]
	TRMOP.	CX,
	  SETZ	CX,
	HRLM	CX,TTYSAV(T4)
	AOBJN	T4,TSVLP
;The below are done separately so we won't try to reset them later.
	MOVE	CX,[2,,T1]	;Find receive speed so can...
	MOVEI	T1,.TOTSP	;Set the seg size
	TRMOP.	CX,
	  SETZ	CX,		;Assume max
	MOVEM	CX,TTBAUD	;Save it
	MOVE	CX,[2,,T1]
	MOVEI	T1,.TOTRM		;Get the TTY: type
	TRMOP.	CX,
	  SETZ	CX,
	MOVSI	T1,-TTPLEN		;Length of type table
TTYPLP:	CAME	CX,TTPTB(T1)		;This type?
	AOBJN	T1,TTYPLP
	SKIPL	T1			;If actually found one
	  SETO	T1,
	HRREM	T1,TTYTYP		;Save the index
	MOVE	T1,[PS.FAC!T2]
	MOVEI	T2,$TTY			;Channel to add
	MOVE	T3,[TTYVEC-VECBAS,,PS.RID!PS.REF!PS.ROD]	;Input done
	MOVSI	T4,1			;PI level 1
	PISYS.	T1,			;Add it
	  ERR	CTP,<Can't add TTY: to PSI system>	;Can't
	POPJ	P,			;Return with it set up
	SUBTTL	Routine to set desired TTY: characterstics

PLM
;+
;.hl Routine SETTTY
MLP
;	SETTTY is called at initialization time to set any characteristics
;we desire to be set on the user's TTY:.  The characteristics should have
;previously been saved.  This routine is table driven through
;the TTYSET table.
PLM
;-
MLP

SETTTY:	MOVSI	T4,-TSTNUM
	MOVE	CX,[3,,T1]
	MOVE	T2,TTYUDX
TTSTLP:	HRRZ	T1,TTYSET(T4)
	MOVEI	T1,.TOSET(T1)
	HLRE	T3,TTYSET(T4)
	TRMOP.	CX,
	MOVE	CX,[3,,T1]
	AOBJN	T4,TTSTLP
	POPJ	P,				;Return with it slaved
	SUBTTL	Routine to reset the TTY: characteristics

PLM
;+
;.hl Routine TTYRST
MLP
;	TTYRST is called upon returning to monitor level or executing
;the exit dialogue.  It restores the characteristics saved in the
;TTYSAV table.  Enter at TTYRS1 if only the TRMOP. characteristics are to
;be done and the TTY: is not to be set to normal ASCII line mode.
PLM
;-
MLP

TTYRST:	SKIPN	TIBUF			;Anything set up?
	  POPJ	P,			;No
	SETSTS	$TTY,.IOASL		;Set to a "normal" mode
	TLZ	F,(F$CVL)		;Clear all convert bits
TTYRS1:	MOVSI	T4,-TSVNUM
	MOVE	CX,[3,,T1]
	MOVE	T2,TTYUDX
TRSTLP:	HRRZ	T1,TTYSAV(T4)
	MOVEI	T1,.TOSET(T1)
	HLRZ	T3,TTYSAV(T4)
	TRMOP.	CX,
	  MOVE	CX,[3,,T1]		;Ignore error
	AOBJN	T4,TRSTLP
	PJRST	CLRCO1			;Undo ^O for now
	SUBTTL	TTY: Output and Echo Routines

PLM
;+
;.hl TTY: Output and Echo Routines
MLP
;	This section contains routines to output characters and strings
;to the TTY:
PLM
;.list 1
;.le
MLP
;STROUT accepts the address of an ASCIZ string in T4 and outputs the string
;to the TTY:.  It uses T1 and T4.
PLM
;-
MLP

STROUT:	HRLI	T4,(POINT 7,,)
STRLP:	ILDB	T1,T4			;Get character
	JUMPE	T1,CPOPJ		;Done
	PUSHJ	P,OUTTTY		;Copy it
	JRST	STRLP			;Continue

PLM
;+
;.le
MLP
;OUTTTY accepts a character in T1 to output to the TTY:.  AC CX is used.
PLM
;-
MLP
 
OUTTTY:	SOSGE	TOBUF+2			;Any character space left?
	 JRST	DOOUT			;No, Then output the current buffer
	TXNN	F,F$PIM			;PIM?
	  PUSHJ	P,DOHPOS		;No, compute HPOS
	IDPB	T1,TOBUF+1		;Output the buffer
	POPJ	P,			;And return to caller

DOOUT:	AOS	TOBUF+2			;Not really -1 characters left
	PUSHJ	P,DOOUT1		;Do the actual out
	JRST	OUTTTY			;And try again

PLM
;+
;.le
MLP
;EKOBRK does break string echoing.  Call with T4=AOBJN pointer to break table
;and T1 containing the break character to echo.  Uses T1, T2, and T4.
PLM
;-
MLP

EKOBRK:	TXNE	F,F$ESC			;Escape sequence processing?
	CAIE	T1,.CHESC		;And processing an escape?
	  TRNA				;No to one of the above
	POPJ	P,			;Done
	HLRZ	T2,(T4)
	CAIE	T2,(T1)			;The right character?
	AOBJN	T4,EKOBRK
	JUMPL	T4,EKOBR1		;Found
	CAIGE	T4," "			;Printing?
	  POPJ	P,			;No, ignore
	PUSHJ	P,OUTTTY		;Output character
	JRST	DOOUT1			;Force out
EKOBR1:	HRRZ	T4,(T4)			;Point to echo string
	PUSHJ	P,STROUT		;Output the string
	FALL	DOOUT1			;Fall into DOOUT1

PLM
;+
;.le
MLP
;DOOUT1 is called to force out any remaining output to the TTY:
;The buffer is queued for output and we allocate a new one.
;We then fall into TOOUT to try to push data out to the TTY:.
;AC CX is used.  Note that if location BUFQUO becomes zero or negative,
;DOOUT1 willcall TOBLOK to sleep until a buffer is available.
PLM
;-
MLP

DOOUT1:	PUSH	P,T1			;Save T1
	TXNN	F,F$PIM			;PIM?
	  PUSHJ	P,STHPOS		;Set HPOS then
	SKIPN	TOBUF			;Is there really one?
	  JRST	TOQ5			;No
	MOVE	T1,CHPBUF		;Get total number of available chars
	SUB	T1,TOBUF+2		;Real number of characters
	JUMPLE	T1,TPOPJ		;Nothing to do
	SOSGE	BUFQUO			;Any more buffers left?
	  PUSHJ	P,TOBLOK		;Wait for output to come back
	IOR	T1,TOFLGS		;Include the flag bits
	HRLM	T1,@TOBUF		;Store the count
TOQOUT:	HRRI	T1,TOQUE-TOB.LK		;Point to output queue
TOQ1:	HRL	T1,TOB.LK(T1)		;Get link
	TLNN	T1,-1			;Another buffer?
	  JRST	TOQ4			;No
	HLRZS	T1			;Point ahead
	JRST	TOQ1			;Continue

TOQ4:	HRL	T1,TOBUF		;Get buffer pointer
	HLRM	T1,TOB.LK(T1)		;Link it in
TOQ5:	HRRZ	T1,BUFCHR		;Size of buffer
	MOVEI	T1,TOB.DT(T1)		;Include link word
	PUSHJ	P,CORGET		;Get core block
	HLL	T1,BUFCHR		;Header pointer
	MOVEM	T1,TOBUF+1		;Pointer
	HRRZM	T1,TOBUF		;The buffer
	MOVE	T1,CHPBUF		;Number of characters per buf
	MOVEM	T1,TOBUF+2		;Set it
	POP	P,T1			;Restore T1
	FALL	TOOUT

PLM
;+
;.le
MLP
;TOOUT is called either at interrupt level to try to output more data
;to the TTY:, or we fall into it from DOOUT1 to try to force out
;data.  It dequeues TTY: buffers queued for output.  AC CX used.
;If entered at TOOUTA, T1-T4 are used also.
PLM
;-
MLP

TOOUT:	PUSHJ	P,SAVT			;Save T1-T4
TOOUTA:	TXZN	F,F$IEC			;Ignore ECC?
	TXNE	F,F$USRV!F$PIM		;Already have input? or PIM?
	  JRST	TOOUTB			;ECC not reliable then
	MOVE	T1,[2,,BKCTRM]		;Any break characters?
	TRMOP.	T1,
	  SETZ	T1,
	JUMPN	T1,TOOUTB		;Yes, ignore ECC
	MOVE	T1,[2,,ECCTRM]		;Check the echo stream
	TRMOP.	T1,			;..
	  SETZ	T1,
	JUMPN	T1,CPOPJ		;Don't start output if echo pending
TOOUTB:	MOVEI	T1,PS.ROD		;Going to service this now
	ANDCAM	T1,TTYSTS		;..
	MOVEI	T3,TOQUE		;Where to point
	SKIPLE	TOBFH+.BFCTR		;Any space?
	  JRST	TOOUT1			;Yes, go BLT in data
TOOUT0:	SKIPGE	TTYUDX			;Got detached?
	  PUSHJ	P,DETWAT		;Wait
;Note there's a window here where you can get stuck
;if we get detached at exactly this point.
	OUT	$TTY,			;Do the output
	  TRNA				;Fine
	JRST	CHKERR			;See if got detached
TOOUT1:	SKIPE	T1,(T3)			;Anything to output?
	TRNN	T1,-1			;Really anything?
	  POPJ	P,
	HLRE	T2,TOB.CT(T1)		;Get count
	ASSUME	F$IOQ,<1B0>
	JUMPGE	F,TOOUT4		;Don't worry about inhibit bit
	TRNE	T2,($TOOIN)		;Override?
	  JRST	TOOUT4			;Yes
	MOVEI	T3,(T1)			;Point ahead
	JRST	TOOUT1
TOOUT4:	ANDI	T2,($TOCNT)		;Preserve only count
	HRLI	T1,TOB.DT(T1)		;Point to data
	HRR	T1,TOBFH+.BFPTR		;Data area
	IBP	TOBFH+.BFPTR		;Normalize
	SOJLE	T2,NOADJ		;If nothing more to increment by
	ADJBP	T2,TOBFH+.BFPTR		;Increment the pointer
	MOVEM	T2,TOBFH+.BFPTR		;Store it
NOADJ:	ASSUME	TOB.DT,1
	AOS	T2,T1			;Point to real area
	BLT	T1,@LASTT2		;Move data
	SETOM	TOBFH+.BFCNT		;Set count to -1
	HRRZ	T1,(T3)			;Point to buffer
	HRRZ	T2,TOB.LK(T1)		;Link to next
	HRRM	T2,(T3)			;Point to it
	HRRZ	T2,BUFCHR		;Size of buffer
	MOVEI	T2,TOB.DT(T2)		;Increment
	PUSHJ	P,CORFRE		;Free the buffer
	AOS	BUFQUO			;Just freed a buffer
	JRST	TOOUT0			;and try to output


CHKERR:	GETSTS	$TTY,T1			;Get the status
	TRNE	T1,IO.ERR&<-1!IO.EOF>	;Any error bits?
	  ERR	OTF,<OUT to TTY: failed>
	TRNN	T1,IO.EOF		;EOF?
	  POPJ	P,
	MOVEI	T1,PS.REF		;Clear EOF pending
	ANDCAM	T1,TTYSTS
	CLOSE	$TTY,			;Clear the EOF
	JRST	TOOUT0			;Try again

DETWAT:	MOVEI	T1,^D60			;Time to sleep
	PUSHJ	P,TOHIBR
	SKIPGE	TTYUDX			;Still waiting?
	  JRST	DETWAT			;Nope
	POPJ	P,

PLM
;+
;.le
MLP
;CLRTOQ	is called to clear all output in progress; both queued buffers
;and that currently being output.  CLRTOQ does NOT clear buffers which
;have the $TOICL bit on in the buffer status word.  CLRTOQ DOES
;do a Clear Output Buffer TRMOP.  It uses nothing.
PLM
;-
MLP

CLRTOQ:	PUSHJ	P,PIOSAV			;Since we're mucking  with the queues
	PUSHJ	P,SAVT				;Save the Ts
	MOVE	T1,[2,,T2]			;Clear any output in progress
	MOVEI	T2,.TOCOB			;Clear output
	MOVE	T3,TTYUDX
	TRMOP.	T1,
	  JFCL
	HRRZ	T2,BUFCHR			;Size of output buffer
	MOVEI	T2,1(T2)			;Including link word
	MOVEI	T4,TOQUE-TOB.LK			;Start
	MOVSI	T3,($TOICL)			;Inhibit clearing
CLRTO1:	SKIPE	T1,TOB.LK(T4)			;Anything in queue?
	TRNN	T1,-1				;Really one there?
	  POPJ	P,				;Return if nothing
	TDNE	T3,TOB.FL(T1)			;Inhibit clear?
	  JRST	CLRTO2				;No
	HRRM	T3,TOB.LK(T4)			;De-link it
	AOS	BUFQUO				;Add another buffer
	PUSHJ	P,CORFRE
	JRST	CLRTO1				;Continue

CLRTO2:	MOVE	T4,T1				;New last chunk
	JRST	CLRTO1				;Continue
PLM
;+
;.end list
;-
MLP
	
	SUBTTL	Set Horizontal Position

PLM
;+
;.hl Horizontal position tables and routines
MLP
;These routines are called to set and compute the horizontal position
;correctly.  They all use only CX.
PLM
;.list 1
;.le
;DOHPOS and STHPOS
MLP
;DOHPOS does the "right" thing to variable HPOS given the
;character in T1.  It should be called when a character is put in the
;TTY: output buffer.  STHPOS sets the monitor's value of HPOS to ours.
;This should be called just before outputting a buffer.  This is done
;because image mode doesn't do the right thing for us.
PLM
;-
MLP

STHPOS:	MOVE	CX,[3,,HPSTRM]		;The TRMOP.
	TRMOP.	CX,
	  JFCL
	POPJ	P,

DOHPOS:	CAIL	T1," "			;Printing?
	CAILE	T1,174			;?
	  JRST	DOHPS1			;No
	AOS	HPOS
	POPJ	P,			;Do simple thing

DOHPS1:	CAIL	T1," "		;The real controls?
	  POPJ	P,		;No, don't do anything
	MOVEI	CX,(T1)		;Dupe character
	LSH	CX,-1		;Shift
	TRNE	T1,1		;Was it odd?
	SKIPA	CX,HPSTBL(CX)	;Yes, use right side
	HLRZ	CX,HPSTBL(CX)	;Else use left
	TRNE	CX,-1
	  JRST	(CX)		;Go if routine
	POPJ	P,		;Else return
PLM
;+
;.le
MLP
;HPSTBL is the dispatch table, in half word addresses, indexed by
;character, of what to do to HPOS for a given character.  A zero entry
;means do nothing.
PLM
;-
MLP

HPSTBL:	Z			;<NUL>,^A
	Z			;^B,^C
	Z			;^D,^E
	Z			;^F,^G
	CHHPOS,,CIHPOS		;^H,<TAB>
	Z			;<LF>,<VT>
	0,,CMHPOS		;<FF>,<CR>
	Z			;^N,^O
	Z			;^P,^Q
	Z			;^R,^S
	Z			;^T,^U
	Z			;^V,^W
	Z			;^X,^Y
	Z			;^Z,<ESC>
	Z			;34,35
	Z			;36,37
PLM
;+
;.le
MLP
;CHHPOS sets HPOS for a backspace.  CMHPOS zeroes HPOS for a <CR>.
PLM
;-
MLP

CHHPOS:	SOSGE	HPOS
CMHPOS:	  SETZM	HPOS				;No negative positions
	POPJ	P,

PLM
;+
;.le
;CIHPOS sets HPOS for a <TAB>.
PLM
;-
MLP

CIHPOS:	MOVEI	CX,7			;Round up
	ADD	CX,HPOS				;By seven
	ANDCMI	CX,7				;Back to next multiple
	MOVEM	CX,HPOS
	POPJ	P,

;PLM
;+
;.end list
;-
MLP
	SUBTTL	Miscellaneous terminal routines

PLM
;+
;.hl Routine OUTCRL
MLP
;	OUTCRL is called to output a <CR><LF> to the TTY:
PLM
;-
MLP

OUTCRL:	PUSH	P,T1		;Save current character
	MOVEI	T1,.CHCRT		;Get a CR
	PUSHJ	P,OUTTTY		;Output to the TTY
	MOVEI	T1,.CHLFD		;Get a LFD
	PUSHJ	P,OUTTTY		;Output the LFD
	POP	P,T1			;Restore character
	POPJ	P,			;And return to caller
	SUBTTL	TTY Input Routines -- INCHR - Get terminal character

PLM
;+
;.hl Routine INCHR
MLP
;	INCHR is called to get a character from the input buffer.
;The characters have actually already been input in the operating
;system independent interrupt service routine; we are here just
;taking them from our internal buffers.  Returns CPOPJ1 with
;character in T1, or CPOPJ if there are no more.  If a character
;has been stored in variable INPCHR, this is read instead.  This
;is a method of forcing a character to be processed immediately.
;Note that ICHCNT is only an upper bound on the number
;of characters available; this is because SCNSER in reality returns
;a word count rather than a byte count.  This routine uses T1-T2.
PLM
;-
MLP

INCHR:	SKIPE	T1,INPCHR		;Leftover character to read?
	 JRST	[SETZM	INPCHR		;Yes. eat it
		 SOS	ICHCNT		;Adjust ICHCNT
		 JRST	CPOPJ1]		;and win
INCHR0:	PUSHJ	P,TTYCHR		;Get character from TTY:
	  POPJ	P,			;None to read
	ANDI	T1,177			;Mask to 7 bits
INCHR1:	TXNE	F,F$PIM			;In line mode?
	  JRST	CPOPJ1			;No, then all is legal
	JUMPE	T1,INCHR0		;If null, eat it
	JRST	CPOPJ1			;And return

TTYCHR:
	SKIPE	T1,INPQUE		;Anything in queue?
	SOSGE	ICHCNT			;Any characters left?
	  JRST	NOCHRS			;None to input
TTYCH1:	SOSGE	IBF.CT(T1)		;Any more chars in this buffer?
	  JRST	NEWIBF			;No, go to next
	ILDB	T1,IBF.PT(T1)		;Get character
	JRST	CPOPJ1			;And return with it

NOCHRS:	SKIPN	T1,INPQUE		;Anything in queue?
	  POPJ	P,			;No
	HRRZ	T2,IBF.LK(T1)		;This should be zero, but just in case
	HRRZM	T2,INPQUE
	HLRE	T2,IBF.LK(T1)		;Return it if so (should be only 1!)
	PUSHJ	P,CORFRE
	JRST	NOCHRS			;Check to be sure all deallocate

NEWIBF:	PUSH	P,T2			;Save T2
	HRRZ	T2,IBF.LK(T1)		;Point to next entry
	HRRZM	T2,INPQUE		;Point to next
	HLRE	T2,IBF.LK(T1)		;Get size of this buffer
	PUSHJ	P,CORFRE		;Free the old buffer
	HRRZ	T1,INPQUE		;Clear left half, put in T1
	POP	P,T2			;Restore T2
	JUMPN	T1,TTYCH1		;Be defensive
	POPJ	P,
	SUBTTL	Output SIXBIT argument to controlling TTY:
PLM
;+
;.hl Routine .TSIX
MLP
;	.TSIX is called by th TSIX MACRO.  The MACRO pushes the argument
;onto the stack and calls .TSIX.  No ACs are used.
PLM
;-
MLP

.TSIX:	EXCH	T1,-1(P)			;Fetch argument
	PUSH	P,T2
.TSIXL:	SETZ	T2,
	ROTC	T1,6
	MOVEI	T2,<" "-' '>(T2)
	OUTCHR	T2
	JUMPN	T1,.TSIXL
	POP	P,T2
	EXCH	T1,-1(P)
	POPJ	P,			;Return
	SUBTTL	Node Name Output Routines

PLM
;+
;.hl Routines TNODE and TNDLST
MLP
;	These routines are used to output a single node (supplied in T2)
;and a list of nodes (for Poor Man's Routing; supplied from table RNODE),
;respectively.  TNODE expects the node name in T2 and does not use an ACs;
;TNDLST uses CX and T2.
PLM
;-
MLP

TNODE:
IFN FTPMR,<
	SKIPE	NODCNT			;Doing PMR
	 JRST	TNDLST			;Type the whole list
> ;End IFN FTPMR
TNODE1:	TSIX	T2
	POPJ	P,			;Return

IFN FTPMR,<
;< ;This is here so that MACRO will not get confused

TNDLST:	OUTSTR	[ASCIZ |, Routing => |]	;Tell him how he is getting there
	SETZ	CX,			;Clear out a flag
TNDL1:	MOVE	T2,RNODE(CX)		;Type it out
	JUMPE	T2,CPOPJ		;Return when done
	TSIX	T2			;Type it out
	SKIPE	RNODE+1(CX)		;Anything left to type?
	 OUTSTR	[ASCIZ |::|]		;Yes.
	AOJA	CX,TNDL1		;Type out the whole list

 > ;End IFN FTPMR
	SUBTTL	SIXBIT Input

PLM
;+
;.HL SIXBIT Input routines:  SIXIN, SIXINW, and SIXINA
MLP
;	These routines all input a SIXBIT value from the controlling
;TTY: in AC T2.  They return with T3 trashed, T2 containing the SIXBIT
;value, and T1 containing the terminating character.
;SIXIN expects the input to be already waiting to be read from the monitor.
;SIXINW waits until a line is typed before beginning to input.
;SIXINA expects T2 to have been set up with the first character of the
;argument already.  The argument is returned left-justified.
PLM
;-
MLP

SIXINW:	SETZ	T2,			;Build target here
	MOVE	T3,[POINT 6,T2]		;Set up bp
SIXIN1:	INCHWL	T1			;Get a character
	CAIE	T1," "			;Is it a space
	 CAIN	T1,"	"		;or a tab?
	  JRST	SIXIN1			;Yes, ignore it
	JRST	SIXIN3			;No, use it

SIXIN:	SKIPA	T3,[POINT 6,T2]		;Set up bp
SIXINA:	  SKIPA	T3,[POINT 6,T2,5]	;First character already
	TDZA	T2,T2			;Build target here
	  SETZ	T1,			;In case no terminator
SIXIN0:	INCHSL	T1			;Get a character
	  POPJ	P,			;Nothing
	CAIE	T1," "			;Eat spaces and tabs
	CAIN	T1,"	"		;..
	  JRST	SIXIN0
	JRST	SIXIN3

SIXIN2:	INCHSL	T1			;Get next character
	 POPJ	P,			;Thats all
SIXIN3:	CAIL	T1,"a"			;Make lowercase
	CAILE	T1,"z"
	TRNA
	TRZ	T1,"a"-"A"
	CAIL	T1,"A"			;Alpha?
	CAILE	T1,"Z"			;.....?
	  TRNA				;No
	JRST	SIXIN4			;Yes
	CAIL	T1,"0"			;Numeric?
	CAILE	T1,"9"			;...?
	  JRST	SIXIN5			;No, done
SIXIN4:	MOVEI	T1,-40(T1)		;Convert to sixbit
	TRNN	T2,77			;Any room left
	 IDPB	T1,T3			;store
	JRST	SIXIN2			;Get next...

SIXIN5:	CAIN	T1,.CHCRT		;<CR>?
	  INCHSL 1(P)			;Yes
	JFCL
	POPJ	P,
	SUBTTL	Scanning Routines -- .LKNAM

PLM
;+
;.hl Routine .LKNAM
MLP
;	.LKNAM is called to search a command table for a match.  It is called
;with T1 containing the AOBJN pointer to the defined commands table and T2
;containing the SIXBIT command name to search for.  .LKNAM will allow
;abbreviation to uniqueness.  It returns CPOPJ if the specified command is
;a duplicate or is not found in the table.  It returns CPOPJ1 with the right
;half of T1 containing the offset from the beginning of the command table
;to the specified entry.  The left half of T1 is returned as zero if the
;specified command word was an abbreviation or less than zero if it was
;an exact match.  .LKNAM uses T3 and T4 but preserves T2.
PLM
;-
MLP

.LKNAM:	JUMPGE	T1,[SETOM T1	;FLAG UNKNOWN
		    POPJ P,]	;ERROR RETURN
	SAVE2			;SAVE P1, P2
	PUSH	P,T1		;SAVE ARGUMENT
	MOVE	T3,T2		;SET ARG TO MASK MAKER
	PUSHJ	P,.MKMSK	;MAKE MASK
	MOVE	T2,T3		;RESTORE NAME
	MOVE	P1,T1		;SAVE FOR MATCHING
	MOVE	T1,(P)		;Recover argument
	SETOM	P2		;SET ABBREVIATION MATCH COUNTER
NAME1:	MOVE	T3,(T1)		;FETCH TABLE ENTRY
	TLNE	T3,(3B1)	;NOTE THAT * IS 12 IN SIXBIT
	JRST	NAME2		;NOT FORCED MATCH
	LSH	T3,6		;SEE IF IT MATCHES
	XOR	T3,T2		;EVEN IN AN ABBR.
	TRZ	T3,77		;CLEAR LAST CHAR SINCE WE DON'T KNOW IT
	AND	T3,P1		;..
	JUMPE	T3,NAME9
	JRST	NAME3		;NO--LOOP
NAME2:	XOR	T3,T2		;SEE IF EXACT MATCH
	JUMPE	T3,NAME9	;YES--A WINNER
	AND	T3,P1		;SEE IF A SUITABLE ABBREVIATION
	JUMPN	T3,NAME3	;NO--LOOP BACK FOR MORE
	MOVE	T4,T1		;SALT AWAY THE LOCATION JUST IN CASE
	AOS	P2		;YES--COUNT 
NAME3:	AOBJN	T1,NAME1	;ADVANCE--LOOP IF NOT DONE YET
	HRRZ	T1,T4		;RESTORE LOCATION OF A WINNER
	JUMPE	P2,NAME9	;DONE--JUMP IF ONE ABBREVIATION
	MOVE	T1,P2		;GIVE FLAG TO CALLER
	POP	P,(P)		;Fix stack
	POPJ	P,		;NONE OR TWO, SO FAIL

NAME9:	POP	P,T3
	HRRZS	T3
	SUBI	T1,(T3)		;Make relative index
	JRST	CPOPJ1		;And give good return
	SUBTTL	Scanning Routines -- .MKMSK

PLM
;+
;.hl Routine .MKMSK
MLP
;	Routine .MKMSK is called to make a mask (returned in T1) with
;"77" (octal) in word positions which are non-blank in the SIXBIT word
;specified in T3.  It also uses T2.
PLM
;-
MLP

.MKMSK:	MOVEI	T1,0		;CLEAR MASK
	MOVSI	T2,(77B5)	;START AT LEFT END
MAKMS1:	TDNE	T3,T2		;SEE IF SPACE HERE
	IOR	T1,T2		;NO--IMPROVE MASK
	LSH	T2,-6		;MOVE RIGHT ONE CHAR
	JUMPN	T2,MAKMS1	;LOOP UNTIL DONE
	POPJ	P,		;RETURN
	SUBTTL	Memory manglement -- Core allocator

PLM
;+
;.hl Routine CORGET
MLP
;	CORGET is the allocation portion of the memory manager.  It is
;called with T1 containing the size (in words) of the block desired.  It
;exits CPOPJ with T1 containing the address of the obtained block.  It will
;stopcode if the core is not available and the program cannot expand.
;CORGET preserves all ACs except T1.
PLM
;-
MLP

CORGET:
	PUSHJ	P,PIOSAV		;Turn off PSI
IFN	FTPARANOID,<
	JUMPLE	T1,[ERR	ICA,<Illegal core allocation>]
>
	PUSH	P,T2			;Save the world
	PUSH	P,T3
	PUSH	P,T4
	SKIPN	T2,FRELST		;Any blocks on the free list?
	JRST	CORG20			;No, make the block
	SETZB	T3,T4			;Not remembering any block
	HRLI	T2,FRELST		;Remember precessor
CORG1:	PUSH	P,(T2)			;Push size of block
	HLRZS	(P)			;Move to right half
	CAMN	T1,(P)			;Same size as we want?
	JRST	CORG7			;Yes, allocate it
	CAML	T1,(P)			;Do we want smaller than this block?
	JRST	CORG6			;No, don't remember it
	JUMPE	T3,CORG4		;If not remembering anything, then this
	CAMG	T4,(P)			;Else is this closer to the size than previous remembered?
	JRST	CORG6			;No, remember previous then
CORG4:	MOVE	T3,T2			;Remember this block & its predecessor
	MOVE	T4,(P)			;And its size
CORG6:	POP	P,(P)			;Fix stack
	HRLI	T2,(T2)			;Remember precessor
	HRR	T2,(T2)			;Point to successor
	TRNE	T2,-1			;If there is one
	JRST	CORG1			;There is, check it out
	JUMPE	T3,CORG20		;If didn't find anything
	MOVE	T2,T3			;Point T2 to block we want
	PUSH	P,(T2)			;And push its size
	HLRZS	(P)			;on the right side
CORG7:	CAMN	T1,(P)			;Size the same as we want?
	JRST	CORG9			;Yes, just de-link it then
	PUSH	P,(P)			;Duplicate size of desired block
	SUBM	T1,(P)			;No, subtract out what we want
	MOVNS	(P)			;Leaving size left
	HRRZI	T3,(T2)			;Start of the block as it is
	ADDI	T3,(T1)			;Where it will now start
	POP	P,(T3)			;Put new size in
	MOVSS	(T3)			;left half, of course
	HRL	T3,(T2)			;Get successor
	HLRM	T3,(T3)			;and place in new block
	MOVSS	T2			;Point to predecessor
	HRRM	T3,(T2)			;Point it to new block
	HRRZM	T1,(P)			;Put desired size on
	HLRZ	T1,T2			;Return with new block in T1
	JRST	CORG30			;Cleared, of course

CORG9:	HRRZI	T1,(T2)			;Point T1 to desired block
	HRRZ	T3,(T2)			;Get successor
	MOVSS	T2			;Get predecessor
	HRRM	T3,(T2)			;Link to new sucessor
	JRST	CORG30			;Clear it and return

CORG20:	PUSH	P,T1			;Save size
	MOVE	T2,.JBFF		;Point to first free location
	ADDI	T2,(T1)			;The address which must be allocated to
	CAMLE	T2,HICORE		;Does that far exist?
	JRST	CORG23			;No, go allocate it
	MOVE	T1,.JBFF		;Point to block
	MOVEM	T2,.JBFF		;Update first free
	JRST	CORG30			;Clear and return

CORG23:	MOVE	T1,.JBFF		;Point to new block
	MOVEM	T2,.JBFF		;Store pointer to new
	IORI	T2,777			;To next page
	MOVEM	T2,HICORE		;Save max
	CORE	T2,			;Get it
	  ERR	CUF,<CORE UUO failed>

CORG30:	EXCH	T1,(P)			;Exchange size for address
	HRRZ	T2,(P)			;Make BLT pointer
	HRLI	T2,1(T2)		;..	
	SETZM	(T2)			;Clear first location
	SOJLE	T1,CORG40		;Skip the BLT if only one word
	MOVSS	T2
	ADD	T1,(P)			;Last location(+1)
	BLT	T2,(T1)			;Clear core
CORG40:	POP	P,T1
	POP	P,T4
	POP	P,T3
	POP	P,T2
	POPJ	P,
	SUBTTL	Memory manglement -- Core De-allocator

PLM
;+
;.hl Routine CORFRE
MLP
;	CORFRE is the de-allocation portion of the memory manager.  Enter
;it iwth T1 containing the address of the block to free and the absolute
;value of T2 containing the number of words to free.  Blocks which are freed
;are placed on a linked list of free blocks for later re-use.  Address space
;is never shrunk when core is de-allocated.  CORFRE preserves all ACs but
;destroys the setting of F$P2.
PLM
;-
MLP

CORFRE:	PUSHJ	P,PIOSAV
IFN	FTPARANOID,<
	CAILE	T1,LSTZER		;Be sure core in reasonable place
	SKIPN	T2
	  ERR	ICD,<Illegal core deallocation>
>
	TLZ	F,(F$P2)		;First pass
	PUSHJ	P,SAVT
	SETZM	(T1)			;No links here yet!
	MOVMS	T2			;Be sure it's positive
	ADDI	T2,(T1)			;Compute end address(+1)
	HRLI	T3,FRELST
	HRR	T3,FRELST		;Get free list pointer
	TRNN	T3,-1
	  JRST	CORF10
CORF1:	HLRZ	T4,(T3)			;Get size of block
	ADDI	T4,(T3)			;Compute its last addr(+1)
	CAME	T4,T1			;Does that block end at us?
	  JRST	CORF4			;No
	SUBI	T2,(T1)			;Get length again
	TLON	F,(F$P2)			;Pass 2?
	  JRST	CORF2			;No, don't return yet
	MOVSS	T2			;Put in left half
	ADDM	T2,(T3)			;Make that block bigger
	POPJ	P,			;Return

CORF2:	HLRZ	T4,(T3)			;Get length of existing block
	ADDI	T2,(T4)			;Add length of new block
	MOVEI	T1,(T3)			;Point T1 at new larger block
CORF3:	HRR	T3,(T3)			;Point T3 at successor
	MOVSS	T3			;Get predecessor
	HLRM	T3,(T3)			;Point it at sucessor
	SETZM	(T1)			;No links yet to new block
	ADDI	T2,(T1)
	MOVSS	T3			;Point T3 at current block
	JRST	CORF9			;And continue scan

CORF4:	CAIE	T2,(T3)			;Does our block end at his?
	  JRST	CORF7			;No
	SUBI	T2,(T1)			;Get length again
	HLRZ	T4,(T3)			;And length of this block
	ADDI	T2,(T4)			;Get length of new block
	TLON	F,(F$P2)			;Pass 2?
	  JRST	CORF3			;No, de-link and continue search
	HRLM	T2,(T1)			;Store in proper place
	HRRZ	T2,(T3)			;Get successor block
	HRRM	T2,(T1)			;And point us to him
	MOVSS	T3			;Get predecessor
	HRRM	T1,(T3)			;And point him to us
	POPJ	P,			;Return

CORF7:	HRLI	T3,(T3)			;Remember us as prececessor
	HRR	T3,(T3)			;Get successor
CORF9:	TRNE	T3,-1			;See if there is one
	  JRST	CORF1			;Yes, check it
CORF10:	MOVSS	T3			;No, point back to last block
	HRRM	T1,(T3)			;Save
	SUBI	T2,(T1)			;Get real length again
	HRLM	T2,(T1)			;Store it
	POPJ	P,			;Return, turning PSISER on on the way
	SUBTTL	SWITCH.INI support -- Read SWITCH.INI
PLM
;+
;.hl Routine SWTINI
MLP
;	SWTINI is the main routine which provides support of reading SWITCH.INI.
;It looks up DSK:SWITCH.INI[,] and parses each line searching for a line
;which begins with "NRT".  It will attempt to parse each switch on the line;
;if a switch parses incorrectly, SWTINI will abort scanning the line
;and return to the caller.  SWTINI uses all T ACs.
PLM
;-
MLP

SWTINI:	OPEN	$SWI,[	.IOASC
		      SIXBIT/DSK/
			DSKHDR	]
	  POPJ	P,			;Oh well
	MOVE	T1,[SIXBIT/SWITCH/]
	MOVSI	T2,'INI'
	SETZ	T3,
	JFCL
	GETPPN	T4,
	JFCL
	LOOKUP	$SWI,T1			;Lookup the file
	  JRST	RELFIL			;Done
FNDNRT:	PUSHJ	P,SIXDSK		;Get sixbit token from disk
	CAMN	T2,[SIXBIT/NRT/]	;For us?
	  JRST	HAVNRT
	PUSHJ	P,DSKEAL		;Eat a disk line
	  JRST	RELFIL			;Done
	JRST	FNDNRT			;Loop around

NRTSWT:	PUSHJ	P,SIXDSK		;Get it 
	MOVE	T1,[-SWTL,,SWTA]	;The table
	PUSHJ	P,.LKNAM		;Look for a switch
	  TRNA				;Do what we can
	PUSHJ	P,@SWTDSP(T1)		;Process the switch
	  JRST	RELFIL			;Oops
HAVNRT:	CAIN	P1,"/"			;Look for switches
	  JRST	NRTSWT			;Process switch
	PUSHJ	P,DSKCH			;Get a character
	  JRST	RELFIL			;Done
	CAIE	P1,"	"		;Tab is OK
	CAIL	P1," "			;But other control chars aren't
	 JRST	HAVNRT			;Continue
RELFIL:	RELEAS	$SWI,
	POPJ	P,

	SUBTTL	SWITCH.INI support -- Switch handling routines

PLM
;+
;.hl Switch handling routines
MLP
;	The following routines handle individual switches:
PLM
;.list 1
;.le
MLP
;ESCSWT handles the /ESCAPE:character switch.
PLM
;-
MLP

ESCSWT:	CAIN	P1,":"			;Validate last character
	PUSHJ	P,DSKCH
	  POPJ	P,
	MOVEM	P1,ESCCHR
	PJRST	DSKCH			;Get next character and return

PLM
;+
;.le
MLP
;MODSWT handles the /MODE switch.  Non-understandable settings of /MODE are
;equivalent to /MODE:NOVICE.
PLM
;-
MLP

MODSWT:	CAIE	P1,":"			;Does he really know what he's doing
	  JRST	CPOPJ1			;Ignore just this
	PUSHJ	P,SIXDSK		;Get string
	MOVE	T1,[-MODL,,MODA]	;The table
	PUSHJ	P,.LKNAM		;Lookup
	  JRST	CPOPJ1			;Ignore this switch
	IOR	F,MODTAB(T1)		;The correct flag bits
	MOVE	T1,MODTB2(T1)		;Get the notify string
	MOVEM	T1,NOTICH		;Save it
	JRST	CPOPJ1

PLM
;+
;.end list
;-
MLP
	SUBTTL	SWITCH.INI support -- I/O Routines

PLM
;+
;.hl Miscellaneous SWITCH.INI support routines
MLP
;	The following routines are used to support the reading of SWITCH.INI:
PLM
;.list 1
;.le
MLP
;SIXDSK returns an alphanumeric SIXBIT token in T2, terminating
;character in P1.  It uses T2 and P1.
PLM
;-
MLP

SIXDSK:	SETZ	T2,
DSKSX1:	PUSHJ	P,DSKCH			;Get a disk character
	  POPJ	P,
	CAIL	P1,"a"
	CAILE	P1,"z"			;Convert lower case
	  TRNA
	ANDI	P1,137			;...
	CAIL	P1,"A"			;Alphanumeric?
	CAILE	P1,"Z"
	  JRST	DSKSX4
DSKSX3:	LSH	T2,6
	ADDI	T2,<'0'-"0">(P1)
	JRST	DSKSX1
DSKSX4:	CAIL	P1,"0"
	CAILE	P1,"9"
	  TRNA
	JRST	DSKSX3
	JUMPE	T2,CPOPJ		;Done
DSKSX5:	TLNE	T2,770000		;Left justify
	  POPJ	P,
	LSH	T2,6
	JRST	DSKSX5

PLM
;+
;.le
MLP
;DSKEAL eats characters until a <LF> is seen.  It uses P1.
PLM
;-
MLP

DSKEAL:	PUSHJ	P,DSKCH
	  POPJ	P,
	CAIE	P1,.CHLFD
	  JRST	DSKEAL
	AOS	(P)
	POPJ	P,

PLM
;+
;.le
MLP
;DSKCH returns with the next character from the file in P1.
;It returns CPOPJ1 if no errors; CPOPJ and P1 zero if error or EOF.
;It uses P1 only.
PLM
;-
MLP


DSKCH:	SETZ	P1,
	SOSGE	DSKHDR+.BFCTR
	  JRST	DSKIN
	ILDB	P1,DSKHDR+.BFPTR
	AOS	(P)
	POPJ	P,

DSKIN:	IN	$SWI,
	  JRST	DSKCH
	POPJ	P,

PLM
;+
;.end list
;-
MLP
	SUBTTL	SWITCH.INI support -- Switch tables

PLM
;+
;.hl Tables SWTA and SWTDSP
MLP
;	These are the tables which define legal switches and correspond
;them with appropriate actions.  SWTA is generated with the NAMTAB MACRO.
;SWTDSP is the list of addresses.  The offset of each address corresponds
;to the offset of the affiliated command from the beginning of the SWTA
;table.
PLM
;-
MLP

	NAMTAB	SWT,<ESCAPE,MODE>

SWTDSP:	ESCSWT
	MODSWT				;Mode switch
IFN	.-SWTDSP-SWTL,<
	PRINTX	%SWITCH.INI dispatch table doesn't match switch table
>

PLM
;+
;.hl Tables MODA, MODTB2, and MODTAB
MLP
;	These tables define the legal settings of the /MODE switch and
;the corresponding bit setting of F$XPT the value of NOTICH.  The offset into
;MODA defined by the input keyword corresponds to the offset into
;MODTAB to obtain the correct flag and MODTB2 to obtain the value
;of NOTICH.
PLM
;-
MLP

	NAMTAB	MOD,<EXPERT,NOTIFY>

;Table for /MODE flag bits.  Must match order of /MODE names above

MODTAB:	EXP	F$XPT
	EXP	F$XPT
IFN	.-MODTAB-MODL,<
	PRINTX	%SWITCH.INI /MODE bits table doesn't match MODES table
>

;Table for value of NOTICH.  Must match order of /MODE names above

MODTB2:	Z
	[ASCIZ//]
IFN	.-MODTB2-MODL,<
	PRINTX	%SWITCH.INI /MODE NOTICH value table doesn't match MODES table
>
	SUBTTL FILHGH - Prototype FILOP. UUO block

PLM
;+
;.hl Data block FILHGH
MLP
;	FILHGH is the prototype FILOP. argument block used by the performance
;analysis routines.
PLM
;-
MLP

IFN FTPERF,<
FILHGH:	$PRF,,	.FOAPP			;Channel,,Mode
	EXP	.IOIMG!UU.RRC		;Mode!Update rib on new file data
	SIXBIT	/DSK/			;Device
	XWD	FOBUF,FIBUF		;Outpbut buffer,,Input buffer headers
	XWD	3,3			;Number of output,,Input buffers
	XWD	0,PRFFIL		;Pointer to Lookup/Enter block
	Z				;No path block
	Z				;Clear out PPN
 >; End IFN FTPERF

	SUBTTL GETCFG - Get the configuration message for the system

PLM
;+
;.hl Routine GETCFG
MLP
;	GETCFG is called to read the configuration message from the
;remote terminal server.  It will read the PMR message and confirm
;that it is a positive response (first byte =/= 2) if that is necessary.
;It will then read and store OSTYPE and PROTMD (the protocol modifier).
;It will type the connect confirmation and escape character reminder
; messages before returning to the user.  Enter at TYPESC to just type the
;escape character reminder message.
PLM
;-
MLP

GETCFG:
	TXZ	F,F$NEOM		;Force new buffer
	PUSHJ	P,NSPINW		;Wait for input
	  JRST	NSPERR			;Oh well
IFN FTPMR,<
	SKIPN	NODCNT			;Using PMR?
	 JRST	GETCF0			;Get the next part of message
	PUSHJ	P,RBYTEC		;Get data
	CAIE	T1,2			;Is it a PMR NAK?
	 JRST	GETCF			;No, then it is ok
	PUSHJ	P,TTYRST		;Reset the TTY:
PMRERR:	PUSHJ	P,NETCHR		;Output data from network
	TXZN	F,F$NEOM		;If EOM
	PUSHJ	P,OUTCRL		;He doesnt supply this either
	PUSHJ	P,NSPINW		;Get more data
	  JRST	[PUSHJ	P,DOOUT1	;Force out last
		 JRST	RESTRT	]	;And re-ask him
	JRST	PMRERR			;Continue outputting
GETCF:	TXZ	F,F$NEOM		;Wait for some input
	PUSHJ	P,NSPINW
	  JRST	NSPERR			;Failed
> ;End IFN FTPMR
GETCF0:	PUSHJ	P,RBYTEC		;Get byte (defines this as config msg)

GETCF1:	PUSHJ	P,RBYTEC		;Get a first byte
	PUSHJ	P,RBYTEC		;Protocol ECO
	MOVEM	T1,PROTMD		;Save it
	PUSHJ	P,RBYTEC		;Protocol modifier
	PUSHJ	P,RBYTEC		;OS type
	MOVE	T3,T1			;save it
	CAILE	T3,MAXOS		;Is this legal?
	  ERR	IOR,<Illegal operating system type returned in configuration>
	MOVEM	T3,OSTYPE		;Save this
	PUSHJ	P,RBYTEC		;2nd byte of O/S type
	PUSHJ	P,GETWRD		;Supported protocols
GETCF9:	TYPE	<
[Connected to >
	TSIX	OSNAME(T3)		;System type
	TYPE	< system>

IFN FTPMR,SKIPG	NODCNT			;Poor mans routing
	 OUTCHR	[" "]			;No, then output the space
	MOVE	T2,RNODE		;Type nodeid
	PUSHJ	P,TNODE			;
	TYPE	<::]
>
TYPESC:	TYPE	<[Type >		;Say how to get out
	MOVE	T2,ESCCHR		;
	CAIL	T2," "			;Is it control?
	 JRST	TYPES1			;No. nothing special
	TYPE	<Control->		;
	MOVEI	T2,"A"-""(T2)
TYPES1:	OUTCHR	T2			;Type it
	SKIPN	T2,ESCCHR		;Get escape back
	 TYPE	< (Control-space)>
	CAIN	T2,""			;Control uparrow?
	 TYPE	< (Control-~ on VT100)>	;Some terminals like this better
	CAIN	T2,""			;Control backarrow?
	 TYPE	< (Control-? on VT100)>	;
TYPES2:	TYPE	< to return]
>		;
	POPJ	P,			;

	SUBTTL	Compute mask bit & word for ESCCHR

PLM
;+
;.hl Routine CMPESC
MLP
;	CMPESC is called to compute the offset bit and word from the
;beginning of a mask.  These values are stored in ESCBIT and ESCWRD
;respectively.  This is for fast adding of the escape character to the
;break set at interrupt level when using break masks.
PLM
;-
MLP

CMPESC:	MOVE	T1,ESCCHR		;Get the escape character
	IDIVI	T1,^D32			;Compute bit, etc. for later
	MOVEM	T1,ESCWRD		;The word
	MOVNS	T2
	MOVSI	T1,(1B0)		;And the bit
	LSH	T1,(T2)
	MOVEM	T1,ESCBIT
	POPJ	P,
	SUBTTL	Fatal errors in job

PLM
;+
;.hl Routine ERRTRP
MLP
;	The ERRTRP routine is entered if the program ever gets a trap
;through .JBINT.  .JBINT traps are enabled for any kind of fatal error
;(such as illegal memory references, pushdown overflows, etc.) and control-C
;interrupts.  These things are specifically not enabled with PSISER because
;the PSI system may be turned off when the error occurs.  This routine
;saves the ACs in location CRSACS and loads up a crash pushdown pointer.
;It then attempts to restore the state of the TTY: (unslave it, in
;particular) and exit.  The program may then be SAVEd and the dump
;analyzed later with FILDDT.
PLM
;-
MLP

ERRTRP:	MOVEM	P,CRSACS+P		;Save P
	ASSUME	P,17			;P must be last
	MOVEI	P,CRSACS		;Save all ACs
	BLT	P,CRSACS+P-1
	MOVE	P,[-10,,CRSPDL]		;Point to crash PDL
IFE	FTDBUG,<
	PUSHJ	P,TTYRST		;Free the TTY:
>
IFN	FTDBUG,<
	PJ	P,TTYRST		;Free the tty:
>
	RESET				;Clear the world
	EXIT	1,			;Die relatively gracefully
	JRST	RESTRT			;Restart the prog
	SUBTTL	ATTACH/DETACH PSI routine

PLM
;+
;.hl Routine DATPSI
MLP
;DATPSI handles an ATTACH/DETACH PSI interrupt.  This is so we can reset
;the old terminal and init the new terminal.  Note that anything set
;after initialization time will not be preserved over an ATTACH.
;Note that ATTACH/DETACH PSIs occur at a higher PSI level than other
;interrupts.
PLM
;-
MLP

DATPSI:	ADJSP	P,4			;Save the Ts (Don't have our own ACs)
	DMOVEM	T1,-3(P)
	DMOVEM	T3,-1(P)
	SKIPGE	T1,TTYUDX		;Don't reset if was detached
	  JRST	DATPS1			;Don't reset if was detached
	CAME	T1,CTLTTY		;TTY: reassigned?
	  JRST	DATRET			;No
	PUSHJ	P,TTYRS1		;Reset the settables
DATPS1:	MOVE	T1,DATVEC+.PSVIS	;Get the UDX
	MOVEM	T1,TTYUDX		;Save in all the appropriate places
	MOVEM	T1,HPSUDX
	MOVEM	T1,LEDUDX		;For checking line editing
	MOVEM	T1,CTLTTY		;Same as before
	MOVEM	T1,ECCUDX		;..
	MOVEM	T1,BKCUDX		;Count of characters to echo
	MOVEM	T1,CTOUDX
	MOVEM	T1,COSUDX
	MOVEM	T1,PAGUDX		;...
	JUMPL	T1,DATRET		;If just got detached, return
	PJOB	T1,		;Get current job
	MOVNS	T1
	JOBSTS	T1,			;Get job status word
	  SETZ	T1,			;Oh well
	TLNN	T1,(JB.UML)		;We at monitor level?
	  JRST	ATTOK			;No, proceed
	MOVEI	T1,.IOASC		;Set a reasonable mode
	SETSTS	$TTY,(T1)
	ASSUME	.IOASC,0
	OUTCHR	T1			;Wait for user level
	CLRBFI				;Make PIM happy
	SETSTS	$TTY,@TTYBLK		;Reset TTY:
ATTOK:	PUSHJ	P,SETTTY		;Set the settables
	PUSHJ	P,TTYSST		;According to what it should be
	SETZ	T1,
	SLEEP	T1,			;Cancel old clock req
DATRET:	DMOVE	T1,-3(P)		;Restore Ts
	DMOVE	T3,-1(P)
	ADJSP	P,-4
	DEBRK.
	  JRST	E..DNI
	POPJ	P,
	SUBTTL	DECnet interrupt routine

PLM
;+
;.hl Routine DCNPSI
MLP
;	DCNPSI is the operating system independent NSP. interrupt service
;routine.  It calls EXCACS to set up the NSP. ACs.  It then decides if
;this is more data available for a previously not completely read
;network message.  If so, in dispatches to NSPCON to finish the read.
;Otherwise, it checks the state of the connection, and, if it it is
;DR, it outputs the "[Connection to remote node aborted]" message and
;exits through NSPER1.  If neither of the above is true, it checks for
;network input and inputs any available, then attempts to
;push out any pending network output.  If any network input now exists,
;it calls the operating system dependent network interrupt service
;routine (whose address was stored at initialization in OSNSP).  Upon
;return it loops to check for more input and to attempt to send out
;pending output.  When no input is available, it restores the ACs in
;use before the interrupt and dismisses the interrupt.
PLM
;-
MLP

DCNPSI:	AOSE	INTLVL			;Get the interlock
	  ERR	INA,<Interlock not available>
	PUSHJ	P,EXCACS		;Get right ACs
	  EXP	NSPACS			;Which set
	TXNE	F,F$NEOM		;EOM seen?
	  JRST	NSPCON			;No, continue
	LDB	T1,[POINT 6,NSPVEC+.PSVIS,^L<NS.STA>+5]	;Get current state
	CAIN	T1,.NSSDR		;Disconnect Received?
	  JRST	NSPERR			;Go clean up
NEWNET:	PUSHJ	P,NSPIN			;See if any network input
	  JRST	NSPERR			;Oops
	PUSHJ	P,NSPO			;Output network stuff if can
	  JRST	NSPERR			;Oops
	SKIPG	IBFCNT			;If nothing the sleep
	  JRST	NSPRET			;Restore the world and return
	PUSHJ	P,@OSNET		;Process network input
	PUSHJ	P,DOOUT1		;Force the buffer out then
	TXZE	F,F$USRV		;Want TTY: service?
	  PUSHJ	P,TTYPS1		;Yes
	JRST	NEWNET			;Check for more

NSPRET:	PUSHJ	P,EXCACS		;Get the ACs back
	  EXP	NSPACS
	SETOM	INTLVL			;Clear the interlock
	DEBRK.
	  JRST	E..DNI			;Not implemented
	POPJ	P,			;In case not called at PSI level
	SUBTTL	TMR PSI routine

PLM
;+
;.hl Routine TMRPSI
MLP
;	This is the operating system independent PITMR. trap routine.
;It first loads up the timer service ACs.  If OSTMR is non-zero, it
;treats it as the address of the operating system dependent timer service
;routine and dispatches there.  Upon return, or if OSTMR is zero, it
;loads up the AC set in use at the time of the interrupt and dismisses
;the interrupt.  The check for non-zero OSTMR is because this routine is
;not used by all operating systems, and, even then, not all the time.
;Although we should not take a trap unless OSTMR is non-zero, it is probably
;not harmful to dismiss any interrupt we may get.
PLM
;-
MLP

TMRPSI:	AOSE	INTLVL			;Get the interlock
	  JRST	E..INA			;Interlock not available
	PUSHJ	P,EXCACS		;Switch ACs
	  EXP	TMRACS			;Which ACs
	SKIPE	OSTMR			;Any routine?
	  PUSHJ	P,@OSTMR		;Yes, call it
	PUSHJ	P,EXCACS
	  EXP	TMRACS			;Restore the ACs
	SETOM	INTLVL			;Free the interlock
	DEBRK.
	  JRST	E..DNI
	POPJ	P,
	SUBTTL	WAKE PSI Service

PLM
;+
;.hl Routine WAKPSI
MLP
;	WAKPSI is the WAKE UUO PSI service routine.  This consists merely of
;checking to see if F$USRV is set.  If it is, we proceed to TTYPSI; if not
;we just dismiss the interrupt.
PLM
;-
MLP

WAKPSI:	TXZE	F,F$USRV				;Really wanted this?
	  JRST	TTYPSI					;Yes, proceed
	DEBRK.						;Toss it
	  JRST	E..DNI					;Oops
	POPJ	P,
	SUBTTL	TTY: PSI Service
PLM
;+
;.hl Routine TTYPSI
MLP
;	TTYPSI is entered via a PSI interrupt for I/O done to the TTY:
;or via a WAKE UUO.  TTY: I/O PSIs happen at a higher interrupt than
;other PSIs (except ATTACH/DETACH PSIs).  If another interrupt is in
;progress, the location INTLVL is non-negative and TTYPSI will store
;the status bits for the requesting interrupt, queue a forced TTY:
;interrupt via FRCTTY, and dismiss the higher level interrupt.
;Like all interrupt service routines, it first loads up its own AC set.
;If in PIM mode, TTYPSI proceeds to directly read input.  Otherwise,
;it checks to see if there is an outstanding read.  If there is, it
;proceeds to read, first checking to be sure the TTY: is echoed if it
;should be.  If there is not read outstanding, we make sure the TTY: is
;not echoed.  This is to simulate the ECHO DEFERed mode which systems
;such as VMS expect.  We then attempt to read TTY: input.  If the IN
;fails, be check if IO.EOF or any error bits are set.  If IO.EOF is set,
;we CLOSE the TTY: and try the read again.  If any error bits are set,
;we stopcode.  If neither is true, we restore ACs and dismiss the interrupt.
;We then check to be sure OSTTY is non-zero (in case this came in
;before we were set up).  If zero, we restore ACs and dismiss the interrupt.
;Otherwise, we allocate an internal buffer for the input and chain it off
;of any existing buffers.  We move the haracters to the input buffer and
;call the operating system dependent TTY: service routine.  Upon return,
;we loop back to check for more input.
PLM
;-
MLP

TTYPS1:	TXO	F,F$NDB			;Don't DEBRK.
	JRST	TTYPS2			;Continue
TTYPSI:	AOSE	INTLVL			;Get the interlock
	  JRST	TTYDFR			;Defer the interrupt
TTYPS2:	PUSHJ	P,EXCACS		;Set AC set
	  EXP	TTYACS			;TTY: ACs
	TXNN	F,F$PIM			;PIM?
	  PUSHJ	P,CHKCTO		;Read it
	MOVE	T1,TTYVEC+.PSVFL	;Reasons
	IORM	T1,TTYSTS		;Set what we need to do
TTYPS3:	MOVEI	T1,PS.ROD!PS.REF	;Output done some time?
	TDNE	T1,TTYSTS		;?
	  PUSHJ	P,TOOUTA		;See if can output anything
	MOVEI	T1,PS.RID!PS.REF	;Input done
	TDNN	T1,TTYSTS		;?
	  JRST	TTYRET			;Nothing more to do
TTYNEW:	MOVEI	T1,PS.RID!PS.REF	;We are going to service this now
	ANDCAM	T1,TTYSTS		;So clear it here
	TXNE	F,F$PIM			;PIM
	  JRST	ISREAD			;Skip this stuff then
	MOVEI	T1,IO.SUP		;Get SUP bit
	TXNN	F,F$READ		;Read active?
	TDNE	T1,TTYBLK		;Is it already on?
	  JRST	ISREAD			;No problem
	IORB	T1,TTYBLK		;Update status
	SETSTS	$TTY,(T1)		;Make TTY: reflect it
ISREAD:	IN	$TTY,			;Get a buffer
	  JRST	TTINOK			;Win
	TXNN	F,F$FRC			;Force set?
	TXNN	F,F$PIM			;No, is PIM set?
	  TRNA				;Force is or PIM is not
	JRST	TTYRET			;Can't get EOF on PIM anyway
	PUSHJ	P,SETCTO		;Set the ^O bit
	GETSTS	$TTY,T1			;Get tty status
	TRNN	T1,IO.EOF!IO.ERR	;Error or EOF?
	  JRST	TTCFRC			;Check the force flag
	TRNN	T1,IO.EOF		;EOF?
	  ERR	ITF,<IN UUO for TTY: failed>
	MOVEI	T1,PS.REF		;Clear EOF pending
	ANDCAM	T1,TTYSTS
	CLOSE	$TTY,			;Close TTY:
	JRST	ISREAD			;Check again
TTCFRC:	TXNN	F,F$FRC			;Force set?
	  JRST	TTYRET			;Done if not
	JRST	TTYDBK			;But don't allocate buffers
TTINOK:	SKIPG	T1,TIBUF+.BFCNT		;Get number of bytes
	  JRST	TTYDBK			;Don't bother allocating buffer
	IDIV	T1,BYTPWD		;Compute number of words
	SKIPE	T2
	AOJ	T1,			;Get it
	MOVEI	T1,IBF.PT+1(T1)		;Include header
	MOVNI	T2,(T1)			;Get negative size in T2
	PUSH	P,T1			;Save on stack
	PUSHJ	P,CORGET		;Get a block of core
	HRLZM	T2,IBF.LK(T1)		;Save size
	MOVEI	T2,INPQUE-IBF.LK	;Point to input queue
QUECHK:	SKIPG	IBF.LK(T2)		;End yet?
	  JRST	QUEFND			;Yes
	HRRZ	T2,IBF.LK(T2)		;Point to next 
	JRST	QUECHK
QUEFND:	MOVNS	IBF.LK(T2)		;Make it not last
	HRRM	T1,IBF.LK(T2)		;Point previous to us
	MOVE	T2,TIBUF+.BFCNT		;Get character count
	MOVEM	T2,IBF.CT(T1)		;Save it
	SKIPGE	ICHCNT			;If count is negative
	  SETZM	ICHCNT			;Zap it here
	ADDM	T2,ICHCNT		;And increase total # of chars
	HLL	T2,TIBUF+.BFPTR		;Get size
	HRRI	T2,IBF.DT-1(T1)		;Where it will go
	MOVEM	T2,IBF.PT(T1)		;Point there
	HRL	T2,TIBUF+.BFPTR		;First address of data
	ADJSP	T2,1			;Add [1,,1]
	ADD	T1,(P)			;Compute last word of buffer
	POP	P,(P)			;Fix stac
	BLT	T2,-1(T1)		;Copy the data

TTYDBK:	SKIPN	OSTTY			;Be sure there's a routine
	  JRST	TTYDB1
	TXNN	F,F$FRC			;Force set?
	SKIPLE	ICHCNT			;Or nothing to do
	  PUSHJ	P,@OSTTY		;Call the OS's TTY input routine
	MOVEI	T1,PS.RID		;Be sure we check
	IORM	T1,TTYSTS		;..
	JRST	TTYPS3			;Check for more TTY: input

TTYDB1:	TXZ	F,F$FRC			;Will exit on no more input
	  JRST	TTYPS3			;If F$FRC not set

TTYRET:	MOVEI	T1,PS.RID!PS.ROD!PS.REF	;Defer something?
	TDNE	T1,TTYSTS		;?
	  TXO	F,F$USRV		;Make sure can get here if not immediately
	PUSHJ	P,EXCACS
	  EXP	TTYACS			;Restore the old ACs
	TXZE	F,F$NDB			;DEBRK.?
	  POPJ	P,			;No
	SETOM	INTLVL			;Free the interlock
	DEBRK.
	  JRST	E..DNI
	POPJ	P,			;If not called at PSI level

;Here if the interrupt level database is interlocked.  Queue the interrupt
;for later

TTYDFR:	PUSH	P,T1			;Save T1
	MOVE	T1,TTYVEC+.PSVFL	;Get condition
	IORM	T1,TTYSTS		;Say what we want to do
	TRNE	T1,PS.ROD		;Output done?
	AOSE	T1,SLPFLG		;Waiting for it?
	  TRNA				;No
	SLEEP	T1,			;Kill old sleep queue entry
	PUSHJ	P,FRCTTY		;Queue an interrupt for later
	POP	P,T1
	DEBRK.
	  JRST	E..DNI
	POPJ	P,			;?
	SUBTTL	TTY: Service -- Flush all type-ahead

PLM
;+
;.hl Routine FLSTAH
MLP
;	FLSTAH is called to flush all type-ahead, both in internal
;chunks and monitor chunks.  It uses no ACs.
PLM
;-
MLP

FLSTAH:	PUSHJ	P,SAVT			;Save the Ts
	SETZM	ICHCNT			;No characters
	SETZM	BRKNUM			;No breaks to pass
	SKIPN	T1,INPQUE		;Get queue contents
	  JRST	FLSTAM			;None
FLSTAL:	SETZM	IBF.CT(T1)		;Clear the count
	SKIPLE	T1,IBF.LK(T1)		;Point to next
	  JRST	FLSTAL
	JUMPG	T1,FLSTAL		;If more, continue
FLSTAM:	MOVE	T1,[2,,T2]		;Clear the chunks too
	MOVEI	T2,.TOCIB
	MOVE	T3,TTYUDX
	TRMOP.	T1,
	  JFCL				;Oh well
	POPJ	P,
	SUBTTL	TTY: Service -- Set Data Mode and Mask

PLM
;+
;.hl Routine TTYSST
MLP
;	TTYSST is the general routine to change the state of the terminal.
;It will set the data mode to .IOPIM if F$PIM is set, otherwise it sets
;it to .IOASL with IO.ABS set so break masks may be enabled.  Location
;IMASK is used as the argument to the .TOSBS TRMOP.  TTYSST guarantees
;that the escape character is part of the break mask.  TTYSST also
;includes or excludes ^Q/^S in the mask depending on the setting of
;the page mode bit for the TTY: (.TOPAG TRMOP.)  TTYSST uses no ACs.
;TTYSST will clear buffers if the terminal mode changes and it will change
;the pointers in the buffer header blocks.  It will also attempt to wait
;(read "BLOCK") for all output buffers to finish being output to the
;TTY: if the data mode (byte size) changes.
PLM
;-
MLP

TTYSST:
	SAVE	<T1,T2>			;No registers get clobbered
	MOVEI	T1,IO.ABS		;Always on, for .TOSOP
	TXNE	F,F$READ		;Read not set, always noecho
	TXNE	F,F$NEC			;Read set, is noecho?
	 TRO	T1,IO.SUP		;Yes. supress it locally
	TLNE	F,(F$PIM)		;Want to use PIM (passall)?
	 TROA	T1,.IOPIM		;Use PIM mode
	TROA	T1,.IOASL		;Use ASCII line if not PIM
	SKIPA	T2,[POINT 8,4,35]	;PIM is 8 bit bytes, 4/word
	MOVE	T2,[POINT 7,5,35]	;ASCII is 7 bit bytes, 5/word
	TXNN	F,F$LEM!F$PALL!F$RALL	;If these are set
	TXNN	F,F$READ		;Logical read outstanding?
	  TRO	T1,IO.LEM		;No, swallow these too
	TLO	T1,(UU.AIO)		;Set ASYNC I/O
	CAMN	T1,TTYBLK		;Any changes?
	 JRST	SETBKM			;No. Just set break mask
	XORM	T1,TTYBLK		;Get differences
	EXCH	T1,TTYBLK		;Get XOR, save new status
	TRNN	T1,IO.MOD		;Any mode differences?
	  JRST	NBFCHG			;No buffer changes
	PUSHJ	P,WATDEQ		;Wait for buffers to dequeue
	HLLM	T2,TIBUF+.BFPTR
	HLLM	T2,TOBFH+.BFPTR		;Set output pointer
	HLLM	T2,BUFCHR
	HRRZM	T2,BYTPWD		;Save byte size (for interrupt level)
	HRRZ	T2,BUFCHR		;Number of words in buffer
	IMUL	T2,BYTPWD		;Total number of chars in buffer
	MOVEM	T2,CHPBUF		;Set number of characters in buffer
	SETZM	TIBUF+.BFCTR		;Clear buffers
NBFCHG:	SETSTS	$TTY,@TTYBLK		;Set the bits
SETBKM:	TLNE	F,(F$PIM)		;Using PIM?
	  JRST	TTYSSZ			;Yes, don't bother with break mask
	MOVE	T1,ESCBIT		;Escape character bit
	MOVE	CX,ESCWRD		;Word
	IORM	T1,IMASK+1(CX)		;Be sure the break character's there
	MOVX	T1,1B<.CHCNW>		;No one supports ^W
	TXNE	F,F$NLF
	  TXO	T1,1B<.CHCRT>		;If <CR> isn't to generate <LF>
	TXNE	F,F$ESC			;Want escape recognition?
	  TXO	T1,1B<.CHESC>		;Yes
	IORM	T1,IMASK+1		;Set it
	MOVE	T1,[2,,PAGTRM]		;Find the page bit
	TRMOP.	T1,
	  SETZ	T1,			;Default
	JUMPE	T1,TTSNPG		;Don't change anything
	MOVX	T2,<1B<.CHCNS>!1B<.CHCNQ>>
	IORM	T2,IMASK+1		;Default we get them
	ANDCM	T2,OBMASK		;VAX needs to see these
	ANDCM	T2,OBMASK+1
	TXNN	F,F$RALL!F$PALL		;Readall or passall?
	 ANDCAM	T2,IMASK+1		;Default can't get them
TTSNPG:	MOVX	T1,1B<.CHCNO>
	IORM	T1,IMASK+1		;Default we see it
	TXNN	F,F$ACO!F$RALL!F$PALL	;Allow ^O if we need to
	 ANDCAM	T1,IMASK+1
	SKIPN	T1,IMASK		;If field width got zapped,
	  MOVEI	T1,1			;Make it one
	CAIL	T1,400			;Max is 377 (octal)
	MOVEI	T1,377			;So set that
	MOVEM	T1,IMASK		;..
	MOVE	T1,[7,,TRMBKS]		;Set break set
	TRMOP.	T1,
	  JFCL				;Oops


TTYSSZ:	RESTORE	<T2,T1>			;
	POPJ	P,			;Return
	SUBTTL	TTY: Service -- Check for line editing

PLM
;+
;.hl Routine CHKLED
MLP
;	CHKLED is called to see if line editing needs to be done on
;type-ahead we haven't yet seen.  Return CPOPJ if something needs to
;be done; CPOPJ1 if not.  **THE BREAK SET IN USE IS ALTERED HERE
;AND NOT CHANGED BACK, BUT IMASK IS LEFT AS THE "DESIRED" MASK**.
;AND IS ALTERED BACK ONLY IF THERE IS NO LINE EDITING TO DO.
;IMASK IS LEFT AS THE "DESIRED" MASK IN ALL CASES, HOWEVER.**
;It uses nothing.
;-
MLP

CHKLED:	PUSHJ	P,SAVT			;Save the ACs
	MOVE	T1,[7,,LEDTRM]		;See if anything to do
	TRMOP.	T1,
	  JRST	CHKLEX
	MOVE	T1,[2,,T2]		;Find number of characters now
	MOVEI	T2,.TOBKC		;..
	MOVE	T3,TTYUDX
	TRMOP.	T1,
	 JRST	CHKLEX
	JUMPN	T1,CPOPJ
CHKLEX:	AOS	(P)
	MOVE	T1,[7,,TRMBKS]		;Restore the mask
	TRMOP.	T1,
	  JFCL
	POPJ	P,
	SUBTTL	TTY: Service -- Check/Set ^O bit

PLM
;+
;.hl Routines CHKCTO, SETCTO, and CLRCTO
MLP
;	These routines handle the control-O bit in relation to F$CTO.
;CHKCTO sets F$CTO according to the bit as the monitor sees it.
;SETCTO sets the output suppression bit if F$CTO is set.  **IT DOES
;NOTHING IF F$CTO IS CLEAR**.  CLRCTO clears both F$CTO and the monitor's
;output suppression bit.  These routines use CX.
PLM
;-
MLP

CHKCTO:	TXNE	F,F$ICO			;Didn't do this earlier so could make
	  POPJ	P,			;PIM check at TTYPSI: faster
	MOVE	CX,[2,,CTOTRM]
	TRMOP.	CX,
	  SETZ	CX,
	DPB	CX,[POINT 1,F,<^L<F$CTO>>]
	JUMPN	CX,CLRTOQ		;Be sure queue is cleared
	POPJ	P,

SETCTO:	TXNN	F,F$ICO			;Ignore?
	TXNN	F,F$CTO
	  POPJ	P,			;Assuming it's clear
	MOVE	T1,[3,,CTOTRS]		;The TRMOP.
	SETOM	COSVAL
	TRMOP.	T1,
	  JFCL
	POPJ	P,

CLRCTO:	TXZ	F,F$CTO!F$ICO
CLRCO1:	MOVE	CX,[3,,CTOTRS]
	SETZM	COSVAL
	TRMOP.	CX,
	  JFCL
	POPJ	P,
	SUBTTL	TTY: Service -- Wait for output to finish

PLM
;+
;.hl Routines WATOUT, WATDEQ, and WATIDL
MLP
;	These routines are called to block for various forms of TTY: output
;to complete.  WATDEQ waits until all buffers are dequeued and the buffer
;is empty.  WATIDL waits until the characters are also out of the chunks.
;WATOUT first calls WATDEQ and then WATIDL.  These routines uses no ACs.
PLM
;-
MLP

WATOUT:	PUSHJ	P,WATDEQ
	PJRST	WATIDL

WATDEQ:	PUSHJ	P,SAVT			;Save the Ts
	PUSH	P,F			;Save the flags
	TXZ	F,F$IOQ			;Must ignore here
	SKIPN	TOBUF			;Is there a buffer already?
	  JRST	WOUT5A			;No
	MOVE	T1,CHPBUF		;Get total number of available chars
	SUB	T1,TOBUF+2		;Real number of characters
	JUMPG	T1,WOUT2		;Nothing to do
	HRRZ	T1,TOBUF		;Get buffer pointer
	HRRZ	T2,BUFCHR		;Size
	MOVEI	T2,1(T2)		;Plus link
	PUSHJ	P,CORFRE		;Deallocate it
	JRST	WOUT5
WOUT2:	HRLM	T1,@TOBUF		;Store the count
	HRRI	T1,TOQUE		;Point to output queue
WOUT3:	HRL	T1,(T1)			;Get link
	TLNN	T1,-1			;Another buffer?
	  JRST	WOUT4			;No
	HLRZS	T1			;Point ahead
	JRST	WOUT3			;Continue

WOUT4:	HRL	T1,TOBUF		;Pointer to buffer
	HLRM	T1,(T1)			;Link it in
WOUT5:	SETZM	TOBUF
	SETZM	TOBUF+1
	SETZM	TOBUF+2			;Zap old pointers
WOUT5A:	MOVE	T4,TTYUDX
	MOVEI	T1,^D60			;Long wait for queueing
	TXO	F,F$IEC			;Ignore LDBECC
WOUT6:	SKIPN	TOQUE			;Anything more to queue?
	SKIPGE	TOBFH+.BFCNT		;Or output?
	  JRST	WOUT7			;Try to dequeue buffer
WATRET:	POP	P,T1			;Saved flags
	TXNE	T1,F$IOQ		;Was this set before?
	  TXO	F,F$IOQ			;Yes, set it again
	TXZ	F,F$IEC
	POPJ	P,
WOUT7:	PUSHJ	P,TOOUT			;Dequeue buffers
	SKIPN	TOQUE			;Still stuff to dequeue?
	SKIPGE	TOBFH+.BFCTR		;Or wait for I/O complete?
	  PUSHJ	P,TOHIBR		;Wait a bit
	JRST	WOUT6

WATIDL:	PUSHJ	P,SAVT			;Save the Ts
	PUSH	P,F			;Save the flags
	TXZ	F,F$IOQ			;Must ignore here
WATID1:	DMOVE	T2,[	2,,T3
			.TOSTP	]	;Output stopped?
	TRMOP.	T2,
	  SETZ	T2,			;Assume it isn't
	SKIPN	T2			;Output stopped?
	  TDZA	T1,T1			;No, short wait
	MOVEI	T1,^D60			;Else long wait
	DMOVE	T2,[	2,,T3
			.TOSOP	]	;Is output going on?
	TRMOP.	T2,
	  JRST	WATRET
	PUSHJ	P,TOHIBR		;Turn PIs off and wait
	JRST	WATID1			;Try to force out again
	SUBTTL	TTY: Service -- Wait for available buffer

PLM
;+
;.hl Routines TOBLOK and TOHIBR
MLP
;	Call TOBLOK to sleep until a buffer ready.  TOBLOK uses no ACs.
;Note that TOBLOK only waits for one buffer to become available
;(although more may in fact be available.  TOHIBR is used by TOBLOK and WATOUT
;to HIBER using the bits specified in T1 to HIBER with PSI turned off
;(HIBER doesn't hiber if this is not true and an interrupt is pending).
;TOHIBR destroys nothing.
PLM
;-
MLP

TOBLOK:	PUSHJ	P,SAVT
	MOVEI	T1,^D60			;Sleep time
	PUSH	P,F			;Save F
	TXO	F,F$IEC			;Ignore ECC
	TXZ	F,F$IOQ			;Clear this too
TOBLK1:	SKIPLE	BUFQUO			;One available?
	  JRST	TOBLK2			;Return
	PUSHJ	P,TOHIBR		;So can use PIOSAV
	PUSHJ	P,TOOUT
	JRST	TOBLK1

TOBLK2:	TXZ	F,F$IEC
	POP	P,T1
	TXNE	T1,F$IOQ		;Was this on?
	  TXO	F,F$IOQ			;Yes
	POPJ	P,

TOHIBR:	PUSHJ	P,TOHB2			;So can use PIOSAV
	SLEEP	T1,
	POPJ	P,

TOHB2:	PUSHJ	P,PIOSAV		;Must, so HIBER works
	SETZM	SLPFLG
	AOS	SLPFLG			;Set sleep flag
	POPJ	P,			;Return
	SUBTTL	TTY: Service -- Scan input for special characters

PLM
;+
;.hl Routine SCNSPC
MLP
;	Call SCNSPC to scan the input queue for "special" characters.
;Enter with T2 pointing to the appropriate "special" character table
;Returns CPOPJ1 if a special character is not found.
;Returns CPOPJ if one is found, with P4 pointing to
;the input buffer the character was found in (or 0 if in INPCHR),
;P1 containing the character,
;P3 containing the number of characters left in the buffer pointed to by P4,
;and P2 containing the LDB pointer to the character found (NOT ILDB!)
;Table CHRTAB is the bit mask to the "special" characters.
;SCNSPC will also set F$BRK if a break character (as defined by LMASK)
;is seen during the scan (i.e. before a special character if one is
;seen or in the whole string if no special characters).  ICHCNT will
;also be updated to be "correct" (no nulls counted) up to the point
;of scan termination.  Note that SCNSPC should NOT be called if
;not in "line" mode (as specified by F$PIM).  If neither a break nor a
;special character is found, P1 contains the last non-null character scanned.
;SCNSPC uses ALL ACs.
PLM
;-
MLP

SCNSPC:	SETZ	P1,			;Assume no special chars
	TXNE	F,F$PIM			;In "line" mode?
	  JRST	CPOPJ1			;No, nothing is special
	PUSH	P,P1			;Last non-special character
	TXZ	F,F$BRK!F$ESA		;Clear break seen, escape active
	SETZ	P4,			;In case we find it here
	SKIPN	P1,INPCHR		;Is there already one there?
	  JRST	SCNSP1			;Not set
	PUSHJ	P,SPCCHK		;Special character?
	  TRNA				;No
	JRST	TPOPJ			;Clear junk and return
SCNSP1:	MOVE	P1,BRKNUM		;Total number of breaks to pass
	MOVEM	P1,BRKCNT		;Initialize the count
	PUSHJ	P,SCNINI		;Init the character scanner
SPCLP:	PUSHJ	P,SCNCHR		;Get character from stream
	  JRST	P1POJ1			;Get last non-special and return
	JUMPN	P1,SPLOOK		;Look at character
	SOS	IBF.CT(P4)		;Get rid of null in
	SOS	ICHCNT			;Both character counts
	JRST	SPCLP
SPLOOK:	PUSHJ	P,SPCCHK		;Is it special?
	  TRNA				;Normal
	JRST	TPOPJ			;Clear junk and return
	PUSHJ	P,CHKBRK		;Break character?
	  TLOA	F,(F$BRK)		;Set seen
	MOVEM	P1,(P)
	JRST	SPCLP			;And look for more

;Here if want to continue scanning

CONSCN:	PUSH	P,[0]			;Last non-special
	JRST	SPCLP			;Continue

;PLM
;+
;.hl Routine SPCRMV
MLP
;	SPCRMV is a routine to remove a "special" character from
;the input stream and shuffle succeeding characters down.
;Call with P2, P3, P4 as returned from SCNSPC.  It uses P1-P3 and CX.
PLM
;-
MLP

SPCRMV:	SOS	IBF.CT(P4)		;Take the character out of the string
	SOS	ICHCNT			;Total number of chars now one less
	MOVNI	P1,1			;Back up the byte pointer
	ADJBP	P1,P2
	JUMPE	P3,CPOPJ		;If last character, don't worry
SPCRM1:	ILDB	CX,P2			;Get next character
	IDPB	CX,P1			;Move it back
	SOJG	P3,SPCRM1		;Move ahead
	POPJ	P,			;Done

PLM
;+
;.hl Routine SPCFLS
MLP
;	SPCFLS is a routine to FLUSH input up to the special chracter found
;by SCNSPC.  Call with P2, P3, P4 as returned from SCNSPC.  It uses T1-T2.
PLM
;-
MLP

SPCFLS:	MOVE	T1,IBF.CT(P4)		;Get total number of chars in buffer
	SUBI	T1,(P3)			;# skipped over
	SUBM	T1,ICHCNT		;ICHCNT now has -#chars
	MOVEM	P3,IBF.CT(P4)		;Set the count
	MOVEM	P2,IBF.PT(P4)		;Set the pointer
	MOVEI	T1,INPQUE-IBF.LK	;Point to start of input
FLSLP:	HRRZ	T1,IBF.LK(T1)		;Point to this buffer
	CAIN	T1,(P4)			;The current buffer?
	  JRST	FLSDON			;Yes
	SKIPLE	T2,IBF.CT(T1)		;If real characters,
	  ADDM	T2,ICHCNT		;"Subtract" from total
	SETZM	IBF.CT(T1)		;None there
	JRST	FLSLP			;Next buffer

FLSDON:	MOVNS	ICHCNT			;Make positive again
	PJRST	CNTESC			;Count number of breaks

PLM
;+
;.hl Routine SPCCHK
MLP
;	This is a routine to check if character in P1 is a "special" character.
;Return CPOPJ1 if it's special, CPOPJ otherwise.  It uses T1-T3.
PLM
;-
MLP

SPCCHK:	SOSGE	BRKCNT			;Count down number of breaks
	CAME	P1,ESCCHR		;No, is this it?
	  TRNA				;Yes or no
	JRST	CPOPJ1			;It's special
	TRNE	F,F$PALL!F$RALL		;Pass all?
	  POPJ	P,			;Yes
	MOVEI	T1,(P1)			;Make copy of char
	IDIVI	T1,^D36			;Make bit mask
	MOVNS	T2
	MOVSI	T3,400000
	LSH	T3,(T2)			;Get the mask
	TDNE	T3,CHRTAB(T1)		;Check the bit
	  AOS	(P)			;Flag found character
	POPJ	P,
	SUBTTL	TTY: Service -- Count number of escape characters

PLM
;+
;.hl Routine CNTESC
MLP
;	CNTESC is called to count the number of escape characters in the
;input stream and set BRKNUM to that number.
PLM
;-
MLP

CNTESC:	SAVE4
	PUSHJ	P,PIOSAV		;..
	PUSHJ	P,SCNINI		;Count number of escapes in stream
	SETZM	BRKNUM			;Number of break characters
CNTBRK:	PUSHJ	P,SCNCHR		;Get character
	  POPJ	P,			;Done
	CAMN	P1,ESCCHR		;Escape character?
	  AOS	BRKNUM			;Yes
	JRST	CNTBRK			;Continue
	SUBTTL	TTY: Service -- Input scan routines

PLM
;+
;.hl Routines SCNINI  SCNCHR, SCNLBK and SCNLCH
MLP
;	These routines are used to scan the input queue
;for certain conditions being met.  You must preserve all
;"P" ACs across calls to these routines in order to use these routines.
PLM
;.list 1
;.le
MLP
;SCNINI - Set up "P" ACs for an input scan.
;SCNINI uses no ACs other than the "P"s.
PLM
;-
MLP

SCNINI:	SKIPN	P4,INPQUE			;Point to input queue
	  JRST	[MOVEI	P4,INPQUE-IBF.LK
		 SETZ	P3,			;There's nothing to read
		 POPJ	P,		]
	MOVE	P3,IBF.CT(P4)			;Count
	MOVE	P2,IBF.PT(P4)			;Pointer
	SETZ	P1,				;No initial character
	POPJ	P,

PLM
;+
;.le
MLP
;SCNCHR - Return with next input character in T1.  Return CPOPJ1 if
;a character is present, CPOPJ if done.
PLM
;-
MLP

SCNNEW:	SKIPG	P4,IBF.LK(P4)			;Point to next buffer
	  POPJ	P,				;If none
	MOVE	P3,IBF.CT(P4)
	MOVE	P2,IBF.PT(P4)

SCNCHR:	SOJL	P3,SCNNEW			;New buffer time
	ILDB	P1,P2
	ANDI	P1,177			;Strip parity
	JRST	CPOPJ1

PLM
;+
;.le
PLM
;SCNPOS - Given ACs as returned from SCNSPC, figure the position
;in the input stream of the special character.  It uses T1-T2.
PLM
;-
MLP

SCNPOS:	MOVNI	T1,(P3)			;Initialize the count
	MOVEI	T2,(P4)			;Init buffer link
POSLP:	SKIPG	T2,IBF.LK(T2)		;Next
	  JRST	POSDON			;Done
	SUB	T1,IBF.CT(T2)		;Subtract the characters
	JRST	POSLP

POSDON:	ADD	T1,ICHCNT		;From total
	POPJ	P,


PLM
;+
;.le
MLP
;SCNLBK - Scan to last break character before character pointed to
;by P2.  It uses T1-T4 also.
PLM
;-
MLP

SCNLBK:	MOVE	T1,P2			;Save pointer
	PUSHJ	P,SCNINI		;Re-initialize
	ADJSP	P,4			;Allocate stack space
	DMOVEM	P1,-3(P)
	DMOVEM	P3,-1(P)		;Initially the beginning
	PUSH	P,T1			;And save the pointer
SCNLB1:	CAMN	P2,(P)			;The final pointer?
	  JRST	SCNLB3			;Yes
	PUSHJ	P,SCNCHR		;Scan a character
	  ERR	CSC,<Couldn't find specified character>
	PUSHJ	P,CHKBRK		;Is it a break?
	CAMN	P2,(P)			;Yes, but not the target char
	  JRST	SCNLB1			;No, loop back
	DMOVEM	P1,-4(P)		;Save the ps
	DMOVEM	P3,-2(P)		;..
	JRST	SCNLB1

SCNLB3:	POP	P,(P)			;...
	PJRST	.RES4			;Restore Ps

PLM
;+
;.le
MLP
;SCNLCH - Scan to immediately preceding character.
;Scan to character preceding that pointed to by P4.
;Return with Ps intact, and Ts set to values from SCNINI/SCNCHR.
PLM
;-
MLP

SCNLCH:	SAVE4				;Save the Ps
	PUSHJ	P,SCNINI		;Initialize a scan
	TXO	F,F$P2			;General PASS2 flag
SCNLC1:	DMOVE	T1,P1			;Save it's first character
	DMOVE	T3,P3
	PUSHJ	P,SCNCHR		;Get chracter
	  POPJ	P,			;?
	CAMN	P2,-3(P)		;POinters match
	  POPJ	P,			;Return if so
	TXZE	F,F$P2			;If haven't already
	  AOS	(P)			;Flag at least one char to undo
	JRST	SCNLC1

PLM
;+
;.le
MLP
;SETICH - Set ICHCNT to be accurate (toss nulls).
PLM
;-
MLP

SETICH:	SAVE4				;Save the Ps
	PUSHJ	P,SCNINI		;Input a character
ICHLP:	PUSHJ	P,SCNCHR		;Get a character
	  JRST	SETIC2			;More
	JUMPN	P1,ICHLP		;If non-zero, nothing
	SOS	IBF.CT(P4)		;Decrement chunk count
	SOS	ICHCNT			;And total count
	JRST	ICHLP

SETIC2:	SKIPGE	ICHCNT
	  SETZM	ICHCNT			;It's really zero
	POPJ	P,

PLM
;+
;.end list
;-
MLP
	SUBTTL	TTY: Service -- Check for break character

PLM
;+
;.hl Routines CHKBRK and CHKBR1
MLP
;	Enter at CHKBRK with the character in question in P1;
;enter at CHKBR1 with character in T1 to save T1 (RH only saved)
;Return CPOPJ if character IS in the break set, CPOPJ1 otherwise
PLM
;.note
MLP
;Location BRKSIZ is incremented each time a compenent of a break is passed.
;***IT IS THE RESPONSIBILITY OF THE CALLER TO BE SURE LOCATION BRKSIZ
;IS ZEROED AT THE RIGHT TIME***
PLM
;.end note
MLP
;Both routines use T1-T4 and CX, except that CHKBR1 saves the right half
;of T1.  If the character in T1 IS a break character, CHKBR1 will store it
;in the left half of location BRKCHR.
PLM
;-
MLP

CHKBRK:	SKIPA	T1,P1			;Copy to T1
CHKBR1:	HRLM	T1,BRKCHR		;Assume it's a character
	TXNE	F,F$ESC			;Want escape sequences?
	  JSP	CX,CHKESC		;Yes
	IDIVI	T1,^D32			;Compute index to word
	MOVSI	CX,(1B0)		;Make a mask
	MOVNS	T2
	LSH	CX,(T2)			;Compute bit mask
	TDNN	CX,LMASK(T1)
	  AOSA	(P)			;Skip return if not a break
	AOSA	BRKSIZ			;Increment break size
	  SKIPA	T1,BRKCHR		;Get character back
	SKIPA	T1,BRKCHR		;...
	  HRRZS	BRKCHR			;No break yet
	HLRZS	T1			;And restore character to T1
	POPJ	P,
	SUBTTL	TTY: Service -- Control-H Routine

PLM
;+
;.hl Control-H processing
MLP
;CHKCTH uses T1 and is called to see if the character in P1 is a control-H
;and if so, see if we should output one to the TTY:.  This is for the benefit
;of those operating systems from whom control-H doesn't function as a rubout
;and isn't a break.
PLM
;-
MLP

CHKCTH:	MOVE	T1,ICHCNT			;Get characters available
	EXCH	T1,LICHCT			;Update
	CAME	T1,LICHCT			;As we last remember it?
	CAIE	P1,.CHCNH			;Yes, did we break for ^H?
	  POPJ	P,				;Doesn't apply then
	TXNE	F,F$NEC				;Noechoed?
	  POPJ	P,				;Doesn't apply then
	MOVEI	T1,($TOOIN)			;Override inhibit
	MOVEM	T1,TOFLGS
	MOVEI	T1,.CHCNH			;Else output one
	PUSHJ	P,OUTTTY
	PUSHJ	P,DOOUT1
	SETZM	TOFLGS
	POPJ	P,
	SUBTTL	TTY: Service -- Escape Sequence processing

PLM
;+
;.hl Escape sequence processing
MLP
;CHKESC is called to check if an escape sequence is beginning or ending.
;If the escape sequence finishes, then F$BRK is set.  If an escape sequence
;begins, then F$ESA is set.  If a bad character is encountered during
;processing, then F$BAD is set.  CHKBRK/CHKBR1 and EKOTAH use this routine.
;It will increment BRKSIZ appropriately to the size of the escape sequence.
;An <ESC> will be stored in BRKCHR.  The table driven routine for validating
;the escape sequences is rumoured to let a few bad sequences through, but
;should definitely pass all good ones.  It was obtained from WSM of ISWS
;who borrowed it from another ISWSite who modified it from VMS' TTDRIVER
;(friend of a friend of a friend...).
PLM
;.note
MLP
;***Note that it is the caller's responsibility to initialize the appropriate
;parts of the data base, in particular, F$ESA.  Note also that in general
;the base must be re-inited at each read request because of multiple
;scanning passes of the same stream with each read request, so
;all bets are off if a partial escape sequence has to be stored
;(i.e. the escape sequence gets split over a read request).  VMS
;doesn't guarantee integrity across such anyway and RSX states nothing
;about it.  The processing uses T1-T4 and CX.
PLM
;.end note
;-
MLP

CHKESC:	TXNE	F,F$ESA			;Escape sequence already active?
	  JRST	ESCACT			;Yes
	CAIE	T1,.CHESC		;Is this an escape?
	  JRST	(CX)			;No
	TXO	F,F$ESA			;Escape sequence now active
	AOS	BRKSIZ			;BRKSIZ one bigger
	SETZM	RULE			;Let's start at the very beginning...
	TXZ	F,F$BAD			;Assume a good escape sequence
	SETOM	IMASK+1			;Break on all now
	MOVE	T1,[IMASK+1,,IMASK+2]
	BLT	T1,ENDMSK
	MOVEI	T1,1			;Let the field width be 1
	MOVEM	T1,IMASK
	AOS	(P)			;Not a break yet
	PUSHJ	P,TTYSST		;Set up TTY:
	PJRST	FRCTTI			;Be sure see changes

ESCACT:	JUMPE	T1,CPOPJ1		;Toss nulls (incomplete requests)
	MOVE	CX,RULE			;Get the current rule
	PUSH	P,T2			;Need another bunch of ACs
	PUSH	P,T3			;...
ESCLOP:	LDB	T2,[POINT 7,ESCTAB(CX),6]
	LDB	T3,[POINT 7,ESCTAB(CX),13] ;Get lower and upper bounds
	CAIL	T1,(T2)
	CAILE	T1,(T3)			;Is character between them?
	  JRST	ESCAC5			;No
	AOS	BRKSIZ			;Break is one character bigger
	HRRZ	CX,ESCTAB(CX)		;In between, more rules?
	JUMPE	CX,ESCDON		;No, finished
	MOVEM	CX,RULE
	AOS	-2(P)			;Skip return
	JRST	ESCRET			;Restore T2, T3 an return
ESCAC5:	HRRZ	T2,ESCTAB(CX)		;Didn't fit, another rule?
	JUMPE	T2,ESCERR		;Bad escape sequence
	AOJA	CX,ESCLOP		;Check it

ESCERR:	TXO	F,F$BAD			;Bad escape sequence
ESCDON:	TXZ	F,F$ESA			;No longer active escape
	MOVEI	T3,.CHESC		;Break character is escape
	HRLM	T3,BRKCHR		;Save it
ESCRET:	POP	P,T3
	POP	P,T2			;Restore ACs
	PJRST	TTYSST			;Return, resetting TTY:
	SUBTTL	TTY: Service -- Escape sequence processing tables

PLM
;+
;.hl Table ESCTAB
MLP
;	ESCTAB is the rule table used by CHKESC to define what is a legal
;ANSI escape sequence.
PLM
;-
MLP

ESCTAB:
	<ASCII |;;|>	!$10-ESCTAB	; <ESC><;><40:57>...<60:176>
	<ASCII |??|>	!$10-ESCTAB	; <ESC><?><40:57>...<60:176>
	<ASCII |OO|>	!$20-ESCTAB	; <ESC><O><40:57>...<100:176>
	<ASCII |YY|>	!$30-ESCTAB	; <ESC><Y><40:176>...<40:176>
;ANSI control sequence
	<ASCII |[[|>	!$15-ESCTAB	; <ESC><[><40:77>...<40:57>...<100:176>
;ESCape sequence			  <ESC><40:57>...<60:176>

$10:	<ASCII | /|>	!$10-ESCTAB
	<ASCII |0~|>	!0
$15:	<ASCII |0?|>	!$15-ESCTAB
$20:	<ASCII | /|>	!$20-ESCTAB
	<ASCII |@~|>	!0
$30:	<ASCII | ~|>	!$40-ESCTAB
$40:	<ASCII | ~|>	!0
	Z
	SUBTTL	TTY: Service -- Echo type-ahead

PLM
;+
;.hl Routine EKOTAH
MLP
;	EKOTAH is called to echo all characters in the input queue.  It should,
;of course, only be called once for a given input stream.  It uses T1-T4.
PLM
;-
MLP

EKOTAH:	TXNE	F,F$NEC			;Noecho?
	  POPJ	P,			;Nice if filtered out earlier, but...
	SAVE4				;Save the Ps
	TXO	F,F$NEC			;Set no-echo
	PUSHJ	P,TTYSST
	PUSHJ	P,CLRCTO
	PUSHJ	P,WATDEQ		;Wait for output to complete
	MOVEI	P1,($TOICL!$TOOIN)	;Buffer flags
	IORM	P1,TOFLGS
	PUSHJ	P,SCNINI		;Init a scan
ECHOLP:	PUSHJ	P,SCNCHR		;Get a character
	  JRST	EKOTAD			;Done
	MOVEI	T1,(P1)			;Copy character
	PUSHJ	P,CHKBR1		;Break?
	  JRST	[PUSHJ	P,DOOUT1
		 SETZM	TOFLGS
		 JRST	EKOTAR	]	;Done
	TXNE	F,F$ESC			;Wanted ESC stuff?
	TXZN	F,F$ESA			;It became active?
	  TRNA
	JRST	EKOTAR
	PUSHJ	P,OUTTTY		;For now, assume just print it
	JRST	ECHOLP			;Continue

EKOTAD:	PUSHJ	P,DOOUT1		;Force it out
	SETZM	TOFLGS			;Clear the flags
	PUSHJ	P,WATOUT		;Wait for it to complete
;Note that the below is a heuristic algorithm rather than a water-tight one.
DOFRCU:	MOVE	T1,[2,,T2]		;Make sure it's OK to do this
	MOVEI	T2,.TOBKC		;Get break count
	MOVE	T3,TTYUDX
	TRMOP.	T1,			;...
	  JRST	EKOTAR
	JUMPN	T1,EKOTAR		;Don't do it
	MOVE	T1,[2,,T2]		;Only if priv'd, but c'est la vi
	MOVE	T2,[SIXBIT/.TYPE/]
	MOVE	T3,TTYUDX
	FRCUUO	T1,
	  JFCL
EKOTAR:	TXZ	F,F$NEC
	PJRST	TTYSST
	SUBTTL	TTY: Service -- Rubout processing

PLM
;+
;.hl Routine DORUB
MLP
;	DORUB is called to do the "normal" thing on a rubout, that is,
;rub out the last character.  It uses T1-T4 and P1-P4.  Call it with
;P1-P4 set from SCNSPC.
PLM
;-
MLP

DORUB:	PUSHJ	P,SCNLCH		;Scan to last character
	  JRST	SPCRMV			;Remove the <RUB> and return
	ADJSP	P,4			;Allocate stack space
	DMOVEM	T1,-3(P)		;Save where last char is
	DMOVEM	T3,-1(P)		;..
	PUSHJ	P,SPCRMV		;Remove the rubout
	DMOVE	P1,-3(P)		;Restore stuff to Ps
	DMOVE	P3,-1(P)
	ADJSP	P,-4			;and fix stack
	PUSHJ	P,CHKBRK		;Is this a break?
	  POPJ	P,			;Just toss rubout if break
	LDB	T1,P2			;Get character rubbed out
	CAMN	T1,ESCCHR		;Escape character?
	  SOS	BRKNUM			;Yes, one less to scan past
	PUSHJ	P,RUBCHR		;Do a rubout
	PUSHJ	P,SPCRMV		;Remove character
	POPJ	P,			;Return
	SUBTTL	TTY: Service -- Routine to do display for <RUB>

PLM
;+
;.hl Routines RUBCHR and VIDRUB
MLP
;	RUBCHR is called with the rubbed out character in T1.  Its purpose
;is to do the "right" think on the screen.  VIDRUB is called if we are on
;a CRT; it uses a table indexed by TTY: type to decide the sequence to
;rubout the character on the screen.  Otherwise, the rubbed out character
;is delimeted by backslashes (consecutive characters get two backslashes
;between them).
PLM
;-
MLP

RUBCHR:
	PUSH	P,T1			;Save character
	MOVEI	T1,($TOOIN)
	MOVEM	T1,TOFLGS
	SKIPL	T1,TTYTYP		;Can we do a video rubout?
	  JRST	VIDRUB			;yes
	MOVEI	T1,"\"			;Delimit rubbed out char
	PUSHJ	P,OUTTTY
	POP	P,T1			;Restore character
	PUSHJ	P,OUTTTY		;...
	MOVEI	T1,"\"
	PUSHJ	P,OUTTTY		;..
RUBRET:	PUSHJ	P,DOOUT1
	SETZM	TOFLGS
	POPJ	P,

VIDRUB:	PUSH	P,T4			;Save T4
	SOSGE	T4,HPOS			;Be sure this is set correctly
	  SETZ	T4,			;No negative positions
	PUSH	P,T4
	HRRZ	T4,RUBS1(T1)		;Point to string
	PUSHJ	P,STROUT		;Output it
	POP	P,HPOS			;Set HPOS correctly
	POP	P,T4			;Restore T4
	POP	P,T1
	JRST	RUBRET
	SUBTTL	TTY: Service -- Handle Control-U

PLM
;+
;.hl Routine DOCTU
MLP
;	DOCTU is called to do "normal" Control-U processing.  Call it with
;P1-P4 set from SCNSPC.  It uses P1-P4 and T1-T4.
PLM
;-
MLP

DOCTU:	ADJSP	P,3			;Allocate stack space
	DMOVEM	P2,-2(P)		;Save P2 and P3
	HRRZM	P4,(P)			;And right half of P4
	PUSHJ	P,SCNLBK		;Scan to last break
	HRRZS	P4			;Be sure only right half
	CAMN	P4,(P)			;In the same chunk?
	  JRST	DOCTU5			;Yes, handle differently
	SUBM	P3,ICHCNT		;All remaining chars in this chunk gone
	SUBM	P3,IBF.CT(P4)		;And here
	MOVNS	IBF.CT(P4)		;Keep the right sign
DOCTU2:	HRRZ	P4,IBF.LK(P4)		;Point to next link
	CAMN	P4,(P)			;One with the ^U in it?
	  JRST	DOCTU3			;Yes
	MOVE	T1,IBF.CT(P4)		;Get the count
	ADDM	T1,ICHCNT		;Remember ICHCNT has the wrong sign
	SETZM	IBF.CT(P4)		;No chars in this chunk
	JRST	DOCTU2			;Until we hit the ^U

DOCTU3:	POP	P,P4			;Restore where ^U was
	POP	P,P2			;Count
	POP	P,IBF.PT(P4)		;It's where input will start
	EXCH	P2,IBF.CT(P4)		;Number of chars left
	SUB	P2,IBF.CT(P4)		;Difference=# chars skipped
	ADDM	P2,ICHCNT		;Take out of total
	MOVNS	ICHCNT			;And make right sign
DOCTU4:	MOVEI	T4,[ASCIZ/^U
/]					;Tell what we did
	MOVEI	T1,($TOOIN)
	MOVEM	T1,TOFLGS		;Override stuff
	PUSHJ	P,STROUT
	PUSHJ	P,DOOUT1		;Force it out
	SETZM	TOFLGS
	PJRST	CNTESC			;Set BRKNUM

DOCTU5:					;Here if ^U and last break in same chunk
	SUB	P3,-1(P)		;# of chars skipped in chunk
	MOVNS	P3			;Make negative
	ADDM	P3,ICHCNT		;So can take out of total
	ADDM	P3,IBF.CT(P4)		;And in this chunk
	POP	P,T4			;Restore pointers in Ts
	POP	P,T3
	POP	P,T2
	JUMPE	T3,DOCTU4		;If nothing else to do
DOCTU6:	ILDB	P1,T2
	IDPB	P1,P2			;Else shuffle characters down
	SOJGE	T3,DOCTU6
	JRST	DOCTU4			;Then return
	SUBTTL	TTY: Service -- Handle Control-R

PLM
;+
;.hl Routine DOCTR
MLP
;	DOCTR is called to handle a Control-R.  Call it with P1-P4 set
;up from SCNSPC and T1 set to address of routine to call after
;outputting "^R<CR><LF>", or zero if none..  It uses P1-P4 and T1-T4.
PLM
;-
MLP

DOCTR:	MOVEI	T4,[ASCIZ/^R
/]					;Preceed with <CRLF>
	PUSH	P,T1			;Save the routine address
	MOVEI	T1,($TOOIN)
	MOVEM	T1,TOFLGS
	PUSHJ	P,STROUT		;Output it
	POP	P,T1			;Get the routine address
	JUMPE	T1,DOCTR0		;None
	PUSHJ	P,(T1)			;Call it
	MOVEI	T1,($TOOIN)
	MOVEM	T1,TOFLGS		;Some routines trash this
DOCTR0:	PUSHJ	P,SCNLBK		;Scan to last break
DOCTR1:	PUSHJ	P,SCNCHR		;Get a character
	  JRST	DOCTR3			;Finish up then
	CAIN	P1,.CHCNR		;Is this the ^R?
	  JRST	DOCTR2			;Yes
	MOVEI	T1,(P1)			;Get character
	PUSHJ	P,OUTTTY		;Output it
	JRST	DOCTR1

DOCTR2:	PUSHJ	P,SPCRMV		;Remove the character now
DOCTR3:	PUSHJ	P,DOOUT1		;Force out
	SETZM	TOFLGS
	POPJ	P,			;Return
	SUBTTL	TTY: Service -- Set to handle ^U, ^R, <RUB>

PLM
;+
;.hl Routine STRURB
MLP
;	STRURB is called to set up masks and the TTY: to be sure we
;handle Ctl-U, Ctl-R, and Rubout ourselves.  It uses T1.
PLM
;-
MLP

STRURB:	TXO	F,F$RUB				;Flag to handle it ourselves
	MOVX	T1,<1B<.CHCNR>!1B<.CHCNU>>
	IORM	T1,IMASK+1
	MOVEI	T1,1B31				;<RUB>
	IORM	T1,IMASK+1+3
	SETZM	IMASK				;TTYSST sets field width to 1
	PUSHJ	P,TTYSST			;Set up TTY:
	PJRST	FRCTTI				;Wake us up
	SUBTTL	TTY: Service -- Clear Handling of ^U, ^R, <RUB>

PLM
;+
;.hl Routines UNRURB and UNRALL
MLP
;	UNRURB and UNRALL clear NRT's handling of Ctl-R, Ctl-U, and Rubout.
;Call UNRALL to clear checking of Ctl-R, Ctl-U, and Rubout unconditionally.
;Call UNRURB to clear "specialness" of UNRURB but not in the mask
;if they are supposed to be reak characters.  These routines use T1 and T2.
;Call them with T3 containing the field width to be set (field width
;gets set to one so we can handle Ctl-U, Ctl-R, and Rubout correctly).
PLM
;-
MLP

UNRURB:	MOVX	T1,<1B<.CHCNR>!1B<.CHCNU>>
	XOR	T1,LMASK
	ANDX	T1,<1B<.CHCNR>!1B<.CHCNU>>
	MOVEI	T2,1B31				;Rubout
	XOR	T2,LMASK+3
	ANDI	T2,1B31
	JRST	DOUNRU

UNRALL:	MOVX	T1,<1B<.CHCNR>!1B<.CHCNU>>
	MOVEI	T2,1B31				;And rubout
DOUNRU:	ANDCAM	T1,IMASK+1
	ANDCAM	T2,IMASK+1+3
	MOVEM	T3,IMASK
	PUSHJ	P,TTYSST
	PJRST	FRCTTI				;Wake up and return
						;No-filter
	SUBTTL PSION/OFF - Turn on/off the software interrupt system

PLM
;+
;.hl Routines PSIOFF, PSION, and PIOSAV
MLP
;	These routines are used to manipulate the software interrupt system.
;PSIOFF turns the interrupt system of and PSION turns it on.  PIOSAV
;is a co-routine called to be sure the interrupt system is off for a subroutine
;and automatically turn it back on (if it was on entry to the subroutine) on
;exit from the subroutine.  All routines use only CX.
PLM
;-
MLP

PSIOFF:	SAVET1
	MOVX	T1,<PS.FOF>
	PISYS.	T1,
	 ERR	UTF,<PISYS. UUO Unable to turn off interrupts>
	TLZ	F,(F$PION)		;PSI isn't on
	POPJ	P,

PIOSAV:	TLZN	F,(F$PION)		;If PSI wasn't on,
	  POPJ	P,			;Just return
	PUSHJ	P,PSIOFF		;Turn off PSI
	PUSHJ	P,@(P)			;Call caller
	  TRNA				;Non-skip
	AOS	-1(P)			;Skip
	POP	P,(P)
PSION:	SAVET1				;save T1
	TLO	F,(F$PION)		;PSI is on
	MOVX	T1,<PS.FON>		;Turn the system on
	PISYS.	T1,			;Now
	 ERR	UTN,<PISYS. UUO Unable to turn on interrupts>
	POPJ	P,			;Return
	SUBTTL	NSP. Routines -- NSPEA - Make an active connection

PLM
;+
;.hl Routine NSPEA
MLP
;	NSPEA does an enter active to a remote's NRTSRV.  We are assuming
;that CONBLK has been set up already.  NSPEA decides to enter either .OBHTH
;or .OBPST depending on the number of nodes the user has specified.
;NSPEA uses CX.  NSPEA returns CPOPJ with the NSP. error code set
;up by SETNER on error, or returns CPOPJ1 with the connection set up.
;If FTPMR is on, NSPEA calls PMR, an external subroutine to actually
;do the connection so.  PMR handles "automatic" Poor Man's Routing
;as specified in the file DCN:DNHOST.TXT.
PLM
;-
MLP


NSPEA:	SAVET1			;Save T1
IFN FTPMR,SKIPG	NODCNT		;Doing PMR?
	 SKIPA	T1,[.OBHTH]	;Not PMR
	MOVEI	T1,.OBPST	;PMR.
	MOVEM	T1,DSTPDB+.NSDOB ;Store it
	MOVE NSAFN,[NS.WAI!<.NSFEA>B17!<.NSAA2>+1] ;Set up the function word
	SETZ	NSACH,		;No channel yet
	MOVEI NSAA1,CONBLK	;Point to the connect block
	MOVE	NSAA2,TTBAUD	;Get baud rate
	CAILE	NSAA2,SEGMAX	;Bigger than max?
	  SETZ	NSAA2,		;Use default then
	MOVE	NSAA2,SEGTBL(NSAA2)	;Get the entry
	MOVEI T1,NSAFN		;Point to the function block
IFN	FTPMR,<
	TXO	T1,PMR$RMR!PMR$DCN	;Set to always do direct connection
	PUSHJ	P,PMR##		;(Look on DCN: to keep TEN happy)
>
IFE	FTPMR,<
	NSP. T1,		;Enter Active
>
	  PJRST SETNER	;Set up NSP. error code for NSPERR
	MOVEM	NSACH,NSPACS+NSACH	;Channel is global
	MOVEM	NSACH,TTYACS+NSACH
	MOVEM	NSACH,TMRACS+NSACH
	JRST	CPOPJ1			;Return

	SUBTTL	NSP. Routines -- Set Link Quotas

PLM
;+
;.hl Routine SETQUO
MLP
;	This routine is called to set the link quotas of the link based
;on the controlling TTY:'s baud rate.  This is so that if functions
;(such as ^O to TOPS-10 or TOPS-20, for example) which are handled
;remotely are requested, they will not take too long due to network
;messages which have already been buffered ahead.

SETQUO:	MOVE	NSAFN,[.NSFRQ,,.NSAA3+1]
	MOVEI	T1,NSAFN
	NSP.	T1,
	  POPJ	P,		;Can't do anything
	MOVE	CX,TTBAUD	;Get the baud rate
	CAILE	CX,QUOMAX	;Up to a certain point only
	  SETZ	CX,
	HRLI	NSAFN,.NSFSQ	;Set quotas and goals
	MOVEI	T1,NSAFN
;Note that the below could be done in one NSP. UUO.  It is done
;in two so that if the setting of the goal fails, the %input will
;still get set.  We assume that the goal may fail due to privilege
;violation if the default goal is set to a low value (at this point
;the monitor doesn't privilege check at all; the goal at this
;point in time is to make the monitor fail if the user tries to set
;the goal higher than the default but not lower.  This may change,
;however).
	HLRE	NSAA2,QUOTBL(CX) ;Get % to allocate
	JUMPL	NSAA2,SETQU1	;No change
	NSP.	T1,
	  POPJ	P,		;Oh well
SETQU1:	HRRE	NSAA3,QUOTBL(CX) ;Get goal
	JUMPL	NSAA3,CPOPJ	;No change
	NSP.	T1,
	  JFCL
	POPJ	P,
	SUBTTL NSP. Routines -- NSPIN - NSP. Input routine

PLM
;+
;.hl Routines NSPIN and NSPINW
MLP
;	NSPIN is called to input data from the network.  It returns
;CPOPJ1 on success, or through SETNER on failure.  On success, INPBUF
;will contain the network data, IBFCNT will contain the byte count, and
;IBFPTR is the ILDB pointer to the data stored at INPBUF.  If called at
;NSPINW, the routine will block until a complete message is read or
;the buffer is full.  If called at NSPIN and an incomplete message is
;only available (and the buffer isn't filled), then it will restore ACs
;and dismiss the interrupt in progress. 
PLM
;.note ***WARNING***
MLP
;NOTE THAT BECAUSE OF THE ABOVE, NSPIN SHOULD BE CALLED ONLY AT NETWORK
;INTERRUPT LEVEL.
PLM
;.end note
MLP
;When a network interrupt signals more data is ready, network interrupt
;service will return here to complete the message.  When it is complete
;(or the buffer is full), NSPIN will return to the caller.
;These routines use CX and the NSP ACs.
PLM
;-
MLP

NSPINW:	SKIPA	NSAFN,[NS.WAI!<.NSFDR>B17!4]
NSPIN:	MOVE NSAFN,[<.NSFDR>B17!4] ;Set up function word
	SAVET1			;Save T1
NSPCON:	TXNE	F,F$NEOM	;Seen EOM last?
	  JRST	DONSPI		;No, don't re-init
	SETZM	IBFCNT
	MOVEI	NSAA1,IBUFSZ	;Get this many bytes if possible
	MOVE	NSAA2,[POINT 8,INPBUF] ;Make up the pointer
DONSPI:	MOVEI	T1,NSAFN	;Point to the function block
	MOVE	CX,NSAA1	;Copy available chars to T1
	NSP.	T1,		;Data Read
	PJRST	SETNER		;Set up NSP. error code for NSPERR
	TXNN	NSAFN,NS.EOM	;End of message?
	 TXOA	F,F$NEOM	;Set the NOT EOM flag
	TXZ	F,F$NEOM	;Clear the more to come flag
	SUB	CX,NSAA1	;Calculate how many we have
	ADDM	CX,IBFCNT
	TXNE	NSACH,NS.NDA	;Normal data available?
	  TXNE	NSAFN,NS.EOM	;Yes, is was EOM seen?
	TRNA			;No data available or EOM
	JUMPG	NSAA1,DONSPI	;No EOM and data available, get if more room
	SKIPN	IBFCNT		;Anything there?
	 TXZ	F,F$NEOM	;No, then clear this flag
	JUMPE	NSAA1,NINSAT	;Satisfied if full
	TXNN	F,F$NEOM	;EOM seen
	  JRST	NINSAT		;Satisfied
	PUSHJ	P,EXCACS	;Restore the ACs
	  EXP	NSPACS
	SETOM	INTLVL		;Free the interlock
	DEBRK.
	  ERR	DNI,<DEBRK. not implemented>
	POPJ	P,
NINSAT:	MOVE T1,[POINT 8,INPBUF-1,35] ;Make the pointer up again
	MOVEM T1,IBFPTR		;Fake this, also
	JRST	CPOPJ1

	SUBTTL  NSP. Routines -- NSPOUT - Outputs OTPBUF to the network

; Called: OBFPTR/ byte pointer to last data byte
PLM
;+
;.hl Routine NSPOUT
MLP
;	NSPOUT is called to output the buffer pointer to by OBFPTR to
;the network.  This routine call QUEOUT to output buffer, and falls
;into NSPO which attempts to output the buffer.  NSPO is also called
;at network interrupt level to force out any buffers which had previously
;been queued (via calling NSPOUT) but could not be output.  When buffers
;are completely output, they are returned to the free core pool.
;NSPOUT uses no ACs (other than the NSP ACs); NSPO uses T1-T4.
;The buffer will be sent with EOM unless the sign bit is on in the
;count field of the buffer header, or F$NEOM is set and this is NOT
;the last buffer in the queue.
PLM
;-
MLP

NSPOUT:	PUSHJ	P,SAVT		;Save the Ts
	PUSHJ	P,QUEOUT	;Queue netword output buffer
	FALL	NSPO		;Fall into NSPO

NSPO:	SKIPN	T2,OUTQUE	;Anything in the output queue?
	  JRST	CPOPJ1		;Done
	HLRZ	NSAA1,OBF.CT(T2);Get count
	MOVE	NSAA2,OBF.PT(T2);And pointer
	MOVE	NSAFN,[NS.EOM!<.NSFDS>B17!.NSAA2+1] ;Set up function word
				;NSAA1 (the count was set up before)
	HRRZ	T3,OBF.LK(T2)	;Pointer to next
	JUMPE	T3,NSPO1	;If zero, follow EOM in buffer
	TXNN	F,F$EOMN	;Else use set flag
NSPO1:	TRZE	NSAA1,400000	;Sign bit set?
	  TXZ	NSAFN,NS.EOM	;Then clear EOM
	MOVEI	T1,NSAFN	;Pointer to argument block
	NSP.	T1,		;Data Send
	PJRST	SETNER		;Set up NSP. error code and return
	MOVEI	T1,(T2)		;Transfer ACs
	JUMPN	NSAA1,NSPEXI	;If didn't finish
	HRRZM	T3,OUTQUE	;Point to it
	MOVEI	T2,OBUFSZ+OBF.DT;Size of buffer
	PUSHJ	P,CORFRE	;Deallocate it
	JRST	NSPO		;Back for more

NSPEXI:	HRLM	NSAA1,OBF.CT(T1);Save count
	MOVEM	NSAA2,OBF.PT(T1);And pointer
	AOS	(P)
	POPJ	P,		;Success return
PLM
;+
;.hl Routines NETQUE and QUEOUT
MLP
;	NETQUE and QUEOUT are called to queue the buffer pointed to by
;OTPBUF into the network output queue, where it will be pushed out via
;NSPO.  NETQUE uses no ACs; QUEOUT uses T1-T4.  Both use the byte pointer
;in the buffer header to compute the number of bytes in the buffer.  If
;the sign bit of OTPBUF is on, the buffer will be flagged to be output without
;EOM.  This is done by setting the sign bit of the count word of the buffer.
;These routines also call INOBUF after queueing the current buffer to
;initialize a new one.
PLM
;-
MLP

NETQUE:	PUSHJ	P,SAVT		;With all ACs saved
	HRROS	OTPBUF		;Force no EOM
QUEOUT:	MOVE	T1,OTPBUF	;Point to buffer
	MOVE	T1,OBF.PT(T1)	;Get pointer
	MOVE	T2,OBFPTR	;Get current location pointer
	PUSHJ	P,BPLENG	;Calculate length based on difference
	SKIPGE	T2,OTPBUF	;See if sign bit is set...
	  TRO	T1,400000	;Set no EOM when sending
	HRLZM	T1,OBF.CT(T2)	;Store count there
	MOVEI	T3,OUTQUE-OBF.LK
OUTCHK:	SKIPE	T4,OBF.LK(T3)	;Make first time a litte faster
	TRNN	T4,-1		;Pointer to next?
	  JRST	OUTFND		;No
	HRRZI	T3,(T4)		;Get next entry
	JRST	OUTCHK		;Continue

OUTFND:	HRRM	T2,OBF.LK(T3)	;Queue it up
	PJRST	INOBUF		;Re-init the output buffers

	SUBTTL SETNOD - Sets up node name in ASCNOD in the connect block

PLM
;+
;.HL Routine SETNOD
MLP
;	SETNOD is called to translate the SIXBIT node name stored at RNODE
;into an eight-bit ASCII name in the connect block, suitable for use in
;the NSP. .NSFEA function.  It falls into SIX2SB and therefore uses
;T1-T2 and P1-P2.
PLM
;-
MLP

SETNOD:	MOVE T1,RNODE		;Get the node name
	MOVEI T2,ASCNOD		;PUT IT IN THIS STRING BLOCK
	FALL	SIX2SB		;Do it
	SUBTTL SIX2SB - Store SIXBIT T1 in string block pointed to by T2

PLM
;+
;.HL Routine SIX2SB
MLP
;	SIX2SB takes a SIXBIT string in T1 and translates it to eight-bit
;ASCII, placing the result in the string block pointed to by T2.  SIX2SB
;uses P1-P2 as well.
PLM
;-
MLP

SIX2SB:	SAVE2			;Save P1,P2
	MOVE P1,T2		;Preserve the string block pointer
	MOVE P2,[POINT 8,1(P1)]	;Set up byte pointer to data part of block
	SETZ T2,		;Use T2 for count
	MOVE T3,[POINT 6,T1]	;and T1 for a byte pointer into SIXBIT name
SIXS21:	ILDB T4,T3		;Get a byte from SIXBIT name
	JUMPE T4,SIXS22		;Nothing there, must be end of name
	ADDI T4," "		;ASCIIize the byte
	IDPB T4,P2		;Store it in the string block
	CAIE T2,6		;If we've hit six bytes, don't try anymore
	AOJA T2,SIXS21		;Otherwise, loop
SIXS22:	HRLM T2,(P1)		;Put the count in the first block
	ASH T2,-2		;Make count into words
	ADDI T2,2		;Some overhead
	HRRM T2,(P1)		;Put max length in
	POPJ	P,		;And return
	SUBTTL INIOBF - Initialize OBUF and IBUF

PLM
;+
;.hl Routines INIOBF and INOBUF
MLP
;	These routines are called to initialize IBFPTR/IBFCNT, and
;OBFCNT/OBFPTR.  INIOBF initializes both input and output buffers;
;INOBUF initializes only output buffers.  They use T1-T2.  The input buffer
;is fixed; the output buffers are allocated dynamically from the free core
;pool.
PLM
;-
MLP

INIOBF:
	SETZM IBFCNT		;Just being paranoid
	MOVE T1,[POINT 8,INPBUF-1,35]
	MOVEM T1,IBFPTR

INOBUF:	MOVEI	T1,OBUFSZ+OBF.DT ;Include the header
	PUSHJ	P,CORGET	;Get a buffer
	HRRZM	T1,OTPBUF	;Save it (Default to send EOM)
	MOVE	T2,[POINT 8,OBF.DT,]	;Make byte pointer to data portion
	ADD	T2,T1		;Put into proper perspective
	MOVEM	T2,OBFPTR	;Set pointer
	MOVEM	T2,OBF.PT(T1)	;Save for later output
	MOVEI	T1,4*OBUFSZ
	MOVEM	T1,OBFCTR	;For those who care...
	POPJ	P,		;Return to sender
	SUBTTL BPLENG - Compute length of byte pointer in T1

PLM
;+
;.hl Routine BPLENG
MLP
;	BPLENG is called to compute the number of bytes in the buffer.  It
;is called with the byte pointer to the beginning of the buffer in T1 and
;the byte pointer to the end of the buffer in T2.  Both pointers
;must specify eight-bit bytes and the beginning pointer must be word aligned.
;BPLENG returns with the number of bytes in T1.  T1 and T2 are used.
PLM
;-
MLP

BPLENG:	SAVE2			;Save P1,P2
	DMOVE P1,T1		;Preserve the byte pointers
	
	HLRZ T1,P1		;Get the s and p stuff
	CAIE T1,(POINT 8,)	;Is it word aligned and 8 bits?
	  ERR	IBP,<Illegal byte pointer>

	HRRZ T1,P2		;Get the address part of new BP
	HRRZ T2,P1		;and old BP
	SUB T1,T2		;Get the difference
	ASH T1,2		;Make it into bytes

	LDB T2,[POINT 6,P2,6+5]	;Get S field of byte pointer
	CAIE T2,^D8		;Is it eight bits?
	  ERR	IBS,<Illegal byte size>

	LDB T2,[POINT 6,P2,5]	;Get P field of byte pointer
	SUBI T2,4		;P starts at the right
	ASH T2,-3		;Divide by eight
	SUBI T2,4		;Reverse the order
	SUB T1,T2		;Figure out the final count
	POPJ	P,		;And return
	SUBTTL	Miscellaneous support - Digest a mask

PLM
;+
;.hl Routine CPYMSK
MLP
;	CPYMSK is called to take a mask from the current position of
;the network input buffer and copy it to the place specified by the
;byte pointer in T3. Enter with T4 containing the count for the
;mask; T4 must be non-zero.
;	This routine is provided for systems like RSX and VMS which
;provide a break mask for input termination where the bytes appear
;in the network buffer from low-order to high order and the correspondance
;of bits to ASCII character values (in each byte) proceeds with the
;high order bit representing the highest character value.  In TOPS-10
;format we translate the following into the B0-B32 format:
PLM
;.bl 1.lit
;  B7,B6,B5,B4,B3,B2,B1,B0   B15,B14,B13,B12,B11,B10,B9,B8  ...
;  \_____first  byte_____/   \________second byte________/   ...
PLM
;.end lit
PLM
;CPYMSK uses T1-T4.
PLM
;-
MLP

CPYMSK:	PUSHJ	P,RBYTEC	;Get a byte
	MUL	T1,[100200401002] ;Reverse the bits
	AND	T2,[20420420020];via HACKMEM
	ANDI	T1,41
	DIVI	T1,1777		;Casting out 2**10.-1's
	IDPB	T2,T3
	SOJG	T4,CPYMSK	;And continue copying the mask
	POPJ	P,			;Return
	SUBTTL Miscellaneous Support -- GET & PUT word routines

PLM
;+
;.hl Routines GETWRD, PUTWRD, GETLWD, and PUTLWD
MLP
;	These routines are for -11 flavoured machines which have
;bytes in reversed order.  The GETxxx routines input the appropriate
;quanity (2 bytes for WRD and 4 bytes for LWD) into T1 from the
;current position in the network input buffer; the PUTxxx routines
;output from P1 to the current position in the output buffer.
;These routines use CX and the appropriate argument AC.
;The PUTxxx routines do not destroy the argument.
PLM
;-
MLP

PUTWRD:	NETOCH	P1			;Network character
	ROT	P1,^D-8			;Shift down
	NETOCH	P1			;And second half
	ROT	P1,^D8			;Make it look right
	POPJ	P,			;And return

PUTLWD:	MOVEI	CX,^D3			;Number of times to do it
PUTL1:	NETOCH	P1
	ROT	P1,-^D8			;Do the next 8
	SOJG	CX,PUTL1		;Loop for all of them
	NETOCH	P1
	ROT	P1,-^D12		;In place again
	POPJ	P,			;And return

GETWRD:	PUSHJ	P,RBYTEC		;Get a byte from the system
	PUSH	P,T1			;Save it
	PUSHJ	P,RBYTEC		;And another
	LSH	T1,^D8			;Put the upper 8 bits first
	IOR	T1,(P)			;OR in the lower 8 bits
	POP	P,(P)			;Loose the number we stored
	POPJ	P,			;And return

GETLWD:	MOVSI	T1,20000		;Get an indicator in T1
GETLW1:	PUSH	P,T1			;Save T1
	PUSHJ	P,RBYTEC		;Get a data byte
	MOVE	T2,T1			;Save the number in T1+1
	POP	P,T1			;Restore the old stuff
	ROTC	T1,-^D8			;Put it in place
	JUMPGE	T2,GETLW1		;Loop for all of them
	ASH	T1,-^D4			;Use the lower 32 bits
	POPJ	P,			;And return
	SUBTTL	Miscellaneous Routines

PLM
;+
;.hl AC saving routines
MLP
;	These are the AC saving/restoring routines/co-routines.  Most of
;them are called by MACROS.  This is shown in the following table:
PLM
;.nofil.bl 1.ts 10,20,30,40,50
;^&
MLP
;	Routine		MACRO	Call	Function
PLM
;.bl 1
;\&
MLP
;	.SAVT1		SAVT1	JSP	Save/restore T1
;	SAVT		---	PUSHJ	Save/restore T1-T4
;	REST		---	JRST	Restore T1-T4
;	.SAV1		SAVE1	JSP	Save/restore P1
;	TPOPJ		---	JRST	Restore T1
;	P1POJ1		---	JRST	Restore P1/skip return
;	P1POPJ		---	JRST	Restore P1
;	.SAV2		SAVE2	JSP	Save/restore P1-P2
;	.SAV4		SAVE4	JSP	Save/restore P1-P4
;	.RES4		---	JRST	Restore P1-P4
PLM
;.fill.just.ts.bl 1
MLP
;In the above, JSP calls use AC CX.  Restoration routines restore ACs from
;the stack.
PLM
;-
MLP

.SAVT1:	PUSH P,T1
	PUSHJ P,0(CX)
	  TRNA
	AOS -1(P)
	POP P,T1
	POPJ P,

SAVT:	EXCH	T1,(P)
	PUSH	P,T2
	PUSH	P,T3
	PUSH	P,T4
	PUSH	P,[REST]
	PUSH	P,T1
	MOVE	T1,-5(P)
	POPJ	P,

REST:	TRNA
	AOS	-4(P)
	POP	P,T4
	POP	P,T3
TTPOPJ:	POP	P,T2
TPOPJ:	POP	P,T1
	POPJ	P,

.SAV1:	PUSH P,P1
	PUSHJ P,0(CX)
	  TRNA
P1POJ1:	AOS -1(P)
P1POPJ:	POP P,P1
	POPJ P,

.SAV2:	PUSH P,P1
	PUSH P,P2
	PUSHJ P,0(CX)
	  TRNA
	AOS -2(P)
	POP P,P2
	POP P,P1
	POPJ P,

.SAV4:	ADJSP	P,4
	DMOVEM	P1,-3(P)
	DMOVEM	P3,-1(P)
	PUSHJ	P,(CX)
	  TRNA
	AOS	-4(P)
.RES4:	DMOVE	P1,-3(P)
	DMOVE	P3,-1(P)
	ADJSP	P,-4
	POPJ	P,
	SUBTTL	Returns

PLM
;+
;.hl Routines TPOPJ1, CPOPJ1, and CPOPJ
MLP
;	These are return routines which are JRSTed to:  TPOPJ1 restores
;T1 from the stack and skips, CPOPJ1 skip returns, and CPOPJ just returns.
PLM
;-
MLP

TPOPJ1:	POP	P,T1
CPOPJ1:	AOS	(P)		;Skip
CPOPJ:	POPJ	P,		;Return to caller

	SUBTTL	EXCACS

PLM
;+
;.hl Routine EXCACS
MLP
;	EXCACS is called by the interrupt service routines to exchange
;AC sets.  Call is:
PLM
;.bl 1.nofill.ts 8,16,24,32,40,48,56

MLP
;	PUSHJ	P,EXCACS	;Call
;	EXP	ACset		;Block of 20 locations with which to
;				;exchange current ACs
PLM
;.fill.just.ts.bl 1
MLP
;AC F is not altered.
PLM
;-
MLP


	ASSUME	F,0
	ASSUME	P,17

EXCACS:	PUSH	P,@(P)			;Push addr of AC block on stack
	MOVEM	F,@(P)			;Save F
	MOVE	F,T1			;Save T1 in F
	POP	P,T1			;Address of AC block in T1
	EXCH	F,T1(T1)		;Switch the T1s
	PUSH	P,T2			;Save T2
	MOVE	T2,P(T1)		;Get the right PDL pointer
	EXCH	T2,P			;New pointer to P, old one to T2
	ADJSP	P,2			;Allocate space
	POP	T2,(P)			;T2 to new PDL
	POP	T2,-1(P)		;Return addr to new PDL
	MOVEM	T2,P(T1)		;What P to restore
	POP	P,T2			;Restore T2
	EXCH	T2,T2(T1)		;And now do the others
	EXCH	T3,T3(T1)
	EXCH	T4,T4(T1)
	EXCH	P1,P1(T1)
	EXCH	P2,P2(T1)
	EXCH	P3,P3(T1)
	EXCH	P4,P4(T1)
	EXCH	CX,CX(T1)
	EXCH	NSAFN,NSAFN(T1)
	EXCH	NSACH,NSACH(T1)
	EXCH	NSAA1,NSAA1(T1)
	EXCH	NSAA2,NSAA2(T1)
	EXCH	NSAA3,NSAA3(T1)
	MOVE	T1,F(T1)		;Restore flags to T1
	EXCH	T1,F			;Flags to F, T1 to T1
	AOS	(P)			;Skip the AC block designator
	POPJ	P,			;And return
	SUBTTL	Operating System Specific Support

PLM
;+
;.Chapter Operating System Specific Support
;.hl Overview
MLP
;	The rest of the code in NRT is concerned with supporting specific
;operating system's remote terminal servers.  This section contains an
;overview of the general requirements for supporting an operating system.
;	Each operating system requires an initialization routine,
;a network interrupt service routine, and a TTY: service interrupt routine.
;	The initialization routine is called when NRT knows what type
;of operating system the remote host is.  This information is passed in the
;configuration message from the remote host.  The initialization routine
;is responsible for setting flags as to which data mode the TTY: should
;be in (PIM or ASCII line) and calling TTYSST to set that up.  It is also
;responsible for sending the appropriate return configuration message
;and any other messages which should be sent to the remote host at
;initialization time (e.g. the unsolicited interrupt to VMS to simulate
;typing a <CR> on a terminal).
;	The network interrupt routine is responsible for handling any
;messages sent by the remote host over DECnet.  This can range
;from simply outputting the data to the TTY: (as is the case
;for TOPS-10 and TOPS-20) or processing the messages as various
;flavours of I/O requests (as is the case for VMS and RSX).
;The network interrupt service is called by DCNPSI, the operating system
;independent network interrupt service routine, when a complete message
;is available or the network input buffer is full.
;	The TTY: interrupt service has the responsiblity of handling
;characters typed by the user.  It is responsible for noticing the
;escape character was typed and calling MONITO.  Other than that, its
;responsibilities may be simply to ship the characters typed by the
;user out to the network (as is the case for TOPS-10 and TOPS-20), or
;they may include local processing and buffering of characters until
;the remote host requests them (VMS and RSX).  The TTY: interrupt service
;is called by the operating system independent TTY: service routine
;(TTYPSI) when new TTY: input is available.
;	Currently there are two basic types of protocols used.
;The first type is referred to henceforth as a TRANSPARENT protocol; the second
;as a MESSAGE protocol.  Some operating systems combine elements from
;each type of protocol.
;	A transparent protocol is one in which the DECnet messages
;passed between the local and remote hosts consist simply of the characters
;typed by the user and sent from the programs running on the remote host.
;Messages are passed when the connection is established to confirm that
;the correct protocol is being used, but from that point forward any message
;sent is considered to be data to be input by the remote host or displayed
;on the terminal by the local host.  All echoing and special character
;handling is handled by the remote host.  Generally, type-ahead is also
;handled by the remote host.  Transparent protocols are usually handled
;by doing terminal I/O in PIM mode and simply passing the characters
;directly through to the remote host.  Any characters sent from the
;remote host are sent immediately to the terminal.  Since all echoing
;is done by the remote host, the remote host is also responsible for
;handling echo deferring, etc.
;	A message protocol exists where the DECnet messages passed between
;the local and remote host consist of requests for characters or information
;(generally sent only from the remote to the local host) and acknowledgements
;fulfillments of the above mentioned requests (may be sent in either
;direction).  In general, in a message protocol, typed characters are
;not sent from the local to the remote host until they are requested by
;the remote host.  Echoing and special character handling are normally
;done by the local host in a message protocol.  Type-ahead
;is the responsiblity of the local host.  A message protocol
;is handled by not transferring the user's typed characters from NRT's
;internal buffers to the network until a request is received from the
;remote host for them.  The remote host provides a break mask (or utilizes
;an implied mask) and a maximum count with each request.  At this point,
;characters will be transferred to the remote host as dictated by the
;specific request.  If the characters arrive after the request, NRT will
;have allowed the monitor to echo them (assuming they are to be echoed).
;If the characters are typed before the request is received, NRT will
;not allow the monitor to echo them and will echo them when they are
;sent out over the network.

;	Rather than describe each routine in detail, the rest of the
;PLM will consist of a general description of each operating system type
;and pointers to appropriate reference manuals.  The general description
;will outline the type of protocol which is used to communicate with the
;remote host and any peculiarities of the particular operating system.
;This lack of detailed documentation is in part intentional.  The user
;should NOT try to repair any operating system specific routines unless
;he thoroughly understands both NRT's general approach (as described in
;in this manual) AND the appropriate internals (not just the external
;appearance) of the remote host.  To this effect, lists of appropriate
;documents will be provided, but it is the user's responsibility to
;read the suggested references.
;	In debugging NRT, it is very helpful to utilize the DNSNUP
;program provided on the DECnet Tools Tape.  This program is invaluable
;in providing a trace of what the remote operating system is actually
;sending you (as opposed to what the spec says).
;	I repeat for emphasis:
PLM
;.note ***WARNING*** ***WARNING***
MLP
;DO NOT TRY TO "FIX" ANY OPERATING SYSTEM SPECIFIC CODE UNLESS YOU THOROUGHLY
;UNDERSTAND THE REMOTE HOST OPERATING SYSTEM, UNDER PENALTY OF GETTING BOTH
;NRT AND YOUR FINGERS BROKEN.
PLM
;.end note
;-
MLP

	SUBTTL	RSTS Support -- Protocol definitions

PLM
;+
;.hl 2 RSTS Support
;	RSTS is implemented by a protocol which is a combination of
;transparent and message protocols.  Characters are passed from the local to
;the remote host as they are typed, but they are bound in a message.
;Echoing is done on the local host.
;	RSTS supports five types of messages:
;.list 1
;.le
;Configuration message (Type 1):  This is the normal configuration message.
;This is passed only when the link is being established.
;.le
;Control message (Type 2):  This is sent to request a change of various
;terminal states, such as to turn of echoing.
;.le
;Unsupported protocol message (Type 3):  This message is sent when one end
;requests a function which the other end does not support.
;It should never be sent during the normal course of
;events.
;.le
;Reserved for DEC (Type 4)
;.le
;Data message (Type 5):  This message passes characters to be displayed
;(from the remote to the local host) or characters typed by the user
;(from the local to the remote host).
;.end list
;	Reference documents:
;.list 1
;.le
;^&DECnet/E Virtual Terminal Protocol (VTP) Version 1.0\& -
;This memo, dated 20-Jan-79, describes the types of messages which
;comprise RSTS' protocol.  A difference between the memo and reality
;is that the data message is Type 5 rather than Type 4.
;It was also distributed on the TOPS-20 version 5 SWSKIT tape.
;.end list
;-
MLP

;Message types:

	MT$CFG==1			;Configuration message
	MT$CTL==2			;Control message
	MT$UNS==3			;Unsupported protocol message
	MT$DAT==5			;Data message

;Menu items (control message)

	MN$EKO==1			;Echo control
	MN$MSK==2			;Change delimiter mask
	MN$WID==4			;TTY: width

;Echo state:

	EK$OFF==1			;Off
	EK$ON==2			;On
	SUBTTL	RSTS Support -- RSTS network input

RST.NT:	PUSHJ	P,NETICH		;Anything from the other end?
	  POPJ	P,			;None?
	MOVEI	P1,RSSFNC		;Get the function code table
	PUSHJ	P,FNDFNC		;Find the function
	  ERR	IRS,<Illegal RSTS function>
	POPJ	P,			;Return
	SUBTTL	RSTS Support -- TTY: input

RST.TT:	PUSHJ	P,SCNSPC		;Scan for special characters
	  JRST	[PUSHJ	P,RST.SC	;Handle them
		 JRST	.-1	]	;Check again
	TXZN	F,F$BRK			;Is there a break?
	  JRST	SCRURB			;No, check rubout stuff
	MOVEI	T1,MT$DAT		;Data message
	NETOCH	T1			;Set it
	PUSH	P,OBFPTR		;Save pointer to counts
	NETALC	3			;Allocate 3 bytes in network buffer
	SETZ	P1,			;Init character counter
RST.T1:	PUSHJ	P,INCHR			;Go get what we can from the TTY
	 JRST	RST.T5			;Nothing
	CAMN	T1,ESCCHR		;Is this the escape character?
	  SOS	BRKNUM			;Yes, one less
RST.T3:	NETOCH	T1			;Output char to networkk
	PUSHJ	P,CHKBR1		;Break character?
	  AOJA	P1,RST.T4		;Yes
	AOJA	P1,RST.T1		;Count character
RST.T4:	TXNE	F,F$NEC			;Noecho?
	  JRST	RST.T5			;Yes, don't do it then
	HLRZ	T1,BRKCHR
	MOVE	T4,[-RSBLEN,,RSBTBL]
	PUSHJ	P,EKOBRK		;Echo the break character
RST.T5:	MOVE	T1,OBFPTR
	EXCH	T1,(P)
	MOVEM	T1,OBFPTR		;Point to counts
	MOVEI	T1,3			;Fudge counts
	ADDM	T1,OBFCTR
	MOVEI	T1,(P1)			;Data count
	MOVEI	P1,4(P1)		;Message size
	PUSHJ	P,PUTWRD
	NETOCH	T1			;Data size
	POP	P,OBFPTR		;Point to real end of message
	PUSHJ	P,XMTMSS		;Output the message
	MOVE	T2,RSTDMK		;Get count
	PJRST	SCRURB			;Clear as appropriate
	SUBTTL RSTS Support -- RST.IN - Initialization Routine

RST.IN:	MOVEI	T1,RST$CF		;Send config
	TXO	F,F$READ!F$ACO		;Always outstanding read
	TXZ	F,F$PIM
	PUSHJ	P,XMTMSG		;
	MOVEI	T1,RST$UN		;Send input
	PUSHJ	P,XMTMSG
	MOVE	T1,[RSTDMK,,IMASK]
	BLT	T1,ENDMSK
	MOVE	T1,[RSTDMK+1,,LMASK]
	BLT	T1,ELMASK
	PJRST	TTYSST			;Set up TTY
	SUBTTL RSTS Support -- RST.CT - RSTS control Message

RST.CT:	PUSHJ	P,GETWRD		;Get length of message
	PUSHJ	P,RBYTEC		;Get menu count
	XCT	[PUSHJ	P,RBYTEC	;Get menu bytes (one byte)
		 PUSHJ	P,GETWRD
		 PUSHJ	P,[PUSHJ	P,RBYTEC
			   PUSH		P,T1
			   PUSHJ	P,GETWRD
			   LSH		T1,^D8
			   IOR		T1,(P)
			   POP		P,(P)
			   POPJ		P,	]
		 PUSHJ	P,GETLWD
		 PUSHJ	P,[PUSHJ	P,GETLWD
			   PUSH		P,T1
			   PUSHJ	P,RBYTEC
			   JRST		TPOPJ	]
		 PUSHJ	P,[PUSHJ	P,GETLWD
			   PUSH		P,T1
			   PUSHJ	P,GETWRD
			   JRST		TPOPJ	]]-1(T1) ;Ignore high order for now
	MOVE	P1,T1			;Save it
	PUSHJ	P,RBYTEC		;Get echo specifier
	TRNN	P1,MN$EKO		;Change it?
	  JRST	RS.CT1			;No
	TRNE	T1,EK$OFF		;Turn echo off?
	  TXOA	F,F$NEC			;Yes
	TXZ	F,F$NEC
RS.CT1:	TRNN	P1,MN$MSK		;Set mask?
	  JRST	RS.CT3			;No, skip some
	MOVE	T3,[POINT 8,IMASK+1,]	;Destination pointer
	MOVEI	T4,^D32			;Number of bytes
	PUSHJ	P,CPYMSK		;Copy it
	MOVE	T1,[IMASK+1,,LMASK]	;Set logical mask too
	BLT	T1,ELMASK
RS.CT3:	PUSHJ	P,TTYSST		;Set up TTY:
	PJRST	FRCTTI			;Look at changes
	SUBTTL RSTS Support -- RST.DA - Recieve Data message

RST.DA:	IBP	IBFPTR			;Skip over the count
	IBP	IBFPTR			;Second byte
	IBP	IBFPTR			;And count of characters
	MOVNI	T1,^D3			;Adjust for what we just took
	ADDM	T1,IBFCNT
	PJRST	NETCHR			;Get some data

	SUBTTL	RSTS Support -- Handle special characters

RST.SC:	CAME	P1,ESCCHR		;Escape?
	  JRST	RS.CTU			;Check Control-U, etc.
	PUSHJ	P,MONITO		;Return to command level
	  TRNA				;Skip next
	AOSA	BRKNUM			;One more break to ignore
	PUSHJ	P,SPCRMV		;Remove if required
	PJRST	SCRURB			;Check rubout status

RS.CTU:	CAIE	P1,.CHCNU		;Control-U?
	  JRST	RS.CTR			;Control-R
	PUSHJ	P,DOCTU			;Do the control-U
	PJRST	UNRURB			;Clear the bits

RS.CTR:	CAIE	P1,.CHCNR		;Control-R?
	  PJRST	DORUB			;Must be rubout
	SETZ	T1,			;No routine
	PUSHJ	P,DOCTR			;Do the Control-R
	PJRST	SPCRMV			;Remove ^R and return
	SUBTTL	RSTS Support -- Check Set/Clear of Local ^U/^R/<RUB>

SCRURB:	SKIPN	ICHCNT			;Any chars in buffer?
	  JRST	SURURB			;No, clear
	MOVEI	T1,<1B<.CHCNR>!1B<.CHCNU>>
	AND	T1,LMASK		;Don't set special if he's to see
	XORI	T1,<1B<.CHCNR>!1B<.CHCNU>>
	IORM	T1,CHRTAB
	LDB	T1,[POINT 1,LMASK+3,31]	;Get the rubout bit
	LSH	T1,^D36-^D19		;Position it
	TRC	T1,1B19			;Complement it
	IORM	T1,CHRTAB+3		;Set appropriate
	PJRST	STRURB			;Set mask bits

SURURB:	MOVEI	T1,<1B<.CHCNR>!1B<.CHCNU>>
	ANDCAM	T1,CHRTAB		;Clear specialness
	MOVEI	T1,1B19
	ANDCAM	T1,CHRTAB+3		;...
	PJRST	UNRURB
	SUBTTL	RSTS Support -- Break Echo Table

RSBTBL:	.CHCRT,,[ASCIZ/
/]					;<CR>
	.CHCNZ,,[ASCIZ/^Z
/]					;^Z
	.CHESC,,[ASCIZ/$/]		;<ESC>
	.CHCNC,,[ASCIZ/^C
/]					;^C
	.CHCNO,,[ASCIZ/^O
/]					;^O
	RSBLEN==.-RSBTBL

	SUBTTL RSX Support -- Protocol defintions

PLM
;+
;.hl 2 RSX Support
;	RSX utilizes a message protocol.  There are twelve
;types of message requests
;which may be passed, including the configuration message.  In most cases,
;a request is generated in the remote host.  The local host responds when
;able to complete the request with a complementary message containing the
;same operation code.  There also a reference identifier which is sent
;in the original message; this must also be returned when the request
;is acknowledged.
;	There are two exceptions to the above protocol:
;.list 1
;.le
;Exception condition message (Message Type 12 (decimal) or 14 (octal)):
;This message is only sent from the local to the remote host and is sent
;when the user types certain special characters that could require
;immediate attention, for example, ^C.
;.le
;Write operation with No-Write-Complete modifier:  Like any other
;message, a Write message should be acknowledged when it is completed.
;It is possible, however, for the remote host to specify that the
;Write request is not to be acknowledged.  If this is the case, then
;the local host should perform the Write request but not acknowledge it.
;.end list
;	Reference documents:
;.list 1
;.le
;^&RSX I/O Users Guide\& - This gives a general idea of what an RSX program
;expects to see.
;.le
;^&RMT Protocol Specification for RMT/RMHACP version 1.08\& -
;This memo specifies the RSX remote terminal
;protocol.  It describes the types of messages passed and the
;appropriate responses.  Author:  S. Goldfarb; reviewed by
;S. Seufert, J. Schriesheim, and J. Forecast
;.end list
;	A further current peculiarity of RSX is its inability to handle having
;the link turned off.  This is actually done within the monitor, as TOPS-10
;does optimistic buffering and will occasionally have to request that a
;remote host send no more DECnet messages.  For RSX, if this happens, the link
;will shut off but will never turn on again when the monitor requests the
;remote host to begin sending messages again.  This is handled in NRT by
;turning off the optimistic buffering during initialization.  This
;feature is currently under FTCROCK.
;	RSX seems to have a further peculiarity in tossing characters
;during unsolicted input if only the break character is typed (and it's
;not a <CR>).  This is implemented for unsolicited input by first breaking
;on all characters, and then breaking under a complete request.
;-
MLP

	RF.NOP==0	;NO-OP
	RF.SSD==1	;Set system data (Configuration)
	RF.DIS==2	;Disconnect
	RF.WTD==3	;Write data to terminal
	RF.RDD==4	;Read data from terminal
	RF.WRD==5	;Write-then-read
	RF.UNS==6	;Unsolicited input
	RF.RSC==7	;Single Characters
	RF.KIL==10	;Kill I/O
	RF.ATT==11	;Attach task to terminal (as RSX means it)
	RF.GTC==12	;Get terminal Characteristics
	RF.STC==13	;Set terminal Characteristics
	RF.ECR==14	;Exception condition request

 ;MODE definitions
	RM.WBN==1	;Image write (RF.(WTD,WRD))
	RM.OSA==1	;Only system attention characters (RF.RSC)
	RM.WBT==2	;Write breaks through read (RF.(WTD,WRD)
	RM.NSA==2	;No system attention characters (RF.RSC)
	RM.RBN==4	;Image read (RF.(RDD,WRD))
	RM.NOT==4	;Notify (RF.RSC)
	RM.RTC==10	;Terminate on all CTL (RF.(RDD,WRD))
	RM.RNE==20	;Read no echo (RF.(RDD,WRD,RSC))
	RM.RTO==40	;Reset timeout on each char (RF.RSC)
	RM.CUR==40	;Cursor info imbedded (RF.(WTD,WRD))
	RM.RTT==40	;Terminator mask supplied (RF.RDD)
	RM.RTM==100	;Timeout (RF.(RDD,WRD))
	RM.NWC==200	;No write complete (RF.WTD)
	RM.TUI==200	;Terminate unsolicited input (RF.UNS)
	RM.TSC==200	;Terminate single character input (RF.RSC)
	RM.DET==200	;Detach (RF.ATT)

 ;Flags
	RM.PRI==2	;Process immediately
	RM.CAO==4	;Cancel abort-output

;Status returns:
XS.SFC==0		;Successful
XS.FPE==1		;Function processing error
XS.UFC==2		;Unsupported function requested
XS.IPF==3		;Illegal protocol function
XS.IPD==4		;Illegal protocal data
XS.ICF==5		;Illegal characteristics function

;Exception condition code descriptions

RE.SAR==0		;System attention request (^C)
RE.HAO==1		;Host abort output (^O)

;Characteristic variables

	RC.TBL==1	;Buffer size
	RC.CCT==2	;Carriage control type
	RC.SCI==3	;Read single characters
	RC.ACL==4	;Autocrlf
	RC.WBT==5	;Write breaks through read
	RC.CAO==6	;Cancel I/O
	RC.LUC==7	;Case conversion
	RC.RNE==^D8	;Noecho
	RC.RTC==^D9	;Terminate on control characters
	RC.CRT==^D10	;CRT support
	RC.RIL==^D11	;^R
	RC.RWB==^D12	;Image
	RC.UNS==^D13	;Unsolicited input
	RC.SCX==^D14	;Read single extensions
	RC.RTT==^D15	;Break masks
	RC.NUC==^D16	;Case conversion
	RC.HFF==^D17	;Hardware for feeds
	RC.HHT==^D18	;Hardware tabs
	RC.NEC==^D19	;Echo
	RC.RSP==^D20	;Receive speed
	RC.TSP==^D21	;Transmit speed
	RC.TTP==^D22	;TTY: type
	RC.SCP==^D23	;CRT
	RC.BIN==^D24	;Passall
	RC.SPN==^D25	;Suspended output
	RC.HFL==^D26	;Horizontal fill characters
	RC.VFL==^D27	;Vertical fill characters
	RC.TPL==^D28	;Page size
	RC.ETA==^D29	;Typeahead
	RC.CTA==^D30	;Read/clear typeahead buffer
	RC.REB==^D31	;Eight bit characters
	RC.RTM==^D32	;Timeout
	RC.CUR==^D33	;Cursor
	RC.CCF==^D34		;Control-C flush
	RC.FDX==^D35		;Full duplex
	RC.IMG==^D36		;Ignore messages
	RC.RAT==^D37		;Read type-ahead
	RC.SMO==^D38		;Enable lowercase output
	RC.SMP==^D39		;Force lowercase input
		RC.MAX==^D39		;Maximum type
	RC.VER==^D127		;Version type

;Terminal types:

	RXV52==11		;VT52
	RXV100==15		;VT100
	RXV101==24		;VT101
	RXV102==25		;VT102
	RXV125==27		;VT125
	RXV132==31		;VT132
	RXV61==13		;VT61
	RXV55==12		;VT55

;RSX digested header block:

	PHASE	0

R.LINK:			;(RH) Link to next request
R.IDENT:		;(LH) Identifier for this request
	BLOCK	1
R.MOD:			;(LH) Modifiers for this request
R.FLAG:	BLOCK	1	;(RH) Flags for this request

R.TIME:	BLOCK	1	;Timeout time if applicable

R.PROMPT:
	BLOCK	1	;Byte count,,pointer to prompt block
R.COUNT:		;I/O request count (read request)
	BLOCK	1

R.MASK:	BLOCK	^D8	;Terminator mask

	REQSIZ==.
	DEPHASE
ISBTBL:	.CHCRT,,[BYTE(7)15]		;<CR> For IAS
	.CHCNZ,,[ASCIZ/^Z/]		;No extra <CR>s for IAS
RXBTBL:	.CHCRT,,[ASCIZ/
/]					;<CR> for unsolicited read
	.CHCNZ,,[ASCIZ/^Z
/]					;^Z for unsolicited read
	.CHESC,,[ASCIZ/$/]		;<ESC>
	.CHCNC,,[ASCIZ/^C
/]					;^C
	RXBLEN==.-RXBTBL
	ISBLEN==.-ISBTBL
	SUBTTL RSX Support -- RSX.IN - Initialization

RSX.IN:	TXO	F,<F$UAST!F$NLF>	;Flag no extra <LF>s
	TXZ	F,F$PIM			;And not PIM
IFN	FTCROCK,<			;Turn of optimistic buffering
	MOVEI	CX,NSAFN		;Since -11 will hang
	MOVE	NSAFN,[.NSFRQ,,.NSAA3+1]
	NSP.	CX,
	  JRST	RX.INC			;Oops
	MOVEI	CX,NSAFN
	HRLI	NSAFN,.NSFSQ		;Set quota
	SETZ	NSAA3,			;To zero
	NSP.	CX,
	  JFCL
RX.INC:>				;Done
	MOVEI	T1,RSX$CF		;Send back configuration msg
	PUSHJ	P,XMTMSG		;
	MOVEI	T1,RSX$UN		;Send a message
	MOVE	T2,OSTYPE		;Get OS
	CAIE	T2,OSIAS		;RSX? (Might be IAS)
	PUSHJ	P,XMTMSG		;IAS doesn't like this
	MOVE	T1,[RXDMSK,,IMASK]	;Set RSX default break mask
	BLT	T1,ENDMSK		;Set up
	MOVE	T1,[RXDMSK+1,,LMASK]	;Set the local mask too	
	BLT	T1,ELMASK
	MOVX	T1,<1B<.CHCNC>!1B<.CHCNO>!1B<.CHCNX>>
	MOVEM	T1,CHRTAB		;Set ^C, ^O as special
	IORM	T1,IMASK+1		;Be sure they're breaks for us
	MOVE	T1,[3,,T2]		;Set no lower case as that
	MOVEI	T2,.TOSET+.TOLCT	;Is the default
	MOVE	T3,TTYUDX
	SETO	T4,
	TRMOP.	T1,
	  JFCL
	PJRST	TTYSST			;Set up TTY

	SUBTTL	RSX Support -- Network interrupt

RX.NET:	PUSHJ	P,RBYTEC		;Get the function
	MOVEI	P1,RSXFNC		;Point to function table
	PUSHJ	P,FNDFNC		;Go do it
	  ERR	IXF,<Illegal RSX function>
	POPJ	P,			;Return
	SUBTTL	RSX Support -- TTY: input

RSX.TT:	SKIPE	P4,READQ		;Is there an outstanding read?
	  PJRST	RX.CRQ			;Finish up
	SKIPE	P4,XSCREQ		;Is there a single char request?
	  JRST	RX.TT1			;Yes
	HRROS	XUNREQ			;Flag from TTY: service
RX.RCN:	PUSHJ	P,SCNSPC		;Scan special characters
	  JRST	RX.TT0			;Then anything special
RX.NES:	MOVE	P4,XUNREQ		;Get the unsolicited request
	HRRZS	XUNREQ			;Make it the way it was
	TXNE	F,F$UAST		;Want unsolicited input?
	TRNN	P4,-1			;Is there an unsolicted request?
	  POPJ	P,			;Doesn't want it
	FALL	RX.TU1			;Fall into unsolicited support
;Here to see if unsolicited input is enabled

RX.TU1:	PUSHJ	P,CLRCTO
	MOVEM	F,RSXSVF		;So won't send extra message
	MOVE	T1,R.COUNT(P4)		;Get its count
	TXZN	F,F$BRK			;See a break?
	CAMG	T1,ICHCNT		;Or count satisfied?
	  JRST	RX.TU3			;Satisfied, one way or another
	TXNN	F,F$RU1			;First time through here?
	  PJRST	CHKCTH			;See about ^H stuff
	PUSHJ	P,SCNINI		;Else echo the char
	PUSHJ	P,SCNCHR		;...
	  PJRST	XCRURB			;Nothing
	MOVEI	T1,(P1)			;Put in useful AC
	CAIG	T1," "			;Not control or space?
	CAIN	T1,.CHCRT		;But <CR> is special
	  JRST	RX.TU2			;Output it
	PUSHJ	P,INCHR			;Eat character
	  JFCL				;?
	PJRST	XCRURB			;See about ^U/^R/<RUB>
RX.TU2:	TXZ	F,F$RU1			;No longer in first character
	PUSHJ	P,EKOTAH		;Echo all the type-ahead
	MOVE	T1,[LMASK,,IMASK+1]
	BLT	T1,ENDMSK		;Set reasonable mask now
	MOVX	T1,1B<.CHCNH>		;Be sure can see this
	IORM	T1,IMASK+1
	PUSHJ	P,FRCTTI		;Force wakeup
	PUSHJ	P,CHKLED		;Need to do editing?
	  POPJ	P,			;Yes, do it
	PJRST	XCRURB			;Set ^U, ^R, etc. in mask
					;Note this calls TTYSST
;Here if the read is really satisfied

RX.TU3:	SETOM	LICHCT			;A read satisfied
	MOVEI	T1,RF.UNS		;Unsolicited function
	PUSHJ	P,RSX.BH		;Build the header
	SETZ	P1,
	NETOCH	P1			;Reserved
	PUSH	P,OBFPTR		;Save pointer
	NETALC	2			;Allocate read count
	PUSHJ	P,PUTWRD		;And write count
	MOVN	P1,R.COUNT(P4)		;Get the count
	HRLZI	P1,(P1)
RX.TU4:	PUSHJ	P,INCHR			;Get character
	  JRST	RX.TU9			;Oops
	CAMN	T1,ESCCHR		;Escape?
	  SOS	BRKNUM			;One less break
RX.TU5:	NETOCH	T1
	PUSHJ	P,CHKBR1		;If still a break,
	  JRST	RX.TU7			;Then check it's echo
	TLNN	P4,400000		;From TTY: service?
	  PUSHJ	P,OUTTTY		;No, echo character
	AOBJN	P1,RX.TU4		;..
	SETZ	T1,			;Use <NUL> terminator if none
	TRNA				;Already have character
RX.TU7:	HLRZ	T1,BRKCHR
	TLNN	P4,400000		;From TTY: service?
	  PUSHJ	P,DOOUT1		;No, make sure characters get out
	MOVE	T4,[-RXBLEN,,RXBTBL]	;Break echo table
	MOVSI	T3,RM.RNE		;To see if noecho
	TDNN	T3,R.MOD(P4)		;Is it?
	TRNN	P1,-1			;Yes, any chars other than term?
	  JRST	RX.TU9			;No chars except term or noecho
	CAIE	T1,.CHCNZ		;^Z?
	CAIN	T1,.CHCRT		;<CR>?
	  TXOA	F,F$CLF			;Warn to cancel <LF>
	TXZ	F,F$CLF
	PUSHJ	P,EKOBRK		;Echo break character
RX.TU9:	MOVE	T1,OBFPTR
	EXCH	T1,(P)			;Point to count word
	MOVEM	T1,OBFPTR
	MOVEI	T1,2			;Putting in 2 chars
	ADDM	T1,OBFCTR
	PUSHJ	P,PUTWRD		;Put the count in
	POP	P,OBFPTR		;Restore the real pointer
	PUSHJ	P,XMTMSS		;Send message
	PUSHJ	P,XCRURB		;Clear ^R/^U/<RUB>
	JRST	RX.DUN			;Reset up unsolicited
;Here to handle special characters

RX.TT0:	PUSHJ	P,RX.SPC		;Handle it
	  JRST	RSX.TT			;If a return
	PUSHJ	P,CONSCN		;?Continue the scan
	  JRST	RX.TT0			;See about that one
	JRST	RX.NES			;?

;Here if there is a read single characters active

RX.TT1:	PUSHJ	P,SCNINI		;Init a scan (in case we need it)
RX.T1A:	PUSHJ	P,SCNCHR		;Get character
	  JRST	RX.TT2
	CAME	P1,ESCCHR		;Escape character?
	  JRST	RX.T1A			;No
	PUSHJ	P,MONITO		;Return
	  PUSHJ	P,SPCRMV		;Remove character
RX.TT2:	SKIPN	ICHCNT			;Anything really there?
	  POPJ	P,
	MOVE	P4,XSCREQ		;Restore request block
	TXZ	F,F$TEX			;Flag from TTY: service
;Here for timeouts on single characters
RX.SSS:	HLRZ	T4,R.MOD(P4)		;Get modifiers
	ANDI	T4,RM.NOT!RM.NSA!RM.OSA	;Save only relevant bits
	JUMPE	T4,RX.ACH		;If any character
	CAIN	T4,RM.NOT		;Only want notification?
	  JRST	RX.NOT			;Do that then
	CAIN	T4,RM.NSA		;Only want non-system?
	  JRST	RX.NSA			;Yes, see if that's what is in
	CAIN	T4,RM.NSA!RM.OSA	;Want any character?
	  JRST	RX.ACH			;Yes, send then
	CAIE	P1,.CHCNC		;^C?
	  JRST	RX.NOT			;Not system attention, just notify
	TXNE	F,F$TEX			;From TTY: service?
	  JRST	RX.SCH			;No
RX.ACH:	MOVSI	T1,RM.RTO		;Reset on each character...
	SKIPE	R.TIME(P4)		;Any timeout or,
	TDNE	T1,R.MOD(P4)		;?
	  JRST	RX.SCH			;Terminate request now
	POPJ	P,			;Didn't timeout yet
RX.SCH:	MOVEI	T1,RF.RSC		;Function
	NETOCH	T1
	HLRZ	T1,R.MOD(P4)		;Get the modifiers
	ANDCMI	T1,RM.NOT		;We aren't just notifying
	JUMPE	T1,RX.SCZ		;Doesn't care about character
	TRZ	T1,RM.OSA		;Assume it's a normal character
	TRO	T1,RM.NSA		;..
	CAIE	P1,.CHCNC		;Attention?
	  TRC	T1,RM.OSA!RM.NSA	;No, normal
RX.SCZ:	NETOCH	T1			;Put in modifiers
	SETZ	P1,
	ASSUME	XS.SFC,0
	PUSHJ	P,PUTWRD		;Completion status and flags
	HLRZ	T2,R.IDENT(P4)		;Get request ID
	NETOCH	T2
	ASSUME	XS.SFC,0		;From above
	NETOCH	P1			;Reserved byte
	PUSH	P,OBFPTR		;Save current pointer
	SETZB	P1,P2			;Count, last character
	PUSHJ	P,PUTLWD		;no writes
	HLRZ	P3,R.MOD(P4)		;Modifiers
	TRC	P3,RM.OSA!RM.NSA	;Easier to test zeroes
RX.TT3:	PUSHJ	P,INCHR			;Get character
	  JRST	RX.TT4			;None
	TRNN	P3,RM.OSA!RM.NSA	;Were both set?
	CAIN	T1,P2			;Or are both the same?
	  JRST	RX.T3A			;Both the same or both not set
	JUMPE	P2,RX.T3A		;Or if this is first character
	CAIE	T1,.CHCNC		;Is this a ^C?
	CAIN	P2,.CHCNC		;Or was that?
	  TRNA				;One was (blast!)
	JRST	RX.T3A			;Neither was, continue
	EXCH	T1,(P)			;Save character, get pointer
	MOVEI	T2,2
	ADDM	T2,OBFCTR		;Fudge count
	PUSH	P,OBFPTR		;Save old pointer
	MOVEM	T1,OBFPTR		;Fudged pointer
	PUSHJ	P,PUTWRD		;Current counter
	POP	P,OBFPTR		;Real pointer
	PUSHJ	P,XMTMSS		;Send the message
	MOVEI	T1,RF.RSC		;Function
	NETOCH	T1			;Rebuild header
	POP	P,T1			;Restore saved character
	MOVEI	T2,RM.NSA		;Assume normal
	CAIN	T1,.CHCNC		;Is it?
	  TRC	T1,RM.OSA!RM.NSA	;No
	NETOCH	T2			;Output modifiers
	SETZ	P1,
	ASSUME	XS.SFC,0
	PUSHJ	P,PUTWRD		;Completion status and flags
	HLRZ	T2,R.IDENT(P4)		;Get request ID
	NETOCH	T2
	ASSUME	XS.SFC,0		;From above
	NETOCH	P1			;Reserved byte
	PUSH	P,OBFPTR		;Save current pointer
	SETZB	P1,P2			;Count, last character
	PUSHJ	P,PUTLWD		;no writes
RX.T3A:	MOVE	P2,T1			;Remember character
	NETOCH	T1
	AOJA	P1,RX.TT3
RX.TT4:	MOVEI	T1,2
	ADDM	T1,OBFCTR		;Fudge count
	MOVE	T1,OBFPTR
	EXCH	T1,(P)			;Point to read count
	MOVEM	T1,OBFPTR
	PUSHJ	P,PUTWRD
	POP	P,OBFPTR
	SKIPE	R.TIME(P4)		;Is there a timeout?
	  PUSHJ	P,RX.STM		;Yes, reset it
	PJRST	XMTMSS			;Send the message

;Here if only want non-system characters

RX.NSA:	CAIN	P1,.CHCNC		;Is it ^C?
	  JRST	RX.TT0			;Yes
	PJRST	RX.ACH			;Send the char


;Here if only notifying

RX.NOT:	MOVEI	T1,RF.RSC		;Function
	NETOCH	T1
	HLRZ	T1,R.MOD(P4)
	NETOCH	T1
	SETZ	P1,			;Flags and reserved
	ASSUME	XS.SFC,0
	PUSHJ	P,PUTWRD
	PUSHJ	P,PUTLWD		;Counts
	PJRST	XMTMSS
	SUBTTL	RSX Support -- NOP function

;Also here is the RX.CCO routine to clear F$CTO in both F and the RSXSVF
;copy of F.

RX.NOP:	PUSHJ	P,RBYTEC		;Get modifiers (0)
	PUSHJ	P,RBYTEC		;Get flags
	TRNN	T1,RM.CAO		;Cancel abort I/O?
	  POPJ	P,
RX.CCO:	PUSHJ	P,CLRCTO		;Do the cancel
	MOVEM	F,RSXSVF		;Save F
	POPJ	P,
	SUBTTL	RSX Support -- Set unsolicited characters

RX.SUN:	PUSHJ	P,RSX.EH		;Eat header
	PUSHJ	P,GETWRD		;Count
	MOVEM	T1,R.COUNT(P4)		;Set it
	MOVSI	T1,RM.TUI		;Terminate?
	TDNE	T1,R.MOD(P4)		;?
	  JRST	RX.TUN			;Yes
	MOVEM	P4,XUNREQ		;Point to it
	SKIPE	READQ			;Read pending?
	  POPJ	P,			;Yes
RX.DUN:	TXNE	F,F$UAST		;Set read status unless attached
	TXO	F,F$READ!F$RU1		;Read outstanding, just got re-enabled
	MOVE	T1,R.COUNT(P4)		;Get the count
	MOVEM	T1,IMASK		;Set it
	MOVE	T2,[RXDMSK+1,,LMASK]
	BLT	T2,ELMASK		;Set both masks
	SETOM	IMASK+1			;Break on all chars at first
	MOVE	T2,[IMASK+1,,IMASK+2]
	SOSG	T1			;If more than one character to what we planned
	  HRLI	T2,RXDMSK+1		;Else it is default too
	BLT	T2,ENDMSK
	JUMPLE	T1,RX.DU4
	MOVX	T2,<1B<.CHCNC>!1B<.CHCNO>!1B<.CHCNR>!1B<.CHCNU>!1B<.CHCNS>!1B<.CHCNQ>!1B<.CHCNX>>
	ANDCAM	T2,IMASK+1		;But don't break on these
	MOVEI	T2,1B31			;Same for <RUB>
	ANDCAM	T2,IMASK+1+3
RX.DU4:	TXZ	F,F$NEC			;Must echo
	MOVX	T1,<1B<.CHCNC>!1B<.CHCNO>!1B<.CHCNX>>
	IORM	T1,CHRTAB
	IORM	T1,IMASK+1		;Be sure we see them
	PUSHJ	P,FRCTTI		;Force TTY: check
	PUSHJ	P,TTYSST		;Set up TTY:
	PJRST	RX.RCN			;In case some type-ahead

RX.TUN:	SKIPN	READQ			;Not a read unless there really is one
	  TXZ	F,F$READ
	MOVEI	T1,(P4)
	MOVEI	T2,REQSIZ
	PUSHJ	P,CORFRE
	MOVE	T1,XUNREQ
	SETZM	XUNREQ
	PJRST	CORFRE
	SUBTTL	RSX Support -- Kill I/O

RX.KIL:	NETOCH	T1			;ACK the function
	SETZ	P1,
	PUSHJ	P,PUTWRD		;No flags or modifiers
	ASSUME	XS.SFC,0
	NETOCH	P1			;Status is success
	PUSHJ	P,RBYTEC		;Get modifiers (0)
	PUSHJ	P,RBYTEC		;Get flags
	TRNE	T1,RM.CAO		;Cancel ^O?
	  PUSHJ	P,RX.CCO
	PUSHJ	P,RBYTEC		;Status
	PUSHJ	P,RBYTEC		;Request ID
	NETOCH	T1			;Put it in
	MOVEI	P2,(T1)			;Save it
	HRRZ	P4,READQ		;Get current request
	JUMPE	P4,XMTMSS		;ACK and return
	MOVEI	P3,READQ-R.LINK		;Predecessor
RX.KI1:	HLRZ	T1,R.IDENT(P4)		;Get the identifier
	CAIE	T1,(P2)			;Right one?
	  JRST	[HRRZI	P3,(P4)		;This is last block
		 JRST	RX.KI3	     ]	;Continue
	HRL	P3,R.LINK(P4)		;Successor
	HLRM	P3,R.LINK(P3)		;Link to predecessor
RX.KIA:	SKIPN	T1,R.PROMPT(P4)		;Prompt?
	  JRST	RX.KI2			;No
	HLRZ	T2,T1			;Size
	LSHC	T2,-2
	TLNE	T3,600000
	  AOJ	T2,
	HRRZI	T1,(T1)
	PUSHJ	P,CORFRE
RX.KI2:	HRRZI	T1,(P4)			;Point T1 at core block
	MOVEI	T2,REQSIZ
	PUSHJ	P,CORFRE
RX.KI3:	HRRZ	P4,R.LINK(P3)		;Point to next
	JUMPN	P4,RX.KI1		;More
	SKIPN	P4,XSCREQ		;Single?
	  JRST	RX.KI4			;No
	HLRZ	T1,R.IDENT(P4)		;Get identifier
	CAIE	T1,(P2)			;The required ID?
	  JRST	RX.KI4			;No
	MOVEI	P3,XSCREQ-R.LINK	;Fake predecessor
	SETZM	XSCREQ			;No request any more
	SKIPN	P4,READQ		;Read request?
	  TXZA	F,F$NEC!F$PALL		;No, clear noecho and passall
	TXZ	F,F$PALL		;Yes, just clear passall
	JRST	RX.KIA			;Deallocate

RX.KI4:	SKIPN	P4,XUNREQ		;Unsolicited request?
	  JRST	RX.KI5
	HLRZ	T1,R.IDENT(P4)
	CAIE	T1,(P2)			;Right thing?
	  JRST	RX.KI5			;No
	SETZM	XUNREQ
	HRRI	P3,XUNREQ-R.LINK	;Fake predecessor
	JRST	RX.KIA			;Kill

RX.KI5:	SKIPN	READQ
	SKIPE	XUNREQ
	  PJRST	XMTMSS
	SKIPN	XSCREQ
	  TXZ	F,F$READ
	PJRST	XMTMSS
	SUBTTL	RSX Support -- Disconnect link

RX.DIS:	POPJ	P,			;We'll find out soon enough
	SUBTTL	RSX Support -- Single character mode

RX.SSC:	PUSHJ	P,RSX.EH		;Digest it
	MOVSI	T1,RM.TSC		;If terminate,
	TDNE	T1,R.MOD(P4)		;Then exit now
	  JRST	RX.TSC			;And perform it
	PUSHJ	P,GETLWD		;Eat counts
	PUSHJ	P,RBYTEC		;Timeout
	JUMPE	T1,RX.SC1
	IMULI	T1,^D4000		;Convert to MS
	IDIVI	T1,^D60
	CAIL	T2,^D30
	AOJ	T1,
	TLO	T1,(1B0)		;Flag in MS
	MOVEM	T1,R.TIME(P4)		;Save
RX.SC1:	MOVEM	P4,XSCREQ		;Save it
	SKIPE	READQ			;Is there a read outstanding?
	  POPJ	P,			;Then its charactersitics apply
;Enter here with P4 pointing to block
RX.SCS:	HLRZ	T1,R.MOD(P4)
	TRNE	T1,RM.RNE		;NO echo?
	  TXOA	F,F$NEC			;Yes
	TXZ	F,F$NEC			;No
	SKIPE	R.TIME(P4)		;Timeout?
	  PUSHJ	P,RX.STM		;Yes
	MOVEI	T1,1			;Break on each character
	MOVEM	T1,IMASK
	SETOM	IMASK+1
	MOVE	T1,[IMASK+1,,IMASK+2]
	ASSUME	LMASK,<<ENDMSK+1>>
	BLT	T1,ELMASK		;..
	TXO	F,F$PALL		;Set no special characters
	PUSHJ	P,TTYSST		;Set TTY: up
	PUSHJ	P,FRCTTI		;Force TTY: look
	PJRST	RX.TT1			;See if any typeahead

RX.TSC:	SKIPN	READQ			;If no read
	  TXZ	F,F$TMR			;Cancel timeout
	MOVEI	T1,(P4)
	MOVEI	T2,REQSIZ
	PUSHJ	P,CORFRE
	MOVE	T1,XSCREQ
	SETZM	XSCREQ
	PUSHJ	P,CORFRE
	SKIPN	P4,READQ		;Read request?
	  TXZA	F,F$NEC!F$PALL		;No, clear noecho and passall
	TXZA	F,F$PALL		;Yes, just clear passall
	  JRST	RX.CUN			;Check unsolicited
	PUSHJ	P,FRCTTI		;Force TTY: look
	PJRST	RX.PM5			;In case satisfied from typeahead
	SUBTTL	RSX Support -- ATTACH/DETACH

RX.DAT:	PUSHJ	P,RBYTEC		;Get modifiers
	TRNE	T1,RM.DET		;Detach?
	  JRST	RX.DET			;Yes
	TXZ	F,F$UAST		;Don't really want unsolicited
	SKIPN	READQ			;When ATTACHed, if not a read
	  TXZ	F,F$READ		;Then there really isn't one
	PUSHJ	P,TTYSST		;Change mask
	PJRST	FRCTTI			;Check for input

RX.DET:	TXO	F,F$UAST		;Want unsolicited if enabled
	SKIPN	P4,XUNREQ		;Request?
	  POPJ	P,			;No
	PJRST	RX.DUN			;Reset unsolicited
	SUBTTL	RSX Support -- Get terminal characteristics

RX.GTC:	MOVEI	T1,RF.GTC		;ACK the function
	NETOCH	T1
	SETZ	P1,			;Modifiers & flags
	PUSHJ	P,PUTWRD
	PUSHJ	P,GETWRD		;Get modifiers, flags
	TRNE	T1,<RM.CAO>B<35-8>
	  PUSHJ	P,RX.CCO
	PUSHJ	P,RBYTEC		;Status
	ASSUME	XS.SFC,0
	NETOCH	T1			;Assume it stays the same
	PUSHJ	P,GETWRD		;Identifier, reserved
	MOVE	P1,T1
	PUSHJ	P,PUTWRD		;Return it
	PUSHJ	P,GETLWD		;Eat counts
	SETZ	P1,
	PUSHJ	P,PUTLWD		;Put zero for them
RXCHLP:	PUSHJ	P,NETICH		;Get characteristic
	  JRST	RXCHGX			;Done
	JUMPE	T1,RXCHGX		;Or this way
	NETOCH	T1			;Type
	CAIE	T1,RC.CTA		;Type-ahead?
	  JRST	RXCH1			;No
	PUSHJ	P,SETICH		;Set ICHCNT
	MOVE	T1,[2,,T2]
	MOVE	T2,TTYUDX
	MOVEI	T3,.TOTTC		;Figure it out
	TRMOP.	T1,
	  SETZ	T1,
	ADD	T1,ICHCNT		;..
	  TRNA				;Skip normal loading
RXCH1:	MOVE	T1,RXCHTB-1(T1)		;Get the answer
	NETOCH	T1			;Put in
	PUSHJ	P,RBYTEC		;Eat the "field"
	JRST	RXCHLP			;Proceed

RXCHGX:	SETZ	T1,
	PUSHJ	P,PUTWRD
	PJRST	XMTMSS			;Finish off and end
	SUBTTL	RSX Support -- Set terminal characteristics

RX.STC:	NETOCH	T1			;Output the function
	PUSHJ	P,GETWRD		;Get modifiers and flags
	TRNE	T1,<RM.CAO>B<^D35-8>	;?
	  PUSHJ	P,RX.CCO
	SETZ	P1,
	PUSHJ	P,PUTWRD		;Modifiers and flags
	ASSUME	XS.SFC,0
	NETOCH	P1			;Status
	PUSHJ	P,RBYTEC		;Input status
	PUSHJ	P,GETWRD		;ID, reserved
	MOVE	P1,T1			;Transfer
	PUSHJ	P,PUTWRD		;And do it
	PUSHJ	P,GETLWD		;Get counts
	MOVE	P1,T1
	PUSHJ	P,PUTLWD
RXSCLP:	PUSHJ	P,NETICH		;Get a characteristic
	  SETZ	T1,
	JUMPE	T1,[PUSHJ	P,TTYSST
		    PJRST	XMTMSS	]
	MOVEI	P1,(T1)			;Save it
	PUSHJ	P,RBYTEC		;Get set field
	MOVEM	T1,RXCHTB-1(P1)		;Save it
	CAIN	P1,RC.BIN		;Binary?
	  XCT	[TXZ	F,F$PALL	;Yes, set it
		 TXO	F,F$PALL](T1)	;appropriately
	CAIN	P1,RC.NEC
	  XCT	[TXZ	F,F$NEC
		 TXO	F,F$NEC](T1)
	CAIN	P1,RC.CTA		;Type-ahead function?
	  PUSHJ	P,FLSTAH		;Clear all type-ahead
	SKIPN	T2,RXTRMP(P1)		;Should we do a TRMOP. here?
	  JRST	RXSCLP			;Continue
	TLZE	T2,400000		;Sign bit set?
	  TRC	T1,1			;Yes, complement setting
	MOVE	T4,T1			;Copy
	CAIE	P1,RC.TTP		;Set TTY: type?
	  JRST	RXSTRM			;No, set other characteristics then
	MOVSI	T2,-TTPLEN		;Terminal table
	HRRZ	T3,RTPTB(T2)		;Get RSX terminal type
	CAIE	T3,(T4)			;Match ours?
	AOBJN	T2,.-2			;Keep looking if not
	JUMPGE	T2,RXSCLP		;Oh well, don't know it
	MOVE	T4,TTPTB(T2)		;Get TOPS-10 name
RXSTRM:	MOVE	T3,TTYUDX
	MOVE	T1,[3,,T2]
	TRMOP.	T1,
	  JFCL
	JRST	RXSCLP

	SUBTTL	RSX Support -- Read data, Read with prompt

RX.PRD:	SKIPA	P1,[-1]			;This is a prompt request
RX.RED:	SETZ	P1,
	PUSHJ	P,RX.CCO		;Cancel ^O
	TXO	F,F$READ		;Read outstanding
	PUSHJ	P,RSX.EH		;Eat the header
	MOVEM	P1,R.PROMPT(P4)		;Save prompt status
	PUSHJ	P,GETWRD		;Get read count
	MOVEM	T1,R.COUNT(P4)		;Save
	MOVSI	T2,RM.RTM		;Timeout?
	TDNN	T2,R.MOD(P4)		;??
	  JRST	RX.NT1			;No
	ANDI	T1,377			;Clear count
	ANDCAM	T1,R.COUNT(P4)		;Clear timout value in count
	LSH	T1,-^D8			;Two instrs to save precision
	IMULI	T1,^D10			;Convert to seconds
	MOVEM	T1,R.TIME(P4)		;Save timeout
RX.NT1:	SETZ	T1,			;Default nothing
	MOVSI	T2,RM.RTT		;The terminator mask bit
	SKIPN	R.PROMPT(P4)		;Wanted prompt?
	TDNE	T2,R.MOD(P4)		;See if terminator bit set
	PUSHJ	P,GETWRD		;Get write/terminator count
	SKIPN	R.PROMPT(P4)		;Want prompt?
	SKIPN	T4,T1			;Copy count to T4
	  JRST	RX.NMK			;There really isn't a mask
	MOVE	T3,[POINT 8,R.MASK(P4),];Point to mask area
	PUSHJ	P,CPYMSK		;Copy in the mask
	SETZ	T1,			;Can't combine mask and prompt
RX.NMK:	MOVSI	T2,RM.RTC		;See if terminate on characters
	TDNN	T2,R.MOD(P4)		;?
	  JRST	RX.NCC			;No
	MOVE	T2,[777777,,777760]	;Set it
	MOVEM	T2,R.MASK(P4)		;Control chars
	MOVEI	T2,7B31			;Also include <ALT>s and <RUB>
	MOVEM	T2,R.MASK+3(P4)		;Set them all
RX.NCC:	JUMPE	T1,RX.NPT		;No prompt
	PUSH	P,T1			;Save size of string
	LSHC	T1,-2
	TLNE	T2,600000		;Check remainder
	  AOS	T1
	PUSHJ	P,CORGET		;Get block for prompt
	HRRM	T1,R.PROMPT(P4)		;Save it
	POP	P,T4			;Get byte count
	HRLM	T4,R.PROMPT(P4)		;Save it
	MOVEI	T2,(T1)			;Point to block
	HRLI	T2,(POINT 8,,)		;Make a byte pointer
RX.PM1:	PUSHJ	P,RBYTEC		;Get byte of string
	IDPB	T1,T2
	SOJG	T4,RX.PM1
RX.NPT:	TXZ	F,F$PALL		;Not while read active
	MOVEI	T1,RM.PRI		;Process immediately?
	MOVE	T4,READQ
	TDNN	T1,R.FLAG(P4)		;Is this process immediately?
	  JUMPN	T4,XQREAD		;No, queue request here
	MOVEM	P4,READQ		;This is now current request
	HRRM	T4,R.LINK(P4)		;In case this is a PRI
RX.NRQ:	TXO	F,F$IOQ			;Inhibit output
	PUSHJ	P,XPROMT		;Output the prompt
RX.CTM:	SKIPE	T1,R.TIME(P4)		;Is there a timeout?
	  TXO	F,F$TMR			;Set there is a timeout
RX.PM5:	PUSHJ	P,RX.STT		;Set TTY: up for this request
	PUSHJ	P,CHKLED		;See if need to do editing
	  PJRST	FRCTTI			;Yes, do it
	PUSHJ	P,EKOTAH		;Echo type-ahead
	TLZA	P4,400000		;Flag not from TTY: service
	FALL	RX.CRQ			;Fall in CRQ
;Here from TTY: service to see if request can now be completed

RX.CRQ:	PUSHJ	P,CLRCTO		;Clear ^O
	MOVEM	F,RSXSVF		;Saved copy
	TLO	P4,400000		;Flag from TTY: service
	TXNE	F,F$TMR			;Timeout?
	SKIPN	R.TIME(P4)		;Really? (not RSC)
	  TRNA				;Nope
	PUSHJ	P,RX.STM		;Set it up
	MOVEM	P4,READQ		;Save the request
	PUSHJ	P,SCNSPC		;Any special characters in input?
	  JRST	RX.CSC			;Check special characters
RX.NSC:	MOVE	P4,READQ		;Get the request back
	HRRZ	T1,R.COUNT(P4)		;Get count desired
	CAMLE	T1,ICHCNT		;Do we have at least that many?
	TLZE	F,(F$BRK)		;Or have we seen a break?
	  JRST	RX.RDS			;Read is satisfied
	PUSHJ	P,XCRURB		;See about rubout etc.
	PJRST	CHKCTH			;Check ^H
;Also enter here with P4 pointing to header block from TIMEOUT service
RX.RDS:	SETOM	LICHCT			;Flag to do ^H next time
	SETZM	XSPCNT			;Going to eat all ^Cs
	MOVEI	T1,($TOOIN!$TOICL)	;Overrid inhibit for echo
	IORM	T1,TOFLGS
	MOVEI	T1,RF.RDD		;Build header for read
	PUSHJ	P,RSX.BH		;Build header to complete request
	SETZ	P1,			;Reserved byte
	NETOCH	P1
	PUSH	P,OBFPTR		;Save output pointer
	NETALC	2			;Two for the read
	PUSHJ	P,PUTWRD		;Two for the write
	MOVN	P2,R.COUNT(P4)		;Get desired count
	HRLZI	P2,(P2)			;Make AOBJN pointer
	JUMPE	P2,RX.RDZ		;**Zero length read**
	HLRZ	P3,R.MOD(P4)		;Get modifiers
RX.RDL:	PUSHJ	P,INCHR			;Get a character
	  JRST	[HRRZI	P2,(P2)		;Flag no break character
		 MOVSI	T1,(<RM.RTM>B15);Set a timeout
		 IORM	T1,@OTPBUF	;...
		 JRST	RX.RDD	  ]	;Read is done
	CAMN	T1,ESCCHR		;Escape character?
	  SOS	BRKNUM			;One less break
	NETOCH	T1
	PUSHJ	P,CHKBR1		;Is it a break?
	  JRST	RX.RDD			;yes, read is done
	TLNN	P4,400000		;From TTY: service?
	TRNE	P3,RM.RNE		;No, noecho?
	  JRST	RX.RDF			;From TTY: or noecho
	PUSHJ	P,OUTTTY		;Output character
RX.RDF:	AOBJN	P2,RX.RDL		;Continue
RX.RDZ:	SETZ	T1,			;Make terminator a <NUL>
	NETOCH	T1
	JRST	RX.RNB			;No break
RX.RDD:	HLRZ	T1,BRKCHR
	CAIN	T1,.CHCNC		;Control-C?
	SKIPN	T2,XSCREQ		;Any single request?
	  JRST	RX.RDE			;No
	HLRZ	T2,R.MOD(T2)		;Get modifiers
	TRNE	T2,RM.OSA		;?
	  JRST	RX.RNB			;Already echoed it
RX.RDE:	MOVSI	T2,RM.RTC		;Terminate on control?
	TDNE	T2,R.MOD(P4)		;?
	CAIL	T1," "			;Is this a control character?
	  SKIPN	R.COUNT(P4)		;Make sure non-zero length request
	JRST	RX.RNB
	CAIE	T1,.CHCNZ		;^Z?
	CAIN	T1,.CHCRT		;<CR>?
	  TXNE	F,F$NEC			;Yes, noecho?
	TXZA	F,F$CLF			;Don't
	  TXO	F,F$CLF			;Set CLF if all of the above are true
	MOVE	T4,OSTYPE		;Get OS
	CAIN	T4,OSIAS		;11M or IAS?
	  SKIPA	T4,[-ISBLEN,,ISBTBL]	;Use IAS table
	SKIPA	T4,[-RXBLEN,,RXBTBL]
	  TXZ	F,F$CLF			;Skip this stuff if IAS
	PUSHJ	P,EKOBRK		;Echo if not
RX.RNB:	MOVE	T1,OBFPTR		;Save real output pointer
	EXCH	T1,(P)			;Get count pointer
	MOVEM	T1,OBFPTR		;Point to status word
	MOVEI	T1,2			;Was subtracted before
	ADDM	T1,OBFCTR		;..
	MOVEI	P1,(P2)			;Character count
	PUSHJ	P,PUTWRD		;Put it in
	POP	P,OBFPTR		;Restore real pointer now
RX.RDQ:	PUSHJ	P,XMTMSS		;Send the message now
	TLZN	P4,400000		;From TTY:?
	TRNE	P3,RM.RNE		;No-echo?
	  JRST	RX.RQ1
	PUSHJ	P,DOOUT1		;Force out
	SETZM	TOFLGS
RX.RQ1:	HRRZ	T1,R.LINK(P4)		;Point to next request
	HRRZM	T1,READQ		;which is now current
	SKIPN	T1,R.PROMPT(P4)		;Prompt block to free?
	  JRST	RX.NPF			;No
	HLRE	T2,T1			;Put length in T2
	LSHC	T2,-2			;To words
	TLNE	T3,600000		;Check remainder
	AOJ	T2,
	HRRZI	T1,(T1)
	PUSHJ	P,CORFRE
RX.NPF:	MOVEI	T1,(P4)			;Free this block
	MOVEI	T2,REQSIZ
	PUSHJ	P,CORFRE		;..
	PUSHJ	P,XCRUR1		;...
	TXZ	F,F$IOQ			;Don't inhibit any more
	SKIPE	P4,READQ		;New request
	  JRST	RX.NRQ			;New request
	SKIPN	P4,XSCREQ		;Read single in effect?
	  TXZA	F,F$READ		;No, no read
	TXOA	F,F$READ		;Be sure it's set
	  JRST	RX.CUN			;See if unsolicited
	TXZ	F,F$TMR			;Clear timeout
	PJRST	RX.SCS			;Set it up

;Here to check if an unsolicited request

RX.CUN:	SKIPE	P4,XUNREQ		;Is there one?
	  PJRST	RX.DUN			;Do setup
	PUSHJ	P,TTYSST		;Set up TTY:
	PJRST	FRCTTI			;Look

;Here if a special character was found by SCNSPC, ponder what to do

RX.CSC:	SKIPN	T1,XSCREQ	;Read single in effect?
	  JRST	RX.DSC		;No
	HLRZ	T2,R.MOD(T1)	;Get modifiers
	CAIE	P1,.CHCNC	;Is this the interesting character?
	  JRST	RX.DSC		;No
	TRNN	T2,RM.OSA	;Want attention characters?
	  JRST	RX.CS2		;No
	SKIPN	T2,XSPCNT	;Count of ^C's in buffer
	  JRST	RX.CS5		;This is the first
	PUSH	P,T2		;Save in an interesting place
RX.CS1:	PUSHJ	P,CONSCN	;Continue the scan
	  JRST	RX.CS3		;Found one
	POP	P,(P)		;Clear junk
RX.CS2:	MOVEI	P1,.CHCNC	;Is the magic character also a break?
	PUSHJ	P,CHKBRK	;?
	  TXO	F,F$BRK		;Yes, flag it
	JRST	RX.NSC		;Didn't really see a special character
RX.CS3:	CAIE	P1,.CHCNC	;The magic character?
	  JRST	[POP	P,(P)	;No
		 JRST	RX.DSC]	;Process it
	SOSLE	(P)		;Yes, notify for it already?
	  JRST	RX.CS1		;Continue scanning
	POP	P,(P)
RX.CS5:	AOS	XSPCNT		;We scanned this one
	MOVE	P4,XSCREQ	;The unsolicited request
	MOVEI	T1,RF.RSC	;Function
	NETOCH	T1
	HLRZ	T1,R.MOD(P4)	;Get modifiers
	ANDI	T1,RM.OSA	;Saving only this
	NETOCH	T1		;Put in modifiers
	SETZ	P1,
	ASSUME	XS.SFC,0
	PUSHJ	P,PUTWRD	;Completion status and flags
	HLRZ	T2,R.IDENT(P4)	;Get request ID
	NETOCH	T2
	ASSUME	XS.SFC,0	;From above
	NETOCH	P1		;Reserved byte
	MOVEI	P1,1		;Number of characters here
	PUSHJ	P,PUTLWD	;plus zero writes
	MOVEI	T1,.CHCNC
	NETOCH	T1
	PUSHJ	P,XMTMSS	;Send the message
;	HLRZ	T2,R.MOD(P4)	;Get modifiers
	MOVE	P4,READQ	;Restore P4 to point to queue block
;	TRNE	T2,RM.RNE	;Noecho?
;	  JRST	RX.CRQ		;Yes, continue processing
	MOVEI	T4,[ASCIZ/^C
/]
	PUSHJ	P,STROUT
	PUSHJ	P,DOOUT1
	JRST	RX.CRQ		;Echo before continuing

RX.DSC:	PUSHJ	P,RX.SPC	;Yes, handle them
	  JRST	RX.DS1		;Normal return
	PUSHJ	P,CONSCN	;Continue scan
	  JRST	RX.DSC
	JRST	RX.NSC		;No special chars at all
RX.DS1:	SKIPE	P4,READQ	;Still a queued request?
	  JRST	RX.CRQ		;Yes, scan again (must be from TTY:)
	PJRST	XCRURB		;No, give up now
	SUBTTL	RSX Support -- Output prompt string

;This routine outputs the prompt string in the RSX digested header block
;pointed to by P4.  Uses T1, T3, and T4.

XPROMT:	SKIPN	T4,R.PROMPT(P4)		;Get the prompt string
	  POPJ	P,			;None to do
	MOVEI	T3,($TOOIN!$TOICL)
	MOVEM	T3,TOFLGS
	HLRZ	T3,T4			;Get count
	HRLI	T4,(POINT 8,,)		;Point to data
RX.OPM:	ILDB	T1,T4
	PUSHJ	P,OUTTTY
	SOJG	T3,RX.OPM		;Output all prompt data
	PUSHJ	P,DOOUT1
	SETZM	TOFLGS
	POPJ	P,
	SUBTTL	RSX Support -- Handle special characters

RX.SPC:	CAME	P1,ESCCHR		;Escape?
	  JRST	RX.CCC			;No, see if ^C
	PUSHJ	P,MONITO		;Return to monitor
	  JRST	[PUSHJ	P,SPCRMV	;Remove special chracter
		 PJRST	XCRURB	]	;See about this
	AOS	BRKNUM			;One more break to ignore
	PJRST	XCRURB			;Check bits

RX.CCC:	CAIE	P1,.CHCNO
	  JRST	RX.CTC			;Control-C or ^X
	PUSHJ	P,SPCRMV		;Clear it
	PUSHJ	P,XCRURB
	TXCN	F,F$CTO			;Setting ^O?
	  PUSHJ	P,CLRTOQ		;Clear the TO queue
	MOVEI	T4,[ASCIZ/^O
/]					;How to echo it
	PUSHJ	P,STROUT
RX.CTO:	PUSHJ	P,DOOUT1
RX.CO1:	MOVEM	F,RSXSVF		;Save the current flags
	MOVEI	T1,RF.ECR
	NETOCH	T1			;Tell him to toggle too
	SETZ	P1,
	PUSHJ	P,PUTWRD		;No flags or modifiers
	MOVEI	T1,RE.HAO
	NETOCH	T1			;Output reason
	PUSHJ	P,XMTMSS		;Tell him
	TXZ	F,F$ICO			;Don't ignore any more
	TXNN	F,F$CTO			;Set or clear?
	  PJRST	CLRCTO			;Tell the monitor
	PUSHJ	P,WATOUT		;Wait for it to go out if just set
	PJRST	SETCTO

RX.CTC:	CAIE	P1,.CHCNC		;^C?
	  JRST	RX.CTX			;Check ^X if not
	PUSHJ	P,SPCFLS		;Clear input to ^C
	MOVEI	T1,RF.ECR		;Request an exception
	NETOCH	T1
	SETZ	P1,			;No flags or modifiers
	PUSHJ	P,PUTWRD
	ASSUME	RE.SAR,0
	NETOCH	P1			;Output the reason
	SKIPN	P4,READQ		;A request?
	  PJRST	XMTMSS			;Send the message and return
	PUSHJ	P,XMTMSS		;Send the abort
	MOVEI	T1,RF.RDD		;Set the request type
	PUSHJ	P,RSX.BH		;Build it
	SETZ	P1,			;The reserved byte
	NETOCH	P1			;..
	PUSHJ	P,PUTLWD		;Also the counts
	MOVEI	P1,.CHCNC		;The terminator
	NETOCH	P1			;Output it
	PJRST	RX.RDQ			;Clean up


RX.CTX:	CAIE	P1,.CHCNX		;Control-X?
	  JRST	RX.CTU			;Maybe ^U
	PUSHJ	P,SPCFLS		;Flush input to ^X
	SKIPN	READQ			;If not inputting
	  POPJ	P,			;Then return
	MOVEI	T4,[ASCIZ/^U
/]
	PUSHJ	P,STROUT
	PUSHJ	P,DOOUT1		;Force it out
	PJRST	RX.CU1			;And check some things

RX.CTU:	PUSHJ	P,SCNPOS		;Get position
	SKIPE	T2,READQ		;Read request?
	  JRST	[MOVE	T2,R.COUNT(T2)	;Yes, use this count
		 JRST	RX.CCU	      ]	;Do it
	SKIPN	T2,XUNREQ		;Get request
	  JRST	CPOPJ1			;None, ignore these special chars
	MOVE	T2,R.COUNT(T2)		;Get count
RX.CCU:	CAILE	T1,(T2)
	  JRST	CPOPJ1			;Return
	CAIE	P1,.CHCNU		;Control-U?
	  JRST	RX.CTR			;Maybe ^R
	PUSHJ	P,DOCTU
RX.CU1:	PUSHJ	P,RX.CNC		;Count ^Cs
	TXNE	F,F$PALL		;Shouldn't be here if this is set, but
	  JRST	RX.CU3			;See about request
	SKIPN	P4,READQ		;Read request?
	  JRST	RX.CU2
	PUSHJ	P,XPROMT		;Output the prompt string
	PJRST	XCRURB			;...
RX.CU2:	SKIPN	P4,XUNREQ		;No, unsolicited request?
	  PJRST	XCRURB			;No request
	PJRST	RX.DUN			;Re-set unsolicited stuff

RX.CU3:	SKIPN	P4,READQ		;Prompt request?
	  POPJ	P,
	PJRST	XPROMT			;Output and return

RX.CTR:	CAIE	P1,.CHCNR		;Control-r?
	  JRST	RX.RUB			;Must be rubout
	MOVEI	T1,RX.CR1		;For outputting the prompt
	PUSHJ	P,DOCTR
	PJRST	XCRURB			;See about flags

RX.CR1:	SAVE4				;Save the Ps
	SKIPE	P4,READQ		;Request?
	  PJRST	XPROMT			;Finish it
	POPJ	P,

RX.RUB:	PUSHJ	P,DORUB			;Do the rubout
	PUSHJ	P,RX.CNC		;Count ^Cs in buffer
	FALL	XCRURB			;See about flags
	SUBTTL	RSX Support -- Check about ^U/^R/<RUB> processing

XCRURB:	TDZA	T1,T1				;Flag to set
XCRUR1:	SETO	T1,				;Don't set
	TXNN	F,F$READ			;Read pending?
	  JRST	XURURB				;No
	TXNN	F,F$PALL			;Passall?
	SKIPN	ICHCNT				;Any chars?
	  JRST	XURURB				;No
XSRURB:	JUMPN	T1,CPOPJ			;Don't change it
	MOVEI	T1,<1B<.CHCNR>!1B<.CHCNU>>	;Set to watch them
	AND	T1,LMASK			;Unless he wanted them
	XORI	T1,<1B<.CHCNR>!1B<.CHCNU>>	;..
	IORM	T1,CHRTAB
	MOVEI	T1,1B31				;<RUB> in LMASK
	TDNE	T1,LMASK+3			;Set there?
	  TRO	T1,1B19				;Yes, set here
	TRC	T1,1B19!1B31			;31 off, 19 as decided
	IORM	T1,CHRTAB+3
	PJRST	STRURB				;Set and return
	POPJ	P,				;Return

XURURB:	MOVEI	T1,<1B<.CHCNR>!1B<.CHCNU>>	;Clear in CHRTAB
	ANDCAM	T1,CHRTAB
	MOVEI	T1,1B19				;Clear rubout too
	ANDCAM	T1,CHRTAB+3
	MOVE	T3,RXDMSK			;Default count
	SKIPE	T1,READQ			;In case a request
	MOVE	T3,R.COUNT(T1)			;Get count from there
	PJRST	UNRURB				;Cancel unless in mask
	SUBTTL	RSX Support -- Count ^Cs

;Here to set XSPCNT correctly.  Uses T1-T4
;Note that no interrupt which can affect XSPCNT should be allowed to happen

RX.CNC:	SAVE4				;Save the Ps
	PUSHJ	P,SCNINI
	SETZM	XSPCNT			;Init count
RX.CNL:	PUSHJ	P,SCNCHR
	  POPJ	P,			;Done if no more characters
	CAIN	P1,.CHCNC		;Is it the magic character?
	  AOS	XSPCNT			;Count it if so
	JRST	RX.CNL
	SUBTTL	RSX Support -- Set TTY: up

;Enter with P4 pointing to header block
;Note this should only be called for "normal" read requests

RX.STT:	MOVSI	T1,RM.RNE			;No-echo?
	TDNN	T1,R.MOD(P4)			;?
	TXZA	F,<F$NEC>			;Echo, clear the bit
	TXO	F,<F$NEC>			;Set it
	HRLI	T1,RXDMSK+1			;Assume default
	SKIPE	R.MASK(P4)			;Is there?
	HRLI	T1,R.MASK(P4)			;Yes
	HRRI	T1,IMASK+1			;Put it in
	BLT	T1,ENDMSK
	MOVE	T1,[IMASK+1,,LMASK]		;Set logical mask
	BLT	T1,ELMASK			;..
	MOVSI	T1,RM.RTC			;Terminate on control?
	TDNN	T1,R.MOD(P4)			;?
	  JRST	RX.ST2				;No
	MOVEI	T1,37
	ANDM	T1,CHRTAB
	MOVEI	T1,1B19
	ANDCAM	T1,CHRTAB+3
	SETZ	T1,
	JRST	RX.ST3
RX.ST2:	MOVX	T1,<1B<.CHCNC>!1B<.CHCNO>!1B<.CHCNX>>
	IORM	T1,CHRTAB
RX.ST3:	TXO	T1,1B<.CHCNH>			;Be sure see this too
	IORM	T1,IMASK+1
	MOVE	T1,R.COUNT(P4)			;Set the default field width
	MOVEM	T1,IMASK
	TXNN	F,F$TMR				;See if timeouts are involved
	  JRST	RX.ST4				;Continue
	MOVEI	T1,1				;Then field must be only one
	MOVEM	T1,IMASK
RX.ST4:	SKIPN	T1,XSCREQ			;Read single active?
	  JRST	RX.ST6				;No, skip some
	HLRZ	T1,R.MOD(T1)			;Get modifiers
	TRNN	T1,RM.OSA			;Want ^C?
	  JRST	RX.ST6				;Set TTY:
	MOVX	T1,1B<.CHCNC>			;Be sure in mask
	IORM	T1,IMASK+1
RX.ST6:	PUSHJ	P,TTYSST			;Set up TTY:
	PJRST	FRCTTI				;And wake up
	SUBTTL	RSX Support -- handle timed requests

;Call with protocol header pointed to by P4

RX.STM:	TXO	F,F$TEX				;Be sure it's set
	MOVEI	T1,RX.TMR			;Routine to handle
	MOVEM	T1,OSTMR			;Set the routine
	HLRZ	T1,R.IDENT(P4)			;Get identifier
	MOVEM	T1,TMRSEQ			;Save to be sure right req
	MOVE	T1,R.TIME(P4)			;Get the time
	PITMR.	T1,
	  JFCL
	POPJ	P,

;Routine to actually handle requests:

RX.TMR:	SKIPN	P4,READQ		;Any request
	  JRST	RX.CTS			;See if single-character timeout
	HLRZ	T1,R.IDENT(P4)
	MOVSI	T2,RM.RTM		;Check ID and timer flag, in case SSC
	CAMN	T1,TMRSEQ		;Right sequence number?
	TDNN	T2,R.MOD(P4)		;Single characters maybe
	  JRST	RX.CTS			;No time-out here, check single chars
	PJRST	RX.RDS			;Read "satisfied"

RX.CTS:	SKIPN	P4,XSCREQ		;Single characters request?
	  POPJ	P,
	HLRZ	T1,R.IDENT(P4)		;Be sure ID matches
	CAME	T1,TMRSEQ		;?
	  POPJ	P,			;Doesn't match
	TXO	F,F$TEX			;Timeout expired
	JRST	RX.SSS			;Single satisfied
	SUBTTL	RSX Support -- Write data

RX.WRT:	PUSHJ	P,RSX.EH		;Eat common header
	PUSHJ	P,CHKCTO		;Check status of ^O
	MOVE	T1,RSXSVF		;Get old flags
	XOR	T1,F			;Get difference
	TXNE	T1,F$CTO		;Has state changed?
	  PUSHJ	P,RX.CO1		;Yes, inform the host
	TXNE	F,F$CTO			;Control-O in effect?
	  JRST	RX.WR1			;Yes
	PUSHJ	P,GETWRD		;Get read count (should be zero)
	PUSHJ	P,GETWRD		;Get write count
	JUMPE	T1,RX.WR1		;No real bytes
	MOVEI	T4,(T1)			;Transfer ACs
	SETZM	TOFLGS			;Assume normal write
	MOVSI	T1,RM.WBT		;Breakthrough type?
	TDNN	T1,R.MOD(P4)		;?
	  JRST	RX.WR0			;No
	MOVEI	T1,($TOOIN)
	MOVEM	T1,TOFLGS
RX.WR0:	PUSHJ	P,RBYTEC		;Else get a byte
	CAIL	T1," "			;Printing?
	  TXZA	F,F$CLF			;No, cancel line feed
	CAIN	T1,.CHLFD		;Line feed?
	  TXZN	F,F$CLF			;Supposed to cancel one?
	PUSHJ	P,OUTTTY		;Output character to TTY:
	SOJG	T4,RX.WR0		;For all characters
	PUSHJ	P,DOOUT1
	SKIPN	TOFLGS
	  PUSHJ	P,WATDEQ
	SETZM	TOFLGS
RX.WR1:	MOVSI	T1,RM.NWC		;Want write complete?
	TDNE	T1,R.MOD(P4)		;?
	  JRST	RX.WR4			;No
	MOVEI	T1,RF.WTD		;Write function
	PUSHJ	P,RSX.BH		;Build a header
	PUSHJ	P,XMTMSS		;Send ACK
RX.WR4:	MOVEI	T1,(P4)
	MOVEI	T2,REQSIZ
	PJRST	CORFRE			;Free block and return

	SUBTTL	RSX Support -- Eat common header

;Returns with digested header block (R.xxxx) pointed to by P4

RSX.EH:	MOVEI	T1,REQSIZ
	PUSHJ	P,CORGET
	MOVEI	P4,(T1)			;Point P4 at it
	PUSHJ	P,RBYTEC		;Get modifiers
	HRLM	T1,R.MOD(P4)		;Store them
	PUSHJ	P,RBYTEC		;Get flags
	TRNE	T1,RM.CAO		;Cancel ^O?
	  PUSHJ	P,RX.CCO		;Clear ^O
	HRRM	T1,R.FLAG(P4)		;Also flags
	PUSHJ	P,GETWRD		;Get status and identifier
	LSH	T1,-^D8			;Put ID in low order byte
	HRLM	T1,R.IDENT(P4)		;Save it
	PJRST	RBYTEC			;Eat reserved byte and return
	SUBTTL	RSX Support -- Build header for output message

;Enter with T1=function code to build header for; P4=digested header block

RSX.BH:	NETOCH	T1			;Put function in header
	HLRZ	T1,R.MOD(P4)		;Get modifiers
	ANDCMI	T1,RM.RTM		;Default didn't time out
	NETOCH	T1
	SETZ	T1,			;Flags
	NETOCH	T1
	MOVEI	T1,XS.SFC		;Set Normal function
	NETOCH	T1
	HLRZ	T1,R.IDENT(P4)		;Get identifier
	SOSGE	OBFCTR
	  JRST	[PUSHJ	P,NETQUE
		 JRST	.-1	]
	IDPB	T1,OBFPTR		;Do NETOCH by hand
	POPJ	P,			;So is a few less instructions
	SUBTTL	RSX Support -- Queue read request

;Enter with RSX digested header block in P4

XQREAD:	MOVEI	T1,READQ-R.LINK
	MOVEI	T2,-1			;So can check queue
XQLP:	TDNN	T2,R.LINK(T1)		;Anything there?
	  JRST	XQHAV			;Done
	HRRZ	T1,R.LINK(T1)
	JRST	XQLP
XQHAV:	HRRM	P4,R.LINK(T1)
	POPJ	P,			;Return
	SUBTTL	VMS Support -- Protocol definitions

PLM
;+
;.hl 2 VMS Support
;	VMS also uses a message protocol.  It is perhaps most important
;for VMS that the user understand the internals of the remote operating
;system.  This is due to the fact that the program which communicates
;with VMS becomes, in essence, an equivalent of TTDRIVER.
;	A further peculiarity of VMS is the "free line feed" logic.  This
;is part of VMS such that the user doesn't over-write a just-typed
;out line with echoed characters.  The basic rules are:
;.list 1
;.le
;If the last write or broadcast operation ended with a <CR> not followed
;by a <LF> (remember that a VMS "record" is <LF>data<CR>), then the
;next read operation generates a "free" line feed.  If there is a leading
;line feed in the prompt, that is the "free" line feed.
;.le
;If the last read operation was terminated by <CR>, then <CR> echoes
;as <CR><LF> and the "free" line feed is "canceled" for the next read
;request (assuming no writing is done in between).  This means if
;there is a leading <LF> in the prompt, it is eaten and not displayed.
;.le
;The above is not through for any flavour of physical only I/O (IO$__READPBLK,
;IO$__READALL, PASSALL mode, etc.).
;.end list
;	Reference documents:
;.list 1
;.le
;^&VAX/VMS Network Command Terminal Protocol\& - This memo by Scott G. Davis
;describes the pre-release 3.x protocol.
;.le
;^&VMS V3.0 Remote Terminal Protocol\& - This memo by Darrell Duffy
;specifies the updates to the above memo for VMS V3.x.
;.le
;^&VAX/VMS I/O Users' Guide\& - Since the VAX expects NRT to be the equivalent
;of the terminal driver, it is useful to know what is expected of a terminal
;driver.
;.end list
;-
MLP

;Digested header block:
	PHASE	0
V.LINK:	BLOCK	1			;Link to next request
V.IDENT:BLOCK	1			;Identifier for this request
V.MOD:	BLOCK	1			;Modifiers for this request
V.COUNT:BLOCK	1			;Request byte count for this request
V.TIME:	BLOCK	1			;Timeout for this request
V.PROM:	BLOCK	1			;Pointer to prompt string and size
V.STAT:	BLOCK	1			;Status we want, if request doesn't complete
V.MASK:	BLOCK	11			;One word length + enough for 256 bits
	VRQSIZ==.-V.LINK		;Size of digested request block

	DEPHASE
; op code modifiers
; READ

	CVTLOW==400			;IO$M_CVTLOW
	DISMBX==2000			;IO$M_DSABLMX
	NOECHO==100			;IO$M_NOECHO
	NFILTR==1000			;IO$M_NOFILTR
	PURGE==4000			;IO$M_PURGE
	REFRSH==2000			;IO$M_REFRESH
	TIMER==200			;IO$M_TIMED
	TNOEKO==10000			;IO$M_TRMNOECHO
	ESCAPE==40000			;IO$M_ESCAPE
	TYPAHD==100			;IO$M_TYPEAHDCNT

;Internal modifiers (left half of V.MOD)
	VM.RAL==1B0			;Readall, MUST BE SIGN BIT

; WRITE
	CANCTRLO==100			;IO$M_CANCTRLO
	ENAMBX==200			;IO$M_ENABLMBX
	NFORMT==400			;IO$M_NOFORMAT
; SETMODE
	CC=400				;IO$M_CTRLCAST
	CY==200				;IO$M_CTRLYAST
	HANGUP==1000			;IO$M_HANGUP
	OBAND==2000			;IO$M_OUTBAND
	INCLUDE==10000			;IO$M_INCLUDE
	MODEM==2000			;IO$M_SET_MODEM

; Status codes returned
	NORMAL==1			;SS$_NORMAL
	TIMEOUT==1054			;SS$TIMEOUT
	ABORTS==54			;SS$_ABORT
	PARTES==774			;SS$_PARTESCAPE
	BADESC==74			;SS$_BADESCAPE
	CONTRC==3121			;SS$_CONTROLC
	CONTRY==3021			;SS$_CONTROLY
	CANCEL==4060			;SS$_CANCEL
	HNGUPS==1314			;SS$_HANGUP
	CONTRO==3011			;SS$_CONTROLO
	ILLFNC==364			;SS$_ILLIOFUNC


; Modifiers for attention code

	RA.UNS==0			;Unsolicited data
	RA.HUP==1			;Modem hangup
	RA.CTC==2			;Control C
	RA.CTY==3			;Control Y
	RA.RSV==4			;Reserved
	RA.BRD==5			;Broadcast mailbox
	RA.OUB==6			;Out-of-band completion

;Miscellaneous constants:

	MTMBRD==^D83			;MSG$_TRMBRDCAST

; VAX Terminal symbols

	DC$TERM==102			;Generic terminals
	DT$L120==41			;LA120
	DT$L180==3			;LA180
	DT$L36==40			;LA36
	DT$TTY==0			;Generic hard copy
	DT$V52==100			;VT52
	DT$V100==140			;VT100
	DT$V5X==100			;Generic CRT

; Terminal Definitions

	TPSAL==1			;TT$M_PASSALL
	TNEKO==2			;TT$M_NOECHO
	TNTPH==4			;TT$M_NOTYPEAHEAD
	TESCP==10			;TT$M_ESCAPE
	THSYN==20			;TT$M_HOSTSYNC
	TTSYN==40			;TT$M_TTSYNC
	TLOWR==200			;TT$M_LOWER
	TMTAB==400			;TT$M_MECHTAB
	TWRAP==1000			;TT$M_WRAP
	TCRLF==2000			;TT$M_CRFILL
	TLFFL==4000			;TT$M_LFFILL
	TSCOP==10000			;TT$M_SCOPE
	TRMOT==20000			;TT$M_REMOTE
	THSCR==40000			;TT$M_HOLDSCREEN
	T8BIT==100000			;TT$M_EIGHTBIT
	TMDIS==200000			;TT$M_MBXDSBL
	TNBCS==400000			;TT$M_NOBROADCAST
	TRSYN==1,,0			;TT$M_READSYNC
	TMFRM==2,,0			;TT$M_MECHFORM
	THDUP==4,,0			;TT$M_HALFDUP

;TT2 defs:

	T2BCM==20			;Broadcast mailbox
	T2DCRT==4000000000		;TT2$M_DECCRT
	T2ACRT==100000000		;TT2$M_ANSICRT

; Misc terminal flags

	TAPAR==40			;TT$M_ALTRPAR
	TPAR==100			;TT$M_PARITY
	TODD==200			;TT$M_ODD
	TSCRP==100			;TT$M_SCRIPT
	TSPAG==10			;TT$S_PAGE
	TMPAG==37700,,0			;TT$M_PAGE

;I/O function codes ($IODEF)

	VF.WPH==13	;These are all writes
	VF.WLB==40
	VF.WVB==60

	VF.RPH==14	;these are all reads
	VF.RLB==41
	VF.RVB==61
	VF.RAL==72	;READALL
	VF.RPR==67	;Read with prompt
	VF.RPA==73	;READALL with prompt

	VF.STC==32	;Set characteristics
	VF.STM==43	;Set mode
	VF.SNC==33	;Sense characteristics
	VF.SNM==47	;Sense mode

	VF.ACC==70	;ACPcontrol (Kill)
	VF.BCS==177777	;Broadcast

;Return Opcodes

	VR.ATT==-1	;Attention
	VR.END==-2	;I/O complete
	VR.ERR==-3	;Error

	SUBTTL	VMS Support -- VAX/VMS network input routine

VMS.NT:	PUSHJ	P,GETWRD		;Get a word (should be there!)
	PUSH	P,T1			;Save function
	MOVEI	T1,VRQSIZ		;Get length of block
	PUSHJ	P,CORGET		;Get it
	MOVEI	P4,(T1)			;Copy addr of request block to P4
	PUSHJ	P,VMS.EH		;Eat common header
	POP	P,T1			;Restore function
	MOVEI	P1,VMSFNC		;Point to QIO table
	PUSHJ	P,FNDFNC		;Find the function in the table
	  ERR	IVQ,<Illegal VMS QIO function>
VM.ETI:	TXZN	F,F$NEOM		;If we encountered EOM, then
	  POPJ	P,			;It is OK to return
	PUSHJ	P,NSPIN			;Else eat to EOM
	  JRST	NSPERR			;Oops
	JRST	VM.ETI			;Eat all input
	SUBTTL VMS Support -- VMS TTY: input routine

VMS.TT:
	PUSHJ	P,VM.SCT		;Set CHRTAB
	  JRST	VMS.NS			;Nothing is special
	PUSHJ	P,VM.CHO
	  PUSHJ	P,VMS.OB		;Yes send out of band first
VMS.NS:	SKIPE	P4,SENSEQ		;Sense pending?
	  PUSHJ	P,VM.SNC		;Finish it up
	SKIPE	P4,READQ		;Is there a read queued?
	  JRST	[TLO	P4,400000	;Flag here from TTY
		 PJRST	CHKREQ	]	;Check the request
VMS.N1:	PUSHJ	P,SCNSPC		;Scan for "special" characters
	  JRST	VMS.N5			;See about treating them
VMS.N3:	SKIPE	ICHCNT			;Any characters?
	  PJRST	VMS.UN			;Tell him there's data
	PJRST	VCRURB			;Check setting of F$RUB

VMS.N5:	PUSHJ	P,VMS.SC		;Treat them
	  JRST	VMS.N1			;Check again
	PUSHJ	P,CONSCN		;See if more special chars
	  JRST	VMS.N5			;Yes
	JRST	VMS.N3			;No, ignore the ones we saw
	SUBTTL VMS Support -- VMS.DA - Recieve VMS data

VMS.PW:	MOVEI	T1,NFORMT	;Noformat bit
	IORM	T1,V.MOD(P4)	;Set it
VMS.DA:
	MOVE	T1,V.MOD(P4)	;Get modifiers
	TRNE	T1,CANCTRLO	;Cancel ^O effect?
	  PUSHJ	P,CLRCTO	;Yes
	PUSHJ	P,CHKCTO	;See what the setting is
	TRNE	T1,ENAMBX	;Want unsolicited now?
	  PUSHJ	P,VM.SUN	;Set up unsolicited stuff
	TXNE	F,F$CTO		;Is ^O in effect?
	  JRST	VM.CTO		;Toss the write then
	TXNN	F,F$PALL	;Passall?
	TRNE	T1,NFORMT	;Or NOformat?
	  TXOA	F,F$PIM		;Set PIM
	JRST	VM.DA1		;OK to use ASCII
	PUSHJ	P,TTYSST	;Set PIM (wait for pending output to complete)
VM.DA1:	PUSHJ	P,GETLWD	;Get count
	MOVEI	P1,(T1)		;Save for later
	PUSHJ	P,GETWRD	;Get first and second bytes of carcon
	ANDI	T1,377		;Save only carcon byte
	JUMPN	T1,VM.FRT	;FORTRAN carriage control
	PUSHJ	P,RBYTEC	;Get prefix carcon byte
	PUSH	P,T1
	PUSHJ	P,RBYTEC	;Get postfix control
	EXCH	T1,(P)		;Save postfix, get prefix
VM.DCC:	PUSHJ	P,VM.CCN	;Do the control
	PUSHJ	P,VMS.WR	;Write the record out (P1=count)
	POP	P,T1		;Get postfix control back
	PUSHJ	P,VM.CCN	;Do the control
	TXZE	F,F$PIM		;Clear PIM
	  PUSHJ	P,TTYSST	;Change back
VM.DC2:	MOVE	T1,V.MOD(P4)	;Get modifiers
	TRNE	F,REFRSH	;Refresh?
	PUSHJ	P,VM.CRF	;Need to refresh
	PJRST	VMS.AK		;ACK the request and return
;Here to interpret a Fortran carriage control character

VM.FRT:	DMOVE	T3,[	2	;2 <LF>s
		    200!.CHCRT]	;<CR> for postfix
	CAIN	T1,"0"		;Is it double-space?
	  JRST	VM.FR1		;Yes, process
	DMOVE	T3,[200!.CHFFD	;Form-feed prefix
		    200!.CHCRT]	;<CR> postfix
	CAIN	T1,"1"		;Eject?
	  JRST	VM.FR1		;Yes
	DMOVE	T3,[	Z	;Null prefix
		    200!.CHCRT]	;<CR> postfix
	CAIN	T1,"+"		;If overprint control
	  JRST	VM.FR1
	DMOVE	T3,[	1	;1 <LF>
		    200!.CHCRT]	;<CR> postfix
	CAIN	T1,"$"		;Unless prompt sequence
	  DMOVE	T3,[	1	;1 <LF>
			Z   ]	;Null postfix
VM.FR1:	PUSHJ	P,GETWRD	;Eat next two bytes
	MOVEI	T1,(T3)		;Prefix to T1
	PUSH	P,T4		;Postfix to stack
	JRST	VM.DCC		;Go do it
	SUBTTL	VMS Support -- Routine to do carriage control

;Call with carriage control byte in T1

VM.CCN:	JUMPE	T1,CPOPJ		;Nothing to do
	TRZE	T1,200			;<LF> count?
	  JRST	[CAIN	T1,.CHCRT	;<CR>
		   TXOA	F,F$FLF		;Yes, may need free line feed
		 TXZ	F,F$FLF		;Don't want free <LF>
		 JRST	OUTTTY	]	;...
	TXZ	F,F$FLF			;Don't need free line feed if already
	TXZE	F,F$CLF			;Supposed to cancel a line feed?
	  SOJLE	T1,CPOPJ		;Yes, exit if only one to do here
	MOVEI	T2,(T1)			;Move count to T2
	MOVEI	T1,.CHCRT		;Do one <CR>
	PUSHJ	P,OUTTTY		;(don't need more than one)
	MOVEI	T1,.CHLFD		;Get a line feed
VM.LFS:	PUSHJ	P,OUTTTY
	SOJG	T2,VM.LFS		;Do them
	POPJ	P,			;Then return
	SUBTTL	VMS Support -- Routine to actually write the record

;Character count in P1, zeroed on return

VMS.WR:	JUMPE	P1,CPOPJ	;If nothing to do
	SETO	P2,		;Flag first time through
VM.WR1:	PUSHJ	P,RBYTEC	;Get a byte from the record
	CAIE	T1,.CHCRT	;<CR>
	  TXZA	F,F$FLF		;No, don't want free line feed
	TXO	F,F$FLF		;Flag may want it
	AOJG	P2,VM.WR2	;Don't worry about this if not first time
	TXNN	F,F$CLF		;Cancel on?
	  JRST	VM.WR2		;No, just ignore
	CAIN	T1,.CHCRT	;If <CR>...
	  SOJA	P2,VM.WR3	;Just ignore
	CAIN	T1,.CHLFD	;A line feed?
	  TXZA	F,F$CLF		;Yes, we already did it
VM.WR2:	PUSHJ	P,OUTTTY	;Output the character
VM.WR3:	SOJG	P1,VM.WR1
	TXZ	F,F$CLF		;Real data, don't cancel any free line feeds
	POPJ	P,		;Return with characters output
	SUBTTL	VMS Support -- Check to see if REFRESH needed

VM.CRF:	PUSH	P,P4
	SKIPN	P4,READQ	;Is there a request
	  JRST	VM.CF2
	PUSHJ	P,CHKPRM	;Do the prompt string
	MOVE	CX,[2,,T1]	;Force out the rescan buffer
	MOVE	T1,[SIXBIT/.TYPE/]
	MOVE	T2,TTYUDX
	FRCUUO	CX,
	  JFCL			;Ignore; they fail randomly anyway
VM.CF2:	POP	P,P4
	POPJ	P,
	SUBTTL  VMS Support -- Read and Read with prompt

VMS.PA:	SKIPA	T2,[-1]		;Prompt
VMS.RA:	SETZ	T2,
	MOVSI	T1,(VM.RAL)	;Set special mode bit for us
	IORM	T1,V.MOD(P4)	;Turn it on
	JRST	VM.RED


VMS.PD:	SKIPA	T2,[-1]
VMS.RD:	SETZ	T2,
VM.RED:	MOVEM	T2,V.PROMPT(P4)	;Set prompt or not flag
	PUSHJ	P,GETLWD	;Get a longword count for chars
	MOVEM	T1,V.COUNT(P4)	;Save count
	PUSHJ	P,GETLWD	;Get time-out
	MOVEM	T1,V.TIME(P4)	;Save timeout
	PUSHJ	P,RBYTEC	;Get a byte
	JUMPE	T1,NOMSK	;No terminator mask
	MOVE	T4,T1		;Count of bytes to get
	MOVEM	T1,V.MASK(P4)	;Flag there is a mask
	MOVEI	T3,V.MASK+1(P4)	;Point to mask word
	HRLI	T3,(POINT 8,,)	;Make byte pointer to it
	PUSHJ	P,CPYMSK	;Set the mask copy

NOMSK:	SKIPE	V.PROMPT(P4)	;Prompt?
	SKIPGE	IBFCNT		;Data for one?
	  JRST	NOPMT		;No prompt requested or no data
	PUSHJ	P,GETWRD	;Get length of string
	SKIPN	P1,T1		;Copy to P1 and see if there is any string
	  JRST	NOPMT
CPYPMT:	SKIPN	P1,T1				;Copy to P1, is it non-zero?
	  POPJ	P,				;No
	LSHC	T1,-2
	TLNE	T2,600000			;Remainder?
	  AOJ	T1,
	PUSHJ	P,CORGET			;Get the block
	MOVEM	T1,V.PROM(P4)			;Point to prompt string
	HRLM	P1,V.PROM(P4)			;Save number of characters
	HRLI	T1,(POINT 8,,)			;Byte pointer to data
	MOVE	T2,T1				;But don't keep it in T1
	PUSHJ	P,RBYTEC			;Get a byte
	IDPB	T1,T2				;Save
	SOJG	P1,.-2				;For all bytes
	TRNA					;There really is a prompt
NOPMT:	SETZM	V.PROMPT(P4)			;There really isn't a prompt

	SKIPE	READQ				;Read already queued?
	  JRST	VQREAD				;Yes, just queue this request
NVRDRQ:	PUSHJ	P,CLRCTO			;Clear ^O
	MOVX	T1,VM.RAL			;Physical type request?
	TXNE	F,F$PALL			;Physical?
	  TXZA	F,F$FLF				;Skip one useless instruction
	TXNN	F,F$CLF				;Cancel a free line feed?
	TDNE	T1,V.MOD(P4)			;(No, physical)?
	  TXZ	F,F$FLF				;Yes, no formatting
	MOVE	T1,V.MOD(P4)			;Get modifiers
	MOVE	T2,VMTTCH+1			;Get terminal characteristics
	TRNN	T2,TESCP			;Set escape recognition here?
	TRNE	T1,ESCAPE			;Want escape processing?
	  TXOA	F,F$ESC				;Yes
	TXZ	F,F$ESC!F$ESA			;Clear all traces
	TRNE	T1,DISMBX			;Disable unsolicited?
	  TXZ	F,F$UAST			;Yes
	TRNE	T1,PURGE			;Purge typeahead?
	  PUSHJ	P,FLSTAH			;Flush type-ahead
	PUSHJ	P,CHKPRM			;See if have to do a prompt
	MOVEI	T1,NOECHO			;Noecho?
	TDNN	T1,V.MOD(P4)			;..?
	TXNN	F,F$FLF				;Echoing, need free line feed?
	  JRST	VM.NFL				;no
	MOVEI	T1,.CHLFD
	PUSHJ	P,OUTTTY			;Output
	PUSHJ	P,DOOUT1			;...
VM.NFL:	HRRZM	P4,READQ			;This is the current request
	TXO	F,F$READ			;Read outstanding
	SETOM	UNSCNT				;Allow unsolicited messages
	MOVEI	T1,TIMER			;Timed request?
	TDNE	T1,V.MOD(P4)			;?
	  PUSHJ	P,VM.STM			;Yes, set a timer request
	PUSHJ	P,VM.STT			;Set TTY: up
;Enter here on TTY: I/O complete to see if we can now satisfy this request
;Enter with P4 pointing to digested QIO block and sign bit set
;if from TTY: service
CHKREQ:
	PUSHJ	P,CLRCTO			;Clear ^O
	MOVEM	P4,READQ			;Store request
CHKRQ1:	PUSHJ	P,SCNSPC			;Check for special characters
	  JRST	VM.CRS				;See about special characters
CHKRQ2:	MOVE	P4,READQ			;Get request
	MOVE	T1,ICHCNT			;Any characters?
	TLZN	F,(F$BRK)			;Break?
	CAML	T1,V.COUNT(P4)			;Enough characters input to satisfy?
	  JRST	VM.RDS				;Satisfied
	TXZE	F,F$TEX				;Timeout expiration?
	  PJRST	FRCTTI				;Give it one more shot
	SKIPN	V.STAT(P4)			;Set a status?
	  JRST	VQREAD				;Nope, queue the read
VM.RDS:	SETOM	LICHCT				;Be sure we output ^H next time
	MOVEI	P2,($TOOIN!$TOICL)
	MOVEM	P2,TOFLGS
	TXZ	F,F$ESA				;Be sure zapped
	PUSHJ	P,VMS.BH			;Build data header
	PUSH	P,OBFPTR			;Save where iosb goes
	NETALC	^D8+2				;Skip over IOSB and count
	MOVN	P2,V.COUNT(P4)			;Get character count
	HRLZI	P2,(P2)				;Make aobjn ptr
	MOVE	P3,V.MOD(P4)			;Get the modifiers
	SETZM	BRKSIZ				;Clear size of break string
	JUMPE	P2,VM.RDZ			;**Zero length read**
	JUMPG	P2,[MOVE	P1,V.STAT(P4)	;Get status desired
		    JRST	VM.RD0	     ]	;And complete
VM.RDL:	PUSHJ	P,INCHR				;Get a character
	  JRST	[SKIPN	P1,V.STAT(P4)		;Get status if set (TIMEOUT)
		  MOVEI	P1,TIMEOUT		;?
		 TLZ	P2,400000		;Be sure don't do terminator stuff
		 JRST	VM.RD0]			;And finish it
	CAMN	T1,ESCCHR			;Escape character?
	  SOS	BRKNUM				;One less break to ignore
	TRNN	P3,CVTLOW			;Convert lower case?
	  JRST	VM.NLC				;No, don't bother
	CAIL	T1,"a"				;Is it lower case?
	CAILE	T1,"z"				;?
	  TRNA					;No
	TRZ	T1,<"a"-"A">			;Convert if it is
VM.NLC:	NETOCH	T1
	PUSHJ	P,CHKBR1			;See if it's a break character
	  JRST	VM.RDD				;Read done if this is break
	TXNE	F,F$ESA				;Escape sequence active?
	  SOJA	P2,VM.RDQ			;Yes, don't count as part of string
	TLNN	P4,400000			;From TTY: service?
	TRNE	P3,NOECHO			;No (type-ahead), is this no echo?
	  TRNA					;Yes or yes, don't echo
	PUSHJ	P,OUTTTY			;Output character if no
VM.RDQ:	AOBJN	P2,VM.RDL			;Loop for all chars
VM.RDZ:	TXNE	F,F$ESA				;Is an escape still active?
	  SKIPA	P1,[PARTES]			;Flag it
VM.RDD:	MOVEI	P1,NORMAL
	TXZE	F,F$BAD				;Bad escape sequence?
	  MOVEI	P1,BADESC			;Yes
VM.RD0:	MOVE	T4,OBFPTR			;Get current output pointer
	EXCH	T4,(P)				;Get pointer to IOSB
	EXCH	T4,OBFPTR			;Force PUTWRD to put things in the right place
	MOVEI	T4,^D8+2			;Account for stuff already gone
	ADDM	T4,OBFCTR
	PUSHJ	P,PUTWRD			;Put it in
	MOVEI	P1,(P2)				;Number of characters in string
	PUSHJ	P,PUTWRD			;Put it in
	JUMPGE	P2,[SETZ  P1,
		    PUSHJ	P,PUTLWD	;Put it in
		    SKIPN	V.COUNT(P4)	;Zero character read?
		      JRST	VM.RD2		;No characters
		    LDB		T1,OBFPTR	;Get last character output
		    TXZ		F,F$CLF!F$FLF	;Clear flags
		    CAIN	T1,.CHCRT	;<CR>
		      TXO	F,F$FLF		;Yes, might need this
		    JRST	VM.RD2	     ]	;And finish up
	HLRZ	T1,BRKCHR			;Break char to T1 for echoing
	MOVEI	P1,(T1)				;Get the break character
	PUSHJ	P,PUTWRD			;Put it in
	HRRZ	P1,BRKSIZ			;Size of the break character
	ADDI	P2,(P1)				;Include in count
	PUSHJ	P,PUTWRD			;And it too
	TXNE	F,F$ESC				;Escape sequence?
	CAIG	P1,1				;Yes, was this terminated by such?
	  JRST	VM.RDW				;No
	CAIN	P1,(P2)				;Only the break?
	  JRST	VM.RD2				;Yes, don't change F$CLF
VM.RDW:	SKIPE	V.COUNT(P4)			;If count is non-zero, then
	  TXZ	F,F$FLF!F$CLF			;Clear these too
	TRNE	P3,TNOEKO!NOECHO 		;Various flavour of no-echo?
	  JRST	VM.RD2				;Yes, observe them
	CAIE	T1,.CHCNZ			;Cancel free <LF> on ^Z
	CAIN	T1,.CHCRT			; or <CR>?
	  TXO	F,F$CLF				;Cancel free line feed
	MOVE	T4,[-VBKLEN,,VBKTAB]
	PUSHJ	P,EKOBRK			;Try and echo it
VM.RD2:	MOVEI	P1,(P2)				;Total # of chars in record
	PUSHJ	P,PUTWRD			;Put it in
	POP	P,OBFPTR			;Restore old byte pointer
VM.FNR:						;Here to finish a read request
						;(^C/^Y also come here)
	TXZ	F,F$RALL!F$ESC!F$FRC		;No readall, no type-ahead echo
	TXZE	F,F$IOQ
	  PUSHJ	P,FRCTTO
	SETZM	TOFLGS				;Clear the buffer flags
	PUSHJ	P,XMTMSS			;Send the message
	MOVE	T1,V.LINK(P4)			;Get next
	HRRZM	T1,READQ			;It is now first
VM.RD3:	SKIPN	T1,V.PROM(P4)			;Deallocate any prompt block
	  JRST	VM.RD4				;None
	HLRZ	T2,T1				;Get size
	LSHC	T2,-2				;Convert to words
	TLNE	T3,600000			;Remainder?
	  AOJ	T2,
	HRRZI	T1,(T1)
	PUSHJ	P,CORFRE
VM.RD4:	MOVEI	T1,(P4)
	MOVEI	T2,VRQSIZ			;Free cor block
	PUSHJ	P,CORFRE			;Free the core block
	PUSHJ	P,VCRUR1			;Check F$RUB
	SKIPE	P4,READQ			;Is there another request ready?
	  JRST	NVRDRQ				;New VAX read request
	TXZ	F,F$READ!F$RUB			;No read request outstanding
	TXNE	F,F$UAST			;Want unsolicited?
	  PJRST	VM.SUN				;Yes
	PUSHJ	P,TTYSST			;Be sure no-echoed
	PJRST	FRCTTI				;And a look

VM.CRS:	PUSHJ	P,VMS.SC 			;Handle the special character first
	  JRST	VM.CS4				;See if still a request
	PUSHJ	P,CONSCN			;See if more characters
	  JRST	VM.CRS				;Yes, see about them
	JRST	CHKRQ2				;Continue processing
VM.CS4:	SKIPE	P4,READQ 			;Is there still a request?
	  JRST	CHKRQ1	  			;Yes
	JRST	VCRURB				;See if need to clear bits
	SUBTTL	VMS Support -- Routine to output prompt

;Routine to output a prompt string if there is one

CHKPRM:	SKIPN	T4,V.PROM(P4)			;Is there one?
	  POPJ	P,				;No
	PUSHJ	P,WATDEQ			;Wait for things to settle
	PUSH	P,TOFLGS			;Save the flags
	MOVEI	T3,($TOICL!$TOOIN)		;Form of echo
	MOVEM	T3,TOFLGS
	HLRZ	T3,T4				;Get the character count
	TXZ	F,F$ESA!F$BAD			;Cancel these
	HRLI	T4,(POINT 8,,)			;Point to string
OUTPMT:	ILDB	T1,T4				;Get character
	TXNN	F,F$ESC				;Escape processing?
	  JRST	OUTPM1				;No
	TXZ	F,F$BAD
	PUSH	P,T4				;Gotta save those Ts
	PUSH	P,T3
	PUSH	P,T1
	MOVEI	CX,OUTPM0			;In case it returns this way
	PUSHJ	P,CHKESC
	  TXO	F,F$BRK
	TRNA
OUTPM0:	POP	P,(P)				;Fix stack
	POP	P,T1
	POP	P,T3
	POP	P,T4
	TXNE	F,F$ESA!F$BRK			;Active or done?
	  JRST	NOFLF3				;Don't bother flags
OUTPM1:	TRZE	F,F$FLF				;Need to give free LF?
	CAIN	T1,.CHLFD			;Yes, is this a line feed?
	  JRST	NOFLF2				;Is <LF> or don't need
	CAIE	T1,.CHCRT			;Is it a <CR>?
	  JRST	FLFA				;No, give <CR> then
	MOVE	T2,T4				;Get byte pointer copy
CHKFLF:	ILDB	T1,T2				;Get next character
	CAIN	T1,.CHLFD			;Is it a <LF>
	  JRST	NOFLFA				;Yes, don't need one then
	CAIN	T1,.CHCRT			;Is it a <CR>?
	  JRST	CHKFLF				;Yes, scan more
FLFA:	MOVEI	T1,.CHLFD			;Get a line feed
	PUSHJ	P,OUTTTY			;Output it
NOFLFA:	LDB	T1,T4				;Get old character back
NOFLF2:	TXNN	F,F$CLF				;Cancel free line feed?
	  JRST	NOFLF3				;No
	CAIN	T1,.CHCRT			;Yes, if <CR> just toss
	  TXZA	F,F$CLF				;Set bit to zero
	CAIN	T1,.CHLFD			;If this is a line feed
	  TXCA	F,F$CLF				;Then clear bit and toss
	TXZA	F,F$CLF				;Don't cancel except in first
	  TRNA					;Proceed
NOFLF3:	PUSHJ	P,OUTTTY			;Output to TTY:
	SOJG	T3,OUTPMT			;Get next
NOPMT1:	PUSHJ	P,DOOUT1
	POP	P,TOFLGS			;Restore the flags
	TXO	F,F$IOQ				;Read is "active"
	POPJ	P,
	SUBTTL	VMS Support -- Break echo string table

VBKTAB:	.CHCRT,,[BYTE (7)15,12]		;<CR>
	.CHESC,,[ASCIZ/$/]		;<ESC>
	.CHCNZ,,[ASCIZ/^Z
/]					;^Z
	.CHTAB,,[ASCIZ/	/]		;<TAB>
	VBKLEN==.-VBKTAB
	SUBTTL VMS Support -- Routine to queue a read request for VMS

VQREAD:	SKIPE	ICHCNT				;Characters?
	  TXO	F,F$IOQ				;Yes
	TXO	F,F$READ			;Set read request active
	TLNN	P4,400000			;Clear sign bit
	  JRST	VQRD1				;Do other things
	SETZM	IMASK				;Go into character mode
	PUSHJ	P,CHKCTH			;See about ^H stuff
VQRD1:	MOVEI	T1,READQ-V.LINK			;Find the end of the queue
	HRRZI	T3,(P4)				;Right half only
FNDENV:	SKIPN	T2,V.LINK(T1)			;Is it here?
	  JRST	ENVFND				;Found it
	CAIN	T3,(T2)				;Already queued?
	  JRST	ENVFN1				;Yes, but be sure TTY: kicked
	MOVEI	T1,(T2)				;Point ahead
	JRST	FNDENV				;And look there
ENVFND:	HRRZM	T3,V.LINK(T1)			;Make this last request
ENVFN1:	CAMN	T3,READQ			;Adding first request to queue?
	  PUSHJ	P,FRCTTI			;Force TTY: if so
VQRD2:	TXNE	F,F$RALL!F$PALL!F$LEM		;Need to worry about editing?
	  JRST	VQRD3				;Nope
	PUSHJ	P,CHKLED			;Line editing to do?
	  POPJ	P,				;Wait for it to happen then
VQRD3:	TLNN	P4,400000			;From TTY: service?
	  PUSHJ	P,EKOTAH			;No, do type-ahead
	PUSHJ	P,VCRURB			;Check this stuff
	SKIPE	IMASK				;Need to call TTYSST?
	  POPJ	P,
	PUSHJ	P,TTYSST
	PJRST	FRCTTI				;Yes, do it
	SUBTTL VMS Support -- Eat and store common header

VMS.EH:	PUSHJ	P,GETWRD	;Go get a VAX word (16 bits)
	MOVE	P1,T1		;Get the word in P1
	MOVEM	P1,V.MOD(P4)	;Save
	PUSHJ	P,GETLWD	;Get a long word identifier
	MOVEM	T1,V.IDENT(P4)	;Save identifier
	PJRST	GETWRD		;get the unit number which is unimportant
				;and return With Modifiers in P1, Ident in P2

	SUBTTL	VMS Support -- Handle Control-O

VM.CTO:	PUSHJ	P,VMS.BH		;Build header
	MOVEI	P1,CONTRO		;Say what happened
	JRST	VM.AK1			;AK the message
	SUBTTL VMS Support -- VMS.KI - Kill I/O

VMS.KI:
	TLZ	F,(F$CAST!F$UAST)	;Cancel ^Cs
	SKIPN	P1,READQ		;Point to queue
	  PJRST	VM.AK2			;Nothing to do
	HRLI	P1,READQ-V.LINK		;Predecessor
VM.KIL:	MOVE	T1,V.IDENT(P4)		;Ident he wants to kill
VM.CKI:	CAMN	T1,V.IDENT(P1)		;This identifier?
	  JRST	VM.KI1
	HRLI	P1,(P1)			;Next in queue
	HRR	P1,V.LINK(P1)		;Link to next
	TRNE	P1,-1			;Any more?
	  JRST	VM.AK2			;Nope
	JRST	VM.CKI			;Check it out
VM.KI1:	MOVEI	T1,(P4)			;Get this request
	MOVEI	T2,VRQSIZ		;Free it
	PUSHJ	P,CORFRE		;...
	HRRZI	P4,(P1)			;Point P4 at block
	HRR	P1,V.LINK(P1)		;Get successor to this
	MOVSS	P1			;Predecessor,,successor
	HLRM	P1,V.LINK(P1)		;De-link from here
	HRRZ	T1,READQ		;Get the first request in the list
	HRRZM	P4,READQ		;We are now first
	HRRZM	T1,V.LINK(P4)		;First is now next
	MOVEI	P1,ABORTS		;Status
	MOVEM	P1,V.STAT(P4)		;Status to complete with
	SETOM	V.COUNT(P4)		;Flag not to complete
	PJRST	VM.RDS			;Finish it up

	SUBTTL VMS Support --  VMS.AK - Write complete and Acknowledge

VMS.AK:				;Acknowledgements
	SKIPN	V.IDENT(P4)	;Is there an identifier?
	  JRST	VM.AK2		;No, don't AK then
	PUSHJ	P,VMS.BH	;Build header
	MOVEI	P1,NORMAL	;Give good return
;Enter here with P1 header built and P1 containing the I/O status
VM.AK1:	PUSHJ	P,PUTLWD
	SETZ	P1,		;Zap high order
	PUSHJ	P,PUTLWD	;Put it in
	PUSHJ	P,XMTMSS	;Send completion with no data
VM.AK2:	MOVEI	T1,(P4)		;Free the core block for the request
	MOVEI	T2,VRQSIZ
	PJRST	CORFRE		;Do it
	SUBTTL VMS Support -- VMS.BH - Build Header

VMS.BH:	SKIPN	V.IDENT(P4)	;Get identifier (already shifted)
	 POPJ	P,		;Return
	MOVX	P1,<BYTE (8) 0,0,377,VR.END> ;MOD,MOD,OP,OP
	ROT	P1,-4		;Use the lower 4 bits
	PUSHJ	P,PUTLWD	;Put long word into buffer
	MOVE	P1,V.IDENT(P4)	;Get the identifier
	SKIPGE	P1		;Do we have one for real?
	 SETZ	P1,		;No, then store a zero
	PUSHJ	P,PUTLWD	;Put long word in buffer
	SETZ	P1,		;No unit
	PJRST	PUTWRD		;Put it in and exit

	SUBTTL VMS Support -- VMS.IN - Initialization message

VMS.IN:	TXZ	F,F$READ	;No outstanding read yet
	TXO	F,F$NLF!F$UAST	;Don't want <LF>s on <CR>s
	SETZM	UNSCNT		;We are going to send an unsolicited message
	SKIPGE	T1,TTYTYP	;Get the type
	SKIPA	T4,[DT$TTY]	;Set TTY: then
	HRRZ	T4,VTPTB(T1)
	DPB	T4,[POINT 8,VMS$CF+3,^D15]	;Set the type
	DPB	T4,[POINT 8,VMTTCH,^D35-8]
	MOVEI	T2,20		;Number of characters in pre-V3
	SKIPN	PROTMD		;If non-zero, V3 or later
	  JRST	VM.IN0		;Don't do V3 stuff
	MOVEI	T2,24		;Size of characteristics in V3
	JUMPL	T1,VM.IN0	;TTY
	HLRZ	T3,VTPTB(T1)	;Get the DEC/ANSI CRT characteristics
	ASSUME	T2ACRT,100000000
	ASSUME	T2DCRT,4000000000
	DPB	T3,[POINT 8,VMS$CF+5,^D31]
	DPB	T3,[POINT 8,VMTTCH+2,^D35-<3*8>]
VM.IN0:	MOVEM	T2,VMS$CF
	HLRZ	T1,TSVWID	;Get the width
	DPB	T1,[POINT 16,VMTTCH,^D35-^D16]
	DPB	T1,[POINT 8,VMS$CF+3,23]
	ROT	T1,-8		;High order
	DPB	T1,[POINT 8,VMS$CF+3,31]
	HLRZ	T1,TSVLNB	;Get page size
	DPB	T1,[POINT 8,VMTTCH+1,^D35-^D24]
	DPB	T1,[POINT 8,VMS$CF+4,31]
	HLRZ	T1,TSVDIS	;Get the display bit
	DPB	T1,[POINT 1,VMS$CF+4,<^D35-^L<TSCOP>>/8*8+7-<<^D35-^L<TSCOP>>-<<^D35-^L<TSCOP>>/8*8>>]
	LSH	T1,<^D35-^L<TSCOP>>
	IORM	T1,VMTTCH+1	;Set that here
	HLRZ	T1,TSVNFC		;Free <CR> bit
	TRC	T1,1			;Convert to WRAP bit
	DPB	T1,[POINT 1,VMS$CF+4,<^D35-^L<TWRAP>>/8*8+7-<<^D35-^L<TWRAP>>-<<^D35-^L<TWRAP>>/8*8>>]
	LSH	T1,<^D35-^L<TWRAP>>
	IORM	T1,VMTTCH+1		;Set it in characteristics
	HLRZ	T1,TSVXNF		;XON/XOFF
	DPB	T1,[POINT 1,VMS$CF+4,<^D25-^L<TTSYN>>/8*8+7-<<^D35-^L<TTSYN>>-<<^D35-^L<TTSYN>>/8*8>>]
	LSH	T1,<^D35-^L<TTSYN>>
	IORM	T1,VMTTCH+1
VM.IN1:	MOVEI	T1,VMS$CF	;Return config
	PUSHJ	P,XMTMSG	;
	MOVEI	T1,VMS$UN	;Get unsolicited data message
	PUSHJ	P,XMTMSG	;Send it
	MOVE	T1,[VXDMSK,,IMASK]	;Set the terminal mask
	BLT	T1,ENDMSK		;Set it
	MOVE	T1,[VXDMSK+1,,LMASK]	;Also set logical mask
	BLT	T1,ELMASK
	MOVE	T1,[7,,TRMBKS]
	TRMOP.	T1,
	  JFCL
	PUSHJ	P,TTYSST		;Set TTY: up
	PJRST	FRCTTI
	SUBTTL	VMS Support -- VM.STM - timed requests

;This routine is called if the request is timed.
;QIO block pointed to by P4.

VM.STM:	MOVEI	T1,VM.TMR		;Be sure timer trap is set
	MOVEM	T1,OSTMR		;to go to the right place
	MOVE	T1,V.IDENT(P4)		;Get the identifier
	MOVEM	T1,TMRSEQ		;Make it the sequence identifier
	MOVE	T1,V.TIME(P4)		;Get time request
	PITMR.	T1,
	  JFCL				;Oh well
	POPJ	P,


;VMS routine to actually handle the timer trap

VM.TMR:	SKIPN	P4,READQ		;Point to queue
	  POPJ	P,			;No entry
	MOVE	T1,V.IDENT(P4)		;Get the sequence number
	CAME	T1,TMRSEQ		;Right sequence number?
	  POPJ	P,			;Wrong request
	MOVE	T1,[2,,T2]		;Find how many chars are in the chunks
	MOVEI	T2,.TOTTC
	MOVE	T3,TTYUDX
	TRMOP.	T1,
	  PJRST	VM.RDS			;Oh well
	JUMPE	T1,VM.RDS		;If none pending
	MOVEM	T1,IMASK		;Set that many
	MOVEI	T1,TIMEOUT		;Set status
	MOVEM	T1,V.STAT(P4)		;Status for read
	TXO	F,F$FRC!F$TEX		;Force call to TTYSST
	PUSHJ	P,FRCTTI		;Force wakeup
	PJRST	TTYSST			;Set TTY: up and return
	SUBTTL VMS Support -- Set TTY: up for this read

VM.STT:	TXZ	F,<F$NEC!F$PIM!F$LEM>	;Clear some bits
	MOVE	T1,V.MOD(P4)		;Get modifiers
	MOVEI	CX,TNEKO		;Check perm chars too
	TDNN	CX,VMTTCH+1		;?
	TRNE	T1,NOECHO		;Or program requested?
	  TLOA	F,(F$NEC)		;Flag to TTY: service
	TRNA				;Don't do anything
	  TRO	T1,NOECHO		;Make it say so in request
	MOVEM	T1,V.MOD(P4)		;Store for when request complete
	ASSUME	CVTLOW,F$CVL
	XOR	T1,F			;Get the CVTLOW bit
	HLRZ	T2,TSVLCT		;Get saved lower case ability
	JUMPN	T2,VM.SMK		;If TTY: already upper case, no problem
	TRNN	T1,CVTLOW		;Is it on now?
	  JRST	VM.SMK			;No, no change
	TRCE	F,F$CVL			;Is it set in F?
	TDZA	T3,T3			;Yes, must want to set to upper case
	SETO	T3,			;If F was zero must want to clear upper case
	MOVE	T2,TTYUDX
	MOVEI	T1,.TOLCT+.TOSET
	MOVE	CX,[3,,T1]
	TRMOP.	CX,			;Do the right thing
	  JFCL
VM.SMK:	HRRZ	CX,V.COUNT(P4)		;Get maximum size
	MOVEM	CX,IMASK		;Set size of field
	SKIPN	V.MASK(P4)		;Mask specified?
	SKIPA	CX,[VXDMSK+1,,]		;Set default mask
	HRLI	CX,V.MASK+1(P4)		;Set it
	HRRI	CX,IMASK+1
	BLT	CX,ENDMSK		;Set the mask
	MOVE	CX,[IMASK+1,,LMASK]	;Set the "local" mask to this too
	BLT	CX,ELMASK		;To the end
	MOVX	T1,<1B<.CHCNH>>		;Must always see ^H
	IORM	T1,IMASK+1
	TXNE	F,F$PALL		;If passall, then stop here
	  JRST	VM.NRX			;Set it up
	ASSUME	VM.RAL,<1B0>		;This must be true
	SKIPGE	V.MOD(P4)		;If READALL bit is set
	TROA	F,F$RALL		;Set readall bit
	TXZA	F,F$RALL		;Set readall
	  PJRST	VM.NRX			;Set TTY: up
VM.NRA:	MOVE	T1,OBMASK		;Get the out of band mask
	IORM	T1,IMASK+1
	MOVE	T1,OBMASK+1		;Both include and exclude
	IORM	T1,IMASK+1
	SETZ	T1,			;Initialize
	TLNE	F,(F$CAST)		;Want ^C?
	TXO	T1,<<1B<.CHCNC>>>	;Yes
	TLNE	F,(F$YAST)		;Want ^Y?
	TXO	T1,<<1B<.CHCNC>>!<1B<.CHCNY>>>
	MOVE	T2,V.MOD(P4)		;Get modifiers
	MOVEI	CX,<1B31>		;Default not NFILTR
	TRNE	T2,NFILTR		;No filter?
	  JRST	VM.NR1			;Proceed
	TXO	F,F$RUB			;In case any snuck in
	PUSHJ	P,VM.SCT		;Set up CHRTAB (must be after setting F$RUB)
	  JFCL				;? Shouldn't get here
	ANDCAM	CX,LMASK+3		;Clear rubout in appropriate places
	ANDCAM	CX,IMASK+1+3
	MOVX	CX,<<1B<.CHCNR>>!<1B<.CHCNU>>!<1B<.CHCNX>>>
	ANDCAM	CX,LMASK		;These too
	TXZ	CX,<1B<.CHCNX>>		;We must handle ^X
	ANDCM	CX,OBMASK
	ANDCM	CX,OBMASK+1
	ANDCAM	CX,IMASK+1
	IORM	T1,IMASK+1		;Set special bits too
VM.NRX:	PUSHJ	P,TTYSST		;Do it
	PJRST	FRCTTI

VM.NR1:	TXO	F,F$LEM			;Set LEM
	PUSHJ	P,VM.SCT		;Set up CHRTAB
	  JFCL				;? Shouldn't get here
	TXO	T1,<<1B<.CHCNR>>!<1B<.CHCNU>>!<1B<.CHCNX>>>
	MOVEI	CX,<1B31>		;Also set rubout
	IORM	CX,IMASK+1+3
	IORM	T1,IMASK+1		;Set appropriate bits
	SKIPE	V.MASK(P4)		;Using default mask?
	  JRST	VM.NRX			;No, change TTY:
	IORM	T1,LMASK		;Default bits change
	IORM	CX,LMASK+3		;..
	PUSHJ	P,TTYSST
	PJRST	FRCTTI
	SUBTTL	VMS Support -- Set Unsolicited mode

;This routine sets the break mask for unsolicited input

VM.SUN:	SAVE1
	TXO	F,F$UAST		;Say we want it
	SKIPE	READQ			;Is there a read request?
	  POPJ	P,			;No
	SETZM	IMASK			;TTYSST will set it to 1
	SETOM	IMASK+1			;Break on all characters
	MOVE	P1,[IMASK+1,,IMASK+2]	;Set the whole mask
	BLT	P1,ENDMSK		;Set it
	PUSHJ	P,TTYSST
	PJRST	FRCTTI			;Set up and return
	SUBTTL	VMS Support -- Set CHRTAB

;This routine is to set up CHRTAB

VM.SCT:	PUSHJ	P,SAVT			;Save the Ts
	TXNE	F,F$PALL!F$RALL		;If in a flavour of passall
	  POPJ	P,			;Don't diddle CHRTAB
	MOVX	T1,<1B<.CHCNO>>		;Set control-O normal
	TXNN	F,F$LEM			;Editor?
	   TXO	T1,<1B<.CHCNX>>		;No, set ^X
	MOVE	T4,VMTTCH+1		;Get characters
	TXNE	T4,TTSYN		;Paged mode?
	  TXO	T1,<1B<.CHCNS>!1B<.CHCNQ>> ;Yes, we must handle these if they come in
	MOVEI	T4,1B19			;Assume don't have to do rubouts
	ANDCAM	T4,CHRTAB+3		;..
	TXNE	F,F$RUB			;Do I have to do rubouts etc.?
	TXNE	F,F$LEM			;Only if not this
	  JRST	VM.NRU			;No
	TXO	T1,<1B<.CHCNR>!1B<.CHCNU>>
	IORM	T4,CHRTAB+3		;..
VM.NRU:	TXNE	F,<F$CAST>		;Want ^C?
	TXO	T1,1B<.CHCNC>		;Yes
	TXNE	F,<F$YAST>		;And if wants ^Y
	TXO	T1,<1B<.CHCNC>!1B<.CHCNY>>
	MOVEM	T1,CHRTAB		;Set special characters
	JRST	CPOPJ1			;We changed it
	SUBTTL	VMS Support -- Handle special characters

;This routine handles ^C, ^Y, and the escape character for VMS

VMS.SC:	CAME	P1,ESCCHR		;Is it the break character?
	  JRST	VM.NBK			;No
	PUSHJ	P,MONITO		;Yes, go get response
	  JRST	[PUSHJ	P,SPCRMV	;Remove
		 PJRST	VCRURB	]	;See if have to do this
	AOS	BRKNUM			;One more break
	PJRST	VCRURB			;Set processing and return
VM.NBK:	CAIN	P1,.CHCNO		;Control-O?
	  JRST	VM.SCO			;Yes, set it
	CAIN	P1,.CHCNX		;^X?
	  JRST	VM.SCX			;Yes, handle it
	CAIE	P1,.CHCNQ		;^Q?
	CAIN	P1,.CHCNS		;or ^S?
	  JRST	VM.SCQ			;Yes, handle them
	CAIE	P1,.CHCNC		;Control-C?
	  JRST	VM.NCC			;No
	MOVSI	T4,(1B<.CHCNC>)		;One time-AST only
	ANDCAM	T4,CHRTAB		;So isn't special any more
	TDNN	T4,LMASK		;Want to see ^C as break?
	 ANDCAM	T4,IMASK+1		;No, clear in IMASK
	TLZN	F,(F$CAST)		;User want ^C?
	  JRST	VM.SCY			;No, send ^Y then
	PUSH	P,[RA.CTC,,CONTRC]	;Abort reason and ^C attention
	MOVEI	T4,[ASCIZ/
^C
/]
	JRST	VM.CYC			;Send attention interrupt

VM.NCC:	CAIE	P1,.CHCNY		;Control-Y?
	  JRST	VM.LED			;See about line editing stuff

VM.SCY:	MOVEI	T4,1B<.CHCNY>		;^Y is one-time also
	ANDCAM	T4,CHRTAB
	TDNN	T4,LMASK		;Does he want ^Y as break
	 ANDCAM	T4,IMASK+1		;No
	TLZN	F,(F$YAST)		;Want ^Y?
	  POPJ	P,			;Return
	PUSH	P,[RA.CTY,,CONTRY]	;Control-Y abort and attention
	MOVEI	T4,[ASCIZ/
^Y
/]
VM.CYC:	PUSHJ	P,CLRTOQ		;Flush the output queue
	PUSHJ	P,STROUT		;Output echo
	PUSHJ	P,DOOUT1		;Force it out
	PUSHJ	P,SPCFLS		;Flush input
	HLRZ	T1,(P)
	PUSHJ	P,VMS.AT		;Send attention message too
	SKIPN	P4,READQ		;Anything in input queue?
	  JRST	TPOPJ			;Fix stack and return
	PUSHJ	P,VMS.BH		;Build header for it
	HRRZ	P1,(P)			;Get abort reason
	PUSHJ	P,PUTLWD		;Put the word in
	SETZ	P1,
	PUSHJ	P,PUTLWD		;Zap I/O status
	NETOCH	P1
	POP	P,(P)			;Attention reason
	PJRST	VM.FNR			;Read request finished

;Here on control-O

VM.SCO:	TXZ	F,F$ICO			;Don't ignore monitor any more
	PUSHJ	P,SPCRMV		;Eat the ^O
	PUSHJ	P,VCRURB		;Set special processing
	TXCN	F,F$CTO			;Complement the bit
	  PUSHJ	P,CLRTOQ		;Clear the TO queue
	PUSH	P,TOFLGS		;Save the flags
	MOVEI	T4,($TOOIN!$TOICL)
	MOVEM	T4,TOFLGS
	MOVEI	T4,[ASCIZ/^O
/]
	PUSHJ	P,STROUT		;Output
	PUSHJ	P,DOOUT1		;Force out
	POP	P,TOFLGS
	TXNN	F,F$CTO			;Did we set it?
	  PJRST	CLRCTO			;Inform the monitor
	PUSHJ	P,WATOUT		;Wait for string to get there
	PJRST	SETCTO			;Inform the monitor too

VM.SCX:	PUSHJ	P,SPCFLS		;Eat all type-ahead
	SKIPN	READQ
	  POPJ	P,			;Return if no outstanding read
	MOVEI	T1,($TOOIN!$TOICL)
	MOVEM	T1,TOFLGS
	MOVEI	T4,[ASCIZ/^U
/]					;Say what we did
	PUSHJ	P,STROUT
	PUSHJ	P,DOOUT1
	SETZM	TOFLGS
	POPJ	P,

;Here on ^S/^Q

VM.SCQ:	MOVE	T1,[3,,T2]		;Change the bit
	MOVEI	T2,.TOSET+.TOSTP	;The output bit
	MOVE	T3,TTYUDX
	CAIE	P1,.CHCNS		;^S?
	  TDZA	T4,T4			;No, ^Q, clear
	MOVEI	T4,1
	TRMOP.	T1,
	  JFCL
	PJRST	SPCRMV			;Toss character and return

;Here to see about line editing stuff

VM.LED:	PUSHJ	P,SCNPOS		;Get position of scan
	SKIPN	T2,READQ		;Get read request
	  JRST	CPOPJ1			;None?
	CAMG	T1,V.COUNT(T2)		;Satisfy already?
	TXNE	F,F$BRK			;Break seen already?
	  JRST	CPOPJ1			;Yeah, do this later
VM.LD1:	CAIN	P1,.CHCNU		;Control-U?
	  JRST	VM.SCU			;Do it also
	CAIN	P1,.CHDEL		;Rubout?
	  JRST	VM.RUB			;Yes
	CAIE	P1,.CHCNR		;Control-R?
	  JRST	CPOPJ1			;Ignore it, I guess

;Here to process ^R

VM.SCR:	MOVEI	T1,VM.CTR		;Routine to call
	PUSHJ	P,DOCTR			;Handle the ^R
	JRST	VCRURB			;Check flag

VM.CTR:	SAVE4				;Save the Ps
VM.CUR:	SKIPN	P4,READQ		;Get current request, if any
	  POPJ	P,			;None
	TXO	F,F$CLF			;Cancel a line feed
	TXZ	F,F$FLF			;None
	PJRST	CHKPRM			;See if need it

;Here to process ^U

VM.SCU:	PUSHJ	P,DOCTU			;Handle ^U
	PUSHJ	P,VM.CUR		;See if prompt
	JRST	VURURB			;Turn off bits

;Here to process rubout

VM.RUB:	PUSHJ	P,DORUB			;Do the rubout
	JRST	VCRURB			;Check flag
	SUBTTL VMS Support -- VMS.AT - Send Attention 

VMS.AT:	MOVEI	P1,VR.ATT		;Get Attention header
	PUSHJ	P,PUTWRD		;Put it in
	MOVEI	P1,(T1)			;Get attention reason
	PUSHJ	P,PUTWRD
	PJRST	XMTMSS			;Send the message
	SUBTTL	VMS Support -- VMS.ST - Set characteristics/mode

VMS.ST:				;'Set Mode' message
	MOVE	T1,V.MOD(P4)	;Get the modifier
	MOVX	T2,<1B<.CHCNC>>	;Mask for ^C special
	TRNE	T1,CC		;Want ^C AST?
	  TLOA	F,(F$CAST)	;Yes, set flag
	JRST	VM.CCY		;Check ^Y

	IORM	T2,CHRTAB+<.CHCNC/36.> ;Set ^C bit
	MOVX	T2,<1B<.CHCNY>!1B<.CHCNC>>	;The bits
	PJRST	VMS.AK

VM.CCY:	TRNN	T1,CY		;Want ^Y AST?
	  JRST	VM.COB		;check out of band stuff then
	TLO	F,(F$YAST)	;Yes
	IORM	T2,CHRTAB+<.CHCNY/36.>	;Set ^Y bit
	PJRST	VMS.AK

VM.COB:	SKIPE	PROTMD		;V3+ protocol?
	TRNN	T1,OBAND	;Want out-of-band AST?
	  JRST	VM.STC		;No
	SETO	P3,		;Do this twice
	MOVE	T3,[POINT 8,P1,]
	SETZB	P1,P2		;No bits in mask yet
VM.CB1:	PUSHJ	P,NETICH	;Get character from network
	  PJRST	VMS.AK		;Done if none
	MOVEI	T4,4		;Four times each time
	PUSHJ	P,CPYMSK	;Copy the mask
	AOJE	P3,VM.CB1
	IORM	P1,IMASK+1
	IORM	P2,IMASK+1	;Both of them
	DMOVEM	P1,OBMASK	;Save the masks
	IOR	P1,P2		;See if ^O is in mask
	TXNE	P1,1B<.CHCNO>	;?
	  TXOA	F,F$ACO		;Allow it in mask if so
	TXZ	F,F$ACO		;Not allowed any more
	IORM	P1,IMASK+1	;If any significant changes
	PUSHJ	P,TTYSST	;(just in case)
	MOVE	T1,V.MOD(P4)	;Get modifier
	PJRST	VMS.AK

VM.STC:	TRNE	T1,777700	;Any modifiers?
	  PJRST	VMS.UM		;Unsupported modifier if so
	PUSHJ	P,GETLWD	;Get first word of chars
	EXCH	T1,VMTTCH	;Store it, get old
	XOR	T1,VMTTCH	;Get differences
	TRNN	T1,377B<^D35-^D8>;Type change?
	  JRST	VM.ST0		;No
	LDB	T1,[POINT 8,VMTTCH,^D35-^D8]	;Get the type
	MOVSI	T2,-TTPLEN
VM.STL:	HRRZ	T3,VTPTB(T2)
	CAIE	T1,(T3)		;This one?
	AOBJN	T2,VM.STL	;No
	JUMPGE	T2,VM.ST0	;Can't find it
	HRRZM	T2,TTYTYP	;Save it
	MOVE	T4,TTPTB(T2)	;Get TOPS-10 type
	MOVE	T3,TTYUDX
	MOVEI	T2,.TOTRM+.TOSET
	MOVE	T1,[3,,T2]
	TRMOP.	T1,
	  JFCL
VM.ST0:	PUSHJ	P,GETLWD	;Get second word
	TRNN	T1,TPSAL	;Check passall
	TXZA	F,F$PALL
	TXO	F,F$PALL	;Set or clear as appropriate
	EXCH	T1,VMTTCH+1	;Save it too
	XOR	T1,VMTTCH+1	;Get changes
	MOVE	CX,[3,,T2]
	MOVE	T3,TTYUDX	;Who to change
	MOVX	T2,TWRAP	;Get the wrap bit
	TDNN	T1,T2		;Did it change?
	  JRST	VM.ST1		;No
	TDNE	T2,VMTTCH+1	;On or off?
	  TDZA	T4,T4		;Off
	SETO	T4,		;On
	MOVEI	T2,.TONFC+.TOSET
	TRMOP.	CX,		;Do it
	  JFCL
VM.ST1:	MOVX	T2,TTSYN	;Paged mode?
	TDNN	T1,T2		;Change?
	  JRST	VM.ST2		;No
	TDNN	T2,VMTTCH+1	;On or off now?
	  TDZA	T4,T4		;Off
	SETO	T4,
	MOVEI	T2,.TOSET+.TOXNF
	MOVE	CX,[3,,T2]	;Set as appropriate
	TRMOP.	CX,
	  JFCL
VM.ST2:	SKIPN	PROTMD		;Version 3 or later protocol?
	  PJRST	VMS.AK		;Write the data to the VAX
	PUSHJ	P,GETLWD	;Version 3, eat speed, fill, and parity
	PUSHJ	P,GETLWD
	PUSHJ	P,GETLWD
	PUSHJ	P,GETLWD	;And get second characteristics word
	MOVEM	T1,VMTTCH+2	;Save them away too
	CALLRE	VMS.AK		;AK the message
	SUBTTL VMS Support -- VMS.NI - Unsolicited Data Message

VMS.UN:	TXNE	F,F$UAST	;Want message?
	AOSE	UNSCNT		;Send unsolicited message?
	  POPJ	P,
	MOVEI	T1,VMS$UN	;Tell host about unsolicited data
	PJRST	XMTMSG		;

	SUBTTL	VMS Support -- Checkout-of-band character

;Scan input for out-of-band character.  If found, then
;return CPOPJ with character.  If not found, return CPOPJ1

VM.CHO:	SKIPN	P4,INPQUE		;Get any input
	  JRST	CPOPJ1			;None
VM.CHA:	SKIPG	IBF.LK(P4)		;Another buffer?
	  JRST	VM.CHC			;No, done
	HRRZ	P4,IBF.LK(P4)		;Point to next
	JRST	VM.CHA

VM.CHC:	MOVE	P3,IBF.CT(P4)		;Get count
	MOVE	P2,IBF.PT(P4)		;And pointer
VM.CH1:	PUSHJ	P,SCNCHR		;Any?
	  JRST	CPOPJ1			;None
	CAIL	P1," "			;Must be a control character
	  JRST	VM.CH1			;No
	MOVEI	T1,(P1)
	IDIVI	T1,^D32		;Get bit numer
	MOVSI	T1,400000	;Get bit 0
	MOVNS	T2		;Negate the remainder
	LSH	T1,(T2)		;Compute mask
	TDNN	T1,OBMASK	;In include mask?
	TDNE	T1,OBMASK+1	;In exclude mask?
	  TRNA			;In one of them
	JRST	VM.CH1		;Check next character
	TDNE	T1,OBMASK	;In include mask?
	  JRST	VCRURB		;Yes
	PUSH	P,P1		;Save character
	PUSHJ	P,SPCRMV	;Remove the character now
	POP	P,P1		;Restore the character
	CAMN	P1,BRKCHR	;Escape character?
	  SOS	BRKCNT		;Yes
	FALL	VCRURB		;Check ^R, ^U, <RUB>
				;Fall into below
	SUBTTL	VMS Support -- Check ^R, ^U, and <RUB>

;This routine checks to see if we must do processing for ^R, ^U, or <RUB>
;and sets bits appropriately

VCRURB:	TDZA	T3,T3				;Flag to set
VCRUR1:	SETO	T3,				;Don't set
	TXNN	F,F$READ			;Read pending?
	  PJRST	VURURB				;No
	SKIPE	ICHCNT				;Any characters in input?
	TXNE	F,F$PALL			;Yes, passall?
	  PJRST	VURURB				;Clear if need to
	SKIPN	T1,READQ
	  PJRST	VCRUR2				;Set stuff, no request active
	MOVX	T2,VM.RAL!NFILTR
	TDNN	T2,V.MOD(T1)			;??
VCRUR2:	JUMPE	T3,STRURB			;Set
	POPJ	P,

VURURB:	MOVE	T3,VXDMSK			;Use default if no request
	SKIPE	T1,READQ			;Current request
	  SKIPA	T3,V.COUNT(T1)			;Get count from there then
	JRST	VCKPAL				;Check passall only
	HRL	T1,V.MOD(T1)			;Get modifiers
	TLNN	T1,NFILTR			;This no-filter?
VCKPAL:	TXNE	F,F$PALL			;Passall?
	  JRST	UNRURB				;Conditional based on mask
	JUMPE	T1,UNRALL			;Always if no request
	TXNN	F,F$RALL			;Read-all check if a request
	  JRST	UNRALL				;Always then
	JRST	UNRURB				;Else conditional
	SUBTTL	VMS Support -- Out-of-band ATTN

VMS.OB:	PUSH	P,P1		;Save character
	MOVEI	P1,VR.ATT	;Get attention reason
	PUSHJ	P,PUTWRD	;set it
	MOVEI	P1,RA.OUB	;Modifier
	PUSHJ	P,PUTWRD	;Also there
	SETZ	P1,
	PUSHJ	P,PUTLWD	;Longword
	PUSHJ	P,PUTWRD
	POP	P,P1
	NETOCH	P1		;Put character in
	PJRST	XMTMSS		;Send the message
	SUBTTL	VMS Support -- VMS.BC - Broadcast data

VMS.BC:	PUSHJ	P,GETLWD	;Get count
	SKIPN	P3,T1		;Copy to P1 if any
	  JRST	VMS.AK		;ACK it if no data
	SKIPN	V.IDENT(P4)	;If no identifier
	  JRST	VM.BNA		;Then just don't ACK this
	PUSHJ	P,VMS.BH	;ACK the req but don't return the block
	MOVEI	P1,NORMAL
	PUSHJ	P,PUTLWD
	SETZ	P1,
	PUSHJ	P,PUTLWD
	PUSHJ	P,XMTMSS	;Send the ACK
VM.BNA:	PUSHJ	P,GETLWD	;Get junk long-word
	PUSH	P,TOFLGS	;Save current flags
	MOVEI	P1,($TOOIN)
	MOVEM	P1,TOFLGS
	PUSH	P,F		;Save F
	PUSH	P,IMASK+1
	DMOVE	T3,VMTTCH+1	;Get characteristics
	TRNN	T3,TNBCS	;No mailbox, is no broadcast set?
	TXNE	F,F$CTO		;Or is ^O in effect?
	  JRST	[TRNE T4,T2BCM	;Is there a mailbox?
		  JRST	VM.BNB	;Yes
		 JRST	VM.BXD ];No
	SKIPN	T1,READQ	;Is there a current read request?
	  JRST	VM.BNZ		;No
	SKIPE	V.PROM(T1)	;Prompt string?
	  JRST	[TXO	F,F$FLF	;Yes, set FLF
		 JRST	VM.BNZ ];Continue
	TXZ	F,F$FLF!F$CLF	;Clear flags
	TXNE	F,F$NEC		;No-echoed?
	  JRST	VM.BNZ		;Yes
	PUSHJ	P,SETICH	;Set counts
	SKIPE	ICHCNT		;Any characters there?
	  TXOA	F,F$FLF		;Yes, flag a line feed
	TXO	F,F$CLF		;No characters, any line feed taken care of
;The above is not quite accurate.
VM.BNZ:	TRNN	T4,T2BCM	;Is there also a mailbox?
	  JRST	VM.BCL		;No

VM.BNB:	SETO	P1,
	PUSHJ	P,PUTWRD	;Attention request
	MOVEI	P1,5		;Completion op code
	PUSHJ	P,PUTWRD	;...
	SETZ	P1,		;ID (should be ignored
	PUSHJ	P,PUTLWD
	PUSHJ	P,PUTWRD	;Unit
	MOVEI	P1,^D22(P3)	;Remaining data size
	PUSHJ	P,PUTWRD
	MOVEI	P1,MTMBRD	;Code
	SETZ	P1,		;Just to look nice
	PUSHJ	P,PUTWRD
	PUSHJ	P,PUTWRD	;BRDUNIT
	PUSHJ	P,PUTLWD	;BRDNAME
	PUSHJ	P,PUTLWD
	PUSHJ	P,PUTLWD
	PUSHJ	P,PUTLWD
	MOVEI	P1,(P3)		;Text size
	PUSHJ	P,PUTWRD
VM.BCL:	PUSHJ	P,RBYTEC	;Get a byte
	TRNE	T4,T2BCM	;Mailbox?
	 NETOCH	T1		;Ship to network
	TXNN	F,F$CTO		;Control-O?
	TRNE	T3,TNBCS	;No broadcast?
	  JRST	VM.BX3		;Skip all this then
	TXNN	F,F$FLF		;Supposed to be free line feed?
	  JRST	VM.BX1		;No
	CAIN	T1,.CHLFD	;Is this a line feed?
	  TXZA	F,F$FLF		;Yes, clear it
	CAIGE	T1," "		;Printing character?
	  JRST	VM.BX1		;No
	PUSH	P,T1
	MOVEI	T1,.CHLFD	;Output the <LF>
	PUSHJ	P,OUTTTY
	POP	P,T1
	TXZ	F,F$FLF		;Don't do it any more
VM.BX1:	TXNE	F,F$CLF		;Cancel line feed?
	CAIN	T1,.CHLFD	;Yes, is this a line feed?
	  TXZN	F,F$CLF		;Yes, clear
VM.BX2:	PUSHJ	P,OUTTTY	;Output to TTY:
VM.BX3:	SOJG	P3,VM.BCL	;For all bytes
	CAIN	T1,.CHCRT	;Last character a <CR>?
	  TXO	F,F$FLF		;Yes
	TXZ	F,F$CLF		;Don't cancel any more line feeds
	TRNE	T4,T2BCM	;Mailbox?
	  PUSHJ	P,XMTMSS	;Send mailbox message now
VM.BXD:	MOVEI	T1,(P4)		;Point to request block
	MOVEI	T2,VRQSIZ
	PUSHJ	P,CORFRE	;Free the block
	TXNN	F,F$CTO		;^O?
	TRNE	T3,TNBCS	;Nobroadcast?
	  JRST	VM.BC8		;Return
	SKIPN	P4,READQ	;Anything in queue?
	  JRST	VM.BC9
	MOVX	T1,VM.RAL
	TDNE	T1,V.MOD(P4)	;Any of the physical stuff?
	  TXZ	F,F$FLF		;Yes
	PUSHJ	P,CHKPRM	;Output prompt it any
	SETZ	P3,		;Clear who we're remembering
	MOVX	T1,F$NEC	;Are we supposed to be noechoed?
	TDNE	T1,-1(P)	;?
	  JRST	VM.BC8		;Yes
	SKIPN	P4,INPQUE
	  JRST	VM.BC5		;Just do FRCUUO
VM.BC0:	SKIPG	IBF.LK(P4)
	  JRST	VM.BC1
	HRRZ	P4,IBF.LK(P4)
	SKIPLE	IBF.CT(P4)	;Is this one real?
	  HRRZI	P3,(P4)		;Yes, remember it
	JRST	VM.BC0
VM.BC1:	SKIPG	IBF.CT(P4)	;If this has a real count then it's the one
	  MOVEI	P4,(P3)		;Else this is the one
	JUMPE	P4,VM.BC5	;Nothing, just do frcuuo

	MOVE	P2,IBF.PT(P4)	;Pointer
	SKIPN	P3,IBF.CT(P4)	;Get count
	  JRST	VM.BC4		;It's zero
	IBP	P2		;Force normalization
	SOJE	P3,VM.BC4	;If just one byte
	EXCH	P2,P3		;Set up for ADJBP
	ADJBP	P2,P3
VM.BC4:
	PUSH	P,P2
	PUSHJ	P,SCNLBK	;Point to last character before
VM.BC2:	PUSHJ	P,SCNCHR
	  JRST	VM.BC3
	TXNE	F,F$FLF		;Need free line feed?
	CAIN	P1,.CHLFD	;This a line feed?
	  JRST	VM.BC6		;Proceed
	MOVEI	T1,.CHLFD	;Output a line feed
	PUSHJ	P,OUTTTY	;Output
VM.BC6:
	TXZ	F,F$FLF
	MOVEI	T1,(P1)
	PUSHJ	P,OUTTTY
	CAME	P2,(P)
	  JRST	VM.BC2
VM.BC3:
	POP	P,(P)			;Clear junk
VM.BC5:	TXZN	F,F$FLF			;Still need?
	  JRST	VM.BC7			;No
	TXO	F,F$CLF			;Say we gave one
	TXNE	F,F$NEC			;Currently noechoed?
	  JRST	VM.BC7			;Yes, no line feed
	MOVEI	T1,.CHLFD		;Output one
	PUSHJ	P,OUTTTY
VM.BC7:	PUSHJ	P,DOOUT1
	PUSHJ	P,DOFRCU		;Do a FRCUUO
VM.BC8:	POP	P,T2			;Restore old value for next time
	POP	P,T1
	POP	P,TOFLGS		;Restore output flags
	TXNN	T1,F$NEC
	  TXZ	F,F$NEC			;Clear no-echo
	PUSHJ	P,TTYSST
	MOVEM	T2,IMASK+1
	TXZ	F,F$ACO
	POPJ	P,

VM.BC9:	PUSHJ	P,DOOUT1
	PJRST	VM.BC8
	SUBTTL VMS Support -- VMS.SN - Sense Mode message

VMS.SN:					;'Sense Mode' message received
	MOVE	T1,V.MOD(P4)		;Get the modifiers
	TRNE	T1,TYPAHD		;Want typeahead count?
	  JRST	VMS.TA			;Yes
	TRNE	T1,MODEM		;Want modem status
	  JRST	VM.NMD			;Yes, sense modem
	PUSHJ	P,VMS.BH		;Build the usual header
	MOVEI	P1,NORMAL
	PUSHJ	P,PUTWRD
	SETZ	P1,			;**TEMP
	PUSHJ	P,PUTWRD
	PUSHJ	P,PUTLWD
	MOVE	P1,VMTTCH		;Get first word of characteristics
	PUSHJ	P,PUTLWD
	MOVE	P1,VMTTCH+1
	PUSHJ	P,PUTLWD
	SKIPN	PROTMD			;Version 3 protocol?
	  JRST	VM.SN1			;No
	MOVE	P1,VMTTCH+2		;Get char 2
	PUSHJ	P,PUTLWD
VM.SN1:	PUSHJ	P,XMTMSS
	MOVEI	T1,(P4)
	MOVEI	T2,VRQSIZ
	PJRST	CORFRE

VMS.TA:	PUSHJ	P,SETICH		;Set input character count
	MOVE	T1,[2,,T2]		;Find how many in chunks
	MOVEI	T2,.TOTTC		;..
	MOVE	T3,TTYUDX
	TRMOP.	T1,
	  SETZ	T1,
	PUSH	P,P4			;Save P4
	PUSHJ	P,SCNINI		;Init a scan
	PUSHJ	P,SCNCHR		;Get the character
	  JUMPN	T1,VM.TA4		;Figure what's out there
	MOVEI	P3,(P1)			;Remember character
	POP	P,P4			;Restore P4
	PUSHJ	P,VMS.BH		;Build the usual header
	MOVEI	P1,NORMAL
	PUSHJ	P,PUTWRD
	SETZ	P1,			;**TEMP
	PUSHJ	P,PUTWRD
	PUSHJ	P,PUTLWD
	MOVE	P1,ICHCNT
	ADDI	P1,(T1)			;Add them in
	PUSHJ	P,PUTWRD		;Tell him
	NETOCH	P3			;Output the character
	NETALC	5			;Rest is reserved
	JRST	VM.SN1			;Return

;Here if there are characters in the chunks and none internally.  Cheat.

VM.TA4:	TXO	F,F$FRC			;Force a read
	PUSHJ	P,FRCTTI		;Force wakeup
	SETZM	IMASK			;Only want to see first character
	POP	P,SENSEQ		;Remember the request
	PJRST	TTYSST			;Set TTY: up and return

;Here at TTY: interrupt level after the read is complete

VM.SNC:	TXZ	F,F$FRC			;Don't need to force any more
	SETZM	SENSEQ			;Done here
	JRST	VMS.TA			;Finish up the sense

;Here if modem modifer is set

VM.NMD:	PUSHJ	P,VMS.BH		;Build header
	MOVEI	P1,NORMAL
	PUSHJ	P,PUTWRD
	SETZ	P1,			;**TEMP
	PUSHJ	P,PUTWRD
	PUSHJ	P,PUTLWD
	PUSHJ	P,PUTLWD		;Return all zeroes
	PUSHJ	P,PUTLWD
	JRST	VM.SN1			;Finish up
	SUBTTL	VMS Support -- Return unsupported

;This routine returns an unsupported return for those functions we
;don't know what to do with.  Call with request block in P4.

VMS.UM:	PUSHJ	P,VMS.BH			;Build header
	MOVEI	P1,ILLFNC			;Say what's wrong
	PUSHJ	P,PUTWRD			;Put it in
	SETZ	P1,				;Do the rest
	PUSHJ	P,PUTWRD
	PUSHJ	P,PUTLWD			;Of the IOSB
	PUSHJ	P,XMTMSS			;Send the message
	MOVEI	T1,(P4)				;Free the block
	MOVEI	T2,VRQSIZ
	PJRST	CORFRE
	SUBTTL	TOPS-10/20 support -- Network service
PLM
;+
;.hl 2 TOPS-10/TOPS-20 Support
;	TOPS-10 and TOPS-20 are implemented via a transparent protocol.
;As such, all characters typed by the user are read in PIM mode from
;the terminal and queued immediately for network output.  All characters
;sent from the remote host are displayed on the terminal.
;-
MLP

T10.NT:
T20.NT:	SKIPE	OSTMR			;Are we enabled for flush?
	  TXO	F,F$CTO			;Yes, flag it
	PUSHJ	P,NETCHR		;See if we have a network character
IFN FTPERF,<
DOT204:	TXNN	F,F$PERF		;Performance flag set?
	  POPJ	P,			;Done
T10.NP:	PUSHJ	P,GETPRC		;Get a performance character
	  JRST	DOT109			;Force out the character
T10.EP:	PUSHJ	P,TSTRET		;Finish
	  JRST	T10.TT			;Get a new character
	JRST	DOT109			;Or pass break
> ;End IFN FTPERF
IFE	FTPERF,<
	  POPJ	P,			;No, Return (no null messages)
>
	SUBTTL	TOPS-10/20 support -- TTY: service

T10.TT:
T20.TT:
	TXZE	F,F$CTO			;Don't flush anything else
	  SETZM	OSTMR			;No more timer stuff
T10.T1:	PUSHJ	P,INCHR
	  JRST	T10.T5			;See if anything to output
IFN	FTPERF,<
	TXNN	F,F$PERF		;All being handled by other stuff
>
	  JRST	DOT107			;Process
IFN	FTPERF,<
	CAME	T1,ESCCHR		;In case he wants to abort
	  JRST	T10.T1			;No, just eat
	JRST	T10.EP			;End performance analysis
>
DOT106:	PUSHJ	P,INCHR			;Get a character
	  JRST	XMTMSS			;Send the message
DOT107:	CAME	T1,ESCCHR		;Escape character
	  JRST	DOT109
	MOVE	T1,TTYUDX		;Get controlling TTY: UDX
	CAME	T1,CTLTTY		;Same as controlling terminal?
	  JRST	DOT108
	TXNE	F,F$XPT			;Is he supposed to be an expert?
	PUSHJ	P,INCHR			;Anything to eat?
DOT108:	  TDZA	T3,T3			;No character
	MOVE	T3,T1			;Put character in T2
T10.MN:	PUSHJ	P,MONITC		;Go to the monitor 
IFN	FTPERF,<
	  JRST	[TXNN	F,F$PERF	;Now in performace?
		   JRST	T10.T1		;Loop around if not
		 JRST	T10.NP]		;Start PERF stuff
>
IFE	FTPERF,<
	  JRST	T10.T1
>
;	SETZM	BRKNUM			;(Not really used here anyway)
DOT109:	NETOCH	T1			;Output to network

IFN FTPERF,<
	TXNN	F,F$PERF		;Doing performance stuff
	 JRST	DOT106			;No, then just continue on normal path
	PJRST	XMTMSS			;Force out and dismiss

> ;End IFN FTPERF

	JRST	DOT106			;Loop for whole message

T10.T5:	MOVEI	T1,4*OBUFSZ
	SUB	T1,OBFCTR		;Do anything?
	JUMPN	T1,XMTMSS		;Yes, force it out
	POPJ	P,
	SUBTTL	TOPS-10/20 support -- Timer service

;Timer service is utilized for the "Flush Network Output" command.
;This is implemented so that we can automatically turn off the flush
;command if no network messages are received within the timeout period

T10.TM:	TXZN	F,F$CTO			;Clear the flush flag
	  JRST	T10.TC			;Clear timer stuff and return
	MOVEI	T1,1			;Reset for one second
	PITMR.	T1,			;Set the timer
	  JFCL
	POPJ	P,			;Done

T10.TC:	SETZM	OSTMR			;Don't come back here
	SKIPE	T4,NOTICH		;Point to string
	TXNN	F,F$XPT			;And in some expert mode?
	  POPJ	P,
	PUSHJ	P,STROUT		;Do it
	PJRST	DOOUT1			;Tell him
	SUBTTL TOPS-10/20 support -- Initialization

T10.IN:
T20.IN:	TXO	F,<F$PIM!F$READ!F$EOMN>
				;No local echo, PIM, always read active
				;No EOM except on last buffer
	PUSHJ	P,SETQUO	;Set link quotas
	PJRST	TTYSST
	SUBTTL	Unsupported System support

DORT11:	ERR	USP,<Unsupported Protocol found>
DOIAS:	JRST	E..USP
DORTS8:	JRST	E..USP
DOOS8:	JRST	E..USP
DOCOPOS: JRST	E..USP
DORXMP:	JRST	E..USP
	SUBTTL	O/S Name table

;PLM
;+
;.Chapter Data Tables
;.hl
MLP
;	The rest of the program is concerned with the data tables and
;variables used by the program:
PLM
;.list 1
;.le
MLP
;Table OSNAME is a list of SIXBIT text names indexed by the operating
;system type as returned in the configuration message.
PLM
;-
MLP

OSNAME:	'RSTS-E'	;Old RSTS
	'RT-11 '
	'RSTS/E'
	'RSX11S'
	'RSX11M'
	'RSX11D'
	'IAS   '
	'VMS   '
	'TOPS20'
	'TOPS10'
	'RTS-8 '
	'OS-8  '
	'RSX-M+'
	'COPOS '
	SUBTTL Protocal Dispatch Blocks -- RSTS

PLM
;+
;.le
MLP
;The following are the protocol dispatch blocks for each type of operating
;system type.  They defined the legal functions for each operating system.
;The format of an entry in a table is "dispatch-address,,function-key-value".
PLM
;.list 1
;.le
MLP
;RSSFNC is the protocol block for RSTS.
PLM
;-
MLP

RSSFNC:	RST.CT,,MT$CTL	;Control
	RST.DA,,MT$DAT	;Data
		Z
	SUBTTL Protocal Dispatch Blocks -- RSX

PLM
;+
;.le
MLP
;RSXFNC is the protocol block for RSX.
PLM
;-
MLP

RSXFNC:	RX.WRT,,RF.WTD	;Write Data (3)
	RX.PRD,,RF.WRD	;Write-then-read (5)
	RX.RED,,RF.RDD	;Read Data (4)
	RX.NOP,,RF.NOP	;No-op (0)
	RX.KIL,,RF.KIL	;Kill I/O (8)
	RX.SSC,,RF.RSC	;Single-char input (7)
	RX.SUN,,RF.UNS	;Unsolicited input (6)
	RX.DIS,,RF.DIS	;Disconnect link
	RX.DAT,,RF.ATT	;ATTACH/DETACH
	RX.GTC,,RF.GTC	;Get terminal characteristics
	RX.STC,,RF.STC	;Set terminal characteristics
		Z




	SUBTTL Protocal Dispatch Blocks -- VMS

;PLM
;+
;.le
MLP
;VMSFNC is the protocol block for VMS.
PLM
;-
MLP

VMSFNC:	VMS.PW,,VF.WPH	;Write
	VMS.DA,,VF.WLB	;
	VMS.DA,,VF.WVB	;
	VMS.RA,,VF.RPH	;Read
	VMS.RD,,VF.RLB	;
	VMS.RD,,VF.RVB	;
	VMS.PD,,VF.RPR	;Read with prompt
	VMS.RA,,VF.RAL	;Readall
	VMS.PA,,VF.RPA	;Readall with prompt
	VMS.KI,,VF.ACC	;Kill I/O
	VMS.ST,,VF.STM	;Set mode
	VMS.ST,,VF.STC	;
	VMS.SN,,VF.SNM	;Sense mode
	VMS.SN,,VF.SNC	;
	VMS.BC,,VF.BCS	;Broadcast
		Z

PLM
;+
;.end list
;-
MLP
	SUBTTL	Lowseg Initializers Stored in Hiseg

PLM
;+
;.le
MLP
;HILOST is the start of a section of initializing data for the low segment.
;.list 1
PLM
;-
MLP

HILOST:			;This gets BLTted to the Loseg

IFN FTPSECT,<.PSECT .LOW.>
IFE FTPSECT,<RELOC 0>
LOLOST:
IFN FTPSECT,<.PSECT .HIGH.>
IFE FTPSECT,<RELOC>

PHASE LOLOST
	SUBTTL NSP. Connect Block

PLM
;+
;.le
MLP
;CONBLK, SRCPDB, DSTPDB, and SRCNAM are the prototype parts of
;NSP. argument blocks.
PLM
;-
MLP

CONBLK:	EXP	.NSCUD+1	;ENTER ACTIVE CONNECT BLOCK
	EXP	ASCNOD		;NODE NAME STRING BLOCK
	EXP	SRCPDB		;SOURCE PROCESS BLOCK
	EXP	DSTPDB		;DESTINATION PROCESS BLOCK
	EXP	USERID		;USERID STRING BLOCK
	EXP	PASSWD		;PASSWORD STRING BLOCK
	EXP	ACCOUN		;ACCOUNT STRING BLOCK
	EXP	USERDA		;USER DATA STRING BLOCK

SRCPDB:	.NSDPN+1		;Length of block
	DEC	1		;Format type
	.OBGEN			;Object(=0)
	Z			;PPN
	SRCNAM			;Pointer to name block

SRCNAM:	XWD	^D11,4		;11 bytes, four words
	ASCII8	<TOPS-10 NRT>
PLM
;+
;.le
MLP
;TOBUF is the header for the terminal output buffer.

TOFLGS:	BLOCK	1		;Flags to include when buffer queued
BUFQUO:	EXP	OUTQUO		;Number of output buffers which can be queued
TOBUF:	BLOCK	3		;Used by us
TOBFH:	BLOCK	3		;Used by OUT UUO
TOQUE:	BLOCK	1		;Output buffer queue

PLM
;-
MLP
PLM
;+
;.le
MLP
;HPSTRM is the argument block for the maintenance of horizontal position data
PLM
;-
MLP

HPSTRM:	EXP	.TOHPS+.TOSET
HPSUDX:	BLOCK	1		;For fast access
HPOS:	EXP	Z		;The position

PLM
;+
;.le
MLP
;ECCTRM is for checking if characters are pending to be echoed.
PLM
;-
MLP

ECCTRM:	EXP	.TOECC
ECCUDX:	BLOCK	1

PLM
;+
;.le
MLP
;BKCTRM is for obtaining the count of break characters in the input buffer
PLM
;-
MLP

BKCTRM:	EXP	.TOBKC
BKCUDX:	BLOCK	1

PLM
;+
;.le
MLP
;PAGTRM is for checking the setting of the page bit.
PLM
;-
MLP

PAGTRM:	EXP	.TOPAG
PAGUDX:	BLOCK	1

PLM
;+
;.le
MLP
;CTOTRM is used to check the ^O bit; CTOTRS is for setting the ^O bit.
PLM
;-
MLP

CTOTRM:	EXP	.TOOSU
CTOUDX:	BLOCK	1
CTOTRS:	EXP	.TOOSU+.TOSET
COSUDX:	BLOCK	1
COSVAL:	BLOCK	1
PLM
;+
;.le
MLP
;BMASK is the default (TOPS-10) break mask.
PLM
;-
MLP

BMASK:	EXP	255			;Field size
	BRKMSK	<CGJKLZ[>
PLM
;+
;.le
MLP
;TTYBLK is the OPEN block for device TT:.
PLM
;-
MLP

TTYBLK:	Z
	SIXBIT 'TT'
	TOBFH,,TIBUF
PLM
;+
;.le
MLP
;TTYSAV is the table of TTY: characteristics to be saved on entering NRT
;and restored later.
PLM
;-
MLP

TTYSAV:					;Start of table of saved TTY: chars.
	TRMCHR	SLV
	TRMCHR	LCT			;Lower case
	TRMCHR	NFC			;Free <CR>
	TRMCHR	LCP
	TRMCHR	WID			;Width
	TRMCHR	LNB			;Page size
	TRMCHR	DIS			;Display bit
	TRMCHR	BLK			;Blanks
	TRMCHR	XNF			;XON/XOFF bit
	TSVNUM==.-TTYSAV		;Number of characteristics

PLM
;+
;.le
MLP
;TTYSET is a table of terminal characterstics which NRT wishes to
;be set a particular way while it runs.  Entries in TTYSET should also
;be in TTYSAV.
PLM
;-
MLP

TTYSET:	TRMCHR	SLV,-1,ST
	TRMCHR	BLK,0,ST
	TSTNUM==.-TTYSET
	SUBTTL	Special stuff for VAX
PLM
;+
;.le
MLP
;VMTTCH is storage for VMS terminal characteristics.  The default
;type of terminal we set is a TTY:.
PLM
;-
MLP

VMTTCH:	<BYTE	(8)0,0,DT$TTY,DC$TERM>_-4
	Z
	Z

	SUBTTL	Special stuff for RSX

PLM
;+
;.le
MLP
;RXCHTB is storage for the RSX terminal characteristics.
PLM
;-
MLP

RXCHTB:	BLOCK	RC.MAX			;Terminal characteristics table

PLM
;+
;.LE
MLP
;LEDTRM and LEDUDX are used to check to see if, during type-ahead,
;the user typed some line editing characters.
PLM
;-
MLP

LEDTRM:	.TOSBS				;Set break mask
LEDUDX:	BLOCK	1			;UDX
	^D255				;Mask size
	EXP	<1B<.CHCNU>!1B<.CHCNR>>,0,0,1B31 ;All the interesting bits
PLM
;+
;.end list
;-
MLP
LOLOND:
DEPHASE
	SUBTTL	Useful break masks

PLM
;+
;.le
MLP
;Default break masks:
PLM
;.list 1
;.le
MLP
;VXDMSK is the VAX default break mask.
PLM
;-
MLP

VXDMSK:	^D255
	BRKMSK	<ABCDEFGMNOPQRSTUVWXYZ[\]^_>

PLM
;+
;.le
MLP
;RXDMSK is the default RSX break mask.
PLM
;-
MLP

RXDMSK:	^D255
	BRKMSK	<CGJMNZ[\]^_>

PLM
;+
;.le
MLP
;RSTDMK is the default RSTS break mask
PLM
;-
MLP

RSTDMK:	^D130
	BRKMSK	<CJMOTYZ[>

PLM
;+
;.end list
;-
MLP
	SUBTTL	Terminal information tables

PLM
;+
;.le
MLP
;The next set of tables are TTY: type tables.  This is so we can
;pass intelligently the type of terminal we are to the remote host.
;The index into each table should yield the corresponding terminal
;type for the appropriate operating system.
PLM
;.list 1
;.le
MLP
;TTPTB is the TOPS-10 version of the table.
PLM
;-
MLP

TTPTB:	SIXBIT/VT52/		;Type VT52
	SIXBIT/VT100/		;Type VT100
	SIXBIT/VT61/		;Type VT61
	SIXBIT/VT102/		;Type VT102
	SIXBIT/VT101/		;Type VT101
	SIXBIT/VT132/		;Type VT132
	SIXBIT/VT125/		;Type VT125
	SIXBIT/VT103/		;Type VT103
	TTPLEN==.-TTPTB

PLM
;+
;.le
MLP
;VTPTB is the VMS terminal type table.
PLM
;-
MLP
;VMS corresponding types (must be same order)
;Left half is the high order byte of the TT2 characteristics, or the
;DEC/ANSI CRT byte

VTPTB:	VTTCHR	(T2DCRT,V52)		;VT52
	VTTCHR	(T2ACRT,V100)		;VT100
	VTTCHR	(T2DCRT,V5X)		;VT%x
	VTTCHR	(T2ACRT,V100)
	VTTCHR	(T2ACRT,V100)
	VTTCHR	(T2ACRT,V100)
	VTTCHR	(T2ACRT,V100)
	VTTCHR	(T2ACRT,V100)

	IFN	<.-VTPTB-TTPLEN>,<
	PRINTX	%Incorrect number of VAX terminal types
>
PLM
;+
;.le
MLP
;RTPTB is the RSX terminal type table
PLM
;-
MLP

RTPTB:	RXV52			;VT52
	RXV100		;VT100
	RXV61		;VT61
	RXV102		;VT102
	RXV101		;VT101
	RXV132		;VT132
	RXV125		;VT125
	RXV102		;VT103

	IFN	<.-RTPTB-TTPLEN>,<
	PRINTX	%Incorrect # of RSX terminal types
	>
PLM
;+
;.le
MLP
;RXTRMP is the table of TRMOP. functions to do (including .TOSET) for
;SET TERMINAL CHARACTERISTICS messages.
;Bit 0 in the left half indicates that the value should be complemented
;before doing the TRMOP.
PLM
;-
MLP

RXTRMP:
	Z				;Zero (undefined)
	REPEAT	^D15,<
	Z				;1-15 undefined
	>
	400000,,.TOSET+.TOLCT		;Lower case
	.TOSET+.TOFRM			;Form feed
	.TOSET+.TOTAB			;Tab
	Z				;Handled by F$NEC
	Z				;Can't change baud rate
	Z				;Can't change baud rate
	.TOSET+.TOTRM			;Terminal type
	.TOSET+.TODIS			;Display bit
	Z				;Handled by F$PALL
	.TOSET+.TOSTP			;XON/XOFF done
	.TOSET+.TOFLC			;Fill class (horizontal)
	.TOSET+.TOFLC			;Fill class (vertical)
	.TOSET+.TOPSZ			;Page size
	Z				;Enable/disable type-ahead (can't do)
	Z				;Handled separately
	Z				;Eight bit ascii
	Z				;Can't be changed
	Z				;Can't be changed
	Z				;Control-C flush (always on)
	Z				;Full duplex (always on)
	Z				;Local GAG (can't do)
	Z				;Read type-ahead
	Z				;Enable lowercase output
	Z				;Force lowercase input
PLM
;+
;.end list
;-
MLP

PLM
;+
;.le
MLP
;QUOTBL is the link quota and percentage goal table, indexed by
;TTY: baud rate.  The left half of each entry is the percentage to allocate
;for input; the right half is the goal.
PLM
;-
MLP

QUOTBL:	-1				;Default
	-1				;Assume 50 is really 19.2K
	^D7,,0				;75 BAUD
	^D7,,0				;110 BAUD
	^D7,,0				;134.5 BAUD
	^D15,,0				;150 BAUD
	^D15,,1				;200 BAUD
	^D15,,1				;300 BAUD
	^D22,,1				;600 BAUD
	^D22,,2				;1200 BAUD
	^D30,,2				;1800 BAUD
	^D40,,3				;2400 BAUD
	QUOMAX==.-QUOTBL		;4800 and 9600 at MAX

PLM
;+
;.le
MLP
;SEGTBL is the segment size table, also based on baud rate.
PLM
;-
MLP

SEGTBL:	0			;Default
	0			;Assume 50 is really 19.2K
	^D30			;75
	^D30			;110
	^D30			;134.5
	^D30			;150
	^D30			;200
	^D30			;300
	^D60			;600
	^D60			;1200
	^D100			;1800
	^D100			;2400
	SEGMAX==.-SEGTBL	;Above 2400, use default
	SUBTTL	Terminal strings for <RUB>

PLM
;+
;.le
MLP
;RUBS1 is the rubout string table, indexed by terminal type (same as
;the terminal type tables above).
PLM
;-
MLP

RUBS1:	[BYTE	(7)^D8,40,^D8]		;VT52: <BSP><SP><BSP>
	[BYTE	(7)^D8,40,^D8]		;VT100: <BSP><SP><BSP>
	[BYTE	(7)^D8,40,^D8]		;VT61: <BSP><SP><BSP>
	[BYTE	(7)^D8,40,^D8]		;VT102: <BSP><SP><BSP>
	[BYTE	(7)^D8,40,^D8]		;VT101: <BSP><SP><BSP>
	[BYTE	(7)^D8,40,^D8]		;VT132: <BSP><SP><BSP>
	[BYTE	(7)^D8,40,^D8]		;VT125: <BSP><SP><BSP>
	[BYTE	(7)^D8,40,^D8]		;VT103: <BSP><SP><BSP>
	IFN	.-RUBS1-TTPLEN,<
		PRINTX	%Number of rubout strings doesn't match number of types
		>
	SUBTTL	Literal storage

	XLIST
	LIT
	LIST
PLM
;+
;.end list
;-
MLP
	SUBTTL	STORAGE

	RELOC	LOLOND+1	;THIS STUFF MUST BE IN THE LOW SEG

PLM
;+
MLP
;The rest of the low segment data should be reasonably well documented
;in the comments in the source and hence will not be documented here.
PLM
;-
MLP

FSTZER:!

IBFCNT:	BLOCK	1		;Count of bytes input
IBFPTR:	BLOCK	1		;Byte pointer to data
OBFCTR:	BLOCK	1		;Count of bytes left in buffer
OBFPTR:	BLOCK	1		;Pointer to next byte in buffer

;Here are the volitile NSP. blocks:

ASCNOD:	BLOCK	3		;NODE NAME

USERID:	BLOCK	10		;USER-ID

PASSWD:	BLOCK	10		;PASSWORD

ACCOUN:	BLOCK	10		;ACCOUNT

USERDA:	BLOCK	10		;USER DATA

NSPECD:	BLOCK	1		;ERROR CODE FOR SETNER
FTZER:				;FIRST WORD OF TTY DATA BASE TO ZERO
LSTCHR:	BLOCK	1		;Storage for last character just typed
TRMLEN:	BLOCK	1		;Terminator length
INPCHR:	BLOCK	1		;Saved TTY input Character
TIBUF:	BLOCK	3		;TTY input buffer header

BYTPWD:	BLOCK	1		;Current I/O byte size
CHPBUF:	BLOCK	1		;Number of characters in buffer
BUFCHR:	BLOCK	1		;LH(byte pointer),,#words in buffer
LASTT2:	BLOCK	1		;Pointer to last word in buffer indexed by T2
ICHCNT:	BLOCK	1		;Number of characters available
LICHCT:	BLOCK	1		;Remember value of ICHCNT
INPQUE:	BLOCK	1		;Pointer to input blocks
 LTZER==.-1			;Last word to zero on TTY reset

PROTMD:	BLOCK	1		;Protocol modifier
OSTYPE:	BLOCK	1		;What kind of system is this?
OSTTY:	BLOCK	1		;Routine to handle TTY input for this OS
OSNET:	BLOCK	1		;Routine to handle network input for this OS

;The interrupt level database interlock

INTLVL:	BLOCK	1		;..
SLPFLG:	BLOCK	1		;Flag, set to 1 if we're sleeping
				;for output to complete

;The TTY interrupts which have been requested.  Zero on exit from TTY: service
;IOR requested conditions in when an interrupt is deferred.

TTYSTS:	BLOCK	1

;These are the fake buffers that are used by NSPIN and NSPOUT.

OTPBUF:	BLOCK	1		;Pointer to output buffer
				;Note that sign bit set means DON'T set EOM
OUTQUE:	BLOCK	1		;Pointer to the output queue

INPBUF:	BLOCK ^D<132/4>+^D10	;Network Input data
	BFLEN==.-INPBUF		;Length of the buffer
	IBUFSZ==<.-INPBUF>*4-1	;LENGTH IN BYTES

IFN FTPMR,<
RNODE:	BLOCK	MAXPMR+1	;Remote node ID

NODCNT:	BLOCK	1		;Count of number of nodes in string
PMRCNT:	BLOCK	1		;Storage for length of string
PMRMSG:	BLOCK	MAXPMR+5	;For the PMR connect string
> ;End IFN FTPMR

IFE FTPMR,<
RNODE:	BLOCK	1		 ;Remote node name
	>

CHRTAB:	BLOCK	<^D256/^D36>+1	;Special character table
TTYTYP:	BLOCK	1		;Index into TTY: type tables
OBMASK:	BLOCK	2		;Out of band include & exclude masks
				;(VMS)
XSPCNT:	BLOCK	1		;Count of ^Cs in buffer to skip
XSCREQ:	BLOCK	1		;Pointer to request block for Read Single Characters (RSX)
XUNREQ:	BLOCK	1		;Pointer to request block for Unsolicited input (RSX)
BRKCHR:				;(LH) Char to be considered as "break" char
BRKSIZ:	BLOCK	1		;(RH) Size of break string (VMS escape seq.)
	 LSTZER==.-1		;End of Zeroable low segment

NOTICH:	BLOCK	1		;Notification string

;Break mask
TRMBKS:	EXP	.TOSBS		;Set the break set
TTYUDX:	BLOCK	1		;Storage for UDX of my TTY
	FALL	IMASK
IMASK:	BLOCK	5		;For break Mask
	ENDMSK==.-1
	FALL	LMASK		;***THESE MUST BE CONTIGUOUS***(RX.SCS)
LMASK:	BLOCK	4		;"Local" or "logical" break mask
	ELMASK==.-1

CTLTTY:	BLOCK	1		;IONDX for controlling TTY:
NODBLK:	BLOCK	.DNNMS+1	;For DNET. UUO
BRKNUM:	BLOCK	1		;Number of breaks to ignore in input
BRKCNT:	BLOCK	1		;Counter in scanning for above
ESCCHR:	BLOCK	1		;Char to escape from program
ESCBIT:	BLOCK	1		;Bit mask for escape character
ESCWRD:	BLOCK	1		;Word offset for the mask bit
READQ:	BLOCK	1		;Pointer to queued reads for VAX, RSX
SENSEQ:	BLOCK	1		;Queued Sense Request (VAX)
RSXSVF:	BLOCK	1		;Saved F for RSX (Control-O)
UNSCNT:	BLOCK	1		;Unsolicted count (VAX, really full word flag)
RSTFLG:	BLOCK	1		;RESTART flag
RULE:	BLOCK	1		;Current rule number for ANSI escape sequences
TTBAUD:	BLOCK	1		;BAUD rate code for controlling TTY:

DSKHDR:	BLOCK	.BFCTR+1	;Block for SWITCH.INI input
	SUBTTL NSP. UUO DSTPDB Block

DSTPDB:	.NSDOB+1		;Length of block
	DEC	0		;FORMAT TYPE
	.OBHTH			;OBJECT NUMBER OF NRT SERVER
	SUBTTL	Configuration & Control Messages

;Each of the following messages is preceded by its length

	DEFINE	NETMSG	(LENGTH,STRING)<
	EXP	LENGTH
	BYTE	(8)	STRING
	>

RST$CF:	NETMSG	^D10,<MT$CFG,^D10,0,OST10,0,0,0,0,0,0>	;RSTS CONFIG MSG

RST$UN:	NETMSG	5,<MT$DAT,5,0,1,.CHCNZ>

RSX$CF:	NETMSG	^D42,<RF.SSD,1,0,0,OST10,0,2,0,^D132,0,
		RC.VER,1,
		RC.TBL,^D255,
		RC.CCT,1,
		RC.SCI,1,
		RC.WBT,1,
		RC.CAO,1,
		RC.RNE,1,
		RC.RTC,1,
		RC.CRT,1,
		RC.RIL,1,
		RC.RWB,1,
		RC.UNS,1,
		RC.SCX,1,
		RC.RTT,1,
		RC.RTM,1,
		RC.CUR,0>		;No cursor addressing

RSX$UN:	NETMSG	4,<RF.ECR,0,0,RE.SAR>

;This defaults to version 3 protocol.  It will be changed accordingly
VMS$CF:	NETMSG	24,<1,1,1,0,11,0,4,0,DC$TERM,DT$TTY,0,0,200,0,0,0,0,0,0,0>
VMS$UN:	NETMSG	4,<VR.ATT,377,RA.UNS,0>
	SUBTTL Performance analysis low segment

IFN FTPERF,<
TSTPTR:	BLOCK	1		;Storage for pointer to string
TSTLFT:	BLOCK	1		;Number of characters left to send
COMLEN:	BLOCK	1		;# characters in record
COMREC:	BLOCK	^D50		;250 characters max
TSTREP:	BLOCK	1		;Number of reps to do
TSTBEG:	BLOCK	1		;MSTIME at start
TSTEND:	BLOCK	1		;MSTIME at end
TSTTOT:	BLOCK	1		;Total # of Milliseconds it took
TSTTIM:	BLOCK	1		;UDT time at beginning
FILBLK:	BLOCK	^D8		;FILOP. UUO block
FOBUF:	BLOCK	3		;File output header
FIBUF:	BLOCK	3		;File input header
PRFFIL:	SIXBIT	/NETRSP/
	SIXBIT	/DAT/
	Z
	Z
	Z
> ;End IFN FTPERF
	SUBTTL Low segment for Interrupt system

VECBAS:
TTYVEC:	EXP	TTYPSI,0,0,0
NSPVEC:	EXP	DCNPSI,0,0,0
TMRVEC:	EXP	TMRPSI,0,0,0			;Filled in when needed
DATVEC:	EXP	DATPSI,0,0,0
WAKVEC:	EXP	WAKPSI,0,0,0

PSYNSP:	EXP	.PCNSP
	NSPVEC-VECBAS,,0
		Z

PSYTMR:	EXP	.PCTMR		;Arg block for TIMER PSIs
	TMRVEC-VECBAS,,0
		Z
	SUBTTL	.JBINT stuff

	LOC	.JBINT
	EXP	ERRBLK
	RELOC


ERRBLK:	EXP	ERRTRP,ER.ICC!ER.EIJ!ER.TLX!ER.QEX!ER.FUL!ER.OFL,0,0
	SUBTTL	Data base for timed I/O requests

OSTMR:	Z				;Filled in at run time, OS specific
					;timer trap processor

TMRSEQ:	Z				;Identifier for request being timed
	SUBTTL	Low segment for core manager

FRELST:	BLOCK	1			;Pointer to linked list of free blocks
HICORE:	BLOCK	1			;Highest location gotten with CORE UUO
	SUBTTL	Low segment AC blocks and PDLs

PDL:	BLOCK	PDLLEN			;Non-interrupt PDL
NSPPDL:	BLOCK	PDLLEN			;NSP interrupt PDL
TTYPDL:	BLOCK	PDLLEN			;TTY: service PDL
TMRPDL:	BLOCK	PDLLEN			;Timer service PDL
NSPACS:	BLOCK	20			;For NSP.'s ACs
TTYACS:	BLOCK	20			;TTY: service ACs
TMRACS:	BLOCK	20			;Timer trap ACs
CRSACS:	BLOCK	20			;For crash ACs
CRSPDL:	BLOCK	10			;For resetting things
	SUBTTL End of Program

	END	GO