; -*-MIDAS-*-
;[MIT-OZ]OZ:<EMACS>TECO.MID.1210,  2-Aug-85 13:15:37, Edit by GZ
;Increase symtab, merge AJ510 term type from UDC.  Make the long filename
;code for ITS work.
;[WASHINGTON]PS:<EMACS>TECO.MID.1209, 10-Nov-83 19:02:30, Edit by FHSU
; NOTE: A CONFIG.MID file is used to customize TECO to a site.
;	A TECTRM.MID file is used to customize TECO to terminal types.
;-----------------------------------------------------------------------------
;ITS TECO was built by RMS on the work of others
;at the MIT Artificial Intelligence Lab
;(not to be confused with the Laboratory for Computer Science).
;It was converted to run on Twenex by MMCM at SRI.
;
;TECO is available to those who like the way it is,
;on a basis of communal co-operation:
;you are welcome to make improvements, but only if you consult
;with the other user sites, and send your changes
;to MIT to be merged in and distributed to everyone.

.SYMTAB 9733.			;SHOULD BE PLENTY

TITLE TECO

; RESET THE SYSTEM CONDITIONALS NOT SPECIFIED BY /T AT ASSEMBLY TIME.
IFNDEF ITS, ITS==0
IFNDEF 10X, 10X==0
IFNDEF FNX, FNX==0
IFNDEF 20X, 20X==0
IFG ITS+10X+FNX+20X-1, .FATAL TWO OPERATING SYSTEMS SPECIFIED

; IF NO SYSTEM SPECIFIED THEN DEFAULT TO THE ONE WE'RE ASSEMBLING ON.
IFE ITS\10X\FNX\20X,[
IFE .OSMIDAS-SIXBIT/ITS/,   ITS==1
IFE .OSMIDAS-SIXBIT/TENEX/, 10X==1
IFE .OSMIDAS-SIXBIT/TWENEX/,20X==1
]
IFE ITS\10X\FNX\20X, .FATAL NO OPERATING SYSTEM SPECIFIED

TNX==:10X\FNX\20X		;TNX MEANS EITHER TENEX OR TWENEX
				;FOR NOW, FNX JUST TURNS ON SOME CROCKS
				;HOPEFULLY, LATER IT WILL MEAN COMND JSYS,
				;VTS, ETC.

IFN TNX,[
IFNDEF EMCSDV,EMCSDV==0	;NONZERO CAUSES TRANSLATION OF <EMACS> TO EMACS: FOR 20X.
IFNDEF INFODV,INFODV==0
IFNDEF EXITCL,EXITCL==0	;CLEAR THE SCREEN WHEN EXITING OR RUNNING AN INFERIOR
IFNDEF COMNDF,COMNDF==20X	;USE COMND JSYS FOR :ET, WORKS ON TWENEX REL >=3
IFNDEF SUMTTF,SUMTTF==0		;SUMEX TTY CODE FOR TENEX
IFN SUMTTF,STCHA=JSYS 633	;SET HOLD CHARACTER
IFNDEF LINSAV,LINSAV==0		;ASSUME TWENEX DOESN'T HAVE SUPDUP CAPABILITY
.DECSAV
IFN .OSMIDAS-SIXBIT/TENEX/,[
    IFN .OSMIDAS-SIXBIT/TWENEX/,[
	IF1 [
	    .INSRT SYS:TNXDFS
	    .TNXDF
	    .INSRT SYS:TWXBTS
	    ]]]
]

IFN ITS,[
.SBLK
LINSAV==1
IFNDEF MAXLBL,MAXLBL==400	;HIGHEST LABEL NUMBER WE CAN HANDLE, FOR LINE SAVING.
COMNDF==0
IFN .OSMIDAS-SIXBIT/ITS/,[
    IF1 [
	.INSRT SYS:ITSDFS
	.ITSDF
	.INSRT SYS:ITSBTS
	]]
]

GLITCH==177
ALTMOD==33
IFN ITS,EOFCHR==3	;PADDING CHARACTER FOR FILES.
IFN TNX,EOFCHR==0
IFN ITS,PAGSIZ==2000	;PAGE SIZE, IN WORDS.
IFN TNX,PAGSIZ==1000

IFN TNX,.INSRT CONFIG	;READ SITE-SPECIFIC DEFINITIONS.

IRPS AC,,FF A B C D E J BP T TT TT1 IN OUT CH Q P
AC=.IRPCNT
TERMIN

A0==TT		;ACS FOR .I PSEUDO.
A1==TT1

.XCREF FF,P,A,B,C,IN,OUT,CH,T

IFN 0,[		;I HOPE THAT EVERYTHING THAT DEPENDS ON ORDER OF ACS
MUL: MULI: DIV: DIVI: IDIV: IDIVI:	;WILL X-REF TO ONE OF THESE.
ROTC: ASHC: LSHC: CIRC:
BLT: JFFO:
.OPEN: .RDATIM:
]

IFN ITS,[
CHTTYI==1
CHFILI==3
CHFILO==4
CHRAND==6	;FOR READING FILE DIRECTORIES
CHDPYO==7	;BLOCK MODE DISPLAY OUTPUT FOR ASSEMBLED-IN ^P-CODE STRINGS.
CHERRI==11
CHECHO==12	;ECHO-MODE OUTPUT FOR RUBOUT.
CHSIO==14	;SUPER IMAGE OUTPUT.
CHTTYO==15	;NORMAL TYPEOUT.
CHJRNI==16	;JOURNAL FILE INPUT.
CHJRNO==17	;JOURNAL FILE OUTPUT.

TYPIN==1_<CHTTYI>
TSMSK==%PJATY\%PJWRO\%PJRLT,,%PIPDL+%PIMPV
TSMSK1==TYPIN

%TSNEA==1000	;BIT 4.1 IN TTYSTS: ECHO IN MP AREA EVEN IF AN ECHO AREA EXISTS.
		;FOR THE SAKE OF THE ECHOIN SYSTEM CALL AND RRECIN.

OPNLBP==220600	;B.P. TO OPEN LOSS CODE IN CHANNEL STATUS.
];IFN ITS
;LOCAL EDITING IN THE TERMINAL

%TRLED==100000	;BIT IN TTYSMT, WHICH SAYS TERMINAL CAN DO LOCAL EDITING.
%TRLSV==034000	;THESE BITS GIVE MAX LABEL FOR LINE SAVING, AS LOG BASE 4.

%TDSYN==240	;%TDSYN code charcount IS A REPLY TO A RESYNCH FROM THE TERMINAL.
%TDECO==241	;REQUESTS USE OF REMOTE (IN-TERMINAL) ECHOING FEATURE.
		;THIS JUST ASKS THE TERMINAL TO SEND US A RESYNCH IF IT CAN.
%TDEDF==242	;SPECIFIES FUNCTIONS OF CONTROL CHARS.
		;FOLLOWED BY 2 CHARS, WHICH MAKE UP 14 BITS,
		;WHICH THEN DIVIDE INTO THE BOTTOM 9 BITS (CHARACTER CODE)
		;AND THE TOP 5 BITS, WHICH SAY WHAT THAT CHARACTER DOES.
		;THE FUNCTION CODES ARE DEFINED IN LMWIN;SUPDUP.
		;TECO DOES NOT KNOW WHAT MOST OF THE CODES MEAN; TECO PROGRAMS DO.
		;HOWEVER, CODE 31 MEANS RESET WORD SYNTAX OF CHAR (CTL BIT MEANS
		;PART OF WORD),
		;CODE 32 MEANS SELECT INSERT OR REPLACE MODE
		; (LOW BIT OF CHAR = 1 FOR INSERT MODE),
		;CODE 33 MEANS REINITIALIZE
		; (CHARS 40 THRU 176 SELF-INSERT, OTHERS UNDEFINED;
		;  ONLY LETTERS ARE PART OF WORDS; INSERT MODE).
%TDNLE==243	;SENT BY ITS, WHENEVER TTY SWITCHES JOBS,
		;TO TELL TERMINAL TO STOP DOING LOCAL EDITING.
%TDTSP==244	;JUST LIKE A SPACE, BUT SIGNIFIES THAT THE SPACE
		;IS PART OF THE DISPLAY OF A TAB CHARACTER.
%TDCTB==245	;THIS LINE BEGINS WITH A CONTINUATION.
%TDCTE==246	;THIS LINE ENDS WITH A CONTINUATION.
%TDMLT==247	;%TDMLT <N> <CH> SAYS NEXT <N> SCREEN POSITIONS REPRESENT ONE TEXT CHAR <CH>.
%TDSVL==250	;%TDSVL <N> <L1> <L2> SAVE N LINES STARTING AT CURSOR
		;UNDER LABELS STARTING WITH <L2>*7+<L1>
%TDRSL==251	;INVERSE OPERATION: RESTORE <N> LINES.
%TDSSR==252	;SET RANGE OF COLUMNS TO SAVE AND RESTORE.  WE DON'T NEED THIS.
%TDSLL==253	;SET LABEL FOR TERMINAL TO SAVE LINES UNDER.  WE DON'T SUPPORT THIS.

SUBTTL FLAGS IN FF

;RIGHT HALF FLAGS

FR==525252	;BIT TYPEOUT PREFIX.
FRARG==1	;THIS COMMAND HAS A POSTCOMMA ARG
FRARG2==2	;THIS COMMAND HAS A PRECOMMA ARG
FRCLN==4	;THIS COMMAND WAS GIVEN THE COLON MODIFIER
FRUPRW==10	;THIS COMMAND WAS GIVEN THE ATSIGN OR UPARROW MODIFIER.
FRALT==20	;RANDOM FLAG USED BY SEVERAL COMMANDS
FROP==40	;SET WHEN ARITH OP NEEDS A RIGHT ARG.
FRSYL==200	;A SYLLABLE IS AVAIL TO USE AS RIGHT OPERAND OF ARITH OP.
FRFIND==2000	;FA AND FILENAME READER USE THIS.
FRQMRK==4000	;LAST COMMAND STRING HAD ERROR;  "?" IN COMMAND READER PRINTS LAST FEW CHARS.
FRNOT==10000	;RANDOM FLAG USED BY SEVERAL COMMANDS
FRTRACE==20000	;TRACE IN PROGRESS:  PRINT TECO COMMANDS AS EXECUTED.
FRBACK==40000	;SEARCH IN REVERSE (ARGUMENT NEGATIVE)
FRQPRN==100000	;IN ('S SAVED FLAGS, 1 => THIS ( WAS A Q-REG NAME, SO
		;CLOSE SHOULD RETURN TO QREGXR.
FRSPAC==200000	;IN FA, PREVIOUS CHAR WAS A SPACE.

;LEFT HALF FLAGS

FL==1,,525252	;BIT TYPEOUT PREFIX
FLNEG==1	;DPT-ING A NEGATIVE NUMBER
FLDIRDPY==2	;SET => LAST COMMAND WAS FILE COMMAND, SO DISPLAY DIR INSTEAD OF BUFFER
FLIN==200	;INPUT FILE OPEN.
FLOUT==400	;OUTPUT FILE OPEN
FLNOIN==400000	;INSIDE ^R, 1 => THIS IS A ^ V, AND SHOULD READ NO INPUT.


SUBTTL OPCODES AND BITS

TYPR4=37000,,
NUUOS==1

CALL=PUSHJ P,
SAVE=PUSH P,
REST=POP P,
RET=POPJ P,

IF1 EXPUNGE EDIT		;STUPID WORTHLESS EXTENDED INSTRUCTION GETS IN THE WAY.
EXPUNGE DMOVE,DMOVEM		;TWENEX PEOPLE ARE TEMPTED TO USE THESE AND SCREW TENEX.

.XCREF CALL,REST,SAVE,RET

BP7==440700

;BITS IN 12-BIT AND 9-BIT CHARACTERS
CONTRL==200
META==400
SHIFT==1000
SHIFTL==2000
TOP==4000

SUBTTL DOUBLE-DOT Q-REGS

IFNDEF NQSETS,NQSETS==3
NQREG==<"Z-"A+1+"9-"0+1>*NQSETS
.QCRSR==10.		;..A HOLDS CURSOR.
.QBFDS==.QCRSR+1	;..B HOLDS MACRO EXECUTED AT END OF CMD STRING IF BUFFER DISPLAY WANTED (FLDIRDPY IS OFF)
.QCPRT==.QBFDS+1	;..C IS UNUSED
.QDLIM==.QCPRT+1	;..D HOLDS DISPATCH FOR FW, "B, "C, ^B IN SEARCHES.
.QBASE==.QDLIM+1	;..E HOLDS OUTPUT RADIX FOR = AND \. (INITIALY 10.)
.QCRMC==.QBASE+1	;..F HOLDS ^R MODE SECRETARY MACRO.
.QFDDS==.QCRMC+1	;..G HOLDS MACRO EXECUTED AFTER COMMAND STRING TO DISPLAY FILE DIRECTORY.
.QVWFL==.QFDDS+1	;..H IS NONZERO IF THERE HAS BEEN TYPEOUT BY PRGM (SUPPRESS BUFFER DISPLAY)
.QPT1==.QVWFL+1		;..I HOLDS WHAT . HAD AT START OF CMD STRING.
.QMODE==.QPT1+1		;..J HOLDS "MODE" STRING, DISPLAYED ON THE --MORE-- LINE.
.QRRBF==.QMODE+1	;..K HAS WHAT WAS KILLED IN ^R MODE.
.QRSTR==.QRRBF+1	;..L HOLDS MACRO EXECUTED WHEN TECO IS $G'D.
.QLOCL==.QRSTR+1	;..M IS UNUSED
.QUNWN==.QLOCL+1	;..N HOLDS STRING MACROED BEFORE QREG UNWOUND.
.QBUFR==.QUNWN+1	;..O HOLDS CURRENT BUFFER.
.QERRH==.QBUFR+1	;..P HOLDS ERROR-HANDLER MACRO.
.QSYMT==.QERRH+1	;..Q HOLDS SYMBOL TABLE SCANNED FOR Q<NAME> CONTRUCT.
.Q..Z==10.+"Z-"A	;..Z HOLDS SAME AS ..O, INITIALLY.

.QKS==0	;..0, ..1, ..2 USED BY ^P SORT.
.QKE==1
.QDL==2
.Q..0==0	;OTHER NAMES FOR ..0, ..1, ..2
.Q..1==.Q..0+1
.Q..2==.Q..1+1
.Q..3==.Q..2+1

IF2 [
$QCRSR==QTAB+36.*2+.QCRSR
$QCRMC==QTAB+36.*2+.QCRMC
$QMODE==QTAB+36.*2+.QMODE
$QUNWN==QTAB+36.*2+.QUNWN
$QBUFR==QTAB+36.*2+.QBUFR
$Q..0==QTAB+36.*2+.Q..0
$QMODE==QTAB+36.*2+.QMODE
$QERRH==QTAB+36.*2+.QERRH
]

IFNDEF LIOPDL,LIOPDL==8		;IO PDL SIZE (MUST BE < ITS'S)
IFNDEF FDRBFL,FDRBFL==100.	;SIZE OF FILE DIR READING BUFFER.
IFNDEF LPDL,LPDL==200		;SIZE OF REGULAR PDL.
IFNDEF MFNUM,MFNUM==25.		;[ ;INITIAL # OF FRAMES FOR MACRO OR ^] CALLS, OR ITERATIONS.
IFNDEF MFMAX,MFMAX==105.	;MAXIMUM NUMBER OF FRAMES.
IFNDEF MFINCR,MFINCR==20.	;NUMBER OF NEW FRAMES TO ALLOCATE AT ONCE.
IFNDEF SLPQWR,SLPQWR==20000	;# WDS TO EXPAND IMPURE STRING SPACE BY.
IFNDEF SLPWRD,SLPWRD==400	;# WDS TO EXPAND BUFFER GAP BY.
IFNDEF GCOFTN,GCOFTN==5*2000*10.	;# CHARS OF IMPURE STRINGS WRITTEN TO CAUSE A GC.
IFNDEF LPF,LPF==400		;QREG PDL # WDS (2 WDS/ENTRY)
IFNDEF STBLSZ,STBLSZ==300	;SEARCH TABLE SIZE.
IFNDEF CBUFSZ,CBUFSZ==10.	;INITIAL # WDS IN CMD BUFFER.
IFNDEF MACPSZ,MACPSZ==<2*MFMAX+8>/9	;# WDS IN MACRO PDL (4-BIT BYTES)
IFNDEF FSPSPL,FSPSPL==20	;LENGTH OF RING BUFFER OF POINT.
IFNDEF UTBSZ,UTBSZ==40		;LENGTH OF I-O BUFFERS.
IFNDEF LHIMAX,LHIMAX==400	;NUMBER OF 1ST PAGE NOT AVAIL FOR :EJ
IFNDEF TYIBSZ,TYIBSZ==20.	;RECORD LAST 60 CHARACTERS TYPED.
IFNDEF CTRLT,CTRLT==0		;WE DO NOT WANT THE OLD ^T COMMAND.
IFNDEF FNMLEN,FNMLEN==40	;LENGTH IN WORDS ALLOCATED FOR FILENAME STRING.
IFNDEF FNBLEN,FNBLEN==2*14	;14 ELEMENTS ALLOWED IN FILENAME BLOCKS.

SPD==60.*60.*24.	;NUMBER OF SECONDS IN A DAY (FITS IN A HALFWORD)

SUBTTL MACROS

DEFINE DBP7 A
	ADD A,[70000,,]
	SKIPGE A
	SUB A,[430000,,1]
TERMIN

DEFINE INSIRP A,B
	IRPS ZZZ,,[B]
	A,ZZZ
TERMIN TERMIN

DEFINE CONC CONC1,CONC2
CONC1!CONC2!TERMIN

;ERROR MACRO: TYPRE [ERRCODE]
DEFINE TYPRE A
	TYPR4 ER$!A
TERMIN

IF2 ISKER1==TYPRE [ISK]		;"INVALID SORT KEY" ERROR, IF WITHIN A ^P COMMAND.
DEFINE ISKERR
	SKIPE PSSAVP
	 TYPRE [ISK]
TERMIN

;GIVEN MACPTR OR CTXPTR, SKIP IF THAT STACK IS NOT EMPTY.
DEFINE SKNTOP X
	SKIPN A,X
TERMIN

;SAY HOW ASSEMBLY IS PROGRESSING, AND HOW MUCH CORE IT TAKES SO FAR.
DEFINE INFORM A,B
IF1,[PRINTX \A = B
\]TERMIN

;SUPPY AN ARITH OP WITHOUT A RIGHT ARG WITH 1 AS AN ARG.
;OPTIONALLY (IF FOO IS Z, O OR N) DEFAULT NO ARG TO AN ARG OF 1,
;PERHAPS SETTING OR CLEARING THE ARGUMENT FLAG (IF FOO IS O OR Z)
DEFINE ARGDFL FOO	;FOO SHOULD BE "O", "Z", "N" OR NULL.
IFNB FOO,TR!FOO!E FF,FRARG
	TRZE FF,FROP
	 CALL ARGDF0
TERMIN

SUBTTL SYSTEM-DEPENDENT MACROS TO REDUCE CONDITIONALS ELSEWHERE

IFN ITS,[
DEFINE SIXBNM A
SIXBIT/A/TERMIN

DEFINE TSOPEN A,B
	.OPEN A,B
	 .LOSE %LSFIL
	TERMIN

DEFINE SYSCAL A,B
	.CALL [SETZ ? SIXBIT/A/ ? B ((SETZ))]
TERMIN

;MAKE NEXT TTY INPUT NOT WAIT FOR AN ACTIVATION CHARACATER.
DEFINE TTYACT
	CALL TTYAC1
TERMIN

;WAIT FOR OUTPUT TO FINISH;  RETURN # CHARS OF AVAILABLE INPUT IN AC "X".
DEFINE LISTEN X
	.LISTEN X,
TERMIN

DEFINE CIS
	.SUSET [.SPICL,,[-1]]
TERMIN

DEFINE CLOSEF X
	.CLOSE X,
TERMIN

DEFINE DISSTR *STRING*	;GENERATE AN ARG FOR DISIOT.
	MOVE Q,[-<<.LENGTH /STRING/+4>/5>,,[ASCIC /STRING/]]
TERMIN
]

IFN TNX,[
DEFINE .VALUE
	JSR ERRRET
TERMIN

DEFINE TTYACT
TERMIN

DEFINE STRCNC STR1,STR2
ASCIZ \STR1!STR2\
TERMIN

DEFINE LISTEN X
IFN X-1,SAVE 1
IFN X-2,SAVE 2
	MOVEI 1,.CTTRM
	SKIPE DWAIT
	DOBE
	SIBE
	 SKIPA X,2
	  SETZ X,
IFN X-2,REST 2
IFN X-1,REST 1
TERMIN

DEFINE CLOSEF X
	MOVE 1,X
	CLOSF
	 JFCL
	SETZM X
TERMIN

DEFINE DISSTR *STRING*	;GENERATE AN ARG FOR DISIOT
	HRROI Q,[ASCIZ /STRING/]
TERMIN

IFNDEF .FNAM3,.FNAM3==.FVERS

IF1 EXPUNG BOOT,OPEN,CLOSE
]

SUBTTL DISPLAY VARIABLES

LOC 41
	JSR UUOH
IFN ITS,JSR TSINT
IFN ITS,LOC 100
IFN TNX,LOC 140	;DONT GET SMASHED BY LINK VARIABLES

RGETTY:	0	;TCTYP VARIABLE OF TTY.
TTYOPT:	0	;TTYOPT VARIABLE OF TERMINAL.
TTYSMT:	0	;TTYSMT VARIABLE OF TERMINAL.
OSPEED:	0	;OUTPUT LINE SPEED IN BAUD, OR 0 IF UNKNOWN.
TABWID:	10	;WIDTH OF TAB - DISTANCE BETWEEN TAB STOPS.  FS TABWID.
NVLNS:	0	;# VERTICAL LINES ON CONSOLE
NHLNS:	0	;# HORIZONTAL POSITIONS ON CONSOLE
USZ:	0	;# VERTICAL LINES USABLE FOR DISPLAY. MUST FOLLOW NHLNS.
IFN USZ-NHLNS-1,.ERR
NELNS:	0	;# ECHO LINES (NVLNS-USZ). USUALLY 3, SET BY FS ECHO $
MXNVLS==70.
MXNHLS==160.
TOPLIN:	0	;# OF 1ST LINE OF SCREEN TO USE FOR BUFFER DISPLAY.
NLINES:	0	;# LINES OF BUFFER TO DISPLAY, 0 => DEFAULT
		; (2 ON TTYS, AS MANY AS WILL FIT ON DISPLAYS)
VSIZE:	0	;# OF LINES FOR VBD TO USE (SAME AS NLINES, OR THE DEFAULT # OF LINES).
BOTLIN:	0	;# OF 1ST LINE BELOW WINDOW.
RRTOPM:	0	;BOTTOM OF "TOP MARGIN" WHERE CURSOR SHOULDNT GO (SET BY %TOP)
RRBOTM:	0	;TOP OF "BOTTOM MARGIN" WHERE CURSOR SHOULDNT GO (SET BY %BOTTOM)
DISTRN:	0	;-1 => TRUNCATE LINES, ELSE CONTINUE THEM.
DISPCR:	0	;-1 => STRAY CR REALLY DOES A CR.
		;IF NOT OUTPUT AS CR, IT IS OUTPUT AS UPARROW-M.
		;ALSO SIMILARLY CONTROLS WHETHER STRAY LF'S ARE OUTPUT AS LF OR ^-J.
DISPBS:	0	;-1 => ^H OUTPUT AS BS.  OTHERWISE IT IS OUTPUT AS UPARROW-H.
DISSAI:	0	;ASSUME CTL CHARS ARE 1-POSITION GRAPHICS INSTEAD OF PRINTING AS ^-MUMBLE.
LID:	0	;NONZERO => TRY TO USE INSERT/DELETE LINE TO MOVE TEXT AROUND.
CID:	0	;NONZERO => USE CHAR I/D FOR SIMPLE ^R INSERT/DELETE COMMANDS
NOCEOL:	0	;NONZERO => TERMINAL DOESN'T HAVE CLEAR TO END OF LINE.
EOLFLG:	0	;KLUDGE FLAG FOR TERMINALS WITH NO CLEOL
IFN ITS,[
	.BYTE 8	;STRINGS TO OUTPUT IN SUPERIMAGE OUTPUT MODE:
EXPUNG DISCPV DISC1V DISCPH MORMCV
DISCMV=,.	;SET CURSOR AND CLEAR LINE.
	%TDMV0 ? DISCPV: 0 ? 0 ? %TDEOL
DISCM1=,.	;SET CURSOR, DON'T CLEAR LINE.
	%TDNOP ? %TDMV0 ? DISC1V: 0 ? DISCPH: 0
	.BYTE
IFN 700000&(DISCPH),[	;IF MIDAS DEFINED ALL THE TAGS 1 BYTE TO SMALL, FIX THEM UP.
IRPS XX,,DISCPV DISCPH DISC1V
.AOP IBP,1,XX
EXPUNGE XX
XX=IFN .AVAL1-1,[.AVAL1] .ELSE [.AVAL2]	; KLUDGE FOR KL'S
TERMIN
]] ;IFN ITS
DISVP:	-1	;VERT POS. OF LAST LINE GIVEN TO DISLIN, REGARDLESS OF
		;WHETHER THE LINE ACTUALLY HAD TO BE IOTTED.
		;(-1 ==> JUST WENT TO TOP OF SCREEN)
		;IF DISLIN SEES IT IS HACKING SAME LINE AS PREVIOUS
		;CALL TO DISLIN, IT DOESN'T CLEAR THE LINE.
DISVP1:	0	;VERT. POS. OF MAIN PRGM AREA TTY CURSOR.
		;TO MOVE TO LINE <C(DISVP1)+1>, DO AN LF INSTEAD OF
		;THE USUAL ^PV.
DISFLF:	0	;-1 ==> FORCE DISLIN TO SET CURSOR POS.

CHCTBP:	0	;BP. FOR CHCT TO STUFF CHARS.
		;1 => DISCARD CHARS BUT COMPUTE HASH.  0 => DON'T HASH EITHER.
		;TYOFLG MUST BE -1 IF CHCTBP IS 0 OR 1.
CHCTVS:	0	;LAST +1 LINE FOR CHCT TO USE (= BOTLIN EXCEPT DURING TYPEOUT ON PRINTING TTY)
CHCTHP:	0	;POSITION IN TYPED LINE (FOR CONTINUATION AND TABS)
CHCTCF:	0	;-1 ==> LAST CHAR GIVEN TO CHCT WAS ^M.
CHCIGN:	0	;-1 => OUTPUTTING TRUNCATED PORTION OF LINE.
CHCTAD:	0	;CHCT PUSHJ'S @. WITH EACH LINE.
CHCTVP:	0	;VERT. POS. OF THAT LINE.
CHCTHC:	0	;HASH CODE OF THAT LINE.
CHCTBL:	0	;WHEN @CHCTAD CALLED, THIS HOLDS CHAR ADDR 1ST CHAR
		;IN THE LINE BEING DISPLAYED. (ASSUMING THAT
		;DISAD WAS CALLED WITH IN HOLDING ADDR
		;OF THE CHAR AFTER THE ONE BEING OUTPUT.)
CHCTNL:	0	;WHEN @CHCTAD CALLED, THIS WD >0 => CHAR ADDR
	;1ST CHAR TO APPEAR ON NEXT SCREEN LINE (IF ANY)
	;-1 => NEXT CALL TO @CHCTAD WILL BE ON SAME SCREEN LINE.
CHCRHP:	0	;WHEN @CHCTAD CALLED, THIS IS HPOS AT WHICH TTY CURSOR WILL BE LEFT (FOR SCPOS)
CHCOVP:	0	;WHEN @CHCTAD CALLED, INDICATES A STRAY ^M OR ^H WAS JUST IOTTED.
ORESET:	0	;OUTPUT STOPPED BY QUIT NOW IN PROGRESS
MORFLF:	0	;USER HAS FLUSHED TYPEOUT (1 => WITH RUBOUT, -1 => WITH OTHER CHAR)
OLDFLF:	0	;GETS VALUE OF MORFLF WHEN TYPEOUT IS UN-FLUSHED AGAIN (RETURN TO ^R, ETC).
MORNXT:	0	;NONZERO => NEXT CHAR OUTPUT SHOULD TRIGGER A --MORE--.
MORESW:	0	;0 => NO --MORE-- OR ANYTHING.  1 => --BOT--.  2 => --TOP--.  ETC.
MS%UP==1	;VALUES 0, 1, 2 AND 3 ARE MADE OF THESE 2 BITS.
MS%DWN==2	;MS%UP MEAN'S THERE'S TEXT ABOVE THE SCREEN;  MS%DWN, THAT THERE'S TEXT BELOW.
		;IF IT'S 3 THEN THE LH IS THE PERCENTAGE OF THE FILE ABOVE SCREEN.
MS%MOR==4	;4 MEANS THAT --MORE-- IS BEING DISPLAYED.
MS%FLS==5	;5 MEANS THAT --MORE--FLUSHED IS BEING DISPLAYED.
;ADDITIONAL BITS IN MORESW.  THESE NEVER ACCOMPANY MS%MOR OR MS%FLS.
MS%MOD==10	;10-BIT MEANS THERE IS A STAR IN THE MODE LINE, MEANING THE BUFFER IS MODIFIED.
MS%LOS==20	;SET => MODE LINE DOESN'T MATCH MORESW, AND MUST BE UPDATED.
MS%PCT==40	;SET => RECALCULATE PERCENTAGE FOR --NN%--, AND REDISPLAY IT IF CHANGED.
MOREHP:	0	;HPOS AT WHICH THE --TOP-- (OR WHATEVER) STARTS IN THE MODE LINE.
DISOMD:	-1	;WHAT $QMODE HAD WHEN LAST DISPLAYED.
		;IF $QMODE NE DISOMD, MUST REDISPLAY THE MODE.
MODCHG:	0	;POSITIVE => ..J NEEDS TO BE RECOMPUTED, SO RUN MODMAC.
		;NEGATIVE => IT IS -2* A FS QP PTR$.  IF POP PAST THERE, MUST RUN MODMAC.
MODMAC:	0	;NON-0 => IT IS MACRO TO RECOMPUTE ..J WHEN IT IS ABOUT TO BE DISPLAYED.
TYOFLG:	-1	;>= 0 ==> TYPEOUT INITTED.
ECHACT:	0	;-1 => SOMETHING WAS PRINTED IN THE ECHO AREA, SO ^R SHOULD CLEAR IT.  FS ECHO ACTIVE$
		;1 => CLEAR AFTER NEXT COMMAND BUT NOT AFTER THIS COMMAND.
ECHFLS:	0	;NONZERO TO ENABLE THE ECHACT FEATURE.  FS ECHO FLUSH$.
ECHONL:	0	;-1 => NEXT ECHO AREA OUTPUT SHOULD GO TO FRESH LINE AND CLEAR IT.
ECHCHR:	0	;-1 => LAST COMMAND HAS TYPED OUT, SO ^R SHOULDN'T ECHO IT.
		;OTHERWISE, IT IS CHARACTER OR STRING TO ECHO.
		;(PRINTING TERMINALS ONLY).
RUBENC:	0	;NONZERO => IS CHAR OR STRING TO TYPE BEFORE TYPING ANYTHING ELSE
		;(EG, \, AFTER A RUBOUT IN ^R IN SCANNING MODE).  FS XPROMPT$.
BSNOLF:	0	;-1 => BACKWARD MOTION AND RUBBING OUT SHOULDN'T DO LF'S (PRINTING TTY ONLY).
DISADP:	0	;WHEN DISAD IS CALLED, THIS SHOULD HOLD C(PT)+1.
		;USED BY DISAD TO DECIDE WHEN TO OUTPUT CURSOR.
TTYMAC:	0	;MACRO FOR FS TTY INIT$ TO CALL TO RESET TTY PARAMETERS FOR USER OPTIONS.
INVMOD:	0	; NONZERO MEANS SET THE MODE LINE INVERSE VIDEO
SCINV: 0	; NONZERO MEANS CHARACTERS BEING OUTPUT IN STANDOUT MODE
IFNDEF DISBFL,DISBFL==MXNHLS/4+1	;LENGTH OF TTY IOT BUFFER.

IFN TNX,[
TTYNBR: -1	;.CTTRM NUMBER FOR T(W)ENEX.
SGTTYP: 0	;EXPLICIT TYPE OR -1,,SYSTEM TERMINAL TYPE
PADCHR:	177	;CHARACTER FOR PADDING, -1 => USE DELAY INSTEAD OF PADDING.
BBNPAD: 0	;PAD CALCULATION FOR BITGRAPHS
TIMPDS:	.BYTE 7	;ASCIZ STRING OF RUBOUTS OR WHATEVER
	REPEAT 100.,177
	.BYTE
TIMPDE::

AALSCL::	;USED BY AMBASSADOR SUPPORT FOR LAST-SCREEN CLEAR TIME
C1PADF::	;USED BY C100 FOR HOLDING PAD MULTIPLIER
VT1BUF::	;USED ALSO BY VT100 FOR SCROLLING COMMANDS
BBNBUF::	;USED BY BITGRAPH FOR SCROLLING COMMANDS
HPBUF:	BLOCK 4	;BUFFER FOR HP CURSOR MOTION COMMANDS
DISBF1:	BLOCK 6	;HOLDS STUFF TO SET CURSOR POS FOR THE LINE IN DISBUF.
]
IFN ITS,[	;DISBF1 AND DISBUF IOTTED AT ONCE.
DISBF1:	BLOCK 2	;IF NO CURSOR MOTION NEEDED, THIS HOLDS %TDNOP (0 ON TENEX).
]
DISBUF:	BLOCK DISBFL	;BUFFER FOR TEXT TO BE IOTTED TO TTY.
DISBFC:	0	;# CHARS SPACE LEFT IN DISBUF.

DISPRR:	0	;NON0 => PDL LEVEL AT RRDISP.
		;CAUSES CRSR POS AT PT TO BY REMEMBERED, ETC.
GEA:	0	;-1, OR OLD ADDR (REL TO BEG) OF 1ST CHAR OF BUFFER DISPLAYED.
%TOP:	10.	;PERCENT OF SCREEN CURSOR SHOULDN'T ENTER AT TOP.
%BOTTO:	10.	;SIMILAR, FOR BOTTOM.
%CENTE:	40.	;PERCENT FROM TOP CURSOR SHOULD GO WHEN WINDOW CHANGES.
%END:	30.	;WHEN WINDOW MOVED, CURSOR MUST BE >= THIS MUCH FROM BOTTOM.
CLRMOD:	-1	;-1 => CLEAR SCREEN IN DISTOP IF TTY
		;HAD BEEN TAKEN AWAY AND RETURNED BY TECO'S SUPERIOR.
		;0 => DON'T DO THAT.
		;1 => DISABLE ALL SCREEN-CLEARING, EWVEN BY ^L AND F+
PJATY:	-1	;-1 => WE JUST GOT A %PJATY INT, SO SHOULD REDISPLAY WHOLE SCREEN SOON.
REFRSH:	0	;NONZERO => MACRO IT WHEN WANT TO CLEAR SCREEN DUE TO PJATY
		;(INSTEAD OF MACROING FS ^R DISPLAY$).
VREMEM:	0	;NON0 WHEN DISPLAYING STUFF THAT'S IN BUFFER.
RRINHI:	0	;NON-0 INHIBITS ALL DISPLAY UPDATING (FS ^R INHIBIT$)
RRECBP:	0	;NONZERO INDICATES WE RESTARTED TECO OUT OF RRECIN, SO CALL RRECI5.
RRECSD:	0	;IF SPACE'S DEFINITION EQUALS THIS, SPACE CAN BE ECHOED.  USE FOR AUTO-FILL.
TTMODE:	0	;NON-0 => DISPLAY BUFFER AFTER CMD STRINGS EVEN IF PRINTING TTY.
HCDS:	BLOCK MXNVLS	;HASH CODES OF LINES ON SCREEN
HCDSE:	0

LINBEG:	BLOCK MXNVLS	;1 WD / LINE ON SCREEN, SET BY VBD AS FOLLOWS:
	 ;BITS 3.9 - 1.1 -- CHAR ADDR OF 1ST CHAR ON THE LINE
	 ;BITS 4.9 - 4.1 -- HPOS THAT CHARACTER STARTED IN.
LINEND:	BLOCK MXNVLS	;FOR EACH LINE, THE HPOS OF THE END OF THE LINE:
			;THE HPOS THAT THE NEXT CHARACTER ON IT WOULD HAVE HAD.
DWAIT:	0	;WAIT FOR OUTPUT TO FINISH BETWEEN LINES, TO AVOID BUFFERING UP LOTS OF STUFF.
DFORCE:	0	;FORCE DISPLAY TO FINISH DESPITE PENDING INPUT.  DON'T UPDATE MODELINE.
SHOMOD:	0	;ON PRINTING TTY, FR TYPES OUT ..J IF THIS IS NONZERO.

;JOURNAL FILE DATA.
JRNOCT:	0		;NUMBER OF COMMAND CHARS BEFORE OUTPUT JOURNAL IS FORCED OUT.
JRNOIVL:50.		;NUMBER OF COMMAND CHARS BETWEEN FORCINGS OUT.
JRNOUT:	0		;NONZERO => OUTPUT JOURNAL FILE IS OPEN.
JRNIN:	0		;NONZERO => INPUT JOURNAL FILE BEING RE-EXECUTED.
JRNINH:	0		;NONZERO => TEMPORARILY INHIBIT USE OF JOURNAL FILE FOR INPUT.
JRNMAC:	0		;MACRO TO BE CALLED WHEN "::" IS SEEN IN A JOURNAL FILE.

DBGBUF:	BLOCK 40	;DEBUG INFO BUFFER.
DBGBFE::

DBGBFX:	DBGBUF		;POINTER FOR STORING IN DEBUG INFO BUFFER.

FDRBUF:	BLOCK FDRBFL		;BUFFER FOR READING FROM CHRAND.
FDRBFE:	<EOFCHR>_29.
FDRP:	0			;BYTE POINTER TO FDRBUF

SUBTTL ITS FILE AND INTERRUPT VARIABLES

IFN ITS,[
TIME:	0		;TIME IN SIXBIT
DATE:	0		;DATE IN SIXBIT
PDTIME:	0		;# SECONDS SINCE BEGINNING OF YEAR
LPDTIM:	0		;LOCALIZED "
YEAR:	0		;YEAR AND FLAGS
CDATE:	SIXBIT/ 00,19/
CTIME:	SIXBIT /  :  :  /
	0

SEQPGE:	4	;PAGE AHEAD DISTANCE.  0 => DON'T USE SEQUENTIAL PAGING.
SEQPGF:	0	;NONZERO => SEQ PGNG REQUESTED; ON IF WE THINK IT'S WORTH IT.
SEQPGN:	0	;NONZERO => .PAGAHD IS NONZERO; SEQPGX MUST ACTUALLY CLEAR IT.
SEQPGC:	-1	;-1 + NUMBER OF NESTED SEQUENTIAL PAGING REQUESTS NOW.

INTJPC:	0	;PLACE THAT JUMPED TO WHERE YOU WERE INTERRUPTED FROM
UUOJPC:	0	;PLACE THAT JUMPED TO WHERE YOU UUO'D FROM, IF IT WAS ILLEGAL MUUO.

TSINT:	0
	0
	.SUSET [.RJPC,,INTJPC]
	JRST TSINTP

INTACS:	BLOCK	20

TTYST1:	322020,,202020	;ACTIVATE ON ^C (AND OTHER RANDOM CTL CHARS)
			;OUTPUT CTL CHARS IN IMAGE MODE.
TTYST2:	332033,,300220	;ACT. ON ^G (^S), RUB, ALT; INT. ON ^G (^S) ,ALTMODE; OUTPUT CR IN IMAGE.
TTYSTS:	0	;3RD ARG FOR TTYSET.

DEFFIL:	BLOCK FNMLEN	;DEFAULT FILENAME (ASCIZ STRING).

INFILE:	BLOCK FNMLEN	;CURRENT OR MOST RECENT INPUT FILE'S TRUE NAME.

OUTFIL:	BLOCK FNMLEN	;NAME OF LAST OUTPUT FILE EXPLICITLY CLOSED.

TMPFIL:	BLOCK FNMLEN	;TEMPORARY FILE NAME FOR MERGING, FOR OPENING OUTPUT FILES, ETC.

TMPF1:	BLOCK FNMLEN

IFN 0,[
DEFDEV:	0	;DEFAULT FILENAMES.  DEFAULT DEVICE INITTED TO MACHINE NAME.
DEFFN1:	SIXBIT /@/
DEFFN2:	SIXBIT />/
DEFFN3==DEFFN2	;GENERATION NUMBER IS THE SAME AS SECOND FILENAME
DEFDIR:	0	;CURRENT SNAME.
ERDEV:	0	;LIKE EIDEV BUT FOR DEV BEING READ.
RUTF1:	0	;REAL FILE NAMES
RUTF2:	0	;ON READ
ERSNM:	0	;AND SNAME BEING READ.
ROUDEV:	0	;REAL FILE NAMES OF LAST OUTPUT FILE EXPLICITLY CLOSED.  DEVICE NAME.
ROUFN1:	0	;FN1 OF IT.
ROUFN2:	0	;FN2 OF IT.
ROUSNM:	0	;SNAME OF IT.
]

MNAME:
MACHIN:	0	;SIXBIT NAME OF MACHINE.

CHPOPX:	TRNE\TRNN T,1	;SEE IF THIS PUSHED IOCHNL IS THE RIGHT DIRECTION
GCHN2:	CAIN E,.	;DON'T USE CHNL AS TEMP
			;IF ITS THE ONE WE WANT TO POP INTO.

IOP:	-LIOPDL,,IOPDL-1	;POINTER TO LOCAL IO PDL
IOPDL:	BLOCK LIOPDL	;LOCAL IO PDL
];IFN ITS

SUBTTL TWENEX FILE AND INTERRUPT VARIABLES

IFN TNX,[
	NFKS==10	;NUMBER OF SUBFORKS THERE CAN BE AT ONE TIME (NOT COUNTING EXECFK).
EXECFK:	-1		;FORK HANDLE FOR EXEC (FZ$ := PUSH)
RUNFRK:	0		;FORK HANDLE OF CURRENTLY RUNNING PROCESS (WITHIN FZ).
FRKTAB:	BLOCK NFKS	;TABLE OF FORK HANDLES, INDEXED BY FZ ARGUMENT NUMBER
FRKTTY:	BLOCK <<NFKS+1>*3>	;TABLE OF TERM STATUS INDEXED BY FZ ARGUMENT NO.
FZNAM:	0		;JOBNAME TO RESTORE ON RETURN FROM SUB FORK
FRKJFN:	0		;JFN of current process (within fz)
FRKNUM:	0		;USEFUL STORAGE FOR FZ COMMAND
FRKLST:	SIXBIT /EXEC  /	;AN OFFSET OF ZERO IS ALWAYS THE EXEC
	BLOCK NFKS	;POINTERS TO JOB NAMES INDEXED BY FZ ARGUMENT NUMBER.
FRKJCL:	0		;STRING OF JCL FOR THE FORK
FZSTR:	BLOCK 2		;POINTERS TO RESCAN STUFF FOR USE WITH FZ
FRKNAM:	BLOCK 20	;FILE NAME LONGER THAN 100 CHARS LOOSES.
INTACS:	BLOCK 20	;SAVE ACS ON INTERRUPTS
INTPC:	0		;INTERRUPT SAVED PCS FOR THE THREE LEVELS.
INTPC1:	0
INTPC2:	0
BOOTP:	0		;P SAVED HERE TO BE DUMPED IN EJ FILES (SINCE SSAVE DOESN'T SAVE ACS).
DISCPH:	0		;STARTING HPOS FOR THIS LINE
FCITYI:	0		;HIGH ORDER BITS ARENT PARITY (CROCK NEEDED FOR DM1520)
IFN 20X,[			;<
PAGMOD:	0		;NON-ZERO => LEAVE TERMINAL IN PAGE MODE (FOR ^S/^Q)
]
IFN TNX,[
JCLNAM:	BLOCK 2		;PROGRAM NAME FROM JCL
]
ITTYMD:	BLOCK 3		;PLACE TO SAVE INITIAL TTY MODES TO RESTORE BEFORE CALLING SUBFORK.
FTTYMD:	0		;INFERIOR FORK STPAR
ECHOP:	-1		;ARE WE IN ECHO AREA?
ECHOF2:	0		;MUST TECO EXPLICITLY ECHO INPUT?
ECHOL0:	0		;VPOS OF FIRST LINE OF ECHO AREA
ECHOPS:	0		;CURRENT POSITION IN ECHO AREA: VPOS,,HPOS
ECODPF:	0		;FS ECHO DISPLAY:  -1 AFTER ^P, -2 AFTER ^PH, -3 AFTER ^PV.
ECODPS:	0		;SAVED POSITION FOR ^PS IN ECHO AREA
SAVMOD:	0		;SFMOD TO BE RESTORED ON ^G INTERRUPT (FOR :ET), ELSE 0
	BLOCK 2		;CCOC WORDS ARE SAVED HERE WHEN CALLING AN INFERIOR FORK
TTLPOS:	0		;REAL SCREEN POSITION (INTERNAL RFPOS/SFPOS EQUIVALENT)
IFN SUMTTF,[
HLDCHR:	0		;HOLD CHARACTER SAVED HERE
];IFN SUMTTF
OPNJFN:	0		;JFN BEFORE OPENF
CHFILI:	0		;INPUT FILE JFN
CHFILO:	0		;OUTPUT FILE JFN
GJBITS:	0		;GJ%XTN BITS FOR INVISIBLE FILES
DEFDEV:	ASCII /DSK/	;DEFAULT DEVICE
	0
DEFDIR:	BLOCK 20	;DIRECTORY NAME
DEFFN1:	ASCII /FILE/	;DEFAULT TO SOMETHING RANDOM
	BLOCK 17	;NAME
DEFFN2:	BLOCK 20	;EXTENSION
DEFFN3:	0		;GENERATION NUMBER
ERDEV:	BLOCK 63	;SAME FORMAT - LAST READ FILE'S NAME
ROUDEV:	BLOCK 63	;DITTO - REAL OUTPUT FILENAMES
ETMODE:	37		;BITMASK OF FIELDS TO DEFAULT FOR :ET COMMAND
CCLJFN:	0		;JFN IN 1 IF STARTED AT NORMAL ENTRY+2
INIOP:	-LIOPDL,,INIPDL-1	;INPUT I/O PDL POINTER
INIPDL:	BLOCK LIOPDL	;INPUT I/O PDL
OUTIOP:	-LIOPDL,,OUIPDL-1	;OUTPUT I/O PDL POINTER
OUIPDL:	BLOCK LIOPDL	;OUTPUT I/O PDL

SAVABC:	0		;JSR HERE TO SAVE AC'S A, B, AND C ON THE STACK
	SAVE A
	SAVE B
	SAVE C
	JRST @SAVABC
	
ERRRET:	0
	MOVEM 17,77	;SAVE ALL ACS IN CASE WANT TO DO A DUMP
	MOVEI 17,60
	BLT 17,76
	HRROI A,[ASCIZ /Internal error at /]
	ESOUT
	MOVEI A,.PRIOU
	HRRZ B,ERRRET
	MOVEI C,10
	NOUT
	 JFCL
ERRRST:	MOVSI 17,60	;RESTORE ACS FOR IMMEDIATE DEBUGGING (ERRRSTG FROM DUMP ALSO)
	BLT 17,17
	HALTF
	JRST @ERRRET


%TOERS==40000		;CAN SELECTIVELY ERASE
%TOHDX==20000		;HALF DUPLEX (BOUND TO LOSE SOMEWHERE)
%TOMVB==10000		;CAN BS
%TOSAI==4000		;SAIL CHAR SET
%TOSA1==2000		;USE SAIL CHAR SET
%TOOVR==1000		;CAN OVERWRITE
%TOMVU==400		;CAN MOVE THE CURSOR UP
%TOMOR==200		;MORE PROCESSING
%TOROL==100		;ROLL
%TOLWR==20		;HAS LOWERCASE KEYBOARD
%TOFCI==10		;HAS 12 BIT INPUT CAPABILITY
%TOLID==2		;HAS LINE I/D
%TOCID==1		;HAS CHAR I/D
%TPRSC==4		;(IN RIGHT HALF) TTY HAS ABILITY TO SCROLL A REGION OF THE SCREEN.
%TPMTA==400		;(IN RIGHT HALF) HAS A META KEY

;MAYBE LOAD VTS DEFINITIONS
IF1,IFNDEF RTCHR,.INSRT VTSDEF
];IFN TNX

SUBTTL RCH, CHARACTER SYNTAX TABLES, ^]

UUOQ:	0
UUOH:	0
	MOVEM Q,UUOQ
	LDB Q,[331100,,40]
	CAIN Q,TYPR4_-33
	 JRST ETYP2A
IFN ITS,.SUSET [.RJPC,,UUOJPC]
	MOVE Q,UUOQ
	.VALUE
	TYPRE [DSI]

SKRCH:	SKIPG COMCNT
	 TYPRE [UEC]
RCH:	SOSGE COMCNT
	 JRST RCH2	;NOTE RCH2 LOOKS AT OUR RETURN ADDRESS.
	ILDB CH,CPTR
	XCT RCHDTB(CH)	;DO SPECIAL STUFF OR JFCL..
TRACS:	 POPJ P,TYOS	;OR JRST TYOS IN TRACE MODE.
	SKIPN MACPTR	;RCHDTB ENTRY SKIPS IF SHOULD CHANGE CHAR'S CASE.
	 XORI CH,40	;BUT NEVER CHANGE CASE OF CHARS IN MACROS.
	JRST TRACS

;[[[[
RCHDTB:	REPEAT 33,JFCL
RCHALT:	JFCL ENDARG	;OR JRST IF SHOULD END A ^]^X
	REPEAT ^]-34,JFCL
RCHBRC:	JRST CTLBRC	;^]
	REPEAT "?-^],JFCL
	SKIPL RCHSFF		;@
	REPEAT 26.,SKIPL CASE	;UPPER CASE LETTERS
	REPEAT 5,SKIPL RCHSFF	;[\]^_
	JFCL			;`
	REPEAT 26.,SKIPG CASE	;LOWER CASE LETTERS.
	REPEAT 5,JFCL		;{|}~<RUBOUT>
IFN .-200-RCHDTB, .ERR RCHDTB WRONG SIZE.

SQUOTP:	0	;;SIGN => READING SUPER-QUOTED MACRO.
		;4.8 => READING DELIMITER-PROTECTED MACRO.
DLMF2:	0	;INTERNAL FLAG FOR CTLBRC INDICATES THAT 4.8 OF SQUOTP SHOULD BE SET
SQUOF2:	0	;    "      "   "     "        "      "  SIGN OF SQUOTP    "    "  " 
BRC1CF:	0	;INTERNAL FLAG FOR CTLBRC INDICATES THAT ONLY ONE CHARACTER SHOULD BE GOBBLED
BRCUAV:	0	;INTERNAL FLAG FOR CTLBRC INDICATES THE Q-REGISTER
		 ;SHOULD BE USED AS A NUMERIC VALUE (IE. ASCII VALUE)

BRC1:	0	;[ ZERO => HANDLE ^] NORMALLY
		;[[[[[; -1 => DO-NOT EXPAND MACROS, BUT HANDLE ^]^],^]$,^]^V<Q-REG>,AND ^]^Q NORMALLY
BRCFLG:	0	;[ ;SET TO -1 BY ^]'S THAT INSERT UNPREDICTABLE STUFF.
		;[ ;SET IT TO 0 AND TEST IT LATER TO SEE IF ANY ^]'S HAVE HAPPENED.
		;[ ;ALSO, ^]^V LEAVES THE CHARACTER HERE ON RETURN, AS IT WAS
		;BEFORE BEING TRUNCATED TO 7 BITS.

CASE:	0	;DESIRED INPUT CASE.
		;0 => LEAVE CASE OF CHARS ALONE,
		;<0 => WANT CHARS IN LOWER CASE,
		;>0 => WANT CHARS IN UPPER CASE.
		;NEGATED BY CASE-SHIFT AND CASE-LOCK CHARS.
CASNRM:	0	;NORMAL CASE - REINIT. CASE AT START OF CMD STRING.
		;THIS IS WHAT FSCASE SETS.
CASDIS:	0	;NONZERO => PUT CASESHIFTS IN OUTPUT.
CASSFT:	-1	;CASE-SHIFT CHAR, OR -1 IF NONE.
CASLOK:	-1	;CASE-LOCK CHAR, OR -1 IF NONE.
RCHSFD:	0	;SAVED NORMAL CONTENTS OF RCHDTB ENTRY FOR
		;CASE-:SHIFT CHAR (RCHDTB ENTRY NOW IS <CALL RCHSFT>)
RCHLOD:	0	;SAVED NORMAL RCHDTB ENTRY FOR CASE-LOCK CHAR.
RCHSFF:	0	;-1 => LAST CHAR WAS A CASE-SHIFT.
		;USED TO CAUSE A CASE SHIFT TO QUOTE ITSELF.

SUBTTL ADDRESS SPACE ORGANIZATION

;;; THE 1ST 2 PAGES ARE THE "LOW IMPURE", CONTAINING SPECIAL-PURPOSE VARIABLES.
;;; THEN COMES THE PURE CODE, FROM "INIT" TO "HUSED".
;;; THEN COMES THE HIGH IMPURE, STARTING WITH A FEW SPECIAL-PURPOSE VARIABLES,
;;; FOLLOWED BY THE ^R COMMAND DISPATCH TABLE.

;;; THEN COME THE DYNAMICALY ALLOCATED AREAS:
; THE COMMAND BUFFER IS USED FOR OLD-FASHIONED (NON-^R) TECO TOP-LEVEL COMMAND READIN.
CBUFLO:	10740,,CBUF	;SET TO BP -> BOTTOM OF COMMAND BUFFER.
CBUFH:	CBUF+CBUFSZ-1	;-> LAST WD OF COMMAND BUFFER

; IMPURE STRING SPACE CONTAINS STRINGS AND BUFFERS' POINTER-STRINGS.
; BOTH START WITH A FLAG CHARACTER (QRSTR OR QRBFR, RESPECTIVELY), FOLLOWED
; BY 3 CHARACTERS HOLDING A NUMBER.  IN A STRING, THAT NUMBER IS THE LENGTH,
; INCLUDING THE FOUR HEADER CHARACTERS, AND THE DATA FOLLOWS THE NUMBER.
; IN A BUFFER POINTER-STRING, THE NUMBER IS THE ADDRESS OF THE BUFFER'S FRAME.
; EITHER KIND OF OBJECT IS REPRESENTED IN QREGS, AS VALUES, ETC. BY A NUMBER
; WHICH IS THE CHARACTER ADDRESS RELATIVE TO THE START OF THE SPACE, PLUS SETZ.
QRBUF:	INIQRB		;CHAR ADDR START OF IMPURE STRING SPACE
QRWRT:	INIQRW		;CHAR ADDR 1ST CHAR ABOVE IMPURE STRING SPACE.
QRSTR==177	;PREFIX CHAR FOR STRING (FOLLOWED BY 3 CHARS HOLDING
		;21-BIT SIZE OF STRING INCLUDING 4 HEADER BYTES, FOLLOWED BY TEXT).
QRBFR==176	;PREFIX CHAR FOR BUFFER POINTER (FOLLOWED BY 3 CHARS
		;HOLDING ADDR OF POINTER-BLOCK (IN MACRO-FRAME SPACE)).

; THEN COMES A GAP, CONTAINING  NON-EXISTENT MEMORY, FOLLOWED BY BUFFER SPACE.
; EVERY BUFFER'S DATA AREA IS A SUBSET OF BUFFER SPACE, AND BUFFER SPACE
; IS USED FOR NO OTHER PURPOSE.
; BUFFER SPACE STARTS AND ENDS ON WORD BOUNDARIES, BUT BUFFERS NEED NOT START ON THEM.
; EACH BUFFER ENDS ON A WORD BOUNDARY, AND IS FOLLOWED BY ONE UNUSED WORD,
; WHICH IS INCLUDED IN BUFFER SPACE.  ASIDE FORM THOSE UNUSED WORDS, EVERY WORD
; IN BUFFER SPACE CONTAINS PART OF AT LEAST ONE BUFFER.
; BUFFER DATA IS POINTED TO BY BUFFER FRAMES (SEE MFBFR),
.SEE BEG ; OR, FOR THE CURRENT BUFFER, BY BEG, ETC.
BFRBOT:	INIBUF	;CHAR ADDR BOTTOM OF BUFFER SPACE (= BEG OF LOWERMOST BUFFER)
BFRTOP:	INITOP	;CHAR ADDR TOP OF BUFFER SPACE (> Z OF UPPERMOST BUFFER)

; THE MEMORY ABOVE BUFFER SPACE CAN CONTAIN ^P-SORT TABLES. IT CAN
; ALSO CONTAIN RANDOM DATA USED ENTIRELY WITHIN A SINGLE COMMAND.
MEMT:	<1777+INITOP/5>_-10.	;NUMBER OF 1ST PAGE OF NXM ABOVE BUFFER SPACE.

; ABOVE THE RANDM DATA THERE IS A GAP, RUNNING TO THE TOP OF MEMORY OR TO THE
; BEGINNING OF PURE STRING SPACE, WHICH STRETCHES DOWN FROM THE TOP OF MEMORY.
; OBJECTS IN PURE STRING SPACE LOOK LIKE OBJECTS IN IMPURE STRING SPACE, AND
; ARE POINTED TO BY NUMBERS WHICH ARE SETZ PLUS THE ABSOLUTE CHARACTER ADDRESS.
LHIPAG:	LHIMAX	;LOWEST PAGE IN USE BY PURE STRING SPACE.

INSINP:	0		;WHILE INSERTING, PDL LEVEL AT INSLUP, ELSE 0.
INSLEN:	0		;LENGTH OF THE LAST STRING INSERTED OR SEARCHED FOR.
TOTALC:	0		;# CHARS AT END OF GAP NOT YET USED BY INSERT.
INSRCH:	0		;INSN FOR INSERT TO XCT TO GET A CHAR.
INSDLM:	0		;THE DELIMITER FOR THIS INSERT
INSBP:	-1		;NORMALLY -1 => NO ACTION.
			;INSERT AND FCECMD SET IT TO 0, SIGNALLING RCH
			;THAT BP SHOULD BE SAVED IN INSBP IF THERE IS A CHANCE
			;THAT A GC WILL OCCUR (EG IF PUSMAC IS CALLED).
			;BFRRLC WILL THEN RELOCATE INSBP AS A BYTE POINTER
			;EVENTUALLY RCH WILL COPY INSBP BACK TO BP AND ZERO INSBP.

;VARIABLES DESCRIBING THE CURRENTLY SELECTED BUFFER.
BFRSTR:	SETZ INI..O-INIQRB	;INTERNAL VERSION OF $QBUFR;
		;-> POINTER-STRING OF CURRENT BUFFER.
BFRPTR:	MFBUF1	;-> BUFFER FRAME FOR CURRENT BUFFER (IN MACRO-FRAME SPACE).
BEG:	INIBEG		;CHARACTER ADDRESS OF BEGINNING OF BUFFER
BEGV:	INIBEG		;CHAR ADDR BEGINNING OF AREA BEING EDITED.
PT:	INIBEG		;CHARACTER ADDRESS OF "POINTER"
GPT:	INIBEG		;CHARACTER ADDRESS OF THE BEGINNING OF THE GAP
ZV:	INIBEG		;CHAR ADDR 1ST CHAR AFTER AREA BEING EDITED.
Z:	INIBEG		;CHARACTER ADDRESS OF FIRST CHARACTER AFTER BUFFER
EXTRAC:	0		;SIZE OF GAP (# CHARS)
	JRST SUPCMD	;START TECO HERE TO REQUEST SPACE IN BUFFER, ETC.
SUPARG:	0		;HOW MUCH SPACE IS WANTED.     RETURNS WITH .BREAK 16,100000
MODIFF:	0		;NONZERO IFF THIS BUFFER HAS BEEN WRITTEN IN RECENTLY.
			;SET BY WRITING;  CAN BE SET OR CLEARED BY USER.
READON:	0		;NON-0 DISALLOWS MODIFYING THIS BUFFER; CAN BE SET OR CLEARED BY USER
MODIFM:	0		;ALTERNATE VERSION OF MODIFF, NOT DISPLAYED IN THE MODE LINE.
			;YOU CAN CLEAR EITHER ONE BY ITSELF.

;VARS ASSOCIATED WITH COMPUTATION OF NUMERIC ARGUMENTS.
LEV:	0	;DEPTH IN PARENTHESES.
NUM:	0
SARG:	0	;ARG BEFORE COMMA FOUND HERE IF FRARG2 FLAG SET.
DLIM:	ADD C,SYL	;THIS INSN SET BY ARITH OPS.
SYL:	0
OSYL:	0
IBASE:	10.	;INPUT RADIX FOR NUMBERS NOT FOLLOWED BY "."
I.BASE:	8	;INPUT RADIX FOR NUMBERS FOLLOWED BY ".".

;VARS USED BY TYPE-IN, AND LIS.
TYIBUF: BLOCK TYIBSZ		;BUFFER WHICH HOLDS LAST TYIBSZ*3 INPUT CHARACTERS.
TYIBFP:	441400,,TYIBUF		;POINTER FOR STORING IN TYIBUF.
TYIBFQ:	441400,,TYIBUF		;PTR FOR READING.  COPIED FROM TYIBFP AFTER EACH CHAR STORED.
TYISNK:	0	;MACRO TO BE CALLED WITH EACH TYPED-IN CHARACTER (BUT NOT REREAD ONES)
		;IN ADDITION TO PROCESSING THE CHARACTER NORMALLY.  FOR DEFINING MACROS.
TYISRC:	0	;NONZERO => MACRO TO SUPPLY "TYPE-IN" CHARACTERS.  FOR EXECUTING MACROS.

ECHOFL:	0	;NONZERO => SYSTEM ECHOING IS TURNED ON.
LTYICH:	0	;LAST CHAR READ FROM TTY, FOR DETECTING $$.
UNRCHC:	-1	;-1, OR CHARACTER TO BE RE-READ.
INCHCT:	0	;NUMBER OF CHARACTERS READ FROM TTY SO FAR.
INCHRR:	0	;VALUE OF INCHCT AT LAST TIME THROUGH RRLP1.
		;INCHCT-INCHRR IS LENGTH OF THIS ^R COMMAND IN INPUT CHARS.
INCHEC:	-1	;FUTURE VALUE OF INCHCT AT WHICH NEXT NON-REMOTELY-ECHOED CHAR
		;WILL APPEAR.  AS LONG AS INCHCT <= INCHEC, WE ARE PROCESSING
		;PRE-ECHOED INPUT, AND WE SHOULD PRETEND TO DISPLAY BUT OUTPUT NOTHING.

LEABLE:	0	;1 => TERMINAL HAS ABILITY TO DO LOCAL EDITING.
LEINIT:	0	;-1 => MUST TOTALLY REINIT LOCAL EDITING MODES.
LEDEFS:	0	;TABLE MATCHING COMMAND DEFINITIONS TO %TDEDF FUNCTION CODES.
		;IF THIS IS A QVECTOR, IT SHOULD CONTAIN ALTERNATING
		;COMMAND DEFINITIONS AND FUNCTION CODES.
		;TECO SEARCHES THE TABLE FOR THE CURRENT DEFINITION OF A COMMAND
		;AND USES THE FUNCTION CODE THAT MATCHES (OR 0, IF NO MATCH).
		;IF THIS IS A STRING, TECO EXECUTES IT, AND THEN EXPECTS
		;LEDEFS TO HAVE BEEN SET TO A QVECTOR OR ELSE 0.
INCHSY:	0	;VALUE OF INCHCT WHEN LAST INPUT RESYNCH WAS RECEIVED FROM
		;REMOTE SMART TERMINAL.
INCHRQ:	0	;DON'T SEND ANOTHER %TDECO UNTIL INCHCT IS BIGGER THAT INCHRQ.
INSYNC:	0	;UNIQUE ID FROM LAST INPUT RESYNCH RECEIVED.
RDFMSK: REPEAT 20,-20
		;1 BIT FOR EACH 9-BIT CHAR (32 PER WORD); SET IF CHAR HAS BEEN REDEFINED
		;AND LOCAL EDITING TERMINAL HAS NOT BEEN INFORMED.
WRDMSK:	REPEAT 4,0	;RECORDS WORD SYNTAX AS LAST DESCRIBED TO TERMINAL.
			;1 BIT MEANS CHAR IS PART OF A WORD.
			;32 BITS PER WORD, STARTING WITH SIGN BIT.
INSMOD:	1	;1 => TERMINAL IN INSERT MODE.  2 => REPLACE MODE.
		;0 =. SELF-INSERTING CHARS TURNED OFF IN TERMINAL.
TBOTMAR:0	;# LINES AT SCREEN BOTTOM NOT BEING USED FOR EDITING,
		;AS LAST TOLD TO THE TERMINAL.

HELPMA:	0	;FS HELP MAC$:  NONZERO => MACRO TO RUN WHEN "HELP" KEY IS TYPED.
HELPCH:	TOP+"H	;FS HELP CHAR$: CHARACTER TO INVOKE HELP MACRO
PROMCH:	"&	;THE PROMPT-CHARACTER; FS PROMPT $. 0 => NO PROMPTING.
CMFLFL:	0	;-1 READ COMMAND OR INIT FILE
;[[
CTLBRF:	0	;-1 IF READING CHARACTER AFTER A ^] OR ^]^Q (IN TECO CMD STRING).
CBMAX:	0	;LENGTH OF WHAT IS NOW IN CBUF.
SAVCMX:	1	;CBMAX OF LAST CBUF STRING THAT WAS LONGER THAN 3 WORDS.
SAVCW1:	0	;AND 1ST 3 WDS OF THAT CMD STRING.
SAVCW2:	0	;THESE VARS COPIED BACK INTO CBMAX, CMD BUFFER,
SAVCW3:	0	;AND CPTR BY LISCY (^Y AS FIRST CHAR TYPED)
SAVCPT:	0	;(SAVED CPTR) SO IT CAN RESTORE LAST LONG COMMAND.

FSPSPB:	BLOCK FSPSPL	;RING BUFFER OF PT.
FSPSPP:	4400,,FSPSPB-1	;RING BUFFER POINTER, -> LAST USED ENTRY.

LISTF5:	CALL .		;XCT THIS TO OUTPUT A CHARACTER.
DPT5:	MOVEI CH,40	;RH HAS CHARTO PAD A PRINTED NUMBER WITH.

SUBTTL MACRO CALL FRAMES

;MACRO AND ITERATION HANDLING LIST STRUCTURE:
;EACH CELL HAS MFBLEN WORDS.
;LISTS ARE LINKED THRU THE LAST WORD.
;THE FIRST 2 WORDS ARE RELOCATED BY GC.
;POINTERS TO NON-FREE BLOCKS ACTUALLY POINT TO THE
;LAST WORD OF THE BLOCK.

MFBLEN==7	;# WORDS PER CELL.

;[ ;MACRO OR ^]<Q-REG> INVOKATION LIST...
;(POINTED TO BY MACPTR)
MFCCNT==0	;COMCNT
MFCPTR==1	;CPTR
MFCSTR==2	;CSTR
MFARG1==3	;MARG1
MFARG2==4	;MARG2
MFPF==5		;MACSPF
MFLINK==6	;MACPTR <POINTER TO PREVIOUS MACRO CELL.>
		;LH HAS SAVED LH(MACBTS).

;[[[ ;^]^X READ CELL.  ^]^X IS A SPECIAL KLUDGE TO ALLOW STRING ARGUMENTS
 ;TO BE READ FROM THE PREVIOUS COMMAND STRING LEVEL.  IT TRIES TO BE
 ;CLEVER ABOUT WHAT IT DOES WHEN OTHER ^] STRINGS ARE ENCOUNTERED WHILE
 ;SCANNING FOR THE END OF THE ARGUMENT, DEFINED BY THE FIRST <ALTMODE>
 ;ENCOUNTERED THAT ISN'T PROTECTED AGAINST TRIPPING THE CATCH (IE., BY QUOTING IT)>
;THESE CELLS FORM A LIST POINTED TO BY CTXPTR.
	;COMCNT
	;CPTR
	;CSTR
	;MARG1
	;MARG2
	;UNUSED.
;[	;CTXPTR <POINTER TO THE PREVIOUS ^]^X CELL IN FS: SPACE>

;ITERATION  OR ERRSET (:<  --  >)CELL
;THESE FORM A LIST POINTED TO BY ITRPTR.
		;COMCNT
		;CPTR
		;CSTR
MFICNT==3	;ITERCT <NUMBER OF ITERATIONS LEFT ON THE PREVIOUS ITERATION LEVEL>
MFMACP==4	;MACPDP <FOR POPPING ON ERROR IN ERRSET>
  MFERS1==40	;THE 40 BIT IN THE LH (THE EXTRA BIT OF THE BYTE POINTER WHICH IS MACPDP)
		;IS USED TO INDICATE THAT THIS IS AN @:< TYPE OF ERRSET.
MFPF==5		;LH OF THIS WORD HAS RH OF P, RH HAS RH OF PF.
		   ;AS THEY WERE WHEN THE < WAS EXECUTED.
		;ITRPTR <PREV. ERRSET CELL,,PREV ITER CELL.>

;BUFFER FRAME - DISTINGUISHED BY NEGATIVE 1ST WORD OF BLOCK.
MFBBTS==770000	;THESE ARE ALL THE BITS IN MFBEG WORDS.
MFBFR==400000	;1 => THIS IS A BUFFER FRAME.
MFMARK==200000	;GC MARK BIT FOR BUFFER FRAME.
MFQVEC==100000	;BIT INDICATING MARK THRU THE WORDS OF THIS BUFFER
MFMODIF==040000	;1 => THIS BUFFER HAS BEEN WRITTEN IN RECENTLY (MODIFF).
MFREADO==020000	;1 => DONT ALLOW MODIFICATION OF THIS BUFFER
MFMODM==010000	;1 => THIS BUFFER HAS BEEN WRITTEN IN RECENTLY (MODIFM).

MFBEG==0	;HOLDS WHAT WOULD BE IN BEG IF THIS BUFFER WERE SELECTED.
		;AS WELL AS MFBFR AND MFMARK IN THE LH.
MFBEGV==1	;SIMILAR, BUT FOR BEGV, AND NO MFBFR OR MFMARK.
MFPT==2		;SIMILAR, FOR PT.
MFGPT==3	;SIMILAR, FOR GPT.
MFZV==4		;SIMILAR, FOR ZV.
MFZ==5		;SIMILAR, FOR Z.
MFEXTR==6	;SIMILAR, FOR EXTRAC.

;THE FREE STORAGE LIST OF CELLS IS POINTED TO BY MFFREE,
;AND LINKED THROUGH THE LAST (MFLINK) WORD OF THE CELL,
;AND TERMINATED WITH A 0.
;THE MFCPTR OF A FREE CELL CONTAINS 0.
;POINTERS TO FREE CELLS ACTUALLY POINT TO THE WORD
;BEFORE THE FIRST WORD OF THE CELL.
;IF THE 1ST WORD OF A CELL IS NEGATIVE (MFBFR IS SET) THE CELL IS A BUFFER FRAME.

MFFREE:	MFSTRT-1		;MACRO FRAME FREE LIST POINTER.
MFEND: MFEND1			;END OF SPACE ALLOCATED TO MACRO FRAMES.

COMCNT:	0	;NUMBER OF CHARACTERS LEFT IN CURRENT LEVEL OF COMMAND STRING
CPTR:	0	;BYTE POINTER TO COMMAND STRING (CURRENT LEVEL)
CSTR:	0	;THE TECO STRING OBJECT WE ARE NOW EXECUTING PART OF.
		;IF EXECUTING SOMETHING NOT IN A TECO STRING, THIS IS BP TO ILDB 1ST CHAR.
MARG1:	0	;FIRST NUMERIC MACRO ARGUMENT (GOTTEN BY ^X INSIDE MACRO)
MARG2:	0	;SECOND NUMERIC MACRO ARGUMENT (FETCHED BY ^Y)
MACSPF:	0	;PF COPIED INTO THIS WORD WHEN MACRO IS CALLED.

MACPTR:	0	;POINTER TO THE LAST CELL IN THE MACRO INVOKATION AND
;[		    ;^]<Q-REGISTER> INVOKATION LIST
MACDEP:	0	;NUMBER OF FRAMES IN MACPTR STACK (INCLUDING THOSE VIA MACXP).

CTXPTR:	0	;[ ;POINTER TO LAST CELL IN THE ^]^X INVOKATION LIST

MACBTS:	0	;BITS IN LH SAYING HOW MANY ARGS GIVEN TO CURRENT MACRO.
MFBA1==400000	;1 => 2 ARGS WERE GIVEN.
MFBA2==200000	;1 => AN ARG WAS GIVEN.
MFBATSN==100000	;1 => @ WAS SPECIFIED IN THE CALL TO THIS MACRO.


ITRPTR:	0	;RH PTR TO INNERMOST ITERATION OR ERRSET CELL
		;LH PTR TO INNERMOST ERRSET CELL (OR 0)
ITERCT:	0	;# PASSES LEFT IN INNERMOST ITERATION.

;[[[[[ ;THE MACRO PDL CONSISTS OF 4-BIT BYTES, ONE PER MACRO CALL
;OR ^]-CALL (INCLUDING ^]^X).
;MACRO PDL OVERFLOW IS IMPOSSIBLE BECAUSE THE RATIO OF MACRO-PDL
;TO MACRO CELL SPACE INSURES THAT THE LATTER WILL RUN OUT FIRST.
;ONE ENTRY PUSHED FOR EACH ^] CALL (INCLUDING ^]^X) OR M COMMAND.
;0 => MACRO CALL THAT DIDN'T SUPERQUOTE OR DELIMITER-PROTECT.
;1 - 7  => MACRO CALL. 4 BIT => HAD BEEN LOOKING FOR $ AT RCHALT.
;     1 AND 2 BITS: SUBTRACT 1, THEN GET OLD 4.8, 4.9 OF SQUOTP.
;10 => NULL ENTRY, IGNORE WHEN POPPING.
;11 THRU 17 => ^]^X CALL, LOW 3 BUTS SAME AS FOR 1 - 7.

MACPDP:	400,,MACPDL-1	;MACRO PDL PTR, -> HIGHEST USED BYTE.
MACPDL:	BLOCK MACPSZ
MACXP:	0	;P IN LAST CALL TO MACXCT OR MACXQ.

SUBTTL SORT AND SEARCH VARIABLES

;^P SORT VARIABLES:
PSMEM:	0	;WD ADDR 1ST WD OF ^P SORT TABLE
		;(WHICH LIVES ABOVE THE BUFFER)
PSMEMT:	0	;WD ADDR 1ST WD OF LAST ENTRY OF TABLE
		;ENTRIES ARE ADDED AT THE END, AND ARE 4 WDS LONG.
PSSAVP:	0	;P SAVED INSIDE ^P, OR 0. USED TO TELL WHETHER A SORT IS IN PROGRESS.
		;ALSO USED TO DETECT UNWINDING OUT OF A SORT.
PSZF:	0	;SET TO -1 TO INDICATE LAST RECORD HAS BEEN FOUND.
PSCASE:	0	;NONZERO => ^P-SEARCH IGNORES CASE. (FS ^PCASE)

LPSDBK==4	;SORT TABLE ENTRIES ARE 4 WDS LONG:
	;0TH WD	CHAR ADDR START OF KEY, RELATIVE TO BEG.
		;LATER REPLACED BY BP TO ILDB KEY.
	;1ST WD	-<# CHARS IN RECORD>,,-<# CHARS IN KEY>
	;2ND WD	CHAR ADDR START OF RECORD, RELATIVE TO BEG.
	;3RD WD	POINTER (RELATIVE TO PSMEM) TO NEXT ENTRY,
		;OR -1 FOR LAST ENTRY. TABLE IS SORTED
		;BY CHANGING THESE POINTERS.

;SEARCH VARIABLES:
PNCHFG:	0	;0 => S OR FB OR REVERSE SEARCH, 1 => _, -1 => N
SEARG:	0	;# TIMES TO SEARCH. 1 FOR FB;
		;= ABS VAL. OF NUMERIC ARG FOR S, _, N.
SRCBEG:	0	;CHARACTER NUMBER (REL TO BEG) OF START OF SEARCH RANGE.
SRCEND:	0	;CHARACTER NUMBER (REL TO BEG) OF END OF SEARCH RANGE.
SRCERR:	0	;-1 => FAILING SEARCHES SHOULD BE ERRORS EVEN INSIDE ITERATIONS.
BBP:	0	;BP. TO 1ST CHAR IN RANGE TO BE SEARCHED.
ZBP:	0	;BP TO CHAR AFTER LAST CHAR IN RANGE TO BE SEARCHED.
BBP1:	0	;NOT USED IN FORWARD SEARCH.
		;FOR BACKWARD SEARCH, IT IS THE SAME AS BBP
		;UNLESS THE GAP IS BETWEEN BBP AND WHERE WE ARE SEARCHING,
		;IN WHICH CASE BBP1 POINTS TO THE FIRST CHARACTER AFTER THE GAP.
ZBP1:	0	;IF GAP IS WITHIN RANGE OF SEARCH,
		;BP TO 1ST CHAR POS WITHIN THE GAP;  OTHERWISE, SAME AS ZBP.
		;WHEN FWD SEARCH CROSSES THE GAP, ZBP1 SET FROM ZBP
SLP4N:	0	;WHEN E MOVES TEMPORARILY FORWARD OVER THE GAP, WHILE TESTING ONE ALTERNATIVE,
SLP4N1:	0	;SLP4 AND SLP4-1 ARE SAVED IN THESE TWO WORDS.
		;WHEN E IS RESET FROM C, THEY ARE RESTORED FROM THESE WORDS.
SLP1P:	JRA B,.	;SLP1D\SLP1I INSTRUCTION EXECUTED WHEN TIME TO READ ANOTHER CHARACTER
TEM1:	0	;0, OR BP TO START OF LAST INSTANCE FOUND.
TEM2:	0	;0, OR BP TO END OF LAST INSTANCE FOUND.

SFINDF:	0	;VALUE OF THE LAST SEARCH (WHETHER :-SEARCH OR NOT)

SBFRS:	SETZ INISRS-INIQRB	;STRING-POINTER THAT PRESERVES SEARCH-BUFFER.
SBFRP:	MFSBUF			;-> SEARCH BUFFER HEADER.
STBLP:	INISRB/5		;ADDRESS OF SEARCH BUFFER BODY.
STBLPX:	INISRB/5,,SLP1P		;ALWAYS THE SAME FUNCTION OF STBLP.

SFXOR:	0	;ASCII /QQQQQ/, IF 1ST CHAR OF SEARCH STRING IS Q, INSIDE SFAST.
SFASAD:	SFAFN0,SFAFC0	;ADDRESS TO ENTER APPROPRIATE MAIN LOOP OF SFAST.
			;DEPENDS ON WHETHER CASE BEING IGNORED FOR 1ST CHAR OF STRING.

SUBTTL MORE VARIABLES

GCPTR:	0	;POINTER USED BY GC FOR STORING RELOCATION INFO.
		;ALSO, NONZERO MEANS GC IS IN PROGRESS.
GCNRLC:	0	;-1 => GC SHOULDN'T RELOCATE STRINGS, JUST FLUSH UNNEEDED BUFFERS.
QRGCMX:	INIQRB+GCOFTN	;GC IMPURE STRINGS WHEN QRWRT GETS THIS LARGE.
STOPF:	0	;FS QUIT$.  NEGATIVE == QUIT DESIRED (FS QUIT)
		;^G AT INT LVL SETS STOPF; SETTING STOPF CAUSES
		;QUITTING ACTION UNDER CONTROL OF NOQUIT.
NOQUIT:	0	;(FS NOQUIT) 0 => ^G QUITS TO TECO'S TOP LEVEL.
		;POSITIVE => ^G JUST SETS STOPF FOR PROGRAM TO TEST.
		;NEGATIVE => ^G CAUSES "QIT" ERROR (ERRSETABLE).
CLKFLG:	0	;-1 => IT IS TIME TO RUN THE REAL-TIME CLOCK ROUTINE.
CLKINT:	0	;SETTING OF FS CLK INT$.
CLKMAC:	0	;POINTER TO REAL-TIME CLOCK ROUTINE.
RUNFLG:	0	;-1 ==> TECO HAS BEEN RUN.  Q..Q, ETC. HAVE BEEN INITTED.
VARMAC:	0	;NONZERO => ENABLE FEATURE OF CALLING MACRO WHEN A NAMED VARIABLE IS SET.
LASTER:	0	;MOST RECENT ERROR MESSAGE (A STRING POINTER).
ERRFLG:	0	;-1 WHILE PROCESSING AN ERROR.
ERRFL1:	0	;FS ERRFLG$ - NEGATIVE (-<N>) =. PROTECT 1ST <N> LINES OF SCREEN
		;FROM REDISPLAY (ASSUMING THEY CONTAIN ERROR MESSAGE).  SET BY FG.
VERBOS:	-1	;IF NON-ZERO, DISPLAY WHOLE ERROR MESSAGE STRING IMMEDITAELY
ERR1:	0
ERR2:	0
ERRECH:	0	;-1 => TYPE ERR MSGS IN ECHO AREA.

PTLFCD:	0	;PTLAB FILE CREATION DATE

STABP:			;THIS IS THE CACHE FOR JUMPS ("O" COMMAND)
SYMS:	BLOCK 20	;THESE HOLD THE CPTRS AT SOME JUMPS;
VALS:	BLOCK 20	;THESE, THE CPTRS OF TAGS JUMPED TO;
CNTS:	BLOCK 20	;THESE, THE COMCNTS AT THOSE TAGS.
SYMEND:			;ENTRIES ARE IN PAIRS. EACH JUMP CPTR SELECTS A PAIR
			;THE ENTRIES IN A PAIR ARE USED FIFO BY NEW JUMPS.

PF:	-LPF-1,,PFL-1	;Q REGISTER PDL POINTER
PFL:	BLOCK LPF
;QREG PDL ENTRIES ARE 2 WORDS EACH.
;THE FIRST WORD CONTAINS THE DATA PUSHED.
;THE SECOND CONTAINS INFO ON WHERE PUSHED FROM:
;  EITHER THE CORE LOCATION PUSHED FROM,
;  THE QREG NAME (FOR Q$FOO$ Q-REGS),
;  OR THE INDEX IN FLAGD OF THE FS FALG THAT WAS PUSHED.
;  THESE ARE DISTINGUISHED BY WHETHER THE NUMBER IS < FLAGSL.

PDL:	BLOCK LPDL
BAKTAB:			;TEMPORARY BUFFER FOR USE WITHIN A COMMAND.
			;MAY BE CLOBBERED WHENEVER OUTPUT OR INPUT IS DONE.
IFN COMNDF,LTABS==120.
.ELSE LTABS==100.
IFNDEF F10LEN,F10LEN==FNMLEN*5/4	;# WDS NEEDED FOR FILENAME IF STORED AS 8-BIT BYTES.
IFL LTABS-F10LEN-3*FNBLEN,LTABS==F10LEN+3*FNBLEN	;# WDS FFRRDD WANTS.
	BLOCK LTABS
	;HOLDS STRING ARG DURING MANY COMMANDS (O, FO, F^B, F^G ...)
	;JCL READ INTO IT. USED AS BUFFER BY E_. USED BY ALINK
	;TO HOLD SOME TEMPS.

QRB:	QTAB		;POINTER TO BLOCK OF QREGS WITH NO "."'S IN NAME.
QRB.:	QTAB+36.	;POINTER TO BLOCK OF ONE-"." QREGS.
QRB..:	QTAB+36.*2	;POINTER TO BLOCK OF ".." QREGS.
QTAB:	BLOCK NQREG

CTLCF:	0		;SET BY ^C, SAYS EXIT AFTER COMMAND DONE.

UTIBUF:	BLOCK UTBSZ		;BUFFER FOR READING FROM CHFILI
UTIBE:	0			;WORD TO HOLD A ^C STUCK ON TO DETECT EOB
UTRLDT:	350700,,		;B.P. TO THE ^C TERMINATING FILLED PART OF UTIBUF
UTYIP:	010700,,0		;B.P. FOR UNLOADING UTIBUF

UTOBUF:	BLOCK UTBSZ		;BUFFER FOR WRITING TO CHFILO
UTOBE:
UTYOP:	010700,,0		;B.P. FOR STUFFING UTOBUF
UTYOCT:	0

IMQUIT:	0	;-1 SAYS ^G SHOULD QUIT IMMEDIATELY.
		;SET EG. DURING SEARCHES, WHICH DON'T NEED TO CLEAN UP.
		;1 => GOX1 SHOULD JUST OMIT PUSHING STUFF.
		;SET TO 1 ONLY AT TECO STARTUP AND WITHIN LIS.

GOXFLS:	0	;ZEROED BY GO. -1 => GO SHOULD POP ALL THE WAY TO THE TOP LEVEL.
		;1 => GOX1 SHOULD JUST OMIT PUSHING STUFF.

TSINAL:	0	;-1 => LAST INT. CHAR. WAS ALTMODE. (FOR FINDING $$ AT INT LVL)
TSALTC:	0	;# OF $$'S ITYIC'D BUT NOT IOT'D.

PAGENU:	0	;PAGE # IN INPUT FILE.
LASTPA:	-1	;0 IF HAVE YANKED LAST PAGE OF INPUT FILE.

IFN ITS,MSNAME:	0	;WORKING DIRECTORY.
HSNAME:	0	;HOME DIRECTORY (SIXBIT IN ITS, DIR # IN TWENEX).
OUTFLG:	0	;-1 => OUTPUT TO EW'D FILE DISABLED.
FILEPA:	EOFCHR	;CHAR TO PAD LAST WORD OF OUTPUT FILES WITH.
RDMNMS:	3.14	;USED BY RANDOM # GENERATOR. VALUE OF FS RANDOM
DOWNF:	0	;-1 => DOING AN FLD
SEXPFL:	0	;-1 => FL IS LOOKING FOR S-EXP, NOT LIST.
		;S-EXP MEANS EITHER WORD OR LIST, WHICHEVER STARTS FIRST.
FFRRCT:	0	;IN FILENAME READER = <# OF FILENAMES> -1
FNAMSY:	0	;0 => IF ONLY 1 FILENAME IN STRING, IT IS FN2.
		;NOT 0 => IT IS FN1 (LIKE ALL OTHER PROGRAMS). (FS FNAMSYNTAX)
ADLINE:	60.	;SIXTY CHARACTERS PER LINE OF ADJUSTED TEXT (FA)
NOOPAL:	-1	;IGNORE ALTMODES IF NEGATIVE.
		;STRAY ALTMODES ARE ERRORS IF THIS IS 0. THEY ARE LIKE ^_ IF >0.
NLAROW:	0	;0 => "_" LEGAL. 1 => ILLEGAL. -1 => "_" TREATED AS "-".
YDISAB:	0	;0 => Y IS LEGAL. 1 => ILLEGAL. -1 => Y TREATED AS ^ Y.
TABMOD:	0	;0 => TAB INSERTS, 1 => TAB ILLEGAL, -1 => TAB IGNORED.
FFMODE:	0	;NON0 => ^L'S READ FROM FILE GO IN BFR.
		;0 => ^L AT END OF PAGE Y'D OR FILE ^Y'D
		;IS THROWN AWAY, AND PW GENERATES A ^L.
UNWINF:	0	;0 => UNWIND QREG PDL AFTER EACH COMMAND STRING.
BKRTLV:	0	;INSIDE FS BACK RET, IS MACRO FRAME TO RETURN TO.
BOTHCA:	0	;NONZERO => SEARCH DOESN'T DISTINGUISH UPPER AND LOWER CASE.
SKNBPT:	0	;B.P. TO LDB 1ST CHAR OF THE STRING IN .QDLIM.
		;HAS A IN INDEX FIELD.
KILMOD:	-1	;0 => FS BKILL SHOULDN'T REALLY KILL.
SLPNCR:	0	;-1 => SLPN00 SHOULDN'T CLEAR LOW BITS.
TRCOUT:	0	;NONZERO WHILE OUTPUTTING TRACE OUTPUT.
		;USED TO PREVENT TRACE OUTPUT FROM CLOBBERING TOP LINE OF SCREEN.
PUREFL:	0	;-1 => TECO HAS BEEN PURIFIED.
INITF1:	0	;SET TO -1 BY STARTUP CODE SO THAT ..L WILL BE MACROED
		;NEXT TIME THROUGH THE LOOP AT GO.
INITFL:	0	;TECO WAS STARTED AT INIT+2, SAYING IT IS UNDER A LISP.
STEPFL:	0	;-1 => TECO MACRO LINE-STEPPING FEATURE ENABLED:
		;CR AS A COMMAND DOES ^VW AND THEN QUITS IF CHAR IS ^G,
		;ENTERS ^R IF CHAR IS ^R, SETS STEPFL TO 0 IF CHAR IS ^P.
		;ELSE, CAN BE A MACRO TO CALL TO DO THE STEPPING.
STEPDE:	-1	;MAXIMUM MACRO PDL DEPTH (FS BACKDEPTH) AT WHICH TO ALLOW STEPPING, OR -1.
SETPP:	0	;OLD CONTENTS OF P BEFORE MOST RECENT CALL TO SETPP.  DEBUGGING ONLY.
SUPHND:	0	;FS SUPERIOR$ - MACRO TO HANDLE REQUESTS FROM SUPERIOR.

SUBTTL BOOTSTRAP FOR EJ FILES

IF2 PURP1==INIT/2000		;# OF 1ST PURE CODE PAGE
IF2 PURPL==<HUSED+1777>/2000	;# OF 1ST PAGE ABOVE PURE CODE.

BOOT:	JRST BOOT1	;THIS IS THE START ADDRESS WRITTEN INTO EJ FILES.
IFN ITS,.VALUE
.ELSE	JRST BOOT1	;REENTER SAME AS START
	SETOM INITFL	;START AT START + 2 => SET FS LISPT.
IFN TNX,MOVEM 1,CCLJFN	;TWENEX - SAVE THE JFN WE WERE GIVEN FOR FS CCL FNA$
BOOT1:	SKIPE LIMPUR	;WERE WE JUST LOADED, OR WERE WE RESTARTED?
	 JRST INIT	 ;RESTARTED => PURE CODE ALREADY PRESENT, SO DO NORMAL RESTART.
IFN ITS,[
	SYSCAL OPEN,[[.UII,,CHFILI] ? ['DSK,,] ? ['TECPUR]
			RADIX 10.
			[SIXBNM \.FVERS]
			RADIX 8
			['.TECO.]]
	 .LOSE %LSFIL	;TECO PURE FILE NOT FOUND.
	.IOT CHFILI,A
	SKIPE A
	 .LOSE		;NOT A PDUMP FILE??
	.ACCESS CHFILI,[INIT+2000]	;GOBBLE TECO'S PURE PAGES OUT OF THE PDUMP FILE.
	MOVE A,[PURP1-PURPL,,PURP1]
	SYSCAL CORBLK,[%CLIMM,,%CBNDR ? %CLIMM,,%JSELF ? A ? %CLIMM,,CHFILI]
	 .LOSE %LSFIL
	.CLOSE CHFILI,
]
IFN TNX,[
	MOVE P,BOOTP
	MOVSI 1,(GJ%OLD\GJ%SHT)
RADIX 10.
IFN 20X,[ IFN EMCSDV,	HRROI 2,[STRCNC [EMACS:TECPUR.EXE.]\.FNAM3 ]
	  .ELSE		HRROI 2,[STRCNC [PS:<EMACS>TECPUR.EXE.]\.FNAM3 ]
]
.ELSE			HRROI 2,[STRCNC [<EMACS>TECPUR.SAV;]\.FNAM3 ]
RADIX 8
	GTJFN
	 .VALUE
IFN 20X,[IOR 1,[.FHSLF,,GT%ADR]
	MOVE 2,[PURP1*2,,PURPL*2]
]
.ELSE	HRLI 1,.FHSLF
	GET
];IFN TNX
	SETOM PJATY		;SCREEN NEEDS COMPLETE REDISPLAY SINCE WE HAVEN'T INITTED IT.
	MOVEI TT,LHIMAX		;WE HAVE NO LIBRARIES LOADED IN YET.
	MOVEM TT,LHIPAG
;PUT A BREAKPOINT HERE TO STOP EMACS WHEN TECPUR IS MAPPED IN.
HAVPUR:	JRST INIT

CONSTA			;WITHOUT THIS, OUR LITERALS WOULD BE IN THE PURE CODE.

RRVARX:: IF2 IFNDEF RRVARB, RRVARB:: BLOCK RRVARL

IF2 VPAT: VPATCH:

INFORM [END OF LOW IMPURE]\.-1
LOC .\1777		;MOVE TO LAST WORD OF PAGE
LIMPUR:: -1		;0 => THIS IS AN EJ FILE JUST LOADED;  IT MUST GET TECO'S PURE PAGES.

SUBTTL ^R MODE VARIABLES

;^R REAL TIME EDIT MODE VARIABLES.  ON PASS 2 WE PUT THEM IN LOW IMPURE IF THEY FIT,
;OTHERWISE IN HIGH IMPURE.

RRVARL==54.	;NUMBER OF WORDS OF ^R VARIABLES.

IF2 [	;BY THE TIME WE GET HERE ON PASS 2, RRVARB WILL
	;HAVE THE DESIRED LOCATION OF THE ^R VARIABLES BLOCK.
RRTMPV==.  ?  LOC RRVARB

RRHPOS:	0	;CURRENT CURSOR HPOS & VPOS: REFLECT
RRVPOS:	0	;CURRENT VALUE OF PT, EVEN IF SCREEN HASN'T CAUGHT UP.
RROHPO:	-1	;WHAT RRHPOS HELD LAST TIME CURSOR ACTUALLY WAS MOVED.
RROVPO:	-1	;IF THESE DIFFER FROM CURRENT POS, MUST MOVE CURSOR.
RRCMMT:	-1	;0 IF IN COMMENT MODE.
RRCCOL:	0	;COLUMN IN WHICH THE COMMENTS SHOULD START.
RRMNVP:	0	;THE VPOS OF UPPERMOST LINE THAT NEEDS REDISPLAY,
		;OR 377777,,-1 MEANING NO LINES NEED REDISPLAY,
		;OR -1 MEANING DON'T TRUST LINBEG AT ALL;  DO FULL REDISPLAY.
		;IF RRMNVP IS POSITIVE AND FINITE, ALL LINBEGS FROM TOPLIN
		;DOWN THRU THE RRMNVP'TH LINE (INCLUSIVE) MUST BE ACCURATE OR YOU WILL LOSE!
RRMNHP:	0	;LEFTMOST COLUMN ON THAT LINE THAT NEEDS REDISPLAY.
RRMAXP:	0	;NON0 => LARGEST VALUE OF PT AT WHICH BUFFER WAS CHANGED.
RRMSNG:	-1	;EITHER -1, OR VPOS OF A LINE; SAYS THAT LINE AND FOLLOWING LINES
		;NEED REDISPLAY EVEN THOUGH NOT CHANGED.
		;A VALUE LESS THAN THE VALUE OF RRMNVP, IS TREATED AS IF
		;IT WERE REPLACED BY A COPY OF THE VALUE OF RRMNVP.
		;FOR THIS TO BE > -1 IS IN MANY WAYS LIKE HAVING RRMAXP VERY VERY LARGE,
		;BUT SOME THINGS LIKE RRLCHG CAN MAKE A DISTINCTION.
RRRPCT:	0	;NUMERIC ARG SPEC'D WITH ^V OR CTL-DIGITS.
RRARGP:	0	;NONZERO => RRRPCT HAS BEEN SET (ELSE IT DEFAULTS TO 1).
RR4TCT:	0	;# OF OCCURRENCES OF ^U.  THE NUMERIC ARG TO A COMMAND IS  RRRPCT*(4 ^ RR4TCT)
RUBCRL:	0	;-1 => ^D AND RUBOUT DELETE A WHOLE CRLF AT ONE BLOW.
RRLAST:	0	;MOST RECENT ^R-MODE CHAR THAT WASN'T AN ARGUMENT-SETTING COMMAND
RRPRVC:	0	;WHAT WAS IN RRLAST BEFORE ITS CURRENT CONTENTS.
RRRPLC:	0	;-1 => NORMAL CHARS REPLACE (X = DIX$)
		;1 => THAT, AND META-CHARS INSERT (LIKE ETV)
RRMCCT:	0	;FS CRMDLY -- # CHARS TO HANDLE BETWEEN
		;INVOCATIONS OF SECRETARY MACRO.
RRMCC1:	0	;THIS IS USED TO COUNT THAT MANY CHARS.
RRNCCR:	0	;SET TO -1 DURING REDISPLAY IF THE PTR
		;COMES AFTER A CR. THAT MEANS RRHPOS IS WRONG
		;AND SHOULD BE COMPUTED BY CALLING RRBTCR.
RRCCHP:	0	;TEMP. IN CHCT; SAVES HPOS AT START OF EACH CHAR.
RRERFL:	0	;TEMP. THAT SAVES ERRFL1 OVER CALL TO VBD.
RROLZV:	0	;VALUE OF ZV, AT TIME OF LAST REDISPLAY EITHER FINISHED OR PRE-EMPTED.
RRIDVP:	0	.SEE RRLID	;VPOS AT WHICH WE SHOULD INSERT/DELETE LINES.
RRIDLB:	0	;OLD LINBEG OF THAT LINE.
RRIDBK:	0	;# OF NEWLY MADE BLANK LINES BEFORE THAT LINE.
RRCIDP:	0	; POS => THIS INSERT OR DELETE IS RIGHT BEFORE A TAB.
		; NEG => THIS INSERT OR DELETE IS USING I/D CHAR (SPECIAL CASE, NOT RRLCHG).
RRUNQT:	0	;-1 => TEMPORARILY REENABLE BUILTIN COMMANDS.
RRALQT:	-1	;NONNEG => DISABLE BUILTIN COMMANDS, BUT
		;THIS WD'S CONTENTS ARE CHAR THAT REENABLES THEM TEMPORARILY.
RRCMQT:	0	;-1 => ALL CONTROL-META-LETTERS,ETC. ARE SELF-INSERTING (FOR EDITING MACROS).
RREZ:	INIBEG	;WHEN ^R MODE IS EXITED, Z, BEG AND PT
RREBEG:	INIBEG	;ARE SAVED IN THESE 3 VARS. IF ^R IS REENTERED
RREPT:	INIBEG	;WITH ARGS, THEY ARE COMPARED WITH THESE VALUES.
		;RREBEG IS 0 WHILE ^R IS ACTUALLY IN CONTROL.
		;NOT 0 DURING NORMAL COMMAND EXECUTION, INCLUDING MACROS CALLED FROM ^R.
		;0 PREVENTS ^G FROM QUITTING AT INT LVL.
RREVPS:	0	;REMEMBER RRVPOS AND RRHPOS AT EXIT, IN CASE WE REENTER
RREHPS:	0	;WITH ONE ARGUMENT.
RREBUF:	0	;REMEMBER BUFFER THAT ^R WAS PREVIOUSLY DISPLAYING (AS STRING PTR).
RRMKPT:	-1	;THE MARK USED BY ^T, ^X, ^W.
RRSCAN:	0	;NONZERO => VARIOUS COMMANDS PRINT WHAT THEY STEP OVER/INSERT/DELETE.
RRTTMX:	50.	;FS ^RMAX$.  MAX # CHARS OF INSERT TO BE WILLING TO SCAN ON PRINTING TTY.
RRTTM1: 0	;FS ^RTTM1$.  MACRO TO CALL TO HANDLE LARGE CURSOR MOTION ON PRINTING TTY.
RRECHO:	0	;-1 => ECHO THE ^R COMMANDS EXECUTED. 0 => ECHO ONLY ON PRINTING TTY
RRMORF:	0	;POSITIVE => USE --MORE-- INSTEAD OF --TOP--, ETC., EVEN THOUGH IN ^R.
		;NEGATIVE => DON'T USE EITHER --MORE-- OR --TOP--, ETC. WHEN IN ^R.
RRSTAR:	1	;NONZERO => DISPLAY A STAR IN MODE LINE IF BUFFER MODIFIED.
RRXINV:	0	;THIS IS THE REAL DEFINITION OF "SELF-INSERTING CHARS", 0 => SELF-INSERT
RRPARN:	0	;THIS GETS RUN BY ANY "SELF-INSERTING CHAR" WHOSE LISP SYNTAX IN ..D IS ")".
RRENTM:	0	;FS ^R ENTER$, NONZERO => MACRO IT WHEN ENTER ^R.
RRLEVM:	0	;FS ^R LEAVE$, NONZERO => MACRO IT WHEN LEAVE ^R.
RRDISM:	0	;FS ^R DISPLAY$, NONZERO => MACRO WHEN ABOUT TO DO NONTRIVIAL REDISPLAY.
RUBMAC:	0	;FS RUB MACRO$, NONZERO => MACRO TO DO DELETE WITH NUMERIC ARG.

;DEBUGGING VARIABLES:
RRDHPS:	0	;REMEMBERS RRHPOS BEFORE LAST REDISPLAY.
RRDVPS:	0	;SAME FOR RRVPOS
RRDMHP:	0	;SAME FOR RRMNHP
RRDMVP:	0	;SAME FOR RRMNVP
RRDPT:	0	;REMEMBER 1ST CHAR DISPLAYED IN LAST REDISPLAY.
IFN .-RRVARB-RRVARL, .ERR RRVARL ISN'T SET RIGHT.

LOC RRTMPV

] ;END IF2

SUBTTL INITIALIZATION

INIT:	SKIPE RUNFLG	;RESTARTING => DON'T CLOBBER BUFFER, Q-REGS.
	 JRST GOZ
	SETZ FF,
	MOVE P,[-LPDL,,PDL-1]
GOZ:	SETZM SQUOTP		;NONZERO SQUOTP CAN INTERFERE WITH INSASC.
	SETOM PJATY		;SCREEN CONTENTS HAVE BEEN RANDOMLY CLOBBERED.
	SETZM STOPF
	MOVE CH,LIMPUR		;CH GETS 0 IF THIS IS EITHER TECO JUST LOADED
				; OR AN EJ FILE JUST LOADED
	AND CH,RUNFLG
IFN ITS,[
	SETZM JRNIN
	.CLOSE CHJRNI,		;STOP RE-EXECUTING A JOURNAL WHEN RESTARTED.
	MOVE E,[-9,,[.SMASK,,[TSMSK] ? .SMSK2,,[TSMSK1]	;SET MASKS,
		    .SPICL,,[-1] ? .SWHO1,,[0]
		    .RSNAME,,MSNAME ? .RHSNAME,,HSNAME
		    .RIOS+CHJRNO,,B
		    .RIOS+CHFILI,,A ? .RIOS+CHFILO,,C]]
	.SUSET E
	SKIPN B		;IF OUTPUT JOURNAL FILE NO LONGER OPEN, DON'T THINK THAT IT IS.
	 SETZM JRNOUT
	JUMPN CH,GOZ4B	;IF TS TECO OR SOME EJ FILE HAS JUST BEEN LOADED,
	SAVE C
	SAVE A
	SYSCAL SSTATU,[REPEAT 6,[ ? %CLOUT,,MACHIN ]]
	 .LOSE %LSSYS
	MOVE D,[440700,,DEFFIL]	;REINITIALIZE OUR DEFAULT FILENAME.
	MOVE A,MACHIN
	PUSHJ P,STRGE1
	MOVEI B,":
	IDPB B,D
	MOVEI B,40
	IDPB B,D
	MOVE A,MSNAME
	PUSHJ P,STRGE1
	MOVEI B,";
	IDPB B,D
	MOVEI B,40
	IDPB B,D
	MOVE A,[SIXBIT/FOO/]
	PUSHJ P,STRGE1
	MOVEI B,40
	IDPB B,D
	MOVEI B,">
	IDPB B,D
	SETZ B,
	IDPB B,D
	REST A
	REST C
GOZ4B:	SKIPN A		;ALSO SEE IF DISK CHNLS REALLY STILL OPEN, IN CASE THIS IS A RESTART.
	 CALL UICLS	;IF THEY AREN'T, TECO SHOULDN'T THINK THEY ARE.
	SKIPN C
	 TLZ FF,FLOUT

];IFN ITS
IFN TNX,[
	CLOSEF JRNIN
	CIS			;FORGET ANY INTERRUPTS IN PROGRESS
	MOVEI A,.FHSLF
	MOVE B,[LEVTAB,,CHNTAB]
	SIR
	EIR
IFN 20X,MOVE 2,[740400,,020000]	; CHANNELS 0-3, 9 AND 22
.ELSE	MOVE 2,[700410,,020000]	; CHANNELS 0-2, 9, 14 AND 22
	AIC
	RPCAP
	TRZ 2,-1		;ONLY ENABLE LH CAPS
	IOR 3,2
	EPCAP
	JUMPGE 3,GOZ4A		; NO ^C CAPABILITY?
	MOVE A,[.TICCC,,2]
	ATI			; ^C ON CHANNEL 2
GOZ4A:	SETZM ECODPF		;WE ARE NOT FOLLOWING A ^P ON TERMINAL OUTPUT.
	MOVEI A,.CTTRM
	RFCOC
	MOVEM B,ITTYMD+1
	MOVEM C,ITTYMD+2
	RFMOD
	MOVEM B,ITTYMD		;SAVE TTY MODES
	MOVEM B,FTTYMD
IFN 20X,[
	LDB C,[.BP TT%PGM,B]
	MOVEM C,PAGMOD	; SAVE INITIAL TERMINAL PAGE MODE SETTING
];20X
	JUMPN CH,GOZ4B
	GJINF
IFN 20X,[
	MOVEM 4,TTYNBR			;SAVE .CTTRM NUMBER
	TLNE 1,-1
	 TLO 1,040000	; MAKE SURE THIS LOOKS LIKE A DIRECTORY
	MOVEM 1,HSNAME	; HSNAME IS DIRECTORY CORRESPONDING TO USER
	MOVSI 1,(GJ%OFG\GJ%SHT)	; PARSE ONLY
	HRROI 2,DEFFN1
	GTJFN
	 JRST GOZ4B
	CALL FFSET3	; SET DEFAULTS FROM IT
	RLJFN
	 JFCL
]
.ELSE [
	MOVEM A,HSNAME	; HSNAME IS JUST USER
	HRROI A,DEFDIR	; CANNOT JUST DO GTJFN, CAUSE LOSING TENEX FILESYSTEM WILL FAIL
	DIRST		; ON SECOND ATTEMPT
	 JFCL
]	
GOZ4B:	SKIPN 1,CHFILI
	 JRST GOZ4
	GTSTS
	TLNN 1,(GS%OPN)	; FILE STILL OPEN?
	 CALL UICLS	; NO
GOZ4:	SKIPN 1,CHFILO
	 JRST GOZ4C
	GTSTS
	TLNN 1,(GS%OPN)
	 TLZ FF,FLOUT
GOZ4C:	SKIPN 1,JRNOUT
	 JRST GOZ5
	GTSTS
	TLNN 1,(GS%OPN)
	 SETZM JRNOUT
];IFN TNX

GOZ5:	SETOM LIMPUR	;MAKE SURE A SECOND $G WON'T MAKE BOOT REBOOT.
	CALL INITTY	;INITIALIZE TTY AND FLAGS ABOUT WHAT KIND AND HOW TO TREAT IT.
	MOVEI A,[ASCIZ *-!-*] ;USE -!- FOR CURSOR ON PRINTING TTYS.
	SKIPE C,RGETTY
	 MOVEI A,[ASCIZ */\*] ;USE /\ ON DISPLAYS.
IFN ITS,[
	CAIN C,%TNIML
	 MOVEI A,[ASCIZ //] ;BUT USE "I-BEAM" ON IMLACS.
]
IFN TNX,[
	CAIN C,DM25I
	 MOVEI A,[ASCIZ /_/]	;WHAT PEOPLE ARE USED TO ON DATAMEDIAS
]
	HRLI A,BP7
	MOVE CH,QRB..
	ADDI CH,.QCRSR
	CALL INSASC	;INSERT ASCII STRING IN Q-REG ..A.
	SETOM INITF1	;CAUSE ..L TO BE RUN.
GOZ3:	SETZM CPTR	;CPTR MIGHT POINT INTO PURE STRING SPACE WHICH IS NOW NXM.
	SKIPE C,CLKINT	;IF WE HAD CLOCK INTERRUPTS, TURN THEM BACK ON.
	 CALL FSCLK0
	  JFCL
IFN ITS,[
	SKIPE RRECBP
	 CALL RRECI5
]
	SKIPE RUNFLG
	 JRST CTLW

;STUFF TO DO WHEN STARTED UP THE 1ST TIME ONLY.
	MOVE CH,QRB..
	MOVEI A,10.
	MOVEM A,.QBASE(CH)	;INIT. OUTPUT RADIX.
	MOVE A,[SETZ 1+INIDLM*5-INIQRB]
	MOVEM A,.QDLIM(CH)
	HRRI A,INI..O-INIQRB
	MOVEM A,.QBUFR(CH)
	MOVEM A,.Q..Z(CH)
	MOVE IN,BEG	;MAKE SURE THE BOTTOM PAGE OF BUFFER EXISTS
	CALL GETCHR	;TO PREVENT CONFUSING THE CODE AT FLSCOR
	SETOM RUNFLG	;SAY TECO HAS BEEN RUN.
	MOVEI A,[ASCIZ/ 5FSQVECTOU..Q 2U:..Q(0)/]
	CALL MACXCW	;PUT AN EMPTY SYMBOL TABLE IN ..Q.
	MOVEI A,TYOA
	HRRM A,LISTF5	;CAUSE OUTPUT ROUTINES TO TYPE ON TTY.
	MOVEI A,[ASCIZ/IMPURE /]
	SKIPN PUREFL
	 CALL ASCIND
	MOVE A,[.FNAM1]
	MOVEI C,".
	CALL SIXINT
	MOVEI C,.FVERS
	CALL DPT
IFN ITS,[
	.SUSET [.RXUNAME,,C]
	.CALL GOZO1		; OPEN <HSNAME>;<XUNAME> TECO
	 CAIA
	  JRST GOZ7
	MOVSI C,(SIXBIT/*/)
	.CALL GOZO1		; OPEN <HSNAME>;* TECO
	 CAIA
	  JRST GOZ7
	.CALL GOZO2		; LAST RESORT IS .TECO.;* TECO
	 CAIA
GOZ7:	  SETOM CMFLFL		;BUT IF INIT FILE EXISTS, USE IT,
GOZ6:	JRST CTLW		;DROP INTO MAIN LOOP AS IF AFTER ^G.

GOZO1:	SETZ ? SIXBIT/OPEN/ ? [.BAI,,CHFILI]
	  [SIXBIT/DSK/] ? C ? [SIXBIT /TECO/] ? SETZ HSNAME

GOZO2:	SETZ ? SIXBIT /OPEN/ ? [.BAI,,CHFILI]
	  [SIXBIT/DSK/] ? [SIXBIT/*/] ? [SIXBIT/TECO/] ? SETZ [SIXBIT/.TECO./]
]
IFN TNX,[
	MOVSI 1,(GJ%OLD\GJ%SHT)
	HRROI 2,[ASCIZ /TECO.INIT/]
	GTJFN
	 JRST GOZ6
	MOVE 2,[36._30.+OF%RD]
	OPENF
	 JRST GOZ6
	MOVEM 1,CHFILI
	SETOM CMFLFL
GOZ6:	JRST CTLW	;DROP INTO MAIN LOOP AS IF AFTER ^G.
]

;OPEN THE TTY CHANNELS AND SET VARIOUS VARS ACCORDING TO TYPE OF TTY.
;ON T(W)ENEX A NUMERIC ARGUMENT SPECIFIES THE TERMINAL TYPE CODE,
;OVERRIDING WHAT THE SYSTEM SAYS.
FSTTYI:
IFN ITS,[
INITTY:	TSOPEN CHTTYI,[[%TIFUL+40,,'TTY]]	;INITIALIZE TTY.
	TSOPEN CHDPYO,[[%TJCTN+%TJDIS+.BAO,,'TTY]]	;BLOCK OUTPUT FOR DISIOT.
	TSOPEN CHECHO,[[%TJECH+%TJPP2+.UAO,,'TTY]]	;ECHO MODE OUTPUT.
	TSOPEN CHSIO,[[%TJSIO+%TJCTN+.UAO,,'TTY]]	;SUPER-IMAGE OUTPUT.
	TSOPEN CHTTYO,[[%TJCTN+.UAO,,'TTY]]		;NORMAL TYPE OUT.
	PUSHJ P,SETTTM	;SET UP RGETTY, STTYS.
	MOVEM CH,RGETTY
	SYSCAL TTYVAR,[%CLIMM,,CHTTYO ? ['OSPEED] ? %CLOUT,,OSPEED]
	 SETZM OSPEED
	SYSCAL TTYVAR,[%CLIMM,,CHTTYO ? ['SMARTS] ? %CLOUT,,TTYSMT]
	 SETZM TTYSMT
	SETZM INCHRQ
	SETZM LEABLE
	MOVE A,TTYSMT
	TRNE A,%TRLED
	 SETOM LEABLE
	.CALL RSSB	;SET NVLNS, NHLNS, TTYOPT.
	 .VALUE
	MOVE A,NHLNS
]
IFN TNX,[
	MOVE CH,C
	TRNN FF,FRARG
	 JRST INITT1
	CAIGE CH,MAXTTY
	 SKIPGE CH
	  TYPRE [AOR]
	HRLM CH,SGTTYP		;SAVE EXPLICIT TERMINAL TYPE
INITT1:	TRZN FF,FRARG		;READ TTY TYPE FROM SYSTEM UNLESS
				;ARGUMENT IS SPECIFIED.
INITTY:	 CALL RTTYTP		;IF CALLED INTERNALLY, DON'T LOOK AT ARGUMENT
	MOVEM CH,RGETTY
	CALL SETTTM
IFN 20X\FNX\SUMTTF,[MOVEI A,.CTTRM
	RFMOD
	LDB C,[.BP TT%LEN,B]	;TERMINAL LENGTH
	MOVEM C,NVLNS
	LDB C,[.BP TT%WID,B]	;TERMINAL WIDTH
IFN SUMTTF,[
	MOVEM C,NHLNS
];SUMTTF
IFE SUMTTF,[
	MOVEI B,.MORLW		;WORKS FOR ALL TTY WIDTHS
	MTOPR
	 ERJMP .+1
	MOVEM C,NHLNS
	MOVEI B,.MORSP		;READ TTY'S SPEED
	MTOPR
	 ERJMP .+3
	MOVEI C,(C)		;GET OUTPUT SPEED
	CAILE C,9600.		;DONT GET CONFUSED BY NVT'S OR PTY'S
	 SETZ C,
	MOVEM C,OSPEED		;SAVE IT
];SUMTTF
]
IFN 10X,SETZM OSPEED
	MOVE C,TTYTBS(CH)	;GET DISPATCH VECTOR FOR TERMINAL
IFN 20X\FNX\SUMTTF,SKIPG A,NVLNS ;USE CURRENT SETTING IF REASONABLE
	HLRZ A,0(C)		;ENTRY 0 IS PAGE SIZE
	ANDI A,777
	MOVEM A,NVLNS		;NUMBER OF VERTICAL LINES
	MOVE A,1(C)		;ENTRY 1 IS TTY OPTION BITS
IFN 20X,[
	CAIE CH,VTSI		;IF VTS TERMINAL, CALCULATE TTYOPT
	 JRST INITTV
	MOVEI A,.PRIOU
	RTCHR
	MOVSI A,%TOLWR		;SHOULD CHECK RFMOD WORD FOR THIS
	TLNE B,(TC%MOV)
	 TLO A,%TOMVU
	TLNE B,(TC%BS\TC%MOV)
	 TLO A,%TOMVB
	TLNE B,(TC%SCL)
	 TLO A,%TOERS
	TLNE B,(TC%LID)
	 TRO A,%TPRSC
	TLNE B,(TC%CID)
	 TLO A,%TOCID
	TLNE B,(TC%FCI)
	 TLO A,%TOFCI
	TLNE B,(TC%MET)
	 TRO A,%TPMTA
	TLNE B,(TC%OVR)
	 TLO A,%TOOVR
] ;20X
INITTV:	MOVEM A,TTYOPT
IFN 20X\FNX\SUMTTF,SOSG A,NHLNS	;CURRENT WIDTH, LESS ONE FOR !
	HRRZ A,0(C)		;NUMBER OF HORIZONTAL LINES
]
	CAILE A,MXNHLS		;MUST BE IN RANGE
	 MOVEI A,MXNHLS
	MOVEM A,NHLNS
IFN LINSAV,[
	SETZM LBLLIM		;BY DEFAULT, TURN OFF LINE SAVING.
	LDB A,[.BP %TRLSV,TTYSMT]
	JUMPE A,INITLS
	MOVEI B,1
	LSH B,(A)
	LSH B,(A)		;COMPUTE MAXIMUM LINE LABEL TERMINAL WILL ACCEPT (+1).
	CAIL B,MAXLBL
	 MOVEI B,MAXLBL		;COMPUTE MAXIMUM WE WILL USE.
	SKIPE A,OSPEED		;USE LINE-SAVING ONLY ON SLOW TERMINALS
	 CAILE A,1200.		;BECAUSE THINKING ABOUT IT IS SLOW.
	  JRST INITLS
	MOVEM B,LBLLIM
	SETZM LBLBEG		;CLEAR OUT DATA ON LABELS.
	MOVE A,[LBLBEG,,LBLBEG+1]
	BLT A,LBLEND-1
INITLS: ];LINSAV
	SETCM A,TTYOPT	;GET OPTION BITS FOR THIS TERMINAL
	TLNE A,%TOOVR	;TTY CAN'T OVERPRINT =>
	 SETZM DISPCR	;DON'T LET STRAY CR'S TRY TO DO SO.
	TLNE A,%TOOVR+%TOMVB	;DON'T LET BS OVERPRINT IF TTY CAN'T BS.
	 SETZM DISPBS
	MOVE A,TTYOPT
	SETZM DISSAI
	TLNE A,%TOSA1	;:TCTYP SAIL => WE SHOULD USE SAIL CHAR SET.
	 SETOM DISSAI
	TLNN A,%TOERS	;IF TTY CAN'T ERASE SELECTIVELY,
	 TLNN A,%TOOVR	;AND SPACE WON'T ERASE EITHER, WE LOSE.
	  TLNN A,%TOMVU	;IF CAN'T MOVE CURSOR UP, WE LOSE.
	   JRST [	
		MOVSI C,377777	;WE SHOULD NEVER DO --MORE--,
		MOVEM C,NVLNS
		SETZM TOPLIN	;WE CAN'T START DISPLAY IN MIDDLE OF SCREEN.
IFN ITS,[	MOVSI C,%TSMOR	;SYSTEM SHOULD DO **MORE** PROCESSING.
		ANDCAM C,TTYSTS
	]
		SETZB C,RGETTY	;ALSO PRETEND TO BE PRINTING TTY.
		CALL FSECL1	;AND NO ECHO LINES.
		SETZM BSNOLF
		TLNN A,%TOOVR
		 SETOM BSNOLF	;ON GLASS TTY, PULL VARIOUS OVERPRINT-ERASE HACKS.
		SKIPE A,TTYMAC	;RUN FS TTY MAC$ TO RESET PARAMETERS.
		 JRST MACXQ
		RET]
	SETZM NOCEOL
	TLNN A,%TOERS		;IF TTY HASN'T GOT BUILT-IN CLEAR TO EOL, SET FLAG
	 SETOM NOCEOL		;SO WE WILL CLEAR SCREEN AT TIMES FOR EFFICIENCY.
	SETZM CHCTVP
	SETZM CHCTCF
	SETOM DWAIT
	SKIPE C,OSPEED	;SET DWAIT IF TTY'S SPEED IS KNOWN TO BE 600 BAUD OR LESS.
	 CAILE C,600.
	  SETZM DWAIT
	LDB C,[.BP (%TOLID),A]
	MOVEM C,LID	;IF TTY CAN INSERT/DELETE LINES, DEFAULT IS TO USE THEM.
	TRNE A,%TPRSC	;IF TTY HAS REGION SCROLLING, USE IT INSTEAD OF INSERT AND DELETE.
	 SETOM LID
	LDB C,[.BP (%TOCID),A]
	MOVEM C,CID	;LIKEWISE CHAR I/D
IFN TNX,[
	SETZ C,		;ASSUME 200 BIT IS PARITY
	TRNE A,%TPMTA	;UNLESS THIS TERMINAL TYPE CAN HAVE META KEY
	 MOVEI C,1
	TLNE A,%TOFCI	;OR FULL INPUT CHAR SET EVEN
	 SETO C,
	MOVEM C,FCITYI
	JUMPGE C,.+3
	MOVEI CH,TOP+"H
	MOVEM CH,HELPCH	;MAKE FS HELP CHAR BE TOP-H ON FCI TERMINALS
	MOVE CH,RGETTY
	MOVE C,OSPEED
	CAIN CH,OWLI	;INSERT/DELETE LINE LOSES ON OWLS AT ABOVE 1200 BAUD.
	 CAIG C,1200.
	  CAIA
	   SETZM LID
]
	MOVE C,NVLNS
	CAIL C,MXNVLS
	 MOVEI C,MXNVLS
	MOVEM C,NVLNS
	CAMG C,TOPLIN
	 SETZM TOPLIN
	IDIVI C,6	;COMPUTE # ECHO LINES.
	CAIGE C,3
	 MOVEI C,3
	CALL FSECL1	;AND SET THAT MANY.
	SETOM ECHONL	;SAY  FIRST ECHO AREA OUTPUT SHOULD GO TO FRESH LINE.
	SKIPE A,TTYMAC	;RUN FS TTY MAC$ TO RESET PARAMETERS.
	 JRST MACXQ
	RET

SUBTTL SET/READ SCROLL BITS
FSSCRO:	TRNN FF,FRARG
	 JRST [ MOVEI A,0		;SAY "NOT USING SCROLLING"
		MOVE CH,TTYOPT		;GET TTYOPT VAR.
		TRNE CH,%TPRSC		;SCROLLING?
		 MOVEI A,1		;YES. SAY "USING SCROLLING"
		JRST CPOPJ1 ]		;RETURN THE VALUE
	MOVE CH,TTYOPT			;GET TTYOPT VARIABLE
	TRO CH,%TPRSC			;SET SCROLLING ON
	SKIPG C,			;ARG > 1?
	 TRZ CH,%TPRSC			;NO. TURN SCROLLING OFF.
	MOVEM CH,TTYOPT			;RESAVE IT.
	RET

SUBTTL 	MORE 20X ROUTINES FOR FS FLAGS(?)
IFN 20X,[

;GET OUR USER NUMBER
FSXUSR:	HRRZ A,HSNAME
	JRST CPOPJ1

; GET USER NUMBER FOR NUMARG, OR LAST ONE SET
FSUSRN:	TRNN FF,FRARG			;ARG?
	 JRST FSXUSR			;RETURN OUR OWN USR NUM
	MOVE A,C
	MOVE C,[440700,,BAKTAB]
	CALL STRASC
	MOVSI A,(RC%PAR)
	HRROI B,BAKTAB
	SETZ C,
;	TRNN FF,FRARG2
;	 RCDIR
;	TRNE FF,FRARG2
	 RCUSR
;	TRZ FF,FRARG2			;CLEAR THIS FOR NEXT COMMAND
	TLNE A,(RC%NOM\RC%AMB)		;NO MATCH OR AMBIGUOUS?
	 JRST [ HRRI B,STRX08		;NO SUCH USER
		HRLI B,.FHSLF		;OURSELF
		TRO FF,FRNOT		;NO FILENAME
		JRST OPNER6 ]		;ERROR...
	MOVEI A,(C)
	TRNE FF,FRARG
	 SETZM NUM
	JRST CPOPJ1

; CHECK FOR EXISTENCE OF USER MAIL FILE ON 20X FOR USR #
FSUML:	TRNN FF,FRARG			;NUMARG?
	 MOVE C,HSNAME
;	 JRST FSUML0
;	MOVE A,[440700,,BAKTAB]
;	HRROI B,[ASCIZ/PS:</]		;MUST BE ON PS: DIRECTORY
;	SETZ C,
;	SOUT
;	MOVE C,A			;CONVERT NUMARG TO ASCIZ STRING
;	MOVE C,[440700,,BAKTAB]
;	MOVE A,NUM
;	CALL STRASC
;	MOVE A,C
	TLNN C,-1
	 TLO C,540000
	HRROI A,BAKTAB
	MOVE B,C
	SETZ C,
	DIRST
	 ERJMP FSUML1
FSUML2:	HRROI B,[ASCIZ/MAIL.TXT.1/]	;FINISH OFF FILESPEC
	SETZ C,
	SOUT
	MOVSI A,(GJ%SHT\GJ%OLD\GJ%DEL)
	HRROI B,BAKTAB			;FILESPEC
	GTJFN				;IS IT THERE?
	 ERJMP FSUML1			;NOPE.
	MOVEI A,(A)			;YUP.
	RLJFN				;RELEASE THE JFN
	 JFCL
	SETO A,				;SUCCESS - MAILBOX?
	TRNE FF,FRARG
	 SETZM NUM
	JRST CPOPJ1

FSUML1:	SETZ A,				;FAILED - NO MAILBOX?
	TRNE FF,FRARG
	 SETZM NUM
	JRST CPOPJ1

;FSUML0:	HRROI A,BAKTAB
;	MOVE B,HSNAME			;OURSELF
;	SETZ C,
;	DIRST
;	 ERJMP FSUML1
;	JRST FSUML2

; SET/RESET DONT REAP BIT
FSREAP:	TLNN FF,FLIN
	 TYPRE [NFI]
	TRNN FF,FRARG			;ARG?
	 MOVEI C,.ARSET			;DEFAULT IS TO RESIST
	SKIPE C,			;ZERO? (.ARCLR)
	 MOVEI C,.ARSET			;RESIST!
	MOVEI B,.ARNAR			;FUNCTION CODE
	MOVE A,CHFILI			;JFN
	ARCF
	 JFCL
	RET
]; 20X

SUBTTL SET INVERSE MODE ON/OFF	;[fHsu] Get access to screen mode routines

FSCRIV:	MOVE CH,C		;GET ARGUMENT
	TRNN FF,FRARG		;DID WE GET AN ARGUMENT?
	 JRST FSRNLY		;RETURN CURRENT SETTING
	SKIPN CH		;NONZERO: USER WANTS TO SET INVERSE MODE?
	 JRST FSCRI0		;NO. SO GO TURN IT OFF.
IFN TNX,CALL DPYIVI+1
.ELSE	CALL DPYIVI+2		;INVERT, BUT DON'T CHECK INVMOD FLAG
	MOVEI CH,1
	MOVEM CH,SCINV		;SET POSITIVE MEANS DONE OK.
IFN TNX,[
	MOVE CH,RGETTY		;INTERNAL TERMINAL TYPE
	MOVE CH,TTYTBS(CH)	;DISPATCH VECTOR
	MOVE CH,22(CH)		;INVERT MODE ROUTINE
	CAMN CH,[JFCL]		;DOES TERMINAL HAVE CAPABILITY?
	 SETOM SCINV		;NO. NEGATIVE MEANS SET, BUT NOT DONE.
]
	RET
FSCRI0:	
IFN TNX,CALL DPYIVC+2		;RESET, BUT DON'T CHECK INVMOD FLAG
.ELSE	CALL DPYIVC+1
	SETZM SCINV
	RET

SUBTTL ECHOING CONTROL

IFN ITS,[
;REINITIALIZE TTYSTS, TTYST1, TTYST2;
;TURN ON ECHOING, AND SET ECHOFL TO INDICATE THAT WAS DONE.
SETTTM:	.CALL RTTYS1
	.VALUE
	MOVE TT,TTYST1
	MOVE TT1,TTYST2
	ANDCM TT,[202020,,202020]	;HAVE ECHOING ON IFF
	ANDCM TT1,[202020,,202020]	;FS ECHOLINES $ IS >=0.
	SKIPL NELNS
	 IOR TT,[202020,,202020]
	SKIPL NELNS
	 IOR TT1,[202020,,200020]
	TLO Q,%TSCLE+%TSACT+%TSMOR
	SKIPN RGETTY
	 TLZ Q,%TSMOR
	TLZ Q,%TSNEA\%TSINT\%TSSAI
	.CALL STTYS1
	 .VALUE
	SETOM ECHOFL
	MOVEM Q,TTYSTS
	RET

TTYAC2:	HRROS (P)		;INTERRUPT ON NEXT INPUT CHARACTER.
	CAIA
TTYAC1:	 HRRZS (P)		;ACTIVATE ON NEXT INPUT CHARACTER.
TTYAC4:	SAVE Q
	SAVE TT
	SAVE TT1
	SAVE CH
	.CALL RTTYS1
	 .LOSE %LSFIL
	TLZ Q,%TSINT
	TLO Q,%TSACT
	SKIPGE -4(P)
	 TLO Q,%TSINT
	.CALL STTYS1
	 .LOSE %LSFIL
	REST CH
	REST TT1
	REST TT
	JRST POPQJ

RSSB:	SETZ
	SIXBIT /CNSGET/
	%CLIMM,,CHDPYO
	%CLOUT,,NVLNS
	%CLOUT,,NHLNS
	%CLOUT,,TT	;TCTYP
	%CLOUT,,TT	;TTYCOM
	400000+%CLOUT,,TTYOPT

RTTYS1:	SETZ
	SIXBIT \TTYGET\
	%CLIMM,,CHTTYI
	%CLOUT,,TT
	%CLOUT,,TT1
	%CLOUT,,Q
	%CLOUT,,CH
	400000+%CLOUT,,CH	;TCTYP VARIABLE

STTYS1:	SETZ
	SIXBIT \TTYSET\
	%CLIMM,,CHTTYI
	TT
	TT1
	SETZ Q
]

IFN TNX,[

;RETURN TECO INTERNAL TTY TYPE IN CH.
RTTYTP:	MOVEI A,.CTTRM
	GTTYP			; GET TERMINAL TYPE
	CAMN B,[SIXBIT /4023/]	; BBN'S WAY OF DOING TTY TYPES
	 MOVEI B,TK4023
	CAME B,[SIXBIT /4024/]	; SAME THING AS 4025
	 CAMN B,[SIXBIT /4025/]
	  MOVEI B,TK4025
	CAMN B,[SIXBIT /HP/]
	 MOVEI B,HP2645
	CAMN B,[SIXBIT /C100/ ]
	 MOVEI B,C100
	CAMN B,[SIXBIT /BITGRF/]
	 MOVEI B,BITGRA
	CAMN B,[SIXBIT /ID100/]
	 MOVEI B,VT100		;ID100's are ANSI-VT100's with graphics
	CAMN B,[SIXBIT /T1061/]
	 MOVEI B,TL1061
	HRRZ CH,SGTTYP		; GET TYPE FROM LAST TIME
	CAME CH,B		; IF SYSTEM TERMINAL TYPE IS THE SAME
	 JRST RTTYT1
	HLRE CH,SGTTYP		; AND USER SPECIFIED WHAT THAT MEANS
	JUMPGE CH,CPOPJ		; USE THAT INSTEAD OF DEFAULT
RTTYT1:	HRROM B,SGTTYP		; ELSE SAVE SYSTEM TYPE
	CAIL B,NTTYPE
	 MOVEI B,NTTYPE-1	; STAY IN RANGE
	MOVE CH,TTYTYP(B)	; AND GET TERMINAL TYPE DISPATCH
	RET

; DO INITIAL SETUP
SETTTM:	SAVE C
	MOVSI A,.TICCG		; ^G ON CHANNEL 0
	SKIPG NOQUIT		; IF QUITTING IS ALWAYS DISABLED, DO NOT ARM
	 ATI			; ^G, SO THAT IT WILL ARRIVE AS A COMMAND AT
				; THE CORRECT TIME (THIS IS FOR RMODE).
	CALL DOSTIW		; SETUP TERMINAL INT MASK
	MOVEI A,.CTTRM
	RFMOD			; GET TTY MODE WORD
	SKIPE CH,RGETTY		; PRINTING?
	 TRZA 2,TT%DAM		; NO, BINARY MODE THEN
	  TRO 2,1_6\TT%ECO	; YES, MAKE SURE DATA MODE NORMAL
IFN 20X,[
	CAIN CH,VTSI		; IF RUNNING UNDER VTS
	 TRO 2,1_7		; TURN ON OUTPUT TRANSLATION
]
	SFMOD
IFN 20X,[
	SKIPGE PAGMOD		; WANT PAGE MODE LEFT ON?
	 JRST .+4		; YES, DONT MESS WITH IT
	TRZE 2,TT%PGM		; TURN OFF PAGE MODE ON DISPLAY
	 STPAR
	JUMPE CH,SETTM1
	RTMOD			; INTERPRET ^P CODES
	 ERJMP .+3		; WILL NOT LOSE ON NON-VTS SYSTEM
	TLO 2,(TM%SCR\TM%DPY)
	STMOD
	SETOB 2,3		; FIX UP CCOC WORDS FOR VTS
	CAIN CH,VTSI
	 SFCOC
]
IFN SUMTTF,[			;TURN OFF HOLD CHAR
	PUSH P,A
	SETZ A,			;ZERO MEANS OFF
	STCHA
	SKIPE	A		;DON'T SAVE IF ALREADY OFF
	 MOVEM A,HLDCHR
	POP P,A
];IFN SUMTTF
	CALL DPYINI		; INIT THOSE TERMINALS THAT NEED IT.
SETTM1:	SETOM ECHOF2		; ASSUME ECHO	
	SKIPE RGETTY		; PRINTING TTY'S ECHO FOR THEMSELVES
	 SKIPGE NELNS		; FS ECHOLINES >= 0 ?
	  SETZM ECHOF2		; NO, ECHO OFF
	SETOM ECHOFL		; SAY WE DID SOMETHING
	JUMPN CH,POPCJ		; DONE UNLESS PRINTING
	MOVE B,[.BYTE 2 ? 1 ? 1 ? 1 ? 0 ? 1 ? 1 ? 1 ? 2 ? 2 ? 3 ? 2 ? 1 ? 1 ? 2 ? 1 ? 1 ? 1 ? 1]
IFN 20X,MOVE C,[.BYTE 2 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 3 ? 1 ? 1 ? 1 ? 1]
.ELSE	MOVE C,[.BYTE 2 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 1 ? 3 ? 1 ? 1 ? 1 ? 3]
	SFCOC
	JRST POPCJ		; AND RETURN
] ;TNX


;TURN OFF ECHOING.  CLOBBERS A AND B.
NOECHO:	SETZM ECHOFL
IFN ITS,[
	MOVE A,TTYSTS		;ECHO IN M.P. AREA, NOT ECHO AREA
	TLO A,%TSNEA		;(ECHOING HAPPENS ONLY IN AN ECHOIN SYSTEM CALL).
	SYSCAL TTYSET,[%CLIMM,,CHTTYI
		[020202,,020202]	;NOTHING ECHOES, EVERYTHING ACTIVATES,
		[030202,,120202]	;^G INTERRUPTS, CR OUTPUT IN IMAGE MODE.
		A]
	 .LOSE %LSFIL
]
IFN TNX,[
	SETZM ECHOF2		;SAY DONT ECHO THINGS FOR DISPLAY TERMINAL
	SKIPE RGETTY
	 RET
	MOVEI A,.CTTRM
	RFMOD
	TRZ B,TT%ECO		;TURN OFF ECHOS ON PRINTING TERMINAL
	SFMOD
]
	RET

SUBTTL TERMINAL INPUT

;READ A CHARACTER FROM THE TTY.
TYI:	CALL TYINH
TYIH:	CAIN CH,TOP+"H		;IS THIS THE "HELP" KEY?
TYIURH:	SKIPN HELPMAC		;YES, IS THERE A HELP MACRO?
	 RET			;JUST RETURN THE CHARACTER
	CALL [	CALL SAVACS	;PRESERVE ACS AND CURRENT TECO VALUES.
		MOVE A,HELPMAC
		CALL MACXCP
		JRST RSTACS]
	SKIPN RREBEG	;IF FS HELPMAC$ RUN INSIDE ^R, RETURN FROM TYI SO THAT
	 RET		;RRLP1 CAN GO TO RRLP AND MAKE SPACE REDISPLAY THE SCREEN.
	JRST TYI	;AFTER RUNNING FS HELP$, TRY AGAIN TO READ A CHARACTER.

TYIW0:	CALL TYIWN0	;DONT CHECK STOPF, BUT DO UNREAD AND HELP CHAR
	JRST TYIH

;READ CHARACTER, CHECK FOR AND STANDARDIZE HELP CHARACTER, BUT DONT RUN HELP MACRO
TYINH:	SKIPGE STOPF
	 CALL QUIT1
TYIWN0:	MOVE CH,UNRCHC	;GOBBLE ANY UNREAD CHARACTER.
	SETOM UNRCHC
	JUMPGE CH,CPOPJ
	SKIPE TYISRC	;IF THERE IS A "TYI SOURCE", CALL IT.
	 JRST [	PUSH P,[TYIWN0]
		CALL SAVACS
		MOVE A,TYISRC	;SINCE IT CAN'T RETURN A VALUE UNCLOBBERED,
		CALL MACXCP	;IT SHOULD SET FS REREAD$ TO THE CHARACTER.
		JRST RSTACS]	;AND WE RETURN TO TYIWN0 TO GOBBLE IT.
	SKIPE JRNIN		;IF WE ARE REDOING A JOURNAL FILE,
	 JRST [	SKIPN JRNINH	;AND ARE NOT INHIBITED TEMP. FROM READING IT,
		 CALL JRNICH	;READ NEXT CHARACTER FROM IT,
		  JRST .+1	;IF REACH EOF, TRY THE TTY AGAIN.
		  JRST TYIJRN
		JRST TYIWN0]	;DOUBLE SKIP MEANS TRY UNRCHC AGAIN.
	SKIPGE CLKFLG
	 CALL RLTCLK
IFN ITS,[
TYIIOT: .IOT CHTTYI,CH
	CAIN CH,TOP+"S	;IS THIS AN INPUT RESYNCHRONIZATION FOR REMOTE ECHO?
	 JRST [	.IOT CHTTYI,INSYNC	;IF SO, RECORD IT.
		MOVE CH,INCHCT
		MOVEM CH,INCHSY
		JRST TYIIOT]
	CAIN CH,TOP+"E	;IS THIS A DECLARATION THAT FOLLOWING INPUT IS PRE-ECHOED?
	 JRST [	.IOT CHTTYI,CH	;YES, HOW MANY CHARS?
		ADD CH,INCHCT
		MOVEM CH,INCHEC	;RECORD CHAR NUMBER OF 1ST FOLLOWING UNECHOED INPUT CHAR.
		JRST TYIIOT]
];IFN ITS
IFN TNX,[
IFN 20X\FNX,[
	SKIPGE FCITYI	;CAN THIS TERMINAL DO FULL INPUT?
	 JRST VTSTYI
];IFN 20X\FNX
	EXCH A,CH
	PBIN
TYIIOT:
IFN 10X\FNX,CAIN A,37 
.ELSE [
	CAIE A,^M
	 JRST TYI5
	SAVE B
	MOVEI A,.PRIIN
	RFMOD
	SAVE B
	TRO B,100
	SFMOD			;GO INTO ASCII MODE AND
	BIN			;FLUSH LF AFTER CR IN CASE OF GTJFN LATER
	REST B
	SFMOD
	REST B
];20X
	MOVEI A,^M
TYI5:	EXCH A,CH
	SKIPN FCITYI	;ARE HIGH ORDER BITS PARITY BITS?
	 ANDI CH,177	;YES, MASK THEM OFF (SOME TERMINALS GENERATE PARITY)
	TRZE CH,200	;CONVERT EDIT TO META AT LOWEST LEVEL
	 TRO CH,META
TYI5A:	SKIPE ECHOF2
	 CALL ECHOCH	;ECHO IT IF REQUESTED, AND SYSTEM DIDN'T ECHO IT.
]
TYIJRN:	ANDI CH,777+TOP
	SKIPE JRNOUT	;WRITE CHARACTER TO JOURNAL FILE IF THERE IS ONE.
	 CALL JRNOCH
	CAME CH,HELPCH		;TURN OUR HELP CHARACTER INTO TOP-H.
	 JRST TYI6
	CALL TYI4
	MOVEI CH,TOP+"H
	RET

TYI6:	SKIPE DISPRR	;WHEN OUTSIDE OF ^R,
	 JRST TYI7
	CAIN CH,33	;DETECT ALTMODE-ALTMODE.
	 CAME CH,LTYICH
	  JRST TYI2
	SOSGE TSALTC	;FOUND ONE! DECREMENT COUNT OF PAIRS REMAINING TO BE READ.
	 AOS TSALTC
TYI7:	HRLI CH,-1	;MAKE SURE 2ND ALTMODE OF PAIR CAN'T COUNT AS FIRST OF ANOTHER.
TYI2:	MOVEM CH,LTYICH
	ANDI CH,#META#CONTRL	;TURN ASCII CTL CHARS INTO 9-BIT ONES,
	CAIE CH,^M
	 CAIG CH,^J		;EXCEPT FOR ^H, ^I, ^J, ^M AND ALTMODE.
	  CAIGE CH,^H
	   CAIN CH,33
	    JRST TYI3
	TRNN CH,TOP+140		;ALSO, DON'T ALTER THINGS WHICH HAVE THE "TOP" BIT.
	 IORI CH,CONTRL+100
TYI3:	IOR CH,LTYICH		;NOW RESTORE THE CONTROL AND META BITS, AND FLUSH TOP.
	ANDI CH,CONTRL+META+177
TYI4:	IDPB CH,TYIBFP		;RECORD THE INPUT CHARACTER IN THE RING BUFFER FOR SUCH.
	CALL TYI1
	SKIPN TYISNK		;INVOKE FS TYISINK$ IF THERE IS ONE
	 RET
	CALL SAVACS
	MOVE C,CH		;WITH THE CHARACTER AS ARGUMENT.
	MOVE A,TYISNK
	CALL MACXCP
	JRST RSTACS

IFN 20X\FNX,[
VTSTYI:	PUSH P,A
	PUSH P,B
	EXCH C,CH
	MOVEI A,.CTTRM
	MOVEI B,.MOFCI
	MTOPR			;READ 12-BIT CHARACTER
VTSIOT:	EXCH C,CH
IFN 20X,[
	CAIE CH,^M
	 JRST VTSIO1
	RFMOD
	SAVE B
	TRO B,100
	SFMOD			;GO INTO ASCII MODE AND
	BIN			;FLUSH LF AFTER CR IN CASE OF GTJFN LATER
	REST B
	SFMOD
VTSIO1:	];IFN 20X
	POP P,B
	POP P,A
	JRST TYI5A
];IFN 20X\FNX

FSTBBK:	MOVE A,TYIBFQ		;FS .TYIBACK$: BACK UP TYIBFP ONE CHARACTER.
	CAMN A,[001400,,TYIBUF-1]
	 ADDI A,TYIBSZ		;IF BACK BEFORE START OF BUFFER, WRAP TO END.
	MOVEM A,TYIBFQ
	IBP TYIBFQ		;TO BACK UP THE POINTER,
	IBP TYIBFQ		;ADVANCE IT TWICE, THEN BACK UP A WORD.
	SOS TYIBFQ
	RET

FSTBNXT:ILDB A,TYIBFQ		;FS .TYINXT$: GET NEXT OLD TYI CHARACTER.
	AOS (P)
	MOVE CH,TYIBFQ
	CAMN CH,[001400,,TYIBUF+TYIBSZ-1]
	 SUBI CH,TYIBSZ
	MOVEM CH,TYIBFQ
	RET

TYI1:	AOS INCHCT		;BUMP COUNT OF INPUT CHARACTERS READ SO FAR.
	EXCH CH,TYIBFP		;PUSH THE CHARACTER ONTO THE RING BUFFER OF INPUT.
	CAMN CH,[001400,,TYIBUF+TYIBSZ-1]
	 SUBI CH,TYIBSZ
	MOVEM CH,TYIBFQ
	EXCH CH,TYIBFP
	RET

;CONVERT CHAR. IN CH FROM TV CHAR SET TO ASCII.
TYINRM:	TRZ CH,META	;CONTROL-^-MUMBLE JUST BECOMES ^-MUMBLE.
	 TRZN CH,CONTRL
	  RET
	CAIN CH,177
	 RET		;CONTROL-RUBOUT SHOULD BE RUBOUT, NOT "?".
	CAIE CH,40	;CONTROL-SPACE IS ^@.
	 TRZE CH,100	;NOTE TV CHAR SET HAS CONTROL-LOWERCASE LETTERS!
	  ANDCMI CH,40	;THEY SHOULD CONVERT JUST LIKE CONTROL-UPPERCASE LETTERS.
	RET

;STORE INFO IN DEBUG BUFFER
;WHEN INPUT STOPS DISPLAY
DBGBFI:	SAVE A
	MOVEI A,DBGBFI
	CALL DBGBFP
	MOVE A,CHCTVP
	CALL DBGBFP
	MOVE A,INCHCT
	CALL DBGBFP
	MOVE A,RRMAXP
	CALL DBGBFP
	MOVE A,RRMSNG
	CALL DBGBFP
	JRST POPAJ

;PUSH ONE WORD ONTO THE DEBUG BUFFER.
DBGBFP:	SAVE B
	MOVE B,DBGBFX
	CAIN B,DBGBFE
	 MOVEI B,DBGBUF
	MOVEM A,(B)
	AOS B
	MOVEM B,DBGBFX
	REST B
	RET

SUBTTL JOURNAL FILES

;FORMAT OF DATA IN JOURNAL FILES:
;MOST THINGS ARE REPRESENTED BY PAIRS OF CHARACTERS.
;CRLF REPRESENTS A CR COMMAND.
;"??" REPRESENTS THE HELP CHARACTER.
;SPACE AND A CHAR REPRESENT THAT CHAR.
;^ AND A CHAR REPRESENT THAT 7-BIT CHAR PLUS THE CONTROL BIT.
;+ IS LIKE ^, FOR META.  * IS LIKE ^, FOR CONTROL AND META TOGETHER.

;THINGS OTHER THAN PAIRS OF CHARACTERS INCLUDE:
; SEMICOLON, WHICH STARTS A COMMENT TERMINATED BY A CRLF;
; :, WHICH CAUSES FS JRN MAC TO BE RUN AND IS FOLLOWED BY ARGUMENTS FOR THAT MACRO;
; ^G (007), WHICH CAUSES FS JRN MAC TO BE RUN BUT IS NOT FOLLOWED BY ARGUMENTS.
; THE COLON OR ^G IS PASSED TO FS JRN MAC AS AN ARGUMENT.

;START WRITING A JOURNAL FILE.  USE THE DEFAULT FILENAMES.
;COLON FLAG MEANS CLOSE THE FILE.
FSJRNO:	MOVE A,JRNOIVL
	MOVEM A,JRNOCT
	MOVEI E,JRNOUT
IFN TNX,[
	MOVSI A,(GJ%FOU)
	MOVE B,[7_30.+OF%WR]
];TNX
.ELSE	MOVE A,[.UAO,,CHJRNO]
	JRST FSJRN

;START RE-EXECUTING A JOURNAL FILE.  USE THE DEFAULT FILENAMES.
;COLON FLAG MEANS STOP.
FSJRNX:	MOVEI E,JRNIN
IFN TNX,[
	MOVSI A,(GJ%OLD)
	MOVE B,[7_30.+OF%RD]
];TNX
.ELSE	MOVEI A,CHJRNI
FSJRN:	TRZN FF,FRCLN		;IF COLON FLAG, CLOSE CHANNEL AND LEAVE IT THAT WAY.
	 JRST FSJRNN
FSJRNC:
IFN ITS,[
	SYSCAL CLOSE,[A]
	 .LOSE %LSFIL
];ITS
IFN TNX,[
	MOVE A,(E)
	CLOSF
	 JFCL
];TNX
	SETZM (E)
	RET

FSJRNN:	SETZM (E)		;SAY NONE IS OPEN IN CASE OPEN FAILS (OR WE QUIT).
	CALL IMMQIT		;ALLOW QUITTING OUT OF THE OPEN.
IFN ITS,[
	.CALL RREDB
	 JRST OPNER1
	SETOM (E)		;SUCCESS, SAY ONE IS OPEN.
];ITS
IFN TNX,[
	SAVE B			;SAVE OPENF FLAGS
	CALL FF5		;GET JFN FROM DEFAULTS
	 JRST OPNER1
	REST B
	OPENF
	 JRST OPNER1
	MOVEM A,(E)
IFN 20X,[			;ON TOPS-20, MAKE SURE FILE EXISTS SO IT SURVIVES
	TRNN B,OF%WR
	 JRST DELQIT
	HRLI A,(CO%NRJ)
	CLOSF			;BY CLOSING
	 JRST OPNER1
	HRRZS A
	HRRI B,OF%APP
	OPENF			;AND OPENING AGAIN FOR APPEND
	 JRST OPNER1
];20X
];TNX
	JRST DELQIT

;READ A CHARACTER INTO A FROM THE INPUT JOURNAL FILE.  FS JRN READ.
FSJRNR:
IFN ITS,[
	SKIPE A,JRNIN
	 .IOT CHJRNI,A
];ITS
IFN TNX,[
	SKIPN A,JRNIN
	 JRST POPJ1
	BIN
	MOVE A,B
];TNX
	JRST POPJ1

;WRITE A CHARACTER INTO THE OUTPUT JOURNAL FILE FROM C.  FS JRN WRITE.
;DON'T WRITE IN THE NEW JOURNAL WHILE WE ARE READING AN OLD ONE.
FSJRNW:	SKIPN JRNIN
	 SKIPN JRNOUT
	 RET
	SKIPGE CH,C		;HANDLE EITHER STRING OR CHARACTER
	 JSP CH,FSMPD1
IFN ITS,.IOT CHJRNO,CH
IFN TNX,[
	EXCH A,JRNOUT
	EXCH B,CH
	BOUT
	EXCH B,CH
	EXCH A,JRNOUT
];TNX
	RET

;READ A COMMAND CHARACTER INTO CH FROM AN INPUT JOURNAL FILE.
JRNICH:	CALL JRNIC0
IFN ITS,[
	JUMPL CH,JRNEOF
	CAIN CH,^C
	 JRST JRNEOF			;EOF => RETURN NON-SKIP.
];ITS
IFN TNX,JUMPE CH,JRNEOF
	CAIN CH,";
	 JRST JRNICM		;SEMICOLON IN JOURNAL MEANS A COMMENT.
	CAIN CH,"?		;HELP CHARACTER IS REPRESENTED BY "??"
	 JRST JRNIHP
	CAIE CH,^G		;^G MEANS WE QUIT.  BETTER LET USER LOOK AROUND.
	 CAIN CH,":		;: MEANS EXECUTE A COMMAND.
	  JRST JRNCMD
	CAIN CH,^M		;CRLF STANDS FOR JUST CR TYPED IN.
	 JRST JRNICR
	SAVE A
	SETO A,			;ELSE READ 1ST CHAR OF PAIR,
	CAIN CH,40		;WHICH SHOULD SPECIFY THE CONTROL AND META BITS.
	 SETZ A,
	CAIN CH,"^
	 MOVEI A,200
	CAIN CH,"+
	 MOVEI A,400
	CAIN CH,"*
	 MOVEI A,600
	SKIPGE A		;NOT SPACE, ^, + OR * => JOURNAL FILE IS NO GOOD.
	 TYPRE [UJC]
	CALL JRNIC0		;MERGE IN BASIC ASCII CHAR AND RETURN IT.
	ADD CH,A
	AOS -1(P)
	JRST POPAJ

JRNIC0:
IFN ITS,.IOT CHJRNI,CH
IFN TNX,[
	EXCH A,JRNIN		;READ A SINGLE CHARACTER FROM THE FILE
	EXCH B,CH
	BIN
	EXCH B,CH
	EXCH A,JRNIN
] ;TNX
	RET

JRNEOF:	
IFN ITS,[
	.CLOSE CHJRNI,
	SETZM JRNIN
	RET
];ITS
IFN TNX,[
	SAVE A
	CLOSEF JRNIN
	JRST POPAJ
];TNX

JRNICM:	CALL JRNIC0		;COMMENT - SKIP PAST LINEFEED, THEN TRY AGAIN TO READ CHAR.
	CAIE CH,^J
	 JRST JRNICM
	JRST JRNICH

JRNICR:	CALL JRNIC0
	CAIE CH,^J
	 TYPRE [UJC]
	MOVEI CH,^M
	JRST POPJ1

JRNIHP:	CALL JRNIC0		;GOT ONE "?" => CHECK FOR TWO, AND RETURN HELP CHAR.
	CAIE CH,"?
	 TYPRE [UJC]
	MOVE CH,HELPCH
	JRST POPJ1

;^G OR COLON READ FROM JOURNAL FILE.  CALL FS JRN MACRO.
JRNCMD:	AOS (P)			;RETURN SKIPPING TWICE, TO CHECK UNRCHC AGAIN.
	AOS (P)			;IF NOTHING THERE, IT WILL COME BACK TO JRNICH AGAIN.
	CALL SAVACS
	MOVE C,CH		;PASS CHARACTER AS ARGUMENT.
	MOVE A,JRNMAC
	CALL MACXCP
	JRST RSTACS

;WRITE COMMAND CHARACTER IN CH TO JOURNAL OUTPUT FILE.  CLOBBERS NOTHING.
;EACH COMMAND CHARACTER IS REPRESENTED BY TWO CHARACTERS IN THE JOURNAL FILE.
;THE CHARACTER CR IS REPRESENTED BY A CRLF.
;THE HELP CHARACTER IS REPRESENTED BY "??".
;OTHER CHARACTERS HAVE FIRST SPACE, ^, + OR * FOR NONE, CTL, META AND CTL-META,
;FOLLOWED BY THE ASCII BASIC CHARACTER.
JRNOCH:	SKIPE JRNIN
	 RET
	CAIN CH,^M		;CR IS OUTPUT AS A CRLF.
	 JRST JRNOCR
	CAMN CH,HELPCH
	 JRST JRNOHP
	HRLM CH,(P)
	LSH CH,-7
IFN ITS,[
	.IOT CHJRNO,JRNOTB(CH)	;OUTPUT SOMETHING TO REPRESENT THE META BITS
	HLRZ CH,(P)
	.IOT CHJRNO,CH		;THEN OUTPUT THE BASIC CHARACTER.
];ITS
IFN TNX,[
	EXCH A,JRNOUT
	EXCH B,CH
	MOVE B,JRNOTB(B)
	BOUT
	HLRZ B,(P)
	BOUT
	EXCH B,CH
	EXCH A,JRNOUT
];TNX
	JRST JRNFRC

JRNOTB:	40 ? "^ ? "+ ? "*

JRNOHP:	
IFN ITS,[
	.IOT CHJRNO,["?]
	.IOT CHJRNO,["?]
	JRST JRNFRC
];ITS
IFN TNX,[
	EXCH A,JRNOUT
	SAVE B
	MOVEI B,"?
	BOUT
	JRST JRNOC1
];TNX

JRNOCR:	
IFN ITS,[
	.IOT CHJRNO,[^M]
	.IOT CHJRNO,[^J]
];ITS
IFN TNX,[
	EXCH A,JRNOUT
	SAVE B
	MOVEI B,^M
	BOUT
	MOVEI B,^J
JRNOC1:	BOUT
	REST B
	EXCH A,JRNOUT
];TNX
JRNFRC:	SOSLE JRNOCT		;EVERY SO OFTEN, MAKE SURE THE SYSTEM BUFFER IS WRITTEN OUT.
	 RET
IFN ITS,[
	SYSCAL FORCE,[%CLIMM,,CHJRNO]
	 .LOSE %LSFIL
];ITS
IFN 20X,[
	SAVE B
	SAVE A
	HRRZ A,JRNOUT
	RFPTR
	 SETZ B,
	ADDI B,4777
	SAVE C
	IDIVI B,5000		;GET NUMBER OF PAGES IN FILE
	REST C
	HRLZ A,JRNOUT
	UFPGS			;FORCE THEM OUT TO DISK
	 JFCL
	REST A
	REST B
];20X
	PUSH P,JRNOIVL
	POP P,JRNOCT
	RET

SUBTTL PURIFY

IFN ITS,[
;DUMPIT$G TO DO $Y<CR> THEN PURIFY, WITH THE BONUS THAT IT REFUSES
;TO WORK ON A TECO THAT HAS BEEN RUN.
DUMPIT:	SKIPE RUNFLG
	 .VALUE
	.VALUE [ASCIZ /Y
P/]

;PURIFY$G TO MAKE PURE THE PAGES THAT ARE SUPPOSED TO BE PURE.
PURIFY:	SKIPE RUNFLG
	 .VALUE
	.VALUE [ASCIZ /B P/]
	MOVEI P,PDL
	MOVE A,[PURP1-PURPL,,PURP1]
	SYSCAL CORBLK,[%CLIMM,,%CBRED ? %CLIMM,,%JSELF ? A]
	 .LOSE %LSFIL
	SETOM PUREFL
RADIX 10.
	.VALUE [.ASCII \
:Purified

:PDUMP .TECO.;TECPUR !.FVERS \]
RADIX 8
	JRST INIT
]

IFN TNX,[
PURIFY:	SKIPE RUNFLG
	 .VALUE
	SETOM PUREFL
	MOVSI 1,(GJ%SHT) ;FIRST WRITE OUT SYMBOL TABLE
RADIX 10.
IFN 20X,HRROI 2,[STRCNC [TECO.SYMBOLS.]\.FNAM3 ]
.ELSE	HRROI 2,[STRCNC [TECO.SYMBOLS;]\.FNAM3 ]
RADIX 8
	GTJFN
	 JRST PFYERR
	MOVE 2,[36._30.+OF%WR]
	OPENF
	 JRST PFYERR
	MOVE 2,116	;AOBJN POINTER
	SUBI 2,1	;INTO IOWD
	BOUT
	HLRE 3,2	;LENGTH
	HRLI 2,004400
	SOUT
	CLOSF
	 JRST PFYERR
	HLRE 2,116	;BLT OUT THE SYMBOL TABLE
	AOS 1,116	;FIRST ADDRESS OF SYMBOLS+1
	HRLI 1,-1(1)
	SETZM -1(1)	;ZERO IT OUT
	SUBI 2,(1)	;GET LAST WORD OF THEM
	MOVM 2,2
	BLT 1,(2)	;AND ZERO THE REST OF THEM
	SETZM 116	;ZERO POINTER TOO FOR DDT

	MOVEI 1,.FHSLF
	MOVE 2,[3,,BOOT]
	SEVEC		;SET UP OUR ENTRY VECTOR

	MOVSI 1,(GJ%SHT)
RADIX 10.
IFN 20X,HRROI 2,[STRCNC [TECO.EXE.]\.FNAM3 ]
.ELSE	HRROI 2,[STRCNC [TECO.SAV;]\.FNAM3 ]
RADIX 8
	GTJFN
	 JRST PFYERR
	HRLI 1,.FHSLF
	MOVE 2,[SS%CPY+SS%RD+SS%EXE+<-600,,0>]
	SETZ 3,
	SSAVE
	 ERJMP PFYERR
RADIX 10.
	MOVSI 1,(GJ%SHT)
IFN 20X,HRROI 2,[STRCNC [TECPUR.EXE.]\.FNAM3 ]
.ELSE	HRROI 2,[STRCNC [TECPUR.SAV;]\.FNAM3 ]
RADIX 8
	GTJFN
	 JRST PFYERR
	HRLI 1,.FHSLF
	MOVE 2,[SS%RD+SS%EXE+<PURP1*2-PURPL*2,,PURP1*2>]
	SSAVE
	 ERJMP PFYERR
	JRST INIT

PFYERR:	MOVEI 1,.PRIOU		;ERROR WHILE PURIFYING, GIVE THE PERSON A HINT WHAT HAPPENED
	HRLOI 2,.FHSLF		;LAST ERROR THIS PROCESS
	SETZ 3,
	ERSTR
	 JFCL
	 JFCL
	.VALUE
] ;IFN TNX

SUBTTL SUBROUTINES FOR COMMAND STREAM CHARACTER READER RCH

;COME HERE ON TRYING TO READ PAST THE END OF A COMMAND STRING LEVEL.
RCH2:	SAVE A		;POP OFF MACRO FRAME
	SETZM COMCNT	;DON'T LET COMCNT BE -1 -- WOULD SCREW IF ERROR HANDLER DOES BACKTRACE.
	SKIPN A,MACPTR	;0 MEANS TRIED TO POP OUT OF TOP-LEVEL
	 JRST INSCHK
RCH2A:	CALL ERSTST	;REFUSE TO POP OUT OF MACRO CONTAINING UNTERMINATED "<" OR ":<".
	LDB CH,MACPDP	;TRY TO POP MACPDL ENTRY FOR THE MACRO-CALL.
	TRNE CH,10
	 JRST RCH2B	;TOP OF MACPDL ISN'T A MACRO-CALL ENTRY!
	HRRE A,(A)
	JUMPGE A,RCH2D	;ARE WE POPPING OUT OF A MACXQ (MIDAS TO TECO CALL)?
	HRRZ A,-1(P)	;YES, ONLY ALLOWED FROM COMMAND LOOP.
	CAIE A,CDRCH
	 JRST INSCHK	;INSIDE A COMMAND => ERROR.
RCH2D:	MOVE A,MACPTR
	CALL DECDCH	;IT IS ONE, RESTORE RCHALT AND SQUOTP AS IT SAYS.
	CALL POPMAC	;POP THE MACRO-STRING-FRAME.
	CALL POPMP	;ACTUALLY DEECREMENT MACPDP.
RCH2C:	REST A
	SKIPL MACPTR	;ARE WE POPPING OUT OF A MACXQ?
	 JRST RCH	;NO, TRY AGAIN, READ FROM WHAT WE POPPED INTO.
	MOVE CH,MACXP	;YES, RESTORE PDL LEVEL TO THAT AT
	POP CH,MACXP	;CALL TO MACXQ, AND PREPARE TO RETURN.
	POP CH,MACPTR
	EXCH C,NUM	;FINISH PROCESSING A NUMBER OR "." AT END OF MACRO
	TRZE FF,FRSYL
	 XCT DLIM	;BY COMBINING IT WITH PREVIOUS ARITH OP.
	EXCH C,NUM	;AND MAKE IT THE NEW VALUE
	JRST SETP	;SET P FROM CH AND ADJUST LEV.

RCH2B:	CAIN CH,10	;A NULL ENTRY? FLUSH IT AND TRY AGAIN.
	 JRST [CALL POPMP ? JRST RCH2A]
	MOVEI CH,4	;[ ;CAN'T POP SINCE ^]^X'D INTO,
	MOVEM CH,COMCNT	;[ ;INSTEAD ^]^X UP ANOTHER LEVEL.
	MOVE CH,[BP7,,[ASCIZ//]]
	MOVEM CH,CPTR
	MOVEM CH,CSTR
	SKIPGE MACPTR	;I THINK TECO LOSES IF IT USES UP
	 .VALUE		;[ ;ALL OF A MACXQ'D STRING WITH A ^]^X.
	JRST RCH2C

;THE RCHDTB ENTRY FOR THE CASE SHIFT CHAR IS <CALL RCHSFT>
RCHSFT:	SKIPN MACPTR	;IN MACRO, CASE SHIFT ISN'T SPECIAL.
RCHSF1:	SKIPE RCHSFF	;IF PREV. CHAR WAS SHIFT, THIS ONE IS QUOTED.
	 POPJ P,	;PRETEND NOT TO BE A CASE-SHIFT.
	MOVNS CASE	;ELSE ASK TO READ NEXT CHAR IN THE OTHER CASE,
	MOVE CH,-1(P)	;GET RET. ADDR OF READ RTN,
	SETOM RCHSFF	;QUOTE NEXT CHAR IF CASE-SHIFT OR LOCK.
	XCT -1(CH)	;RE-CALL THE READ RTN. (TRACES IF NEC)
	MOVNS CASE	;RESTORE CASE TO WHAT IT HAD BEEN.
	SETZM RCHSFF
POP1J:	SUB P,[1,,1]	;RETURN FROM THE CALL TO RCH
	POPJ P,		;SINCE CHAR WAS ALREADY TRACED.

RCHLOK:	SKIPN MACPTR	;RCHDTB ENTRY FOR CASE-LOCK CALLS HERE..
	SKIPE RCHSFF	;IF IN MACRO OR QUOTED BY A CASESHIFT,
	 POPJ P,	;DO NOTHING SPECIAL.
	MOVNS CASE	;ELSE SWITCH THE CASE WE WANT CHARS IN,
RCHTRY:	SUB P,[1,,1]
	REST CH
	JRST -1(CH)	;AND GO READ THE NEXT CHAR.

;OUTPUT CHARACTER IN CH WHOSE EXECUTION IS TRACED.
.SEE TRACS ;TRACS CONTAINS JRST TYOS WHEN TRACING IS ON.
;CLOBBERS NO ACS.
TYOS:	SKIPE BRC1
         RET  
	SAVE Q
	SAVE CH
	SETOM TRCOUT
	PUSHJ P,TYO
	MOVE CH,(P)
	CAIE CH,^M	;DON'T MAKE CR COME OUT AS ^M.
	PUSHJ P,DISFLS
	SETZM TRCOUT
	REST CH
POPQJ:	REST Q
	RET

;COME HERE IF POP OUT OF MACXQ'D OR TOP-LEVEL STRING IN THE MIDDLE OF A COMMAND.
INSCHK:	SKIPN INSINP	;IF WITHIN AN INSERT, WE COULD JUST ERR OUT
	 TYPRE [CNM]
	MOVE P,INSINP	;BUT THAT WOULD LOSE THE STUFF INSERTED SO FAR.
	SETZM INSINP	;SO TELL INSDUN TO DO THE CNM ERROR
	JRST INSDUN	;AND CAUSE INSERT TO FINISH UP.

SUBTTL MACRO FRAME ALLOCATION

;FREE UP A CELL OF MACRO CALL SPACE.
;A -> 1ST WD OF CELL, MINUS 1.
FLSFRM:	ANDI A,-1		;MAKE SURE NO GARBAGE BLOCK IS PUT ON THE FRAME FREELIST.
	CAMGE A,MFEND
	 CAIGE A,MFSTRT-1
	  .VALUE
	SETZM MFCPTR+1(A)
	SETZM MFBEG+1(A)
	EXCH CH,MFFREE
	MOVEM CH,MFLINK+1(A)
	MOVE CH,MFFREE
	HRRZM A,MFFREE
	POPJ P,

;OBTAIN A FREE CELL OF MACRO CALL CELL SPACE.
;RETURN POINTER TO WD BEFORE 1ST WD OF CELL, IN A.
GETFRM:	SKIPG A,MFFREE
	 JRST GETFR1
	ANDI A,-1
	CAMGE A,MFEND
	 CAIGE A,MFSTRT-1
	  .VALUE
	MOVE A,MFLINK+1(A)
	EXCH A,MFFREE
	POPJ P,

GETFR1:	CALL GCNRL	;GC, PERHAPS FREEING FRAMES USED BY BUFFERS.
	SKIPE MFFREE
	 JRST GETFRM	;ONE WAS FREED.
	CALL GETFR2
	JRST GETFRM

GETFR2:	CALL SAVACS		;MAKE MFINCR MORE MACRO FRAMES,
	SAVE TOTALC
	MOVE A,MFEND		;UNLESS WE ALREADY HAVE THE MOST WE ARE ALLOWED TO HAVE.
	CAILE A,MFSTRT+<MFMAX-MFINCR>*MFBLEN
	 TYPRE [TMN]
	MOVEI C,MFINCR*MFBLEN*5	;NUMBER OF CHARS WORTH OF SPACE WE WILL ALLOCATE.
	CALL SLPQGT		;MAKE SURE IMPURE STRING SPACE HAS ROOM TO MOVE UP THAT FAR.
	HRRZ BP,CBUFLO
	IMULI BP,5
	MOVE TT,QRWRT		;GET START AND END OF RANGE OF CORE TO MOVE UP, IN CHARS.
	HRRZ CH,INSBP		;NOTE THAT IF A STRING IS NOW BEING WRITTEN JUST PAST QRWRT,
	ADDI CH,1		;IT MUST BE INCLUDED IN RANGE TO MOVE.
	IMULI CH,5
	CAML CH,BFRBOT
	 JRST GETFR7
	CAMGE TT,CH
	 MOVE TT,CH
GETFR7:	MOVEI C,MFINCR*MFBLEN	;GET NUMBER OF WORDS TO MOVE UP BY.
	CALL SLPN0Q
	SAVE E
	MOVE A,MACPTR
	CALL GETFR5		;RELOCATE ALL BYTE POINTERS IN MACRO, CTX AND ITERATION FRAMES.
	MOVE A,CTXPTR
	CALL GETFR5
	MOVE A,ITRPTR
	CALL GETFR5
	CAML D,CSTR		;IF CPTR IS A B.P. TO A STRING, RELOCATE IT.
	 ADDM C,CPTR
	REST E
	ADDM E,QRBUF		;ADD # CHARS MOVED BY (SET BY SLPN0Q) TO
	ADDM E,QRWRT		;BOUNDS OF IMPURE STRING SPACE.
	MOVE D,BFRBOT
	IDIVI D,5
	HRRZ E,INSBP
	CAIL E,@CBUFLO		;IF INSBP IS IN THE COMMAND BUFFER OR IMPURE STRING SPACE,
	 CAMLE E,D		;RELOCATE IT.
	  JRST GETFR4		;(THESE TESTS EXCLUDE THE SPECIAL VALUES, 0 AND -1).
	ADDM C,INSBP
GETFR4:	ADDM C,CBUFLO
	ADDM C,CBUFH		;UPDATE BOUNDS OF COMMAND BUFFER.
	MOVE A,MFEND
	ADDB C,MFEND		;MARK ADDITIONAL SPACE AS IN USE BY MACRO FRAMES.
	SOS A
GETFR3:	CALL FLSFRM		;NOW "FREE" ALL THE NEWLY ALLOCATED FRAMES SO THEY CAN BE USED.
	ADDI A,MFBLEN		;NOTE THAT THE ARG TO FLSFRM MUST BE THE FRAME ADDR MINUS 1.
	CAIE A,-1(C)
	 JRST GETFR3
	REST TOTALC
	JRST RSTACS

;IF A POINTS TO THE START OF A LIST OF MACRO FRAMES,
;RELOCATE THOSE MFCPTR'S OF FRAMES IN THE LIST WHICH POINT AT STRINGS.
;C IS THE AMOUNT TO RELOCATE BY.
GETFR5:	MOVE D,QRWRT
	TLO D,400000		;D GETS THE LARGEST NUMBER WHICH IS A STRING POINTER.
	MOVE E,MACXP		;IF THIS LIST IS MACPTR, IT MAY HAVE POINTERS THRU THE STACK.
GETFR6:	JUMPE A,CPOPJ		;EXIT ON REACHING END OF LIST.
	CAML D,MFCSTR-MFLINK(A)	;RELOCATE THE CPTR IF THE CSTR INDICATES THAT THE CPTR
	 ADDM C,MFCPTR-MFLINK(A)	;POINTS INTO AN IMPURE STRING.
	HRRE A,MFLINK-MFLINK(A)	;NOTE THAT A POINTS AT THE MFLINK WORD, NOT THE START OF THE FRAME.
	JUMPGE A,GETFR6		;NOW ADVANCE TO THE NEXT FRAME IN THE LIST.
	MOVE A,-1(E)		;BUT MAYBE ADVANCE DOWN A LINK MADE BY A MACXQ CALL.
	MOVE E,(E)
	JRST GETFR6

;[
SUBTTL ^]

;[ ;THE RCHDTB ENTRY FOR ^] IS <CALL CTLBRC>
;NOTE THIS CAN RETURN TO THE CALLING PUSHJ, TO RETRY IT.
CTLBRC:	JUMPL CH,TRACS
	SKIPGE SQUOTP
	 JRST TRACS
	CALL TRACS
	SETZM BRC1CF
	SETZM BRCUAV
	SETOM DLMF2
	SETZM SQUOF2
BRCREC:	PUSHJ P,[		;[ ;^]@ OF A STRING RETURNS HERE TO READ 1ST CHAR OF STRING.
		SKIPG COMCNT
		 TYPRE [UEC]
		SOS COMCNT
		ILDB CH,CPTR
		POPJ P,]
				;[ ;^]@ OF A NUMBER RETURNS HERE WITH NUMBER IN CH.
	CALL TRACS
BRCRC2:	INSIRP PUSH P,A B TT TT1 BP	;BP MUST BE LAST - SEE EXPMAC.
	SETZ A,
	PUSHJ P,QNMGE2
	 JRST QLET
	SKIPE BRC1
	 JRST BRCRT5
	CALL QLGET
	 JRST BRCNVL
	JRST EXPMAC

QLET:	SKIPE A
	 TYPRE [IQN]
INSIRP POP P,BP TT1 TT B A	;[
	CAIE CH,^]
	 CAIN CH,ALTMOD
	  JRST BRCPRT
	CAIN CH,""		;[ ;ALLOW ^] TO QUOTE A ".
	 JRST BRCPRT
	CAIN CH,"$
	 JRST RET33
	CAIN CH,^Q
	 JRST BRCCTQ
	CAIN CH,^T
	 JRST BRCCTT
	CAIN CH,^S
	 JRST BRCCTS
	CAIN CH,^A
	 JRST BRC1CH
	CAIN CH,^V
	 JRST BRCCTV
	SKIPE BRC1
	 JRST BRCRC3
	CAIN CH,"@
	 JRST BRCIND
	CAIN CH,^X
	 JRST BRCCTX
	CAIN CH,^Y
	 JRST BRCCTY
	TYPRE [ICB]

BRCRC3:	CAIN CH,"@
	 JRST BRCREC
	CAIE CH,^X
	 CAIN CH,^Y
	  JRST BRCRT
	TYPRE [ICB]

BRCCTS:	SETOM SQUOF2
	SETOM DLMF2
	JRST BRCREC

BRCCTT:	SETZM DLMF2
	JRST BRCREC

BRC1CH:	SETOM BRC1CF
	JRST BRCREC

BRCIND:	SAVE [BRCREC+1]
	JRST BRCREC	;CALL BRCREC, THEN GO TO BRCRC2.

BRCCTV:	SETOM BRCUAV
	JRST BRCREC

BRCNVL:	SKIPN BRCUAV
	 TYPRE [QNS]
	SETOM BRCFLG
	INSIRP POP P,BP TT1 TT B
	MOVE CH,A
	HRROM A,BRCUAV	;LEAVE UNTRUNCATED VALUE FOR QNMGET.
	ANDI CH,177
	CALL TRACS
	SKIPE SQUOF2
	 HRLI CH,-1
	JRST POPAJ

BRCCTQ:	CALL SKRCH
BRCPRT:	HRLI CH,-1	;RETURN THE CHARACTER SUPERQUOTED.
	POPJ P,

;SET SQUOTP ACC TO SQUOF2, DLMF2 AND TURN OFF RCHALT.
;ALSO SAVE OLD STATE OF THOSE VARS AS BITS IN CH FOR PUSHING ON MACPDP
FLGENC:	SETZ CH,
	SKIPE DLMF2	;SET SQUOTP ACC. TO SQUOF2, DLMF2
	 TLO CH,2^5
	SKIPE SQUOF2
	 TLO CH,4^5	;AND SET CH ACC TO PREVIOUS SQUOTP AND RCHALT
	EXCH CH,SQUOTP
	IORM CH,SQUOTP
	ROT CH,2	.SEE MACPDP	;SET UP CH AS A MACPDL ENTRY
	ADDI CH,1
	HLRZ A,RCHALT
	CAIN A,(CALL)
	 ADDI CH,4
	MOVEI A,(JFCL)	;ALSO TURN OFF RCHALT.
	HRLM A,RCHALT
	POPJ P,

DECDCH:	TRNN CH,3	
	 POPJ P,	;THIS ENTRY DIDN'T PUSH SQUOTP, RCHALT.
	SUBI CH,1
	DPB CH,[420200,,SQUOTP]
	TRNN CH,4
	SKIPA CH,[(JFCL)]
	MOVEI CH,(CALL)
	HRLM CH,RCHALT
	POPJ P,

;A HAS STRING OBJECT, B HAS LENGTH, BP HAS POINTER TO IT.
;PUSH A CALL TO THAT OBJECT ONTO THE RCH INPUT STREAM.
;NOTE TOP OF PDL HAS VALUE THAT WAS IN BP WHEN RCH WAS CALLED.
EXPMAC:	SETOM BRCFLG
	MOVE BP,(P)	;SAVE BP, AND GET OUR CALLER'S BP.
	CALL PUSMA0	;PUSH MACRO PDL, RELOCATING BP IF BUFFERS MOVE.
	MOVEM BP,(P)	;GIVE CALLER'S BP BACK TO HIM, RELOCATED IF NEC.
	CALL QLGET0	;REDECODE ADDR OF STRING (MAYBE PUSMA0 MADE FRAMES AND CHANGED IT).
	SKIPE BRC1CF
	 MOVEI TT,1
	MOVEM A,CSTR
	MOVEM BP,CPTR
	SKIPE BRC1CF	;IF WANT WHOLE STRING,
	CAMLE TT,B	;OR IF WANT MORE CHARS THAN STRING HAS,
	 MOVE TT,B	;USE STRING LENGTH RATHER THAN DESIRED # CHARS.
	MOVEM TT,COMCNT
	MOVE B,PF
	MOVEM B,MACSPF
	SETZM MACBTS	;[ ;THERE ARE NO ARGS IN A ^] CALL.
	SETZ CH,	;IF NOT SETTING ANY FLAGS, PUSH 0 ON MACPDL.
	SKIPN SQUOF2
	SKIPE DLMF2
	 CALL FLGENC	;ELSE COMPUTE WHAT TO PUSH.
	IDPB CH,MACPDP
BRCRT5:	INSIRP POP P,BP TT1 TT B
BRCRT4:	REST A
BRCRT:	REST CH
	JRST -1(CH)	;RETRY THE RCH.

RET33:	MOVEI CH,ALTMOD
	POPJ P,

;[  ;PERFORM A PUSH INTO A ^]^X.
BRCCTX:	SKIPE BRC1CF
	 JRST BRCCTY
	SETOM BRCFLG
	PUSH P,A
	HRRZ A,-2(P)
	CAIE A,BCYRCH+1	;[[  ;IF THE ^]^X WAS IN THE CHARACTER THAT A ^]^Y WAS TRYING TO READ,
	 JRST BRCCX2
	PUSH P,RCHALT
	HRLZI A,(JFCL)	;[  ;PERFORM A RECURSIVE ^]^Y,
	HLLM A,RCHALT
	PUSHJ P,BRCCTY
	POP P,RCHALT	;[  ; WE HAVE ADVANCED PAST THE ^]^X IN THIS MACRO LEVEL.
	CAIN CH,ALTMOD	;IF WHAT WE JUST GOT IS AN ALTMODE, THAT'S OK;  RETURN IT.
	 JRST BRCRT4
	MOVE A,CPTR	;[  ;BUT OTHERWISE, THIS ^]^X HAS LONGER TO RUN,
	PUSH P,CH	;SO WE MUST BACK UP OVER IT.
BRCCX1:	DBP7 A
	AOS COMCNT
	LDB CH,A	;[
	CAIE CH,^]	;[  ;SO BACK UP UNTIL WE GET TO THE ^].
	 JRST BRCCX1
	DBP7 A		;AND BACK UP ONE CHAR FURTHER.
	AOS COMCNT
	MOVEM A,CPTR
	POP P,CH	;[  ;THEN RETURN THE THING WE GOT FROM THE RECURSIVE ^]^Y.
	JRST POPAJ

BRCCX2: CALL BRCCX0
	JRST BRCRT4

;[  ;PUSH INTO A ^]^X, AS A SUBROUTINE, NOT CALLED BY RCH.  RETURNS WITH A NORMAL POPJ.
BRCCX0:	PUSHJ P,PUSCX0
	SKNTOP MACPTR
	 TYPRE [NIM]
	PUSHJ P,POPMAC
	CALL FLGENC	;SET SQUOTP, GET OLD STATE IN CH.
	ADDI CH,10	;[ ;INDICATE PUSHED BY ^]^X, NOT MACRO CALL.
	IDPB CH,MACPDP
	MOVEI A,(CALL)
	HRLM A,RCHALT	;[ ;START LOOKING FOR AN $ TO END ^]^X.
	SKIPGE MACPTR	;[ ;TRYING TO ^]^X OUT OF A MACXQ => PHONY UP NULL ARG.
	 CALL ENDAR2
	RET

ENDARG:	MOVEM A,(P)
	CALL ENDAR2
	JRST BRCRT4

ENDAR2:	CALL ERSTST
	LDB CH,MACPDP
	TRNN CH,10
	 JRST ENDAR1	;[ ;POPPING ^]^X BUT MACPDP SAYS MACRO CALL.
	CAIN CH,10	;NULL ENTRY ON MACPDP? FLUSH IT.
	 JRST [CALL POPMP ? JRST ENDAR2]
ENDAR5:	CALL DECDCH	;[ ;A ^]^X ENTRY, UNBIND SQUOTP AND RCHALT.
	CALL POPMP	;AND REMOVE THE ENTRY FROM THE STACK.
	JRST ENDAR4

ENDAR1:	SAVE MACPDP
ENDAR3:	CALL POPMP
	CALL ERSTST
	LDB CH,MACPDP	;[ ;LOOK DOWN MACPDP FOR A ^]^X ENTRY.
	CAIG CH,10
	 JRST ENDAR3	;THE ENTRIES ABOVE MUST BE 0 OR 10 .
	CALL DECDCH	;FOUND THE ENTRY, RESTORE SQUOTP.
	MOVEI CH,10	;REPLACE THE ENTRY WITH A NULL.
	DPB CH,MACPDP
	REST MACPDP
ENDAR4:	CALL PUSMA0
	JRST POPCTX

BRCCTY:	SETOM BRCFLG
	PUSH P,A	;HANDLE ^Y OR ^F^X.
	PUSHJ P,PUSCX0
	SKNTOP MACPTR
	TYPRE [NIM]
	PUSHJ P,POPMAC
	CALL FLGENC
	ADDI CH,10
	IDPB CH,MACPDP
	SKIPGE MACPTR	;IF OUR CALLER WAS MACHINE-LANGUAGE TECO,
	 SKIPA CH,[ALTMOD]	;DON'T TRY TO POP INTO IT; PHONY UP AN ALTMODE.
BCYRCH:	PUSHJ P,RCH
	SKIPGE SQUOTP
	 HRLI CH,-1
	SAVE CH
	CALL ENDAR2
	REST CH
	REST A
	RET

;F^K COMMAND FOR READING STRING ARGUMENTS:

;DO <ARGS>F^K<PROMPT>$.  IF YOU WERE CALLED BY A MACRO, IT WILL ACT LIKE   ;[
;  :I*^]^X$, GOBBLING A STRING ARG FROM THAT MACRO.
;OTHERWISE, IT ACTS LIKE <ARGS>M$*F^K HOOK*$<PROMPT>$,
;  WHICH SHOULD READ AN ARGUMENT FROM THE TERMINAL, PROMPTING.
;  IF THE USER RUBS OUT PAST THE START OF THE ARGUMENT,
;  M$*F^K HOOK*$ SHOULD EXIT FROM THE F^K'ING MACRO WITH -2FS BACK RETURN$.

;:F^K RETURNS A NEGATIVE VALUE IF THE CURRENT MACRO'S CALLER WAS TECO INTERNAL CODE.
;IT RETURNS A NONNEGATIVE NUMBER IF THE CALLER WAS ANOTHER MACRO.

;CALLING A MACRO WITH @M MAKES F^K WITHIN THAT MACRO BELIEVE THAT THE
;MACRO WAS CALLED FROM TECO INTERNAL CODE.

FCTLK:	SKIPN A,MACPTR
	 TYPRE [CNM]	;BARF IF NO CALLER AT ALL
	HRRE A,(A)
	MOVE T,MACBTS	;@M IS TREATED LIKE A CALL FROM INSIDE TECO.
	TLNE T,MFBATSN
	 SETO A,
	TRZE FF,FRCLN	;FOR :F^K, RETURN NEGATIVE IF CALLER IS TECO CODE.
	 JRST POPJ1
	JUMPL A,FCTLK1	;NO COLON.  JUMP IF CALLER IS ^R OR OTHER TECO CODE.
	CALL FNOOP	;CALLER IS A MACRO.  FLUSH <PROMPT>.
	MOVE A,CPTR	;BACK UP OVER THE ALTMODE, SO THAT IT WILL TERMINATE THE
	DBP7 A		;ARG WHICH THE :I* WILL READ.
	MOVEM A,CPTR
	AOS COMCNT
	SETZM SQUOF2
	SETOM DLMF2
	CALL BRCCX0	;[  ;SIMULATE GOBBLING A ^]^X.  DELIMITER PROTECT, BUT NO SUPERQUOTING.
FCTLK0:	TRZ FF,FRARG\FRARG2\FRCLN\FRUPRW
	MOVEI CH,A
	MOVE OUT,[CALL RCH]
	MOVEM OUT,INSRCH
	AOS (P)
	JRST PSI	;THEN SIMULATE A :I* AND RETURN ITS VALUE.

FCTLK1:	MOVEI A,[ASCIZ /FM*F HOOK*/]
	HRLI A,440700
	MOVE BP,A
	MOVEI B,14.	;THIS IS THE NUMBER OF CHARACTERS IN THAT ASCIZ STRING!!
	REST T		;DISCARD RETURN ADDRESS, SINCE MAC2 WILL JUMP TO MAIN LOOP.
	CAIN T,CDRET
	 .VALUE
	JRST MAC2	;[  ;WE CAN'T USE MACXQ, SINCE WE NEED TO HAVE ^]^X WORK THROUGH THIS.

PUSMA0:	SKIPE INSBP	;SHOULD BP BE RELOCATED?
	 JRST PUSMAC
	EXCH BP,INSBP	;YES; PUT IT WHERE GC LOOKS.
	CALL PUSMAC
	EXCH BP,INSBP
	RET
	
PUSMAC:	SAVE A
	PUSHJ P,GETFRM
IRP ...,,[COMCNT,CPTR,CSTR,MARG1,MARG2,MACSPF,MACPTR]
	PUSH A,...
TERMIN	MOVEM A,MACPTR
	AOS MACDEP
	HLL A,MACBTS
	HLLM A,(A)
	JRST POPAJ

POPMAC:	SKNTOP MACPTR
	 TYPRE [CNM]
POPMA1:IRP ...,,[MACPTR,MACSPF,MARG2,MARG1,CSTR,CPTR,COMCNT]
	POP A,...
TERMIN
	CALL FLSFRM
	MOVE A,MACPTR
	HRLS MACPTR
	HLLZM A,MACBTS
	SOS MACDEP
	RET

PUSCX0:	SKIPE INSBP	;SHOULD BP BE RELOCATED?
	 JRST PUSCTX
	EXCH BP,INSBP	;YES; PUT IT WHERE GC LOOKS.
	CALL PUSCTX
	EXCH BP,INSBP
	RET

PUSCTX:	PUSHJ P,GETFRM
IRP ...,,[COMCNT,CPTR,CSTR,MARG1,MARG2,MACSPF,CTXPTR]
	PUSH A,...
TERMIN	MOVEM A,CTXPTR
	HLL A,MACBTS
	HLLM A,(A)
	POPJ P,

POPCTX:	SKNTOP CTXPTR
	 JRST [.VALUE ? JRST GO]
IRP ...,,[CTXPTR,MACSPF,MARG2,MARG1,CSTR,CPTR,COMCNT]
	POP A,...
TERMIN
	CALL FLSFRM
	MOVE A,CTXPTR
	HRLS CTXPTR
	HLLZM A,MACBTS
	RET

;DECREMENT MACPDP.
POPMP:	MOVE CH,MACPDP
	ADD CH,[40000,,]
	JUMPGE CH,POPMP1
	CAML CH,[440000,,]
	 SUB CH,[440000,,1]
POPMP1:	MOVEM CH,MACPDP
	POPJ P,

;IF ABOUT TO POP MACPDP, MAKE SURE NOT POPPING
;OUT OF A LEVEL CONTAINING AN UNTERMINATED ERRSET OR ITERATION.
ERSTST:	HRRZ CH,ITRPTR	;ADDR OF BLOCK FOR INNERMOST ERRSET OR ITERATION.
	JUMPE CH,CPOPJ	;THERE IS NONE IN PROGRESS.
	MOVE CH,MFMACP-MFBLEN+1(CH)	;GET THE MACPDP VALUE AT TIME IT WAS ENTERED.
	TLZ CH,40
	CAME CH,MACPDP	;ARE WE POPPING THAT LEVEL?
	 RET
	TSC CH,ITRPTR	;YES. WHICH IS IT - AN ERRSET OR AN ITERATION?
	TRNN CH,-1
	 TYPRE [ERP]	;AN ERRSET.
	TYPRE [UTI]	;AN ITERATION.

SUBTTL ERRORS

;FE -- INSERT A "TECO ERROR" FILE IN THE BUFFER BEFORE PT.
;:FE -- INSERT A LIST OF NAMES OF FS FLAGS.
;<N>FE -- INSERT IN BUFFER THE 3-LETTER CODE
 ;AND MESSAGE ASSOCIATED WITH ERROR CODE <N>
;@FE<CHARS>$ -- RETURNS THE ERROR CODE ASSOCIATED WITH THE 3-CHAR
 ;MESSAGE <CHARS>.
FECMD:	TRZE FF,FRUPRW
	 JRST FECMU
	MOVSI T,-LERTAB
	MOVEI A,TYOM	;TYPEOUT INTO BUFFER AT PT.
	HRRM A,LISTF5
	CALL GAPSLP
	TRNE FF,FRCLN	;:FE - INSERT LIST OF FS FLAGS.
	 JRST FECMD3
	TRZN FF,FRARG
	 JRST FECMD2	;NO ARG, INSERT A LINE FOR EACH ERROR.
	MOVE A,C	;AN ARG (ERROR CODE) IS JUST A STRING, SO GET IT.
FECMD6:	CALL QGET3
	JRST CRR1

FECMD2:	SAVE PT			;SAVE CURRENT PT SO CAN SET UP INSLEN.
FECMD5:	MOVE A,ERRTAB(T)
	HRLI A,400000		;MAKE STRING PTR TO NEXT ERROR MESSAGE.
	SAVE T
	CALL FECMD6		;INSERT EACH ERROR MESSAGE IN THE BUFFER.
	REST T
	AOBJN T,FECMD5
	REST C			;C GETS OLD PT.
	SUB C,PT
	MOVNM C,INSLEN		;FKD WILL DELETE THE WHOLE TABLE.
	RET

FECMD3:	MOVSI T,-FLAGSL
FECMD4:	MOVE E,FLAGS(T)	;GET THE NEXT FLAG'S NAME
	CALL TYPR	;AND TYPE IT OUT INTO BUFFER.
	CALL CRR1	;EACH NAME GOES ON A LINE.
	AOBJP T,CPOPJ	;WHEN THRU, UNBIND LISTF5 AND DONE.
	AOJA T,FECMD4	;HANDLE NEXT FLAG NAME.

;HANDLE @FE.
FECMU:	CALL FSIXR		;READ ARG, MAKE SIXBIT WORD IN A.
	 JFCL
	HLRZ C,A
	MOVSI A,-LERTAB		;NOW SEARCH ERROR TABLE FOR THIS ERROR.
FECMU2:	HLRZ TT,ERRTAB(A)
	CAIE TT,(C)
	 AOBJN A,FECMU2		;STOP WHEN FIND IT, OR AT END OF ERRTAB.
	CAIN A,LERTAB		;IS IT THE END?
	 JRST NRET0		;YES, NO SUCH ERROR MESSAGE, RETURN 0.
	HRRZ A,ERRTAB(A)
	HRLI A,400000		;ELSE RETURN POINTER TO THE ERROR STRING.
	JRST POPJ1

;READ IN A STRING , AND RETURN CONVERTED TO SIXBIT IN A.  IGNORE CONTROL CHARS.  SKIPS. 
FSIXR:	MOVE OUT,[440600,,A]
	SETZ A,
FSIXRL:	CALL LRCH
	CAIN CH,ALTMOD
	 SKIPE SQUOTP
	  CAIA
	   JRST POPJ1
	CAIL CH,40
	 TLNN OUT,770000
	  JRST FSIXRL
	SUBI CH,40
	IDPB CH,OUT
	JRST FSIXRL

;ROUTINE FOR FS ERR$.
FSERR:	MOVE A,LASTER
	TRNN FF,FRARG
	 JRST POPJ1	;READING ONLY - RETURN LAST ERROR'S CODE.
	MOVEM C,LASTER
	JRST DISTOE

;FG -- MAKE A STANDARD ERROR REPORT (USEFUL IN ERROR HANDLER MACROS).
;IF ARG, PRINT STANDARD ERROR MESSAGE FOR THAT ERROR CODE.
  ;AND IF ":", DO IT AT TOP OF SCREEN.
  ;Q..H IS NOT CHANGED BY FG EVEN IF IT DOES TYPEOUT.
;IF "@", THROW AWAY TYPE AHEAD.
;IN ANY CASE, TYPE A BELL.
FGCMD:	MOVE A,QRB..
	SAVE .QVWFL(A)
	TRZE FF,FRARG
	 CALL FGCMDP
	MOVE A,QRB..
	REST .QVWFL(A)
	SKIPE ERRECH		;IF WE TYPED THE ERR MSG IN THE ECHO AREA,
	 SETZM ECHACT
	TRZN FF,FRUPRW
	 JRST TYPBEL
IFN ITS,.RESET CHTTYI,
IFN TNX,[MOVEI A,.PRIIN	;CLEAR INPUT
	CFIBF]
	SETZM TSINAL
	SETZM TSALTC
	SETOM UNRCHC
TYPBEL:	SKIPE TYISNK
	 HRRZM P,MODCHG		;IF CLEARING TYISNK, REMOVE "DEF" FROM EMACS MODE LINE.
	SETZM TYISNK
	SETZM TYISRC
IFN ITS,[
	SKIPE ERRECH
	 .IOT CHECHO,[^G]
	SKIPN ERRECH
	 .IOT CHTTYO,[^G]
]
IFN TNX,[
	SAVE CH
	MOVEI CH,^G
	SKIPE ERRECH
	 CALL ECHOCH
	SKIPN ERRECH
	 CALL TYOINV
	REST CH
]
	JRST FSECO6

FGCMDP:	JUMPE C,CPOPJ		;THERE WS NO ERROR => DON'T PRINT ERROR MESSAGE.
	TRZE FF,FRCLN
	 CALL [	SKIPN ERRECH
		 JRST [	CALL DPYIVI	;IF IN M.P. AREA, USE INVERSE VIDEO.
			JRST DISTOT]
		SKIPGE PJATY	;IF SCREEN MUST BE REDISPLAYED, CLEAR IT NOW RATHER THAN
		 CALL DISIN0	;AFTER THE ERROR MESSAGE IS PRINTED.
		MOVEI CH,^M
		JRST FSECO1]
	MOVE D,VERBOS
FGCMD3:	HRRZM P,ERRFL1		;DON'T LET FS ERRFLG$ STOP THIS FROM PRINTING.
	MOVEI A,TYOA
	SKIPE ERRECH		;IF SPECIFIED, TYPE IN ECHO AREA.
	 MOVEI A,FSECO1
	HRRM A,LISTF5
	CALL FGCMD1
	MOVEI CH,"?
	CALL @LISTF5
	SKIPE ERRECH
	 RET
	CALL DISFLS
	CALL DPYIVC
	MOVE E,TOPLIN
	SUB E,CHCTVP		;HOW MANY LINES WERE USED?
	SOS E
	MOVEM E,ERRFL1		;MAKE SURE THOSE LINES AREN'T ERASED BY REDISPLAY.
	RET

FGCMD1:	MOVE A,C	;PRINT CONTENTS OF STRING IN C.
	CALL QLGET0
	 RET
FGCMD2:	JUMPE B,CPOPJ
	ILDB CH,BP
	CAIN CH,^I	;IF D IS ZERO, STOP AT FIRST TAB.
	 JUMPE D,CPOPJ
	CALL @LISTF5
	SOJA B,FGCMD2

;HANDLE TOP-LEVEL ^X COMMAND:  PRINT THE FULL EROR MESSAGE FOR THE LAST ERROR.
FECMD8:	MOVE C,LASTER
	SETO D,
	JRST FGCMD3

;COME HERE TO REPORT SYSTEM CALL ERROR, ASSUMING THE FILE NAMES ARE IN DEFFIL.
IFN ITS,[
OPNER1:	.SUSET [.RBCHN,,CH]	;GET # OF CHANNEL IN ERROR,
	LSH CH,27
	IOR CH,[.STATUS CH]
	XCT CH		;READ THE ERROR CODE,
	LDB CH,[220600,,CH]
OPNER4:	SAVE CH		;ENTER HERE WITH ERRCODE IN RH(CH), TO PRETEND I.T.S GAVE AN ERROR.
	HRLZS (P)
	MOVEI C,70.	;WRITE A STRING CONTAINING FILENAMES AND I.T.S. ERROR MESSAGE.
	CALL QOPEN	;MAKE SURE ENOUGH SPACE, SET UP BP AND LISTF5 TO STORE INTO STRING.
	MOVSI E,'OPN
	CALL SIXNTY	;FIRST IN THE STRING GOES "OPN" FOLLOWED BY 3-DIGIT ERROR CODE.
	LDB CH,[.BP (700),(P)]
	CALL DGPT
	LDB CH,[.BP (70),(P)]
	CALL DGPT
	LDB CH,[.BP (7),(P)]
	CALL DGPT
	MOVEI CH,40
   REPEAT 2,XCT LISTF5	;THEN 2 SPACES.
	MOVE A,[440700,,DEFFIL]
	CALL ASCIND	;THEN THE FILENAMES.
	MOVEI CH,40
   REPEAT 3,XCT LISTF5	;3 SPACES.
	REST E
	SYSCAL OPEN,[%CLIMM,,CHERRI ? ['ERR,,] ? %CLIMM,,3 ? E]
	 JRST .-1
OPNER2:	.IOT CHERRI,CH	;COPY INTO STRING, STOPPING AT CRLF OR FF.
	CAIE CH,^M
	 CAIN CH,^L
	  JRST [.CLOSE CHERRI,
		JRST OPNER3]
	XCT LISTF5
	JRST OPNER2
]

IFN TNX,[
OPNER0:	SKIPE A,OPNJFN
	 RLJFN
	 JFCL
	SETZM OPNJFN
OPNER1:	TRZA FF,FRNOT	;PRINT DEFAULTS IN ERROR MESSAGE
OPNER2:	 TRO FF,FRNOT
	MOVEI A,.FHSLF	;GET THIS FORKS LAST JSYS ERROR MESSAGE
IFN 10X\FNX,[MOVE C,[4,,BAKTAB+4]
	BLT C,BAKTAB+10	;GETER ON TENEX SMASHES 4-10
]
	GETER
IFN 10X\FNX,[MOVS C,[4,,BAKTAB+4]
	BLT C,10
]
	CAIA
OPNER4:	TRZ FF,FRNOT	;PRINT ERROR MESSAGE
OPNER6:	PUSH P,2	;ENTER HERE TO FAKE ERROR FROM 2
	MOVEI C,70.	;MAKE ENOUGH STRING SPACE
	CALL QOPEN
	MOVSI E,'OPN	;INSERT OPN
	CALL SIXNTY
	POP P,2
	LDB CH,[110300,,2]
	CALL DGPT
	LDB CH,[060300,,2]
	CALL DGPT
	LDB CH,[030300,,2]
	CALL DGPT
	LDB CH,[000300,,2]
	CALL DGPT
	MOVEI CH,40	;AND TWO SPACES
   REPEAT 2,XCT LISTF5
	TRZE FF,FRNOT	;PRINT FILENAME DEFAULTS?
	 JRST OPNER5
	MOVEI E,DEFDEV
	CALL FSDFR1	;INSERT DEFAULTS
	MOVEI CH,40
   REPEAT 3,XCT LISTF5
OPNER5:	MOVE A,[440700,,BAKTAB]
	SETZ C,
	ERSTR
	 JFCL
	 JFCL
IFN 10X\FNX,IDPB C,A	;STUPID 10X JSYS DOESNT MAKE ASCIZ
	MOVEI A,BAKTAB
	CALL ASCIND	;AND INSERT IT TOO
]
OPNER3:	CALL QCLOSV	;NOW FINISH THE STRING'S HEADER, AND RETURN POINTER IN A.
	MOVEM A,LASTER	;REMEMBER IT AS THE MOST RECENT ERROR'S CODE.
	JRST DISTOE	;NOW GET CAUGHT BY ERRSET INVOKE ERROR HANDLER.

;TYPR4 UUO (TYPRE MACRO) COMES HERE.
ETYP2A:	HRRZ CH,@40	;ERROR, AND IT CAN BE HANDLED NORMALLY; GET THE ERROR CODE.
	HRLI CH,400000
	MOVEM CH,LASTER	;REMEMBER AS CODE OF MOST RECENT ERROR.
	JRST DISTOE	;GET CAUGHT BY ERRSET OR POP.

IMMQIT:	SETOM IMQUIT	;ALLOW QUITS TO HAPPEN AT ANY TIME,
	SKIPL STOPF	;AND QUIT IF ALREADY PENDING.
	 RET
QUIT0:	;CALL HERE IF STOPF IS SET, WHEN IT IS ACCEPTABLE TO QUIT.
QUIT1:	SETZM ORESET	;RE-ALLOW TYPEOUT NOW THAT WE GOT THRU WITH THE COMMAND
	SKIPLE NOQUIT
	 SKIPLE IMQUIT
	  CAIA		;NOQUIT POSITIVE => NO QUITTING AT ALL (UNLESS IMQUIT OVERRIDES)
	   RET
	SETZM STOPF	;ELSE QUIT, AND CLEAR FLAG SAYING WE NEED TO QUIT.
IFN 20X,[MOVEI A,.TICTI	;UNARM ANY INPUT INTERRUPT
	DTI
]
	CALL DISRST	;THROW AWAY ANYTHING IN DISBUF.
	SKIPG IMQUIT	;IMQUIT POSITIVE ONLY AT STARTUP AND IN COMMAND READER
	 SKIPN NOQUIT	;IF QUITTING SHOULD GO TO TOP LEVEL, DO SO.
	  CAIA
	   TYPRE [QIT]	;NOQUIT NEGATIVE WANTS TO SIGNAL AN ERROR.
	CIS		;CLEAR ANY INTERRUPTS IN PROGRESS.
	SETOM RROVPO
	CALL TYPBEL
	SETZM ECHACT
	MOVEI CH,"^
	CALL ECHOC1
	MOVEI CH,"G
	CALL ECHOC1
	JRST GOX1

DELQIT:	SETZM IMQUIT	;STOP ALLOWING QUITS INSIDE COMMANDS, AND EXIT.
	RET

;CALL HERE TO SIGNAL AN ERROR, AFTER SETTING LASTER.
;DISTOE RETURNS TO AN ERRSET IF THERE IS ONE;  OTHERWISE, IT GOES TO
;GOX1 TO ENTER A BREAK LOOP, INVOKE THE ERROR HANDLER, OR POP TO ^R OR TOP LVL.
DISTOE:	MOVE Q,PT	;ERROR CHECK: IS PT OUT OF BUFFER BOUNDS?
	CAMG Q,ZV
	 CAMGE Q,BEGV
	  .VALUE
	TRNN P,-1
	 .VALUE
	HRRZ Q,ER$UJC
	HRLI Q,400000	;IF UJC ERROR, STOP REPLAYING THE JOURNAL FILE.
	MOVEI E,JRNIN
	TRO FF,FRCLN
	CAMN Q,LASTER
	 CALL FSJRNX
	CIS
	SKIPL ERRFLG	;WERE WE ALREADY INVOLVED IN STARTING TO HANDLE AN ERROR?
	 JRST DISTOW
	MOVE CH,[-LPDL,,PDL-1]
	CAME CH,P	;YES; GIVE UP TRYING TO RECOVER AND POP ALL THE WAY UP,
	 PUSHJ CH,SETP	;SINCE TRYING TO HANDLE THIS ERROR NORMALLY WILL PROBABLY
			;CAUSE ANOTHER ERROR.
	SETZM ERRFL1	;PREVENT TYPEOUT OF THE MESSAGE FROM BEING SUPPRESSED.
	CALL DISTOT
	MOVEI CH,TYOA
	HRRM CH,LISTF5	;NOT CAUGHT BY ERRSET, PREPARE FOR TYPEOUT.
	MOVEI A,[ASCIZ/ERROR WHILE ENTERING ERROR HANDLER! POPPING TO TOP LEVEL.
/]
	CALL ASCIND
	CALL ERESET
	JRST CTLW

DISTOW:	SETOM ERRFLG
	CALL ERESET
	HLRZ Q,ITRPTR
	JUMPE Q,GOX1	;IF WITHIN AN ERRSET
	MOVE CH,MFMACP-MFBLEN+1(Q)
	TLNE CH,MFERS1	;WHICH IS NOT REALLY AN ERROR CATCH (:@< ... >),
	 JRST GOX1
	HLRZ CH,MFPF-MFBLEN+1(Q)
	HRRZ A,DISPRR	;AND WHICH HAS NO ^R INSIDE IT
	SKIPE A
	 CAIG A,(CH)
	  JRST ERRP3	;THEN THROW TO THE ERRSET.
	JRST GOX1	;ELSE GIVE TO THE ^R OR TO ERROR HANDLER.

;COME WHEN ERROR IS CAUGHT BY ERRSET.
ERRP3:	CALL UNWIND	;POP SOME STUFF OF MACRO PDL, ETC.
	 JRST ERRP4	;DOESN'T SKIP IF HAVE FINISHED UNWINDING; CH = RH(ITRPTR)
	 JRST ERRP3	;SKIPS 1 AFTER POPPING MACRO CALLED BY "M" CMD.
	MOVE CH,MACXP
	POP CH,MACXP
	POP CH,MACPTR
	PUSHJ CH,SETP	;SKIPS 2 AFTER POPPING A MACXQ OR MACXCW.
	JRST ERRP3

ERRP4:	HRROI Q,MFCSTR-MFBLEN+1(CH)
	POP Q,CSTR	;POSITION AT THE FRONT OF THE ERRSET
	POP Q,CPTR
	POP Q,COMCNT
	JRST INCMA0	;THEN SEARCH FOR THE >.

;CLEAN UP WHEN ERROR OR QUIT HAPPENS, IN CASE VARIABLES WERE SCREWED.
;THIS STUFF DONE REGARDLESS OF WHETHER ERROR WAS CAUGHT BY ERRSET.
ERESET:	SKIPE GCPTR	;ERROR IN GC: WE MAY HAVE BEEN USING THE PAGE JUST BELOW LIBRARIES.
	 CALL FLSCOR	;IF SO, MAKE SURE WE FLUSH IT.
IFN ITS,CALL SEQPGQ	;TURN OFF SEQUENTIAL PAGING, IF IT IS ON.
	SETZM GCPTR
	SETOM INSBP
	SETZM DISFLF
	SETZM IMQUIT
	SETZM INSINP
	SETZM INSBP
	SETZM TRCOUT
	SETZM BRC1
	SETZM SLPNCR
IFN ITS,.CLOSE CHRAND,	;IN CASE WE QUIT OUT OF READING FILE DIR.
	MOVE A,QRB..	;MAKE SURE BFRPTR AND BFRSTR AGREE WITH ..O.
	MOVE C,.QBUFR(A)	;A PDL OVERFLOW IN CERTAIN PLACES CAN CONFUSE THEM.
	JRST BFRSET

;FS ERR THROW - THROW TO INNERMOST ERROR-CATCHING COMMAND LOOP.
;IT CAN BE EITHER A TECO COMMAND LOOP, A ^R, OR AN ERROR CATCH (:@< ... >).
FSERTH:	HLRZ Q,ITRPTR
FSERT0:	JUMPE Q,FSERT1	;IF WITHIN AN ERRSET
	MOVE CH,MFMACP-MFBLEN+1(Q)
	TLNE CH,MFERS1	;WHICH IS REALLY AN ERROR CATCH (:@< ... >),
	 JRST FSERT2	;THEN MAYBE THROW TO IT.
	HLRZ Q,(Q)	;IF INNERMOST ERRSET ISN'T AN ERROR CATCH,
	JRST FSERT0	;MAYBE THE NEXT ERRSET OUT IS ONE.

FSERT2:	HLRZ CH,MFPF-MFBLEN+1(Q)
	HRRZ A,DISPRR	;FOUND AN ERROR CATCH; USE IT ONLY IF NO ^R WITHIN IT.
	SKIPE A
	 CAIG A,(CH)
	  JRST  [	;THEN THROW TO THE ERROR CATCH.
		MOVEM C,LASTER	;MAKE IT RETURN FS ERR THROW'S ARG.
		SETOM ERRFLG
		JRST FSERT3]
FSERT1:	SKIPN A,DISPRR	;OTHERWISE, IF INSIDE A ^R, RETURN TO THAT ^R.
	 JRST GO
	TRZ FF,FRARG+FRARG2
	SKIPE MACXP
	 CAML A,MACXP	;IF DON'T WANT A BREAK LOOP AND INSIDE A ^R, RETURN TO THAT ^R.
	  JRST [SETZM RREBEG
		JRST RRTHRW]	;HOW TO DO IT DEPENDS ON WHETHER WE CALLED ANY MACROS FROM IT.
	JRST FSCRTH

;THROW TO THE INNERMOST ERROR CATCH (WE ALREADY CHECKED THAT THERE IS ONE).
FSERT3:	CALL UNWIND	;POP SOME STUFF OF MACRO PDL, ETC.
	 JRST FSERT4	;NO SKIP IF HAVE REACHED ERRSET OR ERROR CATCH; CH = RH(ITRPTR)
	 JRST FSERT3	;SKIPS 1 AFTER POPPING MACRO CALLED BY "M" CMD.
	MOVE CH,MACXP
	POP CH,MACXP
	POP CH,MACPTR
	PUSHJ CH,SETP	;SKIPS 2 AFTER POPPING A MACXQ OR MACXCW.
	JRST FSERT3

FSERT4:	MOVE Q,MFMACP-MFBLEN+1(CH)
	TLNN Q,MFERS1	;IF THIS IS A RANDOM ERRSET, NOT AN ERROR CATCH, KEEP UNWINDING.
	 JRST [	CALL ITRPOP
		JRST FSERT3]
	HRROI Q,MFCSTR-MFBLEN+1(CH)
	POP Q,CSTR	;POSITION AT THE FRONT OF THE ERRSET
	POP Q,CPTR
	POP Q,COMCNT
	JRST INCMA0	;THEN SEARCH FOR THE >.

;TRY TO UNWIND MACRO PDL AND ITERATIONS UNTIL REACH INNERMOST ERRSET.
;DON'T SKIP IF REACH THERE. SKIP 1 IF POP AN ORDINARY MACR (IN WHICH CASE
;UNWINDING ISN'T FINISHED). SKIP 2 AFTER POPPING A MACRO CALLED
;BY A MACXQ.
UNWIND:	HRRO A,ITRPTR	;FIND INNERMOST ERRSET OR ITERATION,
	SKIPN ITRPTR	;[ ;IF NO ITERATION, POP ANY MACRO OR ^]^X.
	 SKIPA CH,[400,,MACPDL-1]
	 MOVE CH,MFMACP-MFBLEN+1(A)
	TLZ CH,40
	CAMN CH,MACPDP	;[ ;ANY MACRO OR ^]^X CALLS INSIDE IT => POP THEM.
	 JRST UNWINI	;ELSE HANDLE THE ERRSET OR ITERATION.
UNWINM:	LDB CH,MACPDP	;[ ;IS IT A MACRO? OR A ^]^X?
	CAIN CH,10
	 JRST UNWIN2	;IT'S A NULL, THROW IT AWAY.
	TRNE CH,10
	 JRST UNWIN1	;[ ;IT'S A ^]^X.
	SKIPN MACPTR
	 .VALUE		;MACPDP AND MACPTR OUT OF PHASE??
	CALL DECDCH	;IT'S A MACRO CALL, RESTORE SQUOTP, ETC.
	CALL POPMAC	;POP STRING PTR, ETC.
	AOS (P)		;SKIP 1 OR 2 DEPENDING.
	SKIPGE MACPTR
	 AOS (P)
	JRST POPMP

UNWIN1:	CALL DECDCH	;[ ;POP A ^]^X.
	CALL POPCTX
	CALL PUSMAC
UNWIN2:	CALL POPMP
	JRST UNWIND

UNWINI:	SKIPN ITRPTR	;TRYING TO UNWIND WHEN NO ITERATION OR MACRO =>
	 .VALUE		;UNWIND'S CALLER'S END TEST FAILED.
	HLRZ CH,ITRPTR	;IS THIS AN ERRSET OR AN ITERATION?
	CAIN CH,(A)
	 RET		;REACHED AN ERRSET.
	CALL ITRPOP	;AN ITERATION - POP IT
	JRST UNWIND	;AND LOOK AT THE NEXT ONE OUT.

;FS ^R EXIT - WITHIN A MACRO CALLED FROM ^R, RETURN FROM THE ^R.
;FS ^R THROW - WITHIN A MACRO CALLED FROM ^R, RETURN TO ^R.
FSCREX:	SKIPA Q,[FSCRE1,,MEXIT1]
FSCRTH:	 MOVE Q,[FSCRT1,,MEXIT1]
	SKIPN DISPRR	;NOT INSIDE ^R => ERROR.
	 TYPRE [N%R]
	JRST MEXIT1

;FS BACK RETURN$: RETURN TO A SPECIFIED FRAME (SPECIFIED A LA FS BACK ARGS$).
FSBKRT:	CALL BACKTR		;A GETS A POINTER TO THE FRAME TO RETURN TO.
	MOVE Q,[FSBKR2,,FSBKR1]
	SOS A			;REMEMBER ADDR OF FRAME (MINUS 1,
	MOVEM A,BKRTLV		; AS IT WILL BE WHEN ON THE FREELIST).
	JRST MEXIT1

FSBKR1:	SKIPA B,[CD]		;AFTER POPPING A MACRO FRAME, B GETS HOW TO RETURN
FSBKR2:	 MOVEI B,CPOPJ		;TO THAT FRAME, DEPENDING ON WHETHER IT WAS A MACXQ.
	MOVE A,BKRTLV
	CAME A,MFFREE		;IF THE FRAME JUST POPPED INTO AND FREED WAS THE RIGHT ONE,
	 JRST MEXIT1		;RETURN TO IT.  ELSE, KEEP POPPING.
	JRST (B)

;^\ - IN A MACRO, RETURN FROM IT, POPPING QREGS AND ITERATIONS.
;:^\ DOESN'T POP QREGS.
MEXIT:	SKIPN MACPTR
	 TYPRE [NIM]	;"EXIT MACRO" IF NOT INSIDE ONE?
	MOVE Q,[CPOPJ,,CD5A]
;RH(Q) HAS WHERE TO GO AFTER POPPING A MACRO CALLED BY "M".
;LH(Q) HAS WHERE TO GO AFTER POPPING A MACXQ.
MEXIT1:	MOVE C,MACSPF	;PLACE TO POP TO.
	TRZN FF,FRCLN	;POP THE QREG PDL UNLESS :^\.
	 JRST [	SAVE Q
		CALL FSQPU0
		REST Q
		JRST .+1]
MEXIT2:	CALL UNWIND	;POP A MACRO OR ITERATION.
	 JRST [	CALL ITRPOP	;HERE IF ENCOUNTER AN ERRSET.
		JRST MEXIT2]
	  JRST (Q)	;POPPED AN ORDINARY MACRO.
	MOVE CH,MACXP	;POPPED A MACRO CALLED BY A MACXQ.
	POP CH,MACXP
	POP CH,MACPTR
	PUSHJ CH,SETP	;SET P FROM CH, UNWIND STUFF, THEN POPJ P,
	HLRZ CH,Q
	JRST (CH)

FSCRE1:	SKIPA C,[RREXI0]
FSCRT1:	 MOVEI C,RRTHRW
	SKIPE A,MACXP	;WE HAVE JUST POPPED THE MACRO CALLED FROM ^R, IF
	 CAMG A,DISPRR	;THE NEXT POSSIBLE CANDIDATE MACRO FRAME
	  JRST (C)	;IS TOO FAR OUT ON THE CONTROL STACK.
	JRST MEXIT1	;NO, POP THE INNERMOST MACRO AGAIN.

SUBTTL QUIT/ERROR REINITIALIZATION

;COME HERE ON INITIALIZATION, QUIT, AND ^W COMMAND.
CTLW:	SETOM GOXFLS	;POP TO TOP LEVEL; DON'T INVOKE ERROR HANDLER OR MAKE BREAK LOOP

;COME HERE ON ERROR.
;IMQUIT IS POSITIVE IF WE QUIT OUT OF LIS (TECO COMMAND READER). IT MEANS
  ;WE SHOULD STAY IN THE COMMAND LEVEL THAT WAS CALLING LIS.
;OTHERWISE, IF $QERRH (Q..P) IS NONZERO, IT IS THE ERROR HANDLER MACRO TO CALL.
;OTHERWISE, IF UNWINF (FS*RSET$) IS NONZERO, CREATE A BREAK LOOP.
GOX1:	SKIPN CH,LEV	;COMPUTE THE PDL LEVEL AT THE INNERMOST
	 MOVE CH,[-LPDL,,PDL-1]
	SKIPN Q,MACXP	;INVOCATION OF THE COMMAND LOOP OR ^R.
	 MOVE Q,[-LPDL,,PDL-1]
	CAMGE CH,Q	;NAMELY, MUST BE INSIDE ALL OPEN-PARENS,
	 MOVE CH,Q	;INSIDE ALL MACXQ'S, ABOVE BOTTOM OF STACK,
	SKIPN Q,DISPRR	;AND ABOVE DISPRR.
	 MOVE Q,[-LPDL,,PDL-1]
	CAMGE CH,Q
	 MOVE CH,Q
	SKIPGE GOXFLS	;MAYBE WE HAVE BEEN RQ'D TO POP ALL THE WAY TO TOP.
	 MOVE CH,[-LPDL,,PDL-1]
	CAME P,CH	;MUSTN'T PUSHJ CH, IF CH=P, SINCE RET. ADDR WOULD BE UNPROTECTED
	 PUSHJ CH,SETP	;SET P FROM CH, UNWINDING SOME STUFF; THEN POPJ P,
	SKIPL TYOFLG		;IF TYPEOUT IN PROGRESS, FORCE IT OUT.
	 CALL DISFLS
	SETZM CTLCF
	SKIPE CPTR
	 CALL ERRP2		;MARK THE CURRENT PC FOR "?" TO DISPLAY.
	MOVE C,IMQUIT
	SETZM IMQUIT
	MOVE TT,BEG
	SKIPN E,RREBEG		;MUSTN'T RUN OUTSIDE ^R WITH RREBEG ZERO.
	 MOVEM TT,RREBEG
	SKIPL ERRFLG
	 SETZM LASTER		;IF NO ERROR, MAKE SURE FS ERROR IS 0.
	HRRZM P,ERRFL1		;AS YET, NO ERROR MESSAGE PRINTED (THOUGH MAY CHANGE)
	SKIPN GOXFLS	;IF WE'RE POPPING TO TOP, DON'T PUSH NOW.
	 SKIPLE C	;IF THIS IS TECO STARTUP, OR QUIT OUT OF COMMAND READER,
	  JRST GOX4	;THERE'S REALLY NOTHING TO PUSH NOW.
	SKIPN UNWINF	;ENTER BREAK LOOP?
	 SKIPE $QERRH	;OR HAVE AN ERROR HANDLER?
	  CAIA
	   JRST GOX4	;NEITHER; NO NEED TO PUSH.
	JUMPN E,GOX5	;IF ERROR OCCURRED ACTUALLY INSIDE ^R (NOT WITHIN A MACRO)
	SAVE [[	MOVE P,DISPRR
		REST A
		JRST RRLP]]	;THEN SIMULATE A MACXQ CALL WHICH, WHEN RETURNED FROM, WILL
	SAVE MACPTR		;RETURN TO ^R.
	SAVE MACXP
	SETOM MACPTR
	MOVEM P,MACXP
GOX5:	JSP T,OPEN1	;NOW PUSH VALUES
	CALL PUSMAC	;AND THE CURRENT MACRO (THAT ERRED).
	CALL FLGENC	;ENCODE AND SAVE SQUOTP AND RCHALT
	IDPB CH,MACPDP
	MOVE CH,PF	;REMEMBER THE QREG PDL LEVEL ON ENTRY TO THE ERROR HANDLER.
	MOVEM CH,MACSPF
	SETZM SQUOTP
	CALL GOCPY	;IF CBUF IS ON MACRO PDL, COPY IT TO A STRING
			 ;SINCE CBUF IS LIKELY TO BE OVERWRITTEN NOW.
	SKIPE A,$QERRH	;IF THE USER HAS AN ERROR HANDLER, GO TO IT.
	 JRST [	TRO FF,FRCLN	;WE ALREADY PUSHED THE ERRING MACRO; NO NEED TO PUSH AGAIN.
		SETZM ERRFLG	;ERROR PROCESSING NOW FINISHED.
		JRST MAC5]	;NOW RUN THE ERROR HANDLER.
GOX4:	TRO FF,FRARG\FRCLN\FRUPRW
	SKIPGE GOXFLS	;GOXFLS AND ERRFLG IMPLY THIS IS "ERROR ENTERING ERROR HANDLER"
	 TRZ FF,FRCLN	;SO DON'T OVERWRITE THAT LINE WITH THE ERROR MSG.
	SKIPE C,LASTER	;NO USER ERROR-HANDLER, SO IF RESPONDING TO AN ERROR,
	 CALL FGCMD	;PRINT STANDARD ERROR MESSAGE, FLUSH TYPEAHEAD, AND TYPE A BELL.
	SETOM UNRCHC	;IF WE ARE ^G-QUITTING BACK TO TECO CMD LOOP, FLUSH THE ^G.
	SETZM TYISRC
	SETZM TYISNK
	SETOM TYOFLG	;FORCE TYPEOUT TO RE-INIT.
	SKIPN RGETTY
	 CALL CRR
	SETZM ERRFLG		;ERROR PROCESSING NOW FINISHED.
	SKIPN GOXFLS		;IF POPPING ALL TEH WAY OUT, ENTER A TECO COMMAND LOOP.
	 SKIPE UNWINF		;IF *RSET IS ON, ENTER A TECO COMMAND LOOP.
	  JRST GO
	JRST FSERTH		;OTHERWISE EXIT TO INNERMOST ^R OR ERROR CATCH.

;ALTMODE AS COMMAND.
ALTCMD:	SKIPGE NOOPAL	;FS NOOPALT NEGATIVE => IGNORE ALTMODE.
	 JRST CD5
	SKIPN NOOPAL	;POSITIVE => ALTMODE IS LIKE ^_.
	 TYPRE [DCD]	;ERROR IN MACROS, IGNORE AT TOP LEVEL.
LGOGO:
		;COME HERE WHEN EXECUTE ^_, PERHAPS ALTMODE.
	CALL FLSOUT	;EMPTY OUTPUT BUFFER INTO OUTPUT FILE.
IFN ITS,[
	.SUSET [.RJNAM,,A]
	CAME A,['HACTRN]
	 .LOGOUT
]
	AOSN CTLCF	;IF READ ^C,
	 CALL FSEXI1	;RETURN TO DDT.
	HRRZM P,ERRFL1
GO:	MOVE A,GOXFLS	;IF WE'RE REQUESTED TO POP ALL THE WAY
	SETZM GOXFLS
	SKIPE UNWINF	;OR NOT IN *RSET MODE,
	 JUMPGE A,GO2
	MOVE CH,[-LPDL,,PDL-1]
	CAME CH,P
	 PUSHJ CH,SETP	;SET P FROM CH, UNWINDING OUT OF ^R OR SORT OR PARENS.
	SETZM MACXP
	SETZM NOQUIT
	SETZM MACPTR
	SETZM MACDEP
	SETZM CTXPTR
	SETZM ITRPTR
	MOVE A,[400,,MACPDL-1]
	MOVEM A,MACPDP
	MOVEI A,MFSTRT-1	;NOW PUT ALL CELLS ON THE FREE LIST.
	SETZM MFFREE
	MOVE B,MFEND
GO1:	SKIPL MFBEG+1(A) .SEE MFBFR	;FREE ALL MACRO FRAMES, EXCEPT THOSE OF BUFFERS.
	 CALL FLSFRM	;FREE IT.
	ADDI A,MFBLEN
	CAIGE A,-1(B)
	 JRST GO1
	MOVE C,PFINI	;UNWIND QREG PDL.
	CALL FSQPU0
GO2:	MOVEI A,(JFCL)
	HRLM A,RCHALT
	SETZM SQUOTP
	SETZM MACBTS	;THERE ARE NO MACRO ARGS IN TOP-LEVEL CMD STRING.
	CALL FLSCM1	;FLUSH SOME CORE, AND FORCE OUT OUTPUT BUFFER.
	SKIPL TYOFLG	;FORCE ALL TYPEOUT TO BE PRINTED.
	 CALL DISFLS
	SETZM IMQUIT
	SKIPN ECHOFL
	 CALL SETTTM	;TURN ECHOING BACK ON IF NECESSARY.
	SKIPE MORFLF	;IF PREVIOUS COMMAND FLUSHED,
	 SETOM TYOFLG	;NEXT TYPEOUT WILL REINIT AND UN-FLUSH.
	SETZM MORFLF
	MOVE C,QRB..
	MOVE C,.QPT1(C)	;GET WHAT . WAS WHEN LAST CMD STRING STARTED.
	CALL FSPSPT	;PUSH ON . RING BUFFER.
	MOVE CH,QRB..	;MACRO ..L IF THAT'S APPROPRIATE.
	MOVE A,.QRSTR(CH)
	AOSN INITF1
	 JUMPN A,GOXX
	CALL VIEW2	;NOW GO TRY TO DISPLAY DIR. OR BUFFER.
	JRST LIS

GOXX:	TRO FF,FRCLN	;DO A :M TO ..L, MAKING IT THE TOP LEVEL MACRO FRAME
	JRST MAC5	;LEAVING MACPDL EMPTY.

;FIND THE MACRO FRAME THAT IS EXECUTING OUT OF CBUF, COPY THE CONTENTS
;OF CBUF INTO A STRING, AND MAKE THE MACRO FRAME POINT TO THAT STRING INSTEAD.
;THE GOAL IS TO FREE UP CBUF FOR RE-USE WHEN COMMAND READER IS ENTERED
;IN A BREAK LOOP.
;DOESN'T PROMISE TO RPESERVE ANY ACS.
GOCPY:	MOVEI A,MFSTRT
GOCPY1:	SKIPGE MFBEG(A)	.SEE MFBFR	;DONT CONSIDER BUFFER FRAMES.
	 JRST GOCPY2
	HRRZ C,MFCPTR(A)	;WHERE DOES B.P. OF MACRO FRAME POINT?
	JUMPE C,GOCPY2		;IGNORE FREE CELLS; THERE MAY BE SOME -> CBUF.
	CAIL C,@CBUFLO
	 CAIL C,@CBUFH
	  JRST GOCPY2
	JRST GOCPY3		;CPTR OF THIS FRAME POINTS WITHIN CBUF!

GOCPY2:	ADDI A,MFBLEN
	CAMGE A,MFEND		;SCAN ALL FRAMES.
	 JRST GOCPY1
	RET			;NO FRAME POINTS IN CBUF - NO COPYING NEED BE DONE.

GOCPY3:	HRRZ E,CBMAX		;HOW LONG IS USED PART OF CBUF?
	MOVEI C,4(E)		;GET THAT MUCH SPACE, PLUS SOME FOR STRING HEADER
	CALL SLPQGT
	MOVEI B,QRSTR
	MOVEI C,4(E)
	CALL QHDRW1		;WRITE HEADER OF STRING; B.P. RETURNED IN BP TO IDPB TEXT.
	MOVE C,E
	MOVE IN,CBUFLO		;AND GET B.P. TO ILDB TEXT TO COPY.
GOCPY4:	ILDB CH,IN
	IDPB CH,BP
	SOJG C,GOCPY4
	MOVE BP,QRWRT
	SUB BP,QRBUF
	TLO BP,400000
	MOVEM BP,MFCSTR(A)	;STORE STRING POINTER TO NEWLY CONSTRUCTED STRING IN MACRO FRAME.
	MOVEI BP,4(E)
	ADDB BP,QRWRT		;CLOSE THE FINISHED STRING; ET CHAR ADDR 1 + LAST CHAR.
	SUB BP,MFCCNT(A)		;GET NEW CHAR ADDR OF CHAR CPTR SHOULD ILDB NEXT
	CALL GETIBP		;AND SET UP CPTR -> SAME CHARACTER IN ITS NEW HOME.
	MOVEM BP,MFCPTR(A)
	RET

SUBTTL F? COMMAND

;F? COMMAND - MBOX CONTROL.
;ARGUMENT IS BIT-DECODED. NO ARG, OR ARG=0, IMPLIES ARG=30 .
;BIT 1.1 - CLOSE GAP. MAY BE NEEDED FOR COMMUNICATION WITH OTHER PROGRAMS
;		THAT DON'T UNDERSTAND THE GAP.
;BIT 1.2 - GC STRING SPACE. USEFUL BEFORE DUMPING OUT OR IF IT IS SUSPECTED
;		MANY STRINGS HAVE RECENTLY BEEN DISCARDED.
;BIT 1.3 - SWEEP THE JUMP CACHE. NECESSARY IF A STRING'S CONTENTS HAVE BEEN
;		ALTERED BY THE F^E COMMAND, AND IT IS A MACRO THAT MIGHT
;		HAVE CONTAINED "O" COMMANDS.
;BIT 1.4 - FLUSH UNOCCUPIED CORE. GOOD TO DO EVERY SO OFTEN, OR IF IT IS
;		LIKELY THE BUFFER HAS JUST SHRUNK.
;BIT 1.5 - CLOSE THE GAP, IF IT IS > 5000 CHARACTERS. GOOD TO DO EVERY SO
;		OFTEN, IN CASE USER DELETES LARGE AMOUNTS OF TEXT; SAY,
;		WHENEVER EXCESS CORE IS FLUSHED.
FLSCMD:	ARGDFL
	SKIPE C
	 TRNN FF,FRARG	;NO ARG SAME AS ARG OF 30.
FLSCM1:	  MOVEI C,30
	HRLM C,(P)
	CALL FLSOUT	;FIRST, FORCE OUT OUTPOUT BUFFER.
	HLRZ C,(P)
	MOVE A,EXTRAC
	TRNE C,20
	CAIG A,5000	;"20" BIT MEANS CLOSE GAP IF VERY LARGE.
	 TRNE C,1	;"1" BIT MEANS CLOSE GAP IN ANY CASE.
	  CALL SLPSHT
	TRNE C,2	;IF "2" BIT IS SET IN ARG, DO A GC,
	 JRST GCC	;THAT INCLUDES FLUSHING CORE AND SWEEPING CACHE.
	TRNN C,4	;"4" BIT MEANS SWEEP JUMP CACHE.
	 JRST FLSCM2
	CLEARM STABP
	MOVE T,[STABP,,STABP+1]
	BLT T,SYMEND-1
FLSCM2:	TRNN C,10	;"10" BIT MEANS FLUSH UNUSED CORE.
	 RET
FLSCOR:	SAVE A
	SAVE B
	SAVE C
	MOVE A,BFRTOP	;OTHERWISE JUST FLUSH CORE.
	CAMN A,BFRBOT	;DON'T FLUSH ALL PAGES, ELSE THE
	 ADDI A,1	;GAP BETWEEN IMPURE STRINGS AND BUFFER WOULD FILL UP.
	ADDI A,2000*5-1
	IDIVI A,5*2000	;A_ # PAGES WE'RE REALLY USING.
	MOVE C,MEMT	;C_ # OF LAST PAGE WE HAVE.
	SUBM A,C	;C HAS -<# PAGES TO FLUSH>
	JUMPE C,POPCBA
	MOVE J,A
IFN ITS,[
	HRLM C,A	;A HAS AOBJN -> PAGES TO BE FLUSHED.
	SKIPGE A	;WE'RE TRYING TO CORE UP???
	 SYSCAL CORBLK,[%CLIMM,,0 ? %CLIMM,,%JSELF ? A]
	  .VALUE
]
IFN TNX,[
	MOVEI B,(A)	;FIRST BLOCK TO DO
	ASH B,1		;MAKE A PAGE NUMBER
	HRLI B,.FHSLF
	SETO A,		;SAY UNMAP
	ASH C,1
IFN 20X,[MOVM C,C	;NUMBER OF PAGES
	HRLI C,(PM%CNT)
	PMAP		;UNMAP THEM
]
.ELSE [	PMAP		;TENEX -- NO MULTIPLE PMAPS
	AOJGE C,.+2
	AOJA B,.-2
]]
	MOVEM J,MEMT	;UPDATE # OF FIRST K OF NXM.
	CAML J,LHIPAG	;WE SHOULD HAVE A 1K GAP BETWEEN BUFFER SPACE AND LIBRARIES.
	 .VALUE
	JRST POPCBA

SUBTTL TECO COMMAND STRING READER

LISCRF:	CALL ECHOCR
LIS:	HRRZM P,IMQUIT	;^G DURING TYPEIN QUITS IMMEDIATELY.
	SETZM NOQUIT
	SKIPGE STOPF	;PERFORM ANY PENDING QUIT.
	 CALL QUIT0
	SKIPN ECHOFL
	 CALL SETTTM	;MAKE SURE ECHOING IS ON.
	SETZM RCHSFF
	.I CASE=CASNRM	;REINIT THE INPUT CASE.
	TTYACT		;TO SET "ACTIVATE ON NEXT CHAR REGARDLESS" AGAIN
	CALL VBDACU
	 JFCL
	SETZM CTLBRF
	MOVE C,QRB..
	SETZM .QVWFL(C)
	MOVE B,CBUFLO	;BP TO BEFORE CMD BUFF.
	MOVE TT,CBMAX	;WAS THE PREVIOUS CMD STRING A LONG ONE?
	CAIGE TT,10.
	 JRST LISSRT	;NO, IT WAS SHORT.
	MOVEM TT,SAVCMX	;YES, THIS IS CMD STRING FOR ^Y TO INSERT.
	MOVEI TT,SAVCW1-1 ;SO SAVE INFO ON IT SO SHORT CMDS
	PUSH TT,1(B)	;WON'T CLOBBER THE BEGINNING OF IT.
	PUSH TT,2(B)
	PUSH TT,3(B)
	.I SAVCPT=CPTR
LISSRT:	SETZM CBMAX	;CBMAX COUNTS CHARS IN CMD STRING BEING READ IN
	SETZM COMCNT
	MOVEM B,CPTR	;INIT CPTR FOR EXECUTION OF THE CMD STRING
	MOVEM B,CSTR
	MOVE C,CBUFH
			;HANDLE ":TECO FOO BAR" FROM DDT
	SKIPGE CMFLFL	;READING FROM INIT FILE => GO YANK AND XCT IT.
	 JRST LISINI
LI1:	SKIPE RGETTY	;IF NO DISPLAY,
	 JRST LILUP
	SKIPE CH,PROMCH	;PROMPT UNLESS PROMPTING DISABLED.
	 CALL TYANOW
;FALLS THROUGH TO READ THE FIRST CHARACTER.

;FALLS THROUGH.
;LOOP AFTER HANDLING A CHAR OTHER THAN ALTMODE.
LILUP:	TRZ FF,FRALT	;SAY THE PRECEDING CHAR WASN'T ALTMODE.
LI2:	MOVE C,CBUFH
	CAILE C,(B)	;LOOP BACK HERE AFTER ALTMODE, WITH FRALT SET.
	 JRST LI3
	ADDI C,100	;IF WE'VE FILLED THE COMMAND BUFFER, MAKE IT BIGGER.
	SAVE C
	MOVEI C,500	;MAKE SURE WHEN IMPURE STRING SPACE IS MOVED UP
	CALL SLPQGT	;IT WON'T REACH BUFFER SPACE.
	REST C
	MOVE E,QRWRT	;LAST WD TO MOVE UP IS LAST IN IMPURE STRING SPACE.
	IDIVI E,5
	MOVE J,QRBUF
	IDIVI J,5
	SUBM E,J
	MOVE CH,(E)
	MOVEM CH,100(E)
	SOS E
	SOJGE J,.-3
	MOVEI T,500
	ADDM T,QRBUF
	ADDM T,QRWRT
LI3:	MOVEM C,CBUFH
	SETZM CTLCF
	CALL TYI	;READ CHARACTER FROM TERMINAL.
	CALL TYINRM
	MOVEI TT,^J	;PRETEND THAT EVERY CR IS FOLLOWED BY A LF.
	CAIN CH,^M
	 MOVEM TT,UNRCHC
	SKIPL CTLBRF	;[ ;LET ^]^Q QUOTE A ^C
IFN ITS, CAIE CH,^C
IFN TNX, CAIE CH,^Z	;^C IMPLIES GO
	  JRST LI3Z
	SETOM CTLCF	;BACK TO DDT IF FINISH COMMAND STRING WITHOUT ERROR.
	JRST LISEOF	;IT ALSO TERMINATES THE COMMAND STRING.

LI3Z:	CAME B,CBUFLO	;IF THIS IS 1ST CHAR, SOME CHARS ARE SPECIAL.
	 JRST LI3D1	;NO, NORMAL.
	JRST LISFST

;COME HERE AFTER READING A CHAR, WHEN THE CMD BUFFER IS EMPTY.
LISFST:	CAIN CH,^R
	 JRST RRIMMD
IFN CTRLT,[
  	CAIN CH,^T
	 JRST EDIT
]
	CAIN CH,^U	;^U => DISPLAY FILE DIR USING USER'S MACRO.
	 JRST [	MOVE CH,QRB..
		SETZM .QVWFL(CH)
		TLO FF,FLDIRDPY
		SETZM IMQUIT
		JRST GO]
	CAIN CH,^V
	 JRST [ MOVE CH,QRB..
		SETZM .QVWFL(CH)	;ALLOW BUFFER DISPLAY.
		CALL POPPT		;POP . RING BUFFER.
		 JFCL
		MOVE CH,QRB..
		MOVEM A,.QPT1(CH)	;PREVENT AUTOMATIC RE-PUSH.
		JRST GO]
	CAIN CH,^X
	 SKIPN LASTER
	  CAIA
	   JRST [CALL FECMD8 ? JRST GO]
	CAIN CH,^Y
	 JRST LISCY
	TRNN FF,FRQMRK
	 JRST LI3D1
	CAIN CH,"?
	 JRST ERRTYP
LI3D1:	PUSHJ P,CKCH
	 JRST LISCRF	;RUBOUT ON AN EMPTY BUFFER.
	 JRST [SETZM CTLBRF ? JRST LILUP]	;A CHAR WAS RUBBED.
LISTOR:	AOS CBMAX
	IDPB CH,B
	AOSE CTLBRF	;[[ ;WAS THIS CHAR PRECEDED BY ^] OR ^]^Q?
	 JRST LISBR1	 ;NO.
	CAIN CH,^Q	;YES, ^Q=> NEXT CHAR ALSO QUOTED.
LISBRC:	 SETOM CTLBRF
	JRST LILUP	;[ ;QUOTED ^] AND ALTMODE AREN'T SPECIAL.

		;[[ BRACKETS MUST BALANCE FOR CONDITIONALS.
LISBR1:	CAIN CH,^]	;NOT QUOTED, ^] QUOTES NEXT CHAR.
	 JRST LISBRC
	CAIE CH,ALTMOD	;ALTMODE => CHECK FOR ALT-ALT, MAYBE END STRING.
	 JRST LILUP
	TRON FF,FRALT	;SAY JUST SAW AN ALTMODE,
	 JRST LI2
	JRST LISDUN	;PREV. CHAR ALSO ALTMODE => END STRING.

CKCH:	CAIE CH,177
	JRST POPJ2	;OK CHAR - RETURN, SKIPPING TWO
	CAMN B,CBUFLO
	POPJ P,		;RUBBED TO BEGINNING - NO SKIP
	LDB CH,B
	PUSHJ P,FSECOR
	DBP7 B
	SOS CBMAX
	JRST POPJ1	;RUBBED ONE CHAR -  RETURN, SKIPPING ONE

;COME HERE ON ^C ON TTY.
LISEOF:	MOVEI CH,ALTMOD	;DUMMY UP TWO ALTMODES.
	IDPB CH,B
	AOS CBMAX
	IDPB CH,B
	AOS CBMAX

;COME HERE AFTER HANDLING AND STORING ALTMODE-ALTMODE
LISDUN:	MOVEI CH,^_	;^_ TO STOP EXECUTION OF CMD STRING.
	IDPB CH,B
	AOS TT,CBMAX
	MOVEM TT,COMCNT

;INITIALIZE RANDOM STUFF FOR ANOTHER CMD STRING.
	SETZM IMQUIT
	SETZM ERRFLG	;DON'T IGNORE 1ST LINE OF NEXT V-COMMAND.
IFN TNX,SETZM ECHOP	;NOT IN ECHO AREA ANY MORE
	SKIPN RGETTY
	 PUSHJ P,CRR
	TRZ FF,#FRTRACE
	MOVE A,PT	;Q..I _ . .
	SUB A,BEG
	MOVE CH,QRB..
	SETZM .QVWFL(CH)	;ALLOW BUFFER DISPLAY.
	MOVEM A,.QPT1(CH)	;PUT . INTO Q..I.
	JRST CD

POPJ2:	AOS (P)
CPOPJ1:
POPJ1:
	AOS (P)
	POPJ P,

LISINI:	CALL RRED1	;INIT FILE OPEN ON CHFILI; PREPARE TO YANK IT.
	MOVE CH,QRB..
	SETZM .QVWFL(CH)	;ALLOW A BUFFER DISPLAY TO SHOW RESULTS.
	MOVEI A,[ASCIZ /@Y :M(HFX*)/]
	SETZM CMFLFL	;COMMAND FILE HAS BEEN HANDLED (ALMOST)
	SETZM IMQUIT
	CALL MACXCW	;XCT THAT STRING, TO YANK AND XCT THE INIT FILE.
	JRST GO

;CONTROL-Y WAS 1ST CHAR TYPED --
; INSERT LAST COMMAND STRING INTO BUFFER, THEN REDISPLAY.
LISCY:	MOVE CH,QRB..
	SETZM .QVWFL(CH)	;ALLOW A BUFFER DISPLAY TO SHOW RESULTS OF ^Y.
	SETOM SQUOTP	;[ ;DON'T LET ^] EXPAND WHEN WE REREAD CMD STRING.
	SETOM BRC1
	.I COMCNT=SAVCMX
	HRROI TT,SAVCW3	;RESTORE THE LAST LONG (>7 CHARS) CMD STRING
	POP TT,3(B)	;.I <3RD WD OF CMD BUFFER>=SAVCW3
	POP TT,2(B)
	POP TT,1(B)
	MOVE B,SAVCPT
	SETO OUT,

LISCY1:	CALL SKRCH	;READ CHAR FROM CMD STRING, DON'T TRACE.
	MOVE C,COMCNT	;IF WE'VE REACHED THE $$^_ AT THE END,
	CAIGE C,3	;DON'T PUT THE $ IN THE BUFFER.
	 JRST [JUMPL OUT,GO	;IF CMD STRING WASN'T ALL READ,
		MOVEM OUT,PT	;PUT PT AFTER LAST CHAR THAT WAS.
		JRST GO]
	CALL TYOMGS	;INSERT NEXT CHAR OF CMD STRING INTO BUFFER.
	CAMN B,CPTR	;THE PTR SHOULD END UP AT THE POINT
	 MOVE OUT,PT	;COMMAND STRING READING STOPPED.
	JRST LISCY1

;? WAS 1ST CHAR TYPED AFTER ERR MSG, RETYPE LAST FEW CHARS.
ERRTYP:	HRRZM P,ERRFL1	;DON'T LET ERRFL1 PREVENT OUR TYPEOUT FROM APPEARING.
	MOVE B,ERR2
	MOVEI C,8*5
	SUBI B,8
	ILDB CH,B
	CAMG C,ERR1
	PUSHJ P,TYO
	CAME B,ERR2
	SOJA C,.-4
	JRST GO

;MARK THE CURRENT MACRO PC FOR ERRTYP TO TYPE OUT.
ERRP2:	MOVEI A,COMCNT
	CALL MFBEGP		;C GETS CURRENT PC IN CHARS IN CURRENT MACRO.
	TRO FF,FRQMRK
	MOVEM C,ERR1		;SAVE THAT, AND B.P. TO LAST CHAR READ.
	MOVE A,CPTR
	MOVEM A,ERR2
	RET

SUBTTL ^R MODE

;GET LENGTH CODE OF CHAR IN CH INTO A.
;SKIP IF NOT A CTL CHAR. NOTE THAT CALLING DISAD6 MAY BE
;EQUIVALENT TO DOING  CALL .+1  .
DEFINE	RRCHRG
	SKIPE CASDIS	;IN -1F$ MODE, HANDLE SLASHIFICATION.
	 CALL DISAD6
	MOVEI A,(CH)
	IDIVI A,6
	LDB A,RRCHBP(B)
	CAIN CH,177	;RUBOUT PRINTS AS ^? OR AS INTEGRAL SIGN, SO TREAT IT AS A CTL CHAR.
	 SKIPA A,[1]
	CAIGE CH,40
TERMIN

;ENTRY FOR ^R 1ST CHAR TYPED IN CMD STRING.
RRIMMD:	SAVE [GO]
	MOVE TT,QRB..
	SETZM .QVWFL(TT)	;ALLOW A BUFFER DISPLAY TO SHOW RESULTS OF ^R.
	SETZM IMQUIT

;^R EXECUTED AS A COMMAND.
RRENTR:	.I CASE=CASNRM
	TLZA FF,FLNOIN	;SAY INPUT IS ACCEPTIBLE.
;@V COMMAND WITHIN A MACRO CALLED FROM ^R MODE COMES HERE.
RRNOIN:	 TLO FF,FLNOIN	;ENTRY TO DISPLAY ONCE AND RETURN, PROCESSING NO INPUT.
	CALL RREARG	;PROCESS ARGS IF ANY, DECIDE WHAT REDISPLAY NEEDED.
		;ALSO MAKE SURE RRHPOS AND RRVPOS ARE REASONABLE.
	SAVE FF		;REMEMBER WHETHER THIS IS ^R OR @V, FOR RREAR0.
	SAVE PF		;SAVE QPDL PTR SO EXITING ^R CAN POP WHAT FS ^R ENTER PUSHES.
	SAVE DISPRR
	CALL [MOVEM P,DISPRR	;SET UP PDL RESTORATION POINT
		RET]		;FOR ERRORS CAUGHT BY ^R.
	 JUMPL FF,RRNOI2
	SKIPE A,RRENTM
	 CALL RRMACR
RRNOI2::SETOM ECHCHR		;ENTERING ^R SHOULDN'T ECHO A COMMAND.  @V SHOUDLN'T ECHO ONE.
	TLNN FF,FLNOIN
	 SETOM RRLAST
;DROPS THROUGH.

SUBTTL ^R MODE REDISPLAY

;DROPS THROUGH.

;MAIN LOOP OF ^R EDIT: ROUTINES DISPATCHED TO WILL POPJ TO HERE.
RRLP:	 CAIA
	  CALL RRTTY1	;BUILT-IN COMMANDS SKIP TO "RETURN ONE VALUE", SO SCAN CURSOR MOTION.
	CALL RRTTYE	;PRINTING TTY IN SCAN MODE, IF COMMAND DOESN'T TYPE OUT, ECHO IT.
	SETZM STOPF
	SETZM ORESET
	JUMPL FF,RRLP6	;THIS IS ^R AS OPPOSED TO @V
	CALL RRARGF	;THEN FLUSH ARGS IF COMMAND WASN'T AN ARG-SETTER.
	SKIPN RRLAST	;AND IF THE LAST COMMAND WAS NOT AN ARG-SETTER,
	 JRST RRLP6B
	MOVE CH,INCHCT	;THEN A COMMAND HAS JUST ENDED, SO SAVE FS TYI COUNT IN FS TYI BEG.
	SKIPL UNRCHC	;BUT DON'T INCLUDE ANY CHARACTER THA<T'S GOING TO BE REREAD.
	 SOS CH
	MOVEM CH,INCHRR
	SKIPE ECHFLS
	 SKIPGE PJATY	;IF WHOLE SCREEN IS ABOUT TO BE CLEARED ANYWAY, DON'T BOTHER.
	  JRST RRLP6B
	SKIPN C,ECHACT	;IF ECHO AREA SHOULD BE CLEARED, DO SO.
	 JRST RRLP6B
	JUMPG C,[SETOM ECHACT	;IF IT SHOULD BE CLEARED NEXT TIME BUT NOT THIS TIME,
		 JRST RRLP6B]	;REMEMBER THAT.
	SETZM ECHACT	;INDICATE ECHO AREA NO LONGER OCCUPIED.
	SKIPN RGETTY
	 JRST RRLP6B
	MOVEI C,^P
	CALL FSECDS
	MOVEI C,"C
	CALL FSECDS	;FSECDS SETS RROVPO SO WE WILL REPOSITION THE CURSOR WHEN WE CAN.
	SETZM ECHACT	;RE-CLEAR SINCE FSECDS SET IT AGAIN.
RRLP6B:	SKIPLE RRMCCT	;AND IF FS ^RMDLY ISN'T 0,
	 SOSLE RRMCC1	;THEN IF IT IS ALREADY TIME TO INVOKE SECY, DO SO.
	  JRST RRLP6
	MOVE CH,QRB..	;IF THERE IS ONE.  IF THERE IS NONE, RRMCC1 IS NEGATIVE SO AS
	SKIPN A,.QCRMC(CH)	;SOON AS THERE IS ONE AGAIN IT WILL BE RUN.
	 JRST RRLP6
	CALL RRMACR	;DO SO.
	MOVE A,RRMCCT	;AND REINIT # CHARS TO EXECUTE BEFORE
	MOVEM A,RRMCC1	;NEXT INVOKATION.
RRLP6:	SETO OUT,	;WE HAVEN'T RUN THE FS ^R DISPLAY MACRO YET.
RRLP6A:	SKIPN RGETTY
	 JRST [	SKIPGE GEA	;ON PRINTING TTY, REDISPLAY ONLY AFTER A ^L.
		 JRST RRLP4
		JRST RRLP1]	;OTHERWISE JUST READ ANOTHER COMMAND.
	SKIPE RRINHI	;IF DISPLAYING IS INHIBITED, READ ANOTHER COMMAND WITHOUT DISPLAYING
	 JRST [	MOVE T,MORESW	;BUT DO UPDATE THE MODE-LINE.
		CAIE T,MS%FLS	;AND DON'T TRY TO LEAVE IT SAYING "FLUSHED".
		 SETZ T,
		CALL DISMD
		JRST RRLP1]
	SKIPE DFORCE
	 JRST RRLP6C
	SKIPGE UNRCHC	;ANY BUFFERED INPUT TO PROCESS?
	 SKIPE TYISRC
	  JRST RRLP1
	LISTEN TT
	JUMPN TT,RRLP1
RRLP6C:	SETOM TYOFLG	;DOING ^R DISPLAY FORCES TYPEOUT TO RE-INIT.
	SKIPGE GEA	;^L OR F+ HAS CLEARED THE SCREEN => REDISPLAY
	 JRST RRLP4
	SKIPL PJATY	;SCREEN GOT CLOBBERED, OR LOTS OF CHANGES HAPPENED, =>
	 SKIPGE RRMNVP	;MUST CHECK THE WINDOW BEFORE DISPLAYING ANYTHING.
	  JRST RRLP4
	CALL RRWBLS	;IS OLD WINDOW STILL GOOD?
	 CALL [	TRO FF,FRUPRW	;NO => CHOOSE A NEW ONE FROM SCRATCH, AND
		JRST RRALT6]	;TRY SCROLLING THE TEXT WITH INSERT/DELETE LINE.
	SKIPGE PJATY	;RRALT6 CAN SET THIS ON NOCEOL TERMINALS.
	 JRST RRLP4
	MOVE A,RRMAXP	;RRMAXP=1 IS SET TO INHIBIT UPDATING IN RRDLB AND RRINSC.
	CAIN A,1	;IT DOESN'T INDICATE ANY CHANGES HAVE ACTUALLY OCCURRED.
	 SETZM RRMAXP
	SKIPN RRMAXP	;ANY REDISPLAY REQUIRED?
	 SKIPL RRMSNG
	  CAIA
	   JRST RRLP3	;NO, JUST MOVE CURSOR IF NEC.
	MOVE A,RRMNVP
	CAML A,BOTLIN	;IF ALL REQUIRED REDISPLAY IS REALLY OFF BOTTOM OF SCREEN,
	 JRST [	CALL RRDIS2	;SAY IT'S BEEN DONE, AND MOVE THE CURSOR IF NEC.
		JRST RRLP3]
	JUMPE OUT,RRLP2F	;RUN FS ^R DISPLAY, UNLESS WE JUST FINISHED RUNNING IT.
	SKIPN A,RRDISM	;ABOUT TO DISPLAY;  FIRST CALL USER'S MACRO.
	 JRST RRLP2F
	CALL RRMACR
	SETZ OUT,	;MARK FS ^R DISPLAY AS RUN, THIS TIME, TO AVOID INFINITE LOOP.
	TRNN FF,FRARG2	;IF 0 OR 2 VALUES, RECONSIDER WHAT DISPLAY TO DO
	 TRNN FF,FRARG
	  SETO OUT,
	JRST RRLP6A

;HERE IF PART OF THE SCREEN NEEDS REDISPLAY BUT NOT WHOLE SCREEN.
RRLP2F:	SETOM RRIDLB	;IF NO INSERT/DELETE LINE, CAUSE ASSOCIATED CODE TO DO NOTHING.
	SKIPE LID	;IF THE TERMINAL HAS INSERT/DELETE LINE, SEE HOW MANY LINES OF
	 CALL RRLID	;BOTTOM OF WINDOW WILL STILL BE GOOD IF SHIFTED A FEW LINES.
	CALL CHCTI0	;INIT. FOR CALLING DISAD.
	SETOM TYOFLG
	SETZM CHCTBP
	AOS CHCTBP	;(MUSTN'T BE 0, OR CHCTHC WOULDN'T BE SET)
	HLLOS DISBFC
	MOVEI TT,CPOPJ
	MOVEM TT,CHCTAD	;MAKE SURE DISLIN NOT CALLED, IN CASE STRAY CR OR BS.
	.I RRDHPS=RRHPOS	;SAVE INFO FOR DEBUGGING.
	.I RRDVPS=RRVPOS
	.I RRDMHP=RRMNHP
	.I RRDMVP=RRMNVP
	SAVE PT
	SAVE RRHPOS
	SAVE RRVPOS
RRLP2G:	MOVE A,RRMNVP	;FIND THE 1ST CHAR IN THE 1ST LINE
	MOVEM A,RRVPOS
	LDB TT,[3300,,LINBEG(A)]	;WHICH WAS ALTERED,
	MOVEM TT,PT
	MOVE TT,LINBEG(A)
	ASH TT,-33
	MOVEM TT,RRHPOS	;AND WHAT COLUMN IT WAS TYPED IN.
	MOVEM TT,CHCTHP	;IN CASE LINE DOESN'T START AT LEFT MARGIN
			;(DUE PERHAPS TO LF WITHOUT CR)
	CALL CHCTL4	;INIT CHCTHC WITH SPACES.
	SETZ T,		;T GETS THE LARGEST HPOS THAT ACTUALLY EXISTS ON THE LINE.
			;IF THE LINE ENDS SHORT OF RRMNHP, WE RESET RRMNHP TO THAT AND RETRY.
RRLP2B:	MOVE TT,RRHPOS	;MOVE FORWARD TILL WE FIND 1ST CHAR
	CAML TT,RRMNHP	;THAT FALLS IN THE 1ST ALTERED COLUMN.
	 JRST RRLP2C
	MOVE TT,PT
	CAML TT,ZV
	 JRST RRLP2C
	CALL RRFORW
	CAMGE T,RRHPOS
	 MOVE T,RRHPOS
	MOVE TT,RRVPOS
	CAME TT,RRMNVP	;BUT DON'T LET US MOVE PAST THE END OF
	 JRST RRLP2D	;THE LINE WE'RE SUPPOSED TO START ON.
	CALL DISAD2	;PUT THE CHARACTERS WE SKIP OVER INTO THE LINE'S HASH CODE.
	JRST RRLP2B

RRLP2D:	MOVEM T,RRMNHP	;HERE IF THE LINE DOESN'T EXTEND AS FAR RIGHT AS RRMNHP SAYS.
	CALL CHCTI0	;SET RRMNHP BACK TO THE LARGEST HPOS ON THE LINE, AND TRY AGAIN.
	JRST RRLP2G	;SO WE DISPLAY FROM THE VERY END OF THE LINE.

RRLP2C:	MOVE IN,PT	;CHAR ADDR 1ST CHAR TO BE OUTPUT.
	AOSN CHCTCF
	 CALL CHCT5	;FORCE OUT SAVED-UP CR.
	CAML IN,BEGV
	 CAMLE IN,ZV
	  .VALUE
	MOVEM IN,RRDPT	;REMEMBER WHERE OUTPUT STARTD, FOR DEBUGGING.
	.I DISVP1=CHCTVP=DISVP=RRVPOS=RRMNVP
	CALL DISLI6
	MOVEI TT,DISLIN
	MOVEM TT,CHCTAD
	.I CHCTVS=BOTLIN
	SETZM MORNXT
;NOW THINK ABOUT REDISPLAYING ONLY PART OF A LINE, MAYBE USING I/D CHAR.
	MOVE A,RRMAXP
	MOVE BP,RRMNVP	;NOW IS THE LAST THING THAT CHANGED
	MOVEI TT,1(BP)	;THIS WON'T WORK ON THE LAST LINE ON THE SCREEN
	CAML TT,BOTLIN	;BECAUSE THERE ISN'T A LINBEG GIVING ITS END ADDRESS.
	 JRST RRLP2H
	SUB A,ZV	;ON THE SAME LINE AS THE FIRST CHANGE?
	ADD A,RROLZV
	ADDI A,2	;CHANGES MUST END BEFORE THE CRLF BEFORE THE NEXT LINE.
	SAVE CHCTHP
	CAMGE A,LINBEG+1(BP)
	 CALL RRLCHG	;IF SO, USE MORE EFFICIENT PARTIAL-LINE UPDATING PROCEDURE.
	  CAIA
	   JRST [	;IF IT WINS, WE ARE FINISHED!
		SUB P,[1,,1]
		REST RRVPOS
		REST RRHPOS
		REST PT
		SKIPL RRMSNG
		 JRST RRLP6
		JRST RRLP5]
	REST CHCTHP
	.I RRHPOS=CHCTHP
	.I RRVPOS=RRMNVP
RRLP2H:	MOVE TT,RRMNVP
	CAME TT,BOTLIN	;UNLESS IT'S THE --MORE-- LINE,
	SKIPN CHCTHP	;IF WE'RE DISPLAYING A WHOLE LINE, DON'T CLEAR UNLESS CHECKSUM
	 JRST [	SETOM DISVP	;SAYS IT HAS ACTUALLY CHANGED.
		SETOM DISVP1
		JRST RRLP2E]
	MOVE CH,INCHCT	;IF "DISPLAYING" PRE-ECHOED CHARS, DON'T ACTUALLY OUTPUT.
	CAMG CH,INCHEC
	 JRST RRLP2E
	CALL RRMVC	;DISPLAYING ONLY PART OF A LINE:  CHECKSUM MECHANISM WOULD LOSE,
	SETOM HCDS(TT)	;SO DISABLE THE CHECKSUM MECHANISM TO FORCE OUTPUTTING.
	SKIPN NOCEOL	;IF NOCEOL, THE FIRST DISLIN WILL CLEAR IT ANYWA.
	 CALL CLREOL
RRLP2E:	REST RRVPOS
	REST RRHPOS
	REST PT
	SETOM RROVPO	;WHEN WE STOP DISPLAYING, MUST REPOSITION PHYSICAL CURSOR.
	CALL VBDOK3	;DO THE DISPLAYING.  ALL PREPARATIONS NECESSARY FOR VBDOK3
			;SHOULD BE DONE BEFORE THE CALL TO RRLCHG.
	CALL RRDIS2	;INDICATE NOW REDISPLAY NOT NEEDED.
	JRST RRLP5

;REDISPLAY CHANGES ENTIRELY WITHIN ONE LINE.
;IN CONTAINS THE CHAR ADDR AT WHICH CHANGES START.  WE DON'T CLOBBER IN.
;SKIP IF WE SUCCEED IN BEING ABLE TO DO ANYTHING.
;OTHERWISE, NOTHING HAS BEEN DONE TO THE SCREEN
;AND THE MORE GENERAL TECHNIQUE MUST BE USED.
RRLCHG:	MOVE BP,RRMNVP
	MOVE T,RRMSNG		;DON'T ACT IF THE CHANGED LINE
	CAML BP,T		; MIGHT NOT HAVE BEEN CORRECT ON THE SCREEN.
	 JUMPGE T,CPOPJ
	MOVEM BP,RRVPOS
	PUSH P,IN
	MOVE T,LINEND(BP)	;IF LINE USED TO BE CONTINUED, GIVE UP.
	CAMLE T,NHLNS		;WE CAN TELL BECAUSE ITS END HPOS WILL BE PAST THE ! COLUMN.
	 JRST RRLCHQ
	SETZ D,			;D BECOMES NONZERO AFTER WE ENCOUNTER THE FIRST TAB.
	SETO T,
RRLCH1:	CAMN IN,RRMAXP		;WHEN WE REACH THE CHARACTER AT WHICH CHANGES STOP,
	 MOVE T,RRHPOS		;REMEMBER THE HPOS.
	CAMLE T,RRHPOS		;IF ANYTHING PAST END OF CHANGES BACKSPACES AND OVERSTRIKES
	 JRST RRLCHQ		;WITH THE CHANGED STUFF, WE CAN'T WIN WITH I/D CHAR.
	CALL RREOLT
	 JRST RRLCH2		;WHEN WE REACH THE END OF THE LINE, WANT THE HPOS THERE TOO.
	CALL RRFORW
	JUMPL T,RRLCHC
	CAIE CH,^I		;IF WE FIND A TAB AFTER THE END OF THE CHANGES,
	 JRST RRLCHC
	JUMPL D,RRLCHC		;THEN WE MUST INCLUDE EVERYTHING UP THRU THE FIRST SUCH TAB
	MOVEM IN,RRMAXP		;AS TEXT TO BE REDISPLAYED, AS IF IT HAD ALL BEEN CHANGED.
	SETO D,			;SET D TO SAY WE HAVE FOUND ONE TAB SO MORE TABS NO TROUBLE.
		;TEXT CONTAINING TABS CAN'T BE COUNTED ON TO MOVE RIGIDLY WHEN STUFF IS
		;INSERTED OR DELETED BEFORE IT, UNLESS A TAB IMMEDIATELY PRECEDES IT.
RRLCHC:	MOVE TT,RRVPOS
	CAME TT,RRMNVP		;GIVE UP IF THE LINE IS CONTINUED.
	 JRST RRLCHQ
	JRST RRLCH1

RRLCH2:	JUMPL T,RRLCHQ		;IF HAVEN'T FOUND END OF CHANGES, A CRLF HAS BEEN INSERTED,
				;SO GIVE UP.  WE WIN ONLY IF THE LINE IS STILL ONE LINE.
	MOVE A,RRHPOS		;GET CURRENT NEEDED END-HPOS OF TEXT FOLLOWING THE CHANGE.
	MOVE BP,RRVPOS
	SUB A,LINEND(BP)	;SUBTRACT OLD END-HPOS TO GET DISTANCE TO MOVE RIGHT.
;WE NOW HAVE GATHERED ALL THE INFORMATION.
;DECIDE WHETHER IT IS FASTER TO REWRITE ONLY PART OF THE LINE.
	MOVE B,RRHPOS
	SUB B,T			;GET NUMBER OF CHARS THAT WE COULD AVOID REPRINTING.
	LSH B,-1		;WE WIN IF THAT'S MORE THAN TWICE THE NUMBER OF
	MOVM TT,A
	CAMGE B,TT		;INSERTS OR DELETES WE MUST DO.
	 JRST RRLCHQ
	SKIPN CID		;IF TERMINAL CAN'T DO INSERT OR DELETE CHARACTER,
	 JUMPN A,RRLCHQ		;WE WIN ONLY IN THE CASE THAT NONE ARE NECESSARY.
	SKIPL A
	 SUB T,A		;GET MINIMUM OF DESIRED STARTING HPOS AND OLD STARTING HPOS.
	CAMGE T,RRMNHP		;BUT CAN'T MOVE ANYTHING THAT DOES OR WILL OVERLAP
				;WITH THE TEXT TO THE LEFT OF THE CHANGED AREA
	 JRST RRLCHQ		;(PATHOLOGICAL CASE OF INSERTING OR DELETING A BACKSPACE).
	ADDM A,LINEND(BP)
	MOVE TT,INCHCT		;IF PROCESSING A PRE-ECHOED CHANGE,
	CAMG TT,INCHEC		;DON'T ACTUALLY OUTPUT ANYTHING.
	 JRST RRLCH7
	MOVE TT,TTYOPT		;IF NO CHANGE IN NUMBER OF CHARS, AND NO OVERPRINTING,
	TLNN TT,%TOOVR		;JUST MOVE CURSOR ONCE.
	 JUMPE A,RRLCH5
	HRLZS BP
	HRR BP,T
	CALL SETCUR		;MOVE CURSOR THERE.
	JUMPL A,RRLCH4
	JUMPE A,RRLCH3
	CALL INSCHR		;INSERT OR DELETE CHARACTERS, MOVING TEXT AFTER THE CHANGE
	JRST RRLCH3		;TO ITS DESIRED LOCATION.

RRLCH4:	MOVMS A
	CALL DELCHR
RRLCH3:
;; NOW, ON A TERMINAL THAT CAN OVERPRINT, WE MUST ERASE THE REMAINING CHANGED AREA.
;; WE CAN DO THAT BY BACKSPACING OVER THE AREA DOING %TDDLF'S.
;; ON A TERMINAL THAT CANNOT OVERPRINT, WE NEED ONLY MOVE THE CURSOR BACK TO THAT POINT.
;; THE CURRENT CURSOR HPOS IS IN T.  THE DESIRED ONE IS IN RRMNHP.
	MOVE TT,TTYOPT
	TLNN TT,%TOOVR
	 JRST RRLCH5
RRLCH6:	CAMN T,RRMNHP		;TILL WE BACK UP TO THE STARTING POSITION,
	 JRST RRLCH7
	MOVEI CH,^H		;FOR EACH POSITION, DO ONE BACKSPACE AND ONE ERASE-CHAR.
	CALL TYOINV
	CALL ERSCHR
	SOJA T,RRLCH6

RRLCH5:	HRLZ BP,RRVPOS
	HRR BP,RRMNHP		;GET POSITION OF START OF CHANGES.
	CALL SETCUR
RRLCH7:	MOVE IN,(P)		;GET RANGE CONTAINING NEW TEXT, AND TYPE IT OUT.
	MOVE BP,RRVPOS
	SAVE LINEND(BP)
	SAVE LINBEG+1(BP)	;DISLIN WOULD WANT TO CLOBBER THESE!
RRLCH8:	CAMN IN,RRMAXP
	 JRST RRLCH9
	CALL GETINC
	CALL DISAD
	JRST RRLCH8

RRLCH9:	SETZM LINEND(BP)	;PREVENT LINE-CLEARING ON NOCEOL TERMINALS.
	SETCM TT,CHCTHC		;IF TTY CAN OVERPRINT, THEN WE HAVE ALREADY CLOBBERED
	MOVE TT1,TTYOPT		;THE TEXT ON THE SCREEN EVEN IF WE DID NO I/D,
	TLNE TT1,%TOOVR		;SO PREVENT A HASH MATCH FROM PREVENTING
	 MOVEM TT,HCDS(BP)	;THE LINE FROM BEING OUTPUT.
	CALL DISFLS		;FORCE OUT WHAT WE HAVE SENT THROUGH DISAD.
	SETOM TYOFLG
	SETZM CHCTBP		;NOW SET UP FOR JUST COMPUTING HASH CODE, NOT OUTPUTTING. 
	AOS CHCTBP		;(MUSTN'T BE 0, OR CHCTHC WOULDN'T BE SET)
	HLLOS DISBFC
	MOVEI TT,CPOPJ
	MOVEM TT,CHCTAD		;MAKE SURE DISLIN NOT CALLED, IN CASE STRAY CR OR BS.
RRLCHA:	CALL RREOLT		;NOW FINISH "OUTPUTTING" UP TO THE END OF THE LINE,
	 JRST RRLCHB
	CALL GETINC		;BUT SINCE CHCTAD IS A NO-OP NOTHING WILL COME OUT.
	CALL DISAD		;HOWEVER, THE HASH CODE FOR THE LINE WILL BE CALCULATED.
	JRST RRLCHA

RRLCHB:	MOVE BP,RRVPOS
	MOVE T,CHCTHC
	MOVEM T,HCDS(BP)	;STORE THE NEW CORRECT HASH CODE.
	REST LINBEG+1(BP)
	REST LINEND(BP)
	MOVE T,ZV
	SUB T,RROLZV		;UPDATE LINBEGS OF ALL FOLLOWING LINES.
	CALL RRINS3
	SETZM RRMAXP		;NO CHANGES REMAIN TO BE DISPLAYED.
	SKIPGE RRMSNG		;IF NO LINES ARE MISSING AT THE END, NO DISPLAY IS NEEDED.
	 CALL RRDIS2
	SETZM RRMNHP		;OTHERWISE, START THINKING AT START OF LINE.
	SETOM RROVPO		;WHEN WE STOP DISPLAYING, MUST REPOSITION PHYSICAL CURSOR.
	AOS -1(P)		;WE HAVE WON - RETURN SKIPPING.
RRLCHQ:	REST IN			;WE HAVE LOST - RETURN NON-SKIPPING.
	RET

;TEST THE WINDOW FOR VALIDITY, ASSUMING RRVPOS IS CORRECT.
;MUCH FASTER THAN AN ACTUAL VBDBLS.
;CLOBBERS A, IN, TT, TT1.
RRWBLS:	MOVE A,RRVPOS
	SKIPN GEA
	 JRST RRWBL1
	CAMGE A,RRTOPM	;CURSOR TOO NEAR TOP => NEW WINDOW.
	 RET
RRWBL1:	MOVE TT,MORESW
	TRNN TT,MS%DWN	;IF THERE'S STUFF PAST THE SCREEN BOTTOM,
	 JRST RRWBL2	;WE DON'T WANT CURSOR TOO NEAR BOTTOM.
	CAML A,RRBOTM
	 RET
RRWBL2:	CAMGE A,BOTLIN	;IF CURSOR'S BELOW BOTTOM, WE MUST SHIFT THE WINDOW.
	 JRST POPJ1	;ELSE, OLD WINDOW IS STILL GOOD.
	MOVE IN,PT	;EXCEPTION:  CURSOR AT FRONT OF --MORE-- LINE
	CAMG  A,BOTLIN	;AT END OF BUFFER AFTER A CRLF,
	 CAME IN,ZV	;IS CONSIDERED AT THE END, RATHER THAN BELOW IT.
	  RET
	SUBI IN,2
	CALL RREOLT	;SO CHECK FOR THE CRLF.
	 JRST POPJ1
	RET

;COME HERE HAVING DETERMINED THAT A FULL SCREEN REDISPLAY IS NEEDED.
RRLP4:	MOVE A,RRDISM	;DO FULL REDISPLAY, TESTING PREVIOUS WINDOW.
	JUMPE A,RRLP5A
	CALL RRMACR
	SKIPL GEA	;ON RETURN, IS REDISPLAY STILL NEEDED OR WAS IT ALREADY DONE?
	 SKIPGE RRMAXP
	  JRST RRLP5A
	SKIPGE PJATY	;IF SEEMS TO HAVE BEEN DONE, MAYBE WE SHOULDN'T DO IT.
	 SKIPL RRMSNG
	  CAIA
	   JRST RRLP6
RRLP5A:	SETOM RROVPO	;WHEN WE STOP DISPLAYING, MUST REPOSITION PHYSICAL CURSOR.
	.I RRERFL=ERRFL1
	SETOM RRIDLB	;IN FULL REDISPLAY, NONE OF THE TEXT ALREADY ON THE SCREEN CAN BE REUSED.
	CALL RRDISP	;NORMAL (VBD) DISPLAY, MAYBE CHANGING WINDOW.
	CALL RRDIS2	;REDISPLAY NOW NOT NEEDED,
	SKIPL RRERFL	;UNLESS THIS REDISPLAY DIDN'T DISPLAY THE TOP LINE
	 JRST RRLP5
	.I RRMNVP=TOPLIN	;(PRESERVING AN ERR MSG) IN WHICH CASE REDISPLAY AFTER NEXT CMD.
	SETZM RRMNHP
	.I RRMAXP=GEA+BEGV
RRLP5:	.I RROLZV=ZV
	AOSN RRNCCR	;IF CHAR BEFORE PT WAS A CR, RRHPOS WASN'T SET
		;(DUE TO THE FACT THAT A CR ISN'T OUTPUT UNTIL THE
		;NEXT CHAR IS SEEN)
	 CALL [	SOS PT	;HPOS AND VPOS ARE CORRECT FOR BEFORE
		JRST RRFORW]	;THE CR, SO SPACE OVER IT.
	MOVE A,RRHPOS	;DON'T LET THE CURSOR BE OVER THE "!"
	CALL RRFOR3	;OF A CONTINUATION.
RRLP3:	MOVE T,MORESW
	CALL DISMD	;REDISPLAY Q..J IF IT HAS CHANGED, NOT CHANGING --MORE-- STATUS.
	SKIPE RGETTY
	 CALL RRMVC	;PUT THE HARDWARE CURSOR AT THE POINTER.
	JRST RRLP1

RRDISX:	MOVEI T,RRLP1	;COME HERE TO QUIT DISPLAYING BECAUSE INPUT WAITING.
	MOVE CH,DISPRR	;BP HAS VPOS OF LINE WE WOULD HAVE DISPLAYED NEXT
	MOVEM T,(CH)	;PREVENT RRARGF FROM BEING CALLED.
;COME HERE IF STOP DISPLAYING SINCE KNOW NO MORE DISPLAY NEEDED.
;BP HAS VPOS OF LINE WE WOULD HAVE DISPLAYED NEXT (LAST LINE
;WITH VALID LINBEG).
RRDISF:	MOVE P,DISPRR
	MOVE T,ZV
	SUB T,RROLZV
	ADDM T,RROLZV
RRDISG:	MOVE A,T	;NOW UPDATE THE LINBEG WORDS OF THE REMAINING SCREEN LINES.
	AOS TT,BP
	CAMLE TT,BOTLIN
	 .VALUE
	JRST RRFXR1

RRDISP:	SKIPN RGETTY
	 JRST RRDIS3
	.I RRMNVP=TOPLIN ;IF DISPLAYING IS INTERRUPTED, MAKE
	SETZM RRMNHP	;WE RESTART THE RIGHT WAY.
	SETZM RRMSNG	;SAY WE CAN'T STOP DISPLAYING AT RRMAXP.
	JRST VBDRR

RRDIS1:	MOVE CH,CHCTHP	;CALL HERE WHEN CURSOR IS OUTPUT,
	MOVEM CH,RRHPOS	;OR AT END OF BUFFER IF PT IS THERE.
	MOVE CH,CHCTCF	;IF THE LAST CHAR WAS CR,
	MOVEM CH,RRNCCR	;SAY WE DON'T KNOW CORRECT HPOS.
	MOVE CH,CHCTVP
	MOVEM CH,RRVPOS	;REMEMBER SCREEN POS. OF CURSOR.
	POPJ P,

RRDIS2:	SETZM RRMAXP		;HERE TO DECLARE THAT NO REDISPLAY IS NEEDED.
	SETOM RRMSNG
	HRLOI TT,377777
	MOVEM TT,RRMNVP
	MOVEM TT,RRMNHP
	POPJ P,

;MOVE THE CURSOR TO THE PLACE SPECIFIED BY RRVPOS AND RRHPOS.
;ASSUMES THAT RROHPO, RROVPO HOLD CURRENT ACTUAL LOCATION OF CURSOR,
;OR -1 IF THE OLD POSITION IS NOT KNOWN. CLOBBERS Q.

RRMVC:	MOVE Q,RRHPOS
	SKIPN RGETTY
	 MOVEM Q,CHCTHP
	SKIPE RGETTY
	 CAME Q,RROHPO	;IF NEITHER COORD NEEDS TO BE CHANGED,
	  JRST RRMVC1
	MOVE Q,RRVPOS
	CAMN Q,RROVPO
	 RET		;DON'T BOTHER TO DO ANYTHING.
RRMVC1:	SAVE BP
	HRRZ BP,RRHPOS
	HRL BP,RRVPOS
	HRRZM BP,RROHPOS
	HLRZM BP,RROVPOS
	MOVE Q,INCHCT	;IF "DISPLAYING" PRE-ECHOED INPUT,
	CAMLE Q,INCHEC	;DON'T ACTUALLY OUTPUT ANYTHING.
	 CALL SETCUR
	JRST POPBPJ

;HERE TO SEE IF ANY OF THE TEXT ON THE SCREEN, PAST ALL CHANGES WE MUST DISPLAY,
;CAN STILL BE USED IF WE CAN MOVE IT TO THE RIGHT LINE ON THE SCREEN
;(USING INSERT/DELETE LINE).  SOMETIMES WE ACTUALLY MOVE THE TEXT AND BLT THE TABLES.
;USUALLY WE JUST SET RRIDVP TO THAT LINE'S VPOS AND RRIDLB TO ITS LINBEG WORD
;(RELOCATED TO CONTAIN A CURRENT ADDRESS RATHER THAN A HISTORICAL ONE).
;RRIDBK IS SET TO THE NUMBER OF BLANK LINES WHICH NOW PRECEDE THAT STILL-USEFUL LINE.
;IT IS USED IN RECOGNIZING WHERE THAT LINE IS GOING TO BE WANTED ON THE SCREEN
;AS SOON AS THE FIRST BLANK LINE IS REACHED IN TYPEOUT.  THIS REDUCES WASTEFUL DISPLAY.
RRLID:	CALL RRLID2		;FIND THE TEXT TO BE PRESERVED, SET RRIDLB AND RRDVP.
	 RET			;NO SKIP MEANS NO TEXT ON SCREEN MAY BE PRESERVED.
	MOVE BP,RRMNVP
	MOVE TT1,RRIDLB
	CAME TT1,LINBEG(BP)	;IF THAT TEXT OUGHT TO BE MOVED UP TO WHERE WE WILL START
	 RET			;DISPLAYING (IE, WE ARE DISPLAYING THAT SOME LINES WERE KILLED)
;DELETE LINES OF TEXT FROM C(BP) TO C(RRIDVP).
	SOS BP
	CALL DSLID	;MOVE THE STUFF UP, RIGHT NOW.  BP HAS -1 PLUS LINE WE ARE "AT".
	 RET		;IF DSLID DECIDED TO ABORT, THAT'S OK.
	SETZM RRMAXP	;ALL CHANGES ARE BEING HANDLED BY THE LINE-DELETE, SO THERE AREN'T ANY MORE.
;; OTHER PLACES JUMP TO RRLID5, AFTER CALLING DSLID TO MOVE TEXT UP, WITH VPOS-1 IN BP.
RRLID5:	MOVE TT,RRIDLB		;MAKE LINBEG OF LINE MOVED UP BE RIGHT.
	MOVEM TT,LINBEG+1(BP)
	SKIPE RRMAXP		;IF BUFFER HAS CHANGES, DON'T TRY TO JUMP RRMNVP FORWARD,
	 RET
	MOVE BP,RRMSNG	;NO CHANGES, SO RRMSNG GIVES FIRST VPOS THAT NEEDS REDISPLAY;
	SOS BP		;BUT THE PREVIOUS LINE IS THE LAST ONE WHOSE LINBEG IS CORRECT,
	CAMGE BP,RRMNVP	;SO START DISPLAYING THERE.  NOTE RRMSNG CAN BE LESS THAN TOPLIN,
	 MOVE BP,RRMNVP	;BUT IN THAT CASE ITS VALUE IS NOT MEANINGFUL.
	CAMN BP,[SETZ-1]
	 .VALUE		;RRMNVP SHOULD NOT BE INFINITY, HERE.
	EXCH BP,RRMNVP
	SETZM RRMNHP
	MOVE CH,ZV
	SUB CH,RROLZV	;NOW RELOCATE LINBEGS OF ALL LINES PAST OLD RRMNVP THRU NEW RRMNVP,
	JUMPE CH,RRLID6	;SINCE LINBEGS OF ALL LINES ABOVE RRMNVP ARE SUPPOSED TO BE
;Version 1112: changed to add to all LINBEGs, not just those above RRMNVP,
;and to add to RROLZV as well.  This fixes the ugly display bug that used
;to happen when there were three ^D's in a row, deleting CRLFs, and twice
;display was pre-empted during the last call to DISLIN.
RRLID4:	AOS BP		;CORRECT WITHOUT NEEDING RELOCATION.
	CAML BP,BOTLIN	;ALSO RELOCATE THE REST, DOWN TO BOTLIN, AND UPDATE RROLZV
	 JRST RRLID6	;SAYING NO RELOCATION NECESSARY.  THAT'S CAUSE WE DON'T KNOW FOR
	ADDM CH,LINBEG(BP)	;SURE WHERE RRMNVP WILL END UP.
	JRST RRLID4

RRLID6:	ADDM CH,RROLZV
	MOVE CH,ZV	;DON'T LEAVE RRMNVP POINTING PAST THE END OF THE BUFFER.
RRLID7:	MOVE BP,RRMNVP	;IF THE LINE IT POINTS AT IS AT OR AFTER THE END OF BUFFER,
	CAMLE BP,TOPLIN	;MOVE IT BACK TO THE LINE THAT ACTUALLY FOLLOWS THE END.
	 CAME CH,LINBEG(BP)	;CHANGED FROM LINBEG-1(BP) SO DOESN'T LOSE ON A BUFFER
	  RET			;WHICH DOES NOT END WITH A CRLF.
	SOS RRMNVP
	JRST RRLID7

;DETERMINE WHETHER ANY OF THE LINES AT THE BOTTOM OF THE SCREEN CAN BE PRESERVED
;(PERHAPS MOVING THEM UP OR DOWN WITH INSERT/DELETE LINE).
;SKIP IF THERE ARE ANY, SETTING RRIDVP TO THE VPOS OF THE FIRST, AND RRIDLB
;TO THAT LINE'S LINBEG (UPDATED TO BE CORRECT WITH CURRENT ZV, RATHER THAN RROLZV).
RRLID2:	SETOM RRIDLB
	SETZM RRIDBK
	MOVE OUT,RROLZV
	SUB OUT,ZV	;COMPUTE ADDRESS BEYOND WHICH NO BUFFER CHANGES HAVE OCCURRED,
	ADD OUT,RRMAXP	;RELOCATED TO MATCH OLD LINBEG WORDS.
	MOVE BP,TOPLIN
RRLID1:	CAMN BP,BOTLIN
	 RET		;REACH END OF WINDOW => NO EXISTING TEXT STILL GOOD.  DON'T SET RRIDLB.
	LDB TT1,[3300,,LINBEG(BP)]
	CAMLE OUT,TT1	;SEE WHICH LINE IS THE FIRST TO START AFTER THAT POINT.
	 AOJA BP,RRLID1
	ADD TT1,ZV
	SUB TT1,RROLZV
	CAMN TT1,BEGV	;A LINE IS ACCEPTABLE ONLY IF ITS TEXT IS STILL AT THE FRONT OF A LINE.
	 JRST RRLID3	;SO REQUIRE THAT IT BE AT FRONT OF BUFFER OR AFTER A CRLF.
	MOVE IN,TT1
	SUBI IN,2
	CALL GETINC
	CAIE CH,^M
	 AOJA BP,RRLID1	;IF THIS LINE NOT GOOD FOR THIS REASON, NEXT LINE PROBABLY STILL GOOD.
	CALL GETCHR
	CAIE CH,^J
	 AOJA BP,RRLID1
RRLID3:	MOVEM BP,RRIDVP	;RRIDVP POINTS AT 1ST LINE NOT INVALIDATED, OR AT BOTLIN IF ALL INVALID
	MOVE TT1,LINBEG(BP)
	ADD TT1,ZV	;GET ADDR OF BEGINNING OF TEXT THAT CAN BE SAVED IF MOVED UP OR DOWN,
	SUB TT1,RROLZV	;RELOCATED TO BE THE CURRENT ADDRESS, NOT THE ADDR IT HAD
	MOVE TT,TT1
	TLZ TT,777000	;DON'T TRY TO MOVE FOLLOWING TEXT IF IT IS NULL (IT STARTS AT Z).
	CAMN TT,ZV
	 RET
	MOVEM TT1,RRIDLB ;WHEN LAST DISPLAYED.
	MOVE IN,TT
	SETOM RRIDBK	;NOW HOW MANY BLANK LINES ARE THERE BEFORE THAT POINT?
RRLID8:	SOS IN		;SCAN BACKWARDS COUNTING THEM AND PUT NUMBER IN RRIDBK.
	CAMGE IN,BEGV	;IF REACH BEG OF BFR JUST BEFORE A CRLF, THEN EACH CRLF WE PASSED
	 JRST [	AOS RRIDBK	;COUNTS FOR ONE BLANK LINE.
		JRST POPJ1]
	CALL GETCHR
	CAIE CH,^J	;OTHERWISE, THE LAST CRLF WE FIND IS REALLY THE END OF A NONBLANK LINE
	 JRST POPJ1	;AND SHOULDN'T COUNT.  TO ARRANGE THAT, WE START COUNTING AT -1.
	CAMG IN,BEGV
	 JRST POPJ1
	SOS IN
	CALL GETCHR
	CAIE CH,^M
	 JRST POPJ1
	AOS RRIDBK
	JRST RRLID8

SUBTTL PRINTING TERMINAL ^R DISPLAY

;DISPLAY CURRENT LINE AND PUT TTY CURSOR IN RIGHT PLACE, FOR PRINTING TTY SCAN MODE.
RRDIS3:	SKIPN RRSCAN
	 RET
	CALL RRBTCR
	SETZM RRVPOS	;TYPE LINE UP TO POINT (0T)
	SETZM RUBENC
	CALL DISTOT
	SETZ C,
	CALL GETAG7	;FIND RANGE (0F^@).
	 JFCL
	.I GEA=E-BEGV
	CALL TYPE2	;TYPE IT.
	TRO FF,FRCLN
	MOVEI C,1
	CALL GETAG7	;NOW TYPE TO END OF LINE.
	 JFCL
	CAMN C,E
	 RET
	CALL TYPE2	;AND BS OVER IT, SAYING MUST DO A LF IF WE ARE AT THE END OF THE LINE.
	JRST RRTTY2

;HERE TO HANDLE CURSOR MOTION, ON PRINTING TERMINAL IN SCAN MODE.
RRTTY:	SKIPN RRSCAN
	 JRST RRBTCR
	TRNN FF,FRARG		;IF WE KNOW NOTHING ABOUT THIS OPERATION,
	 JRST [	SKIPE A,RRTTM1	;DON'T DISPLAY (BUT LET USER'S HANDLER DISPLAY).
		 CALL RRMACR
		JRST RRBTCR]
	TRNE FF,FRARG2
	 JRST RRTTID		;JUMP IF IT'S AN INSERT/DELETE OPERATION.
	MOVE CH,ECHCHR		;DON'T DO IT OUR WAY IF COMMAND HAS ALREADY TYPED OUT.
	AOJE CH,CPOPJ
	CALL RRMAC3
	SKIPGE RRMNVP
	 RET
RRTTY1:	SKIPN RGETTY		;HERE TO SCAN MOTION CAUSED BY BUILT-IN ^F, ETC.
	 SKIPN RRSCAN
	  RET
	MOVE A,RRVPOS		;SHOW THE USER THE CURSOR MOTION IN SOME NICE WAY.
	SUB A,RREVPS		;IF WE'RE ON THE SAME LINE, OR THE NEXT ONE,
	JUMPL A,RRTTY5		;OTHERWISE, LET USER HANDLE DISPLAY.
	CAIL A,2		;(OR JUST ECHO THE COMMAND, IF NO HANDLER).
	 JRST RRTTY5
	MOVE C,PT
	MOVE E,RREPT		;FORWARD HORIZONTAL MOTION => TYPE CHARS MOVED OVER.
RRTTY4:	CAMGE E,C
	 JRST RRTTYF
	CAMG E,C		;NO MOTION, EVEN, => STILL PREVENT ECHOING.
	 JRST RRTTY3
RRTTY2:	SKIPE A,RUBENC		;NO NEED TO LF BETWEEN TWO BACKWARD MOTION CMDS.
	 CAIN A,^J		;ASIDE FROM THAT, IF LAST THING DONE WANTED STUFF TYPED,
	  CAIA			;TYPE IT.
	   CALL RUBEND
	CALL RRMVC		;BUT IF BACKWARD MOTION, JUST MOVE BACK TO HPOS, BUT
	MOVEI A,^J
	SKIPN BSNOLF
	 MOVEM A,RUBENC		;MAKE SURE WE TYPE A LF BEFORE TYPING ANYTHING ON THIS LINE.
RRTTY3:	SETOM ECHCHR		;MAKE THIS COMMAND NOT BE ECHOED.
	RET

RRTTYF:	SAVE DISPCR	;HERE TO SCAN FORWARD MOTION:  TYPE CHARS MOVED OVER,
	SETOM DISPCR	;WITH FS ^M PRINT$ SET TO -1 SO THAT STRAY CR AND LF
	CALL TYPE2	;COME OUT AS THEMSELVES.
	REST DISPCR
	RET

RRTTY5:	MOVE C,RREPT
	MOVEM C,NUM
	SKIPE A,RRTTM1	;MOTION TOO FAR TO JUST ECHO OR BACK UP;
	 JRST RRMAC6	;CALL THE USER'S MACRO TO HANDLE IT,
	RET		;OR DO NOTHING (AND COMMAND WILL ECHO).

;COME HERE AFTER A COMMAND.  IF IN SCAN MODE ON PRINTING TTY, AND COMMAND DIDN'T
;TYPE ANYTHING, ECHO IT (BY TYPING THE CHAR OR STRING IN FS ECHO CHAR$).
RRTTYE:	MOVE CH,ECHCHR
	CAME CH,[-1]
	 SKIPE RGETTY
	  RET
	SKIPGE GEA	;DON'T ECHO A ^L OR SIMILAR CHAR.
	 RET
	SKIPE RRSCAN
	 SKIPN RRLAST	;DON'T ECHO ARG-SETTING COMMANDS.
	  RET
	CAIL CH,
	 CALL TYINRM	;IF IT'S A CHAR (NOT A STRING) CONVERT TO 7-BIT.
	JRST FSECO1

RUBEND:	SAVE CH		;AND IF THERE'S ANYTHING TO TYPE (SUCH AS LF AFTER
	SKIPE CH,RUBENC	;BACKWARD MOTION IN ^R MODE), TYPE IT.
	 CALL FSECOR
	SETZM RUBENC
	JRST POPCHJ

;COME HERE TO HANDLE A COMMAND THAT RETURNED 2 VALUES, ON A PRINTING TTY IN SCAN MODE.
RRTTID:	MOVE CH,ECHCHR		;DON'T HACK REDISPLAY IF COMMAND TYPED SOMETHING.
	AOJE CH,RRBTCR
	MOVE C,NUM
	MOVE E,SARG
	CAML E,C
	 EXCH C,E
	CALL GETANU		;E, C GET THE CHAR ADDRS OF START AND END OF CHANGED RANGE.
	CAME C,PT		;WE DON'T KNOW HOW TO HANDLE IT UNLESS POINT WAS PUT AT END.
	 JRST RRTTI2
	.I C-E
	CAML TT,RRTTMX		;IS SIZE OF RANGE CHANGED BELOW THRESHHOLD?
	 JRST RRTTI2		;TOO MANY CHANGES => DON'T PRINT THEM.
	CAMN E,RREPT		;DID CHANGES START AT THE OLD POINT?
	 JRST RRTTI1
	SAVE C			;IF NOT, MOVE BACK TO WHERE CHANGES STARTED.
	SAVE E
	SAVE PT
	MOVEM E,PT		;MOVE RRVPOS, RRHPOS TO THE POSITION OF THAT PLACE.
	CALL RRMAC3
	REST PT			;BUT DON'T REALLY SET PT THERE.
	MOVE C,(P)
	MOVE E,RREPT		;NOW "MOVE BACK" THERE "FROM" WHERE PT USED TO BE.
	CALL RRTTY4
	REST E
	REST C
RRTTI1:	CALL RRBTCR
	CAME E,C		;NOW TYPE ALL THE NEW TEXT, LEAVING CURSOR AT POINT
	 JRST RRTTYF		;SINCE POINT IS WHERE THE NEW TEXT ENDS.
	RET

;IF WE CAN'T HANDLE THIS INSERT OR DELETE, EITHER BECAUSE IT'S TOO LONG,
;OR BECAUSE POINT IS NOT AT THE END OF IT, CALL USER'S HANDLER
;PASSING TWO ARGUMENTS (A RANGE OF THE BUFFER).
RRTTI2:	TRO FF,FRARG+FRARG2
	CALL RRMAC7
	JRST RRBTCR

SUBTTL ^R COMMAND DISPATCH

;COME HERE TO HANDLE INPUT (NO DISPLAY NEEDED OR INPUT KNOWN TO BE WAITING).
RRLP1:	TLNE FF,FLNOIN	;IF WE'RE DOING AN @V, RETURN
	 CALL RREXIT	;(DOESN'T COME BACK) AFTER DISPLAYING ONCE.
IFN ITS,CALL RRSYNC
IFN ITS,CALL RRECIN	;HAVE SYSTEM ECHO AND INSERT PRINTING CHARACTERS, MAYBE.
	CALL TYIW0	;READ A CHARACTER
	CAIN CH,TOP+"H	;IGNORE "HELP" (FS HELPMAC$ ALREADY RUN, IF APPROPRIATE),
	 JRST RRLP	;BUT DO GO TO RRLP SO SPACE WILL FLUSH HELPMAC'S TYPEOUT.
	ANDI CH,777
	MOVEM CH,$Q..0	;PUT CHAR WHERE USER MACRO DEFINITION CAN FIND IT.
	MOVEM CH,RRLAST	;ALSO PUT IT IN FS ^R LAST$.
	MOVEM CH,ECHCHR	;FOR PRINTING TTY, REMEMBER WHICH CHAR TO ECHO.
	SKIPN RGETTY
	 SKIPE RRECHO	;DECIDE WHETHER TO ECHO ^R INPUT.
	  SKIPGE RRECHO
	   CALL [CALL TYINRM	;MUST NORMALIZE CHARACTER BEFORE OUTPUTTING,
		 JRST FSECO1]
	MOVE CH,$Q..0		;(IN CASE WE CALLED TYINRM).
	SAVE [RRLP]
	CALL RRARGD	;PUT VALUE OF COMMAND'S ARG IN C.
RRLP7:	CALL RRLEA2	;NOW SET UP "RRE" VARS IN CASE RRTTY CALLED AFTER CMD.
	MOVE TT,QRB..
	SETZM .QVWFL(TT)	;COMMAND WILL SET ..H TO SAY ^R SHOULD WAIT BEFORE DISPLAYING.
	CAMN CH,CASSFT	;F$ CASE CTL CHRS DON'T HAVE FIXED VALUES.
	 JRST RRSFT
	CAMN CH,CASLOK	;SO THE DISPATCH TABLE CAN'T CHECK FOR THEM.
	 JRST RRLOK
	CALL RRCASC	;IF IN F$ MODE, DO CASE CONVERSION.
	TRNN CH,META
	 JRST RRLP7I
	TRNE CH,CONTRL	;META NON-CONTROL CHARACTERS ALL SELF-INSERT
	 JRST RRLP7J
	SKIPLE RRRPLC	;IF IN FS ^R REPLACE$ > 0 MODE.
	 JRST RRXINS
RRLP7J:	TRNE CH,CONTRL	;CONTROL-META LETTERS SELF INSERT IF FS CTLMTA$ NEGATIVE.
	 TRNN CH,100
	  JRST RRLP7I
	SKIPGE RRCMQT
	 JRST RRXINS
RRLP7I:
;"INDIRECT" (RRINDR) DEFINITIONS LOOP BACK HERE.
RRIND1:	MOVE E,RRMACT(CH)	;GET CURRENT DEFINITION OF CHARACTER.
	SKIPL RRALQT	;UNLESS DEFINITIONS ARE SUPPRESSED,
	SKIPGE RRUNQT
	 JRST RRLP7D	;USE THE DEFINITION
	CAME CH,RRALQT	;ELSE IF THIS IS NOT THE UNQUOTING CHAR,
	 JRST RRLP7B	;MAKE IT SELF-INSERTING.
	SETOM RRUNQT	;IF IT IS, REENABLE DEFINITIONS FOR 1 COMMAND.
	SETZM RRLAST	;DON'T FLUSH NEXT COMMAND'S ARGUMENT.
	RET

;DEFINITION OF "NORMAL SELF-INSERTING" CHARACTERS.
RRXINS:	SKIP
	SKIPN E,RRXINV		;GET THE DEFINITION INTENDED FOR SUCH CHARACTERS
	 MOVE E,[RRDINS,,RRREPI] ;OR THE DEFAULT DEFINITION,
	SAVE C
	SAVE CH
	CALL RRLP7D		;AND RUN IT.
	 TRNE FF,FRARG
	  AOS -2(P)
	CALL SKNBCP		;IF THE CHARACTER HAS THE LISP SYNTAX OF CLOSEPAREN,
	REST A
	REST C
	JUMPE C,RRXIN1		;AND OUR ARGUMENT WAS NOT ZERO,
	ILDB CH,SKNBPT
	SKIPE RGETTY
	 SKIPN A,RRPARN
	  JRST RRXIN1
	CAIN CH,")
	 CALL RRMACR		;THEN RUN THE CLOSEPAREN MATCHING MACRO.
	  JFCL
RRXIN1:	SETZ A,
	RET

;HANDLE A CHARACTER IN SUPPRESS MODE.
RRLP7B:	JUMPL E,RRLP7E	;IF ITS DEF. IS A MACRO, SEE WHETHER IT STARTS WITH "W".
	MOVEI A,(E)
	CAIE A,RRINDR
	CAIN CH,177
	 JRST RRLP7D	;RUBOUT WORKS EVEN IN SUPPRESS MODE.
RRLP7F:	CAIN CH,CONTRL+"M ;OTHER CHARS BECOME SELF-INSERTING.
	 SKIPA E,[RRCRLF,,RRREPT]
	  JRST RRXINS
RRLP7D:	SKIPGE A,E	;COME HERE TO USE WHATEVER DEFINITION IS IN E.
	 JRST RRMAC0	;EITHER A MACRO OR A BUILT-IN FUNCTION.
RRLP7H:	TRZ FF,FRCLN\FRUPRW
	LDB A,[331100,,(E)] ;BUILT-INS MUST START WITH A "SKIP" (THAT DOESN'T SKIP EVER).
IFN ITS,CAIE A,.BREAK_-33 ;DON'T BE CONFUSED BY BREAKPOINTS.
IFN TNX,CAIE A,JSYS_-33	;BPT MAYBE?
	 CAIN A,SKIP_-33
	  JRST (E)
	TYPRE [M%R]

RRLP7E:	MOVE A,E	;MACRO-CHAR. TYPED IN SUPPRESS MODE.
	CALL QLGET1
	 JRST RRLP7F
	ILDB TT,BP	;WHAT IS ITS 1ST CHARACTER?
	CAIE TT,"W+40
	 CAIN TT,"W	;IF IT DOESN'T START WITH A "W"	THEN THE DEFINITION IS SUPPRESSED.
	  JUMPG B,RRLP7D	;IF IT STARTS WITH "W", THEN EXECUTE DEFINITION EVEN IN SUPPRESS MODE.
	JRST RRLP7F

;TELL THE TERMINAL WHEN (AND HOW) TO DO LOCAL EDITING.

IFN ITS,[
RRSYNC:	SKIPN LEDEFS		;IF FS LEDEFS IS CLEARED, IMMEDIATELY STOP USING LEP.
	 RET
	SKIPE INCHSY		;IF TERMINAL IS DOING SYNCHRONIZATION,
	 SKIPN MODIFF		;AND BUFFER ALREADY MODIFIED SO NO NEED TO WRITE A STAR,
	  JRST RRSYNX
	SKIPGE UNRCHC		;AND THERE IS NO INTERNALLY GENERATED INPUT
	 SKIPE TYISRC		;AVAILABLE
	  RET
	SKIPE JRNIN
	 SKIPE JRNINH
	  CAIA
	   RET
	MOVE CH,INCHCT		;BUT THE LAST INPUT CHARACTER WAS NOT PRE-ECHOED,
	CAMG CH,INCHEC
	 RET
	SUBI CH,210.
	CAML CH,INCHSY		;AND THE LAST RESYNCH WE RECEIVED WAS RECENT ENOUGH
	 JRST RRSYNX		;(OTHERWISE WE SHOULD ASK FOR A NEW ONE),
	.STATUS CHTTYI,CH	;AND THERE IS NO TTY INPUT AVAILABLE,
	ANDI CH,2000
	JUMPE CH,CPOPJ
;OK, WE CAN REQUEST LOCAL ECHO NOW.
;FIRST, TELL TERMINAL ABOUT ANY COMMANDS THAT HAVE BEEN REDEFINED.
RRSYN0:	MOVE C,LEDEFS
	TRO FF,FRARG
	CALL FDATTY
	 .VALUE
	JUMPL A,CPOPJ		;VALUE IS A NUMBER.  GIVE UP.
	CAIE A,1
	 JRST [	MOVE A,LEDEFS	;VALUE IS A STRING.  EXECUTE IT AND LOOK AGAIN.
		CALL RRMAC0	;THE STRING SHOULD SET LEDEFS TO A QVECTOR.
		 JFCL
		JRST RRSYN0]
	MOVE C,LEDEFS
	CALL QBGET		;IT'S A QVECTOR.  FIND ITS DATA.
	MOVE IN,MFBEG(B)	;GET STARTING AND ENDING WORD ADDRESS
	TLZ IN,777700
	IDIVI IN,5		;IN IN AND OUT.
	MOVE OUT,MFZ(B)
	IDIVI OUT,5
	SKIPL LEINIT		;IF MUST REINIT EVERYTHING, SEND COMMAND TO DO SO.
	 JRST RRSYN6
	.IOT CHSIO,[%TDEDF]
	.IOT CHSIO,[33_2]		;THEN, INSTEAD OF SENDING FOR ALL CHANGED CHARS,
	.IOT CHSIO,[0]		;SEND ALL CHARS WHOSE DEFNS ARE NOT IN THE INITIAL STATE.
	SETZM WRDMSK		;SET WRDMSK TO REFLECT WHAT THE TERMINAL WILL DO TO IT
	MOVE A,[<1777_26.>_-20]	;AFTER IT RECEIVES THAT %TDEDF TO RESET EVERYTHING.
	MOVEM A,WRDMSK+1	;THAT IS TO SAY, JUST DIGITS AND LETTERS GO IN WORDS.
	MOVE A,[377777,,777000]
	MOVEM A,WRDMSK+2
	MOVEM A,WRDMSK+3
	MOVEI A,1		;RESETTING TERMINAL PUTS IT INTO INSERT MODE.
	MOVEM A,INSMOD
	SETZM TBOTMAR
;NOW SEND OUT DEFINITIONS FOR ALL COMMAND CHARS
;WHICH EITHER 1) HAVE CHANGED (IF THIS IS NOT THE FIRST RESYNCH REPLY)
;OR 2) DON'T MATCH THE STANDARD INITIAL DEFINITIONS (IF THIS IS THE FIRST TIME).
RRSYN6:	CALL SKNBCP		;SET UP SKNBPT TO LDB LISP SYNTAXES.
	IBP SKNBPT
	SETZ A,			;A COUNTS CHAR WE ARE CONSIDERING.
	MOVE B,[040100,,RDFMSK-1] ;B IS BP TO FETCH FROM RDFMSK.
RRSYN1:	TRNN A,37
	 SUB B,[040000,,]	;DON'T USE LOW 4 BITS OF EACH RDFMSK WORD.
	ILDB C,B
	SKIPL LEINIT		;OR ARE WE REINITIALIZING?
	 JUMPE C,RRSYN2		;OR HAS THIS CHAR BEEN REDEFINED?
	MOVE CH,RRMACT(A)	;GET THE NEW DEFINITION AND LOOK IT UP IN LEDEFS.
	MOVE Q,IN
RRSYN4:	CAML Q,OUT
	 JRST [	SETZ CH,	;DEFN IS NOT LISTED - USE FUNCTION CODE 0
		JRST RRSYN3]	;(NO LOCAL EDITING POSSIBLE).
	CAME CH,(Q)
	 AOJA Q,[AOJA Q,RRSYN4]
	MOVE CH,1(Q)		;WE FOUND IT - GET CORRESP %TDEDF FUNCTION CODE.
	LDB C,[0700,,A]
	LDB D,SKNBPT
	CAIN D,")		;CLOSEPAREN CHARS CAN'T BE HANDLED LOCALLY
	 SKIPN RRPARN		;IF THEY ARE SUPPOSED TO DISPLAY WHAT THEY MATCH.
	  CAIA
	   JRST RRSYND
	CAIE C,177		;IF IT'S A RUBOUT
	 CAIGE C,40		;OR A CONTROL CHAR, DON'T ALLOW SELF-INSERT
	  CAIN C,33		;UNLESS IT'S AN ALTMODE.
	   JRST RRSYN3
RRSYND:	CAIN CH,7		;REPLACE SELF-INSERTING WITH "NO LOCAL HANDLING".
	 SETZ CH,
RRSYN3:	SKIPL LEINIT		;IF WE ARE REPORTING INCREMENTAL CHANGES,
	 JRST RRSYN5		;CERTAINLY REPORT THIS CHAR -- IT CHANGED.
	MOVEI Q,7
	CAIL A,40		;IF WE ARE REINITIALIZING, REPORT CHAR
	 CAIL A,177		;ONLY IF ITS STATE DOES NOT MATCH THE INITIAL ONE.
	  SETZ Q,
	CAIL C,"0		;DIGITS WITH CONTROL OR META ARE ARG-SPECIFIERS.
	 CAILE C,"9
	  JRST RRSYNA
	TRNE A,600		;BUT NOT PLAIN DIGITS.
	 MOVEI Q,27
RRSYNA:	CAIL C,"a		;LOWER CASE LETTERS, PLUS ANY CONTROL/META BITS,
	 CAILE C,"z		;ARE DEFINED AS EQUIVALENCES IN THE INITIAL STATE.
	  CAIA
	   MOVEI Q,22
	CAMN CH,Q
	 JRST RRSYN2
RRSYN5:	LSH CH,9
	ADD CH,A		;MERGE CHARACTER AND FUNCTION CODE TOGETHER,
	LDB Q,[070700,,CH]	;MAKE TWO 7-BIT BYTES, AND SEND A %TDEDF.
	ANDI CH,177
	.IOT CHSIO,[%TDEDF]
	.IOT CHSIO,Q
	.IOT CHSIO,CH
RRSYN2:	CAIE A,777		;CONSIDER NEXT CHARACTER.
	 AOJA A,RRSYN1
	SETZM RDFMSK		;ALL NEW DEFINITIONS REPORTED; SO
	MOVE A,[RDFMSK,,RDFMSK+1]	;MARK ALL CHARS AS UP-TO-DATE.
	BLT A,RDFMSK+17
;NOW TELL THE TERMINAL ANY WORD SYNTAXES THAT HAVE CHANGED
;FROM THE PREVIOUS SETTING OR THE INITIAL SETTING.
	CALL SKNBCP		;SET UP SKNBPT TO LDB WORD SYNTAXES.
	SETZ A,
	MOVE IN,[040100,,WRDMSK-1]
RRSYN7:	TRNN A,37		;SKIP OVER BOTTOM 4 BITS IN EACH WRDMSK WORD.
	 SUB IN,[040000,,]
	LDB B,SKNBPT		;GET WORD SYNTAX OF NEXT CHAR.
	SETZ C,			;CONVERT TO 1 IF PART OF WORD, 0 IF SEPARATOR, IN C.
	CAIN B,"A
	 MOVEI C,1
	ILDB CH,IN		;GET TERMINAL'S IDEA OF WORD SYNTAX,
	DPB C,IN		;RECORD NEW SYNTAX.
	CAMN C,CH		;IF THEY DON'T MATCH, TELL THE TERMINAL.
	 JRST RRSYN8
	.IOT CHSIO,[%TDEDF]
	ADDI C,31_2
	.IOT CHSIO,C
	.IOT CHSIO,A
RRSYN8:	CAIE A,177
	 AOJA A,RRSYN7
;NOW TELL THE TERMINAL WHETHER WE ARE IN INSERT MODE,
;IF IT HAS CHANGED.
	MOVEI A,2
	SKIPN RRRPLC
	 MOVEI A,1
	SKIPE RRXINV		;IF FS ^R NORMAL IS NONZERO,
	 SETZ A,		;"SELF-INSERTING" CHARACTERS CAN'T BE HANDLED BY TERMINAL.
	EXCH A,INSMOD
	CAMN A,INSMOD
	 JRST RRSYN9
	.IOT CHSIO,[%TDEDF]
	.IOT CHSIO,[32_2]
	.IOT CHSIO,INSMOD
RRSYN9:	MOVE A,NVLNS
	SUB A,BOTLIN
	EXCH A,TBOTMAR
	CAMN A,TBOTMAR
	 JRST RRSYNB
	.IOT CHSIO,[%TDEDF]	;TELL THE TERMINAL HOW MANY LINES AT SCREEN
	.IOT CHSIO,[34_2+3]	;BOTTOM ARE NOT BEING USED FOR EDITING.
	.IOT CHSIO,TBOTMAR
RRSYNB:
;NOW TERMINAL KNOWS THE RIGHT COMMANDS; TELL IT TO START LOCAL EDITING.
	.IOT CHSIO,[%TDSYN]	;OUTPUT A SYNCH MARKER AND SAY HOW MANY
	.IOT CHSIO,INSYNC	;CHARS OF INPUT WE HAVE READ SINCE
	MOVE CH,INCHCT		;WE RECEIVED THE REQUEST FOR ONE.
	SUB CH,INCHSY
	.IOT CHSIO,CH
	SETZM LEINIT		;WE HAVE FINISHED REINITTING (IF WE WERE).
	RET

RRSYNX:	SETZM INCHSY		;IF NO RECENT RESYNCH, FORGET ALL RESYNCHS,
	SETOM INCHEC		;CERTAINLY NOT PROCESSING PRE-ECHOED CHARS ANY MORE.
	SETOM LEINIT		;IF WE GET SYNCHED AGAIN, MUST RE-INIT ALL CHAR DEFNS.
	MOVE CH,TTYSMT
	TRNN CH,%TRLED		;BUT IF THE TERMINAL HAS THE CAPABILITY,
	 RET			;ASK FOR A RESYNCH.
	MOVE CH,INCHCT
	CAMG CH,INCHRQ		;BUT DON'T ASK TOO OFTEN!
	 RET
	ADDI CH,1000.		;NO MORE THAN EVERY 1000 CHARS.
	MOVEM CH,INCHRQ
	 .IOT CHSIO,[%TDECO]
	SYSCAL SCPOS,[%CLIMM,,CHTTYI ? %CLBIT,,1]
	 .LOSE %LSFIL		;TELL ITS TO ALLOW TOP-E AND TOP=S THROUGH AS INPUT.
	RET
]

SUBTTL ^R CHARACTER FORWARD/BACKWARD

;^B - MOVE BACKWARDS ONE CHARACTER.
;UPDATES RRHPOS AND RRVPOS.  LEAVES THE CHAR MOVED OVER IN CH.
;LEAVES PT IN IN. CLOBBERS OUT, TT, TT1, A, B, C.
RRBACK:	MOVE IN,BEGV	;ERROR IF AT BEGINNING OF BUFFER.
	CAML IN,PT
	 JRST RRERR
RRBAC4:	SOS IN,PT	;GET THE CHAR BEFORE THE PTR
	CALL GETCHR
RRBAC0:	RRCHRG		;GET CHAR'S DISPATCH TYPE CODE IN A.  CLOBBERS B.
	XCT RRBACT(A)
RRBAC1:	 SOS A,RRHPOS
	JUMPGE A,CPOPJ
RRBAC3:	ADD A,NHLNS	;MOVED OVER LINE-CONTINUATION.
	MOVEM A,RRHPOS	;GO BACK TO PREV. LINE'S END.
RRBACV:	SOS RRVPOS
	POPJ P,

RRBACT:	SOSA A,RRHPOS	;ORD. CHAR., BACK 1 POS.
	JRST RRBACC	;NON-FORMATTING CONTROL CHARS.
	JRST RRBACH	;^H, CHECK ^HPRINT FLAG.
	JRST RRBACR	;^M, SPECIAL.
	JRST RRBACL	;^J, UP 1 LINE.
	SAVE [RRBTCR]	;TAB, COMPUTE RRHPOS BY MOVING FWD
			;FROM PREVIOUS CR.
	JRST RRBAC2	;2-POS CTL CHARS NO AFFECTED BY FS SAIL (^P AND ^C).

RRBACR:	ADDI IN,1	;CR: IS IT FOLLOWED BY LF?
	CALL GETCHR
	MOVEI A,(CH)
	MOVEI CH,^M
	CAMGE IN,ZV
	 CAIE A,^J	;IF THIS CR REALLY CAME OUT AS CR,
	  SKIPGE DISPCR
	   JRST RRBTCR	;COMPUTE HPOS THE HARD WAY.
	SUBI IN,1
RRBAC2:	SOS RRHPOS	;IF IT CAME OUT AS UPARROW-M,
	JRST RRBAC1	;TREAT AS 2-POS CTL CHAR.

RRBACL:	SUBI IN,1	;LF: SEE IF PREV. CHAR IS CR.
	CALL GETINC
	MOVEI A,(CH)
	MOVEI CH,^J
	CAML IN,BEGV
	 CAIE A,^M	;BASED ON THAT AND ON DISPCR, DECIDE HOW LF WAS PRINTED OUT.
	  SKIPGE DISPCR
	   JRST RRBACV
	JRST RRBAC2

RRBACH:	SKIPL DISPBS	;MOVE BACK OVER ^H - IF IT CAME OUT AS
	 JRST RRBACC	;UPARROW-H, TREAT AS ORDINARY CTL CHAR.
	MOVE A,RRHPOS	;ELSE, IF WE KNOW IT CAME OUT AS A BACKSPACE, IT'S SIMPLE.
	CAIG A,2
	 JRST RRBTCR	;NEAR MARGIN, WE CAN'T BE SURE, SO MUST SCAN FORWARD.
	AOS RRHPOS
	RET

;NON-FORMATTING CONTROL CHARS, CHECK SAIL FLAG.
RRBACC:	SKIPN DISSAI
	 JRST RRBAC2	;NORMALLY, MOVE BACK 2 POS.
	JRST RRBAC1	;IN SAIL MODE, MOVE 1 POS.

;^F -- MOVE FWD 1 CHAR.  SEE THE COMMENTS BEFORE RRBACK.
RRFORW:	MOVE IN,PT	;ERROR IF AT END OF BUFFER.
	CAML IN,ZV
	 JRST RRERR
	CALL GETINC
RRFOR0:	AOS PT
	RRCHRG
	XCT RRFORT(A)	;DISPATCH ON TYPE OF CHAR.
RRFOR1:	 AOS A,RRHPOS
RRFOR3:	CAMGE A,NHLNS	;HAVE WE MOVED PAST RIGHT MARGIN?
	 POPJ P,
	CAMN A,NHLNS	;CHECK FOR JUST REACHING THE RIGHT MARGIN.
	 JRST [	SAVE CH	;IF REACH RIGHT MARGIN, MUST
		MOVE IN,PT	;CONTINUE PROVIDED WE'RE NOT AT
		CALL RREOLT	;THE END OF THE LINE.
		 JRST POPCHJ	;AT END OF LINE, NOTHING TO DO.
		REST CH		;NOT AT EOL, CONTINUE.
		MOVE A,RRHPOS
		JRST .+1]
	SUB A,NHLNS
	MOVEM A,RRHPOS
RRFORV:	AOS RRVPOS
	POPJ P,

RRFORT:	AOSA A,RRHPOS	;ORDINARY CHAR, MOVE FWD 1 POS.
	JRST RRFORC	;NON-FORMATTING CONTROLS.
	JRST RRFORH	;MOVE FWD OVER ^H - CHECK ^HPRINT FLAG.
	JRST RRFWCR	;^M, SPECIAL.
	JRST RRFORL	;^J, DOWN 1 LINE.
	JRST RRFOTB	;^I
	JRST RRFOR2	;2-POS CTL CHRS NOT AFFECTED BY FS SAIL (^P AND ^C).

RRFOTB:	MOVE TT,RRHPOS
	MOVE A,TT
	CAMN TT,NHLNS
	 SETZ A,
	ADD A,TABWID
	IDIV A,TABWID
	IMUL A,TABWID	;A GETS POSITION OF NEXT TAB STOP.
	CAMLE A,NHLNS	;BUT IF THAT'S OFF THE SCREEN, TAB STOP IS RIGHT MARGIN
	 MOVE A,NHLNS
	CAMN TT,NHLNS	;IF WE STARTED AT THE MARGIN, TREAT MARGIN AS COLUMN 0.
	 ADD A,NHLNS
	MOVEM A,RRHPOS
	JRST RRFOR3

RRFWCR:	SKIPGE DISPCR
	 JRST RRFWC1
	CALL GETCHR	;CR - SEE IF NEXT CHAR IS LF.
	MOVEI A,(CH)
	MOVEI CH,^M	;MAKE SURE WE RETURN CHAR BEING PASSED IN CH.
	CAMGE IN,ZV
	CAIE A,^J
	 JRST RRFOR2	;NO, CR CAME OUT AS UPARROW-M
RRFWC1:	SETOM RRHPOS	;(RRHPOS WILL BE AOS'D TO 0)
	JRST RRFOR1

RRFORL:	SKIPGE DISPCR	;LF: BASED ON WHETHER A CR PRECEDES IT AND ON DISPCR,
	 JRST RRFORV
	SUBI IN,2
	CALL GETCHR	;DECIDE HOW THE LF CAME OUT AND THEREFORE
	MOVEI A,(CH)
	MOVEI CH,^J
	MOVE TT,IN
	ADDI IN,2
	CAML TT,BEGV
	 CAIE A,^M	;HOW TO MOVE OVER IT.
	  JRST RRFOR2
	JRST RRFORV

RRFORH:	SKIPGE DISPBS	;MOVING FWD OVER ^H -IF CAME OUT AS
	 SKIPN RRHPOS
	  JRST RRFORC
	JRST RRBAC1	;REAL ^H, MOVE BACK 1 POS

;NON-FORMATTING CONTROLS, CHECK FS SAIL FLAG.
RRFORC:	SKIPE DISSAI	;IN SAIL MODE, THEY'RE 1-POS GRAPHICS.
	 JRST RRFOR1
RRFOR2:	AOS RRHPOS	;ELSE TREAT AS 2-POS CTL CHAR.
	JRST RRFOR1

;MAKE SURE RRHPOS IS CORRECT BY MOVING BACK TO THE LAST CR THAT
;REALLY CAME OUT AS A CR, AND MOVING FORWARD AGAIN. PT IS UNCHANGED.
;THE LARGEST HPOS THAT OCCURS ON THE LINE UP TO PT IS RETURNED IN OUT.
;PT IS RETURNED IN IN.  CLOBBERS TT, TT1.
;A CONTAINS ADDR OF THE CR WE WENT BACK TO (+1), AND B HAS VPOS DIFFERENCE FROM THERE.
RRBTCR:	SAVE CH
	SAVE RRVPOS	;VPOS WILL BE ALTERED WHILE WE MOVE FWD
			;BUT WE REALLY DON'T WANT IT CHANGED.
RRBTC5:	SAVE PT		;REMEMBER WHERE TO STOP WHEN MOVE FWD AGAIN.
	MOVE A,GEA	;1ST, FIGURE OUT WHERE TO STOP MOVING BACKWARD
	ADD A,BEGV	;IF WE DON'T FIND A CR. 1ST CHAR ON SCREEN
			;IS ONE PLACE. BEGINNING OF BFR IS ANOTHER.
	SKIPL GEA
	CAMLE A,PT	;(AT BOTH PLACES, HPOS MUST BE 0)
	 MOVE A,BEGV	;USE WHICHEVER WE'LL REACH SOONER.
	MOVE B,PT	;STOP IN ANY CASE AFTER MOVING BACK 10000 CHARS.
	SUBI B,10000.	;AT THAT POINT, BETTER TO CHOOSE A NEW WINDOW AND START OVER!
	CAMG B,A	;NOW B GETS WHICHEVER OF THOSE TWO STOPPING POINTS IS REACHED FIRST.
	 MOVE B,A
	SETZ OUT,	;ON 1ST PASS OUT=-1 => AN LF HAS BEEN PASSED GOING BACKWARDS.
RRBTC0:	MOVE IN,PT
	CAMG IN,B	;REACHED A STOPPING POINT => WHICH KIND?
	 JRST [	CAMN B,A	;A LEGITIMATE ONE (BEG OR TOP OF SCREEN) =>
		 JRST RRBTC1	;WE CAN JUST SCAN FORWARD FROM THERE.
		REST PT
		CALL [	CALL SAVACS
			SETO A,
			CALL VBDBLS	;ELSE, COMPUTE A NEW TOP OF SCREEN
			JRST RSTACS]
		JRST RRBTC5]	;AND TRY AGAIN.
	SOS IN,PT
	CALL GETINC	;ELSE, KEEP GOING BACK.
	CAIN CH,^J
	 SETO OUT,	;REACHED LF => SAY NOT ON LINE WE STARTED ON.
	CAIE CH,^M	;REACHED CR => SEE WHETHER IT CAME OUT AS ONE.
	 JRST RRBTC0
	JUMPE OUT,RRBTC0 ;BUT DON'T STOP AT ANY CR IF WE HAVEN'T GONE UP AT LEAST ONE LINE.
	SKIPGE DISPCR
	 JRST RRBTC4
	CALL GETCHR
	CAIE CH,^J
	 JRST RRBTC0
	AOS PT		;START AFTER THE CR AND THE LF.
RRBTC4:	AOS PT		;START AFTER THE CR.
RRBTC1:	SETZB OUT,RRHPOS ;AT THE CR, KNOW HPOS IS 0.
	SAVE PT		;REMEMBER WHERE WE WENT BACK TO, TO RETURN IT IN A.
	SAVE RRVPOS
RRBTC2:	MOVE IN,PT	;REACHED WHERE WE STARTED?
	CAMN IN,-2(P)
	 JRST RRBTC3	;YES, FLUSH STACK & EXIT.
	CALL RRFORW	;MOVE FWD TILL GET THERE.
	MOVE A,RRVPOS	;IF WE'VE MOVED TO ANOTHER LINE,
	CAME A,(P)
	 JRST [	MOVEM A,(P)	;THEN THE CHARS SEEN SO FAR ARE NOT ON THE SAME
		SETZ OUT,	;LINE RRBTCR STARTED ON, SO THEY DON'T COUNT
		JRST RRBTC2]	;IN OUT'S VALUE.
	CAML OUT,RRHPOS	;IF CURRENT HPOS IS > LARGEST SO FAR,
	 JRST RRBTC2
	MOVE OUT,RRHPOS	;UPDATE MAXIMUM-HPOS-ON-CURRENT-LINE.
	JRST RRBTC2

RRBTC3:	REST B		;RETURN IN B THE VPOS DIFFERENCE WE MOVED OVER.
	REST A		;RETURN IN A THE ADDR OF WHERE WE WENT BACK TO.
	SUB P,[1,,1]
	REST RRVPOS
	SUB B,RRVPOS
	JRST POPCHJ

SUBTTL ^R MODE SYSTEM ECHO FOR SELF-INSERTING CHARACTERS

IFN ITS,[
RRECIN:	SKIPN RRMAXP		;SYSTEM ECHO CAN'T BE USED IF WE HAVE PENDING REDISPLAY.
	 SKIPL RRMSNG
	  RET
	SKIPN INCHRQ		;IF WE ARE OR EXPECT TO BE ALLOWING TERMINAL LOCAL EDITING,
	 SKIPE INCHSY		;DON'T USE ECHOIN, OR IT WOULD GOBBLE THE TOP-S RESYNCH.
	  RET
	MOVE A,RRVPOS		;CAN'T SYSTEM ECHO IF THERE'S AN ARGUMENT,
	SKIPN RRARGP		;OR IF ON A SCREEN LINE WHICH DOESN'T REALLY EXIST.
	 CAML A,BOTLIN
	  RET
	SKIPE MODIFF		;NOT MODIFIED => FIRST INSERTION MUST CHANGE MODE LINE.
	 SKIPE READON		;DON'T ALLOW INSERTION IN READ-ONLY BUFFER.
	  RET
	MOVE IN,PT
	CAMN IN,GPT		;ECHOING ALLOWED ONLY IF THE GAP IS AT POINT, AND NONEMPTY,
	 SKIPN EXTRAC
	  RET
	SKIPE CASNRM		;CAN'T USE ECHOIN IF CASE CONVERSION DESIRED.
	 RET
	SKIPGE CASSFT
	 SKIPL CASLOK
	  RET
	MOVE D,NHLNS		;COMPUTE HPOS AT WHICH SYSTEM ECHOING MUST STOP
	MOVE A,RRMACT+40	;(WHICH DEPENDS ON WHETHER AUTO-FILL IS ON.
	CAMN A,RRECSD		; CHECK THE DEFINITION OF SPACE TO FIND OUT).
	 MOVE D,ADLINE
	CAMLE D,RRHPOS		;CAN'T USE SYSTEM ECHOING IF AT OR PAST THAT POINT.
	 SKIPE TYISNK		;CAN'T USE ECHOING WHILE DEFINING A KEYBOARD MACRO.
	  RET			;(WE COULD MAKE RRECI5 HANDLE IT, BUT WHAT IF
				; TYI SINK GETS AN ERROR ON ONE OF THE CHARS?
				; YOU SHOULD FIND OUT RIGHT AWAY).
	CAME A,RRECSD		;IF WE ARE USING AUTO-FILL SPACE,
	 JRST RRECIA
	MOVE IN,RRVPOS		;CAN'T SYSTEM ECHO IF IN A CONTINUATION LINE.
	MOVE IN,LINBEG(IN)
	SUBI IN,2		;LOOK AT THE TWO CHARACTERS BEFORE START OF THIS SCREEN LINE
	CAMGE IN,BEGV		;(IF STARTS AT BEG OF BUFFER, IT CAN'T BE A CONTINUATION)
	 JRST RRECIA
	CALL GETINC		;IF THE CHARS ARE NOT CRLF, WE CAN'T SYSTEM ECHO.
	CAIE CH,^M
	 RET
	CALL GETCHR
	CAIE CH,^J
	 RET
RRECIA:	SKIPGE UNRCHC		;CAN'T SYSTEM ECHO IF ALREADY HAVE INPUT TO PROCESS.
	 SKIPE JRNIN		;DON'T READ FROM TTY WHILE READING A JOURNAL FILE.
	  RET
	SKIPN TYISRC		;CAN'T USE ECHOIN IF EXECUTING A KBD MACRO (!)
	 SKIPE RRXINV		;CAN'T USE ECHOIN IF ALL "NORMAL" CHARACTERS ARE NOW FUNNY.
	  RET
	MOVE IN,PT
	CALL RREOLT		;ECHOING IS GOOD ONLY AT THE END OF A LINE.
	 CAIA
	  RET
	.LISTEN A,		;WAIT FOR OUTPUT TO FINISH.  IF THERE IS OUTPUT WAITING,
				;THEN ECHOING MIGHT BE DELAYED, AND A BREAK CHARACTER COULD
				;COME IN, AND ITS OUTPUT MIGHT HAPPEN BEFORE THE ECHOING!
	JUMPN A,CPOPJ		;DON'T BOTHER COMPUTING BREAK TABLES IF NON-ECHOED INPUT HERE.
;COMPUTE THE BREAK TABLE.
	SETZM SKNBPT
	SKIPE RRPARN		;IF WE HAVE A CLOSEPAREN MACRO TO BE HACKED,
	 CALL SKNBCP		;GET POINTER TO LDB LISP SYNTAX OF CHAR IN A.
	IBP SKNBPT
	SETZ A,			;A SAYS WHICH ASCII CHARACTER.
RRECI1:	MOVSI B,400000		;B IS THE BIT FOR THAT CHARACTER.
	SETO C,			;C IS THE BIT MASK BEING CONSTRUCTED.
	MOVEI TT,RRXINS		;TT IS WHAT A NORMAL CHARACTER'S DEFINITION LOOKS LIKE.
RRECI2:	CAMN TT,RRMACT(A)	;PROCESS 32 CHARS.  MAKE A BIT MASK SAYING
	 ANDCM C,B		;WHICH OF THEM ARE NOT NORMAL SELF-INSERTING CHARACTERS.
	LDB CH,SKNBPT		;IF CLOSEPAREN CHARS RUN A MACRO, AND THIS CHAR IS ONE,
	CAIN CH,")		;THEN IT CAN'T BE ECHOED.  NOTE THAT IF THERE IS NO MACRO,
	 IOR C,B		;SKNBPT WILL BE ZERO SO CH WILL BE ZERO.
	LSH B,-1
	AOS A
	TRNE A,37
	 JRST RRECI2
	PUSH P,C		;PUSH THE NEXT WORD OF BIT MASK ON THE STACK,
	CAIE A,140		;THEN MAKE ANOTHER WORD FOR THE NEXT 32 CHARACTERS.
	 JRST RRECI1
	MOVSI B,400000		;LOWER CASE ARE DIFFERENT SINCE THEY CAN BE INDIRECT.
	MOVE TT1,[40,,RRINDR]
RRECI3:	CAME TT1,RRMACT(A)	;SO START FROM THE WORD FOR UPPER CASE CHARS, AND TURN ON
	 IOR C,B		;THE BIT FOR ANY LOWER CASE CHAR THAT FAILS TO INDIRECT.
	CAMN TT,RRMACT(A)	;BUT TURN IT OFF FOR ANY THAT IS SELF INSERTING
	 ANDCM C,B		;IN ITS OWN RIGHT (SUCH AS BRACES, TILDE, ETC).
	LDB CH,SKNBPT		;IF CLOSEPAREN CHARS RUN A MACRO, AND THIS CHAR IS ONE,
	CAIN CH,")		;THEN IT CAN'T BE ECHOED.  NOTE THAT IF THERE IS NO MACRO,
	 IOR C,B		;SKNBPT WILL BE ZERO SO CH WILL BE ZERO.
	LSH B,-1
	AOS A
	CAIE A,200
	 JRST RRECI3
	PUSH P,C
	SKIPN DISSAI		;IF NOT IN SAIL MODE, CHARS 0-37 CAN'T BE INSERTED BY ECHOIN.
	 SETOM -3(P)
	MOVSI A,400000		;IF SPACE'S DEFINITION EQUALS FS ^R EC SP, WE CAN ECHO IT.
	MOVE B,RRMACT+40
	CAMN B,RRECSD
	 ANDCAM A,-2(P)
;THE BREAK TABLE IS PUSHED.  HOW MANY CHARACTERS CAN WE HANDLE?
	MOVE B,D
	SUB B,RRHPOS		;B GETS MAX NUMBER OF CHARACTERS TO HANDLE,
	CAML B,EXTRAC		;WHICH CAN'T BE MORE THAN SIZE OF GAP.
	 MOVE B,EXTRAC
	MOVE E,QRB..
	SKIPE .QCRMC(E)		;IF WE HAVE A ..F MACRO,
	 SKIPG E,RRMCCT		;DON'T DO ECHOIN PAST TIME WHEN IT SHOULD RUN.
	  JRST RRECI6
	CAML B,RRMCC1
	 MOVE B,RRMCC1
RRECI6:	MOVE BP,PT
	CALL GETIBP		;BP GETS B.P. TO WHERE TO PUT THEM.
	MOVEM BP,RRECBP		;SAVE OLD VALUE SO WE CAN SEE, AFTERWARD, WHAT GOT INSERTED.
	MOVE E,PT
;THIS LABEL USED BY INTERRUPT ROUTINES TO SEE IF WE ARE INSIDE THE ECHOIN, AND EXIT IT IF SO.
RRECI7:	SYSCAL ECHOIN,[%CLIMM,,CHTTYI ? BP ? B ? %CLIMM,,-3(P) ? %CLIMM,,BEG]
	 JFCL
	MOVE T,PT
	SUB T,E			;T HAS NUMBER OF CHARACTERS INSERTED.
	JUMPE T,RRECIX		;0 => CAN JUST EXIT, BUT MAKE SURE RRECBP IS 0.
	MOVE A,T
	MOVE TT,RRECBP
	MOVE BP,RRVPOS
RRECI8:	ILDB CH,TT		;SCAN THE CHARACTERS INSERTED,
	CALL CHCTHI		;ADDING THEM TO HACH CODE
	AOS RRHPOS		;AND INCREMENTING THE HPOS.
	SOJG A,RRECI8
	CALL RRINS3		;UPDATE LINBEGS OF FOLLOWING LINES.  ARGS ARE BP AND T.
	MOVE TT,RRHPOS
	MOVE BP,RRVPOS		;UPDATE HPOS OF END OF LINE.
	MOVEM TT,LINEND(BP)
	MOVEM TT,RROHPO		;ALSO NOTE THAT THE TERMINAL CURSOR IS WHERE IT OUGHT TO BE.
	CALL RRECI5		;PUT INSERTED CHARS INTO THE TYPE-IN RING BUFFER.
	MOVE TT,INCHCT		;COUNT ALL OF THESE CHARACTERS AS PROCESSED BY ^R,
	MOVEM TT,INCHRR		;SO THAT THE NEXT COMMAND DOESN'T ECHO THEM.
RRECIX:	SETZM RRECBP		;CLEAR THIS, OR ELSE ^Z $G WOULD DO RANDOM THINGS.
POP4J:	SUB P,[4,,4]
	RET

;FIND ALL THE CHARS JUST INSERTED BY AN ECHOIN, AND PUT THEM IN THE TYI BUFFER.
;THIS IS CALLED ON RESTART AND BY QUITTING, IF RRECBP IS NONZERO.
RRECI5:	MOVE A,RRECBP
	MOVE BP,PT
	CALL GETIBP
	SETZM RRECBP
RRECI4:	CAMN A,BP		;SIMULATE TYPING THE INSERTED CHARACTERS IN
	 RET
	ILDB B,A		;BY PUTTING THEM IN THE TYI BUFFER RING
	MOVEM B,RRPRVC
	IDPB B,TYIBFP		;SO FS .TYINXT$ WILL SEE THEM.
	CALL TYI1
	MOVE CH,B
	SKIPE JRNOUT		;AND PUTTING THEM IN THE JOURNAL OUTPUT FILE.
	 CALL JRNOCH
	SETOM MODIFF		;ANY CHARACTERS INSERTED => BUFFER IS MODIFIED NOW.
	SETOM MODIFM
	SKIPLE RRMCCT
	 SOS RRMCC1		;ADVANCE TOWARD RUNNING SECRETARY MACRO.
	JRST RRECI4
] ;IFN ITS

SUBTTL ^R MODE ARGUMENT PROCESSING

;^U - MULTIPLY REPEAT COUNT OR WHATEVER BY 4.
RR4TIM:	SKIP
	AOS RR4TCT
	MOVEI TT,1
	JRST RRNXI2	;SET RRARGP TO SAY NON-NULL ARG.

;^V - READ IN A NUMERIC ARGUMENT.
;THE CHARS OF THE ARG ARE ECHOED IN THE ECHO AREA.
;^G CANCELS THE ARG. ANY OTHER NON-DIGIT IS TREATED AS A COMMAND
;WHICH USES THE ARG (THIS INCLUDES RUBOUT). THE ARG IS LEFT IN RRRPCT.
RRARG:	SKIP C,[0]	;WE'LL COMPUTE ARG'S VALUE IN C.
	CALL RRECSP	;TYPE A SPACE AT BOTTOM OF SCREEN.
RRARG0:	CALL TYIW0	;READ CHAR: EITHER PART OF ARG, OR NEXT COMMAND.
	MOVEM CH,$Q..0	;IF THE LATTER, IT WILL EXPECT TO BE IN Q..0.
	CAIN CH,"-
	 JUMPE C,[SAVE [RRARGN]	;1ST CHAR IS "-" => NEGATE ARG.
		  JRST RRARG1]
	CAIL CH,"0
	CAILE CH,"9
	 JRST RRARGX	;NON-DIGIT: TERMINATE ARG.
	IMUL C,IBASE	;DIGIT: PUT IT IN ARG.
	ADDI C,-"0(CH)
RRARG1:	CALL FSECO1	;AND PRINT IT IN THE ECHO AREA.
	JRST RRARG0

RRARGX:	MOVEM C,RRRPCT	;SAVE AWAY THE ARG WE READ.
	MOVEM CH,UNRCHC	;REPROCESS THE ARG-TERMINATING CHAR AS A COMMAND WITH THAT ARG
	JRST RRNXIT	;SAY THERE'S AN ARG IN RRRPCT.

RRARGN:	MOVNS RRRPCT
	RET

RRCMNS:	SKIP		;CONTROL-MINUS:  SET BIT SAYING NEGATE THE ARGUMENT.
	MOVEI TT,5
	JRST RRNXI2

RRCDGT:	SKIP TT,RRRPCT		;CONTROL-DIGITS:  ACCUMULATE AN ARGUMENT.
	IMUL TT,IBASE
	ANDI CH,77		;WIN FOR META DIGITS AND C-M-DIGITS.
	ADDI TT,-60(CH)
	MOVEM TT,RRRPCT
RRNXIT:	MOVEI TT,3
RRNXI2:	IORM TT,RRARGP
	SETZM RRLAST	;SAY THIS IS ARG-SETTING COMMAND SO WON'T CLOBBER RRPRVC OR FLUSH ARG.
	JRST POPJ1	;SKIPPING IS LIKE RETURNING ONE VALUE TO ^R.

;COMMANDS THAT WANT TO BE REPEATED A NUMBER OF TIMES EQUAL
;TO THE NUMERIC ARG DISPATCH THRU HERE.
;(THAT IS, THE DISPATCH WD HOLDS <CMD-RTN>,,RRREPT )
RRREPT:	SKIP		;TELL RRLP7H ERROR-CHECK WE'RE GOOD GUYS.
	HLRZS E		;PUT <CMD-RTN> IN RH.
RRREP1:	JUMPLE C,POPJ1	;C HAS <VALUE OF ARG>-<# TIMES ALREADY DONE>
	CAIN C,1	;IF CALLING FOR THE LAST TIME, THEN IF COMMAND SKIPS WE SHOULD.
	 JRST (E)	;(THUS RETURNING 1 VAL IF CALLED WITH M COMMAND, OR TRIGGERING RRTTY).
	SAVE E
	HRLM CH,(P)	;SAVE CMD RTN ADDR AND THE CHAR.
	SAVE C		;AND # TIMES REMAINING.
	CALL (E)	;DO IT ONCE
	 JFCL
	SKIPGE STOPF	;LET USER QUIT OUT OF C-U 100000 C-F.
	 CALL QUIT1
	REST C
	REST E
	HLRZ CH,E
	SOJA C,RRREP1

;LIKE RRREPT, BUT IF REPEAT COUNT IS > 8 THEN SAY IN ADVANCE THAT
;REDISPLAY IS NEEDED (TO INHIBIT UPDATING).
;USED TO REPEAT INSERT COMMANDS, SO THAT ^U^UA DOESN'T
;RUN SLOWLY BY TYPING OUT AN A AT A TIME.
RRREPI:	SKIP
	HLRZS E
RRREP2:	CAIG C,8
	 JRST RRREP1
	SKIPN RRMAXP	;RRMAXP=1 INHIBITS UPDATING BUT DOESN'T MARK ANY ACTUAL PART
	 AOS RRMAXP	;OF THE BUFFER AS NEEDING REDISPLAY.  THE INSERT RTN WILL CHANGE
	JRST RRREP1	;RRMAXP TO INCLUDE WHAT IT INSERTS.

;COMPUTE THE ARGUMENT FROM THE EXPLICIT ARGUMENT AND
;THE POWER-OF-4. RETURN IN C.
RRARGD:	MOVE TT,RRARGP	;GET THE EXPLICIT ARG, OR 1 IF NONE SPEC'D.
	TRNE TT,2
	 SKIPA C,RRRPCT
	  MOVEI C,1
	TRNE TT,4	;IF ^- SET THE 4 BIT, NEGATE THE ARG.
	 MOVNS C
	MOVE TT,RR4TCT	;THEN MULTIPLY BY 4 FOR EACH ^U.
	SOJGE TT,[LSH C,2 ? JRST .]
	RET

;AFTER A COMMAND, IF IT DIDN'T IDENTIFY ITSELF AS AN ARGUMENT-SETTING COMMAND
;(BY CLEARING RRLAST), FLUSH THE ARGUMENT THAT THE COMMAND USED.
RRARGF:	SKIPN TT,RRLAST	;IF THE LAST COMMAND DIDN'T PRESERVE OR MAKE AN ARG,
	 RET
	MOVEM TT,RRPRVC	;REMEMBER IT AS "PREVIOUS COMMAND" FOR NEXT COMMAND,
	SETZM RRARGP	;SAY TO GIVE NEXT COMMAND THE DEFAULT ARG (1)
	SETZM RR4TCT	;AND CLEAR ARG ACCUMULATION VARIABLES.
	SETZM RRRPCT
	SETZM RRUNQT
	RET

;COME HERE FOR ^G.
RRQUIT:	SKIP TT,CASNRM	;NOTE: THIS RTN IS CALLABLE BY RRLP7H, SO NEED "SKIP"
	MOVEM TT,CASE	;IN F$ MODE, UNDO ANY CASE-LOCKAGE.
	SETOM RRMKPT	;ELIMINATE THE MARK.
	SKIPE NELNS
	 CALL ECHOCL	;GO TO NEW LINE IN ECHO REGION
	SETOM RROVPO	;FORCE CURSOR REPOSITIONING

;ERROR DETECTED BY RR EDIT:
RRERR:	SKIP
	SKIPE RREBEG	;IF NOT INSIDE ^R, GIVE A TECO ERROR.
	 TYPRE [BEL]
	MOVE P,DISPRR
	JRST TYPBEL	;TYPE A BELL AND REENTER MAIN LOOP.

;"UNDEFINED" ^R COMMAND CHARACTERS HAVE THIS DEFINITION, WHICH TYPES A BELL
;AND RETURNS 1 VALUE.  THIS AVOIDS GETTING A "BEL" ERROR, IF UNDEFINED CHAR
;IS RUN WITH M^R<CHAR>.
RRUNDF:	SKIP
	AOS (P)
	JRST TYPBEL

;EXPECT CHAR ADDR IN "IN", SKIP UNLESS IT POINTS TO THE END
;OF THE BUFFER OR THE END OF A LINE. CLOBBERS TT, TT1
RREOLT:	CAMN IN,ZV
	 POPJ P,	;AT EOF.
	SAVE CH
	CALL GETINC
	CAIN CH,^M
	CAMN IN,ZV
	 SOJA IN,POPCH1 ;BEFORE A CR THAT'S THE LAST CHAR.
	CALL GETCHR
	SUBI IN,1
	CAIE CH,^J
POPCH1:	 AOS -1(P)	;BEFORE A STRAY CR => NOT AT EOL.
	JRST POPCHJ	;BEFORE A CRLF => EOL.

;IF A CHARACTER <C>'S DEFINITION IS <N>,,RRINDR, IT IS AN INDIRECT PTR
;TO THE DEFINITION OF THE CHARACTER <C>-<N>. USED TO HANDLE
;THE LOWER CASE CONTROL CHARACTERS SUCH AS 341 = CTL-LOWERCASE-A.
;ALSO USED TO MAKE CONTROL-H EQUIVALENT TO BACKSPACE; SIMILAR FOR TAB & LF.
RRINDR:	SKIP
	HLRZS E		;GET <N>
	SUB CH,E
	JRST RRIND1	;GO USE DEF'N OF <C>-<N>.

SUBTTL ^R MODE SINGLE CHARACTER DELETION AND INSERTION

RRDLNB:	MOVNS C		;HERE FOR DELETE BACKWARD WITH NEGATIVE ARG.  SKIPS.
	JRST RRCTD1

;^D -- DELETE FORWARD. (D)
RRCTLD:	SKIP
	JUMPGE C,RRCTD1
	MOVNS C
	MOVEM C,RRRPCT		;IF NEGATIVE ARG, SET ITS NEGATION UP AS ARG
	.I RRARGP=3
	SETZM RR4TCT
	MOVEI CH,177		;AND TURN INTO RUBOUT.
	JRST RRIND1

RRCTD1:	SKIPE RRARGP		;IF WE HAVE AN EXPLICIT ARGUMENT,
	 SKIPN A,RUBMAC		;CALL THE SUPPLIED MULTI-CHARACTER DELETE MACRO.
	  CAIA
	   JRST [ MOVNS C	;CALL WITH NEGATIVE ARG (NUMBER TO RUB OUT).
		  AOS (P)
		  JRST RRMAC0]
	JSP E,RRREP1		;ELSE REPEAT WHAT FOLLOWS THAT MANY TIMES:
	AOS (P)
	MOVE IN,PT
	CAML IN,ZV
	 JRST RRERR
	JSP E,RRTYPP	;ON PRINTING TTY, MAYBE TYPE SCAN INFO
	 CALL [	SETCM E,TTYOPT
		CALL GETCHR		;GET CHARACTER ABOUT TO DELETE
		MOVEI A,(CH)
		MOVEI CH,"/
		TLNE E,%TOOVR\%TOMVB	;IF CAN BACKSPACE AND OVERPRINT, OVERPINT A SLASH.
		 CAIN A,^M		;ABOUT TO DELETE A CRLF, TYPE A SLASH.
		  CALL FSECOR
		MOVEI CH,^H		;BS OVER IT IF OVERPRINTING
		TLNN E,%TOOVR\%TOMVB
		 CALL FSECOR
		MOVEI CH,(A)		;GET CHARACTER AGAIN
		CALL FSECOR
		SKIPN BSNOLF
		 RET
		JRST RRMVC]		;THEN ECHO THE CHAR BEING DELETED.
	SKIPN RUBCRL	;IF FS RUBCRLF$ NONZERO,
	 JRST RRDLF
	CALL RREOLT	;IF BEFORE A CRLF, DELETE BOTH CHARS.
	 JRST [	CALL GAPSLP
		CALL DEL1F	;DELETE THEM AT ONCE, AND DON'T TRY TO DO UPDATING.
		CALL DEL1F
		MOVE BP,RRVPOS
		MOVE T,RRHPOS
		MOVNI A,2
		JRST RRFXM1]

;INTERNAL ROUTINE TO DELETE FORWARD.
RRDLF:	CALL RRFORW	;MOVE OVER THE CHAR, THEN DELETE IT BACKWARD.

;INTERNAL ROUTINE TO DELETE BACKWARD (-D).  DELETED CHAR LEFT IN CH.
;CLOBBERS A,B,IN,OUT,TT,TT1,Q, T, BP
RRDLB:	SETOM RRMKPT
	MOVE IN,PT	;ERROR AT BEGINNING OF BUFFER.
	CAMG IN,BEGV
	 JRST RRERR
	SAVE RRVPOS	;REMEMBER VPOS TO RIGHT OF CHARACTER.
	CALL RRBACK	;ACCOUNT FOR CURSOR POS CHANGE DUE TO DELETION.
	CALL GAPSLP
	CALL RRCRDI
	 	CALL DEL1F	;DELETE FORWARD FROM BUFFER, NO CURSOR HACKERY.
	CAIE CH,^H	;DELETING CHARS THAT MOVE LEFT IS HARD.
	CAIN CH,^M
	 JRST RRDLB4
	CAIN CH,^J
	 JRST RRDLB4
	CAIE CH,^I
	 SKIPN DISSAI
	  CAIL CH,40	;BETTER NOT BE DIFFICULT CHARACTER
	   CAIN CH,177
	    JRST RRDLB4	;IF IT IS, JUST REDISPLAY
	CALL RRICHK	;SEE WHETHER IT'S EASY TO UPDATE SCREEN.
	REST A
	CAMN A,BP	;IF EFFECTS OF CHANGE REACH PREV. LINE,
	SKIPE RRMAXP	;OR IF REDISPLAY WILL BE DONE ANYWAY.
	 JRST RRDLB1	;DON'T BOTHER TO DO IT HERE.
	CALL RRMVC	;UPDATE THE SCREEN NOW:
	MOVNI T,1	;UPDATE LINBEG WORDS OF ALL LINES
	CALL RRINS3	;BELOW THIS ONE.
	MOVE BP,RRVPOS
	SKIPGE T,RRCIDP
	 JRST [	SETOM HCDS(BP)	;IF MOVING CHARS TO NEW HPOSES, WE CAN'T FIX THE HASHCODE.
		SOS LINEND(BP)
		MOVE A,INCHCT	;IF "DISPLAYING" PRE-ECHOED INPUT,
		CAMG A,INCHEC	;DON'T ACTUALY OUTPUT ANYTHING, JUST PRETEND WE DID.
		 RET
		MOVEI A,1
		JRST DELCHR]
	CALL CHCTHR		;ELSE REMOVE THIS CHARACTER FROM THE HASH CODE; RRHPOS IS HPOS.
	MOVE A,INCHCT	;IF "DISPLAYING" PRE-ECHOED INPUT,
	CAMG A,INCHEC	;DON'T ACTUALY OUTPUT ANYTHING, JUST PRETEND WE DID.
	 JRST [	JUMPLE T,CPOPJ
		MOVE T,RRHPOS
		MOVEM T,LINEND(BP)	;AT END OF LINE => CURRENT POS IS NEW END-OF-LINE POS.
		RET]
	JUMPG T,ERSCHR		;NOW GO CLEAR OUT THE APPROPRIATE PARTS OF THE SCREEN.
	MOVE T,RRHPOS
	MOVEM T,LINEND(BP)	;AT END OF LINE => CURRENT POS IS NEW END-OF-LINE POS.
	JRST CLREOL

RRDLB4:	SUB P,[1,,1]	;FLUSH SAVED VPOS. FROM STACK.
	SKIPGE DISPCR
	 SETZ T,	;DELETING A REAL STRAY CR => MUST REDISPLAY WHOLE LINE
			;TO GET RID OF OVERSTRUCK CHAR IN POSITION 0.
RRDLB1:	MOVNI A,1	;1 CHAR DELETED AT VPOS, HPOS IN BP,T.
	JRST RRFXM1

FSRRRU:	ARGDFL Z	;FS ^R RUBOUT$
	SAVE [RRLEA1]	;AFTERWARDS SET RREPT, RREHPS, RREVPS.
	JSP E,RRREP2
	JRST RRDLB	;RUB OUT SPEC'D # OF CHARS WITH NO TAB OR CRLF HACKS.

;BUILT-IN DEFINITION OF RUBOUT: DECODE ARGUMENT.
RRRUB:	SKIP
	JUMPL C,RRDLNB	;NEGATIVE ARG => REALLY DELETE FORWARD.
	SKIPE RRARGP	;ELSE, EXPLICIT ARG MEANS CALL 
	 SKIPN A,RUBMAC	;THE MULTI-CHAR DELETE MACRO, IF ANY.
	  CAIA
	   JRST [
		AOS (P)
		JRST RRMAC0]
	JSP E,RRREP2	;REPEAT ARG TIMES WHAT FOLLOWS (BUT FIRST OTHER STUFF)
	AOS (P)
RRRUBD:	SKIPN RRRPLC	;RUBOUT IN OVERWRITE MODE MEANS
	 JRST RRRUB1
	MOVE IN,PT	;REPLACE PREVIOUS CHARACTER WITH A SPACE.
	CAMG IN,BEGV	;BUT THERE MUST BE A PREVIOUS CHARACTER,
	 JRST RRRUB1
	SOS IN
	CALL GETCHR
	CAIE CH,^J	;AND IT MUSTN'T BE ONE OF THESE FUNNY ONES.
	 CAIN CH,^M
	  JRST RRRUB1
	CAIE CH,^I
	 CAIN CH,^H
	  JRST RRRUB1
	CAIN CH,^L
	 JRST RRRUB1
	CALL RRBACK	;SO REPLACE PREV. CHAR WITH A SPACE BY BACKING UP
	MOVEI CH,40	;AND DOING AN OVERWRITE-MODE INSRT OF A SPACE.
	MOVEM CH,$Q..0
	CALL RRDINS
	 JFCL
	JRST RRBACK	;THEN BACK UP OVER THE SPACE AGAIN.

RRRUB1:	CALL RRDLB	;DELETE ONE CHAR BACKWARD
	SKIPE RUBCRL	;AND THEN IF FS RUBCRLF$ NONZERO, AFTER RUBBING OUT A ^J
	 CAIE CH,^J
	  JRST RRRUBP
	MOVE IN,PT	;FLUSH A CR BEFORE IT, TOO.
	SOS IN
	CAMGE IN,BEGV
	 JRST RRRUBP
	CALL GETCHR
	CAIN CH,^M
	 CALL RRDLB
RRRUBP:	JSP E,RRTYPP	;ON PRINTING TTY, IF SCANNING, TYPE THE RUBBED CHARACTER.
	 CAIA		;NOTICE THAT IF RUBBING A CRLF WE COME HERE FOR THE CR
	  RET		;WHICH WILL ECHO AS CRLF.
	MOVE E,TTYOPT
	TLNE E,%TOMVB	;ON TTY THAT CAN'T BS, SURROUND RUBBED STUFF WITH \'S.
	 JRST RRRUBB
	MOVEI IN,"\
	SAVE CH
	MOVEI CH,"\
	CAME IN,RUBENC	;IF NOT YET INSIDE A \ PAIR, START ONE.
	 CALL FSECO1
	SETZM RUBENC	;IF INSIDE ONE ALREADY, DON'T END IT YET.
	REST CH
	CALL FSECOR	;TYPE THE RUBBED CHARACTER.
	MOVEM IN,RUBENC	;FOLLOW WITH A \ WHEN WE STOP RUBBING OUT.
	RET

RRRUBB:	CALL RRTTY2	;MOVE CURSOR TO RIGHT PLACE.  THIS KING OF RUBOUT CAN INTERMIX
	MOVEI CH,"/	;WITH BACKWARD MOTION.
	CALL FSECOR	;OVERSTRIKE A / (MAY ERASE OR NOT, WHO CARES?)
	JRST RRMVC

;CTL-RUBOUT:  LIKE RUBOUT, BUT CONVERTS TABS INTO SPACES FIRST.
RRCRUB:	SKIP
	JUMPL C,RRDLNB	;NEGATIVE ARG => REALLY DELETE FORWARD.
	SKIPE RRARGP	;ELSE, EXPLICIT ARG MEANS CALL 
	 SKIPN A,RUBMAC	;THE MULTI-CHAR DELETE MACRO, IF ANY.
	  JRST RRCRU2
	AOS (P)
	MOVEM C,NUM
	SETOM SARG	;FOR TAB-HACKING, GIVE IT -1 AS ^X ARG.
	TRO FF,FRARG2
	JRST RRMAC7	;FRARG2 WON'T BE SET, BUT THAT DOESN'T MATTER.

RRCRU2:	JSP E,RRREP2	;REPEAT THE FOLLOWING ARG TIMES:
	AOS (P)
	SAVE RRHPOS
	CALL RRBACK	;WE NEED HPOS BOTH BEFORE AND AFTER CHAR TO BE FLUSHED,
	REST E		;IF IT'S A TAB.
	CAIE CH,^I
	 JRST [	CALL RRFORW	;NOT TAB => UNDO THE RRBACK
		JRST RRRUBD]	;AND DO A NORMAL RUBOUT.
	CALL GAPSLP
	SAVE PT
	AOS (P)
	CALL DEL1F	;ELSE FLUSH THE TAB AND PUT IN APPRO. # OF SPACES
	SUB E,RRHPOS
RRCRU1:	MOVEI CH,40
	CALL TYOM
	SOS PT
	CALL RRFORW	;MOVING FORWARD OVER THEM
	SOJG E,RRCRU1	;LEAVING US IN INITIAL STATE EXCEPT TAB REPLACED BY SPACES.
	REST T
	SUB T,PT
	MOVNS T		;T HAS CHANGE IN PT DUE TO OUR INSERTION.
	SKIPE RREPT	;IF WE ARE CALLED FROM TECO CODE, UPDATE RREPT
	 ADDM T,RREPT	;TO CORRESPOND TO THE SPACES INSTEAD OF THE TABS.
	MOVE BP,RRVPOS
	CAMGE BP,TOPLIN	;IF THE CHANGE IS ABOVE THE SCREEN, RELOCATE ALL LINBEGS IN THE WINDOW.
	 MOVE BP,TOPLIN
	CAMGE BP,BOTLIN	;IF THIS CHANGE IS OFF THE END OF THE SCREEN, WE ARE DONE.
	 CALL RRINS3	;RELOCATE LINBEG TABLE FOR WHAT WE HAVE DONE.
	JRST RRRUBD	;THEN DELETE THE LAST SPACE.

;COME HERE WHEN CASE-SHIFT IS READ.
RRSFT:	MOVNS CASE	;READ NEXT CHAR IN ABNORMAL CASE.
	AOSE RCHSFF
	 SETOM RCHSFF	;RESTORE TO NORMAL AFTER NEXT CHAR.
	SKIPN RCHSFF	;ALLOW THE CASE-SHIFT TO QUOTE ITSELF.
	 JRST RRLP7J

;TYPE THE CHAR IN Q..0 AS A PROMPT, IF THERE IS NO INPUT AVAILABLE.
RRECO1:	SKIPE RGETTY
	 SKIPGE RRECHO	;ON DISPLAY TTY, IF NOT ECHOING THE COMMAND,
	  RET
	MOVEI A,[ASCIZ /0@V @:FT..00 /]
	JRST RRMACR

;COME HERE FOR CASE-LOCK AS A COMMAND.
RRLOK:	MOVNS CASE
	POPJ P,

;^O - INSERT CRLF, THEN BACK UP OVER IT.
RRCTLO:	CALL RRCRL1	;INSERT CRLF
	 JFCL
	AOS (P)
	CALL RRBACK	;THEN BACK OVER IT.
	JRST RRBACK

;^M - INSERT ^M AND ^J.
RRCRLF:	CALL RRCMRU	;REMOVE TAB-SEMI'S FROM LINE WE'RE ON.
RRCRL1:	MOVEI CH,^M
	CALL RRINS	;INSERT THE ^M.
	MOVEI CH,^J
	JRST RRINSQ	;INSERT THE ^J.

;^Q -- READ NEXT CHAR AND INSERT IT.
RRQUOT:	SKIP
	SAVE C
	CALL RRECO1	;FINISH DISPLAYING, MAYBE PROMPT WITH A "^Q".
	CALL TYI	;READ THE CHAR TO BE QUOTED.
	CALL TYINRM
	REST C
	JSP E,RRREP1	;NOTE ^Q MUST DO ITS OWN REPETITION.
	JRST RRINSQ	;OTHERWISE ^V5^Q WOULD READ AND INSERT 5 CHARS.
			;INSTEAD OF READING 1 CHAR AND INSERTING
			;IT 5 TIMES.

;THIS IS THE DEFAULT DEFINITION OF "SELF-INSERTING" CHARACTERS:
;NORMALLY, JUST INSERT.  META-CHARS INSERT.  IF FS ^R REPLACE$ NONZERO,
;NON-META CHARS REPLACE INSTEAD (BUT AT END OF LINE, THEY INSERT).
RRDINS:	MOVE CH,$Q..0
	TRNN CH,META
	 SKIPN RRRPLC
	  JRST RRINSC
	MOVE IN,PT
	CAML IN,ZV	;AT END OF BUFFER, JUST INSERT.
	 JRST RRINSC
	CALL GETCHR	;HERE IF SUPPOSED TO TRY TO REPLACE.
	CAIE CH,^M	;AT END OF LINE?
	 CAIN CH,^J
	  JRST RRINSC	;YES => INSERT, DON'T REPLACE.
	CAIE CH,^H
	 CAIN CH,^L
	  JRST RRINSC
	CAIN CH,^I
	 JRST RRDINT
RRDIN0:	AOS (P)
	CALL RRICH9	;CHECK FOR VARIOUS CONDITIONS PROHIBITING UPDATING.
	CALL RRFORW
	SAVE RRHPOS	;WHAT IS HPOS AFTER THE CHAR WE ARE REPLACING??
	CALL RRBACK	;DELETE THAT CHARACTER.
	SAVE CH
	SAVE RRHPOS
	CALL GAPSLP
	CALL DEL1F
	MOVE CH,$Q..0
	CALL TYOM	;INSERT THE NEW CHARACTER.
	SOS PT
	MOVE BP,RRVPOS
	CALL RRFORW	;WHAT IS THE HPOS AFTER THE NEW CHARACTER?
	REST T		;T GETS HPOS BEFORE THIS CHARACTER.
	REST B		;B HAS CHAR WE ARE REPLACING.
	REST A		;A GETS HPOS AFTER CHAR WE REPLACED.
	CAMN A,RRHPOS	;HPOS AFTER THIS CHAR SAME AS AFTER OLD => WE CAN REWRITE ON SCREEN,
	 CAME BP,RRVPOS	;AS LONG AS IT DOESN'T CONTINUE THE LINE.
	  JRST RRDIN3
	CAIE CH,ALTMOD	;EITHER CHAR IS ALTMODE => CAN'T UPDATE.
	 CAIN B,ALTMOD
	  JRST RRDIN3
	SKIPE RRMAXP
	 JRST RRDIN3
	EXCH T,RRHPOS	;T GETS HPOS AFTER (LIKE A), RRHPOS GETS HPOS BEFORE CHAR.
	EXCH CH,B
	CAIN CH,11
	 MOVEI CH,40
	CALL CHCTHR	;UPDATE HASH CODE OF LINE FOR CHAR BEING REPLACED.
	MOVE CH,B
	CALL CHCTHI	;UPDATE THE HASH CODE OF THE LINE FOR CHAR BEING INSERTED.
	CALL RRMVC	;MOVE TO HPOS OF START OF CHARACTER.
	SUB A,RRHPOS	;A GETS NUMBER OF POSITIONS THE CHARACTER TAKES.
	CAIE A,1
	 SETOM HCDS(BP)	;MORE THAN 1 => WE CAN'T FIX THE HASH CODE, SO CALL FOR REDISPLAY.
	MOVE TT,INCHCT	;IF "DISPLAYING" PRE-ECHOED INPUT,
	CAMG TT,INCHEC	;DON'T ACTUALLY OUTPUT ANYTHING,
	 JRST [	MOVEM T,RRHPOS	;JUST PRETEND WE DID.
		MOVEM T,RROHPO
		RET]
	MOVE TT,TTYOPT
	TLNN TT,%TOOVR	;IF TERMINAL CAN OVERPRINT, WE MUST CLEAR THE SPOTS.
	 JRST RRDIN2
RRDIN1:	SAVE A
	CALL ERSCHR	;CLEAR OUT THAT MANY POSITIONS.
	REST A
	MOVEI CH,40
	CALL TYOINV
	SOJG A,RRDIN1
	SETOM RROHPO
	CALL RRMVC	;THEN RESTORE CURSOR POSITION.
RRDIN2:	MOVEM T,RRHPOS	;SET HPOS TO ITS VALUE AFTER THE NEW CHARACTER.
	MOVEM T,RROHPO
	MOVE CH,$Q..0	;NOW PRINT THE NEW CHARACTER AT THE DESIRED PLACE.
	SKIPE CASDIS
	 CALL DISAD6
	JRST TYOINV

RRDIN3:	SETZ A,		;HERE TO UPDATE RRMNVP, RRMNHP, RRMAXP IF CAN'T UPDATE SCREEN.
	JRST RRFXM1	;T HAS HPOS OF CHAR, BP HAS VPOS.

RRDINT:	.I RRHPOS+1	;BEFORE A TAB => INSERT UNLESS TAB NOW TAKING ONLY 1 SPACE.
	IDIV TT,TABWID
	JUMPE TT1,RRDIN0
RRINSC:	MOVE CH,$Q..0
RRINSQ:	AOS (P)
	TRZ FF,FRARG2
	JRST RRINS

FSRRINS:MOVE CH,C	;USER-INTERFACE TO RRINS: FS ^R INSERT$

;INSERT CHAR IN CH.
;CLOBBERS A, B, IN, OUT, TT, TT1, CH, Q, T, BP
RRINS:	CALL TYINRM	;CONVERT CHARACTER TO ASCII.
	SETOM RRMKPT
	MOVE A,TABWID
	CAIN A,8
	 CAIE CH,^I	;INSERTING ANY CTL CHAR IS HARD EXCEPT 8-SPACE TAB.
	  CAIA
	   SKIPE LEABLE	;AND TAB IS HARD TOO IF TERMINAL CAN DO LOCAL EDITING.
	    SKIPE RRMAXP
	     JRST RRINS2
	CAIL CH,40
	 CAIN CH,177
	  AOSA RRMAXP
RRINS2:	CALL RRICHK	;SEE IF OBVIOUSLY CAN'T UPDATE SCREEN NOW.
	CALL RRCRDI
	 CALL [	CALL TYOMGS ;INSERT CHAR AFTER PT.
		SOS PT
		POPJ P,]
	MOVE Q,RRHPOS
	CALL RRFORW	;THEN MOVE FORWARD OVER IT.
	MOVEI A,1	;(FOR RRFXM1) 1 CHAR INSERTED.
	CAMN BP,RRVPOS	;CHAR MOVED TO NEXT LINE => MUST REDISPLAY
	SKIPE RRMAXP	;IF REDISPLAY ALREADY NEEDED, DON'T TRY TO UPDATE FOR THIS.
	 JRST RRFXM1
	SKIPE RRCIDP	;IF GOING TO DO SOMETHING WITH CHAR I/D
	 CAIE CH,^I	;MUST BE AN EASY CHAR
	 CAIA
	 JRST RRFXM1	;FOR TABS REDISPLAY REQUIRED
	MOVE T,Q
	EXCH T,RRHPOS	;POSITION CURSOR AT HPOS BEFORE THE CHARACTER.
	CALL RRMVC
	CALL CHCTHI	;USE THAT HPOS TO UPDATE LINE'S HASH CODE.
	CAIN CH,^I	;AFTER A TAB, THE HASH CODE WAS NOT UPDATED PROPERLY.
	 SETOM HCDS(BP)
	MOVEM T,RRHPOS
	MOVEM T,RROHPO
	MOVEI T,1	;UPDATE LINBEG WDS OF ALL LINES
	CALL RRINS3	;BELOW THIS LINE.
	MOVE BP,RRVPOS
	SKIPN CASDIS	;IF CASE FLAGGING MIGHT BE HAPPENING,
	 SKIPGE RRCIDP	;OR IF WE ARE MOVING OTHER CHARACTERS AROUND,
	  SETOM HCDS(BP) ;THEN UPDATING THE HASH CODE LOST, SO CALL FOR REDISPLAY OF LINE.
	SKIPG RRCIDP	;IF AT END OF LINE OR INSERTING, UPDATE REMEMBERED LINE-END-HPOS.
	 AOS LINEND(BP)
	MOVE TT,RRHPOS
	SKIPN RRCIDP	;INSERTING AT END OF LINE => CURRENT HPOS IS NEW END-OF-LINE HPOS.
	 MOVEM TT,LINEND(BP)	;THIS IS USUALLY SAME AS AOS'ING BUT NOT WHEN TAB IS INSERTED!
	MOVE A,INCHCT	;IF "DISPLAYING" PRE-ECHOED INSERTING CHARS,
	CAMG A,INCHEC	;DON'T ACTUALLY OUTPUT ANYTHING NOW.
	 RET
	MOVEI A,1
	SKIPGE RRCIDP	;IF USING CHAR I/D FOR THIS
	 CALL INSCHR	;INSERT THE SPACE FOR IT FIRST
	SKIPE CASDIS	;OUTPUT CHARACTER, WITH CASE-SHIFT IF ANY.
	 CALL DISAD6
	JRST TYOINV

RRINS3:	ADDM T,RROLZV
	JRST RRDISG

;CHECK FOR SOME OF THE THINGS THAT WOULD RULE OUT UPDATING THE
;SCREEN IMMEDIATELY FOR AN INSERT OR DELETE. IF ANY IS
;FOUND, LEAVE RRMAXP NONZERO (THIS WON'T CONFUSE RRLP BECAUSE
;WE'LL SET RRMAXP ANYWAY IN ORDER TO CAUSE REDISPLAY)
;REDISPLAY WILL ALWAYS WORK, BUT UPDATING IS FASTER.
;CLOBBERS A, B, IN, OUT, TT, TT1
RRICHK:	HRROS (P)	;SET SIGN FOR CHECKING INSERTION AND DELETION.
	CAIA
RRICH9:	 HRRZS (P)	;CLEAR SIGN FOR CHECKING FOR REPLACEMENT.
	SETZM RRCIDP	;SO FAR NO TAB OR CHAR I/D STUFF APPEARS TO BE NECESSARY.
	SKIPE RRMAXP	;REDISPLAY NECESSARY ANYWAY =>
	 RET		;IT WILL FIX SCREEN; WE NEEDN'T.
	SKIPL RRINHI
	 SKIPL RRMSNG
	  JRST RRICH2
	SAVE CH
	SKIPN RGETTY
	 JRST RRICH1	;CAN'T UPDATE IF THERE'S A CURSOR STRING.
	MOVE CH,RRVPOS	;IF CURSOR IS OFF SCREEN,
	CAML CH,TOPLIN
	CAML CH,BOTLIN	;DON'T UPDATE, REDISPLAY IS NEEDED.
	 JRST RRICH1
	SKIPL -1(P)
	 JRST RRICH4
	MOVE IN,PT
	CALL RREOLT	;UPDATING FOR INSERT/DELETE POSSIBLE ONLY AT END OF LINE.
	 CAIA
	  JRST RRICH3	;UNLESS BEFORE TAB OR CHAR I/D CAN BE USED
RRICH4:	SKIPE TYISRC
	 JRST RRICH1
	LISTEN A	;MANY UPDATES DON'T BEAT 1 REDISPLAY.
	CAIL A,5
	 JRST RRICH1
	SKIPL DISPCR	;IF THERE ARE NO REAL BS'S OR STRAY CR'S
	 SKIPGE DISPBS
	  CAIA
	   JRST POPCHJ	;NO NEED FOR THE NEXT TEST.
	CALL RRBTCR	;PERHAPS, DUE TO BACKSPACES, SOMETHING
	CAMG OUT,RRHPOS ;EARLIER IN THE LINE APPEARS FARTHER
	 JRST POPCHJ	 ;RIGHT ON THE SCREEN (EG ABC<BS>/\)
RRICH1:	REST CH
RRICH2:	AOS RRMAXP	;CAUSE CALLER NOT TO TRY UPDATING.
	RET

;CHECK FOR CONDITIONS THAT MIGHT ALLOW US TO AVOID REDISPLAY EVEN IF
;NOT AT THE END OF THE LINE, IF RETURNS SUCCESSFUL, RRCIDP WILL BE
;POSITIVE IF WE ARE BEFORE A TAB THAT TAKES MORE THAN 1 SPACE AND SO
;CAN INSERT BY OVERWRITING, OR NEGATIVE IF WE ARE TO USE CHAR I/D
RRICH3:	SKIPE CASDIS	;DONT GET SCREWED BY FLAGGING
	 JRST RRICH1	;JUST REDISPLAY IN THAT CASE
	CALL GETINC	;GET NEXT CHAR
	CAIE CH,^I	;IS IT A TAB?
	 JRST RRICH5	;NO, TRY CHAR I/D MAYBE
	.I RRHPOS+1	;GET NUMBER OF CHARS IT USES
	IDIV TT,TABWID
	JUMPE TT1,RRICH1 ;JUMP IF ONLY ONE.
	AOS RRCIDP	;SAY HACKING A TAB,
	JRST RRICH4	;AND GO CONTINUE CHECKS

RRICH5:	SKIPE CID	;TRY TO USE CHAR I/D?
	 CALL RRNTBP	;CHECK THAT THE LINE HAS NO TABS AFTER THIS IN IT
	 JRST RRICH1	;NO, FORGET IT, MUST REDISPLAY
	SETOM RRCIDP	;SAY USE CHAR I/D FOR THIS ONE
	JRST RRICH4	;AND CONTINUE CHECKING

;CONVERT LOWER CASE TO UPPER OR VICE VERSA, ACC. TO FS CASE $
;FOR SHIFT OR LOCK CHARS, RCHSFT AND RCHLOK MIGHT GET CALLED!
RRCASC:	TRNE CH,CONTRL+META
	 RET
	CAIL CH,100	;[ ;XCTING WOULD LOSE ON ALTMODE, ^].
	 XCT RCHDTB(CH)	;SKIPS FOR CHARS WHOSE CASE IS WRONG.
	CAIA
	XORI CH,40	;CHANGE TO THE OTHER CASE.
	MOVEM CH,$Q..0
	AOSN RCHSFF
	 MOVNS CASE	;IF PREV. CHAR WAS CASE SHIFT, UN-COMPLIMENT CASE.
	POPJ P,

;CHECK IF THE CURRENT LINE HAS TABS IN IT AFTER PT, WHICH MIGHT MAKE
;AVOIDING REDISPLAY TOO HARD, SKIP IF NONE FOUND AND BUFFER LINE DOES NOT
;WRAP AROUND TO SEVERAL SCREEN LINES
RRNTBP:	SAVE BP
	MOVE IN,PT
	CALL GETIBI	;GET POINTER TO CURRENT POSITION
RRNTB1:	CAMN IN,ZV
	 JRST RRNTB3	;AT THE VERY END, OK NO TABS THEN
	CAMN IN,GPT
	 CALL FEQGAP	;MOVE OVER GAP
	ILDB CH,BP
RRNTB2:	CAIN CH,^I	;IS IT A TAB?
	 JRST POPBPJ	;YES, FAILURE THEN
	CAIE CH,^M	;GOT TO CR?
	 AOJA IN,RRNTB1	;NO, KEEP LOOKING
	AOJ IN,
	CAMN IN,ZV
	 JRST RRNTB3
	CAMN IN,GPT
	 CALL FEQGAP
	ILDB CH,BP
	CAIE CH,^J	;REALLY AT CRLF?
	 JRST RRNTB2	;NO, IT WAS STRAY CR.  MAYBE THIS CHAR IS A TAB.
	SUBI IN,1	;CHECK HPOS JUST BEFORE THE CR.
RRNTB3:	SKIPGE DISTRN	;IF WE ARE JUST TO TRUNCATE LONG LINES
	 JRST POPBP1	;THAT'S ENOUGH CHECKING, SKIP RETURN
INSIRP PUSH P,RRHPOS RRVPOS PT E
	MOVE E,IN
	CALL RRMOV	;FIND POSITION OF END OF LINE (AS OF LAST REDISPLAY)
	MOVE TT,RRHPOS	;GET NEW VALUES
	MOVE TT1,RRVPOS
INSIRP POP P,E PT RRVPOS RRHPOS
	CAME TT1,RRVPOS	;ON THE SAME LINE?
	 JRST POPBPJ	;NO, MUST REDISPLAY THEN
	CAMGE TT,NHLNS	;ALSO IF THIS WOULD BE DISPLAYED PAST END OF LINE
POPBP1:	AOS -1(P)	;SUCCESS RETURN
	JRST POPBPJ

;TAKE CARE OF THE POSSIBILITY THAT CHANGING THE BUFFER AFTER PT MAY
;CHANGE WHAT APPEARS ON THE SCREEN BEFORE PT. (FOR EXAMPLE,
;INSERTING OR DELETING A LF AFTER A CR.)
;FOLLOW A CALL TO RRCRDI WITH AN INSN THAT CHANGES THE BUFFER
;AFTER PT, BUT DOESN'T CHANGE PT, AND DOESN'T CLOBBER BP OR T.
;ON RETURN, PT IS UNCHANGED, RRHPOS AND RRVPOS
;ARE CORRECT, AND BP,T CONTAIN THE V AND HPOS OF A PLACE ON THE SCREEN
;BEFORE WHICH NOTHING NEEDS TO CHANGE.
;CLOBBERS A,B,TT,TT1,IN,OUT
RRCRDI:	SAVE CH
	SAVE PT
	CALL RRCRDB	;MOVE BACK TO BEFORE ALL BEFORE-EFFECTS.
	MOVE IN,PT
	CAMN IN,(P)	;IF WE DIDN'T MOVE BACK AT ALL, NO PROBLEM.
	 JRST RRCRDX
	SUB IN,BEG	;ELSE REMEMBER HOW FAR BACK WE MOVED,
	EXCH IN,(P)	;RELATIVE TO BEG IN CASE BUFFER MOVES.
	MOVEM IN,PT	;GIVE PT THE RIGHT VALUE FOR USER'S RTN,
	MOVE CH,-1(P)	;AND CH.
	MOVE T,RRHPOS	;GET HPOS AND VPOS OF PLACE WE MOVED BACK TO,
	MOVE BP,RRVPOS	;TO RETURN TO OUR CALLER.
	XCT @-2(P)	;DO WHAT CALLER WANTED DONE.
	MOVE IN,(P)	;SET PT TO WHERE WE MOVED BACK TO
	ADD IN,BEG
	EXCH IN,PT	;BUT REMEMBER ITS REAL VALUE.
	MOVEM IN,(P)
RRCRD1:	CALL RRFORW	;THEN MOVE FWD OVER WHAT WE MOVED
	CAME IN,(P)	;BACK OVER.
	 JRST RRCRD1
	SUB P,[1,,1]
	JRST POPCH1

RRCRDX:	MOVE T,RRHPOS	;NO PROBLEM OF BEFORE-EFFECTS, JUST
	MOVE BP,RRVPOS	;RETURN THE HPOS AND VPOS, AND EXIT
	SUB P,[1,,1]	;TO THE USER'S BUFFER-MUNGING INSN.
	JRST POPCHJ

RRCRDB:	MOVE IN,PT
	SUBI IN,1	;ARE WE AFTER A CR? IF SO, IT MAY CHANGE FORM.
	CAMGE IN,BEGV
	 POPJ P,	;AT BEGINNING OF BUFFER, NO PROBLEM.
	CALL GETCHR	;ARE WE AFTER A CR?
	CAIN CH,^M	;IF SO, IT MIGHT CHANGE FORM.
	 CALL [	SKIPL DISPCR	;IF IT CAN COME OUT AS "^M"
		 JRST RRBACK	;THEN IT CAN PROPAGATE BEFORE-EFFECTS.
		JRST POP1J]	;ELSE, IT GUARANTEES NO BEFORE-EFFECTS.
	MOVE IN,PT
	SUBI IN,2	;IF IN HORIZ. POS. 0, AND
	SKIPG RRHPOS
	CAMGE IN,BEGV	;NOT NEAR THE BEGINNING OF BUFFER,
	 POPJ P,
	CALL GETINC	;AND NOT SHORTLY AFTER A CR (NOTE THIS
	CAIN CH,^M	;CATCHES A PRECEDING CRLF)
	 RET
	CALL GETCHR
	SKIPGE DISPBS	;AND NOT RIGHT AFTER A ^H THAT REALLY BACKSPACES (THEN MOVING BACK
	 CAIE CH,^H	;OVER IT WOULD UNDERESTIMATE!)
	  CALL RRBACK	;THEN MAYBE "!" MUST BE WRITTEN OR ERASED AT END OF PREVIOUS LINE.
	POPJ P,

SUBTTL LEAVE ^R, UPWARD OR DOWNWARD

;ALTMODE - LEAVE ^R MODE.
RREXIT:	SKIP A,RREBEG
	JUMPN A,FSCREX	;IF COMING FROM M.^R$, DO A FS^REXIT$.
RREXI0:	MOVE CH,QRB..	;DON'T INHIBIT REDISPLAY AT NEXT OPPORTUNITY (UNLESS RRLEVM TYPES)
	SETZM .QVWFL(CH)
	TLO FF,FLNOIN	;EXECUTING COMMANDS CLOBBERS FLNOIN, SO RESTORE IT
	MOVE A,DISPRR
	SKIPGE -3(A)
	 JRST RREXI2	;@V - LEAVE FLNOIN ON.
	SKIPE A,RRLEVM	;IF EXITING ^R, RUN FS ^R LEAVE$.
	 CALL RRMACR
	TLZ FF,FLNOIN
RREXI2:	MOVE P,DISPRR
	SUB P,[1,,1]	;POP OFF RET ADDR AT RRLP
	REST DISPRR
	CALL RRLEAV	;SET UP "RRE" VARIABLES.
	SETOM ECHCHR	;A ^R COMMAND WHICH CALLS ^R SHOULDN'T HAVE ECHOING WHEN IT RETURNS.
	ANDCMI FF,FRARG+FRARG2
	SKIPE DISPRR	;IF EXITING THE OUTERMOST LEVEL OF ^R,
	 JRST RREXI1
	CALL SETTTM	;TURN ON SYSTEM ECHOING AGAIN.
	MOVE CH,QRB..
	SKIPE A,.QCRMC(CH) ;EXECUTE THE SECRETARY MACRO IF ANY.
	 CALL MACXQ
RREXI1:	REST C		;POP QREG PDL PTR SAVED AT ENTRY TO ^R
	CALL FSQPU0	;UNWIND PDL DOWN TO THAT LEVEL.
	JRST POP1J

RRTHRW:	MOVE CH,DISPRR	;RETURN TO ^R MAIN LOOP.
	PUSHJ CH,SETP
	MOVEI TT,RRLP	;RETURN TO IT AT NORMAL RETURN, NO MATTER WHERE WE LEFT IT FROM.
	MOVEM TT,(P)
	.I RRLAST=RRPRVC	;MAKE SURE ARGS GET FLUSHED.
	JRST RREAR0	;WE'RE COMING FROM OUTSIDE ^R, SO MUST OFFICIALLY RE-ENTER.

RRLEAV:	.I RREZ=Z
	.I RREBEG=BEG
RRLEA1:
RRLEA2:	.I RREPT=PT
	.I RREHPS=RRHPOS
	.I RREVPS=RRVPOS
	.I RREBUF=BFRSTR
	RET


;[ ;HANDLE THE ^] COMMAND IN ^R MODE.
;CLOBBERS ALL ACS. SKIPS.
RRBRC:	SKIP
	MOVEI A,[ASCIZ /[0[1MU0:I1
<@V@:FT0 FIU0 :I110 Q0-."N0;'>
F@:M(:I* F@:M1(]1]0) ) /]

RRMAC0:	SKIP		;SUPPLY ^R-STYLE NUMERIC ARG AS ARG TO MACRO.
	MOVEM C,NUM	;SUPPLY THE COMMAND'S ARG, OR 1 (THE DEFAULT), TO THE MACRO,
	TRZ FF,FRARG
	SKIPE RRARGP
RRMAC6:	 IORI FF,FRARG	;AND TELL IT IT HAS AN ARG IF THE ARG IS NON-DEFAULTED.
	JRST RRMAC5

;CALL THE MACRO IN A WITH NO ARG., AND LOOK AT ITS RETURNED VALUES TO DECIDE
;HOW TO UPDATE THE ^R-MODE VARIABLES.
RRMACR:	ANDCMI FF,FRARG
	SETZM NUM
RRMAC5:	SETZM SARG
	TRZ FF,FRARG2	;IN ANY CASE THE MACRO DOESN'T HAVE 2 ARGS.
RRMAC7:	ANDCMI FF,FRCLN\FRSYL\FROP	;TURN OFF RANDOM FLAGS.
	SKIPE RREBEG	;IF WE HAPPEN TO BE CALLED FROM TECO COMMANDS, NOT ^R ITSELF,
	 JRST MACXQW	;DON'T INTERFERE WITH THE "RRE" VARIABLES.  JUST CALL THE MACRO.
	CALL RRLEAV	;SET UP THE "RRE" VARIABLES.
	CALL MACXQW	;EXECUTE THE MACRO.
	JRST RREAR0

SUBTTL PROCESS ARGUMENTS/VALUES GIVEN TO ^R

RREAR0:	TLO FF,FLNOIN	;EXECUTING COMMANDS CLOBBERS FLNOIN, SO RESTORE IT
	MOVE A,DISPRR
	SKIPL -3(A)
	 TLZ FF,FLNOIN	;TO SAY WHETHER THIS IS ^R OR @V.
RREARG:	SKIPE ECHOFL
	 CALL NOECHO
RREAR1:	CALL VBDACU	;MAKE SURE FS ALTCOUNT IS IN PHASE WITH REALITY
	 JFCL
	MOVE C,NLINES
	CALL WINSET	;COMPUTE SIZE AND POS OF WINDOW, SET RRTOPM. RRBOTM, BOTLIN, VSIZE.
	MOVMS DISTRN	;TRUNCATION SCREWS ^R-MODE.
	MOVE T,BFRSTR
	CAME T,RREBUF	;IF BUFFER HAS BEEN SWITCHED ON US, RECOMPUTE THE DISPLAY!
	 SETOM RRMNVP
	.I RRHPOS=RREHPS
	.I RRVPOS=RREVPS
	MOVE A,BEG	;RELOCATE ALL ^R-MODE POINTERS INTO BUFFER.
	SUB A,RREBEG
	SETZM RREBEG	;DECLARE ^R IN CONTROL; PREVENT ^G INT LVL QUIT.
	ADDM A,RREPT
	ADDM A,RREZ
	SKIPN RGETTY
	 JRST RRTTY
	CALL RRFXRL		;RELOCATE LINBEG TABLE BY A.
	MOVE BP,TOPLIN
	MOVE T,GEA		;IF CURRENT FS WINDOW$ IS NOT CONSISTENT WITH LINBEGS,
	ADD T,BEGV		;WE SHOULDN'T HAVE BEEN FED ANY ARGS,
	LDB B,[3300,,LINBEG(BP)]
	CAMN B,T
	 CAMLE B,ZV		;SO FLUSH THEM.  SAME GOES IF FS WINDOW$ IS IMPOSSIBLE.
	  TRZ FF,FRARG
	MOVE C,QRB..
	SKIPE TT,MORFLF		;IF OUR MACRO RAN INTO A --MORE--FLUSHED,
	 SETOM TYOFLG		;DON'T LET IT STAY AROUND TO PLAGUE NEXT COMMAND,
;	SKIPE MORFLF
;	 SETZM .QVWFL(C)	;AND WE CAN ALSO REDISPLAY RIGHT NOW.
;REMOVED SO THAT FLUSHING WITH A RUBOUT WILL CAUSE REDISPLAY AFTER THE NEXT INPUT CHAR.
;IS NOT EXPECTED TO AFFECT WHAT HAPPENS WHEN YOU FLUSH WITH NON-RUBOUT.
	SETZM MORFLF
	MOVEM TT,OLDFLF
	MOVE TT,MORESW
	SKIPN .QVWFL(C)	;DOES STUFF ON SCREEN WANT TO BE PRESERVED?
	 JRST [	CAIE TT,MS%FLS	;NO:  BUT IF MODE LINE SAYS --MORE--FLUSHED,
		 JRST RREAR2	;WE MUST ACT TO PREVENT LOSS AT RRLP3.
		JRST RREAR4]
	SETZM .QVWFL(C)
	CALL TYINH	;YES: WAIT TILL USER TYPES A CHARACTER SAYING
	CAIE CH,40
	 MOVEM CH,UNRCHC ;HE HAS READ THE STUFF (DON'T FLUSH THE CHARACTER UNLESS IT'S A SPACE)
RREAR4:	CALL RRLRDS	;NOW MAKE SURE THAT THE BUFFER IS REDISPLAYED AFTER THIS CHARACTER
	SETZM RRMSNG	;NOTE LINES MAY NEED REDISPLAY EVEN THOUGH AFTER RRMAXP.
	SETZM ERRFL1	;NO NEED TO PROTECT AN ERROR MESSAGE PAST NEXT INPUT CHARACTER.
RREAR2:	MOVE C,NUM	;GETARG WANTS 2ND VALUE IN C.
	MOVE E,SARG	;AND 1ST VALUE IN E.
	SKIPL RRMNVP	;*IF THIS IS A SCREW, AT LEAST DO THIS IN RREAR3*
	TRNN FF,FRARG	;MACRO RETURNED NO ARG =>
	 JRST RRMAC1	;DON'T ASSUME ANYTHING.
	SKIPGE GEA	;PREVENT CONFUSION IF ALREADY KNOW GOING TO DO FULL REDISPLAY.
	 JRST RRMAC1
	TRNN FF,FRARG2	;1 ARG => ONLY PT HAS CHANGED.
	 JRST RREAR5
	CAML E,C	;2 ARGS.
	 EXCH C,E	;DO F^@ - PREVENT 2<1 ERROR BY ORDERING THE ARGS PROPERLY.
	CALL GETANU	;TURN MACRO'S VALUES INTO CHAR ADDRS.
	CALL RRLMOV	;FIND VPOS IN BP OF LOWEST UNCHANGED LINE.
	 JRST RRMAC3	; CHANGES ARE BELOW SCREEN, NOTHING TO DO.
	CAMGE BP,TOPLIN
	 JRST RREAR3	;IF CHANGES REACH PAST TOP, SCROLL DOWN.
	MOVE TT,Z
	SUBM TT,RREZ	;RREZ _ CHANGE IN # CHARS IN BUFFER.
	SAVE PT
	CALL RRHMOV
	CALL RRCRDB	;MOVE BACK TO ELIMINATE BEFORE-EFFECTS.
	REST E		;WE ARE JUST BEFORE 1ST PLACE ON SCREEN
	MOVE BP,RRVPOS	;THAT WAS CHANGED. MARK THIS AS PLACE
	MOVE T,RRHPOS	;THAT REDISPLAY MUST START BEFORE.
	CALL RRDLB2	;UPDATE RRMNVP AND RRMNHP.
	CALL RRQMOV	;GET BACK CORRECT PT, MOVE FWD TO THERE, GETTING CORRECT HPOS AND VPOS.
	MOVE E,C
	MOVE A,RREZ
	JRST RRFXMX	;UPDATE RRMAXP.

;COME HERE IF ONE ARG (ONLY POINT HAS CHANGED).  IN CASE THAT ASSUMPTION IS FALSE,
;CHECK IT JUST ENOUGH TO AVOID CRASHING IF IT'S EXTREMELY FALSE.
RREAR5:	MOVE TT,RRMNVP	;IF TEXT HAS BEEN CHANGED ENOUGH THAT
	CAIGE TT,777777	;THE TEXT WE EXPECT TO START DISPLAY AT
	 JRST RREAR6
	MOVE TT,BOTLIN
	SUBI TT,1
RREAR6:	LDB TT,[003300,,LINBEG(TT)]
	CAMLE TT,ZV	;IS NOW A NONEXISTENT ADDRESS,
	 JRST RRMAC1	;THEN DO FULL REDISPLAY SO WE DON'T CRASH LATER.
	JRST RRMAC3	;OTHERWISE NO ADDITIONAL REDISPLAY IS NEEDED.

;HERE FOR CHANGES THAT REACH PAST TOP OF SCREEN.
;FIGURE OUT WHERE CHANGES STOP, AND CHOOSE A NEW WINDOW TO PUT THAT POINT
;ON THE SAME LINE WHERE IT IS NOW, THUS AVOIDING REDISPLAYING THE UNCHANGED TEXT.
RREAR3:	MOVE A,Z
	SUB A,RREZ
	MOVE E,C	;FIRST, ADJUST RRMAXP FOR THE CHANGES MADE.
	CALL RRFXMX
	CALL RRLID2	;THEN, FIND 1ST UNALTERED LINE'S POS IN BUFFER AND SCREEN
	 JRST RRMAC1	;THERE IS NONE => DO FULL REDISPLAY.
	MOVE A,RRIDVP	;A GETS THAT LINE'S VPOS.
	SUB A,TOPLIN
	LDB E,[014300,,A]
	ADD A,E		;IF IT IS IN THE BOTTOM 1/3 OF THE SCREEN,
	ADD A,TOPLIN
	CAML A,BOTLIN	;MIGHT AS WELL RE-CENTER THE WHOLE THING.
	 JRST RRMAC1
	SAVE PT
	LDB A,[3300,,RRIDLB]
	MOVEM A,PT	;OTHERWISE, PICK A WINDOW THAT DOESN'T REQUIRE IT TO MOVE.
	MOVE A,RRIDVP	;CALCULATE WINDOW PUTTING PT AT VPOS IN A.
	CALL VBDBL1
	MOVEM B,RRVPOS
	MOVE A,RRIDLB	;OK, POINT OF LAST CHANGE HASN'T MOVED ON SCREEN,
	ASH A,-33	;BUT CURSOR MIGHT NOT BE AT THE END OF CHANGED REGION.
	MOVEM A,RRHPOS	;SO FIGURE OUT WHERE THE CURSOR IS.
	REST E
	CALL RRMOV
;HERE TO SAY REDISPLAY MUST START AT THE TOP OF THE SCREEN, BUT NOT REQUIRE TESTING THE WINDOW.
;SAYS NOTHING ABOUT WHERE REDISPLAY NEEDS TO END.
RRLRDS:	MOVE TT,TOPLIN	;NOW THAT WINDOW HAS BEENCHANGED, EVERY LINE NEEDS REDISPLAY.
	CAMGE TT,RRMNVP	;IF RRMNVP IS -1, DON'T FORGET THAT FACT!
	 MOVEM TT,RRMNVP
	SETZM RRMNHP
	MOVE A,GEA	;AND WE MUST SET UP FIRT LINE'S LINBEG SO DISPLAY STARTS OFF RIGHT.
	ADD A,BEGV	;WE COULD JUST SETOM RRMNVP, BUT THEN THE WINDOW, WHICH WE KNOW IS
	MOVEM A,LINBEG(TT)	;VALID, WOULD BE WASTEFULLY REBLESSED.
	RET

;FIGURE OUT CURRENT CURSOR POSITION OF CHAR ADDR IN E.
;USES THE OLD LINBEGS AND RRMNVP, AS A SHORTCUT.
RRQMOV:	CALL RRLMOV
	 JFCL
	CAMGE BP,TOPLIN
	 MOVE BP,TOPLIN
;ASSUMES BP WAS SET UP BY CALLING RRLMOV.
RRHMOV:	MOVEM BP,RRVPOS	;SET PT, RRVPOS AND RRHPOS TO VALUES
	LDB TT,[3300,,LINBEG(BP)]
	MOVEM TT,PT	;AT START OF LINE ON WHICH 1ST CHANGE LIES.
	MOVE TT,LINBEG(BP) ;THOSE ARE STILL VALID, SINCE NOTHING CHANGED ABOVE THEM.
	ASH TT,-33
	MOVEM TT,RRHPOS
	JRST RRMOV	;THEN SCAN FROM THERE TO THE DESIRED POINT.

;FIND IN BP THE VERTICAL POSITION OF THE LOWEST LINE
;WHICH, AS OF LAST DISPLAY (NOT, NOT, NOW) BEGAN BEFORE THE CHAR ADDR IN E.
RRLMOV:	MOVE BP,RRMNVP
	CAMN BP,[377777,,777777]
	 JRST RRLMO1
	LDB TT,[3300,,LINBEG(BP)]
	CAMGE TT,E
	 JRST POPJ1
RRLMO1:	MOVE BP,TOPLIN
	SOS BP
RRMAC2:	MOVEI TT,1(BP)
	CAME BP,RRMNVP	;WE CAN'T USE A VPOS WHOSE LINBEG DOESN'T EXIST OR ISN'T VALID.
	 CAMN TT,BOTLIN
	  JRST POPJ1
	LDB TT,[3300,,LINBEG+1(BP)]
	CAML TT,RROLZV	;IF CHANGES WERE INSERTION AT END OF BFR, WE WANT TO FIND THE LINE
	 JRST [ CAMGE BP,TOPLIN	;WHICH CONTAINS THE LAST OF THE OLD TEXT CHARACTERS.
		 MOVE BP,TOPLIN	;INSERTION INTO EMPTY BUFFER IS A CHANGE STARTING WITH LINE 0.
		JRST POPJ1]
			;IF CHANGES START AT 1ST CHAR OF NEXT LINE, WE NEED NOT SCAN THIS LINE,
	CAMN TT,E	;UNLESS NEXT LINE STARTS IN MID-CHARACTER,
	 SKIPL LINBEG+1(BP)	;IN WHICH CASE THE CHAR REALLY BEGINS ON THIS LINE.
	  CAMLE TT,E		;IF CHANGES START BEFORE NEXT LINE, MUST SCAN THIS LINE.
	   JRST POPJ1
	;THIS CHANGED FROM CAML SO THAT ^K'ING TOP LINE OF SCREEN
	;WOULD NOT END UP SAYING CHANGES REACH PAST TOP OF SCREEN, ETC.
	AOJA BP,RRMAC2		;IF CHANGES START AFTER END OF LINE, NEED NOT SEARCH IT.

;UPDATE THE "MINIMUM SCREEN POSITION THAT CHANGED"
;USING DICTIONARY ORDER ON RRVPOS, RRHPOS.
;TAKES VPOS, HPOS OF START OF NEW CHANGE IN BP, T.
;CLOBBERS T.
RRDLB2:	CAML BP,BOTLIN		;DON'T EVER LET RRMNVP BECOME AS LARGE AS BOTLIN.
	 JRST [	MOVE BP,BOTLIN
		SOJA BP,.+1]
	CAMLE BP,RRMNVP
	 POPJ P,
	CAMGE BP,TOPLIN		;DON'T ALLOW RRMNVP TO BECOME LESS THAN TOPLIN.
	 SETO BP,		;MAKE IT -1 (WHICH IS SPECIAL) IF CHANGES GO OFF TOP.
	EXCH BP,RRMNVP
	CAMG BP,RRMNVP
	CAMG T,RRMNHP
	 MOVEM T,RRMNHP
	CAMN BP,RRMNVP
	 RET
	MOVE T,RRMAXP		;IT CAN LEGITIMATELY HAPPEN THAT LINBEGS BEFORE
	CAILE T,1		;THE OLD RRMNVP ARE SMALLER THAN THE OLD RRMAXP.
	 CAMLE T,LINBEG(BP)	;IF SO, IF WE MOVE RRMNVP UP AND DON'T CHANGE
	  RET
	SKIPL RRMSNG		;RRMAXP MUCH OR AT ALL, WE COULD FORGET ABOUT
	 CAMG BP,RRMSNG		;THE CHANGES BELOW THE OLD RRMNVP.
	  MOVEM BP,RRMSNG	;SO USE RRMSNG TO REMEMBER THEM.
	POPJ P,

RRFXM1:	MOVE E,PT
	CALL RRDLB2
;UPDATE RRMAXP. SIGNED # CHARS INSERTED OR DELETED IN A,
;PLACE INSERTED OR DELETED IN E.
RRFXMX:	MOVE T,RRMAXP	;NOTE RRMAXP MAY HAVE THE SPECIAL VALUE INFINITY (LARGEST POS NUMBER)
	AOS T
	CAILE T,1	;IN WHICH CASE IT SHOULDN'T BE RELOCATED.
	 ADDM A,RRMAXP	;RELOCATE OLD VALUE IN CASE IT'S ABOVE WHERE CHANGE HAPPENED.
	CAML E,RRMAXP
	 MOVEM E,RRMAXP	;MAKE SURE RRMAXP IS ABOVE PLACE CHANGE HAPPENED.
	POPJ P,

;SET PT TO VALUE IN E, UPDATING CURSOR POS.
;CLOBBERS A,B,TT,TT1,IN,OUT
RRMOV:	CAMN E,PT	;PT SAME AS MARK => DO NOTHING.
	 POPJ P,
	MOVE A,E
	SUB A,PT	;MOVING A LONG DISTANCE => DON'T BOTHER TO KEEP TRACK OF
	MOVMS A		;CHANGES IN VPOS AND HPOS.  JUST GO THERE AND RECOMPUTE HPOS.
	CAIL A,10000.
	 SKIPN RGETTY
	  CAIA
	   JRST RRMOVL
	CAML E,PT
	 JRST RRMOVF	;PT BEFORE DESIRED PT => GO FWD.
RRMOVB:	CALL RRBACK
	CAMN E,IN	;REACHED THE DESIRED PT YET?
	 RET
	SKIPL A,RRVPOS	;GONE ABOVE TOP OF SCREEN?
	 JRST RRMOVB
	MOVNS A		;ON TERMINAL WITH INSERT/DELETE LINE, KEEP TRACK OF VPOS
	ADD A,TOPLIN
	CAMGE A,VSIZE	;TILL WE GET A SCREEN HEIGHT ABOVE THE TOP OF THE SCREEN.
	 SKIPN LID	;UNTIL THAT POINT, THERE MAY BE SOME ADVANTAGE IN SCROLLING
	  CAIA		;THE SCREEN DOWN, AND FOR THAT WE NEED TO KEEP THE VPOS.
	   JRST RRMOVB
RRMOVL:	MOVEM E,PT	;IT'S PROBABLY FASTER TO REQUEST COMPLETE RECOMPUTATION.
	JRST RRMAC1

RRMOVF:	MOVE TT,RRVPOS
	ADDI TT,3
	SAVE TT
RRMOVG:	CALL RRFORW
	CAMN E,IN
	 JRST POP1J
	MOVE TT,RRVPOS
	MOVE TT1,(P)	;IF GO AT LEAST 3 LINES (FOR RRTTY'S SAKE, TO AVOID HAVING LONG JUMPS
	CAML TT,TT1	;LOOK LIKE MOTION TO NEXT LINE) AND
	CAMG TT,BOTLIN	;GONE BELOW BOTTOM OF SCREEN, THEN DON'T BOTHER SCANNING IT OUT.
	 JRST RRMOVG
	SUB TT,BOTLIN	;ON TTY WITH INSERT/DELETE LINE, KEEP TRACK OF VPOS
	CAMGE TT,VSIZE	;TILL A SCREEN HEIGHT BELOW THE BOTTOM, IN CASE WE CAN
	 SKIPN LID	;SAVE DISPLAY BY SCROLLING THE TEXT UPWARD.
	  CAIA
	   JRST RRMOVG
	SUB P,[1,,1]
	JRST RRMOVL

;<M>,<N>F^R - REPORT CHANGES BETWEEN <M>,<N> TO ^R WITHOUT DISPLAYING ANYTHING.
;F^R TELLS ^R NOT TO REMEMBER ANYTHING FROM ITS PREVIOUS DISPLAYING.

;:F^R FORCES A VALID FS WINDOW$ TO BE CALCULATED NOW.
;SET FS WINDOW TO -1 FIRST, TO FORCE A NEW WINDOW TO BE COMPUTED FROM SCRATCH.
;DO A F^R FIRST TO AVOID ASSUMING THAT FS ^R VPOS$ IS VALID.
;<VPOS>:F^R CHOOSES A WINDOW THAT PUTS POINT ON LINE <VPOS>+FS TOPLIN$
;A NEGATIVE <VPOS> COUNTS FROM THE BOTTOM OF THE USABLE WINDOW.
;IF THE WINDOW IS CHANGED, THAT FACT IS REPORTED TO ^R IMMEDIATELY,
;SO YOU CAN RETURN ONE VALUE TO ^R IF YOU ARE SURE YOU DON'T INVALIDATE IT.

;@:F^R IS LIKE :F^R EXCEPT THAT, IF INSERT/DELETE LINE ARE AVAILABLE,
;IT IMMEDIATELY SHIFTS STUFF ON THE SCREEN TO REDUCE EVENTUAL REDISPLAY.

;<TOP>,<BOTTOM>@ F^R SAYS LINES FROM TOP (INCLUSIVE) TO BOTTOM (EXCLUSIVE) NEED REDISPLAY.
RRALTR:	TRNE FF,FRCLN
	 JRST RRALT1
	TRNE FF,FRUPRW	;@F^R IS FOR EXITING THE MINIBUFFER.
	 JRST RRMNX
	TRNN FF,FRARG	;NO ARG => SAY ALL HAS CHANGED.
	 JRST RRMAC1
	TRNN FF,FRARG2	;1 ARG => SAY NOTHING HAS.  ^R WILL KNOW ANYWAY
	 RET		;IF POINT HAS BEEN CHANGED.
	MOVE C,NLINES
	CALL WINSET	;COMPUTE SIZE AND POS OF WINDOW, SET RRTOPM. RRBOTM, BOTLIN, VSIZE.
	MOVE A,BEG	;2 ARGS => REPORT MODIFICATIONS TO PART OF BUFFER.
	SUBM A,RREBEG
	EXCH A,RREBEG
	CALL RRFXRL
	CALL [	SKIPE RGETTY
		 JRST RREAR2
		JRST RRTTY]
	.I RREZ=Z
	JRST RRLEA2

RRALT1:	SKIPGE C	; :F^R COMES HERE.
	 ADD C,VSIZE	;A NEGATIVE ARG COUNTS FROM WINDOW BOTTOM.
	ADD C,TOPLIN	;ALL ARGS ARE RELATIVE TO WINDOW, NOT ABSOLUTE ON SCREEN.
	MOVE A,C
	TRNE FF,FRARG	;NO ARG => TEST OLD WINDOW, BASED ON RRVPOS.
	 JRST RRALT2
	SKIPL GEA	;OLD WINDOW NOT KNOWN OR RRVPOS REPORTED SUSPECT => 
	 SKIPGE RRMNVP
	  JRST RRALT7	;SKIP THE FAST CHECK, AND DO ORDINARY BLESSING.
	MOVE B,PT	;THE FAST CHECK IS ONLY APPLICABLE WHEN POINT IS
	CAME B,RREPT	;AT THE PLACE WE HAVE REMEMBERED THE VPOS OF.
	 JRST RRALT7
	CALL RRWBLS
	 CAIA		;FAST CHECK APPLICABLE AND LOSES => NEW WINDOW CERTAINLY NEEDED,
	  RET
RRALT6:	SETOB A,GEA	; SO TELL VBDBLS NOT TO BOTHER WITH THE OLD ONE.
RRALT2:	CAML A,TOPLIN
	 CAML A,BOTLIN
RRALT7:	  SETO A,
	SAVE GEA
	SAVE RRVPOS
	CALL VBDBLS
	REST E		;E HAS PREVIOUS VPOS OF POINT.
	REST A		;A HAS PREVIOUS ADDRESS OF TOP LINE.
	MOVEM B,RREVPS	;B HAS NEW VPOS OF POINT.
	MOVEM B,RRVPOS
	.I RREHPS=CHCTHP
	.I RREPT=PT	;WHEN WE RETURN TO ^R IT SHOULD KNOW WHICH POINT RREVPS REFERS TO.
	CAMN A,GEA	;IF THE WINDOW IS ACTUALY CHANGED,
	 RET
	SKIPE LID	;AND WE CAN'T OR SHOULDN'T MOVE THE TEXT,
	 TRNN FF,FRUPRW
	  JRST RRALT5
	SKIPL RRMNVP
	 JRST RRALT3
RRALT5:	SETZM RRMSNG	;JUST TELL ^R THAT EVERY LINE NEEDS REDISPLAY BUT WINDOW IS OK.
	SKIPN TOPLIN
	 SKIPE NLINES
	  JRST RRLRDS
	SKIPE NOCEOL	;IF TTY HAS NO CLEOL, IT IS FASTER TO CLEAR THE SCREEN FIRST.
	 SETOM PJATY
	JRST RRLRDS

;HERE TO TRY TO MOVE TEXT ON THE SCREEN WITH INSERT/DELETE LINE
RRALT3:	MOVN C,B	;HOW FAR ARE WE MOVING TEXT, AND WHICH WAY?
	ADD C,E
	MOVM E,C	;GET MAGNITUDE OF DISTANCE MOVED.
	CAML E,VSIZE	;MOVING MORE THAN SCREEN HEIGHT => ALL OF OLD WINDOW GOING OFF SCREEN
	 JRST RRALT5	;SO DON'T BOTHER WITH THIS.
	MOVE BP,TOPLIN	;THE LINE THAT WILL MOVE TO POSITION TOPLIN
	MOVE E,C	;IS NOW ON THE SCREEN AT POSITION TOPLIN+C(C).
	ADD E,BP	;TELL DSLID WHAT THAT POSITION IS.
	MOVEM E,RRIDVP	;FOR DOWNWARD MOTION, THAT LINE IS FICTITIOUS, BUT DSLID KNOWS THAT.
	JUMPL C,RRALT4
	;MOVING UP => PRETEND DELETED THE FIRST FEW LINES ON THE SCREEN.
	CAML E,RRMNVP	;CAN'T WIN IF CHANGES TO TEXT EXTEND ABOVE WHAT WILL BECOME
	 JRST RRALT5	;THE FIRST LINE ON THE SCREEN, SINCE IN THAT CASE ITS LINBEG IS WRONG.
	MOVE TT,LINBEG(E)
	MOVEM TT,RRIDLB	;RRIDLB GETS LINBEG OF WHAT WILL BECOME THE TOP LINE ON SCREEN.
	MOVE TT,RRMNVP	;RRMNVP MOVES UP WITH THE TEXT.
	CAMN TT,[SETZ-1]
	 MOVE TT,BOTLIN		;IF RRMNVP HAD BEEN INFINITE, SET IT TO THE FIRST OF THE NEWLY
	SUB TT,C	;INSERTED BLANK LINES ABOVE THE MODE LINE.
	SOS TT		;DECREMENT AGAIN TO REACH LOWEST LINE THAT HAS A VALID LINBEG.
	MOVEM TT,RRMNVP	;NOTE IT CAN'T GO PAST TOPLIN, DUE TO CAML E,RRMNVP ABOVE.
	SOS BP
	CALL DSLID	;MOVE THE STUFF UP, RIGHT NOW.  BP HAS -1 PLUS LINE WE ARE "AT".
	 JRST RRALT5	;IF DSLID DECIDED TO ABORT, THAT'S OK.  JUST REDISPLAY.
	JRST RRLID5	;GO DO BOOKKEEPING FOR MOTION JUST DONE.

RRALT4:	AOS RRIDVP	;COMPENSATE FOR DIFFERENT MEANING OF THIS AND BP IF MOVING TEXT DOWN.
	CALL DSLID	;MOVE IT.
	 JFCL
	MOVE CH,RRIDLB	;SAY THAT CHANGES REACH PAST ALL THE BLANK LINES JUST MADE
	TLZ CH,777000	;AT THE TOP OF THE SCREEN.  JUST SETTING RRMSNG DOESN'T WORK
	ADDI CH,1	;SINCE RRLID RUNS AND THINKS THAT THOSE BLANK LINES CONTAIN
	CAML CH,RRMAXP	;VALID TEXT.  BUT RRMAXP AS SET HERE SAYS THAT TEXT IS USELESS.
	 MOVEM CH,RRMAXP
	JRST RRLRDS	;THEN SAY EVERY LINE MIGHT NEED REDISPLAY.

;HERE FOR <TOP>,<BOTTOM>@ F^R SAYING LINES FROM TOP (INCLUSIVE) TO BOTTOM (EXCLUSIVE)
;NEED REDISPLAY.
RRMNX:	CAML C,RRMNVP	;HANDLE END OF RANGE OF VPOS'S BY SETTING RRMAXP TO CORRESPOND TO IT,
	 JRST RRMNX1	;OR, IF LINBEGS AROUND THERE ARE UNKNOWN, BY SETTING RRMSNG.
	LDB T,[3300,,LINBEG(C)]
	MOVEM T,RRMAXP
	JRST RRMNX2

RRMNX1:	MOVEM E,RRMSNG	;HERE, SAY ALL LINES PAST TOP OF RANGE MIGHT NEED REDISPLAY.
RRMNX2:	MOVE BP,E	;HANDLE BEGINNING OF RANGE OF VPOS'S BY SETTING RRMNVP THERE.
	SETZ T,
	JRST RRDLB2

;<M>,<N>FM - MOVE DOWN TO HPOS <N>, <M> LINES DOWN.
;<M>,<N>@FM - MOVE UP TO HPOS <N>, -<M> LINES UP.
;NORMALLY, EXACT VALUE OF HPOS IS NEEDED TO STOP SCAN.
;BUT COLON MODIFYER => ANY LARGER HPOS IS ALSO OK.
;IF SCAN DOESN'T FIND AN ACCEPTABLE HPOS ON THE DESIRED LINE
;THEN EITHER A NIB ERROR OR A NHP ERROR WILL RESULT.
;FM TRIES TO AVOID STOPPING BETWEEN A CR AND ITS LF.
FMCMD:	TRNE FF,FRARG2
	 TRNN FF,FRARG
	  TYPRE [WNA]
	CALL RRBTCR	;MAKE SURE RRHPOS IS CORRECT FOR CURRENT BUFFER AND PT.
	ADD E,RRVPOS	;E IS DESTINATION VPOS.
	MOVE IN,PT
	TRNE FF,FRUPRW
	 JRST FMBACK	;NOW FORWARD AND BACKWARD MOTION DIVERGE.
FMFWD:	CAMGE E,RRVPOS	;IF WENT PAST TARGET LINE, WITHOUT STOPPING ON IT, BARF.
	 JRST [ CALL RRBCRL	;MOVE BACK TO END OF DESIRED LINE.
		TYPRE [NHP]]
	CAME E,RRVPOS	;IF HAVE REACHED TARGET VPOS,
	 JRST FMFWD1
	TRNE FF,FRCLN
	 CAML C,RRHPOS	;AND HAVE REACHED TARGET HPOS,
	  CAMN C,RRHPOS
	   RET
FMFWD1:	CAML IN,ZV
	 TYPRE [NIB]	;AT END OF BUFFER WITHOUT REACHING TARGET => BARF.
	CALL RRFORW
	JRST FMFWD

FMBACK:	CAMLE E,RRVPOS	;WENT PAST TARGET VPOS WITHOUT FINDING TARGET HPOS => BARF.
	 JRST [	CALL RRFCRL	;RETURN TO DESIRED LINE BEFORE COMPLAINING.
		TYPRE [NHP]]
	CAME E,RRVPOS	;REACHED TARGET VPOS
	 JRST FMBAC1
	TRNE FF,FRCLN
	 CAML C,RRHPOS
	  CAMN C,RRHPOS
	   RET
FMBAC1:	CAMG IN,BEGV
	 TYPRE [NIB]
	CALL RRBCRL
	JRST FMBACK

;MOVE FORWARD OVER EITHER A SINGLE CHAR OR A CRLF.
RRFCRL:	CALL RRFORW
	CAIE CH,^M
	 RET
	CALL GETCHR
	CAIE CH,^J
	 RET
	JRST RRFORW

;MOVE BACKWARD OVER EITHER A SINGLE CHAR OR A CR-LF PAIR.
RRBCRL:	CALL RRBACK	;MOVE BACK 1 CHAR,
	CAIE CH,^J	;AND IF THAT LEAVES US BETWEEN A CR AND ITS LF,
	 RET		;MOVE BACK 1 MORE.
	SOS IN
	CALL GETINC
	CAIE CH,^M
	 RET
	JRST RRBACK

SUBTTL ^R COMMAND DISPATCH TABLE MANAGEMENT

;<CHAR>FS ^R INIT$ RETURNS THE INITIAL SETTING OF <CHAR>FS ^R CMAC$.
;THE UPARROW FLAG HAS THE SAME MEANING AS FOR FS ^R CMAC$.
FSCRIN:	TRZN FF,FRARG
	 TYPRE [WNA]
	CALL TYIABN		;IF DON'T HAVE UPARROW FLAG, CONVERT ASCII ARG TO 9-BIT.
	MOVEI CH,(C)
	TRZN CH,META
	 TRNN C,CONTRL
	  SKIPA A,[RRXINS]	;META OR NON-CONTROL CHARS ARE SELF-INSERTING (EXCEPT RUBOUT)
	   MOVEI A,RRUNDF	;MOST CONTROLS ARE ERRORS.
	LDB Q,[.BP 177,CH]
	CAIL Q,40+"A
	 CAILE Q,40+"Z
	  CAIA			;IF THE ASCII PART IS LOWER CASE,
	   MOVE A,[40,,RRINDR]	;IT IS A "RRINDR" CHAR (INDIRECT).
	CAIN CH,CONTRL+33	;CONTROL-ALTMODE GOES INDIRECT THROUGH ALTMODE.
	 MOVE A,[200,,RRINDR]	;AND SIMILAR FOR CONTROL-META-ALTMODE.
	CAIL CH,CONTRL+^H	;SIMILAR FOR CONTROL-BS, CONTROL-TAB, CONTROL-LF,
	 CAILE CH,CONTRL+^J	;CONTROL-CR, AND META EQUIVALENTS.
	  CAIN CH,CONTRL+^M
	   MOVE A,[200,,RRINDR]
	CAIL CH,CONTRL+"H
	 CAILE CH,CONTRL+"J
	  JRST FSCRI1
	MOVE A,[300,,RRINDR]
	JRST POPJ1

FSCRI1:	CAIN C,33		;ALTMODE ON TV IS NOT SAME AS CTL-[  ;]
	 MOVEI A,RREXIT
	CAIN C,^M		;SIMILARLY, HANDLE CR (WHICH IS NOT CTL-M)
	 MOVE A,[RRCRLF,,RRREPT]
	CAIL C,^H
	 CAILE C,^J
	  CAIA
	   MOVE A,[RRINSC,,RRREPI]
	CAIL Q,"0		;CONTROL, META AND C-M-DIGITS ALL ADD TO ARGUMENT TO NEXT CMD.
	 CAILE Q,"9
	  JRST FSCRI2
	TRNE C,CONTRL+META
	 MOVEI A,RRCDGT
FSCRI2:	CAIE Q,"-		;C-MINUS, M-MINUS AND C-M-MINUS ALL SET "NEGATE ARG" FLAG
	 JRST FSCRI3
	TRNE C,CONTRL+META
	 MOVEI A,RRCMNS
FSCRI3:	CAIN C,177		;RUBOUT IS A RUBOUT.
	 MOVEI A,RRRUB
	CAIN C,CONTRL+177	;CTL-RUBOUT IS TAB-HACKING RUBOUT.
	 MOVEI A,RRCRUB
	CAIL C,CONTRL+"@
	 CAILE C,CONTRL+"_
	  JRST POPJ1
	SUBI C,CONTRL+"@	;AS A LAST RESORT, LOOK CHAR UP IN RRITAB.
	ROT C,-1
	HRRZ A,RRITAB(C)	;INDEX TO HALFWORD OF INITIAL VALUE TABLE.
	SKIPL C
	 HLRZ A,RRITAB(C)
	TRZN A,400000		;400000 BIT => DEFINITION GOES THROUGH RRREPT.
	 JRST POPJ1
	HRLZS A
	HRRI A,RRREPT
	JRST POPJ1


;TABLE OF INITIAL ^R-MODE DEFINITIONS OF CONTROL CHARACTERS.
.SEE RRMACT	;CHANGE RRMACT WHEN YOU CHANGE THIS.
.BYTE 22
RRITAB:	RRUNDF		;^@
	RRBEG		;^A
	RRCTLB		;^B
	RRCMSW		;^C
	RRCTLD		;^D
	RREND		;^E
	RRCTLF		;^F
	RRQUIT		;^G
	RRINDR		;CONTROL-H (THIS ENTRY NOT ACTUALLY USED)
	RRINDR		;CONTROL-I    "
	RRINDR		;CONTROL-J    "
	RRKILL		;^K
	RRCTLL		;^L
	400000+RRINSC	;CONTROL M
	RRNEXT		;^N
	400000+RRCTLO	;^O
	RRPREV		;^P
	RRQUOT		;^Q
	RRCMCS		;^R
	RRSRCH		;^S
	RRMARK		;^T
	RR4TIM		;^U
	RRARG		;^V
	RRFX		;^W
	RREXCH		;^X
	RRUNDF		;^Y
	RRUNDF		;^Z
	RRUNDF		;CONTROL-[  ;]
	RRUNDF		;^\
	RRBRC		;[ ;^]
	RRUNDF		;^^
	RRUNDF		;^_
.BYTE

;GET OR SET THE MACRO ASSOCIATED WITH A CHARACTER
;(IF A CHAR HAS AN ASSOCIATED MACRO, WHEN THAT CHAR IS READ IN
;^R-MODE, THE MACRO IS CALLED INSTEAD OF THE USUAL ACTION FOR
;THAT CHARACTER.)
;^^<CHAR>FS^RCMAC$ GETS, Q<QREG>,^^<CHAR>FS^RCMAC$ SETS.
;CHARACTER IS ASSUMED TO BE ASCII. IF UPARROW FLAG IS ON,
;THE CHARACTER IS TREATED AS 9-BIT INSTEAD.
;DEPOSITS IN -1(P)! ASSUMES THE CALLER WAS THE FS COMMAND DISPATCH!
FSCRMA:	TRZN FF,FRARG
	 TYPRE [WNA]
	TRZE FF,FRARG2
	 IORI FF,FRARG	;2 ARGS => SETTING, ELSE GETTING.
	CALL TYIABN	;IF FRUPRW OFF, CONVERT ASCII ARG TO 9-BIT.
	MOVE E,C
	MOVE C,SARG
	CAIGE E,RRMACL	;LAST ARG OUT OF RANGE => ERROR.
	SKIPGE E
	 TYPRE [AOR]
	ADDI E,RRMACT	;E -> WORD TO BE SET OR GOTTEN.
	HRLM E,-1(P)	.SEE FSCALL
	TRNN FF,FRARG	;IF CHAR IS BEING REDEFINED,
	 JRST FSNOR1
	MOVE CH,E	;SET THE BIT IN RDFMSK FOR THIS CHARACTER
	CALL USE5
	JRST FSNOR1

TYIABN:	TRZN FF,FRUPRW	;IF FRUPRW IS OFF, CONVERT ASCII CHAR IN C TO 9-BIT.
	 CAIL C,40
	  RET
	CAIE C,33
	 CAIN C,^M
	  RET
	CAIL C,^H
	 CAILE C,^J
	  ADDI C,300
	RET

;<N> FS ^R IND RETURNS THE CHAR CODE THAT <N> INDIRECTS TO (MAY BE <N> ITSELF).
FSINDT:	TRZ FF,FRARG		;FLUSH ARG OR WE WILL ADD TO IT.
	CAIGE C,512.
	 CAIGE C,0
	  TYPRE [AOR]
	HRRZ A,C		;INITIALLY ASSUME CHAR NOT INDIRECT.
FSIND1:	HRRZ T,RRMACT(A)
	CAIE T,RRINDR
	 JRST POPJ1		;NOT INDIRECT => RETURN IT.
	HLRE T,RRMACT(A)	;ELSE COMPUTE THE CHAR IT INDIRECTS TO.
	SUB A,T
	JRST FSIND1

;<START>,<VAL> F^S <Q> SEARCHES BUFFER IN <Q> STARTING AT WORD <START>
;FOR A WORD CONTAINING <VAL>.  RETURNS IDX OF FIRST SUCH, OR -1 IF NONE.
;<START>,<VA.> :F^S SEARCHES ^R DEFINITION TABLE.
TABSRC:	TRNN FF,FRARG
	 TYPRE [WNA]
	MOVE J,[-RRMACL,,RRMACT]
	TRNE FF,FRCLN		;COLON => SEARCH ^R DEFINITION TABLE.
	 JRST TABSR1
	CALL QREGX		; ELSE READ QREG NAME
	CALL QLGET0		; GET BYTE POINTER AND LENGTH
	 TYPRE [QNS]
	IBP BP			; INSURE WORD ALIGNED
	HLRZ A,BP
	CAIE A,350700
	 TYPRE [ARG]
	MOVE T,B		; CONVERT BYTE COUNT TO WORD COUNT
	IDIVI T,5
	HRLOI J,-1(T)		; GET AOBJN POINTER
	EQVI J,(BP)		; ...
TABSR1:	HRLS E
	ADD E,J			;1ST ARG IS # OF ENTRIES AT FRONT OF TABLE NOT TO TEST.
	CAME C,(E)
	 AOBJN E,.-1
	TRZ FF,FRARG\FRARG2\FRCLN\FRUPRW
	JUMPGE E,NRETM1		;RETURN -1 IF DON'T FIND THE OBJECT.
	SUB E,J
	HRRZ A,E
	JRST POPJ1		;ELSE RETURN INDEX FIRST FIND IT AT.

SUBTTL MISCELANEOUS ^R MODE COMMANDS

RRCTLL:	SKIP		;^L COMMAND.
	SKIPN RGETTY	;^L WITH ARG PRINTS SPEC'D # OF LINES (FOR PRINTING TTY'S).
	 JRST RRDISL
	CALL CTLL
RRMAC1:	SETOM RRMNVP	;CAUSE WINDOW TO BE TESTED,
	SETZM RRMSNG	;AND THE WHOLE BUFFER TO BE REDISPLAYED.
	JRST RRBTCR	;IN CASE THAT DOESN'T HAPPEN FOR A WHILE
			;MAKE SURE WE HAVE A REASONABLE RRHPOS.

RRDISL:	SETZM RUBENC	;HERE FOR <N>^L;  DISPLAY <N> LINES OF BUFFER.
	CALL CRR
	CALL CRR
	CALL WINSET	;SET WINDOW SIZE TO <N> LINES.
	CALL VBDRR	;DO THE DISPLAY.
	CALL RRDIS3	;THEN DO A 0T SO USER SEES WHERE CURSOR IS.
	MOVE C,NLINES	;RESTORE NORMAL WINDOW SIZE.
	JRST WINSET

RRMAC3:	ADDB A,RREPT	;RELOCATE OLD PT FOR BUFFER MOTION.
	CAML A,BEGV	;OLD CURSOR-LOCATION NO LONGER INSIDE BUFFER =>
	 CAMLE A,ZV	;CAN'T MOVE FROM THERE, MUST REDISPLAY SLOW WAY.
	  JRST RRMAC1
	MOVE E,PT
	SKIPN RGETTY	;ELSE, USE EITHER RRMOV OR RRQMOV TO DETERMINE NEW VPOS/HPOS,
	 JRST RRMOV1	;GUESSING WHICH ONE WILL BE FASTER;  BUT ON TTY'S USE ONLY RRMOV.
	MOVE TT,A
	SUB TT,PT
	MOVMS TT
	CAIL TT,30.
	 JRST RRQMOV
RRMOV1:	MOVEM A,PT	;THAT IS WHERE RRHPOS AND RRVPOS ARE RIGHT FOR.
	JRST RRMOV

RRERST:	SAVE Q
RRERS1:	CAML CH,DISPRR	;POPPING OUT OF A MACXQ: POPPING OUT OF A ^R-INVOCATION?
	 JRST POPQJ
	SOS Q,DISPRR	;IF SO, RESTORE DISPRR'S VALUE OUTSIDE THAT INVOCATION.
	POP Q,DISPRR
	SKIPE DISPRR	;IF THIS ^R WAS THE OUTERMOST,
	 JRST RRERS1
	SAVE TT
	SAVE TT1
	SAVE CH
	CALL SETTTM	;RESTORE NORMAL TTYSET.
	REST CH
	REST TT1
	REST TT
	JRST POPQJ

;RTNS TO HANDLE THE MARK.

;SET THE MARK AT PT.
RRMARK:	SKIP
	SKIPE RR4TCT	;^U^T EXCHANGES MARK WITH PT.
	 JRST RREXCH
RRMRK1:	.I RRMKPT=PT-BEG
	POPJ P,

;EXCHANGE THE MARK AND PT.
RREXCH:	SKIP
	SKIPGE E,RRMKPT
	 JRST RRERR	;NO MARK => CAN'T EXCHANGE.
	ADD E,BEG	;TURN INTO CHAR ADDR.
	SAVE PT		;REMEMBER NEW VALUE OF MARK.
	CALL RRMOV	;MOVE PT TO OLD MARK.
	REST TT		;SET MARK TO OLD PT.
	SUB TT,BEG
	MOVEM TT,RRMKPT
	JRST RRTTY		;ON PRINTING TERMINAL, GO SHOW CURSOR MOTION.

;DO FX..K ON EVERYTHING FROM PT TO THE MARK.
RRFX:	SKIP
	SKIPGE A,RRMKPT
	 JRST RRERR
	ADD A,BEG
	CAMN A,PT	;DELETING NO CHARS =>
	 JRST RRFXXT	;DON'T CLOBBER QREG ..K.
	CAMG A,PT
	 CALL RREXCH	;MAKE SURE PT IS BEFORE MARK.
	MOVE E,PT
	MOVE A,RRMKPT
	ADD A,BEG
	MOVE C,A
	SUBM E,A
	CALL RRFXMX	;SET RRMAXP
	CALL RRCRDI	;WORRY ABOUT BEFORE-EFFECTS.
	 CALL [	CALL RRDLB2	;SET RRMNVP, RRMNHP FROM T,BP.
		MOVE CH,QRB..
		ADDI CH,.QRRBF
		CALL FXCMD2	;DO THE FX. D _ AMOUNT BEG CHANGED.
		MOVE A,D
		JRST RRFXRL]	;RELOCATE VARIOUS PTRS THAT MUCH
RRFXXT:	SETOM RRMKPT	;ELIMINATE THE MARK.
	POPJ P,

;RELOCATE RR MODE'S VARIOUS PTR THAT ARE KEPT AS CHAR ADDRS,
;BY THE AMOUNT IN A. (IN CASE THE BUFFER WAS MOVED)
;CLOBBERS TT
RRFXRL:	MOVE TT,RRMAXP	;NOTE THAT IF RRMAXP IS INFINITY IT SHOULDN'T BE CHANGED.
	AOS TT
	CAILE TT,1	;ALSO IF IT IS ZERO.
	 ADDM A,RRMAXP
	ADDM A,RROLZV
	MOVE TT,TOPLIN
RRFXR1:	CAMLE TT,BOTLIN
	 .VALUE
	JUMPE A,[
		MOVE TT,BOTLIN
		RET]
RRFXR2:	CAML TT,BOTLIN
	 RET
	ADDM A,LINBEG(TT)
	AOJA TT,RRFXR2

;KILL <ARG> LINES STARTING AT PT, AND PUT IN QREG ..K.
RRKILL:	SKIP
	CALL RRMRK1
	CALL RRNEX1
	JRST RRFX

;^S -- READ CHAR, AND SEARCH FOR THAT CHAR.
RRSRCH:	SKIP
	SAVE C
	CALL RRECO1	;MAYBE PROMPT WITH A ^S.
	REST NUM
	MOVEI A,[ASCIZ/FIU..0 :S..0 /]
	JRST RRMAC6

RRCTLB:	SKIP		;^B MOVES BACKWARD - IT IS -^F.
	MOVNS C
RRCTLF:	SKIP		;^F MOVES FORWARD, BUT ON PRINTING TTY IT ECHOES.
	AOS (P)
	JUMPL C,RRCB1		;WORK FOR NEGATIVE ARGS.
	JSP E,RRREP1
	MOVE IN,PT
	CALL RREOLT
	 CALL RRFORW
	JRST RRFORW

RRCB1:	MOVNS C
	JSP E,RRREP1
	CALL RRBACK		;MOVE BACK AT LEAST ONE CHARACTER.
	SOS IN
	CAMLE IN,BEGV		;IF IT IS A LF, AND THE PRECEDING CHAR IS A CR,
	 CAIE CH,^J
	  RET
	CALL GETCHR
	CAIE CH,^M
	 RET
	JRST RRBACK		;MOVE BACK OVER THAT AS WELL.

;JSP E,RRTYPP  SKIPS UNLESS WE ARE SCANNING (SHOULD PRINT SCANNED CHARACTERS).
RRTYPP:	SKIPN RGETTY
	 SKIPN RRSCAN
	  JRST 1(E)
	JRST (E)

;^P -- WITH ARGUMENT <N>, DOES -<N>@L.
RRPREV:	SKIP		;CALCULATE <N>,
	MOVNS C
	JRST RRNEX2	;<N> IS -<N>.

;^A -- MOVE TO BEGINNING OF LINE.
;WITH ARGUMENT <N>, DOES <N>-1@L.
RRBEG:	SKIP
	SOJA C,RREND2

;^E -- MOVE TO END OF LINE (:@L).  WITH ARGUMENT <N>, DO :<N>@L.
RREND:	SKIP
RREND1:	TRO FF,FRCLN
RREND2:	AOS (P)
	JRST RRNEX1

;^N -- MOVE TO BEGINNING OF NEXT LINE. (@L)
;WITH ARGUMENT <N>, DOES <N>@L.
RRNEXT:	SKIP
RRNEX2:	AOS (P)
	SAVE [RRCMIN]	;DO COMMENT-MODE STUFF AT START AND FINISH OF MOTION.
	CALL RRCMRU
RRNEX1:	MOVE IN,PT
	TRO FF,FRUPRW
	CALL GETAG4	;COMPUTE WHERE WE'RE GOING TO.
	 JFCL
	ADD E,C		;THE WAY THE L COMMAND DOES.
	SUB E,PT
	JRST RRMOV	;THEN GO THERE.

;CALL HERE WHEN LEAVING A LINE.
;IN COMMENT MODE, TAB-SEMI'S ARE REMOVED BY THIS RTN.
RRCMRU:	SKIPGE RRCMMT
	 POPJ P,	;DO NOTHING IF NOT COMMENT MODE.
RRCMR1:	SAVE C
	MOVEI C,1
	CALL RREND1
	 JFCL
	REST C
	MOVE IN,PT
	CAMG IN,BEGV
	 POPJ P,	;DO NOTHING AT BEGINNING OF BUFFER.
	SOS IN
	CALL GETCHR	;IF CHAR BEFORE PT IS A SEMI,
	CAIE CH,";
	 POPJ P,
RRCMR0:	CALL RRDLB	;DELETE IT, AND ANY TABS BEFORE IT.
	MOVE IN,PT
	CAMG IN,BEGV
	 POPJ P,
	SOS IN
	CALL GETCHR
	CAIE CH,^I
	CAIN CH,40
	 JRST RRCMR0
	POPJ P,

RRCMS1:	SETZ C,
	CALL RRNEX1

;CALL HERE WHEN ENTER A LINE.
;IN COMMENT MODE, TAB-SEMI WILL BE INSERTED.
RRCMIN:	SKIPGE RRCMMT
	 RET		;NOT COMMENT MODE.
RRCMI0:	MOVE IN,PT	;MOVE UP TO EXISTING COMMENT
	CALL RREOLT	;OR END OF LINE.
	 JRST RRCMI1	;REACHED END, INSERT TAB-SEMI.
	CALL GETCHR
	CAIN CH,";
	 JRST RRFORW	;REACHED SEMI, STOP AFTER IT.
	CALL RRFORW
	JRST RRCMI0	;ELSE KEEP LOOKING.

RRCMI1:	MOVEI CH,^I	;INSERT TABS TILL REACH COMMENT COLUMN
	CALL RRINS
	MOVE A,RRHPOS
	CAMGE A,RRCCOL	;REACHED THE COMMENT COLUMN?
	 JRST RRCMI1	;NO, MORE TABS TO INSERT.
	MOVEI CH,";	;YES, INSERT THE SEMI.
	JRST RRINS

;^C -- COMPLEMENT COMMENT MODE.
RRCMSW:	SKIP		;IF NUMERIC ARG, IT IS SETTING OF COMMENT COLUMN.
	CAIE C,1
	 MOVEM C,RRCCOL
	AOSE A,RRCMMT	;IF WAS -1, MAKE IT 0.
	 SETOB A,RRCMMT	;WAS >=0, MAKE IT -1.
	CALL RRECSP	;THEN INDICATE WHICH MODE WE'RE IN.
	MOVE CH,(A)1+[ "T ? "C ]
	CALL FSECO1
	XCT (A)1+[CALL RRCMR1	;LEAVING COMMENT MODE, REMOVE SEMI.
		CALL RRCMS1]	;WHEN ENTER COMMENT MD, INSERT SEMI.
;TYPE A SPACE IN THE ECHO REGION, MAKING SURE CURSOR WILL
;BE REPOSITIONED IN THE DISPLAY REGION. PRESERVE ALL ACS.
RRECSP:	SAVE CH
	MOVEI CH,40
	CALL FSECO1
	JRST POPCHJ

;^R -- SET COMMENT COLUMN FROM CURRENT HPOS.
RRCMCS:	SKIP A,RRHPOS
	SKIPGE RRCMMT	;NO EFFECT UNLESS IN COMMENT MODE.
	 POPJ P,
	MOVEM A,RRCCOL
	POPJ P,

;TABLES USED BY RRCHRG. THE ENTRY FOR EACH
;CHARACTER IS AN INDEX INTO RRFORT OR RRBACT.

RRCHBP:	REPEAT 6,<360600-<6*.RPCNT>_12.>,,RRCHTB(A)

;CODES IN RRCHTB ARE:
 ;0 - 1-POSITION CHARACTER.
 ;1 - ORDINARY CTL CHAR - USUALLY 2-POSITION, BUT 1-POSITION IN SAIL MODE.
 ;2 - BACKSPACE.
 ;3 - CR
 ;4 - LF
 ;5 - TAB.
 ;6 - SPECIAL CTL CHARACTER - 2-POSITION EVEN IN SAIL MODE.

RRCHTB:	.BYTE 6
	1		;^@
	1		;^A
	1		;^B
	1		;^C
	1		;^D
	1		;^E
	1		;^F
	1		;^G
	2		;^H
	5		;^I
	4		;^J
	1		;^K
	1		;^L
	3		;^M
	1		;^N
	1		;^O
	1		;^P
	1		;^Q
	1		;^R
	1		;^S
	1		;^T
	1		;^U
	1		;^V
	1		;^W
	1		;^X
	1		;^Y
	1		;^Z
	0		;ALTMODE, 1 POSITION.
	1		;[ ;^]
	1		;^\
	1		;^^
	1		;^_
	.BYTE

IFN CTRLT,[

SUBTTL OBSOLETE ^T COMMAND

EDIT:	CALL GAPSLP
	SKIPE ECHOFL
	 CALL NOECHO
	TRZ FF,FRARG+FRARG2+FRUPRW	;FRARG ON = INSERT MODE, OFF = OVERWRITE MODE
				;FRARG2 ON = IN IS POINTING TO CR
				;FRUPRW ON = BACKWARDS RUB MODE
	SETZM COMCNT
	MOVE B,CBUFLO
	SKIPA IN,PT
ED0.0:	POP P,A		;PURGE EXTRA PUSHJ P,
ED0:	PUSHJ P,CRR
	TRZ FF,FRUPRW	;TURN OFF "\" FLAG
ED1:	PUSHJ P,DISFLS
	PUSHJ P,TYI
	CALL TYINRM
	MOVE A,CH
	MOVEI CH,"\
	CAIL A,40
	JRST EDLIS
	SKIPL C,EDDPTB(A)	;IS IT A RUBBACK COMMAND
	JRST ED11		;NO
	TRON FF,FRUPRW	;TURN ON "\" FLAG
ED12:	PUSHJ P,TYOA	;AND IF WAS OFF, TYPE "\"
ED13:	MOVE CH,A
	PUSHJ P,@C
	PUSHJ P,TYO
	JRST ED1

ED11:	TRZE FF,FRUPRW	;TURN OFF "\" FLAG
	JRST ED12	;IF IT WAS ON, PRINT "\"
	JRST ED13

BELL:	CALL TYPBEL
	JRST CPOPJ1

EDLIS:	CAIE A,177
	JRST EDLIS1
	TRON FF,FRUPRW
	PUSHJ P,TYOA
	JRST .+3
EDLIS1:	TRZE FF,FRUPRW
	PUSHJ P,TYOA
	MOVE CH,A
	PUSHJ P,CKCH
	JRST ED0
	JRST ED1
	PUSHJ P,EDOV
	JUMPL CH,ED1
	PUSHJ P,TYO
	JRST ED1

ED%:	MOVEI CH,"#
	PUSHJ P,TYO
	PUSH P,IN
	PUSH P,FF
ED%1:	PUSHJ P,CGETIN
	JUMPL CH,ED%2	;END OF LINE OR BUFFER
	PUSHJ P,TYO
	JRST ED%1
ED%2:	POP P,FF
	POP P,IN
	PUSHJ P,CRR
	MOVE A,COMCNT
	JUMPLE A,CPOPJ1
	MOVE B,CBUFLO
	ILDB CH,B
	PUSHJ P,TYO
	SOJG A,.-2
	JRST CPOPJ1
EDOV:	MOVE A,CH
	TRNN FF,FRARG	;IN INSERT MODE
	PUSHJ P,CGETIN	;NO
	SKIPA CH,A
EDCPY:	PUSHJ P,CGETIN
	JUMPL CH,CPOPJ
EDCPY1:	IDPB CH,B
	AOS COMCNT
	POPJ P,

CGETIN:	MOVNI CH,1
	TRNE FF,FRARG2
	POPJ P,
	CAML IN,ZV	;AT END OF BUFFER
	JRST CGETI1
	PUSHJ P,GETCHR
	CAIN CH,15
CGETI1:	TROA FF,FRARG2
	AOJA IN,CPOPJ
	MOVNI CH,1
	POPJ P,

EDCR:	PUSHJ P,CRR
EDCR2:	TRNE FF,FRARG2
	JRST EDCR1
	PUSHJ P,CGETIN
	JRST EDCR2
EDCR1:	MOVE C,IN	;GET ADDR AFTER END OF OLD LINE,
	MOVE E,PT	;GET ADDR OF START OF IT,
	CALL DELET1	;TURN THAT INTO GAP.
	MOVE C,COMCNT	;NOW INSERT SPACE FOR NEW LINE,
	CALL SLPGET	;BP GETS BP TO IDPB INTO SPACE.
	MOVE A,COMCNT
	JUMPE A,EDCR3
	MOVE B,CBUFLO
	ILDB CH,B
	IDPB CH,BP
	SOJG A,.-2
EDCR3:	TRZ FF,FRARG+FRUPRW+FRARG2
	SETZM COMCNT
	SETOM UNRCHC
	PUSHJ P,SETTTM
	JRST GO

RTYI:	PUSHJ P,TYI
	CALL TYINRM
	CAIE CH,177
	POPJ P,
	MOVEI CH,"\
	TRON FF,FRUPRW
	PUSHJ P,TYOA
	MOVE CH,A
	SUB P,[1,,1]
	POPJ P,

EDD:	PUSHJ P,CGETIN	;DELETE NEXT CHAR
	JUMPL CH,BELL	;BELL IF NONE
	MOVEI CH,"%
	POPJ P,

EDP:	MOVEI CH,"<	;COMPLEMENT STATE OF INSERT/OVERWRITE MODE
	TRCE FF,FRARG
	MOVEI CH,">
	POPJ P,

EDS:	PUSHJ P,RTYI	;COPY THRU "T"
	MOVE A,CH
	PUSH P,IN
	PUSH P,FF
EDS1:	PUSHJ P,CGETIN
	TRNE FF,FRARG2
	JRST EDS2	;AT EOL AND NOT FOUND
	CAME CH,A
	JRST EDS1	;KEEP LOOKING
	POP P,FF
	POP P,IN
	JRST EDN1
EDN:	PUSHJ P,EDCPY	;COPY THRU 1ST SPACE AFTER 1ST NON-SPACE OR TO EOL
	JUMPL CH,CPOPJ1
	PUSHJ P,TYO
	CAIN CH," 
	JRST EDN
	MOVEI A," 
EDN1:	PUSHJ P,EDCPY
	JUMPL CH,CPOPJ1
	PUSHJ P,TYO
	CAME CH,A
	JRST EDN1
	JRST CPOPJ1

EDS2:	POP P,FF
	POP P,IN
	JRST BELL

EDQ:	PUSHJ P,RTYI	;QUOTE NEXT CHAR
	JRST EDOV

EDT:	PUSHJ P,RTYI	;DELETE THRU "T"
	MOVE A,CH
	PUSH P,IN
	PUSH P,FF
EDT1:	PUSHJ P,CGETIN
	TRNE FF,FRARG2
	JRST EDS2	;AT EOL AND NOT FOUND
	CAME CH,A
	JRST EDT1
	POP P,FF
	POP P,IN
	JRST EDO1

EDO:	PUSHJ P,CGETIN	;DELETE THRU NEXT SPACE AFTER 1ST NON-SPACE OR TO EOL
	JUMPL CH,CPOPJ1
	MOVE A,CH
	MOVEI CH,"%
	PUSHJ P,TYO
	CAIN A," 
	JRST EDO
	MOVEI A," 
EDO1:	PUSHJ P,CGETIN
	JUMPL CH,CPOPJ1
	CAMN CH,A
	SETOM A
	MOVEI CH,"%
	PUSHJ P,TYO
	JUMPL A,CPOPJ1
	JRST EDO1

EDR:	TROA FF,FRARG+FRUPRW	;FRARG ON = ECHO
EDL:	TRZ FF,FRARG+FRUPRW	;FRUPRW ON = DONT END EDIT
EDL1:	TRNE FF,FRARG2
	JRST EDL2
	PUSHJ P,EDCPY
	JUMPL CH,EDL2
	TRNE FF,FRARG
	PUSHJ P,TYO
	JRST EDL1
EDL2:	TRZ FF,FRARG
	TRZE FF,FRUPRW
	JRST CPOPJ1	;DON'T END EDIT
	PUSHJ P,CRR	;CR-LF THEN END EDIT
	JRST EDCR1

EDW:	LDB CH,B	;RUBBACK TO 1ST NON-SPACE, THEN BACK TO 1ST SPACE
	CAIE CH," 
	JRST EDW1
	MOVEI CH,177
	PUSHJ P,CKCH
	JRST ED0.0
	JRST EDW
EDW1:	LDB CH,B
	CAIN CH," 
	JRST CPOPJ1	;FOUND SPACE, QUIT
	MOVEI CH,177	;TO TELL CKCH TO RUBBACK
	PUSHJ P,CKCH
	JRST ED0.0		;NOTHING TO RUB
	JRST EDW1
	.VALUE	;SHOULD NEVER GET HERE

EDALT:	TRO FF,FRARG	;COPY REST W/ ECHO AND END EDIT
	TRZ FF,FRUPRW
	JRST EDL1

] ;IFN CTRLT

SUBTTL TECO COMMAND DISPATCH / ARGUMENT ARITHMETIC

CD:	SETZM NUM	;FLUSH ANY ARGUMENT, OR : OR @.
	SETZM SARG
	TRZA FF,FRARG+FRARG2+FROP+FRUPRW+FRCLN+FRSYL
CD2B:	 TROA FF,FROP+FRARG ;COME HERE FROM ARITH OPS, NEED 2ND ARG.
CD2A:	MOVSI A,(ADD C,);SET UP DLIM FOR THE DEFAULT
			 ;CONDITION OF ADDING THE OLD VALUE
			  ;WITH ANY NEW NUMBER ENTERED
	HLLM A,DLIM	;PUT THE APPROPRIATE OPERATOR AWAY
	CLEARM SYL	;CLEAR THE NEW NUMBER ENTERED
	CLEARM OSYL	;ALSO CLEAR ITS OCTAL INTERPRETATION
CD5:	MOVE A,QRWRT	;IF IMPURE STRING SPACE HAS INCREASED BY
	CAML A,QRGCMX	;GCOFTN CHARS SINCE PREVIOUS GC,
	 PUSHJ P,GC	;GC THE IMPURE STRINGS.
CD5A:	SKIPGE STOPF	;IF THE USER HAS ^G'ED, TRY TO QUIT,
	 CALL QUIT0	;TRY TO QUIT (CHECK NOQUIT).
	CALL RCH	;GET THE NEXT COMMAND CHARACTER
CDRCH:	TRNE CH,100	;CONVERT LOWER CASE TO UPPER.
	 ANDCMI CH,40
	SETZB B,SQUOTP
	TRZ FF,FRNOT	;RESET MORE FLAGS
	XCT DTB(CH)	;EXECUTE THE ENTRY FROM THE DISPATCH TABLE
CD5B:	TLZ FF,FLDIRDPY	;RESET THE "DISPLAY THE FILE DIRECTORY BIT", THIS INSURES
			;THAT AN E COMMAND WILL ONLY DISPLAY THEBUFFER IF IT IS THE LAST COMMAND
	MOVE C,NUM	;GET THE OLD VALUE
	TRZN FF,FRSYL
	 JRST CD5C
	XCT DLIM	;THEN PERFORM THE SAVED OPERATION
	MOVEM C,NUM	;AND MAKE IT THE NEW OLD VALUE
CD5C:	MOVE E,SARG	;GET THE SECOND ARGUMENT TO THE COMMAND (IF ANY)
	JUMPGE B,(B)	;IF B POSITIVE, THEN JUMP TO IT.
	PUSHJ P,(B)	;IF B NEGATIVE, PUSHJ
CDRET:	 JRST CD	;NON-SKIP RETURNING COMMANDS DON'T RETURN VALUE
VALREC:	TROE FF,FRARG	;IF HAVE ARG FROM BEFORE, NOT GOBBLED,
	 JRST VALRET	;DO ARITH. WITH IT & THIS CMD'S VALUE.
	MOVEM A,NUM	;IF NO ARG OR THIS CMD USED IT, ITS
	TRZ FF,FROP	;VALUE IS ALL THE ARG WE HAVE.
	JRST CD2A

CDNUM:	JFCL 10,.+1	;CLEAR OVERFLOW FLAG.
	MOVE A,OSYL	;ASSEMBLE THIS DIGIT INTO A NUMBER
	IMUL A,I.BASE	;(USUALLY OCTAL)
	JFCL 10,[TLC A,400000	;ALLOW OVERFLOW INTO SIGN BIT.
		 JRST .+1]
	ADDI A,-60(CH)
	MOVEM A,OSYL
	JFCL 10,.+1
	MOVE A,SYL
	IMUL A,IBASE	;AND IN DECIMAL (USUALLY)
	JFCL 10,[TLC A,400000	;ALLOW OVERFLOW INTO SIGN BIT.
		 JRST .+1]
	ADDI A,-60(CH)
VALRET:	MOVEM A,SYL	;SAVE IT AS A VALUE
	TRZ FF,FROP	;DON'T HAVE ARITH OP WAITING FOR 2ND ARG
CD7:	TRO FF,FRARG+FRSYL ;DECLARE THAT THERE IS AN ARGUMENT AND A CURRENT VALUE
	JRST CD5	;AND RETURN


;ARGDFL MACRO CALLS HERE IF FROP WAS SET, AFTER CLEARING IT.
;ARGDFL IS USED TO DEFAULT "-" TO "-1", ETC.
ARGDF0:	SETZM SYL	;PRETEND A "1" HAD PRECEDED THIS CMD,
	AOS SYL		;AFTER THE OPERATOR THAT NEEDS 2ND ARG,
	XCT DLIM	;DO THE ARITHMETIC,
	POPJ P,

PNT:	MOVE A,OSYL
	TRNE FF,FRSYL
	 JRST VALRET
	MOVE A,PT
	SUB A,BEG
	JRST VALRET

CNTRAT:	ARGDFL Z,	;^@ - TAKES 1 ARG, RETURNS .,.+ARG OR .+ARG,.  .
	TRZE FF,FRARG2
	 JRST [	TRZE FF,FRCLN	;M,N:^@ RETURNS N,M.
		 JRST [	MOVE B,C
			MOVE A,E
			JRST 2VALS]
		MOVE A,C	;M,N^@ RETURNS N-M.
		SUB A,E
		JRST POPJ1]
	MOVE B,PT
	ADD C,PT
	MOVE A,C
	CAMG A,B	;MAKE SURE ARGS ARE IN RIGHT ORDER.
	 EXCH A,B
	JRST HOLE0

HOLE:	MOVE B,BEGV
	MOVE A,ZV
HOLE0:	SUB B,BEG	;RETURN 2 CHAR ADDRS AS VALUES.
	SUB A,BEG	;CHANGE THEM TO CHARACTER NUMBERS (REL TO BEG, THAT IS)
2VALS:	MOVEM B,SARG	;RETURN 2 VALUES IN B, A.
	TRO FF,FRARG2
	JRST POPJ1

END1:	SKIPA A,ZV
BCMD:	MOVE A,BEGV
FSROC1:	SUB A,BEG
	JRST POPJ1

;F^X COMMAND - WITHIN MACRO, RETURN THE MACRO ARGS
;(AS MANY AS IT WAS CALLED WITH).
FCTLX:	MOVE A,MARG2	;GET THE VALUES THE MACRO'S ARGS HAVE IF THEY EXIST.
	MOVE B,MARG1
	MOVE C,MACBTS	;GET THE BITS THAT SAY WHETHER THEY DO.
;ENTER HERE DO F^X ON SOME OLD MACRO FRAME, WITH ITS DATA IN A, B, C.
FCTLX2:	TRZ FF,FRARG+FRARG2+FROP+FRSYL
	SETZM NUM	;FLUSH ALL TRACES OF ARGUMENTS.
	SUB P,[1,,1]	;THROW AWAY RET ADDR (VALREC-1); WE WILL JUMP INTO COMMAND LOOP.
	TLNN C,MFBA1	;IF THERE'S A 1ST ARG,
	 JRST FCTLX1
	MOVEM B,SARG	;PUT IT AWAY
	TRO FF,FRARG2	;AND SAY THERE IS ONE.
FCTLX1:	TLNE C,MFBA2
	 JRST VALREC	;IF THERE'S A 2ND ARG, SET IT UP AS CURRENT VALUE.
	JRST CD2A	;IF THERE ISN'T, SET UP NO CURRENT VALUE BUT DON'T CLEAR FRARG2.

;F^Y COMMAND - TAKES 0,1 OR 2 ARGS, AND RETURNS 0 IF NO ARGS, 1 IF ONLY A 2ND ARG,
;2 IF ONLY A 1ST ARG (EG 1,F), 3 IF TWO ARGS (EG 1,2F).
;IN ADDITION, 4 IS ADDED TO THE RESULT IF THE COLON FLAG IS SET,
;AND 8 IS ADDED TO THE RESULT IF THE ATSIGN FLAG IS SET.
FCTLY:	LDB A,[.BP FRARG+FRARG2+FRCLN+FRUPRW,FF]
	TRZ FF,FRARG+FRARG2+FRUPRW+FRCLN
	JRST POPJ1

;^M - FLUSH CURRENT VALUE
CTLM:	MOVE A,CPTR	;^M.  IF NEXT CHAR IS ^J, READ IT NOW.
	ILDB CH,A
	CAIN CH,^J
	 SKIPN COMCNT	;THIS IS SO THAT, IF FS STEP CALLS A MACRO,
	  CAIA		;THE POINTER IN AN FS BACKTRACE$ IS AT A NICE-LOOKING PLACE.
	   CALL RCH
CTLM2:	SKIPN A,STEPFL
	 RET
	MOVE B,STEPDE	;DON'T STEP IF DEEPER IN MACRO CALLS THAN USER-SUPPLIED LIMIT.
	CAMGE B,MACDEP
	 JUMPGE B,CPOPJ
	SETZ C,		;(DON'T GIVE THE STEP MACRO A NONZERO ARG)
	CALL QLGET0
	 CAIA		;IF FS STEP IS A NONZERO NUMBER, DO OUR BUILT-IN STEPPING.
	  JRST MACXCP	;IF IT'S A STRING, MACRO IT AND RETURN ITS VALUE.
	MOVE A,QRB..
	SKIPE .QVWFL(A)
	 JRST CTLM1
	TRZ FF,FRARG+FRARG2+FRCLN
	TRO FF,FRUPRW	;IN LINE-STEPPING MODE (SEE FS STEP$),
	CALL VIEW1B	;DO @VW, AND DECODE VALUE OF CHARACTER READ
CTLM1:	MOVE A,QRB..
	SETZM .QVWFL(A)	;AND ALLOW BUFFER DISPLAY AFTER COMMAND.
	TRZ FF,FRUPRW+FRCLN
	CALL FTYI
	 JFCL
	CAIN A,^F
	 JRST [	SETZM NOQUIT	;^F QUITS EVEN WHEN QUITTING NOT ALLOWED.
		SETOM STOPF
		RET]
	CAIN A,^R
	 JRST [	CALL RRENTR	; ENTER ^R MODE
		JRST CTLM1]	;THEN DECODE ANOTHER CHARACTER.
	CAIN A,^P
	 SETZM STEPFL	;OR TURN OFF STEPPING
	RET

CAND:	MOVSI A,(AND C,)
	JRST CD2B
COR:	MOVSI A,(IOR C,)
	JRST CD2B
BAKARR:	HRROI B,SERCHA	;_ IS EITHER SEARCH-AND-YANK OR SAME AS -.
	SKIPLE NLAROW	;FS _DISABLE POSITIVE => "_" IS ERROR.
	 TYPRE [DCD]	;"DISABLED COMMAND"
	SKIPN NLAROW	;FS _DISABLE IS NEGATIVE => "_" IS TREATED AS "-".
	 JRST CD5B	;FS _DISABLE IS 0 => "_" IS SEARCH-AND-YANK.
MINUS:	MOVSI A,(SUB C,)
	JRST CD2B
TIMES:	MOVSI A,(IMUL C,)
	JRST CD2B
SLASH:	MOVSI A,(IDIV C,)
	JRST CD2B
CXOR:	MOVSI A,(XOR C,)
	JRST CD2B
PLUS:	MOVSI A,(ADD C,)
	JRST CD2B

SPACE:	TRNE FF,FROP	;SPACE BETWEEN NUMBERS IS LIKE PLUS,
	 JRST CD5A	;BUT SPACE NEXT TO AN ARITHMETIC OPERATOR IS IGNORED.
	JRST CD2A

COMMA:	TRZN FF,FRARG
	 JRST COMMA1
	MOVEM C,SARG
	TROE FF,FRARG2
	 TYPRE [WNA]
COMMA1:	SETZM NUM	;NO ACCUMULATED 1ST ARG ANYMORE,
	JRST CD2A	;INIT. FOR NEW ARG, DON'T CLEAR FRCLN.

ASLSL:	TROA FF,FRUPRW	;TURN ON THE UPARROW FLAG
ACOLON:	TRO FF,FRCLN	;TURN ON THE COLON FLAG
	JRST CD5A	;AND GO BACK FOR MORE

;HANDLE (, ), F(, F)

FOPEN:	SUB P,[1,,1]	;F( - PUSH VALUES BUT DON'T FLUSH THEM.
	SKIPA T,[CD5A]
OPEN:	 MOVEI T,CD	;( - PUSH AND FLUSH VALUES.
OPEN1:	TRZ FF,FRQPRN	;SAY THIS ( ISN'T A QREG NAME.
OPEN2:	SAVE NUM
	HLLZ CH,DLIM
	HRR CH,FF	;REMEMBER CURRENT FRCLN, FRUPRW, FRARG2.
	TRNE FF,FRARG2
	 SAVE SARG	;SAVE 2ND ARG IF THEE IS ONE.
	SAVE CH
	SAVE LEV
	MOVEM P,LEV
	JRST (T)

FCLOSE:	SUB P,[1,,1]	;F) - POP AND THROW AWAY VALUES. CALLED WITH PUSHJ.
	SKIPA T,[CD5A]
CLOSE:	 HRROI T,CD5A	;) - POP AND RETURN VALUES. RH(T) IS RET. ADDR., SIGN=0 => THROW AWAY.
CLOSE2:	CAME P,LEV
	 TYPRE [UMC]	;NOT ALLOWED IF TOP OF STACK DOESN'T HAVE SOME PUSHED VALS.
	SKIPN Q,ITRPTR
	 JRST CLOSE1
	HLRZ Q,-1(Q)
	CAIN Q,(P)
	 TYPRE [UMC]	;DON'T ALLOW SEQUENCE "(<)" - WOULD SCREW UP ">".
CLOSE1:	REST LEV
	REST CH
	ANDCMI CH,#FRARG2#FRCLN#FRUPRW#FROP#FRARG#FRQPRN
	TRNE CH,FRARG2
	 REST B
	REST A
	TRNN CH,FRQPRN
	 JUMPGE T,(T)	;FOR F), DO NOTHING WITH THE POPPED STUFF.
	EXCH A,NUM	;ELSE RESTORE SAVED ARG VALUES AND OPERATOR.
	HLLM CH,DLIM
	TRNE CH,FRARG2
	 MOVEM B,SARG
	TRZE CH,FRQPRN	;FOR Q( - ), WE HANDLE THE FLAGS A SPECIAL WAY.
	 JRST QREGXR
	TRNE FF,FRARG	;NORMALLY, WE SET UP THE VALUE WITHIN THE PARENS AS A SYLLABLE
	 TRZ CH,FROP	;TO DO ARITHMETIC ON. SO THE PREVIOUS OPERATOR GETS A RIGHT OPERAND.
	TRNE FF,FRARG
	 IORI FF,FRSYL
	MOVEM A,SYL
	IORI FF,(CH)
	JRST (T)

;SET P FROM CH, AND FORGET ABOUT ALL ('S
;THAT WERE IN THE PART OF THE STACK THAT HAS BEEN FLUSHED.
;ALSO PERFORM APPROPRIATE ACTIONS IN CASE POPPING PAST A ^R OR A SORT.
;THEN EXIT WITH POPJ P, (NOTE P HAS CHANGED, SO CALL WITH PUSHJ CH,
;BUT DON'T DARE DO THAT IF P=CH, SINCETHAT WOULD LEAVE THE RETURN
;POINTER ON STACK ABOVE P, CAUSING TIMING ERROR WITH INT. LEVEL).
SETP:	MOVEM P,SETPP
	CAMLE CH,P
	 .VALUE		;MOVING PDL POINTER UPWARDS??
	SKIPE DISPRR	;IF POPPING OUT OF A ^R,
	 CALL RRERST	;UNBIND SOME STUFF.
	CAMGE CH,PSSAVP
	 SETZM PSSAVP	;DETECT ERRING OUT THROUGH A ^P, AND RELEASE SORT TABLES.
SETP1:	SKIPE LEV	;IF THERE IS AN (,
	 CAML CH,LEV	;AND IT'S NO LONGER BENEATH P,
	  JRST [ MOVE P,CH ? RET]
	HRRZ P,LEV
	CAIL P,PDL
	 CAIL P,PDL+LPDL
	  .VALUE
	MOVE P,LEV	;FLUSH THE INNERMOST "("
	REST LEV
	JRST SETP1	;AND EXAMINE THE NEXT ONE.

SUBTTL VIRTUAL CHARACTER ADDRESS SUBROUTINES

CHKC:	CAML E,BEGV		;BARF IF E NOT IN BUFFER.
	 CAMLE E,ZV
	  TYPRE [NIB]
	RET

CHK:	CAMG C,ZV
	 CAMGE C,BEGV
	  TYPRE [NIB]
	RET

CHK1:	CAMG E,BEGV
	 MOVE E,BEGV
	CAML C,ZV
	 MOVE C,ZV
	CAMLE E,C
	 TYPRE [2%1]	;2<1
	RET

CHK1A:	CAMG E,BEG
	 MOVE E,BEG
	CAML C,Z
	 MOVE C,Z
	CAMLE E,C
	 TYPRE [2%1]	;2<1
	RET

GETIBI:	SKIPA BP,IN
GETIB.:	 MOVE BP,PT
GETIBV:	CAML BP,GPT
	 ADD BP,EXTRAC
GETIBP:	SOSA TT,BP
GETBP:	 MOVE TT,BP
	IDIVI TT,5
	MOVE BP,BTAB(TT1)
	HRRI BP,(TT)
	TLZ BP,17
	POPJ P,

;CONVERT THE BYTE POINTER IN BP TO A CHARACTER ADDRESS
GETCA:	LDB TT,[360600,,BP]	;GET POSITION FIELD IN TT
	MOVEI BP,1(BP)	;CLEAR OUT LH OF BYTE POINTER
	IMULI BP,5
	IDIVI TT,7
	SUBI BP,1(TT)
	POPJ P,

GETINC:	MOVE TT,IN
	AOSA IN
GETCHR:	 MOVE TT,IN
	CAML TT,GPT
	 ADD TT,EXTRAC
	IDIVI TT,5
	LDB CH,BTAB(TT1)
	POPJ P,

PUTINC:	MOVE TT,OUT
	AOSA OUT
PUT:	 MOVE TT,OUT
	CAML TT,GPT
	 ADD TT,EXTRAC
	IDIVI TT,5
	DPB CH,BTAB(TT1)
	POPJ P,

	440700+TT,,	;FOR SORT
BTAB:	350700+TT,,
	260700+TT,,
	170700+TT,,
	100700+TT,,
	10700+TT,,

;CALL GETARG TO DECODE 0,1 OR 2 ARGS AS "T", "K", "X", ETC. DO.
;RETURNS IN E,C THE CHAR ADDRS OF BEGINNING AND END OF RANGE.
;SKIPS IF THERE WERE 0 OR 1 ARG; DOESN'T SKIP IF WERE 2.
;THE CALL TO GETARG SHOULD BE FOLLOWED BY A CALL TO CHK1
;OR CHK1A, TO MAKE SURE THE ARGS ARE IN RANGE, IF THERE ARE 2 ARGS.

;NOTE: ^G CAN QUIT OUT OF THE MIDDLE OF THESE ROUTINES!

;HERE TO AVOID LOOKING AT THE UPARROW FLAG.  ALSO, CHECK RANGE USING VIRTUAL BOUNDS.
GETANU:	SAVE FF
	ANDCMI FF,FRUPRW
	CALL GETARG
	 CALL CHK1
	REST FF
	ANDCMI FF,FRCLN
	RET

;WITH THE UPARROW MODIFIER, WE STOP ONLY AT CRLFS, NOT STRAY LF'S.
GETARG:	TRNE FF,FRARG2
	 JRST GETAG6
	ARGDFL O
	CALL IMMQIT	;ALLOW QUITTING UNTIL WE RETURN.
	AOS (P)
	SAVE [DELQIT-1] ;THIS WILL BE INCREMENTED
;GETAG7 AND GETAG4 ARE USED AS ENTRY POINTS
;BY THINGS THAT WANT TO PARSE A FEW LINES FORWARD OR BACK.
GETAG7:	MOVE IN,PT
GETAG4:	SAVE CH
	SAVE A			;A = Saved Last Character
	SAVE B
	JUMPLE C,GETAG2
	MOVE BP,IN
	CAML BP,GPT
	 ADD BP,EXTRAC
	CALL GETIBP
	SETO CH,		;Saved Last Character
GETAR1:	MOVE A,CH		;Store Saved Last Character
	CAMN IN,ZV
	 JRST GETAG5
	CAMN IN,GPT	;REACHING THE GAP => MOVE OVER IT.
	 CALL FEQGAP
	ILDB CH,BP
	CAIE CH,^J	;SCN UNTIL THE NEXT LF.
	 AOJA IN,GETAR1
	TRNN FF,FRUPRW	;IF WE HAVE THE UPARROW FLAG,
	 AOJA IN,GETAR2
	TRNE FF,FRCLN	;IF WE HAVE COLON FLAG, WE WILL STOP BEFORE THE CR,
	 CAME IN,PT	;SO INSIST THAT THE CR ITSELF BE AFTER OUR STARTING POINT.
	  CAIE A,^M		;Saved Last Character
	   AOJA IN,GETAR1
	AOJ IN,
GETAR2:	SOJG C,GETAR1	;FOUND LF OR CRLF AS APPROPRIATE.  IN POINTS AFTER THE LF.
GETAG1:	TRZE FF,FRCLN
	 CALL GETAG8
	CAMG IN,BEGV
	 MOVE IN,BEGV
GETAG5:	REST B
	REST A
	REST CH
	MOVE E,PT
	MOVE C,IN
	TRZ FF,FRCLN\FRUPRW	;TURN IT OFF IF NOT ALREADY DONE
	TLZE FF,FLNEG
	 EXCH C,E
	AOS (P)
	RET

GETAG8:	SUBI IN,2
	PUSHJ P,GETCHR
	CAIE CH,15
	 AOJA IN,GETAG9
	POPJ P,

GETAG9:	PUSHJ P,GETCHR
	CAIE CH,12
	 AOJ IN,
	POPJ P,

GETAG6:	ADD C,BEG
	ADD E,BEG
	TRZ FF,FRCLN\FRUPRW
	POPJ P,

GETAG2:	SOS IN
GETAG0:	CAMGE IN,BEGV
	 AOJA IN,GETAG3
	PUSHJ P,GETCHR
	CAIE CH,12
	 SOJA IN,GETAG0
	TRNN FF,FRUPRW
	 JRST GETAR3
	CAMN IN,BEGV
	 JRST GETAG3
	SUBI IN,1
	CALL GETINC
	CAIE CH,^M
	 SOJA IN,GETAG0
GETAR3:	AOJLE C,GETAG2
	AOJ IN,
GETAG3:	TLO FF,FLNEG
	JRST GETAG1

SUBTTL FUNDAMENTAL TECO COMMANDS

REVERS:	TRNE FF,FRARG2	;<N>R MOVES BACK N CHARACTERS.
	 JRST LINE	;MAKE FLR MOVE RIGHT OVER A LIST.
	ARGDFL Z
	MOVNS C
	JRST REVER1

CHARAC:	ARGDFL Z
REVER1:	ADD C,PT
JMP1:	CAML C,BEGV	;IS THE SPEC'D POS. WITHIN BFR'S LIMITS?
	CAMLE C,ZV
	 JRST [TRZE FF,FRCLN	;NO, FOR :C, ETC.
		 JRST NRET0	;RETURN FAILURE.
		TYPRE [NIB]]	;NO :, THIS IS ERROR.
	MOVEM C,PT
	TRZE FF,FRCLN
	 JRST NRETM1	;FOR :C, ETC. SAY SUCCESSFUL.
	POPJ P,

JMP:	TRZN FF,FRARG
	 SKIPA C,BEGV
	ADD C,BEG
	JRST JMP1

LINE:	CALL GETARG	;GET PT AND DESIRED PT IN C,E.  DO GOBBLE UPARROW FLAG.
	 CALL CHK1	;MAKE SURE ARGS ARE WITHIN VIRT. BUFFER.
	ADD C,E
	SUB C,PT	;IF EITHER ARG EQUALED PT, PT IS NOW THE OTHER ONE.
	JRST JMP1

KILL:	PUSHJ P,GETARG
	 PUSHJ P,CHK1
	JRST DELET1

DELETE:	ARGDFL Z
DELET0:	JUMPE C,CPOPJ	;DELETING 0 CHARS.
	MOVE E,PT
	ADD C,PT	;C,E HAVE 2 ENDS OF RANGE TO DELETE.
	CALL CHK	;MAKE SURE C IS IN THE BUFFER.

;MAIN DELETE RTN. C,E VIRTUAL CHAR ADDRS -> ENDS OF STUFF TO DELETE
;SETS PT TO PLACE DELETED FROM, LEAVES GAP THERE TOO.
.SEE FXCMD	;MUSTN'T CLOBBER A OR D.
DELET1:	CAMG C,E	;GET UPPER END IN C, LOWER IN E.
	 EXCH C,E
	MOVEM E,PT	;TELL GAPSLP WHERE TO PUT GAP (IF CALL IT)
	SKIPE READON	;IF NOT ALLOWED TO MODIFY BUFFER
	 TYPRE [RDO]	;BARF OUT HERE
	CAML C,GPT	;IF THE GAP IS IN OR NEXT TO
	CAMLE E,GPT	;THE AREA BEING DELETED, OK.
	 CALL GAPSLP	;ELSE MOVE IT TO BE SO.
	MOVEM E,GPT	;NOW TURN THE AREA INTO GAP.
	SUB C,E
DELETB:	SETOM MODIFF	;WE ARE CHANGING THE BUFFER CONTENTS.
	SETOM MODIFM
	ADDM C,EXTRAC
	MOVNS C
	ADDM C,ZV
	ADDM C,Z
	POPJ P,

DEL1B:	SOS PT		;DELETE 1 CHARACTER BACKWARDS FROM PT.
	SOS GPT
DEL1F:	SOS ZV		;DELETE 1 FORWARDS FROM PT.
	SOS Z
	AOS EXTRAC
	RET

SUBTTL F^E REPLACE CHARACTERS COMMAND

;<N>F^E<STRING>$ - REPLACE STRING INTO BUFFER STARTING AT POSITION <N>.
;<N>:F^E<Q><STRING>$ - REPLACE IN QREG <Q> (EITHER STRING OR BUFFER WORKS).
;REPLACING IS LIKE INSERTING AND THEN DELETING AS MANY CHARS AS WERE INSERTED.
FCECMD:	ARGDFL
	TRZN FF,FRCLN
	 JRST FCE1	;INSERT IN BUFFER?
	TRZN FF,FRARG
	 TYPRE [WNA]
	CALL QREGX	;NO, QREG. WHICH ONE?
	CALL QLGET0	;LENGTHH IN B, B.P. TO ILDB IN BP.
	 TYPRE [QNS]
	SKIPL C
	 CAMLE C,B	;MAKE SURE ARG IS IN RANGE
	  TYPRE [AOR]
	CALL GETCA
	ADD BP,C		;ADJUST B.P. TO PLACE TO START REPLACING AT.
	CALL GETBP
	SETZ A,		;THERE'S NO GAP TO WORRY ABOUT.
	JRST FCE2

FCE1:	SKIPE READON	;ALLOWED TO MUNGE THIS BUFFER?
	 TYPRE [RDO]	;NO
	SETOM MODIFF	;HERE WE ARE CHANGING THE CURRENT BUFFER'S CONTENTS.
	SETOM MODIFM
	TRZE FF,FRARG	;NO ARG, AND REPLACING IN BUFFER => USE ".".
	 JRST FCE5
	MOVE C,PT
	SUB C,BEG
FCE5:	MOVE BP,GPT	;REPLACE IN BUFFER.
	CALL GETIBP	;MAKE B.P. TO START OF GAP SO WE CAN TELL WHEN WE REACH GAP.
	MOVE A,BP
	MOVE BP,BEG
	ADD BP,C		;GET VIRT. CHAR ADDR OF WHERE TO START REPLACING
	CAML BP,BEGV
	 CAMLE BP,ZV
	  TYPRE [AOR]
	CALL GETIBV	;TURN INTO REAL CHAR ADDR, THEN BP.
	ADD C,BEG	;TURN STOP ADRD IN C INTO ADDR REL. TO VIRTUAL BEG,
	SUB C,BEGV	;SINCE MUST BE COMPARED WITH VIRTUAL SIZE.
	MOVE B,ZV
	SUB B,BEGV	;GET LENGTH OF BUFFER.
FCE2:	SUB B,C		;C HAS CHARS FROM PLACE WE START TO END OF BUFFER OR QREG.
	SETZM INSBP	;MAKE SURE BP IS RELOCATED IF BUFFER MOVES.
	MOVEI CH,ALTMOD
	TRZE FF,FRUPRW	;FIND OUT WHAT STRING ARG DELIMITER WE'RE USING.
	 CALL RCH
	MOVEM CH,INSDLM
FCE3:	CALL RCH	;THIS IS THE INNER LOOP OF FCE
	SKIPE SQUOTP
	 JRST FCE4
	CAMN CH,INSDLM	;CHECK CHAR FOR DELIMITERNESS UNLESS SUPERQUOTED, ETC.
	 JRST FCEEND
FCE4:	SOJL B,[TYPRE [STL]]	;CHECK FOR END OF BUFFER OR QREG.
	CAMN A,BP
	 CALL FEQGAP		;CHECK FOR GAP - MOVE B.P. IN BP OVER IT.
	IDPB CH,BP
	JRST FCE3

FCEEND:	SETOM INSBP
	RET

SUBTTL INSERTION COMMANDS

;INSERT ASCIZ STRING <- BP IN A, INTO Q-REG IN CH.
INSASC:	TRO FF,FRCLN	;SAY INSERT IN Q-REG.
	SAVE CH
	SAVE [0]
	SETZM INSDLM	;DELIMITER IS THE ^@ ENDING THE ASCIZ.
	MOVE CH,[ILDB CH,A]
	MOVEM CH,INSRCH	;GET CHARS BY ILDB-ING BP.
	JRST INSAS1

FNCMD:	MOVE CH,[CALL RCH] ;FN = [..N:I..N BUT PREVENTS QUIT IN BETWEEN. ;]
	MOVEM CH,INSRCH
	MOVE CH,QRB..
	ADDI CH,.QUNWN
	CALL OPENB2
	JRST PSI

CNTRLF:	MOVN C,INSLEN	;^F -- SAME AS "FKDI".
	CALL DELET0
	TRZ FF,FRARG	;MAKE SURE <N>^F DOESN'T INSERT ASCII(N).
	JRST INSERT

TAB:	HRROI B,TAB0	;HERE FOR TAB.  DECIDE WHETHER IT'S
	SKIPLE TABMOD
	 TYPRE [DCD]	;DISABLED,
	SKIPE TABMOD
	 MOVEI B,SPACE	;IGNORED (LIKE SPACE, ACTUALLY),
	JRST CD5B	;OR ENABLED (IN WHICH CASE COME BACK TO TAB0).

TAB0:	PUSHJ P,TYOMGS	;USED FOR ENTRY FROM SELF-INSERTING CHARACTERS
	ANDCMI FF,FRCLN\FRUPRW\FRARG\FRARG2
INSERT:	TRNE FF,FRARG	;IF GIVEN AN ARG,
	 JRST INS1C	;THEN JUST INSERT THAT CHARACTER
	MOVE OUT,[CALL RCH]	;SAY TO USE RCH TO GET CHARACTERS TO INSERT
	MOVEM OUT,INSRCH
	TRNN FF,FRCLN	;IF NOT GOING TO A Q REG
	 JRST INS1	;THEN SKIP THIS STUFF
	PUSHJ P,QREGVS	;OTHERWISE GET THE Q-REG NAME
	JUMPE B,INS0		;IS THE QREG SUBSCRIPTED? (:I:Q(IDX))
	JSP TT,QREGVA		;IF SO, EXTRA HAIR IN CASE OUR CONSING
				;MOVES THE Q-VECTOR CONTAINING THE Q-REG.
				;CALLS PSI, THEN RETURNS TO INSERT'S CALLER.
	JRST INS0

;PSI IS USED BY THINGS THAT WANT TO INSERT A STRING ARG INTO A SPECIFIC QREG.
;THE QREG ADDRESS SHOULD BE IN CH.
PSI:	SETZ B,
	TRO FF,FRCLN
INS0:	SAVE CH		;REMEMBER WHICH QREG TO STORE IN.
	SAVE B
	CAIA
INS1:	 PUSHJ P,GAPSLP	;GET THE GAP AROUND THE HOME COUNTRY
	MOVEI CH,ALTMOD	;GET THE TEMPORARY APROX-
			;IMATION TO THE DELIMITER
	TRZE FF,FRUPRW	;IF IT ISN'T RIGHT (THE UPARROW
			;INDICATOR IS TURNED ON)
	 PUSHJ P,RCH	;THEN GET THE RIGHT ONE
	MOVEM CH,INSDLM	;AND SAVE IT AS THE ONE TO USE
	TRNN FF,FRCLN	;IF NOT INTO A Q-REG, THEN JUMP
	 JRST INS2	;FORWARD
INSAS1:	MOVE C,BFRBOT	;GET # CHARS UNUSED AFTER IMPURE STRING SPACE,
	SUB C,QRWRT
	SUBI C,4	;WE'LL CERTAINLY NEED 4 FOR HEADER OF NEW STRING.
			;INS5 WILL PUT THAT IN TOTALC, # CHARS FREE TO USE.
	MOVE BP,QRWRT	;START STRING AT START OF FREE SPACE,
	ADDI BP,4	;BEGIN THE TEXT AFTER WHERE HEADER'LL GO.
	JRST INS5

INS2:	MOVE BP,PT	;NEXT, GET THE POINTER ADDRESS
	MOVE C,EXTRAC	;# CHARS FREE TO STORE IN IS GAP SIZE.
INS5:	MOVEM C,TOTALC
	CALL GETIBP	;GET BP FOR IDPB INTO GAP.
	MOVEM P,INSINP	.SEE INSCHK	;GO TO INSDUN ON CNM ERROR, TO CLEAN UP.
	SETZM INSBP	;MAKE SURE BP IS RELOCATED IF BUFFER MOVES INSIDE GETFRM INSIDE RCH.

;HERE IS THE LOOP THAT GETS CHARACTERS AND PUTS THEM IN THE BUFFER
INSLUP:	XCT INSRCH	;GET A CHARACTER (RCH AUTOMATICALLY
			;[ ;TAKES CARE OF ALL ^] CALLS AND MACRO
			;RETURNS)
INSDCK:	SKIPE SQUOTP	;UNLESS WITHIN QUOTED MACRO,
	 JRST INSDIR
	CAMN CH,INSDLM	;THEN SEE IF IT IS THE DELIMITER
	 JRST INSDUN	;IF SO, YOU'RE ALMOST DONE
INSDIR:	SOSGE TOTALC
	CALL INSSL1
	IDPB CH,BP
	JRST INSLUP
 
INSSL1:	SETOM INSBP	.SEE BFRRL3 ;FAKE OUT THE ERROR CHECK AT BFRRL3+EPSILON
	CALL INSSLP
	SETZM INSBP
	RET

INSSLP:	MOVN C,TOTALC	;HOW MANY CHARS ALREADY KNOWN NEEDED.?
	TRNE FF,FRCLN
	 JRST SLPQRG	;:I, MOVE UP BUFFER AT LEAST THAT MUCH.
	ADD C,EXTRAC
	JRST SLPSAV	;ELSE MAKE GAP > THAT MUCH BIGGER.

INSDUN:	SETOM INSBP
	CALL GETCA
	AOS OUT,BP	;CHAR ADDR 1ST PLACE NOT STORED IN.
	TRNN FF,FRCLN	;IF YOU'RE NOT USING A Q-REG
	 JRST INS4	;THEN EVERYTHING IS MUCH SIMPLER
	SKIPGE TOTALC	;IF INSERTING 0 CHARS, MAKE SURE SPACE FOR HEADER.
	 CALL INSSL1
INSDU1:	MOVE C,BP	;GET END OF STRING,
	MOVE BP,QRWRT	;AND PLACE START OF HEADER SHOULD BE.
	SUB C,BP	;# CHARS WE USED (TEXT SIZE +4)
	MOVEI B,QRSTR	;THIS IS THE CHAR TO START THE HEADER
	CALL QHDRW0	;WRITE A STRING HEADER AT <- CHAR ADDR IN BP.
INS3:	REST B		;GET BACK INFO ON QREG.
	REST CH		;GET BACK ADDR OF QREG TO STORE IN.
	CALL QCLOSE	;STORE IN IT; OUT HAS CHAR ADDR END OF STRING.
			;QRWRT HAS CHAR ADDR OF BEINNING. UPDATES ALL PTRS.
	JRST INSRT1

INS4:	MOVEM BP,PT
	MOVEM BP,GPT
	MOVE CH,TOTALC	;# CHARS OF GAP WE DIDN'T USE.
	EXCH CH,EXTRAC	;IS WHAT'S LEFT OF THE GAP.
	SUB CH,EXTRAC	;AMOUNT WE DID USE
	MOVEM CH,INSLEN	;IS # CHARS INSERTED.
	ADDM CH,Z	;THAT MANY MORE CHARS NOW.
	ADDM CH,ZV
INSRT1:	SKIPN INSINP	;0 => WAS CLEARED BY INSCHK, WAS CNM ERROR.
	 TYPRE [CNM]
	SETZM INSINP	;NO LONGER IN MIDDLE OF INSERT.
	TRZ FF,FRCLN+FRUPRW	;IF THIS IS :I*, WE ARE RETURNING VALUE SO MUST CLEAR THESE
	RET			;BY HAND.

INS1C:	ARGDFL
	TRNN FF,FRARG2	;<N>,<CH>I - INSERT <CH> <N> TIMES.
	 MOVEI E,1
	SKIPGE E
TYPAOR:	 TYPRE [AOR]
	TRZE FF,FRCLN
	 JRST INS1CQ	;INTO QREG?
	MOVE CH,NUM	;INTO BUFFER.
	ANDCMI FF,FRCLN
	PUSHJ P,GAPSLP
	SKIPN C,E
	 RET
	CALL SLPGET	;GET C(C) CHARS SPACE, AND B.P. IN BP.
	IDPB CH,BP
	SOJG C,.-1
	RET

TYOMGS:	CALL GAPSLP
TYOM:	SAVE C
	PUSH P,TT
	PUSH P,TT1
	SAVE BP
	MOVEI C,1
	CALL SLPGE1
	IDPB CH,BP
	REST BP
	POP P,TT1
	POP P,TT
POPCJ:	REST C
	RET

;<CH>:I<Q>  --  INSERT 1 CHAR IN QREG.
;<N>,<CH>:I<Q>  --  INSERT <N> COPIES OF CHARACTER.
;<CH>:I*  --  RETURNS A STRING CONTAINING THE CHARACTER <CH>.
INS1CQ:	CALL QREGVS	;GET ADDR OF QREG IN CH.
	TRZ FF,FRARG\FRARG2\FRCLN\FRUPRW
		;FLUSH ARG IN CASE :I* - OTHERWISE WOULD ADD ARG TO VALUE.
	JUMPE B,INS1CR		;IS THE QREG SUBSCRIPTED? (:I:Q(IDX))
	JSP TT,QREGVA		;IF SO, EXTRA HAIR IN CASE OUR CONSING
				;MOVES THE Q-VECTOR CONTAINING THE Q-REG.
				;CALLS INS1CR, THEN RETURNS TO INSERT'S CALLER.
INS1CR:	SAVE B
	MOVEI C,4(E)	;NEED 4 CHARS FOR HEADER, + CONTENTS.
	CALL SLPQGT	;MOVE BUFFER UP IF NEC.
	MOVEI B,QRSTR	;1ST CHARACTER, FOR HEADER.
	MOVEI C,4(E)	;LENGTH, FOR HEADER.
	CALL QHDRW1	;WRITE THE STRING HEADER, LEAVE BP IN BP.
	MOVE C,E
	MOVE A,NUM
	IDPB A,BP
	SOJG C,.-1
	MOVEI OUT,4(E)	;GET ADDR 1ST CHAR THIS NEW STRING DOESN'T USE.
	ADD OUT,QRWRT
	REST B
	JRST QCLOSE	;UPDATE QRWRT; STORE STRING IN QREG <- CH.

SUBTTL GAP CONTROL

IFNDEF SLPAMT,SLPAMT==SLPWRD*5	;MAKE GAP IN UNITS OF THIS MANY CHARS.
IFNDEF SLPQAM,SLPQAM==SLPQWR*5	;MOVE BUFFER UP IN UNITS OF THIS MANY.

;MAKE SOME SPACE BY MOVING A SEGMENT OF MEMORY UPWARD.
;REAL CHARACTER ADDR. OF BOTTOM CHAR. OF SEGMENT TO MOVE IN BP
;REAL CHAR ADDR OF SEGMENT IN TT.
;MINIMUM AMOUNT OF SPACE (# OF CHRS) IN C.
;SPACE IS MADE ONLY IN MULTIPLES OF A WORD.
SLPN00:	MOVE D,BFRTOP
	SUB D,BEG		;GET NUMBER OF CHARS WE WILL HAVE TO MOVE.
	CAIL D,2000*5*5		;IF MORE THAN 5K WORDS, IT PAYS TO MAKE LOTS OF SPACE.
	 SKIPA D,[2000]		;SO MAKE IT A K AT A TIME, AND USE PAGE-MAPPING.
	  MOVEI D,200		;ELSE JUST MAKE 200 WORDS AT A TIME.
	MOVE E,@BFRPTR
	TLNE E,MFQVEC		;IN A QVECTOR, MAKE ONLY 200 WORDS OF SPACE
	 MOVEI D,200		;SINCE THEY NEVER GET VERY BIG.
	MOVE E,D
	IMULI D,5
	ADDI C,-1(D)		;ROUND C, THE NUMBER OF CHARS OF SPACE WE NEED,
	IDIV C,D		;UP TO A MULTIPLE OF WHAT'S IN D,
	IMUL C,E		;BUT CONVERT IT TO WORDS INSTEAD OF CHARACTERS.
;HERE TO MAKE SPACE FOR IMPURE STRING SPACE.
SLPN0Q:	ADDI TT,4
	IDIVI TT,5
	MOVE E,TT
	ADD E,C		;ADDR OF LAST WD TO MOVE INTO, + 1.
	SKIPE PSSAVP	;IF SORTING,
	 CAMGE E,PSMEM	;IF WE'D BE CLOBBERING SORT TABLES, MOVE THEM TOO.
	  JRST SLPN01
	MOVE TT,PSMEMT	;LAST WD TO MOVE UP IS LAST WD OF SORT TABLES,
	ADDI TT,3
	ADDM C,PSMEM	;RELOCATE POINTERS TO SORT TABLES.
	ADDM C,PSMEMT
	MOVE E,TT
	ADD E,C
SLPN01:	ADDI E,2000
	LSH E,-10.
	CAML E,LHIPAG	;DON'T IMPINGE ON PURE STRING SPACE!  LEAVE 1K EMPTY IN BETWEEN.
	 TYPRE [URK]
	IDIVI BP,5
IFN ITS,[
	TRNN C,1777	;IF MAKING SPACE IN UNITS OF A K, DO IT BY PAGE MAPPING
	 SKIPE PSSAVP	;BUT ONLY IF NO SORT TABLE.
	  CAIA
	   JRST SLPN0P	;TO AVOID HAVING TO SWAP EVERYTHING IN.
SLPN0W:	SAVE TT
	MOVE Q,TT	;IF WE DO HAVE TO SWAP IT IN, USE SEQUENTIAL PAGING.
	ADD Q,C
	IMULI Q,5
	MOVE TT,C
	IMULI TT,5
	MOVE CH,BP
	CALL SEQPAG
	REST TT
]
	SUBM TT,BP	;BP _ # WDS TO MOVE.
	HRLI TT,-1	;TT HAS -1,,LAST WD + 1.
	SUB TT,[1,,1]	;MAKE -> LAST WD (1ST POP WILL MOVE IT)
	MOVEI D,(C)
	HRLI D,(POP TT,(TT))
	MOVE E,[SOJGE BP,D]
	MOVE J,[JRST SLPN02]
	JRST E
SLPN02:	MOVE E,C	;GET BACK # WDS ADDED,
	IMULI E,5
	ADDM E,TOTALC
IFN ITS,JRST SEQPGX
.ELSE	RET

IFN ITS,[
SLPN0P:	CAILE TT,2000(BP)	;MAKE SURE WE HAVE AT LEAST A K LEFT TO DO!
	 SKIPE PSSAVP		;USE PAGE-MAPPING ONLY IF NO SORT TABLE!  WE'D CLOBBER IT!
	  JRST SLPN0W
SLPN03:	MOVEI D,-1(TT)
	LSH D,-10.		;COMPUTE # OF TOP PAGE TO MOVE,
	MOVEI E,1777(TT)
	ADD E,C			;AND # OF PAGE TO MOVE IT INTO, + 1.
	LSH E,-10.
	CAMLE E,MEMT		;SINCE WE ARE MOVING UP THE BOUNDARY OF BUFFER SPACE MEMORY,
	 MOVEM E,MEMT		;WE MUST REMEMBER THAT.
	SUBI E,1		;NOW CONVERT TO EXACT PAGE TO MOVE INTO.
	SYSCAL CORBLK,[%CLIMM,,%CBNDW ? %CLIMM,,%JSELF ? E ? %CLIMM,,%JSELF ? D]
	 .LOSE %LSSYS
	SUBI TT,1
	ANDI TT,-2000		;SET TT TO TOP OF WHAT STILL NEEDS TO BE MOVED.
	CAILE TT,2000(BP)	;KEEP MOVING PAGES UNTIL LESS THAN A PAGE REMAINS.
	 JRST SLPN03
SLPN0R:	CAMG E,D		;NOW, MAKE FRESH PAGES WHERE THE NEWLY CREATED GAP IS.
	 JRST SLPN0W
	SOS E			;ENOUGH TO MAKE SURE WE DON'T HAVE ANYTHING IN THE MAP TWICE
	SYSCAL CORBLK,[%CLIMM,,%CBNDW ? %CLIMM,,%JSELF ? E ? %CLIMM,,%JSNEW]
	 .LOSE %LSSYS		;IS EXACTLY THE RIGHT NUMBER.
	JRST SLPN0R
] ;IFN ITS

;MAKE SURE GAP AT LEAST SOME MINIMUM SIZE
;(# CHARS IN C)
SLPSAV:	CAMG C,EXTRAC
	 RET
	CALL SAVACS
	SUB C,EXTRAC	;HOW MANY MORE CHARS NEEDED?
	MOVE BP,GPT	;GET ACTUAL ADDR OF END OF GAP.
	ADD BP,EXTRAC
	MOVE TT,BFRTOP	;GET ACTUAL ADDR OF END OF BUFFER.
	SAVE Z
	SAVE MEMT
	PUSHJ P,SLPN00
	MOVEI D,@D	;GET ADDR LAST WD OF NEWLY MADE GAP.
	REST BP		;DON'T NEED TO CLEAR NEWLY OBTAINED CORE.
	LSH BP,10.
	CAML D,BP
	 SOS D,BP
	MOVEI BP,1	;PREPARE TO CLEAR LOW BITS OF WDS THAT NEED IT.
	REST A		;ANY WD PREVIOUSLY PART OF THIS BUFFER DOESN'T NEED IT.
	IDIVI A,5
SLPSA2:	CAMGE D,A
	 JRST SLPSA1
	ANDCAM BP,(D)
	SOJA D,SLPSA2

SLPSA1:	ADDM E,EXTRAC
	MOVE T,E
	MOVE TT,Z
	CALL BFRRLC
	JRST RSTACS

;LIKE SLPGET, BUT FOR COMMANDS THAT EITHER INSERT IN THE BUFFER
;OR CONS UP AND RETURN A STRING.  SUCH COMMANDS SHOULD ALSO EXIT THRU SLPXIT.
SLP:	TRNE FF,FRCLN
	 JRST QOPEN

;INSERT C(C) CHARS AT PT, MAKING SPACE IF NEC.
;PUTS PT AFTER THEM.  BRINGS THE GAP TO PT.
;DON'T ACTUALLY PUT ANYTHING IN THOSE CHARS,
;RATHER RETURN IN BP A BP. TO IDPB INTO THEM.
;CLOBBERS TT, TT1.  PRESERVES C!
SLPGET:	CALL GAPSLP
SLPGE1:	CAMLE C,EXTRAC	;HAVE ENOUGH ROOM FOR THE CHARS?
	 CALL SLPSAV	;NO, STRETCH GAP.
	MOVE BP,PT
	ADDM C,PT	;UPDATE VARS FOR INSERTION OF THOSE CHARS.
	ADDM C,GPT
	MOVNS C		;DELETE -<N> CHARS TO UPDATE Z, ZV, EXTRAC.
	CALL DELETB	;DELETB NEGATES C.
	SOJA BP,GETBP	;MAKE REMEMBERED PT (IN BP) INTO BP.

;MAKE SURE UNUSED SPACE AFTER IMPURE STRING SPACE AT LEAST C(C) CHARS.
;MAY MOVE BUFFER, IN WHICH CASE ALL BUFFER POINTERS WILL
;BE UPDATED AS NECESSARY.
SLPQGT:	ADD C,QRWRT	;CHAR ADDR LAST CHAR WE'LL NEED.
	SUB C,BFRBOT	;THAT CHAR IN BUFFER?
	JUMPL C,CPOPJ	;NO, HVE ENOUGH ROOM.

;GET AT LEAST C(C) MORE UNUSED SPACE FOR IMPURE STRINGS.
;WILL MOVE BUFFER AND UPDATE ALL BUFFER POINTERS.
SLPQRG:	CALL SAVACS
	MOVE BP,BFRBOT	;MOVE ENTIRE BUFFER.
	MOVE TT,BFRTOP	;GET REAL ADDR. END OF BUFFER.
	ADDI C,SLPQAM-1
	IDIVI C,SLPQAM	;# OF UNIT INCREMENTS WE NEED.
	IMULI C,SLPQWR	;# OF WDS TO MOVE THE BUFFER.
	CALL SLPN0Q	;MOVE IT.
	MOVE BP,BFRBOT
	IDIVI BP,5
SLPQR1:	SETZM (BP)	;CLEAR ALL WORDS OF SPACE JUST MADE.
	AOJ BP,		;NOTE THAT BFRBOT HAS NOT BEEN RELOCATED YET, SO IT POINTS AT
	SOJG C,SLPQR1	;THE BOTTOM OF THE SPACE JUST MADE.
	MOVE T,E
	CALL BFRMOV	;RELOCATE ALL PTRS TO BUFFER.
	JRST RSTACS

;WRITE A STRING HEADER. B HAS INITIAL CHARACTER (QRSTR OR QRBFR),
;C HAS CONTENTS (LENGTH OR BUFFER FRAME ADDRESS).
;BP IS LEFT WITH A B.P. TO LAST CHAR. OF HEADER.
;CLOBBERS C,T,TT.
QHDRW1:	MOVE BP,QRWRT	;WRITE HEADER IN FIRST FREE SPOT.
QHDRW0:	CALL GETBP	;ASSUME BP HAS CHAR ADDR OF PLACE TO WRITE.
	DPB B,BP
	IDPB C,BP
	LSH C,-7
	IDPB C,BP
	LSH C,-7
	IDPB C,BP
	RET

QCLOSV:	CALL GETCA	;WHERE DID WE STOP IDPB'ING?
	AOS BP
	MOVE C,BP
	MOVE BP,QRWRT	;BP GETS PLACE TO WRITE HEADER.
	MOVE OUT,C	;OUT GETS NEW VALUE FOR QRWRT.
	SUB C,BP		;C GETS LENGTH OF WHAT WE JUST WROTE (INCL HEADER)
	MOVEI B,QRSTR
	CALL QHDRW0	;WRITE THE HEADER
	MOVEI CH,A	;TELL QCLOSE TO STORE INTO A,
	SETZ B,		;WHICH IS NOT A NAMED VARIABLE.
	JRST QCLOSE

;MAKE SURE THERE IS SPACE IN IMPURE STRING SPACE FOR C(C) CHARS,
;THEN SET UP LISTF5 TO IDPB THRU BP INTO IMPURE STRING SPACE.
QOPEN:	SAVE C
	ADDI C,4	;HEADER OF STRING NEDS SPACE TOO.
	CALL SLPQGT	;MAKE SURE EXISTS ENOUGH SPACE.
	REST C
	MOVE BP,QRWRT	;START WRITING INTO UNUSED IMPURE STRING SPACE
	ADDI BP,4	;SKIPPING ROOM FOR THE NEW STRING'S HEADER-TO-BE.
	CALL GETIBP
	MOVEI A,[IDPB CH,BP ? RET]
	HRRM A,LISTF5
	POPJ P,

;ASSUME A STRING HAS BEEN STORED IN THE AREA ABOVE QRWRT,
;UPDATE QRWRT AND STORE STRING PTR IN QREG.
QCLOSQ:	TDZA B,B	;QREG ADDR IN CH, AND CERTAINLY NOT A NAMED VARIABLE.
QCLOSP:	REST CH		;QREG ADDR IS ON STACK.  B IS AS RETURNED BY QREGX.
QCLOSE:	EXCH OUT,QRWRT	;QREG ADDR IN CH.  B IS AS RETURNED BY QREGX.
	SUB OUT,QRBUF
	TLO OUT,400000
	MOVE C,OUT
	JRST USE2	;STORE VALUE IN QREG, WITH ERROR CHECKING ETC.

;CLOSE UP THE GAP, AND SAY IT IS AT PT.  CLOBBERS NO ACS.  DOESN'T SET MODIFF.
SLPSHT:	SKIPN EXTRAC	;NOTHING TO DO IF NO GAP.
	 JRST GAPSLN
	SAVE Q
	MOVE Q,Z
	CAMN Q,GPT
	 JRST SLPSH2
	EXCH Q,PT
	SAVE Q
	CALL GAPSL0	;THEN MOVE THE GAP TO PT.  DON'T SET MODIFF.
	REST PT
SLPSH2:	REST Q
	CALL GAPKIL	;NOW GAP IS AT END, JUST FORGET ABOUT IT.
GAPSLN:	SAVE PT		;GAP LENGTH IS 0, MAKES NO DIFFERENCE WHERE
	REST GPT		;WE SAY THE GAP IS LOCATED.
	RET

;ASSUMING THAT THE GAP IS AT THE END OF THE CURRENT BUFFER,
;CLOSE IT UP. CLOBBERS NO ACS. RELOCATES ALL NECESSARY POINTERS
;IN BUFFER FRAMES (AND BFRTOP).
GAPKIL:	SAVE A
	SAVE B
	SAVE C
	MOVE A,Z
	ADD A,EXTRAC
	IDIVI A,5	;WHAT WORD DOES THE THING AFTER THE BUFFER
	MOVE C,A	;ACTUALLY START IN?
	IMULI A,5
	ADDI A,5
	CAML A,BFRTOP	;IF THERE'S NOTHING AFTER THE BUFFER, JUST CHANGE A FEW POINTERS
	 JRST [	MOVE A,Z	;IN PARTICULAR BFRTOP POINTED AFTER GAP,
		IDIVI A,5
		IMULI A,5	;MAKE IT -> CHAR ADDR OF WORD BNDRY
		ADDI A,5	;AFTER THE END OF THE BUFFER.
		MOVEM A,BFRTOP
		JRST GAPKI1]
IFN ITS,[
	INSIRP PUSH P,TT TT1 CH Q
	MOVE TT,Z		;ARRANGE FOR SEQUENTIAL PAGING AS WE DO THE BLT.
	ADD TT,EXTRAC
	MOVE Q,BEG
	MOVE CH,BFRTOP
	CALL SEQPAG
	INSIRP POP P,Q CH TT1 TT
]
	SAVE C		;THERE'S ANOTHER BUFFER AFTER THIS ONE.
	MOVE A,Z
	IDIVI A,5	;WHAT WORD SHOULD IT START IN (ACTUALLY 1 LESS THAN)
	HRL A,(P)	;AND -1+<WHERE IT DOES START>
	HRRZ C,A
	SUB C,(P)	;C HAS -<HOW FAR DOWN IT'S MOVING>
	ADD A,[1,,1]	;<WHERE IT STARTS>,,<WHERE IT SHOULD>
	MOVEM A,(P)
	MOVE A,BFRTOP
	IDIVI A,5	;WORD FOR BLT TO STOP MOVING OUT OF (PLUS 1)
	ADDI A,-1(C)
	EXCH C,(P)
	BLT C,(A)
IFN ITS,CALL SEQPGX
	EXCH T,(P)	;GET # WORDS THINGS MOVED BY.
	IMULI T,5
	SAVE TT
	MOVE TT,Z
	ADD TT,EXTRAC
	CALL BFRRLC	;RELOCATE PTRS TO BUFFERS WE MOVED.
	REST TT
	REST T
GAPKI1:	SETZM EXTRAC
POPCBA:	REST C
POPBAJ:	REST B
POPAJ:	REST A
	RET

;MOVE THE GAP TO PT.
GAPSLP:	SKIPE READON	;ALLOWED TO MODIFY?
	 TYPRE [RDO]
	SETOM MODIFF	;IF WE CARE WHERE GAP IS, WE MUST BE ABOUT TO MUNG THE BUFFER.
	SETOM MODIFM
GAPSL0:	SKIPN EXTRAC	;NO GAP REALLY =>
	 JRST GAPSLN	 ;JUST SAY IT'S AT PT, REALLY DOESN'T MATTER.
	SAVE Q
	MOVE Q,PT
	CAMN Q,GPT	;GAP ALREADY AT PT => NOTHING TO DO.
	 JRST POPQJ
	CAMG Q,GPT	;MOVING GAP DOWN => DIFFERENT.
	 JRST GAPDN
	REST Q
	CALL SAVACS
GAPUP3:	MOVE BP,GPT	;MOVE 1ST FEW CHARS 1 AT A TIME.
	CAMN BP,PT	;(WHEN GET HERE 2ND TIME,
	 JRST RSTACS	 ;MIGHT BE NOTHING TO MOVE)
	ADD BP,EXTRAC	;GET FETCHING PTR -> ABOVE GAP.
	CALL GETIBP
	MOVE TT,GPT
	IDIVI TT,5	;GET STORING PTR -> BELOW GAP.
	MOVE A,PT
	SUB A,GPT	;GET TOTAL # CHARS TO BE MOVED.
	JUMPE TT1,[SOJA TT,GAPUP2]
GAPUP0:	SUBI TT1,5	;(WILL INCREM. TO 0 WHEN REACH WD BNDRY)
GAPUP1:	ILDB IN,BP	;GET A CHAR FROM ABOVE GAP,
	DPB IN,BTAB+5(TT1) ;PUT IT BELOW GAP,
	AOS GPT		;SAY GAP HAS MOVED UP 1 CHAR.
	SOJLE A,RSTACS	;GAP HAS REACHED PT => DONE.
	AOJN TT1,GAPUP1	;EFFECTIVELY IBP THE STORING PTR.
GAPUP2:	CAIGE A,5	;BOTTOM OF GAP NOW ON WD BNDRY,
	 AOJA TT,GAPUP0	;< 1 WDS LEFT => KEEP GOING CHAR BY CHAR.
	MOVEI C,1(TT)	;GET ADDR 1ST WD TO MOVE DOWN INTO.
IFN ITS,[
	MOVE Q,GPT	;SET UP SEQUENTIAL PAGING IN AREA TO MOVE.
	ADD Q,EXTRAC
	MOVE CH,PT
	MOVE TT,EXTRAC
	CALL SEQPAG
]
	MOVE 10,PT
	ADD 10,EXTRAC	;REAL ADDR 1ST CHAR NOT TO MOVE DOWN.
	SUBI 10,5	;DON'T MOVE THE LAST 5 CHARS WITH FAST LOOP (CAN GARBAGE).
	IDIVI 10,5	;10 -> HIGHEST WD TO MOVE DOWN FROM.  NOTE 10 = T.
	MOVN 12,EXTRAC
	IDIVI 12,5	;12 GETS <# WDS OF GAP, ROUNDED UP>.  13 <- # CHARS ROUNDED BY.
	JUMPE 13,[	;HERE IF CAN USE BLT (ALL ON WORD BNDRYS).
		ADD 10,12	;10 GETS ADDR OF LAST WD TO MOVE DOWN TO.
		SUBM C,12	;12 GETS 1ST ADDR TO MOVE FROM.
		MOVEI 11,1(10)
		SUB 11,C	;11 GETS # OF WORDS TO MOVE.
		IMULI 11,5
		ADDM 11,GPT	;UPDATE GPT FOR WHAT WE'RE DOING HERE.
		HRLI C,(12)
		BLT C,(10)
		JRST GAPUP4]
	ADDI 12,-1(10)	;12 -> HIGHEST WD TO MOVE DOWN INTO.
	MOVNM 13,11
	IMULI 11,7
	MOVNI 14,-43(11)
	SUBI C,1(12)	;C HAS MINUS # WDS TO MOVE
	JUMPE C,[AOS TT,12	;WOULD MOVE 0 WORDS (CAN HAPPEN) => DO REST BY CHARS.
		 SETZ TT1,
		 IFN ITS,CALL SEQPGX
		 JRST GAPUP0]
	MOVN 15,C	;UPDATE GPT FOR THE WDS WE'RE MOVING.
	IMULI 15,5
	ADDM 15,GPT
	MOVE 13,12
	HRLI 10,(MOVE B,(C))
	HRLI 11,(LSHC A,)
	MOVE 12,[LSH A,1]
	HRLI 13,(MOVEM A,(C))
	HRLI 14,(LSHC A,)
	MOVE 16,[JRST GAPUP4]
	MOVE A,@10
	ROT A,-1
	MOVE 15,.+1
	AOJLE C,10

GAPUP4:
IFN ITS,CALL SEQPGX
	JRST GAPUP3

;MOVE THE GAP DOWN (IE MOVE CHARS FROM PT TO GPT UP).  Q IS ON THE STACK.
GAPDN:
IFN ITS,[			;ON TNX, PAGE MAPPING GAP MAKING IS NOT IMPLEMENTED.
	MOVE Q,@BFRPTR
	TLNE Q,MFQVEC		;IN A QVECTOR, PAGE MAPPING WOULDN'T BE USED
	 JRST GAPDN7		;SO THIS HACK WOULD SLOW THINGS DOWN.
	MOVE Q,PT
	ADD Q,BFRTOP		;COMPUTE AVERAGE OF PT AND BFRTOP.
	LSH Q,-1
	ADDI Q,5*2000*5		;IF GAP IS AT LEAST 10K CLOSER TO BFRTOP,
	CAMG Q,GPT		;WE WILL SWAP IN 10 FEWER PAGES
	 JRST [	REST Q		;IF WE KILL THE GAP AND RECREATE IT A PAGE LONG,
		JRST SLPSHT]	;BECAUSE GAP CREATION IS DONE WITH PAGE MAPPING.
GAPDN7: ]
	MOVE Q,PT
	ADD Q,Z
	ADD Q,Z
	ADD Q,Z		;COMPUTE WEIGHTED AVERAGE OF PT AND Z, THEN COMPARE WITH GPT
	LSH Q,-2
	CAMG Q,GPT	;IS GPT CLOSER TO PT, OR TO Z?
	 CALL [ SAVE PT		;GPT IS MUCH CLOSER TO Z THAN TO POINT. SO FASTEST THING
		MOVE Q,Z	;IS TO MOVE GAP TO Z, ADJUST WITH GAPADJ, AND
		MOVEM Q,PT	;MOVE IT DOWN AGAIN USING A POP-LOOP.
		CALL GAPSLP
		REST PT
		RET]
	REST Q		;GPT CLOSER TO PT; FASTER TO MOVE GAP DIRECTLY TO POINT.
	CALL SAVACS
	MOVE BP,GPT
	CAMN BP,Z	;IF GAP IS AT END OF BUFFER, WE CAN ADJUST ITS SIZE A LITTLE
	 CALL GAPADJ	;AND THEREBY ENABLE WHAT FOLLOWS TO USE A BLT.
GAPDN3:	MOVE BP,GPT	;MOVE THE 1ST FEW CHARS UP,
	CAMN BP,PT	;(FOR GETTING HERE 2ND TIME WITH
	 JRST RSTACS	 ;TO BE MOVED)
	CALL GETBP	;GET PTR FOR FETCHING CHARS BELOW GAP,
	MOVE TT,GPT
	ADD TT,EXTRAC	;GET PTR FOR STORING ABOVE GAP.
	IDIVI TT,5
	MOVE A,GPT	;GET TOTAL # CHARS MUST MOVE UP.
	SUB A,PT
	SOJL TT1,GAPDN2 ;ALREADY MOVING TO WD BNDRY.
GAPDN1:	DBP7 BP		;GET PTR -> LAST CHAR BELOW GAP.
	LDB CH,BP
	DPB CH,BTAB(TT1) ;MOVE IT BELOW TOP OF GAP.
	SOS GPT		;GAP HAS MOVED DOWN 1 CHAR.
	SOJLE A,RSTACS	;GAP HAS REACHED PT => DONE.
	SOJGE TT1,GAPDN1 ;EFFECTIVELY DBP7 THE OUTPUT BP.
GAPDN2:	CAIGE A,5	;TOP OF GAP NOW ON WD BNDRY
GAPDN5:	 SOJA TT,[ADDI TT1,5	;< 1 WD LEFT, KEEP
		JRST GAPDN1]	;CHAR AT A TIME.
IFN ITS,[
	MOVE Q,GPT	;SET UP SEQUENTIAL PAGING IN AREA TO MOVE.
	ADD Q,EXTRAC
	MOVE CH,PT
	MOVE TT,EXTRAC
	CALL SEQPAG
]
	MOVE 13,EXTRAC	;MOVE AS MUCH AS CAN, WD AT A TIME.
	IDIVI 13,5
	IMULI 14,7
	MOVN 11,14
	MOVEI 14,-43(14)
	MOVE B,PT
	ADDI B,4
	IDIVI B,5
	MOVE 15,GPT
	IDIVI 15,5
	MOVEI C,(15)
	SUB C,B
	JUMPE C,[MOVE TT,GPT	;IF CAN'T MOVE ANYTHING WORD-WISE AFTER ALL,
		 ADD TT,EXTRAC	;REENTER CHAR-AT-A-TIME LOOP
		 IDIVI TT,5
		 IFN ITS,CALL SEQPGX
		 SOJA TT1,GAPDN5]
	MOVE 7,B
	MOVN 15,C	;MAKE GPT REFLECT THE MOTION OF GAP
	IMULI 15,5	;THAT IS NOW ABOUT TO BE DONE.
	ADDM 15,GPT
	JUMPE 11,GAPDN4	;(TRANSLATING BY INTEGRAL # OF WDS.)
	ADDI 13,1(7)
	HRLI 7,(MOVE A,(C))
	HRLOI 10,(LSH A,)
	HRLI 11,(LSHC A,)
	MOVE 12,[ANDCMI B,1]
	HRLI 13,(MOVEM B,(C))
	HRLI 14,(LSHC A,)
	MOVE 16,[JRST GAPDN6]
	MOVE B,@7
	MOVE 15,.+1
	SOJGE C,7

GAPDN4:	HRLI 13,(POP 7,(7))	;EXTRAC = 0 MOD 5, NEED NOT ROTATE
	ADDI 7,-1(C)		;-> HIGHEST WD TO MOVE FROM
	HRLI 7,-1		;PREVENT PDL OV.
	MOVE 15,[JRST GAPDN6]	;INSN THAT EXITS LOOP.
	MOVE 14,.+1
	SOJGE C,13		;C HAS # WDS TO MOVE.

GAPDN6:
IFN ITS,CALL SEQPGX
	JRST GAPDN3

;WHEN THE GAP IS AT Z, WE CAN ADJUST ITS SIZE WITHIN A RANGE OF 5 WITHOUT MOVING ANYTHING.
;IF WE WANT TO MOVE THE GAP DOWN, ADJUSTING ITS SIZE TO A MULTIPLE OF 5
;WILL ENABLE US TO USE A POP-LOOP INSTEAD OF A SLOWER LOOP.

GAPADJ:	MOVE A,Z
	IDIVI A,5	;IF EXTRAC IS A MULTPLE OF 5, REAL Z (Z+EXTRAC) MOD 5 IS THIS REMAINDER
	MOVE IN,Z
	ADD IN,EXTRAC	;SO GET REAL Z
	IDIVI IN,5
	IMULI IN,5	;AND ADJUST IT TO EQUAL THAT, MOD 5,
	ADD IN,B	;WITHOUT CHANGING WHICH WORD IT POINTS AT.
	SUB IN,Z	;BUT Z CAN'T CHANGE, SO THE CHANGE IN REAL Z
	MOVEM IN,EXTRAC	;MUST ALL BE DUE TO CHANGE IN EXTRAC.
	RET

IFN ITS,[
;MAKE USE OF SEQUENTIAL PAGING WHILE SCANNING THROUGH CORE.
;THE LENGTH IN CHARACTERS OF THE REGION TO BE USED AT ANY INSTANT
;SHOULD BE IN TT.
;THE STARTING CHARACTER ADDRESS OF THE SCAN SHOULD BE IN Q.
;THE STOPPING CHARACTER ADDRESS SHOULD BE IN CH.
;BOTH ARGUMENTS CLOBBERED.  CLOBBERS TT1 AND Q ALSO.

;TO STOP USING SEQUENTIAL PAGING, CALL SEQPGX.

;WHILE SEQUENTIAL PAGING IS IN USE, IT CAN BE REQUESTED AGAIN.
;THE INNER REQUESTS ARE IGNORED BUT COUNTED SO THAT THE
;OUTER REQUEST IS NOT TURNED OFF UNTIL THE MATCHING SEQPGX.

;SEQPGV IS LIKE SEQPAG BUT TAKES TWO VIRTUAL ADDRESSES.
SEQPGV:	CAMLE Q,GPT
	 ADD Q,EXTRAC
	CAML CH,GPT
	 ADD CH,EXTRAC

SEQPAG:	SKIPE SEQPGE	;CHECK WHETHER PAGE AHEAD IS ENABLED.
	 AOSE SEQPGC	;DO NOTHING IF ALREADY IN USE.
	  RET
	SETOM SEQPGF	;PAGE AHEAD OFFICIALLY "ON" - BUT USE ONLY IF WORTH WHILE.
	ADDI TT,2*5*2000-1
	IDIVI TT,5*2000	;COMPUTE NUMBER OF PAGES WE NEED TO LOOK AT AT ONCE.
	HRLZ TT1,SEQPGE	;LH(TT1) HAS PAGE-AHEAD DISTANCE.
	CAML Q,CH	;NEGATE PAGE-AHEAD IF MOVING DOWNWARD,
	 MOVNS TT1
	CAMG Q,CH	;NEGATE PAGE-BEHIND IF MOVING UPWARD.
	 MOVNS TT
	CAML Q,CH
	 EXCH Q,CH	;Q NOW HAS THE LOW END OF THE RANGE TO BE SCANNED, CH HAS HIGH END.
	HRR TT1,TT	;TT1 HAS PAGE AHEAD DISTANCE,,PAGE BEHIND DISTANCE.
	MOVE TT,Q
	ADDI Q,5*2000*3	;IF TOTAL DISTANCE TO SCAN IS LESS THAN 3 PAGES,
	CAML Q,CH	;DON'T BOTHER WITH SEQUENTIAL PAGING.
	 RET
	.SUSET [.SPAGAHD,,TT1]
	IDIVI TT,5*2000	;CONVERT THAT TO PAGE NUMBER.
	IDIVI CH,5*2000	;CONVERT HIGH END TO PAGE NUMBER.
	HRL CH,TT
	.SUSET [.SPAGRAN,,CH]
	SETOM SEQPGN	;PAGE AHEAD IS ACTUALLY ON.
	RET

;TURN OFF SEQUENTIAL PAGING.
;MULTIPLE TURN-ONS REQUIRE MULTIPLE TURN-OFFS.
SEQPGX:	SKIPE SEQPGF	;ALLOW TURN-OFF WITHOUT TURN-ON.
	 SOSL SEQPGC	;IF NOT AS MANY TURN-OFFS AS TURN-ONS, DO NOTHING.
	  RET
SEQPGQ:	SETOM SEQPGC
	SETZM SEQPGF	;NOW OFFICIALLY "OFF"
	SKIPN SEQPGN	;BUT IF IT WASN'T REALLY ON, SAVE THE SYSTEM CALL.
	 RET
	SETZM SEQPGN
	.SUSET [.SPAGRAN,,[0]]
	.SUSET [.SPAGAHD,,[0]]
	RET
];ITS

SUBTTL STRING SPACE GARBAGE COLLECTION

GC:
GCC:	SETZM GCNRLC
	CAIA
GCNRL:	 SETOM GCNRLC	;GC TO RECLAIM MACRO FRAMES. DON'T MOVE IMPURE STRINGS.
			;(THEREFORE, CAN BE CALLED IN MID-COMMAND)
	CALL SAVACS
IFN ITS,[
	MOVE A,[-2,,[.SWHO1,,[.BYTE 2,3,3 ? 1 ? 6 ? 6]
		     .SWHO2,,[SIXBIT/QR GC/]]]
	.SUSET A
]
	MOVEI A,1000.		;IN CASE WE GET AN URK ERROR IN THIS GC,
	SKIPN GCNRLC		;ALLOW SOME CONSING BEFORE NEXT ATTEMPT TO GC.
	 ADDM A,QRGCMX
	MOVEI A,MFSTRT		;LOOK AT ALL BUFFER FRAMES,
	MOVSI B,MFMARK
GCC6:	MOVE T,MFBEG(A)		;AND CLEAR THE MARK BITS.
	TLNE T,MFBFR
	 ANDCAM B,MFBEG(A)
	ADDI A,MFBLEN
	CAMGE A,MFEND
	 JRST GCC6
	CALL MEMTOP	;A -> 1ST UNUSED WORD ABOVE BFR & SORT TABLES.
	HRLI A,4400
	MOVEM A,GCPTR	;GCPTR HAS B.P. TO IDPB INTO HIGH CORE.
	PUSH P,A	;REMEMBER WHAT ITS STARTING VALUE WAS.
	MOVE C,BFRPTR	;COPY BEG, ETC. INTO CURRENT BUFFER'S
	CALL NEWBFR	;FRAME, SO THE LATTER IS UP TO DATE.
	CLEARM STABP
	MOVE T,[STABP,,STABP+1]
	BLT T,SYMEND-1	;CLEAR THE JUMP CACHE, SINCE IT WILL NOW BECOME INVALID.
	MOVEI T,CSTR	;MARK CSTR
	PUSHJ P,GCMA
GCC1:	MOVEI T,MFSTRT+MFCSTR	;MARK ALL MACRO FRAMES' STRINGS.
GCC2:	SKIPGE MFBEG-MFCSTR(T)	;DON'T MARK BUFFER FRAMES THIS WAY.
	 JRST GCC4
	ADDI T,MFARG1-MFCSTR
	CALL GCM	;MARK MACRO ARG 1 (MAY BE A STRING POINTER)
	ADDI T,MFARG2-MFARG1
	CALL GCM	;MARK MACRO ARG 2
	SUBI T,MFARG2-MFCSTR	;POINT TO CSTR AGAIN
	SKIPE (T)
	 PUSHJ P,GCMA
GCC4:	ADDI T,MFBLEN
	CAMGE T,MFEND
	 JRST GCC2
GCC3:	HRRZ T,PF	;MARK THE QREG PDL.
	CAIL T,PFL	;MARK BOTH VALUES AND ADDRS, SINCE "ADDR" MIGHT BE A NAME-STRING.
GCC5:	 CALL GCM
	CAILE T,PFL
	 SOJA T,GCC5
	HRRZ T,LEV	;NOW MARK ALL SAVED VALUES
GCC7:	SKIPN A,T	;OF ALL PAREN'S.
	 JRST GCC8	;WE'VE REACHED THE OUTERMOST; WE'RE DONE.
	SUBI T,2	;GET ADDR OF LAST SAVED VALUE.
	CALL GCM
	SUBI T,1	;GET ADDR OF 1ST (IF THERE ARE 2)
	MOVE TT,2(T)	;GET THE WORD WHICH SAYS HOW MANY.
	TRNE TT,FRARG2	;IF THERE ARE 2, MARK THE 1ST.
	 CALL GCM
	MOVE T,(A)	;NOW HANDLE NEXT PAREN OUT.
	JRST GCC7

GCC8:	MOVE T,[-NQREG,,QTAB]
	CALL GCM
	AOBJN T,.-1
	MOVE T,[-RRMACL,,RRMACT]
	CALL GCM
	AOBJN T,.-1
IRPS XX,,DISOMD SBFRS BFRSTR MARG1 MARG2 SARG NUM SYL RRXINV RRENTM RRLEVM RRDISM REFRSH LASTER STEPFL HELPMAC ECHCHR CLKMAC TYISNK TYISRC RREBUF MODMAC TTYMAC RUBMAC RRECSD RRPARN RRTTM1 SUPHND LEDEFS
	MOVEI T,XX
	CALL GCM
TERMIN
IFN 20X,[
	MOVEI T,FRKJCL
	CALL GCM
]
	POP P,A
	MOVE T,A	;STARTING GCPTR MINUS CURRENT
	SUB T,GCPTR	;GIVES -<# WDS IDPB'D>
	HRLM T,A	;AOBJN -> TABLE OF POINTERS.
	ADDI A,1
	MOVEM A,GCPTR
	JUMPGE A,GCE	;NO ENTRIES => NO IMPURE STRINGS TO GC.
	SKIPE GCNRLC	;IF SHOULDN'T MOVE IMPURE STRINGS, SKIP THAT PART.
	 JRST GCE5
	CALL GCSORT	;ELSE SORT POINTERS INTO ORDER STRINGS APPEAR IN MEMORY.
	CALL GCSWP	;COMPRESS STRING SPACE, USING GCPTR TABLE TO RELOCATE POINTERS.
	MOVE IN,B	;IN GETS NEW VALUE FOR QRWRT.
	JRST GCE1	;GO FLUSH EXCESS PAGES, MAYBE MOVING BUFFER SPACE DOWNWARD.

;MARK THE TECO OBJECT POINTER IN THE WORD WHICH RH(T) POINTS AT.
;IF THE OBJECT IS A POINTER, WE PUSH AN ENTRY ONTO GCPTR.
GCM:	MOVE IN,(T)
	TLZE IN,400000	;RETURN IF NOT A STRING POINTER OR IF POINTS AT THE ERROR MESSAGES.
	 CAIGE IN,EREND*5-INIQRB
	  RET		;NO NEED TO MARK BUILT-IN ERROR MESSAGES SINCE NOT SWEPT.
	ADD IN,QRBUF
GCM3:	CAML IN,QRBUF
	 CAML IN,QRWRT	;FINISH CHECKING THAT IT REALLY POINTS INTO IMPURE STRING SPACE.
	  RET
	CALL GETCHR	;DOES IT POINT AT A 177 OR 176?
	CAIN CH,QRBFR
	 JRST GCMB	;176 => THIS IS A BUFFER.
	CAIE CH,QRSTR	;177 => THIS IS A STRING.
	 RET		;ANYTHING ELSE => THIS IS NEITHER.  DON'T MARK IT.

;PUSH A GCPTR ENTRY FOR POINTER LOCATION RH(T) AND STRING ADDRESS C(IN).
GCM2:	IDPB IN,GCPTR
	IDPB T,GCPTR
	POPJ P,

;FOUND A POINTER TO A BUFFER.
GCMB:	MOVE BP,IN
	CALL GCM2	;MARK THE 4-CHAR STRING THAT WE GO INDIRECT THROUGH,
	CALL GETBP	;GO INDIRECT THROUGH IT TO GET FRAME ADDRESS
	CALL QLGET4	;RETURNS <FRAME ADDR>-4
	JUMPL B,CPOPJ	;DEAD BUFFER HAS NO BUFFER FRAME.
	MOVSI IN,MFMARK	;AND MARK THE BUFFER FRAME AS LIVING.
	IOR IN,4(B)
	EXCH IN,4(B)
	TLNN IN,MFMARK	;IF THE FRAME WASN'T ALREADY MARKED,
	 TLNN IN,MFQVEC	;AND MUST BE MARKED THROUGH, DO SO.
	  RET
	SAVE T
	MOVE T,MFBEG+4(B)
	TLZ T,MFBBTS
	IDIVI T,5	;FIRST, MARK BELOW THE GAP.
	MOVE TT,MFGPT+4(B)
	CALL GCMBR
	MOVE T,MFGPT+4(B)
	ADD T,MFEXTR+4(B)
	IDIVI T,5	;THEN MARK ABOVE GAP (GPT+EXTRAC TO Z+EXTRAC)
	MOVE TT,MFZ+4(B)
	ADD TT,MFEXTR+4(B)
	CALL GCMBR
POPTJ:	REST T
	RET

;MARK INDIRECT THROUGH A RANGE OF WORDS (IN A QVECTOR).
GCMBR:	SAVE B		;T HAS WORD ADDR, TT CHAR ADDR.
	IDIVI TT,5	;MARK ALL TEH WORDS FROM T TO TT.
	SUBM T,TT
	HRL T,TT
	SKIPGE T
	 CALL GCM
	AOBJN T,.-1
	REST B
	RET

;HERE TO MARK A BYTE POINTER, SUCH AS CPTR.  T POINTS AT THE CSTR WORD OF A
;COMCNT, CPTR, CSTR TRIPLE.  IF THE POINTER POINTS INTO IMPURE STRING SPACE,
;WE PUSH A GCPTR ENTRY POINTING AT THE CPTR WORD BUT GIVING THE CHAR ADDR EQUIVALENT
;AS ITS STRING ADDRESS.
GCMA:	SAVE GCPTR
	CALL GCM	;MARK THE CSTR WORD, AS AN ORDINARY TECO OBJECT.
	REST TT
	CAMN TT,GCPTR	;IF IT DOESN'T NEED RELOCATION, NEITHER DOES CPTR.
	 RET
	HRRZ IN,CPTR-CSTR(T)
	IMULI IN,5	;WATCH OUT!  IF EXECUTING CONTENTS OF BUFFER,
	CAML IN,BFRBOT	;CSTR POINTS AT IMPURE STRING SPACE, BUT NOT CPTR!
	 RET
	MOVE IN,1(TT)	;IF CSTR NEEDS IT, SO DOES CPTR;  PUSH A MARKER FOR CPTR
	IDPB IN,GCPTR	;GIVING THE SAME "CHAR ADDR TO RELOCATE ACCORDING TO"
	MOVEI IN,CPTR-CSTR(T)
	IDPB IN,GCPTR	;WHICH THE CSTR USED, BUT POINTING AT THE CPTR INSTEAD OF THE CSTR.
	RET

;SORT THE POINTER TABLE TO FACILITATE SWEEPING.
;THE POINTERS GO IN THE SAME ORDER AS THE STRINGS THEY POINT AT.
GCSORT:	HRRZ A,GCPTR
	HLRE B,GCPTR
	SUBM A,B
	MOVSI C,10

;RECURSIVE RADIX-EXCHANGE SORT.
;A POINTS TO FIRST ENTRY IN THIS SUB-SORT.
;B POINTS TO LAST ENTRY + 1
;C HAS ONE BIT SET, THAT BIT MOST SIGNIFICANT BIT TO SORT ON FOR THIS SUB-SORT.
GCSWPS==2		;2 WORDS PER TABLE ENTRY.

GCSRT:	HRLM B,(P)	;SAVE UPPER BOUND
	CAIL A,-GCSWPS(B)
	 JRST GCSRT7	;ONE OR ZERO ENTRIES
	PUSH P,A	;SAVE LOWER BOUND
GCSRT3:	TDNN C,(A)	;BIT SET IN LOWER ENTRY?
	 JRST GCSRT4	;NO, INCREMENT TO NEXT AND MAYBE TRY AGAIN
	SUBI B,GCSWPS	;YES, NOW BACK UP UPPER POINT	
	TDNE C,(B)	;BIT CLEAR IN UPPER ENTRY?
	 JRST GCSRT5	;NO, CHECK FOR END, DECREMENT B, AND TRY AGAIN
REPEAT GCSWPS,[		;BIT SET IN LOWER ENTRY AND CLEAR IN UPPER => EXCHANGE ENTRIES
	MOVE D,.RPCNT(A)
	EXCH D,.RPCNT(B)
	MOVEM D,.RPCNT(A)
]
GCSRT4:	ADDI A,GCSWPS	;INCREMENT LOWER BOUND POINTER TO NEXT ENTRY
GCSRT5:	CAME A,B	;ANY MORE ENTRIES LEFT?
	 JRST GCSRT3	;YES, GO PROCESS THEM
		;A AND B NOW BOTH POINT TO FIRST ENTRY WITH BIT SET
	ROT C,-1	;ROTATE BIT INDICATOR TO NEXT (LESS SIGNIFICANT) BIT
	POP P,A		;RESTORE LOWER BOUND OF ENTIRE SORT
	JUMPL C,GCSRT6	;JUMP IF NO MORE KEY TO SORT ON
	PUSHJ P,GCSRT	;SORT BOTTOM PART OF TABLE
	HLRZ B,(P)	;RESTORE UPPER BOUND (SORT CLOBBERED A TO MIDDLE)
	PUSHJ P,GCSRT	;SORT TOP PART OF TABLE
GCSRT6:	ROT C,1		;BACK UP KEY AGAIN SO AS TOO "NOT CLOBBER C"
GCSRT7:	HLRZ A,(P)	;MAKE A POINT ABOVE TABLE ENTRIES SORTED
	RET

;SWEEP THE IMPURE STRING SPACE, DISCARDING GARBAGE BY MOVING THE GOOD STUFF DOWN.
GCSWP:	MOVE IN,QRBUF
	ADDI IN,EREND*5-INIQRB
	IDIVI IN,5	;IN GETS PLACE WE EXPECT NEXT OLD STRING (GARBAGE OR NOT) TO START.
	MOVE OUT,IN	;OUT GETS PLACE TO PUT NEXT NON-GARBAGE STRING.
	MOVE Q,GCPTR	;Q IS USED TO STEP THROUGH THE POINTER TABLE.
	SETZ BP,	;THERE IS NO PENDING BLT, YET.
;WHEN BP IS NONZERO, IT IS THE AC FOR A PENDING BLT.  WHEN WE SEE A NON-GARBAGE STRING,
;WE KNOW IT NEEDS TO BE BLT'ED (USUALLY), BUT WE DON'T DO THE BLT UNTIL WE COME
;TO SOME ACTUAL GARBAGE.  THAT WAY WE BLT CONTIGUOUS NON-GARBAGE STRINGS TOGETHER.
;INSTEAD OF BLT'ING, WE SET UP BP AS THE BLT AC (OLD START,,NEW START) AS A REMINDER.

;B CONTAINS CHAR ADDR PAST END OF LAST STRING PROCESSED.
	MOVE B,QRWRT

;COME HERE TO EXAMINE THE NEXT POINTER AND SEE WHETHER WE HAVE FOUND A GAP OF GARBAGE.
GCSWPL:	JUMPGE Q,GCBLT	;NO MORE POINTERS => FINISHED SWEEPING.  DO ANY PENDING BLT.
	MOVE A,(Q)	;WHERE DOES THE NEXT NON-GARBAGE STRING START?
	IDIVI A,5
	JUMPE BP,GCSWP2
	CAMG A,IN	;STARTS IN THE EXPECTED PLACE => IT IS CONTIGUOUS WITH
	 JRST GCSWP1	;PREVIOUS NON-GARBAGE, SO DON'T BLT NOW.
	CALL GCBLT	;NOT CONTIGUOUS => BETTER BLT THE OLD STUFF.
;HERE FOR THE BEGINNING OF A CONTIGUOUS RUN OF NON-GARBAGE;  SET BP NONZERO
GCSWP2:	MOVE IN,A
	HRRZ BP,OUT	;AND MAKE BP DESCRIBE HOW THIS STUFF WILL HAVE TO BE BLT'ED.
	HRL BP,A
GCSWP1:	SAVE BP		;NOW FIND OUT WHERE THIS STRING ENDS.
	SETZ B,		;B GETS (EVENTUALLY) LENGTH OF STRING-OBJECT
	MOVE BP,(Q)
	CALL GETBP	;WHICH IS IT?  A BUFFER OR A STRING?
	LDB CH,BP
	CAIN CH,QRBFR	;IF IT'S A BUFFER, THERE'S REALLY JUST A 4-CHAR HEADER HERE.
	 JRST GCSWP3
	CAIE CH,QRSTR	;IF IT'S A STRING, THERE'S THE HEADER PLUS DATA.
	 .VALUE
	CALL QLGET4	;HOW MUCH DATA?
GCSWP3:	ADDI B,3	;B GETS LENGTH OF HEADER + (DATA IF ANY) - 1.
	MOVE BP,(Q)
	ADDB BP,B	;BOTH B AND BP HAVE CHAR ADDR OF LAST CHAR.
	CALL GETBP	;BP GETS BP TO LDB LAST CHAR.
	MOVEI A,1(BP)	;A GETS ADDR OF WORD AFTER THE END OF THIS STRING.
	REST BP
	SUB A,IN	;NOW INCREASE IN TO EQUAL THAT, AND INCREASE OUT THE SAME AMOUNT.
	ADD IN,A	;NEW VALUE OF IN IS WHERE THE NEXT STRING SHOULD START IF IT IS CONTIG.
	ADD OUT,A	;ACTUALLY, IT CAN START IN THE PREVIOUS WORD IF IT IS REALLY CONTIG.
			;THE CAMG ABOVE WILL NOT SKIP IN EITHER CASE.
;NOW RELOCATE ALL THE POINTERS INTO THIS STRING.
;B IS CHAR ADDR REL QRBUF OF LAST CHAR OF STRING.
;ALL POINTERS LESS THAN OR EQUAL TO THAT POINT INTO THIS STRING.
	MOVE C,OUT
	SUB C,IN	;C GETS # OF WORDS (NEGATIVE ALWAYS) THIS STRING IS MOVING BY.
	MOVE D,C
	IMULI D,5	;D GETS # OF CHARACTERS.
GCSWPR:	CAMGE B,(Q)	;AFTER THE LAST POINTER INTO THIS STRING,
	 JRST GCSWPX	;GO EXAMINE THE NEXT AND MAYBE BLT THIS ONE, ETC.
	MOVE A,1(Q)
	SKIPL (A)	;ELSE RELOCATE.  RELOCATE POSITIVE QTYS (B.P.S) BY WORDS,
	 ADDM C,(A)
	SKIPGE (A)	;RELOCATE NEGATIVE ONES (TECO OBJECTS) BY CHARS.
	 ADDM D,(A)
	AOBJN Q,.+1
	AOBJN Q,GCSWPR	;LOOK AT ALL PTRS.  IF RUN OUT, DO ANY PENDING BLT AND WE'RE DONE.
GCSWPX:	ADD B,D		;B NOW HAS NEW CHAR ADDR OF LAST CHAR, NOT OLD CHAR ADDR.
	AOJA B,GCSWPL	;NOW IT HAS ADDR OF CHAR AFTER THE END.

;DO THE PENDING BLT DESCRIBED BY BP.  OUT, THE PLACE TO START THE NEXT GOOD STRING,
;TELLS US WHERE THE BLT SHOULD STOP.
GCBLT:	JUMPE BP,CPOPJ
	CAIN OUT,(BP)
	 .VALUE
	MOVS C,BP
	CAME C,BP	;DON'T DO THE BLT IF IT IS SHIFTING BY 0 WORDS.
	 BLT BP,-1(OUT)
	SETZ BP,
	RET

GCE5:	SKIPA IN,QRWRT
GCE:	 MOVE IN,QRBUF
GCE1:	MOVE CH,IN	;GC AGAIN AFTER GCOFTN CHARS
	ADDI CH,GCOFTN	;OF IMPURE STRING ARE CREATED.
	SKIPL GCNRLC
	 MOVEM CH,QRGCMX
	MOVE A,QRWRT		;REMEMBER OLD TOP OF IMPURE STRING SPACE FOR SAKE OF LOW BIT CLEARING.
	CAMGE A,IN		;GC PRODUCED NEGATIVE FREE SPACE?
	 .VALUE
	MOVEM IN,QRWRT		;CHAR ADDR ABOVE END OF STRING SPACE.
	ADDI IN,SLPQAM*2	;LEAVE 2*SLPQAM CHARS SPACE TO WRITE MORE STRINGS INTO,
	MOVE CH,IN
	ADDI CH,SLPQAM
	CAML CH,BFRBOT		;AND IF BUFFER SPACE STARTS AT LEAST SLPQAM ABOVE THAT POINT,
	 MOVE IN,BFRBOT		;MOVE IT DOWN TO THAT POINT.  ELSE DON'T MOVE IT.
	IDIVI IN,5
IFN ITS,[
	MOVE CH,QRWRT
	ADDI CH,2000*5-1	;COMPUTE 1ST PAGE IMPURE STRINGS DON'T NEED.
	IDIVI CH,2000*5
	LDB Q,[121000,,IN]	;AND 1ST PAGE BUFFER NEEDS.
	SUBM CH,Q		;-<# PAGES WE CAN FLUSH>
	JUMPE Q,GCE2
	SKIPL Q
	 .VALUE
	SAVE CH
	HRLI CH,(Q)		;AOBJN -> PAGES TO FLUSH.
	SYSCAL CORBLK,[%CLIMM,,0 ? %CLIMM,,%JSELF ? CH]
	 .LOSE %LSSYS
	REST CH
	IMULI CH,2000*5
	CAML A,CH		;BETTER NOT CLEAR LOW BITS IN THE PAGES WE JUST FLUSHED.
	 MOVE A,CH
GCE2:
]
	SAVE A
	MOVEI A,MFSTRT		;LOOK AT ALL BUFFER FRAMES,
GCE3:	MOVE T,MFBEG(A)	;AND RELEASE ALL THE DEAD ONES.
	TLNN T,MFBFR
	 JRST GCE4		;THIS IS A MACRO CALL, NOT A BUFFER.
	TLZN T,MFMARK
	 JRST [	CALL KILBFR	;THIS ONE IS DEAD.
		JRST GCE4]
	MOVEM T,MFBEG(A)	;CLEAR THE MARK-BIT.
GCE4:	ADDI A,MFBLEN
	CAMGE A,MFEND
	 JRST GCE3
	REST A
	IDIVI A,5
	CAML A,IN		;DON'T CLEAR LOW BITS IN CORE THAT BUFFERS WILL OCCUPY. 
	 MOVE A,IN
	MOVE T,QRWRT		;NOW, CLEAR LOW BITS BY CLEARING ALL OF THE EXISTING
	ADDI T,4		;CORE FROM THE TOP OF THE OCCUPIED PORTION OF
	IDIVI T,5		;IMPURE STRING SPACE UP TO BUFFER SPACE.
	CAMG A,T
	 JRST GCE7
	MOVE C,[SIXBIT /LBCLR/]
	MOVEM C,(T)		;STORE THIS RECOGNIZABLE CONSTANT TO CLEAR THE LOW BIT
	HRL T,T			;(FOR SAKE OF DEBUGGING).
	ADDI T,1
	CAIL A,1(T)
	 BLT T,-1(A)
GCE7:	MOVE T,BFRBOT		;C(IN) IS THE PLACE BUFFER SPACE
	IDIVI T,5		;SHOULD START; MOVE IT DOWN IF NEC.
	CAMG T,IN
	 JRST GCE6
	SUBM IN,T
	HRLS IN
	SUB IN,T
	MOVSS IN
	MOVE C,BFRTOP
	IDIVI C,5
	ADDI C,(T)
	BLT IN,(C)
	CALL BFRMVW
GCE6:	CALL FLSCOR
IFN ITS,.SUSET [.SWHO1,,[0]]
	JRST RSTACS

;PUSHJ HERE, AND IT RETURNS WITH ACS 0-16 SAVED.
IFN P-17,.ERR PDL POINTER NOT AC17
.SEE CIRC			;THIS DEPENDS ON THE ORDER OF THE AC'S
SAVACS:	ADD P,[16,,16]		;MAKE ROOM ON STACK FOR 1 THRU 16.
	MOVEM 1,-15(P)		;SAVE 1
	MOVEI 1,-14(P)
	HRLI 1,2
	BLT 1,(P)		;USE 1 TO SAVE THE REST
	MOVE 1,-15(P)		;RESTORE 1.
	SKIPL P
	 TYPRE [PDL]
	SAVE -16(P)		;PUT RETURN PC ON TOP OF STACK,
	MOVEM 0,-17(P)		;SAVE AC 0 IN ITS PLACE,
	RET

;JRST RSTACS TO UNDO A SAVACS, THEN POPJ OUT OF THE ROUTINE THAT CALLED THE SAVACS.
RSTACS:	MOVSI 16,-16(P)		;GET START OF WHERE THEY ARE
	HRRI 16,0
	BLT 16,16		;RESTORE THE REST
	SUB P,[17,,17]
	RET

RST321:	REST C			;JSP A,RST321 TO POP ACS 3 2 AND 1 OFF THE STACK
	REST B
	EXCH A,(P)
	RET

SUBTTL BUFFER SELECTION, CREATION AND KILLING

;A -> BUFFER FRAME; FREE THE FRAME AND THE SPACE IT POINTS TO.
;CLOBBERS C,E,T,TT.
KILBFR:	MOVSI C,MFREADO
	ANDCAM C,(A)	;MAKE READ-ONLY BUFFER WRITEABLE SO WE DON'T GET ERROR EMPTYING IT.
	MOVEI C,(A)
	SAVE BFRPTR
	CALL NEWBFR	;SELECT THAT BUFFER FRAME AS CURRENT.
	MOVE C,Z
	MOVE E,BEG
	CALL DELET1	;DELETE ALL THE TEXT IN IT.
	MOVEI C,5	;FAKE GAPKIL INTO CLOSING UP THE 1-WORD INTER-BUFFER
	ADDM C,EXTRAC	;GAP, AS WELL AS THE ACTUAL SPACE OCCUPIED BY THIS BFR.
	MOVNI C,5
	ADDM C,Z
	CALL GAPKIL	;FLUSH ALL SPACE IN BUFFER AREA USED BY THIS BUFFER.
	SETZM MFBEG(A)	;FREE THE BUFFER FRAME BY CLEARING MFBFR BIT
	SAVE A
	SOJ A,
	CALL FLSFRM	;AND PUTTING ON FREELIST (WHOSE POINTERS -> FRAME-1)
	REST A
	REST C		;NOW RESELECT THE BUFFER THAT WAS CURRENT AT CALL.
			;WITH OUT DESELECTING THE NOW-DEAD BUFFER
	JRST NEWBF1	;(THE IDEA IS TO AVOID SETTING ITS MFBFR BIT).

;C -> BUFFER FRAME; SELECT IT AS CURRENT. SETS UP BEG, ETC.
;CLOBBERS C,T,TT.
NEWBFR:	MOVE T,BFRPTR	;COPY BEG, ETC. BACK INTO THE FRAME
	MOVE TT,T	;THEY CAME FROM.
	HRLI T,BEG	;(THAT IS, THE ONE CEASING TO BE CURRENT)
	HLL C,MFBEG(TT)	;DON'T CLOBBER THE MFBFR AND MFMARK BITS.
	BLT T,MFEXTR(TT)
	HLLZ T,C	;WE SAVE THE BITS IN LH(C) TO AVOID USING ANY STACK.
	ANDI C,-1	;A PDL OV IN HERE WOULD BE HORRIBLE.
	AND T,[MFBBTS-MFMODIF-MFREADO-MFMODM,,]
	SKIPE MODIFF
	 TLO T,MFMODIF	;STORE MODIFF OF DESELECTED BUFFER AS A BIT.
	SKIPE MODIFM
	 TLO T,MFMODM	;STORE MODIFM ALSO.
	SKIPE READON
	 TLO T,MFREADO	;AND FS READ ONLY$
	IORM T,MFBEG(TT)
NEWBF1:	MOVEM C,BFRPTR	;REMEMBER WHICH FRAME NOW CURRENT.
	SKIPL T,(C)	;SELECTING A FRAME WHICH ISN'T A BUFFER?
	 .VALUE
	LDB TT,[.BP (MFREADO),T]
	MOVEM TT,READON	;RESTORE READONLY FLAG
	LDB TT,[.BP (MFMODM),T]
	MOVEM TT,MODIFM
	AND T,[MFMODIF,,]
	MOVEM T,MODIFF	;RESTORE THE MODIFF OF THE BUFFER BEING SELECTED.
	MOVSS C
	HRRI C,BEG
	BLT C,EXTRAC	;SET UP VARS FOR IT.
	MOVSI T,MFBBTS	;BUFFER FLAG BITS SHOULD BE IN MFBEG BUT NOT BEG.
	ANDCAM T,BEG
	RET

;<N>FSWORD$ RETURNS WORD OF BUFFER CONTAINING CHARACTER AFTER <N>
;<W>,<N>FSWORD$ ALSO SETS THAT WORD TO <W>. NOTE THAT NO WORD EVER
;CONTAINS PART OF 2 DIFFERENT BUFFERS, BECAUSE OF FSBCREATE$'S ALLOCATION POLICY.
FSWORD:	TRZN FF,FRARG
	 TYPRE [WNA]
	TRZE FF,FRARG2
	 IORI FF,FRARG	;2 ARGS => WRITING; ELSE READING.
	ADD C,BEG	;GET VIRT CHAR ADDRESS OF A CHAR IN DESIRED WORD.
	CALL CHK	;"NIB" IF OUTSIDE BUFFER BOUNDS.
	TRNN FF,FRARG	;WRITING IN FS WORD$ MODIFIES BUFFER CONTENTS.
	 JRST FSWRD1
	SKIPE READON	;ALLOWED TO MODIFY THIS BUFFER?
	 TYPRE [RDO]
	SETOM MODIFF
	SETOM MODIFM
FSWRD1:	CAML C,GPT	;CONVERT VIRTUAL ADDRESS TO REAL ADDRESS.
	 ADD C,EXTRAC
	IDIVI C,5	;GET ADDRESS OF WORD CONTAINING CHAR AFTER SPEC'D CHAR ADDR.
	MOVE E,C	;PUT ADDRESS OF FLAG-WORD IN E FOR FSNORM
	MOVE C,SARG	;AND VALUE TO STORE (IF ANY) IN C, THE ARGUMENT TO FSNORM.
	JRST FSNOR1	;NOW READ AND MAYBE WRITE THE BUFFER WORD.

BFRMVW:		IMULI T,5
BFRMOV:	MOVE TT,BFRBOT
	ADDM T,BFRBOT
	ADDM T,BEG
	ADDM T,BEGV
	ADDM T,PT
	ADDM T,GPT
	ADDM T,ZV
	ADDM T,Z
	JRST BFRRLC

;RELOCATE POINTERS INTO BUFFER SPACE WHEN PART OF IT MOVES.
;ALL POINTERS IN ALL BUFFER FRAMES ARE CHANGED IF THEY ARE
;LARGER THAN C(TT) WHICH IS PRESUMABLY THE CHAR ADDR AT WHICH
;SOMETHING GREW OR SHRANK. C(T) IS THE AMOUNT TO ADD TO EACH
;POINTER. DOES NOT RELOCATE BEG, BEGV, PT, GPT, ZV OR Z.
;BYTE POINTERS IN MACRO FRAMES, AND CPTR AND INSBP, ARE ALSO RELOCATED.
;CLOBBERS A,C. RELOCATES BFRTOP PROPERLY.
BFRRLC:	SKIPL @BFRPTR	;CURRENT BUFFER HEADER ISN'T A BUFFER HEADER?
	 .VALUE
	SAVE BP
	MOVE A,BFRTOP	;TO SAVE TIME, IF WE CAN FIGURE OUT THAT THE CHANGE
	SUBI A,5	;TOOK PLACE IN THE UPPERMOST BUFFER, THEN WE KNOW NO
	CAMLE TT,A	;BUFFER HAS TO BE RELOCATED.
	 JRST BFRRL3	;SO WE DON'T HAVE TO TEST THEM ALL.
	MOVEI A,MFSTRT	;SCAN ALL BUFFER FRAMES.
BFRRL1:	SKIPL C,MFBEG(A)	.SEE MFBFR
	 JRST BFRRL4	;THIS FRAME ISN'T A BUFFER FRAME.
	TLZ C,MFBBTS	;IT IS A BUFFER FRAME.
	CAME A,BFRPTR
	 CAMGE C,TT	;IS IT HIGH ENOUGH IN MEMORY TO BE RELOCATED?
	  JRST BFRRL2
INSIRP ADDM T(A),MFBEG MFBEGV MFPT MFGPT MFZV MFZ
	ADD C,T
	CAMGE C,BFRBOT	;BUFFER RELOCATED TO BELOW BUFFER SPACE?
	 .VALUE
BFRRL2:	ADDI A,MFBLEN
	CAMGE A,MFEND
	 JRST BFRRL1
BFRRL3:	MOVE BP,CPTR	;RELOCATE CPTR - MAYBE WE'RE EXECUTING OUT OF A BUFFER NOW.
	CALL BFRRL5
	 MOVEM BP,CPTR
	SKIPE INSINP
	 SKIPE INSBP
	  CAIA
	   .VALUE	;IN INSERT, AND INSBP ISN'T SAVING IT??
	MOVE BP,INSBP
	CALL BFRRL5
	 MOVEM BP,INSBP
	ADDM T,BFRTOP
	SKIPL @BFRPTR
	 .VALUE
POPBPJ:	REST BP
	RET

BFRRL4:	MOVE BP,MFCPTR(A) ;MACRO FRAME FOUND: IF THE CPTR POINTS AT A BUFFER,
	JUMPE BP,BFRRL2
	CALL BFRRL5	;RELOCATE IT IF THAT BUFFER IS MOVING.
	 MOVEM BP,MFCPTR(A)
	JRST BFRRL2

BFRRL5:	SAVE TT		;BP HAS A B.P.  EITHER RELOCATE IT, OR SKIP IF IT'S UNCHANGED.
	CALL GETCA
	REST TT
	CAMGE BP,BFRTOP
	 CAMGE BP,TT
	  JRST POPJ1	;IF WE SKIP, BP IS CLOBBERED, BUT CALLER SHOULD ASSUME UNCHANGED.
	ADD BP,T		;RELOCATE THE POINTER IF NEC.
	SAVE TT
	CALL GETBP
	REST TT
	RET

BFRSE2:	MOVEM B,PF	;SPECIAL ENTRY FROM FSQPUN
			;STORE BACK QREG PDL PTR; OTHERWISE ERROR QNB WOULD
			;CAUSE A LOOP DUE TO AUTOMATIC UNWIND.
;SELECT THE BUFFER IN THE Q-REG CH POINTS AT (PRESUMABLY ..O), PROVIDED IT IS LEGITIMATE.
;OTHERWISE, CLOBBER THE QREG BACK TO THE CURRENTLY SELECTED BUFFER.
BFRSE1:	SAVE C
	MOVE C,BFRSTR
	EXCH C,(CH)
	CALL BFRSET	;WHILE WE SELECT IT, KEEP THE OLD, GOOD BUFFER IN ..O.
	MOVEM C,(CH)	;THEN PUT NEW ONE BACK IN ..O WHEN ERROR CAN'T HAPPEN.
	JRST POPCJ

;ASSUME C HAS A STRING PTR TO A BUFFER'S POINTER STRING;
;MAKE THAT BUFFER CURRENT. CLOBBERS BP,T,TT.
BFRSET:	SAVE C
	SAVE CH
	SAVE B
	SAVE C
	CALL QBGET
	SKIPN C,B
	 TYPRE [QNB]	;SELECTING A KILLED BUFFER?
	REST BFRSTR
	REST B
	CALL NEWBFR
	REST CH
	JRST POPCJ

;C HAS STRING PTR TO PTR STRING OF BUFFER.
;RETURN IN B THE ADDR OF THE FRAME.
;RETURN IN CH A BP TO 1ST CHAR OF POINTER STRING.
;CLOBBERS BP,T,TT.
QBGET:	MOVE BP,C
QBGET2:	ADD BP,QRBUF
	TLZE BP,400000
	 CAML BP,QRWRT
	  TYPRE [QNB]
	CALL GETBP
	LDB CH,BP
	CAIE CH,QRBFR
	 TYPRE [QNB]
	MOVE CH,BP
	CALL QLGET4	;FORM NEXT 3 CHARS INTO NUMBER IN B
	ADDI B,4	;QLGET4 SUBTRACTS 4; WE MUST COMPENSATE.
	RET

;HERE TO DECODE A BUFFER POINTER IN BP, AND ALSO MAKE SURE, IN CASE IT IS THE
;SELECTED BUFFER, THAT THE WORDS IN THE BUFFER BLOCK ARE UP TO DATE.
QBGET1:	CAME BP,BFRSTR
	 JRST QBGET2
	SAVE C
	MOVE C,BFRPTR
	CALL NEWBFR
	REST C
	JRST QBGET2

;FS BCREATE$ -- CREATE A NEW BUFFER, AND MAKE IT CURRENT.
FSCRBF:	CALL FSCRB1
	MOVEI CH,$QBUFR	;ADDR OF QREG TO STORE IN.
	CALL QCLOSQ
	MOVEM OUT,BFRSTR ;SET INTERNAL Q..O AS WELL.
	MOVE C,A
	JRST NEWBFR	;SET PREDIGESTED Q..O (BFRPTR) AS WELL.

;FS BCONS$ -- RETURNS A NEWLY CREATED BUFFER.
FSBCON:	CALL FSCRB1
FSBCO1:	MOVEI CH,A
	CALL QCLOSQ
	JRST POPJ1

;FS QVECTOR$ -- RETURNS A QREG VECTOR BUFFER.
FSQVEC:	CALL FSCRB1
	MOVSI T,MFQVEC
	IORM T,(A)	;NOTE A -> BUFFER FRAME.
	JRST FSBCO1

FSCRB1:	TRZN FF,FRARG
	 SETZ C,	;C HAS # OF CHARS OF SPACE TO MAKE IN THE BUFFER.
	SAVE C		;(SPACE IS NOT INITIALIZED).
	MOVEI C,4
	CALL SLPQGT	;GET SPACE FOR POINTER-STRING.
			;NOW THE BUFFERS WON'T MOVE, SO WE CAN SET
			;UP THE POINTERS IN THE FRAME.
	CALL GETFRM	;OBTAIN FRAME FOR BUFFER; ADDR IN A.
	MOVEI A,1(A)	;GETFRM ACTUALLY GIVES ADDR OF FRAME MINUS 1.
	SETZM MFEXTR(A)
	MOVE C,BFRTOP	;PUT THIS NEW BUFFER AT TOP OF MEM.
INSIRP MOVEM C(A),MFBEGV MFPT MFGPT MFZV MFZ
	TLO C,MFBFR	;MARK THIS FRAME AS A BUFFER FRAME
	MOVEM C,MFBEG(A)
	TLZ C,MFBFR
	IDIVI C,5	;FIND WHICH WORD WE START IN
	HRLZ TT,C	;MAKE A BLT POINTER TO ZERO STARTING FROM THERE.
	HRRI TT,1(C)
	REST C		;HOW MUCH SPACE DO WE WANT?
	ADDM C,MFZV(A)	;INCLUDE IT IN THE BUFFER BY SETTING Z AND ZV.
	ADDB C,MFZ(A)
	IDIVI C,5	;WHICH WORD DO WE END IN?
	SETZM -1(TT)	;ZERO ALL THE SPACE, INCLUDING THAT WORD.
	CAIE C,-1(TT)
	 BLT TT,(C)
	IMULI C,5	;FIND THE NEXT WORD BOUNDARY, FOR NEW TOP OF BUFFER SPACE.
	ADDI C,5
	MOVEM C,BFRTOP	;EACH BUFFER GETS A WORD OF SPACE SO THEY'RE SEPARATED.
	MOVEI B,QRBFR	;NOW CREATE THE POINTER STRING IN SPACE ALREADY RESERVED.
	MOVE C,A	;IT SHOULD CONTAIN THE ADDR OF THE BUFFER FRAME.
	CALL QHDRW1
	MOVEI OUT,4
	ADD OUT,QRWRT
	RET

;FS BKILL$ -- TAKES ARG = STRING POINTER TO PTR STRING OF BUFFER,
;AND KILLS THAT BUFFER. THAT IS, THE BUFFER FRAME AND TEXT ARE FREED,
;AND THE PTR STRING IS CHANGED TO BE A DEAD BUFFER. IF NO ARG,
;[ ;DO " Q..O(]..O[A)UA QA-Q..O"NFSBKILL$' ]A ".
FSKILB:	TRZE FF,FRARG	;IF THERE'S AN ARG, USE IT.
	 JRST FSKIL1
	SAVE $QBUFR	;OTHERWISE, POP QREG PDL INTO Q..O,
	MOVEI CH,$QBUFR
	CALL CLOSB2
	REST C		;AND IF POPPED VALUE DIFFERS FROM PREV. CONTENTS,
	CAMN C,$QBUFR	;KILL THE PREVIOUS CONTENTS.
	 RET
FSKIL1:	SKIPN KILMOD
	 RET		;ALLOW THIS TO BE DISABLED FOR DEBUGGING.
	CALL QBGET	;GET ADDR OF FRAME IN B.
	CAMN B,BFRPTR
	 TYPRE [KCB]	;KILL A BUFFER WHILE IT'S SELECTED?
	SKIPN A,B
	 RET		;KILLING A DEAD BUFFER.
	SETZ Q,
	IDPB Q,CH	;STORE 0'S IN BUFFER-FRAME-ADDR IN PTR STRING.
	IDPB Q,CH
	IDPB Q,CH
	JRST KILBFR	;FREE FRAME AND TEXT.

;F[B BIND$ -- PUSH THE CURRENT BUFFER.  F]B BIND$ -- POP IT.
FSBBIN:	TRNN FF,FRARG
	 JRST FSBBI3	;NO ARG => MUST BE PUSHING.
	JUMPGE C,FSBBI3	;ARG IS POSITIVE => MUST BE SIZE OF BUFFER TO MAKE, SO WE'RE PUSHING.
	SAVE BFRSTR	;ARG => POPPING.  REMEMBER THE INNER BINDING BEING FLUSHED.
	MOVEM C,$QBUFR
	CALL BFRSET	;SELECT THE OLD BINDING (IN C)
	REST C		;KILL THE INNER BINDING AFTER THAT SUCCEEDS.
	JRST FSKIL1

FSBBI3:	TRO FF,FRARG
	CALL FSBCONS	;PUSHING THE SEARCH TABLE:  MAKE A NEW ONE,
	 JFCL
	SAVE BFRSTR	;SAVE THE OLD ONE TO RETURN, AND SELECT NEW ONE.
	MOVE C,A
	CALL BFRSET
	MOVEM A,$QBUFR
POPAJ1:	REST A		;THEN RETURN THE OLD ONE (TO GO ON QREG PDL).
	JRST POPJ1

;EMACS BUFFER SWITCH LOCAL VARIABLE SWAPPING

;<M>,<N>F^G<Q> - DO A LOCAL VARIABLE SWAP FOR THE EMACS BUFFER TABLE.
;<Q> IS THE BUFFER WHICH IS THE EMACS BUFFER TABLE.
;<M> IS THE WORD OFFSET (VIRTUAL) OF AN ENTRY IN IT.
;<N> IS THE POSITION WITHIN THAT ENTRY OF THE FIRST LOCAL VARIABLE.
;LOCAL VARIABLES FILL ALL THE REST OF THE ENTRY FROM THERE
; (THE TOTAL LENGTH OF THE ENTRY IS ITS FIRST WORD).
;EACH LOCAL VARIABLE TAKES TWO WORDS:
; THE FIRST IS THE NAME AS A STRING POINTER, OR THE :FSQPHOME$ OF A ^R COMMAND SLOT OR Q-REG,
; AND THE SECOND IS THE SWAPPED-OUT VALUE.

;@F^G ONLY STORES THE CURRENT VALUES INTO THE BUFFER TABLE.
;:F^G ONLY GETS NEW VALUES OUT OF THE BUFFER TABLE.

;NOTE: WE ASSUME THAT THE GAP IN THE BUFFER TABLE IS NOT IN THE MIDDLE OF THIS ENTRY!
;IT IS OK IF IT IS DIRECTLY IN FRONT OR BEHIND THE ENTRY.

FCTLG:	EXCH C,E	;HAHA I THOUGHT <M>,<N> PUT <M> IN C AND <N> IN E, SO MAKE IT THAT WAY.
	CALL QREGX	;READ QREG CONTAINING THE BUFFER TABLE.
	MOVE BP,A
	CALL QBGET1	;B GETS PTR TO BUFFER TABLE'S BUFFER FRAME.
	IMULI C,5	;C HAS CHARACTER POINTER TO START OF EMACS BUFFER'S ENTRY.
	ADD C,MFBEGV(B)
	CAML C,MFGPT(B)
	 ADD C,MFEXTR(B)
	IDIVI C,5	;C NOW HAS WORD ADDRESS OF START OF ENTRY.
	MOVE D,(C)	;D HAS LENGTH OF ENTRY.
	ADD C,E		;C NOW GETS POINTER TO FIRST LOCAL VARIABLE ENTRY.
	SUB D,E		;D HAS # OF WORDS LEFT (TWICE NUMBER OF LOCAL VARS).
	JUMPLE D,CPOPJ

;HACK THE NEXT LOCAL VAR.  C POINTS TO THE WORD IN THE BUFFER TABLE HOLDING ITS NAME.
;D HAS THE NUMBER OF WORDS OF LOCAL VARS LEFT TO HACK IN THIS BUFFER.
FCTLG1:	MOVE A,(C)
	CALL FCTLG2	;LOAD NAME OF NEXT LOCAL VAR INTO BAKTAB.
	 JRST FCTLG4	;IT ISN'T A STRING => IT IS ADDRESS IN RRMACT.
	MOVE IN,QRB..	;GET STRING POINTER TO SYMBOL TABLE.
	MOVE A,.QSYMT(IN)
	SAVE C
	SAVE D
	SAVE FF
	TRZ FF,FRCLN\FRUPRW\FRARG\FRARG2
	TRO FF,FRUPRW	;INSIST ON EXACT MATCH IN LOCAL VARIABLE NAME.
	CALL FOCMD3	;LOOK UP THAT VARIABLE IN THE SYMBOL TABLE.  IN GETS S.T.E. ADDRESS.
	 TYPRE [UVN]
	REST FF
	MOVEI CH,1(IN)	;CH GETS ADDR OF VALUE WORD IN S.T.E.
	MOVE IN,-1(P)	;IN GETS ADDR OF LOCAL VARIABLE ENTRY./
	MOVE D,(CH)	;BEGIN THE EXCHANGE,
	MOVE C,1(IN)
	TRNN FF,FRCLN	;COLON MEANS DON'T STORE IN THE BUFFER TABLE.
	 MOVEM D,1(IN)
	TRNN FF,FRUPRW	;ATSIGN MEANS DON'T SET THE VARIABLE.
	 CALL [	SKIPE VARMAC	;IF SETTING THE VAR CAN CALL A MACRO,
		 JRST USE3	;USE USE3 TO DO IT SO THAT THE MACRO GETS CALLED.
		MOVEM C,(CH)	;OTHERWISE JUST STORE.
		RET]
	REST D
	REST C
	JRST FCTLG6

FCTLG4:	MOVE IN,A	;HERE IF A LOCAL'S "NAME" ISN'T A STRING.
	CAIGE IN,RRMACT+1000	;IT SHOULD POINT INTO RRMACT OR AT A Q-REG.
	 CAIGE IN,RRMACT
	  CAIGE IN,QTAB+NQREG
	   CAIGE IN,QTAB
	    CAIA	;SKIP IF NOT THE ADDRESS OF A LEGITIMATE LOCAL Q-REGISTER.
	     JRST FCTLG5	;GO SWAP THE CONTENTS OF THAT WORD.
	TRNN IN,1
	 CAIL IN,FLAGSL*2	;IF IT ISN'T A LOCAL Q-REG, MAYBE IT'S AN FS FLAG.
	  TYPRE [ILN]	;THEY ARE REPRESENTED BY INDICES INTO THE TABLE FLAGS.
	SAVE C
	SAVE D
	MOVE B,IN	;GET ADDRESS OF FLAG ROUTINE, FOR FSFND.
	MOVE C,1(C)	;GET VALUE TO SWAP IN AS ARG TO FLAG ROUTINE.
	SAVE FF
	TRZ FF,FRCLN+FRARG+FRARG2
	TRZN FF,FRUPRW	;IF NO ATSIGN, SET THE FLAG.
	 TRO FF,FRARG
	CALL FSFND	;IN ANY CASE, CALL FLAG ROUTINE SO WE GET THE OLD VALUE
	 TYPRE [WNA]	;DIDN'T RETURN A VALUE
	REST FF
	REST D
	REST C
	TRNN FF,FRCLN	;WHICH, IF NO COLON, WE STORE IN THE BUFFER TABLE.
	 MOVEM A,1(C)
	JRST FCTLG6

FCTLG5:	MOVE CH,(IN)		;FETCH BOTH VALUES, TO EXCHANGE THEM.
	MOVE Q,1(C)
	TRNN FF,FRCLN		;IF NO COLON, STORE IN THE BUFFER TABLE.
	 MOVEM CH,1(C)
	TRNE FF,FRUPRW		;IF NO ATSIGN, SET THE Q-REG.
	 JRST FCTLG6
	MOVEM Q,(IN)
	CAIL IN,RRMACT
	 CAIL IN,RRMACT+1000
	  JRST FCTLG6
	MOVE CH,IN		;IF SETTING ^R CHAR DEFN TO A DIFFERENT VALUE,
	CAME CH,Q		;SET THE FLAG SAYING THIS CHAR HAS CHANGED.
	 CALL USE5
FCTLG6:	ADDI C,2	;MOVE PAST THIS LOCAL VAR AND DECREMENT COUNT OF REMAINING ONES.
	SUBI D,2
	JUMPG D,FCTLG1
	RET		;AFTER HACKING ALL LOCAL VARS, WE ARE DONE.

;GIVEN A STRING POINTER IN A, LOAD THE STRING INTO BAKTAB WITH J POINTING AT THE END.
;SKIPS UNLESS THE OBJECT IN A REALLY IS A STRING.
;CLOBBERS B,BP,CH,TT,TT1.
FCTLG2:	CALL QLGET0	;GET BP TO VAR NAME STRING IN BP AND LENGTH IN B.
	 RET
	MOVEI J,BAKTAB-1
	JUMPE B,POPJ1
FCTLG3:	ILDB CH,BP	;FETCH NEXT CHAR OF VARIABLE NAME STRING
	CAIL CH,"A+40	;CONVERT LETTERS TO UPPER CASE.
	 CAILE CH,"Z+40
	  CAIA
	   SUBI CH,40
	CAMN J,[LTABS,,BAKTAB+LTABS-1]
	 TYPRE [STL]
	PUSH J,CH	;AND STORE IN BAKTAB FOR OUR LOOKUP.
	SOJG B,FCTLG3
	JRST POPJ1

SUBTTL SEARCH COMMANDS

;GET ARGUMENTS TO SEARCH
GSARG:	TRZ FF,FRBACK	;CLEAR SOME FLAGS
	ARGDFL Z,	;GET ARGUMENT OR OPERATOR CONVERTED TO VALUE
	MOVMM C,SEARG	;STORE # OCCURRENCES TO LOOK FOR.
	JUMPL C,GSARGN	;J IF SEARCHING BACKWARDS.
	MOVE E,PT	;ELSE RANGE TO SEARCH IS PT TO ZV.
	MOVE C,ZV
GSARG2:	MOVEI B,SLP1I	;GET-CHAR RTN FOR MOVING FWD.
GSARG1:	HRRM B,SLP1P	;STORE GET CHAR RTN ADDR.
GSAPCH:	MOVE BP,E	;CHAR ADDR BOTTOM OF RANGE.
	CAML E,GPT	;IF CHAR ADDRESSED IS ABOVY RANGE, PT TO IT.
	 ADD BP,EXTRAC
	CALL GETBP
	MOVEM BP,BBP	;SAVE BP'S TO BOTTOM OF RANGE.
	MOVEM BP,BBP1
	MOVE BP,C	;MAKE PTR TO TOP OF RANGE:
	CAMG C,GPT	;IF IT IS BEYOND GAP,
	CAML E,GPT	;OR BOTTOM IS AT GAP,
	 ADD BP,EXTRAC	;RELOCATE TO PT ABOVE GAP,
	CALL GETBP
	MOVEM BP,ZBP
	MOVEM BP,ZBP1
	CAMGE E,GPT	;IS THE GAP WITHIN RANGE OF SEARCH?
	CAMG C,GPT
	 JRST GSARG7
	TRNN FF,FRBACK
	 JRST GSARG4
	MOVE BP,GPT	;IN BACKWARD SEARCH, MUST STOP AT GAP
	ADD BP,EXTRAC	;TO MOVE OVER IT.
	CALL GETBP
	MOVEM BP,BBP1
GSARG4:	MOVE BP,GPT	;FOR MOVING FWD OVER GAP,
	CALL GETBP
	MOVEM BP,ZBP1	;NEED BP TO START OF GAP.
GSARG7:	SUB E,BEG
	SUB C,BEG
	MOVEM E,SRCBEG	;REMEMBER RANGE SEARCHED, FOR ^B COMMAND.
	MOVEM C,SRCEND
	POPJ P,

GSARGN:	MOVE E,BEGV	;BACKWARDS, RANGE IS BEGV TO PT.
	MOVE C,PT
GSARG6:	TRO FF,FRBACK
	MOVEI B,SLP1D	;RTN TO GET CHARS BACKWARDS.
	SETZM PNCHFG	;NEVER READ FROM FILE IF BACKWARD SEARCH FAILS.
	JRST GSARG1

GSARGB:	TRZ FF,FRBACK	;BOUNDED SEARCH.
	MOVEI J,1	;GO ONLY ONCE.
	MOVEM J,SEARG
	TRNE FF,FRARG2
	CAMG E,C	;IF FB HAS 2 ARGS, IN REVERSE ORDER,
	 JRST GSARG5
	EXCH C,E	;THEN DO BACKWARDS BOUNDED SEARCH.
	CALL GETARG
	 CALL CHK1
	JRST GSARG6

GSARG5:	CALL GETARG	;GET RANGE IN C,E.
	 CALL CHK1
	JRST GSARG2

		;SEARCH COMMANDS

SERCHA:	HRRZM P,PNCHFG	;_ COMMAND. PNCHFG POSITIVE.
	CAIA
SERCHP:	 SETOM PNCHFG	;N COMMAND.  PNCHFG NEGATIVE.
	CAIA
SERCH:	 SETZM PNCHFG	;S COMMAND.  PNCHFG ZERO.
	CALL GSARG	;HANDLE ARG, SET UP DISPATCHES.
	JRST SERCH1

;FB -- BOUNDED SEARCH. ARGS LIKE K,T. (:FB IS LIKE :S, NOT :K).
FBCMD:	SAVE FF		;SAVE FRCLN.
	ANDCMI FF,FRCLN\FRUPRW
	CALL GSARGB	;GET RANGE OF BUFFER, SET UP DISPATCHES.
	SETZM PNCHFG
	REST A
	ANDI A,FRCLN\FRUPRW	;RESTORE: FLAG SO IT WILL SAY WHETHER TO RETURN A VALUE.
	IORI FF,(A)
SERCH1:	MOVEI CH,ALTMOD	;NOW TO CHOOSE A TEXT TERMINATOR, DEFAULT IS ALTMODE
	TRNE FF,FRUPRW	;UPARROW TYPED?
	CALL RCH	;YES, GET NEXT CHARACTER INSTEAD
	HRRM CH,INSDLM	;STORE AS DELIMITER
	MOVE E,SBFRP	;ADDRESS OF SEARCH BUFFER HEADER BLOCK.
	MOVE TT,MFZ(E)
	MOVE E,MFBEGV(E) ;CHAR ADDRS OF BEGINNING AND END OF SEARCH BUFFER.
	IDIVI E,5
	AOS E
	MOVEM E,STBLP	;WORD ADDRESS OF SEARCH BUFFER BODY, + 1 (START OF DATA)
	HRLM E,STBLPX
	IDIVI TT,5
	SUBM E,TT	;-<LENGTH OF SEARCH BUFFER, IN WORDS>
	HRLI E,-1(TT)	;AOBJN -> SEARCH BUFFER
	SETO D,		;SAY THERE ISN'T A CHAR TO BE REREAD.
	TRZE FF,FRUPRW
	 JRST SERCH2
	CALL RCH	;IF NOT AN @-TYPE ARG, CHECK FOR NULL ARG
	SKIPE SQUOTP
	 JRST SERCH3	;DON'T BE CONFUSED BY SUPERQUOTED ALTMODES.
	CAIN CH,ALTMOD	;WHICH MEANS REPEAT PREVIOUS SEARCH.
	 JRST SRLC
SERCH3:	MOVE D,CH	;ELSE CAUSE THE CHAR TO BE REREAD.
	TLZ D,4^5	;DON'T LET IT BE NEGATIVE.
	JRST SERCH2

;REPEAT THE PREVIOUS SEARCH. THE SEARCH BUFFER CONTAINS POINTERS INTO ITSELF.
;ALL THOSE POINTERS MUST BE RELOCATED IF THE SEAECH BUFFER HAS MOVED SINCE THE LAST
;TIME IT WAS USED. E -> BUFFER BODY BOTTOM. CLOBBERS E,D,TT.
SRLC:	SKIPN -1(E)	;DOES BUFFER SAY IT IS VALID?
	 TYPRE [SNR]
	HRRZ TT,(E)	;RH OF 1ST WORD OF TABLE SHOULD POINT TO 2ND.
	SUBI TT,1(E)	;SUBTRACT REAL ADDR OF 2ND, GIVES AMOUNT BUFFER HAS MOVED.
	MOVNS TT
	HRLZ TT1,TT	;WE MAY WANT TO RELOCATE LH'S AS WELL AS RH'S.
	JUMPE TT,SRN3	;DON'T BOTHER RELOCATING IF RLOC. AMOUNT IS 0.
SRLC1:	ADDM TT1,(E)	;LH OF EACH SUBSTRING HEADER IS A POINTER.
	HRRZ D,(E)
	CAIN D,SLP1P	;REACHED END OF TABLE?
	 JRST SRN3
	ADDM TT,(E)	;NO; RH IS ALSO A POINTER.
	HLRZ E,(E)	;FIND NEXT SUBSTRING.
	JRST SRLC1

;NOW COMPILE SEARCH TABLE 
SERCH2:	SETZM -1(E)	;WHILE WE SET UP STBL IT IS INVALID.
SCPL:	HRRZ C,E	;SAVE LOCATION OF BEGINNING OF BLOCK (LOOP POINT FOR CONTROL O)
	MOVEI CH,1(E)	;GET RIGHT HALF OF UPCOMING HEADER
	PUSHJ P,SDEP	;DEPOSIT IN TABLE
SCPL1:	TDZA A,A	;CLEAR INDEX AND FALL INTO LOOP
SCNOT:	TRC A,1		;CONTROL N, COMPLEMENT 1 BIT INDEX
	SKIPGE CH,D	;IF THERE'S A CHAR TO REREAD, USE IT.
	 CALL RCH	;ELSE GET NEXT CHARACTER.
	SETO D,		;FLUSH THE SAVED CHAR IF ANY.
	SKIPGE SQUOTP
	 JRST SCNSP	;SUPERQUOTED CHAR.
	SKIPE SQUOTP
	 JRST SCNDL	;DELIM-PROTECTED CHAR.
	CAMN CH,INSDLM	;IF TEXT TERMINATOR (RH MODIFIED),
	 JRST SCPX	;THEN DONE COMPILING, GO DO IT
SCNDL:	CAILE CH,^X
	 JRST SCNSP
	CAIN CH,^X	;IF CONTROL X (FOR "ANY CHARACTER"),
	 ADDI A,XSER	;THEN SET INDEX
	CAIN CH,^B	;IF CONTROL B (FOR BREAK CHARACTER)
	 ADDI A,BSER	;THEN SET INDEX
	CAIN CH,^S
	 ADDI A,SSER
	CAIN CH,^N	;IF CONTROL N (FOR "NOT")
	 JRST SCNOT	;THEN CLOBBER INDEX AND GET NEXT CHARACTER
	CAIN CH,^O	;IF CONTROL O ("OR"),
	 JRST SCPOR	;THEN GENERATE NEW HEADER
	CAIN CH,^Q	;IF CONTROL Q (QUOTES THE NEXT CHARACTER),
	 CALL RCH	;THEN REALLY USE NEXT CHARACTER, SKIPPING ABOVE TESTS
SCNSP:	SKIPE BOTHCA	;BOTHCASE=0 => CASES ARE DISTINCT.
	 TRNN CH,100	;BOTHCASE=1 => CASE IGNORED FOR LETTERS ONLY.
	  JRST SCNSP1	;BOTHCASE=-1 => CASE IGNORED FOR ALL CHARS > 100 .
	ANDI CH,-1	;SUPERQUOTED CHARS STIL GET CONVERTED.
	CAIL CH,"A+40	;IF IGNORING CASE FOR A CHARACTER, CONVERT IT TO
	 CAILE CH,"Z+40	;UPPER CASE HERE, ND ALSO WHIE SEARCHING THE BUFFER.
	  SKIPG BOTHCA
	   ANDCMI CH,40
SCNSP1:	TRNE A,-2	;IF INDEX CLOBBERED,
	 SKIPA CH,(A)	;THEN GET TABLE ENTRY
	  HLL CH,CHSER(A)	;INDEX NOT CLOBBERED OUT OF EXISTENCE, TURN INTO CAIE OR CAIN
	CALL SDEP	;DEPOSIT TABLE ENTRY
	CAME CH,SSER
	 CAMN CH,SSER+1	;IF IT WAS A ^S OR ^N^S ENTRY,
	  CALL [CALL RCH	;READ FOLLOWING CHAR AND DEPOSIT AS NEXT TABLE ENTRY.
		JRST SDEP]
	JRST SCPL1	;LOOP

SDEP:	MOVEM CH,(E)	;ADD AN ENTRY TO THE SEARCH TABLE
	AOBJN E,CPOPJ	;RETURN IF TABLE NOT FULL
	TYPRE [STL]

SCPX:	TDZA B,B	;TEXT TERMINATOR ENCOUNTERED
SCPOR:	MOVEI B,SCPL	;CONTROL O
	MOVE CH,[JRST WIN]	;SET FINAL TABLE ENTRY (EXECUTED => THIS STRING FOUND)
	CAIN C,-1(E)
	 HRRI CH,WINNL1	;BUT FOR NULL STRINGS, USE WINNL1 INSTEAD WIN.
	PUSHJ P,SDEP	;DEPOSIT
	HRLM E,(C)	;STORE POINTER TO THIS HEADER IN LH(LAST HEADER)
	JUMPN B,(B)	;JUMP IF NOT TEXT TERMINATOR
	MOVS A,STBLPX	;GET LIST CIRCULIZER/POINTER TO ROUTINE TO READ NEXT CHAR.
	MOVSM A,(E)	;STORE IN TABLE (THIS LAST ENTRY, DON'T INCREMENT E OR CHECK FOR OVERFLOW)
	SETOM -1(A)	;SEARCH TABLE NOW COMPILED.
	MOVEI E,1(E)
	IMULI E,5
	MOVE A,SBFRP
	MOVEM E,MFZV(A)	;ZV OF SEARCH BUFER POINTS TO END OF REGION BEING USED.
	JRST SRN3

		;TABLES FOR COMPILING SEARCH TABLE

XSER:	JFCL		;CONTROL X
	CAIA		;NOT CONTROL X

BSER:	PUSHJ P,SKNBRK	;CONTROL B
	PUSHJ P,SKBRK	;NOT CONTROL B

CHSER:	CAIN A,		;NORMAL CHARACTERS (HLL'ED WITH CHAR. IN RIGHT HALF)
	CAIE A,		;NOT CHAR.

SSER:	PUSHJ P,SKNLSY	;CONTROL S
	PUSHJ P,SKLSYN	;NOT CONTROL S.
			;THE FOLLOWING WORD OF SEARCH TABLE
			;WILL CONTAIN THE CHAR TO COMPARE THE SYNTAX WITH.

;SEARCH TABLE FORMAT

;FOLLOWING IS COMPILATION OF "SFOO SP()"
 ;EVERY WORD ASSEMBLED WITH ",," IS A SUBSTRING HEADER.

;STBLP POINTS HERE:
;TEM:	.+5,,.+1	;HEADER, LH POINTS TO NEXT COMPARISON STRING
		;RH POINTS TO TABLE THIS COMPARISON STRING
;	CAIN A,"F	;IF THE TEST IS TO SUCCEED THEN THE INSTRUCTION SHOULD NOT SKIP
;	CAIE A,"O	;THE CHARACTERS ARE IN A
;	CAIN A,"O
;	JRST WIN	;DOES JRST WIN IF ENTIRE STRING HAS BEEN FOUND
;	.+10,,.+1	;THIS LAST COMPARISON STRING BUT LH STILL POINTS SOMEWHERE
;	CAIN A,40
;	CAIE A,"S
;	CAIN A,"P
;	PUSHJ P,SKLSYN	;^N^S(   ARGS IN THE SEARCH TABLE MUST HAVE OPCODE 0!  SEE SLP1Z2.
;	  "(
;	PUSHJ P,SKBRK	;SKBRK => , SKNBRK => 
;	JFCL
;	CAIN A,")
;	JRST WIN
;	.+2,,.+1
;	JRST WINNL1
;	TEM,,SLP1P	;FINAL HEADER, LH POINTS TO FIRST HEADER MAKING LIST CIRCULAR
		;RH POINTS TO A JRA B,<ROUTINE TO GET NEXT CHARACTER>

;MAIN SEARCH LOOP

SLP2LC:	OFFSET 17-9-.
SLP2::
	LDB A,C		;GET CHARACTER
	XCT (B)	;COMPARE WITH FIRST CHARACTER THIS COMPARISON STRING
		;SKIP => THIS CHARACTER LOSES, TRY NEXT COMPARISON STRING
		;NO SKIP => THIS CHARACTER WINS, TRY NEXT ONE
		;WIN ON STRING => JRST WIN
		;THIS CHARACTER TOTALLY LOSES ON ALL COMPARISON STRINGS => EXECUTE SLP1P
			;^ => B := FIRST HEADER IN SEARCH TABLE
SLP2A::	SKIPA E,C	;WIN THIS CHARACTER, GET POINTER FOR CHECKING FUTURE CHARACTERS
	JRA B,.-2	;LOSE THIS COMPARISON STRING, TRY NEXT
SLP3::
	ILDB A,E	;GET NEXT CHARACTER
	XCT 1(B)	;EXECUTE NEXT TABLE ENTRY
	CAMN E,ZBP	;IT CLAIMS TO HAVE WON; WAS IT AT END OF BUFFER?
SLP4::	JRA B,SLP2	;LOSE, TRY NEXT COMPARISON STRING
	AOJA B,SLP3	;WIN THIS CHARACTER, TRY NEXT

IFN .-17,.ERR SLP2 WRONG TABLE LENGTH

	OFFSET 0

;FALLS THROUGH.
;ASSUMING THE SEARCH TABLE IS SET UP, DO THE SEARCHING.
SRN3:	TRZ FF,FRARG+FRARG2
	SETOB A,SFINDF	;A NULL SEARCH OR SEARCHING 0 TIMES SHOULD STATE THAT IT WON.
	SKIPE SEARG	;IF ARGUMENT ZERO, (ENTRY FOR "AGAIN" COMMAND)
	 JRST SRN2
	TRNE FF,FRCLN	;THEN WIN, DON'T BOTHER ACTUALLY SEARCHING.
	 JRST POPJ1	;RETURN -1 AS VALUE IF ONE IS WANTED.
	RET

;WE7RE FINISHED SETTING UP THE SEARCH TABLE AND BOUNDS.  NOW REALLY SEARCH.
SRN2:	CALL SKNBCP	;SET UP SKNBPT FROM Q..D, FOR SKNBRK'S SAKE.
IFN ITS,[
	MOVE TT,SBFRP		;GET LENGTH OF CONTENTS OF SEARCH BUFFER,
	MOVE TT,MFZV(TT)	;WHICH IS UPPER BOUND ON NUMBER OF CONSECUTIVE
	SUB TT,STBLP		;CHARACTERS WE MAY NEED TO EXAMINE AT ONCE.
	MOVE Q,SRCBEG		;TURN ON SEQUENTIAL PAGING.
	MOVE CH,SRCEND
	CALL SEQPGV
];ITS
	SETZM TEM2	;NO WINNING SEARCHES FOR SRCV TO DOCUMENT
	MOVE C,BBP	;GET PLACE TO START; NORMALLY LOW END
	TRNE FF,FRBACK
	 MOVE C,ZBP	;BUT HIGH END IF REVERSE.
;FOR SEARCH WITH REPEAT COUNT, REPETITIONS COME BACK HERE.
SRN2RP:	MOVE E,C	;INIT. BP TO END OF STRING IN CASE FIND NULL STRING.
	MOVS 16,[SLP2,,SLP2LC]	;GET POINTER FOR BLTING IN MAIN LOOP
	BLT 16,16	;BLT IN MAIN LOOP
	SKIPGE BOTHCA	;IN BOTH-CASES MODE,
	 MOVE SLP2,[JRST SLPLO1]
	SKIPGE BOTHCA	;IGNORE THE CASE OF THE CHARS SEARCHING.
	 MOVE SLP3,[JRST SLPLOW]
	SKIPLE BOTHCA	;BOTHCA POSITIVE => IGNORE CASE OF LETTERS ONLY.
	 MOVE SLP2,[JRST SLPLO3]
	SKIPLE BOTHCA
	 MOVE SLP3,[JRST SLPLO2]
	CALL IMMQIT	;IT'S OK TO QUIT OUT OF MIDDLE OF SEARCH.
	MOVE B,ZBP
	TRNN FF,FRBACK	;IF GAP IS IN THE RANGE
	CAMN B,ZBP1	;AND WE'RE STARTING BEFORE IT,
	 JRST SRN1
	MOVE SLP4,[JRST SLP1Z]	;TEMP. PTR ADVANCE
	HRRI SLP4-1,ZBP1	;WILL ENCOUNTER GAP BEFORE END.
	MOVEM SLP4,SLP4N
	MOVEM SLP4-1,SLP4N1
SRN1:	MOVE B,@STBLP	;INITIALIZE LIST POINTER
	HLRZ A,B
	TRNE FF,FRBACK	;IF BACKWARDS, ENTER NORMAL LOOP.
	 JRST WINNUL
	HRRZ A,(A)	;IF THERE IS ONLY ONE ALTERNATIVE IN THE SEARCH STRING
	CAIE A,SLP1P
	 JRST SRN5
	HLRZ A,(B)	;AND THE 1ST CHAR OF SEARCH STRING
	CAIE A,(CAIN A,)	;IS NOT A SPECIAL SEARCH CHARACTER,
	 JRST SRN5
	MOVEI A,SFAST	;THEN WE CAN GO FAST
	HRRM A,SLP1P	;USE THE GET-NEXT-CHAR ROUTINE THAT CAN SKIP FAST
	HRRZ A,(B)	;OVER UNINTERESTING REGIONS.
	MOVEI D,SFAFN0	;WHICH MAIN LOOP SHOULD WE USE?
	SKIPE BOTHCA	;SFAFC0 IGNORES THE 40 BIT; SFAFN0 DOESN'T.
	 CAIGE A,100	;IS THE 1ST CHAR ONE WHOSE CASE WE WANT TO IGNORE?
	  JRST SRN4	;NO.
	CAIL A,"A
	 CAILE A,"Z
	  SKIPG BOTHCA
	   MOVEI D,SFAFC0 ;YES.
SRN4:	MOVEM D,SFASAD	;TELL SFAST WHERE TO GO.
REPEAT 4,[ROT A,7	;GENERATE AN ASCII CONSTANT WITH 1ST CHAR OF SEARCH
	TRO A,@(B)	;REPEATED 5 TIMES.
]
	LSH A,1
	MOVEM A,SFXOR
SRN5:	CAMN C,ZBP
	 JRST WINNUL
	JRST SLP1K

;ROUTINE TO GET NEXT CHARACTER GOING FORWARD UNDER SPECIAL CIRCUMSTANCES.
;MAY SKIP FAST OVER MANY CHARACTERS BEFORE FINALLY STOPPING WITH A CHARACTER IT CAN'T
;QUICKLY RULE OUT.
SFAST:	TLNE C,760000
	 JRST SLP1I	;GO SLOW IF NOT STARTING NEW WORD.
	HRRZ A,ZBP1
	CAIN A,(C)	;OR IF NEAR GAP OR END OF RANGE
	 JRST SLP1I
	SUBM C,A
	HRL C,A		;AOBJN -> RANGE OF WORDS WE CAN SCAN FAST.
	JRST @SFASAD	;TO SFAFN0 OR SFAFC0.

;THIS IS THE SFAST MAIN LOOP THAT DOESN'T IGNORE THE 40 BIT OF THE CHARACTER.
SFAFNL:	MOVE A,(C)
	XOR A,SFXOR	;XOR NEXT WORD WITH ASCII/QQQQQ/ WHERE Q IS CHAR WE'RE LOOKING FOR.
	TLNN A,(177_35)	;IS 1ST CHAR OF WORD THE ONE WE WANT?
	 JRST SFAF1
	TLNN A,(177_26)	;OR THE 2ND?
	 JRST SFAF2
	TDNN A,[177_17]
	 JRST SFAF3
	TRNN A,177_10
	 JRST SFAF4
	TRNN A,177_1
	 JRST SFAF5
SFAFN0:	AOBJN C,SFAFNL	;NO NEED TO STOP IN THIS WORD; LOOK AT NEXT.
	HRLI C,350700	;APPROACHING GAP OR END OF RANGE; SLOW DOWN.
	JRST SLP1K	;ONLY THE SLOW ROUTINE KNOWS HOW TO HANDLE THEM.

;MAIN LOOP THAT IGNORES THE 40 BIT.
SFAFCL:	MOVE A,(C)
	XOR A,SFXOR
	TLNN A,(137_35)	;ONLY DIFFERENCE IS THAT EACH MASK OMITS THE 40 BIT.
	 JRST SFAF1
	TLNN A,(137_26)
	 JRST SFAF2
	TDNN A,[137_17]
	 JRST SFAF3
	TRNN A,137_10
	 JRST SFAF4
	TRNN A,137_1
	 JRST SFAF5
SFAFC0:	AOBJN C,SFAFCL	;NO NEED TO STOP IN THIS WORD; LOOK AT NEXT.
	HRLI C,350700	;APPROACHING GAP OR END OF RANGE; SLOW DOWN.
	JRST SLP1K	;ONLY THE SLOW ROUTINE KNOWS HOW TO HANDLE THEM.

SFAF1:	HRLI C,350700	;MUST EXAMINE 1ST CHAR THIS WORD - SO DROP INTO
	JRST SLP2A	;MAIN SEARCH LOOP.

SFAF2:	HRLI C,260700
	JRST SLP2A

SFAF3:	HRLI C,170700
	JRST SLP2A

SFAF4:	HRLI C,100700
	JRST SLP2A

SFAF5:	HRLI C,010700
	JRST SLP2A

;GET NEXT CHARACTER SEARCHING BACKWARDS

SLP1E:	MOVEM C,ZBP	;INITIALIZATION, SET CEILING FOR SEARCH
SLP1D:	CAMN C,BBP1	;AT BEGINNING OF BUFFER OR END OF GAP?
	 JRST SLP1F	;YES, FIGURE OUT WHICH.
	ADD C,[70000,,]	;NO, DECREMENT C,
	JUMPGE C,SLP2	;AND GO BACK INTO LOOP
	SUB C,[430000,,1]
	JRST SLP2

SLP1F:	CAMN C,BBP
	 JRST LOSE	;REALLY AT START OF RANGE, SEARCH FAILED.
	JRST SLP1G	;MOVED BACK TO GAP, GO OVER IT.

;GET NEXT CHARACTER SEARCHING FORWARDS

SLP1I:	IBP C		;INCREMENT TO NEXT CHARACTER
SLP1K:	CAME C,ZBP1	;AT START OF GAP OR END OF RANGE?
	 JRST SLP2	;NO, KEEP GOING
	CAMN C,ZBP	;WHICH ONE IS IT?
	 JRST LOSE	;IT'S END OF RANGE.
;MOVE OVER GAP TO GET NEXT CHARACTER
SLP1G:	INSIRP PUSH P,BP TT TT1
	MOVE BP,GPT	;COMPUTE A B.P. TO OTHER SIDE OF GAP.
	TRNE FF,FRBACK
	 AOSA BP		;BACKWARD => 1ST CHAR OF GAP,
	ADD BP,EXTRAC	;FWD => LAST CHAR OF GAP.
	CALL GETIBP
	MOVE C,BP
	MOVE BP,BBP	;ALREADY PASSED GAP SOLOOK FOR BNDRYS
	MOVEM BP,BBP1	;OF RANGE INSTEAD.
	MOVE BP,ZBP
	TRNN FF,FRBACK
	 MOVEM BP,ZBP1
	XORI SLP4-1,ZBP#ZBP1
	MOVEM SLP4-1,SLP4N1
	XOR SLP4,[<JRA B,SLP2>#<JRST SLP1Z>]
	MOVEM SLP4,SLP4N
INSIRP POP P,TT1 TT BP
	HRRZ A,SLP1P	;NOW WE'RE ACROSS GAP SO RETRY FETCHING NEXT CHAR.
	JRST (A)

;WHEN WE COME HERE, EITHER THIS ALTERNATIVE HAS FAILED
;OR WE HAVE MET THE GAP, ON A CHARACTER OTHER THAN THE FIRST ONE
;OF THE ALTERNATIVE.
SLP1Z:	XCT SLP4-1		;WHICH ONE?  IF NOT GAP YET, IT'S A SIMPLE FAILURE.
	 CAIA
	JRA B,SLP2
;WE HAVE MET THE GAP.  THE TEST OJUST DONE WAS INVALID SINCE
;IT WAS TESTING A RANDOM CHAR OF GAP, SO WE MUST DO IT OVER
;AFTER ADVANCING THE POINTER IN E OVER THE GAP.
;ALSO, FROM NOW ON, WE MUST TEST FOR REACHING Z RATHER THAN THE GAP.
;IF THIS ALTERNATIVE FAILS LATER ON, WE WILL BE BACKING UP TO BEFORE THE GAP,
;SO IN THAT CASE GO TO SLP1Z1 TO UNDO WHAT WE ARE DOING NOW.
	MOVE SLP4-1,[CAMN E,ZBP]	;FROM NOW ON, IN THIS ALTERNATIVE, TEST FOR Z.
	MOVE SLP4,[JRA B,SLP1Z1]
	INSIRP PUSH P,BP TT TT1
	MOVE BP,GPT		;ADVANCE POINTER PAST THE GAP.
	ADD BP,EXTRAC
	CALL GETIBP
	MOVE E,BP
SLP1Z2:	MOVE BP,1(B)		;BACK UP B OVER ARGUMENTS
	TLNN BP,777000		;TO THE LAST SEARCH PREDICATE
	 SOJA B,SLP1Z2		;SO WE RE-EXECUTE THE SEARCH PREDICATE.
INSIRP POP P,TT1 TT BP
	JRST SLP3		;FETCH THE CHAR AGAIN AND RETRY COMPARISON.

SLP1Z1:	MOVE SLP4-1,SLP4N1
	MOVE SLP4,SLP4N
	JRST SLP2

SLPLOW:	ILDB A,E	;COME HERE FROM SLP3 IN BOTHCASES MODE.
	CAIL A,140
	 SUBI A,40
	JRST SLP3+1

SLPLO1:	LDB A,C		;SIMILAR, FOR SLP2.
	CAIL A,140
	 SUBI A,40
	JRST SLP2+1

SLPLO2:	ILDB A,E	;COME HERE FROM SLP3 WHEN IGNORING CASE FOR LETTERS ONLY.
	CAIL A,"A+40
	 CAILE A,"Z+40
	  JRST SLP3+1
	 SUBI A,40
	JRST SLP3+1

SLPLO3:	LDB A,C		;SIMILAR, FOR SLP2.
	CAIL A,"A+40
	 CAILE A,"Z+40
	  JRST SLP2+1
	 SUBI A,40
	JRST SLP2+1

;HERE IF SEARCH FAILS TO FIND THE STRING.  EITHER READ NEXT PAGE, OR COMMAND HAS FAILED.
LOSE:
IFN ITS,CALL SEQPGX	;TURN OFF SEQUENTIAL PAGING USED DURING SEARCH.
	SKIPE PNCHFG	;IS IT AN N OR _ COMMAND?
	 SKIPL LASTPA	;IF SO, AND NOT AT EOF, TRY READING MORE FROM FILE.
	  JRST LOSE2	;OTHERWISE, SEARCH HAS REALLY FAILED.
	MOVEI C,1	;MAYBE PUNCH ONCE
	SETZM IMQUIT	;DON'T QUIT OUT OF I-O - MIGHT GARBLE FILE.
	TRZ FF,FRARG
	CALL [	SKIPGE PNCHFG	;PUNCH?
		 JRST PUNCHA	;YES
		JRST YANK]	;NO
	MOVE E,BEGV	;GET RANGE TO SEARCH = WHOLE BUFFER,
	MOVE C,ZV
	CALL GSAPCH	;SET BBP, ZBP.
	JRST SRN2	;SEARCH NEW BUFFER

LOSE2:	SETZM SFINDF	;SEARCH LOST, CLEAR FLAG FOR SEMICOLON
	PUSHJ P,SRCV	;SET PT (IF THIS WAS REPEATED SEARCH, MAYBE WE FOUND IT ONCE).
	TRZE FF,FRCLN	;IF COLON TYPED FOR SEARCH,
	 JRST NRET0	;THEN RETURN 0 AS VALUE
	MOVE TT,ITRPTR	;ARE WE WITHIN AN ITERATION?
	TSC TT,ITRPTR	;(BUT ERRSETS DON'T COUNT).
	TRNN TT,-1
	 SKIPE PSSAVP	;OR ARE WE WITHIN A ^P-SORT?
	  SKIPE SRCERR	;YES. IF SRCERR IS 0, INHIBIT THE ERROR.
	   TYPRE [SFL]
	RET

;SEARCHING STARTING AT END OF BUFFER, DON'T WIN FOR FORWARD NON-NULL SEARCH
WINNUL:	MOVE A,[JRST WINNL1]	;SET UP A AS CONSTANT FOR COMPARISON AGAINST MEMORY
WINNL2:	CAMN A,(B)	;IF AGREEMENT,
	 JRST WINNL1	;THEN NULL COMPARISON STRING, WIN, KIND OF
	CAME B,STBLPX	;IF THIS ISN'T LAST ENTRY IN TABLE,
	 JRA B,WINNL2	;THEN TRY NEXT ONE
	TRNN FF,FRBACK	;NO NON-NULL COMPARISON STRINGS, IF SEARCHING FORWARD,
	 JRST LOSE	;THEN LOSE
	JRA B,SLP1E	;SEARCHING BACKWARDS => RE-INITIALIZE LIST POINTER, FALL IN

WINNL1:	MOVE E,C	;NULL SEARCH STRING FOUND.
;ALL SUCCESSFUL SEARCHES COME HERE.
WIN:	MOVEM C,TEM1	;SAVE C, (BYTE POINTER TO FIRST CHARACTER IN FOUND STRING)
	MOVEM E,TEM2	;AND E, ( " TO LAST CHARACTER IN FOUND STRING)
	SOSLE SEARG	;THIS LAST SEARCH?
	 JRST WIN3	;NO, KEEP GOING
WIN1:
IFN ITS,CALL SEQPGX	;TURN OFF SEQUENTIAL PAGING USED DURING SEARCH.
	PUSHJ P,SRCV	;PICK UP THE PIECES (ENTRY FOR FOUND NULL STRING AT END OF BUFFER)
	TRZ B,-1	;YES, CHASE DOWN LIST LOOKING FOR THIS LIST POINTER
	MOVE C,@STBLP	;GET INITIAL POINTER
	MOVNI A,1	;INITIALIZE COUNT
WIN2:	TRZ C,-1	;CLEAR OUT RIGHT HALF OF THIS LIST ENTRY
	CAME C,B	;IS THIS THE ONE?
	 JRA C,[SOJA A,WIN2]	;NO, TRY NEXT
	MOVEM A,SFINDF	;STORE FS SVALUE$
	TRZE FF,FRCLN	;RETURN SFINDF AS VALUE IFF IT'S A ":S".
	 AOS (P)
	RET

;HERE TO SEARCH OVER AGAIN.  CLEAN UP FOR RE-ENTERING SEARCH LOOP.
WIN3:	TRNE FF,FRBACK
	 JRST WIN3R
	MOVE BP,E
	CALL GETCA	;BP GETS REAL CHAR ADDR CORRESPONDING TO END OF INSTANCE FOUND.
	MOVE C,ZBP	;IF FORWARD, THEN START FROM END OF THE INSTANCE WE JUST FOUND (IN E),
	CAMLE BP,GPT	;AND IF THAT MEANS SKIPPING OVER THE GAP, FIX UP ZBP1 TO MATCH ZBP.
	 MOVEM C,ZBP1
	MOVE C,E
	JRST SRN2RP

WIN3R:	MOVE E,ZBP	;IF BACKWARD, START FROM BEGINNING OF WHAT WE FOUND,
	MOVEM C,ZBP	;BUT PREVENT OVERLAP BY SETTING END OF RANGE TO THERE.
	MOVE BP,C
	CALL GETCA
	CAME E,ZBP1	;IF THE GAP WASN'T OR IS NO LONGER IN THE RANGE,
	 CAMGE BP,GPT
	  MOVEM C,ZBP1	;THEN ZBP1 SHOULD EQUAL ZBP.
	JRST SRN2RP

;PICK UP PIECES FROM SEARCH; COMPUTE NEW VALUE OF PT.

SRCV:	SETZM IMQUIT
	SKIPN BP,TEM2	;GET POINTER TO LAST CHARACTER IN FOUND STRING
	 JRST SRCVX	;NO WINNERS THIS BUFFER
	MOVE C,TEM1	;GET POINTER TO FIRST CHARACTER IN FOUND STRING
	TRNE FF,FRBACK	;IF SEARCH WAS BACKWARDS,
	 EXCH C,BP	;THEN REALLY WANT THEM INTERCHANGED
		;BP NOW HAS TECO'S . IN BYTE POINTER FORM
		;C HAS BYTE POINTER TO OTHER END OF STRING FOUND
	PUSHJ P,GETCA	;CONVERT BP TO CHARACTER ADDRESS
	EXCH BP,C	;GET OTHER BYTE POINTER IN BP
	PUSHJ P,GETCA	;CONVERT TO CHARACTER ADDRESS
	CAMLE C,GPT	;CONVERT CHAR ADDR OF END TO VIRTUAL,
	 SUB C,EXTRAC
	CAMLE BP,GPT	;CONVERT CHAR ADDR OF END TO VIRTUAL.
	 SUB BP,EXTRAC
	SUB BP,C		;DIFFERENCE = LENGTH OF LAST SEARCH STRING FOUND.
	MOVEM C,PT	;GO THERE.
SRCVX:	MOVNM BP,INSLEN	;STORE SIGNED LENGTH OF LAST SEARCH STRING FOUND
		;SIGN OF LLSSF IS OPPOSITE THAT OF ARG TO SEARCH FROM WHICH IT WAS SET
	POPJ P,

FKCMD:	MOVN A,INSLEN	;"FK" -<LENGTH OF LAST STRING FOUND OR INSERTED>
	JRST POPJ1

;FS S STRING$ - READ OR SET THE DEFAULT SEARCH STRING.
FSSSTR:	CALL FSSSTV	;FIRST, CONS UP A STRING CONTAINING THE OLD VALUE.
	TRZE FF,FRARG	;THEN, IF WE HAVE AN ARG, SET THE DEFAULT FROM IT:
	 CAMN C,[-1]	;ARG OF -1 MEANS "INVALID SEARCH STRING";  JUST DON'T SET.
	  JRST POPJ1
	JSP T,GCPUSA	;MUST SET.  PUSH VALUE TO RETURN WHERE GC WILL RELOCATE IT.
	MOVEI A,[ASCIZ /[0 U0 0@S|0| ]0/]
	SAVE SFINDF
	CALL MACXCP	;SET SEARCH STRING DEFAULT BY PASSING ARG TO AN S COMMAND.
	REST SFINDF
;POP A GCPUSA'D VALUE AND RETURN IT AS COMMAND'S VALUE.
GCPOPV:	REST LEV
	SUB P,[1,,1]
	JRST POPAJ1

GCPUSA:	SAVE A		;PUSH THE VALUE IN A AND ARRANGE FOR GC TO RELOCATE IT
	SAVE [0]	;WHILE IT IS ON THE STACK.  THIS IS DONE BY MAKING
	SAVE LEV	;IT LOOK LIKE A "(" BLOCK.
	MOVEM P,LEV
	JRST (T)

;RETURN IN A A STRING CONTAINING THE CURRENT DEFAULT SEARCH STRING.  PRESERVE C.
FSSSTV:	MOVE E,SBFRP
	MOVE CH,MFZV(E)
	MOVE E,MFBEGV(E)
	IDIVI E,5	;GET WORD ADDR'S OF START AND END OF SEARCH TABLE.
	IDIVI CH,5
	AOS E		;SKIP OVER THE VALID-WORD AT THE START.
	SETO A,
	SKIPN -1(E)	;BUT IF THE TABLE'S CONTENTS AREN'T VALID, RETURN -1.
	 POPJ P,
	SAVE C		;ELSE WE'LL RETURN A STRING.  WHAT'S A BOUND ON LENGTH WE NEED?
	SAVE [POPCJ]
	MOVE C,CH
	SUB C,E		;TWICE LENGTH OF SEARCH TABLE IS ENOUGH.
	LSH C,1
	CALL QOPEN	;ALLOCATE THAT SPACE, SET UP LISTF5 TO STORE INTO STRING.
	AOS E		;SKIP THE FIRST POINTER-PAIR IN THE SEARCH TABLE.
FSSSTL:	SETZ B,		;WE ARE NOT JUST AFTER A ^S OR ^N^S.
FSSST5:	SETZ C,
	HLRZ TT,(E)	;GET LH AND RH OF NEXT SEARCH TABLE WORD.
	HRRZ TT1,(E)
	CAIN TT1,SLP1P	;SLP1P IN RH IDENTIFIES END OF SEARCH TABLE
	 JRST QCLOSV	;SO FINISH UP THE STRING'S HEADER AND RETURN IT.
	CAIL TT1,HUSED	;AN RH THAT'S AN ADDRESS IN BUFFER SPACE
	 JRST [	MOVEI CH,^O	;INDICATES A DIVISION BETWEEN ALTERNATIVE STRINGS,
		JRST FSSST2]	;SO WE NEED A ^O FOR IT.
	CAIN TT,(JRST)	;JRST INSN MUST BE JRST WIN OR WINNUL, WHICH IS AT THE END OF
	 AOJA E,FSSSTL	;EVERY ALTERNATIVE.  IT CORRESPONDS TO NO CHAR IN USER'S ARG.
	CAIN TT,(JFCL)
	 MOVSI C,(ASCII //)	;JFCL IS GENERATED BY A ^X.
	CAIN TT,(CAIA)
	 MOVSI C,(ASCII //)	;CAIA COMES FROM A ^N^X.
	CAIN TT1,SKNBRK
	 MOVSI C,(ASCII //)	;CALL SKNBRK COMES FROM ^B.
	CAIN TT1,SKBRK
	 MOVSI C,(ASCII //)	;CALL SKBRK COMES FROM ^N^B.
	CAIN TT1,SKNLSY
	 MOVSI C,(ASCII //)	;CALL SKNLSY COMES FROM ^S
	CAIN TT1,SKLSYN
	 MOVSI C,(ASCII //)	;CALL SKLSYN COMES FROM ^N^S.
	JUMPE C,FSSST1		;ANYTHING ELSE MUST BE ORDINARY, OR A ^N.
;HERE FOR SPECIAL SEARCH CHARACTER.
	SETZ B,
	CAIE TT1,SKNLSY		;SET FLAG FOR NEXT CHAR: B IS -1
	 CAIN TT1,SKLSYN	;IF NEXT CHAR IS FOLLOWING A ^S.
	  SETO B,
	MOVEI A,C
	CALL ASCIND		;OUTPUT THE SPECIAL CHAR, WITH ITS ^N IF APPRO.
	AOJA E,FSSST5

FSSST1:	JUMPL B,FSSST6		;THE CHAR AFTER A ^S SHOULDN'T GET ^N OR ^Q.
	MOVEI CH,^N
	CAIN TT,(CAIE A,)	;DECIDE BETWEEN ORDINARY CHAR AND ^N'D CHARACTER.
	 XCT LISTF5
	MOVEI CH,^Q	;IF CHAR IS ONE THAT WOULD BE SPECIAL, MUST QUOTE IT.
	CAIE TT1,^B
	 CAIN TT1,^X
	  XCT LISTF5
	CAIE TT1,^Q
	 CAIN TT1,^O
	  XCT LISTF5
	CAIE TT1,^S
	 CAIN TT1,^N
	  XCT LISTF5
FSSST6:	MOVE CH,TT1	;[
	CAIN CH,^]
	 XCT LISTF5	;[   ;^] HAS ITS OWN WAY TO BE QUOTED.
FSSST2:	XCT LISTF5
	AOJA E,FSSSTL

SUBTTL ..D DELIMITER DISPATCH USAGE

;SKNBRK SKIPS UNLESS THE CHARACTER IN A IS A DELIMITER CHARACTER.
;THE SET OF DELIMITERS IS DEFINED BY THE CONTENTS OF QREG ..D,
;WHICH SHOULD BE A STRING CONTAINING 5*128. CHARACTERS, FORMING A
;DISPATCH TABLE. EACH ASCII CHAR HAS A 5-CHAR DISPATCH ENTRY WHOSE
;FIRST TWO CHARACTERS ONLY ARE SIGNIFICANT.
;THE FIRST CHARACTER IS THE MOST GENERAL: IF IT IS NOT A SPACE, THEN
;THE CHARACTER WHOSE ENTRY IT IS IS NOT A DELIMITER.
;INITIALLY ALL NON-SQUOZE CHARACTERS ARE DELIMITERS.
;THE SECOND CHARACTER SAYS HOW LISP HANDLES THE CHAR BEING HANDLED.
;THE POSSIBLE DISPATCH CHARS ARE "(", ")", "/", "|", "A" AND " ".
;SKNBRK ASSUMES THAT SKNBPT HAS BEEN SET UP BY SKNBCP ALREADY.
;CLOBBERS D.
SKNBRK:	LDB D,SKNBPT
	CAIN D,"A
	 AOS (P)
	RET

DQT3:	CALL SKNBCP	;SKIP IF CHAR IN C IS DELIMITER; RECOMPUTES SKNBPT.
	MOVE A,C
SKBRK:	LDB D,SKNBPT	;SKIP IF CHAR IN A IS DELIM. SKNBCP SHOULD HAVE BEEN CALLED.
	CAIE D,"A
	 AOS (P)
	RET

;LOOK AT QREG ..D, AND SET UP SKNBPT FOR USE BY SKNBRK.
SKNBCP:	MOVE CH,QRB..
	ADDI CH,.QDLIM
	CALL QLGET	;BP _ BP TO TEXT.
	 TYPRE [QNS]
	CAIGE B,5*200	;NOT LONG ENOUGH => ERROR.
	 TYPRE [STS]
	IBP BP		;BP HAS BP TO LDB 1ST CHAR.
	TLO BP,A	;LDB BP TO GET DISPATCH OF CHAR IN A.
	MOVEM BP,SKNBPT
	RET

;SKIP IF LISP SYNTAX OF CHAR DOESN'T MATCH FOLLOWING WORD OF SEARCH TABLE.
SKNLSY:	MOVE D,(P)		;GET OUR RETURN ADDRESS.
	AOS B			;GO INDIRECT THRU THE XCT THAT POINTED AT
	PUSH P,@-1(D)		;THE CALL TO THIS INSN, TO FIND THE SYNTAX CHAR.
	MOVE D,SKNBPT		;THEN GET THE SYNTAX OF THE BUFFER CHAR IN CH.
	IBP D
	LDB D,D
	CAME D,(P)
	 AOS -1(P)
	SUB P,[1,,1]
	RET

;SKIP IF LISP SYNTAX OF CHAR MATCHES FOLLOWING WORD OF SEARCH TABLE.
SKLSYN:	MOVE D,(P)		;GET OUR RETURN ADDRESS.
	AOS B			;GO INDIRECT THRU THE XCT THAT POINTED AT
	PUSH P,@-1(D)		;THE CALL TO THIS INSN, TO FIND THE SYNTAX CHAR.
	MOVE D,SKNBPT		;THEN GET THE SYNTAX OF THE BUFFER CHAR IN CH.
	IBP D
	LDB D,D
	CAMN D,(P)
	 AOS -1(P)
	SUB P,[1,,1]
	RET

;; ^B COMMAND:  GO TO BEGINNING OF BUFFER IF LAST SEARCH WAS BACKWARD AND FAILED,
;; OR TO END IF LAST SEARCH WAS FORWARD AND FAILED.  SET FS INSLEN$ TO 0 EITHER WAY.
;; IF LAST SEARCH SUCCEEDED, DON'T MOVE, AND DON'T CHANGE FS INSLEN$.
;; WITH COLON FLAG, IF SEARCH WAS SUCCESSFUL DO FKC.
CTLB:	TRZ FF,FRARG\FRARG2
	MOVN C,INSLEN
	SKIPE SFINDF
	 JRST [	TRZE FF,FRCLN
		 JRST REVER1
		RET]
	SETZM INSLEN
	HRRZ A,SLP1P
	CAIE A,SLP1D	;WAS LAST SEARCH FORWARD?
	 SKIPA A,SRCEND	;IF SO, GO TO END
	  MOVE A,SRCBEG	;ELSE GO TO BEGINNING.
	ADD A,BEG
	MOVEM A,PT
	RET

SUBTTL F AND FS COMMAND DISPATCH

;F-COMMAND SUBDISPATCH.
FCMD:	PUSHJ P,LRCH
	XCT FDTB(CH)
	 POPJ P,
	JRST POPJ1

;FS COMMAND.
FSET:	MOVE B,[440600,,D]
	MOVE E,[440600,,J]
	SETO BP,
	SETZB D,J
;D GETS THE SPEC'D NAME; J GETS MASK TO THOSE CHARS IN THE WORD WHICH WERE SPEC'D.
FSLUP:	CALL RCH
	ANDI CH,-1
	TRNE CH,100
	 ANDCMI CH,40	;CONVERT TO LOWER CASE.
	CAILE CH,40
	 JRST FSCHAR	;NON-CONTROLS ARE FOR REAL.
	CAIN CH,ALTMOD
	 SKIPGE SQUOTP	;ALTMODE ENDS NAME UNLESS SUPERQUOTED.
	  CAIA		;OTHERWISE, ^X IS TREATED AS IF IT WERE AN UPARROW AND AN X.
	   JRST FSLKUP
	MOVEI TT,'^
	CAIE CH,40	;SPACE, UNLIKE CTL CHARS, IS JUST IGNORED.
	 TLNN B,770000	;CTL CHARS ALSO IGNORED IF ALREADY HAVE 6 CHARS.
	  JRST FSLUP
	IDPB TT,B
	IDPB BP,E

FSCHAR:	HRREI CH,-40(CH) ;GET SIXBIT, IGNORING LH SINCE MIGHT BE -1
	TLNE B,770000	 ;[  ;IF THE CHAR WAS QUOTED WITH ^]^Q
	 IDPB CH,B
	TLNE E,770000
	 IDPB BP,E
	JRST FSLUP

FSLKUP:	MOVE B,[-FLAGSL*2,,FLAGS]

;BINARY SEARCH IN VECTOR OF FLAGS <- AOBJN IN B
;FOR VALUE IN D.  CLOBBERS B,E,TT.
FSLUKB:	HLRE E,B
	HRLI B,E	;B IS INDEX OF E.
	MOVNS TT,E
;B -> INSIDE AREA, IDX OF E.
;E = SIZE OF LAST STEP.
;TT = # WDS LEFT IN PART OF AREA AFTER B.
;LEAVES B POINTING TO LAST FLAG WHOSE NAME IS < DESIRED NAME
;(NOTE: IF ALL FLAGS ARE >= DESIRED NAME, B -> 1ST FLAG).
;THEN GOES TO FSLUK1.
FSLUK0:	CAILE E,(TT)	;E_MAX(LAST STEP,SPACE LEFT)
	 MOVEI E,(TT)
	CAIN E,2	;ONLY 1 ENTRY TO SEARCH THRU => DONE.
	 JRST FSLUK1
	LSH E,-1	;STEP = .5* SIZE OF STUFF TO SEARCH.
	TRZE E,1	;ROUND UP TO EVEN NUMBER.
	 ADDI E,2
	CAMG D,@B	;E.A. IS RH(B)+STEP.
	 JRST FSLUK0	 ;THAT'S TOO FAR, DON'T MOVE B.
	HRRI B,@B	;NOT TOO FAR, SET PTR THERE.
	SUBI TT,(E)	;WE'RE CLOSER TO END NOW.
	JRST FSLUK0

FSLUK1:	CAMLE D,(B)	;(THIS PREVENTS LOSSAGE IF SUPPOSED TO FIND 1ST FLAG IN TABLE)
	 ADDI B,2
	MOVEI B,-FLAGS(B)	;POINT TO 1ST FLAG GREATER THAN OR EQUAL TO DESIRED.
	MOVE E,FLAGS(B)
	AND E,J		;IF THIS FLAG DOESN'T MATCH SPEC'D NAME, NONE DOES.
	CAME D,E
	 TYPRE [IFN]
	CAMN D,FLAGS(B) ;EXACT MATCH IS NEVER CONSIDERED AMBIGUOUS.
	 JRST FSFND
	MOVE E,FLAGS+2(B) ;ELSE, DOES THE NEXT FLAG AFTER THE ONE FOUND
	AND E,J		;ALSO MATCH THE SPECIFIED NAME?
	CAMN D,E
	 TYPRE [AFN]	;YES - SPEC'D NAME IS AMBIGUOUS.
FSFND:	MOVS E,FLAGD(B)
	HRLM B,(P)
FSCALL:	CALL (E)	;SOME ROUTINES WILL DEPOSIT IN -1(P)! THEY ALL CREF FSCALL.
	 RET		;(THEIR GOAL IS TO FAKE OUT FPUSH VIA THE INSN AT .+1)
	HLRZ E,(P)	;FOR FLAGS THAT RETURN VALUE, MAKE SURE INDEX OF FLAG IS
	JRST POPJ1	;IN E, FOR FPUSH TO WORK.

SUBTTL FS FLAG ROUTINES

;[   ;F]<FLAGNAME>$ POPS QREG PDL INTO THAT FLAG.
;[   ;<CH>F]^RCMAC$ WORKS, ETC.
FPOP:	MOVEI CH,E	;CH HAS ADDR TO POP INTO.
	CALL CLOSB2
	TRON FF,FRARG
	 SKIPA C,E	;MAKE POPPED VALUE COME BEFORE ANY SPEC'D ARG.
	  TRO FF,FRARG2
	CALL FSET	;SET THE FLAG, RETURNING THE OLD VALUE OF THE FLAG.
	 JFCL
	RET		;RETURN NO VALUE.

;F[<FLAGNAME>$ PUSHES THAT FLAG ONTO THE QREG PDL.
;<CH>F[^RCMAC$, ETC., WORK.		;]]
FPUSH:	MOVE B,PF	;IF WE ARE ABOUT TO OVERFLOW QREG PDL, DETECT THAT
	CAMN B,PFTOP	;BEFORE SETTING THE FLAG.
	 JRST OPENB1
	CALL FSET	;DO FS<FLAG>$, WHICH LEAVES INDEX IN FLAGD IN E.
	 TYPRE [WNA]	;FLAG HAS NO VALUE, AND YOU WANT TO PUSH IT??
	TRNE FF,FRARG2	;BARF IF TRY TO PUSH FS BOUNDARIES$, SINCE IT DOESN'T WIN.
	 TYPRE [WNA]
	MOVEI CH,A
	CALL OPENB2	;PUSH THE VALUE FROM A, WHERE FSET LEFT IT,
	MOVEM E,(B)	;THEN SET "WHERE PUSHED FROM" FIELD TO THE INDEX OF THIS
			;FLAG IN THE FLAGS TABLE,
			;THUS TELLING AUTO-UNWIND TO POP THE FLAG BY DOING FPOP.
	RET

;HERE ARE THE COMMONLY USED FS FLAG ROUTINES.

IFN ITS,FSNQIT:: FSDIRH::
IFN TNX,FSFVER::
FSNORM:	HLRZS E		;HERE TO READ/SET NORMAL FLAG;  E -> WORD HOLDING VALUE.
FSNOR1:	MOVE A,(E)
FSNOR2:	ARGDFL
	TRZN FF,FRARG
	 JRST POPJ1
	MOVEM C,(E)
	CAIE E,CASNRM	;IF SET CASNRM, ALSO SET CASDIS.
	 JRST POPJ1
	ANDI C,1
	MOVEM C,CASDIS
	JRST POPJ1

FSVAL:	HLRZ A,E	;HERE TO RETURN CONSTANT VALUE (AS FOR FS VERSIO$)
	JRST POPJ1

IFN ITS,[
FSRSYS:	HRRI E,A	;HERE TO READ A PARTICULAR .SUSET VAR (AS FOR FS OPTION$)
	.SUSET E
	JRST POPJ1

FSOPTL:	.SUSET [.ROPTIO,,B]	;READ BIT IN LH OF .OPTION.  C SAYS WHICH BIT.
	JRST FSBIT1
]

FSRNLY:	MOVE A,E	;READ-ONLY FLAG'S ADDR IN LH(E)
	JRA A,POPJ1

FSROCA:	MOVE A,E	;READ ONLY CHAR. ADDR, RETURN RELATIVE TO BEG.
	JRA A,FSROC1

FSWBIT:	ARGDFL
	HRRI E,FF	;HERE IF WE WANT TO BE ABLE TO WRITE A BIT AS WELL AS READ IT.
	MOVE B,FF	;LH(E) HAS B.P. L.H., AND WE ASSUME THE BIT IS IN FF.
	SKIPE C		;WE MUST SAVE THE OLD FF SO WE CAN RETURN THE OLD SETTING OF THE BIT.
	 SETO C,	;ANY NONZERO ARG MEANS TURN THE BIT TO 1.
	TRNE FF,FRARG
	 DPB C,E
	CAMN E,[.BP FRTRACE]
	 CALL QUEST1	;IF THE BIT JUST CHANGED IS FRTRACE, SET TRACS TOO.
	JRST FSBIT1

FSBIT:	SKIPA B,FF	;LH(E) HAS B.P. L.H., TO FETCH BIT IN FF.
FSTTOL:	 HLLZ B,TTYOPT	;TEST BIT IN LH(TTYOPT).
FSBIT1:	HRRI E,B
	LDB E,E		;FETCH THE DESIRED BIT.
	SKIPN E
NRET0:	 TDZA A,A	;VALUE IS 0 IF BIT CLEAR,
NRETM1:	  SETO A,	;-1 IF SET.
	JRST POPJ1

;ALTCOUNT FLAG, # COMMAND STRINGS TYPED AHEAD BY USER.
FSALTC:	CALL VBDACU	;DO LISTEN TO UPDATE TSALTC,
	 JFCL
	JRST FSNORM	;THEN DO NORMAL FS ON TSALTC.

;READ OR SET # OF COMMAND LINES.
FSECLS:	MOVE A,NELNS	;GET CURRENT # OF CMD LINES,
	ARGDFL
	TRZE FF,FRARG
	 CALL FSECL1	;AND SET IT IF NEC.
	JRST POPJ1

;DESIRED # ECHO LINES IN C. (OR -<N> => NO ECHO, BUT <N>-1 ECHO LINES)
FSECL1:	SKIPGE E,C	;GET ARG IF POSITIVE,
	 SETCA E,	;OR -1-ARG IF NEGATIVE.
	CAML E,NVLNS	;VALUE TOO LARGE => WOULD CRASH TECO.
	 TYPRE [AOR]
	SKIPN RGETTY
	 JRST FSECL3
	MOVE T,NVLNS
	SUB T,NELNS	;IN CASE WE ARE REDUCING NELNS, ZERO OUT HASH CODES OF ALL LINES
FSECL2:	CAML T,NVLNS
	 JRST FSECL3
	SETOM HCDS-1(T)	;THAT WERE PREVIOUSLY THE ECHO AREA AND THE MODE LINE.
	AOJA T,FSECL2	

FSECL3:	MOVEM C,NELNS
	MOVE C,NVLNS	;TOTAL # LINES - # ECHO LINES
	SUB C,E
IFN TNX,[
	MOVEM C,ECHOL0	;SAVE FIRST LINE OF ECHO AREA
	HRLZM C,ECHOPS	;AND SET UP AS NEW ECHO POSITION
]
	SUBI C,1	;DEDUCT 1 LINE FOR THE --MORE--
	MOVEM C,USZ	;= # LINES FOR BUFFER DISPLAY.
	SETOM DISOMD	;MUST NOW REDISPLAY MODE LINE.
IFN ITS,[
	SYSCAL SCML,[%CLIMM,,CHTTYI ? E]
	 .LOSE %LSFIL
]
	SKIPE ECHOFL	;IF ECHOING NOMINALLY "ON" (THAT IS, NOT OFF DUE TO ^R OR ^T)
	 CALL SETTTM	;THEN MAYBE CHANGING THIS FLAG TURNS IT OFF OR ON.
	SETOM TYOFLG	;USZ HAS CHANGED, SO MAKE SURE TYPEOUT KNOWS ABOUT IT.
	RET

;READ OR SET FS TOP LINE$.  DON'T LET IT BE SET OUT OF RANGE.
;DON'T LET IT BE NONZERO ON A PRINTING TERMINAL.
FSTPLN:	TRNN FF,FRARG
	 JRST FSNORM
	SKIPN RGETTY
	 JUMPN C,FSTPLL
	CAMGE C,USZ
	 JUMPGE C,FSNORM
FSTPLL:	TYPRE [AOR]

FSWIDTH:TRNE FF,FRARG
	 CAIG C,MXNHLS
	  JRST FSNORM
	TYPRE [AOR]

IFN 20X,[
FSTTPG:	MOVE A,PAGMOD	;GET CURRENT PAGE MODE STATE
	TRNE FF,FRARG	;IF ANY ARG
	 MOVEM C,PAGMOD	;SETUP NEW ONE
	JUMPGE C,CPOPJ1	;AND IF NOT -1, DONT NEED TO CHANGE YET
	SAVE A
	MOVEI A,.CTTRM
	RFMOD
	TRON B,TT%PGM	;TURN ON PAGE MODE WHILE IN TECO
	 STPAR
	REST A
	JRST CPOPJ1
]

FSRUNT:	
IFN ITS,[
	.SUSET [.RRUNT,,A]
	MULI A,4069.	;CONVERT TO NANOSEC.,
	DIV A,[1.^6]	;THEN TO MILLISEC.
]
IFN TNX,[
	MOVEI A,.FHSLF	;THIS FORK
	RUNTM		;RUNTIME IN MS.
]
	JRST POPJ1

FSUPTI:	
IFN ITS,.RDTIME A,	;RETURN THE SYSTEM UP TIME - FS UPTIME $
IFN TNX,TIME		;SYSTEM UPTIME IN MS.
	JRST POPJ1

FSSWIT:	
IFN ITS,.RDSW A, 
IFN TNX,SWTCH		;FOR WHAT ITS WORTH
	JRST POPJ1	;RETURN PDP10 CONSOLE SWITCHES.

FSDDFS:
IFN ITS,[	;RETURN -1 IF DEFAULT DEVICE IS "FAST".
	MOVE D,[440700,,DEFFIL]
	MOVE B,[440600,,CH]
	SETZ CH,
	ILDB A,D
	CAIGE A,140
	 SUBI A,40
	SUBI A,40
	IDPB A,B
	ILDB A,D
	CAIGE A,140
	 SUBI A,40
	SUBI A,40
	IDPB A,B
	ILDB A,D
	CAIN A,":
	 CAME CH,MACHIN
	  JRST NRET0
]
	JRST NRETM1	;ONLY ITS HAS ANY SLOW DEVICES.

IFN ITS,[
..RHSNAM==16 ? ..RMAIL==17

;<ITS>,<USER>FS U HSNAME$ RETURNS IN SIXBIT THE HSNAME OF <USER> ON MACHINE <ITS>.
;BOTH ARGS SHOULD BE SIXBIT.  <ITS> CAN BE OMITTED FOR THE CURRENT MACHINE.
FSUHSN:	MOVE A,SARG
	MOVE B,C
	TRNN FF,FRARG
	 .SUSET [.RXUNAM,,B]
	.BREAK 12,[..RHSNAM,,A]
	MOVE A,B
	TRZ FF,FRARG\FRARG2
	JRST POPJ1

;<ITS>,<USER>FS UMAIL$ SETS DEFAULT FILENAMES TO MAIL FILE OF <USER> ON <ITS>.
;BOTH ARGS SHOULD BE SIXBIT.  <ITS> CAN BE OMITTED MEANING USE THAT USER'S HOME MACHINE.
FSUML:	MOVE A,SARG
	MOVE B,C
	TRNN FF,FRARG
	 .SUSET [.RXUNAM,,B]
	.BREAK 12,[..RMAIL,,A]
	SAVE C
	SAVE B
	MOVE D,[440700,,DEFFIL]	;STORE AS ASCIZ STRING IN DEFFIL.
	CALL STRGE1
	MOVEI B,":
	IDPB B,D
	MOVEI B,40
	IDPB B,D
	REST A
	CALL STRGE1
	MOVEI B,";
	IDPB B,D
	MOVEI B,40
	IDPB B,D
	REST A
	CALL STRGE1
	MOVEI B,40
	IDPB B,D
	MOVE A,[SIXBIT /MAIL/]
	CALL STRGE1
	SETZ B,
	IDPB B,D
	RET
];IFN ITS

FSEJPG:	MOVE A,LHIPAG		;READ OR WRITE FS :EJ PAGE$.
	ARGDFL
	TRZN FF,FRARG
	 JRST POPJ1
	CAML C,LHIPAG		;ILLEGAL TO SET IT TO A SMALLER VALUE SINCE PAGES DON'T EXIST.
	 CAILE C,LHIMAX		;ILLEGAL TO SET ABOVE TOP OF ADDRESS SPACE.
	  TYPRE [AOR]
	EXCH C,LHIPAG
;NOW FLUSH THE PAGES WE HAVE REMOVED FROM PURE STRING SPACE.
IFN ITS,[
	MOVE B,C
	SUB B,LHIPAG		;B GETS MINUS NUMBER OF PAGES FS :EJPAGE$ HAS ADVANCED OVER.
	JUMPE B,POPJ1
	HRL C,B			;C GETS AOBJN TO PAGES TO BE FLUSHED.
	SYSCAL CORBLK,[%CLIMM,,0 ? %CLIMM,,%JSELF ? C]
	 .LOSE %LSSYS
];IFN ITS
IFN TNX,[
	MOVE B,C
	SUB C,LHIPAG		;NEGATIVE NUMBER OF K
	JUMPE C,POPJ1
	MOVM C,C
	LSHC B,1		;TRANSLATE FROM K TO PAGES.
	HRLI B,.FHSLF		;THIS FORK
	SAVE A			;PRESERVE WHAT FS EJPAGE IS GOING TO RETURN.
	SETO A,
IFN 20X,[
	HRLI C,(PM%CNT)		;COUNT GIVEN
	PMAP
];IFN 20X
.ELSE	[
FSEJP1:	PMAP
	SOJLE C,FSEJP2
	AOJA B,FSEJP1
FSEJP2:	
];ELSE
	REST A
];IFN TNX
	JRST POPJ1

;RETURN CURRENT DATE/TIME IN DISK FILE DATE FORMAT.
FSDATE:	
IFN ITS,[
	SYSCAL RQDATE,[%CLOUT,,A]
	 .LOSE %LSSYS
]
IFN TNX,GTAD		;GET TIME IN SYSTEM INTERNAL FORMAT (ASSUME WILL
	JRST POPJ1	;BE PASSED ALONG TO FS F DCONV$ UNMUNGED)

FSFDAT:	
IFN ITS,[
	HLRZS E		;CREATION DATE OF FILE ON CHNL IN LH(E)
	ARGDFL
	SYSCAL RFDATE,[E ? %CLOUT,,A]
	 JRST OPNER1
	TRZN FF,FRARG
	 JRST POPJ1
	SYSCAL SFDATE,[E ? C]
	 JRST OPNER1
	JRST POPJ1
]
IFN TNX,[
	HLRZS E
	SKIPG A,(E)	;GET THE JFN
	 JRST [	CAIN E,CHFILI
		 TYPRE [NFI]
		TYPRE [NDO]
		]
	ARGDFL
	SAVE C		;SAVE ANY ARG
	MOVE B,[1,,.FBWRT]
	MOVEI C,A
	GTFDB		;GET THE OLD WRITE DATE
	 ERJMP OPNER1
	REST C
	TRZN FF,FRARG	;WRITING ON THIS FLAG?
	 JRST POPJ1	;NO, JUST RETURN
FSFDT2:	SAVE A
	MOVE A,(E)
	SETO B,
	HRLI A,.FBWRT
	CHFDB		;YES, CHANGE IT
	REST A		;AND RETURN OLD VALUE
	JRST POPJ1
]

;"FS FDCONV $" IS LIKE "\" BUT HANDLES FILE DATES INSTEAD NUMBERS.
FSDCNV:	TRNE FF,FRARG
	 JRST FSDCN2	;ARG => GO TURN IT INTO STRING IN BUFFER
	JRST FSDCNI	;ELSE PARSE A DATE OUT OF THE BUFFER.

IFN ITS,[
FSDCNI:	SAVE [0]	;PUSH WORD TO ACCUM. THE DATE IN.
FSDCN0:	MOVE OUT,[-6,, [40,,	;MONTH
			1,,	;DAY
			1000,,	;YEAR
			3600.*2	;HOUR (IN TERMS OF 1/2 SEC)
			60.*2	;MINUTE
			2]]	;SECOND
	JRST FSDCN4

FSDCN3:	MOVE IN,PT
	CAMN IN,ZV	;AT END OF BUFFER => RETURN WHAT WE HAVE
	 JRST FSDCN1
	CALL GETINC
	CAIN CH,^M	;STOP BEFORE A CR.
	 JRST FSDCN1
	AOS PT		;ELSE MOVE OVER DELIMITER
FSDCN4:	MOVE Q,PT
	SAVE OUT
	CALL BAKSL	;READ THE NEXT NUMBER
	 JFCL
	REST OUT
	CAMN Q,PT
	 JRST FSDCN1	;NO NUMBER => FINISHED.
	IMUL A,(OUT)	;ELSE PUT THIS # IN RIGHT PLACE
	ADDM A,(P)	;IN THE DATE BEING ACCUMULATED.
	AOBJN OUT,FSDCN3 ;HAVEN'T READ ALL 6 YET => KEEP GOING.
FSDCN1:	REST A		;A HAS DATE TO RETURN.
	CAMN OUT,@FSDCN0 ;IF DATE IN BUFFER WAS NULL,
	 SETO A,	;RETURN -1
	JRST POPJ1

FSDCN2:	MOVEM C,PTLFCD
	MOVEI TT,TYOM
	HRRM TT,LISTF5		;PRINT THE DATE INTO MEMORY.
	CALL [	TRNN FF,FRCLN
		 JRST GAPSLP
		MOVEI C,18.
		JRST QOPEN]
	SKIPL PTLFCD		;DATE IS -1 => LEAVE EMPTY.
	 CALL PTLAB9
	JRST SLPXIT
] ;IFN ITS

IFN TNX,[
FSDCNI:	CALL GAPSL0	;MOVE GAP TO PT, BUT ARENT MUNGING BUFFER
	CALL GETIB.	;GET BYTE POINTER TO .
	MOVE A,BP
	SETZ B,
	IDTIM		;READ IN TIME
	 SETO B,
IFN 20X,DBP7 A		;MAKE RESULTING BYTE POSITIONS CONSISTANT
	MOVE BP,A	;GET UPDATED BYTE POINTER
	CALL GETCA	;GET CHARACTER ADDR
	SUB BP,EXTRAC	;MOVE OVER GAP
	MOVEM BP,PT	;UPDATE .
	MOVE A,B	;VALUE TO RETURN
	JRST POPJ1

FSDCN2:	MOVEI A,TYOM	;INTO BUFFER
	HRRM A,LISTF5
	HRROI A,BAKTAB	;STRING SPACE
	MOVE B,C
	TRNE FF,FRARG2
	 SKIPA C,SARG	;USE ANY SECOND ARG AS THE FORMAT
	 MOVSI C,(OT%NMN\OT%DAM\OT%SLA)	;ELSE DEFAULT TO DD/MM/YY HH:MM:SS
	ODTIM
	LDB C,[350700,,BAKTAB]	;IF ITS FORMAT, MUST MAKE UP FOR ODTIM LOSSAGE
	TRNN FF,FRARG2
	 CAIE C,40
	 JRST FSDCN3
	MOVEI C,"0	;BY CONVERTING LEADING SPACE TO 0
	DPB C,[350700,,BAKTAB]
FSDCN3:	MOVEI C,20.	;MAKE ENOUGH ROOM
	CALL [	TRNN FF,FRCLN
		 JRST GAPSLP
		JRST QOPEN]
	MOVEI A,BAKTAB
	CALL ASCIND	;INSERT IT
	JRST SLPXIT

FSJOBN:	GJINF		;GET JOB NUMBER
	MOVEI A,(C)
	JRST CPOPJ1

FSGXNM:	SKIPE JCLNAM	;FS XJNAME, USE NAME FROM JCL IF THERE IS ONE
	 JRST [	MOVEI E,JCLNAM
		JRST FSSTR0]
FSGTNM:	GETNM		;GET SIXBIT JOB NAME
	MOVE C,A	;SET UP AS AN ARG
	JRST FSIXST	;AND GO MAKE A STRING OF IT

FSMACH:
IFDEF HSTNAM,[
	MOVEI E,[HSTNAM]
	JRST FSSTR0
];HSTNAM
.ELSE [
	MOVE A,[SIXBIT/LHOSTN/]	; SYSGT ARG: SIXBIT TABLE NAME
	SYSGT			; GET LOCAL HOST NO.
	JUMPE B,FSMAC1		; TRY ALTERNATIVE METHOD IF NO LHOSTN
	JUMPL A,FSMAC1		; OR IF LHOSTN IS NEGATIVE (TOPS-20 RELEASE 3
				; HAS A LHOSTN ENTRY ON ALL SYSTEMS)
	MOVE B,A
	HRROI A,BAKTAB
	CVHST			; CONVERT HOST NO. TO NAME
	 JRST FSMAC1		; NO STRING FOR THAT HOST
	MOVEI B,0		; MAKE SURE STRING IS ASCIZ
	IDPB B,A		; ...
	JRST FSSTR3
FSMAC1:	
IFN 20X,[
	MOVEI A,.NDGLN		;TRY DECNET NODE NAME
	MOVEI B,C
	HRROI C,BAKTAB
	NODE
	 ERJMP FSMAC2
	JRST FSSTR3		;BAKTAB NOW HAS ASCIZ NODE NAME
];20X
FSMAC2:	SETZM BAKTAB		; FOR THE MOMENT RETURN 0
	JRST FSSTR3
];HSTNAM

FSCCLF:	SKIPN A,CCLJFN	;FS CCL FNA$ - IF STARTED AT +2, ...
	 JRST CPOPJ1	;NOT, RETURN 0
	MOVEI B,(A)
	HRROI A,BAKTAB	;RETURN STRING OF JFN GIVEN
	MOVE C,[111110,,000001]	;AS DSK:<DIR>NAM.EXT.GEN
	JFNS
	TRZE FF,FRUPRW	;IF ATSIGN,
	  JRST FSSTR3	;  THEN DON'T RELEASE THE JFN
	MOVEI A,(B)
	RLJFN
	 JFCL
	SETZM CCLJFN	;DONT HAVE STRAY JFNS AROUND LATER
	JRST FSSTR3	;MOVE STRING FROM BAKTAB AND RETURN STRING POINTER

FSNQIT:	MOVE A,NOQUIT	;GET PREVIOUS SETTING
	ARGDFL
	TRZN FF,FRARG	;IF NO ARG,
	 JRST POPJ1	;RETURN IT
	MOVEM C,NOQUIT	;SETUP NEW ONE
	JUMPG A,FSNQT2	;CHANGING FROM POSITIVE
	JUMPLE C,POPJ1	;IF NOT CHANGING TO POSITIVE, NOTHING TO DO
	SAVE A
	MOVEI A,.TICCG
	DTI		;ELSE TURN OFF ^G INTERRUPT
	JRST POPAJ1
FSNQT2:	JUMPG C,POPJ1	;NOTHING IF CHANGING TO POSITIVE
	SAVE A
	MOVSI A,.TICCG	;ELSE RE-ASSIGN ^G INTERRUPT
	ATI
	JRST POPAJ1

FSLOAD:	MOVE A,[SIXBIT/SYSTAT/]	; SYSGT ARG: SIXBIT TABLE NAME
	SYSGT			; FIND TABLE NO. OF SYSTAT TABLE
	JUMPE B,FSLOA1		; 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
	 TDZA B,B		; IF ERROR RETURN ZERO
	MOVE B,A
FSLOA1:	HRROI A,BAKTAB
	MOVE C,[FL%ONE\FL%PNT\020200]
	JSYS 233		;FLOUT MAYBE SHOULD BE RENAMED
	 SETZM BAKTAB
	JRST FSSTR3
];IFN TNX

IFN TNX,[

FSDIRH:	MOVE B,HSNAME	;HOME DIRECTORY
	JRST FSDIR3
FSDIR2:	GJINF
	MOVE B,A	;LOGIN DIR
	JRST FSDIR3

FSDIRS:	TRZE FF,FRARG	; IF ARGUMENT
	 JRST FSDIR4	; THEN CONNECT TO DIRECTORY
	GJINF		;CONNECTED DIR
FSDIR3:	HRROI A,BAKTAB
	DIRST		;INTO STRING SPACE
	 SETZM BAKTAB
FSSTR3:	MOVEI E,BAKTAB
FSSTR0:	MOVEI C,10	;GET ENOUGH STRING
	CALL QOPEN
	MOVEI A,(E)
	CALL ASCIND	;INSERT IT
FSSTR2:	CALL QCLOSV	;AND RETURN STRING POINTER
	JRST POPJ1

; HERE TO HANDLE <VALUE>FSMSNAME
FSDIR4:	MOVE A,C	; CONVERT OUR STRING ARGUMENT TO ASCIZ IN BAKTAB
	MOVE C,[440700,,BAKTAB]	; ...
	CALL STRASC		; ...
	PUSH P,[0]	; 0 IF NO PASSWORD
	TRZN FF,FRARG2	; PRE-COMMA ARGUMENT?
	 JRST FSDIR7	; NO
	MOVEM C,(P)	; YES, SET PASSWORD POINTER NONZERO
	MOVE A,SARG	; CONVERT PRE-COMMA STRING ARGUMENT TO ASCIZ
	CALL STRASC	; ...
FSDIR7:
IFN 20X,[
	MOVE A,[AC%CON+3]	; ACCES ARG: A = FLAGS,,ARGUMENT BLOCK LENGTH
	MOVEI B,C	; ACCES ARG: B = ARGUMENT BLOCK ADDRESS
	HRROI C,BAKTAB	; ARGUMENT BLOCK + 0: DIRECTORY NAME
	POP P,D		; ARGUMENT BLOCK + 1: PASSWORD
	MOVNI E,1	; ARGUMENT BLOCK + 2: JOB NUMBER
	ACCES		; CONNECT TO DIRECTORY
	 ERJMP OPNER2	; GIVE FILENAMELESS ERROR
]
.ELSE	[
	HRROI B,BAKTAB	; STDIR ARG: B = DIRECTORY NAME
	STDIR		; TRANSLATE DIRECTORY NAME TO NUMBER
	 ; +2 RETURN NOT POSSIBLE IF ASKING FOR EXACT MATCH, SO CAN ASSUME
	 ; ERROR, IF ANY, WILL GO TO +1
	 MOVE B,[.FHSLF,,600075]	; ERSTR ARG: FORK,,ERROR CODE
	 JRST [	TRO FF,FRNOT	; NO FILENAME
		JRST OPNER6 ]	; GIVE NO SUCH DIRECTORY ERROR
	HRRZ A,A	; CNDIR ARG: A = DIRECTORY NUMBER
	POP P,B		; CNDIR ARG: B = PASSWORD STRING POINTER
	CNDIR		; CONNECT TO DIRECTORY
	 JRST OPNER2	; GIVE FILENAMELESS ERROR
]
	RET

STRASC:	CALL QLGET0
	 TYPRE [QNS]
	JUMPE B,FSDIR6
FSDIR5:	ILDB A,BP
	IDPB A,C
	SOJG B,FSDIR5
FSDIR6:	MOVEI A,0
	IDPB A,C
	RET

FSDSNM:	TRO FF,FRNOT	;FLAG TO FLUSH DIRST PUNCTUATION
FSSTRR:	HLRZS E		;GET DESIRED ADDRESS
	PUSH P,C	;SAVE ARG IN CASE NEED IT
	CALL FSSTR0	;GET STRING TO RETURN
	 JFCL
	EXCH A,(P)
	TRZN FF,FRARG	;ANY ARG?
	 JRST FSST1A	;NO, JUST RETURN IT
	HRLI E,440700	;MAKE BYTE POINTER
	SKIPGE A	;GET ARG - SHOULD BE A STRING
	CALL QLGET0	;GET BYTE POINTER AND SIZE OF STRING
	 TYPRE [ARG]	;NOT A STRING?
FSSTR1:	ILDB CH,BP
	CAIL CH,"a
	 CAILE CH,"z
	 CAIA
	 SUBI CH,"a-"A	;MAKE SURE IS UPPERCASE
	CAIN CH,":	;LOOK LIKE STRUCTURE PUNCTUATION FROM DIRST
	 TRNN FF,FRNOT	;AND ON THE LOOKOUT FOR THAT?
	 CAIA
	 JRST FSDSN2	;YES, GO HANDLE THAT
	CAIE CH,"<
	 CAIN CH,">	;IF PART OF DIRECTORY PUNCTUATION
	 TRNN FF,FRNOT	;AND LOOKING FOR IT - SKIP MOVING CHAR
	IDPB CH,E
	SOJG B,FSSTR1	;MOVE STRING INTO DESIRED PLACE
	MOVEI CH,^@	;AND END WITH A NULL
	IDPB CH,E
FSST1A:	POP P,A
	JRST CPOPJ1	;RETURN OLD VALUE

FSDSN2:	MOVEI CH,^@
	IDPB CH,E
	MOVE CH,DEFDIR	;IF : SEEN IN DIRECTORY, MOVE STRUCTURE
	MOVEM CH,DEFDEV	;OVER TO DEVICE
	MOVE CH,DEFDIR+1
	MOVEM CH,DEFDEV+1
	MOVE E,[440700,,DEFDIR]	;AND RESET POINTER TO DIRECTORY
	SOJA B,FSSTR1

;EXPUNGE CONNECTED DIRECTORY
FSEXPU:
IFN 20X,[
	GJINF		;GET CONNECTED DIRECTORY INTO B
	SETZ A,		;NO FLAGS
];20X
	DELDF
	 ERJMP OPNER2
	RET
] ;IFN TNX

;RETURN THE HORIZ POS. OF THE CURRENT POINTER SETTING,
;ASSUMING THAT BACKSPACES AND STRAY CR'S COME OUT AS SUCH.
; ^HPRINT AND ^MPRINT FLAGS ARE NOT LOOKED AT.
;FS TABWID IS OBEYED.
FSHPOS:	MOVE BP,BEGV
	SOS C,BP
	SETZ A,
	MOVE BP,PT
	CAMN BP,BEGV
	JRST POPJ1
	MOVE IN,BP
	SOS BP
FSHPOL:	SOS IN
	CALL GETCHR
	CAIE CH,^M
	 CAMN C,IN
	  JRST FSHPOT
	JRST FSHPOL

FSHPOD:	AOS IN
	CALL GETCHR
	CAIE CH,^J
	 CAIN CH,GLITCH
	  JRST FSHPOT
	CAIN CH,^I
	 JRST [	ADD A,TABWID
		IDIV A,TABWID
		IMUL A,TABWID
		JRST FSHPOT]
	CAIN CH,ALTMOD
	 AOJA A,FSHPOT
	CAIN CH,^H
	 SOJA A,FSHPOT
	CAIGE CH," 
	 AOJ A,
	AOJ A,
FSHPOT:	CAME IN,BP
	 JRST FSHPOD
	JRST POPJ1

;RETURN HPOS COUNTING CTL CHARS AS THEY APPEAR, BUT NOT COUNTING CONTINUATION.
FSSHPS:	SAVE NHLNS
	.I NHLNS=1000000.
	CALL RRBTCR
	MOVE A,RRHPOS
	REST NHLNS
	SAVE A
	CALL RRBTCR
	REST A
	JRST POPJ1

;READ OR SET THE VIRTUAL BUFFER BOUNDARIES - THE RANGE OF
;BUFFER THAT ALL OTHER COMMANDS ARE ALLOWED TO TOUCH.
FSBOUN:	TRNN FF,FRARG
	 JRST HOLE	;NO ARG => RETURN BOUNDS, LIKE H COMMAND
	MOVE E,SARG
	CALL GETARG	;ELSE CALCULATE NEW BOUNDS,
	 CALL CHK1A
	CALL HOLE	;SET UP THE VALUES TO BE RETURNED,
	 JFCL
FSBOU1:	CALL CHK1A	;MAKE SURE BEG<C<E<Z, IN CASE COMING FROM FSVB OR FSVZ.
	MOVEM C,ZV	;STORE NEW BOUNDS (HOLE LOOKED AT OLD ONES)
	MOVEM E,BEGV
	CAMG C,PT	;MOVE PT INTO THE RANGE NOW
	 MOVEM C,PT	;BEING EDITED, IN CASE IT IS OUTSIDE IT.
	CAML E,PT
	 MOVEM E,PT
VALRTA:	TRZ FF,FRARG	;RETURN VALUE, FLUSHING ARGUMENTS.
	JRST POPJ1

FSVB:	MOVE A,BEGV	;GET C AS REL. CHAR ADDR.
	SUB A,BEG
	TRZN FF,FRARG	;IF NO ARG, JUST RETURN THAT.
	 JRST POPJ1
	ADD C,BEG	;ELSE TURN ARG INTO ABS CHAR ADDR, TO SET BEGV.
	MOVE E,C	;GET IN C NEW VALUE OF ZV (SAME AS OLD
	CAMG C,ZV	;UNLESS THAT WOUL DBE LESS THAN NEW BEGV).
	 MOVE C,ZV
	JRST FSBOU1	;GO SET THEM BOTH (AND MAYBE PT).

FSVZ:	MOVE A,Z	;GET Z-ZV TO RETURN.
	SUB A,ZV
	TRZN FF,FRARG	;IF ARG, IT IS DESIRED Z-ZV
	 JRST POPJ1
	MOVE E,Z
	SUBB E,C	;SO COMPUTE DESIRED ZV FROM IT
	CAML E,BEGV
	 MOVE E,BEGV	;AND IF NECESSARY CHANGE BEGV AS WELL.
	JRST FSBOU1

SUBTTL F6 COMMAND - SIXBIT CONVERSION

IFN TNX,[
;ON TWENEX, "SIXBIT" VALUES ARE REALLY STRINGS.  SO THE F6 COMMAND IS TRIVIAL.
FSIXB:	TRZN FF,FRARG
	 JRST FCTLK0	;NO ARG => CONVERT STRING ARG TO "SIXBIT", SAME AS :I*.
	MOVE A,C
	TRZE FF,FRUPRW+FRCLN
	 JRST POPJ1	;:F6 CONVERTS "SIXBIT" TO STRING:  RETURN THE ARG.
	JRST QGET4	;F6 INSERTS "SIXBIT" ARG IN BUFFER:  ENTER "G" COMMAND.
]

IFN ITS,[
;F6 COMMAND.
FSIXB:	TRZN FF,FRARG	;NO ARG => READ IN STRING AND CONVERT TO SIXBIT
	 JRST FSIXR
	TRZE FF,FRUPRW+FRCLN	; :F6 RETURNS STRING CONTAINING THE CHARS OF THE SIXBIT. 
	 JRST FSIXST
	MOVE A,C	;ELSE INSERT ARG IN BUFFER.
	CALL QLGET0	;IF ARG IS ACTUALLY A STRING, GO TO G COMMAND.
	 CAIA
	  JRST QGET4
	MOVE E,C	;TREAT ARG AS WD OF SIXBIT AND INSERT IN BUFFER. 
	MOVEI A,TYOM
	HRRM A,LISTF5
	CALL GAPSLP
	JRST SIXNTY	;GO INSERT THE SIXBIT. 
]

FSIXST:	AOS (P)		;HERE TO CONVERT SIXBIT TO STRING. 
	MOVE A,C
	CALL QLGET0
	 CAIA
	  RET			;IF ARG IS STRING ALREADY, JUST RETURN IT.
	SAVE C
	MOVEI C,12.	;WE WILL NEED AT MOST 12 CHARS - MAKE SURE SPACE IS THERE. 
	CALL QOPEN
	REST E		;NOW OUTPUT THE SIXBIT INTO STRING SPACE (LISTF5 AND BP
	CALL SIXNTY		;SET UP BY QOPEN). 
	JRST QCLOSV	;WRITE THE HEADER AND RETURN THE STRING POINTER. 

FSIXFL:	AOS (P)		;CONVERT SIXBIT TO STRING, PUTTING "FS" IN FRONT AND ALTMODE BEHIND.
	SAVE C
	MOVEI C,15.	;WORKS ALMOST LIKE FSIXST.
	CALL QOPEN
	MOVEI CH,"F	;BUT PUT IN THE "FS" NOW.
	IDPB CH,BP
	MOVEI CH,"S
	IDPB CH,BP
	REST E
	CALL SIXNTY
	MOVEI CH,ALTMOD	;PUT IN THE ALTMODE AT THE END.
	IDPB CH,BP
	JRST QCLOSV

IFN ITS,[

FSFDEV:	MOVSI CH,(LFN"DEVFLG)
	JRST FSFNC

FSFDIR:	MOVSI CH,(LFN"DIRFLG)
	JRST FSFNC

FSFFN1:	MOVE CH,[LFN"NAMFLG 1]
	JRST FSFNC

FSFFN2:	MOVE CH,[LFN"NAMFLG 2]
	;JRST FSFNC

;Get the CH component of lh(E).  If arg given, replace the component with it.
FSFNC:	SAVE E
	CALL FSRFNC
	SAVE CH
	MOVEI E,TMPFIL
	CALL FSDFR1		;Make a Teco string
	REST CH
	REST E
	TRZN FF,FRARG
	 JRST POPJ1
	SAVE A
	MOVE D,[440700,,BAKTAB]
	MOVEI B,^X
	TRNE CH,2
	 IDPB B,D
	CALL STRGET
	MOVEI B,":
	TLNN CH,(LFN"DEVFLG)
	 MOVEI B,";
	TLNE CH,(LFN"DEVFLG\LFN"DIRFLG)
	 IDPB B,D
	SETZ B,
	IDPB B,D
	CALL FSSFNC
	JRST POPAJ1

;Replace the CH component of lh(E) with arg in BAKTAB
FSSFNC:	SAVE C
	SAVE E
	MOVE A,[-FNBLEN,,BAKTAB+F10LEN]
	HLRZ D,E
	CALL LFN"PARFN
	 JFCL
	SAVE A
	MOVE A,[-FNBLEN,,BAKTAB+F10LEN+FNBLEN]
	MOVEI D,BAKTAB
	CALL LFN"PARFN
	 JFCL
	REST B
	MOVEI C,TMPFIL
	MOVEI D,FNMLEN*5
	SETO E,
	CALL LFN"SMERGE
	 TYPRE [FTL]
	REST E
	HLR D,E			;Put it back into default
	HRLI D,TMPFIL
	MOVEI B,FNMLEN-1(D)
	BLT D,(B)
	JRST POPCJ

;Read filename component specified by CH from filename in lh(E) into TMPFIL.
;Clobbers A,D,E
FSRFNC:	SAVE C
	MOVE A,[-FNBLEN,,BAKTAB+F10LEN]
	HLRZ D,E
	CALL LFN"PARFN
	 JFCL
	MOVEI C,TMPFIL
	MOVEI D,FNMLEN*5
	MOVE E,CH
	CALL LFN"SGNAME
	 TYPRE [FTL]
	SKIPG D
	 IBP C
	SETZ D,
	DPB D,C			;Flush terminator
	JRST POPCJ

;Given a sixbit word or TECO string pointer in C,
;turn it into ASCII and send it down BP in D with filename quoting.
STRGET:	MOVE A,C
	CALL QLGET0
	 JRST STRGE1
	JUMPE B,CPOPJ
	CAILE B,FNMLEN*5-2
	 TYPRE [FTL]
STRGE2:	ILDB TT,BP
	IDPB TT,D
	SOJG B,STRGE2
	RET

STRGE1:	JUMPE A,CPOPJ
	SETZ B,
	ROTC A,6
	ADDI B,40
	MOVEI TT,^Q
	CAIE B,":
	 CAIN B,";
	  IDPB TT,D
	CAIN B,40
	 IDPB TT,D
	IDPB B,D
	JRST STRGE1
];ITS

IFN ITS,[

;FS D VERSI$ - RETURN OR SET DEFAULT VERSION NUMBERS
FSDVER:	SAVE C
	CALL FSFVER	;GET VALUE IN A CORRESPONDING TO OLD VALUE OF DEFAULT FN2.
	 JFCL
	EXCH A,(P)
	TRZN FF,FRARG	;ANY ARG GIVEN?
	 JRST POPAJ1	;NO, GO RETURN DEFAULT
	MOVSI T,(SIXBIT/>/)	;Convert arg to sixbit
	JUMPE A,FSDVR1
	MOVSI T,(SIXBIT/</)
	CAMN A,[-2]
	 JRST FSDVR1
	JUMPL A,POPAJ1	;ARG IS -1 => DON'T CHANGE ANYTHING.
	CAMLE A,[999999.]
	 TYPRE [ARG]	;ELSE MUST BE REASONABLE VERSION NUMBER.
	CALL DPTSIX
FSDVR1:	MOVE A,[-FNBLEN,,BAKTAB+F10LEN]	;Check out default
	MOVEI D,DEFFIL
	CALL LFN"PARFN
	 JFCL
	MOVEI D,(E)		;Get number of filenames
	JUMPG D,FSDVR2
	;No default filenames and wants to set the version!  What to do???
	;Make it ^Xvers and hope he sets the filename somewhere along the way.
	HRRZ B,A
	HLRE C,A
	SUB B,C
	MOVE C,[440700,,[ASCIZ ""]]
	MOVEM C,(B)
	MOVE C,[LFN"NAMFLG 1]
	MOVEM C,1(B)
	SUB A,[2,,0]
FSDVR2:	SOJG D,FSDVR3
	HRRZ B,A		;Here if one filename, make version the new
	HLRE C,A		;second filename
	SUB B,C			;Point to end of name
	SUB A,[2,,0]		;Gonna make one more
	JRST FSDVR5
FSDVR3:	MOVSI E,(LFN"NAMFLG)	;Here if at least two names, gonna replace
	SKIPA B,A		;the last one, so find it.
FSDVR4:	 ADD B,[2,,2]
	TDNN E,1(B)
	 JRST FSDVR4
	SOJGE D,FSDVR4
FSDVR5:	MOVEM T,(B)		;Save version
	HRLOI T,(LFN"NAMFLG)	;Mark as sixbit name
	MOVEM T,1(B)
	MOVEI C,TMPFIL
	MOVEI D,FNMLEN*5
	CALL LFN"PFNMCH
	 TYPRE [FTL]
	MOVE A,[TMPFIL,,DEFFIL]
	BLT A,DEFFIL+FNMLEN-1
	JRST POPAJ1

DPTSIX:	SETZ T,
	MOVE TT,[440600,,T]
DPTSX0:	IDIVI A,10.
	HRLM B,(P)
	SKIPE A
	 CALL DPTSX0
	HLRZ B,(P)
	ADDI B,'0
	IDPB B,T
	POPJ P,


;FS IF VERS$ - RETURN VERSION NUMBER OF INPUT FILE AS A NUMBER.
;FS OF VERS$ - RETURN VERSION NUMBER OF LAST OUTPUT FILE CLOSED.
;FS D VERSION$, READING HALF - RETURN DEFAULT FN2 AS NUMBER.
;EXPECTS ADDRESS OF FILENAME STRING IN LH(E).
; RETURN -1 IF THE FN2 IS NOT NUMERIC.
; -2 FOR "<" AND 0 FOR ">" (FS D VERSION$ ONLY)
FSFVER:	MOVE A,[-FNBLEN,,BAKTAB+F10LEN]
	HLRZ D,E
	CALL LFN"PARFN
	 JFCL
	TLZ E,-1		;Get # of names.
	JUMPE E,NRETM1		;None, return -1
	SOJE E,NRET0		;Only one, so second name is the default (">")
	HRLOI E,(LFN"NAMFLG)	;More than one, so look at the last name entry
	MOVE C,[-2,,TT]
	CALL LFN"BGNAME
	 JFCL
	HRRZ E,TT1
	CAIE E,1		;One char long?
	 JRST FSFVR1
	MOVE D,TT		;Yea, check for < >.
	ILDB D,D
	CAIN D,">
	 JRST NRET0
	CAIE D,"<
	 JRST FSFVR1
	HRROI A,-2
	JRST POPJ1
FSFVR1:	SETZ A,
FSFVR2:	ILDB D,TT
	CAIL D,"0
	 CAILE D,"9	;ALLOW ONLY DIGITS
	  JRST NRETM1	;RETURN -1 OTHERWISE
	IMULI A,10.
	ADDI A,-"0(D)
	SOJG E,FSFVR2
	JRST POPJ1	;NO NON-DIGITS => RETURN THE NUMBER.
] ;IFN ITS

IFN TNX,[
;FS D VERSION$ IS LIKE FSNORM ON DEFFN3 EXCEPT THAT IT REFERS TO THE SIGN-EXTENDED RH.
FSDVER:	HRRZS C
	HLRZS E
	HRRE A,(E)
	JRST FSNOR2
] ;IFN TNX

SUBTTL FA (FILL / JUSTIFY) COMMAND

;FA COMMAND (TEXT JUSTIFICATION). ARGS SPEC RANGE OF BUFFER.
;THE LINE SIZE IS KEPT IN ADLINE (FS ADLINE).
;A CRLF FOLLOWED BY A CRLF OR SPACE CAUSES A BREAK.
;OTHERWISE, CRLFS ARE REPLACED BY SPACES, UNLESS THEY END BLANK LINES.
;EXCESS SPACES (OR CRLFS TURNED INTO SPACES) ARE NOT REMOVED
;UNLESS A CRLF IS INSERTED JUST BEFORE THEM.  IN THAT CASE, THEY MUST
;BE REMOVED TO AVOID CREATING A BREAK.

;SPACES AT THE BEGINNING OF A LINE ARE TREATED AS PART OF
;THE FIRST WORD OF THE LINE FOR JUSTIFICATION PURPOSES,
;TO PREVENT INDENTATION OF PARAGRAPHS FROM CHANGING.
;THE LAST PART-LINE OF STUFF TO BE JUSTIFIED
;IS CONSIDERED TO HAVE A BREAK AFTER IT.
;SPACE-BACKSPACE-SPACE ACTS LIKE A SINGLE ORDINARY CHAR.
;THIS MAKES IT POSSIBLE TO PUT A SPACE INTO A WORD.
;@FA IS LIKE FA BUT ONLY FILLS - IT DOESN'T JUSTIFY.

;FRALT => IF NEXT CHAR IS SPACE OR CR, IT SHOULD BREAK.
;FRNOT => NO NON-SPACE HAS BEEN SEEN YET ON THIS LINE
	;(SO SPACES SHOULD BE LIKE ORDINARY CHARS)
;FRFIND => PREVIOUS CHAR WAS ^H SO SPACE IS ORDINARY.
;FRSPAC => PREV. CHAR WAS SPACE, SO SPACE SHOULD BE ORDINARY AFTER IT
ADJUST:	PUSHJ P,GETANU
	EXCH C,E	;THROUGHOUT THE CMD, E -> 1ST CHAR AFTER RANGE TO JUSTIFY.
	MOVEM C,PT
	CALL GAPSLP
	SAVE [0]	;THIS WD HAS STARTING HPOS OF LINE.

;COME HERE TO PRODUCE 1 MORE LINE OF JUSTIFIED TEXT.
ADJLP0:	ANDCMI FF,FRALT
	MOVE IN,PT
	MOVE D,IN	;D -> 1ST CHAR THAT MIGHT NOT FIT (DON'T KNOW YET)
	ANDCMI FF,FRFIND+FRSPAC	;PREV. CHAR WASN'T ^H. OR SPACE.
	TRO FF,FRNOT	;NO NON-SPACE HAS BEEN SEEN SO FAR.
	MOVE J,(P)	;J HAS HPOS IN OUTPUT LINE,
	SETZ OUT,	;OUT IS # WDS FOUND SO FAR.
	SETZ Q,		;Q IS 0 IF WE HAVEN'T PASSED A CRLF, OR CHAR ADDR AFTER LAST CRLF.
	SETZ C,		;C HAS # WDS AS OF LAST CRLF WE PASSED.
	SAVE J		;(P) HAS WHAT J HAD WHEN IN HAD WHAT D HAS.
	MOVE BP,IN
	ADD BP,EXTRAC
	CALL GETIBP	;WE WILL FETCH CHARS VIA BP.
ADJLP1:	CAML IN,E
	 JRST ADJEN1	;PRETEND THERE'S A SPACE AFTER RANGE TO WORK ON.
	ILDB CH,BP
	AOJ IN,
	CAIG CH,40
	 JRST ADJCTL
ADJNRM:	ANDCMI FF,FRALT\FRNOT\FRFIND\FRSPAC	;NORMAL CHAR ON PASS 1 OF FA.
	AOJA J,ADJLP1

ADJEN1:	TRNE FF,FRNOT		;HERE IF WE REACH END OF REGION TO BE FILLED.
	 JRST ADJSKP		;IF LAST LINE IS JUST SPACES, LEAVE IT ALONE.
	JUMPE J,ADJSKP		;IF IT IS EMPTY, LEAVE IT ALONE.
	JUMPE OUT,ADJSP2	;IF IT IS JUST ONE WORD, LEAVE IT ALONE.
	CAMLE J,ADLINE		;ELSE MAY HAVE TO BREAK IT IF IT IS TOO LONG.
	 JRST ADJGO
	JRST ADJBRK		;IF IT FITS IN ONE LINE, REMOVE ANY OLD CRLFS FROM IT.

ADJCTL:	CAIN CH,40
	 JRST ADJSPC	;SPACE ENDS A WORD.
	CAIN CH,^M
	 JRST ADJCR	;CR ENDS A WORD.
	CAIN CH,^I
	 JRST ADJTAB
	CAIN CH,^L	;^L MAKES A BREAK BEFORE AND AFTER THE LINE CONTAINING IT.
	 JRST ADJFF
	CAIE CH,^H
	 JRST ADJNRM
	TRZ FF,FRALT\FRNOT\FRSPAC
	IORI FF,FRFIND
	SOJGE J,ADJLP1
	AOJA J,ADJLP1

ADJFF:	JUMPN Q,ADJFF1	;^L:  IF IT'S NOT ON THE LINE WE STARTED HACKING ON THIS CYCLE,
			;FILL UP TO THE CRLF BEFORE THE ^L, THEN CONSIDER IT AGAIN.
	JRST ADJSK1	;JUST SKIP OVER THE ^L, AND WHAT PRECEDES IT ON THE LINE.

ADJTAB:	TRNE FF,FRALT	;COME HERE FOR TAB
	 SOJA IN,ADJBRK	;TAB AT START OF LINE BREAKS.
	SAVE BP
	ADD J,TABWID	;ADVANCE J TO NEXT TAB STOP.
	IDIV J,TABWID
	IMUL J,TABWID
	REST BP
	MOVEM J,-1(P)	;SAY NEXT OUTPUT LINE STARTS AT THAT STOP
	JUMPE Q,ADJSK1	;IF WE HAVEN'T PASSED A CRLF THIS TIME, SKIP PAST ALL BEFORE TAB.
ADJFF1:	MOVE IN,Q	;ELSE BACK UP TO THE CRLF AND FILL UP TO IT.
	MOVE OUT,C	;THEN NEXT TIME WE'LL SKIP ALL FROM CRLF TO THE TAB.
	JRST ADJBRK

;COME HERE ON SPACE
ADJSPC:	TRNE FF,FRALT	;IF 1ST CHAR ON LINE, IT IS A BREAK.
	 JRST ADJSP1
	TRNN FF,FRFIND\FRSPAC\FRNOT	;ELSE IF SPACE FOLLOWS A WORD,
	 SKIPA B,BP	;THEN UNLESS
	  JRST ADJNSP
	ILDB B,B	;IT IS FOLLOWED BY A BACKSPACE, WE END A WORD.
	CAIE B,^H
	 JRST ADJSP1
ADJNSP:	TRZ FF,FRFIND\FRALT
	AOJA J,ADJLP1

ADJCR:	TRZE FF,FRFIND	;COME HERE ON CR.
	 AOJA IN,ADJBRK	;CR PRECEDED BY ^H CAUSES BREAK AFTER FOLLOWING LF.
	TRNE FF,FRALT	;THIS CR ENDS NULL LINE => BREAK
	 SOJA IN,ADJBRK	;BEFORE IT.
			;THE PARAGRAPH WILL BE ENDED, AND WE'LL
			;COME BACK HERE WITH FRALT CLEAR,
			;AND DO THE JUMPE J, BELOW.
	TRNE FF,FRNOT	;LINE OF ONLY SPACES IS A BREAK.
	 AOJA IN,ADJSKP
	IBP BP		;SKIP THE LF ASSUMED TO FOLLOW THE CR.
	AOS IN
	MOVE Q,IN	;REMEMBER CHAR ADDR AND # WDS AS OF MOST RECENT CRLF.
	MOVE C,OUT
	JUMPE J,ADJSKP	;NULL LINE AT BEGINNING => PASS OVER IT.
ADJSP1:	TRNE FF,FRALT	;SPACE AFTER CRLF; BREAK BEFORE THE SPACE
	 SOJA IN,ADJBRK	;SO SPACE WILL BE REPROCESSED FOR NEXT LINE.
	JUMPE OUT,ADJSP2 ;PREVENT LOSSAGE FROM SUPERLONG WORD.
	CAMLE J,ADLINE
	 JRST ADJGO	;WORD JUST ENDED WON'T FIT =>JUSTIFY THE OTHERS & NEW LINE.
ADJSP2:	CAIN CH,^M
	 TRO FF,FRALT	;AFTER ^M, ANOTHER SPACE BREAKS.
	TROE FF,FRSPAC	;AFTER A SPACE, DON'T COUNT A NEW WORD, BUT DO ADVANCE HPOS.
	 AOJA J,ADJLP1
	MOVEM J,(P)	;REMEMBER HOW FAR WE GOT IN BUFFER AND LINE.
	MOVE D,IN
	AOS J		;IF NEXT WD FITS, WILL NEED 1 POS FOR SPACE.
	AOJA OUT,ADJLP1

ADJSKP:	SETZM -1(P)
ADJSK1:	MOVEM IN,PT	;PASS OVER SOME TEXT, NOT FILLING.
	SUB P,[1,,1]
	CALL GAPSLP
	JRST ADJBR3

ADJBRK:	SETZM (P)	;FILL THE LINE BEFORE A BREAK BUT NOJUST.
	MOVE D,IN
	TRO FF,FRALT	;INDICATE WE STOPPED AT A BREAK.
	JRST ADJBR1

;COME HERE AFTER DELIMITING WHAT WILL BECOME ONE LINE, TO JUSTIFY IT.
ADJGO:	MOVN J,(P)
	ADD J,ADLINE
	TRNE FF,FRUPRW	;JUST FILLING => INSERT NO SPACES.
	 SETZ J,
	TRZ FF,FRALT	;WE DID NOT STOP AT A BREAK.
	MOVEM J,(P)	;# SPACES MUST SCATTER THRU LINE.

;(P) HAS # OF SPACES WE MUST INSERT TO JUSTIFY
 ;(0 IF STOPPED AT A BREAK, IN WHICH CASE FRALT SET)
;OUT HAS # OF WORD-BREAKS IN THE LINE.
;-1(P) STILL HAS HPOS TO START NEXT LINE AT.
;E STILL HAS 1ST CHAR NOT TO BE PROCESSED BY THE FA COMMAND.
;D HAS CHAR ADDR OF 1ST CHAR NOT TO BE INCLUDED.
;IF FRALT IS SET (BREAK FOLLOWS), D IS EXACT.
;THE CRLF BEFORE D MAY HAVE PRECEDING SPACES, WHICH ARE DELETED.
;OTHERWISE, D POINTS AFTER THE SPACE OR CRLF AFTER THE LAST WORD TO INCLUDE.
;IN THIS CASE, THERE MAY BE MORE SPACES FOLLOWING, WHICH OUGHT TO BE DELETED.
;A CRLF AFTER THE SPACES SHOULD ALSO BE DELETED.
ADJBR1:	SETZ J,
	SOSG OUT
	 MOVEI OUT,1
	ANDCMI FF,FRFIND+FRSPAC
	TRO FF,FRNOT	;NO NON-SPACE CHAR SEEN YET.
	MOVE IN,PT	;IN IS CHAR ADDR FOR TAKING FROM ABOVE GAP,
	MOVE BP,PT
	CALL GETIBP	;BP IS BP FOR IDPBNG INTO BOTTOM OF GAP.
ADJGL:	CAML IN,E
	 JRST POP2J	;AT END OF RANGE IN MID-LINE => DON'T PUT IN A CRLF.
	CALL GETINC
	CAIN CH,^M
	 JRST ADJGCR
	CAIN CH,40
	 JRST ADJGS
ADJGS4:	CAMLE IN,D	;AT END OF THIS OUTPUT LINE & PAST ALL TRAILING SPACES
	 JRST ADJDUN	;=> INSERT THE CRLF AND HACK NEXT LINE.
	ANDCMI FF,FRNOT+FRSPAC	;NON-SPACE SEEN.
	CAIN CH,^H
	 TROA FF,FRFIND
ADJGS1:	ANDCMI FF,FRFIND
	IDPB CH,BP	;ORD. CHR., JUST COPY TO BELOW THE GAP.
	AOS GPT
	AOS PT
	JRST ADJGL

ADJGS:	CAME E,IN	;SPACE AT END OF RANGE => DON'T CHECK FOLLOWING CHAR.
	 TRNE FF,FRNOT+FRFIND
	  JRST ADJGS1	;SPACE AFTER BS OR BEFORE 1ST WD IS NORMAL CHAR.
	CALL GETINC	;ELSE SEE IF FOLLOWED BY BS.
	CAIE CH,^H
	 SOJA IN,[	;NO, IT IS A WORD DELIMITER.
		TRNN FF,FRALT	;IF LINE DOESN'T END WITH A BREAK,
		 JRST ADJCR1	;MAKE SURE EXTRA SPACES PAST END ARE DELETED.
		JRST ADJCR2]
	MOVEI CH,40
	SOJA IN,ADJGS4	;YES, IT IS ORDINARY.

ADJGCR:	ANDCMI FF,FRFIND	;CR: DELETE FOLLOWING LF IF ANY.
	CALL GETCHR
	CAIN CH,^J
	 CALL ADJDLC
ADJCR2:	CAMGE IN,D	;CRLF (OR SPACE, IF THERE'S A BREAK HERE) PAST THE END OF THE LINE
	 JRST ADJCR1	;MEANS WE HAVE FINISHED SKIPPING THE EXCESS MULTIPLE SPACES
	CALL ADJDLC	;AND WE SHOULD JUST FLUSH THIS ONE AND PREVIOUS ONES
	JRST ADJDUN	;AND PUT IN THE CRLF.

ADJCR1:	MOVEI CH,40	;ALSO REPLACE THE CR WITH A SPACE.
	TROE FF,FRSPAC	;A SPACE OR CR WHICH FOLLOWS A SPACE
	 JRST ADJGS1	;SHOULD NOT HAVE SPACES INSERTED AFTER IT FOR JUSTIFICATION.
	CAMGE IN,D
	 ADD J,(P)
ADJGS2:	CAMGE J,OUT
	 JRST ADJGS1
	IBP BP		;TIME TO GENERATE A SPACE.
	SUB J,OUT
	AOS E
	AOS D		;RELOC OUR PTRS TO BUFFER SINCE INSERTING CHAR.
	AOS IN
	CALL TYOM
	JRST ADJGS2	;SEE IF SHOULD INSERT ANOTHER SPACE.

;COME HERE WHEN WE HAVE DONE PASS 2 ON A WHOLE LINE
ADJDUN:	SUBI IN,2	;WE HAVE JUST PASSED AT LEAST ONE SPACE INTO THE OUTPUT LINE.
	JRST ADJEND	;MAKE IN POINT AT IT.  IN SHOULD BE GPT-1 NOW.

ADJDUD:	CALL ADJDLB
ADJEND:	CALL GETCHR	;DELETE ANY SPACES WHICH WOULD OTHERWISE BE LEFT AT
	CAIN CH,40	;THE END OF THE LINE, BEFORE THE CRLF WE ARE ABOUT TO MAKE.
	 JRST ADJDUD
ADJDU1:	REST J
	MOVEI CH,^M	;PRODUCED A LINE, PUT CRLF AFTER IT, REPLACING THE SPACE THERE.
	CALL TYOM
	MOVEI CH,^J
	CALL TYOM
	ADDI E,2	;RELOCATE PTR TO BUFFER ABOVE PLACE INSERTED IN.
	SETZM (P)	;NEXT LINE STARTS IN COLUMN 0.
ADJBR3:	CAMLE E,PT	;MORE CHARS TO HANDLE =>
	 JRST ADJLP0	;DO ANOTHER LINE.
	JRST POP1J

ADJDLB:	SOS PT
	SOS GPT
	SOS IN
ADJDLC:	AOS EXTRAC	;DELETE THE CHAR AT PT.
	SOS Z
	SOS E
	SOS ZV
	SOJA D,CPOPJ

SUBTTL F^A DISPATCH-TABLE COMMAND

;"F^A" SCAN THROUGH THE BUFFER, DISPATCHING THROUGH A
;USER-SUPPLIED TABLE ON EACH CHARACTER.
;"@F^A" SCANS BACKWARDS.
FCACMD:	CALL QREGX	;GET DISPATCH TABLE IN A.
	LDB OUT,[.BP FRCLN,FF]
	TRZ FF,FRCLN
	CALL GETANU	;E,C HAVE RANGE TO SCAN.
	DPB OUT,[.BP FRCLN,FF]
	TRNE FF,FRUPRW
	 EXCH C,E	;E HAS PLACE TO START; C HAS PLACE TO STOP.
	MOVEM E,PT
	MOVEI TT,FCA1	;LOOP POINT IF FCA1 FOR FORWARD SCAN.
	TRZE FF,FRUPRW
	 MOVEI TT,FCA3	;FCA3 FOR BACKWARD SCAN.
	SAVE FF
	SAVE TT
	MOVE OUT,QRB..	;SAVE DISPATCH TABLE STRING IN .Q..3
	MOVEM A,.Q..3(OUT)
FCA0:	CALL QLGET1	;GET LENGTH IN B, BP IN BP.
	 TYPRE [QNS]
	CAIGE B,128.*5
	 TYPRE [STS]	;STRING TOO SHORT.
	JRST @(P)	;FCA1 OR FCA3

;LOOP POINT FOR FORWARD SCAN.
;BP HAS BP TO ILDB TABLE;
;C HAS CHAR ADDR OF LAST CHAR TO SCAN + 1.
FCA1:	MOVE IN,PT
	CAML IN,C
	 JRST POP2J	;FINISHED SCAN => RETURN.
	CALL GETINC
	MOVEM IN,PT
FCA4:	TRNE FF,FRTRACE
	 CALL FCATRC	;PRINT PRETTY INFO IF TRACING.
	MOVEM CH,.Q..0(OUT) ;SAVE CHAR IN CASE MACRO WANTS IT.
	ADD CH,BP	;FIND THE 5 CHARS OF TABLE FOR THIS CHR.
	ILDB A,CH	;IS THE FIRST A SPACE?
	CAIE A,40
	 JRST FCA2	;NO, MACRO THE 5 CHARS.
	ILDB A,CH	;YES, THE NEXT CHAR HOLDS THE WIDTH
	SUBI A,100
	ADDM A,.Q..1(OUT) ;OF THIS CHAR, PLUS 100 .
	ILDB A,CH	;GET THE 3RD CHAR OF THE FIVE.
	CAIN A,40	;"(" AND ")" ARE SPECIAL, " " IS NORMAL.
	 JRST @(P)	;FCA1 OR FCA3
	HRRZ CH,(P)	;IT'S SPECIAL. WHICH DIRECTION ARE WE SCANNING?
	CAIE A,")	;IF CODE IS ")",
	 JRST FCAOPN
	SKIPGE .Q..1(OUT) ;STOP IF COUNT < 0 AND GOING FORWARD.
	 CAIE CH,FCA1
	  JRST (CH)
	JRST POP2J

FCAOPN:	SKIPLE .Q..1(OUT) ;CODE IS "("; STOP IF COUNT > 0 AND GOING BACKWARD.
	 CAIE CH,FCA3
	  JRST (CH)
	JRST POP2J

FCA3:	MOVE IN,PT	;LOOP POINT FOR SCANNING BACKWARDS
	CAMG IN,C
	 JRST POP2J
	SOS IN,PT
	CALL GETCHR
	JRST FCA4

;IN TRACE MODE, CALL HERE TO PRINT !<CHAR>! FOR EACH CHAR WE PASS.
FCATRC:	SAVE CH
	MOVEI CH,"!
	CALL TYOS
	MOVE CH,(P)
	CALL TYOS
	MOVEI CH,"!
	CALL TYOS
	JRST POPCHJ

;HERE FOR A CHAR WHICH REQUIRES THAT WE ACTUALLY MACRO SOME STUFF.
FCA2:	MOVN TT,(P)
	ADDI TT,FCA1	;TT IS POS. IFF SCANNING FORWARD.
IFL FCA3-FCA1,.ERR
	ASH TT,-43	;-1 IFF BACKWARD, 0 IFF FORWARD.
	IORI TT,1	;-1 IFF BACKWARD, 1 IFF FORWARD.
	MOVEM TT,INSLEN	;MAKE "^F" REPLACE THE CHAR SCANNED.
	JUMPG TT,[	SUB C,ZV	;IF FORWARD, STORE END OF RANGE AS DISTANCE FROM Z.
			MOVNM C,.Q..2(OUT)
			JRST FCA5]
	SUB C,BEGV	;GOING BACKWARD, STORE DISTANCE FROM C.
	MOVEM C,.Q..2(OUT)
FCA5:	MOVE B,.Q..0(OUT)
	ADD BP,B
	MOVE E,-1(P)
	TRNE E,FRCLN	;:F^A TREATS DISPATCH TABLE AS A QVECTOR.
	 JRST [	IBP BP	;IT EXTRACTS A WORD, AND TREATS IT AS A STRING POINTER TO A MACRO.
		MOVE A,(BP)
		CALL MACXQ
		JRST FCA7]
	MOVE A,.Q..3(OUT)
	MOVEI B,5	;MACRO A STRING THAT IS AN INITIAL
		;SEGMENT OF THE DISPATCH TABLE, ENDING AFTER THE
		;FIFTH OF THE CHARS FOR THE CHAR JUST SCANNED.
		;WANT TO SET COMCNT TO 5.
	CALL MACXC2	;EXECUTE THEM.
FCA7:	MOVE OUT,QRB..
	MOVE TT,(P)
	CAIN TT,FCA1
	 JRST [	MOVN C,.Q..2(OUT)
		ADD C,ZV	;SEE HOW THE MACRO HAS CHANGED END OF RANGE.
		JRST FCA6]	;MUST USE DIFFERENT CODE DEPENDING ON HOW IT WAS STORED.
	MOVE C,.Q..2(OUT)
	ADD C,BEGV
FCA6:	CAMGE C,BEGV	;DON'T LET END OF RANGE GET OUTSIDE VIRTUAL BOUNDARIES.
	 MOVE C,BEGV
	CAMLE C,ZV
	 MOVE C,ZV
	MOVE A,.Q..3(OUT)
	JRST FCA0

POP2J:	SUB P,[2,,2]
	POPJ P,

SUBTTL F^B COMMAND

;<CH>F^B<STRING>$ - RETURNS -1 IF <CH> DOES NOT OCCUR IN <STRING>;
; OTHERWISE RETURNS THE POSITION OF THE FIRST OCCURRENCE
; (0 IF <CH> IS THE FIRST CHARACTER OF <STRING>).
;AT CALL, <CH> IS IN C.  THIS COULD BE SMARTER:
; IF <CH> IS FOUND IN THE MIDDLE OF A SUBSTITUTED QREG WITHIN <STRING>,
; WE COULD JUST POP OUT OF IT RATHER THAN READING THROUGH IT.
;<POS>,<CH>F^B<STRING>$ SKIPS <POS> CHARS OF <STRING> BEFORE LOOKING FOR <CH>.
FMEMQ:	TRNE FF,FRUPRW
	 JRST FFIND
	TRZN FF,FRARG
	 TYPRE [WNA]
	TRZN FF,FRARG2
	 SETZ E,	;E IS PLACE TO START SEARCHING (0, FOR 1ST CHAR, IF NO ARG).
	MOVE B,MACPDP
	SETZ A,		;A COUNTS THE CHARS WHICH AREN'T <CH>.
FMEMQ1:	CALL RCH
	SKIPN SQUOTP	;NO; REACHED END OF STRING?
	 CAIE CH,ALTMOD
	  CAIA		;NO, SEE IF REACHED DESIRED CHARACTER (OUR NUMERIC ARG)
	   JRST NRETM1	;YES, RETURN -1
	CAIE C,(CH)
	 AOJA A,FMEMQ1	;DIDN'T REACH CHAR BEING SEARCHED FOR.
	CAMGE A,E
	 AOJA A,FMEMQ1	;REACHED IT, BUT BEFORE WHERE WE ARE SUPPOSED TO BE LOOKING.
	CALL FNOOP	;FOUND <CH>.  NOW IGNORE REST OF STRING
	JRST POPJ1	;AND RETURN THE VALUE, ALREADY IN A.

;HERE FOR @F^B<STRING>$ - FIND NEXT OCCURRENCE IN THE BUFFER
;OF A CHARACTER NOT IN <STRING>, AND RETURN .,<ADDR OF THAT OCCURRENCE>.
;@:F^B<STRING>$ RETURNS .,<ADDR OF NEXT CHAR WHICH IS IN STRING>.
;AN ARGUMENT OF -1 CAUSES SCANNING TO GO BACKWARDS INSTEAD.
;THUS, @F^B $K KILLS ALL SPACES AFTER POINT, AND @-F^B $K KILLS ALL THOSE BEFORE.
;WITH 2 ARGS <X>,<Y>, WE JUMP TO <X> AND THEN SCAN TOWARD <Y>.
FFIND:	JSP BP,FLCMD1		;FLCMD1 CALLS US TO MOVE POINT TO OTHER END OF RANGE,
				;THEN CALCULATES AND RETURNS THE RANGE AS TWO VALUES.
	CALL INDARG		;READ IN THE STRING.  ST+1 HAS 1ST CHAR.
	TRNN FF,FRARG2
	 JRST FFINDA
	ADD C,BEG		;2 ARGS GIVE RANGE TO SCAN.  CONVERT TO INTERNAL CHAR ADDRS.
	ADD E,BEG
	CALL CHKC		;BARF IF E NOT IN BUFFER.
	CALL CHK		;BARF IF C NOT IN BUFFER.
	MOVEM E,PT		;1ST ARG SAYS WHERE TO START THE SCAN.
	MOVE OUT,C		;2ND ARG SAYS WHERE TO STOP.
	SUB C,E			;SIGN OF C GETS DIRECTION OF SEARCH (AS IF JUST 1 ARG).
	JRST FFINDZ

FFINDA:	SKIPL C			;HERE FOR JUST 1 ARG.  OUT GETS PLACE TO STOP SCAN.
	 SKIPA OUT,ZV
	  MOVE OUT,BEGV
FFINDZ:	MOVE IN,PT		;J POINTS AT WORD AFTER THE LAST CHAR IN BAKTAB.
	CALL GETIBI		;GOING FWD => GET B.P. TO ILDB CHAR AFTER POINT.
	JUMPL C,FFINDB		;GOING BACKWARD => ALTER THAT.
FFINDC:	CAMN IN,OUT		;IN AND PT ARE THE SAME.  BP HAS B.P. TO ILDB CHAR AT PT.
	 RET
	CAMN IN,GPT		;HANDLE MOVING ACROSS THE GAP.
	 CALL FEQGAP
	ILDB CH,BP
FFINDS:	MOVEI A,BAKTAB		;HERE FOR EITHER FWD OR BACKWD SCAN, TO SEE IF CHAR IS IN
FFIND1:	CAMN A,J		;THE STRING.
	 JRST [	TRNN FF,FRCLN	;NO => FOR NON-COLON, WE HAVE FOUND END OF RANGE.
		 RET
		JRST FFIND2]
	CAME CH,(A)
	 AOJA A,FFIND1
	TRNE FF,FRCLN		;YES => FOR @:F^B WE HAVE FOUND THE END OF THE RANGE.
	 RET
FFIND2:	JUMPL C,FFINDD		;NOT AT END => MOVE TO NEXT CHARACTER.
	AOS IN,PT
	JRST FFINDC

FFINDB:	IBP BP			;MOVE BACKWARRD, THE FIRST TIME.
	CAIA
FFINDD:	 SOS IN,PT		;MOVE BACKWARD AGAIN.
	CAMN IN,OUT
	 RET
	CAMN IN,GPT
	 CALL DWNGAP
	DBP7 BP
	LDB CH,BP
	JRST FFINDS

;READ IN A STRING ARG, AND SAVE IT 1 CHAR PER WORD IN BAKTAB.
;LEAVE J -> LAST WORD USED IN BAKTAB + 1. USED BY @F^B.
;CLOBBERS A, CH.
INDARG:	MOVEI J,BAKTAB
INDA1:	CALL RCH
	SKIPE SQUOTP
	 JRST INDA2
	CAIN CH,ALTMOD
	 RET
INDA2:	CAIN J,BAKTAB+LTABS
	 TYPRE [STL]
	HRRZM CH,(J)
	AOJA J,INDA1

SUBTTL WORD AND LIST PARSING COMMANDS
 
FWCMD:	MOVEI BP,WORDSP
	JRST .+2
FLCMD:	MOVEI BP,LISTSP
FLCMD1:	ARGDFL Z
	CALL IMMQIT	;ALLOW IMMEDIATE QUITTING IN CASE WE HAVE FAR TO SEARCH.
	SAVE PT
	SETZM SEXPFL
	CALL (BP)
	MOVE E,PT
	REST C
	MOVEM C,PT
	CAMGE C,E
	 EXCH C,E
	SUB C,BEG
	SUB E,BEG
	MOVEM E,SARG
	MOVE A,C
	TRZ FF,FRUPRW+FRCLN
	TRO FF,FRARG2
	SETZM IMQUIT	;STOP ALLOWING IMMEDIATE QUITTING.
	JRST POPJ1

FUCMD:	JSP BP,FLCMD1
	SETZM DOWNF
	MOVM D,C
	MOVNS D
FUCMD1:	JUMPE D,CPOPJ
	HLRES C
	JRST LISTSQ

FDCMD:	JSP BP,FLCMD1
	SETOM DOWNF
	MOVM D,C
	JRST FUCMD1

;THIS ROUTINE TAKES ARG IN C, AND DOES <ARG>FWL.
;FS INSLEN IS SET TO LENGTH OF LAST WORD OR INTER-WORD-SPACE SEEN
;(NOTE IF YOU START WITHIN A WORD, FS INSLEN$ MIGHT NOT BE WHAT YOU WANT).
;IF SEXPFL IS SET, ASSUMES WAS REACHED FROM @FL, AND GOES BACK THERE
;AFTER FINDING ONE WORD.
;THE UPARROW FLAG CAUSES SCANNING TO BE FOR LISP ATOMS INSTEAD OF WORDS.
WORDSP:	CALL SKNBCP	;INITIALIZE SO WE CAN CALL SKNBRK.
	TRNE FF,FRUPRW
	 IBP SKNBPT	;FOR LISP, USE 2ND CHAR OF DISPATCH ENTRY RATHER THAN 1ST.
	JUMPL C,WBACK
	JUMPE C,CPOPJ
	CALL LFINIT	;SET UP E, IN, BP.
WFVBA1:	SKIPE SEXPFL	;HERE TO START WORD-GAP, TREATING LAST CHAR SEEN AS PART OF PREV. WORD.
	 JRST LFLOOP
	MOVE B,E	;SAVE E IN B EVERY SO OFTEN. E-B WILL BE VALUE OF INSLEN.
	SOSA B
WFSBEG:	 MOVE B,E	;LIKE WFVBA1, BUT COUNT LAST TERMINATOR AS PART OF THIS GAP.
	SKIPE SEXPFL
	 JRST LFDSP
WFSLUP:	SOJLE E,WFSEOB
	CAMN E,IN	;IF WE'VE REACHED THE GAP,
	 CALL FEQGAP	;MAKE BP POINT ABOVE IT.
	ILDB A,BP
	LDB A,SKNBPT
	CAIE A,";
	 CAIN A,"A
	  JRST WFSEND
	CAIN A,"+
	 JRST WFSEND
	CAIE A,"/
	 CAIN A,"|
	  JRST WFSEND
	JRST WFSLUP

WFSEND:	TRNE FF,FRCLN
WFVBA2:	 SOJLE C,WFDONC
	MOVE B,E
	CAIN A,"|
	 JRST WFVBAR	;WIN IN CASES LIKE |FOO||BAR|
	JRST WFWDSP	;NOW PROCESS CHAR THAT STARTS THE WORD AS IF FOUND IT INSIDE WORD

;HERE WHEN A :FW FINDS START OF WORD AND THINK'S IT IS FINISHED.
WFDONC: TRNN FF,FRUPRW	;IF IT WAS AN @:FW, AND LAST CHAR WAS A ', BACK UP OVER IT.
	 JRST WFDONE
	CAMN E,IN
	 CALL DWNGAP
	AOS E		;AND KEEP BACKING UP PAST ALL '-TYPE CHARS.
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
	CAIN A,"'
	 JRST WFDONC
	SOJA E,WFDONE

WFWLUP:	SOJLE E,WFWEOB
	CAMN E,IN	;IF WE'VE REACHED THE GAP,
	 CALL FEQGAP	;MAKE BP POINT ABOVE IT.
	ILDB A,BP
	LDB A,SKNBPT
WFWDSP:	CAIE A,";
	 CAIN A,"A
	  JRST WFWLUP
	CAIN A,"+
	 JRST WFWLUP
	CAIN A,"'	;' CHARS CAN CONTINUE A WORD, BUT NOT START ONE.
	 JRST WFWLUP
	CAIN A,"/
	 JRST WFSLSH
	CAIN A,"|	;| INSIDE WORD IS CASE OF FOO|BAR|, WHICH IS 2 WORDS,
	 JRST [	TRNE FF,FRCLN	;SO END THIS WORD AND IMMEDIATELY START ANOTHER.
		 MOVE B,E
		JRST WFVBA2]
WFWEND:	TRNE FF,FRCLN
	 JRST WFSBEG
	SOJG C,WFSBEG
WFDONE:	SUB B,E
	SUB E,ZV
	MOVNS E
	JRST WORD12

WFSEOB:	TRC FF,FRCLN	;WENT FWD PAST Z, BETWEEN WORDS.
WFWEOB:	SOJG C,TYPNIB	;WENT FWD PAST Z, IN MIDDLE OF WORD.
	TRNE FF,FRCLN
	 JRST TYPNIB
	JRST WFDONE

WFSLSH:	CALL LFSLSH	;HANDLE A SLASH-CHARACTER GOING FORWARD.
	JRST WFWLUP

WFVBAR:	CALL LFVBAR	;VERTICAL BAR:  SKIP TO MATCHING ONE.
	TRNN FF,FRCLN	;IF TIME TO STOP MOVING, MAKE SURE CLOSING VBAR
	 SOJLE C,[SOJA E,WFDONE] ;COUNTS AS PART OF WORD, NOT PART OF GAP.
			;IF MUST KEEP GOING, DO SO, BUT DON'T COUNT
	JRST WFVBA1	;THE VBAR AS PART OF THE GAP THAT'S STARTING.

;MOVE BACKWARDS OVER WORDS.

WBACK:	MOVMS C
	CALL LBINIT	;SET UP BP, E, IN.
WBVBA1:	SKIPE SEXPFL
	 JRST LBLOOP
	MOVE B,E
	SOSA B
WBSBEG:	 MOVE B,E
	SKIPE SEXPFL
	 JRST LBDSP
WBSLUP:	SOJL E,WBSEOB
	CAMN E,IN	;IF WE'VE REACHED THE GAP,
	 CALL DWNGAP	;MAKE BP POINT BELOW IT.
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
	CAIE A,"A
	 CAIN A,"|
	  JRST WBSEND
	CAIE A,"+
	 CAIN A,";
	  JRST WBSEND
	CAIE A,"/
	 JRST WBSLUP
WBSLSH:	SAVE E		;FOUND A SLASH GOING BACKWARD.
	SAVE BP		;IF IT'S SLASHED, IT ENDS A WORD; ELSE FOLLOWING CHAR
	CALL REALP	;IS SLASHED AND ENDS THE WORD.
	 JFCL		;BIT 1.1 OF CH IS 1 IF SLASH IS SLASHED.
	REST BP
	REST E
	TRNE CH,1
	 JRST WBSEND
	IBP BP
	AOJ E,
WBSEND:	TRNE FF,FRCLN
WBVBA2:	 SOJLE C,WBDONE
	MOVE B,E
	CAIN A,"|
	 JRST WBVBAR
	JRST WBWDSP

WBWLUP:	SOJL E,WBWEOB
	CAMN E,IN	;IF WE'VE REACHED THE GAP,
	 CALL DWNGAP	;MAKE BP POINT BELOW IT.
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
WBWDSP:	CAIE A,";
	 CAIN A,"A
	  JRST WBWLUP
	CAIN A,"+
	 JRST WBWLUP
	CAIN A,"|
	 JRST [	TRNE FF,FRCLN
		 MOVE B,E
		JRST WBVBA2]
	CAIE A,"'
	CAIN A,"/
	 JRST WBWLUP
	SAVE BP
	SAVE E
	CALL REALP
	 JFCL
	REST E
	REST BP
	TRNE CH,1
	 JRST WBWLUP
WBWEND:	TRNE FF,FRCLN
	 JRST WBSBEG
	SOJG C,WBSBEG
WBDONE:	SUBM E,B
	AOJ E,
	ADD E,BEGV
WORD12:	MOVEM E,PT
	MOVEM B,INSLEN
	TRZ FF,FRCLN+FRUPRW
	RET

WBSEOB:	TRC FF,FRCLN
WBWEOB:	SOJG C,TYPNIB
	TRNE FF,FRCLN
	 JRST TYPNIB
	JRST WBDONE

WBVBAR:	CALL LBVBAR	;MOVE BACK OVER A VERTICAL BAR GROUPING.
WBVBA4:	JUMPE E,WBVBA3	;THEN BACK OVER ALL ' CHARACTERS BEFORE IT.
	SAVE E
	SAVE BP
	SOJ E,
	CAMN E,IN	;IF WE'VE REACHED THE GAP,
	 CALL DWNGAP	;MAKE BP POINT BELOW IT.
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
	CAIN A,"'
	 JRST [	SUB P,[2,,2]
		JRST WBVBA4]
	REST BP
	REST E
WBVBA3:	TRNN FF,FRCLN	;IF IT'S TIME TO STOP MOVING, SAY WE STOPPED AFTER PASSING THE
	 SOJLE C,[SOJA E,WBDONE] ;VBAR, INSTEAD OF BEFORE, AS WE WOULD STOP AT A SPACE.
	JRST WBVBA1	;IF KEEP MOVING, DON'T INCLUDE THE VBAR IN THE NEW GAP.

LISTSP:	TRNE FF,FRUPRW
	 SETOM SEXPFL
	SETZB D,DOWNF
	JUMPE C,CPOPJ
LISTSQ:	CALL SKNBCP	;SET UP SKNBPT FROM ..D
	IBP SKNBPT
	JUMPL C,LBACK
	CALL LFINIT	;SET UP BP, E, IN.
LFLOOP:	SOJLE E,LFEOB	;AFTER THIS INSN E HAS # CHARS LEFT TO SCAN.
	CAMN E,IN	;IF WE'RE ABOUT TO ILDB INTO THE GAP, CROSS IT:
	 CALL FEQGAP	;(BP <- BP TO ILDB 1ST CHAR AFTER GAP).
	ILDB A,BP
	LDB A,SKNBPT	;GET DISPATCH ENTRY OF THIS CHARACTER.
LFDSP:	CAIN A,"/
	 JRST [	TRNE FF,FRUPRW	;FOR @FL, REMEMBER SLASH STARTS AN ATOM.
		 JUMPE D,WFSEND
		CALL LFSLSH
		JRST LFLOOP]
	CAIN A,"|
	 JRST [	TRNE FF,FRUPRW
	 	 JUMPE D,WFSEND
		CALL LFVBAR
		JRST LFLOOP]
	CAIE A,";
	 CAIN A,"A		;SEMICOLON AND LETTERS START ATOMS.
	  TRNN FF,FRUPRW
	   JRST LFFOO1
	JUMPE D,WFSEND
LFFOO1:	CAIN A,"(
	 JRST LFLPAR
	CAIE A,")
	 JRST LFLOOP
	SKIPE DOWNF
	AOJA D,LFLOOP
	AOJL D,LFLOOP
	SETZ D,		;MAKE SURE 2FLL SAME AS FLL FLL.
	SOJG C,LFLOOP
LFDONE:	SUB E,ZV
	TRC FF,FRCLN
	JRST LISTX

LFEOB:	JUMPL D,[TYPRE [UBP]]	;UNBALANCED PARENTHESES
TYPNIB:	TYPRE [NIB]

LFSLSH:	SOJLE E,TYPUEB	;HANDLE "/" GOING FORWARD.
	CAMN E,IN	;IF WE'VE REACHED THE GAP, MAKE BP CROSS IT.
	 CALL FEQGAP
	IBP BP
	RET

TYPUEB:	TYPRE [UEB]

LFLPAR:	TRNE FF,FRCLN	;:FL => STOP BEFORE ( INSTEAD OF AFTER IT AS FOR FD.
	 JUMPE D,[SOJE C,LFCDON	;ALSO, :FL BACKS OVER ''S WHILE FD DOESN'T.
		  AOJA C,.+1]
	SKIPN DOWNF
	 SOJA D,LFLOOP
	SOJG D,LFLOOP
	JRST LFDONE

LFCDON:	MOVNS E
	ADD E,ZV	;TURN INTO CHAR ADDR OF THE (.
	TRZ FF,FRCLN	;DON'T LET LISTX MUNG IT.
	TRNE FF,FRUPRW	;FOR @:FL,
LFCDO1:	 CAMG E,BEGV	;SCAN BACKWARD PAST ANY QUOTES BEFORE THE (.
	  JRST LISTX
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
	CAIN A,"'
	 SOJA E,LFCDO1
	JRST LISTX

LFVBAR:	SOJLE E,TYPUEB	;HANDLE "|" GOING FORWARD.
	CAMN E,IN
	 CALL FEQGAP	;WHEN REACH GAP, MOVE OVER IT.
	ILDB A,BP
	LDB A,SKNBPT	;DECODE NEXT CHARACTER.
	CAIN A,"/
	 JRST [	CALL LFSLSH	;SLASH => DON'T CHECK NEXT CHAR FOR BEING A "|".
		JRST LFVBAR]
	CAIE A,"|
	 JRST LFVBAR	;FIRST UNSLASHIFIED "|" ENDS THE STRING.
	RET

;MOVE BACKWARD OVER LISTS.

LBACK:	MOVMS C
	CALL LBINIT	;SET UP BP, E, IN.
LBLOOP:	SOJL E,LFEOB
	CAMN E,IN	;IF ABOUT TO DLDB INTO LAST CHAR OF GAP,
	 CALL DWNGAP	;MAKE BP -> LOWEST CHAR. OF GAP.
	DBP7 BP
LBDSP:	LDB A,BP
	LDB A,SKNBPT
	CAIN A,"|
	 JRST [	TRNE FF,FRUPRW
		 JUMPE D,WBSEND
		CALL LBVBAR
		JRST LBLOOP]
	TRNN FF,FRUPRW	;IF @FL, NOTE THAT LETTERS AND SLASH START ATOMS
	 JRST LBFOO1
	CAIN A,"A
	 JUMPE D,WBSEND
	CAIN A,"/	;FOR SLASH, THE CHAR AFTER IT (ALREADY SCANNED)
	 JUMPE D,WBSLSH	;IS ALSO PART OF THE ATOM.
LBFOO1:	CAIN A,")
	 JRST LBRPAR
	CAIE A,"(
	 JRST LBLOOP
	CALL REALP
	 JRST LBQOTD
	SKIPE DOWNF
	 AOJA D,LBLOOP
	AOJL D,LBLOOP
	SETZ D,
	SOJG C,LBLOOP
	TRNN FF,FRUPRW	;FOUND MATCHING OPENPAREN.  NOW, IF PASSING SEXPS,
	 JRST LBDONE
LBQOT1:	MOVE B,E	;SKIP OVER ANY NO-SLASHIFIED '-LIKE CHARACTERS
	SOJL E,LBQOT2	;THAT PRECEDE THE OPENPAREN.
	CAMN E,IN
	 CALL DWNGAP
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
	CAIN A,"'
	 CALL REALP
LBQOT2:	  SKIPA E,B
	   JRST LBQOT1
LBDONE:	ADD E,BEGV
LISTX:	MOVMM E,PT
	TRZE FF,FRCLN
	 AOS PT
	POPJ P,

LBVBAR:	CALL REALP	;HANDLE "|" GOING BACKWARDS.
	 RET
LBVBLP:	SOJL E,TYPUEB
	CAMN E,IN
	 CALL DWNGAP
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
	CAIN A,"|
	 CALL REALP
	  JRST LBVBLP
	RET

LBRPAR:	CALL REALP	;HANDLE ")", MOVING BACKWARD.
	 JRST LBQOTD
	TRNE FF,FRCLN
	 JUMPE D,[SOJE C,LBDONE
		AOJA C,.+1]
	SKIPN DOWNF
	 SOJA D,LBLOOP
	SOJG D,LBLOOP
	JRST LBDONE

LBQOTD:	MOVEI A,"A		;SLASHIFIED PAREN HAS "ALPHABETIC" SYNTAX
	TRNE FF,FRUPRW		;AND CAN START (END?) AN ATOM.
	 JUMPE D,WBSEND
	JRST LBLOOP

;INITIALIZATION AND AUXILIARY ROUTINES FOR FW AND FL.

;SET UP BP, E, IN  FOR GOING FORWARD.
LFINIT:	MOVE BP,PT
	CAML BP,GPT
	 ADD BP,EXTRAC	;GET REAL CHAR ADDR OF CHAR AFTER PT.
	CALL GETIBP
	MOVE IN,ZV
	SUB IN,GPT	;THIS IS WHAT E WILL HAVE WHEN GAP IS REACHED.
	MOVE E,ZV
	SUB E,PT
	AOJA E,CPOPJ

;BP GETS A B.P. TO THE 1ST CHARACTER OF THE GAP, TO DLDB INTO THE REGION
;BELOW THE GAP.
DWNGAP:	MOVE BP,GPT
	JRST GETBP

;SET UP BP, E, IN  FOR GOING BACKWARD.
LBINIT:	MOVE BP,PT
	CAMLE BP,GPT	;BP GETS REAL CHAR ADDR +1 OF CHAR BEFORE PT.
	 ADD BP,EXTRAC	
	CALL GETBP	;BP SET UP FOR DLDB.
	MOVE E,PT
	SUB E,BEGV
	MOVE IN,GPT	;IN USED FOR DETECTING THAT GAP IS REACHED.
	SUB IN,BEGV	;CHECK: IF PT = GPT NOW, E WILL = IN THE FIRST TIME THRU.
	SOJA IN,CPOPJ

;DURING BACKWARD SCAN, CHECK WHETHER THE CHAR JUST REACHED WAS SLASHIFIED.
;MOVES BP AND E BACK OVER THE SLASHES, LEAVES THEM AS IF 1ST OF THE SLASHES
;WAS JUST GOBBLED. IF # SLASHES IS EVEN (CHAR IS NOT SLASHIFIED),
;BIT 1.1 OF CH WILL BE 0, AND REALP WILL SKIP.
REALP:	SETZI CH,
REALP3:	SOJL E,REALP1
	CAMN IN,E
	 CALL DWNGAP
	DBP7 BP
	LDB A,BP
	LDB A,SKNBPT
	CAIN A,"/
	 AOJA CH,REALP3
	IBP BP
REALP1:	AOJ E,
	TRNN CH,1
	 AOS (P)
	POPJ P,

;F^F IS TH HAIRY FORWARD-ONLY LIST PARSER.
;IT TAKES A "STATE" WHICH INCLUDES THE PAREN DEPTH AS AN ARGUMENT,
;PARSES FROM POINT TO A SPECIFIED PLACE, AND RETURNS THE UPDATED STATE.
;DO <OLD STATE>,<PLACE TO STOP PARSING>F^F AND IT RETURNS THE NEW STATE.
;THE STATE'S RH IS TH PAREN DEPTH.  THE LH IS BITS, AS FOLLOWS:
; 100,, => INSIDE A COMMENT.
; 4,, => INSIDE VERTICAL BARS.
; 2,, => INSIDE OR RIGHT AFTER AN ATOM.
; 1,, => SLASHIFIED.
;WE ARE INSIDE (AS OPPOSED TO ADJACENT TO) AN ATOM IF 4,, OR 1,, IS SET,
;OR IF 2,, IS SET AND THH NEXT CHARACTER HAS A OR / SYNTAX.
;WHEN WE RETURN, Q..0 GETS THE ADDRESS AFTER THE LAST OPEN-| OR ; SEEN;
;Q..1 GETS THE ADDRESS OF THE LAST UNMATCHED (, OR -1;
;Q..2 GETS THE ADDRESS OF THE START OF THH LAST SEXP, OR -1.

;SCANNING STOPS WHEN IT REACHES THE SPECIFIED ADDRESS,
; OR WHEN THE PAREN DEPTH REACHES 0.
;FOR :F^F, SCAN ALSO STOPS WHEN AFTER ANY ATOM-START CHARACTER.


FCTLF:	TRZE FF,FRARG
	 TRZN FF,FRARG2
	  TYPRE [WNA]	;WE MUST HAVE 2 ARGS.  AND DISCARD THEM.
	SETZ OUT,
	TRZE FF,FRCLN	;OUT GETS BITS OF STATE WHICH ARE TERMINATING CONDITIONS.
	 MOVSI OUT,7
	ADD C,BEG
	CALL CHK	;CALCULATE AND VALIDATE ADDRESS TO STOP SCANNING AT.
	CALL SKNBCP
	IBP SKNBPT	;SKNBPT IS B.P. TO LDB LISP SYNTAX OF CHAR IN CH.
	MOVEI TT,CH		;PUT "CH" IN INDEX FIELD TO MAKE THAT TRUE.
	DPB TT,[220600,,SKNBPT]
	SKIPGE A,E	;KEEP THE STATE IN A.  NEGATIVE NUMBER AS ARG
	 ANDI A,-1	;MEANS A NEGATIVE PAREN DEPTH, WITH STATE BITS 0.
	MOVE CH,QRB..
	SETOM .Q..0(CH)	;SO FAR WE HAVE NOT SEEN ANY ( OR |.
	MOVE IN,PT
	CALL GETIBI	;IN GETS SCAN POINT AS VIRT ADDR, BP GETS BP TO ILDB.
	CAMLE IN,C
	 TYPRE [2%1]
	MOVE Q,P
	SETZB D,B	;D HAS ADDR+1 OF START OF SEXP THHT ENDED LAST, OR 0.
			;B HAS STATE BEFORE LAST CHARACTER SCANNED.
FCTLFL:	TLNN B,7	;IF LAST CHAR WASN'T IN OR AFTER AN ATOM,
	 TLNN A,7	;AND THIS ONE WAS,
	  CAIA		;THEN WE HAVE JUST STARTED AN ATOM,
	   MOVE D,IN	;SO REMEMBER . AS ADDR+1 OF LAST SEXP'S START.
	MOVE B,A
	TDNN A,OUT	;STOP CONDITION MET OR REACHED END OF RANGE =>
	 CAMN IN,C	;RETURN, SETTING APPRO. Q-REGS.
	  JRST FCTLFX
	CAMN IN,GPT
	 CALL FEQGAP	;WHEN WE COME TO TH GAP, MOVE TH B.P. OVER IT.
	AOS IN,PT
	ILDB CH,BP
	TLZE A,1	;PREVIOUS CHARACTER WAS SLASH => DON'T CHECK THIS ONE.
	 JRST FCTLFL
	TLZ A,2
	LDB CH,SKNBPT
	TLNE A,100	;INSIDE A COMMENT, ONLY CR IS INTERESTING.
	 JRST [	CAIN CH,^M
		 TLZ A,100
		JRST FCTLFL]
	CAIN CH,"/
	 JRST [	TLO A,3
		JRST FCTLFL]
	CAIN CH,"|
	 JRST [	MOVE CH,IN	;| => COMPLEMENT IN-|-NESS,
		SUB CH,BEG	;AND IF THIS IS ENTERING A PAIR,
		TLCN A,4 	; REMEMBER THE ADDRESS IN Q..0.
		 MOVEM CH,@QRB..
		JRST FCTLFL]
	TLNE A,4
	 JRST FCTLFL		;WITHIN VERTICAL BARS => ONLY | AND / ARE SPECIAL.
	CAIN CH,";
	 JRST [	MOVE CH,IN	;ELSE ; STARTS A COMMENT, AND REMEMBER ITS ADDRESS.
		SUB CH,BEG
		MOVEM CH,@QRB..
		TLO A,100
		JRST FCTLFL]
	CAIN CH,"A
	 TLO A,2
	CAIN CH,"(
	 JRST [	HRRI A,1(A)	;( => PUSH ITS ADDRESS+1 SO WE CAN
		PUSH P,IN	;FIND THE LAST UNMATCHED ONE.
		JRST FCTLF1]	;ALSO INCREMENT THE DEPTH COUNTER.
	CAIE CH,")
	 JRST FCTLFL
	CAME Q,P		;) => POP ADDR+1 OF THE MATCHING (, IF ANY.
	 POP P,D		;IT BECOMES THE ADDR+1 OF THE LAST SEXP TO START.
	HRRI A,-1(A)		;DECREMENT THE DEPTH.
FCTLF1:	TRNE A,-1		;IF THE DEPTH EVER BECOMES 0 AFTER A PAREN, EXIT.
	 JRST FCTLFL
FCTLFX:	CAME Q,P		;EXIT:  GET ADDRESS OF LAST UNMATCHED (,
	 SOSA IN,(P)		;OR -1 IF THERE IS NONE.
	  SKIPA IN,[-1]
	   SUB IN,BEG
	MOVE CH,QRB..
	MOVEM IN,.Q..1(CH)	;STORE THAT IN Q..1
	SOSLE D
	 SUB D,BEG		;TURN D INTO REL CHAR ADDR OF
	MOVEM D,.Q..2(CH)	;THE START OF THE LAST SEXP.  PUT IN Q..2
	MOVE P,Q		;FLUSH SAVED ( ADDRESSES FROM THE STACK.
	JRST POPJ1		;RETURN THE NEW STATE, WHICH IS IN A.

SUBTTL MISCELANEOUS F- COMMANDS

;FX<Q> - PUT TEXT INTO <Q> AND DELETE IT.  FX* RETURNS THE TEXT.
;AC D HAS # CHARS BUFFER WAS MOVED (BY CREATION OF THE STRING)
FXCMD:	CALL QREGVS	;THIS CAN MAKE US SKIP!
	CALL GETANU	;TAKES ARGS LIKE X, K, ETC.
	SKIPA
FXCMD2:  SETZ B,	;HERE WITH CH POINTING AT QREG, ASSUMED NOT IN A QVECTOR.
	SAVE C
	SAVE E		;REMEMBER BOTH ON PDL.
	SAVE BEG	;X10 MAY MOVE BUFFER, MUST KNOW HOW MUCH.
	CALL X12	;GO PUT IN QREG (WHICH MIGHT BE AC A - SEE QREGVS)
	REST D
	SUB D,BEG	;-<# CHARS BUFFER MOVED UP>
	REST E
	REST C		;GET THE ENDS BACK,
	MOVNS D
	ADD E,D		;RELOCATE REMEMBERED PTRS.
	ADD C,D
	MOVEM C,PT
	JRST DELET1

FTYI:	CALL DISMDI	;UPDATE MODE DISPLAY (Q..J) IF NEC.
	SKIPL UNRCHC
	 JRST FTYI1
	TTYACT		;MAKE SURE NEXT CHARACTER ACTIVATES - UNLESS WE ALREADY HAVE IT.
FTYI1:	CALL TYI
	TRZE FF,FRCLN	;:FI READS CHAR AND DOESN'T GOBBLE.
	 MOVEM CH,UNRCHC
	TRZN FF,FRUPRW	;@FI RETURNS UNNORMALIZED CHARACTER.
	 CALL TYINRM	;NORMAL FI RETURNS NORMAILZED CHARACTER.
	MOVE A,CH
	JRST POPJ1

CNTRUP:	CALL RCH	;^^ - RETURN ASCII FOR NEXT CHAR IN CMD STRING.  [
	MOVEI A,(CH)	;DISCARD LH, WHICH IS NONZERO FOR ^]^Q'D CHAR.
	JRST POPJ1

;? COMMAND, COMPLEMENT TRACE MODE.  :? TURNS OFF TRACE MODE.
QUESTN:	TRNE FF,FRCLN
	 TRZA FF,FRTRACE
	  TRC FF,FRTRACE
QUEST1:	MOVSI A,(JRST)
	TRNN FF,FRTRACE
	 MOVSI A,(RET)
	HRRI A,TYOS
	MOVEM A,TRACS
	POPJ P,

FCTLAT:	CALL GETARG	;F^@ - TAKES RANGE OF BUFFER,
	 JFCL
	CAMG C,E	;RETURNS 2 ARGS DELIMITING THAT RANGE
	 EXCH C,E	;IN NUMERIC ORDER.  2,1F^@ GIVES 1,2.
	MOVE B,E
	MOVE A,C
	ANDCMI FF,FRARG+FRARG2
	JRST HOLE0

;F*<STRING>$ -- NO-OP.
;[ ;MAINLY USEFUL FOR F*^]^X$
FNOOP:	JSP B,RDALTC
	 POPJ P,
	JRST FNOOP

;READ 1 CHAR OF STRING ARG, TURNING UNQUOTED DOLLARSIGNS TO ALTMODES.
;AT END OF ARG, FAIL TO SKIP.
RDALTC:	PUSHJ P,RCH
	SKIPE SQUOTP
	 JRST 1(B)
	CAIN CH,ALTMOD
	JRST (B)
	CAIN CH,"$
	MOVEI CH,ALTMOD
	JRST 1(B)

;^V WITH ARG -- PUSH ARGUMENT ON RING BUFFER OF PT. RETURNS NO VALUE.
;NORMALLY, DOESN'T PUSH IF ARG SAME AS CURRENT TOP. :^V PUSHES IN ANY CASE.
FSPSPT:	MOVE E,FSPSPP	;GET RING BUFFER POINTER.
	LDB CH,E	;GET LAST VALUE PUSHED.
	TRZE FF,FRCLN	;UNLESS THIS IS :^V,
	 JRST FSPSP1
	CAMN C,CH
	 RET		;DON'T PUSH THE SAME THING TWICE IN A ROW.
FSPSP1:	CAMN E,[4400,,FSPSPB+FSPSPL-1]
	 SUBI E,FSPSPL	;AT END, RING AROUND TO BEGINNING.
	IDPB C,E
	MOVEM E,FSPSPP
	RET

;^V COMMAND -- WITHOUT ARG, POP TOP OF RING BUFFER OF PT INTO PT;
;THEN RETURN WHAT REMAINS ON TOP OF RING BUFFER (IF THAT VALUE IS
;PUT IN Q..I, THE TOP-LEVEL WILL AVOID PUSHING WHEN IT IS NEXT ENTERED).
;:^V RETURNS VALUE ON TOP OF RING BUFFER.
;^V WITH ARG PUSHES - SEE ABOVE.
CTLV:	TRNE FF,FRARG
	 JRST FSPSPT
POPPT:	MOVE E,FSPSPP
	MOVE A,(E)	;GET LAST THING PUSHED.
	TRZE FF,FRCLN
	 JRST POPJ1	;:^V JUST RETURNS VALUE ON TOP OF RING BUFFER.
	ADD A,BEG	;PREPARE TO SET PT FROM IT.
	SUBI E,1	;DECREMENT THE RING BUFFER POINTER.
	CAMN E,[4400,,FSPSPB-1]
	 ADDI E,FSPSPL
	MOVEM E,FSPSPP
	MOVE C,A	;TAKE THE VALUE JUST POPPED.
	CALL CHK	;ERR OUT IF IT ISN'T INSIDE THE BUFFER.
	MOVEM A,PT	;JUMP THERE IF IT IS.
	MOVE A,(E)	;RETURN WHAT IS NOW AT THE TOP.
	JRST POPJ1

;<N>^Z -- INSERT <N> RANDOM LETTERS BEFORE PT.
;^Z WITHOUT ARG -- RETURN A RANDOM NUMBER.
RANDOM:	ARGDFL
	JUMPE C,RNDNUM
	JUMPLE C,CPOPJ
	CALL SLPGET	;INSERT C(C) CHARS, RET. BP. IN BP.
RNDLUP:	MOVSI A,123467
	FMPB A,RDMNMS
	IDIVI A,26.
	MOVEI CH,"A(B)
	IDPB CH,BP
	SOJG C,RNDLUP
	POPJ P,

RNDNUM:	MOVSI A,132476
	FMPB A,RDMNMS
	TLZ A,400000
	JRST POPJ1

SUBTTL COMMUNICATION WITH SUPERIOR JOB

FSEXI1:	TLZ FF,FLDIRDPY	;COME HERE TO HANDLE ^C TYPED AT TECO COMMAND READER.
	MOVEI C,100000
FSEXIT:	MOVEI B,BEG	.SEE CIRC
IFN ITS,.BREAK 16,(C)	;FS EXIT
IFN TNX,JRST .EXIT
	RET

SUPCMD:	MOVE C,SUPARG	;JUMP HERE IF SUPERIOR STARTS TECO AT BFR BLOCK + 7.
	MOVEM C,NUM	;FETCH THE ARG IN BFR BLOCK + 8, AND MAKE IT CURRENT ARGUMENT.
	TRO FF,FRARG
	SKIPE A,SUPHND	;IF TECO MACRO HANDLER SUPPLIED, RUN IT GIVING IT
	 JRST MAC5	;THE ARG OUR SUPERIOR GAVE.
	CALL GAPSLP
	SKIPLE C	;OTHERWISE, IF ARG IS POSITIVE INSURE AT LEAST THAT MUCH GAP.
	 CALL SLPGET
	MOVEI C,500000	;DO AN $X RETURN IN CASE $X'ING FROM DDT.
	JRST FSEXIT

;^K<STRING>$ -- VALRET <STRING>.
DECDMP:	CALL DECDMX	;FORMULATE STRING
	MOVEI B,BEG	.SEE CIRC
	SKIPGE PJATY	;MAKE SURE WE DON'T CLEAR PJATY IF IT WAS ALREADY ON.
	 TRZ FF,FRUPRW
IFN ITS,.VALUE (A)	;SUPERIOR EXPECTS 2 TO POINT TO BEG
IFN TNX,[
	HRLI A,440700
IFN 20X,[
	RSCAN		;BEST WAY WE HAVE TO RETURN A STRING TO THE EXEC
	 TDN
	SETZ A,
	RSCAN
	 TDN
]
.ELSE	[
	MOVE CH,A	;BYTE POINTER TO CHARS TO DO
	MOVEI A,.CTTRM
DECDM2:	ILDB B,CH
	JUMPE B,DECDM3
	STI		;STUFF INTO TERMINAL'S INPUT BUFFER
	JRST DECDM2
DECDM3:
]
	CALL .EXIT
]
	TRZE FF,FRUPRW
	 SETZM PJATY	;@ FLAG => SUPPRESS AUTOMATIC REDISPLAY.
	POPJ P,

DECDMX:	CALL MEMTOP	;GET ADDR OF 1ST WD ABOVE BFR IN A.
	AOS OUT,A
	IMULI OUT,5	;GET CHAR ADDR 1ST CHAR IN THAT WD.
	SUB OUT,EXTRAC	;SINCE PUTINC WILL ADD EXTRAC.
	JSP B,RDALTC
	 JRST DECDM1
	CALL PUTINC	;STUFF CHARS THERE, ABOVE BUFFER.
	JRST RDALTC

DECDM1:	SETZ CH,	;AFTER STRING, PUT ^@
	CALL PUTINC	;TO TELL DDT IT'S THE END.
	SETZM 1(TT)	;ZERO NEXT WD SO DDT WILL STOP FETCHING.
	RET

;FZ - MANIPULATE INFERIOR PROCESS
;
; FZ<STRING>$	CREATE FORK, RETURNS FORK INDEX
;		TAKES EVERYTHING UP TO THE FIRST SPACE (NOT QUOTED BY ^V) AS
;		THE FILE SPECIFICATION (NO DEFAULTS ALLOWED).  THE STRING IS
;		PLACED IN THE RESCAN BUFFER IN THE SAME FORMAT EXEC USES.
;		IE. "FILENAME JCL<CR><LF>".
; 0FZ<STRING>$	"PUSH" USING EXISTING EXEC FORK IF PRESENT.  THE STRING IS 
;		PLACED IN THE RESCAN BUFFER AND THE RESCAN BUFFER IS SET
;		FOR READING.
;-1,0FZ<STRING>$ AS ABOVE BUT THE EXISTING EXEC FORK (IF PRESENT) IS KILLED
;		FIRST, AND STRING IS INTERPRETED AS FOR AN ORDINARY FORK.
; FZ$		"PUSH"  USE EXISTING INFERIOR EXEC FORK IF PRESENT.
; NFZ<STRING>$	RESUME FORK N PLACING THE STRING IN THE RESCAN BUFFER.
; -NFZ$		KILL FORK N
;
; A PRE-COMMA ARGUMENT MAY BE SPECIFIED:
; +VE -- INDICATES THE POSITION IN THE ENTRY VECTOR AT WHICH TO START THE FORK
; -VE -- INDICATES THAT THE RESCAN BUFFER IS TO BE SET UP FOR READ BY .CTTRM
;	 BEFORE THE SUB FORK IS STARTED.  (THE CURRENT LOCATION OR THE PRIMARY
;	 START ADDRESS IS USED DEPENDING IF THE FORK ALREADY EXISTS OR NOT.)
; A -VE PRE-COMMA ARGUMENT TO AN EXEC FORK IS AN EXCEPTION (SEE ABOVE).

IFN TNX,[
FZCMD:	CALL DECDMX	;BUFFER STRING
	MOVEM A,FZSTR	; SAVE THE POINTER
	HRRO B,A
	MOVE A,0(B)	; SEE IF NULL STRING ARG
	TLNN A,774000	;
	 SETZM FZSTR	; YES SAY NO RESCAN STUFF
	GETNM		; GET THE CURRENT NAME SO WE CAN PUT IT BACK LATER
	MOVEM A,FZNAM	; AND SAVE IT
	TRZE FF,FRARG	;ARG GIVEN?
	 JRST FZCMD3	;YES - MORE CHECKING
	SKIPN FZSTR	; NO - SEE IF NULL STRING ARG
	 JRST .PUSH	;YES - DO PUSH
	CALL FZSEP	; ELSE - SEPARATE FILE NAME AND RESCAN STUFF
	CALL NEWFRK	;CREATE NEW FORK
	MOVEM B,RUNFRK	;SAVE FORK INDEX
FZCMD1:	CALL SETFRK	;SET FORK TTY STATE
IFN 20X,CALL FZRSCN	; PUT STUFF IN RESCAN BUFFER IF NECESSARY
FZCMD2:	CALL GOFRK	;START UP FORK
	MOVE A,RUNFRK	;NO - RETURN FORK INDEX
	TRZ FF,FRARG2
	JRST POPJ1	;RETURN OK

FZCMD3:	SKIPN A,NUM	;EXPLICIT 0?
	 JRST .PUSH0	;YES - MAYBE KILL OLD EXEC THEN "PUSH"
	JUMPL A,KILFRK	;IF NEGATIVE, THEN KILL FORK
	MOVEM A,RUNFRK	;SAVE FORK INDEX
	CAILE A,NFKS	;CHECK VALIDITY
	 TYPRE [AOR]
	SKIPN A,FRKTAB-1(A)
	 TYPRE [ARG]
	CALL SETFRK	;SET FORK STATES
IFN 20X,CALL FZRSCN	; PUT STUFF IN RESCAN BUFFER IF NECESSARY
	TRNN FF,FRARG2	; HAVE PRE-COMMA ARG.?
	 JRST FZCMD6	; NO, JUST GO START FORK
	SKIPL SARG	; IS IT NEGATIVE?
	 JRST FZCMD4	; NO, USE IT AS POINTER INTO ENTRY VECT.
IFN 20X,[
	SKIPN FZSTR	; IS THERE A STRING IN RESCAN?
	 JRST FZCMD6	; NO, JUST START FORK
	SAVE A
	SETZ A,
	RSCAN		; SAY WE WANT TO READ RESCAN STUFF
	 TDN
	REST A
];20X
	JRST FZCMD6	; AND GO START FORK
FZCMD4:	SAVE A
	SAVE B
	MOVE B,SARG	; GET PRE-COMMA ARG.
	SFRKV		; TRY AND START THE FORK
	REST B
	REST A
FZCMD6:	SAVE C		; SAVE AC
	SAVE A		; SAVE FORK HANDLE
	RFSTS		; GET FORK STATUS AND PC
	HLRZ C,A	; COPY FORK STATUS
	REST A		; RESTORE FORK HANDLE
	TRZE C,(RF%FRZ)	; FORK FROZEN?
	 RFORK		; YES, WARM IT UP
	CAIE C,.RFHLT	; HALTED?
	 CAIN C,.RFFPT
	  SFORK		; YES, START IT AT PC RETURNED BY RFSTS
	REST C		; RESTORE AC
	JRST WAITA	;WAIT FOR TERMINATION

; USE RESCAN BUFFER TO COMMUNICATE WITH INFERIOR
; SEPARATE THE FILE NAME AND THE JCL FOR CREATING THE FORK
FZSEP:	SKIPN FZSTR	; NOTHING HERE?
	 RET		; YES, JUST RETURN
	SAVE B		; SEPARATE FILE NAME AND RESCAN STUFF
	MOVSI A,440700
	HRR A,FZSTR	; MAKE A BYTE POINTER TO STRING
FZSEP1:	ILDB B,A	; GET A BYTE FROM STRING
	CAIN B,26	; IS IT A QUOTE (^V) CHAR?
	 JRST FZSEP2	; YES, SKIP NEXT CHAR.
	CAIN B,0	; IS IT A NULL?
	 JRST FZSEP3	; YES, ONLY FILE NAME PRESENT.
	CAIN B,40	; IS IT A SPACE?
	 JRST FZSEP4	; YES, THATS THE END OF THE FILE SPEC.
	JRST FZSEP1	; NONE OF THE ABOVE SO LOOP.
FZSEP2:	IBP A		; SKIP A CHARACTER
	JRST FZSEP1	; AND LOOP
FZSEP3:	SETZM FZSTR+1	; MARK NO JCL STUFF
	JRST FZSEP5	; AND QUIT
FZSEP4:	SETZ B,		; CLEAR OUT SPACE
	DPB B,A		; AND REPLACE IT WITH A NULL
	MOVEM A,FZSTR+1	; NEW STARTING BYTE POINTER FOR RESCAN
	ILDB B,A	; CHECK IF THERE IS ANY STUFF FOR RSCAN
	CAIN B,0	; IS FIRST BYTE NULL?
	 SETZM FZSTR+1	; YES, NO RESCAN STUFF IS THERE
FZSEP5:	REST B
	RET

; FIX RESCAN STUFF TO CONFORM WITH EXECUTIVE CONVENTION
FZFIX:	SKIPN FZSTR+1	; ANYTHING AT ALL FOR RESCAN?
	 JRST [	SETZM FZSTR	;NO, CLEAR FLAG
		RET]
	JSR SAVABC
	SAVE D
	MOVEI B,(A)	; PUT THE FORK HANDLE IN B
	HRRO A,FZSTR
	MOVE C,[001000,,000000]	; RETURN FILE NAME
	JFNS		; SO GET IT INTO STRING
	TRNN FF,FRARG2	; DO WE HAVE A PRE COMMA ARG?
	 JRST FZFIXA	; NO, DO THE FIX UP
	SKIPL SARG	; IS IT NEGATIVE
	 JRST FZFIXA	; NO, DO THE FIX UP
	SKIPN FZSTR+1	; ANYTHING TO PUT IN RESCAN
	 JRST FZFIX3	; NO, JUST QUIT
	MOVSI A,440700	; MAKE A BYTE POINTER
	HRR A,FZSTR	; TO THE START OF BUFFER
	JRST FZFIX2	; MOVE THE STRING TO THE START OF BUFFER
FZFIXA:	SKIPE FZSTR+1	; ANY JCL TO ADD TO LINE?
	 JRST FZFIX1	; YES, GO DO IT
	MOVEI B,12
	IDPB B,A	; PUT IN A ^J
	SETZ B,
	IDPB B,A	; AND A ZERO BYTE
	JRST FZFIX3	; AND QUIT
FZFIX1:	MOVEI B,40
	IDPB B,A	; AND PUT IN A SPACE
FZFIX2:	ILDB B,FZSTR+1	; GET A BYTE FROM THE JCL STRING
	IDPB B,A	; AND MOVE IT DOWN IN STRING
	SKIPLE B	; WAS THAT A NULL?
	 JRST FZFIX2	; NO, SO DO IT AGAIN
FZFIX3:	SETZM FZSTR+1
	REST D
	JRST POPCBA

IFN 20X,[
;PUT STRING IN THE RESCAN BUFFER (IF A STRING IS PRESENT)
FZRSCN:	SAVE A
	SKIPN A,FZSTR	; GET POINTER TO RESCAN STUFF
	 MOVE A,[440700,,FZSTR ]	; NO, SET UP TO CLEAR RESCAN BUFFER
	TLNN A,770700	; IS IT A BYTE POINTER ALREADY?
	 HRLI A,440700	; NO, SO MAKE IT ONE.
	RSCAN		; PUT IT IN THE RESCAN BUFFER
	 TDN
	REST A
	RET
];20X

;RUN AN EXEC PROCESS

.PUSH0:	TRNE FF,FRARG2	; DO WE HAVE A PRE-COMMA ARGUMENT?
	 SKIPL SARG	; IS IT NEGATIVE?
	 JRST .PUSH	; NO, JUST DO A .PUSH
	SKIPG A,EXECFK	; HAVE AN EXEC?
	 JRST .PUSHE
	KFORK
IFN 20X\FNX, ERJMP .+1
	SETOM EXECFK	;SAY NO EXEC
.PUSHE:	CALL FZSEP	;GET FILENAME TO RUN
	SKIPN FZSTR	;USE DEFAULT UNLESS THERE WAS STRING THERE
.PUSH:
IFN 20X, HRROI B,[ASCIZ /SYSTEM:EXEC.EXE/]
.ELSE	 HRROI B,[ASCIZ /<SYSTEM>EXEC.SAV/]
	SETZM RUNFRK	;0 - EXEC FORK INDEX
	SKIPLE A,EXECFK	;HAVE EXEC?
	 JRST FZCMD1	;YES - USE IT
	SETZM EXECFK	;FLAG TO SAVE FORK HANDLE
	CALL NEWFRK	;CREATE AN EXEC FORK
	JRST FZCMD1	;RUN EXEC AND RETURN

;KILL FORK (INDEX IN A)

KILFRK:	MOVN B,A	;GET POSITIVE INDEX
	CAILE B,NFKS	;CHECK VALIDITY
	 TYPRE [AOR]
	SKIPN A,FRKTAB-1(B)
	 TYPRE [ARG]
	KFORK		;KILL OFF FORK
IFN 20X\FNX, ERJMP .+1
	SETZM FRKTAB-1(B)
	CALL FRKTIN	;RESET TTY MODES TO DEFAULTS
	RET		;RETURN NO VALUE.

;SET UP TTY MODES FOR RUNNING INFERIOR

SETFRK:	SKIPGE PJATY	;DON'T CLEAR THIS IF ALREADY ON
	 TRZ FF,FRUPRW
	SAVE A		;SAVE FORK HANDLE
IFN EXITCL,[
	TRNN FF,FRUPRW	;UNLESS DISPLAY WILL BE LEFT ALONE
	 CALL CLRSCN	;CLEAR THE SCREEN BEFORE STARTING SUB-FORK
];EXITCL
	TRNN FF,FRUPRW	;UNLESS DISPLAY WILL BE LEFT ALONE
	 CALL DPYRST	;RESET TERMINAL (IF DPY)
	MOVE C, RUNFRK	;GET THE FORK INDEX
	MOVE A,FRKLST(C)	;GET THE SIXBIT NAME TO CALL THE FORK
	SETNM		;AND SET THE PROGRAM NAME
	MOVEI A,.CTTRM	;CONTROLLING TERMINAL
	RFMOD		;SET SAVMOD FOR RETURN
	MOVEM B,SAVMOD
	RFCOC		;AND SAVE THE CCOC WORDS
	MOVEM B,SAVMOD+1
	MOVEM C,SAVMOD+2
	MOVE C,RUNFRK	;GET THE FORK INDEX
	IMULI C,3	;AND CONVERT TO AN OFFSET
	MOVE B,FRKTTY(C)	;RESTORE TTY MODES
	SFMOD
	STPAR
	MOVE B,FRKTTY+1(C)	;COULD BE DMOVE EXCEPT FOR KA10 TYPES
	MOVE C,FRKTTY+2(C)
	SFCOC
IFN SUMTTF,[
	MOVE A,HLDCHR		;RESTORE HOLD CHARACTER
	STCHA
];SUMTTF
	MOVEI A,.FHJOB	;SETUP TERMINAL INTERUPT WORD
	SETO B,
	SETZ C,
	STIW
	MOVEI A,.TICCG	;CTRL-G
	DTI		;TURN IT OFF
	JRST POPAJ	;RESTORE FORK HANDLE AND EXIT

;START INFERIOR (HANDLE IN A)

GOFRK:	SETZ B,		; ASSUME NEGATIVE OR NO PRE-COMMA ARG.
	TRNN FF,FRARG2	; HAVE PRE-COMMA ARG.?
	 JRST GOFRK1	; NO, GO CHECK FOR EXEC
	SKIPGE SARG	; IS IT POSITIVE?
	 JRST GOFRK2	; NO, SAY WE WANT RESCAN READ
	MOVE B,SARG	; YES, SET ENTRY IN STARTING VECTOR
GOFRK1:	
IFN 20X,[
	SKIPE FZSTR	; ANYTHING TO READ FROM RSCAN
	 CAME A,EXECFK	; IS THIS THE EXEC FORK?
	 JRST GOFRK3	; NO, START THE FORK
GOFRK2:	SAVE A
	SETZ A,
	RSCAN		; SAY WE WANT THE RESCAN BUFFER READ
	 TDN
	REST A
GOFRK3:
];IFN 20X
.ELSE GOFRK2:
	SFRKV		;START INFERIOR

WAITA:	WFORK		;WAIT FOR FORK TO TERMINATE
WAITX:			;SPECIAL LABEL FOR TSINT
RETFRK:	SAVE A		;SAVE FORK HANDLE
	SAVE D
	MOVE D,RUNFRK	; GET THE INDEX OF THE FORK WE JUST EXITED
	IMULI D,3	; AND CONVERT TO AN OFFSET
	MOVEI A,.CTTRM
	RFMOD		; AND READ THE MODES WE FIND NOW
	MOVEM B,FRKTTY(D)	; SAVE THEM IN CASE WE WANT FORK AGAIN
	RFCOC		; SAME FOR CCOC WORDS
	MOVEM B,FRKTTY+1(D)
	MOVEM C,FRKTTY+2(D)
	REST D
	SKIPN B,SAVMOD	; RESTORE TTY MODES IF REQUESTED (WAS IN TSINT)
	 JRST RETFR2	; NO
	MOVEI A,.CTTRM
	SFMOD
	STPAR
	MOVE B,SAVMOD+1	; RESTORE THE CCOC WORDS ON FORK EXIT
	MOVE C,SAVMOD+2
	SFCOC
	SETZM SAVMOD	; SAY NO MODE TO RESTORE
RETFR2:	MOVE A,FZNAM	; RESET JOB NAME
	SETNM
IFN SUMTTF,[
	SETZ A,		; ZERO = OFF
	STCHA
	SKIPE A
	 MOVEM A,HLDCHR
];SUMTTF
	SETOM PJATY	; SAY WE MESSED UP THE DISPLAY
	TRNE FF,FRUPRW	;RES
	 SETZM PJATY	;@ FLAG => SUPPRESS AUTO REDISPLAY
	MOVSI A,.TICCG	;MAKE SURE ^G ASSIGNED ON CHANNEL 0
	ATI
	CALL DOSTIW	;GET RID OF ANY INTERRUPT CHARACTERS DUE TO INFERIOR
	TRZN FF,FRUPRW	; UNLESS DISPLAY NOT TOUCHED
	 CALL DPYINI	; RE-INIT THOSE TTY'S THAT NEED IT. (VT100 ETC.)
	SETZM FZSTR	; CLEAN UP FLAGS AND POINTERS
	JRST POPAJ	;RESTORE HANDLE AND EXIT

;CREATE A NEW FORK FOR PROGRAM NAMED BY POINTER IN B
;IF EXECFK IS 0, WE WANT TO CREATE AN EXEC FORK.
;OTHERWISE, WE ALLOCATE AN INDEX AND RETURN IT IN B.

NEWFRK:	MOVSI A,(GJ%SHT\GJ%OLD)
	GTJFN
	 JRST OPNER2
	MOVEM A,FRKJFN	; SAVE THE JFN FOR MORE STUFF LATER
	SAVE A		;SAVE JFN
	SKIPE EXECFK	; IS THIS TO BE AN EXEC FORK?
	 CALL FZFIX	; NO, GO PUT RESCAN JCL IN STANDARD EXEC FORMAT
	MOVSI A,(CR%CAP)	;PASS ON CAPABILITIES
	CFORK
	 JRST FRKC3
	EXCH A,0(P)	;SAVE FORK HANDLE GET JFN
	SKIPN FRKJCL	;WANTS JCL?
	 JRST NEWFR1
	MOVEI B,(A)	;YES, GET JFN
	HRROI A,BAKTAB
	MOVSI C,001000
	JFNS
	PUSH P,B	;SAVE JFN AGAIN
	MOVEI B,40
	IDPB B,A
	PUSH P,A	;SAVE STRING POINTER
	SKIPL A,FRKJCL	;GET JCL - SHOULD BE A STRING
	 CAIA
	CALL QLGET0	;GET BYTE POINTER AND SIZE OF STRING
	 JRST [	POP P,(P)	;NOT A STRING
		POP P,A	;JFN
		RLJFN
		 JFCL
		POP P,A	;FORK
		KFORK
		SETZM FRKJCL	;DONT GET IT AGAIN
		TYPRE [ARG]]
	POP P,A
NEWFR4:	ILDB CH,BP
	IDPB CH,A
	SOJG B,NEWFR4
	MOVEI B,12
	IDPB B,A
	MOVEI B,0
	IDPB B,A
	HRROI A,BAKTAB	;STICK IN THE JCL
	MOVEM A,FZSTR	;TAKING PRECEDENCE
	SETZM FRKJCL	;DONT GET IT AGAIN
	POP P,A		;NOW GET THE JFN AGAIN
NEWFR1:	HRL A,0(P)	;FORK,,JFN
	GET		;GET FILE
IFN 20X\FNX, ERJMP FRKC4
	REST A		;RESTORE FORK HANDLE
	SKIPN EXECFK	;WANT THIS HANDLE?
	 JRST NEWFRE	;ITS AN EXEC FORK
	MOVSI B,-NFKS
	SKIPE FRKTAB(B)	;IN USE?
	 AOBJN B,.-1	;YES - TRY NEXT
	JUMPG B,FRKC5	;TABLE FULL?
	MOVEM A,FRKTAB(B) ;SAVE NEW HANDLE
	MOVEI B,1(B)	;RETURN NEW INDEX IN B
	CALL FRKTIN	; INIT. TTY MODES FOR A NEW FORK
	JSR SAVABC	; SAVE SOME WORKING AC'S
	SAVE D		;
	SETZ A,		; ZERO THE SUBJOB NAME
	MOVEM A,FRKLST(B) ; (IE. SET IT TO BLANKS)
	HRRI A,FRKLST(B) ; MAKE A BYTE POINTER TO IT
	HRLI A,440600	; SIX BIT BYTES
	HRR B,FZSTR	; AND A BYTE POINTER TO THE START OF THE FILE
	HRLI B,440700	; NAME STRING POINTED TO BY FZSTR
	MOVEI D,6	; MAX OF SIX CHARS IN THE SUBJOB NAME
NEWFR2:	ILDB C,B	; GET A BYTE
	CAIE C,15	; IF ITS A CARRAGE RETURN QUIT
	 SKIPN C	; WAS IT A NULL?
	  JRST NEWFR3	; YES, SO QUIT
	SUBI C,40	; MAKE IT SIXBIT
	SKIPN C		; IF IT WAS A SPACE WE'RE DONE AS WELL
	 JRST NEWFR3	; DONE
	ANDI C,77	; JUST MAKE SURE ITS SIXBIT
	IDPB C,A	; PUT IT IN THE SUBJOB NAME
	SOJG D,NEWFR2	; HAVE WE DONE SIX YET, IF NOT LOOP
NEWFR3:	REST D		; GET THE STUFF BACK AGAIN
	JRST POPCBA


NEWFRE:	MOVEM A,EXECFK
	SAVE B
	SETZ B,		; SET EXEC INDEX
	CALL FRKTIN	; AND INITIALIZE TTY MODES FOR NEW EXEC
	REST B
	RET

FRKTIN:	SAVE A
	SAVE B
	IMULI B,3	; AND CONVERT TO AN OFFSET
	HRRI A,FRKTTY(B)	; GET STARTING ADDRESS IN DESTINATION TABLE
	HRLI A,ITTYMD		; GET STARTING ADDRESS IN SOURCE TABLE
	BLT A,FRKTTY+2(B)	; AND TRANSFER THE DEFAULT TTY STATUS WORDS
	JRST POPBAJ

FRKC3:	REST A		;JFN ON STACK
	RLJFN		;RELEASE JFN IN A
	 JFCL
	JRST OPNER2

FRKC4:	TLZ A,-1	;JFN
	RLJFN
	 JFCL
	REST A		;FORK HANDLE ON STACK
	KFORK		;FLUSH FORK
IFN 20X\FNX, ERJMP .+1
	JRST OPNER2

FRKC5:	KFORK		;KILL OFF FORK
IFN 20X\FNX, ERJMP .+1
	MOVEI B,CFRKX3
	JRST OPNER4
];TNX (FZ COMMAND)

;FJ  --  INSERT THE CMD STRING FROM DDT IN THE BUFFER.
;IF NO STRING, INSERTS NOTHING. STRING WILL USUALLY END WITH CRLF.
FJCL:	PUSHJ P,FJCLRD	;READ IN THE COMMAND STRING,
	SKIPN BAKTAB
	 POPJ P,	;NOTHING TO DO IF STRING NULL.
	MOVE A,[BP7,,BAKTAB]
 	MOVEI C,	;COUNT THE CHARS IN E.
FJCL1:	ILDB CH,A
	JUMPE CH,FJCL2
	CAIE CH,^M	;^M AND ^@ END THE STRING.
	AOJA C,FJCL1
	ADDI C,2	;^M COUNTS AS 2 CHARS, ^@ AS NONE.
FJCL2:	CALL SLPGET	;INSERT C(C) CHARS, BP IN BP FOR IDPB.
	MOVE A,[BP7,,BAKTAB]
FJCL3:	ILDB CH,A	;COPY THE CHARS INTO THE SPACE.
	JUMPE CH,CPOPJ	;STOP BEFORE A ^@.
	IDPB CH,BP
	CAIE CH,^M	;AFTER ^M, STORE ^J AND DONE.
	JRST FJCL3
	MOVEI CH,^J
	IDPB CH,BP
	POPJ P,

;READ THE CMD STRING FROM DDT INTO BAKTAB.
FJCLRD:
IFN TNX,[
IFN 10X\FNX,[
	HRROI A,[ASCIZ \DSK\]	;Get/save dev designator for DSK
	STDEV
	 .VALUE			;???
	PUSH P,B
	MOVEI A,.PRIIN		;Now check charact. of primary input
	DVCHR
	POP P,B			;Is it a disk file?
	CAME A,B
	 JRST FJCLR6		;No
	MOVEI A,.PRIIN		;Yes - JCL file, get its size
	SIZEF
	 .VALUE
	JUMPLE C,FJCLR5		;If null file, quit
	MOVN C,B		;c := neg char count
];10X\FNX
IFN 20X,[
	SETZB A,BAKTAB
	RSCAN		;GET RSCAN BUFFER
	 TDN
	MOVN C,A	;GET NUMBER OF CHARACTERS IN IT
];20X
	MOVE B,[BP7,,BAKTAB]
FJCLR2:	JUMPGE C,FJCLR5		;If no chars rescanned, we have no JCL.
	PBIN			;Flush the first word of the rscan line.
	CAIL A,"A+40		;Make it upper case
	 CAILE A,"Z+40		;For easy reading later
	  TRNA
	   SUBI A,40
	IDPB A,B
	CAILE A,40		;Find end of invoking field
	 AOJA C,FJCLR2
	AOJGE C,FJCLR5		;Reached end already => no JCL for us.
	TRZN A,40		;Is separator?
	 JRST FJCLR3		;No, a terminator.  Ignore the JCL.
	DPB A,B			;Stick in null
	MOVE B,BAKTAB		;Look at first word
	CAME B,[ASCII/RUN/]	;Should anything more follow?
	 CAMN B,[ASCII/R/]	
	  JRST FJCLR3		;R or RUN means ignore the JCL.
	MOVEM B,JCLNAM		;Save the name of the program in JCL
	MOVE B,BAKTAB+1
	TRZ B,177_1		;Only get 9 characters
	MOVEM B,JCLNAM+1
IFN 20X, JRST FJCLR4
IFN 10X\FNX,[
	CALL FJCLR4		;Read rest of JCL
;;;	JRST FJCLR

; Now divert primary output back to controlling TTY
FJCLR7:	MOVEI A,.FHSLF
	MOVE B,[.CTTRM,,.CTTRM]
	SPJFN
	RET
];10X\FNX

FJCLR3:	CALL FJCLR4		;Ignore the JCL: read it all in,
FJCLR5:	
IFN 10X\FNX,[
	CALL FJCLR7		;Reset primary i/o
FJCLR6:
];10X\FNX
	SETZM BAKTAB		;but say there was none.
	SETZM JCLNAM
	RET
FJCLR4:
];TNX
	SETZM BAKTAB
	MOVE A,[BAKTAB,,BAKTAB+1]
	BLT A,BAKTAB+LTABS-2
IFN ITS,[
	MOVEM A,BAKTAB+LTABS-1	;LAST WD NOT 0 TO STOP STORING.
;FIRST, RETURN WITH BAKTAB ZEROED IF THERE IS NO JCL.
	.SUSET [.ROPTIO,,A]
	TLNN A,OPTCMD	;HAS SUPERIOR SAID IT HAS CMD STRING?
	 POPJ P,	;NO, RETURN AS IF READ 0 FROM IT.
;THERE IS JCL, SO READ IT INTO BAKTAB.
	.BREAK 12,[5,,BAKTAB]
]
IFN TNX,[
	MOVEI A,.PRIIN	;READ FROM PRIMARY INPUT
	HRROI B,BAKTAB
	SIN		;THE REST OF THE RSCAN STRING
];TNX
	RET

SUBTTL F=, F~ STRING COMPARISON

;F=<QREG><STRING>$ OR <BUFFER-RANGE>F=<STRING>$
;COMPARES THE STRINGS AND RETURNS A NUMBER WHOSE SIGN IS NEGATIVE
;IF QREG OR BUFFER RANGE IS LESS;  POSITIVE, IF GREATER;  0, IF THE
;TWO STRINGS ARE EQUAL.
;IF THE VALUE IS NONZERO, ITS ABS VALUE IS 1 + THE POSITION OF THE FIRST
;DIFFERENCE; I.E., 1 IF THE FIRST CHARACTERS DIFFER.
;A STRING IS GREATER THAN ANY INITIAL SEGMENT OF IT.
;F~ (OR F^) COMPARES SIMILARLY BUT IGNORES CASE DIFFERENCES.
FAPPRX:	TRO FF,FRNOT
FEQ:	TRNE FF,FRARG\FRCLN
	 JRST FEQ0	;NUMERIC ARG => USE BUFFER RANGE.
	SAVE FF		;PRESERVE FRNOT OVER QREGX.
	CALL QREGX	;ELSE READ NAME OF QREG.
	REST FF
	CALL QLGET0	;GET LENGTH IN B, BP TO ILDB IN BP.
	 TYPRE [QNS]
	SETZB D,IN	;THERE'S NO GAP TO SKIP OVER.
	AOJA IN,FEQ1

FEQ0:	CALL GETANU	;DECODE 1 OR 2 ARGS AS FOR K, T, X ETC.
	MOVE D,GPT	;D GETS CHAR ADDR OF START OF GAP.
	MOVE B,C	;B GETS # CHARS,
	SUB B,E
	MOVE BP,E
	CAML E,GPT
	 ADD BP,EXTRAC	;IN CASE RANGE STARTS AFTER GAP.
	MOVE IN,BP
	CALL GETIBP	;BP GETS BP TO ILDB 1ST CHAR.
FEQ1:	SETZ A,		;ORDER OF STRINGS NOT KNOWN YET.
	  ;WHEN ORDER IS DETERMINED, A WILL GET 1 OR -1.
	MOVE E,B	;REMEMBER INITIAL VALUE OF B.
	SETZM INSBP	;MAKE SURE RCH RELOCATES BP.
	MOVEI CH,ALTMOD
	TRZE FF,FRUPRW	;UPARROW SAYS USE DELIMITER OTHER THAN ALTMD.
	 CALL RCH
	MOVEM CH,INSDLM	;REMEMBER THE DELIMITER.
	TRZ FF,FRARG+FRCLN+FRARG2
;GET THE NEXT CHAR FROM THE STRING ARG.
FEQLUP:	CALL RCH	;READ IT.
	SKIPE SQUOTP	;IF NOT QUOTED OR DELIM-PROTECTED,
	 JRST FEQLU1
	CAMN CH,INSDLM	;SEE IF IT IS THE DELIMITER.
	 JRST FEQEND
FEQLU1:	JUMPN A,FEQLUP	;INEQUALITY SEEN => JUST SKIPPING TO END OF STRING ARG NOW.
	SOJL B,FEQEN1	;END OF QREG BUT NOT END OF STRING ARG => QREG IS LESS.
	CAMN D,IN	;ELSE GET NEXT CHAR OF QREG OR BUFFER.
	 CALL FEQGAP	;SKIP OVER GAP IF HAVE REACHED IT.
	AOS IN
	ILDB C,BP
	CAIN C,(CH)	;CHARS EQUAL => NO DECISION YET,
	 JRST FEQLUP	;KEEP LOOKING.
	TRNN FF,FRNOT	;NO MATCH => IF F^, TRY IGNORING CASE.
	 JRST FEQNE
	CAIL C,"A+40
	 CAILE C,"Z+40
	  CAIA
	   SUBI C,40
	CAIL CH,"A+40
	 CAILE CH,"Z+40
	  CAIA
	   SUBI CH,40
	CAMN C,CH
	 JRST FEQLUP
FEQNE:	CAIL C,(CH)	;QREG OR BUFFER GREATER =>
	 AOJA A,FEQLUP	;RETURN POSITIVE; ELSE NEGATIVE.
FEQEN1:	SOJA A,FEQLUP	;EITHER WAY, SKIP OVER REST OF STRING ARG.

FEQEND:	SETOM INSBP
	JUMPN A,FEQEN2	;END OF STRING ARG: RETURN ANSWER IF KNOWN.
	SOJL B,POPJ1	;ELSE QREG ENDING NOW TOO => EQUAL.
	AOJ A,		;STRING ARG FINISHED, OTHER NOT => STRING ARG IS SMALLER.
FEQEN2:	SUB E,B		;INITIAL VALUE OF B - CURRENT
	IMUL A,E	;GIVES 1+POSITION OF 1ST DIFFERENCE.
	JRST POPJ1

FEQGAP:	MOVE BP,GPT 	; BP GETS BP TO ILDB 1ST CHAR AFTER GAP.
	ADD BP,EXTRAC
	JRST GETIBP

SUBTTL CASE CONVERSION

;FC - TAKES ARGS LIKE K, CONVERTS AREA OF BUFFER TO LOWER CASE
;PT GOES BEFORE THE SAME CHARACTER BEFORE AND AFTER.
;@FC CONVERTS TO UPPER CASE.
;<CH>:FC RETURNS <CH>, CONVERTED TO UPPER CASE.
LOWCON:	TRZE FF,FRCLN
	 JRST LOWCO3	;:FC GOES OFF.
	PUSHJ P,GETANU
	MOVE IN,E
	SUB C,IN
	SKIPE READON
	 TYPRE [RDO]
	SETOM MODIFF	;WE ARE ABOUT TO CHANGE THE BUFFER CONTENTS.
	SETOM MODIFM
	CALL GETIBI	;GET IN BP B.P. TO ILDB CHARS STARTING WHERE IN POINTS.
LOWCO1:	SOJL C,CPOPJ
	CAMN IN,GPT	;WHEN REACH GAP, MOVE B.P. OVER IT.
	 CALL FEQGAP
	ILDB CH,BP
	TRNE FF,FRUPRW
	 JRST LOWCO5
	CAIG CH,"Z
	CAIGE CH,"A
	 JRST LOWCO2
LOWCO6:	XORI CH,40
LOWCO2:	DPB CH,BP	;PUT CHAR INTO FRONT OF GAP,
	AOJA IN,LOWCO1

LOWCO5:	CAIG CH,40+"Z	;CONVERTING TO UPPER CASE:
	CAIGE CH,40+"A
	 JRST LOWCO2
	JRST LOWCO6	;LOWER CASE CHARS GET SHIFTED,

LOWCO3:	TRZN FF,FRARG
	 TYPRE [WNA]
	MOVE A,C	;HANDLE :FC.  TO GET VALUE, START WITH ARG,
	TRZ FF,FRUPRW	;DON'T LEAVE @ FLAG ON;  DON'T LET ARG INTERFERE WITH VALUE.
	CALL QLGET0	;ARG IS STRING => CONVERT ALL CHARS OF THE STRING.
	 CAIA
	  JRST LOWCO4
	ANDI C,177
	CAIG C,40+"Z
	 CAIGE C,40+"A
	  CAIA
	   XORI A,40
	JRST POPJ1

LOWCO4:	AOS (P)
	MOVE C,B	;ARG IS STRING;  MAKE NEW STRING = OLD ONE CONVERTED TO U.C.
	MOVE E,BP	;SAVE PTR TO OLD STRING;  QOPEN RETURNS PTR TO NEW ONE IN BP.
	CALL QOPEN	;MEANWHILE C HAS SIZE NEEDED FOR NEW ONE, = SIZE OF OLD.
	JUMPE B,QCLOSV
LOWCO7:	ILDB TT,E	;COPY OLD STRING
	CAIL TT,"A+40
	 CAILE TT,"Z+40
	  CAIA
	   SUBI TT,40	;CONVERT EACH CHARACTER IF NECESSARY.
	IDPB TT,BP	;STORE INTO THE NEW STRING.
	SOJG B,LOWCO7
	JRST QCLOSV	;THEN FINISH THE NEW STRING'S HEADER AND RETURN IT.

NEWAS:	ARGDFL		;DOLLARSIGN COMMAND.
	CALL FSCASF	;UNLESS IN -1$, NO CASE SHIFT OR LOCK.
	SKIPGE C
	MOVEI IN,"/	;-1$, USE / AS THE CASE-SHIFT, NO CASE-LOCK.
	JRST FSCAS1

FSCASV:	MOVE A,CASNRM	;COMPUTE VALUE FOR FS CASE TO RETURN.
	SKIPL CH,CASSFT	;IF THERE'S A CASE-SHIFT, PUT IT IN BUFFER..
	 CALL TYOMGS
	SKIPL CH,CASLOK	;SAME FOR CASE-LOCK.
	 CALL TYOM
	JRST POPJ1

FSCASE:	TRNN FF,FRARG	;FS CASE -- NO ARG => RETURN STATUS INFO.
	 JRST FSCASV
	ARGDFL
	CALL FSCASF	;READ THE STRING ARG WITH NO CASE SHIFT OR CASE LOCK.
	CALL RCH	;READ WHAT MIGHT BE THE CASE-SHIFT.
	CAIN CH,ALTMOD	;NULL STRING ARG => NEITHER.
	 JRST FSCAS1	;(NOTE IN, OUT HOLD -1)
	MOVEI IN,(CH)	;ELSE 1ST CHAR OF ARG IS CASE-:SHIFT.
	CALL RCH	;AND THERE MAY BE A CASE-LOCK.
	CAIN CH,ALTMOD
	 JRST FSCAS1	;NO MORE CHARS IN ARG => NO CASE-LOCK.
	MOVEI OUT,(CH)
FSCAS0:	JSP B,RDALTC	;IGNORE REST OF STRING ARG.
	 CAIA
	JRST FSCAS0
FSCAS1:	CAMN IN,OUT	;TRYING TO MAKE SAME CHAR SHIFT & LOCK?
	 SETO IN,	;JUST USE IT AS LOCK.
	MOVEM C,CASNRM	;SIGN OF ARG IS NORMAL INPUT CASE.
	MOVEM C,CASE	;SET CURRENT CASE TO NEW NORMAL.
	ANDI C,1
	MOVEM C,CASDIS	;ARG ODD => FLAG ON OUTPUT.
	MOVEM IN,CASSFT	;THEN STORE AWAY NEW SHIFT AND LOCK CHARS,
	MOVEM OUT,CASLOK
	MOVE TT,[CALL RCHSFT]	;ACTUALLY MAKE THE NEW CASE-SHIFT
	SKIPL IN		;(IF ANY)
	 EXCH TT,RCHDTB(IN)	;ACT LIKE ONE.
	MOVEM TT,RCHSFD		;MAKE SURE CAN UNDO THAT EXCH.
	MOVE TT,[CALL RCHLOK]
	SKIPL OUT		;SIMILAR FOR THE NEW CASE-LOCK.
	 EXCH TT,RCHDTB(OUT)
	MOVEM TT,RCHLOD
	POPJ P,

;CAUSE THE CASE-SHIFT AND CASE-LOCK, IF ANY, TO BECOME NORMAL.
;CHARACTERS AGAIN, WITH NO CASE-SHIFT OR -LOCK IN EXISTENCE.
;SETOM'S IN, OUT. CLOBBERS TT, TT1.
FSCASF:	MOVE TT,RCHLOD	;FIRST TURN THE OLD SHIFT AND LOCK CHARS
	SKIPL TT1,CASLOK ;INTO NORMAL CHARS.
	 MOVEM TT,RCHDTB(TT1)
	MOVE TT,RCHSFD
	SKIPL TT1,CASSFT
	 MOVEM TT,RCHDTB(TT1)
	SETOB IN,CASSFT	;THEN SAY THERE ARE NONE.
	SETOB OUT,CASLOK
	POPJ P,

SUBTTL Q-REGISTER NAME READERS

;ROUTINES TO READ IN SUFFIX QREG ARGS:

;THERE ARE SEVERAL TYPES OF SUFFIX QREGS, AND VARIOUS ROUTINES ALLOW CERTAIN SUBSETS.
;A LETTER (OR DOTS AND A LETTER, OR A ^R OR ^^ NAME) NAMES A FIXED LOCATION IN TECO.
;AN EXPRESSION IN PARENTHESES IS A READ-ONLY QREG "CONTAINING" THE VALUE OF THE EXP.
;A * IS A WRITE-ONLY QREG AND WHAT IS WRITTEN IN IT IS THE COMMAND'S VALUE.
;:<Q>(<IDX>) WHERE <Q> IS A QREG CONTAINING A Q-VECTOR, IS A SUBSCRIPTING EXPRESSION.
;   IN THIS CASE, THE QREG IS ONE WORD IN THE QVECTOR.
;<NAME> IS A LONG-NAME QREG.  THE NAME IS LOOKED UP IN THE SYMBOL TABLE
;   (A QVECTOR IN ..Q) WITH FO TO FIND THE WORD IN THAT QVECTOR HOLDING THE VALUE.

;THE REASON THERE ARE SEVERAL ROUTINES IS THAT ONLY READING-ONLY COMMANDS
;ALLOW (-) QREGS, AND ONLY WRITING-ONLY COMMANDS ALLOW *.
;QREGS IS THE BASIC ROUTINE (NEITHER * NOR PARENS), QREGX ALLOWS PARENS,
;AND QREGVS ALLOWS *.

;THE ROUTINES HAVE SIMILAR VALUE CONVENTIONS:
;A CONTAINS THE CONTENTS OF THE QREG,
;CH CONTAINS ITS ADDRESS (BAKTAB, FOR PAREN-QREGS WHICH CAN'T BE WRITTEN)
;B CONTAINS AN INDICATION OF WHICH TYPE OF NAME WAS READ.
 ;NORMALLY, IT IS ZERO.  FOR :<Q>(<IDX>), IT IS POSITIVE;  FOR NAME, IT IS NEGATIVE.
   ;IN EITHER OF THOSE TWO CASES, THE RH POINTS AT THE BUFFER BLOCK OF THE QVECTOR
   ;CONTAINING THE SLOT.  THAT IS SO THAT COMMANDS LIKE :I CAN TELL IF THAT QVECTOR
   ;IS RELOCATED AND CORRECT ACCORDINGLY (SEE QREGVA).
;IN, FOR A NAME QREG (B IS NEGATIVE), CONTAINS A TECO STRING POINTER TO THE
;INTERNED NAME OF THE QREG AS FOUND IN THE SYMBOL TABLE.

;READ EITHER A QREG NAME OR AN EXPRESSION IN PARENS, WHOSE VALUE
;IS USED AS THE "CONTENTS" OF THE QREG.  CONTENTS RETURNED IN A.  CLOBBERS ALL ACS
;EXCEPT C,E.  ALSO ALLOWS SUBSCRIPTED QVECTORS, LIKE QREGS.
QREGX:	CALL SKRCH
	CAIE CH,"(
	 JRST QREGS0
	TRO FF,FRQPRN	;MARK THIS ( AS BEING FROM QREGX.
	MOVEI T,CD
	JRST OPEN2	;SAVE ARGS, ETC;  WILL COME BACK WHEN ")" IS SEEN

QREGXR:	MOVE C,NUM	;TO HERE.  A HAS VALUE WITHIN THE PARENS.
	MOVE E,SARG	;RESTORE THE SAVED ARGS.
	TRZ FF,FRARG\FRARG2\FRCLN\FRUPRW
	IORI FF,(CH)
	SETZ B,		;RETURN B AS 0 TO SHOW THIS WASN'T A SUBSCTRIPTED QREG.
	MOVEI CH,BAKTAB		;MAKE SURE, IF CALLER TRIES TO WRITE OUR QREG, NO HARM DONE.
	RET

;HERE TAKE CARE OF "SIMPLE" (..A OR ...^RX) TYPE QREG NAMES.
QREGXX:	SETZB A,B
	CALL QNMGE2	;HERE FROM QREGX OR QREGS IF IT'S AN ORDINARY QREG NAME AFTER ALL.
	 TYPRE [IQN]
	MOVE A,(CH)
	POPJ P,

;HERE TO READ EITHER QREG NAME OR "*" MEANING RETURN AS VALUE INSTEAD OF SETTING QREG.
;ASSUMES -1(P) IS CALLER'S RETURN ADDRESS, AND AOS'S IT SO CALLER RETURNS THE VALUE.
QREGVS:	CALL SKRCH		;HERE TO ALLOW EITHER * OR SUBSCRIPTING.
	CAIE CH,"*
	 JRST QREGS0
	MOVEI CH,A		;SUPPLY AC A AS ADDR OF "QREG".
	SETZB A,B		;SAY ITS VALUE IS 0 (FOR THINGS LIKE @X).
	AOS -1(P)		;MAKE OUR CALLER SKIP-RETURN
	RET

;READ IN A QREG NAME, ALLOWING SUBSCRIPTING (AS IN Q:.Q(10) = 10TH ELT OF Q-VECTOR IN .Q)
;ON RETURN FROM THIS OR ANY OTHER QREG-READING ROUTINE, IF B IS NONZERO
;THEN THE QREG WAS SUBSCRIPTED, AND B POINTS AT THE BUFFER BLOCK OF THE Q-VECTOR.
;WE ALSO HANDLE "LONG QREG NAMES" AS IN QFOO, SINCE THAT IS IMPLEMENTED
;BY MEANS OF INDEXING (INTO THE SYMBOL TABLE QVECTOR).
QREGS:	CALL SKRCH
QREGS0:	CAIN CH,ALTMOD
	 JRST QREGN		;CHECK FOR Q$FOO$ CONSTRUCT.
	CAIE CH,":
	 JRST QREGXX
	CALL QREGX		;FIRST, READ THE QREG WHICH IS THE Q-VECTOR TO SUBSCRIPT.
	SAVE A			;SAVE IT AS IF IN A (.
	SAVE [0]
	SAVE LEV
	MOVEM P,LEV
	CALL QREGX		;THEN READ THE VALUE OF THE INDEX.
	MOVE IN,A
	MOVEI T,.+2
	JRST CLOSE2		;POP STUFF OFF, LEAVING Q-VECTOR IN A.
	MOVE BP,A
	CALL QBGET1		;GET BUFFER-BLOCK ADDR IN B.
	SKIPN B
	 TYPRE [QNB]
	IMULI IN,5		;GET VIRTUAL CHAR ADDR INSIDE Q-VECTOR OF DESIRED WORD.
	ADD IN,MFBEG(B)
	TLZ IN,MFBBTS
	CAML IN,MFBEGV(B)	;COMPLAIN IF NOT INSIDE VIRTUAL BOUNDS.
	 CAML IN,MFZV(B)
	  TYPRE [NIB]
	CAML IN,MFGPT(B)
	 ADD IN,MFEXTR(B)	;TURN INTO REAL ADDRESS.
	IDIVI IN,5
	MOVE A,(IN)		;FETCH CONTENTS OF WORD,
	MOVE CH,IN		;AND ALSO RETURN ITS ADDRESS, FOR "U", ETC.
	RET

;COMMANDS THAT DO CONSING, AFTER CALLING QREGVS, SHOULD, IF B IS NONZERO,
;DO A JSP TT,QREGVA TO WORRY ABOUT CHANCE THAT CONSING WILL MOVE THE Q-VECTOR.
;QREGVA SAVES STUFF, CALLS BACK TO DO THE WORK, THEN FIXES UP AND RETURNS TO COMMAND'S CALLER.
;IF B IS NEGATIVE, THE QREG IS A NAMED VARIABLE, AND WE MAY NEED TO CALL A MACRO
;WHEN ITS VALUE CHANGES.  WE PRESERVE B FOR USE2 TO ACCOMPLISH THAT.
QREGVA:	SAVE B			;REMEMBER ADDR OF BUFFER BLOCK OF QVECTOR
	SAVE CH			;REMEMBER ADDRESS OF WORD IN QVECTOR.
	MOVE CH,MFBEGV(B)
	IDIVI CH,5		;BUT CONVERT IT INTO AN INDEX RELATIVE TO QVECTOR'S B.
	MOVNS CH
	ADDM CH,(P)
	MOVEI CH,A		;NOW CALL THE COMMAND BACK, GETTING RESULT IN A.
	SETZ B,
	CALL (TT)
	MOVE B,-1(P)		;NOW CONVERT REL. IDX. INTO QVECTOR BACK INTO ADDRESS.
	MOVE CH,MFBEGV(B)
	IDIVI CH,5
	ADD CH,(P)
	SUB P,[2,,2]
	MOVE C,A		;NOW GO STORE VALUE IN QREG.
	JRST USE2

;HERE AFTER SEEING A QREG NAME STARTS WITH AN ALTMODE, AS IN QFOO.  [
QREGN:	SETZM SQUOTP		;Q^]A WHERE A HOLDS $FOO$ SHOULD WIN.
	SAVE C
	SAVE E			;FO CLOBBERS ALL ACS
	SAVE FF
	MOVE A,QRB..
	MOVE A,.QSYMT(A)	;GET THE PTR TO THE QVECTOR USED AS SYMBOL TABLE.
	MOVE BP,A
	CALL QBGET1
	SAVE B
	TRZ FF,FRCLN\FRARG\FRARG2\FRUPRW
	CALL FOCMD0		;DO FO TO READ IN THE "FOO" AND SEARCH SYMBOL TABLE.
	 JFCL			;PUTS VAL IN A AND ADDR OF S.T.E. IN IN.
	MOVEI CH,1(IN)		;CH GETS ADDR OF SLOT IN QVECTOR HOLDING THE VALUE.
	MOVE IN,(IN)		;IN GETS THE STRING WHICH IS THE FULL NAME.
	REST B			;RETURN IN B THE BUFFER BLOCK OF THE QVECTOR
	TLO B,400000
	REST FF			;(FOR RELOCATION HACKERY IN QREGVA FOR :I AND X).
	REST E
	JRST POPCJ

;SKIP IF CHAR IN CH IS A LETTER OR A DIGIT. ALSO, CONVERT LOWER
;CASE LETETRS TO UPPER CASE.
QRVTST:	CAIL CH,"0
	CAILE CH,"9
	CAIA
	JRST POPJ1
	CAIL CH,"A
	CAILE CH,"Z
	CAIA
	JRST POPJ1
	CAIL CH,"A+40
	CAILE CH,"Z+40
	POPJ P,
	SUBI CH,40
	JRST POPJ1

;READ IN A QREG NAME, AND RETURN IN CH THE ADDRESS OF THE QREG.
;CLOBBERS A AND CH.
QNMGET:	SETZI A,
	CALL SKRCH
QNMGE2:	CAIN CH,".
	 AOJA A,QNMGET+1
	CAIE CH,^R
	 CAIN CH,^^
	  JRST QNMGE3
	CALL QRVTST
	 RET
	CAILE A,NQSETS-1
	 RET
	AOS (P)
QNMGE1:	MOVEI CH,-"0(CH)
	CAILE CH,9
	 SUBI CH,"A-"9-1
	ADD CH,QRB(A)
	RET

QNMGE3:	LSH A,7		;HANDLE QREG NAME CONTAINING "^R" OR "^^":
	CAIN CH,^^
	 XORI A,100
QNMGE5:	SETZM BRCUAV	;[ ;IF A ^]^V IS DONE, BRCUAV WILL BECOME NEGATIVE.
	CALL SKRCH	;READ IN NAME OF ^R-MODE CHARACTER
	SKIPGE BRCUAV	;[ ;THE POINT OF THIS IS THAT ^]^V TRUNCATES TO 7 BITS,
	 HRRZ CH,BRCUAV	;BUT WE HAVE TO GET BACK THE 9-BIT VALUE.
	XOR CH,A	;GET THE SPECIFIED CHAR. IN TV CHAR SET.
	ANDI CH,777
	ADDI CH,RRMACT	;THE "QREG" IS THE RRMACT ENTRY FOR THE CHARACTER.
	JRST POPJ1

;F^^ -- CONVERT A ^R-COMMAND NAME INTO A NUMBER (F^^.^R. RETURNS 174. = 256)
;<STRING>:F^^ -- IF <STRING> IS A VALID Q-REG NAME, RETURN THE
;:FSQPHOME$ OF THE Q-REG.  OTHERWISE, RETURN 0.
FCTLUP:	TRZE FF,FRCLN
	 JRST FCUP1
	CALL QNMGET
	 TYPRE [ARG]
	MOVEI A,-RRMACT(CH)
	CAIL A,1000
	 TYPRE [ARG]
	JRST POPJ1

FCUP1:	TRZ FF,FRARG
	MOVE A,C	;<STRING>:F^^.
	CALL QLGET0	;DECODE THE STRING, B.P. IN BP AND LENGTH IN B.
	 JRST NRET0
	SETZ A,		;COUNT NUMBER OF DOTS IN A.
FCUP2:	SOJL B,NRET0	;STRING EXHAUSTED => NOT VALID.
	ILDB CH,BP
	CAIN CH,".	;NEXT CHAR IS A DOT => JUST COUNT IT.
	 AOJA A,FCUP2
	CAIE CH,^R	;NON-DOT => WE'RE NEAR THE END NOW.
	 CAIN CH,^^
	  JRST FCUP3	;^R CHARACTER DEFN NAMES ARE OK TOO.
	CALL QNMGE2	;ELSE FIGURE OUT THE QREG NAME,
	 SETZ CH,	;NO SKIP MEANS IT ISN'T A VALID ONE, SO RETURN 0.
	MOVE A,CH	;ELSE QNMGE2 LEFT THE DESIRED VALUE IN CH.
	JUMPN B,NRET0	;WE WIN PROVIDED STRING IS NOW EXHAUSTED.
	JRST POPJ1

FCUP3:	LSH A,7		;^R CHARACTER DEFN NAME => PUT DOTS IN CTL AND META BITS,
	CAIN CH,^^
	 XORI A,100	;FOR ^^ CONTROLIFY WHAT FOLLOWS.
	SOJL B,NRET0	;STRING EXHAUSTED RIGHT AFTER THE ^R OR ^^ => LOSE.
	ILDB CH,BP
	XOR A,CH	;ELSE MERGE CHAR WITH DOTS AND RETURN.
	ANDI A,777
	ADDI A,RRMACT
	JUMPN B,NRET0	;WE WIN PROVIDED STRING IS NOW EXHAUSTED.
	JRST POPJ1

;FO COMMAND - BINARY SEARCH A TABLE FOR A GIVEN STRING.
;FOLLOW BY QREG WHICH POINTS TO A STRING OR BUFFER CONTAINING THE TABLE
;(MUST BE ON A WORD BOUNDARY, SO USELESS WITH IMPURE STRINGS).
;AFTER THE QREG NAME COMES THE STRING TO SEARCH FOR.
;THE FIRST WORD OF THE TABLE MUST CONTAIN THE SIZE (IN WORDS) OF
;ALL THE ENTRIES;  AFTER IT COME THE ENTRIES.  THE FIRST WORD OF EACH ENTRY
;IS ASSUMED TO BE THE POINTER TO THE NAME-STRING TO SEARCH FOR.
;IF THE TABLE IS A PURE STRING, THAT PONTER IS RELATIVE TO THE TABLE ITSELF.
;PLAIN FO GETS AN ERROR (UVN OR AVN) IF THE TARGET NAME IS MISSING OR AMBIGUOUS;
;OTHERWISE, IT RETURNS THE VALUE IN THE SECOND WORD OF THE ENTRY.
;:FO RETURNS THE OFFSET OF THE ENTRY FOUND;  IF THE TARGET IS NOT FOUND
;OR AMBIGUOUS, MINUS THE OFFSET OF THE ENTRY TO INSERT BEFORE IS RETURNED.
;<ARG>FO RETURNS THE VALUE OF THE VARIABLE IF IT IS DEFINED, <ARG> OTHERWISE.
;"@" MODIFIER => DON'T ALLOW ABBREVIATIONS, JUST EXACT MATCHES.
FOCMD:	CALL QREGX		;READ THE QREG NAME.
FOCMD0:	MOVEI J,BAKTAB-1	;THEN ACCUMULATE STRING TO SEARCH FOR IN BAKTAB.
	MOVEI B,40		;B HOLDS PREVIOUS CHARACTER, FOR COMPRESSING SPACES.
	TRZ FF,FRNOT
FOCMD1:	CALL ORCH		;READ CHAR, CONVERT LETTERS TO U.C.
	CAIN CH,ALTMOD
	 SKIPE SQUOTP
	  CAIA
	   JRST FOCMD2
	SKIPGE SQUOTP		;ALLOW FOR SUPERQUOTED SPACES
	 HRLI CH,-1
	CAIN CH,^I
	 MOVEI CH,40		;CONVERT ALL TABS TO SPACES.
	CAIN CH,40		;CHECK FOR MULTIPLE OR LEADING WHITESPACE.
	 CAIE B,40		;IF THIS CHAR AND PREVIOUS BOTH SPACING, IGNORE THIS ONE.
	  CAIA
	   JRST FOCMD1
	MOVE B,CH		;REMEMBER THIS CHAR AS PREVIOUS FOR NEXT.
	HRRZS CH
	CAMN J,[LTABS,,BAKTAB+LTABS-1]
	 TYPRE [STL]
	PUSH J,CH		;REMEMBER CHAR IN BAKTAB.
	JRST FOCMD1

FOCMD2:	CAIN B,40		;FLUSH TRAILING SPACES.
	 SOS J
;ENTER HERE FROM F^G COMMAND.
FOCMD3:	CALL QLGET0		;GET TABLE LENGTH IN CHARS IN B, B.P. TO ILDB IN BP.
	 TYPRE [QNS]
	IBP BP
	HLRZ A,BP
	CAIE A,350700		;TABLE MUST START ON WORD BOUNDARY.
	 TYPRE [ARG]
	MOVE C,(BP)		;C GETS ENTRY SIZE IN WORDS, FROM 1ST WORD OF TABLE.
	MOVE OUT,B
	IDIVI OUT,5		;SIZE MUST BE INTEGRAL # OF WORDS.
	SKIPE OUT+1 .SEE CH
	 TYPRE [ARG]
	SOS CH,OUT		;OUT GETS TABLE SIZE, NOT COUNTING 1ST WORD (SIZE PER ENTRY).
	IDIV CH,C
	SKIPE CH+1 .SEE Q
	 TYPRE [ARG]		;TABLE MUST BE INTEGRAL NUMBER OF ENTRIES.
	MOVEI IN,1(BP)		;IN -> 1ST WORD (NOT COUNTING ENTRY-SIZE WORD AT FRONT).
	ADD OUT,IN		;OUT -> LAST WORD + 1
	HRRZ E,BP
	IMULI E,5		;E GETS CHAR ADDR OF START OF TABLE (INCLUDING DOPE WORD).
	CAML E,BFRTOP		;IF TABLE IS A PURE STRING, SET FRNOT, INDICATING
	 TRO FF,FRNOT		;NAME POINTERS ARE RELATIVE TO BOTTOM OF STRING (NEED E ADDED).
	SUBI E,4
	TLO E,400000
	MOVE T,OUT		;SAVE BOUNDS OF WHOLE TABLE AS [E,T)  ;]
	HRRZS J			;J POINTS AT END OF STUFF IN BAKTAB.
	CAIGE J,BAKTAB
	 JRST FOCMDU		;ARG NULL AFTER HACKING IT => NO GOOD.
	JRST FOCMDN

;NOW TRY TO NARROW THE RANGE [IN,OUT) WHICH THE OBJECT MIGHT BE IN.  ;]
;E HAS CHAR ADDR START OF TABLE MINUS 4 (WITH SIGN SET),
;T -> WORD AFTER END, C HAS ENTRY SIZE IN WORDS,
;J POINTS TO LAST USED WORD IN BAKTAB.
FOCMDN:	MOVE CH,OUT
	SUB CH,IN
	CAMG CH,C
	 JRST FOCMDF		;NARROWED TO ONE ENTRY => IT'S THAT OR NOTHING.
	IDIV CH,C		;HOW MANY ENTRIES THEN?
	MOVE D,CH
	LSH D,-1		;BINARY SEARCH STEP IS HALF THAT MANY.
	IMUL D,C
	ADD D,IN		;GET PTR TO MIDDLE OF RANGE; COMPARE THAT POINT WITH TARGET.
	CALL FOCMP
	 JRST [	MOVE OUT,D	;TARGET IS LESS => NARROW TO BOTTOM HALF-RANGE.
		JRST FOCMDN]
	 JRST [ MOVE IN,D	;TARGET IS MORE => NARROW TO TOP HALF-RANGE.
		JRST FOCMDN]
	MOVE IN,D
	JRST FOCMDW		;TARGET IS EQUAL => WE CERTAINLY WIN.

;NARROWED TO JUST ONE ENTRY;  IS IT GOOD?
FOCMDF:	CAML IN,T
	 JRST FOCMDU
	MOVE D,IN		;FIRST OF ALL, THIS ENTRY IS THAT LAST ONE L.E. TARGET.
	CALL FOCMP		;SO ADVANCE TO THE FIRST ONE G.E. THE TARGET
	 CAIA
	 ADD IN,C		;SINCE THE TARGET MIGHT BE ABBREVIATION FOR THAT ONE.
	CAML IN,T		;DETECT CASE THAT TARGET IS GREATER THAN ALL SYMBOLS
	 JRST FOCMDU
	MOVE OUT,IN
	ADD OUT,C
	MOVE A,(IN)
	CALL FOCMDA		;DOES TARGET ABBREVIATE ENTRY'S NAME?
	 JRST FOCMDU		;NO => TARGET NOT FOUND, RETURN 0.
	JUMPE B,FOCMDW		;YES, MAY BE GOOD.  IF EXACT MATCH, CERTAINLY GOOD.
	TRNE FF,FRUPRW		;"@" AND NOT EXACT MATCH => IT'S "UNDEFINED".
	 JRST FOCMDU
	CAMN OUT,T
	 JRST FOCMDW		;NO FOLLOWING ENTRY => NAME CAN'T BE AMGIBUOUS.
	MOVE A,(OUT)		;DOES FOLLOWING ENTRY ALSO WIN?
	CALL FOCMDA
	 JRST FOCMDW		;NO => THIS ENTRY WINS!
	TRNE FF,FRARG		;AMBIGUOUS NAME.  IF HAVE DEFAULT (ARG), RETURN IT.
	 JRST FOCMDU
	TRZN FF,FRCLN		;OR ELSE MAYBE GIVE ERROR,
	 TYPRE [AVN]
FOCMDL:	MOVEI A,-1(IN)		;MAYBE RETURN MINUS THE PLACE TO PUT THE NAME.
	TRZ FF,FRARG\FRUPRW
	TLZ E,400000
	IDIVI E,5		;E GETS WORD BEFORE THE WORD TABLE STARTS IN.
	SUBM E,A
	JRST POPJ1

FOCMDU:	TRZE FF,FRARG		;HERE IF NAME IS UNDEFINED;  IN -> PLACE TO INSERT IT.
	 JRST [	TRZ FF,FRCLN\FRUPRW
		MOVE A,NUM
		JRST POPJ1]
	TRZN FF,FRCLN
	 TYPRE [UVN]
	JRST FOCMDL

FOCMDW:	MOVE A,1(IN)		;FOUND THE TARGET.  RETURN EITHER 2ND WORD OF ENTRY
	TRZ FF,FRARG\FRUPRW
	TLZ E,400000
	TRZN FF,FRCLN
	 JRST POPJ1
	MOVEI A,-1(IN)
	IDIVI E,5
	SUB A,E
	JRST POPJ1		;OR THE INDEX OF THE ENTRY.

;SKIP IF THE STRING IN BAKTAB IS AN ABBREVIATION FOR THE STRING A POINTS TO
;(A HOLDS TECO STRING POINTER).
FOCMDA:	TRNE FF,FRNOT		;IF TABLE IS PURE STRING, "NAME POINTERS" ARE
	 ADD A,E		;ACTUALLY RELATIVE.
	CALL QLGET0		;SKIP IF TARGET ABBREVIATES THE STRING A POINTS TO.
	 TYPRE [QNS]
	MOVEI Q,BAKTAB
FOCMDG:	CAMLE Q,J
	 JRST POPJ1		;JUMP IF TARGET ABBREVIATES ENTRY'S NAME.
	JUMPE B,CPOPJ		;TARGET DOESN'T ABBREVIATE ENTRY'S NAME => TARGET NOT FOUND.
	ILDB CH,BP
	CAIL CH,"A+40
	 CAILE CH,"Z+40
	  CAIA
	   SUBI CH,40
	CAME CH,(Q)
	 RET
	SOS B
	AOJA Q,FOCMDG

;COMPARE STRING IN BAKTAB  (TARGET) WITH STRING THAT @(D) POINTS TO.  SKIP ONCE
;IF TARGET BIGGER, SKIP TWICE IF EQUAL.
FOCMP:	MOVE A,(D)		;GET THIS ENTRY'S NAME.
	TRNE FF,FRNOT		;IF TABLE IS PURE STRING, "NAME POINTERS" ARE
	 ADD A,E		;ACTUALLY RELATIVE.
	CALL QLGET0		;DECODE AS STRING.
	 TYPRE [QNS]
	MOVEI Q,BAKTAB		;Q SCANS TARGET, BP SCANS THIS ENTRY'S NAME.
FOCMPL:	JUMPE B,[CAMLE Q,J
		   JRST POPJ2	;IF BOTH STRINGS EXHAUSTED, THEUY ARE EQUAL.
		  JRST POPJ1]	;TARGET HAS MORE => IT IS BIGGER.
	CAMLE Q,J
	 RET			;TARGET EMPTY, BUT THIS ENTRY NAME HAS MORE => TARGET LESS.
	ILDB CH,BP
	CAIL CH,"A+40
	 CAILE CH,"Z+40
	  CAIA
	   SUBI CH,40
	CAMGE CH,(Q)
	 JRST POPJ1		;TARGET IS BIGGER.
	CAMLE CH,(Q)
	 RET			;TARGET SMALLER.
	SOS B
	AOJA Q,FOCMPL		;EQUAL SO FAR, KEEP LOOKING.

SUBTTL DECODE A STRING POINTER

;CH HAS QREG IDX; DON'T SKIP IF QREG NOT STRING.
;ELSE SKIP WITH B HOLDING # CHARS OF TEXT IN STRING (NOT INCLUDING HEADER),
;BP HOLDING A B.P. TO ILDB THE TEXT.  CLOBBERS TT, TT1.
QLGET:	MOVE A,(CH)
QLGET0:	CAML A,[SETZ+LHIMAX*5*2000]
	 RET		;CAN'T  BE EITHER PURE OR IMPURE SPACE.
QLGET1:	MOVE BP,A
	TLZ BP,400000	;FLUSH THE SIGN BIT (SET IN ALL POINTERS)
	CAMGE BP,BFRTOP	;IF IT'S IMPURE SPACE,
	 ADD BP,QRBUF	;POINTER IS RELATIVE TO START OF IMPURE SPACE.
QLGET2:	PUSHJ P,GETBP
QLGET3:	LDB B,BP
	CAIN B,QRBFR
	 JRST QLGET5
	CAIE B,QRSTR
	 RET
	AOS (P)
QLGET4:	ILDB B,BP
	ILDB TT,BP
	ROT TT,7
	IOR B,TT
	ILDB TT,BP
	LSH TT,14.
	IOR B,TT
	SUBI B,4
	RET

;HANDLE THE CASE IN WHICH QLGET IS CALLED ON QREG HOLDING A BUFFER.
QLGET5:	CALL QLGET4	;GET ADDR OF HEADER, MINUS 4, IN B.
	ADDI B,4
	JUMPE B,POPJ1	;GIVE 0 AS LENGTH OF DEAD BUFFER
	SAVE T
	SAVE C
	MOVEI C,(B)	;IF THIS BUFFER IS CURRENT, THE VALUES IN ITS HEADER
	CAMN C,BFRPTR	;MAY BE  OUT OF DATE. UPDATE THEM BY RESELECTING.
	 CALL NEWBFR
	MOVE BP,MFGPT(B)
	CAMG BP,MFBEGV(B)
	 JRST QLGET6
	CAML BP,MFZV(B) ;IF THE GAP IS WHERE IT WILL DO HARM, THEN MOVE IT TO WHERE IT WON'T.
	 JRST QLGET6
	SAVE BFRPTR	;PUSH CURRENT BUFFER,
	MOVEI C,(B)	;SELECT THE ONE BEING QLGET'ED
	CALL NEWBFR
	SAVE PT
	MOVE BP,ZV
	MOVEM BP,PT	;PUT PT WHERE WE WANT THE GAP TO BE
	CALL GAPSL0	;AND MOVE THE GAP THERE. (WITHOUT SETTING MODIFF, NOT REALLY MODIFYING)
	REST PT
	REST C		;POP THE SELECTED BUFFER.
	CALL NEWBFR
QLGET6:	REST C
	MOVE BP,MFBEGV(B)	;GET VIRT ADDR OF BEGINNING OF BUFFER
	MOVE T,MFZV(B)
	SUB T,BP			;GET LENGTH OF BUFFER.
	CAML BP,MFGPT(B)
	 ADD BP,MFEXTR(B)	;CONVERT VIRT ADDR TO REAL ADDR.
	MOVE B,T
	REST T
	AOS (P)
	JRST GETIBP		;RETURN IN BP, B.P. TO ILDB BUFFER.

SUBTTL Q-REGISTER COMMANDS

;FQ<Q> - RETURN LENGTH OF TEXT IN <Q>, OR -1 IF NOT TEXT.
QLEN:	PUSHJ P,QREGX
	PUSHJ P,QLGET0
RETM1A:	 SKIPA A,[-1]
	MOVE A,B
	JRST POPJ1

;Q<Q> - RETURN CONTENTS OF QREG <Q> AS A NUMBER.
QREG:	AOS (P)
	JRST QREGX

;%<Q> - INCREMENT <Q>, RETURN NEW VALUE.
PCNT:	CALL QREGS	;READ QREG NAME, GET IDX IN CH.
	AOS C,A		;INCREMENT.  PUT IN C FOR USE2 AND IN A TO RETURN.
	AOS (P)		;WE ALWAYS RETURN A VALUE.
	JRST USE2	;GO STORE BACK IN QREG.

;U<Q> - PUT NUMERIC ARG IN <Q>. 2 ARGS => USE 2ND, RETURN 1ST.
USE:	TRZN FF,FRARG
	 TYPRE [WNA]
	ARGDFL
	CALL QREGS
USE1:	CAIN CH,A	;MAKE SURE U* IS A NO-OP.
	 JRST POPJ1
	TRZN FF,FRARG2	;M,NUQ SHOULD RETURN M.
	 JRST USE2
	MOVE A,E
	AOS (P)
;STORE THE CONTENTS OF C INTO THE QREG IN CH.
;B IS ASSUMED TO CONTAIN WHAT QREGX LEAVES THERE.
USE2:	CAIN CH,$QBUFR	;SELECT A NEW BUFFER BEFORE! SETTING ..O, IN CASE IT GETS ERROR.
	 CALL BFRSET
	SKIPE VARMAC
	 JUMPL B,USE3	;IF SETTING A NAMED VARIABLE, SEE IF THERE'S A MACRO TO RUN.
	CAIL CH,RRMACT
	 CAIL CH,RRMACT+1000
	  CAIA
	   CALL USE5
	MOVEM C,(CH)
	RET

;SETTING A ^R CHARACTER DEFINITION.
;SET THE RDFMSK BIT FOR THIS CHARACTER
;TO RECORD THAT IT HAS CHANGED.
USE5:	SAVE A
	SAVE B
	SAVE C
	MOVEI A,-RRMACT(CH)
	IDIVI A,32.
	MOVNS B
	MOVSI C,400000
	LSH C,(B)
	IORM C,RDFMSK(A)
	JRST POPCBA

USE3:	SAVE A
	SAVE B
	SKIPN A,1(CH)	;LOOK AT THE THIRD WORD OF THE NAMED VARIABLE'S DATA BLOCK.
	 JRST USE4	;(IF VARMAC IS SET, WE ASSUME THAT WORD EXISTS).
	CALL QLGET0	;IS IT A STRING?
	 JRST USE4
	ILDB B,BP	;DOES IT START WITH "!"?
	CAIN B,"!
	 CALL [	CALL SAVACS	;BOTH YES => CALL IT WITH NEW VALUE OF VARIABLE AS ARG.
		CALL MACXCP
		JRST RSTACS]
USE4:	MOVEM C,(CH)	;THEN, OR IN ANY CASE, SET THE VARIABLE.
	JRST POPBAJ

;<ARG>FP RETURNS AN INDICATION OF <ARG>'S DATA TYPE:
;-4 => NUMBER (NOT IN RANGE FOR PURE OR IMPURE STRING SPACE)
;-3 => PURE OBJECT WITH MEANINGLESS HEADER
;-2 => IMPURE OBJECT WITH MEANINGLESS HEADER
;-1 => DEAD BUFFER
;0 => LIVING BUFFER
;1 => Q-VECTOR.
;100 => PURE STRING
;101 => IMPURE STRING
FDATTY:	MOVNI A,4
	TRZN FF,FRARG
	 TYPRE [WNA]
	TLZN C,400000	;MUST BE CLOSE TO 400000,, TO BE ANYTHING BUT A NUMBER.
	 JRST POPJ1
	MOVE BP,C
	CAML C,BFRBOT	;IS IT IN RANGE FOR IMURE SPACE?
	 JRST [	MOVE D,LHIPAG
		IMULI D,5*2000
		CAMGE C,[LHIMAX*5*2000]	;NO, WHAT ABOUT PURE SPACE?
		 CAMGE C,D
		  JRST POPJ1		;NO, ORDINARY NUMBER
		AOJA A,FDATT2]		;YES, SEE WHAT KIND OBJECT (A _ -3)
	ADD BP,QRBUF	;ADDR'S IN IMPURE SPACE ARE REL. TO QRBUF.
	MOVNI A,2
;A HAS -2 FOR IMPURE SPACE, -3 FOR PURE SPACE.
;SEE IF OBJECT IS STRING, BUFFER OR NOTHING.
FDATT2:	CALL GETIBP
	ILDB B,BP
	CAIN B,QRSTR	;STRING => RETURN 100. OR 101.
	 JRST [	ADDI A,103.
		JRST POPJ1]
	CAME A,[-3]	;PURE AND NOT STRING => RETURN -3.
	 CAIE B,QRBFR	;IF IMPURE, MAYBE IT IS A BUFFER OR QVECTOR.
	  JRST POPJ1	;NOTHING => RETURN -3 OR -2.
	CALL QLGET4	;BUFFER: IS IT STILL ALIVE?
	ADDI B,4	;B GETS BUFFER BLOCK ADDR, OR 0 IF DEAD BUFFER.
	JUMPE B,RETM1A	;RETURN -1 IF DEAD.
	MOVEI A,0
	MOVE C,(B)
	TLNE C,MFQVEC
	 AOS A		;IF Q-VECTOR, RETURN 1, ELSE 0.
	JRST POPJ1

QGET3:	TRZ FF,FRARG\FRARG2
	JRST QGET4

;G<Q> COMMAND -- INSERT QREG <Q> IN BUFFER BEFORE PT.
;<M>,<N>G<Q> -- GET RANGE OF CHARS <M>,<N> FROM QREG.
;FS INSLEN$ IS SET TO # CHARS INSERTED.
;<M>:G<Q> -- RETURN THE <M>'TH CHARACTER OF <Q>.
QGET:	CALL QREGX
QGET4:	CALL QLGET0
	 JRST [	MOVE C,A ? JRST BAKSL1]
	TRNN FF,FRARG
	 SETZ C,
	CAMLE C,B	;MAKE SURE UNCOMMA'D ARG, IF ANY, IS WITHIN RANGE
	 MOVE C,B	;[0 , <LENGTH OF STRING>]
	SKIPGE C
	 SETZ C,
	TRNE FF,FRARG	;DETECT THE 1-ARG CASE (ONLY LEGAL WITH COLON).
	 TRNE FF,FRARG2
	  CAIA
	   JRST QGET7
	TRNN FF,FRARG2	;(IF NO ARGS, C AND E MAY BE RANDOM. PREVENT 2<1 ERROR).
	 SETZB C,E
	SKIPGE E
	 SETZ E,
	CAMLE E,C	;MAKE SURE ARGS ARE IN INCREASING ORDER.
	 TYPRE [2%1]
	TRNN FF,FRARG2
	 SKIPA C,B	;IF NO ARGS, # CHARS TO INSERT IS LENGTH OF QREG.
	  SUB C,E	;IF ARGS, IT IS DIFFERENCE BETWEEN ARGS.
	MOVEM C,INSLEN
QGETI:	SAVE A
	CALL SLP	;INSERT BUFFER SPACE OR PREPARE TO WRITE AT QRWRT. LEAVE BP. IN BP.
	MOVE IN,BP
	REST A
	JUMPE C,SLPXIT
	CALL QLGET0	;IN CASE QREG IS BUFFER AND WAS MOVED BY SLPGET,
	 .VALUE		;RECOMPUTE THE BYTE PTR TO IT.
	JUMPE E,QGET1	;IF NOT STARTING AT BEGINNING OF STRING,
	CALL GETCA	;MAKE B.P. -> ARG1'TH CHAR OF QREG.
	ADD BP,E
	CALL GETBP
QGET1:	HLRZ CH,BP
	HLRZ D,IN
	CAIN CH,010700
	 CAIE D,010700	;IF WE'RE AT A WORD BOUNDARY IN BOTH QREG AND BUFFER,
	  JRST QGET2
	CAIGE C,5	;AND TRANSFERING AT LEAST 1 WORD,
	 JRST QGET2
	IDIVI C,5	;DO A BLT TO AVOID LOSING LOW BITS.
	MOVEI CH,1(IN)
	HRLI CH,1(BP)
	ADD BP,C		;AND UPDATE BOTH B.P.'S TO POINT AFTER WHAT WE'RE BLT'ING.
	ADD IN,C
	BLT CH,(IN)
	SKIPN C,D	;# CHARS NOT TRANSFERED BY THE BLT.
	 JRST QGET6
QGET2:	ILDB CH,BP
	IDPB CH,IN
	SOJG C,QGET2
QGET6:	MOVE BP,IN		;IF WRITING A STRING, SLPXIT REQUIRES B.P. TO LAST CHAR IN BP.
SLPXIT:	TRZN FF,FRCLN		;WRITING IN BUFFER => FINISHED.
	 RET
	TRZ FF,FRUPRW+FRARG+FRARG2	;WRITING A STRING => FINISH CONSING AND RETURN IT.
	AOS (P)
	JRST QCLOSV

QGET7:	TRZN FF,FRCLN		;1 ARG TO G IS BAD NUMBER UNLESS WE HAVE A COLON.
	 TYPRE [WNA]
	CAML C,B
	 TYPRE [ARG]
	TRZ FF,FRUPRW+FRARG
	CALL GETCA		;INCREMENT THE B.P. IN BP BY THE # CHARS WHICH IS THE ARG.
	ADD BP,C
	CALL GETBP
	ILDB A,BP		;AND FETCH THAT CHARACTER AND RETURN IT AS VALUE OF <N>:G<Q>.
	JRST POPJ1

X:	CALL QREGVS
	CALL GETANU		;X COMMAND, GET ENDS OF AREA IN C,E.
X12:	TRZ FF,FRARG\FRARG2	;FLUSH ARG;  AVOIDS LOSSAGE FOR X* WHICH RETURNS VALUE.
	JUMPE B,X10		;IS THE QREG SUBSCRIPTED? (X:Q(IDX))
	JSP TT,QREGVA		;IF SO, EXTRA HAIR IN CASE OUR CONSING
				;MOVES THE Q-VECTOR CONTAINING THE Q-REG.
				;CALLS X10, THEN RETURNS TO INSERT'S CALLER.

X10:	SAVE CH
	SAVE B
	TRZE FF,FRUPRW
	 PUSHJ P,QLGET0	;APPENDING TO QREG-GET PREVIOUS LENGTH/LOCATION
	  SETZB B,BP
	SAVE B
	SAVE BP
	CALL CHK1
	SUB C,E		;C HAS # CHARS TO X AWAY
	ADDI C,4	;THEN INCLUDE 4 CHARS FOR HEADER.
	ADD C,-1(P)	;HOW MUCH SPACE, INCLUDING OLD STRING WE ARE APPENDING TO?
	SAVE C
	MOVN J,BEG
	CALL SLPQGT	;MAKE SURE HAVE ENOUGH SPACE IN IMPURE STRING SPACE.
	ADD J,BEG	;CHANGE IN BEG = AMOUNT BUFFER MOVED.
	ADD E,J		;RELOCATE ADDR OF START OF AREA OF BUFFER TO X FROM.
	MOVE C,(P)	;GET LENGTH INCL. HEADER.
	MOVEI B,QRSTR	;AND 1ST CHAR FOR HEADER.
	CALL QHDRW1	;WRITE THE HEADER IN BOTTOM OF FREE AREA.
	REST C
	SUBI C,4	;C HAS LENGTH NOT INCL. HEADER.
	CALL IMMQIT	;ALLOW QUITTING OUT OF COPYING THE CHARACTERS.
	MOVE D,BP	;D HAS BP FOR STUFFING CHARS DOWN.
	SKIPN J,-1(P)	;ANY CHARS TO APPEND TO?
	 JRST X8
	SUB C,J		;YES, COUNT OFF THAT MANY AS INSERTED,
	MOVE OUT,(P)	;GET BP TO ILDB OLD TEXT TO APPEND TO,
X7:	ILDB CH,OUT	;AND COPY INTO NEW STRING.
	IDPB CH,D
	SOJG J,X7
X8:	MOVE BP,E	;BP GETS BP TO FETCH FROM BUFFER.
	MOVE IN,BP	;IN GETS CHAR ADDR OF WHAT WE ARE FETCHING.
	CALL GETIBV
X1:	SOJL C,X2	;INSERT THE CHARS FROM THE BUFFER INTO THE STRING.
	CAMN IN,GPT	;MOVE BP ACROSS THE GAP WHEN WE REACH IT.
	 CALL FEQGAP
	ILDB CH,BP
	IDPB CH,D
	AOJA IN,X1

X2:	CALL DELQIT
	MOVE BP,D	;FIND CHAR ADDR OF WHERE WE STOPPED WRITING THE STRING
	CALL GETCA
	AOS OUT,BP	;GET CHAR ADDR OF LAST+1.
	TRZ FF,FRCLN\FRUPRW
	SUB P,[2,,2]	;FLUSH INFO ON OLD STRING TO APPEND TO.
	REST B
	JRST QCLOSP	;POP QREG ADDR AND STORE STRING IN IT.

SUBTTL Q-REGISTER PDL

;[<Q> - PUSH <Q> ONTO QREG PDL.  ;]
OPENB:	ARGDFL			;MAKE -[0 THE SAME AS -1[0  ;]]
	CALL QREGX		;READ THE QREG VALUE IN A AND ADDR IN CH.
	SAVE CH
	SKIPLE B		;IF THIS QREG IS REALLY AN ELT OF A QVECTOR,
	 TYPRE [IQN]		;AUTO-UNWIND WOULD LOSE, SO COMPLAIN.
	SKIPGE B
	 MOVE CH,IN		;FOR NAME QREGS, PUSH INTERNED NAME-STRING AS QREG ADDR.
	SAVE B			;PRESERVE FLAG FOR USE1.
	MOVE B,PF
	CAMN B,PFTOP		;CHECK FOR OVERFLOW BEFORE WRITING ANYTHING.
	 TYPRE [QRP]
	PUSH B,A		;THEN PUSH OLD CONTENTS
	CALL OPENB3		;GO PUSH ADDR OF QREG (FOR UNWINDING) AND RETURN.
	REST B
	REST CH			;GET BACK ACTUAL LOCATION OF QREG
	TRZN FF,FRARG		;AND IF WE HAVE ARG, STORE ARG INTO IT.
	 RET
	JRST USE1		;DO IT VIA USE SO THAT STORING INTO ..O WORKS.

OPENB2:	MOVE B,PF
	CAMN B,PFTOP		;DETECT OVERPUSH BEFORE A PDLOV INT HAPPENS.
OPENB1:	 TYPRE [QRP]
	PUSH B,(CH)
OPENB3:	PUSH B,CH
FSQPU2:	MOVEM B,PF
	POPJ P,

;[[  ;]<Q> - POP FROM QREG PDL INTO <Q>.  ]* POPS AND RETURNS AS VALUE.
CLOSEB:	CALL QREGVS		;CAN MAKE US SKIP!
	CAIA
;POP INTO ADDRESS SUPPLIED IN CH.  ASSUME IT'S NOT A NAMED VARIABLE.
CLOSB2:	 SETZ B,	;B SUPPLIES INFORMATION TO USE2.
	MOVE A,PF
	CAMN A,PFINI	;DETECT UNDERFLOW FIRST THING.
	 TYPRE [QRP]
	POP A,C
	POP A,C		;C GETS VALUE POPPED FROM SLOT.
	MOVEM A,PF	;MARK SLOT GONE BEFORE WE STORE, SINCE USE2 CAN ERR.
	JRST USE2

;FS QPPTR $ -- GET OR SET QREG PDL POINTER.
;TAKES AND RETURNS # ENTRIES ON STACK.
FSQPPT:	HRRZ A,PF
	SUBI A,PFL-1	;GET 2*<# ENTRIES NOW ON STACK>
	LSH A,-1	;A HAS VALUE TO RETURN.
	TRZN FF,FRARG
	 JRST POPJ1	;NO ARG => JUST RETURN THE VALUE.
	CALL FSQPRG	;CONVERT ARG TO NEW PDL PTR.
	MOVEM C,PF	;STORE NEW CONTENTS.
	JRST POPJ1

;HANDLE ARGUMENT DECODING FOR FS QP SLOT, FS QP PTR, AND FS QP UNWIND.
FSQPRG:	ARGDFL
	JUMPL C,FSQPR1
	LSH C,1		;ARG -> PTR TRANSFORMATION IS INVERSE OF
	HRLI C,(C)	;PTR -> VALUE TRANSFORMATION DONE ABOVE.
	ADD C,PFINI
	CAMLE C,PF
	 JRST TYPAOR	;DON'T ALLOW REF. TO CELLS ABOVE CURRENT POINTER POS.
	RET

FSQPR1:	LSH C,1		;NEGATIVE ARG IS RELATIVE TO CURRENT POINTER.
	HRLI C,-1(C)
	ADD C,PF
	CAMGE C,PFINI	;DON'T ALLOW REF BELOW BOTTOM OF QREG PDL.
	 JRST TYPAOR
	RET

PFINI:	-LPF-1,,PFL-1
PFTOP:	-1,,PFL+LPF-1

;<N>FS QP HOME$ RETURNS A STRING WHICH IS THE NAME OF THE Q-REG THAT WAS
;PUSHED INTO PDL SLOT <N>.  <N>:FSQP HOME$ RETURNS A NUMBER THAT ENCODES
;THAT NAME - SUCH NUMBERS ARE USEFUL IN THAT, IN A GIVEN TECO, EACH QREG
;HAS A UNIQUE NUMBER.  WITH NO COLON, IF THE SLOT WAS PUSHED WITH
;F[FOO$, WE RETURN "FSFOO$".     ;]
;@FS QPHOME$ CONVERTS AN NUMBER WHICH IS A :FSQPHOME VALUE INTO A
;DESCRIPTIVE FSQPHOME$-STYLE STRING.  SO <N>:FSQPHOME$ @FSQPHOME$ = <N>FSQPHOME$.
FSQPHO:	TRZN FF,FRARG
	 TYPRE [WNA]
	TRZE FF,FRUPRW
	 JRST FSQPH2
	CALL FSQPRG	;FIND SLOT <N>.
	CAML C,PF	;FSQPGR ALLOWS CURRENT PDL PTR AS ARG, BUT THAT ISN'T
	 TYPRE [AOR]	;LEGAL AS THE NUMBER OF A SLOT.
	MOVE C,2(C)	;GET WHERE PUSHED FROM.
	MOVE A,C
FSQPH2:	TRZE FF,FRCLN	;NUMERIC FORM MAY BE WHAT WE WANT.
	 JRST POPJ1	;OTHERWISE, MUST DECODE AND TURN INTO STRING:
		;ALREADY A STRING => IT IS VARIABLE NAME;  PUT ALTMODES AROUND IT.
	JUMPL C,[ MOVEM C,NUM
		  MOVEI A,[ASCIZ /[0 :I*Q0/]   ;]
		  JRST MACXQV]	;THAT'S DONE MOST EASILY BY TECO COMMANDS.
	MOVEI A,[ASCIZ /:I**/]
	CAIN C,BAKTAB	;IF A [(...) PUSHED THIS SLOT, RETURN "*".   ;]
	 JRST MACXQV
	CAIGE C,FLAGSL*2	;IF AN F[ PUSHED THIS,  ;]
	 JRST [	MOVE C,FLAGS(C)	;RETURN NAME OF FLAG IN ASCII.
		JRST FSIXFL]
	MOVE E,C
	MOVEI C,6	;OTHERWISE IT WAS A NORMAL QREG OR A ^R COMMAND DEFINITION.
	CALL QOPEN	;SO START CONSING UP A STRING WITH THE NAME.
	MOVEI CH,"Q
	IDPB CH,BP
	CAIGE E,RRMACT
	 JRST FSQPH1
	SUBI E,RRMACT	;IT WAS A ^R COMMAND.  WHAT WAS 9-BIT CHARACTER?
	IDIVI E,200
	CALL FSQPH.	;PUT OUT 1 DOT FOR CTL, 2 FOR META, 3 FOR BOTH.
	MOVEI CH,^R
	IDPB CH,BP
FSQPH3:	IDPB J,BP	;THEN THE ASCII PART OF THE CHARACTER.
	AOS (P)
	JRST QCLOSV	;INISH CONSING THE STRING AND RETURN IT.

FSQPH1:	SUBI E,QTAB	;ORDINARY OLD-FASHIONED QREG.
	IDIVI E,36.	;HOW MANY DOTS?
	CALL FSQPH.
	ADDI J,"0	;CONVERT WHAT'S LEFT TO A LETTER OR DIGIT.
	CAILE J,"9	;(STARTS OUT AS IDX IN QRB, QRB. OR QRB..).
	 ADDI J,"A-"0-10.
	JRST FSQPH3

FSQPH.:	MOVEI CH,".	;OUTPUT DOTS THRU BP IN BP.  J SAYS HOW MANY.
	JUMPE E,CPOPJ
	IDPB CH,BP
	SOJA E,FSQPH.

MACXQV:	CALL MACXQW	;EXECUTE A MACRO IN A AND RETURN THE VALUE IT RETURNS.
	MOVE A,NUM
	TRZ FF,FRARG\FRARG2\FRUPRW\FRCLN
	JRST POPJ1

;<N> FS QPSLOT $ -- RETURNS CONTENTS OF SLOT <N>.
;<M>,<N>FS QPSLOT $ ALSO SETS THE SLOT TO <M>.
FSQPSL:	MOVE E,SARG
	TRZN FF,FRARG	;MUST HAVE ARG TO KNOW WHICH SLOT.
	 TYPRE [WNA]
	TRZE FF,FRARG2	;IF 1 ARG, IT'S SLOT #, IN C.
	 TRO FF,FRARG	;IF 2, SLOT #'S IN C, NEW VALUE IN E.
	CALL FSQPRG	;FIND ADDRESS OF DESIRED SLOT IN C.
	CAML C,PF	;FSQPGR ALLOWS CURRENT PDL PTR AS ARG, BUT THAT ISN'T
	 TYPRE [AOR]	;LEGAL AS THE NUMBER OF A SLOT.
	EXCH C,E
	AOJA E,FSNOR1	;WORD TO GET OR SET IS 2ND WORD OF SLOT.

;<N> FS QPUNWIND $ -- UNWINDS QREG PDL TO LEVEL <N>.
;THAT IS, POPS EACH ENTRY BACK INTO THE QREG IT WAS PUSHED FROM.
FSQPUN:	TRZN FF,FRARG	;NO ARG => ASSUME 0.
	 SETZ C,
	PUSHJ P,FSQPRG	;COMPUTE LEVEL TO UNWIND TO FROM ARG.
FSQPU0:	SAVE STOPF	;DON'T QUIT WHILE UNWINDING!!
	SETZM STOPF	;MIGHT WANT TO SET NOQUIT INSTEAD, BUT THIS IS SAFER.
FSQPU7:	MOVE B,PF
FSQPU1:	CAMG B,C	;DOWN TO DESIRED LEVEL?
	 JRST [	REST STOPF
	 	JRST FSQPU2]	 ;JUST SET PF & EXIT
	POP B,CH	;POP 1 ENTRY
	JUMPL CH,FSQPU5	;JUMP IF "QREG ADDR" IS A STRING - MEANS IT IS QREG NAME, A LA QFOO.
IF2 IFG FLAGSL*2-QTAB,.ERR QRP CAN'T TELL [ FROM F[
			;]]
	CAIGE CH,FLAGSL*2	;IF ENTRY WAS MADE BY AN F[, POP INTO FLAG.  ;]
	 JRST FSQPU4
	CAIN CH,$QUNWN	;IF UNWINDING Q..N,
	 JRST [	MOVE A,(CH)
		POP B,(CH) ;POP IT, STORING OR SAVING ALL TEMPS,
		JRST FSQPU3];AND GO MACRO IT.
	POP B,(CH)
	CAIN CH,$QBUFR	;IF UNWINDING Q..O, WE'RE SELECTING A NEW BUFFER.
	 CALL BFRSE2
	CAIL CH,RRMACT
	 CAIL CH,RRMACT+1000
	  CAIA		;UNWINDING A ^R CHAR DEFINITION => RECORD THIS FACT
	   CALL USE5	;TO TELL TERMINAL LATER (FOR LOCAL EDITING).
	JRST FSQPU1

FSQPU4:	SAVE C		;HANDLE UNWINDING AN FS FLAG.
	POP B,C	;GET OLD FLAG VALUE, AS ARG.
	MOVS E,FLAGD(CH)
	SAVE FF
	IORI FF,FRARG	;SAY THERE'S AN ARG.
	MOVEM B,PF
	CALL (E)	;SET THE FLAG.
	 JFCL
	REST FF		;DON'T LET THE ROUTINE CLOBBER THE VALUES.
	REST C
	JRST FSQPU7

FSQPU3:	JUMPE A,FSQPU1
	JSP T,OPEN1	;HANDLE UNWINDING Q..N; MUST PRESERVE TEMPS.
FSQPU6:	SAVE C
	SAVE BKRTLV
	MOVEM B,PF
	CALL MACXQW	;EXECUTE THE INNER BINDING OF ..N (WHICH IS IN A).
	REST BKRTLV
	REST C
	HRROI T,FSQPU7
	TRZ FF,FRARG+FRARG2+FRSYL+FROP
	JRST CLOSE2	;POP WHAT OPEN PUSHED, AND GO TO FSQPU0

FSQPU5:	MOVE A,CH	;POP INTO LONG-NAMED QREG WHOSE NAME IS IN CH.
	JSP T,OPEN1
	MOVEM A,SARG
	TRO FF,FRARG\FRARG2
	TRZ FF,FRCLN\FRUPRW\FRSYL\FROP
	POP B,NUM
	MOVEI A,[ASCIZ /[0 U0/]    ;]
	JRST FSQPU6

SUBTTL M SUBROUTINE CALL COMMAND

;M<Q> SAVES CURRENT EXECUTION POINTERS AND THEN EXECUTES CONTENTS OF <Q>.
 ;<Q> MAY CONTAIN TEXT OR THE ADDRESS OF A BUILT-IN FUNCTION.
;:M<Q> JUMPS INTO THE STRING IN <Q> AND DOESN'T RETURN - BUILT-IN FUNCTIONS NOT ALLOWED.
MAC:	CALL QREGX	;GET A NAME AND PUT ITS ENTRY IN A
	CAIL CH,RRMACT	;FOR M^R ETC, PUT THE CHARACTER WHOSE DEFINITION IS BEING RUN
	 CAIL CH,RRMACT+1000
	  JRST MAC6
	SUBI CH,RRMACT	;IN Q..0.
	MOVEM CH,$Q..0
MAC6:	MOVE CH,$Q..0
MAC5:	CALL QLGET0	;REALLY TEXT? IF SO, LENGTH IN B, BP TO ILDB TEXT IN BP.
	 JSP T,MACN	;NOT REALLY TEXT; USE AS BUILT-IN FUNCTION ADDRESS.
	TRNE FF,FRCLN	;IF YOU ARE DOING A :M, DON'T PUSH THE CALLING STRING
	 JRST MAC3
MAC2:	MOVEM BP,INSBP	;ELSE PUSH THE STRING CONTAINING THE "M" BEFORE JUMPING.
	CALL PUSMAC	;WE SAVE THE B.P. TO THE MACRO BEING CALLED IN INSBP
	MOVE BP,INSBP	;SO IT WILL BE RELOCATED BY GETFR2.
	MOVEI CH,0
	IDPB CH,MACPDP	;PUSH A 0 (MACRO CALL) ENTRY.
	.I MACSPF=PF	;REMEMBER QREG PDL LEVEL FOR THIS FRAME TO POP TO.
	SETZM MACBTS
MAC3:	MOVEM A,CSTR	;STORE TECO OBJECT POINTER TO WHAT WE'RE CALLING.
	SETZ TT,	;PUT IN MACBTS INDICATIONS OF HOW MANY ARGS THERE ARE.
	TRNE FF,FRARG	;MFBA1 AND MFBA2 ARE SIMPLY SET.
	 TLO TT,MFBA2
	TRNE FF,FRARG2
	 TLO TT,MFBA1
	TRNE FF,FRUPRW	;MFBATSN IS SET TO WHETHER THERE WAS AN @, EXCEPT
	 TLO TT,MFBATSN
	MOVSI C,MFBATSN	;THAT :M WITH NO @ DOES NOT CLEAR MFBATSN IF IT WAS SET.
	ANDM C,MACBTS
	IORM TT,MACBTS
	MOVEI C,1
	TRZE FF,FRUPRW	;GET THE FIRST MACRO ARGUMENT (OR, IF NONE,
	 TRNE FF,FRARG	;EITHER 0 OR (IF FRUPRW) 1).
	  MOVE C,NUM
	ARGDFL
	MOVEM C,MARG2	;SAVE IT AS THE THING ^Y GETS
	MOVE C,SARG	;TRY FOR A SECOND ARGUMENT
	TRNN FF,FRARG2
	MOVEI C,0	;IF NONE, THEN 0
	MOVEM C,MARG1	;SIGH
	MOVEM B,COMCNT	;STORE LENGTH OF TEXT AS LENGTH OF MACRO.
	MOVEM BP,CPTR	;GIVE RCH THE BP TO THE TEXT.
	ILDB CH,BP	;NOW, START EXECUTING THE MACRO, BUT FIRST
	CAIE CH,"W+40	;UNLESS THE FIRST CHARACTER IS "W", MAYBE INVOKE FS STEPMAC$
	 CAIN CH,"W
	  JUMPN B,CD
	CALL CTLM2
	JRST CD

;A IS ADDR 1ST WD ASCIZ STRING, EXECUTE STRING AS MACRO.
MACXCW:	HRLI A,BP7
MACXCT:	SETO B,	;A IS BP -> STRING.
	MOVE BP,A	;MUST COUNT # CHARS IN STRING.
MACXC1:	ILDB CH,A
	AOJ B,
	JUMPN CH,MACXC1
	MOVE A,BP	;GIVE THE BYTE POINTER AS THE FS BACK STR$ SINCE THERE'S NO
	JRST MACXC2	;ACTUAL TECO OBJECT POINTER WE CAN USE.

MACXQW:	JUMPGE A,MACXCW	;EXECUTE EITHER A QREG OR AN ASSEMBLED-IN ASCII STRING.
			;DISTINGUISH THEM SINCE STRING QREGS ARE NEGATIVE.

;A HAS CONTENTS OF A QREG; PUSHJ HERE TO EXECUTE IT, POPJ'ING AFTER IT FINISHES.
MACXQ:	CALL QLGET0	;GET LENGTH AND STARTING BP OF STRING.
	 JSP T,MACN1	;(QREG CONTAINS A NUMBER;  PUSHJ TO THAT LOCATION).
MACXC2:	TRZ FF,FRUPRW
	SAVE MACPTR
	SAVE MACXP
	MOVEM P,MACXP	.SEE RCH2
	SETOM MACPTR	;-1 SAYS CALLED FROM MACXP.
	JRST MAC2

MACN:	TRNN FF,FRCLN	;HERE WHEN AN "M" COMMAND CALLS A BUILT-IN FUNCTION.
	 JRST MACN2
	MOVE T,[440700,,[ASCIZ //]]
	MOVEM T,CPTR	;IF IT'S A ":M", THEN DISCARD REST OF CALLING STRING
	MOVEM T,CSTR	;REPLACING IT WITH A ^\ TO POP ITS QREGS.
	MOVEI T,1
	MOVEM T,COMCNT
MACN2:	SAVE [CDRET]	;POPJ TO EITHER (JRST TO) CD, OR VALREC IF SKIP.
	MOVEI T,2+[ SUB P,[1,,1] ? JRST MAC5]
;T HAS 2+ ADDR TO GO TO IF THIS NUMBER "TURNS OUT" TO BE A STRING AFTER ALL.
;2+ IS SO CAN JSP AFTER A FAILING CALL TO QLGET0.
MACN1:	ARGDFL		;MACROING A QREG CONTAINING A NUMBER.
	TRNN FF,FRARG
	 MOVEI C,1
	MOVE E,A
	ANDI A,-1
	CAIE A,RRINDR	;TRACE THRU INDIRECTD DEFINITIONS HERE, SO THAT
	 JRST [	TRZ FF,FRCLN
		JRST RRLP7H]
	HLRE A,E	;IF THE ULTIMATE TARGET IS A STRING, WE CAN MACRO IT
	SUB CH,A	;WITH OUT GOING THROUGH RRMACR.
	MOVE A,RRMACT(CH)
	JRST -2(T)

;<N>FSBACKTRACE$ - INSERT IN THE BUFFER THE TEXT OF THE MACRO IN FRAME <N>.
;LEAVE POINT AT THE PC OF THAT FRAME.
FSBAKT:	CALL BACKTR	;FIND THE FRAME THE USER SPECIFIED.
FSBAK1:	CALL MFBEGP	;GET STARTING B.P. IN B AND CURRENT PC IN C.
	SAVE B
	ADD C,MFCCNT(A)	;C GETS TOTAL SIZE OF MACRO.
	MOVEM C,INSLEN	;INSERT SPACE IN BUFFER TO HOLD THE STRING.
	CALL SLPGET
	MOVN A,MFCCNT(A)
	ADDM A,PT
	MOVE IN,BP
	REST BP
	JRST QGET1

;<N>FS BACK PC$ - RETURN RELATIVE PC (OFFSET FROM 1ST CHAR) OF MACRO IN FRAME <N>.
;<PC>,<N>FS BACK PC$ - SET RELATIVE PC OF THAT FRAME TO <PC>.
; SETTIN THE PC TO A VERY LARGE NUMBER PUTS IT AT THE END OF THE STRING.
FSBAKP:	CALL BACKTR
	CALL MFBEGP	;C GETS CURRENT RELATIVE PC.
	SAVE C
	TRZN FF,FRARG2	;DO WE WANT TO CHANGE IT?
	 JRST POPAJ1
	ADD C,MFCCNT(A)
	MOVE E,SARG
	CAMLE E,C	;IF ARG IS GREATER THAN # OF CHARS IN STRING, MAKE POINT AT END.
	 MOVE E,C
	SKIPGE E	;NEGATIVE PC'S ARE MEANINGLESS.
	 TYPRE [AOR]
	ADD BP,E	;IF SO, ADD DESIRED PC TO CHAR ADDR OF START
	CALL GETBP	;CONVERT TO B.P. AND STORE AS THE FETCH POINTER.
	MOVEM BP,MFCPTR(A)
	SUB E,(P)	;GET THE DIFFERENCE BETWEEN NEW PC AND OLD
	MOVNS E
	ADDM E,MFCCNT(A) ;AND UPDATE NUMBER-OF-CHARS-TO-GO BY THAT MUCH.
	JRST POPAJ1

;<N>FS BACK QP PTR$ - RETURN FS QP PTR$ OF BOTTOM OF QP FRAME
;BELONGING TO MACRO FRAME <N>.  THIS IS THE QP PTR WHICH
;^\'ING THAT FRAME WOULD UNWIND TO.
FSBAKQ:	CALL BACKTR
	HRRZ A,MFPF(A)	;GET SAVED QREG PDL POINTER,
	SUBI A,PFL-1	;CONVERT IT TO A PDL DEPTH INDEX.
	LSH A,-1
	JRST POPJ1

;<N>FS BACK ARGS$ - RETURN ARGS OF MACRO FRAME <N>.
FSBAKA:	CALL BACKTR		;GET POINTER TO FRAME IN A.
	MOVE C,MFLINK(A)	;GET FRAME'S SAVED MACBTS, MARG1, MARG2
	MOVE B,MFARG1(A)
	MOVE A,MFARG2(A)
	JRST FCTLX2		;AND RETURN APPROPRIATE VALUES, A LA F^X.

;<N>FS BACK STRING$ - RETURN STRING POINTER TO MACRO BEING EXECUTED IN FRAME <N>.
;IF THAT MACRO ISN'T A STRING, WE RETURN A BYTE POINTER (A NUMBER).
;THERE IS NO WAY TO DECODE SUCH BYTE POINTERS, BUT THEY CAN BE COMPARED RELIABLY.
FSBAKS:	CALL BACKTR		;GET FRAME POINTER IN A.
	MOVE A,MFCSTR(A)
	JRST POPJ1

;SUBROUTINES FOR FS BACK WHATEVER.

;A POINTS AT A MACRO FRAME (OR AT COMCNT);  RETURN IN B A B.P. TO THE MACRO'S START,
;AND IN C THE DISTANCE IN CHARACTERS OF THE CURRENT PC FROM THE START.
MFBEGP:	MOVE BP,MFCPTR(A)
	CALL GETCA
	MOVE C,BP
	SAVE A
	MOVE A,MFCSTR(A)
	CALL QLGET0
	 MOVE BP,A
	MOVE B,BP	;B GETS B.P. TO START OF MACRO.
	CALL GETCA	;BP GETS CHAR ADDR OF IT.
	SUB C,BP
	JRST POPAJ

;RETURN IN A A POINTER TO THE MACRO FRAME SPECIFIED BY THE DEPTH IN C.
;IF C IS POSITIVE, IT IS COUNTING FROM THE BOTTOM OF THE STACK
;(0 = OUTERMOST FRAME).  IF IT IS NEGATIVE, IT COUNTS DOWN FROM THE
;CURRENT FRAME (-1 = THIS FRAME'S CALLER).
BACKTR:	ARGDFL Z
	MOVNS C
	SKIPG C
	 ADD C,MACDEP	;C NOW HAS NUMBER OF FRAMES TO GO OUT FROM CURRENT ONE.
	SOJL C,TYPAOR	;ILLEGAL TO REFER TO CURRENT FRAME, SINCE IT ISN'T STORED THE SAME WAY.
	MOVE B,MACXP
	HRRE A,MACPTR	;START WITH TOP OF MACPTR STACK (CURRENT MACRO'S CALLER).
BACKT0:	JUMPGE A,BACKT2
	HRRE A,-1(B)	;WHENEVER A MACXQ CALL IS FOUND, GO BACK THROUGH IT.
	MOVE B,(B)
	JRST BACKT0

BACKT2:	JUMPE A,TYPAOR
	JUMPE C,[	;HAVE WE GONE OUT ENOUGH FRAMES?
		SUBI A,MFLINK
		RET]
	HRRE A,(A)	;NO, GO OUT ONE FRAME MORE.
	SOJA C,BACKT0

GMARG2:	SKIPA A,MARG2
GMARG1:	MOVE A,MARG1
	JRST POPJ1

SUBTTL CONVERT NUMBERS TO STRINGS

BAKSL:	TRZ FF,FRUPRW
	TRZE FF,FRARG
	 JRST BAKS1A
	SETZ A,
	MOVE IN,PT
	PUSHJ P,GETINC
	TRZE FF,FRCLN
	 CAIE CH,"-
	  JRST BAKSL7
	TRO FF,FRARG
BAKSLA:	PUSHJ P,GETINC
BAKSL7:	CAMLE IN,ZV
	 JRST BAKSL3
BAKSL6:	CAIG CH,"9
	 CAIGE CH,"0
	  SOJA IN,BAKSL2
	JFCL 10,.+1
	IMUL A,IBASE
	JFCL 10,[TLC A,400000 ? JRST .+1]	;MAKE OVERFLOW ACT AS IF UNSIGNED MULTIPLY.
	ADDI A,-60(CH)
	JRST BAKSLA

BAKSL3:	MOVE IN,ZV
BAKSL2:	TRZE FF,FRARG
	 MOVNS A
	MOVEM IN,PT
	JRST POPJ1

;<N>\ WRITE <N> IN BASE IN ..E, INTO BUFFER.  :<N>\ CONS INTO STRING AND RETURN IT.
;<M>,<N>\ USE <M> COLUMNS, MAKING LEADING SPACES IF NEEDED.
BAKS1A:	MOVEI TT,40
	HRRM TT,DPT5
	TRZN FF,FRARG2
	 JRST BAKSL1
	CAIL E,LTABS*5	;DON'T ALLOW USELESSLY LARGE 1ST ARGS
	 TYPRE [AOR]	;SINCE MAKING THEM WORK PROPERLY WOULD BE A PAIN.
	SOS TT,E
	SKIPA BP,[DPT1]
BAKSL1:	 MOVEI BP,DPT
	MOVE T,[(700)BAKTAB-1]
	MOVEI E,0
	MOVEI CH,[IDPB CH,T ? AOJA E,CPOPJ]
	HRRM CH,LISTF5
	PUSHJ P,(BP)
	MOVE C,E
	MOVEM C,INSLEN
	CALL SLP	;INSERT THEM, OR PREPARE TO WRITE STRING. GET BP IN BP.
	MOVE T,[440700,,BAKTAB]
BAKSLL:	ILDB CH,T	;COPY THE PRINTED STUFF INTO INSERTED SPACE.
	IDPB CH,BP
	SOJG C,BAKSLL
	JRST SLPXIT	;IN CASE OF :\, FINISH CONSING THE STRING.

SUBTTL CONTROL CONSTRUCTS

FDQUOT:	SUB P,[1,,1]	;F" LIKE " BUT ARGUMENT REMAINS AS WELL AS BEING TESTED.
	SKIPA A,[CD2A]
DQUOTE:	 MOVEI A,CD
	CALL LRCH	;READ THE CONDITION NAME (B, C, G, L, E, N, #)
	CAIN CH,"#	;IS THIS AN "ELSE"?
	 JRST [	CALL NOGO	;YES, FAIL: SKIP TO THE ',
		JRST CD2A]	;RETURN WITHOUT FLUSHING VALUE.
	CAIN CH,"'
	 JRST VCOND
	SAVE A			;REMEMBER RETURN ADDRESS (CD OR CD2A).
	CALL CONDIT		;DECODE THE CONDITION,
	XCT A			;TEST IT,
	 TRC FF,FRCLN		;TAKE THE EQV OF ITS SUCCESS AND THE COLON FLAG.
	TRZN FF,FRCLN
	 JRST CTLM2		;NON-: CONDITION WON OR :-CONDITION LOST, INVOKE STEPPER AND RETURN.
NOGO:	MOVEI A,0		;CONDITION FAILED.  SKIP TO THE ' AND CHECK FOR AN ELSE.
	MOVE C,COMCNT		;REMEMBER WHERE STARTING FROM, SO IF HAVE UTC ERROR
	MOVE E,CPTR		;CAN SIGNAL IT AT THE ".
NOGO1:	SOSGE COMCNT
	 JRST [	MOVEM C,COMCNT
		MOVEM E,CPTR
		TYPRE [UTC]]
	ILDB CH,CPTR
	CAIN CH,""
	 AOJA A,NOGO1
	CAIE CH,"'
	 JRST NOGO1
	SOJGE A,NOGO1
	CALL TRACS	;FOUND THE TERMINATING '.  MENTION IT IF TRACING.
	MOVE A,COMCNT
	MOVE BP,CPTR
NOGO2:	SOJL A,CPOPJ	;AFTER THE MATCHING ', CHECK FOR AN ELSE ("#)
	ILDB CH,BP	;IS THE NEXT CHAR A DOUBLEQUOTE?
	CAIE CH,^M
	 CAIN CH,^J	;ALLOW CRLFS TO INTERVENE BEFORE THE DOUBLEQUOTE.
	  JRST NOGO2	;JUST PASS THEM BY.
	SKIPGE TABMOD
	 CAIE CH,^I
	  CAIN CH,40
	   JRST NOGO2	;ALSO ALLOW SPACES BETWEEN.
	CAIN CH,"!	;ALSO ALLOW TAGS BETWEEN.
	 JRST NOGO3
	CAIE CH,""
	 RET		;NO - THERE IS NO "ELSE"
	SOJL A,CPOPJ	;MAKE SURE A "#" FOLLOWS THE """".
	ILDB B,BP
	CAIE B,"#
	 RET
	CALL TRACS	;THERE IS AN ELSE - TRACE THE " AND #.
	MOVEI CH,"#
	CALL TRACS
	MOVEM BP,CPTR	;RESUME EXECUTION INSIDE THE ELSE CLAUSE.
	MOVEM A,COMCNT
	JRST CTLM2	;WE HAVE JUST ENETERED AN ELSE CLAUSE, SO INVOKE STEPPER.

NOGO3:	SOJL A,CPOPJ
	ILDB CH,BP	;SKIP UNTIL THE NEXT "!", THEN CONTINUE LOOKING FOR '"#'.
	CAIE CH,"!
	 JRST NOGO3
	JRST NOGO2

;READ THE NAME OF A CONDITION, AND RETURN IN A
;AN INSTRUCTION TO SKIP IF THE CONDITION IS TRUE.
CONDIT:	TRNN FF,FRARG
	 TYPRE [WNA]	;THIS IS A NUMERIC CONDITIONAL: SNARF THE ARG.
	MOVEI A,C
IRPC Z,,[GLNE]
	CAIN CH,"Z
	 HRLI A,(SKIP!Z)
TERMIN
	CAIN CH,"A
	 MOVE A,[CALL DQTLET]
	CAIN CH,"D
	 MOVE A,[CALL DQTDGT]
	CAIN CH,"U
	 MOVE A,[CALL DQTUC]
	CAIN CH,"C
	 MOVE A,[CALL DQT1]
	CAIN CH,"B
	 MOVE A,[CALL DQT3]	;B => GET INSN TO SKIP IF GIVEN A BREAK CHARACTER.
	TLNN A,-1		;IF WE DIDN'T RECOGNIZE THE CONDITION, SIGNAL AN ERROR.
	 TYPRE [BD%]
	RET

DQT1:	PUSHJ P,DQT3		;SKIP IF CHAR IN C IS NOT A BREAK CHARACTER.
	 AOS (P)
	RET

DQTLET:	CAIG C,"Z+40		;SKIP IF CHARACTER IN C IS A LETTER.
	 CAIGE C,"A+40
DQTUC:	  CAIG C,"Z		;SKIP IF THE CHARACTER IN C IS AN UPPER-CASE LETTER.
	   CAIGE C,"A
	    RET
	JRST POPJ1

DQTDGT:	CAIG C,"9		;SKIP IF THE CHARACTER IN C IS A DIGIT.
	 CAIGE C,"0
	  RET
	JRST POPJ1

VCOND:	CALL LRCH		;"' COMMAND:  TEST A CONDITION,
	CALL CONDIT		;BUT RETURN -1 IF IT SUCCEEDS, OR ELSE 0.
	XCT A			;THUS, 0"'N RETURNS 0 BUT 1"'N RETURNS -1.
	 TRC FF,FRCLN
	TRZ FF,FRARG
	SAVE [CDRET]
	TRZN FF,FRCLN
	 JRST NRETM1
	JRST NRET0

EXCLAM:	SETOM BRC1	;HANDLE "!" AS A COMMAND.
	CALL SKRCH	;[  ;SKIP UNTIL THE NEXT "!".  BRC1 INHIBITS MOST ^] FORMS.
	CAIE CH,"!
	 JRST .-2
	SETZM BRC1
	CALL TRACS	;IN TRACE MODE, TRACE A SECOND "!" TO MINIMIZE USER CONFUSION.
	JRST CD5A

LRCH:	PUSHJ P,RCH
	TRNE CH,100
	 ANDCMI CH,40
	POPJ P,

;HANDLE THE "O" COMMAND: O<TAG>$ JUMPS TO !<TAG>!. ":O" DOES NOT ERR IF TAG UNFOUND.
OG:	MOVE A,CPTR	;FIRST, LOOK IN THE JUMP CACHE FOR ADDR OF "O" CMD.
	MOVE C,A
	ANDI C,16	;GET INDEX IN CACHE OF ENTRY PAIR THAT'S APPRO.
	CAMN A,SYMS(C)	;IS FIRST ENTRY FOR THIS "O"?
	 JRST OGFND
	CAMN A,SYMS+1(C) ;IS THE SECOND?
	 AOJA C,OGFND	;IF FOUND, GET PLACE TO JUMP TO FROM CACHE ENTRY.
;THIS JUMP NOT IN CACHE; MUST ACTUALLY SEARCH.
	SAVE CPTR	;PUSH INFO ON WHERE TO STORE INTO CACHE WHEN FIND TAG.
	SAVE C		;THESE 2 WORDS ARE NOT USED FOR ANY OTHER PURPOSE.
	CALL OARG	;READ IN THE STRING ARG.
	MOVEI A,COMCNT
	CALL MFBEGP	;FIND START OF CURRENT MACRO.
	EXCH BP,B	;NOW BP HAS BP TO START, B HAS STRING POINTER TO MACRO,
	ADD C,COMCNT	;C HAS TOTAL SIZE OF MACRO.
	CAMGE B,BFRTOP
	 CAMGE B,QRWRT	;ARE WE IN A STRING? OR IN A BUFFER OR CBUF?
	  CAMGE B,QRBUF
	   SETOM BRCFLG	;JUMPS IN BUFFERS AND CBUF AREN'T CACHED,
		;SINCE THE DATA AT A GIVEN LOCATION IS LIKELY TO CHANGE.

;NOW SEARCH FOR THE DESIRED LABEL.
	TRNE FF,FRUPRW
	 SOS J
OG4:	MOVEI D,BAKTAB
OG5:	CAIN D,1(J)
	 JRST OG3
	SOJL C,OGUGT	;COMPARE MACRO CHAR BY CHAR AGAINST TAG.
	ILDB CH,BP
	CAIL CH,"A+40	;CONVERT TO UPPER CASE.
	 CAILE CH,"Z+40
	  CAIA
	   SUBI CH,40
	CAMN CH,(D)
	 AOJA D,OG5
	TLNE BP,760000	;AT WORD BOUNDARY => TRY TO SKIP WORDS FAST.
	 JRST OG4
OG6:	SUBI C,5
	JUMPL C,OG7	;NOT A WHOLE WORD LEFT TO SCAN => CAN'T GO FAST.
	MOVE D,1(BP)	;ELSE GET THE NEXT WORD
	XOR D,[ASCII /!!!!!/]	;AND SEE IF THERE ARE ANY !'S IN IT.
	TLNE D,(177_35)
	 TLNN D,(177_26)
	  JRST OG7
	TRNE D,177_1
	 TRNN D,177_10
	  JRST OG7
	TDNN D,[177_17]
	 JRST OG7
	AOJA BP,OG6	;THERE ARE NONE, SO WKIP THIS WORD.

OG7:	ADDI C,5	;FOUND AN !, SO SCAN SLOWLY TO LOCALIZE IT.
	JRST OG4

;COME HERE WHEN WE HAVE FOUND THE TAG BY SEARCHING.
OG3:	MOVEM C,COMCNT	;SET COMMAND-READING POINT TO WHERE WE FOUND THE TAG.
	MOVEM BP,CPTR
	REST A		;REMEMBER IDX OF CACHE ENTRY TO STORE IN.
	REST B		;REMEMBER CPTR OF "O" TO PUT IN CACHE
	SKIPE BRCFLG
	 JRST OGXIT	;BUT MAYBE CACHE IS INHIBITED FOR THIS JUMP.
	EXCH B,SYMS(A)	;STORE THIS JUMP IN 1ST ENTRY OF PAIR, AND MOVE
	MOVEM B,SYMS+1(A) 	;OLD CONTENTS OF 1ST ENTRY INTO 2ND.
	MOVE B,COMCNT
	EXCH B,CNTS(A)		;CACHE ENTRY CONTAINS CPTR OF "O",
	MOVEM B,CNTS+1(A)	;CPTR OF TAG, AND COMCNT OF TAG.
	MOVE BP,CPTR
	EXCH BP,VALS(A)
	MOVEM BP,VALS+1(A)
	JRST OGXIT

OGFND:	TRNE FF,FRTRACE
	 CALL OARG	;IF TRACING, READ IN ARGUMENT SO IT WILL SHOW IN TRACE.
	MOVE A,VALS(C)	;COME HERE WHEN THE JUMP IS FOUND IN THE CACHE.
	MOVEM A,CPTR
	MOVE A,CNTS(C)
	MOVEM A,COMCNT
OGXIT:	TRZ FF,FRCLN
	TRZN FF,FRUPRW
	 JRST CD
	MOVEI CH,"!
	CALL TRACS
	JRST EXCLAM	;@ O => WE'RE INSIDE A LABEL, SO WE MUST SKIP TO THE END.

OGUGT:	TRZN FF,FRCLN	;COME HERE IF TAG IS NOT FOUND.
	 TYPRE [UGT]
	SUB P,[2,,2]
	JRST CD

;READ IN A STRING ARG, AND SAVE IT 1 CHAR PER WORD
;IN BAKTAB, WITH AN ! BEFORE AND AFTER. LEAVE J -> LAST
;WORD USED IN BAKTAB. USED BY "O" AND "F;".   ;[
;BRCFLG LEFT NONZERO IFF SOME UNPREDICTABLE ^] CALLS TOOK PLACE.
;CLOBBERS A, CH.
OARG:	MOVEI J,BAKTAB+1
	MOVEI A,41
	MOVEM A,-1(J)
	SETZM BRCFLG	;[ ;ANY ^] CALLS WE WORRY ABOUT WILL SET BRCFLG.
OGNF1:	CAIN J,BAKTAB+LTABS
	 TYPRE [STL]
	CALL ORCH
	HRRZM CH,(J)
	SKIPN SQUOTP
	 CAIE CH,ALTMOD
	  AOJA J,OGNF1
	MOVEM A,(J)
	RET

ORCH:	CALL RCH	;READ CHAR AND CONVERT L.C. LETTERS (ONLY) TO U.C.
	CAIL CH,"A+40
	 CAILE CH,"Z+40
	  RET
	SUBI CH,40
	RET

;SEMICOLON AND ITERATIONS.

SEMICL:	SKIPN ITRPTR
	 TYPRE [SNI]
	TRNN FF,FRARG
	 MOVE C,SFINDF
	TRNN FF,FRUPRW	;UNLESS THE @ FLAG IS SET, CONVERT SIGN TO NONZERO-NESS.
	 ASH C,-35.
	MOVE A,[JUMPN C,CD]	;THEN WIN (KEEP ITERATING) IF NONZERO,
	TRNE FF,FRCLN		;OR, IF COLON, WIN IF ZERO.
	 HRLI A,(JUMPE C,)
	XCT A
INCMA0:	MOVEI CH,">	;"TRACE" A ">" TO HELP USER UNDERSTAND.
	CALL TRACS
	MOVEI A,0
	MOVE BP,CPTR
	MOVE C,COMCNT	;SEARCH FOR THE ">" THAT ENDS THIS ITERATION.
INCMA1:	SOJL C,[HRRO A,ITRPTR
		CALL ITRPOP
		TYPRE [UTI]]
	ILDB CH,BP
	CAIN CH,"<
	 AOJA A,INCMA1
	CAIE CH,">
	 JRST INCMA1
	SOJGE A,INCMA1
	MOVEM BP,CPTR
	MOVEM C,COMCNT

;HERE THE CODE FOR ">", ";", "F;", AND ERRORS INSIDE ERRSETS,
;MERGES INTO ONE.
INCMA2:	HRRO A,ITRPTR	;PTR TO INNERMOST ITER OR ERRSET.
	HLRZ TT,ITRPTR	;TO INNERMOST ERRSET.
	MOVEI E,(A)
	CALL FSEMIP	;SKIP IF THIS ITERATION WAS A CATCH.
	 CAIN TT,(A)	;SKIP UNLESS IT WAS AN ERRSET.
	  SKIPA TT,[-1]	;TT HAS -1 IF CATCH OR ERRSET,
	   SETZ TT,	;0 FOR ORDINARY ITERATION.
	CALL ITRPOP	;POP THE ITERATION FRAME.
	JUMPE TT,CD	;FOR ORDINARY ITER'S, THAT'S ALL.
;EXITING A CATCH OR ERRSET: 1ST, WE MAY HAVE JUST UNWOUND
;AND NEED TO RESET PDLS. 2ND, WE MUST RETURN A VALUE SAYING
;WHETHER WE EXITED NORMALLY.
	TRZ FF,FRARG+FRARG2+FROP+FRSYL+FRCLN+FRUPRW
	AOS A,ERRFLG	;EXITING ERRSET, WAS THERE ERROR?
	JUMPN A,[SETZ A, ? JRST VALREC] ;RETURN 0 IF NO ERROR.
	HLRZ CH,C
	HRLI CH,1-PDL-LPDL(CH)
	CAME P,CH	;IF CH=P, SETP IS NOT NEEDED, AND RET. ADDR WOULD BE ABOVE P!
	 PUSHJ CH,SETP	;MOVE P,CH , CHECK FOR UNWINDING PARENS, SORT OR ^R, THEN POPJ P,
	HRLI C,1-PFL-LPF(C)
	CALL FSQPU0	;ON ERROR IN ERRSET, UNWIND QREG PDL
	MOVE A,LASTER
	JRST VALREC

;A CONTAINS ITRPTR'S RH; POP OFF AN ITERATION.
ITRPOP:	POP A,ITRPTR
	POP A,C
	POP A,(A)
	POP A,ITERCT
	MOVEI A,-MFICNT(A)
	JRST FLSFRM

;> AS COMMAND RETURNS TO THE MATCHING < (END ITERATION).
GRTH:	SKNTOP ITRPTR
	 TYPRE [UMC]
	TRZE FF,FRUPRW	;@> IGNORES ITERATION COUNT, AND ALWAYS LOOPS BACK.
	 JRST GRTH1	;THIS IS FOR THE SAKE OF THE !<!@> CONSTRUCT.
	SOSN ITERCT	;OTHERWISE, DECREMENT COUNT AND DON'T LOOP IF IT RUNS OUT.
	 JRST INCMA2
GRTH1:	HRRO A,ITRPTR
	MOVE CH,MFMACP-MFBLEN+1(A)
	TLZ CH,40
	CAME CH,MACPDP	;IF MATCHED < WAS AT A DIFFERENT STACK LEVEL,
	 TYPRE [UMC]	;THIS IS AN ERROR.
	SUBI A,MFBLEN-MFCPTR-1
	POP A,CPTR	;OTHERWISE, RESTORE THE "PC" SAVED BY THE <.
	POP A,COMCNT
	MOVEI CH,^M	;THEN IF WE ARE IN TRACE MODE MAKE THE TRACE LOOK GOOD.
	CALL TRACS
	MOVEI CH,^J
	CALL TRACS
	MOVEI CH,"<
	CALL TRACS
	JRST CD

FLSSTH:	SUB P,[1,,1]
LSSTH:	PUSHJ P,GETFRM
	MOVE TT,PF
	HRLI TT,(P)
	MOVE TT1,MACPDP		;IN WITH MACPDP, SET BIT MFERS1 TO REMEMBER THE @ FLAG.
	TRZE FF,FRUPRW
	 TLO TT1,MFERS1
INSIRP PUSH A,COMCNT CPTR CSTR ITERCT TT1 TT ITRPTR
	HRRM A,ITRPTR	;STORE PTR TO INNERMOST ITER OR ERRSET.
	TRZE FF,FRCLN	;IF THIS IS ERRSET, SET PTR TO
	 HRLM A,ITRPTR	;INNERMOST ERRSET.
	TRZE FF,FRARG
	 JRST LSSTH2
	SETOM ITERCT
	JRST CD

LSSTH2:	JUMPLE C,INCMA0
	MOVEM C,ITERCT
	JRST CD

CNTRLN:	SETOM GEA
	TRNE FF,FRARG
	 MOVEM C,NLINES
	TRZN FF,FRCLN
	 RET
	AOSE TTMODE
	SETOM TTMODE
	POPJ P,

;<ARG>F;<TAG>$ - THROW TO <TAG>, RETURNING 1 (OR F;'S ARG, IF ANY) FROM THE F<...>.
FSEMIC:	TRZN FF,FRARG
	 MOVEI C,1
	SAVE C
	CALL OARG	;READ <TAG> INTO BAKTAB, WITH "!"'S.
;NOW LOOK AT ALL ITERATIONS, INNERMOST FIRST, FOR ONE WHICH
;IS A CATCH WITH THE APPROPRIATE TAG.
	HRRZ E,ITRPTR
FSEMI1:	JUMPE E,[TYPRE [UCT]]	;UNSEEN CATCH TAG.
	CALL FSEMIP	;IS THIS ITERATION A CATCH?
	 JRST FSEMI2	;NO, LOOK AT NEXT ONE OUT.
	IBP BP
	MOVEI D,BAKTAB	;YES, COMPARE ITS TAB WITH <TAG>.
	MOVE A,MFCCNT-MFBLEN+1(E)
FSEMI3:	SOJL A,FSEMI2	;F< TAG ENDED TOO SOON - MISMATCH.
	ILDB TT,BP
	CAIL TT,"A+40	;CONVERT L.C. LETTERS TO U.C.
	 CAILE TT,"Z+40
	  CAIA
	   SUBI TT,40
	CAME TT,(D)
	 JRST FSEMI2	;THE CHARS DIFFER.
	ADDI D,1	;ADVANCE TO NEXT CHAR IN <TAG>
	CAME D,J
	 JRST FSEMI3
;WE'VE FOUND A CATCH WITH OUR TAG!
	REST LASTER	;VALUE TO BE RETURNED FROM F<...>, WHERE ERRP3 WANTS IT.
	SETOM ERRFLG	;FAKE INCMA2 INTO RETURNING NEGATIVE.
FSEMI4:	HRRO A,ITRPTR	;POP OFF ALL ITERATIONS INSIDE THE
	CAIN E,(A)	;CATCH WE'RE POPPING TO.
	 JRST [	HRLM E,ITRPTR	;THEN PRETEND THIS CATCH WAS AN ERRSET
		JRST ERRP3]	;AND ERR OUT OF IT.
	CALL ITRPOP
	JRST FSEMI4

;COME HERE IF ITERATION ISN'T A CATCH, OR HAS WRONG TAG.
FSEMI2:	HRRZ E,MFLINK-MFBLEN+1(E)
	JRST FSEMI1

;E -> AN ITERATION FRAME. SKIP IF THAT ITERATION IS REALLUY A
;CATCH. IN THAT CASE, RETURN IN BP B.P. TO ILDB THE "<".
FSEMIP:	MOVE BP,MFCPTR-MFBLEN+1(E)
	SUBI BP,1	;BACK UP BP BY 2 CHARS.
REPEAT 3,IBP BP
	ILDB C,BP	;FETCH THE CHAR BEFORE THE "<"
	CAIE C,"F+40
	 CAIN C,"F	;IF IT'S "F", THIS ITERATION'S A CATCH.
	  AOS (P)
	RET

SUBTTL ^P SORT COMMAND

;THE SORT TABLE IS A TABLE OF POINTERS TO SORT RECORDS.
;PSMEM POINTS AT THE FIRST ENTRY.  PSMEMT POINTS PAST THE LAST ONE.
;EACH ENTRY IS 4 (LPSDBK) WORDS LONG.
;THE 1ST WORD OF AN ENTRY IS EITHER A B.P. TO THE START OF THE RECORD'S KEY
  ;OR THE KEY ITSELF IF IT IS A NUMBER.
;THE SECOND WORD'S RH IS THE LENGTH OF THE KEY IF THE KEY IS A STRING,
  ;OR -1 IF THE KEY IS A NUMBER.
;THE SECOND WORD'S LH IS MINUS THE LENGTH OF THE RECORD IN CHARACTERS.
;THE THIRD WORD IS THE CHAR ADDR OF THE START OF THE RECORD.
;THE FOURTH WORD POINTS TO THE NEXT ENTRY (IN ORIGINAL ORDER BEFORE SORT,
 ;IN SORTED ORDER AFTER.  THIS IS THE LINK FOR A LIST SORT).

PSORT:	ISKERR		;CAN'T SORT WITHIN SORT.
	SAVE FF		;REMEMBER FRCLN (PSI SETS IT)
	MOVE CH,[JRST [
	 CALL RCH	;READ CHAR,
	 SKIPGE SQUOTP	;SUPERQUOTED =>
	  JRST INSDIR	;JUST INSERT.
	 CAIE CH,"$	;ELSE REPLACE $ BY ALTMODE
	  JRST INSDCK
	 MOVEI CH,ALTMOD
	 JRST INSDIR]]	;AND CHECK FOR DELIMITER UNLESS DELIM PROTECTED.
	MOVEM CH,INSRCH
	MOVE CH,QRB..
	ADDI CH,.QKS	;GET ARGS
	CALL PSI	;IN PSEUDO Q-REGS
	MOVE CH,QRB..
	ADDI CH,.QKE
	CALL PSI
	MOVE CH,QRB..
	ADDI CH,.QDL
	CALL PSI
	CALL MEMTOP
	MOVEM P,PSSAVP	;INDICATE A SORT IS IN PROGRESS.
	MOVEM A,PSMEM
	MOVEM A,PSMEMT
	MOVE T,A
	SETZM PSZF
	MOVE TT,ZV
	SUB TT,BEGV	;# CHARS IN RANGE BEING EDITED.
	JUMPE TT,PSXIT	;SORTING NO CHARS IS NOOP.
	MOVE C,BEGV	;START FROM BEGINNING
	MOVEM C,PT
;DROPS THROUGH.

;DROPS THROUGH.
;LOOP HERE TO DELIMIT THE NEXT RECORD AND ITS KEY.
PS4:	SUB C,BEG	;KEEP ALL ADDRS RELATIVE TO BEG IN CASE IMPURE STRINGS MOVE BUFFER.
	MOVEM C,2(T)	;3RD WORD OF POINTER: CHAR ADDR OF RECORD.
	PUSH P,C
	MOVE A,QRB..
	MOVE A,.QKS(A)	;FIND BEGINNING OF KEY
	CALL MACXQ
	MOVE T,PSMEMT
	MOVE C,PT
	SUB C,BEG	;FOR NOW, KEEP CHAR ADDR REL BUFFER, WILL CHANGE TO BP LATER.
	PUSH P,C
	MOVEM C,(T)	;IS 1ST POINTER WORD
	MOVE A,QRB..
	MOVE A,.QKE(A)	;FIND END OF KEY
	PUSHJ P,PS2
	SKIPGE C	;BARF IF THE KEY IS NEGATIVE IN LENGTH (WOULD THINK IT WAS NUMERIC).
	 TYPRE [ISK]
	TRNN FF,FRARG	;IF "END OF KEY" MACRO RETURNS A VALUE, THAT VALUE IS THE KEY.
	 JRST PS8
	MOVE A,NUM	;STORE IT INSTEAD OF THE CHAR ADDR OF THE KEY.
	MOVEM A,(T)	;STORE -1 AS "KEY LENGTH" TO IDENTIFY THIS KEY AS NUMBER
	MOVNI C,1	;INSTEAD OF A STRING.
PS8:	MOVEM C,1(T)	;#CHARS IN KEY FOR RH(2ND WORD OF TABLE ENTRY)
	MOVE A,QRB..
	MOVE A,.QDL(A)	;FIND NEXT RECORD
	PUSHJ P,PS1
PS7:	MOVNS C
	SKIPL C
	 TYPRE [ESR]	;SORT-RECORD WITH NO CHARACTERS (OR NEGATIVE NUMBER???)
	HRLM C,1(T)	;-LENGTH OF RECORD FOR AOBJN
	ADDI T,LPSDBK	;NEXT POINTER
	MOVEM T,PSMEMT
	MOVE C,PT
	SKIPL PSZF	;DID WE RUN OUT
	 JRST PS4	;NO
	MOVE A,ZV
	MOVEM A,PT
	CALL GAPSLP
	MOVEI C,20.	;MAKE SURE THERE'S A GAP AFTER RANGE BEING
	CALL SLPSAV	;SORTED, SO BLT OF SORTED STUFF WON'T CLOBBER A FEW CHARS.
	MOVE A,PSMEM	;LOWER BOUND
	MOVE B,PSMEMT	;UPPER BOUND.
PS7A:	CAMN A,B	;NOW CONVERT ADDRS REL. TO BEG TO WHAT WE REALLY WANT.
	 JRST PS7B	;ALL RECORDS HANDLED.
	HRRE E,1(A)
	JUMPL E,PS7C	;IF THE KEY IS A STRING, NOT A NUMBER,
	MOVE E,(A)	;GET ADDR START OF KEY,
	ADD E,BEG
	IDIVI E,5	;CONVERT TO BP. TO 1ST BIT.
	ADD E,BTAB-1(J)
	TLZ E,17
	MOVEM E,(A)
PS7C:	ADDI A,LPSDBK
	MOVE E,A
	SUB E,PSMEM
	MOVEM E,-1(A)	;MAKE ENTRY'S 3RD WD POINT TO NEXT ENTRY.
	JRST PS7A	;DO NEXT RECORD.

PS1:	SKIPGE PSZF	;ALREADY AT END => NOOP INSTEAD OF USER'S MACRO.
	 JRST PS2A
PS2:	CALL MACXQ
PS2A:	MOVE T,PSMEMT
	POP P,J		;RETURN POINT
	POP P,E		;OLD PT-BEG
	ADD E,BEG
	MOVE C,PT
	CAML C,ZV	;IF WE'RE AT THE END OF THE BUFFER
	 SETOM PSZF	;THEN THIS RECORD IS THE LAST ONE.
	SUB C,E		;# CHARS IN C
	JRST (J)

;RETURN IN A A PTR TO THE 1ST UNUSED WORD OF HIGH MEM.
MEMTOP:	MOVE A,BFRTOP
	IDIVI A,5
	SUBI  A,3
	SKIPE PSSAVP
	 MOVE A,PSMEMT
	ADDI A,4
	POPJ P,

PS7B:	SETOM -1(A)	;LAST ENTRY'S LINK WORD IS NIL.
	MOVE A,(P)	;RESTORE FRCLN AS IT WAS AT CALL TO PSORT.
	TRNE A,FRCLN
	 IORI FF,FRCLN
	HRRZ J,PSMEMT	;DYNAMICALLY ALLOCATED PDL
	PUSHJ J,PS3	;SORT POINTERS
	HRRZ J,PSMEMT	;ZERO OUT THE CORE WE WILL COPY THE SORTED RECORDS INTO
	HRLS J		;SO THAT THE LOW BITS WILL NOT BE SET.
	SETZM (J)
	ADDI J,1
	MOVE T,MEMT
	LSH T,10.
	BLT J,-1(T)
	MOVE T,BEGV	;SET UP FOR LATER BLTING DOWN THE COPIED RECORDS INTO THE
	IDIVI T,5	;ORIGINAL SPACE.
	HRRM T,J	;DESTINATION = WORD CONTAINING BEGV
	MOVE CH,(T)	;MUST HAVE CHARS BEFORE BEGV IN WD
	HLL C,BTAB-1(TT)	;GET BPT TO NEW BUFFER AREA
	TLZ C,77
	HRR C,PSMEMT	;WHICH OVERWRITES SORT PDL
	HRLM C,J	;SOURCE FOR BLT
	MOVEM CH,(C)	;SAVE CHARS
PS6:	ADD A,PSMEM	;CHANGE REL PTR TO ABS, -> NEXT TAB ENTRY.
	HLRE E,1(A)	;- # CHARS IN RECORD.
	JUMPE E,PS5
	MOVE BP,2(A)	;CHAR ADDR START OF RECORD.
	ADD BP,BEG
	CALL GETIBP
PS6A:	ILDB CH,BP	;MOVE THE RECORD.
	IDPB CH,C
	AOJL E,PS6A
PS5:	MOVE A,3(A)	;GET PTR TO NEXT RECORD'S ENTRY.
	JUMPGE A,PS6	;IF THERE IS ANOTHER, LOOP BACK.
	MOVE A,ZV
	IDIVI A,5
	BLT J,1(A)	;DONE, MOVE IT DOWN
	CALL FLSCOR
PSXIT:	SETZM PSSAVP	;TURN OFF SORT FLAG.
	MOVE A,BEGV
	MOVEM A,PT
	JRST POP1J

;ACTUALLY SORT THE LIST OF SORT TABLE ENTRIES,
;BY REARRANGING THE LINK WORDS SO THAT THEY ARE LINKED
;IN SORTED ORDER.
PS3:	SETZ E,		;POINT TO THE HEAD OF THE LIST O SORT.
	MOVE C,PSMEMT	;C _ LENGTH(E)
	SUB C,PSMEM
	LSH C,-2

;(DEFUN NSORT (N) (COND ((= N 1) (CHOP1))
;		(T (MERGE (NSORT (/ N 2)) (NSORT (- N (/ N 2)))))))
;E HOLDS L, C HOLDS N, J USED AS PDL PTR, VALUE RETURNED IN A.
PS3NSORT:	CAIN C,1
	 JRST PS3NS1
	PUSH J,C
	LSH C,-1		;THIS IS N/2
	PUSHJ J,PS3NSORT ;(NSORT (/ N 2))
	POP J,C
	PUSH J,A
	AOJ C,
	LSH C,-1	;(- N (/ N 2))
	PUSHJ J,PS3NSORT ;(NSORT (- N (/ N 2)))
	POP J,C		;A, C HAVE ARGS TO MERGE.
	MOVEI B,D	;B -> TAIL OF ACCUMULATED MERGED LIST,
			;D WILL EVENTUALLY POINT TO ITS HEAD.
PS3MRG:	JUMPL C,PS3TK1	;1ST ARG EMPTY => TAKE FROM 2ND.
	JUMPL A,PS3TKB	;2ND EXHAUSTED => TAKE FROM FIRST.
	MOVE TT,PSMEM	;ELSE GET PTRS TO AND SIZES OF THE KEYS
	MOVE TT1,PSMEM
	ADD TT,A	;BELONGING TO THE HEADS OF 1ST AND 2ND ARG.
	ADD TT1,C
	TRNE FF,FRCLN	;@ ^P - SORT IN REVERSE ORDER.
	 EXCH TT,TT1
	MOVE CH,(TT)	;CH IS BP TO ILDB KEY OF 2ND,
	MOVE Q,(TT1)	;Q, FOR 1ST.
	HRRE TT,1(TT)	;# CHARS IN KEY OF 2ND,
	HRRE TT1,1(TT1)	;SAME FOR 1ST.
	JUMPGE TT1,PS3CM3
	JUMPGE TT,PS3TKB	;1ST KEY A NUMBER, 2ND A STRING => 1ST IS LESS.
	CAMLE Q,CH
	 JRST PS3TKA	;BOTH NUMBERS => 1ST KEY NUMBER GREATER => TAKE 2ND.
	JRST PS3TKB

PS3CM3:	JUMPL TT,PS3TKA	;2ND KEY A NUMBER, 1ST A STRING => 2ND IS LESS.

;COMPARE TWO KEYS WHICH ARE STRINGS, GO TO PS3TKA IF 2ND KEY IS LESS, ELSE PS3TKB.
PS3CMP:	SOJL TT1,PS3TKB	;FIRST KEY ENDED, IT IS .LE., SO USE IT.
	SOJL TT,PS3TKA	;2ND KEY ENDED, IT IS .L., TAKE 2ND.
	ILDB T,CH	;ELSE LOOK AT NEXT CHAR OF EACH.
	ILDB BP,Q
	SKIPN PSCASE	;IF WE SHOULD IGNORE CASE,
	 JRST PS3CM1
	CAIGE T,"A+40
	 JRST PS3CM2
	CAIG T,"Z+40
	 SUBI T,40
PS3CM2:	CAIGE BP,"A+40
	 JRST PS3CM1
	CAIG BP,"Z+40
	 SUBI BP,40
PS3CM1:	CAIN T,(BP)
	 JRST PS3CMP	;CHARS EQUAL => KEEP LOOKING.
	CAIG T,(BP)
	 JRST PS3TKA	;CHAR FROM 2ND IS LESS, TAKE 2ND.
PS3TKB:	MOVEM C,(B)	;"TAKE 1ST"; ENTRY AT HEAD OF 1ST ARG
	ADD C,PSMEM	;IS LESS THAN THAT AT HEAD OF 2ND, SO
	MOVEI B,3(C)	;TRANSFER IT TO TAIL OF MERGED LIST
	MOVE C,(B)	;AND ADVANCE DOWN THE 1ST ARG.
	JRST PS3MRG

PS3TKA:	MOVEM A,(B)	;"TAKE 2ND"; LIKE "TAKE 1ST" BUT FOR 2ND ARG.
	ADD A,PSMEM
	MOVEI B,3(A)
	MOVE A,(B)
	JRST PS3MRG

PS3TK1:	JUMPGE A,PS3TKA	;1ST EXHAUSTED; 2ND ISN'T => TAKE 2ND.
	SETOM (B)	;BOTH ARGS EXHAUSTED => MERGE FINISHED, TERMINATE LIST.
	MOVE A,D	;RETURN VALUE IN A.
	POPJ J,

PS3NS1:	MOVEI A,(E)	;(NSORT 1) COMES HERE.
	ADD E,PSMEM	;RETURN THE HEAD OF LIST TO BE SORTED,
	MOVE T,E
	MOVE E,3(T)	;REPLACING THAT LIST WITH ITS CDR,
	SETOM 3(T)	;AND MAKING THE HEAD'S CDR NIL.
	POPJ J,

SUBTTL INPUT FROM FILES

APPEND:	ARGDFL
	TRZE FF,FRCLN
	 JRST APPNDL
	TRZN FF,FRARG
	 JRST YANK2
	ADD C,PT
	SOS IN,C
	CAMGE IN,ZV
	CAMGE IN,BEGV
	 JRST APPND2	;J IF OUT OF RANGE OF BUFFER.
	ANDCMI FF,FRARG2
	PUSHJ P,GETCHR
	MOVE A,CH
	JRST POPJ1

APPND2:	TRZN FF,FRARG2	;IF ONLY ARG, OUT OF RANGE IS ERROR.
	 TYPRE [NIB]
	MOVE A,E	;2 ARGS => RETURN 1ST ARG.
	JRST POPJ1

APPNDL:	TRNN FF,FRARG	;<N>:A - APPEND <N> LINES, OR TO ^L,
	 MOVEI C,1	;WHICHEVER COMES FIRST.
	TLNN FF,FLIN
	 RET
	SAVE PT
	MOVE OUT,ZV	;TEMPORARILY PUT PT AT END SO
	MOVEM OUT,PT	;TYOM WILL INSERT AT END.
	CALL GAPSLP
APPNL2:	PUSHJ P,UTYI
	SKIPN FFMODE
	 CAIE CH,^L
	  SKIPL LASTPA	;AT EOF => UTYI WAS RETURNING DUMMY CHARS; IGNORE THEM.
	   JRST APPNL1
	PUSHJ P,TYOM
	CAIN CH,^L
	 JRST APPNL1
	CAIE CH,^J	;END OF LINE
	 JRST APPNL2
	SOJG C,APPNL2
APPNL1:	REST PT
	CAIE CH,^L
	 RET
	AOS PAGENU
;CLOSE THE INPUT FILE IF IT IS EMPTY EXCEPT FOR PADDING.
APPNL4:	CALL UTYI	;READ AHEAD 1 CHAR TO SEE IF ANYTHING
	SKIPL LASTPA	;IS LEFT IN THE FILE.
	 RET		;NO => LEAVE FILE MARKED "EOF".
	MOVE A,UTYIP	;ELSE ARRANGE TO RE-READ THAT CHAR.
	DBP7 A
	MOVEM A,UTYIP
	POPJ P,

;Y => READ ONE PAGE FROM THE OPEN INPUT FILE,
;DESTROYING PREVIOUS CONTENTS OF BUFFER.
;IF NO FILE OPEN, JUST EMPTY THE BUFFER.
;THE FS YDISABLE$ FLAG MAY TURN Y INTO AN ERROR.
;@ Y READS IN ALL THE REST OF THE FILE.
YANK:	SKIPGE YDISAB
	 IORI FF,FRUPRW	;YDISAB NEGATIVE => Y IS @Y.
	SKIPLE YDISAB
	 TYPRE [DCD]	;FS YDISABLE POSITIVE => "Y" IS ILLEGAL.
YANKEE:	MOVE E,BEGV
	MOVE C,ZV	;FIRST, KILL CURRENT CONTENTS.
	CALL DELET1
YANK2:	TLNN FF,FLIN
	 JRST UTLSTP	;NO FILE OPEN => INSERT NOTHING.
	TRNE FF,FRUPRW
	 JRST YANKAL	;"@ Y" IS HANDLED SEPARATELY.
	MOVE BP,ZV	;GET PLACE TO INSERT AT.
	EXCH BP,PT	;GET GAP THERE.
	CALL GAPSLP
	MOVEM BP,PT
	MOVE BP,BEG
	CAME BP,Z	;IF BUFFER IS EMPTY NOW,
	 JRST YANK3
	MOVE BP,BEG	;ADJUST VALUE OF BEG SO THAT
	IDIVI BP,5	;THE BUFFER STARTS IN THE SAME PART OF A WORD
			;AS THE EMPTY PART OF UTOBUF FOR ORDINARY Y.
	HLL BP,UTYOP	;(MAKES IT MORE LIKELY THAT PW CAN GO FAST)
	TLNN BP,760000	;MAKE SURE WE DON'T MOVE BEG TO
	 SUBI BP,1	;A DIFFERENT WORD.
	CALL GETCA	;TURN INTO CHAR ADDR OF LAST CHAR BEFORE BUFFER
	SUB BP,BEG
	AOS TT,BP	;TURN INTO DISPLACEMENT OF NEW BEG FROM OLD
	ADDB TT,BEG	;UPDATE BEG.
	CAMGE TT,BFRBOT	;NEW BEG ISN'T SUPPOSED TO BE OUTSIDE BUFFER SPACE.
	 .VALUE
	ADDM BP,BEGV	;SHIFT ALL THE OTHER BUFFER POINTERS JUST LIKE BEG
	ADDM BP,PT
	ADDM BP,GPT
	ADDM BP,Z
	ADDM BP,ZV
	MOVNS BP
	ADDM BP,EXTRAC
YANK3:	MOVE BP,ZV
	AOS PAGENU
	SAVE D
	PUSHJ P,GETIBP
	MOVE OUT,BP
	MOVE IN,[YPG,,A]
	BLT IN,BP
	MOVE IN,UTYIP
	SKIPN Q,EXTRAC
	 JRST YPGNRM
	JRST A

YPG:	ILDB CH,IN	;A
	CAIE CH,EOFCHR	;B
	CAIN CH,14	;C
	JRST YPG1	;D
	IDPB CH,OUT	;E
	SOJG Q,A	;J
	JRST YPGNRM	;BP

YPG1:	MOVEM IN,UTYIP	;WE JUST ILDB'D ^C OR ^L.
	HRRZ TT,IN
	CAIN TT,UTIBE
	 JRST YPG2	;JUST END OF UTIBUF - RELOAD IT.
	CAIE CH,EOFCHR
	 JRST YPG3	;IT WAS A ^L - GO INSERT IT AND RETURN.
	CAME IN,UTRLDT
	 JRST E		;^C INSIDE THE FILE - INSERT IT AND KEEP GOING.
	CALL UTLSTP	;EOF - MARK FILE AS AT EOF.
YPG1A:	MOVE BP,OUT
	CALL GETCA
	AOS BP
	MOVE E,ZV	;GET PLACE WHERE INSERTED FILE STARTS, FOR YANKX'S USE.
	CALL YPG1B	;UPDATE BUFFER BLOCK FOR CHARS WE HAVE READ IN.
	REST D
	JRST YANKX	;NOW MAYBE DELETE PADDING OR A TRAILING ^L.

YPG1B:	MOVEM BP,GPT
	SUB BP,ZV	;# CHARS YANKED.
	ADDM BP,Z
	ADDM BP,ZV
	MOVNS BP
	ADDM BP,EXTRAC
	POPJ P,

YPG3:	IDPB CH,OUT	;ENCOUNTERED A ^L - INSERT IT,
	CALL APPNL4	;MARK THE FILE CLOSED IF THERE'S NOTHING LEFT IN IT
	JRST YPG1A	;THEN FINISH UP AS IF REACHED EOF.

YPG2:	CALL UTRLD2	;EOB AND CAN'T GO FAST, RELOAD UTIBUF.
	MOVE IN,UTYIP
	JRST A		;TRY AGAIN TO READ A CHARACTER.

YPGNRM:	SAVE C		;COME HERE WHEN RUN OUT OF GAP TO YANK INTO.
	MOVE C,EXTRAC
	ADDI C,5*<UTIBE-UTIBUF>	;C <- AMOUNT OF GAP WE WANT.
	MOVN Q,EXTRAC
	CALL SLPSAV
	REST C
	ADD Q,EXTRAC
	JRST A

;HANDLE "@Y" AND "@A" - READ IN ALL OF INPUTR FILE, THEN
;REMOVE PADDING FROM END, AND MAYBE REMOVE A TRAILING ^L.
YANKAL:	MOVE C,ZV
	SAVE C		;MOVE POINT TO ZV, SAVING ZV AND OLD POINT.
	EXCH C,PT
	SAVE C
	CALL FYCMDA	;THEN INSERT THE WHOLE FILE THERE.
	CALL GAPSLP	;AND MOVE THE GAP TO THE END OF WHAT WAS INSERTED.
	REST PT		;POINT IS NOW SAME AS AT ENTRY, BUT GPT = ZV.
	REST E		;THIS IS OLD VALUE OF ZV - WHERE THE FILE STARTS.
	CALL UICLS
	CALL YANKX	;DELETE PADDING CHARS AT END.
	JRST FLSCM1	;FLUSH EXCESS CORE.

;DELETE BACKWARDS FROM GPT ALL CONSECUTIVE ^C'S AND ^@'S;
;THEN, IF FS ^LINSERT$ IS 0, DELETE A FORMFEED IF ANY.
;REFUSES TO DELETE BACK PAST WHERE E POINTS.
YANKX:	MOVE IN,GPT
YANKX1:	MOVEI C,1
	CAMN E,IN
	 RET
	SOS IN
	CALL GETCHR
	CAIE CH,^C
	 JUMPN CH,YANKX2
	SOS GPT
	CALL DELETB	;DELETE 1 CHAR AFTER GPT (SINCE C HAS 1).
	JRST YANKX1

YANKX2:	CAIN CH,^L	;GOT ALL ^C'S AND ^@'S - NOW MAYBE TAKE A ^L.
	 SKIPE FFMODE
	  RET
	SOS GPT
	JRST DELETB

;INSERT ALL OF THE OPEN INPUT FILE BEFORE POINT.
;FY WITH NO ARGUMENT USES THIS, AS DOES "@Y".
FYCMDA:	CALL FSIFLEN	;HOW MUCH SPACE DO WE NEED?
	 JFCL
	JUMPL A,FYCMD7
	MOVE C,A	;SAVE FILE SIZE FOR FYPMAP.
IFN ITS,[
	SYSCAL RFPNTR,[%CLIMM,,CHFILI ? %CLOUT,,B]
	 SETZ B,
];ITS
IFN TNX,[
	MOVE A,CHFILI
	RFPTR
	 TDZA B,B		;FAILED, ASSUME 0 BUT DONT PMAP
	  JUMPE B,FYPMAP		;IF AT START OF FILE STILL, CAN READ IT IN FAST
]
	IMULI B,5	;IF WE ARE NOT POINTING AT THE FRONT OF THE FILE, WE DON'T
	SUB C,B		;HAVE AS MUCH TO READ, SO WE DON'T NEED AS MUCH SPACE.
	SKIPGE C	;IF KNOW HOW MUCH SPACE, READ WHOLE FILE AT ONCE.
FYCMD7:	 MOVEI C,2000*5 ;ELSE GET 1K AT A TIME.
	CALL FYCMD6	;READ THAT MUCH.
	SKIPE LASTPA	;IS THERE ANY MORE IN THE FILE?
	 JRST FYCMD7	;YES, SO GET MORE.
	RET

IFN TNX,[

;THIS CODE WORKS ON ITS, BUT LOSES IF DSK IS TRANSLATED,
;AND PROVES TO OFFER NO IMPROVEMENT IN EFFICIENCY ON ITS.

;MAP IN INPUT FILE USING PAGING.  ASSUMES FILE IS ON DISK
;AND THAT WE ARE MAPPING THE WHOLE FILE.  C HAS FILE SIZE IN CHARS.
FYPMAP:	CALL GAPSLP		;MOVE GAP TO PT
	SAVE C			;SAVE SIZE OF INPUT FILE
	MOVE A,GPT
	IDIVI A,PAGSIZ*5	;GET PAGE TO START MAPPING INTO
	JUMPE B,.+2	.SEE CIRC
	 AOJ A,
	SAVE A			;SAVE PAGE NUMBER
	IMULI A,PAGSIZ*5	;GET CHARACTER ADDRESS
	IDIVI C,PAGSIZ*5	;GET NUMBER OF PAGES IN INPUT FILE
	JUMPE D,FYPMA1	.SEE CIRC
	AOJ C,
	SUBI D,PAGSIZ*5		;D IS -<NUMBER OF CHARACTERS AFTER FILE TO END OF PAGE>
FYPMA1:	SAVE C			;SAVE IT
	IMULI C,PAGSIZ*5	;BACK INTO CHARACTERS
	SUB C,GPT		;GET SIZE OF GAP WE WILL NEED FOR ALL THIS
	ADDB C,A		;END OF LAST PAGE TO BE MAPPED
	CALL SLPSAV		;MAKE SURE THERE IS THAT MUCH ROOM FOR IT
	SUB A,EXTRAC		;COMPUTE SIZE OF GAP AFTER END OF NEW PAGES
	ADD D,A			;D IS -<TOTAL ROOM AFTER END OF NEW TEXT>
	MOVE B,-1(P)		;FIRST PROCESS PAGE
IFN ITS,[
	REST C
	MOVNS C
	HRL B,C			;B GETS -NPAGES,,FIRSTPAGE
	SYSCAL CORBLK,[%CLIMM,,%CBCPY+%CBWRT ? %CLIMM,,%JSELF ? B ?%CLIMM,,CHFILI]
	 .LOSE %LSSYS
]
IFN TNX,[
IFN 20X,[
	HRLZ A,CHFILI		;GET INPUT FILE AGAIN
	HRLI B,.FHSLF
	REST C			;NUMBER OF PAGES AGAIN
	HRLI C,(PM%CNT\PM%RD\PM%CPY\PM%PLD)	;READ, COPY, PRELOAD
	PMAP			;READ IN THE WHOLE FILE.
]
.ELSE	[
	HRLZ A,CHFILI		;GET INPUT FILE AGAIN
	HRLI B,.FHSLF
	REST T			;COUNT OF PAGES TO MAP
	JUMPE T,FYPMA3		;EMPTY FILE DOES NO PMAPS
	MOVSI C,(PM%RD\PM%EX\PM%CPY)	;THIS IS THE SECOND BIGGEST CROCK
FYPMA2:	PMAP
	SOJLE T,FYPMA3
	AOJ A,
	AOJA B,FYPMA2
FYPMA3:
];NOT 20X
];TNX
	REST A			;GET FIRST PAGE AGAIN
	IMULI A,PAGSIZ*5	;GET CHARACTER ADDRESS OF START OF MAPPED IN FILE
	SUB A,GPT		;COMPUTE NEW SIZE OF GAP ON THIS END
	MOVEM A,EXTRAC
	REST A			;SIZE OF INPUT FILE AGAIN
	ADDM A,PT		;PT TO END OF STUFF JUST INSERTED
	ADDM A,ZV
	SUB A,D			;FOR NOW SET END HIGH SO GETS BLTED ALONG WITH REST OF
	ADDM A,Z
	CALL SLPSHT		;CLOSE UP THE LOWER GAP
	ADDM D,Z		;FIX UP END OF BUFFER
	MOVNM D,EXTRAC		;SIZE OF UPPER GAP
	JRST UTLSTP		;TELL EVERYONE AT EOF NOW
];TNX

;<N>FY - READ <N> CHARACTERS FROM THE INPUT FILE, OR UNTIL EOF,
;AND INSERT THEM IN THE BUFFER BEFORE POINT. NO PADDING CHARACTERS ARE
;FLUSHED, SO ALL IS UNDER PROGRAMMER CONTROL. IF THE TRANSFER GOES TO A WORD
;BOUNDARY, AND STARTS AT A WORD BOUNDARY IN THE FILE, THEN IT IS
;SUITABLE FOR READING IN BINARY DATA.  TO MAKE THAT HAPPEN, WE SOMETIMES
;INSERT SOME SPACES IN THE BUFFER TO PRODUCE CORRECT ALIGNMENT,
;AND THEN DELETE THEM WHEN FINISHED READING.
FYCMD:	TLNN FF,FLIN
	 TYPRE [NFI]
	TRNN FF,FRARG
	 JRST FYCMDA	;NO ARG => READ THE WHOLE FILE.
	JUMPL C,TYPAOR	;NEGATIVE ARG NOT ALLOWED.
FYCMD6:	SAVE C
	MOVE BP,UTYIP	;FOR SPEED, LEAVE ENOUGH SPACE BEFORE INSERTING THE FILE
	CALL GETCA	;TO ENABLE TRANSFER TO GO WORDWISE.
	MOVEI BP,1(BP)
	SUB BP,PT
	IDIVI BP,5
	SKIPE BP,T
	 ADDI BP,5
	SAVE BP
	ADD C,BP		;THAT MUCH, PLUS # CHARS BEING READ, IS AMT OF SPACE WE NEED.
	CALL GAPSLP	;GET GAP TO POINT.
	CALL SLPSAV	;MAKE SURE THERE'S ENOUGH SPACE.
	CALL IMMQIT	;ALLOW QUITTING IF WE HANG UP DOING THE I/O
	MOVE C,-1(P)
	MOVE BP,PT
	ADD BP,(P)	;LEAVE THE FEW CHARS OF SPACE TO REACH PROPER ALIGNMENT.
	CALL GETIBP	;CREATE B.P. FOR IDPB'ING INTO THE GAP.
FYCMD0:	JUMPE C,FYCMDE
	MOVE A,UTYIP	;AND LOOK AT B.P. WE'LL ILDB FROM.
	HRRZ B,UTRLDT
	ADD B,[(010700)-1]
FYCMDW:	TLNN A,760000
	 JRST FYCMD1	;JUMP IF CAN START GOING WORD-WISE.
FYCMDS:	CAMN A,B
	 JRST FYCMDR	;IF UTIBUF EXHAUSTED, MUST RELOAD IT.
	ILDB CH,A	;OTHERWISE, TRANSFER ONE MORE CHARACTER
	IDPB CH,BP
	SOJG C,FYCMDW
	MOVEM A,UTYIP
FYCMDE:	CALL UTEOF	;IF THERE'S NOTHING LEFT IN THE INPUT FILE, MARK IT "AT EOF".
	CALL DELQIT
	MOVE E,-1(P)
	SUB E,C		;# CHARS ACTUALLY READ IN
	ADD E,(P)	;PLUS # CHARS OF SPACE LEFT AT FRONT.
	ADDM E,GPT	;"INSERT" THE DATA AND THE SPACE AT FRONT.
	ADDM E,ZV	;BUT DON'T CHANGE POINT, YET.
	ADDM E,Z
	SUBM E,EXTRAC
	MOVNS EXTRAC
	REST C		;C HAS # CHARS OF SPACE THAT'S NOW IN THE BUFFER
	SUB P,[1,,1]
	JUMPE C,FYCMD8
	SUB E,C		;E HAS # CHARS OF REAL DATA NOW INSERTED.
	CALL GAPSLP	;GET GAP TO POINT, WHICH STILL POINTS VBEFORE THE SPACE
	CALL DELETB	;AND DELETE THE SPACE.
FYCMD8:	ADDM E,PT	;NOW MAKE POINT GO AFTER THE INSERTED DATA.
	RET

FYCMDR:	CAME A,[010700,,UTIBE-1]
	 JRST FYCMDE	;IF LAST INPUT BUFFER WASN'T FULL, THIS IS EOF.
	CALL UTRLD2	;ELSE, READ ANOTHER INPUT BUFFER AND CONTINUE TRANSFERING.
	JRST FYCMD0

;HERE TO ATTEMPT A WORD-WISE TRANSFER.
FYCMD1:	MOVEM A,UTYIP
	CAIGE C,5	;DON'T BOTHER TRYING TO GO FAST IF < 1 WHOLE WORD LEFT.
	 JRST FYCMDS
	IDIVI C,5	.SEE D
	IBP BP
	SUB B,A		;IF THEER'S ANYTHING LEFT IN UTIBUF, MUST USE IT FIRST.
	JUMPE B,FYCMDI	;LH'S CANCEL SINCE BOTH ARE 010700.
	IBP A
	HRL BP,A
	CAMLE B,C	;# WORDS TO TRANSFER RIGHT NOW =
	 MOVE B,C	;MIN (<WORDS LEFT IN UTIBUF>, <WORDS WANTED>).
	ADDM B,UTYIP	;REMOVE THAT MANY WORDS FROM THE BUFFER.
	SUB C,B		;# WORDS THAT WILL BE LEFT EMPTY AFTER USING UP UTIBUF?
	ADD B,BP
	BLT BP,-1(B)	;TRANSFER WHAT'S LEFT OF UTIBUF.
	IMULI C,5
	HRRZ BP,B
	JRST FYCMD2

;GOING WORD AT A TIME, AND UTIBUF IS EMPTY, SO GET DIRECTLY FROM FILE.
FYCMDI:
IFN ITS,[
	CAIGE C,100000	;DON'T TRY TO IOT MORE THAN 32K AT A TIME.
	 JRST FYCMD4
	IMULI C,5
	ADD D,C		;SO PUT TOTAL # CHARS TO GET, MINUS 32K OF CHARS, IN D,
	SUBI D,5*100000
	MOVEI C,100000	;AND GET ONLY 32K RIGHT NOW.
FYCMD4:	MOVNS C
	HRL BP,C		;AOBJN -> BUFFER WORDS TO TRANSFER INTO.
	.IOT CHFILI,BP
	HLRE C,BP
]
IFN TNX,[
	SAVE B
	MOVE A,CHFILI	;INPUT FILE
	MOVEI B,(BP)	;FIRST WORD TO READ INTO
	HRLI B,444400
	MOVNS C
	SIN
	MOVEI BP,1(B)	;UPDATE FIRST WORD NOT READ INTO
	HRL BP,C		;UPDATE COUNT LEFT TO DO
	REST B
]
	IMUL C,[-5]
FYCMD2:	ADD C,D		;# CHARS WE WERE SUPPOSED TO TRANSFER BUT HAVEN'T YET.
	JUMPL BP,FYCMD3	;EOF => WE WILL NEVER GET THEM, SO INSERT WHAT WE HAVE GOT.
	ADD BP,[(010700)-1]	;GET BACK B.P. TO IDPB THE REST OF THE DATA
	JRST FYCMD0	;RELOAD BUFFER TO XFER LAST FEW CHARS 1 AT A TIME.

FYCMD3:	CALL UTLSTP
	JRST FYCMDE

;READ NEXT CHARACTER FROM OPEN INPUT FILE, AND RETURN IT IN CH.
;UP TO A WORD OF ^C'S OR ^@'S BEFORE THE END OF THE FILE WILL BE IGNORED.
;IF TRY TO READ PAST EOF, FS LASTPAGE$ WILL BE SET TO 0, AND ^L WILL BE RETURNED.
UTYI:	ILDB CH,UTYIP
	CAILE CH,EOFCHR
	 RET
	CAIE CH,EOFCHR
	 JUMPN CH,CPOPJ
	HRRZ CH,UTYIP
	CAIN CH,UTIBE
	 JRST UTYIR	;EXHAUSTED BUFFER => REALOD IT AND TRY AGAIN.
UTYI4:	MOVE CH,UTYIP
	CAMN CH,UTRLDT
	 JRST UTYIE	;READ PAST EOF => CLOSE FILE AND RETURN A ^L.
;^C OR ^@ INSIDE THE FILE - IS IT PADDING BEFORE EOF?
	HRLI CH,010700
	IBP CH
	CAME CH,UTRLDT	;MORE THAN 1 WORD FROM THE END => IT ISN'T PADDING.
	 JRST UTYI5
	ANDI CH,-1
	CAIE CH,UTIBE	;THIS LAST WORD OF INPUT BUFFER => WE DON'T KNOW WHETHER
	 JRST UTYI1	;THERE ARE MORE WORDS IN THE FILE,
	MOVE CH,UTIBE-1	;SO FIND OUT BY PUTTING THIS WORD AT BEGINNING OF BUFFER
	MOVEM CH,UTIBUF	;AND FILLING UP THE REST IF POSSIBLE.
	MOVE CH,UTIBE
	MOVEM CH,UTIBUF+1
	MOVNI CH,UTIBE-UTIBUF-1
	ADDM CH,UTYIP
	ADDM CH,UTRLDT
	CALL UTRLD3	;NOW TRY FILLING REST OF INPUT BUFFER.
	JRST UTYI4	;WE NOW HAVE ENOUGH INFO TO ANSWER OUR QUESTION.

;COME HERE WHEN A ^C OR ^@ IS FOUND IN THE LAST WORD OF THE FILE, TO LOOK
;AHEAD AND SEE IF REST OF THE CHARS IN LAST WORD ARE ALL ^C OR ^@.
UTYI1:	SAVE UTYIP
UTYI3:	ILDB CH,UTYIP
	CAIE CH,^C
	 JUMPN CH,UTYI2
	MOVE CH,UTYIP
	CAME CH,UTRLDT
	 JRST UTYI3
	SUB P,[1,,1]	;ALL ARE ^C OR ^@ => RETURN CLOSING FILE.
UTYIE:	CALL UTLSTP
	MOVEI CH,^L
	RET

UTYI2:	REST UTYIP	;NOT ALL PADDING => THIS ^C OR ^@ IS REALLY DATA, AND SO ARE THE REST.
UTYI5:	LDB CH,UTYIP
	RET

UTYIR:	CALL UTRLD2
	JRST UTYI	;GO BACK AND TRY AGAIN

;"EC" COMMAND -- CLOSE THE INPUT FILE AND MARK IT CLOSED.
UICLS:	CALL UTLSTP	;FIRST, SET "AT EOF" SO ATTEMPTS TO READ WILL GET ^C'S.
IFN ITS,[
	CLOSEF CHFILI
	TLZ FF,FLIN
]
.ELSE [
	MOVE A,CHFILI
	TLZN FF,FLIN
	 JRST [	JUMPE A,CPOPJ
		RLJFN
		 JFCL
		JRST .+3]
	CLOSF
	 JFCL
	SETZM CHFILI
]
	RET

;REFILL THE INPUT BUFFER.
UTRLD2:	MOVE CH,[10700,,UTIBUF-1]
	MOVEM CH,UTYIP
IFN ITS,[
	SKIPA CH,[UTIBUF-UTIBE,,UTIBUF]
UTRLD3:	 MOVE CH,[UTIBUF+1-UTIBE,,UTIBUF+1]
	.IOT CHFILI,CH
	HRRM CH,UTRLDT	;FIRST ADR. NOT LOADED BY SYS
	JUMPGE CH,CPOPJ
	MOVEI CH,EOFCHR
	DPB CH,UTRLDT	;STORE EOF THERE
	POPJ P,
]
IFN TNX,[
	JSR SAVABC	;SAVE ACS
	MOVE B,[444400,,UTIBUF]	;POINTER TO BUFFER
	MOVNI C,UTIBE-UTIBUF	;COUNT TO READ
UTRLD4:	MOVE A,CHFILI	;INPUT FILE
	SIN
	AOJ B,		;WILL BE OF THE FORM 004400,,ADDR-1
	HRRM B,UTRLDT	;FIRST ADDR NOT LOADED
	JUMPE C,POPCBA	;HAVE WE REACHED EOF?
	MOVEI CH,EOFCHR	;YES
	DPB CH,UTRLDT
	JRST POPCBA
UTRLD3:	JSR SAVABC
	MOVE B,[444400,,UTIBUF+1]	;TRY TO FILL THE REST OF THE BUFFER
	MOVNI C,UTIBE-UTIBUF-1
	JRST UTRLD4
]

;SEE IF THE INPUT FILE IS AT EOF.  IF SO, SET FS LASTPA, ETC.
;TO TELL THE USER THAT IT IS.
UTEOF:	SKIPL LASTPA
	 RET		;ALREADY AT EOF => NO CHANGE.
	MOVE CH,UTYIP
	IBP CH
	CAME CH,UTRLDT	;MORE LEFT IN INPUT BUFFER => NOT EOF
	 RET
	ANDI CH,-1
	CAIE CH,UTIBE	;NONE LEFT IN INPUT BUFFER, AND BUFFER WASN'T A FULL ONE,
	 JRST UTLSTP	;=> CLEARLY AT EOF.
	CALL UTRLD2	;AT END OF BUFFER => TRY READING SOME MORE TO SEE
	JRST UTEOF	;IF AT EOF.

;INDICATE THAT THE INPUT FILE IS AT EOF. ALL ATTEMPTS TO READ MORE
;WILL JUST ENCOUNTER ANOTHER EOF.
UTLSTP:	SETZM LASTPA	;SAY "EOF" TO ANYONE WHO ASKS.
	MOVE CH,[010700,,[.BYTE 7 ? EOFCHR]-1]
	MOVEM CH,UTYIP	;SET UP BUFFER TO APPEAR TO BE JUST BEFORE AN EOF
	IBP CH		;SO THAT ANY ATTEMPT TO READ A CHARACTER WILL SEE EOF
	MOVEM CH,UTRLDT	;AND COME RIGHT BACK HERE.
	RET

;FS IF LENGTH$ - READ LENGTH OF OPEN INPUT FILE.
FSIFLEN:TLNN FF,FLIN
	 TYPRE [NFI]
	MOVEI A,CHFILI
IFN ITS,[
FSIFL1:	SYSCAL FILLEN,[A ? %CLOUT,,A]
	 SKIPA A,[-1]
]
IFN TNX,[
FSIFL1:	MOVE A,(A)	;INPUT FILE
	MOVE B,[2,,.FBBYV]
	MOVEI C,A
	GTFDB
	EXCH A,B
	LDB C,[.BP FB%BSZ,B]	;GET BYTE SIZE
	CAIN C,7	;IF 7, ALREADY HAVE WHAT WE WANT
	 JRST POPJ1
	CAIN C,36.	;IF 36, KNOW HOW MANY WORDS ALREADY
	 JRST .+4
	MOVEI B,36.
	IDIVI B,(C)	;GET NUNBER OF BYTES IN A WORD
	IDIVI A,(B)	;GET NUMBER OF WORDS
]
	  IMULI A,5	;INTO CHARACTERS
	JRST POPJ1

FSOFLEN:TLNN FF,FLOUT
	 TYPRE [NDO]
	MOVEI A,CHFILO
	JRST FSIFL1

;SET INPUT FILE ACCESS POINTER TO CHAR # IN C.
FSIFAC:	TLNN FF,FLIN
	 TYPRE [NFI]
IFN ITS,[
	MOVEI A,CHFILI
	.CALL RFACCB
	 TYPRE [NRA]	;NOT RANDOM ACCESS FILE.
	IDIVI C,5	;CHANGE ARG TO WORD #.
	.ACCES CHFILI,C	;FIND THAT WORD.
]
IFN TNX,[
	IDIVI C,5	;CONVERT TO WORD #
	MOVE A,CHFILI
	MOVE B,C	;GET ARG
	SFPTR
	 TYPRE [NRA]
]
	SETOM LASTPA	;EVEN IF FILE WAS AT EOF, IT WON'T BE ANY MORE.
	CALL UTRLD2	;FILL UP THE INPUT BUFFER
	HRRZ CH,UTRLDT
	CAIN CH,UTIBUF	;DID WE GET ANYTHING?
	 JRST UTLSTP	;NO, .ACCESS WENT TO EOF.
	JUMPE D,CPOPJ	;YES, ADVANCE IN WORD TO SPEC'D CHARACTER IF IT ISN'T THE 1ST.
	IBP UTYIP
	SOJG D,.-1
	RET

SUBTTL OUTPUT TO FILES

;THIS IS THE HIGHER LEVELS OF THE P COMMAND.
PUNCH:	SKIPGE OUTFLG		;CHECK FOR OUTPUT DISABLED OR NO FILE OPEN.
	 RET
	TLNN FF,FLOUT
	 TYPRE [NDO]
	TRNE FF,FRARG2
	 JRST PUNCHB		;2-ARG P COMMAND.
	MOVE T,CPTR
	ILDB T,T		;ELSE PEEK AT NEXT CHAR TO SEE IF IT IS W.
	ANDCMI T,40
	SKIPE COMCNT
	 CAIE T,"W
PUNCHA:	  SETZ T,		;ENTER HERE FOR N AND EE COMMANDS.
	SKIPGE OUTFLG		;IF T IS NONZERO, DON'T READ, JUST OUTPUT.
	 RET
	TLNN FF,FLOUT
	 TYPRE [NDO]
	MOVE D,C		;D HAS NUMBER OF PAGES TO OUTPUT.
	JUMPL D,CPOPJ
PUN1:	SAVE D
	SAVE T
	PUSHJ P,PUNCHR
	TRZ FF,FRARG
	SKIPN (P)
	 CALL YANKEE
	REST T
	REST D
	MOVE E,ZV
	CAMN E,BEGV		;KEEP FEEDING PAGES THROUGH UNTIL COUNT RUNS OUT
	 SKIPE LASTPA		;OR WE ARE AT EOF WITH AN EMPTY BUFFER.
	  SOJG D,PUN1
CPOPJ:	POPJ P,VIEW1

PUNCHR:	SKIPGE STOPF	;IN BETWEEN PAGES,
	 CALL QUIT0	;TRY TO QUIT IF DESIRED (CHECKS NOQUIT).
	MOVE E,BEGV
	MOVE C,ZV
	TRZ FF,FRUPRW
	SKIPE FFMODE	;IN FFMODE, ANY ^L DESIRED IS ALREADY IN BFR.
	 JRST PUNCHF
	CALL PUNCHF	;IF ^L'S READ GET THROWN AWAY,
	MOVEI CH,^L	;MUST REGENERATE THEM ON OUTPUT.
	JRST PPA

;FORCE OUT CONTENTS OF OUTPUT BUFFER. CLOBBERS A, B, C.
FLSOUT:	TLNN FF,FLOUT
	 RET		;NO OUTPUT FILE.
	MOVE B,UTYOP
	IBP B		;-> WD NEXT OUTPUT CHAR WILL GO IN.
	MOVEI A,@B
	MOVNI C,-UTOBUF(A) ;# WDS FILLED UP IN FRONT END OF BFR.
	JUMPE C,CPOPJ
IFN ITS,[
	HRLZI A,(C)
	HRRI A,UTOBUF	;AOBJN -> FILLED PART.
	.IOT CHFILO,A
]
IFN TNX,[
	SAVE C
	SAVE B
	MOVE A,CHFILO	;OUTPUT FILE
	MOVE B,[444400,,UTOBUF]	;POINTER TO BUFFER
	SOUT
	REST B
	REST C
]
	MOVE A,(B)	;GET THE PARTIALLY FILLED WORD.
	MOVEM A,UTOBUF	;PUT IT IN 1ST WD OF BUFFER,
	ADDM C,UTYOP	;BACK THE BP UP THE RIGHT # WDS.
	IMULI C,5
	ADDM C,UTYOCT	;MORE SPACE IN OUTPUT BUFFER NOW.
	POPJ P,

;P COMMAND WITH 2 ARGS.
PUNCHB:	SAVE FF
	TRZ FF,FRUPRW
	CALL GETARG	;DECODE THE TWO ARGS, BUT DON'T PROCESS THE @ FLAG NOW.
	 CALL CHK1A	;SAVE IT FOR LATER.
	REST FF
	TRZ FF,FRCLN

;OUTPUT RANGE SPEC'D BY C,E.
PUNCHF:
IFN ITS,[		;TURN ON SEQUENTIAL PAGING FOR RANGE TO BE WRITTEN.
	MOVEI TT,5*2000*5
	MOVE Q,E
	CAMLE Q,GPT
	 ADD Q,EXTRAC
	MOVE CH,C
	CAML CH,GPT
	 ADD CH,EXTRAC
	CALL SEQPAG
	SAVE [SEQPGX]	;REMEMBER TO TURN OFF SEQUENTIAL PAGING LATER.
];ITS
	CAMGE E,GPT
	 CAMG C,GPT	;IF GAP IS INSIDE RANGE TO BE PUNCHED, WE MUST BE CAREFUL.
	  JRST PUNCHG
	PUSH P,C
	MOVE C,GPT
	CALL PUNCHG	;FIRST, PUNCH EVERYTHING UP TO THE GAP.
	MOVE E,GPT
	MOVE TT,EXTRAC
	IDIVI TT,5
	JUMPE TT1,[	;IF GAP DOESN'T DESTROY ALIGNMENT, JUST PUNCH EVERYTHING AFTER THE GAP.
		POP P,C
		JRST PUNCHG]
PUNCHJ:	MOVE E,GPT	;GAP DESTROYS ALIGNMENT;  IT IS FASTEST TO ADJUST ALIGNMENT OURSELVES
	MOVE C,E	;BY MOVING THE GAP UP PAST THE TEXT TO BE OUTPUT.
	ADDI C,4*5*2000	;MOVE THE GAP PAST AT MOST 4K AT A TIME
	SUB C,UTYOCT	;(PLUS ENOUGH TO FILL OUTPUT BUFFER, TO INSURE IT'S EMPTY AT NEXT STOP)
	MOVE T,(P)	;AND THEN OUTPUT THAT 4K.
	CAMG T,C	;WHEN LESS THAN 4K REMAIN TO BE DONE,
	 JRST [	POP P,C	;WE DO WHAT IS LEFT AND EXIT.
		JRST PUNCHH]
	CALL PUNCHH
	JRST PUNCHJ

;OUTPUT RANGE FROM C(E) TO C(C), MOVING GAP PAST IT FIRST.
PUNCHH:	SAVE PT		;MOVE THE GAP UP PAST END OF RANGE TO BE TRANSFERRED NOW,
	MOVEM C,PT
	CALL GAPSL0	;WITHOUT MARKING THE BUFFER AS MODIFIED, HOWEVER.
	REST PT

;OUTPUT RANGE FROM C(E) TO C(C), OF VIRTUAL ADDRESSES,
;ASSUMING THE GAP IS NOT IN THE WAY.
PUNCHG:	MOVE IN,E
	MOVE BP,IN
	SUBM C,IN	;IN GETS COUNT OF CHARS REMAINING.
	JUMPLE IN,CPOPJ
	PUSHJ P,GETIBV	;BP GETS BP TO FETCH FROM BUFFER.
PCHF1:	MOVE TT,UTYOP
	HLRZ OUT,BP
	CAMN TT,[010700,,UTOBUF-1] ;UTOBUF EMPTY AND
	CAIE OUT,010700	;NEXT CHR IN BUFFER IS 1ST IN A WD =>
	 JRST PCHF2
PCHF3:	CAIGE IN,5	;TRY .IOTING OUT OF BUFFER.
	 JRST PCHF2
	ADDI BP,1
	MOVE CH,IN	;GET # WDS FULL IN BUFFER AFTER WHERE WE ARE.
	IDIVI CH,5
	CAIL CH,4000
	 MOVEI CH,4000	;DON'T OUTPUT MORE THAN 2K AT ONCE.
	TRNE FF,FRUPRW
	 JRST PCHF4
	SAVE BP		;UNLESS THIS IS @P,
	MOVN Q,CH	;CLEAR THE LOW BITS IN THIS 2K.
	HRL BP,Q	;WE GET BETTER PAGING BEHAVIOR IF WE CLEAR AND THEN OUTPUT
	MOVEI Q,1	;2K AT A TIME.
	ANDCAM Q,(BP)
	AOBJN BP,.-1
	REST BP
PCHF4:
IFN ITS,[
	MOVNS CH
	HRLI BP,(CH)	;BP HAS AOBJN -> WDS IN BUFFER.
	.IOT CHFILO,BP
]
IFN TNX,[
	JSR SAVABC	;SAVE ACS
	MOVNS C,CH	;NUMBER OF CHARS
	MOVEI B,(BP)	;FIRST WORD 
	HRLI B,444400
	MOVE A,CHFILO	;OUTPUT FILE
	SOUT
	HRRI BP,1(B)	;FIRST ADDR NOT WRITTEN
	JSP A,RST321	;RESTORE ACS
]
	IMULI CH,5	;# CHARS JUST OUTPUT.
	ADD IN,CH	;THAT MANY FEWER LEFT.
	SUBI BP,1	;CHANGE BP BACK TO BP TO NEXT CHAR.
	HRLI BP,010700
	JRST PCHF3	;HANDLE REMAINING CHARS.

PCHF2:	MOVN OUT,UTYOCT
	CAMLE OUT,IN
	 MOVE OUT,IN	;OUT GETS # OF CHARS TO XFER INTO OUTPUT BUFFER.
	PUSH P,OUT
	JUMPE OUT,PPG1
	MOVE E,[PPG,,A]
	BLT E,D
	JRST A

PPG:	ILDB CH,BP	;A
	IDPB CH,TT	;B
	SOJG OUT,A	;C
	JRST PPG1	;D

PPG1:	POP P,OUT
	MOVEM TT,UTYOP
	ADDM OUT,UTYOCT	;UPDATE MINUS NUMBER OF FREE CHARS REMAINING IN BUFFER.
	SKIPL UTYOCT
	 CALL UTYOA
	SUB IN,OUT
	JUMPG IN,PCHF1
	RET

POPDJ:	POP P,D
	POPJ P,

;OUTPUT CHAR IN CH TO OUTPUT FILE, IF ANY.
PPA:
PPA2:	SKIPGE OUTFLG
	 RET
	TLNE FF,FLOUT
	 JRST UTYO
	RET

UTYO:	IDPB CH,UTYOP
	AOSGE UTYOCT
	 POPJ P,
UTYOA:	MOVEM CH,UTYOP
	MOVNI CH,<UTOBE-UTOBUF>*5
	MOVEM CH,UTYOCT
IFN ITS,[
	MOVE CH,[UTOBUF-UTOBE,,UTOBUF]
	.IOT CHFILO,CH
	MOVE CH,[10700,,UTOBUF-1]
	EXCH CH,UTYOP
	POPJ P,
]
IFN TNX,[
	JSR SAVABC	;SAVE ACS
	MOVE A,CHFILO	;OUTPUT FILE
	MOVE B,[444400,,UTOBUF]	;POINTER TO BUFFER
	MOVNI C,UTOBE-UTOBUF	;COUNT
	SOUT
	MOVE CH,[10700,,UTOBUF-1]	;UPDATE BUFFER POINTER
	EXCH CH,UTYOP
	JRST POPCBA	;RESTORE ACS AND RETURN
] ;IFN TNX

;SET ACCESS POINTER OF OUTPUT FILE TO CHAR # IN C,
;WHICH MUST BE A MULTIPLE OF 5. ERROR IF ANY CHARS IN OUTPUT
;BUFFER ARE LOST (WHICH WILL BE THE CASE UNLESS OUTPUT STOPPED
;ON A WORD BOUNDARY).
FSOFAC:	TLNN FF,FLOUT
	 TYPRE [NDO]
IFN ITS,[
	MOVEI A,CHFILO
	.CALL RFACCB
	 TYPRE [NRA]
]
	SAVE C
	CALL FLSOUT	;FORCE OUT THE OUTPUT BUFFER.
	REST C
	MOVN A,UTYOCT	;ANYTHING NOT FORCED OUT??
	CAIE A,UTBSZ*5
	 TYPRE [WLO]
	IDIVI C,5	;GET WORD # IN FILE OF DESIRED POSITION.
	SKIPE D
	 TYPRE [ARG]	;ARG NOT MULTIPLE OF 5??
IFN ITS,.ACCES CHFILO,C
IFN TNX,[
	MOVE A,CHFILO	;OUTPUT FILE
	MOVE B,C
	SFPTR		;SET POINTER
	 TYPRE [NRA]
]
	RET

SUBTTL I/O COMMANDS

ECMD:	TLO FF,FLDIRDPY	;DISPATCH FOR E-COMMANDS.
	PUSHJ P,LRCH
	ANDI CH,-1
	CAIN CH,^U
	 JRST EUHACK
	CAIGE CH,"?	;IF CHARACTER BEYOND "?, DISPATCH ON IT.
	 TYPRE [IEC]
	XCT ETAB-"?(CH)

RLTCLK:	CALL SAVACS	;RUN THE REAL TIME CLOCK HANDLER.  DON'T CLOBBER ANYTHING.
	SAVE SQUOTP
	SAVE RCHALT
	MOVE A,[JFCL ENDARG]
	MOVEM A,RCHALT
	SETZM CLKFLG
	SKIPE A,CLKMAC
	 CALL MACXCP
	SETZM CLKFLG
	REST RCHALT
	REST SQUOTP
	JRST RSTACS

IFN ITS,[.SEE %%TNX%	;WHERE THIS MOBY CONDITIONAL ENDS

ASLEEP:	CALL IMMQIT
	TRZE FF,FRCLN
	 JRST ASLEE1
	TRZE FF,FRARG
	 .SLEEP C,
	JRST DELQIT

ASLEE1:	AOS (P)		;<DUR>:^S 1) RETURNS RESULT OF FS LISTEN$
ASLEE4:	TRZ FF,FRARG	;         2) SLEEPS ONLY AS LONG AS THERE IS NO INPUT AVAIL.
	SKIPN TYISRC
	 SKIPL UNRCHC
	  SKIPA A,[1]
	   .LISTEN A,
	JUMPN A,DELQIT
	JUMPE C,DELQIT
	CALL TTYAC2
ASLEE2:	.SLEEP C,
	JRST ASLEE4

EQMRK:	CALL FFRRDD	;E?<FILE>$ 0 IF FILE EXISTS, ELSE (NUMERIC) ERROR CODE.
	MOVE A,[.BAI+10,,CHRAND] ;THE 10 MEANS DON'INSIST ON EXISTING JOB,
				 ;OR DON'T SET THE REF DATE FOR A DISK FILE.
	CALL IMMQIT
	.CALL RREDB	;TRY TO OPEN;  A GETS 0 OR I.T.S. ERROR CODE
	 JFCL
	SETZM IMQUIT
	.CLOSE CHRAND,
	JRST POPJ1

;FS CLK INTERVAL$ - SET REAL TIME CLOCK INTERVAL IN 60THS.  VALUE SAVED IN CLKINT BY FSNORM.
FSCLKI:	TRNN FF,FRARG
	 JRST FSNORM
	SKIPE C		;OR TURN OFF REAL TIME CLOCK, WITH ARG OF 0.
FSCLK0:	 SKIPA A,[%RLSET,,C]
	  MOVSI A,%RLFLS
	.REALT A,
	JRST FSNORM

SUBTTL EG COMMAND

EGET:	PUSH P,LISTF5
	MOVEI A,TYOM
	HRRM A,LISTF5
	CALL GAPSLP
	TLZ FF,FLDIRDPY	;EGET TO INSERT IN THE BUFFER
	PUSHJ P,GDATIM
	JFCL
	PUSHJ P,GLPDTM
	SKIPG E,DATE	;THE DATE
	 SETZ E,	;IF SYSTEM DOESN'T KNOW DATE, USE 6 SPACES.
	CALL TYPR
	CALL CRR1
	SKIPG E,TIME
	 SETZ E,
	CALL TYPR	;INSERT TIME FROM SIXBIT WORD,
	CALL CRR1
	MOVSI CH,(LFN"DIRFLG)	;Get default directory into TMPFIL
	MOVSI E,DEFFIL
	CALL FSRFNC
	MOVEI A,TMPFIL
	CALL ASCIND
	CALL CRR1
	MOVEI A,DEFFIL
	CALL ASCIND	;INSERT CURRENT DEFAULT FILE NAMES.
	CALL CRR1
	TLNN FF,FLIN	;THE NAMES OF THE FILE OPEN FOR READING (IF ANY)
	 JRST EGET2	;(NONE, LEAVE BLANK LINE - EVENTUALLY REPLACE THIS CRUFT WITH .RCHST)
	MOVEI A,INFILE
	CALL ASCIND
EGET2:	CALL CRR1
	SKIPL TIME
	PUSHJ P,SYMDAT	;THE DATE IN STANDARD SYMBOLIC FORM
	PUSHJ P,CRR1
	LDB CH,[320300,,YEAR]	;A THREE DIGIT NUMBER
	PUSHJ P,DGPT	;FIRST DIGIT DAY OF WEEK (0 => SUNDAY)
	LDB CH,[270300,,YEAR]	;SECOND DIGIT DAY OF WEEK OF BEGINNING OF YEAR
	PUSHJ P,DGPT
	LDB CH,[410300,,YEAR]	;THIRD DIGIT 3 BITS
		;4 BIT 1 => NORMAL YEAR AFTER 2/28
		;2 BIT 1 => LEAP YEAR
		;1 BIT 1 => DAYLIGHT SAVINGS TIME IN EFFECT
	PUSHJ P,DGPT
	PUSHJ P,CRR1
	PUSHJ P,POM	;THE PHASE OF THE MOON
	PUSHJ P,CRR1
	POP P,LISTF5
	POPJ P,

		;VARIOUS TIME GETTING ROUTINES

GDATIM:	.RDATIM A,	;GET TIME IN A, DATE IN B
	MOVEM A,TIME	;STORE SIXBIT TIME
	MOVEM B,DATE	;STORE SIXBIT DATE
	JUMPGE A,POPJ1	;IF TIME AVAILABLE THEN SKIP-RETURN
	POPJ P,		;NOT AVAILABLE, DON'T SKIP (BUT LEAVE TIME AND DATE NEGATIVE)

GLPDTM:	.RLPDT A,	;GET VARIOUS TIMES IN BINARY
	MOVEM B,YEAR	;SAVE YEAR AND FLAGS
	MOVEM A,LPDTIM	;SAVE LOCALIZED # SECONDS SINCE BEGINNING OF YEAR
	TLNE B,400000	;IF NORMAL YEAR AFTER FEB 28,
	SUBI A,SPD	;THEN BACK UP A DAY
	TLNE B,100000	;IF DAYLIGHT SAVINGS TIME IN EFFECT,
	SUBI A,3600.	;THEN BACK UP AN HOUR
	MOVEM A,PDTIME	;SAVE # SECONDS SINCE BEGINNING OF YEAR
	POPJ P,

		;TYPE OUT (THROUGH LISTF5) THE DATE IN ENGLISH

SYMDAT:	PUSHJ P,DOW	;TYPE DAY OF WEEK
	REPEAT 2,PUSHJ P,SPSP	;TYPE TWO SPACES
	MOVE E,DATE	;GET DATE
	DPB E,[221400,,CDATE]	;DEPOSIT SIXBIT FOR DAY OF MONTH
	LDB CH,[220100,,DATE]	;GET FIRST DIGIT OF MONTH
	LDB E,[140400,,DATE]	;GET SECOND DIGIT OF MONTH
	IMULI CH,10.	;MULTIPLY THE FIRST DIGIT TO ITS PROPER WEIGHTING
	ADD E,CH	;ADD TOGETHER TO GET MONTH
	MOVE E,MONTHS-1(E)	;GET MONTH IN SIXBIT
	PUSHJ P,SIXNTY	;TYPE OUT MONTH
	MOVE E,CDATE	;GET FIRST PART OF DATE
	PUSHJ P,TYPR	;TYPE OUT
	MOVE E,DATE	;GET DATE
	MOVEI IN,2	;LIMIT TYPEOUT TO TWO CHARACTERS
	JRST TYPR3	;TYPE OUT LAST TWO DIGITS OF YEAR AND RETURN

MONTHS:	IRPS S,,[JAN FEB MARCH APRIL
MAY JUNE JULY AUG SEPT OCT NOV DEC]
	SIXBIT /S/
TERMIN

		;TYPE OUT DAY OF WEEK

DOW:	LDB A,[320300,,YEAR]	;GET DAY OF WEEK (0 => SUNDAY)
	MOVE A,DOWTBL(A)	;GET SIXBIT FOR DAY (EXCEPT FOR THE "DAY")
	PUSHJ P,SIXIN1	;TYPE OUT
	MOVSI A,(SIXBIT /DAY/)	;NOW FOR THE "DAY"
	JRST SIXIN1	;TYPE IT OUT AND RETURN

DOWTBL:	IRPS DAY,,[SUN MON TUES WEDNES THURS FRI SATUR]
	SIXBIT /DAY/
	TERMIN

		;TYPE OUT THE PHASE OF THE MOON

POM:	PUSHJ P,GNDS0	;GET NUMBER OF DAYS SINCE 1/1/0000
	MULI A,SPD	;CONVERT TO SECONDS IN A AND B
	JFCL 17,.+1	;CLEAR FLAGS FOR FOLLOWING
	ADD B,PDTIME	;# SECONDS SINCE BEGINNING OF YEAR
	ADD B,SYNOFS	;THE MOON DOESN'T QUITE BELIEVE IN THE GREGORIAN CALENDAR SYSTEM
	JFCL 4,[AOJA A,.+1]	;CRY1
	ASHC A,2	;CONVERT TO QUARTER SECONDS
	DIV A,SYNP	;DIVIDE BY NUMBER OF SECONDS IN A PERIOD TO GET NUMBER OF QUARTERS SINCE THEN
	ASH B,-2	;CONVERT REMAINDER TO SECONDS (# SECONDS INTO THIS QUARTER)
	PUSH P,B	;SAVE REMAINDER
	IDIVI A,4	;GET QUARTER IN B
	MOVE A,[SIXBIT /NM+   FQ+   FM+   LQ+/](B)	;GET SIXBIT CRUFT IN A (I REFUSE TO CHANGE THE 1Q!!!)
	PUSHJ P,SIXIN1	;TYPE IT OUT
	POP P,B	;RESTORE # SECONDS INTO THIS PERIOD
TDHMS:	MOVEI E,TDHMST	;SET POINTER TO TABLE
TDHMS1:	IDIVI B,@(E)
	JUMPE B,TDHMS2
	HRLM C,(P)
	PUSHJ P,[AOJA E,TDHMS1]	;INCREMENT INDEX WHILE RECURSING
	HLRZ C,(P)
TDHMS2:	PUSHJ P,DPT	;TYPE OUT IN DECIMAL
	HLLZ A,(E)	;GET SIXBIT CRUFT
	SOJA E,SIXIN1	;BACK UP INDEX, TYPE OUT, AND RETURN

TDHMST:	SIXBIT /S./+60.	;SECONDS
	SIXBIT /M./+60.	;MINUTES
	SIXBIT /H./+24.	;HOURS
	SIXBIT /D./+<,-1>	;DAYS

SYNP:	2551443.
SYNOFS:	690882.

		;GET NUMBER OF DAYS SINCE 1/1/0000 (AS OF 1/1/CURRENT YEAR) IN A

GNDS0:	MOVEI C,@YEAR	;GET YEAR
	MOVEI A,-1(C)	;ALSO GET YEAR-1 IN A
	IMULI C,365.	;FIRST APPROXIMATION
	IDIVI A,4
	ADD C,A		;ADD NUMBER OF YEARS DIVISIBLE BY 4
	IDIVI A,25.
	SUB C,A		;SUBTRACT NUMBER OF YEARS DIVISIBLE BY 100
	IDIVI A,4
	ADD A,C	;ADD CRUD ALREADY CALCULATED TO NUMBER OF YEARS DIVISIBLE BY 400
	AOJA A,CPOPJ

SUBTTL FILENAME READER FOR ITS

;Read in a filename, merge in the defaults from DEFFIL,
;and store the results back in DEFFIL.
ETCMD:
FFRRDD:	CALL FRD
	MOVE A,[TMPFIL,,DEFFIL]
	BLT A,DEFFIL+FNMLEN-1
	RET

;Read in a filename and leave it in TMPFIL.  Don't change DEFFIL.
FRD:	MOVE D,[441000,,BAKTAB]
FF2:	PUSHJ P,LRCH
	SKIPGE SQUOTP		;If char is superquoted, set 200 bit to make compares
	 TRO CH,200		;with special syntax chars fail to match.
	SKIPN SQUOTP		;The 200 bit will be dropped in the PFNMCH below.
	 CAIE CH,ALTMOD
	  CAIA
	   JRST FFTRM
	CAME D,[141000,,BAKTAB+F10LEN-1]
	 IDPB CH,D		;Store the arg as a string in BAKTAB.
	JRST FF2

FFTRM:	SETZ B,			;Make the string asciz.
	IDPB B,D
	MOVE D,[441000,,BAKTAB]

;Merge the filenames from the BP in D with the current defaults
;and put the results in TMPFIL.  Clobbers A, B, C.
FFMRG:	MOVE C,[440700,,DEFFIL]
FFMRG1:	SAVE E
	SAVE C
	MOVE A,[-FNBLEN,,BAKTAB+F10LEN]
	CALL LFN"PARFN		;Parse into a filename block.
	 JFCL
	REST D			;Get back default string
	MOVE B,A		;Save first filename block ptr
	MOVE A,[-FNBLEN,,BAKTAB+F10LEN+FNBLEN]
	CALL LFN"PARFN		;Parse the defaults into another filename block
	 JFCL
	EXCH A,B
	MOVEI C,TMPFIL
	MOVEI D,FNMLEN*5
	MOVEI E,1
	SKIPL FNAMSY
	 MOVEI E,2
	CALL LFN"SMERGE
	 TYPRE [FTL]
	REST E
	POPJ P,

LFN"$$PARSE==1
LFN"$$GNAME==1
LFN"$$MERGE==1
LFN"$$PFNMCH==1
LFN"$$MNAME==1
;Insert filename reader library.
.INSRT SYSENG;LFN

;Subroutines called by RFN and PFN.
PFNTRM:
RFNTRM:	RET

FSIFILE:SKIPA E,[INFILE]	;FS I FILE$ - DESCRIBE OPEN INPUT FILE.
FSOFIL:	 MOVEI E,OUTFIL	;FS O FILE$ - DESCRIBE LAST CLOSED OUTPUT FILE.
	AOSA (P)
FSDFRD:	 MOVEI E,DEFFIL
FSDFR1:	SAVE C
	MOVEI C,FNMLEN*5	;UPPER BOUND ON SPACE REQUIRED.
	CALL QOPEN	;MAKE SURE ENOUGH SPACE, SET UP BP AND LISTF5 TO STORE INTO STRING.
	MOVE A,E
	CALL ASCIND		;OUTPUT DATA COPIED OUT OF FILENAME INTO STRING SPACE.
	CALL QCLOSV		;MAKE THE STRING HEADER.
	JRST POPCJ

;FILE COPY
FCOPY:	PUSHJ P,FFRRDD
	MOVE A,[.BAI,,CHRAND]
	CALL IMMQIT
	.CALL RREDB	;OPEN FOR INPUT, NAMES IN DEFFIL
	 JRST OPNER1
	TRNN FF,FRUPRW	;@ E_ => XFER REAL FILENAMES OF SOURCE TO DEFAULTS.
	 JRST FCOPY3
	SYSCAL RFNAME,[ %CLIMM,,%JSELF ? %CLIMM,,CHRAND
			[440700,,DEFFIL] ? %CLIMM,,FNMLEN*5]
	 .LOSE %LSFIL
FCOPY3:	PUSHJ P,FFRRDD		;READ OUTPUT FILENAME INTO DEFFIL.N
	MOVE D,[440700,,[ASCIZ /_TECO_ OUTPUT/]]
	CALL FFMRG		;CONSTRUCT TEMP FILE NAME IN TMPFIL
	SYSCAL SOPEN,[[.BAO,,CHERRI] ? [440700,,TMPFIL]]
	 JRST OPNER1
	TRNN FF,FRCLN	;:E_ => TRANSFER INPUT FILE DATE TO OUTPUT FILE.
	 JRST FCOPY2
	SYSCAL RFDATE,[%CLIMM,,CHRAND ? %CLOUT,,Q]
	 SETOM Q
	SYSCAL SFDATE,[%CLIMM,,CHERRI ? Q]
	 JFCL
	SYSCAL RAUTH,[%CLIMM,,CHRAND ? %CLOUT,,Q]
	 JRST FCOPY2
	SYSCAL SAUTH,[%CLIMM,,CHERRI ? Q]
	 JFCL
FCOPY2:	MOVE T,[-LTABS,,BAKTAB]
	.IOT CHRAND,T
	JUMPL T,FCOPY4
	MOVE T,[-LTABS,,BAKTAB]
	.IOT CHERRI,T
	JRST FCOPY2

FCOPY4:	.CLOSE CHRAND,
	MOVSI T,-BAKTAB-1(T)
	EQVI T,-1#BAKTAB
	.IOT CHERRI,T
	SYSCAL RENMWO,[%CLIMM,,CHERRI ? [440700,,DEFFIL]]
	 .VALUE
	.CLOSE CHERRI,
	JRST DELQIT

BPNTRD:	PUSHJ P,.OPNRD
	TRZ FF,FRARG
	JRST .FNPNT

.OPNRD:	PUSHJ P,FFRRDD
RRED:	TLZ FF,FLIN	;IN CASE OPEN FAILS, INDICATE NOTHING IS OPEN.
	CALL UTLSTP
	MOVE A,[2,,CHFILI]
	MOVE C,NUM
	TRNE FF,FRARG	;IF HAVE ARG, IOR IT INTO OPEN-MODE.
	 TLO A,(C)
	TRZE FF,FRARG2	;PRE-COMMA ARG MEANS DON'T UPDATE REFERENCE DATES
	 TLO A,10
	CALL IMMQIT
	TLZ A,1		;MAKE SURE MODE USED FOR INPUT OPEN IS EVEN!
	.CALL RREDB	;OPEN NAMES IN DEFFIL, MODE,,CHNL IN A.
	 JRST OPNER1	;FAILURE.
	SETZM IMQUIT
	SETZM PAGENU	;HAVE READ 0 PAGES SO FAR.
	SETOM LASTPA	;NOT ON LAST PAGE AS FAR AS TECO KNOWS.
	CALL RREDGN	;DO .RCHST, SET UP ERDEV, ERSNM, RUTF1, RUTF2.
;COME HERE TO START "OFFICIALLY" READING A FILE ALREADY OPEN.
RRED1:	TLO FF,FLIN
	MOVEI CH,^C
	DPB CH,[350700,,UTIBE]
	MOVE CH,[010700,,UTIBE-1]
	MOVEM CH,UTYIP
	AOS CH
	HRRM CH,UTRLDT
	POPJ P,

RREDB:	SETZ ? SIXBIT/SOPEN/ ? A ? [440700,,DEFFIL] ? 403000,,A

RREDGN:	SYSCAL RFNAME,[%CLIMM,,%JSELF ? %CLIMM,,CHFILI ? [440700,,BAKTAB] ? %CLIMM,,FNMLEN*5]
	 .LOSE %LSFIL
	MOVE D,[440700,,BAKTAB]
	CALL FFMRG
	MOVE A,[TMPFIL,,INFILE]
	BLT A,INFILE+FNMLEN-1
	RET

;IO PUSH-DOWN COMMANDS

;E[ => PUSH INPUT CHANNEL
PSHIC:	TLZ FF,FLDIRDPY	;DON'T TRY TO CONTROL U
	MOVEI CH,CHFILI	;SET ARG TO FOLLOWING
	TLNN FF,FLIN	;IF FILE NOT OPEN,
	 JRST PSHIC2
	PUSHJ P,PSHCK	;E := WORD ADR OR DIE BECAUSE NOT RANDOM ACCESS
	MOVE A,UTYIP	;GET BYTE POINTER
	IBP A		;MAKE SURE IT POINTS *TO* THE WORD TO GET THE NEXT BYTE FROM
	MOVEI T,(A)
	SUB T,UTRLDT
	HRREI T,(T)	;GET -<# WORDS TO GO TO END OF BUFFER>
	JUMPE T,PSHIC2	;JUMP IF AT END OF BUFFER, DON'T NEED TO DO .ACCESS
	ADD E,T		;CALCULATE DESIRED WORD ADDRESS
	.ACCESS CHFILI,E	;CLOBBER TO DESIRED
PSHIC2:	MOVE E,PAGENU	;SAVE PAGENU AND LASTPA.
	LSH E,1
	SUB E,LASTPA	;LASTPA HOLDS 0 OR -1.
	LSH E,2
	TLNE FF,FLIN	;SAVE STATE OF FLIN TOO.
	 ADDI E,2
	HRRI A,1(E)	;LOW BIT SET SAYS INPUT CHNL.
	PUSHJ P,CHPSH	;DO THE PUSH
	JRST UICLS	;CLOBBER POINTERS AND RETURN

		;E] => POP INTO INPUT CHANNEL

POPIC:	TLZ FF,FLDIRDPY	;DON'T DISPLAY DIRECTORY.
	PUSHJ P,UICLS	;CLOBBER POINTERS FIRST
	MOVE CH,[TRNN T,CHFILI]	;TRNN SKIPS IF THIS RIGHT KIND OF PDL ENTRY, CHFILI CHANNEL TO POP INTO
	PUSHJ P,CHPOP	;POP INTO THE CHANNEL
	LDB CH,[020100,,A]
	MOVNM CH,LASTPA
	LDB CH,[031700,,A]
	MOVEM CH,PAGENU
	.STATUS CHFILI,CH	;GET CHANNEL STATUS
	TRNE CH,77	;IF NO DEVICE OPEN NOW
	 TRNN A,2	;OR NONE WAS OPEN THEN,
	  JRST UTLSTP	;SAY WE'RE AT END OF FILE (MUST ALWAYS SAY THAT IF FLIN OFF)
	TLO FF,FLIN	;OTHERWISE, SAY A FILE IS OPEN
	CALL UTRLD2	;RE-FILL INPUT BUFFER.
	HRRI A,UTIBUF	;CONVERT BACK TO BYTE POINTER
	DBP7 A		;DECREMENT TO GET RELOCATED ORIGINAL POINTER.
	MOVEM A,UTYIP	;STORE AS POINTER
	JRST RREDGN	;DO RFNAME; SET UP ERDEV, ERSNM, RUTF1, RUTF2.

		;CHECK THE VALIDITY OF THE INPUT FILE OPEN ON CHANNEL SPECIFIED BY CH

PSHCK:	HRRZ A,CH	;GET CHANNEL
	.CALL RFACCB
	 TYPRE [NRA]
	RET

RFACCB:	SETZ ? 'RFPNTR ? A ? MOVEM E ((SETZ))

		;E\ => PUSH OUTPUT CHANNEL

PSHOC:	TLZ FF,FLDIRDPY	;DON'T TRY TO CONTROL U
	CALL FLSOUT	;FORCE OUT BUFFER, EXCEPT 1 WD (LEFT IN 1ST WD OF BUFFER)
	MOVE B,UTYOP	;GET B.P. TO SHIFT POS. FIELD INTO A.
	IBP B		;GET BP TO PLACE NEXT CHAR GOES (RH = UTOBUF).
	LDB A,[73500,,UTOBUF]	;GET 1ST 4 CHRS FROM THAT WD
		;(5TH CAN'T BE USED, SINCE FLSOUT WOULD HAVE OUTPUT THE WD)
	LSHC A,7	;LEFT-JUSTIFY CHARACTERS AND SHIFT MEAT OF BYTE POINTER IN, LEAVE BIT 1.1 BLANK (=> OUTPUT)
	MOVEI CH,CHFILO	;PUT CHANNEL SPECIFICATION IN CH
	PUSHJ P,CHPSH	;PUSH THE CHANNEL (ALSO PUSH A ONTO LOCAL PDL)
	TLZ FF,FLOUT
	RET		;CLOBBER BUFFER POINTERS AND RETURN

		;E^ => POP INTO OUTPUT CHANNEL

POPOC:	TLZ FF,FLDIRDPY\FLOUT	;DON'T TRY TO CONTROL U
	MOVE CH,[TRNE T,CHFILO]	;GET CHANNEL AND TEST INSTRUCTION IN T (INSTRUCTION SKIPS IF THIS RIGHT PDL ENTRY)
	PUSHJ P,CHPOP	;POP INTO THE CHANNEL
	.STATUS CHFILO,C
	TRNN C,77
	 POPJ P,	;POPPED AN UNOPENED CHANNEL.
	MOVEM A,UTOBUF	;STORE BACK PARTIALLY FILLED WORD
	MOVE C,[700,,UTOBUF]	;GET BYTE POINTER LESS POSITION FIELD IN C
	DPB A,[350700,,C]	;DEPOSIT POS FIELD + EXTRA LOW BIT
	DBP7 C
	MOVEM C,UTYOP	;STORE BACK NEW POINTER
	ANDI A,177	;MASK A TO POSITION FIELD_1
	IDIVI A,7_1	;GET # CHARACTERS STILL TO BE PROCESSED THIS WORD - 1 IN A
	ADDI A,<UTOBE-UTOBUF>*5-4	;CONVERT TO NUMBER OF CHARACTERS YET TO OUTPUT
	MOVNM A,UTYOCT	;STORE AS COUNT REMAINING
	TLO FF,FLOUT	;FILE OPEN
	RET

		;PUSH THE IO CHANNEL SPECIFIED BY CH

CHPSH:	MOVE C,IOP	;GET IO PDL POINTER
	PUSHJ P,CHPSH1	;DO THE PUSH
	MOVEM C,IOP	;STORE BACK UPDATED POINTER
	POPJ P,

CHPSH1:	PUSH C,A
	MOVE Q,[.IOPUS]
	DPB CH,[270400,,Q]
	XCT Q
	POPJ P,

CHPOP2:	MOVE Q,[.IOPOP]
	DPB E,[270400,,Q]
	XCT Q
	RET

		;IO POP INTO THE CHANNEL SPECIFIED BY CH

CHPOP:	HLLM CH,CHPOPX	;STORE VALIDITY CHECKING INSTRUCTION
	HRRM CH,GCHN2	;STORE CHANNEL IN CHANNEL SEARCH ROUTINE (MAKE IT SKIP OVER IT)
	MOVEI E,17	;SET FIRST CHANEL FOR GCHN TO TRY
	MOVE C,IOP	;GET IO PDL POINTER
	HRRZ A,C	;GET RH IN A
	MOVE B,[TYPRE [NOP]
]			;NOT ON PDL: EXECUTED IF SPECIFIED TYPE OF CHANNEL HASN'T BEEN PUSHED
	PUSHJ P,CHPOP1	;DO THE POP
	XCT B		;LOST, DO THE APPROPRIATE THING
	MOVEM C,IOP	;STORE BACK UPDATED POINTER
	MOVE A,B	;PUT RETURN LOCAL PDL WORD IN A FOR ROUTINE THAT CALLED THIS ONE
	MOVE CH,E	;RESTORE CH FOR CALLING ROUTINE
	POPJ P,

		;ENTRY ON TOP OF PDL WRONG TYPE, POP IT SOMEWHERE ELSE, RECURSE, THEN PUSH IT BACK

CHPOP3:	PUSH P,T	;SAVE LOCAL DESCRIPTOR WORD ON MAIN PDL
	PUSHJ P,GCHN	;GET A FREE CHANNEL TO POP INTO
	 JRST POPAJ	;NO CHANNELS AVAILABLE
	PUSHJ P,CHPOP2	;POP INTO CHANNEL
	HRLM E,-1(P)	;SAVE CHANNEL NUMBER POPPED INTO
	PUSHJ P,[SOJA A,CHPOP1]	;TRY AGAIN ON ORIGINAL TASK
	SOS -1(P)	;LOSE, CAUSE RETURN NOT TO SKIP
	HLRZ CH,-1(P)	;RESTORE CHANNEL NUMBER, THIS TIME IN CH FOR PUSH BACK
	POP P,A		;RESTORE LOCAL PDL ENTRY, BUT IN A
	AOS (P)		;CAUSE RETURN TO SKIP
	JRST CHPSH1	;PUSH BACK CHANNEL AND RETURN


CHPOP1:	CAIGE A,IOPDL	;IF A DOESN'T POINT INTO PDL,
	 RET		;THEN NOT ON PDL , UNSCREW PDL AND DO TYPRE [NOP]
	POP C,T		;POP LOCAL PDL ENTRY INTO T
	XCT CHPOPX	;SKIP IF THIS THE RIGHT KIND OF PDL ENTRY
	 JRST CHPOP3	;WRONG KIND OF ENTRY, POP IT SOMEWHERE ELSE, RECURSE, THEN PUSH IT BACK
	MOVE E,CH	;RIGHT KIND OF ENTRY, SAVE ORIGINAL CHANNEL SPECIFICATION IN E
	MOVE B,T	;WIN, SAVE LOCAL PDL ENTRY FOR TOP LEVEL
	AOS (P)		;CAUSE RETURN TO SKIP
	JRST CHPOP2

		;FIND A FREE CHANNEL TO POP INTO

GCHN:			;GCHN NAME OF ENTRY TRANSFERED TO, GCHN2 NAME OF INSTRUCTION TO ADDRESS MODIFY
	XCT GCHN2		;RH MODIFIED, CHANNEL REALLY TRYING TO POP INTO SO LEAVE IT ALONE
	JRST GCHN3	;DON'T POP INTO THIS CHANNEL
	MOVE T,[.STATUS T]
	DPB E,[270400,,T]
	XCT T		;GET STATUS OF CHNL CONSIDERING POPPING INTO.
	TRNN T,77	;DEVICE OPEN ON CHANNEL?
	JRST POPJ1	;NO, RETURN WINNING
GCHN3:	SOJGE E,GCHN	;LOSE, TRY NEXT CHANNEL
	MOVE B,[TYPRE [NFC]
]			;NO FREE CHANNELS TO POP INTO
	POPJ P,		;NON-SKIP RETURN

EXITE:	HRLOI C,377777	;INFINITY
	TRO FF,FRARG
	MOVE E,BEGV	;PUNCH OUT IF BUFFER NONEMPTY
	CAMN E,ZV
	 SKIPE LASTPA	;OR AN INPUT FILE IS OPEN
	  PUSHJ P,PUNCHA
	CALL UICLS
	JRST EFCMD

;EF COMMAND - CLOSE OUTPUT FILE.
EFCMD:	PUSHJ P,FFRRDD	;READ FILENAMES TO CLOSE UNDER.
	TLNN FF,FLOUT
	 TYPRE [NDO]
	CAIA
EFCMDA:	 CALL UTYO		;PAD WITH THE CHARACTER IN FS FILEPAD TO WORD BNDRY.
	MOVE CH,UTYOP
	HRR CH,FILEPAD
	TLNE CH,760000
	 JRST EFCMDA
	CALL FLSOUT		;FORCE OUT THE BUFFER (INCL. PADDING).
	TRZE FF,FRCLN
	 JRST EFCMD2
	SYSCAL RENMWO,[%CLIMM,,CHFILO ? [440700,,DEFFIL]]	;GIVE FILE ITS ULTIMATE SPEC'D NAME.
	 JRST OPNER1
EFCMD2:	SYSCAL RFNAME,[%CLIMM,,%JSELF ? %CLIMM,,CHFILO
			[440700,,OUTFIL] ? %CLIMM,,FNMLEN*5]
	 .LOSE %LSFIL		;SET FS OFILE$ SO USER CAN FIND WHICH VERSION # IT WAS.
	.CLOSE CHFILO,
	TLZ FF,FLOUT
	POPJ P,

;EJ - OPEN FILE FOR READING AND LOAD IMPURE AREAS AS DUMPED IN FILE.
;TAKES A FILENAME ARGUMENT. DOES NOT ALTER THE DEFAULT SNAME.
;AFTER LOADING, TECO IS RESTARTED, WHICH MEANS M..L WILL BE DONE.
;@EJ - WRITE ALL IMPURE AREAS INTO A FILE OPEN FOR WRITING, AND
;FILE IT AWAY AS SPEC'D NAMES.

;FORMAT OF FILE:
;1ST WORD: SIXBIT/TECO/+1  (FOR ERROR CHECKING)
;2ND WORD: .FVERS OF TECO DOING THE DUMPING.
   ;PREVENTS TECOS FROM LOADING DUMP FILES OF OTHER VERSIONS.
;3RD WORD: JRST 1, AS REQUIRED TO MARK THE BEGINNING OF SBLK DATA IN A BIN FILE
;THEN COME SBLK DATA BLOCKS SPECIFYING RANGES OF CORE TO LOAD,
;AND THEN TWO COPIES OF THE START ADDRESS (BOOT).

;: EJ - OPEN FILE FOR READING AND MAP IT INTO CORE JUST UNDER LHIPAG.
;LHIPAG IS SET TO POINT AT THE BEGINNING OF THE FILE, AND A PURE
;STRING POINTER TO THE START OF THE FILE IS RETURNED. THIS COMMAND
;DOES NOT USE THE FILE FORMAT USED BY PLAIN EJ AND @EJ; IN FACT,
;THE FILE IS JUST A CORE IMAGE.

EJCMD:	TRZN FF,FRUPRW
	 JRST EJCMDR
	TLNN FF,FLOUT	;@EJ.
	 TYPRE [NDO]
	MOVE A,[-3,,[SIXBIT /TECO/+1
		     .FVERS
		     JRST 1]]
	.IOT CHFILO,A	;SAY THIS IS A TECO DUMP FILE, AND WHAT
			;TECO VERSION DUMPED IT.
	HRROI A,P
	JSP T,EJWBLK
	MOVE A,[20-HCDS,,20]
	JSP T,EJWBLK	;DUMP LOW IMPURE.
	MOVE A,[HCDSE-LIMPUR,,HCDSE]
	JSP T,EJWBLK	;EXCEPT FOR THE SCREEN-LINE HASH CODES.
	MOVE A,QRWRT
	ADDI A,4
	IDIVI A,5	;ADDR LAST WORD OF IMPURE STRING SPACE.
	SUBI A,HIMPUR	;LENGTH OF HIGH IMPURE.
	MOVNS A
	HRLZS A
	HRRI A,HIMPUR
	JSP T,EJWBLK	;DUMP OUT HIGH IMPURE.
	MOVE A,BFRBOT
	IDIVI A,5
	MOVE C,BFRTOP
	IDIVI C,5
	SUBM A,C	;-<LENGTH OF BUFFER SPACE>
	HRL A,C		;AOBJN TO BUFFER SPACE.
	JSP T,EJWBLK	;DUMP OUT BUFFER SPACE.
	HRROI A,[JRST BOOT]
	.IOT CHFILO,A	;OUTPUT THE STARTING ADDRESS
	MOVE TT,[-4,,2]	;OUTPUT AN INDIRECT SYMBOL TABLE POINTER BLOCK,
RADIX 10.
	MOVE A,[-4,,[SIXBIT /DSK/ ? SIXBIT /TECPUR/ ? SIXBNM \.FVERS
			SIXBIT /.TECO./]]
RADIX 8
	JSP T,EJWBL1	;WHICH NEEDS A CHECKSUM LIKE ALL OTHERS.
	HRROI A,[JRST BOOT]
	.IOT CHFILO,A	;AND THEN ANOTHER COPY, THUS MARKING OFF A NULL SYMBOL TABLE.
	JRST EFCMD	;RENAME AND CLOSE FILE.

;A HAS AOBJN POINTER TO RANGE OF DATA;  WRITE AN SBLK DESCRIBING IT.
EJWBLK:	MOVE TT,A
;HERE IF TT CONTAINS BLOCK HEADER, DISTINCT FROM THE POINTER TO THE DATA.
EJWBL1:	HRROI C,TT	;FIRST WE NEED TO WRITE THE AOBJN ITSELF.
	.IOT CHFILO,C
	.IOT CHFILO,A	;THEN WRITE THE DATA IN THAT RANGE.
	MOVE TT1,TT	;THEN COMPUTE THE CHECKSUM IN TT, INCLUDING THE AOBJN WORD
	ROT TT,1
	ADD TT,(TT1)	;AND THEN THE DATA WORDS.
	AOBJN TT1,.-2
	HRROI C,TT
	.IOT CHFILO,C	;OUTPUT THE CHECKSUM.
	JRST (T)

;EJ AND :EJ COMMANDS (THE INPUT VERSIONS OF EJ).
EJCMDR:	TRZ FF,FRARG	;DON'T PASS ANY ARG TO .OPNRD;  USE BLOCK ASCII MODE ALWAYS.
	CALL .OPNRD	;READ FILE SPEC & OPEN FILE
	TRZN FF,FRCLN	;:EJ?
	 JRST EJCMD2
	SYSCAL FILLEN,[%CLIMM,,CHFILI ? %CLOUT,,A]
	 JRST OPNER1
	ADDI A,1777	;HOW MANY PAGES LONG IS THE FILE?
	LSH A,-10.
	MOVNS C,A
	ADD C,LHIPAG	;IF IT WILL END JUST BELOW LHIPAG, WHERE SHOULD IT START?
	CAMG C,MEMT	;LEAVE AT LEAST ONE EMPTY PAGE ABOVE BUFFER SPACE.
	 CALL [	CALL FLSCOR	;NO ROOM - CAN WE FLUSH SOME WASTAGE FROM BUFFER SPACE?
		CAMG C,MEMT
		 TYPRE [URK]	;NO, THERE'S REALLY NO ROOM.
		RET]
	HRL C,A
	SYSCAL CORBLK,[%CLIMM,,200000 ? %CLIMM,,%JSELF ? C ? %CLIMM,,CHFILI]
	 JRST OPNER1
	CALL UICLS	;ALL PAGES MAPPED; DON'T NEED THE FILE NOW.
	ADDB A,LHIPAG	;ADJUST LHIPAG FOR PAGES WE HAVE GOBBLED.
	IMULI A,5*2000
	TLO A,400000	;RETURN A STRING POINTER TO BOTTOM OF FILE.
	JRST POPJ1

EJCMD2:	MOVE A,[-3,,C]	;ORDINARY "EJ".  CHECK FIRST 3 WORDS OF FILE.
	.IOT CHFILI,A	.SEE IDIVI	;CONSECUTIVE AC'S USED HERE.
	CAMN C,[SIXBIT/TECO/+1]
	 CAME D,[.FVERS] ;DUMPED BY DIFFERENT TECO VERSION,
	  TYPRE [AOR]	;OR NOT A TECO DUMP FILE.
	CAME E,[JRST 1]
	 TYPRE [AOR]
	.SUSET [.SMSK2,,[0]] ;INTERRUPT MIGHT DO TTYSET FROM NEWLY CLOBBERED VARS.
	MOVE E,LHIPAG	;SINCE WE AREN'T OVERWRITING PURE STRING SPACE
			;MUSTN'T FORGET WHERE IT STARTS.
	MOVE D,MSNAME	;ALSO DON'T CLOBBER MSNAME.
	MOVE T,MEMT	;.IOT'S CAN MAKE MEMORY BUT CAN'T FLUSH ANY.
	MOVE J,INITFL
EJCMD1:	HRROI A,C
	.IOT CHFILI,A	;READ NEXT BLOCK HEADER
	JUMPGE C,EJCMD3	;POSITIVE => END OF BLOCK DATA;  RESTART TECO, RUNNING Q..L.
	.IOT CHFILI,C	;LOAD DATA OF BLOCK,
EJCMD4:	HRROI A,C	.SEE TSINT4	;MPV HERE OK EVEN IF BELOW QRWRT.
	.IOT CHFILI,A	;SKIP THE CHECKSUM.
	JRST EJCMD1	;READ NEXT BLOCK.

EJCMD3:	MOVEM E,LHIPAG
	INSIRP MOVEM D,MSNAME
	MOVE A,D		;CONVERT MSNAME FROM SIXBIT TO ASCII IN BAKTAB.
	MOVE D,[440700,,BAKTAB]
	CALL STRGE1
	MOVEI C,";		;ADD SEMICOLON, AND NULL TO TERMINATE ASCIZ.
	IDPB C,D
	SETZ C,
	IDPB C,D
	MOVE D,[440700,,BAKTAB]
	CALL FFMRG		;USE THAT TO SET THE DEFAULTS.
	MOVE A,[TMPFIL,,DEFFIL]
	BLT A,DEFFIL+FNMLEN-1
	CAMLE T,MEMT
	 MOVEM T,MEMT
	MOVEM J,INITFL	;FS LISPT$ SHOULD NOT BE CHANGED BY AN EJ.
	.I SAVCMX=CBMAX=1
	.CLOSE CHFILI,
	JRST INIT

RENAM:	PUSHJ P,FFRRDD
	PUSHJ P,FRD
	CALL IMMQIT
	SYSCAL RENAME,[[440700,,DEFFIL] ? [440700,,TMPFIL]]
	 JRST OPNER1
	MOVE A,[TMPFIL,,DEFFIL]
	BLT A,TMPFIL+FNMLEN-1
	JRST DELQIT

;RETURN -1 IF CURRENT INPUT FILE WAS REACHED VIA LINKS WHEN OPENED.
FSIFLN:	SYSCAL LNKEDP,[%CLIMM,,CHFILI ? %CLOUT,,A]
	 SETZ A,
	JUMPN A,NRETM1
	JRST NRET0

ALINK:	PUSHJ P,FFRRDD	;GET LINK NAME
	CAME A,[SIXBIT/>/]
	CAMN B,[SIXBIT/>/]
	 JRST ALINK1	;MAKING LINK FROM FOO > WON'T DELETE ANYTHING.
	MOVEI A,CHRAND
	CALL IMMQIT
	.CALL RREDB	;ELSE SEE IF ANY FILE WITH THAT NAME.
	 JRST ALINK1
	MOVEI CH,%EEXFL	;GET ERROR CODE FOR "FILE ALREADY EXISTS",
	JRST OPNER4	;SIGNAL AN ERROR WITH MESSAGE READ FROM SYSTEM.

ALINK1:	SETZM IMQUIT
	CALL FRD		;READ NAMES LINKED TO.
	MOVE A,[TMPFIL,,TMPF1]
	BLT A,TMPF1+FNMLEN-1
	MOVE A,TMPF1		;COPY THEM INTO TMPF1.
	AND A,[.BYTE 7 ? 177 ? 177 ? 177 ? 177]
	SETZ D,			;IF DEVICE IS SYS: OR COM:, CHANGE DIR TO
	CAMN A,[ASCIZ /COM:/]	;SYS; OR COMMON; BEFORE TRYING TO MAKE THE LINK.
	 MOVE D,[440700,,[ASCIZ /DSK: COMMON;/]]
	CAMN A,[ASCIZ /SYS:/]
	 MOVE D,[440700,,[ASCIZ /DSK: SYS;/]]
	MOVE C,[440700,,TMPF1]
	SKIPE B
	 CALL FFMRG1
	CALL IMMQIT
	SYSCAL MLINK,[[440700,,DEFFIL] ? [440700,,TMPFIL]]
	 JRST OPNER1
	JRST DELQIT

UNREAP==2

;READ OR WRITE DON'T-REAP BIT OF FILE OPEN ON CHANNEL IN LH(E).
FSREAP:	HLRZS E
	SYSCAL FILBLK,[E ? %CLOUT,,A ? %CLOUT,,A ? %CLOUT,,A]
	 JRST OPNER1
	LDB A,[.BP (UNREAP),A]
	MOVE B,['SREAPB]
	JRST FSREA1

;READ OR WRITE DUMPED BIT OF FILE OPEN ON CHANNEL IN LH(E).
FSDUMP:	HLRZS E
	SYSCAL RDMPBT,[E ? %CLOUT,,A]
	 JRST OPNER1
	MOVE B,['SDMPBT]
FSREA1:	TRZN FF,FRARG
	 JRST POPJ1
	SYSCAL CALL,[B ? E ? C]
	 JRST OPNER1
	JRST POPJ1

WWINIT:	CALL FFRRDD	;Set default filenames.
EICMD:
WINIT:	MOVE A,[DEFFIL,,TMPFIL]
	BLT A,TMPFIL+FNMLEN-1
	TRZE FF,FRCLN	;:EW, :EI USE SPEC'D NAMES TO OPEN AS,
	 JRST WINIT1
	MOVE D,[440700,,[ASCIZ /_TECO_ OUTPUT/]]
	CALL FFMRG
WINIT1:	TLZ FF,FLOUT
	CALL IMMQIT
	HRLI T,100000\.BAO	;@EW OPENS IN WRITE-OVER MODE.
	TRZN FF,FRUPRW
WINIT2:	 HRLI T,.BAO	;OTHERWISE, USE NORMAL WRITE.
	HRRI T,CHFILO
	SYSCAL SOPEN,[T ? [440700,,TMPFIL]]
	 JRST WINIT3
	SETZM IMQUIT
	JSP T,FHAK	;INIT. BUFFER POINTERS.
	TLO FF,FLOUT
	POPJ P,

WINIT3:	TLNN T,100000
	  JRST OPNER1
	.STATUS CHFILO,D	;IF WRITE-OVER OPEN FAILS FOR "FILE NOT FOUND"
	LDB D,[220600,,D]
	CAIN D,%ENSFL	
	 JRST WINIT2		;THEN USE NORMAL WRITE OPEN INSTEAD.
	JRST OPNER1

FHAK:	TLO FF,FLOUT
	MOVE CH,[10700,,UTOBUF-1]
	MOVEM CH,UTYOP
	MOVNI CH,<UTOBE-UTOBUF>*5
	MOVEM CH,UTYOCT
	JRST 1(T)

;DO .MTAPE ON CHANNEL IN E, WITH ARGS IN C AND SARG.
FSMTAP:	HRLZS E
	HRRI E,C	;E GETS CHANNEL,,ADDRESS
	HRL C,SARG	;LH(C) GETS COUNT (DEFAULT IS 1).
	TRNN FF,FRARG2
	 HRLI C,1
	.MTAPE E,
	 JFCL
	MOVE A,C
	JRST POPJ1

DELE:	TRZE FF,FRCLN
	 JRST DELE1		; :ED IS DELETE INPUT FILE.
	PUSHJ P,FFRRDD
	SYSCAL DELETE,[[440700,,DEFFIL]]
	 JRST OPNER1
	POPJ P,

DELE1:	TLZN FF,FLIN
	 TYPRE [NFI]
	SYSCAL DELEWO,[%CLIMM,,CHFILI]
	 .LOSE %LSFIL
	POPJ P,

LISTF:	CALL FFRRDD	;EY COMMAND - READ DEV NAME.
CNTRU1:	CALL VBDACU	;IF THERE'S A CMD STRING PENDING,
	 RET		;DON'T BOTHER OPENING THE DIR.
	SETZ CH,
	CALL DISINI
	SKIPA OUT,[CHCT]
LISTFM:	 MOVEI OUT,TYOM	;EZ AND EM COMMANDS.
	TRNE CH,20
	 CALL FFRRDD
	TLZ FF,FLDIRDPY
	HRRM OUT,LISTF5
	CALL AOFDIR
LISTF2:	HRRZ OUT,LISTF5
	CALL GFDBLK
	CAIN OUT,TYOM	;IF DUMPING CRUD INTO BUFFER,
	 JRST LSTF3	;THEN DO IT FAST
LISTF6:	ILDB CH,FDRP
	CAIE CH,EOFCHR
	 CAIN CH,14
	  JRST LISTF%
	CALL @LISTF5
	JRST LISTF6

LSTF3:	ANDI CH,-1
	CAIE CH,FDRBUF	;DONT ALLOW TO BACK UP BEFORE BEGINNING
	 SUBI CH,1	;BACK UP TO LAST WORD .IOT'ED INTO
	CAIE CH,FDRBUF	;IF NOT POINTING TO BEGINNING OF BUFFER,
	 SUBI CH,1	;THEN BACK UP A WORD FOR "FORM FEED AT END OF LAST WORD" SCREW
	MOVEI E,-FDRBUF(CH)	;GET INDEX INTO BUFFER IN E
	IMULI E,5	;CONVERT E TO NUMBER OF CHARACTERS UP TO THIS WORD
	HRLI CH,440700	;CONVERT TO BYTE POINTER TO WORD
LSTF4:	ILDB A,CH	;GET CHARACTER FROM LAST WORD (DOES THIS LOOK BACKWARDS TO YOU?)
	CAIE A,14	;IF FORM FEED,
	 CAIN A,EOFCHR	;OR IF EOF CHARACTER,
	  JRST .+2	;THEN FOUND END
	   AOJA E,LSTF4	;HAVEN'T FOUND END YET, LOOP BACK
	JUMPE E,CPOPJ	;IF NO CHARACTERS THEN THAT'S ALL FOR THIS ROUTINE
	MOVEI C,(E)
	CALL SLPGET	;INSERT THAT MANY CHARS, GET IDPB BP IN BP.
	ILDB CH,FDRP	;NOW GET CHARACTER TO COPY
	IDPB CH,BP	;COPY IT
	SOJG E,.-2	;DO IT THE APPROPRIATE NUMBER OF TIMES
	IBP FDRP	;INCREMENT FDRP TO MAKE IT APPEAR THAT THE ACTUAL EOF CHARACTER WAS ENCOUNTERED

		;PROCESS THE NEXT BLOCK OF THE FILE DIRECTORY BEING LISTED

LISTF%:	SKIPN MORFLF
	 JRST LSTF%2
	HRRZ A,LISTF5	;USER HAS "FLUSHED", SEE IF TYPING OUT
	CAIN A,CHCT
	 JRST LSTF%3	;TYPING OUT, STOP NOW
LSTF%2:	HRRZ CH,FDRP
	CAIN CH,FDRBFE
	 JRST LISTF2	;MORE TO COME
LSTF%3:	.CLOSE CHRAND,
	HRRZ A,LISTF5
	CAIN A,CHCT
	 JRST DISCLG
	POPJ P,

IFN 0,%%TNX%:
]	;END IFN ITS CONDTIONAL

SUBTTL TWENEX FILE COMMANDS

IFN TNX,[.SEE %%TNX.	;END OF THIS CONDITIONAL

ASLEEP:	TRZN FF,FRARG
	 SETZ C,
	LSH C,5		;CONVERT 30THS OF A SECONDS TO MS (MORE OR LESS)
	TRZE FF,FRCLN	;:^S?
	 JRST ASLEE1	;YES
	CALL IMMQIT	;SLEEP FOR N 30TH'S OF A SECOND
	MOVE A,C
	DISMS
	JRST DELQIT

ASLEE1:	JUMPE C,FSLISN	;0:^S IS JUST LIKE FSLISTEN$, SO SAVE TIME THAT ATI, DTI WOULD TAKE.
	CALL IMMQIT	;ELSE SLEEP FOR N 30TH'S OF A SECOND
ASLEE5:	MOVEI B,1
	SKIPGE UNRCHC
	 SKIPE TYISRC	;IF WE ALREADY KNOW THE ANSWER,
	  JRST ASLEE4	;DON'T WASTE TIME ENABLING INTERRUPT.
	MOVEI A,.PRIIN
	SIBE		;NO SKIP => SETS B TO # CHARS AVAILABLE.
	 JRST ASLEE4
IFN 20X,[
	MOVE A,[.TICTI,,1]
	ATI		;ASSIGN ANY TYPEIN TO CHANNEL 1
	MOVE A,C
	DISMS		;SLEEP OR GET AWAKENED
	SETZ B,		;RETURN 0
	JRST ASLEE3
	
ASLEE2:	CIS		;FLUSH INTERRUPTS
	MOVEI A,.PRIIN
	SIBE		;RETURN FS LISTEN
	 CAIA
	 SETZ B,	;NOTHING WAITING
ASLEE3:	MOVEI A,.TICTI	;UNARM ANY INPUT INTERRUPT
	DTI
]
.ELSE	[
	CAIGE C,50.	;TENEX DOESNT HAVE TYPEIN INTERRUPT, SO TAKE 50. MS NAPS
	 SKIPA A,C	;LESS THAN INCREMENT, SLEEP FOR REMAINDER
	 MOVEI A,50.	;ELSE JUST FOR 50.
	DISMS
	SUBI C,50.
	JUMPG C,ASLEE5	;STILL TIME TO GO
	SETZ B,		;TIME RAN OUT, RETURN 0
]
ASLEE4:	SETZM IMQUIT
	MOVE A,B
	JRST CPOPJ1

EQMRK:	MOVSI A,(GJ%OLD)
	CALL FRD	;E? RETURN 0 IF FILE EXISTS
	 JRST CPOPJ1	;IT DOESNT, JUST RETURN ERROR CODE THEN
IFN 10X\FNX,[
	MOVE B,[1,,.FBCTL]
	MOVEI C,D
	GTFDB
];IFN 10X\FNX
	RLJFN		;GET RID OF THE JFN
	 JFCL
IFN 10X\FNX,[
	TLNN D,(FB%NXF)		;FILE DOES NOT EXIST?
	 TDZA A,A		;IT DOES, RETURN SUCCESS
	 MOVEI A,OPNX2
];IFN 10X\FNX
.ELSE	SETZ A,		;RETURN 0 FOR SUCCESS
	JRST CPOPJ1

IFN 10X,[			;STUPID TENICES CANT STANDARDIZE THIS
IF1 [
PRINTX \IIT JSYS TYPE (0 - NONE, 1 - BBN, 2 - SUMEX): \
.TTYMAC FOO
.IIT==FOO
TERMIN
]]
IFN FNX,.IIT==2
IFNDEF .IIT,.IIT==0
IFE .IIT-1,IIT=JSYS 247		;NOT EVEN THE SAME JSYS NUMBER
IFE .IIT-2,IIT=JSYS 630

;FS CLK INTERVAL$ - SET REAL TIME CLOCK INTERVAL IN 60THS OF SECONDS.  VALUE SAVED IN CLKINT.
FSCLKI:	TRNN FF,FRARG
	 JRST FSNORM
FSCLK0:	SAVE C		;PRESERVE ARG.
IFN 20X,[
	MOVE A,[.FHSLF,,.TIMAL]	;DELETE ALL TIMERS FOR THIS FORK
	MOVEI C,3	;LOSING SYSTEM CHECKS CHANNEL EVEN WHEN NOT USED FOR ANYTHING
	TIMER
]
IFE .IIT-1,[
	MOVE A,[100000,,.FHSLF]	;DELETE ALL BEFORE THIS TIME
	HRLOI B,377777	;INFINITY
	IIT
]
	 JFCL		;IGNORE ERRORS
	REST C
	SAVE CLKINT	;GET OLD SETTING, TO RETURN IT.
	MOVEM C,CLKINT
	CALL FSCLK2	;SET UP NEXT INTERRUPT, IF DESIRED.
	REST A
	JRST POPJ1	;RETURN VALUE.

FSCLK2:	SKIPN B,CLKINT	;GET LENGTH OF REAL-TIME INTERVAL
	 RET		;NO MORE TO DO IF 0
	LSH B,4		;CONVERT TO MSEC, APPROXIMATELY.
IFN 20X,[
	MOVE A,[.FHSLF,,.TIMEL]	;SET ELAPSED TIME
	MOVEI C,3	;ON CHANNEL 3
	TIMER
]
IFE .IIT-1,[
	MOVE A,[400000,,.FHSLF]
	IIT
]
IFE .IIT-2,[
	MOVE C,B		;NUMBER OF MS UNTIL TIME
	MOVEI A,.FHSLF
	MOVSI B,10		;ON CHAN 14.
	IIT
]
	 JFCL		;IGNORE ERROR HERE AS WELL
	RET

TSINTC:	SETOM CLKFLG	;REAL-TIME INTERRUPT, SAY IT IS TIME TO RUN HANDLER
INSIRP	PUSH P,A B C
	HRRZ A,INTPC2	;GET WHERE INTERRUPT CAME FROM
	CAIN A,TYIIOT	;WAITING FOR INPUT?
	 CALL [	SUBI A,1	;YES, RUN THE HANDLER NOW, BUT IN CASE AN ERRSET GOES OFF
		MOVEM A,INTPC2	;DURING THE MACRO EXECUTION, ENSURE WE RESTART THE PBIN
		JRST RLTCLK]	;AND DONT EVER FALL THROUGH WITH GARBAGE USER DIDNT TYPE
	CALL FSCLK2	;SETUP NEW TIMER FOR NEXT TIME
INSIRP	POP P,C B A
	DEBRK
IFN 20X\FNX, ERJMP .+1
	JRST @INTPC2

EGET:	SAVE LISTF5	;EG - INSERT STUFF INTO BUFFER
	MOVEI A,TYOM
	HRRM A,LISTF5
	CALL GAPSLP
	TLZ FF,FLDIRDPY
	HRROI A,BAKTAB
	SETO B,	;CURRENT TIME
	MOVSI C,(OT%NMN\OT%DAM)
	ODTIM
	MOVE A,[350700,,BAKTAB+1]
	MOVEI C,1
	CALL EGETYP
	MOVE A,[440700,,BAKTAB]
	MOVEI C,2
	CALL EGETYP
	CALL CRR1
	MOVE A,[100700,,BAKTAB+1]
	MOVEI C,3
	CALL EGETYP
	CALL CRR1
	GJINF		;CONNECTED DIRECTORY
	HRROI A,BAKTAB
	DIRST
	 SETZM BAKTAB
	MOVEI A,BAKTAB
	CALL ASCIND
	CALL CRR1
	MOVEI E,DEFDEV
	CALL FSDFR1	;INSERT CURRENT FILENAME DEFAULTS
	CALL CRR1
	TLNN FF,FLIN	;HAVE AN OPEN INPUT FILE?
	 JRST EGET2
	MOVEI E,ERDEV	;YES, INSERT IT'S REAL NAME
	CALL FSDFR1
EGET2:	CALL CRR1
	HRROI A,BAKTAB	;CURRENT DATE IN ENGLISH FORMAT
	SETO B,
	MOVSI C,(OT%DAY\OT%FDY\OT%4YR\OT%DAM\OT%SPA\OT%NTM\OT%SCL)
	ODTIM		;"MONDAY, NOV 28 1977"
	MOVE A,[440700,,BAKTAB]
	MOVEI C,3	;REPLACE THIRD SPACE WITH COMMA
	ILDB B,A
	CAIE B,40
	 JRST .-2
	SOJG C,.-3
	MOVEI B,",
	DPB B,A
	MOVEI A,BAKTAB
	CALL ASCIND
	CALL CRR1
	CALL CRR1
	CALL POM	;THE PHASE OF THE MOON (CLOSE)
	CALL CRR1
	REST LISTF5	;RESTORE THINGS
	RET

EGETYP:	ILDB CH,A	;INSERT 2 CHARS AND THEN FLUSH THE NEXT ONE C TIMES
	CAIN CH,40
	 MOVEI CH,"0
	XCT LISTF5
	ILDB CH,A
	XCT LISTF5
	SOJLE C,CPOPJ
	IBP A
	JRST EGETYP

;TYPE OUT PHASE OF THE MOON
POM:	GTAD
	SUB A,SYNOFS			;OFFSET TO NEAREST NEW MOON TO DAY 0
	IDIV A,SYNP			;DIVIDE INTO QUARTER PERIODS
	ANDI A,3			;GET PERIOD
	MOVEI A,PHSNMS(A)
	CALL ASCIND			;TYPE ITS NAME
	MULI B,24.*60.*60.		;CONVERT TO SECONDS
	LSH C,1				;FLUSH DUPLICATE SIGN BIT
	LSHC B,17.			;GET ONE WORD PRODUCT
	MOVEI E,TDHMST
TDHMS1:	IDIVI B,@(E)
	JUMPE B,TDHMS2
	HRLM C,(P)
	CALL [AOJA E,TDHMS1]		;INCREMENT AND RECURSE
	HLRZ C,(P)
TDHMS2:	CALL DPT			;TYPE IN IN DECIMAL
	HLLZ A,(E)
	SOJA E,SIXIN1			;BACK UP, TYPE AND RETURN
; USE SOME OTHER OUTPUT ROUTINE, SUCH AS SIXNTY OR ASCIND.

PHSNMS:	ASCII /NM+/
	ASCII /FQ+/
	ASCII /FM+/
	ASCII /LQ+/

TDHMST:	SIXBIT /S./+60.
	SIXBIT /M./+60.
	SIXBIT /H./+24.
	SIXBIT /D./+<,-1>

SYNP:	<29.53059&<777,,-1>>_-6		;LENGTH OF QUARTER IN GTAD UNITS
SYNOFS:	22,,253553			;18 DAYS AND A BIT

FRDOLD:	MOVSI A,(GJ%OLD)	;INSIST ON OLD FILE
	CALL FRD
	 JRST OPNER1	;DOESNT EXIST, ERROR
IFN 10X\FNX,[		;THIS IS EXTREMELY DISTASTEFUL
	SKIPN DEFFN2	;IS THERE SUPPOSED TO BE AN EXTENSION?
	 RET		;NO, OK THEN
	MOVE B,A	;YES, WE MUST CHECK FOR A GROSS MISFEATURE IN THE TENEX FILESYSTEM,
	HRROI A,BAKTAB	;WHEREBY IF FILE WITH DEFAULT FN2 DOES NOT EXIST BUT A FILE WITH A NULL
	MOVSI C,000200	;FN2 DOES, IT WILL STILL BE FOUND
	JFNS		;SEE WHAT THE EXTENSION OF THE FILE WE GOT IS
	MOVE A,B
	LDB B,[350700,,BAKTAB]
	JUMPN B,CPOPJ	;NON-NULL, OK
	RLJFN		;FOO! WE HAVE BEEN SCREWED, GET RID OF LOSING JFN
	 JFCL
	MOVEI 2,GJFX19
	JRST OPNER4	;AND FAKE NO SUCH EXTENSION ERROR
]
.ELSE	RET

FRD0:	TDZA A,A
FRDFOU:	MOVSI A,(GJ%FOU)
; GET A JFN FROM A FOLLOWING STRING, USING THE CURRENT DEFAULTS
; TAKES GTJFN FLAGS IN 1 RETURNS +1 A/ ERROR CODE OR +2 A/ JFN
FRD:	CALL FFRRDD	;CONVERT STRING TO FILESPEC FORMAT
FF5:	SETZ B,
FF5A:	MOVE C,[.NULIO,,.NULIO]
	SETO D,		;USE ALL DEFAULT FIELDS
	CALL FF4
	MOVEI A,BAKTAB
	GTJFN
	 RET		;SINGLE RETURN
	JRST CPOPJ1	;SKIP RETURN WITH THE JFN

FFRRTS:	TRNN FF,FRARG		;:ET - GET FROM TTY IN ECHO AREA
	 TLZA A,-1
	 HRLZ A,C		;ANY ARGUMENT IS THE GTJFN FLAGS
IFN COMNDF,TLO A,(GJ%FLG)		;RETURN FLAGS AS WELL
.ELSE	TLO A,(GJ%FLG\GJ%CFM)	;ASSURE CONFIRMED
	SETZ B,			;NO STRING
	MOVE C,[.PRIIN,,.PRIOU]	;FROM TTY:
	MOVE D,ETMODE		;WITH FS :ET MODE MASK OF DEFAULTS TO USE
FF4:	MOVEM C,BAKTAB+.GJSRC
	TRNN D,1	;DEFAULT GENERATION NUMBER?
	 TRZA A,-1	;NO, USE 0 THEN
	 HRR A,DEFFN3	;GET DEFAULT GENERATION NUMBER
	TLO A,4		;SET GJ%XTN BIT ON.
	MOVEM A,BAKTAB+.GJGEN
.GJFN1==.GJNAM
.GJFN2==.GJEXT
IRPS STR,,[FN2 FN1 DIR DEV]
	ROT D,-1
	TRNE D,1	;DEFAULT THIS FIELD?
	 SKIPN DEF!STR	;AND HAVE A DEFAULT?
	 TDZA A,A	;NO OR NO
	 HRROI A,DEF!STR	;YES, GET IT
	MOVEM A,BAKTAB+.GJ!STR
TERMIN
	SETZM BAKTAB+.GJPRO	;CLEAR OUT THE REMAINDER OF THE BLOCK
	MOVE A,[BAKTAB+.GJPRO,,BAKTAB+.GJPRO+1]
IFN COMNDF,GTBEND==BAKTAB+.GJATR
.ELSE GTBEND==BAKTAB+.GJACT
	BLT A,GTBEND
	MOVE A,GJBITS	;GET GJ%XTN BITS
	MOVEM A,BAKTAB+.GJF2	;AND SAVE INTO LONG FORM JFN BLOCK
	SETZM GJBITS	;AND CLEAR FOR NEXT TIME...
	RET

;READ A FILESPEC, SETTING DEFAULTS FROM IT
FFRRDD:	SAVE A
	CALL MEMTOP		;GET A POINTER TO START OF FREE BUFFER SPACE
	HRLI A,440700		;MAKE IT A BYTE POINTER
	SAVE A			;SAVE IT FOR LATER
	SETZ B,			;RESET FLAGS
FFST0:	SETZB TT,(A)		;ZERO LAST CHARACTER INSERTED
	MOVSI C,(A)
	HRRI C,1(A)
	BLT C,17(A)		;AND AREA WE WILL BE INSERTING INTO
FFST1:	CALL RCH		;GET A CHARACTER
	SKIPGE SQUOTP		;SUPERQUOTED?
	 JRST FFSTQ1		;YES, INSERT IT QUOTED THEN
	CAIL CH,"a
	 CAILE CH,"z
	 CAIA
	 SUBI CH,"a-"A
	SKIPN SQUOTP		;NOT A TERMINATOR?
	 CAIE CH,33		;ELSE ALTMODE TERMINATES
	 CAIA
	 JRST FFST4
	TLNE B,040000		;PARSING DIRECTORY NAME?
	 JRST FFSTDR		;YES, INSERT IT THEN
	CAIE CH,^A
	 CAIN CH,^X		;WANTS FIRST NAME DEFAULT?
	 JRST FFSCTX
	CAIE CH,^B
	 CAIN CH,^Y		;WANTS SECOND NAME DEFAULT?
	 JRST FFSCTY
	CAIE CH,^V		;^V OR ...
	 CAIN CH,^Q		;^Q QUOTES ANOTHER CHARACTER
	 JRST FFSTQT
	CAIN CH,40		;TRANSLATE SPACE TO DOT
	 JRST FFSTSP
	CAIN CH,":		;END OF DEVICE NAME
	 JRST FFSTCL
	CAIN CH,"<		;MAYBE PART OF DIRECTORY
	 JRST FFSTLT
	CAIN CH,">		;DITTO
	 JRST FFSTGT
	CAIN CH,".		;NOTICE WHEN WE GET THE DOT
	 JRST FFSTDT
	CAIN CH,";		;MAYBE PART OF DIRECTORY FOR ITS
	 JRST FFSTSM
IFN 20X,[CAIE CH,"[		;THESE NEED TO BE QUOTED
	 CAIN CH,"]
]
.ELSE	CAIN CH,"_		;THIS NEEDS TO BE QUOTED ON TENEX
	 JRST FFSTQ2
	CAIE CH,"(
	 CAIN CH,")
	 JRST FFSTQ2
	CAIE CH,"@
	 CAIN CH,"^
	 JRST FFSTQ2
FFST2:	MOVEI TT,(CH)		;SAVE LAST CHAR INSERTED
FFST3:	IDPB CH,A		;STICK IT IN
	JRST FFST1		;AND GET ANOTHER CHAR

FFSTQT:	CALL RCH		;^Q QUOTES NEXT CHAR
FFSTQ1:	CAIL CH,"A		;DON'T NEED TO QUOTE UPPERCASE
	 CAILE CH,"Z
	 JRST FFSTQ2
	JRST FFST2

FFSTQ2:	MOVEI C,^V
	CAIE TT,^V		;UNLESS ^V WAS LAST TO GO IN
	 IDPB C,A		;INSERT ONE
	HRROI TT,(CH)		;SAY CHAR WAS QUOTED
	JRST FFST3		;AND INSERT IT

FFSTDR:	CAIE CH,">		;WAITING FOR DIRECTORY
	 JRST FFST2
	TLZ B,040000
FFSTB4:	
IFN EMCSDV\INFODV,[		;IF CERTAIN DIRECTORIES ARE SPECIAL
	MOVE C,DEFDEV		;THEY ARE SPECIAL ONLY IF NO DEVICE SPECIFIED, OR DSK:.
	TLNE B,010000		;DID USER SPECIFY DEVICE?
	 CAMN C,[ASCII/DSK/]	;YES.  DID SHE SPECIFY DSK:? (NECESSARY!!!)
	  SKIPA
	   JRST FFSTB5		;THE DIR NAME IS NOT SPECIAL.  SO FUNNY-STR:<EMACS> WORKS.
	HRRZ A,(P)		;GET ADDRESS OF STRING
	MOVE C,(A)		;AND FIRST WORD THEREOF
IFN EMCSDV,[
	CAMN C,[ASCII /EMACS/]	;STARTS WITH EMACS
	 SKIPE 1(A)		;AND ENDS RIGHT AWAY?
IFE INFODV,SKIPA
]
IFN INFODV,CAMN C,[ASCIZ /INFO/]
	JRST [	MOVEM C,DEFDEV	;MAKE THAT THE DEFAULT DEVICE AS WELL
		SETZM DEFDEV+1
		JRST FFSTB6]
FFSTB5:	SKIPE DEFDEV+1
	 JRST FFSTB6
	MOVE C,DEFDEV		;IF NEW DIRECTORY IS NOT A SPECIAL ONE,
	CAME C,[ASCII /INFO/]	;THEN IF THE DEVICE IS EMACS: OR INFO:
	 CAMN C,[ASCII /EMACS/]
	  TLNE B,010000		;AND WASN'T JUST SPECIFIED EXPLICITLY,
	   JRST FFSTB6
	MOVE C,[ASCIZ /DSK/]	;RESET IT TO DSK.
	MOVEM C,DEFDEV
] ;END EMCSDV\INFODV
FFSTB6:	SKIPA A,[DEFDIR]
FFSTB0:	 MOVEI A,DEFFN1
FFSTB1:	HRL A,(P)		;GET START OF WHERE IT IS
FFSTB2:	MOVEI C,17(A)		;GET END
	BLT A,(C)		;MOVE THE DEFAULT IN
FFSTB3:	MOVE A,(P)		;GET FRESH STRING POINTER
	JRST FFST0		;AND CONTINUE

FFSCTX:	SKIPA A,[DEFFN1,,0]	;INSERT DEFAULT FN1
FFSCTY:	 MOVSI A,DEFFN2		;INSERT FN2
	TLO B,400000		;THESE ARE ITS CONSTRUCTS
	JUMPE TT,FFSCT2		;UNLESS NOTHING SEEN YET,
	MOVEI C,DEFFN1		;SET UP WHAT WE HAVE AS FN1
	HRL C,(P)
	MOVEI CH,17(C)
	BLT C,(CH)
FFSCT2:	HRRI A,DEFFN1		;ASSUME SETTING FN1
	TLOE B,200000		;UNLESS DOT SEEN ALREADY
	 HRRI A,DEFFN2		;IN WHICH CASE, FN2
	JRST FFSTB2		;GO SET THEM AND CONTINUE

FFSTSP:	JUMPE TT,FFST1		;SPACE - IF NOTHING YET, FLUSH IT IN ALL CASES
	TLO B,400000		;ELSE IT IS ITS STYLE
	TLOE B,200000		;IF ALREADY HAVE A DOT,
	 JRST FFST1		;JUST FLUSH IT
	JRST FFSTB0		;ELSE GO SET FN1 FROM WHAT WE HAVE

FFSTCL:	HRRZ A,(P)		;: - GET FIRST WORD FOR DEVICE
	TLO B,010000		;USER SPECIFIED A DEVICE
	MOVE C,(A)
	MOVEM C,DEFDEV
	MOVE C,1(A)
	MOVEM C,DEFDEV+1
	JRST FFSTB3		;AND GO GET MORE

FFSTLT:	JUMPGE B,FFSTL2		;< - IF NOT ITS, MUST BE DIRECTORY
	SKIPA C,[.GJLEG]	;ELSE WANT OLDEST VERSION
FFSTGT:	 MOVEI C,.GJDEF		;> - WANT NEWEST VERSION
	MOVEM C,DEFFN3		;SET UP DEFAULT GEN NUMBER
	SETZM DEFFN2		;AND DEFAULT FN2 TO NULL
	TLOA B,320000		;BOTH NAMES SEEN
FFSTL2:	 TLO B,040000		;LOOK FOR DIRECTORY NAME
	JRST FFST1

FFSTDT:	JUMPL B,FFSTQ2		;QUOTE IT IF ITS STYLE
	TLOE B,200000		;ALREADY HAVE A DOT?
	 JRST FFSTD2		;YES, MUST BE END OF FN2 OR GENERATION NUMBER
	JUMPN TT,FFSTB0		;NON NULL STRING, MUST TERMINATE FN1
	TLO B,400000		;ELSE ITS STYLE,
	JRST FFSTQ2		;SO INSERT IT QUOTED
FFSTD2:	TLOE B,100000		;ALREADY HAVE BOTH DOTS?
	 JRST FFSTD3		;YES, MUST BE END OF GENERATION NUMBER THEN
	MOVEI A,DEFFN2		;ELSE, SET DEFAULT FN2
	JRST FFSTB1		;AND RETURN
FFSTD3:	TLOE B,020000		;EVERYTHING SEEN
	 JRST FFST1		;ALREADY ALL SEEN, FLUSH IT THEN
	CALL FFSGEN		;GET GENERATION NUMBER FROM STRING
	JRST FFSTB3		;AND RETURN

FFSTSM:	TLNE B,200000		;IF DOT SEEN ALREADY,
	 JRST FFSTD2		;TREAT IT AS A DOT NOW
	TLO B,400000		;ELSE, ITS'S ITS STYLE
	JRST FFSTB4		;AND THE DIRECTORY

FFST4:	POP P,A			;GET BACK STRING POINTER
	TLNE B,020000		;IF EVERYTHING SEEN ALREADY,
	 JRST POPAJ		;DONE
	TLNE B,300000		;IF EITHER FN1 OR FN2 SEEN,
	 SETZM DEFFN3		;RESET THE GENERATION NUMBER
	JUMPE TT,[TLNN B,100000
		   TLNN B,200000
		   JRST POPAJ	;NOT PARSING FN2, DONE
		  JRST FFST4B]
	TLNE B,040000		;IF WAITING FOR DIR,
	 JRST FFST4D		;FINISH IT UP
	TLNE B,100000		;IF PARSING GENERATION NUMBER
	 JRST FFST4G		;GO DO THAT
	TLNE B,200000		;IF PARSING FN2,
	 JRST FFST4B
	SKIPLE C,FNAMSY		;FS FNAM SYNTAX$ > 0 => DEFAULT FN1
	 JRST FFST4A		;GO SET FN1
	JUMPE C,FFST4B		;0 => GO SET FN2
	SETZM DEFFN2		;DEFAULT TO FOO..0
FFST4A:	SKIPA C,[DEFFN1]	;SETTING DEFFN1
FFST4B:	 MOVEI C,DEFFN2		;SETTING DEFFN2
FFST4C:	HRLI C,(A)		;SOURCE
	MOVEI A,17(C)
	BLT C,(A)		;SET IT UP
	JRST POPAJ		;AND RETURN
FFST4D:	MOVEI C,DEFDIR		;SETTING DIRECTORY
	JRST FFST4C
FFST4G:	CALL FFSGN0		;SET GENERATION NUMBER
	JRST POPAJ		;AND RETURN

FFSGEN:	MOVE A,-1(P)		;GET STARTING POINTER
FFSGN0:	SETZB TT,C		;INIT NUMBER
	ILDB CH,A		;PEEK FIRST CHAR
	CAIN CH,"*
	 JRST [	MOVNI TT,3
		JRST FFSGN4]
	CAIE CH,"-		;NEGATIVE?
	 JRST FFSGN2		;NO
	SETO C,			;SAY NEGATIVE NUMBER
FFSGN1:	ILDB CH,A		;GET CHARACTER
FFSGN2:	CAIL CH,"0
	 CAILE CH,"9
	 JRST FFSGN3
	IMULI TT,10.
	ADDI TT,-"0(CH)
	JRST FFSGN1
FFSGN3:	SKIPGE C		;NEGATIVE?
	 MOVNS TT		;YES
FFSGN4:	MOVEM TT,DEFFN3		;SET UP DEFAULT GEN NUMBER
	RET

;SET UP DEFAULTS FROM STRING FOLLOWING
ETCMD:	TRZN FF,FRCLN		;:ET?
	 JRST FFRRDD		;NO

FFRRTT:
IFE COMNDF,[
	TRZN FF,FRARG2		;WAS THERE A STRING TOO?
	 JRST FFRRT4		;NOPE
	MOVE CH,SARG		;YES, GET IT
	CALL FSECO1		;TYPE IT OUT IN THE ECHO AREA
FFRRT4:
];COMNDF
	CALL ECOPOS		;POSITION TO CURRENT PLACE IN ECHO AREA
	CALL DPYRSS		;RESET DISPLAY MODE
	MOVEI A,.CTTRM
	RFMOD
	SETOM IMQUIT		;ALLOW ^G'ING OUT OF GTJFN
	MOVEM B,SAVMOD		;SAVE TTY MODE (ALSO FOR ^G TO USE)
IFN 20X,[
	MOVE CH,RGETTY		;DON'T CHANGE MODES WITH VTS
	CAIN CH,VTSI	
	 JRST FFRRT0
]
	TRO B,1_6\TT%ECO	;MAKE SURE ECHO ON AND DATA MODE OK
	SFMOD
IFN 20X,[
	MOVE B,TTLPOS
	SFPOS			;MAKE SURE MONITOR KNOWS HORIZONTAL POSITION
	BKJFN
	 JRST FFRRT0
	BIN			;GET THE LAST CHARACTER TYPED
	CAIN B,15		;WAS IT CR?
	 BIN			;YES, READ LF TOO
FFRRT0:	];20X
	CALL FFRRTS		;SET UP BAKTAB AS GTJFN ARG BLOCK.
IFN COMNDF,[
CMDBF==GTBEND+1			;STATE BLOCK FOR COMND JSYS
CMDBFT==CMDBF+12		;TEXT BUFFER FOR COMND JSYS.  HOLDS 200. CHARS.
CMDBFA==CMDBFT+<200./5>		;ATOM BUFFER.  HOLDS 200. CHARS.
CMDRTY==CMDBFA+<200./5>		;PROMPT STRING
IFL BAKTAB+LTABS-CMDRTY-10,.ERR BAKTAB TOO SHORT
	MOVE A,[CM%XIF+FFRRTE]	;REPARSE ADDRESS
	MOVEM A,CMDBF+.CMFLG
	MOVE A,[.PRIIN,,.PRIOU]
	MOVEM A,CMDBF+.CMIOJ
	HRROI A,CMDBFT
	MOVEM A,CMDBF+.CMBFP
	MOVEM A,CMDBF+.CMPTR
	MOVEI A,200.
	MOVEM A,CMDBF+.CMCNT
	MOVEM A,CMDBF+.CMABC
	SETZM CMDBF+.CMINC
	HRROI A,CMDBFA
	MOVEM A,CMDBF+.CMABP
	MOVEI A,BAKTAB
	MOVEM A,CMDBF+.CMGJB
	MOVE A,[440700,,CMDRTY]	;POINTER FOR PROMPT STRING
	MOVEM A,CMDBF+.CMRTY
	TRZN FF,FRARG2		;WAS THERE A PRE-COMMA ARG?
	 JRST FFRRT9		;NO, USE NULL STRING THEN
	SKIPL A,SARG		;GET ARG, SHOULD BE BYTE POINTER
	 CAIA
	CALL QLGET0		;GET BYTE POINTER AND SIZE OF STRING
	 TYPRE [ARG]
	MOVE A,CMDBF+.CMRTY	;GET WHERE TO PUT IT AGAIN
FFRRT8:	ILDB CH,BP
	IDPB CH,A
	SOJG B,FFRRT8		;MOVE IT ALL IN
FFRRT9:	MOVEI CH,0		;END WITH NULL
	IDPB CH,A
	MOVEI A,CMDBF
	MOVEI B,[.BYTE 9 ? .CMINI]	;INITIALIZE COMND STATE BLOCK
	COMND
FFRRTA:	MOVEI D,[FFRRT7]	;NORMALLY FAILURE OF COMND MEANS AN ERROR.
	MOVE C,BAKTAB		;LOOK AT GTJFN FLAGS.  C IS TEMP HERE.
	TLNE C,GJ%NEW		;IF NO REQUEST FOR OLD OR NEW FILE,
	 JRST FFRRT4
	MOVE C,ETMODE		;AND EXTENSION DEFAULTING IS WANTED,
	TRNN C,20
	 JRST FFRRT4
	MOVEI D,FFRRT3		;THEN RETRY A FEW TIMES WITH DIFFERENT FLAGS AND DEFAULTS.
	MOVSI C,(GJ%OLD)
	IORB C,BAKTAB+.GJGEN
	TLNN C,(GJ%IFG)		;UNLESS PARSING WILDCARDS
	 HLLZS BAKTAB+.GJGEN	;DON'T ACTUALLY GIVE GTJFN A NONZERO DEFAULT VERSION.
	SKIPA B,[CMDFOC]	;FILE OR CONFIRM
FFRRT4:	 MOVEI B,[.BYTE 9 ? .CMFIL]	;FILE ONLY
	MOVEI A,CMDBF
	COMND
	TLNE A,(CM%NOP)		;DID IT PARSE OK?
	 AOJA D,@(D)		;NO, TRY SOMETHING ELSE
	HRRZS C			;GET THE ONE PARSED SUCCESSFULLY
	CAIN C,CMDCFM		;WAS IT A FILE WE GOT?
	 JRST FFRRT1		;NO, NO JFN THEN, CAN RETURN
	HRRZ C,CMDBF+.CMCNT	;GET CHARACTERS LEFT IN THE BUFFER
	CAIL C,200.		;IF NOTHING TYPED YET
	 JRST [	MOVE A,B
		RLJFN		;DON'T LEAVE AROUND JFNS
		 JFCL
		JRST FFRRT1]	;JUST LEAVE DEFAULTS ALONE IN THIS CASE
	MOVE D,B		;B HAS <GTJFN FLAGS>,,JFN
	MOVEI A,CMDBF
	MOVEI B,CMDCFM		;NOW CONFIRM THE SELECTION
	COMND
CFMPC:	EXCH D,A		;RECOVER JFN
	TLNE D,(CM%NOP)		;NOT CONFIRMED?
	 JRST [	RLJFN
		 JFCL
		JRST FFRRT7]
FFRRTB:
] ;COMNDF
.ELSE [
	MOVEI A,BAKTAB
	GTJFN
	 JRST FFRRT7
]
	PUSH P,A		;SAVE FLAGS
	CALL FFSET		;SET UP DEFAULTS FROM JFN
	ANDI A,-1
	RLJFN			;FLUSH REAL JFN
	 JFCL
	POP P,A			;GET BACK JFN FLAGS
	TLNE A,(GJ%VER)		;IF VERSION NUMBER HAD WILDCARDS
	 JRST [	HRROI B,-3
		MOVEM B,DEFFN3	;SET IT TO DEFAULT RIGHT
		JRST FFRRT1]
	SKIPL BAKTAB+.GJGEN	;FOR OUTPUT USE?
	 JRST [	TLNE A,(GJ%UHV)	;NO, HIGHEST EXISTING = 0
		 JRST .+2
		JRST .+3]
	TLNE A,(GJ%NHV)		;YES, NEXT HIGHER = 0
	 SETZM DEFFN3		;SETUP VERSION NUMBER DEFAULT RIGHT
FFRRT1:	SETZM IMQUIT		;NO MORE ^G AFTER THIS
	MOVE B,SAVMOD		;RESTORE TTY MODE AFTER GTJFN
IFN 20X,[
	MOVE CH,RGETTY
	CAIN CH,VTSI
	 JRST FFRT2A
]
FFRRT2:	MOVEI A,.CTTRM
	SFMOD
FFRT2A:	SETZM SAVMOD		;AND NO MODE TO RESTORE
	JRST DPYINI

IFN COMNDF,[
;TABLE OF PLACES TO GO IF COMND FAILS.
FFRRT3:	FFRRT5			;AFTER FIRST TRY, TRY WITHOUT DEFAULT EXT
	FFRRTF			;NEXT FLUSH DEFAULT FILENAME, PUT BACK EXTENSION.
	FFRRT5			;NEXT FLUSH BOTH DEFAULTS.
	FFRRT6			;NEXT ALLOW A NEW FILE AND TRY AGAIN, WITH DEFAULTS
	FFRRT7			;FAILS AGAIN => REALLY LOSES.

FFRRT5:	SETZM BAKTAB+.GJEXT	;THIS TIME NO DEFAULT EXTENSION
	JRST FFRRT4

FFRRTF:	SKIPE A,DEFFN2		;GET THE DEFAULT EXTENSION AGAIN
	 HRROI A,DEFFN2
	MOVEM A,BAKTAB+.GJEXT
	SETZM BAKTAB+.GJNAM	;BUT FLUSH THE DEFAULT FILENAME.
	JRST FFRRT4

FFRRT6:	MOVE A,NUM		;TRY NEW FILE NEXT.
	TRNE A,4		;BUT NOT IFUSER WANTS ONLY EXISTING FILE.
	 JRST FFRRT7
	SKIPE A,DEFFN2		;GET THE DEFAULT EXTENSION AGAIN
	 HRROI A,DEFFN2
	MOVEM A,BAKTAB+.GJEXT
	SKIPE A,DEFFN1		;GET THE DEFAULT FILENAME AGAIN.
	 HRROI A,DEFFN1
	MOVEM A,BAKTAB+.GJNAM
	MOVSI C,(GJ%OLD)	;STOP INSISTING ON AN EXISTING FILE.
	ANDCAM C,BAKTAB
	JRST FFRRT4

FFRRTE:	MOVE A,D		;REPARSE, IF THERE IS A JFN, FLUSH IT
	TLZE A,-1
	 RLJFN
	 JFCL
	MOVE C,NUM		;RESET GTJFN BLOCK
	CALL FFRRTS
	JRST FFRRTA		;AND TRY AGAIN FROM THE BEGINNING

CMDFOC:	<.BYTE 9 ? 0 ? 0 ? .CMFIL>,,CMDCFM	;PARSE FILE OR CONFIRM
CMDCFM:	<.BYTE 9 ? .CMCFM>
] ;COMNDF

;HERE IF WE GIVE UP ON FLUSHING DEFAULTS -- REALLY MAKE AN ERROR.
FFRRT7:	CALL FFRRT1	;RESTORE TTY MODE FIRST
	JRST OPNER2	;THEN REPORT ERROR

;SET UP FILENAME DEFAULTS FROM A JFN IN 1
ROUNMS:	MOVEI E,ROUDEV		;GIVE FILENAMES FOR LAST REAL OUTPUT FILE
	JRST FFSET1

RREDGN:	SKIPA E,[ERDEV]		;FOR LAST READ FILE
FFSET:	MOVEI E,DEFDEV		;FOR CURRENT DEFAULTS
FFSET1:	SETZM (E)
	MOVSI C,(E)
	HRRI C,1(E)
	BLT C,ERDEV-1-DEFDEV(E)	;ZERO OUT BLOCK FIRST
	SAVE A			;SAVE JFN TO SET THEM FROM
	ANDI A,-1
	MOVE B,[1,,.FBGEN]
	MOVEI C,C
	GTFDB
	 ERJMP FFSET2		;FAILED, LEAVE AT 0
	HLRZM C,DEFFN3-DEFDEV(E) ;GENERATION NUMBER
FFSET2:	MOVE B,(P)
JS%FN1==JS%NAM
JS%FN2==JS%TYP
IRPS STR,,[DEV DIR FN1 FN2]
	HRROI A,DEF!STR-DEFDEV(E)
	MOVSI C,(JS%!STR)&101100
	JFNS
TERMIN
	JRST POPAJ
FFSET3:	MOVEI E,DEFDEV			;SETUP DEFAULTS
	SAVE A
	JRST FFSET2

FSIFIL:	SKIPA E,[ERDEV]			;DESCRIBE INPUT FILE
FSOFIL:	 MOVEI E,ROUDEV			;DESCRIBE LAST OUTPUT FILE
	AOSA (P)
FSDFRD:	 MOVEI E,DEFDEV			;DESCRIBE DEFAULTS
	SAVE C
	MOVEI C,140.			;BE SURE LONG ENOUGH
	CALL QOPEN
	CALL FSDFR1
FSDFRT:	CALL QCLOSV			;CLOSE UP Q REG SPACE AND GIVE STRING
	JRST POPCJ

;PRODUCE STRING OF DEFAULTS CONTAINED IN BLOCK POINTED TO BY E
FSDFR1:
;PRODUCE STRING OF DEFAULTS CONTAINED IN BLOCK POINTED TO BY E
FSDFR1:	MOVEI A,DEFDEV-DEFDEV(E)
	CALL ASCIND			;DEVICE
	MOVEI CH,":
	LDB A,[350705,,DEFDEV-DEFDEV]
	SKIPE A				;NO USELESS PUNCTUATION.
	CALL @LISTF5
	LDB A,[350705,,DEFDIR-DEFDEV]	;IS THERE A DIRECTORY TO BE MENTIONED?
	JUMPE A,FSDFR2
	MOVEI CH,"<
	CALL @LISTF5
	MOVEI A,DEFDIR-DEFDEV(E)	;DIRECTORY
	CALL ASCIND
	MOVEI CH,">
	CALL @LISTF5
FSDFR2:	MOVEI A,DEFFN1-DEFDEV(E)	;NAME
	CALL ASCIND
	MOVEI CH,".
	CALL @LISTF5
	MOVEI A,DEFFN2-DEFDEV(E)	;EXTENSION
	CALL ASCIND
IFN 20X,MOVEI CH,".
.ELSE	MOVEI CH,";
	CALL @LISTF5
	HRRE C,DEFFN3-DEFDEV(E)		;GENERATION NUMBER
	JRST DPT

;FILE COPY
FCOPY:	CALL FRDOLD			;GET FIRST FILENAME
	MOVE B,[7_30.+OF%RD]		;OPEN FOR 7 BIT READ
	MOVEM A,OPNJFN
	OPENF
	 JRST OPNER0
	SETZM OPNJFN
	SAVE A
	CALL FRDFOU			;GET SECOND ONE
	 JRST OPNER1
	MOVE B,[7_30.+OF%WR]
	MOVEM A,OPNJFN
	OPENF
	 JRST [	POP P,A
		RLJFN
		 JFCL
		JRST OPNER0
		]
	SETZM OPNJFN
	TRNN FF,FRCLN			;: E_ XFER INPUT FILE DATES TOO
	 JRST FCOPY2
	EXCH A,(P)			;INPUT FILE
IFN 20X,[
	MOVEI B,T
	MOVEI C,1
	RFTAD
	EXCH A,(P)
	SFTAD
]
.ELSE	[
	MOVE B,[1,,.FBWRT]
	MOVEI C,C
	GTFDB
	EXCH A,(P)
	HRLI A,.FBWRT
	SETO B,
	CHFDB
	ANDI A,-1
]
FCOPY2:	EXCH A,(P)			;GET INPUT FILE
	MOVE B,[440700,,BAKTAB]
	MOVNI C,LTABS*5
	SIN
	ADDI C,LTABS*5			;GET NUMBER OF WORDS REALLY TRANSFERED
	JUMPE C,FCOPY4			;NONE, EOF
	MOVN C,C
	MOVE B,[440700,,BAKTAB]
	EXCH A,(P)			;OUTPUT FILE
	SOUT
	JRST FCOPY2
FCOPY4:	CLOSF				;CLOSE INPUT FILE
	 JFCL
	REST A				;FILE JUST WRITTEN
	CLOSF
	 JFCL
	JRST DELQIT

;OPEN INPUT FILE AND BIGPRINT NAME ON OUTPUT DEVICE
BPNTRD:	CALL .OPNRD
	TRZ FF,FRARG
	JRST .FNPNT

;OPEN FILE FOR READ
.OPNRD:	CALL FRDOLD
	MOVEM A,OPNJFN
	SETZ A,
	EXCH A,CHFILI
	TLZN FF,FLIN	;JUST IN CASE
	 JRST [	JUMPE A,RRED2
	      	 RLJFN
		 JFCL
	      	JRST RRED2]
	CLOSF
	 JFCL
RRED2:	MOVE A,OPNJFN
IFN 20X\SUMTTF,MOVE B,[36._30.+OF%RD]
.ELSE	MOVE B,[36._30.+OF%RD+OF%EX]	;THIS IS THE BIGGEST CROCK
	TRNE FF,FRARG
	 TDO B,NUM
	TRZN FF,FRARG2	;PRE-COMMA ARG?
	 JRST RRED3
	MOVE C,SARG
	TRNE C,1		;1 BIT MEANS DON'T UPDATE REFERENCE DATES
	 TRO B,OF%PDT
	TRNE C,2		;2 BIT MEANS OPEN IN THAWED MODE
	 TRO B,OF%THW
	TRNE C,4		;4 BIT MEANS DON'T REALLY OPEN
	 JRST RREDGN		;JUST SET REAL NAMES AND RETURN
RRED3:	CALL IMMQIT
	OPENF
	 JRST OPNER0
	SETZM OPNJFN
	MOVEM A,CHFILI
	SETZM IMQUIT
	SETZM PAGENU
	SETOM LASTPA
	CALL RREDGN		;SET UP REAL FILENAMES OF INPUT FILE

;HERE TO ACTUALLY START READING FROM IT
RRED1:	TLO FF,FLIN
	MOVEI CH,EOFCHR
	DPB CH,[350700,,UTIBE]
	MOVE CH,[010700,,UTIBE-1]
	MOVEM CH,UTYIP
	AOJ CH,
	HRRM CH,UTRLDT
	RET

; I/O PDL COMMANDS
;E[ - PUSH INPUT JFN AND STATE
PSHIC:	TLZ FF,FLDIRDPY
	TLNN FF,FLIN			;ANYTHING OPEN NOW?
	 JRST PSHIC2
	MOVE A,CHFILI			;GET CURRENT POSITION
	RFPTR
	 TYPRE [NRA]
	MOVE C,UTYIP			;GET CURRENT POINTER
	IBP C				;FIGURE HOW MANY WORDS WE HAVENT USED
	MOVEI T,(C)
	SUB T,UTRLDT
	HRREI T,(T)
	JUMPE T,PSHIC2
	ADD B,T			;RESET BYTE POSITION BEFORE THEM
	SFPTR
	 TYPRE [NRA]
PSHIC2:	MOVE E,PAGENU			;SAVE PAGENU AND LASTPA
	LSH E,1
	SUB E,LASTPA
	LSH E,2
	TLNE FF,FLIN			;AND STATE OF FLIN
	 ADDI E,2
	HRRI C,1(E)
	MOVE A,INIOP			;GET INPUT PDL POINTER
	PUSH A,CHFILI			;PUSH JFN
	PUSH A,C			;PUSH STATE THEREOF
	MOVEM A,INIOP			;UPDATE PDL POINTER
	TLZ FF,FLIN
	SETZM CHFILI			;FORGET JFN
	JRST UTLSTP			;SET TO SEE EOF

;E] - POP INPUT JFN
POPIC:	TLZ FF,FLDIRDPY
	CALL UICLS			;CLOSE ANYTHING WE HAVE NOW
	MOVE C,INIOP			;GET INPUT PDL POINTER
	POP C,CH			;GET STATE FLAGS
	LDB A,[020100,,CH]
	MOVNM A,LASTPA			;STATE OF LASTPA
	LDB A,[031700,,CH]
	MOVEM A,PAGENU			;STATE OF PAGENU
	POP C,A				;GET JFN
	MOVEM C,INIOP			;UPDATE PDL POINTER
	GTSTS
	TLNE B,(GS%OPN)			;IS IT OPEN?
	 TRNN CH,2			;AND WE THOUGHT ONE WAS TOO?
	 RET				;NO OR NO, FORGET IT
	TLO FF,FLIN			;YES, SAY ONE IS NOW
	MOVEM A,CHFILI			;STORE AWAY JFN
	SAVE CH
	CALL UTRLD2			;GET A BUFFER FULL
	REST CH
	HRRI CH,UTIBUF
	DBP7 CH
	MOVEM CH,UTYIP			;UPDATE BUFFER POINTER
	JRST RREDGN			;AND SET REAL FILENAMES

;E\ - PUSH OUTPUT JFN
PSHOC:	TLZ FF,FLDIRDPY
	CALL FLSOUT			;FLUSH ANY CURRENT OUTPUT THRU
	MOVE B,UTYOP			;GET POINTER TO OUTPUT BUFFER
	IBP B
	LDB A,[073500,,UTOBUF]
	LSHC A,7
	MOVE C,OUTIOP			;GET OUTPUT PDL
	PUSH C,CHFILO			;SAVE JFN
	PUSH C,A			;SAVE STATE OF JFN
	MOVEM C,OUTIOP			;UPDATE PDL POINTER
	TLZ FF,FLOUT			;SAY NO FILE TO WRITE ON NOW
	RET

;E^ - POP OUTPUT CHANNEL
POPOC:	TLZ FF,FLDIRDPY\FLOUT		;PERHAPS NO FILE TO WRITE
	MOVE C,OUTIOP			;GET OUTPUT PDL POINTER
	POP C,CH			;GET STATE
	POP C,A				;GET JFN
	MOVEM C,OUTIOP			;UPDATE PDL POINTER
	GTSTS
	TLNN B,(GS%OPN)		;FILE NOW OPEN?
	 RET				;NO, DONE THEN
	MOVEM A,CHFILO			;YES, UPDATE BUFFER POINTERS
	MOVEM CH,UTOBUF
	MOVE C,[000700,,UTOBUF]
	DPB CH,[350700,,C]
	DBP7 C
	MOVEM C,UTYOP
	ANDI CH,177
	IDIVI CH,7_1
	ADDI CH,<UTOBE-UTOBUF>*5-4
	MOVNM CH,UTYOCT			;AND COUNT OF REMAINING BYTES
	TLO FF,FLOUT			;SAY WE HAVE AN OUTPUT FILE NOW
	RET

EXITE:	HRLOI C,377777			;EE - WRITE OUT FILE AND CLOSE IT
	TRO FF,FRARG
	MOVE E,BEGV			;ANYTHING IN THE BUFFER?
	CAMN E,ZV
	 SKIPE LASTPA			;OR THE INPUT FILE?
	 CALL PUNCHA			;YES, WRITE IT OUT THEN
	CALL UICLS			;CLOSE ANY INPUT FILE
	JRST EFCMD			;AND GO CLOSE AND RENAME OUTPUT FILE

EXITX:	TLNN FF,FLOUT			;IF NO OUTPUT FILE
	 CALL FFRRDD			;STILL READ AND SET DEFAULTS
	TLNE FF,FLOUT			;IF HAVE AN OUTPUT FILE,
	 CALL EXITE			;FINISH IT UP
IFN 20X,[
	MOVE A,[.PRAST,,.FHSLF]		;SET THIS FORK
	MOVEI B,[1			;MAGIC FOR THE EXEC
		 400740,,2
		  0]
	MOVEI C,3			;LENGTH
	PRARG				;SET PROCESS ARG BLOCK
]
.ELSE	[				;THIS IS THE ONLY WAY TO GET BACK CCL FOR 10X
RUN==47000,,35				;1050 UUO
	MOVE A,[1,,[SIXBIT /SYS/
		    SIXBIT /CCL/
		    0 ? 0 ? 0 ? 0]]
	RUN A,				;SWAP IN CCL AND DO LAST COMMAND AGAIN
	 JFCL
]
	JRST .EXIT			;AND QUIT BACK TO EXEC

EFCMD:	CALL FFRRDD			;GET FILE DEFAULTS FOR REAL OUTPUT
	TLNN FF,FLOUT			;MUST HAVE AN OUTPUT FILE
	 TYPRE [NDO]
	TDZA A,A			;RESET COUNT OF FILLER BYTES
EFCMDA:	 CALL UTYO
	MOVE CH,UTYOP
	HRR CH,FILEPA			;PAD TO EVEN WORD WITH FILEPAD
	TLNE CH,760000
	 AOJA A,EFCMDA
	PUSH P,A			;SAVE COUNT OF FILLER BYTES
	CALL FLSOUT			;FLUSH OUT LAST OF BUFFER
	MOVE A,CHFILO
	RFPTR				;GET WHERE WE ARE
	 SETZ B,
	IMULI B,5			;INTO CHARS
	SUBM B,(P)			;LESS FILLERS
	TLO A,(CO%NRJ)			;CLOSE, BUT SAVE JFN
	CLOSF
	 JFCL
IFN 10X,[
	HRRZS CH,A			;SAVE JFN
	DVCHR
	HRRI A,(CH)			;GET JFN BACK INTO RH
	TLNE A,(DV%TYP)			;CHECK FOR DSK:
	 JRST EFCMD5			;DO NOT ATTEMPT CHFDB IF NOT
					;20X OR FNX WILL TAKE ERJMP
]
	HRLI A,.FBSIZ			;SET FILE SIZE
	SETO B,
	POP P,C				;TO NOT INCLUDE FILLERS
	CHFDB
	 ERJMP EFCMD5			;MAYBE ONLY WRITE ACCESS, NO FDB
	HRLI A,.FBBYV			;AND SET BYTE SIZE
	MOVSI B,(FB%BSZ)
	MOVSI C,000700			;TO BE 7-BIT
	CHFDB
EFCMD5:	MOVSI C,DEFDEV-ERDEV		;SEE IF FILENAME DEFAULTS HAVE CHANGED
EFCMD4:	MOVE B,DEFDEV(C)
	CAME B,ROUDEV(C)
	 JRST EFCMD3			;DIFFERENT, MUST DO RENAME
	AOBJN C,EFCMD4
	ANDI A,-1			;GET JUST JFN
EFCMD2:	CALL ROUNMS			;SET UP REAL NAMES OF OUTPUT FILE
	RLJFN				;THRU WITH THE JFN
	 JFCL
	TLZ FF,FLOUT			;NO MORE OUTPUT FILE
	SETZM CHFILO
	RET
EFCMD3:	MOVSI A,(GJ%FOU)
	CALL FF5			;GET JFN FOR NEW NAME
	 JRST OPNER1
	MOVEI B,(A)
	MOVE A,CHFILO			;RENAME OUTPUT FILE TO IT
	RNAMF
	 JRST [	MOVE A,CHFILO
		RLJFN
		 JFCL
		MOVE A,B
		RLJFN
		 JFCL
		JRST OPNER1]
	MOVEI A,(B)
	JRST EFCMD2

;EJ - LOAD IMPURE PORTIONS FROM FILE
;:EJ LOAD LIBRARY FILE INTO PURE STRING SPACE.
;@EJ - WRITE OUT IMPURE PORTIONS IN A BOOTABLE FORMAT
;DUMP FILES CAN BE IDENTIFIED BECAUSE THEY HAVE 'TEC,,VERSION-NUMBER
;IN THE .FBUSW WORD IN THE FDB.

EJCMD:	TRZN FF,FRUPRW
	 JRST EJCMDR			;READ IN
	TLZN FF,FLOUT			;@EJ
	 TYPRE [NDO]			;MUST HAVE AN OUTPUT FILE ALREADY
	MOVEM P,BOOTP			;SSAVE DOESNT SAVE AC'S
	MOVE A,CHFILO
	TLO A,(CO%NRJ)
	CLOSF
	 JFCL				;CLOSE FAKE OUTPUT FILE
	HRLI A,(DF%EXP)
	DELF				;AND GET RID OF IT
	 JFCL
	SETZM CHFILO			;DONT HAVE THIS SET IN THE DUMPED OUT FILE
	SETZM FRKTAB
	MOVE A,[FRKTAB,,FRKTAB+1]
	BLT 1,FRKTAB+NFKS-1		;FORGET ANY INFERIORS
	CALL FRDFOU			;GET REAL OUTPUT FILE
	 JRST OPNER1
	CALL ROUNMS			;SET UP REAL OUTPUT NAMES
	HRLI A,.FBUSW
	SETO B,
	MOVE C,[SIXBIT /TEC/+.FVERS]	;TO IDENTIFY A DUMP FILE
	CHFDB
IFN 20X,[
IFDEF .FBKEP,[
	HRLI A,.FBCTL
	MOVSI B,(FB%FCF)
	MOVSI C,(<.DPB .FBKEP,<.BP FB%FCF>,0>)	;MAKE FILE AUTOKEEP
	CHFDB
	 ERJMP .+1
]];IFN 20X
	MOVE TT,[-<<LIMPUR+1>_-9>,,SS%CPY\SS%RD\SS%EXE+0]
	MOVEM TT,BAKTAB			;LOW IMPURE
	MOVE TT,QRWRT
	ADDI TT,4
	IDIVI TT,5000
	SUBI TT,HIMPUR_-9
	MOVNI TT,1(TT)			;NEGATIVE OF NUMBER OF PAGES
	HRLI TT,SS%CPY\SS%RD\SS%EXE+HIMPUR_-9
	MOVSM TT,BAKTAB+1		;START OF HIGH IMPURE
	MOVE B,BFRBOT
	IDIVI B,5000			;STARTING PAGE OF BUFFER SPACE
	MOVE C,BFRTOP
	IDIVI C,5000
	SUBM B,C			;-LENGTH
	HRLI B,-1(C)			;-<NUMBER OF PAGES>
	TRO B,SS%CPY\SS%RD\SS%EXE
	MOVEM B,BAKTAB+2
	HRLI A,.FHSLF
	MOVEI B,BAKTAB
	SETZB C,BAKTAB+3
	SETZM LIMPUR			;MAKE SURE THE EJ FILE LOADS TECPUR IF RUN
	SSAVE				;SAVE THOSE IMPURE PAGES
	SETOM LIMPUR
	RET

;INPUT VERSIONS
EJCMDR:	CALL FRDOLD			;GET FILE
	TRZN FF,FRCLN
	 JRST EJCMD2			;EJ - MAP IN IMPURE AREAS
	MOVE B,[36._30.+OF%RD]
	MOVEM A,OPNJFN
	OPENF
	 JRST OPNER0
	SETZM OPNJFN
	SIZEF
	 TYPRE [URK]			;SOME SORT OF ERROR HERE
	ASH C,-1			;CONVERT PAGES TO BLOCKS
	MOVNI B,(C)
	ADD B,LHIPAG			;WITHIN RANGE?
	CAMG B,MEMT			;LEAVE AT LEAST ONE BLANK PAGE ABOVE BUFFER SPACE.
	 CALL [	CALL FLSCOR		;BUT SEE IF THERE IS ANYTHING WASTED WE CAN FLUSH
		CAMG B,MEMT		;BEFORE DECIDING IT'S FATAL.
		 TYPRE [URK]
		RET]
	MOVEM B,LHIPAG			;UPDATE BOTTOM PAGE
	ASHC B,1			;CONVERT BACK TO BLOCKS
	HRLI B,.FHSLF
	HRLZS A				;JFN
	HRLI C,(PM%CNT\PM%RD)		;DON'T ALLOW COPY ON WRITE
					;ELSE BUFFER SPACE COULD UNKNOWINGLY OVERWRITE IT.
IFN 20X,PMAP				;MAP IN THOSE PAGES
.ELSE	[
	MOVEI D,(C)
	PMAP				;10X - NO MULTIPLE PMAP'S
	SOJLE D,.+3
	AOJ A,
	AOJA B,.-3
]
	HLRZ A,A
	CLOSF
	 JFCL
	HRRZ A,LHIPAG			;RETURN POINTER
	IMULI A,12000
	TLO A,400000
	JRST POPJ1

EJCMD2:	MOVE B,[1,,.FBUSW]		;CHECK USER SETTABLE WORD
	MOVEI C,C
	GTFDB
	CAME C,[SIXBIT /TEC/+.FVERS]	;A COMPATIBLE DUMP FILE?
	 TYPRE [AOR]			;NOPE
IFN 20X,[
	PUSH P,A
	MOVEI A,.CTTRM
	RFMOD 
	SKIPE PAGMOD
	 TROE B,TT%PGM
	 CAIA
	 STPAR
	POP P,A
]
	MOVE E,LHIPAG
	MOVE T,MEMT
	MOVE J,INITFL			;SAVE THESE GUYS
	HRLI A,.FHSLF
	GET				;THIS SHOULD ONLY HAVE IMPURE PAGES
	MOVEM E,LHIPAG
	MOVE B,D
	HRROI A,DEFDIR
	DIRST
	 JFCL
	CAMLE T,MEMT
	 MOVEM T,MEMT
	MOVEM J,INITFL
	.I SAVCMX=CBMAX=1	;RESTORE THEM
	SETOM PJATY		;WE JUST LOADED INVALID HCDS, SO NEED ALL LINES REDISPLAYED.
	JRST INIT		;RESTART OURSELVES

;RENAME FILE 1 TO FILE 2
RENAM:	CALL FRDOLD			;GET FIRST FILE
	SAVE A
	CALL FRDFOU			;GET SECOND FILE
	 JRST OPNER1
	CALL IMMQIT
	MOVEI B,(A)
	REST A
	RNAMF				;DO THE RENAME
	 JRST OPNER1
	MOVEI A,(B)
	RLJFN
	 JFCL
	JRST DELQIT

;DELETE A FILE
DELE:	TRZE FF,FRCLN
	 JRST DELE1			; :ED IS DELETE INPUT FILE.
	CALL FRDOLD			;GET OLD FILE JFN
	TRNE FF,FRUPRW			;@ED MEANS EXPUNGE THE FILE TOO.
	 HRLI A,(DF%EXP)
	DELF				;DELETE IT
	 JRST OPNER1
IFN 10X\FNX,[
	RLJFN				;ON TENEX, MUST GET RID OF JFN TOO.
	 JFCL
];10X\FNX
	RET
DELE1:	TLZN FF,FLIN
	 TYPRE [NFI]
	MOVEI A,0
	EXCH A,CHFILI
	DELF				;DELETE IT
	 JRST OPNER1
	CLOSF				;CLOSE IT
	 JFCL
	RET

WWINIT:	CALL FFRRDD			;EW - GET FILENAME DEFAULTS
EICMD:	SKIPG A,CHFILO
	 JRST WWINI0
	TLO A,(CZ%ABT)			;GET RID OF ANY OLD FILE
	CLOSF
	 JFCL
WWINI0:	TRNE FF,FRUPRW			;@EW MEANS CAN OVERWRITE
	 TDZA A,A			;NO GTJFN FLAGS THEN
	 MOVSI A,(GJ%FOU)		;OTHERWISE USER OUTPUT DEFAULTS
	TRNE FF,FRARG2			;PRECOMMA ARG?
	 TLO A,(GJ%DEL\GJ%FOU)		;YES. DELETED OK. CREATE FILE ALSO.
	CALL FF5			;GET JFN FROM DEFAULTS
	 JRST OPNER1
	MOVEM A,CHFILO
	MOVE B,[36._30.+OF%WR]		;OPEN FOR WRITE
	TRNE FF,FRUPRW			;AND IF IN OVERWRITE MODE,
	 TRO B,OF%RD			;READ TOO, SO FILE NOT CLOBBERED
	TRNE FF,FRARG			;POSTCOMMA ARG?
	 MOVE B,NUM			;YES. USE USER BITS THEN.
	CALL IMMQIT
	MOVEM A,OPNJFN
	OPENF
	 JRST OPNER0
	SETZM OPNJFN
	SETZM IMQUIT
	TLO FF,FLOUT			;SAY WE HAVE ONE
	MOVE CH,[DEFDEV,,ROUDEV]	;SAVE CURRENT FILENAME DEFAULTS
	BLT CH,ROUDEV+ERDEV-DEFDEV-1
	MOVE CH,[010700,,UTOBUF-1]	;REINIT BUFFER POINTER
	MOVEM CH,UTYOP
	MOVNI CH,<UTOBE-UTOBUF>*5
	MOVEM CH,UTYOCT			;AND BUFFER COUNT
	RET

; DO MTOPR ON JFN FROM LH E, WITH ARGS IN C AND SARG
FSMTAP:	HLRZS E
	MOVE A,(E)
	MOVE C,SARG
	MTOPR
	 ERJMP OPNER1
	MOVE A,C			;ANY ARG RETURNED IN 3
	JRST POPJ1

; READ OR MODIFY FDB FOR INPUT FILE
FSIFDB:	TLNN FF,FLIN
	 TYPRE [NFI]
	JRST FSXFDB
FSOFDB:	TLNN FF,FLOUT
	 TYPRE [NDO]
FSXFDB:	TRZN FF,FRARG
	 TYPRE [WNA]
	HLRZS E
	MOVE A,(E)
	MOVEI B,(C)		;FIRST WORD TO DO
	HRLI B,1		;ONE WORD
	MOVEI C,D		;WHERE TO PUT IT
	GTFDB
	TRZN FF,FRARG2		;WAS THERE A SECOND ARGUMENT?
	 JRST FSFDB2		;NO, JUST RETURN OLD VALUE
	HRLI A,(B)		;WORD TO CHANGE
	MOVE C,SARG		;NEW VALUE
	MOVE B,C
	XOR B,D			;GENERATE MASK FOR NEW VALUES
	CHFDB
	 ERJMP OPNER1
FSFDB2:	MOVE A,D
	JRST CPOPJ1

;DIRECTORY DISPLAY COMMANDS
LISTF:	CALL LSTFRD			;GET FILESPEC FROM FOLLOWING STRING
CNTRU1:	 CALL LSTFR2			;USE DEFAULT (DEV:<DIR>*.*.*)
	CALL VBDACU			;SEE IF THERE IS ANY COMMAND WAITING
	 RET				;RETURN RIGHT AWAY
	SETZ CH,
	CALL DISINI			;INIT DISPLAY
	MOVEI OUT,CHCT			;TYPE OUT
	JRST LISTF1

LISTFM:	SETZM GJBITS
	MOVEI OUT,TYOM			;TYPE INTO MEMORY
	TRNE CH,20			;EZ?
	 CALL LSTFRD			;YES, READ FROM USER
	 CALL LSTFR2			;NO, USE DEFAULTS
LISTF1:	SAVE A				;SAVE THE JFN
	TLZ FF,FLDIRDPY			;DONT NEED IT AGAIN
	HRRM OUT,LISTF5

LISTF2:	HRROI A,FDRBUF			;ADDRESS OF SPACE TO KEEP DATA IN.
	HRRZ B,(P)
	TRNE FF,FRARG			;USE USERS FORMAT IF AN ARGUMENT OF IT
	 SKIPA C,NUM
	  MOVE C,[1_27.+1_24.+1_21.+JS%SIZ+JS%LWR+JS%LRD+JS%PSD+JS%PAF]
	TRNE FF,FRUPRW			;@?
	 TRO C,JS%OFL			;YES. SHOW OFFLINE ATTRIBUTE
	JFNS				;ALONG WITH SIZE AND READ AND WRITE DATES
	TRNE FF,FRARG2			;WHAT ABOUT 'GIVE AUTHOR' ARG?
	 JRST LISTFE			;ANY ARG MEANS DON'T GIVE AUTHOR
	MOVEI CH,",
	IDPB CH,A
	EXCH A,B
IFN 20X,[
	HRLI A,.GFLWR			;AND THE LAST WRITER TOO
	GFUST
	 ERJMP [DBP7 B			;DON'T LEAVE TRAILING COMMA
		 JRST .+1]
	EXCH A,B
]
.ELSE	[
	SAVE A
	SAVE B
	MOVE B,[1,,.FBUSE]		;LAST USER WHO WROTE
	MOVEI C,2			;PUT DIRECTORY NUMBER IN B<LH>
	GTFDB
	REST A
	HLRZ B,B			;MAKE IT ACCEPTABLE
	DIRST				;PUT DIRECTORY NUMBER THERE
	 ERJMP [DBP7 A
	         JRST .+1]
	REST B
]	
	
LISTFE:	MOVEI CH,^M			;AND A CRLF
	IDPB CH,A
	MOVEI CH,^J
	IDPB CH,A
	MOVEI CH,^@
	IDPB CH,A			;END WITH NULL

	HRRZ OUT,LISTF5			;GET WHERE IT GOES
	CAIN OUT,TYOM			;INTO MEMORY?
	 JRST LISTF8			;YES, DO IT FAST THEN
	MOVEI A,FDRBUF			;START OF WHERE STRING IS
	CALL ASCIND			;TYPE THIS LINE OUT
	SKIPL MORFLF			;--MORE-- FLUSHED?
	 JRST LISTF3			;NO
	POP P,A				;GET BACK JFN
	RLJFN				;GET RID OF IT
	 JFCL
	JRST LISTF7			;DONE

	
LISTF8:	HRRZ C,A
	SUBI C,FDRBUF			;NUMBER OF WORDS
	IMULI C,5
	LSH A,-30.
	HRREI A,-36.+7(A)		;NULL DOESNT COUNT
	IDIVI A,7
	SUB C,A				;GET TOTAL NUMBER OF CHARS USED
	CALL SLPGET			;MAKE THAT MUCH ROOM
	MOVE A,[440700,,FDRBUF]
LISTF6:	ILDB CH,A			;INSERT GIVEN NUMBER OF CHARACTERS
	IDPB CH,BP
	SOJG C,LISTF6

LISTF3:	MOVE A,(P)			;GET BACK MULTI JFN
	GNJFN				;GET NEXT FILE
	 CAIA				;NONE LEFT
	  JRST LISTF2			;TAKE CARE OF IT TOO
	POP P,A				;FLUSH JFN
LISTF7:	HRRZ A,LISTF5			;IF OUTPUT IS GOING TO DISPLAY AREA,
	CAIN A,CHCT
	 JRST DISCLG			;FINISH UP DISPLAY
	RET

LSTFRD:	AOSA (P)			;GET A FILENAME FROM THE USER
LSTFR2:	 TLZA FF,FRNOT			;GET JUST DEFAULTS
	 TLO FF,FRNOT
	SAVE OUT
	CALL LSTFR0
	 JFCL
	REST OUT
	MOVE A,OPNJFN
	RET

LSTFR0:	CALL FSDFRD			;GET CURRENT DEFAULTS
	JSP T,GCPUSA			;SAVE IN A GC PROTECTED WAY
	MOVSI A,(<ASCII /*/>)
	MOVEM A,DEFFN1			;SET THEM UP
	MOVEM A,DEFFN2
	MOVEI A,-3			;AND .*
	HRRM A,DEFFN3
	SETZ A,
	TRNE FF,FRUPRW			;ATSIGN?
	 MOVSI A,(G1%IIN)		;YES. INVISIBLE OK.
	MOVEM A,GJBITS			;SAVE FOR GTJFN CALL.
	MOVSI A,(GJ%IFG\GJ%OLD)		;ALLOW MULTIPLE INPUT FILESPECS
	TRNE FF,FRCLN			;COLON?
	 MOVSI A,(GJ%IFG\GJ%OLD\GJ%DEL)	;YES. DELETED OK.
	TLNE FF,FRNOT			;READING FROM STRING?
	 JRST LSTFR4			;YES, GET IT
IFN 20X,HRROI B,[ASCIZ /*.*.*/]	;DEFAULT STRING IF NOT FOM USER
.ELSE	HRROI B,[ASCIZ /*.*;*/]
LSTFR5:	CALL FF5A
	 JRST OPNER1
LSTFR3:	MOVEM A,OPNJFN			;SAVE THE JFN
	MOVE C,-2(P)			;GET OLD DEFAULTS
	JRST FSDFL1			;AND RESTORE THEM

LSTFR4:	CALL FFRRDD			;READ FILESPEC STRING
	JRST LSTFR5

IFN 0,%%TNX.:
]	;END IFN TNX CONDITIONAL

;FS DFILE$ -- THE DEFAULT FILE NAMES, AS A STRING.  CAN BE READ OR SET.
FSDFILE:CALL FSDFRD	;FIRST GET VALUE TO RETURN FROM OLD FILENAMES.
	TRZN FF,FRARG	;IF HAVE ARG, SET FILENAMES TO IT BY INSERTING IT
	 JRST POPJ1	;INTO AN ET COMMAND.
	JSP T,GCPUSA	;MEANWHILE, KEEP VALUE WHERE IT WILL BE RELOCATED.
FSDFL1:	MOVEI A,[ASCIZ /[0 U0 ET0 ]0/]
	CALL MACXCP
	JRST GCPOPV

;HERE TO MACRO STRING PTR OR ASCIZ ADDR IN A, WITH ARG IN C, SAVING CURRENT VALUE STATUS.
MACXCP:	JSP T,OPEN1
	JUMPGE A,.+3		;IF ITS A POINTER, NOT AN ASCIZ STRING, THEN
	 CALL QLGET0		;IF NOT GOOD STRING POINTER, GET ERROR NOW, BECAUSE PAST RRMAC5
	  TYPRE [QNS]		;WE WILL NOT BE IN SAFE STATE FOR GETTING ERRORS.
	MOVEM C,NUM
	CALL RRMAC5		;USE RRMAC5, NOT MACXQW, IN CASE WE ARE CALLED BY ^R.
	TRZ FF,FRARG\FRARG2\FRCLN\FRUPRW\FROP\FRSYL
	HRROI T,CPOPJ
	JRST CLOSE2

SUBTTL OUTPUT ROUTINES THAT USE LISTF5

;COME HERE FOR DPT OF NEGATIVE NUMBER.
DPT2:	CAMN C,[SETZ]	;CAN'T NEGATE THIS! MUST WORK SPECIALLY
	 JRST DPTMNF
	MOVNS C		;OTHERWISE PRINT THE MAGNITUDE, PRECEDED BY A "-".
	TLO FF,FLNEG
RDPT:	SOJA TT,DPT6

DPT:	TDZA TT,TT	;DECIMAL PRINT, NO LEADING ZEROS.
SLDPT:	MOVEI TT,2	;DECIMAL PRINT, WITH AT LEAST 3 POSITIONS USED.
DPT1:	JUMPL C,DPT2
DPT6:	MOVE D,QRB..
	MOVM CH,.QBASE(D)
	SOJLE CH,[
		MOVEI C,10.	;IF ..E HOLDS 0, 1 OR -1, REPLACE BY 10.
		MOVEM C,.QBASE(D)
		TYPRE [..E]]
	IDIV C,.QBASE(D)
DPT8:	HRLM D,(P)
	JUMPGE D,DPT7		;HANDLE NEGATIVE REMAINDER (IMPLIES NEG. RADIX).
	MOVE D,QRB..
	HRLZ D,.QBASE(D)	
	MOVNS D
	ADDM D,(P)
	AOS C
DPT7:	SKIPE C
	 CALL RDPT
	TLZE FF,FLNEG
	 SAVE ["--"0,,DPT3]
DPT3:	JUMPLE TT,DPT4
	XCT DPT5
	PUSHJ P,@LISTF5
	SOJG TT,.-1
DPT4:	HLRE CH,(P)
DGPT:	ADDI CH,"0
	CAILE CH,"9	;FOR "DIGITS" ABOVE 9, USE LETTERS.
	 ADDI CH,"A-"9-1
	JRST @LISTF5

DPTMNF:	MOVE D,QRB..	;HANDLE PRINTING OF 400000,,
	MOVE D,.QBASE(D)
	CAIE D,8	;PRINT IT WITH A "-" SIGN, EXCEPT IN OCTAL.
	 TLO FF,FLNEG
	SAVE D
	LSHC C,-35.	;NOTE LOW BIT OF E IS 0, SINCE QRB.. ISN'T TOO BIG.
	DIV C,(P)
	SUB P,[1,,1]
	JRST DPT8

;<ARG>= PRINTS <ARG><CR>.
;<ARG>,= PRINTS <ARG>,<CR>.
;<ARG>,<ARG1>= PRINTS <ARG>,<ARG1><CR>.
;@ => PRINT IN ECHO AREA.  : => OMIT THE <CR>.
PRNT:	ARGDFL		;-= MEANS -1=.
	TRNN FF,FRARG+FRARG2
	 TYPRE [WNA]
	TRNN FF,FRARG2
	 JRST PRNT2
	EXCH C,E	;= WITH 2 ARGS:
	CALL PRNT3	;PRINT THE 1ST ARG,
	MOVEI CH,",
	CALL @LISTF5	;A COMMA,
	EXCH C,E	;AND THE SECOND ARG.
	TRNE FF,FRARG
PRNT2:	 PUSHJ P,PRNT3
	TRNN FF,FRUPRW
	 SAVE [DISFLS]	;IF ORDINARY TYPEOUT, MUST FORCE IT OUT WHEN DONE.
	TRNE FF,FRCLN
	 RET
	JRST CRR1

PRNT3:	MOVEI A,TYO
	TRNE FF,FRUPRW
	 MOVEI A,FSECO2
	HRRM A,LISTF5
	JRST DPT

CRR:	MOVEI CH,TYO
	HRRM CH,LISTF5
	PUSHJ P,CRR1
	JRST DISFLS

CRR1:	MOVEI CH,15
	PUSHJ P,@LISTF5
	MOVEI CH,12
	JRST @LISTF5

CTLQM:	SKIPA CH,[^Q]
SPSP:	MOVEI CH,40
	JRST @LISTF5

FORMF:	MOVEI CH,^M
	CALL @LISTF5
	MOVEI CH,^L
	JRST @LISTF5

;OUTPUT A WORD OF SIXBIT, WITH ^Q'S AS NEC. SO TECO CAN READ BACK IN AS FILENAME.
SIXIN1:	JUMPE A,CPOPJ
	MOVEI B,0
	ROTC A,6
IFN ITS,[
	JUMPE B,SIXIN2
	CAIE B,':
	CAIN B,';
SIXIN2:	PUSHJ P,CTLQM
]
	MOVEI CH,40(B)
	PUSHJ P,@LISTF5
	JRST SIXIN1

SIXINT:	PUSHJ P,SIXIN1	;INSERT IN THE BUFFER THE SIXBIT WORD IN A
	MOVE CH,C	;AND THE ASCII CHAR IN C
	JRST @LISTF5

SIXINS:	PUSHJ P,SIXIN1
	JRST CRR1	;END WITH CRLF

;OUTPUT ASCIZ STRING <- A, THRU LISTF5.
ASCIND:	HRLI A,BP7	;GET BP TO STRING.
ASCIN1:	ILDB CH,A
	JUMPE CH,CPOPJ
	XCT LISTF5
	JRST ASCIN1

SIXNTY:	PUSH P,OUT
	MOVE OUT,E
SIXNT1:	SETZ CH,
	ROTC OUT,6
	ADDI CH,40
	CALL @LISTF5
	JUMPN OUT,SIXNT1
	REST OUT
	POPJ P,

TYPR:	MOVEI IN,6
TYPR3:	MOVE OUT,[(600)E-1]
	ILDB CH,OUT
	ADDI CH,40
	XCT LISTF5
	SOJG IN,.-3
TYPR2A:	POPJ P,LISTF4

SLTAB:  LISTF4:
	MOVEI CH,^I
	JRST @LISTF5

SUBTTL TERMINAL I/O FS FLAGS

;FS LISTEN$ - RETURN NONZERO IFF INPUT IS AVAILABLE.
;IF NONZERO ARG, THEN IF NO INPUT AVAILABLE PRINT IT AS ASCII CHAR IN ECHO AREA.
FSLISN:	SKIPN TYISRC
	 SKIPL A,UNRCHC	;RETURN -1 IF INPUT IS AVAILABLE FROM ANY SOURCE.
	  JRST POPJ1
	LISTEN A
	JUMPG A,NRETM1
	TRZE FF,FRARG	;OTHERWISE, IF THERE'S AN ARG,
	 SKIPN RGETTY
	  JRST POPJ1
	AOS (P)
	JRST FSECOT	;TYPE IT IN ECHO MODE (ON DISPLAYS ONLY)

IFN ITS,[
;FS MP DISPLAY$ - OUTPUT CHARACTER OR STRING TO M.P. AREA IN DISPLAY MODE.
FSMPDS:	SKIPGE CH,C
	 JSP CH,FSMPD1
	SYSCAL IOT,[%CLIMM,,CHTTYO ? CH ? %CLBIT,,%TJDIS]
	 .LOSE %LSFIL
	RET
]

;TO HANDLE A STRING BY LOOPING OVER THE CHARACTERS, OR HANDLE A SINGLE CHARACTER, DO
;	SKIPGE CH,C
;	 JSP CH,FSMPD1
;	... HANDLE ONE CHARACTER IN CH.
FSMPD1:	HRRM CH,LISTF5
	SETO D,
	JRST FGCMD1

;FS ECHO DISPLAY$ - OUTPUT CHAR OR STRING IN DISPLAY MODE (^P IS SPECIAL) TO THE ECHO AREA.
;ARG IN C; CLOBBERS CH.
FSECDS:	SKIPGE CH,NELNS
	 SETCM CH,NELNS
	JUMPE CH,CPOPJ	;DO NOTHING IF THERE'S NO ECHO AREA.
	CALL FSECO7	;IF PJATY SET, CLEAR SCREEN NOW SO DON'T LOSE ECHO AREA TYPEOUT.
	SKIPGE CH,C
	 JRST [	JSP CH,FSMPD1	;IF ARG IS A STRING, TYPE THE CHARS IN IT.
		CAIN CH,^M	;FSMPD1 CALLS BACK HERE WITH SUCCESSIVE CHARS.
		 JRST FSECD2	;BUT IN A STRING, CR SHOULD COME OUT AS A STRAY CR, NOT CRLF.
		JRST .+1]
	CALL ECHODP		;OUTPUT TO ECHO AREA IN DISPLAY MODE.
	JRST FSECO5

IFN TNX,FSMPDS:		;CLOSEST WE CAN COME - NOTHING SHOULD DO IT ANYWAY
FSIMAG:	SKIPGE CH,C	;FS IMAGE OUT$ - OUTPUT CHARACTER OR STRING IN SUPER-IMAGE MODE.
	 JSP CH,FSMPD1	;IF IT'S A STRING, CALL .+1 FOR EACH CHARACTER.
IFN ITS,.IOT CHSIO,CH
IFN TNX,[
	MOVEI A,(CH)
	PBOUT
]
	JRST FSECO6

;OUTPUT CHAR TO ECHO AREA;  ^M COMES OUT AS STRAY CR.
FSECO2:	CALL FSECO7	;IF PJATY SET, CLEAR SCREEN NOW SO DON'T LOSE ECHO AREA TYPEOUT.
	SKIPN RGETTY	;ON PRINTING TTY, MUST TYPE USING NORMAL MECHANISM;  OTHERWISE
	 JRST TYO	;CHCTHP WOULD NOT BE UPDATED AND SPURIOUS CONTINUATIONS WOULD HAPPEN
	SKIPE RUBENC	;IF PREVIOUS COMMAND WANTED A CHAR TYPED BY US, TYPE IT.
	 CALL RUBEND
FSECD2:	CALL ECHOC0	;OUTPUT CHAR IN ECHO AREA BUT NOT IN ECHO MODE.
	JRST FSECO5

;FS ECHO OUT - OUTPUT ARG IN ECHO MODE (WRITE-ONLY)
FSECOT:	MOVE CH,C	;OUTPUT CHAR TO ECHO AREA;  ^M COMES OUT AS CRLF.
;INTERNAL ENTRY POINT WITH CHARACTER IN CH.  THIS MUST PRESERVE ALL ACS EXCEPT CH AND Q.
FSECO1:	SKIPN RGETTY	;ON PRINTING TTY, WE WILL USE NORMAL TYPEOUT, WHICH MEANS
	 SAVE [DISFLS]	;THAT AFTERWARD WE MUST FORCE IT OUT.
	CALL FSECO7	;IF PJATY SET, CLEAR SCREEN NOW SO DON'T LOSE ECHO AREA TYPEOUT.
	JUMPL CH,[	;IF ARG IS A STRING, TYPE OUT ALL ITS CHARACTERS.
		CALL SAVACS
		SAVE [RSTACS]
		MOVE C,CH
		JSP CH,FSMPD1
		JRST FSECO2]	;USE FSECO2 SO CR COMES OUT A A STRAY CR.
	SKIPN RGETTY
	 JRST [	SETOM ECHACT
		CAIN CH,^M
		 JRST CRR
		JRST TYO]
	SKIPE RUBENC	;IF PREVIOUS COMMAND WANTED A CHAR TYPED BY US, TYPE IT.
	 CALL RUBEND
FSECOR:	CALL ECHOCH	;OUTPUT CHAR IN CH IN ECHO MODE.
FSECO5:	SKIPG ECHACT
	 SETOM ECHACT	;MAKE SURE ECHO AREA IS CLEARED.
FSECO6:	SETOM RROVPO	;IN CASE IN ^R MODE,
	SETOM RROHPO	;MAKE SURE CURSOR GETS REPOSITIONED.
	SETOM ECHCHR
	RET

FSECO7:	AOSE PJATY	;CLEAR SCREEN IF IT SAYS IT NEEDS TO BE CLEARED SOON.
	 JRST [	SKIPL ECHONL	;ELSE GO TO FRESH CLEAR LINE IF THAT'S PENDING.
		 RET
		JRST ECHOCL]
	CALL CTLL1
	SETZM RRMSNG	;MAKE SURE ^R REDISPLAYS EVERYTHING NEXT TIME.
	JRST RRLRDS

;GO TO FRESH LINE IN ECHO AREA AND CLEAR IT.
ECHOCL:	SETZM ECHONL	;CLEAR THE FLAG SAYING TO DO THIS LATER.
	SAVE CH
	MOVEI CH,^P
	CALL ECHODP
	MOVEI CH,"A
	CALL ECHODP
	MOVEI CH,^P
	CALL ECHODP
	MOVEI CH,"]
	CALL ECHODP
	JRST POPCHJ

SUBTTL TERMINAL OUTPUT COMMANDS

;FV<STRING>$  --  DISPLAY <STRING>
FVIEW:	TROE FF,FRCLN	;:FV DOESN'T START AT TOP OF SCREEN.
	 JRST FVIEW1	;AND IT DOES TYPEOUT INSTEAD OF DISPLAY.
	CALL DISINI
	JRST FVIEW1

;FT<STRING>$  --  TYPE <STRING>
FTYPE:	TRNE FF,FRUPRW	;@FT TYPES STRING IN ECHO AREA.
	 JRST [	TRNN FF,FRCLN	;@:FT DOES DOES SO ONLY IF NO INPUT AVAILABLE.
		 JRST FTYECH
		SKIPGE UNRCHC
		 SKIPE TYISRC
		  JRST FNOOP
		LISTEN A
		JUMPE A,FTYECH
		JRST FNOOP]	;THERE'S INPUT; IGNORE STRING INSTEAD TYPING IT.
	TRZE FF,FRCLN	;:FT STARTS AT TOP OF SCREEN.
	 SETOM TYOFLG
	CALL DISINT
FVIEW1:	MOVEI BP,CHCT
FTYLUP:	CALL RCH
	SKIPN SQUOTP
	 CAIE CH,33
	  CAIA
	   JRST FTEND
	SKIPGE STOPF
	 CALL QUIT0
FTYCHR:	ANDI CH,177
	CALL (BP)
	JRST FTYLUP

FTEND:	TRNE FF,FRCLN
	 JRST DISCLG
	SKIPGE TYOFLG
	 RET
	JRST DISFLS

FTYEC1:	ANDI CH,-1	;REMEMBER SUPRQUTED CHARS HAVE L.H. SET!
	CALL [	CAIE CH,^M
		 CAIN CH,^J
		  JRST FSECO2
		JRST FSECO1]
FTYECH:	SKIPGE STOPF
	 CALL QUIT0
	CALL RCH
	SKIPN SQUOTP
	 CAIE CH,33
	  JRST FTYEC1
	SKIPN RGETTY
	 JRST DISFLS
	RET

;V COMMAND, AND ALL VARIATIONS THEREOF. EXIT WITH JRST RET.
VIEW:	TRZE FF,FRUPRW
	 JRST [	CALL VIEW1B	;"@V" - DO APPRO. KIND OF DISPLAY
		JRST VIEW1A]	;THEN CHECK FOR FOLLOWING W.
	SKIPN RGETTY
	 JRST VIEW1A
	PUSHJ P,GETARG
	PUSHJ P,DISINI
	SETOM VREMEM	;TRY TO DISPLAY BFR AT SAME PLACE
	 CALL CHK1A
	MOVE A,E
	SUB A,BEGV
	SKIPGE A
	 SETO A,
	MOVEM A,GEA
	.I DISADP=PT+1	;TELL DISAD WHERE TO PUT CURSOR.
	MOVEI J,DISAD
	PUSHJ P,TYPE1
VIEW1:	PUSHJ P,DISCLG
VIEW1A:	MOVE T,CPTR
	ILDB C,T
	CAIE C,"W
	CAIN C,"W+40
	SKIPN COMCNT
	 POPJ P,
	CALL RCH	;FLUSH THE "W" OF "VW".
	TRZ FF,FRARG2+FRARG+FRCLN
	JRST FTYI	;READ IN CHAR, RETURN AS NUMBER.

VIEW1B:	SKIPE DISPRR	;"@V": IN ^R MODE, DO A ^R-STYLE DISPLAY
	 JRST RRNOIN
	JRST VIEW3A	;ELSE DO STANDARD DISPLAY.

EUHACK:	CALL FFRRDD	;E^U -- READ FILENAME, THEN DO
	JRST CNTRLU	;WHATEVER DIR DISPLAY THE USER WANTS.

;COME HERE FROM GO, AFTER THE END OF A COMMAND STRING
;(WHETHER IT ENDED SUCCESSFULLY OR NOT)
;DECIDE WHETHER AND HOW TO DISPLAY.
VIEW2:	ANDCMI FF,FRCLN
	TLZE FF,FLDIRDPY	;FRCLN _ FLDIRDPY
;^U COMMAND - DO USER'S SELECTED TYPE OF DIRECTORY DISPLAY.
CNTRLU:	 IORI FF,FRCLN
	MOVE CH,QRB..
	TRNN FF,FRCLN
	SKIPA A,.QBFDS(CH)	;FLDIRDPY WAS OFF, WE WANT BUFFER DISPLAY.
	 MOVE A,.QFDDS(CH)	;IT WAS ON, WE WANT DIR DISPLAY.
	JUMPE A,VIEW3B	;USER HASN'T SUPPLIED MACRO: DO @V OR :@V.
	JRST MACXQ	;DO THE MACRO.

TYPE:	PUSHJ P,GETANU	;T COMMAND: DECODE ARGS.
	MOVEI J,FSECO2	;@T TYPES IN ECHO AREA.
	TRZN FF,FRUPRW
TYPE2:	 MOVEI J,TYO	;TYPE RANE IN E,C.
TYPE1:	MOVE IN,E
TYPE3:	SKIPN MORFLF
	 SKIPE STOPF
	  RET
	CAML IN,C
	 JRST TYPE5
	PUSHJ P,GETINC
	PUSHJ P,(J)
	JRST TYPE3

TYPE5:	CAIE J,TYO
	 SKIPN RGETTY
	  SKIPGE TYOFLG
	   POPJ P,
	JRST DISFLS	;FORCE THE TYPEOUT OUT, IF THE M.P. AREA TYPEOUT MECHANISM WAS USED.

SUBTTL BUFFER DISPLAY

;COME HERE AFTER EACH CMD STRING,
;IF USER HAS NOT SUPPLIED A MACRO TO BE INVOKED.
VIEW3B:	TRZ FF,FRARG
	MOVE TT,QRB..
	SKIPE .QVWFL(TT)
	 POPJ P,	;DON'T DISPLAY IF CMDS IN STRING INHIBITED IT.
	SKIPE RGETTY	;SHOULD WE EVER DISPLAY ON THIS TERMINAL
	 JRST VIEW3A
	TRNN FF,FRCLN	;ELSE, ON PRINTING TTY, NO DISPLAY OF DIRS,
	 SKIPN TTMODE	;BUFFER DISPLAYED ONLY IN :^N MODE.
	  RET
VIEW3A:	TRZE FF,FRCLN
	 JRST CNTRU1
	CALL VBDACU	;UPDATE TSALTC, SKIP IF OK TO DISPLAY.
	 POPJ P,
VBD:	SETO A,
	CALL VBDBLS	;MAKE SURE WE HAVE A VALID WINDOW (BLESS IT)
	JRST VBDDIS	;THEN DISPLAY FROM THERE.

VBDRR:	SETO A,
	CALL VBDBL1	;HERE TO DISPLAY FOR ^R, WITH OUTPUT AND WINDOW SET UP.  ON DISPLAYS ONLY!
	MOVEM B,RRVPOS
	JRST VBDDIS

;A/ -1 => MAKE SURE THAT WE HAVE A VALID WINDOW.
;A/ VPOS => CHOOSE WINDOW TO PUT PT AT THAT VPOS.
VBDBLS:	MOVE C,NLINES
	CALL WINSET
VBDBL1:	SETOM TYOFLG	;SINCE WE ARE SCREWING UP VPOS AND HPOS, TYPEOUT SHOULD REINIT.
			;ALSO, TYOFLG POSITIVE WITH CHCTBP ZERO CAN CAUSE CRASH IN DISFLS.
	SAVE %END
	SAVE CHCTVS	;ON PRINTING TTY'S WE MUSTN'T CHANGE THE WINDOW SIZE FOR GOOD.
	.I CHCTVS=BOTLIN ;BUT DURING BUFFER DISPLAY, RESTRICT TO # LINES.
	CALL VBDRR2	;CALCULATE NEW ABSOLUTE WINDOW ADDRESS IN A.
	.I GEA=A-BEGV
	REST CHCTVS
	REST %END
	RET

VBDRR2:	JUMPGE A,[ SETOM %END	;IF VPOS FOR PT SPEC'D EXPLICITLY, USE IT.
		   JRST VBDN5]	;ALSO TURN OFF MARGIN CHECKING FOR ZV.
	SKIPE RGETTY	;NOT DATAPOINT => NO DESIRE TO DISPLAY FROM SAME PLACE.
	 SKIPGE IN,GEA	;OR NO OLD PLACE TO START FROM =>
	  JRST VBDNEW	;START FROM SCRATCH.
	ADD IN,BEGV	;TRY THE OLD START.
	CAMLE IN,PT	;NO GOOD TO START AFTER POINTER.
	 JRST VBDNEW
	JRST VBDTRY	;ELSE SEE IF OLD WINDOW STILL GOOD.

;SET THE VARIABLES THAT DESCRIBE THE SIZE AND POSITION OF THE WINDOW
;AND THE MARGINS (REGIONS WHERE WE DON'T WANT THE POINTER TO BE); NAMELY,
;RRTOPM, RRBOTM, BOTLIN, AND VSIZE.
;C SHOULD CONTAIN NLINES (OR SOMETHING TO USE INSTEAD).
WINSET:	SAVE D
	SKIPGE C
	 SETZ C,	;NEGATIVE # LINES NOT ALLOWED.
	SAVE J
	SKIPL J,TOPLIN
	 CAML J,USZ
	  SETZM TOPLIN	;IF FS TOP LINE$ IS INVALID, SET IT TO 0 INSTEAD.
	REST J
	SKIPE C
	 ADD C,TOPLIN	;C HAS DESIRED LAST LINE (+1) TO USE, OR 0 FOR WHOLE SCREEN.
	CAML C,USZ
	 SETZ C,	;CAN'T USE MORE LINES THAN WE HAVE.
	SKIPN C
	 MOVE C,USZ	;NO SPECIFICATION, OR BAD SPEC, => USE TILL SCREEN BOTTOM.
	CAIL C,MXNVLS	;IF THAT'S INFINITELY MANY LINES, USE 2 LINES.
	 MOVEI C,2
	MOVEM C,BOTLIN	;STORE DESIRED LAST LINE (+1) IN BOTLIN.
	SUB C,TOPLIN
	MOVEM C,VSIZE
	IMUL C,%TOP	;COMPUTE MARGINS THAT CURSOR MUSN'T GO OUTSIDE.
	IDIVI C,100.
	ADD C,TOPLIN
	MOVEM C,RRTOPM
	MOVE C,VSIZE
	IMUL C,%BOTTO
	IDIVI C,100.
	SUB C,BOTLIN
	MOVNM C,RRBOTM
	JRST POPDJ

;TRY TO MAKE SURE TSALTC IS UP TO DATE.  TSALTC CAN GET WRONG IF TTY IS
;RETURNED TO DDT AND IT THROWS AWAY ALL THE INPUT.
VBDACU:	SKIPN TSALTC	;UPDATE TSALTC (IN CASE DDT HAS FLUSHED
	 SKIPE TSINAL	;THE $$'S THAT INT'D US) (SKIP IF ENDS UP 0)
	  CAIA
	   JRST POPJ1
	LISTEN CH,
	JUMPN CH,CPOPJ
	SETZM TSALTC	;NO INPUT CHARS WAITING => NO $$'S.
	SETZM TSINAL	;AND NO STRAY $.
	HRROS LTYICH
	JRST POPJ1

;COME HERE TO SEE IF THE PREVIOUS WINDOW (ADDR IN IN) CAN BE REUSED (GEA > -1).
;IN THIS CASE, CAN GO TO VBDNEW IF THE WINDOW IS BAD, OR CAN RETURN WINDOW IN A.
;COME HERE FROM VBDNEW WITH A TENTATIVE WINDOW ADDRESS IN IN (WHICH MAY BE TOO
;CLOSE TO BEG) TO FIND A MORE PRECISE WINDOW (GEA = -1).
;IN THIS CASE, C HOLDS -<DESIRED # LINES ABOVE CURSOR>, AND WE ALWAYS RETURN.
;WE ALWAYS RETURN THE NEW VPOS OF POINT IN B.
;WE SHOULD NEVER BE CALLED WITH A WINDOW THAT IS AFTER POINT.
VBDTRY:	CALL CHCTI0	;INIT VARIOUS TEMPS FOR TYPEOUT.
	SETZ T,		;INITIAL HPOS IS 0 (VBDL UPDATES)
	SETZM MORFLF	;THIS MIGHT HAVE STOPPED LAST VBDTRY.
	CALL MEMTOP	;OUT GETS ADDR OF FREE STORAGE,
	MOVE OUT,A	;FOR TABLE OF LINE-BEGINNING ADDRESSES.
	MOVE A,IN	;A _ THE START WE'RE TRYING NOW.
	CAMLE A,PT
	 .VALUE
	CALL GETIBI	;BP IN BP TO FETCH CHARS TO TYPE, STARTING AT IN.
	MOVEI TT,VBDL	;CALL VBDL TO "OUTPUT" A LINE.
	MOVEM TT,CHCTAD
	SETZB TT,CHCTBP	;TELL CHCT TO THROW AWAY CHARS.
	HLLOM TT,DISBFC	;IT WILL NEVER FILL UP ITS INFINITE SINK.
	MOVE TT,TOPLIN	;START "PRINTING" WHERE WE WILL LATER REALLY START PRINTING.
	MOVEM TT,CHCTVP
	ADD TT,OUT	;STORE BEGINNING OF 1ST LINE DISPLAYED AS 1ST CHAR DISPLAYED.
	MOVEM IN,(OUT)
VBD0:	CAMN IN,PT	;REACHED PT =>
	 JRST VBDPT	;CHECK WHETHER THIS WINDOW IS OK.
VBDPT2:	CAMN IN,ZV	;(COMES BACK IF CAN'T TELL YET,
			;NEAR END OF SCREEN BUT OK IF END OF BUFFER FITS)
	 JRST VBD3	;AT END, SEE IF MADE IT ON TO SCREEN.
	CAMN IN,GPT	;IF AT GAP, MOVE BP OVER IT.
	 CALL FEQGAP
	ILDB CH,BP
	ADDI IN,1
	CALL DISAD2	;OUTPUT NEXT CHAR.
	SKIPN MORFLF
	 JRST VBD0
	JRST VBDNEW	;OFF END OF SCREEN AND PT TOO LOW.

VBD3:	MOVE TT,CHCTVP	;REACHED ZV BEFORE FLUSHING,
	CAMN TT,BOTLIN	;WINDOW OK IF ZV IS ON SCREEN ABOVE --MORE-- LINE
	CAMN T,CHCTHP	;OR IF ZV IS ON IT BUT NO CHARS TYPED ON IT
	CAIA
	 JRST VBDNEW

;REACHED PT DURING VBD0 LOOP.
VBDPT:	SKIPGE GEA	;CAME TO VBDTRY FROM VBDNEW =>
	 JRST VBDDWN	;ZERO IN ON BEST WINDOW.
	CAMN A,BEGV	;TRYING TO RE-USE WINDOW =>
	 JRST VBDPT1	 ;UNLESS WE STARTED AT START OF BUFFER,
	MOVE TT,RRTOPM
	CAMLE TT,CHCTVP	;SHOULDN'T HAVE PT < %TOP PERCENT OF SCREEN FROM TOP.
	 JRST VBDNEW
VBDPT1:	MOVE B,CHCTVP	;MIGHT BE OK, REMRMBER # OF LINE WITH PT.
	CAMN B,BOTLIN	;IF WE'RE ON THE --MORE-- LINE
	CAMN T,CHCTHP	;WE'RE REALLY OFF BOTTOM, BAD WINDOW.
	CAIA
	 JRST VBDNEW
	CAML B,RRBOTM	;NOT IN LAST %BOTTOM PERCENT OF SCREEN OR
	CAMN IN,ZV	;ALREADY AT BUFFER END =>
	 RET		;CAN'T BE TO NEAR BOTTOM.  IT'S GOOD; RETURN IT.
	CALL DISBAR
	JRST VBDPT2	;ELSE SEE IF END OF BUFFER FITS ON SCREEN.

;CHCT CALLS HERE WITH EACH LINE DURING VBDTRY.
;SETS UP THE LINE-BEGINNING ADDRESS ENTRY FOR THE LINE.
;LEAVES HORIZ POS. START OF NEXT LINE IN T.
VBDL:	MOVE Q,CHCTVP
	MOVE TT1,Q
	ADD TT1,OUT
	MOVE T,CHCTNL	;STORE ADDRESS OF 1ST CHAR ON LINE.
	MOVEM T,1(TT1)
	MOVE T,CHCTHP	;RETURN H.P. AFTER LINE.
	MOVE TT1,GEA	;IF GOING TO GO TO VDBDWN,
	AOJE TT1,CPOPJ	;MAKE SURE ALL THE LINE'S STARTS ARE STORED.
	CAMN Q,BOTLIN	;AT BOTTOM OF SCREEN =>
	 SETOM MORFLF	;STOP THE LOOP AT VBDTRY.
	POPJ P,

;START FROM SCRATCH, FIGURING OUT A NEW WINDOW.
;RETURN THE NEW WINDOW ADDRESS IN A, AND THE NEW VPOS OF POINT IN B.
VBDNEW:	SKIPGE DISTRN
	 JRST VIEW2A	;IN TRUNCATE MODE, EVERYTHING EASIER.
	MOVE A,VSIZE	;PRETEND WE'RE STARTING AT MIDDLE OF SCREEN.
	IMUL A,%CENTER
	IDIVI A,100.
	SKIPGE A
	 SETZ A,
	MOVE T,VSIZE
	CAMG T,A
	 MOVEI A,-1(T)
	ADD A,TOPLIN
;HERE FROM RREAR3;  A HAS DESIRED VPOS OF PT.
VBDN5:	SETOM GEA	;SO NEXT TIME REACH VBDPT WON'T COME HERE AGAIN.
	CALL CHCTI0
	SETZM CHCTBP	;MAKE SURE WE DON'T TRY USING UP INFINITE AMOUNTS OF DISBUF.
	MOVEM A,CHCTVP
	SETZB T,MORFLF
	MOVE BP,PT
	CAMN BP,BEGV	;IF PT = BEGV, WINDOW MUST START AT BEGV.
	 JRST [	MOVE A,BP
		MOVE B,TOPLIN
		RET]
	MOVEI C,CPOPJ	;TELL DISAD NOT TO DO ANYTHING WITH THE LINES IT CONSTRUCTS.
	MOVEM C,CHCTAD
	SAVE CHCTVP	;SAVE TOPLINE+#CENTER.
	MOVE TT,VSIZE
	IMUL TT,%END
	JUMPL TT,VBDN6
	IDIVI TT,100.
	SAVE TT		;REMEMBER #END (TOTAL*%END/100)
	IMUL TT,NHLNS	;ARE WE WITHIN #END*WIDTH*2 CHARS OF END OF BUFFER?
	LSH TT,1
	CAIL TT,1000.	;IF NOT FOR THIS, SMALL %END'S WOULD BE IGNORED UNLESS PT VERY NEAR Z.
	 MOVEI TT,1000.	;RATHER, THEY MEAN "PUT Z VERY NEAR SCREEN END, IF IT'S ON SCREEN AT ALL"
	ADD TT,BP
	CAMGE TT,ZV	;IF SO, DON'T LEAVE MORE THAN #END BLANK LINES AT BOTTOM.
	 JRST VBDN4	 ;IF NOT, ASSUME WE WON'T LEAVE THEM & DON'T WASTE TIME.
	CAMN BP,ZV	;WE'RE AT END OF BUFFER =>
	 JRST [SOS IN,BP	   ;NEED FULL SCREEN ABOVE PT.
		CALL GETCHR ;IF LAST CHAR ISN'T LF,
		CAIE CH,^J ;MAKE SURE THE LAST UNTERMINATED LINE
		 AOS CHCTVP ;DOESN'T END UP OFF SCREEN BOTTOM.
		JRST VBDN2]
	CAMLE BP,GPT
	 ADD BP,EXTRAC
	CALL GETIBP	;SEE HOW MANY LINESOF TEXT THERE ARE BETWEEN PT AND BUFFER END.
	MOVE IN,PT
	SKIPE RGETTY
	 SKIPE RREBEG
	  CALL DISBAR	;STARTING AT THE PTR SO MAKE CURSOR (EXCEPT IN ^R ON DISPLAY TTY).
	MOVE E,BOTLIN	;IF WE GET DOWN TO VPOS = TOTAL-#END, WE CAN PUT CURSOR
	SUB E,(P)	;AT THE USUAL PLACE (#CENTER), SO STOP COUNTING LINES.
VBDN1:	CAMN IN,ZV
	 JRST VBDN2	;ALL USED UP, SEE HOW MANY LINES THAT MADE.
	CAMG E,CHCTVP
	 JRST VBDN4
	CAMN IN,GPT	;WHEN AT GAP, MOVE BP OVER GAP.
	 CALL FEQGAP
	ILDB CH,BP
	ADDI IN,1
	CALL DISAD2
	JRST VBDN1

VBDN2:	MOVE C,CHCTVP	;REACHED END OF BFR WITHOUT REACHING VPOS = TOTAL-#END.
	CAME T,CHCTHP	;MAYBE WE STARTED ANOTHER LINE NOT COUNTED IN VPOS. COUNT IT TOO
	 JRST [	CAME C,BOTLIN ;UNLESS IT'S REALLY OFF
		 AOS C		;BOTTOM OF SCREEN.
		JRST .+1]
	SUB C,A		;# LINES WE PRINTED IN VBDN1 LOOP.
	ADD C,(P)	;PLUS MAX # BLANK LINES TO LEAVE BELOW THEM,
	MOVNS C		;GIVES MAX # LINES WE CAN ALLOW BELOW PT.
	ADD C,BOTLIN	;SUBTRACT FROM WINDOW BOTTOM TO GIVE MIN VPOS FOR PT.
	MOVEM C,-1(P)	;(SMALLER THAN AND INSTEAD OF TOPLIN+#CENTER WHICH WE SAVED).
VBDN4:	SUB P,[1,,1]	;NO LONGER NEED #END.
VBDN6:	MOVNS C,(P)	;GET BACK #CENTER OR CORRECTED # OF LINES WE WANT ABOVE PT.
	ADD C,TOPLIN	;-<# LINES NEEDED ABOVE PT>
	CALL VBDN7	;IN GETS PLACE WHERE THOSE LINES START.
	REST C		;- <MINIMUM VPOS WE WANT PT TO APPEAR AT>.
	JRST VBDTRY

;RETURN IN IN THE CHAR ADDR OF A SPOT C(C) LINES UP FROM POINT.
;MORE PRECISELY, IT MUST BE AT LEAST C(C) SCREEN LINES UP, BUT MAY BE MORE,
;BUT SHOULDN'T BE TOO MUCH MORE FOR THE SAKE OF EFFICIENCY.
;LIKE DOING -<N>@L BUT WITH CUTOFF IN CASE THERE ARE NO CRLFS IN THE BUFFER.
VBDN7:	MOVE E,C		;FIND PLACE BACK FROM POINT FAR ENOUGH
	SUBI E,2		;TO FILL UP THAT MANY SCREEN LINES (PLUS 2)
	IMUL E,NHLNS		;WITH JUST CONTINUATION LINES.
	ADD E,PT
	CAMGE E,BEGV		;THERE, OR BEGINNING OF BUFFER, IS WHERE WE CUT OFF.
	 MOVE E,BEGV
	MOVE IN,PT		;NOW, LOOK BACK THAT MANY LINES FROM POINT, BUT NOT PAST THERE.
VBDN7L:	SOS IN			;LOOP HERE OVER LINES.
VBDN7C:	CAMGE IN,E		;LOOP HERE OVER CHARACTERS.
	 AOJA IN,CPOPJ
	CALL GETCHR		;EXAMINE NEXT CHAR BACK FOR BEING A LF.
	CAIE CH,^J
	 SOJA IN,VBDN7C
	CAMN IN,E
	 RET
	SUBI IN,1		;IF SO, SEE IF WHAT PRECEDES IT IS A CR.
	CALL GETINC
	CAIE CH,^M
	 SOJA IN,VBDN7C
	AOJLE C,VBDN7L		;IF SO, THAT'S ONE LINE DOWN.
	AOJA IN,CPOPJ		;WHEN WE'VE GONE ENOUGH LINES, LEAVE IN -> CHAR AFTER THE LF.

;COME HERE IN VBDTRY TO SEE WHETHER OUR GUESS FOR GEA WAS GOOD.
;IT'S NO GOOD IF POINT WOULD APPEAR FARTHER DOWN THE SCREEN THAN EXPECTED/
;SINCE WE REMEMBERED WHERE IN THE BUFFER EACH SCREEN LINE STARTED,
;WE CAN IMMEDIATELY FIND THE CHARACTER THE RIGHT NUMBER OF LINES UP FROM POINT.
;C HAS THE NUMBER OF SCREEN LINES DESIRED ABOVE POINT.
VBDDWN:	SAVE A
	SAVE RRHPOS
	SAVE RRVPOS		;FIRST WORRY ABOUT THINGS LIKE:
	.I RRHPOS=CHCTHP
	.I RRVPOS=CHCTVP
	AOSN RRNCCR		;WHAT IF POINT IS RIGHT AFTER A CR?  IN THAT CASE
	 CALL [	SOS PT		;THE CR HASN'T REALLY BEEN OUTPUT YET.
		JRST RRFORW]	;SO ADJUST OUR SCREEN POSITION TO BE AFTER THE CR.
	MOVE A,RRHPOS
	CALL RRFOR3		;ALSO, MAYBE THE NEXT CHARACTER WOULD CAUSE A CONTINUATION.
	MOVE A,RRHPOS
	MOVEM A,CHCTHP
	MOVE A,RRVPOS		;ADJUST SCREEN POSITION FOR THAT, IF NECESSARY.
	EXCH A,CHCTVP
	ADD A,OUT		;IN CASE WE DO START A CONTINUATION LINE,
	PUSH A,PT		;ENTER IN THE TABLE WHERE THAT CONTINUATION STARTS.
	REST RRVPOS
	REST RRHPOS
	REST A
	MOVN B,C
	CAMLE B,CHCTVP
	 MOVE B,CHCTVP
	ADD C,CHCTVP	;(C STILL HAD - # LINES WANTED ABOVE PTR)
	JUMPLE C,CPOPJ	;NOT MORE THAN MAX, OK.
	ADD C,TOPLIN
	ADD C,OUT
	MOVE A,(C)	;ELSE FIND 1ST CHAR ON THE LINE WE SHOULD START WITH.
	RET

;DISPLAY THE BUFFER STARTING AT THE WINDOW IN GEA.
VBDDIS:	SAVE CHCTVS
	SAVE [[ REST CHCTVS
		RET]]
	SAVE BOTLIN
	CALL DISINI	;SET UP FOR DISPLAY.
	REST BOTLIN	;DISINI RESETS BOTLIN IGNORING FS LINES, WHICH IS WRONG.
	.I CHCTVS=BOTLIN
	MOVE TT,QRB..	;DISPLAY SHOULDN'T INHIBIT ANOTHER DISPLAY OF SAME STUFF.
	SETZM .QVWFL(TT)
	SETOM VREMEM
	MOVE TT,TOPLIN
	MOVEM TT,CHCTVP
	MOVE IN,GEA
	ADD IN,BEGV
	MOVEM IN,LINBEG(TT)
VBDOK3:	MOVEM IN,CHCTBL	;REMEMBER CHAR ADDR START OF 1ST LINE
			;(DISAD WILL SET CHCTBL FOR LATER LINES)
	CALL GETIBI
	SETZM MORNXT
VBDOK1:	CAMN IN,ZV	;STOP IF NO MORE CHARS.
	 JRST DISCLG
	MOVE TT,CHCTVP	;STOP IF PAST END OF SCREEN.
	CAML TT,CHCTVS
	 CALL DISMOR	;DO IT VIA DISMOR SO WE RETURN TO ^R PROPERLY.
	SKIPN MORFLF
	 SKIPGE ORESET	;STOP IF FLUSHED OR QUITTING.
	  JRST DISCLG
	CAMN IN,PT	;OUTPUT THE CURSOR IF BEFORE PT.
	 CALL DISBAR
	CAMN IN,GPT	;IF AT GAP, MOVE B.P. IN BP OVER IT.
	 CALL FEQGAP
	MOVE TT,CHCTHP
	CAME TT,NHLNS	;IF ABOUT TO CONTINUE A LINE
	 SKIPN DISBFC	 ;OR IF THE BUFFER IS FULL,
	  JRST VBDSLO	;OUTPUT 1 CHARACTER SLOWLY TO CONTINUE OR EMPTY THE BUFFER.
	SKIPGE DISTRN
	 JRST VBDSLO
	SKIPE CASDIS	;IF WE NEED CASE-FLAGGING, OR
	 JRST VBDSLO
	SKIPL CHCTCF	;IF WE HAVE AN UNPROCESSED CR,
	 JRST VBDFAS	;MUST GO THRU DISAD SINCE ONLY DISAD KNOWS HOW TO HACK ONE.
VBDSLO:	ILDB CH,BP
	AOS IN
VBDSL1:	.I RRCCHP=CHCTHP
	CALL DISAD2	;OUTPUT THE CHAR.
	JRST VBDOK1

;IF WE GET HERE, WE KNOW WE CAN GO AT LEAST 1 CHAR BEFORE REACHING PT, GPT, ZV,
;THE RIGHT MARGIN, OR THE END OF DISBUF.
;A HAS THE HPOS TIMES 7, E HAS THE HASH CODE, BP HAS THE BP AND IN HAS THE CHAR ADDRESS.
;TT HAS THE HPOS TO STOP AT, TIMES 7.  OUT HAS THE BP TO STOP AT.  CH HOLDS THE CHAR.
VBDFAS:	MOVE OUT,BP
	MOVE BP,ZV	;CONSIDER PT, GPT AND ZV;  BP GETS WHICHEVER IS SMALLEST
	CAMGE IN,GPT
	 CAMG BP,GPT
	  CAIA
	   MOVE BP,GPT	;YET BEYOND WHERE IN IS NOW.
	CAMGE IN,PT
	 CAMG BP,PT
	  CAIA
	   MOVE BP,PT
	SOS BP		;CONVERT CHAR ADDR IN BP TO THE B.P. TO LDB THE PREVIOUS CHAR.
	CALL GETIBV
	IBP BP		;(GETIBV FOLLOWED BY IBP = GETBV).
	EXCH OUT,BP
	MOVE A,CHCTHP	;A GETS 7 TIMES THE HPOS.  WE USE IT FOR SHIFTING FOR THE HASH CODE.
	IMULI A,7	;ALSO, TT GETS 7 TIMES THE LINE WIDTH AND THAT IS AN END TEST.
	MOVE TT,NHLNS
	IMULI TT,7
	MOVE E,CHCTHC	;E IS WHERE WE ACCUMULATE THE CHECKSUM.
VBDFLP:	ILDB CH,BP
	XCT VBDTBL(CH)	;FOR FUNNY CHARS, GO SOMEPLACE ELSE.
VBDNRM:	IDPB CH,CHCTBP	;STORE CHAR INTO OUTPUT.
	ROT CH,(A)
	ADD E,CH	;UPDATE THE HASH CODE OF THE LINE.
VBDTRT:	ADDI A,7
	CAME BP,OUT	;STOP IF REACH PT, GPT OR ZV.
	 CAMN A,TT	;STOP IF REACH RIGHT MARGIN.
	  CAIA		;IN EITHER CASE, INCREMENT HPOS FOR CHAR WE JUST DID.
	   JRST VBDFLP
;HERE EITHER IN = PT,GPT OR ZV, OR ELSE WE ARE ABOUT TO CONTINUE A LINE.
;SO VBDOK1 IS GUARANTEED TO DO 1 CHAR THE SLOW WAY BEFORE VBDFAS IS REACHED.
VBDOUT:	CALL VBDSTO	;STORE BACK CHCTHC, CHCTHP, AND IN
	JRST VBDOK1

VBDTBL:	JRST VBDCTL	;^@
REPEAT 6,JRST VBDCTL	;^A THRU ^F
	JRST VBDCTL	;^G
	JRST VBDBS	;^H
	JRST VBDTAB	;^I
	JRST VBDLF	;^J
REPEAT 2,JRST VBDCTL	;^K, ^L
	JRST VBDCR	;^M
REPEAT 13.,JRST VBDCTL	;^N THRU ^Z
	JRST VBDALT	;ALTMODE
REPEAT 4,JRST VBDCTL	;^\ THRU ^_
REPEAT 137,JFCL		;NORMAL GRAPHICS CHARACTERS
	JRST VBDCTL	;RUBOUT IS LIKE A CTL CHAR.
IFN .-VBDTBL-200,.ERR WRONG TABLE LENGTH

VBDSTO:	IDIVI A,7	;CONVERT A BACK TO HPOS TIMES 1.
	EXCH A,CHCTHP	;A IS UPDATED CHCTHP
	SUB A,CHCTHP	;OLD CHCTHP MINUS NEW CHCTHP (A NEGATIVE NUMBER)
	ADDM A,DISBFC	;IS ALSO - <# OF CHARS IDPB'D>.
	MOVEM E,CHCTHC
	SAVE BP
	CALL GETCA
	AOS IN,BP
	CAMLE IN,GPT
	 SUB IN,EXTRAC
	REST BP
	RET

VBDCR:	SETOM CHCTCF	;CR => SET FLAG FOR NEXT CHAR AND HANDLE IT WITH DISAD.
	JRST VBDOUT

VBDCTL:	SKIPE DISSAI	;MOST CONTROL CHARS ARE NORMAL IN SAIL MODE, LOSING OTHERWISE.
	 JRST VBDNRM
VBDBS:: VBDLF::
VBDLOS:	CALL VBDSTO	;HERE FOR A CHAR THAT MUST BE HANDLED WITH DISAD.
	JRST VBDSL1	;WE KNOW THAT IN DOESN'T = PT, GPT, OR ZV, OR WE WOULN'T HAVE
		;GOT EVEN THIS FAR, SO IT'S SAFE TO GO STRAIGHT TO VBDSLO.

VBDALT:	MOVE TT1,TTYOPT
	TLNN TT1,%TOSAI
	 MOVEI CH,"$
	JRST VBDNRM

VBDTAB:	SAVE B
VBDTA1:	MOVEI CH,40	;OUTPUT SPACES OR %TDTSP (THE LATTER FOR LOCAL EDITING TERMINALS)
	SKIPE LEABLE
	 MOVEI CH,%TDTSP
	IDPB CH,CHCTBP
	MOVEI CH,40	;IN EITHER CASE, A SPACE GOES IN OUR HASH CODE.
	ROT CH,(A)
	ADD E,CH
	ADDI A,7	;AND INCREMENTING THE HPOS
	SAVE A
	IDIVI A,7
	IDIV A,TABWID	;TILL WE REACH A TAB STOP.
	REST A
	CAME A,TT	;THE END OF THE LINE COUNTS AS A TAB STOP.
	 JUMPN B,VBDTA1
	REST B
	SUBI A,7
	JRST VBDTRT	;RE-ENTER NORMAL LOOP, EXIT IF REACHED OBSTACLE.

VIEW2A:	MOVE C,VSIZE
	ADDI C,1	;(IF C ODD, WANT LINE WITH PT CENTERED)
	LSH C,-1
	SAVE FF
	TRZ FF,FRCLN\FRUPRW
	PUSHJ P,GETAG7	;GET 1 + LAST CHAR ADR TO PRINT IN E
	 JFCL
	MOVN C,VSIZE
	CAMN IN,BEGV	;IF BUFFER NOT EMPTY,
	 JRST VIEW2B
	SOS IN
	CALL GETINC	;LOOK AT LAST CHAR, NOT CHANGING IN.
	CAIE CH,^J	;IF NOT LF, IT COUNTS AS A LINE.
	 AOS C
VIEW2B:	PUSHJ P,GETAG4	;THEN MOVE 2*N BACKWARD FROM THERE, GET 1ST TO DISPLAY.
	 JFCL
	MOVE A,E	;DISPLAY AS MUCH AS WILL FIT.
	REST FF
	RET

SUBTTL SINGLE CHARACTER TERMINAL OUTPUT, BUFFERED

;OUTPUT ROUTINES. OUTPUT CHAR IN CH AS DESCRIBED, CLOBBERING ONLY Q.
;IN SHOULD CONTAIN 1 PLUS CHAR ADDR OF CHAR BEING OUTPUT.

;"DISPLAY" - OUTPUT CURSOR, DO CASE-FLAGGING.
DISAD:	MOVE Q,CHCTHP
	MOVEM Q,RRCCHP
	CAMN IN,DISADP	;IF THIS CHAR COMES AFTER POINTER,
	 CALL DISBAR	;OUTPUT CURSOR.

;DON'T OUTPUT CURSOR, DO CASE-FLAGGING.
DISAD2:	SKIPN CASDIS	;IF IN -1F$ MODE
	 JRST CHCT
	SAVE .-1	;DO CASE-FLAGGING: ROUTINE FOR 1 CHAR IS CHCT.

;CALL DISAD6 ? OUTPUT 1 CHAR ? POPJ P, ;TO OUTPUT A CASESHIFT IF NEC.
DISAD6:	SKIPGE CASSFT	;DON'T TRY OUTPUTTING CASESHIFT
	 POPJ P,	;IF THERE ISN'T ANY.
	CAME CH,CASSFT	;PUT CASE-SHIFTS BEFORE
	CAMN CH,CASLOK	;CASE-SHIFTS AND CASE-:LOCKS.
	 JRST DISAD3
	CAILE CH,"Z+40	;LOWER CASE SPECIAL CHARACTERS ALWAYS NEED CASESHIFTS.
	 CAIN CH,177
	  CAIN CH,"@+40
	   JRST DISAD3
	CAIL CH,"A+40	;LOWER CASE LETTERS NEED THEM IS NORMAL CASE IS UPPER.
	 CAILE CH,"Z+40
	  JRST DISAD4
	SKIPG CASNRM
	 RET
	JRST DISAD3	;PUT SLASHES BEFORE LOWER.

DISAD4:	SKIPL CASNRM	;IF NORMAL CASE IS LOWER,
	 RET
	CAIL CH,"A	;PUT CASE-SHIFTS BEFORE UPPER CASE.
	 CAILE CH,"Z
	  RET
DISAD3:	SAVE [DISAD5]	;CASESHIFT NEEDED; ARRANGE TO OUTPUT IT,
	SAVE -1(P)	;THEN POPJ TO OUTPUT ORIGINAL CHAR.
	HRLM CH,-2(P)
	MOVE CH,CASSFT
	POPJ P,		;PDL HAS 1-CHAR-RTN ? DISAD5 ? CHAR,,1-CHAR-RTN.

;OUTPUT A CURSOR.
DISBAR:	PUSH P,CH
	SKIPE RREBEG
	 JRST DISBA1
	CALL RRDIS1
	SKIPE RGETTY
	 JRST POPCHJ
DISBA1:
INSIRP PUSH P,TT TT1 BP A B
	MOVE CH,QRB..	;GET ADDR OF CURSOR QREG
	ADDI CH,.QCRSR
	CALL QLGET
	 JRST DISBA2	;NOT TEXT, NO CURSOR.
	AOSN CHCTCF	;FORCE OUT ANY BUFFERED CR BEFORE THE CURSOR.
	 CALL CHCT5
	MOVE A,BP
DISBA3:	SOJL B,DISBA2	;LENGTH OF TEXT WAS IN B,
	ILDB CH,A	;GET AND OUTPUT CHARS OF CURSOR.
	CALL [	CAIN CH,^H
		 JRST DISBBS	;OUTPUT BS AS REAL BACKSPACE.
		CAIL CH,40	;OUTPUT CTL CHARS OTHER THAN ^H IN IMAGE MODE.
		 JRST CHCT
		JRST CHCT4]
	JRST DISBA3

DISBA2:	INSIRP POP P,B A BP TT1 TT
POPCHJ:	POP P,CH
	POPJ P,

;TTY AND DISPLAY ROUTINES.
;"TYPEOUT" - DON'T TYPE CURSOR, DO NOTICE CASDIS.
TYO:	PUSHJ P,DISINT	;INIT. TYPEOUT.
	JRST DISAD2

TYANOW:	PUSHJ P,TYOA	;TYPEOUT, NO CURSOR, NO SLASH.
	JRST DISFLS	;FORCE IT OUT IMMEDIATELY.

TYOA:	PUSHJ P,DISINT	;"TYPEOUT"

;NO CURSOR, DON'T DO CASE FLAGGING.
CHCT:	SKIPE MORNXT
	 CALL DISMOR
	SKIPN ORESET
	SKIPE MORFLF	;DON'T OUTPUT AFTER -FLUSHED.
	 POPJ P,
	CAIN CH,^J
	 JRST CHCTLF	;LF => OUTPUT LINE.
	AOSN CHCTCF	;ELSE FORCE OUT SAVED UP CR.
	 CALL CHCT5B
	CAIN CH,177
	 JRST CHCT0A	;RUBOUT COMES OUT AS ^? .
	CAIL CH,40	;NON-CTL CHARS. ONE POSITION.
	 JRST CHCT1A
	CAIN CH,^I	;TAB => OUTPUT SEVERAL SPACES.
	 JRST CHCTTB
	CAIN CH,^H
	 JRST CHCTBS
	CAIN CH,^M	;REMEMBER A CR, NEXT CHAR WILL DECIDE.
	 JRST [SETOM CHCTCF ? POPJ P,]
	CAIN CH,33	;ALTMODE  => OUTPUT.
	 JRST [	SKIPE INCHSY	;USING LOCAL EDITING => SEND REAL ALTMODE.
		 JRST CHCT1A
		MOVE Q,TTYOPT
		TLNN Q,%TOSAI	;ON TERMINALS WHICH CAN HANDLE ONE, SEND REAL ALTMODE.
		 MOVEI CH,"$	;OTHERWISE SEND DOLLARSIGN.
		CALL CHCT1A
		JRST RET33]	;IN EITHER CASE DON'T CLOBBER CH.
CHCT0A:	SKIPE DISSAI	;IN SAIL MODE, CTL CHARS OUTPUT AS THEMSELVES
	 JRST CHCT1A	;AND ASSUMED TO TAKE 1 POS. ON SCREEN.
CHCT0B:	HRLM CH,(P)
	SKIPN INCHSY
	 JRST CHCT0C
	MOVEI CH,%TDMLT
	CALL CHCT4
	MOVEI CH,2
	CALL CHCT4
	HLRZ CH,(P)
	CALL CHCT4
CHCT0C:	MOVEI CH,"^	;OTHER CTL CHARS => OUTPUT "^"
	MOVE Q,TTYOPT
	TLNE Q,%TOSAI	
	 MOVEI CH,13	;(OR UPARROW, ON TTY'S WITH SAIL CHAR SET)
	CALL CHCT1A
	HLRZ CH,(P)
	XORI CH,100	;AND UN-CTLED CHAR.
	CALL CHCT
DISAD5:	HLRZ CH,(P)
	POPJ P,

;OUTPUT AN ORDINARY PRINTING CHARACTER.
;WHEN A FULL LINE HAS BEEN ACCUMULATED, CALL @CHCTAD
;WITH HASH CODE IN CHCTHC, VERT. POS. IN CHCTVP,
;HORIZ. POS. AFTER LINE IN CHCTHP.
CHCT1A:	MOVE Q,CHCTHP
	CAMGE Q,NHLNS	;IF FILLED LINE, CONTINUE IT.
	 JRST CHCT2
	PUSH P,CH
	SKIPGE DISTRN	;TRUNCATING MEANS IGNORING CHARS TILL NEXT CR.
	 JRST [	MOVEI CH,"!	;IF WE'VE JUST BEGUN TO TRUNCATE,
		SKIPL CHCIGN	;PUT IN AN EXCL.
		 CALL CHCT4
		SETOM CHCIGN	;START IGNORING MOST CHARS.
		JRST CHCT1B]
	MOVEI CH,"!
	CALL CHCT4	;PUT A ! AT END OF LINE.
	AOS CHCTHP
	MOVEM IN,CHCTNL
	SOS CHCTNL	;ADDR OF 1ST CHAR OF NEXT LINE.
	SETZM CHCTCF
	CALL CHCTL0	;NOW DO A CRLF.
CHCT1B:	POP P,CH
CHCT2:	SKIPL CHCTHP
	 CALL CHCT4	;OUTPUT THE CHAR IF NECESSARY,
	AOS CHCTHP
	RET

;PUT THE CHAR IN CH INTO THE BUFFER AND THE HASH-CODE.
;IF THE BUFFER (<- CHCTBP) IS FULL, OUTPUT IT FIRST.
CHCT4:	SKIPL CHCIGN
	SKIPN CHCTBP
	 POPJ P,
	SOSG DISBFC	;IF BUFFER FULL,FLUSH IT
	JRST [	PUSH P,CH
		SETOM CHCTNL
		MOVE CH,CHCTHP
		MOVEM CH,CHCRHP
		PUSHJ P,@CHCTAD
		POP P,CH
		JRST .+1]
	IDPB CH,CHCTBP	;STORE CHAR IN CALLER'S BUFFER.
	CAIN CH,%TDTSP
	 MOVEI CH,40

;MERGE CHARACTER IN CH INTO THE HASH CODE FOR THIS LINE.
;THE HASHING DEPENDS ON THE HPOS.  WE GET IT FROM CHCTHP.
CHCTH:	HRLM CH,(P)
	MOVE Q,CHCTHP
	IMULI Q,7
	ROT CH,(Q)
	ADDM CH,CHCTHC
	HLRZ CH,(P)
	RET

;HERE WE GET THE HPOS FROM RRHPOS.  USED FOR INSERTION OF
;SINGLE CHARACTERS, TO UPDATE THE HCODE OF THE LINE AT VPOS IN BP.
CHCTHI:	HRLM CH,(P)
	MOVE Q,RRHPOS
	IMULI Q,7
	ROT CH,(Q)
	ADDM CH,HCDS(BP)
	HLRZ CH,(P)
	RET

;HERE WE GET THE HPOS FROM RRHPOS.  USED FOR DELETION OF
;SINGLE CHARACTERS, TO UPDATE THE HCODE OF THE LINE AT VPOS IN BP.
CHCTHR:	HRLM CH,(P)
	MOVE Q,RRHPOS
	IMULI Q,7
	ROT CH,(Q)
	MOVNS CH
	ADDM CH,HCDS(BP)
	HLRZ CH,(P)
	RET

CHCTTB:	MOVEI CH,40	;TAB: OUTPUT SPACES.
	SKIPE LEABLE	;(OR, FOR LOCAL EDITING TERMINALS, OUTPUT %TDTSP
	 MOVEI CH,%TDTSP ;SO THE TERMINAL CAN TELL WHERE THE TABS WERE).
	PUSHJ P,CHCT1A
	MOVE CH,CHCTHP	;NOT AT TAB STOP =>
	SKIPN MORFLF	;GO OUTPUT ANOTHER UNLESS FLUSHED
	 CAMN CH,NHLNS	;OR WE ARE AT MARGIN, OR AT A TAB STOP.
	  JRST CHCTT1
	IDIV CH,TABWID
	JUMPN Q,CHCTTB
CHCTT1:	MOVEI CH,11
	RET

;INIT. FOR CHCT.
CHCTI0:	SETZM CHCTCF	;NO PENDING ^M.
	SETZM CHCOVP
	SETZM CHCTHP
	SETZM CHCIGN	;NOT BEYOND RIGHT MARGIN.
CHCTI1:	AOS CHCTVP
	SETZM CHCTHC	;INIT. ACCUMULATION OF HASH CODE.
	POPJ P,

;FORCE OUT CR BECAUSE FOLLOWING CHAR IS NOT LF.
;IN CONTAINS 2 PLUS CHAR ADDR OF THE CR.
CHCT5B:	SOS IN
	CALL CHCT5
	AOS IN
	RET

;OUTPUT A STRAY CR.  ;IN SHOULD HAVE 1 PLUS ADDR OF THE CR.
CHCT5:	PUSH P,CH
	SKIPL DISPCR	;-1 => DO REAL CR.
	 JRST CHCT5A
	MOVE CH,CHCTHP
	MOVEM CH,CHCRHP
	SETZM CHCTHP	;REAL CR: ZERO HORIZ POSITION,
	SETZM CHCIGN	;NO LONGER PAST RIGHT MARGIN.
	MOVEI CH,^M	;NOW FORCE OUT THE BUFFER, AND,
	CALL CHCTIM	;ON PRINTING TTY, OUTPUT A REAL CR.
	JRST POPCHJ

CHCT5A:	MOVEI CH,"^	;SHOULDN'T OVERPRINT, PRINT AS ^M.
	MOVE Q,TTYOPT
	TLNE Q,%TOSAI	
	 MOVEI CH,13	;(OR UPARROW, ON TTY'S WITH SAIL CHAR SET)
	CALL CHCT1A
	MOVEI CH,"M
	CALL CHCT1A
	MOVE CH,CHCTHP	;IF WE CONTINUE THE LINE RIGHT AFTER THE ^M, WE SHOULD REALIZE
	MOVEM CH,RRCCHP	;THAT THE NEXT CHAR STARTS IN COLUMN 0 OF NEXT LINE, NOT COLUMN -2!
	JRST POPCHJ

CHCTBS:	SKIPL DISPBS	;DISPBS < 0 => PRINT AS BS.
	 JRST CHCT0A
DISBBS:	SKIPN CHCTHP	;CAN'T DO ANYTHING AT LEFT MARGIN.
	 JRST CHCT0A	;^H AT COLUMN 0 => TYPE ^H.
	MOVE Q,CHCTHP
	MOVEM Q,CHCRHP
	SOS CHCTHP
	MOVEI CH,^H	;IF WE'RE REALLY PRINTING, OUTPUT REAL ^H.
CHCTIM:	SAVE CH
	SETOM CHCTNL
	SETOM DISFLF
	CALL @CHCTAD	;SEND WHAT WE HAVE SO FAR.
	SETZM DISFLF
	REST CH
CHCTI9:	SAVE CH
	MOVE CH,CHCTAD
	CAIE CH,DISLIN	;DON'T SEND THE ^H OR ^M IF WE'RE NOT REALLY TYPING.
	 JRST POPCHJ
	MOVE CH,CHCTVP	;NO NEED TO SEND CR NOW IF WILL MOVE DOWN ANYWAY,
	CAME CH,DISVP	;SINCE IN THAT CASE THE CURSOR MOTION WILL BE DONE BEFORE NEXT LINE.
	 JRST POPCHJ
	REST CH
	SETOM CHCOVP	;INDICATE DOING OVERPRINTING:  NEXT DISLIN MUSTN'T %TDMV1 (IMLAX LOSE).
	JRST TYOINV

;COME HERE TO OUTPUT A LF. CALLED BY THE ROUTINE TO OUTPUT STRAY CR.
;CLOBBERS ONLY Q. LEAVES A ^J IN CH.
CHCTLF:	MOVEM IN,CHCTNL
	AOSE CHCTCF	;IF HAVE UNPROCESSED CR, OUTPUT IT.
	JRST [	SKIPL DISPCR ;NO CR; WHAT DO WE DO FOR STRAY LF?
		 JRST CHCT0B	;MAYBE OUTPUT AS ^ AND J.
		MOVE Q,CHCTHP
		MOVEM Q,CHCRHP
		JRST CHCTL1]
	SETZM RRCCHP
CHCTL0:	SETZM CHCIGN	;STOP IGNORING CHARS IF HAD TRUNCATED LINE.
	MOVE Q,CHCTHP
	MOVEM Q,CHCRHP
	SETZM CHCTHP	;REFLECT IT IN HORIZ. POS.
CHCTL1:	PUSHJ P,@CHCTAD	;LF ENDS LINE, TELL CALLER ABOUT IT.
	MOVEI CH,^M	;ON NON-DISPLAY, MUST ACTUALLY DO THE CR IF WANTED.
	SKIPN CHCTCF
	 SKIPE RGETTY
	  CAIA
	   CALL CHCTI9
	PUSHJ P,CHCTI1	;INIT NEW LINE.
	SKIPL CH,CHCTNL
	 MOVEM CH,CHCTBL
	MOVE CH,CHCTVP	;IF NOW PAST END OF SCREEN, NEXT CHARACTER MUST DO A --MORE--.
	CAMN CH,CHCTVS
	 SETOM MORNXT
CHCTL4:	SKIPG CH,CHCTHP
	 JRST CHCTL3
	MOVE Q,CHCTHC	;PUT SPACES IN HASH CODE.
CHCTL2:	ROT Q,7	;FOR THE INDENT IN LINE WE'RE STARTING WITH.
	ADDI Q,40
	SOJG CH,CHCTL2
	MOVEM Q,CHCTHC
CHCTL3:	MOVEI CH,^J
	POPJ P,

SUBTTL HANDLE BOTTOM-OF-SCREEN CONDITION

;PRINT --MORE--, RETURN SETTING MORFLF IF FLUSHED, CLOBBERING ONLY Q.
;IN ^R MODE, EXIT RESTORING P FROM DISPRR.
DISMOR:	MOVE Q,CHCTAD
	CAIE Q,DISLIN		;IF NOT REALLY PRINTING OUT, DON'T DO --MORE--ING.
	 RET
	SKIPN RREBEG
	 JRST [	MOVE P,DISPRR	;IN ^R MODE: WE WANT TO POP BACK TO ^R PDL LEVEL.
		SKIPN RGETTY	;^R MODE ON PRINTING TTY:  WE'RE ALREADY IN POSITION.
		 RET
		MOVEI T,MS%DWN	;^R ON DISPLAY:  CHOOSE AMONG --TOP--, --MIDDLE--
		SKIPE GEA
		 TRO T,MS%UP
		SKIPE RRMORF	;AND --MORE-- IF FS ^R MORE IS > 0.
		 MOVEI T,MS%MOR
		SKIPGE RRMORF	;USE NONE AT ALL IF FS ^R MORE IS < 0.
		 SETZ T,
		SETZ A,
		TRNE T,MS%UP	;IF NOT SAYING --MORE-- AND HAVE TEXT ABOVE AND BELOW SCREEN,
		 CALL DISMO6	;COMPUTE FRACTION OF TEXT ABOVE
		HRLM A,T	;AND INCLUDE THAT IN THE MODE LINE.
		JRST DISMD]	;UPDATE --MORE-- LINE AND RETURN TO ^R.
	SKIPN RGETTY
	 JRST [	CALL DISFLS	;ON PRINTING TTY, JUST ASSUME FLUSHED.
		SETOM MORFLF	;AFTER PRINTING THE LF THAT CAUSED THE --MORE--
		RET]
	SKIPN ORESET
	 SKIPE MORFLF
	  RET		;ALREADY FLUSHED.
	SAVE CH
	SAVE T
	SAVE LISTF5
	SETZM MORESW
	MOVEI T,MS%MOR	;REDISPLAY --MORE-- LINE AND PUT --MORE-- ON IT.
	CALL DISMD
	SKIPGE CTLCF	;^C IMPLIES FLUSH IT.
	 JRST DISMO2
	TTYACT
IFN TNX,[SAVE ECHOF2
	SETZM ECHOF2]	;DONT ECHO IT NOW
	PUSHJ P,TYINH
IFN TNX,REST ECHOF2
	CAIN CH,40	;READ A SPACE =>
	 JRST [	SAVE CHCTHP
		SAVE CHCTHC
		PUSHJ P,DISTOP	;TOP OF SCREEN, THEN TRY AGAIN.
		REST CHCTHC
		REST CHCTHP
		SKIPL VREMEM	;IF DISPLAYING STUFF THAT'S IN BUFFER,
		 JRST DISMOX
		MOVE Q,CHCTBL	;REMEMBER WHERE THIS SCREENFULL STARTED,
		SUB Q,BEGV	;NEXT BUFFER DISPLAY WILL TRY TO START AT SAME PLACE.
		MOVEM Q,GEA
		JRST DISMOX]
	CAIE CH,177	;ELSE RE-READ UNLESS RUBOUT.
	 MOVEM CH,UNRCHC
	HRRZM P,MORFLF
	CAIE CH,177	;SET MORFLF (FS FLUSHED$) TO NONZERO, POSITIVE IFF RUBOUT.
DISMO2:	 SETOM MORFLF
	DISSTR /-FLUSHED/
	CALL DPYIVI	; INIT INVERSE VIDEO
	PUSHJ P,DISIOT	;PUT FLUSHED ON THE --MORE-- LINE
	CALL DPYIVC	; CANCEL INVERSE VIDEO
	MOVEI T,MS%FLS
	MOVEM T,MORESW	;AND REMEMBER THAT THAT IS WHAT'S THERE.
IFN TNX,[SKIPE ECHOF2
	  CALL ECHOCH]	;ECHO IT NOW
DISMOX:	REST LISTF5
	REST T
	REST CH
	RET

;A GETS PERCENT OF BUFFER ABOVE START OF WINDOW.
DISMO6:	SAVE B
	MOVE A,GEA
	ADD A,BEGV
	SUB A,BEG		;GET WINDOW START REL. TO BEG.
	MOVE B,Z
	SUB B,BEG		;GET Z REL. TO BEG.
	IMULI A,100.
	IDIV A,B		;A GETS WINDOW AS PERCENT OF Z.
POPBJ:	REST B
	RET

SUBTTL SEND THE TERMINAL OUTPUT BUFFER

;CALL HERE TO FORCE OUT BUFFERED OUTPUT.
;CALL AFTER EACH TECO COMMAND THAT DOES OUTPUT.
DISFLS:	SETOM DISFLF	;FORCE DISLIN TO MOVE CURSOR
DISFL1:	AOSN CHCTCF	;FORCE OUT ANY UNPROCESSED CR.
	 CALL CHCT5	;THIS CAN BE A SCREW IF BETWEEN THAT CR AND A LF!
	SETOM CHCTNL
	MOVE Q,CHCTHP
	MOVEM Q,CHCRHP
	PUSHJ P,DISLIN	;.IOT IT.
	SETZM DISFLF
	POPJ P,

;OUTPUT THE BUFFER.
DISLIN:	SKIPE TSALTC	;IF A CMD STRING IS WAITING TO BE READ,
	 SETOM MORFLF	;GIVE UP TYPEING OUT.
	SKIPN ORESET
	SKIPE MORFLF
	 JRST DISRST
	SAVE T
	SAVE BP
DISLI7:	SKIPN BP,CHCTVP	;IF ABOUT TO WRITE ON TOP LINE
	 JRST [	SKIPN TRCOUT	;BECAUSE OF TRACE MODE,
		 JRST .+1
		DISSTR /
/	
		CALL DISIOT	;CLEAR 1ST LINE AND USE SECOND INSTEAD.
		AOS BP,CHCTVP	;THIS WAY ERROR MESSAGES DON'T CLOBBER ANY TRACE OUTPUT.
		SETZM HCDS
		JRST .+1]
	MOVE CH,CHCTHC
	SKIPN RGETTY
	 JRST DISLI0	;ON PRINTING TTY, NO OLD LINE REMAINS ON SCREEN.

;; SET UP LINBEG OF FOLLOWING LINE, AND MAYBE MOVE TEXT BELOW UP OR DOWN ON SCREEN.
	CAML BP,CHCTVS	;IF WE'RE WITHIN THE SCREEN AREA,
	 JRST DISLI8
	SKIPN RREBEG
	 SKIPGE CHCTNL	;IN ^R, IF AFTER THIS BUFFERFULL STARTS A NEW LINE,
	  JRST DISLI8	;COMPUTE THE LINBEG WORD FOR THE LINE THAT WILL FOLLOW THIS ONE:
	MOVE T,RRCCHP	;STARTING HPOS IS CURRENT HPOS UNLESS
	CAME T,CHCTHP	;WE ARE CONTINUING IN MIDDLE OF A CHAR,
	 SUB T,NHLNS	;IN WHICH CASE IT IS MINUS THE NUMBER
			;OF POSITIONS USED ON PREV. LINE BY THIS CHAR.
	LSH T,33	;PUT STARTING HPOS IN TOP 9 BITS.
	ADD T,CHCTNL	;PUT STARTING PT OF LINE IN LOW 33 BITS.
	SKIPG Q,RRIDLB	;IF CAN INSERT/DELETE, SEE IF THAT TEXT IS PRESENT ON THE SCREEN
	 JRST DISLI8
	CAMN Q,T
	 JRST DISLI9	;AND IF SO, MOVE IT TO THE LINE AFTER THIS ONE.
	CAML T,Q	;IF WE HAVE ALREADY HACKED RRIDLB AND PASSED IT, DO NOTHING NOW.
	 JRST DISLI8
	SUB Q,RRIDBK	;ELSE MAYBE WE HAVE REACHED THE BLANK LINES PRECEDING RRIDLB.
	SUB Q,RRIDBK
	CAMG T,Q
	 JRST DISLI8
	SUB T,Q		;IF SO, FIGURE OUT FROM RRIDBK HOW MANY BLANK LINES REMAIN
	ASH T,-1	;TO BE PRINTED, AND FROM THAT, WHAT VPOS TO COPY RRIDLB TO.
	SUB T,RRIDBK	;BUT THERE IS A FUNNY WAY TO TELL DSLID THAT.
	ADDM T,RRIDVP
DISLI9:	CALL DSLID	;MOVE THE TEXT ACCORDING TO Q AND BP.
	 JFCL
	SETOM RRIDLB	;DON'T TRY TO MOVE IT AGAIN; WOULD GET CONFUSED.

;; WE ARE NOW FINISHED WORRYING ABOUT MOVING THE TEXT BELOW THIS LINE ON THE SCREEN.
DISLI8:
IFN ITS,[MOVE Q,[.BYTE 8 ? %TDNOP ? %TDNOP ? %TDNOP ? %TDNOP]
	MOVEM Q,DISBF1	;INITIALLY ASSUME NO POSITIONING NEEDED
	MOVEM Q,DISBF1+1
]
IFN TNX,[
	SETZM DISBF1	;CLEAR OUT CURSOR POSITIONING
	MOVE Q,[DISBF1,,DISBF1+1]
	BLT Q,DISBF1+5
]
	CAML BP,CHCTVS	;IF MOVING CURSOR TO BOTTOM OF SCREEN, DON'T CLEAR THE LINE.
	 JRST [	MOVEM BP,DISVP
		MOVEM BP,DISVP1
		JRST DISLI4]
	AOSG CHCOVP
	 JRST DISLI1
	AOSG ERRFL1	;IF ERRFL1 (FS ERRFLG$) IS <0, IT IS - # LINE OF ERROR MSGS ON SCREEN,
	 JRST DISLN5	;SO COUNT OFF THAT MANY LINES BEFORE OUTPUTTING.
	CAME CH,HCDS(BP) ;IF HASH CODE DOESN'T MATCH, OUTPUT THE LINE.
	 JRST DISLI4
	CAME BP,DISVP	;ELSE IF DISFLF IS SET AND CURSOR NOT ON PROPER LINE ALREADY,
	 SKIPN DISFLF	;OUTPUT ANYWAY.
	  JRST DISLN5
DISLI4:	SKIPE NOCEOL		;IF WE SHOULD CLEAR THE LINE,
	 JRST [ MOVE T,CHCRHP	;BUT TERMINAL DOESN'T KNOW HOW,
		SUB T,LINEND(BP) ;DO IT BY OUTPUTTING EXTRA SPACES AT THE END
		MOVEM T,EOLFLG	; COMPUTE HOW MANY SPACES TO USE.
		MOVEM BP,DISVP	;IF EOLFLG IS >0, NO CLEARING IS DONE.
			;IN THIS CASE, WE CLEAR EVEN IF BP=DISVP
			;FOR THE SAKE OF RRLP2C.  RRLCHG SETS THE LINEND WORD TO 0
			;TO INHIBIT THE CLEARING.
		JRST .+1]
IFN ITS,[
	DPB BP,[DISCPV]	;PREPARE TO SET VERT. POS.
	DPB BP,[DISC1V]
	MOVE Q,DISCM1	;IF SAME LINE AS BEFORE, JUST MOVE CURSOR;  DON'T CLEAR.
	MOVEM Q,DISBF1+1
	CAMN BP,DISVP
	 JRST DISLN3
	MOVE Q,DISCMV
	LDB T,[DISCPH]
	JUMPN T,[	;IF NOT STARTING IN COL 0, MUST GO TO COL 0, CLEAR, THEN SET CURSOR.
		MOVEM Q,DISBF1
		JRST DISLN3]
	MOVEM Q,DISBF1+1 ;IF STARTING IN COL 0, JUST GO TO COL 0 AND CLEAR.
	JUMPE BP,DISLN3
IFN LINSAV,[
	SKIPE LBLLIM		;IF WE MIGHT CALL SAVLIN, WHICH WOULD MOVE THE CURSOR,
	 JRST DISLN3		;DON'T USE A RELATIVE MOTION OPERATION.
]
	MOVEI T,-1(BP)	;IF MOVING DOWN 1 LINE, AND GOING TO COL 0, DO IT WITH A %TDCRL.
	MOVE Q,[.BYTE 8 ? %TDNOP ? %TDNOP ? %TDNOP ? %TDCRL]
	CAMN T,DISVP1
	 MOVEM Q,DISBF1+1
DISLN3:
]
IFN TNX,[
	MOVEI Q,DISMOV	;ASSUME CLEAR TOO
	CAMN BP,DISVP
	 MOVEI Q,DISMV1	;DONT NEED TO
	CALL (Q)	;SET UP DISBF1 RIGHT
]
	MOVEM BP,DISVP1	;REMEMBER WHAT LINE THE CURSOR IS ON.
	JRST DISLN4	;GO OUTPUT POSITIONING & LINE.

DISLI0:	SKIPL DISVP	;ON PRINTING TTY,
	 CAMN BP,DISVP	;IF NOT SAME LINE AS BEFORE, LINEFEED.
	  JRST DISLI1
IFN ITS,[HRROI Q,[ASCIC/
/]
	CALL DISIOT
]
IFN TNX,CALL ECHLF2
	JRST DISLN4

DISLN4:	SKIPN RGETTY	;HERE WHEN WE KNOW WE MUST OUTPUT THE LINE.
	 JRST DISLI1
	MOVE T,INCHCT	;IF "DISPLAYING" PRE-ECHOED INPUT,
	CAMG T,INCHEC	;DON'T ACTUALLY OUTPUT ANYTHING.  JUST PRETEND WE DID.
	 JRST DISLI3
IFN LINSAV,[
	SKIPE LBLLIM	;SAVE OLD CONTENTS OF LINE,
	 CALL SAVLIN	;TO BE BROUGHT BACK ONTO SCREEN LATER WHEN WE WANT TO.
	SKIPE LBLLIM
	 CALL RSTLIN	;IF THE NEW CONTENTS ARE STORED UNDER A LABEL, RESTORE.
]
	SKIPN INCHSY
	 JRST DISLI1
	MOVEI Q,%TDCTE	;IF LINE IS CONTINUED AT END, OUTPUT A %TDCTE WITH IT.
	MOVE T,CHCRHP
	CAMLE T,NHLNS
	 IDPB Q,CHCTBP
	MOVEI Q,%TDCTB
	MOVE T,LINEND-1(BP)
	CAME BP,TOPLIN	;IF LINE IS A CONTINUATION, OR IS TOP LINE AND THEREFORE
	 CAMLE T,NHLNS	;MIGHT BE A CONTINUATION, OUTPUT A %TDCTB WITH IT.
	  IDPB Q,CHCTBP
DISLI1:	SKIPGE Q,CHCTBP	;GET THE STUFFING B.P. AND MAKE NORMALIZE IT
	 SUB Q,[400000,,1]	;BY CONVERTING 441000,,FOO TO 041000,,FOO-1
	SETZ T,
DISLI2:	TLNE Q,700000	;COUNT THE NUMBER OF UNUSED BYTES IN THE LAST WORD
	 AOJA T,[IBP Q ? JRST DISLI2]	;OF THE OUTPUT BUFFER.
	MOVEI Q,1-DISBF1(Q)
	LSH Q,2
	SUBM Q,T	;# OF CHARS TO BE OUTPUT.
	CALL DISSIOT	;OUTPUT THAT MANY CHARS STARTING AT DISBF1
DISLI3:	SKIPE RGETTY
	 CAML BP,CHCTVS	;STORE NEW HASHCODE.
	  JRST DISLN5
	MOVE T,CHCRHP	;RECORD HPOS OF END OF LINE.
	MOVEM T,LINEND(BP)
	MOVE CH,CHCTHC
	MOVEM CH,HCDS(BP)
DISLN5:	MOVEM BP,DISVP	;INDICATE WHERE WE HAVE PUT THE CURSOR.
	MOVEI T,1(BP)
	SKIPE RGETTY	;ON A DISPLAY, CONSIDER STOPPING OUTPUT BECAUSE OF INPUT AVAIL.
	 CAML T,CHCTVS	;AVOID BOUNDARY LOSSAGE:  DON'T STOP ON --MORE-- LINE
	  JRST DISLN1	;OR THE LINE BEFORE IT (WOULD SET --MORE-- LINE'S LINBEG).
	SKIPN RREBEG
	 SKIPGE CHCTNL	;IF AFTER THIS BUFFERFULL STARTS A NEW LINE,
	  JRST DISLN1
;SET UP LINBEG WORD FOR LINE AFTER THIS ONE, IN CASE WE DECIDE TO STOP DISPLAYING NOW.
;IF WE DO, THE LINBEG WORD FOR THE NEXT LINE IS NECESSARY FOR STARTING UP AGAIN.
	MOVE T,RRCCHP	;STARTING HPOS IS CURRENT HPOS UNLESS
	CAME T,CHCTHP	;WE ARE CONTINUING IN MIDDLE OF A CHAR,
	 SUB T,NHLNS	;IN WHICH CASE IT IS MINUS THE NUMBER
			;OF POSITIONS USED ON PREV. LINE BY THIS CHAR.
	LSH T,33	;PUT STARTING HPOS IN TOP 9 BITS.
	ADD T,CHCTNL	;PUT STARTING PT OF LINE IN LOW 33 BITS.
	SETZM DISFLF	;IN CASE WE EXIT, MAKE SURE DISFLF DOESN'T STAY SET.
	MOVE Q,CHCTNL
	CAMLE Q,RRMAXP	;IF NEXT LINE STARTS PAST THE END OF ALL CHANGES,
	 SKIPL RRMSNG	;AND ALL UNCHANGED LINES ARE PROPERLY ON THE SCREEN, MAYBE WE CAN STOP.
	  JRST DISLN2
	MOVE Q,LINBEG+1(BP)
	ADD Q,ZV	;IF WE ARE ABOUT TO DISPLAY THE SAME CHARACTERS THAT ARE ON THE LINE
	SUB Q,RROLZV	;ALREADY (TAKING INTO ACCOUNT INSERTIONS AND DELETIONS SINCE
	CAMN T,Q	;OLD LINBEG WAS STORED), THEN WE NEED NOT REALLY REDISPLAY.
	 JRST RRDISF	;SO STOP DISPLAYING AND RETURN TO ^R.
DISLN2:	AOS BP
	MOVEM T,LINBEG(BP)
	MOVEM BP,RRMNVP	;IF THERE IS INPUT, STOP DISPLAYING;  LATER START FROM NEXT LINE.
	SKIPL RRMSNG	;IF WE ARE MOVING PAST THE RRMSNG LINE, MOVE RRMSNG ALONG.
	 CAMG BP,RRMSNG
	  CAIA
	   MOVEM BP,RRMSNG
	SETZM RRMNHP	;THUS MAKE SURE REDISPLAY STARTS THIS FAR UP AT LEAST.
	SKIPE DFORCE	;FS DFORCE$ MEANS FINISH DISPLAY EVEN IF INPUT IS WAITING.
	 JRST DISLN1
	CAMN BP,RRIDVP	;DON'T STOP DISPLAY JUST AFTER CLOBBERING LINBEG RECORDING
	 SKIPG RRIDLB	;THE TEXT WE WANT TO MOVE ON THE SCREEN.
	  CAIA		;ELSE COULD CAUSE I/D LINE NOT TO BE USED IN AUTO FILL
	   JRST DISLN1	;IF WE STOP DISPLAY HERE NOW AND AGAIN ONE LINE LOWER.
	MOVE T,INCHCT
	CAMN T,INCHEC	;DON'T PRE-EMPT DURING "DISPLAY" CALCULATIONS
	 JRST DISLN1	;AFTER INPUT THAT WAS PRE-ECHOED, SO IT DOESN'T MIX
			;WITH INPUT THAT WE REALLY DO HAVE TO OUTPUT FOR.
IFN ITS,[
	SKIPE DWAIT	;FOR VERY SLOW TTYS, WAIT BETWEEN LINES SO WE STOP DISPLAYING FAST
	 .LISTEN T,	;WHEN THERE IS TYPE-IN.
	.STATUS CHTTYI,T	;ARE CHARS AVAILABLE FOR ^R TO PROCESS?
	ANDI T,2000	;IF SO, STOP DISPLAYING AND PROCESS THEM.
]
IFN TNX,[
	SAVE A
	SAVE B
	MOVEI A,.CTTRM
	SKIPE DWAIT		;DO DOBE ONLY IF SLOW TERMINAL
	 DOBE			;(DONT USE LISTEN MACRO)
	SIBE			;ANY CHARACTERS FOR ^R TO PROCESS?
	 TDZA T,T		;YES
	 SETO T,		;NO
	REST B
	REST A
]
	JUMPN T,DISLN1
;WE HAVE INPUT; STOP DISPLAY.
	CALL DBGBFI		;SAVE UP SOME INFO FOR DEBUGGING.
	 SKIPE LID		;IF CAN DO INSERT/DELETE, SET RRMSNG INSTEAD OF UPPING RRMAXP
	 JRST [	MOVE T,BOTLIN	;SINCE LATTER WOULD PREVENT THIS INPUT CHAR
		SKIPL RRMSNG	;FROM INSERTING OR DELETING LINES.
		 CAMGE T,RRMSNG
		  MOVEM T,RRMSNG
		JRST RRDISX]
	MOVE T,CHCTNL		;MAKE SURE NEXT REDISPLAY DOESN'T
	CAMLE T,RRMAXP		;STOP BEFORE REACHING THIS FAR DOWN.
	 MOVEM T,RRMAXP		;WITHOUT THIS, <CR> <RUB> <RUB> LOSES IF THE TWO
	JRST RRDISX		;RUBOUTS STOP DISPLAY, 1ST AT LINE 15 (SAY), THEN AT LINE 12.

DISLN1:	REST BP
	REST T
DISLI6: MOVE Q,CHCTHP		;REMEMBER STARTING HORIZ POS. OF NEXT LINE.
IFN ITS,DPB Q,[DISCPH]
IFN TNX,MOVEM Q,DISCPH
DISRST:	MOVE Q,[441000,,DISBUF]
	MOVEM Q,CHCTBP	;RE-INIT BUFFERING.
	MOVEI Q,4*DISBFC-6
	MOVEM Q,DISBFC
	POPJ P,

;HERE IN REDISPLAY ON TERMINALS WITH INSERT/DELETE LINE
;WHEN WHAT'S LEFT ON THE SCREEN BELOW CURSOR IS VALUABLE, IF MOVED TO THE RIGHT PLACE.
;WE MOVE IT THERE AND THEN RESUME DISPLAYING.
;BP HAS VPOS OF LINE ABOUT TO BE OUTPUT, WHEN CALLED FROM DISLIN.
;THIS MEANS THAT FOR UPWARD MOTION WE MOVE THINGS UP TO LINES STARTING FROM 1(BP),
;WHEREAS FOR DOWNWARD MOTION WE MOVE DOWN FROM LINES STARTING FROM (BP).
;THE DISTANCE THAT LINES MOVE ACROSS IS (RRIDVP)-(BP)-1 IN EITHER CASE.
;OTHER CALLERS MUST ARRANGE BP AND RRIDVP ACCORDINGLY.
;WE CLOBBER ONLY Q.
;SKIPS IF WE REALLY DO MOVE TEXT.
DSLID:	MOVE Q,RRIDVP	;GET OLD POSITION OF TEXT WE WANT TO MOVE UP OR DOWN.
	SUBI Q,1(BP)	;Q GETS # LINES TO MOVE IT UP (OR - # TO MOVE IT DOWN).
;Q=0 IS A SPECIAL CASE- NO MOTION OF THE STUFF ON THE SCREEN IS NECESSARY!
	JUMPE Q,CPOPJ	;THE NON-INSERT-DELETE MECHANISMS FOR RROLZV WILL WIN IN THIS CASE.
IFN ITS,[SAVE 0		;PUSH THE CURRENT CURSOR POS SO WE CAN AVOID CHANGING IT.
	SYSCAL RCPOS,[%CLIMM,,CHTTYO ? %CLOUT,,(P)]
	 .LOSE %LSFIL
]
.ELSE	SAVE TTLPOS
	SAVE Q
	SAVE BP
	JUMPL Q,DSLIDD
;WE WANT TO MOVE STUFF UP.
	AOS BP
	ADD BP,-1(P)	;CHECK FOR SCREW CASE THAT THERE REALLY AREN'T ANY USEFUL LINES
	CAML BP,BOTLIN	;LEFT TO MOVE UP.  IF WE DIDN'T CHECK, DSLID5 WOULD CLOBBER LOW CORE.
	 JRST DSLID4
	SUB BP,BOTLIN
	MOVNS BP	;HOW MANY LINES ARE WE PRESERVING?
	IMULI BP,5	;IF IT'S NOT AT LEAST 1/5 AS MANY AS HOW FAR WE ARE MOVING THEM,
	CAMGE BP,Q	;GIVE UP AND REWRITE THEM ALL.
	 JRST DSLID4
	MOVE BP,INCHCT	;IF "DISPLAYING" PRE-ECHOED INPUT,
	CAMG BP,INCHEC	;DON'T ACTUALLY OUTPUT ANYTHING.
	 JRST DSLID8
IFN LINSAV,[
	SKIPN LBLLIM
	 JRST DSLIDE
	MOVE BP,(P)
	AOS BP
DSLIDB:	CALL SAVLIN	;TELL TERMINAL TO REMEMBER THE LINES WE ARE
	CAMG BP,RRIDVP	;PUSHING OFF THE SCREEN.
	 AOJA BP,DSLIDB
DSLIDE:] ;LINSAV
	MOVE BP,(P)
	AOS BP
	SKIPGE LID	;TERMINAL CAN SCROLL MIDDLE OF SCREEN?
	 JRST [CALL SCRLUP	;YES, SCROLL Q LINES UP THEN
	       JRST DSLID8]
	CALL DELLIN	;DELETE THAT MANY LINES BELOW WHERE CURSOR IS NOW.
	MOVE BP,BOTLIN
	SUB BP,-1(P)
	MOVE Q,-1(P)	;NOW GO THAT MANY LINES ABOVE MODE LINE (TO WHERE TEXT OF MODE LINE IS)
	CALL INSLIN	;AND INSERT EMPTY LINES TO PUSH MODE LINE BACK TO RIGHT PLACE.
DSLID8:	MOVE Q,(P)
	AOS BP,Q		;Q GETS NEW VPOS OF UPPERMOST LINE MOVED UP.
	ADD BP,-1(P)	;BP GETS THE VPOS IT CAME FROM.
	SAVE A
DSLID5:	MOVE A,LINBEG(BP)	;COPY UP THE LINBEGS FOR THE LINES MOVED UP.
	MOVEM A,LINBEG(Q)
	MOVE A,LINEND(BP)
	MOVEM A,LINEND(Q)
IFN LINSAV,[
	MOVE A,LINLBL(BP)
	MOVEM A,LINLBL(Q)
]
	MOVE A,HCDS(BP)
	MOVEM A,HCDS(Q)		;ALSO COPY THE HASH CODES OF THE COPIED LINES.
	AOS BP
	AOS Q
	CAMGE BP,BOTLIN	;STOP WHEN BP POINTS AT THE WINDOW END, WHICH WASN'T MOVED UP.
	 JRST DSLID5
	SKIPGE RRMSNG
	 JRST DSLIDA
	MOVN A,-2(P)	;RRMSNG, IF NOT -1, MUST RELOCATE WITH THE TEXT IT REFERS TO.
	ADDM A,RRMSNG
	SKIPGE RRMSNG	;BUT DON'T LET RELOCATION MAKE IT NEGATIVE, SINCE THAT IS DIFFERENT.
	 SETZM RRMSNG
DSLIDA:	SKIPL RRMSNG
	 CAMGE Q,RRMSNG	;THE INSERTED BLANK LINES NEED REDISPLAY,
	  MOVEM Q,RRMSNG ;EVEN THOUGH THERE MAY BE NO CHANGES TO THE BUFFER THAT FAR DOWN.
	REST A
DSLID6:	SETZM HCDS(Q)	;ZERO THE HASH CODES FOR THE INSERTED BLANK LINES.
IFN LINSAV,SETOM LINLBL(Q)
	SETZM LINEND(Q)
	AOS Q
	CAMGE Q,BOTLIN
	 JRST DSLID6
DSLID3:	MOVE BP,-2(P)	;NOW RESTORE CURSOR TO POSITION IT HAD ON ENTRY TO DSLID.
	CALL SETCU1
	AOS -3(P)
DSLID4:	REST BP		;SO THAT WE FILL IN THOSE BLANK LINES.
	REST Q
	JRST POP1J

;HERE TO MOVE TEXT DOWNWARD.
DSLIDD:	MOVMS -1(P)	;GET POSITIVE # OF LINES TO MOVE DOWN.
	MOVE BP,BOTLIN
	SUB BP,-1(P)
	MOVE Q,BP
	SOS Q
	CAMG Q,(P)	;DETECT FUNNY CASE WHERE THE NUMBER OF LINES LEFT IS LESS THAN
	 JRST DSLID4	;THE DISTANCE DOWN WE MUST MOVE THEM.  GIVE UP IN THAT CASE.
	SUB Q,(P)	;GET NUMBER OF LINES TO BE PRESERVED.
	IMULI Q,5	;IF THAT ISN'T AT LEAST 1/5 THE DISTANCE THEY ARE MOVING, DON'T BOTHER.
	CAMGE Q,-1(P)
	 JRST DSLID4
	MOVE Q,INCHCT	;IF "DISPLAYING" PRE-ECHOED INPUT,
	CAMG Q,INCHEC	;DON'T ACTUALLY OUTPUT ANYTHING.
	 JRST DSLID9
IFN LINSAV,[
	SKIPN LBLLIM
	 JRST DSLIDF
	SAVE BP
DSLIDC:	CALL SAVLIN	;TELL TERMINAL TO REMEMBER THE LINES WE ARE
	CAMGE BP,BOTLIN	;PUSHING OFF THE SCREEN.
	 AOJA BP,DSLIDC
	REST BP
DSLIDF:] ;LINSAV
	MOVE Q,-1(P)
	SKIPGE LID	;TERMINAL CAN SCROLL MIDDLE?
	 JRST [MOVE BP,(P)	;YES, GET TOP LINE AGAIN
	       CALL SCRLDN	;SCROLL Q LINES DOWN
	       JRST DSLID9]
	CALL DELLIN	;FIRST, DELETE SOME LINES JUST ABOVE THE MODE LINE.
	MOVE BP,(P)
	MOVE Q,-1(P)
	CALL INSLIN	;THEN, INSERT THE SAME NUMBER JUST BELOW THIS LINE.
DSLID9:	MOVE Q,BOTLIN
	SOS Q
	MOVE BP,Q
	SUB BP,-1(P)
	SAVE A
	SAVE LINBEG+1(BP)	;REMEMBER LINBEG OF FIRST LINE THAT MOVES OFF SCREEN BOTTOM.
DSLID1:	MOVE A,LINBEG(BP)	;COPY DOWN THE LINBEGS FOR THE LINES MOVED DOWN.
	MOVEM A,LINBEG(Q)
	MOVE A,LINEND(BP)
	MOVEM A,LINEND(Q)
IFN LINSAV,[
	MOVE A,LINLBL(BP)
	MOVEM A,LINLBL(Q)
]
	MOVE A,HCDS(BP)
	MOVEM A,HCDS(Q)		;ALSO COPY THE HASH CODES OF THE COPIED LINES.
	SOS BP
	SOS Q
	CAML BP,-2(P)		;STOP AFTER MOVING THE HIGHEST LINE TO BE MOVED.
	 JRST DSLID1
	LDB A,[3300,,LINBEG+1(Q)]	;PREVENT DISPLAY FROM STOPPING INSIDE THE
	ADD A,ZV		;NEWLY CREATED BLANK SCREEN LINES
	SUB A,RROLZV		;BY SETTING RRMAXP TO A VALUE JUST HIGH ENOUGH
	CAMLE A,RRMAXP		;TO PREVENT STOPPING THERE.
	 MOVEM A,RRMAXP
DSLID7:	MOVE A,LINBEG+1(BP)	;FILL THE LINBEGS OF THE NEWLY CREATED BLANK LINES WITH
	MOVEM A,LINBEG(Q)	;SOMETHING MEANINGFUL:  THE LINBEG OF THE FIRST FOLLOWING LINE.
	SETZM HCDS(Q)		;CLEAR THE HASHCODES OF THE NEWLY MADE BLANK LINES.
	SETZM LINEND(Q)
IFN LINSAV,SETOM LINLBL(Q)
	CAIE Q,1(BP)
	 SOJA Q,DSLID7
	REST A			;GET BACK LINBEG OF LINE MOVED OFF BOTTOM OF SCREEN.
	SKIPN DFORCE		;DFORCE => MODE LINE SHOULD NOT BE UPDATED BY THIS REDISPLAY.
	 SKIPL RRMSNG		;IF RRMSNG IS SET THEN THE LINBEGS AREN'T EVEN VALID FOR
	  JRST DSLID2		;WHAT FOLLOWS, BUT SOMEONE ELSE WILL HANDLE IT.
	SKIPL RRMORF
	 CAMN A,RROLZV		;IF THERE WAS DISPLAYED TEXT ON THAT LINE,
	  JRST DSLID2
	MOVE A,MORESW		;THEN THERE IS NOW TEXT PAST BOTTOM.
	TRON A,MS%DWN		;THIS FACT MUST GO IN MORESW FOR RRWBLS EVEN IF NO REDISLPLAY.
	 TRO A,MS%LOS		;BUT IF MODE LINE IS NOW OBSOLETE, MAKE IT GET REDISPLAYED.
	TRO A,MS%PCT		;MAKE SURE --NN%-- IS RECALCULATED IN CASE CHANGED.
	SKIPE RRMORF
	 MOVEI A,MS%MOR
	MOVEM A,MORESW
DSLID2:	REST A
	JRST DSLID3

SUBTTL INITIALIZE DISPLAY OUTPUT

;INIT FOR DISPLAY OUTPUT.
DISINI:	SETOM TYOFLG	;"TYPEOUT" NO LONGER INITTED.
	SETOM ECHCHR	;IF ^R COMMAND DOES DISPLAYING IT SHOULDN'T BE ECHOED ON PRINTING TTY.
	MOVE Q,QRB..
	SETOM .QVWFL(Q)
DISIN0:	SETZM VREMEM
DISTO1:	PUSHJ P,CHCTI0	;INIT FOR CHCT.
	MOVEI Q,DISLIN	;TELL IT TO CALL DISLIN EACH LINE.
	MOVEM Q,CHCTAD
	PUSHJ P,DISLI6	;INIT. BUFFERING.

;MOVE TO TOP OF SCREEN.  CLOBBERS ONLY Q.
DISTOP:	AOSN PJATY
	 JRST [	CALL CTLL1
		JRST DISTO1 ]	;REINIT IN CASE FS REDISPLAY$ DID SOME TYPEOUT.
	SETZM MORFLF	;UNDO A FLUSHED.
	SETZM MORNXT
	SETZM OLDFLF
	SETOM DISVP
	SETZM DISVP1
	MOVE Q,USZ
	MOVEM Q,CHCTVS
	SKIPN RGETTY
	 JRST [	SETZM TOPLIN
		SKIPE RUBENC	;ON PRINTING TTY, NORMALLY ADVANCE TO CLEAN LINE,
		 JRST RUBEND	;BUT DO SOMETHING SPECIAL IF WAS PREARRANGED.
		JRST CRIF]
	SAVE C
	MOVE C,NLINES	;SET UP WINDOW SIZE FROM USER-SETTABLE FLAGS (LINES AND TOPLINE).
	CALL WINSET
	REST C
	MOVE Q,TOPLIN
	MOVEM Q,CHCTVP
	MOVE Q,BOTLIN
	SKIPN RGETTY
	 MOVE Q,USZ
	MOVEM Q,CHCTVS
	SKIPGE ERRFL1
	 RET
	JRST HOMCUR	;BRING CURSOR TO TOP LEFT.

;START "TYPEOUT" AT TOP OF SCREEN.
DISTOT:	SETOM TYOFLG	;FORCE RE-INIT.

;INIT FOR TYPEOUT, PREVENT BUFFER DISPLAY.
;ALL TYPEOUT ROUTINES MUST COME HERE.
DISINT:	MOVE Q,QRB..
	SETOM .QVWFL(Q)
	SETOM ECHCHR	;IF ^R COMMAND DOES TYPEOUT IT SHOULDN'T BE ECHOED ON PRINTING TTY.
	AOSN TYOFLG	;IF NO PREVIOUS TYPEOUT,
 	 JRST DISIN0
	SKIPE RUBENC
	 CALL RUBEND
	RET

CTLL:	SKIPLE CLRMOD	;SCREEN-CLEARING MAY BE DISABLED.
	 RET
	MOVE Q,QRB..
	SETZM .QVWFL(Q)	;ALLOW BUFFER DISPLAY.
	SETOM TYOFLG	;NEXT TYPEOUT WILL START AT TOP OF SCREEN.
	SETOM GEA	;ALLOW NEW TEXT WINDOW TO BE CHOSEN.
	SETZM MORFLF	;FLUSHING A --MORE-- DOESN'T LAST PAST CLEARING THE SCREEN.
	SETZM OLDFLF
	SKIPGE PJATY
	 JRST CTLL1
	SKIPE RGETTY
	 SKIPN NLINES	;IF NOT USING WHOLE SCREEN FOR WINDOW NOW,
	  SKIPE TOPLIN	;CLEAR JUST WHAT'S IN THE WINDOW.
	   JRST CTLL2
	JRST CTLL3

;HERE TO DO A REAL CLEAR-SCREEN BECAUSE TTY WAS TAKEN AWAY.
CTLL1:	SETZM INCHSY	;TERMINAL HAS STOPPED USING LOCAL EDITING;
	SETZM INCHRQ	;WE MUST ASK IT TO RESYNCH WITH US.
	SETOM INCHEC	;NOT PROCESSING PRE-ECHOED CHARS NOW.
CTLL3:	SETZM PJATY	;HERE TO CLEAR WHOLE SCREEN.
	SETZM MORESW	;BE AWARE THAT --MORE-- IS BEING ERASED.
	SETZM ECHACT	;ECHO AREA IS NOW CLEAR.
	SETZM ECHONL
	CALL ECHOHU	;HOME UP ECHO AREA CURSOR
			;DO IT BEFORE CLRSCN SO CURSOR DOESN'T ACTUALLY
			;MOVE THERE ON ITS.
	CALL CLRSCN	;CLEAR SCREEN.
	SETOM RROVPO	;SHOW RRTTY THAT IT NEEDN'T ECHO THE COMMAND.
	SETOM DISOMD	;REDISPLAY THE "MODE" ON THE --MORE-- LINE.
	SETZM HCDS	;SET HASH CODES TO 0
	MOVE Q,[HCDS,,HCDS+1]
	BLT Q,HCDSE-1	;SINCE 0 IS CODE FOR A NULL LINE
	SETZM LINEND	;STORE LINE END HPOS AS 0 FOR EACH LINE.
	MOVE Q,[LINEND,,LINEND+1]
	BLT Q,LINEND+MXNVLS-1
	SKIPN REFRSH	;IF USER HAS A REFRESH ROUTINE, RUN IT.
	 RET
	CALL SAVACS	;SAVING ALL ACS, AND DOING A (-) AROUND IT.
	MOVE A,REFRSH
	CALL MACXCP
	JRST RSTACS

CTLL2:	SKIPE RGETTY	;ON DISPLAYS, EFFECTIVELY CLEAR ECHO AREA WITH A CR.
	 CALL ECHOCL
	CALL DISINI	;CLEAR WINDOW AREA BY DOING A "BUFFER DISPLAY" OF NO CHARACTERS.
	SETO IN,
	CALL DISCLR	;NOW "REST OF SCREEN", MEANING ALL OF WINDOW.
	MOVE Q,QRB..
	SETZM .QVWFLA(Q)
	RET

;"CLOSE" A BUNCH OF DISPLAY OUTPUT - CLEAR LINES FROM CURSOR TO END OF WINDOW.
DISCLG:	CAME IN,PT
	 JRST DISCL3
	SKIPN RREBEG
	 CALL RRDIS1
DISCL3:	SETZM VREMEM
	SETOM TYOFLG	;FORCE NEXT TYPEOUT TO CALL DISINT
	CALL DISFL1	;FORCE OUT ANY INCOMPLETE LINE.
	SKIPN ORESET
	SKIPE MORFLF	;IF WE WERE FLUSHED AT A --MORE--, JUST UN-FLUSH.
	 RET
	SKIPN RGETTY	;ELSE, ON DISPLAY TTY, CLEAR REST OF SCREEN
	 RET
	AOS CHCTVP
	CALL DISCLR	;CLEAR OUT REST OF LINES IN DISPLAY AREA.  SET LINBEGS FROM IN.
;MAKE SURE THE --MORE-- LINE DOESN'T SAY "--MORE--", AND HAS THE
;CORRECT MODE DISPLAYED ON IT.
DISCLJ:	MOVEI T,MS%UP
	SKIPE GEA	;FIGURE OUT WHETHER WE WANT AN EMPTY --MORE-- FIELD, OR A --BOT--.
	 SKIPE RREBEG
	  SETZ T,
	SKIPE RRMORF
	 SETZ T,
	JRST DISMD	;AND UPDATE THE --MORE-- LINE IF IT ISN'T WHAT WE WANT.

;CLEAR LINES FROM CHCTVP DOWN TO END OF DISPLAY AREA.
;IN CAN HAVE ADDRESS OF END OF BUFFER, IF PREVIOUS LINES HOLD DATA FROM BUFFER.
;IF IN CONTAINS -1, WE CLEAR LINES EVEN IF ALREADY CLEAR.
DISCLR:	MOVE BP,CHCTVP
	CAML BP,CHCTVS	;STOP CLEARING AT END OF WINDOW, OR END OF SCREEN.
	 RET
	SKIPLE IN
	 MOVEM IN,LINBEG(BP)	;ABOUT TO CLEAR A LINE:  SET ITS LINBEG TO END OF BUFFER.
	SKIPN HCDS(BP)	;LINE ALREADY CLEAR => DON'T CLEAR IT.
	 JUMPGE IN,DISCL1
	SETZM HCDS(BP)	;CLEAR A LINE BY CLEARING THE HASH CODE,
	HRLZS BP	;MOVING TO THE LINE
	CALL SETCUR
	CALL CLREOL	;AND CLEARING VIA THE SYSTEM.
DISCL1:	AOS CHCTVP
	JRST DISCLR

;<HASH>,<VPOS>FS TYO HASH$ SETS HASH CODE OF LINE.
FSHCD:	TRZN FF,FRARG
	 TYPRE [AOR]
	MOVE E,SARG
	SKIPL C		;REQUIRE VPOS TO BE IN RANGE.
	 CAML C,USZ
	  TYPRE [AOR]
	MOVE A,HCDS(C)
	TRZE FF,FRARG2
	 MOVEM E,HCDS(C)
	JRST POPJ1

SUBTTL MODE LINE DISPLAY

FRCMD:	TRZE FF,FRCLN
	 JRST CLRMOR	;:FR => CLEAR THE MORE LINE ENTIRELY.
	SKIPN RGETTY	;FR => ON PRINTING TTY, MAYBE TYPE OUT THE MODE.
	 JRST DISMDP	;FOR IMPLICIT FR'S SUCH AS FI AND ^R, WE NEVER DO THAT.
;REDISPLAY THE MODE LINE AND RETURN CURSOR TO WHERE IT IS,
;PROVIDED THERE IS NO INPUT AVAILABLE.
DISMDI:	MOVE Q,$QMODE	;UPDATE MODE DISPLAY IF IT IS NECESSARY
	SKIPN RGETTY	;ON PRINTING TTY, WE DISPLAY IT DIFFERENTLY.
	 RET
	MOVE T,PFINI
	SUB T,PF		;COMPARE -2*(FS QP PTR$) WITH FS MODE CHANGE$
	HRRES T
	CAMG T,MODCHG		;IF FS MODE CHANGE$ LESS, WE MUST RUN FS MODE MAC$
	 SKIPLE MODCHG		;IF FS MODE CHANGE$ IS POS, WE MUST RUN FS MODE MAC$
	  JRST .+3
	CAMN Q,DISOMD
	 RET
	SKIPN TYISRC
	 SKIPL UNRCHC
	  RET
	LISTEN Q,
	JUMPN Q,CPOPJ	;DON'T UPDATE MODE LINE IF INPUT AVAILABLE.
	MOVE T,MORESW	;DON'T CHANGE THE --MORE-- OR WHATEVER,
	CAIN T,MS%FLS	;EXCEPT GET RID OF A "FLUSHED".
	 MOVEI T,MS%MOR
IFN ITS,[
	HRROI Q,[ASCIC/S/]	;AVOID CLOBBERING CURSOR POSITION.
	CALL DISIOT
	CALL DISMD	;NO INPUT: DISPLAY THE NEW "MODE"
	HRROI Q,[ASCIC/R/]
	JRST DISIOT
]
IFN TNX,[
	SAVE B
	MOVE B,TTLPOS	;MOVE CURSOR BACK WHERE IT WAS BEFORE
	CALL DISMD
	JRST SETCU3
]

DISMDP:	SKIPN SHOMOD	;ONLY DISPLAY MODE ON PRINTING TTY IF FS SHOWMODE$ IS SET.
	 RET
	MOVEM Q,DISOMD	;AND THEN ALWAYS SHOW IT EVEN IF HAVE INPUT.
	CALL CRIF	;GET FRESH LINE
	CALL DISMD2	;TYPE OUT MODE
	JRST CRIF	;AND ANOTHER NEW LINE

;UPDATE, IF NECESSARY, THE "MODE" DISPLAYED ON THE --MORE-- LINE.
;THE "MODE" IS A TEXT STRING STORED IN Q..J. THE CONTENTS OF THAT QREG ARE
;ALWAYS VISIBLE ON THE --MORE-- LINE. THE IDEA IS FOR THE USER TO BE
;ABLE TO TELL IMMEDIATELY WHAT MODE HE IS IN (WHERE THE MODES ARE DEFINED
;BY HIS MACROS PACKAGE).
;T SHOULD HAVE THE DESIRED MORESW VALUE SAYING WHETHER WE WANT --MORE-- OR --TOP-- OR WHAT.
DISMD:	MOVE Q,PFINI
	SUB Q,PF		;COMPARE -2*(FS QP PTR$) WITH FS MODE CHANGE$
	HRRES Q
	CAMG Q,MODCHG		;IF FS MODE CHANGE$ IS LESS, WE MUST RUN FS MODE MAC$
	 SKIPLE MODCHG		;IF IT IS POSITIVE, WE MUST RUN IT TOO.
	  CALL [
		CALL SAVACS
		SAVE SQUOTP
		SAVE RCHALT
		MOVE A,[JFCL ENDARG]
		MOVEM A,RCHALT
		SETZM MODCHG	;CLEAR THE FLAG.
		SETZB C,E	;PASS 0 AS ARG TO USER'S MACRO.
		SKIPE A,MODMAC
		 CALL MACXCP	;CALL USER'S MACRO TO RECOMPUTE IT
		REST RCHALT
		REST SQUOTP
		JRST RSTACS]
	SKIPN RGETTY	;NO MODE IS SHOWN ON PRINTING TTY'S.
	 RET
	SKIPE DFORCE	;DON'T UPDATE MODE IF FS D FORCE$ IS SET.
	 RET
	TRZE T,MS%LOS	;MS%LOS SET IN T MEANS WE GOT T FROM MORESW AND MODE LINE DOESN'T
	 SETOM MORESW	;MATCH IT, SO MAKE SURE WE REDISPLAY THE MODE LINE  --NN%--.
	TRZN T,MS%PCT
	 JRST DISMDM
	TRNE T,MS%UP	;IF MS%PCT WAS SET, WE SHOULD RECOMPUTE PERCENTAGE ABOVE SCREEN,
	 TRNN T,MS%DWN	;PROVIDED WE WANT TO DISPLAY IT AT ALL (NOT --TOP-- OR --BOT--).
	  JRST DISMDM
	SAVE A
	CALL DISMO6	;COMPUTE IT, PUT IT IN LH(T).
	HRL T,A
	REST A
DISMDM:	TRO T,MS%MOD	;DECIDE WHETHER WE WANT A STAR FOR "BUFFER MODIFIED".
	SKIPE MODIFF
	 SKIPE RRMORF
	  TRZ T,MS%MOD
	SKIPE RRSTAR
	 TRNE T,MS%MOR
	  TRZ T,MS%MOD
	MOVE Q,$QMODE	;IF THE DESIRED MODE STRING IS CHANGED, REDISPLAY THE ENTIRE LINE.
	CAME Q,DISOMD
	 JRST DISMD2
	CAMN T,MORESW	;IF ONLY THE DESIRED STATE OF --MORE-- OR --TOP-- IS CHANGED,
	 RET		;REDISPLAY FOR THAT.
DISMD2:	SETOM RROHPO	;REMEMBER THAT I.T.S. CURSOR POS. IS BEING CLOBBERED.
	SETOM RROVPO
INSIRP PUSH P,A B TT TT1 BP CH
	MOVE TT,NHLNS	;FIND HPOS TO TRUNCATE ..J AT SO THAT --MORE-- OR WHATEVER WILL FIT.
	SKIPE T
	 SUBI TT,7	;TOGETHER WITH THE --TOP-- OR WHATEVER.
	TRNE T,MS%MOR	;OR, IF IT MIGHT BE --MORE---FLUSHED,
	 SUBI TT,9	;LEAVE ROOM FOR THAT.
	TRNE T,MS%MOD	;IF IT SHOULD HAVE A STAR, LEAVE ROOM FOR THAT TOO.
	 SUBI TT,2
	MOVE Q,$QMODE	;ON DISPLAY TTY, IF ..J IS UNCHANGED, DISPLAY ONLY THE --TOP--.
	CAMN Q,DISOMD
	 SKIPN RGETTY
	  CAIA
	   JRST DISMD9
	MOVEM Q,DISOMD
	MOVE A,Q
	CALL CLRMOR	;CLEAR THE WHOLE --MORE-- LINE.
	MOVE Q,TT
	CALL DPYIVI	; INIT INVERSE VIDEO
	CALL QLGET0
	 JRST DISMD1	;MODE STRING IS NULL?
DISMD3:	SOJL B,DISMD1	;DISPLAY THE ..J STRING, COUNTING DOWN LENGTH IN B.
	SOJL Q,DISMD1	;Q HAS MAX # COLUMNS TO USE.
	ILDB CH,BP
	CAIE CH,177	;COUNT TWO POSITIONS FOR CTL CHARS.  THEY MIGHT POSSIBLY
	 CAIGE CH,40	;USE ONLY ONE, BUT BETTER TO ERR CONSERVATIVELY.
	  SOJL Q,DISMD1
IFN ITS,[		;OUTPUT WITH %TJECH SET SO CTL CHARS DON'T COME OUT IN IMAGE MODE.
	SYSCAL IOT,[%CLIMM,,CHTTYO ? CH ? %CLBIT,,%TJECH]
	 .LOSE %LSFIL
]
.ELSE	CALL TYOIN1
	JRST DISMD3

;WE HAVE WRITTEN OUT ..J (OR PART OF IT).  NOW SAVE THE HPOS WHERE IT ENDS,
;AND THEN WRITE OUT --TOP--, --NN%-- OR WHATEVER SHOULD GO AT THE END.
DISMD1:
	CALL DPYIVC	; CLEAR INVERSE VIDEO
IFN ITS,[
	SYSCAL RCPOS,[%CLIMM,,CHTTYO ? %CLOUT,,CH]
	 .LOSE %LSFIL
]
.ELSE	MOVE CH,TTLPOS
	HRRZM CH,MOREHP
	JRST DISMD8

DISMD9:	HRRZ BP,MOREHP	;REDISPLAY ONLY THE --TOP-- OR WHATEVER:
	CAML BP,TT	;MUST MOVE HORIZONTALLY TO SKIP THE ..J STRING,
	 MOVE BP,TT	;BUT NOT SO FA THAT --TOP-- OR WHATEVER WON'T FIT ON THE LINE.
	MOVEM BP,MOREHP
	HRL BP,USZ
	CALL SETCUR
	CALL CLREOL
DISMD8:
	CALL DPYIVI	; INIT INVERSE VIDEO.
	MOVEM T,MORESW
	TRZ T,MS%MOD
	JUMPE T,DISMD6	;IF WE ARE SUPPOSED TO HAVE --MORE-- OR SOMETHING, WRITE IT.
	SKIPN RGETTY
	 JRST DISMD6
	TLNN T,-1	;IF % ABOVE SCREEN IN LH IS NONZERO, PRINT THAT.
	 CAIN T,3	;IF IN MIDDLE OF BUFFER BUT PERCENT IS 0, PRINT 1%.
	  JRST DISMD5
	CAIL T,5	;WE SHOULDN'T GET HERE WANTING TO DISPLAY --MORE--FLUSHED!
	 .VALUE
	MOVE Q,DISMD4-1(T)
IFN ITS,HRLI Q,-2
IFN TNX,HRLI Q,-1
	CALL DISIOT
DISMD6:	MOVE T,MORESW	;PUT A STAR ON THE END, IF MORESW SAYS SO.
	TRNN T,MS%MOD
	 JRST DISMD7
	MOVEI CH,40
	CALL TYOINV
	MOVEI CH,"*
	CALL TYOINV
DISMD7:
	CALL DPYIVC		;TURN OFF INVERSE VIDEO.
INSIRP POP P,CH BP TT1 TT B A
	RET

DISMD4:
IFN ITS,[
	[ASCIC *--BOT--*]
	[ASCIC *--TOP--*]
	0
	[ASCIC /--MORE--/]
]
IFN TNX,[
	[ASCIZ *--BOT--*]
	[ASCIZ *--TOP--*]
	0
	[ASCIZ /--MORE--/]
]

;OUTPUT --NN%-- WHERE N IS IN LH(T).
DISMD5:	DISSTR /--/
	CALL DISIOT
	HLRZ CH,T
	SKIPN CH	;PRINT 01% INSTEAD OF 00%, SINCE 00% WHEN NOT AT TOP
	 MOVEI CH,1	;MIGHT BE PARADOXICAL.
	IDIVI CH,10.
	ADDI CH,"0
	CALL TYOINV
	MOVEI CH,"0(Q)
	CALL TYOINV
	DISSTR /%--/
	CALL DISIOT
	JRST DISMD6

;CLEAR THE --MORE-- LINE.
CLRMOR:	SETZM MOREHP
	HRLZ BP,USZ
	CALL SETCUR
	JRST CLREOL

SUBTTL CURSOR CONTROL SUBROUTINES

IFN ITS,[
;SCROLL LINES IN WINDOW FROM BP TO BELOW BOTLIN UP Q LINES.
SCRLUP:	CALL SCRLU2
	.IOT CHSIO,[%TDRSU]
	JRST SCRLU1

;SCROLL LINES IN WINDOW FROM BP TO BELOW BOTLIN DOWN Q LINES.
SCRLDN:	CALL SCRLU2
	.IOT CHSIO,[%TDRSD]
SCRLU1:	SAVE A
	MOVE A,BOTLIN
	SUB A,BP
	.IOT CHSIO,A
	.IOT CHSIO,Q
	JRST POPAJ

;MOVE CURSOR TO BEGINNING OF LINE WHOSE VPOS IS IN BP.  CLOBBERS DISBUF.
SCRLU2:	SAVE Q
	SAVE BP
	HRLZS BP
	CALL SETCUR
	REST BP
	JRST POPQJ

;DELETE # OF LINES IN Q AT VPOS IN BP.
DELLIN:	SAVE [%TDDLP]
	JRST DELLI1

;INSERT # LINES IN Q AT VPOS IN BP.
INSLIN:	SAVE [%TDILP]
DELLI1:	SAVE [440800,,DISBF1]	;ACCUMULATE STRING IN DISBF1.
	SAVE A
	MOVEI A,%TDMV0		;FIRST A COMAND TO SET DESIRED VPOS, AND HPOS 0.
	IDPB A,-1(P)
	IDPB BP,-1(P)
	SETZ A,
	IDPB A,-1(P)
	MOVEI A,3		;IF INSERTING/DELETING 0 LINES, JUST MOVE THE CURSOR.
	JUMPE Q,DELLI2		;DON'T PUT IN A %TDILP OR %TDDLP.
	MOVE A,-2(P)		;THEN A COMMAND TO INSERT OR DELETE
	IDPB A,-1(P)
	IDPB Q,-1(P)		;THE SPECIFIED NUMBER OF LINES.
	MOVEI A,5
DELLI2:	SAVE Q
	MOVE Q,[441000,,DISBF1]	;THEN OUTPUT THE STRING.
	SYSCAL SIOT,[%CLIMM,,CHSIO ? Q ? A]
	 .LOSE %LSFIL
	REST Q
	REST A
	SUB P,[2,,2]
	RET

;OUTPUT C(T) CHARS STARTING AT DISBF1, WITH SUPER-IMAGE SIOT.
DISSIOT:MOVE Q,[441000,,DISBF1]
	SKIPN RGETTY
	 MOVE Q,[441000,,DISBUF]
	SKIPN RGETTY
	 SUBI T,4*<DISBUF-DISBF1>
DISLI5:	ILDB CH,Q	;SKIP ALL %TDNOP'S AT THE BEGINNING.
	CAIN CH,%TDNOP
	 SOJG T,DISLI5
	JUMPE T,CPOPJ	;NO CHARS REALLY NEED TO BE SENT => RETURN.
	ADD Q,[100000,,]
	MOVEI CH,CHSIO
	SKIPN RGETTY	;ON PRINTING TTYS, DON'T USE SUPER-IMAGE MODE.
	 MOVEI CH,CHTTYO
DISSI1:	SYSCAL SIOT,[CH ? Q ? T]
	 .LOSE %LSFIL
	SKIPN RGETTY
	 RET
	MOVE Q,NHLNS
	CAML Q,CHCRHP
	 MOVE Q,CHCRHP
	SYSCAL SCPOS,[CH ? BP ? Q]
	 .LOSE %LSFIL
	RET

;MOVE CURSOR AND TELL ITS WHERE IT IS.   ON A PRINTING TTY, DON'T ACTUALLY CHANGE
;THE VERTICAL POSITION, IN CASE THE TTY IS A STORAGE TUBE.  CLOBBERS BP AND Q.
SETCUR:	SKIPE RGETTY
	 JRST SETCU2
	SYSCAL RCPOS,[%CLIMM,,CHTTYO ? %CLOUT,,Q]
	 .LOSE %LSFIL
	HLL BP,Q
SETCU2:	CALL SETCU1
	HLRZ Q,BP
	ANDI BP,-1
	SYSCAL SCPOS,[%CLIMM,,CHTTYO ? Q ? BP]
	 .LOSE %LSFIL
	RET

;MOVE CURSOR USING SUPERIMAGE MODE TO POSITION SPECD AS VPOS,,HPOS IN BP.
;CLOBBERS Q.
SETCU1:	SAVE BP
	SAVE [441000,,DISBF1]
	SAVE A
	MOVEI A,%TDMV0
	IDPB A,-1(P)
	HLRZ Q,BP
	IDPB Q,-1(P)
	IDPB BP,-1(P)
	MOVEI A,3
	JRST DELLI2

;OUTPUT CHAR IN CH TO ECHO AREA BUT NOT ECHO MODE OUTPUT.
ECHOC0:	SYSCAL IOT,[%CLIMM,,CHECHO ? CH ? %CLBIT,,%TJECH]
	 .LOSE %LSFIL
	RET

;OUTPUT CHAR IN CH TO ECHO AREA.
ECHOC1:
ECHOCH:	.IOT CHECHO,CH
	RET

;OUTPUT CHAR IN CH TO ECHO AREA, PROCESSING ^P.
ECHODP:	SYSCAL IOT,[%CLIMM,,CHECHO ? CH ? %CLBIT,,%TJDIS\%TJCTN]
	 .LOSE %LSFIL
	RET

;CRLF IN ECHO AREA.
ECHOCR:	.IOT CHECHO,[^M]
	RET

;HOME UP ECHO AREA CURSOR.
ECHOHU:	SAVE CH
	MOVEI CH,^P	;DOESN'T USE DISIOT BECAUSE WE MUST MOVE
	CALL ECHODP	;THE ECHO AREA CURSOR, NOT THE M.P. CURSOR.
	MOVEI CH,"T
	CALL ECHODP
	JRST POPCHJ

CLRSCN:	HRROI Q,[ASCIC/C/]
	JRST DISIOT

HOMCUR:	HRROI Q,[ASCIC/T/]
	JRST DISIOT

ERSCHR:	HRROI Q,[ASCIC/K/]
	JRST DISIOT

;INSERT CHARACTERS.  THE NUMBER TO INSERT IS IN A.
INSCHR:	JUMPE A,CPOPJ
	.IOT CHSIO,[%TDICP]
	.IOT CHSIO,A
	RET

;DELETE CHARACTERS.  THE NUMBER TO DELETE IS IN A.
DELCHR:	JUMPE A,CPOPJ
	.IOT CHSIO,[%TDDCP]
	.IOT CHSIO,A
	RET

CRIF:	HRROI Q,[ASCIC /A/]
	JRST DISIOT

CLREOL:	HRROI Q,[ASCIC/L/]
DISIOT:	.IOT CHDPYO,Q
	RET

;IMMEDIATE TYPEOUT, NO HASH-CODING.
TYOINV:	.IOT CHTTYO,CH
	POPJ P,

; INVERSE VIDEO START.
DPYIVI:	SKIPE INVMOD
	 .IOT CHSIO,[%TDBOW]
	RET

; INVERSE VIDEO END.
DPYIVC:	SKIPE INVMOD
	 .IOT CHSIO,[%TDRST]
	RET

IFN LINSAV,[

;"SAVE" THE CURRENT LINE (VPOS IN BP) WITH A LABEL.
;TELL THE TERMINAL TO REMEMBER THE CURRENT CONTENTS UNDER THE
;LABEL IN LBLNXT.
SAVLIN:	SAVE A			;JUNK, SINCE DELLI2 WANTS TO POP 2 THINGS.
	MOVE A,LINEND(BP)
	CAIGE A,20		;DON'T BOTHER SAVING A LINE WITH LITTLE TEXT.
	 JRST POPAJ
	REST A
	SAVE DISBF1		;IF CALLED FROM DISLIN, DON'T CLOBBER BUFFER.
	SAVE Q
	CALL SAVLI1
	REST Q
	REST DISBF1
	RET

SAVLI1:	SAVE A			;PUSH JUNK WORD FOR DELLI2 TO FLUSH.
	SAVE BP			;MOVE CURSOR TO THE LINE WE WANT TO SAVE.
	HRLZS BP
	CALL SETCU1
	REST BP
	SAVE [441000,,DISBF1]
	SAVE A
	SAVE HCDS(BP)		;REMEMBER WHAT HASH CODE WENT WITH THE DATA
	MOVE A,LBLNXT		;SAVED UNDER THIS LABEL.
	REST LBLHCD(A)
	MOVEI A,%TDSVL		;PRODUCE THE OUTPUT CODE TO SAVE THE LINE.
	IDPB A,-1(P)
	MOVEI A,1
	IDPB A,-1(P)
	LDB A,[.BP 177,LBLNXT]
	IDPB A,-1(P)
	LDB A,[.BP 177_7,LBLNXT]
	IDPB A,-1(P)
	AOS LBLNXT		;INCREMENT THE NEXT LABEL, WITH WRAPAROUND.
	MOVN A,LBLLIM
	ANDCAM A,LBLNXT
	MOVEI A,4		;GO AND OUTPUT 4 CHARS.
	JRST DELLI2

;WHEN WE ARE ABOUT TO OUTPUT A LINE,
;SEE IF THE DESIRED CONTENTS ARE SAVED IN THE TERMINAL UNDER A LABEL.
;IF SO, REPLACE THE LINE CONTENTS WITH A COMMAND TO RESTORE THAT LABEL.
;DISBF1 ALREADY CONTAINS THE CURSOR POSITIONING COMMANDS.  DON'T CHANGE THEM.
RSTLIN:	SAVE A
	SAVE B
	MOVE A,CHCRHP		;SINCE WE DON'T SAVE LINES LESS THAN 20 CHARS LONG,
	CAIGE A,20		;IF THE NEW LINE IS SHORT, DON'T EVEN LOOK FOR LABEL.
	 JRST POPBAJ
	MOVE A,CHCTHC
	MOVN B,LBLLIM
	HRLZS B
RSTLI1:	CAME A,LBLHCD(B)	;SEARCH HASH CODES ASSOCIATED WITH LABELS
	 AOBJN B,RSTLI1		;FOR ONE WHICH MATCHES WHAT WE ARE ABOUT TO WRITE.
	JUMPGE B,POPBAJ
	ANDI B,-1		;IF WE FIND ONE, RECORD THAT IT WAS USED TO
	MOVEM B,LINLBL(BP)	;OUTPUT THIS LINE,
	MOVE A,[441000,,DISBUF]
	MOVEM A,CHCTBP		;AND REPLACE THE LINE CONTENTS IN DISBUF
	MOVEI A,%TDRSL		;WITH THE COMMAND TO RESTORE THE LABEL.
	IDPB A,CHCTBP
	MOVEI A,1
	IDPB A,CHCTBP
	LDB A,[.BP 177,B]
	IDPB A,CHCTBP
	LDB A,[.BP 177_7,B]
	IDPB A,CHCTBP
	JRST POPBAJ
];LINSAV

] ;IFN ITS

IFN TNX,[
;FUNDAMENTAL DISPLAY OPERATIONS, ON A TERMINAL-INDEPENDANT BASIS.

IFNDEF DEFOSP,DEFOSP==9600.	;DEFAULT SPEED TO ASSUME FOR PADDING CALCULATIONS.

;THE TTYTYP TABLE TRANSLATES TWENEX TERMINAL TYPE CODES TO TECO INTERNAL TERMINAL TYPES.
;THE TECO INTERNAL TYPE IS WHAT LIVES IN RGETTY.  USING FS TTYINIT$ WITH ARG,
;THE USER CAN SET THIS TO ANY DESIRED VALUE.

;Internal types 0 and 1 are for printing ttys and glass ttys.
;Higher type codes are for displays.  The index-symbol (such as VT100I)
;has the internal type as its value.

;A name of the terminal type, such as "VT100",
;can be 0 to omit the code for that terminal,
;-1 to assemble the code,
;or the Twenex terminal type number for that terminal.
;These symbols should be assigned in the CONFIG file.

DEFINE DEFTYP TYPE,TABLE,SYMBOL
IFNDEF TYPE,TYPE=-1
IFG TYPE-NTTYPE+1,.ERR TYPE is too large to be a GTTYP index
%%TYPE==%%TYPE+1

IFN TYPE,TABLE
.ELSE PRINTB

SYMBOL==:%%TYPE

IFG TYPE,[
%%TMP==.
LOC TTYTYP+TYPE
%%TYPE
LOC %%TMP
]
TERMIN


NTTYPE==50.	;1+ LARGEST TWENEX TERMINAL TYPE.  SIZE OF TTYTYP TABLE.
TTYTYP:	BLOCK NTTYPE	;INTERNAL TYPE (RGETTY), INDEXED BY GTTYP TYPE
			;DEFTYP FILLS IN THE WORDS OF THIS TABLE.

IF2 [
GLASCD TYPE,[
IFG TYPE-NTTYPE+1,.ERR TYPE is too large to be a GTTYP index
LOC TTYTYP+TYPE
	1
]
LOC TTYTYP+NTTYPE
]

;DEVICE DEPENDANT ROUTINE DISPATCH TABLE, INDEXED BY RGETTY
TTYTBS:	PRINTB
	GLASTB
%%TYPE==1
DEFTYP DM2500,DM25TB,DM25I
DEFTYP H1500,HZ15TB,HZ15I
DEFTYP VT52,VT52TB,VT52I
DEFTYP DM1520,DM15TB,DM15I
DEFTYP IMLAC,IMLCTB,IMLCI
DEFTYP VT05,VT05TB,VT05I
DEFTYP TK4025,TK40TB,TK40I
DEFTYP VT61,VT61TB,VT61I
DEFTYP TL4041,TL40TB,TL40I
DEFTYP FOX,FOXTB,FOXI
DEFTYP HP2645,HPTB,HPI
DEFTYP I400,I400TB,I400I
DEFTYP TK4023,TK43TB,TK43I
DEFTYP ANNARB,AATB,AAI
DEFTYP C100,C100TB,C100I
DEFTYP IQ120,IQ12TB,IQ12I
DEFTYP VT100,VT10TB,VT100I
DEFTYP I100,I100TB,I100I
DEFTYP TL1061,TL40TB,TL106I
DEFTYP HEATH,HTHTB,HTHI
DEFTYP VC404,VC44TB,VC44I	;Volker-Craig.
DEFTYP CNCPT,CNCPTB,CNCPI	;CN Railroad Stupid Terminal.
DEFTYP TVI912,TVITB,TVII	;TeleVideo.  May be ADM-2.
DEFTYP OWL,OWLTB,OWLI
DEFTYP BANTAM,BANTB,BANTI
DEFTYP DM3045,DM34TB,DM34I
DEFTYP DM3052,DM35TB,DM35I
DEFTYP HMOD1,HZM1TB,HMD1I	;Hazeltine Modular One
DEFTYP H1510,HZ15TB,HZ151I	;Hazeltine 1510 (same for our purposes as 1500).
DEFTYP ADM3A,ADM3TB,ADM3I
DEFTYP VT100V,VT15TB,VT152I	;VT100 IN VT52 MODE
DEFTYP SIMLAC,SIMLTB,SIMLCI	;I.T.S. VIRTUAL DISPLAY TERMINAL.
DEFTYP VT100W,VT1WTB,VT10WI	;VT100 IN VT52 MODE OUTSIDE AND ANSI MODE INSIDE
DEFTYP VT100X,VT1XTB,VT10XI	;VT100 IN ANSI MODE OUTSIDE AND VT52 MODE INSIDE
DEFTYP ADM42,ADM42T,ADM42I	;ADM42  Also good for ADM31.
DEFTYP NIH5200,NH52TB,NH52I	;NIH (Delta Data modified) 5200
DEFTYP V200,V200TB,V200I	;Visual 200
DEFTYP PTV,PTVTB,PTVI		;MIT-Plasma TV system emulating a large VT52
DEFTYP E19,E19TB,E19I		;Edmond's modified H19
DEFTYP VTS,VTSTB,VTSI		;VTS virtual terminal
DEFTYP ACT4,ACT4TB,ACT4I	;ACT-IV terminal.
DEFTYP IM3101,IM31TB,IM31I	;IBM 3101
DEFTYP GILL,GILLTB,GILLI	;Hazeltine w/ John Gill's custom ROM
DEFTYP DM3025,DM32TB,DM32I	;Datamedia 3025
DEFTYP AMBASS,AMBATB,AMBASI	;Ann Arbor Ambassador
DEFTYP MIME2A,MI2ATB,MIM2AI	;Mime2a in VT52 enhanced emulation mode
DEFTYP DG132,DG13TB,DG13I	;Datagraphics 132
DEFTYP IIMLAC,IIMLTB,IIMLCI	;IMLAC WITH FCI USING ITP
DEFTYP BUR80,BUR80T,BUR80I	;Modified version of Burroughs TD850
DEFTYP INTEXT,INTXTB,INTXI	;INtext (modified OWL-1200)
DEFTYP VT132,V132TB,VT132I	;VT132 (just implements char I/D)
DEFTYP ADVPT,ADVPTB,ADVPTI	;ADDS Viewpoint
DEFTYP NH7000,NH70TB,NH70I	;NIH (Delta Data modified) 7000
DEFTYP BEE2,BEE2TB,BEE2I	;MICROBEE 2
DEFTYP GIGI,GIGITB,GIGII
DEFTYP TVI950,TV5TB,TV9I	;TeleVideo (tvi912 -padding +%tolid)
DEFTYP BITGRA,BBNTB,BBNI	;BBN Bitgraph
DEFTYP AJ510,AJ510T,AJ510I	;Anderson Jacobson 510 [Joshua Brodsky @UDC]
MAXTTY==%%TYPE+1

PRINTB:	377777,,79.	;PRINTING TERMINAL DISPATCH VECTOR
	(%TOOVR+%TOMVB+%TOLWR)
REPEAT 22,JFCL

GLASTB:	377777,,79.	;"GLASS TTY" DISPATCH VECTOR
	(%TOMVB+%TOLWR)
REPEAT 22,JFCL

;SET CURSOR POSITION TO VPOS,,HPOS IN 2
CURPOS:	SETOM ECHOP
CURPS0:	SAVE B		;SAVE DESIRED POSITION
	CALL CURPS1	;DO WORK FIRST
	REST TTLPOS
	RET
CURPS1:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR CURSOR POSITIONING
CURPSX:	 2(T)		;ENTRY 2 IN DEVICE TABLE

;DISPATCH BY RGETTY INTO TABLE INDEXED BY POINTER AFTER CALLER
DDPYTB:	SAVE T
	SAVE B
	MOVE T,RGETTY	;GET INTERNAL TERMINAL TYPE
	MOVE T,TTYTBS(T)	;GET DISPATCH VECTOR
	XCT @(A)	;CALL APPROPRIATE ROUTINE
	REST B
	REST T
	JRST POPAJ

;CLEAR TO END OF LINE
CLREOL:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR CLEAR EOL
	 3(T)		;ENTRY 3 IN TABLE

;CLEAR TO END OF SCREEN
CLREOS:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR CLEAR EOS
	 4(T)		;ENTRY 4 IN TABLE

;CLEAR SCREEN
CLRSCN:	SAVE A
	SETZM TTLPOS	;SAY WE ARE AT HOME
	SETOM ECHOP
	MOVE A,ECHOL0	;FIRST LINE OF ECHO AREA
	HRLZM A,ECHOPS	;RESET ECHO POSITION
	JSP A,DDPYTB
	 5(T)		;CLEAR SCREEN ENTRY 5 IN TABLE

;INSERT LINES
INSLIN:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR INSERT LINE
	 11(T)		;ENTRY 11 IN TABLE

;DELETE LINES
DELLIN:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR DELETE LINE
	 12(T)		;ENTRY 12 IN TABLE

;INSERT C(A) CHARACTERS
INSCHR:	SAVE Q
	MOVE Q,A
	CALL INSCH1
	JRST POPQJ

;INSERT C(Q) CHARACTERS.  CLOBBERS Q.
INSCH1:	JUMPE Q,CPOPJ
	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR INSERT CHAR
	 13(T)		;ENTRY 13 IN TABLE

;DELETE C(A) CHARACTERS
DELCHR:	SAVE Q
	MOVE Q,A
	CALL DELCH1
	JRST POPQJ

;DELETE C(Q) CHARACTERS.  CLOBBERS Q.
DELCH1:	JUMPE Q,CPOPJ
	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR DELETE CHAR
	 14(T)		;ENTRY 14 IN TABLE

;SET UP DISBF1 TO CLEAR LINE FIRST
DISMOV:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR DISMOV
	 7(T)		;ENTRY 7 IN TABLE

;DONT CLEAR IT, JUST GO THERE
DISMV1:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR DISMV1
	 10(T)		;ENTRY 10 IN TABLE

;TAKE TERMINAL OUT OF DISPLAY MODE, AND CLEAR FUNNY STUFF SUCH AS REVERSE
; VIDEO FROM SCREEN.  USED ONLY FOR FAIRLY FINAL EXITS, WHEN THE USER IS
; GOING TO REDISPLAY THE SCREEN IF HE EVER GETS BACK.
DPYRST:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR TERMINAL RESET
	 15(T)		;ENTRY 15 IN TABLE

;TAKE TERMINAL OUT OF DISPLAY MODE TEMPORARILY FOR :ET COMMAND.
DPYRSS:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR TERMINAL RESET
	 21(T)		;ENTRY 21 IN TABLE

;SCROLL LINES IN WINDOW FROM BP TO BELOW BOTLIN UP Q LINES.
SCRLUP:	SAVE A
	JSP A,DDPYTB
	 16(T)

;SCROLL LINES IN WINDOW FROM BP TO BELOW BOTLIN DOWN Q LINES.
SCRLDN:	SAVE A
	JSP A,DDPYTB
	 17(T)

;INITIALIZE TERMINAL CHARACTERISTICS 
DPYINI:	SAVE A
	JSP A,DDPYTB	;DISPATCH FOR TERMINAL INIT
	 20(T)		;ENTRY 20 IN TABLE

; INVERSE VIDEO START
DPYIVI:	SKIPN INVMOD	;  DOES HE WANT INVERSE VIDEO?
	 RET
	SAVE A
	JSP A,DDPYTB	;  DISPATCH FOR START INVERSE VIDEO CODE
	 22(T)

; INVERSE VIDEO END.
DPYIVC:	SKIPN INVMOD
	 RET
	SAVE A
	JSP A,DDPYTB
	 23(T)

;LOW LEVEL INTERFACES TO DEVICE DEPENDANT ROUTINES

DISSIO:	JSR SAVABC	;SAVE ACS
	SKIPN RGETTY
	 JRST [	MOVE B,[441000,,DISBUF]
		SUBI T,4*<DISBUF-DISBF1>
		JUMPG T,DISSI2
		JRST POPCBA]
	MOVE B,[441000,,DISBF1]
DISSI2:	ILDB CH,B
	JUMPN CH,DISSI3	;FLUSH INITIAL NULLS
	SOJG T,DISSI2
	JRST DISSI4		;NOTHING TO DO
DISSI3:	MOVEI A,.PRIOU
	ADD B,[100000,,0]	;MAKE BYTE POINTER
	MOVNI C,(T)	;NUMBER OF CHARACTERS TO OUTPUT
	SOUT
	SETOM ECHOP	;NO LONGER IN ECHO AREA IF WE WERE
	SKIPN RGETTY	;DONE IF PRINTING
	 JRST POPCBA
	MOVE B,NHLNS
	CAML B,CHCRHP
	 MOVE B,CHCRHP	;UPDATE HORIZONTAL POSITION
	HRLI B,(BP)
	MOVEM B,TTLPOS	;UPDATE CURSOR POSITION
DISSI4:	SKIPN NOCEOL
	 JRST POPCBA
	SKIPGE EOLFLG		;POSTPONED CLEARING NEEDED?
	 CALL CLREOL		;YES, FAKE IT
	JRST POPCBA

;SET CURSOR POS TO VPOS,,HPOS IN BP.  CLOBBERS AT MOST Q.
SETCU1::
SETCUR:	SKIPN RGETTY	;ON PRINTING TERMINAL
	 JRST SETCU2	;USE BS OR SPACE TO DO WHAT WE CAN
	SAVE B		;SAVE ACS
	MOVE B,BP	;GET DESIRED POSITION
SETCU3:	CALL CURPOS	;GO THERE
	JRST POPBJ

SETCU2:	SAVE A		;HANDLE "CURSOR MOTION" ON PRINTING TTY
	TRNN BP,-1	;MOVE TO START OF LINE?
	 JRST [MOVEI A,^M ;YES, DO IT FAST
	       PBOUT
	       JRST POPAJ]
	SAVE B
	MOVEI A,.PRIOU
	RFPOS		;GET CURRENT POSITION
	ANDI B,-1	;SHOULD ONLY BE ASKED TO HANDLE HORIZ MOTION
	SUBI B,(BP)	;GET DIFFERENCE
	JUMPE B,POPBAJ	;ALREADY THERE, NOTHING TO DO
	MOVEI A,^H	;USE BS IF MOVING LEFT
	JUMPL B,[MOVMS B	;BUT IF MOVING RIGHT
		 MOVEI A,40	;USE SPACE
		 JRST .+1]
	PBOUT
	SOJG B,.-1
	JRST POPBAJ

;RETURN CURSOR TO UPPER LEFT CORNER OF SCREEN.
HOMCUR:	SAVE B
	SETZ B,
	CALL CURPOS
	JRST POPBJ

;OUTPUT ASCIZ STRING Q POINTS AT.
DISIOT:	EXCH A,Q
	PSOUT
	EXCH A,Q
	RET

;OUTPUT A CHARACTER, PUTTING UPARROW BEFORE CONTROL CHARS AND RUBOUT.  FOR THE MODE LINE.
TYOIN1:	CAIN CH,ALTMOD
	 MOVEI CH,"$
	CAIE CH,177
	 CAIGE CH,40	;IN MODE LINE, IT'S GOOD FOR CR AND LF TO BE PRINTED WITH UPARROWS TOO.
	  CAIN CH,^I	;BUT NOT TAB, SINCE THAT CAN WORK OK AS A FORMATTER.
	   JRST TYOINV
	SAVE A
	MOVEI A,"^
	PBOUT
	MOVE A,CH
	XORI A,100
	PBOUT
	MOVEI A,2
	ADDM A,TTLPOS
	JRST POPAJ

;ITS-STYLE ASCII MODE OUTPUT.
TYOINV:	SKIPN RGETTY		;SIMPLE ON PRINTING TERMINAL
	 JRST [ EXCH A,CH
		PBOUT
		EXCH A,CH
		RET ]
	SAVE A
	SAVE B
	CAIN CH,^G
	 JRST TYOIV2		;BELL - ZERO WIDTH
	MOVEI A,.PRIOU
	MOVE B,TTLPOS
	CAIN CH,^I
	 JRST TYOIVT
	CAIN CH,^J
	 ADD B,[1,,0]		;LF - MOVE TO NEXT LINE
	CAIN CH,^M
	 TRZ B,-1		;CR - MOVE TO START OF LINE
	CAIN CH,^H
	 SOJ B,			;BS - MOVE BACK ONE
	CAIL CH,40
	 AOJ B,			;PRINTING CHAR, COUNT ONE POSITION
	MOVEM B,TTLPOS
TYOIV2:	MOVE A,RGETTY
	CAIE A,IIMLCI
	 CAIN A,SIMLCI
	 JRST TYOIVI
TYOIV1:	MOVE A,CH
	PBOUT
	JRST POPBAJ

TYOIVT:	ADDI B,10		;TAB - MOVE TO NEXT TAB STOP.
	TRZ B,7			;USE 8-CHAR TABS FOR THIS
TYOIVP:	CALL CURPS0		;BECAUSE ON ITS WE JUST OUTPUT THE CHAR
	JRST POPBAJ		;AND ITS WOULD USE 8-CHAR TAB STOPS.

;TYPEOUT ON FUNNY IMLACS, SOME FORMAT EFFECTORS ARE REALLY PRINTING
TYOIVI:	CAIE CH,^M
	 CAIN CH,^J
	 JRST TYOIVP		;POSITIONING COMMANDS REALLY
	CAIN CH,^H
	 JRST TYOIVP
	CAIE CH,^G
	 JRST TYOIV1		;LOOKS SAFE TO JUST TYPE IT OUT
	MOVE A,[440800,,[.BYTE 8 ? 177 ? 221-176 ? 0]]	;%TDBEL
TOIVI1:	PSOUT
	JRST POPBAJ

;GET FRESH LINE
CRIF:	SAVE A
	SAVE B
	MOVEI A,.PRIOU
	RFPOS
	HRROI A,[ASCIZ/
/]
	TRNE B,-1
	 PSOUT
	JRST POPBAJ

SUBTTL SIMULATE ITS ECHO AND ^P FOR TWENEX

;ECHO CHARACTER IN CH, IN THE ECHO AREA.
ECHOC0:	HRROS (P)	;FLAG THAT CR SHOULD COME OUT AS STRAY ONE
	CAIA
ECHOCH:	HRRZS (P)
	SAVE CH
	TRZE CH,CONTRL
	 TRZ CH,100
	ANDI CH,177	;CLEAR OTHER RANDOM BITS
	CAIN CH,177	;RUBOUTS DONT ECHO
	 JRST POPCHJ
	CAIN CH,^J	;LF?
	 JRST ECHOLF
	CAIN CH,^M	;CR?
	 JRST ECOCR0
	CAIN CH,33	;ESC COMES OUT AS $
	 MOVEI CH,"$
	CAIN CH,^I	;TAB?
	 JRST ECHOTB
	CAIN CH,^H	;BS?
	 JRST ECHOBS
	CAIE CH,^G	;THIS ALWAYS BEEPS
	 CAIL CH,40	;CONTROL-MUMBLE?
	 JRST ECHOC3
	MOVEI CH,"^	;YES, PRINT ^-MUMBLE
	CALL ECHOC1
	MOVE CH,(P)
	TRO CH,100
ECHOC3:	CALL ECHOC1	;PRINT SINGLE CHARACTER
	JRST POPCHJ

ECHOLF:	SKIPN RGETTY
	 JRST ECHLF3
ECHLF1:	CALL ECHOC2	;ADVANCE TO NEXT LINE
	JRST POPCHJ
ECHLF3:	CALL ECHLF2
	JRST POPCHJ

ECHLF2:	SAVE A
	SAVE B
	MOVEI A,.PRIOU	;MONITOR WONT LET US TYPE A BARE LF, SO...
IFN 20X,[
	RFPOS
	SAVE B
	TRZ B,-1	;FIRST PRETEND WE ARE AT THE LEFT MARGIN ALREADY
	SFPOS
]
	MOVEI B,^J	;THEN TYPE IT
	BOUT
IFN 20X,[
	RFPOS		;GET LINE IT THINKS THAT PUTS US ON
	HLLM B,(P)
	REST B		;AND SET UP TO REALLY BE IN MIDDLE OF IT
	SFPOS
]
	JRST POPBAJ
	
ECHOCR:	HRRZS (P)	;ALWAYS CRLF
	SAVE CH
	MOVEI CH,^M
ECOCR0:	SKIPN RGETTY
	 JRST [CALL ECHOC1	;ON PRINTING TTY, JUST TYPE IT
	       JRST POPCHJ]	;AND RETURN
	HLLZS ECHOPS	;GO TO START OF THIS LINE
	SKIPGE -1(P)	;OUTPUT STRAY CR?
	 JRST ECOTB2	;YES, JUST GO TO START OF LINE THEN
	JRST ECHLF1	;ELSE ADVANCE A LINE AND CLEAR IT

ECHOC1:	SKIPE RGETTY
	 CALL ECOPOS
	CALL TYOINV	;DO TYPEOUT WITH SPECIAL CHECKS FOR ^G, ETC.  THIS WILL CHANGE TTLPOS
			;IN WAYS THAT WE DON'T REALLY CARE ABOUT.
	CAIE CH,^G	;THIS HAS NO WIDTH
	 SKIPN RGETTY
	 RET
	AOS CH,ECHOPS
	ANDI CH,-1	;GET HPOS
	CAMGE CH,NHLNS
	 JRST ECHOC4	;STILL WITHIN RANGE
	HLLZS ECHOPS	;START OF NEW LINE
ECHOC2:	HLRZ CH,ECHOPS
	AOJ CH,
	CAML CH,NVLNS
	 HRRZ CH,ECHOL0
	HRLM CH,ECHOPS
	CALL ECOPS0
	JRST CLREOL

ECHOC4:	MOVE CH,ECHOPS	;MAKE SURE KNOW OUR POSITION RIGHT
	MOVEM CH,TTLPOS
	RET

ECHOTB:	SKIPN RGETTY
	 JRST ECHOC3
	HRRZ CH,ECHOPS
	ADDI CH,8
	TRZ CH,7
	CAML CH,NHLNS
	 SETZ CH,
	HRRM CH,ECHOPS
	JUMPE CH,ECHLF1	;ADVANCE TO NEXT LINE IF WRAP AROUND
ECOTB2:	CALL ECOPS0
	JRST POPCHJ


ECHOBS:	SKIPN RGETTY
	 JRST ECHOC3
	SOS CH,ECHOPS		;DECREMENT POSITION
	TRNE CH,400000		;BUT DON'T WRAP AROUND
	 AOS ECHOPS
	JRST ECOTB2

ECOPS0:	SETOM ECHOP	;HERE TO BE SURE WE GO THERE FIRST
ECOPOS:	AOSE ECHOP
	 RET
	SAVE A
	SAVE B
	MOVE B,ECHOPS
	CALL CURPS0
	JRST POPBAJ

;SIMULATE DISPLAY TYPEOUT IN ECHO AREA (IE INTERPRET ^P CODES)
ECHODP:	AOSG ECODPF		;HAD A ^P LAST TIME?
	 JRST ECODP0		;YES, OF SOME SORT
	CAIE CH,^P		;^P NOW?
	 JRST ECHOC1		;NO, JUST OUTPUT THIS CHARACTER.
	SETOM ECODPF		;YES, SAY SO FOR NEXT TIME
	RET

ECODP0:	SAVE C
	MOVE C,ECODPF
	SETZM ECODPF
	AOJLE C,ECODP1		;^PH OR ^PV?
	SKIPGE C,ECODTB-"A(CH)
	 CALL ECOPOS		;SEE IF WE SHOULD MOVE TO RIGHT SPOT FIRST
	CALL (C)		;DISPATCH FOR THIS ONE
	JRST POPCJ

ECODP1:	AOJLE C,ECODP2		;FOLLOWING A ^PV?
	MOVEI C,-10(CH)		;NO, ^PH.  GET DESIRED HPOS
	CAMLE C,NHLNS
	 MOVE C,NHLNS
	HRRM C,ECHOPS		;MAKE IT THE "CURRENT ECHO HPOS"
ECODP3:	REST C
	JRST ECOPS0		;MOVE THE CURSOR THERE

ECODP2:	MOVEI C,-10(CH)		;GET DESIRED VPOS
	SETZM ECODPF
	CAMGE C,ECHOL0
	 MOVE C,ECHOL0
	CAMLE C,NVLNS
	 MOVE C,NVLNS		;GET IT IN RANGE
	HRLM C,ECHOPS		;MAKE IT CURRENT POS AND GO THERE.
	JRST ECODP3

ECODTB:	ECODPA			;A - ADVANCE TO FRESH LINE
	ECODPB			;B - MOVE BACKWARD
	ECODPC			;C - CLEAR ECHO AREA
	ECHOC2			;D - MOVEM DOWN
	-1,,CLREOS		;E - CLEAR TO END OF SCREEN
	ECODF0			;F - MOVE FORWARD
	CPOPJ			;G
	ECODPH			;H - SET HORIZONTAL POSITION
	CPOPJ			;I
	CPOPJ			;J
	-1,,ECODPK		;K - ERASE CURRENT CHARACTER POSITION
	-1,,CLREOL		;L - CLEAR TO END OF LINE
	CPOPJ			;M - MORE - SHOULNDT BE DOING THAT, RIGHT?
	CPOPJ			;N - DITTO
	CPOPJ			;O
	ECODPP			;P - OUTPUT ^P
	ECODPQ			;Q - OUTPUT ^C
	[MOVE C,ECODPS ? MOVEM C,ECHOPS ? JRST ECOPS0]	;R - RESTORE POSITION
	[MOVE C,ECHOPS ? MOVEM C,ECODPS ? RET]	;S - SAVE POSITION
	ECODPT			;T - GO TO TOP OF ECHO AREA
	ECODPU			;U - MOVE UP
	ECODPV			;V - SET VERTICAL POSITION
	CPOPJ			;W
	ECODPX			;X - BACKSPACE AND ERASE CHARACTER
	CPOPJ			;Y
	ECODPZ			;Z - HOME DOWN
	-1,,INSLIN		;[ INSERT LINE
	-1,,DELLIN		;\ DELETE LINE
	-1,,CLREOL		;] SAME AS ^PL
	-1,,INSCHR		;^ INSERT CHARACTER
	-1,,DELCHR		;_ DELETE CHARACTER

ECODPA:	MOVE C,ECHOPS		;^PA - MOVE TO FRESH LINE
	TRNN C,-1		;AT START OF A LINE NOW?
	 RET			;YES
	JRST ECHOCR		;NO, TYPE CRLF

ECODPB:	HRRZ C,ECHOPS		;^PB - MOVE BACKWARD
	SOJL C,ECODB2
ECODB1:	HRRM C,ECHOPS		;STILL WITHIN RANGE, GO THERE
	JRST ECOPS0
ECODB2:	MOVE C,NHLNS		;MOVE TO LAST LINE - 2
	SUBI C,2
	HRRM C,ECHOPS
	JRST ECODPU		;AND UP A LINE

ECODPC:	SKIPN RGETTY		;^PC - CLEAR ECHO AREA
	 JRST ECHOCR		;TYPE CRLF ON PRINTING TERMINAL
	CALL ECODPT		;MOVE TO TOP OF ECHO AREA
	JRST CLREOS		;AND CLEAR TO END OF SCREEN

ECODF0:	HRRZ C,ECHOPS		;^PF - MOVE FORWARD
	AOJ C,
	CAMLE C,NHLNS
	 SETZ C,		;WRAP AROUND ON THE SAME LINE
	JRST ECODB1		;GO THERE

ECODPH:	SKIPA C,[-2]		;^PH - SET HORIZONTAL POSITION
ECODPV:	 MOVNI C,3		;^PV - SET VERTICAL POSITION
	MOVEM C,ECODPF
	RET

ERSCHR:
ECODPK:
IFN PTV\IMLAC\SIMLAC\IIMLAC\VTS,MOVE A,RGETTY
IFN PTV,[
	CAIN A,PTVI		;Plasma TV?
	 JRST [	HRROI A,[.BYTE 7 ? 33 ? "E]	;Yes, it needs this for
		JRST ECODK0 ]	; erase char (BS will overwrite)
]
IFN IMLAC\SIMLAC\IIMLAC,[
	CAIN A,IIMLCI
	 JRST .+3
	CAIE A,IMLCI		;BS OVERWRITES ON IMLAX
	 CAIN A,SIMLCI
	 JRST [	HRROI A,[.BYTE 7 ? 177 ? 204-176 ? 0]
		JRST ECODK0]
]
IFN VTS,[
	CAIN A,VTSI		;VTS virtual terminal?
	 JRST [	HRROI A,[.BYTE 7 ? ^P ? "K ]	;Yes, let monitor decide
		JRST ECODK0 ]
]
	HRROI A,[.BYTE 7 ? 40 ? 10 ? 0]		;^PK - ERASE CURRENT CHAR
ECODK0:	PSOUT
	RET

ECODPP:	SKIPA CH,[^P]		;^PP - TYPE ^P
ECODPQ:	 MOVEI CH,^C		;^PQ - TYPE ^C
	JRST ECHOC1		;JUST TYPE IT OUT

ECODPZ:	MOVE C,NVLNS		;^PZ - HOME DOWN
	SOSA C			;NUMBER OF LINES -1
ECODPT:	 MOVE C,ECHOL0		;^PT MOVE TO TOP
	HRLZM C,ECHOPS
	JRST ECOPS0		;GO THERE

ECHOHU:	MOVE Q,ECHOL0		;HOME UP ECHO AREA CURSOR
	HRLZM Q,ECHOPS		;BUT DON'T ACTUALLY MOVE THERE NOW.
	RET

ECODU2:	SKIPA C,NVLNS		;GO TO BOTTOM LINE
ECODPU:	 HLRZ C,ECHOPS		;^PU - MOVE UP
	SOJL C,ECODU2		;STILL IN RANGE?
	HRLM C,ECHOPS
	JRST ECOPS0		;YES, GO THERE

ECODPX:	MOVE C,ECHOPS		;^PX ERASE LAST CHARACTER
	TRNN C,-1		;AT START OF LINE?
	 JRST ECODX2
	CALL ECOPOS
	SOJ C,
	MOVEM C,ECHOPS
	MOVEI CH,^H
	CALL TYOINV
	JRST ECODPK
ECODX2:	HRR C,NHLNS
	SUB C,[1,,2]
	MOVEM C,ECHOPS
	CALL ECOPS0		;MOVE TO LAST COL -2 OF LAST LINE
	JRST CLREOL		;AND CLEAR TO END

;;; "TERMCAP" FILE FOR VARIOUS TERMINALS NOW IN SEPARATE FILE FOR
.INSRT	TECTRM.MID		;GET TERMINAL HANDLERS

OUTNSP:	MOVEI A,40
OUTN:	SAVE Q
	PBOUT
	SOJG Q,.-1
	REST Q
	RET

;OUTPUT AN ALTMODE FOLLOWED BY THE CHARACTER IN A, PRESERVING ALL ACS.
OUTESC:	SAVE A
	SAVE B
	MOVSI B,(ASCII//)
	DPB A,[260700,,B]
	HRROI A,B
	PSOUT
	JRST POPBAJ

;PAD WITH A SPECIFIC NUMBER OF RUBOUTS (IN A).
EXPPAD:	SAVE B
	CALL EXPPD1		;OUTPUT THEM ALL.
	JRST POPBJ

;PAD FOR A SPECIFIC LENGTH OF TIME.
;A CONTAINS THE NUMBER OF MSEC.  WE CLOBBER A AND B.
TIMPAD:	SKIPGE B,PADCHR		;PADCHR NONZERO MEANS WAIT INSTEAD OF PADDING.
	 JRST [	SAVE A
		MOVEI A,.PRIOU
		DOBE
		REST A
		DISMS
		RET]
	IMUL B,[<.BYTE 7 ? 1 ? 1 ? 1 ? 1 ? 1>_-1]
	LSH B,1
	CAME B,TIMPDS		;CHECK THAT WE HAVE THE RIGHT PAD CHARACTER
	 JRST [	MOVEM B,TIMPDS
		MOVE B,[TIMPDS,,TIMPDS+1]
		BLT B,TIMPDE-1
		JRST .+1]
	SKIPN B,OSPEED
	 MOVEI B,DEFOSP		;IF UNKNOWN, USE DEFAULT
	IMUL A,B
	CAIGE A,8000.		;IF MUCH LESS THAN 1 CHAR NEEDED, DON'T SEND ANY.
	 RET
	ADDI A,10000.-1
	IDIVI A,10000.		;GET NUMBER OF CHARS TO SEND
EXPPD1:	CAIL A,100.		;WE ONLY HAVE 100. RUBOUTS,
	 JRST [ SAVE A		;SO IF WE NEED MORE THAN THAT,
		MOVEI A,100.	;SEND 100. AT A TIME.
		CALL EXPPD2
		REST A
		SUBI A,100.
		JRST .-1]
EXPPD2:	JUMPE A,CPOPJ
	PUSH P,C
	MOVN C,A
	MOVEI A,.PRIOU		;NUMBER OF RUBOUTS TO OUTPUT
	HRROI B,TIMPDS
	SOUT
	JRST POPCJ

; SIMULATE CLEAR-TO-EOL ON A TERMINAL WHICH DOESN'T HAVE IT.
; THE DISPATCH VECTOR ENTRY FOR CLEAR-TO-EOL (AND THE ONE FOR CLEAR EOS,
; IF THAT IS ALSO MISSING) SHOULD CALL THIS ROUTINE.

;IF EOLFLG IS NEGATIVE, IT IS MINUS THE NUMBER OF COLUMNS THAT REALLY NEED CLEARING.
;THIS IS USED WHEN IT IS KNOWN THAT THE LINE USED TO BE BLANK PAST
;A CERTAIN POINT.
EOLSIM:	JSR SAVABC		; SAVE ACs
	SKIPGE C,EOLFLG		; NO. OF SPACES SET?
	 JRST EOLSI1		; YES, USE THAT
	HRRZ C,TTLPOS		; GET CURRENT POSITION
	SUB C,NHLNS
	SUBI C,1
EOLSI1:	HRROI B,SPACES
	MOVEI A,.PRIOU
	SOUT
	SETZM EOLFLG
	MOVE B,TTLPOS
	XCT @CURPSX
	JRST POPCBA

SPACES:	ASCII /                                                                                /
];IFN TNX

SUBTTL INTERRUPT HANDLERS

IFN ITS,[

TSINTP:	MOVEM 16,INTACS+16	;SAVE ALL ACS.
	MOVEI 16,INTACS
	BLT 16,INTACS+15
	MOVE C,TSINT
TSIL:	HRRZ A,TSINT+1	;GET THE PC IN CASE THE INTERRUPT ROUTINE WANTS TO CHECK IT FOR TYIIOT
	JUMPL C,TSIN2	;INT IN SECOND WORD
	TLZE C,%PJATY
	 JRST TSINTA
	TLZE C,%PJRLT
	 JRST TSINTC
	TLZE C,%PJWRO
	 TYPRE [PUR]
	TRZE C,%PIMPV		;MPV => CREATE THE NONEXISTENT CORE AND RETRY.
	 JRST TSINT4
	TRZE C,%PIPDL
	 TYPRE [PDL]
TSIN2A:	MOVSI 16,INTACS
	BLT 16,16
	.SUSET [.SJPC,,INTJPC]
	.DISMI TSINT+1

TSINTA:	CAIN A,RRECI7	;TTY GIVEN BACK TO TECO INTERRUPT.
	 AOS TSINT+1	;IF INSIDE AN ECHOIN, FINISH IT NOW, SO WE CAN CLEAR THE SCREEN.
	SKIPE RGETTY
	 SKIPL CLRMOD	;THIS FEATURE CAN BE DISABLED FOR DEBUGGING.
	  JRST TSIL
	SETOM PJATY	;SAY THAT WE SHOULD CLEAR THE SCREEN AND REDISPLAY COMPLETELY.
	SETOM DISOMD
	JRST TSIL

TSINTC:	SETOM CLKFLG	;REAL-TIME CLOCK INTERRUPT.  SAY IT'S TIME TO RUN THE HANDLER.
	CAIN A,RRECI7	;IF IN MIDDLE OF AN ECHOIN, RETURN FROM IT.
	 AOS TSINT+1	;THEN ^R WILL CALL TYI AND THAT WILL RUN THE HANDLER.
	CAIE A,TYIIOT	;IF WE ARE NOW WAITING FOR INPUT, RUN IT RIGHT AWAY,
	 JRST TSIL
	MOVEI A,TSINTD
	MOVEM A,TSINT+1	;BUT FIRST EXIT FROM INTERRUPT LEVEL AND RESTORE ACS.
	JRST TSIL

TSINTD:	CALL RLTCLK
	JRST TYIIOT

TSINT4:	SOS TSINT+1
	CAIL A,HUSED		;MPV INT: CATCH JUMPS TO RANDOMNESS.
	 .VALUE
	CAIN A,QLGET3+1		;IF DECODING A STRING POINTER, GIVE PROPER ERROR.
	 TYPRE [QNS]
	.SUSET [.RMPVA,,C]	;GET ADR START OF MISSING PAGE.
	LSH C,-12
	CAIN A,EJCMD4
	 JRST TSIN4A
	MOVE B,C
	IMULI B,2000*5
	CAMGE B,QRWRT		;ALL OF IMPURE STRING SPACE MARKED AS EXISTING SHOULD
	 .VALUE			;REALLY EXIST, OR THERE'S A BUG.
TSIN4A:	MOVE A,C
	SKIPN GCPTR		;NORMALLY, DON'T ALLOW USE OF LAST PAGE BLW PURE SPACE
	 AOS A			;BUT ALLOW GC TO USE IT FOR RELOCATION DATA.
	CAML A,LHIPAG
	 TYPRE [URK]
	SYSCAL CORBLK,[%CLIMM,,%CBWRT ? %CLIMM,,%JSELF ? C ? %CLIMM,,%JSNEW]
	 .LOSE %LSSYS
	MOVEI A,1(C)
	CAMLE A,MEMT	;IF THIS PAGE IS ABOVE ALL OTHERS, ADJUST MEMT.
	 MOVEM A,MEMT
	JRST TSIL

TSINT6:	SKIPE DISPRR	;HANDLE INTERRUPT FROM ALTMODE
	 JRST TSIL	;DO NOTHING IF INSIDE ^R.
	SETCMM TSINAL	;REMEMBER PARITY OF ALTMODES,
	SKIPN TSINAL	;IF SECOND, STOP DISPLAYING BUFFER.
	 JRST [	AOS TSALTC	;COUNT NUMBER OF $$ PAIRS SEEN.
		JRST TSIL]
	CALL TTYAC2	;IF FIRST ALTMODE, SAY THAT NEXT CHARACTER MUST INTERRUPT
	JRST TSIL	;SO WE CAN TELL AT INT. LEVEL. WHETHER THIS IS A $$ PAIR.

TSIN2:	TRZN C,TYPIN	;SECOND WORD INTERRUPT.  IS IT TYPE-IN?
	 JRST TSIN2A	;THAT'S ALL THERE IS.
TSINT1:	MOVEI A,CHTTYI
	.ITYIC A,
	 JRST TSIL
	HRRZ CH,TSINT+1
	CAIN CH,ASLEE2	;IF M.P. IS INSIDE A :^S, WAKE IT UP
	 AOS TSINT+1	;(IT HAS ARRANGED FOR ALL CHARS TO INTERRUPT)
	TRZ A,SHIFT+SHIFTL
	HRRZ CH,A
	ANDI CH,177
	CAIN CH,33	;ALTMODE => MUST SEE IF FOLLOWING CHAR IS AN ALTMODE.
	 JRST TSINT6
	SETZM TSINAL	;ELSE TELL NEXT CHAR (IF ALTMODE) THAT PREV. CHAR. WASN'T ONE.
	CAIE A,^G
	 CAIN A,CONTRL+"G
	  JRST TSINT3	;NOW CHECK FOR ALL FORMS OF ^G.
	CAIE A,CONTRL+"G+40
	 JRST TSIL
TSINT3:	TLNN FF,FLNOIN		;UNLESS IT IS JUST DISPLAYING, ...
	 SKIPE RREBEG		;DONT SET IF IN A ^R
	  SETOM STOPF
	MOVEI CH,CONTRL+"G
	CALL TYI4		;PUT THE ^G IN THE TYPE-IN RING BUFFER.
	HRRZ A,TSINT+1
	SKIPE JRNOUT
	 SKIPGE NOQUIT		;IF NOQUIT NEGATIVE (CAUSE ERROR), DON'T RECORD THE
	  JRST TSINT2		;QUIT: IT IS UP TO THE ONE HANDLING THE ERROR TO DO THAT.
	CAIN A,TYIIOT		;IF WAITING FOR INPUT, REPRESENT IT AS ":^G" IN THE JOURNAL
	 .IOT CHJRNO,[":]	;WHICH MEANS NO NEED FOR HAIR WHEN WE REPLAY.
	.IOT CHJRNO,[^G]	;IF ASYNCHRONOUS, REPRESENT AS JUST ^G.
TSINT2:	SKIPE JRNINH
	 JRST TSINT8
	SKIPE JRNIN		;STOP REPLAYING AN INPUT JOURNAL FILE.
	 .CLOSE CHJRNI,
	SETZM JRNIN
TSINT8:	SKIPLE CH,NOQUIT	;THAT'S ALL, IF NO QUITTING RIGHT NOW.
	 JRST TSIL
	CAIN A,RRECI7		;DON'T RETURN TO AN ECHOIN SYSTEM CALL.
	 AOS A,TSINT+1
	AOJL CH,TSINT5	;-2FSNOQUIT$ => DON'T FLUSH INPUT & OUTPUT.
	SKIPE RGETTY
	 JRST TSINT7	;ON DISPLAYS, CAN'T .RESET MAIN OUTPUT SINCE COULD LOSE TRACK OF SCREEN
	HLRZ CH,(A)
	ANDI CH,777740
	CAIN A,DISSI1
	 AOSA A,TSINT+1
	CAIN CH,(.IOT CHDPYO,)	;ON PRINTING TTY DON'T RETURN TO HUNG OUTPUT .IOT
	 AOS A,TSINT+1
	.RESET CHDPYO,
	.RESET CHTTYO,
TSINT7:	.RESET CHTTYI,
	SETOM UNRCHC
	SETZM TYISRC		;FLUSH ANY EXECUTING KBD MACRO.
	SKIPE TYISNK
	 HRRZM P,MODCHG		;MAKE MODE LINE RECOMPUTE SO IT WON'T SAY WE ARE DEFINING.
	SETZM TYISNK		;FLUSH DEFINING A KBD MACRO.
	MOVE CH,QRB..		;STUFF ON SCREEN CAN GO AWAY.
	SETZM .QVWFL(CH)
	MOVEI CH,TYI
	CAIN A,TYIIOT
	 MOVEM CH,TSINT+1
	MOVEI CH,CONTRL+"G	;IF NOW INSIDE ^R, STICK A ^G IN AS INPUT
	SKIPN RREBEG		;INSTEAD OF SETTING STOPF (WHICH WE AVOIDED DOING).
	 MOVEM CH,UNRCHC
	SKIPE RREBEG
	 SETOM ORESET		;SIGNAL TYPEOUT ROUTINES TO STOP TYPING
TSINT5:	SKIPN RREBEG
	 JRST TSIL
	CAIE A,TYIIOT
	SKIPE IMQUIT
	 CALL QUIT0	;QUIT, ERR, OR DO NOTHING ACCORDING TO NOQUIT.
	JRST TSIL
]

IFN TNX,[
;^G INTERRUPT COMES HERE
TSINT:	MOVEM 16,INTACS+16	;SAVE ACS
	MOVEI 16,INTACS
	BLT 16,INTACS+15
TSINT3:	TLNN FF,FLNOIN
	 SKIPE RREBEG		;SET STOPF, UNLESS INSIDE ^R (@V DOESN7T COUNT AS ^R).
	  SETOM STOPF
IFN COMNDF,[
	HRRZ A,INTPC1
	CAIN A,CFMPC
	 JRST [	HRRZ A,INTACS+D	;DON'T LEAVE AROUND STRAY JFNS
		RLJFN
		 JFCL
		JRST .+1]
];COMNDF
	SKIPE B,SAVMOD		;RESTORE TTY MODE REQUESTED?
	 CALL FFRRT2		;YES, DO IT THEN
	MOVEI CH,CONTRL+"G
	CALL TYI4		;PUT THE ^G IN THE TYPE-IN RING BUFFER.
	SKIPN JRNOUT
	 JRST TSINT6
	MOVE A,JRNOUT		;WRITE A ^G TO A JOURNAL FILE BEING WRITTEN.
	HRRZ C,INTPC1
IFN 20X\FNX,[
	CAIN C,VTSIOT		;RECOGNIZE OTHER POSSIBILITY FOR TYPEIN
	 MOVEI C,TYIIOT
];IFN 20X\FNX
	CAIE C,TYIIOT		;IF ^G TYPED WHILE NOT WAITING FOR INPUT
	 SKIPL NOQUIT		;AND NOQUIT NEGATIVE (CAUSE ERROR), DON'T RECORD THE
	  CAIA			;QUIT: IT IS UP TO THE ONE HANDLING THE ERROR TO DO THAT.
	   JRST TSINT6
	MOVEI B,":
	CAIN C,TYIIOT
	 BOUT			;IF WE WERE WAITING FOR INPUT, PUT ":^G" IN JOURNAL FILE.
	MOVEI B,^G		;OTHERWISE PUT JUST "^G" IN JOURNAL FILE.
	BOUT
TSINT6:	SKIPN JRNINH
	 SKIPN JRNIN		;IF REPLAYING A JOURNAL, STOP.
	  JRST TSINT7
	CLOSEF JRNIN
TSINT7:	SKIPLE B,NOQUIT	;QUIT NOT ALLOWED?
	 JRST TSIL	;YES, RETURN RIGHT AWAY
	MOVEI CH,CONTRL+"G
	AOJL B,TSINT5	;WANTS CLEAR INPUT?
	MOVEI A,.PRIIN	;YES
	CFIBF
	SETOM UNRCHC	;NOTHING WAITING
	SETZM TYISRC
	SKIPE TYISNK
	 HRRZM P,MODCHG		;MAKE MODE LINE RECOMPUTE SO IT WON'T SAY WE ARE DEFINING.
	SETZM TYISNK
	MOVE A,QRB..		;STUFF ON SCREEN CAN GO AWAY.
	SETZM .QVWFL(A)
	SKIPE RREBEG
	 SETOM ORESET
	SKIPN RREBEG	;IF FROM ^R, ...
TSINT5:	 MOVEM CH,UNRCHC	;PRETEND TO READ IT RATHER THAN SETTING STOPF
	HRRZ A,INTPC1
	MOVEI CH,TYI
IFN 20X\FNX,[
	CAIN A,VTSIOT
	 JRST [	ADJSP P,-2	.SEE VTSIO1
		MOVEI A,TYIIOT
		JRST .+2]		
]
	CAIN A,TYIIOT
	 MOVEM CH,INTPC1 ;DONT GET HUNG UP ON READING FROM TTY
	SKIPN RREBEG	;RETURN IF FROM ^R
	 JRST TSIL
	CAIE A,TYIIOT
	SKIPE IMQUIT
	 CALL QUIT0	;QUIT IF REQUESTED
TSIL:	MOVSI 16,INTACS	;RETURN
	BLT 16,16
	DEBRK

NXPINT:	MOVEM 16,INTACS+16
	MOVEI 16,INTACS
	BLT 16,INTACS+15
	HRRZ A,INTPC1
	CAIE A,QLGET3
	 CAIN A,QLGET3+1	;IF MPV HAPPENS TRYING TO LOOK AT A STRING POINTER,
	  TYPRE [QNS]		;GIVE "QREG NOT STRING" ERROR, NOT "URK".
	MOVEI 1,.FHSLF
	GTRPW
	HRRZS B,A	;GET WORD THAT GOT PAGE FAULT
	LSH A,-12
	IMULI B,5
	CAMGE B,QRWRT
	 .VALUE
	SKIPN GCPTR	;NORMALLY, REQUIRE ONE PAGE OF GAP BELOW PURE STRING SPACE,
	 AOS A		;BUT ALLOW GC TO USE THAT SPACE FOR ITS RELOCATION DATA.
	CAML A,LHIPAG
	 TYPRE [URK]
	SKIPE GCPTR	;DO THE AOS NOW IF WE DIDN'T BEFORE.
	 AOS A
	CAMLE A,MEMT	;IF THIS PAGE IS ABOVE ALL OTHERS, ADJUST MEMT.
	 MOVEM A,MEMT
	JRST TSIL

CNTRLC:	MOVEM 16,INTACS+16
	MOVEI 16,INTACS
	BLT 16,INTACS+15
	MOVEI CH,^C
	CALL ECHOCH
	HRRZ A,INTPC
	CAIN A,WAITX		;RUNNING AN INFERIOR?
	 JRST [	MOVEM A,INTPC	;FORCE JSYS RETURN
		MOVE A,INTACS+A	;GET FORK HANDLE
		FFORK		;FREEZE IT
		JRST TSIL]	;DEBRK TO PROCESS TERMINATION CODE
	CALL .EXIT		;OTHERWISE EXIT TO EXEC
	JRST TSIL

IFN EXITCL,[
.EXIT1:	CALL CLRSCN
	JRST DPYRST
];EXITCL
.ELSE	.EXIT1==DPYRST

.EXIT:	SKIPN SAVMOD			;UNLESS FROM INSIDE GTJFN
	 CALL .EXIT1			;TAKE TERMINAL OUT OF DISPLAY MODE
	MOVEI A,.CTTRM			;TENEX EXEC DOESNT KNOW ALWAYS KNOW
	RFMOD 
IFN 20X,[SKIPE PAGMOD			;WAS PAGE MODE IN EFFECT?
	 TROE B,TT%PGM			;YES, IS IT NOW?
	 CAIA
	 STPAR
];20X
IFN 20X\SUMTTF,[
	MOVE B,TTLPOS			;LET MONITOR KNOW WHERE WE ARE ON THE LINE
	MOVE CH,RGETTY
	CAIE CH,VTSI
	 SFPOS
];20X\SUMTTF
IFN 10X\FNX,[
IFE SUMTTF,[
	CALL ECHOCR			;CANNOT TELL MONITOR POSITION, SO GO TO BOL
	TRON B,100			;ABOUT RESTORING ASCII DATA MODE
	 SFMOD
];SUMTTF
IFN SUMTTF,[
	MOVE A,HLDCHR
	STCHA
];SUMTTF
	MOVEI A,.FHJOB
	SETO B,			;AND JOB TERMINAL INTERRUPT MASK
	STIW
]
	MOVEI B,BEG		.SEE CIRC
	HALTF			;STOP HERE
	PUSHJ P,DPYINI		;RE-INIT TERMINAL

PAGON:	SKIPGE CLRMOD
	 SETOM PJATY		;MUST ASSUME WE MESSED UP THE SCREEN
IFN 20X,[
	SKIPGE PAGMOD		;IF NOT MESSING WITH PAGE MODE
	 JRST DOSTIW
];20X
	MOVEI A,.CTTRM
	RFMOD
IFN 20X,[
	LDB C,[.BP TT%PGM,B]
	MOVEM C,PAGMOD			;SAVE CURRENT PAGE MODE SETTING FIRST
];20X
	MOVEI C,TT%PGM		;MAKE SURE PAGE MODE TURNED OFF
	SKIPE SAVMOD
	 JRST PAGON1		;FROM INSIDE GTJFN, JUST AFFECT PAGE MODE
	SKIPE CH,RGETTY		;RESET MODES
	 CAIN CH,VTSI		;IF VTS OR PRINTING,
	 SKIPA			;NO BINARY MODE CHANGES
	 TRO C,TT%DAM
PAGON1:	TRZN B,(C)
	 JRST DOSTIW
	SFMOD
	STPAR
IFN SUMTTF,[
	SETZ A,
	STCHA
	SKIPE A
	 MOVEM A,HLDCHR
];SUMTTF

DOSTIW:	MOVEI A,.FHSLF
	RPCAP
	JUMPGE C,CPOPJ			;NO ^C CAPABILITY
	MOVEI A,.FHJOB			;RESTORE INTERRUPT MASKS
IFN 10X\FNX,TLO A,400000
	MOVE B,[042000,,000060]	;^C & ^G
	MOVE C,RRMACT+CONTRL+"T		;IF ^T NOT ASSIGNED AS COMMAND
	CAIN C,RRUNDF
	 TRO B,100000			;ALLOW IT AS INTERRUPT TO SYSTEM
	MOVSI C,040000			;^C DEFERRED
	STIW
	RET

LEVTAB:	INTPC
	INTPC1
	INTPC2
CHNTAB:	2,,TSINT			;^G
IFN 20X,3,,ASLEE2			;ANYTHING TO WAKE FROM :^S
.ELSE	0
	1,,CNTRLC			;CONTROL-C INTERRUPT
IFN 20X,3,,TSINTC			;CLOCK INTERRUPT
	BLOCK .ICPOV-<.-CHNTAB>
	1,,[CIS ? TYPRE [PDL] ]		;PUSHDOWN OVERFLOW
	BLOCK .ICTOD-<.-CHNTAB>
IFN 10X\FNX,3,,TSINTC			;10X IIT INTERRUPT
	BLOCK .ICNXP-<.-CHNTAB>
	2,,NXPINT			;NEW PAGE CREATED
	BLOCK 36.-<.-CHNTAB>
];END IFN TNX

SUBTTL BIGPRINTING

.FNPNT:	
IFN ITS,[SYSCAL RFDATE,[%CLIMM,,CHFILI ? %CLOUT,,PTLFCD]
	 SETOM PTLFCD
]
	MOVEI A,PPA
	HRRM A,LISTF5
	PUSHJ P,.+1	;PRINT THE BIGPRINT TWICE.
IFN ITS,[
	MOVSI E,INFILE
.BPNT:	SAVE E
	MOVE CH,[LFN"NAMFLG 1]
	CALL .FNPT2
	REST E
	MOVE CH,[LFN"NAMFLG 2]
	CALL .FNPT2
]
.ELSE,[
	MOVEI A,ERDEV+DEFFN1-DEFDEV	;FN1
	CALL .FNPT2
	MOVEI A,ERDEV+DEFFN2-DEFDEV	;FN2
	CALL .FNPT2
]
	JRST FORMF

;BIGPRINT THE FILENAME WHOSE ADDRESS IS IN A
.FNPT2:	
IFN ITS,CALL FSRFNC
IFN ITS,MOVEI A,TMPFIL
IFN TNX,MOVE C,A
	CALL .ST26B
	PUSH P,A
	TRNN FF,FRARG
	 PUSHJ P,PTLAB
.FN3:	MOVE A,(P)
	MOVEI C,4
	PUSHJ P,CRR1
	SOJN C,.-1
	MOVEI TT1,7
.FN239:	MOVEI J,3
.FN249:	SETZM B
	ROTC A,6
	MOVEI T,3
.FN259:	XCT LDBT1-1(T)
	IMULI B,10101
	SETZM E
	TRNE TT,2
	HRLM B,E
	CAIG T,1
	JRST .FN269
	TRNE TT,1
	HRRM B,E
.FN269:	PUSHJ P,[JUMPN A,TYPR
		CAIE T,1	;DON'T PRINT TRAILING SPACES.
		 JRST TYPR
		JRST SIXNTY]
	IDIVI B,10101
	SOJN T,.FN259
	JUMPE A,.FN279
	MOVEI CH,40
	REPEAT 3,PUSHJ P,PPA
	JRST .FN249
.FN279:	MOVE A,(P)
	PUSHJ P,CRR1
	SOJN J,.FN249
	SOJN TT1,.FN239
	JRST POPAJ

IFN ITS,[
PTLAB:	PUSHJ P,CRR1
	MOVSI CH,(LFN"DEVFLG)	;OUTPUT DEVICE NAME
	MOVSI E,DEFFIL
	CALL FSRFNC
	MOVEI A,TMPFIL
	CALL ASCIND
	MOVEI CH,(LFN"DIRFLG)	;AND THE SNAME
	MOVSI E,DEFFIL
	CALL FSRFNC
	MOVEI A,TMPFIL
	CALL ASCIND

	CALL LISTF4
	.SUSET [.RUNAM,,E]
	PUSHJ P,TYPR
	PUSHJ P,LISTF4
	PUSHJ P,GDATIM	;GET DATE AND TIME
	POPJ P,		;SYSTEM DOESN'T HAVE THEM, QUIT HERE
	PUSHJ P,GLPDTM	;WIN, ALSO GET CRUD FOR PHASE OF MOON
	MOVE E,TIME	;GET TIME FOR PRINTING OUT
	DPB E,[301400,,CTIME+1]
	LSH E,-14
	DPB E,[61400,,CTIME]
	LSH E,-14
	DPB E,[301400,,CTIME]
	MOVE E,CTIME
	PUSHJ P,TYPR
	MOVE E,CTIME+1
	PUSHJ P,SIXNTY
	PUSHJ P,LISTF4
	PUSHJ P,SYMDAT	;TYPE OUT DATE
	PUSHJ P,LISTF4	;TYPE ANOTHER TAB
	PUSHJ P,POM		;PUSH OUT PHASE OF MOON
	SKIPG PTLFCD
	POPJ P,
	PUSHJ P,LISTF4
	MOVEI A,[ASCIZ \CREATED \]
	PUSHJ P,ASCIND
PTLAB9:	MOVEI A,"0
	HRRM A,DPT5
	TLZ FF,FLNEG
IRPS Q,R,[270400/220500/330700]
	LDB C,[Q,,PTLFCD]
	MOVEI TT,1
	PUSHJ P,DPT1
IFSE R,/,[	MOVEI CH,"/
	PUSHJ P,@LISTF5
]
TERMIN
	CALL SPSP
	HRRZ A,PTLFCD
	LSH A,-1
IRPS Q,R,[6:6:0]
	IDIVI A,12
	PUSH P,B
IFN Q,[	IDIVI A,Q
	PUSH P,B
	PUSH P,["R-"0]
]
.ELSE	PUSH P,A
TERMIN
	MOVEI IN,10
PTLAB3:	POP P,CH
	ADDI CH,"0
	PUSHJ P,@LISTF5
	SOJG IN,PTLAB3
	POPJ P,
]

IFN TNX,[
PTLAB:	PUSHJ P,CRR1
	MOVEI A,ERDEV
	CALL ASCIND
	MOVEI CH,":			;DEVICE:
	XCT LISTF5
	MOVEI CH,"<
	XCT LISTF5
	MOVEI A,ERDEV+DEFDIR-DEFDEV
	CALL ASCIND			;DIRECTORY
	MOVEI CH,">
	XCT LISTF5
	CALL LISTF4			;TYPE TAB
	GJINF
	MOVEI B,(A)			;LOGIN DIRECTORY
	HRROI A,BAKTAB
	DIRST
	 SETZM BAKTAB
	MOVEI A,BAKTAB
	CALL ASCIND
	CALL LISTF4
	HRROI A,BAKTAB
	SETOB B,C
	ODTIM
	MOVEI A,BAKTAB
	CALL ASCIND
	CALL LISTF4
	CALL POM			;INSERT PHASE OF MOON
	SKIPG PTLFCD
	 RET
	CALL LISTF4
	MOVEI A,[ASCIZ /Last written /]
	CALL ASCIND
	MOVE A,CHFILI
IFN 20X,[
	MOVEI B,B
	MOVEI C,1
	RFTAD
]
.ELSE	[
	MOVE B,[1,,.FBWRT]
	MOVEI C,B
	GTFDB
]
	HRROI A,BAKTAB
	SETZ C,
	ODTIM
	MOVEI A,BAKTAB
	JRST ASCIND
]
.ST26B:	SETZ A,
	MOVE OUT,[440600,,A]
	MOVEI IN,6
	HRLI C,440700
.ST26C:	ILDB CH,C
	JUMPE CH,CPOPJ
	SUBI CH,40
	IDPB CH,OUT
	SOJG IN,.ST26C
	RET

IFN ITS,[
AOFDIR:	MOVE D,[440700,,[ASCIZ /.FILE. (DIR)/]]
	CALL FFMRG
	SYSCAL SOPEN,[[.BAI,,CHRAND] ? [440700,,TMPFIL]]
	 JRST OPNER1
	POPJ P,

GFDBLK:	MOVE CH,[440700,,FDRBUF]
	MOVEM CH,FDRP
	HRLI CH,-FDRBFL
	SKIPN NOQUIT
	 SKIPL STOPF	;CHECK FOR QUIT; IF SO, PLAY LIKE EOF
	 .IOT CHRAND,CH
	HRLI CH,EOFCHR_<18.-7>
	HLLZM CH,(CH)
	POPJ P,
]

IFN ITS,[
SYMLST:	MOVEI CH,PPA
	HRRM CH,LISTF5
	PUSHJ P,FRD
	SETZM PTLFCD
	MOVSI E,TMPFIL
	JRST .BPNT
]
IFN TNX,[
SYMLST:	MOVEI CH,PPA
	HRRM CH,LISTF5
	SETZM PTLFCD
	CALL FRD0	;GET FILESPEC
	 JRST OPNER1
	PUSH P,A
	MOVSI C,001000
	CALL SYMLS2	;PRINT FILENAME
	MOVSI C,000100
	CALL SYMLS2	;AND EXTENSION
	POP P,A
	RLJFN		;GET RID OF IT
	 JFCL
	JRST FORMF

SYMLS2:	HRROI A,BAKTAB
	MOVE B,-1(P)
	JFNS
	MOVEI A,BAKTAB
	JRST .FNPT2	;AND BIGPRINT IT
]

LDBT1:	REPEAT 3,LDB TT,LDBT2-1+.RPCNT*7(TT1)

LDBT2:	REPEAT 21.,[%T1==.RPCNT/7
		%T2==.RPCNT-%T1*7
		CH5.7T(B+200+<2*%T1+5*%T2>_12.)
		]

CH5.7T:	0	;SP
DEFINE .. A,B,C,D,E,F,G,H
	IFSN H,,[PRINTC /CH5.7T LOSE!
/]
	A_31.+B_26.+C_21.+D_16.+E_11.+F_6+G_1
TERMIN

	.. 4,4,4,4,4,0,4,,	;!
	.. 12,12,12,0,0,0,0,,	;"
	.. 12,12,37,12,37,12,12,,	;#
	.. 4,17,24,16,5,36,4,,	;$
	.. 36,31,2,4,10,23,3,,	;%
	.. 4,12,4,10,25,22,15,,	;&
	.. 4,4,4,0,0,0,0,,	;'
	.. 2,4,10,10,10,4,2,,	;(
	.. 10,4,2,2,2,4,10,,	;)
	.. 0,25,16,33,16,25,0,,	;*
	.. 0,0,4,33,4,0,0,,	;+
	.. 0,0,0,0,14,4,10,,	;,
	.. 0,0,0,16,0,0,0,,	;-
	.. 0,0,0,0,0,14,14,,	;.
	.. 0,1,2,4,10,20,0,,	;/
	.. 16,21,23,25,31,21,16,,	;0
	.. 4,14,4,4,4,4,16,,	;1
	.. 16,21,1,2,4,10,37,,	;2
	.. 16,21,1,6,1,21,16,,	;3
	.. 2,6,12,37,2,2,2,,	;4 . . . OK, BEELER?
	.. 37,20,36,1,1,21,16,,	;5
	.. 16,21,20,36,21,21,16,,	;6
	.. 37,1,2,4,10,20,20,,	;7
	.. 16,21,16,21,21,21,16,,	;8
	.. 16,21,21,17,1,21,16,,	;9
	.. 0,14,14,0,14,14,0,,	;:
	.. 0,14,14,0,14,4,10,,	; ;
	.. 0,2,4,10,4,2,0,,	;<
	.. 0,0,37,0,37,0,0,,	;=
	.. 0,10,4,2,4,10,0,,	;>
	.. 16,21,2,4,4,0,4,,	;?
	.. 16,21,27,25,27,20,17,,	;@
	.. 16,21,21,37,21,21,21,,	;A
	.. 36,21,21,36,21,21,36,,	;B
	.. 16,21,20,20,20,21,16,,	;C
	.. 36,21,21,21,21,21,36,,	;D
	.. 37,20,20,36,20,20,37,,	;E
	.. 37,20,20,36,20,20,20,,	;F
	.. 16,21,20,20,23,21,16,,	;G
	.. 21,21,21,37,21,21,21,,	;H
	.. 16,4,4,4,4,4,16,,	;I
	.. 7,1,1,1,1,21,16,,	;J
	.. 21,22,24,34,22,21,21,,	;K
	.. 20,20,20,20,20,20,37,,	;L
	.. 21,33,25,21,21,21,21,,	;M
	.. 21,21,31,25,23,21,21,,	;N
	.. 16,21,21,21,21,21,16,,	;O
	.. 36,21,21,36,20,20,20,,	;P
	.. 16,21,21,21,25,22,15,,	;Q
	.. 36,21,21,36,21,21,21,,	;R
	.. 16,21,20,16,1,21,16,,	;S
	.. 37,4,4,4,4,4,4,,	;T
	.. 21,21,21,21,21,21,16,,	;U
	.. 21,21,21,21,21,12,4,,	;V
	.. 21,21,21,21,21,25,12,,	;W
	.. 21,21,12,4,12,21,21,,	;X
	.. 21,21,12,4,4,4,4,,	;Y
	.. 37,2,4,16,4,10,37,,	;Z
	.. 6,4,4,4,4,4,6,,	;[
	.. 0,20,10,4,2,1,0,,	;\
	.. 14,4,4,4,4,4,14,,	;]
	.. 4,16,25,4,4,4,4,,	;^
	.. 0,4,10,37,10,4,0,,	;_

	IFN .-CH5.7T-64.,.. ,,,,,,,69


SUBTTL DISPATCH TABLES

IFN CTRLT,[

;^T DISPATCH TABLE
EDDPTB:
REPEAT 3.,	BELL	;^@ - ^B
	EDCPY	;^C COPY NEXT CHAR
	EDD	;^D DELETE NEXT CHAR
	BELL	;^E
	ED%	;^F HELP TYPE REST OF THIS LINE, CR-LF, WHAT'S BEEN DONE SO FAR
	BELL	;^G QUIT (NEVER GETS HERE)
	BELL	;^H
	EDOV	;^I TAB, TAKE AS CHAR
	EDOV	;^J LINEFEED TAKE AS CHAR
	BELL	;^K
	EDL	;^L COPY REST OF LINE W/O ECHO AND END EDIT
	EDCR	;^M CR - END EDIT
	EDN	;^N COPY THRU NEXT SPACE OR EOL
	EDO	;^O DELETE THRU NEXT SPACE
	EDP	;^P ENTER/LEAVE PUT(INSERT) MODE
	EDQ	;^Q TAKE "T" AS CHAR ("T" IS CHAR FOLLOWING ^P IN TYPIN STRING)
	EDR	;^R COPY REST OF LINE
	EDS	;^S COPY TO CHAR "T"
	EDT	;^T DELETE TO CHAR "T"
REPEAT 2,BELL	;^U - ^V
	400000,,EDW	;^W DELETE TO LAST SPACE
REPEAT 3,	BELL	;^X - ^Z
	EDALT	;^[ (ALTMODE) COPY REST WITH ECHO AND END EDIT ;]
REPEAT 4,	BELL	; ^[, ^\, ^], ^^ AND ^_

] ;IFN CTRLT

;THE ERROR TABLE: EACH WORD HAS THE 3-CHAR MESSAGE IN LH,
;POINTER TO ASCIZ STRING IN RH.
;THE TABLE IS SORTED WITH THE 3-CHAR MESSAGE AS THE KEY.
;THE FIRST ARG TO ERRDEF IS THE 3-CHAR MESSAGE. IT MUST
;CONSIST OF 3 SIXBIT CHARACTERS.
;THE SECOND ARG TO ERRDEF IS WHAT SHOULD BE GIVEN AS THE ARG
;TO THE TYPRE MACRO. IT MUST CONSIST OF 3 SQUOZE CHARS.
;IN TECO LISTINGS, CROSS-REFS GO UNDER THE NAME WHICH
;IS THE ARG TO ERRDEF. IN CREFS, THEY ARE UNDER THE LABEL ACTUALLY
;USED, WHICH HAS AN "ER$" CONCATENATED ON TO THE FRONT.
;OF TYPRE TO CHECK FOR THEM.

IF1 [
ERTOTL==0	;ON PASS 1, ERTOTL ACCUMULATES AMOUNT OF STRING SPACE NEEDED FOR MESSAGES.
		;ALSO DEFINE THE LABELS FOR THE WORDS IN THIS TABLE.
DEFINE ERRDEF A,B,C/
ER$!B	ERTOTL==ERTOTL+<5+4+.LENGTH |C|+4>/5
	BLOCK 1
TERMIN
]

IF2 [
ERNEXT==ERSTRT	;ON PASS 2, PUT THE STRINGS WHERE THEY BELONG, AND THE 3-CHAR NAMES HERE.

DEFINE ERRDEF A,B,C/
ER$!B	SIXBIT /A/ ERNEXT*5-INIQRB+1
ERTMP==.
.=ERNEXT
	.BYTE 7
	0
	QRSTR
	ERLEN==<4+4+.LENGTH |C|>
	ERLEN&177
	<ERLEN/200>&177
	0
	.BYTE
	ASCII |A	C|
ERNEXT==.
.=ERTMP
TERMIN
]

ERRTAB:	ERRDEF	[..E]..E:,Bad value in q-reg ..E (output radix)
	ERRDEF	[2<1]2%1:,The second argument was less than the first
	ERRDEF	[AFN]AFN:,Ambiguous FS flag name
	ERRDEF	[AOR]AOR:,Argument out of range
	ERRDEF	[ARG]ARG:,Bad argument
	ERRDEF	[AVN]AVN:,Ambiguous variable or macro name.
	ERRDEF	[BD"]BD%:,Bad condition after " -- should be G,L,N,E,B,C,D,A or U
	ERRDEF	[BEL]BEL:,A built-in ^R command called from macro signaled an error
	ERRDEF	[CMD]CMD:,A char that isn't a TECO command was executed
	ERRDEF	[CNM]CNM:,Caller wasn't a macro (it was TECO internal code)
	ERRDEF	[DCD]DCD:,A disabled command was executed
	ERRDEF	[DSI]DSI:,Damned screw infinitely
	ERRDEF	[ERP]ERP:,Attempted :< ... ^\ with no closing > first
	ERRDEF	[ESR]ESR:,Empty sort record
	ERRDEF	[FTL]FTL:,Filename too long
;[
	ERRDEF	[ICB]ICB:,Illegal ^] command
	ERRDEF	[IEC]IEC:,Illegal "E" command
	ERRDEF	[IFC]IFC:,Illegal "F" command
	ERRDEF	[IFN]IFN:,Illegal FS flag name
	ERRDEF	[IQN]IQN:,Invalid q-register name
	ERRDEF	[ILN]ILN:,Invalid local q-register number
	ERRDEF	[ISK]ISK:,Invalid sort key - "^P" command
	ERRDEF	[KCB]KCB:,Kill currently selected buffer
	ERRDEF	[M^R]M%R:,Attempted to macro a meaningless number
	ERRDEF	[NDO]NDO:,No device open for output - try "EW"
	ERRDEF	[NFC]NFC:,No free channels to pop into
	ERRDEF	[NFI]NFI:,No file open for input - try doing "ER"
	ERRDEF	[NHP]NHP:,Nonexistent horizontal position
	ERRDEF	[NIB]NIB:,You have addressed a character not in the buffer
	ERRDEF	[NIM]NIM:,Not inside a macro
	ERRDEF	[NOP]NOP:,Specified type of IO channel hasn't been pushed
	ERRDEF	[NRA]NRA:,File not random access
	ERRDEF	[N^R]N%R:,Not in ^R - command meaningful only inside ^R
	ERRDEF	[PDL]PDL:,Pushdown stack full
	ERRDEF	[PUR]PUR:,Attempted write in pure page
	ERRDEF	[RDO]RDO:,Attempt to modify a read-only buffer
	ERRDEF	[QIT]QIT:,^G typed on TTY and FS NOQUIT$ was negative
	ERRDEF	[QNB]QNB:,Q-register not buffer - attempt to select a string or number
	ERRDEF	[QNN]QNN:,Q-register not numeric
	ERRDEF	[QNS]QNS:,Q-register not string or buffer
	ERRDEF	[QRF]QRF:,Q-regs failed, probably TECO bug
	ERRDEF	[QRP]QRP:,Q-register PDL overflow or underflow
	ERRDEF	[SFL]SFL:,Search failed
	ERRDEF	[SNI]SNI:,Semicolon not in iteration
	ERRDEF	[SNR]SNR:,There is no valid search string to repeat
	ERRDEF	[STL]STL:,String argument too long
	ERRDEF	[STS]STS:,Dispatch string too short
;[[[
	ERRDEF	[TMN]TMN:,Too many macro, ^]q-register, ^]^X, or ^]^Y nestings
	ERRDEF	[UBP]UBP:,Unbalanced parentheses found with an FL-type command
	ERRDEF	[UCT]UCT:,Unseen catch tag
	ERRDEF	[UEB]UEB:,FL-type command encountered end of buffer.
	ERRDEF	[UEC]UEC:,Unexpected end of command
	ERRDEF	[UGT]UGT:,Unseen go-tag
	ERRDEF	[UJC]UJC:,Undefined journal file characters
	ERRDEF	[UMC]UMC:,Unmatched ")" or ">" as a command
	ERRDEF	[URK]URK:,Buffer space or library space exhausted
	ERRDEF	[UTC]UTC:,Unterminated conditional
	ERRDEF	[UTI]UTI:,Unterminated iteration or errset (missing ">"?)
	ERRDEF	[UVN]UVN:,Undefined variable or macro name
	ERRDEF	[WLO]WLO:,FS OFACCP$ when old access pointer wasn't multiple of 5
	ERRDEF	[WNA]WNA:,Wrong number of arguments

LERTAB==.-ERRTAB

IF2 IFN ERNEXT-EREND,.ERR LOSSAGE IN ERRTAB.

;	E COMMANDS DISPATCH TABLES

ETAB:	JRST EQMRK		;?
	TYPRE [IEC]		;@
	TYPRE [IEC]		;A
	TYPRE [IEC]		;B
	JRST UICLS		;C
	JRST DELE		;D
	JRST EXITE		;E
	JRST EFCMD		;F
	JRST EGET		;G
	TYPRE [IEC]		;H
	JRST EICMD		;I
	JRST EJCMD		;J
	TYPRE [IEC]		;K
	JRST CNTRU1		;L
	JRST LISTFM		;M
	JRST RENAM		;N
	TYPRE [IEC]		;O
	JRST BPNTRD		;P
IFN ITS,JRST ALINK		;Q
IFN TNX,TYPRE [IEC]		;Q
	JRST .OPNRD		;R
	TYPRE [IEC]		;S
	JRST ETCMD		;T
	TYPRE [IEC]		;U
	TYPRE [IEC]		;V
	JRST WWINIT		;W
IFN TNX,JRST EXITX		;X
.ELSE	TYPRE [IEC]
	JRST LISTF		;Y
	JRST LISTFM		;Z
	JRST PSHIC		;[
	JRST PSHOC		;\
	JRST POPIC		;]
	JRST POPOC		;^
	JRST FCOPY		;_

LETAB==.-ETAB

;MUST BE SORTED BY FLAG NAME

DEFINE FLG A,B,C
	.1STWD SIXBIT/A/
IFB C,[FSNORM,,]IFNB C,[C,,]B+IFB B,A
TERMIN

FLAGS:	FLG ADLINE,		;SIZE OF LINE ADJUST FILLS (FA)
	FLG ALTCOU,TSALTC,FSALTC ;# CMD STRINGS WAITING TO BE READ.
	FLG BACKAR,0,FSBAKA	;RETURN ARGS OF OLD MACRO FRAME
	FLG BACKDE,MACDEP,FSRNLY ;DEPTH OF MACRO PDL.
	FLG BACKPC,0,FSBAKP	;RETURN RELATIVE PC OF OLD MACRO FRAME
	FLG BACKQP,0,FSBAKQ	;RETURN QPDL UNWIND POINTER OF OLD MACRO FRAME
	FLG BACKRE,0,FSBKRT	;RETURN CONTROL TO SPECIFIED FRAME.
	FLG BACKST,0,FSBAKS	;RETURN STRING POINTER TO MACRO ON MACRO PDL.
	FLG BACKTR,0,FSBAKT	;TRACES BACK THE MACRO PDL.
	FLG BBIND,0,FSBBIND	;PUSH OR POP CURRENT BUFFER CONVENIENTLY.
	FLG BCONS,0,FSBCON	;RETURN A NEW BUFFER.
	FLG BCREAT,0,FSCRBF	;CREATE NEW BUFFER (AND SELECT IT).
	FLG BKILL,0,FSKILB	;ARG = POINTER TO BUFFER TO BE KILLED.
	FLG BOTHCA,		;NONZERO => SEARCHES IGNORE CASE DISTINCTIONS.
	FLG BOUNDA,0,FSBOUN	;BOUNDARIES OF PART OF BUFFER BEING EDITED.
	FLG BSNOLF		;NOT 0 => BACKWARD MOTION SHOULDN'T BE FOLLOWED BY A LF.
	FLG CASE,CASNRM		;SET CASE-SHIFTING MODE.
	FLG CASENO,CASE		;SET CURRENT CASE-LOCK STATE.
IFN TNX,FLG CCLFNA,0,FSCCLF	;RETURN STRING FOR JFN IN 1 AT NORMAL ENTRY+2
	FLG CLKINT,CLKINT,FSCLKI	;SET CLOCK INTERVAL.
	FLG CLKMAC,CLKMAC	;CLOCK HANDLER ROUTINE.
	FLG CTLMTA,RRCMQT	;NEGATIVE => CONTROL-META-LETTER SSELF INSERTING.
	FLG DATASW,0,FSSWIT	;PDP10 CONSOLE SWITCHES.
	FLG DATE,0,FSDATE	;RETURN CURRENT DATE IN DISK FORMAT.
IFN TNX,FLG DDEVICE,DEFDEV,FSSTRR	;DEFAULT DEVICE AND FILENAMES.
IFN ITS,FLG DDEVICE,DEFFIL,FSFDEV
	FLG DDFAST,0,FSDDFS	;-1 IF DEFAULT DEVICE IS "FAST".
	FLG DFILE,0,FSDFILE	;DEFAULT FILE'S NAMES, AS STRING.
IFN TNX,FLG DFN1,DEFFN1,FSSTRR
IFN ITS,FLG DFN1,DEFFIL,FSFFN1
IFN TNX,FLG DFN2,DEFFN2,FSSTRR
IFN ITS,FLG DFN2,DEFFIL,FSFFN2
	FLG DFORCE,		;NOT 0 => FINISH DISPLAY DESPITE PENDING INPUT, DON'T UPDATE MODE LINE.
IFN TNX,FLG DSNAME,DEFDIR,FSDSNM
IFN ITS,FLG DSNAME,DEFFIL,FSFDIR
IFN TNX,FLG DVERSI,DEFFN3,FSDVER	;DEFAULT FN2 AS NUMBER < AND > SPECIAL
IFN ITS,FLG DVERSI,DEFFIL,FSDVER
	FLG DWAIT		;NONZERO => DON'T ALLOW MUCH STUFF IN TTY OUTPUT BUFFER.
	FLG ECHOAC,ECHACT	;-1 => ECHO AREA IS ACTIVE (CRUFT SHOULD BE CLEARED BY ^R).
	FLG ECHOCH,ECHCHR	;NONZERO => INHIBIT SCAN-ECHOING THIS ^R COMMAND.
	FLG ECHODI,0,FSECDS	;(WRITE-ONLY) ECHO-MODE DISPLAY-MODE OUTPUT OF ARG.
	FLG ECHOER,ERRECH	;NONZERO => TYPE ERR MSGS IN ECHO AREA.
	FLG ECHOFL,ECHFLS	;NONZERO => CLEAR ECHO AREA AFTER EACH COMPLETE ^R COMMAND.
	FLG ECHOLI,0,FSECLS	;# OF COMMAND LINES.
	FLG ECHOOU,0,FSECOT	;(WRITE-ONLY) ECHO-MODE OUTPUT OF ARGUMENT.
	FLG ERR,LASTER,FSERR	;SIGNAL AN ARBITRARY ERROR.
	FLG ERRFLG,ERRFL1	;WHEN ..B OR ..G MACROED, THIS
				;HAS 0 OR ERROR CODE OF CMD STRING JUST ENDED.
	FLG ERROR,LASTER,	;ERROR CODE OF MOST RECENT ERROR.
	FLG ERRTHROW,0,FSERTH	;THROW TO ERROR-CATCHING COMMAND LOOP (^R OR :@<).
	FLG EXIT,0,FSEXIT	;DO .BREAK 16, TO INTERUPT SUPERIOR.
IFN TNX,FLG EXPUNG,0,FSEXPU	;EXPUNGE CONNECTED DIRECTORY
	FLG FDCONV,0,FSDCNV	;CONVERT NUMERIC TO ASCII FILE DATES.
	FLG FILEPA,		;CHAR TO PAD LAST WD OF OUTPUT FILE WITH.
	FLG FLUSHED,MORFLF	;0 => NOT AFTER --FLUSHED, 1 => RUBOUT, -1 => OTHER FLUSHAGE.
	FLG FNAMSY,		;0 => IF ONLY ONE FILENAME, IT IS FN2.
				;> 0 => ONLY ONE FILENAME IS FN1.
				;< 0 => ONLY ONE FNAME IS FN1, AND FN2 IS ">".
IFN 20X,FLG FORKJC,FRKJCL	;JCL FOR THE GIVEN FORK
	FLG GAPLEN,EXTRAC,FSRNLY ;SIZE OF GAP.
	FLG GAPLOC,GPT,FSROCA	;CHAR ADDR OF GAP.
	FLG HEIGHT,NVLNS,FSRNLY	;NUMBER OF LINES TO DISPLAY
	FLG HELPCH,		;CHARACTER TO INVOKE "HELP" MACRO
	FLG HELPMAC,		;MACRO TO CALL IF USER TYPES "HELP" KEY.
	FLG HPOSIT,0,FSHPOS	;PHYSICAL POSITION OF A 2741 TYPEBALL IF IT TYPED FROM THE PREVOUS CARRET
	FLG HSNAME,,FSDIRH	;HOME DIRECTORY NAME.
	FLG I&DCHR,CID		;NONZERO => TRY TO USE CHAR I/D.
	FLG I&DLIN,LID		;NONZERO => TRY TO INSERT AND DELETE LINES.
	FLG I.BASE,		;INPUT RADIX FOR #S FOLLOWED BY ".".
	FLG IBASE,		;ORDINARY INPUT RADIX.
	FLG IFACCE,0,FSIFAC	;(WRITE-ONLY) SET INPUT FILE ACCESS PTR
	FLG IFCDAT,CHFILI,FSFDAT	;NUMERIC CREATION DATE OF INPUT FILE.
IFN TNX,FLG IFDEVI,ERDEV,FSSTRR	;DEVICE NOW READING FROM.
IFN ITS,FLG IFDEVI,INFILE,FSFDEV
IFN ITS,FLG IFDUMP,CHFILI,FSDUMP	;FILE HAS BEEN DUMPED BIT.
IFN TNX,FLG IFFDB,CHFILI,FSIFDB	;READ OR MODIFY FILE DESCRIPTOR BLOCK
IFN TNX,FLG IFFN1,<ERDEV+DEFFN1-DEFDEV>,FSSTRR	;FN1 OF FILE NOW OPEN FOR READING.
IFN ITS,FLG IFFN1,INFILE,FSFFN1
IFN TNX,FLG IFFN2,<ERDEV+DEFFN2-DEFDEV>,FSSTRR	;FN2 OF FILE NOW OPEN FOR READING.
IFN ITS,FLG IFFN2,INFILE,FSFFN2
	FLG IFILE,0,FSIFILE	;FILENAMES OF FILE NOW READING , AS STRING.
	FLG IFLENG,0,FSIFLEN	;(R-O) LENGTH OF INPUT FILE.
IFN ITS,FLG IFLINK,0,FSIFLN	;(R-O) -1 IF LAST INPUT FILE WAS REACHED VIA LINKS.
IFN TNX,FLG IFLINK,0,FSVAL
	FLG IFMTAP,CHFILI,FSMTAP	;DO .MTAPE ON INPUT FILE.
IFN ITS,FLG IFREAP,CHFILI,FSREAP	;DON'T REAP BIT.
IFN 20X,FLG IFREAP,CHFILI,FSREAP
IFN TNX,FLG IFSNAM,<ERDEV+DEFDIR-DEFDEV>,FSSTRR	;SNAME OF FILE NOW READING FROM.
IFN ITS,FLG IFSNAM,INFILE,FSFDIR
IFN TNX,FLG IFVERS,<ERDEV+DEFFN3-DEFDEV>,FSFVER	;VERSION OF FILE OPEN FOR READING.
IFN ITS,FLG IFVERS,INFILE,FSFVER
	FLG IMAGEO,0,FSIMAG	;(WRITE-ONLY) IMAGE MODE OUTPUT OF ARG
	FLG INCOUN,INCHCT	;NUMBER OF INPUT CHARACTERS SO FAR.
	FLG INSLEN,INSLEN	;LENGTH OF THE LAST INSERT STRING
	FLG INVMOD		; INVERSE VIDEO MODE LINE
IFN ITS,FLG JNAME,.RJNAM,FSRSYS	;GET TECO'S JNAME.
IFN TNX,FLG JNAME,0,FSGTNM
	FLG JRNEXE,0,FSJRNX	;OPEN AND EXECUTE A JOURNAL FILE.  USES DEFAULT NAMES.
	FLG JRNIN,,FSRNLY	;NON-ZERO IF JOURNAL FILE BEING RE-EXECUTED.
	FLG JRNINH		;NONZERO TO READ FROM TTY IN MIDDLE OF REDOING JOURNAL FILE.
	FLG JRNINT,JRNOIVL	;INTERVAL BETWEEN FORCING OUT JOURNAL OUTPUT FILE.
	FLG JRNMAC		;MACRO CALLED TO HANDLE "::" SEEN IN INPUT JOURNAL FILE.
	FLG JRNOPE,0,FSJRNO	;OPEN AN OUTPUT JOURNAL FILE.  USES DEFAULT NAMES.
	FLG JRNOUT,,FSRNLY	;NON-ZERO IF JOURNAL FILE BEING WRITTEN.
	FLG JRNREA,0,FSJRNR	;READ CHARACTER FROM JOURNAL INPUT FILE.
	FLG JRNUPD,0,JRNFRC	;UPDATE JOURNAL FILE.
	FLG JRNWRI,0,FSJRNW	;WRITE CHARACTER TO JOURNAL OUTPUT FILE.
	FLG LASTPA,,FSRNLY	;SET BY TECO TO 0 AFTER READING LAST PAGE OF INPUT FILE.
	FLG LEDEFS		.SEE RRSYNC
	FLG LINES,NLINES	;NUMBER OF LINES TO DISPLAY
	FLG LISPT,INITFL	;NONZERO => TECO WAS STARTED AT ALTERNATE ENTRY
				;POINT SIGNIFYING THAT SUPERIOR IS A LISP.
	FLG LISTEN,0,FSLISN	;DO .LISTEN, MAYBE PROMPT VIA FS ECHOT.
IFN TNX,FLG LOADAV,0,FSLOAD	;1 MINUTE LOAD AVERAGE
IFN ITS,FLG MACHIN,,FSRNLY	;READ MACHINE NAME
IFN TNX,FLG MACHIN,0,FSMACH
	FLG MODECH,MODCHG	;NONZERO SAYS MODMAC MUST BE CALLED.
	FLG MODEMA,MODMAC	;NONZERO => IS MACRO TO RECOMPUTE ..J WHEN NECESSARY.
	FLG MODIFI,MODIFF	;SET NONZERO WHEN BUFFER WRITTEN IN.
IFN ITS,FLG MPDISP,0,FSMPDS	;DISPLAY OUTPUT TO M.P. AREA.
IFN ITS,FLG MSNAME		;READ WORKING DIRECTORY NAME
IFN TNX,FLG MSNAME,0,FSDIRS	;READ CURRENT CONNECTED DIRECTORY
	FLG NLAROW,		;<>0=> DON'T ALLOW _ COMMAND
	FLG NOCEOL		;NONZERO MEANS TERMINAL HAS NO CL-EOL OPERATION
	FLG NOOPAL,		;SAY WHAT TO TO WITH ALTMODES AS COMMANDS.
				;0 => ERROR, -1 => IGNORE, 1 => LIKE ^_.
	FLG NOQUIT,,FSNQIT	;0 => ^G QUITS NORMALLY.
				;POS => ^G JUST SETS STOPF; NO QUITTING.
				;NEG => ^G CAUSES ERRSETABLE "QIT" ERROR.
	FLG OFACCE,0,FSOFAC	;(WRITE-ONLY) SET OUTPUT FILE ACCESS POINTER
	FLG OFCDAT,CHFILO,FSFDAT	;DATE OF OUTPUT FILE (NUMERIC)
IFN TNX,FLG OFFDB,CHFILO,FSOFDB	;MUNG OUTPUT FILE'S FDB
	FLG OFILE,0,FSOFILE	;REAL NAMES OF LAST OUTPUT FILE CLOSED.
	FLG OFLENG,0,FSOFLEN	;LENGTH OF OUTPUT FILE.
	FLG OFMTAP,CHFILO,FSMTAP	;DO .MTAPE ON OUTPUT FILE.
IFN TNX,FLG OFVERS,<ROUDEV+DEFFN3-DEFDEV>,FSFVER ;VERSION LAST OUTPUT FILE
IFN ITS,FLG OFVERS,OUTFIL,FSFVER
	FLG OLDFLU,OLDFLF	;OLD VALUE OF FS FLUSHED, IN NEXT ^R COMMAND AFTER THE FLUSHED ONE.
	FLG OLDMOD,DISOMD	;LAST ..J VALUE DISPLAYED.
	FLG OSPEED		;OUTPUT SPEED IN BAUD, OR 0 IF UNKNOWN.
	FLG OSTECO,TNX+10X\FNX,FSVAL	;OPERATING SYSTEM, 0 => ITS,
					;1 => TWENEX, 2 => TENEX
	FLG OUTPUT,OUTFLG	;-1 => OUTPUT TO FILE DISABLED.
IFN TNX,FLG PADCHR		;-1 => USE DELAY INSTEAD OF PADDING.
	FLG PAGENU,		;PAGE # IN CURRENT INPUT FILE.
	FLG PJATY		;NONZERO => SCREEN NEEDS REFRESHING.
	FLG PROMPT,PROMCH	;0, OR ASCII VALUE OF PROMPT CHAR.
	FLG PUSHPT,0,FSPSPT	;DO <ARG>^V
	FLG QPHOME,0,FSQPHO	;QREG PDL SLOT - WHERE IT WAS PUSHED FROM.
	FLG QPPTR,0,FSQPPT	;QREG PDL PTR
	FLG QPSLOT,0,FSQPSL	;QREG PDL SLOT (ARG SAYS WHICH ONE)
	FLG QPUNWI,0,FSQPUN	;UNWIND QREG PDL.
	FLG QUIT,STOPF		;NEGATIVE => A ^G-QUIT HAS BEEN REQUESTED.
	FLG QVECTO,0,FSQVEC	;RETURN A NEW QREG VECTOR BUFFER.
	FLG RANDOM,RDMNMS	;RANDOM # GENERATOR'S SEED.
	FLG READON		;NON-0 => DONT ALLOW MODIFICATION OF THIS BUFFER
	FLG REALAD,BEG,FSRNLY	;PHYS CHAR ADDR OF BEGINNING OF BUFFER.
	FLG REFRES,REFRSH	;MACRO TO REDISPLAY WHOLE SCREEN.
	FLG REREAD,UNRCHC	;-1, OR TTY CHARACTER TO RE-READ.
	FLG RGETTY,RGETTY,FSRNLY ;NON-0=> DISPLAY TERMINAL
	FLG RUBCRL		;NON-0 => RUBOUT AND ^D DELETE A WHOLE CRLF AT ONCE.
	FLG RUBMAC		;MACRO TO DO DELETE IN ^R OF MORE THAN ONE CHAR.
	FLG RUNTIM,0,FSRUNT	;NUMBER OF MICROSECONDS OF CPU TIME USED
	FLG SAIL,DISSAI		;NON0 => TTY ASSUMED TO PRINT SAIL CHAR SET.
	FLG SCRINV,SCINV,FSCRIV ; TURN INVERSE MODE ON/OFF
	FLG SCROLL,TTYOPT,FSSCRO
	FLG SEARCH,SFINDF	;VALUE RETURNED BY THE LAST SEARCH
	FLG SERROR,SRCERR	;NONZERO => FAILING SERACHES ARE ERRORS EVEN IN ITERATIONS.
	FLG SHOWMO,SHOMOD	;NOT 0 => FR SHOULD PRINT ..J ON PRINTING TTY.
	FLG SHPOS,0,FSSHPS	;LIKE FS HPOS BUT CTL CHARS APPEAR AS ON SCREEN.
	FLG SSTRING,0,FSSSTR	;CURRENT SEARCH STRING, AS A STRING.
	FLG STEPDE,STEPDE	;MAXIMUM MACRO PDL DEPTH FOR STEPPING TO GO ON.
	FLG STEPMA,STEPFL	;NONZERO => SINGLE STEP MACROS, LINE AT A TIME.
	FLG SUPERI,SUPHND	;MACRO TO HANDLE REQUESTS FROM SUPERIOR.
	FLG SVALUE,SFINDF	;VALUE RETURNED BY LAST SEARCH.
	FLG TABWID		;WIDTH OF TAB.
	FLG TOPLIN,TOPLIN,FSTPLN	;1ST LINE TO USE FOR BUFFER DISPLAY.
	FLG TRACE,<(.BP FRTRACE)>,FSWBIT	; -1 IFF IN TRACE MODE.
	FLG TRUNCA,DISTRN	;CONTROLS TRUNCATION VS. CONTINUATION OF TYPED LINES.
				;NEGATIVE => TRUNCATE, ELSE CONTINUE.
	FLG TTMODE,TTMODE
IFN 20X,FLG TTPAGM,PAGMOD,FSTTPG	;PAGE MODE HANDLING (^Q/^S)
IFN TNX,FLG TTYFCI,FCITYI	;POSITIVE, TERMINAL HAS META KEY
				;NEGATIVE, TERMINAL CAN DO 12-BIT INPUT
	FLG TTYINI,0,FSTTYI	;RE-INIT THE VARS RELATING TO TYPE OF TTY.
	FLG TTYMAC,TTYMAC	;MACRO FOR FS TTY INIT$ TO CALL.
IFN 20X,FLG TTYNBR,		;TTY'S .CTTRM NUMBER FOR 20X
	FLG TTYOPT,		;TTY'S TTYOPT VARIABLE.
IFN 20X,FLG TTYPAG,PAGMOD,FSTTPG	;PAGE MODE HANDLING (^Q/^S)
	FLG TTYSMT,		;TTY'S TTYSMT VARIABLE.
	FLG TYIBEG,INCHRR
	FLG TYICOU,INCHCT
	FLG TYISIN,TYISNK	;MACRO CALLED WITH EACH INPUT CHARACTER, FOR DEFINING KBD MACRO
	FLG TYISOU,TYISRC	;MACRO CALLED TO GET INPUT CHARS FROM KBD MACRO.
	FLG TYOHAS,0,FSHCD	;HASH CODE OF SCREEN LINE.
	FLG TYOHPO,CHCTHP,FSRNLY ;HPOS OF TYPEOUT, AT THE MOMENT.
	FLG TYOVPO,CHCTVP,FSRNLY ;VPOS OF TYPEOUT, AT THE MOMENT.
	FLG TYPEOU,TYOFLG	;-1 => NEXT TYPEOUT GOES AT SCREEN TOP.
				;ELSE TYPEOUT HAS BEEN DONE AND MORE TYPEOUT FOLLOWS IT.
IFN ITS,FLG UHSNAM,0,FSUHSN	;GET HSNAME OF A USER FROM DDT.
IFN ITS,FLG UINDEX,.RUIND,FSRSYS ;GET TECO'S JOB NUMBER.
IFN TNX,FLG UINDEX,0,FSJOBN
IFN ITS,FLG UMAILF,0,FSUML	;GET FILENAME OF A USER'S MAIL FILE FROM DDT.
IFN 20X,FLG UMAILF,0,FSUML	;TOPS-20 MAIL FILE
IFN ITS,FLG UNAME,.RUNAME,FSRSYS ;GET TECO'S UNAME.
IFN TNX,FLG UNAME,0,FSDIR2
	FLG UPTIME,0,FSUPTI	;SYSTEM UP TIME IN 60'TH'S.
	FLG UREAD,<(.BP (FLIN))>,FSBIT	;-1 IF INPUT FILE, ELSE 0.
IFN 20X,FLG USRNUM,0,FSUSRN	;20X USER NUMBER
	FLG UWRITE,<(.BP (FLOUT))>,FSBIT	;-1 IFF OUTPUT FILE OPEN, ELSE 0.
	FLG VARMAC,		;NONZERO => ENABLE FEATURE TO RUN MACRO WHEN VARIABLE CHANGES.
	FLG VB,0,FSVB		;BEGV, BUT CAN BE PUSHED/POPPED.
	FLG VERBOS,VERBOS	;<>0=> DISPLAY MOBY ERROR MESSAGES
	FLG VERSIO,.FVERS,FSVAL	;VERSION NUMBER OF THIS TECO
	FLG VZ,0,FSVZ		;Z-ZV, BUT CAN BE PUSHED/POPPED.
	FLG WIDTH,NHLNS,FSWIDTH	;SIZE OF THE TYPED\DISPLAYED LINE
	FLG WINDOW,GEA		;CHAR ADDR (REL BEGV) OF 1ST CHAR IN WINDOW
	FLG WORD,0,FSWORD	;GET OR SET SOME WORD IN THE CURRNET BUFFER.
IFN ITS,FLG XJNAME,.RXJNA,FSRSYS ;INSERT .XJNAME IN BUFFER
IFN TNX,FLG XJNAME,0,FSGXNM
	FLG XMODIF,MODIFM	;LONG-TERM VERSION OF FS MODIFIED.
	FLG XPROMP,RUBENC	;0, OR CHAR TO TYPE NEXT TIME DISINI DONE.
IFN ITS,FLG XUNAME,.RXUNA,FSRSYS ;INSERT .XUNAME IN BUFFER
IFN TNX,FLG XUNAME,0,FSDIR2
IFN TNX,FLG XUSRNU,0,FSXUSR
	FLG YDISAB,		;DISABLES Y COMMAND IN VARIOUS WAYS
	FLG Z,Z,FSROCA		;# CHARS IN BUFFER (Z COMMAND IS 1 + # OF LAST CHAR IN RANGE BEING EDITED.)
	FLG ^HPRIN,DISPBS	;PRINT BS AS BS?  NEGATIVE => YES.
	FLG ^IDISA,TABMOD	;0 => TABS INSERT  1 => ERROR  -1 => IGNORE.
	FLG ^LINSE,FFMODE	;NON0 => ^L'S READ FROM FILE GO IN BUFFER.
	FLG ^MPRIN,DISPCR	;STRAY CR CAN COME OUT AS CR?  NEGATIVE => YES.
	FLG ^PCASE,PSCASE	;NONZERO => ^P SORT IGNORES CASE.
	FLG ^RARG,RRRPCT	;BASIC ^R-MODE ARGUMENT (SET BY ^V)
	FLG ^RARGP,RRARGP	;0 => USE 1 INSTEAD OF FS ^RARG$.
	FLG ^RCCOL,RRCCOL	;COMMENT COLUMN FOR ^R MODE.
	FLG ^RCMAC,0,FSCRMA	;MACROS ASSOCIATED WITH CHARS.
	FLG ^RDISP,RRDISM	;MACRO TO RUN WHEN ABOUT TO DO NONTRIVIAL REDISPLAY.
	FLG ^RECHO,RRECHO	;CONTROLS ECHOING OF CHARACTERS READ IN BY ^R.
	FLG ^RECSD,RRECSD	;IF SPACE'S DEFINITION EQUALS THIS, RRECIN CAN ECHO SPACES.
	FLG ^RENTER,RRENTM	;MACROED WHEN ^R IS ENTERED.
	FLG ^REXIT,0,FSCREX	;EXIT FROM ^R WHEN EXECUTED.
	FLG ^REXPT,RR4TCT	;EXPONENT-OF-4, INCREMENTED BY ^U.
	FLG ^RHMIN,RRMNHP	;HPOS OF FIRST CHANGE ON SCREEN NEEDING REDISPLAY.
	FLG ^RHPOS,RRHPOS	;HPOS OF CURSOR IN ^R MODE.
	FLG ^RINCO,INCHRR	;TOTAL # OF INPUT CHARS, AT START OF LAST ^R COMMAND.
	FLG ^RINDI,0,FSINDT	;TRACE ^R INDIRECT COMMAND DEFINITIONS.
	FLG ^RINHI,RRINHI	;NONZERO INHIBITS ALL DISPLAY UPDATING.
	FLG ^RINIT,0,FSCRIN	;INITIAL VALUE OF FS ^R CMACRO$
	FLG ^RINSE,0,FSRRINS	;INTERNAL ^R 1-CHAR INSERT ROUTINE.
	FLG ^RLAST,RRLAST	;MOST RECENT ^R-MODE CHAR (EXCEPT ARG-SETTING CHARS)
	FLG ^RLEAVE,RRLEVM	;MACROED WHEN ^R EXITS (BUT NOT IF ERR'D OR THROWN THRU)
	FLG ^RMARK,RRMKPT	;THE ^R-MODE MARK, SET BY ^T. -1 => NO MARK NOW.
	FLG ^RMAX,RRTTMX	;MAX # CHARS OF INSERT OR DELETE TO TYPE OUT.
	FLG ^RMCNT,RRMCC1	;THE COUNTER USED TO TELL WHEN TO CALL SEC'Y MACRO.
				;INITTED FROM FS ^RMDLY, COUNTED DOWN TO 0.
	FLG ^RMDLY,RRMCCT	;# OF ^R CMDS TO DO BETWEEN INVOCATIONS OF SEC'Y MACRO.
	FLG ^RMODE,DISPRR,FSRNLY ;NONZERO IN ^R MODE.
	FLG ^RMORE,RRMORF	;> 0 SAYS USE --MORE-- INSTEAD OF --TOP-- IN ^R MODE.
				;< 0 SAYS USE NEITHER --MORE-- NOR --TOP--.
	FLG ^RNORM,RRXINV	;THIS IS THE REAL DEFINITION OF ANY ^R-MD CHAR DEFINED
				;TO BE "SELF-INSERTING". ZERO MEANS ACTUALLY SELF-INSERT.
	FLG ^RPAREN,RRPARN	;THIS GETS RUN FOR SELF-INSERTING CHARS THAT HAVE ")" SYNTAX.
	FLG ^RPREV,RRPRVC	;THE ^R-MODE COMMAND CHAR BEFORE THE ONE IN ^R LAST.
	FLG ^RREPL,RRRPLC	;CONTROLS INSERTION VS REPLACEMENT BY NORMAL CHARS.
	FLG ^RRUBO,0,FSRRRUB	;INTERNAL ^R RUBOUT ROUTINE.
	FLG ^RSCAN,RRSCAN	;NONZERO => ^R ON PRINTING TTY PRINTS CHARS MOVED OVER.
	FLG ^RSTAR,RRSTAR	;NONZERO => DISPLAY STAR IN MODE LINE.
	FLG ^RSUPP,RRALQT	;NONZERO SUPPRESSES BUILTIN COMMANDS
	FLG ^RTHRO,0,FSCRTH	;THROW TO INNERMOST ^R INVOCATION.
	FLG ^RTTM1,RRTTM1	;MACRO TO HANDLE LONG CURSOR MOTION ON PRINTING TTY.
	FLG ^RUNSU,RRUNQT
	FLG ^RVMIN,RRMNVP	;VPOS OF FIRST CHANGE ON SCREEN NEEDING REDISPLAY.
	FLG ^RVPOS,RRVPOS	;VPOS OF CURSOR IN ^R MODE.
	FLG _DISAB,NLAROW
	FLG %BOTTO,		;PERCENT AT BOTTOM BARRED TO CURSOR.
	FLG %CENTE,		;PERCENT FROM TOP TO PREFERRED LOCATION FOR CURSOR (WHEN WINDOW CHOSEN)
	FLG %END,		;PERCENT AT BOTTOM BARRED TO CURSOR WHEN WINDOW CHOSEN.
IFN ITS,FLG %OPLSP,<(.BP (%OPLSP))>,FSOPTL	;VALUE OF JOB'S %OPLSP BIT (SUPERIOR IS LISP).
	FLG %TOCID,<(.BP (%TOCID))>,FSTTOL	;VALUE OF TTY'S %TOCID BIT.
	FLG %TOFCI,<(.BP (%TOFCI))>,FSTTOL	;VALUE OF TTY'S %TOFCI BIT.
	FLG %TOHDX,<(.BP (%TOHDX))>,FSTTOL	;VALUE OF TTY'S %TOHDX BIT.
	FLG %TOLID,<(.BP (%TOLID))>,FSTTOL	;VALUE OF TTY'S %TOLID BIT.
	FLG %TOLWR,<(.BP (%TOLWR))>,FSTTOL	;VALUE OF TTY'S %TOLWR BIT.
	FLG %TOMOR,<(.BP (%TOMOR))>,FSTTOL	;VALUE OF TTY'S %TOMOR BIT.
	FLG %TOOVR,<(.BP (%TOOVR))>,FSTTOL	;VALUE OF TTY'S %TOOVR BIT.
	FLG %TOP,				;PERCENT OF SCREEN AT TOP BARRED TO CURSOR.
	FLG %TOROL,<(.BP (%TOROL))>,FSTTOL	;VALUE OF TTY'S %TOROL BIT.
	FLG %TOSAI,<(.BP (%TOSAI))>,FSTTOL	;VALUE OF TTY'S %TOSAI BIT.
	FLG %TPMTA,<(.BP %TPMTA)>,FSTTOL	;VALUE OF TTY'S %TPMTA BIT.
	FLG *RSET,UNWINF	;NONZERO PREVENTS AUTOMATIC QRP UNWINDING.
	FLG .CLRMO,CLRMOD	;NONZERO => CLEAR SCREEN WHEN TTY GIVEN BACK BY SUPERIOR.
	FLG .KILMO,KILMOD	;(NORMALLY NON-0) 0 MAKES FSBKILL$ A NOOP.
	FLG .TYIBA,0,FSTBBK	;DECREMENT THE FS .TYIPT$ POINTER.
	FLG .TYINX,0,FSTBNXT	;ILDB THAT POINTER AND RING IT AROUND TO GET NEXT OLD TYI CHAR.
	FLG .TYIPT,TYIBFQ,FSRNLY	;POINTER TO NEXT TYI CHARACTER IN RING BUFFER.
	FLG :EJPAG,LHIPAG,FSEJPG	;# OF LOWEST PAGE IN USE BY PURE STRING SPACE
IFN TNX,FLG :ETMOD,ETMODE	;BITMASK OF FIELDS TO DEFAULT IN :ET COMMAND
FLAGSL==<.-FLAGS>/2

FLAGD==FLAGS+1

	<-1>_-1		;THIS TERMINATES THE AMBIGUITY TEST AT FSFND.
	BLOCK 4		;FOR PATCHING (HARD BUT POSSIBLE)

IFCERR==TYPRE [IFC]

FDTB:	JRST FCTLAT	;^@
	JRST FCACMD	;^A
	JRST FMEMQ	;^B
TYPIFC:	IFCERR		;^C
	IFCERR		;^D
	JRST FCECMD	;^E
	JRST FCTLF	;^F
	JRST FCTLG	;^G
	IFCERR		;^H
	IFCERR		;^I
	IFCERR		;^J
	JRST FCTLK	;^K
	REPEAT ^R-^K-1,IFCERR
	JRST RRALTR	;^R
	JRST TABSRC	;^S
	REPEAT ^X-^S-1,IFCERR
	JRST FCTLX	;^X
	JRST FCTLY	;^Y   ;[
	REPEAT 4,IFCERR	;^Z - ^]
	JRST FCTLUP	;^^
	IFCERR		;^_
	IFCERR		;SPACE
	IFCERR		;!
	JRST FDQUOT	;"
	IFCERR		;#
	JRST FSCASE	;$
	REPEAT 3,IFCERR	;%-'
	JRST FOPEN	;(
	JRST FCLOSE	;)
	JRST FNOOP	;*
	JRST CTLL	;+
	REPEAT "6-"+-1,IFCERR
	JRST FSIXB	;6
	REPEAT ";-"6-1,IFCERR
	JRST FSEMIC	;;
	JRST FLSSTH	;<
	JRST FEQ	;=
	IFCERR		;>
	JRST FLSCMD	;?
	IFCERR		;@
	JRST ADJUST	;A
	JRST FBCMD	;B
	JRST LOWCON	;C
	JRST FDCMD	;D
	JRST FECMD	;E
	IFCERR		;F
	JRST FGCMD	;G
	IFCERR		;H
	JRST FTYI	;I
	JRST FJCL	;J
	JRST FKCMD	;K
	JRST FLCMD	;L
	JRST FMCMD	;M
	JRST FNCMD	;N
	JRST FOCMD	;O
	JRST FDATTY	;P
	JRST QLEN	;Q
	JRST FRCMD	;R
	JRST FSET	;S
	JRST FTYPE	;T
	JRST FUCMD	;U
	JRST FVIEW	;V
	JRST FWCMD	;W
	JRST FXCMD	;X
	JRST FYCMD	;Y
IFE TNX,IFCERR		;Z
IFN TNX,JRST FZCMD	;Z
	JRST FPUSH	;[
	IFCERR		;\
	JRST FPOP	;]
	JRST FAPPRX	;^
	JRST SERCHA	;_, LIKE NORMAL _ CMD.
IFN .-FDTB-140,[PRINTX \FDTB LOSS
\]


DTB:	HRROI B,CNTRAT	;^@
	MOVEI B,COR	;^A
	HRROI B,CTLB	;^B
	TYPRE [CMD]	;^C
	TYPRE [CMD]	;^D
	TYPRE [CMD]	;^E
	HRROI B,CNTRLF	;^F
	TYPRE [CMD]	;^G - TS QUIT
	TYPRE [CMD]	;^H - BACKSPACE
	JRST TAB	;^I - TAB
	MOVEI B,CD	;^J - LINE FEED
	HRROI B,DECDMP	;^K - VALRET SOMETHING
	HRROI B,CTLL	;^L - FORM FEED
	HRROI B,CTLM	;^M - CARR RET
	HRROI B,CNTRLN	;^N
	HRROI B,SYMLST	;^O
	HRROI B,PSORT	;^P
	TYPRE [CMD]	;^Q
	HRROI B,RRENTR	;^R
	HRROI B,ASLEEP	;^S
IFN CTRLT,HRROI B,EDIT	;^T
.ELSE	TYPRE [CMD]	;^T
	HRROI B,CNTRLU	;^U
	HRROI B,CTLV	;^V
	JRST CTLW	;^W
	HRROI B,GMARG1	;^X
	HRROI B,GMARG2	;^Y
	HRROI B,RANDOM	;^Z
	JRST ALTCMD	;ALTMODE
	MOVEI B,MEXIT	;^\
	TYPRE [CMD]	;[ ;^]
	HRROI B,CNTRUP	;^^
	JRST LGOGO	;^_

	MOVEI B,SPACE	;
	MOVEI B,EXCLAM	;!
	MOVEI B,DQUOTE	;"
	MOVEI B,CXOR	;#
	HRROI B,NEWAS	;$
	HRROI B,PCNT	;%
	MOVEI B,CAND	;&
	JRST CD5A	;'
	MOVEI B,OPEN	;(
	MOVEI B,CLOSE	;)
	MOVEI B,TIMES	;*
	MOVEI B,PLUS	;+
	MOVEI B,COMMA	;,
	MOVEI B,MINUS	;-
	JRST PNT	;.
	MOVEI B,SLASH	;/
REPEAT 12,JRST CDNUM	;DIGITS 0 - 9.
	JRST ACOLON	;:
	MOVEI B,SEMICL	; ;
	MOVEI B,LSSTH	;<
	HRROI B,PRNT	;=
	JRST GRTH	;>
	HRROI B,QUESTN	;?
	JRST ASLSL	;@
	HRROI B,APPEND	;A
	HRROI B,BCMD	;B
	HRROI B,CHARAC	;C
	HRROI B,DELETE	;D
	HRROI B,ECMD	;E
	HRROI B,FCMD	;F
	HRROI B,QGET	;G
	HRROI B,HOLE	;H
	HRROI B,INSERT	;I
	HRROI B,JMP	;J
	HRROI B,KILL	;K
	HRROI B,LINE	;L
	MOVEI B,MAC	;M
	HRROI B,SERCHP	;N
	MOVEI B,OG	;O
	HRROI B,PUNCH	;P
	HRROI B,QREG	;Q
	HRROI B,REVERS	;R
	HRROI B,SERCH	;S
	HRROI B,TYPE	;T
	HRROI B,USE	;U
	HRROI B,VIEW	;V
	MOVEI B,CD	;W
	HRROI B,X	;X
	HRROI B,YANK	;Y
	HRROI B,END1	;Z
	HRROI B,OPENB	;[
	HRROI B,BAKSL	;\
	HRROI B,CLOSEB	;]
	JRST ASLSL	;^
	JRST BAKARR	;_
IFN .-DTB-140,.ERR DTB WRONG # ENTRIES.

CONSTANTS

PAT:
PATCH":	BLOCK 200
PATCHE":	0

HUSED:	INFORM [TOP OF PURE]\.-1

LOC <.+1777>&776000

HIMPUR::

VARIABLES

;IF ^R VARIABLES DON'T FIT IN LOW IMPURE, PUT THEM HERE.
IFG <RRVARX&1777>+RRVARL-1777, RRVARB:: BLOCK RRVARL

IFN LINSAV,[
;VARIABLES FOR LINE SAVING PROTOCOL.

;Highest label (+ 1) that we can use.
;Zero if line saving is not available on our terminal.
LBLLIM:	0

;Beginning of region to clear at tty init time.
LBLBEG::

;Hash code of what was saved under each label.
;-1 for unused label.
LBLHCD:	BLOCK MAXLBL

;Indexed by screen line, gives label last used to restore that line
;or -1 if it was output explicitly, or was cleared and not output yet.
LINLBL:	BLOCK MXNVLS

;Next label to allocate when we save another line.
LBLNXT:	0

;End of region to clear at tty init time.
LBLEND::

;Label we used for restoring the last line that wanted restoring.
;-1 if no label was available.
;For successive lines, successive labels is a good guess.
LBLRST:	-1
];LINSAV

;^R-MODE COMMAND DISPATCH TABLE. POSITIVE => BUILTIN COMMAND;
;RH IS DISP. ADDR, LH IS EXTRA INFO (SECONDARY DISP. ADDR).
;NEGATIVE => IT IS STRING POINTER TO MACRO.
RRMACT:
;NON-CONTROL, NON-META CHARACTERS:
REPEAT ^H,RRXINS	;^@ - ^G
REPEAT 3,RRINSC,,RRREPI	;^H, ^I, ^J NEVER REPLACE, REGARDLESS OF FS ^R REPLACE$
	RRXINS		;^K
	RRXINS		;^L
	RRCRLF,,RRREPT	;^M
REPEAT 33-^M-1,RRXINS	;^N - ^Z
	RREXIT		;ALTMODE
REPEAT "A+40-ALTMOD-1,RRXINS ;^\ - `
REPEAT 26.,40,,RRINDR	;LOWERCASE LETTERS.
REPEAT 4,RRXINS		;LOWERCASE SPECIAL CHARACTERS.
	RRRUB

.SEE RRITAB	;MUST BE CHANGED WHEN THE ENTRIES BELOW ARE CHANGED.
;CONTROL, NON-META CHARACTERS:
REPEAT ^H,RRUNDF	;CONTROL-^@ TO CONTROL-^G
REPEAT 3,200,,RRINDR	;CONTROL-BS TO CONTROL-LF.
REPEAT 2,RRUNDF		;CONTROL-^K AND CONTROL-^L.
	200,,RRINDR	;CONTROL-CR
REPEAT 33-^M-1,RRUNDF	;CONTROL-^N THROUGH CONTROL-^Z.
	200,,RRINDR	;CONTROL-ALTMODE.
REPEAT "--33-1,RRUNDF	;CONTROL-^\ TO CONTROL-,
	RRCMNS		;CONTROL-MINUS
REPEAT "0-"--1,RRUNDF	;CONTROL-. TO CONTROL-/
REPEAT 10.,RRCDGT	;CONTROL-0 THRU CONTROL-9
REPEAT 100-"9-1,RRUNDF	;CONTROL-: TO CONTROL-?
	RRUNDF		;^@
	RRBEG		;^A
	RRCTLB		;^B
	RRCMSW		;^C
	RRCTLD		;^D
	RREND		;^E
	RRCTLF		;^F
	RRQUIT		;^G
	300,,RRINDR	;^H
	300,,RRINDR	;^I
	300,,RRINDR	;^J
	RRKILL		;^K
	RRCTLL		;^L
	RRINSC,,RRREPI	;^M
	RRNEXT		;^N
	RRCTLO,,RRREPT	;^O
	RRPREV		;^P
	RRQUOT		;^Q
	RRCMCS		;^R
	RRSRCH		;^S
	RRMARK		;^T
	RR4TIM		;^U
	RRARG		;^V
	RRFX		;^W
	RREXCH		;^X
	RRUNDF		;^Y
	RRUNDF		;^Z
	RRUNDF		;^[
	RRUNDF		;^\
	RRBRC		;^]
	RRUNDF		;^^
	RRUNDF		;^_
	RRUNDF		;^`
REPEAT 32,40,,RRINDR	;^<LOWERCASE LETTERS>
REPEAT 4,RRUNDF		;^{ ^| ^} ^~
	RRCRUB		;CONTROL-RUBOUT.
IFN .-RRMACT-400,,.ERR

;META CHARS:
REPEAT "-,RRXINS
	RRCMNS
REPEAT "0-"--1,RRXINS
REPEAT 10.,RRCDGT
REPEAT "A+40-"9-1,RRXINS
REPEAT 26.,40,,RRINDR	;LOWERCASE LETTERS INDIRECT THRU UPPERCASE.
REPEAT 5,RRXINS

;CONTROL-META CHARS: MOSTLY SELF-INSERTING, BUT SOME ARE INDIRECT THROUGH OTHERS.
REPEAT ^H,RRXINS	;^@ THRU ^G
REPEAT 3,200,,RRINDR	;^H THRU ^J
REPEAT 2,RRXINS		;^K, ^L
	200,,RRINDR	;^M
REPEAT 33-^M-1,RRXINS	;^N TO ^Z
	200,,RRINDR	;ALTMODE
REPEAT "--33-1,RRXINS	;^\ TO COMMA
	RRCMNS		;MINUS SIGN
REPEAT "0-"--1,RRXINS	;. TO /
REPEAT 10.,RRCDGT	;0 TO 9
REPEAT "H-"9-1,RRXINS	;: TO G
REPEAT 3,300,,RRINDR	;H, I, J
REPEAT "`-"J,RRXINS	;K TO `
REPEAT 32,40,,RRINDR	;a to z
REPEAT 200-172-1,RRXINS	;{ TO RUBOUT.

IFN .-RRMACT-1000,.ERR

RRMACL==1000	;LENGTH OF RRMACT

SUBTTL INITIAL CONTENTS OF STRING AND BUFFER SPACE

;; BUFFER AND MACRO CALL FRAMES.  MORE CAN BE CREATED, PUSHING COMMAND BUFFER UP.

MFSTRT:	REPEAT MFNUM-3, REPEAT MFBLEN-1,[ 0 ?] .
	REPEAT MFBLEN, 0
MFBUF1:	MFBFR,,INIBEG	;BUFFER FRAME FOR INITIALLY SELECTED BUFFER.
	REPEAT MFBLEN-2,INIBEG
	0
MFSBUF:	MFBFR,,INISRB	;THIS BUFFER HOLDS THE COMPILED SEARCH STRING.
	REPEAT 4,INISRB
	INISRE
	0
MFEND1::

CBUF:	BLOCK CBUFSZ	;COMMAND BUFFER FOR NON-^R MAIN LOOP.

;INITIAL CONTENTS OF STRING SPACE:

INIQRB==5*.
ERSTRT:	BLOCK ERTOTL		;STRINGS FOR ERROR MESSAGES GO HERE.
EREND::
INIDLM::
	<.BYTE 7 ? 177 ? QRSTR ? 4 ? 5 ? 0>
	REPEAT ^M,	ASCII /     /
			ASCII / î   /	;CR.  ENDS COMMENTS IN LISP.
	REPEAT 33-^M-1,	ASCII /     /
			ASCII / A   /	;ALTMODE
	REPEAT 40-33,	ASCII /     /	;34 THRU SPACE
			ASCII / A   /	;!
			ASCII / A   /	;"
			ASCII / A   /	;#
	REPEAT "%-"$+1,	ASCII /AA   /	;$, %.
			ASCII / A   /	;&
			ASCII / '   /	;'
			ASCII / (   /	;(
			ASCII / )   /	;)
			ASCII / A   /	;*
			ASCII / A   /	;+
			ASCII /     /	;,
			ASCII / A   /	;-
			ASCII /AA   /	;.
			ASCII . /   .	;/
	REPEAT "0-"/-1,	ASCII / A   /
	REPEAT "9-"0+1,	ASCII /AA   /
	REPEAT ";-"9-1, ASCII / A   /
			ASCII / ;   /
	REPEAT "A-";-1,	ASCII / A   /
	REPEAT "Z-"A+1,	ASCII /AA   /
	REPEAT "a-"Z-1,	ASCII / A   /
	REPEAT "z-"a+1,	ASCII /AA   /
	REPEAT "|-"z-1,	ASCII / A   /
			ASCII / |   /
	REPEAT 176-"|,	ASCII / A   /
			ASCII /     /
IFN .-INIDLM-201,.ERR WRONG TABLE LENGTH
INI..O==5*.
	<.BYTE 7 ? QRBFR ? MFBUF1&177 ? MFBUF1_<-7>&177
		MFBUF1_<-14.>&177>
INISRS==5*.
	<.BYTE 7 ? QRBFR ? MFSBUF&177 ? MFSBUF_<-7>&177 ? MFSBUF_<-16>&177>
INIQRW==5*.

;INITIAL CONTENTS OF BUFFER SPACE.

INIBUF==5*<<INIQRB/5+SLPQWR>&<-2000>>
INISRB==INIBUF
INISRE==INISRB+5*<1+STBLSZ>
INIBEG==INISRE+5
INITOP==INIBEG+5

END BOOT
