Google
 

Trailing-Edge - PDP-10 Archives - bb-m836c-bm_tops20_v6_1_tools - tools/sysdpy/dpy.mac
There are 24 other files named dpy.mac in the archive. Click here to see a list.
;TCO 6.1.1427 - Add definitions for VT200.
; UPD ID= 8, SNARK:<6.TOOLS-TAPE>DPY.MAC.2,  14-Dec-82 13:42:07 by PAETZOLD
;TCO 6.1415 - Add definitions for VT102 and VT125

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT  (C)  DIGITAL  EQUIPMENT  CORPORATION  1976, 1985.
;ALL RIGHTS RESERVED.

	TITLE	DPY	MODULE TO MAKE CRT DISPLAYS EASY
	SUBTTL	DEFINITIONS

;THIS MODULE IS USED TO PRODUCE A CONSTANTLY UPDATING DISPLAY.
;COMMUNICATION BETWEEN IT AND THE CALLING PROGRAM IS BY LUUOS.  THIS
;MODULE CAN RUN ON VARIOUS KINDS OF TERMINALS.  THE FILE DPYDEF.MAC
;CONTAINS ALL OF THE NECESSARY DEFINITIONS.



	TWOSEG	400000		;ALWAYS MAKE PROGRAM TWO SEGMENTS
	SALL			;MAKE GOOD LOOKING MACROS
	ENTRY	DPYUUO		;DEFINE ENTRY POINT
	INTERN	DPYTAB		;AND THE TABLE
	SEARCH	DPYDEF		;GET BIT DEFINITIONS



	VERSION==3		;THIRD VERSION OF DPY
	EDIT==171		;EDIT NUMBER


	IFNDEF	FTDEC20,<FTDEC20==1>	;ON FOR TOPS-20, OFF FOR TOPS-10



	DEFINE	IF10,<IFE FTDEC20>	;SHORTHAND CONDITIONALS
	DEFINE	IF20,<IFN FTDEC20>



	IF10,<	SEARCH	UUOSYM	>	;IF TOPS-10, GET SYMBOLS
	IF20,<	SEARCH	MONSYM	>	;IF TOPS-20, GET SYMBOLS
	SUBTTL	ACCUMULATORS AND FLAGS




;ACCUMULATORS.  THE USER AC'S ARE ALWAYS PRESERVED.  AC "U" IS ASSUMED
;TO BE THE LAST NON-STACK AC ALWAYS.  IF ANOTHER AC IS EVER DEFINED,
;THEN ALSO CHANGE THE AC SAVING AREAS AT THE END OF THE PROGRAM.


	F=0		;FLAG BITS
	T1=1		;TEMPORARY USE
	T2=2
	T3=3
	T4=4
	X=5		;INDEX TO DATA TABLE
	C=6		;CHARACTER HOLDING
	A=7		;USER'S LUUO AND ADDRESS TO GET WORDS FROM
	L=10		;PRESENT LINE NUMBER BEING OUTPUT TO
	N=11		;PRESENT COLUMN NUMBER BEING OUTPUT TO
	B=12		;BYTE POINTER INTO SCREEN ARRAY
	U=13		;ADDRESS OF TERMINAL BLOCK
	P=17		;STACK POINTER



;FLAGS IN RIGHT HALF OF AC F.  ALL OF THESE BITS ARE TERMINAL
;CHARACTERISTIC FLAGS, SET WHEN INITIALIZING THE TERMINAL TYPE.


	FR.XBY==1	;IN ADDRESSING, X COORDINATE GOES BEFORE Y
	FR.TAB==2	;TERMINAL HAS NORMAL TAB STOPS
	FR.ELC==4	;TERMINAL DOES CRLF WHEN LAST COLUMN IS REACHED
	FR.RAI==10	;LOWER CASE IS SAME AS UPPER CASE
	FR.ANS==20	;THIS IS AN ANSI STANDARD TERMINAL
	FR.TTY==40	;THIS IS A NON-VIDEO TERMINAL


;FLAGS IN THE LEFT HALF OF AC F.  THESE BITS ARE STATUS BITS.


	FL.OUT==1	;THERE HAS BEEN OUTPUT IN CURRENT WINDOW
	FL.PNT==2	;TERMINAL NEEDS TO HAVE OUTPUT FORCED LATER
	FL.ACR==4	;WE ARE IN AUTO-CARRIAGE RETURN MODE
	FL.AC2==10	;SAME AS FL.ACR, BUT TEMPORARY
	FL.INI==20	;INI$ FUNCTION HAS BEEN DONE
	FL.OKU==40	;IT IS OK TO UPDATE THE SAME LOCATION TWICE
	FL.NZP==100	;DON'T CLEAR REST OF WINDOWS
	FL.NOS==200	;DON'T SAVE USER ACS WHEN GIVING CHARS TO HIM
;USEFUL CHARACTER DEFINITIONS:


	LF==12			;LINE FEED
	CR==15			;CARRIAGE RETURN
	TAB==11			;TAB
	ALT==33			;STANDARD ALTMODE
	SP==40			;SPACE
	RUB==177		;RUBOUT
	NUL==0			;NULL



;OTHER DEFINITIONS:



	DEFINE	CL(CHAR),<"CHAR"-100>	;TO DEFINE CONTROL CHARACTERS
	OPDEF	PJRST	[JRST]		;USUAL


	TTYLEN==^D20		;SIZE OF TERMINAL BUFFER
	UPDATE==200		;FLAG MEANING CHARACTER NEEDS UPDATING
	PRETTY==3		;NUMBER OF CHARS EXTRA FOR GOOD LOOKS
	DFTTRM==.ASR33		;DEFAULT TERMINAL TYPE
	SUBTTL	MACRO USED TO DEFINE TERMINAL TYPES



;THE FOLLOWING MACRO IS USED TO DEFINE THE PARAMETERS OF EACH TERMINAL
;WHICH WE CAN RUN ON.  IT EXPANDS INTO A BLOCK OF WORDS WHICH CONTAIN
;THE CONSTANTS APPLICABLE TO EACH PARTICULAR TERMINAL.


DEFINE	TTY(NAME,TYP10,TYP20,LENGTH,WIDTH,FLAGS,MAXCHR,EATCHR,LFTSEQ,
RHTSEQ,UPSEQ,DWNSEQ,CRSEQ,HOMSEQ,CLRSEQ,EOLSEQ,EOFSEQ,ADRSEQ,AD2SEQ,
AD3SEQ,XOFFV,YOFFV),<


.'NAME:	ADDR==.				;;DEFINE DATA BLOCK ADDRESS

XX	TYP,<TYPNUM TYP10,TYP20>	;;TERMINAL TYPE NUMBER
XX	FLAG,<FLG <FLAGS>>		;;FLAGS
XX	LEN,<DFT ^D<LENGTH-1>,^D23>	;;LENGTH OF SCREEN

	IFG <VAL+1-MAXLEN>,<MAXLEN==VAL+1>	;;REMEMBER NEW MAX
	VAL2==VAL+1			;;REMEMBER VALUE

XX	WID,<DFT ^D<WIDTH-1>,^D79>	;;WIDTH OF SCREEN

	VAL==<VAL+4>/4			;;GET WORDS PER LINE

XX	WRDS,<EXP VAL>			;;NUMBER OF WORDS PER LINE

	IFG <VAL-MAXWID>,<MAXWID==VAL>	;;REMEMBER NEW MAX
	VAL==VAL*VAL2			;;COMPUTE STORAGE NEEDED
	IFG <VAL-MAXARE>,<MAXARE==VAL>	;REMEMBER NEW MAX

XX	MAXC,<DFT MAXCHR,176>	;;HIGHEST PRINTING CHARACTER
XX	EATC,<DFT EATCHR," ">	;;CHAR WHICH EATS
XX	LEFT,SEQ <LFTSEQ>	;;SEQUENCE TO MOVE LEFT
XX	RHT,SEQ <RHTSEQ>	;;SEQUENCE TO MOVE RIGHT
XX	UP,SEQ <UPSEQ>		;;SEQUENCE TO MOVE UP
XX	DOWN,SEQ <DWNSEQ>	;;SEQUENCE TO MOVE DOWN
XX	CR,SEQ <CRSEQ>		;;SEQ TO DO A CARRIAGE RETURN
XX	HOM,SEQ <HOMSEQ>	;;SEQUENCE TO HOME UP
XX	CLR,SEQ <CLRSEQ>	;;SEQUENCE TO HOME UP AND CLEAR
XX	EOL,SEQ <EOLSEQ>	;;SEQUENCE TO ERASE END OF LINE
XX	EOF,SEQ <EOFSEQ>	;;SEQUENCE TO ERASE END OF FORM
XX	ADR,SEQ <ADRSEQ>	;;SEQUENCE TO START ADDRESSING
XX	ADR2,SEQ <AD2SEQ>	;;SEQUENCE FOR FILLS BETWEEN X AND Y
XX	ADR3,SEQ <AD3SEQ>	;;SEQUENCE FOR FILLS AFTER ADDRESSING
XX	XOFF,<DFT XOFFV,40>	;;OFFSET FOR X COORDINATE
XX	YOFF,<DFT YOFFV,40>	;;OFFSET FOR Y COORDINATE

	APPEND	<	XWD	[ASCIZ/NAME/],.'NAME
>				;;ADD THIS TERMINAL TO CONCATENATED TEXT
>
;DEFINITION OF EMBEDDED XX MACRO.  FIRST ARGUMENT DEFINES THE
;OFFSET INTO THE BLOCK.  SECOND ARGUMENT DEFINES THE DATA FOR
;THIS LOCATION.


DEFINE XX(OFFSET,DATA),<

	T.'OFFSET==.-ADDR	;;DEFINE OFFSET INTO BLOCK
	DATA			;;THEN STORE THE DATA
>


;NOW DEFINE THE IMBEDDED DFT MACRO, TO GENERATE AN OCTAL WORD.
;THE FIRST ARGUMENT IS THE SYMBOL NAME, THE SECOND ARGUMENT IS
;THE DEFAULT VALUE IF NO SYMBOL WAS GIVEN.  THE SYMBOL VAL IS
;DEFINED AS THE RESULT OF THE MACRO.



DEFINE DFT(SYMBOL,VALUE),<

	VAL==VALUE		;;FIRST USE THE DEFAULT VALUE

  IFNB <SYMBOL>,<		;;IF A SYMBOL WAS GIVEN
	VAL==SYMBOL		;;THEN USE IT INSTEAD
  >
	EXP	VAL		;;THEN DUMP THE VALUE
>
;NOW DEFINE THE IMBEDDED FLG MACRO, TO GENERATE THE FLAG BITS
;FOR THE TERMINAL.  IT TAKES ONE ARGUMENT, MADE UP OF A SEQUENCE
;OF FLAGS.


DEFINE FLG(BITS),<

	BIT==0			;;INITIALIZE BITS

  IRP <BITS>,<			;;LOOP OVER ALL BITS
	BIT==BIT!FR.'BITS	;;ADD IN NEW BIT TO PREVIOUS ONES
  >
	EXP	BIT		;;DUMP THE FINAL RESULT
>




;NOW DEFINE THE TYPNUM MACRO, USED TO GENERATE THE PROPER TTY TYPE.
;THE FIRST ARGUMENT IS USED IF WE ARE RUNNING ON TOPS-10, THE SECOND
;ONE IF WE ARE RUNNING ON TOPS-20.



DEFINE TYPNUM(VAL10,VAL20),<

IF10,<	EXP	SIXBIT/VAL10/>	;IF TOPS-10, GENERATE THIS
IF20,<	DFT	VAL20,377777>	;;IF TOPS-20, GENERATE THIS
>
;NOW DEFINE THE IMBEDDED SEQ MACRO.  IT TAKES ONE ARGUMENT,
;MADE UP OF A SEQUENCE OF CHARACTERS.  A WORD IS GENERATED IN THE
;FORM ADDR,,N WHERE N IS THE NUMBER OF CHARACTERS, AND ADDRESS IS
;THE ADDRESS OF THE STRING OF CHARACTERS.


DEFINE SEQ(CHARS),<

	CNT==0				;;START COUNT AT ZERO
	IRP	<CHARS>,<CNT==CNT+1>	;;LOOP OVER CHARS COUNTING THEM

  IFE CNT,<				;;IF NO CHARACTERS
	EXP	0			;;THEN PRODUCE JUST A ZERO WORD
  >

  IFN CNT,<				;;IF ANY CHARACTERS
	XWD	[			;;START LITERAL
	WORD==0				;;INITIALIZE WORD TO ZERO
	SHIFT==^D29			;;INITIALIZE SHIFT VALUE

    IRP <CHARS>,<			;;LOOP OVER ALL CHARS AGAIN
	WORD==WORD+<<CHARS>_SHIFT>	;;ADD NEW CHAR INTO WORD
	SHIFT==SHIFT-7			;;LESSEN SHIFT BY A CHAR

      IFL SHIFT,<			;;IF THE WORD IS FULL
	EXP	WORD			;;DUMP COMPLETED WORD OF CHARS
	WORD==0				;;RESET THE WORD
	SHIFT==^D29			;;AND THE SHIFT VALUE
      >
    >					;;END OF LOOP OVER CHARS

    IFN <SHIFT-^D29>,<			;;SEE IF ANY PARTIAL WORD LEFT
	EXP	WORD			;;IF SO, DUMP IT TOO
    >
	],CNT				;;END LITERAL AND STORE COUNT
  >					;;END OF IFN CNT CONDITIONAL
>
;THE FOLLOWING MACRO IS USED TO APPEND STRINGS TOGETHER.  THE USE OF
;THIS IS IN GENERATING THE TTYTYP TABLE AFTER EACH TERMINAL HAS BEEN
;DEFINED.



DEFINE	CONCAT(TEXT),<			;;MACRO TO APPEND NEW TEXT TO OLD

	DEFINE	APPEND(NEWTXT),<	;;REDEFINE OTHER MACRO
	CONCAT	(<TEXT''NEWTXT>)	;;WHICH DOES THE WORK
	>

	DEFINE	STRING,<		;;AND DEFINE MACRO FOR WHOLE TEXT
TEXT
>
>


	CONCAT				;INITIALIZE CONCATENATION MACROS






;FINALLY, INITIALIZE THE MAXIMUM VALUES OF THE WIDTH, LENGTH, AND AREA
;USED FOR ANY SCREEN.  NEEDED TO ALLOCATE DATA FOR WORST CASE.


	MAXLEN==0		;INITIALIZE MAXIMUM LENGTH
	MAXWID==0		;INITIALIZE MAXIMUM WIDTH
	MAXARE==0		;INITIALIZE MAXIMUM AREA
;NOW DEFINE ALL THE TERMINALS WHICH WE CAN RUN ON.  THE FOLLOWING TERMINAL
;NAMES MUST BE IN ALPHABETICAL ORDER!!!




TTY(ADM3A,,,24,80,,176,SP,CL(H),CL(L),CL(K),LF,CR,CL(^),CL(Z),,,
<ALT,"=">,,,SP,SP)


TTY(ASR33,ASR33,.TT33,25,71,TTY,176,SP,,SP,,LF,CR,
<CR,LF,LF>,<CR,LF,LF>,,,,,)


