	.TITLE	VIEW	A FILE ON A VT-100
	.ident	/V1E/
	.ENABL	LC

; Copyright (C) 1981 Berez Associates

; Mods are in lower case...

; Modified slightly to fix a VT100 reset bug
; Also to add some PRO300 support (cursor off/on)
; W. K. Walker / V1A; 18 Jun 84

; Mod to show formfeeds by default
; W. K. Walker / V1B; 28 Jun 84

; Mod to change VT100 setup sequence
; W. K. Walker / V1C; 01 Jul 84

; Mod to add on-line R, H, and X commands
; Also changed things so reset sequence on exit does not force
;   80 columns, normal video
; Made control-C work like Q (quit) command
; Changed help text slightly
; W. K. Walker / V1D; 03 Jul 84

; Added up-arrow (U command) and down-arrow (D) key support.
; PF2 (HELP key for KED and SL) works like H command.
; W. K. Walker / V1E; 06 Jul 84

	.MCALL	.EXIT,.TTYIN,.TTYOUT
	.MCALL	.PRINT,.CSIGEN,.SETTOP,.LOOKUP
	.MCALL	.WRITE,.READW,.WAIT,.QSET
	.mcall	.scca


;CONSTANTS
.iif ndf pc$300, pc$300 = 0	;PC$300 = 1 enables cursor on/off support
ERRBYT=	52			;ERROR CODE BYTE
JSW=	44			;JOB STATUS WORD
BUFTOP=	50			;TOP OF MEMORY
INCHAN=	3			;INPUT (FILE) CHANNEL
TTCHAN=	1			;OUTPUT (TERMINAL) CHANNEL
tcbit$	= 100			;FB, XM inhibit terminal wait bit
ttspc$	= 10000			;Special mode terminal bit

;CHARACTER DEFINITIONS
ESC=	33
TAB=	11
CR=	15
LF=	12
FF=	14
RUBOUT=	177
SPACE=	40
BELL=	7
EOF=	32
;MACROS

	;DISPLAY ERROR MESSAGE AND EXIT
.MACRO	ERROR	STR
	.CSECT	STRING
	$$$=.
	.ASCIZ	\STR\
	.CSECT	CODE
	JSR	R5,ERROR
	.WORD	$$$
.ENDM	ERROR

	;PUT A TERMINAL COMMAND IN OUTPUT BUFFER
.MACRO	COMAND	STR
	.CSECT	STRING
	$$$=.
	.ASCIZ	\STR\
	.CSECT	CODE
	JSR	R5,COMAND
	.WORD	$$$
.ENDM	COMAND
	.asect
. = jsw
	.word	ttspc$!tcbit$	;Puts console in "special mode"
. = 110
	.rad50	"V1E"		;Undocumented "tell 'em who we are" location

	.CSECT	DATA

AREA:	.BLKW	5		;USED BY RT MACROS
scca:	.word	0		;Terminal status word for .SCCA request
DEFTYP:	.RAD50	/LST/		;DEFAULT INPUT FILE TYPE
	.WORD	0,0,0
BUFBOT:	.WORD	BUFFER		;BOTTOM OF BUFFER, ABOVE HANDLERS
OBUF1:	0			;FIRST OUTPUT BUFFER LOCATION
OBUF2:	0			;SECOND OUTPUT BUFFER LOCATION
OBUFE:	0			;END OF SECOND BUFFER
OUTBUF:	0			;CURRENT OUTPUT BUFFER
OUTPTR:	0			;NEXT OUTPUT CHARACTER LOCATION
OBFEND:	0			;END OF CURRENT OUTPUT BUFFER
INBUF:	0			;INPUT BUFFER
IBFEND:	0			;END OF INPUT BUFFER
TTNAME:	.RAD50	/TT /		;TERMINAL NAME FOR .LOOKUP
	.WORD	0,0,0
WIDE:	0			;WIDE SCREEN OUTPUT?
REVVID:	0			;REVERSE VIDEO?
FORM:	1			;SHOW FORM-FEEDS? (ON by default)
CONTRL:	0			;SHOW CONTROL-CHARACTERS?
SPACES:	0			;SHOW SPACES?
WIDTH:	0			;LINE WIDTH
CURBLK:	-1			;FIRST INPUT FILE BLOCK IN CORE
INPTR:	0			;NEXT CHARACTER TO READ
EOFFLG:	0			;END-OF-FILE ON CURRENT PAGE?
DOWN:	1			;MOVING DOWN?
INVERS:	0			;IN INVERSE VIDEO MODE?
SPECS:	0			;IN SPECIAL CHARACTER SET MODE?
INLEN:	0			;INPUT BUFFER LENGTH IN WORDS
IBLKS:	0			;NUMBER OF BLOCKS IN BUFFER
LASTWD:	0			;LAST WORD POINTER
HPOS:	0			;HORIZONTAL POSITION TO START FIRST LINE
QADDR:	.BLKW	10.		;EXTRA QUEUE ELEMENT
	.CSECT	STRING
	.nlist	bex
