.SYMTAB 8009.			; -*-MIDAS-*-

TITLE CRTSTY - STY program for unsupported CRTs
; (c) Copyright 1979,1983 by Ken Harrenstien and Earl Killian.

comment ~
		Building a CRTSTY

To create a new CRTSTY for ITS, do:
	:MIDAS SYSENG;_CRTSTY	; Assemble CRTSTY
	:JOB CRTSTY
	:LOAD CRTSTY		; Load CRTSTY BIN into a job
	PURIFY$G		; This will dump to SYSBIN;CRTSTY BIN
				; if you confirm with CR.  Another filename
				; can be specified.

To create a new CRTSTY for TENEX or TOPS-20 (known collectively as TNX),
first obtain the following files from their canonical location on MIT-MC:
	TNX filename		MIT-MC location
	CRTSTY.MID		SYSENG;CRTSTY >
	SYSTEM.MID		SYSENG;SYSTEM >
	MACROS.MID		KSC;MACROS >

Be sure to preserve the ITS version numbers; e.g. if the MIT-MC file is
CRTSTY 1300, then the TNX filename should be CRTSTY.MID.1300.
Then do: (this example is for TOPS-20)
	[@]MIDAS CRTSTY			; Assemble CRTSTY
	[@]GET CRTSTY			; Load it up
	[@]START PURIFY			; [Optional - start at "purify"]
	[@]SAVE <SUBSYS>CTN		; Then save as sharable program.

NOTE that the default assembly on ITS produces a "local" CRTSTY which
deals with STYs (pseudo-TTYs).  It is necessary to specify NET==1 to
produce a "Supdup" CRTSTY (which acts like TELNET).  On TNX this is
reversed, i.e. the default produces a Supdup CRTSTY (also called CTN)
since the assumption is that one will use it to access an ITS host over
the network.  By setting STY==1 a local CRTSTY can be built instead,
which is also called a PTY CRTSTY or PCRTSTY.  For example:
	[@]MIDAS CRTSTY/T
	[TTY: .INSRTed, end input with ^Z:]
	STY==1
	^Z
			; This results in a PCRTSTY.
~

comment ~

Operation:

	CRTSTY is a program which was originally meant to provide ITS
display support for terminals which ITS does not support itself.  It is
now also capable of acting as a SUPDUP (TELNET-like) user program, as
well as a general-purpose terminal translator which can emulate or
support many different types of terminals.

Because the design of ITS display support is interwoven closely with
CRTSTY, a brief overview of how ITS supports "virtual terminals" is
necessary to understand CRTSTY.  When an ITS program sends output to a
terminal it is interpreted by the ITS Main Program (MP) Level TTY
routines.  In addition to straight text to be displayed a program may
output special character sequences to perform useful operations on the
displayed output.  These character sequences are called "^P codes".
The ITS MP Level interprets ^P codes (and certain ASCII format
effectors such as CR, LF, etc.) and deposits in the terminal's output
buffer "%TD codes" - an internal representation of the operations to
be performed on the display.  Finally at output interrupt level the
ITS interrupt routines read %TD codes from the output buffer and send
the terminal specific codes necessary to operate on the display.

                         Normal ITS terminal output:

-----------    -------------    ----------    -------------    ------------
|         |    |    ITS    |    |  ITS   |    |    ITS    |    |          |
| Program |--->| Main Prog |--->| Output |--->| Interrupt |--->| Terminal |
|         | |  |   Level   | |  | Buffer | |  |   Level   | |  |          |
----------- |  ------------- |  ---------- |  ------------- |  ------------
            |                |             |                |
         ^P codes        %TD codes     %TD codes      Terminal codes

	Thus the only terminals directly supported by ITS are the few
which the ITS Interrupt Level knows about.  However it is possible to
indirectly support other terminals by means of a program like CRTSTY,
which runs in a separate process and basically replaces the
ITS Interrupt Level in the above diagram.  It does this via the STY
device which allows it to read from the output buffer of the TTY
associated with the STY.  Thus CRTSTY is able to read ITS %TD codes
and translate them into terminal codes for the supported terminal.
Finally CRTSTY outputs the terminal codes to the terminal, again going
through the ITS MP Level, ITS output buffer, and ITS Interrupt Level.
However it outputs in a special mode called "super image ouput mode"
which prevents MP Level and Interrupt Level from doing anything but
passing what CRTSTY sends verbatim.

                              CRTSTY operation:

-----------    -------------    ----------    ----------    ----------
|         |    |    ITS    |    |  ITS   |    | Pseudo |    |        |
| Program |--->| Main Prog |--->| Output |--->|  TTY   |--->| CRTSTY |--->
|         | |  |   Level   | |  | Buffer | |  | Device | |  |        | |
----------- |  ------------- |  ---------- |  ---------- |  ---------- |
            |                |             |             |             |
         ^P codes        %TD codes     %TD codes     %TD codes  Terminal codes

               -------------    ----------    -------------    ------------
               |    ITS    |    |  ITS   |    |    ITS    |    |          |
           --->| Main Prog |--->| Output |--->| Interrupt |--->| Terminal |
               |   Level   | |  | Buffer | |  |   Level   | |  |          |
               ------------- |  ---------- |  ------------- |  ------------
                             |             |                |
                      Terminal codes  Terminal codes  Terminal codes

     Add some stuff about what CRTSTY does when it gets the %TD codes.
Explain its "never do today what you can put off until tomorrow" attitude.
~

comment ~
		CRTSTY Internal Structure

	CRTSTY operates as two separate processes, one for the "Input Stream"
and one for the "Output Stream".  Each stream contains one module for
the SUPPORT of a particular terminal, and another for the SIMULATION of
a different terminal.

				 %TOFCI bits - Ideal input stream
				    |
		   SIMULATION	    |	     SUPPORT
	       |----------------|   |	|----------------|
  PYO channel  |     "SMI"	|   |	|     "TYI"	 |  TYIC channel
input  <<======|smibout< <smiget|=======|tyiput<  <tyibin|===========<< keybd
  |	    out|		|	|		 | in		  |
PROGRAM   STY  |----------------| IDEAL	|----------------|   TTY	USER
  |	    in |     "SMO"	|	|     "TYO"	 | out		  |
output >>======|smobin> >=======|=======|td.xxx> >tyobout|===========>> display
  PYI channel  |		|   |	|		 |  TYOC channel
	       |----------------|   |	|----------------|
				    |
				%TD codes - Ideal output stream

	Input Stream:  SMI+TYI	Support Pair:  TYI+TYO
	Output Stream: SMO+TYO	Simulate Pair: SMI+SMO

Remember that each data stream is implemented as a complete
	process, with its own ACs and stack.  In some TNX configurations
	the output stream is actually an inferior fork!
Also note a common source of confusion:	each stream has both input and output
	aspects at various stages, depending on the point of view;
	e.g. note that output to a STY is actually input from the TTY,
	and vice versa.

In the very center one sees the "IDEAL" virtual terminal, using %TOFCI
bits on input and %TD codes on output.  By using this virtual terminal
concept it is possible to simulate and support any pair of real terminals
freely, since each module will be "plug compatible" with every other.

In general, only the output stream is of interest, since keyboard
input is usually passed along to the program with no modification or
special action.  Note that the SMI and TYI modules as implemented are
actually co-routines within the input-stream process; each believes it
is driving the other.  SMO on the other hand does drive TYO directly;
in fact the channel between them is one of execution paths rather than
actual data, wherein SMO decides what TD.XXX routines to invoke.

The SIMULATE (SMx) component's task is to fake the program into believing
that its controlling TTY is some particular terminal, primarily by scanning the
output stream for display commands and translating them into %TD codes.
This is useful when dealing with programs which were written with one
particular terminal in mind, as is often the case on non-ITS systems.
By default this component simulates an ITS "Soft" TTY.  Since a Soft
TTY is merely the ITS virtual terminal specification, identical or
almost so to CRTSTY's virtual terminal, this default involves essentially
no overhead.

The SUPPORT (TYx) component's task is to translate the virtual-terminal
%TD-code display commands into specific output sequences for the
particular terminal type actually being used.  It is also sometimes
responsible, in the TYI module, for implementing various keyboard input
features that try to compensate for whatever mis-features the terminal
has.  A prime example of this is the underscore/DEL exchange for
keyboards which have these chars on the same key, wrong side up (i.e.
they expect you to hold down SHIFT every time you rubout something).

CRTSTY normally configures the SMI/SMO simulation to accurately reflect
the capabilities of the terminal being supported (by TYI/TYO).  This is
particularly easy when the simulated terminal is the ITS virtual terminal
since many parameters are easily varied.  It is more difficult when the
user has requested simulation of some other, specific terminal, because
an adequate simulation may REQUIRE capabilities which the supported
terminal does not have.  An obvious example is an attempt to simulate
a VT52 on a printing terminal.

~

subttl	History

comment ~

Historical:

	Historically derived from TEKSTY, munged by DPR, RZ, MOON,
CBF, EAK, and KLH.  Current version nearly a complete KLH rewrite
(with exception of command parsing).  TEKSTY was a version of STY
(written by PJ?) hacked up by JLK and RLB.

Date   Version	Who	What
(Note KLH doesn't pay much attention to this nonsense)
 3/20/78   394	EAK	fix auto-nl bug again
 3/28/78   400	EAK	add TM.AX and TM.AY entries to HP's
 3/31/78   402	EAK	put check in MOVCUR for fast return if no movement
 3/31/78   403	CBF	remove my version of the NIH5200
 4/05/78   407	EAK	fix Concept 100 initialization to set tabs correctly
 4/07/78   416	EAK	Purified CRTSTY
 4/08/78   417	EAK	Fixed bug in SCRDCP
 4/12/78   421	CBF	Added DTI terminal
 4/16/78   422	EAK	Fixed bug in TEK4025
 4/26/78   423	EAK	Added home entry to TEK4025
 4/28/78   435	EAK	Fixed some OMRON bugs
 5/06/78   436	EAK	Increased OMRON InsLine and DelLine padding
 5/11/78   437	EAK	Switched to winning version of ASCNT macro
 5/16/78   439	KLH	Added DM3025 as per FURST's specifications
 5/16/78   440	CBF	Changed some timings and 1 bug in DM3025 definition
 5/16/78   443	EAK	Fixed some paddings in DM3025
 5/22/78   448	EAK	Restored C100 editing functions
 5/22/78   449	EAK	Fixed FOX absolute move bug and NOABS flag
 5/22/78   450	CBF	Made TR.AMC definitions for FOX, OWL, HP2645 and HP2640
 5/22/78   452	EAK	Changed C100 padding on basis of experimentation
 5/28/78   454	RJL	Added control _ and control ^ to c100 on function keys
 5/31/78   459	RJL	Added esc n function keys, padding on formfeed and
			fixed init bug in C100
 6/02/78   480	EAK	Changed insert/delete line/character entries to take
			argument instead of assuming 1
 7/03/78   507	EAK	Finally debugged the TEK4025 code.  The terminal is
			a real crock, and the manual is impossible.
 7/19/78   520	KLH	Hacked TRMBEG macro and CORFLS routine so that
			several terminal definitions can share same page.
 7/24/78   521	EAK	Added some stuff to TEK4025 code.
 8/01/78   527	EAK	Fixed a bug in TEK4025 code.  Also made definition
			macros barf if arguments are blank.
 8/02/78   530	EAK	Created two new zone tables and modified some terminal
			definitions to use them.
 8/06/78   564	EAK	Put in redundent movement optimizer.
 8/11/78   572	KLH	Finished EAK's mods and added smart CLEOL hackery!
 8/12/78	RWK	Made VT52 alternate keypad work right, made it %TOFCI
			and put in timeout for ESC (SEL).  Fixed FEEP code.
 8/14/78   608	EAK	Changed the world to use arguments for relative
			movement functions.
 8/17/78   615	EAK	Redid ORDNRY to fix bugs, provide better control
			character output.
 8/20/78   633	EAK	Fixed some bugs in movement optimizer and ORDNRY.
 8/20/78   634	EAK	Added a TR.WRP entry for the HP terminals.
 8/20/78   635	EAK	Hacked the HP terminal definitions somewhat.
 8/20/78   638	EAK	Added the Tektronix 4027.  It is almost identical
			to the 4025, but lacks  for move up.
 8/20/78   639	EAK	Fixed a bug in CLEOL-less terminal bug in ORDNRY.
 8/20/78   641	EAK	Hacked 4027 CLEOL to used DCH at 60cps or slower.
 8/21/78   644	EAK	Fixed bug in SIMEOL so that it will clear the last
			character position on a line.
 8/21/78   646	EAK	Moved screen image updating from ORDNRY to SCHO.
 8/21/78   647	EAK	Removed  hackery from 4025 since not all of them
			have it.
 8/21/78   656	EAK	Added TRMTOO and associated hackery.
 8/22/78   657	EAK	Fixed bug in FTLINT.
 8/23/78   660	CBF	Added H1500A cause Hazeltine changed RP's CR to an NL
 8/23/78   661	CBF	Added T1061
 8/23/78   662	CBF	Changed TK4027 to always use DWN instead of LF
			This may also have to be done to the 4025
 8/23/78   663	RWK	Fixed a %CLPND bug in ORDNRY.
 8/23/78   664	EAK	Added DBUFC for debugging.
 8/27/78   667	EAK	Changed FRCEOL to not output CLEOL unless its
			really needed.
 9/01/78   668	EAK	Fixed a bug I introduced into FRCEOL.
 9/01/78   669	EAK	Added more smarts to SMEOL on terminal with CLEOL.
 9/03/78   670	EAK	Added a CHO routine for the Concept 100.  Also,
			turned off character insert/delete.
 9/05/78   671	CBF	Add the BEE3 for CMR
 9/07/78   679	EAK	Fixed some VT100 stuff after playing with one.
 9/08/78   680	EAK	Added some scroll region optimizations for the VT100.
 9/08/78   681	EAK	Added Infoton 4380 support.  Also added sample
			terminal definition.
 9/09/78   683	RWK	Made -> key on VT52 into [BREAK] instead of [FORM]
 9/09/78   684	RWK	Added [ENTER] key hackery to VT52 stuff
 9/09/78   686	RWK	Made code for [ENTER] stuff available to any terminal
			and added code to flush it from core for those that
			don't use it.
 9/09/78   691	RWK	Added terminal-specific interactive ([ENTER])
			capability.  Intended for re-initing terminal
			parameters, etc.
 9/09/78   691	RWK	Added Alarm mode toggle as an [ENTER] command
 9/09/78   692	RWK	Started adding the DELPHI terminal type.  (An
			intelligent protocol between DELPHI UNIX and ITS
			including a mini-FTP for people here TA'ing 6.031)
 9/09/78   694	RWK	Spec'd out the FTP portion of DELPHI type.
 9/09/78   699	RWK	Added log file hackery
 9/09/78   703	RWK	Fixed a bug in VT52 sail graphics.
 9/09/78   705	RWK	More DELPHI hacking.
 9/12/78   706	EAK	Added a VT100 absolute movement cost calculator.
 9/12/78   708	EAK	Fixed two bugs in log file stuff.
 9/13/78   709	EAK	Fixed two bugs in Teleray 1061 code before demo today.
 9/13/78   717	EAK	Debugged Teleray 1061 support.
 9/13/78   718	EAK	Fixed bug in VTCHO.
 9/15/78   719	CBF	Hacked Adds 980 a bit.
 9/17/78   724	EAK	Hacked log file stuff a little more.
 9/20/78   727	CBF	Fixed BADSPC up a little.
 9/20/78   729	EAK	Tidied up OMRON code.
 9/20/78   731	EAK	Removed GRAFIX hack per request.
 9/20/78   736	EAK	Changed around a lot of the command line parsing.
			Still needs an awful lot of work.
 9/24/78   738	RWK	Fixed a bug in the CRTSTY-escape code.
 9/27/78   739	CBF	Made TK4027 use the obscure hardware CLEOL.
10/12/78   751	EAK	Added stuff to flush initialization code after
			startup.
10/20/78   766	EAK	Created terminal type SOFT and reorganized lots
			of the TD routines.  In the process HOMCLR went
			away; TDCLR and TDEOF now conspire to do it's job.
10/20/78   767	EAK	Fixed up TK40XX insert line at top code a little.
10/20/78   770	EAK	Added basic windowing stuff.
10/21/78   777	EAK	Added insert/delete line/character simulation.
10/23/78   780	KLH	Changed the terminal definition table to be BLT'd
			into the TB array at initialization.  Redid STY
			input.
10/24/78   790	KLH	Added NLS LP simulation.
10/24/78   792	EAK	Redid screen dumping stuff a little.
10/24/78   793	EAK	Added some TNX conditionals.
10/25/78   794	MMCM	Added Soroc IQ 120.
10/25/78   797	EAK	Added some more TNX stuff.  Changed WARN to use ORDNRY.
10/27/78   804	CBF	Added RPVT52, it's sick.
10/27/78   807	KLH	Added H1510.
10/28/78   808	EAK	Added %TDWIN stuff.  Created TE.WIN entries for the
			VT100 and Concept 100.
10/30/78   809	EAK	Hacked insert/delete line/character to work better
			in windows.  Also added .TRFIN to be called before
			CRTSTY quits.
10/30/78   810	EAK	Added ACT-IV.  Changed log file's home to be CRASH.
11/01/78   811	EAK	More fixes for insert/delete line/char in windows.
			Added .TPSCR, the scroll count for the terminal
			(corresponds to TTYROL in ITS).  Also, changed screen
			image to live right after variables to save a page
			on occaisions.
11/01/78   812	EAK	Reorganized TD subroutines.  Added some more TNX
			conditionals.
11/03/78   814	EAK	Redid TD.(DLF ILP DLP ICP DCP) yet again.  %FNxxx
			no longer need to be specified in terminal definitions.
			SIMEOL now calls TD.DLF instead of ORDNRY.
11/06/78   819	EAK	Replaced PAD subroutine with PAD UUO.  Changed all
			the TR.TYI handlers to conform to KLH's new scheme.
11/07/78   821	EAK	Added @ITS command line option.
11/08/78   822	EAK	Changed NOWARN to NO WARN, NOLOGIN to NO LOGIN, and
			NOBELL to NO BELL.  Also changed SCREOL, SCREOS,
			and SCRILP to work with windowing.
11/09/78   824	RWK	Fixed bugs in ENTER code.
11/09/78   827	EAK	Reorganized more of the initialization code to make
			it more modular and make it easier to conditionalize
			it for TNX.  Also changed C100 padding to be closer
			to reality, making it pretty hairy.
11/10/78   828	EAK	Changed NOABS to NO ABS, and NOTABS to NO TABS.
			Hacked TPCBS stuff.  Moved lots of code around
			to make groupings more logical.  PAD UUO now rounds up.
11/10/78   830	EAK	Changed SCRICP to work with windowing.  Commented
			out DBUFC (not worth the buffer space it takes).
11/14/78   834	EAK	Added a wrap optimizer to the I4380.
11/16/78   837	EAK	Removed %FLCNL and added CCHO in its place.  CCHO
			hacks scrolling when typing in the last column of the
			last line.  Added redisplay command to ACT stuff.
11/16/78   838	EAK	Changed SCRDLP to work with windowing.
11/21/78   852	KLH	Re-did some LP support/simulation stuff.
11/21/78   853	GSB	Added TX.VBL entry for Concept 100 and also changed
			its TR.CHO to hack underscores to avoid lossage.
11/21/78   854	EAK	Fixed a bug in C1CHO and hacked it a bit.
11/24/78   8??	KLH	decides to give up and start writing garbage in here.
11/24/78   880	KLH	Made TYI and SMO modules into co-routines, re-did
			most TR.TYI entries to take advantage of new
			capabilities.  Added more doc, clarified structure.
			Fixed several bugs in term defs (ACs not saved).
11/26/78   883	EAK	Changed TD.SCR to TD.SU.  Added SCROLL command line
			option.
11/27/78   888	KLH	Fixed bug in TD.ILP/DLP/ICP/DCP routines, added
			TD.SD (scroll down), redid terminal subttl's.
11/27/78   892	EAK	Undid KLH's undo of my undo to KLH's undo of my .TPSCR
			stuff.  Also fixed a bug in .TPSCR where cursor isn't
			updated updated correctly when .TPSCR<>1.
11/27/78   897	EAK	Changed SCRDCP to hack windowing.
			Began TR.TYI changes to improve co-routine setup.
11/29/78   899	KLH	Completed most TR.TYI changes, also changed STY
			interrupt vectoring similarly.  Fixed SCREOL bug.
			Added ACT-V.
11/30/78   900	EAK	Removed HP2640 definition, moved much of its stuff
			into the HP2645.  Eventually I'd like to make HPINIT
			see what name was used to invoke the HP code and do
			some stuff conditional on that name being HP2640.
11/30/78   901	EAK	Redid VT52 input co-routine and timeout stuff.
			Timeout stuff is now available to all terminals.
11/30/78   902	EAK	Hacked REDISP stuff a little.
12/01/78   903	RWK	Put [HELP] back in the ASKQUE routine.  This is easier
			to type on a VT52 (and I expect other TTY's too) than
			[BACK-NEXT]H or [TOP]H
12/01/78   906	RWK	Put in table of TOP characters.  What existed was
			useless. 
12/01/78   909	EAK	HP2645 bug fix.
12/02/78   912	EAK	Fixed up simulator output co-routine initialization.
12/03/78   914	EAK	Added some 20X PTY code.
12/04/78   915	KLH	Added  for LP mouse simulation.
12/05/78   917	EAK	Random changes all over.
12/06/78   918	EAK	CT64 bug fix.
12/06/78   919	EAK	ADM2 bug fix.
12/06/78   920	EAK	Fixed initialization bug introduced in 917.
12/06/78   921	EAK	Changes to %PITTY interrupts.
12/07/78   922	CBF	Minor fix to RPVT52, fixed JTRMSLS to list several
			terminals per line again, and put in VT100 padding.
12/07/78   926	KLH	Added DATAPOINT, tried to document some hair.
12/08/78   928	KLH	Added XLOG, improved CCHO, removed SCRLCOUNT=0
			check.  Scroll stuff really needs to be fixed.
12/08/78   929	EAK	Put back detached check in RLTINT; it is needed
			because %PITTY doesn't go off reliably.
12/08/78   930	EAK	Added SLEEP macro.  Reversed PG$MSK convention.
12/08/78   931	EAK	More TNX modifications.
12/14/78   943	KLH	Added DATALOSER (still needs work), condensed
			TMCDEF etc macros, TB entries now have labels for DDT.
			Changed TR.INI default, dbgsw setting.
12/14/78   944	KLH	Fixed a CLEOL bug.
12/14/78   947	KLH	Changed Dm2500 i/c and i/l code to use cleverness.
12/17/78   950	RWK	Put the ASKHLP routine (from ASKQUE) inside the IFN ITS
12/22/78   953	KLH	Fixed DEFINI bug, changed LP's .TRINI back owing to 
			problems with hacking TYIGET before interrupts enabled.
 1/03/79   954	BYRON	Minor adjustment to C100 padding.
 1/29/79   960	CBF	Changed OMRON to -%TOLID if > 300 baud.
 2/25/79   962	CBF	Added MIME52 for Emery.  Essentially VT52 with line i/d
 2/28/79   964	EAK	Changed C1CHO3 to use repeat character horizontal.
			Also changed OSMAP a little.
 3/01/79   966	GSB&EAK	Hacked C1CHO some more.
 3/02/79   967	EAK	Added STYIP for hacky optimizations.
 3/03/79   968	EAK	Added TRANSLUCENT option for C100.  Completely redid
			C1CHO.  Also started WHOLINE option.
 3/05/79   970	EAK	Moved OSMAP code into OSINIT, TTYINI, STYINI.
			Changed HPINIT to use BUFC while sending terminal
			reset.
 3/11/79   971	EAK	Fixed up TKILP.
 3/11/79   972	EAK	Added WHO1/WHO2/WHO3 hacking to WHOLINE stuff.
 3/11/79   973	EAK	Added JTMU, NMPGS, and NSWPGS hackery to WHOLINE.
 3/11/79   974	EAK	Fixed screwed up %F flag definitions.
 3/12/79   976	EAK	Added I400.
 3/13/79   977	CBF	Added I100.  (This is support your local Infoton week)
 3/13/79   978	CBF	Added ADS100 for Macrak and hacked MIME52 for Emery
 3/14/79   979	EAK	Fixed I400 bugs, changed C1CHO to hack last column
			better.
 3/15/79   980	EAK	More I400 work.
 3/16/79   981	EAK	Changed XITEX to use NUL for padding.
 3/17/79   982	EAK	Fixed formatting bug in WRTLOG.
 3/18/79   983	EAK	Fixed TDORS problem with WHOLINE.
 3/24/79   984	EAK	C100 window hacking.
 3/25/79   985	EAK	Added optimization to TDDLP.
 3/26/79   986	EAK	Hacked C100 insert/delete character subroutines.
 3/26/79   989	EAK	Random hacking.
 3/30/79   990	EAK	Added TR.NRM to make wrapping work.  Also changed
			%FNxxx computation in SETUP3 and TD.WIN.  It is now
			possible to have, for example, a TE.ICP entry which
			isn't used because of a %FNICP in TP.FLG (but that
			can be overriden by a CID in the command line).
			Also added %PIATY interrupt handler and DMOVE/DMOVEM
			macros.
 3/31/79   991	CBF	VT100  hacking.
 3/31/79   992	EAK	Rewrote ORDNRY, SCHO, CCHO to be faster.
 3/31/79   993	EAK	Added TE.EIM and TE.LIM.
 4/01/79   994	EAK	Fixed bug in %PIATY interrupt handler.
 4/03/79   999	EAK	Numerous changes to everything.  Mostly completing the
			TNX SUPDUP code.
 4/09/79  1000	EAK	More changes for TNX SUPDUP code.  Sort of hacky
			at the moment.
 4/09/79  1001	EAK	Wrote FINI, QUIT, and PROCED.  Flushed C1FINI.
 4/10/79  1002	EAK	Fixed bug %TOLID/%TOCID bug in SETUP4.
 4/12/79  1003	EAK	Added more command character hackery.  Hacked CC.FWD.
 4/20/79  1004	CBF	Added VDM1 for Jerry Pournelle
 4/22/79  1005	CBF	Added H19
 4/22/79  1007	RWK	Added TH6416 for NEAL (he wrote it, this is a merge)
 4/24/79  1008	EAK	Fixed H2000 bug.
 4/24/79  1009	EAK	Added some %TX code to SWSMI.  Hacked ENTER/CMDCHR.
 4/25/79  1010	EAK	Fixed bug in H19DEC.
 4/27/79  1011	EAK	Added %FNEOL+%FNEOS to Xitex's TP.FLG.
 4/28/79  1013	EAK	Reduced padding for Teleray 1061.  TNX hackery.
 5/10/79  1015	EAK	Changed VT100 definition a fair amount.
 5/17/79  1017	EAK	Added CLEOL padding to T1061.
 5/18/79  1018	EAK	Fixed NO BELL, added VT100 visbel.
 5/28/79  1019	EAK	Added ANNARB and ADI60.
 5/29/79  1020	EAK	Added tabs to ANNARB support.
 5/30/79  1021	EAK	Added TEL3 for ELL.
 6/10/79  1022	EAK	Added TLC for AUTHOR.
 6/12/79  1023	EAK	Added PGA,GYRO's DD5200 code.
 6/18/79  1024	EAK	Added SOL20 for LEWIS! and DEVON.
 6/18/78  1025	EAK	Changed C1EOL and C1EOS to use Clear All.
 6/18/78  1026	EAK	Added I200 for MACRAK.
 6/19/79  1027	EAK	Changed SOL20 for DEVON.
 6/20/79  1028	EAK	Added VT52 simulation.
 6/21/79  1029	EAK	Added TNX JERR1 uuo for reporting JSYS failure returns.
 6/22/79  1030	EAK	Added real TYITOG for TNX, added SIBEBUG stuff.
 6/22/79  1032	EAK	Added more TNX error handling code.
 6/25/79  1034	EAK	Debugged TNX PTY and INT code.  TNX&STY&INT doesn't
			work because SIBE doesn't appear to work on PTY
			channels!  TNX&INT doesn't work because .TICTI
			doesn't leave interrupt character in input buffer!
 6/26/79  1036	EAK	Stopped using IVORY in favor of SECTIONs.
 7/05/79  1037	EAK	Fixed bug in TNX NET STYINI, CHNTAB definition,
			changed IQ120 to use CCHO, and fixed missing
			TE.EOL in SOL20 definition.
 7/09/79  1038	EAK	Added C1TYI.
 7/10/79  1039	EAK	CID option tells C100 support to use fixes for
			insert/delete character.
 7/11/79  1040	EAK	Changed SIMULATE default for TNX&STY to VT52.
 7/20/79  1043	EAK	Merged in HARV's TUBE1.5.
 7/21/79  1044	EAK	Added automatic login on TNX PTYs and open TTY:
			instead of TTYnnn.
 7/21/79  1045  EAK	Added ICMASK so DM2500 and T1061 input handlers can
			hack meta bits.
 7/22/79  1046  DCH	Added MIME.
 7/23/79  1047	EAK	Added NO LOGIN option for TNX&STY.
 7/27/79  1048	EAK	Fixed H19 per MT's request.
 7/28/79  1049	EAK	Fixed SOL20 and TUBE1.5 per requests.
 7/28/79  1050	EAK	Moved VTABS to utility section, added TYODEC utility.
 7/31/79  1052	EAK	Merge several insert/delete lines in VT52 simulation.
 8/01/79  1053	EAK	Added PURIFY routine for TNX.
 8/12/79  1055	EAK	Added code to handle too many insert/delete
			lines/characters.
 8/14/79  1056	EAK	Added fair share to wholine, updated option listing,
			change ICP to be to SUPDUP socket, made TNX TYIPUF and
			SMIPUF better, and added %FSPD to H19 flags.
 8/16/79  1057  CBF	Added HP2621 from HP2645 definition
 8/16/79  1058	EAK	Added more comments, fixed %PIATY bug, hacked FRCV
			to handle non-existant receive fork.  Added REINIT
			and NO FLUSH.
 8/16/79  1059	EAK	Divided INT conditional into TINT and SINT for
			TTY and STY.  Got TTY input interrupts to work.
 8/21/79  1065	EAK	Add ITS network code.  Still needs work.
 8/22/79  1066	EAK	Added TNX WHOLINE code.  Fixed up VT52 simulator.
 8/23/79  1067	EAK	Added a few .XCREFs.
 8/31/79  1069	EAK	Added load average to TNX WHOLINE.
 9/04/79  1075	KLH	Fixed bug in LP, TDDLP.  Cvtted LP to TNX.
			Added TYIPUC routine to centralize cmd-char check.
 9/05/79  1081	KLH	Put in kludge code to make SIBE work with TINT.
			Added IBUFIP.
 9/09/79  1084	EAK	Added IQ140 for JAC.
 9/11/79  1085	EAK	Fixed IBUFIP.
 9/12/79  1086	EAK	Lots of little changes all over.  Fixed TM.NLs
			that used TYN instead of TYO.  Re-ordered JCOPTs
			and :CRTSTY ? listing.  Renamed CLEOS to
			STEOS and added NO CLEOL and NO CLEOS.  Moved MOVC20
			label to right place.  Bummed an instruction from
			CC.TAB.  Deleted H200 and H2LOSE CLEOL routines.
 9/13/79  1087	CBF	Added Perkin-Elmer Bantam
 9/27/79  1088	EAK	Added chaosnet code.
10/01/79  1089  CBF	Made DM2500 cancel modes at initialization time
10/13/79  1090	CBF	Added IBM 3101.
10/23/79  1091	EAK	Fixed bugs in IBM 3101.
11/02/79  1092	EAK	Conditionalized stuff in VTTYI on ITS\NET.
11/12/79  1093	EAK	Added VT52 absolute positioning hack to VT52 simulation
12/03/79  1094  HIC	Fixed some bugs in BANTAM support.  Still needs work.
12/11/79  1095	EAK	Added AAB for AQE (another Ann Arbor!).  Also
			changed TR.NRM to be just for horizontal wrapping.
12/13/79  1096	EAK	Added %TDRSU/%TDRSD code.  Not tested yet.
12/20/79  1100	RWK	Added TE.SU entry for H19, made TE.INI reset auto-CR
			and turn on the cursor!  Flushed losing DELPHI spec
			which was never finished and useless now anyway.
			Added TX.WE, TX.WB, TX.WI, and TR.WHO, and gave H19 a
			TR.WHO to use the 25'the line.
12/21/79  1101	EAK	Changed around new wholine stuff.  Fixed several bugs
			in it (probably introduced a few).  TP.WHO kludge
			eliminated in favor of TR.WI.
 1/13/80  1109	EAK	Added %TDRSU/%TDRSD code.
 1/24/80  1110	EAK	Fixed a 20X TT%PGM bug.
 1/29/80  1111	EAK	Turn on %TPRSC when %TOLID turned on.  Fixed bug
			at XDLP4 that caused random lossage sometimes.
 1/30/80  1112	EAK	Added TR.FIN for H19 to prevent cursor from
			being left on status line.
 1/30/80  1113	EAK	Fixed bug in STYIP that prevented one character of
			the input stream from being read!
 2/07/80  1114	EAK	H19 wholine bug fix.
 3/30/80  1122	CBF	Installed RLL's first cut at VT132.
 4/18/80  1125	EAK	Added gross padding to VT132.
 5/07/80  1127	EAK	Increased C100 insert/delete line padding a bit.
 5/23/80  1129	EAK	Changed IQ140 insert/delete codes for JAC.
 5/25/80  1130	EAK	Fixed H19 25th line problems with 20X SUPDUP version.
 6/08/80  1133	CBF	Added TVI912 for DBK, put IQ120,140 in alpha order.
 6/21/80  1138	CBF	Added AJ510 for GNU, installed BKD's Cromem 3101
			Had to up MAXTRMs from 80.!  Set it to 120.
 6/27/80  1142	EAK	Added CSK's VT05 code and removed RLJFN from PURIFY.
 7/12/80  1144	CBF	Couldn't resist the amusement of adding DWARME's ACT-II
			commented out due to CRTSTY lossage
 7/30/80  1150  CBF	Added VIP7800 for MAXB
 8/5/80	  1152	CBF	The problem with the ACT-II and the VIP7800 was due
			to Midas limits on constants.  EAK made a new version
			on MC which fixes it.  In celebration I added, KTM2
			for MAXB, DG200 for JJK and INtertec-S for JWP.
			ACT-II & VIP7800 should work now also.
 9/8/80	  1162  RLL	Added support for the AAA (Ann Arbor Ambassador)
			terminal.  There is no padding, but that might
			change when it's tried out on the terminal.
 9/9/80	  1167	EAK	Fixed up AAA support a bit.  Added TYOANS & TYNANS
			UUOs.
11/1/80	  1176	CBF	Added ADM-31 for Stever
12/30/80  1187	EAK	Fixed bug in TDICP.
 1/4/81   1188	EAK	Added AUTONL option.
 1/6/81   1189	EAK	Fixed bug in TD.IC.
 1/7/81	  1192	RWK	Fixed up AAA, added padding to CLEOS, and made it
			always use absolute positioning, since as near as I can
			tell the move forward and backwards commands don't work
			in random cases.  Sounds unbelievable, and I'll try
			hacking it some other time.
 1/9/81   1193	EAK	Fixed but in WHOOUT that caused H19 wholines and
			SMEOL to lose together.
1/14/81	  1197	RWK	Hacked up on AAA.  Will try the Move Horizontal Relative
			command instead of the Forward Cursor, and see if that
			works.  Made it set mode to ensure clear screen actually
			clears, even if there are protected fields.  Determined
			that the clear-screen command cannot work at 9600 baud
			since it does not home up until after the padding is
			done and it puts characters at the cursor as it moves
			the cursor (or some such lossage).  I.e. if you make it
			pad for 2 seconds, the screen clears, the cursor frobs
			away at the bottom of the screen while padding happens,
			a few characters are placed partway up the screen, and
			then finally the rest make it to the top.  Probably a
			bug in the ucode, not an inherent flaw....
			Probably the padding needs to be adjusted according to
			the screen size.
2/4/81	 1198	BEE	Fixed AAA to set the screen size correctly. Also why is
			the tab setting commented out?
3/6/81   1208	EAK	Fixed H19 problem with CRTSTY --> prompt and
			redisplay.
3/7/81   1209	EAK	Wasn't good enough; another try.
3/15/81  1210	EAK	Fixed up ITS network code to install a SCRTSTY.
5/5/81   1219	EAK	Added KTM3 for ELF.
8/21/81  1236   LRH     Added VISBEL to KTM3 and comments for ADM2
8/21/81  1237   LRH     Fixed bug caused by code added in 1236
9/9/81	 1238	CBF	Added ADDS viewpoint, changed ADS100 to make it work?
11/8/81	 1242	GNU	Fixed VT132 enter/exit insert (reversed), standout.
11/8/81  1243	EAK	Added ADDS25 for RMS (EMACS user request).
11/9/81  1244	GNU	Added ENTER C to send control chars user can't make.
			Also fixed VT100 VISBEL.
11/19/81 1246	CBF,EAK	Added ISC800 for FJW.
11/21/81 1248	EAK	Worked on Ambassador code a little.
12/25/81 1250	CHIRON	Cleaned up some Chaos code.  Can now use TINT&CHAOS
	                without spurious error messages.  When Chaos
			host breaks connection, CRTSTY handles it
			properly.  Added ADM5 terminal (per best
			documents available).  Attempted to make Chaos
			code interupt driven (CHAOS&SINT&TINT), but
			Twenex seems wedged. 
 1/6/82	 1254	CHIRON	Fixed ADM5 Definition.
 3/27/82 1257	RWK	Visibel for AAA
 3/27/82 1259	RWK	JRTR6F was making caller skip instead of self, so
			:AAA ... would kill itself rather than assume AAA.
 3/27/82 1260	RWK	AAA -- Fixed standout mode to work with inverse video,
			made wholine use it.
 4/4/82	 1264	RWK	AAA: Fixed wholine to use standout mode on all of the
			wholine, including the part initially drawn.  Make
			VISBEL not un-invert it.
 4/21/82 1270	CHIRON  Fixed ADM5 definition to be 80x24.  Users are 
			should run with auto-NL off, and perhaps tell CRTSTY
			to only use 79 columns.
 4/27/82 1271   LRH     Changed KTM-3 bell code to use new bell character.
 8/16/82 1272	CBF	Added Lunar for Moon's terminal.
 9/20/82 1273	CAH Fixed VIP7800 tab setting.
 1/03/83 0930	CAH Fixed VIP7800 at end of line.
 2/22/83 1277   EBM Added Kimtron ABM-85 terminal, a slightly hacked TVI920
11/22/83 1281	KLH	Merged in TCP/IP for 20X.
12/03/83 1294	KLH	Added META, speed options; partial-match JCL;
			fixed LP simulate, cleaned up variousness.
12/08/83 1309	KLH	Added many comments & did some cleanup.  Renamed some
			stuff.  New runtime command stuff.
03/15/84 1347	GRUPP	Fixed ADDS25 to work in either page or scroll mode.
			Added VIS50, a Visual 50.
07/02/84 1348   CBF	Put obnoxious warning message in for AAA --
	                telling user he'd rather use TCTYP
08/02/85 1374	GUMBY	Fix AJ5 to use decimal cursorpos for TYSON
05/31/86 1376	GUMBY	Add obnoxious warning like above for h19 losers

History:		; This is here for the TAGS package to find where to
			; add new history entries
~

subttl	Things-to-do

comment ~	To Be Done (someday)?:
	Not all of these things are, of course, realistic.

Fix metizer and controlizer runtime commands so that unusual chars
are properly echoed.  Current code just sends back to terminal, which
can really screw it up for control chars etc!

Extend NVT and TELNET operation to permit transparent/binary connections.
	Probably want the following modes:
	INPUT (User to remote host)
	A. Fully transparent (binary mode) 8-bit bytes from terminal
	B. Semi-transparent - binary mode, 7-bit bytes from terminal
	C. Normal (not binary mode), 7-bit bytes from terminal.
		CRs should be followed by NULs.

	OUTPUT (Remote host to user)
	A. Fully transparent (binary mode) - 8-bit bytes from net, sent to term
	B. Semi-transparent (binary mode) - 8-bit bytes from net, 7 bits to TTY
	C. Normal direct (not binary mode) - 7 from net, 7 to TTY, no interp.
	D. Opaque - 7 from net, let OS handle output controls.
	E. CRTSTY - 8/7 from net, CRTSTY manipulates TTY.
	F. NVT - ignore anything not part of NVT output set.

Provide equivalent IPSCAL capability for other direction, i.e. TYI/SMI asks
SMO/TYO to do something (not just freeze).  This would solve LP's
problem of finalizing mouse cursor position.
May want to have interrupt insert a JRST or CALL into an impure
location that inferior loop always goes through.

Maybe redo naming conventions for modules, to make more consistent
and easier to remember:
			Simulation/Emulation	Support
	Input stream	ISM,ISE,IEM,IPY		ISP,ISS,ITY
			PYO,SYO,SMI,SIS		TYI,,,TIS
			ISS,ISP,PIS		IST,,TIS
			ISO			ISI

	Output stream	OSM,OSE,OEM,OPY		OSP,OSS,OTY
			PYI,SYI,SMI,SOS		TYO,,,TOS
			OSS,OSP,POS		OST,,TOS
			OSI			OSO

	sbout< <smoget  tyiput< <tbin		; Standardize bin/bout for I/O
	sbin>  >call	td.xx> >tbout

	smoput< <smoget	tyiput< <tyiget		; Standardize modget/modput
	smiget>  >call	td.xx>   >tyoput

	sbout< <smiget	tyiput< <tbin		; Reverse SMI/SMO with bin/bout
	sbin>  >call	td.xx	>tbout

	smiput< <smiget	tyiput< <tyiget		; Reverse SMI/SMO with get/put
	smoget>  >call	td.xx>  >tyoput

	smibout< <smiget tyiput< <tyibin	; Rev SMI/SMO with modbin/bout
	smobin>  >call	td.xx>  >tyobout


New JCL option: META.
	Fix META-bit processing.  Escape becomes meta-^@.
	Allow site-dependent frobs, eg at SRI, most Dm2500's have
		an EDIT key.
	For ITS, check %TPMTA of controlling TTY so can automatically
		enable it?  Does super-image input mung the 8th
		bit if %TPMTA is set?

Add support for %TOOVR terminals.

Make tabstop setter more general, have "set-tab" terminal-table entry
as well as "clear-tab" (or "clear-all-tabs") or something.

MOVCUR Optimizer - variable-size tab calculations?

Figure how to have efficient distinction between
a) neither atomic nor simulate exist.
b) atomic commands, no simulate
c) no atomic, uses simulate.
d) atomic cmds exist, but shorter simulate also exists.
(assmption is that a longer-than-atomic simulate will never want
to exist!)

Separate universal term flags into LH of F, dependent flags into RH
(or define mask range for them)

Store line sum counts in front of SCREEN?  For easier check-EOL-ing;
not hard to do, but saving may be trivial.

Must remember MODE that terminal is in; some terms have many different
modes with different ways of exiting each.  (upon entry to mode, store
vector to getting out of mode?)

CRTSTY test program?  either routine in CRTSTY, or program using ^P
codes? (or program feeding it software codes directly? 2 sty's in a row...)
see KLH;CRTEST >

Detach sty when tty disappears.  May need more ITS support.

Check %TANJS bit of STYGET call?  Or somehow detect when the ^Z sent to
STY isn't getting a hactrn; this could be a big loss if it
hangs up crtsty forever.

Debug script file.  normal feedthru chars all on one line, all 2xx
chars given as:
<crlf> <octal> <name of %TD> | <oct>..<oct>  move h,v -> nh,nv
			   (chars sent)	(description)
~

subttl	Definitions

IF1 {
$$ask==0	; Normally don't ask questions, use current system.
its==1		; Allow these two systems
tnx==1
.insrt system
} ; IF1

ifndef sty, sty==0		; STY device output
ifndef net, net==0		; NET device output (i.e. a TELNET or SUPDUP)
ife sty\net, sty==its ? net==1-sty	; If neither specified,
				; Default to STY on ITS, NET otherwise.

ifndef tint,tint==its\20x	; 1= Input stream driven by TTY input interrupt
				;	(TENEX loses here)
ifndef sint,sint==its\<20x&sty>	; 1= Output stream driven by STY/NET input
				;	interrupt
ifn net,{
	ifndef tcp, tcp==1	; Use TCP, not NCP, if NET.
	ifndef ncp, ncp==<1-tcp>
	ifndef chaos, chaos==1
}
ife net, ncp==0 ? chaos==0 ? tcp==0

; The SIBEBUG hack is necessary because SIBE returns the wrong # of bytes for
; some kinds of input.  Specifically it loses for TENEX PTY/NET input and for
; TOPS-20 NET input.  Evidently it does work for TOPS-20 PTYs now.
; Basically if SIBEBUG is set, input from the PTY/NET must be read in a
; byte at a time, and only if SIBE doesn't skip.  This of course makes
; for pretty gross inefficiency.
ifndef sibebug, sibebug==10x\<20x&net>

ifndef histohack, histohack==0	; 1 to enable histogram cnt of chars by value

F=:0		; AC of flags
A=:1		; A-E are used for arguments and return values.
B=:2		; In general these ACs are preserved across subroutine calls.
C=:3
D=:4
E=:5
Z=:6		; Random MOVCUR AC
CP=:7		; Cursor motion hack stack
V=:10		; "Actual" current vertical position
H=:11		; "Actual" current horizontal position
VH==:V		; VH refers to the pair V,H
NV=:12		; "New" virtual positions
NH=:13		; "New" virtual positions
NVH==:NV	; NVH refers to the pair NV,NH
T1=:14		; temporaries, not saved by UUOs, subroutines, or macros
T2=:15		; ...
		; 16 unused!
P=:17		; PDL pointer

.XCREF F,A,B,C,D,E,V,H,NV,NH,T1,T2,P


; ACs for .I/.F
A0==:T1
A1==:T2


IFN ITS,{
; I/O channel assignments.
tyon==:2	; Console terminal output during startup
pbout==:<.iot tyon,a>	; Hack for reducing conditionals!

tyic==:3	; Input from supported terminal (Superimage)
tyoc==:4	; Output to supported terminal (Superimage)

ifn net&ncp, icpch==:5	; ICP channel, PYI/PYO must be ICPCH+2/ICPCH+3

pyi==:7		; Input from sty/net (some program outputting to TTY)
pyo==:pyi+1	; Output to sty/net (some program reading typein from TTY)

dsko==:12	; channel for various disk outputs.
} ; IFN ITS


; F flag values, LH (see TRMFLG for RH values)

; These flags used for setting bucky-bit input.
%imeta==400000	; For input, metize next char
%itop== 200000	; topify next char
%ictrl==100000	; controlify
%imtc==%imeta+%itop+%ictrl
%ipesc== 40000	; Indicate ESC key seen (preceding current)
%ipesq== 20000	; Indicates ESC-? (for VT terms)

%ipcts== 10000	; for ^S/^Q hacking by RPVT52
%clpnd==  4000	; 1 => CLEOL pending
%icm==:   2000	; insert character mode

IFN TNX, IF1 EXPUNGE DTI

ifndef maxver,maxver==70.	; max value for vertical screen size (SHEIGHT)
ifndef maxhor,maxhor==140.	; max value for horizontal screen size (SWIDTH)

IFE ITS\.ITS,{
;NOW COME THE BITS OF THE CHARACTER ITSELF:
%TXTOP==:4000	;"TOP" KEY.
%TXSFL==:2000	;"SHIFT-LOCK" KEY.
%TXSFT==:1000	;"SHIFT" KEY.
%TXMTA==:400	;"META" KEY.
%TXCTL==:200	;"CONTROL" KEY.
%TXASC==:177	;THE ASCII PART OF THE CHARACTER.

%TNPRT==:0	;PRINTING TTY.
%TNDP==:1	;TTY USES DATAPOINT CURSOR CTL CODES.
%TNODP==:2	;TTY IS A LOSING DATAPOINT.
%TNIML==:3	;TTY USES IMLAC CURSOR CODES.
%TNTEK==:4	;TEKTRONIX 4000 SERIES
%TNTV==:5	;TTY IS A KNIGHT TV DISPLAY.
%TNMEM==:6	;TTY IS A MEMOWRECK.
%TNSFW==:7	;"SOFTWARE" TTY THAT WANTS I.T.S. CURSOR-MOTION CODES.
%TNTRM==:10	;TTY IS A TERMINET.
%TNESC==:11	;TTY WANTS ASCII STANDARD ESCAPE SEQUENCES. (E.G. VT52)
%TNDTM==:12	;DATAMEDIA
%TNMAX==:13


;TTYOPT WORD DESCRIBES CHARACTERISTICS OF THE PARTICULAR
;TERMINAL ATTACHED TO EACH LINE.

;LEFT HALF BITS ARE:
%TO==:1,,525252		;BIT TYPEOUT MASK
%TOALT==:200000	;4.8 => STANDARDIZE ALTMODES.
%TOCLC==:100000	;4.7 => CONVERT LOWER CASE TO UPPER.
%TOERS==:40000	;4.6 => THIS TTY CAN SELECTIVELY ERASE.
%TOHDX==:20000	;4.5 => THIS TTY IS HALF-DUPLEX.
$TOHDX==:370100
%TOMVB==:10000	;4.4 => THIS TTY CAN BACKSPACE.
%TOSAI==:4000	;4.3 => THIS TTY HAS SAIL CHAR SET ON OUTPUT.
%TOSA1==:2000	;4.2 INIT %TSSAI OF NEW JOBS.
%TOOVR==:1000	;4.1 => THIS TTY CAN OVERPRINT SUCCESSFULLY.
%TOMVU==:400	;3.9 => THIS TTY CAN MOVE CURSOR UP (I.E. IT'S A DISPLAY).
%TOMOR==:200	;3.8 => DO **MORE** PROCESSING ON THIS TTY
			;(ACTUALLY JUST USED TO INIT %TSMOR FOR NEW JOBS).
%TOROL==:100	;3.7 SIMILARLY, INIT %TSROL FOR NEW JOBS.
%TORAW==:40	;3.6 => SUPPRESS CURSOR MOTION OPTIMIZATION.
%TOLWR==:20	;3.5 => THIS TTY HAS LOWER CASE KEYBOARD.
%TOFCI==:10	;3.4 => KEYBOARD CAN GENERATE FULL 12-BIT CHARACTER SET
%TOIML==:4	;3.3 => SPACE, BS DON'T EQUAL ^PF, ^PB; ALSO ^PC SENDS ^L.
%TOLID==:2	;3.2 => %TDILP, %TDDLP WORK (INSERT AND DELETE LINES)
%TOCID==:1	;3.1 => %TDICP, %TDDCP WORK (INSERT AND DELETE CHARACTERS)

;RIGHT HALF:
%TP==:707252		;BIT TYPEOUT MASK
%TPPLF==:100000
$TPPLF==:170300	;3-BIT FIELD SAYING HOW TO PAD LF.
			;0 - DON'T. 1 - MEMOWRECK, 2741. 2 - TERMINET.
%TPPCR==:10000
$TPPCR==:140300	;3-BIT FIELD SAYING HOW TO PAD CR.
			;7 - UNUSED. 6 - MEMOWRECK. 5 - 2741. 4 - EXECUPORT.
			;0 - DON'T. 1 - NORMAL. 2 - DOUBLE.
			;ON DATAPOINTS, = # CHARS PADDING NEEDED FOR ALL CURSOR MOTION.
			;4 IS RIGHT FOR 2400 BAUD; 3, FOR 1200.
			;ON TERMINETS, 0 => NO PADDING, ELSE a,2,3,4,5
			;ARE PADDING FOR SPEEDS 10,15,30,60,120 CPS.
%TPPCW==:6	;FOR MEMO WRECK.
%TPPTB==:1000
$TPPTB==:110300	;3 BIT FIELD SAYING HOW MUCH PADDING NEEDED AFTER TAB.
			;0 => TABS NOT ALLOWED; ELSE 1 +<# PADDING CHARS NEEDED>
			;BUT ON A DISPLAY, TABS ARE NEVER PADDED AND THIS FIELD IS
			;1 TO USE TABS, 2 TO USE ABSOLUTE CURSOR POSITIONING,
			;3 TO USE BOTH, 0 TO USE NEITHER.
%TPMTA==:400	;1.9 => treat bit 1.8 of input characters as the meta bit.
%TPPRN==:200	;1.8 => INTERCHANGE () WITH [] ON INPUT
%TPTEL==:100	;1.7 => HANDLE CR-LF ON INPUT AS CR, FOR TELNET PROTOCOL
%TPCBS==:40	;1.6 => ENABLE SPECIAL HANDLING OF CONTROL BACK SLASH ON INPUT
			 ;(THE "INTELLIGENT TERMINAL PROTOCOL").
%TP11T==:20	;1.5 => PDP-11 TV TTY. REFLECTS %TY11T.
			;NOT SETTABLE BY USER.
%TPORS==:10	;1.4 => OUTPUT RESET ON THIS TTY SHOULD REALLY DO SOMETHING.
%TPRSC==:4	;1.3 => THIS TTY SUPPORTS %TDRSU, %TDRSD
} ; IFE ITS\.ITS

subttl	Macros

; Make use of some winning macros.

ifn its, .insrt syseng;$call macro

%%%asc==:1			; use winning ASCNT
ifn .its, .insrt klh;macros >
ife .its, .insrt macros

call=:<pushj p,>		; saves typing
return=:<popj p,>
;pjrst==:jrst			; CALL FOO ? RETURN
paoja==:aoja			; ADDI AC,1 ? CALL FOO ? RETURN
.xcref call,return,pjrst


define	movx #ac,con
ife con&#777777, movei ac,con ? .stop
ife con&777777,  movsi ac,(con) ? .stop
	move ac,[con]
termin

IFNDEF KA,KA==1-20X

IFN KA,{
IF1 {
define	dmove ac,m
	ac ? m
termin
equals dmovem,dmove
equals fltr,dmove
} ; IF1
IF2 {
define	dmove #ac,m
ifn m&20000000, .err DMOVE macro can't hack indirection
	move ac,m
	move ac+1,m+1
termin

define	dmovem #ac,m
ifn m&20000000, .err DMOVEM macro can't hack indirection
	movem ac,m
	movem ac+1,m+1
termin

define	fltr #ac,m
	move ac,m
	fsc ac,233
termin
} ; IF2
} ; IFN KA


define	say &string&
	move t1,[ascnt string]
	call typasc
termin

define	saycr &string&
	move t1,[ascnt string]
	call typasc
	call typcr
termin

; SLEEP - Macro to sleep <argument> tenths of a second.  Clobbers A.
IFN ITS,{
define	sleep t
	movx a,t*3.
	.sleep a,
termin
} ; IFN ITS
IFN TNX,{
define	sleep t
	movx a,t*100.
	disms
termin
} ; IFN TNX

IFN 0,{
.defmac ivar			; tell @ that IVAR defines its argument
.defmac mvar			; tell @ that MVAR defines its argument
.defmac tvar			; tell @ that TVAR defines its argument
.defmac svar			; tell @ that SVAR defines its argument
}

define	inform a,b,c,d,e,f,g
	printx á!b!c!d!e!f!g
Š
termin

define	section name
$sect
loc name
define	$sect
name==.
termin
termin

; Start off with SECTION MAINVAR.
define	$sect
mainvar==.
termin


init==	0+<22.*2000>		; leave 22K for variables and screen images
initvar==init+<5*2000>		; leave 5K for initialization section
main==	initvar+<1*2000>	; leave 1K for initialization variable section

;fmvpg==:0			; First MAINVAR page
fipg==:init/pg$siz		; First INIT page
fivpg==:initvar/pg$siz		; First INITVAR page
fmpg==:main/pg$siz		; First MAIN page


IFN 0,{
define	mvar v1,v2,v3,v4
  irp v,,[v1,v2,v3,v4]
    irps s,c,[v]
      s=:mainvar
      ifse [c][] mainvar==mainvar+1 ? .istop
      irpnc <.length "s">+1,<.length "v">-<.length "s">-2,1,l,,[v]
	mainvar==mainvar+<l>
      termin
      .istop
    termin
  termin
termin
}
.ELSE {
equals mvar,.scalar		; .SCALAR is presumably faster, so use it in
				; place of MVAR since it occurs most often
}

define	ivar v1,v2,v3,v4
  irp v,,[v1,v2,v3,v4]
    irps s,c,[v]
      s=:initvar
      ifse [c][] initvar==initvar+1 ? .istop
      irpnc <.length "s">+1,<.length "v">-<.length "s">-2,1,l,,[v]
	initvar==initvar+<l>
      termin
      .istop
    termin
  termin
termin

equals tvar,mvar
equals svar,mvar

subttl	Part I - Initialization
subttl	Purification


patch:	pat:	block 40	; patch area
debug:	0			; set positive for any runtime debug switching

prgnam:	IFN NET,ascnt "CTN"
	.else	ascnt "CRTSTY"
constants
SECTION INIT

IFN ITS,{
; Use PURIFYG to purify CRTSTY before dumping.
purify:	move a,[<sipg-fipg>,,sipg]	; flush screen image pages
	$call corblk,[#0,#%jself,a]	; ...
	 .lose %lssys
	move a,[-<lipg-fipg+1>,,fipg]	; purify INIT pages
	$call corblk,[#%cbndr,#%jself,a]
	 .lose %lssys
	move a,[-<lmpg-fmpg+1>,,fmpg]	; purify MAIN pages
	$call corblk,[#%cbndr,#%jself,a]
	 .lose %lssys
IFN STY,{
	.value [asciz ": Purified, now dump...
:PDUMP DSK:SYSBIN;CRTSTY BIN"]
}
IFN NET,{
	.value [asciz ": Purified, now dump...
:PDUMP DSK:SYSBIN;CTN BIN"]
}
} ; IFN ITS
IFN TNX,{
IFN 20X,{	; T20 EXEC does SAVE properly, retains page access bits.
purify:	move p,[-lpdl,,pdl-1]	; set PDL pointer
	move a,[-<lipg-fipg+1>,,fipg]	; INIT pages
	call purifp
	move a,[-<lmpg-fmpg+1>,,fmpg]	; MAIN pages
	call purifp
	haltf			; Purified, done.
	jrst crtsty

	; Purify pages, given AOBJN ptr to same.
purifp:	pushae p,[b,c]
	skipl c,a
	 jrst purif9
	hrli a,.fhslf
	movsi b,(pa%rd+pa%ex)	; Permit read/execute only.
purif2:	hrri a,(c)
	spacs			; Do it!
	aobjn c,purif2
purif9:	popae p,[c,b]
	return

} ;IFN 20X

IFN 10X,{	; TENEX EXEC is stupid about SSAVEing with same access,
		; so must do the save ourselves.
purtab:	-sipg,,ss%cpy\ss%rd\ss%exe\0			; MAINVAR pages
	-<lipg-fipg+1>,,ss%rd\ss%exe\fipg		; INIT pages
	-<livpg-fivpg+1>,,ss%cpy\ss%rd\ss%exe\fivpg	; INITVAR pages
	-<lmpg-fmpg+1>,,ss%rd\ss%exe\fmpg		; MAIN pages
	-<512.-<lmpg+1>>,,ss%rd\<lmpg+1>	; symbol table pages
	0

purify:	move p,[-lpdl,,pdl-1]	; set PDL pointer so can use error UUO
	movei a,.fhslf		; SEVEC arg: A = process handle
	move b,[1,,crtsty]	; SEVEC arg: B = length,,address
	sevec			; set entry vector
	move a,[gj%sht+.fvers]	; GTJFN arg: A = bits,,default version
IFE STY,{
ifn 20x, hrroi b,[asciz "CRTSTY.EXE"]
ifn 10x, hrroi b,[asciz "CRTSTY.SAV"]
}
IFN STY,{
ifn 20x, hrroi b,[asciz "PCRTSTY.EXE"]
ifn 10x, hrroi b,[asciz "PCRTSTY.SAV"]
}
				; GTJFN arg: B = filename
	gtjfn			; get JFN to CRTSTY save file
	 jerr1 [asciz "Unable to assign JFN - "]
	hrli a,.fhslf		; SSAVE arg: A = fork handle,,JFN
	movei b,purtab		; SSAVE arg: B = table address
	movei c,0		; SSAVE arg: C = flag bits
	ssave			; dump ourself
	haltf
} ; IFN 10X
} ; IFN TNX

subttl	Startup - Main init routine

crtini:	movei f,0		; initialize flags
	call osinit		; operating system dependent initialization
	call jclpar		; parse command line to get terminal type,
				; TTY no., etc.
	 jrst logout		; error in command line
	call ttyini		; Open TTY, initialize some options
	call jclpar		; Parse command line again, this time
				; for rest of options
	 jrst logout		; error in command line
	call ttyoin	; TTY output initialization
	call trmchk	; Check out the "support" terminal spec
	call trmini	; Set up parameters for supported terminal!
	call scrini	; Initialize screen image
	call simchk	; Check out "simulate" terminal spec
	call simini	; Set up initial params for simulated terminal (styini
			;   or netini may re-do this)

IFN STY,call styopn		; Open STY and get info about it.
IFN NET,{
	call netcnf		; Set up net protocol configuration stuff
	say "Trying..."
	call netopn		; Open net connection, set up info.
	saycr "Open"
	call netini		; Initialize (including negotiations)
} ;IFN NET
	call smiini		; Initialize SMI co-routine

IFN ITS&STY,setom cmdchr	; ITS CRTSTY has no command char.
.ELSE	movei t1,^^ ? movem t1,cmdchr	; All other cases

	setzb h,v		; Initialize both sets of cursor coords
	dmove nvh,wmin
	xct .trini+tb		; Initialize terminal (must clear screen,
				; reset window, leave insert mode)
				; See "Notes about Terminal-table entries"!!
ifn sty,call whoini
	call tyofrc		; Ensure all TTY output forced out

	skipl jsii		; NO SII specified?  Skip if so.
	 jrst [	skipg jsii	; SII specified?
		 skipg debug	; and DEBUG not specified?
		  call sii	; then use Super-Image Input.
		jrst .+1]
IFN ITS,.close tyon,		; don't need this any more
IFN NET,{
	skiple jattach		; ATTACH specified?
	 call attach		; Do it only if explicitly requested.
} ; IFN NET
IFN STY,{
	skipl jattach		; NO ATTACH specified?  Skip if so.
	 jrst [	skipg jattach	; ATTACH specified?  Do it by default.
		 skipg debug	; No.  Last check, don't attach if debugging
		  call attach	; Make ourselves top-level
		jrst .+1]
	skipg jslave		; SLAVE specified? Don't even ^Z (or ^C) if so.
	 jrst slogin		; Nope, so log in the STY.
				; See comments at SLOGIN which explain why this
				; has to be a JRST... stack becomes useless.
} ;IFN STY
	ret			; Return to non-INIT section to
				; perform final CRTSTY initialization

; Startup of initialization.
constants
SECTION MAIN

lpdl==100			; Length of PDL
mvar pdl(lpdl)			; PDL
mvar oncefl			; Once-only flag

; CRTSTY starts here!

crtsty:	skipe oncefl
	 jrst [	saycr "Restarting is not possible."
		jrst logout]
	setom oncefl
	move p,[-lpdl,,pdl-1]	; initialize PDL pointer
	call crtini		; Perform lots of once-only init.

	; All set up, now operate at interrupt level.
	call trmfls		; OK, now flush core pages of unused terms
	move a,[<fipg-fmpg>,,fipg]
IFN ITS&NET, skiple jflush	; For an ITS SUPDUP, keep ANALYZE around
IFE ITS&NET, skipl jflush	; NO FLUSH specified?
	 call corfls		; no, so flush unneeded pages.

	; Enable remaining interrupts: realtime and input.
IFN ITS,{
IFE TINT&SINT, .err No interrupts?
	move a,[600000,,[clkfrm]]
	.realt a,			; Set clock frame
	 jfcl
	move a,[-2,,[
		.simask,,[%pirlt]		; enable .realt interrupt
		.sadf2,,[1_pyi+1_tyic]		; undefer tyi, pyi ints
		]]
	.suset a

	; Now do all the work at interrupt level.
IFE STY,{
	jfcl			; hang around forever
	.hang			; ...
} ; IFE STY
IFN STY,{
	skipg jslave		; supposed to be slave?
	 jrst noslav
	jfcl			; slave, so hang forever
	.hang
noslav:	skipl @ttysts		; Wait until TTY becomes free
	 .hang
	.suset [.sidf2,,[<1_tyic>\<1_pyi>]]	; disable interrupts
	jrst quitng
} ; IFN STY
} ; IFN ITS

IFN TNX,{
IFE TINT\SINT,{
	; No interrupts to be used at all, so must start up inferior
	; fork to handle the Output Stream process (SMO+TYO).
	move t1,[iftlev,,iftint]	; create inferior fork termination
	movem t1,chntab+.icift		; handler
	move t1,[ipslev,,ipsint]	; Ditto to process "do" requests
	movem t1,chntab+ipschn		; from inferior fork.
	movei a,.fhslf			; AIC arg: A = fork handle
	move b,[<1_<35.-.icift>>\<1_<35.-ipschn>>]	; B = channel mask
	aic			; activate inferior fork termination
				; interrupt
irp x,,[f,nv,nh,v,h,p]
	movem x,acblk+x		; pass ACs to simulation input process
termin
	movsi a,(cr%map\cr%st\cr%acs)	; CFORK arg: LH A = control bits
	hrr a,.trsmo+tb		; RH A = start address (SMO module)
	movei b,acblk		; CFORK arg: B = AC block address
	cfork			; create simulation input fork sharing our
				; address space, start up output process.
	 jerr1 [asciz "Error creating inferior fork - "]
	; don't use stack until TYIINI!
	movem a,rcvfrk		; CFORK result: A = fork handle
				; RPCAP arg: A = fork handle
	rpcap			; read process capabilities
				; result: B = possible capabilities,
				; C = enabled capabilities
	tlo b,(sc%sup)		; allow simulation input fork to interrupt
	tlo c,(sc%sup)		; us
	epcap			; set process capabilities
	jrst tyiini		; Now go start the Input Stream process,
				; by initializing TYI module!
} ; IFE TINT\SINT

IFN TINT\SINT,{
	; Use interrupts for Input (and maybe Output) streams!
	; This means interrupting on TTY input and PTY (or NET) input.
	; TENEX cannot do this because it has no such thing as .TICTI
	; (interrupt on any typein), but TOPS-20 can.

	; If it is desired to have only one stream using interrupts, this
	; is only really do-able if the Input stream (TTY input) interrupts
	; and STY/NET input doesn't, because TTY input must always have
	; higher priority.
IFE TINT, .err TINT=0 and SINT=1 cannot work!

	move a,[ipslev,,ipsint]	; Set up handler for Input-Process level
	movem a,chntab+ipschn	;   reqs from Output Process.
	movei a,.fhslf		; AIC arg: A = fork handle
IFE SINT,move b,[<1_<35.-ttychn>>\<1_<35.-timchn>>\<1_<35.-ipschn>>]
IFN SINT,move b,[<1_<35.-ttychn>>\<1_<35.-timchn>>\<1_<35.-ipschn>>\<1_<35.-smochn>>]
				; AIC arg: B = channel mask
	aic			; enable TTY, timer, IPS, and maybe PTY interrupts
	movei a,.fhslf		; STIW arg: A = fork handle
	movx b,1_<35.-.ticti>	; STIW arg: B = terminal interrupt word
	movei c,0		; STIW arg: C = deferred interrupt word
	stiw			; interrupt on all characters
	movei a,.fhslf		; IIC arg: A = fork handle
IFE SINT,move b,[<1_<35.-ttychn>>]
IFN SINT,move b,[<1_<35.-ttychn>>\<1_<35.-smochn>>]
				; IIC arg: B = channels to interrupt on
	iic			; Fire initial interrupts to catch anything
				; that might have happened prior to AIC/STIW.
IFN SINT, wait			; Now do everything at interrupt level!
IFE SINT, jrst @.trsmo+tb	; Go to SMO module as main loop
				; for Output Stream process.
} ; IFN TINT\SINT
} ; IFN TNX

constants
SECTION MAINVAR

bughlt:	0		; Called by JSR BUGHLT for fatal errors
IFN ITS, .lose
IFN TNX,{
	hrroi 1,[asciz "Fatal CRTSTY error!  Check location BUGHLT/
"]
	psout
	haltf
	jrst .-1
}
SECTION INIT		; Revert to initialization code section

subttl	Operating system initialization

IFN ITS,{
osinit:	move a,[-lintpdl,,intpdl-1]	; initialize interrupt PDL
	movem a,intpdp		; ...
	setzm iocvec		; no IOC error handler yet
	move a,[-24.,,[
		.roption ? tlo %opint+%opopc	; turn on new style ints
		.roption ? movem option
		.rmask ? movei %piioc		; enable interrupts
		.rmsk2 ? movei 0		; ...
		.rdf1 ? movei 0			; and set defer words
		.rdf2 ? movei 0			; ...
		.rcnsl ? movem cnsl		; get console TTY no.
		.runame ? movem uname
		.rjname ? movem jname
		.ruind ? movem uind
		.rxuname ? movem xuname
		.rxjname ? movem xjname
		]]
	$call usrvar,[#%jself,a]
	 .lose %lssys
	.i ttynum=cnsl		; default TTY supported to our console
	$call open,[#tyon,[sixbit/tty/]][][#.uao]
	 .lose %lsfil		; Normal unit output to TTY
	hlrz a,uname		; get LH of uname
	cain a,-1		; not logged in?
	 jrst [	saycr "You must log in to use CRTSTY"
		jrst logout]

	move e,xjname		; JRTR6F arg: sixbit name
	call jrtr6f		; is XJNAME some terminal name?
	 setz a,		; No, so zap...
	hrrzm a,trmadr		; yes, set terminal to use.

	move a,option		; get OPTION variable
	tlnn a,%opcmd		; command for us?
	 jrst [	skipe trmadr	; No, barf unless terminal selected by xjname.
		 jrst .+1
		call cusage	; Barf politely.
		call dohelp
		jrst logout]
	move a,[jclbuf,,jclbuf+1]	; clear command line buffer
	setzm jclbuf		; ...
	blt a,jclbuf+<ljcl+4>/5-2	; ...
	movsi a,(ascii "
")	; put CR at end of command line buffer
	movem a,jclbuf+<ljcl+4>/5-1	; ...
	.break 12,[5,,jclbuf]	; get command line from superior
	call wrtlog		; Write log file entry with cmd line.
ifn histohack,	call histo

	move b,[squoze 0,%TDMAX]	; Find highest software code
	.eval b,
	 .lose %lssys
	caile b,%tdmax			; see if system has same ideas we do.
	 jrst [	saycr "Warning: Some display codes may not work.
Send mail to BUG-CRTSTY@MC about this!"
		jrst .+1]

	move a,[squoze 0,LUBLK]	; find length of a user-var block
	.eval a,
	 .lose %lssys
	movem a,lublk
	imul a,uind		; find position from start of user-var storage
	movem a,myuind		; save in case later need

	movei a,syspg
	movem a,syspno

	move a,[squoze 0,TIME]
	movei b,0
	call itsmap
	movem a,time

	move a,[squoze 0,APRC]
	move b,myuind
	call itsmap
	movem a,aprc

	move a,[squoze 0,SUPPRO]
	move b,myuind
	call itsmap
	movem a,suppro

	return
} ; IFN ITS

IFN TNX,{

osinit:	reset			; initialize system's data for this fork
				; (this does an automatic CIS so that's not
				; needed below)
	movei a,.fhslf		; RPCAP arg: fork handle
	rpcap			; read our capabilities
				; results: B = possible capabilities,
				; C = enabled capabilities
	tlo c,(sc%ctc\sc%gtb)	; turn on control-C intercept and
	epcap			; GETAB capabilities
	gjinf			; get job specific information
	movem a,ldir		; directory no. logged in under
	movem d,cnsl		; GJINF val: terminal no. associated with
				; this job (or -1 if detached)
	setom ttynum		; default to using TTY: instead of TTYnnn:
	move t1,[chntab,,chntab+1]	; zero channel table
	setzm chntab			; ...
	blt t1,chntab+35.		; ...
	movei a,.fhslf		; SIR arg: process handle
	move b,[levtab,,chntab]	; SIR arg: level table,,channel table
	sir			; set channel and level table addresses
	eir			; enable interrupt system
	setzm siiset		; no superimage input yet
; Get command line.
IFN 20X,{
	movei a,0		; RSCAN arg: 0 to read last string
	rscan			; put command line in input buffer
	 jerr1 [asciz "Error reading command line - "]
	movn c,a
	; skip over 1st word of command line
os1:	aojge c,os9		; nothing more to read?
	pbin			; get next character
	cain a,^J		; LF?
	 jrst os9		; yes, no real command line
	caie a,40		; space?
	 jrst os1		; no, keep going
	movei a,.priin		; SIN arg: A = source designator
	move b,[440700,,jclbuf]	; SIN arg: B = B.P.
				; SIN arg: C = -count
	sin			; read command line into command buffer
	movei a,^M		; replace LF at end of string with CR
	dpb a,b			; ...
} ; IFN 20X
IFN 10X,{
	movei a,.priin		; BKJFN arg: A = JFN
	bkjfn			; backup one character in input stream
	 jrst os0		; can't, oh well
	pbin			; get last character typed
	cain a,37		; CR?
	 jrst os9		; yes, no command line
os0:	move b,[10700,,jclbuf-1]	; byte pointer to command line buffer
os1:	pbin			; get next character
	cain a,37		; CR?
	 jrst os2		; yes, we're done
	cain a,177		; RUBOUT?
	 jrst [	camn b,[10700,,jclbuf-1]	; yes, nothing to rubout?
		 jrst [	movei a,^G	; nothing, PBOUT arg: character
			pbout		; feep at user
			jrst os1 ]	; keep reading
		ldb a,b		; get character rubbed out
		pbout		; echo it back
		add b,[70000,,0]	; decrement byte pointer
		jumpge b,os1		; ...
		sub b,[430000,,1]	; ...
		jrst os1 ]	; keep reading
	idpb a,b		; put character into command line buffer
	jrst os1		; keep reading
os2:	movei a,^M		; deposit an actual CR, instead of 37
	idpb a,b		; ...
} ; IFN 10X
IFN STY,{
	move a,[sixbit/ptypar/]	; SYSGT arg: SIXBIT table name
	sysgt			; get PTY information
				; results: A = first word of table,
				; B = table no.
	jumpe b,[		; no PTYPAR table?
		saycr "System lacks PTYs"
		jrst logout
		]
	hlrzm a,syspty		; no. of PTYs in system
	hrrzm a,firpty		; TTY no. of first PTY
} ; IFN STY
IFN NCP,{
	setzm lskt		; local relative socket no.
}
	return

os9:	call cusage		; Barf politely.
	call dohelp
	jrst logout

} ; IFN TNX

subttl	Output entry to CRTSTY log file

IFN ITS,{
wrtlog:	movei a,logint		; where to go if we get an IOC error
	movem a,iocvec
sretry:	syscal open,[ %clbit,,100000\.uao ? %climm,,dsko
		      [sixbit /DSK/]
		      [sixbit /CRTSTY/] ? [sixbit /LOG/] ? [sixbit /CRASH/]
		      %clerr,,a]	; get the error code
	 jrst [	cain a,%enafl		;   file locked?
		 jrst [	movei a,5	; sleep a bit
			.sleep a,
			jrst sretry ]	; and try again
		caie a,%ensfl		; file not found?
		 $call lose,[#%lsfil,#sretry]	; unknown error, hassle
		syscal open,[ %clbit,,.uao ? %climm,,dsko ? [sixbit /DSK/]
			       [sixbit /CRTSTY/] ? [sixbit /LOG/]
			       [sixbit /CRASH/]]
		 .lose %lsfil
		jrst .+1]
	$call fillen,[#dsko][a]	; find end of file
	 .lose %lsfil
	$call access,[#dsko,a]	; and start there
	 .lose %lsfil
	.rdatim a,		; get date and time
	move e,b		; hack the date first
	rot e,12.		; make MMDDYY
	movei b,"/		; separate by /'s
	call timprt		; print the time
	.iot dsko,[40]		; separate by a space
	move e,a		; hack the time now
	movei b,":		; separate by :'s
	call timprt		; print it
	.iot dsko,[40]		; space again
	move a,uind		; get job no.
	caige a,100
	 .iot dsko,[40]
	caige a,10
	 .iot dsko,[40]
	call numout
	.iot dsko,[40]
	move e,[.fnam1]
	call sixout		; output FN1 if strange.
	.iot dsko,[40]
	move e,[.fnam2]
	call sixout
	.iot dsko,[40]
	move e,xuname
	call sixout		; print it
	.iot dsko,[40]
	$call stlget,[#tyon][a,e]	; get the host
	 caia
	  jumpn e,log1
	move a,cnsl		; get terminal no.
	lshc a,-3		; convert to sixbit
	lsh a,3			; ...
	lshc a,3		; ...
	movsi e,'T00(a)		; convert to device name
log1:	call sixout		; print it
	.iot dsko,[40]
	.iot dsko,[40]
	move a,[440700,,jclbuf]	; BP to the command buffer
logcmd:	ildb b,a		; get a char
	caie b,^M		; end of line?
	 cain b,^C		;   Another form of end of line
	  jrst logcls		;     yes, close up the line
	caie b,^_		; still another form of end of the line
	 cain b,0		;  yet another
	  jrst logcls		;   so close up the line
	.iot dsko,b		; no, output it
	jrst logcmd		; and do another

logcls:	.iot dsko,[^M]		; new line
	.iot dsko,[^J]
logint:	.close dsko,
	setzm iocvec		; remove IOC error handler
	return


numout:	push p,b
	idivi a,10
	caile a,0
	 call numout
	addi b,"0
	.iot dsko,b
	pop p,b
	return

sixout:	movei b,6
	call prtdig		; print a character
	sojg b,.-1
	return

; SIXDO - output sixbit in E cleverly to disk; always outputs
; at least one char (a blank if word 0).
sixdo:	movei d,0
	lshc d,6
	addi d,40
	.iot dsko,d
	jumpn e,sixdo
	return

timprt:	call prt2dg		; print two digits
	.iot dsko,b		; and the delimiter
	call prt2dg		; print two more digits
	.iot dsko,b		; and the delimiter
	pjrst prt2dg		; and the final portion

prt2dg:	call prtdig
prtdig:	movei d,0
	lshc d,6
	addi d,40
	.iot dsko,d
	return
} ; IFN ITS

IFN ITS&HISTOHACK,{

histch==17

histo:	$call open,[#histch,[sixbit/DSK/],[sixbit/.CHAR/],[sixbit/.COUNT/]][][#.bio]
	 .lose %lsfil
	movsi t1,-256.
	.iot histch,t1
	.close histch,
	$call open,[#histch,[sixbit/DSK/],[sixbit/.CHAR/],[sixbit/.COUNT/]][][#.uio+100000]
	 .lose %lsfil
	$call corblk,[#%cbndw+%cbndr,#%jself,#histpg,#histch,#0]
	 .lose %lssys
	move t1,[counts+0,,counts+1]
	setzm counts+0
	blt t1,counts+256.-1
	return
}

subttl	Command line processing

ljcl==:120.			; length of command line buffer
ivar jclbuf(<ljcl+4>/5)		; command line buffer
ltoken==:20.			; option buffer length
ivar token(<ltoken+4>/5)	; option buffer
ivar cmdysw			; Holds +1 for YES, -1 for NO.


jclpar:	move a,[440700,,jclbuf]	; initialize pointer to the command buffer
	movem a,jclp
	hllz f,f		; Clear terminal flags.
jclp01:	setom cmdysw		; Set state to YES by setting -1 then negating
jclp02:	movns cmdysw		; Come here to reverse state.
	call jclf		; pick up next token
	 jrst popj1		; EOF, return2 from JCLPAR for winnage
	move d,token		; get 1st word of token
	camn d,[asciz /NO/]	; requesting opposite state?
	 jrst jclp02		; Yes, negate state & get next field.
	move a,[440700,,token]	; Set up BP to token
	movsi d,-njopts		; Loop through JCL option table.
	setz e,			; Say no duplicates yet
jclp10:	move b,jcoptb(d)	; Get addr of ASCIZ option string
	hrli b,440700		; Set up BP
	call strcmp		; Compare them
	 jrst jclp19		; Failed, try another.
	 jrst [	jumpl e,jclp19	; Partial match, jump if ignoring.
		jumpg e,[seto e,	; If already a partial match, ignore
			jrst jclp19]	; all further partial matches.
		movei e,(d)	; No other partial matches, save index!
		jrst jclp19]
	jrst jclp20		; Won!  Go execute this routine.	
jclp19:	aobjn d,jclp10		; Drop thru if fail to match...
	jumple e,jclp50		; If no partial matches, go try term names.
	movei d,(e)		; Got exactly one partial match, use it!

	; JCL Option match found.
jclp20:	hlrz c,jcoptb(d)	; Get routine address from LH of entry
	move a,cmdysw		; Set up yes/no argument in A
	call (c)		; Execute matching rtn.
	 return			; return1 from JCLPAR to indicate error
	jrst jclp01		; Continue loop

	; No options matched token, try it as a terminal name.
jclp50:	move e,[440700,,token]	; didn't match a JCL opt, try as terminal.
	call jrtrmf		; Check out.
	 jrst jclp60		; No match, try other stuff.
	skipe b,trmadr		; won, but was something already spec'd?
	 cain b,(c)
	  caia			; No, or specifying same thing, OK.
	   jrst [saycr "Terminal already specified!"
		return]
	hrrzm c,trmadr		; first spec of terminal.
 	jrst jclp01		; Continue if won...

	; Not an option or terminal name.  See if it's a host name,
	; in case we're hacking network.
jclp60:
IFN NET,{
	skipe hstsen		; If HOST option already given,
	 jrst jclp70		; Don't bother trying to parse as hostname.
	move a,[440700,,token]	; Set up pointer to token
	call hstpar		; Get number for host
	 jrst jclp70		; Failed, give up.
	movem a,frnhst		; Won!  Set host address
	move a,[440700,,hstnam]
	call tokcpy		; and copy token into hostname buffer!
	jrst jclp01		; Done, back for another token.
}
jclp70:		; Fall through to complain about bad JCL spec.

bad:	say |"|
	move t1,tokp
	move t2,tokl
	call typstr
	saycr |" is not a valid terminal name or option.
|
	call cusage	; Barf politely.
	call dohelp
        return		; don't fall thru to help anymore

cusage:	say "Usage is "
IFN ITS,say |:|
IFN TNX,say |@|
	move t1,prgnam
	call typasc
	saycr "<terminal name> <options>"
	ret
dohelp:	say "Do "
IFN ITS,say |:|
IFN TNX,say |@|
	move t1,prgnam
	call typasc
	saycr " HELP for help."
	ret

help:	skiple trmadr	; if he specified a good terminal,
	 jrst lstopt	; don't list them
	call cusage
	say "
Terminals are:"
	call jtrmls
	say "
"
lstopt:	say "Options are:
; Terminal description:
HEIGHT <no. of lines on the screen>,
WIDTH <no. of columns per line>,
<bps>, SPEED <bps>, ISPEED <bps>, OSPEED <bps>,
NO ABS, NO TABS, NO BELL, NO CLEOL, NO CLEOS, NO LID, NO CID,
[NO] META, [NO] EDIT,
SCRLCOUNT <no. of lines>

; ITS options (same meaning as with TCTYP):
GLASS, SAIL, SCROLL

; CRTSTY options:
[NO] INVERSE, VISBEL, WHOLINE, ALARM <idle mins>,
[NO] SMEOL, STEOS,
NO LOGIN, LOGIN <uname>,
NO WARN, SOFTOK, SLAVE, NO SII, NO ATTACH, DEBUG,
BUFFER <size>,
TTY <terminal no. to use>,
SIMULATE <terminal>"
IFN NET,{
	say ",
<hostname>, HOST <hostname>"
}
	say "
"
	return

badtrm:	say "Terminal id may be one of:"
	pjrst jtrmls

subttl	JCL option routines & dispatch table

comment |
	JCL options are defined very easily; for example,
to define an option FOO, we just put in 

	jcopt /FOO/,<label>	; comment

where <label> is the address of the routine that will handle the
option, when invoked.  Typically it can just set a flag, but it
may ask for more arguments by calling JNUMB or 7PARM or 6PARM.
Routines are free to use all of acs A-E, but note that in many cases
E is used to return a value.  (someday perhaps this will become A).

	Note that upon entry to the routine, ac A is set to a value
signifying either YES or NO.  It will be NO if the previous "option"
was "NO", YES otherwise; all routines which set tri-state (yes/no/default)
switches should simply store this value.
		+1 = YES
		 0 = default
		-1 = NO
|

blkini jcblk		; initialize/define block for JCL option table.
define jcopt &name&,rtn	; and define macro to add entries.
blkadd jcblk,[rtn,,[asciz name]
]
termin


	jcopt /?/,jrhelp
	jcopt /HELP/,jrhelp
jrhelp==help

	jcopt /TERM/,jrterm	; Specify terminal type.
jrterm:	call 7parm		; Get asciz param in next field.
	 return
	move b,e		; Save BP, and
	call 6parmt		; get 6bit version also.
	camn e,[sixbit /VT/]	; Generic-VT command?
	 pjrst jrvt		; Yes, go identify VT
	move e,b		; Nope, restore BP to asciz name
	call jrtrmf		; and identify terminal type.
	 jrst [	say "Unknown terminal type!  "
		pjrst badtrm ]
	skipe trmadr
	 camn c,trmadr
	  caia
	   jrst [saycr "Terminal already specified!"
		return ]
	hrrzm c,trmadr		; Won, store term idx.
	pjrst popj1

	jcopt /VT/,jrvt		; Identify VT type and use as term ID.
ivar jvtsw			; nonzero if loser wants use to guess which VT
jrvt:	setom jvtsw		; set switch to do the hack at setup time
	pjrst popj1


	jcopt /LINEL/,jrwidt	; Specify line length (width of screen)
	jcopt /WIDTH/,jrwidt	; Ditto
ivar jwidth			; specified line length
jrwidt:	call jnumb		; get numeric argument into e
	 return
	caile e,10.		; make some trivial checks
	 caile e,maxhor
	  jrst [saycr "Ridiculous screen width"
		return]
	movem e,jwidth		; and save it
	pjrst popj1

	jcopt /PAGEL/,jrpagl	; Specify page length (height of screen)
	jcopt /HEIGHT/,jrpagl	; ditto
ivar jheight			; specified height
jrpagl:	call jnumb		; Get nmber in next field
	 return
	caile e,5		; Make some checks
	 caile e,maxver
	  jrst [saycr "Ridiculous height"
		return]
	movem e,jheight		; Well, it passes! Save it.
	pjrst popj1


	jcopt /SPEED/,jrspd	; Specify actual speed of terminal
	irp speed,,[110,300,600,1200,1800,2400,4800,9600,19200]
	jcopt /speed/,jrspdp
	termin
jrspd:	call jnumb
	 return
	jrst jrspd2
jrspdp:	call jnumtk		; Re-parse token as number.
	 return
jrspd2:	movem e,ospeed
	movem e,ispeed
	pjrst popj1

	jcopt /OSPEED/,jrospd
jrospd:	call jnumb
	 return
	movem e,ospeed
	pjrst popj1

	jcopt /ISPEED/,jrispd
jrispd:	call jnumb
	 return
	movem e,ispeed
	pjrst popj1

	jcopt /AUTONL/,jranl
ivar janl
jranl:	movem a,janl
	pjrst popj1

	jcopt /ABS/,jrabs	; Suppress use of absolute move.
ivar jabs
jrabs:	movem a,jabs		; set switch to prevent absolute cursor
				; positioning
	pjrst popj1

	jcopt /TABS/,jrtab	; Say term has no tabs.
mvar jtab			; positive: use tabs, negative: don't,
				; zero: default
jrtab:	movem a,jtab		; set switch to prevent tabbage
	pjrst popj1

	jcopt /BELL/,jrbell	; Don't use audible bell.
mvar jbell			; positive for no audible bell
jrbell:	movem a,jbell
	pjrst popj1

	jcopt /CLEOL/,jrclel
ivar jcleol
jrclel:	movem a,jcleol
	pjrst popj1

	jcopt /CLEOS/,jrcles
ivar jcleos
jrcles:	movem a,jcleos
	pjrst popj1

	jcopt /LID/,jrlid
ivar jlid
jrlid:	movem a,jlid
	pjrst popj1

	jcopt /CID/,jrcid
ivar jcid
jrcid:	movem a,jcid
	pjrst popj1

	jcopt /SCRLCOUNT/,jrscrc
ivar jscrcnt
jrscrc:	call jnumb
	 return
	movem e,jscrcnt
	pjrst popj1


; ITS options:

	jcopt /SAIL/,jrsail
ivar jsail			; if positive do :TCTYP SAIL
jrsail:	movem a,jsail
	pjrst popj1

	jcopt /SCROLL/,jrscr
ivar jscrol			; if positive do :TCTYP SCROLL
jrscr:	movem a,jscrol
	pjrst popj1

	jcopt /GLASS/,jglass	; Claim it's a "glass tty" rather than a full display
ivar glassw			; positive to be glass tty, not display
jglass:	movem a,glassw
	pjrst popj1


; CRTSTY options:

	jcopt /INVERSE/,jrinv	; Use inverse video hacking.
mvar jinvrs			; use inverse video on display
jrinv:	movem a,jinvrs
	pjrst popj1

	jcopt /TRANSLUCENT/,jrtran
ivar jtrans			; positive for C100 translucent option
jrtran:	movem a,jtrans
	pjrst popj1

	jcopt /VISBEL/,jrvbel	; Use a visible bell.
mvar visbel			; positive for visible bell
jrvbel:	movem a,visbel
	pjrst popj1

IFN STY,{
	jcopt /WHOLINE/,jrwho
mvar wholin			; positive: hack a wholine
jrwho:	movem a,wholin
	pjrst popj1
} ; IFN STY

IFN TINT&SINT,{
	jcopt /ALARM/,jralrm	; Set # idle mins after which to feep when output resumed.
jralrm:	call jnumb		; Get number
	 return
	jumpl e,[saycr "Impossible alarm time"
		return ]
	imuli e,ticspm		; clock tics per minute.
	skipn e
	 movei e,ticspm		; Default to 1 minute.
	movem e,feepmx		; store specified # ticks.
	pjrst popj1
} ; IFN TINT&SINT

	jcopt /META/,jr8mta	; Use 8-bit input, 8th bit is meta bit.
	jcopt /EDIT/,jr8mta	; Another common name for 8th bit.
ivar j8meta
jr8mta:	movem a,j8meta		; Set switch to desired value
	pjrst popj1

	jcopt /SMEOL/,jrsmel	; Use "Smart CLEOL".
ivar jsmeol
jrsmel:	movem a,jsmeol
	pjrst popj1

	jcopt /STEOS/,jrstes	; Use "Stupid CLEOS".
ivar jsteos
jrstes:	movem a,jsteos
	pjrst popj1

	jcopt /TPCBS/,jrtmp
mvar tpcbs			; if negative don't use %TPCBS
				; only meaningful when simulating software
				; TTYs
jrtmp:	movem a,tpcbs
	pjrst popj1

IFN ITS&STY,{
	jcopt /LOGIN/,jrlgin	; Specify login name to use.
ivar juname			; uname to LOGIN as
jrlgin:	movem a,juname
	jumpl a,popj1		; if NO LOGIN then don't read uname
	call 6parm		; Get 6bit parm into E
	 return
	movem e,juname		; save name to use.
	pjrst popj1
} ; IFN ITS&STY
IFN TNX&STY,{
	jcopt /LOGIN/,jrlgin
ivar jlogin
jrlgin:	movem a,jlogin
	pjrst popj1
} ; IFN TNX&STY

	jcopt /WARN/,jrwarn	; Don't send warning message
ivar jwarn			; if nonzero don't show warning message
jrwarn:	movem a,jwarn
	pjrst popj1

IFN ITS,{
	jcopt /SOFTOK/,jrsoft	; proceed even if TTY is software type.
ivar jsftok			; if nonzero then OK to go ahead even if TTY is software type.
jrsoft:	movem a,jsftok
	pjrst popj1
} ; IFN ITS

	jcopt /SII/,jrsii
ivar jsii			; superimage input
jrsii:	movem a,jsii
	pjrst popj1

	jcopt /ATTACH/,jrattc
ivar jattach
jrattc:	movem a,jattach
	pjrst popj1

	jcopt /FLUSH/,jrflsh
ivar jflush
jrflsh:	movem a,jflush
	pjrst popj1

	jcopt /DEBUG/,jdebug
jdebug:	movem a,debug
	pjrst popj1

	jcopt /BUFFER/,jrbuff	; Specify buffer size to use
jrbuff:	call jnumb		; Get number in next field
	 return
	caig e,1		; See if reasonable.
	 jrst [	saycr "Unreasonable buffer size"
		return]
	movem e,buffmx		; remember specified buff size.
	pjrst popj1

	jcopt /TTY/,jrtty	; Specify TTY no. to support
ivar ttynum			; TTY no. of terminal to support
jrtty:	call jnumb
	 return
	movem e,ttynum
	pjrst popj1

	jcopt /SIMULATE/,jrsim		; Simulate a terminal.
jrsim:	call 7parm		; Get asciz terminal name
	 return
	call jrtrmf		; Find index
	 return
	skipn .trsmo(c)		; See if has simulate capability.
	 jrst [	saycr "No simulate code exists for that terminal"
		return]
	movem c,simadr		; Save addr of simulator definition
	pjrst popj1

IFN NET,{
	jcopt /HOST/,jrhost
ivar hstsen		; -1 if HOST spec explicitly given.
mvar hstnam(8.)		; Host name
mvar frnhst		; Host number (0 if none)
jrhost:	call jclf
	 jrst [	saycr "Host name missing."
		return ]
	setom hstsen		; Say HOST option seen.
	move a,[440700,,hstnam]	; Copy token into hostname buffer
	call tokcpy
	call hstpar		; Given BP in A, return host # in A
	 setz a,		; Failed, just zap host address.
	movem a,frnhst		; Won!  Set up.
	pjrst popj1
} ; IFN NET

IFN NET,{
	jcopt /TELNET/,jrteln
ivar jtelnt
jrteln:	movem a,jtelnt		; Use TELNET instead of SUPDUP.
	pjrst popj1
}

IFN ITS,{
	jcopt /@ITS/,jrits
ivar jatits
jrits:	movem a,jatits
	pjrst popj1
} ; IFN ITS

IFN STY,{
	jcopt /SLAVE/,jrslav	; open terminal as slave, don't ^Z or login
mvar jslave			; want to permit use as slave console?
jrslav:	movem a,jslave
	pjrst popj1
} ; IFN STY


; Here expand the string block for JCL options table...
jcoptb:	jcblk
njopts==.-jcoptb

subttl	Terminal name parsing & listing

; JRTRMF - Find terminal name.
;	E/ BP to uppercase ASCIZ terminal name string.
; Returns .+1 if failed, else .+2 with
;	C/ index to terminal definition - (address of table)

jrtrmf:	pushae p,[a,b,d,e]
	movsi c,-nterms		; AOBJN thru term table
jrtrm2:	move d,trmtab(c)	; Get pointer to a term def block
	move d,.tpnam(d)	; get addr of asciz string for names
	hrli d,440700		; Make BP to it
jrtrm4:	ildb a,d		; Get char from term def string
	ildb b,e		; and from arg string
	cain a,(b)
	 jumpn a,jrtrm4		; if matched, continue.
	jumpe a,[jumpe b,jrtrm8	; If both strings counted out, won...
		jrst jrtrm6]	; else failed; def string gone.
	jumpe b,[cain a,",	; If arg string out, and def string hit ","
		 jrst jrtrm8	; then also won.
		jrst .+1]
	; No luck, move up to next name in term def string.
	move e,(p)		; Restore BP to arg string.
jrtrm5:	cain a,",
	 jrst jrtrm4		; Hit "," so try next name now.
	ildb a,d
	jumpn a,jrtrm5

jrtrm6:	aobjn c,jrtrm2		; try another terminal.
	jrst jrtrm9		; failed.

jrtrm8:	move c,trmtab(c)	; Win, return address of term def block.
	aos -4(p)		; Win return.
jrtrm9:	popae p,[e,d,b,a]
	return

; JRTR6F - Search for SIXBIT terminal name in E.  Skip with ptr in A if win.
;	Clobbers A,B,C.

jrtr6f:	movsi c,-nterms		; AOBJN thru term table
jrtr62:	move a,trmtab(c)	; get pointer to a terminal def block
	hlrz b,.tpnam(a)	; get pointer to sixbit name.
	camn e,(b)		; this one matches?
	 aosa (p)		; won, skip on return.
	aobjn c,jrtr62		; drop thru if failed.
	return


jtrmls:	push p,a		; termtab pointer
	push p,b		; byte pointer
	push p,c		; character
	push p,d		; hpos
	movei d,0
	movsi c,-nterms
jtrml3:	move b,trmtab(c)	; get addr of term def block
	move b,.tpnam(b)	; get addr of asciz string of term names
	hrli b,440700
jtrml5:	jumpe d,jtrml6
	say ", "
	addi d,2
	caig d,64.
	 jrst jtrml4
jtrml6:	say "
"
	movei d,0
jtrml4:	ildb a,b
	jumpe a,jtrml7
	pbout
	addi d,1		; inc hpos
	jrst jtrml4

jtrml7:	aobjn c,jtrml3
	jumpe d,jtrml8
	 say "
"
jtrml8:	popae p,[d,c,b,a]	; restore regs
	return


; SIXO types out the SIXBIT value in A.
sixo:	push p,b
	move b,a
sixo2:	movei a,0
	lshc a,6
	addi a,40
	pbout
	jumpn b,sixo2
	pop p,b
	return

subttl	Command line parsing subroutines

;	JCLF - reads JCL field into TOKEN and skips;
; doesn't skip if nothing there.
; This routine is a horrible mess and should be rewritten. -EAK

ivar jclp			; Holds BP into JCL
ivar tokl
ivar tokp


jclf:	pushae p,[a,b,d]
	move a,[token,,token+1]	; clear token buffer
	setzm token		; ...
	blt a,token+<ltoken+4>/5-1	; ...
	move a,jclp
	move c,[440700,,token]
	movei d,ltoken-1		; max length count for option

jclf1:	move e,a
	ildb b,a		; pick up JCL character
	jumpe b,[
		move a,e
		jrst jclf9 ]
	caie b,^C		; ^C or CR?
	cain b,^M
	 jrst [	move a,e
		jrst jclf9 ]
	cain b,40		; space?
	 jrst jclf1		; yeah, continue to scan for option
jclf2:	jumpe d,jclf3		; room in option word
	cail b,"a		; lower case alpha?
	 trz b,040		; make into upper case
	idpb b,c		; deposit character of option
	subi d,1
jclf3:	move e,a		; save command line pointer
	ildb b,a		; get next command line character
	caie b,^C		; control C or
	cain b,^M		;  or control M of command line?
	 jrst [	move a,e	; restore pointer to ^M
		jrst jclf8 ]	; and return option word
	caie b,40
	 cain b,",
	  jrst jclf8
	jrst jclf2		; process nonspace
				; otherwise return result found
jclf8:	movei b,ltoken-1		; max option length
	sub b,d			; return length in b
	movem b,tokl		; and in TOKL
	move c,[440700,,token]	; and option pointer in c
	movem c,tokp		; and in TOKP
	aos -3(p)		; Skip on win return.
jclf9:	movem a,jclp		; restore updated BP
	popae p,[d,b,a]
	return


;	get parameter into sixbit in e

7parm:	call jclf		; get next field
	 jrst [	saycr "Argument missing"
		return ]
	move e,tokp
	pjrst popj1

6parm:	call 7parm
	 return
	aos (p)			; Have result, so always skip after convert.
6parmt:	pushae p,[a,b,c,d]
	move c,[440700,,token]	; enter here with option in TOKEN
	move d,[440600,,e]
	movei e,0
6parm2:	ildb a,c		; Get char from arg
	jumpe a,6parm7		; end if hit null
	trz a,40
	trze a,100		; cvt to 6bit
	 tro a,40
	idpb a,d		; deposit in e
	tlne d,770000		; done when ptr hits end.
	 jrst 6parm2
6parm7:	popae p,[d,c,b,a]
	return			; return with result in e


; JNUMB - Command line number parser, reads next field as number.
;	Skips if wins, with # in E.

jnumb:	call jclf		; get the next jcl field
	 jrst [	saycr "Numeric argument missing"
		return]

	; Entry point to parse existing token as number.
jnumtk:	pushae p,[a,b,c,d]
	move c,[440700,,token]	; pointer to the options string
	setzb a,e		; clear oct/dec accumulators
jnumb3:	ildb  b,c		; pick up a character
	jumpe b,jnumb7
	cail  b,"0		; is it less than zero?
	 caile b,"9		; or not less than nine?
	  jrst jnumb2		; then must be a terminator
	imuli e,10.		; multiply previous by 10
	addi e,-"0(b)		; and add in the new digit
	lsh a,3			; also build up an octal value
	addi a,-"0(b)		; and put it in here
	jrst jnumb3		; and get next digit

jnumb5:	say "Number in bad format"
	jrst jnumb8
jnumb2:	cain b,40		; space?
	 jrst jnumb7		; yes, then must be decimal
	cain b,".
	 jrst jnumb7		; no. ending in period is also decimal
	cain b,"'
	 move e,a		; no. ending in ' is octal
jnumb7:	aos -4(p)
jnumb8:	popae p,[d,c,b,a]
	return			; and return it in e

; TOKCPY - Copy token into specified location.
;	A/ BP to place to copy token.  Leaves ASCIZ string.

tokcpy:	pushae p,[a,tokp,tokl]
	skipg tokl
	 jrst tokcp2
tokcp1:	ildb t1,tokp
	idpb t1,a
	sosle tokl
	 jrst tokcp1
tokcp2:	movei t1,0
	idpb t1,a
	popae p,[tokl,tokp,a]
	return

; STRCMP - Compares two ASCIZ strings.
;	A/ BP to ASCIZ target string
;	B/ BP to ASCIZ test string
; Returns .+1 if failed
; Returns .+2 if string A partially matches B (ie A is shorter but matches)
; Returns .+3 if fully matches.

strcmp:	pushae p,[a,b,c,d]
strcm2:	ildb c,a
	ildb d,b
	caie c,(d)
	 jrst strcm8		; Mis-match.
	jumpn c,strcm2
	aosa -4(p)		; Both counted out, won!
strcm8:	 cain c,		; Mismatch, but skip once if A counted out.
	  aos -4(p)
	popae p,[d,c,b,a]
	return

IFN NET,{

; HSTPAR - Find host address for a host name.
;	A/ BP to ASCIZ host name
; Returns .+1 if failed
; Returns .+2 if won, host address in A

IFN TNX,{
hstpar:	pushae p,[b,c]
	move b,a
	movei a,.gthsn
	gthst		; Find host address
	 caia
	  aos -2(p)	; Won, skip return.
	move a,c
	popae p,[c,b]
	ret
} ;IFN TNX
IFN ITS,{
hstpar:	pushae p,[b,a]
	skipe netwrk"hstadr	; Already mapped?
	 jrst hstpr2		; Don't re-do it if so.
	move a,syspno		; HSTMAP arg: A = page no. for mapping
	movei b,dsko		; HSTMAP arg: B = channel no.
	call netwrk"hstmap	; load in the HOSTS3 data base
	 jrst [	say "Cannot map in HOSTS3 database!"
		jrst logout]
	hrrzm a,syspno		; Update 1st unused page #
hstpr2:	pop p,a			; Restore BP argument
	pushae p,[c,d,e]
	call netwrk"hstlook	; Get hostaddr in A, net # in TT
	 caia
	  aos -4(p)		; Won, so do skip return!
	popae p,[e,d,c,b]
	ret

} ;IFN ITS
} ;IFN NET

subttl	Set up TTY

IFN ITS,{
; Open TTY with terminal to support.  Find out various things about it.
ttyini:	move a,ttynum		; TTY no. to support
	lshc a,-3		; convert to device name
	lsh a,3
	lshc a,3
	movsi a,'T00(a)
	$call open,[#tyic,a][][#.uai+%tiful+%tiint+%tinwt]
	 jrst [	say "Specified TTY not available."
		jrst logout ]
	$call open,[#tyoc,a][][#.uao+%tjsio]
	 .lose %lsfil
	move a,[squoze 0,TORM]	; Now want to map TORM+(our TTY)
	move b,ttynum		; add in # of TTY as proper index
	call itsmap
	movem a,torm		; Save address in our map
	move a,[-4,,[
		sixbit /msk2/ ? tro 1_tyic	; enable interrupts
		sixbit /df2/  ? tro 1_tyic	; but defer them
		]]
	$call usrvar,[#%jself,a]
	 .lose %lssys
	$call ttyset,[#tyic,[030303,,030303],[030303,,030303]]
	 .lose %lsfil		; Set to defaults (interrupt, activate on all)
	move a,[-6,,[
		sixbit /tctyp/ ? movem tctyp
		sixbit /ispeed/ ? movem ispeed
		sixbit /ospeed/ ? movem ospeed
		]]
	$call ttyvar,[#tyic,a]	; get TCTYP, OSPEED, and ISPEED
	 .lose %lsfil
	skipge jatits		; NO @ITS specified?
	 return			; Yes, that's it
	skipe trmadr		; ITS info not prohibited, see if term type
				; was specified by user.  If not, ask ITS.
	 skipe jatits		; If term type given, ignore ITS info unless
				; @ITS was specified to force it.
	  caia			; Here to get ITS info about terminal.
	   ret			; Here to NOT get any more ITS info.
	move a,[-10.,,[
		sixbit /tctyp/	? movem b
		sixbit /ttyopt/	? movem c
		sixbit /width/	? movem jwidth
		sixbit /height/	? movem jheight
		sixbit /ttyrol/	? movem jscrcnt
		]]
	$call ttyvar,[#tyoc,a]
	 .lose %lsfil
	aos jwidth		; correct for ITS lossage
	skipn a,trmadr
	 skipe a,tctypt(b)
	  movem a,trmadr
	tlne c,%tofci
	 tro f,%ffci
	tlne c,%tosai
	 tro f,%fsail
	tdnn c,[%tolid,,%tprsc]
	 setom jlid
	tlnn c,%tocid
	 setom jcid
	return

; Table of CRTSTY terminal types, indexed by TCTYP.
tctypt:	offset 0-.
%tnprt:: 0			; random printing terminal
%tndp::	 dp			; Datapoint
%tnodp:: dpluz			; Datapoint loser
%tniml:: 0			; Imlac (no longer actually used)
%tntek:: 0			; Tektronix storage scope
%tntv::	 soft			; TV
%tnmem:: 0			; Memowreck
%tnsfw:: soft			; Software TTY
%tntrm:: 0			; Terminet
%tnesc:: vt52			; VT52
%tndtm:: dm25			; Datamedia 2500
%tnray:: t1061			; Teleray 1061
%tnhds:: c100			; Concept 100
%tnh19:: h19			; Heath 19
%tnaaa:: aaa			; Ann Arbor Ambassador
%tnmax::
	offset 0

} ; IFN ITS

IFN TNX,{

ivar ttynam(2)			; asciz name of terminal to support

ttyini:	move a,ttynum		; DEVST arg: device designator:
	camn a,[-1]
	 skipa a,[.cttrm]	; No TTY #, use controlling terminal (TTY:)
	  hrli a,.dvdes+.dvtty	; Else fix up device code,,unit no.
	gttyp			; Get TTY type
	movem b,ttytyp		; Save it.

	move b,a		; Move dest designator to B for DEVST
	hrroi a,ttynam		; DEVST arg: destination descriptor
	devst			; convert terminal no. to terminal name
	 jerr1 ttyerr
	movei b,":		; add a colon for the GTJFN
	idpb b,a		; ...
	movei b,0		; terminate string with a null
	idpb b,a		; ...
ttyin1:	movsi a,(gj%sht)	; GTJFN arg: bits
	hrroi b,ttynam		; GTJFN arg: source designator (filename)
	gtjfn			; get JFN for specified TTY
	 jerr1 ttyerr
	movem a,ttyjfn		; save TTY JFN
	move b,[8._30.+of%rd+of%wr]	; OPENF arg: byte size and control bits
	openf			; open terminal in binary mode
	 jerr1 ttyerr
	movei t1,177
	movem t1,icmask		; Set input char mask for 7 bits only.
IFN 20X,{
				; MTOPR arg: A = JFN
	movei b,.morsp		; MTOPR arg: B = opcode (read speed)
	mtopr			; read terminal speed
				; result: input speed,,output speed
	jumple c,ttyin2		; ignore a 0 or -1 result
	hrrzm c,ospeed
	hlrzm c,ispeed
ttyin2:
} ; IFN 20X

	; See if terminal type matches anything we know about.
	skipe trmadr		; If term type already specified,
	 jrst ttyin4		; don't bother finding it.
	movsi b,-ntnxty
ttyin3:	hlrz a,tnxtys(b)	; Get a type from table
	came a,ttytyp		; Matches our TTY type (as per GTTYP)?
	 aobjn b,ttyin3
	jumpl b,[hrrz a,tnxtys(b)	; Won, found entry
		movem a,trmadr		; Set up right terminal support rtn.
		jrst .+1]
ttyin4:
IFN TINT,{
	move a,[ttylev,,ttyivi]	; set up CHNTAB entry for terminal interrupts
	movem a,chntab+ttychn	; ...
	move a,[.ticti,,ttychn]	; ATI arg: terminal code,,channel no.
	ati			; all characters should interrupt on TTYCHN
	move a,[ttylev,,tyirlt]	; set up CHNTAB entry for time-out interrupts
	movem a,chntab+timchn	; ...
} ; IFN TINT
	return

ttyerr:	asciz "Error opening TTY - "

; Table of TNX terminal types that we know about.
; This is not guaranteed to work since terminal types vary from system to
; system - this is why the IFDEFs exist, and why indexing won't work
; (unlike the ITS table).  Assumes that terminal type symbols are
; consistent across systems, which may not be true!
; The TOPS-20 monitor source file STG.MAC defines the parameters and cursor
; control sequences used for each defined terminal type.  The file
; MONSYM.MAC defines the terminal-type .TT symbols which index these tables.
; Note that the only cursor controls which the TOPS-20 monitor knows about
; are UP, DOWN, BACK, FWD, HOME, CLEOS, and CLEOL.  Big deal.

define tnxtyp type,crtrtn	; <type #>,,<CRTSTY support addr>
	ifdef type, type,,crtrtn
termin

tnxtys:	; First group is DEC-defined terminal type symbols.
	tnxtyp .tt33,0		; TTY model 33
	tnxtyp .tt35,0		; TTY model 35
	tnxtyp .tt37,0		; TTY model 37
	tnxtyp .ttexe,0		; TI/Execuport
	tnxtyp .ttdef,0		; Default
	tnxtyp .ttidl,0		; Ideal (NVT)
	tnxtyp .ttv05,vt05	; VT05
	tnxtyp .ttv50,vt50	; VT50 (or maybe VT50H)
	tnxtyp .ttl30,0		; LA30
	tnxtyp .ttg40,0		; GT40 (could be anything...)
	tnxtyp .ttl36,0		; LA36
	tnxtyp .ttv52,vt52	; VT52
	tnxtyp .tt100,vt100	; VT100
	tnxtyp .ttl38,0		; LA38
	tnxtyp .tt120		; LA120
	tnxtyp .tt125,vt100	; VT125 (use VT100 support for now)
	tnxtyp .ttk10,vt100	; VK100 (use VT100 support for now)

	; Various non-DEC terminal type symbols
	; The following is the union of all terminal type defs from
	; the systems at SRI, STANFORD, ISI, and MIT.
	tnxtyp .tt43,0		; TTY model 43
	tnxtyp .ttti,0		; TI
	tnxtyp .ttnvt,0		; NVT
	tnxtyp .ttaaa,aaa	; Ann Arbor Ambassador
	tnxtyp .ttamb,aaa	; Ann Arbor Ambassador
	tnxtyp .ttann,annarb	; Ann Arbor (?? not sure which type)
	tnxtyp .ttadm,adm3	; LSI ADM-3
	tnxtyp .ttbbn,0		; BBN Bitgraph
	tnxtyp .ttcpt,c100	; Concept 100
	tnxtyp .ttc10,c100	; Concept 100
	tnxtyp .ttdam,dm25	; Datamedia 2500
	tnxtyp .ttdm,dm25	; Datamedia 2500
	tnxtyp .ttdm2,dm15	; Datamedia 1520
	tnxtyp .tt152,dm15	; Datamedia 1520
	tnxtyp .ttesp,0		; ESPRIT (what's this??)
	tnxtyp .ttfox,fox	; FOX 1100
	tnxtyp .ttfrd,0		; FREEDOM-100 (what's this??)
	tnxtyp .ttgil,0		; GILLOTINE (what's this??)
	tnxtyp .ttgls,0		; Glass TTY (may just be ADM3??)
	tnxtyp .tthaz,h15	; Hazeltine 1500
	tnxtyp .tthp,hp2645	; HP2645 etc.
	tnxtyp .tthp0,hp2645	; HP2645 (if this exists then .tthp=HP2640)
	tnxtyp .tth19,h19	; Heath H19
	tnxtyp .ttibm,ibm3101	; IBM 3101-20
	tnxtyp .ttiml,0		; Imlac
	tnxtyp .ttimx,0		; IMLAC
	tnxtyp .ttlnp,lp	; Line Processor
	tnxtyp .ttptv,		; Plasma TV
	tnxtyp .ttsrc,iq120	; Soroc IQ 120
	tnxtyp .ttsup,soft	; SUPDUP virtual terminal
	tnxtyp .ttt10,t1061	; Teleray 1061
	tnxtyp .tttel,t1061	; Teleray 1061
	tnxtyp .tttek,tk4025	; Tektronix 4025
	tnxtyp .tttk3,tk4023	; Tektronix 4023
	tnxtyp .tttvi,tvi912	; Televideo-912
	tnxtyp .tttac,		; TAC/WTEC
	tnxtyp .tttec,mtec	; TEC (Mini-TEC???)
	tnxtyp .ttv10,vt100	; VT100 in VT52 mode
	tnxtyp .tt100,vt100	; VT100 in ANSI mode

ntnxty==<.-tnxtys>	; # of possible TNX terminal types

} ; IFN TNX



; TRMCHK - Check out the specification for the supported terminal type,
;	to make sure we have a valid TRMADR.

trmchk:	skipe jvtsw		; VT specified?
	 jrst [	call vtsu	; see if can identify terminal type
		 jrst logout
		jrst .+1 ]
	skipn trmadr		; Now identified a terminal?
	 jrst [	say "No terminal type specified!  "
		call badtrm
		jrst logout ]
	move b,trmadr		; Last-minute check to make sure idx legal.
	movsi a,-nterms		; check to make sure it's legal.
	came b,trmtab(a)
	 aobjn a,.-1
	jumpge a,[say "Bug - bad TRM address?? "
		jsr bughlt	; Never return
		]
IFE ITS,ret
IFN ITS,{
	; Check for potential lossage if TTY is software.
	move b,tctyp	; check - software TTY controlling us?
	caie b,%tnsfw	; ...
	 ret		; nope, go ahead
	move a,trmadr	; Yes, software TTY!
	caie a,soft	; If we are "supporting" it, then it's OK
	 skiple jsftok	; likewise if user has insisted SOFTOK.
	  ret
	saycr |
Foo!  You are on a "software" terminal, either because you are already
using CRTSTY or are using a SUPDUP network server; CRTSTY cannot work.
If you know what you're doing, use "SOFTOK" in the command line.  (but
you can't say we didn't warn you)|
	jrst logout
} ; IFN ITS

; VTSU - Identify DEC VT terminal type if possible.
;	Most of the ANSI info came from Eric P. Scott (EPS) 1/6/84


mvar vtsipn	; Pn if ANSI, else ASCII value if VT52 mode
mvar vtsips	; Ps if ANSI, else -1 if VT52 mode

vtsu:	pushae p,[a,b,c]
	setom vtsipn		; Initialize result values
	setom vtsips
	say "
Identifying VT type: "
IFN ITS,.reset tyic,		; Make sure input flushed
IFN TNX,{
	move a,ttyjfn		; CFIBF arg: A = JFN
	cfibf			; flush input
} ; IFN TNX
	movei a,33		; send "identify-yourself" command to VT
	call tyobout		; ...
	movei a,"Z		; ...
	call tyobout		; ...
	call tyofin	
	sleep 10.		; sleep for 1 second - plenty time

	call tbin
	caie a,33		; first char should be ESC
	 jrst vtsu9		; not escape? lose.
	call tbin
	cain a,"/		; second char should be "/" or "[".  ;]
	 jrst vtsu1		; Aha, is "/", handle simple VT52 case
	cain a,"[		;]
	 jrst vtsu2		; Ugh, handle ANSI case.
	jrst vtsu9		; Was neither, so we lose.

; Handle VT52 style report, (ESC / <type>)
;	<type> byte identifies terminal type.
; Note: EPS reports that VAX/VMS treats any of ABHJKLMQRSTZ as a VT52,
;	and C or E as a VT55.
vtsu1:	call tbin		; Get identifier byte
	movei b,0		; Clear CRTSTY term-type
	cain a,"A		; A - VT50
	 movei b,vt50
	caie a,"H		; H - VT50H
	 cain a,"J		; J - VT50H
	  movei b,vt50h
	caie a,"K		; K - VT52
	 cain a,"L		; L - VT52
	  movei b,vt52
	cain a,"Z		; Z - VT100 in VT52 mode
	 movei b,vt100
	jrst vtsu7

; Handle ANSI style report, (ESC [ ? Pn c) or (ESC [ ? Pn ; Ps c)
;	Pn indicates terminal type
;	Ps is supplementary info, meaning depends on Pn.
; Each parameter is composed of from 0 to 3 decimal digits; a parameter
; with a zero value need not be given explicitly (hence an absent Ps
; is numerically 0).
; EPS: Ps is probably uninteresting to CRTSTY, unless you plan on
;	supporting VT100s in 132-column mode (for VT100s, bit 1.2
;	indicates the presence of the "advanced video" non-option-option
;	without which only 14 lines are available).

vtsu2:	call tbin		; Get next byte,
	caie a,"?		; Should be "?" or
	 jrst vtsu9		; we lose.
	call tnin		; Get numerical parameter
	move c,b		; Save Pn in C.
	cain a,"c		; Terminated with "c"?
	 jrst vtsu3		; yeah, skip the Ps part.
	caie a,";		; No, better be separated with ";".
	 jrst vtsu9		; Sigh, bad response format.
	call tnin
	caie a,"c		; OK, terminator better be "c" now!
	 jrst vtsu9
	movem b,vtsips		; Save returned status options
vtsu3:	movem c,vtsipn		; Save returned terminal type #
	cail c,vtsitl		; Check to ensure # is in table
	 jrst vtsu9		; Nope, too big.
	move b,vtsitb(c)	; Get CRTSTY terminal type from table
	jrst vtsu7		; Go finish setup.

	; Following magic numbers lifted by EPS from VAX/VMS source microfiche.
	;	; Pn	Terminal	Comments
vtsitb:	0	;  0	-
	vt100	;  1	VT100		24x80, 14x132 (24x132 if Ps bit 1.2)
	0	;  2	LA120		66x132 hardcopy
	0	;  3	LA34		66x132 hardcopy
	vt132	;  4	VT132		has LID, CID
	0	;  5	VK100 (GIGI)	24x84
	vt102	;  6	VT102		24x80, 24x132, has LID, CID
	vt132	;  7	VT131		has LID, CID
	0	; 10	LA100		66x132 hardcopy
	0	; 11	-
	vt100	; 12	VT125		VT100 with graphics board
	0	; 13	LQP02		66x132 hardcopy
	0	; 14	-
	0	; 15	LA12		66x80 hardcopy
vtsitl==<.-vtsitb>		; # of entries in table

; This is by no means an exhaustive list.
; VT131s can probably be supported as VT132s and VT125s
; as VT100s, although pad requirements may differ, among other things.

vtsu7:	jumple b,vtsu9		; Jump if no CRTSTY terminal type.
	hrrzm b,trmadr		; Identified, store idx.
	hlrz a,.tpnam(b)
	move a,(a)		; Get sixbit name for confirmation to user.
	call sixo
	saycr ""
	popae p,[c,b,a]
	pjrst popj1		; Win return

vtsu9:	saycr " Unable to identify terminal as a VT type."
	popae p,[c,b,a]
	return

; TNIN - Get ASCII numerical parameter from TTY, such as in ANSI sequences.
; Returns
;	A/ terminating char
;	B/ parameter value

tnin:	setz b,		; Initialize param value to 0
tnin2:	call tbin	; Get a digit
	cail a,"0
	 caile a,"9
	  ret		; Not a digit, so return.
	imuli b,10.	; Params are decimal.
	addi b,-"0(a)	; Add digit into number thus far.
	jrst tnin2
	

; SIMCHK - Check out the specification for the simulated terminal type,
;	to make sure we have a valid SIMADR.

simchk:	skipe c,simadr		; If explicit simulator furnished,
	 jrst simck2		; use it!
IFE TNX&STY, movei c,soft	; If no explicit simulator, use SOFT!!
IFN TNX&STY,{		; For TNX STY, default to VT52 since we know
			; for sure DEC supports that!
	movei c,vt52		; If no explicit simulator, use VT52!!
IFDEF RTCHR,{
	movei a,.priin
	rtchr
	 erjmp simck2
	movei c,soft		; unless VTS present, in which case use SOFT
}
} ;IFN TNX&STY
simck2:	movem c,simadr
	movsi a,-nterms
simck3:	came c,trmtab(a)
	 aobjn a,simck3
	caige a,		; Ensure specified term exists,
	 skipn .trsmi(c)	; and has a simulation entry!
	  call simck9		; Error!
	skipe .trsmo(c)
	 skipn .trsmf(c)
	  call simck9		; Ditto
	ret
simck9:	say "Bug - bad SIM terminal specification!"
	jsr bughlt

; SIMINI - Set up simulation-terminal-dependent variables
;	Takes simulator index from SIMADR and sets up .TRSMI, .TRSMO, .TRSMF

simini:	pushae p,[a,b]
	skipe b,simadr		; Get simulator idx
	 skipn a,.trsmo(b)	; and dispatch for it
	  jrst [say "Bug - bad SIMADR!! "
		jsr bughlt]
	movem a,.trsmo+tb
	move a,.trsmi(b)
	movem a,.trsmi+tb
	move a,.trsmf(b)
	movem a,.trsmf+tb
	popae p,[b,a]
	ret

subttl	TRMINI - Set up terminal-dependent variables

trmini:	call trmblt		; First move terminal table into TB.

	tdo f,.tpflg+tb		; set necessary flags for type.

	skipn ospeed		; speed known?
	 trnn f,%fspd		; no, will we lose by not knowing the speed?
	  jrst su3.4		; no
	saycr "Terminal's speed is unknown.  Please use the SPEED command
(or the OSPEED and ISPEED commands) to tell CRTSTY the line
speed in bits per second."
	jrst logout
su3.4:

	; initialize screen dimensions
	setzm tvmin		; terminal window starts at 1st line of screen
	skipn a,jheight		; if command line specified height, use that
	 move a,.tpvsz+tb	; else use standard for type
	jumpe a,[
		saycr "You must specify a screen height for this terminal"
		jrst logout
		]
	movem a,sheight		; set screen height
	movem a,theight		; and terminal window height
	subi a,1		; convert height to maximum vertical coordinate
	movem a,svmax		; set screen vertical maximum
	movem a,tvmax		; terminal window ends at last line of screen
	setzm thmin		; terminal window starts at 1st column of screen
	skipn a,jwidth		; was a command line width specified?
	 move a,.tphsz+tb	; no, use standard for type
	jumpe a,[
		saycr "You must specify a screen width for this terminal"
		jrst logout
		]
	movem a,swidth		; store width
	movem a,twidth
	subi a,1		; subtract 1 to get maximum horz coordinate
	movem a,shmax		; ...
	movem a,thmax
	skipe a,jscrcnt		; SCRLCOUNT specified?
	 movem a,.tpscr+tb	; yes, use it instead of terminal default
	skipge .tpscr+tb	; make sure we've got a SCRLCOUNT
	 jrst [	saycr "You must specify a SCRLCOUNT for this terminal"
		jrst logout
		]
	move a,.trcho+tb
	skipl janl
	 jrst su3.5
	cain a,ccho
	 movei a,scho
	cain a,ccho0
	 movei a,scho0
	caie a,scho
	 cain a,scho0
	  jrst su3.7
	say "NO "
	jrst su3.6
su3.5:	skipg janl
	 jrst su3.7
	cain a,scho
	 movei a,ccho
	cain a,scho0
	 movei a,ccho0
	caie a,ccho
	 cain a,ccho0
	  jrst su3.7
su3.6:	saycr "AUTONL ignored"
	setzm janl		; print warning
su3.7:	movem a,.trcho+tb

	move a,[movei a,nutcst]	; "impossible" movement cost calculator
	skipge jabs		; NO ABS?
	 movem a,.tcabs+tb	; yes, make absolute positioning cost
				; "impossible"
	skipge jtab		; NO TABS?
	 movem a,.tctab+tb	; yes, make tab cost "impossible"

	move a,speed		; speed 120cps or lower?
	caile a,120.		; ...
	 skiple jsmeol		; or user specify SMEOL?
	  tro f,%fsmeol		; yes, turn on smart CLEOL
	skipge jsmeol		; user specify NO SMEOL?
	 trz f,%fsmeol		; yes, turn off smart CLEOL

	skiple j8meta		; META/EDIT specified?
	 tro f,%f8ci		; Yes, enable use of 8th input bit as meta bit.
	skipge j8meta		; NO META/EDIT?
	 trz f,%f8ci		; Yes, disable use of 8th input bit.
	movei a,177
	trne f,%f8ci		; If not using 8th bit, set mask to 7 bits
	 movei a,377		; else allow 8-bit input char mask!
	movem a,icmask

	skiple jsteos		; STEOS specified?
	 tro f,%fcsel		; yes, turn on hack
	skipge jsteos		; NO STEOS specified?
	 trz f,%fcsel		; yes, turn off hack

	skiple jcleol		; CLEOL specified?
	 trz f,%fneol		; yes
	skipge jcleol		; NO CLEOL specified?
	 trz f,%fneol		; yes
	skiple jcleos		; CLEOS specified?
	 trz f,%fneos		; yes
	skipge jcleos		; NO CLEOS specified?
	 trz f,%fneos		; yes
	skiple jlid		; LID specified?
	 trz f,%fnilp+%fndlp	; yes
	skipge jlid		; NO LID specified?
	 tro f,%fnilp+%fndlp	; yes
	skiple jcid		; CID specified?
	 trz f,%fnicp+%fndcp	; yes
	skipge jcid		; NO CID specified?
	 tro f,%fnicp+%fndcp	; yes
; Now compute what functions are usable.  Someday this may have to become
; a terminal dependent routine.
irp x,,[eol,eos,clr,su,sd,ilp,dlp,dcp]
	skipn .te!x+tb
	 tro f,%fn!x
termin
	skipn .teicp+tb
	 skipe .teeim+tb
	  caia
	   tro f,%fnicp
	movem f,.tpflg+tb
	pjrst @.trwi+tb		; initialize window variables

; SWI - Default window initialization.
swi:	setzb a,b		; TDWIN1 args: A = minimum vertical,
				; B = minimum horizontal
IFN STY,{
	skiple wholin		; WHOLINE specified?
	 movei a,1		; use second line as minimum vertical
} ; IFN STY
	dmove c,smax		; TDWIN1 args: C = maximum vertical,
				; D = maximum horizontal
	pjrst tdwin1		; calculate capabilities in window


; TRMBLT - snarf terminal table into TB for fast impure reference.
;	Takes term idx from TRMADR, and sets up TB table.

trmblt:	pushae p,[a,b]
	skipn b,trmadr		; Get term idx
	 jrst [	say "Bug - bad TRMADR!! "
		jsr bughlt]
	movsi a,(b)
	hrri a,tb
	blt a,tb+ltb-1		; Snarf its table.
	popae p,[b,a]
	return

subttl	Set up STY

; STYOPN - Open/Initialize STY.  The TB array and AC F are referenced;
; i.e. TRMBLT and SETUP3 must have been executed.

IFN ITS&STY,{
styopn:	$call open,[#pyi,[sixbit/STY/]][?a][#10+.uii]
				; don't-hang input from sty
	 jrst [	caie a,%efldv	; device full?
		 $call lose,[#%lsfil,#styopn]	; no, lose
		saycr "Can't get a STY!  Probably too many in use right now."
		jrst logout ]
	$call open,[#pyo,[sixbit/STY/]][][#10+.uio]
				; image,unit,output to sty
	 .lose %lsfil		; "don't-hang" here means echo feep when
				; buffer full, rather than hanging.
	move a,[-4,,[
		sixbit /msk2/ ? tro 1_pyi	; enable interrupts
		sixbit /df2/  ? tro 1_pyi	; but defer them
		]]
	$call usrvar,[#%jself,a]
	 .lose %lssys

	call setup4		; Set up ITS TTY vars
	move b,[-12.,,[
		sixbit /height/ ? move tcmxv
		sixbit /width/ ? move tcmxh
		sixbit /tctyp/ ? move tctyp
		sixbit /ttycom/ ? movei 0
		sixbit /ttyopt/ ? move ttyopt
		sixbit /ttyrol/ ? move ttyrol
		]]
	$call ttyvar,[#pyi,b]
	 .lose %lsfil
	move b,[-4.,,[
		sixbit /ispeed/ ? move ispeed
		sixbit /ospeed/ ? move ospeed
		]]
	$call ttyvar,[#pyi,b]	; set ispeed/ospeed separately
	 jfcl			; to ignore error if ITS can't encode values
				; in 4 bits
	.suset [.rioc+pyi,,a]	; IOCHNM word for PYI channel
	ldb a,[$tiidx,,a]	; get TTY no. for STY we opened
	movem a,stynum		; ...

	move a,[squoze 0,TTYSTS]
	move b,stynum		; add in # of STY as proper index
	call itsmap
	movem a,ttysts		; Save address in our map

	move a,[squoze 0,TTYOAC]	; Now want to map TTYOAC+(our STY)
	move b,stynum		; add in # of STY as proper index
	call itsmap
	movem a,ttyoac		; Save address in our map

	return
} ; IFN ITS&STY

IFN ITS&NET,{
$$HST3==1		; Use new HOSTS3 format table
$$ARPA==1		; support both Arpa and Chaos nets
$$TCP==1		; ...
$$CHAOS==1		; ...
$$CONNECT==1		; Want the TCPCON routine.
$$HSTMAP==1		; Include HSTMAP routine for mapping in table.
$$HOSTNM==1		; Want hostname lookup routine.
$$SYMLOOK==1
$$ICP==1
$$HSTSIX==1		; Include sixbit hostname abbreviations
$$ANALYZE==1		; Want error analysis routine.

T==:T1				; define NETWRK ACs
TT==:T2				; ...
.XCREF T,TT

.INSRT SYSTEM;CHSDEF >
.INSRT SYSNET;NETWRK >
} ; IFN ITS&NET

IFN ITS&NET,{

mvar chaosp

netopn:	move a,frnhst		; Get host we're connecting to
	netwrk"getnet tt,a	; Get network number in TT
	came tt,[netwrk"nw%chs]	; CHAOSnet?
	 jrst netop2		; Nope, assume Internet.

	setom chaosp
	movei a,pyi		; CHACON arg: A = channel no.
	move b,frnhst		; CHACON arg: B = host no.
	movei c,[asciz "SUPDUP"]	; CHACON arg: C = contact name
	movei d,5		; CHACON arg: D = window size
	call netwrk"chacon	; open connection
	 jrst netluz
	jrst netop3

netop2:
IFN TCP,{
	movei a,pyi		; Input channel number, output must be +1
	move b,frnhst		; Foreign host addr
	move c,icpskt		; Foreign port #
	call netwrk"tcpcon	; Do the connect!
	 jrst netluz		; Barf, we lost.
} ;IFN TCP
IFN NCP,{
	movei a,icpch		; first of 4 pins (channels) to ICP with
	move b,frnhst		; host to ICP to
	move c,icpskt		; contact socket
	move d,[40+.uai,,40+.uao]	; modes (8 bit)
	call netwrk"arpicp	; do it all
	 jrst netluz		; lost
} ;IFN NCP

netop3:	call netwrk"hstunmap	; Unmap HOSTS3, don't need any more.


	move a,[-4,,[
		sixbit /msk2/ ? tro 1_pyi	; enable interrupts
		sixbit /df2/  ? tro 1_pyi	; but defer them
		]]
	$call usrvar,[#%jself,a]
	 .lose %lssys
	return

netluz:
;	.iot tyon,[^P]		; IOC error on NET.  Go to fresh line
;	.iot tyon,["A]		; ...
	call netwrk"analyze	; and type the error message
	 .value
	jrst logout

	; Need this hack rtn for NETWRK"ANALYZE to output err msg.
netwrk"putchr:
	.iot tyon,t1
	return

} ; IFN ITS&NET

IFN TNX&STY,{

styopn:	call getpty		; get a PTY
IFN SINT,{
	move a,[ptylev,,styivi]	; set up CHNTAB entry for PTY output
	movem a,chntab+ptychn+1	; interrupts
	move a,smojfn				; MTOPR arg: JFN
	move b,[mo%oir+<ptychn_18.>+.moapi]	; MTOPR arg: function code
	mtopr			; assign PTY interrupt channel
} ; IFN SINT
	call setup4		; Set up ITS TTY vars.
	move t1,tctyp		; find terminal type we're simulating
	movei b,.ttidl		; STTYP arg: B = terminal type
	cain t1,%tnesc		; simulating VT52?
	 movei b,.ttv52		; yes, tell TNX we're a VT52 instead
IFDEF .TTSUP,{
	caie t1,%tnsfw		; simulating a ITS software terminal?
	 jrst nosup		; no
	movei b,.ttsup		; yes, tell TNX we're a SUPDUP terminal
	move t1,[441000,,ibuff]
	movem t1,ibufip
nosup:
}
	move a,ptyttd		; STTYP arg: A = terminal designator
	sttyp			; set PTY's TTY's terminal type
	move b,tcmxv		; get terminal height
	lsh b,25.	.see tt%len	; shift into position
	move t1,tcmxh		; get terminal width
	movsi t1,1(t1)	.see tt%wid	; add 1 and shift into position
	add b,t1		; add to STPAR word
	move t1,ttyopt		; terminal have tabs?
	trne t1,%tpptb*7	; ...
	 tlo b,(tt%tab)		; yes, tell TNX about it
	tdo b,[tt%lca\tt%pgm]	; turn on display mode and lowercase
				; STPAR arg: A = terminal designator
				; STPAR arg: B = terminal mode word
	stpar			; set height, width, capabilities, etc.
IFDEF STCHR,{
	move b,[tc%mov+tc%bs+tc%hom+tc%clr+tc%scl+tc%lid+tc%cid+tc%met+tc%scr]
	move c,ttyopt
	tlnn a,%tomvu
	 tlc b,(tc%mov)
	tlnn a,%tomvb
	 tlc b,(tc%bs\tc%mov)
	tlnn a,%toers
	 tlc b,(tc%scl)
	trnn a,%tprsc
	 tlc b,(tc%lid)
	tlnn a,%tocid
	 tlc b,(tc%cid)
	tlnn a,%tofci
	 tlc b,(tc%met)
	tlnn a,%toovr
	 tlc b,(tc%ovr)
	skipn ttyrol
	 tlc b,(tc%scr)
	stchr
	 erjmp .+1
}
	return


ivar devnam(2)			; PTY device name for GTJFN

getpty:	movei d,0		; start at first PTY
getpt1:	caml d,syspty		; any more?
	 jrst [	saycr "No PTYs available"
		jrst logout
		]
	move a,d		; DVCHR arg: device designator:
	hrli a,.dvdes+.dvpty	; device type,,unit no.
	dvchr			; get characteristics of this PTY
	tlnn b,(dv%av)		; is it available?
	 aoja d,getpt1		; no
	move b,a
	hrroi a,devnam
	devst			; convert device designator to a name
	 aoja d,getpt1
	movei b,":		; add a colon for the GTJFN
	idpb b,a		; ...
	movei b,0		; terminate with a null
	idpb b,a		; ...
	movsi a,(gj%sht)
	hrroi b,devnam
	gtjfn
	 aoja d,getpt1		; not available
	movem a,smojfn		; save PTY JFN
	movem a,smijfn
	move b,[8._30.+of%rd+of%wr]
	openf			; open PTY
	 jrst [	move a,smojfn	; RLJFN arg: JFN
		rljfn		; PTY not available, release JFN for it
		 jfcl
		aoja d,getpt1	; try next one
		]
	add d,firpty		; turn PTY no. into TTY no.
	addi d,.ttdes		; turn TTY no. into device designator
	movem d,ptyttd		; ...
	return
} ; IFN TNX&STY


IFN TNX&NET,{

.mosnd==:21			; send all currently buffered bytes
ifn ncp,	.moain==:24	; assign INS/INR and FSM PSI channels
ifn chaos,{
		.moacn==:24	; assign input/output interrupt channels
		IOX4==:600220	; End of file error message
} ; ifn chaos

ivar hstbfr(10)

netopn:

IFN CHAOS,{
	call chaicp
IFE NCP\TCP, jerr1 icperr
IFN NCP\TCP,{
	 jrst [	caie a,gjfx16	; no such device? (chaosnet not supported)
		 cain a,gjfx18	; no such filename? (host not on chaosnet)
		  jrst styin1	; either, try ARPAnet
		jerr1 icperr	; chaosnet supported, and host known, report
				; error
		]
} ; IFN NCP\TCP
IFN SINT,{
	move a,[ntilev,,styivi]
	movem a,chntab+ntichn
	move a,smojfn		; MTOPR arg: A = JFN
	movei b,.moacn		; MTOPR arg: B = function code
	move c,[-1,,ntichn]	; MTOPR arg: C = output channel,,input channel
	mtopr			; assign input interrupt channel
} ; IFN SINT
	return
} ; IFN CHAOS

IFN NCP\TCP,{
styin1:
IFN NCP,call arpicp		; Try to open connection!
IFN TCP,call tcpicp		; Try to open connection!
	 jerr1 icperr
	setzm inscnt
	move a,[inslev,,insint]
	movem a,chntab+inschn
	move a,[netlev,,netint]
	movem a,chntab+netchn
	movei a,.fhslf		; AIC arg: A = fork handle
	movsi b,(1_<35.-inschn>\1_<35.-netchn>)
				; AIC arg: B = channels to activate
	aic			; activate INSCHN and NETCHN
IFN NCP,{
	move a,smojfn		; MTOPR arg: A = JFN
	movei b,.moain		; MTOPR arg: B = function code
	movsi c,(inschn_30.\77_24.\netchn_18.)
	mtopr			; assign INS/INR and state change interrupt
				; channels
} ;IFN NCP
IFN TCP,{
	move a,smojfn		; Get JCN (including TCP%JS)
	move b,[<inschn_30.>+<77_24.>+<77_18.>+<77_12.>+<netchn_6.>+77]
	tcpchn			; Assign INSCHN to INTRP (urgent data)
				; and NETCHN to state change (open/close).
	 call [	say "Cannot assign PSIs for TCP conn - "
		call tcpe
		jrst erhalt]
} ;IFN TCP
	return
} ; IFN NCP\TCP

icperr:	asciz "Error connecting to foreign host - "
} ; IFN TNX&NET

IFN TNX&NET,{

IFN CHAOS,{
chaicp:	move a,[ascii "CHA:"]
	movem a,hstbfr+0
	move a,[100700,,hstbfr]
	move b,[440700,,hstnam]
	call icp3
	move b,[440700,,[asciz ".SUPDUP"]]
	call icp3
	movei b,0
	idpb b,a
	movsi a,(gj%sht)
	hrroi b,hstbfr
	gtjfn
	 return
	movem a,smojfn
	movem a,smijfn
				; OPENF arg: A = JFN
	move b,[8._30.\of%rd\of%wr]	; OPENF arg: B = byte size, data
					; mode, control bits
	openf			; open receive connection in immediate return
				; mode
	 return			; should release JFN
	aos (p)
	return
} ; IFN CHAOS

IFN NCP,{
ncpicp:	move a,[ascii "NET:"]
	movem a,hstbfr+0
	move a,[100700,,hstbfr]
	movei b,2		; get next local socket no.
	addb b,lskt		; ...
	subi b,2		; ...
	call icp2
	movei b,".
	idpb b,a
	move b,[440700,,hstnam]
	call icp3
	movn b,icpskt
	call icp2
	call icp1
	movsi a,(gj%sht)
	hrroi b,hstbfr
	gtjfn
	 return
	movem a,smojfn		; GTJFN result: OPENF arg: A = JFN
	move b,[32._30.\of%rd]	; OPENF arg: B = byte size, control bits
	openf			; ICP to foreign connection socket
	 jerr1 icperr
				; BIN arg: A = JFN
	bin			; get foreign socket no.
	movem b,fskt		; save for later
				; GDSTS arg: A = JFN
	gdsts			; get foreign host no.
				; GDSTS result: B = connection state,
				; C = host no., D = socket no.
	hrroi a,hstnam		; CVHST arg: A = B.P.
	move b,c		; CVHST arg: B = host no.
	cvhst			; get official host name
	 jfcl			; OK if didn't write anything
	move a,smojfn		; CLOSF arg: A = JFN
	closf
	 return
	move a,[100700,,hstbfr]
	movei b,2		; get next local socket no.
	addb b,lskt		; ...
	subi b,2		; ...
	call icp2
	movei t1,".
	idpb t1,a
	move b,[440700,,hstnam]
	call icp3
	movn b,fskt
	call icp2
	call icp1
	movsi a,(gj%sht)
	hrroi b,hstbfr
	gtjfn
	 return
	movem a,smijfn
	movsi a,(gj%sht)
	hrroi b,hstbfr
	gtjfn
	 return
	movem a,smojfn		; OPENF arg: A = JFN
	move b,[8._30.\6_26.\of%rd]	; OPENF arg: B = byte size, data
					; mode, control bits
	openf			; open receive connection in immediate return
				; mode
	 return
	move a,smijfn		; OPENF arg: A = JFN
	move b,[8._30.\5_26.\of%wr]	; OPENF arg: B = byte size, data
					; mode, control bits
	openf			; open send connection in buffered send mode
	 return
	aos (p)
	return

icp1:	movei b,";
	idpb b,a
	movei b,"T
	idpb b,a
	movei b,0
	idpb b,a
	return

icp2:	movei c,8.
	nout
	 .lose
	return
} ;IFN NCP

IFN TCP,{
tcpicp:	movei a,.gthsn
	hrroi b,hstnam
	gthst		; Find host address
	 jerr1 [asciz "GTHST failed, unknown host name - "]
	movem c,frnhst	; Store it
	time
	andi a,177777	; Use time to get local port (ugh bletch)
	move b,a
	move a,[tcp%fs+tcp%wt+tcp%ps+tcblk]	; Set up ptr to TCB
	setzm (a)	; Set local host #
	movem b,1(a)	; Store local port #
	move b,icpskt
	movem b,3(a)	; Store foreign port #
	movem c,2(a)	; Store foreign host #
	movei b,60.	; 1 minute to try opening connection
	move c,[3002,,2]
;;TENEX should now be using TCP-4.
;;IFN 10X,addi a,1	; If TENEX, assume TCP-3 (sigh)
	tcpopn
	 call [	say "TCP open failed - "
		call tcpe
		jrst erhalt]
	hrrzs a
	tlo a,(tcp%js)
	movem a,smojfn
	movem a,smijfn
	movem a,tcpjcn
	call tcpini
	aos (p)
	return

mvar tcblk(4)

} ;IFN TCP

icp3a:	idpb t1,a
icp3:	ildb t1,b
	jumpn t1,icp3a
	return
} ; IFN TNX&NET

IFN NET,{

IAC==:255.	; TELNET protocol escape, "Interpret As Command".

IA$SE==: 240.	; Subnegotiation End
IA$NOP==:241.	; No-Op
IA$DM==: 242.	; Data Mark
IA$BRK==:243.	; NVT char BREAK
IA$IP==: 244.	; Interrupt Process function
IA$AO==: 245.	; Abort Output function
IA$AYT==:246.	; Are You There function
IA$EC==: 247.	; Erase Character function
IA$EL==: 248.	; Erase Line function
IA$GA==: 249.	; Go Ahead signal
IA$SB==: 250.	; Subnegotiation Begin
IA$WIL==:251.	; WILL
IA$WNT==:252.	; WON'T
IA$DO==: 253.	; DO
IA$DNT==:254.	; DON'T

PRT$TN==:23.	; Port # for TELNET
PRT$SD==:137	; Port # for SUPDUP


; TELNET option rules:
;	Parties may only request a change in option status, i.e. they cannot
;		send a "request" merely to announce mode status.
;	If a party receives a request to enter some mode it is already
;		in, the request should NOT be acknowledged.  All others
;		should always be acknowledged.
; See RFC 854, "Telnet Protocol Specification" for more details.

; TELNET Option definitions

define telop name,val,&strnam&
to$!name==:val
tel!name: val
	block 4
	[asciz strnam]
termin

; TELNET option entry format
$TOVAL==:0	; Option number
$TOLOC==:1	; Local option status
$TOREM==:2	; Remote "
$TONGL==:3	; Local option negotiation status
$TONGR==:4	; Remote   "
$TONAM==:5	; Addr of ASCIZ short name of option
  $TOL==:6	; # of words per option entry

; $TOLOC shows LOCAL  option status (as sender)
; $TOREM shows REMOTE option status (as receiver)
;	-1 if option in effect, 0 (default) otherwise.
; $TONGL holds LOCAL negotiation status.
;	LH remembers what we received, RH what we sent.
;	0  - nothing received/sent, or negotiation complete.
;	-1 - LH: received DON'T	RH: sent WON'T
;	+1 - LH: received DO	RH: sent WILL
; $TONGR holds REMOTE negotiation status.
;	LH remembers what we received, RH what we sent.
;	0 - nothing received/sent, or negotiation complete.
;	-1 - LH: received WON'T	RH: sent DON'T
;	+1 - LH: received WILL	RH: sent DO

constants
section MAINVAR
tloptb:
telop bin,0,"Binary"	; Transmit-Binary
telop ech,1,"Echo"	; Echo
telop sga,3,"SuprGA"	; Suppress-Go-Ahead
telop sta,5,"Status"	; Status
telop tim,6,"Tim-Mark"	; Timing-Mark
telop sup,21.,"SUPDUP"	; SUPDUP
telop ext,255.,"ExOpL"	; Extended-Options-List
ntlops==<.-tloptb>/$tol	; # of options
teljnk:	block $tol	; Junk option pointed to when no match.

; May wish to have small temp table of remote unknown-option requests
; which need refusing at some point.
section MAIN


; STLGET - Get a TELNET item (char or option)
; Returns .+1:
;	A/ <char> - plain character
; Returns .+2:
;	A/ <option #> - TELNET option received
;	B/ <flag>,,<DO/etc>	; Flag is -1 for DON'T/WON'T, 0 otherwise.
;	C/ <ptr to option entry>	; 0 if unknown option.
;	Updates appropriate entry in options table.
;	If option is unknown, caller should probably call SAVOPT to save
;	it in a buffer for later refusal.

stlget:	call sbini	; Get a char
	caie a,IAC
	 ret		; Just a plain char, return it.
	call sbini	; Was an IAC escape, get next.
	cail a,IA$WIL	; 251. through
	 caile a,IA$DNT	; 254. inclusive.
	  jrst stlget	; Not an option negotiation so ignore it for now.

	push p,a	; Save the op
	call sbini	; Get option code
	pop p,b		; Restore op to B
	move c,[-ntlops,,tloptb]
stlgt0:	camn a,$toval(c)
	 jrst @(b)-IA$WIL+[stlgt1 ? stlgt2 ? stlgt3 ? stlgt4]
	addi c,$tol-1
	aobjn c,stlgt0

	; Unknown option.
	setz c,		; Couldn't find, say junk option.
	caie b,IA$WNT
	 cain b,IA$DNT
	  tlo b,-1
	jrst popj1

	; WILL
stlgt1:	movei a,1
	hrlm a,$tongr(c)
	jrst stlgt5

	; WON'T
stlgt2:	hrros $tongr(c)
	tlo b,-1
	jrst stlgt5

	; DO
stlgt3:	movei a,1
	hrlm a,$tongl(c)
	jrst stlgt5

	; DON'T
stlgt4:	hrros $tongl(c)
	tlo b,-1
stlgt5:	move a,$toval(c)
	aos (p)
	ret

constants
section INIT

ivar icpskt	; Socket/Port # to use for NCP/TCP
mvar usetel	; -1 if using TELNET protocol on connection
ivar supneg	; -1 to try negotiating for SUPDUP (must have usetel set)
		; Note that TELSUP+$TOREM will be set if SUPDUP in effect.

optbfl==20	; # of random options we can remember to reply to.
ivar optbfp	; index of 1st free buffer wd
ivar optbuf(optbfl)	; Random option entries, <DO/etc>,,<option #>


; NETCNF - Figure out which socket/port/contact-name to use
;	Also does last-minute host spec check.

netcnf:
IFN ITS,skipe frnhst		; ITS always needs number at this point.
	skipn hstnam		; HOST <name> specified?
	 jrst [	saycr "HOST <name> required."
		jrst logout ]

	skipg jtelnt		; Only if explicitly requested for now.
	 jrst [	movei a,PRT$SD	; Use SUPDUP
		movem a,icpskt
		setzm usetel	; Don't use TELNET protocol
		setom telsup+$torem	; Say SUPDUP option in effect
		ret]
	movei a,PRT$TN		; Use TELNET
	movem a,icpskt
	setom usetel		; Say to use TELNET protocol
	setom supneg		; and try negotiating for SUPDUP anyway.
	ret

netini:	skipe telsup+$torem	; Already hacking SUPDUP?
	 jrst neti50		; Yes, can skip this stuff.
	skipn usetel		; Using TELNET protocol?
	 jrst neti90		; Nope, use "direct" unvarnished connection!

	; Using TELNET protocol!  See whether to negotiate for SUPDUPness...
	skipn supneg
	 jrst neti30		; No SUPDUP, must use plain TELNET conns.

	; Negotiate for SUPDUP.  Send IAC DO SUPDUP
	move a,[IA$DO,,telsup]
	call sndopt		; Send TELNET option

	; Now wait for response.
neti10:	call stlget	; Get a TELNET option or char.
	 jrst [	pbout	; Not an option, just echo it.
		jrst neti10]
	cain a,TO$SUP	; Was it the SUPDUP option?
	 jrst [	jumple b,neti30	; Yes, check the response and jump if failed
		setzm usetel	; Won, reply was WILL!
		jrst neti50]	; Go hack SUPDUP protocol now.
	jumpn c,neti10		; Was it a known option?  If so, already noted.
	hrli a,(b)		; Nope, so must remember it specially.
	aos c,optbfp		; Get index into option buffer
	caile c,optbfl
	 jrst neti10		; Ignore completely if no more room in buffer.
	movem a,optbuf-1(c)	; Store <DO/etc>,,<option #> in buffer.
	jrst neti10

	; Sigh, assume no SUPDUP, just use plain TELNET.
neti30:	setzm telsup+$tongr	; Say SUPDUP negotiations complete (if any).
	move c,simadr		; See if we were depending on simulating SOFT
	cain c,soft
	 jrst [	movei c,nvt	; Ugh, gotta change it.  Use NVT for now.
		movem c,simadr
		call simini
		jrst .+1]
	; Here, we should send out desired TELNET options, and respond
	; to the ones we've already received!
	; First reject all unknown options.
	skipn d,optbfp		; See if any unknown options received.
	 jrst neti35
	caile d,optbfl
	 movei d,optbfl
	imul d,[-1,,]
neti32:	move a,optbuf(d)	; Get received option
	hlrz b,a		; Isolate DO/etc
	caie b,IA$WNT
	 cain b,IA$DNT		; If it's a negative option,
	  jrst neti33		; then just ignore, no response needed.
	cain b,IA$DO		; If asking us to DO something,
	 hrli a,IA$WNT		; say we WON'T.
	cain b,IA$WIL		; If WILL do something,
	 hrli a,IA$DNT		; respond please DON'T.
	tlo a,(setz)		; Set sign bit to indicate RH is option #
	call sndopt		; Then send back our response!
neti33:	aobjn c,neti32
	setzm optbfp		; Clear just for neatness.

	; Now tell remote site which options we want to have
neti35:	move a,[IA$DO,,telech]	; Send IAC DO ECHO
	call sndopt

	; Now see if any unfinished negotiations to reply to.
	move d,[-ntlops,,tloptb]
neti36:	skipe a,$tongl(d)	; Any local-option negotiations?
	 jrst [	tlnn a,-1	; Check for received requests
		 jrst .+1
		movsi a,IA$WNT	; Refuse the request.
		hrri a,(c)
		call sndopt
		jrst .+1]
	skipe a,$tongr(d)	; Any remote-option negs?
	 jrst [	tlnn a,-1	; Check for received offers.
		 jrst .+1
		movsi a,IA$DNT	; Refuse the offer.
		hrri a,(c)
		call sndopt
		jrst .+1]
	addi d,$tol-1
	aobjn d,neti36

	jrst neti90

	; Hack SUPDUP protocol!
	; Note that this forces the simulation type to be SOFT since
	; otherwise there is no reason to be using supdup!
neti50:	movei c,soft		; Force to SOFT no matter what user said.
	movem c,simadr
	call simini		; and set up vars for that simulation type.
	call setup4		; Set up ITS TTY vars from term defs
	move b,[440600,,spdblk]
	movei c,lspdblk*6
neti52:	ildb a,b	; Send the ITS TTY vars to remote host.
	call smibout
	sojg c,neti52
	call smifrc
neti53:	call sbini
	jumpl a,logout
	cain a,%tdnop	; Until a confirming %TDNOP is seen,
	 jrst neti90
	pbout		; Echo to user's terminal.
	jrst neti53

neti90:
	return

} ; IFN NET


; SETUP4 - ...
; Set up the ITS TTY variables
;	TCMXV, TCMXH, SMARTS, TTYROL, TCTYP, TTYOPT

setup4:	.i tcmxv=wheight
	.i tcmxh=wwidth-1
	setzm smarts
	move t1,.tpscr+tb
	movem t1,ttyrol
	move t1,simadr
	cain t1,vt52
	 jrst [	movei t1,%tnesc
		movem t1,tctyp
		move a,[%toers+%tomvb+%tomvu+%tolwr+%tolid,,3*%tpptb]
		jrst su4.1 ]
	caie t1,soft		; simulating an ITS Software-TTY?
	 jrst [	movei t1,%tnprt	; No, tell ITS it's a "printing" TTY.
		movem t1,tctyp	; ...
		move a,[%tomor+%tolwr,,%tpors]	; and use these flags.
		jrst su4.2 ]
	movei t1,%tnsfw
	movem t1,tctyp
	move a,[%toers+%tomvb+%tomvu+%tomor+%tolwr+%tolid+%tocid,,%tpors+%tpcbs+%tprsc]
	skipge tpcbs		; NO TPCBS?
	 trz a,%tpcbs		; yes
su4.1:	trne f,%fsail
	 tlo a,%tosai
	trne f,%ffci		; Hacking full 12-bit (bucky bit) char input?
	 tlo a,%tofci		; Yup, say so.
	tlne a,%tofci		; If hacking 12-bit input, then
	 trz f,%f8ci		;  ensure we don't bother with 8-bit hacking.
	trne f,%f8ci		; If %TOFCI isn't set, but 8th bit is useful
	 tlo a,%tofci		;  then claim we have full input char set!
	skiple glassw
	 tlz a,%tomvu+%toers	; GLASS option, don't claim to be a display
	trnn f,%fnilp		; terminal support insert and delete line?
	 trne f,%fndlp		; ...
	  tdz a,[%tolid,,%tprsc]	; no, turn off %TOLID
	trnn f,%fnicp		; terminal support insert and delete character?
	 trne f,%fndcp		; ...
	  tlz a,%tocid		; no, turn off %TOCID

su4.2:	skiple jsail		; SAIL specified?
	 tlo a,%tosa1		; yes, do :TCTYP SAIL
	skiple jscrol		; SCROLL specified?
	 tlo a,%torol		; yes, do :TCTYP SCROLL
	movem a,ttyopt
	return

subttl	Setup - Attach and Login STY

IFN STY,{
IFN ITS,{
; NOTE!  Because we allow the output process to run briefly, the
; stack gets messed up.  Thus, SLOGIN preserves its return address
; specially, and SLOGIN's caller (just the CRTSTY mainline at nonce)
; cannot be allowed to use the stack again for anything (eg for calls!).
; Perhaps later this crock can be cleaned up by switching to the SMOPDL
; stack.
ivar slogrt		; Save SLOGIN return addr
ivar slogac(4)		; Saved ACs

slogin:	pop p,slogrt		; Save our return addr, and flush stack.
	setzm ibufpt			; clear "flag" to hang on
	.suset [.sadf2,,[1_pyi]]	; now undefer STY interrupts
	movei a,^Z
	call tyiput
	skipn ibufpt		; wait until got going. (typing out login msg)
	 .hang			; The first SMOBIN will trip this.
	.suset [.sidf2,,[1_pyi]]	; now defer interrupts again
					; (couldn't use stack if STY
					; interrupts weren't deferred)
	movem a,slogac		; Save ACs
	movem e,slogac+1
	move a,juname		; NO LOGIN specified?
	aoje a,logi3		; yes
	move e,[440600,,juname]	; byte pointer to login name
	skipe juname		; if login name already specified,
	 jrst logi1		; just use it.
	move e,[440600,,xuname]	; else if xuname begins with punctuation,
	ildb a,e		; (hack for compatibility with old stuff)
	caile a,17		; see if punctuation, (40-57), if so use rest.
	 move e,[440600,,xuname]	; isn't punctuation, use whole xuname.
logi1:	ildb a,e
	jumpe a,logi2
	addi a,40		; convert to ascii
	call tyiput
	tlne e,770000		; Stop when run out.
	 jrst logi1
logi2:	movei a,33		; send out $U to terminate login
	call tyiput
	movei a,"U
	call tyiput
logi3:	move a,slogac		; Restore ACs
	move e,slogac+1
	jrst @slogrt		; and return.
;;	ret
} ; IFN ITS

IFN TNX,{
; Note that the output process (which would otherwise echo these chars)
; is NOT allowed to run for TNX, so we don't have to worry about preserving
; the call context as for the ITS version.

ivar lname(10.)
slogin:	movei a,^C
	call tyiput
	skipge jlogin		; NO LOGIN specified?
	 jrst logi3		; yes, skip this cruft
	movei a,500.		; DISMS arg: no. of milliseconds
	disms			; wait for ^C to be acted upon or else login
				; command gets lost
	hrroi a,lname
	move b,ldir
	dirst
	 jrst logi3
irpc X,,[LOGIN ]
	movei a,"X
	call tyiput
termin
	push p,[440700,,lname]
	caia
logi1:	 call tyiput
	ildb a,(p)
	jumpn a,logi1
	pop p,a
	movei a,40
	call tyiput
	movei a,^M
	call tyiput
logi3:	ret
} ;IFN TNX
} ;IFN STY

IFN TNX,{
attach:	ret		; No such thing as attaching on TNX.

} ;IFN TNX

IFN ITS,{

sii:	move a,[-2,,[
		sixbit /ttycom/ ? movsi %tcrfs	; refuse com links to
						; supported TTY
;		sixbit /ttysts/ ? movsi %tssii	; turn on super-image input
		]]
	$call ttyvar,[#tyic,a]
	 .lose %lsfil
	$call ttyset,[#tyic,[030303,,030303],[030303,,030303],[%tssii,,0]]
	 .lose %lsfil		; just until TTYVAR can hack TTYSTS
	return


attach:	skipge @suppro		; top-level?
	 jrst attac4		; yes, skip the nonsense
	move a,option		; DDT superior?
	tlnn a,%opddt		; ...
	 jrst [	saycr "Superior isn't DDT; can't attach."
		return ]
	$call usrvar,[#%jssup,[sixbit/suppro/]][a]
	 .lose %lssys
	jumpge a,[
		saycr "Superior isn't top-level; can't attach."
		return ]	; if superior isn't top-level then forget it

	;; We have a top-level superior which claims to be DDT.

	.value [asciz ":attach "]
	; The following code is will be unnecessary when we can specify the
	; ATTACH call control bits with :ATTACH.  Control bit 1.3 will P
	; us only after we've become top-level.
	skipl @suppro
	 .hang

attac3:	$call usrvar,[#%jself,[sixbit/jname/],[sixbit/hactrn/],?a]
				; change our JNAME to HACTRN to
				; insure DDT has vanished
	 jrst [	caie a,%eexfl	; failed, "file already exists" error?
		 $call lose,[#%lssys,#attac3]	; no, lose
		movei a,1	; wait a while
		.sleep a,	; ...
		jrst attac3	; and try again
		]

	;; We are a top-level job.  Change our name to reflect the
	;; supportted terminal.  This also allows the user to login
	;; as FOO instead of FOO0.
attac4:	hlrz a,.tpnam+tb		; get sixbit name of terminal
	move a,(a)			; ...
	move t1,[-6,,[
		sixbit /mask/	? tdo [ftl%pi+%pitty+%piaty]
		sixbit /tty/	? tlo %tbint
		sixbit /sname/	? move a
		]]
	$call usrvar,[#%jself,t1]	; enable interrupts on fatal
	 .lose %lssys			; conditions and missing TTY
					; set SNAME to terminal name
attac5:	$call usrvar,[#%jself,[sixbit/jname/],a,?b]
					; try to set jname to term name
	 jrst [	caie b,%eexfl		; failed, "already exists" error?
		 $call lose,[#%lssys,#attac5]
		aoja a,attac5		; yes, bump and try again
		]
	return
} ; IFN ITS

; STDWRN - semi-standard warning routine.
;	A - ASCNT ptr to string to display as warning message.
; UNDELW - Entry pt for standard warning msg about DEL/underscore switch.

undlcw:	xct .teclr+tb		; Another entry pt to clear screen normally.
undelw:	move a,[ascnt " Warning: interchanged Underscore and Delete keys."]
stdwrn:	skipge jwarn
	 return
	pushae p,[nh,nv]
	move nv,wheight
	lsh nv,-1		; Put message halfway down screen.
	add nv,wvmin
	move nh,whmin
	call td.mfrc		; Move cursor there.
	call td.bow		; Switch to standout mode.
	call warn		; output warning message.
	call td.rst		; Reset standout mode.
	popae p,[nv,nh]
	return

warn:	skipge jwarn		; Send warning message only if switch allows.
	 return
	pushae p,[b,c]
	move c,a
	hrli c,440700
	hlrz b,a
	jumpe b,warn4
warn2:	ildb a,c
	cain a,^M
	 jrst [	movei nh,0
		jrst warn3 ]
	cain a,^J
	 aoja nv,warn3
	call td.cho
warn3:	sojg b,warn2
warn4:	call tyofin		; make sure obuff completely empty
	sleep 10.		; let user see message for at least a second
	popae p,[c,b]
	return

IFN ITS,{
; ITSMAP - Map an ITS location into address space.
; Arguments:
;   A	SQUOZE variable name.
;   B	offset
; Result:
;   A	pointer in our address space to location.

itsmap:	.eval a,
	 .lose %lssys
	add a,b
	idivi a,pg$siz
	$call corblk,[#%cbndr,#%jself,syspno,#%jsnum+0,a]
	 .lose %lssys
	move a,syspno
	lsh a,pg$log
	add a,b
	aos syspno
	return

ivar syspno			; next page to use for mapping

} ; IFN ITS

; TRMFLS - flush unneeded terminal pages.
trmfls:	move b,trmadr
	move c,simadr
	caie c,vt52
	 cain c,soft		; Note kludge to avoid always saving SOFT.
	  move c,b
	movsi d,-nterms
	hlrz a,pagtab		; Get 1st page
trmfl2:	came b,trmtab(d)
	 camn c,trmtab(d)
	  call trmfl4		; hit protected entry, hack it.
	aobjn d,trmfl2		; drop thru when done,
	movei d,nterms-1	; faking out pagtab reference.
	hrrz e,pagtab(d)
	aoja e,trmfl5

	; hit one of protected entries, flush pages bypassed so far.
	; A has first page to start flushing at.
trmfl4:	hlrz e,pagtab(d)	; Find 1st page of protected
trmfl5:	subi e,(a)		; Find # pages to flush
	jumple e,trmfl6		; jump if none.
	movn e,e
	hrl a,e			; Now have page AOBJN
	call corfls
trmfl6:	hrrz a,pagtab(d)	; Now find last page protected,
	addi a,1		; and use that+1 as 1st page to flush next.
	return


; TRMEND macro deposits data here.
ifndef maxtrm, maxtrm==120.	; Gads! (Gadzooks! -CBF 21Jun80)
trmtab: block maxtrm		; address of terminal table
pagtab:	block maxtrm		; <first page>,,<last page>


constants
SECTION MAIN

IFN NCP\TCP,{
mvar inscnt
mvar supres
} ; IFN NCP\TCP

IFN ITS,{
; ITS variables for CRTSTY
mvar option		; our OPTION
mvar uname		; our UNAME
mvar jname		; our JNAME
mvar uind		; our UIND (user index)
mvar xuname		; our XUNAME
mvar xjname		; our XJNAME
mvar cnsl		; our CNSL


mvar buffct			; negative number of chars left to put

mvar lublk

; Pointers to system variables.
mvar time	; holds address of system time variable
mvar myuind	; Holds internal ITS user index of this job.
mvar aprc	; holds addr indirected thru for direct APRC user-var check.
mvar suppro	; holds address of SUPPRO user-variable
mvar torm	; holds addr indirected thru for direct TORM+Tnm check.
		; TORM(I) holds # chars free in output buffer.
IFN STY,{
mvar stynum 	; holds # of STY opened.  Used to index TTYSTS, TTYOAC in sys.
mvar ttyoac	; holds addr indirected thru for direct TTYOAC+Snm check.
		; TTYOAC(I) is -1 if output inactive.
mvar ttysts	; holds addr indirected thru for direct TTYSTS+Snm check.
		; TTYSTS(I) sign bit indicates terminal is free.
} ; IFN STY
} ; IFN ITS

IFN TNX,{
mvar ldir			; login directory no.
mvar cnsl
mvar ttytyp			; TTY type from GTTYP.
mvar ttyjfn
mvar smojfn
mvar smijfn
mvar oldtiw			; old terminal interrupt word
mvar oldmod			; old JFN mode word
IFN STY,{
mvar syspty
mvar firpty
mvar ptyttd
} ; IFN STY
IFN NCP\TCP,{
mvar lskt
mvar fskt
} ; IFN NCP\TCP
IFE TINT\SINT,{
mvar rcvfrk
}
} ; IFN TNX


SECTION MAINVAR
spdblk:	-<lspdblk-1>,,0
tctyp:	block 1
ttyopt:	block 1
tcmxv:	block 1
tcmxh:	block 1
ttyrol:	block 1
smarts:	block 1
ispeed:	block 1		; input speed variable (in bps)
ospeed:	block 1		; output speed variable (in bps)
lspdblk==:.-spdblk

SECTION MAIN

mvar feepmx	; If pos, holds # clock ticks of inactivity to cause feep.
mvar feeptm	; Countdown to see if should feep when output appears.
mvar ofeptm	; "old-feeptm" check to help canonicalize feeptm.

mvar speed		; output speed in characters per second
mvar buffmx		; negative number of chars put out before .listen

; CORFLS - Remove unneeded pages from address space.
; Argument:
;   A	-<no. pages>,,<first page>

IFN ITS,{
corfls:	$call corblk,[#0,#%jself,a]
	 .lose %lssys
	return
} ; IFN ITS
IFN 20X,{
corfls:	pushae p,[b,c]		; save ACs
	hlre c,a		; PMAP arg: control bits,,repeat count
	movn c,c		; ...
	tlo c,(pm%cnt)		; set repeat count control bit
	move b,a		; PMAP arg: process handle,,page no.
	hrli b,.fhslf		; ...
	seto a,			; PMAP arg: source of -1 to unmap
	pmap			; remove specified pages
	popae p,[c,b]		; restore ACs
	return
} ; IFN 20X
IFN 10X,{
corfls:	pushae p,[b,d]		; save ACs
	move d,a		; copy argument
corf1:	move b,d		; PMAP arg: process handle,,page no.
	hrli b,.fhslf		; ...
	seto a,			; PMAP arg: source of -1 to unmap
	pmap			; remove one page
	aobjn d,corf1
	popae p,[d,b]		; restore ACs
	return
} ; IFN 10X

IFN TNX&NET&TCP,{

tcp%js==setz		; JCN furnished to call
tcp%wt==1_<35.-1>	; Wait for function to complete
tcp%fs==1_<35.-5.>	; Force Sync
tcp%ps==1_<35.-6.>	; Persist - keep sendin SYN
tcp%dn==1_<35.-12.>	; Buffer flag: Set when TCP done with buffer.
tcp%ur==1_<35.-15.>	; Buffer flag: last byte is Urgent
tcp%el==1_<35.-16.>	; Buffer flag: send "end-of-letter" with buffer.
tcpsnd=:<jsys 740>
tcprcv=:<jsys 741>
tcpopn=:<jsys 742>
tcpcls=:<jsys 743>
tcpsc=:<jsys 744>
tcpst=:<jsys 745>		;STATUS
tcpchn=:<jsys 746>
tcpabt=:<jsys 747>

mvar tcpjcn

tcpini:	call tcpoi
	setzm tcpict
	ret

.scalar tcpict	; # bytes left to read
.scalar tcpibp	; BP for read
tcpiln==2000
.scalar tcpibf(tcpiln/4)

	call tcpifl
tcpchi:	sosge tcpict
	 jrst .-2
	ildb a,tcpibp
	ret

tcpifl:	pushae p,[a,b,c]
	movei a,10.		; Allow 10 tries of 5 sec each
	movem a,tcpiwt
tretry:	move a,tcpjcn
	hrli a,(tcp%js+tcp%wt)
	movei b,tcpihd
	setzm (b)	; Clear buffer flags
	movei c,tcpibf
	movem c,1(b)	; Set buffer addr
	movei c,tcpiln
	movem c,2(b)
	tcprcv		; Do it!
	 call tcperr	; Foo?  Handle TCP call error.
retest:	move a,tcpihd	; Get flags
	tlnn a,(tcp%dn)	; TCP done?
	 jrst [	sosge tcpiwt
		 jrst .+1
		movei a,5*1000.
		disms
		jrst retest]
	movei a,tcpiln
	sub a,tcpihd+2
	jumple a,[sosge tcpiwt
		 call [	say "TCP input timeout"		; give up
			jrst erhalt]
		movei a,5*1000.
		disms			; Sleep for 5 sec
		jrst tretry]
	movem a,tcpict
	move a,[441000,,tcpibf]
	movem a,tcpibp
	popae p,[c,b,a]
	ret

.scalar tcpiwt	; retry count
.scalar tcpihd(3)	; flags, buff adr, # bytes

.scalar tcpoct	; # chars left for output
.scalar tcpobp	; BP for deposit
tcpoln==512.
.scalar tcpobf(tcpoln/4)

tcpcho:	sosge tcpoct
	 jrst [	setzm tcpoct
		call tcpofl
		jrst tcpcho]
	idpb a,tcpobp
	ret
tcpofl:	push p,a
	move a,tcpoct	; Check # bytes left in buffer
	cail a,tcpoln	; Must be less than buffer length
	 jrst [	pop p,a	; No, nothing to send.  Don't try, or will hang!
		pjrst tcpoi]
	pushae p,[b,c,d]
	move a,tcpjcn
	hrli a,(tcp%js+tcp%wt)
	movei b,tcpohd
	movsi c,(tcp%el)	; Say to PUSH it out
	movem c,(b)	; Set buffer flags
	movei c,tcpobf
	movem c,1(b)	; Set buffer addr
	movei c,tcpoln
	sub c,tcpoct
	movem c,2(b)
	movei c,0	; infinite timeout
	move d,tcprtr
	tcpsnd		; do it!
	 call tcperr	; aw phooey
	call tcpoi
	popae p,[d,c,b,a]
	ret
tcpoi:	push p,[tcpoln]
	pop p,tcpoct
	push p,[441000,,tcpobf]
	pop p,tcpobp
	ret

tcprtr:	003002,,0		; retrans params
.scalar tcpohd(3)	; flags, buff addr, # bytes

tcperr:	say "TCP call error - "
	call tcpe
	jrst logout


; TCPE - output TCP error message for given number.
;	A/ TCP error #

tcpe:	skipge t1,a
	 skipa t1,[-1]
	  andi t1,37		; Mask to 5 bits (unless -1)
	move t1,tcestr(t1)	; Get ASCNT for error string
	call typasc
	ret

;; TCP error strings -- pointer table indexed by 5 bit error code
	ascnt "Internal program error (-1)"	; -1
tcestr:	ascnt "Unknown error (0)"		; 0 (decimal)
	ascnt "Argument error in JSYS"	; 1
	ascnt "Invalid options specified"	; 2
	ascnt "Connection not open"		; 3
	ascnt "Temporarily out of resources"	; 4
	ascnt "Wild fgn host/port not allowed"	; 5
	ascnt "Connection already exists"	; 6
	ascnt "Connection rejected or reset"	; 7
	ascnt "Unknown error (8)"		; 8
	ascnt "Transmission timeout"		; 9
	ascnt "Unknown error (10)"		; 10
	ascnt "Unknown error (11)"		; 11
	ascnt "Connection closed or closing"	; 12
	ascnt "Wild local port illegal"	; 13
	ascnt "Connection reset"		; 14
	ascnt "Bad buffer argument"		; 15
	ascnt "Insufficient local resources"	; 16
	ascnt "Bad channel arg to CHANL"	; 17
	ascnt "Unknown error (18)"		; 18
	ascnt "Unknown error (19)"		; 19
	ascnt "Bad STAT offset"		; 20
	ascnt "Bad STAT count"		; 21
	ascnt "Bad STAT name"			; 22
	ascnt "Unknown error (23)"		; 23
	ascnt "Unknown error (24)"		; 24
	ascnt "Unknown error (25)"		; 25
	ascnt "Unknown error (26)"		; 26
	ascnt "Unknown error (27)"		; 27
	ascnt "Unknown error (28)"		; 28
	ascnt "Cannot change security level"	; 29
	ascnt "Use of TCP%VT not allowed"	; 30
	ascnt "TCP not available"		; 31

} ;IFN TNX&NET&TCP

subttl	Part II - UUOs, Interrupts, I/O, etc.
subttl	UUO dispatch

tmploc 41,{
	call uuoh		; UUO handler
}

; UUOH - UUO handler.
uuoh:	ldb t1,[$opcod,,40]	; get opcode
	caig t1,nuuo		; ensure within bounds
	 jrst @uuotab(t1)	; dispatch if so
IFN ITS,{
iluuo:	.suset [.sipirqc,,[%piilo]]	; give illegal operation interrupt
	return			; if we're continued just ignore UUO
} ; IFN ITS
IFN TNX,{
iluuo:	pushae p,[a,b]		; save ACs
	movei a,.fhslf		; IIC arg: A = fork handle
	movx b,1_<35.-.icili>	; IIC arg: B = channel mask
	iic			; give illegal instruction interrupt
	popae p,[b,a]		; restore ACs
	return			; if we're continued just ignore UUO
} ; IFN TNX


uuotab:	iluuo			; opcode  0 - illegal
	utyo			; opcode  1 - one or two character typeout
	utyn			; opcode  2 - TYO n times
	uzout			; opcode  3 - ASCIZ typeout
	uzoutn			; opcode  4 - ZOUT n times
	upad			; opcode  5 - padding UUO
	utyoan			; opcode  6 - TYOANS -- ANSI sequence UUO
	utynan			; opcode  7 - TYNANS -- ANS sequence UUO with
				; argument
IFN TNX, ujerr1			; opcode 10 - error reporting UUO
.ELSE	 iluuo
	iluuo			; opcode 11 - unassigned UUO (for patching)
nuuo==:.-uuotab


; UUO Opcode definition
tyo=:1_27.			; TYO is opcode 1
tyn=:2_27.			; TYN is opcode 2
zout=:3_27.			; ZOUT is opcode 3
zoutn=:4_27.			; ZOUTN is opcode 4
pad=:5_27.			; PAD is opcode 5
tyoans=:6_27.			; TYOANS is opcode 6
tynans=:7_27.			; TYNANS is opcode 7
ifn tnx, jerr1=:10_27.		; JERR1 is opcode 10

.xcref tyo,tyn

IFN ITS,{			; define how UUOs reference AC and E
..u001==:0			; TYO - EA
..u002==:0			; TYN - EA
..u005==:1			; PAD - C(EA)
..u006==:0			; TYOANS - EA
..u007==:0			; TYNANS - EA
} ; IFN ITS

subttl	Interrupt vectoring

IFN ITS,{
ftl%pi==%pipdl+%pimpv+%piilo+%pilos+%pipar
				; define fatal interrupts:
				; PDL Overflow, Memory Protect Violation,
				; Illegal Operation, .LOSE, parity error

lintpdl==7*5			; enough for 7 levels
mvar intpdl(lintpdl)		; Interrupt stack
mvar intpdp			; Interrupt stack pointer

tmploc 42,{
	-lintblk,,intblk	; new interrupt vectoring
}

SECTION MAINVAR			; switch to impure so can clobber TTYVEC and
				; STYVEC
intblk:	intpdp			; stack pointer (separate from P!)

; Asynchronous interrupts:
	0 ? 1_pyi		; STY input interrupts (most common)
	%piaty ? 1_pyi		; defer self
styvec:	styivi			; Initial dispatch; clobbered.

	0 ? 1_tyic		; TTY input interrupts
	%pirlt+%piaty ? 1_tyic+1_pyi	; defer STY, realtime, and self
ttyvec:	ttyivi			; Initial dispatch vector

	%pirlt ? 0		; realtime interrupts
	%pirlt+%piaty ? 1_tyic+1_pyi	; defer same stuff as terminal input
rltvec:	rltint			; realtime interrupt vector

	%piaty ? 0		; screen smashed
	%piaty ? 1_pyi		; defer self and output
	piaty

; Synchronous interrupts:
; If it is ever necessary for a synchronous-interrupt handler to
; look at the PC interrupted from, then that vector MUST come before
; any asynchronous interrupt vectors!  Otherwise, these almost-never-used
; handlers are kept at the bottom, to minimize overhead.
	ftl%pi ? 0		; fatal interrupts
	-1 ? -1			; defer everything
	ftlint

	%piioc ? 0		; IOC error (on disk channel maybe)
	-1 ? -1			; may be fatal, so defer everything
	iocint

	%pitty ? 0		; trying to use TTY and don't have it
	-1 ? -1			; defer everything
	detint

lintblk==.-intblk
SECTION MAIN

dismis:	$call dismis,intpdp	; dismiss interrupt
	 .lose %lssys
} ; IFN ITS

IFN TNX,{

; LEVTAB - Table indexed by priority minus 1 to get place to store PC.
levtab:	lev1pc			; level 1: errors (highest priority)
	lev2pc			; level 2: TTY input
	lev3pc			; level 3: PTY input (lowest priority)

mvar lev1pc,lev2pc,lev3pc


; CHNTAB - Table indexed by channel no.  LH of each word is priority level
; for that channel.  The RH contains the address of the interrupt routine.
; CHNTAB is set up at initialization.

mvar chntab(36.)

errlev==:1	; (Highest) Priority level for various errors
ttylev==:2	; (       ) Priority level for TTY (Input Stream) ints
ptylev==:3	; (Lowest)  Priority level for STY/NET (Output Stream) ints

iftlev==:errlev			; Level for .ICIFT (inferior termination) ints
ipschn==:5 ? ipslev==:ttylev	; Chan/lev for signals from inferior

IFN TINT,{
timchn==:0			; timer interrupts (same level as TTY)
ttychn==:1			; Channel no. for TTY interrupts
if2 ttyvec==:chntab+ttychn	; clobber TTYVEC to redirect TTY input ints
} ; IFN TINT

IFN STY&SINT,{
ptychn==:2			; channel no. for PTY interrupts
				; PTYCHN is output interrupt channel (unused),
smochn==:ptychn+1		; PTYCHN+1 is input interrupt channel
if2 styvec==:chntab+ptychn+1	; clobber STYVEC to redirect STY input
				; interrupts
} ; IFN STY&STINT

IFN NCP\TCP,{
inschn==:2 ? inslev==:ptylev	; channel no. for INS/INR interrupts
netchn==:3 ? netlev==:errlev	; channel no. for network state changes
} ; IFN NCP\TCP
IFN CHAOS&SINT,{
ntichn==:3 ? ntilev==:ptylev
smochn==:ntichn
if2 styvec==:chntab+ntichn	; clobber STYVEC to redirect STY input
				; interrupts
} ; IFN CHAOS&SINT

ticspm==:60.*1000.		; no. of timer ticks per minute

dismis:	debrk

; TNXHNG - crock to poorly simulate .HANG

tnxhng:	push p,a
	sleep 10	; sleep for a sec.
	pop p,a
	sos (p)		; return to instr prev. to call
	return

} ; IFN TNX

subttl	Miscellaneous interrupt handlers

IFN ITS,{

mvar iocvec			; address of IOC error handler

; %PIIOC interrupt, probably on disk channel.
iocint:	skipe iocvec			; IOC handler exist?
	 $call dismis,[intpdp,iocvec]	; yes, jump to it
					; fall through to FTLINT


; Fatal interrupts - MPV, PDL OV, etc.
; It's up to chance whether the following msg will be seen by
; the screwed up luser, but we'll try anyway...
ftlint:
IFN STY,{
	jsr detsty		; detach tree connected to STY
}
	move t1,[ascnt "
Ugh!  CRTSTY hit a fatal interrupt... please mail details (how you did
it, etc.) to BUG-CRTSTY@MC.
"]
	hlrz t2,t1
	hrli t1,440700
	$call siot,[#tyoc,t1,t2]
	 .lose %lsfil
	.value			; and lose, badly.  Leave job around.


; %PITTY interrupt - come here when try to use non-ex TTY.
; Probably indicates job has been detached.
detint:	skipge @suppro		; top-level?
	 jrst detin1		; yes, detach tree connected to STY and logout
	;; We're not top-level so we shouldn't have gotten the interrupt
	;; (%PITTY is only enabled for top-level CRTSTYs).  Perhaps we've
	;; been reowned??
	.suset [.sipirqc,,[%pitty]]	; let superior figure it out
	jrst dismis			; ...

	;; We're top-level and trying to use a non-existant TTY.
detin1:
IFN STY,{
	jsr detsty		; detach tree connected to STY if possible
				; fall through to LOGOUT
}


logout:	.logout			; logout if top-level
	skiple debug
	 .value [asciz /: Debug halt 
/]
	.logout 1,


IFN STY,{
; DETSTY - routine to detach STY if possible.
SECTION MAINVAR
detsty:	0 ? jrst detst0		; called via JSR.
SECTION MAIN
detst0:	$call detach,#pyi,,#4	; detach tree connected to STY and kill
				; it if no action within an hour
	 jfcl			; ok if error (e.g. no job at other end)
	jrst @detsty
}


clkfrm==5*60.			; no. of 60ths per clock tick
ticspm==60.*60./clkfrm		; no. of ticks per minute for ALARM


mvar ltime			; time of last tick

mvar rsttim			; -1 if we should do a .REALT to reset our
				; clock rate.


; RLTINT - Standard realtime interrupt handler (realtime interrupts are 
; vectored to TYIRLT when a terminal input timeout is needed).  Realtime
; interrupts serve two purposes: (1) for periodic checks of detachment,
; and (2) to implement the ALARM feature.

rltint:
	;; Check to see if top-level and detached.  If so, act as if a
	;; %PITTY interrupt happened; i.e. detach tree connected to STY
	;; and logout.
	skipl @aprc		; detached?
	 jrst rlti1		; no
	skipge @suppro		; detached, top-level?
	 jrst detin1		; detached and top-level, do %PITTY stuff

	;; Not detached and top-level.  Hack ALARM stuff.
rlti1:	push p,a		; save AC
	move a,@time		; get time of this tick
	movem a,ltime		; remember it for later
	skipe rsttim		; maybe reset time
	 jrst [	move a,[600000,,[clkfrm]]  ;  yes, reset to normal
	        .realt a,
		setzm rsttim	; note we've reset
		jrst .+1 ]

	; Check for ALARM timeout.
	move a,ofeptm		; Get old countdown
	came a,feeptm		; Same as current?
	 move a,feepmx		; No, TYI or SMI interfered, so reset to max.
	sosge a			; OK, count down some more.
	 seto a,		; canonicalize over-run to -1.
	movem a,feeptm		; and set new count-down,
	movem a,ofeptm		; saving copy for check next time.

IFN STY,{
	move a,whotim
	camg a,@time
	 .suset [.siifpir,,[1_pyi]]
} ; IFN STY
	pop p,a			; restore AC
	jrst dismis


; %PIATY interrupt.
piaty:	call redisp		; REDISP bashes registers, but that's ok
				; because all other interrupts defer %PIATY
				; and nothing is happening at main program
				; level
	jrst dismis

} ; IFN ITS

IFN ITS,{
; IPSCAL - Execute routine at Input-Process level
; 	(signalled by SMO/TYO)
;	If the routine performs any I/O it is possible that the SMI/TYI
;	modules could become confused, but since IPSCAL cannot be invoked
;	unless the input process is quiescent (waiting for the user to
;	input something) it seems fairly safe to assume that SMI won't be
;	in the middle of outputting any funny sequences.
;	A/ arg to routine
;	B/ routine addr to CALL
; Returns .+1 or .+2, whichever called routine does.
; Clobbers whatever routine does.

ipscal:	.suset [.sidf2,,[1_tyic]]	; Defer all Input-Process ints!
	call (b)			; Call the routine!
	 caia
	  aos (p)
	.suset [.sadf2,,[1_tyic]]	; Now undefer any IP ints.
	ret
} ;IFN ITS

IFN TNX,{
; IPSCAL on TNX uses a PSI interrupt channel on the same level as the
; Input Process.  This not only simplifies TYI interrupt deferring when
; running in a single fork -- it is the only way to work when using two forks.

mvar ipsarg	; Argument to routine
mvar ipsrtn	; Routine to CALL at IP level
mvar ipsflg	; -1 when waiting for routine to be executed, 0 when done.

ipscal:	movem a,ipsarg
	movem b,ipsrtn
	setom ipsflg
IFN TINT, movei a,.fhslf
IFE TINT, movei a,.fhsup
	move b,[<1_<35.-ipschn>>]	; Trigger interrupt
	iic
ipscl5:
IFE TINT,movei a,1 ? disms		; Sleep if inferior fork
	skipge ipsflg			; Don't go ahead until execution done!
	 jrst ipscl5
	ret
} ;IFN TNX

IFN TNX,{

; IPSCHN interrupt handler - handle signals from Output process
;	(may be an inferior fork)

ipsint:	pushae p,[a,b,c]
IFE TINT,call frcv		; Freeze the inferior fork
	move a,ipsarg		; Get argument for routine
	call @ipsrtn		; Execute the routine!
	setzm ipsflg		; Say execution done!
IFE TINT,call rrcv		; Resume the inferior fork
	popae p,[c,b,a]
	jrst dismis

IFE TINT\SINT,{

; .ICIFT interrupt handler.
iftint:	push p,a		; save AC
	push p,b
	push p,c
ifn CHAOS,{
	move a,smijfn		;GDSTS arg: A = File Handle
	gdsts			;Check to see if Chaos connection still there
	jumpe b,chbrk1		;Nope, we gone.
} ;ifn CHAOS
	hrrz a,rcvfrk		;get receive fork handle
	rfsts			;read the status
	tlnn a,2		;voluntary termination?
	jrst iftin1		;nope, then let it go...
	hrroi a,[asciz "Inferior fork unexpectedly terminated."]
	esout
	pop p,c
	pop p,b
	pop p,a			; restore AC
	haltf
	jrst .-1
iftin1:	pop p,c
	pop p,b
	pop p,a
	jrst dismis
} ;IFE TINT\SINT

; JERR1 uuo - report error with error code in A.
ujerr1:	pushae p,[a,b,c]	; save ACs
	move b,a		; save error code
	hrro a,40		; ESOUT arg: A = string pointer
	esout			; output argument to UUO
	movei a,.priou		; ERSTR arg: A = JFN
	hrli b,.fhslf		; ERSTR arg: B = fork handle,,error code
	movei c,0		; ERSTR arg: C = byte count,,0
	erstr			; output error message
	 jfcl			; return1: undefined error code
	 jfcl			; return2: string size out of bounds, or bad
				; JFN
	popae p,[c,b,a]		; restore ACs

erhalt:	haltf			; stop
	jrst .-1


logout:	skipg debug
	 jrst logou2
	haltf
	jrst .-1
logou2:	movei e,5
	reset			; Flush all channels, inferior, etc.
	erjmp [	sojge e,.-1	; Try several times despite failures.
		jrst .+1]
	haltf
	jrst .-1

chalos:	jumpe b,chbrok		;If zero, BIN detected EOF
	movei a,.fhslf		;GETER arg: A = fork handle
	GETER			;get the last error message
	hrrzm a,a		;Clear AC left
	caie a,IOX4		;Hit EOF packet from chaos?
	 jerr1 [asciz "Chaos Net trouble - "]	;Nope, must be fairly fatal
chbrok:				;Reached EOF, time to punt.
IFE TINT\SINT, call frcv	;If we have a receiver fork, freeze it
chbrk1:	move a,[ascnt "Host broke connection"]
	call ascout		;Inform user
	pjrst quitng		;quit.


IFN NCP\TCP,{

; INS/INR interrupts.
insint:	aosle inscnt
	 setom supres
	debrk

; Network state change interrupts.
netint:	pushae p,[a,b,c,d]
	move a,smijfn
IFN TCP,jumpl a,netnt7	; If TCP always assume the worst for now,
			; since too hard to figure out TCPST status call.
	gdsts
	lsh b,-40
	caie b,7
	 jrst netnt7
netnt9:	popae p,[d,c,b,a]
	debrk
netnt7:	call frcv
	move a,[ascnt "Host broke connection"]
	call ascout
	pjrst quitng
} ; IFN NCP\TCP
} ; IFN TNX

subttl	TTY Output

; TYPxxx routines exist for "normal" (non-binary, non-superimage) TTY output
; usually at initialization time.  Efficiency is not important.
;	For ITS these use channel TYON.
;	For TNX these use JFN .PRIOU (primary output)
; TYPASZ - T1/ BP to ASCIZ string
; TYPASC - T1/ ASCNT pointer
; TYPSTR - T1/ BP to string, T2/ # chars
; PBOUT - A/ Character	(NOTE: this is a macro!)
; TYPCR - No arg, type a CR.

typcr:	move t1,[ascnt "
"]
typasc:	hlrz t2,t1		; Get # chars in T2
	hrli t1,440700
typstr:	jumple t2,apopj
	push p,a
	ildb a,t1
	pbout
	sojg t2,.-2
	pop p,a
	ret

typasz:	push p,a
	caia
typaz2:	 pbout
	ildb a,t1
	jumpn a,typaz2
	pop p,a
	ret

constants
SECTION INIT

ttyoin:	skipn a,ospeed		; get output speed in bits per second
	 movei a,9600.		; assume 9600
	cain a,110.		; 110 bps?
	 movei a,100.		; yes, fix so will be 10cps
	idivi a,10.		; convert from BPS to CPS
	movem a,speed		; save cps in SPEED

	; Initialize terminal output

	skipn b,buffmx		; Buffer size already specified?
	 move b,speed		; no, get # chars at a time to allow.
	caile b,obufmx		; force down to fit if too big.
	 movei b,obufmx
	caig b,5		; likewise force up if too small.
	 movei b,5
	movem b,obuflm		; establish this as output buff limitation.
	movem b,obufct		; Set up cnt for obuff.
IFN ITS,{
	move a,[squoze 0,TOBS]	; Find max # chars in ITS output buffer
	.eval a,
	 .lose %lssys
	lsh b,-1		; get .5 of our buff limit
	subi a,(b)		; and find # chars TORM will indicate
				; when ITS has obuflm/2 chars buffered.
	movem a,tormin		; Store as minimum TORM to output on.
} ; IFN ITS
	move a,[441000,,obuff]	; initialize output buffer pointer
	movem a,obufpt		; ...
	.i padc=177		; initialize pad character
	; terminal output initialized, ready to go
	return

constants
SECTION MAIN

; TYOBOUT buffers a character for output to the terminal.
; A contains the character to output.  No ACs are clobbered.

tyobout:
ifn histohack,{
	move t1,a
	andi t1,377
	aos counts(t1)
}
	idpb a,obufpt		; put character into output buffer
	sosle obufct		; buffer full?
	 return			; no, we're done
	pjrst tyofrc		; yes, send buffer


mvar obufpt			; BP for depositing into buffer
mvar obufct			; # of chars still free in buffer
mvar obuflm			; # chars of buffer to be used.
obufmx==250.			; max size of buffer
mvar obuff(<obufmx+3>/4+1)

; TYOFRC - Empty our output buffer.
IFN ITS,{
; Note that the ITS symbol TOBS => max chars in output buffer
; currently has value of 260. (404 octal)
tyofrc:	move t2,obuflm		; Compare initial count with current, to
	sub t2,obufct		; make sure something to output...
	jumple t2,[return]	; Nope.
	move t1,tormin		; Get # minimum chars room in ITS output
	caml t1,@torm		; buffer to wait for, and wait..
	 .hang			; until TORM attains minimum.
	move t1,[441000,,obuff]	; pointer to beginning of buffer
	movem t1,obufpt		; reset B.P.
	addm t2,obufct		; reset count
	$call siot,[#tyoc,t1,t2]	; Send!
	 .lose %lsfil
	return

mvar tormin	; minimum no. characters in ITS output buffer to hang on
} ; IFN ITS
IFN TNX,{
tyofrc:	push p,c
	move c,obufct
	sub c,obuflm
	jumpe c,obfs1
	push p,a
	push p,b
	move a,ttyjfn
	move b,[441000,,obuff]
	movem b,obufpt		; reset BP here
	sout
	move c,obuflm
	movem c,obufct		; reset count
	pop p,b
	pop p,a
obfs1:	pop p,c
	return
} ; IFN TNX


; TYOFIN - Force output, and wait until output reaches terminal.

tyofin:	call tyofrc		; Force output buffer into system,
				; then wait until system buffer empty.
IFN ITS,{
	$call finish,#tyoc
	 .lose %lsfil
} ; IFN ITS
IFN TNX,{
	push p,a		; save AC
	move a,ttyjfn		; DOBE arg: JFN
	dobe			; dimiss until output buffer empty
	pop p,a			; restore AC
} ; IFN TNX
	return

subttl	TTY output UUOs

; UUO to output an ASCIZ string.  The effective address is a ptr to an ASCIZ
; string of 7 bit bytes which are output.
uzout:	push p,a		; save ACs
	push p,b		; ...
	move b,40		; get effective address of UUO:
				; ptr to asciz str
	hrli b,440700		; convert ptr to BP
	ildb a,b		; get first character of string
	jumpe a,uz2		; terminate on zero byte
uz1:	call @.trtyo+tb		; output character
	ildb a,b		; get next character of string
	jumpn a,uz1		; terminate on zero byte
uz2:	pop p,b			; restore ACs
	pop p,a			; ...
	return


; UUO to output an ASCIZ string N times.  The effective address is a ptr to
; an ASCIZ string of 7 bit bytes which are output.  A contains N.
uzoutn:	jumpe a,[return]
	push p,a		; save ACs
	push p,b		; ...
	push p,c		; ...
	move c,a
uzn1:	move b,40		; get effective address of UUO:
				; pointer to asciz string
	hrli b,440700		; convert ptr to BP
	ildb a,b		; get first character of string
	jumpe a,uzn3		; terminate on zero byte
uzn2:	call @.trtyo+tb		; output character
	ildb a,b		; get next character of string
	jumpn a,uzn2		; terminate on zero byte
	sojg c,uzn1
uzn3:	pop p,c			; restore ACs
	pop p,b			; ...
	pop p,a			; ...
	return


; Character output UUO:
;  TYO <immediate value> - The 18 bit address is considered to be
;	two 9-bit fields, each of which will be output to the TTY
;	in unit mode.  If the first is 0, only the second (rightmost)
;	field will be sent.

tyoesc=tyo+<33_9.>		; TYOESC CH sends a 033 before sending CH.
tyo16=tyo+<16_9.>		; TYO16  CH sends a 016 before sending CH.
tyo174=tyo+<174_9.>		; TYO174 CH sends a 174 before sending CH.
tyo176=tyo+<176_9.>		; TYO176 CH sends a 176 before sending CH.
.xcref tyoesc

utyo:	push p,a		; save AC
	hrrz a,40		; get effective address of UUO:
				; one or two bytes to output
	trnn a,777000		; is high byte nonzero?
	 jrst utyo1		; no, goto TYOBOUT to output low byte
	rot a,-9.		; nonzero high byte, rotate to make it low
	call @.trtyo+tb		; output high byte
	rot a,9.		; restore low byte
utyo1:	call @.trtyo+tb
	pop p,a			; restore AC
	return


tynesc=tyn+<33_9.>		; TYNESC CH sends a 033 before sending CH.
tyn16=tyn+<16_9.>		; TYN16  CH sends a 016 before sending CH.
tyn174=tyn+<174_9.>		; TYN174 CH sends a 174 before sending CH.
tyn176=tyn+<176_9.>		; TYN176 CH sends a 176 before sending CH.
.xcref tynesc

; UUO to output its effective address as one or two bytes N times.  N is
; passed in A (which UUOH saves on the stack and then clobbers).
utyn:	push p,a		; save ACs
	push p,b		; ...
	skipn b,a		; pick up numeric argument
	 jrst utyn3		; do nothing in N=0
	hrrz a,40		; get effective address of UUO
utyn1:	trnn a,777000		; is high byte nonzero?
	 jrst utyn2
	rot a,-9.		; nonzero high byte, rotate to make it low
	call @.trtyo+tb		; output high byte
	rot a,9.		; restore low byte
utyn2:	call @.trtyo+tb		; output low byte
	sojg b,utyn1		; do N times
utyn3:	pop p,b			; restore ACs
	pop p,a			; ...
	return


mvar padc			; pad character

; PAD - Send padding characters.
upad:	move t1,@40		; get no. of seconds to pad for
	push p,a		; save ACs
	push p,b		; ...
	fltr a,speed		; get no. of characters output in a second
	fmpr a,t1		; get no. of pad chars
IFN KA,{
	muli a,400		; fix
	ash b,-243(a)		; ...
}
IFE KA,{
	fix b,a
}
	jumpe b,upad2		; return if no padding required
upad1:	move a,padc		; type pad character
	call @.trtyo+tb		; ...
	sojn b,upad1
upad2:	pop p,b			; restore ACs
	pop p,a			; ...
	return


; TYODEC - Output decimal no.
; Argument:
;   A	No. (unchanged)

tyodec:	push p,a		; save argument
	call tyod1		; output no., clobbering argument
	pop p,a			; restore argument
	return
tyod1:	push p,b		; save AC
	idivi a,10.		; get last digit
	jumpe a,.+2		; if other digits zero then just print last
	 call tyod1		; print other digits
	movei a,"0(b)		; convert to ASCII
	pop p,b			; restore AC
	pjrst @.trtyo+tb	; print digit


utyoan:	push p,a		; save AC
	movei a,33
	call @.trtyo+tb
	movei a,"[		; ]
	call @.trtyo+tb
	hrrz a,40		; get effective address of UUO: termination
				; character of ANS sequence
	call @.trtyo+tb
	pop p,a			; restore AC
	return


utynan:	push p,a		; save AC
	movei a,33
	call @.trtyo+tb
	movei a,"[		; ]
	call @.trtyo+tb
	move a,(p)
	caie a,1
	 call tyodec
	hrrz a,40		; get effective address of UUO: termination
				; character of ANS sequence
	call @.trtyo+tb
	pop p,a			; restore AC
	return

subttl	TYI module - Input Stream TTY input co-routine

; Interface specs for TYI module:
;	The TYI module is the driving force in the Input Stream process.
; It provides Terminal Input Support and is responsible for reading TTY input
; and giving it to the SMI module.  The TYI module has highest interrupt
; priority and can interrupt the Output Stream process at any point.

; A terminal definition can specify a TYI module to use.  This module must
; use the following interface:
;	CALL TYIBIN	; To obtain char from TTY (in A)
;	  CALL TYITOG	;   Like TYIBIN but returns -1 if no char in 1/5 sec
;	CALL TYIPUT	; To pass char to SMI module (in A)
;			;	This call may clobber A, T1, T2.
;	  CALL TYIPUC	;   Like TYIPUT but checks for CRTSTY command escape
;			;	char, and calls ENTER if it's seen.
;
; No ACs other than A, T1, and T2 should be clobbered by the TYI module.
; Saving and restoring ACs on the PDL is okay.
; Note side effect of TYIBIN - if it must wait for TTY input, it will first
; call SMIFRC in order to clear up any buffered SMI output.  This keeps
; the Input Stream as clear as possible.

ltyipdl==35.			; terminal input co-routine PDL length
mvar tyipdl(ltyipdl)		; terminal input co-routine PDL


; TYIPUF - Address pushed onto top of TYI module stack, to catch over-POPJing.
;	If it is ever invoked, it should generate a PDL overflow interrupt.

IFN ITS,{
tyipuf:	.suset [.sipirqc,,[%pipdl]]
	jrst tyipuf
}
IFN TNX,{
mvar sava(2)

tyipuf:	dmovem a,sava
	movei a,.fhslf
	movx b,1_<35.-.icpov>
	iic
	jrst .-1
}


IFE TINT,{
; TINT==0, so Input Stream is NOT interrupt driven.  The following routines
; constitute the basic TYI module for this case.  Note that the IS process
; has complete control of the PDL and normally waits indefinitely for input
; from the TTY.

; TYIINI - Initialize terminal input co-routine.
tyiini:	move p,[-ltyipdl,,tyipdl-1]
	push p,[tyipuf]
	jrst @.trtyi+tb

; TYIBIN - Called by TTY input co-routine to get next character.
;	If no character is available TYIBIN waits for it, after first
;	invoking SMIFRC so the SMI module has a chance to clear out its
;	buffer.

tyibin:	call tbin		; Get a TTY input char (-1 if none)
	jumpge a,tyibi2
	call smifrc		; No more, invoke SMIFRC to clear up stuff
	call tbinw		; then settle back to wait for TTY input.
tyibi2:	trnn f,%f8ci		; If hacking 8-bit input,
	 ret
	trze a,200		; and 8th bit is set,
	 tro a,%txmta		; Return char with meta bit in canonical place.
	ret

; TYITOG - Like TYIBIN but returns -1 if char doesn't arrive within 1/5 sec.

tyitog:	call tbin
	jumpge a,apopj
	sleep 2			; 1/5 second
	pjrst tbin		; Return whatever we have now.

} ; IFE TINT

IFN TINT,{
; TINT==1, so the Input Stream process IS interrupt driven!
; Requires maintenance of special PDL and interrupt vectors.
; Whenever input is not available, the process must dismiss the interrupt
; so that Output Stream processing can continue.

mvar tyip			; Terminal input co-routine PDL pointer

; TTYIVI - First TTY input interrupt comes here.  Initializes
; TTY input interrupt vector and TYI module (TTY input co-routine).

ttyivi:	pushae p,[a,t1,t2]	; must do same things as TTYINT here
	movem p,tyip		; save current PDL pointer
	move p,[-ltyipdl,,tyipdl-1]	; set up terminal input co-routine
					; PDL pointer 
	push p,[tyipuf]		; hack to catch over POPJing
	movei t1,ttyint		; set TTY input interrupt vector
	skipe feepmx		; to TTYINT if not feeping and TTYINF
	 movei t1,ttyinf	; if feeping
	hrrm t1,ttyvec		; ...
	jrst @.trtyi+tb		; and off we go to TYI co-routine.


; TTYINF/TTYINT - entry points for TTY input interrupt.
; Note that the handler actually triggers co-routines!

ttyinf:	aos feeptm		; reset feep timer
ttyint:	pushae p,[a,t1,t2]	; save ACs
	exch p,tyip		; switch to input co-routine stack
	; fall through to TYIBIN

; TYIBIN - Called by TTY input co-routine to get next character.
; If no character is available TYIBIN dismisses after invoking SMIFRC and
; will be re-entered by an input interrupt when the next character is typed.

tyibin:	call tbin		; read next character, if any
	jumpl a,tyigt5		; Jump if -1 (no input chars available)
	; Got one, return it.
	trnn f,%f8ci		; If hacking 8-bit input,
	 ret
	trze a,200		; and 8th bit is set,
	 tro a,%txmta		; Return char with meta bit in canonical place.
	ret

	; No more input, dismiss input interrupt
tyigt5:	call smifrc		; Flush out SMI module.
	exch p,tyip		; switch back to old stack
	popae p,[t2,t1,a]	; restore ACs
	jrst dismis


; TYIRLT - Timer interrupt handler when hacking time outs on terminal input.

tyirlt:	pushae p,[a,t1,t2]	; save ACs, must be the same as in TTYINT!!
	exch p,tyip		; switch to terminal input co-routine
	seto a,			; return -1 from TYIBIN to indicate timeout
	return			; happened 


; TYITOG - Get a character like TYIBIN, but return -1 if the character
; doesn't arrive within 1/6 of a second.

IFN ITS,{
tyitog:	movei a,tyirlt		; set %PIRLT handler to our routine to hack
	movem a,rltvec		; timeouts
	move a,[600000,,[10.]]	; timeout in 1/6 second
	.realt a,
	call tyibin		; get character
	move t1,ltime		; get previous time
	sub t1,@time		; -1*<time since last ran feep counter>
	addi t1,clkfrm		; A gets time to go in current feep frame
	jumple t1,tyito1	; if time is here or past, do it now!
	move t2,[600000,,t1]	; interrupt at that new time
	.realt t2,
	setom rsttim		; flag to return to normal rate after next tick
	jrst tyito2
tyito1:	.suset [.sipirqc,,[%pirlt]]	; give the interrupt
	move a,[600000,,[clkfrm]]	; restore the normal timing
	.realt a,			; ...
tyito2:	movei t1,rltint		; set %PIRLT handler back to feep handler
	movem t1,rltvec		; ...
	return
} ; IFN ITS

IFN 20X,{

.timel==:1
.timal==:5

tyitog:	move a,[.fhslf,,.timel]	; TIMER arg: A = fork handle,,function code
	movei b,167.		; TIMER arg: B = milliseconds until interrupt
	movei c,timchn		; TIMER arg: C = channel no.
	timer			; give interrupt in 1/6 second
	 jerr1 [asciz "Error setting timeout - "]
	call tyibin		; get character
	push p,a		; save character
	move a,[.fhslf,,.timal]	; TIMER arg: A = fork handle,,function code
	movei c,timchn		; TIMER arg: C = channel no. (stupid system
				; checks channel even when not used)
	timer			; remove pending timer requests
	 jerr1 [asciz "Error clearing timeout - "]
	pop p,a			; restore character
	return
} ; IFN 20X
} ; IFN TINT


; TYIPUT - Terminal input subroutine to hand a character to the simulator
;	output co-routine.
; Argument:
;   A/	Character (with %TX bits).
; TYIPUC - Variant which checks for "command escape" char before
;	passing along to SMI.

tyipuc:	camn a,cmdchr		; Entry point to check for cmd char
	 pjrst enter		; Aha, a command!  Go do it.
tyiput:	exch p,smip		; save terminal input co-routine PDL pointer
				; and restore simulator output co-routine PDL
				; pointer
	return			; return from SMIGET call

mvar cmdchr			; command character

subttl	TYI module subroutines (TTY input)

mvar icmask		; Input character mask (really only used on TNX)

; TBIN - Get next TTY input character; -1 if none.
; Arguments:
;   None
; Result:
;   A	Character

IFN ITS,{
tbin:	.iot tyic,a
	return
} ; IFN ITS
IFN TNX,{
IFN TINT, mvar tbinlc	; Save last input char for ridiculous
			; crock to get around outrageous SIBE bug.
tbin:	push p,b		; save AC
	move a,ttyjfn		; SIBE arg: A = JFN
	sibe			; TTY input available?
	 jrst [			; BIN arg: A = JFN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;; CROCKLUDGECROCKLUDGECROCKLUDGE ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IFN TINT,{	cain b,15	; CROCK CROCK If "# chars available"
		 came b,tbinlc	; happens to = ^M which is = last char,
		  caia
		   jrst [seto a,	; Then totally ignore!
			pop p,b ? return]
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
		bin		; get input character
IFN TINT,	movem b,tbinlc	;;;;;;;;;;;;;;;;;;;;;CROCKCROCKCROCK
		move a,b	; result: character
		and a,icmask	; AND with either 177 or 377
		pop p,b		; restore AC
		return ]
IFE TINT,seto a,		; no TTY input, return -1
IFN TINT,setob a,tbinlc		; CROCKCROCK
	pop p,b			; restore AC
	return
} ; IFN TNX


; TBINW - Get next TTY input character.  Waits if no input available.
; Arguments:
;   None
; Result:
;   A	Character


IFN ITS,{
tbinw:	$call iot,[#tyic,a][][#%tinwt]
	 .lose %lsfil
	return
} ; IFN ITS
IFN TNX,{
tbinw:	push p,b		; save AC
	move a,ttyjfn		; BIN arg: A = JFN
	bin			; input character from TTY
	move a,b		; return character in A
	pop p,b			; restore AC
	and a,icmask		; AND with 177 or 377
	trnn f,%f8ci		; Are we hacking 8th bit as meta bit?
	 return			; Nope
	trze a,200		; Yes, check for it!
	 tro a,%txmta		; If 200 bit set, clear it and set meta bit.
	return
} ; IFN TNX

subttl	SMI module - Input Stream Simulator output (to STY/NET)

; Interface specs for SMI module:
;	The SMI module is driven by TYI, in the Input Stream process.
; It provides STY/NET Input Simulation and is responsible for getting chars
; from the TYI module and sending them out to the STY/NET as simulated input.
; Remember that the input stream process has highest priority and can
; interrupt the Output Stream process at any point.

; A terminal definition can specify a SMI module to use.  This module must
; use the following interface:
;	CALL SMIGET	; To obtain %TOFCI char from TYI (in A)
;			;	This call may clobber A, T1, T2.
;			;	This call waits until a char is available.
;	CALL SMIBOUT	; To output char to STY/NET (in A)
;			;	Clobbers no ACs.
;	CALL SMIFRC	; Force any buffered output chars to be sent
;			;	immediately.  This routine is invoked by
;			;	TYIBIN if there is no more user input.
;			;	Clobbers no ACs.
;
; No ACs other than A, T1, and T2 should be clobbered by the SMI module.
; Saving and restoring ACs on the PDL is usually NOT okay!  It is only
; allowed if no call to SMIGET intervenes between the save and the restore.
; NOTE!!  CALL SMIGET must be the very first thing in the routine that TR.SMI
; specifies!!!
; Note the slight lapse in modularity where SMIFRC can be invoked directly
; by TYIBIN in order to force out any buffered output while waiting for
; more user input.  It could be modularized by introducing a couple of new
; calls, SMIGOT (like SMIGET but returns -1 if no char available) and
; TYIFRC ("force" output to SMI module when no more user input) but at the
; moment that seems unnecessary.

lsmipdl==25.			; simulator output co-routine PDL length
mvar smip			; simulator output co-routine PDL pointer
mvar smipdl(lsmipdl)		; simulator output co-routine PDL

constants
SECTION INIT

; SMIINI - Set up SMI co-routine.

smiini:	movem p,smip		; save our PDL pointer
	move p,[-lsmipdl,,smipdl-1]	; set up simulator output co-routine
					; PDL pointer 
	push p,[smipuf]		; hack to catch over POPJing
	pjrst @.trsmi+tb	; start simulator output co-routine
				; (control returns to our caller when the
				; the co-routine does CALL SMIGET to get
				; the first terminal input character)

constants
SECTION MAIN

; SMIPUF - Address pushed onto top of SMI module stack, to catch over-POPJing.
;	If it is ever invoked, it should generate a PDL overflow interrupt.

IFN ITS,{
smipuf:	.suset [.sipirqc,,[%pipdl]]
	jrst smipuf
}
IFN TNX,{
smipuf:	dmovem a,sava
	movei a,.fhslf
	movx b,1_<35.-.icpov>
	iic
	jrst .-1
}


; SMIGET - Simulator output subroutine to get a character from the terminal
;	input co-routine.
; Value:
;   A	Character (with %TX bits).

smiget:	exch p,smip		; save simulator output co-routine PDL pointer
				; and restore terminal input co-routine PDL
				; pointer
	return			; return from TYIPUT call


; SMIBOUT - Output character to STY/NET.
; Argument:
;   A	Character.

IFN ITS,{
smibout:	.iot pyo,a	; output character to STY/NET
ifn net,.nets pyo,
	return
} ; IFN ITS
IFN TNX,{
smibout:
IFN NET&TCP,{
	skipge smijfn
	 jrst tcpcho		; Go output TCP byte (but don't force out)
;	 jrst [	call tcpcho
;		pjrst tcpofl]
} ;IFN NET&TCP
	pushae p,[a,b]		; save ACs
	move b,a		; BOUT arg: byte
	move a,smijfn		; BOUT arg: JFN
	bout			; output character to PTY
IFN NET,{
				; MTOPR arg: A = JFN
	movei b,.mosnd		; MTOPR arg: B = function code
	mtopr			; send bytes buffered so far
} ; IFN NET
	popae p,[b,a]		; restore ACs
	return
} ; IFN TNX


; SMIFRC
IFE NET,{
smifrc:	return
}
IFN NET,{
IFN ITS,{
smifrc:	.nets pyo,
	return
} ; IFN ITS
IFN TNX,{
smifrc:
IFN TCP,{
	skipge smijfn
	 pjrst tcpofl
} ;IFN TCP
	pushae p,[a,b]
	move a,smijfn
	movei b,.mosnd
	mtopr
	popae p,[b,a]
	return
} ; IFN TNX
} ; IFN NET

subttl	SMO module - Output Stream Simulator input (STY/NET) interrupt handler

; Interface specs for SMO module:
;	The SMO module is the driving force in the Output Stream process.
; It provides STY/NET Output Simulation and is responsible for reading
; STY/NET output and giving it to the TYO module.  The output stream
; process has lower priority than the Input Stream and can be interrupted
; at any point.

; A terminal definition can specify a SMO module to use.  This module must
; use the following interface:
;	SMOBIN <ac>,	; To obtain output char from STY/NET (in <ac>)
;			;	Warning: can clobber all ACs except P.
;	CALL STYIP	; Peek at next char, returns in A (-1 if none)
;	CALL TD.xxx	; To perform various terminal operations.
;			;	No ACs are clobbered. (maybe?)
;
; All ACs can be used by the SMO module.
; NOTE!! A SMOBIN must be the very first thing in the routine that TR.SMO
; specifies!!!

comment |
	Note carefully that the PDL is set up during SETUP, before
interrupts are turned on, to point at a SMOBIN macro invocation within
an input loop routine.
	As far as the STY input side is concerned, interrupts and
dismisses all take place inside STYIN5/STYINT.  Anything at main
program level or another interrupt loop must not clobber the return
address on the PDL!  STY input interrupt level, however, need not
worry about saving anything, since it is the most heavily invoked
and the burden of AC saving is thereby decreed to rest upon all other
interrupt levels.

	Interrupts are vectored to STYINT normally, to STYINF if
the ALARM option was requested by user.
|

; Note that the SMO stack is really the Output-Process stack since
; SMO+TYO are not co-routines like TYI+SMI are.
; This stack is not used yet -- have to figur out elegant way of
; initializing it once-only.
lsmopdl==50.			; SMO PDL length
mvar smop			; SMO PDL pointer
mvar smopdl(lsmopdl)		; SMO PDL stack

IFN SINT,{
; STYIVI - PYI initial interrupt vector dispatch & initialization.

styivi:	setzm ibufct		; Ensure that first SMOBIN will ask for chars.
IFN ITS&NET,{
	movei t1,arpint
	skipe chaosp
	 movei t1,chaint
}
IFN TNX&CHAOS,{
	movei t1,chaint
}
IFE NET,{
	movei t1,styint
}
	skipe feepmx
	 movei t1,styinf
	hrrm t1,styvec
	jrst @.trsmo+tb		; and off we go into SMO loop!


styinf:	aosg feeptm	; Bump feep timer and check it...
	 call td.bel	; Uh-oh, timed-out and must feep.
	jrst styint
}; IFN SINT

IFN ITS,{
IFN STY,{
styint:	move t1,ibufip		; 8-bit BP pointing to start of buffer
	movem t1,ibufpt
	movei a,ibufln
	$call siot,[#pyi,t1,a]
	 .lose %lsfil
	subi a,ibufln-1		; Find -<#-1> chars read.
	jumpg a,styin5		; jump out if none read.
	movnm a,ibufct		; else store magnitude,
	return			; and return, letting macro ILDB char.
			; Note that on return, IBUFCT will actually hold
			; one less than actual # chars in buffer, to simulate
			; the SOSGE that we bypassed.

; STYIN5 is called by the SMOBIN macro when the buffer
; becomes empty.  It "invokes" STYINT to read more chars from
; the system's buffer if any exist there, and tries hard to avoid
; dismissing (i.e. finalizing) too quickly.

styin5:	skipl @ttyoac		; our buffer's empty; is system's?
	 jrst styint		; no, gobble more from it.
	call tyofrc		; Empty - force out our stuff so far,
	skipa ? skipa ? .hang	; and block momentarily.
	skipl @ttyoac		; Still empty?
	 jrst styint		; no, hurray!
	move t1,whotim
	camg t1,@time
	 call whoout
	call @.trsmf+tb		; Sigh, empty, finalize
	jrst dismis
} ; IFN STY


IFN NET,{
styin5: styint:
	skipe chaosp		; chaosnet?
	 jrst chaint		; yes, hack it
; the above should be replaced by changing the interrupt vector to point to
; either ARPINT or CHAINT.
arpint:	$call whyint,[#pyi][t1,t1,t2]
	 .lose %lsfil
	jumpl t1,[
		tlz t1,400000
		.reset pyi,	; tell system to forget INS
		aosle inscnt
		 setom supres
		jrst .+1 ]
	caie t1,%nsinp		; input available
	 cain t1,%nscli		; CLS received, data available for input
	  jrst styin6
	cain t1,%nsopn		; no input?
	 jrst styin7		; nope
	cain t1,%nscls		; closed?
	 jfcl
	jrst netlzi		; Closed or unknown state.  Tell luser.

styin6:	jumpn t2,styin9		; %NSINP and no input??
styin7:	call @.trsmf+tb
	jrst dismis

chaint:	$call whyint,[#pyi][t1,t1,t2]
	 .lose %lsfil
	hlrz t2,t2		; get input packet count
	cain t1,%csopn		; connection open?
	 jrst styin8		; yes, get input
	caie t1,%cscls
	 cain t1,%cslos
	  sojg t2,styin8	; get input unless only LOS or CLS
;	jrst netlzi		; connection not open, go analyze

netlzi:	$call open,[#tyon,[sixbit/tty/]][][#.uao]
	 .lose %lssys
	say "
Net connection broken - "
	movei a,pyi
	jrst netluz

styin8:	jumpe t2,styin7		; if no input, don't do anything
	movei t2,ibufln		; on chaosnet, ask for bufferful and use
				; don't hang mode
styin9:	move t1,ibufip		; 8-bit BP pointing to start of buffer
	movem t1,ibufpt
	movem t2,ibufct
	$call siot,[#pyi,t1,ibufct][][#10]	; don't hang mode on chaosnet
	 .lose %lsfil
	subm t2,ibufct
	sos ibufct		; subtract one from IBUFCT to simulate the
				; SOSGE that we bypassed.
	return			; and return, letting macro ILDB char.
} ; IFN NET



; STYIP - Peek at next character in STY input buffer.
; Result:
;   A	character; -1 if none.

IFN STY,{
styip:	skipg ibufct
	 jrst [	skipge a,@ttyoac
		 return
		call styint
		aos ibufct	; undo SOS done in STYINT!
		jrst .+1 ]
	move a,ibufpt
	ildb a,a
	return
} ; IFN STY
IFE STY,{
styip:	skipg ibufct
	 jrst [	seto a,
		return ]
	move a,ibufpt
	ildb a,a
	return
} ; IFE STY

; SMOBIN - Get-char macro. If nec, slurp in a bufferfull to process.
; Note that, because it may invoke STYIN5 which can invoke
; various screen finalizations, no AC can be considered truly safe
; where SMOBIN appears.
define smobin ac
	sosge ibufct		; See if characters left
	 call styin5		; No, must slurp another bufferfull.
	ildb ac,ibufpt		; some left, get character
termin
} ; IFN ITS


IFN TNX,{
IFE SIBEBUG,{
ifn chaos, chaint:		;entry point for chaos "interrupt" and
styint:				;psuedo-tty "interrupt".
IFE STY,{
IFE TCP,move a,smojfn		; SIBE arg: JFN
IFN TCP,skipl a,smojfn
	sibe
	 jrst styi1
} ; IFE STY
IFN STY,{			; SIBE always skips on PTY channels!
	move a,ptyttd
	sobe
	 jrst styi1
	move a,smojfn
} ; IFN STY
;	call tyofrc
;	dobe
;	sibe
;	 jrst styi1
	call @.trsmf+tb
IFN SINT,{
	debrk
}; IFN SINT
IFE SINT,{
	move a,smojfn
IFN TCP,{
	jumpl a,[call tcpchi
		move b,ibufip
		movem b,ibufpt
		idpb a,b
		setzm ibufct
		return]
} ;IFN TCP
	bin
IFN CHAOS, erjmp chalos
	move a,ibufip
	movem a,ibufpt
	idpb b,a
	setzm ibufct
	return
}; IFE SINT
styi1:
IFN NET&TCP,{
	skipg tcpict
	 call tcpifl
	move a,tcpibp
	movem a,ibufpt
	move a,tcpict
	movem a,ibufct
	sos ibufct
	setzm tcpict
	return
} ;IFN NET&TCP
ifn sty,move a,smojfn
	caile b,ibufln
	 movei b,ibufln
	movem b,ibufct
	movn c,b
	move b,ibufip
	movem b,ibufpt
	sin
IFN CHAOS, erjmp chalos
	sos ibufct		; subtract one to simulate SOSGE that we
				; bypassed
	return


styip:	skipg ibufct
	 jrst [	skipge a,smojfn
		 jrst [seto a, ? return]	; TCP always loses.
		sibe
		 jrst [	call styi1
			aos ibufct	; undo SOS IBUFCT in STYI1!
			jrst styip1
			]
		seto a,
		return
		]
styip1:	move a,ibufpt
	ildb a,a
	return


; SMOBIN - Get-char macro. If necessary, slurp in a bufferfull to process.
; Note that, because it may invoke STYINT which can invoke
; various screen finalizations, no AC can be considered truly safe
; where SMOBIN appears.
define smobin ac
	sosge ibufct		; See if chars left
	 call styint		; No, must slurp another bufferfull.
	ildb ac,ibufpt		; some left, get char
termin
} ; IFE SIBEBUG
} ; IFN TNX

IFE SIBEBUG,{
	; CROCK LIVES HERE!  Use 7-bit chars instead of 8-bit if
	; TNX&STY, to avoid getting random 8th bit!!!
	; Goddam fucking screwed-up TNX TTY "support"!!!
; Here is defined the "initial BP" into IBUFF.
SECTION MAINVAR
IFN TNX&STY, ibufip: 440700,,ibuff	; TNX&STY uses 7 bits for now
SECTION MAIN
IFE TNX&STY, ibufip: 441000,,ibuff	; else normal 8 bits.

mvar ibufct		; # chars left to read in buffer
mvar ibufpt		; 8-bit BP reading from buffer
ibufln==400.		; Length of buffer in 8-bit bytes.
mvar ibuff(<ibufln+3>/4)
} ; IFE SIBEBUG

IFN SIBEBUG,{
define smobin ac
	call styixx
ifn ac-a,move ac,a
termin

styixx:	skipl a,styirr
	 jrst [	setom styirr
		return ]
IFE NET&TCP,move a,smojfn
IFN NET&TCP,{
	skipge a,smojfn
	 jrst [	skipg tcpict
		 call @.trsmf+tb
		call tcpchi
		return]
} ;IFN NET&TCP
	sibe
	 jrst styix1
styix2:	call @.trsmf+tb
	move a,smojfn
styix1:	bin
	move a,b
	return

styip:	skipl a,styirr
	 return
IFE NET&TCP, move a,smojfn
IFN NET&TCP,{
	skipge a,smojfn
	 jrst [	skipg tcpict
		 jrst [seto a, ? return]
		call tcpchi
		movem a,styirr
		return]
} ;IFN NET&TCP
	sibe
	 jrst [	push p,b
		bin
		move a,b
		movem a,styirr
		pop p,b
		return ]
	seto a,
	return

SECTION MAINVAR
styirr:	-1

SECTION MAIN
} ; IFN SIBEBUG

; SBIN - callable routine to invoke SMOBIN to get char from STY/NET.
;	Hangs until input available - remember finalization can happen!
; Returns
;	A/ <input char>

sbin:	smobin a,
	ret

; SBINI - "SBIN Immediate" - similar routine, but bypasses buffering
;	and finalization completely.  Only really used for startup stuff.

sbini:
IFN ITS, .iot pyi,a
IFN TNX,{
IFN NET,{
	skipge a,smojfn
	 pjrst tcpchi
}
	push p,b
	bin
	move a,b
	pop p,b
} ;IFN TNX
	ret

; FPSET - Feep Set.  Start ALARM feeping.

fpset:	skipg t1,feepmx		; get time specified in ALARM option
	 movei t1,ticspm	; Default to 1 minute if unspecified.
	movem t1,feeptm
	movem t1,ofeptm
IFN TINT,{
	movei t1,ttyinf		; Clobber TYI and SMI interrupt vectors.
	hrrm t1,ttyvec
}
IFN SINT,{
	movei t1,styinf
	hrrm t1,styvec
}
	return

	
; FPRSET - Feep Reset.  Stop ALARM feeping.

fprset:
IFN TINT,{
	movei t1,ttyint		; Reset TYI and SMI interrupt vectors.
	hrrm t1,ttyvec
}
IFN SINT,{
	movei t1,styint
	hrrm t1,styvec
}
	return

IFN NET,{
; Main reason STLPRC is here instead of with other net code is
; because SMOBIN macro isn't defined until here!  Sigh!  Maybe should
; define SBIN as callable routine...

; STLPRC - Process TELNET IAC received from remote site
;	Called by SMO module if IAC seen.
; Can clobber A,B,C

mvar tlperr		; # of TELNET protocol errors seen

stlprc:	smobin a,	; Get next byte after the IAC
	cail a,IA$WIL	; 251. through
	 caile a,IA$DNT	; 254. inclusive.
	  ret		; Not an option negotiation so ignore it for now.
	push p,a
	smobin a,	; Get option code
	pop p,b
	move c,[-ntlops,,tloptb]
stlpr0:	camn a,$toval(c)
	 jrst @(b)-IA$WIL+[stlpr1 ? stlpr2 ? stlpr3 ? stlpr4]
	addi c,$tol-1
	aobjn c,stlpr0
	jrst stlpr8	; Don't know this option, so flush it.

	; Have option!  Perform appropriate actions.
	; For any particular one of DO/DON'T/WILL/WON'T there are
	; two cases:
	; (1) Response to request/offer by local site (we set option
	;	accordingly and don't reply)
	; (2) Spontaneous action by remote site (we must reply, unless
	;	desired state already exists).  If it's DON'T/WON'T
	;	we must respond WON'T/DON'T, but if it's DO/WILL then
	;	we have a choice of agreeing or refusing.

	; WILL - Remote site agreeing to our DO request, or offering to start.
stlpr1:	hrre a,$tongr(c)	; Get current status
	jumpg a,[		; Is this a response to a DO?
		setom $torem(c)	; Yes, ensure option on!
		setzm $tongr(c)	; and say negs are done.
		ret]
	jumpl a,[		; Sent DON'T but got WILL!  Ptcl error!
		aos a,tlperr	; Bump count of errs
		caile a,5	; Allow 5 errs
		 ret		; after which we just ignore it.
		movsi a,IA$DNT	; Try sending DON'T again.
		jrst stlpr9]
	skipe $torem(c)	; Spontaneous request, handle it.
	 ret		; Option already on, nothing to do.
	movei a,1	; Hmm, say WILL seen.
	hrlzm a,$tongr(c)

		; Remote site is offering to perform an option we didn't
		; ask for.
		; Must decide here if we want it or not!
		; For time being, always reject it, with DONT.
		; If we accepted the offer, we would turn the option on
		; right here, and then send a DO.  In either case SNDOPT
		; will complete the negs.
	movsi a,IA$DNT
	jrst stlpr9	; Go refuse.

	; WON'T - Remote site refusing DO or confirming DON'T request,
	;	or wants to stop.
stlpr2:	hrre a,$tongr(c)	; See what current status is
	jumpn a,[	; Is this a response to a DO/DONT request?
		setzm $torem(c)	; Yes, ensure option off
		setzm $tongr(c)	; And say negs are done.
		ret]
	skipn $torem(c)	; Spontaneous request, handle it.
	 ret		; Option already off, nothing to do.
	setzm $torem(c)	; Ugh!  Say remote site has stopped.
	hrros $tongr(c)	; Say WON'T seen, and
	movsi a,IA$DNT	; Confirm with DON'T.
	jrst stlpr9	; Send it off (SNDOPT will complete negs)

	; DO - Remote site accepting our WILL offer, or requesting we start.
stlpr3:	hrre a,$tongl(c)	; Get current status
	jumpg a,[		; Is this a response to a WILL?
		setom $toloc(c)	; Yes, ensure option on!
		setzm $tongl(c)	; and say negs are done.
		ret]
	jumpl a,[		; Sent WON'T but got DO!  Ptcl error!
		aos a,tlperr	; Bump count of errs
		caile a,5	; Allow 5 errs
		 ret		; after which we just ignore it.
		movsi a,IA$WNT	; Try sending WON'T again.
		jrst stlpr9]
	skipe $toloc(c)	; Spontaneous request, handle it.
	 ret		; Option already on, nothing to do.
	movei a,1	; Hmm, say DO seen.
	hrlzm a,$tongl(c)

		; Remote site is requesting we perform some option.
		; Must decide here whether we want it or not!
		; For now, always refuse to do it (send WONT).
		; If we agreed to the request, we would turn the option on
		; in SNDOPT just after sending a WILL.
		; In either case, SNDOPT will complete the negs.
	movsi a,IA$WNT
	jrst stlpr9

	; DON'T - Remote site refusing our DO offer or confirming our WON'T,
	;	or demands we stop.
stlpr4:	hrre a,$tongl(c)	; Get current status
	jumpn a,[		; Is this a response to a WILL/WONT?
		setzm $toloc(c)	; Yes, ensure option off
		setzm $tongl(c)	; and say negs are done.
		ret]
	skipn $toloc(c)	; Spontaneous request, handle it.
	 ret		; Option already off, nothing to do.
	hrros $tongl(c)	; Ugh. Say DON'T seen.
	movsi a,IA$WNT	; We are obliged to always confirm with WON'T.
	jrst stlpr9	; Send reply (SNDOPT will complete negs and
			; turn local option off)

	; Unknown option.  Refuse it, whatever it is.
stlpr8:	caie b,IA$DNT	; If it's asking for something OFF,
	 cain b,IA$WNT
	  ret		; Then just ignore since default is always OFF.
	cain b,IA$DO	; If was making request,
	 hrli a,IA$WNT	; Say we WON'T.
	cain b,IA$WIL	; If was making offer,
	 hrli a,IA$DNT	; Refuse politely with DON'T.
	tloa a,(setz)	; Set sign bit in <WNT/DNT>,,<option> to indicate
			; special entry, and skip over normal stuff.
stlpr9:	 hrri a,(c)	; Known option - set up <DO/etc>,,<option addr>
	movei b,sndopt	; Arg in A, routine addr in B
	call ipscal	; Signal the Input Stream to perform routine!
	ret

; SNDOPT - Routine called at Input Process level (suspending normal
;	IP operations) to respond to TELNET options seen by SMO module.
;	Note local options are set here if negotiations are complete,
;	but never remote options (these are set upon receipt by
;	STLPRC).
;	A/ <DO/DONT/etc>,,<option addr>	; Sign bit set if no option addr,
;					; RH is actual option value.
; Clobbers A,B,C

sndopt:	move c,a
	movei a,IAC		; Response starts with IAC
	call smibout
	hlrz a,c
	jumpl c,[andi a,377	; Not a known option, so we just
		call smibout	; send the response
		movei a,(c)	; Followed by the option value.
		call smibout
		pjrst smifrc]
	call smibout		; Send response
	move a,$toval(c)	; and option val
	call smibout
	call smifrc
	hlrz a,c		; Get response again
	cain a,IA$DNT
	 jrst [	move a,$tongr(c)	; See if we are responding to something
		tlnn a,-1		; Already received anything?
		 troa a,-1		; No, so remember we sent DON'T.
		  setz a,		; Yes, so this is an answer, say
		movem a,$tongr(c)	;	negotiations complete.
		cain a,			; Just in case, clear flag
		 setzm $torem(c)	; if negs are complete.
		ret]
	cain a,IA$DO
	 jrst [	move a,$tongr(c)	; See if this is a response
		tlne a,-1		; Already received anything?
		 tdza a,a		; Yes, so this is a response, say
					;   negotiations completed.
		  movei a,1		; No, so remember we sent DO!
		movem a,$tongr(c)
		cain a,			; Just in case, set flag
		 setom $torem(c)	; if negs are complete.
		ret]
	cain a,IA$WIL
	 jrst [	move a,$tongl(c)	; See if responding to anything
		tlne a,-1
		 tdza a,a		; Yes, so this is a response, say
					;   negotiations completed.
		  movei a,1		; No, so remember we sent WILL!
		movem a,$tongl(c)
		cain a,			; If negs complete, then
		 setom $toloc(c)	; turn on local option!
		ret]
	cain a,IA$WNT
	 jrst [	move a,$tongl(c)	; See if responding to anything
		tlnn a,-1
		 troa a,-1		; No, so remember we sent WON'T!
		  setz a,		; Yes, say negotiations complete.
		setzm $toloc(c)		; Always turn off local option!
		ret]
	jsr bughlt			; Shouldn't come here.
} ;IFN NET

subttl	TYO module - Output Stream TTY output routines

Comment |

Interface specs for TYO module:
	The TYO module is driven by SMO, in the Output Stream process.
It provides TTY Output Support and is responsible for performing all
terminal operations that the SMO module requests, including normal
character output.  Remember that the input stream process has highest
priority and can interrupt the Output Stream process at any point.

A terminal definition can specify a TR.TYO parameter, but this does
not mean that a TYO module is specified.  This is because the entire
definition is itself the overall TYO module specification!  CRTSTY
uses the terminal definition parameters to do the right things.
The following is the conceptual TYO module interface:

	TD.xxx	; "Input" - TD.xxx routines are invoked by the SMO module
		;	to perform terminal operations.  All arguments are
		;	furnished in the ACs.
		;	SMO should not interact with TYO except via TD rtns!
; In particular, the following exist even though they do not correspond
; to any %TD codes:
	TD.CHO	; This rtn outputs the "normal" char in A.
	TD.FRC	; Force any pending CLEOL and cursor movement.
	TD.MFRC	; Force any pending cursor movement.

	CALL TYOBOUT	; Output char in A to TTY.  Always buffers.
	CALL TYOFRC	; Force immediate output of all buffered chars.
	CALL TYOFIN	; Ditto, but waits for output to complete.

If a terminal definition specifies a TR.TYO routine, this routine
should expect a character in A and should use TYOBOUT to send any resulting
output to the TTY.  No ACs other than A should be clobbered.
The TR.TYO routine is invoked for all TTY output done by the TD.xxx
routines, and in fact is the lowest level that these routines use.
The default TR.TYO routine is simply TYOBOUT.

There are only 3 TD.xxx routines which correspond to no %TD codes.
These are TD.CHO, TD.FRC, and TD.MFRC.
|

; TD.FRC - Perform pending CLEOL and cursor movement if any.
td.frc:	tlne f,%clpnd		; CLEOL pending?
	 call frcel1		; yes, do it
				; fall through to TD.MFRC

; TD.MFRC - Perform pending cursor movement.
td.mfrc:	cain h,(nh)		; horizontal position correct?
	 caie v,(nv)		; vertical correct also?
	  pjrst @.trmov+tb	; no, move the cursor
	return			; both correct, return right away

subttl	   TYO - TD.WIN, TD.MOV

; TD.WIN - Set window.
; Arguments:
;   A	first line of window
;   B	first column of window
;   C	last line of window
;   D	last column of window

td.win:	camn a,wvmin		; if new minimum vertical
	 came b,whmin		; or new minimum horizontal
	  jrst tdwin0		; different from old then do it
	camn c,wvmax		; if new maximum vertical
	 came d,whmax		; or new maximum horizontal
	  jrst tdwin0		; different from old then do it
	return			; otherwise no change, do nothing
tdwin0:	call frceol		; force any pending CLEOL
	xct .tewin+tb
tdwin1:	dmovem a,wmin		; set WVMIN and WHMIN
	dmovem c,wmax		; set WVMAX and WHMAX
	.i wheight=wvmax-wvmin+1
	.i wwidth=whmax-whmin+1
	trz f,%fnclr+%fneos+%fneol+%fnsu+%fnsd+%fnilp+%fndlp+%fnicp+%fndcp
	tdo f,.tpflg+tb
	came a,tvmin
	 tro f,%fnclr+%fnsu+%fnsd
	came b,thmin
	 tro f,%fneos+%fnclr+%fnsu+%fnsd+%fnilp+%fndlp
	came c,tvmax
	 tro f,%fneos+%fnclr+%fnsu+%fnsd
	came d,thmax
	 tro f,%fneol+%fneos+%fnclr+%fnsu+%fnsd+%fnilp+%fndlp
	camn c,tvmax
	 jrst tdwin2
	trnn f,%fnilp
	 trne f,%fndlp
	  tro f,%fnilp+%fndlp
tdwin2:	camn d,thmax
	 return
	trnn f,%fnicp
	 trne f,%fndcp
	  tro f,%fnicp+%fndcp
	return


; TD.MOV - Move cursor to specified position.
; Arguments:
;   A	Vertical position.
;   B	Horizontal position.

td.mov:	dmove nvh,a
	add nv,wvmin		; convert from window relative position
	add nh,whmin		; to absolute one
	camle nv,wvmax		; too big?
	 move nv,wvmax		; yes, set to biggest possible
	camle nh,whmax		; too big?
	 move nh,whmax		; yes, set to biggest possible
	return

subttl	   TYO - TD.DLF

; TD.DLF - Delete Forward (character) without moving cursor.
td.dlf:	movei t1,blchar		; character position already clear?
	camn t1,@scrntb(nv)	; ...
	 return			; yes, no need to do anything
	skipn .tedel+tb		; terminal have character delete?
	 pjrst simdlf		; no, simulate
	call td.mfrc		; move cursor to position
	xct .tedel+tb		; erase character position
	 pjrst scrdlf		; update screen image if .TEDEL didn't
	return

; SIMDLF - TD.DLF simulation.
simdlf:	push p,a		; save AC
	call td.mfrc		; force cursor movement
	movei a,blchar		; delete character by overprinting
	call @.trcho+tb		; with space
	pop p,a			; restore AC
	return

subttl	   TYO - TD.EOL

SECTION MAINVAR
ceolp::
ceolpv:	block 1			; Position of pending-CLEOL
ceolph:	block 1			; ...

SECTION MAIN

; TD.EOL - Clear to EOL (End of Line).
; Arguments:
;   None

td.eol:	tlnn f,%clpnd		; CLEOL already pending?
	 jrst tdeol1		; no
	came nv,ceolpv		; yes, are we trying to CLEOL on same line?
	 jrst [	call frcel1	; no, finish previous CLEOL
		jrst tdeol1 ]	; and then do this one
	caml nh,ceolph		; same line, is current pos AFTER a pending
				; CLEOL position?
	 return			; yes, ignore this redundant CLEOL
	tlz f,%clpnd		; clear CLEOL pending flag
tdeol1:	trnn f,%fsmeol		; want to hack smart CLEOL?
	 pjrst frcel2		; no, force out CLEOL
	dmovem nvh,ceolp	; save current position
	tlo f,%clpnd		; and say CLEOL is pending
	return


; FRCEOL - Force out CLEOL.  Note that %CLPND must be
; cleared before executing .TEEOL because some EOL routines
; may use TD.CHO for output (which checks for %CLPND etc)
frceol:	tlnn f,%clpnd		; CLEOL pending?
	 return			; no, we're done
				; fall through
; FRCEL1 - Do the pending CLEOL (assumes there is a CLEOL pending).
frcel1:	pushae p,[nh,nv]	; save current position
	dmove nvh,ceolp		; get position to start CLEOL
	tlz f,%clpnd		; clear CLEOL pending flag
	call frcel2		; actually do it
	popae p,[nv,nh]		; restore cursor position
	return

; FRCEL2 - Actually do a CLEOL.
frcel2:	trne f,%fneol		; atomic CLEOL available?
	 pjrst simeol		; no, simulate

; If rest of line is already blank, ignore CLEOL.
	push p,nh		; save horizontal position
	movei t1,blchar		; space for blankness testing
frcel3:	came t1,@scrntb(nv)	; blank?
	 jrst frcel4		; no, we really have to CLEOL
	camge nh,whmax		; reached end?
	 aoja nh,frcel3		; no, test rest of line
	pop p,nh		; restore horizontal position
	return
frcel4:	pop p,nh		; restore horizontal position

	call td.mfrc		; move cursor first if necessary
	xct .teeol+tb		; clear to end of line
	 pjrst screol		; update screen image if .TEEOL didn't
	return


; SEOL - PJRST SEOL is equivalent to CALL SIMEOL ? AOS (P) ? RETURN.
; Meant to be called by terminal CLEOL handlers when they want to punt.
seol:	aos (p)			; take skip return

; Routine to simulate Clear-to-EOL by spaces.  Used by
; terminals with no CLEOL or line del/ins!
simeol:	push p,nh		; save horizontal position
smeol1:	call td.dlf		; erase character position
	camge nh,whmax		; erased last position?
	 aoja nh,smeol1		; no, keep going
	pop p,nh		; restore horizontal position
	return

subttl	   TYO - TD.EOF, TD.CLR

; TD.EOF - Clear to EOF (End of Screen).
; Arguments:
;   None

td.eof:	camn nv,wvmax		; on last line of screen?
	 pjrst td.eol		; yes, then CLEOS is equivalent to CLEOL
	came nh,whmin
	 jrst tdeof1
	camn nv,wvmin
	 pjrst tdclr1
tdeof1:	trne f,%fcsel		; OK to do real CLEOS?
	 pjrst td.eol		; No, do CLEOL instead.
	trne f,%fneos
	 pjrst simeos
	tlne f,%clpnd		; CLEOL pending? (clear flag ahead of time)
	 jrst [	camge nv,ceolpv	; if cursor above CLEOL loc,
		 jrst .+1	; the CLEOS will wipe it out.
		camn nv,ceolpv	; Hmm, if on same line,
		 camle nh,ceolph ; and cursor precedes CLEOL pos, also win
		  call frcel1	; else (sigh) do it.
		jrst .+1]
	tlz f,%clpnd
	call td.mfrc
	xct .teeos+tb
	 pjrst screos
	return


; SEOS - PJRST SEOS is equivalent to CALL SIMEOS ? AOS (P) ? RETURN.
; Meant to be called by terminal CLEOS handlers when they want to punt.
seos:	aos (p)			; take skip return

; SIMEOS - Simulate Clear-to-EOS with many Clear-to-EOLs.
simeos:	pushae p,[nh,nv]	; save desired cursor position
	trne f,%fneol		; CLEOL work?
	 jrst seos2		; no
seos1:	call td.eol		; clear to end of current line
	move nh,whmin		; CR so next CLEOL zaps whole line
	camge nv,wvmax		; if not on last line
	 aoja nv,seos1		; then move to next one and clear it
	jrst seos4		; that's all
seos2:	; no CLEOL - try other hacks before punting all the way to spaces
	trne f,%fndlp		; insert/delete line?
	 jrst seos1		; no, punt to spaces
	camg nh,whmin		; first column?
	 jrst seos3		; yes, use insert/delete right away
	call td.eol		; clear rest of this line
	move nh,whmin		; CR
	caml nv,wvmax		; if last line,
	 jrst seos4		; then we're done
	addi nv,1		; else LF
seos3:	push p,a
	move a,wvmax
	subi a,(nv)		; Find # of lines to delete
	addi a,1
	call td.mfrc
	xct .tedlp+tb		; flush em.
	 call scrdlp
	pop p,a
seos4:	popae p,[nv,nh]
	return


; TD.CLR - Clear Screen.
; Arguments:
;   None

td.clr:	dmove nvh,wmin		; move to beginning of the current window
tdclr1:	trne f,%fnclr		; atomic clear in our arsenal?
	 jrst tdeof1		; no, simulate by doing CLEOS
	xct .teclr+tb		; clear screen
	 call screos		; update screen image if .TECLR didn't
	dmove vh,tmin		; clearing the screen homes
	tlz f,%clpnd		; no CLEOL pending after a clear screen!
	return

subttl	   TYO - TD.SCR, TD.SD, TD.SU

; TD.SCR - Scroll window in either direction.
; Arguments:
;   A	# lines to scroll; pos scrolls up, neg scrolls down.

td.scr:	jumpge a,td.su		; If pos let TD.SU handle it.
	movn a,a		; get magnitude.
	call td.sd
	movn a,a
	return


; TD.SD - Scroll window down.
;  A	# lines to scroll down.

td.sd:	pushae p,[nh,nv]
	trne f,%fnsd		; Do we have atomic scroll down?
	 jrst tdsd1		; No, simulate.
	dmove nvh,wmin		; move to first line of current window
	call td.mfrc		; ...
	xct .tesd+tb		; scroll down
	 call scrsd		; update screen image if .TESD didn't
	jrst tdsd2
tdsd1:	dmove nvh,wmin		; move to first column of first line of
				; current window
	call td.ilp		; and insert specified no. of lines
tdsd2:	popae p,[nv,nh]		; restore current position
	return


; TD.SU - Scroll up.
; Arguments:
;   A	No. of lines to scroll

td.su:	jumple a,[return]	; nothing to do?
	pushae p,[nh,nv]	; save current position
	trne f,%fnsu		; atomic scroll up in our arsenal?
	 jrst tdsu1		; no, simulate
	move nv,wvmax		; move to last line of current window
	movei nh,0		; ...
	call td.mfrc		; ...
	xct .tesu+tb		; scroll up
	 call scrsu		; update screen image if .TESU didn't
	addi v,-1(a)		; update cursor position
	jrst tdsu2
tdsu1:	dmove nvh,wmin		; move to first column of first line of
				; current window
	call td.dlp		; and delete specified no. of lines
tdsu2:	popae p,[nv,nh]		; restore current position
	return

subttl	   TYO - TD.RSD, TD.RSU, TD.ILP

; TD.RSD
; Arguments:
;   A	Scroll count.
;   B	No. of lines in region.

td.rsd:	jumpe a,[return]	; nop if no movement
	jumpe b,[return]	; nop if null region
	movei c,(nv)		; TD.WIN arg: maximum vertical
	addi c,-1(b)		; is current position plus region size - 1
	caml c,wvmax		; if at or below bottom line, then use
	 pjrst td.ilp		; simple insert line
	push p,wvmax		; save current window bottom
	push p,a		; save scroll count
	dmove a,wmin		; TD.WIN args: minimum vertical, minimum
				; horizontal
	move d,whmax		; TD.WIN arg: maximum horizontal
	call td.win		; set window
	pop p,a			; get count
	call td.ilp		; insert n lines in window
	dmove a,wmin		; TD.WIN arg: minimum vertical, minimum
				; horizontal
	pop p,c			; TD.WIN arg: maximum vertical
	move d,whmax		; TD.WIN arg: maximum horizontal
	pjrst td.win		; set window to what it used to be


; TD.RSU
; Arguments:
;   A	Scroll count.
;   B	No. of lines in region.

td.rsu:	jumpe a,[return]	; nop if no movement
	jumpe b,[return]	; nop if null region
	movei c,(nv)		; TD.WIN arg: maximum vertical
	addi c,-1(b)		; is current position plus region size - 1
	caml c,wvmax		; if at or below line, then use simple
	 pjrst td.dlp		; delete line
	push p,wvmax		; save current window bottom
	push p,a		; save scroll count
	dmove a,wmin		; TD.WIN args: minimum vertical, minimum
				; horizontal
	move d,whmax		; TD.WIN arg: maximum horizontal
	call td.win		; set window
	pop p,a			; get count
	call td.dlp		; delete n lines in window
	dmove a,wmin		; TD.WIN arg: minimum vertical, minimum
				; horizontal
	pop p,c			; TD.WIN arg: maximum vertical
	move d,whmax		; TD.WIN arg: maximum horizontal
	pjrst td.win		; set window to what it used to be


; TD.ILP - Insert Line Position.
; Argument:
;   A	No. of lines to insert.

td.ilp:	jumple a,[return]	; nothing to do?
	movei t1,(nv)		; calculate where current line will be
	addi t1,(a)		; moved to by insertion
	camle t1,wvmax		; past end of window?
	 pjrst td.eof		; yes, then this is equivalent to CLEOS
	trne f,%fnilp		; able to use insert lines?
	 pjrst similp		; no, simulate
	move t1,wvmax		; last line of the terminal's window the same
	camn t1,tvmax		; as our software window?
	 jrst tdilp1		; yes, a simple insert will do

	; Last line of terminal window is not the same as the last line of the
	; software window.  Therefore the lines to be inserted must be balanced
	; by deleting lines at the end of the window.
	push p,nv		; save current vertical position
	move nv,t1		; move n lines before end of window
	subi nv,-1(a)		; subtracting from wvmax, so -1.
	call td.frc		; force CLEOL and cursor movement
	xct .tedlp+tb		; delete n lines
	 call scrdlp		; update screen image if .TEDLP didn't
	pop p,nv		; restore vertical position
tdilp1:	call td.frc		; force CLEOL and cursor movement
	xct .teilp+tb		; insert n lines
	 pjrst scrilp		; update screen image if .TEILP didn't
	return


; SIMILP
similp:	pushae p,[nv,b,a]
	move nv,wvmax
simil1:	move nh,whmin
	sub nv,(p)
	camge nv,-2(p)
	 jrst simil3
	movn b,wwidth
	movs b,b
	hrri b,@scrntb(nv)
	add nv,(p)
	call td.eol
simil2:	move a,(b)
	call td.cho
	aobjn b,simil2
	soja nv,simil1
simil3:	add nv,(p)
simil4:	camge nv,-2(p)
	 jrst simil5
	call td.eol
	soja nv,simil4
simil5:	popae p,[a,b,nv]
	return

subttl	   TYO - TD.DLP

; TD.DLP - Delete Line Position.
; Argument:
;   A	No. of lines to delete.

td.dlp:	jumple a,[return]	; nothing to do?
	movei t1,(nv)		; calculate line no. which will be moved
	addi t1,(a)		; to current line by deletion
	camle t1,wvmax		; past end of window?
	 pjrst td.eof		; yes, then this is equivalent to CLEOS
	trne f,%fndlp		; able to use delete lines?
	 pjrst simdlp		; no, simulate
	call td.frc		; force CLEOL and cursor movement
	xct .tedlp+tb		; delete n lines
	 call scrdlp		; update screen image if .TEDLP didn't
	move t1,wvmax		; last line of the terminal's window the same
	camn t1,tvmax		; as our software window?
	 return			; yes, we're done

	; Last line of terminal window is not the same as the last line of the
	; software window.  Therefore the deleted lines must be balanced with
	; lines inserted at the end of the window.
	push p,nv		; save current vertical position
	move nv,t1		; move n lines before last line of window
	subi nv,-1(a)		; subtracting from wvmax, so -1...
	call td.mfrc		; force cursor movement
	xct .teilp+tb		; insert n lines
	 call scrilp		; update screen image if .TEILP didn't
	pop p,nv		; restore vertical position
	return


; SIMDLP
simdlp:	pushae p,[nv,b,a]
simdl1:	move nh,whmin
	add nv,(p)
	camle nv,wvmax
	 jrst simdl3
	movn b,wwidth
	movs b,b
	hrri b,@scrntb(nv)
	sub nv,(p)
	call td.eol
simdl2:	move a,(b)
	call td.cho
	aobjn b,simdl2
	aoja nv,simdl1
simdl3:	sub nv,(p)
	call td.eof
	popae p,[a,b,nv]
	return

subttl	   TYO - TD.IC, TD.ICP

td.ic:	caml nh,whmax		; if last column
	 pjrst td.cho		; then just use simple typeout
	push p,a		; save character
	cail a,40		; if not 40-176
	 cail a,177		; ...
	  jrst tdic2		; then use general method
				; the above test is losing, but should work
				; 99.9% of the time
	skipn .teeim+tb		; if insert mode not available
	 jrst tdic2		; use general method
	movei a,1		; 1 character
	move t1,whmax		; last column of software window the same as
	camn t1,thmax		; the last column of the terminal's window?
	 pjrst tdic1		; yes, a simple insert will do
	; Last column of terminal window is not the same as the last column
	; of the software window.  Therefore the characters to be inserted
	; must be balanced by deleting characters at the end of the window.
	push p,nh		; save current horizontal position
	move nh,t1		; move to last column
	call td.frc		; force CLEOL and cursor movement
	xct .tedcp+tb		; delete n characters
	 call scrdcp		; update screen image if .TEDCP didn't
	pop p,nh		; restore horizontal position
tdic1:	call td.frc		; force cursor movement
	tlon f,%icm		; insert character mode on?
	 xct .teeim+tb		; no, turn it on
	call scricp		; update screen image
	pop p,a			; restore character
	call @.trtyo+tb		; insert it
	movem a,@scrtab(v)	; update screen image
	aos h,nh		; increment H and NH (since they're the same,
				; can do it in one instruction)
	return
tdic2:	movei a,1		; TD.ICP arg: A = insert count
	call td.icp		; insert 1 space
	pop p,a			; restore character
	pjrst td.cho		; type it


; TD.ICP - Insert Character Position.
; Argument:
;   A	No. of characters to insert.

td.icp:	jumple a,[return]	; nothing to do?
	movei t1,(nh)		; calculate column that current character
	addi t1,(a)		; will be moved to by insertion
	camle t1,whmax		; past end of window?
	 pjrst td.eol		; yes, then this is equivalent to CLEOL
	trne f,%fnicp		; able to use insert characters?
	 pjrst simicp		; no, simulate
	move t1,whmax		; last column of software window the same as
	camn t1,thmax		; the last column of the terminal's window?
	 pjrst xicp		; yes, a simple insert will do

	; Last column of terminal window is not the same as the last column
	; of the software window.  Therefore the characters to be inserted
	; must be balanced by deleting characters at the end of the window.
	push p,nh		; save current horizontal position
	move nh,t1		; move n characters before last column
	subi nh,-1(a)		; subtracting from whmax, so -1...
	call td.frc		; force CLEOL and cursor movement
	xct .tedcp+tb		; delete n characters
	 call scrdcp		; update screen image if .TEDCP didn't
	pop p,nh		; restore horizontal position
	; fall through to XICP

xicp:	call td.frc		; force cursor movement
	skipn t1,.teicp+tb	; insert n characters directly?
	 jrst xicp1		; no, use insert character mode
	xct t1			; insert n characters
	 pjrst scricp		; update screen image if .TEICP didn't
	return
xicp1:	tlon f,%icm		; insert character mode on?
	 xct .teeim+tb		; no, turn it on
	tyn 40			; type n spaces
	add h,a			; update actual cursor position
	pjrst scricp		; update screen image


mvar siline(maxhor)

; SIMICP
simicp:	pushae p,[nh,a]
	add a,nh
	camle a,whmax
	 jrst simic2
	movsi t1,@scrntb(nv)
	hrri t1,siline(a)
	move a,whmax
	blt t1,siline(a)
	call td.eol
	add nh,(p)
simic1:	move a,siline(nh)
	caml nh,whmax
	 jrst simic3
	call td.cho
	jrst simic1
simic2:	call td.eol
	jrst simic4
simic3:	call td.cho
simic4:	popae p,[a,nh]
	return

subttl	   TYO - TD.DCP

; TD.DCP - Delete Character Position.
; Argument:
;   A	No. of characters to delete.

td.dcp:	jumple a,[return]	; nothing to do?
	movei t1,(nh)		; calculate column no. which will be moved
	addi t1,(a)		; to current position by deletion
	camle t1,whmax		; past end of window?
	 pjrst td.eol		; yes, then this is equivalent to CLEOL
	trne f,%fndcp		; able to use delete characters?
	 pjrst simdcp		; no, simulate
	call td.frc		; force CLEOL and cursor movement
	xct .tedcp+tb		; delete n characters
	 call scrdcp		; update screen image if .TEDCP didn't
	move t1,whmax		; last column of software window the same as
	camn t1,thmax		; the last column of the terminal's window?
	 return			; yes, we're done

	; Last char of terminal window is not the same as the last character
	; of the software window.  Therefore the deleted characters must be
	; balanced with characters inserted at the end of the window.
	push p,nh		; save current horizontal position
	move nh,t1		; move n characters before last column
	subi nh,-1(a)		; subtracting from whmax, so -1.
	call xicp		; insert n characters
	pop p,nh		; restore horizontal position
	return


; SIMDCP
simdcp:	pushae p,[nh,b,a]
	add nh,a
	camle nh,whmax
	 jrst simdc3
	movsi t1,@scrntb(nv)
	sub nh,a
	hrri t1,siline(nh)
	movn b,a
	add b,whmax
	blt t1,siline(b)
	call td.eol
	sub b,nh
simdc1:	move a,siline(nh)
	call td.cho
	sojg b,simdc1
simdc2:	popae p,[a,b,nh]
	return
simdc3:	call td.eol
	jrst simdc2

subttl	   TYO - TD.BEL, TD.BOW, TD.RST, TD.QOT

; TD.BEL - Ding bell.
td.bel:	skipl jbell		; skip if don't want audible.
	 xct .txbel+tb		; want feep, send out.
	skiple visbel		; and return unless want visible bell.
	 xct .txvbl+tb		; do a visible bell.
	return


; TD.BOW - Enter Black-on-White mode (Standout).
td.bow:	skipe .txso+tb		; terminal support standout mode?
	 tloe f,%fbow		; yes, already in standout mode?
	  return		; unsupported or already in it, ignore request
	call td.frc		; force CLEOL and cursor movement
	xct .txso+tb		; enter standout mode
	movsi t1,%cmbow
	iorm t1,scmode		; Set standout-mode flag to OR into char vals
	return


; TD.RST - Reset BOW (standout) mode to normal.  In future may
; apply to other modes as well.
td.rst:	tlzn f,%fbow		; already in standout mode?
	  return		; no, ignore request
	call td.frc		; force CLEOL and cursor movement
	xct .txsor+tb		; exit standout mode
	setzm scmode		; Clear any char-val flags.
	return


; TD.QOT - Send device-dependent data.
; Argument:
;   A	Byte to output.
td.qot:	call td.frc		; force CLEOL and cursor movement
	pjrst @.trtyo+tb	; out it goes.

subttl	   TYO - Ordinary character output

; TD.CHO - Output a character.
; Argument:
;   A	Character.

td.cho:	ior a,scmode		; IOR in flags for current screen image mode
	tlne f,%clpnd		; CLEOL pending?
	 jrst ordn2		; yes, special hacking

; No pending CLEOL.
ordn0:	camn a,@scrntb(nv)	; character already there?
	 jrst ordn1		; yes, just update cursor position
	cain h,(nh)		; cursor where it's supposed to be?
	 caie v,(nv)		; (do test inline for speed)
	  call @.trmov+tb	; no, move it before outputting character
	call @.trcho+tb		; output character
ordn1:	camge nh,whmax		; last column?
	 addi nh,1		; no, advance one position
	return

; There is a pending CLEOL.
ordn2:	came nv,ceolpv		; on same line as pending CLEOL?
	 jrst ordn9		; no, do CLEOL and output character normally
	camle nh,ceolph		; NH less than or equal to EOL position?
	 jrst ordn5		; no, must insure positions between
				; CEOLPH and NH are clear
; NH <= CEOLPH.
ordn3:	camn a,@scrntb(nv)	; character already there?
	 jrst ordn4		; yes, just update cursor position
	cain h,(nh)		; cursor where it's supposed to be?
	 caie v,(nv)		; (do test inline for speed)
	  call @.trmov+tb	; no, move it before outputting character
	call @.trcho+tb		; output character
ordn4:	caml nh,whmax		; last column?
	 jrst [	tlz f,%clpnd	; yes, CLEOL no longer pending
		return ]
	came nh,ceolph		; just typed in column CLEOL pending at?
	 aoja nh,[return]	; no, advance one position and that's it
	addi nh,1		; advance one position
	movem nh,ceolph		; and update CLEOL pending column
	return

; NH > CEOLPH.
ordn5:	push p,a		; save character
	exch nh,ceolph		; start clear/test scan at CEOLPH position
	movei a,blchar		; space character for clearing/testing
	trnn f,%fneol		; does the terminal have CLEOL?
	 jrst ordn8		; yes
; Terminal lacks CLEOL.  Clear between CEOLPH and current position with
; spaces.
ordn6:	camn a,@scrntb(nv)	; already clear?
	 jrst ordn6a		; yes, just advance
	cain h,(nh)		; cursor where it's supposed to be?
	 caie v,(nv)		; (do test inline for speed)
	  call @.trmov+tb	; no, move it before outputting character
	call @.trcho+tb		; output character
ordn6a:	addi nh,1
	camge nh,ceolph		; reached desired position?
	 jrst ordn6		; no, keep going
	pop p,a			; restore character
	jrst ordn3		; now hack character
; Terminal has CLEOL.  First check if need to erase area between CEOLPH and
; current position.  If so then do CLEOL.
ordn7:	caml nh,ceolph		; reached desired position?
	 jrst [	pop p,a		; yes, all blank, restore character
		jrst ordn3 ]	; go output character
ordn8:	camn a,@scrntb(nv)	; this character position blank?
	 aoja nh,ordn7		; yes, keep checking
; Area between CEOLPH and current position needs to be cleared.
	exch nh,ceolph		; put first position to be cleared in CEOLPH,
				; and restore current position
	pop p,a			; restore character
ordn9:	call frcel1		; do the pending CLEOL
	jrst ordn0

subttl	Window variables

comment ~
Three kinds of window limits are used.  The first set defines the terminal
screen.  The lower limits are always zero and the upper limits are given by
SVMAX and SHMAX.  These are set at start up and never changed.  For
convenience SWIDTH and SHEIGHT are SHMAX-0+1 and SVMAX-0+1 respectively.

The second set defines the current "hardware" or "terminal" window.  These
are TVMIN, THMIN, TVMAX, and THMAX.  These are initialized to 0, 0, SVMAX,
and SHMAX.  These are set every time a set window command is sent to the
terminal (only a few terminals have a set window command).  For convenience
TWIDTH and THEIGHT are always THMAX-THMIN+1 and TVMAX-TVMIN+1 respectively.

Finally the third set is the current software window.  It is what ITS (or
whatever) thinks the current window is.  These are WVMIN, WHMIN, WVMAX, and
WHMAX.  Thus a %TDEOL means erase from here to WHMAX.  If WHMAX=THMAX then
the terminal's atomic CLEOL can be used to accomplish this.  Otherwise the
%TDEOL will have to be simulated; using the terminal's CLEOL would clear out
to THMAX, which would be more than intended.  For convenience WWIDTH and
WHEIGHT are always WHMAX-WHMIN+1 and WVMAX-WVMIN+1 respectively.

~
SECTION MAINVAR
sheight: block 1	; screen height (no. lines on screen)
swidth:	 block 1	; screen width (no. of characters per screen line)
smax::			; SMAX refers to the pair SVMAX,SHMAX
svmax:	 block 1	; maximum vertical screen position (SHEIGHT-1)
shmax:	 block 1	; maximum horizontal screen position (SWIDTH-1)

tmin::			; TMIN refers to the pair TVMIN,THMIN
tvmin:	 block 1	; first line of terminal window
thmin:	 block 1	; first column of terminal window
tmax::			; TMAX refers to the pair TVMAX,THMAX
tvmax:	 block 1	; last line of terminal window
thmax:	 block 1	; last column of terminal window
theight: block 1	; terminal window height (TVMAX-TVMIN+1)
twidth:	 block 1	; terminal window width (THMAX-THMIN+1)

wmin::			; WMIN refers to the pair WVMIN,WHMIN
wvmin:	 block 1	; first line of window
whmin:	 block 1	; first column of window
wmax::			; WMAX refers to the pair WVMAX,WHMAX
wvmax:	 block 1	; last line of window
whmax:	 block 1	; last column of window
wheight: block 1	; window height (WVMAX-VVMIN+1)
wwidth:	 block 1	; window width (WHMAX-WHMIN+1)

wsave:	 block 4	; save area for WVMIN,WHMIN,WVMAX,WHMAX

SECTION MAIN

subttl	Screen Image

blchar==:40	; "blank" char value
mvar scmode	; Screen-image char output mode flags in LH
 %cmbow==1	;  Standout-mode in effect.

; Screen image tables and routines

constants
SECTION INIT

; SCRINI - Initialize Screen image.  This uses SHEIGHT and SWIDTH and so
; must be called after SETUP3.

scrini:	pushae p,[a,b,c]
	setzm scmode		; Clear screen-image char mode
IFN ITS,{
	move b,sheight		; get no. of lines
	imul b,swidth		; multiply by width to get no. of characters
	addi b,screen		; add in start of screen image
	addi b,pg$siz-1		; add PG$SIZ-1 to so LSH will round up
	lsh b,-pg$log		; get last page no. needed
	subi b,sipg		; get no. of pages needed
	jumpe b,scini1
	hrloi b,-1(b)
	eqvi b,sipg		; now have page AOBJN
	$call corblk,[#%cbndw,#%jself,b,#%jsnew]
	 .lose %lssys
} ; IFN ITS
scini1:	movn a,sheight
	hrlz a,a		; Set up aobjn for no. of lines.
	move b,[screen(nh)]
	move c,[screen(h)]
scini2:	movem b,scrntb(a)
	movem c,scrtab(a)
	add b,swidth
	add c,swidth
	aobjn a,scini2		; Fill out addresing table.
	move a,swidth		; now get total # wds in screen-image buffer
	imul a,sheight		; like so.
	movem a,scrlen
	addi a,screen-1		; Find address of last word usd.
	movem a,scrlst		; Store for BLT.
	movei a,blchar		; clear first character position
	movem a,screen		; ...
	move a,[screen,,screen+1]	; clear rest of screen image
	blt a,@scrlst			; ...
	popae p,[c,b,a]
	return

constants
SECTION MAIN

; SCRDLF - Update screen image after a erase character operation.

scrdlf:	movei t1,blchar
	movem t1,@scrntb(nv)
	return


; SCREOL - Update screen image after a CLEOL operation.

screol:	push p,nh		; save horizontal position
	movei t1,@scrntb(nv)	; pointer to current character position
	movei t2,blchar		; clear current character position
	movem t2,(t1)		; ...
	hrli t1,(t1)		; make BLT AC of form address,,address+1
	addi t1,1		; ...
	move nh,thmax		; pointer to last character position of line
	movei t2,@scrntb(nv)	; ...
	cail t2,(t1)		; already cleared whole line?
	 blt t1,(t2)		; no, clear rest of line
	pop p,nh		; restore horizontal position
	return


; SCREOS - Update screen image after a CLEOS operation.

screos:	pushae p,[nv,nh]	; save current position
scres1:	call screol		; erase to end of line
	move nh,thmin		; move to beginning of line
	camge nv,tvmax		; done?
	 aoja nv,scres1		; no, move to next line and do erase again
	popae p,[nh,nv]		; restore current position
	return


; SCRICP - Update screen image after a insert characters operation.
; Argument:
;   A	No. of characters inserted.

scricp:	jumple a,[return]	; NOP if no. of characters is zero
	push p,nh		; save horizontal position
	move nh,thmax		; start at end of line
scric1:	sub nh,a		; move back by no. of characters inserted
				; to get position of next character to move
	camge nh,(p)		; passed point of insertion?
	 jrst scric2		; yes, character movement done
	move t1,@scrntb(nv)	; get next character
	add nh,a		; add no. inserted to get its new position
	movem t1,@scrntb(nv)	; and put it there
	soja nh,scric1		; backup and do some more
scric2:	pop p,nh		; restore horizontal position
	movei t1,@scrntb(nv)	; get pointer to first character position
	movei t2,blchar		; clear first character position
	movem t2,(t1)		; ...
	caig a,1		; only one character position to clear?
	 return			; yes, we're done
	movei t2,1(t1)		; create BLT pointer of form addr,,addr+1
	hrl t2,t1		; ...
	add t1,a		; add no. of characters to get stopping
				; address
	blt t2,-1(t1)		; clear inserted positions
	return


; SCRDCP - Update screen image after a delete characters operation.
; Argument:
;   A	No. of characters deleted

scrdcp:	jumple a,[return]	; NOP if zero characters deleted
	push p,nh		; save horizontal position

	; Copy characters
	movei t1,@scrntb(nv)	; form BLT AC of form <curpos>+n,,<curpos>
	add nh,a		; ...
	hrli t1,@scrntb(nv)	; ...
	move nh,thmax		; get pointer to last character position to
	sub nh,a		; copy, i.e. n characters before end of line
	movei t2,@scrntb(nv)	; ...
	cail t2,(t1)		; don't copy anything if deleting all the
				; characters on the line (or more)
	 blt t1,(t2)		; copy characters from <curpos>+n to <curpos>

	; Clear n character positions at the end of the line.
	movei a,blchar		; clear last character position
	movem a,1(t2)		; ...
	hrli t2,1(t2)		; create BLT pointer of form addr,,addr+1
	addi t2,2		; ...
	move nh,thmax		; get pointer to end of line to use as stop
	movei t1,@scrntb(nv)	; address
	cail t1,(t2)		; already cleared all we have to?
	 blt t2,(t1)		; no, clear to end of line

	pop p,nh		; restore horizontal position
	return


; SCRILP - Update screen image after a insert line operation.
; Argument:
;   A	No. of lines inserted.

scrilp:	jumple a,[return]	; NOP if no. of lines is zero
	pushae p,[a,b,nh]	; save ACs

	move b,tvmax		; start at bottom and work backwards
scril1:	sub b,a			; get line no. to copy from
	camge b,nv		; passed position of insert?
	 jrst scril2		; yes, done copying
	move nh,thmin		; put pointer to beginning of line
	movsi t1,@scrntb(b)	; to copy from in LH of BLT AC
	add b,a			; put pointer to beginning of line
	hrri t1,@scrntb(b)	; to copy to in RH of BLT AC
	move nh,thmax		; copy until reach end of destination line
	blt t1,@scrntb(b)	; ...
	soja b,scril1		; move up one line and do it again

	; Now clear the "inserted" lines.
scril2:	addi b,1		; move to next line
	move nh,thmin		; pointer to beginning of line
	movei t1,@scrntb(b)	; ...
	movei t2,blchar		; clear first character
	movem t2,(t1)		; ...
	hrl t1,t1		; make BLT AC of address,,address+1
	addi t1,1		; ...
	move nh,thmax		; clear until reach last character of line
	blt t1,@scrntb(b)	; ...
	sojg a,scril2		; loop back for rest of inserted lines

	popae p,[nh,b,a]	; restore ACs
	return


; SCRDLP - Update screen image after a delete line operation.
; Argument:
;   A	No. of lines deleted.

scrdlp:	jumple a,[return]	; NOP if no. of lines is zero
	pushae p,[nh,nv]	; save ACs

scrdl1:	add nv,a		; get line no. to copy from
	camle nv,tvmax		; about to copy from non-existant line?
	 jrst scrdl2		; yes, done copying
	move nh,thmin		; put pointer to beginning of line
	movsi t1,@scrntb(nv)	; to copy from in LH of BLT AC
	sub nv,a		; put pointer to beginning of line
	hrri t1,@scrntb(nv)	; to copy to in RH of BLT AC
	move nh,thmax		; copy until reach end of destination line
	blt t1,@scrntb(nv)	; ...
	aoja nv,scrdl1		; move down one line and do it again

	; Now clear the "inserted" lines.
scrdl2:	sub nv,a		; move to first line to clear
scrdl3:	move nh,thmin		; pointer to beginning of line
	movei t1,@scrntb(nv)	; ...
	movei t2,blchar		; clear first character
	movem t2,(t1)		; ...
	hrl t1,t1		; make BLT AC of address,,address+1
	addi t1,1		; ...
	move nh,thmax		; clear until reach last character of line
	blt t1,@scrntb(nv)	; ...
	camge nv,tvmax		; cleared last line?
	 aoja nv,scrdl3		; no, keep going
	popae p,[nv,nh]		; restore ACs
	return


; SCRSD - Update screen image after a scroll down operation.
; Argument:
;   A	No. of scroll downs.

scrsd:	pushae p,[a,nv]
	imul a,.tpscr+tb
	move nv,tvmin
	call scrilp
	popae p,[nv,a]
	return


; SCRSU - Update screen image after a scroll up operation.
; Argument:
;   A	No. of scroll ups.

scrsu:	pushae p,[a,nv]
	imul a,.tpscr+tb
	move nv,tvmin
	call scrdlp
	popae p,[nv,a]
	return


; SCRxTB - Screen Vertical index table.  Indexed by NV
;	to get index into SCREEN that starts specified line.
;	i.e. to access position indexed by current NH, NV, use
;	@SCRNTB(NV).
mvar scrntb(maxver+1)	; Holds vectors into SCREEN, indexed by NH
mvar scrtab(maxver+1)	; Holds vectors into SCREEN, indexed by H
mvar scrlen			; Holds length in words of screen image
mvar scrlst			; Holds address of last word used (for BLT)

subttl	Random routines

; ABSCLR - Clear screen, without assuming anything (like screen image,
; cursor position, etc.).  This doesn't (and shouldn't) update the screen
; image.  This does (and should) update the actual cursor position.

absclr:	dmove nvh,wmin		; set desired cursor position to home
	trnn f,%fnclr		; atomic clear screen?
	 jrst [	xct .teclr+tb	; yes, do it
		dmove vh,tmin	; cursor now at home
		return
		]
	skipe .tmhom+tb		; atomic home?
	 jrst [	xct .tmhom+tb	; yes, do it
		dmove vh,tmin	; update actual cursor position
		call td.mfrc	; move from TMIN to WMIN
		jrst abscl1
		]
	xct .tmabs+tb		; assume terminal has direct cursor
				; positioning!
	dmove vh,nvh		; update actual cursor position
abscl1:	trnn f,%fneos		; atomic CLEOS?
	 xct .teeos+tb		; yes, do it
	  jfcl			; don't update screen image!
	return


; FULWIN - Set window to full screeen.
fulwin:	pushae p,[a,b,c,d]	; save regs
	move t1,[wmin,,wsave]	; save current window
	blt t1,wsave+3		; ...
	setzb a,b		; TD.WIN args: minimum vertical, minimum
				; horizontal
	dmove c,smax		; TD.WIN args: maximum vertical, maximum
				; horizontal
	call td.win		; set window to whole screen
	popae p,[d,c,b,a]	; restore regs
	return

; RESWIN - Restore window after FULWIN.
reswin:	pushae p,[a,b,c,d]	; save regs
	move t1,[wsave,,a]	; TD.WIN args: A = minimum vertical,
	blt t1,d		; B = minimum horizontal,
				; C = maximum vertical,
				; D = maximum horizontal
	call td.win		; restore window
	popae p,[d,c,b,a]	; restore regs
	return


; FINI- Clean up terminal stuff.
fini:	call fulwin		; set window to whole screen
	tlze f,%icm		; insert character mode on?
	 xct .telim+tb		; yes, turn it off
	trze f,%fbow		; standout mode on?
	 xct .txsor+tb		; yes, turn it off
	call td.mfrc		; move cursor to where it's supposed to be
	xct .trfin+tb		; call TTY cleanup handler
	pjrst tyofin		; send buffered output, ensure it gets there

subttl	Process Start/Stop/Wakeup

; If we are dealing with an inferior fork process then we need to
; be able to stop it during times when the input stream needs to
; deal directly with the TTY (ordinarily the province of the TYO module).

IFN TINT\SINT,{
frcv:	rrcv:		; No inferior fork.  Freeze/Resume are noops.
	return
}
IFE TINT\SINT,{
IFN TNX,{
mvar acblk(20)

; FRCV - Freeze receive fork.
frcv:	skipn a,rcvfrk		; FFORK arg: A = fork handle
	 return			; there might not be a receive fork
	ffork			; freeze fork
				; RFACS arg: A = fork handle
	movei b,acblk		; RFACS arg: B = AC block address
	rfacs			; read fork ACs
irp x,,[f,nv,nh,v,h]
	move x,acblk+x		; get interesting ACs from inferior
termin
	return

; RRCV - Resume receive fork.
rrcv:
irp x,,[f,nv,nh,h,v]
	movem x,acblk+x		; pass interesting ACs back to inferior
termin
	move a,rcvfrk		; SFACS arg: A = fork handle
	movei b,acblk		; SFACS arg: B = address of AC block
	sfacs			; set fork ACs
				; RFORK arg: A = fork handle
	rfork			; resume fork
	return
} ; IFN TNX
} ; IFE TINT\SINT

; STOP - Prepare for program pause or stop.
IFN ITS,{
stop:	$call scpos,[#tyoc,nv,nh]
	 jfcl
	return
} ; IFN ITS
IFN TNX,{
mvar siiset			; nonzero if superimage input on

stop:	skipn siiset		; if superimage input not set,
	 return			; don't try to undo it
IFN 20X,{
	move a,ttyjfn		; STPAR arg: A = JFN
	move b,oldmod		; STPAR arg: B = JFN mode word
	stpar			; restore JFN mode word to previous value
	move a,ttyjfn		; SFPOS arg: A = JFN
	move b,h		; SFPOS arg: B = line no.,,column no.
	sfpos			; tell operating system where cursor is
} ; IFN 20X
IFN 10X,{
	say "
"				; can't tell 10X horizontal position so CRLF
				; to make it zero
} ; IFN 10X
	movei a,.fhjob		; STIW arg: A = fork handle
	move b,oldtiw		; STIW arg: B = terminal interrupt word
	stiw			; restore terminal interrupts
	setzm siiset		; superimage input no longer set
	return
} ; IFN TNX

; RESUME - Continue after pausing.
IFN ITS,{
resume:	return
} ; IFN ITS
IFN TNX,{
resume:
sii:
	movei a,.fhjob		; RTIW arg: A = bits,,fork handle
	rtiw			; read terminal interrupt word for job
				; result: B = terminal interrupt word
	movem b,oldtiw		; save away
				; STIW arg: A = bits,,fork handle
IFE TINT, movei b,0		; STIW arg: B = terminal interrupt word
IFN TINT, movx b,1_<35.-.ticti>
	stiw			; set terminal interrupt word
IFN 20X,{
	move a,ttyjfn		; RFMOD arg: A = JFN
	rfmod			; read JFN mode word to save old value
	movem b,oldmod		; RFMOD result: B = JFN mode word
	trze b,tt%pgm		; turn off output page mode
	 stpar			; if it's on
} ; IFN 20X
	setom siiset		; remember we've run
	return

} ; IFN TNX


; QUIT - Terminate program.
quit:
IFN NET,move a,[ascnt "Quit and close connection [Confirm]"]
IFN STY,{
IFN ITS,move a,[ascnt "Quit and detach STY [Confirm]"]
IFN TNX,move a,[ascnt "Quit and detach PTY [Confirm]"]
}
	call ascout
	call td.frc
	call tyofrc
	call tbinw		; Get next char (wait for it)
	cain a,^M		; CR is yes
	 jrst quitng
	caie a,"Y
	 cain a,"y
	  jrst quitng
	move a,[ascnt " No"]
	call ascout		; Don't quit.
	call td.frc
	call tyofrc		; Put up the "No" momentarily.
	ret			; and return normally instead of stopping.

quitng:	call fini		; clean up
	call stop		; prepare to stop
	pjrst logout

; PROCED - Return to superior.
proced:	pushae p,[nv,nh]	; save cursor position
	call fini		; clean up
	call stop		; prepare to stop
ifn its, .break 16,100000	; pause
ifn tnx, haltf			; pause
	call resume		; undo STOP
	call redis0		; redisplay
	call reswin		; restore window
	popae p,[nh,nv]		; restore cursor position
	return


; REINIT - Reinitialize terminal.
reinit:	pushae p,[nv,nh]	; save cursor position
	move t1,[wmin,,wsave]	; save current window
	blt t1,wsave+3		; ...
	setzb v,h		; cursor will be moved to home
	setzb nv,nh		; ...
	xct .trini+tb		; call terminal initialization
	call redis1		; redisplay screen
	call reswin		; restore window
	popae p,[nh,nv]		; resrore cursor position
	return

; REDISP - Redisplay whole screen from screen image.
; Clobbers A.
redisp:	pushae p,[nv,nh]	; save cursor position
	call fulwin		; set window to whole screen
	call redis0		; redisplay current window
	call reswin		; restore window
	popae p,[nh,nv]		; restore cursor position
	return

; REDIS0 - Redisplay current window.
redis0:	call absclr		; clear screen without updating screen image
redis1:	move a,@scrntb(nv)	; get character from screen image
	cain a,blchar		; blank?
	 jrst redis2		; yes, don't bother
	call td.mfrc		; force cursor to desired position
	call @.trcho+tb		; output character
redis2:	camge nh,whmax		; done last character of line?
	 aoja nh,redis1		; no, keep going
	move nh,whmin		; move to beginning of line
	camge nv,wvmax		; done last line of screen?
	 aoja nv,redis1		; no, keep going
	return


popj1:	aosa (p)
popaj:	pop p,a
apopj:	return			; a popj to jump to.

subttl	Wholine

IFN STY,{

; WHOINI - Initialize wholine code.

IFN ITS,{
whoini:	move a,[setz-1]		; set WHOTIM to plus infinity
	movem a,whotim		; ...
	skipg wholin		; WHOLINE specified?
	 return			; no, done
	move a,@time
	addi a,5*30.-2
	movem a,whotim
	move a,[squoze 0,SLOADU]
	movei b,0
	call itsmap
	movem a,sloadu

irp v,,[JTMU,NMPGS,NSWPGS]
	move a,[squoze 0,v]
	.eval a,
	 .lose %lssys
	movem a,v
termin
	return
} ; IFN ITS
IFN TNX,	whoini==:apopj

; WHOOUT - Output wholine.

whoout:	pushae p,[a,b,c,d]	; save regs
	pushae p,[nv,nh]	; save position
	call frceol		; force CLEOL if pending
	call @.trwb+tb		; setup for the wholine
	call td.eol		; erase wholine
	call whoman		; output wholine data
	call frceol		; finish erase if necessary
	call @.trwe+tb		; End the wholine, cleaning up
	popae p,[nh,nv]		; restore position
	call td.frc
	call tyofin		; Force output and wait for output to be sent
IFN ITS,{
	move a,@time
	addi a,5*30.-2
	movem a,whotim
} ;    IFN ITS
	popae p,[d,c,b,a]	; restore regs
	return


; WHOWB - Default TR.WB.
whowb:	call fulwin		; reset window to full screen
	setzb nv,nh		; home
	return

; WHOWE - Default TR.WE.
whowe=:reswin			; restore window

IFN ITS,{
whoman:	$call rqdate,,b		; get date and time in disk format
	 .lose %lssys
	move a,[-16.,,[	sixbit /uind/	? movem wuind
			sixbit /uname/	? movem wuname
			sixbit /jname/	? movem wjname
			sixbit /sname/	? movem wsname
			sixbit /runt/	? movem wrunt
			sixbit /who1/	? movem wwho1
			sixbit /who2/	? movem wwho2
			sixbit /who3/	? movem wwho3
			]]
	$call usrvar,[#pyi,a]	; get information on job using STY's TTY
	 return			; don't error if no job
	move a,wuind
	imul a,lublk
	move t1,jtmu
	add t1,a
	movem t1,wvars+0
	move t1,nmpgs
	add t1,a
	movem t1,wvars+2
	add a,nswpgs
	movem a,wvars+4
	move a,[-lwvars,,wvars]
	$call usrmem,[#%jsnum+0,a]
	 .lose %lssys
	hlrz a,b		; WDATE arg: disk format date
	lsh a,2			; shifted left two
	call wdate		; print date
	call whosp		; output a space
	hrrz a,b
	call wtime2

; Job statistics.
	; Job no.
	call whosp		; output a space
	move a,wuind
	call woct		; output user index
	; UNAME
	call whosp		; output a space
	move b,wuname
	call whosx6		; output UNAME
	; JNAME
	call whosp		; output a space
	move b,wjname
	call whosx6		; output JNAME
	; SNAME
	call whosp		; output a space
	move b,wsname
	call whosx6		; output SNAME
	; State
	; %Run
	call whosp		; output a space
	move a,wjtmu
	muli a,100.
	div a,[2.^6]
	call whodec
	movei a,"/
	call td.cho
	movei a,10000.
	idiv a,@sloadu
	call whodec
	movei a,"%
	call td.cho
	; Runtime
	call whosp		; output a space
	move a,wrunt
	idivi a,<1000000./4>/40.	; convert to 40ths
	call wtime1
	; In/Total K
	call whosp		; output a space
	move a,wnmpgs
	sub a,wnswpgs
	call whodec
	movei a,"/
	call td.cho
	move a,wnmpgs
	call whodec
	movei a,"K
	call td.cho
	; user controlled
	skipg wwho1
	 return
	call whosp		; output a space
	move c,wwho1
	hlrz a,wwho2
	ldb t1,[370300,,c]
	call @whotbl(t1)
	ldb a,[240700,,c]
	jumpe a,whoo1
	call td.cho
	tlne c,1000
	 call td.cho
whoo1:	tlnn c,200000
	 call whosp		; output a space
	hrrz a,wwho2
	ldb t1,[340300,,c]
	call @whotbl(t1)
	tlnn c,2
	 call whosp		; output a space
	hlrz a,wwho3
	ldb t1,[170300,,c]
	call @whotbl(t1)
	ldb a,[040700,,c]
	jumpe a,whoo2
	call td.cho
	trne c,4000
	 call td.cho
	tlnn c,1
	 call whosp		; output a space
whoo2:	hrrz a,wwho3
	ldb t1,[140300,,c]
	pjrst @whotbl(t1)


; Dispatch table for WHO2/WHO3 printing modes.
whotbl:	[return]		; don't print
	wdate			; date
	wtime1			; time in 40ths
	wtime2			; time in half seconds
	woct			; octal
	whodec			; decimal
	wsix			; sixbit
	[return]		; unused


; WDATE - Print date.
wdate:	push p,a
	ldb a,[070400,,(p)]
	call whodc2
	movei a,"/
	call td.cho
	ldb a,[020500,,(p)]
	call whodc2
	movei a,"/
	call td.cho
	pop p,a
	ldb a,[130700,,a]
	pjrst whodc2


wtime1:	lsh a,-2		; convert 40ths to 10ths
	idivi a,10.
	push p,b
	call wtime3
	movei a,".
	call td.cho
	pop p,a
	addi a,"0
	pjrst td.cho

wtime2:	lsh a,-1		; convert half-seconds to seconds
wtime3:	idivi a,60.*60.
	call whodc2
	movei a,":
	call td.cho
	move a,b
	idivi a,60.
	call whodc2
	movei a,":
	call td.cho
	move a,b
	pjrst whodc2

woct:	push p,b
	idivi a,8.
	jumpe a,.+2
	 call woct
	movei a,"0(b)
	pop p,b
	pjrst td.cho

wsix:	movsi b,(a)
	call whosx2
	pjrst whosix


SECTION MAINVAR
wvars:	block 1
	movem wjtmu
	block 1
	movem wnmpgs
	block 1
	movem wnswpgs
lwvars==:.-wvars
SECTION MAIN

mvar whotim

mvar sloadu	; holds address of system fair share variable

mvar jtmu
mvar nmpgs
mvar nswpgs

mvar wuind
mvar wuname
mvar wjname
mvar wsname
mvar wjtmu
mvar wrunt
mvar wnmpgs
mvar wnswpgs
mvar wwho1
mvar wwho2
mvar wwho3
} ; IFN ITS

IFN TNX,{
whoman:	hrroi a,wtemp		; ODTIM arg: A = B.P.
	seto b,			; ODTIM arg: B = -1 for current date/time
	movsi c,(ot%nmn\ot%sla\ot%12h\ot%dam\ot%scl)
				; ODTIM arg: C = control bits
	odtim			; get current date/time
	call wstr		; output it
	move a,ptyttd		; GETJI arg: A = 400000+TTY no.
	move b,[-7,,wji]	; GETJI arg: B = AOBJN to data area
	getji			; get job information
	 return			; huh?
	; Job no.
	call whosp
	move a,wji+.jijno	; WHODEC arg: A = number
	call whodec		; output job no.
	; login name
	call whosp
	hrroi a,wtemp		; DIRST arg: A = B.P.
	move b,wji+.jiuno	; DIRST arg: B = user no.
	dirst			; convert user no. to string
	 jrst .+2
	  call wstr		; output user name
	; prgoram name
	call whosp
	move b,wji+.jipnm	; WHOSX6 arg: B = sixbit
	call whosx6		; output program name
	; connected directory
	call whosp
	hrroi a,wtemp		; DIRST arg: A = B.P.
	move b,wji+.jidno	; DIRST arg: B = directory no.
	dirst			; convert directory no. to string
	 jrst .+2
	  call wstr		; output directory name
	; load average
	call whosp
	move a,[sixbit/SYSTAT/]	; SYSGT arg: A = sixbit table name
	sysgt			; find table no. of systat table
	jumpe b,whoo2		; if not found then return zero
	movei a,(b)		; GETAB arg: table no. in RH
	hrli a,14		; and offset in LH
	getab			; get entry 14 of systat table: 1 minute load
				; average
	 jrst whoo2
	move b,a		; FLOUT arg: B = floating point number
	hrroi a,wtemp		; FLOUT arg: A = B.P.
	move c,[fl%one\fl%pnt\020200]	; FLOUT arg: C = control bits
	flout			; convert floating point number to string
	 jrst whoo2
	call wstr		; output load average
whoo2:
	; runtime
	call whosp
	move a,wji+.jirt	; WTIME arg: A = run time
;	pjrst wtime


wtime:	idivi a,100.		; convert milliseconds to tenths
	idivi a,10.		; convert tenths to seconds and remainder
	push p,b		; save remainder
	idivi a,60.*60.
	call whodc2
	movei a,":
	call td.cho
	move a,b
	idivi a,60.
	call whodc2
	movei a,":
	call td.cho
	move a,b
	call whodc2
	movei a,".
	call td.cho
	pop p,a
	addi a,"0
	pjrst td.cho

wstr:	push p,a
	move b,[440700,,wtemp]
wstr1:	camn b,(p)
	 jrst wstr2
	ildb a,b
	call td.cho
	jrst wstr1
wstr2:	pop p,a
	return

mvar wji(7)
mvar wtemp(6)
} ; IFN TNX

; WHOSP - Output a space.
whosp:	movei a,40
	pjrst td.cho

; WHOSX6 - Output a word of sixbit.
whosx6:	call whosx2
	call whosx2

; WHOSX2 - Output two sixbit characters.
whosx2:	call whosix

; WHOSIX - Output one sixbit character.
whosix:	movei a,0
	lshc a,6
	addi a,40
	pjrst td.cho

; WHODC2 - Output number as two decimal digits.
whodc2:	push p,b
	idivi a,10.
	addi a,"0
	call td.cho
	movei a,"0(b)
	pop p,b
	pjrst td.cho

; WHODEC - Output decimal number.
whodec:	push p,b
	idivi a,10.
	jumpe a,.+2
	 call whodec
	movei a,"0(b)
	pop p,b
	pjrst td.cho

} ; IFN STY

subttl	Routines for CRTSTY interactive typeouts

;;; ENTER is a routine to hack run-time interaction between CRTSTY and the
;;; user.  It saves the bottom line of the screen, and prompts for a command.
;;; The command is executed and the screen is restored.

;;; If a terminal wishes to provide terminal-specific commands, it may
;;; initialize the variable ENTACT to be a routine to process commands.
;;; If it skip returns, it found and executed a command, otherwise the
;;; standard error message will be given.

mvar entact		; If non-zero, a routine to handle terminal
			; specific commands.  (initialize modes, or
			; whatever....)
mvar scrmng		; -1 if screen munged and needs redisplay.

enter:	call frcv
	pushae p,[nh,nv,a,b,c,d]
	move nv,svmax
	call savl
	setzm scrmng

askcm2:	movei nh,0
	move nv,svmax
	call td.eol		; CLEOL
	move a,prgnam		; Show program name
	call ascout
	move a,[ascnt "-->"]	; plus prompt
	call ascout
	call td.frc		; Force everything to happen
	call tyofrc

	call tbinw		; Get next char (wait for it!)
	camn a,cmdchr		; command character?
	 jrst [	call tyiput	; yes, send it through
		jrst askcm9]	; and return.
	cain a,"?		; Special help command?
	 jrst [	skipn scrmng	; Yes, if screen not already munged,
		 call savscr	; then save screen image.
		setom scrmng	; Say screen image being munged
		call shohlp	; Show help for commands
		jrst askcm2]	; and go get another command!

	cail a,"a		; Convert lowercase to uppercase
	 caile a,"z
	  caia
	   subi a,40		; yes, convert to uppercase
	movsi c,-ncmds
askcm4:	hlrz b,cmdtab(c)	; Get a command char
	cain a,(b)
	 jrst askcm5		; Found command in table, go do it.
	addi c,1		; Table entries are 2 wds long.
	aobjn c,askcm4
	skipe entact		; does this terminal have some ops of it's own?
	 call @entact		;   yes, check them out
	  jrst [call unknwn	;     not one of them, either
		jrst askcm2]	; Ask again after pause.
	jrst askcm9		; one of them, we won!
askcm5:	move b,cmdtab(c)	; Get command table entry
	call (b)		; Execute it.

	; Come here when done with command(s).
askcm9:	skipe scrmng
	 call [	call resscr		; Sigh!  Restore screen.
		pjrst redisp]		; and redisplay it.
	move nv,svmax
	call resl
	popae p,[d,c,b,a,nv,nh]
	call td.frc
	call tyofrc
	pjrst rrcv


define cmd char,rtn,&help&	; Command macro, simple for now.
	<char>,,rtn
ifsn [help][]	[asciz help]	; 0 if no help string.
.else	0
termin

; CRTSTY runtime command table

cmdtab:	cmd "?,shohlp,	"?  - Show commands"
	cmd "Q,quit,	"Q  - Quit (cannot continue)"
IFN TNX,cmd ^C,proced,	"^C - Return to superior (can continue)"
IFN ITS,cmd ^Z,proced,	"^Z - Return to superior (can continue)"
IFN TNX,cmd "P,pushex,	"P - Push to inferior EXEC"
IFN TNX,cmd "E,pushex,	"E -   ditto"
	cmd "D,scrdmp,	"D - Dump screen image to file"
IFN STY,cmd "W,whoout,	"W - Start up a WHO-line"
	cmd "I,reinit,	"I - Initialize terminal"
	cmd "R,redisp,	"R - Redisplay screen"
	cmd ^L,redisp
	cmd "F,feeptg,	"F - Toggle feep-mode"
	cmd "H,sndhlp,	"H - Send HELP char (TOP-H)"
	cmd "B,sndbrk,	"B - Send BREAK char (TOP-B)"
	cmd "C,entctl,	"C - Controlify next char"
	cmd "M,entmta,	"M - Metize next char"
	cmd 0,apopj,	"<cmd char> - send command escape character"
	cmd ^M,apopj,	"CR,DEL - no action"
	cmd 177,apopj
ncmds==<.-cmdtab>/2

shohlp:	setzb nv,nh		; Home up
	call td.eol
	move a,[ascnt "CRTSTY runtime commands:"]
	call ascout
	setz nh, ? addi nv,1	; Move to next line
	movsi c,-ncmds
shohl2:	skipn a,cmdtab+1(c)	; Get addr of help text
	 jrst shohl3
	call td.eol
	call aszout		; Output ASCIZ string
	setz nh,
	addi nv,1		; Move to next line.
shohl3:	addi c,1
	aobjn c,shohl2
	ret

;	* - Possibly other misc chars defined by term support code.
; Should be added for NET (SUPDUP) mode:
;	C - Close connection (also D?  Same as Q.)
;	L - Logout remote job (also K?)

unknwn:	move a,[ascnt |Huh?  Type "?" for help.|]
unknw0:	call ascout		; Output string from above or elsewhere
forslp:	call td.frc		; Force everything to happen
sleep1:	call tyofin
	sleep 10.		; let user see message for at least one second
	return

sndhlp:	call td.cho		; Echo the H
	movei a,%txtop+"H	; [HELP] character
	pjrst tyiput		; send it out, and return

sndbrk:	call td.cho		; Echo the B
	movei a,%txtop+"B	; [BREAK] character
	pjrst tyiput		; send it out, and return

entmta:	move a,[ascnt "Meta-"]
	call entch2
	tro a,%txmta
	call tyiput
	pjrst forslp

entctl:	move a,[ascnt "Cntl-"]
	call entch2
	andi a,37		; make a control char out of it
; Note, maybe map to 60 octal onward and set %txctl?
	call tyiput		; send onward to host
	jrst forslp		; let user see it 1 sec, then resume.

entch2:	call ascout		; send the message to the screen
	call td.frc		; Force everything to happen
	call tyofrc
	call tbinw		; Get char to controllify (wait for it!)
	call td.cho		; echo it to screen
	return

feeptg:
IFN TINT&SINT,{
	move a,ttyvec
	caie a,ttyinf		; already feeping?
	 jrst [	call fpset	; No, turn on.
		move a,[ascnt "Feep-mode on!"]
		jrst unknw0]	; tell him it's on
	call fprset		; Yes, turn off.
} ; IFN TINT&SINT
	move a,[ascnt "Feep-mode off!"]
	jrst unknw0		; tell him it's off


; SCRDMP - put copy of screen image in file.
scrdmp:	skipe scrmng		; If screen was munged, gotta restore first.
	 jrst [	call resscr	; Sigh!  Restore screen.
		setzm scrmng
		call redisp	; and redisplay it (choke!)
		jrst .+1]
	movei nh,0		; return to the beginning of the line
	call td.eol
ifn its,move a,[ascnt "Dumping screen to .TEMP.;<uname> SCREEN"]
ifn tnx,move a,[ascnt "Dumping screen to SCREEN.TEMP"]
	call ascout		; send the message to the screen
	call td.frc		; Force everything to happen
	call tyofrc
IFN ITS,{
	push p,@time		; save current time
	$call OPEN,[#dsko,['DSK,,0],uname,['SCREEN],['.TEMP.]][][#.uao\100000]
	 jrst [	$call OPEN,[#dsko,['DSK,,0],uname,['SCREEN],['.TEMP.]][][#.uao]
	         jrst [	move a,[ascnt " -- Can't open dump file"]
			jrst unknw0]	;  So output it and wait for him to see
		jrst sd1]	;   So hack the file from the start
	$call FILLEN,[#dsko][a]	; Find the end of the file
	 .lose %lsfil
	.access dsko,a		; Go to the end of the file
	.iot dsko,[^L]		; Separate screens with FF
sd1:	movei nv,0
sd2:	move nh,shmax
	movei t1,blchar
sd3:	camn t1,@scrntb(nv)
	 sojge nh,sd3
	hrrz a,scrntb(nv)
	hrli a,444400
	movei b,1(nh)
	$call SIOT,[#dsko,a,b]	; send the characters
	 .lose %lsfil
	.iot dsko,[^M]		; Terpri
	.iot dsko,[^J]
	addi nv,1
	camge nv,svmax
	 jrst sd2

; Output all but last line.  Last line can be found in OLDL.
	move a,[440700,,oldl]	; And send that last line out to the file
	move b,oldll
	$call siot,[#dsko,a,b]
	 .lose %lsfil
	.iot dsko,[^M]		; Terpri to finish it off
	.iot dsko,[^J]
	.close dsko,		; yes, finish up
	pop p,a			; get time message was output
	addi a,30.		; add 1 second
	movn a,a
	.sleep a,		; sleep until then
	return
} ; IFN ITS
IFN TNX,{
	movsi a,(gj%fou\gj%new\gj%sht\gj%acc)
	hrroi b,[asciz "SCREEN.TEMP"]
	gtjfn
	 jrst sd4
	move b,[7._30.\of%wr\of%rtd]
	openf
	 jrst sd4
sd1:	movei nv,0
sd2:	move nh,shmax
	movei t1,blchar
sd3:	camn t1,@scrntb(nv)
	 sojge nh,sd3
	hrrz b,scrntb(nv)
	hrli b,444400
	movni c,1(nh)
	skipge c
	 sout
	movei b,^M
	bout
	movei b,^J
	bout
	addi nv,1
	camge nv,svmax
	 jrst sd2

	;; Output all but last line.  Last line can be found in OLDL.
	hrroi b,oldl
	movn c,oldll
	skipge c
	 sout

	;; TERPRI to finish it off
	movei b,^M
	bout
	movei b,^J
	bout
	closf			; yes, finish up
	sleep 10.
	return
sd4:	move a,[ascnt " -- Can't open dump file"]
	jrst unknw0
} ; IFN TNX


IFN TNX,{
; PUSHEX - Push to EXEC (command interpreter)
mvar exefrk			; EXEC fork handle
pushex:	move a,[ascnt "Push to Exec"]
	call ascout
	pushae p,[nv,nh]	; save cursor position
	call fini		; clean up
	call stop		; prepare to stop
	pushae p,[a,b,c]	; save ACs
IFE TINT\SINT,{			; If we're using inferior fork process,
	movei a,.fhslf		; disable inferior fork
	movx b,1_<35.-.icift>	; termination interrupt!!!
	dic
}
	skiple a,exefrk		; been here before?
	 jrst pushe1		; yes, just start it up
	movsi a,(gj%old\gj%sht)	; find EXEC
ifn 20x,	hrroi b,[asciz "SYSTEM:EXEC.EXE"]
ifn 10x,	hrroi b,[asciz "<SYSTEM>EXEC.SAV"]
	gtjfn
	 jerr1 [asciz "Unable to assign EXEC jfn - "]
	push p,a		; save jfn
	movsi a,(cr%cap)	; (this may be a mistake)
	cfork			; create inferior fork
	 jerr1 [asciz "Unable to create EXEC fork - "]
	movem a,exefrk		; save fork handle
	rpcap			; read capabilities
	tlz b,(sc%log)		; make sure EXEC can't
	tlz c,(sc%log)		; log out!
	epcap			; enable capabilities
	exch a,(p)		; retrieve jfn
	hrl a,(p)		; fork handle in left half
	get			; load EXEC into inferior fork
	pop p,a			; retrieve fork handle
pushe1:	movei b,0		; start at primary start address
	sfrkv
	rfork
	wfork			; wait for termination
IFE TINT\SINT,{			; If using inferior fork process,
	movei a,.fhslf		; reactivate inferior
	movx b,1_<35.-.icift>	; fork interrupt
	aic
}
	popae p,[c,b,a]		; restore ACs
	call resume		; undo STOP
	call redis0		; redisplay
	call reswin		; restore window
	popae p,[nh,nv]		; restore cursor position
	return
} ; IFN 20X


mvar oldl(<maxhor+4>/5)		; old line
mvar oldll			; old last line length


; SAVL - Save line.  Clobbers NH.
savl:	push p,a		; save AC
	movei nh,0
	setom oldll		; just in case whole line is blank
	move a,[440700,,oldl]
sl1:	move t1,@scrntb(nv)
	idpb t1,a
	caie t1,blchar
	 movem nh,oldll
	camge nh,shmax
	 aoja nh,sl1
	aos oldll
	pop p,a			; restore AC
	return


; Restore line.  Clobbers NH.
resl:	pushae p,[a,b,c]	; save ACs
	movei nh,0
	call td.eol
	move b,[440700,,oldl]
	move c,oldll
	jumpe c,rl2
rl1:	ildb a,b		; get a character
	call td.cho		; output it
	sojg c,rl1
rl2:	popae p,[c,b,a]		; restore ACs
	return



aszout:	hrli a,440700
bpzout:	push p,b
	skipa b,a
aszou2:	 call td.cho
	ildb a,b		; Get a char
	jumpn a,aszou2		; Output it if not zero
	pop p,b
	ret

ascout:	push p,b
	hlrz b,a
	hrli a,440700
	push p,a
asc1:	ildb a,(p)		; get a char
	call td.cho		; send it
	sojg b,asc1		; if more chars, send get another
	popae p,[a,b]
	return

; SAVSCR - Save screen image in secondary buffer.

savscr:	pushae p,[a,b]
	move a,[screen,,scren2]
	movei b,scren2
	add b,scrlen		; Add # of wds to move
	blt a,-1(b)		; Store copy!
	popae p,[b,a]
	ret

; RESSCR - Restore screen image from secondary buffer.

resscr:	push p,a
	move a,[scren2,,screen]
	blt a,@scrlst
	pop p,a
	ret

subttl	ITS virtual terminal (Software-TTY) simulation

; Like all simulation code, this consists of both a SMO and SMI module.
; Unlike most other terminal simulation modules, however, this one is
; relatively simple because a Software TTY is almost the same thing as
; CRTSTY's internal "virtual terminal".  Thus these routines are good
; skeletal examples of how a SMO/SMI simulation can be written.

; SWSMI - SMI module for Software-TTY simulation.
; Argument:
;   A	Character with %TX bits.

swsmi:	call smiget		; Get character from TYI (input support)
IFE ITS&STY,{
	trne a,%txtop\%txmta\%txctl
	 jrst [	push p,a	; save character
		movei a,^\	; SMIBOUT arg: A = character
		call smibout
		move a,(p)
		lsh a,-7
		addi a,100
		call smibout
		pop p,a
		andi a,%txasc
		call smibout
		jrst swsmi
		]
} ; IFE ITS&STY
	call smibout		; output to STY
	caie a,^\		; ^\?
	 jrst swsmi		; no, that's it
	skipl tpcbs		; NO TPCBS specified?
	 call smibout		; no, output another ^\ to get one through
	jrst swsmi


; ITS software TTY codes are defined in SYSTEM;BITS > (search for "%TD"
; twice).  Complete page they appear on also contains all definitions
; for the full input buffer bits.


; SWSMO - SMO module for Software-TTY simulation.

swsmo:	smobin a,		; Get character into A (STY/NET input)
IFN NCP\TCP,{
	skipe supres		; If suppressing til see an "output reset"
	 jrst [	cain a,%tdors	; Then check for one.
		 call tdors	; Got one, handle it.
		jrst swsmo]	; Then back for more input.
}
	push p,[swsmo]		; Simulate PUSHJ for easy return to beg of loop
	caig a,200		; software-TTY code?
	 pjrst td.cho		; no, ordinary spacing character
	caige a,%tdmax+1	; Too big? (+1 for windowing hack)
	 pjrst @sftcod-200(a)	; Internal ITS software-TTY code! Dispatch.
	pjrst unused


; SWSMF - SMO module Force routine for Software-TTY simulation.

swsmf:	call td.frc		; force CLEOL and cursor movement
	pjrst tyofrc		; and finally make sure all output goes out.


; Dispatch table for %TD codes, used by SWSMO.
sftcod:	offset 200-sftcod
%tdmov:: tdmov	; 200 %TDMOV - Move cursor
%tdmv1:: unused	; 201 %TDMV1 - Dummy, shouldn't be seen.
%tdeof:: td.eof	; 202 %TDEOF - Erase to end of page
%tdeol:: td.eol	; 203 %TDEOL - Erase to end of line
%tddlf:: td.dlf	; 204 %TDDLF - Delete forward
%tdmtf:: unused	; 205 %TDMTF - Motor off (terminets only)
%tdmtn:: unused	; 206 %TDMTN - Motor on  (  " " )
%tdcrl:: tdcrl	; 207 %TDCRL - CRLF and CLEOL (see note below)
%tdnop:: tdnop	; 210 %TDNOP - Noop for SuperDuperImage
%tdbs::	 unused	; 211 %TDBS  - Backspace, only on TTY's with %TORAW set.
%tdlf::	 unused	; 212 %TDLF  - Linefeed,   (   "   )
%tdrcr:: unused	; 213 %TDRCR - CR,         (   "   )
%tdors:: tdors	; 214 %TDORS - Output Reset.  Seen when TTY output reset done.
%tdqot:: tdqot	; 215 %TDQOT - Device dependent data in next byte (quoted)
%tdfs::	 tdfs	; 216 %TDFS  - Move cursor forward one space
%tdmv0:: tdmv0	; 217 %TDMV0 - Replacement for %TDMOV, illegal if %TORAW.
%tdclr:: td.clr	; 220 %TDCLR - Home and Clear the screen
%tdbel:: td.bel	; 221 %TDBEL - Ding the bell
%tdini:: unused	; 222 %TDINI - System just came up, reinit intelligent term
%tdilp:: tdilp	; 223 %TDILP - Insert Line-Position. Followed by count
%tddlp:: tddlp	; 224 %TDDLP - Delete Line-Position. Followed by count
%tdicp:: tdicp	; 225 %TDICP - Insert Char-Position. Followed by count
%tddcp:: tddcp	; 226 %TDDCP - Delete Char-Position. Followed by count
%tdbow:: td.bow	; 227 %TDBOW - Enter Black-on-White mode (inverse video)
%tdrst:: td.rst	; 230 %TDRST - Reset mode. Deselect all special modes (eg BOW)
%tdgrf:: unused	; 231 %TDGRF - Enter graphics mode.
%tdrsu:: tdrsu	; 232 %TDRSU - Region scroll up.
%tdrsd:: tdrsd	; 233 %TDRSD - Region scroll down.
	 unused	; 234 "Next 4 codes are used for some weird form of
	 unused	; 235  graphics output that will eventually be flushed"
	 unused	; 236      -TS3TTY
	 unused ; 237
;; following are for local editing terminals.  How does this affect
;; CRTSTY? -CBF
%tdsyn:: unused	; 240 Resynch reply to local editing terminal.  Ignore 1 arg
%tdeco:: unused	; 241 Ask terminal to try local editing by sending a
		; resynch. Ignore.
%tdedf:: unused	; 242 Set local editing terminal command definition.
		; Ignore 2 args.
%tdnle:: unused	; 243 Stop doing local editing.  Ignore.
%tdtsp:: unused	; 244 Displays like space, but is part of tab.  Ignore.
		; Shouldn't happen?
%tdctb:: unused	; 245 This line is continued at the beginning.
%tdcte:: unused	; 246 This line is continued at the end.
%tdmlt:: unused	; 247 Declare multi-position char for local editing.
		; Ignore 2 args.
%tdsvl:: unused	; 250 Save line contents.  Ignore 3 args.
%tdrsl:: unused	; 251 Restore line contents. Ignore 3 args.
%tdssr:: unused	; 252 Set range of columns to save.  Ignore 2 args.
%tdsll:: unused	; 253 Set label for local line saving.  Ignore 2 args.

%tdmax::
	offset 0
	tdwin	; xxx %TDWIN - Set window.


; UNUSED - Error, saw a software TTY code we shouldn't have?
; Handling here isn't so good, can be improved with command line.
unused:	call td.bel		; ring bell and call to attention of luser
	movei a,-100(a)		; map into ascii range of alpha 200=@
	skipn .txso+tb
	 pjrst td.cho		; if no standout routine, just output
	pjrst chstdo


; %TDNOP - No Operation.
tdnop:	return			; no operation


; %TDMOV - Move cursor (old, 4 bytes).
tdmov:	smobin a,		; Throw away the position estimate
	smobin a,		; ...

; %TDMV0 - Move cursor (new, 2 bytes).
tdmv0:	smobin a,		; get new vertical position
	push p,a		; save (SMOBIN may clobber ACs)
	smobin b,		; and new horizontal position
	pop p,a			; restore new vertical
	pjrst td.mov


; %TDFS - Move cursor Forward
tdfs:	camge nh,whmax		; last column?
	 addi nh,1		; no, increment horizontal position
	return


; %TDCRL - Move to Next Line and clear it.
; If on screen bottom, receipt of this code means ITS wants screen
; to scroll up.
tdcrl:	move nh,whmin		; do CR part of CRLF
	movei a,1		; TD.SU arg: no. of lines to scroll
	caml nv,wvmax		; last line of current window?
	 pjrst td.su		; yes, LF part of CRLF means scroll up
	aoja nv,td.eol		; do LF part of CRLF
				; and goto clear to end of line routine


; %TDILP - Insert Line Position.
tdilp:	smobin a,		; get count in A
	pjrst td.ilp


; %TDDLP - Delete Line Position.
tddlp:	push p,wvmax		; save last line no. of window
	smobin a,		; get count in A
	push p,a		; save count
	call styip		; peek at next byte
	caie a,%tdmv0		; move?
	 jrst [	pop p,a			; TD.DLP arg: count
		pop p,t1		; pop off WVMAX
		pjrst td.dlp ]		; execute the %TDDLP

	smobin a,		; get %TDMV0
	smobin a,		; get new vertical
	add a,wvmin		; ...
	push p,a		; save
	smobin a,		; get new horizontal
	add a,whmin		; ...
	push p,a		; save
	call styip		; peek at next byte
	caie a,%tdilp		; insert line?
	 jrst xdlp4		; no
	pop p,a			; flush H-pos from stack
	smobin a,		; get %TDILP
	smobin a,		; get insert count
	came a,-1(p)		; equal to delete count?
	 jrst xdlp3		; no
	dmove a,wmin		; TD.WIN args: minimum vertical, minimum
				; horizontal
	move d,whmax		; TD.WIN arg: maximum horizontal
	caml nv,(p)		; insert above or below delete?
	 jrst xdlp1		; below

	; delete line above insert line - delete line in window
	pop p,c			; get Y-position of insert
	add c,(p)		; add count and
	subi c,1		; subtract one to get last line to move
	call td.win		; set window
	pop p,a			; get count
	call td.dlp		; delete n lines in window
	move nv,wvmax		; leave cursor where %TDILP was done
	subi nv,-1(a)		; ...
	jrst xdlp2		; cleanup

	; delete line below insert line - insert line in window
xdlp1:	move c,nv		; get line no. of delete
	pop p,nv		; move to position of insert
	add c,(p)		; add count to line no. of delete and
	subi c,1		; subtract 1 to get last line of window
	call td.win		; set window
	pop p,a			; TD.ILP arg: count
	call td.ilp		; insert lines in window
xdlp2:	dmove a,wmin		; TD.WIN arg: minimum vertical, minimum
				; horizontal
	pop p,c			; TD.WIN arg: maximum vertical
	move d,whmax		; TD.WIN arg: maximum horizontal
	pjrst td.win		; set window to what it used to be
xdlp3:	exch a,-1(p)		; exchange insert and delete counts
	call td.dlp		; execute the delete line request
	pop p,nv		; execute the %TDMV0
	pop p,a			; TD.ILP arg: count
	pop p,t1		; pop off WVMAX
	pjrst td.ilp		; execute the %TDILP
xdlp4:	move a,-2(p)		; TD.DLP arg: count
	call td.dlp		; execute the %TDDLP
	pop p,nh		; execute the %TDMV0
	pop p,nv		; ...
	sub p,[2,,2]		; pop off count, WVMAX
	return


; %TDICP - Insert Character Position.
tdicp:	push p,[0]
tdicpl:	smobin a,		; get count in A
	addm a,(p)		; add to count so far
	call styip		; peek at next character
	cain a,%tdicp		; %TDICP?
	 jrst [	smobin a,	; yes, read it
		jrst tdicpl ]	; and go back for count
	caige a,200
	 jrst [	pop p,a
		caie a,1
		 pjrst td.icp
		smobin a,
		pjrst td.ic ]
	pop p,a			; get final count
	pjrst td.icp


; %TDDCP - Delete Character Position.
tddcp:	push p,[0]
tddcpl:	smobin a,		; get count in A
	addm a,(p)		; add to count so far
	call styip		; peek at next character
	cain a,%tddcp		; %TDDCP?
	 jrst [	smobin a,	; yes, read it
		jrst tddcpl ]	; and go back for count
	pop p,a			; get final count
	pjrst td.dcp


; %TDORS - Output Reset.  Tell ITS where cursor should be.
; Unfortunately this needs %TPCBS set to win (losing ITS).
; Note that the Input-Stream process is invoked if a cursor-position
; response is sent.
IFN ITS&STY,{
tdors:	movei a,(nv)
	sub a,wvmin
	movei b,(nh)
	sub b,whmin
	$call scpos,[#pyo,a,b,[-1]]
	 .lose %lsfil
	return
} ; IFN ITS&STY
.ELSE {
tdors:
IFN NCP\TCP,{
	sosg inscnt
	 setzm supres
}
	; Must send a cursor-position response.  Since we are
	; in the Output-Stream process, we must invoke IPSCAL
	; to safely run in the Input-Stream context.
	movei b,(nv)
	sub b,wvmin
	movei a,(nh)
	sub a,whmin
	hrli a,(b)	; Set up <v,,h>
	movei b,sndpos
	call ipscal	; Invoke SNDORS within Input-Stream process.
	ret

	; Send response to %TDORS - current cursor position.
sndpos:	push p,a
	movei a,^\
	call smibout
	movei a,^P
	call smibout
	hlrz a,(p)	; Get V
	call smibout
	hrrz a,(p)	; Get H
	call smibout
	call smifrc	; Force out
	pop p,a
	ret
} ; IFE ITS&STY


; %TDQOT - Quote device-dependent data in next byte.
; Just have to hope program knows what it's doing.
tdqot:	smobin a,		; get next byte
	pjrst td.qot


; %TDRSU region count - Region scroll up.
tdrsu:	smobin b,		; TD.RSU arg: B = no. of lines in region
	push p,b
	smobin a,		; TD.RSU arg: A = scroll count
	pop p,b
	pjrst td.rsu


; %TDRSD region count - Region scroll down.
tdrsd:	smobin b,		; TD.RSD arg: B = no. of lines in region
	push p,b
	smobin a,		; TD.RSD arg: A = scroll count
	pop p,b
	pjrst td.rsd


; %TDWIN - Set window.
tdwin:	smobin a,
	push p,a
	smobin b,
	push p,b
	smobin c,
	push p,c
	smobin d,
	pop p,c
	pop p,b
	pop p,a
	pjrst td.win

subttl	Raw TTY simulation

; RWSMI - SMI loop for Raw TTY

rwsmi:	call smiget		; Get char from input support
	call smibout		; Output it.
	jrst rwsmi

; RWSMO - SMO loop for Raw TTY

rwsmo:	smobin a,		; Get char
	tyo (a)			; Output (don't even hack screen image)
	jrst rwsmo

; RWSMF - SMO finalization for Raw TTY
rwsmf:	pjrst tyofrc		; Force out buffered output.


subttl	NVT simulation

IFN NET,{	; NVT not needed unless hacking network.

; NVTSMI - SMI loop for Network Virtual TTY

nvtsmi:	call smiget		; Get char from input support
	call smibout		; Output it.
	jrst nvtsmi

; NVTSMF - SMO finalization for Network Virtual TTY
nvtsmf:	call td.frc
	pjrst tyofrc		; Force out buffered output.

; NVTSMO - SMO loop for Network Virtual TTY

nvtsmo:	smobin a,		; Get char
	push p,[nvtsmo]		; Make RETURNs come back.
	cail a,200
	 jrst nvsmo2		; High bit set, jump out.
	caige a,40
	 jrst nvsmo3		; Control char
	caie a,177		; Ignore rubout
	 call td.cho		; Output printing char
	ret

nvsmo2:	cain a,IAC		; Only IACs understood if high bit set
	 call stlprc		; Process IAC escape
	ret

nvsmo3:
	; NULL, LF, and CR have specified meanings for NVT printer.
	cain a,			; Null - no-op
	 ret
	cain a,^J
	 pjrst vtlf
	cain a,^M
	 pjrst vtcr
	; Following codes have defined (but not required) meanings.
	cain a,^G		; Bell
	 pjrst td.bel
	cain a,^H
	 pjrst vtbs
	cain a,^I
	 pjrst vttab
	cain a,^K		; Vertical tab ignored for now
	 ret
	cain a,^L		; Formfeed ignored for now
	 ret
	ret			; All other codes are no-ops!
} ;IFN NET

subttl	VT52 Simulation

; VTSMI - STY output co-routine loop for VT52 simulation.

vtsmi:	call smiget		; get character from input support
	call smibout		; output to STY
	jrst vtsmi


; VTSMF - VT52 simulation force routine.
vtsmf:	call td.frc		; force CLEOL and cursor movement
	pjrst tyofrc		; and finally make sure all output goes out.


; VTSMO -  Main loop of VT52 simulation.  Handles STY input.
vtsmo:	smobin a,		; get character into A
	push p,[vtsmo]		; Put return addr on stack
IFN NET,{
	cail a,200		; If hacking net and get high bit,
	 jrst nvsmo2		; go check for IAC and handle if so.
}
.ELSE	andi a,177
	caige a,40
	 pjrst @vtctl(a)
	caie a,177
	 pjrst td.cho
	ret		; Back to start of loop

vtctl:	apopj			; ^@ - ignored
	apopj			; ^A - ignored
	apopj			; ^B - ignored
	apopj			; ^C - ignored
	apopj			; ^D - ignored
	apopj			; ^E - ignored
	apopj			; ^F - ignored
	td.bel			; ^G - ring bell
	vtbs			; ^H - backspace
	vttab			; ^I - tab
	vtlf			; ^J - linefeed
	apopj			; ^K - ignored
	apopj			; ^L - ignored
	vtcr			; ^M - carriage return
	apopj			; ^N - ignored
	apopj			; ^O - ignored
	apopj			; ^P - ignored
	apopj			; ^Q - ignored
	apopj			; ^R - ignored
	apopj			; ^S - ignored
	apopj			; ^T - ignored
	apopj			; ^U - ignored
	apopj			; ^V - ignored
	apopj			; ^W - ignored
	apopj			; ^X - ignored
	apopj			; ^Y - ignored
	apopj			; ^Z - ignored
	vt.esc			; ^[ - escape
	apopj			; ^\ - ignored
	apopj			; ^] - ignored
	apopj			; ^^ - ignored
	apopj			; ^_ - ignored

vtbs:	camle nh,whmin
	 subi nh,1
	ret

vttab:	addi nh,10
	trz nh,7
	camle nh,whmax
	 move nh,whmax
	ret

vtlf:	camge nv,wvmax
	 aoja nv,apopj
	movei a,1
	pjrst td.su

vtcr:	move nh,whmin
	ret

vt.esc:	smobin a,
	cail a,"A
	 caile a,"Z
	  ret
	pjrst @vtesct-"A(a)

vtesct:	vtup			; ESC A - up
	vtdown			; ESC B - down
	vtrght			; ESC C - right
	vtbs			; ESC D - left
	apopj			; ESC E - ignored
	apopj			; ESC F - ignored
	apopj			; ESC G - ignored
	vthome			; ESC H - home
	vtsd			; ESC I - scroll down
	td.eof			; ESC J - erase to end of screen
	td.eol			; ESC K - erase to end of line
	vtilp			; ESC L - insert 1 line
	vtdlp			; ESC M - delete 1 line
	apopj			; ESC N - ignored
	apopj			; ESC O - ignored (H19: exit insert mode)
	apopj			; ESC P - ignored (T1061: insert 1 space)
				;		  (HP26XX: delete 1 char)
	apopj			; ESC Q - ignored (T1061: delete 1 char)
				;		  (HP26XX: enter insert mode)
	apopj			; ESC R - ignored (HP26XX: exit insert mode)
	apopj			; ESC S - ignored
	apopj			; ESC T - ignored
	apopj			; ESC U - ignored
	apopj			; ESC V - ignored
	apopj			; ESC W - ignored
	apopj			; ESC X - ignored
	vtpos			; ESC Y - direct cursor positioning
	apopj			; ESC Z - ignored


vtup:	camle nv,wvmin
	 subi nv,1
	ret

vtdown:	camge nv,wvmax
	 addi nv,1
	ret

vtrght:	camge nh,whmax
	 addi nh,1
	ret

vthome:	dmove nvh,wmin
	ret

vtsd:	movei a,1
	pjrst td.sd
	

vtilp:	push p,[1]		; start with repeat count of 1
vtilp1:	call styip		; peek at next character
	jumpe a,vtilp4		; if NUL then ignore it
	caie a,33		; ESC?
	 jrst vtilp2		; no, go do insert line
	smobin a,		; read ESC
	call styip		; peek at next character
	caie a,"L		; L?
	 jrst vtilp3		; no, go do insert line and then hack ESC
	smobin a,		; read L
	aos (p)			; increment repeat count
	jrst vtilp1		; go peek so more
vtilp2:	pop p,a			; TD.ILP arg: A = count
	call td.ilp		; insert n lines
	ret
vtilp3:	pop p,a			; TD.ILP arg: A = count
	call td.ilp		; insert n lines
	jrst vt.esc
vtilp4:	smobin a,		; read NUL
	jrst vtilp1		; go back for more

vtdlp:	push p,[1]		; start with repeat count of 1
vtdlp1:	call styip		; peek at next character
	jumpe a,vtdlp4		; if NUL then ignore it
	caie a,33		; ESC?
	 jrst vtdlp2		; no, go do delete line
	smobin a,		; read ESC
	call styip		; peek at next character
	caie a,"M		; M?
	 jrst vtdlp3		; no, go do delete line and then hack ESC
	smobin a,		; read M
	aos (p)			; increment repeat count
	jrst vtdlp1		; go peek so more
vtdlp2:	pop p,a			; TD.DLP arg: A = count
	call td.dlp		; delete n lines
	ret
vtdlp3:	pop p,a			; TD.DLP arg: A = count
	call td.dlp		; delete n lines
	jrst vt.esc
vtdlp4:	smobin a,		; read NUL
	jrst vtdlp1		; go back for more

vtpos:	smobin a,		; get vertical position + 40
	push p,a
	smobin b,		; get horizontal position + 40
	pop p,a
	movei a,-40(a)		; TD.MOV arg: A = vertical position
	camg a,wvmax		; if position out of range,
	 jrst .+3
	  movei a,(nv)		; then it remains unchanged
	  sub a,wvmin		; ...
	movei b,-40(b)		; TD.MOV arg: B = horizontal position
	call td.mov		; move cursor
	ret

subttl	Part IV - Support
subttl	Random terminal support routines - Input

; STYI - Standard TR.TYI co-routine loop; gets character via TYIBIN and
; puts character via TYIPUC.  Does no processing at all on TTY input
; characters, except for command-escape check.

styi:	call tyibin		; get character from TTY
	call tyipuc		; put char to STY (via SMI)
	jrst styi		; loop forever


; UNDEL - TR.TYI co-routine loop which exchanges delete and underscore.
; Should be used by any terminal that has delete as shift-underscore.

undel:	call tyibin
	caie a,177
	 cain a,137
	  xori a,137#177
	call tyipuc
	jrst undel


; BCKYCH - Set "bucky bits" in character as per F flags.
; TOP characters are aproximately corresponding to the correspondeces
; used on a knight keyboard.  Certain exceptions are made for the
; keyboard layout used in the VT52, such as the digits.  All alphabetics
; are the same, however.

bckych:	tlze f,%imeta
	 tro a,%txmta
	tlze f,%itop
	  call bcktop		   ; topify
	tlze f,%ictrl
	 tro a,%txctl
	return

bcktop:	cail a,140		   ; uppercasify, like TV would
	 subi a,40
	caige a,40		   ; controls we just top-ify
	 jrst [	tro a,%txtop
		return ]
	push p,b
	subi a,40		   ; offset is from space
	idivi a,5		   ; index into toptab
	ldb a,topbpt(b)
	pop p,b
	tro a,%txtop
	return

;; Table of TOP characters for each alphabetic.  These correspond
;; to the TOP-ifing of characters on a Knight keyboard, and
;; make no sence at all.  Certain non-alphabetics are modified to
;; correspond with the VT52 keyboard instead of the knight.  digits,
;; for example.
;; in format of 7-bit bytes, indexed as offset from space

topbpt:  350700,,toptab(a)	   ; BP's into toptab
	 260700,,toptab(a)
	 170700,,toptab(a)
	 100700,,toptab(a)
	 010700,,toptab(a)
toptab:
.byte 7
repeat 14,37+.rpcnt		   ; space through + are just top of selves
74				   ; , -- top-<
75				   ; - -- top-=
76				   ; . -- top->
77				   ; / -- top-?
51				   ; 0 -- top-)
41				   ; 1 -- top-!
100				   ; 2 -- top-@
43				   ; 3 -- top-#
44				   ; 4 -- top-$
45				   ; 5 -- top-%
136				   ; 6 -- top-^
46				   ; 7 -- top-&
52				   ; 8 -- top-*
50				   ; 9 -- top-(
73				   ; : -- top-;
73				   ; ; -- top-;
74				   ; < -- top-<
75				   ; = -- top-=
76				   ; > -- top->
77				   ; ? -- top-?
140				   ; @ -- top-`
34				   ; A -- less than or equal to
7				   ; B --PI
3				   ; C -- Epsilon
36				   ; D -- triple-bar (identically equal)
22				   ; E -- intersection
17				   ; F -- I duno what it's called.
32				   ; G -- Not equal to.
110				   ; H -- [HELP]
26				   ; I -- circle-with-X
30				   ; J -- Back-arrow
31				   ; K -- Forward arrow
27				   ; L -- back-forward double-arrow
25				   ; M -- Existential quantifier
24				   ; N -- Universal quantifier
1				   ; O -- down arrow
13				   ; P -- up arrow
4				   ; Q -- conjunction
23				   ; R -- union
35				   ; S -- greater or equal
20				   ; T -- is a subset of
5				   ; U -- not
10				   ; V -- lambda
37				   ; W -- disjunction
3				   ; X -- Beta
21				   ; Y - is a superset of
2				   ; Z -- Alpha
.byte

subttl	Random terminal support routines - Output

; SCHO0 - SCHO for insert character mode terminals.
scho0:	tlze f,%icm		; insert character mode on?
	 xct .telim+tb		; yes, turn it off

; SCHO - Default .TRCHO.  Display character.
; Argument:
;   A	Character.

scho:	cail a,40		; control character?
;	 cail a,177		; or rubout (or worse)?
	 trne a,-1#177		; Ensure no high bits set (but cant test 177)
	  return		; yes, ignore it
; SCHO1 - SCHO without control character test.  Several .TRCHO's JRST here.
scho1:	movem a,@scrtab(v)	; store character in screen image
	camge h,thmax		; in last column?
	 paoja h,@.trtyo+tb	; no, output character and advance one position
	pjrst @.trtyo+tb	; output character, cursor stays put


; CCHO0 - CCHO for terminals with insert character mode.
ccho0:	tlze f,%icm		; insert character mode on?
	 xct .telim+tb		; yes, turn it off

; CCHO - .TRCHO for terminals which CRLF after typing in the last column.
ccho:	cail a,40		; control character?
;	 cail a,177		; or rubout (or worse)?
	 trne a,-1#177		; Ensure no high bits set (but cant test 177)
	  return		; yes, ignore it
; CCHO1 - CCHO without control character test.  Several .TRCHO's JRST here.
ccho1:	caml h,thmax		; last column?
	 jrst ccho2		; yes
	movem a,@scrtab(v)	; store character in screen image
	paoja h,@.trtyo+tb	; output it, increment horizontal position
ccho2:	caml v,tvmax		; last line too?
	 return			; yes, ignore character completely
	movem a,@scrtab(v)	; store character in screen image
	move h,thmin		; output character and
	paoja v,@.trtyo+tb	; reflect CRLF in actual cursor position


; SIMVBL - Default TX.VBL.
simvbl:	movei a,"G		; Default visible-bell routine.
	skipe .txso+tb
	 pjrst chstdo		; output in standout mode.
	return

; Output char in "standout" mode if any.
chstdo:	call td.bow		; Enter standout mode
	call td.cho		; Output character in A
	call td.rst		; Leave mode
	return


; VTABS - VT52 style absolute move.
vtabs:	tyoesc "Y
	tyo 40(nv)
	tyo 40(nh)
	return


; CHLNCT - counts chars on line, on either side of cursor;
; A gets count of chars from beg of line to cursor,
; B gets count of chars from cursor to EOL. (incl cursor position)
chlnct:	push p,c
	push p,d
	movei d,blchar
	movn c,twidth
	hrlzs c
	hrr c,scrntb(nv)	; Now have AOBJN to start of line
	setzb a,b		; clear counts.
chlnc2:	caig h,(c)		; See if reached cursor pos yet
	 jrst chlnc3		; yes, jump to next loop.
	came d,(c)		; not yet. check this char
	 addi a,1		; increment cnt if found one
	aobjn c,chlnc2
	pop p,d
	pop p,c			; if cursor at EOL, oh well.
	return
chlnc3:	came d,(c)
	 addi b,1	; in this loop, count B = chars at & after cursor.
	aobjn c,chlnc3
	pop p,d
	pop p,c
	return


; SETTAB - used by a few terminals to set tab stops
; the caller is responsible for clearing the terminals tab stop before calling.
settab: pushae p,[a,b,nh,nv]
	setzb nh,nv		; home
	call td.mfrc		; ...
	move b,shmax		; calculate the no. of tabs to set
	lsh b,-3		; ...
setab1:	movei a,8.		; move to next multiple of 8
	tyn 40			; ...
	tyoesc "1		; and set a tabstop there
	addi h,(a)		; and update actual cursor pos.
	sojg b,setab1
	popae p,[nv,nh,b,a]
	return

subttl	Cursor movement

; MOVCUR - Default cursor movement subroutine.

movcur:	dmovem vh,savvh
	dmovem nvh,savnvh

	; Check requested position to be sure it's within limits.
	camge nh,whmin
	 jrst [	aos errhl	; Jump if horizontal is too small
		move nh,whmin	; Force to left edge
		jrst movc10
		]
	camle nh,whmax		; compare with hmax, skip if still OK
	 jrst [	aos errhg	; NH too big!
		move nh,whmax	; Force to right margin
		jrst movc10
		]
movc10:	camge nv,wvmin
	 jrst [	aos errvl	; Jump if vertical is too small
		move nv,wvmin	; force to top line
		jrst movc20
		]
	camle nv,wvmax		; See if about to go off bottom?
	 jrst [	aos errvg	; Ugh, too big!
		move nv,wvmax	; Force to bottom line
		jrst movc20
		]
movc20:	cain h,(nh)
	 caie v,(nv)
	  caia
	   return
	pushae p,[a,b,c,d,e]	; save ACs

	; Optimizer loop - try each cost-calculation routine
	; until find one returning cost of 1, or use
	; least-cost one upon finishing table.
	move cp,[-cpdlen,,cpdl-1]	; init cursor-motion pdl
	hrrzm cp,zxbeg		; store first entry as "best" - abs move.
	push cp,[1,,cc.abs]
	hrrzm cp,zxend
	xct .tcabs+tb		; set best cost to aboslute cursor positioning
	movem a,zbestc		; cost
	move z,.trzns+tb	; get AOBJN pointer to zone-table
movc30:	hrrzm cp,zxsav		; Store ptr to start of list for routine
	call @(z)		; Go execute...

	 jrst movc35		; failed to get better cost than zbestc.
	move b,zxsav
	movem b,zxbeg
	hrrzm cp,zxend		; aha, save end-ptr to execute list!
	caig c,1		; and if cost =1,
	 jrst movc40		; go execute immediately - can't get better.
	cail c,nutcst		; Make SURE that never hack missing functions.
	 jsr bughlt
	movem c,zbestc		; else store as new best-cost-found.
movc35:	aobjn z,movc30		; Loop thru all zone check rtns.
movc40:	aos cp,zxbeg		; done, now find ptr to xct list.
movc45:	move b,(cp)		; get an instr
	hlrz a,b		; get repeat count
	call (b)		; xct stuff at given location.
	camge cp,zxend		; and until reach end,
	 aoja cp,movc45		; proceed down list.

; Done, but let's make sure...
	cain h,(nh)
	 caie v,(nv)
	  jsr bughlt			; Argh, trying to sneak past, eh?
	popae p,[e,d,c,b,a]
	return


SECTION MAINVAR
savvh::
savv:	block 1
savh:	block 1
savnvh::
savnv:	block 1
savnh:	block 1

SECTION MAIN

; Count of various erroneous attempts to move cursor.
mvar errhl			; Horizontal too small
mvar errhg			; Horizontal too great
mvar errvl			; Vertical too small
mvar errvg			; Vertical too great

; Pointers into CPDL
mvar zxsav			; temp while collecting a path.
mvar zxbeg			; points to first instr in path to xct.
mvar zxend			; points to last instr in path to execute.
mvar zbestc			; Holds cost of best path so far.

; Cursor motion path stack.  Used for accumulating paths
; while checking/comparing them.
cpdlen==50
mvar cpdl(cpdlen)

subttl	Cursor Control routines

cc.abs:	xct .tmabs+tb
	dmove vh,nvh
	return

cc.ay:	xct .tmay+tb
	movei v,(nv)
	return

cc.ax:	xct .tmax+tb
	movei h,(nh)
	return

cc.hom:	xct .tmhom+tb
	dmove vh,tmin
	return

cc.up:	xct .tmup+tb
	subi v,(a)
	camge v,tvmin
	 add v,theight
	return

cc.dwn:	xct .tmdwn+tb
	addi v,(a)
	camle v,tvmax
	 sub v,theight
	return

cc.fwd:	movei b,(a)		; save repeat count
	xct .tcfwd+tb		; get move forward cost
	caile a,(b)		; terminal's move better than typing
				; characters already there?
	 jrst ccfwd1		; no, retype characters
	move a,b		; .TMFWD arg: repeat count
	xct .tmfwd+tb		; move forward
	addi h,(a)		; update cursor position
	camle h,thmax		; moved past right margin
	 xct .trnrm+tb		; yes, normalize
	return
ccfwd1:	move a,@scrtab(v)	; Must index by H,V
	call @.trcho+tb		; out it goes!
	sojg b,ccfwd1
	return

cc.lft:	xct .tmbck+tb
	subi h,(a)
	camge h,thmin
	 xct .trnrm+tb
	return

cc.cr:	xct .tmcr+tb
	move h,thmin
	return

cc.nl:	xct .tmnl+tb
	move h,thmin
	addi v,1
	return

cc.tab:	xct .tmtab+tb
	lsh h,-3
	add h,a
	lsh h,3
	return

subttl	Movement optimization - description & defaults

comment |
	The movement optimizer is based on the concept of "zones"; a zone,
generally speaking, is the area immediately surrounding the cursor which can
be reached simply by moving in various combinations of up, down, right, or 
left.  The "primary" zone is simply that around the actual cursor location;
there may be several "secondary" zones, which are centered around some point
that the cursor can reach in a single unusual movement - for example, HOME
and CR are unusual.  Anything which produces movement in two coordinates at
once, or an arbitrary amount in one direction, is "unusual" because the
zone-optimizer (which figures out the least-cost movement given a particular
zone) only handles specific units of independent X and Y motion.

	When the overall optimizer is called, it is pointed at a table of zones
to check (the default table is ZT1).  The first zone is the primary one,
and it finds the cost of moving when no "unusual" commands are used.  All
the others are secondary zones; what they do is start with the cost of
executing some unusual move, and then pretend that the cursor has actually
been moved there, calling the faked-out zone-optimizer to see what the
cost of moving is now with no further unusual commands.

	Each zone-test routine is required to accept in H,V the current
cursor position and in NH,NV the desired cursor position; on a successful
(skipping) return, it must return in A the cost (# of chars) of the particular
strategy it represents, which is returned on a stack pointed to by CP.
Each strategy consists of first an unusual move (except for the primary zone
of course), followed by any necessary regular movements to reach NH,NV.
All that the zone-test routine needs to do to specify some particular
commands is:
		PUSH CP,[<# times to xct>,,<rtn to xct>]
If the total cost proves lowest of all zones tested, the commands stored by
the winning zone will be executed in the order they were pushed on the CP
stack.  NOTE: it is not necessary to always specify a complete set of
commands; if the zone-test routine by some heuristic finds that its cost
will be no better than the best-so-far, it can return immediately, provided
that it fails to skip.  Any commands it stored will be ignored.

EXAMPLE:
	Note that ZTEST is the basic primary zone tester.  ZTHOM is a typical
secondary-zone tester; it stores on CP a command to do a home-up, finds
the cost of this unusual move, and updates the NH,NV coordinates so as to
fake out ZTEST, which it then calls via an entry point that preserves
the cost thus far.

CUSTOMIZING:
	To specify your very own zone table for a terminal, just put
an AOBJN pointer to it in the TR.ZNS declaration, e.g.
	TR.ZNS -foxzln,,foxzns
This allows you to specify more "unusual" commands to be used in optimization
rather than just settling for those of the default zone-table (ZT1).
	The zone concept need not even be adhered to; all the optimizer
is really doing is seeing which routine can specify the lowest-cost strategy.
To prevent wasting too much time, frequent checks of the cost-thus-far
should be made to see if it is > or = to the best-cost-thus-far (ZBESTC),
and an immediate loss return made if so.  The first entries in the zone table
should be those with the highest probability of returning the lowest cost.
One other heuristic, done by the overall optimizer, is that anything with a
cost of 1 will be executed immediately when the zone-test routine returns.
	To reiterate the requirements for zone-test routines:

	Called via CALL 
	Inputs:
		H,V - current cursor location
		NH,NV - desired cursor location
		CP    - Cursor stack pointer; commands pushed on this.
	Outputs:
		A  - total cost of commands pushed on CP  (# chars required)
		CP - updated stack pointer
	Returns to:
		.+1 on failure; A can have garbage.
		.+2 on success.

	Routine must not clobber NH,NV,H,V.  It is OK to smash
	acs B,C,D,E freely.

WRAP-AROUND:
	It is possible to have the optimizer take screen wrap-around into
account, by specifying a routine in the TR.WRP declaration.  There is no
default action since wrap-around is highly terminal dependent.  The idea is
that after ZTEST finds out what relative motions are called for, the
wrap-around routine will be invoked to take a look at these values (lying in
D for horizontal movement, E for verical movement) and decide whether it is
possible for motion in the OPPOSITE direction to successfully wrap around the
screen and thereby reach the target faster.  If so, the routine will simply
clobber D and/or E as appropriate to reverse the sign and furnish a
presumably smaller magnitude, and return to let the rest of the optimization
proceed.  See HPWRP and I43WRP for good examples.  Be careful in writing
wrap handlers; things like FSTFWD and tabs make it difficult to optimize
forward movement into wrapping backward movement.
    Of course, this could be integral with some terminal's own zone-test
routine, should it so desire.  But the current location of the invocation, in
ZTEST, is the most general place.  For example, if left-edge wraparound is
possible, then to move the cursor from screen center to upper right corner
can be done by means of a home-up followed by a backspace - and the optimizer
will do it!  |

; ZT1 - zone table for terminals with the basic set of secondary zones.
zt1:	ztest			; primary zone - no weird moves
	zthom			; home then test
	ztcr			; CR then test
lzt1==.-zt1

; ZT2 - zone table for terminals with NL.
zt2:	ztest			; relative move
	zthom			; home and relative move
	ztcr			; CR and relative move
	ztnl			; NL and relative move
lzt2==.-zt2

; ZT3 - zone table for terminals with independent absolute Y and X moves.
zt3:	ztest			; relative move
	zthom			; home and relative move
	ztcr			; CR and relative move
	ztay			; absolute Y move and relative X move
	ztaycr			; absolute Y move, CR, and relative X move
	ztax			; absolute X move and relative Y move
lzt3==.-zt3


; ZTAY - Absolute Y move and relative move check.
ztay:	pushae p,[h,v]
	push cp,[1,,cc.ay]
	xct .tcay+tb		; start with absolute Y move cost
	movei c,(a)		; ...
	movei v,(nv)		; effect absolute Y move
	jrst ztestc

; ZTAYCR - Absolute Y move, CR, and relative move check.
ztaycr:	pushae p,[h,v]
	push cp,[1,,cc.ay]
	xct .tcay+tb		; start with absolute Y move cost
	movei c,(a)		; ...
	movei v,(nv)		; effect absolute Y move
	push cp,[1,,cc.cr]
	xct .tccr+tb
	add c,a			; add CR cost
	move h,thmin		; effect CR
	jrst ztestc

; ZTAX - Absolute X move and relative move check.
ztax:	pushae p,[h,v]
	push cp,[1,,cc.ax]
	xct .tcax+tb		; start with absolute X move cost
	movei c,(a)		; ...
	movei h,(nh)		; effect absolute X move
	jrst ztestc


; ZTHOM - Home and relative move check.
zthom:	pushae p,[h,v]
	push cp,[1,,cc.hom]
	xct .tchom+tb		; start with home cost
	move c,a		; ...
	dmove vh,tmin		; home
	jrst ztestc

; ZTNL - Newline and relative move check.
ztnl:	caml v,tvmax		; last line?
	 return			; yes, forget NL!
	pushae p,[h,v]
	push cp,[1,,cc.nl]
	xct .tcnl+tb		; start with NL cost
	move c,a		; ...
	move h,thmin		; effect NL
	aoja v,ztestc

; ZTCR - CR and relative move check.
ztcr:	pushae p,[h,v]
	push cp,[1,,cc.cr]
	xct .tccr+tb		; start with CR cost
	move c,a		; ...
	move h,thmin		; effect CR
			; drop thru for cost & zone check

ztestc:	caml c,zbestc
	 jrst ztstc9		; blew it already
	call ztest0		; now try zone around new position.
	 jrst ztstc9
	aos -2(p)		; won!
ztstc9:	popae p,[v,h]
	return

; ZTEST - PRIMARY ZONE TESTER
;	This is the hairy, basic zone tester that tries to find
;	the best possible path from current H,V to NH,NV using only
;	basic up/down/right/left commands.

ztest:	movei c,0		; start off cost at zero
ztest0:	move d,nh		; entry point to avoid smashing cost
	sub d,h
	move e,nv
	sub e,v			; Get differences NH-H, NV-V in D, E
	xct .trwrp+tb		; adjust to consider wraparound

; test V movement
	jumpe e,ztest2		; skip if none needed
	jumpg e,[		; V movement downward.
		move a,e
		xct .tcdwn+tb	; check V cost.
		add c,a
		caml c,zbestc
		 return
		push cp,[cc.dwn]
		hrlm e,(cp)	; store iteration value.
		jrst ztest2
		]
	movn a,e
	xct .tcup+tb		; V movement upward.
	add c,a
	caml c,zbestc
	 return
	push cp,[cc.up]
	movn a,e
	hrlm a,(cp)

; Check H movement
ztest2:	jumpe d,ztest8		; jump if no movement necessary.
	jumpl d,[		; Backward H movement.
		movn a,d
		xct .tcbck+tb
		add c,a
		caml c,zbestc
		 return
		push cp,[cc.lft]
		movn a,d
		hrlm a,(cp)
		jrst ztest8
		]
	cain d,1		; moving forward by 1?
	 jrst [	addi c,1	; yes, don't consider tabs
		caml c,zbestc	; compare to best so far
		 return		; no better
		push cp,[1,,cc.fwd]	; better!
		jrst ztest8
		]

; Forward H movement.  Hairy - check for tabs etc.

mvar zsc			; saved C
mvar zsd			; saved D
	movem c,zsc
	movem d,zsd

; Calculate the no. of tabs to move to before desired horizontal position and
; no. of positions remaining.
	move e,h		; find tabstop at or before current position
	trz e,7			; ...
	move d,nh		; subtract from desired position to get
	subb d,e		; distance from tabstop
	andi d,7		; low three bits are positions remaining
	lsh e,-3		; higher bits are no. of tabs
	jumpn e,.+2
	 move d,zsd

; Calculate cost of tabs and forward moves.
	move a,e		; calculate cost of tabs
	xct .tctab+tb		; ...
	add c,a			; add to cost
	caml c,zbestc		; too big?
	 jrst ztest5		; yes, forget tabs
	move a,d		; calculate cost of forward moves
	xct .tcfwd+tb		; ...
	camle a,d		; compare the terminal's move forward to ours
	 move a,d		; ours (FSTFWD) is better
	add c,a			; add to cost

; Check if possible to overtab and then backspace.
	movei a,10(nh)		; find tabstop beyond desired position
	trz a,7			; ...
	camle a,thmax		; too big?
	 jrst ztest4		; yes, forget overtabbing

; Calculate cost of overtabbing and backspacing.
	move b,zsc		; start with accumulated cost
	sub a,nh		; subtract desired position to find no. of
				; backspaces
	xct .tcbck+tb		; calculate cost of backspaces
	add b,a			; add to cost
	movei a,1(e)		; calculate cost of overtabbing
	xct .tctab+tb		; ...
	add b,a			; add to cost
	caml b,c		; overtabbing better than not?
	 jrst ztest4		; no
	move c,b		; yes
	caml c,zbestc		; overtabbing best?
	 jrst ztest5		; no
; Overtabbing and backspacing is best.
	push cp,[cc.tab]
	addi e,1
	hrlm e,(cp)
	push cp,[cc.lft]
	movei d,10(nh)
	trz d,7
	sub d,nh
	hrlm d,(cp)
	jrst ztest8
; TAB-SP is better than TAB-BS.
ztest4:	caml c,zbestc
	 jrst ztest5
; TAB-SP is best.
	jumpe e,.+3
	 push cp,[cc.tab]
	 hrlm e,(cp)
	jumpe d,ztest8
	push cp,[cc.fwd]
	hrlm d,(cp)
	jrst ztest8		; win!

; Use plain old spaces to get there.
ztest5:	move c,zsc		; restore C, cost so far
	move d,zsd		; restore D, horizontal difference
ztest6:	move a,d		; calculate cost of move forward
	xct .tcfwd+tb		; ...
	camle a,d		; compare the terminal's move forward to ours
	 move a,d		; ours (FSTFWD) is better
	add c,a			; add move forward cost to cost so far
	caml c,zbestc		; compare to best so far
	 return			; worse, oh well
	push cp,[cc.fwd]
	hrlm d,(cp)

ztest8:	aos (p)
	return

constants

loc <.+pg$siz-1>&#pg$msk	; align on page boundary

subttl	Terminal Definition Macros

comment |
	 These macros are intended to be used in the following sequence:
TRMBEG <symbol>:,<name>		; The ":" is so CREF listings will notice it)
  trmup <this>
  trmdwn <that>
  ...
  <other table specification macros>
  <special routines pointed to by table entries if any>
TRMEND

	The initial TRMBEG macro aligns to page boundary and
reserves room for terminal table entries, which the following
macros insert stuff into.  Each entry is characterized by a
name of 3 letters max such as DWN, HOM, UP, etc. as well as 1 group
letter such as M, E, etc. and has 3 symbols associated with it:
( "g" represents group letter, "xxx" the name)

  [1] Tg.xxx - A MACRO which takes one whole-line argument and
	stuffs it in the entry of that name, for the terminal
	currently being defined.
  [2] .Tgxxx - An OFFSET from the start of that terminal's table, ie an
	index to that entry.  Thus one uses XCT TB+.Tgxxx etc.
  [3] TBgxxx - An ADDRESS defined as TB+.Tgxxx so that DDT can
	report more informative things than "TB+45".  It is
	recommended that source code use the "TB+.Tgxxx" form however.

The TMCDEF macro exists for defining entries given their names.
As a special case, TMVDEF will define a special sort of move-group
macro which takes two args (one for the move code, one for its cost)
|

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

IF1 ntcvar==0			; initialize offset/definition count

; TMCDEF <group>,<entry name> - defines a terminal-table entry.

define tmcdef g,nam	; Macro for defining table entries
if1 ntcvar==<.T!g!nam==ntcvar>+1
if2 TB!g!nam=:tb+.T!g!nam	; TB undefined on pass1
  define T!g!.!nam -arg
    ifb [arg],.err Argument must be given to T!g!.!nam
    loc %%toob+.T!g!nam
    arg
  termin
termin

; TADEF <name> defines a absolute cost terminal-table entry.

define tadef nam
if1 ntcvar==<.TC!nam==ntcvar>+1
if2 TBC!nam=:tb+.TC!nam
  define TC.!nam -arg
    ifb [arg],.err Argument must be given to TC.!nam
    if1 {arg
	.stop }
    loc %%toob+.TC!nam
    .x.==arg		; because arg may have comment etc.
    ifn 777777&(.x.),	.x.
    .else		movei a,.x.
  termin
termin

; TCDEF <name> defines a relative cost terminal-table entry.

define tcdef nam
if1 ntcvar==<.TC!nam==ntcvar>+1
if2 TBC!nam=:tb+.TC!nam
  define TC.!nam -arg
    ifb [arg],.err Argument must be given to TC.!nam
    if1 {arg
	.stop }
    loc %%toob+.TC!nam
    .x.==arg
    ifn 777777&(.x.),	.x.
    .else {
	ife .x.-1, jfcl ? .stop
	ife .x.-2, lsh a,1 ? .stop
	ife .x.-4, lsh a,2 ? .stop
	imuli a,.x.
	}
  termin
termin


; TMVDEF <entry name> - defines two entries at once for a
;	move group routine: .TMxxx for the code, and .TCxxx
;	for the associated cost.  The resulting TM.xxx macro
;	takes the cost as an additional argument, to make its
;	use easier.

define tmvdef x,nam
  t!x!def nam
if1 ntcvar==<.TM!nam==ntcvar>+1
if2 TBM!nam=:tb+.TM!nam
  define TM.!nam cost,-arg
    TC.!nam cost
    ifb [arg],.err Argument must be given to TM.!nam
    loc %%toob+.TM!nam
    arg
  termin
termin

; TRMBEG <sym>:,[<name1>,<name2>...]
;	Begins a terminal definition.  The ":" after <sym> is
; so that CREF's will semi-win; at least one name must be specified
; such that the first is "official" and any of these in command line
; will be recognized as meaning this terminal type. (someday)

%%ntrm==-1			; Initialize no. of terminals defined
%%tchk==0			; and check flag
ifndef minrem,minrem==ntcvar+60	; minimum amount of leftover space in page
				; necessary to avoid page force.  Set 0 to
				; never force, PG$SIZ to always force.
define trmbeg sym,(name)
ifn %%tchk, .err No TRMEND for previous TRMBEG?
%%tchk==1
%%tmp==<.+pg$siz-1>&#pg$msk	; find start of next page, and if this one
ifl <%%tmp-.>-minrem, loc %%tmp	; doesn't have much room, move to new one.
fpage==./pg$siz			; first page
%%ntoo==0
trmtoo sym,name
termin

; TRMTOO is used to define a new terminal type within a TRMBEG-TRMEND pair.

define trmtoo sym,list
%%ntrm==%%ntrm+1
%%ntoo==%%ntoo+1
ifle maxtrm-%%ntrm, .err Too many crt types!?
if2 {irp name,,[list]
	ife %%ntrm,{printx /Term/ ? printx /inals: !name/}
		.else printx /,!name/
     .istop
     termin }
sym				; Def <sym> as start of definitions
%%toob==.
if2 { tmploc trmtab+%%ntrm,{ %%toob }
      }
	block ntcvar+1
irp name,,[list]
  tp.nam [sixbit /name/],,[asciz /list/]
  .istop
  termin
crty.d				; stick in basic defaults
termin


; TABEND - end terminal definition table.

define tabend
loc %%toob+ntcvar+1
termin

; TRMEND - used when terminal definition finished.

define trmend
ife %%tchk, .err TRMEND seen without a preceding TRMBEG?
%%tchk==0
; Try turning this off.
;	constants
lpage==<.-1>/pg$siz		; last page occupied
if2  repeat %%ntoo, tmploc pagtab+%%ntrm+1-%%ntoo+.rpcnt,{ fpage,,lpage }
termin

; ////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
;<<<<<<<<<<<<<<<< Terminal-table Entry Definitions >>>>>>>>>>>>>>>>>
; \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/////////////////////////////////

; Display controls - Move and Cost group. (M, C)
; These use the TMVDEF macro instead of TMCDEF,
; so that resulting macros will take cost as additional arg.
tmvdef C,UP	; Move up
tmvdef C,DWN	; Move down
tmvdef C,FWD	; Move forward (right)
tmvdef C,BCK	; Move backward (left)
tmvdef C,TAB	; Move to next tab stop (every 8 chars)
tmvdef A,CR	; Move to beginning of line
tmvdef A,NL	; Move to new line (CR and DWN)
tmvdef A,HOM	; Home up (0,0)
tmvdef A,AX	; Absolute X move
tmvdef A,AY	; Absolute Y move
tmvdef A,ABS	; Absolute move (X,Y)

; Display controls - Erase/Edit group (E)
tmcdef E,DEL	; Delete forward
tmcdef E,WIN	; Set window
tmcdef E,EOL	; Erase to EOL (End of Line)
tmcdef E,EOS	; Erase to EOS (End of Screen)
tmcdef E,CLR	; Clear screen and home up
tmcdef E,SU	; Scroll screen up if at bottom, and go to beg of line.
tmcdef E,SD	; Scroll screen down
tmcdef E,EIM	; Enter insert character mode
tmcdef E,LIM	; Leave insert character mode
tmcdef E,ICP	; Insert char position
tmcdef E,DCP	; Delete char position
tmcdef E,ILP	; Insert line position
tmcdef E,DLP	; Delete line position

; Display controls - Misc group (X)
tmcdef X,BEL	; Ring bell
tmcdef X,VBL	; Show visible bell
tmcdef X,SO	; Go into standout mode
tmcdef X,SOR	; Leave standout mode

; Routine & dispatch group (R)
tmcdef R,INI	; Initialization routine
tmcdef R,FIN	; Cleanup routine
tmcdef R,TYO	; Dispatch for own TYO processing
tmcdef R,TYI	; Dispatch for own input processing
tmcdef R,CHO	; Dispatch for own ordinary-character output
tmcdef R,MOV	; Dispatch for cursor mover
tmcdef R,ZNS	; Pointer to table of tailored optimization routines
tmcdef R,WRP	; Routine for optimization wraparound if any
tmcdef R,NRM	; Wrap normalization
tmcdef R,SMI	; SIMULATION: STY output-char routine address
tmcdef R,SMO	; SIMULATION: STY input loop address
tmcdef R,SMF	; SIMULATION: STY input loop output finalizer address
tmcdef R,WI	; Window initialize
IFN STY,{
tmcdef R,WB	; Wholine begin
tmcdef R,WE	; Wholine end
}
IFE STY,{
define	tr.wb -x
termin
equals	tr.we,tr.wb
}

; Parameters group (P) - includes flags
tmcdef P,FLG	; Flag word, holds various flags
tmcdef P,NAM	; Holds sixbit name of terminal
tmcdef P,HSZ	; Horizontal screen size
tmcdef P,VSZ	; Vertical screen size
tmcdef P,SCR	; Scroll count

;============================================================================

; .TPFLG flag definitions - put into RH of F

%f==525252	; mask for terminal flags in F
%fsmeol==:    1	; Wants "Smart CLEOL".
%fcsel==:     2	; Do %TDEOL instead of %TDEOF - i.e. don't do CLEOS.
%fsail==:     4	; SAIL characters available on output
%ffci==:     10	; Full character input
%f8ci==:     20	; (ignored if %ffci set) 8-bit char input, 8th bit is META.
%fspd==:     40	; need to know the output speed

%fneol==:   100	; No simple clear-to-EOL.
%fneos==:   200	; No simple clear-to-EOS.
%fnclr==:   400	; No simple clear-and-home.
%fnsu==:   1000	; No simple scroll up
%fnsd==:   2000	; No simple scroll down
%fnicp==:  4000	; No simple insert character
%fndcp==: 10000	; No simple delete character
%fnilp==: 20000	; No simple insert line
%fndlp==: 40000	; No simple delete line

%fbow==:100000	; inverse video on

%ff1==:200000	; reserved for terminal handlers
%ff2==:400000	; reserved for terminal handlers


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; CRTY.D - sets up basic defaults; stuck into ALL terms by TRMBEG.
define crty.d
if1 .stop
irp x,,[up,dwn,fwd,bck,cr,nl,tab,hom,ax,ay,abs]
  tc.!x movei a,nutcst		; Set costs to something absurd
termin

tp.scr	1			; scroll count of 1
tr.zns	-lzt1,,zt1		; default zone table
tr.ini	call absclr		; default init routine
tr.fin	jfcl
tr.tyo	tyobout
tr.tyi	styi
tr.cho	scho
tr.mov	movcur
tr.wrp	jfcl
tr.wi	swi
tr.wb	whowb
tr.we	whowe
te.win	jfcl
tx.bel	tyo ^G
tx.vbl	call simvbl

termin

nutcst==5000.	; Use this as default "absurd cost" for missing functions.


ltb==ntcvar		; Set length of TB for copying term table into.
mvar trmadr		; holds addr of selected supporter definition.
mvar simadr		; Holds addr of selected simulator definition.
mvar tb(ltb)		; TB table - term tab copied here for fast impure ref.

subttl	Notes about terminal-table entries

Comment |
	Someday this may be a guide to adding terminals.  For now it is a page
devoted to various notes about the conventions surrounding terminal-table 
entries:

---- General ----
	Groups TM, TC, TE, and TX are always XCT'd.  P's are always data
values.  R's can be various things, (TR.ZNS is an AOBJN pointer for the
MOVCUR optimizer) but basically a "routine" is always XCT'd, and a
"dispatch" is JRST @'d to; such code is written only with a
good understanding of what calls them and what the effects should be
and where control should return.

*> Note that the insert/delete line/character functions (TE.ILP, TE.DLP,
TE.ICP, TE.DCP) and the relative movement functions (TM.FWD, TM.BCK,
TM.UP, TM.DWN, TM.TAB, TM.NL) take an argument in A saying how many
times to perform the function.  Without exception, this value MUST NOT
BE CLOBBERED by the execution of these functions.

---- TR.INI ----
	This entry is XCT'd and must do two basic things: home the
cursor and clear the screen.  TR.INI must be provided, unless one of
TE.CLR, TM.HOM, or TM.ABS exists.  The screen image is cleared and
NH,NV and H,V are zero'd before TR.INI is XCT'd.
	If a routine is furnished which types anything out (as in
warning messages), the coordinates and the screen image must be
maintained.  If this sounds too difficult, just clear the screen again
after doing whatever you like.  But since ITS automatically sends a
%TDCLR when the STY is ^Z'd, in general it's OK to just maintain the
cursor position.  In general.

---- TM.ABS ----
	If a TM.ABS entry exists, it is not necessary to have any other TM.xxx
entries; the optimizer will always use whatever is available, and fall
back on absolute move when necessary.  (although this depends on the
zone-table used.)  If TM.ABS does NOT exist, then one must use common
sense and make sure that some way exists for the optimizer to move
the cursor up, down, left, and right, by whatever means.  (This means
it is perfectly OK to have TM.HOM as the only way of moving up and left!)
The reason all this works is because the cost for non-specified entries
is set to an absurd figure which the optimizer will reject immediately.
	The routine furnished for TM.ABS must whenever possible pay no
attention to H,V and simply assume that the cursor may be anywhere on
the screen, and move it to NH,NV.  Otherwise, the power of absolute
move is compromised.  MOVCUR will do necessary optimization if TM.AX
and TM.AY entries happen to exist (and the proper zone table is used).

---- TR.WI, TR.WB, TR.WE ----
TR.WI is called to initialize window variables.
TR.WB, TR.WE are terminal hooks into the wholine display;
TR.WB after the window is switched but before outputing anything,
TR.WE just after it's all output.

*> The entries TR.SMO, TR.SMF, and TR.SMI are completely unlike any
others, because they represent the capability of SIMULATING the
terminal rather than supporting it!  TR.SMO should be ZERO (i.e.
unspecified) if no such capability exists; if so, it and the others
will be defaulted appropriately.  Basically, TR.SMO and TR.SMI point
at the SMO and SMI modules, which normally are SWSMO and SWSMI
to "simulate" the ITS Software virtual terminal.
	These entries are also unlike other entries in that for a
terminal-support selection, their values are ignored and in fact
smashed with the values of TR.SMx for the terminal being simulated!
See the SIMINI routine where this is done.

---- TR.SMO ----
	TR.SMO points to the SMO module for a particular terminal.  If
it exists, it should point at a loop similar to that for SWSMO.  In
particular a SMOBIN macro invocation MUST be the first thing that is
executed upon dispatch to the loop!  See the specifications for SMO
routines on the page where SMOBIN is defined.

---- TR.SMF ----
	TR.SMF is part of the SMO module if one is specified.  It
points to a routine which is called whenever there is no more STY/NET
output to process.  Normally this should "finalize" things by forcing
out any buffered TTY output.

---- TR.SMI ----
	TR.SMI points to the SMI module for a particular terminal.  If
it exists, it must point at a loop similar to that for SWSMI.  In
particular, a CALL SMIGET MUST be the first thing that is executed
upon dispatch to the loop!  See the specifications for SMI routines on
the page where SMIGET is defined.

---- TR.TYI ----
The TR.TYI entry points at the TYI module for a particular terminal.
As such it is required to input chars via TYIBIN and output them via
TYIPUT, and loop forever like STYI does.  See the specifications on
the page where TYIBIN is defined.

---- AC usage for terminal-definition routines ----
	Be very very careful about writing code for either the TYI or SMI
modules (i.e. which TR.TYI and TR.SMI point to), because they function
at TYIC interrupt level and only a few ACs are saved.  If any acs are
to remain clobbered across a TYIBIN or SMIGET call, they had better
be ones that TTYINT saves and restores!!  
	As already mentioned, any functions taking an argument in A should
save it.  More generally, everything in a terminal definition should
avoid clobbering any ACs, with the following exceptions:
	T1 and T2 are fair game.
	Any TM.XXX routine can clobber B,C,D,E freely.
	NH and NV may be set if one wishes to move the cursor; but see
		discussion of "actual and virtual cursor position".

---- Actual and Virtual cursor position ----
	This section is supposed to explain about H,V vs NH,NV and
when you should use one and when the other.  Should also explain
when and why it is necessary to effect a cursor force.
	Theoretically, H,V represent the actual, physical position of
the cursor on the terminal's screen.  NH and NV represent the
"virtual" position - where the cursor is in the mind of ITS (or whatever
program is running under the STY), and where all new operations
(char output, line insert, etc) are to take place.  As a result of
CRTSTY's optimization algorithms, the two positions are sometimes
different.  Whenever an operation is about to be executed which
does not simply consist of moving the cursor (in which case one merely
changes NH,NV), it is necessary to make sure that NH and NV reflect
reality and are identical to H,V; MOVCUR is the routine that will
ensure this.

|

comment ~
     Here is a sample terminal definition:

subttl	FOO - Find Outer Otter Terminal

	trmbeg FOO:,[FOO]

tp.flg	0			; Terminal flags.  Chosen from:
				; %fsmeol, %fcsel, %fsail, %ffci
tp.vsz	24.			; no. of lines displayable on the screen
tp.hsz	80.			; no. of characters per line
tp.scr	1			; scroll count (defaults reasonably)
tr.ini	call fooini		; call to initialization procedure
tr.fin	call foofin		; call to finialization procedure (defaults
				; reasonably)
tr.tyi	footyi			; input character handler (defaults reasonably)
tr.tyo	footyo			; output character handler (defaults
				; reasonably) 
tr.cho	foocho			; display character routine (defaults
				; reasonably, but use CCHO if terminal CRLFs
				; after typing in the last column)
tr.zns	-lzt1,,zt1		; AOBJN to zone table (defaults reasonably)
tr.wrp	call foowrp		; call to wrap handler (defaults reasonably)
tr.nrm	call foonrm		; call to normalizer (needed only if TR.WRP
				; specified)
tm.up	2,tynesc "A		; move up n
tm.dwn	1,tyn ^J		; move down n (LF)
tm.fwd	2,tynesc "C		; move forward n
tm.bck	1,tyn ^H		; move back n (BS)
tm.tab	1,tyn ^I		; move to nth next tabstop (TAB)
tm.cr	1,tyo ^M		; move to left margin (CR)
tm.nl	2,tyo ^_		; move to beginning of next line (NL)
tm.hom	2,tyoesc "H		; move to upper left corner (home)
tm.ax	3,call fooah		; absolute horizontal move
tm.ay	3,call fooav		; absolute vertical move
tm.abs	6,call fooabs		; absolute move
te.eol	tyoesc "K		; erase to end of line
te.eos	tyoesc "J		; erase to end of screen
te.clr	tyoesc "j		; erase whole screen (and home)
te.su	tyn ^J			; scroll the screen up
te.sd	tynesc "I		; scroll the screen down
te.eim	tyoesc "Q		; enter insert character mode
te.lim	tyoesc "R		; leave insert character mode
te.icp	tynesc "@		; insert n character positions
te.dcp	tynesc "P		; delete n character positions
te.ilp	tynesc "L		; insert n lines
te.dlp	tynesc "M		; delete n lines
tx.so	call fooso		; enter standout mode
tx.sor	call foosor		; exit standout mode
tx.bel	tyo ^G			; ring bell (defaults reasonably)
tx.vbl	call foovbl		; visible bell
tabend


; Various support routines called above.

trmend
~

subttl	RAW, NVT - Raw TTY and Network Virtual TTY simulation

; These entries exist just so the simulation code can be pointed to.
; "Support" is not currently provided.

	trmbeg RAW:,[RAW]
tr.smi	rwsmi
tr.smo	rwsmo
tr.smf	rwsmf

tr.ini	jfcl
;tr.tyi		; Default TYI module is STYI which is OK.

tabend

rwtyi:	

IFN NET,{
	trmtoo NVT:,[NVT]

tr.smo	nvtsmo
tr.smi	nvtsmi
tr.smf	nvtsmf
tabend
} ;IFN NET

trmend

subttl	AAD - Ann Arbor Display Controller
; The E.E. Plasma group and JLK has these (anyone else?)

; No padding is needed.
	trmbeg AAD:,[AAD]

tp.flg	%fsmeol
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho
tm.up	1,tyn 16
tm.dwn	1,tyn 12
tm.fwd	1,tyn 11		; tab moves over one space
tm.bck	1,tyn 10
tm.cr	1,tyo 15
tm.hom	1,tyo 13
tm.abs	3,call aadmv
te.clr	tyo 14
te.su	tyn ^J
tx.vbl	call aadvbl
tabend

aadmv:	pushae p,[a,b]
	tyo ^O			; abs cursor pos command
	movei a,(nh)		; cretinous BCD type format
	idivi a,10.
	lsh a,4			; high bits are 10's digit
	iori a,(b)		; or in remainder (should only be 4 bits)
	call @.trtyo+tb
	movei a,100(nv)
	call @.trtyo+tb
	popae p,[b,a]
	return

aadvbl:	pushae p,[nh,nv]
	movei nh,70.
	movei nv,23.
	call aadmv
	zout [asciz /########/]
	movei nh,70.
	call aadmv
	zout [asciz /--Bell--/]
	popae p,[nv,nh]
	return

trmend

subttl	ANNARB - Ann Arbor Display

	trmbeg ANNARB:,[ANNARB]

tp.flg	%fsmeol
tp.vsz	40.
tp.hsz	80.
tr.ini	call annini
tr.cho	ccho
tm.up	1,tyn ^N
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^_
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^K
tm.abs	3,call annabs
te.clr	tyo ^L
te.su	tyn ^J
tabend

annini:	xct .teclr+tb		; clear whole screen
	push p,nh
	movei nh,8.
annin1:	call annabs
	tyo ^]			; set tabstop in current column
	addi nh,8.
	camg nh,shmax
	 jrst annin1
	pop p,nh
	return


annabs:	pushae p,[a,b]
	tyo ^O			; abs cursor pos command
	movei a,(nh)		; cretinous BCD type format
	idivi a,10.
	lsh a,4			; high bits are 10's digit
	iori a,(b)		; or in remainder (should only be 4 bits)
	call @.trtyo+tb
	movei a,100(nv)
	cail a,20.+100
	 addi a,12.
	call @.trtyo+tb
	popae p,[b,a]
	return

trmend

subttl	AAB - Another Ann Arbor

	trmbeg AAB:,[AAB]

tp.flg	%fsmeol
tp.vsz	40.
tp.hsz	80.
tr.cho	ccho
tr.wrp	call aabwrp
tm.up	1,tyn ^N
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^I		; yes, tab
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^K
tm.abs	3,call aababs
te.clr	tyo ^L			; 2ms padding needed
te.su	tyn ^J
tabend

aababs:	pushae p,[a,b]
	tyo ^O			; abs cursor pos command
	movei a,(nh)		; cretinous BCD type format
	idivi a,10.
	lsh a,4			; high bits are 10's digit
	iori a,(b)		; or in remainder (should only be 4 bits)
	call @.trtyo+tb
	movei a,(nv)
	cail a,20.
	 addi a,12.
	call @.trtyo+tb
	popae p,[b,a]
	return


; Arguments:
;   D	horizontal distance
;   E	vertical distance

aabwrp:	caile e,20.		; moving more than 20 lines down?
	 sub e,theight		; yes, use 40-n move ups instead
	return

trmend

subttl	Ann Arbor Ambassador - Ann Arbor Terminals Ambassador

	trmbeg AAA:,[AAA]

;;; Added by RLL on 09/07/80.  The Ambassador is supposed to implement
;;; the full ANSI X3.64-1979 standard for Video display terminals.

tp.flg	0
tp.vsz	48.			; 60 is too scrunched
tp.hsz	80.
tr.ini	call aaaini
tr.fin	call aaafin
tr.cho	scho0
tr.wb	call aaawb
tr.we	call aaawe
tm.up	3,tynans "A
tm.dwn	1,tyn ^J
tm.fwd	3,tynans "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.nl	2,tyoesc "E
tm.hom	3,tyoans "H
tm.abs	[call aaamvc] call aaaabs  
;te.del	tyoans "X		; can take argument, but CRTSTY doesn't know
				; about that
te.eol	tyoans "K		; 5ms to clear one line
te.eos	call aaaeos		; needs padding
te.sd	tynans "M
te.su	tyn ^J
te.icp	tynans "@		; 4 ms
;Don't use insert mode; it frys your brain to see the cursor flash so fast.
;te.eim	tyoesc "6		; toggle character insertion mode
;te.lim	tyoesc "6		; toggle character insertion mode
te.dcp	tynans "P		; 4 ms
te.ilp	tynans "L		; 3 ms
te.dlp	tynans "M		; 3 ms
tx.vbl	call aaavbl		; VISBEL
tx.so	call aaaso		; Complement video
tx.sor	call aaasor		; Un-highlight (Back to requested video)
tabend


;;; Finish up routine.  Called on exiting CRTSTY.
aaafin:	tyoans ">		; turn wrap in last column on
	zout [asciz "33h"]	; ...
	zout [asciz "[60;;;"] ;]
				; memory size = 60, upper host area = 0,
				; lower host area = 0
	move a,sheight		; TYODEC arg: A = no.
	call tyodec		; screen size = specified value
	tyo "p			; ...
	setzb h,v		; cursor homed
	return


;;; Initialization.

;;; We don't touch Guarded Area Transfer (1), Keyboard Action Mode (2),
;;; Format Effector Transfer (14), Multiple Area Transfer (15), Transfer
;;; Termination (16), Selected Area Transfer (17), Margin Bell (25), Key
;;; Click (26), Key Repeat (28), Block Cursor (31), Blinking Cursor (32),
;;; Auto Pause (38), Transfer Pointer Display (41), Line Transfer (42),
;;; Column Separator Transfer (43), Field Separator Transfer (44), Graphic
;;; Rendition Transfer (45), Fast Repeat (47), Hold in Area (48), Guarded
;;; Area Print (49), or Function Key Initialize (50).

aaaini:
IFN 0,[ ; commented out because can't call TYIBIN yet at initialization
	; must come up with some kludge like splicing this to the TTY
	; input co-rotuine

	;; Find out revision number of terminal and if its high enough
	;; tell ITS it has a Meta key.  This code is very Ann Arbor
	;; specific.  Perhaps one day a general subroutine for parsing
	;; ANSI reply sequences would be useful.
	zout [asciz "[0c"] ;]	; Request a device attributes report
	call tyofin		; make sure its sent out

	call tyibin		; read a character from terminal
	caie a,33		; DA reply should start with an escape
	 jrst aanorp		; if not, its not right reply.  If this
				; isn't a timeout is there someway to give
				; char back?
	call tyibin		; should be left bracket
	jumpn a,aanorp		; give up on timout	
	call tyibin		; should be <
	jumpn a,aanorp		; give up on timout

	call tyibin		; get first digit of verison number
	jumpn a,aanorp		; give up on timout
	caie a,"0		; if its not 0, it must be higher
	 jrst aagotm		; so its got a meta key
	call tyibin		; get 2nd digit
	jumpn a,aanorp		; give up on timout
	caile a,"1		; if greater than version 1
	 jrst aagotm
	call tyibin		; next read revision number, count on version

	caie a,";		; number never breaking 2 digits
	 jrst aanorp

	call tyibin		; get first digit of revision number
	jumpn a,aanorp
	caile t1,"1		; version 20 or greater is good enoguh
	 jrst aagotm
	cain t1,"0		; but leading 0 TSis a loser
	 jrst aaflsh
	cail a,"1		; 2nd digit 1 or greater?
	 jrst aaflsh		; no, then rev 10 doesn't have meta key

aagotm:	;; its got a meta key, turn on the bit
	$call ttyvar,[#pyi,[sixbit/ttyopt/],#0,[tro %tpmta]]
	 .lose %lsfil

aaflsh:	call tyibin		; flush rest of reply, either by
	jumpl a,aanorp		; time out or end of string..
	caie a,"c		; reply string ends with a "c"
	 jrst aaflsh
aanorp:

] ; IFN ITS
;;; ANSI modes:
	setzm padc		; ^@ is the pad character
	tyoesc "[ ;]		; start of modes to reset
	zout [asciz "4;"]	; Turn off Insert Character Mode
	zout [asciz "18;"]	; Select Tab mode to have tabs in columns
				; on the whole screen
	zout [asciz "20l"]	; LF is Line Feed rather than New Line
	tyoesc "[ ;]		; start of modes to set
	zout [asciz "6;"]	; Enable clearing the entire screen
				; (protected field nonsense)
	zout [asciz "12h"]	; Enable sending to host
	zout [asciz "[1Q"] ;]	; Insert/delete character stop at end of
				; line

;;; Ann Arbor Modes
	tyoans ">		; start of modes to be reset (separate
				; each by a ';')
	zout [asciz "27;"]	; Turn off Keypad Control Mode (make numeric
				; keypad send numbers unshifted and escape
				; codes shifted)
	zout [asciz "29;"]	; Turn off CR LF Mode
	zout [asciz "30;"]	; Turn off Destructive Backspace Mode
	zout [asciz "33;"]	; Turn off Wrap Forward Mode
;	zout [asciz "34;"]	; Turn off Wrap Backward Mode
	zout [asciz "36;"]	; Turn off Scroll-Page Mode (so TE.SU works)
	zout [asciz "37;"]	; Turn off Auto XON/XOFF Mode
	zout [asciz "39;"]	; Turn off Slow Scroll Mode
	zout [asciz "40;"]	; Turn off Half-Duplex Mode
	zout [asciz "46;"]	; Turn off Auto Keyboard Disable Mode
	zout [asciz "51l"]	; Turn off Alternate Cursor Mode
				; and end list of modes to be reset

	tyoans ">		; start of modes to be set (seperate
				; each by a ';')
	zout [asciz "35;"]	; Turn on DEL Character Display Mode
	zout [asciz "52h"]	; Turn on Meta Key Mode

	tyoesc "[ ;]		; Start of set display parameters
	move a,sheight		; TYODEC arg: A = no.
	call tyodec		; set requested no. of lines for memory
	zout [asciz ";;;"]	; no upper or lower areas
	move a,sheight		; TYODEC arg: A = no.
	call tyodec		; set requested no. of lines for screen area
	tyo "p			; ...
	skiple jinvrs		; INVERSE specified?
	 zout [asciz "[7m"] ;]	; yes, enter inverse video mode
	skipge jinvrs		; NO INVERSE specified?
	 zout [asciz "[0m"] ;]	; yes, exit inverse video mode
	tyoans "H		; Home up
	zout [asciz "[3g"]	; Clear all tabs
	movei a,9		; Set 9 tabs
aaain1:	zout [asciz "[8CH"]	; Forward 8 spaces and set a tab
	sojg a,aaain1
	tyoans "H		; Home up and clear screen
	call aaaeos

	ifn its,[		; too many ITS users are using AAA
	  ife net,[		; CRTSTY -CBF
	move a,[ascnt "
                    Warning:

Using CRTSTY consumes more system resources and results in slower output
than standard ITS support.  You can use standard ITS support by typing
:TCTYP AAA instead of :CRTSTY AAA.
"]
            call stdwrn
	    movei a,4.*30.	; wait 4 more seconds so message can be read
	    skipl jwarn
	     .sleep a,
	    ]]

aaain2:	return


aaamvc:	movei a,4		; start with 4 for ESC-[-digit-H ;]
	movei t1,(nv)
	sub t1,tvmin
	cail t1,10.-1		; vertical position require two digits?
	 addi a,1		; yes, make it 5
	movei t1,(nh)
	sub t1,thmin
	jumpe t1,[return]
	addi a,2		; add 2 for semi-digit
	cail t1,10.-1		; horizontal position require two digits?
	 addi a,1		; yes, account for that
	return

aaaabs:	tyoesc "[ ;]
	movei a,1(nv)		; line number, 1-origin
	sub a,tvmin
	caie a,1		; 1 is default
	 call tyodec
	camn nh,thmin		; first line of scroll region?
	 jrst aaamv1		; yes, that's default, don't send
	tyo ";
	movei a,1(nh)		; column number, 1-origin
	sub a,thmin
	call tyodec
aaamv1:	tyo "H
	return

aaaeos:	tyoans "J
	pad [.3]		; I think this is .156 --RWK
	return

aaavbl:	push p,nh		;Save the cursor position
	push p,nv
	setzb nh,nv		;move to home 
	call td.frc		;force it to happen now, plus any SMEOL
	xct tb+.txso
	zout [asciz "9"]	;Set the graphics rendition of the rest of the
				;screen.  Assumes no DAQs have been set.
	pad [.283]		;Takes 283 ms.
	xct tb+.txsor
	zout [asciz "9"]	;Set it for all the screen
	pad [.283]		;Takes a while
	pop p,nv		;Restore the cursor position
	pop p,nh
	return


aaaso:	skiple jinvrs		;Assume normal video
	  jrst aaaso1
	zout [asciz "[7m"]	;Back to normal video if inverse
	return

aaaso1:	zout [asciz "[0m"]	;Use inverse video if normal
	return

aaasor:	skiple jinvrs		;Assume normal video
	  jrst aaasr1
	zout [asciz "[0m"]	;Back to inverse video
	return

aaasr1:	zout [asciz "[7m"]	;Back to normal video
	return

tvar aaawini			; Set if we've already inited the wholine
; Start the wholine
aaawb:	call fulwin		; reset window to full screen
	setzb nv,nh		; home
	xct tb+.txso
	skipe aaawini
	  return
	call td.frc
	xct tb+.teeol	; Really clear to EOL to invert whole line
	setom aaawini
	return

; Finish the wholine
aaawe:	call frceol		;Clear to EOL
	xct tb+.txsor		;Turn off inverse vid
	jrst reswin		; restore window

trmend

subttl	ACT-II

	trmbeg ACT2:,[ACT-II]

;;; This may be the silliest terminal yet suported.
;;; Note that the cursor actually stays on the bottom line and what we are
;;; really doing is rolling the screen around.

tp.vsz	16.
tp.hsz	63.			; don't use right edge cause of auto scroll up
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^K
tm.fwd	1,tyn ^I
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
te.clr	call act2cl
te.su	tyn ^J			; scroll up
tabend
; screen clearing is accomplished by scrolling all the lines off the screen
act2cl:	push p,a
	move a,sheight
	tyn ^J
	pop p,a
	return

trmend

subttl	ACT-IV

	trmbeg ACT4:,[ACT-IV]

comment ~
At 19200 baud CLEOS must be followed by at least one filler code, e.g. 00,
if more than half the screen is to be cleared.  Home up needs 2 padding
characters, at least, at 19200 baud.
~

tp.flg	0
tp.vsz	24.			; no. of lines displayable on the screen
tp.hsz	80.			; no. of characters per line
tr.cho	ccho			; character display routine 
tm.up	1,tyn ^Z		; move up n
tm.dwn	1,tyn ^K		; move down n (LF)
tm.fwd	1,tyn ^X		; move forward n
tm.bck	1,tyn ^H		; move back n (BS)
tm.cr	1,tyo ^M		; move to left margin (CR)
tm.hom	1,tyo ^]		; move to upper left corner (home)
tm.abs	3,call actmov		; absolute move
te.eol	tyo ^^			; erase to end of line
te.eos	tyo ^_			; erase to end of screen
te.clr	tyo ^L			; erase whole screen (and home)
te.su	tyn ^J			; scroll the screen
tx.so	tyo ^E			; enter standout mode
tx.sor	tyo ^E			; exit stadout mode
tabend


; Absolute move.
actmov:	tyo ^T
	tyo (nv)
	tyo (nh)
	return

; No TRMEND since next is TRMTOO.

subttl	ACT-V - Microterm ACT V

	trmtoo ACTV:,[ACT-V]

tp.flg	%fnicp+%fndcp+%fnilp+%fndlp	; on most models these are local only
tp.vsz	24.
tp.hsz	80.
tr.ini	call undlcw
tr.tyi	undel
tr.cho	ccho
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^K
tm.fwd	1,tyn ^X
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^]
tm.abs	3,call actmov
te.eol	tyo ^^
te.eos	tyo ^_
te.clr	tyo ^L
te.icp	call acticp
te.dcp	tyn ^Q
te.ilp	tyn ^A
te.dlp	tyn ^W
te.su	tyn ^J
te.sd	tynesc "H
tx.so	tyoesc "B
tx.sor	tyoesc "C
tabend

acticp:	tyo ^S			; Enter char insert mode
	tyn 40			; send N spaces
	tyo ^H			; Move back once to get out of mode
	addi h,-1(a)		; hope this works.
	return

trmend

subttl	ADI60 - Applied Dynamics International Series 60 Basic Universial Terminal

	trmbeg ADI60:,[ADI60]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho
tm.up	1,tyn ^_
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^\
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^K
tm.abs	4,call adiabs
te.eol	zout [asciz "EE"]
te.eos	zout [asciz "EP"]
te.clr	tyo ^L
te.su	tyn ^J
te.icp	zoutn [asciz "IC"]
te.dcp	zoutn [asciz "KC"]
te.ilp	zoutn [asciz "IL"]
te.dlp	zoutn [asciz "KL"]
tabend


; Direct cursor positioning.
adiabs:	tyoesc "A
	tyo 40(nh)
	tyo 40(nv)
	return

trmend

subttl	ADM2 - Lear Siegler ADM-2

	trmbeg ADM2:,[ADM2]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	call a2init		; warn user of changes we make in keyboard
tr.tyi	a2tyi			; make changes in keyboard for each character
tr.cho	ccho			; character display routine 
tr.zns	-lzt2,,zt2		; use zone table which includes NL
tm.up	1,tyn 13		; ^K
tm.dwn	1,tyn 12		; ^J
tm.fwd	1,tyn 14		; ^L
tm.bck	1,tyn 10		; ^H
tm.nl	1,tyo 37		; ^_
tm.cr	1,tyo 15		; ^M
tm.hom	1,tyo 36		; ^^
tm.abs	4,call a2abs
te.eol	tyoesc "T
te.eos	tyoesc "Y
te.clr	tyoesc "*
te.su	tyn ^J			; scroll up
te.icp	tynesc "Q
te.dcp	tynesc "W
te.ilp	tynesc "E
te.dlp	tynesc "R
tx.vbl	call a2vbl
tx.so	tyoesc "^		; start blinking field
tx.sor	tyoesc "^		; same char to end blinking field!
tabend


; Initialization.
a2init:	xct .teclr+tb		; zap screen
	move a,[ascnt " Warning, interchanged Underscore and Delete keys.
 To type an Escape you must hit the Escape key TWICE."]
	pjrst stdwrn		; Go off to standard warn routine

				
; Terminal input co-routine.
a2tyi1:	call tyipuc
a2tyi:	call tyibin		; get next character
	caie a,177		; interchange underscore and delete
	 cain a,137
	  xori a,137#177
	caie a,33		; Escape?
	 pjrst a2tyi1		; Nope, just pass on.
	call tyibin		; Hmm, get next character
	cain a,33		; Also an escape?
	 pjrst a2tyi1		; Yes, pass on.
	push p,a		; No, must send esc plus character
	movei a,33
	call tyipuc
	pop p,a
	jrst a2tyi1


a2abs:	tyoesc "=		; absmove command
	tyo 40(nv)		; Y, then
	tyo 40(nh)		; X.
	return


a2vbl:	tyoesc "^		; VISBEL - start blink field
	tyoesc "U		; control chars print mode
	tyo ^G			; now the ^G makes a little blinking bell
	tyoesc "X		; control chars DON'T print mode
	tyoesc "^		; stop blink field
	return

trmend


subttl	ADM3A - Lear Siegler ADM-3A

comment | Other randomness: ^N unlocks kbd if locked, ^O locks
kbd if enabled to do so.  Has switch for auto-NL or not.
  ADM-3 is similar but doesn't have
tm.up, tm.fwd, tm.hom, or tm.abs!!  Complete loser. |

	trmbeg ADM3:,[ADM3A]

tp.flg	%fsmeol
tp.vsz	24.
tp.hsz	80.
tr.ini	call adm3in		; Announce that we'll
tr.tyi	undel			; input through standard _/DEL swap.
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call adm3mv
te.clr	tyo ^Z
te.su	tyn ^J			; scroll up
tabend


adm3in:	skipe janl		; don't print auto-nl warning if user
				; specified state
	 pjrst undlcw
	tyo ^Z			; clear screen
	move a,[ascnt "Warning: interchanged Underscore and Delete keys.
Warning: auto newline switch should be off."]
	pjrst stdwrn


adm3mv:	tyoesc "=		; absmove command
	tyo 40(nv)		; Y, then
	tyo 40(nh)		; X.
	return

; no TRMEND cause next is a TRMTOO

subttl	ADM5 - Lear Siegler ADM-5

comment | Other randomness: ^N unlocks kbd if locked, ^O locks
          kbd if enabled to do so.  Has switch for auto-NL or not.
	  ADM-3A is similar but doesn't have te.eol, te.eos.|

	trmtoo ADM5:,[ADM5]

tp.vsz	24.
tp.hsz	80.
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call adm3mv
te.clr	tyo ^Z
te.eol  tyoesc "T
te.eos  tyoesc "Y
te.su	tyn ^J			; scroll up
tabend

trmend

subttl	ADDS25 - ADDS Regent 25

	trmbeg ADDS25:,[ADDS25]

tp.vsz	24.
tp.hsz	80.
tr.cho	ccho
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^F
tm.bck	1,tyn ^U
tm.cr	1,tyo ^M
; tm.hom	1,tyo ^A	;this doesn't work in scroll mode
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "k
te.clr	tyo ^L
te.su	tyn ^J
tabend

trmend

subttl	ADS100 - ADDS Regent 100

	trmbeg ADS100:,[ADS100]

tp.vsz	24.
tp.hsz	80.
tr.cho	CCHO			; terminal auto-crlf's in last column
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^F
tm.bck	1,tyn ^H		; move back n (BS)
; "claims to have tab but I don't know what it does" -Macrak
;tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^A
tm.ax	2,call a100ah
tm.ay	2,tyo _9+100(nv)
tm.abs	4,call vtabs
;te.eol	tyoesc "K  disabled because the actual operation to be performed varies
;te.eos	tyoesc "k  according to the KEYBOARD shift key.
te.clr	tyo ^L
te.su	tyn ^J			; scroll the screen up
tabend

a100ah:	tyo ^P
	move c,nh
	idivi c,10.
	lsh d,4
	ior c,d
	tyo (c)
	return

trmend

subttl	ADS580 - ADDS 580

comment |
	This info comes from NATE@ML
  HERE ARE THE SPECS FOR THE 580:

1) BACKSPACE=^U, FORWARD=^F
2) DOWN A LINE=^J, UP A LINE=^Z
3) CARRAGE RETURN=^M
4) HOMEUP AND ERASE=^L, HOMEDOWN=^A
5) NO HARDWARE TAB, ER-EOL, ER-EOS
6) BELL=^G
7) DIRECT VERTICAL POSITIONING: ^K FOLLOWED BY ASCII 0 THROUGH
	23; ZERO IS TOP LINE, 23 IS BOTTOM
8) DIRECT HORIZONTAL POSITION: ^P FOLLOWED BY ASCII 0 THROUGH 71.
9) SCREEN DIMENSIONS: 72 (HORIZONTAL) X 24 (VERTICAL)
10) 5X7 DOT MATRIX
11) NO LOWER CASE
12) NO KEYBOARD BUGS, NUMBER KEYPAD AT RIGHT, CURSOR POSITION KEYS
	FURTHER RIGHT.
13) SELECTABLE WRAP/SCROLL FEATURE: WRAP AROUND OR SCROLL DOWN (ONLY DOWN)
14) AUTO LINEFEED OPTION (SWITCH SELECTABLE)
15) FULL OR HALF DUPLEX (SWITCH SELECTABLE)
16) EXTERNAL PRINTER; RS232 OUTPUT ON BACK.  TURN ON WITH ^R
	TURN OFF WITH ^T.
17) ADJUSTABLE BAUD RATE: 110, 300, 1200, 2400, 9600
NOTE: ANYTHING NOT MENTIONED MAY BE ASSUMED TO BE STANDARD.

|

	trmbeg A580:,[ADS580]

tp.flg	%fsmeol
tp.vsz	24.
tp.hsz	72.
tr.zns	-lzt3,,zt3		; use zone table for AX/AY capability
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^F
tm.bck	1,tyn ^U	; ??
tm.cr	1,tyo ^M
tm.ax	2,call a580ax
tm.ay	2,call a580ay
tm.abs	4,call a580mv
te.clr	tyo ^L		; homeup & erase
tabend

a580mv:	call a580ay	; then drop thru to do AX.

a580ax:	tyo ^P
	tyo (nh)
	return

a580ay:	tyo ^K
	tyo (nv)
	return

trmend

subttl	ADS980 - ADDS Consul 980 with escapified number-pad

comment | ADDS 980 has tabs every 5, not every 8!  

ADS980 WRAPS TO FIRST POSITION OF NEXT LINE.
IF AT LAST POSITION ON LAST LINE AND CHARACTER IS RECEIVED, SCROLL
OCCURS FIRST, AND THEN CHARACTER APPEARS ON NEW BOTTOM LINE.

HERE IS THE TABLE THAT ADDS SUPPLIES FOR PADDING INFORMATION:

	BAUD RATE	9600	4800	2400	1200
FUNCTION

LINE INS/DEL		20	10	5	3
SCREEN ERASE		2	1	0	0
CURSOR ADDRESS		2	1	0	0
LINE FEED (I.E. CR)	2	1	0	0

from byron:
alternate keypad has another (unadvertised) "feature".
In AK mode, <ctrl>-<shift>-char sends <esc>-<lower>-char
for alphabetic characters.  I don't know quite what to do with this,
though currently I just accept both chars sent.
  All chars between a "{" and a "}" blink!  This can be disabled
with internal jumper, but in that mode it simply inhibits all display
of the chars in between!
|

	trmbeg A980:,[ADS980]

tp.flg	%fsmeol+%fspd
tp.vsz	24.
tp.hsz	80.
tr.tyi	a98tyi
tr.ini	call a98ini
tr.cho	ccho			; character display routine 
tm.bck	1,tyn ^H
tm.hom	2,tyo 013140		; ^K 140 - go to beg of line 0.
tm.abs	4,call a98abs
te.eol	call a98eol
te.clr	tyo ^L
te.su	tyn ^M
te.ilp	call a98ilp
te.dlp	call a98dlp
tabend


; Initialization.
a98ini:	tyo ^_			; format off
	tyo ^O			; stop tag
	xct .teclr+tb		; clear screen
	pjrst undelw		; output warning message


; Insert line.
a98ilp:	push p,a
a98il1:	tyoesc ^N		; Line-position insert
	pad [.025]
	sojg a,a98il1
	pop p,a
	return


; Delete line.
a98dlp:	push p,a
a98dl1:	tyoesc ^O		; Line-position delete
	pad [.025]
	sojg a,a98dl1
	pop p,a
	return


; Clear to end of line.
a98eol: caml v,tvmax		; last line?
	 pjrst a98el1		; yes, hack specially
	tyo ^M			; CR does a CLEOL and CRLF
	movei h,0		; account for cursor motion of CR
	addi v,1		; ...
	return
a98el1:	jumpn h,seol		; if not at beginning of line, hack spaces
	tyoesc ^O		; otherwise delete this, the bottom line
	pad [.025]		; pad the delete line
	return


; Absolute move takes advantage of the feature (?) wherein a horizontal
; move exceeding (hmax - hpos), but less than 99., wraps to next line

a98abs:	came v,nv
	 jrst mva981
	caml h,nh
	 jrst mva982
	move d,nh		;nv = v and nh > h so move horizontally
 	sub d,h
	jrst hor980
mva981:	move d,nv		;check if nv = v+1
	sub d,v
	caie d,1
	 jrst mva982		;if not, use normal positioning
	move d,nh
	sub d,h
	cail d,20.		;check that total move is less than 100.
	 jrst mva982
	addi d,80.
	jrst hor980		;if so, use funny horizontal move
mva982:	tyo ^K			;absolute move for ADS980
	tyo 40(nv)		; move to beginning of line
	camn nh,thmin
	 return
	move d,nh
hor980:	tyoesc ^E		; set horizontal position
	idivi d,10.		; using two decimal (!) digits
	tyo 40(d)
	tyo 40(e)
	return


; Terminal input co-routine.
a98i1:	call bckych
	call tyipuc
a98tyi: call a98get
a98i2:	caie a,33
	 jrst a98i1
	call tyibin
	cain a,".		; period?
	 jrst a980$.
	cail a,"0		; between 0 and 9?
	 caile a,"9
	  jrst [
		push p,a
		movei a,33
		call bckych
		call tyipuc
		pop p,a
		jrst a98i2
		]
	xct a980$n-"0(a)	; Yes, execute appropriate instr
	jrst a98tyi		; and flush char if no jump made.

a98get:	call tyibin
	caie a,177		; first exchange DEL and underscore.
	 cain a,137
	  xori a,137#177
	return

a980$.: tlz f,%imeta+%itop+%ictrl	; cancel meta, top, or control
	jrst a98tyi
a980$n:	jfcl			; $0
	jrst a980$1		; $1 = escape
	jfcl			; $2
	jfcl			; $3
	jrst a980$4		; $4 = CALL
	jfcl			; $5
	jfcl			; $6
	tlo f,%imeta		; $7 = META
	tlo f,%imeta+%ictrl	; $8 = CONTROL-META (TOP no longer exists)
	tlo f,%ictrl		; $9 = CONTROL

a980$1:	movei a,33		; $1 = escape
	jrst a98i1
a980$4:	movei a,336		; $4 = CALL
	jrst a98i1

trmend

subttl	AJ510 - Anderson Jacobson 510

	trmbeg AJ510:,[AJ510]

tp.vsz	24.
tp.hsz	80.
tr.ini	call aj5ini
tr.zns	-lzt3,,zt3		; AOBJN pointer to zone table with AX/AY test
tr.cho	aj5cho			; need output routine to fix up _ lossage
tm.up	2,tynesc "Y
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "X
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.ax	5,call aj5ax
tm.ay	5,call aj5ay
te.eol	zout [asciz "'L"]
te.eos	zout [asciz "'P"]
te.su	tyn ^J			; scroll the screen up
te.eim	zout [asciz "'I"]
te.lim	zout [asciz "'J"]
te.dcp	zoutn [asciz "'D"]
te.ilp	zoutn [asciz "&I"]
te.dlp	zoutn [asciz "&D"]
tx.so	zout [asciz |"I|]	; choose inverse video for standout
tx.sor	zout [asciz |"N|]	; resets them all
tabend

aj5ini:	zout [asciz |&C&J&F"NH|]
				; character mode, unlock kbd, fulldpx, reset
				; standout modes, home cursor, clear all tabs
	setzb v,h		; reflect action of the home command
	pjrst settab		; set the tabs
	
aj5ax:	tyoesc "A		; X position
	push p,a
	push p,b
	move a,nh
	jrst aj5dec

aj5ay:	tyoesc "B		; Y position
	push p,a
	push p,b
	move a,nv
aj5dec:	tyo "0			; peculiar, they demand 3 digits
	idivi a,10.		; in decimal!
	tyo "0(a)
	tyo "0(b)
	pop p,b
	pop p,a
	return

aj5cho:	cail a,40		; control character?
	 cail a,177		; or rubout (or worse)?
	  return		; yes, ignore it
	movei t1,"_		; are well about to overlay an underscore?
	camn t1,@scrtab(v)
	 jrst aj5chu		; if so, gotta do special work
aj5ch1:	tlze f,%icm		; insert character on?
	 xct .telim+tb		; yes, turn it off
	movem a,@scrtab(v)	; store character in screen image
	camg h,thmax		; past last column?
	 paoja h,@.trtyo+tb	; no, output char and advance 1 position
	return			; otherwise, throw away out of bounds chars

aj5chu:	zout [asciz |'D|]	; delete char quickest way to kill _
	tlon f,%icm		; insert char already on?
	 zout [asciz |'I|]	; no, turn it on
	tyo <40_9.>+10		; insert 1 position and then backup over it
	jrst aj5ch1		; now we can output the char

trmend

subttl	ANSI - ANSI 3.64 braindamage

	trmbeg ANSI:,[ANSI]

tp.flg	%fnicp+%fndcp
tp.vsz	0			; ask
tp.hsz	0			; ask
tr.ini	call ansini
tr.cho	scho0
tm.up	3,tynans "A
tm.dwn	1,tyn ^J
tm.fwd	3,tynans "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	3,tyoans "H
tm.abs	[call ansmvc] call ansabs
te.eol	tyoans "K
te.eos	tyoans "J
te.su	tyn ^J
;ICP gives better performance.
;te.eim	zout [asciz "[4h"] ;]
;te.lim	zout [asciz "[4l"] ;]
te.icp	tynans "@
te.dcp	tynans "P
te.ilp	tynans "L
te.dlp	tynans "M
tx.so	zout [asciz "[5m"] ;]
tx.sor	zout [asciz "[0m"] ;]
tabend


; Initialization.
ansini:	zout [asciz "[20l"] ;]	; LF is Line Feed rather than New Line
	tyoans "H		; home
	tyoans "J		; clear screen
	return


; Calculate absolute move cost.
ansmvc:	movei a,4		; start with 4 for ESC-[-digit-H ;]
	movei t1,(nv)
	sub t1,tvmin
	cail t1,10.-1		; vertical position require two digits?
	 addi a,1		; yes, make it 5
	movei t1,(nh)
	sub t1,thmin
	jumpe t1,[return]
	addi a,2		; add 2 for semi-digit
	cail t1,10.-1		; horizontal position require two digits?
	 addi a,1		; yes, account for that
	return

; Absolute move.
ansabs:	tyoesc "[ ;]
	movei a,1(nv)		; line number, 1-origin
	sub a,tvmin
	caie a,1		; 1 is default
	 call tyodec
	camn nh,thmin		; first line of scroll region?
	 jrst ansmv1		; yes, that's default, don't send
	tyo ";
	movei a,1(nh)		; column number, 1-origin
	sub a,thmin
	call tyodec
ansmv1:	tyo "H			; They say lower-case f also works, I wonder
				; what difference
	return

trmend

subttl	BANTAM - Perkin-Elmer Bantam

	trmbeg BANTAM:,[BANTAM]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
;tr.cho	ccho			; I think auto-NL is an internal switch,
				; We presume most people have it set wrong?
tr.zns	-lzt3,,zt3		; AOBJN pointer to zone table with AX/AY test
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.ax	3,call banah		; abs move in horizontal direction
tm.ay	3,call banav		; abs move in vertical direction
tm.abs	6,call banmv
te.clr	tyoesc "K
te.eol	tyoesc "I		; not ESC K !!
te.su	tyn ^J			; scroll up
tx.vbl	call banvbl		; visible bell
tabend


; Transparent mode displays all spaces as small NU's; doing this briefly
; is quite flashy.
banvbl:	tyo ^P			; ^P^B goes into transparent mode
	tyo ^B
	tyo ^P			; ^P^C exits debug mode.
	tyo ^C
	return

; perform abs move
banmv:	call banav	; Drop thru to do H after doing V.

banah:	tyoesc "Y		; is abs move in HORIZONTAL direction!
	tyo 40(nh)
	return
banav:	tyoesc "X		; is abs move in VERTICAL direction!
	tyo 40(nv)
	return

trmend

subttl	BEE3 - Beehive Model III

;	SIZE OF SCREEN      20 LINES X 80 CHARACTERS PER LINE.
;	CURSOR UP           ^R
;	CURSOR DOWN         ^J
;	CURSOR BACK         ^D
;	CURSOR FORWARD      ^P
;	CURSOR HOME         ^E
;	CURSOR START OF LINE^M
;	ERASE TO END OF LINE^L
;	ERASE END OF SCREEN ^K
;	CLEARS SCREEN       ^T  (THIS ALSO ERASES ALL TABS AND HOMES CURSOR)
;	RING BELLS          ^G
;	SET TAB STOPS       ^F
;	CLEAR TAB STOPS     ^V   (THIS IS ONLY FOR A SINGLE TAB AT A TIME)
;	CLEAR ALL TABS      ^T
;	TABULATION          ^I
;
;	NO ABSOLUTE CURSOR POSISTIONING, INSERT/DELETE  CHAR/LINE   EXISTS ONLY
;	IN LOCAL MODE. NOT AVAILABLE ON LINE.
;
;	WHEN THE CURSOR REACHREACHES END OF LINE
;	AUTOMATIC  <CR><LF>  TO THE NEXT LINE.
;	LINE FEEDING OFF THE BOTTOM ONLINE CAUSES SCROLLING  IN LOCAL IT MOVES
;	IT TO THE TOP. OFF AN AUTOMATIC <CR><LF> ON THE LAST LINE, 
;	SCROLLING OCCURS.  OFF THE TOP OF THE SCREEN WHEN CONTINUING UP
;	THE CURSOR GOTO THE BOTTOM AND CONTINUES UP. TO THE RIGHT , THE CURSOR
;	<CR><LF>'S TO THE NEXT LINE. THE INVERSE OCCURS WHEN GOING TO 
;	THE LEFT .
;
;	NO PADDING IS REQUIRED FOR ANY FUNCTIONS.
;
;	EXTRA FEATURES ARE:
;	
;	BLINKING VIDEO      STARTS FROM POSISTION AND CONTINUES TO END OF LINE.
;	(^\)
;	CLEAR BLINK ON ENTIRE PAGE  (^[)  [<ESCAPE>]
;	REVERSED   VIDEO  (^])
;	REVERSED BLINKING VIDEO (^^)
;	RESET BLINK FOR THE LINE  (^_)
;
;	FORMAT MODE.
;
;	ENTRY IS ONLY PERMITTED BETWEEN  BRACKETS. TAB MOVES TO NEXT ENTRY
;	SPOT. EXAMPLE,
;
;	NAME:[      ]   TELEPHONE NUMBER :[    ]
;
;	ENTRIES CAN BE MADE ONLY IN THE BRACKETS AND SEND ON.
;
;	TO GET INTO FORMAT MODE TYPE ^O  (SHIFT IN)
;
;
;	PRESS STOP KEY  (NO CODE) TO QUIT  OR  ^T AND HIT ^N
;
;
;	BLOCK SEND IS AVAILABLE WHERE AN ENTIRE SCREEN FUL IS PREPARED AND
;	THEN THE \  CHARACTER INDICATES THE END OF THE MESSAGE. HIT THE
;	SEND KKEY AND IT SENDS ALL THE INFORMATION AT ONCE. ( SEND = ^U)
;
;	^H=NEW LINE IS USED TO INDICATE END O F LINE . THE SCREEN AUTOMATICALLY
;	OUTPUTS <CR><LF><NULL> IN PLACE OF THE ^H WHEN TRANSMITTED.
;
;	WHENEVER ^H IS RECEIVED, THE TERMINAL AUTOMATICALLY DOES
;	<CR><LF><NULL>.
;
;	TO SEND THE TERMINAL TO LOCAL MODE  TYPE  ^X. THERE IS NO REMOTE
;	WAY TO RETURN TO ON LINE. THAT CONDITION MUST BE RESTORED BY
;	THE PERSON USING THE TERMINAL.
;
;	THE LAST FIVE CHARS IN ASCII ARE NOT ABLE TO BE SENT EXCEPT FOR
;	<RUBOUT>  ASCII  173,174,175,176  CAN BE PRODUCED AND 
;	RECEIVED BUT CAN NOT BE TRANSMITTED DUE TO CONSTRUCTION OF KEYBOARD
;	WHICH RESEMBLES MODEL 35 TELETYPE WITH THE EXCEPTION OF THE ALPHA
;	LOCK KEY WHICH DETERMINSE UPPER OR LOWERCASE FOR LETTERS.
;
;	ASCII 136  EQUALS  CARAT
;	ASCII 137  EQUALS  UNDERSCORE
;	ASCII 173  EQUALS  LEFT BRACE
;	ASCII  174  EQUALS  VERTICAL BAR
;	ASCII 175  EQUALS  RIGHT BRACE
;	ASCII 176  EQUALS  TILDA

	TRMBEG BEE3:,[BEE3]

tp.flg	0
tp.vsz	20.			; rather tiny
tp.hsz	80.
tr.ini	call b3ini
tr.cho	ccho			; character display routine 
tm.up	1,tyn ^R
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^P
tm.bck	1,tyn ^D
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^E
te.eol	tyo ^L
te.eos	tyo ^K
tabend

b3ini:	pushae p,[a,b]
	tyo ^T			; clear screen, clear tabs
	move b,shmax		; calculate the no. of tabs to set
	lsh b,-3		; ...
b3tab1:	movei a,8.		; move to next multiple of 8
	tyn 40			; ...
	tyo ^F			; and set a tabstop there
	sojg b,b3tab1
	tyo ^E			; restore cursor to home
	popae p,[b,a]
	return

trmend

subttl	CDC713 - Control Data 713

	trmbeg C713:,[CDC713]

tp.flg	0
tp.vsz	16.			; rather tiny
tp.hsz	80.
tr.cho	ccho			; character display routine 
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^U
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^Y
te.eol	tyo ^V
te.clr	tyo ^X
te.su	tyn ^J
tabend

trmend

subttl	C100 - Human Designed Systems Concept 100

	trmbeg C100:,[C100]

tp.flg	%fspd+%fnicp+%fndcp	; insert/delete characters not used due to
				; HDS braindamage
tp.vsz	24.
tp.hsz	80.
tr.ini	call c1init
tr.tyi	c1tyi
tr.cho	c1cho
tr.wrp	call c1wrap
tm.up	2,tynesc ";
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "=
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "?
tm.abs	4,call c1abs
te.win	call c1win
te.eol	call c1eol
te.eos	call c1eos
te.clr	call c1clr
te.su	call c1su
;te.eim	tyoesc ^P		; use TE.ICP instead because of padding
te.lim	tyoesc ^@
te.icp	call c1icp
te.dcp	call c1dcp
te.ilp	call c1ilp
te.dlp	call c1dlp
tx.so	tyoesc "D		; turn on blinking
tx.sor	tyoesc "d		; turn off blinking
tx.vbl	call c1vbl
tabend


tvar c1padf
; Concept 100 initialization.  Reset terminal and set tabs.
c1init:	pushae p,[a,b,c,d]
	fltr b,speed		; get output speed in characters per second
	fdvr b,[-3200.0]	; calculate .3*(speed/960)
	fadr b,[.55]		; calculate 1 - (.45 + .3*(speed/960))
	move a,[1.0]
	fdvr a,b		; divide execution time by the fraction of
				; the processor available to get the padding
				; time
	movem a,c1padf

	movei a,c1cho4		; normally all control characters have to be
	skiple jtrans		; quoted, unless the terminal has the
	 move a,[@.trtyo+tb]	; translucent option
	movem a,c1ctl+0		; fill table of control characters with
	move a,[c1ctl+0,,c1ctl+1]	; right subroutine
	blt a,c1ctl+37			; ...
	skiple jtrans		; if translucent option then change a few
	 jrst [	movei a,c1cho4		; quoting character output subroutine
		movem a,c1ctl+0		; NUL
		movem a,c1ctl+^H	; BS
		movem a,c1ctl+^I	; TAB
		movem a,c1ctl+^J	; LF
		movem a,c1ctl+^L	; FF
		movem a,c1ctl+^M	; CR
		movem a,c1ctl+33	; ESC
		jrst .+1 ]
	tyoesc "U		; set programmer mode or abs move won't work!
	tyoesc "f		; set text mode (for ins/del line to work!)
	tyoesc "7		; set character mode (as opposed to block)
	tyoesc "5		; set upper-lower case mode
	tyoesc "8		; set full duplex
	tyoesc "l		; reset auto linefeed (normal CR)
	tyoesc "N		; send set attribute word command
	tyo 110			; attribute word with all zeros, except
				; protect = 1 (no protection)
	skiple jcid		; CID specified?
	 zout [asciz "!A@ "]	; yes, insert mode should stop at
					; end of line, and clearing shouldn't
					; set nodisplay bit
	skiple jinvrs		; INVERSE specified?
	 tyoesc "k		; yes, reverse video the screen
	skipge jinvrs		; NO INVERSE specified?
	 tyoesc "K		; yes, normal video the screen
	tyoesc "o		; somewhat random, change EOM to null
	tyo 46_9+0		; which should cause no eom character
	tyoesc "o		; set message character
	tyo 47_9+^^		; function key lead-in to ^^
;	tyoesc "$		; reset all function keys
	tyoesc "4		; set function key
	tyo 41060		; length 1, INSRT
	tyo 40			; transmit default
	tyoesc "4		; set function key
	tyo 40040		; length 0, SHIFT INSRT
	tyo 40			; transmit default
	tyoesc "4		; set function key
	tyo 41061		; length 1, DEL CHAR
	tyo 42037		; transmit control backarrow
	tyoesc "4		; set function key
	tyo 40041		; length 0, SHIFT DEL CHAR
	tyo 40			; transmit default
	tyoesc "4		; set function key
	tyo 41062		; length 1, DEL LINE INS
	tyo 42000		; transmit NUL
	tyoesc "4		; set function key
	tyo 40042		; length 0, SHIFT DEL LINE INS
	tyo 40			; transmit default
	tyoesc "4		; set function key
	tyo 40063		; length 0, EOP CLEAR EOL
	tyo 40			; transmit default
	tyoesc "4		; set function key
	tyo 40043		; length 0, SHIFT EOP CLEAR EOL
	tyo 40			; transmit default
	tyoesc "4		; set function key
	tyo 40064		; length 0, SEND
	tyo 40			; transmit default
	tyoesc "4		; set function key
	tyo 40044		; length 0, SHIFT SEND
	tyo 40			; transmit default

	setzb a,b		; C1WIN args: minimum vertical, minimum
				; horizontal
	dmove c,smax		; C1WIN arg: maximum vertical, maximum
				; horizontal
	call c1win1		; set window to whole screen
	xct .teclr+tb		; clear whole screen
IFN 0,{
	push p,nh		; save horizontal position
	movei nh,8.
c1ini1:	call c1abs
	dmove vh,nvh
	tyoesc "]		; ESC ] sets a tabstop
	addi nh,8.
	camg nh,shmax
	 jrst c1ini1
	pop p,nh		; restore horizontal position
} ; IFN 0
	popae p,[d,c,b,a]	; restore ACs
	return


; Set window.
c1win:	camn a,tvmin		; if new minimum vertical
	 came b,thmin		; or new minimum horizontal
	  jrst c1win1		; different from old then do it
	camn c,tvmax		; if new maximum vertical
	 came d,thmax		; or new maximum horizontal
	  jrst c1win1		; different from old then do it
	return			; otherwise no change, do nothing
c1win1:	pushae p,[c,d]		; save arguments we clobber
	dmovem a,tmin		; remember terminal window we're about to set
	dmovem c,tmax		; ...
	sub c,a			; subtract minimum vertical from maximum
	addi c,1		; and add 1 to get window height
	movem c,theight		; save away
	sub d,b			; subtract minimum horizontal from maximum
	addi d,1		; and add 1 to get window width
	movem d,twidth		; save away
	tyoesc "v		; send define window command
	tyo 40(a)
	tyo 40(b)
	tyo 40(c)
	tyo 40(d)
	dmove vh,tmin		; setting window homes cursor
	lsh c,1			; calculate 2/3 of window height for
	idivi c,3		; wrapping optimization
	movem c,c1vwrp		; save away
	popae p,[d,c]		; restore clobbered arguments
	return


; Wrap calculation.  Only hacks 1 out of 4 possible optimizations.  Backward
; movement isn't wrapped because of FSTFWD hackery, tabs, and because it
; moves up when it wraps on backspace.  Forward movment isn't wrapped because
; tabs aren't taken into consideration and because it moves down when it
; wraps going forward.  Finally, upward movement isn't wrapped because LF
; doesn't wrap (it scrolls).

; Arguments:
;   D	horizontal distance
;   E	vertical distance

c1wrap:	camle e,c1vwrp		; moving more than 16 lines down?
	 sub e,theight		; yes, use 24-n move ups instead
	return
tvar c1vwrp			; vertical movement distance at which
				; wrapping becomes worth it


; Concept 100 direct cursor address.
c1abs:	sub nv,tvmin		; cursor address is relative to start
	sub nh,thmin		; of window
	tyoesc "a		; direct cursor address command
	tyo 40(nv)
	tyo 40(nh)
	add nv,tvmin		; restore NV and NH
	add nh,thmin		; ...
	return


; Concept 100 scroll.
c1su:	push p,a
c1su1:	tyo ^J
	pad [.002]
	sojg a,c1su1
	pop p,a
	return


; Concept 100 clear to end of line.
c1eol:	tyoesc ^U		; send CLEOL
	pjrst c1pad4		; pad for 4 milliseconds


; Concept 100 clear to end of screen.
c1eos:	tyoesc ^E		; send clear to end of screen command
	push p,a		; save AC
	move a,tvmax		; calculate no. of lines cleared
	sub a,v			; ...
	addi a,1		; ...
	fsc a,233		; float
	fmpr a,[.0035]		; 3.5ms per line
	fadr a,[.0005]		; +.5ms
	fmpr a,c1padf
	pad a
	pop p,a			; restore AC
	return


; Concept 100 clear screen
c1clr:	tyo ^L			; send clear screen command
	push p,a		; save AC
	fltr a,theight		; get no. of lines in window
	fmpr a,[.0005]		; multiply by .5ms/line to get no. of
				; seconds of execution time
	fmpr a,c1padf
	pad a
	pop p,a			; restore AC
	return


; Concept 100 insert characters command.
c1icp:	tlon f,%icm		; insert character mode off?
	 tyoesc ^P		; no, turn on insert character mode
	push p,a		; save argument
c1icp1:	tyo 40			; output N spaces
	call c1pad4		; pad for 4 milliseconds
	sojg a,c1icp1
	pop p,a			; restore argument
	add h,a			; and move back over them
	return


; Delete characters.
c1dcp:	push p,a		; save argument
c1dcp1:	tyoesc ^Q		; send delete 1 character command
	call c1pad4		; pad for 4 milliseconds
	sojg a,c1dcp1
	pop p,a			; restore argument
	return


; Pad for 4 milliseconds.
c1pad4:	move t1,speed		; speed > 30cps?
	caig t1,30.		; ...
	 return			; no, no padding needed
	push p,a		; save AC
	move a,[.004]		; 4 milliseconds
	fmpr a,c1padf
	pad a
	pop p,a			; restore AC
	return


; Concept 100 insert line command.
c1ilp:	push p,a		; save argument
c1il1:	tyoesc ^R		; send insert line
	call c1lidp		; pad the insert line
	sojg a,c1il1
	pop p,a			; restore argument
	return


; Concept 100 delete line command.
c1dlp:	push p,a		; save argument
c1dl1:	tyoesc ^B		; send delete line
	call c1lidp		; pad the delete line
	sojg a,c1dl1
	pop p,a			; restore argument
	return


; Concept 100 line insert/delete padding.
c1lidp:	move t1,speed
	caig t1,30.
	 return
	push p,a		; save AC
	move a,tvmax		; TVMAX - V is no. of lines moved
	sub a,v			; ...
	addi a,1		; +1 for line that is cleared
	fsc a,233		; float that
	fmpr a,[.00075]		; C1PAD arg: execution time of .75ms per line
				; moved
	fmpr a,c1padf
	pad a
	pop p,a			; restore AC
	return


; Concept 100 visible bell.
c1vbl:	skipn jinvrs		; INVERSE or NO INVERSE specified?
	 jrst c1vbl1		; no, do it the hard way
	movei a,"K		; switch to normal video
	skipg jinvrs		; NO INVERSE?
	 movei a,"k		; yes, switch to reverse video
	tyoesc (a)		; flip video
	pad [.06]		; wait a little while
	xori a,"K#"k		; get command character to restore video
	tyoesc (a)		; restore it
	pad [.04]		; wait a little while(?)
	return
c1vbl1:	pushae p,[nh,nv,a,b,c,d]	; save ACs
	dmove nvh,tmin		; home cursor
	movei a,40		; C1SBA arg: attribute mask
	movei b,40		; C1SBA arg: attributes
	move c,theight		; C1SBA arg: no. of lines
	move d,twidth		; C1SBA arg: no. of columns
	call c1sba		; set whole screen to inverse video
	movei a,40		; C1SBA arg: attribute mask
	movei b,0		; C1SBA arg: attributes
	move c,theight		; C1SBA arg: no. of lines
	move d,twidth		; C1SBA arg: no. of columns
	call c1sba		; set whole screen to normal video
	popae p,[d,c,b,a,nv,nh]	; restore ACs
	return

; Set block attribute.
; Arguments:
;   A	Attributes mask.
;   B	Attributes.
;   C	No. of lines
;   D	No. of columns

c1sba:	call td.frc
	tyoesc "J		; set block attribute command
	addi a,100		; add 100 to avoid control characters
	call @.trtyo+tb		; send attribute mask
	movei a,100(b)
	call @.trtyo+tb		; send attributes
	movei a,40(c)
	call @.trtyo+tb		; send no. of lines
	movei a,40(d)
	call @.trtyo+tb		; send no. of columns
	imul d,c		; get total no. of characters
	fsc c,233
	fmpr c,[.0003]		; .3ms/line
	fsc d,233
	fmpr d,[.00002]		; .02ms/character
	fadr c,d
	fmpr c,c1padf
	pad c
	return


; C1CHO - Concept 100 character output.
c1cho:	tlze f,%icm		; insert character mode on?
	 tyoesc ^@		; yes, turn off insert character mode
	movem a,@scrtab(v)	; store character in screen image
	caml h,thmax		; last column?
	 jrst c1cho1		; yes, hack specially
	caie a,"_		; underscore?
	 cail a,177		; rubout (or worse)?
	  paoja h,c1cho4	; yes, special output
	cail a,40		; control character?
	 paoja h,@.trtyo+tb	; no, just send to terminal straight
	paoja h,@c1ctl(a)	; dispatch to either @.TRTYO+TB or C1CHO4

	; Last column.
c1cho1:	tyoesc "R		; repeat character vertical
	call @.trtyo+tb		; character
	tyo "!			; repeat count of 1
	return

; C100 quoted character output subroutine.
c1cho4:	tyoesc "r		; send repeat character horizontal command
	call @.trtyo+tb		; output character
	tyo "!			; send repeat count of 1
	return

tvar c1ctl(32.)			; table of control character output subroutines


; C100 terminal input co-routine.
c1tyi2:	movei a,^^
c1tyi1:	call tyiput
c1tyi:	call tyibin
	caie a,^^
	 jrst c1tyi1
	call tyitog
	jumpl a,c1tyi2
	cain a,"0
	 jrst c1tyi2
	cail a,"4
	 caile a,"B
	  jrst c1tyi3
	addi a,"0-"4+%txmta
	jrst c1tyi1
c1tyi3:	cain a,40
	 jrst c1tyi4
	push p,a
	movei a,^^
	call tyiput
	pop p,a
	jrst c1tyi1
c1tyi4:	call enter
	jrst c1tyi

trmend

subttl	Cromemco 3101

	trmbeg CROMEM:,[CROMEMCO]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	call undlcw		;Annouce that
tr.tyi	undel			; we'll switch "_" and "delete"
tr.cho	ccho			;Handle the auto-wrap at end of line 
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4.,call crabs
te.clr	tyoesc "E
te.su	tyn ^J			; scroll up
te.eol	tyoesc "K
te.eos	tyoesc "J
tabend

; Absolute move.
crabs:	tyoesc "F		;Esc F <v+32.> <h+32.>
	tyo 40(nv)
	tyo 40(nh)
	return

trmend

subttl	CT64 - SWTP CT-64

	trmbeg CT64:,[CT64]

tp.flg	0
tp.hsz	64.
tp.vsz	16.
tr.cho	ccho
tr.ini	tyo ^L_9+^U		; home and CLEOS
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^I
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^L
te.eol	tyo ^^
te.eos	call cteos
te.su	tyn ^J			; scroll up
tabend


cteos:	tyo ^^			; Erase to End of current line first
	caml v,tvmax		; are we at end of screen?
	 return			;  if so, then we've no more to do.
	jumpe h,.+3
	 tyo ^M
	 movei h,0
	tyo ^J			; Otherwise move to next line
	addi v,1
	tyo ^U			; then erase to end of screen
	return

trmend

subttl	CT1111 - Convergent Technologies 1111
comment ~
 pending resolution of the region scrolling issue -CBF 14 Dec 80
	trmbeg CT1111:,[CT1111]

tp.flg	0
tp.vsz	31.
tp.hsz	132.
tr.zns	-ltz3,,zt3		; zone table with NL
tm.up	1,tyn ^A
tm.dwn	1,tyn ^K
tm.fwd	1,tyn ^R
tm.bck	1,tyn ^N
tm.nl	1,tyo ^J
tm.abs	4,call ct1abs
te.eol	zout [asciz "EL"]
te.eos	zout [asciz "EF"]
~


subttl	DD4000 - Delta Data 4000

	trmbeg DD4:,[DD4000]

tp.flg	%fspd
tp.vsz	25.
tp.hsz	80.
tr.ini	call dd4ini
tr.cho	ccho			; character display routine 
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	8.,call dd4mv
te.eol	tyoesc "K
te.eos	tyoesc "J
te.ilp	tynesc "L
te.dlp	call dd4dl
tabend


; Initialization.
dd4ini:	setzm padc		; rubout is an ugly center-dot!
	tyoesc "E		; clear screen and tabs
	skipl jtab		; tabs?
	 pjrst settab		; yes, set tab stops
	return

dd4mv:	tyoesc "F		; StupidBee positioning
	move d,nh
	idivi d,100.
	tyo "0(d)
	movei d,(e)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	move d,nv
	idivi d,100.
	tyo "0(d)
	movei d,(e)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	return

dd4dl:	push p,a
dd4dl1:	tyoesc "M
	pad [.1]
	sojg a,dd4dl1
	pop p,a
	return

trmend

subttl DD5200 -  Delta Data 5200

	trmbeg DD5200:,[DD5200]

tp.flg	0
tr.ini	tyo16 122
tr.cho	scho0
tp.vsz	27.
tp.hsz	79.			; try 1 less column to win
tm.up	1,tyn 32
tm.dwn	1,tyn 13
tm.fwd	1,tyn 31
tm.bck	1,tyn 10
tm.hom  2,tyo16 121
tm.abs	4,call dd5abs
te.eol	tyo16 125
te.clr	tyo16 122
te.eim	tyo16 131
te.lim	tyo16 130
te.dcp	tyn16 126
te.ilp	tyn16 115
te.dlp	tyn16 114
tx.so	tyo16 37
tx.sor	tyo16 36
tabend


; DD5ABS -- absolute positioning.
dd5abs:	tyo16 116
	movn a,nh
	subi a,1
	andi a,177
	tyo (a)
	movn a,nv
	subi a,1
	andi a,177
	tyo (a)
	return

trmend

subttl	NIH5200 - Delta Data 5200 (NIH version)

	trmbeg NIH52:,[NIH5200]

tp.flg	%fspd
tp.vsz	27.
tp.hsz	80.
tr.cho	nh5cho
tm.up	1,tyn 32		; ^Z
tm.dwn	1,tyn 13		; ^K
tm.fwd	1,tyn 31		; ^Y
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	2,tyo16 "Q		; ^NQ
tm.abs	3,call nh5amv
te.eol	tyo16 "U
te.eos	zout [asciz "S"]	; CLEOS
te.clr	tyo ^L
te.dcp	tyn16 "V		; delete character
te.eim	tyo16 "Y		; go into insert mode.
te.lim	tyo ^R			; (NIH) exit insert mode
te.ilp	tyn16 "M		; insert line
te.dlp	zoutn [asciz "UL"]	; delete line
tx.so	tyo ^_			; Blinking
tx.sor	tyo ^^			; Unblink
tabend

; Come here to output character in A.
nh5cho:	cail a,40		; control character?
	 cail a,177		; or rubout (or worse)?
	  return		; yes, ignore it
	tlze f,%icm
	 xct .telim+tb
	movei t1,blchar
	came t1,@scrtab(v)	; see if already something there...
	 pjrst scho1		; yes, needn't worry.
	push p,h		; Sigh, must check... save old H.
	sojl h,nh5ch9		; if at beg of line, win.
	came t1,@scrtab(v)	; check preceding char position
	 jrst nh5ch9		; if something there, also win.
	move h,thmax
	camn t1,@scrtab(v)	; Find rightmost char on line
	 sojge h,.-1		; quickly.
	sub h,(p)		; Is rightmost char to right of cursor?
	jumpge h,nh5ch9		; yes, win.
	movn h,h		; make positive, and get
	subi h,1		; # blanks between current pos and rtmost char
	exch h,(p)		; now save it, restoring current hpos
	call scho1		; for output purposes.
	exch a,(p)		; Get back # blanks to pad for...
	fsc a,233		; float it
	fmpr a,[0.00144]	; 1.44 msec per blank to fill
	pad a
	pop p,a
	return

nh5ch9:	pop p,h			; no padding required, just restore stuff
	pjrst scho1		; and output normally


; Absolute move
nh5amv:	tyo ^A
	movn d,nh		; X coordinate is encoded as 177-nh
	tyo 177(d)		;  so we negate nh and add 177 to it.
	movn d,nv		; Y coordinate is encoded same way.
	tyo 177(d)
	return

trmend

subttl	NIH7000 - Delta Data NIH something

comment | Info from Ricart
start blink ESC blank
end blink ESC ( or end of line
start underlining ESC !
end underlining ESC ) or oend of line
start reverse video ESC "
end reverse video ESC *
start dim ESC #
end dim ESC + or end of line
start vertical bar in the RHS of char box ESC $
end vertical bar in the RHS of char box ESC , (char is still seen)
start display supression ESC % (useless)
end display supression ESC -
start horizontal bar in bottom of char box (char still seen, underlining still available) ESC &
end horizontal bar in bottom of char box ESC .
start put a little "mark" in upper left-hand corner of char box ESC '
end of that ESC / (or, of course, as with all of these, end of line)

The horizontal and vertical var features are indended for "dividing"
the screen but you can't do separate scrolling or windowing, so are
not much used.

[7] Crocks: using LFCR instead of CRLF causes next line to be displayed
"slowly" (still no fill needed unless it happens continuously over a 1200
baud line)  "slowly" means about 30  about 30 cps.

    p. Set tab ESC 1
    q. Tab HT (standard)
[3] char typed in column 80: cursor goes to first position on next line.
    If, however, at this point the terminal receives CRLF, the cursor
    does not move (prevents double-spacing of 80 char lines).  If
    it receives anything else, like just LF or LF CR, cursor will move.
[4] a. LF off bottom of screen...screen scrolls up
    b. cursor position off bottom of screen...screen scrools up as much
    as necessary to display new cursor position.
    c. auto crlf off last line...screen scrolls
    d. cursor position off right...goes to first posn of next line, scrolls if
       on bottom line.
       cusor position off left...goes to last posn of previous line, scrolls if on top line
       cursor posn off top....terminal scrolls (backwards)
[5] No timing necessary

|
	trmbeg n7k:,[NIH7000]

tp.flg	0
tp.vsz	28.			; no. of lines displayable on the screen
tp.hsz	79.			; no. of characters per line (80 but lossage)
tr.ini	call n7kini		; Set tabs.
tr.cho	scho0
tm.up	2,tynesc "`		; move up n
tm.dwn	1,tyn ^J		; move down n (LF)
tm.fwd	2,tynesc "b		; move forward n
tm.bck	1,tyn ^H		; move back n (BS)
tm.tab	1,tyn ^I		; move to nth next tabstop (TAB)
tm.cr	1,tyo ^M		; move to left margin (CR)
tm.hom	2,tyoesc "l		; move to upper left corner (home)
tm.ax	3,call n7kax
tm.abs	4,call n7kabs		; absolute move
te.eol	tyoesc "U		; erase to end of line
te.eos	tyoesc "X		; erase to end of screen
te.clr	tyo ^L			; erase whole screen (and home)
te.su	tyn ^J			; scroll up
te.eim	tyoesc "Q		; Begin insert mode
te.lim	tyoesc "R		; End insert mode
te.dcp	tynesc "P		; delete n character positions
te.ilp	tynesc "T		; insert n lines
te.dlp	tynesc "S		; delete n lines
tx.so	tyoesc ""		; enter standout mode
tx.sor	tyoesc "*		; exit standout mode
tabend

n7kini:	setzb nh,nv
	xct .teclr+tb
	skipl jtab		; tabs?
	 pjrst settab		; yes, set tab stops
	return

n7kabs:	tyoesc "_
	setcmi d,(nh)	; Use ones complement
	andi d,177
	tyo (d)
	setcmi d,(nv)
	andi d,177
	tyo (d)
	return

n7kax:	tyoesc "]	; "absolute tab"
	setcmi d,(nh)
	andi d,177
	tyo (d)
	return

trmend

subttl	DG132 - Datagraphix 132 models A & B?

	trmbeg DG132:,[DG132]

tp.flg	0
tp.vsz	30.
tp.hsz	132.
tr.ini	call dg1ini
tr.cho	scho0
tm.up	2,tynesc "K
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "L
tm.bck	1,tyn ^H
;tm.tab	1,tyn ^I		maybe tabs don't work
tm.cr	1,tyo 15
tm.hom	2,tyoesc "T
tm.abs	8,call dg1abs
te.eol	tyoesc "O
te.eos	tyoesc "I
te.clr	tyoesc "H
te.eim	tyoesc "0
te.lim	tyoesc "5
te.dcp	tynesc "6
te.ilp	tynesc "3
te.dlp	tynesc "4
te.su	tynesc "V		; Is this better than LF off the bottom?
te.sd	tynesc "W
tx.so	tyo ^_			; dim (not clear this is a winning "standout"
				; mode)
tx.sor	tyo ^^			; normal
tabend

dg1ini:	xct .teclr+tb		; home and clear screen
	xct .txsor+tb		; get out of dim mode?
	call settab
	skipe janl		; don't print warning if user specified state
	 return
	move a,[ascnt "Warning: AutoNewline mode should be off."]
	pjrst stdwrn

dg1abs:	tyoesc "8
	movei d,1(nv)
	idivi d,100.
	tyo "0(d)
	movei d,(e)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	movei d,1(nh)
	idivi d,100.
	tyo "0(d)
	movei d,(e)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	return
trmend

subttl	DG200 - Data General 200

	trmbeg DG200:,[DG200]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	call dg2ini
tr.cho	ccho
tr.tyi	dg2tyi			; switch CR & Nl
tr.zns	-lzt2,,zt2		; zone tables that includes NL 
tm.up	1,tyn 027
tm.dwn	1,tyn 032
tm.fwd	1,tyn 030
tm.bck	1,tyn 031
tm.cr	1,tyo 15
tm.nl	1,tyo 12
tm.hom	1,tyo 10
tm.abs	3,call dg2abs
te.eol	tyo 13
te.clr	tyo 14
te.su	zoutn [.byte 7 ? 022 ? 12 ? 023]	; roll enable, newline, roll disable
tx.so	zout [.byte 7 ? 036 ? 104]
tx.sor	zout [.byte 7 ? 036 ? 105]

tabend

dg2ini:	zout [.byte 7 ? 023? 14]	; roll disable, clear screen & home
	move a,[ascnt " Warning: Interchanged Newline and Return keys."]
	pjrst stdwrn

dg2abs:	tyo 020			; absolute position
	tyo (nh)		; column
	tyo (nv)		; line
	return

dg2tyi:	call tyibin		; interchange Newline and return on input
	caie a,12
	 cain a,15
	  xori a,15#12
	call tyipuc
	jrst dg2tyi

trmend

subttl	DLOG33 - Digi-Log Model 33

comment |
Character entered at EOL remains at EOL
Cursor position off to right: stays at col 80
Cursor position off to left: goes to col 80 of same line
Cursor off top: stays at top
|
	trmbeg DL33:,[DLOG33]

tp.flg	%fsmeol
tp.vsz	16.			; rather tiny
tp.hsz	80.
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^I
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^N
te.clr	tyo ^L
te.su	tyn ^J			; scroll up
tabend

trmend

subttl	DM1520 - Datamedia Elite 1520

	trmbeg DM15:,[DM1520]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho			; character display routine 
tm.up	1,tyn 37		; ^_
tm.dwn	1,tyn 12		; ^J
tm.fwd	1,tyn 34		; ^\
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo 31		; ^Y
tm.abs	3,call dm15mv
te.eol	tyo 35			; ^]
te.eos	tyo 13			; ^K
te.clr	tyo 14			; ^L
te.su	tyn ^J			; scroll up
tabend


dm15mv:	tyo 36			; ^^
	tyo 40(nh)
	jumpe nv,[tyo 1 ? xct .tmup+tb ? return]	; can't output Null
	tyo (nv)
	return

trmend

subttl	DM2500 - Datamedia Elite 2500

comment | optimizer must consider NL, not CR! |

	trmbeg DM25:,[DM2500]

%fdmcr==:%ff1			; Last char was CR (flag for DM2500 only)

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call d25ini
tr.fin	tyo 35			; ^] Exit should turn roll mode back on
tr.cho	ccho			; character display routine 
tr.tyo	dm25o			; Special output check for LF after CR.
;tr.zns	-lzt2,,zt2		; I suspect this causes lossage with NL --KLH
tm.up	1,tyn 32		; ^Z
tm.dwn	1,tyn 12		; ^J
tm.fwd	1,tyn 34		; ^\
tm.bck	1,tyn ^H
tm.nl	1,tyo ^M		; Note newline, not CR!
tm.hom	1,tyo 2			; ^B
tm.abs	3, call dm25mv
te.eol	tyo 27			; ^W
te.clr	tyo 036036	; ^^ is master clear, ^_ may be CLEOS sometimes.
			; sending twice takes care of 9600 baud timing.
te.icp	call dm25ic		; insert character
te.dcp	call dm25dc		; delete character
te.ilp	call dm25il		; insert line
te.dlp	call dm25dl		; delete line
tx.so	tyo 16		; ^N begins blink field
tx.sor	tyo 30		; ^X ends special field
tabend


tvar dm25lz		; Flag for 9600 baud.

d25ini:	xct .teclr+tb
	move a,speed		; get output speed
	setzm dm25lz
	cail a,960.		; If at 9600,
	 setom dm25lz		; set flag to do I/C kludgily.
	tyo 30			; exit any modes terminal was in
	return

; Special output hacking required since DM2500 will swallow
; up a LF immediately after a CR.  So, if we're trying to
; do that, output padding (a rubout) between CR and LF.

dm25o:	cain a,^M		; CR?
	 troa f,%fdmcr		; set CR flag, output the CR
	trzn f,%fdmcr		; last character CR?
	 pjrst tyobout		; no, output this character
	caie a,^J		; last character was CR, this one LF?
	 pjrst tyobout		; no, let it be
	movei a,177		; output pad character between CR and LF
	call tyobout		; ...
	movei a,^J		; now output LF
	pjrst tyobout		; ...

dm25mv:	tyo ^L
	movei d,(nh)
	trc d,140
	tyo (d)
	movei d,(nv)
	trc d,140
	tyo (d)
	return

; Insert character

dm25ic:	tyo ^P			; enter insert/delete mode
	skipn dm25lz		; Losing at 9600?
	 jrst [	tyn 34		; No, use normal insert w/o pad.
		tyo ^X		; and exit mode and return.
		return]
	tyn <40_9.>+177		; Follow each inserted-space with 1 pad.
	tyo ^X			; exit insert/delete mode
	caile a,3		; Must get back to orig pos, see how far.
	 jrst [	xct tb+.tmabs	; Abs move fastest, return to nh,nv.
		jrst .+2]
	tyn ^H			; Rel move best, backspace up.
	tyn 40			; Then over-write any garbage.
	addi h,(a)		; and update real cursor pos.
	return

; Delete character

dm25dc:	tyo ^P			; enter insert/delete mode
	skipe dm25lz
	 tyn <^H_9.>+177	; at 9600 follow each delete with 1 pad.
	skipn dm25lz
	 tyn ^H			; otherwise just delete.
	tyo ^X			; exit insert/delete mode
	return

; Delete line

dm25dl:	tyo ^P			; enter insert/delete mode
	skipe dm25lz
	 tyn <32_9.>+177	; at 9600, ^Z with 1 pad following.
	skipn dm25lz
	 tyn 32			; else just delete.
	tyo ^X			; exit insert/delete mode
	return

; Insert line
; This makes use of the mysterious ((30.-vpos)*speed-240.)/1440.
; calculation to get # pads.

dm25il:	pushae p,[b,a]
	movei a,30.
	subi a,(v)		; Boy will this lose for fake DM's!
	imul a,speed
	subi a,240.
	idivi a,1440.		; Now have # pads needed in A.
	move b,(p)		; Get # times to ins line.
	tyo ^P			; enter insert/delete mode
dm25i2:	tyo ^J
	tyn 177			; Pad as needed.
	sojg b,dm25i2
	tyo ^X			; exit insert/delete mode
	popae p,[a,b]
	return
trmend

subttl	DM3025 - Datamedia 3025A

	trmbeg DM30:,[DM3025]

tp.flg	%fspd			; No funnies! Tabs every 8, no autoNL.
tp.hsz	80.
tp.vsz	24.
tr.ini	call dm3ini
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J		; LF
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H		; BS
tm.tab	1,tyn ^I		; TAB
tm.hom	2,tyoesc "H
tm.abs	4,call dm3abs		; esc Y x+32. y+32.
te.eos	call dm3eos
te.eol	tyoesc "K
te.clr	call dm3clr
te.ilp	call dm3ilp
te.dlp	call dm3dlp
te.icp	call dm3icp
te.dcp	call dm3dcp
tx.so	zout [asciz "OA"]
tx.sor	zout [asciz "O@"]
tabend


dm3ini:	call dm3clr		; do Master Reset
	tyoesc "W		; disable Roll mode
	tyoesc "Q		; disable I/D (for now)
	tyoesc "U		; enable kbd (well who knows?)
	return

dm3abs:	tyoesc "Y
	tyo 40(nh)
	tyo 40(nv)
	return


dm3eos:	tyoesc "J		; send erase to end of screen
	caia			; skip over Master Reset!
dm3clr:	tyoesc "M		; Master Reset
	pad [.002]
	return


define dm3id time,-instr
	push p,a
	tyoesc "P		; enable I/D
	instr
	pad [time]
	sojg a,.-2
	tyoesc "Q		; disable I/D
	pop p,a
termin

dm3ilp:	dm3id .130, tyo ^J
	return
dm3dlp:	dm3id .130, tyoesc "A
	return
dm3dcp:	dm3id .006, tyo ^H
	return
dm3icp:	dm3id .006, tyo 40
	add h,a
	return

comment |

Updated timings from the manual (CBF):
Clear to End of screen = 2 ms, Insert char = 6 ms, Delete char = 6 ms,
Insert line = 130 ms, Delete line = 130 ms

       		DataMedia 3025A
       		---------------
           
           
       (ESC) @		Disable keyboard
       (ESC) A		Cursor up
       (ESC) C		Cursor right
       (ESC) E		Back tab
       (ESC) F v	Mode change (to mode v)
       (ESC) G		Read cursor
       (ESC) H		Home cursor
       (ESC) J		Erase EOS
       (ESC) K		Erase EOL
       (ESC) L		Transmit page
       (ESC) M		Master reset (also Home and EOS)
       (ESC) O v	Attribute change (to attribute v)
       (ESC) P		Enable insert/delete
       (ESC) Q		Disable insert/delete
       (ESC) S		Send function
       (ESC) T		Transmit line
       (ESC) U		Enable keyboard
       (ESC) V		Enable roll mode
       (ESC) W		Disable roll mode
       (ESC) Y x y	Position cursor to (x+32,y+32)
       (ESC) ]		Print
|


trmend

subttl	DP - Datapoint ("winning")

	trmbeg DP:,[DP,DATAPOINT]

comment |
	As near as I can make out, the datapoint requires some very
strange padding, apparently because it uses a shift register refresh memory.
The main weirdness is that the 4 basic movement controls (up/down/right/left)
can come in any sequence without padding, but the whole sequence must
be PRE-padded with $TPPCR chars (3 at 1200, 4 at 2400.)
	ITS does this by spewing out the pads at the beginning of every
%TDMV0.  This can have strange results, e.g. a home-down followed
by a line-starve can result in 7 pads sitting in between the home-down
and the line-starve!
	All the ZOUT sequences here are copied exactly from what ITS
sends regardless of the speed.
|

tp.flg	%fspd
tp.vsz	25.			; no. of lines displayable on the screen
tp.hsz	71.			; no. of characters per line

tr.wrp	call dpwrp		; Need to hack rel-move pre-padding.
tm.up	1,tyn 32		; See note about pre-padding these!
tm.dwn	1,tyn ^J
tm.fwd	1,tyn 30
tm.bck	1,tyn ^H

tm.cr	1,tyo ^M		; Requires no padding!?
tm.hom	1,tyo 35		; Requires no padding!?
;tm.hdn	3,zout [.byte 7 ? 34 ? 177 ? 177 ? 177 ? 0]	; doesnt work for loser

;te.clr	zout [.byte 7 ? 35 ? 37 ? 177 ? 177 ? 177 ? 0]
			; Note that TE.CLR is exactly the same as a HOME
			; followed by CLEOS.  The ZOUT is shown here to
			; document what the ITS sequence is.
te.eol	zout [.byte 7 ? 36 ? 177 ? 177 ? 177 ? 0]
te.eos	zout [.byte 7 ? 37 ? 177 ? 177 ? 177 ? 0]
tabend

dpwrp:	cain d,0
	 jumpe e,apopj
	addi c,4
	push cp,[4,,dppad]
	return

dppad:	tyn 177
	return


; For TDCRL, sequence has 0, 3, 4, 4 pads between ^M^J and CLEOL
; sequence, depending on whether $TPCCR is 2, 3, 4, or 5.  Of these
; values 3 corresponds to 1200 baud, 4 to 2400 baud.  In general
; that many pads are required for all cursor motion, but it's not clear
; when this padding is really necessary.
;  E.G. for non-losing datapoints, the CLEOL in the above TDCRL
; sequence has no padding following it!

comment | Loser datapoint
; On losers, must do a LF after a CR or a home-up in order to reset
; something called the SPOW latch.  This means if on bottom line, must
; move up a line before doing the CR, so that a LF is possible.
; If following a home-up, no further padding is necessary.

; Also, on losers there is no home-down, and ^M must be followed by
; $TPPCR pads, except within a TDCRL sequence which is the same
; as for non-loser except the non-loser's single-char CLEOL command
; is replaced by the loser's normal CLEOL sequence.

tm.hom	3,zout [.byte 7 ? 35 ? 35 ? 35 ? 0]

te.clr	zout [.byte 7 ? 35 ? 35 ? 35 ? 37 ? 37 ? 37 ? 37 ? 37 ? 0]
te.eol	zout [.byte 7 ? 36 ? 36 ? 36 ? 36 ? 0]
te.eos	zout [.byte 7 ? 37 ? 37 ? 37 ? 37 ? 37 ? 0]

|

; No trmend cause next is a trmtoo.

subttl	DATALOSER - Losing Datapoint

comment |
		Loser datapoint
On losers, must do a LF after a CR or a home-up in order to reset
something called the SPOW latch.  This means if on bottom line, must
move up a line before doing the CR, so that a LF is possible.
If following a home-up, no further padding is necessary.

Also, on losers there is no home-down, and ^M must be followed by
$TPPCR pads, except within a TDCRL sequence which is the same
as for non-loser except the non-loser's single-char CLEOL command
is replaced by the loser's normal CLEOL sequence.

|

	trmtoo DPLUZ:,[DATALOSER,DPLUZ]

tp.flg	%fspd
tp.vsz	25.			; no. of lines displayable on the screen
tp.hsz	71.			; no. of characters per line

tr.wrp	call dpwrp		; Need to hack rel-move pre-padding.
tm.up	1,tyn 32		; See note about pre-padding these!
tm.dwn	1,tyn ^J
tm.fwd	1,tyn 30
tm.bck	1,tyn ^H

;tm.cr	5,zout [.byte 7 ? ^M ? 177 ? 177 ? 177 ? 177 ? 0]
tm.cr	7,call dplcr
;tm.hom	3,zout [.byte 7 ? 35 ? 35 ? 35 ? 0]
tm.hom	5,zout [.byte 7 ? 35 ? 35 ? 35 ? ^J ? 32 ? 0]	; will this work?
;te.clr	zout [.byte 7 ? 35 ? 35 ? 35 ? 37 ? 37 ? 37 ? 37 ? 37 ? 0]
			; Note that TE.CLR is exactly the same as a HOME
			; followed by CLEOS.  The ZOUT is shown here to
			; document what the ITS sequence is.
te.eol	zout [.byte 7 ? 36 ? 36 ? 36 ? 36 ? 0]
te.eos	zout [.byte 7 ? 37 ? 37 ? 37 ? 37 ? 37 ? 0]
tabend

dplcr:	caml v,svmax	; at screen bottom?
	 zout [.byte 7 ? 177 ? 177 ? 177 ? 177 ? 32 ? 0]	; move up
	zout [.byte 7 ? ^M ? 177 ? 177 ? 177 ? 177 ? ^J ? 0]	; do CRLF
	camge v,svmax
	 tyo 32		; Unless at bottom, move back up.
	return

trmend

subttl	DTI - Data Terminal Corporation DTI

	trmbeg DTI:,[DTI]

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call dti2wn		; warn user of changes we make in keyboard
tr.tyi	undel			; make changes in keyboard for each char
tr.cho	ccho			; character display routine 
tm.up	1,tyn 13		; ^K
tm.dwn	1,tyn 12		; ^J
tm.fwd	1,tyn 14		; ^L
tm.bck	1,tyn 10		; ^H
tm.tab	1,tyn 11		; ^I
;tm.nl	1,tyo 37		; ^_
tm.cr	1,tyo 15		; ^M
tm.hom	1,tyo 36		; ^^
tm.abs	4,call dti2mv
te.eol	call dtieol		; tyoesc "T + padding
te.eos	call dtieos		; tyoesc "+ + padding
te.su	tyn ^J			; scroll up
te.icp	tynesc "Q
te.dcp	tynesc "W
;te.ilp	tynesc "E
;te.dlp	tynesc "R
;tx.vbl	call dti2vb
tx.so	tyoesc "^		; start blinking field
tx.sor	tyoesc "^		; same char to end blinking field!
tabend


dti2wn:	tyo ^^			; home
	setzb h,v
	xct .teeos+tb		; clear
	pjrst undelw		; Type std msg about DEL/_ switch.


dtieol:	tyoesc "T
	pad [.01]
	return

dtieos:	tyoesc "Y
	pad [.04]
	return


dti2mv:	tyoesc "=		; absmove command
	tyo 40(nv)		; Y, then
	tyo 40(nh)		; X.
	return

dti2vb:	tyoesc "^
	tyoesc "U
	tyo ^G
	tyoesc "X
	tyoesc "^
	return

trmend

subttl	FOX - Perkin-Elmer FOX-1100

	trmbeg FOX:,[FOX]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.tyi	undel			; exchange del, underscore
tr.ini	call foxini		; set tabs and warn user
tr.zns	-lzt3,,zt3		; AOBJN pointer to zone table with AX/AY test
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.ax	3,call foxah		; abs move in horizontal direction
tm.ay	3,call foxav		; abs move in vertical direction
tm.abs	6,call foxmv
te.eol	tyoesc "I		; not ESC K !!
te.eos	call foxeos
te.su	tyn ^J			; scroll up
tx.vbl	call foxvbl		; visible bell
tabend


; Transparent mode displays all spaces as small NU's; doing this briefly
; is quite flashy.
foxvbl:	tyo ^P			; ^P^B goes into transparent mode
	tyo ^B
	tyo ^P			; ^P^C exits debug mode.
	tyo ^C
	return

foxini:	tyoesc "K		; home, clear screen and clear tabs
	call settab		; Set tabs standardly.
	skipge warn		; inhibit warnings?
	 return			; yes, just return
	move a,[ascnt " Warning: interchanged Underscore and Delete keys.
          Newline Enable key should be OFF (up)."]
	pjrst stdwrn		; type message


; Clear to end of screen.
foxeos:	tyoesc "J
	pad [.12]
	return


; perform abs move
foxmv:	call foxav	; Drop thru to do H after doing V.

foxah:	tyoesc "Y		; is abs move in HORIZONTAL direction!
	tyo 40(nh)
	return
foxav:	tyoesc "X		; is abs move in VERTICAL direction!
	tyo 40(nv)
	return

trmend

subttl	H19 - Heathkit 19

	trmbeg H19:,[H19]

tp.flg	%fspd
tp.vsz	25.			; 25 lines, but only 24 usable
				; this is for getting the screen image right
tp.hsz	80.
tr.ini	call h19ini
tr.fin	call h19fin
tr.cho	scho0
tr.wi	h19wi
tr.wb	h19wb
tr.we	h19we
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.clr	tyoesc "E
te.sd	tynesc "I
te.su	tyn ^J
te.eim	tyoesc "@
te.lim	tyoesc "O
te.dcp	call h19dcp
te.ilp	call h19ilp
te.dlp	call h19dlp
tx.so	tyoesc "p
tx.sor	tyoesc "q
tabend


; H19WI - Initialize window stuff.  This exists to make the H19 wholine hack
; work.
h19wi:	setzb a,b		; TD.WIN args: A = minimum vertical,
				; B = minimum horizontal
	dmove c,smax		; TD.WIN arg: C = maximum vertical,
				; D = maximum horizontal
	movem c,theight		; keep THEIGHT = TVMAX - TVMIN + 1 after
				; adjustment below
	subi c,1		; normal terminal window doesn't include
				; status line
	movem c,tvmax		; so set terminal window to 24 lines
	movem c,svmax		; kludge: set screen vmax too since that line
				; isn't real.  this will, I hope, fix more
				; problems than it introduces.
	pjrst tdwin1		; set software window too


; H19INI - Clear screen, set modes, etc.
h19ini:	setzm padc		; RUBOUT doesn't win for padding - goes into
				; buffer and causes ^S^Q to be sent
				; The $[?2h is to enter it into Heath mode if
				; it were in ANSI mode.  Just echos if it were
				; already in Heath mode.
	zout [asciz "[?2hEGOq\wy8y9y5x1"]	; ]

	ifn its,[		; too many ITS losers are using h19
	  ife net,[		; CRTSTY
	move a,[ascnt "
                    Warning:

Using CRTSTY consumes more system resources and results in slower output
than standard ITS support.  You can use standard ITS support by typing
:TCTYP H19 instead of :CRTSTY H19.
"]
            call stdwrn
	    movei a,4.*30.	; wait 4 more seconds so message can be read
	    skipl jwarn
	     .sleep a,
	    ]]

	return


h19fin:	cain nv,24.		; on 25th line?
	 zout [asciz "îKY7 "]	; yes, clear it and position on 24th
	return

;;; Is 3 really the right number below??? --RWK
h19dcp:	caig a,3		; don't enter ANSI mode for just < 3 char
	 jrst [	tynesc "N
		return ]
	tyoesc "<		; enter ANSI mode
	tyoesc "[		; ]
	call tyodec
	tyo "P			; delete char
	zout [asciz "[?2h"]	; ] exit ANSI mode
	return

h19ilp:	caig a,1		; don't enter ANSI mode for just 1 line
	 jrst [	tyoesc "L
		pad [.019]	; 19ms padding
		return ]
	tyoesc "<		; enter ANSI mode
	tyoesc "[		; ]
	call tyodec
	tyo "L			; delete lines
	jrst h19idp

h19dlp:	caig a,1		; don't enter ANSI mode for just 1 line
	 jrst [	tyoesc "M
		pad [.019]	; 19ms padding
		return ]
	tyoesc "<		; enter ANSI mode
	tyoesc "[		; ]
	call tyodec
	tyo "M			; delete lines
h19idp:	push p,a
	fsc a,233		; float no. of lines
	fmpr a,[.019]		; 19ms per line
	pad a
	pop p,a
	zout [asciz "[?2h"]	; ] exit ANSI mode
	return

h19wb:	move t1,[wmin,,wsave]	; save current window
	blt t1,wsave+3		; ...
	move a,svmax		; TDWIN1 arg: A = minimum vertical
	addi a,1		; compsensate for -1 in H19WI
	movei b,0.		; TDWIN1 arg: B = minimum horizontal
	move c,a		; TDWIN1 arg: C = maximum vertical
	move d,shmax		; TDWIN1 arg: D = maximum horizontal
	dmovem a,tmin		; set terminal window
	dmovem c,tmax		; ...
	dmove nvh,a		; use absolute move to 25th line to
	call vtabs		; get to status line
	dmove vh,nvh		; update real cursor position
	call tdwin1		; update software window and capabilities
	tyoesc "p		; enter reverse video mode
	return

h19we:	tyoesc "q		; exit reverse video mode
	tyoesc "H		; home cursor to get off of 25th line
	setzb v,h		; ...
	setzb a,b		; TD.WIN args: A = minimum vertical,
				; B = minimum horizontal
	dmove c,smax		; TD.WIN arg: C = maximum vertical,
				; D = maximum horizontal
	dmovem a,tmin		; so set terminal window to 24 lines
	dmovem c,tmax		; ...
	move t1,[wsave,,a]	; TD.WIN args: A = minimum vertical,
	blt t1,d		; B = minimum horizontal,
				; C = maximum vertical,
				; D = maximum horizontal
	pjrst td.win		; restore window
trmend

subttl	H1500 - Hazeltine 1500

;Actually looks identical to MOD1, except this has CLEOL & CLEOS

; NOTE: the "Auto-LF" vs "CR" switch must be set to the "CR" position. 
; CR's will then move to beginning of line, and LF's down one line
; otherwise, CR's will do a newline, and LF's ignored completely. 

	trmbeg H15:,[H1500]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.tyi	undel			; interchange underscore and del
tr.cho	h15cho			; Highlight tildes.
tr.ini	call undlcw		; warn user of _/DEL switch
tm.abs	4,call h15mv
tm.up	2,tyn176 14		; ^L FF
tm.dwn	2,tyn176 13		; ^K VT
tm.fwd	1,tyn 20		; ^P DLE
tm.bck	1,tyn 10		; ^H BS
tm.cr	1,tyo 15		; ^M CR
tm.hom	2,tyo176 22		; ^R DC2
te.eol	tyo176 17		; ^O SI production version seems to use this
				;    instead of 36 ^^ that protype & mod1 used.
te.eos	tyo176 30		; ^X Can
te.su	tyn ^J			; scroll up
te.clr	tyo176 34		; ^\ GS  (mod1 is WEIRD...)(so is H1500)
te.ilp	tyn176 32		; ^Z Sub
te.dlp	tyn176 23		; ^S DC3
tx.so	tyo176 37		; ^_ US  called "foreground mode" is BRIGHT!
tx.sor	tyo176 31		; ^Y EM  called "background mode" is dim..
tabend


h15cho:	caie a,176		; Tilde?
	 pjrst ccho
	movei a,"^		; use bright caret.
	pjrst chstdo


h15mv:	tyo176 ^Q
	caile nh,30.		; if address is > 30. we can send it as is.
	 tyo (nh)
	caig nh,30.		; otherwise, map it into range 96. - 126.
	 tyo 140(nh)		; dont ask me why, but the manual says so
	tyo 140(nv)		; and it actually doesnt work to use 32.
	return

; no trmend cause next is a trmtoo

subttl	H1510 - Hazeltine 1510

	trmtoo H51:,[H1510]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho			; character display routine 
tm.abs	4,call h51mv
tm.up	2,tynesc 14		; ^L FF
tm.dwn	2,tynesc 13		; ^K VT
tm.fwd	1,tyn 20		; ^P DLE
tm.bck	1,tyn 10		; ^H BS
tm.cr	1,tyo 15		; ^M CR
tm.hom	2,tyoesc 22		; ^R DC2
te.eol	tyoesc 17		; ^O SI production version seems to use this
				;    instead of 36 ^^ that protype & mod1 used.
te.eos	tyoesc 30		; ^X Can
te.su	tyn ^J			; scroll up
te.clr	tyoesc 34		; ^\ GS  (mod1 is WEIRD...)(so is H1500)
te.ilp	tynesc 32		; ^Z Sub
te.dlp	tynesc 23		; ^S DC3
tx.so	tyoesc 37		; ^_ US  called "foreground mode" is BRIGHT!
tx.sor	tyoesc 31		; ^Y EM  called "background mode" is dim..
tabend

h51mv:	tyoesc ^Q
	caile nh,30.		; if address is > 30. we can send it as is.
	 tyo (nh)
	caig nh,30.		; otherwise, map it into range 96. - 126.
	 tyo 140(nh)		; dont ask me why, but the manual says so
	tyo 140(nv)		; and it actually doesnt work to use 32.
	return

trmend

subttl	H2000 - Hazeltine 2000

comment |
	This is the Hazeltine 2000 as described in the user's manual.
Needless to say, it may not work.
	The manual describes 12 remote functions which the H2000 can perform,
as follows.  Note that all except backspace (^H) require a "leadin code" of
176 (tilde), even ^M!

1. Transmit		^N
2. Address Cursor	^Q	Followed by X, Y
3. Home Cursor		^R
4. Delete Line		^S	**
5. Background Follows	^Y
6. Insert Line		^Z	**
7. Clear Screen		^\	**
8. Clear Foreground	^]	**
9. Print		^^
10. Foreground Follows	^_
11. Carriage Return	^M	(not stored - I think without leadin, it is)
12. Backspace Cursor	^H	No lead-in required.

NUL, LF, and DEL are ignored unless part of a cursor address command.

** = requires "between 5 and 6 millisec".  From 150-1200 baud, 1 padding
DEL is recommended; above 1200, "additional DEL chars are required". Barf.

It is worth noting that [11] and [12] do not appear on early Hazeltine doc,
before 1972.  Probably not implemented until 1972, perhaps even later.

If cursor is in bottom right corner, it will scroll up on the auto-NL.
|

	trmbeg H2000:,[H2000]

tp.flg	%fsmeol+%fspd
tp.vsz	27.
tp.hsz	74.
tr.ini	call h2kini
tr.cho	h2kcho		; Must intercept normal underscore, tilde. (137, 176)
;tr.zns	-lh2kzns,,h2kzns	; point to zone optimizer dispatch table
tm.abs	4,call h2kmv
tm.bck	1,tyn ^H
tm.nl	2,tyo176 ^M		; Newline, not CR
tm.hom	2,tyo176 22		; 176 ^R
te.clr	call h2kclr		; Needs padding!
te.ilp	call h2kilp		; ditto
te.dlp	call h2kdlp		; ditto
tx.bel	jfcl			; No bell!! TX.VBL is ok though.
tx.so	tyo176 37		; 176 ^_ enters "foreground mode" (bright)
tx.sor	tyo176 31		; 176 ^Y enters "background mode" (normal)
tabend

tvar h2kpdc			; # pads needed for clear-screen
tvar h2klpd			; # pads needed for line ins/del

h2kini:	pushae p,[a,b]
	move a,speed
	movei b,8.	; Assume 9600 baud
	caig a,480.	; skip if assumption correct
	 movei b,4	; less, use 4800
	caig a,240.	; else,
	 movei b,2	; 2400 baud speed.
	caig a,120.	; At 1200 Hazeltine claims only one pad required.
	 movei b,1	; So use that.
	caig a,10.	; and stick with 1 pad unless
	 movei b,0	; at horrible 10 cps rate.
	movem b,h2kpdc	; store # pads needed for clear-screen
	movem b,h2klpd	; and line ins/del
	xct .teclr+tb	; now clear screen
	popae p,[b,a]
	return

comment | Might reactivate this later for efficiency.

; zone optimization table
h2kzns:	h2kz0			; 0 - try NL (losing type)
	zthom			; 1 - home, then test.
	ztest			; normal.
lh2kzns==.-h2kzns

h2kz0:	move t1,@scrtab(v)	; Can't do NL unless current pos clear!
	cain t1,blchar
	 pjrst ztnl		; H, it's clear; go try NL.
	return
|


; "ordinary char" output.  Must substitute for underscore
; and tilde (176) - these are functional commands! Also
; highlight {, |, } since these are changed to [, \, and ].
h2kcho:
;	cain a,"_	; underscore?
;	 jrst [	movei a,"-	; replace with bright dash.
;		pjrst chstdo]
	cain a,176		; Tilde?
	 jrst [	movei a,""	; replace with bright double-quote.
		pjrst chstdo]
	cail a,173		; check for between {
	 caile a,175		; and }, inclusive
	  pjrst ccho		; nope
	subi a,40
	pjrst chstdo		; yep, highlight it.


h2kmv:	tyo176 21	; 176 ^Q <X> <Y>
	cain nh,	; Avoid MTY misfeature by sending equivalent for null.
	 tyo 140
	caie nh,
	 tyo (nh)	; This could lose on MTY for 0...
	tyo 40(nv)	; takes Y as modulo 40, so it's safe.
	return

h2kilp:	pushae p,[a,b]		; save AC
	move b,a
	move a,h2klpd
h2kil1:	tyo176 32		; 176 ^Z insert line, leaves cursor at beg.
	tyn 177
	sojg b,h2kil1
	popae p,[b,a]
	return

h2kdlp:	pushae p,[a,b]		; save AC
	move b,a
	move a,h2klpd
h2kdl1:	tyo176 23		; 176 ^S delete line, leaves cursor at beg.
	tyn 177
	sojg b,h2kdl1
	popae p,[b,a]
	return


h2kclr:	tyo176 34	; 176 ^\ Clear and home.
	push p,a
	skipa a,h2kpdc	; get # pads required.
	 tyo 177	; can use DEL.
	sojge a,.-1
	pop p,a
;	xct .tmhom+tb	; then home back (goddam turkeys can't ignore
	return		; a pad character??!!!!)

trmend

subttl	H2LOSE - Hazeltine 2000  NOTE: This specific page is for loser type!

comment |
	HAZELTINE 2000 SPECIFICATIONS:

    THE HAZELTINE 2000 IS A CRT DEVICE WITH A SCREEN WHICH IS
74 COLUMNS WIDE AND 27 LINES HIGH.  IT ALLOWS DIRECT CURSOR
ADDRESSING, SCREEN CLEARING, AND DELETE AND INSERT LINES.
CHARACTERS CAN BE OF TWO INTENSITIES: BRIGHT, KNOWN AS FOREGROUND
MODE, AND NORMAL, KNOWN AS BACKGROUND MODE.  THESE FEATURES WILL
BE DESCRIBED IN MORE DETAIL IN THE FOLLOWING.
    CARRIAGE RETURNS AND LINE-FEEDS ARE HANDLED DIFFERENTLY THAN
ON MOST TERMINALS:  CARRIAGE RETURN ACTS LIKE CR, LF DOES NORMALLY,
WHILE LINE-FEED IS IGNORED.  ALSO, THE TERMINAL DOES AN
AUTO-NEWLINE AT THE END OF THE LINE.  THE TERMINAL IS A SCROLLING ONE,
SO DOING A CR OR AUTO-NEWLINE ON THE LAST LINE MOVES EVERYTHING UP ONE
LINE.  Warning - a CR will delete (space over) the current char
position before moving back and down!!
    THE TERMINAL DOES AUTOMATIC CONVERSION FROM LOWER TO UPPER CASE,
CHANGING ALL CHARACTERS FROM ASCII 140 (OCTAL) TO 175 INTO ASCII 
100 TO 135.  ALL NON-GRAPHIC CHARACTERS APPEAR AS SPACES, WITH THE
FOLLOWING EXCEPTIONS: CR AND LF AS EXPLAINED ABOVE, AND DEL (RUBOUT)
WHICH, LIKE LF, IS IGNORED.  (NOTE THAT NUL AND BACKSPACE (^H)
APPEAR AS SPACES.) ALSO, CERTAIN CHARACTERS DO SPECIAL THINGS WHEN
PRECEDED BY ASCII 176, AS DISCUSSED BELOW.
    TO DO A BACKSPACE, AN UNDERSCORE (ASCII 137) IS USED.  IT MOVES
THE CURSOR BACK 1 SPACE WITHOUT DELETING THE CHARACTER
BACKSPACED OVER.  NOTE THAT THE TERMINAL DOES NOT ALLOW OVERSTRIKING,
SO BACKSPACING IS USUALLY USELESS, EXCEPT TO FACILITATE CURSOR 
POSITIONING.  ALSO, BACKSPACING DOES NOT WORK BEYOND THE BEGINNING OF
THE LINE.
    THE HAZELTINE'S BELL CANNOT BE FEEPED UNDER COMPUTER CONTROL.  IT
WORKS ONLY UNDER LOCAL CONDITIONS NOT RELEVANT TO THIS DISCUSSION.
(NOTE THAT, LIKE OTHER NON-GRAPHIC CHARACTERS, IT APPEARS AS A SPACE.)
    TO USE THE HAZELTINE'S SPECIAL FEATURES, AT LEAST 2 CHARACTERS
MUST BE SENT.  THE FIRST OF THESE IS ^> (ASCII 176).  IT IS FOLLOWED BY
ONE OF THE CHARACTERS LISTED BELOW:

CHAR.	ASCII	FUNCTION
^Q	021	CURSOR ADDRESSING (SEE BELOW)
^R	022	HOME (SENDS CURSOR TO UPPER LEFT CORNER)
^S	023	DELETE LINE (DELETE LINE WHICH CURSOR IS ON, 
		    MOVING THOSE BELOW IT UP ONE LINE, AND PUTTING
		    CURSOR AT BEGINNING OF LINE.)
^Y	031	ENTER BACKGROUND MODE (FOLLOWING CHARACTERS APPEAR IN 
		    BACKGROUND UNTIL  ^>,^^ IS RECEIVED.  NOTE
		    THAT THIS IS THE NORMAL STATE OF THE TERMINAL.)
^Z	032	INSERT LINE (INSERT A BLANK LINE AT CURSOR POSITION,
		    MOVING THOSE AT OR BELOW DOWN ONE LINE, AND
		    PUT CURSOR AT BEGINNING OF BLANK LINE.)
^\	034	CLEAR SCREEN (AND SEND CURSOR HOME)
^]	035	CLEAR FOREGROUND (CLEARS ONLY FOREGROUND CHARACTERS,
		    AND SENDS CURSOR HOME.)
^_	037	ENTER FOREGROUND MODE (FOLLOWING CHARACTERS APPEAR IN
		    FOREGROUND UNTIL ^>,^Y IS RECEIVED.)

    AFTER RECEIVING THE CHARACTERS TO DELETE OR INSERT A LINE OR TO
CLEAR (ALL OR FOREGROUND ONLY) A PAUSE OF ABOUT .13 SECONDS IS
NECESSARY.  (THE EXACT TIMING IS UNKNOWN, BUT AT 300 BAUD,
4 NULS DO THE TRICK, WHILE AT 110 BAUD, NONE ARE NEEDED.  NOTE THAT
ANYTHING OTHER THAN NULS CAUSES GARBAGE TO BE PRINTED.  ALSO, IF
MORE NULS THAN ARE NEEDED ARE SENT, THEY WILL APPEAR AS SPACES.)
    DIRECT CURSOR ADDRESSING IS DONE AS FOLLOWS:  THE CHARACTERS
^>,^Q ARE SENT FOLLOWED BY ONE CHARACTER FOR THE COLUMN AND
ONE FOR THE ROW.  THE COLUMNS ARE NUMBERED FROM 0 TO 73 (DECIMAL)
AND THE ROWS FROM 0 TO 26.  THE CHARACTER FOR THE ROW IS CONSIDERED
MODULO 32.  (NOTE THAT IT IS POSSIBLE TO ADDRESS THE CURSOR OFF
OF THE SCREEN, BUT THE STRANGE RESULTS ARE NOT RELEVANT HERE.)
    IF THERE ARE ANY QUESTIONS PLEASE CONTACT EITHER DBA OR DRH AT MC.
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	trmbeg H2L:,[H2LOSE]

tp.flg	%fsmeol+%fspd
tp.vsz	27.
tp.hsz	74.
tr.ini	call h2lini
tr.cho	h2lcho		; Must intercept normal underscore, tilde. (137, 176)
tr.zns	-lh2lzns,,h2lzns	; AOBJN to zone optimizer dispatch table
tm.abs	4,call h2lmv
tm.bck	1,tyn "_		; Underscore, not ^H! (gasp)
tm.nl	1,tyo ^M		; Newline, not CR
tm.hom	2,tyo176 22		; 176 ^R
te.clr	call h2lclr		; Needs padding!
te.ilp	call h2lilp		; ditto
te.dlp	call h2ldlp		; ditto
tx.bel	jfcl			; No bell!! TX.VBL is ok though.
tx.so	tyo176 37		; 176 ^_ enters "foreground mode" (bright)
tx.sor	tyo176 31		; 176 ^Y enters "background mode" (normal)
tabend


tvar h2lpdc			; # pads needed for clear-screen
tvar h2llpd			; # pads needed for line ins/del

h2lini:	pushae p,[a,b]
	move a,speed
	movei b,32.		; Assume 2400 baud
	caig a,120.		; skip if assumption correct
	 movei b,16.		; less, use 1200
	caig a,30.		; else,
	 movei b,4		; 300 baud speed.
	caig a,10.		; but this is possible...
	 movei b,0
	movem b,h2lpdc		; store # pads needed for clear-screen
	lsh b,-2		; get approx pads for line I/D (currently a guess)
	movem b,h2llpd		; save.
	xct .teclr+tb		; now clear screen
	popae p,[b,a]
	return

; Zone optimization table
h2lzns:	h2lz0			; 0 - try NL (losing type)
	zthom			; 1 - home, then test.
	ztest			; normal.
lh2lzns==.-h2lzns

h2lz0:	move t1,@scrtab(v)	; Can't do NL unless current pos clear!
	cain t1,blchar
	 pjrst ztnl		; H, it's clear; go try NL.
	return
	


; "ordinary char" output.  Must substitute for underscore
; and tilde (176) - these are functional commands! Also
; highlight {, |, } since these are changed to [, \, and ].
h2lcho:	cain a,"_		; underscore?
	 jrst [	movei a,"-	; replace with bright dash.
		pjrst chstdo]
	cain a,176		; Tilde?
	 jrst [	movei a,""	; replace with bright double-quote.
		pjrst chstdo]
	cail a,173		; check for between {
	 caile a,175		; and }, inclusive
	  pjrst ccho		; nope
	pjrst chstdo		; yep, highlight it.


h2lmv:	tyo176 21		; 176 ^Q <X> <Y>
	tyo (nh)		; This could lose on MTY for 0... may have to
				; go to col 1 and backspace instead.
	tyo 40(nv)		; takes Y as modulo 40, so it's safe.
	return

h2lilp:	push p,a
	call h2lil1
	sojg a,h2lilp
	pop p,a
	return

h2ldlp:	push p,a
	call h2ldl1
	sojg a,h2ldlp
	pop p,a
	return
h2lil1:	tyo176 32		; 176 ^Z insert line, leaves cursor at beg.
	caia

h2ldl1:	tyo176 23		; 176 ^S delete line, leave cursor at beg
	push p,a
	skipg a,h2llpd		; get # pads required.
	 pjrst popaj		; if none, return.
	tyo 0			; must pad with NULL - may lose for MTY.
	sojg a,.-1
	pop p,a
	pushae p,[nh,nv]
	setz nh,
	movei nv,(v)
	call h2lmv		; Move back to beg of line in case pads spaced!
	popae p,[nv,nh]		; the H2000 is a LOSER!!!!!!!!!!!!!!!!!!
	return

h2lclr:	tyo176 34		; 176 ^\ Clear and home.
	push p,a
	skipa a,h2lpdc		; get # pads required.
	 tyo 0			; must pad with NULL - may lose for MTY.
	sojge a,.-1
	pop p,a
	xct .tmhom+tb		; then home back (goddam turkeys can't ignore
	return			; a pad character??!!!!)

trmend

subttl	HP2600 - ALMOST A DATAPOINT

	trmbeg HP2600:,[HP2600]


tp.flg	0
tp.vsz	25.
tp.hsz	72.
tr.zns	-lztb,,ztb		; use zone table which includes BOT
tr.cho	ccho			; character display routine 
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^X
tm.bck	1,tyn ^Y
;tm.cr	1,tyo ^M		; CR SETS THE SPOW LATCH (BAD!) LF CLEARS IT
tm.nl	2,tyo <^M_9.>+^J
tm.hom	1,tyo ^]
te.eol	tyo ^^
te.eos	tyo ^_
te.su	tyn ^J			; scroll up
tabend


; ZTB - zone table for terminals with home down.
ztb:	ztest			; primary zone - no weird moves
	zthom			; home then test
	ztnl			; NL then test
	ztbot			; home down then test
lztb==:.-ztb

; ZTBOT - Home down and relative move check.
ztbot:	pushae p,[h,v]
	push cp,[1,,cc.bot]
	movei a,1		; start with home down cost
	move c,a		; ...
	move h,thmin
	move v,tvmax
	jrst ztestc

cc.bot:	tyo ^\			; home down
	move h,thmin
	move v,tvmax
	return

trmend

subttl	HP2645 - Hewlett-Packard 2645A

	trmbeg HP2645:,[HP2645,HP2640]

%hpack==:%ff1			; used for ENQ/ACK semaphoring

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call hpinit
tr.tyi	hptyi			; terminal input co-routine
tr.tyo	hptyo			; terminal output subroutine
tr.cho	ccho0			; character display routine 
tr.zns	-lzt3,,zt3		; AOBJN to zone table with AX/AY test
tr.wrp	call hpwrp
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.ax	[call hpahc] call hpah
tm.ay	[call hpavc] call hpav
tm.abs	[call hpabsc] call hpabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
te.eim	tyoesc "Q
te.lim	tyoesc "R
te.dcp	tynesc "P
te.ilp	tynesc "L
te.dlp	tynesc "M
tabend


; Initialization.
hpinit:	movei b,tyobout		; use TYOBOUT for sending reset command
	movem b,.trtyo+tb	; ...
	tyoesc "E		; reset HP2645
	pad [.5]		; pad a lot
	call tyofrc		; empty buffer
	movei b,hptyo		; if 480cps or greater the HP2545 has trouble
	move t1,speed		; keeping up and ENQ/ACK stuff is necessary
	cail t1,480.		; so use HPTYO instead of TYOBOUT
	 movem b,.trtyo+tb	; ...
	movei t1,70.		; set no. of characters between ENQ/ACK to
	movem t1,ack.nm		; 70 and initialize the countdown
	movem t1,ack.ct		; ...
	trz f,%hpack		; not waiting for an ack yet
	skipl jtab		; tabs?
	 call settab		; yes, set tab stops
	pjrst undelw


; Terminal input co-routine.
hptyi:	call tyibin
	cain a,^F
	 jrst [	trzn f,%hpack
		 jrst .+1
		jrst hptyi
		]
	caie a,177
	 cain a,137
	  xori a,177#137
	call tyipuc
	jrst hptyi

tvar ack.nm			; no. of characters to allow between HP2640
				; ENQ/ACKs
tvar ack.ct			; countdown for same

; HP2640 output routine to implement ENQ/ACK buffering.

hptyo:	sosle ack.ct		; time to send an ENQ?
	 pjrst tyobout		; no, use normal output subroutine
	call tyobout		; output the character
	push p,a		; save character
	andi a,377		; get 8-bits so can compare
	cain a,33		; ESC?
	 jrst hptyo1		; yes, don't send the ENQ in the middle of an
				; ESC sequence
	movei a,^E		; TYOBOUT arg: character
	call tyobout		; send ENQ
	call tyofrc		; make sure everything sent
	.i ack.ct=ack.nm	; reset no. of characters until ENQ count
	tro f,%hpack		; set flag to indicate waiting for ACK
IFN ITS,.suset [.sadf2,,[1_tyic]]	; undefer TTY input interrupts
					; this is only necessary at startup,
					; hopefully a better way will be found
	trne f,%hpack		; and wait until ACK received
IFN ITS, .hang
IFN TNX, call tnxhng		; Yecch!!

hptyo1:	pop p,a			; restore character
	return


; Calculate absolute horizontal move cost.
hpahc:	movei a,5
	cail nh,10.
	 addi a,1
	return

; Absolute horizontal move.
hpah:	zout [asciz "&a"]
	movei a,(nh)
	call tyodec
	tyo "C
	return


; Calculate absolute vertical move cost.
hpavc:	movei a,5
	cail nv,10.
	 addi a,1
	return

; Absolute vertical move.
hpav:	zout [asciz "&a"]
	move a,nv
	call tyodec
	tyo "Y
	return


; Calculate absolute move cost.
hpabsc:	movei a,7
	cail nh,10.
	 addi a,1
	cail nv,10.
	 addi a,1
	return

; Absolute move.
hpabs:	zout [asciz "&a"]
	movei a,(nv)
	call tyodec
	tyo "y
	movei a,(nh)
	call tyodec
	tyo "C
	return


; Wrap calculation.  Only hacks 1 out of 4 possible optimizations.  Backward
; movement isn't wrapped because of FSTFWD hackery and tabs.  Forward movment
; isn't wrapped because tabs aren't taken into consideration and because
; backspace doesn't wrap (though D does).  Finally, upward movement isn't
; wrapped because LF doesn't wrap (though B does).

; Arguments:
;   D	horizontal distance
;   E	vertical distance

hpwrp:	caile e,16.		; moving more than 16 lines down?
	 sub e,theight		; yes, use 24-n move ups instead
	return

; no trmend cause next is a TRMTOO


subttl	HP2621 - Hewlett-Packard 2621

	trmtoo HP2621:,[HP2621]

%hpack==:%ff1			; used for ENQ/ACK semaphoring

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call hp1nit
tr.tyi	hp1tyi			; terminal input co-routine
tr.tyo	hptyo			; terminal output subroutine
tr.cho	ccho0			; character display routine 
tr.zns	-lzt3,,zt3		; AOBJN to zone table with AX/AY test
tr.wrp	call hpwrp
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.ax	[call hpahc] call hpah
tm.ay	[call hpavc] call hpav
tm.abs	[call hpabsc] call hpabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
te.eim	tyoesc "Q
te.lim	tyoesc "R
te.dcp	tynesc "P
te.ilp	tynesc "L
te.dlp	tynesc "M
tabend


; Initialization.
hp1nit:	movei b,tyobout		; use TYOBOUT for sending reset command
	movem b,.trtyo+tb	; ...
	setzm padc		; pad with nulls because Dels really confuse
				; the poor machine if it tries to interrupt
				; partial chars during a reset
	zout [asciz "HJ"]	; clear screen - should other things go here
				; too?
	call tyofrc		; empty buffer
	movei b,hptyo		; if 480cps or greater the HP2545 has trouble
	move t1,speed		; keeping up and ENQ/ACK stuff is necessary
	cail t1,480.		; so use HPTYO instead of TYOBOUT
	 movem b,.trtyo+tb	; ...
	movei t1,70.		; set no. of characters between ENQ/ACK to
	movem t1,ack.nm		; 70 and initialize the countdown
	movem t1,ack.ct		; ...
	trz f,%hpack		; not waiting for an ack yet
	skipl jtab		; tabs?
	 call settab		; yes, set tab stops
	move a,[ascnt " Warning: Interchanged backquote (`) and Delete keys."]
	pjrst warn

; Terminal input co-routine.
hp1tyi:	call tyibin
	cain a,^F
	 jrst [	trzn f,%hpack
		 jrst .+1
		jrst hp1tyi
		]
	caie a,177		; Interchange underscore and backquote
	 cain a,140
	  xori a,177#140
	call tyipuc
	jrst hp1tyi

trmend

subttl	I100 - Infoton 100

	trmbeg I100:,[I100]

tp.flg	0
tp.flg	%fnicp+%fndcp		; Insert and Delete char are optional
tp.vsz	24.
tp.hsz	80.
tr.ini	call i10ini
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call i10abs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.clr	tyo ^L
te.su	tyn ^J
te.icp	tynesc "@
te.dcp	tynesc "P
te.ilp	tynesc "L
te.dlp	tynesc "M
; the standout mode on this terminal is unacceptable since setting standout
; mode constitutes a field definition and field defitions cause tabs to
; stop at them.
tabend

i10ini:	tyo ^O			; exit graphics mode
	tyoesc "l		; unlock keyboard
	tyoesc "n		; video on
	tyoesc "G		; clear all tab stops
	tyoesc "H
	tyoesc "J
	call settab		; set them
	move a,[ascnt " Use the CID option if your terminal has char insert/delete
 capabilities (block mode option).  ANL, CRNL, switches in rear should be off."]
	tlne f,%fnicp+%fndcp
	 pjrst stdwrn		; type message
	return

; Absolute move.
i10abs:	tyoesc "f		; Horizontal then Vertical, according
	tyo 40(nh)		; to MAP.  -CBF 12 Jan 80
	tyo 40(nv)
	return

trmend

subttl	I200 - Infoton 200

	trmbeg I200:,[I200]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho
tm.up	1,tyn ^\
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^Y
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^Z
tm.abs	3,call i2abs
te.eol	call i2eol
te.clr	tyo ^L
te.su	tyn ^J
tabend


; Direct cursor positioning.
i2abs:	tyo ^W
	tyo 40(nh)
	tyo 40(nv)
	return


; Clear to end of line.
i2eol:	jumpn h,seol
	tyo ^K
	return

trmend

subttl	I400 - Infoton 400

	trmbeg I400:,[I400]

; ANSI code sequences, but apparently you can leave out the "[".

tp.flg	0
tp.vsz	25.
tp.hsz	80.
tr.ini	call i40ini
tr.tyi	undel
tr.cho	ccho0
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	[call i40mvc] call i40mv
te.eol	tyoesc "N
te.eos	tyoesc "J
te.clr	zout [asciz "2J"]
te.su	tyn ^J
te.eim	zout [asciz "4h"]
te.lim	zout [asciz "4l"]
te.dcp	call i40dcp
te.ilp	call i40ilp
te.dlp	call i40dlp
tabend


i40ini:	zout [asciz "6h"]	; enter erase mode
	zout [asciz "4l"]	; exit insert mode
	zout [asciz "2Q"]	; enter "edit-extent" mode
	zout [asciz "2J"]	; clear screen
ifn 0,{
	zout [asciz "3g"]	; clear all tabs
	movei nh,8.
i40in1:	call i40mv
	movei h,(nh)
	tyoesc "I		; set tab stop
	addi nh,8.
	camg nh,shmax
	 jrst i40in1
	movei nh,0
}
	pjrst undelw


; Calculate absolute move cost.
i40mvc:	jumpe nv,i40mc1		; if vertical position is zero, send no digits
	movei a,5		; start with 5 for ESC-digit-semi-digit-H
	cail nv,10.		; vertical position require two digits?
	 addi a,1		; yes, make it 6
	jumpe nh,i40mc2		; if horizontal position is zero we're done
i40mc0:	cail nh,10.		; horizontal position require two digits?
	 addi a,1		; yes, account for that
	return
i40mc1:	movei a,4		; start with 4 for ESC-semi-digit-H
	jumpn nh,i40mc0
i40mc2:	subi a,2		; semi-digit not required, subtract 2
	return


i40mv:	tyo 33			; send escape
	movei a,1(nv)
	caie a,1
	 call tyodec
	jumpe nh,i40mv1
	tyo ";
	movei a,1(nh)
	caie a,1
	 call tyodec
i40mv1:	tyo "H
	return

i40dcp:	tyo 33			; send escape
	caie a,1
	 call tyodec		; send count
	tyo "P			; send command code
	return

i40ilp:	zout [asciz "Q"]	; exit "edit-extent" mode, send escape
	caie a,1
	 call tyodec		; send count
	zout [asciz "L2Q"]	; send command code, enter "edit-extent" mode
	return

i40dlp:	zout [asciz "Q"]	; exit "edit-extent" mode, send escape
	caie a,1
	 call tyodec		; send count
	zout [asciz "M2Q"]	; send command code, enter "edit-extent" mode
	return

trmend
~

subttl	I4380 - Infoton 4380

	trmbeg I4380:,[I4380]

tp.flg	0
tp.vsz	20.
tp.hsz	80.
tr.ini	call i43ini
tr.cho	ccho			; character display routine 
tr.wrp	call i43wrp
tr.nrm	call i43nrm
tm.up	1,tyn ^\
tm.dwn	1,tyn ^]
tm.fwd	1,tyn ^Y
tm.bck	1,tyn ^Z
tm.cr	1,tyo ^M
tm.hom	1,tyo ^H
te.eol	tyo ^K
te.clr	tyo ^L
te.su	tyn ^J			; scroll up
tx.so	tyo ^_
tx.sor	tyo ^O
tabend


; Initialization.
i43ini:	tyo ^L			; clear screen
	move t1,theight		; move calculation out of wrap
	lsh t1,-1		; optimizer
	movem t1,thh		; ...
	movnm t1,thhn		; ...
	move t1,twidth
	lsh t1,-1
	addi t1,1
	movem t1,thw
	movnm t1,thwn
	return

tvar thw
tvar thwn
tvar thh
tvar thhn


; Wrap optimizer.  Changes upward movement to wrapping downward movement
; and vice versa if that's cheaper.  Likewise for horizontal movement.
; Note that the terminal moves down (up) a line when it wraps going forward
; (backward).

; Arguments:
;   D	horizontal distance
;   E	vertical distance

i43wrp:	camle d,thw		; moving forward by more than 41 characters?
	 jrst [	sub d,twidth	; yes, change that into 80-n backward moves
		aoja e,i43w1	; and compensate for funny wraparound by moving
		]		; down one line
	camge d,thwn		; moving backward by more than 41 characters?
	 jrst [	add d,twidth	; yes, change that into 80-n forward moves
		soja e,i43w1	; and compensate for funny wraparound by moving
		]		; up one line
i43w1:	camle e,thh		; moving down by more than 10 lines?
	 sub e,theight		; yes, change that into 20-n upward moves
	camge e,thhn		; moving up by more than 10 lines?
	 add e,theight		; yes, change that into 20-n downward moves
	return


; Cursor movement normalizer.
i43nrm:	camge h,thmin		; past left margin?
	 jrst [	add h,twidth	; yes, wrapped to right margin
		subi v,1	; and up a line
		camge v,tvmin	; above top line?
		 add v,theight	; yes, wrapped to bottom
		return
		]
	camg h,thmax		; past right margin?
	 return
	sub h,twidth		; yes, wrapped to left margin
	addi v,1		; and down a line
	camle v,tvmax		; below bottom line?
	 sub v,theight		; yes, wrapped to top
	return

trmend

subttl	IBM 3101

	trmbeg IBM3101:,[IBM3101,3101]

tp.flg	%fnicp+%fndcp+%fnilp+%fndlp	; Model 10 doesn't have them
tp.vsz	24.
tp.hsz	80.
tr.ini	call ibmini
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "I
te.eos	tyoesc "J
te.su	tyn ^J
te.icp	call ibmicp
te.dcp	tynesc "Q
te.ilp	call ibmilp
te.dlp	call ibmdlp
tabend

ibmini:	pushae p,[a,b,nh,nv]
	setzb nh,nv		; home
	tyoesc "L		; clear world
	move b,shmax		; calculate the no. of tabs to set
	lsh b,-3		; ...
ibtab1:	movei a,8.		; move to next multiple of 8
	tyn 40			; ...
	tyoesc "0		; and set a tabstop there
	addi h,(a)		; and update actual cursor pos.
	sojg b,ibtab1
	popae p,[nv,nh,b,a]
	return

ibmicp:	tyoesc "P		; (enter insert mode?)
	tyn 40
	tyn 10			; move back (and exit insert mode?)
	return

ibmilp:	push p,a		; save repeat count
ibmil1:	tyoesc "N		; Insert Line
	pad [0.1]		; 100 Milliseconds (can't really be this bad?)
	soja a,ibmil1
	pop p,a			; restore repeat count
	return

ibmdlp:	push p,a		; save repeat count
ibmdl1:	tyoesc "O		; Delete Line
	pad [0.1]		; 100 Milliseconds (can't really be this bad?)
	soja a,ibmdl1
	pop p,a			; restore repeat count
	return

trmend

subttl	Intertec-S - Intertec Superbrain

	trmbeg Intert:,[INTERTEC-S]
			; I refuse to have a terminal called "Suberbrain"

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	tyo ^L
tr.cho	ccho
tm.up	1,tyo ^K
tm.dwn	1,tyo ^J
tm.fwd	1,tyo ^F
tm.bck	1,tyo ^H
tm.tab	1,tyo ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^A
tm.abs	4,call vtabs
te.eol	zout [asciz "~K"]
te.eos	zout [asciz "~k"]
te.clr	tyo ^L
tabend
trmend

subttl	INTEXT - INteractive Systems Corporation INtext

comment	|
	The INtext is a Perkin-Elmer Owl 1200 with custom braindamaged
microcode for the sake of INed, INactive's window editor.  Caltech's
infamous Booth Computing Center purchased a roomful of them (and then
some...).  They're a lot better than the alternatives (ADM3As and
(yech!!!) IBM3101s).  Somehow a few of them manage to stray from their
assigned chore of (you guessed it!) wordprocessing and find their way
into ARPAland.

This entry was coded by Eric P. Scott <EPS@UCLA-Security> of Caltech
High Energy Physics since he let himself get talked into it.  "Never
again!"  (famous last words)

BTW, everything I know about the INtext was determined empirically.
There's no padding code in here even though some functions require it.
There are a lot of neat "features" (like windowing, box drawing
characters, and a few other random non-ASCII displayable characters)
which I don't take advantage of.  There are several standout modes
("color1" on "color2" where "colori" is one of black, white, gray)
each optionally blinking, but the attribute character takes up a space
in screen memory.
|
tyo26=:tyo 26_9.		; INtext's "magic character" is ^V
tyn26=:tyn 26_9.

	trmbeg INTEXT:,[INTEXT]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	call INtini
tr.tyi	undel			; _/DEL are backwards
tr.cho	ccho			; wrap at right margin
tm.up	1,call INtup		; 1,tyn ^\
tm.dwn	1,call INtdwn		; 1,tyn ^J
tm.fwd	1,call INtfwd		; 1,tyn ^^
tm.bck	1,call INtbck		; 1,tyn ^_  (^H is destructive bs)
tm.tab	1,call INttab		; 1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^Z
tm.abs	3,call INtabs
te.eol	call INteol
te.clr	tyo ^L			; this is really "clear window," but the
				; window is the full screen initially
te.su	call INtdwn		; tyn ^J
te.icp	call INticp		; tyn26 "3
te.dcp	call INtdcp		; tyn ^R
te.ilp	call INtilp		; tyn ^P
te.dlp	call INtdlp		; tyn ^Q
tabend

; Initialization.
INtini:	setzm padc		; Rubout is a "printing" character
	tyo26 "9		; Reset everything
	call tyofin
	sleep 5.		; I hope half a second is enough
	pjrst undelw		; Standard _/DEL swap warning

; Relative cursor motion.  The sequence ^K count+32. chr
; repeats chr count times.
INtup:	caig a,3
	 jrst [	tyn ^\
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^\
	return

INtdwn:	caig a,3
	 jrst [	tyn ^J
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^J
	return

INtfwd:	caig a,3
	 jrst [	tyn ^^
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^^
	return

INtbck:	caig a,3
	 jrst [	tyn ^_
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^_
	return

INttab:	caig a,3
	 jrst [	tyn ^I
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^I
	return
; ^Y is backtab, but CRTSTY doesn't hack 'em.

; Absolute move.
INtabs:	tyo ^O
	tyo 40(nv)
	tyo 40(nh)
	return

; Clear to EOL.  The two-character sequence ^V # does this,
; but an implicit CR follows.
INteol:	tyo26 "#
	move h,thmin		; terminal gratuitously did a CR
	return

; Insert character position.
INticp:	caig a,2
	 jrst [ tyn26 "3
		return ]
	tyo ^K
	tyo 40(a)
	tyo26 "3
	return

; Delete character position.
INtdcp:	caig a,3
	 jrst [	tyn ^R
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^R
	return

; Insert line position.
INtilp:	caig a,3
	 jrst [	tyn ^P
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^P
	return

; Delete line position.
INtdlp:	caig a,3
	 jrst [	tyn ^Q
		return ]
	tyo ^K
	tyo 40(a)
	tyo ^Q
	return

trmend

subttl	IQ120 - Soroc IQ 120

	trmbeg IQ120:,[IQ120]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	tyoesc "*		; clear all and set unprotected
tr.cho	ccho
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call iqabs
te.eol	tyoesc "T
te.eos	tyoesc "Y
te.clr	tyoesc "+
te.su	tyn ^J			; scroll up
tabend

; Absolute move.
iqabs:	tyoesc "=
	tyo 40(nv)
	tyo 40(nh)
	return

; no TRMEND because next is TRMTOO

subttl	IQ140 - Soroc IQ 140

	trmtoo IQ140:,[IQ140,ADM31]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho0
tr.ini	tyoesc "*		; same incantion as IQ120?
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call iqabs
te.eol	tyoesc "T
te.eos	tyoesc "Y
te.clr	tyoesc "+
te.su	tyn ^J
te.eim	tyoesc "9
te.lim	tyoesc "8
te.icp	tynesc "Q
te.dcp	tynesc "W
te.ilp	call tviilp
te.dlp	call tvidlp
tabend

tviilp:	push p,a
tvilp1:	tyoesc "E
	pad tvipad
	sojg a,tvilp1
	pop p,a
	return

tvidlp:	push p,a
tvilp2:	tyoesc "R
	pad tvipad
	sojg a,tvilp2
	pop p,a
	return

; this is explicitly not a literal so it can be safely patched
tvipad:	.01			; start out at 10 milliseconds per

;;; no TRMEND because next is TRMTOO

subttl	TVI912

	trmtoo TVI912:,[TVI912,TVI920]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho
tr.ini	tyoesc "*
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call iqabs
te.eol	tyoesc "T
te.eos	tyoesc "Y
te.clr	tyoesc "+
te.su	tyn ^J
te.icp	tynesc "Q
te.dcp	tynesc "W
te.ilp	call tviilp
te.dlp	call tvidlp
tabend

;;; no TRMEND because next is TRMTOO

subttl	ABM85

	trmtoo ABM85:,[ABM85,KIMTRON]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho0
tr.ini	tyoesc "*
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call iqabs
te.eol	tyoesc "T
te.eos	tyoesc "Y
te.clr	tyoesc "+
te.su	tyn ^J
te.eim	tyoesc "Q
te.lim	tyoesc "r
te.dcp	tynesc "W
te.ilp	call tviilp
te.dlp	call tvidlp
tabend

trmend

subttl	Inteligent Systems Corp 8000

	trmbeg ISC800:,[ISC8000]

tp.flg	0
tp.vsz	47.
tp.hsz	80.
tr.ini	call iscini
tr.cho	ccho
tm.up	1,tyn ^\
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^Y
tm.bck	1,tyn ^Z
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^H
tm.abs	3,call iscabs
te.eol	call isceol
te.clr	tyo ^L
te.su	tyn ^J
te.ilp	tynesc ^U
te.dlp	tynesc ^V
te.icp	call iscicp
te.dcp	call iscdcp
tx.so	tyo ^]_9+^U
tx.sor	tyo ^]_9+^W
tx.vbl	zout [asciz ""]	; green background and then back

tabend


;;; set initial hieght
iscini:	move a,sheight		; get selected neight
	caig a,24.		; 24. or under, select 24 line mode
	 tyo ^N
	caile a,24.
	 tyo ^O
	return


; Direct cursor positioning.
iscabs:	tyo ^C
	tyo (nh)
	move t1,sheight
	caig t1,24.		; is the screen half height?
	 jrst [	move t1,nv	; if so, then double the address
		add t1,nv
		tyo 1(t1)
		return ]
	tyo (nv)
	return


; Clear to end of line.
isceol:	jumpn h,seol
	tyo ^K
	return

iscicp:	tyoesc "Q
	tyn 40
	tyoesc "[		; try a null command to get us out
	add h,a			; indicate we've moved the cursor
	return

iscdcp:	tyoesc "Q
	tyn 177
	tyoesc "[		; try a null command  to get us out
	return

trmend

subttl	Synertek KTM-2/80

trmbeg KTM2:,[KTM2]

tp.hsz	80.		; Large size screen (there is also a 40 char version)
tp.vsz	24.
tr.ini	call ktmclr
tm.up	1,tyo 13		; ^K
tm.dwn	1,tyo 12		; ^J
tm.fwd	1,tyo 11		; ^I
tm.bck	1,tyo 10		; ^H
tm.abs	4,call ktmv

te.clr	call ktmclr
te.eos	call ktmeos

tx.so	tyoesc "R		;sets reverse video for capitals only
tx.sor	tyoesc "r		;clears the above

tabend

ktmv:	tyoesc "=		; Esc = selects absolute cursor addressing,
	tyo 40(nv)		; First send 32. + Y (to get out of control chars),
	tyo 40(nh)		; then 32. + X
	return

ktmclr:	tyo 14			;^L clears the screen, but 
	tyo 377		 	;a padc must be sent
	return

ktmeos:	tyoesc "J		;Clear eos requires padding sometimes too
	tyo 377
	return
trmend

subttl	KTM3 - KTM-3/80

	trmbeg KTM3:,[KTM3]

tp.vsz	24.
tp.hsz	80.
tr.ini	call undlcw
tr.tyi	undel
tr.cho	ccho
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
;tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call ktmabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.clr	tyo ^Z
te.su	tyn ^J
tx.vbl  call k3vbl
tabend


ktmabs:	tyoesc "=
	tyo 40(nv)
	tyo 40(nh)
	return

k3vbl:  tyoesc "T		; VISBEL - print control chars mode
	tyo 7			; leave little bell... this works for
				; NON-STANDARD KTM-3 owned by LRH and ELF
				; (changes in KTM-3 by LRH)
	tyoesc "/		; control chars DON'T print mode
	tyo 10			; but the esc-/ did, so be nice
	tyo 10			; and back up over it so you can
	tyo 40			; obliterate the esc
	tyo 40			; and the /
	tyo 10			; then back up
	tyo 10			; again!
	return

trmend

subttl	LP - Cretinous NLS LineProcessor

	trmbeg LP:,[LP]

tr.smo	lpsmo		; Can simulate!!!!
tr.smf	lpsmf
tr.smi	lpsmi

tp.flg	%fsmeol
tp.vsz	24.
tp.hsz	80.
tr.tyi	lptyi			; Check input for reset-button push.
tr.ini	call lpinit
tr.fin	call lpfin		; when done return to TTY simulate mode.
tm.bck	1,tyn ^H
tm.abs	4,call lpmv		; LP has only abs move!
te.eol	call lpeol
te.clr	call lpclr
te.ilp	call lpilp
te.dlp	call lpdlp
tx.so	tyoesc 56		; Begin bright mode
tx.sor	tyoesc 57		; End bright
tabend

lpfin:	tyoesc 60	; Leave coord mode
	tyoesc 51	; and reset LP.
	push p,a
	move a,lpadc
	tyn 177
	pop p,a
	return

; Routine to initialize & interrogate the LP, and compute
; various garbage necessary to bypass its stupidity.  Must
; be called with interrupts OFF!

lpinit:	pushae p,[a,b,c]
IFN ITS,.reset tyic,		; Clear input buffer.
IFN TNX,move a,ttyjfn ? cfibf
	tyoesc 55		; First send "interrogate" command.
	call tyofrc
	setzm lpinwc		; clear wait count.
lpini1:	call lpinwt
	caie a,34		; Loop til find LP escape sequence
	 jrst lpini1
	call lpinwt
	caie a,46		; of type "reply to interrogate".
	 jrst lpini1
;	call tyibin		; Get xmax+40
	call lpinwt
	subi a,40		; get maximum X coord
	caige a,		; "Big coordinate"? (1st char 36)
	 call lprbcd		; Yes, get it.
	movem a,thmax		; Save
	movem a,shmax
	addi a,1
	movem a,swidth
	movem a,twidth
	movem a,wwidth
;	call tyibin		; Now get max Y
	call lpinwt
	subi a,40
	caige a,
	 call lprbcd
	movem a,tvmax
	movem a,svmax
	movei b,1(a)
	movem b,sheight
	movem b,theight
	movem b,wheight

;	call tyibin		; Get lptype stuff
	call lpinwt
	lshc a,-4		; Get leftmost 3 bits
	andi a,7		; as LP type
	movem a,lptype
	lshc a,4		; Now recover rightmost 4
	andi a,17
	caile a,6
	 movei a,6		; Force down to 6.
	movem a,lptypd		; as type of terminal actually driving.

;	call tyibin		; Get Dtim for scrolling
	call lpinwt
	subi a,40		; Get #
	movem a,lpadtm		; save

;	call tyibin
	call lpinwt
	subi a,40		; Get pad factor F
	movem a,lpfspd

define lpad num,sto	; Little macro for tedious pad calcs
	skipge a,num
	 move a,lpadtm
	idiv a,lpfspd
	addi a,1	; NLS always does (#/f)+1
	movem a,sto
termin
	move c,lptypd		; Get idx into pad tables
	move a,lpadl		; Compute
	addi a,14.
	lpad a,lpadl		; # pads for a scrolling LF.
	lpad lpdtbd(c),lpadd	; Padding for Delete Line
	lpad lpdtbi(c),lpadi	; padding for Insert Line
	lpad lpdtbc(c),lpadc	; padding for Clear Screen & Reset

	; Params all set, now zap LP state.
	tyoesc 51		; Reset LP
	skipa a,lpadc
	 tyo 177
	sojge a,.-1
	tyoesc 60		; Turn off coordinate mode!
	tyoesc 40		; And set a position to stop tracking!
	tyo 40			; X pos at 0
	move a,svmax
	tyo 40(a)		; Y pos at 0
	call tyofrc		; Force stuff out.
	popae p,[c,b,a]
	return

	; Read a "big coordinate"
lprbcd:
;	call tyibin
	call lpinwt
	subi a,40
	movei b,-40(a)
;	call tyibin
	call lpinwt
	subi a,40
	subi a,40
	lsh b,6
	addi a,(b)
	return

tvar lpinwc
lpinwt:	call tbin		; Pull in a char (or try to)
	cail a,
	 return
	aos a,lpinwc
	caile a,20.		; tolerate 20 secs wait
	 jrst [	zout [asciz "
No response to INTERROGATE; you're no lineprocessor!
"]
		call tyofrc
		jrst logout]
	sleep 10.		; Wait for a sec
	jrst lpinwt

tvar lpfspd	; Pad factor "F" for this LP, as returned from interrogate
tvar lptype	; Type of LP, as ditto.
	; 0= Complete alpha LP with copy printer receiver for cassette drive
	; 2= LP with Mouse, Keyset, Printer
	; 6= Graphics LP with Tektronix 4014
	; 7= Graphics LP with Tektronix 4012
tvar lptypd	; Type of this LP's display, as ditto.
	; 1= Delta Data 5200 (not supported any more)
	; 2= Hazeltine H2000 (ditto)
	; 3= Datamedia 2500
	; 4= Lear Siegler ADM-2 (ditto)
	; 5= Datamedia 4000
	; 6=    "       "    with scroll window capability

	; Padding factor tables, indexed by LPTYPD. -1 means use DTIM.
	;   DD   Hzl  DM25  LS   DM4  DM4
lpdtbc:	0 ?  5  ? 6 ?  1  ? 17. ? -1 ? -1	; "Clr" - time to clear screen
lpdtbd:	0 ? 80. ? 7 ?  1  ? 17. ? -1 ? -1	; "Del" - time to delete a line
lpdtbi:	0 ?  0  ? 7 ? 30. ? 17. ?  0 ?  0	; "Ins" - time to insert a line

tvar lpadtm	; This is "DTIM" as returned by LP interrogate.
tvar lpadd	; # pads for line delete
tvar lpadi	; # pads for line insert
tvar lpadc	; # pads for screen clear
tvar lpadl	; # pads for a scrolling LF.

; Note that DM4000 type LP's can pass "big coordinates" where the usual
; form X+40 is replaced by 36, <high 6 bits>+40, <low 6 bits>+40.
; This is only necessary for coords > 135 octal.
; The following EP->LP commands allow big coords:
;	Position, Pushbug(markit), Cline.
; And the following for LP->EP:
;	Response to Interrogate, "Big chars".
; Also note that lineprocessor coords have Y inverted, i.e. 0,0 is lower left!


lpmv:	tyoesc 40
	caile nh,135
	 jrst [	tyo 36
		movei d,(nh)
		lsh d,-6
		tyo 40(d)
		movei d,(nh)
		andi d,77
		tyo 40(d)
		jrst .+2]
	tyo 40(nh)	; X is okay...
	move d,svmax
	subi d,(nv)	; but Y needs mapping.
	caile d,135
	 jrst [	tyo 36
		push p,d
		lsh d,-6
		tyo 40(d)
		pop p,d
		andi d,77
		tyo 40(d)
		return ]
	tyo 40(d)
	return


lpeol:	push p,a
	hrrz a,scrtab(v)+1	; find address+1 of  the last pos.
	subi a,1
lpeol1:	caige a,@scrtab(v)	; compare with currnt position
	 jrst lpeol9		; win, all blank aready!
	skipl t1,(a)		; check blank or not
	 cain t1,blchar
	  soja a,lpeol1
	addi a,1
	subi a,@scrtab(v)	; Find # blanks to write.
	caile a,30.		; if over 30 blanks requied,
	 caie h,0		; and on left margin, use del/ins!
	  jrst lpeol2
	movei a,1
	xct .tedlp+tb		; on left margin! simply delete current line
	caml v,tvmax
	 jrst lpeol9		; If no lines below, can return here.
	movei a,1
	xct .teilp+tb
	jrst lpeol9

lpeol2:	push p,nh
	move nh,h		; save current pos
	addi h,(a)		; update to new.
	tyoesc 43
	tyo 40(a)
	push p,b
	idiv a,lpfspd		; Divide N by pad factor
	addi a,1
	pop p,b
	tyn 177			; pad out as necessary.
	call lpmv		; now move cursor back
	movei h,(nh)
	pop p,nh
lpeol9:	pop p,a
	return


	; Insert Line Position
lpilp:	pushae p,[a,b]
	move b,a
lpil1:	tyoesc 45
	move a,lpadi		; get no. of pads to send
	tyn 177
	sojg b,lpil1
	popae p,[b,a]
	return

	; Delete Line Position
lpdlp:	pushae p,[a,b]
	move b,a
lpdl1:	tyoesc 44
	move a,lpadd
	tyn 177
	sojg b,lpdl1
	popae p,[b,a]
	return

lpclr:	setzb nh,nv	; Clear and home up.
lpclr0:	push p,a
	tyoesc 50	; Clear screen
	move a,lpadc
	tyn 177
	pop p,a
	return

	; LPTYI - input chars are checked thru this.  Called at TYI
	; interrupt level.
lptyi:	push p,[lptyi]
	call tyibin
	caie a,176		; If 176 seen, skip to handle.
	 pjrst tyipuc		; nope, return to output character

	; Special LP interrupt. Called at TTYI interrupt level when 176 seen.
	call tyibin
	cain a,177		; "system reset"?
	 return			; for now, simply ignore.
	cain a,41		; reporting error?
	 jrst lpspc3		; must slurp up.
	push p,a
	movei a,176
	call tyipuc		; none of above, pass on both 176 and following
	pop p,a
	pjrst tyipuc

lpspc3:	call tyibin
	caile a,40+20
	 movei a,40+20
	push p,b
	movni b,-40(a)
	hrlzs b
	call tyibin
	movem a,lpertb(b)
	aobjn b,.-2
	pop p,b
	return			; return when error all slurped.

tvar lpertb(20)

; NLS LP simulation routines!!

svar lprqrs	; -1 if input side requesting "reset" on finalize.
svar lpcmod	; -1 if in coordinate mode, send stuff escorted.
svar lpmtrk	; -1 if "mouse" being tracked.
svar lpmx	; "mouse" X pos
svar lpmy	; "mouse" Y pos
svar lptysx	; TTY simulate window X cursor pos (saved NH)
svar lptysy	; TTY simulate window Y cursor pos (saved NV)
svar lptybg	; # of 1st line in TTY simulate window.
svar lptyln	; # lines in TTY simulate window.
svar lpstki	; LP bug stack index
svar lpbstk(10)	; LP bug stack

comment |
	FJW & SPK want the following definitions:

	^H - Back Character
	^A - Beginning of current real line
	^E - End of current real line
	^F - Forward Character
	^N - Down real line (absolute vertical)
	^P - Up real line (absolute vertical)

	$< - Beginning of 20-line display (upper left)
	$> - End of 20-line display (lower right)
	$A - Back to beginning of this sentence (or next previous sentence)
	$H - Back to beginning of this word (or next previous word)
	$E - Forward to end of this sentence (or next sentence)
	$F - Forward to beginning of next word
	$[ - Back to beginning of this paragraph (or next previous
	     paragraph)
	$] - Forward to beginning of next paragraph

	( $ means <esc> or Meta- )

Character, word, sentence, paragraph, and ^U have the same meaning as
for EMACS. 

|

; LPSMI - LP output-to-STY simulate co-routine
; Examine TTY input, and output to STY as appropriate.

lpsmi:	call smiget		; Get character
	push p,[lpsmi]		; Return to above for infinite loop.
	skipn lpcmod		; In coordinate mode?
	 pjrst smibout		; Nope, just feed out normally.

	; Coordinate mode, check for special local kbd commands.
lpsmic:	trne a,%txmta		; Meta-bit set?
	 jrst lpmeta		; Yes, go check for meta-command.
	caige a,40		; Coord mode! hacking a ctl?
	 jrst lpctl		; Yes, off to hack.
	pjrst smibout		; Nope, output normally.

lpctl:	call @lpctlv(a)		; process control char.
lpctlr:
IFN SINT,{
	; Idea of this code is to "wake up" the SMO module so that
	; it will finalize any alterations made to the cursor position.
IFN ITS,.suset [.siifpir,,[1_pyi]]	; After handling, ensure output kicked.
IFN TNX,{
	movei a,.fhslf
	push p,b
	move b,[1_<35.-smochn>]
	iic			; Trigger SMO interrupt.
	pop p,b
} ; IFN TNX
} ; IFN SINT
IFE SINT,{
	.err LP simulate code loses for SINT=0
	; For this to work, have to figure out some way of poking the
	; inferior fork into action, without screwing it up.  Probably
	; the only way to do this is to define some random PSI which
	; causes the inferior fork to examine the PC interrupted from, and
	; do appropriate re-finalization things if it turns out that
	; it was doing nothing but waiting for input.

} ;IFE SINT

	return

comment |
Summary of current LP simulation user interface

General:
^Q	Quote next char
^G	Reset
^U	Repeat next thing 4 times

Mouse moving commands:
^P	Up
^N	Down
^F	Right
^H	Left
^A	Beg of text on line
^E	End of text on line
^S	Search forward for next char
^R	Search backward for next char
ESC	Set Meta/Edit bit for next char
M-F	Forward word
M-H	Backward word
M-<	Beg of text area
M->	End of text area

Mouse buttons
^B	CMD RPT
^X	CMD DEL
^D	CA (OK)
|

lpctlv:	repeat 40,smibout		; default is to simply output.

tmploc lpctlv+^U,{lpmrpt}	; ^U = repeat next char 4 times.

lpmrpt:	push p,[4]
lpmrp1:	call smiget
	cain a,^U		; Another one?
	 jrst [	movei a,4
		imulm a,(p)
		jrst lpmrp1]
	push p,a
lpmrp2:	move a,(p)
	call lpsmic
	sosle -1(p)
	 jrst lpmrp2
	sub p,[2,,2]
	return

tmploc lpctlv+033,{lpmesc}	; ESC -> set meta bit in next char.
				; actually just dispatch as if set.

	; Jump here if char is metized.
lpmesc:	call smiget	; Jump here for ESC - get next, then handle.
lpmeta:	andi a,177
	cail a,"a
	 caile a,"z
	  caia
	   trz a,40
	cain a,"F	; Forward word
	 jrst [	call lpmwf
		jrst lpctlr]
	cain a,"H	; Backward word
	 jrst [	call lpmwb
		jrst lpctlr]
	cain a,"<	; Move to beg of text area
	 jrst [
		;move a,svmin
		movei a,0
		addi a,4
		camle a,svmax
		 move a,svmax
		movem a,lpmy
		setzm lpmx
		pjrst lpctlr]
	cain a,">		; Move to end of text area
	 jrst [	move a,svmax
		movem a,lpmy
		move a,shmax
		movem a,lpmx
		pjrst lpctlr]
	cain a,"H	; Move back word
	 jrst [return]
	cain a,"F	; Move forward word
	 jrst [return]
	pjrst smibout		; Matched none, simply output it.

tmploc lpctlv+002,{lpcrdo}	; ^B (CMD RPT)
tmploc lpctlv+004,{lpcrdo}	; ^D (CA)
tmploc lpctlv+030,{lpcrdo}	; ^X (CMD DEL)

	; LP Coord Output - "Escort" controls.
lpcrdo:	push p,a
	movei a,34
	call smibout
	movei a,43
	call smibout
	pop p,a
	addi a,140	; keyboard char.
	call smibout
	move a,lpmx
	call lpsbcd
	move a,svmax
	sub a,lpmy	; Y coord is inverted for LP.
			; Drop thru to "call" LPSBCD.

lpsbcd:	caig a,135
	 jrst lpsbc7
	push p,a
	movei a,36	; Big coord escape
	call smibout
	move a,(p)
	lsh a,-6
	addi a,40
	call smibout
	pop p,a
	andi a,77
lpsbc7:	addi a,40
	pjrst smibout

tmploc lpctlv+^Q,{lpmqot}	; Quoter
lpmqot:	call smiget		; Get next char
	pjrst smibout		; and output no matter what.

tmploc lpctlv+^G,{lpmrst}	; ^G - reset
lpmrst:	setom lprqrs		; Request reset.
	return

tmploc lpctlv+^P,{lpmup}	; up
tmploc lpctlv+^N,{lpmdwn}	; down
tmploc lpctlv+^F,{lpmfwd}	; right
tmploc lpctlv+^H,{lpmbck}	; left
tmploc lpctlv+^A,{lpmlbg}	; beg of text on line
tmploc lpctlv+^E,{lpmle}	; end of text on line

	; Search for rightmost text on line
lpmle:	pushae p,[nh,nv]
	move nh,shmax
	move nv,lpmy
	skipl a,@scrntb(nv)
	 cain a,blchar
	  sojg nh,.-2
	movem nh,lpmx
popnvh:	popae p,[nv,nh]
	return

	; Search for leftmost text on line
lpmlbg:	pushae p,[nh,nv]
;	move nh,shmin
	movei nh,0
	movem nh,lpmx
	move nv,lpmy
	camle nh,shmax		; Loop here
	 pjrst popnvh
	skipl a,@scrntb(nv)
	 cain a,blchar
	  aoja nh,.-4
	movem nh,lpmx
	pjrst popnvh

lpmdwn:	aos a,lpmy
	camle a,svmax
	 sos lpmy
	return

lpmup:	sosge lpmy
	 aos lpmy
	return

lpmfwd:	aos a,lpmx
	camle a,shmax
	 sos lpmx
	return

lpmbck:	sosge lpmx
	 aos lpmx
	return

lpmbgl:	setzm lpmx
	return
lpmel:	move a,shmax
	movem a,lpmx
	return

tmploc lpctlv+^S,{lpmsrf}	; search forward
tmploc lpctlv+^R,{lpmsrr}	; search backward
svar srchdr
svar srchch

lpmsrf:	skipa a,[1]
lpmsrr:	 seto a,
	movem a,srchdr
	call smiget		; Get char to search for.
	caie a,^S
	 cain a,^R
	  move a,srchch
	movem a,srchch
	pushae p,[nh,nv]
	move nh,lpmx
	move nv,lpmy
lpmsr3:	call lpmsch		; Move forward or backward in screen image
	 jrst lpmsr6
	came a,@scrntb(nv)	; Check for char
	 jrst lpmsr3		; not found, try next.
	movem nh,lpmx		; Found! Set mouse pos.
	movem nv,lpmy

lpmsr6:	popae p,[nv,nh]
	return

lpmsch:	cail nv,0
	 camle nv,svmax
	  return		; If go off either end, terminate search.
lpmsc4:	add nh,srchdr		; Bump in appropriate direction
	caige nh,0
	 jrst [	move nh,shmax	; Went off left edge, move to above line
		soja nv,lpmsch]
	camle nh,shmax
	 jrst [	setz nh,	; Went off right edge, move to lower line
		aoja nv,lpmsch]
	aos (p)
	return

	; Move over a word
lpmwf:	skipa a,[1]

	; Move back over a word
lpmwb:	 seto a,
	movem a,srchdr
	pushae p,[nh,nv]
	move nh,lpmx
	move nv,lpmy
lpmwm2:	call lpmsch	; Get next position
	 jrst lpmwm8	; If hit end, don't move mouse pos.
	move a,@scrntb(nv)	; Get char that's there
	call lpmwck	; Skip if char is a word-char.
	 jrst lpmwm2	; Loop until find one.
lpmwm4:	call lpmsch
	 jrst lpmwm7	; If hit end here, finalize at current pos.
	move a,@scrntb(nv)
	call lpmwck
	 caia
	  jrst lpmwm4
	movns srchdr	; Hit non-word char, stop and back up 1
	call lpmsch
	 jfcl
lpmwm7:	movem nh,lpmx
	movem nv,lpmy
lpmwm8:	popae p,[nv,nh]
	return

lpmwck:	cail a,"A
	 caile a,"Z
	  cail a,"a
	   caile a,"z
	    return	; not a word-char.
	aos (p)
	return

;;; This stuff handles NLS to LP protocol.

; Jump here on 1st time.
lpsmo:	smobin a,	; Get char in A
	push p,a
	call lprset	; do LP reset stuff.
	move a,shmax	; And put mouse in screen center.
	lsh a,-1
	movem a,lpmx
	move a,svmax
	lsh a,-1
	movem a,lpmy
	pop p,a
	jrst lpsmox		; jump into real loop.



lpsmol:	smobin a,
lpsmox:	push p,[lpsmol]	; loop back.
	caie a,
	 cain a,177
	  return	; Ignore padding before it does any damage.
	cain a,33	; ESC?
	 pjrst lpesc	; go handle protocol string.
	skipn lpmtrk	; Mouse being tracked?
	 pjrst td.cho	; No, can simply output.

	; Mouse being tracked, shit, must hack TTY simulation window.
	move nh,lptysx		; Restore cursor pos.
	move nv,lptysy
	push p,a
	move a,lptybg	; 1st line
	movei b,0	; 1st col
	move c,lptyln
	addi c,(a)	
	subi c,1	; last line
	move d,shmax	; last col
	call td.win	; Set window
	pop p,a

	; Check for format effectors (not many)
	cain a,^M	
	 jrst [	movei nh,0 ? jrst lpstc1]
	cain a,^J
	 jrst [	camge nv,wvmax
		 aoja nv,lpstc1
		movei a,1
		call td.su		; Scroll up
		jrst lpstc1]

lpstco:	call td.cho
lpstc1:	movem nh,lptysx
	movem nv,lptysy
	setzb a,b
	dmove c,smax
	pjrst td.win

;;;  ESC received, handle NLS-to-LP protocol string

lpesc:	smobin a,		; Get following char
	cail a,lpemin
	 caile a,lpemax		; Must be in 40-62 range
	  return		; if not, ignore totally.
	pjrst @lpetb-lpemin(a)

lpemin==:40	; Min esc code.  Note indented entries are no-ops.
lpetb:	lp.pos		; 40 - position cursor
	lp.tys		; 41 - set TTY simulate window
	lp.trk		; 42 - resume tracking
	lp.wbl		; 43 - write blanks
	lp.dlp		; 44 - delete line
	lp.ilp		; 45 - insert line
	lp.psh		; 46 - push bug
	lp.pop		; 47 - pop bug
	lp.clr		; 50 - clear screen
	lp.rst		; 51 - reset
	 lp.ops		; 52 - printer string (dev, cnt+40, chars)
	 apopj		; 53 - open printer port  (no args)
	 apopj		; 54 - close printer port (no args)
	lp.qry		; 55 - interrogate
	lp.son		; 56 - standout mode on
	lp.sof		; 57 - standout mode off
	lp.cof		; 60 - coordinate mode off
	lp.con		; 61 - coordinate mode on
	 lp.crs		; 62 - cursor resolution (N+40)
	 lp.nps		; 63 - new copy printer string(cs2,cs2,dev,seq,cnt,chs)
	 lp.npo		; 64 - new copy printer open (dev, mode)
	lp.scr		; 65 - scroll window
lpemax==:65
ifn <.-lpetb>-<1+lpemax-lpemin>, .err LPETB loses

lp.pos:	call lprcrd	; Get X coord
	push p,a
	call lprcdy	; Get Y coord
	movei nv,(a)
	pop p,nh
	setzm lpmtrk	; Stop mouse tracking.
	return

lp.tys:	call lprcrd	; Get Y for top line of window
	sub a,svmax	; must invert.
	movmm a,lptybg
	call lprcdy	; Get Y for bottom line of window
	sub a,lptybg	; Find # lines-1 in TTY simulate window.
	movem a,lptysy	; Use that as initial Y coord.
	addi a,1
	movem a,lptyln	; Store # lines.
	setzm lptysx
	return

lprset:	setzm lpcmod	; This entry point zaps coord mode also.
	setzm lprqrs	; and flushes any pending reset request.
lp.rst:	call td.clr	; clear screen
	move a,svmax
	movem a,lptyln	; Set TTY simulate window to full screen.
	aos lptyln
	movem a,lptysy	; and reset TTY simulate coords.
	setzm lptysx
	setom lpmtrk	; Resume tracking
	setzm lpstki	; Reset bug selection stack.
	return



lp.trk:	setom lpmtrk	; Resume tracking mouse
	return

lp.wbl:	call lprcrd	; Get # blanks to write.
	jumple a,apopj
	push p,a	; Must save count.
lp.wb2:	movei a,40
	call td.cho
	sosle (p)
	 jrst lp.wb2
	pop p,a
	return

lp.psh:	call lprcrd		; Get X coord
	push p,a		; save
	call lprcdy		; then Y coord
	pop p,b
	hrli a,(b)		; Get <H>,,<V>
	move b,lpstki
	cail b,7
	 return			; Ignore if no more room on stack.
	aos lpstki
	movem a,lpbstk(b)	; Store coords
	pushae p,[nh,nv]
	hlrz b,a
	movei a,(a)
	call td.mov
	call td.bow
	movei a,"O
	call td.cho
	call td.rst
	popae p,[nv,nh]
	return

lp.pop:	skipg lpstki
	 return
	sos b,lpstki
	move a,lpbstk(b)
	pushae p,[nh,nv]
	hlrz b,a
	movei a,(a)
	call td.mov
	movei a,40
	call td.cho
	popae p,[nv,nh]
	return

lp.dlp:	movei a,1
	pjrst td.dlp

lp.ilp:	movei a,1
	pjrst td.ilp

lp.clr:	pjrst td.clr

lp.cof:	setzm lpcmod	; Turn coordinate mode off
	return

lp.con:	setom lpcmod	; Turn coordinate mode on
	return

lp.son:	pjrst td.bow	; Turn standout mode on

lp.sof:	pjrst td.rst	; Turn standout mode off

lp.qry:	movei a,34
	call smibout
	movei a,46
	call smibout
	move a,shmax
	call lpsbcd	; Send coord value
	move a,svmax
	call lpsbcd
	movei a,<<2_4>+6>+40	; type 2 (alpha LP), ter 6 (Dm4000)
	call smibout		; (or 3 for Dm2500)
	movei a,40
	call smibout	; zero delay
	movei a,32.+40	; Pretend 300 baud for minimal pads
	pjrst smibout

; Scroll window
lp.scr:	call lprcrd	; Get leftX
	push p,a
	call lprcrd	; and rightX
	camg a,(p)	; just make sure...
	 exch a,(p)
	push p,a	; save horiz window coords.
	call lprcdy	; Get topY
	push p,a	; save
	call lprcdy	; get botY
	camg a,(p)	; make sure bottom coord greater.
	 exch a,(p)
	push p,a	; Save vertical window coords
	call lprcrd	; Get N
	trne a,1_11.	; is 12th bit set? (12-bit 2's complement)
	 ior a,[-1,,770000]	; Yes, so "extend sign"...
	skipn e,a	; Get out of way...
	 jrst [	popae p,[a,a,a,a]
		return]

	pop p,c			; Restore botY into wvmax
	pop p,a			; restore topY into wvmin
	pop p,d			; restore rightX into whmax
	pop p,b			; restore leftX into whmin
	pushae p,[wvmin,whmin,wvmax,whmax]
	call td.win		; set window
	move a,e		; restore arg
	call td.scr		; Scroll whichever way.
	popae p,[d,c,b,a]	; Restore previous window.
	pjrst td.win


	; Input a Y-coordinate.
lprcdy:	call lprcrd	; Get value
	sub a,svmax	; invert it.
	movm a,a
	return

	; Input a coordinate value.
lprcrd:	smobin a,
	subi a,40
	jumpge a,apopj
	smobin a,
	subi a,40
	lsh a,6
	push p,a
	smobin a,
	subi a,40
	andi a,77
	addm a,(p)
	pop p,a
	return

lp.crs:	pjrst lprcrd

lp.npo:	smobin a,
	smobin a,
	return

lp.nps:	smobin a,	; checksum 2
	smobin a,	; checksum 1
	smobin a,	; device
	smobin a,	; mode
;	smobin a,	; Sequence #  (drop thru to hack rest)

lp.ops:	smobin a,
	call lprcrd
	jumple a,apopj
	push p,a
lpops2:	smobin a,
	sosle (p)
	 jrst lpops2
	pop p,a
	return


; Finalize - resume tracking or whatever.
lpsmf:	skipe lprqrs		; Requesting reset?
	 jrst [	setzm lprqrs	; Yes, do it.  Clear request flag.
		call lp.rst	; Then perform local reset
		skipe lpcmod	; and if in coord mode,
		 jrst [	movei a,34	; use ptcl to tell NLS to re-display.
			call smibout
			movei a,50
			call smibout
			jrst .+1]
		movei a,176	; Else not in coord mode, but simulate
		call smibout	; LP lossage anyway!
		movei a,177
		call smibout
		jrst .+1]
	skipn lpmtrk		; Mouse supposed to be tracked?
	 pjrst lpsmf1		; Nope, take normal finalize return.

	; Shit, move cursor to where "mouse" is.
	skipge nh,lpmx
	 setz nh,
	camle nh,shmax
	 move nh,shmax
	movem nh,lpmx		; canonicalize mouse position.
	skipge nv,lpmy
	 setz nv,
	camle nv,svmax
	 move nv,svmax
	movem nv,lpmy
lpsmf1:	call td.frc
	pjrst tyofrc

trmend


subttl	Lunar - Moon's hacked terminal

	trmbeg Lunar:,[LUNAR]

tp.vsz	24.
tp.hsz	80.
tm.up	1,tyn 32		; ^Z
tm.dwn	1,tyn 12		; ^J
tm.fwd	1,tyn 34		; ^\
tm.bck	1,tyn ^H
;tm.cr	1,tyo ^M
tm.hom	1,tyo 2			; ^B
tm.abs	3, call lunmov
te.eol	tyo 27			; ^W
tabend
lunmov:	tyo ^L
	movei d,(nh)
	trc d,140
	tyo (d)
	movei d,(nv)
	trc d,140
	tyo (d)
	return

trmend

subttl	MB0 - Mini-Bee

	trmbeg MB0:,[MB0]

tp.flg	%fsmeol+%fspd
tp.vsz	25.
tp.hsz	80.
tr.ini	zout [asciz "HJ"]	; clear screen
tr.cho	ccho			; character display routine 
tm.up	2,tynesc "A
tm.dwn	2,tynesc "B
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,call mb0tab
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
te.eol	call mb0eol		; MB0 uses esc "K too, but zaps entire line.
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
tabend


mb0tab:	push p,a
	tyn ^I
	move a,speed
	caige a,480.		; if at 4800 baud or greater
	 pjrst popaj
	tyo 177			; Must pad tabs with 2 rubouts.
	tyo 177
	pjrst popaj

; MB0EOL - Simulated Clear-to-EOL for MB0
mb0eol:	jumpn h,seol		; If not on edge, hack spaces.
	tyoesc "K		; If on edge, can zap whole line.
	return

trmend

subttl	MB4 - Mini-Bee 4

	trmbeg MB4:,[MB4]

tp.flg	%fspd
tp.vsz	25.
tp.hsz	80.
tr.ini	call mb4ini
tr.tyi	undel			; just del/underscore exchange
tm.up	2,tynesc "A
tm.dwn	2,tynesc "B
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,call mb4tab
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call mb4mv
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
tabend


mb4ini:	zout [asciz "HJ"]
	skipl jtab		; tabs?
	 call settab		; yes, set tab stops
	pjrst undelw		; warn about _/DEL switch


mb4tab:	push p,a
	tyn ^I
	move a,speed
	caige a,480.		; if at 4800 baud or greater
	 pjrst popaj
	tyo 177			; Must pad tabs with 2 rubouts.
	tyo 177
	pjrst popaj

mb4mv:	tyoesc "F
	move d,nv
	idivi d,10.
	rot e,-4
	lshc d,4
	cain d,
	 movei d,1
	tyo (d)
	move d,nh
	idivi d,10.
	rot e,-4
	lshc d,4
	jumpe d,[tyo 1		; MTY misfeature
		tyo 10
		skipn nv
		 tyoesc "A
		return]
	tyo (d)
	skipn nv
	 tyoesc "A
	return


trmend

subttl	MIME - Microterm MIME

; Background follows			^Y
; Change intensity (toggle)		^N
; Clear foreground			^F
; Clear to end of line			^^
; Clear to end of frame (screen)	^_
; Clear to end of screen background	^C
; 	spaces
; Cursor down				^K
; Cursor right				^X
; Cursor up				^Z
; Delete line				^W
; Enter graphics mode			^O
; Exit graphics mode			ESC
; Foreground follows			^S
; Home and clear			^L
; Home up				^]
; Insert line				^A
; Request cursor position		^E
;   (this will return two chars that give the cursor position as if
;    they were passed as Direct Cursor Addressing codes)
; Reverse line feed			^R
; Send line				FS (ascii 28 decimal)
; Send screen				^B
; Tab to next unprotected field		^D
; Underline				^U
;    (this will underline the character at the current
;     cursor position)

	trmbeg MIME:,[MIME]

tp.flg	0
tp.vsz	24.			; no. of lines displayable on the screen
tp.hsz	80.			; no. of characters per line
tr.ini	call mimein		; reset various modes and clear screen
tr.tyi	undel			; reverse _ and rubout
tr.cho	ccho			; character display routine 
tm.up	1,tyn ^Z		; move up n
tm.dwn	1,tyn ^K		; move down n
tm.fwd	1,tyn ^X		; move forward n
tm.bck	1,tyn ^H		; move back n (BS)
tm.cr	1,tyo ^M		; move to left margin (CR)
tm.hom	1,tyo ^]		; move to upper left corner (home)
tm.abs	3,call mimemv		; absolute move
te.eol	tyo ^^			; erase to end of line
te.eos	tyo ^_			; erase to end of screen
te.clr	tyo ^L			; erase whole screen (and home)
te.su	tyn ^J			; scroll the screen
te.sd	tyn ^R			; reverse scroll
te.ilp	tyn ^A			; insert line
te.dlp	tyn ^W			; delete line
tabend


; initialize
mimein:	tyo ^S			; foreground follows
	tyo ^[			; turn off graphics mode
	call undlcw		; print warning about interchanged _ and rubout
	return

; Absolute move.
mimemv:	tyo ^T
	tyo (nv)
	tyo (nh)
	return

trmend

subttl	MTEC - Mini-Tec

comment |
	Unused info:

ESC R READS THE CURSOR POSITION, returning two chars which are
	the one's complement of the horizontal, then vertical, address.
"ENTER" (^B) hacks block mode transmit.
"PRINT KEY" and "CANCEL" (^R and ^X) also hack block xmit.
TAB = moves cursor to beg of next unprotected field.
SET TAB: ANY PROTECTED CHARACTER SETS THE TAB.
ESC P STARTS A PROTECTED AREA, AND ESC C ENDS IT.
ESC L locks kbd, ESC U releases.
|

	trmbeg MTEC:,[MTEC,MINI-TEC]

tp.flg	%fsmeol
tp.vsz	24.
tp.hsz	80.
tm.up	1,tyn 13		; ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn 37		; ^_ (1F)
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo 36		; ^^
tm.abs	4,call mtcabs	; absolute move
te.eos	tyo 14			; ^L erase to end of screen
te.clr	tyo 34			; ^\ erase all
te.clr	tyo 34			; ^\ erase all
te.su	tyn ^J			; scroll up
tabend

mtcabs:	tyoesc "F
	setcmi d,(nh)	; Coords are complemented!
	andi d,177
	tyo (d)
	setcmi d,(nv)
	andi d,177
	tyo (d)
	return
trmend

subttl	MOD1 - Hazeltine "Modular One"

	trmbeg MOD1:,[MOD1]

tp.flg	%fsmeol
tp.vsz	24.
tp.hsz	80.
tm.up	2,tyn176 14	; ^L
tm.dwn	2,tyn176 13	; ^K
tm.fwd	1,tyn 20	; ^P
tm.bck	1,tyn 10	; ^H
tm.cr	1,tyo 15	; ^M
tm.hom	2,tyo176 22	; ^R
tm.abs	4,call mod1mv
te.eol	call mod1el
te.clr	tyo176 34		; ^\  (mod1 is WEIRD...)
te.su	tyn ^J
te.ilp	tyn176 32		; ^Z
te.ilp	tyn176 23		; ^S
tabend


; MOD1MV - absolute move for MOD1
mod1mv:	tyo176 ^Q
	cail nh,40
	 tyo (nh)
	caige nh,40
	 tyo 140(nh)
	tyo 140(nv)
	return


; MOD1EL - Simulated Clear-to-EOL for MOD1
mod1el:	jumpn h,seol		; If not on edge, hack spaces.
	tyo176 ^S		; Else can win by deleting line
	tyo176 ^Z		; and inserting blank line!
	return

trmend

subttl	O4000 - Ontel 4000

	trmbeg O4000:,[O4000]

tp.flg	0
tp.vsz	20.
tp.hsz	79.
tm.abs	6,call o4kmv
tm.up	1,tyn ^^
tm.dwn	1,tyn ^\
tm.fwd	1,tyn ^]
tm.bck	1,tyn ^H
;tm.tab	1,tyn ^I		; for now don't use tabs
tm.hom	1,tyo ^_
te.clr	tyo ^L
te.eol	tyo174 "+
te.eos	tyo174 ";
te.icp	call o4kicp
te.dcp	call o4kdcp
te.ilp	call o4kilp
te.dlp	call o4kdlp
tr.cho	call o4kcho		; must intercept "|"
tabend

o4kcho:	cain a,174		; vertical bar?
	 movei a,"!		; for now, substitute excl. point.
	pjrst scho

o4kmv:	tyo174 "-		; start cursor move
	movei d,(nv)		; Follow by vert pos.
	idivi d,10.		; in BCD type format.
	tyo "0(d)
	tyo "0(e)
	movei d,(nh)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	return

o4kicp:	tyn174 "5
	tyn 40
	tyn ^H
	return

o4kdcp:	tyn174 "6
	return

o4kilp:	tyn174 "7
	return

o4kdlp:	tyn174 "'
	return

trmend

subttl	O8030B - Omron 8030B

; Manual claims that padding is only required above 2400 baud, i.e.
; at 4800 and 9600, but gives no timings.

	trmbeg O3B:,[O8030B]

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call o3bini
tr.cho	ccho0			; character display routine 
tm.up	2,tynesc "C		; Not "A!
tm.dwn	1,tyn ^J		; Scrolls on bottom. Or use 2,tynesc "B
tm.fwd	2,tynesc "D
tm.bck	1,tyn ^H		; or 2,tynesc "E
;tm.tab	1,tyn ^I		; wait for tab setter.
tm.cr	1,tyo ^M		; only in CHAR mode
tm.hom	2,tyoesc "H
tm.abs	7,call o3bmov		; ESC "u yyy xx
te.eol	tyoesc "L
te.eos	tyoesc "M		; clears page (not to end of memory)
te.ilp	tynesc "X
te.dlp	tynesc "V
te.eim	tyoesc "Y
te.lim	tyoesc "Z
te.dcp	tynesc "W
tabend

o3bini:	zout [asciz /K000/]	; make sure on page 0.
	xct .teeos+tb
	tyoesc "1		; Make sure in CHAR mode.
	tyoesc ^I		; Clear all tab stops.
	pjrst settab		; ESC "S sets tabstop at current position.


; Abs move is ESC "u followed by 3 digits of line # and 2 digits
; of column #.  Must always be that many digits.
o3bmov:	tyoesc "u		; Yes, lowercase "u".
	movei d,(nv)
	idivi d,10.
	push p,e
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	pop p,e
	tyo "0(e)
	movei d,(nh)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	return

trmend

subttl	O8030A - Omron 8030A (not actually implemented)

ifn 0,[

Omron 8030A according to CEH is very much like 8025 except:

	Doesn't handle multiple pages right (doesn't put you on page 0 to start)
	Doesn't do the 'control character off' (<esc>{)
	(yes there is a key for it, key layout for functions is:
XMIT	CARRIER	REMOTE	HALF	CLEAR	CHAR	CHAR	WAIT
		LOCAL	FULL		DELETE	INSERT

PRINT	BATCH	PROT.	NULL	CLEAR	CNTL	UPPER	BREAK
	CHAR	ON/OFF	SUPRSS	LINE	CHAR	CASE
					OFF

A short summary of relevant 8030a escape sequences is:

<ESC> 
with	does
;	Half Duplex
1	Set tab stop
2	Clear tab stop
@	Character Insert (1 char)
A	Cursor UP
B	Cursor DOWN
C	Cursor RIGHT
D	Cursor LEFT
E	Lock Keyboard
F	Unlock Keyboard
G	Cursor Return (same as CR, useful in forms mode)
H	Home cursor (top of screen not position 0,0 in memory)
I	Tab (<esc>^I, ^I too, see forms mode)
J	Clear screen
K	Clear line
L	Line insert
M	Line Delete
N	Upper case only
O	Upper/Lower case
P	Character Delete
Q	Character insert mode (all printing characters inserted)
R	Character insert mode OFF
S	Scroll up
T	Scroll down
U	Next page
V	Previous page
Z	Quote mode on. Display graphics for ALL chars, ignores esc seqences
	Can only be turned off from keyboard.  Use forms mode instead.
j	Send BREAK
k	Synchronous/Asynchronous Communications Interface (SACA) control
m	Clear block
n	Clear to end of memory (from cursor)
v	Set block terminataion character (for transmit)
w	Set forms mode.  Display graphics for all characters except escape
	sequences, which are interpreted.
x	Reset forms mode.
{	Control characters off. (don't display the nonformatting control chars)
|	Read cursor address. (response is esc sequence to position cursor to the
	current position, followed by a block termination character (default
	block term char is EOT ()))
}	Position cursor. Position is coded in four bytes, four bits per byte
	with 64 optionally added. Line # first two bytes, Column number second
	Upper left of first page is 0,0 (or }@@@@ )
~	Control characters on.  Display graphics for all non-formatting control
	characters.  Formatting effectors are: BEL,BS,HT,LF,CR
]

subttl	OMRON - Omron 8025

	trmbeg OMRON:,[OMRON]

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call omrini
tr.tyi	omrtyi
tr.cho	ccho			; character display routine 
tr.zns	-lzt2,,zt2		; AOBJN to zone table with NL test
tm.up	2,tynesc "A
tm.dwn	2,tynesc "B		; LF is NL!
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
;tm.tab	1,tyn ^I
tm.nl	1,tyo ^J
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	6,call omrabs
te.eol	call omrnel		; maybe this needs padding also?
te.eos	call omrnes		; standard, but needs delay.
te.icp	call omricp
te.dcp	tynesc "P
te.ilp	call omrilp
te.dlp	call omrdlp
tx.so	tyoesc "d		; Standout - half inverse video
tx.sor	tyoesc "4		; normal video
tabend


; Initialization.
omrini:
IFN ITS,{
	move a,speed		; if output speed is greater than 30 cps
	caile a,30.		; then should disable %TOLID cause its too slow
	 jrst [	$call ttyvar,[#pyi,[sixbit/ttyopt/],#0,[tlz %tolid]]
		 .lose %lsfil
		jrst .+1 ]
}
	setzm padc		; set pad character to null
	tyoesc "H		; home to get things synchronized
	setzb h,v		; ...
	xct .teeos+tb		; clear the screen
	skipl jtab		; tabs?
	 call settab		; yes, set tab stops
	move a,[ascnt |Warning: changed keys "TAB" = rubout, "CR" = line feed,
"NEW LINE" = return, "shift/_" = tab|]
	pjrst stdwrn


; Input handler.
omrtyi:	call tyibin
	caie a,^J		;interchange cr and lf (nl) keys
	 cain a,^M
	  xori a,^J#^M
	caie a,^I		;interchange del and tab keys
	 cain a,177
	  xori a,^I#177
	call tyipuc
	jrst omrtyi


; Absolute move.
omrabs:	pushae p,[nh,nv]
	tyoesc 175		; Omron positioning
	aos e,nv		; vertical first
	lsh e,-4		; high 4 bits first
	tyo 100(e)
	andi nv,17
	tyo 100(nv)
	aos e,nh		; then horizontal
	lsh e,-4
	tyo 100(e)
	andi nh,17
	tyo 100(nh)
	popae p,[nv,nh]
	return


; Clear to EOS.
omrnes:	tyoesc "J		; Clear in standard fashion, but
	pad [1.0]
	return


; Clear to EOL.
omrnel:	tyoesc "K		; Clear in standard fashion, but
	pad [.0415]		; 1/25 second padding?
	return


; Insert line.

omrilp:	push p,a
omrill:	tyoesc "L	
	call omrpad
	sojg a,omrill
	pop p,a
	return


; Delete line.

omrdlp:	push p,a
omrdll:	tyoesc "M
	call omrpad
	sojg a,omrdll
	pop p,a
	return


omrpad:	push p,a
	move a,tvmax
	sub a,v	
	fsc a,233		; float
	fdvr a,[10.0]
	pad a
	pop p,a
	return


; Insert character.
omricp:	zoutn [asciz "@ "]
	add h,a
	return


trmend

subttl	OWL - Perkin-Elmer OWL-1200

	trmbeg OWL:,[OWL]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.tyi	undel			; exchange del, underscore
tr.ini	call owlini		; set tabs and warn user
tr.zns	-lzt3,,zt3		; AOBJN to zone table with AX/AY test
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J		; line feed faster than ESC B
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.ax	3,call owlah		; abs move in horizontal dir
tm.ay	3,call owlav		; abs move in vertical dir
tm.abs	6,call owlmv
te.eol	tyoesc "I		; not ESC K !!
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
te.icp	zoutn [asciz /N /]	; $N<char> inserts char - do BS after a blank.
te.dcp	tynesc "O		; can't be the same as anyone else
te.ilp	call owlilp
te.dlp	call owldlp
tx.vbl	call owlvbl		; visible bell
tabend

owlilp:	tynesc "L
	pad [.1]
	return

owldlp:	tynesc "M
	pad [.1]
	return

; Transparent mode displays all spaces as small NU's; doing this briefly
; is quite flashy.
owlvbl:	tyo ^P			; ^P^B goes into transparent mode
	tyo ^B
	tyo ^P			; ^P^C exits debug mode.
	tyo ^C
	return

owlini:	tyoesc "K		; home, clear screen and clear tabs
	skipl jtab		; tabs?
	 call settab		; yes, set tab stops
	skipge jwarn		; inhibit warnings?
	 return			; yes, just return
	move a,[ascnt " Warning: interchanged Underscore and Delete keys.
          Newline Enable key should be OFF (up)."]
	pjrst stdwrn		; type message


owlmv:	call owlah		; Absmove does horiz then drops thru for vert.

owlav:	tyoesc "X		; is abs move in VERTICAL direction!
	tyo 40(nv)
	return
owlah:	tyoesc "Y		; is abs move in HORIZONTAL direction!
	tyo 40(nh)
	return

trmend

subttl	REMB - REM's 6502 Beehive

comment |
settab=^F  (and clrtab=^V)
When printing last column, cursor moves to first column on next line,
 except after printing last column of last line it first scrolls.
(Exception, tab that wraps around end-of-line lands on first column
 of next line but never scrolls, thus ends up home if wrap around end
 of screen. Crock!)
Linefeed from bottom line, even if caused by printing or ^P on last char
 of last line, scrolls (see tab exception above).
To clear screen without affecting tab tops, home followed by erase-to-end-of-screen.
To clear screen and all tab stops and leave cursor home, clear=^T except
 my 6502 intercepts it to protect against this disaster, so don't use it
 except during startup when the user knows to get into PROM-TTY mode instead
 of smart-RAM-TTY mode.
Extras: start-blink=^\ start-reversed-video=^] start-blink-reversed-video=^^
 start-normal=^_ (all revert to normal at end of line, all require one
 char position - i.e. each affects from next character thru last char on
 line or thru next such char, whichever occurs first - note that these
 characters, no matter how they got on the screen, have static effect
 permanently until they get replaced or scroll off top of screen, effect
 refresh circuity directly)  purge-all-rev/blk=^[ (immediate effect, edit
 screen to replace all of the above four by <space> characters, thus
 removing any blink or reversed video immediately - doesn't consume char pos)
More extras, intercepted by 6502 to avoid disaster: enter-format-mode=^O
 leave-format-mode=^N print=^U new-line=^H (prints faint-H and then does
 cr and lf functions) null=^@ (intercepted by 6502 and converted into ^])
 <rubout> is ignored (note, computer-->beehive ignores, but beehive-->computer
 uses <rubout> as a delete character on most DEC systems, echoing ^H or
 somesuch), characters <space> thru '176 print as normal characters

|
	trmbeg REMB:,[REMB]

tp.flg	%fsmeol
tp.vsz	20.
tp.hsz	79.			; actually 80 but has newline scroll lossage.
tm.up	1,tyn ^R
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^P
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I		; REM has 6502 set tabs every 8
tm.cr	1,tyo ^M
tm.hom	1,tyo ^E
tm.abs	3,call rembmv	; same as dm2500
te.eos	tyo ^K			; may need padding
te.clr	tyo 005013		; ^E, ^K = home then cleos.
te.su	tyn ^J			; scroll up
tabend


rembmv:	tyo ^L
	movei d,(nh)
	trc d,140
	tyo (d)
	movei d,(nv)
	trc d,140
	tyo (d)
	return

trmend

subttl	SB1 - Super-Bee

; Like a Super-Bee 2 but doesn't even have bugs fixed
	trmbeg SB1:,[SB1]

tp.flg	%fspd
tp.vsz	25.
tp.hsz	80.
tr.ini	call sbinit
tr.tyi	sb1in			; to hack losing Escapes
tr.cho	ccho			; character display routine 
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	8.,call sbabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.ilp	tynesc "L
te.dlp	call sbdlp
tabend


; Input.
; Make the F1 key be Escape, F2 key be ^C
sb1in:	push p,[sb1in]
	call tyibin
	caie a,33		; Is char an escape?
	 pjrst tyiput		; No, pass on.
	call tyibin		; Yes, get next!
	cain a,"C		; <esc>C = space to correct for SPOW mode
	 jrst [	movei a,40
		pjrst tyiput ]
	cain a,"p		; <esc>p = Function key 1 is Escape
	 jrst [	movei a,33
		pjrst tyiput ]
	cain a,"q		; <esc>q = Function key 2 is control-C
	 jrst [ movei a,^C
		pjrst tyiput ]
	cain a,"r		; <esc>r = Function key 3
	 pjrst enter
	push p,a
	movei a,33
	call tyiput		; anything else should go through as
	pop p,a
	pjrst tyiput	; both characters, ie. <esc><whatever>


trmend

subttl	SB2 - Super-Bee

	trmbeg SB2:,[SB2]

tp.flg	%fspd
tp.vsz	25.
tp.hsz	80.
tr.ini	call sbinit
tr.cho	ccho			; character display routine 
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	8.,call sbabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.ilp	tynesc "L
te.dlp	call sbdlp
tabend


; Initialization.
sbinit:	tyoesc "E		; clear screen and tabs
	skipl jtab		; tabs?
	 pjrst settab		; yes, set tab stops
	return


; Absolute move.
sbabs:	tyoesc "F		; StupidBee positioning
	move d,nh
	idivi d,100.
	tyo "0(d)
	movei d,(e)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	move d,nv
	idivi d,100.
	tyo "0(d)
	movei d,(e)
	idivi d,10.
	tyo "0(d)
	tyo "0(e)
	return


; Delete line.
sbdlp:	push p,a
sbdlp1:	tyoesc "M
	pad [.1]
	sojg a,sbdlp1
	pop p,a
	return

trmend

subttl	SOFT - Software terminal type

	trmbeg SOFT:,[SOFT]

tr.smo	swsmo			; Note standard STY input for simulate!
tr.smi	swsmi
tr.smf	swsmf

tp.flg	0
tp.vsz	0			; no. of lines displayable on the screen
tp.hsz	0			; no. of characters per line
tp.scr	-1			; scroll count
tr.ini	tyo %tdclr		; initialization
tr.fin	tyo %tdrst		; cleanup
tr.cho	scho1			; display character routine
tr.mov	swmov			; cursor movement
te.del	tyo %tddlf		; erase character position
te.eol	tyo %tdeol		; erase to end of line
te.eos	tyo %tdeof		; erase to end of screen
te.clr	tyo %tdclr		; erase whole screen (and home)
te.su	tyn %tdcrl		; scroll up
te.icp	tyo %tdicp_9(a)		; insert n character positions
te.dcp	tyo %tddcp_9(a)		; delete n character positions
te.ilp	tyo %tdilp_9(a)		; insert n lines
te.dlp	tyo %tddlp_9(a)		; delete n lines
tx.so	tyo %tdbow		; enter standout mode
tx.sor	tyo %tdrst		; exit standout mode
tx.bel	tyo %tdbel		; ring bell
tabend


; Cursor movement routine.
swmov:	push p,a		; save AC
	cain nv,(v)
	 caie nh,1(h)
	  jrst swmov1
	movei a,%tdfs
	call @.trtyo+tb
	aoja h,swmov2
swmov1:	movei a,%tdmv0
	call @.trtyo+tb
	movei a,(nv)
	call @.trtyo+tb
	movei a,(nh)
	call @.trtyo+tb
	dmove vh,nvh
swmov2:	pop p,a			; restore AC
	return

trmend

subttl	Sol-20

	trmbeg SOL20:,[SOL20,SOL]

tp.flg	%fsmeol+%fsail
tp.vsz	16.
tp.hsz	64.
tr.cho	solcho
tr.zns	-lsolzns,,solzns
tr.ini	call solini
;tm.up	1,tyn ^W
tm.dwn	1,tyn ^J
;tm.fwd	1,tyn ^S
;tm.bck	1,tyn ^A
;tm.hom	1,tyo ^N
tm.ax	3,call solax
tm.ay	3,call solay
tm.abs	6,call solabs
;te.clr	tyo ^K
te.eol	call soleol
te.su	tyn ^J
tabend


; SOLZNS - SOL20 zone table for movement optimizer.
solzns:	ztest			; relative move
;	zthom			; home and relative move
;	ztcr			; CR and relative move
	ztay			; absolute Y move and relative X move
;	ztaycr			; absolute Y move, CR, and relative X move
	ztax			; absolute X move and relative Y move
lsolzns==.-solzns


solini:	move nh,whmin
	move nv,wvmax
	call solabs		; position on last line of screen
	move h,nh
	move a,sheight
	tyn ^J			; clear screen by scrolling everything else
				; away
	move v,tvmax
	return


solabs:	call solay

solax:	tyoesc ^A
	tyo 100(nh)
	return

solay:	tyoesc ^B
	tyo 100(nv)
	return


soleol:	tyo ^M			; CR!
	move h,thmin
	return


solcho:	jumpe a,[return]	; can't display NUL
	caml h,thmax		; last column?
	 jrst solch3		; yes
	movem a,@scrtab(v)	; store character in screen image
	addi h,1
solch1:	caie a,"_		; underscore?
	 cain a,177		; DEL?
	  jrst solch2		; underscore or DEL, quote it
	caie a,^M		; CR?
	 cain a,^J		; LF?
	  jrst solch2		; CR or LF, quote it
	cain a,33		; ESC?
solch2:	 tyoesc ^E		; yes, quote it
	pjrst @.trtyo+tb	; output character

solch3:	caml v,tvmax		; last line too?
	 return			; yes, ignore character completely
	movem a,@scrtab(v)	; store character in screen image
	move h,thmin		; output character and
	aoja v,solch1		; reflect CRLF in actual cursor position


trmend

subttl	TK4023 - Tektronix 4023

	trmbeg TK4023:,[TK4023]

tp.flg	%fsmeol
tp.vsz	24.			; no. of lines displayable on the screen
tp.hsz	80.			; no. of characters per line
tr.cho	ccho
tm.dwn	1,tyn ^J		; move down n (LF)
tm.bck	1,tyn ^H		; move back n (BS)
tm.fwd	1,tyn ^I
tm.cr	1,tyo ^M		; move to left margin (CR)
tm.abs	3,call t23abs		; absolute move
te.clr	tyoesc ^L		; erase whole screen (and home)
te.su	tyn ^J			; scroll the screen once
tabend


; Various support routines called above.
t23abs:	tyo ^\
	tyo 40(nh)
	tyo 40(nv)
	return

trmend

subttl	TK4025 - Tektronix 4025

	trmbeg TK4025:,[TK4025]

define	tzout *s*
	zout [asciz "`s"]
termin

tp.flg	%fsmeol			; default to smart CLEOL
tp.vsz	34.
tp.hsz	80.
tr.ini	call tkinit
tr.cho	ccho			; character display routine 
tr.zns	-ltkzt,,tkzt
tm.up	[call tkupc] call tkup
tm.dwn	[call tkdwnc] call tkdwn
tm.fwd	[call tkfwdc] call tkfwd
tm.bck	[call tkbckc] call tkbck
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
te.clr	tzout "ERA;"
te.su	tyn ^J			; scroll up
te.dlp	call tkdlp
te.ilp	call tkilp
te.dcp	call tkdcp
te.icp	call tkicp
tabend


; Tektronix 4025 zone table.
tkzt:	ztest
	ztcr
ltkzt==.-tkzt


; Initialization.
tkinit:	tzout "MON 34 H K;"
	tzout "ERA;"
	skipl jtab				; tabs?
	 tzout "STO 9 17 25 33 41 49 57 65 73;"	; yes, set tab stops
	return


; Calculate move forward cost.
tkfwdc:	movei t1,6
	cain a,1
	 movei t1,5
	cail a,10.
	 movei t1,7
	move a,t1
	return

; Move forward.
tkfwd:	tzout "RIG"
	pjrst tknum


; Calculate move backward cost.
tkbckc:	caig a,6
	 return
	movei t1,6
	cail a,10.
	 movei t1,7
	move a,t1
	return

; Move backward.
tkbck:	caile a,6
	 jrst tkbck1
	tyn ^H
	return
tkbck1:	tzout "LEF"
	pjrst tknum


; Calculate move down cost.
tkdwnc:	;caig a,6		See tkdwn
	; return
	movei t1,6
	cail a,10.
	 movei t1,7
	move a,t1
	return

; Move down.
tkdwn:	;caile a,6		LF sometimes doesn't work when following a
				; CR.  I can't isolate the cases.  -CBF
	 jrst tkdwn1
	tyn ^J
	return
tkdwn1:	tzout "DOW"
	pjrst tknum


; Calculate move up cost.
tkupc:	movei t1,5
	cail a,10.
	 movei t1,6
	move a,t1
	return

; Move up.
tkup:	tzout "UP"
	pjrst tknum


; Insert lines.
tkilp:	jumpe v,tkilp1		; hack 1st line specially
	tzout "UP;"
	subi v,1
	tzout "ILI"
	call tknum
	add v,a
	return
; Insert line before 1st line.
tkilp1:	tzout "ILI"		; insert line
	call tknum
	add v,a
	push p,a
	movei nv,1		; update screen image
	call scrilp		; ...
	move nv,a
	movei nh,0
	move b,[-80.,,screen]
tkilp2:	move a,(b)
	call td.cho
	aobjn b,tkilp2
	setzb nh,nv
	pop p,a
	aos (p)			; skip return since screen image is updated
	pjrst td.eol


; Delete lines.
tkdlp:	tzout "DLI"
	pjrst tknum


; Insert characters.
tkicp:	tzout "ICH;"
	tyn 40
	tzout "LEF"
	pjrst tknum


; Delete characters.
tkdcp:	tzout "DCH"
	pjrst tknum


; Tektronix 4025 decimal no. output for arguments.
tknum:	caie a,1
	 call tyodec
	tyo ";
	return

subttl	TK4027 - Tektronix 4027

	trmtoo TK4027:,[TK4027]

define	tzout *s*
	zout [asciz "`s"]
termin

tp.flg	%fsmeol+%fspd		; default to smart CLEOL
tp.vsz	34.
tp.hsz	80.
tr.ini	call tk7ini
tr.cho	ccho			; character display routine 
tr.zns	-ltkzt,,tkzt
tm.up	[call tkupc] call tkup
tm.dwn	[call tkdwnc] call tkdwn
tm.fwd	[call tkfwdc] call tkfwd
tm.bck	[call tkbckc] call tkbck
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
te.clr	tzout "ERA;"
te.eol	call tk7eol
te.su	tyn ^J			; scroll up
te.dlp	call tkdlp
te.ilp	call tkilp
te.dcp	call tkdcp
te.icp	call tkicp
tabend


; Initialization.
tk7ini:	tzout "MON 34 H K;"
	tzout "ERA;"
	skipl jtab				; tabs?
	 tzout "STO 9 17 25 33 41 49 57 65 73;"	; yes, set tab stops
	tzout "LEA M1 138;"	; for CLEOL
	return


; Erase to end of line.
tk7eol:	caml v,tvmax
	 jrst tk7sml
	tzout "EXP M1;"
	addi v,1
	move h,thmin
	return
tk7sml:	move t1,speed
	caile t1,60.
	 jrst seol
	movei a,80.
	sub a,h
	tzout "DCH"
	pjrst tknum

trmend

subttl	TLC - Problem Solver's Systems' TLC

	trmbeg TLC1:,[TLC]

comment ~
   10. A ^K (inverse-linefeed) at top line WILL DO a reverse scroll, HOWEVER:
if the ^K is done like this, a previous line that was scrolled off the top
WILL reappear, up to a total of 24 lines (i.e., the terminal has a two-
screen-full buffer.  I suggest that the cursor be relocated to home before
the ^K is sent, and a erase-to-end-of-line follwed by the correct line
be sent after that.  This will be easier to write and lead to no confusion
if you're not following me.
   13. Ridiculousness:  Control-Z is not transmitted by the terminal. It does
clear the screen locally.  Incredible goof by the designers -- I wrote them
a tremendously nasty letter.
~

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	4,call tlcabs
te.eol	tyoesc "T
te.eos	tyoesc "Y
te.clr	tyo ^Z
te.su	tyn ^J
te.sd	tyn ^K
tabend


; Direct cursor positioning.
tlcabs:	tyoesc "=
	tyo 40(nv)
	tyo 40(nh)
	return

trmend

subttl	T1061 - Teleray 1061

	trmbeg T1061:,[T1061]

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call t61ini
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J		; line feed faster than ESC B
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	call t61eol		; ESC-K, but needs padding
te.eos	call t61eos
te.clr	call t61clr
te.su	tyn ^J			; scroll up
te.icp	tynesc "P
te.dcp	tynesc "Q		; can't be the same as anyone else
te.ilp	call t61ilp
te.dlp	call t61dlp
tx.vbl	call t61vbl
tabend


; Initialization.
t61ini:	setzm padc
	call t61clr		; clear screen
	tyoesc "G		; clear all tab stops
	push p,b
	movei b,9.		; no. of tab stops to set
t61t1:	zout [asciz "        "]	; move to next multiple of 8
	tyoesc "F		; and set a tabstop there
	sojg b,t61t1
	tyo ^M
	pop p,b
	return


; Clear screen.
t61clr:	tyoesc "j
	pad [.06]		; no. of seconds to pad
	return


; Erase to end of line.
t61eol:	tyoesc "K
	push p,a
	move a,thmax
	sub a,h
	addi a,1
	fsc a,233
	fmpr a,[.000054]
	pad a
	pop p,a
	return


; Erase to end of screen.
t61eos:	tyoesc "J
	push p,a
	move a,tvmax
	sub a,v
	addi a,1
	fsc a,233
	fmpr a,[.0025]		; no. of seconds to pad
	pad a
	pop p,a
	return


; Insert line.
t61ilp:	push p,a
t61il1:	tyoesc "L
	call t61idp
	sojg a,t61il1
	pop p,a
	return


; Delete line.
t61dlp:	push p,a
t61dl1:	tyoesc "M
	call t61idp
	sojg a,t61dl1
	pop p,a
	return


; Insert/delete line padding.
t61idp:	push p,a
	move a,tvmax
	sub a,v
	addi a,1
	fsc a,233
	fmpr a,[.0025]
	pad a
	pop p,a
	return


; Visible bell.
t61vbl:	tyoesc "R		; enter mode select
	tyo "O			; underline, inverse video, blink
	tyo "G			; character to blink
	tyoesc "R		; sequence to shut it off
	tyo "@
	return

trmend

subttl	TEL3 - Delta Data Telterm 3

	trmbeg TEL3:,[TEL3]

tp.flg	0
tp.vsz	27.
tp.hsz	80.
tr.cho	ccho
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^K
tm.fwd	1,tyn ^Y
tm.bck	1,tyn ^H
;tm.tab	1,tyn ^I		; only 5 tab stops
tm.cr	1,tyo ^M
tm.hom	1,tyo ^T
tm.abs	6,call telabs
te.eol	tyo ^S
te.eos	tyo ^P_9+^S		; hmm, may need to set EOM symbol
te.clr	tyo ^P_9+^R
te.eim	tyo ^P_9+^Y
te.lim	tyo ^P_9+^X
te.dcp	tyn ^P_9+^V
te.ilp	tyn ^P_9+^M
te.dlp	tyn ^P_9+^L
tx.so	tyo ^_
tx.sor	tyo ^^
tabend

; Direct cursor position.
telabs:	pushae p,[a,b]
	tyo ^P_9+^N
	movei a,(nh)
	call telhex
	movei a,(nv)
	call telhex
	pad [.006]
	popae p,[b,a]
	return

telhex:	idivi a,16.
	movei a,"0(a)
	caile a,"9
	 addi a,"A-<"9+1>
	call @.trtyo+tb
	movei a,"0(b)
	caile a,"9
	 addi a,"A-<"9+1>
	pjrst @.trtyo+tb

trmend

subttl	TH3216 - DJBLOG's almost-Xitex.

Comment |
	Cannot scroll.
|

	trmbeg TH3216:,[TH3216]

tp.flg	%fsmeol
tp.hsz	31.
tp.vsz	16.
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^I
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^L
te.clr	tyo ^D
te.eol	tyo ^E
tabend


trmend

subttl  TH6416 - NEAL's almost-XITEX
	trmbeg TH6416:,[TH6416]

tp.flg	%fsmeol
tp.hsz	63.
tp.vsz	16.
tm.up	1,tyn ^N
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^I
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^K
te.clr	tyo ^L
te.eol	tyo ^O
tabend

trmend

subttl	TUBE1.5 - Intertec Data's Intertube with 1.5x

comment | 

	The intertube has been put out with n different software
	packages. This entry supports 1.5X.
 |

	trmbeg TUBE:,[TUBE1.7]

tp.flg	0
tp.vsz	25.
tp.hsz	80.			; comfortable size
tr.ini	call tubini		; set some modes
tr.cho	ccho			; Stupid losing 80th column
tr.zns	-lzt3,,zt3
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^F
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^A
tm.ax	2,call tubax
tm.ay	2,call tubay
tm.abs	4,call tubabs
te.eol	tyoesc "K
te.clr	tyo ^L
tx.so	call tubso
tx.sor	call tubsor
tabend

tubini:	tyoesc "0
	tyo "@
	tyo ^L			; Clear screen after setting regular video
	return

tubso:	tyoesc "0
	tyo "B
	return			; Blink on

tubsor:	tyoesc "0
	tyo "@
	return			; Blink off


tubabs:	call tubay

tubax:	tyo ^P
	move c,nh
	idivi c,10.
	lsh c,4
	ior c,d
	tyo (c)
	return			; Format is:upper 3 bits(7
				; total)=field,lower=loc
tubay:	tyo ^K
	tyo (nv)
	return

trmend

subttl	ADS100 - ADDS Viewpoint

	trmbeg Viewpoint:,[VIEWPOINT]

tp.vsz	24.
tp.hsz	80.
tr.cho	CCHO			; terminal auto-crlf's in last column
tm.up	1,tyn ^Z
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^F
tm.bck	1,tyn ^H		; move back n (BS)
; "claims to have tab but I don't know what it does" -Macrak
;tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
;tm.hom	1,tyo ^A  with autoscroll enabled home is LOWER left corner!
;tm.ax	2,call a100ah  no evidence the viewpoint has the X and Y only commands
;tm.ay	2,tyo _9+100(nv)
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "k
te.clr	tyo ^L
te.su	tyn ^J			; scroll the screen up
tabend

trmend

subttl	UlmoApple - Ulmo's Apple II garbage

	trmbeg ULMO:,[ULMO]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	ccho
tm.up	1,tyn ^_
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^\
tm.bck	1,tyn ^H
;tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	1,tyo ^Y
tm.abs	4,call ulabs
te.eol	tyo ^]
te.eos	tyo ^K
te.clr	tyo ^L
te.su	tyn ^J			; scroll the screen up

tabend

; Direct cursor positioning.
ulabs:	tyo ^^
	tyo 40(nh)
	tyo 40(nv)
	return

trmend

subttl	VDM1 - Jerry Pournelle's terminal

	trmbeg VDM1:,[VDM1]

tp.flg	0
tp.vsz	16.
tp.hsz	64.
tm.up	1,tyn ^K
tm.dwn	1,tyn ^J
tm.fwd	1,tyn ^L
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^^
tm.abs	3,call vdabs
te.eol	tyo ^\
te.eos	tyo ^]
te.clr	tyo ^_
te.su	tyn ^J			; scroll up

tabend

; Absolute move.
vdabs:	tyo 33
	tyo 40(nh)
	tyo 40(nv)
	return

trmend

subttl	Honeywell VIP780X

trmbeg vip780:,[VIP7800,VIP7801]

tp.hsz	80.
tp.vsz	24.
tr.cho	scho0
tr.ini	call v78ini
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd 	2,tyoesc "C
tm.bck	1,tyn ^H
tm.abs	4,call v78mov
tm.tab	1,tyn ^I
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J
te.eim	zout [asciz "[I"]	; ]
te.lim	zout [asciz "[J"]	; ]
te.dcp  zoutn [asciz "[P"]	; ]
te.ilp	zoutn [asciz "[L"]	; ]
te.dlp  zoutn [asciz "[M"]	; ]

tabend

v78ini:	tyoesc "`		; reset everything and clear the screen
	tyoesc "e
	tyoesc "m	; turn off local echo
	push p,b
	setzb nh,nv
	movei b,9.		; set 9 tabs
v78tbs:	addi nh,8.		; every 8 columns (zero based)
	call v78mov		; position cursor at a mod 8 boundary
	tyoesc "p		; set a tab stop
	sojg b,v78tbs
	pop p,b
	move h,nh		; update position
	move v,nv
	return

v78mov:	tyoesc "f		;binary absolute move selected by esc-f
	tyo 40(nh)		;first 40+x sent,
	tyo 40(nv)		;then 40+y
	return

trmend

subttl	VIS50 - Visual 50

	trmbeg	VIS50:,[VIS50]

; Added 08/23/83 by GRUPP.  This is very close to a VT52 (+ins/del line)
; but can't use any of the input/output hackery for it.  NOTE: don't use
; $v (clear screen) it seems to loose.  Home and era_eos instead.

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	call v50ini
tr.cho	scho
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J	; $B is move down, no scroll
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H	; $D is also move backward
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J		; scroll up if on bottom line
te.sd	tynesc "I	; scroll down if on top line
te.ilp	tynesc "L
te.dlp	tynesc "M
tabend

; Initialization.
v50ini:	zout [asciz "HJG"]	;$G clears loosing graphics mode
	move a,[ascnt |Warning: AUTO WRAP and AUTO LF/CR should be OFF.|]
	call stdwrn
	return

trmend

subttl	VIS200 - Visual 200

	trmbeg VIS200:,[VIS200]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.cho	scho0
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J		; line feed faster than ESC B
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "x		; ESC K and ESC J don't clear background
te.eos	tyoesc "y		; data...
te.clr	tyoesc "v
te.sd	tynesc "I
te.su	tyn ^J
te.eim	tyoesc "i		; can't be the same as anyone else
te.lim	tyoesc "j		; ...
te.dcp	tynesc "O		; ...
te.ilp	tynesc "L
te.dlp	tynesc "M
tabend

trmend

subttl	VT05 - DEC VT-05

	trmbeg	VT05:,[VT05]

tp.flg	%fspd
tp.vsz	20.
tp.hsz	72.
tr.ini	call v5ini
tm.up	[imul a,v5padn] zoutn v5up
tm.dwn	[imul a,v5padn] zoutn v5dwn
tm.fwd	1,tyn ^X
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	[move a,v5padn] zout v5hom
tm.abs	[move a,v5absn] call v5abs
te.eol	zout v5eol
te.eos	zout v5eos
te.su	zout v5dwn
tabend

tvar v5padn			;length of padded strings, for multiplying by
tvar v5absn			;pads+3, for cost of abs addressing

tvar v5up(2)			;padded string to move up
tvar v5dwn(2)			;		       down
tvar v5hom(2)			; ...
tvar v5eol(2)
tvar v5eos(2)

v5ini:	pushae p,[a,b]
	move a,speed		;4 pads at 2400, 2 at 1200, 1 at 600, else 0
	idivi a,60.
	caile a,4
	 movei a,4
	movei b,1(a)		;normal seq = 1 char + n pads
	movem b,v5padn
	movei b,3(a)		;abs seq = 3 chars + n pads
	movem b,v5absn

	move b,[.byte 7 ? 32 ? 177 ? 177 ? 177 ? 177] ;make padded strings
	and b,v5msk(a)
	movem b,v5up
	move b,[.byte 7 ? 12 ? 177 ? 177 ? 177 ? 177]
	and b,v5msk(a)
	movem b,v5dwn
	move b,[.byte 7 ? 35 ? 35 ? 35 ? 35 ? 35]
	and b,v5msk(a)
	movem b,v5hom
	move b,[.byte 7 ? 36 ? 36 ? 36 ? 36 ? 36]
	and b,v5msk(a)
	movem b,v5eol
	move b,[.byte 7 ? 37 ? 37 ? 37 ? 37 ? 37]
	and b,v5msk(a)
	movem b,v5eos

	zout v5hom
	zout v5eos
	popae p,[b,a]
	return


v5abs:	tyo ^N
	tyo 40(nv)
	push p,a
	move a,v5padn
	subi a,1
	tyn 0
	pop p,a
	tyo 40(nh)
	return

v5msk:	774000000000		;0 pads
	777760000000		;1
	777777700000		;2
	777777777400		;3
	777777777776		;4

trmend

subttl	VT50 - DEC VT-50

	trmbeg VT50:,[VT50]

tp.flg	0
tp.vsz	12.			; Tiny screen!
tp.hsz	80.
tr.ini	zout [asciz "HJ"]	; clear screen
tm.up	2,tynesc "A		; I is move up with scrolling
tm.dwn	1,tyn ^J		; B is move down, no scroll
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H		; D is also move backward
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
tabend

trmend

subttl	VT52 - DEC VT-52

	trmbeg VT52:,[VT52]

%fgph==:%ff1			; in graphics mode (VT52 only)

tr.smo	vtsmo
tr.smi	vtsmi
tr.smf	vtsmf

tp.flg	%fsail+%ffci
tp.vsz	24.
tp.hsz	80.
tr.ini	call vtinit
tr.fin	call vtfin
tr.tyi	vttyi
tr.cho	vtcho
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J		; B is move down, no scroll
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H		; D is also move backward
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
te.sd	tynesc "I		; scroll down
tabend


; Initialization.
vtinit:	zout [asciz "HJG="]	; = puts into alternate keypad mode
	trz f,%fgph		; G exited graphics mode
IFN ITS\NET,{
	move a,[ascnt |Warning: Use UPARROW (on the keypad) for [CALL].|]
	call stdwrn
}
	return


; Termination. (careful if you modify, also used by MIME52 -cbf)
vtfin:	trze f,%fgph		; in graphics mode?
	 tyoesc "G		; yes, leave it
	return


; Terminal input co-routine.
vttyi:	call tyibin		; get character
IFN ITS\NET,{
	caige a,40		; control character?
	 jrst vttyi2		; yes
}
IFE ITS\NET,{
	cain a,33
	 jrst vtesc
}
	; JRST here to output character in A and repeat loop.
vttyi1:	call bckych		; add any bucky bits
	call tyiput		; hand character to output co-routine
	jrst vttyi		; go process next character
IFN ITS\NET,{
	; control character typed
vttyi2:	cain a,33		; escape?
	 jrst vtesc		; yes
	caie a,^I		; TAB?
	 cain a,^M		; CR?
	  jrst vttyi1		; TAB or CR, don't add %TXCTL
	caie a,^J		; LF?
	 cain a,^H		; BS??
	  jrst vttyi1		; LF or BS, don't add %TXCTL
	iori a,%txctl+"@	; convert to control character
	jrst vttyi1
}
vtesc:	call tyitog		; get next character with timeout
	jumpl a,vtesc2		; timed-out
	cain a,"?		; ESC-? ?
	 jrst vtescq		; yes

	; Check for ESC- P,Q,R
	cail a,"P		; check for P,Q,R
	 caile a,"R
	  jrst vtesc1
	xct vtitb1-"P(a)	; execute
	jrst vttyi

	; Check for ESC- A,B,C,D
vtesc1:	cail a,"A		; Check for A,B,C,D
	 caile a,"D
	  jrst vtesc2
	xct vtitb2-"A(a)	; execute 
	jrst vttyi

	; Not a known ESC sequence, assume user typed it.
vtesc2:	push p,a
	movei a,33
	call bckych
	call tyiput
	pop p,a
	jumpl a,vttyi
	jrst vttyi1		; don't hack ESC-ESC as the second being an
				; escape code.

	; ESC-? seen...
vtescq:	call tyitog		; get next character with timeout
	jumpl a,vtesq1		; timed-out
	cain a,"M		; [ENTER]?
	 jrst [	call enter	; yes, goto CRTSTY command processor
		jrst vttyi ]
	cain a,"n		; "." on keypad?
	 jrst [	movei a,%TXMTA+"-  ; . is META-[MINUS]
		jrst vttyi1 ]
	cail a,"p		; 0-9?
	 caile a,"y
	  jrst vtesq1
	addi a,%txmta+"0-"p	; convert to meta-<digit>
	jrst vttyi1

vtesq1:	push p,a		; Not on alternate keypad, assume user typed.
	movei a,33
	call bckych
	call tyiput
	movei a,"?
	call tyiput
	pop p,a
	jumpl a,vttyi
	jrst vttyi1

; XCT table for ESC- P,Q,R (blank keys, VT50H and VT52).
vtitb1:	tlo f,%imeta		; P - left   (blue) blank = META
	tlo f,%ictrl		; Q - center  (red) blank = CONTROL
	tlo f,%itop		; R - right (black) blank = TOP

; XCT table for ESC- A,B,C,D (arrow keys, VT50H and VT52).
vtitb2:	jrst vti$A		; A - up    arrow = [CALL]
	tlz f,%imtc		; B - down  arrow = cancel previous keys
	jrst vti$C		; C - right arrow = [BREAK]
	jrst vti$D		; D - left  arrow = [BACK-NEXT]

vti$A:	movei a,32		; Up-arrow - ESC-A = CALL
	jrst vttyi1		; Allow M-[CALL] (defered call!)

vti$C:	movei a,%TXTOP+"B	; [BREAK]
	jrst vttyi1

vti$D:	movei a,^_		; [BACK-NEXT]
	jrst vttyi1


; Output character in A.
vtcho:	cail a,40		; control character?
	 cain a,177		; or rubout?
	  jrst vtcho1		; yes, different hackery
	trne f,%fgph		; not in graphics mode?
	 caige a,136		; or character < 136?
	  jrst scho1		; yes, go handle simply
	tyoesc "G		; leave graphics mode
	trz f,%fgph		; ...
	jrst scho1		; now output character
vtcho1:	movem a,@scrtab(v)	; store character in screen image
	tron f,%fgph		; in graphics mode?
	 tyoesc "F		; no, enter it
	caie a,177		; rubout?
	 skipn a,sailtb(a)	; no, get mapped character
	  movei a,163		; no mapping, substitute a box
	call @.trtyo+tb
	camge h,thmax		; in last column?
	 addi h,1		; no, advance one position
	return


sailtb:	000	;null
	152	;a
	176	;b
	150	;c
	167	;d
	175	;e
	172	;f
	000	;g
	000	;h
	000	;i
	000	;j
	146	;k
	171	;l
	163	;m
	160	;n
	155	;o
	145	;p
	147	;q
	151	;r
	174	;s
	143	;t
	137	;u
	157	;v
	000	;w
	144	;x
	142	;y
	154	;z
	140	;esc
	171	;less eq
	141	;great eq
	161	;equiv
	170	;down circum

;no trmend continue to MIME52,

subttl	MIME52 - Microterm MIME emulating VT52

; Background follows			^Y
; Clear foreground			^F
; Clear to end of screen background	^C
; 	spaces
; Delete line				^W
; Foreground follows			^S
; Enter format mode			^X
; Exit format mode			^T
; Home and clear			^L
; Insert line				^A
; Request cursor position		^E
;   (this will return two chars that give the cursor position as if
;    they were passed as Direct Cursor Addressing codes)
; Send line				FS (ascii 28 decimal)
; Send screen				^B
; Tab to next unprotected field		^D
; Underline				^U
;    (this will underline the character at the current
;     cursor position)

	trmtoo MIME52:,[MIME52]

tp.flg	%fsail
tp.vsz	24.
tp.hsz	80.
tr.ini	call mimini
tr.fin	call vtfin
tr.cho	vtcho			; use VT52 hackey output..
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.clr	tyo ^L
te.su	tyn ^J
te.sd	tynesc "I
te.ilp	tyn ^A
te.dlp	tyn ^W
;tx.so				 can we figure out how to use the
;tx.sor				 underline feature?
tabend

mimini:	tyo ^L			; clear screen
	tyoesc "G		; take it out of grphics mode
	trz f,%fgph		; indicate we are not in graphics mode
	return

; no trmend, continue right to RPVT2,

subttl	RPVT52 - special support for RP's VT52

	trmtoo RPVT52:,[RPVT52]

tp.flg	0
tp.vsz	24.
tp.hsz	80.
tr.ini	zout [asciz "HJ"]	; clear the screen
tr.tyi	rptyi
tr.cho	rpcho
tm.up	2,tynesc "A		; I is move up with scrolling
tm.dwn	2,tyn ^J		; B is move down, no scroll
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H		; D is also move backward
tm.cr	1,call rpcr
tm.hom	2,tyoesc "H
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
te.sd	tynesc "I		; scroll down
tabend


; Carriage return.
rpcr:	tyo ^M
	pad [.07]
	return


rptyi2:	call tyipuc
rptyi:	call tyibin
rptyi3:	caie a,^S
	 pjrst rptyi2		; Not ^S, just pass on.
	tlo f,%ipcts
	call tyibin		; Hmm, must inspect next.
	tlz f,%ipcts
	cain a,^Q		; Next char is ^Q?
	 jrst rptyi		; Yes, ignore ^S^Q sequence totally.
	push p,a		; Oops, not ^S,
	movei a,^S
	call tyipuc		; must output it after all
	pop p,a
	pjrst rptyi3		; followed by next char (but check it!)
	

; Output routine to implement / protocol.

rpcho:	tlne f,%ipcts		; has a ^S been received?
IFN ITS, .hang			; If so, wait until TYI module clears.
IFN TNX, call tnxhng
	pjrst scho		; then output normally.


subttl	VT50H - DEC VT-50H

	trmtoo VT50H:,[VT50H]

tp.flg	0
tp.vsz	12.			; very tiny screen!
tp.hsz	80.
tr.ini	zout [asciz "HJ"]	; clear the screen
tm.up	2,tynesc "A		; I is move up with scrolling
tm.dwn	2,tyn ^J		; B is move down, no scroll
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H		; D is also move backward
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
tabend

; no TRMEND - next is TRMTOO

subttl	SVT52 - Simulated VT52

	trmtoo SVT52:,[SVT52]

tp.flg	%fsail
tp.vsz	24.
tp.hsz	80.
tr.cho	svtcho
tm.up	2,tynesc "A
tm.dwn	1,tyn ^J		; B is move down, no scroll
tm.fwd	2,tynesc "C
tm.bck	1,tyn ^H		; D is also move backward
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.hom	2,tyoesc "H
tm.abs	4,call vtabs
te.eol	tyoesc "K
te.eos	tyoesc "J
te.su	tyn ^J			; scroll up
te.sd	tynesc "I		; scroll down
tabend

svtcho:	movem a,@scrtab(v)	; store character in screen image
	caige a,40		; control character?
	 tyoesc "N		; yes, quote it
	camge h,thmax		; in last column?
	 paoja h,@.trtyo+tb	; no, output character and advance one position
	pjrst @.trtyo+tb	; output character, cursor stays put

trmend

subttl	VT100 - DEC VT-100

	trmbeg VT100:,[VT100,VT101]

; Put in 8/9/78 by Moon.  Debugged 9/7/78 by EAK.  Additions 9/18/81 by Gnu.
; Uses "ANSI" mode.  Assumes you aren't using 132-column mode due to eyestrain.
; We should have a user JCL option for 132/80 column usage and smooth/non-
; smooth scrolling.  Maybe figure out at what speed smooth scrolling won't
; lose and select it by default if slow enough (300 baud for example) cause
; it looks really neat.
; Correct "SETUP B" modes are:
;  xxxx 0xx0 xxxx xxxx xxxx
; The important things here are Right Margin Bell disabled and ^Q/^S disabled.
; For some brain-damaged reason you can neither set nor read these (and a few
; other less-important things) from the remote line.
;					               Milliseconds 
; FUNCTION				           VT100         VT132
;
;ED (Erase Display)			              94	 208
;Newline, Index, LF, Reverse Index - Smooth Scroll   200	 200
;(NEL)  , (IND), LF, (RI)	   - Jump Scroll      31	  31
;DECCOLM (80/132 column mode select)		     127         131
;DECALN (Screen Align - Fill screen with E's)	     127	 131
;IL (Insert Line) see Note 1                           -  	  99
;DL (Delete Line) see Note 1			       -	  99
;EL (Erase Line)				       2	  11
;DCH (Delete Character) see Note 1		       -	   7
;DECINLM (Interlace mode select)		       1	   3
;All others except DECTST and RIS		       1	   1
;	(Confidence Test), (Reset to initial state)
;Any other character:  see Note 2		       -           1
;
;Note 1: For IL, DL, and DCH the number of fill characters required is the
;number of parameters for that command multiplied by the fill count given
;above.
;
;Note 2: "At 19,200 baud, one fill character is required for every character
;transmitted to the terminal"  - VT132 manual.

tp.flg	%fspd+%fnicp+%fndcp
tp.vsz	24.
tp.hsz	80.
tr.ini	call vt1ini
tr.cho	scho0
tm.up	3,tynans "A
tm.dwn	1,tyn ^J
tm.fwd	3,tynans "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.nl	2,tyoesc "E
tm.hom	3,tyoans "H
tm.abs	[call vt1mvc] call vt1abs
te.win	call vt1win
te.eol	tyoans "K
te.eos	call vt1eos
te.sd	tynesc "M
te.su	tyn ^J
te.eim	zout [asciz "[4h"] ;]
te.lim	zout [asciz "[4l"] ;]
te.dcp	tynans "P
te.ilp	call vt1ilp
te.dlp	call vt1dlp
tx.vbl	call vt1vbl
tx.so	zout [asciz "[7m"] ;]	; Inverse video for Standout (Gnu 18Sep81)
tx.sor	zout [asciz "[m"] ;]
tabend


; Initialization.
vt1ini:	zout [asciz "<"]	; ANSI mode.  This is ignored if already
				; in ANSI mode.
; Don't change 80 column mode, auto-repeat on keyboard, interlace, graphics.
; ANSI modes:
	zout [asciz "[20l"] ;]	; LF is Line Feed rather than New Line
; DEC modes:
; NO:	zout [asciz "[?1h"] ;]	; Cursor keys should transmit codes
	move t1,speed		; Smooth scrolling is ok at 30cps or less
	caile t1,30.
	 zout [asciz "[?4l"];]	; Jump scrolling, it's faster
	skiple jinvrs		; INVERSE specified?
	 zout [asciz "[?5h"];]	; yes, set reverse video mode
	skipge jinvrs		; NO INVERSE specified?
	 zout [asciz "[?5l"];]	; yes, set normal video
	zout [asciz "[?6h"] ;]	; Relative origin mode (relative to
				; scroll region)
; Try without changing Auto-Wrap.  This causes char typed in col 81 to
; go to the next line instead of overwriting column 80.  CRTSTY should
; never try to type in column 81.
; NO:	zout [asciz "[?7l"] ;]	; Autowrap off (I wonder what it is)
; NO:	zout [asciz "="] ;]	; Numeric keypad should send escape codes


	movei a,0		; VT1SRG arg: minimum vertical
	move b,svmax		; VT1SRG arg: maximum vertical
	call vt1sr1		; set scroll region to whole screen
	tyoans "H		; home
	tyoans "J		; clear screen
	skipl jtab		; tabs?
	 zout [asciz "[3g        H        H        H        H        H        H        H        H        H        H        H        H        H        H
"] ;]
				; Clear all tabs, set them 8 apart
	return


; Set window.  Need to worry about cursor motion.  Need a manual.
vt1win:	pushae p,[a,b,c,d]
	movem a,tvmin
	movem c,tvmax
	.i theight=tvmax-tvmin+1
	move b,c
	call vt1srg
	popae p,[d,c,b,a]
	return


; Visible bell.
vt1vbl:	skiple jinvrs		; INVERSE specified?
	 jrst vt1vbi
	zout [asciz "[?5h"];]	; Assume non-inverse, go inverse.
	pad [.1]		; wait a while
	zout [asciz "[?5l"];]	; set normal video
	return
; Visible bell with INVERSE reverses backwards (sort of)
vt1vbi:	zout [asciz "[?5l"];]	; set normal video mode
	pad [.1]		; wait a while
	zout [asciz "[?5h"];]	; set reverse video mode
	return


; Calculate absolute move cost.
vt1mvc:	movei a,4		; start with 4 for ESC-[-digit-H ;]
	movei t1,(nv)
	sub t1,tvmin
	cail t1,10.-1		; vertical position require two digits?
	 addi a,1		; yes, make it 5
	movei t1,(nh)
	sub t1,thmin
	jumpe t1,[return]
	addi a,2		; add 2 for semi-digit
	cail t1,10.-1		; horizontal position require two digits?
	 addi a,1		; yes, account for that
	return

; Absolute move.
vt1abs:	tyoesc "[ ;]
	movei a,1(nv)		; line number, 1-origin
	sub a,tvmin
	caie a,1		; 1 is default
	 call tyodec
	camn nh,thmin		; first line of scroll region?
	 jrst vt1mv1		; yes, that's default, don't send
	tyo ";
	movei a,1(nh)		; column number, 1-origin
	sub a,thmin
	call tyodec
vt1mv1:	tyo "H			; Lower-case f also works, but is a format 
				; effector instead of a cursor control.
				; Nobody but ANSI X3.64 knows the difference.
				;        (OR CARES)
	return

; Erase to end of screen
vt1eos:	tyoans "J
	move t1,speed		; punt padding for slow speed lusers
	caile t1,120.
	 pad [.09]
	return

vt1ilp:	pushae p,[a,b]		; save ACs
	move a,nv		; VT1SRG arg: line no.
	move b,tvmax		; VT1SRG arg: line no.
	call vt1srg		; set scroll region to rest of screen
	call td.mfrc
	move a,-1(p)		; restore delete count
	tynesc "M		; scroll down
	move b,speed		; get output speed
	caile b,120.		; if speed is 120cps or less, it takes enough
				; characters to send command so no need to pad.
	 jrst [  fsc a,233	; float the numer of lines moved
		 fmpr a,[.031]	; 31 milliseconds a line
		 pad a
		 jrst .+1 ]
	move a,tvmin		; VT1SRG arg: line no.
	move b,tvmax		; VT1SRG arg: line no.
	call vt1srg		; set scroll region back to whole window
	popae p,[b,a]		; restore ACs
	return

vt1dlp:	pushae p,[a,b,nv]	; save ACs
	move a,nv		; VT1SRG arg: line no.
	move b,tvmax		; VT1SRG arg: line no.
	call vt1srg		; set scroll region to rest of screen
	move nv,tvmax
	call td.mfrc		; move to NH,TVMAX
	move a,-2(p)		; restore delete count
	tyn ^J			; scroll up
	move a,tvmin		; VT1SRG arg: line no.
	move b,tvmax		; VT1SRG arg: line no.
	call vt1srg		; set scroll region back to whole window
	popae p,[nv,b,a]	; restore ACs
	return


tvar vt1srb			; line scroll region begins on
tvar vt1sre			; line scroll region ends on
; Define scrolling region from here to bottom of screen.
vt1srg:	camn a,vt1srb
	 came b,vt1sre
	  jrst vt1sr1
	return
vt1sr1:	movem a,vt1srb
	movem b,vt1sre
	tyoesc "[ ;]
	movei a,1(a)		; TYODEC arg: no.
	caie a,1		; if first parameter is 1, omit it
	 call tyodec
	camn b,svmax		; is second parameter = screen height?
	 jrst vt1sr3		; yes, omit it
	tyo ";
	movei a,1(b)		; TYODEC arg: no.
	call tyodec
vt1sr3:	tyo "r
	move v,vt1srb		; this homes (to top of region in relative
	movei h,0		; origin mode)
	return

; no TRMEND next is a TRMTOO

subttl	VT102 - DEC VT-102

	trmtoo VT102:,[VT102]
;;; Only difference from VT100 is that VT102 has char/line insert/delete
;;; standard.  These operations probably require padding at high speed,
;;; but for now, we'll just presume that most users are getting here a
;;; relatively slow way and try to get away without it.  -CBF 9 Oct 82

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call vt1ini
tr.cho	scho0
tm.up	3,tynans "A
tm.dwn	1,tyn ^J
tm.fwd	3,tynans "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.nl	2,tyoesc "E
tm.hom	3,tyoans "H
tm.abs	[call vt1mvc] call vt1abs
te.win	call vt1win
te.eol	tyoans "K
te.eos	call vt1eos
te.sd	tynesc "M
te.su	tyn ^J
te.eim	zout [asciz "[4h"] ;]
te.lim	zout [asciz "[4l"] ;]
te.dcp	tynans "P
te.ilp	call vt1ilp
te.dlp	call vt1dlp
tx.vbl	call vt1vbl
tx.so	zout [asciz "[7m"] ;]	; Inverse video for Standout (Gnu 18Sep81)
tx.sor	zout [asciz "[m"] ;]

	tabend
; no TRMEND next is a TRMTOO

subttl  IBM Personal Computer

	trmtoo IBMPC:,[IBMPC]

tp.vsz	24.
tp.hsz	80.
tr.ini	call vt1ini
tr.cho	scho0
tm.cr	1,tyo ^M
tm.nl	2,tyoesc "E
tm.hom	3,tyoans "H
tm.bck	1,tyn ^H
tm.abs	[call vt1mvc] call vt1abs
tm.tab	1,tyn ^I
te.eol	tyoans "K
te.eos	call vt1eos
te.sd	tynesc "M
te.su	tyn ^J
te.eim	zout [asciz "[4h"] ;]
te.lim	zout [asciz "[4l"] ;]
te.dcp	tynans "P
te.ilp	tynans "L
te.dlp	tynans "M
tabend
; no TRMEND next is a TRMTOO

subttl	VT132 - DEC VT-132

	trmtoo VT132:,[VT132]

; Put in by RLL on 3/30/80, cleaned up by CBF same night.
; Still need to put in hacking for character insert delete, have to
; get exact description of behavior from GMP.

tp.flg	%fspd
tp.vsz	24.
tp.hsz	80.
tr.ini	call vt3ini
tr.cho	scho0			; changed to VT3CHO if 960cps
tm.up	3,tynans "A
tm.dwn	1,tyn ^J
tm.fwd	3,tynans "C
tm.bck	1,tyn ^H
tm.tab	1,tyn ^I
tm.cr	1,tyo ^M
tm.nl	2,tyoesc "E
tm.hom	3,tyoans "H
tm.abs	[call vt1mvc] call vt1abs	; changed to VT3ABS if 960cps
te.win	call vt1win
te.eol	call vt3eol
te.eos	call vt3eos
te.sd	call vt3sd
te.su	call vt3su
te.eim	zout [asciz "[4h"] ;]
te.lim	zout [asciz "[4l"] ;]
te.dcp	call vt3dcp
te.ilp	call vt1ilp
te.dlp	call vt1dlp
tx.vbl	call vt1vbl
tx.so	zout [asciz "[7m"] ;]
tx.sor	zout [asciz "[0m"] ;]
tabend

vt3ini:	move t1,speed
	caige t1,960.
	 pjrst vt1ini
	movei t1,vt3cho
	movem t1,.trcho+tb
	movei t1,vt3abs
	hrrm t1,.tmabs+tb
	.i vt3cc=1
	pjrst vt1ini


vt3abs:	call vt1abs		; this routine used only at 960cps
	tyo 177
	return


; If speed is 120 cps or less, we'll risk not padding enough on presumption
; the buffer will generally allow the terminal to catch up before triggering
; a nasty ^S, should it be enabled for some silly reason.  We do this
; because it is important to use every possible bps of bandwidth for those
; poor losers on slow lines.  We can win with this policy as long as we
; keep no more than 96 characters outstanding in the terminals buffer.

vt3su:	tyn ^J
	move t1,speed		; punt padding for slow speed lusers
	caile t1,120.
	 jrst [	move t1,a	; numer of lines moved
		fsc t1,233	; float it
		fmpr t1,[.031]	; 31 milliseconds per line moved
		pad t1
		jrst .+1]
	return

vt3sd:	tynesc "M
	move t1,speed		; punt padding for slow speed lusers
	caile t1,120.
	 jrst [	move t1,a	; numer of lines moved
		fsc t1,233	; float it
		fmpr t1,[.031]	; 31 milliseconds per line moved
		pad t1
		jrst .+1]
	return

; Erase to end of line
vt3eol:	tyoans "K
	move t1,speed		; punt padding for slow speed lusers
	caile t1,120.
	 pad [.040]
	return

; Erase to end of screen
vt3eos: tyoans "J
	move t1,speed		; punt padding for slow speed lusers
	caile t1,120.
	 pad [.208]
	return

vt3dcp:	tynans "P
	move t1,speed		; punt padding for slow speed lusers
	caile t1,120.
	 jrst [	move t1,a	; distance characters moved
		fsc t1,233	; float it
		fmpr t1,[.007]	; 7 milliseconds per char moved
		pad t1
		jrst .+1]
	return

tvar vt3cc			; number of characters until next pad

; This incredibly crufty terminal can't keep up with simple character output
; at 960cps, so we send a pad character ever few characters output.
vt3cho:	sosle vt3cc
	 pjrst scho0
	tyo 177
	.i vt3cc=1
	pjrst scho0

trmend

subttl	XITEX - XITEX SCT-100

Comment |
HERE ARE THE FEATURES AND CAPABILITIES:
64 CHARCTERS PER LINE X 16 LINES
5 X 7 DOT-MATRIX, UPPER AND LOWER CASE WITH DESCENDERS
RS-232 (MODIFIED, XMIT AT TTL LEVELS) OR CURRENT LOOP (20/60 MA)
110 OR 300 BAUD, ASCII OR BAUDOT OPERATION, HALF/FULL DUPLEX
X-Y CURSOR ADDRESSING, (ABSOLUTE OR RELATIVE), ERASE TO END
OF LINE, ERASE TO END OF PAGE, SCROLL UP/DOWN, FULL CURSOR
CONTROL (UP, DOWN, LEFT, RIGHT) ETC. HERE ARE THE CONTROL CODES:
OCTAL	HEX	CNTL	FUNCTION
------	---	----	--------
004	04	D	HOM	HOME CURSOR TO UPPER LEFT OF SCREEN
005	05	E	EOL	ERASE END OF LINE - ERASES CURRENT LINE FROM 
                  		RIGHT MARGIN TO CURRENT POSITION (1600 MS MAX)
006	06	F	EOS	ERASE END OF SCREEN - ERASES LINES FROM BOTTOM
				OF SCREEN TO, BUT NOT INCLUDING, CURRENT LINE
				(400 MS MAX)
010	08	H	BS	BACK SPACE - MOVE CURSOR LEFT ONE COLUMN UNLESS
				ALREADY IN LEFT MOST COLUMN
011	09	I	HT	HORIZONTAL TAB - MOVES CURSOR RIGHT ONE COLUMN
				UNLESS ALREADY IN RIGHT MOST COLUMN
012	0A	J	LF	LINE FEED - MOVES CURSOR DOWN ONE LINE, SCROLLS
				SCREEN UP IF ALREADY ON BOTTOM LINE
013	0B	K	VT	VERTICAL TAB - MOVES CURSOR UP ONE LINE,
				SCROLLS DOWN IF ALREADY AT TOP LINE
014	0C	L	FF	FORM FEED - CLEARS SCREEN AND HOMES CURSOR
				(400 MS)
015	0D	M	CR	CARRIAGE RETURN - MOVES CURSOR TO LEFT MARGIN
020	10	P	DS	DOWN SHIFT - SEQUENCE CAUSES CHARACTER FOLLOW-
				ING DS TO BE INTERPRETED AS PRINTABLE RATHER 
				THAN CONTROL.  REQUIRED FOR LOWER 32 SYMBOLS 
				(GREEK AND MATH), BUT MAY BE USED WITH ANY
				CHARACTERS.
021	11	Q	DC1	DEVICE CONTROL - SETS AUX BIT.
023	13	S	DC3	DEVICE CONTROL - CLEARS AUX BIT.
033	1B	CSK	ESC	DIRECT CURSOR ADDRESING - ESC + V H ADDS V
				MODULO 16 TO VERTICAL CURSOR ADDRESS, ADDS H
				MODULO 64 TO HOIZONTAL CUSOR ADDRESS

				ESC = V H SETS VERTICAL CURSOR ADDRESS TO V
				MODULO 16, SETS HORIZONTAL CURSOR ADDRESS TO H
				MODULO 64.
				
(I.E. <ESC> + IS RELATIVE, <ESC> = ABSOLUTE)
177	7F		DEL	DELETE - MOVES CURSOR LEFT ONE COLUMN, UNLESS
				CURSOR WAS ALREADY ON LEFTMOST COLUMN; ERASES
				NEW POSTION. (E.G. BACKSPACE-SPACE-BACKSPACE
				SIMULATED IN HARDWARE (FAST!))
|

	trmbeg X100:,[XITEX]

tp.flg	%fsmeol+%fspd+%fneol+%fneos
tp.hsz	64.			; Usual low resolution TV terminal
tp.vsz	16.
tr.ini	call x1init
tm.up	1,tyn ^K		; will scroll down if at top
tm.dwn	1,tyn ^J		; will scroll up if on bottom
tm.fwd	1,tyn ^I		; weird
tm.bck	1,tyn ^H
tm.cr	1,tyo ^M
tm.hom	1,tyo ^D
tm.abs	4,call x1cabs
te.eol	call x1ceol		; Needs padding
te.eos	call x1ceos		; also needs padding
te.clr	call x1cclr		; boy what a slow eraser.
te.su	tyn ^J			; scroll up
te.sd	tyn ^K
tabend


x1init:	setzm padc		; rubout isn't a pad character!
	pjrst x1cclr


x1cabs:	tyoesc "=		; Abs positioning
	tyo 100(nv)		; uses mod 16, so can stay out of cntls.
	tyo 100(nh)		; Uses mod 64
	return

x1ceos:	tyo 06			; ^F - erase lines below current one.
	pad [.4]		; 400 msec
	; finish off with CEOL

x1ceol:	caml h,thmax		; in last column?
	 jrst [	tyo 40		; Yes, fix screwage by just giving space;
		return] ; apparently a bug causes CLEOL there to blow up.
	tyo 05			; ^E - erase to EOL
	pad [1.6]		; with ridiculously long delay
	return

x1cclr:	tyo 14			; ^L - clear and home.
	pad [.4]
	return

trmend

subttl	End of terminal definitions, wrapup

nterms==%%ntrm+1		; no. of terminals defined

IF2 {	inform
radix 8+2
	inform \nterms, terminals defined
radix 8
} ; IF2

; Already in main section
; SECTION MAIN
loc <<.+pg$siz-1>/pg$siz>*pg$siz	; Round up to page boundary
%%cons==.
constants
IF2 {
radix 8+2
	inform \<.-%%cons>, words of constants
radix 8
}

SECTION MAINVAR

variables

IF2 {
radix 8+2
	inform \., words of variables
radix 8
}

screen:	block maxhor*maxver
scren2:	block maxhor*maxver	; For saving entire screen image temporarily
sipg==:<screen+pg$siz-1>/pg$siz
ifl fipg*pg$siz-.,		.err MAINVAR section overflowed
ifl fivpg*pg$siz-init,		.err INIT section overflowed
ifl fmpg*pg$siz-initvar,	.err INITVAR section overflowed

lipg==:<init-1>/pg$siz		; last INIT page
livpg==:<initvar-1>/pg$siz	; last INITVAR page
lmpg==:<main-1>/pg$siz		; last MAIN page

IFN ITS, syspg==lmpg+1		; for mapping in system
IFN HISTOHACK, HISTPG==:SYSPG ? SYSPG==SYSPG+1 ? COUNTS==HISTPG*PG$SIZ
IFE ITS, loc <lmpg+1>*pg$siz	; put symbols in right place

end crtsty