TTY(ASR35,ASR35,.TT35,25,71,<TAB,TTY>,176,SP,,SP,,LF,CR,
<CR,LF,LF>,<CR,LF,LF>,,,,,)


TTY(VT05,VT05,.TTV05,20,72,<TAB,RAI>,176,SP,CL(H),CL(X),
<CL(Z),RUB,RUB,RUB,RUB>,<LF,RUB,RUB,RUB,RUB>,CR,<CL(]),RUB,RUB,RUB,RUB>,
<CL(]),RUB,RUB,RUB,RUB,CL(_),RUB,RUB,RUB,RUB>,<CL(^),RUB,RUB,RUB,RUB>,
<CL(_),RUB,RUB,RUB,RUB>,CL(N),<NUL,NUL,NUL,NUL>,,SP,SP)


TTY(VT06,VT06,,25,72,RAI,176,SP,CL(H),CL(X),CL(Z),LF,CR,CL(]),
<CL(]),CL(_)>,CL(^),CL(_),,,,SP,SP)

TTY(VT100,VT100,.TT100,24,80,<TAB,ANSI>,176,SP,CL(H),<ALT,"[","C">,
<ALT,"[","A">,LF,CR,<ALT,"[","H">,<ALT,"[","H",ALT,"[","J">,
<ALT,"[","K">,<ALT,"[","J">,<ALT,"[">,,,,)

TTY(VT102,VT102,.TT102,24,80,<TAB,ANSI>,176,SP,CL(H),<ALT,"[","C">,
<ALT,"[","A">,LF,CR,<ALT,"[","H">,<ALT,"[","H",ALT,"[","J">,
<ALT,"[","K">,<ALT,"[","J">,<ALT,"[">,,,,)

TTY(VT125,VT125,.TT125,24,80,<TAB,ANSI>,176,SP,CL(H),<ALT,"[","C">,
<ALT,"[","A">,LF,CR,<ALT,"[","H">,<ALT,"[","H",ALT,"[","J">,
<ALT,"[","K">,<ALT,"[","J">,<ALT,"[">,,,,)

TTY(VT200,VT200,.TT200,24,80,<TAB,ANSI>,176,SP,CL(H),<ALT,"[","C">,
<ALT,"[","A">,LF,CR,<ALT,"[","H">,<ALT,"[","H",ALT,"[","J">,
<ALT,"[","K">,<ALT,"[","J">,<ALT,"[">,,,,)

TTY(VT50,VT50,.TTV50,12,80,<TAB,RAI>,176,SP,CL(H),<ALT,"C">,<ALT,"A">,
LF,CR,<ALT,"H">,<ALT,"H",ALT,"J">,<ALT,"K">,<ALT,"J">,,,,SP,SP)


TTY(VT52,VT52,.TTV52,24,80,TAB,176,SP,CL(H),<ALT,"C">,<ALT,"A">,LF,CR,
<ALT,"H">,<ALT,"H",ALT,"J">,<ALT,"K">,<ALT,"J">,<ALT,"Y">,,,SP,SP)
;NOW DEFINE THE TERMINAL TYPE TABLE, WHICH POINTS OFF TO EACH OF THE
;TERMINAL BLOCKS.  THIS DATA TABLE IS IN THE FORMAT NEEDED FOR
;THE TBLUK JSYS.



	XALL			;SHOW THE EXPANSION


TTYTYP:	XWD	TYPMAX,TYPMAX	;HEADER WORD FOR TABLE
	STRING			;THE TERMINAL TYPES


	TYPMAX==.-TTYTYP-1	;NUMBER OF TERMINAL TYPES


	SALL			;RETURN TO NORMAL LISTING
;THE FOLLOWING SIMPLE MACROS ARE USED TO DEFINE THE ERROR HANDLING
;INSTRUCTIONS.  THE AC FIELD OF THE XCT INSTRUCTION IS THE ERROR
;CODE.  THE INSTRUCTION XCT'D IS A SUBROUTINE CALLING INSTRUCTION.


DEFINE	DIE(CODE),<
	XCT	<E..'CODE-ERRTAB>,DIEBIG	;;GO TO ERROR ROUTINE
>



DEFINE	ERR(CODE,TEXT),<
E..'CODE:	[ASCIZ/TEXT/]	;;THE MESSAGE FOR THE ERROR
>
	SUBTTL	DISPATCH ROUTINE


;HERE ON AN LUUO, TO SAVE THE AC'S, DISPATCH TO THE PROPER ROUTINE,
;RESTORE THE AC'S, AND GO BACK TO THE USER.



DPYUUO:	MOVEM	P,SAVEP		;SAVE PUSH-DOWN AC IN CASE OF ERRORS
	MOVEM	F,SAVEF		;SAVE AN AC
	MOVE	F,[T1,,SAVET1]	;SET UP FOR BLT
	BLT	F,SAVEU		;SAVE REST OF AC'S WE USE
	MOVE	A,.JBUUO##	;GRAB HIS UUO
	LDB	T1,[POINT 4,A,12]	;GRAB THE AC FIELD
	CAILE	T1,MAXUUO	;SEE IF LEGAL LUUO WAS GIVEN
	  DIE	ILR		;NO, DIE
	JUMPE	T1,DOUUO	;IF INITIALIZATION, SKIP ON
	MOVE	X,@DP+$DPADR	;GET POINTER TO DATA AREA
	DMOVE	L,OURLN(X)	;RESTORE AC'S L AND N
	DMOVE	B,OURBU(X)	;RESTORE AC'S B AND U
	MOVE	F,OURF(X)	;GET OUR FLAGS
	TLNN	F,FL.INI	;HAVE WE BEEN INITIALIZED?
	  DIE	ING		;NO, LOSE
DOUUO:	PUSHJ	P,@DSPTAB(T1)	;CALL SUBROUTINE
	SKIPE	OUTADR(X)	;PROGRAM INTERCEPTING OUTPUT?
	PUSHJ	P,USRLST	;YES, INDICATE THIS IS END OF IT
	TLZE	F,FL.PNT	;NEED TO FORCE OUTPUT?
	PUSHJ	P,PUNT		;YES, SEND OUT REMAINING STUFF

RETURN:	MOVEM	F,OURF(X)	;SAVE FLAGS
	DMOVEM	L,OURLN(X)	;SAVE AC'S L AND N
	DMOVEM	B,OURBU(X)	;SAVE AC'S B AND U
	MOVSI	U,SAVEF		;SET UP FOR BLT
	BLT	U,U		;RESTORE HIS AC'S
CPOPJ:	POPJ	P,		;RETURN
;TABLE OF FUNCTION CODES.  THESE FUNCTIONS ARE DETERMINED BY THE
;AC FIELD OF THE LUUO.


DSPTAB:	EXP	FUNINI		;(0) INITIALIZE
	EXP	FUNSTR		;(1) STRING OUTPUT
	EXP	FUNCHR		;(2) CHARACTER OUTPUT
	EXP	FUNCHI		;(3) IMMEDIATE CHARACTER OUTPUT
	EXP	FUNSIZ		;(4) SET WINDOW SIZE
	EXP	FUNTAB		;(5) SET TABS
	EXP	FUNREF		;(6) REFRESH SCREEN
	EXP	FUNDPY		;(7) UPDATE SCREEN
	EXP	FUNSET		;(10) SET VARIOUS PARAMETERS
	EXP	FUNTTY		;(11) OUTPUT THINGS TO TTY
	EXP	FUNLOC		;(12) RETURN LOCATION OF NEXT OUTPUT
	EXP	FUNADR		;(13) MOVE TO GIVEN POSITION ON SCREEN

	MAXUUO==.-DSPTAB-1	;MAXIMUM LUUO ALLOWED
	SUBTTL	FUNCTION TO INITIALIZE


;FUNCTION WHICH SETS UP EVERYTHING SO THAT ON THE NEXT CALL TO OUR
;DPY ROUTINES, WE DO CORRECT THINGS.  I.E., WE CLEAR ALL FLAGS, SET
;UP DEFAULT TABS, CLEAR THE STORED SCREEN, AND MAYBE ERASE SCREEN.
;CALL TO INITIALIZE IS:
;
;	INI$	[FLAGS,,COUNT
;		ARGS]		;INITIALIZE DPY



FUNINI:	MOVSI	F,FL.INI	;SET INITIALIZATION FLAG
	PUSHJ	P,INIUSR	;READ USER ARGUMENTS AND PROCESS THEM
	HRR	F,T.FLAG(U)	;SET UP FLAGS FOR TERMINAL
	MOVE	T1,T.LEN(U)	;GET LENGTH OF SCREEN
	MOVEM	T1,@DP+$DPLEN	;SAVE IT
	MOVE	T1,T.WID(U)	;GET WIDTH OF SCREEN
	MOVEM	T1,@DP+$DPWID	;SAVE IT TOO
	MOVE	T1,[POINT 7,TTYBUF(X)] ;GET TERMINAL POINTER
	MOVEM	T1,BUFPTR(X)	;INITIALIZE IT
	SETZM	BUFCNT(X)	;CLEAR COUNT OF CHARACTERS
	PUSHJ	P,DFTTAB	;SET UP DEFAULT TAB STOPS
	PUSHJ	P,SIZINI	;SET UP THE DEFAULT WINDOW
	SETZM	ZERBLK(X)	;GET SET
	HRLI	T1,ZERBLK(X)	;MAKE BLT POINTER...
	HRRI	T1,ZERBLK+1(X)	;TO CLEAR ALL PARAMETERS
	BLT	T1,ZEREND(X)	;DO IT
	MOVE	T1,[BYTE (9)SP,SP,SP,SP]	;SET UP SPACES
	MOVEM	T1,SCREEN(X)	;STORE IN SCREEN
	HRRZM	T1,TTYN(X)	;SET CURSER WAY OFF OF SCREEN
	HRRZM	T1,TTYL(X)	;SO IF NOT CLEARED, WILL ADDRESS OR HOME
	HRLI	T1,SCREEN(X)	;SET UP...
	HRRI	T1,SCREEN+1(X)	;BLT POINTER
	BLT	T1,SCREEN+MAXARE-1(X)	;MAKE WHOLE SCREEN SPACES
	MOVE	A,INIFLG	;GET BACK USER FLAGS
	TRNN	A,IN$NCL	;SHOULD WE CLEAR THE SCREEN?
	  JRST	DOCLR		;YES, GO DO IT
	POPJ	P,		;NO, JUST RETURN
	SUBTTL	ROUTINE TO PROCESS USER ARGUMENTS FOR INI$ FUNCTION




;CALLED TO LOOK AT THE USER'S ARGUMENTS FOR THE INI$ FUNCTION, AND
;PROCESS THEM.  THE MOST IMPORTANT FUNCTION DONE IS SETTING WHICH
;TERMINAL TYPE WE ARE RUNNING ON.



INIUSR:	TRNN	A,-1		;WERE ARGUMENTS SUPPLIED?
	MOVEI	A,ZERO		;NO, THEN POINT TO DEFAULT ONE
	MOVSI	B,-ININUM	;GET READY FOR LOOP

INILP1:	PUSHJ	P,GETWRD	;READ ARGUMENT FOR NEXT ROUTINE
INILP2:	PUSHJ	P,@INITAB(B)	;THEN CALL ROUTINE
	AOBJP	B,CPOPJ		;RETURN IF DONE
	SOSL	INICNT		;USER HAVE ANY MORE ARGS?
	  JRST	INILP1		;YES, GET READ IT AND PROCESS IT
	SETZ	T1,		;NO, THEN DEFAULT TO ZERO
	JRST	INILP2		;GO BACK FOR NEXT ROUTINE



INITAB:	EXP	INIHDR		;(0) THE HEADER WORD
	EXP	INIADR		;(1) THE ADDRESS OF THE RELOCATABLE DATA
	EXP	INIERR		;(2) ROUTINE TO GO TO ON ERROR
	EXP	INITTY		;(3) TERMINAL STRING
	EXP	INIJFN		;(4) THE JFN OR CHANNEL FOR OUTPUT

	ININUM==.-INITAB	;NUMBER OF ARGUMENTS TOTAL
;HERE TO PROCESS THE HEADER WORD.  THIS CONTAINS FLAGS AND THE COUNT
;OF REMAINING ARGUMENTS TO BE PROCESSED.


INIHDR:	HLRZM	T1,INIFLG	;SAVE THE FLAGS
	HRRZM	T1,INICNT	;AND THE COUNT OF ARGUMENTS
	POPJ	P,		;DONE




;HERE TO PROCESS THE ADDRESS OF THE RELOCATABLE DATA.  THE USER CAN
;TELL US WHERE IN CORE TO STORE OUR DATA.


INIADR:	SKIPN	X,T1		;DID HE GIVE AN ADDRESS?
	MOVEI	X,DATBEG	;NO, THEN USE OUR OWN
	MOVEM	X,DATADR	;REMEMBER THE LOCATION FOR LATER
	POPJ	P,		;DONE




;HERE TO PROCESS THE ERROR ADDRESS.  THIS IS SO THAT IF THE INI$
;FUNCTION FAILS SOMEHOW, THE CALLER CAN RECOVER FROM THE ERROR.


INIERR:	MOVEM	T1,ERRADR(X)	;REMEMBER THE ERROR ADDRESS
	POPJ	P,		;DONE





;HERE TO PROCESS THE JFN (OR BUFFER,,CHANNEL) FOR OUTPUT.  IF ZERO,
;WE HAVE TO ALLOCATE OUR OWN JFN (OR USE IONEOU).  OTHERWISE, WE ARE
;TO USE THE SPECIFIED JFN FOR OUTPUT.


INIJFN:	MOVEM	T1,TTYJFN(X)	;SET UP JFN
	POPJ	P,		;RETURN
;HERE TO INITIALIZE THE TERMINAL TYPE.  ZERO MEANS USE OUR CURRENT
;TERMINAL TYPE.  FOR TOPS-20, 5B2 MEANS TERMINAL TYPE IS IN RIGHT HALF,
;OTHERWISE WE HAVE A POINTER TO AN ASCIZ STRING.  FOR TOPS-10, THE
;SIXBIT TERMINAL NAME IS SUPPLIED IF NONZERO.



INITTY:	IF20,<

	JUMPE	T1,FNDTYP	;ASK MONITOR FOR TYPE IF NOTHING GIVEN
	HRRZ	T2,T1		;GET RIGHT HALF BY ITSELF
	HLRZ	T1,T1		;AND LEFT HALF BY ITSELF TOO
	CAIN	T1,(5B2)	;IS THIS A TERMINAL TYPE NUMBER?
	JRST	FNDTTY		;YES, GO USE IT
	CAIE	T1,0		;IS THIS AN ADDRESS?
	CAIN	T1,-1		;OR THE DEFAULT POINTER?
	TLOA	T2,(POINT 7,)	;YES, GET STANDARD POINTER
	HRL	T2,T1		;OTHERWISE RESTORE POINTER
	MOVEI	T1,TTYTYP	;POINT TO TABLE
	TBLUK			;SEARCH FOR GIVEN STRING
	TLNN	T2,(TL%ABR!TL%EXM)	;FIND UNIQUE MATCH?
	SKIPA	U,[DFTTRM]	;NO, USE DEFAULT TERMINAL TYPE
	HRRZ	U,(T1)		;YES, SET UP POINTER FOR THIS TERMINAL
	POPJ	P,		;RETURN