TRMINI:	.ASCII	<esc>/[1;24r/<esc>/[H/<esc>/[J/<ESC>/</<ESC>/)0/
.if ne pc$300
	.ascii	<esc>/[?25l/	;Cursor off
.endc
	.byte	200
SETWID:	.ASCII	<ESC>/[?3h/<200> ;SET TERMINAL WIDTH TO 132
UNSWID:	.ASCII	<ESC>/[?3l/<200> ;RESET TERMINAL WIDTH TO 80
SETREV:	.ASCII	<ESC>/[?5h/<200> ;SET REVERSE VIDEO MODE
setnrm:	.ascii	<esc>/[?5l/<200> ;Set normal video mode
ERRMSG:	.ASCII	/?VIEW-F-/<200>	;ERROR MESSAGE HEADER
clrscn:	.ascii	<esc>/[H/<esc>/[J/ ;Home cursor, clear screen
TRESET:	.ASCII	<ESC>/[m/<17><ESC>/[q/ ;"Reset" terminal
.if ne pc$300
	.ascii	<esc>/[?25h/	;Cursor on
.endc
	.byte	200
HLPSTR:	.ascii	<esc>/[H/<esc>/[J/
	.ASCII	<esc>/[1mVIEW Switches:/<esc>/[0m/<CR><LF> ;HELP TEXT
	.ASCII	\	/W	Wide screen output\<CR><LF>
	.ASCII	\	/A	Show all characters\<CR><LF>
	.ASCII	\	/R	Reverse video\<CR><LF>
	.ASCII	\	/H	Help text\<CR><LF>
	.ASCII	<esc>\[1mVIEW Commands:\<esc>\[0m\<CR><LF>
	.ASCII	\	D	Move down file (or down-arrow key)\<CR><LF>
	.ASCII	\	U	Move up file (or up-arrow key)\<CR><LF>
	.ASCII	\	<space>	Next page\<CR><LF>
	.ASCII	\	1-9	Next n pages\<CR><LF>
	.ASCII	\	T	Top of file\<CR><LF>
	.ASCII	\	B	Bottom of file\<CR><LF>
	.ASCII	\	W	Toggle screen width\<CR><LF>
	.ASCII	\	F	Toggle form-feed mode\<CR><LF>
	.ASCII	\	C	Toggle controls mode\<CR><LF>
	.ASCII	\	S	Toggle spaces mode\<CR><LF>
	.ascii	\	R	Toggle video mode\<cr><lf>
	.ascii	\	H	Help text (or use PF2 key)\<cr><lf>
	.ASCII	\	Q	Quit (or X -- clear screen and quit)\<CR><LF>
.if eq pc$300
	.ASCII	<esc>\[1mVIEW Lights:\<esc>\[0m\<CR><LF>
	.ASCII	\	L1	Moving down\<CR><LF>
	.ASCII	\	L2	Moving up\<CR><LF>
.iff
	.ascii	<lf><esc>\[1m\
	.ascii	\(version for PC300 series computers)\<esc>\[0m\<cr><lf><lf>
.endc
	.ASCII	\Copyright (C) 1981  Berez Associates; \
	.ascii	<esc>\[1mV1E by WKW, July, 1984\<esc>\[0m\<200>
crlf:	.byte	0
	.list	bex
	.CSECT	CODE

	.ENABL	LSB
START::
	.CSIGEN	BUFBOT,#DEFTYP,#0 ;OPEN FILE TO BE VIEWED
	BCC	1$
	ERROR	<Input file open failed>
1$:	MOV	(SP)+,R1	;NUMBER OF SWITCHES ENTERED
	BEQ	8$		;NONE
2$:	MOV	(SP)+,R2	;GET NEXT SWITCH
	BPL	3$		;NO ARGUMENT?
	TST	(SP)+		;FLUSH ARGUMENT
3$:	CMPB	R2,#'W
	BNE	4$
	INC	WIDE		;USE WIDE SCREEN OUTPUT
	BR	7$
4$:	CMPB	R2,#'A		;SHOW ALL?
	BNE	5$
	INC	FORM		;SHOW FORM-FEEDS
	INC	CONTRL		;SHOW CONTROL-CHARACTERS
	INC	SPACES		;SHOW SPACES
	BR	7$
5$:	CMPB	R2,#'H
	BNE	6$
	.PRINT	#HLPSTR		;SHOW HELP TEXT
	JMP	EXIT		;AND EXIT
6$:	CMPB	R2,#'R
	BNE	7$
	INC	REVVID		;USE REVERSE VIDEO
7$:	SOB	R1,2$
8$:	MOV	R0,BUFBOT	;FIRST WORD AFTER HANDLER, IF ANY
	.QSET	#QADDR,#1	;GET AN EXTRA QUEUE ELEMENT
	.LOOKUP	#AREA,#TTCHAN,#TTNAME ;OPEN CHANNEL TO TERMINAL
	BCC	RESTRT
	ERROR	<Terminal open failed>
RESTRT:	MOV	#80.*24.+1500.,R1 ;OUTPUT BUFFER SIZE, ASSUMING NARROW LINES
	MOV	#80.,WIDTH	;LINE WIDTH
	TST	WIDE		;WIDE LINES DESIRED?
	BEQ	9$		;NO
	MOV	#132.*24.+1500.,R1 ;YES, MODIFY EARLIER ASSUMPTION
	MOV	#132.,WIDTH	;CHANGE THIS, TOO
9$:	MOV	BUFBOT,R2	;BEGINNING OF AVAILABLE BUFFER SPACE
	MOV	R2,OBUF1	;PUT FIRST OUTPUT BUFFER HERE
	ADD	R1,R2		;ADD BUFFER SIZE
	MOV	R2,OBUF2	;SECOND OUTPUT BUFFER FOLLOWS FIRST
	ADD	R1,R2
	MOV	R2,OBUFE	;END OF OUTPUT BUFFERS
	MOV	OBUF1,OUTBUF	;SELECT FIRST BUFFER FIRST
	MOV	OBUF2,OBFEND
	DEC	R2		;ROUND UP TO BLOCK BOUNDARY FOR CONVENIENCE
	BIC	#777,R2
	ADD	#1000,R2
	MOV	R2,INBUF	;START INPUT BUFFER HERE
	ADD	#14000,R2	;ALLOW ROOM FOR INPUT BUFFER AND DATA STACK
	SUB	#2,R2		;POINT TO LAST DESIRED WORD
	.SETTOP	R2		;TRY TO GET THE MEMORY
	MOV	R0,R5		;LAST AVAILABLE LOCATION
	SUB	#4000,R0	;RESERVE SPACE FOR PAGE STACK (POINTER IN R5)
	BIC	#777,R0		;ROUND DOWN TO BLOCK BOUNDARY
	MOV	R0,IBFEND	;END OF INPUT BUFFER
	SUB	INBUF,R0	;SIZE OF INPUT BUFFER
	BHI	10$		;MUST BE POSITIVE
	ERROR	<Insufficient memory>
10$:	ASR	R0
	MOV	R0,INLEN	;SAVE LENGTH IN WORDS
	SWAB	R0
	MOV	R0,IBLKS	;SAVE NUMBER OF BLOCKS
11$:	.PRINT	#TRMINI		;INITIALIZE TERMINAL (ANSI MODE & CHAR SET)
	TST	WIDE		;WIDE OUTPUT?
	BEQ	12$		;NO
	.PRINT	#SETWID		;YES, SET TERMINAL WIDTH
12$:	TST	REVVID		;REVERSE VIDEO?
	BEQ	13$		;NO
	.PRINT	#SETREV		;YES, SELECT IT
13$:	CLR	-(R5)		;SET UP POINTERS FOR FIRST PAGE
	MOV	INBUF,-(R5)
	CLR	-(R5)
	.scca	#area,#scca	;Turn off ^C
	.DSABL	LSB
	.ENABL	LSB
NEWPAG:	JSR	PC,SETPTR	;POINT TO PAGE IN INPUT FILE
	ADD	#6,R5		;CLEAN UP STACK
1$:	JSR	PC,GETPAG	;GET (FORMAT) NEXT OUTPUT PAGE
2$:	JSR	PC,OUTPAG	;QUEUE THE PAGE FOR OUTPUT
3$:	JSR	PC,GETPAG	;GET THE NEXT ONE WHILE LAST ONE PRINTS
4$:	call	ttnesc		;GET COMMAND FROM USER
	CMP	R0,#SPACE	;SPACE MEANS NEXT PAGE
	BEQ	2$
	CMP	R0,#'1		;1 IS SAME AS SPACE
	BEQ	2$
	CMP	R0,#'D		;D MEANS SWITCH TO DOWN MODE & NEXT PAGE
	BNE	5$
	TST	DOWN		;ALREADY IN D MODE?
	BNE	2$		;YES, ACT LIKE SPACE
	INC	DOWN		;NO, SET MODE & GET PROPER PAGE
	SUB	#6,R5		;POINT TO PROPER PAGE (PRINTED PREVIOUSLY)
	BR	NEWPAG		;SET THE POINTER
5$:	CMP	R0,#'U		;U MEANS SWITCH TO UP MODE & NEXT PAGE
	BNE	6$
	TST	DOWN		;ALREADY IN U MODE?
	BEQ	2$		;YES, ACT LIKE SPACE
	CLR	DOWN		;NO, SET MODE & GET PROPER PAGE
	BR	1$
6$:	CMP	R0,#'T		;T MEANS TOP OF FILE
	BNE	7$
GOTOP:	MOV	@#BUFTOP,R5	;RESET STACK TO BEGINNING OF FILE
	SUB	#6,R5
	INC	DOWN		;MAKE SURE WE'RE IN DOWN MODE
	CLR	EOFFLG		;NO LONGER AT EOF, EITHER
	BR	NEWPAG		;GET FIRST PAGE
7$:	CMP	R0,#'B		;B MEANS BOTTOM OF FILE
	BNE	9$
	TST	DOWN		;ALREADY GOING DOWN?
	BNE	8$		;YES
	INC	DOWN		;NO, CHANGE DIRECTION
	SUB	#6,R5		;AND POINT TO PROPER FILE POSITION
	JSR	PC,SETPTR
	ADD	#6,R5
8$:	JSR	PC,GETPAG
	TST	EOFFLG
	BEQ	8$		;SKIP PAGES UNTIL END OF FILE
	JSR	PC,OUTPAG	;PRINT THE PAGE
	JSR	PC,GETPAG	;ONE MORE FOR GOOD MEASURE
	CLR	DOWN		;NOW SWITCH TO UP MODE
	BR	3$		;AND GET NEXT USER COMMAND
9$:	CMP	R0,#'W		;W MEANS TOGGLE SCREEN WIDTH
	BNE	12$
	INC	DOWN		;SET PROPER STATE
	CLR	EOFFLG
	TST	WIDE		;ALREADY WIDE?
	BEQ	10$
	CLR	WIDE		;YES, CLEAR IT
	.PRINT	#UNSWID		;CHANGE TERMINAL WIDTH BACK TO NORMAL
	BR	11$
10$:	INC	WIDE		;NO, SET IT
11$:	MOV	#-1,CURBLK	;FORGET BLOCKS READ
	JMP	RESTRT		;MUST RESTART TO CHANGE SCREEN WIDTH
12$:	CMP	R0,#'F		;F MEANS TOGGLE FORM MODE
	BNE	14$
	TST	FORM		;ALREADY SET?
	BEQ	13$
	CLR	FORM		;YES, CLEAR IT
	BR	GOTOP		;AND GO TO TOP OF FILE
13$:	INC	FORM		;NO, SET IT
	BR	GOTOP		;ETC.
14$:	CMP	R0,#'C		;C MEANS TOGGLE CONTROL MODE
	BNE	16$
	TST	CONTRL		;ALREADY SET?
	BEQ	15$
	CLR	CONTRL		;YES, CLEAR IT
	BR	GOTOP		;AND GO TO TOP OF FILE
15$:	INC	CONTRL		;NO, SET IT
	BR	GOTOP		;ETC.
16$:	CMP	R0,#'S		;S MEANS TOGGLE SPACES MODE
	BNE	18$
	TST	SPACES		;ALREADY SET?
	BEQ	17$
	CLR	SPACES		;YES, CLEAR IT
	BR	GOTOP		;AND GO TO TOP OF FILE
17$:	INC	SPACES		;NO, SET IT
	BR	GOTOP		;ETC.
18$:	CMP	R0,#'Q		;Q MEANS QUIT
	BNE	19$
	JMP	EXIT
19$:	CMP	R0,#'2		;DIGIT 2-9?
	BLT	26$
	CMP	R0,#'9
	BGT	22$
	SUB	#'1,R0		;NUMBER OF EXTRA PAGES TO SKIP
	MOV	@#BUFTOP,R1
	SUB	#12.,R1		;TOP-OF-STACK FOR COMPARISON
20$:	MOV	R0,-(SP)
	JSR	PC,GETPAG	;SKIP A PAGE
	MOV	(SP)+,R0
	CMP	R5,R1		;AT BEGINNING OF FILE?
	BEQ	21$		;YES, STOP HERE
	TST	EOFFLG		;AT END OF FILE?
	BNE	21$		;YES, STOP HERE
	SOB	R0,20$		;SKIP N-1 PAGES
21$:	JMP	2$		;SHOW N'TH PAGE
22$:	cmpb	r0,#'R		;Toggle video?
	bne	24$		;Branch if not
	tst	revvid		;Already reversed?
	bne	23$		;Branch if so
	inc	revvid		;Set reverse video flag
	.print	#setrev		; and do it
	jmp	4$		;Go get next character
23$:	clr	revvid		;Clear reverse video flag
	.print	#setnrm		;Make screen normal
	jmp	4$		;Go get next character
24$:	cmpb	r0,#'X		;Clear screen and quit?...
	bne	25$
	.print	#clrscn		;Clear the screen and
	jmp	exit0		; go quit
25$:	cmpb	r0,#'H		;Print help text?
	bne	26$		;Branch if not
	.print	#hlpstr		;Do it...
	.print	#crlf
	jmp	4$
26$:	cmpb	r0,#3		;Control-C?...
	bne	27$
	jmp	exit		;Go quit if so
27$:
	.TTYOUT	#BELL		;FEEP & GET ANOTHER CHARACTER
	JMP	4$
	.DSABL	LSB
; Get a character or escape sequence from user.
; Escape sequences translate as follows:
;
;	  KEY		SEQUENCE	COMMAND
;	up-arrow	<esc>[A		   U
;	down-arrow	<esc>[B		   D
;	PF2		<esc>OQ		   H

ttnesc::
	.ttyin			;Get a character
	cmpb	r0,#esc		;Escape?
	beq	10$		;Branch if so
	return			;Just return otherwise

10$:	.ttyin			;Get a character
	cmpb	r0,#'[		;Possible arrow key?...
	bne	40$
	.ttyin			;Get a character
	cmpb	r0,#'A		;Up-arrow?...
	bne	20$
	movb	#'U,r0		;Make it a U...
	return
20$:	cmpb	r0,#'B		;Down-arrow?...
	bne	30$
	movb	#'D,r0		;Make it a D...
	return

30$:	clr	r0		;Return with obvious garbage in R0...
	return

40$:	cmpb	r0,#'O		;Possible PF2 key?
	bne	30$		;Nope
	.ttyin			;Get next character
	cmpb	r0,#'Q		;Is it a Q...
	bne	30$
	movb	#'H,r0		;Make it an H...
	return
	;GET (FORMAT) NEXT OUTPUT PAGE
	.ENABL	LSB
GETPAG:	MOV	OUTBUF,R2	;GET OUTPUT POINTER
	COMAND	<[H>		;TOP OF SCREEN
	COMAND	<[q>		;CLEAR LIGHTS
	TST	DOWN		;PAGING DOWN?
	BEQ	PGUP		;NO
	TST	EOFFLG		;ARE WE AT END OF FILE?
	BEQ	PGDOWN		;NO
	BMI	1$		;YES, BUT WE'VE ALREADY BEEN HERE
	NEG	EOFFLG		;REMEMBER THAT WE WERE HERE
	SUB	#6,R5		;SET STACK IN CASE WE BACK UP FROM HERE
	CLR	OUTPTR		;SET FLAG FOR OUTPAG
1$:	RTS	PC
PGDOWN:	COMAND	<[1q>		;PAGING DOWN, TURN ON LIGHT 1
	MOV	CURBLK,-(R5)	;SAVE CURRENT BLOCK NUMBER
	MOV	INPTR,-(R5)	;ALSO SAVE CHARACTER POINTER
	MOV	HPOS,R3		;GET HORIZONTAL POSITION FROM LAST PAGE
	MOV	R3,-(R5)	;SAVE IT, TOO
	CMP	R5,IBFEND	;CHECK FOR STACK OVERFLOW
	BHIS	PGBEG		;NO OVERFLOW
	ERROR	<Too many pages>
PGUP:	COMAND	<[2q>		;PAGING UP, TURN ON LIGHT 2
	ADD	#12.,R5		;POP OFF CURRENT PAGE POINTERS (ONE UNPRINTED)
	CMP	R5,@#BUFTOP	;WAS THIS THE FIRST PAGE?
	BLO	3$		;NO
	BNE	2$		;FIRST TIME BACK TO FIRST PAGE?
	ADD	#6,R5		;YES, SET UP POINTER FOR DOWN MOTION
2$:	SUB	#12.,R5		;NO, LEAVE PAGE STACK UNCHANGED
	MOVB	#7,(R2)+	;IF AT FIRST PAGE, SIMPLY FEEP AT USER
	JMP	PDONE1		;AND RETURN
3$:	CLR	EOFFLG		;IF WE WERE AT EOF, WE AREN'T ANYMORE
	JSR	PC,SETPTR	;SET THE INPUT POINTER FOR THIS PAGE
	MOV	(R5),R3		;GET PROPER HPOS FOR THIS PAGE
	SUB	#6,R5		;RESTORE POINTER FOR NEXT PAGE
PGBEG:	CLR	INVERS		;EXIT ANY SPECIAL MODES
	COMAND	<[m>		;NON-INVERTED MODE
	CLR	SPECS
	MOVB	#17,(R2)+	;NON-SPECIAL CHARACTER MODE
	CLR	R4		;INITIALIZE LINE COUNTER
	TST	R3		;START AT BEGINNING OF LINE?
	BEQ	NXTLIN		;YES
	COMAND	<[>		;NO, MOVE CURSOR
	MOV	R3,R0
	JSR	PC,PUTNUM	;PUT POSITION NUMBER IN BUFFER
	MOVB	#'C,(R2)+	;MOVE CURSOR RIGHT
NXTLIN:	COMAND	<[2K>		;START LINE CLEAR
NXTCHR:	JSR	PC,GETCHR	;GET A CHARACTER FROM FILE
	 BR	EOF0		;NO MORE CHARACTERS
	BR	NXTCH1
EOF0:	JMP	GOTEOF
NXTCH1:	TST	R0
	BEQ	NXTCHR		;IGNORE NULLS
	CMP	R0,#RUBOUT	;RUBOUT IS ALWAYS HANDLED SPECIALLY
	BNE	4$
	MOV	#'?,R0
	BR	CTRL
4$:	CMP	R0,#SPACE	;CONTROL CHARACTER OR SPACE?
	BGT	OUTCHR		;NO, DO NOTHING SPECIAL
	BLT	5$		;CONTROL CHARACTER
	TST	SPACES		;SPACE, SHOW SPACES?
	BEQ	OUTCHR		;NO
	MOV	#176,R0		;YES, DISPLAY SYMBOL
	BR	SPECCH
5$:	CMP	R0,#TAB		;TAB?
	BNE	7$		;NO
	TST	CONTRL		;YES, SHOW CONTROLS?
	BEQ	6$		;NO, HANDLE CURSOR MOVEMENT
	MOV	#'b,R0		;YES, DISPLAY HORIZONTAL TAB SYMBOL
	BR	SCTRL
6$:	BIC	#7,R3		;UPDATE HPOS
	ADD	#10,R3
	BR	IMAGE
7$:	CMP	R0,#BELL	;BELL?
	BNE	8$		;NO
	TST	CONTRL		;SHOW CONTROLS?
	BEQ	IMAGE		;NO, DISPLAY WITH NO CURSOR MOVEMENT
	BR	CTRL0		;YES, SHOW IT
8$:	CMP	R0,#CR		;CARRIAGE RETURN?
	BNE	11$		;NO
	TST	CONTRL		;SHOW CONTROLS?
	BEQ	10$		;NO, HANDLE NORMALLY
	JSR	PC,GETCHR	;YES, SEE IF NEXT CHARACTER IS A LF
	BR	GOTEOF		;END OF FILE
	CMP	R0,#LF		;WELL?
	BEQ	9$		;YES, JUST PROCESS BOTH NORMALLY
	DEC	INPTR		;NO, UNREAD IT
	MOV	#'d,R0		;AND SHOW CR
	BR	SCTRL
9$:	MOVB	#CR,(R2)+	;BUFFER THE CR
	CLR	R3		;CURSOR RETURNS TO BEGINNING OF LINE
	BR	22$		;AND LINE IS ENDED
10$:	CLR	R3		;CURSOR RETURNS TO BEGINNING OF LINE
	BR	IMAGE
11$:	CMP	R0,#LF		;LINE FEED?
	BNE	12$		;NO
	TST	CONTRL		;YES, SHOW CONTROLS?
	BEQ	22$		;NO, NORMAL END OF LINE
	MOV	#'e,R0		;YES, THIS MUST BE A NAKED LF
	BR	SCTRL
12$:	CMP	R0,#FF		;FORM FEED?
	BNE	13$		;NO
	TST	FORM		;YES, SHOW FORM FEEDS?
	BEQ	PDONE		;NO, END OF PAGE
	MOV	#'c,R0		;YES, USE FORM FEED SYMBOL
	BR	SCTRL
13$:	CMP	R0,#ESC		;ESCAPE PRINTED AS DIAMOND
	BNE	CTRL0
	MOV	#'`,R0
	BR	SPECCH
CTRL0:	BIS	#100,R0		;USE CORRESPONDING ALPHA CHARACTER
CTRL:	TST	INVERS		;ALREADY IN INVERSE MODE?
	BNE	OUTCH1		;YES
	INC	INVERS		;NO, ENTER IT
	COMAND	<[7m>		;INVERSE VIDEO MODE
14$:	BR	OUTCH1		;NOW DISPLAY CHARACTER
SCTRL:	TST	INVERS		;ALREADY IN INVERSE MODE?
	BNE	15$		;YES
	INC	INVERS		;NO, ENTER IT
	COMAND	<[7m>		;INVERSE VIDEO MODE
	BR	15$
SPECCH:	TST	INVERS		;ARE WE IN INVERSE MODE?
	BEQ	15$		;NO
	CLR	INVERS		;YES, CLEAR IT
	COMAND	<[m>		;NON-INVERTED MODE
15$:	TST	SPECS		;ALREADY IN SPECIAL SET?
	BNE	16$		;YES
	INC	SPECS		;NO, SELECT SPECIAL SET
	MOVB	#16,(R2)+
16$:	MOVB	R0,(R2)+	;DISPLAY CHARACTER
17$:	INC	R3		;ALL OF THIS TAKES ONE POSITION
	BR	19$
OUTCHR:	TST	INVERS		;ARE WE IN INVERSE MODE?
	BEQ	18$		;NO
	CLR	INVERS		;YES, CLEAR IT
	COMAND	<[m>		;NON-INVERTED MODE
18$:	TST	SPECS		;ARE WE IN SPECIAL SET?
	BEQ	OUTCH1		;NO
	CLR	SPECS		;YES, CLEAR IT
	MOVB	#17,(R2)+
OUTCH1:	INC	R3		;BUMP HPOS FOR NORMAL CHARACTERS
IMAGE:	MOVB	R0,(R2)+	;TRANSFER CHARACTER TO OUTPUT BUFFER
19$:	CMP	R3,WIDTH	;END OF LINE?
	BGE	20$		;YES
	JMP	NXTCHR		;NO, CONTINUE GETTING CHARACTERS
20$:	JSR	PC,GETCHR	;YES, SEE IF NEXT CHARACTER IS A CR
	BR	GOTEOF		;END OF FILE
	CMP	R0,#CR		;WELL?
	BNE	21$		;NO
	JMP	NXTCH1		;YES, JUST PROCESS IT NORMALLY
21$:	DEC	INPTR		;NO, UNREAD IT
	MOVB	#CR,(R2)+	;SIMULATE A CARRIAGE RETURN & LINE FEED
	CLR	R3
22$:	INC	R4		;BUMP LINE COUNTER
	CMP	R4,#24.		;END OF PAGE?
	BEQ	PDONE1		;YES
	MOVB	#LF,(R2)+	;NO, OUTPUT THE LF
	JMP	NXTLIN		;AND CONTINUE
GOTEOF:	INC	EOFFLG		;END OF FILE, SET THE FLAG
PDONE:	COMAND	<[J>		;CLEAR REST OF PAGE
PDONE1:	MOV	R2,OUTPTR	;SAVE UPDATED OUTPUT POINTER
	MOV	R3,HPOS		;AND UPDATED HORIZONTAL POSITION
	RTS	PC
	.DSABL	LSB

	;OUTPUT A PAGE TO THE TERMINAL
	.ENABL	LSB
OUTPAG:	TST	OUTPTR		;END OF FILE?
	BNE	1$		;NO
	.TTYOUT	#BELL		;YES, JUST FEEP
	RTS	PC		;AND RETURN
1$:	.WAIT	#TTCHAN		;ENSURE THAT PREVIOUS OUTPUT IS COMPLETE
	BCS	4$		;ERROR
	MOV	OUTPTR,R1	;GET CURRENT OUTPUT POINTER
	CMP	R1,OBFEND	;PAST LEGAL END OF BUFFER?
	BLOS	2$		;NO
	ERROR	<Output buffer overflow>
2$:	SUB	OUTBUF,R1	;NUMBER OF BYTES TO OUTPUT
	ROR	R1		;CONVERT TO WORDS
	BCC	3$		;NOT ODD
	INC	R1		;ODD, INCREMENT WORD COUNT
	CLRB	@OUTPTR		;ZERO EXTRA CHARACTER
3$:	.WRITE	#AREA,#TTCHAN,OUTBUF,R1,#0 ;TRANSFER CHARACTERS
	BCC	5$
4$:	ERROR	<Terminal output failed>
5$:	CMP	OUTBUF,OBUF1	;WAS THIS BUFFER 1?
	BNE	6$		;NO
	MOV	OBUF2,OUTBUF	;YES, USE BUFFER 2 NEXT
	MOV	OBUFE,OBFEND
	BR	7$
6$:	MOV	OBUF1,OUTBUF	;WAS BUFFER 2, SWITCH TO BUFFER 1
	MOV	OBUF2,OBFEND
7$:	MOV	OUTBUF,OUTPTR	;RESET OUTPUT POINTER
	RTS	PC
	.DSABL	LSB

	;PUT A TERMINAL COMMAND IN OUTPUT BUFFER
COMAND:	MOVB	#ESC,(R2)+	;COMMANDS START WITH AN ESCAPE
	MOV	R0,-(SP)
	MOV	R1,-(SP)
	MOV	(R5)+,R1	;STRING TO TRANSFER
1$:	MOVB	(R1)+,R0	;NEXT CHARACTER
	BEQ	2$		;END OF STRING
	MOVB	R0,(R2)+	;TRANSFER IT
	BR	1$		;LOOP
2$:	MOV	(SP)+,R1
	MOV	(SP)+,R0
	RTS	R5

	;DECODE NUMBER IN R0 AND TRANSFER IT TO OUTPUT BUFFER
PUTNUM:	CMP	R0,#100.	;AT LEAST 100?
	BLT	1$		;NO
	SUB	#100.,R0	;YES, OUTPUT LEADING 1
	MOVB	#'1,(R2)+
1$:	MOV	R1,-(SP)
	CMP	R0,#10.		;AT LEAST 10?
	BLT	3$		;NO
	MOV	#'0-1,R1	;YES, DIVIDE BY 10
2$:	INC	R1
	SUB	#10.,R0
	BGE	2$
	ADD	#10.,R0
	MOVB	R1,(R2)+	;OUTPUT TENS DIGIT
3$:	ADD	#'0,R0		;OUTPUT ONES DIGIT
	MOVB	R0,(R2)+
	MOV	(SP)+,R1
	RTS	PC
	;SET INPUT POINTER TO PROPER FILE POSITION (FROM R5 STACK)
SETPTR:	CMP	4(R5),CURBLK	;PROPER BLOCK ALREADY IN CORE?
	BEQ	1$		;YES
	MOV	4(R5),CURBLK	;NO, GET IT
	JSR	PC,SETBLK
1$:	MOV	2(R5),INPTR	;RESET INPUT POINTER
	MOV	(R5),HPOS	;AND HORIZONTAL POSITION
	RTS	PC

	;SET CURRENT BLOCK
	.ENABL	LSB
SETBLK:	.READW	#AREA,#INCHAN,INBUF,INLEN,CURBLK ;READ PROPER AREA INTO CORE
	BCC	1$
	TSTB	@#ERRBYT	;END OF FILE?
	BEQ	1$		;YES, DON'T WORRY
	ERROR	<File input failed>
1$:	ASL	R0		;NUMBER OF BYTES TRANSFERED
	ADD	INBUF,R0	;FIND LASTWD (ACTUALLY, NEXT WORD AFTER LAST)
	MOV	R0,LASTWD	;SAVE IT
	RTS	PC
	.DSABL	LSB

	;GET A CHARACTER FROM INPUT BUFFER, SKIP ON SUCCESS
GETCHR:	CMP	INPTR,IBFEND	;AT END OF BUFFER?
	BNE	1$		;NO
	ADD	IBLKS,CURBLK	;CALCULATE NEXT BLOCK TO READ
	JSR	PC,SETBLK	;GET IT
	MOV	INBUF,INPTR	;RESET INPUT POINTER
1$:	CMP	INPTR,LASTWD	;AT END OF FILE?
	BEQ	2$		;YES, FAILURE RETURN
	MOVB	@INPTR,R0	;NO, TRANSFER A CHARACTER
	INC	INPTR		;UPDATE POINTER
	ADD	#2,(SP)		;SUCCESSFUL RETURN
2$:	RTS	PC

	;ERROR HANDLER
ERROR:	.PRINT	#TRESET		;RESET TERMINAL
	.PRINT	#ERRMSG		;PRINT MESSAGE HEADER
	.PRINT	(R5)		;ACTUAL MESSAGE

	;NORMAL EXIT AND ERROR ENTRY
EXIT:	.PRINT	#TRESET		;RESET TERMINAL
exit0:	.scca	#area,#0	;Turn ^C back on
	.EXIT			;QUIT

	;BEGINNING OF BUFFER AREA ABOVE PROGRAM
BUFFER:

	.END	START
