Google
 

Trailing-Edge - PDP-10 Archives - bb-d868e-bm_tops20_v41_2020_dist_1of2 - 4-1-sources/tv.mac
There are 20 other files named tv.mac in the archive. Click here to see a list.
;**Modify PERUSE so there is no default filename on a ;X -SMAYO
; UPD ID= 156, SNARK:<6.UTILITIES>TV.MAC.9,  12-Oct-82 22:47:51 by CHALL
;TCO 6.1308- ALLOW THE "PERUSE" COMMAND
; UPD ID= 34, AU51:TV.MAC.20,   1-Sep-82 11:06:17 by MAYO
;**Edit 513 by SM - Stop <;Efile$> from giving stack overflow. 18173.
; UPD ID= 31, AU5:TV.MAC.18,   9-Jul-82 09:56:31 by MAYO
;**Edit 512 by SM - Add SETSN code at startup. Add WLIBRARY$. No SPR.
; UPD ID= 26, AU5:TV.MAC.15,   9-Jun-82 13:00:16 by MAYO
;**Edit 511 by SM - 502 broke n,mP; fix. No SPR.
; UPD ID= 23, AU5:TV.MAC.13,  26-May-82 17:50:30 by MAYO
;**Edit 510 by SM - :N,:R weren't returning values properly.
; UPD ID= 19, AU5:TV.MAC.9,   5-May-82 13:48:01 by MAYO
;**Edit 509 by SM  - WFILE$ returns nothing after CREATE foo. Fix. No SPR.
;    Also S...^Ex...$ doing things at runtime that could be done at compile
;    time. Fix. No SPR.
; UPD ID= 8, AU5:TV.MAC.4,  22-Apr-82 13:37:54 by MAYO
;**Edit 508 by SM - Stack imbalance at OPNOUT. Fix. No SPR.
;**Edit 507 by SM - n,nK returns n. Fix. No SPR.
;**Edit 506 by SM - ARG2 not being cleared properly. Fix. No SPR.
;**Edit 505 by SM - Fix octal input; large values can get trashed. No SPR.
; UPD ID= 26, AU41:TV.MAC.5,  26-Mar-82 15:16:27 by MAYO
;**Edit 504 by SM - clean up code. V5. Fix comments. No SPR.
; UPD ID= 17, AU41:TV.MAC.4,  25-Mar-82 11:22:42 by MAYO
;**Edit 503 by SM - Fix edit 474 (make N and _ work)
; UPD ID= 4, AU41:TV.MAC.2,  23-Mar-82 20:59:14 by MAYO
;**Edit 502 by SM - Large fix for arg passing and scanning.
; UPD ID= 985, AU4:TV.MAC.3,  18-Feb-82 12:39:58 by MAYO
;**Edit 501 by SM - Stop Y and A from stripping nulls
; UPD ID= 984, AU4:TV.MAC.2,  18-Feb-82 12:07:29 by MAYO
;**Edit 500 by SM - Have 0"N^I$' not insert tab. Also force version decimal.
;
; UPD ID= 889, AU4:TV.MAC.6,  11-Nov-81 10:36:35 by MULLAHOO
;EDIT 477 - Make TV reset Cursor Key Mode for VT100
; UPD ID= 882, AU4:TV.MAC.5,  26-Oct-81 14:41:53 by MULLAHOO
;EDIT 476 - Delete erroneous code in MOVRIT routine
; UPD ID= 829, AU4:TV.MAC.4,  22-Sep-81 13:54:52 by MULLAHOO
;Edit 475 - Make  -1:SFOO$  return 0 on failure
;
; UPD ID= 204, AU4:TV.MAC.3,  12-Sep-80 13:08:20 by SIMMONS
;TCO 5.1144 - TV.MAC.474 FIX INFINITE LOOP ON N COMMAND ON INPUT FILE (see 503)
; UPD ID= 133, AU4:TV.MAC.2,  28-Jul-80 11:37:39 by SIMMONS
;TCO 5.1107 - MAKE 0"N%X' NOT RETURN AN ERROR 473
;TCO 5.1037 - FIX WLIST$$ COMMAND 472
;
;This software is furnished under a license and may only be used
;  or copied in accordance with the terms of such license.
;
;Copyright (C) 1976,1977,1978,1979,1980,1981,1982,
; By DIGITAL EQUIPMENT CORPORATION, Maynard, Mass.

	TITLE TV - screen editor for TOPS-20 systems

	SEARCH MONSYM,MACSYM
	SALL			;MACROS TEND TO BE MESSY

	EXTERNAL .RLEND		;SYMBOL SHOWING END OF MACREL

	WHTV==0			;LAST EDITED BY DEC
	VRTV==5			;MAJOR VERSION #
	RVTV==1			;REVISION #

	RADIX	10
	.EDIT==513		;EDIT NUMBER, decimal
	RADIX	8		;RESTORE OLD RADIX

	%%RVER==: .EDIT		 ;RHS FOR LINK
	%%LVER==: <WHTV>B20+<VRTV>B29+RVTV ;LHS

;IF DEFINED, LEAVE ALONE, IF UNDEFINED, DEFINE IT

	DEFINE ND(SYM,VAL),	<IFDEF SYM,<SYM=SYM>
				 IFNDEF SYM,<SYM=VAL> >

;COMPILATION "FALL-OVER-AND-DIE" MACRO

	DEFINE FOAD ($MSG)<
	 PRINTX ?'$MSG
	 PASS2
	 END>

;COMPILATION "PLEASE TAKE NOTE" MACRO

	DEFINE UH.OH ($MSG)<
	 IF1, <PRINTX $MSG> >

;CONSTANTS OF MERIT

	ND MAXWTH,^D255			;MAXIMUM VALUE ALLOWABLE FOR SWIDTH

	ND USARYL,^D200			;NUMBER OF CELLS IN USER ARRAY
	ND MAXSEC,7			;MAX # OF SECTS WE GIVE TO THE USER
					 ;SET TO 0 TO REMOVE EXTENDED COMMANDS
					 ;SET TO 0 ON 2020's
	ND FTRSC,0			;IF 0, ALWAYS RESCAN ON RESTART
	ND FTDEB,0			;ADDS RANDOM NNU'D ROUTINES

	ND FTUNS,0		;IF NONZERO, *** THIS BECOMES UNSUPPORTED ***
				;to get various interesting flavors of TV
				 ;you could override the 0 in ND FTUNS,0 with
				 ;below values. ANY NONZERO VALUE
				 ;of FTUNS is UNSUPPORTED.

	UN.ENC==1B0		 ;1B0 Coding algorithm included (WENCRYPT$)

	UN.CST==1B35		 ;if customized, light this bit
				 ;bits 25-34 for customer use

	UN.ANY==-1		;if ANY bit lit, UN.ANY hits it

	DEFINE OPTION(OPT,CDE),<
	 IFN FTUNS&UN.'OPT,<CDE> >


;Paranoia checks
	OPTION ANY,<UH.OH <%This version of TV is *NOT* supported> >
	OPTION ENC,<UH.OH < ENCRYPTION included> >
	OPTION CST,<UH.OH < (This is a USER CUSTOMISED version of TV)> >

	IFLE MAXSEC, UH.OH <%Extended buffer commands will not be available.>
	IFL USARYL-^D10, FOAD <Array size set too small>
;ACCUMULATOR ASSIGNMENTS

	FF=0			;CONTROL FLAGS

;*** A, b AND c MUST BE CONTIGUOUS AND IN THAT ORDER ***
	A=1
	B=2			;BYTE POINTER TO COMMAND BUFFER

;*** c AND d MUST BE ADJACENT AND c .L. 11 ***
	C=3			;COMMAND BUFFER END ADDRESS
	D=4
	P1=5
	P2=6

;*** OU AND CH MUST BE CONSECUTIVE
	OU=7
	CH=10
	T=11

;*** TT AND TT1 MUST BE ADJACENT ***
	TT=12
	TT1=13

;*** I IS FOR GENERAL USAGE
	I=14

;*** 15 AND 16 RESERVED FOR TRVAR AND FRIENDS, EXCEPT FOR SEARCH ROUTINE
;*** SAC1 AND SAC2 MUST BE CONSECUTIVE
	SAC1=15
	SAC2=16
	CX=16
	P=17

.JBUUO==40			;UUO WORD
.JB41==41			;INSTRUCTION EXECUTED BY UUO
;OPDEFS AND DEFINES

	OPDEF	UERR	[01B8]
	OPDEF	UPSTR	[02B8]	;PRINT STRING UUO
	OPDEF	ULDB	[03B8]	;LDB BUT ADJUST BYTE POINTER TO AVOID HOLE
	OPDEF	UILDB	[04B8]	;SAME FOR ILDB
	OPDEF	ULERR	[05B8]	;LOCAL ERROR
	OPDEF	UJERR	[06B8]	;JSYS ERROR
	OPDEF	UJERR	[07B8]	;LOCAL JSYS ERROR
	OPDEF	UIERR	[8B8]	;INTERNAL ERROR
	OPDEF	UCTYPE	[9B8]	;SINGLE CHARACTER

;ERROR MACRO

	DEFINE ERROR ($MSG)<	UERR [ASCIZ \$MSG\]>

;INTERNAL ERROR (NOT USER ERROR)

	DEFINE IERROR ($MSG)<	UIERR [ASCIZ \TV internal error - $MSG\]>

;JSYS ERROR

	DEFINE JERROR ($MSG)<	UJERR [ASCIZ \$MSG\]>

;LOCAL JSYS ERROR

	DEFINE LJERR ($MSG)<	UJERR [ASCIZ \$MSG\]>

;LOCAL ERROR MACRO (LIKE ERROR, BUT RETURNS)

	DEFINE LERROR ($MSG)<	ULERR [ASCIZ \$MSG\]>

;PRINT STRING MACRO

	DEFINE PSTR ($MSG)<	UPSTR [ASCIZ \$MSG\]>

;PRINT LITERAL CHARACTER

	DEFINE CTYPE (CHAR)<	UCTYPE "CHAR">

;MACROS WHICH EXPAND INTO COMND JSYS FUNCTION BLOCKS...

	DEFINE NOISEX (MESSAG)
<	FLDDB. .CMNOI,,<-1,,[ASCIZ /MESSAG/]>
>

	DEFINE C.(WHAT)
<DEFINE WHAT'X
<	FLDDB. .'WHAT
>>

C. CMINI
C. CMCFM
C. CMIFI
C. CMFIL
C. CMFLD
C. CMCFM
C. CMOFI

;MAJOR BUFFER ASSIGNMENTS

	CBUF=50000			;BUFFER FOR TYPIN AND QREG TEXT
	MTBUF0==400000			;MAIN TEXT AREA
	BBUF1==100000			;BACKUP BUFFERS IN LOWER FORK
		; (LOWER FORK COPYS ONE TO DISK WHILE WE USE OTHER ONE)
	BBUF2==400000
	EMTBUF=765000			;END OF MAIN BFR AREA
		; (FIRST PAGE BEYOND END OF BUFFER, LEAVE ROOM FOR DDT!)
;CONTROL FLAGS

	ARG2==	1B34		;THERE IS A SECOND ARGUMENT
	ARG==	1B33		;THERE IS AN ARGUMENT
	PERUS==	1B32		;PERUSE MODE
	SLSL==	1B31		;@ SEEN
	PCHFLG==1B30		;N SEARCH
	COLONF==1B29		;COLON SEEN
	SYLF==	1B28		;SYLLABLE FLAG
	RUBCF==	1B27		;RUBOUT IN OUTPUT TO FILE
;**;[503] At GOGO: -52L, Deleted 1 line         	SM	24-Mar-82
	FINDR==	1B26		;LEFT ARROW SEARCH
	RPLFG==	1B25		;I REPLACE COMMAND
	NOTF==	1B24		;^N SEARCH MODIFIER
	TRACEF==1B23		;? SEEN
	DDTMF==	1B22		;NEED TO TYI IN DDT MODE
	FORM==	1B18		;FORM FEED TERMINATED LAST Y OR A

	RSCNF2==1B17		;SAYS RESCANNED DATA AVAILABLE
	RSCANF==1B16		;SAYS WE'RE USING RESCANNED DATA
	FINF==	1B15		;INPUT CLOSED BY EOF
	UREAD==	1B10		;INPUT FILE IS OPEN
	UWRITE==1B9		;OUTPUT FILE IS OPEN
	DUMPF==	1B8		;FULL FILE OPERATION IN PROGRESS (LIKE ;U ;X)
	SCANF==	1B7		;SET IF SCANNING

;VARIOUS CHARACTER DEFINITIONS
PCHAR=="*"			;PROMPT CHARACTER
CFLAG=="'"			;CHAR FOR FLAGGING "WRONG CASE" CHARACTERS

C.MORE==40			;CHARACTER TO CONTINUE DISPLAY
C.TOP==37			;SAME
C.QUOT=="V"-100			;QUOTE ONE CHARACTER
C.LOWR=="A"-100			;LOWERCASE SHIFT
C.RAIS=="B"-100			;UPPERCASE SHIFT

;VT05 ESCAPE CODES...

	C.CAD=="N"-100		;vt05 cursor addressing character
	C.LM==37			;add column or row to get there on vt05
	C.UP=="Z"-100			;-L
	C.DOWN=="K"-100			;+L
	C.LEFT=="H"-100			;-c
	C.RITE=="X"-100			;+c
	C.EOL=="^"-100			;CLEAR TO END OF LINE

;VT50, VT52 ESCAPE CODES, MUST BE PRECEDED BY ALTMODE

	V52.ES==33
	V52.UP==101
	V52.DN==102
	V52.RT==103
	V52.LT==104
	V52.EL==113			;CLEAR TO END OF LINE

;STORAGE

	LPDL=200
	GCTBL=150
	LPF=200			;AT LEAST ENOUGH ROOM FOR SAVING ALL THE QREGS
	OTABL=110		;LENGTH FOR TAGS FOR "O" COMMAND

LOC 140
;ENTRY VECTOR

GOGO:	JRST TECO		;START ADDRESS
	JRST REE		;REENTER ADDRESS
VRSNI:	%%LVER,,%%RVER		;VERSION NUMBER
ENLEN==.-GOGO			;LENGTH OF ENTRY VECTOR
;CHARACTER TABLE.  ALLOWS RAISING, LOWERING, ETC. IN ONE INSTRUCTION.
;ALSO HAS INFORMATION CONCERNING "WHAT KIND OF CHARACTER IS THIS?"

	CH%UPR==1B35		;BIT TO MEAN CHARACTER IS CAPITAL LETTER
	CH%DWN==1B34		;LOWER CASE
	CH%EOL==1B33		;<CR><LF><FF>
	CH%BL0==1B32		;<SP><TAB>

	CH%DIG==1B28		;DIGITS, 0-9
	CH%PN1==1B27		;PUNCTUATION .,;:!?"

	CH%SYM==1B24		;.$%
	CH%USR==1B23		;USER DEFINABLE

	 CH%ALP=CH%DWN!CH%UPR	;ALPHABETIC IS UPPER+LOWER
	 CH%SBL==CH%ALP!CH%DIG!CH%SYM	;SYMBOL CONSTUTIENT IS ALPHA+DIGITS+.%$
	 CH%BL1==CH%EOL!CH%BL0	;BLANK TYPE 1 - <CR><FF><LF><SP><TAB>

	LWRFLD==177B8
	UPRFLD==177B15
	MSKSTR LWRCOD,CHRTAB,LWRFLD ;LOWERCASE VERSION OF CHARACTER
	MSKSTR UPRCOD,CHRTAB,UPRFLD ;UPPERCASE VERSION

CHRTAB:		FLD(0,LWRFLD)!FLD(0,UPRFLD)
		FLD(1,LWRFLD)!FLD(1,UPRFLD)
		FLD(2,LWRFLD)!FLD(2,UPRFLD)
		FLD(3,LWRFLD)!FLD(3,UPRFLD)
		FLD(4,LWRFLD)!FLD(4,UPRFLD)
		FLD(5,LWRFLD)!FLD(5,UPRFLD)
		FLD(6,LWRFLD)!FLD(6,UPRFLD)
		FLD(7,LWRFLD)!FLD(7,UPRFLD)
		FLD(10,LWRFLD)!FLD(10,UPRFLD)
	CH%BL0!	FLD(11,LWRFLD)!FLD(11,UPRFLD)	;^I
	CH%EOL!	FLD(12,LWRFLD)!FLD(12,UPRFLD)	;^J
		FLD(13,LWRFLD)!FLD(13,UPRFLD)
	CH%EOL!	FLD(14,LWRFLD)!FLD(14,UPRFLD)	;^L
	CH%EOL!	FLD(15,LWRFLD)!FLD(15,UPRFLD)	;^M
		FLD(16,LWRFLD)!FLD(16,UPRFLD)
		FLD(17,LWRFLD)!FLD(17,UPRFLD)
		FLD(20,LWRFLD)!FLD(20,UPRFLD)
		FLD(21,LWRFLD)!FLD(21,UPRFLD)
		FLD(22,LWRFLD)!FLD(22,UPRFLD)
		FLD(23,LWRFLD)!FLD(23,UPRFLD)
		FLD(24,LWRFLD)!FLD(24,UPRFLD)
		FLD(25,LWRFLD)!FLD(25,UPRFLD)
		FLD(26,LWRFLD)!FLD(26,UPRFLD)
		FLD(27,LWRFLD)!FLD(27,UPRFLD)
		FLD(30,LWRFLD)!FLD(30,UPRFLD)
		FLD(31,LWRFLD)!FLD(31,UPRFLD)
		FLD(32,LWRFLD)!FLD(32,UPRFLD)
		FLD(33,LWRFLD)!FLD(33,UPRFLD)	;^Z
		FLD(34,LWRFLD)!FLD(34,UPRFLD)
		FLD(35,LWRFLD)!FLD(35,UPRFLD)
		FLD(36,LWRFLD)!FLD(36,UPRFLD)
		FLD(37,LWRFLD)!FLD(37,UPRFLD)
	CH%BL0!	FLD(40,LWRFLD)!FLD(40,UPRFLD)	;SPACE
	CH%PN1!	FLD(41,LWRFLD)!FLD(41,UPRFLD)	;!
	CH%PN1!	FLD(42,LWRFLD)!FLD(42,UPRFLD)	;"
		FLD(43,LWRFLD)!FLD(43,UPRFLD)
	CH%SYM!	FLD(44,LWRFLD)!FLD(44,UPRFLD)	;$
	CH%SYM!	FLD(45,LWRFLD)!FLD(45,UPRFLD)	;%
		FLD(46,LWRFLD)!FLD(46,UPRFLD)
		FLD(47,LWRFLD)!FLD(47,UPRFLD)
		FLD(50,LWRFLD)!FLD(50,UPRFLD)
		FLD(51,LWRFLD)!FLD(51,UPRFLD)
		FLD(52,LWRFLD)!FLD(52,UPRFLD)
		FLD(53,LWRFLD)!FLD(53,UPRFLD)
	CH%PN1!	FLD(54,LWRFLD)!FLD(54,UPRFLD)	;,
		FLD(55,LWRFLD)!FLD(55,UPRFLD)	;-
	CH%PN1!CH%SYM!	FLD(56,LWRFLD)!FLD(56,UPRFLD)	;.
		FLD(57,LWRFLD)!FLD(57,UPRFLD)
	CH%DIG!	FLD(60,LWRFLD)!FLD(60,UPRFLD)	;0
	CH%DIG!	FLD(61,LWRFLD)!FLD(61,UPRFLD)	;1
	CH%DIG!	FLD(62,LWRFLD)!FLD(62,UPRFLD)	;2
	CH%DIG!	FLD(63,LWRFLD)!FLD(63,UPRFLD)	;3
	CH%DIG!	FLD(64,LWRFLD)!FLD(64,UPRFLD)	;4
	CH%DIG!	FLD(65,LWRFLD)!FLD(65,UPRFLD)	;5
	CH%DIG!	FLD(66,LWRFLD)!FLD(66,UPRFLD)	;6
	CH%DIG!	FLD(67,LWRFLD)!FLD(67,UPRFLD)	;7
	CH%DIG!	FLD(70,LWRFLD)!FLD(70,UPRFLD)	;8
	CH%DIG!	FLD(71,LWRFLD)!FLD(71,UPRFLD)	;9
	CH%PN1!	FLD(72,LWRFLD)!FLD(72,UPRFLD)	;:
	CH%PN1!	FLD(73,LWRFLD)!FLD(73,UPRFLD)	;;
		FLD(74,LWRFLD)!FLD(74,UPRFLD)
		FLD(75,LWRFLD)!FLD(75,UPRFLD)
		FLD(76,LWRFLD)!FLD(76,UPRFLD)
	CH%PN1!	FLD(77,LWRFLD)!FLD(77,UPRFLD)	;?
		FLD(100,LWRFLD)!FLD(100,UPRFLD)
	CH%UPR!	FLD(141,LWRFLD)!FLD(101,UPRFLD)
	CH%UPR!	FLD(142,LWRFLD)!FLD(102,UPRFLD)
	CH%UPR!	FLD(143,LWRFLD)!FLD(103,UPRFLD)
	CH%UPR!	FLD(144,LWRFLD)!FLD(104,UPRFLD)
	CH%UPR!	FLD(145,LWRFLD)!FLD(105,UPRFLD)
	CH%UPR!	FLD(146,LWRFLD)!FLD(106,UPRFLD)
	CH%UPR!	FLD(147,LWRFLD)!FLD(107,UPRFLD)
	CH%UPR!	FLD(150,LWRFLD)!FLD(110,UPRFLD)
	CH%UPR!	FLD(151,LWRFLD)!FLD(111,UPRFLD)
	CH%UPR!	FLD(152,LWRFLD)!FLD(112,UPRFLD)
	CH%UPR!	FLD(153,LWRFLD)!FLD(113,UPRFLD)
	CH%UPR!	FLD(154,LWRFLD)!FLD(114,UPRFLD)
	CH%UPR!	FLD(155,LWRFLD)!FLD(115,UPRFLD)
	CH%UPR!	FLD(156,LWRFLD)!FLD(116,UPRFLD)
	CH%UPR!	FLD(157,LWRFLD)!FLD(117,UPRFLD)
	CH%UPR!	FLD(160,LWRFLD)!FLD(120,UPRFLD)
	CH%UPR!	FLD(161,LWRFLD)!FLD(121,UPRFLD)
	CH%UPR!	FLD(162,LWRFLD)!FLD(122,UPRFLD)
	CH%UPR!	FLD(163,LWRFLD)!FLD(123,UPRFLD)
	CH%UPR!	FLD(164,LWRFLD)!FLD(124,UPRFLD)
	CH%UPR!	FLD(165,LWRFLD)!FLD(125,UPRFLD)
	CH%UPR!	FLD(166,LWRFLD)!FLD(126,UPRFLD)
	CH%UPR!	FLD(167,LWRFLD)!FLD(127,UPRFLD)
	CH%UPR!	FLD(170,LWRFLD)!FLD(130,UPRFLD)
	CH%UPR!	FLD(171,LWRFLD)!FLD(131,UPRFLD)
	CH%UPR!	FLD(172,LWRFLD)!FLD(132,UPRFLD)
		FLD(133,LWRFLD)!FLD(133,UPRFLD)
		FLD(134,LWRFLD)!FLD(134,UPRFLD)
		FLD(135,LWRFLD)!FLD(135,UPRFLD)
		FLD(136,LWRFLD)!FLD(136,UPRFLD)
		FLD(137,LWRFLD)!FLD(137,UPRFLD)
		FLD(140,LWRFLD)!FLD(140,UPRFLD)
	CH%DWN!	FLD(141,LWRFLD)!FLD(101,UPRFLD)	;a
	CH%DWN!	FLD(142,LWRFLD)!FLD(102,UPRFLD)
	CH%DWN!	FLD(143,LWRFLD)!FLD(103,UPRFLD)
	CH%DWN!	FLD(144,LWRFLD)!FLD(104,UPRFLD)
	CH%DWN!	FLD(145,LWRFLD)!FLD(105,UPRFLD)
	CH%DWN!	FLD(146,LWRFLD)!FLD(106,UPRFLD)
	CH%DWN!	FLD(147,LWRFLD)!FLD(107,UPRFLD)
	CH%DWN!	FLD(150,LWRFLD)!FLD(110,UPRFLD)
	CH%DWN!	FLD(151,LWRFLD)!FLD(111,UPRFLD)
	CH%DWN!	FLD(152,LWRFLD)!FLD(112,UPRFLD)
	CH%DWN!	FLD(153,LWRFLD)!FLD(113,UPRFLD)
	CH%DWN!	FLD(154,LWRFLD)!FLD(114,UPRFLD)
	CH%DWN!	FLD(155,LWRFLD)!FLD(115,UPRFLD)
	CH%DWN!	FLD(156,LWRFLD)!FLD(116,UPRFLD)
	CH%DWN!	FLD(157,LWRFLD)!FLD(117,UPRFLD)
	CH%DWN!	FLD(160,LWRFLD)!FLD(120,UPRFLD)
	CH%DWN!	FLD(161,LWRFLD)!FLD(121,UPRFLD)
	CH%DWN!	FLD(162,LWRFLD)!FLD(122,UPRFLD)
	CH%DWN!	FLD(163,LWRFLD)!FLD(123,UPRFLD)
	CH%DWN!	FLD(164,LWRFLD)!FLD(124,UPRFLD)
	CH%DWN!	FLD(165,LWRFLD)!FLD(125,UPRFLD)
	CH%DWN!	FLD(166,LWRFLD)!FLD(126,UPRFLD)
	CH%DWN!	FLD(167,LWRFLD)!FLD(127,UPRFLD)
	CH%DWN!	FLD(170,LWRFLD)!FLD(130,UPRFLD)
	CH%DWN!	FLD(171,LWRFLD)!FLD(131,UPRFLD)
	CH%DWN!	FLD(172,LWRFLD)!FLD(132,UPRFLD)	;z
		FLD(173,LWRFLD)!FLD(173,UPRFLD)
		FLD(174,LWRFLD)!FLD(174,UPRFLD)
		FLD(175,LWRFLD)!FLD(175,UPRFLD)
		FLD(176,LWRFLD)!FLD(176,UPRFLD)
		FLD(177,LWRFLD)!FLD(177,UPRFLD)
;Flags for commands

	CM.ATS==1B0	;Atsign is meaningful for this command
	CM.0AI==1B1	;it is illegal to have 0 args before the command
	CM.1AI==1B2	;it is illegal to have only 1 arg 'fore the cmd
	CM.2AI==1B3	;it is illegal to have 2 args before this command
	 CM.NAI==CM.2AI!CM.1AI ;no args allowed before this command
	CM.MOD==1B4	;this command modifies the buffer
	CM.OPR==1B5	;this is a binary operator (could be unary also)
	CM.EXE==1B6	;this command is to be executed while scanning
	CM.PRE==1B7	;this is a command prefix char (^ ;)
;Reserved 1B9 and 1B8
	CM.OFS==777B17	;this field contains 0 or the offset to ARGTAB
	CM.ADR==777777	;this field is the address to PUSHJ to,
			; or Prefix value to if CM.PRE is set.

;Prefix character types (index into PREPTR)

	PRE.NO==0	;No prefix character seen
	PRE.SM==1	;Semicolon character seen
	PRE.UP==2	;Uparrow prefix seen
	PRE.CL==3	;Colon seen
	PRE.AT==4	;Atsign seen


;Argtypes, used in scanning over commands. These end up in strings at ARGTAB.

	CS.STP==0	;End of argtype string
	CS.SY1==1	;Followed by one symbol
	CS.QRG==2	;followed by Qreg name
	CS.DIG==3	;followed by a digit string, len .GE. 0
	CS.STR==4	;followed by a simple string (no special ^x chars)
	CS.INS==5	;followed by insert string or filename
	CS.SRS==6	;followed by a search string
	 NBACS==3	 ;Number of bits to hold largest of Argtype values

	ILLEG==0	;illegal command
	NOFLG==0	;no flags for this command
;This macro sets up the command table for TV. It contains the flags needed to 
;to parse the commands or scan over them while scanning (SCANF flag) is being
;done.

	DEFINE CTR%(CHAR,FLAGS,ADDR,TYPES),<
	 ifn FLAGS&<0,,-1>,<	;;if any flags are in the RH...
		FOAD <Command table error, flags in RH> >
	 %%'CHAR==0		;;assume no argtype string will be needed
	 irp TYPES,<		;;get the first arg in TYPES (or -1)
	  %TMP==TYPES		;;..
	  stopi>		;;stop after first
	 ifg %TMP,< %%'CHAR==1-ARGTA1+<[BYTE(NBACS)TYPES ,CS.STP]>>
				;;if there is a real string, point to it.
	 EXP FLAGS!<%%'CHAR,,ADDR> ;;punch out the word
	 PURGE %%'CHAR>		;;and toss out the unneeded symbol

;This macro is used to call the above. It passes the decimal expansion of the
;character's ascii value (so CTR% can produce a unique symbol, %%nnn) and
;fills in reasonable defaults. It creates the symbols in order. The args are:
; A Address to jump to
; F flags approprate to this command (see CM.xxx)
; T Trailing argtypes (see CS.xxx)

	DEFINE CT%(A<ILLEG>,F<0>,T<-1>),<
	 IFNDEF %%TMP,<%%TMP==0>
	 CTR% \<%%TMP>,F,A,<T>
	 %%TMP==%%TMP+1>

;Off the listing to punch out any literals made so far - must be done right
; before CMDTAB.
	XLIST
	 LIT
	LIST
;Punched!
;Main Command table here

CMDTAB:
CT%								;^@
CT%	COMM	,CM.NAI!CM.ATS		,<CS.STR>		;^A
CT%	CCOND	,CM.0AI!CM.2AI		,<CS.SY1>		;^B
CT%								;^C
CT%	CALDDT							;^D
CT%	FFEED	,CM.2AI						;^E
CT%	FITER	,CM.2AI						;^F
CT%	DECDMP							;^G
CT%	GTIME							;^H
CT%	TAB	,CM.NAI!CM.MOD		,<CS.INS>		;^I
CT%	CFLUSH							;^J
CT%								;^K
CT%	CTRLL							;^L
CT%	CFLUSH							;^M
CT%	ALTFLW	,CM.2AI						;^N
CT%								;^O
CT%								;^P
CT%	QCVAL	,CM.ATS			,<CS.QRG>		;^Q
CT%	RNGE	,CM.0AI						;^R
CT%								;^S
CT%	SPTYI							;^T
CT%								;^U
CT%	VRSN							;^V
CT%								;^W
CT%	SSERCH	,CM.2AI						;^X
CT%	ARRY	,CM.ATS						;^Y
CT%								;^Z
CT%	CFLUSH							;ESC
CT%								;^\
CT%	HLFWRD	,CM.0AI!CM.ATS					;^]
CT%	CNTRUP	,CM.NAI			,<CS.SY1>		;^^
CT%	DUJSI	,CM.0AI						;^_
   UPALEN=.-CMDTAB	;END OF ^ COMMAND RANGE

CT%	SPACC	,CM.OPR						;SPACE
CT%	EXCLAM	,CM.EXE						;!
CT%	DQUOTE	,CM.2AI!CM.EXE		,<CS.SY1>		;"
CT%	COR	,CM.OPR!CM.0AI					;#
CT%	CFLUSH							;$ DOLLARSIGN
CT%	PCNT	,NOFLG			,<CS.QRG>		;%
CT%	CAND	,CM.OPR!CM.0AI					;&
CT%	APOST	,CM.EXE						;'
CT%	OPEN							;(
CT%	CLOSE							;)
CT%	TIMES	,CM.OPR!CM.0AI					;*
CT%	PLUS	,CM.OPR						;+
CT%	COMMA	,CM.2AI!CM.0AI					;,
CT%	MINUS	,CM.OPR						;-
CT%	PNT							;.
CT%	SLASH	,CM.OPR!CM.0AI					;/
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;0
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;1
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;2
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;3
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;4
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;5
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;6
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;7
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;8
CT%	CDNUM	,CM.ATS			,<CS.DIG>		;9
CT%	PRE.CL	,CM.PRE						;:
CT%	PRE.SM	,CM.PRE						;;
CT%	LSSTH	,CM.EXE						;LEFT ANGLE
CT%	PRNT	,CM.0AI						;=
CT%	GRTH	,CM.EXE						;RIGHT ANGLE
CT%	QUESTN							;?
CT%	PRE.AT	,CM.PRE						;@
CT%	ACMD							;A
CT%	ZERINA							;B
CT%	CHARAC	,CM.2AI						;C
CT%	DELETE	,CM.2AI!CM.MOD					;D
CT%	ELINE	,CM.2AI						;E
CT%								;F
CT%	QGET	,CM.MOD			,<CS.QRG>		;G
CT%	HOLE	,CM.2AI						;H
CT%	INSERT	,CM.2AI!CM.ATS!CM.MOD	,<CS.INS>		;I
CT%	JMP	,CM.2AI!CM.ATS					;J
CT%	KILL	,CM.MOD						;K
CT%	LINE	,CM.2AI						;L
CT%	MAC	,NOFLG			,<CS.QRG>		;M
CT%	SERCHP	,CM.2AI!CM.ATS!CM.MOD	,<CS.SRS>		;N
CT%	OG	,NOFLG			,<CS.STR>		;O
CT%	PUNCH	,CM.MOD						;P
CT%	QREG	,NOFLG			,<CS.QRG>		;Q
CT%	REPLAC	,CM.2AI!CM.ATS!CM.MOD	,<CS.SRS,CS.INS>	;R
CT%	SERCH	,CM.2AI!CM.ATS		,<CS.SRS>		;S
CT%	TYPE							;T
CT%	USE	,CM.2AI!CM.0AI		,<CS.QRG>		;U
CT%	VIEW							;V
CT%	WRDCOM	,NOFLG			,<CS.STR>		;W
CT%	X	,CM.MOD!CM.ATS		,<CS.QRG>		;X
CT%	DYANK	,CM.2AI!CM.MOD					;Y
CT%	END1							;Z
CT%	OPENB	,NOFLG			,<CS.QRG>		;[
CT%	BAKSL							;\
CT%	CLOSEB	,NOFLG			,<CS.QRG>		;]
CT%	PRE.UP	,CM.PRE						;^
CT%	LARR	,CM.ATS!CM.2AI!CM.MOD	,<CS.SRS>		;_

   CMDLEN=.-CMDTAB	;LENGTH OF COMMAND TABLE
;SEMTAB is just like CMDTAB, for SEMICOLON commands

SEMTAB:
CT%	TCOND							; ;SPACE 
CT%								; ;!
CT%								; ;"
CT%								; ;#
CT%								; ;$
CT%								; ;%
CT%	TXZNC	,CM.0AI!CM.2AI		,<CS.QRG>		; ;&
CT%								; ;'
CT%								; ;(
CT%								; ;)
CT%								; ;*
CT%								; ;+
CT%								; ;,
CT%								; ;-
CT%								; ;.
CT%	REMDIV	,CM.NAI						; ;/
CT%								; ;0
CT%								; ;1
CT%								; ;2
CT%								; ;3
CT%								; ;4
CT%								; ;5
CT%								; ;6
CT%								; ;7
CT%								; ;8
CT%								; ;9
CT%								; ;:
CT%								; ;;
CT%								; ;LEFT ANG
CT%	UDFFLS	,CM.2AI			,<CS.STR>		; ;=
CT%								; ;RIGHT ANG
CT%								; ;?
CT%	UDFFL	,CM.2AI			,<CS.QRG>		; ;@
CT%								; ;A
CT%								; ;B
CT%	SEMIC							; ;C
CT%	DNLD							; ;D
CT%	DOFILE	,NOFLG			,<CS.INS>		; ;E
CT%								; ;F
CT%	GETOB	,CM.MOD						; ;G
CT%	DECDMP							; ;H
CT%	OVWR	,CM.0AI!CM.2AI!CM.MOD				; ;I
CT%								; ;J
CT%								; ;K
CT%	CNLINE	,CM.0AI!CM.1AI					; ;L
CT%	MFILE	,CM.2AI			,<CS.QRG,CS.INS>	; ;M
CT%	PIKNUM	,CM.2AI						; ;N
CT%								; ;O
CT%	PICKUP							; ;P
CT%								; ;Q
CT%	OPNRD	,NOFLG			,<CS.INS>		; ;R
CT%	BSAVE							; ;S
CT%	TPREG	,CM.2AI						; ;T
CT%	UNLD							; ;U
CT%								; ;V
CT%	OPNWR	,NOFLG			,<CS.INS>		; ;W
CT%	EXCOM							; ;X
CT%	YLOAD	,CM.NAI!CM.MOD					; ;Y
CT%								; ;Z
CT%	SOPENB	,CM.0AI!CM.2AI					; ;[
CT%	RAND	,CM.0AI						; ;\
CT%	SCLOSB	,CM.NAI						; ;]
   SEMLEN=.-SEMTAB

	IF2, <PURGE CTR%,CT%>
	PURGE %TMP,%%TMP
ZEROW:				;Guaranteed zero word.
ARGTAB:	0			;0 offset to ARGTAB is meaningless.
ARGTA1:	LIT			;the macros defined strings in literals -
				; punch them out as an array at ARGTAB
;START HERE FOR DEBUGGING.  THIS ENTRY MAKES TV THINK YOU STARTED
;IT WITH THE COMMAND "TV FOO.BAR"

 IFN FTDEB,<

DEBUG:	HRROI A,[ASCIZ /TV FOO.BAR
/]
	RSCAN%
	 JSHLT
	SETOM VIRGIN		;SO RSCAN STUFF HAPPENS ON RESTART
	JRST TECO
>

;STARTUP TIME INITIALIZATION

TECO:	RESET%
	XMOVEI A,20
	TLNE A,-1		;ARE WE IN A NON-ZERO SECTION?
	JRST [HRROI A,[ASCIZ/
?TV does not run in non-zero sections; those sections are reserved for data./]
	     PSOUT%
	     HALTF%
	     JRST TECO]		;YES, DIE NOW
;**;[512] At TECO: +1L, Inserted 4 lines                    SM  9-Jul-82
	MOVE A,[SIXBIT/TV/]	;[512] SET UP FOR SETSN
	MOVE B,A		;[512] BOTH NAMES TO "TV"
	SETSN%			;[512] SET IT
	 ERJMP .+1		;[512] IGNORE NON-EXISTANT ERROR RETURN
	AOS VIRGIN		;VIRGIN 0 MEANS PROGRAM HASN'T BEEN RUN
	MOVE A,[XWD FIRSTV,FIRSTV+1]
	SETZM FIRSTV		;CLEAR VARIABLES AREA
	BLT A,TOP

;SET UP LUUO DISPATCH FOR SECTION 0 AND ALL OTHER SECTIONS

	MOVE A,[CALL S0UUOH]	;SETUP SECTION 0 UUO DISPATCH
	MOVEM A,.JB41
	XMOVEI A,S1UUOH		;SETUP NON-ZERO SECTION UUO DISPATCH
	MOVEM A,UUOB+.ARNPC
	MOVEI A,.FHSLF
	MOVEI B,.SWLUT		;FUNCTION CODE
	XMOVEI C,UUOB		;ADDRESS OF LUUO BLOCK
	SWTRP%			;REQUEST UUO TRAPPING IN NON-0 SECTIONS

;MISCELLANEOUS SET UP

	MOVE P,[XWD -LPDL,PDL-1]
	MOVEI A,"!"
	MOVEM A,LASTCH		;DISPLAY CONTINUATION CHARACTER
	MOVSI A,(ASCII A/\A)
	MOVEM A,PTRCHR		;WHAT POINTER LOOKS LIKE ON SCREEN
	SETOM BAKFLG		;DEFAULT IS TO SAVE COMMAND STRINGS.
	SETOM LPM		;GUARANTEE INITIAL PMAP
	SETOM LPM2
	MOVX A,RD%JFN+RD%BBG+RD%BEG
	 ;JFNS AND DESTINATION POINTER GIVEN, RETURN WHEN EVERYTHING DELETED
	MOVEM A,RDFLG		;STORE FLAGS
	MOVEI A,RDEND-RDCWB	;CALCULATE SIZE OF TEXTI BLOCK
	MOVEM A,RDCWB
	MOVEI A,[EXP 1B<.CHESC>,0,0,0] ;WAKE UP ON ALTMODE
	MOVEM A,RDBRK
	MOVSI A,(<RET>)
	MOVEM A,TRACS
	MOVEI A,CBUF+200	;ADR OF TEXT BUFFER
	IMULI A,5		;CHR ADDR OF BEGINNING
	MOVEM A,QRBUF
	MOVEM A,EQRBUF		;SETUP END OF QREG BUF
	MOVEI A,MTBUF0		;SETUP MAIN TEXT BUFFER ADDRESSES
	IMULI A,5
	MOVEM A,BEG
	MOVEM A,PT
	MOVEM A,ZEE
	MOVE I,BEG
	MOVEM I,SCRNPT		;FOR DISPLAY ROUTINE
	MOVEI A,CBUF+77
	MOVEM A,CBUFH
	MOVEI A,CBUF
	MOVEM A,LSTCB
	MOVEM A,LSTCE
	MOVEI FF,0		;CLEAR FLAG REGISTER
;**;[503] At TECO: +53L, Deleted 1 line         	SM	24-Mar-82
	MOVEI A,.PRIOU		;GET CONTROL SETTINGS BEFORE THEY GET CHANGED
	RFCOC%			;GET CONTROL CHARACTER SETTINGS
	TRO C,600000		;MAKE SURE ALTMODE ECHOES AS $
	DMOVEM B,REGCWD		;REMEMBER SETTING
	MOVSI A,(CR%CAP+CR%ACS)
	XMOVEI B,[SAVPDL]-17	;LOAD SAVER'S AC17 WITH STACK ADDRESS
	CFORK%			;COMMAND SAVER WITH INITIALIZED STACK POINTER
	 JSHLT
	SETOM SDONEF		;ASSUME SAVER IS INITIALLY "DONE"
	MOVEM A,SAVFRK		;REMEMBER FORK HANDLE
	SETZM SAVJFN		;SAY NO JFN YET ON BACKUP FILE
	XMOVEI A,SAVBEG		;GET ADDRESS OF START OF WINDOW
	LSH A,-11		;CONVERT TO PROCESS PAGE #
	HRLI A,.FHSLF		;SOURCE FORK HANDLE ,, PAGE #
	MOVEI B,SAVBEG_-9	;CREATE WINDOW FROM SAVER FORK TO US
	HRL B,SAVFRK
	MOVE C,[PM%CNT+PM%RD+PM%WR+PM%EX+<SAVEND-SAVBEG>_-9+2]
	PMAP%
	CALL HK			;KILL THE ENTIRE BUFFER
	MOVEI A,^D50		;DEFAULT NUMBER OF CHARACTERS BETWEEN SAVES
	MOVEM A,BAKLEN
	SETZM BBLEN		;NOTHING IN BACKUP BUFFER YET
	SETZM OBBLEN
	MOVE A,[POINT 7,BBUF1]	;INITIALIZE POINTER TO BACKUP BUFFER
	MOVEM A,BBPTR
	MOVEM A,BBUFX
	SETZM WTOGGL		;START WITH FIRST WINDOW
	SETO A,			;GET INFO ABOUT OUR JOB.
	HRROI B,P2		;GET ONE PIECE OF INFORMATION INTO "p2"
	MOVEI C,.JILNO		;LOGGED-IN DIRECTORY NUMBER
	GETJI%			;GET LOGGED-IN DIR NUMBER INTO p2
	 JSHLT
GDS:	HRROI A,DIRECT		;PUT DIRECTORY NAME IN "DIRECT"
	MOVE B,P2		;b HOLDS DIRECTORY NUMBER
	DIRST%			;GET DIRECTORY NAME FROM MONITOR
	 JSHLT
	CALL SETIO		;RESET IO
	MOVEI A,.PRIOU		;USE PRIMARY OUTPUT
	MOVEM A,TTYOUT		;SAVE CHANNEL
	CALL CMDINI		;INITIALIZE FOR COMND JSYS
	CALL RESCAN		;MAKE RESCANNED DATA AVAILABLE
	DMOVE A,[EXP INIFIL,<-1,,DIRECT>]
	GTJFN%			;TRY TO ACCESS <USER>TV.INI
	JRST NOINI		;ASSUME NONE
	MOVE B,[7B5!OF%RD]
	OPENF%			;OPEN IT FOR READING
	JRST NOINI		;COULDN'T, SO ASSUME NONE EXISTS
	MOVEM A,INIJFN		;REMEMBER JFN OF INI FILE
NOINI:	CALL SYSMOD		;GET SYSTEM'S TERMINAL CHARACTERISTICS
	CALL SETMOD		;SET UP CTRL/CHARACTER ECHOING
	SKIPE SCRNF		;LEAVE WINDOW SIZE 0 UNLESS TERMINAL IS A SCREEN
	CALL WINSTN		;SET WINDOW SIZE UP
;(ONLY HERE, SO AFTER REENTER, CUSTOM WINDOW SIZE DOESN'T GET CLOBBERED)
	JRST GOX

;ROUTINE TO ENABLE RESCANNED DATA IF AVAILABLE

ENARES:	TXZE FF,RSCNF2		;RESCANNED DATA AVAILABLE?
	TXO FF,RSCANF		;YES, ENABLE IT
	RET

;THE FOLLOWING CODE SUPPORTS THE OPTION OF THE USER INITIATING THIS
;PROGRAM WITH AN EXEC COMMAND LINE LOOKING LIKE:
;
;		@NAME FILE.EXT
;
;WHERE "NAME" IS WHATEVER NAME THIS VERSION OF TECO IS SAVED AS AND
;"FILE.EXT" IS THE FILE THE USER WISHES TO EDIT.  THE EFFECT IS JUST
;AS THOUGH THE TYPESCRIPT HAD ORIGINALLY BEEN:
;
;		@NAME
;		*;Y$
;		INPUT FILE:	FILE.EXT
;

RESCAN:	CALL RESC1		;DO MOST OF THE WORK
	 CAIA			;IF NOT RESCANNING, THROW AWAY REST OF LINE
	RET
	CALL RSCNT		;NO, SEE HOW MANY CHARACTERS LEFT TO READ
	JUMPE A,CPOPJ		;JUST RETURN IF NONE
	MOVN C,A		;THAT MANY TO READ
	MOVEI A,.PRIIN		;READ FROM PRIMARY
	SETZ B,			;DON'T REALLY READ THEM TO ANYWHERE
	SIN%			;THROW THEM AWAY
	RET

;ROUTINE TO RETURN IN A NUMBER OF RSCAN CHARACTERS LEFT TO READ

RSCNT:	MOVEI A,.RSCNT		;CODE FOR GETTING NUMBER
	RSCAN%			;ASK SYSTEM WHAT NUMBER IS
	 MOVEI A,0		;SAY 0 IF ERROR
	RET

RESC1:	STKVAR <CREAF>
 IFN FTRSC,<			;;DO RESCANS ON RESTARTS?
	SKIPE VIRGIN
	RET >			;IF PROGRAM IS RESTARTED, NO MESSING ALLOWED
	SETZM CREAF		;NOT CREATE COMMAND YET
	SETZB A,ENTFLG		;NOT SURE HOW WE GOT HERE YET
	RSCAN%		;CAUSE ORIGINAL COMMAND LINE TO BE AVAILABLE AS INPUT
	 RET			;COULDN'T EVEN DO THAT!
	CALL RSCNT		;GET NUMBER OF CHARACTERS AVAILABLE
	JUMPE A,CPOPJ		;JUMP IF NONE
	MOVEI A,0		;NO PROMPT
	CALL READY		;INITIALIZE FOR COMND JSYS
	MOVEI A,[CMFLDX]	;READ PROGRAM NAME AS FIELD
	CALL RFIELD		;READ IT INTO ATOM BUFFER
	 RET			;IF CAN'T, GIVE UP
	GETNM%			;FIND OUT WHAT PROGRAM NAME WE'RE RUNNING AS
	MOVE C,A		;PUT OUT SIXBIT NAME IN c
	MOVE P1,[POINT 6,C]	;AND A BYTE POINTER TO IT IN p1
	MOVE P2,[POINT 7,ATMBFR] ;PREPARE TO READ CHARACTERS FROM PROGRAM NAME
RSCANR:	CAMN P1,[600,,C]	;THEY AGREED BUT WEREN'T SPACES, SO NOW
	JRST RSCAN2		;IF ENTIRE NAME HAS MATCHED, STOP COMPARING
	ILDB B,P1		;PICK UP A LETTER FROM OUR NAME
	JUMPE B,RSCAN2		;JUMP IF NAME MATCHES
	ILDB CH,P2		;READ A CHARACTER OF THE COMMAND LINE
	LOAD CH,UPRCOD,(CH)	;DO ALL COMPARISONS IN UPPER CASE
	CAIN CH,"A"-'A'(B)	;YES?
	JRST RSCANR		;CONTINUE COMPARING NAME
	MOVEI P1,1		;IF "EDIT" WE WILL STORE 1 IN ENTFLG
	HRROI A,ATMBFR		;NAME DIFFERED, LOOK AT COMMAND LINE AGAIN
	HRROI B,[ASCIZ /EDIT/]
	STCMP%			;IS IT AN "EDIT" COMMAND?
	JUMPE A,RSCAN2		;YES, O.K.
	HRROI A,ATMBFR
	HRROI B,[ASCIZ /PERUSE/]
	STCMP%
	JUMPE A,RSCANE		;PERUSE?
	HRROI A,ATMBFR		;NOT "EDIT", MAYBE "CREATE"
	HRROI B,[ASCIZ /CREATE/]
	STCMP%
	JUMPE A,[SETOB P1,CREAF	;YES, "CREATE", AND ENTFLG WILL BE -1
		 JRST RSCAN2]
	RET		;NOT RECOGNIZABLE COMMAND, DON'T USE RESCANNED DATA

RSCANE:	TXO FF,PERUS
RSCAN2:	MOVEM P1,ENTFLG		;SO USER CAN GET THE WAY WE ENTERED
	MOVEI A,[NOISEX (FILE)]
	CALL RFIELD		;CHECK FOR NOISE WORDS
	 RET			;DON'T DO RESCANNING IF FAILS
	CALL CONFRM		;see if end of line
	 CAIA			;NO END OF LINE
	RET			;END OF LINE, SO NO FILESPEC COMING
	SKIPE CREAF		;DOING CREATE COMMAND?
	JRST RSOUT		;YES, PARSE OUTPUT SPEC
	MOVEI A,[CMIFIX]	;read input file
	CALL READFL		;read filespec from terminal
	SKIPE GTJERR		;DID WE GET A SUCCESSFUL INPUT SPEC?
	JRST RS3		;NO, SO DON'T PARSE OUTPUT SPEC
	MOVEI A,[NOISEX (OUTPUT AS)]
	CALL RFIELD		;PERHAPS AN OUTPUT SPEC SUPPLIED
	 JRST RS3		;NO
	MOVEI A,[CMOFIX]	;READ OUTPUT SPEC
	CALL RFIELD
	 JRST RS3		;DON'T OPEN OUTPUT FILE IF CAN'T READ NAME
RS3A:	MOVEM B,CREJFN		;REMEMBER JFN FOR CREATE COMMAND
RS3:	SKIPN CREAF		;NO RESCANNED DATA AVAILABLE IF CREATE COMMAND
	TXO FF,RSCNF2		;NOTE THAT RESCANNED DATA AVAILABLE
	JRST CPOPJ1		;SKIP TO MARK THAT COMMAND LINE WAS GIVEN
RSOUT:	MOVEI A,[CMOFIX]
	CALL READFL
	JRST RS3A

;ROUTINE TO INITIALIZE FOR COMMAND LINE.  IT TAKES EITHER 0 OR A BYTE POINTER
;IN A TO PROMPT STRING.

READY:	CAIN A,0		;ANY PROMPT?
	HRROI A,ZEROW		;NO, POINT TO A NULL STRING
	MOVEM A,SBK+.CMRTY	;SAVE POINTER TO PROMPT
	POP P,REPARA		;REMEMBER REPARSE ADDRESS
	DMOVEM 0,CMDACS+0	;SAVE AC'S
	MOVE 1,[2,,CMDACS+2]
	BLT 1,CMDACS+17
	MOVE A,[PDL,,CMDPDL]	;PREPARE TO SAVE ENTIRE STACK
	HRRZI B,-PDL(P)		;FIGURE HOW MANY WORDS TO SAVE (MINUS 1)
	BLT A,CMDPDL(B)		;SAVE THE STACK
	PUSH P,REPARA		;MAKE STACK LIKE IT WAS
	HRL A,TYIJFN		;SOURCE OF COMMAND
	HRRI A,.PRIOU		;REGULAR PRIMARY OUTPUT
	MOVEM A,SBK+.CMIOJ
	MOVEI A,[CMINIX]	;TYPE PROMPT
	CALL RFIELD
	 JFCL			;SHOULDN'T FAIL
	RET			;RETURN TO CALLER

;COME HERE IF REPARSE IS NEEDED (BECAUSE USER EDITED INTO PARSED STUFF)

REPARS:	MOVE P,CMDACS+P		;RESTORE P FIRST
	MOVE A,[CMDPDL,,PDL]	;PREPARE TO RESTORE STACK
	BLT A,(P)		;RESTORE THE STACK
	MOVSI 16,CMDACS
	BLT 16,16		;RESTORE AC'S
	HRRZ 16,REPARA		;GET LOCAL ADDRESS TO RETURN TO
	JRST (16)		;RETURN TO BEGINNING OF COMMAND LINE

;ROUTINE WHICH CHECKS FOR LINE CONFIRMATION (CR OR LF) AND SKIPS
;IF SO

CONFRM:	MOVEI A,[CMCFMX]	;CHECK FOR END OF LINE
	CALL RFIELD
	 RET			;no skip if no confirmation
	JRST	CPOPJ1

;READ A FIELD ROUTINE.  GIVE IT ADDRESS OF FUNCTION BLOCK IN A.
;IT SKIPS IFF COMND GIVES A SUCCESSFUL RETURN.  A AND B WILL HAVE
;RESULT OF COMND JSYS IN THEM.

RFIELD:	STKVAR <CFCN>
	SETOM WINFLG		;IF RECEIVING INPUT, ASSUME USER HAS SEEN ALL
	MOVEM A,CFCN		;SAVE FUNCTION
RF1:	MOVE B,CFCN		;PUT FUNCTION BLOCK POINTER IN B
	MOVEI A,SBK		;POINTER TO STATE BLOCK IN A
	COMND%			;READ FIELD OF COMND
	 ERJMP CMDERR		;ERROR IN COMND JSYS
	TXNE A,CM%NOP		;DID COMMAND PARSE CORRECTLY?
	 RET			;NO, SO SINGLE RETURN
	JRST	CPOPJ1		;YES, SO SKIP RETURN

CMDERR:	CALL %GETER		;GET REASON FOR ERROR
	HRRZ B,A		;LEAVE ERROR CODE IN B
	CAIN B,IOX4		;END OF FILE?
	JRST CMDE1		;YES, GO HANDLE IT
	TXO A,CM%NOP		;DESIGNATE NO PARSE
	RET			;RETURN NON-SKIP

CMDE1:	CALL TYIPOP		;GET BACK TO LAST INPUT STREAM
	JRST RF1		;RETRY COMND JSYS

;ROUTINE TO RETURN LAST ERROR FOR OURSELF IN A.

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

;COMND JSYS INITIALIZATION ROUTINE.  CALL ONLY ONCE AT BEGINNING OF
;PROGRAM.

CMDINI:	MOVEI A,REPARS		;REPARSE ADDRESS
	MOVEM A,SBK+.CMFLG
	HRROI A,CMDBFR		;POINTER TO COMMAND BUFFER
	MOVEM A,SBK+.CMBFP
	MOVEM A,SBK+.CMPTR	;POINTER TO NEXT FIELD
	MOVEI A,CMDBLN*5	;ROOM FOR TYPIN
	MOVEM A,SBK+.CMCNT
	SETZM SBK+.CMINC	;NO UNPARSED CHARACTERS YET
	HRROI A,ATMBFR		;POINTER TO ATOM BUFFER
	MOVEM A,SBK+.CMABP
	MOVEI A,ATMBLN*5
	MOVEM A,SBK+.CMABC	;ROOM IN ATOM BUFFER
	MOVEI A,CJFNBK		;POINTER TO JFN BLOCK
	MOVEM A,SBK+.CMGJB
	RET

;CALL THE FOLLOWING TO RESET TERMINAL IO (AT STARTUP AND REENTER)

SETIO:	MOVEI A,.PRIIN
	MOVEM A,TYIPDL		;PUSH TTY INPUT ONTO TYPIN STACK
	MOVEM A,TYIJFN		;INITIAL TYPIN JFN IS TERMINAL
	MOVE A,[1-TYILEN,,TYIPDL] ;INITIALIZE IO STACK
	MOVEM A,TYIP
	SETOM TERIO		;ASSUME INITIAL INPUT IS A TERMINAL
	RET
;CALL HERE DURING STARTUP TO ENABLE CTRL/C TRAPPING.

ENACC:	MOVEI A,.FHSLF		;OURSELF
	RPCAP%			;GET CURRENT CAPABILITIES
	TXO C,SC%CTC
	EPCAP%			;ENABLE CTRL/C TRAPPING
	MOVE A,[3,,2]		;CTRL/C TRAPPING IS ON CHANNEL 2
	ATI%			;TRY TO ENABLE CTRL/C
	 ERJMP .+1		;QUIETLY FAIL IF USER SAID "SET NO CONTROL-C"
	RET

FTUVAL:	EXP	FTUNS		;STORE THE ASSEMBLY FLAGS
FTESEC:	EXP	MAXSEC		;STORE THE NUMBER OF SECTIONS ALLOWED

REE:	MOVX	A,PC%USR
	MOVEI	B,REE0		;GET TO SECT 0 ALWAYS
	XJRSTF A		;GET TO REE0 IN PROPER SECTION
	 ;..

REE0:	MOVE P,[XWD -LPDL,PDL-1] ;INITIALIZE PUSHDOWN LIST
	TXZ FF,RSCANF+RSCNF2	;NO MORE RESCANNING ON REENTER
	CALL SETIO		;ALWAYS RESET IO ON REENTER
	CALL SYSMOD		;GET SYSTEM'S TERMINAL MODES
	CALL SETMOD		;SET UP CTRL/CHARACTER ECHOING
	SETZM INIJFN		;NO LONGER DOING INITIALIZATION
GOX:	SETZM UPDATF		;NOT DOING WUPDATE YET
	SETZM QUOJFN		;NO JFN CURRENTLY BEING OUTPUT TO
	CALL CLRSCN		;MAYBE CLEAR THE SCREEN
	SETOM WINFLG		;SO DISPLAY HAPPENS ON REENTER
	CALL XSIR		;SET UP LEVTAB, CHNTAB, AND DO SIR
	MOVEI A,.FHSLF
	CIS%			;CLEAR PENDING INTERRUPTS
	MOVE 2,[17B3+1B11+1B12]	;SELECT CHANNELS 0,1,2,11,12
	AIC%			;ACTIVATE CHANNELS
	MOVSI 1,.TICCG		;CONTROL-G TO CHANNEL 0
	ATI%
	MOVE 1,[.TICCO,,1]	;CONTROL-O TO CHANNEL 1
	ATI%
	CALL ENACC		;ENABLE CTRL/C TRAPPING
GO:	MOVE P,[XWD -LPDL,PDL-1] ;INITIALIZE PUSHDOWN LIST
;**;[503] At GO: +1L, Deleted 2 lines           	SM	24-Mar-82
	TXZ FF,-1-TRACEF-FORM-UREAD-UWRITE-RSCNF2-DUMPF-PERUS
	TXNE FF,DUMPF		;INTERRUPTED OUT OF LARGE OUTPUT?
	CALL FIXOUT		;YES
	MOVEI A,.FHSLF
	EIR%			;MAKE SURE INTERRUPTS ARE ON
	MOVEI A,^D10
	MOVEM A,RADIX		;initialize typeout to decimal
	SETZM ABORTF		;CLEAR INTERRUPT FLAGS
	SETZM LISNF
	CALL UPDATE		;UPDATE THE SCREEN
	CLEARM LEV
	MOVE A,[IOWD LPF,PFL]	;MAKE STACK POINTER
	MOVEM A,PF		;INITIALIZE QREG STACK
	JRST CLIS

;THIS ROUTINE CALLED IF INTERRUPT OR REENTER FROM A ;U-CLASS COMMAND THAT
;WAS IN THE MIDDLE OF WRITING THE FILE

FIXOUT:	SKIPGE A,OUTJFN
	JRST FIX1		;NO OUTPUT!  (OPENF IN OPNOUT PROBABLY FAILED)
	TXO A,CZ%ABT		;FLUSH THE OUTPUT OPERATION
	CLOSF%
	 ERJMP .+1		;IGNORE FAILURE
FIX1:	TXZ FF,DUMPF!UWRITE	;FORGET THAT FILE WAS OPEN
	RET
;ROUTINE TO SET UP CHNTAB AND LEVTAB, THEN DO SIR JSYS
;(TEMPORARY) IN NON-ZERO SECTIONS, EXTENDED SIR JSYS IS USED

XSIR:	XMOVEI D,20
	HLRZS D			;GET SECTION # IN D. IN SECTION 0 ?
	JUMPE D,[MOVEI A,.FHSLF	;YES
		MOVE B,[LEVTAB,,CHNTAB] ;GET TABLE ADDRESSES
		SIR%		;COMMUNICATE THEM TO THE MONITOR
		RET]

;FIX LEVTAB AND CHNTAB FOR EXTENDED SIR JSYS

	HRLM D,LEVTAB
	HRLM D,LEVTAB+1
	HRLM D,LEVTAB+2

	MOVSI A,-^D36		;FORM AOBJN POINTER
XSIR1:	HLRZ B,CHNTAB(A)	;IS THIS ENTRY BEING USED?
	TRNN B,770000		;DON'T DO IF LEVEL # ALREADY SET UP
	JUMPN B,[DPB B,[POINT 6,CHNTAB(A),5] ;YES, LEVEL # IN BITS 0-5
		DPB D,[POINT 12,CHNTAB(A),17] ;SECTION # IN BITS 6-17
		JRST .+1]
	AOBJN A,XSIR1		;LOOP THRU ALL ENTRIES OF CHNTAB

;PERFORM EXTENDED SIR JSYS

	MOVE A,[1,,.FHSLF]	;EXTENDED VERSION, THIS FORK
	XMOVEI B,LEVTAB		;GLOBAL ADDRESS OF LEVTAB
	XMOVEI C,CHNTAB		;GLOBAL ADDRESS OF CHNTAB
	SIR%
	RET
;Extended buffer code
;This implementation was suggested by God. Please direct inquiries
; to Him.

	SM%RWX==PM%RWX		;ACCESS WANTED TO SECTIONS

;This code will not work on a machine without extended addressing.

	CDESEC=1		;SECTION THE CODE AND DATA START IN
	FDGSEC=MAXSEC+CDESEC	;FDGSEC IS WHERE WE GO TO CREATE XBLT HANDLER


 IFG MAXSEC,<		;IF turned on, a lot of code is added.

	IFG FDGSEC-37, FOAD <Unacceptable values for CDESEC and MAXSEC>

CDEL:	TDZA	A,A		;TELL THE CODE TO KILL A PIECE
CIN:	SETO	A,		;TELL THE CODE TO READ A PIECE
	SKIPN	MSECF		;HAVE WE DONE SAVES YET?
	JRST	EXTQE		;NO, SO WE CAN'T FIND ANYTHING
	MOVEM	A,SYL		;SAVE FUNCTION CODE FOR A SEC...
	MOVX	A,.FHSLF	;MUST DISABLE INTERRUPTS SO THEY DONT HAPPEN..
	DIR%			;DURING NON-0 SECTION CODE
;From this point, errors must leave via RETCPY (to turn interrupt code back on)
	MOVE	A,SYL		;GET IT BACK
	TXNE	FF,ARG		;ANY ARGS?
	CAIN	C,0		;OR ARG OF ZERO?
	SETOM	FARG		;DEFAULT BUFFER NAME IS -1
	JRST	GOSAV3		;OK

COUT:	TXNE	FF,ARG		;ANY ARG?
	CAIN	C,0		;OR ARG OF 0?
	SETOM	FARG		;DEFAULT BUFFER NAME IS -1
	MOVX	A,.FHSLF	;MUST TURN OFF INTERRUPTS FOR THIS
	DIR%			;OFF...
	SKIPE	MSECF		;DONE ANY MULTIPLE SECTION STUFF?
	JRST	GOSAVS		;YES, SO SECTION CDESEC IS SET UP
	 ;..

;This is "once only" code. It is done on the first call to COUT only
; (and calls to CDEL or CIN return errors if COUT was never called.)
;At the end, MSECF is set nonzero.

	MOVSI	A,.FHSLF	;WE NEED TO GO NON-0 TO GO THIS
	MOVE	B,[.FHSLF,,FDGSEC] ;.. USE A FAR OUT SECTION TO SET UP,
	MOVX	C,SM%RWX+SM%IND+1 ;WITH ALL ACCESSES, 1 SECT ONLY
	SMAP%			;JUST LIKE SECTION 0
	 ERJMP	SMAPQE
	SETZ	A,		;NOW CREATE SECTIONS CDESEC ON UP
	MOVE	B,[.FHSLF,,CDESEC] ;..
	MOVX	C,SM%RWX+MAXSEC	;VIRGIN WITH ALL ACCESSES
	SMAP%
	 ERJMP	SMAPQE		;SNH
	XJRSTF	[PC%USR
		 FDGSEC,,COUATL] ;INTO CODE IN SECTION FDGSEC FOR XBLTS

	 ;.. INTO SECTION FDGSEC ..

COUATL:	MOVEI	A,CDLEN1	;XBLT THE CODE FROM SECT 0 TO SEC CDESEC
	MOVEI	B,CDFDG
	MOVE	C,[CDESEC,,BTRF]
	EXTEND	A,[XBLT]	;..
	MOVEI	A,VAR1E-VAR1SP+1 ;NOW CLEAR THE CDESEC VARIABLE SPACE
	MOVE	B,[CDESEC,,VAR1SP]
	MOVE	C,[CDESEC,,VAR1SP+1]
	EXTEND	A,[XBLT]	;..
	MOVEI	A,2		;AND PUT IN THE 2 WORDS AT NPGES1
	MOVEI	B,[EXP <MAXSEC*1000*1000-NPGES1-1000>,0]
	MOVE	C,[NPGES1]
	EXTEND	A,[XBLT]	;THIS INITIALISES THE FREESPACE
	XJRSTF	[PC%USR
		 0,,COUT1]	;NOW BACK TO SECT 0

	 ;.. BACK TO SECTION 0 ..

COUT1:	SETO	A,		;NOW DESTROY SECTION FDGSEC, ITS NOT NEEDED
	MOVE	B,[.FHSLF,,FDGSEC]
	MOVEI	C,1
	SMAP%			;..
	 ERJMP	.+1		;IF CANT, DONT CARE
	SETOM	MSECF		;OK, WE HAVE THE UNIVERSE SET UP NOW

GOSAVS:	MOVE	A,ZEE		;GET CHARACTER POSITION OF END
	CALL	MOVHOL		;MOVE HOLE TO END SO NEEDN'T SAVE IT
	SETO	A,		;"INDEX" INTO LIST OF ITEMS WE ARE BUILDING
	MOVE	B,[BFINFO,,BFINFE] ;THIS SAVES PT, ZEE, ETC.
	ADDI	A,1		;+1 FOR EACH ENTRY
	MOVEM	B,MVELST(A)	;FOR SAVING BUFFER
	MOVE	B,ZEE
	SUB	B,BEG		;HOW MANY CHARACTERS? (HOLE IS AT END)
	IDIVI	B,5		;MAKE THAT A WORD LENGTH
	ADDI	B,2		;AND DONT MISS ANYTHING
	HRLI	B,MTBUF0	;PUT BUFFER START IN LH, LEN IS IN RH
	ADDI	A,1		;NOW STORE THIS ENTRY
	MOVEM	B,MVELST(A)
	 ;..

;Come here to gate to code at BTRF in section CDESEC. The "name" of the
;info wanted is in FARG, and A contains one of the following:
; -1 to read the info down into section 0 (RETRIEve)
;  0 to quamp the info named by FARG (DELETe Block)
;  1 or more to save the information in section 0 referenced by the MVELST
;	array into an extended section. In this case, A is the highest
;	index valid in MVELST.

GOSAV3:	MOVE	C,FARG
	XJRSTF	[PC%USR
		 CDESEC,,BTRF]	;AND GO

SMAPQE:	MOVEI	P1,3		;THE ERROR CODE FOR NO SMAP MESSAGE
	 ;..			;AND FALL INTO RETCPY

;Back here after BTRF has run. Always come here (to reenable interrupts).
;P1 contains 0 if all ok, .GT. 0 is an error index.

RETCPY:	MOVX	A,.FHSLF
	EIR%			;REENABLE INTERRUPTS
	JUMPG	P1,EXTQE-1(P1)	;ERROR? GO TO CORRECT MESSAGE
	TXZN	FF,ARG2		;NO ERROR. IF 2 ARGS...
	JRST	CFLUSH		;NO
	MOVE	P1,SARG		;THEN CHECK FOR FLAGS
	TXNE	P1,1		;1B35=HK
	CALL	HK
	JRST	CFLUSH		;NO MORE FLAGS

EXTQE:	ERROR	<Cannot find that saved buffer>		;1
	ERROR	<Extended buffer space exhausted>	;2
	ERROR	<SMAP not available>			;3

;Punch out Literals so there aren't problems with literals in wrong sections.
;Listing off for neatness
	XLIST
	LIT
	LIST

;The following code ends up in section CDESEC starting at BTRF. It lives there
;so the XBLTs between section 0 and other sections will work.
;The values of A and C are important here.

 BTRF==140

CDFDG:	PHASE	BTRF		;THIS CODE GOES TO SECTION 1
	MOVEM	C,NAMEI		;SAVE INFO NAME
	JUMPL	A,RETRIE	;A.LT.0 MEANS RETRIEVE INFO NAMED (C)
	JUMPE	A,DELETB	;A.EQ.0 MEANS DELETE IT
	MOVEM	A,NUMBI		;NUMBER OF WORDS IN "COMMAND LIST"
	ADDI	A,1		;CORRECT COUNT FOR XBLT
	MOVEI	B,MVELST	;ADDR, SECTION 0, OF "COMMAND LIST"
	XMOVEI	C,CMDLST	;TO COPY UP HERE FOR EASIER MANIPULATION
	EXTEND	A,[XBLT]	;..
	MOVE	C,NAMEI		;DOES THIS BLOCK EXIST NOW?
	SETO	D,		;USE TO POINT TO FIRST ZERO SLOT
	MOVSI	A,-NAMLEN	;GO AND SEE
NAMCHK:	MOVE	B,NAMLST(A)
	CAME	C,B		;MATCH?
	JRST	CCMPCK
	JSP	I,DELBA		;DELETE BLOCK REF'D BY WHERE(A)
	JRST	OPSLOT
CCMPCK:	JUMPN	B,NXTNAM	;IF A REAL NAME, SKIP 0 MEMORY
OPSLOT:	CAIGE	D,0		;HAVE WE SEEN A ZERO LOC BEFORE?
	HRRZ	D,A		;NO, REMEMBER THIS ONE
NXTNAM:	AOBJN	A,NAMCHK	;OK, LOOK NEXT
	JUMPL	D,SPACQE	;IF NO OPEN SLOTS, GO COMPLAIN
	MOVEM	D,SLOT		;REMEMBER CHOSEN SLOT
	SETZ	A,		;COUNT UP NUMBER OF WORDS NEEDED
	SKIPA	B,CMDLST	;IN THE ARRAY AT CMDLST
CNTWRD:	ADD	B,CMDLST(A)
	ADDI	B,3		;EACH SECTION NEEDS +3 WORDS
	CAMGE	A,NUMBI		;COUNTED UP COMMAND LIST?
	AOJA	A,CNTWRD	;NO, AGAIN FOR NEXT
	MOVEI	B,1(B)		;TOSS OUT LH, IT CONTAINS TRASH, ADD 1
	XMOVEI	C,FRELST
	MOVE	D,FRELST+1	;POINT TO FREELIST
NXTCHK:	CAMG	B,(D)		;ENOUGH SPACE HERE?
	JRST	OKSPAC		;YES, WE CAN GO
	MOVE	C,D		;WE NEED THIS SO AS TO UPDATE FRELST LATER
	SKIPE	D,1(D)		;ADVANCE THROUGH CHAIN
	JRST	NXTCHK
SPACQE:	MOVEI	P1,2		;OUT OF SLOTS
	JRST	LEAVE1
OKSPAC:	MOVE	A,SLOT		;GET SLOT CHOSEN
	MOVEM	D,WHERE(A)	;SAVE POINTER TO BLOCK
	MOVE	A,(D)		;HOW MANY HERE?
	SUB	A,B		;HOW MANY WILL BE LEFT?
	MOVE	P1,A		;COPY THE "SIZE LEFT"
	SUBI	P1,4		;SEE IF LESS THAN 4
	JUMPG	P1,NOTALL	;JUMP IF 4 OR MORE LEFT
	MOVE	A,1(D)		;GET THIS WORD'S "NEXT" POINTER
	MOVEM	A,1(C)		;AND HAVE THIS BLOCK SKIPPED OVER
	JRST	GBLK
NOTALL:	ADDB	B,1(C)		;ADJUST POINTER DOWN BY NUMBER USING
	MOVEM	A,(B)		;SAY HOW MANY AT NEW BLOCK
	MOVE	A,1(D)		;GET OLD BLOCK'S NEXT POINTER
	MOVEM	A,1(B)		;COPY IT HERE
GBLK:	MOVE	A,SLOT
	MOVE	D,WHERE(A)	;GET START BLOCK ADDRESS
	SETZ	A,		;TIME TO SCAN CMDLST
XBLTLP:	HRRZ	B,CMDLST(A)	;LENGTH IN B
	MOVEM	B,(D)		;ALSO AT TOP OF BLOCK
	MOVE	C,D
	ADDI	C,3		;POINT TO WHERE DATA WILL LAND
	MOVEM	C,1(D)		;TO MAKE FUTURE XBLTS EASY
	HLRZ	C,CMDLST(A)	;GET SECTION 0 ADDR OF INFO
	MOVEM	C,2(D)		;STORE THAT
	ADDI	D,3		;ADVANCE POINTER TO BEGINNING OF DATA RANGE
	EXTEND	B,[XBLT]	;THIS COPIES THE DATA
	SETZM	(D)		;POINTS TO WORD AFTER, MAKE 0 (TO MARK END)
	CAMGE	A,NUMBI		;DONE LIST?
	AOJA	A,XBLTLP
	MOVE	A,SLOT		;WHERE DOES THIS GO?
	MOVE	C,NAMEI
	MOVEM	C,NAMLST(A)	;STORE NAME IN THAT SLOT
LEAVOK:	SETZ	P1,		;0 = OK
LEAVE1:	XJRSTF	[PC%USR
		 0,,RETCPY]

DELETB:	MOVSI	A,-NAMLEN
	SETZ	I,		;STAYS 0 IF NO NAMLST ENTRY MATCHES
DELB1:	CAMN	C,NAMLST(A)
	JSP	I,DELBA		;DELETE BLOCK AT WHERE(A)
	AOBJN	A,DELB1
	JUMPN	I,LEAVOK	;NONZERO IF JSP EVER DONE
	TXNE	FF,COLONF	;DOES USER CARE IF NOT FOUND?
	JRST	LEAVOK		;COLON SEEN, HE DOESNT CARE
	JRST	NFNDQE		;HE CARES, SET UP TO GIVE ERROR

RETRIE:	MOVSI	A,-NAMLEN
SCANR:	CAMN	C,NAMLST(A)
	JRST	GOTBLK
	AOBJN	A,SCANR
NFNDQE:	MOVEI	P1,1
	JRST	LEAVE1
GOTBLK:	MOVE	C,WHERE(A)
GNXTB:	SKIPN	B,(C)		;IS THERE DATA HERE?
	JRST	LEAVOK
	DMOVE	C,1(C)		;NEATLY LOAD C & D FOR XBLT
	EXTEND	B,[XBLT]	;BONZAI!
 BONZAI=CDESEC,,.		;FOR FUN
	JRST	GNXTB		;GO SEE

DELBA:	DMOVEM	A,S1TMP		;SAVE A & B
	DMOVEM	C,S1TMP2	;AND C & D
	SETZM	NAMLST(A)	;KILL THE NAME
	MOVE	D,WHERE(A)	;GET WHERE IT IS
	MOVEM	D,WHRKIL	;IT WILL BE KILLED
	SETZ	B,		;READY TO COUNT UP SPACE
MSBLK:	SKIPN	A,(D)		;ANY DATA HERE?
	AOJA	B,GKILL		;NO, ACCOUNT FOR 0 WORD AND GO KILL
	ADDI	B,3(A)		;COUNT UP SPACE
	ADDI	D,3(A)		;ADVANCE POINTER OVER BLOCK
	JRST	MSBLK
GKILL:	MOVEM	B,SIZKIL	;SAVE SIZE TO BE ADDED TO FRELST CHAIN
	MOVE	D,WHRKIL	;WHERE DOES IT START?
	MOVEM	B,(D)		;FIRST WORD OF FREEBLOCK IS LENGTH
	XMOVEI	C,FRELST
	MOVE	D,FRELST+1	;GET ADDRESSES TO SCAN FRELST WITH
	MOVE	A,WHRKIL	;GET ADDRESS OF THIS BLOCK IN MEMORY
FPIFL:	CAMG	A,D		;ARE WE BELOW THE RIGHT PLACE?
	JRST	KILHRE
	MOVE	C,D		;TRAILING CHASER
	MOVE	D,1(D)		;GET THE NEXT ADDRESS
	JUMPN	D,FPIFL
KILHRE:	MOVE	A,1(C)
	MOVE	B,WHRKIL	;POINT TO BLOCK TO GO IN AGAIN
	MOVEM	A,1(B)		;SECOND WORD IS "WHERE NEXT"
	MOVEM	B,1(C)		;MAKE LAST BLOCK POINT TO NEW ONE

	MOVE	A,WHRKIL	;NOW SEE IF PMAPING CAN FREE PAGES UP
	MOVE	B,A		;THIS IS MERELY TO REDUCE SWAPPING SPACE STRAIN
	ADD	B,SIZKIL	;LENGTH+START YIELDS LOC+1 OF END
	SUBI	B,1		;POINT TO END
	LSH	B,-9		;GET PAGE #
	SUBI	B,1		;LESS ONE
	LSH	A,-9
	ADDI	A,1		;AND 1 DOWN FROM TOP FOR START PAGE
	CAMLE	A,B		;IS START PAGE .LE. THAN END PAGE?
	JRST	CHKSET		;NO, NO PMAP TO DESTROY PAGES
	SUB	B,A		;HOW MANY PAGES?
	MOVEI	B,1(B)		;+1 TO GET REPETITION COUNT
	TXO	B,PM%CNT	;SET IT SO
	MOVE	C,B		;AND PUT IN C FOR PMAP
	HRRZ	B,A		;GET FIRST PAGE # IN RH B
	HRLI	B,.FHSLF	;DONE TO SELF
	SETO	A,
	PMAP%			;BLOW PAGES AWAY
	 ERJMP	CHKSET		;OH, WELL
CHKSET:	MOVE	C,FRELST+1	;GET WHAT FRELST POINTS TO TO START
CHKADJ:	MOVE	A,(C)
	ADD	A,C		;IF BLOCK LOC+BLOCK LEN IS
	CAME	A,1(C)		; .EQ. LOC NEXT BLOCK
	JRST	CHKAD2		;(NO)
	MOVE	B,1(C)		;THEN THE LEN OF THE NEXT BLOCK
	MOVE	A,(B)		;GETS ADDED TO THIS ONE
	ADDM	A,(C)		;..
	MOVE	A,1(B)		;AND THE "WHERE NEXT" OF THAT BLOCK
	MOVEM	A,1(C)		;BECOMES THIS ONE (THE BLOCKS ARE COMBINED)
CHKAD2:	SKIPE	C,1(C)		;IF THERE IS A NEXT BLOCK
	JRST	CHKADJ		;THEN GO AGAIN
	DMOVE	A,S1TMP		;ALL DONE, RESTORE AC'S
	DMOVE	C,S1TMP2
	SETZM	WHERE(A)	;FOR NEATNESS
	JRST	(I)		;CALLED BY JSP I,
CDLENI=.-BTRF

	XLIST
	LIT
	LIST

S1TMP:	BLOCK	2
S1TMP2:	BLOCK	2
WHRKIL:	0			;LOC OF FIRST PAGE TO PMAP AWAY
SIZKIL:	0
NAMEI:	0
NUMBI:	0			;# OF WORDS IN "COMMAND LIST"
SLOT:	0
CMDLST:	BLOCK	30		;DONT EXPECT MORE THAN 30 ENTRIES
VAR1SP:	0
 NAMLEN==200			;MAX NUMBER OF ENTRIES
NAMLST:	BLOCK	NAMLEN
WHERE:	BLOCK	NAMLEN
 VAR1E==.-1
FRELST:	0			;ZERO WORD FOR ALGORITHM TO CHEW ON
	NPGES1			;PAGE ADDRESS OF FREESPACE

 NPGES1=CDESEC,,<.&777000>+1000	;WHERE FIRST LOC OF FREESPACE IS

 CDLEN1==.-BTRF+1		;# OF WORDS TO COPY TO SEC CDESEC

	DEPHASE
>				;END OF IFG MAXSEC

;Back to a semblence of reality.
;Routines to play with the array, part 1

WZERO:	TXNN FF,ARG
	SETZ C,			;If no value given, assume 0
	EXCH C,USRARY		;Store user value, return old
WZERO1:	MOVE B,[USRARY,,USRARY+1] ;Ready to propagate value
	BLT B,USRARY+USARYL-1	;Cascade it
	JRST ARGINC		;And return value

WSUM:	TXZN FF,ARG2		;2 ARGS?
	TDZA P1,P1		;NO, SET PRECOMMA ARG TO 0
	JUMPL P1,ARRYQE
	CAIL P1,USARYL		;IN BOUNDS?
	JRST ARRYQE
	TXNN FF,ARG		;ONE ARG?
	MOVEI C,USARYL-1	;NO, PROVIDE THAT DEFAULT TOO
	JUMPL C,ARRYQE
	CAIL C,USARYL		;USUAL RANGE CHECK
	JRST ARRYQE
	CAMLE P1,C		;ARGS IN CANONICAL ORDER?
	EXCH P1,C		;NO, SWITCH THEM FOR HIM
	SKIPA A,USRARY(P1)	;BETTER THAN SETZ A, AND EXTRA ADD
WSUM1:	ADD A,USRARY(P1)	;SUM IN NEXT ARRAY LOC
	CAMGE P1,C		;WAS THAT THE LAST ONE REQUESTED?
	AOJA P1,WSUM1		;NO, ADD IN NEXT
	JRST ARGINA		;YES, SUM IN A


	IFN FTDEB,<		;NOT NORMALLY USED

;SETX - RUN TV IN A NON-ZERO SECTION
;REPLACE RESET AT TECO WITH JRST SETX
;RETURNS +1: ALWAYS, WITH PC IN A NON-ZERO SECTION AND SECTION
;	     0 MAPPED INTO THAT SECTION

SETX:	MOVSI A,.FHSLF		;GET SOURCE FORK HANDLE ,, SECTION#
	MOVE B,[.FHSLF,,3]	;DESTINATION F.H. ,, SECTION#
	MOVE C,[PM%RD+PM%WR+1]	;ACCESS,,COUNT
	SMAP%			;MAP SECTION 0 INTO ANOTHER SECTION
	MOVSI A,(PC%USR)	;BUILD PC
	MOVSS B
	HRRI B,TECO+1
	XJRSTF A		;GET TO TECO+1 IN NON-ZERO SECTION
> ;end of FTDEB
;INTERRUPT HANDLING ROUTINES

;COME HERE IF QUOTA EXCEEDED OR DISK FULL...

OVRQUO:	PUSH P,CX		;SAVE CX SINCE "SAVEAC" CLOBBERS IT
	CALL OVR2		;DO THE WORK (THIS WAY SO SAVEAC CAN BE USED)
	POP P,CX
	DEBRK%			;GO BACK AND CONTINUE TRYING TO WRITE FILE

OVR2:	SAVEAC <A,B,C>		;DON'T CLOBBER AC'S
	SKIPE EXPFLG		;DON'T EXPUNGE UNLESS USER ALLOWS IT
	SKIPN B,QUOJFN		;FIRST TIME THROUGH HERE?
	JRST OVR1		;NO, DON'T LOOP!
	PSTR <
%Quota exceeded or disk full - expunging deleted files
>
	SETZM QUOJFN		;CLEAR CELL SO WE DON'T LOOP
	SETZ A,			;NO SPECIAL BITS
	RCDIR%			;SEE WHICH DIRECTORY WE'RE WRITING TO
	 ERJMP OVR1		;FAILED, SO GIVE REAL ERROR
	SETZ A,			;NO SPECIAL BITS (AGAIN)
	MOVE B,C		;GET DIRECTORY BEING EXPUNGED
	DELDF%			;EXPUNGE IT
	 ERJMP OVR1		;FAILED, SO GIVE REAL ERROR
	RET

;COME HERE IF OVER QUOTA OR DISK FULL, BUT EXPUNGE DOESN'T OR CAN'T HELP

OVR1:	LERROR <Over quota or disk full -
 After some files are EXPUNGEd, type CONTINUE.
>
	CALL DOHALT		;LET USER FIX PROBLEM
	RET			;CONTINUE WRITING THE FILE

;WAUTO-EXPUNGE ALLOWS EXPUNGE TO BE DONE WHEN OVER QUOTA

AUTO:	SETOM EXPFLG
	JRST CFLUSH		;[502] DONE

;NOAUTO-EXPUNGE DISALLOWS AUTO-EXPUNGE TO BE DONE WHEN OVER QUOTA

NOAUTO:	SETZM EXPFLG
	JRST CFLUSH		;[502] DONE

;COME HERE WHEN USER TYPES ^C.

CTRL.C:	CALL SAVACS		;SAVE THE ACS
	PSTR <^C>		;SHOW USER THE ^C
	SETOM MESFLG		;ASSUME SCREEN MESSED UP
	SKIPE SCRNF		;ARE WE ON A SCREEN
	CALL EOS		;YES, SO CLEAR TO END OF SCREEN
	CALL DOHALT		;HALT
	JRST DEBRK.		;DISMISS INTERRUPT

;ROUTINE TO HALT.  IT RESTORES TERMINAL MODES TO WHAT THEY WERE LAST
;TIME USER ENTERED TV.  ALSO, IF USER CONTINUES, IT REMEMBERS NEW
;TERMINAL MODES, AND RESTORES TV'S MODES.

DOHALT:	HALTF%			;STOP
HALTED:	CALL SYSMOD		;USER CONTINUED, GET NEW MODES
	JRST CFLUSH		;[502] DONE

;INTERRUPT TO HERE WHEN USER TYPES CTRL/G

TTYINT:	CALL SAVACS
	MOVEI A,.PRIOU
	CFOBF%			;CLEAR OUTPUT BUFFER ALWAYS
	SKIPN LISNF		;DOING COMMAND INPUT?
	JRST TTYI1		;NO
	SKIPE ABORTF		;YES, FIRST INTERRUPT?
	JRST REE1		;YES, START COMMAND INPUT OVER.
TTYI3:	AOS ABORTF		;NOTE INTERRUPT REQUEST
	MOVEI A,"G"-100
	PBOUT%			;DO DING
	JRST IOER1		;RETURN

TTYI1:	MOVEI 1,.PRIIN
	CFIBF%			;CLEAR INPUT BUFFER
	SKIPE ABORTF		;FIRST REQUEST?
	JRST TTYI2		;NO, STOP IMMEDIATELY
	JRST TTYI3

ABORT:	PSTR <
Aborted
>
	JRST REE1

TYOQT:	MOVEI A,.PRIOU		;QUIT FROM TYPEOUT, CLEAR OUTPUT BUFFER
	CFOBF%
	JRST REE1

;IMMEDIATE STOP

TTYI2:	MOVEI 1,.FHSLF		;JIC!
	CIS%
	JRST REE1

REE1:	JRST REE		;CODE AT REENTER WILL TRY TO SAVE MODES AWAY

;ROUTINE WHICH SKIPS IFF BACKING UP IS CURRENTLY HAPPENING

SKBACK:	SKIPE TERIO		;DON'T BACK UP CHARACTERS NOT TYPED ON TERMINAL
	SKIPN BAKFLG		;IF BAKFLG IS 0
	RET			;SINGLE SKIP FOR NO INITIALIZATION
	JRST	CPOPJ1		;SKIP RETURN FOR BACK UP GOING ON

;CALL THIS ROUTINE IN ORDER TO WAIT FOR ALL COMMAND STRINGS FED TO SAVER
;SO FAR TO BE SAFELY OUT ON THE DISK.  MAINLY USED FOR EXITING BACK TO
;THE EXEC.

SINK:	CALL SKBACK		;MAKE SURE WE'RE DOING BACKUP
	RET
	MOVEI A,0		;NO NONPERMANENTS
	CALL BUPDAT
	SKIPN SDONEF		;WAIT FOR LAST UPDATE TO COMPLETE
	CALL HANG
	SKIPL SDONEF		;WAS THERE AN ERROR?
	JRST BUPERR		;YES, GO REPORT IT
	RET			;WHEN COMPLETE, RETURN

;THE FOLLOWING ROUTINE ALLOWS FOR WAITING FOR A SOMETHING TO HAPPEN
;WITHOUT TYING DOWN THE SYSTEM.
;WHAT YOU REALLY WANT			HOW YOU DO IT
;--------------------			-------------
;
;	HAS-"IT"-HAPPENED??		HAS-"IT"-HAPPENED??
;	JRST .-1	;NO		CALL HANG	;NO, WAIT FOR IT
;	...		;YES		...		;YES

HANG:	MOVEI A,^D150		;SLEEP FOR A WHILE
	DISMS%
	POP P,A			;GET ADDRESS WE WOULD HAVE RETURNED TO
	JRST -2(A)		;GO BACK AND SEE IF EVENT HAS HAPPENED YET
;CONTROL-O INTERRUPT, SUPRESS OUTPUT BUT DON'T STOP PROCESSING

CTRL.O:	AOSN COFLG		;COMPLEMENT FLAG - NOW CLEAR?
	DEBRK%			;YES, DO NOTHING FURTHER
	CALL SAVACS
	MOVEI A,.PRIOU
	CFOBF%			;FLUSH OUTPUT
	PSTR <^O...
>
	SETOM COFLG		;SET FLUSH FLAG
	XMOVEI B,20		;GET SECTION # IN LEFT HALF
	HRRZ A,LEV3PC		;SEE WHERE WE CAME FROM
	TLNE B,-1		;NON-ZERO SECTION?
	HRRZ A,LEV3PC+1		;YES, PC IS IN 2ND WORD
	MOVSI B,(PC%USR)
	CAIN A,TYOLOC+1		;THE BOUT?
	IORM B,LEV3PC		;YES, SET PC NOT TO RESUME BOUT
	JRST IOER1
;IO ERROR INTERRUPT

IOERR:	CALL SAVACS		;SAVE ACS DURING INTERRUPT
	PSTR <
IO data error, >
	MOVE B,IAC+A		;ASSUME JFN IN A
	CAMN B,INJFN		;THE INPUT ONE?
	JRST IOERI		;YES
	CAMN B,OUTJFN		;THE OUTPUT ONE?
	JRST IOERO		;YES
	PSTR <Unexplained
>
IOER1:	JRST DEBRK.

;SAVACS SAVES AC'S FOR DURING INTERRUPT ROUTINES
;LEAVES AC0 ALONE, SINCE IT HAS FLAGS IN IT

SAVACS:	MOVEM 1,IAC+1		;SAVE AC 1
	MOVE 1,[2,,IAC+2]
	BLT 1,IAC+16		;SAVE ACS 2 THROUGH 16
	RET

;COME HERE TO RESTORE AC'S AND DISMISS INTERRUPT

DEBRK.:	MOVE 16,[IAC+1,,1]
	BLT 16,16		;restore ac's
	DEBRK%

IOERI:	PSTR <Input file: >
IOER2:	MOVEI 1,.PRIOU
	SETZ 3,
	JFNS%			;TYPE FULL NAME OF FILE
	HRROI 1,[ASCIZ /
/]
	PSOUT%
	AOS ABORTF		;REQUEST ABORT
	JRST IOER1

IOERO:	PSTR <Output file: >
	JRST IOER2

;(REST OF INTERRUPT TABLES MOVED INTO SAVER FORK AREA)

;ROUTINE TO POP UP ONE TYPIN JFN.

TYIPOP:	SKIPE	SILFLG
	JRST	SHHH
	PSTR <
End of >
	MOVEI A,.PRIOU		;OUTPUT TO PRIMARY
	MOVE B,TYIJFN		;TYPE FILESPEC BEING ENDED
	SETZ C,			;PRINT IT IN STANDARD FORMAT
	JFNS%
	CALL CRR
SHHH:	MOVE A,TYIJFN		;GET JFN WE'RE GETTING RID OF.
	CLOSF%			;CLOSE THE FILE.
	 JFCL			;COULDN'T BUT DON'T WORRY.
	MOVE A,TYIP		;POP UP TO LAST INPUT JFN BECAUSE EOF.
	POP A,TYIJFN
	MOVEM A,TYIP		;SAVE NEW POINTER
	MOVE A,TYIJFN		;GET NOW CURRENT INPUT JFN.
	HRRM A,RDIOJ		;STORE LATEST JFNS FOR TEXTI
	HRLM A,RDIOJ
	HRRM A,SBK+.CMIOJ	;STORE FOR COMND JSYS TOO
	HRLM A,SBK+.CMIOJ
	DVCHR%			;SEE IF THIS JFN IS A TERMINAL
	MOVE A,TERIO		;REMEMBER WHETHER ENDING STREAM IS A TERMINAL
	MOVEM A,OTERIO
	SETZM TERIO		;FIRST ASSUME IT'S NOT.
	LDB A,[221100,,B]	;GET DEVICE TYPE NUMBER
	CAIN A,.DVTTY		;SKIP IF IT IS A TERMINAL
	SETOM TERIO		;REMEMBER THAT IT'S A TERMINAL
	RET

;ROUTINE TO CAUSE CHAR TO BE REAVAILABLE FOR INPUT.

RECHAR:	MOVE A,TYIJFN		;CORRECT JFN IN A
	BKJFN%			;PUT CHARACTER BACK IN STREAM
	 JSHLT
	RET

;ROUTINE TO INPUT A CHARACTER BUT NOTHING ELSE(I.E. NO BACKUP)

TYIX:	SETOM WINFLG		;IF RECEIVING INPUT, ASSUME USER HAS SEEN ALL
	MOVE A,TYIJFN		;GET APPROPRIATE INPUT JFN
	BIN%			;READ THE CHARACTER
	 ERJMP TYIEOF		;IF FAILS, PROBABLY END OF FILE
	MOVE A,B		;RETURN IT IN A
	RET

TYIEOF:	CALL %GETER		;GET REASON FOR FAILURE
	CAIE A,IOX4		;END OF FILE?
	 JSHLT			;NO, UNEXPECTED ERROR
	CALL TYIPOP		;YES, GET BACK TO LAST INPUT LEVEL
	JRST TYIX		;CONTINUE READING

;ROUTINE TO BACKUP A CHARACTER IN A.

BCHAR:	STKVAR <SHCHR>
	LSH A,1			;SHIFT CHARACTER TO MAKE IT ASCII
	MOVEM A,SHCHR
	CALL SKBACK		;MAKE SURE WE'RE BACKING UP
	RET
	AOS B,BBLEN		;ACCUMULATE CHARACTER IN BACKUP BUFFER
	HRLI B,100700		;MAKE POINTER TO CHARACTER
	HRRI B,SHCHR
	MOVE A,BBPTR		;POINTER TO WHERE CHARACTER GOES
	MOVEI C,1		;ONLY DOING ONE CHARACTER
	CALL TUTHER		;COPY CHARACTER INTO BACKUP BUFFER
	IBP BBPTR		;STORE UPDATED POINTER
	MOVE A,BBLEN
	SUB A,OBBLEN		;SEE HOW MANY ACCUM'D CHARS SINCE LAST UPDATE
	CAMGE A,BAKLEN		;ENOUGH CHARACTERS YET TO DO UPDATE?
	RET
	MOVEI A,0		;NO NONPERMANENT CHARS
;	CALLRET BUPDAT		;YES, INITIATE AN UPDATE

;ROUTINE WHICH INITIATES UPDATE OF BACKUP FILE.  PASS IT NUMBER OF
;NONPERMANENT CHARACTERS TO UPDATE IN A.

BUPDAT:	STKVAR <NONPER,SAVPAG,SAVCNT>
	MOVEM A,NONPER		;REMEMBER NUMBER OF NONPERMANENT CHARS
	MOVE A,BBLEN
	MOVEM A,OBBLEN		;REMEMBER NUMBER OF BACKUP CHARACTERS
				 ;AT TIME OF THIS UPDATE
	SKIPN SDONEF		;MAKE SURE SAVER IS DONE WITH LAST CHUNK
	CALL HANG		;NOT, SO WAIT FOR IT TO BE
	SKIPL SDONEF		;MAKE SURE THERE WERE NO ERRORS
	JRST BUPERR		;THERE WAS, PROBABLY OVER QUOTA
	MOVE A,BBLEN
	MOVEM A,SAVPER		;SAVER NEEDS TO KNOW # OF PERMANENT CHARS
	ADD A,NONPER		;GET TOTAL NUMBER OF CHARACTERS
	MOVEM A,SAVTOT		;SAVER NEEDS THAT
	MOVE A,BBPTR		;FIGURE OUT WHERE NONPERMANENT CHARACTERS GO
	MOVE B,RDBFP		;GIVE SAVER NONPERMANENT CHARACTERS
	MOVE C,NONPER		;GET PERMANENT NUMBER OF CHARACTERS
	CALL TUTHER		;APPEND NONPERMANENTS TO PERMANENTS
	MOVE A,BBUFX
	MOVEM A,SAVX		;TELL SAVER WHICH BUFFER TO USE
	CALL SAVGO		;START THE SAVER
	SETZM BBLEN		;THERE'S NO CHARACTERS LEFT IN BACKUP BUFFER
	SETZM OBBLEN		;RESET OLD COUNT SO NEXT SAVE HAPPENS..
	MOVE A,[<POINT 7,BBUF1>+<POINT 7,BBUF2>] ; AT RIGHT TIME
	SUB A,BBUFX		;SWITCH TO OTHER BACKUP BUFFER
	MOVEM A,BBUFX
	MOVEM A,BBPTR
	SETCMM WTOGGL		;TOGGLE TO OTHER WINDOW BUFFER
	RET

;COME HERE IF SAVER ENCOUNTERED ERROR DURING TRYING TO BACKUP LAST
;SEGMENT.  ASSUME THE ERROR CAN BE CORRECTED BY USER, LIKE "OVER QUOTA".
;HENCE PRINT THE ERROR MESSAGE, BUT OTHERWISE JUST RETRY THE LAST SAVE
;AND DON'T TRY TO BACKUP ANY NEW CHARACTERS YET.

BUPERR:	PSTR <
%TV backup file not updated yet - >
	MOVE B,SDONEF		;GET ERROR CODE
	HRL B,SAVFRK		;USE SAVER'S FORK HANDLE
	MOVE A,TTYOUT		;DIRECT OUTPUT TO TERMINAL
	MOVEI C,0		;NO CHARACTER COUNT LIMITATION
	ERSTR%			;PRINT SYSTEM'S REASON FOR ERROR
	 JFCL
	 JFCL
	CALL CRR
	CALLRET SAVGO		;MAYBE UNDER QUOTA AGAIN, RETRY THE SAVE

;ROUTINE TO CALL WHEN DESTINATION BUFFER STARTING ADDRESS IS SET UP.
;THIS ROUTINE CONJURES UP AN INITIAL OLD COMMAND POINTER BASED ON HOW MANY
;CHARACTERS HAVE BEEN TYPED THAT HAVE NOT YET BEEN BACKED UP, SUCH THAT
;WHEN SAVLEN'S WORTH HAVE ACCUMULATED, A BACKUP WILL HAPPEN

SETOCP:	MOVN A,BBLEN		;GET NEGATIVE NUMBER OF CHARACTERS TYPED
				; AND NOT BACKED UP
	ADJBP A,RDBFP		;INITIALIZE PLACE IN COMMAND STRING AT
				; WHICH LAST UPDATE HAPPENED
	MOVEM A,OCP		;REMEMBER
	RET

;ROUTINE TO START UP SAVER FORK

SAVGO:	MOVE A,SAVFRK		;START UP THE SAVER
	MOVEI B,SAVST
	SETZM SDONEF		;SAY SAVER ISN'T DONE YET
	SFORK%
	RET

;FOLLOWING ROUTINE TAKES PAGE NUMBER IN RIGHT HALF OF A, AND DOES PMAP SUCH THAT
;A WRITE INTO OUR PAGE AT FRKWI2 OR FRKWIN ACTUALLY CAUSES A WRITE INTO PAGE
;GIVEN IN A OF OTHER FORK

SFW:	HRRZ A,A		;KEEP ONLY PAGE NUMBER
	MOVEI D,LPM		;FIRST ASSUME FIRST WINDOW
	SKIPE WTOGGL		;OTHER?
	MOVEI D,LPM2		;YES
	CAMN A,(D)		;SAME AS LAST PAGE MAPPED?
	RET			;YES SO NOTHING TO DO
	HRL A,SAVFRK		;GET CORRECT FORK HANDLE
	MOVE B,[.FHSLF,,FRKWPN]	;GET WINDOW PAGE NUMBER
	SKIPE WTOGGL
	HRRI B,FRKWP2		;KEEP WINDOW NUMBER CORRECT
	XMOVEI C,20		;GET SECTION # IN LH
	LSH C,-11		;GET SECTION # IN BITS 18-26
	TDO B,C			;PUT SECTION # IN PMAP DESTINATION
	MOVX C,PM%WR		;WE WANT TO WRITE INTO THE PAGE
	PMAP%			;MAP FROM OTHER FORK TO US
	HRRZM A,(D)		;REMEMBER NEW MAPPED PAGE
	RET

;ROUTINE TO COPY CHARACTERS "TO OTHER" FORK.  GIVE IT DESTINATION POINTER
;IN A (PLACE IN OTHER FORK TO WHICH CHARACTERS ARE GOING), SOURCE
;POINTER IN B, AND NUMBER OF CHARACTERS IN C.
;THIS ROUTINE ASSUMES ASCII POINTERS

TUTHER:	STKVAR <TFROM,TWHERE,TCNT,INUM,TPTR>
	TLC B,-1
	TLCN B,-1
	HRLI B,(POINT 7)		;CHANGE -1 TO 440700
	TLC A,-1
	TLCN A,-1
	HRLI A,(POINT 7)		;CHANGE -1 TO 440700
	MOVEM B,TFROM
	MOVEM A,TWHERE
	MOVEM C,TCNT
TU1:	JUMPE C,CPOPJ		;RETURN IF EVERYTHING MOVED
	MOVE A,[010700,,FRKWIN+777] ;GET POINTER TO END OF WINDOW
	SKIPE WTOGGL		;USING OTHER WINDOW?
	MOVE A,[010700,,FRKWI2+777]	;YES, GET POINTER TO IT
	MOVE B,TWHERE		;GET PLACE WE'RE MOVING DATA TO
	IBP B			;CHANGE 010700,,F-1 TO 440700,,F
	ADD B,[70000,,0]
	MOVEM B,TWHERE		;REMEMBER THE POINT 7 VERSION
	TRZ B,777000		;GET RID OF PAGE NUMBER
	SKIPN WTOGGL		;CHOOSE APPROPRIATE WINDOW
	TROA B,FRKWIN		;GET BYTE POINTER AS TRANSLATED FOR OTHER FORK
	TRO B,FRKWI2
	MOVEM B,TPTR		;REMEMBER TRANSLATED POINTER
	CALL SUBBP		;CALCULATE NUMBER OF BYTES WE CAN DO
	MOVEM A,INUM		;REMEMBER HOW MANY WE CAN DO BEFORE UPING PAGE#
	LDB A,[111100,,TWHERE]	;GET PAGE OF FORK TO BE MAPPED
	CALL SFW		;SET UP FORK WINDOW
	MOVE P1,INUM		;GET NUMBER OF CHARACTERS WE CAN DO ON THIS PAGE
	CAMLE P1,TCNT		;MAKE SURE LESS THAN ENTIRE AMOUNT DESIRED
	MOVE P1,TCNT		;MORE.  ONLY DO WHAT WAS REQUESTED
	MOVEM P1,INUM		;REMEMBER NUMBER WE'RE ACTUALLY DOING
	MOVE I,TFROM		;TRANSFER FROM WHERE WE'RE SUPPOSED TO
	MOVE OU,TPTR		;USE TRANSLATED POINTER FOR DESTINATION
	CALL MVSTR		;TRANSFER AS MUCH AS CAN BE
	MOVE A,INUM		;GET NUMBER WE JUST DID
	ADJBP A,TFROM		;CALCULATE POINTERS FOR NEXT SECTION
	MOVEM A,TFROM
	MOVE A,INUM
	ADJBP A,TWHERE
	MOVEM A,TWHERE
	MOVN C,INUM
	ADDB C,TCNT		;UPDATE COUNT OF LEFT TO DO
	JRST TU1		;LOOP TO FINISH

;ROUTINE WHICH INPUTS COMMAND STRING USING TEXTI

DTEXTI:	STKVAR <CCL>
	SETOM WINFLG		;IF RECEIVING INPUT, ASSUME USER HAS SEEN ALL
DTXTI1:	MOVEI A,RDCWB		;ASSUME EVERYTHING ELSE CORRECT
	TEXTI%			;READ SOME MORE INPUT
	 JRST MEOF		;MAYBE END OF FILE
	SETZM ABORTF		;SO IFOO^G$$ DOES THE INSERT
	MOVE A,RDDBP
	MOVE B,RDBFP		;YES, SEE HOW LONG COMMAND STRING IS
	CALL SUBBP
	MOVEM A,CCL		;REMEMBER NEW COMMAND STRING LENGTH
	MOVE A,RDDBP		;GET RIGHTMOST POSITION OF COMMAND
	MOVE B,OCP		;GET OLD POSITION, AT LAST UPDATE
	CALL SUBBP		;SEE HOW MUCH TYPED SINCE LAST UPDATE
	CAMGE A,BAKLEN		;ENOUGH FOR A BACKUP?
	JRST DTNOG		;NO, NOT YET
	MOVE A,RDDBP		;YES, SO REMEMBER WHERE THIS UPDATE HAPPENED
	MOVEM A,OCP		;..
	CALL SKBACK		;BACKING UP?
	JRST DTNOG		;NO, CHAR NOT FROM TTY OR USER SAID WNOBACKUP$
	MOVE A,CCL		;GET CURRENT COMMAND STRING LENGTH
	CALL BUPDAT		;UPDATE THE BACKUP FILE
DTNOG:	MOVE A,RDFLG		;SEE WHY TEXTI STOPPED INPUTTING
	TXNN A,RD%BTM		;BREAK CHARACTER?
	RET			;NO, LET CALLER HANDLE IT
	CALL TYIX		;YES, ESCAPE TYPED, SEE IF NEXT ESCAPE ALSO
	CAIN A,.CHESC		;IS IT ESCAPE?
	CALLRET STFCHR		;STUFF THE SECOND ESCAPE AND RETURN
	CALL RECHAR		;NOT AN ESCAPE, CAUSE IT TO BE REREAD
	JRST DTXTI1		;GO BACK AND KEEP READING

;HERE IF ERROR DURING TEXTI

MEOF:	CAIE A,IOX4		;END OF FILE REACHED?
	 JSHLT			;NO, SOME OTHER ERROR
	CALL TYIPOP		;YES, POP BACK TO PREVIOUS LEVEL OF IO
	SKIPE OTERIO		;ENDING A NON-TERMINAL STREAM?
	RET			;NO
	MOVE A,RDDBP		;YES, DON'T LET TYPIST DELETE CHAR RECEIVED..
	MOVEM A,RDBFP		; FROM NON-TERMINAL
	SETZ B,
	IDPB B,A		;DON'T LET PSOUT GO TOO FAR
	MOVEI A,PCHAR		;DISPLAY PROMPT CHARACTER
	SKIPE TERIO		;BUT NOT IF READING FROM NON-TERMINAL
	PBOUT%
	MOVE A,CPTR		;SHOW USER COMMAND SO FAR
	SKIPE TERIO		;DON'T BOTHER DISPLAYING COMMAND SO FAR IF
	PSOUT%			; STILL READING FROM NON-TERMINAL
	MOVE A,RDBFP		;SEARCH BACK TO BEGINNING OF CURRENT LINE
MEOF1:	CAMN A,RDRTY		;ARE WE BACK TO THE BEGINNING OF BUFFER?
	JRST MEOF2		;YES
	LDB B,A			;NO, SEE IF WE'VE FOUND BEGINNING OF LINE
	CAIN B,.CHLFD		;HAVE WE?
	JRST MEOF2		;YES
	SETO B,			;NO, SEARCH BACKWARDS FOR IT
	ADJBP B,A
	MOVE A,B
	JRST MEOF1
MEOF2:	MOVEM A,RDRTY		;SET UP SO ^R ONLY SHOWS CURRENT LINE
	CALL SETOCP		;SET UP THE OLD COMMAND POINTER
	JRST DTXTI1		;GO CONTINUE READING FROM PREVIOUS SOURCE

;ROUTINE TO STUFF CHARACTER INTO COMMAND STRING.

STFCHR:	IDPB A,RDDBP		;STUFF THE CHARACTER IN
	SOS RDDBC		;ASSUME THERE WAS ROOM!
	RET

	;JSYS ERROR REPORT

JSER:	CALL WINCLS		;DON'T LET SCREEN UPDATE WIPE OUT ERROR MESSAGE
	PSTR <
?>
	CALL CLRINP		;CLEAR TYPEAHEAD
	HRLOI 2,.FHSLF		;THIS FORK, LAST ERROR
	SETZ 3,
	ERSTR%			;PRINT ERROR MSG
	 JFCL
	 JFCL
	CALL CRR
	RET

	IFN FTDEB,<		;NOT NORMALLY USED

;THIS ROUTINE PRINTS A CRLF AND A ? AND THE ERROR CODE CORRESPONDING TO
;THE ERROR NUMBER IN 1.

JSER1:	MOVE B,A		;PUT ERROR CODE IN 2
	MOVEI A,.PRIOU		;AND SAY TO PRINT ERROR ON TTY
	SETZ C,			;SAY TO PRINT WHOLE MESSAGE
	PSTR <
?>
	HRLI B,.FHSLF
	ERSTR%			;PRINT MESSAGE
	 JFCL
	 JFCL
	CALLRET CRR

> ;END OF FTDEB

;ROUTINE TO CLEAR TYPEAHEAD.  THIS IS DESIRABLE WHEN AN ERROR OCCURS,
;SINCE USER PROBABLY DOES NOT WANT HIS TYPEAHEAD EXECUTED IF PREVIOUS
;COMMAND FAILS.

CLRINP:	MOVEI 1,.PRIOU
	DOBE%			;WAIT FOR PRESENT OUTPUT TO BE SEEN
	CFIBF%			;CLEAR EXTRA TYPING
	RET
;OUTPUT A CHARACTER.  TAKES CHARACTER IN A.

TYO:	MOVE B,A		;CHARACTER TO B
	MOVE A,TTYOUT		;GET OUTPUT CHANNEL
TYOLOC:	BOUT%			;PRINT IT; THIS TAG IS FOR INTERRUPT SYSTEM
	RET

;SERVICE ROUTINE FOR CTYPE MACRO, TYPES ONE LITERAL CHARACTER

UCTYP0:	HRRZ A,UUOB+.AREFA	;GET THE CHARACTER (EFF ADDR OF UUO)
	CALLRET TYO		;TYPE IT AND RETURN

;PRINT STRING SUBROUTINE - SEE MACRO DEFINITION
; HRROI TT,[ASCIZ /STRING/]
; CALL PSTR0

PSTR0:	HRLI TT,(POINT 7)	;MAKE BYTE PTR
	ILDB A,TT		;GET CHAR FROM STRING
	JUMPN A,[CALL TYO	;OUTPUT IF IF NOT NULL
		JRST .-1]
	RET			;OTHERWISE, DONE
;ROUTINE TO OUTPUT DECIMAL INTEGER
;CALL MOVE c, DECIMAL INTEGER
;	MOVEI A,ADDRESS OF OUTPUT ROUTINE
;	HRRM A,LISTF5
;	CALL DPT
;	RETURN

DPT0:	HRRM A,LISTF5		;SETUP CHAR DISPATCH ADR
DPT:	MOVSI CH,(IFIW)
	HLLM CH,LISTF5		;SET FOR LOCAL INDIRECT REFERENCE
	MOVEI A,"-"
	SKIPGE C		;NEGATIVE NUMBER?
	CALL @LISTF5		;YES, OUTPUT MINUS SIGN
	MOVMS C			;c:=ABSOLUTE VALUE OF c
	CAIGE C,0		;DID THAT FETCH IT POSITIVE OR ZERO?
	SETZ C,			;HE JUST INVENTED -0 (1B0)
DPT2:	IDIV C,RADIX		;d:=DIGIT
	PUSH P,D		;STACK THE DIGIT
	SKIPE C			;DONE?
	CALL DPT2		;NO.
	POP P,A			;YES, RETRIEVE DIGIT
	ADDI A,60		;CONVERT IT TO ASCII.
	JRST @LISTF5		;PRINT IT

;ROUTINE TO TYPE CARRIAGE RETURN LINE FEED
;CALL CALL CRR
;	RETURN

CRR:	MOVEI A,.CHCRT
	CALL TYO
	MOVEI A,.CHLFD
	CALLRET TYO

;ROUTINE TO GET TO LEFT MARGIN

LM:	CALL CHKLM		;AT LEFT MARGIN?
	 CALLRET CRR		;NO, GET THERE
	RET			;YES, ALREADY THERE

;SKIP IF AT LEFT MARGIN

CHKLM:	MOVE A,TTYOUT		;GET OUTPUT CHANNEL
	RFPOS%			;GET POSITION ON LINE
	TRNN B,-1		;AT LEFT MARGIN?
	AOS (P)			;YES
	RET			;NO
;HERE TO GET NEXT COMMAND STRING FROM TTY

CLIS:	SKIPN A,INIJFN		;IS THERE A TV.INI?
	JRST CLIS3		;NO, OR WE'VE ALREADY EXECUTED IT
	MOVEI B,1		;INITIALIZE A NULL COMMAND
	MOVEM B,COMCNT
	MOVEM B,COMAX
	MOVSI B,(<BYTE(7)177>)
	MOVEM B,CBUF
	MOVE B,[POINT 7,CBUF]
	MOVEM B,CPTR
	CALL MFILE0		;READ FILE INTO Q-REG AREA
	CALL MAC0
	CALL CFLUSH
	JRST ICMD
CLIS3:	CALL ENARES		;MAKE RESCANNED DATA AVAILABLE
CLIS1:	HRRZ A,LSTCB		;PREPARE TO SAVE LAST COMMAND STRING
	HRRZ B,LSTCE
	CAIG A,CBUF
	JRST CSAV1		;IS ALREADY IN RIGHT PLACE
	SUBI B,0(A)
	CAIG B,3
	JRST CRST		;NOT USEFULLY LONG
	ADDI B,CBUF
	MOVEI A,CBUF
	HRL A,LSTCB
	BLT A,-1(B)		;MOVE TO CBUF
CSAV1:	HLL B,LSTCE		;NUMBER OF CHARS
	MOVEM B,LSTCB
	JRST CSAV2

CRST:	MOVE B,LSTCB		;RESET COMMAND STRING
CSAV2:	HRLI B,10700		;MAKE BYTE POINTER
	SOJ B,			;MAKE PROPER BYTE POINTER
	MOVEM B,RDRTY		;SET UP RETYPE BUFFER
	MOVEI A,PCHAR		;SET UP PROMPT
	IDPB A,B
	MOVEM B,CPTR
	MOVEM B,RDBFP		;MARK BEGINNING OF INPUT BUFFER
	MOVEM B,RDDBP		;DESIGNATE CURRENT END OF INPUT BUFFER
	MOVEM B,RDBKL		;MARK BACKUP LIMIT
	CALL TYO		;TYPE THE PROMPT
	MOVE A,TYIJFN
	HRL A,TYIJFN		;INPUT AND ECHO COME FROM INPUT JFN
	MOVEM A,RDIOJ		;TELL TEXTI WHERE CHARACTERS COMING FROM
	MOVEM A,SBK+.CMIOJ	;TELL COMND JSYS TOO
	SETOM LISNF		;NOTE NOW DOING COMMAND INPUT
	SETOM ABORTF		;CAUSES ^G TO ACT IMMEDIATELY HERE
	MOVEI 1,.PRIOU
	DOBE%			;WAIT FOR ALL OUTPUT, IN CASE ^G
	SETZM COFLG		;CLEAR TYPEOUT FLAG
	SETZM ABORTF		;CLEAR ABORT FLAG
	SETZM DUNFLG		;DON'T PUT OUT HEADING AGAIN
	SKIPGE WINFLG
	SKIPN SCRNF		;NO SCREEN CLEARING FOR NON-DISPLAY!
	TRNA			;NO SCREEN CLEARING IF PRESERVED OUTPUT!
	CALL EOS		;CLEAR PAD FOR COMMAND TYPEIN
	SKIPE SCRNF
	CALL EOL		;ALWAYS CLEAR LINE IF DISPLAY TERMINAL.
	CLEARM INTDPH		;INTDPH:=0
	CLEARM PCISG
ZSYMT:	CLEARM SYMS
	MOVE T,[XWD SYMS,SYMS+1]
	BLT T,SYMEND
	MOVE C,CBUFH
	CALL SETOCP		;CALCULATE INITIAL OLD COMMAND POINTER
	TXNN FF,RSCANF		;ARE WE RESCANNING?
	JRST LINRS		;NO
	MOVE B,[POINT 7,[ASCII /;Y/]]
			;GOBBLE INPUT BEFORE OUTPUT IN CASE "EDIT A..3 A..3"
	JRST LIFAKE		;FORCE THIS COMMAND STRING
LINRS:	CALL TYIX		;INPUT FIRST CHARACTER
	MOVEM A,FCHAR		;SAVE SINCE EOS CLOBBERS A
	SKIPE SCRNF		;DON'T CLEAR SCREEN ON NON-SCREENS
	CALL EOS		;CLEAR PREVIOUS PRESERVED OUTPUT
	MOVE A,FCHAR
	MOVEI B,0
	SKIPN EOBFLG		;IF EOBUFFER ALREADY DISPLAYED, <SP> NO-OPS.
	SKIPN SLENTH		;USING A DISPLAY WINDOW?
	JRST LINRS1		;NO, SO SPACE ISN'T SPECIAL
	CAIN A,C.MORE		;MAGIC "MORE" CHARACTER?
	JRST DMORE		;YES, GO DO IT
LINRS1:	CAIE A,.CHLFD		;FIRST CHARACTER LINEFEED?
	JRST LI69NL		;NO.
	MOVE B,[POINT 7,[ASCII /LT/]] ;
	SKIPE SLENTH		;DON'T DO THE "T" IF A WINDOW IS BEING USED.
	MOVE B,[POINT 7,[ASCII /L/]]
LI69NL:	CAIE A,"^"		;UP ARROW?
	JRST LI69NU		;NO.
	MOVE B,[POINT 7,[ASCIZ /-LT/]]
	SKIPE SLENTH		;NO "T" IF A WINDOW IS BEING USED.
	MOVE B,[POINT 7,[ASCII /-L/]]
LI69NU:	MOVE C,TRMTYP
	CAIE C,12		;ONLY VT05 HAS FUNNY ARROWS.
	JRST LI83
	CAIN A,C.UP
	MOVE B,[POINT 7,[ASCII /-L/]] ;FIRST CHARACTER IS "UP ARROW"
	CAIN A,C.DOWN
	MOVE B,[POINT 7,[ASCII /+L/]] ;FIRST CHARACTER IS "DOWN ARROW"
	CAIN A,C.RITE
	MOVE B,[POINT 7,[ASCII /+C/]] ;FIRST CHARACTER IS "RIGHT ARROW"
	CAIN A,C.LEFT
	MOVE B,[POINT 7,[ASCII /-C/]] ;"LEFT ARROW"
	JRST LI96		;FOR VT05, DON'T RECOGNIZE CONTROL-H AS -LT
LI83:	CAIN C,.TT100		;VT100?
	JRST LIV100		;YES
	CAIE C,.TTV50		;VT50?
	CAIN C,.TTV52		;OR VT52?
	CAIA			;YES
	JRST LI84		;NO
LIV100:	CAIE A,.CHESC		;ESCAPE SEQUENCE COMING? (ARROWS)
	JRST LI84		;NO
	MOVE C,TRMTYP
	CAIE C,.TT100		;VT100?
	JRST LIN100		;NO
	CALL TYIX		;YES, READ THE "[" BEFORE THE ARROW DESIGNATOR
	CAIE A,"["		;PROPER ESCAPE SEQUENCE COMING?
	JRST LINONE		;NO
LIN100:	CALL TYIX		;LOOK AT NEXT CHARACTER
	MOVE CH,A
	LOAD CH,UPRCOD,(CH)	;GET RAISED VERSION OF IT
	CAIN CH,V52.UP
	MOVE B,[POINT 7,[ASCII /-L/]] ;YES
	CAIN CH,V52.DN
	MOVE B,[POINT 7,[ASCII /+L/]]
	CAIN CH,V52.LT
	MOVE B,[POINT 7,[ASCII /-C/]]
	CAIN CH,V52.RT
	MOVE B,[POINT 7,[ASCII /+C/]]
	CAIN B,0		;ANY ESCAPE SEQUENCE CALCULATED?
LINONE:	MOVE B,[POINT 7,[ASCII / /]] ;NO, SO DO NOTHING
LIFAKE:	MOVE P1,B		;POINTER TO CHARACTERS IN P1
LIF1:	ILDB A,P1		;GET CHARACTER OF FAKE COMMAND
	JUMPE A,LI89		;ENTIRE COMMAND STUFFED IF NULL FOUND
	CALL STFCHR		;STUFF NEXT CHARACTER OF COMMAND
	JRST LIF1		;LOOP FOR ALL CHARACTERS
LI85:	CALL RECHAR		;CAUSE NON-SPECIAL CHARACTER TO BE REAVAILABLE
	MOVEI A,.TICTI		;DISABLE TYPEIN INTERRUPT
	DTI%			;SO THEY DON'T KEEP HAPPENING DURING...
				; COMMAND INPUT
LI1:	MOVE C,CBUFH
	MOVE B,RDDBP
	CAIG C,(B)		;COMMAND BUFFER EXCEEDED?
	 CALL LIXPND		; YES, EXPAND
	MOVE A,CBUFH
	MOVE B,RDDBP
	HRLI A,010700		;MAKE BYTE POINTER
	CALL SUBBP		;SEE HOW MANY CHARACTERS THERES ROOM FOR
	MOVE P1,A		;REMEMBER ROOM LEFT BEFORE EXPANSION REQUIRED
	MOVE A,RDDBP		;GET RIGHTEND OF COMMAND STRING
	MOVE B,OCP		;GET PLACE AT LAST BACKUP
	CALL SUBBP		;GET NUMBER OF UNBACKED UP CHARS
	MOVE B,BAKLEN		;GET NUMBER ALLOWED BEFORE BACKUP REQUIRED
	SUB B,A			;GET NUMBER TO INPUT BEFORE BACKUP REQUIRED
	CAML P1,B		;EXPANSION BEFORE BACKUP?
	MOVE P1,B		;NO, BACKUP WILL HAPPEN FIRST
	MOVEM P1,RDDBC		;REMEMBER HOW MANY CHARS TO INPUT
	CALL DTEXTI		;INPUT SOME OF THE COMMAND STRING
	MOVE A,RDFLG		;GET FLAGS FROM TEXTI
	TXNE A,RD%BLR		;DID USER DELETE EVERYTHING?
	JRST LINRS		;YES, GO CHECK FOR SPECIAL FIRST CHARACTER AGAIN
	TXNN A,RD%BTM		;TWO ALTMODES SEEN?
	JRST LI1		;NO, GET MORE INPUT
LI89:	MOVE A,[.TICTI,,TICHN]	;WE WANT TO KNOW WHEN USER TYPES
	ATI%
	MOVE A,RDDBP
	MOVE B,CPTR
	CALL SUBBP		;SUBTRACT POINTERS TO CALCULATE LEN OF COMMAND
	MOVEM A,COMCNT		;REMEMBER LENGTH
	CALL SKBACK		;MAKE SURE WE'RE BACKING UP
	JRST LINB		;NO
	MOVE A,RDDBP
	MOVE B,RDBFP
	CALL SUBBP		;CALCULATE LENGTH OF ACTUAL TYPED STRING
 ; (ENTIRE COMMAND MINUS PERHAPS SOME PARTIAL COMMAND FROM OLD BACKUP FILE!)
	MOVE C,A
	ADDM C,BBLEN		;BACKUP BUFFER IS NOW LONGER
	MOVE A,BBPTR		;APPEND COMMAND TO BACKUP BUFFER
	MOVE B,RDBFP
	MOVE D,C
	ADJBP D,BBPTR		;UPDATE POINTER TO END OF BACKUP BUFFER
	MOVEM D,BBPTR
	CALL TUTHER		;IT IS, COPY THE STRING
LINB:	MOVEI CH,177		;END OF COMMAND STRING MARKER
	AOS A,COMCNT		;MARK END OF COMMAND STRING WITH ASCII 177
	IDPB CH,RDDBP
	MOVEM A,COMAX
	MOVE P1,RDDBP		;SAVE END OF THIS COM STRING
	IBP P1			; FOR POSSIBLE LATER USE
	IBP P1			;POINTER BEFORE LAST THREE CHARS
	HRLI P1,-3(A)
	MOVEM P1,LSTCE
	SETZM LISNF		;NO LONGER DOING COMMAND INPUT
	SKIPN SLENTH		;IF NO WINDOW,
	CALL LM			;MAKE SURE AT LEFT MARGIN
LINOCR:	TXNE FF,TRACEF		;ARE WE TRACING?
	CALL WINCLS		;YES, SO DON'T LET SCREEN WIPE OUT TRACINGS!
	CALL CFLUSH		;[502] CLEAR MISC FLAGS
	SETZM EXECOP		;[502] CLEAR THESE HERE
	SETZM LASTOP		;[502] ..
	JRST ICMD		;[502] GO DO WORK

;SUBBP ROUTINE SUBTRACTS TWO ASCII BYTE POINTERS GIVEN IN A AND B,
;YIELDING CHARACTER DIFFERENCE IN B

SUBBP:	LDB C,[360600,,A]	;C TELLS HOW FAR FROM RIGHT EDGE A IS
	LDB D,[360600,,B]	;D SHOWS HOW FAR FROM RIGHT EDGE B IS
	SUB C,D			;BITS DIFFERENT A AND B ARE
	IDIVI C,7		;CHARACTERS DIFFERENT A AND B ARE
	SUB A,B			;CALCULATE HOW MANY WORDS APART A AND B ARE
	IMULI A,5		;CHANGE FROM WORDS TO CHARACTERS
	SUBI A,(C)		;GET TOTAL CHARACTER DIFFERENCE
	HRRZ A,A		;GET RID OF GARBAGE IN LEFT HALF
	RET

LIXPND:	MOVEI C,100
	ADDM C,CBUFH		;ALLOW COMMAND TO EXTEND FURTHER
	MOVE P1,EQRBUF
	IDIVI P1,5		;p1:=QREG BUFFER END WORD ADDRESS.
	MOVE P2,QRBUF
	IDIVI P2,5		;p2:=Q-REG BUFFER BASE WORD ADDRESS.
	SUBM P1,P2		;NO. OF WORDS IN Q-REG AND DATA BUFFER.
	MOVE CH,(P1)
	MOVEM CH,100(P1)	;MOVE Q-REG AND DATA BUFFERS UP 100 WORDS.
	SOS P1
	SOJGE P2,.-3
	MOVEI P1,500
	ADDM P1,QRBUF		;QRBUF:=p1(QRBUF)+500
	ADDM P1,EQRBUF		;UPDATE END OF QREG BUF
	RET

;ROUTINE TO SKIP IF CHARACTER SHOULD BE FLAGGED (WRONG CASE OR CONTROL)

SFLAGC:	CAIL CH,37		;IS CHARACTER CONTROL?
	JRST SFNC		;NO
	CAIE CH,.CHESC		;IS CHARACTER AN ESCAPE
	AOS (P)			;YES, SO NO FLAG
	RET				;CONTROL, NOT ESCAPE, FLAG IT
SFNC:	SKIPN FLAGF		;CASE SWITCH UPPER?
	RET			;CASE SWITCH 0, NO FLAG
	MOVX A,CH%UPR		;FLAGGING UPPERASE, GET UPPERCASE BIT
	TDNE A,CHRTAB(CH)	;IS CHARACTER UPPERASE?
	AOS (P)			;GIVE SKIP
	RET
LI84:	CAIN A,C.LEFT
	MOVE B,[POINT 7,[ASCIZ /-LT/]] ;FOR NON-VT05, "BACKSPACE" IS -LT.
	CAIE A,C.LEFT
	JRST LI96		;JUMP IF FIRST CHARACTER IS NOT A "BS"
	SKIPE SLENTH
	MOVE B,[POINT 7,[ASCII /-L/]]
		 ;DON'T DO THE "T" IF WE'RE USING A NON-0 WINDOW SIZE.
LI96:	JUMPN B,LIFAKE		;JUMP IF CHARACTER IS SPECIAL
	JRST LI85		;GO PUT IT BACK INTO INPUT STREAM

;DECREMENT ASCII BYTE PTR

DBP:	CAMN TT,HOLEPT		;SITTING JUST TO RIGHT OF HOLE?
	MOVE TT,HOLBPT		;YES, SO GET TO LEFT OF IT
	ADD TT,[7B5]		;BACK UP POINTER
	JUMPGE TT,.+2		;SKIP IF P NOT NOW 44 OR MORE
	SUB TT,[43B5+1]		;FIX FUNNY POINTERS
	RET
;ROUTINE TO RETURN NEXT CHARACTER FROM COMMAND BUFFER AND ERROR IF EMPTY.
;CALL CALL SKRCH
;	RETURN WITH CHARACTER IN CH
;GOES TO ERR IF COMMAND BUFFER IS EMPTY

SKRCH:	SKIPN COMCNT		;COMMAND BUFFER EMPTY?
SKRCQE:	ERROR <Missing command character(s) or terminator>

;ROUTINE TO RETURN NEXT CHARACTER FROM COMMAND BUFFER.
;CALL CALL RCH
;	RETURN ALWAYS WITH CHARACTER IN CH

RCH:	SOSGE COMCNT		;DECREMENT COMMAND BUFFER CHARACTER COUNT
				;IS COMMAND BUFFER EMPTY?
	JRST RCH2		;YES. POP UP TO HIGHER MACRO LEVEL.
	ILDB CH,CPTR		;NO. GET COMMAND CHARACTER IN CH
	TXNE FF,SCANF		;DON'T PRINT CHARACTERS BEING SCANNED OVER
	RET
	MOVE A,CH		;TYO WANTS CHARACTER IN A
	XCT TRACS		;RETURN OR JRST TYO IN TRACE MODE

RCH2:	POP P,CH		;SAVE RETURN FOR POPJ IN CH
	SKIPE INTDPH		;MAKE SURE ITERATIONS HAVE ENDED!
	ERROR <Unended iteration loop>
	POP P,INTDPH		;RESTORE PREVIOUS NESTING DEPTH
	CALL RESCMD		;RESTORE PREVIOUS COMMAND STATE
	PUSH P,CH		;GET RETURN BACK ON PDL.
	JRST RCH		;TRY AGAIN.

;ROUTINE TO PEEK AT NEXT CHARACTER IN COMMAND STRING WITHOUT ACTUALLY
;READING IT.  SKIPS IFF THERE WAS ONE TO READ, RETURNS IT IN CH.

PEEKCH:	MOVE CH,COMCNT		;SEE IF MORE COMMAND
	SOJL CH,CPOPJ		;JUMP IF THERE ISN'T
	MOVE CH,CPTR		;THERE IS, SO PEEK AT NEXT CHARACTER
	ILDB CH,CH
	JRST	CPOPJ1

;GET CHARACTER W/O TRACE - USED WHEN SKIPPING IN CONDITIONALS

SKRCH1:	SOSGE COMCNT		;ANY CHARACTERS LEFT?
	JRST SKRCQE		;NO, GO ERROR
	ILDB CH,CPTR		;YES. GET A CHARACTER.
	RET			;RETURN.

;These blocks are used by the command "parser" to point to the proper
;range and table for each command type.

PREPTR:	0,,CMDPTR		;PREFIX TYPE 0 (NONE)
	0,,SEMPTR		;PREFIX TYPE PRE.SM
	0,,UPAPTR		;PREFIX TYPE PRE.UP
	COLFLG,,CMDPTR		;PREFIX TYPE PRE.CL
	ATSFLG,,CMDPTR		;PREFIX TYPE PRE.AT

COLFLG:	COLONF
ATSFLG:	SLSL

UPAPTR:	0,,CMDTAB		;USE MAIN TABLE FOR ^ COMMANDS
	"@"			;OFFSET BY "@"
	"@"+UPALEN		;LENGTH IS CONTROL CHAR RANGE

CMDPTR:	0,,CMDTAB		;UNPREFIXED COMMANDS
	0			;THERE IS NO OFFSET FOR THESE!
	0+CMDLEN		;MAX LEGAL IS TABLE LENGTH

SEMPTR:	0,,SEMTAB		;SEMICOMMANDS USE SEMTAB TABLE
	" "			;OFFSET BY SPACE
	" "+SEMLEN		;MAX IS TABLE LENGTH OF SEMTAB


ICMD:	SKIPE	ABORTF		;<RUB>, ^G, I/O ERROR
	JRST	ABORT		;ARE ALL EXCUSES TO QUIT
	SETZM	DLIMIT		;NO FUNNY DELIMITERS WHILE SCANNING
ICMD2:	CALL	RCH		;GET THE COMMAND CHARACTER
	CAIN	CH,177		;MAGIC EOC CHARACTER?
	JRST	[SETZM INIJFN
		 JRST GO]	;YES, END OF TV.INI
	CAIE	CH,140		;EXPLICIT TEST FOR GRAVE, IT'S NOT AN ATSIGN
	CAILE	CH,172		;ABOVE A LOWER CASE Z
	JRST	NOSUCH		;IS CONSIDERED ILLEGAL
	CAIL	CH,141		;IS THIS CHARACTER LOWERCASE?
	SUBI	CH,40		;YES, CONVERT TO UPPER CASE
	MOVE	A,PREFXC	;GET PREFIX TYPE (OR 0)
	MOVE	B,PREPTR(A)	;B POINTS TO RANGE/INFO BLOCK
	HLRZ	A,B		;LH (IF >0) IS LOC OF FLAGS TO OR IN
	CAIE	A,0		;IS IT?
	OR	FF,(A)		;YES, OR IN FLAGS
	SETZM	PREFXC		;GOT TYPE, CLEAR PREFIX STATE
NPREFX:	MOVE	C,1(B)		;GET LOW LIMIT IN C
	CAMG	CH,2(B)		;DOES IT EXCEED THE UPPER BOUND?
	CAMGE	CH,C		;OR IS IT LESS THEN THE LOWER BOUND?
NOSUCH:	ERROR <Undefined command> ;COMMAND LOSES
	SUBM	CH,C		;OFFSET BY LOWER BOUND AND STORE IN C
	ADD	C,(B)		;AND ADD POINTER TO PROPER TABLE
	MOVE	A,(C)		;PICKUP COMMAND INFO
	HRRZ	B,A		;GET DISPATCH ADDR, PREFIX TYPE OR 0
	JUMPE	B,NOSUCH	;IF ZERO, NONESUCH
	TXNE	A,CM.PRE	;IS THIS A PREFIX CHARACTER?
	JRST	[MOVEM B,PREFXC ;YES, STORE AS SUCH (TYPE IN B)
		 JRST ICMD2]	;AND GO GET THE REST OF THE COMMAND
	TXNN	A,CM.EXE	;IS THIS COMMAND EXECUTED EVEN WHILST SCANNING?
	TXNN	FF,SCANF	;NO, ARE WE SCANNING?
	JRST	GODO		;THIS COMMAND ACTUALLY GETS DONE
	LDB	A,[POINT 9,A,17] ;SCANNING - FETCH OFFSET INTO ARG TABLE
	JUMPE	A,ICMD		;IF ZERO, THIS COMMAND HAS NO TRAILING ARGS
	MOVEI	C,ARGTAB(A)	;ELSE FETCH THE POINTER TO THEM.
	HRLI	C,(POINT NBACS)	;STORED IN A STRING, BYTE SIZE NBACS
	MOVEM	C,SKPPNT	;STORE POINTER FOR ILDBing
SKPTRL:	ILDB	A,SKPPNT	;PICKUP TRAILING ARG TYPE
	JUMPE	A,ICMD		;IF ZERO, DONE SCANNING OVER TRAILING ARGS
	CALL	@SKPTAB(A)	;ELSE, GO DO ROUTINE TO SKIP THE TYPE OF ARG
	JRST	SKPTRL		;UNTIL ALL TYPES ARE DONE

GODO:	TXNE	FF,SCANF	;IF EXECUTING WHILE SCANNING...
	JRST	DOCALL		;THEN SKIP REST OF CHECKING, AND PUSHJ OUT
	TXNE	FF,SLSL		;IS ATSIGN SET FOR THIS COMMAND?
	TXNE	A,CM.ATS	;YES, IS IT MEANINGFUL?
	SKIPA	C,LASTOP	;YES, SKIP WITH LAST OP SEEN
	ERROR	<Atsign modifier seen for command that cannot accept it>
	MOVEM	C,EXECOP	;STORE OP TO DO AFTER THIS COMMAND
	SETZM	LASTOP		;AND LEAVE LASTOP EMPTY
	MOVE	C,FARG		;IT'S OK, GET THE FIRST ARG
	TXNE	A,CM.OPR	;IS THIS AN OPERATOR COMING UP?
	MOVEM	C,PREOPV	;STORE THE PRE-OP VALUE
	TXNN	FF,ARG		;IS THERE AN ARG HERE?
	TXNN	A,CM.0AI	;NO. IS THAT LEGAL?
	SKIPA	P1,SARG		;COMBO OK, PICK UP ANY SECOND ARG
AG0QE:	ERROR	<Argument is missing>
	SETO	T,		;ASSUME NO ARGS
	TXNN	FF,ARG		;IS THERE ONE?
	JRST	DOCALL		;NO, OK TO DO THIS COMMAND
	TXNN	FF,ARG2		;YES, ARE THERE TWO?
	TDZA	T,T		;NO
	MOVEI	T,1		;YES!
	XCT	[TXNN A,CM.1AI	;ONE ARG WHEN ONE IS ILLEGAL
		 TXNN A,CM.2AI](T) ;TWO WHEN TWO IS WRONG
	JRST	DOCALL		;NO, ITS OK, GO DO
	CAIE	T,0		;WHICH ERROR?
AG2QE:	ERROR	<Two args where two args aren't allowed>
	SKIPL	EXECOP		;WEAK OP CARRYING A VALUE?
AG1QE:	ERROR	<Arg given where it isn't allowed>
	SETZM	EXECOP		;IT WAS MEANINGLESS, JUST KILL IT
	SETO	T,		;SET TO RIGHT NUMBER OF ARGS
	TXZ	FF,ARG		;AND SAY NONE, AND GO ON

;Commands branch here. They see the number of passed args -1 in T, the
;first arg (if any) in C, the second arg (if any) in P1.

DOCALL:	CALL	(B)		;GO DO IT
	 JFCL			;IN CASE SOMETHING HAS A SKIP RET
	SKIPN	A,EXECOP	;IS THERE AN OP TO DO?
	JRST	ICMD		;NO, GO GET NEXT COMMAND
	SKIPN	B,LASTOP	;DID WE JUST SEE ANOTHER OP?
	JRST	GODOOP		;NO, GO DO OP (IF ARGS ARE THERE)
	JUMPG	B,ICMD		;IF REAL LASTOP, LOSE ANY EXECOP
	JUMPL	A,ICMD		;WEAK LASTOP. IF EXECOP WEAK, REPLACE IT
DOP:	MOVEM	A,LASTOP	;WEAK LASTOP. DEFER EXECOP TO GET PAST SPACE!
	JRST	ICMD		;AND GO
GODOOP:	TXNE	FF,ARG		;GOT A GOOD EXECOP. GOT ARGS FOR IT?
	JRST	GARGOP		;GOT AN ARG TO OP ON
	JUMPL	A,DOP		;DONT. IF OP IS WEAK, DEFER IT
	ERROR	<Nothing returned a value after an Operator or Comma>
GARGOP:	MOVE	C,PREOPV	;GET PRE-OP ARG
	MOVE	B,FARG		;AND THE POST OP ONE
	TXZE	A,OPF.NG	;REQUEST 2ND ARG BE NEGATED FIRST?
	MOVN	B,B		;DONE
	XCT	BINFUN(A)	;AND DO THE BINARY FUNCTION
	MOVEM	C,FARG		;AND STORE RESULT
	JRST	ICMD		;GO GET NEXT COMMAND
;Table that indicates what function is to be done when a binary op becomes due.
;OP.nnn is used to index into it

	OP.NOP==1
	OP.ADD==2
	OP.SUB==3
	OP.MUL==4
	OP.DIV==5
	OP.AND==6
	OP.IOR==7
	OP.XOR==10
	OP.ANC==11		;AND /W COMPLEMENT

	OPF.NG=1B18		;NEGATE SECOND VALUE (A op -B)

;TRNA IS USED TO SKIP OVER THE MOVEM (IE, DO NOTHING)
BINFUN:	TRNA			;NOT INDEXED BY 0
	MOVE	C,B		;USED IF "OP" DEMANDS TRAILING VALUE
	ADD	C,B		;ADD IS 2
	SUB	C,B		;SUB IS 3
	IMUL	C,B		;IMUL IS 4
	CALL	DODIVI		;IDIV IS 5, GO DO AND SAVE REMAINDER
	AND	C,B		;AND IS 6
	IOR	C,B		;OR IS 7
	XOR	C,B		;XOR IS 10
	ANDCM	C,B		;ANDCM IS 11

DODIVI:	IDIV	C,B		;IDIV IS 5
	MOVEM	D,DIVREM	;KEEP REMAINDER AROUND FOR THE ;/ COMMAND.
	RET
;This table is index by the SC.xxx values. The represent the addresses of
;routines to CALL when a certain type of trailing arg is to be skipped

SKPTAB:	0			;NOT INDEXED BY ZERO
	SKRCH1			;HERE TO SKIP ONE CHARACTER !CS.SY1
	SKRCH1			;HERE TO SKIP QREG (ONE CHARACTER) !CS.QRG
	SKPDIG			;HERE TO SKIP A DIGIT STRING, LEN.GE.0 !CS.DIG
	SKPSTR			;HERE TO SKIP SIMPLE STRING !CS.STR
	SKPINS			;HERE TO SKIP INSERT STR !CS.INS
	SKPSRS			;HERE TO SKIP SEARCH STRING !CS.SRS

;Skip a string of digits of length greater or EQUAL to zero.
SKPDIG:	CALL	PEEKCH		;CHECK NEXT CHAR IF ANY
	 RET			;NONE, NUMBER SKIPPED OVER
	CAIN	CH,"."		;IS IT THE OCTAL INDICATOR?
	JRST	SKRCH1		;YES, READ IT, AND NUMBER ENDS HERE
	CAIL	CH,"0"
	CAILE	CH,"9"		;IS IT A DIGIT?
	RET			;STOP ON NONNUMERIC
	PUSHJ	P,SKRCH1	;SKIP THE DIGIT
	JRST	SKPDIG		;AND GO FOR NEXT CHAR

;Skip over a simple string, such as ^Atext$ uses.
SKPSTR:	CALL	GETDLM		;GO FIGURE OUT DELIMITER, STORE IN DLIMIT
SKPST1:	CALL	SKRCH1		;SCAN UNTIL GOT IT
	CAME	CH,DLIMIT	;..
	JRST	SKPST1		;NOT YET...
	RET			;GOTCHA.

;Skip over an Insert string, such as Itext$ or Rtext1$text2$ uses.
SKPINS:	CALL	GETDLM		;GET DELIMITER INTO DLIMIT
SKPIN1:	CALL	SKRCH1		;GET CHARACTER FROM STRING
	CAMN	CH,DLIMIT	;IS CHARACTER MEANING "END"?
	RET			;YES, JUST LEAVE
	CAIE	CH,C.LOWR	;IS CASE OF NEXT CHAR BEING SHIFTED?
	CAIN	CH,C.RAIS	;..?
	MOVEI	CH,C.QUOT	;YES, TREAT EXACTLY LIKE QUOTING CHAR
	CAIN	CH,C.QUOT
	CALL	SKRCH1		;WE ARE QUOTING SOMETHING, GOBBLE WHAT'S QUOTED
	JRST	SKPIN1		;AND GO GET NEXT CHAR

;Skip over search strings. This can involve recursion and things of like
;messiness, esp. with ^N or ^E in the string.
SKPSRS:	CALL	GETDLM		;GET DELIMITER INTO DLIMIT
SKPSR1:	CALL	SKRCH1		;GET INITIAL CHARACTER IN TOKEN
	CAMN	CH,DLIMIT	;IS IT END-OF-STRING?
	RET			;YES, HAPPY DAYS
	CALL	IDNTKN		;GO SCAN OVER IF ITS A TOKEN
	JRST	SKPSR1		;AND GET NEXT

IDNCHR:	CALL	SKRCH1		;HERE IF IDNTKN NEEDS A NEW CHAR BUT CARES
				;NOT ABOUT END-OF-STRING CHAR
IDNTKN:	CAIN	CH,"N"-100	;IS IT THE ^N TOKEN?
	CALLRET	IDNCHR		;YES, FETCH NEXT TOKEN AND LEAVE
	CAIE	CH,^D17		;IS IT OLD-STYLE QUOTE
	CAIN	CH,C.QUOT	;OR NEW STYLE QUOTE?
	CALLRET	SKRCH1		;YES, READ A CHARACTER AND LEAVE
	CAIE	CH,"E"-100	;IS IT AN ^E?
	RET			;NO, ITS A SINGLE CHAR TOKEN, DONE
				;(^X,^S need nothing special)
	CALL	SKRCH1		;WHAT KIND OF ^E ARE YOU?
	CAIN	CH,^D60		;AN OPEN ANGLE BRACKET?
	JRST	[CALL SKPDIG	;YES, SKIP THE NUMBER FOLLOWING...
		 CALL SKRCH1	;AND WHAT SHOULD BE A CLOSEANGLE
		 RET]		;AND LEAVE
	CAIE	CH,"["		;MAYBE HEAVY RECURSION AHEAD
	RET			;NO, IT WAS ^Ex
CEBSCN:	CALL	IDNCHR		;RECURSION... "TURNING AND TURNING IN THE
				;WIDENING GYRE..."
	CALL	SKRCH1		;FETCH A CHARACTER, SHOULD BE ] OR ,
	CAIN	CH,","		;LOOK AND SEE
	JRST	CEBSCN		;ITS A REQUEST FOR THE NEXT IN-^E TOKEN
	CAIN	CH,"]"		;IS THIS THE END OF THE ^E[] ?
	RET			;GOOD, UNWIND
	ERROR	<Comma or "]" required, can't skip over string>


;This decides what the delimiter is for the string about to be scanned over -
;ie, ESC unless atsign form is indicated. The delimiter is returned in DLIMIT.
GETDLM:	SKIPE	DLIMIT		;DO WE ALREADY HAVE A KNOWN DELIMITER?
	RET			;YES, USE IT
	MOVEI	CH,.CHESC	;DEFAULT STRING END IS <ESC>
	TXZE	FF,SLSL		;BUT IF ATSIGN FLAG IS LIT
	TXNN	A,CM.ATS	;AND IS NOT MEANINGLESS HERE	
	CAIA			;(NOT CHANGING DELIMITER)
	CALL	SKRCH1		;THEN THE NEXT CHAR IS THE DELIMITER
	MOVEM	CH,DLIMIT	;STORE IT.
	RET
;Routines to return args.
;CFLUSH is what CRET used to be (clears all args & flags)
;All commands should exit by JRSTing here, except for special convolutions and
; fudgery. Commands not changing the arguments may simply RET.
;The meanings are:
;
;ARGXNA - the command stores athe arg in AC A. This wont turn off SLSL or
;	COLONF, but is otherwise like ARGINA. CDNUM needs this.
;ZERINA - command returns a 0
;NE1INA - command returns -1
;ARGINA - the command stores the arg in AC A. This makes sure that the one
;	arg is on, unless two args have already been specified. This turns
;	off SLSL and COLONF.
;ARGINC - same as ARGINA, except the arg is in AC C.
;ARGIN - lights the arg returned (ARG) flag. assumes arg(s) already stored

CFLUSH:	TXZ	FF,COLONF!FINDR!PCHFLG!SLSL!ARG2!ARG ;HERE TO TOSS OUT FLAGS
	SETZM	PREOPV
	SETZM	FARG		;CANT CLEAR EXECOP/LASTOP HERE
	RET			;THE WORLD

ARGXNA:	MOVEM	A,FARG		;STORE THE ARG IN A
	JRST	ARGIN		;BUT DON'T MEDDLE WITH SLSL OR COLONF
ZERINA:	TDZA	A,A		;COMMAND RETURNS A ZERO
NE1INA:	SETO	A,		;COMMAND RETURNS A -1
ARGINA:	MOVE	C,A		;STORE THE ARG IN A
ARGINC:	MOVEM	C,FARG		;STORE THE ARG IN C
ARGINF:	TXZ	FF,SLSL!COLONF	;CLEAR THIS-COMMAND-ONLY FLAGS
ARGIN:	TXO	FF,ARG		;RETURNING AN ARG
CPOPJ:	RET
;MAIN COMMANDS BRANCHED TO BY COMMAND PARSER START HERE.

SPACC:	TXNN	FF,ARG		;IS THERE AN ARG FOR ME?
	RET			;NO, LEAVE THINGS JUST AS THEY ARE...
	SKIPA	A,[1B0+OP.ADD]	;SET LASTOP FOR OP ADD, 1B0 MEANS TENTATIVE
PLUS:	MOVEI	A,OP.ADD	;OPERATION REQUESTED IS ADD
SETBOP:	MOVEM	A,LASTOP
	CAIL	A,0		;IF NOT A TENTATIVE OP,..
	TXZ	FF,ARG		;SAY NO ARG WAITING
	RET

MINUS:	MOVEI	A,OP.SUB	;SUBTRACT
	SKIPN	EXECOP		;IS AN ARG WAITING?
	JRST	SETBOP		;GO SET BINARY OP CONDITION
	MOVEI	A,OPF.NG	;OH! THIS IS DIFFERENT...
	XOR	A,EXECOP	;REMEMBER OPERATION, BUT SAY TO NEGATE POSTOP
	SETZM	EXECOP
	MOVEM	A,LASTOP
	RET			;AND GO PLAY


COMMA:	MOVEM	C,SARG		;STORE ARG
	TXO	FF,ARG2		;TWO ARG2 CONDITION
	TXZ	FF,ARG		;BUT NOT ONE ARG CONDITION, YET.
	MOVEI	A,OP.NOP	;BINARY OP CONDITION FORCES FOLLOWING NUMBER
	JRST	SETBOP		;GO STORE AND RETURN

CAND:	MOVEI	A,OP.AND	;AND OPERATION
	TXNE	FF,COLONF	;:& FUNCTION?
	MOVEI	A,OP.ANC	;YES, AND WITH COMPLEMENT
	JRST	SETBOP

COR:	MOVEI	A,OP.IOR	;OR OPERATION
	TXNE	FF,COLONF	; :# FUNCTION?
	MOVEI	A,OP.XOR	;YES, XOR
	JRST	SETBOP

TIMES:	MOVEI	A,OP.MUL	;MULTIPLY OPERATION
	JRST	SETBOP

SLASH:	MOVEI	A,OP.DIV	;DIVIDE OP
	JRST	SETBOP

CDNUM:	MOVEI	C,-60(CH)	;[502] CONVERT FIRST DIGIT TO A VALUE
;**;[505] At CDNUM: +1L, Added 1 line           	SM	13-Apr-82
	MOVE	D,C		;[505] TWO COPIES; DECIMAL AND OCTAL
CDNUM1:	CALL	PEEKCH		;[502] GET NEXT DIGIT OR DOT, IF ANY
	 JRST	ARGINC		;[502] NONE, THE VALUE IS IN C
	CAIN	CH,"."
	JRST	CDNUM2		;[502] IF A DOT, MUST GO CONVERT TO OCTAL
	CAIL	CH,"0"		;[502] IS A DIGIT?
	CAILE	CH,"9"		;[502] ..
	JRST	[MOVE A,C	;[502] NO, SO WE ARE DONE
		 JRST ARGXNA]	;[502] GO EXIT OUT, PRESERVING FLAGS
	IMULI	C,^D10		;[502] A POWER OF 10 UP...
	ADDI	C,-60(CH)	;[502] AND IN THE NEW LOWORDER DIGIT
;**;[505] At CDNUM1: +10L, Added 2 lines        	SM	13-Apr-82
	LSH	D,3		;[505] GET OCTAL JUST IN CASE
	IORI	D,-60(CH)	;[505] AND ADD IN THE DIGIT.
	CALL	RCH		;[502] TOSS READ DIGIT
	JRST	CDNUM1		;[502] AND GO GET NEXT
CDNUM2:	CALL	RCH		;[502] TOSS DOT OUT
;**;[505] At CDNUM2: +1L, Replaced 2 lines with 1	SM	13-Apr-82
	MOVE	A,D		;[505] GET THE OCTAL
	JRST	ARGXNA		;[502] RETURN WITH VALUE IN PLACE

RNGE:	MOVM C,C		;GET MAGNITUDE OF FIRST ARG
	TXZE FF,ARG2		;IS THERE A SECOND ARG?
	SUB C,P1		;YES, SUBTRACT IT OFF
	JRST ARGINC		;RETURN RESULT

VRSN:	MOVE C,VRSNI
	JRST ARGINC		;RETURN VERSION NUMBER FOR USER

QCVAL:	CALL QREGVI		;A:=QTAB ENTRY, CH:=Q-REG INDEX
	MOVE C,A
	PUSH P,CH
	CALL QGET2		;GET NUMBER OF CHARS
	POP P,C			;Q-REG INDEX
	TXZE FF,SLSL		;@FORM?
	JRST QABSOL		;YES, RETURN BYTE POINTER TO QREG...!
	MOVE A,P1		;GET QREG LEN IN A, IN CASE NO ARGS
	TXNN FF,ARG		;ANY ARGS?
	JRST ARGINA		;NO ARGS, JUST RETURN LENGTH
QCV2:	SKIPLE FARG
	CAMGE A,FARG		;IS REFERENCE WITHIN QREG LENGTH?
	JRST QCVLQE		;NO, GO DECIDE ON ERROR TYPE
	MOVE I,QTAB-"0"(C)
	TLZ I,(-1B14)
	ADD I,QRBUF
	ADDI I,3
	ADD I,FARG		;PUT CHARACTER ADDRESS INTO I
	CALL GETX		;GET POINTER TO BYTE IN TT
	MOVE C,SARG
	LDB A,TT
	TXZE FF,ARG2		;READ OR WRITE?
	DPB C,TT
	JRST ARGINA
QCVLQE:	TXNN FF,COLONF		;DID HE EXPECT THE WORST?
	ERROR	<Qreg character reference out of bounds>
	JRST NE1INA		;RETURN -1 IF ILLEGAL (YES, UNCONVENTIONAL...)
QABSOL:	MOVE I,QTAB-"0"(C)
	TLZ I,(-1B14)
	ADD I,QRBUF
	ADDI I,3
	CALL GETX
	MOVE C,TT
	JRST ARGINC

REMDIV:	MOVE	C,DIVREM
	JRST	ARGINC		;GET REMAINDER FROM LAST IDIV

RAND:	TXNE	FF,ARG
	CAIN	C,0
	MOVEI	C,^D100
	SKIPE	A,ISEED
	JRST	WRAND1
	GTAD%
	AND	A,CONS4
	CAIN	A,0
	MOVEI	A,^D123457
	MOVEM	A,ISEED
WRAND1:	MUL	A,CONS3
	DIV	A,CONS4
	MOVEM	B,ISEED
	MOVSI	A,237K
	DFAD	A,[EXP 0,0]
	FLTR	C,C
	FMP	C,A
	FIX	C,C
	JRST	ARGINC
CONS3:	^D16807
CONS4:	17777,,-1

ARRY:	TXNE FF,SLSL		;ATSIGN?
	JRST	[MOVEI A,USRARY	;@^Y RETURNS PHYSICAL LOC OF ARRAY!
		 TXNE FF,COLONF	;:@^Y RETURNS THE LENGTH OF THE ARRAY!
		 MOVEI A,USARYL
		 JRST ARGINA]	;DONE
	JUMPL T,AG0QE		;IF NO ARGS, COMPLAIN BITTERLY
ARRY1:	CAIL C,0		;ILLEGAL ARRAY REFRENCE IF .LE. 0
	CAIL C,USARYL		;IN LEGAL RANGE FOR ARRAY?
ARRYQE:	ERROR <Reference to array is out of bounds>
	MOVE A,USRARY(C)	;GET VALUE THAT IS THERE
	TXZE FF,ARG2		;DOES HE WANT TO STORE A NEW VALUE?
	MOVEM P1,USRARY(C)	;YES, STORE IT FOR HIM
	JRST ARGINA		;DONE

DUJSI:	HLRZ	A,FARG		;DID HE SPECIFY HIS OWN OPCODE/AC/ETC?
	JUMPN	A,DUXCT
	MOVEI	A,(JSYS)	;THE OPCODE OF A JSYS
	HRLM	A,FARG		;THE USER PROVIDED A JSYS NUMBER
DUXCT:	DMOVE	1,USRARY+1	;GET USER AC'S
	DMOVE	3,USRARY+3	;..
	DMOVE	5,USRARY+5	;..
	SETOM	USRARY+0	;SET ERROR FLAG TO -1 (NO ERROR YET)
	XCT	FARG		;BE IT ON HIS OWN HEAD...
	 ERJMP	DUJSIE		;HE LOSES
	JRST	CLNJSI
	JRST	CLNJSI		;SOME JSI HAVE MULTIPLE SKIPS
DUJSIE:	DMOVEM 	A,USRARY+1
	MOVEI	A,.FHSLF	;GO DISCOVER WHAT HIS ERROR WAS
	GETER%			;..
	 ERJMP	CLNJS2		;IT WONT FAIL.
	HRRZM	B,USRARY+0
	JRST	CLNJS2		;WE ALREADY STORED AC1/2
CLNJSI:	DMOVEM	1,USRARY+1
CLNJS2:	DMOVEM	3,USRARY+3
	DMOVEM	5,USRARY+5	;RESTORE AC'S BACK
	TXZN	FF,ARG2		;DOES HE WANT A WORD RETURNED?
	JRST	DUJEN1		;NO, GO SEE IF HE WANTS ERRORS RETURNED
	MOVE	C,SARG		;THE SECOND ARG IS THE INDEX OF THE WORD
	TXZ	FF,SLSL		;CLEAR ATSIGN
	JRST	ARRY1		;AND BECOME AN ARRY COMMAND

DUJEN1:	TXNN	FF,COLONF	;RETURN ERROR INDICATION OR -1?
	JRST	CFLUSH		;NOPE
	MOVE	C,USRARY+0	;RETURN VALUE
	JRST	ARGINC		;AND DONE

HLFWRD:	TXZE	FF,SLSL		;ATSIGN FORM?
	JRST	SPLWRD		;YES, GO SPLIT LH,,RH
	TXZN	FF,ARG2		;DID HE PROVIDE BOTH ARGS?
	SETZ	P1,		;NOPE, ASSUME ZERO
	HRL	C,P1		;BUILD PRECOMMA ARG LH, POST RH
	TXNE	FF,COLONF	;ETO CHTO ONI KHOTCHUT?
	MOVSS	C		;NYET, TOVARISHCH, NYET...
	JRST	ARGINC		;UVIDIMSYA
SPLWRD:	TXZE	FF,COLONF	;CUANDO?
	HLRZS	C		;LA OTRA, POR FAVOR
	ANDI	C,-1		;DAMELO, 
	JRST	ARGINC		;Y ADIOS.

ENTFVR:	MOVE	C,ENTFLG
	JRST	ARGINC		;NO, GIVE USER THE ENTRY FLAG

UDFFLS:	TXNN	FF,ARG		;ARG GIVEN?
	SETZM	FARG		;NO, ASSUME ZERO
	SKIPE	CEYFLG		;DID SOME SEARCH USE THIS?
	SETOM	SRPF		;YES, MUST REPARSE
	MOVEI	CH,.CHESC	;ASSUME DELIMITER WILL BE ESCAPE
	TXNE	FF,SLSL		;WERE WE RIGHT?
	CALL	SKRCH		;NO, GET USER CHOICE
	MOVEM	CH,DLIMIT	;AND REMEMBER IN EITHER CASE
	MOVE	P1,FARG		;GET USER SELECTED COMMAND MODE
	ANDI	P1,3		;0-3 ONLY
	MOVX	C,CH%USR	;WE WILL BE DIDDLING /W THIS FLAG
	JUMPN	P1,UDFFS1	;IF NON-0, WE WILL NOT HAVE TO CLEAR THE ARRAY
	MOVEI	CH,177		;ARRAY IS 177 LONG...
	ANDCAM	C,CHRTAB(CH)	;CLEAR THE BIT IN EACH ARRAY LOC
	SOJGE	CH,.-1		;..
	MOVEI	P1,1		;AND THE FUNCTION BECOMES 1
UDFFS1:	SKIPE	ABORTF		;^G TYPE INTERRUPT?
	RET			;YES, GIVE UP NOW
	CALL	SKRCH		;NO, GET NEXT CHARACTER.
	CAMN	CH,DLIMIT	;DELIMITER?
	JRST	CFLUSH		;YES, ALL DONE!
	XCT	TDLTAB-1(P1)	;NO, DO THE FUNCTION BASED ON C & CH
	JRST	UDFFS1		;AND GET NEXT CHARACTER

TDLTAB:	IORM	C,CHRTAB(CH)	;1=TURN ON
	ANDCAM	C,CHRTAB(CH)	;2=TURN OFF
	XORM	C,CHRTAB(CH)	;3=COMPLEMENT

UDFFL:	MOVEI	A,1		;ASSUME DEF OF 1
	TXNN	FF,ARG		;DID HE GIVE AN ARG?
	MOVEM	A,FARG		;YES, STUFF AWAY FOR LATER
	SKIPE	CEYFLG		;DID SOME SEARCH USE THIS OPTION?
	SETOM	SRPF		;YES, WE WILL NEED A REPARSE
	CALL	QREGVI		;WHICH QREG?
	MOVE	C,A		;QTST WANTS THE ENTRY IN C
	MOVEM	C,SYL		;WE'LL WANT THIS AGAIN LATER
	CALL	QTST		;IS IT WHAT IT SHOULD BE?
	 JRST	QGETQE		;NO. WE WANT TEXT!
	CALL	QGET2T		;HOW MANY CHARACTERS? INTO P1.
	MOVE	I,SYL		;GET THE ENTRY BACK
	TLZ	I,(-1B14)
	ADD	I,QRBUF
	ADDI	I,4		;POINT AT QREG TEXT
	MOVX	A,CH%USR	;BIT TO TWIDDLE
	SETZ	P2,		;POINTER INTO CHARACTER ARRAY.
MLP1:	SOSGE	P1		;DONE ALL CHARACTERS IN USER QREG YET?
	SKIPA	CH,FARG		;YES, USE DEFAULT
	CALL	GETINC		;NO, READ USER CHOICE
	ANDI	CH,3		;PARSE DOWN TO 2 BITS
	XCT	TWITAB(CH)	;DO THE OPERATION REQUESTED
	CAIGE	P2,177		;AT END OF TABLE?
	AOJA	P2,MLP1		;NO, GET NEXT
	JRST	CFLUSH		;DONE NOW

TWITAB:	ANDCAM	A,CHRTAB(P2)	;0 INDEX, TURN BIT OFF
	CAIL	P2,177		;1 INDEX, DO NOTHING (SAVES 1 INSTRUCTION...)
	IORM	A,CHRTAB(P2)	;2 INDEX, TURN ON BIT
	XORM	A,CHRTAB(P2)	;3 INDEX, COMPLEMENT BIT

;^F returns or modifies the iteration count

FITER:	TXNE	FF,COLONF
	JRST	[TXNN FF,ARG	;IS THERE AN ARG GIVEN?
		 SOSA C,ITERCT	;NO, ASSUME -1
		 ADDB C,ITERCT
		 JRST ARGINC]	;GO RETURN
	TXNN	FF,ARG
	SKIPA	C,ITERCT
	JRST	[MOVEM C,ITERCT
		 JRST CFLUSH]
	JRST	ARGINC

;^N BRANCHES TO THE BEGINNING OR END OF THE CURRENT ITERATION

ALTFLW:	SKIPN	INTDPH
	JRST	TCONQE		;IF NOT IN A LOOP, THIS IS AN ERROR
	TXNE	FF,COLONF	;IS THERE A COLON MODIFIER?
	JRST	ALTFL2		;YES, GO HANDLE
	TXNN	FF,ARG		;IS THERE JUST AN ARG?
	JRST	RSLOP		;NO, JUST ^N - GO TO BEGINNING OF LOOP
	MOVEM	C,ITERCT	;n^N - GO ALTER ITERATION COUNT AND MAYBE LEAVE
	JRST	ALTFLM
ALTFL2:	TXNN	FF,ARG		;ARG GIVEN?
	SOSA	C,ITERCT	;NO, ASSUME -1
	ADDB	C,ITERCT	;YES, ADD IN AND RETURN VALUE
ALTFLM:	JUMPLE	C,INCMA		;IF 0 OR LESS, WE WANT TO LEAVE THIS LOOP
	JRST	RSLOP		;ELSE, WE WANT TO GET TO LOOP'S BEGINNING
;FINISH OUTPUT AND RETURN TO THE TIME-SHARING EXEC.

;SEMICOLON X COMMAND IS LIKE EX COMMAND IN STANDARD TECO. IT DOES
;SEMICOLON U COMMAND, AND RETURNS TO EXEC.

EXCOM:	TXNN FF,PERUS
	JRST	EXCOM1
	SETZM	DEFSPC
	SETZM	DEFNAM
	SETZM	DEFEXT
EXCOM1:	CALL UNLOAD		;DO A ;U COMMAND

;SEMICOLON H COMMAND JUST RETURNS TO EXEC

DECDMP:	CALL SINK		;WAIT FOR COMMAND STRINGS TO BE SAVED
	TXNE FF,COLONF		;IF : FORM, DONT BOTHER TO CLEAR SCREEN
	JRST DOHALT		;JUST FLY AWAY
	CALL CLRSCN		;CLEAR THE SCREEN
	SETOM MESFLG		;ASSUME SCREEN MESSED UP IF RETURNING TO EXEC
	JRST DOHALT		;DO A HALT
;RETURNS THE VALUE OF THE FORM FEED FLAG


FFEED:	TXNE FF,FORM		;IS IT SET?
	JRST NE1INA		;YES, GO RETURN -1
	JRST ZERINA		;NO, GO RETURN 0


;AN ABBREVIATION FOR B,ZEE

HOLE:	CLEARM SARG		;SET SECOND ARGUMENT TO 0.
	TXOA FF,ARG2		;RETURNING 2 ARGS

;.=NUMBER OF CHARACTERS TO THE LEFT OF THE POINTER

PNT:	SKIPA A,PT

;Z=NUMBER OF CHARACTERS IN THE BUFFER

END1:	MOVE A,ZEE
	SUB A,BEG
	JRST ARGINA

;() MAY BE USED TO OVERRIDE LEFT TO RIGHT OPERATOR SCAN

OPEN:	POP P,CH		;[502] GET RETURN ADDRESS FOR LATER JRST
	PUSH P,PREOPV		;[502] SAVE THE OPERAND
	TXNE FF,ARG2		;[502] IS THERE A SECOND ARG?
	PUSH P,SARG		;[502] YES, SAVE IT
	MOVE A,EXECOP		;[502] GET THE OP THAT'S DUE
	SETZM EXECOP		;[502] CLEAR IT, IT'S NOT PENDING ANYMORE
	TXNE FF,ARG2		;[502] DID WE STORE A 2ND VALUE?
	TLO A,(1B17)		;[502] YEAH, RIGHT, FLAG IT
	PUSH P,A		;[502] AND SAVE THIS MESS
	PUSH P,PARCHK		;[502] ADD ON PAREN HEADER
	AOS LEV			;[502] INCREMENT ( LEVEL.
	PUSH P,CH		;[502] PUT THE RETURN ADDRESS BACK
	JRST CFLUSH		;[502] CLEAR ARG2 AND ALL ELSE

CLOSE:	SOSGE LEV		;IS THERE A (?
CLOSX:	ERROR <Unmatched right parenthesis>
	TXZE FF,ARG2		;2 ARGS AT CLOSE PAREN TIME?
	ERROR <Two args given to a close parenthesis>
	POP P,CH		;[502] FETCH OUR RETURN ADDRESS FOR LATER JRST
	POP P,A			;[502] POP OFF THE "IS THIS A PAREN?" WORD
	CAME A,PARCHK		;[502] IS THIS A PAREN?
	JRST CLOSX		;[502] IT LOSES
	POP P,A			;[502] GET OP & FLAGS
	TLZN A,(1B17)		;[502] DID WE SAVE A SECOND ARG?
	JRST CLOSY		;[502] NAY, SKIP THE 2ARG CODE
	TXO FF,ARG2		;[502] YES, MARK ITS COMING BACK
	POP P,SARG		;[502] PUT IT BACK
CLOSY:	POP P,PREOPV		;[502] RETURN PRE-OP VALUE
	MOVEM A,EXECOP		;[502] STORE OP BACK
	JRST (CH)		;[502] AND DONE (ACT LIKE RET)
PARCHK:	707070,,CLOSX		;[502] PAREN HEADER
;N= CAUSES THE VALUE OF N TO BE TYPED OUT.

PRNT:	TXNN FF,COLONF		;DONT LOCK DOWN SCREEN IF COLON FORM
	CALL WINCLS		;ANNOUNCE BEGINNING OF DATA TO BE PRESERVED
	MOVEI A,TYO
	PUSH P,RADIX		;save current radix
	HRRM A,LISTF5		;CONSOLE
	CALL PEEKCH		;PEEK AT NEXT CHARACTER
	 JRST PRNT1		;ISN'T ONE
	CAIE CH,"="		;and if "==" seen,
	JRST PRNT1		;(it wasn't)
	CALL RCH		;then print number in octal
	MOVEI A,8
	MOVEM A,RADIX
PRNT1:	MOVE C,FARG		;GET THE NUMBER
	CALL DPT
	MOVEI A,"."		;get decimal point
	MOVE B,RADIX		;and radix number was printed in
	CAIN B,8		;octal printout ??
	CALL TYO		;yes, so print decimal point
	POP P,RADIX		;restore original base
	TXNN FF,COLONF		;DONT CRLF IF COLON FORM
	CALL CRR		;[502] CRLF AND...
	JRST CFLUSH		;[502] DONE.

;CAUSES COMMAND INTERPRETATION TO STOP UNTIL THE USER TYPES A CHARACTER
;ON THE TELETYPE AND THEN HAS THE ASCII VALUE OF THE CHARACTER TYPED IN.

SPTYI:	CALL TYIX
	MOVEM A,FARG		;REMEMBER CHARACTER
	CALL BCHAR		;BACKUP THE CHARACTER
	JRST ARGINF		;[502] AND RETURN IT PROPER

;WDATE-AND-TIME INPUTS CURRENT DATE AND TIME INTO BUFFER

WDATIM:	HRROI A,DATBUF		;POINT TO DATA BUFFER
	SETO B,			;WE WANT CURRENT DATE AND TIME
	SETZ C,			;NO SPECIAL FLAGS
	ODTIM%			;GET THE DATE AND TIME
	MOVE A,[POINT 7,DATBUF]	;GET POINTER TO THE STRING
	CALL INSRTZ		;[502] INSERT IT...
	JRST CFLUSH		;[502] AND RETURN

; ^H HAS THE VARIOUS TIMES

GTIME:	TXNN	FF,ARG
	JRST	GTMID
	JUMPLE	C,GTMID
	CAIE	C,1
	JRST	GRUNTM
	GTAD%
	JRST	ARGINA
GRUNTM:	MOVEM	C,SYL
	MOVX	A,.FHSLF
	RUNTM%
	MOVE	B,SYL
	CAIE	B,2
	JRST	ARGINC
	JRST	ARGINA
GTMID:	SETO B,			;SAY WE WANT CURRENT TIME
	SETZ D,			;NO SPECIAL FEATURES
	ODCNV%
	HRRZ	C,D
	JRST ARGINC		;AND RETURN


;HAS THE VALUE OF THE NEXT CHARACTER IN THE COMMAND STRING.

CNTRUP:	CALL RCH		;^^ HAS VALUE OF CHAR FOLLOWING IT
	MOVE C,CH
	JRST ARGINC

;^X - SET SEARCH SWITCH

;INITIALED TO 0, 1 MEANS EXACT MATCH REWUIRED ON SEARCHES, 0
;MEANS LOWER AND UPPER CASE LETTERS MATCH TO EITHER LOWER OR UPPER

SSERCH:	MOVE A,EXACTF		;GET PRESENT VALUE
	TXNN FF,ARG		;ARG GIVEN?
	JRST ARGINA		;NO, RETURN PRESENT VALUE
	MOVEM C,EXACTF		;SET NEW VALUE
	SETOM SRPF		;REMEMBER TO REPARSE SEARCH
	JRST CFLUSH

;wflaguppers$ - flag upper case letters

FLAGU:	SETOM FLAGF		;SAY FLAGGING
	MOVEI A,.PRIIN
	RFMOD%
	TXO B,TT%UOC		;FLAG UPPER CASE CHARACTERS
	TXZ B,TT%LCA		;SYSTEM PREVENTS FLAGGING UNLESS THIS BIT OFF
	STPAR%			;TELL SYSTEM
	JRST CFLUSH		;[502] DONE

;wnoflag$ - flag nothing

NOFLAG:	SETZM FLAGF
	MOVEI A,.PRIIN
	RFMOD%
	TXZ B,TT%UOC		;CLEAR FLAG BIT
	STPAR%
	JRST CFLUSH		;[502] DONE

;wnoshift$ - don't change case of input

NSHIFT:	MOVEI A,.PRIIN
	RFMOD%
	TXZ B,TT%LIC		;CLEAR "RAISE" BIT
	STPAR%
	JRST CFLUSH		;[502] DONE

;wraise$ - raise typed in lower case letters

TERRAS:	MOVEI A,.PRIIN
	RFMOD%
	TXO B,TT%LIC		;SET "RAISE" BIT
	STPAR%
	JRST CFLUSH		;[502] DONE

;WSAVLEN$ - SET OR GET NUMBER OF CHARACTERS TO INPUT BETWEEEN SAVES.

BETSAV:	MOVE A,BAKLEN		;GET CURRENT SETTING
	TXNN FF,ARG		;DID USER SUPPLY ARGUMENT?
	JRST ARGINA		;NO, SO RETURN ONE.
	CAIL C,1
	CAILE C,MAXBAK
	ERROR <Arg must be positive and less than or equal to MAXBAK>
	MOVEM C,BAKLEN		;SET NEW VALUE
	JRST CFLUSH		;[502] DONE

;WWIDTH$ - SET OR GET TERMINAL WIDTH

WTHSET:	MOVE A,SWIDTH		;GET CURRENT SETTING
	TXNN FF,ARG		;DID YOU SUPPLY ARG?
	JRST ARGINA		;NO, SO RETURN CURRENT VALUE.
	CAIGE C,0		;MAKE SURE WIDTH IS LEGAL.
	ERROR <Negative width setting not allowed>
	MOVE A,C
	PUSH P,C
	CALL SETWID		;GO SET NEW WIDTH
	JERROR <Couldn't set up terminal width>
	POP P,SWIDTH		;SET UP NEW WIDTH
	JRST CFLUSH		;[502] DONE

;ROUTINE TO SET TERMINAL WIDTH
;ACCEPTS:	A/	NEW WIDTH
;RETURNS:	+1:	FAILED
;		+2:	WON

SETWID:	MOVE C,A
	MOVEI A,.PRIOU		;PRIMARY OUTPUT
	MOVEI B,.MOSLW		;SET LINE WIDTH
	MTOPR%			;TRY TO DO IT
	 ERJMP CPOPJ		;FAILED
	JRST	CPOPJ1		;SUCCEEDED

;GET WIDTH INTO A, SKIP IFF SUCCESS

GETWID:	MOVEI A,.PRIOU
	MOVEI B,.MORLW
	MTOPR%
	 ERJMP CPOPJ
	MOVE A,C
	JRST CPOPJ1

;GET PAGE (SCREEN) SIZE INTO A, SKIPS IFF SUCCESSFUL

GETLEN:	MOVEI A,.PRIOU
	MOVEI B,.MORLL
	MTOPR%
	 ERJMP CPOPJ
	MOVE A,C
	JRST	CPOPJ1

;WWINDOW$ - SET OR RETURN NUMBER OF SCREEN LINES USED FOR WINDOW

WINSET:	MOVE A,SLENTH		;GET CURRENT SIZE OF WINDOW IN LINES
	TXNN FF,ARG		;ARGUMENT TO COMMAND?
	JRST ARGINA		;NO, SO RETURN ONE
	MOVE B,SSIZE		;FOR SCREENS, SCREEN SIZE IS MAXIMUM
	SKIPN SCRNF
	MOVEI B,MAXLEN		;FOR NONSCREENS, INTERNAL BUFFER SIZE IS LIMIT
	CAIL C,0
	CAMLE C,B		;MAKE SURE ARG IS REASONABLE
	ERROR <Invalid window size>
WINSOK:	MOVEM C,SLENTH		;SET NUMBER OF LINES TO USE
	JRST CFLUSH		;[502] DONE

 OPTION ENC,<

;WENCRYPT - SET/CLEAR ENCRYPTION FLAG
COMMENT ~
	If this code is enabled, and the command nWENCRYPT$ is given, where
n is non-zero, the commands that read in files (;Y and related) will prompt
for a "password". This is a decryption keyword; the file is assumed to be
encoded. If it is not, type Carriage Return, and no decryption will be
applied. If the keyword is wrong, you will see the appearance of quantities
of trash in the buffer.
	Also, output commands (;X and related) will ask for an encryption
keyword; as before, if just a Carriage Return is typed, no encryption will
be applied. For paranoia's sake, this is requested twice - the typed strings
must match. Case of letters does not matter.
	If you interrupt TV during reads and writes when encryption is on,
the results are likely to be indeterminate - mostly, you will lose the
buffer.
	0Wencrypt$ turns the encrypt functions off. Without an arg,
Wencrypt$ returns the value of the current flag. ~

ENCPT:	MOVE	A,ENCFLG
	TXNN	FF,ARG		;WANT VALUE OR SET VALUE?
	JRST	ARGINA		;RETURN
	MOVEM	C,ENCFLG
	JRST	CFLUSH
>

;WSILENCE - SET OR CLEAR ALLOWING "END OF..." MESSAGE AFTER ;Efile$

SETSHH:	MOVE	A,SILFLG
	TXNN	FF,ARG		;WANT VALUE OR SET VALUE?
	JRST	ARGINA		;RETURN
	MOVEM	C,SILFLG
	JRST	CFLUSH

;WPERUSE$ - GET OR SET PERUSE MODE BIT
WPERUS:	TXNN	FF,ARG
	JRST	WPERU1
	TXNE	C,1
	TXOA	FF,PERUS
	TXZ	FF,PERUS
	JRST	CFLUSH
WPERU1:	TXNN	FF,PERUS
	JRST	ZERINA
	MOVEI	C,1
	JRST	ARGINC

;WSCREENSIZE - SET OR RETURN NUMBER OF LINES EXISTING ON ENTIRE SCREEN.

SCNSET:	MOVE A,SSIZE		;GET CURRENT SETTING
	TXNN FF,ARG		;DID USER SUPPLY ARG TO COMMAND?
	JRST ARGINA		;NO, SO RETURN CURRENT SETTING.
	CAIL C,0
	CAILE C,MAXLEN		;MAKE SURE NEW SETTING IS REASONABLE.
	ERROR <Illegal screen size setting>
	MOVEM C,SSIZE		;SET NEW SCREEN SIZE
	CALL WINSTN		;[502] SET UP STANDARD WINDOW SIZE
	JRST CFLUSH		;[502] DONE

;WEDITBASIC$ - DON'T FILTER LINE NUMBERS WHEN READING IN FILES, BECAUSE
;THE FILES NEED THEM, LIKE FOR INSTANCE THEY ARE BASIC PROGRAMS.

EBASIC:	SETOM BASICF	;SET THE FLAG TO REMEMBER NOT TO FILTER LINE NUMBERS.
	JRST CFLUSH		;[502] DONE

;WEDITREGULAR$ - FILTER LINE NUMBERS AS USUAL.

ERGLR:	SETZM BASICF		;SAY TO FILTER THE LINE NUMBERS.
	JRST CFLUSH		;[502] DONE
;HAS THE VALUE OF THE NUMBER REPRESENTED BY THE DIGITS (OR MINUS SIGN)
;FOLLOWING THE POINTER IN THE BUFFER.  THE SCAN TERMINATES ON ANY OTHER
;CHARACTER.  THE POINTER IS MOVED OVER THE NUMBER FOUND (IF ANY).

BAKSL:	TXNE FF,ARG		;WHICH KIND OF BACKSLASH?
	JRST BAKSL1		;ARG TO MEMORY
	MOVEI A,^D10		;SPECIFY DECIMAL
PKNM1:	CALL PKNUM		;DO THE WORK
	JRST ARGINA		;PROCEED WITH REST OF COMMAND

;ROUTINE TO PICK UP NUMBER FROM BUFFER IN BASE SPECIFIED IN A, LEAVING POINTER
;AFTER THE NUMBER AND NUMBER IN A

PKNUM:	STKVAR <NEGF,PBASE>
	MOVEM A,PBASE		;REMEMBER BASE
	SETZM SYL		;START WITH NO NUMBER
	MOVE I,PT		;MEMORY TO ARGINA
	CAML I,ZEE		;ANY CHARS?
	JRST BAKSL3		;NO, SO CAN'T POSSIBLY BE A "-"
	CALL GETINC		;SOME CHARS, SEE IF "-"
	SETZM NEGF		;NO MINUS SEEN YET
	CAIE CH,"-"		;IS IT?
	JRST BAKSL5		;NO
	SETOM NEGF		;YES, REMEMBER
BAKSLA:	CAML I,ZEE		;OVERDID IT ?
	JRST BAKSL3		;YES. EXIT
	CALL GETINC		;NO. GET A CHAR
BAKSL5:	MOVE A,PBASE		;GET BASE
	CAIGE CH,"0"(A)		;DIGIT IN CORRECT BASE?
	CAIGE CH,"0"		;DIGIT?
	SOJA I,BAKSL2		;NOT A DIGIT. BACKUP AND LEAVE LOOP
	SUBI CH,"0"		;CONVERT TO NUMBER
	EXCH CH,SYL
	IMUL CH,PBASE
	ADDM CH,SYL		;SYL:= 10.*SYL+CH
	JRST BAKSLA		;LOOP

BAKSL3:	MOVE I,ZEE		;HERE ON OVERFLOW
BAKSL2:	SKIPE NEGF		;MINUS SIGN SEEN?
	MOVNS SYL		;YES. NEGATE
	MOVEM I,PT		;MOVE POINTER PAST #
	MOVE A,SYL		;RETURN NUMBER IN A
	RET

;NA (WHERE N IS A NUMERIC ARGUMENT) = VALUE IN 7-BIT ASCII OF THE
;CHARACTER TO THE RIGHT OF THE POINTER.

ACMD:	TXNN FF,ARG		;DOES AN ARGUMENT PRECEED A?
	JRST APPEND		;NO. THIS IN AN APPEND COMMAND.
	MOVE I,PT		;YES.
PICK1:	CAML I,ZEE		;MAKE SURE THERE'S A CHARACTER AFTER POINTER
	JRST PICKQE
	CALL GET		;CH:=CHARACTER TO THE RIGHT OF PT.
	MOVE C,CH		;RETURN CH AS VALUE.
	JRST ARGINC
PICKQE:	TXNN FF,COLONF		;DID HE EXPECT THE ERROR?
	ERROR <Pointer is at end of buffer>
	JRST NE1INA		;YES, RETURN -1

PICKUP:	MOVE I,PT		; ;P COMMAND, PICKUP CODE AND INC PNTR
	CAMGE I,ZEE
	AOS PT			;DON'T ALLOW POINTER OUT OF BOUNDS
	JRST PICK1
;	;N picks up a positive number from the data (base 10)
;	n;N picks it up in base n.  PT is left at first non-number.

PIKNUM:	TXNN FF,ARG
	MOVEI C,12
	MOVE A,C		;GET BASE
	JRST PKNM1		;DO THE WORK
;NUI PUTS THE NUMERIC VALUE N IN Q-REGISTER I.

USE:	CALL QREGVI		;YES. CH:=Q-REGISTER INDEX.
	EXCH C,QTAB-"0"(CH)	;STORE NEW, FETCH OLD
	TXNE FF,COLONF		;COLON MODIFIED?
	JRST ARGINC		;YES, GO RETURN OLD VALUE
	JRST CFLUSH		;NO, DON'T.

;QI HAS THE VALUE OF THE LATEST QUANTITY PUT INTO Q-REGISTER I.

QREG:	CALL QREGVI
	JRST ARGINA

; n;&I RETURNS THE VALUE IN I ANDED WITH n, AND THEN TURNS OFF THE BITS IN QI
;  SELECTED BY n.

TXZNC:	CALL QREGVI		;GET QREG AND VALUE
	MOVE B,FARG		;AND GET ARG PASSED IN
	AND A,B			;RETURN QREG CONTENTS AND'D WITH ARG
	ANDCAM B,QTAB-"0"(CH)	;BUT TURN OFF THOSE BITS IN THE QREG
	JRST ARGINA		;GOOD FOR ONCE-ONLY TESTS

;ROUTINE TO RETURN Q-REGISTER INDEX IN CH AND CONTENT IN A.
;CALL CALL QREGVI
;	RETURN
;ASSUMES COMCNT,CPTR AND COMAX ARE SET UP.
;IF NEXT CHARACTER IN COMMAND STRING
;IS NOT A LETTER OR A DIGIT, DOES NOT RETURN.
;FROM USEA,PCNT,OPENB+1,MAC,QGET

QREGVI:	CALL RCH		;CH:=NEXT COMMAND STRING CHARACTER.
	CAIL CH,140		;LC LETTER?
	TRZ CH,40		;MAKE UC
	CAIL CH,"0"		;LETTER OR DIGIT?
	CAILE CH,"Z"
QREGQE:	ERROR <Illegal Q-reg name>
	CAILE CH,"9"
	CAIL CH,"A"		;CHECK FOR LONELY 7 BETWEEN DIGITS AND LETTERS
	CAIA
	JRST QREGQE
QREGVC:	CAIL CH,1+"9"		;YES. DIGIT?
	SUBI CH,"A"-"9"-1	;NO. TRANSLATE LETTERS DOWN BY NUMBER OF
				;CHARACTERS BETWEEN 9 AND A.
	MOVE A,QTAB-"0"(CH)	;A:=CONTENTS OF Q-REGISTER.
	RET

;%I ADDS 1 TO THE QUANTITY IN Q-REGISTER IN AND STANDS FOR THE
;	NEW VALUE

PCNT:	CALL QREGVI		;CH:=Q-REGISTER INDEX.
	TXNE FF,COLONF		;DECR OR INCR?
	SOSA C,QTAB-"0"(CH)	;DECREMENT Q-REG.
	AOS C,QTAB-"0"(CH)	;INCREMENT Q-REG.
	JRST ARGINC		;RETURN NEW VALUE.
;m,nXi MOVES A PORTION OF THE BUFFER INTO Q-REGISTER i.
;	IT SETS Q-REGISTER IN TO A DUPLICATE OF THE (M+1)TH
;	THROUGH NTH CHARACTERS IN THE BUFFER.
;nXi INTO Q-REGISTER i IS COPIED THE STRING OF CHARACTERS STARTING
;	IMMEDIATELY TO THE RIGHT OF THE POINTER AND PROCEEDING THROUGH
;	THE NTH LINE FEED.

X:	STKVAR <XARG1,XARG2,OLDEBF,SAVEBF,QNAM>
	SETZM XARG1		;CLEAR SO QGC DOESN'T TRIP OVER TRASH
	SETZM QNAM
	SOSG GCCNT		;TIME FOR GC?
	CALL QGC		;YES
	CALL GETARG		;p1:=FIRST STRING ARGUMENT ADDRESS
				;c:=SECOND STRING ARGUMENT ADDRESS.
	MOVEM P1,XARG1
	MOVEM C,XARG2
	MOVE A,C
	CALL MOVHOL		;GET HOLE OUT OF WAY OF STUFF BEING 
				; MOVED INTO Q-REG
;**NOTE: PUTTING HOLE AFTER TEXT AS OPPOSED TO BEFORE IT IS IMPORTANT
;FOR EFFICIENCY, AS SUBSEQUENT DELETION PUTS HOLE THERE.

	MOVE A,EQRBUF
	MOVEM A,OLDEBF		;SAVE OLD BUFFER ADDRESS
X0:	MOVE P1,XARG1
	MOVE C,XARG2
	SUBM C,P1		;COMPUTE LENGTH OF STRING
	ADDI P1,4		;PLUS 4 OVERHEAD CHARS
	MOVE C,EQRBUF		;COMPUTE NEW END OF QREG BUF
	ADD C,P1
	MOVE A,C
	ADDI A,^D35+5		;LEAVE ROOM FOR SEARCH ROUTINE TO USE
	CAML A,BEG		;OVERLAPS MAIN BUFFER?
	JRST [	MOVE A,EQRBUF
		MOVEM A,SAVEBF	;SAVE PRESENT QREG FREE PTR
		CALL QGC	;YES, DO GC
		MOVE C,SAVEBF
		CAMN C,EQRBUF	;DID GC DO ANYTHING?
		ERROR <Qreg string storage full>
		JRST X0]	;TRY AGAIN
	MOVE OU,EQRBUF		;GET ADDRESS TO PUT STRING
	MOVEM OU,OLDEBF		;SAVE IT FOR QREG
	MOVEM C,EQRBUF		;UPDATE END OF AREA
	MOVEI CH,141		;FIRST CHARACTER OF BUFFER := 141
	CALL PUT
	AOS OU
	MOVE I,[POINT 7,P1,14]	;TO GET LAST 3 CHARS IN p1
	MOVEI P2,3
X3:	ILDB CH,I		;GET PART OF COUNT
	CALL PUT		;WRITE ONTO STORAGE STRING
	AOJ OU,
	SOJG P2,X3		;DO FOR THREE CHARS = 21 BITS
	MOVE OU,TT		;SAVE BYTE POINTER FROM LAST PUT
	SUBI P1,4
	MOVE I,XARG1		;RECOVER SOURCE PTR
	CALL GETX		;CONSTRUCT BYTE PTR TO SOURCE
	CALL DBP		;BACKUP TO BEGINNING
	MOVE I,TT		;SAVE IT
	CALL MVSTR		;MOVE STRING FROM I TO OU
	MOVE P1,XARG1
	MOVE C,XARG2		;RECOVER ARGS
	CALL QREGVI		;GET PTR TO Q-REG AND MAKE SURE NAME IS LEGAL
	MOVEM CH,QNAM		;SAVE Q-REG NAME
	TXNN FF,SLSL		;IF ATSIGN SEEN, DONT REMOVE TEXT!
	CALL KLBUF1		;NORMAL X, JUST REMOVE TEXT
	MOVE CH,QNAM
	MOVE C,OLDEBF
	SUB C,QRBUF		;ADDRESS RELATIVE TO C(QRBUF)
	TLO C,400000
	MOVEM C,QTAB-"0"(CH)	;[502] MAKE QTAB ENTRY
	JRST CFLUSH		;[502] DONE
;GI THE TEXT IN Q-REGISTER IN IS INSERTED INTO THE BUFFER AT THE
;	CURRENT LOCATION OF THE POINTER.  THE POINTER IS THEN PUT JUST
;	TO THE RIGHT OF THE INSERTION.  THE Q-REGISTER IS NOT CHANGED.

QGET:	CALL QREGVI		;A:=QTAB ENTRY, CH:=Q-REG INDEX
	MOVE C,A
	PUSH P,CH		;SAVE QREG POINTER
	CALL QTST		;IS THERE TEXT THERE?
	JRST	[TXZN FF,COLONF	;NO, DO WE CARE?
		JRST QGETQE	;YES, GO YITCH
		POP P,CH	;NO, BALANCE STACK
		JRST BAKSL1]	;AND GO INSERT IT AS A DIGIT STRING
	CALL QGET2T		;GET NUMBER OF CHARS (1ST PART DONE BY QTST)
	POP P,C			;Q-REG INDEX
	JUMPLE P1,CFLUSH	;QUIT IMMEDIATELY IF NULL STRING
	MOVE I,QTAB-"0"(C)
	TLZ I,(-1B14)
	ADD I,QRBUF
	ADDI I,3
	MOVE A,I		;PUT CHARACTER ADDRESS INTO A
	CALL ADDPTR		;CHANGE ADDRESS TO POINTER
	MOVE B,P1		;STRING LENGTH INTO B
	CALL INSRT0		;INSERT Q-REG INTO BUFFER
	JRST CFLUSH		;DONE

; ;T - TYPE CONTENTS OF Q REG

TPREG:	CALL WINCLS		;START PRESERVED OUTPUT
	TXNN FF,ARG
	JRST COMM		;TYPE LITERAL STRING IF NO ARG
				;(THIS GOES AWAY SOMEDAY. USE ^A.)
	MOVE C,FARG		;[502] C GETS LOST BY SUBROUTINES
	CALL QGET2
TPR1:	JUMPE P1,CFLUSH
	CALL GETINC
	MOVE A,CH
	CALL TYO
	SKIPE ABORTF		;ABORTING?
	JRST TYOQT		;YES
	SOJA P1,TPR1


QTST:	TLZN	C,377770	;TEST FOR TEXT IN QREG
	TLZN	C,400000
	RET			;NONSKIP IF NO TEXT
	MOVE	I,QRBUF
	ADD	I,C
	CALL	GETINC		;GET FIRST CHAR
	CAIN	CH,141		;141 MEANS THIS IS A QREG
	AOS	(P)
	RET			;DONE W/ TEST

QGET2:	TLZN C,377770		;DOES Q-REG CONTAIN TEXT?
	TLZN C,400000
	JRST QGETQE
	ADD C,QRBUF		;YES
	MOVE I,C		;I:=Q-REG BUFFER ADDRESS
	CALL GETINC		;IS FIRST CHARACTER IN BUFFER 141?
	CAIE CH,141
QGETQE:	ERROR <Qreg does not contain text>
QGET2T:	CALL GETINC		;p1:=LENGTH OF STRING
	MOVEM CH,P1
	CALL GETINC
	LSH P1,7		;RECONSTRUCT CHAR COUNT,
	IOR P1,CH		;MOST SIGNIFICANT CHARS FIRST
	CALL GETINC
	LSH P1,7
	IOR P1,CH
	SUBI P1,4
	RET
;]I POPS Q-REGISTER IN OFF THE Q-REGISTER PUSHDOWN LIST.
;	THE Q-REGISTER PUSHDOWN LIST IS CLEARED EACH TIME $$ IS TYPED.

CLOSEB:	SKIPA P1,[POP A,]

;[I PUSHES Q-REGISTER IN ONTO THE Q-REGISTER PUSHDOWN LIST.

OPENB:	MOVSI P1,(<PUSH A,>)
	CALL QREGVI
	HRRI P1,QTAB-"0"(CH)	;p1:=Q-REGISTER INDEX.
	MOVE A,PF		;GET STACK POINTER
	XCT P1			;PUSH OR POP Q-REGISTER.
	MOVEM A,PF		;SAVE NEW POINTER
	TXNE FF,ARG		;IS THERE AN ARGUMENT?
	RET			;[502] YES. LEAVE THINGS ALONE THIS WAY
	JRST CFLUSH		;NO. CLEAR FLAGS.

SOPENB:	MOVE	B,PF		;GET STACK
	PUSH	B,C		;PUSH VALUE IN C
	MOVEM	B,PF		;AND DONE
	JRST	CFLUSH		;..

SCLOSB:	MOVE	B,PF		;GET STACK
	POP	B,C		;RETURN A VALUE
	MOVEM	B,PF		;KEEP STACK POINTER
	JRST	ARGINC		;GO RETURN C
;UNLOAD (;U, ;D) COMMANDS

;**; At DNLOAD:, change label				SM	4-Mar-82
DNLD:	SKIPE WRITEF		;MAKE SURE WE'RE AT BEGINNING OF OUTPUT FILE
	ERROR <;Invalid ;D command - output file already partially written>
	SETOM DUNFLG		;SAY ;D MODE
	CALL UNLOAX		;[502] DO A PROPER UNLOAD
	JRST CFLUSH		;[502] DONE
UNLD:	CALL UNLOAD		;[502] DO THE UNLOAD
	JRST CFLUSH		;[502] AND RETURN PROPERLY

UNLOAD:	SETZM DUNFLG		;SAY ;U MODE
;**; At UNLOAD: +1L, Added one label			SM	4-Mar-82
UNLOAX:	CALL SKPWRT		;FILE OPEN?
	 CALL UNLD1		;NO, GO OPEN ONE
	MOVE A,OUTJFN		;GET HANDLE ON OUTPUT DEVICE
	SKIPE DUNFLG		;PUT IN HEADING IF REQUESTED
	CALL HEDING		;PUT HEADING IN OUTPUT FILE
	MOVSI C,2000		;A LARGE NUMBER OF PAGES
	TXO FF,ARG		;MAKE BELIEVE IT WAS TYPED IN
	CALL PUNCH		;PUNCH THOSE PAGES
	CALLRE CLOSEF		;CLOSE AND RENAME FILES


UNLD1:	HRROI B,[ASCIZ /Output file: /]
	MOVX A,GJ%FOU+GJ%MSG	;specify output file spec
	CALL GETCFM		;GET FILE NAME FROM USER AND ASSIGN JFN
	TXO FF,DUMPF		;REMEMBER DOING LARGE DUMP
	JRST OPNOUT		;OPEN FILE AND RETURN

;GET FILESPEC AND CONFIRMATION.  CALL WITH GTJFN BITS IN A, PROMPT
;POINTER IN B.  RETURNS WITH JFN IN A.

GETCFM:	STKVAR <<QUAG,2>,<ARGS1,2>,NAMPTX>
	DMOVEM A,ARGS1		;SAVE GTJFN BITS
GETCF1:	DMOVE A,ARGS1
	CALL GSCRIP		;DO THE GTJFN
	DMOVEM A,QUAG		;SUCCESS, SAVE GTJFN DATA
	TXNE FF,RSCANF		;RESCANNING?
	JRST GETCF2		;YES, SO DON'T WAIT FOR CONFIRMATION
	CALL CONFRM		;confirm
	 JRST GETCFB		;BAD CONFIRMATION
GETCF2:	MOVE C,[POINT 7,NAMBFR]	;GET POINTER TO BEGINNING OF NAME AREA
	MOVEM C,NAMPTX
NAMSTR:	ILDB A,NAMPTX		;PICK UP CHARACTER FROM SCRIPT
	JUMPE A,NAMS1		;LEAVE LOOP WHEN NULL HIT
	CALL BCHAR		;PUT CHARACTER IN LOG FILE
	JRST NAMSTR		;LOOP FOR REST OF NAME.
NAMS1:	MOVEI A,15
	CALL BCHAR		;FINISH WITH CRLF
	MOVEI A,12
	CALL BCHAR
MRETYP:	TXNE FF,RSCANF
	JRST MRTYP1		;ALWAYS RETYPE NAME IF RESCANNING
	SKIPE TERIO
	JRST MR1		;ON TERMINAL IO AND NOT RESCANNING,...
				; DON'T RETYPE NAME.
MRTYP1:	MOVE B,GTJJFN		;PUT RECEIVED JFN IN 2
	MOVEI A,.PRIOU		;AND DIRECT OUTPUT TO TTY
	SETZ C,			;STANDARD PRINTOUT
	JFNS%			;PRINT FILE NAME
	CALL CRR
MR1:	MOVE A,GTJJFN		;PUT JFN BACK IN 1
	RET			;SUCCESS RETURN

GETCFB:	 LERROR <Carriage return required after filespec
>
	JRST GETCF1

;ROUTINE WHICH SAVES FILENAME DEFAULT STRING.  GIVE IT JFN IN A.
;NOTE THAT IF ONLY THE JFN BLOCK DEFAULTS ARE DEPENDED ON, THEN COMND
;WILL JUST REPROMPT FOR FILESPEC IF YOU TRY TO DEFAULT IT BY TYPING
;<CR>.

SETFDS:	MOVE B,A		;JFN IN B
	HRROI A,DEFSPC		;POINT TO DEFAULT SPEC AREA
	MOVX C,1B8+1B11+JS%PAF	;JUST NAME, EXTENSION, PUNCTUATE ALL FIELDS
	JFNS%			;STORE THE STRING
	RET

;ROUTINE TO DO LONG FORM GTJFN AND STORE TYPED NAME IN LOG FILE.
;CALL ROUTINE WITH GTJFN BITS IN A
;give it pointer to prompt string in b.
;THE JFN IS RETURNED IN "A".  THE ROUTINE RETURNS WHEN THE GTJFN SUCCEEDS

GSCRIP:	STKVAR <PROMPT,FAILF>
	SETOM FAILF		;SAY WE HAVEN'T HAD A FAILURE YET
	MOVEM A,CJFNBK+.GJGEN	;remember GTJFN code
	MOVEM B,PROMPT		;remember pointer to prompt
	MOVSI B,774000		;MASK FOR SEEING IF STRINGS EXIST
	HRROI A,DEFNAM		;GET POINTER TO DEFAULT NAME
	TDNE B,DEFNAM		;IS THERE ONE?
	MOVEM A,CJFNBK+.GJNAM	;YES, USE IT
	HRROI A,DEFEXT		;SAME SCHTUCK WITH EXTENSION
	TDNE B,DEFEXT
	MOVEM A,CJFNBK+.GJEXT
GSR2:	MOVE A,PROMPT		;GET POINTER TO PROMPT STRING
	TXNN FF,RSCANF		;ARE WE RESCANNING??
	JRST GSR3		;NO
	PSOUT%			;YES, PRINT THE PROMPT
	JRST GSR1
GSR3:	CALL READY		;type prompt
	MOVX A,CM%DPP		;FIRST ASSUME THERE'S A DEFAULT STRING
	IORM A,FILCBK+.CMFNP	;TURN ON DEFAULT BIT
	MOVSI B,774000		;MASK FOR FIRST CHARACTER OF DEFAULT
	TDNN B,DEFSPC		;IS THERE A DEFAULT?
	ANDCAM A,FILCBK+.CMFNP	;NO, TURN OFF DEFAULT BIT
GSR4:	MOVEI A,FILCBK		;POINT TO FILE FUNCTION BLOCK
	CALL READFL		;read filespec
GSR1:	SKIPN GTJERR		;WAS THERE AN ERROR?
	RET			;NO, JUST RETURN
	AOSE FAILF		;FIRST FAILURE?
	JRST GSR5		;NO, SO DON'T TRY AGAIN
	SETZM CJFNBK+.GJNAM	;YES, SEE IF REMOVING DEFAULTS HELP
	SETZM CJFNBK+.GJEXT
	JRST GSR4		;GO BACK AND REINTERPRET INPUT
GSR5:	TXZ FF,RSCANF		;IF RESCANNED NAME FAILS, MAKE USER TYPE IT
	MOVE A,GTJERR		;GET REASON FOR FAILURE
	MOVEM A,LSTERR		;SAVE FOR ERROR ROUTINE
	LJERR <Can't access file>
	JRST GSR2		;GO BACK AND TRY AGAIN

;ROUTINE TO READ FILESPEC USING COMND JSYS.
;PASS IT THE COMND FUNCTION BLOCK ADDRESS IN A.

READFL:	SETZM GTJERR		;FIRST ASSUME NO GTJFN ERROR
	CALL RFIELD		;READ FILESPEC
	 HRRZM B,GTJERR		;SAVE ERROR CODE
	MOVEM B,GTJJFN		;REMEMBER JFN
	MOVE A,GTJJFN		;GET THE JFN
	SKIPN GTJERR		;DO WE HAVE ONE?
	CALL STORNM		;YES, REMEMBER ITS NAME
	RET

;ROUTINE TO DO GTJFN AND STORE THE FILENAME SO THAT WFILENAME WILL
;BE ABLE TO GET IT.  ASSUMES THE AC'S ARE ALREADY SET UP FOR GTJFN.
;IT RETURNS +1 ON FAILURE, +2 SUCCESS, GTJFN DATA IN A AND B.

DOGTJ:	STKVAR <<GTJDAT,2>>
	GTJFN%			;DO THE GTJFN
	 RET			;RETURN IF FAILURE
	DMOVEM A,GTJDAT		;REMEMBER GTJFN DATA
	CALL STORNM		;store file name
	DMOVE A,GTJDAT		;return gtjfn data in a and b
	JRST	CPOPJ1

;routine to store filename string in nambfr.  pass it the jfn in a.

STORNM:	MOVE B,A		;JFN IN B
STORN1:	HRROI A,NAMBFR		;PREPARE TO STORE NAME
	MOVX C,1B2+1B5+1B8+1B11+1B14+JS%PAF ;WE WANT ALL FIELDS PUNCTUATED
	JFNS%			;STORE THE FILESPEC FOR WFILENAME
	RET
;LOAD ENTIRE FILE COMMAND - ;Y

YLOAD:	SETZM SYL
	TXZE FF,COLONF
	SETOM SYL		;REMEMBER IF COLON FLAG ON
	TXNN FF,UREAD		;FILE OPEN?
	CALL YLD1		;NO, GO OPEN ONE
	CALL SINLDS
	SKIPE SYL		;DOES HE CARE HOW MANY CHARS..?
	JRST CFLUSH		;NO
	MOVE C,ZEE		;NUMBER OF CHARS NOW IN BUFFER
	SUB C,BEG
	MOVEI A,TYO		;SAY WHERE TO OUTPUT CHARS
	CALL DPT0		;DECIMAL PRINT FROM c
	PSTR < chars
>
	JRST CFLUSH

YLD1:	HRROI B,[ASCIZ /Input file: /]
	MOVX A,GJ%OLD		;input file
	CALL GETCFM		;GET FILE NAME
	MOVE B,TYIJFN		;SEE WHERE INPUT CAME FROM
	CAIN B,.PRIIN		;DON'T CLEAR RESCAN FLAG YET IF NOT PRIIN
	TXZ FF,RSCANF		;NOTE THAT WE'RE NOT RESCANNING ANYMORE.
	JRST OPNIN		;GO OPEN THE FILE.
;FAST LOAD OF FILE USING SIN

SINLDS:	SETZM YAMODE		;DOING ;Y NOT Y OR A
SINLD:	STKVAR <LCS,FSPC>
SINLD2:	TXZ FF,FORM
	MOVE A,ZEE
	CALL MOVHOL		;PUT HOLE AT END OF BUFFER
	CALL FILFRE		;GET NUMBER OF CHARACTERS WE CAN READ IN
	MOVEM A,FSPC
	MOVE A,INJFN
	MOVE OU,ZEE		;PUT FILE AT END OF BFR
	CALL PUT		;COMPUTE BYTE PTR
	CALL DBP		;BACKUP 1
	MOVE B,TT		;SET IT FOR SIN
 OPTION ENC,<			;FOR CODING
	movem	b,cdestr	;start decoding here
>
	SKIPG C,FSPC		;GET NUMBER OF CHARACTERS WE CAN READ
	JRST [	SKIPN YAMODE	;NO ROOM? IF NOT Y OR A...
		ERROR <File too large for buffer> ;COMPLAIN
		JRST CFLUSH]	;ELSE JUST RETURN
	MOVN C,C		;MAKE NEG FOR SIN
	PUSH P,C		;AND SAVE THAT WAY
	SKIPN YAMODE		;Y OR A MODE?
	JRST SUCKSI		;NO, ITS ;Y AND ;Y DOESNT *DO* <FF>
	MOVN C,C		;Y OR A - MAKE IT POSITIVE AGAIN,
	MOVEI D,"L"-100		;AND STOP ON <FF>
SUCKSI:	SIN%			;DO ALL OF FILE OR AS MUCH AS FITS
SUCKIN:	SKIPE YAMODE		;DID WE NEGATE BEFORE?
	MOVN C,C		;YES, ACCOUNT FOR THAT
	POP P,TT
	SUBM C,TT		;COMPUTE AMOUNT DONE
 OPTION ENC,<			;FOR CODING ALGORITHM
	movmm	tt,cdecnt	;number bytes to read
>
	ADDM TT,ZEE		;UPDATE Z
	ADDM TT,HOLBEG		;NOTE THAT HOLE STARTS FURTHER TO THE RIGHT
 OPTION ENC,<
	skipe	encflg
	skipn	cdecnt
	jrst	ncodes
	push	p,b
	skipe	cdewin		;need an input password?
	jrst	nopasw
	call	getpsd
	setom	cdewin		;we have one now
	move	b,cdewrd
	movem	b,cdewri
nopasw:	movei	a,cdewri
	skipe	(a)
	call	hack
ncode:	pop	p,b
ncodes:
 >
	LDB CH,B		;GET LAST CHAR STORED
	MOVEM CH,LCS		;REMEMBER IT
	CALL SETHPT		;SET HOLE POINTERS
	MOVE A,INJFN		;RESTORE CLOBBERED JFN
	GTSTS%
	TLNE B,(1B8)
	TXOA FF,FINF
	TXZ FF,FINF		;FINF ON OR OFF FOR EOF
	SKIPE YAMODE
	JRST NCLSF		;DOING Y OR A, DONT TRY TO CLOSE FILE
	TXNN FF,FINF		;DOING ;Y. EOF?
	JRST SINLD2		;NO, TRY S'MORE (PROB. AN I/O ERROR)
	CALL CLSINF		;YES, NOW CLOSE OFF
NCLSF:	MOVE CH,LCS		;GET LAST CHARACTER STORED
	CAIN CH,"L"-100		;IS LAST CHAR FORMFEED?
	TXO FF,FORM		;YES
	RET

 OPTION ENC,<			;coding algorithm

;This code is not supported, principally because this is not an optimal
;encryption scheme.
;perhaps someday, it will be supported.

hack:	movem	a,whrcde
hackl:	sosge	cdecnt
	ret
	setcm	a,@whrcde
	rot	a,5
	move	b,a
	rot	b,2
	add	a,b
	jffo	a,.+2
	movei	a,37424
	addb	a,b
	tlnn	b,100
	xori	a,653201
	tlce	a,401			;an exercise in randomness
	trce	a,20004
	xor	a,[375001674315]
	tlnn	a,1002
	rot	a,6
	trne	b,1000
	xor	a,[130064220717]
	movsm	a,@whrcde 
	ildb	b,cdestr
	xor	b,a
	dpb	b,cdestr
	jrst	hackl
>
;ER PREPARE TO READ FILE

OPNRD:	TXNE FF,UREAD		;FILE NOW OPEN?
	CALL CLSINF		;CLOSE INPUT FILE
	CALL FILSPC		;GET FILE SPEC
	MOVSI A,(1B2+1B17)	;OLD FILE+SHORT FORM
	CALL DOGTJ		;DO GTJFN, AND REMEMBER FILENAME
	JRST TYINPT
	DPB CH,CPTR		;PUT ESCAPE BACK IN
OPNIN:	HRRZM A,INJFN
	HRROI A,DEFNAM		;GET COMPLETE NAME OF FILE JUST OPENED
	MOVE B,INJFN		;FOR POSSIBLE LATER USE AS DEFAULT
	MOVSI C,(1B8)		;NAME ONLY
	JFNS%
	HRROI A,DEFEXT
	MOVSI C,(1B11)		;EXTENSION ONLY
	JFNS%
	 ERJMP .+1
	MOVE A,INJFN		;GET THE JFN
	CALL SETFDS		;SET FILENAME DEFAULT STRING
	MOVE A,INJFN
	MOVE B,[7B5+OF%RD]	;BYTE SIZE+READ
	SKIPE BASICF		;ARE WE FILTERING OUT LINE NUMBERS?
	TXO B,OF%PLN		;NO. (MAYBE A "BASIC" FILE).
	OPENF%
	JRST TYNOPN
 OPTION ENC,<
	setzm	cdewin		;New file, will need password
>
	TXO FF,UREAD		;FILE OPEN
	TXZ FF,FINF		;NOT EOF
OPNT2:	TXNN FF,COLONF
	JRST CFLUSH		;NO COLON, NO VALUE
	JRST NE1INA		;IT WORKED, RETURN -1

;TYPE INPUT DEVICE ERROR

TYNOPN:	MOVE A,INJFN		;RELEASE JFN
	RLJFN%
	JFCL
	CAIA
TYINPT:	DPB CH,CPTR		;UNCLOBBER COMMAND STRING
	SETOM INJFN
FLERR:	TXNE FF,COLONF
	JRST ZERINA		;COLON FLAGGED, RETURN 0, NOT ERROR
	CALL JSER
	ERROR <File operation failed>
;EW SELECTS THE OUTPUT DEVICE AND OPENS THE FILE SPECIFIED (IF ANY)

OPNWR:	CALL SKPWRT		;OUTPUT FILE NOW OPEN?
	 CAIA			;NO
	CALL CLOSEF		;CLOSE IT
	CALL FILSPC
	MOVSI A,(1B0+1B3+1B17)	;WRITE+PRINT OLD/NEW+SHRT
	CALL DOGTJ		;DO GTJFN AND REMEMBER FILESPEC
	JRST OPNBAD
	DPB CH,CPTR
OPNOUT:	HRRZM A,OUTJFN
	HRROI A,DEFNAM		;GET COMPLETE NAME OF FILE JUST OPENED
	MOVE B,OUTJFN		;FOR POSSIBLE LATER USE AS DEFAULT
	MOVSI C,(1B8)		;NAME ONLY
	JFNS%
	HRROI A,DEFEXT		;EXTENSION STRING
	MOVSI C,(1B11)		;EXTENSION ONLY
	JFNS%
	MOVE A,OUTJFN
	CALL SETFDS		;SET FILENAME DEFAULT STRING
	MOVE B,[7B5+OF%WR]
	MOVE A,OUTJFN
	OPENF%
	 ERJMP OUTER1
 OPTION ENC,<
	setzm	cdewon		;will need password
 >
	SETZM WRITEF		;MARK THAT NO OUTPUT HAS HAPPENED YET
	TXO FF,UWRITE		;SAY WE HAVE OUTPUT FILE OPEN
OPNWR2:	TXNN FF,COLONF
	JRST CFLUSH
	JRST NE1INA

OPNBAD:	DPB CH,CPTR		;UNCLOBBER COMMAND STRING
	JRST OUTERR

;SKPWRT SKIPS IFF AN OUTPUT FILE IS OPEN.  IF UWRITE IS OFF AND CREJFN IS
;NON-0, SKPWRT SILENTLY OPENS THE OUTPUT FILE AND SKIPS.  THIS IS SO THAT
;IF THE USER GIVES THE EXEC COMMAND "EDIT A.B.1 A.B.1", ^C WILL LEAVE A.B.1
;INTACT.  NOTE THAT OPENING THE OUTPUT FILE AT STARTUP WOULD FLUSH ITS
;CONTENTS.

SKPWRT:	SKIPN CREJFN		;ANY OUTPUT SPEC WAITING TO BE OPENED?
	TXNE FF,UWRITE		;OUTPUT FILE, OR LATENT ONE?
	CAIA
	RET			;NEITHER, SO DON'T SKIP
	TXNE FF,UWRITE		;OUTPUT FILE ALREADY OPEN?
	JRST	CPOPJ1		;SKIP TO SAY SO
	SKIPE INIJFN		;STILL DOING TV.INI?
	RET			;YES, SO DON'T OPEN LATENT FILE YET
	MOVE A,CREJFN		;DOING CREATE, SO CREATE THE FILE NOW
	CALL OPNOUT		;OPEN IT FOR OUTPUT
	SETZM CREJFN		;THERE'S NO MORE LATENT OUTPUT SPEC
	JRST CPOPJ1		;SAY OUTPUT FILE OPEN
;PUT HEADING INTO OUTPUT FILE

HEDING:	MOVEI B,";"
	CALL BOUTX
	HRRZ B,OUTJFN
	MOVE C,[1B5+1B8+1B11+1B14+1B35]
	CALL JFNSX
	HRROI B,[ASCIZ /, /]
	SETZ C,
	CALL SOUTX
	SETO B,
	SETZ C,
	CALL ODTIMX
	HRROI B,[ASCIZ /, Edit by /]
	CALL SOUTX
	PUSH P,A		;SAVE STRING POINTER
	GJINF%
	MOVE B,A
	POP P,A
	CALL DIRSTX
	 JFCL
	MOVEI B,15
	CALL BOUTX
	MOVEI B,12
	CALL BOUTX
	RET

OUTER1:	MOVE A,OUTJFN
	RLJFN%			;RELEASE JFN
	JFCL
	SETZM CREJFN		;DON'T LET NEXT ATTEMPT USE SAME JFN
OUTERR:	SETOM OUTJFN
	JRST FLERR		;FILE ERROR, GO RETURN 0 OR ERROR
;EF FINISHES OUTPUT ON THE CURRENT OUTPUT FILE WITHOUT
;	SELECTING A NEW OUTPUT FILE.

SEMIC:	CALL	CLOSEF
	JRST	CFLUSH

CLOSEF:	CALL SKPWRT		;OPEN LATENT OUTPUT FILE NOW
	 JFCL			;WE DON'T CARE WHETHER THERE WAS ONE
	TXZN FF,UWRITE!DUMPF
	RET
CLOS2:	MOVE A,OUTJFN
	CLOSF%
	JFCL
	SETZM WRITEF		;MARK THAT NO DATA WRITTEN IN OUTPUT FILE
	SETOM OUTJFN		; (ANYMORE...YET...WHAT HAVE YOU)
	RET

;CLOSE INPUT FILE

CLSINF:	TXZN FF,UREAD
	RET
	MOVE A,INJFN
	CLOSF%
	 ERJMP .+1
	SETOM INJFN
	RET

;GATHER FILE NAME

FILSPC:	STKVAR <SAVFPT>
	MOVE B,CPTR		;GET POINTER TO BEGINNING OF FILESPEC
	MOVEM B,SAVFPT		;REMEMBER IT
FILS2:	CALL SKRCH
	CAIE CH,.CHESC		;FIND THE ESC
	JRST FILS2
	SETZ CH,		;SMASH IT TO 0
	DPB CH,CPTR
	MOVEI CH,.CHESC		;prepare to unclobber command string
	MOVE B,SAVFPT		;RETURN POINTER IN B
	RET			;RETURN ORIGINAL CPTR
;A   APPEND TO THE END OF THE BUFFER FROM THE SELECTED INPUT
;	TERMINATING THE READ IN THE SAME MANNER AS Y.  THE POINTER
;	IS NOT MOVED BY A.

APPEND:	CALL YANKS
	JRST CFLUSH

;Y RENDER THE BUFFER EMPTY.  READ INTO THE BUFFER UNTIL
;	(A)  A FORM FEED CHARACTER IS READ, OR
;	(B)  THE BUFFER IS WITHIN ONE THIRD OR
;128 CHARACTERS OF CAPACITY AND A LINE FEED IS READ, (BULLSHIP!) OR
;	(C)  AN END OF FILE IS READ, OR
;	(D)  THE BUFFER IS COMPLETELY FULL.
;THE FORM FEED (IF PRESENT) DOES ENTER THE BUFFER.

DYANK:	CALL YANK
	JRST CFLUSH

YANK:	TDZA I,I		;HK AND READ BUFFER COMES HERE (Y,N,P)
YANKS:	SETO I,			;APPEND JUMPS HERE
	TXNN FF,UREAD		;HAS AN INPUT FILE BEEN SPECIFIED?
YANKQE:	ERROR <No file for input> ;NO.
	SKIPE ABORTF		;ABORT REQUEST?
	RET			;YES, DON'T CLOBBER BUFFER
	SETOM YAMODE		;TELL SINLD THAT THIS IS Y OR A
	CAIN I,0
	CALL HK			;KILL ENTIRE BUFFER
	JRST SINLD		;GO DO SIN STUFF
	JRST CFLUSH

;^ITEXT$ INSERTS AT THE CURRENT POINTER LOCATION THE ^I (TAB)
;	AND THE TEXT FOLLOWING THE ^I UP TO BUT NOT INCLUDING THE
;	ALT MODE.  THE POINTER IS PUT TO THE RIGHT OF THE INSERTED
;	MATERIAL.

TAB:	MOVE A,[POINT 7,[BYTE (7).CHTAB]]	;PREPARE TO INSERT TAB
	MOVEI B,1		;ONLY ONE CHARACTER
;**;[502] At TAB: +2L, REMOVE EDIT 500 IFF INSTALLED SM 4-Mar-82 (2 LINES)
	CALL INSRT0		;INSERT THE TAB
	;...			;FALL INTO STANDARD INSERT CODE

;ITEXT$ INSERT, AT THE CURRENT POINTER LOCATION, THE TEXT FOLLOWING
;	THE IN UP TO BUT NOT INCLUDING THE FIRST ALT. MODE.  THE
;	POINTER IS PUT TO THE RIGHT OF THE INSERTED MATERIAL.
;NOTE: The I command can't just blindly insert its characters, since there
;may be case control characters in the string.  Therefore the I command doesn't
;use INSRT0.  If you are looking for the general text insertion routine, please
;see INSRT0.

INSERT:	TXNE FF,ARG		;IS THERE AN ARGUMENT?
	JRST INS1A		;YES. NI COMMAND.

;ENTRY FROM REPLACE COMMAND

RPINS:	STKVAR <IBEG,IDSPTR,UUF,LLF,ITERM,ICNT,IBEG>
	SKIPE ABORTF		;ABORT REQUEST?
	RET			;YES, DON'T START INSERT
	MOVEI CH,.CHESC		;NO. CH:=ALT-MODE.
	TXNE FF,SLSL		;DID @ PRECEED I?
	CALL RCH		;YES. CH:=USER SELECTED TERMINATOR.
	MOVEM CH,ITERM		;A:=INSERTION TERMINATOR.
	SETZM UUF		;SAY NO CASE CONTROL HAPPENING YET
	SETZM LLF
	MOVE A,PT
	TXNN FF,SCANF		;DON'T MOVE HOLE IF SCANNING
	CALL MOVHOL		;PUT HOLE WHERE WE'RE INSERTING
	MOVE A,PT
	CALL ADDPTR		;MAKE BYTE POINTER TO DESTINATION OF INSERTION
	SETO B,			;BACK UP 1 SINCE IDPB BEING DONE
	ADJBP B,A
	MOVEM B,IDSPTR		;REMEMBER DESTINATION POINTER
	MOVEM B,IBEG		;REMEMBER BEGINNING FOR MEASURING
	CALL NFREE		;SEE HOW MANY CHARACTERS WE'RE ALLOWED TO INSERT
	MOVEM A,ICNT
INXT:	CALL SKRCH		;GET NEXT CHARACTER
	CAIN CH,C.QUOT		;QUOTE REQUEST?
	JRST [	CALL SKRCH	;YES, READ CHARACTER BEING QUOTED
		JRST II]	;GO INSERT IT
	CAMN CH,ITERM		;FOUND THE TERMINATOR?
	JRST ITDON		;YES
	CAIN CH,C.LOWR		;FORCE LOWERCASE?
	JRST [	CALL SKRCH	;YES LOOK AT NEXT
		CAIN CH,C.LOWR	;LOCK LOWERCASE?
		JRST [	SETOM LLF	;YES
			SETZM UUF	;UNLOCK UPPERS
			JRST INXT]
		LOAD CH,LWRCOD,(CH)	;NO, JUST MAKE ONE CHARACTER LOWERCASE
		JRST II]	;AND GO INSERT THE ONE BEING LOWERED
	CAIN CH,C.RAIS		;FORCING UPPER?
	JRST [	CALL SKRCH	;YES, LOOK AT NEXT CHARACTER
		CAIN CH,C.RAIS	;LOCKING INTO UPPERCASE?
		JRST [	SETOM UUF	;YES, REMEMBER
			SETZM LLF	;AND UNLOCK LOWERS
			JRST INXT]	;GO GET NEXT CHARACTER
		LOAD CH,UPRCOD,(CH)	;NOT LOCKING UPPERCASE, JUST MAKE ONE CHARACTER UPPERCASE
		JRST II]	;GO INSERT IT
	SKIPE UUF		;FORCING UPPER?
	LOAD CH,UPRCOD,(CH)	;YES, GET UPPERCASE
	SKIPE LLF		;FORCING LOWER?
	LOAD CH,LWRCOD,(CH)	;YES, GET LOWERCASE
II:	SOSGE ICNT		;ROOM FOR THIS CHARACTER?
	JRST IERR		;NO, FAIL
	TXNN FF,SCANF		;DON'T REALLY INSERT IF SCANNING
	IDPB CH,IDSPTR		;STORE CHARACTER IN INSERTION STRING
	JRST INXT		;LOOP FOR REST OF INSERTION

ITDON:	MOVE A,IDSPTR		;GET PLACE TEXT RAN TO
	MOVE B,IBEG		;GET PLACE WE STARTED
	CALL SUBBP		;SEE HOW MANY CHARACTERS GOT INSERTED
	ADDM A,ZEE		;SHOW INCREASE IN BUFFER SIZE
	ADDM A,PT		;POINTER HAS ALSO MOVED TO RIGHT
	ADDM A,HOLBEG		;HOLE STARTS FURTHER TO RIGHT NOW (IT'S SMALLER)
	CALL SETHPT		;UPDATE HOLE DATA
	JRST CFLUSH		;[502] DONE

;ASCIZ INSERT ROUTINE.  INSERTS THE ASCIZ STRING (ONE MARKED BY
;(NULL AT END
;CALL:
;	A/	POINTER TO ASCIZ STRING
;	CALL INSRTZ
;RETURN:
;	+1 ALWAYS

INSRTZ:	MOVE C,A		;GET COPY OF INSERTION POINTER
	MOVEI B,0		;FIRST ASSUME 0 CHARACTERS
INZ1:	ILDB D,C		;GET CHARACTER
	CAIE D,0
	AOJA B,INZ1		;LOOP UNTIL NULL FOUND
	CALLRET INSRT0		;DO INSERTION NOW THAT STRING HAS BEEN MEASURED

;GENERAL INSERT ROUTINE.  IT ALWAYS INSERTS TEXT AT THE POINTER.
;THE CALL:
;	A/	POINTER TO INSERTION
;	B/	NUMBER OF CHARACTERS
;	CALL INSRT0
;RETURNS:
;	+1 ALWAYS
;	UPDATED POINTER IN A POINTING TO END OF INSERTION

INSRT0:	STKVAR <IPT,IC>
	MOVEM A,IPT		;SAVE POINTER
	MOVEM B,IC		;SAVE COUNT
	MOVE A,PT
	CALL MOVHOL		;put hole where insert is going
	MOVE P1,IC		;get size of insert
	CALL NFREE		;SEE HOW MANY MORE CHARACTERS WILL FIT IN BUFFER
	CAMGE A,IC		;MAKE SURE THERE'S ROOM FOR THE INSERTION
IERR:	ERROR <No room in buffer>
;MOVE INSERTION INTO DATA BUFFER

INS1B:	MOVE I,IPT		;GET BEGINNING OF INSERTION
	JUMPE P1,INS1C		;IN CASE SOURCE IS NULL
	MOVE OU,PT
	ADDM P1,PT		;UPDATE POINT
	CALL PUT		;COMPUTE DEST BYTE PTR
	CALL DBP		;BACKUP TO BEGINNING OF DEST
	MOVE OU,TT
	CALL MVSTR		;MOVE STRING FROM I TO OU
	MOVE A,IC		;GET SIZE OF INSERTION
	ADDM A,HOLBEG		;HOLE STARTS AT A LARGER ADDRESS NOW
	ADDM A,ZEE		;THERE'S MORE IN BUFFER NOW TOO!
	CALL SETHPT		;SET HOLE POINTERS;
INS1C:	MOVE A,IC		;RETURN UPDATED INSERTION POINTER IN A
	ADJBP A,IPT
	RET
; ;G  INSERT LAST COMMAND STRING (OF  .G. 15 CHARS) INTO BUFFER

GETOB:	HLRZ B,LSTCB		;NUMBER OF CHARS
	JUMPE B,CFLUSH		;NO SAVED STRING
	MOVEI A,1		;SKIP OVER THE PROMPT CHARACTER
	ADJBP A,[POINT 7,CBUF]	;CONSTRUCT PTR TO SAVED STRING
	CALL INSRT0		;INSERT COMMAND STRING INTO BUFFER
	JRST CFLUSH

;WHOLE$ - RETURN CHARACTER LOC OF HOLE IN BUFFER

WHOLE:	MOVE	C,HOLBEG
	SUB	C,BEG
	JRST	ARGINC

;WBACKUP$ - TURN ON BACKUP SYSTEM

BACKUP:	SETOM BAKFLG
	JRST CFLUSH		;[502] DONE

;WNOBACK$ - TURN OFF BACKUP SYSTEM

NOBACK:	SETZM BAKFLG
	JRST CFLUSH		;[502] DONE

;TERMINAL INITIALIZATION ROUTINES
DEFINE TERINI (TABNAM)
<
TABNAM:
%%Z==0
	BLOCK 100		;MAKE SURE UNUSED ENTRIES ARE 0

DEFINE TER (SYMBOL,ADDRES)
<	LOC TABNAM+SYMBOL
	ADDRES
IFG SYMBOL-%%Z,<
	%%Z==SYMBOL
>
	LOC %%Z+TABNAM+1
>>

;TABLE OF TERMINAL INITIALIZATION ROUTINES, INDEXED BY TERMINAL TYPE

	TERINI TRMINI
	TER .TTV05,VT05		;VT05
	TER .TT100,VT100	;VT100
	TER .TTV50,VT50		;VT50
	TER .TTV52,VT52		;VT52

;TABLE OF TERMINAL STANDARD CHARACTERISTICS

LB==7
WB==^D15
SB==^D16

;DEFSTRS TO ACCESS THE VARIOUS TERMINAL STANDARD FIELDS

	DEFSTR STDLEN,TERSTD,LB,8
	DEFSTR STDWTH,TERSTD,WB,8
	DEFSTR SF,TERSTD,SB,1

DEFINE TCR(TYPE,LENGTH,WIDTH,SFF)
<	TER TYPE,<LENGTH>B<LB>+<WIDTH>B<WB>+<SFF>B<SB>
>
	TERINI TERSTD
RADIX 5+5
	TCR .TTV05,20,72,1
	TCR .TTV50,12,80,1
	TCR .TT100,24,80,1
	TCR .TTV52,24,80,1
RADIX 8

;SET UP FOR VT52...

VT52:	MOVEI A,.TTV52		;TERMINAL TYPE
	MOVEM A,TRMTYP
	CALLRET SETPAR		;SET UP PARAMETERS

;INITIALIZATION FOR VT50

VT50:	MOVEI A,13
	MOVEM A,TRMTYP		;SET VT50 TERMINAL TYPE.
VTXXX:	CALL SETPAR
	JRST CFLUSH		;[502] SET PARAMETERS AND LEAVE

;WVT100 - DECLARE VT100 FLAVOR

VT100:	MOVEI A,.TT100
	MOVEM A,TRMTYP
	SETOM SCRNF
	JRST VTXXX

;WVT05$ - TELL TECO WE'RE ON A VT05.

VT05:	MOVEI A,12
	MOVEM A,TRMTYP		;SET VT05 TERMINAL TYPE NUMBER.
	SETOM SCRNF		;SET SCREEN FLAG
	JRST VTXXX		;[502] GO SETUP

;ROUTINE CALLED AT STARTUP AND REENTER TO RESTORE TERMINAL
;CHARACTERISTICS THAT AREN'T INITIALIZED BY RESET JSYS, AND THAT MAY
;HAVE TO BE RESTORED AT REENTER, SINCE JSYS'S SUCH AS COMND MAY HAVE
;CLOBBERED THEM.

SETMOD:	MOVEI A,1
	MOVEM A,COCNST		;FORCE REGCOC TO DO SOMETHING
	CALL REGCOC		;SET UP REGULAR CONTROL CHARACTER STUFF
	MOVE A,TTYOUT		;STANDARD OUTPUT CHANNEL
	RFMOD%			;GET WAKEUP MODES
	TXO B,TT%WAK		;WAKE ON EVERYTHING
	SFMOD%			; (FOR READING FIRST CHARACTER OF COMMAND)
	RET

;REGCOC SETS CONTROL CHARACTER ECHOS TO THAT FOR STANDARD OUTPUT.

REGCOC:	SOSE A,COCNST		;SEE HOW MANY TIMES WE'RE NESTED AFTER THIS
	RET			;NOTHING TO DO IF OUTER ROUTINE...
				; STILL WANTS DISCOC
	MOVE A,TTYOUT		;STANDARD OUTPUT
	SKIPE FLAGF		;ARE WE SUPPOSED TO FLAG?
	JRST [	RFMOD%		;YES, GET SETTINGS
		TXO B,TT%UOC	;YES, TURN FLAGGING BACK ON
		STPAR%
		JRST .+1]
	DMOVE B,REGCWD		;GET STANDARD CONTROL CHARACTER SETTINGS
	SFCOC%
	MOVE B,COCPOS
	SFPOS%			;UNDO SYSTEM-ACCOUNTING OF ESCAPE SEQUENCE
	MOVE A,SWIDTH
	CALL SETWID		;RESTORE CORRECT TERMINAL WIDTH
	 JSHLT			;BETTER NOT FAIL!
	RET

;DISCOC CAUSES ALL CONTROL CHARACTERS TO ECHO LITERALLY, AS IS NEEDED BY
;VIDEO DISPLAY FUNCTIONS

DISCOC:	AOS A,COCNST		;REMEMBER HOW MANY TIMES WE'VE NESTED
	CAIE A,1		;IS THIS THE FIRST TIME?
	RET			;NO, SO NOTHING TO DO
	MOVE A,TTYOUT		;STANDARD OUTPUT CHANNEL
	SKIPE FLAGF		;IS FLAGGING ON?
	JRST [	RFMOD%		;YES, TURN IT OFF
		TXZ B,TT%UOC	;SINCE WE'LL DO OUR OWN FLAGGING.
		STPAR%
		JRST .+1]
	DMOVE B,[EXP 525252525252,525252525252]
	SFCOC%
	RFPOS%			;SEE WHERE ON LINE WE ARE
	MOVEM B,COCPOS		;REMEMBER SO THAT WE CAN UNDO ERRONEOUS
				; SYSTEM ACCOUNTING OF ESCAPE SEQUENCES
	MOVEI A,0		;DON'T ALLOW LINEWRAP
	CALL SETWID
	 JSHLT			;SHOULDN'T EVER FAIL
	RET

;THE FOLLOWING ROUTINE IS CALLED EVERY TIME WE TRANSFER FROM
;THE EXEC (BACK) TO TV.  IT ASKS THE SYSTEM WHAT THE CURRENT TERMINAL
;TYPE IS, AND THEN SETS UP ALL THE TERMINAL PARAMETERS.

SYSMOD:	MOVEI A,.PRIIN
	GTTYP%			;get terminal type
	MOVEM B,TRMTYP		;SAVE TERMINAL TYPE
SYSMD1:	CALL GETMOD		;GET THE REST OF THE TERMINAL MODES
	MOVE A,SLENTH		;GET WINDOW SIZE
	CAMLE A,SSIZE		;MAKE SURE WITHIN RANGE
	CALL WINSTN		;IF NOT, RESET IT TO A STANDARD SETTING
	RET

;CALL THE FOLLOWING AFTER SETTING UP TRMTYP FOR NEW TERMINAL TYPE

SETPAR:	MOVEI A,100		;primary input
	MOVE B,TRMTYP		;get new terminal type
	STTYP%			;tell monitor new terminal type
	SETOM MESFLG		;IF TERMINAL TYPE CHANGED, ASSUME SCREEN MESSED UP
	CALL SYSMD1		;go get all the new modes
	CALLRET WINSTN		;SET UP STANDARD WINDOW SIZE

;THE FOLLOWING ROUTINE ASSUMES THE SYSTEM'S TERMINAL PARAMETERS
;HAVE BEEN SET UP, AND THIS ROUTINE SETS UP TV'S INTERNAL DATA TO
;REFLECT THE CURRENT TERMINAL SETTINGS

GETMOD:	MOVEI A,.PRIIN	;PRIMARY INPUT DEVICE
	RFMOD%			;GET TTY INFO
	SETZM FLAGF		;FIRST ASSUME NOT FLAGGING UPPERS
	TRNE B,TT%UOC
	SETOM FLAGF		;SYSTEM SAYS WE'RE FLAGGING UPPERS.
	CALL GETWID		;GET SYSTEM TERMINAL WIDTH
	 MOVEI A,0		;ASSUME DEFAULT IF CAN'T READ IT
	MOVE B,TRMTYP		;GET TERMINAL TYPE
	CAIN A,0		;IF ZERO,
	LOAD A,STDWTH,(B)	;USE STANDARD WIDTH
	MOVEM A,SWIDTH		;SET UP TERMINAL WIDTH
	CALL GETLEN		;GET SCREEN SIZE
	 MOVEI A,0		;USE STANDARD IF CAN'T
	MOVE B,TRMTYP		;GET TERMINAL TYPE
	CAIG A,MAXLEN		;DON'T ALLOW TOO LARGE SCREEN SIZE
	CAIN A,0		;NON-0 LENGTH?
	LOAD A,STDLEN,(B)	;NO, SO USE STANDARD LENGTH
	MOVEM A,SSIZE		;REMEMBER SCREEN SIZE
	LOAD A,SF,(B)		;SEE IF TERMINAL IS A SCREEN
	SETZM SCRNF		;FIRST ASSUME NOT
	CAIE A,0
	SETOM SCRNF		;BUT MAYBE SO!
	RET

;ROUTINE TO SET UP STANDARD WINDOW SIZE TO 3 LESS THAN SCREEN SIZE

WINSTN:	MOVE A,SSIZE		;GET SCREEN SIZE
	SUBI A,3		;LEAVE ROOM FOR COMMAND LINES
	CAIG A,MAXLEN		;MAKE SURE WINDOW SIZE IS LEGAL
	CAIGE A,0		;NEVER CREATE A ZERO WINDOW SIZE FOR STANDARD
	MOVEI A,0		;USE NO WINDOW IF IT'S <0 AFTER NORMALIZATION
	MOVEM A,SLENTH		;STORE WINDOW SIZE
	RET
;NI INSERT AT THE POINTER A CHARACTER WHOSE 7-BIT ASCII CODE IS N
;  (BASE 10).  THE POINTER IS MOVED TO THE RIGHT OF THE NEW CHARACTER.

INS1A:	MOVE A,[070700,,FARG]	;POINTER TO "STRING"
	MOVEI B,1		;WE'RE ONLY INSERTING ONE CHARACTER
	CALL INSRT0		;[502] INSERT IT
	JRST CFLUSH		;[502] AND DONE

OVWR:	MOVE	I,PT		;WHERE ARE WE?
	CAMN	I,ZEE		;AT END?
	JRST	OVWRND		;YES, WILL HAVE TO USE INS1A
	CALL	GETX		;BYTE POINTER TO NEXT CHAR, PLEASE
	LDB	A,TT		;GET CHARACTER THAT'S THERE
	DPB	C,TT		;AND SET THE USERS VALUE
	AOS	PT		;AND ADVANCE OVER IT
	JRST	ARGINA		;AND RETURN WITH OLD CHARACTER IN A
OVWRND:	CALL	INS1A		;GO INSERT GIVEN CHARACTER
	JRST	NE1INA		;AND RETURN -1

;@IJTEXTJ INSERT, AT THE CURRENT POINTER POSITION, THE TEXT
;	SURROUNDED BY THE INSTANCES OF THE TERMINATOR J, WHICH MAY BE AT
;	THE USER'S CHOICE ANY CHARACTER NOT APPEARING IN THE TEXT.
;	THE POINTER IS PUT TO THE RIGHT OF THE INSERTED MATERIAL.


;NBACKSLASH INSERT AT THE CURRENT POINTER LOCATION THE ASCII NUMBERS
;	EQUAL TO N.

BAKSL1:	PUSH P,RADIX		;SAVE OLD RADIX
	TXZN FF,ARG2		;SECOND ARG?
	JRST BAKSLR
	SKIPG T,SARG		;YES, FETCH
	MOVEI T,^D10		;DEFAULT IS 10
	MOVEM T,RADIX
BAKSLR:	MOVE T,[XWD 700,BAKTAB-1]
	SETZ P1,		;COUNT # DIGITS IN P1.
	MOVEI CH,BAKSL4		;SET DPT TO RETURN TO BAKSL4
	HRRM CH,LISTF5
	CALL DPT		;CONVERT NUMBER TO ASCII, STORE IN BAKTAB.
	MOVE A,[POINT 7,BAKTAB]	;POINT TO NUMBER
	MOVE B,P1		;COUNT OF CHARACTERS
	CALL INSRT0		;INSERT THE NUMBER
	POP P,RADIX		;RESTORE OLD RADIX
	JRST CFLUSH

BAKSL4:	IDPB A,T		;STORE DIGIT IN BAKTAB
	AOJA P1,CPOPJ		;P1:=P1+1. RETURNS TO DPT CALL+1
;NT TYPE OU THE STRING OF CHARACTERS STARTING AT THE RIGHT OF THE
;	POINTER AND CONTINUING THROUGH THE NTH LINE FEED ENCOUNTERED.
;	IF N IS NEGATIVE, N LINES TO THE LEFT OF THE POINTER ARE TYPED.
;T SAME AS 1T.
;I,JT TYPE OUT THE (I+1)TH THROUGH THE JTH CHARACTER OF THE BUFFER.

TYPE:	CALL WINCLS		;START PRESERVED OUTPUT
	CALL TVINIT		;GET AND CHECK ARGS
TYPE3:	SKIPN COFLG		;^O REQUEST?
	CAML I,C		;DONE?
	JRST CFLUSH		;[502] DONE
	UILDB A,P2		;GET NEXT CHAR
	CALL TYO		;OUTPUT IT
	SKIPN ABORTF		;ABORT REQUEST?
	AOJA I,TYPE3		;NO
	JRST TYOQT		;YES, QUIT

;TVINIT ROUTINE RETURNS ILDB POINTER TO BUFFER IN P2, LEFTMOST
;CHARACTER ADDRESS IN I, AND ONE MORE THAN LAST CHARACTER ADDRESS IN
;IN C

TVINIT:	CALL GETARG		;p1:=FIRST STRING ARGUMENT ADDRESS.
				;c:=SECOND STRING ARGUMENT ADDRESS.
	MOVE I,P1		;START GETTING CHARACTERS AT C.
	CALL GET
	MOVSI P2,(07B5)		;BACKUP 1 BECAUSE ILDB BELOW
	ADD P2,TT
	RET
;P IS THE SAME AS 1P
;NP IS IDENTICAL TO PP...P (P PERFORMED N TIMES).
;I,JP OUTPUTS (I+1)TH THROUGH JTH CHARACTERS OF BUFFER.  NO FORM
;	FEED IS PUT AT THE END.  BUFFER UNCHANGED; POINTER UNMOVED.

PUNCH:	CALL PUNCHA		;[502] DO THE WORK
	JRST CFLUSH		;[502] DONE

PUNCHA:
;**;[511] At PUNCHA: +2L, Modified 1 line                   SM  9-Jun-82
	TXNE FF,ARG2		;I,JP? ;[511] DON'T CLEAR ARG2 YET
	JRST PCH0		;YES. GET STRING ARGUMENTS AND OUTPUT.
	TXNN FF,ARG
	MOVEI C,1
	MOVE D,C		;NO. d:=N
	JUMPL D,CPOPJ		;IF N .L. 0, IGNORE P.
	STKVAR <DCNT>		;(HOLDS DE COUNT) (HOW CORNEY!)
	MOVEM D,DCNT		;REMEMBER HOW MANY PAGES TO DO
PUN1:	CALL PUNCHR		;PUNCH OUT BUFFER
	SKIPE ABORTF		;ABORT?
	RET			;YES, DON'T CLOBBER BUFFER
	CALL HK			;KILL ENTIRE BUFFER
	TXNE FF,UREAD
	TXNE FF,FINF
	RET
	SKIPN DCNT		;DONE?
	RET			;YES
	CALL YANK		;RENEW BUFFER
	SKIPE ABORTF		;ABORT?
	RET			;YES
	MOVE P1,ZEE
	CAMN P1,BEG		;EMPTY BUFFER?
	TXNN FF,FINF		;YES. QUIT ON EOF
	SOSG DCNT		;DONE ENOUGH PAGES?
	RET
	JRST PUN1		;NO, KEEP GOING

PUNCHR:	MOVE P1,BEG		;OUTPUT DATA BUFFER.
	MOVE C,ZEE
	JRST PCH1

; ;W - WRITE OUT BUFFER AND DELETE

WRBUF:	TXNN FF,ARG
	JRST [	MOVE P1,BEG	;ASSUME B,ZEE IF NO EXPLICIT ARG
		MOVE C,ZEE
		JRST WRBUF1]
	CALL GETARG
WRBUF1:	PUSH P,C		;SAVE ARGS
	PUSH P,P1
	CALL pch1
	POP P,P1		;RECOVER ARGS FOR KLBUF
	POP P,C
	JRST KLBUF

;DO OUTPUT VIA ROUTINE ADDRESS IN p2
; p1 = START ADDRESS
; c = END ADDRESS

PCH0:	CALL GETARG		;GET STRING ARGS
PCH1:	STKVAR <WRBEG,WREND>	;START AND 1+END CHARACTER ADDRESS
	MOVEM P1,WRBEG		;STORE STARTING ADDRESS
	MOVEM C,WREND		;AND END ADDRESS
	CALL SKPWRT		;CAN DO SOUT
	ERROR <No file for output>
 OPTION ENC,<
	skipe	encflg
	skipe	cdewon		;need an output password?
	jrst	nogpsd
	call	getps2		;ask twice
	setom	cdewon		;got it now
	move	a,cdewrd
	movem	a,cdewro
nogpsd:
>
	MOVE A,WRBEG		;GET STARTING ADDRESS
	CAML A,HOLBEG		;MAKE SURE NOT IN HOLE
	ADD A,HOLSIZ		;IN HOLE, GET OUT
	MOVEM A,WRBEG
	MOVE A,WREND		;SAME FOR END ADDRESS
	CAMLE A,HOLBEG		;ALLOWED TO BE HOLBEG BECAUSE NOT WRITTEN
	ADD A,HOLSIZ
	MOVEM A,WREND
	MOVE A,WRBEG		;GET STARTING ADDRESS
	CAML A,HOLBEG		;IS IT TO LEFT OF HOLE?
	JRST DOAFT		;NO, THERE'S NOTHING TO THE LEFT OF THE
				; HOLE BEING WRITTEN
	MOVE A,HOLBEG		;GET LESSER OF END ADDRESS
	CAML A,WREND		;AND BEGINNING OF HOLE
	MOVE A,WREND		;END ADDRESS MORE LEFT
	SUB A,WRBEG		;A:= # OF CHARS IN FIRST PART
	MOVN C,A		;C GETS MINUS NUMBER OF CHARS
	MOVE I,WRBEG		;I GETS STARTING ADDRESS
	CALL SOUT1		;DUMP STUFF TO LEFT OF HOLE
DOAFT:	MOVE A,WREND		;MAKE SURE RIGHT MARGIN IS TO RIGHT
	CAMG A,HOLEND		;OF END OF HOLE
	JRST NOAFT		;NOTHING TO WRITE TO RIGHT OF HOLE
	MOVE C,HOLEND		;GET GREATER OF BEGINNING OF OUTPUT
	CAMGE C,WRBEG		;AND END OF HOLE
	MOVE C,WRBEG
	MOVE I,C		;SAVE STARTING ADDRESS
	SUB C,WREND		;CALCULATE MINUS NUMBER OF CHARS IN 2ND PART
	CALL SOUT1		;WRITE SECOND PART
NOAFT:	RET			;DONE!

SOUT1:	JUMPE C,CPOPJ		;DO NOTHING IF NO CHARACTERS
	STKVAR <SVCNT>
	MOVEM C,SVCNT		;SAVE NEGATIVE CHARACTER COUNT
	CALL GET1		;GET LDB POINTER TO START IN TT
	SETO B,			;BACK UP BY ONE BYTE
	ADJBP B,TT		;TO GET ILDB POINTER IN B
	MOVE C,SVCNT		;GET CHARACTER COUNT
 OPTION ENC,<			;FOR CODING ALGORITHM
	skipn	encflg
	jrst	nooutc
	jumpe	c,nooutc
	movmm	c,cdecnt
	movem	b,cdestr
	push	p,c
	push	p,b
	movei	a,cdewro
	skipe	(a)
	call	hack
	pop	p,b
	pop	p,c
nooutc:
>
	MOVE A,OUTJFN		;GET JFN TO USE FOR OUTPUT
	CALL SOUTX		;WRITE THE ^%$#&@$ DATA!
	SETOM WRITEF		;SHOW THAT OUTPUT FILE HAS SOME DATA IN IT
	RET			;DONE
 OPTION ENC,<
;Code to fetch and encrypt password.

	blen==100		;max is 100 (319 letters)

getpse:	hrroi	a,[asciz/Did not match, type both again...
/]
	psout
getps2:	hrroi	a,[asciz/ Output/]
	setzm	syl
	jrst	getpsn
getpsd:	setom	syl
	hrroi	a,[asciz/ Input/]
getpsn:	psout
	hrloi	a,(tl%cor!tl%cro)
	seto	b,
	tlink
	 erjmp	.+1
	movx	a,.priin
	rfmod
	move	d,b
	txz	b,tt%eco
	sfmod
	setzm	cdewrd
	hrroi	a,[asciz/ password: /]
	move	c,a
	psout
	setzm	datbuf
	move	a,[datbuf,,datbuf+1]
	blt	a,datbuf+177
	hrroi	a,datbuf
	move	b,[rd%bel!rd%crf!rd%rai+blen*5-1]
	rdtty
	 erjmp	.+1
	movei	a,.chcrt
	pbout
	skipe	syl
	jrst	gogcde
	hrrzm	b,syl
	ldb	b,[point 7,datbuf,6]
	cain	b,.chlfd
	jrst	goytr
	hrroi	a,[asciz/ Retype for paranoia: /]
	move	c,a
	psout
	hrroi	a,datbuf+blen
	move	b,[rd%bel!rd%crf!rd%rai+blen*5-1]
	rdtty
	 erjmp	.+1
	hrrzs	b
	came	b,syl
	jrst	getpse
	subi	b,<blen+1>*5
	idivi	b,5
	hrli	b,datbuf
	movss	b
cmppas:	move	a,blen(b)
	came	a,(b)
	jrst	getpse
	aobjn	b,cmppas
gogcde:	move	b,d
	movx	a,.priin
	sfmod
	call	crr
	move	c,[point 7,datbuf]
	setz	b,
geyt:	ildb	a,c
	cain	a,.chlfd
	jrst	goytr
	setob	d,cdewrd
geyt2:	rot	b,^d9		;these 3 instrs must not ref relocatables
	xor	b,a
	hll	a,c
	sub	b,a
	aosl	a
geyt1:	xori	a,553023
	addi	b,443
	jfcl	17,geyt1
	trne	b,1000
	xor	b,geyt1
	addi	a,-3(b)
	ldb	a,[point 2,a,15]
	xor	b,geyt2(a)
	eqv	b,d
	tlne	b,014000
	aoja	d,geyt2
	soja	b,geyt
goytr:	cain	b,0
	movei	b,114411
	skipe	cdewrd
	movem	b,cdewrd
	ret
>
;THE MUMBLX ROUTINES DO JSYS'S THAT MAY CAUSE OVER QUOTA TRAPS, AND
;WHICH OVER QUOTA CAN BE CORRECTLY CONTINUED FROM.  AT TIME OF THIS
;WRITING, FOR EXAMPLE, A MULTIPLE PAGE PMAP COPYING FROM CORE TO A FILE
;COULD NOT BE CORRECTLY CONTINUED FROM AFTER AN OVER QUOTA TRAP.
;IT WOULD ERRONEOUSLY DO ALL THE PAGES OVER AGAIN, OR FALL THROUGH AND
;NEVER DO THE ONES THAT COME AFTER THE OVER QUOTA TRAP

DEFINE FOOX(WHAT)
<WHAT'X:	MOVE CX,[WHAT]
	CALLRET JSYSX
>

FOOX BOUT
FOOX SOUT
FOOX JFNS
FOOX DIRST
FOOX ODTIM

JSYSX:	MOVEM A,QUOJFN		;STORE JFN IN CASE OVER QUOTA
	XCT CX			;DO THE JSYS
IOWAIT:	 JFCL			;PARANOIA
	SETZM QUOJFN		;CLEAR THIS, DON'T CAUSE AUTO-EXPUNGE
	RET

;THE ;S COMMAND SAVES THE ENTIRE BUFFER AND CLOSES THE OUTPUT FILE, 
;WITHOUT ALTERING THE BUFFER OR THE POINTER.  IF NO FILE IS OPEN
;FOR WRITING WHEN ;S IS EXECUTED, ONE IS OPENED.  WITH ARGUMENT(S),
;THE ;S COMMAND INTERPRETS THE ARGS LIKE K, T, X ETC. AND DOES THE
;SAME AS ;S WITH NO ARGS, EXCEPT ONLY THE SPECIFIED BUFFER PORTION IS
;SAVED.

BSAVE:	TXNE FF,ARG!ARG2	;[506] DID THE USER GIVE ARGS?
	JRST [CALL GETARG	;[506] YES, SET THEM UP...
	      JRST BSAVE1]	;[506] AND USE THEM
	MOVE P1,BEG
	MOVE C,ZEE		;USE (W)HOLE BUFFER IF NO ARGS SUPPLIED.
BSAVE1:	PUSH P,C
	PUSH P,P1		;SAVE THE BUFFER ADDRESS RANGE.
	CALL SKPWRT		;IS AN OUTPUT FILE ALREADY OPEN?
	 CALL UNLD1		;NO, SO OPEN ONE.
	POP P,P1
	POP P,C			;RESTORE BUFFER RANGE TO BE OUTPUT.
	CALL PCH1		;OUTPUT THE SPECIFIED BUFFER PORTION
	JRST SEMIC		;AND DO THE ;C OPERATION
;NJ MOVE THE POINTER TO THE RIGHT OF THE NTH CHARACTER IN THE
;	BUFFER. (I.E., GIVE "." THE VALUE N.)
;J SAME AS 0J.

JMP:	TXZE FF,SLSL		;@J?
	JRST ATSGNJ		;YES.
	ADD C,BEG		;PT:=N+BEG
	JRST JMP1

; R - REPLACE ... BY ...

REPLAC:	CALL CHK2
;**;[510] At REPLAC: +1L, Inserted 1 line                   SM 26-May-82
	MOVEM FF,TMPFLG		;[510] REMEMBER FLAGS FOR LATER
	TXO FF,RPLFG
	TXZ FF,ARG+ARG2		;SO AS NOT TO CONFUSE S K AND I
	MOVEM C,REPARG		;REMEMBER ARGUMENT TO R COMMAND
RPLC3:	CALL SAVCMD		;REMEMBER CMD STATE FOR GARBAGE COLLECTOR
	SKIPE ABORTF		;ABORT?
	JRST RPLC4		;YES, STOP
	MOVEI A,1		;WANT 1ST OCCURENCE
	SKIPGE REPARG		;IS ARG NEGATIVE ??
	SETO A,			;YES, SO WANT -FIRST OCCURANCE
	CALL SERCH0		;SEARCH AND ADVANCE PT
	TXNN FF,SLSL		;SEE IF @ BEFORE R
	JRST RNOHAK		;NO @
	MOVE TT,CPTR		;THERE WAS @, SO BACK UP COMMAND POINTER
				; SO INSERT CAN READ DELIMITER
	CALL DBP		;DECREMENT COMMAND STRING BYTE POINTER
	AOS COMCNT		;AND REMEMBER ONE MORE CHAR IN COMMAND STRING
	MOVEM TT,CPTR		;SAVE NEW POINTER
RNOHAK:	TXNN FF,SCANF		;IF SCANNING, PRETEND SEARCH FAILED
	SKIPL SFINDF		;DID SEARCH SUCCEED?
	JRST NOREPL		;NO, :RFOO$BAR$ WAS REQUESTED, BUT NO FOO FOUND
	MOVN P1,SCHLNN		;GET NUMBER OF CHARACTERS TO DELETE
	SKIPLE REPARG		;IF -ARG, WE ARE ALREADY AT BEG OF STRING
	ADDM P1,PT		;BACKUP PT TO BEG OF SEARCH STRING
	PUSH P,PT
	MOVM A,P1		;SPECIFY HOW MANY CHARACTERS TO DELETE
	CALL ERASE		;DELETE THEM
	CALL RPINS		;INSERT THE NEW STUFF
	POP P,C
	SKIPGE REPARG		;SKIP IF REPLACING IN FORWARD DIRECTION
	MOVEM C,PT		;RESTORE PT IF -ARG
	SKIPLE REPARG		;REPLACING TO THE RIGHT?
	SOS REPARG		;YES, SO APPROACH 0 FROM ABOVE
	SKIPGE REPARG		;REPLACING TO THE LEFT?
	AOS REPARG		;YES, SO APPROACH 0 FROM BELOW
	SKIPN REPARG		;DONE ENOUGH REPLACEMENTS?
	JRST RPLC4		;YES
	CALL RESCMD		;RESTORE COMMAND STATE
	JRST RPLC3

;**;[504] Fix code at NOREPL: to use SKPIN1
NOREPL:	MOVEI CH,.CHESC		;FIRST ASSUME TERMINATOR IS ALTMODE
	TXNE FF,SLSL		;SEE IF @
	CALL RCH		;YES, SO READ TERMINATOR
	MOVEM CH,DLIMIT		;SKPIN1 WANTS DELIMITER IN DLIMIT
	CALL SKPIN1		;SKIP INSERT STRING
RPLC4:	ADJSP P,-CBLEN		;GET RID OF SAVED COMMAND STATE
	TXZ FF,RPLFG
;**;[510] At RPLC4: +2L, Inserted 3 lines                   SM 26-May-82
	MOVE A,TMPFLG		;[510] GET ORIGINAL FLAGS BACK
	TXNE A,COLONF		;[510] DID HE ASK FOR A COLON MODE REPLACE?
	TXO FF,COLONF		;[510] YES, BUT THE FLAG GOT CLOBBERED.
	MOVE A,SFINDF		;RETURN SEARCH SUCCESS VALUE
	JRST SRET		;GO RETURN CORRECT VALUE
;NC SAME AS .+NJ.  NOTE THAT N MAY BE NEGATIVE.

CHARAC:	CALL CHK2		;MAKE SURE THERE IS AN ARGUMENT
	ADD C,PT		;c:=PT+p1(c)

;IF c LIES BETWEEN BEG AND Z, STORE IT IN PT.

JMP1:	CALL CHK		;IS p1(c) WITHIN DATA BUFFER?
	MOVEM C,PT		;YES. PT:=p1(c)
	JRST CFLUSH

;NL IF N .G. 0:	MOVE POINTER TO THE RIGHT, STOPPING WHEN IT HAS
;		PASSED OVER N LINE FEEDS.
;	IF N .L. 0:	MOVE POINTER TO THE LEFT; STOP WHEN IT HAS PASSED
;		OVER N+1 LINE FEEDS AND THEN MOVE IT TO THE RIGHT OF
;		THE LAST LINE FEED PASSED OVER.
;L SAME AS 1L.

LINE:	CALL GETARG		;NO. p1:=FIRST STRING ARGUMENT ADDRESS,
	XOR C,P1		;C:=SECOND STRING ARGUMENT ADDRESS.
	XORM C,PT
	JRST CFLUSH

; n,m;L RETURNS THE NUMBER OF LINEFEEDS BETWEEN n AND m.

CNLINE:	CALL	GETARG
	MOVE	I,P1		;GO HUNTING FOR LINEFEEDS
	SETZ	A,		;ACCUMLATE COUNT HERE
CNTLF1:	CAML	I,C		;GOT TO END OF RANGE?
	JRST	ARGINA		;YES, RETURN ANSWER
	CALL	GET		;GET CHARACTER
	CAIN	CH,.CHLFD	;GOT A LINE FEED?
	ADDI	A,1		;YES, COUNT IT
	AOJA	I,CNTLF1	;AND GO GET NEXT CHARACTER
;"E" - ENDLINE, GOES TO END OF SAME LINE THAT "L" GOES TO BEGINNING
;OF, EXCEPT DEFAULT ARG IS 0, I.E. GO TO END OF CURRENT LINE

ELINE:	SKIPN EXECOP		;[502] IS AN OP WAITING?
	TXNE FF,ARG		;[502] OR AN ARG?
	JRST .+2		;[502] YES, GO HANDLE LIKE THE "L" COMMAND
	JRST ELINE0		;[502] NEITHER, GET TO END OF THIS LINE
	CALL GETARG
	XOR C,P1		;SET PT TO WHICHEVER ARG ISN'T PT
	XORM C,PT
ELINE0:	CALL TOEOL		;MOVE PT TO END OF CURRENT LINE
	JRST CFLUSH

;SUBROUTINE TO MOVE PT TO END OF CURRENT LINE

TOEOL:	MOVE I,PT
	MOVE P1,ZEE
	SUB P1,I		;COMPUTE MAX NUMBER CHARS TO SKIP
	JUMPE P1,CPOPJ		;NOP IF AT END OF BUFFER
	CALL GET		;GET FIRST CHAR
TOEOL1:	AOS PT			;SKIP ONE CHAR
	CAIN CH,.CHLFD		;JUST PASSED END OF LINE?
	JRST TOEOL2		;YES
	UILDB CH,TT		;NO, GET NEXT CHAR
	SOJG P1,TOEOL1		;COUNT CHARS
	RET			;AT END OF BUFFER

;BACKUP OVER END OF LINE CHARACTER AND ANY CR'S WHICH MAY HAVE
;PRECEEDED IT

TOEOL2:	SOS C,PT		;BACKUP OVER CHAR
	CAMG C,BEG		;AT TOP OF BUFFER?
	RET			;YES, DONE
	CALL DBP
	LDB CH,TT		;GET PRECEEDING CHAR
	CAIN CH,.CHCRT		;A CR?
	JRST TOEOL2		;YES, BACK OVER IT TOO
	RET			;NO, DONE
;ROUTINE TO RETURN CURRENT ARGUMENT IN c
;ASSUMES A VALUE OF 1 WITH SIGN OF LAST OPERATOR
;IF THERE IS NO CURRENT ARGUMENT
;CALL CALL CHK2
;	RETURN WITH C:=CURRENT ARG.,+1 OR -1

CHK2:	TXNN FF,ARG		;IS THERE AN ARGUMENT?
	JRST CHK22		;NO, GO CONJURE ONE UP
	MOVE C,FARG		;[502] YES, GET IT
	RET			;DONE

CHK22:	MOVE C,EXECOP		;[502] WHAT IS THE CURRENT OP?
	SETZM EXECOP		;[502] AND BLOW AWAY THE OP
	CAIE C,OP.SUB		;[502] REAL MINUS SIGN?
	TDZA C,C		;[502] NO, 0 (WILL BECOME 1)
	HRROI C,-2		;[502] YES, -2 (WILL BE -1)
	AOJA C,CPOPJ

;NK PERFORM NL BUT DELETE EVERYTHING THE POINTER MOVES OVER.
;M,NK DELETE THE (M+1)TH THROUGH THE NTH CHARACTER FROM THE BUFFER.
;	THE POINTER IS THEN PUT WHERE THE DELETION TOOK PLACE.
;K SAME AS 1K

KILL:	CALL GETARG		;p1:=FIRST STRING ARG. ADDRESS
				;c:=SECOND STRING ARG. ADDRESS
KLBUF:	CAMN P1,BEG
	CAME C,ZEE
	CAIA
	JRST HKC		;[502] BECOME AN HK COMMAND
	MOVEM P1,PT		;PT:=C(p1)
	SUB C,P1		;C:=NO. OF CHARACTERS TO KILL.
	JUMPE C,CFLUSH		;[507] NONE. GO CLEAR FLAGS.
	JRST KLB1

KLBUF1:	TXO FF,RPLFG
	CALL KLBUF
	TXZ FF,RPLFG
	RET
;ND DELETE N CHARACTERS FROM THE BUFFER: IF N IS POSITIVE, DELETE
;	THEM JUST TO THE RIGHT OF THE POINTER; IF N IS NEGATIVE, DELETE
;	THEM JUST TO ITS LEFT.
;D SAME AS 1D

DELETE:	CALL CHK2		;MAKE SURE c CONTAINS AN ARGUMENT
KLB1:	SKIPE ABORTF		;ABORT?
	RET			;YES
	MOVE A,C		;GET NUMBER OF CHARACTERS TO DELETE
	CALL ERASE		;[502] DO IT
	JRST CFLUSH		;[502] AND DONE

;ROUTINE TO KILL ENTIRE BUFFER.  THIS IS CODED AS A SPECIAL CASE SO
;THAT WE DON'T WASTE TIME MOVING THE HOLE TO THE POINT WHERE THE
;DELETION IS TAKING PLACE.

HKC:	CALL HK			;[502] DO THE WORK
	JRST CFLUSH		;[502] AND DONE

HK:	MOVE A,BEG
	MOVEM A,ZEE		;RESET END OF BUFFER TO BEGINNING
	MOVEM A,PT		;PUT POINTER AT BEGINNING TOO
	CALLRET MAKHOL		;RECREATE THE HOLE AND RETURN

;ROUTINE TO ERASE CHARACTERS FROM BUFFER AT THE POINTER.  TAKES NUMBER
;OF CHARACTERS IN A, WHERE POSITIVE MEANS DELETE THEM TO RIGHT OF
;POINTER AND NEGATIVE MEANS DELETE THEM TO LEFT OF POINTER.

ERASE:	STKVAR <COUNT>		;CELL TO HOLD NUMBER OF CHARACTERS BEING DELETED
	MOVEM A,COUNT		;REMEMBER HOW MANY
	MOVE C,A
	ADD C,PT		;c:=PT+c
	CALL CHK		;STILL IN DATA BUFFER?
	MOVE A,PT
	SKIPL B,COUNT
	ADD A,B

;**NOTE: HIGH EFFICIENCY "X" OPERATION ASSUMES THAT THE ERASE ROUTINE
;POSITIONS THE HOLE TO THE RIGHT OF THE DELETION-ELECT.

	CALL MOVHOL		;PUT THE HOLE TO RIGHT OF DELETION-ELECT
	MOVM A,COUNT		;GET EXTRA HOLE SIZE
	MOVN A,A		;GET NEGATIVE
	ADDM A,ZEE		;Z ALWAYS GOES DOWN FOR A DELETION
	ADDM A,HOLBEG		;HOLE STARTS FURTHER LEFT AFTER DELETION
	SKIPGE A,COUNT		;DELETING TO LEFT OF POINTER?
	ADDM A,PT		;YES, SO POINTER MOVES LEFT TOO
	CALL SETHPT		;SET HOLE POINTERS
	RET			;DONE

;ROUTINE TO CHECK DATA BUFFER POINTER
;CALL MOVE c,POINTER
;	CALL CHK
;	RETURN IF c LIES BETWEEN BEG AND Z

CHK:	CAMG C,ZEE
	CAMGE C,BEG
	ERROR <Argument out of range>
	RET

;ROUTINE TO PUT STRING ARGUMENT ADDRESSES WITHIN DATA BUFFER
;BOUNDS AND CHECK ORDER RELATION.
;CALL MOVE p1,FIRST STRING ARGUMENT ADDRESS
;	MOVE c,SECOND STRING ARGUMENT ADDRESS
;	CALL CHK1
;	RETURN
;p1:=MAXI(BEG,C),BEG), c:=MIN(p1(c),Z)
;IF p1 .G. c, DOES NOT RETURN.

CHK1:	CAMG P1,BEG		;p1:=MAX(p1(p1),BEG)
	MOVE P1,BEG
	CAML C,ZEE		;c:=MIN(p1(c),Z)
	MOVE C,ZEE
	CAMLE P1,C		;p1 .G. c?
	ERROR <Second argument is not greater than first>
	RET			;NO

;ROUTINE TO PARSE A SEARCH STRING.
;ACCEPTS:	A/	0 FOR PARSING FROM COMMAND STRING, NON-0 FOR REPARSING
;
;RETURNS:	+1	ALWAYS

SPARSE:	TRVAR <RPCNT,RPPTR,RPRSF,RBEG,REND,<SMAT0,4>>	
				;200(8) BITS, ONE FOR EACH CHARACTER
	MOVEM A,RPRSF		;REMEMBER WHETHER REPARSING
	JUMPN A,[	MOVE A,[POINT 7,SCHBUF]	
				;SET UP POINTER TO STRING BEING REPARSED
			MOVEM A,RPPTR
			MOVE A,SSLEN
				;REMEMBER HOW MANY CHARACTERS TO REPARSE
			MOVEM A,RPCNT
			JRST .+1]
	SETZM SMAT		;CLEAR THE MATRIX
	MOVE A,[SMAT,,SMAT+1]
	BLT A,SMAT+SMATLN-1
	MOVX P1,1B0		;BIT POSITION TO SET IN TABLE
	TXZ FF,NOTF		;NO "NOT" SEEN YET
	MOVE A,[POINT 7,SCHBUF]	;POINTER TO SEARCH STRING BUFFER
	MOVEM A,SCHPTR
	SETZM SSLEN		;INITIALIZE THE SEARCH STRING LENGTH
SER1:	SKIPE RPRSF		;REPARSING?
	JRST [	SKIPG RPCNT	;YES, HAVE WE REACHED END OF STRING?
		JRST SP1	;YES
		CALL GETSCH	;NO, GET NEXT CHARACTER (CNT DEC'D AT GETSCH)
		JRST SER2]	;DON'T CHECK FOR TERMINATOR!
	CALL GETSCH		;GET NEXT CHARACTER FROM SEARCH STRING
	CAMN CH,SDELIM		;END OF SEARCH STRING?
	JRST SP1		;YES
SER2:	JUMPE P1,[ERROR <Search string more than 36 character positions long>]
	CALL SCHST1		;STUFF SEARCH CHARACTER INTO STRING
	CALL SCHAR		;GET BITS FOR CHARACTER
	MOVSI T,-200		;COPY BITS INTO P1TH COLUMN OF SMAT
	MOVE TT,[POINT 1,A]	;1-BIT BYTE POINTER TO BITS (440100)
SER3:	ILDB CH,TT		;GET NEXT BIT
	CAIE CH,0		;SET THIS BIT?
	IORM P1,SMAT(T)		;YES
	AOBJN T,SER3
	LSH P1,-1		;STEP TO NEXT COLUMN IN MATRIX
	JRST SER1		;LOOP FOR REST OF SEARCH STRING

SP1:	MOVE A,P1
	JFFO A,SEOS3		;GET NUMERICAL LENGTH OF SEARCH STRING
	MOVEI B,^D36		;IF A IS 0, THEN SEARCH STRING LENGTH IS 36
SEOS3:	MOVEM B,SCHLNN		;REMEMBER IT
	SETOB A,B		;A ACCUMULATES BITS THAT ARE 1 FOR ALL
				; CHARACTERS MATCHING FIRST FIVE,
				; B ACCUMULATES 0'S
	MOVSI C,-SMATLN		;POINTER TO SEARCH MATRIX
ZLUP1:	LDB D,[370500,,SMAT(C)]	;GET WHICH POSITIONS THIS CHARACTER MAY MATCH IN
	HRRZ P1,C		;GET THE CHARACTER
	MUL P1,[<BYTE(7)1,1,1,1,1>];MAKE FIVE COPIES
	LSH P2,1
	LSHC P1,-1		;GET ALL FIVE COPIES IN ONE WORD
	MOVE P1,P2		;COPY OF CHARACTERS IN P1
;*
;1 TURN ALL BITS ON IN POSITIONS WHERE THIS CHARACTER ISN'T SUPPOSED TO MATCH
;2 TURN ALL BITS OFF IN COLUMNS THAT AREN'T SUPPOSED TO MATCH THIS CHARACTER
;3 ACCUMULATE BIT POSITIONS THAT ARE ON FOR ALL CHARACTERS THAT MAY MATCH
;4 ACCUMULATE BITS THAT ARE OFF FOR ALL CHARACTERS THAT MAY MATCH THIS POSITION
	ORCM P1,MSKTAB(D)	;*1
	AND P2,MSKTAB(D)	;*2
	AND A,P1		;*3
	ANDCM B,P2		;*4
	AOBJN C,ZLUP1		;LOOP FOR ALL CHARACTERS
	IOR A,B			;NOW A HOLDS ALL BITS THAT ARE THE SAME
				; FOR ALL CHAR THAT MATCH IN FIRST 5 POSITIONS
	MOVE B,SCHLNN		;SEE HOW LONG SEARCH STRING IS
	CAIG B,5		;LESS THAN 5?
	TDZ A,DNTCAR(B)		;GET RID OF BITS WE DON'T CARE ABOUT
	LSH A,-1		;WORD DURING SEARCH WILL BE RIGHT-JUSTIFIED
	MOVEM A,CARBTS		;REMEMBER BIT POSITIONS WE CARE ABOUT
	MOVSI A,-SMATLN		;LOOP TO GET SOME STRING THAT MATCHES
	MOVEI B,0		;THIS WILL BECOME SOME STRING THAT'S...
				; A MATCH FOR THE FIRST 5 CHARS OF
				; THE SEARCH STRING
	SETO C,			;THIS SHOWS POSITIONS YET TO BE FILLED
GEN0:	SKIPN P1,SMAT(A)	;DOES THIS CHARACTER MATCH ANYWHERE?
	JRST GEN1		;NO
	TLNE P1,(1B0)		;IS THIS CHARACTER A MATCH FOR THE 1ST POSITION
	TLNN C,(1B0)		;DOES FIRST POSITION NEED FILLING?
	JRST GEN2		;NO
	DPB A,[350700,,B]	;FOUND A CHARACTER FOR FIRST POSITION
	TLZ C,(177B6)		;REMEMBER THAT WE FOUND ONE
GEN2:	TLNE P1,(1B1)		;SAME FOR SECOND CHARACTER POSITION
	TLNN C,(1B7)
	JRST GEN3
	DPB A,[260700,,B]
	TLZ C,(177B13)
GEN3:	TLNE P1,(1B2)
	TLNN C,(1B14)
	JRST GEN4
	DPB A,[170700,,B]
	TDZ C,[177B20]
GEN4:	TLNE P1,(1B3)
	TRNN C,1B21
	JRST GEN5
	DPB A,[100700,,B]
	TRZ C,177B27
GEN5:	TLNE P1,(1B4)
	TRNN C,1B28
	JRST GEN1
	DPB A,[010700,,B]
	TRZ C,177B34
GEN1:	AOBJN A,GEN0		;LOOP FOR ALL CHARACTERS
	MOVE A,SCHLNN		;SEE HOW MANY POSITIONS WE SHOULD HAVE
				; FOUND CHARACTERS FOR
	TRZ C,1			;GET RID OF B35
	CAIG A,5
	TDZ C,DNTCAR(A)		;GET RID OF BITS WE DON'T CARE ABOUT
	JUMPN C,SFAIL		;IF SOME BITS DIDN'T GET CLEARED,
		; THERE'S NO POSSIBLE STRING THAT COULD MATCH THE SEARCH!
	MOVEM B,MATCH		;REMEMBER STRING THAT MATCHES THE SEARCH
	LSH B,-1		;RIGHT-JUSTIFY
	AND B,CARBTS		;KEEP ONLY BITS WE CARE ABOUT
	MOVEM B,SMASK		;REMEMBER MASK FOR SEARCH LOOP

;WHEN SEARCHING IN REVERSE, THE LSHC'S SHIFT THE UNUSED B35 THROUGH THE
;WORD WE'RE TESTING.  ONE WAY TO AVOID THIS IS COLLAPSE THE TWO WORDS
;BEFORE SHIFTING.  HOWEVER, THIS IS AN EXTRA INSTRUCTION EVERY TIME
;THROUGH THE SEARCH LOOP.  INSTEAD, AFTER EVERY SHIFT, WE'LL USE A
;DIFFERENT SET OF MASKS TO TEST THE WORD, MASKS WHICH ASSUME THE
;B35 MOVES THROUGH THE WORD.  THE FOLLOWING TWO CALLS TO GENTAB
;GENERATE THE SPECIAL VERSIONS OF THE TWO MASKS.

	MOVE P1,CARBTS		;MASK SHOWING BIT POSITIONS WE CARE ABOUT
	MOVEI P2,CARTAB	;ADDRESS OF TABLE TO RECEIVE VERSIONS OF THE MASK
	CALL GENTAB		;GENERATE THE DIFFERENT VERSIONS
	MOVE P1,SMASK		;MASK SHOWING WHAT WE'RE LOOKING FOR
	MOVEI P2,SMTAB		;TABLE TO RECEIVE DIFFERENT VERSIONS
	CALLRET GENTAB

;ROUTINE TO READ NEXT CHARACTER FROM COMMAND STRING AND STUFF IT INTO
;SEARCH STRING

SCHSTF:	CALL GETSCH		;READ CHARACTER
SCHST1:	AOS A,SSLEN		;SEE HOW MANY CHARACTERS THIS WILL BE
	CAILE A,SMAXLN		;STILL WITHIN RANGE?
	ERROR <Too many characters in search string>
	IDPB CH,SCHPTR		;STORE CHARACTER IN SEARCH STRING
	RET

;ROUTINE CALLED DURING SEARCH PARSING TO GET NEXT CHARACTER FROM SEARCH
;STRING.  DURING A SEARCH COMMAND.

GETSCH:	SKIPN RPRSF		;REPARSING?
	CALLRET SKRCH		;NO, GO READ CHARACTER FROM COMMAND STRING
	SOS RPCNT		;GET THE $%$^%# COUNT RIGHT!
	ILDB CH,RPPTR		;YES, GET NEXT CHARACTER BEING REPARSED
	RET

;CALL HERE TO SAVE COMMAND STATE ON STACK

SAVCMD:	POP P,B			;GET RETURN ADDRESS
	MOVX A,CMMSK		;GET VALUE TO CHECK AT RESCMD TIME...
	MOVEM A,CMSMK		;AND STORE
	HRRI A,1(P)		;GET STACK ADDRESS FOR SAVING ARGS
	ADJSP P,CBLEN		;ALLOCATE ROOM FOR BLOCK
	HRLI A,CBBLK		;GET STARTING ADDRESS OF BLOCK
	BLT A,(P)		;PUT COMMAND STATE ON STACK
	JRST (B)		;RETURN TO CALLER

;HERE TO READ SAVED STATE BUT *NOT* REMOVE IT FROM THE STACK

REACMD:	POP P,A			;GET RET ADDRESS
	MOVX B,CMMSK		;GET CHECK WORD
	CAME B,(P)		;IS LAST WORD CORRECT?
	JRST RESQE		;NOPE!
	MOVSI B,1-CBLEN(P)	;GET ADDRESS OF STATE
	HRRI B,CBBLK		;ADDRESS OF BLOCK TO RESTORE STATE TO
	BLT B,CBBLK+CBLEN-1	;RESTORE IT
	JRST (A)		;GO LEAVE

;HERE TO RESTORE PREVIOUS COMMAND STATE

RESCMD:	POP P,A			;GET RETURN ADDRESS
	MOVX B,CMMSK		;CHECK LEGALITY
	CAME B,(P)		;OK?
RESQE:	ERROR <Command state not saved, check angle brackets and parentheses>
	HRLI B,1-CBLEN(P)	;GET ADDRESS OF SAVED STATE
	HRRI B,CBBLK		;ADDRESS OF STATE BLOCK
	BLT B,CBBLK+CBLEN-1	;RESTORE STATE
	ADJSP P,-CBLEN		;RELEASE STACK SPACE
	JRST (A)		;RETURN TO CALLER

;ROUTINE TO TURN ON CORRECT BITS IN MATRIX ACCORDING TO WHAT THE NEXT CHARACTER
;IS. CALL WITH CHARACTER IN CH.

SCHAR:	STKVAR <NOTFLG,<SAVSM,4>>
	HRLI A,SMAT0		;SAVE AWAY MATRIX WHILE WE USE IT
	HRRI A,SAVSM
	BLT A,3+SAVSM
	SETZB A,SMAT0		;CLEAR OUT THE BIT TABLE
	SETZB B,1+SMAT0
	DMOVEM A,2+SMAT0	;VERY SLIGHTLY CLEVER
	SETZM NOTFLG		;HAVEN'T SEEN ^N YET
SCHNOT:	CAIN CH,"N"-100		;NOT?
	JRST [	SETCMM NOTFLG	;YES, REVERSE DECISION OF WHETHER TO NEGATE
		CALL SCHSTF	;READ AND STUFF NEXT CHARACTER
		JRST SCHNOT]	;MAYBE DOUBLE NEGATIVE
	CAIE CH,"Q"-100		;^Q?
	CAIN CH,C.QUOT		;QUOTING THE NEXT CHARACTER?
	JRST [	CALL SCHSTF	;YES, READ CHARACTER BEING QUOTED
		CALL SETBIT	;SET BIT FOR LITERAL CHARACTER
		JRST SCHOUT]	;DONE
	CAIN CH,"E"-100		;IS IT SPECIAL SEARCH OPTION CHARACTER?
	JRST DOCE		;YES, GO HANDLE IT
	CAIN CH,"X"-100		;NO. ^X?
	JRST CNTRX		;YES
	CAIN CH,"S"-100		;NO. ^S?
	JRST CNTRB		;YES
	CALL SETBIT		;SET BIT FOR CHARACTER
	SKIPE EXACTF		;EXACT MATCH ONLY?
	JRST SCHOUT		;YES, DON'T SET OTHER CASE
	LOAD CH,UPRCOD,(CH)	;NO, GET UPPERCASE VERSION
	CALL SETBIT		;SET BIT FOR UPPERCASE
	LOAD CH,LWRCOD,(CH)	;GET LOWERCASE VERSION
	CALL SETBIT		;SET BIT FOR LOWERCASE
SCHOUT:	DMOVE A,SAVSM
	DMOVE C,2+SAVSM		;GET PRESERVED SMAT0 FROM PREVIOUS LEVEL
	EXCH A,SMAT0		;RESTORE PRESERVED SMAT0, GET OURS
	EXCH B,1+SMAT0
	EXCH C,2+SMAT0
	EXCH D,3+SMAT0
	SKIPE NOTFLG		;WAS "NOT" SPECIFIED?
	JRST [	SETCA A,	;YES, COMPLEMENT ALL THE BITS
		SETCA B,
		SETCA C,
		SETCA D,
		RET]
	RET


;CNTR X MATCHES ANY ARBITRARY CHARACTER

CNTRX:	SETOB A,SMAT0
	SETOB B,1+SMAT0		;MATCH EVERYTHING
	DMOVEM A,2+SMAT0
	JRST SCHOUT

;HERE TO HANDLE ^E.  THIS ROUTINE RECURSES FOR USEFUL THINGS LIKE
;^E[A,B,^E<12>] ( FIND A OR B OR LINEFEED) AND USELESS THINGS
; LIKE ^E[A,B,^E[C,D]] ( FIND A OR B OR C OR D)

DOCE:	CALL SCHSTF		;PUT CHARACTER IN SEARCH STRING
	CAIE CH,74		;NUMBER COMING UP? (74 IS OPEN ANGLE BRACK)
	JRST SNOTDG		;NO

;OCTAL DIGITS AFTER CTRL/E MEANS CHARACTER WITH SPECIFIED ASCII VALUE

	MOVX P2,1B0		;START WITH 1B0 SO WE'LL KNOW IF ANYTHING TYPED

SDIG1:	CALL PEEKCH		;PEEK AT NEXT CHARACTER
	 JRST SDIGE		;AREN'T ANY MORE!
	CAIL CH,"0"		;OCTAL DIGIT?
	CAILE CH,"7"		;..
	JRST SDIGE		;NO
	LSH P2,3		;YES, MAKE ROOM FOR IT
	CALL SCHSTF		;REALLY READ IT THIS TIME!
	IORI P2,-"0"(CH)	;ACCUMULATE DIGIT
	JRST SDIG1		;GET REST OF DIGITS

SDIGE:	CALL SCHSTF		;MAKE SURE THERE'S A CLOSING BRACKET
	CAIE CH,76		;76 IS CLOSE ANGLE
	ERROR <Angle bracket missing after number in search string>
	JUMPL P2,CPOPJ		; MAKE ^E<> BE A NOOP
	MOVE CH,P2		;SPECIFY WHICH CHARACTER TO SET
	CALL SETBIT
	JRST SCHOUT

;^E NOT FOLLOWED BY OCTAL DIGIT

SNOTDG:	LOAD CH,UPRCOD,(CH)	;GET UPPERCASE
	CAIN CH,"["		;SEE IF OPEN BRACKET...
	JRST SBRAK		;YES, GO PROCESS
	CAIN CH,"A"
	JRST SBALPH		;ANY ALPHABETIC
	CAIN CH,"C"
	JRST SBSYM		;ANY SYMBOL CONSTITUENT
	CAIN CH,"D"
	JRST SBDIG		;ANY DIGIT
	CAIN CH,"P"
	JRST SBPUN		;PUNCTUATION
	CAIN CH,"V"
	JRST SBLOW		;ANY LOWERCASE LETTER
	CAIN CH,"W"
	JRST SBHGH		;ANY UPPERCASE
	CAIN CH,"Y"
	JRST SBUSR		;USER DEFINED HITS
	CAIN CH,"X"
	JRST CNTRX		;ANYTHING
	ERROR <Illegal character after CTRL/E in search string>

;Edit 509
;The following defines are used to build the code to OR in bits to SMAT0.
;I$MSK clears the bits, and should be done before each set of MA$MSKs.
;Each MA$MSK generates 3 (or 6) instructions which light all the bits that
;represent the two characters passed to it, and all the ones inbetween. IE,
;MA$MSK "E","H"  would turn on the bits for E,F,G and H in the SMAT0 array.

;This could have been done a LOT simpler, but future expansion is easier
; this way.

;Isolate the RH or the LH moved to the RH with these.

	DEFINE $RH(V),< <<V>&<0,,-1>> >
	DEFINE $LH(V),< <<<V>&<-1,,0>>_-^D18> >

;DMOVXX tries to load AC,AC+1 with V1 and V2 in the least number of words.

	DEFINE DMOVXX (AC,V1,V2),<
	 %%A1==$RH <V1>
	 %%A2==$LH <V1>
	 %%B1==$RH <V2>
	 %%B2==$LH <V2>
	 IFE $RH <%%A1+1>,<%%A1==0>
	 IFN %%A1,<%%A1==-1>
	 IFE $RH <%%A2+1>,<%%A2==0>
	 IFN %%A2,<%%A2==-1>
	 IFE $RH <%%B1+1>,<%%B1==0>
	 IFN %%B1,<%%B1==-1>
	 IFE $RH <%%B2+1>,<%%B2==0>
	 IFN %%B2,<%%B2==-1>
	 %%A== <%%A1&%%A2>!<%%B1&%%B2>
	 IFN %%A,<	DMOVE AC,[EXP <V1>,<V2>]>
	 IFE %%A,<	MOVX AC,<V1>
			MOVX <AC+1>&17,<V2> > >


	DEFINE I$MSK,<
	 %%W0==0
	 %%W1==0
	 %%W2==0
	 %%W3==0>

	DEFINE OR$MSK (SY,BI),<
	 %%W'SY'==%%W'SY'!BI>

	DEFINE MA$MSK (CH1,CH2,PTQ<-1>),<
	 %%C==CH1
	 %%N==CH2-%%C+1
	 IFLE %%N,<FOAD <Bad args to MA$MSK>>
	 REPEAT %%N,<
	  %%W==%%C/44
	  %%B==<1B0>_<%%W*44-%%C>
	  OR$MSK \%%W,%%B
	  %%C==%%C+1>
	 IFN PTQ,<
	  IFN %%W0,<
	   IFE %%W1,<	MOVX A,%%W0
			IORM 0+SMAT0>
	   IFN %%W1,<	DMOVXX A,%%W0,%%W1
			IORM A,0+SMAT0
			IORM B,1+SMAT0
			 %%W1==0>
	  >
	  IFN %%W1,<
	   IFE %%W2,<	MOVX A,%%W1
			IORM A,1+SMAT0>
	   IFN %%W2,<	DMOVXX A,%%W1,%%W2
			IORM A,1+SMAT0
			IORM B,2+SMAT0
			 %%W2==0>
	  >
	  IFN %%W2,<
	   IFE %%W3,<	MOVX A,%%W2
			IORM A,2+SMAT0>
	   IFN %%W3,<	DMOVXX A,%%W2,%%W3
			IORM A,2+SMAT0
			IORM B,3+SMAT0
			 %%W3==0>
	  >
	  IFN %%W3,<	MOVX A,%%W3
			IORM A,3+SMAT0>
	 > >


;^EA MATCHES ANY ALPHABETIC

SBALPH:	I$MSK
	MA$MSK "a","z",0	;get lowercase, inhibit code gen.
	MA$MSK "A","Z"		;ADD UPPERCASE AND PUNCH OUT CODE
	JRST SCHOUT

;^ED MATCHES ANY DIGIT

SBDIG:	I$MSK
	MA$MSK "0","9"
	JRST SCHOUT

;^EV MATCHES ANY LOWERCASE LETTER

SBLOW:	I$MSK
	MA$MSK "a","z"
	JRST SCHOUT

;^EW MATCHES ANY UPPERCASE LETTER

SBHGH:	I$MSK
	MA$MSK "A","Z"
	JRST SCHOUT

	PURGE %%W,%%B,%%N,%%C,%%W0,%%W1,%%W2,%%W3
	IF2, <PURGE I$MSK,OR$MSK,MA$MSK>
;End edit 509

;DO ANY CHARACTER THAT THE USER FLAGGED WITH THE ;@q COMMAND

SBUSR:	SETOM CEYFLG		;NOTE THAT ^EY IS BEING DONE
	MOVX C,CH%USR
	JRST SBSETA

;DO ANY NON-SYMBOL CHARACTER (^S=^N^EC)

CNTRB:	SETCMM NOTFLG		;SAY "NOT" AND FALL INTO SYMBOL CODE
	;JRST SBSYM

;^EC MATCHES ANY SYMBOL CONSTITUENT

SBSYM:	MOVX C,CH%SBL
	JRST SBSETA

;DO ANY PUNCTUATION CHARACTER (^EP)

SBPUN:	MOVX C,CH%PN1		;PUNCTUATION
	;JRST SBSETA

;HERE TO LIGHT BITS IN SMAT0 ACCORDING TO THE CONTENTS OF C AND
; THE CHRTAB ARRAY.

SBSETA:	MOVEI CH,177		;SCAN CHRTAB
SBUSR1:	MOVE A,CHRTAB(CH)	;GET VALUE FROM TABLE...
	TDNE A,C		;DID USER LIGHT THE BIT FOR THIS CHAR?
	CALL SETBIT		;AH HA! FLAG IT.
	SOJGE CH,SBUSR1		;AND GO FOR NEXT
	JRST SCHOUT

;SET THE BIT INDICATED BY CH IN SMAT0

SETBIT:	MOVE A,CH
	IDIVI A,44		;FIGURE OUT WHICH WORD AND BIT
	ADDI A,SMAT0		;SMAT0 IS AN INDEXED REFRENCE
	MOVE B,SBITS(B)		;GET CORRECT BIT
	IORM B,(A)		;TURN IT ON IN THE PROPER WORD
	RET

;^E FOLLOWED BY [CH1,CH2,CH3...] MEANS MATCH ANY OF THE LISTED ITEMS

SBRAK:	CALL SCHSTF		;READ ITEM
	CALL SCHAR		;ACCUMULATE IT AS A MATCH
	IORM A,SMAT0		;ACCUMULATE CHOICES
	IORM B,1+SMAT0
	IORM C,2+SMAT0
	IORM D,3+SMAT0
	CALL SCHSTF		;READ CLOSING BRACKET OR COMMA
	CAIN CH,","		;COMMA?
	JRST SBRAK		;YES, GO GET NEXT ITEM
	CAIE CH,"]"		;IF NOT COMMA, BETTER BE CLOSING BRACKET
	ERROR <Comma or "]" required>
	JRST SCHOUT

;TABLE OF BIT POSITIONS WE DON'T CARE ABOUT, USED TO MASK OUT
;CHARACTER POSITIONS WHEN SEARCH STRING IS LESS THAN 5 CHARACTERS.

DNTCAR:	-1
	<BYTE(7)0,177,177,177,177>!1;LENGTH IS ONE, LEEP ONLY FIRST POSITION
	<BYTE(7)0,0,177,177,177>!1 ;KEEP 2 FOR 2 ETC.
	<BYTE(7)0,0,0,177,177>!1
	<BYTE(7)0,0,0,0,177>!1
	1			;FOR 5 OR OVER, KEEP ALL

;TABLE OF MASKS FOR CHARACTER POSITIONS.  WORD N OF THIS TABLE
;CONTAINS BYTE(7)M,M,M,M,M  WHERE N IN BINARY IS MMMMM, EXCEPT THAT
;INSTEAD OF 0'S AND 1'S FOR THE M'S, 0'S AND 177'S ARE USED.

MSKTAB:
DEFINE GENMSK(N)
<
 BYTE(7)<<N_-4>*177>,<<N_-3>&1*177>,<<N_-2>&1*177>,<<N_-1>&1*177>,<N&1*177>
>
%%X==0
%%X==0
REPEAT 2*2*2*2*2,<
	GENMSK(%%X)
%%X==%%X+1
>

;ROUTINE WHICH TAKES A WORD IN P1 AND A TABLE ADDRESS IN P2, AND
;STORES THE CONTENTS OF P1 IN THE 5 ELEMENTS OF THE TABLE, EACH COPY
;HAVING A GAP IN A DIFFERENT BIT POSITION

GENTAB:	MOVE B,P1		;GET COPY OF WORD
	LSH B,1			;GET GAP AT B35
	MOVEM B,(P2)		;STORE IN TABLE
	MOVE B,(P2)
	LSHC A,7
	LSH B,-1
	LSHC A,-7		;PUT GAP AT B7
	MOVEM B,1(P2)
	MOVE B,(P2)
	LSHC A,^D14
	LSH B,-1
	LSHC A,-^D14		;PUT IT AT B14, ETC.
	MOVEM B,2(P2)
	MOVE B,(P2)
	LSHC A,^D21
	LSH B,-1
	LSHC A,-^D21
	MOVEM B,3(P2)
	MOVE B,(P2)
	LSHC A,^D28
	LSH B,-1
	LSHC A,-^D28
	MOVEM B,4(P2)
	RET

;ROUTINE WHICH SKIPS IF DIFFERENT SEARCH BEING DONE THIS TIME THAN
;LAST

NOTSAM:	MOVE A,CPTR		;GET POINTER TO CURRENT COMMAND STRING
	MOVE T,SSLEN		;GET LENGTH OF LAST SEARCH STRING
	MOVE B,[POINT 7,SCHBUF]	;GET POINTER TO LAST SEARCH STRING
	MOVE C,COMCNT		;GET MAXIMUM CHARACTERS TO COMPARE
NOTS1:	SOJL C,CPOPJ1		;SAY NOT THE SAME IF CURRENT RUNS OUT
	ILDB D,A		;GET CHARACTER FROM COMMAND STRING
	CAMN D,SDELIM		;HAVE WE COME TO DELIMITER IN COMMAND STRING?
	JRST NOTS2		;YES, MAYBE SEARCH IS SAME AS LAST TIME
	SOJL T,CPOPJ1		;STRINGS DIFFERENT IF LAST ONE SHORTER
	ILDB CH,B		;AND ONE FROM LAST SEARCH STRING
	CAME D,CH		;THE SAME?
	JRST	CPOPJ1		;DIFFERENT SEARCH, SKIP RETURN
	JRST NOTS1		;LOOP TO CHECK REST OF STRINGS

NOTS2:	JUMPE T,CPOPJ		;IF LAST SEARCH STRING RUNS OUT WHEN WE
		; FIND DELIMITER IN BUFFER, WE'VE GOT SAME SEARCH AS LAST TIME
	JRST CPOPJ1		;NEW SEARCH SHORTER, SO IT'S DIFFERENT

;COME HERE WHEN WE KNOW THE CURRENT SEARCH IS THE SAME AS THE LAST ONE,
;BECAUSE THE SPECIFIED STRING IS EXACTLY THE SAME AS THE LAST ONE.
;WE MUST NOW SKIP OVER THE SEARCH STRING IN THE COMMAND BUFFER.

SERCH3:	ILDB C,CPTR		;GET CHARACTER FROM SEARCH STRING
	SOS COMCNT		;ACCOUNT FOR IT BEING READ
			; (WE'VE ALREADY MADE SURE WE'LL FIND A DELIMITER)
	CAME C,SDELIM		;THE DELIMITER YET?
	JRST SERCH3		;NOT YET
	JRST SERCH9		;GO DO SAME SEARCH AS LAST TIME


;ENTER AT SERCH0 WITH ARG FOR SEARCH IN A.  

SERCH0:	MOVEM A,SCHARG		;SAVE ARG
	JRST SERCH1		;FALL INTO COMMON CODE

LARR:	TXOA FF,FINDR		;FINDR:=1 FOR LEFT ARROW SEARCH

SERCHP:	TXO FF,PCHFLG		;PCHFLG:=1 FOR N SEARCH

;ENTRY FOR S COMMAND IS HERE...

SERCH:	CALL CHK2		;MAKE SURE THERE IS AN ARG
	MOVEM C,SCHARG		;REMEMBER ARG
SERCH1:	MOVEI CH,.CHESC		;USE ALT-MODE DELIMITER IF NO @ SEEN
	TXNE FF,SLSL		;@ SEEN?
	CALL RCH		;YES. CH:=USER SPECIFIED DELIMITER.
	MOVEM CH,SDELIM		;REMEMBER DELIMITER

;SET UP SEARCH TABLE

SERCH2:	CALL PEEKCH		;PEEK AT NEXT CHARACTER
	 JRST SERCH4		;IF THERE ISN'T ONE, IT'S NOT THE ONE SOUGHT!
	CAME CH,SDELIM		;THE DELIMITER?
	JRST SERCH4		;NO, PERHAPS DIFFERENT SEARCH
	CALL SKRCH		;YES, REALLY READ IT.
	JRST SERCH9		;GO DO SAME SEARCH AS LAST TIME
SERCH4:	CALL NOTSAM		;SKIP IF DIFFERENT SEARCH BEING DONE
	 JRST SERCH3		;SAME ONE, GO DO IT
	MOVEI A,0		;SAY WE'RE READING SEARCH FROM COMMAND STRING
	SETZM CEYFLG		;WE HAVEN'T SEEN A ^EY YET
	CALL SPARSE		;PARSE THE SEARCH STRING
	SETZM SRPF		;IF JUST READ FROM COMMAND STRING,
				; NO REPARSE NEEDED
SERCH9:	SKIPN SSLEN		;MAKE SURE WE'VE DONE A SEARCH BEFORE.
	ERROR <No default search string set up yet>
	MOVEI A,1
	SKIPE SRPF		;REPARSE DEFAULTED SEARCH IF 1^X OR 0^X TYPED
	CALL SPARSE		;CAN'T CALL SPARSE AT SSERCH,
				; SINCE IT MAY GO TO SFAIL!
	SETZM SRPF		;NO MORE REPARSE NEEDED
	MOVE B,SCHARG		;GET ARG BEFORE IT GETS COUNTED TO 0
	MOVEM B,SOARG		;REMEMBER IT
	JUMPE B,SRET1		;RETURN IMMEDIATELY IF 0S OR 0R

;ENTER HERE IF SEARCH MASKS ARE ALREADY SET UP.  FOR INSTANCE, DURING
; N OR _ OR F COMMAND, SEARCH IS RESUMED HERE AFTER NEW PAGE IS READ
;IN.  R COMMAND COULD BE MADE QUICKER IF IT WERE TAUGHT TO ENTER HERE
;TOO, ESPECIALLY FOR LARGE NUMERICAL ARGS TO R.

SERCHS:	MOVE A,PT		;REMEMBER WHERE CURRENT SEARCH STARTS
	MOVEM A,S0PT
	SKIPG SCHARG		;SEARCHING FORWARD?
	JRST SETBAK		;NO, BACKWARDS

; IN ORDER TO KNOW WHEN WE'VE HIT
;THE BUFFER HOLE, SO THAT WE CAN SKIP OVER IT, WE'LL PLANT A COPY OF A STRING
;THAT MATCHES THE SEARCH JUST AT THE HOLE BOUNDARY.  THIS WILL ALLOW
;US TO DETECT THE HOLE BECAUSE WE'LL GET A FALSE ALARM SEARCH MATCH.
;ALSO, WE'LL COPY A SMALL PART OF THE BUFFER THAT'S BEFORE THE HOLE
;INTO THE HOLE, SO THAT EVEN IF WHAT WE'RE LOOKING FOR CROSSES THE
;HOLE, WE'LL FIND IT.
;IN ADDITION, WE'LL PUT A MATCH AT THE END OF THE BUFFER TO CATCH
;FAILING SEARCHES - THAT IS, SEARCHES REALLY ALWAYS SUCCEED!

	MOVE I,HOLEND		;POINTER TO CHARS AFTER HOLE
	MOVE OU,HOLBEG		;WE WANT TO COPY THEM TO BEGINNING OF HOLE
	MOVE P1,SCHLNN		;WE NEED ONLY COPY ONE LESS THAN NUMBER
	SOJ P1,			;OF CHARS IN THE SEARCH STRING
	CALL MVCST		;COPY THE CHARS
	MOVE I,[5*MATCH]	;POINTER TO STRING GUARANTEED TO MATCH
	MOVE OU,SCHLNN		;WE WANT TO PUT IT ALMOST THIS MANY CHARS IN
	SOJ OU,			;ONE LESS BECAUSE N-1 CHARS WERE COPIED
	ADD OU,HOLBEG		;FIGURE WHERE TO COPY TO
	MOVEI P1,5		;ONLY COPY 5 CHARACTERS
	CALL MVCST		;COPY THE MATCH
	MOVE OU,[010700,,EMTBUF-1] ;WE ALSO WANT TO PUT MATCH AT END OF BUFFER
	MOVE I,[010700,,MATCH-1]
	MOVEI P1,5
	CALL MVSTR		;TO CATCH FAILING SEARCHES
	MOVE A,SCHLNN		;GET NUMBER OF CHARACTERS IN SEARCH STRING
	CAILE A,5
	MOVEI A,5		;FOR THIS CALCULATION, WE WANT 5 OR LESS
	MOVE B,A		;MAKE COPY FOR BYTE POINTER CALCULATION
	IMULI A,7		;FIGURE OUT HOW MANY BITS TO SHIFT
				; FOR GETTING TO NEXT FRAME
	MOVEM A,SLIDE		;REMEMBER HOW MANY
	MOVE C,FNXTAB-1(B)	;FIGURE OUT WHERE TO TRANSFER TO
	MOVEM C,NXTFRM		;REMEMBER WHEN GOING TO NEXT FRAME
	ADJBP B,[000700,,A-1]	;MAKE BYTE POINTER TO RIGHTMOST CHARACTER IN FRAME
	MOVEM B,SLAST		;REMEMBER POINTER TO LAST CHARACTER IN FRAME
	MOVE A,PT		;GET FIRST CHARACTER POSITION TO BE EXAMINED
	CAML A,HOLBEG		;ARE WE IN HOLE?
	ADD A,HOLSIZ		;GET ABSOLUTE CHARACTER ADDRESS
FSRCH:	IDIVI A,5		;NOW A SHOWS WHICH WORD CONTAINS FIRST CHARACTER
	MOVE C,FSTAB(B)		;C TELLS WHERE TO ENTER SEARCH LOOP
	MOVEM C,SADD		;REMEMBER WHERE TO ENTER LOOP
	IMULI B,7		;CALCULATE HOW MUCH TO SHIFT TO LEFT-JUSTIFY
				; FIRST CHARACTER
	MOVEI D,1(A)		;WORD POINTER TO BUFFER FOR SEARCH LOOP
	MOVEM D,SPTR		;REMEMBER WORD POINTER
	MOVE P1,B		;P1 NOW HOLDS HOW MUCH TO SHIFT AT THE START
	DMOVE A,-1(D)		;GET PRIMARY DATA
	LSH A,-1		;GET RID OF GAP AT B35
	LSHC A,(P1)		;SHIFT INTO CORRECT POSITION TO START SEARCH
	DMOVEM A,SDAT		;INITIALIZE SEARCH DATA
	JRST FLSALM		;INITIALIZE SEARCH BY SAYING "FALSE ALARM"

;TABLE OF PLACES TO TRANSFER TO IN FORWARD SEARCH LOOP WHEN WE'VE JUST
;SHIFTED OUR DATA OVER TO THE NEXT FRAME UPON DECIDING THAT SINCE
;RIGHTMOST CHARACTER OF LAST FRAME ISN'T ANYWHERE IN THE SOUGHT STRING,
;WE CAN SAVE TIME BY SKIPPING N CHARACTERS IN BUFFER WHERE N IS NUMBER
;OF CHARACTERS IN SEARCH STRING.

FNXTAB:	IFIW!S1			;SEARCH STRING IS ONE CHARACTER LONG
	IFIW!S2			;TWO CHARACTERS LONG
	IFIW!S3			;GET THE PATTERN?
	IFIW!S4
	IFIW!S5

;TABLE OF PLACES TO TRANSFER WITHIN THE BACKWARD SEARCH LOOP, AND DURING
;THE BACKWARD SEARCH LOOP, WHEN THE LEFTMOST CHARACTER OF THE CURRENT
;FRAME ISN'T ANYWHERE IN THE SOUGHT STRING.  IF THIS IS THE CASE,
;WE CAN SKIP N CHARACTERS OF THE BUFFER.

BNXTAB:	IFIW!BS1			;CAN ONLY SKIP 1 IF 1 CHARACTER LONG
	IFIW!BS2
	IFIW!BS3
	IFIW!BS4
	IFIW!BS0	;(PROBABLY SHOULD BE CALLED BS5 FOR CONSISTENCY)

;TABLE OF ENTRIES INTO THE FORWARD SEARCH LOOP.  SHOWS FIVE ENTIRES
;TO USE DEPENDING ON WHETHER FIRST CHARACTER TO BE CHECKED IS IN POSITION
;0,1,2,3, OR 4 IN THE FIRST WORD TO BE EXAMINED.

FSTAB:	IFIW!S0			;CHARACTER IS LEFT-JUSTIFIED
	IFIW!S1 ;CHARACTER IS ONE CHARACTER TO RIGHT OF LEFT EDGE OF WORD
	IFIW!S2
	IFIW!S3
	IFIW!S4			;CHARACTER IS AT RIGHT MARGIN

;HERE'S THE SEARCH LOOP FORWARD (TO THE RIGHT).  IT GETS ENTERED AT
;VARIOUS PLACES ACCORDING TO WHERE THE FIRST CHARACTER TO BE EXAMINED
;IS LOCATED WITH RESPECT TO WORD BOUNDARIES.

 ;START OF FORWARD SEARCH LOOP.

S00:	MOVE B,(D)		;GET WORD FROM BUFFER
S0:	LDB C,SLAST		;GET RIGHTMOST CHARACTER IN FRAME
	SKIPE SMAT(C)		;IS THAT CHAR ANYWHERE IN THE SEARCH STRING?
	JRST S0A		;YES, SO WE MUST EXAMINE THE FRAME
	LSHC A,@SLIDE		;NO, SLIDE TO NEXT FRAME IMMEDIATELY
	JRST @NXTFRM		;GO EXAMINE NEXT FRAME
S0A:	MOVE C,A		;GET COPY OF CHARACTERS FROM BUFFER
	AND C,P1		;KEEP ONLY BITS WE CARE ABOUT
	CAMN C,P2		;SEE IF IT'S WHAT WE'RE LOOKING FOR
	CALL SWIN1		;MAYBE, CHECK REST OF STRING AND LOCATION
	LSHC A,7		;SLIDE FRAME TO RIGHT ONE POSITION
S1:	MOVE C,A
	AND C,P1
	CAMN C,P2
	CALL SWIN2		;DUPLICATE RATHER THAN LOOP FOR SPEED
	LSHC A,7
S2:	MOVE C,A
	AND C,P1
	CAMN C,P2
	CALL SWIN3
	LSHC A,7
S3:	MOVE C,A
	AND C,P1
	CAMN C,P2
	CALL SWIN4
	LSHC A,7
S4:	MOVE C,A
	AND C,P1
	CAMN C,P2
	CALL SWIN5
	LSHC A,7
S5:	AOJA D,S00		;ALL 5 POSITIONS FAILED.  GET NEW WORD

SWIN1:	MOVEI C,0		;C IS HOW MANY TIMES WE SHIFTED...
				; BEFORE GETTING A MATCH
	JRST SWIN
SWIN2:	MOVEI C,1
	JRST SWIN
SWIN3:	MOVEI C,2
	JRST SWIN
SWIN4:	MOVEI C,3
	JRST SWIN
SWIN5:	MOVEI C,4
	JRST SWIN

;GET HERE WHEN SEARCH MATCHES FIRST FIVE CHARACTERS.  WE MUST CHECK
;THAT THE REST OF THE CHARACTERS MATCH, AND THAT WE ARE STILL IN THE BUF
;FER.  IF WE'RE IN BUFFER BUT REST DON'T MATCH, KEEP SEARCHING.  IF OUT
;OF BUFFER, SEARCH FAILED.

SWIN:	POP P,SADD		;REMEMBER WHERE TO RESUME SEARCH IF...
				; WE'RE NOT REALLY DONE YET
	DMOVEM A,SDAT		;SAVE DATA FOR RESTORING SEARCH LOOP
	MOVEM D,SPTR		;SAVE SEARCH POINTER
	SKIPG SCHARG		;SEARCHING TO THE RIGHT?
	JRST BSWIN		;NO, TO THE LEFT
	MOVEI A,-1(D)		;WE HAVE TO GET CHAR ADDRESS OF FIRST CHAR
	IMULI A,5	;NOW WE'VE GOT CHAR ADDRESS IF WE DID NO SHIFTING
	ADD A,C	 ;ADD NUMBER OF TIMES WE SHIFTED TO GET EXACT CHAR ADDRESS
	MOVEM A,SENDPT		;SAVE CHAR ADDRESS OF FIRST CHAR OF STRING
	CAML A,HOLBEG		;SEE IF WE'RE IN HOLE
	CAMLE A,HOLEND
	JRST SWNIH		;NO
	MOVE B,SCHLNN		;YES, SEE WHERE FAKE MATCH WAS PUT
	ADD B,HOLBEG
	SOJ B,
	CAMN A,B		;DID WE JUST HIT THE FAKE MATCH?
	JRST GETOUT		;YES, GET OUT OF HOLE AND RESUME SEARCH
SWNIH:	CAML A,HOLEND		;ARE WE TO RIGHT OF HOLE?
	SUB A,HOLSIZ		;YES, MAKE VIRTUAL CHARACTER ADDRESS
	MOVE B,A		;GET COPY OF CHAR ADDRESS OF FIRST CHARACTER
	ADD B,SCHLNN		;GET CHARACTER ADDRESS OF CHARACTER AFTER LAST
	CAMLE B,ZEE		;DID WE MATCH IN THE BUFFER?
	JRST SFAIL		;NO, SO THE SEARCH FAILED COMPLETELY
	CALL SCHK		;MAKE SURE REST OF CHARACTERS MATCH
	 JRST FLSALM		;THEY DON'T, GO KEEP SEARCHING
	MOVE A,SENDPT		;GET CHAR ADDRESS OF LEFTMOST CHAR THAT MATCHED
	ADD A,SCHLNN		;GET CHARACTER POSITION OF END OF STRING
	CAML A,HOLEND		;ARE WE TO RIGHT OF HOLE?
	SUB A,HOLSIZ		;YES, CHANGE TO VIRTUAL CHARACTER ADDRESS
	MOVE B,A		;GET A COPY
	SUB B,S0PT		;SEE HOW FAR WE'VE PROGRESSED
	CAMGE B,SCHLNN		;AT LEAST THE LENGTH OF THE STRING?
	 JRST FLSALM		;OTHERWISE /\---- 2S--$ WOULD GO ONLY TO ---/\-
	MOVEM A,S0PT		;REMEMBER WHERE THIS SEARCH BRINGS US TO
SRWIN:	SKIPGE SCHARG		;IS SEARCH ARGUMENT NEGATIVE?
	AOS SCHARG		;YES, SO APPROACH 0 THIS WAY
	SKIPLE SCHARG		;IF SEARCH ARG IS POSITIVE?
	SOS SCHARG		;APPROACH 0 THIS WAY
	SKIPE SCHARG		;HAVE WE FOUND STRING ENOUGH TIMES?
	JRST FLSALM		;NO, KEEP SEARCHING
	MOVEM A,PT		;STORE NEW VALUE OF POINTER
SRET1:	SETOB A,SFINDF		;SET FLAG SAYING SEARCH SUCCEEDED
	TXNE FF,RPLFG		;JUST RETURN IF DOING REPLACE COMMAND
	RET			;ALL DONE!
SRET:	TXNN FF,COLONF		;NOT REPLACE, :S?
	JRST CFLUSH		;NO, DON'T RETURN VALUE
	JRST ARGINA		;YES, RETURN VALUE

;COME HERE WHEN WE WANT TO SEARCH TO THE LEFT

SETBAK:	MOVE I,HOLBEG		;GET LEFT EDGE OF HOLE
	SUB I,SCHLNN
	AOJ I,
	MOVE OU,HOLEND
	SUB OU,SCHLNN
	AOJ OU,
	MOVE P1,SCHLNN
	SOJ P1,
	CALL MVCST		;COPY CHARACTERS FROM TO...
	 ; LEFT OF HOLE TO INTO HOLE AT RIGHT EDGE...
	 ; (IN CASE SEARCH MATCHES ACROSS THE HOLE)
	MOVE OU,HOLEND
	SUB OU,SCHLNN
	SUBI OU,4
	MOVE I,[5*MATCH]
	MOVEI P1,5
	CALL MVCST		;PUT MATCH AT HOLE SO WE'LL KNOW DURING
				; SEARCH LOOP WHEN WE HIT THE HOLE
	MOVE OU,BEG
	SUBI OU,5
	MOVE I,[5*MATCH]
	MOVEI P1,5
	CALL MVCST		;PUT MATCH AT BEGINNING OF BUFFER SO 
				;WE'LL KNOW WHEN SEARCH FAILS
	MOVE A,SCHLNN		;GET LENGTH OF SEARCH STRING
	CAILE A,5
	MOVEI A,5		;WE CAN SKIP AT MOST 5 CHARACTERS AT A TIME
	MOVE B,BNXTAB-1(A)	;FIGURE OUT WHERE TO JUMP TO WHEN FIRST CHARACTER DOESN'T MATCH
	MOVEM B,NXTFRM		;REMEMBER FOR SEARCH LOOP
	IMUL A,[-7]		;FIGURE OUT HOW MANY BITS TO THE RIGHT TO SHIFT
	SOJ A,			;WHEN FIRST CHAR EXAMINED ISN'T IN
				 ; SEARCH STRING AT ALL (ONE EXTRA FOR B35!)
	HRRZM A,SLIDE		;REMEMBER, BUT CLEAR LH BECAUSE REF'D WITH @
	MOVE A,PT
	SOJ A,			;FIGURE OUT WHICH CHAR TO START SEARCHING WITH
	CAML A,HOLBEG
	ADD A,HOLSIZ		;MAKE ABSOLUTE ADDRESS
BSRCH:	IDIVI A,5		;FIND WHICH WORD TO START WITH
	MOVE C,BSTAB(B)		;GET PLACE TO START SEARCH LOOP WITH
	MOVEM C,SADD		;REMEMBER
	MOVEI D,(A)		;D ALWAYS SHOWS NEXT WORD TO LOOK AT
	MOVEM D,SPTR		;REMEMBER WHICH WORD TO PICK UP FIRST
	MOVE P1,B		;P1 REMEMBERS HOW MUCH TO INITIALLY SHIFT
	DMOVE A,(D)		;GET INITIAL DATA TO START SEARCH WITH
	LSHC A,@SHFTAB(P1)	;RIGHT JUSTIFY FIRST 5 CHARS IN A'B
	DMOVEM A,SDAT		;INITIALIZE THE SEARCH DATA
	JRST FLSALM		;INITIALIZE SEARCH BY PRETENDING WE JUST...
				; HAD A FALSE MATCH

;GET HERE WHEN SEARCHING LEFT FINDS A MATCH ON FIRST 5 CHARACTERS.

BSWIN:	MOVE A,D		;GET WORD ADDRESS OF WORD CONTAINING LEFTMOST
				; CHAR IN STRING
	IMULI A,5
	ADDI A,5
	SUB A,C			;A HOLDS LEFTMOST CHARACTER ADDRESS OF THE
	MOVE B,HOLEND		; 5 THAT MATCHED
	SUB B,SCHLNN
	SUBI B,4		;GET TO CHARACTER ADDRESS OF PLANTED STRING
	CAMN A,B		;DID WE JUST MATCH IN THE HOLE?
	JRST BGETOT		;YES, GO GET OUT OF HOLE AND KEEP SEARCHING
	CAML A,HOLBEG
	SUB A,HOLSIZ		;GET VIRTUAL ADDRESS
	MOVEM A,SENDPT		;REMEMBER WHERE SEARCH MAY HAVE MATCHED
	CAMGE A,BEG		;DID IT MATCH IN THE BUFFER AT ALL?
	JRST SFAIL		;NO, SO SEARCH FAILED
	ADD A,SCHLNN		;GET CHAR ADDRESS OF CHAR TO RIGHT
				; OF ENTIRE STRING
	CAMLE A,S0PT		;STRING BETTER ENTIRELY FIT TO LEFT OF
				; POINTER AS OF LAST SEARCH
	JRST FLSALM		;DOESN'T
	SUB A,SCHLNN		;GET FIRST CHARACTER ADDRESS AGAIN
	CALL SCHK		;MAKE SURE ENTIRE STRING MATCHES
	 JRST FLSALM		;DOESN'T
	MOVE A,SENDPT		;GET WHAT TO SET PT TO IF STRING HAS BEEN
				; FOUND ENOUGH TIMES
	MOVEM A,S0PT		;REMEMBER WHERE WE'VE PROGRESSED TO DURING
				; SEARCHING
	JRST SRWIN

;TABLE OF HOW MUCH TO SHIFT INITIAL DATA TO RIGHT-JUSTIFY FIRST 5 CHARACTERS...
;WE'RE TESTING

SHFTAB:	,-^D36			;CHARACTER IS LEFT-JUSTIFIED
	,-^D29			;CHARACTER IS ONE CHARACTER TO THE RIGHT
	,-^D22			;2
	,-^D15			;ONE FROM THE RIGHT
	,-^D8			;CHARACTER RIGHT-JUSTIFIED

;TABLE OF ADDRESS IN LEFTWARD SEARCH LOOP AT WHICH TO ENTER ACCORDING
;TO HOW MUCH INITIAL DATA HAD TO BE SHIFTED TO RIGHT-JUSTIFY FIRST
;CHARACTER IN B

BSTAB:	IFIW!BS0
	IFIW!BS4
	IFIW!BS3
	IFIW!BS2
	IFIW!BS1

;THE BACKWARD SEARCH LOOP.  IT MERELY LOADS A WORD FROM MEMORY,
;SEES IF ANY OF THE 5 POSITIONS OF THAT DATA MATCHES THE FIRST
;FIVE CHARACTERS OF THE SOUGHT STRING, AND THEN PROCEDES TO THE NEXT
;WORD TO THE LEFT IN MEMORY.

BS00:	MOVE A,(D)		;GET NEXT WORD FROM BUFFER
	LDB C,[350700,,B]	;GET LEFTMOST CHARACTER OF FRAME
	SKIPE SMAT(C)		;IS CHARACTER ANYWHERE IN SEARCH STRING
	JRST BS0A		;YES, SO WE MUST EXAMINE FRAME
	LSHC A,@SLIDE		;NO, SO WE CAN SKIP UP TO FIVE POSITIONS
	JRST @NXTFRM		;SKIP SOME.
BS0A:	MOVE C,B		;GET COPY OF DATA
	AND C,P1		;KEEP ONLY BITS EQUAL IN ALL POSSIBLE MATCHES
	CAMN C,T		;SEE IF WE HAVE A MATCH
	CALL SWIN1		;WE DO.  THE "CALL" REMEMBERS HOW
				; MANY TIMES WE HAD TO SHIFT TO GET A MATCH
	LSHC A,-8		;INSTEAD OF 7, WHICH WOULD GET 6 BITS AND B35
BS1:	MOVE C,B
	AND C,P2		;DIFFERENT MASK SINCE B35 IS EMBEDDED
	CAMN C,TT
	CALL SWIN2
	LSHC A,-7		;ONLY 7 NOW SINCE WE'VE SKIPPED OVER B35
BS2:	MOVE C,B
	AND C,OU
	CAMN C,TT1
	CALL SWIN3
	LSHC A,-7
BS3:	MOVE C,B
	AND C,CH
	CAMN C,I
	CALL SWIN4
	LSHC A,-7
BS4:	MOVE C,B
	AND C,SAC1
	CAMN C,SAC2
	CALL SWIN5
	LSHC A,-7		;NO POSITIONS MATCHED
BS0:	SOJA D,BS00		;GO GET NEXT WORD FROM BUFFER

;FOLLOWING ROUTINE TAKES ABSOLUTE CHAR ADDRESS IN A, ASSUMED
;TO BE LEFTMOST CHARACTER IN STRING, AND SKIPS IFF STRING MATCHES
;ONE BEING SEARCHED FOR

SCHK:	SOJ A,			;BACK UP ONE CHAR BECAUSE WE WANT TO DO ILDB
	MOVE I,A
	CALL GET		;MAKE ILDB POINTER IN TT TO BEGINNING
				; OF SUPPOSED MATCHING STRING IN BUFFER
	MOVSI A,400000		;BIT BEING CHECKED IN SEARCH TABLE
	MOVE B,SCHLNN		;B SHOWS HOW MANY CHARACTERS TO TEST
SCHECK:	SOJL B,CPOPJ1		;IF ALL MATCH WE'RE REALLY DONE!
	UILDB C,TT		;GET CHARACTER FROM BUFFER
	TDNN A,SMAT(C)		;IS THIS CHARACTER A MATCH?
	RET			;STRING DOESN'T MATCH
	LSH A,-1		;STEP TO NEXT BIT POSITION
	JRST SCHECK		;YES, CHECK THE REST

;GET HERE WHEN WE JUST HIT THE HOLE WHILE SEARCHING TO THE RIGHT.
;THE FOLLOWING CODE GETS US OUT OF THE HOLE AND CONTINUES THE SEARCH.

GETOUT:	MOVE A,HOLEND		;FIRST CHARACTER TO CHECK NEXT
	JRST FSRCH		;GO RESTART FORWARD SEARCH

;GET HERE WHEN SEARCHING TO THE LEFT, AND WE JUST HIT THE RIGHT
;EDGE OF THE HOLE

BGETOT:	MOVE A,HOLBEG
	SOJ A,			;SKIP OVER HOLE (TO LEFT EDGE OF IT)
	JRST BSRCH		;START SEARCHING AGAIN

;COME HERE IF SEARCH ISN'T THROUGH YET BECAUSE ALTHOUGH FIRST FIVE
;CHARACTERS MATCHED, THE REST OF THE STRING DIDN'T.  HOPEFULLY THIS
;RARELY HAPPENS, AS IT WOULD GROSSLY SLOW DOWN THE SEARCH.  OBVIOUSLY
;SUCH SUCKY CASES CAN BE CONSTRUCTED, BUT AS BENJAMIN FRANKLIN ONCE
;SAID: "TO GAMBLE IS TO COAPUTE THE GREGS OF FRETRICAL INACQUICIES
;	WITHOUT THE CRUX OF PLEGANOUS FINALITY"
;BUT AS GEORGE RAFT REPLIED: "WHAT DOES BENJAMIN FRANKLIN KNOW?"
;(PAT PAULSON SAID IT ALL ACTUALLY)

FLSALM:	DMOVE A,SDAT		;GET SEARCH DATA BACK
	MOVE D,SPTR		;GET BUFFER WORD INDEX
	SKIPG SCHARG
	JRST FLSB		;SEARCH TO LEFT, DIFFERENT INITIALIZATION
	MOVE P1,CARBTS		;GET BITS WE CARE ABOUT
	MOVE P2,SMASK		;GET VALUE THOSE BITS ARE SUPPOSED TO BE
	JRST @SADD		;RESUME THE SEARCH

FLSB:	DMOVE P1,CARTAB		;LOAD UP MASKS OF BITS WE'RE TESTING
	DMOVE OU,CARTAB+2
	MOVE SAC1,CARTAB+4	;THERE 5 DIFFERENT VERSIONS
	DMOVE T,SMTAB		;LOAD UP THE 5 VERSIONS OF SOUGHT
				; VALUES FOR THE BITS
	DMOVE TT1,SMTAB+2
	MOVE SAC2,SMTAB+4
	JRST @SADD		;(RE)ENTER SEARCH LOOP

;TABLE TO TRANSFORM CHARACTER RANK INTO SINGLE BIT MASK.  FOR INSTANCE,
;CHARACTER 1 (THE FIRST) CORRESPONDS TO 1B0, CHARACTER 2 CORRESPONDS
;TO 1B1 ETC.  HENCE "MOVE A,SBITS(P1)" GETS CORRECT BIT LOADED INTO A
;FOR P1TH CHARACTER (WELL 'CONTENTS OF P1'TH ACTUALLY)

SBITS:
	%%X==1B0
REPEAT ^D36,<
	%%X
	%%X==%%X_-1
>

;GET HERE WHEN SEARCH FAILS

SFAIL:	SETZM SFINDF		;CLEAR FLAG SAYING SEARCH SUCCEEDED
	TXNE FF,PCHFLG+FINDR	;S SEARCH?
	JRST NOFND1		;NO.
	TXNN FF,COLONF		;YES. COLON MODIFIER?
	JRST NOFND2		;NO

	TXZ FF,PCHFLG+FINDR	;YES.
	TXNE FF,RPLFG		;ARE WE DOING A REPLACE COMMAND?
	RET			;YES, SO JUST RETURN
	JRST ZERINA		;NO, RETURN 0

NOFND1:	SKIPGE SOARG		;POSITIVE SEARCH?
	JRST NOFND2		;CAN'T DO BEG BACKARROW OR NEG N
	SKIPN ABORTF		;ABORT?
	TXNN FF,UREAD		;INPUT FILE SELECTED?
	JRST NOFND2		;NO. DONE.
;**;[503] At NOFND1: +5L, Replaced 2 lines      	SM	24-Mar-82
	TXNE FF,FINF		;[503] ALREADY AT EOF?
	JRST NOFND3		;[503] YES, SEARCH FAILS, QUAMP THE BUFFER
	MOVEI C,1		;PUNCH 1 PAGE ONLY
	TXNE FF,PCHFLG		;N SEARCH?
	CALL PUNCHA		;YES. PUNCH THIS BUFFER AND REFILL IT.
	TXNE FF,FINDR		;LEFT ARROW SEARCH?
	CALL YANK		;YES. FILL BUFFER.
;**;[503] At NOFND1: +14L, Deleted 1 line       	SM	24-Mar-82
	JRST SERCHS		;CONTINUE SEARCHING

;**;[503] At NOFND2: -1L, Added 4 lines        	SM	24-Mar-82
NOFND3:	MOVEI C,1		;[503] PUNCH 1 BUFFER IF ANY
	TXNE FF,PCHFLG		;[503] NEED TO OUTPUT LAST BUFFER?
	CALL PUNCHA		;[503] YES, PUNCH IT
	CALL HK			;[503] SEARCH FAILED, CLEAR BUFFER.

;**;[510] At NOFND2:, Inserted 2 lines                      SM 26-May-82
NOFND2:	TXNE FF,COLONF		;[510] IS HE INTERCEPTING ERRORS?
	JRST ZERINA		;[510] YES, GIVE HIM ZERO.
	STKVAR <SFLPTR,SFLLEN>	;O.K., SINCE P IS RESET AT "GO"
	LERROR <Search failed for: >
	MOVE A,[POINT 7,SCHBUF]	;POINTER TO STRING WE COULDN'T FIND
	MOVEM A,SFLPTR
	MOVE A,SSLEN		;GET LENGTH (MIGHT BE NULLS IN STRING!)
	MOVEM A,SFLLEN
	UCTYPE """"		;PUT STRING IN QUOTES
NOF1:	SOSGE SFLLEN		;MAYBE STRING IS EXHAUSTED
	JRST	[	PSTR <"
>				;FINISH STRING WITH CLOSE QUOTE AND CRLF
			JRST GO]	;FINISH ERROR HANDLING
	ILDB A,SFLPTR		;GET NEXT CHARACTER FROM SEARCH STRING
	CAIL A,.CHTAB		;FORMATTING CHARACTER?
	CAILE A,.CHCRT
	JRST [	UCTYPE @A	;NO, TYPE THE CHARACTER
		JRST NOF1]	;CONTINUE WITH REST OF STRING
	UCTYPE "<"		;START SPECIAL STRING
	UPSTR @[	[ASCIZ /TAB/]
			[ASCIZ /LF/]
			[ASCIZ /VT/]
			[ASCIZ /FF/]
			[ASCIZ /CR/]]-.CHTAB(A)
	UCTYPE ">"		;FINISH SPECIAL STRING
	JRST NOF1		;DO REST OF STRING

;MI PERFORM NOW THE TEXT IN Q-REGISTER IN AS A SERIES OF COMMANDS.

MAC:	CALL QREGVI		;A:=C(Q-REG)

MAC0:	TLZE A,400000		;MAKE SURE Q-REG CONTAINS TEXT
	TLZE A,377770
	JRST QGETQE
	POP P,SYL		;[502] SAVE RETURN ADDRESS
	ADD A,QRBUF
	MOVE I,A
	CALL SAVCMD		;SAVE CURRENT COMMAND STATE
	PUSH P,INTDPH		;REMEMBER HOW DEEP ITERATIONS ARE
	CALL GETINC		;GET FIRST CHARACTER OF MACRO
	CAIE CH,141		;IT SHOULD BE FLAG
	JRST QGETQE		;OOPS
	CALL GETINC		;GET NUMBER OF CHARACTERS IN MACRO
	MOVE A,CH
	CALL GETINC
	LSH A,7
	IOR A,CH
	CALL GET
	LSH A,7
	IOR A,CH
	SUBI A,4		;-FLAG AND COUNT
	MOVEM A,COMCNT		;THAT MANY COMMANDS TO COUNT
	MOVEM A,COMAX		;AND MAX.
	SETZM INTDPH		;SAY NO ITERATIONS YET
	MOVE A,I
	IDIVI A,5
	MOVE B,BTAB(B)		;MAKE A BYTE POINTER
	HRR B,A
	MOVEM B,CPTR		;PUT IT IN CPTR
	JRST @SYL		;[502] RETURN TO CALLER
;MXFILENAME$ PUTS THE CONTENTS OF THE FILE IN Q-REG X 

MFILE:	CALL QREGVI		;GET Q-REG NAME TO USE & MAKE SURE 'TIS LEGAL.
	MOVE T,CH		;REMEMBER NAME IN T
	CALL FACCES		;OPEN THE FILE
	CALL MFILE0		;LOAD THE FILE
	MOVEM A,QTAB-"0"(T)	;STORE POINTER TO TEXT IN QREG "X"
	JRST CFLUSH		;[502] DONE

;WLIBRARY$FILENAME$ DOES THINGS LIKE ;MI, BUT DIFFERENT

WLIBR:	CALL	FACCES
	MOVEM	A,JFNIS
	DVCHR%			;SEE IF THIS JFN IS A TERMINAL
	LDB A,[221100,,B]	;GET DEVICE TYPE NUMBER
	CAIN A,.DVTTY		;SKIP IF IT IS A TERMINAL
	JRST	[MOVEI	C,[ERROR <Cannot load a Library from the terminal>]
		 JRST	BADLIB]	;IT IS, ILLEGAL
WLIB1:	MOVE	A,JFNIS
NQREGN:	BIN%			;GET THE QREG NAME
	 ERJMP	NOMOR
	CAIE	B,12		;ALLOW CR, LF, ...
	CAIN	B,15
	JRST	NQREGN
	CAIE	B,"\"		;AND BACKSLASH AND SPACE...
	CAIN	B,40		;AS DROSS
	JRST	NQREGN
	MOVE	CH,B		;CANT CALL QREGVx HERE, SINCE AN ILL QREG
	CAIE	CH,"#"		;# MEANS ARRAY REFERENCE
	JRST	QLOADL		;GO LOAD Q-REG LOC
	MOVE	A,JFNIS
	MOVEI	C,^D10
	NIN%
	 ERJMP	ILAQE
	CAIL	B,0
	CAIL	B,USARYL
	JRST	UABNQE
	MOVEI	T,USRARY(B)
	BKJFN%
	 ERJMP	GREF
	JRST	GREF
QLOADL:	CAIL CH,140		; WOULDNT LET US DROP THE JFN. LC LETTER?
	TRZ CH,40		;MAKE UC
	CAIL CH,"0"		;LETTER OR DIGIT?
	CAILE CH,"Z"
	 JRST	BADQRE
	CAILE CH,"9"
	CAIL CH,"A"		;CHECK FOR LONELY 7 BETWEEN DIGITS AND LETTERS
	TRNA
	 JRST	BADQRE
	CALL	QREGVC		;NOW DO THE TRANSLATION
	MOVE	T,CH		;SAVE THE INDEX
	ADDI	T,QTAB-"0"
GREF:	MOVE	A,JFNIS
	BIN%
	 ERJMP	ILIBQE		;ILLEGAL LIBRARY FORMAT
	CAIE	B,"="
	JRST	NORFET
	MOVE	A,JFNIS
	MOVEI	C,^D10
	NIN%
	 ERJMP	INULQE		;ILLEGAL NUMBER
	MOVEM	B,(T)		;STORE THE NUMBER
	BKJFN%
	 ERJMP	WLIB1		;ASSUME OK?
	BIN%
	CAIE	B,"\"		;BACKSLASH IS LEGAL
	CAIG	B,40		;DID THE NUMBER END WITH SPACE OR LESS?
	JRST	WLIB1
	 JRST	INULQE		;NO, GO COMPLAIN
NORFET:	MOVEM	B,STOPAT	;STOP AT THIS CHARACTER...
	CALL	MFILE1		;GO LOAD UP
	TRNA			;NONSKIP IS OK
	 JRST	BADLIB		;IF SKIP, DO ERROR IN AC C
	MOVEM	A,(T)		;AND THE Q-REG IS ALL SET
	JRST	WLIB1
NOMOR:	MOVE	A,JFNIS
	CLOSF%
	 ERJMP	.+1
	JRST	CFLUSH

UABNQE:	MOVEI	C,ARRYQE	;Array reference out of bounds
	JRST	BADLIB
ILAQE:	MOVEI	C,[ERROR <Number not in a readable format after "#">]
	JRST	BADLIB
INULQE:	MOVEI	C,[ERROR <Number not in a readable format after "=">]
	JRST	BADLIB
ILIBQE:	MOVEI	C,[ERROR <EOF while looking for delimiter>]
	JRST	BADLIB
BADQRE:	MOVEI	C,QREGQE	;BAD Q REGISTER
BADLIB:	MOVEM	C,SYL
	LERROR	<Library file error, at file position >
	MOVE	A,JFNIS
	RFPTR%			;WHERE DID IT HAPPEN?
	 ERJMP	NOPOSI		;DONT KNOW
	MOVX	A,.PRIOU
	MOVEI	C,^D10
	NOUT%
	 ERJMP	.+1
NOPOSI:	MOVE	A,JFNIS
	CLOSF%
	 ERJMP	.+1
	JRST	@SYL		;GO JUMP TO ERROR CODE AS APPROPRATE

;ROUTINE TO LOAD A FILE INTO A Q-REG.  GIVE IT JFN IN A.  IT RETURNS
;HANDLE IN A.
;ENTER AT MFILE0 TO READ UNTIL EOF, MFILE1 TO READ UNTIL CHAR IN
; STOPAT. CALLING MFILE1 WITH A NON-NEGATIVE STOPAT MEANS THE FILE
; IN JFN A WILL NOT BE CLOSED ON RETURN, AND A +2 RETURN IS GIVEN IF
; AN ERROR OCCURS (+1 OTHERWISE)

MFILE0:	SETOM	STOPAT		;GO UNTIL EOF
MFILE1:	CALL QGC		;GET AS MUCH SPACE AS POSSIBLE
	MOVE C,EQRBUF		;GET ADDRESS OF BEGINNING OF FREE SPACE
	SUB C,BEG	;SUBTRACT END OF F.S. TO YIELD NEG OF FREE AMOUNT
	ADDI C,4		;LEAVE 4 CHARACTERS SPACE FOR FLAG AND LENGTH
	JUMPGE C,MFILQE
	PUSH P,A		;SAVE JFN FOR A MOMENT
	PUSH P,C		;LIKEWISE COUNT
	DVCHR%			;BE THIS DEVICE A TERMINAL?
	LDB A,[POINT 9,B,17]	;ISOLATE THE TYPE
	SETZM SYL		;ASSUME NOT A TTY
	CAIN A,.DVTTY		;ARE YOU A TTY?
	SETOM SYL		;IT *IS* A TTY! IT GETS SPECIAL TREATMENT
	POP P,C			;RESTORE COUNT
	POP P,A			;RESTORE JFN
	MOVE OU,EQRBUF
	MOVEI CH,141
	CALL PUT		;CREATE BYTE POINTER TO BEGINNING
				; OF FREE SPACE AND PUT IN FLAG
	PUSH P,TT		;SAVE BYTE POINTER
	IBP TT
	IBP TT
	IBP TT
	MOVE B,TT		;TELL SYSTEM WHERE TO READ FILE INTO
	MOVE P1,C		;SAVE AMOUNT WE'LL ATTEMPT TO READ IN
	SKIPL SYL		;IS THIS A TTY?!?
	JRST SININ		;NO, GO SIN IT IN
 ;HERE IF INPUT DEV IS A TTY: - WE WILL DO A TEXTI
	MOVNM C,TXTI+.RDDBC	;STORE POS NUMBER OF BYTES IN TEXTI BLOCK
	HRLI A,.PRIOU		;SET UP JFN STUFF
	MOVSM A,TXTI+.RDIOJ	;..
	TXNE FF,ARG		;WAS AN ARG GIVEN?
	JRST [	SKIPN A,FARG	;GET USER FLAGS
		JRST .+1	;IF NONE REALLY GIVEN, USE NORMAL DEFAULTS
		TRNE A,(RD%BTM)	;DID USER SET A FUNNY BIT (IE, -1 PASSED IN?)
		MOVEI A,(RD%BEL) ;YES, PROVIDE ALTERNATE DEFAULTS
		HRLZS A		;MOVE TO LEFT HALF
		TXO A,RD%JFN	;WE INSIST ON THIS
		JRST .+2]	;NOW SKIP OVER DEFAULT FLAGS
	MOVX A,RD%BRK!RD%JFN	;BRK ON <ESC><^Z>
	MOVEM A,TXTI+.RDFLG	;..
	MOVEM B,TXTI+.RDDBP	;DEST WAS IN B
	MOVEI A,.RDDBC		;HIGHEST ADDRESS IN BLOCK
	MOVEM A,TXTI+.RDCWB	;..THATS THE BLOCK COUNT
	MOVEI A,TXTI		;POINT AT BLOCK...
	TEXTI%			;AND READ FROM TTY: INTO CORE
	 ERJMP .+1		;THIS DOESNT FAIL
	MOVE A,TXTI+.RDFLG	;CHECK THE FLAGS
	TXNE A,RD%BFE		;RUBOUT BACK TO BEFORE BEGINNING?
	JRST [SETZ C,		;YES, MEANING NO CHARS READ
	      JRST NTXTIN]
	TXNN A,RD%BTM		;DID WE END ON A BREAK CHARACTER?
	JRST MFILQE		;NO, GO DIE HORRIBLY - COUNT EXHAUSTED
	ADD C,TXTI+.RDDBC	;#CHARS LEFT+(-#ALLOCATED)
	MOVN C,C		;GET THE POSITIVE # CHARS READ IN
NTXTIN:	HLRZ A,TXTI+.RDIOJ	;GET JFN BACK
	CLOSF%			;AND BAG IT
	 ERJMP MFILCL		;SHAN'T FAIL
	JRST MFILCL		;GO FIGURE OUT WHATS WHERE
SININ:	SKIPL	D,STOPAT	;DOING THE FUNNY STOPAT STUFF?
	MOVN	C,C		;YES, THE MAX COUNT GOES POSITIVE
SININ2:	SIN%			;READ ENTIRE FILE INTO CORE
	SKIPGE	STOPAT		;NORMAL READ TO EOF?
	JRST	SINTST		;YES, GO SEE
	MOVN	C,C		;SET IT NEGATIVE AGAIN
	SUBI	C,1		;WE *DONT* WANT THE TERMINATOR
	JRST	NOCLOS		;DONT CLOSE THE FILE, THATS FOR THE CALLER
SINTST:	GTSTS%			;GET EOF BIT INTO b
	CLOSF%			;CLOSE THE FILE
	 ERJMP	.+1		;IF CANT, TOO BAD
	TXNN B,GS%EOF		;WAS THERE ENOUGH ROOM FOR WHOLE FILE?
	JRST	MFILQE
NOCLOS:	SUB C,P1		;SEE HOW MANY CHARACTERS WE READ IN
MFILCL:	ADDI C,4		;4 FOR FLAG AND COUNT.
	MOVE B,[250700,,C]	;PREPARE TO PICK UP AMOUNT IN THREE INSTALLMENTS
	POP P,D			;RESTORE BYTE POINTER
REPEAT 3,<
	ILDB P1,B		;PICK UP PART OF LENGTH
	IDPB P1,D		;PUT IT AT BEGINNING OF STRING
>
	ADD C,EQRBUF		;COMPUTE NEW SPACE BOUNDARY
	MOVE A,EQRBUF		;GET OLD FREE SPACE BOUNDARY
	MOVEM C,EQRBUF		;UPDATE BOUNDARY
	SUB A,QRBUF		;GET RELATIVE ADDRESS
	TLO A,(1B0)		;SET "TEXT" FLAG
	RET

MFILQE:	SKIPGE	STOPAT		;DO WE RETURN ERRORS TO THE CALLER?
MFI2QE:	ERROR <Not enough qreg space> ;NO. (WE DIDN'T REACH EOF)
	MOVEI	C,MFI2QE	;YES, IN AC C
MFILER:	AOS	(P)		;SKIP FOR ERROR
	RET
;ERROR HANDLERS

DONTFL:	DPB CH,CPTR		;PUT ALTMODE BACK IN STRING
DNTFL2:	CALL JSER		;ANALYZE ERROR
	ERROR <Couldn't access file>
DNTFL1:	MOVE A,C		;COULDN'T OPEN FILE, SO RELEASE JFN
	RLJFN%
	JFCL			;CAN'T EVEN DO THAT!
	JRST DNTFL2		;ANNOUNCE REASON FOR ERROR

;FILE ACCESS ROUTINE

FACCES:	CALL FILSPC		;FIND END OF FILE NAME AND DELIMIT WITH NULL
	MOVSI A,(GJ%OLD+GJ%SHT)	;SHORT FORM+OLD FILE ONLY
	GTJFN%			;GET HANDLE ON FILE
	JRST DONTFL		;COULDN'T.
	DPB CH,CPTR		;PUT ALTMODE BACK
	MOVE B,[70000,,OF%RD]	;7 BIT BYTES+OPEN FOR READING
	MOVE C,A		;SAVE JFN IN CASE OF ERROR
	OPENF%			;OPEN THE FILE
	JRST DNTFL1		;COULDN'T.
	RET

;WFILENAME INSERTS THE FULL FILENAME OF THE LAST FILESPEC GIVEN
;IN A ;Y ;U ;S ;D ;X ;R OR ;W COMMAND

WFILEN:	MOVE A,[POINT 7,NAMBFR]	;POINTER TO FILESPEC
	CALL INSRTZ		;[502] INSERT THE FILENAME
	JRST CFLUSH		;[502] AND LEAVE

;EFILENAME$ PUSHES TYPIN JFN AND INPUTS FROM NAMED FILE.

DOFILE:	CALL FACCES		;OPEN THE FILE
	MOVE C,TYIP		;GET TYPIN STACK POINTER
	PUSH C,TYIJFN		;SAVE OLD TYPIN JFN
;**;[513] At DOFILE: +3L, Inserted 1 line                   SM 31-Aug-82
	 ERJMP	PCMDQE		;[513] IF THATS ILLEGAL, WE WILL GO COMPLAIN
	MOVEM C,TYIP		;SAVE NEW STACK POINTER
	MOVEM A,TYIJFN		;AND SAVE NEW INPUT JFN
	DVCHR%			;SEE IF DEVICE IS A TERMINAL
	SETOM TERIO		;FIRST ASSUME IT'S NOT
	LDB A,[221100,,B]	;GET DEVICE TYPE
	CAIE A,.DVTTY		;SKIP IF IT'S A TERMINAL
	SETZM TERIO		;IT'S NOT.
	JRST CFLUSH		;[502] DONE

;**;[513] At DOFILE: +13L, Inserted 3 lines                 SM 31-Aug-82
PCMDQE:	CLOSF%			;[513] CLOSE THE FILE WE OPENED
	 ERJMP	.+1		;[513] DOESNT MATTER
	ERROR	<Too many command streams pushed>
;<> ITERATION BRACKETS.  COMMAND INTERPRETATION IS SENT
;	BACK TO THE < WHEN THE > IS ENCOUNTERED.

LSSTH:	TXNE FF,SCANF		;SCANNING?
	JRST [	MOVEI A,">"	;YES, SEE IF SCANNING FOR CLOSING BRACKET
		CAMN A,LCHAR
		AOS SCNEST	;YES, SO NEST DEEPER
		JRST CFLUSH]
	POP P,SYL		;[502] STORE THIS FOR THE RETURN
	AOS INTDPH
	PUSH P,ITERCT		;SAVE ITERATION COUNT
	TXZN FF,ARG		;IS THERE AN ARGUMENT?
	 HRLOI C,377777		;NO, SET ITERCT= POS INF
	MOVEM C,ITERCT		;YES. ITERCT:=ARGUMENT
	CALL SAVCMD		;SAVE CURRENT COMMAND STATE
	PUSH P,SYL		;[502] RESTORE RETURN
	SKIPG C,ITERCT
	JRST INCMA		; 0<...> DOES NOTHING FEATURE.
	JRST CFLUSH

GRTH:	TXNE FF,SCANF		;SCANNING?
	JRST [	MOVEI A,^D62	;YES, SEE IF FOR CLOSED BRACKET
		JRST SCAN1]
	SKIPG INTDPH		;IS THERE A LEFT ANGLE BRACKET?
	ERROR <Unmatched right angle bracket>
	SOSG ITERCT		;ITERCT:=ITERCT-1. DONE?
	JRST INCMA2		;YES
RSLOP:	POP P,SYL		;[502] SAVE THE RETURN ADDRESS
	CALL REACMD		;RESTORE COMMAND STATE TO BEGINNING OF LOOP
	PUSH P,SYL		;[502] RESTORE RETURN ADDRESS
	TXNE FF,TRACEF		;TRACING?
	CALL CRR		;YES. OUTPUT CRLF
	JRST CFLUSH
;:	IF NOT IN AN ITERATION, GIVES ERROR.  IF IN AN ITERATION AND
;	IF THE MOST RECENT SEARCH FAILED, SEND COMMAND TO FIRST UNMATCHED
;	RBRACKET TO THE RIGHT.  OTHERWISE, NO EFFECT.

TCOND:	SKIPN INTDPH		;IN < > ?
TCONQE:	ERROR <No iteration loop currently in progress>
	TXNN FF,ARG		;YES. IF NO ARG,
	MOVE C,SFINDF		;LAST SEARCH SWITCH

	JUMPL C,CFLUSH		;IF ARG  .L. 0, JUST RET + EXECUTE LOOP
INCMA:	MOVEI A,^D62		;WHAT WE'RE LOOKING FOR (RIGHT ANGLE BRACK.)
	CALL SCAN		;SET IT

INCMA2:	POP P,SYL		;[502] SAVE HIS RETURN ADDRESS
	SOS INTDPH		;POP OUT A LEVEL
	ADJSP P,-CBLEN		;THROW AWAY SAVED COMMAND STATE
	POP P,ITERCT
	PUSH P,SYL		;[502] RESTORE HIS RETURN ADDRESS
	JRST CFLUSH

				;HERE WITH CHARACTER IN A TO SCAN FOR

SCAN:	MOVEM A,LCHAR		;REMEMBER WHAT WE'RE LOOKING FOR
	TXO FF,SCANF		;REMEMBER WE'RE SCANNING
	SETZM SCNEST		;RESET NESTING LEVEL
	RET			;[502] RETURN

;!TAG! TAG DEFINITION.  THE TAG IS A NAME FOR THE LOCATION IT
;	APPEARS IN IN A MACRO, ITERATION OR COMMAND STRING.

EXCLAM:	CALL SKRCH		;EXCLAM JUST INCREMENTS PAST ANOTHER !
	CAIE CH,"!"
	JRST EXCLAM
	JRST CFLUSH
;OTAG$ GO TO THE TAG NAMED TAG.  THE TAG MUST APPEAR IN THE 
;	CURRENT MACRO OR COMMAND STRING.

OG:	TXNE FF,COLONF		; : FLAG LIT?
	JRST OGNFA		;YES, FOR SOME REASON, USER WANTS RE-INTERPERT
	MOVE A,CPTR		;COMPUTE HASH OF CPTR INTO SYMBOL TABLE
	MOVE B,A
	IDIVI B,17
	CAMN A,SYMS(C)		;DO 3 PROBES MAX THEN GIVE UP
	JRST OGFND
	SKIPN SYMS(C)
	JRST OGNF
	CAMN A,SYMS+1(C)

ES1:	AOJA C,OGFND
	SKIPN SYMS+1(C)
	AOJA C,OGNF
	CAMN A,SYMS+2(C)
	AOJA C,ES1
	SKIPN SYMS+2(C)
	ADDI C,2

OGNF:	PUSH P,CPTR
	PUSH P,C
OGNFA:	MOVEI P2,OTAB+1
	MOVEI A,41
	MOVEM A,-1(P2)		;OTAB_"!"
OGNF1:	CALL SKRCH
	MOVEM CH,(P2)		;OTAB+1 ... _ TAG
	CAIL P2,OTAB+OTABL	;FILLED BUFFER?
	ERROR <Symbol too long or terminator missing>
	CAIE CH,.CHESC
	AOJA P2,OGNF1
	CALL SAVCMD		;SAVE COMMAND STATE NOW
	MOVEI A,"!"
	MOVEM A,(P2)		;ALTMODE: OTAB+N_"!"
	MOVE C,COMCNT
	SUB C,COMAX		;# REMAINING COMMANDS
	IDIVI C,5
	ADD C,CPTR		;MAKE A COMMAND POINTER
	JUMPE D,OG2
	SOS C
	MOVMS D
	JRST .(D)
	IBP C
	IBP C
	IBP C
	IBP C
OG2:	MOVE B,COMAX		;ALL COMMANDS
OG4:	MOVEM C,CPTR
	MOVEM B,COMCNT
	MOVEI D,OTAB		;INIT SEARCH STRING TO "!"
OG5:	CAIN D,1(P2)		;END OF STRING?
	JRST OG3		;YES
	CALL SKRCH1		;NO. GET A CHAR
	CAMN CH,(D)		;MATCH ?
	AOJA D,OG5		;YES. MOVE ON.
	IBP C			;NO. TRY A NEW STARTING PT
	SOJG B,OG4		;COUNT DOWN COMMANDS
	CALL RESCMD		;IT FAILS. RESTORE STATE
	TXNN FF,COLONF		;NONESUCH LABEL. DID USER EXPECT THAT?
	ERROR <Tag not found>	;NO, GIVE HIM HIS ERROR MESSAGE
	JRST CFLUSH		;CONTINUE, THE USER WANTS TO DEAL WITH IT.

OG3:	ADJSP P,-CBLEN		;BLOW AWAY OLD SAVED STATE
	TXNE FF,COLONF		;DID USER INDICATE FUNNY : MODE?
	JRST CFLUSH		;YES, WE ARENT USING THE HASH TABLE
	POP P,A
	POP P,SYMS(A)
	MOVEM B,CNTS(A)
	MOVEM C,VALS(A)
	JRST CFLUSH

OGFND:	MOVE A,VALS(C)
	MOVEM A,CPTR
	MOVE A,CNTS(C)
	MOVEM A,COMCNT
	JRST CFLUSH
;APOSTROPHE MARKS END OF CONDITIONAL FOR DOUBLE QUOTE

APOST:	TXNN FF,SCANF		;SCANNING?
	JRST CFLUSH		;NO, NOTHING TO DO
	MOVEI A,"'"		;YES, SEE FOR WHAT
SCAN1:	CAME A,LCHAR		;FOR APOSTROPHE?
	JRST CFLUSH		;NO
	SOSGE SCNEST		;[502] DEPTH RIGHT YET?
	TXZA FF,SCANF		;[502] YES! BACK TO NORMAL SNAFU
	JRST CFLUSH		;[502] ..
	MOVEM A,SYL
	CALL TRACS		;IF TRACING, I WANT TO SEE THE END
	MOVE A,SYL
	CAIE A,"'"
	JRST CFLUSH
	POP P,SYL		;SAVE OUR RETURN ADDRESS
	CALL SAVCMD
	PUSH P,TRACS		;SAVE THE CURRENT TRACE MODE
	MOVSI CH,(<RET>)	;AND NUKE IT
	MOVEM CH,TRACS		;SO THIS CANT TRACE TWICE
SCANA:	SKIPN COMCNT
	JRST SCANB
	CALL RCH		;IGNORE INTERVIENING SPACES AND CRLFS
	CAIE CH,12
	CAIN CH," "
	JRST SCANA
	CAIN CH,15
	JRST SCANA
	CAIE CH,""""		;IS FIRST NON-BLANK A QUOTE COMMAND?
	JRST SCANB		;NO, SO GO RESET TO NORMAL
	SKIPLE COMCNT
	CALL RCH		;OK, IS " SOMETHING. IS IT "#?
	SETOM PCISG		;ASSUME OK
	CAIE CH,"#"		;IF IT IS, WE WANT THE NEXT "# DONE
	SETZM PCISG		;CHECK AND SEE
SCANB:	POP P,TRACS
	CALL RESCMD
	PUSH P,SYL
	JRST CFLUSH

DQUOTE:	CALL RCH
	TXNE FF,SCANF		;SCANNING?
	JRST DQS		;YES
	CAIN CH,"#"
	JRST [MOVE A,PCISG
	     SETZM PCISG
	     JRST DQ2]
	JUMPL T,AG0QE		;IF MISSING AN ARG, AND NOT "#, COMPLAIN
	CALL EVCOND		;GO EVAL A CONDITIONAL
DQ2:	JUMPL A,CFLUSH		;IF TRUE, GO GET NEXT COMMAND
				;ELSE...
NOGO:	MOVEI A,"'"		;SAY WE'RE LOOKING FOR AN APOSTROPHE
	CALL SCAN		;SCAN COMMAND STRING FOR END OF CONDITIONAL
	JRST CFLUSH

CCOND:	CALL RCH		;GET CONDITIONAL CHARACTER
	CALL EVCOND		;TEST C AGAINST IT
	JRST ARGINA		;0 OR -1 IN A

;EVCOND - GET NEXT COMMAND CHARACTER, SEE IF ITS A LEGAL CONDITIONAL CHAR
;IF IT ISNT, DIE
;IF IT IS, TEST THE VALUE IN C AND RETURN 0 IN A IF FAILED, -1 IF OK

EVCOND:	CAIN	CH,"#"		; "# ALWAYS fails.
	JRST	DFAIL
	LOAD CH,UPRCOD,(CH)
	SUBI	CH,"A"		;UPPERCASE, MINUS "A"
	CAIL	CH,0		;IN RANGE?
	CAILE	CH,DQLEN	;..?
DQQE:	ERROR	<Undefined command, no such conditional test>
	SKIPN	B,DQXCT(CH)	;GET WORD TO XCT TO TEST THIS CONDITION
	JRST	DQQE		;IF 0, THIS ISN'T A LEGAL COMMAND
	LDB	A,[POINT 4,B,12] ;GET THE AC FIELD!
	CAIN	A,A		;REF'ING AC A? IF SO...
	JRST	[JUMPL C,DFAIL	;ONLY CHARACTERS CAN BE LEGAL VALUES
		 CAILE C,177	;SO CHECK THAT FIRST
		 JRST DFAIL	;WASN'T A CHARACTER
		 MOVE A,CHRTAB(C) ;IT WAS, GET THE CHARACTER INFO TO TEST
		 JRST .+1]	;AND GO.
	XCT	B		;PERFORM THE TEST
DFAIL:	TDZA	A,A		;NONSKIP MEANS FAILED, MARK /W 0
DOK:	SETO	A,		;SKIP OR JUMP HERE MEANS PASSED
	TXNE FF,COLONF		;INVERT THE TEST?
	SETCA A,		;YES
	RET			;RETURN WITH ANSWER

;INDEX THIS TABLE TO DO VALUE TESTS (IE, "E, "C STUFF)
;IF THE INSTRUCTION HAS "A" IN THE AC FIELD, THE VALUE BEING TESTED
;MUST BE IN THE RANGE 0-177, AND THE ENTRY FROM CHRTAB MUST BE IN A,
;FOR THE TEST TO MAKE SENSE.

DQXCT:	TXNN	A,CH%ALP	;A ALPHABETIC CHARACTERS
	TXNN	A,CH%BL1	;B BLANKS <SP><TAB><CR><LF><FF>
	TXNN	A,CH%SBL	;C SYMBOL (A-Z 0-9 .%$)
	TXNN	A,CH%DIG	;D DIGIT
	JUMPE	C,DOK		;E .EQ. 0
	JUMPGE	C,DOK		;FALSE, FAILED (.GE. 0)
	JUMPG	C,DOK		;G .GT. 0
	0			;H
	JUMPA 	A,DOK		;I ANY CHARACTER
	JUMPLE	C,DOK		;J .LE. 0
	CALL	CNTCHK		;K ANY CONTROL CHARACTER
	JUMPL	C,DOK		;L .LT. 0
	0			;M
	JUMPN	C,DOK		;N .NE. 0
	TRNN	C,1		;O ODD
	TXNN	A,CH%PN1	;P PUNCTUATION
	CALL	QTST		;Q TEXT QREG
	0			;R
	0			;S
	JUMPL	C,DOK		;TRUE (.LT. 0)
	TXNN	A,CH%UPR	;U UPPER CASE
	TXNN	A,CH%DWN	;V LOWER CASE
	TXNN	A,CH%UPR	;W UPPER CASE
	TXNN	A,CH%BL0	;X SPACING TYPES THAT AREN'T END-OF LINE
	TXNN	A,CH%USR	;Y USER SETTABLE CONDITION
	CALL	ZCHK		;Z BETWEEN 0 AND Z INC
	 DQLEN=.-DQXCT

CNTCHK:	JUMPL	C,CNTCK2	;CONTROL CHARACTER, 0 TO 37
	CAIGE	C,40		;SPACE OR BETTER?
	AOS	(P)		;NO, SKIP, THIS IS A CONTROL CHARACTER
CNTCK2:	RET

ZCHK:	JUMPL	C,CNTCK2	;BETWEEN 0 AND Z. NONSKIP IF <0...
	ADD	C,BEG		;OFFSET BY BEG SO WE CAN COMPARE
	CAMG	C,ZEE		;MUST BE .LE. ZEE TO BE ACCEPTED
CPOPJ1:	AOS	(P)
	RET

;GET HERE WHEN "x ENCOUNTERED DURING A SCAN

DQS:	MOVEI A,"'"
DQS1:	CAMN A,LCHAR		;ARE WE SCANNING FOR APOSTROPHE
	AOS SCNEST		;YES, SO NEST DEEPER
	JRST CFLUSH		;RETURN FOR NEXT COMMAND
;LUUO HANDLER
;S0UUOH - HANDLES LUUO'S FROM SECTION 0, INVOKED BY CALL S0UUOH
;	  IN LOCATION .JB41; WORKS BY DUMMYING UP NON-ZERO SECTION
;	  LUUO BLOCK
;S1UUOH - HANDLES LUUO'S FROM NON-ZERO SECTIONS, INVOKED BY HARDWARE
;	  PASSING CONTROL TO LOCATION WHOSE ADDRESS IS IN UUOB+.ARNPC

S0UUOH:	MOVEM 16,UUOACS+16	;SAVE AC'S 0-16
	MOVEI 16,UUOACS
	BLT 16,UUOACS+15
	HRRZ TT,.JBUUO		;COPY EFFECTIVE ADDR TO UUO BLOCK
	MOVEM TT,UUOB+.AREFA
	LDB TT,[POINT 4,.JBUUO,12] ;COPY AC SPECIFICATION TO UUO BLOCK
	DPB TT,[POINT 4,UUOB+.ARPFL,30]
	LDB TT,[POINT 9,.JBUUO,8] ;COPY OPCODE TO UUO BLOCK
	DPB TT,[POINT 9,UUOB+.ARPFL,26] ;KEEP OPCODE IN TT FOR DISPATCH
	JRST LUUO1		;MERGE WITH NON-0 SECTION CODE

S1UUOH:	MOVEM 16,UUOACS+16	;SAVE AC'S 0-16
	MOVEI 16,UUOACS
	BLT 16,UUOACS+15
	PUSH P,UUOB+.AROPC	;PUT RETURN PC ON STACK FOR POPJ
	LDB TT,[POINT 9,UUOB+.ARPFL,26] ;GET OPCODE OF UUO
LUUO1:	CAIL TT,LUUOTB		;IS THIS OPCODE DEFINED FOR TV?
UUOQE:	IERROR <Undefined LUUO>	;NO
	CALL UUOTAB(TT)		;GO TO ROUTINE
	MOVSI 16,UUOACS
	BLT 16,16		;RESTORE AC'S
	RET			;END OF UUO.

UUOTAB:	JRST UUOQE		;ILLEGAL, GO DIE
	JRST UERR0		;ERROR
	JRST UPSTR0		;PRINT STRING
	JRST %LDB		;GO HANDLE LDB FROM BUFFER
	JRST %LDB		;GO HANDLE ILDB FROM BUFFER
	JRST LERR0		;ERROR BUT RETURN TO CALLER
	JRST JERR0		;JSYS ERROR
	JRST LJERR0		;LOCAL JSYS ERROR
	JRST IERR0		;INTERNAL ERROR
	JRST UCTYP0		;PRINT SINGLE CHARACTER
LUUOTB==.-UUOTAB

;JSYS ERROR.

JERR0:	CALL LJERR0		;DO IT LIKE LOCAL ONE
	JRST GO			;BUT DON'T RETURN

;LOCAL JSYS ERROR.

LJERR0:	CALL ERRMES		;PRINT PROGRAM'S REASON FOR ERROR
	PSTR < - >
	SETZM ERRBUF		;CLEAR BUFFER IN CASE ERSTR FAILS
	HRROI A,ERRBUF		;PREPARE TO BUFFER SYSTEM'S REASON
	HRLOI B,.FHSLF		;OURSELF, LAST ERROR
	SKIPE D,LSTERR		;ANY PARTICULAR ERROR?
	HRR B,D			;YES, USE IT
	MOVSI C,-ERRBLN*5	;NUMBER OF CHARACTERS WE HAVE ROOM FOR...
				; IN OUR BUFFER
	ERSTR%			;GET ERROR STRING
	 PSTR <Unknown error code>
	 JFCL			;DON'T WORRY IF LENGTH TOO SHORT
	UPSTR ERRBUF		;PRINT ERROR MESSAGE
	SETZM LSTERR		;DON'T USE SAME PARTICULAR ERROR OVER AGAIN
	CALLRET CRR		;END WITH CARRIAGE RETURN

;LOCAL ERROR (LERROR) MEANS PRINT THE MESSAGE AS AN ERROR, BUT
;RETURN TO THE CALLER

LERR0:	CALLRET ERRMES		;NO CRLF, SINCE MIGHT BE COMPOSITE MESSAGE

;INTERNAL ERROR

IERR0:	CALL ERRMES		;PRINT THE MESSAGE
	HRROI A,[ASCIZ/
 Please submit an SPR. Version /]
	PSOUT%
	MOVX A,.PRIOU
	MOVEI B,.EDIT
	MOVEI C,^D10
	NOUT%
	 ERJMP .+1
	CALL CRR		;END OF LINE
	CALL DOHALT		;STOP
	RET			;ATTEMPT TO CONTINUE IF USER REQUESTS SO

;ERROR UUO
;TYPE ERROR MESSAGE FOLLOWED BY LAST 10 CHARS OF COMMAND STRING

UERR0:	CALL ERRMES		;PRINT THE ERROR MESSAGE
	SKIPGE COMCNT		;DID COMCNT OVERSHOOT (AT RCH)?
	SETZM COMCNT		;YES, ASSUME COMMAND JUST EXHAUSTED
	MOVE A,COMAX
	SUB A,COMCNT
	MOVEM A,ERR1		;ERR1 := NUMBER OF CHARACTERS EXECUTED
	MOVE P1,CPTR		;VALUE OF CPTR WHEN LAST ERROR OCCURRED.
	MOVEI P2,12
	SUBI P1,2		;BACK POINTER UP 10 CHARACTERS.
	PSTR <:	>
	ILDB A,P1		;GET CHARACTER
	CAMG P2,ERR1		;WAS IT IN THE COMMAND BUFFER?
	CALL TYO		;YES. TYPE IT.
	CAME P1,CPTR		;HAVE WE REACHED THE BAD COMMAND?
	SOJA P2,.-4		;NO. DO IT AGAIN.
	CALL CRR		;TYPE CRLF AFTER ERROR MESSAGE IF NOT SCREEN.
	JRST GO

;PRINT ERROR MESSAGE

ERRMES:	CALL WINCLS		;SO ERROR MESSAGES DON'T GET ERASED
	SETZM INIJFN		;IF ERROR DURING TV.INI,
				; DON'T TRY TO REEXECUTE IT AT CLIS
	PUSH P,UUOB+.AREFA	;SAVE PTR TO ERROR STRING
	CALL LM			;MAKE SURE WE'RE AT LEFT MARGIN
	PSTR <?>		;QUESTION MARK MUST ALWAYS BE AT LEFT MARGIN.
	CALL CLRINP		;CLEAR TYPING INPUT
	POP P,TT		;RECOVER ADR OF ERROR STRING
	HRRO TT,TT		;CONSTRUCT BYTE PTR
	CALLRET PSTR0		;PRINT IT

;PRINT STRING UUO

UPSTR0:	HRRO TT,UUOB+.AREFA	;GET ADR OF STRING
	CALLRET PSTR0		;PRINT IT
;COMMAND TO COMPLEMENT TRACE MODE. "?" AS A COMMAND

QUESTN:	MOVE A,[JRST TYO]
	TXCE FF,TRACEF
	MOVSI A,(<RET>)
	MOVEM A,TRACS
	TXNE FF,TRACEF		;DID WE TOGGLE INTO TRACE MODE?
	CALL WINCLS		;DON'T ERASE TRACINGS
	JRST CFLUSH

COMM:	MOVEI CH,.CHESC		;ASSUME ESCAPE ENDS STRING
	TXNN FF,SLSL		;ATSIGN MODIFIER?
	JRST COMM0		;NAY, GO ACT AS NORMAL
	CALL DISCOC		;ATSIGN FORM ALLOWS CONTROL CHARACTER OUTPUT
	CALL SKRCH		;GET THE DLIMIT CHAR
COMM0:	MOVEM CH,DLIMIT		;SET DELIMITER
COMM1:	PUSHJ P,SKRCH		;GET A COMMENT CHAR
	SKIPE ABORTF		;ABORT?
	JRST TYOQT		;YES, QUIT TYPEOUT
	CAMN CH,DLIMIT		;END OF STRING?
	JRST [TXNE FF,SLSL	;YES, WE WE DOING LITERAL OUTPUT?
	      CALL REGCOC	;YES, SET IT BACK
	      JRST CFLUSH]	;AND LEAVE.
	MOVE A,CH
	PUSHJ P,TYO		;TYPE IT
	JRST COMM1

CALDDT:	SKIPN 770000		;MAKE SURE DDT IS LOADED
	ERROR <DDT is not loaded>
	JRST 770000		;ASSUMED LOC OF DDT
;THE FOLLOWING ROUTINE DECIDES WHERE IN BUFFER TO START DISPLAYING
;FROM.  IT TRYS TO CAUSE THE POINTER TO BE ABOUT ONE HALF DOWN THE
;WINDOW.  AT POPJ TIME, SCRNPT HAS BEEN SET UP AS AN ADDRESS
;OF THE BUFFER CHARACTER TO BE DISPLAYED FIRST.
;THE SCREEN SIZE IS DETERMINED BY THE CONTENTS OF DLENTH.

WINIT:	STKVAR <DFT>
	MOVEI P1,0		;FIRST FIND THE END OF THE CURRENT LINE
	MOVE I,PT		;START FROM THE POINTER.
WINL:	CAML I,ZEE		;END OF BUFFER?
	JRST WINND1		;YES, SO SURELY END OF LINE!
	CALL GET		;FIND OUT WHAT CHARACTER WE'RE AT.
	CAIE CH,12
	CAIN CH,15
	JRST WINND1		;LF OR CR, SO WE'RE AT THE END OF THE LINE.
	AOJ P1,
	CAIG CH,37
	CALL SFLAGC
	CAIA
	AOJ P1,	;FLAGGED LETTER OR CONTROL CHARACTER TAKE UP TWO COLUMNS.
	CAIL P1,MAXWTH	;NEVER SCAN MORE COLUMNS THAN LONGEST ALLOWED LINE.
	JRST WINND1
	CAMGE P1,SWIDTH	;DON'T SCAN LONGER THAN SPECIFIED TERMINAL LINE WIDTH.
	AOJA I,WINL		;KEEP SCANNING FOR END OF LINE.
WINND1:	MOVE A,DLENTH		;GET NUMBER OF LINES IN SCREEN TO BE USED
	IDIVI A,2		;QUOTIENT IS HOW MANY LINES WANTED ABOVE POINTER
	MOVEM A,DFT
WINR5:	MOVEI P1,0		;CHARACTER COUNTER

;WE NOW COUNT LINES IN REVERSE, ACCOUNTING FOR ONE LINE EVERY TIME
;A SCREEN LINE'S WIDTH OF CHARACTERS IS SCANNED, OR AN END OF
;LINE WITHIN THE ACTUAL BUFFER IS ENCOUNTERED

	CAMG I,BEG		;ARE WE ALREADY AT BEGINNING OF BUFFER ?
	JRST WINR1		;YES
WINR4:	SUBI I,1		;BACK UP ONE CHARACTER
	CAMG I,BEG		;BEGINNING OF BUFFER ???
	JRST WINR1		;YUP
	CALL GET		;MAKE BYTE POINTER AND GET CHAR INTO CH
	CAIN CH,12		;LF ??
	JRST WINLF		;YES, END OF LINE
	ADDI P1,1		;ACCOUNT FOR CHARACTER SPACE
	CAIN CH,.CHTAB		;TAB?
	ADDI P1,6		;YES, ASSUME WORST IS 8, 1 ABOVE,
				; 6 HERE, 1 BELOW
	CALL SFLAGC		;AND IF IT SHOULD BE FLAGGED ON OUTPUT
	CAIG CH,37		;OR IS A CONTROL CHARACTER
WINR6:	ADDI P1,1		;IT TAKES UP AT LEAST TWO POSITIONS
	CAIL P1,MAXWTH
	JRST WINRX		;RIDICULOUSLY LONG LINES DON'T LOUSE US UP.
	CAMGE P1,SWIDTH		;REAL LONG LINE?
	JRST WINR4		;NOT YET, GOBBLE ON
WINRX:	SOSLE DFT		;DO MORE LINES?
	JRST WINR5		;YES
WINR1:	MOVEM I,SCRNPT		;SET UP POINTER TO BUFFER WHERE TO START
				; DISPLAYING

;...
;NOW WE PRETTY MUCH KNOW WHERE TO START DISPLAYING FROM.  THE FOLLOWING
;STEP MAKES AN EFFORT TO NOT CHOP OFF THE FIRST LINE ON THE DISPLAY.
;NOTE THAT THE FOLLOWING CODE IS NEEDED IN ADDITION TO THE LININI
;ROUTINE, SINCE WHEN A SCREEN REFRESH IS ALREADY CALLED FOR, WE
;ARE MORE WILLING TO BACK UP TO THE BEGINNING OF THE LINE, SINCE WE
;DON'T CARE IF THAT CAUSES THE REST OF THE LINE TO SPILL ONTO THE NEXT
;ON THE SCREEN.
;...

	MOVE A,I		;GET CURRENT BEGINNING OF DISPLAY
	CALL LINBGQ		;TRY TO FIND BEGINNING OF LINE
	MOVEM A,SCRNPT		;THIS IS WHERE TO DISPLAY FROM
	RET

WINLF:	SUBI I,1		;SAW LINEFEED, BACKUP AND SEE IF CR
	CALL GET		;GET CHAR BEFORE LINEFEED
	CAIE CH,15		;CR?
	AOJ I,			;NO
	SOSLE DFT		;DONE ENOUGH LINES?
	JRST WINR5		;NOT YET
	AOJA I,WINR1		;ENOUGH LINES BACK, PREPARE TO EXIT

;ROUTINE TO FIND BEGINNING OF BUFFER LINE.  PASS IT CHARACTER ADDRESS
;IN A.  THE ROUTINE RETURNS WITH ADDRESS OF BEGINNING OF LINE IN A, OR
;BEGINNING OF BUFFER, OR A UNMODIFIED IF NEITHER IS FOUND.

LINBGQ:	STKVAR <FSTCNT,GIVENA>
	MOVEM A,GIVENA
	SETZM FSTCNT		;AMOUNT WE'VE TRIED TO BACKUP
	SOS I,A
WINBU:	CAMGE I,BEG		;ARE WE BACK TO BEGINNING OF BUFFER?
	AOJA I,WINBU1		;YES, SO WE'RE AT BEGINNING OF LINE
	CALL GET		;SEE IF WE'RE BACK TO BEGINNING OF LINE
	CAIN CH,12		;LINEFEED?
	AOJA I, WINBU1		;YES, ASSUME BEGINNING OF LINE
	AOS A,FSTCNT		;NOT YET, SEE HOW HARD WE'VE LOOKED
	CAIGE A,MAXWTH		;MAXIMUM AMOUNT FOR DISPLAY LINE?
	SOJA I,WINBU		;NO, SO KEEP LOOKING
	MOVE I,GIVENA		;YES, SO NO MODIFICATION
WINBU1:	MOVE A,I		;RETURN LINE BEGINNING IN A
	RET
;ROUTINE TO UPDATE THE SCREEN.  THIS IS INVOKED EVERY TIME TV IS READY
;TO INPUT A COMMAND.  IT IS ALSO INVOKED BY THE "WUPDATE$" COMMAND.

UPDATE:
 OPTION ENC,<
	skipn	encflg		;encryption turned on?
	jrst	updata		;no
	hrloi	a,(tl%cor!tl%cro)
	seto	b,		;yes, break links before typing out
	tlink
	 erjmp	.+1
updata:
>
	MOVE I,ZEE		;GET POINTER TO END OF BUFFER
	SUBI I,1
	CALL GETX		;CHANGE TO BYTE POINTER
	MOVEM TT,SCRNZ		;TELL DISPLAY TO GO ALL THE WAY
	MOVE A,TTYOUT
	MOVEI B,.MORLC
	MTOPR%			;READ LINE COUNTER
	MOVEM C,CRRCNT		;IN CASE WE HAVE TO LINE STARVE UP
				; FROM WHERE WE ARE
	MOVEI B,.MORLM		;GET MAXIMUM LINES OUTPUT
	MTOPR%
	SUB C,SSIZE		;CALCULATE NUMBER OF SCROLLS
	AOJ C,			;NO SCROLL IF EXACTLY AT BOTTOM
	CAML C,SSIZE
	MOVE C,SSIZE		;DON'T TRY TO SCROLL MORE THAN ENTIRE SCREEN
	MOVN B,C
	SKIPN SCRNF		;ON A SCREEN?
	JRST NOSCRL		;NO, SO NO SCROLLING
	JUMPLE C,NOSCRL		;NEG SCROLL AMOUNT MEANS NO SCROLLING HAPPENED
	ADDM B,DISBLK		;ADJUST MARK FOR WHERE PRESERVED OUTPUT BEGINS
	ADDM B,CRRCNT		;ADJUST CURSOR POSITION UPSCREEN DUE TO SCROLL
	MOVE I,LINNEW(C)	;FIND WHAT PART OF BUFFER NOW BEGINS DISPLAY
	MOVEM I,SCRNPT		;SAVE NEW BEGINNING ADDRESS
	IMUL C,[<WINDEX>B17]	;C HAS BUFFER WORD OFFSET IN LEFT HALF
	ADD C,[WINDOW,,WINDOW]	;MAKE WINDOW+X,,WINDOW
	MOVE B,DLENTH		;GET NUMBER OF LINES NEEDED TO SCROLL
	IMULI B,WINDEX		;GET NUMBER OF MEMORY WORDS INVOLVED
	HLRZ D,C		;GET FIRST WORD BEING MOVED FROM
	ADDI D,-1(B)		;CALCULATE LAST MEMORY WORD MOVED FROM
	SUBI D,WINDOW+WINTOP	;SEE HOW MANY WOULD BE OUT OF BOUNDS
	CAIGE D,0		;ARE THERE SOME OUT OF BOUNDS?
	MOVEI D,0		;NO, SO SAY EXACTLY NONE
	SUB B,D			;TRIM SIZE OF BLT TO NOT MOVE WORDS FROM
				; OUT OF BOUNDS
	BLT C,WINDOW-1(B)	;SCROLL THE MEMORY TO AGREE WITH SCREEN
	MOVEI D,WINDOW(B)	;GET NEXT ADDRESS TO BE FIXED 
				;(FIRST ONE BLT MISSED)
	MOVE C,DLENTH		;SEE HOW MANY LINES WE CARE ABOUT
	IMULI C,WINDEX		;SEE HOW MANY BUFFER WORDS WE CARE ABOUT
	ADDI C,WINDOW-WINDEX	;GET FIRST ADDRESS OF LAST GROUP WE CARE ABOUT
UPD1:	CAMLE D,C		;DO WE CARE ABOUT THIS WORD?
	JRST NOSCRL		;NO, WE'RE DONE FIXING MEMORY
	SETOM (D)		;YES, KILL IT TO FORCE IT TO BE REDISPLAYED
	ADDI D,WINDEX		;STEP TO FIRST WORD OF NEXT GROUP
	JRST UPD1
NOSCRL:	MOVE A,DISBLK		;FIND OUT WHERE PRESERVED OUTPUT BEGINS
	SOJ A,			;GET LINES ALLOWABLE FOR WINDOW,
				; LEAVING ROOM FOR PROMPT AND PRESERVED OUTPUT
	CAMG A,SLENTH		;DON'T LET THIS WINDOW EXCEED STANDARD WINDOW.
	SKIPGE WINFLG		;DON'T RESET SCREEN LENGTH IF THERE
				; IS PRESERVED OUTPUT
	MOVE A,SLENTH		;IT WAS.
	MOVEM A,DLENTH		;WE JUST MADE SURE OUTPUT OF T,=, ETC. -
				;  DON'T GET ERASED
	SKIPG DLENTH		;MAYBE DON'T DISPLAY BECAUSE WE MUST
				; PRESERVE THE WHOLE SCREEN
	RET			;DON'T DISPLAY IF ZERO LENGTH WINDOW
	SKIPE MESFLG		;SCREEN MESSED UP?
	CALL CLRSCN		;YES, SO CLEAR GARBAGE OFF IT
	MOVE I,SCRNPT		;GET CHARACTER ADDRESS OF FIRST CHARACTER
	SKIPN MESFLG		;IF REDOING ENTIRE SCREEN ANYWAY, RECENTER IT
	CAML I,ZEE		;ARE WE IN BUFFER?
	CALL WINIT		;NO, RELOCATE DISPLAY BEGINNING POINTER
	CALL DISINI		;INITIALIZE DISPLAY ROUTINE
	CALL LININI		;INITIALIZE FIRST LINE OF DISPLAY
	CALL WINFIL		;FILL UP NEW SCREENFUL
	SKIPN PUTPTF		;SEE IF POINTER IS ON SCREEN
	CALL WINIT		;WASN'T, SO GET NEW STARTING CHARACTER
	SETZM MESFLG		;CLEAR FLAG SAYING SCREEN WAS MESSED UP
	CALL DISINI		;INITIALIZE DISPLAY ROUTINE
	CALL VIEW1		;DISPLAY TO END OF BUFFER
GO2:	RET

;THE WUPDATE$ COMMAND UPDATES THE SCREEN.

WUPDAT:	SETOM UPDATF		;SAY DOING WUPDATE
	CALL UPDATE
	SETZM UPDATF
	JRST CFLUSH		;[502] DONE

;THE NV OR N,MV COMMAND IS JUST LIKE T, EXCEPT THE DISPLAY IS JUST
;UPDATED TO REPRESENT THE TEXT DESIRED TO BE VIEWED.

VIEW:	SKIPN SLENTH		;MAKE SURE A WINDOW SIZE EXISTS
	JRST TYPE		;NO, SO DO REGULAR "T" COMMAND
	CALL TVINIT		;MAKE SURE WE HAVE REASONABLE ARGUMENTS
	MOVEM I,SCRNPT		;CHAR ADDRESS OF CHAR IN BUFFER TO
				; BE DISPLAYED FIRST
	MOVE I,C
	SUBI I,1
	SETZM DISBLK		;DON'T LET ANY OUTPUT HAPPEN AFTER V COMMAND.
	AOS WINFLG		;NOTE THAT PRESERVED OUTPUT HAS STARTED.
	MOVE A,SLENTH
	MOVEM A,DLENTH		;SET WINDOW SIZE TO DEFAULT
	CALL GETX		;MAKE BYTE POINTER
	MOVEM TT,SCRNZ		;LDB POINTER TO LAST CHARACTER TO BE DISPLAYED
	CALL DISINI
	CALL VIEW1		;DISPLAY SOME OF BUFFER
VIEW3:	SKIPE EOBFLG		;SEEN END OF BUFFER?
	JRST CFLUSH		;[502] DONE
	CALL TYIX		;SEE IF HE WANTS TO SEE MORE
	CAIE A,C.MORE		;USER WANT TO SEE MORE?
	JRST	[CALL RECHAR	;NO
		 JRST CFLUSH]
	CALL MORE1		;YES, SHOW HIM SOME
	JRST VIEW3		;LOOP UNTIL DONE

;HERE WHEN FIRST CHARACTER TYPED OF COMMAND IS SPACE.  WE SHOULD DISPLAY
; NEXT BUFFER SECTION.

DMORE:	CALL MORE1		;DO THE WORK
	JRST CLIS		;GO BACK FOR NEXT COMMAND

MORE1:	CALL MORE		;DO THE DISPLAYING
	MOVEI A,C.MORE
	CALLRET BCHAR		;REMEMBER IN BACKUP FILE THAT USER TYPED SPACE

;COME HERE TO DO MORE IF USER TYPES SPACE

MORE:	AOS A,SCNEND		;YES, FIND OUT WHERE WE LEFT OFF
	MOVEM A,SCRNPT		;AND RESUME THERE
	SKIPN SCRNF		;IF NOT ON A SCREEN,
	CALL CRR		;TYPE A CRLF HERE.
	CALLRET VIEW2		;GO BACK AND DISPLAY MORE

;ENTER HERE IF SCRNPT AND SCRNZ ARE ALREADY SET UP

VIEW1:	MOVE TT,SCRNZ
	CALL PTR2AD		;MAKE CHARACTER ADDRESS FROM POINTER
	CAMGE I,SCRNPT
	SETOM EOBFLG		;IF NOTHING TO DISPLAY, PRETEND END OF BUFFER
VIEW2:	SETZM COLUMN
	MOVE A,DLENTH		;START WITH FULL WINDOW'S WORTH
	SKIPN EOBFLG		;SAYING "MORE"?
	SOJ A,			;YES, USE ONE LESS LINE FOR DISPLAY
	CALL DISPLA		;OUTPUT FULL WINDOW'S WORTH
	SKIPN SCRNF		;HARDCOPY?
	 JRST [	CALL CRR	;YES, FINISH LAST LINE
		JRST NOLNPS]	;SKIP CURSOR POSITIONING STUFF
	MOVE CH,DLENTH		;NO, SO PROMPT USER FOR PERMISSION
	SOJ CH,
	CALL LINPOS		;BY REQUESTING PERMISSION AT BOTTOM
	CALL EOL		;OF WINDOW AREA
NOLNPS:	SKIPN UPDATF		;NO "--MORE--" IF WUPDATE
	SKIPE EOBFLG		;QUIT IF END OF BUFFER
	JRST LASTV		;YES
	SKIPE TYPEF		;SKIP IF NOT EO-BUFFER AND USER
				; HASN'T TYPED ANYTHING
	JRST LASTV		;USER TYPED SOMETHING
	MOVE A,TTYOUT		;GET OUTPUT CHANNEL
	HRROI B,[IFE FTUNS,<ASCIZ /--More--/>
		 IFN FTUNS,<ASCIZ /--Less--/>]
	MOVEI C,0
	SOUT%			;ASK FOR PERMISSION TO CONTINUE DISPLAYING
LASTV:	SKIPN SCRNF		;HARDCOPY?
	CALLRET CRR		;YES, PUT END OF LINE AFTER "MORE" AND RETURN
	MOVE CH,DLENTH
	CALL LINPOS		;POSITION CURSOR AFTER WINDOW
	HRRZ A,CRRCNT		;TELL SYSTEM CURSOR POSITION
	CALL SETLIN
	RET

;ROUTINE TAKING ARG IN A AND SETTING LINE COUNTER TO THAT VALUE

SETLIN:	MOVE C,A		;ARG INTO B FOR JSYS
	MOVE A,TTYOUT		;STANDARD OUTPUT
	MOVEI B,.MOSLC		;SET LINE COUNTER
	MTOPR%
	MOVEI B,.MOSLM		;SET MAXIMUM TOO
	MTOPR%
	MOVEI B,0
	SFPOS%	;SAY WE'RE AT LEFT MARGIN (PAGE POSITION SHOULDN'T MATTER)
	RET
;^L CLEARS THE SCREEN AND CAUSES THE POINTER TO BE MOVED
;INTO THE CENTER OF THE SCREEN THE NEXT TIME AN UPDATE HAPPENS

CTRLL:	CALL CLRSCN
	JRST CFLUSH		;[502] CLEAR SCREEN AND LEAVE

CLRSCN:	HRLOI A,377777		;USE OUT-OF-BOUNDS VALUE TO FORCE RECALCULATION
	MOVEM A,SCRNPT
	SETZM WINDOW		;CLEAR WINDOW MEMORY TO SHOW THERE'S
				; NOTHING ON SCREEN
	MOVE A,[WINDOW,,WINDOW+1]
	BLT A,WINDOW+WINTOP
	CALL HOME		;YES, HOME UP FIRST
CEOS:	SKIPN SCRNF		;ARE WE ON A SCREEN?
	RET			;NO, SO DON'T TRY TO CLEAR IT
	JRST EOS		;THEN CLEAR TO END OF SCREEN

CLREOS:	MOVEI CH,37		;MAGIC CLEAR TO END OF SCREEN CHARACTER
	CALLRET CNFILL		;REQUIRES FILLERS
CUP:	MOVEI CH,C.UP		;LINE STARVE
	CALLRET CNFILL

;SCREEN MANAGEMENT ROUTINES

;ROUTINE TO ERASE "REST" OF LINE.

EOL:	CALL DISCOC		;MAKE CONTROL CHARACTERS TYPE LITERALLY
	MOVE A,TRMTYP		;FIND OUT WHAT SPECIES OF TERMINAL WE ARE
	CALL @EOLTAB(A)		;CALL APPROPRIATE ROUTINE
	CALLRET REGCOC		;RESTORE CONTROL CHARACTER STUFF

	TERINI EOLTAB
	TER (.TTV05,IFIW!CLREOL)
	TER (.TTV50,IFIW!V50EOL)
	TER (.TT100,IFIW!V100CL)
	TER (.TTV52,IFIW!V50EOL) ;VT52 GETS CLEARED JUST LIKE VT50

;ROUTINE FOR ERASING "REST OF SCREEN"

EOS:	CALL DISCOC		;MAKE SO ALL CONTROLS ARE LITERAL
	MOVE A,TRMTYP
	CALL @EOSTAB(A)		;CALL APPROPRIATE ROUTINE
	CALLRET REGCOC		;RESTORE REGULAR CONTROL STUFF AND RETURN

	TERINI EOSTAB
	TER (.TTV05,IFIW!CLREOS)
	TER (.TTV50,IFIW!V50EOS)
	TER (.TT100,IFIW!V100ES)
	TER (.TTV52,IFIW!V50EOS) ;SCREEN CLEARING THE SAME ON VT52 AS VT50

;ROUTINE TO PUT CURSOR AT TOP LEFT (HOME) POSITION ON SCREEN.

HOME:	SETZB A,CRRCNT		;RESET LINE COUNTER.
	CALL SETLIN		;TELL SYSTEM WE'RE AT TOP OF SCREEN
	SKIPN SCRNF		;ON A SCREEN?
	CALLRET CRR		;NO, JUST TYPE CRLF AND RETURN
	CALL DISCOC		;MAKE CONTROL CHARACTERS SOME OUT LITERALLY
	MOVE A,TRMTYP
	CALL @HOMTAB(A)		;DO SPECIES DEPENDENT HOMEUP
	CALLRET REGCOC		;RESTORE CONTROL CHARACTERS AND RETURN

	TERINI HOMTAB
	TER (.TTV05,IFIW!HOMEUP)
	TER (.TTV50,IFIW!V50HOM)
	TER (.TT100,IFIW!V100HM)
	TER (.TTV52,IFIW!V50HOM) ;VT50 AND VT52 HOME THE SAME WAY

;LINE STARVE...

LINSTV:	CALL DISCOC		;TYPE CONTROLS LITERALLY
	MOVE A,TRMTYP
	CALL @STVTAB(A)
	CALLRET REGCOC		;RESTORE CONTROL CHARACTER STUFF

	TERINI STVTAB
	TER (.TTV05,IFIW!CUP)
	TER (.TTV50,IFIW!V50CUP)
	TER (.TT100,IFIW!V100UP)
	TER (.TTV52,IFIW!V50CUP)

;VT100 ROUTINES

;MACRO TO CAUSE DISPLAY OF ANSI SEQUENCE ESCAPE - OPEN BRACKET - CHARACTER
;FOLLOWED BY RET

DEFINE DSPANS(CHR)
<	MOVEI A,.CHESC	;;FIRST SEND ESCAPE
	CALL TYO
	MOVEI A,"["	;;THEN BRACKET
	CALL TYO
	MOVEI A,CHR	;;THEN SPECIFIC CHARACTER
	CALLRET TYO	;;DONE
>

V100ES:	DSPANS "J"

V100CL:	DSPANS "K"

V100UP:	DSPANS "A"

;***; [477] ADD 1 line @ V100HM:+0	LEM	11-12-81
V100HM:	PSTR <[?1l>			;[477] reset Cursor Key Mode
	DSPANS "H"

;VT50 ROUTINES

DEFINE DSPANS(CHR)
<	MOVEI	A,V52.ES
	CALL	TYO
	MOVEI	A,CHR
	CALLRET	TYO
>

V50EOS:	DSPANS	112	;CLEAR TO END OF SCREEN

V50EOL:	DSPANS	V52.EL	;CLEAR TO END OF LINE

V50HOM:	DSPANS	110	;HOMEUP

V50CUP:	DSPANS	V52.UP	;LINE STARVE

;VT05 CURSOR CONTROL

CLREOL:	SKIPA CH,[C.EOL]	;MAGIC VT05 CLEAR TO END OF LINE CHARACTER
HOMEUP:	MOVEI CH,"]"-100	;MAGIC VT05 CHARACTER TO HOME UP
CNFILL:	MOVE A,CH
	CALL TYO		;TYPE MAGIC CHARACTER
	MOVEI A,0
	CALL TYO
	MOVEI A,0
	CALL TYO
	MOVEI A,0
	CALL TYO
	MOVEI A,0
	CALL TYO		;FILLERS
	RET

;ROUTINE TO REMEMBER WHERE PRESERVED OUTPUT STARTS.
;PRESERVED OUTPUT IS LIKE T OR = COMMAND.  BUFFER SHOWING SHOULDN'T
;OVERPRINT SUCH OUTPUT.

WINCLS:	AOSE WINFLG		;IS THIS FIRST PRESERVED OUTPUT
				; FOR THIS COMMAND STRING?
	RET			;NO, SO WE'VE ALREADY MARKED POSITION
	CALL LM			;START "T" "=" ETC. AT LEFT MARGIN
	CALL SYSLIN		;FIND OUT LINE WE'RE ON
	MOVEM A,DISBLK		;REMEMBER WHERE PRESERVATION STARTS
	RET

;ROUTINE TO FIND OUT WHAT LINE WE'RE ON

SYSLIN:	MOVE A,TTYOUT
	MOVEI B,.MORLC		;READ LINE COUNTER
	MTOPR%
	MOVE A,C		;GIVE ANSWER IN A
	RET

;ROUTINE TO DISPLAY NEW WINDOW
;PASS IT NUMBER OF LINES TO USE IN A.

DISPLA:	TRVAR <OLDPTR,NEWPTR,NEWCOL,OLDCOL,LINCTR,LINPTR,OLDBEG,NEWBEG,SPCNT,LEN2,LEN1,DLEN1>
	MOVEM A,DLEN1		;REMEMBER NUMBER OF LINES AVAILABLE FOR DATA
	CALL DISCOC		;MAKE CONTROL CHARACTERS ECHO LITERALLY
	SKIPE SCRNF		;HARDCOPY?
	JRST DISPLB		;NO
	CALL LM			;YES, MAKE SURE AT LEFT MARGIN
	SETZM CRRCNT		;ASSUME STARTING AT TOP OF WINDOW
DISPLB:	SETZM TYPEF		;FIRST ASSUME THERE'S NO TYPEAHEAD
	MOVE A,TYIJFN
	SIBE%			;SKIP IF THERE ISN'T.
	 SETOM TYPEF		;THERE IS, SET FLAG SAYING SO.
	CALL WINFIL		;FILL WINEW WITH NEW DISPLAYFUL
	SETZB A,LINCTR		;CLEAR LINE COUNTER AND LOAD INTO A
CM1:	MOVEI B,WINDEX		;GET WORDS PER DISPLAY MEMORY
	IMUL B,A		;CALCULATE OFFSET INTO MEMORY
				; FOR LINE BEING WORKED ON
	MOVE C,B		;COPY FOR POINTER TO NEW DISPLAY MEMORY
	ADD B,[POINT 7,WINDOW]	;COMPLETE POINTER TO CURRENT WINDOW
	MOVEM B,OLDPTR
	MOVEM B,OLDBEG		;REMEMBER POINTER TO BEGINNING OF OLD LINE
	ADD C,[POINT 7,WINEW]	;COMPLETE POINTER TO NEW DATA BEING DISPLAYED
	MOVEM C,NEWBEG		;REMEMBER POINTER TO NEW LINE
	SETZM LEN1		;NUMBER OF CHARACTERS NEEDED TO "FIX" LINE
	CALL LREPLA		;CALCULATE CHARACTERS NECESSARY
				; TO REWRITE WHOLE LINE
	MOVE C,NEWBEG		;RESET LINE POINTER TO BEGINNING
	MOVEM C,NEWPTR
	SETZM OLDCOL		;START AT LEFT MARGIN
	SETZM NEWCOL		;NEW COLUMN WE'RE GOING TO
	MOVE C,[POINT 7,LINBFR]	;POINTER TO LINE BUFFER FOR OUTPUTTING
				; DISPLAY LINE
	MOVEM C,LINPTR		;INITIALIZE DISPLAY LINE POINTER
CMLUP:	ILDB B,OLDPTR		;PICK UP CHARACTER FROM CURRENT SCREEN
	ILDB A,NEWPTR		;AND ONE FOR NEW SCREEN
	JUMPE A,CMEND		;JUMP IF DONE SCANNING LINE
	JUMPE B,CMEND1		;OLD LINE ENDED BEFORE NEW
	SKIPE SCRNF		;IF HARDCOPY
	CAME A,B		;OR IF CHARACTERS ARE DIFFERENT,
	CALL PILB		;THEN DISPLAY NEW CHARACTER
	AOS NEWCOL		;STEP TO NEXT COLUMN ON SCREEN
	JRST CMLUP		;COMPARE REST OF CHARACTERS ON LINE
CMEND1:	CALL PILB		;OLD ENDED FIRST, STASH NEW CHARACTERS
	AOS NEWCOL
	ILDB A,NEWPTR
	JUMPN A,CMEND1		;JUMP IF MORE NEW CHARACTERS
	JRST CMEND2
CMEND:	JUMPE B,CMEND2		;JUMP IF BOTH LINES ENDED AT SAME TIME
	SKIPN SCRNF		;DON'T ATTEMPT TO CLEAR TO EOL ON HARDCOPY
	JRST CMEND2
	CALL MOVCOL		;GET TO END OF LINE BEFORE
				; CLEARING TO END OF LINE!
	CALL GETEOL		;NEW ONE ENDED FIRST, PUT IN AN EOL
CMEND2:	SKIPE TYPEF		;HAS USER STARTED TYPING NEXT COMMAND?
	 JRST DISDON		;YES, SO STOP UPDATING DISPLAY
	MOVE A,LINPTR		;GET LINE POINTER
	CAMN A,[POINT 7,LINBFR]	;WAS ANYTHING PUT IN BUFFER FOR THIS LINE?
	JRST CMNEXT		;NO, SO THIS LINE STAYS AS IS
	MOVEI A,0		;MARK END OF DISPLAY BUFFER WITH NULL
	IDPB A,LINPTR
	MOVEI C,WINDEX		;GET WORDS PER DISPLAY BUFFER
	IMUL C,LINCTR		;CALCULATE OFFSET FOR LINE BEING DISPLAYED NOW
	MOVE A,LINCTR		;GET LINE BEING DONE NOW
	MOVE T,C		;GET COPY OF POINTER TO DISPLAY AREA
	HRL T,T			;COPY IT TO LEFT HALF
	ADD T,[WINEW,,WINDOW]	;MAKE BLT POINTER
	BLT T,WINDOW+WINDEX-1(C);AND MOVE LINE FROM WINEW AREA TO WINDOW AREA
	MOVE CH,LINNEW(A)
	MOVEM CH,LINBEG(A)	;COPY BUFFER POINTER OF BEGINNING OF LINE
	MOVEI CH,(A)		;FIND WHAT DISPLAY LINE POSITION TO
	CALL LINPOS		;GO TO AND GO THERE
DISPL9:	MOVE A,TTYOUT		;USE STANDARD OUTPUT CHANNEL
	HRROI B,LINBFR		;POINTER TO NEW LINE
	MOVEI C,0
	MOVE D,LEN1		;GET NUMBER OF CHARACTERS TO FIX LINE
	SKIPE SCRNF		;ALWAYS REPLACE ENTIRE LINE ON HARDCOPY
	CAML D,LEN2		;BETTER TO FIX THAN REPLACE?
	HRROI B,LINBF2		;BETTER TO REPLACE
	SOUT%			;OUTPUT NEW LINE
CMNEXT:	AOS A,LINCTR		;STEP TO NEXT LINE ON SCREEN
	CAMGE A,DLEN1		;HAVE ALL LINES BEEN PROCESSED?
	JRST CM1		;NO, GO DO NEXT
DISDON:	CALLRET REGCOC		;RESTORE CONTROL CHARACTER BEHAVIOR

;THE FOLLOWING ROUTINE FILLS LINBF2 WITH THE CHARACTERS NECESSARY TO
;COMPLETELY REWRITE THE CURRENT DISPLAY LINE.  LEN2 SHOWS APPROXIMATE
; NUMBER OF CHARACTERS NECESSARY

LREPLA:	SETZM SPCNT		;NO TAB IN PROGRESS YET
	SETZM LEN2		;COUNTS CHARACTERS PUT INTO BUFFER
	MOVE A,NEWBEG		;GET POINTER TO BEGINNING OF NEW LINE
	MOVEM A,NEWPTR		;STORE POINTER FOR SCANNING NEW LINE
	MOVE A,[POINT 7,LINBF2]	;POINTER TO OUTPUT LINE BEING CREATED
	MOVEM A,LINPTR
	SETZM NEWCOL		;COLUMN OF SCREEN WE'RE AT
	SKIPE SCRNF		;DON'T ATTEMPT CLEAR LINE ON HARDCOPY
	CALL GETEOL		;START WITH EOL TO CLEAR OLD LINE
LRLUP:	AOS A,NEWCOL		;SEE WHICH COLUMN TYPING NEXT CHARACTER
				; WILL BRING US TO
	SOJ A,			;SEE WHERE WE'RE AT BEFORE TYPING THE CHARACTER
	TRNN A,7		;A TAB STOP?
	CALL LRTAB		;YES, PUT IN A TAB IF ANY SPACES WERE STORED UP
	ILDB A,NEWPTR		;GET NEXT CHARACTER FROM NEW LINE
	JUMPE A,LR2		;LEAVE LOOP IF END OF STRING
	CAIN A,40		;A SPACE?
	JRST LR1		;YES
	SKIPG B,SPCNT		;DID SOME SPACES PRECEDE THIS CHARACTER?
	JRST LR5		;NO
	MOVEI A,40		;YES, SO PUT THE SPACES IN BEFORE THE CHARACTER
	ADDM B,LEN2		;KEEP TRACK OF NUMBER OF CHARACTERS
LR6:	IDPB A,LINPTR		;PUT IN A SPACE
	SOSLE SPCNT		;MORE NEEDED?
	JRST LR6		;YES, PUT THEM IN
	LDB A,NEWPTR		;GET ORIGINAL CHARACTER BACK
LR5:	IDPB A,LINPTR		;PUT ORIGINAL CHARACTER IN LINE BUFFER
	AOS LEN2		;KEEP TRACK OF BUFFER LENGTH
	JRST LRLUP		;LOOP FOR REST OF CHARACTERS OF LINE
LR1:	AOS SPCNT		;FOR A SPACE, JUST REMEMBER HOW MANY WE'VE SEEN
	JRST LRLUP		;GO GET REST OF CHARACTERS
LR2:	MOVEI A,0
	IDPB A,LINPTR		;FINISH WITH NULL (NOTE THAT WE'VE STRIPPED
				;TRAILING SPACES, OR AT LEAST UP TO 7 OF THEM)
	RET

;EVERY TIME A TAB STOP IS REACHED, COME HERE TO PUT A TAB IN BUFFER IF ANY
;SPACES WERE RIGHT-JUSTIFIED DURING LAST "TAB COLUMN" (8-SPACES)

LRTAB:	SKIPN A,SPCNT		;ANY SPACES STORED UP?
	RET			;NO, SO NOTHING TO DO
	AOS LEN2
	MOVEI A,11		;YES, SO PUT TAB IN BUFFER
	IDPB A,LINPTR
	SETZM SPCNT		;SHOW THAT NO BUFFERED SPACES ANYMORE
	RET

;INTERRUPT TO HERE IF USER TYPES WHILE BUFFER IS EMPTY.

TYPO:	PUSH P,A		;DON'T CLOBBER NUTTIN
	PUSH P,B
	MOVE A,TYIJFN
	SIBE%			;CAREFUL NOT TO SET FLAG IF CHAR
				; THAT CAUSED INTERRUPT HAS ALREADY BEEN READ!
	 SETOM TYPEF		;SET FLAG TO SHOW HE TYPED
	POP P,B
	POP P,A
	DEBRK%

;ROUTINE WHICH TAKES CHARACTER IN A AND PUTS IN IN DISPLAY LINE
;BUFFER.  IT ALSO PUTS IN THE APPROPRIATE CONTROL CHARACTERS FOR
;GETTING THE CURSOR TO THE CORRECT LINE POSITION WHERE THE CHARACTER
;IS SUPPOSED TO GO

PILB:	STKVAR <CHAR>
	MOVEM A,CHAR		;REMEMBER WHICH CHARACTER WE'RE DOING
	MOVE A,NEWCOL		;GET COLUMN AT WHICH THIS CHARACTER GOES
	CAMN A,OLDCOL		;ARE WE ALREADY AT RIGHT PLACE?
	JRST COLOK		;YES
	CALL MOVCOL		;PUT CONTROL SEQUENCE IN TO GET TO
				; CORRECT COLUMN
COLOK:	MOVE A,CHAR		;GET CHARACTER BEING PUT IN
	IDPB A,LINPTR		;PUT IT IN
	AOS LEN1		;KEEP TRACK OF NUMBER OF CHARACTERS IN OUTPUT
				; BUFFER FOR FIXING LINE
	MOVE A,NEWCOL		;GET COLUMN THIS CHARACTER WAS PUT
	AOJ A,			;SHOW COLUMN WE'RE AT NOW
	MOVEM A,OLDCOL		;REMEMBER WHERE WE ARE NOW
	RET

;CODE TO MOVE FROM OLDCOL TO NEWCOL

MOVCOL:	STKVAR <DRIGHT,OLDC,NEWC,SAVB>
	MOVE A,NEWCOL		;GET COLUMN AT WHICH THIS CHARACTER GOES
	SUB A,OLDCOL		;SEE HOW FAR WE MUST MOVE
	MOVE B,OLDCOL		;GET WHERE WE'RE MOVING FROM
	MOVEM A,DRIGHT		;REMEMBER HOW FAR WE'RE MOVING
	MOVEM B,OLDC		;REMEMBER WHERE WE'RE STARTING FROM
	ADD A,OLDC		;CALCULATE WHERE WE'RE GOING
	MOVEM A,NEWC		;REMEMBER
	TRZ B,7			;GO BACK TO LAST TAB STOP
	MOVEI C,11		;GET A TAB
MOVTAB:	ADDI B,8		;SEE WHERE TAB WOULD BRING US
	CAMLE B,NEWC		;TOO FAR?
	JRST MOVNMT		;YES
	IDPB C,LINPTR		;NO, PUT IN A TAB
	AOS LEN1
	JRST MOVTAB		;TRY TO PUT IN ANOTHER TAB
MOVNMT:	SUBI B,8		;UNDO LAST NONTAB!
	CAMGE B,OLDC		;MAKE SURE WE'RE NOT TO THE LEFT OF
				; WHERE WE STARTED!
	MOVE B,OLDC		;WE ARE (WE DIDN'T TYPE ANY TABS)
	MOVEM B,SAVB		;REMEMBER WHERE WE ARE
	MOVE C,B		;NUMBER OF CHARACTERS ALONG LINE WE ARE
	ADJBP C,OLDBEG		;GET POINTER TO CHARACTER BEING PASSED OVER
MOVSPC:	CAML B,NEWC		;ARE WE THERE YET?
	JRST MOVNMC		;YES
	ILDB A,C		;GET CHARACTER BEING PASSED OVER
	IDPB A,LINPTR		;PASS OVER IT BY TYPING IT.
				; (QUICKER THAN $C ON VT52)
	AOS LEN1
	AOS B,SAVB		;SHOW THAT WE'VE MOVED A SPACE
	JRST MOVSPC		;GO SEE IF MORE SPACES NEEDED
MOVNMC:	RET			;ALL DONE, WE'RE AT NEW POSITION

;CLEAR TO END OF LINE (IN BUFFER)

GETEOL:	MOVE A,TRMTYP		;GET FLAVOR
	JRST @EOLTB1(A)		;DO TERMINAL DEPENDENT CLEARING

	TERINI EOLTB1
	TER (.TTV05,IFIW!V05POL)
	TER (.TTV50,IFIW!V50POL)
	TER (.TT100,IFIW!V100PL)
	TER (.TTV52,IFIW!V50POL)

V100PL:	MOVEI A,.CHESC
	IDPB A,LINPTR
	MOVEI A,"["
	IDPB A,LINPTR
	MOVEI A,"K"
	IDPB A,LINPTR
	RET

V05POL:	MOVEI A,C.EOL		;PUT IN CLEARING CHARACTER
	IDPB A,LINPTR
	MOVEI A,177		;NEEDS FILLERS
	REPEAT 4,<IDPB A,LINPTR> ;(CAN'T USE NULLS BECAUSE SOUT WOULD TERMINATE)
	RET

V50POL:	MOVEI A,V52.ES		;ESCAPE CODE FOR VT50
	IDPB A,LINPTR
	MOVEI A,V52.EL		;END OF LINE CHARACTER
	IDPB A,LINPTR
	RET

;MOVE RIGHT A COLUMN (CAN'T USE SPACE, WHICH ERASES AS IT GOES!)

;**;[476] DELETE one line at MOVRIT	LEM	20-OCT-81
;**;[476] DELETE one line at MOVRIT+3	LEM	20-OCT-81
MOVRIT:	MOVE A,TRMTYP		;GET FLAVOR OF TERMINAL
	CALL @RITTAB(A)		;DO TERMINAL DEPENDENT MOVING

	TERINI RITTAB
	TER (.TTV05,IFIW!V05RIT)
	TER (.TTV50,IFIW!V50RIT)
	TER (.TT100,IFIW!V100RT)
	TER (.TTV52,IFIW!V50RIT)

V100RT:	MOVEI A,.CHESC
	IDPB A,LINPTR
	MOVEI A,"["
	IDPB A,LINPTR
	MOVEI A,"C"
	IDPB A,LINPTR
	RET

V05RIT:	MOVEI A,C.RITE		;VT05 CHARACTER FOR MOVING RIGHT
	IDPB A,LINPTR		;PUT IT IN BUFFER
	RET

V50RIT:	MOVEI A,V52.ES		;ESCAPE CODE NEEDED FOR VT5X
	IDPB A,LINPTR
	MOVEI A,V52.RT		;CHARACTER FOR MOVING RIGHT
	IDPB A,LINPTR
	RET

;ROUTINE TO PUT CURSOR ON LINE SPECIFIED BY CONTENTS OF CH

LINPOS:	STKVAR <NEWCRR>
	MOVEM CH,NEWCRR
	CAMN CH,CRRCNT		;ALREADY AT CORRECT PLACE?
	JRST [	CALL CHKLM	;YES, MAKE SURE AT LEFT MARGIN
		 JRST [	MOVEI A,.CHCRT
			CALL TYO
			JRST LINDON]
		JRST LINDON]
	MOVEI A,-1(CH)		;IF GOING DOWN EXACTLY ONE LINE, JUST
	CAME A,CRRCNT		;TYPE CRLF, SO AS NOT TO OVERPRINT
				; SYSTEM MESSAGES
	SKIPN SCRNF		;ON A SCREEN?
	JRST LINHRD		;NO, HARD COPY
	CALL DISCOC		;MAKE CONTROL CHARACTERS ECHO LITERALLY
	MOVE A,TRMTYP
	CALL @POSTAB(A)		;CALL APPROPRIATE ROUTINE
	CALL REGCOC		;RESTORE CONTROL CHARACTERS
LINDON:	MOVE A,NEWCRR
	MOVEM A,CRRCNT		;REMEMBER WHERE WE NOW ARE.
	RET

;POSITIONING ON A HARDCOPY

LINHRD:	CAMGE CH,CRRCNT		;MAKE SURE GOING DOWN
	IERROR <Hardcopy linestarve>
LINH1:	MOVE A,CRRCNT		;SEE WHERE ANOTHER CRLF WILL BRING US
	CAML A,NEWCRR		;FAR ENOUGH?
	RET			;YES, DONE
	CALL CRR		;NO, GET TO NEXT LINE
	AOS CRRCNT
	JRST LINH1		;LOOP FOR REST

	TERINI POSTAB		;CURSOR ADDRESSING ROUTINES
	TER (.TTV05,IFIW!LINECH)
	TER (.TTV50,IFIW!V50LIN)
	TER (.TT100,IFIW!V100LN)
	TER (.TTV52,IFIW!V50LIN)

;ROUTINE FOR VT50 RANDOM LINE ADDRESSING

V50LIN:	PUSH P,CH		;REMEMBER WHERE WE WANT TO GO
	SUB CH,CRRCNT		;CALCULATE HOW FAR AWAY WE ARE.
	JUMPG CH,V50DWN		;WE HAVE TO GO DOWN TO SOMEWHERE
	MOVNI CH,2(CH)		;2 CHARACTERS OVERHEAD FOR HOMEUP
	HRRZ CH,CH		;FLUSH BAD BITS
	CAMG CH,(P)
	JRST V50GUP		;IT'S BETTER TO GO UP THAN HOME AND COME DOWN
	CALL HOME		;CHECK ON THE FOLKS (GO TO TOP OF SCREEN)
	MOVE CH,(P)		;WE'RE GOING TO START AT THE TOP AND COME DOWN.
	JUMPE CH,V50DN1		;MAYBE HOMING UP IS ALL THAT'S NECESSARY
V50LN1:	MOVEI A,12		;CHARACTER FOR MOVING DOWN
	CALL TYO
	SOJG CH,V50LN1		;FAR ENOUGH YET?
	JRST V50DON		;YES.

V50GUP:	ADDI CH,2
	CALL LINSTV		;LINE STARVE
	SOJG CH,.-1
	JRST V50DON

V50DWN:	MOVEI A,12		;CHARACTER TO MOVE DOWN A LINE
	CALL TYO
	SOJG CH,V50DWN		;GO UP UNTIL WE GET TO CORRECT PLACE
V50DON:	MOVEI A,15
	CALL TYO		;GET TO LEFT MARGIN
V50DN1:	POP P,CH
	RET

;VT100 LINE ADDRESSING

V100LN:	MOVEI A,.CHESC
	CALL TYO		;ANNOUNCE ESCAPE SEQUENCE
	MOVEI A,"["
	CALL TYO		;NO COMMENT
	MOVEI B,1(CH)		;LINE 0 IS HARDWARE LINE 1
	MOVEI C,5+5		;SEND LINE NUMBER IN DECIMAL
	MOVE A,TTYOUT		;USE STANDARD OUTPUT CHANNEL
	NOUT%			;SEND THE LINE NUMBER
	 JSERR			;SHOULDN'T FAIL
	MOVEI A,"H"		;SAY WE'RE DOING POSITIONING
	CALLRET TYO

;ROUTINE FOR VT05 RANDOM LINE ADDRESSING

LINECH:	MOVEI A,C.CAD		;MAGIC CURSOR ADDRESSING CHARACTER
	CALL TYO		;TYPE IT
	ADDI CH,40		;MAKE VT05 ADDRESS
	CALL CNFILL		;IT REQUIRES FILLERS
	MOVEI A,C.LM+1		;GO TO COLUMN 1
	CALL TYO
	RET

;THE FOLLOWING ROUTINE ASSUMES SCRNPT CONTAINS A CHARACTER ADDRESS
;OF THE FIRST ONE TO BE DISPLAYED.  THIS
;ROUTINE TRIES TO BACKUP SCRNPT TO THE BEGINNING OF THE LINE, BEING
;CAREFUL NOT TO DO SO IF THAT WOULD CAUSE THE LINE TO OVERFLOW, THUS
;CAUSING A LARGE AMOUNT OF SCREEN REFRESH (SHIFTING EVERYTHING DOWN)

LININI:	STKVAR <LINQCL,CHARAD,BACKTO>
	MOVE A,SCRNPT		;GET CURRENT BEGINNING OF LINE
	CALL LINBGQ		;TRY TO FIND REAL BEGINNING
	MOVEM A,BACKTO		;REMEMBER WHERE BEGINNING IS
	MOVEM A,CHARAD		;INITIAL CHARACTER ADDRESS IS BEGINNING OF LINE
	SETZM LINQCL		;KEEP TRACK OF COLUMNS
LINI1:	MOVE A,LINQCL		;SEE WHAT COLUMN WE'RE UP TO
	CAML A,SWIDTH		;HAS LINE GOTTEN REAL LONG?
	RET			;YES, SO WE WON'T TRY TO REPOSITION
				; BEGINNING POINTER
	MOVE A,CHARAD		;GET CURRENT CHARACTER ADDRESS
	CAML A,ZEE		;MAKE SURE WE HAVEN'T HIT END OF BUFFER
	JRST LINI2		;WE HAVE, SO LINE ISN'T TOO LONG
	MOVE I,A
	CALL GET		;GET CURRENT CHARACTER
	CAIN CH,15		;DID WE FIND END OF LINE?
	JRST LINI2		;YES, SO WE CAN FIT THIS WHOLE LINE ON
	MOVE A,CH
	MOVE B,LINQCL		;FOR TAB, WIDTH DEPENDS ON CURRENT COLUMN
	CALL CHRCOL		;GET WIDTH OF CHARACTER
	MOVEM A,LINQCL		;KEEP TRACK OF WHAT COLUMN WE'RE UP TO
	AOS CHARAD		;STEP TO NEXT CHARACTER IN BUFFER
	JRST LINI1		;LOOP BACK TO SEE IF WE'VE FOUND END OF LINE

LINI2:	MOVE A,BACKTO		;THE LINE IS REASONABLE LENGTH, SO
	MOVEM A,SCRNPT		;WE CAN START DISPLAYING FROM ITS BEGINNING
	RET

;ROUTINE TO TELL EFFECT OF DISPLAYING A CHARACTER, COLUMNWISE.
;THE CALL:
;	1/	CHARACTER TO BE DISPLAYED
;	2/	COLUMN ON LINE SO FAR
;	CALL CHRCOL
;RETURNS +1 ALWAYS WITH:
;	1/	COLUMN CHARACTER BRINGS US TO
;
;THIS ROUTINE KNOWS HOW TO ACCOUNT FOR TABS AND FLAGGED CHARACTERS

CHRCOL:	STKVAR <COL1,CHAR1>
	MOVEM A,CHAR1
	MOVEM B,COL1
	CAIN A,11		;A TAB?
	JRST CHRCTB		;YES
	AOS COL1		;ALL CHARACTERS INCREASE COLUMN BY AT LEAST 1
	MOVE CH,A
	CALL SFLAGC		;A FLAGGED CHARACTER?
	 CAIA			;NO
	AOS COL1		;YES, SO INCREASE COLUMN BY 2
	MOVE A,COL1		;RETURN NEW COLUMN IN A
	RET

CHRCTB:	MOVEI A,8
	ADD A,COL1		;TAB MIGHT GO 8 COLUMNS
	TRZ A,7			;BUT USUALLY NOT QUITE THAT MUCH
	RET

;ROUTINE TO FILL WINEW WITH NEW PICTURE TO BE DISPLAYED
;SCRNPT MUST BE THE ADDRESS OF THE FIRST CHARACTER WITHIN BUFFER
;DESIRED IN DISPLAY.  ROUTINE ASSUMES SCRNPT POINTS TO SOME CHARACTER
;WITHIN THE BUFFER.

WINFIL:	TRVAR <OURWT0,OURWTH,WLNO>
	SKIPE T,SWIDTH
	CAILE T,MAXWTH
	MOVEI T,MAXWTH		;IN SCREEN BUFFER, NOT ANY WIDTH IS ALLOWED!
	MOVEM T,OURWTH		;REMEMBER WIDTH OF OUR SCREEN MEMORY
	SOJ T,			;LEAVE ROOM FOR ONE CONTINUATION CHARACTER
	MOVEM T,OURWT0
	SETZM WLNO		;DISPLAY LINE NUMBER
	MOVEI P2,1		;POINTER TO LINNEW ARRAY
	MOVE I,SCRNPT		;POINTER TO FIRST CHARACTER TO BE DISPLAYED
	SOJ I,			;WE WANT ILDB POINTER
	CALL GETX		;MAKE BYTE POINTER
	MOVE C,TT		;PUT POINTER IN C
WINFL3:	MOVE TT,C		;PUT POINTER IN TT
	CALL PTR2AD		;CHANGE TO CHARACTER ADDRESS
	AOJ I,			;GET FIRST CHARACTER ADDRESS OF DISPLAY LINE
	MOVEM I,LINNEW-1(P2)	;REMEMBER WHAT PART OF BUFFER
				; BEGINS ON EACH LINE
	MOVE P2,[POINT 7,WINEW]
	ADD P2,WLNO		;CREATE POINTER TO NEW DISPLAY IMAGE
	MOVEI P1,0		;# OF CHARS ON THIS SCREEN LINE SO FAR
WINFL2:	CALL PUTCHR		;GET CHARACTER FROM BUFFER
	CAIE T,11		;IS THIS A TAB?
	JRST WINNT		;NO
	MOVEI T,40		;YES, MARK IT WITH APPROPRIATE NUMBER OF SPACES
WINTAB:	AOJ P1,			;COUNT THE COLUMN FOR TAB
	IDPB T,P2		;ALWAYS PUT AT LEAST ONE SPACE IN FOR TAB
	TRNE P1,7		;ARE WE AT NEXT TAB STOP YET?
	JRST WINTAB		;NO, SPACE OVER SOME MORE
	JRST WINFL2		;GO GET NEXT CHARACTER FROM BUFFER

WINNT:	IDPB T,P2		;SAVE IT IN SCREEN MEMORY
	CAIN T,15
	SETO P1,		;SO AOJA CORRECTLY ZEROES p1 FOR END OF LINE
	CAIE T,12		;LF MEANS END OF SCREEN LINE
	AOJA P1,WINFL2		;COUNT CHARACTER AND GO GET ANOTHER
	MOVEI T,0		;CLOBBER END OF LINE WITH 0
	DPB T,P2		;REPLACE LINEFEED WITH NULL
	SETO A,
	ADJBP A,P2		;POINT TO WHAT MAY BE A CARRIAGE RETURN
	CAIN P1,0		;IS IT?
	DPB T,A			;YES, SO NULL IT TOO
			; (DISPLA ROUTINE EXPECTS NULL AFTER TEXT OF LINE)
	MOVEI P2,WINDEX
	ADDB P2,WLNO		;STEP TO NEXT DISPLAY LINE
	IDIVI P2,WINDEX
	ADDI P2,1
	CAMGE P2,DLENTH		;ARE WE THROUGH?
	JRST WINFL3		;NO DO ANOTHER
	MOVE TT,C
	CALL PTR2AD		;MAKE CHARACTER ADDRESS
	MOVEM I,SCNEND		;REMEMBER LAST CHARACTER POSITION DISPLAYED
	MOVE A,WLNO
WINFL5:	CAILE A,WINTOP		;HAS WHOLE DISPLAY AREA BEEN UPDATED?
	RET			;YES
	SETOM WINDOW(A)		;NO, OBSCURE THE UNUSED PORTION
	ADDI A,WINDEX
	JRST WINFL5

;ROUTINE TO RETURN NEXT DISPLAY LINE CHARACTER IN T, TAKES
;TWO CALLS TO GET ^* FOR CONTROL-CHARACTER.
;LINEFEEDS NOT AT THE LEFT MARGIN ARE RETURNED AS ^J.
;CARRIAGE RETURNS NOT FOLLOWED BY LINEFEEDS ARE RETURNED AS ^M.
;THE CONTENTS OF LASTCH IS GIVEN IF LINE IS ABOUT TO GO OVER RIGHT MARGIN.
;POINTER IS DISPLAYED AS CHARACTER STRING THAT IS THE CONTENTS OF
;PTRCHR.

PUTCHR:	SKIPE SEOL		;NON-ZERO SEOL MEANS END OF DISPLAY LINE
	JRST PUTEOL		;END OF LINE
	CAML P1,OURWT0		;BEGINNING OF END OF LINE?
	JRST SCON		;HANDLE END OF LINE
	SKIPE CTLFLG		;OUTPUTTING CONTROL CHARACTER?
	JRST CTLCHR		;YES, GO SEND CHARACTER
	SKIPLE PUTPTF		;if outputting pointer
	JRST PUTPT1		;continue doing so...
	SKIPE EOBFLG		;END OF BUFFER?
	JRST EOBCHR		;YES, JUST SEND CRLFS
	MOVE T,BEG
	CAMN T,ZEE		;NO BUFFER?
	JRST EOBCR2		;THEN SURELY WE ARE AT THE END!
	CAME C,ILDBPT		;ARE WE AT POINTER IN BUFFER?
	JRST PUTCR1		;NOT YET, OR PAST IT
	SKIPE PUTPTF		;AT IT, BUT DID WE ALREADY KNOW THAT?
	JRST PUTPT1		;YES, SO CONTINUE GIVING PICTURE OF POINTER
POINTP:	MOVE T,[010700,,PTRCHR-1] ;GET POINTER TO PICTURE OF POINTER
	MOVEM T,PUTPTF
	JRST PUTPT1		;OUTPUT PICTURE OF POINTER
PUTCR1:	UILDB T,C		;GET NEXT CHARACTER IN BUFFER
	CAMN C,SCRNZ		;IS THIS LAST CHARACTER IN BUFFER?
	SETOM EOBFLG		;YES, SET FLAG FOR NEXT CALL TO PUTCHR
	CAIN T,33		;ALTMODE?
	MOVEI T,"$"		;DOLLAR SIGN
	CAIN T,15		;CR?
	JRST SCR		;YES, MAYBE END OF LINE (IF LINEFEED NEXT)
	CAIN T,12		;LF?
	JRST SLF		;YES, PART OF END OF LINE?
	CAIN T,11		;HANDLE TAB SPECIALLY
	RET			;NOTHING SPECIAL HERE ABOUT TAB
	CAILE T,37		;OTHER CONTROL CHARACTER?
	JRST PUTCR3
PUTCR2:	ADDI T,100		;MAKE * PART OF ^*
	MOVEM T,CTLFLG
	MOVEI T,"^"		;PRINT UPARROW FIRST
	RET

PUTCR3:	MOVE CH,T
	CALL SFLAGC		;FLAG THIS CHARACTER?
	RET			;NO
	MOVEM T,CTLFLG		;REMEMBER WHAT CH WAS FLAGGED
	MOVEI T,CFLAG		;GET FLAG CHARACTER
	RET
PUTPT1:	ILDB T,PUTPTF		;GET CHARACTER OF PICTURE OF POINTER
	JUMPN T,CPOPJ		;ZERO MEANS POINTER HAS COMPLETED BEING
	SETOM PUTPTF		;NEG MEANS POINTER FULLY DISPLAYED
	SKIPE EOBFLG		;END OF BUFFER?
	JRST EOBCR4		;YES
	JRST PUTCR1		;GO BACK TO GET NEXT CHARACTER FROM BUFFER
EOBCR2:	SETOM EOBFLG
	JRST POINTP
CTLCHR:	MOVE T,CTLFLG		;GET CHARACTER THAT WAS "CONTROL"ED
	SETZM CTLFLG		;SAY DONE PROCESSING CONTROL CHARACTER
	RET
EOBCHR:	SKIPL EOBFLG		;EOBFLG NEGATIVE IF JUST REACHED END OF LINE
	JRST EOPCR1		;DIDN'T JUST, SO OSCILLATE BETWEEN CR AND LF
	CAME C,ILDBPT		;IF POINTER IS AT END OF BUFFER,
	JRST EOBCR4		;PUT IT IN PICTURE
	SKIPN PUTPTF		;SKIP IF POINTER IN PICTURE
	JRST POINTP		;IT'S NOT, SO PUT IT IN
EOBCR4:	MOVEI T,12		;SO CR BEFORE LF IN OSCILLATION
	MOVEM T,EOBFLG
EOPCR1:	MOVEI T,27		;CR+LF
	SUBB T,EOBFLG		;CHANGE CR TO LF AND LF TO CR
	RET			;T HAS CR OR LF BECAUSE NO MORE BUFFER
SCR:	CAME C,ILDBPT
	SKIPGE EOBFLG		;ARE WE AT END OF BUFFER?
	JRST PUTCR2		;CR LAST CHAR IN BUFFER = ^M
	MOVE T,C		;SEE IF CHAR AFTER CR IS LF
	UILDB T,T		;GET NEXT CHARACTER
	CAIN T,12		;LF?
	JRST SCR1		;YES
	MOVEI T,15		;NO, ^M
	JRST PUTCR2
SCR1:	MOVEI T,15		;CRLF, SO CARRIAGE RETURN NOT HACKED
	RET
SLF:	MOVE TT,C		;DECREMENT BYTE POINTER
	CALL DBP
	CAME TT,ILDBPT		;IF JUST AFTER CARAT, LINEFEED IS ^J
	JUMPE P1,SLF1		;LINEFEED AT LEFT MARGIN IS JUST LINEFEED
SLF2:	MOVEI T,12		;NO, SO ^J
	JRST PUTCR2
SLF1:	MOVEI T,12		;CR BEFORE LF, SO DON'T HACK LF
	RET
SCON:	CAME C,ILDBPT		;ARE WE AT POINTER NOW?
	JRST SCON4		;NO
	SKIPL PUTPTF		;skip if pointer fully displayed
	JRST SCON2		;it's not
SCON4:	SKIPE CTLFLG		;OR IN THE MIDDLE OF A CONTROL CHARACTER
	JRST SCON2		;THEN TYPE CONTINUATION CHARACTER
	SKIPE EOBFLG		;END OF BUFFER?
	JRST EOBCHR
	MOVE TT,C
	UILDB T,TT		;PEEK AT NEXT TWO CHARACTERS AND IF THEY
				;ARE CRLF, THEN NO CONTINUATION
	CAMN TT,ILDBPT		;AT POINTER NOW
	JRST SCON2		;THEN CONTINUATION REQUIRED
	CAIN T,15		;CR?
	JRST SCON1		;YES, SEE IF LF NEXT
	CAME TT,SCRNZ		;END OF BUFFER?
	JRST SCON69		;NO, MAYBE LINE IS JUST ONE MORE CHARACTER
	SETOM EOBFLG		;REMEMBER THAT END OF BUFFER HAS BEEN REACHED
	CAIE T,11		;TAB AT END OF LINE?
	CAIN T,33		;OR ALTMODE
	JRST SCON5		;TAB OR ALTMODE IS LAST CHAR IN BUFFER
	CAILE T,37
	JRST SCONGD		;NON-CONTROL CHARACTER IS LAST IN BUFFER
SCON2:	CAML P1,OURWTH		;DID WE JUST TAB TO RIGHT MARGIN?
	JRST [	MOVE T,OURWT0	;YES, SO CAN'T PUT ANOTHER CHARACTER IN LIEU
				;OF CONTINUATION SIGNAL EVEN IF THAT CHARACTER
				;IS THE LAST ON THE LINE
		SUB T,P1	;CALCULATE AMOUNT OF OVERSHOOT
		MOVE P1,OURWT0	;POSITION AT EXACT PLACE WHERE CONTINUATION GOES
		ADJBP T,P2	;BACK UP POINTER SO LAST SPACES OF TAB
				; GET REPLACED
				;WITH CONTINUATION SIGNAL
		MOVE P2,T
		JRST .+1]	;DO CONTINUATION BEFORE CHARACTERS AFTER TAB
	MOVEI T,12		;START EOL SEQUENCE WITH LF SO CR FIRST
	MOVEM T,SEOL
	MOVE T,LASTCH		;GET CONTINUATION CHARACTER
	RET
;AT THIS POINT WE KNOW CHARACTER FOR COLUMN 72 IS NOT THE LAST
;IN THE BUFFER, AND IT IS NOT IMMEDIATELY FOLLOWED BY THE POINTER
SCON69:	CAMGE P1,OURWTH		;IF JUST TABBED TO RIGHT MARGIN, NO ROOM FOR
				;LAST REMAINING CHARACTER ON LINE
	CAIG T,37		;IS THIS CHAR A CONTROL CHARACTER
	JRST SCON2		;YES, SO NO ROOM FOR IT HERE
	MOVE CH,T
	CALL SFLAGC		;WOULD THIS CHAR BE FLAGGED?
	CAIA			;NO
	JRST SCON2		;CHARACTER FLAGGED, SO NO ROOM
	UILDB T,TT		;NOT CONTROL, SO IF CRLF NEXT, NO CONTINUATION
	CAME TT,ILDBPT		;NOW AT END OF BUFFER?
	CAMN TT,SCRNZ		;OR RIGHT BEFORE POINTER?
	JRST SCON2		;YES, SO EVEN CR WOULD BE ^M
	CAIE T,15		;CR?
	JRST SCON2		;NO
	UILDB T,TT		;YES, LOOK AT NEXT ONE
	CAIE T,12		;IS IT A LINEFEED?
	JRST SCON2		;NO
	JRST SCONGD		;YES

SCON1:	UILDB T,TT
	CAIE T,12		;LF AFTER CR AT EOL?
	JRST SCON2		;NO
SCONGD:	UILDB T,C		;CRLF , SO JUST GOBBLE IT UNHACKED
	RET
SCON5:	MOVE CH,T
	CALL SFLAGC
	JRST SCONGD
	JRST SCON2
PUTEOL:	MOVEI T,27		;CR + LF
	SUBB T,SEOL		;CHANGE ONE TO THE OTHER
	CAIN T,12		;SEE IF WE'VE PRINTED ONE SET YET
	SETZM SEOL		;YES, ANNOUNCE END OF END OF LINE
	RET
;DISPLAY INITIALIZATION ROUTINE

DISINI:	SETZM EOBFLG		;END OF BUFFER FLAG
	SETZM PUTPTF		;POINTER IN DISPLAY FLAG
	SETZM CTLFLG		;NON-ZERO MEANS CONTROL CHARACTER
	SETZM SEOL		;END OF LINE SEEN FLAG
	MOVE I,PT
	SUBI I,1		;TO POINT TO LAST CHARACTER
	CALL GETX		;LDB POINTER TO CHARACTER AFTER
				; POINTER IN BUFFER
	MOVEM TT,ILDBPT
	RET

;@J TRIES TO PUT THE POINTER IN THE MIDDLE OF THE SCREEN.

ATSGNJ:	SKIPN SLENTH		;IS THERE A POSITIVE WINDOW DEFINED?
	JRST CFLUSH		;NO, SO @J DOES NOTHING.
	MOVE A,SLENTH		;YES, GET WINDOW SIZE.
	LSH A,-1		;DIVIDE BY 2 TO GET IN MIDDLE OF WINDOW.
	MOVE I,LINNEW(A)	;GET POINTER TO FIRST CHARACTER OF A LINE.
	CAMG I,ZEE		;MAKE SURE WE'RE STILL IN THE BUFFER.
	CAMGE I,BEG		;AND NOT BEFORE IT.
	JRST CFLUSH		;WE WEREN'T, SO GIVE UP.
	MOVEM I,PT		;WE'RE O.K., SO CHANGE "POINT".
	JRST CFLUSH
;ROUTINE TO RETURN STRING OPERATION STRING ARGUMENTS.
;ARGUMENTS ARE CHARACTER ADDRESSES IN THE DATA BUFFER.
;TRANSFORMS M,N OR N, WHERE THE LATTER SPECIFIES A NUMBER OF LINES,
;TO ARGUMENTS.
;CALL CALL GETARG
;	RETURN WITH FIRST ARGUMENT ADDRESS IN p1, SECOND IN B.
;THE ROUTINE ALSO MAKES SURE THE ARGUMENTS SUPPLIED ARE REALLY
;WITHIN THE BUFFER!
;GETARG CLEARS ARG2. IT DOES NOT CLOBBER A (SOME ROUTINES DEPEND ON THIS).

GETARG:	MOVE C,FARG		;[502] GET FIRST ARG IF ANY
	TXZE FF,ARG2		;[506] IS THERE A SECOND ARGUMENT?
	JRST GETAG6		;YES

;N SIGN INDICATES DIRECTION RELATIVE TO PT.

	TXON FF,ARG		;NO. IS THERE AN ARGUMENT?
	CALL	CHK22		;[502] C=1 OR -1 (-1 IF OP="-")
				;IE, ASSUME AN ARG OF 1 AND RETAIN SIGN
	MOVE I,PT		;I:=PT
	JUMPLE C,GETAG2		;WAS LAST ARGUMENT FUNCTION -?
GETAG4:	CAMN I,ZEE		;NO. ARGUMENT IS LOCATION OF NTH LINE
				;FEED FORWARD FROM PT.
				;IS PT AT END OF BUFFER?
	JRST GETAG1		;YES.
	CALL GET		;NO.
	CAIE CH,.CHLFD		;LF?
	AOJA I,GETAG4		;NO. TRY AGAIN.
	SOSLE C			;HAVE WE FOUND ENOUGH?
	AOJA I,GETAG4		;NO, FIND ANOTHER.
	CAME I,BEG
	TXNN FF,COLONF
	AOJA I,GETAG1		;AT BEGINNING OF BUFFER OR NOT : COMMAND
	SOJ I,			;FOR :L,:K ETC. PUT POINTER BEFORE END OF LINE
	CALL GETINC		;GET CHARACTER BEFORE LINEFEED
	CAIE CH,.CHCRT		;CR?
	AOJA I,GETAG1		;NO, SO COLON HAS NO EFFECT.
	SOJ I,			;YES, SO PUT POINTER AT END OF LAST LINE

GETAG1:	MOVE C,I		;YES. RETURN FIRST ARGUMENT IN p1
	MOVE P1,PT		;SECOND IN B.
	CALLRET CHK1		;CHECK ARGS AND RETURN.

;M,N

GETAG6:	ADD C,BEG		;p1:=M+BEG
	ADD P1,BEG		;c:=N+BEG
	CALLRET CHK1		;MAKE SURE ARGUMENTS ARE WITHIN BUFFER
				; AND RETURN.

GETAG2:	SOS I			;ARG IS POS OF NTH LINE FEED LEFT OF PT.
				;N:=N-1
GETAG9:	CAMGE I,BEG		;PASSED BEGINNING OF BUFFER?
	JRST GETAG3		;YES. I:=BEG
	CALL GET		;NO.
	CAIE CH,.CHLFD		;LF?
	SOJA I,GETAG9		;NO. BACK UP ONE POSITION AND TRY AGAIN.
	AOSG C			;HAVE WE FOUND ENOUGH LINEFEEDS?
	SOJA I,GETAG9		;NOT YET.
	CAME I,BEG
	TXNN FF,COLONF
	AOJA I,GETAG3		;AT BEGINNING OF BUFFER OR NOT : COMMAND
	SOJ I,			;FOR :L,:K ETC. PUT POINTER BEFORE END OF LINE
	CALL GETINC		;GET CHARACTER BEFORE LINEFEED
	CAIE CH,.CHCRT		;CR?
	AOJA I,GETAG3		;NO, SO COLON HAS NO EFFECT.
	SOJ I,			;YES, SO PUT POINTER AT END OF LAST LINE

GETAG3:	CAMGE I,BEG		;YES. PASSED BEGINNING OF BUFFER?
	MOVE I,BEG		;YES. RESET TO BEGINNING.
	MOVE P1,I		;NO. RETURN FIRST ARGUMENT IN C.
	MOVE C,PT		;SECOND IN c
	CALLRET CHK1		;CHECK ARGS AND RETURN.
;MOVE STRING GIVEN CHARACTER POINTERS
; I/ SOURCE CHAR PTR
; OU/ DEST CHAR PTR
; p1/ COUNT

MVCST:	MOVE A,I		;GET CHAR ADDRESS OF LEFTMOST CHAR IN SOURCE
	CALL ADDPTR		;MAKE LDB POINTER TO FIRST CHARACTER
	SETO I,
	ADJBP I,A		;MAKE ILDB POINTER TO FIRST CHAR IN I
	MOVE A,OU		;LIKEWISE GET IDPB POINTER TO
				; LEFTMOST DESTINATION CHARACTER
	CALL ADDPTR
	SETO OU,
	ADJBP OU,A		;NOW OU HAS IDPB POINTER TO DESTINATION
	CALLRET MVSTR		;MOVE REST OF STRING

;MOVE STRING
; I/ SOURCE BYTE PTR
; OU/ DEST BYTE PTR
; p1/ COUNT
;RETURNS WITH I AND OU UPDATED SUCH THAT SUBSEQUENT CALL WITH NEW COUNT
;IN P1 WOULD JUST "CONTINUE" COPYING.
;THIS SIMULATES AN ILDB/IDPB/SOJG LOOP IF DESTINATION IS TO LEFT OF SOURCE
;IF DESTINATION IS TO RIGHT OF SOURCE, THE SOURCE IS MOVED STARTING
;WITH ITS RIGHTMOST END, HENCE DOING THINGS LIKE SLIDING A LONG STRING
;A FEW CHARACTERS TO THE RIGHT WORKS.  NOTE THAT THE I, OU, AND P1 YOU
;SHOULD CALL MVSTR WITH ARE ALWAYS FOR ILDB/IDPB/SOJG REGARDLESS OF
;CURRENT FLOW.  JUST LEAVE THE DRIVING TO US... BUT YOUR PRAYERS COULDN'T
;HURT

MVSTR:	STKVAR <RETOU,RETI>
	TLC  I,-1		;IF -1 IN LEFT HALF, THEN 0 THERE NOW
	TLCN I,-1		;RESTORE LEFT HALF TO ORIGINAL AND
				; SKIP IF WASN'T -1 ORIGINALLY
	HRLI I,(POINT 7)	;WAS -1 SO MAKE IT 440700
	TLC OU,-1
	TLCN OU,-1
	HRLI OU,(POINT 7)
	MOVE A,P1		;GET COUNT
	ADJBP A,OU		;CALCULATE UPDATED POINTER
	MOVEM A,RETOU
	MOVE A,P1
	ADJBP A,I		;DO BOTH POINTERS
	MOVEM A,RETI
	CALL MVSTWK		;DO THE WORK
	MOVE OU,RETOU
	MOVE I,RETI
	RET

MVSTWK:	JUMPLE P1,CPOPJ		;RETURN NOW IF NO CHARACTERS TO MOVE
	STKVAR <ARGI,ARGOU>
	MOVEM I,ARGI		;SAVE ARGS
	MOVEM OU,ARGOU
	MOVEM P1,STRLEN
	MOVE TT,I		;GET CHARACTER ADDRESSES OF ARGS
	IBP TT			;WE WANT ADDRESS OF BEGINNING OF SOURCE
	MOVEM TT,SRCBPT		;REMEMBER WHERE SOURCE STARTS
	CALL PTRXAD		;MAKE CHARACTER ADDRESS
	MOVEM I,SRCBEG
	MOVE TT,ARGOU
	IBP TT
	MOVEM TT,DESBPT		;REMEMBER WHERE DESTINATION STARTS
	CALL PTRXAD
	MOVEM I,DESBEG
	MOVE I,SRCBEG
	CAMN I,DESBEG		;DOING MUCH MOVING AT ALL?
	RET			;NO, NONE AT ALL
	ADD I,STRLEN		;GET RIGHTMOST CHAR ADDRESS OF SOURCE
	MOVEM I,SRCEND		;REMEMBER CHARACTER ADDRESS JUST TO RIGHT
				; OF SOURCE
	CALL GET1		;GET BYTE POINTER TO JUST TO RIGHT OF SOURCE
	MOVEM TT,SRCEPT
	MOVE I,DESBEG
	ADD I,STRLEN
	MOVEM I,DESEND		;REMEMBER END OF DESTINATION
	CALL GET1		;GET BYTE PTR TO JUST TO RIGHT OF DESTINATION
	MOVEM TT,DESEPT
	MOVE A,DESBEG
	CAML A,SRCBEG
	CAML A,SRCEND
	CAIA			;IT'S SAFE TO ILDB/IDPB/SOJG
	JRST MVSTX		;ILDB/IDPB/SOJG WOULD CLOBBER CERTAIN BYTES
				; WITH IDPB BEFORE THEY GOT ILDB'D !
	MOVE I,ARGI
	MOVE OU,ARGOU		;LEAVE ARGS AS GIVEN TO US

MVST1:	ILDB CH,I		;MOVE ONE CHAR
	IDPB CH,OU
	SOJLE P1,CPOPJ		;RETURN IF COUNT DONE
	TLNE OU,(74B5)		;DEST NOW AT WORD BOUNDARY?
	JRST MVST1		;NO, DO ANOTHER CHAR
	CAIGE P1,^D20		;AT LEAST 20 CHARS TO DO?
	JRST MVST1		;NO, NOT WORTH SETTING UP WORD MOVE
	MOVE TT,P1		;YES, SETUP FOR FULL WORD MOVE
	IDIVI TT,5		;COMPUTE NUMBER FULL WORDS TO MOVE
	MOVEM TT1,P1		;SAVE REMAINDER OF CHARACTERS
	LDB T,[POINT 6,I,5]	;GET SOURCE "P" FIELD
	CAIN T,1		;SOURCE ALSO ON WORD BOUNDARY?
	JRST MVST4		;YES, GO DO BLT
	MOVN P2,T
	SUBI T,1		;T = P-1
	ADDI P2,^D36		;p2 = 36-P
	ADDM TT,I		;UPDATE PTRS FOR FULL WORDS MOVED
	ADDM TT,OU
	MOVNM TT,C		;SETUP NEG COUNT FOR LOOP
	MOVEI B,1(P)		;GET ADDRESS OF NEXT FREE STACK WORD
	ADD P,[NMVLP,,NMVLP]	;ALLOCATE STACK SPACE FOR LOOP
	MOVSI A,MVLP		;COPY MOVE LOOP ONTO STACK
	HRR A,B
	BLT A,0(P)
	HRRZ A,I		;FILL IN SOURCE ADR 
	HRRM A,MVLP0(B)
	HRRZ A,OU		;FILL IN DESR ADR
	HRRM A,MVLPA(B)
	HRRM B,MVLPC(B)		;FILL IN LOOP ADR TO AOJL
	MOVE A,MVLP0(B)		;GET MOVE INSTRUCTION
	TLZ A,(17777B12)	;CLEAR BITS 0-12
	TLO A,(IFIW)		;COMPOSE LOCAL INDIRECT WORD
	MOVE A,@A		;GET FIRST (PARTIAL) SOURCE WORD
	LSH A,-1		;RIGHT JUSTIFY IT
	JRST MVLPC(B)		;JUMP INTO LOOP

;FULL-WORD CHARACTER MOVE LOOP - MOVED ONTO STACK AND ADDRESSES FILLED IN

MVLP:	PHASE 0
MVLP0:	MOVE B,.-.(C)		;GET FIRST PART OF SOURCE WORD
	ROTC A,0(P2)		;SHIFT LEFT TO COMPLETE DEST WORD
	LSH A,1			;LEFT JUSTIFY DEST CHARS
MVLPA:	MOVEM A,.-.(C)		;STORE DEST WORD
	ROTC A,0(T)		;SHIFT IN REMAINDER OF SOURCE WORD
MVLPC:	AOJLE C,.-.		;COUNT WORDS AND LOOP
	JRST MVST2		;LOOP DONE, JUMP OFF STACK
	DEPHASE
NMVLP==.-MVLP			;NUMBER OF WORDS IN LOOP

;LOOP RETURNS HERE FROM STACK WHEN DONE

MVST2:	SUB P,[NMVLP,,NMVLP]	;CLEAR STACK
	JUMPG P1,MVST1		;IF ANY CHARS REMAINING, GO DO THEM
	RET

;BLT CASE - SOURCE AND DEST ARE ALIGNED

MVST4:	HRLZ A,I		;GET SOURCE ADR
	HRR A,OU		;GET DESR ADR
	ADD A,[1,,1]		;MAKE BOTH POINT TO FIRST WORD
	ADDM TT,I		;UPDATE SOURCE PTR FOR FULL WORDS MOVED
	ADDM TT,OU		;UPDATE DEST PTR FOR FULL WORDS MOVED
	HRRZ TT,OU		;GET LOCAL ADDRESS OF LAST WORD
	BLT A,0(TT)		;MOVE WORDS UNTIL LAST WORD OF DEST
	JUMPG P1,MVST1		;IF ANY CHARS REMAINING, GO DO THEM
	RET

;GET HERE WHEN SLIDING A STRING TO THE RIGHT.

MVSTX:	MOVE P1,DESEND		;GET ADDRESS TO RIGHT OF DESTINATION
	IDIVI P1,5		;SEE HOW CLOSE TO WORD BOUNDARY WE ARE
MVSTX1:	JUMPE P2,MVSTX2		;WE'RE ON WORD BOUNDARY
	CALL DOBBYT		;TRANSFER ONE BYTE
	SKIPN STRLEN		;SHOW REFLECTION OF ENTIRE LENGTH
	RET			;LENGTH EXHAUSTED, WE'RE ALL DONE
	SOJA P2,MVSTX1		;LOOP UNTIL DESTINATION ENDS ON WORD BOUNDARY
MVSTX2:	MOVE A,STRLEN		;SEE HOW MANY CHARACTERS TO DO
	CAIGE A,5		;AT LEAST ON WORD'S WORTH IN DESTINATION?
	JRST MVSTX3		;NO
	MOVE A,SRCEND		;SEE WHERE SOURCE ENDS
	IDIVI A,5
	JUMPE B,BAKBLT		;JUMP IF DESTINATION AND SOURCE ARE ON
				; WORD BOUNDARIES
	MOVE A,SRCEND
	IDIVI A,5		;SEE WHERE IN WORD IT IS
	SUBI B,5
	IMULI B,7		;GET MINUS BITS RIGHT TO SHIFT TO WORD ALIGN
				; WITH DESTINATION
	HRRM B,MAKE5		;REMEMBER FOR FAST LOOP
	ADDI B,^D35
	MOVN B,B		;GET MINUS BITS RIGHT TO SHIFT TO
				; REALIGN WITH SOURCE
	HRRM B,RESIDU
	MOVE A,STRLEN
	IDIVI A,5		;GET NUMBER OF FULL DESTINATION
				; WORDS TO BE WRITTEN
	MOVEM A,WCNTB
	MOVE A,DESEND
	SOJ A,			;GET RIGHTMOST ADDRESS OF DESTINATION
	IDIVI A,5		;RIGHTMOST WORD ADDRESS
	SUB A,WCNTB		;TIGHT LOOP ADDS WCNTB
	HRRM A,SETDES		;SAVE FOR STORING DESTINATION
	MOVE A,SRCEND
	SOJ A,			;SRCEND IS ONE CHARACTER TO RIGHT
	IDIVI A,5		;GET SOURCE WORD ADDRESS
	MOVE B,(A)		;PRIME LOOP WITH FIRST SOURCE WORD
	SOJ A,			;RIGHTMOST SOURCE ADDRESS
	SUB A,WCNTB		;OFFSET SOURCE WORD ADDRESS BECAUSE LOOP
				; INDEXES BY C
	HRRM A,GETSRC		;FIX TIGHT LOOP FETCH ADDRESS
	MOVE C,WCNTB		;C TELLS HOW MANY WORDS TO DO
	CALL MBLUP		;DO THE TIGHT LOOP
MVSTX4:	MOVE A,WCNTB
	IMULI A,5		;NUMBER OF CHARACTERS WE DID IN A
	MOVN B,A		;NEGATIVE NUMBER IN B
	ADJBP B,SRCEPT		;UPDATE NEW END OF SOURCE
	MOVEM B,SRCEPT
	MOVN B,A
	ADJBP B,DESEPT		;UPDATE NEW END OF DESTINATION
	MOVEM B,DESEPT
	MOVN B,A		;GET NEGATIVE NUMBER OF CHARACTERS DONE
	ADDM B,STRLEN		;UPDATE NUMBER LEFT TO DO
MVSTX3:	SKIPN STRLEN		;ANY MORE CHARACTERS TO DO?
	RET			;NO, ALL DONE
	CALL DOBBYT		;YES, DO ONE
	JRST MVSTX3		;LOOP FOR REST

;IF SOURCE AND DESTINATION BOTH ARE ON WORD BOUNDARIES, AND THERE'S
;AT LEAST ONE WORD TO DO, COME HERE TO DO IT.  THIS WOULD BE A BLT
;CASE IF A BACKWARDS BLT WERE AVAILABLE.

BAKBLT:	MOVE A,STRLEN		;SEE HOW MANY CHARACTERS LEFT TO DO
	IDIVI A,5		;SEE HOW MANY WORDS
	MOVEM A,WCNTB		;REMEMBER
	MOVE A,SRCEND
	SOJ A,
	IDIVI A,5		;GET RIGHTMOST WORD ADDRESS OF SOURCE
	SUB A,WCNTB		;LOOP ADDS COUNT TO ADDRESS
	HRRM A,BBS		;SET UP FETCH IN LOOP
	MOVE A,DESEND
	SOJ A,
	IDIVI A,5		;GET RIGHTMOST WORD ADDRESS OF DESTINATION
	SUB A,WCNTB
	HRRM A,BBD
	MOVE C,WCNTB		;LOAD COUNTER WITH NUMBER OF WORDS TO DO
	CALL BBL		;DO THE BACKWARDS BLT LOOP
	JRST MVSTX4		;GO UPDATE COUNTS AND FINISH NIBBLINGS

;ROUTINE TO DO ONE BYTE

DOBBYT:	SOS SRCEND		;WE'RE DOING A BYTE, SO SHRINK
				; SOURCE END ADDRESS
	HRROI TT,-2
	ADJBP TT,SRCEPT		;GET MODIFIED PTR TO JUST BEFORE END OF SOURCE
	ILDB CH,TT		;GET THE BYTE
	MOVEM TT,SRCEPT		;REMEMBER NEW END OF SOURCE POINTER
	HRROI TT,-2
	ADJBP TT,DESEPT		;GET POINTER TO DESTINATION
	IDPB CH,TT		;STORE THE BYTE
	MOVEM TT,DESEPT		;UPDATE DESTINATION END POINTER
	SOS DESEND		;UPDATE DESTINATION END ADDRESS
	SOS STRLEN		;SHOW DECREASE IN NUMBER LEFT TO DO
	RET
;ROUTINE TO RETURN IN CH THE CHARACTER TO THE RIGHT OF THE POINTER
;AND INCREMENT THE POINTER.
;CALL MOVE I,POINTER (AS A CHARACTER ADDRESS)
;	CALL GETINC
;	RETURN WITH CHARACTER IN CH AND POINTER TO CHARACTER IN I.

GETINC:	CALL GET
	AOJA I,CPOPJ

;CHANGE CHARACTER ADDRESS INTO BYTE POINTER

ADDPTR:	IDIVI A,5		;DIVIDE BY BYTES PER WORD
	HLL A,BTAB(B)		;CHOOSE CORRECT LEFT HALF
	RET

;"GET" TAKES CHARACTER ADDRESS IN I, RETURNS BYTE POINTER TO CHARACTER
;IN TT, CHARACTER IN CH.  KNOWS ABOUT THE HOLE AND HOW TO AVOID IT.

GET:	CALL GETX		;GET BYTE POINTER
	LDB CH,TT
	RET

;GETX IS LIKE "GET", BUT DOESN'T REFERENCE THE MEMORY POINTED TO
;BY THE CONSTRUCTED BYTE POINTER

GETX:	PUSH P,I		;SAVE CHARACTER ADDRESS ARG
	CAML I,HOLBEG		;ARE WE TO LEFT OF HOLE?
	ADD I,HOLSIZ	;NO, SO MODIFICATION NECESSARY TO GET OUT OF HOLE
	CALL GET2
	POP P,I			;DON'T CLOBBER USER'S I
	RET

;GET1 IS LIKE GETX, BUT DOESN'T CHECK FOR WHETHER WE'RE IN HOLE OR
;NOT

GET1:	CALL GET2
	RET

GET2:	MOVE TT,I
	IDIVI TT,5
	HLL TT,BTAB(TT1)
	RET

PUT:	CALL PUT2
	DPB CH,TT
	RET

PUT2:	MOVE TT,OU
	IDIVI TT,5
	HLL TT,BTAB(TT1)
	RET

;ROUTINE TO SUPPORT ULDB AND UILDB UUO'S, WHICH ARE EXACTLY LIKE
;LDB AND ILDB INSTRUCTIONS, EXCEPT THAT IF THE HOLE IN THE BUFFER IS
;REFERENCED, IT IS PASSED OVER.

%LDB:	HRRZ A,UUOB+.AREFA	;GET ADDRESS OF BYTE POINTER
	CAIGE A,20		;IS IT IN AN AC?
	ADDI A,UUOACS		;YES, SO POINT TO SAVED AC BLOCK
	CAIN TT,<UILDB>_-^D27	;ARE WE SUPPOSED TO INCREMENT POINTER?
	IBP (A)			;YES
	MOVE TT,(A)		;GET BYTE POINTER
	CAMN TT,HOLBPT		;MAKE SURE WE'RE NOT IN HOLE
	MOVE TT,HOLEPT		;WE ARE, GET OUT
	LDB CH,TT		;GET THE DATA
	MOVEM TT,(A)		;STORE RESULTANT POINTER
	LDB A,[POINT 4,UUOB+.ARPFL,30] ;GET AC FIELD OF LUUO
	MOVEM CH,UUOACS(A)	;STORE DATA (SECOND, SO UILDB T,T WINS)
	RET			;ALL DONE

;ROUTINE TO CHANGE BYTE POINTER TO CHARACTER ADDRESS.  GIVE IT THE
;BYTE POINTER IN TT, IT RETURNS THE ADDRESS IN I.  THE ADDRESS GIVEN
;IS AS IF THERE WERE NO HOLE IN THE BUFFER.  THAT IS, IF CHARACTER
;ADDRESS BEFORE DOING THE "AS IF" IS REAL LARGE, I.E. TO RIGHT OF
;HOLE, IT IS ADJUSTED LEFT.

PTR2AD:	CALL PTRXAD		;FIRST DO RAW WORK, THEN WE'LL WORRY ABOUT HOLE
	CAML I,HOLBEG		;ARE WE TO LEFT OF HOLE?
	SUB I,HOLSIZ		;NO, SO ADJUSTMENT NECESSARY
	RET

;ROUTINE TO TAKE BYTE POINTER IN TT AND TRANSFORM IT INTO A CHARACTER
;ADDRESS, WHICH IS RETURNED IN I.  NO AC'S ARE CHANGED EXCEPT, OF COURSE, I.

PTRXAD:	PUSH P,A
	PUSH P,B
	HRRZ I,TT		;CHANGE BYTE POINTER TO CHARACTER ADDRESS
	IMULI I,5		;5 CHARACTERS PER WORD.
	LDB A,[360600,,TT]
	IDIV A,[-7]		;DIVIDE P FIELD FOR NUMBER OF CHARS OVER IN WORD
	ADDI I,4(A)		;ADD CHARACTER REMAINDER TO CHARACTER ADDRESS
	POP P,B
	POP P,A
	RET

;CHARACTER TRANSLATION BYTE POINTER TABLE
;TRANSLATES 1 CHARACTER POSITION TO THE RIGHT
;OF A CHARACTER ADDRESS POINTER

	XWD 440700,0
BTAB:	XWD 350700,0
	XWD 260700,0
	XWD 170700,0
	XWD 100700,0
	XWD 10700,0
;ROUTINE TO CREATE THE HOLE.  IT GETS CALLED WHEN BUFFER IS BEING
;COMPLETELY CLEARED.

MAKHOL:	MOVE A,BEG		;HOLE IS INITIALLY LOCATED AT BEGINNING
	MOVEM A,HOLBEG		;REMEMBER WHERE HOLE BEGINS
	MOVX A,EMTBUF*5		;GET ADDRESS JUST BEYOND END OF HOLE
	MOVEM A,HOLEND
	CALL SETHPT
	RET

;ROUTINE TO MOVE THE HOLE.  CALL IT WITH DESIRED CHARACTER ADDRESS
;IN A.  THE HOLE WILL BE MOVED SUCH THAT ARG IN A IS FIRST CHARACTER
;OF HOLE.  HENCE CALLING IT WITH 0 PUTS HOLE AT BEGINNING OF BUFFER.

MOVHOL:	STKVAR <DISTAN,NEWBEG,NEWEND>
	MOVEM A,NEWBEG		;REMEMBER WHERE HOLE'S GOING TO
	SUB A,HOLBEG		;CALCULATE DISTANCE
	MOVEM A,DISTAN		;REMEMBER DISTANCE
	MOVE A,HOLEND
	SUB A,HOLBEG		;GET SIZE OF HOLE
	ADD A,NEWBEG		;ADD BEGINNING TO GET NEW END
	MOVEM A,NEWEND		;STORE NEW END
	MOVE A,DISTAN		;GET DISTANCE
	JUMPL A,MOVLFT		;JUMP OFF IF MOVING HOLE LEFT
	MOVE I,HOLEND		;GET OLD END OF HOLE
	MOVE OU,HOLBEG
	MOVE P1,DISTAN		;GET NUMBER OF CHARACTERS NECESSARY TO MOVE
	CALL MVCST		;MOVE DATA IN BUFFER TO RELOCATE THE HOLE
MOVDON:	MOVE A,NEWBEG
	SUB A,HOLBEG		;SEE HOW FAR RIGHT WE MOVED IT
	ADDM A,HOLEND		;MARK NEW END OF HOLE
	MOVE A,NEWBEG
	MOVEM A,HOLBEG		;REMEMBER NEW LOCATION OF HOLE
	CALL SETHPT
	RET

;FOLLOWING CODE FOR CASE WHERE HOLE IS BEING MOVED "LEFT".

MOVLFT:	MOVE I,NEWBEG		;MOVE DATA FROM NEW LOCATION OF BEGIN OF HOLE
	MOVE OU,NEWEND		;TO NEW END OF HOLE
	MOVM P1,DISTAN		;GET POSITIVE NUMBER OF CHARACTERS TO MOVE
	CALL MVCST		;MOVE DATA AROUND TO REPOSITION HOLE
	JRST MOVDON		;RESET HOLE LOCATION AND RETURN

;ROUTINE TO UPDATE HOLBPT AND HOLEPT TO CONTAIN BYTE POINTER VERSIONS
;OF HOLBEG AND HOLEND.  THIS ALLOWS MORE EFFICIENT HOLE BOUNDARY
;AVOIDANCE, AS POINTERS NEEDN'T BE CHANGED TO CHARACTERS ADDRESSES TO
;BE CHECKED.

SETHPT:	STKVAR <SAVI,SAVTT>
	MOVEM I,SAVI
	MOVEM TT,SAVTT
	MOVE I,HOLBEG		;GET BEGINNING ADDRESS
	CALL GET1		;CONVERT TO POINTER
	MOVEM TT,HOLBPT		;STORE POINTER
	MOVE I,HOLEND		;GET END OF HOLE ADDRESS
	CALL GET1		;CONVERT TO POINTER
	MOVEM TT,HOLEPT		;STORE ENDING POINTER
	MOVE A,HOLEND
	SUB A,HOLBEG
	MOVEM A,HOLSIZ		;STORE HOLE'S SIZE
	MOVE I,SAVI
	MOVE TT,SAVTT
	RET

;ROUTINE TO SAY HOW MANY CHARACTERS MORE THE BUFFER CAN HOLD
;RETURNS THE RESULT IN A.

NFREE:	MOVE A,HOLSIZ		;SOMEWHERES AROUND THE SIZE OF THE HOLE
	SUBI A,^D35		;NEED ROOM FOR STRINGS BEING SEARCHED FOR
	SUBI A,5		;NEED ROOM FOR MATCH IN SEARCHES
	RET

;WHEN READING IN A FILE, CALL FILFRE INSTEAD OF NFREE SO THAT SOME
;INSERTS MAY BE DONE AFTER THE FILE IS READ IN

FILFRE:	CALL NFREE		;GET ACTUAL SPACE AVAILABLE
	SUBI A,1000		;LEAVE SOME ROOM FOR INSERTS
	RET
;GARBAGE COLLECTION.  REMOVE FROM QREG BUFFER AREA ANY
;STRINGS NO LONGER IN USE, I.E. FOR WHICH NO POINTERS
;CAN BE FOUND.
;THIS ALSO CLEARS THE TAG CACHE
QGC:	MOVEM 16,ACNR+16
	MOVEI 16,ACNR
	BLT 16,ACNR+15		;SAVE AC'S
	CALL GC			;DO THE WORK
	MOVSI 16,ACNR		;RESTORE ACS
	BLT 16,16
	RET

GC:	MOVEI T,100
	MOVEM T,GCCNT		;NUMBER OF X'S TO DO BEFORE NEXT GC
	SETOM GCPTR		;YES. GCPTR:=-1
	CLEARM SYMS		;CLEAR SYMS,VALS AND CNTS TABLES
	MOVE T,[XWD SYMS,SYMS+1]
	BLT T,SYMEND
	MOVEI T,CPTR		;COMMAND BUFFER
	CALL GCMA
	HRRZ T,P
	CAIL T,PDL		;PUSHDOWN LIST EMPTY?
	CALL GCMA		;NO. GARBAGE COLLECT ALL BYTE POINTERS
	CAILE T,PDL
	SOJA T,.-2
	HRRZ T,PF		;COLLECT QREG PDL
	CAIL T,PFL
	CALL GCM
	CAILE T,PFL
	SOJA T,.-2
	MOVE T,[XWD -44,QTAB]	;GARBAGE COLLECT Q-REGISTERS.
	CALL GCM
	AOBJN T,.-1
	MOVE T,[XWD -USARYL,USRARY] ;CHECK IT FOR STRINGS
	CALL GCM		;LOOP THROUGH THE ENTRIES
	AOBJN T,.-1
	 ;..
;COMPACT QREG STRING STORAGE AREA

	;..
	MOVE I,QRBUF		;I WILL CONTAIN NEXT FREE ADDRESS TO USE

;FIND STRING WITH LOWEST ADDRESS IN AREA

GCS1A:	MOVE TT,EQRBUF		;END OF PRESENT QREG AREA
	SKIPGE OU,GCPTR		;SETUP TO SCAN GCTAB - EMPTY?
	JRST GCS21		;YES
GCS1:	MOVE A,GCTAB(OU)	;GET ADR OF STRING FOUND ABOVE
	ADD A,QRBUF
	CAMGE A,I		;PTR ABOVE AREA ALREADY DONE?
	JRST GCS2		;NO, NOT INTERESTED
	CAMGE A,TT		;THIS LOWEST PTR IN GC AREA?
	MOVE TT,A		;YES, REMEMBER IT
GCS2:	SOJGE OU,GCS1
GCS21:	CAML TT,EQRBUF		;IS LOWEST PTR WITHIN QREG AREA?
	JRST [	MOVEM I,EQRBUF	;NO, UPDATE FINAL END OF ACTIVE STUFF
		RET]

;HAVE FOUND A STRING, MOVE IT AND EVERYTHING AFTER IT DOWN TO
;LOWEST FREE ADDRESS.

	MOVE A,TT		;ADDRESS OF STRING
	IDIVI A,5		;COMPUTE WORD ADR OF BEG OF STRING
	MOVE B,I
	IDIVI B,5		;COMPUTE WORD ADDRESS OF BEG OF FREE SPACE
	SKIPE C			;DOES FREE AREA START ON WORD BOUNDARY?
	AOS B			;NO, SKIP PARTIAL WORD
	HRLZ OU,A		;SETUP SOURCE FOR BLT
	MOVE T,A
	SUB T,B			;COMPUTE DISTANCE OF MOVE
	JUMPLE T,GCS4A		;JUMP IF ALREADY IN RIGHT PLACE
	HRR OU,B		;SETUP DEST FOR BLT
	MOVE C,EQRBUF		;EQRBUF IS END OF SOURCE
	IDIVI C,5		;SETUP FINAL DEST FOR BLT
	SUB C,T			;I.E. FINAL SOURCE MINUS DISTANCE
	BLT OU,0(C)		;MOVE STUFF DOWN
	MOVNS OU,T		;GET NEG DISTANCE
	IMULI OU,5		;IN TERMS OF CHARACTERS
	ADDM OU,EQRBUF		;UPDATE AREA END ADDRESS
	ADDM OU,RREL		;RREL:=p1(RREL)-5*NREG
	MOVE CH,GCPTR		;UPDATE INSERTER
GCS3:	MOVE A,GCTAB(CH)	;GET STRING ADR
	ADD A,QRBUF
	CAMGE A,TT
	JRST GCS4
	ADDM OU,GCTAB(CH)	;RELOCATE PTR
	MOVE A,GCTAB2(CH)	;GET ADR WHERE PTR WAS LIVING
	SKIPL TT1,0(A)
	TLNN TT1,777700
	JRST [	ADDM OU,0(A)	;RELOCATE CHAR PTR
		JRST GCS4]
	ADDM T,0(A)		;RELOCATE BYTE POINTER
GCS4:	SOJGE CH,GCS3		;DONE?
	ADD TT,OU		;YES. I:=p1(TT)-5*NREG

GCS4A:	MOVE I,TT		;SHOULD POINT TO BEG OF STRING FLAG (141)
	CALL GETINC
	CAIE CH,141
GCERR:	IERROR <GC error>
	CALL GETINC
	MOVE A,CH
	CALL GETINC
	LSH A,7			;GET COUNT OF STRING
	IOR A,CH
	CALL GETINC
	LSH A,7
	IOR A,CH
	ADD I,A
	SUBI I,4		;CORRECT FOR 4 OVERHEAD CHARS
	JRST GCS1A
;MARK ACTIVE QREG STRING
; T/ ADDRESS OF QREG STRING PTR

GCM:	MOVE I,(T)
	TLZE I,400000		;DOES Q-REG CONTAIN TEXT?
	TLZE I,377770
	RET			;NO
	ADD I,QRBUF		;YES. ENTER POINTER IN GCTAB

GCM2:	CAML I,EQRBUF		;IN QREG BUFFER?
	RET			;NO. FORGET IT.
	CALL GET		;YES. CHECK FOR MARK.
	CAIE CH,141		;END OF STRING?
	RET			;NO.
GCM3:	SUB I,QRBUF		;YES. I:=# CHARACTERS TO RETREIVE.
	AOS TT,GCPTR		;YES. TO BE GRABBED.
	CAIL TT,GCTBL		;AM IN WINNING?
	JRST GCERR		;NO. VERY BAD.
	MOVEM I,GCTAB(TT)	;SAVE CHAR ADR
	MOVEM T,GCTAB2(TT)	;SAVE WHERE IT LIVES
	RET

;MARK ACTIVE BYTE PTR, I.E. CPTR AND SAVED CPTR'S WHILE IN MACROS.
; T/ ADDRESS OF BYTE PTR
;ASSUMED: ADDRESS-1 CONTAINS TOTAL COUNT (COMAX), ADDRESS+1
;CONTAINS REMAINING COUNT (COMCNT).

GCMA:	MOVE I,0(T)
	LDB TT,[POINT 12,I,17]	;BYTE SIZE + XR
	CAIE TT,700		;DOES T PT TO A TEXT BYTE PTR?
	RET			;NO
	LDB TT,[POINT 6,I,5]	;BYTE POSITION
	IDIVI TT,7		;NO. OF CHARACTERS
	HRRZI I,1(I)		;BYTE PTR ADDR +1
	IMULI I,5
	SUBI I,4(TT)		;A MAGIC NUMBER
	ADD I,1(T)		;CT (WE HOPE)
	SUB I,-1(T)		;MAX
	JRST GCM2
WRDCOM:	STKVAR <BEGWRD>
	MOVE A,CPTR		;GET POINTER TO BEGINNING OF WORD
	MOVEM A,BEGWRD		;REMEMBER
WRD1:	CALL SKRCH		;PICK UP LETTER OF WORD FROM COMMAND STRING
	CAIE CH,.CHESC		;END OF WORD FROM COMMAND STRING?
	JRST WRD1		;NO, KEEP LOOKING
	SETZ A,
	DPB A,CPTR		;ISOLATE WORD BY PUTTING BULL AT END
	MOVEI A,WORDS		;TELL SYSTEM WHERE TABLE IS
	MOVE B,BEGWRD		;GET POINTER TO WORD
	TBLUK%			;LOOK UP THE WORD
	MOVEI D,.CHESC
	DPB D,CPTR		;FIX THE COMMAND STRING
	TXNE B,TL%AMB		;GIVE APPROPRIATE ERROR IF FAILURE
	ERROR <Ambigious partial command>
	TXNE B,TL%NOM
	ERROR <Undefined command word>
	HRRZ B,(A)		;GET ADDRESS OF DATA BLOCK
	MOVE A,(B)		;GET FLAGS
	MOVE C,FARG		;[502] JUST GET THE ARG
	JRST @1(B)		;GO EXECUTE THE COMMAND

;WLIST$ - LIST ALL THE DEFINED WORDS

WRDLST:	CALL WINCLS		;THIS IS PRESERVED OUTPUT.
	MOVSI CH,-WLEN		;AOBJN WORD OF SORTS
	MOVE I,SWIDTH		;WHAT DO WE THINK THE WIDTH IS?
	SUBI I,21		;LESS ABOUT 2 TAB STOPS
	MOVEM I,SYL		;WE STOP IF WE WOULD TAB TO HERE
	SETZ I,			;I IS POSITION ON LINE, START AT BEGINNING
WRDLS1:	HLRZ C,WORDS+1(CH)	;(466)GET ADDRESS OF WORD NAME
	UPSTR @C		;TYPE OUT WORD
	AOBJP CH,WRDELX		;IF THATS THE LAST WORD, LEAVE LOOP NOW
	SETZ A,			;NO, MUST COUNT # CHARACTERS TYPED
	HRLI C,(POINT 7)	;READ EACH CHARACTER WE TYPED
WRDLSC:	ILDB B,C		;..
	CAIE B,0		;AT END OF STRING?
	AOJA A,WRDLSC		;NO, ADD ONE TO COUNT AND COUNT ON
	TRZ A,7			;CONVERT TO TABS STOPS-1
	JUMPG A,WRDLS3		;IF 10 OR MORE CHARACTERS, GO
	MOVEI B,1		;NO, NEED 2 TABS, NOT 1
	MOVEI A,10		;AND ACCOUNT FOR TYPED TAB
WRDLS3:	ADDI I,10(A)		;IF TABS TYPED, WE ARE AT CHARACTER LOC (I)
	CAML I,SYL		;AT/PAST MAX FOR THIS LINE?
	JRST [	SETZ I,		;YES, CLEAR COUNT
		CALL CRR	;AND START AN NEW LINE
		JRST WRDLS1]	;AND GO GET NEXT WORD
WRDTBO:	CTYPE <	>		;TYPE TAB
	SOJGE B,WRDTBO		;MIGHT NEED ANOTHER ONE
	JRST WRDLS1		;[502] DONE

WRDELL:	TXNN FF,ARG
WRDELX:	SETZM FARG
WRDEL1:	CALL CRR
	SOSLE FARG
	JRST WRDEL1
	JRST CFLUSH

PRESCR:	MOVE A,WINFLG		;MIGHT WANT WINFLG RETURNED
	CAILE A,0		;IF .GT. 0...
	SETZ A,			;RETURN 0
	TXNN FF,ARG		;TAKE OR RETURN?
	JRST ARGINA		;RETURN
	CAIGE C,0		;TAKE. IF C .LT. 0,...
	SETO C,			;SET TO -1
	MOVEM C,WINFLG		;STORE
	JRST CFLUSH		;AND DONE

;W COMMAND DISPATCH TABLE.  W STANDS FOR WORD AND MAY APPEAR IN THE
;COMMAND STRING FOLLOWED BY A UNIQUE WORD OR PARTIAL WORD.

DEFINE WORD (A,C,FLAGS<0>)<[ASCIZ /A/],,[EXP FLAGS,IFIW!C]>

;**; [502] At WORDS:, remove references to flags CH%TOR SM	4-Mar-82
;CURRENTLY DEFINED WORD COMMANDS:
WORDS:	WLEN,,WLEN
	WORD AUTO-EXPUNGE,AUTO	;AUTO-EXPUNGE WHEN OVER QUOTA
	WORD BACKUP,BACKUP	;TURN ON COMMAND SAVING
	WORD CLEOS,CEOS		;CLEAR TO END OF SCREEN
	WORD CRLF,WRDELL	;TYPE A CRLF (NOT PRESERVED)
	WORD DATE-AND-TIME,WDATIM ;INSERT CURRENT DATE AND TIME
	WORD EDITBASIC,EBASIC	;DON'T FILTER OUT LINE #'S.
	WORD EDITREGULAR,ERGLR	;FILTER LINE NUMBERS AS USUAL.
 OPTION ENC,<
	WORD ENCRYPT,ENCPT	;TURN ENCRYPTION FLAG ON/OFF
>
	WORD ENTER,ENTFVR	;RETURN ENTER FLAG
 IFG MAXSEC,<
	WORD FETCH-BUFFER,CIN	;RESTORE TV STATE
>
	WORD FILENAME,WFILEN	;LAST FILENAME IN COMMAND
	WORD FLAGUPPERS,FLAGU	;FLAG CAPITALS
 IFG MAXSEC,<
	WORD FREE-BUFFER,CDEL	;GO DELETE BUFFER
>
	WORD HOLE,WHOLE		;RETURN LOC OF INTERNAL HOLE
	WORD LIBRARY,WLIBR	;LOAD Q-REGS FROM A FILE
	WORD LIST,WRDLST	;LIST ALL THE DEFINED WORD
	WORD NOAUTO-EXPUNGE,NOAUTO ;DON'T AUTO-EXPUNGE WHEN OVER QUOTA
	WORD NOBACKUP,NOBACK	;TURN OFF COMMAND SAVING
	WORD NOFLAG,NOFLAG	;DON'T FLAG ANY LETTERS
	WORD NOSHIFT,NSHIFT	;DON'T SHIFT INPUT
	WORD PERUSE,WPERUS	;GET/SET/CLEAR PERUSE BIT
	WORD PRESERVE,PRESCR	;SET UP TO PRESERVE SCREEN OUTPUT
	WORD RAISE,TERRAS	;RAISE INPUT LETTERS
	WORD SAVLEN,BETSAV	;GET/SET # CHARS TO INPUT BEFORE SAVING.
	WORD SCREENSIZE,SCNSET	;SET OR GET SCREEN SIZE
	WORD SILENCE,SETSHH	;SET/CLEAR NO "END OF..." MSG
 IFG MAXSEC,<
	WORD STORE-BUFFER,COUT	;"SAVE" TV STATE
>
	WORD SUM,WSUM		;RETURN ARRAY SUM
	WORD UPDATE,WUPDATE	;UPDATE THE SCREEN
	WORD VT05,VT05		;ANNOUNCE THAT YOU ARE RUNNING ON A VT05
	WORD VT100,VT100	;SAY VT100
	WORD VT50,VT50		;SAY YOU ARE ON A VT50.
	WORD VT52,VT52		;SAY WE'RE A VT52
	WORD WIDTH,WTHSET	;SET OR GET CURRENT LINE WIDTH
	WORD WINSIZE,WINSET	;GET OR SET WINDOW SIZE
	WORD ZERO,WZERO		;PROPAGATE 0 (OR SOMETHING) THROUGH THE ARRAY
WLEN==.-WORDS-1

;PUT LITERALS HERE THAT SAVER NEEDN'T HAVE IN ITS MAP
XLIST				;DON'T CLUTTER LINEPRINTER PAPER WITH THEM
LIT
LIST
;PAGES USED FOR WINDOWS TO OTHER FORK

FRKWPN==<.+1000>_-9
FRKWIN==FRKWPN_9
FRKWP2==FRKWPN+1
FRKWI2==FRKWP2_9

LOC FRKWI2+1000			;LEAVE ROOM FOR WINDOWS

;PATCH SPACE

PATS:
PAT:	BLOCK 50

;DATA AREA FOR TV

DATAIS:				;ADDR OF BEGINNING OF VARIABLE SPACE

;IF 0, THIS IS THE VIRGIN RUN (FIRST TIME SINCE LOADING)
VIRGIN:	-1

;ROUTINE TO MOVE STRING STARTING WITH RIGHTMOST END.  IT'S HERE
;BECAUSE THE "000"S GET FILLED IN AT RUN TIME. YES, CRUDE.

MBLUP:
GETSRC:	MOVE A,000(C)		;GET SOURCE WORD
	LSH A,-1		;GET RID OF DATA GAP AT B35
MAKE5:	LSHC A,000		;GET 5 CONTIGUOUS BYTES IN B
	TRZ B,1			;GET RID OF B35
SETDES:	MOVEM B,000(C)		;STORE DESTINATION WORD
RESIDU:	LSHC A,000		;PUT REST OF WHAT WAS IN A LEFT-JUSTIFIED IN B
	SOJG C,MBLUP		;REPEAT FOR ALL FULL WORDS
	RET			;DONE

;ROUTINE TO MOVE STRING FROM RIGHTMOST END WHEN WE KNOW THERE'S NO
;SHIFTING TO DO BECAUSE SOURCE AND DESTINATION ARE WORD ALIGNED

BBL:
BBS:	MOVE A,000(C)		;GET SOURCE WORD
BBD:	MOVEM A,000(C)		;STORE IN DESTINATION
	SOJG C,BBL		;REPEAT FOR ALL WORDS
	RET

;FUNCTION DESCRIPTOR BLOCK FOR COMND TO READ FILESPECS

FILCBK:	<.CMFIL>B8		;SPECIFY FILE FUNCTION
	0			;DATA
	0			;HELP TEXT
	-1,,DEFSPC		;DEFAULT POINTER

FIRSTV:				;FIRST LOCATION CLEARED AT STARTUP
COCNST:	0			;NUMBER OF TIMES WE'VE SET DISPLAY MODE
COCPOS:	0			;SAVED LINE POSITION BEFORE ESCAPE SEQUENCE
REGCWD:	BLOCK 2			;STANDARD CONTROL ECHO BITS
TRMTYP:	0			;HOLDS TERMINAL TYPE
UUOACS:	BLOCK 20		;SAVED AC'S DURING UUOS
IAC:	BLOCK 20		;INTERRUPT AC'S
ABORTF:	0			;ABORT REQUESTED IF NOT 0
LISNF:	0			;DOING COMMAND INPUT IF NOT 0
COFLG:	0			;SUPRESS OUTPUT IF NON-0
BASICF:	0			;-1 IF WE INSIST "NO FILTER LINE #S"
FLAGF:	0			;-1 = FLAGGING UPPERS
CRRCNT:	0			;NUMBER OF CRLFS TYPED
COLUMN:	0			;CURSOR COLUMN DURING COMMAND TYPIN
ERRBLN==20			;ROOM FOR SYSTEM ERROR MESSAGES
LSTERR:	0			;HOLDS 0 OR SPECIFIC ERROR NUMBER
ERRBUF:	BLOCK ERRBLN
FLDSIZ==^D78			;SIZE OF FILESPEC FIELD MAX, 39 CHARS MAYBE
				; ALL QUOTED
FWDS==FLDSIZ/5+1		;WORDS NEEDED FOR FIELD OF FILESPEC

FNAMSZ==FLDSIZ+1+1+FLDSIZ+1+FLDSIZ+1+FLDSIZ+1+6+1+FLDSIZ
 ;STRUCTURE, COLON, BRACKET, DIR, BRACKET, NAME, DOT, EXT, DOT,...
 ; GENERATION, SEMICOLON, ATTRIBUTE

NAMBFR:	BLOCK FNAMSZ/5+1	;ROOM FOR NAME PLUS NULL

DEFSPC:	BLOCK FNAMSZ+1		;DEFAULT FILESPEC

CMDBLN==<FLDSIZ+1+FNAMSZ+2>/5+1	;PROGRAM, SPACE, FILESPEC, CRLF (RESCAN BUFFER)
CMDBFR:	BLOCK CMDBLN
CMDACS:	BLOCK 20		;SAVED AC'S FROM BEGINNING OF COMMAND LINE
 ATMBLN==CMDBLN
ATMBFR:	BLOCK ATMBLN		;HOLDS LAST PARSED FIELD
SBK:	BLOCK 20		;COMND JSYS STATE BLOCK
CJFNBK:	BLOCK 20		;GTJFN BLOCK FOR COMND JSYS
REPARA:	0			;REPARSE ADDRESS FOR COMND
DATBUF:	BLOCK 200		;FOR RANDOM DATA INSERTIONS
BAKTAB:	BLOCK 20		;RECEIVES ASCII CONVERSION OF NUMERICAL ARGUMENT
TRACS:	0			;RET OR JRST OUTPUT ROUTINE
BAKLEN:	0			;NUMBER OF CHARACTERS TO BUFFER BEFORE SAVING
BAKFLG:	0			;-1 IF COMMANDS ARE BEING SAVED
SAVFRK:	0			;HOLDS FORK HANDLE OF SAVER
LPM:	0			;LAST PAGE MAPPED FROM OTHER FORK
LPM2:	0			;LAST OTHER PAGE MAPPED FROM OTHER FORK
RESPTR:	0			;PTR TO CMD STRING INVOKED BY "TV FILENAME"
LSTCB:	0			;BEG OF LAST COMMAND STRING
LSTCE:	0			;END OF LAST COMMAND STRING
ISEED:	0			;FOR RANDOM NUMBER GENERATION (!)
 OPTION ENC,<			;FOR (UNSUPPORTED) CODING ALGORITHM
encflg:	0
cdestr:	0
cdecnt:	0
cdewrd:	0
whrcde:	0
cdewri:	0
cdewro:	0
cdewin:	0
cdewon:	0
 >
DIVREM:	0			;REMAINDER AFTER LAST USER IDIV
ENTFLG:	0			;HOW WE GOT HERE (0=?, 1=EDIT, -1=CREATE)
SYL:	0			;TEMP FOR MANY RANDOM ROUTINES
JFNIS:	0			;USED BY WLIBRARY.
STOPAT:	0			;USED BY MFILE0/1
WLCKF:	0			;LOCK FLAGS
;**;[510] At TMPFLG:, Inserted 1 line                       SM 26-May-82
TMPFLG:	0			;[510] USED FOR STORING FF
DLIMIT:	0			;[502] DELIMITER USED IN SCANNING STRINGS
FARG:	0			;[502] FARG, Not NUM, and DLIM not needed
SARG:	0
EXECOP:	0			;[502] BINARY OP DUE TO BE DONE
LASTOP:	0			;[502] BINARY OP BEING REQUESTED
SKPPNT:	0			;[502] POINTER WHILST SKIPPING TRAILING ARGS
PREFXC:	0			;[502] COMMAND PREFIX
PREOPV:	0			;[502] VALUE BEFORE BINARY OP
LEV:	0
DUNFLG:	0			;  ;D/;U FLAG
DEFNAM:	BLOCK FWDS		;DEFAULT FILE NAME
DEFEXT:	BLOCK FWDS		;DEFAULT EXTENSION
TTYOUT:	0			;TTY OUTPUT JFN
TYIJFN:	0			;TYPIN JFN
TYIP:	0			;TYPIN STACK POINTER
 TYILEN==50			;MAXIMUM DEPTH OF INPUT FILES ALLOWED FOR TYPIN
TYIPDL:	BLOCK TYILEN		;TYPIN STACK
TERIO:	0			;SET IF CURRENT INPUT IS FROM A TERMINAL
OTERIO:	0			;PREVIOUS (OLD) VALUE OF TERIO
INJFN:	0
OUTJFN:	0
YAMODE:	0			;DOING Y OR A, OR ;Y
SILFLG:	0			;NON-0 IF "END OF ..." MESSAGE TO BE SKIPPED.
WRITEF:	0			;NON-0 IF OUTPUT FILE HAS SOME OUTPUT IN IT
SCNEST:	0			;NEST LEVEL WHILE SCANNING
LCHAR:	0			;CHARACTER BEING SCANNED FOR
ITERCT:	0
INTDPH:	0			;DEPTH IN ITERATIONS
PCISG:	0			;USED FOR "# HACK
SRPF:	0			;-1 IF REPARSE NEEDED OF SEARCH STRING
CEYFLG:	0			;-1 IF ^EY HAS CHANGED SINCE LAST SEARCH
EXACTF:	0			;0= SEARCHES MATCH EITHER CASE, 1= EXACT
SFINDF:	0
ERR1:	0
RADIX:	0			;holds radix for number printout
LISTF5:	0			;OUTPUT DISPATCH

UUOB:	BLOCK 4			;HARDWARE LUUO BLOCK

;*** TEXTI STATE BLOCK

RDCWB:	0			;NUMBER OF WORDS FOLLOWING
RDFLG:	0			;FLAGS
RDIOJ:	0			;SOURCE DESIGNATOR,,DESTINATION DESIGNATOR
RDDBP:	0			;DESTINATION POINTER
RDDBC:	0			;NUMBER OF BYTES MORE WE CAN READ
RDBFP:	0			;BEGINNING OF DESTINATION BUFFER
RDRTY:	0			;POINTER TO PROMPT
RDBRK:	0			;POINTER TO BREAK SET
RDBKL:	0			;PLACE IN INPUT WHERE WE MUST REPARSE

RDEND==.			;USED TO MEASURE SIZE OF BLOCK
FCHAR:	0			;FIRST CHARACTER OF COMMAND

;*** DO NOT SEPARATE ***

 	CMMSK==370037,,RESQE	;USUALLY STUFFED IN TO SAY "THIS IS A CSB"
 CBBLK==.		;BEGINNING OF AREA TO STACK WHEN CHANGING COMMAND STATE
COMAX:	0
CPTR:	0
COMCNT:	0
CMSMK:	0			;MUST BE LAST WORD OF THIS BLOCK
 CBLEN==.-CBBLK			;NUMBER OF WORDS TO SAVE FOR COMMAND STATE

;*** DO NOT SEPARATE ***

CBUFH:	0
GCPTR:	0
GCCNT:	0			;COUNT OF X'S TO DO BETWEEN GC'S
RREL:	0

;*** SEARCH DATA

SMAXLN==200			;MAXIMUM SEARCH STRING LENGTH
				; (NUMBER OF TYPED CHARACTERS)
SMAXWD==SMAXLN/5+1		;WORDS TO HOLD MAXIMUM LENGTH
SCHPTR:	0			;POINTER TO SEARCH STRING
SSLEN:	0			;NUMBER OF TYPED CHARACTERS IN LAST SEARCH
SCHBUF:	BLOCK SMAXWD		;ACTUAL CHARACTERS TYPED IN LAST SEARCH STRING
SRCHLN:	0			;BIT N ON MEANS SEARCH STRING IS N CHARS LONG
SCHLNN:	0			;N
SENDPT:	0			;CHAR ADDRESS OF CHAR THAT MATCHED IN SEARCH
S0PT:	0			;WHAT TO SET PT TO IF SEARCH HAS SUCCEEDED
				; n TIMES
SDELIM:	0			;SEARCH DELIMITING CHARACTER ($ UNLESS @S)
CARTAB:	BLOCK 5			;CARBTS WITH GAP IN DIFFERENT PLACES
SMTAB:	BLOCK 5			;SAME AS CARTAB BUT WITH SMASK
SCHARG:	0			;ARGUMENT TO SEARCH COMMAND
SLAST:	0			;B.P. TO NTH CHARACTER POSITION
				; IN SEARCH WORKING REGISTER
NXTFRM:	0			;WHERE TO GO DURING SEARCH TO SKIP FRAME
SLIDE:	0			;NUMBER OF BITS TO SHIFT DATA IN ORDER
				; TO SKIP FRAME
SDAT:	BLOCK 2			;HOLDS SEARCH DATA FROM BUFFER
MATCH:	0			;HOLDS A MATCH ON 1ST 5 CHARACTERS OF SEARCH
SMASK:	0			;SHOWS WHAT FIRST FIVE CHARACTERS SHOULD BE
CARBTS:	0			;BIT POSITIONS WE CARE ABOUT DURING SEARCH
SADD:	0			;ADDRESS AT WHICH TO RESUME SEARCH...
				; AFTER FALSE ALARM
SPTR:	0			;POINTER TO BUFFER DURING SEARCH
REPARG:	0			;ARG TO REPLACE COMMAND
SOARG:	0			;OLD SEARCH ARG
SMATLN==200			;LENGTH OF SEARCH MATRIX
SMAT:	BLOCK SMATLN		;SEARCH MATRIX.  BIT N ON IN WORD K
				;MEANS CHARACTER K IS BEING SEARCHED FOR
				;AS AN N-1TH CHARACTER IN THE SEARCH STRING

;*** END OF SEARCH DATA SECTION

OTAB:	BLOCK OTABL		;"O" COMMAND SEARCH TABLE
GCTAB:	BLOCK GCTBL		;GCS3+4,GCM2+13
GCTAB2:	BLOCK GCTBL
ACNR:	BLOCK 20		;SAVED ACS IN GC

				 ;THESE ARE REF'D BY: [(0)=ZERO'D BY]
SYMS:	BLOCK 22		;ZSYMS(0),OG3+1,GC+3(0)
VALS:	BLOCK 22		;ZSYMS(0),OG3+3,GC+3(0)
CNTS:	BLOCK 22		;ZSYMS(0),OG3+2,GC+3(0)
SYMEND=.-1

 IFN MAXSEC,<			 ;;IF and only if allowing extended addressing
MSECF:	0			;MULSEC FLAG
MVELST:	BLOCK	30		;SPACE TO CREATE COMMAND LISTS FOR FOR XTN GAMES
 >

GTJERR:	0			;ERROR CODE FROM GTJFN
GTJJFN:	0			;JFN
CREJFN:	0			;JFN FOR CREATE COMMAND
BBUFX:	0			;SHOWS WHICH BACKUP BUFFER BEING USED
WTOGGL:	0			;WINDOW BUFFER TOGGLE FOR SAVER FORK
				;HOLDS 0 FOR ONE BUFFER, -1 FOR OTHER
				;USING TWO BUFFERS REDUCES NUMBER OF PMAPS
				;NEEDED
BBPTR:	0			;POINTER TO BACKUP BUFFER
BBLEN:	0			;NUMBER OF CHARACTERS IN BACKUP BUFFER
OBBLEN:	0			;BBLEN AT TIME OF LAST UPDATE
OCP:	0			;OLD COMMAND POINTER (WHERE LAST BACKUP OCCURED)
INIJFN:	0			;HOLDS INI FILE JFN
QUOJFN:	0			;HOLDS JFN BEING WRITTEN TO
UPDATF:	0			;-1 IF DOING WUPDATE

PFINFO:			;QREG STACK
PF:	0			;Q-REG STACK POINTER
PFL:	BLOCK LPF		;Q-REG STACK
PFINFE=.-1

QINFO:			;QREG INFO
QTAB:	BLOCK 45		;Q-REGISTER TABLE
 QTABE=.-1
QRBUF:	0
EQRBUF:	0			;END OF QREG BUFFER AREA
QINFE=.-1

BFINFO:			;BUFFER STATE INFO
HOLBEG:	0			;CHARACTER ADDRESS OF BEGINNING OF HOLE
HOLEND:	0			;CHAR ADDRESS OF FIRST CHARACTER NOT IN HOLE
HOLBPT:	0			;BYTE POINTER (LDB) TO BEGINNING OF HOLE
HOLEPT:	0			;BYTE PTR (LDB) TO FIRST CHAR TO RIGHT OF HOLE
HOLSIZ:	0			;NUMBER OF CHARACTERS IN HOLE
BEG:	0
PT:	0
ZEE:	0			;CHAR PTR TO END OF BFR
 BFINFE=.-BFINFO
			;ARRAY
USRARY:	BLOCK USARYL		;USER ARRAY

;**** VARIABLE AREA FOR STRING MOVE ROUTINE

SRCBEG:	0			;LEFTMOST CHARACTER ADDRESS OF STRING
				; BEING MOVED
SRCBPT:	0			;BYTE POINTER FORM OF SRCBEG
DESBEG:	0			;LEFTMOST CHAR ADDRESS OF DESTINATION
DESBPT:	0			;BYTE POINTER FORM OF DESBEG
SRCEND:	0			;CHAR ADDRESS JUST TO RIGHT OF SOURCE
SRCEPT:	0			;BYTE POINTER FORM OF SRCEND
DESEND:	0			;CHAR ADDRESS JUST TO RIGHT OF DESTINATION
DESEPT:	0			;BYTE POINTER FORM OF DESEND
STRLEN:	0			;NUMBER OF CHARACTERS LEFT TO MOVE
WCNTB:	0			;NUMBER OF WHOLE WORDS BEING MOVED

;**** END OF STRING MOVE STORAGE AREA

PDL:	BLOCK LPDL
CMDPDL:	BLOCK LPDL		;SAVED PDL DURING COMMAND

;*****  DISPLAY ROUTINE VARIABLE AREA

SCRNF:	0			;SET TO -1 IF WE'RE RUNNING ON A SCREEN.
SCRNZ:	0			;BYTE POINTER TO LAST CHARACTER TO BE DISLAYED
SCRNPT:	0			;CHAR ADDRESS OF FIRST CHAR TO BE DISPLAYED
ILDBPT:	0			;LDB POINTER TO CHARACTER BEFORE POINTER
SCNEND:	0			;CHAR ADDRESS OF LAST CHAR IN BUFFER DISPLAYED
MESFLG:	0			;SET TO -1 TO MEAN DISPLAY IS MESSED UP
SWIDTH:	0			;SCREEN WIDTH
LASTCH:	0			;CONTINUATION CHARACTER FOR LAST COLUMN
DLENTH:	0			;NUMBER OF LINES TO USE FOR NEXT DISPLAY WINDOW
DISBLK:	0			;NUMBER OF LINES TYPED BEFORE SOME THAT
				; WANT TO NOT BE OVERWRITTEN BY DISPLAY
TXTI:	BLOCK .RDDBC+1		;TEXTI BLOCK FOR MFILE0:
SLENTH:	0			;HOLDS NUMBER OF SCREEN LINES TO DISPLAY
SSIZE:	0			;HOLDS NUMBER OF LINES THAT FIT ON SCREEN
MAXLEN==^D40			;MAXIMUM VALUE ALLOWABLE FOR SLENTH
PTRCHR:	BLOCK 2			;ASCII STRING TO REPRESENT POINTER WITH
LBSIZ==<MAXWTH*2>/5+1		;WORDS NEEDED FOR DISPLAY LINE BUFFER
LINBFR:	BLOCK LBSIZ
WINDEX=1+<MAXWTH+2>/5		;PDP-10 WORDS PER SCREEN LINE
LINBF2:	BLOCK WINDEX		;OUTPUT BUFFER WHEN REPLACING ENTIRE LINE
				;STORAGE
WINTOP=MAXLEN*WINDEX-1		;HIGHEST WORD USED FOR SCREEN MEMORY RELATIVE
				;TO FIRST WORD (WINDOW OR WINEW)
WINDOW:	BLOCK WINTOP+1		;STORAGE OF WHAT IS SHOWING ON SCREEN NOW
WINEW:	BLOCK WINTOP+1		;NEW SCREENFUL ABOUT TO BE DISPLAYED
LINBEG:	BLOCK MAXLEN		;CHAR POINTERS TO BEGINNING OF DISPLAY
				; LINES IN BUFFER
LINNEW:	BLOCK MAXLEN		;SAME POINTERS AS LINBEG. MOVED TO LINBEG AS
				; LINES ARE ACTUALLY PUT ON SCREEN.
WINFLG:	0			;-1 IF NO LINES WORTH PRESERVING HAVE
				; BEEN PRINTED
EOBFLG:	0			;END OF BUFFER FLAG
SEOL:	0			;END OF DISPLAY LINE FLAG
CTLFLG:	0			;CONTROL CHARACTER FLAG
PUTPTF:	0			;POINTER ON SCREEN FLAG
TYPEF:	0			;-1 WHEN USER STARTS TYPING
DATAE=.-1			;END OF TV VARIABLE SPACE

;THIS IS THE ROUTINE THAT RUNS AS A LOWER FORK TO SAVE TYPED IN
;STRINGS ON THE DISK.
;THIS ROUTINE MUST BE LOADED IN MEMORY CONTIGUOUS TO EVERYTHING
;IT NEEDS TO RUN, SUCH AS ITS LITERALS, DATA, CODE, AND ANY ROUTINES
;IN .REQUIRED FILES.  THIS IS BECAUSE FOR THE PURPOSE OF STARTUP
;EFFICIENCY, WE WANT TO DO A SINGLE PMAP TO SET UP THE MINIMUM NUMBER
;OF PAGES IN THE LOWER FORK.

SAVBEG==.			;REMEMBER WHERE SAVER FORK BEGINS

;DATA FOR SAVER FORK.  IT MUST BE CONTIGUOUS WITH THE SAVER FORK
;ITSELF

SDONEF:	0			;-1 WHEN SAVER DONE SAVING A STRING
SAVJFN:	0			;HOLDS COMMAND FILE JFN
SAVPDL:	BLOCK 50		;STACK FOR SAVER
MAXBAK==^D1000			;MAXIMUM NUMBER OF TYPED IN CHARS
				; ALLOWED BETWEEN SAVES
SAVX:	0			;BYTE POINTER TO WHICH AREA TO SAVE
SAVTOT:	0			;TOTAL CHARACTERS BEING BACKED UP
SAVPER:	0			;NUMBER OF PERMANENT CHARACTERS BEING BACKED UP
SAVPOS:	0			;FILE POSITION AT WHICH SAVED CHARS SHOULD GO
EXPFLG:	0			;-1 FOR AUTO-EXPUNGE
DIRECT:	BLOCK 1+3+^D78/5	;SPACE FOR DIRECTORY NAME

TOP==.-1
;INTERRUPT TABLES

LEVTAB:	LEV1PC
	LEV2PC
	LEV3PC			;LOCATIONS OF SAVED PC DURING INTERRUPTS

LEV1PC:	BLOCK 2
LEV2PC:	BLOCK 2
LEV3PC:	BLOCK 2			;INTERRUPT PC'S STORED HERE

CHNTAB:	XWD 3,TTYINT		;CONTROL-G
	XWD 3,CTRL.O		;CONTROL-O
	XWD 3,CTRL.C		;CONTROL-C
	XWD 3,TYPO		;USER HAS TYPED SOMETHING
TICHN==3			;TYPEIN INTERRUPT CHANNEL
	REPEAT ^D11-^D4,<0>
	XWD 3,IOERR		;CHANNEL 11, IO ERROR
	XWD 3,OVRQUO		;CHANNEL 12, OVER QUOTA
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0
	0

;GTJFN BLOCK FOR COMMAND FILE...

SAVFIL:	GJ%FOU			;FILE FOR OUTPUT USE
	377777,,377777		;NO JFNS FOR FILE NAME INPUT
	0
	0
	POINT 7,[ASCIZ /COMMANDS/]
	POINT 7,[ASCIZ /TV/]
	0			;STANDARD PROTECTION,
	0			;ACCOUNT
	0
	0
	0

;GTJFN INFO FOR ACCESSING TV.INI FILE.

INIFIL:	GJ%OLD			;OLD FILE ONLY
	377777,,377777
	0
	0
	POINT 7,[ASCIZ /TV/]
	POINT 7,[ASCIZ /INI/]
	0
	0
	0
	0
	0

;GET TO HERE WHEN A TYPED IN STRING IS READY TO BE SAVED...

SAVST:	SKIPN A,SAVJFN		;GET JFN OF BACKUP FILE
	JRST CNOGT9		;NO JFN EVER DONE, GO DO IT
SAVST1:	MOVE B,[7B5+OF%WR+OF%RD] ;OPEN FILE IN UPDATE MODE
	OPENF%
	JRST CNOGET		;COULDN'T OPEN IT, SAY WHY
	MOVE B,SAVPOS		;GET TO CORRECT FILE POSITION
	SFPTR%
	 JSHLT
	MOVE A,SAVJFN		;GET JFN TO SAVE STRING ON
	MOVE B,SAVX		;POINT AT TEXT BEING SAVED
	MOVN C,SAVTOT		;GET NEGATIVE NUMBER OF CHARACTERS TO SAVE
	SOUT%			;SAVE THE STRING ON THE DISK
	 ERJMP CNOGTE		;COULDN'T, PROBABLY OVER QUOTA
	TXO A,CO%NRJ		;CLOSE FILE BUT DON'T RELEASE JFN
	CLOSF%
	 JSHLT
	SETO B,			;WE WANT TO CHANGE AN ENTIRE FDB WORD
	MOVE C,SAVPOS		;GET PLACE IN FILE WE STARTED WRITING
	ADD C,SAVTOT		;ADD NUMBER OF CHARACTERS WRITTEN TO GET
				; TOTAL FILE SIZE
	HRLI A,.FBSIZ		;SPECIFY WHICH WORD WE'RE CHANGING
	CHFDB%			;UPDATE THE FILE'S END
	MOVE A,SAVPOS		;GET FILE POSITION
	ADD A,SAVPER		;INCREASE BY AMOUNT EQUAL TO #...
				; OF PERMANENT CHARACTERS
	MOVEM A,SAVPOS
	SETOM SDONEF		;SET DONE FLAG TO SHOW WE'RE DONE
	HALTF%			;JUST HALT

;HERE WHEN ERROR, PROBABLY OVER QUOTA

CNOGTE:	MOVE A,SAVJFN		;CLOSE JFN
	TXO A,CO%NRJ		;BUT DON'T RELEASE IT
	CLOSF%
	 JSHLT
CNOGT3:	MOVEI A,.FHSLF
	GETER%			;GET LAST ERROR
	HRRZM B,SDONEF		;SIGNAL WE'RE DONE WITH ERROR CODE
	HALTF%

CNOGET:	CAIE A,OPNX2		;FILE DELETED OUT FROM UNDER US?
	JRST CNOGT8		;NO, SOMETHING ELSE
	MOVE A,SAVJFN		;YES, THROW AWAY OLD JFN
	RLJFN%
	 JFCL			;DON'T WORRY IF CAN'T
	JRST CNOGT9		;GO GET NEW JFN
CNOGT8:	CAIE A,DESX3		;SKIP IF JFN WAS RELEASED OUT FROM UNDER US
	JRST CNOGT3		;NO, OPENF FAILED FOR OBSCURE REASON
				; (MAYBE ENTIRE DISK FULL!!)
CNOGT9:	DMOVE A,[EXP SAVFIL,<-1,,[ASCIZ /TVBACK:/]>]
	GTJFN%			;PERHAPS USER WANTS BACKUP FILE
				; ON LOGICAL NAME TVBACK:
	 ERJMP CNOGT1		;NO
	JRST CNOGT2		;YES
CNOGT1:	DMOVE A,[EXP SAVFIL,<-1,,DIRECT>]
	GTJFN%			;GET HANDLE ON BACKUP FILE.
	 JSHLT			;COULDN'T EVEN DO THAT!
CNOGT2:	MOVEM A,SAVJFN		;SAVE THE BACKUP FILE JFN.
	JRST SAVST1		;GO BACK AND TRY THE OPENF AGAIN.
XLIST				;DON'T LIST LITERALS IN LISTING
LIT				;MAKE SURE LITERALS SAVER NEEDS ARE IN ITS MAP
LIST				;TURN LISTING BACK ON

RELOC .-140			;WE'RE NOT RELOCATABLE BUT OTHER MODULES MAY BE
.REQUIRE SYS:MACREL
;NOTE THAT ANY .REQUIRES THAT SAVER REFERENCES MUST BE CONTIGUOUS TO
;SAVER

SAVEND==.RLEND			;MARK END OF SAVER FORK

END <ENLEN,,GOGO>