FNDTYP:	MOVEI	T1,.PRIOU	;WANT TO FIND OUTPUT TERMINAL TYPE
	GTTYP			;READ IT
				;THEN FALL INTO SEARCH CODE
>
IF10,<	SKIPE	T2,T1		;SEE IF WE WERE GIVEN A NAME
	JRST	FNDTTY		;YES, GO SEARCH FOR IT
	MOVE	T2,[2,,T3]	;GET READY
	MOVEI	T3,.TOTRM	;TO READ TERMINAL TYPE
	SETO	T4,		;FOR OUR CONTROLLING TTY
	TRMOP.	T2,		;READ TYPE
	JRST	USEDFT		;FAILED, GO USE DEFAULT TERMINAL
>



;HERE WHEN T2 CONTAINS THE TERMINAL TYPE FOR TOPS-20, OR THE TERMINAL
;NAME FOR TOPS-10, TO SEARCH OUR TERMINAL DATA FOR THE RIGHT BLOCK.


FNDTTY:	MOVSI	T1,-TYPMAX	;GET READY FOR LOOP
	HRRZ	T3,TTYTYP+1(T1)	;GET ADDRESS OF NEXT TTY BLOCK
	CAME	T2,T.TYP(T3)	;FOUND THE RIGHT TYPE?
	AOBJN	T1,.-2		;NO, KEEP LOOKING
	SKIPL	T1		;FOUND IT?
USEDFT:	SKIPA	U,[DFTTRM]	;NO, GET DEFAULT TERMINAL BLOCK
	HRRZ	U,TTYTYP+1(T1)	;YES, THEN USE THAT BLOCK
	POPJ	P,		;RETURN
	SUBTTL	THE CHARACTER STORING ROUTINES



;THE FOLLOWING THREE CALLS ARE USED TO GIVE DPY THE CHARACTERS THE
;USER PROGRAM WANTS TO DISPLAY.  STR$ PROCESSES A STRING, CHR$ PROCESSES
;A CHARACTER, AND CHI$ PROCESSES AN IMMEDIATE CHARACTER.




FUNSTR:	ANDI	A,-1		;KEEP ONLY ADDRESS OF STRING
	CAIG	A,U		;REFERENCING THE STORED AC'S?
	ADDI	A,SAVEF		;YES, RELOCATE TO THEM
STRUNS:	TLOA	A,(POINT 7,)	;MAKE BYTE POINTER AND SKIP INTO LOOP
STRLOP:	PUSHJ	P,STORE1	;STORE THIS CHARACTER
	ILDB	C,A		;GRAB THE NEXT CHARACTER
	JUMPN	C,STRLOP	;LOOP OVER WHOLE STRING
	CAME	A,[POINT 7,ZERO,6]	;WENT OFF THE SAVED AC'S?
	  POPJ	P,		;NO, THEN ALL DONE
	MOVEI	A,U+1		;YES, POINT TO UNSAVED AC'S
	JRST	STRUNS		;AND PROCEED



FUNCHR:	PUSHJ	P,GETWRD	;GO GET THE DESIRED WORD
	SKIPA	C,T1		;AND FALL INTO OTHER ROUTINE

FUNCHI:	MOVEI	C,(A)		;GRAB THE CHARACTER
	ANDI	C,177		;REMOVE ALL JUNK
;	PJRST	STORE		;AND FALL INTO STORE ROUTINE
;HERE WHEN HAVE THE CHARACTER IN AC C.  NULLS ARE IGNORED, AS ARE ALL
;NON-USEFUL CONTROL CHARACTERS, AND CHARACTERS HIGHER THAN THE TERMINAL
;CAN TYPE.   THE ONLY CONTROL CHARACTERS THAT ARE HANDLED ARE TAB
;AND LINE FEED.



STORE:	JUMPE	C,CPOPJ		;QUIT NOW IF HAVE A NULL
STORE1:	TLO	F,FL.OUT	;REMEMBER THAT WE HAVE OUTPUT IN THIS WINDOW
	CAMLE	L,MAXL(X)	;IS OUR LINE OFF OF THE BOTTOM?
	  JRST	OVERFL		;YES, GO SEE IF WE MOVE WINDOWS
	CAIL	C,SP		;IS THIS A CONTROL CHAR?
	CAMLE	C,T.MAXC(U)	;OR IS CHAR BEYOND PRINTING RANGE?
	  JRST	CONTRL		;YES, HANDLE SPECIAL
	SKIPLE	EATNUM(X)	;EATING UP CERTAIN NUMBER OF LINES?
	  POPJ	P,		;YES, JUST RETURN
	CAMLE	N,MAXN(X)	;ARE WE OFF RIGHT SIDE OF WINDOW?
	  JRST	OFFRHT		;YES
	TRNN	F,FR.RAI	;LOWER CASE ACTS LIKE UPPER CASE?
	  JRST	NORAIS		;NOPE, SKIP ON
	CAIL	C,"A"+40	;IS THIS A LOWER CASE CHARACTER?
	CAILE	C,176		;WELL?
	  JRST	NORAIS		;NO, DON'T CHANGE IT
	SUBI	C,40		;YES, CONVERT TO UPPER CASE
NORAIS:	ILDB	T1,B		;GRAB THE OLD CHARACTER AT THIS LOCATION
	TRZE	T1,UPDATE	;IS IT ALREADY TO BE UPDATED?
	PUSHJ	P,CKOKUP	;YES, SEE IF IT IS LEGAL TO DO SO
	CAMN	T1,C		;IS NEW CHAR SAME AS OLD ONE?
	  AOJA	N,CPOPJ		;YES, THEN COUNT POSITION AND RETURN
	TRNE	F,FR.ELC	;DOES TERMINAL DO CRLFS AT LAST CHAR?
	CAME	N,T.WID(U)	;AND ARE WE AT LAST COLUMN?
	  JRST	NOKLG		;NO, GO ON
	CAMN	L,T.LEN(U)	;ARE WE AT LAST LINE ALSO?
	  AOJA	N,CPOPJ		;YES, NEVER DIDDLE THE LAST CHAR THEN
NOKLG:	MOVEI	T1,UPDATE(C)	;NO, GET CHAR WITH "MUST UPDATE" BIT
	DPB	T1,B		;STORE IT AWAY
	MOVEI	T1,LINCHG(X)	;GET ADDRESS WE WANT...
	ADD	T1,L		;TO SET TO -1
	SETOM	(T1)		;REMEMBER THAT CHANGES HAVE BEEN DONE
	AOJA	N,CPOPJ		;THEN COUNT POSITION AND RETURN



;ROUTINE TO SEE IF UPDATING THE SAME PLACE ON THE SCREEN TWICE IS
;OK.  WE RETURN IF SO, GIVE AN ERROR IF NOT.


CKOKUP:	TLNN	F,FL.OKU	;DID USER TELL US IT'S OK?
	  DIE	USL		;NO, THEN GIVE THE ERROR
	POPJ	P,		;IT'S OK, JUST IGNORE IT
;HERE TO PROCESS A CONTROL CHARACTER.  THE ONLY CONTROL CHARACTERS WE
;WILL ALLOW ARE <TAB>  OR  <LF>.  ALL OTHER CHARACTERS ARE EATEN, FOR WE
;DON'T KNOW WHAT THE TERMINAL MAY DO WITH THEM.


CONTRL:	CAIE	C,LF		;IS A LINEFEED?
	  JRST	CHKCTL		;NO, GO LOOK FOR A TAB
	SOSL	EATNUM(X)	;DECREMENT NUMBER OF LINES TO EAT
	  POPJ	P,		;STILL HAVE TO EAT MORE, RETURN
	MOVEI	T1,SP+UPDATE	;GET A "MUST UPDATE HERE" SPACE
	MOVEI	T2,LINCHG(L)	;GET OFFSET OF FLAG WORD FOR THIS LINE
	ADD	T2,X		;RELOCATE IT

ZAPLIN:	CAMLE	N,MAXN(X)	;REACHED THE RIGHT LIMIT YET?
	  JRST	NEWLIN		;YES, GO MOVE TO NEXT LINE NOW
	ILDB	T3,B		;NO, THEN GRAB OLD CHARACTER
	TRZE	T3,UPDATE	;HAVE THE "MUST UPDATE" BIT ON?
	PUSHJ	P,CKOKUP	;YES, SEE IF IT'S OK FOR THAT TO HAPPEN
	CAIN	T3,SP		;IS CHAR A SPACE?
	  AOJA	N,ZAPLIN	;YES, LOOK AT NEXT CHAR
	DPB	T1,B		;NO, PUT IN A "MUST UPDATE" SPACE
	SETOM	(T2)		;REMEMBER CHANGES HAVE BEEN DONE
	AOJA	N,ZAPLIN	;AND LOOP TO FINISH OFF LINE



;HERE TO PROCESS A TAB, IF THAT IS WHAT WE HAVE.  IF NOT A TAB HERE,
;WE EAT IT, FOR IT IS A RANDOM CONTROL CHARACTER (INCLUDING CR)


CHKCTL:	CAIN	C,TAB		;IS IT A TAB?
	SKIPLE	EATNUM(X)	;AND DO WE HAVE NO LINES TO IGNORE?
	  POPJ	P,		;NO, JUST RETURN THEN
	MOVEI	T4,(N)		;GET POSITION ON THE LINE
	ADJBP	T4,[POINT 1,TABS(X),0]	;MAKE BYTE POINTER TO BIT
	MOVEI	C,SP		;AND CHANGE TAB TO A SPACE

TABLOP:	PUSHJ	P,STORE1	;GO STORE A SPACE
	CAME	N,MINN(X)	;AT BEGINNING OF NEXT LINE?
	CAMLE	N,MAXN(X)	;OR OUTSIDE THE WINDOW?
	  POPJ	P,		;YES, RETURN THEN
	ILDB	T1,T4		;NO, GET BIT FOR NEXT POSITION
	JUMPE	T1,TABLOP	;IF NOT AT TAB STOP GIVE ANOTHER SPACE
	POPJ	P,		;OTHERWISE ARE THERE



;HERE TO SET UP TO DO NEXT LINE


NEWLIN:	MOVE	N,MINN(X)	;GET LEFT WINDOW VALUE
	AOJA	L,MAKEBP	;INCREMENT LINE, MAKE BYTE POINTER, RETURN
;THESE ARE THE "FIXIT" ROUTINES WHICH SEE WHAT WE DO WHEN WE
;OVERFLOW A LINE, OR THE WHOLE WINDOW.  THE CHOICES DEPEND ON WHAT
;THE USER WANTS.  IF WE OVERFLOW A LINE, WE CAN EITHER IGNORE THE
;CHARACTER, OR DO AN AUTOMATIC CARRIAGE RETURN.  IF WE OVERFLOW
;THE WHOLE WINDOW, WE EITHER INGORE THE CHARACTER, OR WE MOVE THE WINDOW
;TO THE RIGHT SOME, AND CONTINUE OUTPUTTING IN THE NEW WINDOW.
;NOTE THESE ROUTINES ARE CALLED FROM THE  FUNLOC  ROUTINE, ALSO.


;HERE IF WE HAVE GONE OFF THE RIGHT OF THE WINDOW, TO SEE WHETHER WE
;JUST IGNORE THE CHARACTER, OR PRETEND IT WAS A <LF> CHAR


OFFRHT:	TLNN	F,FL.ACR!FL.AC2	;ARE WE DOING AUTO-CRLFS?
	  POPJ	P,		;NO, THEN IGNORE THE CHARACTER
	PUSHJ	P,NEWLIN	;GO MOVE TO THE NEXT LINE
	JRST	STORE		;THEN STORE THE CHARACTER




;HERE IF WE HAVE GONE OFF THE BOTTOM OF THE WINDOW.  WE MUST SEE IF THE
;USER TOLD US TO FLICK IN THE CHARS, OR TO MOVE THE WINDOW FOR HIM.


OVERFL:	SKIPLE	T1,OVFVAL(X)	;DID USER SET UP HOW WE MOVE WINDOWS?
	TRNN	T1,-1		;AND ARE THERE ANY WINDOWS LEFT IN COUNT?
	  JRST	CLROVF		;NO, GO CLEAR WORD FOR SURE AND RETURN
	SOS	OVFVAL(X)	;SUBTRACT 1 FROM COUNT OF WINDOWS LEFT
	HLRZ	T1,T1		;GET DISTANCE BETWEEN WINDOWS
	ADD	T1,MAXN(X)	;ADD TO CURRENT RIGHT MARGIN
	ADDI	T1,1		;AND THEN ONE MORE
	CAMLE	T1,T.WID(U)	;WOULD NEW LEFT MARGIN BE ON SCREEN?
	  JRST	CLROVF		;NO, CLEAR WORD AND IGNORE THIS CHAR
	EXCH	T1,MINN(X)	;SAVE NEW LEFT MARGIN, GET OLD ONE
	MOVE	T2,MAXN(X)	;GET OLD RIGHT MARGIN
	SUB	T2,T1		;SUBTRACT OLD LEFT MARGIN
	ADD	T2,MINN(X)	;AND ADD NEW LEFT MARGIN TO GET NEW RIGHT ONE
	CAMLE	T2,T.WID(U)	;DOES WINDOW GO OFF OF SCREEN?
	MOVE	T2,T.WID(U)	;YES, TRUNCATE IT TO FIT
	MOVEM	T2,MAXN(X)	;SAVE NEW RIGHT MARGIN
	MOVE	L,MINL(X)	;SET OUR LOCATION AT TOP OF WINDOW
	PUSHJ	P,MAKEBP	;CREATE A NEW POINTER
	JRST	STORE		;AND GO PUT THE CHAR IN THE NEW WINDOW


;HERE WHEN CAN'T MAKE A NEW WINDOW, TO CLEAR THE OVFVAL WORD

CLROVF:	SETZM	OVFVAL(X)	;ZERO SO NOT TO BOTHER US AGAIN
	POPJ	P,		;AND RETURN
	SUBTTL	FUNCTION TO REFRESH THE SCREEN


;THIS FUNCTION IS CALLED WHENEVER THE USER WANTS TO MAKE SURE THE
;SCREEN IS CORRECT,  THAT IS WHEN HE THINKS THERE ARE GLITCHES ON THE
;SCREEN AND WANTS THEM FIXED.  CALL IS:
;
;	REF$	FLAGS



FUNREF:	PUSHJ	P,ZAPEND	;FIRST MUNCH ON REST OF WINDOW
	PUSHJ	P,CLRCHG	;CLEAR THE CHANGE TABLE
	TRNE	F,FR.TTY	;IS THIS ON A NON-VIDEO TERMINAL
	  JRST	REFTTY		;YES, GO DO IT STRAIGHT
	TRNN	A,RE$CLR	;SHOULD WE CLEAR SCREEN FIRST?
	  JRST	REFHRD		;NO, GO DO IT THE HARD WAY


REFTTY:	PUSHJ	P,DOCLR		;YES, CLEAR THE SCREEN

