Trailing-Edge
-
PDP-10 Archives
-
BB-J710A-BM
-
tools/sysdpy/dpy.mac
There are 24 other files named dpy.mac in the archive. Click here to see a list.
;<4.UTILITIES>DPY.MAC.12, 3-Jan-80 15:25:26, EDIT BY R.ACE
;UPDATE COPYRIGHT DATE
TITLE DPY MODULE TO MAKE CRT DISPLAYS EASY
SUBTTL DEFINITIONS
;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 BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;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==170 ;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(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
AOJA T2,CHKADF ;COUNT ENDING CHAR AND RETURN
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 luuo received
ERR USL,Updated same location twice
ERR IWS,Illegal window size given
ERR ISF,Illegal set function given
ERR ITF,Illegal tty function given
ERR CDS,Cannot output desired sequence
ERR OPF,Output error occurred
ERR IPG,Illegal terminal address given
ERR ING,Initialize function not given
ERR IFF,Initialize function failed
MAXERR==.-ERRTAB-1 ;THE MAXIMUM ERROR
SUBTTL CONSTANTS AVAILABLE TO USER PROGRAM
;THE FOLLOWING TABLE IS INCLUDED SO THAT THE USER PROGRAM
;CAN READ SOME PARAMETERS WHICH DPY USES. THESE ARE REFERENCED
;BY THEIR OFFSET INTO THE DPYTAB TABLE.
DP: ;ALTERNATIVE LABEL
DPYTAB: EXP DATBEG+TERSIZ ;(0) POINTER TO TERMINAL LENGTH
EXP DATBEG+TERSIZ+1 ;(1) POINTER TO TERMINAL WIDTH
EXP DATBEG+MINL ;(2) POINTER TO PRESENT WINDOW SIZE
EXP DATBEG+OVFVAL ;(3) POINTER TO CURRENT WINDOW COUNTER
EXP DATLEN ;(4) LENGTH OF IMPORTANT DATA
EXP DATADR ;(5) POINTER TO ADDRESS OF THE DATA
EXP DATBEG+SCREEN ;(6) ADDRESS OF STORAGE FOR SCREEN
XWD MAXERR,ERRTAB ;(7) ERROR TABLE -- NOTE NOT RELOCATABLE
EXP TTYTYP ;(10) POINTER TO TERMINAL TYPE TABLE
EXP DATBEG+TTYJFN ;(11) POINTER TO JFN USING FOR TTY
EXP DATBEG+EATNUM ;(12) POINTER TO NUMBER OF LINES TO EAT
SUBTTL LOW SEGMENT STORAGE
;FIRST, DUMP OUT ALL THE HIGH-SEG LITERALS
XLIST ;LITERALS
LIT
LIST
;HERE IS THE ACTUAL DATA REQUIRED BY THE PROGRAM. THESE ARE IN THE
;LOW SEGMENT SO THAT THE PROGRAM CAN BE PURE.
RELOC 0 ;MOVE TO LOW SEGMENT NOW
SAVEF: BLOCK 1 ;STORAGE OF THE USER'S AC'S
SAVET1: BLOCK 1
SAVET2: BLOCK 1
SAVET3: BLOCK 1
SAVET4: BLOCK 1
SAVEX: BLOCK 1
SAVEC: BLOCK 1
SAVEA: BLOCK 1
SAVEL: BLOCK 1
SAVEN: BLOCK 1
SAVEB: BLOCK 1
SAVEU: BLOCK 1
ZERO: BLOCK 1 ;CONTAINS ZERO
SAVEP: BLOCK 1 ;PUSH-POINTER STORED IN CASE OF ERROR
TEMP: BLOCK 1 ;TEMPORARY STORAGE
DATADR: BLOCK 1 ;ADDRESS OF THE RELOCATABLE DATA
INIFLG: BLOCK 1 ;FLAGS FROM INI$ FUNCTION
INICNT: BLOCK 1 ;NUMBER OF ARGUMENTS IN INI$ FUNCTION
BEST: BLOCK 1 ;LOWEST NUMBER OF CHARS TO MOVE CURSER
TABNUM: BLOCK 1 ;NUMBER OF TABS NEEDED TO MOVE TO RIGHT
TABUSE: BLOCK 1 ;TABS NEEDED IN BEST CASE
FSTCHG: BLOCK 1 ;FIRST PLACE ON A LINE NEEDING CHANGING
LSTCHG: BLOCK 1 ;LAST PLACE ON A LINE TO NEED CHANGING
PRECHG: BLOCK 1 ;LAST PLACE TO CHANGE PRECEEDING PRESENT
;LOCATION ON A LINE
LSTNON: BLOCK 1 ;THE LOCATION OF THE LAST NON-SPACE
;THE FOLLOWING DATA IS REFERENCED BY INDEXING OFF OF AC X. THUS THE ACTUAL
;ADDRESS OF THE DATA IS VARIABLE, AND CAN BE SET BY THE USER.
DEFINE WD(SYM,LEN<1>),< ;;MACRO TO DEFINE OFFSETS
SYM:! BLOCK LEN
>
DATBEG: PHASE 0 ;THIS DATA IS PHASED SINCE INDEXED OFF OF X
WD OURF ;STORAGE FOR OUR AC'S
WD OURT1
WD OURT2
WD OURT3
WD OURT4
WD OURX
WD OURC
WD OURA
WD OURLN,2 ;STORAGE FOR ACS L AND N
WD OURBU,2 ;STORAGE FOR ACS B AND U
WD MINL ;LOWEST LINE NUMBER IN CURRENT WINDOW
WD MAXL ;HIGHEST LINE NUMBER IN WINDOW
WD MINN ;LOWEST COLUMN NUMBER IN WINDOW
WD MAXN ;HIGHEST COLUMN NUMBER IN WINDOW
WD TTYL ;LINE NUMBER THE TTY CURSER IS AT NOW
WD TTYN ;COLUMN NUMBER THE TTY CURSER IS AT NOW
WD BUFPTR ;BYTE POINTER INTO TTY BUFFER
WD BUFCNT ;NUMBER OF CHARACTERS IN TTY BUFFER
WD TTYBUF,TTYLEN ;TTY BUFFER
WD TERSIZ,2 ;TERMINAL'S LENGTH AND WIDTH
WD TTYJFN ;JFN OR BUFFER,,CHANNEL FOR OUTPUT
WD TABS,4 ;BIT TABLE FOR TAB STOPS
WD SCREEN,MAXARE ;SCREEN STORAGE
;THE REMAINING LOCATIONS ARE CLEARED ON INITIALIZATION:
ZERBLK: WD OUTADR ;ADDRESS OF ROUTINE TO GIVE OUTPUT CHARS TO
WD ERRADR ;ADDRESS OF ROUTINE TO GO TO ON FATAL ERRORS
WD OVFVAL ;WINDOW MOVING INFORMATION WHEN ONE FILLS UP
WD EATNUM ;NUMBER OF LINES TO IGNORE FROM USER
WD LINCHG,MAXLEN ;FLAGS TO KNOW IF A LINE HAS BEEN CHANGED
ZEREND==.-1 ;LAST LOCATION TO ZERO
DATLEN: DEPHASE ;LENGTH OF RELOCATABLE DATA
END