REFLOP:	SETZ	N,		;START AT FRONT OF LINE
	PUSHJ	P,MAKEBP	;GET A BYTE POINTER TO IT

REFLIN:	ILDB	C,B		;GET NEXT CHAR OF LINE
	TRZE	C,UPDATE	;CLEAR UPDATE BIT
	DPB	C,B		;AND STORE CHAR BACK WITHOUT THE BIT
	CAIN	C,SP		;IS THIS A SPACE?
	  JRST	REFSPC		;YES, SKIP ON
	PUSH	P,C		;NO, SAVE THIS CHAR
	PUSHJ	P,MOVE		;GET TO THIS LOCATION
	POP	P,C		;RESTORE THE CHAR
	PUSHJ	P,DOONE		;OUTPUT IT

REFSPC:	CAMGE	N,T.WID(U)	;DONE WITH THIS LINE?
	  AOJA	N,REFLIN	;NO, LOOP
	CAMGE	L,T.LEN(U)	;DONE WITH ALL LINES?
	  AOJA	L,REFLOP	;NO, KEEP LOOPING
	PJRST	DPYFIN		;YES, GO FINISH UP
;HERE IN CASE WHERE WE DID NOT HOME UP AND CLEAR THE SCREEN.



REFHRD:	PUSHJ	P,DOHOM		;MAKE SURE WE ARE HOMED UP
	MOVE	T1,T.WID(U)	;GET LAST COLUMN
	MOVEM	T1,LSTNON	;AND SAVE SO EOL WILL TYPE WHOLE LINE


RFHLOP:	SETZ	N,		;START AT FRONT OF LINE
	PUSHJ	P,MAKEBP	;MAKE A BYTE POINTER FOR THIS LINE
	MOVE	T1,B		;GET A COPY
	SETOM	LSTCHG		;INITIALIZE TEMPORARY VARIABLE

RFHLIN:	ILDB	C,T1		;GET NEXT CHAR ON LINE
	TRZE	C,UPDATE	;CLEAR UPDATE BIT
	DPB	C,T1		;AND STORE IT BACK WITHOUT BIT
	CAIE	C,SP		;IS IT A SPACE?
	MOVEM	N,LSTCHG	;NO, REMEMBER LAST NONSPACE
	CAMGE	N,T.WID(U)	;SCANNED WHOLE LINE?
	  AOJA	N,RFHLIN	;NO, KEEP GOING
	SETZ	N,		;BACK UP TO FRONT AGAIN
	PUSHJ	P,MOVE		;GO THERE

RFHTYP:	CAMLE	N,LSTCHG	;DONE WITH ALL NONSPACES ON LINE?
	  JRST	RFHDNL		;YES
	ILDB	C,B		;NO, GET CHAR AT THIS SPOT
	PUSHJ	P,DOONE		;OUTPUT IT
	AOJA	N,RFHTYP	;AND CONTINUE

RFHDNL:	CAMG	N,T.WID(U)	;IF NOT AT END OF SCREEN
	PUSHJ	P,DOEOL		;THEN CLEAR THE REST OF THE LINE
	CAMGE	L,T.LEN(U)	;DID ALL LINES?
	  AOJA	L,RFHLOP	;NO, LOOP OVER THEM
	PJRST	DPYFIN		;YES, FINISH UP
	SUBTTL	FUNCTION TO UPDATE THE SCREEN


;THIS FUNCTION IS WHAT DPY IS ALL ABOUT!!!!  AFTER THE USER HAS OUTPUT
;WHATEVER PARTS OF THE SCREEN HE WISHES TO SHOW, HE CALLS THIS ROUTINE, AND
;THE CHANGES ARE SHOWN WITH MINIMUM EFFORT.  CALL IS SIMPLY:
;
;	DPY$	FLAGS




FUNDPY:	PUSHJ	P,ZAPEND	;CLEAR REST OF LAST WINDOW USED
	SETZB	L,N		;BEGIN SEARCH AT TOP LEFT
	TRNE	F,FR.TTY	;NON-VIDIO TERMINAL?
	  JRST	TTYDPY		;YES, HANDLE SPECIAL

FNDLIN:	CAMLE	L,T.LEN(U)	;LOOKED AT ALL THE LINES?
	  JRST	DPYFIN		;YES, GO FINISH UP
	PUSHJ	P,MINMAX	;LOOK FOR CHANGES ON THIS LINE
	  AOJA	L,FNDLIN	;IF NONE, GO TO NEXT LINE
	SKIPN	T.ADR(U)	;CAN TERMINAL ADDRESS?
	  JRST	NODPY		;NO, GO DO DIFFERENTLY

UPDLIN:	MOVE	N,FSTCHG	;YES, GET COLUMN OF FIRST CHANGE
	PUSHJ	P,MOVE		;GO THERE
	PUSHJ	P,SLURP		;DO ALL CHANGES ON THE LINE
	AOJA	L,FNDLIN	;THEN LOOK AT NEXT LINE



;HERE WHEN ALL DONE, TO RESET WINDOWS AND POSSIBLY HOME UP:


DPYFIN:	SETZM	EATNUM(X)	;NO LONGER WANT TO EAT LINES
	SETZB	N,L		;SET AT TOP LEFT CORNER
	TRNN	A,DP$NOH	;WANT TO HOME UP WHEN DONE?
	PUSHJ	P,MOVE		;YES, DO IT
	MOVE	L,MINL(X)	;SET LOCATION TO TOP LINE OF WINDOW
	MOVE	N,MINN(X)	;AND LEFTMOST COLUMN OF WINDOW
	TLZ	F,FL.OUT	;CLEAR OUTPUT IN WINDOW FLAG
	PJRST	MAKEBP		;MAKE A BYTE POINTER AND RETURN
;HERE IF THIS TERMINAL CANNOT ADDRESS.  WE MUST SEE IF IT IS BETTER
;TO GO TO THE RIGHT FIRST, OR TO DO A CARRIAGE RETURN FIRST.



NODPY:	MOVE	N,TTYN(X)	;GET CURRENT COLUMN NUMBER
	CAMLE	N,FSTCHG	;IS CURSER TO LEFT OF FIRST CHANGE?
	CAMLE	N,LSTCHG	;OR IS IT TO RIGHT OF LAST CHANGE?
	  JRST	UPDLIN		;YES, UPDATE LINE FROM LEFT TO RIGHT
	CAMLE	N,LSTNON	;ONLY SPACES BEYOND WHERE WE ARE?
	SKIPN	T.EOL(U)	;AND CAN WE DO ERASE END OF LINES?
	SKIPA	T1,LSTCHG	;NO, GET LAST CHANGE AND SKIP
	  JRST	UPDLIN		;YES, START AT FRONT OF LINE THEN
	PUSH	P,TTYN(X)	;SAVE CURRENT POSITION
	MOVEM	T1,TTYN(X)	;CHANGE WHERE WE THINK WE ARE
	MOVE	N,FSTCHG	;AND WE WANT TO GET TO FIRST CHANGE
	MOVEI	T2,-1		;GET A LARGE NUMBER
	MOVEM	T2,BEST		;SET IT
	PUSHJ	P,CHKDL		;SEE HOW MANY CHARS TO BACK UP
	PUSHJ	P,CHKCDR	;OR HOW MANY TO CR, THEN FORWARD
	POP	P,TTYN(X)	;RESTORE TRUE POSITION
	PUSH	P,BEST		;SAVE NUMBER OF CHARS NEEDED
	MOVEI	T2,-1		;GET LARGE NUMBER AGAIN
	MOVEM	T2,BEST		;AND SET IT AGAIN
	PUSHJ	P,CHKDL		;SEE HOW MANY CHARS TO GET TO FIRST CHANGE
	PUSHJ	P,CHKCDR	;ALSO BY CR FIRST
	POP	P,T1		;RESTORE OTHER COUNT
	MOVE	T2,TTYN(X)	;GET CURRENT POSITION
	SUB	T2,PRECHG	;SUBTRACT NEAREST CHANGE
	ADD	T2,BEST		;ADD IN OTHER COUNT
	ADDI	T1,PRETTY	;ADD IN PRETTYNESS FACTOR
	CAML	T1,T2		;IS IT BETTER TO CRLF FIRST OR NOT?
	  JRST	UPDLIN		;YES, JUST UPDATE LINE
	MOVE	N,TTYN(X)	;START SEARCH AT CURRENT POSITION
	PUSHJ	P,MOVE		;GO TO RIGHT LINE
	PUSHJ	P,SLURP		;UPDATE END OF THE LINE
	MOVE	T1,PRECHG	;GET LAST CHANGE PRIOR TO MOVEMENT
	MOVEM	T1,LSTCHG	;SET IT AS LAST CHANGE
	JRST	UPDLIN		;THEN UPDATE FIRST PART OF LINE
;HERE IF THIS IS A NON-VIDIO TERMINAL.  WE SEE IF ANY CHANGES HAVE
;OCCURED ON THE SCREEN.  IF NOT, WE DO NOTHING.  OTHERWISE WE TYPE
;THE WHOLE SCREEN AGAIN.



TTYDPY:	HRLZ	T1,T.LEN(U)	;GET NUMBER OF LINES TO CHECK
	MOVN	T1,T1		;MAKE AOBJN POINTER
	HRRI	T1,LINCHG(X)	;GET ADDRESS OF THE TABLE
	SKIPN	(T1)		;CHANGES ON THIS LINE?
	AOBJN	T1,.-1		;NO, SEARCH ALL LINES
	JUMPGE	T1,DPYFIN	;JUST RETURN IF NO CHANGES
	PUSHJ	P,CLRCHG	;CLEAR THE CHANGE TABLE
	PUSHJ	P,MOVE		;GO "MOVE" TO HOME POSITION
	JRST	REFLOP		;THEN JOIN REFRESH CODE



CLRCHG:	HRLI	T1,LINCHG(X)	;GET SET
	HRRI	T1,LINCHG+1(X)	;FOR BLT
	MOVE	T2,T.LEN(U)	;GET NUMBER OF LINES
	SETZB	L,LINCHG(X)	;CLEAR LINE NUMBER AND CHANGE FLAG
	ADDI	T2,LINCHG(X)	;GET ADDRESS WE WANT
	BLT	T1,(T2)		;ZERO WHOLE CHANGE TABLE
	POPJ	P,		;DONE
	SUBTTL	ROUTINE TO OUTPUT THE CHANGES ON A LINE



;THIS ROUTINE IS CALLED ONCE WE ARE AT A CHANGE ON A LINE, TO FOLLOW
;THE LINE LOOKING FOR REST OF THE CHANGES.  THIS ROUTINE ALSO TAKES
;CARE OF THE ERASE-END-OF-LINE CHECKS.  CALL IS:
;
;	(CALL MINMAX)		;COLLECT FSTCHG, LSTCHG, ETC.
;	MOVE	N,COLUMN	;SET UP COLUMN OF CHANGE
;	MOVE	L,LINE		;AND LINE OF CHANGE
;	PUSHJ	P,SLURP		;PROCESS THE CHANGES ON THE LINE
;	(RETURN)		;WE TOOK CARE OF ALL CHANGES ON LINE





SLURP:	PUSHJ	P,MAKEBP	;GET A BYTE POINTER TO THIS PLACE
SLPLOP:	CAMLE	N,LSTCHG	;BEYOND THE LAST CHANGE ON THE LINE?
	  POPJ	P,		;YES, RETURN
SLPSCN:	ILDB	C,B		;GET CHARACTER AT THIS POSITION
	TRZN	C,UPDATE	;DOES IT NEED UPDATING?
	  AOJA	N,SLPSCN	;NO, LOOK SOME MORE
	DPB	C,B		;YES, STORE CHAR BACK WITHOUT BIT
	CAME	N,TTYN(X)	;CURSER NOT AT CURRENT COLUMN?
	PUSHJ	P,MOVE		;NO, THEN MOVE THERE
	SKIPE	T.EOL(U)	;CAN THIS TERMINAL ERASE END OF LINE?
	CAMG	N,LSTNON	;AND LINE CONTAINS ONLY SPACES?
	SKIPA			;NO, THEN DO NOTHING SPECIAL
	  JRST	SLPEOL		;YES, GO DO END OF LINE
	LDB	C,B		;GET BACK CHAR IN CASE WE HAD TO MOVE
	PUSHJ	P,DOONE		;THEN OUTPUT THIS CHARACTER
	AOJA	N,SLPLOP	;LOOK AT NEXT CHAR


SLPEOL:	PUSHJ	P,DOEOL		;ERASE REST OF LINE
	MOVEI	C,SP		;GET A SPACE
SLPELL:	CAML	N,LSTCHG	;DID ALL CHARS ON LINE?
	  POPJ	P,		;YES, RETURN
	IDPB	C,B		;STORE A SPACE IN THE ARRAY
	AOJA	N,SLPELL	;AND LOOP
	SUBTTL	FUNCTION WHICH SETS THE "WINDOW" FOR OUTPUT


;THIS FUNCTION IS USED TO SET A "WINDOW" IN WHICH THE USER WANTS TO
;OUTPUT IN.  THE PURPOSE OF THIS IS SO THE USER CAN SPLIT UP THE
;SCREEN IN PIECES, AND OUTPUT HIS STUFF ONE HUNK AT A TIME, AND
;THEREFORE NOT HAVE TO WORRY ABOUT FORMATTING EVERYTHING.  HE JUST
;CALLS THIS ROUTINE EACH TIME HE OUTPUTS A DIFFERENT PIECE.
;USER CALLS THIS ROUTINE WITH:
;
;	SIZE$	[MINLIN,,MAXLIN		;MIN AND MAX LINE NUMBER
;		 MINCHR,,MAXCHR]	;MIN AND MAX CHARACTER POSITION
;
;WHERE THE NUMBERS ARE THE MINIMUM AND MAXIMUM VALUES THE USER WISHES
;TO RANGE BETWEEN.  ZERO IS THE TOP LEFT CORNER OF THE PHYSICAL SCREEN.
;A NEGATIVE MAXIMUM ARGUMENT (I.E., BIT 18 IS SET) IMPLIES TO USE THE
;MAXIMUM VALUE ALLOWED, THE FULL WIDTH OR LENGTH OF THE SCREEN.
;WE ALSO SET THE POSITION TO OUTPUT TO TO THE TOP LEFT OF THE WINDOW,
;TO SAVE THE USER THE TROUBLE, SINCE HE USUALLY WANTS THAT ANYWAY.
;IF THE UUO CONTAINS ZERO AS THE ADDRESS, WE ASSUME HE WANTS TO HAVE
;THE WHOLE SCREEN AS THE WINDOW, AND SO DO IT THAT WAY.


FUNSIZ:	PUSHJ	P,ZAPEND	;CLEAR OUT REST OF PREVIOUS WINDOW FIRST
	TRNN	A,-1		;GIVE US A REASONABLE ADDRESS?
SIZINI:	MOVEI	A,T.LEN(U)	;NO, SET UP USUAL SCREEN THEN
	PUSHJ	P,GETWRD	;GRAB FIRST USER WORD
	HLRZ	L,T1		;SET MINIMUM LINE NUMBER
	TRNE	T1,400000	;IS THE MAXIMUM VALUE NEGATIVE?
	SKIPA	T1,T.LEN(U)	;YES, GRAB LARGEST POSSIBLE VALUE
	MOVEI	T1,(T1)		;NO, ISOLATE MAXIMUM LINE NUMBER
	CAIG	L,(T1)		;MINIMUM SMALLER THAN MAXIMUM?
	CAMLE	T1,T.LEN(U)	;AND MAXIMUM LESS THAN SCREEN?
	DIE	IWS		;NO, IS WRONG, DIE
	MOVEM	L,MINL(X)	;SAVE THE MINIMUM AWAY
	MOVEM	T1,MAXL(X)	;AND THE MAXIMUM
	PUSHJ	P,GETWRD	;GET USER'S SECOND ARGUMENT
	HLRZ	N,T1		;GET MINIMUM CHARACTER POSITION
	TRNE	T1,400000	;IS MAXIMUM VALUE NEGATIVE?
	SKIPA	T1,T.WID(U)	;YES, USE LARGEST LEGAL VALUE
	MOVEI	T1,(T1)		;NO, ISOLATE MAXIMUM POSITION
	CAIG	N,(T1)		;MINIMUM SMALLER THAN MAXIMUM?
	CAMLE	T1,T.WID(U)	;AND MAXIMUM WITHIN SCREEN BOUNDARY?
	DIE	IWS		;NO
	MOVEM	N,MINN(X)	;OK, SAVE AWAY MINIMUM POSITION
	MOVEM	T1,MAXN(X)	;AND MAXIMUM POSITION
	TLO	F,FL.OUT	;ACT LIKE WE HAVE OUTPUT IN WINDOW
	PJRST	MAKEBP		;NOW MAKE BYTE POINTER AND RETURN
	SUBTTL	FUNCTION WHICH SETS TABS


;THIS FUNCTION IS USED TO SET WHERE TABS ARE ON THE SCREEN, SO THAT
;WHEN A TAB CHARACTER IS OUTPUT, WE JUMP TO THE NEXT TAB SETTING.
;BY LETTING HIM CHANGE THE TABS, WE ALLOW VERSATILITY IN HIS OUTPUT.
;NOTE THAT TABS ARE SET ALWAYS WITH RESPECT TO THE SCREEN, NEVER TO
;A WINDOW.  USER CALLS THIS ROUTINE WITH:
;
;	TAB$	ADDR		;LOCATION OF THE TABS
;
;WHERE ADDR CONTAINS A BIT TABLE OF WHERE THE TABS ARE, STARTING WITH
;THE FIRST BIT OF THE FIRST WORD BEING THE LEFT HAND EDGE OF THE SCREEN.
;IF THE ADDRESS GIVEN IS ZERO, WE SUPPLY DEFAULT TABS.



FUNTAB:	TRNN	A,-1		;DOES HE HAVE HIS OWN TABS?
DFTTAB:	MOVEI	A,REGTAB	;NO, THEN USE DEFAULT ONES
	MOVSI	T4,-4		;GET READY FOR LOOP
	HRR	T4,X		;POINT AT DATA

TABPUT:	PUSHJ	P,GETWRD	;GRAB THE NEXT WORD OF BITS
	MOVEM	T1,TABS(T4)	;SAVE THEM AWAY
	AOBJN	T4,TABPUT	;AND LOOP FOR ALL OF THEM
	POPJ	P,		;THEN RETURN



;THE DEFAULT TABS FOLLOW (EVERY EIGHT POSITIONS ON THE SCREEN)


	TAB%%==401002004010	;STARTING POINT OF MAKING TAB TABLE


REGTAB:	REPEAT	4,<

	EXP	TAB%%			;;PUT IN THE TABS FOR SOME LOCATIONS
	TAB%%==<TAB%%_4>!<TAB%%_-4>	;;AND GENERATE NEW TABS FOR NEXT ONE
>
	SUBTTL	FUNCTION WHICH SETS PARAMETERS


;THIS FUNCTION IS CALLED TO SET PARAMETERS WHICH CONTROL EXACTLY HOW
;WE DO CERTAIN THINGS.  THIS ALLOWS THE USER TO CONTROL WHAT HAPPENS MORE
;EXACTLY THAN OTHERWISE.  CALL IS:
;
;	SET$	[FUNCTION,,VALUE]	;SET DESIRED THING
;	(RETURN)			;ALL DONE
;OR:
;	SET$	[0,,NUMBER OF FUNCTIONS
;		 FUNCTION1,,VALUE1
;		 FUNCTION2,,VALUE2
;			...
;		 FUNCTIONN,VALUEN]	;SET BUNCH OF VALUES
;
;WE USE AC'S  T1, T2, AND T4



FUNSET:	PUSHJ	P,GETWRD	;GRAB THE USER'S ARGUMENT
	TLNN	T1,-1		;LEFT HALF ZERO?
	SKIPA	T4,T1		;YES, GET COUNT OF THINGS TO SET
	TDZA	T4,T4		;NO, THEN SET COUNT TO JUST 1 THING

SETLOP:	PUSHJ	P,GETWRD	;GRAB THE NEXT THING TO GRUNGE ON
	HLRE	T2,T1		;GET FUNCTION
	SKIPLE	T2		;OUT OF RANGE?
	CAILE	T2,MAXSET	;MAYBE
	DIE	ISF		;YES, DIE
	XCT	SETTAB-1(T2)	;SET THE PARAMETER
	SOJG	T4,SETLOP	;AND DO NEXT ONE
	POPJ	P,		;UNTIL DID ALL
;TABLE OF INSTRUCTIONS FOR THE VARIOUS FUNCTIONS.


SETTAB:	DPB	T1,[POINT 1,F,^L<(FL.ACR)>] ;(1)  AUTOMATIC CRLFS
	DPB	T1,[POINT 1,F,^L<(FL.NZP)>] ;(2)  DON'T CLEAR REST OF WINDOWS
	DPB	T1,[POINT 1,F,^L<(FL.NOS)>] ;(3)  CALL USER DIRECTLY
	HRRZM	T1,OUTADR(X)		    ;(4)  SET CHARACTER ROUTINE
	HRRZM	T1,ERRADR(X)		    ;(5)  SET ERROR ROUTINE
	PUSHJ	P,WNDSET		    ;(6)  SET WINDOW MOVEMENT
	DPB	T1,[POINT 1,F,^L<(FL.OKU)>] ;(7)  UPDATING SAME PLACE IS OK
	HRRZM	T1,EATNUM(X)		    ;(10) SET NUMBER OF LINES TO EAT

	MAXSET==.-SETTAB		;MAXIMUM FUNCTION



;HERE TO SET WORD WITH WINDOW MOVING INFORMATION.


WNDSET:	PUSH	P,A		;SAVE UUO SINCE MAYBE MORE FUNCTIONS
	MOVE	A,T1		;SET UP ADDRESS OF DATA WE WANT
	PUSHJ	P,GETWRD	;OBTAIN THE REAL ARGUMENT
	MOVEM	T1,OVFVAL(X)	;SAVE IT
	POP	P,A		;RESTORE THE UUO
	POPJ	P,		;RETURN
	SUBTTL	FUNCTION TO RETURN LOCATION IN WINDOW


;THIS FUNCTION IS USED TO GET THE PRESENT LOCATION OF WHERE WE ARE
;OUTPUTTING ON THE SCREEN.  THIS WAY, USER PROGS CAN SEE IF THEY ARE
;OVERFLOWING WINDOWS, OR THEY CAN MAKE THEIR OUTPUT BETTER.  WE
;ALSO RETURN WHETHER OR NOT THE USER HAS OVERFLOWED THE WINDOW HE
;IS OUTPUTTING IN.  CALL IS:
;
;	LOC$	ADDRESS		;RETURN LOCATION ON SCREEN WE ARE AT
;	(RETURN)		;GOT IT IN LOCATION ADDRESS
;
;ADDRESS WILL CONTAIN    LINE,,POSITION    NORMALLY.  BUT IF THE
;PRESENT LINE HAS BEEN OVERFLOWED, POSITION = -1.  IF THE WHOLE
;WINDOW HAS BEEN OVERFLOWED,  THE WHOLE RESULT IS -1.




FUNLOC:	SETZ	C,		;MAKE A NULL, SO STORE ROUTINE RETURNS
	CAMLE	N,MAXN(X)	;ARE WE PAST RIGHT MARGIN?
	PUSHJ	P,OFFRHT	;MAYBE, GO MAKE SURE !!
	CAMLE	L,MAXL(X)	;SIMILARLY, ARE WE OFF END OF LAST WINDOW?
	PUSHJ	P,OVERFL	;MAYBE, MAKE ABSOLUTELY SURE !!
	CAMG	N,MAXN(X)	;ARE WE OFF THE RIGHT OF THE WINDOW?
	SKIPA	T1,N		;NO, GET POSITION IN T1
	MOVEI	T1,-1		;YES, SET RH TO -1 THEN
	CAMG	L,MAXL(X)	;NOW, HAVE WE OVERFLOWED ALL THE WINDOWS?
	TLOA	T1,(L)		;NO, SET LINE NUMBER IN LEFT HALF
	SETO	T1,		;YES, SET WHOLE RESULT TO -1
	PJRST	PUTWRD		;GO STORE VALUE AND RETURN
	SUBTTL	FUNCTION TO ADDRESS TO PARTICULAR SPOT ON SCREEN



;THIS FUNCTION IS USED IF THE USER WANTS TO MOVE THE CURSOR TO
;A PARTICULAR PLACE ON THE SCREEN.  WE REMEMBER THIS LOCATION
;FOR OURSELF TOO, SO THAT WE CAN MOVE FROM THERE TO WHERE WE
;WANT TO UPDATE THE SCREEN.  CALL IS:
;
;	ADR$	[FLAG+LINE,,COLUMN]	;GO TO GIVEN LOCATION
;
;IF THE FLAG BIT IS SET, WE DON'T ACTUALLY MOVE THERE, SO THE
;USER CAN INFORM US HE MOVED AROUND HIMSELF.



FUNADR:	PUSHJ	P,GETWRD	;READ USER'S WORD
	PUSH	P,N		;SAVE AC'S
	PUSH	P,L		;THAT WE DON'T WANT CHANGED
	HLRZ	L,T1		;GET LINE NUMBER
	ANDCMI	L,AD$NOM	;CLEAR THE FLAG BIT
	HRRZ	N,T1		;GET COLUMN NUMBER
	CAMG	L,T.LEN(U)	;ILLEGAL LINE NUMBER GIVEN?
	CAMLE	N,T.WID(U)	;OR ILLEGAL COLUMN POSITION?
	  DIE	IPG		;YES, LOSE
	TLNN	T1,AD$NOM	;WANTS TO ACTUALLY MOVE THERE?
	PUSHJ	P,MOVE		;YES, DO SO
	DMOVEM	L,TTYL(X)	;SAVE LOCATION WE ARE NOW AT
	POP	P,L		;RESTORE AC'S
	POP	P,N		;THAT WE DIDN'T WANT HURT
	POPJ	P,		;AND RETURN
	SUBTTL	FUNCTION TO OUTPUT SPECIAL THINGS STRAIGHT TO TTY


;THIS FUNCTION IS SO USER PROG CAN OUTPUT CERTAIN THINGS TO THE TTY
;WHILE NOT KNOWING HOW TO GO ABOUT IT.  THE THINGS WE CAN OUTPUT ARE
;PRETTY LIMITED, BUT THAT IS BECAUSE NOT EVERYTHING CAN BE DONE FOR
;A PARTICULAR TERMINAL.  CALL IS:
;
;	TTY$	FUNCTION	;OUTPUT SOMETHING
;	(RETURN)		;OK
;



FUNTTY:	MOVEI	A,(A)		;GET ARGUMENT BY ITSELF
	CAILE	A,TTYMAX	;TOO LARGE?
	DIE	ITF		;YES, DIE BIG
	PJRST	@TTYTAB(A)	;NO, OUTPUT IT AND RETURN




;THE THINGS WE OUTPUT FOLLOW



TTYTAB:	EXP	DOHOM		;(0) TO HOME UP
	EXP	DOCLR		;(1) TO HOME UP AND CLEAR THE SCREEN


	TTYMAX==.-TTYTAB-1	;MAXIMUM FUNCTION
	SUBTTL	SUBROUTINE TO SCAN A LINE FOR CHANGES


;THIS SUBROUTINE IS CALLED TO SCAN A LINE OF THE SCREEN, RETURN NICE
;THINGS ABOUT THE LINE WHICH NEED CHANGING.  CALL IS:
;
;	MOVE	L,LINE NUMBER		;SET UP LINE TO LOOK AT
;	PUSHJ	P,MINMAX		;FIND OUT ABOUT LINE CHANGES
;	(NO CHANGES)			;THIS LINE NEEDS NO CHANGING
;	(CHANGES NEEDED)		;CHANGES ARE TO BE DONE
;
;ON A SKIP RETURN, THE FOLLOWING INFORMATION IS KNOWN:
;
;	FSTCHG	-  FIRST COLUMN ON LINE WHICH NEEDS CHANGING
;	LSTCHG	-  LAST COLUMN ON LINE TO NEED CHANGING
;	PRECHG	-  LAST COLUMN PREVIOUS TO CURRENT COLUMN TO NEED CHANGING
;	LSTNON	-  LAST COLUMN ON LINE WHICH WASN'T A SPACE, -1 IF NONE




MINMAX:	MOVEI	T4,LINCHG(X)	;POINT AT LINE CHANGES
	HRLI	T4,L		;INSERT INDEX ACCUMULATOR
	SKIPE	@T4		;ANY CHANGES INDICATED FOR THIS LINE?
	AOSA	(P)		;YES, SET UP SKIP RETURN
	  POPJ	P,		;NO, NON-SKIP RETURN
	SETZM	@T4		;CLEAR CHANGE FLAG SINCE NOW ON LINE
	MOVE	T1,T.WRDS(U)	;GET NUMBER OF WORDS OF STORAGE PER LINE
	IMULI	T1,(L)		;MAKE OFFSET INTO SCREEN FOR THIS LINE
	ADD	T1,[POINT 9,SCREEN(X)] ;MAKE POINTER TO START OF LINE
	SETZB	T2,PRECHG	;INITIALIZE FOR LOOP
	SETOM	LSTNON		;MORE
	SETOM	LSTCHG		;MORE
	SETOM	FSTCHG		;AND MORE


;HERE TO LOOK AT NEXT CHARACTER ON THE LINE


MINNXT:	ILDB	T3,T1		;GRAB NEXT CHAR ON LINE
	TRZN	T3,UPDATE	;THIS POSITION CHANGED?
	  JRST	MINNOU		;NO, GO DO NEXT ONE
	SKIPGE	FSTCHG		;SAVED FIRST CHANGE COLUMN YET?
	MOVEM	T2,FSTCHG	;NO, THEN THIS IS FIRST
	MOVEM	T2,LSTCHG	;COLUMN IS LAST TO NEED CHANGING SO FAR
	CAMGE	T2,TTYN(X)	;BEFORE CURRENT TTY POSITION?
	MOVEM	T2,PRECHG	;YES, REMEMBER POSITION THEN
MINNOU:	CAIE	T3,SP		;IS THIS CHARACTER A SPACE?
	MOVEM	T2,LSTNON	;NO, REMEMBER LAST NON-SPACE COLUMN
	CAMGE	T2,T.WID(U)	;MORE CHARACTERS TO LOOK AT?
	AOJA	T2,MINNXT	;YES, KEEP GOING
	POPJ	P,		;NO, THEN RETURN ALL DONE
	SUBTTL	ROUTINE TO CLEAR THE REST OF A WINDOW


;THIS ROUTINE IS CALLED WHENEVER WE ARE DONE WITH A WINDOW.  THIS
;MEANS WHEN WINDOWS ARE CHANGED, OR WE UPDATE OR REFRESH THE SCREEN.
;THE PURPOSE OF THIS IS SO WHEN A USER DOESN'T FINISH FILLING THE
;WINDOW WITH DATA, THEN WINDOW DOESN'T HAVE OLD JUNK LEFT, IT IS
;EATEN AS IF HE TYPED INFINITE SPACES.



ZAPEND:	SETZM	EATNUM(X)	;CLEAR NUMBER OF LINES TO EAT
	TLNE	F,FL.OUT	;NOTHING BEEN OUTPUT IN WINDOW YET?
	TLNE	F,FL.NZP	;OR USER NOT WANT WINDOW CLEARED?
	  JRST	CLROVF		;YES, JUST CLEAR  OVFVAL AND RETURN
	TLO	F,FL.AC2	;SET SO WILL DO AUTO-CRLFS
	MOVEI	C,SP		;GET A SPACE

ZAPLOP:	PUSHJ	P,STORE1	;STUFF IT AWAY IN THE SCREEN
	CAMLE	L,MAXL(X)	;NOT DONE WITH WINDOW YET?
	SKIPE	OVFVAL(X)	;OR MORE WINDOWS LEFT TO CLEAR?
	JRST	ZAPLOP		;YES, THEN KEEP GIVING SPACES
	TLZ	F,FL.AC2	;CLEAR SPECIAL FLAG
	POPJ	P,		;AND RETURN
	SUBTTL	ROUTINES TO READ AND STORE WORDS FROM THE USER




;THESE ROUTINES ARE CALLED TO READ OR WRITE THE USER'S CORE.  THE
;REASON A STRAIGHT MOVE OR MOVEM IS IMPOSSIBLE IS BECAUSE THE ADDRESS
;TO USE MIGHT BE IN THE SAVED AC AREA, AND WE HAVE TO RELOCATE THE
;ADDRESS IN THIS CASE.



;HERE TO READ INTO T1 THE WORD POINTED TO BY AC A.  THE AC IS INCREMENTED
;ALSO, SO THAT SUCCESSIVE CALLS WILL READ SUCCESSIVE WORDS.


GETWRD:	MOVEI	A,1(A)		;CLEAR LEFT HALF AND INCREMENT
	CAIG	A,U+1		;IS THE WORD IN A SAVED AC?
	SKIPA	T1,SAVEF-1(A)	;YES, GET IT
	MOVE	T1,-1(A)	;NO, GET DIRECTLY THEN
	POPJ	P,		;AND RETURN




;HERE TO STORE THE CONTENTS OF AC T1 INTO THE ADDRESS GIVEN
;IN RIGHT HALF OF AC A.


PUTWRD:	ANDI	A,-1		;ONLY KEEP THE ADDRESS HALF
	CAIG	A,U		;IS IT ONE OF HIS AC'S WE SAVED?
	ADDI	A,SAVEF		;YES, OFFSET TO SAVED AREA
	MOVEM	T1,(A)		;SAVE THE WORD AWAY
	POPJ	P,		;AND RETURN
	SUBTTL	ROUTINE TO MAKE A BYTE POINTER


;ROUTINE TO TAKE THE PRESENT LINE AND CHARACTER POSITION (AS GIVEN IN
;AC'S L AND N) AND CONSTRUCT A BYTE POINTER WHICH POINTS TO THE BYTE
;JUST PRIOR TO THAT LOCATION.  POINTER IS RETURNED IN AC B.  CALL IS:
;
;	MOVEI	L,LINE		;SET UP DESIRED LINE NUMBER
;	MOVEI	N,CHAR		;AND DESIRED CHARACTER POSITION
;	PUSHJ	P,MAKEBP	;GENERATE BYTE POINTER
;	(RETURN)		;GOT IT IN AC B
;
;USES AC'S  T1, T2, AND B


MAKEBP:	MOVE	B,L		;GET LINE NUMBER
	IMUL	B,T.WRDS(U)	;MULTIPLY BY WORDS PER LINE
	MOVE	T1,N		;GET POSITION ON LINE
	IDIVI	T1,4		;DIVIDE BY CHARACTERS IN A WORD
	ADD	B,T1		;ADD IN WORDS IN THIS LINE WE ARE ON
	ADD	B,PNTTAB(T2)	;AND ADD WHICH BYTE, SCREEN LOCATION
	POPJ	P,		;AND RETURN




;THE LIST OF BYTE POINTERS FOR USE IN THE ABOVE ROUTINE


PNTTAB:	POINT	9,SCREEN-1(X),35	;LAST BYTE IN PREVIOUS WORD
	POINT	9,SCREEN(X),8		;FIRST BYTE IN THE WORD
	POINT	9,SCREEN(X),17		;SECOND BYTE IN THE WORD
	POINT	9,SCREEN(X),26		;THIRD BYTE IN THE WORD
	SUBTTL	ROUTINE TO MOVE TO A LOCATION ON THE SCREEN



;THIS ROUTINE IS CALLED WITH THE DESIRED POSITION TO MOVE TO IN
;AC'S L AND N, AND THE CURRENT TERMINAL CURSER POSITION IN LOCATIONS
;TTYL AND TTYN.  THE BEST WAY TO MOVE TO THE NEW POSITION IS CALCULATED,
;AND THE CURSER IS MOVED THERE THAT WAY.



MOVE:	CAMN	L,TTYL(X)	;SEE IF ALREADY AT DESIRED LOCATION
	CAME	N,TTYN(X)	;TO SAVE SOME WORK
	TROA	T1,-1		;NO, SET UP A LARGE NUMBER
	  POPJ	P,		;YES, THEN RETURN NOW
	HRRZM	T1,BEST		;SAVE LARGE NUMBER
	MOVEI	T1,[DIE	CDS]	;SET UP ERROR ROUTINE IN CASE CAN'T MOVE
	PUSHJ	P,CHKADR	;SEE HOW MANY CHARACTERS ADDRESSING TAKES
	CAML	L,TTYL(X)	;IS NEW LOCATION LOWER ON SCREEN?
	TDZA	T2,T2		;YES, CLEAR AC
	MOVEI	T2,1		;NO, SET LOW ORDER BIT
	CAMGE	N,TTYN(X)	;IS NEW LOCATION TO LEFT OF OLD?
	IORI	T2,2		;YES, SET BIT
	PJRST	@[ EXP	MOVDR		;DISPATCH FOR DOWN AND RIGHT
		   EXP	MOVUR		;UP AND RIGHT
		   EXP	MOVDL		;DOWN AND LEFT
		   EXP	MOVUL ](T2)	;UP AND LEFT



MOVDR:	PUSHJ	P,CHKDR		;SEE IF JUST MOVING IS BETTER
	PJRST	(T1)		;DISPATCH TO BEST ROUTINE

MOVDL:	PUSHJ	P,CHKDL		;SEE HOW GOOD DIRECT MOTION IS
	PUSHJ	P,CHKCDR	;SEE IF CR, DOWN, RIGHT IS BEST
	SKIPN	T.CR(U)		;CAN TERMINAL DO CR?
	PUSHJ	P,CHKHDR	;NO, THEN CHECK HOMING UP
	PJRST	(T1)		;DISPATCH TO BEST ROUTINE

MOVUR:	PUSHJ	P,CHKUR		;SEE HOW GOOD THE DIRECT ROUTE IS
	PUSHJ	P,CHKHDR	;SEE IF HOMING UP HELPS ANY
	PJRST	(T1)		;GO TO BEST ROUTINE

MOVUL:	PUSHJ	P,CHKUL		;CHECK OUT THE DIRECT MOTION
	PUSHJ	P,CHKHDR	;SEE HOW HOMING UP WORKS
	PUSHJ	P,CHKCUR	;SEE IF CR, UP AND RIGHT IS GOOD
	PJRST	(T1)		;DISPATCH TO BEST ROUTINE
;FOLLOWING ARE THE ROUTINES TO SEE IF A PARTICULAR WAY OF MOVING
;TAKES FEWER CHARACTERS THAN THE PRECEEDING WAYS.  LOWEST NUMBER OF
;CHARS IS IN ADDRESS BEST, AND ROUTINE WHICH DOES THAT ACTION IS IN T1.



;ROUTINE TO COMPUTE THE COST OF ADDRESSING.
;THIS ROUTINE KNOWS IT IS THE FIRST ROUTINE CALLED.


CHKADR:	SKIPN	T2,T.ADR(U)	;SEE IF ADDRESSING IS POSSIBLE
	  POPJ	P,		;NO, THEN RETURN
	TRNE	F,FR.ANS	;ANSI MODE ADDRESSING?
	JRST	ANSICK		;YES, DIFFERENT COMPUTATIONS
	ADD	T2,T.ADR2(U)	;ADD IN MORE CHARACTERS
	ADD	T2,T.ADR3(U)	;AND ADD IN MORE CHARS
	MOVEI	T2,2(T2)	;THEN ADD 2 CHARS FOR COORDINATES
CHKADF:	MOVEM	T2,BEST		;REMEMBER NUMBER OF CHARS NEEDED
	MOVEI	T1,DOADR	;SET UP ADDRESS FOR ADDRESSING
	POPJ	P,		;RETURN


ANSICK:	MOVEI	T1,1(N)		;GET COLUMN NUMBER
	PUSHJ	P,COLADD	;ADD IN DEPENDING ON SIZE
	MOVEI	T1,1(L)		;GET LINE NUMBER
	PUSHJ	P,COLADD	;ADD IN DEPENDING ON SIZE
	SKIPE	N		;ANY COLUMN?
	ADDI	T2,1		;YES, WILL NEED A SEMICOLON
	MOVEI	T2,1(T2)	;ACCOUNT FOR ENDING CHAR AND CLEAR JUNK
	JRST	CHKADF		;FINISH UP


COLADD:	CAIL	T1,^D100	;THREE DIGITS?
	ADDI	T2,1		;YES, COUNT IT
	CAIL	T1,^D10		;TWO DIGITS?
	ADDI	T2,1		;YES, COUNT IT
	CAIL	T1,2		;NEED ANY DIGITS?
	ADDI	T2,1		;YES, COUNT IT
	POPJ	P,		;DONE
;ROUTINE TO COMPUTE COST OF MOVING UP AND LEFT.


CHKUL:	SKIPE	T3,T.UP(U)	;CAN WE MOVE UP?
	SKIPN	T4,T.LEFT(U)	;AND CAN WE MOVE LEFT?
	  POPJ	P,		;NO, CAN'T DO THIS THEN
	MOVE	T2,TTYL(X)	;GET CURRENT LINE
	SUB	T2,L		;SUBTRACT DESIRED LINE
CHKANL:	IMULI	T2,(T3)		;COMPUTE CHARS NEEDED TO MOVE UP
	MOVE	T3,TTYN(X)	;GET CURRENT COLUMN
	SUB	T3,N		;AND SUBTRACT DESIRED COLUMN
CHKANY:	IMULI	T3,(T4)		;COMPUTE CHARS NEEDED TO MOVE LEFT
	MOVEI	T4,DOANY	;SET UP ROUTINE TO DO ACTION

CHKALL:	ADD	T2,T3		;ADD TOGETHER
	CAML	T2,BEST		;BETTER THAN OLD BEST?
	  POPJ	P,		;NO, RETURN
	MOVEM	T2,BEST		;YES, SAVE NUMBER
	MOVE	T1,T4		;AND ROUTINE TO DO IT
	MOVE	T4,TABNUM	;GET NUMBER OF TABS THAT WILL BE USED
	MOVEM	T4,TABUSE	;AND SET IT
	POPJ	P,		;RETURN
;ROUTINE TO COMPUTE COST OF MOVING DOWN AND LEFT.


CHKDL:	SKIPN	T3,T.DOWN(U)	;CAN WE MOVE DOWN?
	CAMN	L,TTYL(X)	;NO, BUT OK IF DON'T HAVE TO
	SKIPN	T4,T.LEFT(U)	;CAN WE MOVE LEFT TOO?
	  POPJ	P,		;NO, RETURN
	MOVE	T2,L		;GET DESIRED LINE NUMBER
	SUB	T2,TTYL(X)	;SUBTRACT PRESENT LINE
	JRST	CHKANL		;JOIN OTHER CODE




;ROUTINE TO COMPUTE COST OF MOVING DOWN AND RIGHT.


CHKDR:	SKIPN	T.DOWN(U)	;SEE IF CAN MOVE DOWN
	CAMN	L,TTYL(X)	;OR SEE IF DON'T NEED TO
	JRST	.+2		;OK, PROCEED
	  POPJ	P,		;CAN'T DO THIS, RETURN
	PUSHJ	P,CHKTAB	;COMPUTE COUNT FOR MOVING RIGHT
	MOVE	T3,L		;GET LINE TO MOVE TO
	SUB	T3,TTYL(X)	;SUBTRACT CURRENT LINE
	MOVE	T4,T.DOWN(U)	;GET NUMBER NEEDED TO GO DOWN
	JRST	CHKANY		;JOIN COMMON CODE




;ROUTINE TO COMPUTE COST OF MOVING UP AND RIGHT.


CHKUR:	SKIPN	T.UP(U)		;SEE IF WE CAN MOVE UP
	  POPJ	P,		;NO, RETURN
	PUSHJ	P,CHKTAB	;YES, COMPUTE COUNT FOR MOVING RIGHT
	MOVE	T3,TTYL(X)	;GET CURRENT LINE
	SUB	T3,L		;SUBTRACT DESTINATION LINE
	MOVE	T4,T.UP(U)	;GET CHARS NEEDED TO GO UP
	JRST	CHKANY		;JOIN OTHER CODE
;ROUTINE TO COMPUTE COST OF HOMING UP, THEN MOVING DOWN AND RIGHT.


CHKHDR:	SKIPN	T.DOWN(U)	;MAKE SURE WE CAN MOVE DOWN
	CAMN	L,TTYL(X)	;OR THAT WE DON'T HAVE TO
	SKIPN	T.HOM(U)	;AND MAKE SURE WE CAN HOME UP
	  POPJ	P,		;NO, THEN CAN'T DO THIS
	PUSH	P,TTYN(X)	;SAVE CURRENT POSITION
	SETZM	TTYN(X)		;CLEAR POSITION AS IF HOME WAS DONE
	PUSHJ	P,CHKTAB	;SEE HOW MANY TO MOVE RIGHT
	POP	P,TTYN(X)	;RESTORE TRUE COLUMN NUMBER
	MOVE	T3,T.HOM(U)	;GET CHARS NEEDED FOR CARRIAGE RETURN
	ADDI	T2,(T3)		;ADD INTO TOTAL
	HRRZ	T3,T.DOWN(U)	;GET CHARS NEEDED TO DO DOWN
	IMULI	T3,(L)		;MULTIPLY BY DESTINATION LINE
	MOVEI	T4,DOHDR	;GET ROUTINE FOR THIS ACTION
	JRST	CHKALL		;GO SEE IF THIS IS BEST



;ROUTINE TO COMPUTE COST OF DOING CR, THEN MOVING DOWN AND RIGHT.


CHKCDR:	SKIPN	T.DOWN(U)	;CAN WE MOVE DOWN?
	CAMN	L,TTYL(X)	;OR WE DON'T HAVE TO?
	SKIPN	T.CR(U)		;AND CAN WE DO A CARRIAGE RETURN?
	  POPJ	P,		;NO, RETURN
	PUSH	P,TTYN(X)	;SAVE CURRENT POSITION
	SETZM	TTYN(X)		;CLEAR POSITION AS IF A CR WAS DONE
	PUSHJ	P,CHKTAB	;AND COMPUTE COUNT FOR MOVING RIGHT
	POP	P,TTYN(X)	;RESTORE TRUE COLUMN NUMBER
	MOVE	T3,T.CR(U)	;GET CHARS USED FOR CARRIAGE RETURN
	ADDI	T2,(T3)		;ADD IT IN
	MOVE	T3,L		;GET DESTINATION LINE
	SUB	T3,TTYL(X)	;AND SUBTRACT CURRENT ONE
	MOVE	T4,T.DOWN(U)	;GET CHARS NEEDED TO MOVE DOWN
	IMULI	T3,(T4)		;FIND TOTAL CHARS TO MOVE DOWN
	MOVEI	T4,DOCDR	;GET ROUTINE TO DO ACTION
	JRST	CHKALL		;SEE IS THIS IS BEST METHOD
;ROUTINE TO COMPUTE COST OF DOING CARRIAGE RETURN, THEN UP AND RIGHT.


CHKCUR:	SKIPE	T.CR(U)		;SEE IF CAN DO CARRIAGE RETURN
	SKIPN	T.UP(U)		;AND SEE IF CAN GO UP
	  POPJ	P,		;NO, RETURN
	PUSH	P,TTYN(X)	;SAVE CURRENT COLUMN
	SETZM	TTYN(X)		;ASSUME WE DID A CARRIAGE RETURN
	PUSHJ	P,CHKTAB	;SEE HOW MANY TO MOVE RIGHT
	POP	P,TTYN(X)	;RESTORE TRUE COLUMN
	MOVE	T3,T.CR(U)	;GET CHARS NEEDED FOR CR
	ADDI	T2,(T3)		;ADD IN
	MOVE	T3,TTYL(X)	;GET CURRENT LINE NUMBER
	SUB	T3,L		;SUBTRACT DESTINATION LINE
	MOVE	T4,T.UP(U)	;GET COUNT TO MOVE UP
	IMULI	T3,(T4)		;FIND TOTAL CHARS NEEDED TO MOVE DOWN
	MOVEI	T4,DOCDR	;GET ROUTINE TO DO ACTION
	JRST	CHKALL		;AND SEE IF THIS IS BEST
;ROUTINE TO COMPUTE COST OF MOVING RIGHT.
;THIS IS A SUBROUTINE CALLED BY THE PREVIOUS ROUTINES.
;IT SAVES THE NUMBER OF TABS NEEDED FOR LATER.
;RETURNS WITH TOTAL CHARS NEEDED IN AC T2.


CHKTAB:	SETZB	T2,TABNUM	;CLEAR NUMBER OF TABS NEEDED
	CAMN	N,TTYN(X)	;ALREADY AT CORRECT COLUMN?
	  POPJ	P,		;YES, RETURN NOW
	TRNN	F,FR.TAB	;DOES THIS TERMINAL HAVE TABS?
	  JRST	CHKSPS		;NO, JUST MOVE RIGHT
	MOVE	T2,N		;GET COLUMN WE DESIRE TO GET TO
	IORI	T2,7		;MOVE TO FAR RIGHT OF TAB COLUMN
	SUB	T2,TTYN(X)	;SUBTRACT CURRENT POSITION
	LSH	T2,-3		;COMPUTE NUMBER OF TABS NEEDED
	MOVEM	T2,TABNUM	;SAVE NUMBER OF TABS NECESSARY
	TRNN	N,7		;GOING TO EXACT TAB STOP?
	  POPJ	P,		;YES, ALL DONE
	JUMPE	T2,CHKTBN	;JUMP SOME IF USING NO TABS
	MOVE	T3,N		;GET COLUMN MOVING TO
	TRZA	T3,7		;BACK UP TO PREVIOUS TAB STOP
CHKTBN:	MOVE	T3,TTYN(X)	;IF NO TABS, GET CURRENT POSITION
	MOVE	T2,N		;GET COPY OF POSITION
	SUB	T2,T3		;COMPUTE NUMBER OF SPACES NEEDED
	SKIPN	T4,T.LEFT(U)	;CAN WE GO LEFT?
	  JRST	CHKSPT		;NO, THEN ALWAYS MOVE RIGHT
	MOVEI	T3,^D10(N)	;GET COLUMN POSITION PLUS SOME
	CAMLE	T3,T.WID(U)	;GETTING NEAR END OF SCREEN?
	  JRST	CHKSPT		;YES, THEN CAN'T TAB AND BACK UP
	MOVE	T3,N		;GET COLUMN TO MOVE TO
	IORI	T3,7		;MOVE TO FAR RIGHT OF COLUMN
	SUBI	T3,-1(N)	;COMPUTE COLUMNS TO BACK UP BY
	IMULI	T3,(T4)		;MULTIPLY BY CHARS TO BACK UP 1 PLACE
	ADDI	T3,1		;ADD A CHAR DUE TO THE TAB
	CAML	T3,T2		;TAKES LESS CHARS TO BACK UP?
	  JRST	CHKSPT		;NO, GO USE SPACES
	AOS	T2,TABNUM	;YES, INCREMENT TAB COUNT
	ADDI	T2,-1(T3)	;ADD CHARS NEEDED TO BACKSPACE
	POPJ	P,		;AND RETURN


CHKSPS:	MOVE	T2,N		;GET COLUMN TO MOVE TO
	SUB	T2,TTYN(X)	;SUBTRACT COLUMN WE ARE AT
CHKSPT:	ADD	T2,TABNUM	;ADD IN TABS NEEDED
	POPJ	P,		;THEN RETURN
	SUBTTL	ROUTINES TO MOVE SLOWLY TO A LOCATION



;THESE ROUTINES ARE CALLED WITH THE COLUMN AND LINE NUMBERS IN N AND L,
;AND THE CURRENT POSITION IN TTYN AND TTYL.  THE ROUTINE MOVES THE
;CURSOR LEFT, RIGHT, UP, OR DOWN TO GET THERE.



DOHDR:	PUSHJ	P,DOHOM		;HOME UP
	JRST	DOANY		;THEN GO TO NORMAL CODE

DOCDR:	PUSHJ	P,DOCR		;DO A CARRIAGE RETURN FIRST
				;THEN FALL INTO NORMAL CODE



DOANY:	CAMN	L,TTYL(X)	;ALREADY AT RIGHT LINE?
	  JRST	MOVCOL		;YES, GO CHECK COLUMN
	CAMG	L,TTYL(X)	;WANT TO MOVE DOWN?
	  JRST	MOVUP		;NO, GO MOVE UP

MOVDWN:	PUSHJ	P,DODOWN	;YES, MOVE THAT WAY
	CAME	L,TTYL(X)	;AT RIGHT COLUMN YET?
	  JRST	MOVDWN		;NO, KEEP GOING
	JRST	MOVCOL		;YES, NOW CHECK COLUMN

MOVUP:	PUSHJ	P,DOUP		;MOVE UP
	CAME	L,TTYL(X)	;AT RIGHT LINE YET?
	  JRST	MOVUP		;NO, KEEP LOOKING





MOVCOL:	CAMLE	N,TTYN(X)	;WANT TO MOVE TO RIGHT?
	  JRST	MOVRHT		;YES, GO DO IT
MOVLFT:	CAMN	N,TTYN(X)	;AT RIGHT COLUMN YET?
	  POPJ	P,		;YES, RETURN
	PUSHJ	P,DOLEFT	;NO, GO LEFT
	JRST	MOVLFT		;AND CHECK AGAIN
MOVRHT:	SKIPN	T3,TABUSE	;ANY TABS USED TO MOVE RIGHT?
	  JRST	MOVSPS		;NO, GO USE SPACES
	PUSHJ	P,DOTAB		;YES, OUTPUT A TAB
	SOJG	T3,.-1		;LOOP UNTIL DID THEM ALL
	CAML	N,TTYN(X)	;DID WE TAB BEYOND DESTINATION?
	  JRST	MOVSPS		;NO, GO FINISH WITH SPACES

MOVBCK:	PUSHJ	P,DOLEFT	;YES, MOVE LEFT
	CAMN	N,TTYN(X)	;REACHED DESTINATION?
	  POPJ	P,		;YES, ALL DONE
	JRST	MOVBCK		;NO, KEEP GOING


MOVSPS:	CAMN	N,TTYN(X)	;AT DESTINATION YET?
	  POPJ	P,		;YES, RETURN
	MOVE	T1,TTYL(X)	;GET CURRENT LINE
	IMUL	T1,T.WRDS(U)	;MULTIPLY BY WORDS PER LINE
	MOVE	T2,TTYN(X)	;GET CURRENT COLUMN
	IDIVI	T2,4		;DIVIDE BY CHARS TO A WORD
	ADD	T2,T1		;ADD IN WORDS INTO THIS LINE
	ADD	T2,PNTTAB(T3)	;MAKE A BYTE POINTER
MOVSPL:	ILDB	C,T2		;GET CHAR AT THIS POSITION
	PUSHJ	P,DOONE		;OUTPUT IT
	CAME	N,TTYN(X)	;REACHED RIGHT PLACE YET?
	  JRST	MOVSPL		;NO, KEEP GOING
	POPJ	P,		;YES, DONE
	SUBTTL	SUBROUTINE TO ADDRESS



;CALLED WITH NEW X AND Y COORDINATES IN AC'S N AND L, TO ADDRESS TO
;THAT POSITION.  CAN ONLY BE CALLED FOR TERMINALS CAPABLE OF DOING
;ADDRESSING.





DOADR:	DMOVEM	L,TTYL(X)	;SET NEW TERMINAL CURSOR POSITION
	MOVE	T1,T.ADR(U)	;GET SEQUENCE TO START
	PUSHJ	P,SEQOUT	;OUTPUT IT
	TRNE	F,FR.ANS	;ANSI STYLE TERMINAL?
	JRST	ANSIAD		;YES, ADDRESSING DIFFERS
	HRRZ	T3,N		;GET POSITION ON LINE TO GO TO
	ADD	T3,T.XOFF(U)	;ADD IN OFFSET FOR OUTPUT
	HRRZ	C,L		;GET LINE NUMBER TO GO TO
	ADD	C,T.YOFF(U)	;ADD IN ITS OFFSET ALSO
	TRNE	F,FR.XBY	;SHOULD X COORDINATE BE FIRST?
	EXCH	C,T3		;YES, SWAP THE COORDINATES
	PUSHJ	P,TTYOUT	;OUTPUT THE FIRST COORDINATE
	SKIPE	T1,T.ADR2(U)	;ANY FILLER BETWEEN COORDINATES?
	PUSHJ	P,SEQOUT	;YES, OUTPUT THAT
	MOVE	C,T3		;GET SECOND COORDINATE
	PUSHJ	P,TTYOUT	;OUTPUT IT
	SKIPE	T1,T.ADR3(U)	;ANY FILLS AFTER COORDINATE?
	JRST	SEQOUT		;YES, GO GIVE IT AND RETURN
	POPJ	P,		;NO, ALL DONE



ANSIAD:	SKIPE	T1,L		;ANY LINE POSITION?
	PUSHJ	P,DECOU1	;YES, OUTPUT IT
	JUMPE	N,ANSIAE	;SKIP SOME IF AT FIRST COLUMN
	MOVEI	C,";"		;GET SEPARATOR CHAR
	PUSHJ	P,TTYOUT	;OUTPUT IT
	MOVE	T1,N		;GET COLUMN
	PUSHJ	P,DECOU1	;OUTPUT IT
ANSIAE:	MOVEI	C,"H"		;GET ENDING CHAR
	JRST	TTYOUT		;OUTPUT IT
	SUBTTL	SPECIAL SEQUENCE OUTPUT ROUTINES




;HERE TO OUTPUT SPECIAL SEQUENCES OF CHARACTERS FOR A TERMINAL.
;THESE ROUTINES KEEP THE VALUES OF TTYN AND TTYL CORRECT.
;THESE ROUTINE CAN USE T1, T2, AND C.




DOTAB:	MOVEI	C,7		;GET SET
	IORM	C,TTYN(X)	;SET TO FAR RIGHT OF CURRENT COLUMN
	AOS	TTYN(X)		;THEN MOVE TO NEXT TAB STOP
	MOVEI	C,TAB		;GET A TAB CHARACTER
	PJRST	TTYOUT		;OUTPUT IT AND RETURN



DOEOL:	MOVE	T3,LSTNON	;GET LOCATION OF LAST NONSPACE
	CAMGE	T3,LSTCHG	;IS LAST CHANGE BEYOND THAT?
	MOVE	T3,LSTCHG	;YES, GET THAT LOCATION
	SUB	T3,TTYN(X)	;GET NUMBER OF SPACES TO CLEAR LINE
	ADDI	T3,1		;ADD ONE MORE
	SKIPE	T1,T.EOL(U)	;GET SEQUENCE TO DO END OF LINE
	CAIGE	T3,(T1)		;AND SEE IF FASTER TO TYPE SPACES
	SKIPA	C,[SP]		;YES, GET A SPACE
	  PJRST	SEQOUT		;NO, FASTER TO DO END OF LINE SEQUENCE
	PUSHJ	P,DOONE		;OUTPUT A SPACE
	SOJG	T3,.-1		;LOOP REQUIRED TIMES
	POPJ	P,		;THEN RETURN


DOUP:	SOSA	TTYL(X)		;DECREMENT TERMINAL'S LINE NUMBER
DODOWN:	AOSA	TTYL(X)		;OR INCREMENT LINE NUMBER
	SKIPA	T1,T.UP(U)	;THEN GET SEQUENCE TO MOVE UP
	MOVE	T1,T.DOWN(U)	;OR SEQUENCE TO MOVE DOWN
	JRST	SEQOUT		;GO OUTPUT IT


DOCR:	SETZM	TTYN(X)		;CLEAR COLUMN USER SEES CURSER AT
	MOVE	T1,T.CR(U)	;GET SEQUENCE TO DO CR
	JRST	SEQOUT		;GO OUTPUT IT
DOLEFT:	SOSA	TTYN(X)		;DECREMENT COLUMN NUMBER
DORHT:	AOSA	TTYN(X)		;OR INCREMENT IT
	SKIPA	T1,T.LEFT(U)	;GET SEQUENCE TO MOVE LEFT
	MOVE	T1,T.RHT(U)	;OR SEQUENCE TO MOVE RIGHT
	JRST	SEQOUT		;OUTPUT IT AND RETURN



DOONE:	CAIN	C,SP		;OUTPUTTING A SPACE?
	MOVE	C,T.EATC(U)	;YES, CONVERT TO EATING CHAR
	AOS	T1,TTYN(X)	;INCREMENT COLUMN NUMBER
	CAMG	T1,T.WID(U)	;AT LAST COLUMN ON LINE?
	  JRST	TTYOUT		;NO, JUST OUTPUT CHAR AND RETURN
	SOS	TTYN(X)		;YES, BACK UP POSITION
	TRNN	F,FR.ELC	;GET A CRLF TYPING LAST COLUMN?
	  JRST	TTYOUT		;NO, THEN TYPE THE CHAR AND RETURN
	MOVE	T1,TTYL(X)	;GET CURRENT LINE
	CAML	T1,T.LEN(U)	;ON LAST LINE?
	  POPJ	P,		;YES, DON'T TYPE CHAR OR ELSE SCREEN SCROLLS!
	SETZM	TTYN(X)		;NO, CLEAR COLUMN
	AOS	TTYL(X)		;INCREMENT LINE NUMBER
	PJRST	TTYOUT		;THEN OUTPUT CHARACTER



DOCLR:	SKIPA	T1,T.CLR(U)	;GET SEQUENCE TO HOME AND CLEAR
DOHOM:	MOVE	T1,T.HOM(U)	;OR GET SEQUENCE TO JUST HOME
	SETZM	TTYL(X)		;RESET LINE POSITION USER SEES
	SETZM	TTYN(X)		;AND THE COLUMN POSITION
;	PJRST	SEQOUT		;GO OUTPUT IT
	SUBTTL	ROUTINES TO OUTPUT SEQUENCES OF CHARACTERS




;THIS ROUTINE IS CALLED WITH THE STANDARD POINTER TO A SEQUENCE OF
;CHARACTERS TO BE OUTPUT IN AC T1.  SUCH A POINTER IS OF THE FORM
; ADDR,,N  WHERE N IS THE NUMBER OF CHARACTERS IN THE STRING, AND
;ADDR IS THE ADDRESS OF THE STRING.




SEQOUT:	HLRZ	T2,T1		;GET ADDRESS OF STRING
	HRLI	T2,(POINT 7,)	;AND MAKE BYTE POINTER TO IT
	ANDI	T1,-1		;KEEP ONLY COUNT
	JUMPE	T1,[DIE CDS]	;IF NO CHARS, DIE

SEQOUL:	ILDB	C,T2		;GET NEXT CHARACTER IN SEQUENCE
	SOJLE	T1,TTYOUT	;IF LAST CHAR, GO OUTPUT AND RETURN
	PUSHJ	P,TTYOUT	;OUTPUT TO TERMINAL
	JRST	SEQOUL		;LOOP





;CALLED TO OUTPUT A DECIMAL NUMBER IN T1.  USED FOR ANSI MODE ADDRESSING,
;WHERE COORDINATES ARE DECIMAL INTEGERS.


DECOU1:	ADDI	T1,1		;COORDINATES ARE OFFSET BY ONE
DECOUT:	IDIVI	T1,^D10		;SPLIT OFF A DIGIT
	JUMPE	T1,DECFIN	;JUMP IF DONE
	HRLM	T2,(P)		;SAVE DIGIT
	PUSHJ	P,DECOUT	;LOOP UNTIL HAVE ALL DIGITS
	HLRZ	T2,(P)		;GET BACK A DIGIT
DECFIN:	MOVEI	C,"0"(T2)	;MAKE INTO ASCII
	JRST	TTYOUT		;OUTPUT IT AND RETURN
	SUBTTL	ROUTINES TO CLEAR OR SET IMAGE STATE FOR TERMINAL




;CALLED TO SET THE MODE OF THE TERMINAL TO BE IMAGE MODE.  THIS MODE
;IS NECESSARY TO PREVENT THE CONVERSION OF OUR OUTPUT CHARACTERS TO
;DIFFERENT ONES.  IN ADDITION, THE TERMINAL OUTPUT BUFFER IS SET UP.
;NO AC'S ARE CHANGED.  THIS ROUTINE IS NOT NECESSARY FOR TOPS-10.




	IF20,<

SETIMG:	PUSH	P,[POINT 7,TTYBUF(X)] ;GET BYTE POINTER
	POP	P,BUFPTR(X)	;INITIALIZE IT
	SKIPE	TTYJFN(X)	;NEED TO GET A JFN?
	  POPJ	P,		;NO, THEN ALL SET
	PUSH	P,T1		;SAVE SOME AC'S
	PUSH	P,T2		;THAT WE USE
	MOVSI	T1,(GJ%SHT+GJ%ACC)	;SHORT FORM, RESTRICTED
	HRROI	T2,[ASCIZ/TTY:/]	;OUR TERMINAL
	GTJFN			;GET THE JFN
	  DIE	IFF		;CAN'T
	MOVEM	T1,TTYJFN(X)	;SAVE THE JFN
	MOVE	T2,[8B5+OF%WR+OF%RD]	;SET FOR BINARY
	OPENF			;OPEN THE TERMINAL
	  DIE	IFF		;FAILED
	POP	P,T2		;RESTORE THE ACS
	POP	P,T1		;THAT WERE USED
	POPJ	P,		;RETURN
>
	SUBTTL	ROUTINE TO OUTPUT CHARS TO TTY OR TO USER PROGRAM



;SUBROUTINE TO SEND CHARACTERS OUT.  OUTPUT CAN BE SENT TO THE PROGRAM
;IF DESIRED.  OTHERWISE WE BUFFER UP CHARACTERS AND SEND THEM OUT
;OURSELVES.  CHARACTER TO BE OUTPUT IS IN AC C.




TTYOUT:	SKIPE	OUTADR(X)	;OUTPUT BEING INTERCEPTED?
	  JRST	USROUT		;YES, GO GIVE IT TO PROGRAM

IF20,<	TLON	F,FL.PNT	;FIRST OUTPUT?
	PUSHJ	P,SETIMG	;YES, SET UP BUFFERS AND JFN
	IDPB	C,BUFPTR(X)	;STORE CHAR IN BUFFER
	PUSH	P,T1		;SAVE AN AC
	AOS	T1,BUFCNT(X)	;INCREMENT COUNT OF STORED CHARACTERS
	CAIL	T1,<TTYLEN*5>-1	;IS BUFFER FULL YET?
	PUSHJ	P,PUNT		;YES, FORCE OUT BUFFER
	POP	P,T1		;RESTORE AC
	POPJ	P,		;RETURN
>


IF10,<	SKIPN	TTYJFN(X)	;HAVE ANY CHANNEL TO OUTPUT TO?
	IONEOU	C		;NO, OUTPUT STRAIGHT
	SKIPN	TTYJFN(X)	;WELL?
	  POPJ	P,		;NO, DONE
	PUSH	P,T1		;SAVE AN AC
	HLRZ	T1,TTYJFN(X)	;GET BUFFER HEADER ADDRESS
	SOSG	2(T1)		;ANY MORE ROOM LEFT IN BUFFER?
	PUSHJ	P,PUNT		;NO, FORCE OUTPUT NOW
	IDPB	C,1(T1)		;STORE THE CHARACTER
	TLO	F,FL.PNT	;REMEMBER OUTPUT EXISTS
	POP	P,T1		;RESTORE AC
	POPJ	P,		;DONE
>
	SUBTTL	ROUTINE TO FORCE OUT ALL OF TERMINAL OUTPUT SO FAR




;ROUTINE TO FORCE OUT TO THE TERMINAL ALL STORED CHARACTERS.
;NO AC'S ARE CHANGED.



PUNT:	IF20,<
	TLZ	F,FL.PNT	;NO LONGER NEED TO PUNT OUTPUT
	SKIPN	BUFCNT(X)	;ANY CHARACTERS TO BE OUTPUT?
	  POPJ	P,		;NO, JUST RETURN
	PUSH	P,T1		;YES, SAVE AN AC
	PUSH	P,T2		;SAVE SOME MORE AC'S
	PUSH	P,T3		;THAT WE NEED
	MOVE	T1,TTYJFN(X)	;GET JFN FOR OUTPUT
	HRROI	T2,TTYBUF(X)	;FROM TEXT BUFFER
	MOVN	T3,BUFCNT(X)	;GET COUNT OF CHARACTERS
	SOUT			;OUTPUT THE CHARS
	SETZM	BUFCNT(X)	;CLEAR COUNT
	MOVE	T1,[POINT 7,TTYBUF(X)] 	;GET A NEW BYTE POINTER
	MOVEM	T1,BUFPTR(X)	;AND RESET IT
	POP	P,T3		;RESTORE AC'S
	POP	P,T2		;THAT WERE SAVED
	POP	P,T1		;RESTORE THE AC
	POPJ	P,		;AND RETURN
>



	IF10,<

	TLZ	F,FL.PNT	;NO LONGER NEED TO PUNT OUTPUT
	SKIPN	TTYJFN(X)	;ANY OUTPUT CHANNEL SET UP?
	  POPJ	P,		;NO, DO NOTHING
	MOVEM	T1,TEMP		;SAVE AN AC
	HRLZ	T1,TTYJFN(X)	;GET CHANNEL
	LSH	T1,5		;POSITION TO AC FIELD
	TLO	T1,(<OUT 0,>)	;FINISH THE INSTRUCTION
	EXCH	T1,TEMP		;RESTORE AC AND STORE INSTRUCTION
	XCT	TEMP		;DO THE I/O
	  POPJ	P,		;DONE
	DIE	OPF		;FAILED
>
	SUBTTL	ROUTINE TO GIVE CHARS TO USER'S PROGRAM



;HERE WHEN USER WANTS TO GET OUTPUT WE WOULD NORMALLY GIVE TO THE
;TERMINAL.  THE USER HAS THE CHOICE OF HAVING HIS ORIGINAL AC'S, OR
;TO BE FASTER, IF FLAG FL.NZP  IS SET, WE JUMP DIRECTLY TO
;HIS ROUTINE, ASSUMING HE DOESN'T HURT ANY AC'S.  WE GIVE HIM ONE
;CHARACTER AT A TIME.  THE USER DOES THE FOLLOWING:
;
;	POP	P,AC		;BRING THE CHARACTER OFF OF THE STACK
;	   .
;	   .			; (THE USER'S RANDOM CODE)
;	   .
;	POPJ	P,		;RETURN TO DPY AND CONTINUE AS BEFORE
;
;CALL AT USRLST WHEN ALL OUTPUT FOR THIS UUO IS FINISHED, TO NOTIFY
;THE PROGRAM THAT WE ARE DONE BY SENDING A CHARACTER WITH 1B0 SET.




USRLST:	MOVSI	C,(1B0)		;FLAG THIS AS LAST OUTPUT
USROUT:	TLNN	F,FL.NZP	;DOES USER WANT HIS OWN ACS?
	  JRST	USRPAI		;YES, GO DO WORK
	PUSH	P,C		;NO, THEN JUST PUSH THE CHAR
	PJRST	@OUTADR(X)	;AND GO TO USER'S ROUTINE


;HERE IF WE MUST SAVE THE AC'S BEFORE CALLING USER


USRPAI:	PUSH	P,[USRRET]	;PUT THE RETURN ADDRESS ON THE STACK
	PUSH	P,C		;AND PUT THE CHARACTER ON TOO
	MOVEM	F,OURF(X)	;SAVE AN AC OF OURS
	MOVEI	F,@OUTADR(X)	;GET ADDRESS OF ROUTINE TO GO TO
	MOVEM	F,TEMP		;SAVE IT
	HRLI	F,T1		;SET UP
	HRRI	F,OURT1(X)	;BLT POINTER
	BLT	F,OURBU+1(X)	;SAVE ALL OF OUR AC'S
	MOVSI	U,SAVEF		;NOW GET SET
	BLT	U,U		;RESTORE ALL THE USER'S AC'S
	JRST	@TEMP		;AND GO TO THE USER'S ROUTINE


USRRET:	MOVEM	F,SAVEF		;SAVE A USER'S AC
	MOVE	F,[T1,,SAVET1]	;GET SET
	BLT	F,SAVEU		;SAVE ALL OF USER'S AC'S WE USE
	MOVE	X,@DP+$DPADR	;RESTORE RELOCATION AC
	MOVSI	U,OURF(X)	;GET SET
	BLT	U,U		;RESTORE OUR OWN AC'S
	POPJ	P,		;AND RETURN FROM THIS BIG MESS
	SUBTTL	THE ERROR ROUTINE


;WE GET HERE FROM ONE OF THE  DIE  CALLS, TO DIE.  WE EITHER OUTPUT A
;MESSAGE AND EXIT, OR GO BACK TO THE USER WITH AN ERROR CODE.  THE CALL IS:
;
;	XCT	CODE,DIEBIG	;GO DIE, AND GIVE ERROR CODE IN AC FIELD
;
;THERE IS NO RETURN.  IF THE USER TRAPPED THE ERROR, HE CAN DO THE FOLLOWING:
;
;	POP	P,LOCATION	;RESTORE THE ERROR CODE
;	POPJ	P,		;RETURN TO LOCATION AFTER DPY
;				;CALL WHICH FAILED


DIEBIG:	JSP	T2,.+1		;REMEMBER PC SO CAN GET ERROR CODE
	LDB	T2,[POINT 4,-1(T2),12]	;GRAB THE CODE
	CAILE	T2,MAXERR	;IS IT ILLEGAL !!!!????
	SETZ	T2,		;YES, TAME IT SOMEWHAT
	SKIPE	ERRADR(X)	;DID USER GIVE US A TRAP ADDRESS?
	  JRST	TRAP		;YES, GO TO HIM THEN


IF10,<	OUTSTR	[ASCIZ/
? DPY - /]			;NO, THEN GIVE SOME OF MESSAGE
	OUTSTR	@ERRTAB(T2)	;AND REST
	EXIT	1,		;THEN EXIT
	JRST	.-1		;AND STAY THAT WAY
>


IF20,<	HRROI	T1,[ASCIZ/
? DPY - /]			;GET SOME OF MESSAGE
	PSOUT			;OUTPUT IT
	HRROI	T1,@ERRTAB(T2)	;GET REST OF TEXT
	PSOUT			;OUTPUT IT TOO
	HALTF			;QUIT
	JRST	.-1		;AND STAY THAT WAY
>



;HERE TO RETURN TO THE USER WITH THE ERROR CODE


TRAP:	MOVE	P,SAVEP		;RESTORE A POINTER WE KNOW IS GOOD
	PUSH	P,T2		;SAVE THE ERROR CODE ON IT
	MOVE	T1,ERRADR(X)	;GET ADDRESS WHERE TO TRAP TO
	MOVEM	T1,TEMP		;SAVE IN KNOWN PLACE
	PUSHJ	P,RETURN	;RESTORE THE USER'S AC'S
	JRST	@TEMP		;JUMP BACK TO USER
;HERE ARE THE POSSIBLE ERRORS




ERRTAB:	ERR	UKE,Unknown error
	ERR	ILR,Illegal l