Trailing-Edge
-
PDP-10 Archives
-
steco_19840320_1er_E35
-
10,5676/teco/newsrc/tecupd.mac
There are 3 other files named tecupd.mac in the archive. Click here to see a list.
SUBTTL Introduction
; Copyright (c) 1980, 1981 Stevens Institute of Technology, Hoboken, New Jersey
; 07030.
; This software may be used and copied provided that this copyright notice
;is included, and provided that copies of all modifications are sent to:
;
; TECO Project
; Computer Center
; Stevens Institute of Technology
; Castle Point Station
; Hoboken, New Jersey 07030
;
;
; The information in this software is subject to change without notice
; and should not be construed as a commitment by Stevens Institute of
; Technology.
; Search needed universals
SEARCH TECUNV ; TECO universal file
; Generate the prologue
TECVER==200 ; Major version number
TECMIN==1 ; Minor version number
TECEDT==1166 ; Edit level
TECWHO==0 ; Last editor
PROLOGUE(UPD,<TECO Video update processing>) ; Generate the TITLE and other stuff
SUBTTL Table of Contents
SUBTTL Revision History
COMMENT |
1000 Start of this version
1005 By: Nick Bush On: 21-July-1980
Add capability for scrolling the screen downwards on terminals with
the function. This currently works only for VT-52's, but provides
the necessary support for any terminal with a scrolling region.
Modules: TECDEC,TECVID
1007 By: Nick Bush On: 30-July-1980
1) Make CHKTYI work a little better on slow speed (<=600 baud)
terminals. It will now wait until the output buffer is empty before
returning the no input return.
2) Put the cursor in a better position to indicate the location of PT
when PT = Z. The only time the cursor will now be over the prompt
is when PT = Z and the last line of the buffer is terminated by an
end of line character, and is on the last line of the window.
Modules: TECUNV,TECVID,TECTRM
1013 By: Nick Bush On: 6-August-1980
Make UPDLIN use SC$WLN to write out a line if the line on the screen is
blank, and we didn't have a function block for the replacement.
Make FS and FN searches only move the text in the text buffer once, not
do a delete and an insert. It will now only delete characters if the
new string is shorter, and only insert space if the new string is longer.
Modules: TECVID,TECSRH
1015 By: Nick Bush On: 11-August-1980
Don't give the NSM message until after we have parsed the Q-register name.
Otherwise, we a end up executing the Q-register name.
Modules: TECVID
1024 By: Robert McQueen On: 19-August-1980
Clear the executing flag in V$ASK and turn in back on after the character
input has been done.
Modules: TECVID
1026 By: Nick Bush On: 21-August-1980
When the command buffer is not the last thing on the screen on a terminal
without insert/delete line or scrolling, if type in extends past the
end of the section, various errors can result (ill mem ref's, looping,
...).
Modules: TECVID
1047 By: Robert McQueen On: 24-October-1980
79 Character lines would cause the 79th charcter to print twice, the
second time on the wrapped around line if there was no CRLF ending the
line.
Modules: TECVID
1061 By: Nick Bush On: 18-December-1980
1) Finish and debug Tektronix 4025 support.
2) Add FW command.
3) Add capability of logging screen update info in log file.
Modules: TECUNV,TECTEK,TECSRH,TECTBL,TECECM,TECVID,TECERR
1064 By: Robert McQueen On: 23-December-1980
VT100s are strange in that after clearing the screen the cursor is left on
the bottom of the screen. Add a new word to the $CRxxx blocks $CRERY to
be the Y position after the screen is erased.
Modules: TECUNV,TECDEC,TECVID
1065 By: Robert McQueen On: 29-December-1980
Remove the previous edit since it is easier to just add a home sequence
after the erase function. The erase sequence is now: <esc>[2J<esc>[H
Modules: TECUNV,TECDEC,TECVID
1066 By: Robert McQueen On: 6-January-1981
Fix various problems with TECVID processing of VT100s. FFD stopcodes
and illegal memory references.
Modules: TECVID
1102 By: Nick Bush On: 23-Febuary-1981
Fix VIDPOS to handle wrapped around lines correctly. It was using the
wrong value to check if it had found the correct line.
Modules: TECVID
1106 By: Nick Bush On: 13-May-1981
Improve screen updating for times when the new screen has portions which
are identical with the old. This will also fix most cases of wrapped
around lines on the top of the section of the screen.
Also fix some random /MODE:DUMP bugs.
Modules: TECUNV,TECVID,TECCMD,TECECM,TECUUO,TECMEM
1107 By: Nick Bush On: 15-May-1981
PTD stopcodes if screen update is aborted during a scroll down operation.
Modules: TECVID
1110 By: Nick Bush On: 30-June-1981
Fix a couple bugs in updating. Make sure that all lines which
get destroyed as a result of scroll operations actually get marked
that way. Also do not just assume that if the first and last
lines are valid that all lines in between are. Check that all
lines are valid before using the current screen.
Modules: TECVID
1112 By: Robert McQueen On: 10-July-1981
Half the screen would disappear on ADM3As and other types of messed up
screen updates. This would only happen if it was cheaper to clear the
screen and then write the data. Clear LD$SME in the new LDBs in this case.
Modules: TECVID
1113 By: Nick Bush On: 12-July-1981
Fix a backwards compare in SC$WRS. The update will now correctly
fix the bottom line when that should be more efficient.
Modules: TECVID
1116 By: Nick Bush On: 10-August-1981
More work on VT-100's. Get size of scrolling region right, and also make
sure the region is properly set when we do a LF in the command echoing
section.
Modules: TECVID,TECDEC
1117 By: Robert McQueen On: 14-August-1981
- Scroll up didn't work correctly at all times.
- Correct the cursor position after you scroll the screen up.
Modules: TECVID
1120 By: Robert McQueen On: 14-August-1981
NRC stopcodes from control U processing on VT100s if you have a two line
COMMAND-BUFFER.
Modules: TECVID
1121 By: Nick Bush On: 17-August-1981
Control-U's in three line command buffers did not work. More
checks were needed in DISPLY.
Fix defaulting of file spec paths to work correctly. A previous edit
had broken it.
Modules: TECVID,TECFIL
1122 By: nb On: 21-August-1981
Fix DISPLY to not ill mem ref with extremely long lines. (>15000 characters).
DISP.4 was referencing the previously found BEG (or thought it was) without
first checking if there were any lines left on the top of the screen.
Modules: TECVID
Start of Version 200A(1126)
1130 By: Nick Bush@SIT On: 5-November-1981
Split TECVID into two files: TECVID and TECUPD.
Redo how command editing is do in video mode to make the ^W editing
character easier to implement.
Add a new format for the V command when in video mode to allow the
user more control over the position of text on the screen.
Modules: TECVID,TECUPD,TECMVM
1145 By: Nick Bush On: 8-Febuary-1982
Re-write command input routines to implement FI command. As part of this
allow user to set prompt by storing the prompt text for normal commands in
the Q-register 'COMMAND-PROMPT'.
Modules: TECUNV,TECPRS,TECCIN,TECFCM,TECVID,TECUPD
1146 By: Nick Bush On: 16-March-1982
Fix PTD stopcode that occurs with type ahead when a long command has been typed
and not yet updated away.
Modules: TECUPD
1152 By: Nick Bush On: 2-April-1982
Yet another check to avoid PTD stopcode. In FDSPLY/DISPLY, make sure that the
fixed position value is reasonable before we use it.
Modules: TECUPD
1154 By: Nick Bush On: 8-April-1982
Add debugging routine to output the cost matrix for the section update costs.
Fix VT-100 insert and delete cost routines to count the costs for setting
the scroll region in the correct places. This should make VT-100's update
a bit faster, and make the update seem less strange to the user.
Modules: TECUPD,TECDEC
1157 By: Nick Bush On: 28-April-1982
Fix command input to work correctly with a ^U after an escape on the
first line of a command.
Put in yet another check in an attempt to avoid PTD stopcodes for the command
buffer.
Modules: TECCIN,TECUPD
1161 By: Nick Bush On: 13-May-1982
Add new code to support peek-ahead for immediate (FC table) commands and
for a new form of the control-T command.
Add the new form of the control-T command to allow macros to peek at
input, and to make use of timed input. Also add the Q-register
TERMINAL-INPUT-BUFFER to hold the text being peeked at, with the side
effect of allowing macros to store text into the Q-register, and have
it be treated as input typed on the terminal.
Also change the space command to just pass through the arguments unless
EO is set to 4 or less.
Modules: TECUNV,TECVID,TECUPD,TECMVM,TECPRS,TECTRM,TECCMD,TECTBL
1163 By: Nick Bush On: 19-May-1982
Fix ill mem ref when terminal length is set so that command buffer is
not displayed.
Also add VK100 (GIGI) support from Nick Tamburri at DEC.
Modules: TECUPD,TECTBL,TECDEC
1166 By: Nick Bush On: 15-June-1982
Yet another attempt to fix PTD's.
Modules: TECUPD
|
SUBTTL Macro definitions
; The following macros are for use in checking for type-ahead
DEFINE $CHTYI(FLAG),<
IFB <FLAG>,<PUSHJ P,CHKTYI>
IFIDN <FLAG>,<SEEN>,<SKIPN TYIFLG>
IFIDN <FLAG>,<NOWAIT>,<PUSHJ P,CHTYI0>
> ; End of $CHTYI definition
SUBTTL Screen editing -- SC$UPD - Update the screen
;+
;.Hl1 SC$UPD
;This routine will update the screen before each new command is input.
;.literal
;
; Usage:
; T1/ .TRUE if LDB's should be updated with info from VIN
; T1/ .FALSE if they should not (i.e., just update screen as is)
; PUSHJ P,SC$UPD
; (Return)
;.end literal
;-
$CODE ; Put into correct PSECT
NDS. D$LNCE, ^D80 ; Initial estimate of per 1000 iteration
; line cost time. This is the approximate
; runtime per 1000 iterations of the line
; update cost algortim. This is in
; milliseconds.
SC$UPD: JMPNS .POPJ ; If not screen stuff, just return
JMPF T1,.+2 ; Should we update LDBQRG?
PUSHJ P,SC$SSR ; Yes, set up the regions of the screen
JMPNS .POPJ ; If not screen mode anymore, just return
$CHTYI ; Check for type ahead
JRST .+2 ; None, go ahead and update the screen
POPJ P, ; There is some, skip the update
$SAVE <P1,P2,P3> ; Save P1
MOVE P3,SUPDAD ; Get the update mem address
MOVN T1,SCRNLN ; Get the negative number of lines
HRLI P1,(T1) ; Into left half
HRRI P1,(P3) ; Get the update LDB address
SC$U.L: MOVEI T1,(P1) ; Get the LDB address
PUSHJ P,FLSLDB ; Flush the LDB
ADDX P1,$LDLEN-1 ; Bump to next line
AOBJN P1,SC$U.L ; And loop
MOVX T1,D$LNCE ; Get the estimated cost
MOVEM T1,LITRTM ; Save it for later
MOVN P1,SCRNLN ; Get the number of lines again
MOVSI P1,(P1) ; Build an AOBJx pointer
HRR P1,SUPDAD ; Put in the address of the LDBs
SETZ P2, ; Clear the last pointer address
SC$UP0: LOAD. T1,LDBQRG,(P1) ; Get the address of the last one
JUMPE T1,SC$UP1 ; If zero, skip it
MOVE T2,SUPDAD ; Get the new LDB address in case we call SC$WRS
CAME T1,P2 ; Are the addresses the same ?
PUSHJ P,SC$WRS ; Update this section of the screen
LOAD. P2,LDBQRG,(P1) ; Get the pointer again
SC$UP1: ADDX P1,$LDLEN-1 ; Compute the address of the next
$CHTYI ; Check if we should continue
AOBJN P1,SC$UP0 ; Loop looking at all the pointers
SETZM MESFLG ; Things can not be messed up now
SETZ P1, ; Flag nothing seen yet
LOAD. P2,TPTADR,+VINADR ; Get the address of the info block
LOAD. P3,VINNLN,(P2) ; And get the number of lines
SUPD.A: LOAD. T1,VINQRG,(P2) ; Get the Q-register this is
JUMPE T1,SUPD.B ; If nothinghere, try the next
CAMN T1,P1 ; Same as last one?
JRST SUPD.B ; Yes, skip it
MOVE P1,T1 ; No, get the address
MOVEI T1,$QRPDB(P1) ; Get the address of the previous pointer
SKIPE (T1) ; Is there one?
PUSHJ P,M$RELB ; Yes, release it
LOAD. T1,TPTADR,+$QRTPT(P1) ; Get the text buffer address
MOVEI T2,$QRPDB(P1) ; Get the address of the pointer
PUSHJ P,M$USEB ; And set it up
LOAD. T2,BLKEND,(T1) ; Get the current end pointer
STOR. T2,BLKOED,(T1) ; Remember it for the next update
STORI. .MINFI,T2,BLKLST,(T1) ; Last modified loc=-1
STORI. .INFIN,T2,BLKFST,(T1) ; First modified =inifity
SUPD.B: AOJ P2, ; Bump to next line
SOJG P3,SUPD.A ; And try again
MOVE P3,SUPDAD ; Get the address of the update info
MOVN P1,SCRNLN ; Get the number of lines on the screen again
MOVSI P2,(P1) ; Set up P2
MOVSI P1,(P1) ; And P1
HRR P1,SCRNAD ; With pointers to the correct LDB's
HRR P2,P3 ; . . .
$CHTYI ; Check for type ahead again
JRST .+2 ; None, continue on
JRST SUPD.5 ; There is some, just go return the blocks
DMOVE T1,P1 ; Get the pointers
PUSHJ P,SCTCST ; And calculate the best method of updating the screen
; We have the cheapest cost function so far
;Check if clearing the whole screen and then re-writing it is cheaper
PUSH P,T1 ; Save T1
MOVE T2,P2 ; Get the pointer to the new lines
SETZ T3, ; And clear a place to accumulate the cost
SUPD.6: LOAD. T1,LDBNUM,(T2) ; Get the number of chars here
ADD T3,T1 ; Total them in
CAML T3,TOTCST ; See if too much yet
JRST SUPD.7 ; Yes, forget this
ADDX T2,$LDLEN-1 ; Bump to the next line
AOBJN T2,SUPD.6 ; Loop for all the lines
PUSHJ P,SC$ERS ; Clearing the screen is cheaper, clear the screen
SETZ T1, ; Clear the function pointer
EXCH T1,(P) ; . . .
JUMPE T1,.+2 ; If no function block, skip this
PUSHJ P,M$RBLK ; And return the core from the block
PUSH P,P1 ; Save P1
MOVN P1,SCRNLN ; Get the number of lines
HRLI P1,(P1) ; Make an AOBJx pointer
HRR P1,FNCLST ; Get the address of the function list
SUPD.8: SETZ T1, ; Clear T1
EXCH T1,(P1) ; And get the function skip
JUMPE T1,.+2 ; Don't try to return nothing
PUSHJ P,M$RBLK ; Return the block
AOBJN P1,SUPD.8 ; Loop for all the lines
; Now clear the SME bits in the new LDBs.
MOVE P1,P2 ; Copy the pointer
MOVX T1,LD$SME ; Get the bit to clear
SUPD.9: ANDCAM T1,$LDFLG(P1) ; Clear it
ADDX P1,$LDLEN-1 ; Loop
AOBJN P1,SUPD.9 ; for all the ldb
POP P,P1 ; And restore P1
SUPD.7: POP P,T1 ; Restore the function block
DMOVE T2,P1 ; Get the pointers again
PUSHJ P,UPDSCT ; Update the screen
; Here to update PTPOS
SUPD.5: LOAD. T1,TPTADR,+$QRTPT+TXTBUF ; Get the text buffer address
LOAD. T1,BLKPT,(T1) ; And get the pointer
MOVEI T2,TXTBUF ; Get the QRG block address
MOVX T3,QR$VID ; Get the flag to check
TDNN T3,$QRFLG(T2) ; Is TXTBUF displayed?
MOVE T2,CUREDT ; No, use current buffer
TDNE T3,$QRFLG(T2) ; Is it displayed?
PUSHJ P,FNDCHP ; Find the position of this character
JRST SC$UP4 ; If not on the screen, put over the prompt
DMOVEM T1,PTPOS ; Save the position
DMOVE X,T1 ; Get the postion
TXNE F,F.INFI ; Doing an FI command?
POPJ P, ; Yes, don't do this
$CHTYI ; Check for type ahead
PUSHJ P,SC$POS ; No, position the cursor
POPJ P, ; Yes, leave the cursor as it is
; Here if we can't find a reasonable place to put the cursor. Put it over
;where the prompt will go in the command section, and flag that escapes should
;not move the cursor from the echoing position
SC$UP4: LOAD. Y,QRGOFS,+CMDBUF ; Get the offset for the first line of the command buffer
MOVEM Y,PTPOS+$OFSY ; Store it
SETZ X, ; Clear the X position
SETOM PTPOS+$OFSX ; Flag to not put cursor here later
TXNE F,F.INFI ; Doing an FI command?
POPJ P, ; Yes, leave the cursor where it is
$CHTYI ; Check for type ahead
PJRST SC$POS ; Go place the cursor
POPJ P, ; There is some, just return
SUBTTL Screen editing -- SC$UPS - Update a section
;+
;.HL1 SC$UPS
;This routine will update a section. It will first determine if the pointer
;is currently on the screen. If the pointer is not on the screen DISPLY
;will be called to build the new pointers, else the begin and end pointer
;for each LDB for this section will be updated. After the pointers have
;been updated the screen and screen buffer will be updated with the current
;information.
;.literal
;
; Usage:
; MOVE T1,QRG.block.address
; PUSHJ P,SC$UPS
; (Return)
;
;.end literal
;-
SC$UPS: JMPNS .POPJ ; Return if not screen mode
MOVX T2,QR$VID ; Check if displayed
TDNN T2,$QRFLG(T1) ; Is it?
POPJ P, ; No, just return
$SAVE <P1,P2,P3,P4> ; Save P1
$SAVE <A1,A2> ; Save A1 and A2
$SAVE <CH> ; Save CH
FRAME. <CURPT,CUROFS,CURNLN,CURFLG> ; Make some variables on the stack
MOVE P1,T1 ; Copy the argument
MOVE P3,SUPDAD ; Get the update mem address
MOVN T1,SCRNLN ; Get the negative number of lines
HRLI P2,(T1) ; Into left half
HRRI P2,(P3) ; Get the update LDB address
MOVE P4,SCRNAD ; Get the address of the current screen info
SUPS.1: MOVEI T1,(P2) ; Get the LDB address
PUSHJ P,FLSLDB ; Flush the LDB
LOAD. T1,LDBQRG,(P4) ; Copy the fudged QRG info
STOR. T1,LDBQRG,(P2) ; . . .
ADDX P4,$LDLEN ; Advance to the next LDB
ADDX P2,$LDLEN-1 ; Bump to next line
AOBJN P2,SUPS.1 ; And loop
MOVX T1,D$LNCE ; Get the estimated cost
MOVEM T1,LITRTM ; Save it for later
LOAD. T1,TPTADR,+$QRTPT(P1) ; Get the buffer address
LOAD. T2,BLKPT,(T1) ; Get the current pointer
MOVEM T2,CURPT ; Save it
LOAD. T3,QRGNLN,(P1) ; Get the number of lines in the Q-reg
MOVEM T3,CURNLN ; Save it
LOAD. T2,QRGOFS,(P1) ; Get the first line number
MOVEM T2,CUROFS ; Save it
LOAD. T3,QRGFLG,(P1) ; Get the flags
MOVEM T3,CURFLG ; Save them
; Now determine where this Q-reg is currently displayed. It may have
;been shifted due to type-in or incomplete screen updating.
MOVE T1,T2 ; Get a copy of the first line number
IMULX T2,$LDLEN ; get the offset to the LDB
ADD T2,SCRNAD ; And point to the correct one
PUSH P,T2 ; Save for counting up
SETZ T4, ; And clear the count
SUB T1,SCRNLN ; Get the number of lines we can go down
SUPS.2: CFME. T3,LDBQRG,(T2),P1 ; Is this the right data?
JRST SUPS.3 ; No, skip it
ADDX T2,$LDLEN ; Yes, advance to the next line
AOJ T4, ; Bump the line count
AOJL T1,SUPS.2 ; And loop for all lines that we can
SUPS.3: POP P,T2 ; Get the LDB address back
LOAD. T1,LDBLIN,(T2) ; Get the line number back
SUPS.4: SUBX T2,$LDLEN ; Back up a line
SOJL T1,SUPS.5 ; . . .
CFMN. T3,LDBQRG,(T2),P1 ; Same QRG?
AOJA T4,SUPS.4 ; Try again
SUPS.5: AOJ T1, ; Fix up for the last decrement
STOR. T1,QRGOFS,(P1) ; Store the offset
STOR. T4,QRGNLN,(P1) ; And the number of lines
ADDX T2,$LDLEN ; Point back at the first LDB
LOAD. T2,LDBBEG,(T2) ; And get the position
JUMPGE T2,.+2 ; Is it okay?
SETZ T2, ; No, use first position of buffer
LOAD. T1,TPTADR,+$QRTPT(P1) ; Get the buffer address
CFMG. ,BLKFST,(T1),T2 ; After first mod?
SETZ T2, ; Yes, work from start
STOR. T2,QRGVAL,(P1) ; Store into value word
ZERO. T2,QRGFLN,(P1) ; Fix this on the first line of the section
MOVEI T1,(P1) ; Get the QRG address
MOVE T2,P3 ; Get the new address
PUSHJ P,SC$WRS ; Write the new text
MOVEI T1,$QRPDB(P1) ; Get the address of the previous pointer
SKIPE (T1) ; Is there one?
PUSHJ P,M$RELB ; Yes, release it
LOAD. T1,TPTADR,+$QRTPT(P1) ; Get the text buffer address
MOVEI T2,$QRPDB(P1) ; Get the address of the pointer
PUSHJ P,M$USEB ; And set it up
LOAD. T2,BLKEND,(T1) ; Get the current end pointer
STOR. T2,BLKOED,(T1) ; Remember it for the next update
STORI. .MINFI,T2,BLKLST,(T1) ; Last modified loc=-infinity
STORI. .INFIN,T2,BLKFST,(T1) ; First modified =inifity
LOAD. T1,QRGNLN,(P1) ; Get the number of lines in the section
LOAD. T2,QRGOFS,(P1) ; And the offset to the first
IMULX T2,$LDLEN ; Get the offset in words
MOVE P2,SCRNAD ; Get the address of the current screen
ADD P2,T2 ; Point to the first line of this section
ADD P3,T2 ; Also on the new screen
MOVN T1,T1 ; Get the number of lines
HRLI P2,(T1) ; And make the AOBJx pointers
HRLI P3,(T1) ; . . .
; Now compute the cost of going from one to the other
DMOVE T1,P2 ; Get the address of the lists
PUSHJ P,SCTCST ; Compute the cost of updating the section
DMOVE T2,P2 ; Now get the lists to update the sections
PUSHJ P,UPDSCT ; And update the sections
; Now determine the position of the pointer for this QRG
MOVE T2,P1 ; Get the address
MOVE T1,CURPT ; And get the pointer
PUSHJ P,FNDLDB ; Find what line this is on
JRST .+2 ; It isn't there, figure out what to do
JRST SUPS.6 ; We found the LDB, go handle it
; Here if we couldn't find the LDB. This can only be because PT is at Z.
LOAD. P2,TPTADR,+$QRTPT(P1) ; Get the address of the text buffer
MOVE T1,CURPT ; Get the pointer
JUMPE T1,SUPS.9 ; If at start of buffer, make sure we put cursor at start of window
CFME. ,BLKEND,(P2),T1 ; Pointer at the end of the buffer?
JRST SUPS.A ; No, not displayed for some reason
SOJ T1, ; Decrement to point to the last char
IDIVX T1,5 ; Convert to word/byte offset
HLL T1,BTAB(T2) ; Get the byte pointer
ADDI T1,.BKTLN(P2) ; And make the absolute address
LDB CH,T1 ; Get the final character
LOAD. T1,QRGOFS,(P1) ; Get the offset to the first line
IMULX T1,$LDLEN ; Convert to LDB offset
ADD T1,SCRNAD ; Make the absolute address
LOAD. T2,QRGNLN,(P1) ; Get the number of lines
MOVN T2,T2 ; Make it negative
HRLI T1,(T2) ; And make the AOBJx pointer
SUPS.7: LOAD. T2,LDBEND,(T1) ; Get the end pointer
JUMPL T2,SUPS.8 ; Is it valid?
ADDX T1,$LDLEN-1 ; Yes, bump to the next
AOBJN T1,SUPS.7 ; And loop for all the LDB's
; If we get here, all of the lines of the window are used. The only
;special case we need to check now is if the last line does not end with an
;end of line character.
PUSHJ P,CKTRM ; And check if it is a line terminator
JRST .+2 ; Skip
JRST SUPS.A ; Final char is line terminator, just put over prompt
LOAD. T2,LDBLIN,-$LDLEN(T1) ; Get the line number
LOAD. T1,LDBNUM,-$LDLEN(T1) ; And get the number of chars on the line
JRST SUPS.E ; And go set things up
; Here if there are blank lines in the window. Find the correct place to put
;the pointer.
SUPS.8: PUSHJ P,CKTRM ; Check if last char was a line terminator
SUBX T1,$LDLEN ; No, back up one line
LOAD. T2,LDBLIN,(T1) ; Get the line number
LOAD. T1,LDBNUM,(T1) ; Get the position on the line
JRST SUPS.E ; And go finish up
; Here if the pointer is at the start of the buffer. The cursor must
;then be put in column 0 of the first line of the window
SUPS.9: LOAD. T2,QRGOFS,(P1) ; Get the line number
SETZ T1, ; Column 0
JRST SUPS.E ; Go finish up
SUPS.A: LOAD. T2,QRGOFS,(P1) ; Get the offset to the first line
LOAD. T1,QRGNLN,(P1) ; Plus the line number
ADDI T2,-1(T1) ; Get the last line number
SETZ T1, ; Put at start of line
JRST SUPS.E ; And go return it
SUPS.6: MOVE T2,CURPT ; Get the pointer address back
LOAD. T3,TPTADR,+$QRTPT(P1) ; And get the text buffer address
PUSHJ P,FNDPOS ; Get the position
; Now restore the pointer in this text buffer
SUPS.E: MOVE T3,CUROFS ; Get the old offset back
STOR. T3,QRGOFS,(P1) ; Store it
MOVE T3,CURNLN ; And number of lines
STOR. T3,QRGNLN,(P1) ; And store it
MOVE T3,CURFLG ; Get the flags
STOR. T3,QRGFLG,(P1) ; And store them back
LOAD. T3,TPTADR,(P1) ; Get the address
MOVE T4,CURPT ; Get the pointer back
STOR. T4,BLKPT,(T3) ; Store the old pointer back
POPJ P, ; And return
SUBTTL Screen editing -- SC$WRS - Write new chars into a section
;+
;.hl2 SC$WRS
; This routine will cause the text for a section to be written into the
;new LDB's for later updating of the screen.
;.b.lit
;
; Usage:
; MOVE T1,QRG address
; MOVE T2,Base address of new LDB's
; PUSHJ P,SC$WRS
; (return, text written into new LDB's, P1 and P4 intact)
;
;.end literal
;-
SC$WRS: $SAVE <P1,P2,P3,P4> ; Save the ac's
FRAME. <TOPLIN,BOTLIN,SVEPT,OLDPT> ; Make some variables
MOVE P1,T1 ; Get the QRG address
MOVE P4,T2 ; And the screen buffer address
LOAD. P2,TPTADR,+$QRTPT(P1) ; Get the text pointer address
LOAD. T2,BLKPT,(P2) ; Get the current PT
MOVEM T2,OLDPT ; Save here also
MOVE T1,$QRFLG(P1) ; Check if fixed display
TXNN T1,QR$FIX ; Fixed position display
JRST SWRS.1 ; No, skip this
LOAD. T2,QRGVAL,(P1) ; Get the value word (position to fix)
CFMGE. ,BLKEND,(P2),T2 ; Within bounds?
JRST SWRS.2 ; No, punt it
CFMLE. ,BLKFST,(P2),T2 ; Are we before the first modification?
JRST SWRS.1 ; Yes, use this value
SUB T2,.BKOED(P2) ; Fix up to be relative to the new end
ADD T2,.BKEND(P2) ; . . .
CFMGE. ,BLKEND,(P2),T2 ; Still ok?
JRST SWRS.2 ; No, punt
CFMG. ,BLKLST,(P2),T2 ; After last modification?
JRST SWRS.1 ; Yes, all is fine
SWRS.2: BITOFF T1,QR$FIX!QR$SHF,$QRFLG(P1) ; No, clear out the fixed flag
MOVE T2,OLDPT ; Fix position is bad, use current one
SWRS.1: MOVEM T2,SVEPT ; Save the current PT
LOAD. T1,TPTADR,+$QRPDB(P1) ; Get the buffer we were displaying last time
MOVX T2,QR$UPD ; And the flag to set
SKIPN MESFLG ; Whole screen need to be done from scratch?
CAIE T1,(P2) ; Still on the same buffer?
IORM T2,$QRFLG(P1) ; No, flag no data is valid
TDNE T2,$QRFLG(P1) ; Forced update needed?
JRST SWRS.U ; Yes, do it
SETOM TOPLIN ; Clear the current top line
SETOM BOTLIN ; And bottom line
LOAD. T1,QRGOFS,(P1) ; Get the offset to the first line
LOAD. T4,QRGNLN,(P1) ; Get the number of lines also
IMULX T1,$LDLEN ; Make this the word offset
ADD T1,SCRNAD ; Get the offset to the correct LDB
MOVEI T2,-1(T4) ; Get the number of lines
IMULX T2,$LDLEN ; Make it the offset from the first
ADD T2,T1 ; And get the address of the last line
MOVE P3,T1 ; And copy the LDB addresses
LOAD T1,$LDFLG(P3),LD$ICA ; Addresses ok?
JMPT T1,SWRS.D ; No, punt it
CFME. T1,LDBQRG,(P3),P1 ; Did the display get changed?
JRST SWRS.D ; Yes, can't count on anything
LOAD. T1,LDBBEG,(P3) ; Get the start of the first line
JUMPL T1,SWRS.D ; If not valid, just refigure from scratch
CFMG. ,BLKFST,(P2),T1 ; Was there some modification before the start of the screen?
JRST SWRS.A ; Yes, go see whether we can fix the bottom
CAMLE T1,SVEPT ; Is PT before the start of the screen?
JRST SWRS.D ; Yes, figure out new placement completely
LOAD. T3,LDBEND,(T2) ; Get the end address
JUMPL T3,SWRS.F ; Not valid, find last valid line
MOVX T1,LD$CRLF ; Check if there is a CRLF after the last line
TDNE T1,$LDFLG(T2) ; . . .
ADDI T3,2 ; Yes, count them
CFMG. ,BLKFST,(P2),T3 ; Before first modification?
JRST SWRS.F ; No, must do whole set of checks
CAMG T3,SVEPT ; Is PT still on the screen?
JRST SWRS.D ; No, punt
; Here if there has been no modification before the start of the screen,
;and PT is after the start of the screen. We must find the first line that
;has been modified, and work from there.
SWRS.F: MOVE T2,P3 ; Get a copy of the LDB address
MOVX T3,LD$CRLF ; Check if the line included a CRLF
SWRS.Z: CFME. T1,LDBQRG,$LDLEN(T2),P1 ; Still correct Q-reg?
JRST SWRS.Y ; No, done with the loop
CFXGE. ,LDBBEG,$LDLEN(T2),0 ; Is this line valid?
JRST SWRS.Y ; No, all done with this loop
LOAD. T1,LDBEND,(T2) ; Get the end
JUMPL T1,SWRS.Y ; If END is no good, assume BEG is also bad
TDNE T3,$LDFLG(T2) ; Is there one?
ADDI T1,2 ; Yes, count it
CFMG. ,BLKFST,(P2),T1 ; Is the first modification after this point?
JRST SWRS.Y ; No, count the number of lines the same
SOJLE T4,SWRS.W ; If this is the last line, the modification is after the screen
ADDX T2,$LDLEN ; Advance to next line
CFME. ,LDBBEG,(T2),T1 ; Is the end of the last line the start of this?
JRST SWRS.Y ; No, punt this line
JRST SWRS.Z ; Yes, get it's bounds
; Here if the no text was changed on the screen, and PT is still on
;it somewhere.
SWRS.W: LOAD. T1,QRGNLN,(P1) ; Get the number of line
LOAD. T2,QRGOFS,(P1) ; Get the top line
MOVEM T2,TOPLIN ; Save as first line not modified
ADDI T2,-1(T1) ; Get the last line
MOVEM T2,BOTLIN ; Save that also
MOVX T2,QR$FIX ; See if fixed or shifting
TDNE T2,$QRFLG(P1) ; Is it?
JRST SWRS.C ; Yes, must really call FDSPLY or DSPLY
MOVN T1,T1 ; Make it negative
HRLI P3,(T1) ; Make the loop counter
MOVEI T1,(P3) ; Get the LDB address of the first line
SUB T1,SCRNAD ; Get the offset to he first line
ADD P4,T1 ; Point to the the new lines also
SWRS.G:
DEFINE XXX(LIST),<IRP LIST,<
LOAD. T1,LDB'LIST,(P3) ;; Get the old item
STOR. T1,LDB'LIST,(P4) ;; Store it
>> ; End of DEFINE XXX
XXX (<BEG,END,NUM,FLG>) ; Move all the data
BITON T1,LD$SME,$LDFLG(P4) ; Flag the new data is same as old
LOAD. T1,LDBTXT,(P3) ; Get the address of the old text
MOVSI T1,(T1) ; Put in left half
LOAD. T2,LDBTXT,(P4) ; Get the destination address
HRRI T1,(T2) ; Set up the BLT pointer
ADD T2,LINWDS ; Get the final address
BLT T1,-1(T2) ; Move the text
ADDX P4,$LDLEN ; Advance to next line
ADDX P3,$LDLEN-1 ; . . .
AOBJN P3,SWRS.G ; Loop for all the lines
JRST SWRS.9 ; And go finish up
; Here with T2 pointing at the first line which does not definitely contain
;valid data. We will attempt to determine if PT is still on the screen,
;or if not, whether we should fix the bottom or top line of the screen
;and attempt to display it that way.
SWRS.Y: LOAD. T3,LDBLIN,(T2) ; Get the line number of the line we found
MOVEM T3,TOPLIN ; Remember the top line number
; Here to determine how many (if any) lines on the bottom of the section
;are valid as they are.
SWRS.A: LOAD. T1,QRGOFS,(P1) ; Get the offset of the first line
LOAD. T4,QRGNLN,(P1) ; And the number of lines
ADDI T1,-1(T4) ; Get the offset of the last line
IMULX T1,$LDLEN ; Make the address
ADD T1,SCRNAD ; . . .
LOAD. T2,LDBEND,(T1) ; Get the end address
JUMPL T2,SWRS.C ; No, go try fixing the first line
CFME. T3,LDBQRG,(T1),P1 ; Same Q-reg previously?
JRST SWRS.C ; No, can't fix this
MOVE T3,SVEPT ; Get PT
SUB T3,.BKEND(P2) ; Get it relative to the old end
ADD T3,.BKOED(P2) ; . . .
CFMG. ,LDBEND,(T1),T3 ; Is PT on the screen?
JRST SWRS.D ; No, just refigure from scratch
SWRS.B: LOAD. T2,LDBEND,(T1) ; Get the end address
JUMPL T2,SWRS.C ; No, go try fixing the first line
CFME. T3,LDBQRG,(T1),P1 ; Still valid?
JRST SWRS.C ; . . .
CFML. ,BLKLST,(P2),T2 ; Is this before the last modified thing?
JRST SWRS.C ; No, all done
SOJLE T4,SWRS.H ; Loop for all lines in this section
LOAD. T3,LDBBEG,(T1) ; Get the start of this line
JUMPL T3,SWRS.C ; And give up if it isn't valid
SUBX T1,$LDLEN ; Back up a line
CFME. T2,LDBQRG,(T1),P1 ; Same Q-register?
JRST SWRS.C ; No,nothing left
MOVE T2,$LDFLG(T1) ; Get the flags from the previous line
TXNE T2,LD$CRLF ; Previous line end with a CRLF?
SUBI T3,2 ; Yes, account for that also
CFME. ,LDBEND,(T1),T3 ; Is the BEG/END pair correct?
JRST SWRS.C ; No, no lines left
LOAD. T3,LDBLIN,+$LDLEN(T1) ; Get the line number in case
TXNN T2,LD$WAP ; Previous line wrap?
MOVEM T3,BOTLIN ; No, this line is ok
JRST SWRS.B ; Loop for next line
; Here if we need to make a choice between fixing the top and bottom
;lines. We will fix the end which has the best chance of preserving
;the larger number of lines on the screen.
SWRS.C: SKIPGE T1,TOPLIN ; Get the top line we can keep
JRST SWRS.H ; Can't, try the bottom
LOAD. T2,QRGOFS,(P1) ; Get the offset to the first line
SUB T1,T2 ; Get the number of lines that are the same
AOJ T1, ; Plus one
LOAD. T3,QRGNLN,(P1) ; Get the total number of lines
ADDI T2,-1(T3) ; Get the last line number
SKIPL T3,BOTLIN ; Get the bottom line number
SUBM T2,T3 ; Get the number the same
AOJ T3, ; Plus one
CAMLE T3,T1 ; More lines on top the same?
JRST SWRS.H ; No, fix the bottom
; Here if we want to try fixing the top line.
MOVE T1,SVEPT ; Get the saved PT
STOR. T1,BLKPT,(P2) ; Save it
LOAD. T1,LDBBEG,(P3) ; Get the starting address
MOVE T2,P1 ; And the QRG address
LOAD. T3,LDBLIN,(P3) ; And the line number
EXCH P4,SCRNAD ; Use correct buffer
PUSHJ P,FDSPLY ; Write the buffer
MOVE T1,SVEPT ; Get PT
MOVE T2,P1 ; And get the QRG address
PUSHJ P,FNDLDB ; Find PT on the screen
JRST SWRS.L ; Couldn't, check if at Z
EXCH P4,SCRNAD ; Swap things back
JRST SWRS.0 ; And go write in the text
; Here if we couldn't find the position. Check if it is at Z, and if
;it actually is on the screen.
SWRS.L: EXCH P4,SCRNAD ; Fix the address back
MOVE T1,SVEPT ; Get the pointer back
CFME. ,BLKEND,(P2),T1 ; Is PT=Z?
JRST SWRS.H ; No, try fixing the bottom line
LOAD. T1,QRGOFS,(P1) ; Get the offset to the first line
LOAD. T2,QRGNLN,(P1) ; And the number of lines
ADDI T1,-1(T2) ; Get the last line offset
IMULX T1,$LDLEN ; Make the word offset
ADD T1,P4 ; Get the actual address
CFXGE. ,LDBEND,(T1),0 ; Last line blank?
JRST SWRS.0 ; Yes, PT is on the screen
FALL SWRS.H ; No, try fixing the bottom line
; Here to try writing the screen by fixing the bottom line.
SWRS.H: LOAD. T3,QRGOFS,(P1) ; Get the first line number
LOAD. T4,QRGNLN,(P1) ; And the number of lines
ADDI T3,-1(T4) ; Get the offset to the last line
IMULX T3,$LDLEN ; . . .
ADD T3,SCRNAD ; Get the address
CFME. T1,LDBQRG,(T3),P1 ; Same QRG?
JRST SWRS.D ; No, can't do this
LOAD. T1,LDBBEG,(T3) ; Get the start address
JUMPL T1,SWRS.D ; If the bottom is not valid, punt
CFML. ,BLKFST,(P2),T1 ; Before first mod?
JRST SWRS.I ; Yes, do it
CFML. ,BLKLST,(P2),T1 ; After last mod?
JRST SWRS.D ; No, punt
SUB T1,.BKOED(P2) ; Yes, offset by the old end
ADD T1,.BKEND(P2) ; And make it correct for current items
SWRS.I: MOVE T2,SVEPT ; Get the saved PT
STOR. T2,BLKPT,(P2) ; Save it
MOVE T2,P1 ; Get the QRG address
LOAD. T3,LDBLIN,(T3) ; Get the line number
EXCH P4,SCRNAD ; Use correct buffer
PUSHJ P,FDSPLY ; Get the bounds
MOVE T1,SVEPT ; Get PT
MOVE T2,P1 ; And the QRG
PUSHJ P,FNDLDB ; Find the line with PT
JRST [EXCH P4,SCRNAD ; Couldn't, fix things back up
JRST SWRS.D] ; And do it from scratch
EXCH P4,SCRNAD ; Put things back
JRST SWRS.0 ; And go write out the text
; Here if we for some reason must redraw the section without
;regard to what is currently there. This is done on a refresh command,
;or if the text buffer being display in the section changed, or for
;some other reason. In order to remember this fact until we actually
;get some valid text out on the screen, we will invalidate all of
;the BEG/END entries for the lines in the section.
SWRS.U: LOAD. T1,QRGOFS,(P1) ; Get the offset to the first line
IMULX T1,$LDLEN ; Make it the word offset
ADD T1,SCRNAD ; Point at the LDB
LOAD. T2,QRGNLN,(P1) ; Get the number of lines
SWRS.T: ONES. ,LDBBEG,(T1) ; Clear the BEG
ONES. ,LDBEND,(T1) ; And the END of the line
ADDX T1,$LDLEN ; Point to the next line
SOJG T2,SWRS.T ; Loop for all lines
; Here if we have no valid choice other than to re-center to screen.
SWRS.D: MOVE T1,SVEPT ; Get the current PT back
STOR. T1,BLKPT,(P2) ; Make sure PT is correct
MOVE T2,P1 ; Get the QRG block address
EXCH P4,SCRNAD ; Save the screen address
PUSHJ P,DISPLY ; Determine the new LDB offsets (BEG/ENDs)
EXCH P4,SCRNAD ; Get the temp LDB list back again
FALL SWRS.0 ; Update the screen now
; Here to update the screen
SWRS.0: MOVE P2,P4 ; Copy the address for later
LOAD. T1,QRGNLN,(P1) ; Get the number of lines to check
MOVN T1,T1 ; Build the negative of it
HRL P4,T1 ; Build an AOBJN pointer to it
LOAD. T1,QRGOFS,(P1) ; Get the offset
IMULX T1,$LDLEN ; Compute the length
ADD P4,T1 ; Compute the address of the first LDB
SWRS.3: SETZ X, ; Clear the X offset
LOAD. T1,TPTADR,+$QRTPT(P1) ; Get the text block address
LOAD. T2,LDBBEG,(P4) ; Get the beginning address
JUMPL T2,SWRS.5 ; Skip this LDB if none
PUSHJ P,SETLIN ; Set up to get the characters
LOAD. T4,LDBTXT,(P4) ; Get the address of the text buffer
HRLI T4,(POINT 7) ; Finish up the byte pointer
SWRS.4: CFMG. T3,LDBNUM,(P4),X ; Finished with the loop ?
JRST SWRS.5 ; Yes, exit it
LOAD. T1,TPTADR,+$QRTPT(P1) ; Get the text block address
PUSHJ P,GETINC ; Get the next character
JRST SWRS.5 ; Finished with this line ?
PUSHJ P,SC$WRT ; Write the character
JRST SWRS.4 ; Loop back
SWRS.5: ADDX P4,$LDLEN-1 ; Point to the next
AOBJN P4,SWRS.3 ; Loop for all characters
; Now determine if any lines should have LD$SME turned on.
MOVX T1,QR$UPD ; Get the flag
TDNN T1,$QRFLG(P1) ; Is this a forced update?
SKIPE MESFLG ; Or complete refresh?
JRST SWRS.9 ; Yes, don't worry about identical lines
LOAD. T1,QRGOFS,(P1) ; Get the offset to the first line
IMULX T1,$LDLEN ; Make it the address of the LDB
ADD P2,T1 ; (the new one)
MOVE P3,T1 ; Get the offset
ADD P3,SCRNAD ; And point to the old line
LOAD. T2,QRGNLN,(P1) ; Get the number of lines
MOVN T2,T2 ; Make it negative
HRLI P2,(T2) ; Make the pointer
MOVX T3,LD$SME ; Get the flag to turn on
LOAD. P4,TPTADR,+$QRTPT(P1) ; Get the buffer address
SWRS.8: CFME. T1,LDBQRG,(P3),P1 ; Same QRG?
JRST SWRS.N ; No, skip it
LOAD. T1,LDBNUM,(P2) ; Get the number of characters
CFME. ,LDBNUM,(P3),T1 ; Same?
JRST SWRS.7 ; No, skip this line
LOAD. T1,LDBBEG,(P2) ; Get the start address
CFMG. ,BLKFST,(P4),T1 ; Before first change?
JRST SWRS.6 ; No, try after the last
CFME. ,LDBBEG,(P3),T1 ; Save BEG?
JRST SWRS.7 ; No, try the next
LOAD. T1,LDBEND,(P2) ; Get the END
CFMG. ,BLKFST,(P4),T1 ; Before the first change?
JRST SWRS.N ; No, try the next
CFME. ,LDBEND,(P3),T1 ; Yes, same end?
JRST SWRS.P ; No, try again
LOAD T1,$LDFLG(P2),LD$CRLF ; Get the CRLF flag
LOAD T2,$LDFLG(P3),LD$CRLF ; And the other
XOR T1,T2 ; Put them together
JUMPN T1,SWRS.P ; Same?
IORM T3,$LDFLG(P2) ; Flag line is same
JRST SWRS.P ; And try the next
; Here if the line starts after the first change
SWRS.6: SUB T1,.BKEND(P4) ; Offset to old end
ADD T1,.BKOED(P4) ; . . .
CFML. ,BLKLST,(P4),T1 ; After last change?
JRST SWRS.O ; No, try next
CFME. ,LDBBEG,(P3),T1 ; Yes, same as other BEG?
JRST SWRS.O ; No, try next
LOAD. T1,LDBEND,(P2) ; Get the end of the line
SUB T1,.BKEND(P4) ; Offset to old end
ADD T1,.BKOED(P4) ; . . .
CFME. ,LDBEND,(P3),T1 ; Same end?
JRST SWRS.O ; No, advance to next line
LOAD T1,$LDFLG(P2),LD$CRLF ; Make sure CRLF's also match
LOAD T2,$LDFLG(P3),LD$CRLF ; . . .
XOR T1,T2 ; Get the sum
JUMPN T1,SWRS.O ; Same?
IORM T3,$LDFLG(P2) ; Yes, flag it
JRST SWRS.O ; And try the next line
SWRS.7: LOAD. T1,LDBBEG,(P3) ; Get the beg for this line
CFMG. ,BLKFST,(P4),T1 ; Is this before the first change
JRST SWRS.O ; No, check for after last change
LOAD. T1,LDBEND,(P3) ; Get the end of the line
CFML. ,BLKFST,(P4),T1 ; Is the entire line before the changed section?
JRST SWRS.P ; Yes, all done with this line
ONES. ,LDBBEG,(P3) ; No, clear out the LDB
ONES. ,LDBEND,(P3) ; . . .
JRST SWRS.P ; And continue on
SWRS.O: MOVE T1,.BKEND(P4) ; Get the current end
SUB T1,.BKOED(P4) ; Minus the old end
ADDM T1,$LDEND(P3) ; Fix up the addresses
EXCH T1,$LDBEG(P3) ; . . .
ADDM T1,$LDBEG(P3) ; . . .
CFMGE. ,BLKLST,(P4),T1 ; Was the last modification before this?
JRST SWRS.P ; Yes, all is fine
SWRS.N: ONES. ,LDBBEG,(P3) ; No, clear out the LDB's
ONES. ,LDBEND,(P3) ; . . .
SWRS.P: ADDX P3,$LDLEN ; Advance to next line
ADDX P2,$LDLEN-1 ; . . .
AOBJN P2,SWRS.8 ; And loop
SWRS.9: BITOFF T1,QR$UPD,$QRFLG(P1) ; Clear the forced update flag
CFXL. ,BLKLST,(P2),0 ; Anything actually modified?
TXNN T1,QR$FIX ; Is this a fixed position pass?
JRST SWRS.X ; No, skip this
LOAD. T2,QRGVAL,(P1) ; Get the value word
CFML. ,BLKFST,(P2),T2 ; After first item modified?
JRST SWRS.X ; No, skip this
SUB T2,.BKOED(P2) ; Yes, fix up to be relative to new coordinates
ADD T2,.BKEND(P2) ; . . .
STOR. T2,QRGVAL,(P1) ; And store the value back
SWRS.X: MOVX T2,QR$FIX ; Get the flags to clear
TXNE T1,QR$SHF ; Only one time shift of screen
ANDCAM T2,$QRFLG(P1) ; Yes, clear the flags
MOVX T2,QR$SHF ; Get the other flag
TXC T1,QR$FIX!QR$SHF ; See if both flags were on
TXCE T1,QR$FIX!QR$SHF ; . . .
ANDCAM T2,$QRFLG(P1) ; No, flag the the shift data is worthless now
LOAD. T1,TPTADR,+$QRTPT(P1) ; Get the address of the buffer
MOVE T2,OLDPT ; Get the pointer back
PUSHJ P,SETLIN ; Reset the byte pointer
POPJ P, ; And return
SUBTTL Screen editing -- Update section
;+
;.HL1 UPDSCT
;This routine will update a section using the functions that are given
;to it. It assumes the cost analysis has been done to produce the
;the functions.
;.literal
;
; Usage:
; MOVE T1,[XWD -n,Function.block.address]
; MOVE T2,[XWD -n,Old.LDB.address]
; MOVE T3,[XWD -n,New.LDB.address]
; PUSHJ P,UPDSCT
;
;.end literal
;-
UPDSCT: $SAVE <P1,P2,P3,P4> ; Save P1 to P4
$SAVE <X,Y> ; Save the X and Y addresses
PUSH P,T1 ; Save the address of the block
SETOM UPCSFL ; Flag we are doing the update now
DMOVE P2,T2 ; Copy the LDB lists
TXNE CRT,CR$SCR ; Terminal do scrolling instead of insert/delete line
PUSHJ P,OPR2SC ; Yes, convert operations to use only scrolling
MOVE P1,T1 ; Copy the function block address
SETZ X, ; Clear X
LOAD. Y,LDBLIN,(P2) ; Line to start at
SETZB P4,IDLCNT ; Clear the number of lines delete/inserted
$CHTYI ; Any type ahead?
JRST .+2 ; No, continue on
JRST UPDS.2 ; Yes, just return the blocks
JUMPN P1,UPDS.0 ; If we have a list, go do it
MOVX P1,<INSVL.($OPRCH,CS$OPR)> ; No list, assume replaces
MOVEM P1,FNCTMP ; Store the item
HLRE P1,P2 ; Get the number of lines
MOVN P1,P1 ; Make it positive
STOR. P1,CSTRPT,+FNCTMP ; Store the repeat count
MOVX P1,<XWD -1,FNCTMP> ; Get the pointer
UPDS.0: LOAD. T1,CSTRPT,(P1) ; Get the repeat cost
LOAD. T2,CSTDEP,(P1) ; Get the dependant info
LOAD. T3,CSTOPR,(P1) ; Get the function
PUSHJ P,@UPSTBL(T3) ; Call the routine to do the work
$CHTYI(SEEN) ; Any type ahead?
AOBJN P1,UPDS.0 ; Loop for all the functions
; Here when screen is done updating. We must return any function blocks
UPDS.2: MOVN T1,SCRNLN ; Get the number of lines
MOVSI P1,(T1) ; Produce the AOBJN pointer
HRR P1,FNCLST ; Get the address
UPDS.1: SKIPE T1,(P1) ; Get the address of a function
PUSHJ P,M$RBLK ; Return that block
SETZM (P1) ; Clear the entry
AOBJN P1,UPDS.1 ; Loop for all items
POP P,T1 ; Restore the address of the block
JUMPE T1,.POPJ ; Just return if no function block
PJRST M$RBLK ; Return the block to the memory
; Table to dispatch to the different routines
TABDEF UPS,$OP
TABENT SDN,<EXP UPSSDN> ; Routine to scroll down
TABENT SUP,<EXP UPSSUP> ; Routine to scroll up
TABENT DCH,<EXP UPSDCH> ; Routine to delete a line
TABENT ICH,<EXP UPSICH> ; Routine to insert a line
TABENT ACH,<EXP UPSACH> ; Routine to accept a line
TABENT RCH,<EXP UPSRCH> ; Routine to replace a line
TABENT NOP,<EXP UPSNOP> ; Routine to process a no-op
TABEND
SUBTTL Screen editing -- Update section -- Scroll up
;+
;.HL2 UPSSUP
;This routine will cause n lines to be scrolled up on the screen.
;The boundary line will be in the CSTDEP field of the function.
;.literal
;
; Usage:
; MOVE T1,Number.of.lines
; PUSHJ P,UPSSUP
; (Return)
;
;.end literal
;-
UPSSUP: JUMPE T1,USUP.D ; Is this the end of a scrolled region?
$SAVE <P1> ; Save P1
MOVE P1,T1 ; Get the count
PUSH P,T2 ; Save the offset to the last line
SUBM T2,T1 ; Get the number of lines which will remain
SUB P4,P1 ; Count the number of lines
MOVN T3,P1 ; Also for total
ADDM T3,IDLCNT ; So that replace works correctly
; the same
PUSHJ P,UPSLUP ; Move the LDB's up
TXNE CRT,CR$SCR ; Have scrolling functions?
JRST USUP.2 ; Yes, go use them
PUSH P,Y ; Save the current line number
MOVE Y,$CRLIN(CRT) ; Get the final line number (+1)
SOJ Y, ; Decrement to get real one
SETZ X, ; Clear the X pos
PUSHJ P,SC$POS ; Position to that point
MOVE T1,P1 ; Get the number to do
MOVX CH,.CHLFD ; Get a line feed
PUSHJ P,SC$IMG ; And cause the screen to scroll
SOJG T1,.-1 ; Output the correct number to move things up
POP P,Y ; Restore the line number
POP P,T2 ; Restore T2
POPJ P, ; And return
; Here if the terminal has scrolling functions
USUP.2: MOVE T1,P1 ; Get the number to scroll
MOVE T2,Y ; Get the top line
PUSH P,Y ; Save Y
MOVE Y,-1(P) ; Get the offset
ADD Y,T2 ; And make the correct bottom line number
SUBI Y,1 ; . . .
XCT $CRSUP(CRT) ; Scroll the region
POP P,Y ; Restore Y
POP P,T2 ; Restore T2
POPJ P, ; And return
; Here if the function is for the end of a scroll. Fix up the insert/delete
;line counts and write the text.
USUP.D: PUSH P,T2 ; Save the count
MOVE T1,T2 ; Copy it
PUSHJ P,UPSRCH ; Update the section
POP P,T2 ; Restore the count
ADD P4,T2 ; Fix this count
ADDM T2,IDLCNT ; Also here.
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Update section -- Scroll down
;+
;.HL2 UPSSDN
;This routine will cause n lines to be scrolled down on the screen.
;The boundary line number will be in the CSTDEP field of the function
;block.
;.literal
;
; Usage:
; MOVE T1,Number.of.lines
; MOVE T2,Offset to bottom line
; PUSHJ P,UPSSDN
; (Return)
;
;.end literal
;-
UPSSDN: JUMPE T1,USDN.D ; Is this the bottom line?
$SAVE <P1> ; Save P1
MOVE P1,T1 ; Get the number of lines to scroll
PUSH P,T2 ; Save the offset to the last line
MOVE T1,T2 ; Get it for fixing the LDB's
PUSHJ P,UPSLDN ; Scroll things down
IFN FTDEBUG,<
TXNE CRT,CR$SCR ; Have real scrolling?
JRST USDN.F ; Yes, go do it
TXNN CRT,CR$RLF ; No, have a reverse line feed?
STOPCD NRL,<UPSSDN called for terminal without reverse line feed>
SKIPE Y ; First line of screen?
STOPCD NFL,<Not first line for UPSSDN to scroll>
USDN.F:> ; End of IFN FTDEBUG
; First cause the terminal to actually move the lines.
MOVE T1,P1 ; Get the repeat count
POP P,T2 ; And get the offset off the stack
ADDI T2,(Y) ; Point to the bottom line
SOJ T2, ; Minus one
XCT $CRSDN(CRT) ; Scroll down
ADD P4,P1 ; Fix the count of lines inserted
ADDM P1,IDLCNT ; Here also
USDN.3: $CHTYI ; Any type ahead
JRST .+2 ; No, continue on
POPJ P, ; Yes, return
LOAD. T1,LDBQRG,(P3) ; Update the Q-reg address
STOR. T1,LDBQRG,(P2) ; . . .
LOAD. T1,LDBNUM,(P3) ; Get the number of chars
STOR. T1,LDBNUM,(P2) ; Save it
LOAD. T1,LDBBEG,(P3) ; Get the start
STOR. T1,LDBBEG,(P2) ; Save it
LOAD. T1,LDBEND,(P3) ; Get the end
STOR. T1,LDBEND,(P2) ; Save it
LOAD. T1,LDBFLG,(P3) ; Get the flags
STOR. T1,LDBFLG,(P2) ; Save them
LOAD. T1,LDBTXT,(P3) ; Get the text
LOAD. T2,LDBTXT,(P2) ; And the old
STOR. T1,LDBTXT,(P2) ; Switch them around
STOR. T2,LDBTXT,(P3) ; Save the other
MOVEI T1,(P2) ; Get the LDB address
PUSHJ P,SC$WLN ; Write the line out
ADDX P2,<XWD 1,$LDLEN> ; Bump to the next line
ADDX P3,<XWD 1,$LDLEN> ; This one also
AOJ Y, ; Bump the line number
SOJLE P1,.POPJ ; Done yet?
JRST USDN.3 ; No, try again
; Here at the bottom of a scrolled down section
USDN.D: SUB P4,T2 ; Fix this count
MOVN T2,T2 ; Make it negative
ADDM T2,IDLCNT ; And fix the other
POPJ P, ; All done
SUBTTL Screen editing -- Update section -- Accept a line
;+
;.HL2 UPSACH
;This routine will accept n lines. It is called with a repeat count.
;.literal
;
; Usage:
; MOVE T1,Repeat.count
; PUSHJ P,UPSACH
; (Return)
;
;.end literal
;-
UPSACH: ADD Y,T1 ; Increment the Y address
; Loop to copy the line information (other than the text)
UPSA.0: LOAD. T2,LDBQRG,(P3) ; Copy the Q-reg address
STOR. T2,LDBQRG,(P2) ; . . .
LOAD. T2,LDBBEG,(P3) ; Get the new beg
STOR. T2,LDBBEG,(P2) ; Store it
LOAD. T2,LDBEND,(P3) ; Get the new end
STOR. T2,LDBEND,(P2) ; Store it
LOAD. T2,LDBFLG,(P3) ; Get the flags
STOR. T2,LDBFLG,(P2) ; Store them
; Note that LDBNUM and LDBTXT don't need to be copied since the LDBNUM
;fields must be the same and the LDBTXT buffers contain the same text in
;order for the line to be accepted
ADDX P2,<XWD 1,$LDLEN> ; Bump the old pointer
ADDX P3,<XWD 1,$LDLEN> ; And the new
SOJG T1,UPSA.0 ; Loop for all the lines being accepted
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Update section -- Replace a line
;+
;.HL2 UPSRCH
;This routine will replace n lines. It is called with a repeat count
;for the number of lines that are to be replaced.
;.literal
;
; Usage:
; MOVE T1,Repeat.count
; PUSHJ P,UPSRCH
; (Return)
;
;.end literal
;-
UPSRCH: $SAVE <P1> ; Save P1
MOVE P1,T1 ; Copy the repeat count
UPSR.0: SETZ T1, ; Clear this
SKIPE IDLCNT ; Inserts/delets balanced?
JRST UPSR.1 ; No, Skip this
MOVX T2,LD$SME ; Check if lines are identical
TDNE T2,$LDFLG(P3) ; Are they?
JRST UPSR.3 ; Yes, don't need to even look at them
LOAD. T2,LDBLIN,(P2) ; Yes, get the line number
ADD T2,FNCLST ; Point to the function block
EXCH T1,(T2) ; Get the function block for line N
JRST UPSR.2 ; Go update the line
; Here if we don't have a function block for these lines
UPSR.1: LOAD. T2,LDBNUM,(P2) ; Get the number of characters
JUMPE T2,UPSR.2 ; Just update the line
TXNN CRT,CR$DIC ; Have delete and insert character?
JRST UPSR.2 ; No, skip this
MOVEI T1,(P2) ; Get the old LDB address
MOVEI T2,(P3) ; And the new
PUSHJ P,LINCST ; Compute the best method of updating this line
MOVE T1,T2 ; Get the address of the function block
UPSR.2: MOVEI T2,(P2) ; Get the addresses
MOVEI T3,(P3) ; . . .
PUSHJ P,UPDLIN ; Update the line
UPSR.3: LOAD. T1,LDBQRG,(P3) ; Get the Q-reg address
STOR. T1,LDBQRG,(P2) ; Save it in the new LDB
LOAD. T1,LDBTXT,(P2) ; Get the old text address
LOAD. T2,LDBTXT,(P3) ; And the new
STOR. T1,LDBTXT,(P3) ; Reverse the pointers
STOR. T2,LDBTXT,(P2) ; . . .
LOAD. T1,LDBNUM,(P3) ; Get the new number of chars
STOR. T1,LDBNUM,(P2) ; Store it
LOAD. T1,LDBBEG,(P3) ; Get the beg
STOR. T1,LDBBEG,(P2) ; Store it
LOAD. T1,LDBEND,(P3) ; Get the end address
STOR. T1,LDBEND,(P2) ; Store it
LOAD. T1,LDBFLG,(P3) ; Get the flags
STOR. T1,LDBFLG,(P2) ; Store them
ADDX P2,<XWD 1,$LDLEN> ; Move to the next LDB
ADDX P3,<XWD 1,$LDLEN> ; This one also
AOJ Y, ; Bump the line number
$CHTYI ; Check if any type ahead
SOJG P1,UPSR.0 ; Loop for replaces
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Update section -- Delete a line
;+
;.HL2 UPSDCH
;This routine will cause a line(s) to be deleted. The number of lines
;to be deleted depends on the repeat count.
;.literal
;
; Usage:
; MOVE T1,Repeat.count
; PUSHJ P,UPSDCH
; (Return)
;
;.end literal
;-
UPSDCH: $SAVE <P1> ; Save P1
MOVE P1,T1 ; Copy the repeat count
SETZ X, ; Clear the X position
; Check if we are deleting to the end of the screen
LOAD. T1,LDBLIN,(P2) ; Get the line number of the first line
ADD T1,P1 ; Plus the number being deleted
IFN FTDEBUG,<
CAMG T1,SCRNLN ; Deleting to the end of the screen?
JRST UPSD.3 ; No, must do delete lines
STOPCD (DMM,<A delete section function cause movement out of the matrix>)
>; End of IFN FTDEBUG
; First loop clearing the text in the LDBs that are being deleted
UPSD.3: MOVE T2,SCRNLN ; Get the line number of the first
SUBM T2,T1 ; Compute the number to move up
PUSHJ P,UPSLUP ; Move lines up
; Now do the work of deleting the information from the screen
SUB P4,P1 ; Decrement by the number of lines
MOVN T1,P1 ; Get the negative number
ADDM T1,IDLCNT ; And fix the total insert/delete count
PUSHJ P,SC$POS ; Position to the correct place
MOVE T1,P1 ; Copy the repeat factor into the right place
XCT $CRDLL(CRT) ; Delete the lines
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Update section -- Insert a line(s)
;+
;.HL2 UPSICH
;This routine will cause one or more lines to be inserted. The number
;of lines that are handled depends on the repeat count given.
;.literal
;
; Usage:
; MOVE T1,Repeat.count
; PUSHJ P,UPSICH
; (Return)
;
;.end literal
;-
UPSICH: ADD P4,T1 ; Add in the repeat count
ADDM T1,IDLCNT ; Also fix the total counter
SKIPLE P4 ; Have to do it the hard way ?
PUSHJ P,UPSISB ; Yes, call the subroutine
$SAVE <P1> ; Save P1
MOVE P1,T1 ; Copy the repeat count to a safer place
; Move the LDBs around first. This is done by first saving the TXT
; addresses from the bottom of the screen on the stack. Then moving
; the ones above down.
MOVE T2,SCRNLN ; Get the number of lines on the CRT
SUBI T2,1 ; Decrement by one
IMULX T2,$LDLEN ; Compute the address of the last LDB
ADD T2,SCRNAD ; Get the actual address
MOVE T4,T2 ; Get a copy of it
UPSI.3: LOAD. T3,LDBTXT,(T2) ; Get the address of the text block
PUSH P,T3 ; Save it on the stack
SUBX T2,$LDLEN ; Backup up one LDB
SOJG T1,UPSI.3 ; Loop for the number of lines being inserted
; Now move the other information down
MOVE T1,SCRNLN ; Get the number of lines again
SUB T1,Y ; And get the number of lines we are moving
SUB T1,P1 ; . . .
UPSI.4: LOAD. T3,LDBQRG,(T2) ; Get the address of the Q-reg
STOR. T3,LDBQRG,(T4) ; Store it
LOAD. T3,LDBTXT,(T2) ; Get the address of a text block
STOR. T3,LDBTXT,(T4) ; Store it down below
LOAD. T3,LDBNUM,(T2) ; Move the number of characters
STOR. T3,LDBNUM,(T4) ; . .
LOAD. T3,LDBFLG,(T2) ; Move the flags down
STOR. T3,LDBFLG,(T4) ; . . .
LOAD. T3,LDBBEG,(T2) ; Move the beginning down
STOR. T3,LDBBEG,(T4) ; . . .
LOAD. T3,LDBEND,(T2) ; Move the ending down
STOR. T3,LDBEND,(T4) ; . . .
SUBX T2,$LDLEN ; Back up another LDB
SUBX T4,$LDLEN ; . . .
SOJG T1,UPSI.4 ; Try again
MOVE T1,P1 ; Get the number of lines being inserted
IMULX T1,$LDLEN ; And make the number of words to back up P2
HRLI T1,(P1) ; Also fix the counter
SETZ X, ; Clear the X position
PUSHJ P,SC$POS ; Position to the place
MOVE T1,P1 ; Get the number to insert
XCT $CRINL(CRT) ; Cause that may lines to appear
UPSI.0: $CHTYI ; Check if any type ahead
JRST .+2 ; No, continue on
JRST UPSI.6 ; Yes, go clear out the remaining LDB's
LOAD. T1,LDBQRG,(P3) ; Copy the QRG address
STOR. T1,LDBQRG,(P2) ; . . .
LOAD. T1,LDBBEG,(P3) ; Get the beginning adress
STOR. T1,LDBBEG,(P2) ; Store it
LOAD. T1,LDBEND,(P3) ; Move the ends
STOR. T1,LDBEND,(P2) ; . . .
LOAD. T1,LDBFLG,(P3) ; Move the flags
STOR. T1,LDBFLG,(P2) ; . . .
LOAD. T1,LDBNUM,(P3) ; Move the number of characters
STOR. T1,LDBNUM,(P2) ; . . .
LOAD. T1,LDBTXT,(P3) ; Get the address of the text
STOR. T1,LDBTXT,(P2) ; Store in a safer place
POP P,T2 ; Get the text area from the stack
STOR. T2,LDBTXT,(P3) ; Make it the one that gets returned
MOVE T1,P2 ; Get the LDB address
PUSHJ P,SC$WLN ; And write the line
ADDX P2,<1,,$LDLEN> ; Point to the next LDB
ADDX P3,<1,,$LDLEN> ; Point to the next LDB
AOJ Y, ; Bump the line number
SETZ X, ; Clear the X position
SOJLE P1,.POPJ ; Return if done
JRST UPSI.0 ; Loop back
; Here if the user has typed ahead. We will abort the typeout, so we
;have to fix up the rest of the LDB's to reflect the current state of the
;screen.
UPSI.6: POP P,T1 ; Restore the ldb
STOR. T1,LDBTXT,(P2) ; Get the address of teh text
MOVEI T1,(P2) ; Get the LDB address
PUSHJ P,FLSLDB ; Flush out the LDB
ADDX P2,<XWD 1,$LDLEN> ; Bump the pointer
SOJG P1,UPSI.6 ; Loop for all the lines we still have left
POPJ P, ; And return
; Here if we must first delete line before the lines can be inserted
; Look down the function list for a delete function and process that
; before the insert. After enough deletes have been done then the insert
; should be capable of being done.
UPSISB: $SAVE <X,Y> ; Save the position
$SAVE <P1,P2,P3> ; Save the pointers to LDBs and functions
$SAVE <T1,IDLCNT> ; Save T1 and the insert/delete count
MOVEI T2,(T1) ; Get a copy of the repeat count
IMULX T2,$LDLEN ; And make it the number of words to skip in the LDB's
HRLI T2,(T1) ; Fix the pointers
ADD P3,T2 ; Skip the right number of new lines
UPSIS0: AOBJP P1,[STOPCD ROF,<Ran out of functions at UPSISB>]
LOAD. T1,CSTRPT,(P1) ; Get a repeat count
LOAD. T2,CSTOPR,(P1) ; And the operation
CAXE T2,$OPDCH ; Is this a delete function ?
JRST UPSIS1 ; No, Just update the pointers and continue
MOVX T2,$OPNOP ; Change the function to a no-operation
STOR. T2,CSTOPR,(P1) ; Store the operation
PUSHJ P,UPSDCH ; Do the function
$CHTYI ; Check for type ahead
JUMPG P4,UPSIS0 ; If more to do than loop
POPJ P, ; Else just return
; Here if the function is not a delete function. This means that the
; function is just skiped and the line counter updated with the repeat
; count.
UPSIS1: CAXE T2,$OPICH ; Is this an insert function
CAXN T2,$OPNOP ; Was it a no-op?
JRST UPSIS0 ; Yes, don't bother incrementing either
ADD Y,T1 ; Increment the count
MOVEI T3,(T1) ; Get the repeat count
IMULX T3,$LDLEN ; Get the number of words to skip
HRLI T3,(T1) ; Make it the number to fix the AOBJx pointer
ADD P3,T3 ; Increment the new line pointer
ADD P2,T3 ; No, increment the other pointer also
JRST UPSIS0 ; Loop back
SUBTTL Screen editing -- Update section -- No-op
;+
;.HL2 UPSNOP
;This routine will cause a no-op to be processed. This occurs if you
;have to insert lines before you have started to delete lines.
;.literal
;
; Usage:
; MOVE T1,Repeat.count
; PUSHJ P,UPSNOP
; (Return)
;
;.end literal
;-
UPSNOP: MOVN T2,T1 ; Get the number of lines
ADDM T2,IDLCNT ; And fix the counter (NOOP's were deletes)
POPJ P, ; Return to the caller
SUBTTL Screen editing -- UPSLUP - Move LDB's up
;+
;.hl1 UPSLUP
; This routine will move the information a given set of LDB's upwards.
;The LDB's from the top of the section will be cleared.
;.b.lit
;
; Usage:
; MOVE P1,Number.of.lines
; MOVE P2,AOBJx pointer to first line of section
; MOVE T1,Number of lines which will remain the same
; PUSHJ P,UPSLUP
; (return here, LDB's moved)
;
;.end literal
;-
UPSLUP: JUMPE T1,UDLN.W ; If none remain the same, just clear the lines
MOVE T3,T1 ; Get the offset for later
MOVN T4,P1 ; Get minus the number being repeated
MOVSI T4,(T4) ; Build the AOBJN pointer
HRR T4,P2 ; Get the address of the first
UPSL.0: LOAD. T1,LDBTXT,(T4) ; Get the address
PUSH P,T1 ; And save it on the stack
PUSHJ P,CLRL.0 ; Clear this LDB
ADDX T4,$LDLEN-1 ; Point to the next entry
AOBJN T4,UPSL.0 ; Loop for all the LDBs
; Now play musical LDBs so the SCRNAD always points to what is really being
; displayed on the screen. This is done by BLTing the information up.
LOAD. T1,LDBLIN,(P2) ; Get the line number of this LDB
ADD T1,P1 ; Add in the number being deleted
; T1 now contains the line number of the last
; LDB
MOVE T2,T3 ; Get the number of times to loop
HRRZ T3,P2 ; Get the address to
MOVE T1,P1 ; Get the number of lines
IMULX T1,$LDLEN ; Make it the number of words for the LDB's
ADDI T1,(P2) ; And point to the address to fetch from
PUSH P,P1 ; Save P1
PUSH P,P2 ; And P2
UPSL.2: LOAD. T4,LDBQRG,(T1) ; Copy the Q-reg address
STOR. T4,LDBQRG,(T3) ; . . .
LOAD. T4,LDBBEG,(T1) ; Get the from address
STOR. T4,LDBBEG,(T3) ; Store it
LOAD. T4,LDBEND,(T1) ; Move the ending
STOR. T4,LDBEND,(T3) ; . . .
LOAD. T4,LDBNUM,(T1) ; Get the number
STOR. T4,LDBNUM,(T3) ; . . .
LOAD. T4,LDBFLG,(T1) ; Get the flags
STOR. T4,LDBFLG,(T3) ; Store the flags
LOAD. T4,LDBTXT,(T1) ; Get the text block address
STOR. T4,LDBTXT,(T3) ; . . .
ADDX T3,$LDLEN ; Point to the next LDB
ADDX T1,$LDLEN ; . . .
SOJG T2,UPSL.2 ; Loop for all the LDBs
POP P,P2 ; Restore P2
POP P,P1 ; And P1
MOVEI T1,(T3) ; Get the address for storing the old LDB's
MOVN T3,P1 ; Build an AOBJN loop
HRL T1,T3 ; . . .
UPSL.1: POP P,T2 ; Restore a TXT address
STOR. T2,LDBTXT,(T1) ; Store it into the correct place
ZERO. ,LDBNUM,(T1) ; Clear the number of chars on the line
ZERO. ,LDBFLG,(T1) ; And the flags
ONES. ,LDBBEG,(T1) ; Clear the BEG
ONES. ,LDBEND,(T1) ; And the END so we no this data is worthless
ADDX T1,$LDLEN-1 ; Compute the next address
AOBJN T1,UPSL.1 ; Loop for all items
POPJ P, ; All done
SUBTTL Screen editing -- UPSLDN - Move LDB's down
;+
;.HL1 UPSLDN
; This routine is called to move the LDB information down. This is used
;when a section of the screen is being scrolled down by an operation.
;.literal
;
; Usage:
; MOVE P1,Number of lines to scroll
; MOVE P2,AOBJx pointer to the LDB's
; MOVE T1,Size of section
; PUSHJ P,UPSLDN
; (return here, text moved)
;
;.end literal
;-
UPSLDN: CAMN T1,P1 ; Moving the whole section?
JRST UDLN.W ; Yes, go handle it
$SAVE <P3,P4> ; Save a couple ac's to work with
MOVE P3,T1 ; Get the size of the section
MOVEI T2,-1(T1) ; Get the total number of lines being affected
IMULX T2,$LDLEN ; And make it the offset to the last
ADDI T2,(P2) ; Point to the last line
MOVE T3,P1 ; Get the number of lines the section is being shifted
MOVE T4,T2 ; Get the pointer to the line
UDLN.1: LOAD. T1,LDBTXT,(T2) ; Get the text address
PUSH P,T1 ; Save it for later
SUBX T2,$LDLEN ; Back up a line
SOJG T3,UDLN.1 ; And loop
; Now move the lines which will remain the same down
MOVE T3,P3 ; Get the number of lines total
SUB T3,P1 ; Minus the number being shifted out
; Macro to make things easier
DEFINE MVDN(FLD),<
IRP <FLD>,<
LOAD. T1,LDB'FLD,(T2) ;; Get the info
STOR. T1,LDB'FLD,(T4) ;; And move it down
> ;; End of IRP
> ; End of MVDN macro
PUSH P,P1 ; Save P1
PUSH P,P2 ; And P2
UDLN.2: MVDN(<QRG,TXT,NUM,FLG,BEG,END>) ; Move everything down
SUBX T2,$LDLEN ; Back up the top pointer
SUBX T4,$LDLEN ; And the bottom
SOJG T3,UDLN.2 ; And loop for all that are necessary
POP P,P2 ; Restore P2
POP P,P1 ; And P1
; Now pop the lines we saved on the stack and clear them
MOVE T3,P1 ; Get the number of times to loop
UDLN.3: POP P,T1 ; Get the address back
STOR. T1,LDBTXT,(T4) ; Store it
MOVEI T1,(T4) ; Get the LDB address
PUSHJ P,FLSLDB ; Clear the text out
SUBX T4,$LDLEN ; Back up a line
SOJG T3,UDLN.3 ; And loop
POPJ P, ; All done
; Here if for some reason we are scrolling the same number of lines as there
;are in the section. (I'm not sure if this will ever occur, but the cost
;algorithms will find some non-obvious ways of doing things at times.)
UDLN.W: MOVEI T4,(P2) ; Get the first LDB address
MOVEI T3,(P1) ; And the number of times to loop
UDLN.4: MOVEI T1,(T4) ; Get the LDB address
PUSHJ P,FLSLDB ; And clear it out
ADDX T4,$LDLEN ; Bump to the next line
SOJG T3,UDLN.4 ; And loop
POPJ P, ; All done
SUBTTL Screen editing -- OPR2SC -- Convert operation to scrolling
;+
;.hl1 OPR2SC
;This routine will cause the insert and delete functions to be converted
;into scrolling operations. This will only happen on terminals that do
;not have the insert and delete line functions. A good example of a terminal
;like this is the VT100.
;.literal
;
; Usage:
; MOVE T1,Function.list
; PUSHJ P,OPR2SC
; (Return -- Updated list in T1)
;
;.end literal
;-
OPR2SC: JUMPE T1,.POPJ ; Just return if no list to search
$SAVE <P1,P2,P3,P4> ; Save a few registers
PUSH P,T1 ; Save T1
MOVE P1,T1 ; Copy the function list address
MOVE P2,FNCBLK ; Get the function block address
MOVEI P3,1(P) ; Get the address of the free stack entry
IFN FTKL,ADJSP P,@SCRNLN ; Allocate the space on the stack
IFE FTKL,<
MOVE T1,SCRNLN ; Get the number of lines
HRLI T1,(T1) ; Make the XWD
ADD P,T1 ; And fix the stack pointer
> ; End of IFE FTKL
MOVEI P4,(P3) ; Get the base address here also
; First run through the list clearing out CSTDEP in all the entries, so
;that we can use it ourself
PUSH P,P1 ; Save the pointer
MOVX T1,CS$DEP ; Get the mask
ANDCAM T1,(P1) ; Clear the field
AOBJN P1,.-1 ; And loop for all of them
POP P,P1 ; Restore the pointer
OPR2.0: CAIN P3,(P4) ; Any fixups to do?
JRST OPR2.1 ; No, skip this
HLRE T1,P1 ; Get the current loc into the list
HLRE T2,(P3) ; And the one we are waiting for
CAME T1,T2 ; Correct function list entry?
JRST OPR2.1 ; No, do this one
HRRE T1,(P3) ; Get the repeat count
MOVX T2,<INSVL.($OPSDN,CS$OPR)> ; Assume this is the end of a scroll down
JUMPGE T1,.+2 ; Is it?
MOVX T2,<INSVL.($OPSUP,CS$OPR)> ; No, get the scroll up
MOVM T1,T1 ; Get the count
STOR. T1,CSTDEP,+T2 ; Save it
MOVEM T2,(P2) ; Store the word
AOJ P2, ; Bump the index
AOJA P3,OPR2.0 ; And check the next fixup
OPR2.1: MOVE T1,(P1) ; Get the next function word
LOAD. T2,CSTOPR,+T1 ; And get the operation
XCT O2STBL(T2) ; Do correct thing
AOBJN P1,OPR2.0 ; And loop for the next
IFN FTKL,<
MOVN T2,SCRNLN ; Get the number of lines
ADJSP P,(T2) ; Remove the items from the stack
>; End of IFN FTKL
IFE FTKL,<
MOVE T2,SCRNLN ; Get the number of lines to remove
HRL T2,T2 ; Move the number into both halfs
SUB P,T2 ; Fix the stack
>; End of IFE FTKL
POP P,T1 ; Get the count back
HRR T1,FNCBLK ; And set the pointer correctly
SUB P2,FNCBLK ; Get the length
MOVN P2,P2 ; Negate it
HRLI T1,(P2) ; And set up the pointer
POPJ P, ; And return
; The following is the dispatch table for the operations on the function
; list. These routines will determine that is to be done with the function
; list.
TABDEF O2S,$OP
TABENT NOP,<JFCL> ; No-op function
TABENT ACH,<PUSHJ P,O2SACH> ; Accept function
TABENT RCH,<PUSHJ P,O2SRCH> ; Replace function
TABENT SUP,<PUSHJ P,O2SSUP> ; scroll up (?)
TABENT SDN,<PUSHJ P,O2SSDN> ; Scroll down (?)
TABENT ICH,<PUSHJ P,O2SICH> ; Insert lines
TABENT DCH,<PUSHJ P,O2SDCH> ; Delete lines
TABEND
SUBTTL Screen editing -- OPR2SC -- Accept function
SUBTTL Screen editing -- OPR2SC -- Replace function
; Here for the accept and replace functions.
O2SRCH:
O2SACH: MOVEM T1,(P2) ; Save the entry
AOJA P2,.POPJ ; And return
SUBTTL Screen editing -- OPR2SC -- Scroll down fuction
; Here to handle the scroll down function. This function is not expected
; to occur.
O2SSDN: STOPCD FSD,<Found a scroll down function in OPR2SC>
SUBTTL Screen editing -- OPR2SC -- Scroll up function
; Here to handle the scroll up function. This function is not expected
; to occur.
O2SSUP: STOPCD FSU,<Found a scrolll up function in OPR2SC>
SUBTTL Screen editing -- OPR2SC -- Insert lines
; Here to cause lines to be inserted. To do this we must first
; find the matching delete(s) for this function.
O2SICH: SKIPA T4,[EXP $OPDCH] ; Get the function to look for
O2SDCH: MOVX T4,$OPICH ; Get the insert function we want to find
O2SI.0: MOVE T1,T4 ; Get the function
PUSHJ P,O2SFND ; Find it
JUMPE T1,[STOPCD FFD,<Failed to find a delete to match>]
MOVX T3,<INSVL.($OPSDN,CS$OPR)> ; Get the scroll down function
CAXE T4,$OPDCH ; Is that correct?
MOVX T3,<INSVL.($OPSUP,CS$OPR)> ; No, scroll down
MOVEM T3,(P2) ; Save the function
PUSH P,T2 ; Save the number of lines being skipped
HLLM T1,(P4) ; Save the index for the point to do the fixup
LOAD. T2,CSTRPT,(T1) ; Get the repeat count for the function we found
LOAD. T3,CSTRPT,(P1) ; And the one for the current function
CAME T2,T3 ; Same counts on both functions?
JRST O2SI.1 ; No, check which is larger
STOR. T3,CSTRPT,(P2) ; Yes, store the count
LOAD. T2,CSTDEP,(T1) ; Get the count of inserts already done (maybe)
ADD T2,T3 ; Plus the amount we are doing now
CAXE T4,$OPDCH ; Was this an insert?
STOR. T2,CSTDEP,(T1) ; Yes, update the count
POP P,T2 ; Get the number of skipped lines back
ADD T2,T3 ; Get the total
STOR. T2,CSTDEP,(P2) ; Store the offset
LOAD. T3,CSTRPT,(P2) ; Get the repeat count back
CAXE T4,$OPDCH ; Was this an insert?
MOVN T3,T3 ; No, negate the count
HRRM T3,(P4) ; And save it
AOJ P4, ; Bump past the new entry
STORI. $OPNOP,T3,CSTOPR,(T1) ; And convert the other function to a no-op
AOJA P2,.POPJ ; Count the entry and return
; Here if the repeat counts don't match
O2SI.1: CAMG T2,T3 ; Bottom function larger?
JRST O2SI.2 ; No, go handle it
SUB T2,T3 ; Yes, get the number left
STOR. T3,CSTRPT,(P2) ; Save the count of scroll functions
STOR. T2,CSTRPT,(T1) ; And fix up the bottom function repeat count
POP P,T2 ; Get the number of skipped lines back
ADD T3,T2 ; Get the total length of the region
STOR. T3,CSTDEP,(P2) ; Store the offset
LOAD. T3,CSTRPT,(P2) ; Get the repeat count
LOAD. T2,CSTDEP,(T1) ; Get the count of inserts already done (maybe)
ADD T2,T3 ; Plus the amount we are doing now
CAXE T4,$OPDCH ; Was this an insert?
STOR. T2,CSTDEP,(T1) ; Yes, update the count
CAXE T4,$OPDCH ; Was this an insert?
MOVN T3,T3 ; No, negate the count
HRRM T3,(P4) ; And save it
AOJ P4, ; Bump past the new entry
AOJA P2,.POPJ ; Count the entry and return
; Here if the top function has the larger repeat count
O2SI.2: STOR. T2,CSTRPT,(P2) ; Store the number we can do first
CAXE T4,$OPDCH ; Insert ?
ADDM T3,(P) ; Get the overall length
SUB T3,T2 ; Get the number left
STOR. T3,CSTRPT,(P1) ; Reset it
STORI. $OPNOP,T3,CSTOPR,(T1) ; Change the bottom function to a no-op
POP P,T3 ; Get the number of skipped lines back
CAXN T4,$OPDCH ; Insert ?
ADD T3,T2 ; No, must have different count
STOR. T3,CSTDEP,(P2) ; Store the offset
LOAD. T3,CSTRPT,(P2) ; Get the repeat count
LOAD. T2,CSTDEP,(T1) ; Get the count of inserts already done (maybe)
ADD T2,T3 ; Plus the amount we are doing now
CAXE T4,$OPDCH ; Was this an insert?
STOR. T2,CSTDEP,(T1) ; Yes, update the count
CAXE T4,$OPDCH ; Was this an insert?
MOVN T3,T3 ; No, negate the count
HRRM T3,(P4) ; And save it
AOJ P4, ; Bump past the new entry
ANDX T1,RH.ALF ; Keep only the address
CAIE T1,1(P1) ; Is this the next item?
AOJA P2,O2SI.0 ; No, just try again
AOJ P2, ; Point to the next word
MOVX T2,<INSVL.($OPSDN,CS$OPR)> ; Get the operation
CAXE T4,$OPDCH ; Insert?
MOVX T2,<INSVL.($OPSUP,CS$OPR)> ; No, get correct operation
PUSH P,T2 ; Save on the stack
HRRE T2,-1(P4) ; Get the offset
MOVM T2,T2 ; Make positive
STOR. T2,CSTDEP,(P) ; Store it
SOJ P4, ; Remove the item from the list
PUSHJ P,O2SI.0 ; Generate the rest of this item
POP P,(P2) ; Restore the operation
AOJA P2,.POPJ ; And return
SUBTTL Screen editing -- OPR2SC -- Find a function
; This routine will look for a function on the function list. It
; will return the address of the function and the number of lines
; from the start to it.
;
; Usage:
; MOVE T1,Function to look for
; PUSHJ P,O2SFND ; Find the function
; (Return - T1 contains the address and T2 the number of lines)
O2SFND: $SAVE <P1,P2> ; Save the function list pointer
SETZ T2, ; Clear the number of lines
AOBJP P1,O2SF.2 ; Return if finished
O2SF.0: LOAD. T3,CSTRPT,(P1) ; Get the repeat count
LOAD. P2,CSTOPR,(P1) ; Get the operation
CAXE P2,$OPNOP ; Is this a no-op?
CAXN P2,$OPICH ; No, is this an insert?
LOAD. T3,CSTDEP,(P1) ; Get the count of operations already done here
CAME P2,T1 ; Same operator?
JRST O2SF.1 ; No, keep looking
CAXN P2,$OPICH ; Insert?
ADD T2,T3 ; Yes, include the count of what was already done
MOVE T1,P1 ; Copy the pointer
POPJ P, ; Return
; Here to increment the count of the number of lines
O2SF.1: ADD T2,T3 ; Increment the pointer
O2SF.3: AOBJN P1,O2SF.0 ; Loop for all the functions
O2SF.2: SETZ T1, ; Clear it
POPJ P, ; And return
SUBTTL Screen editing -- SCTCST - Determine best way of updating screen
;+
;.HL1 SCTCST
; This routine will calculate the best method of updating the screen.
;It will do this only for terminals which have insert/delete line
;functions. The algorithm used is the same as that used by LINCST
;for terminals with insert and delete character functions.
;.b.lit
;
; Usage:
; MOVE T1,[XWD -n,Old LDB's]
; MOVE T2,[XWD -n,New LDB's]
; PUSHJ P,SCTCST
; (return, T1= -n,,function block, or 0 if just do replacements)
;
;.end literal
;-
SCTCST: $SAVE <P1,P2,P3,P4> ; Save some room to work
$SAVE <X,Y> ; Save X and Y also
MOVEM T1,OLDLDP ; Save the old line pointers
MOVEM T2,NEWLDP ; And the new one
SETZM TOTCST ; Clear the total cost
; First thing we will do is to find the first pair of old
;and new lines which are different. These lines will be the first lines
;we consider for moving.
DMOVE X,T1 ; Get the pointers
LOAD. P1,LDBLIN,(X) ; Get the line number of the first line
MOVE P2,P1 ; Get a copy
ADD P2,CSTLST ; Get the address of the cost list
ADD P1,FNCLST ; Plus the address of the function list
SETZB P3,P4 ; Clear the first and last LDB addresses
SETOM UPCSFL ; Flag we want the function blocks returned
SCTC.B: LOAD T2,$LDFLG(Y),LD$SME ; Check if the same line
JMPT T2,[SETZB T1,T2 ; Clear the cost and function
JRST SCTC.Z] ; And go store it
HRRZ T1,X ; Get the old LDB address
HRRZ T2,Y ; And the new
PUSHJ P,LINCST ; Get the cost
SCTC.Z: MOVEM T1,(P2) ; Save the cost
MOVEM T2,(P1) ; And the function block address
ADDM T1,TOTCST ; Get the total cost so far
JUMPE T1,SCTC.C ; Line the same?
MOVE P3,X ; No, remember the LDB address
JUMPN P4,SCTC.C ; Go for the next
MOVE P4,X ; Remember first different line
SCTC.C: ADDX X,$LDLEN-1 ; Point almost to the next
ADDX Y,$LDLEN ; Make this one point to the next
$CHTYI(NOWAIT) ; Check for type ahead
JRST .+2 ; None, skip on
PJRST .RET0 ; Have some, return now
AOJ P1, ; Bump the function pointer
AOJ P2, ; And the cost pointer
AOBJN X,SCTC.B ; Loop for all the lines
; Here with P4= first old LDB of lines which are different and
;P3= last old LDB of lines which are different.
TXNN CRT,CR$DIL!CR$SCR ; Terminal have delete/insert line or scrolling region?
JRST SCTRPL ; No, calculate based on replacement plus line feed scrolling
HLRE T1,P4 ; Get the first line
HLRE T2,P3 ; And the last
HLRE T3,OLDLDP ; Get the number of old lines
SUBB T1,T3 ; Get the number of initial lines to accept
MOVEM T1,BEGACC ; Save the number of accept functions to start with
JUMPE P3,.+2 ; Get any ending lines?
AOJ T2, ; Get the number of lines at the end to accept
MOVNM T2,ENDACC ; Save it
IMULX T1,$LDLEN ; Get the amount to skip the necessary LDB's
SUB T3,T2 ; Make the number of lines total we are accepting
HRL T1,T3 ; Make the amount to add to the pointers
ADDM T1,OLDLDP ; Add to the old pointer
ADDM T1,NEWLDP ; And the new one to point to the middle lines
SKIPL OLDLDP ; Have anything left to worry about?
PJRST .RET0 ; No, return a zero now
; Here with the pointers to the lines corrected to the ones
;we wish to consider for updating.
HLRE T1,OLDLDP ; Get the number of old lines
HLRE T2,NEWLDP ; And the number of new ones
SOJ T1, ; One more for each
MOVMM T1,NUMCOL ; Save the number of columns
SOJ T2, ; . . .
IFN FTDEBUG,MOVMM T2,NUMROW ; Save the number of rows we have
IMUL T1,T2 ; Get the total number needed
MOVX T2,.BTGEN ; Get the block type
PUSHJ P,M$GBLK ; Get a block for this
MOVEM T1,MATRIX ; Save the address for later
MOVE P1,T1 ; Get a copy
MOVX T1,<INSVL.($OPACH,CS$OPR)> ; Get the initial operation
MOVEM T1,(P1) ; Save it
AOJ P1, ; Point to row 0, column 1
MOVE X,OLDLDP ; Get the pointer to the old lines
MOVE Y,NEWLDP ; Get the address of the new lines
IFN FTDEBUG,<
PUSHJ P,D$LINS ; Dump the lines for debugging
> ; End of IFN FTDEBUG
; Here to build the top row of the table. P1= the address of the element
SCTC.0: MOVE T1,-1(P1) ; Get the previous entry
XCT $CRCDL(CRT) ; Get the delete cost
MOVE T2,-1(P1) ; Get the previous entry back again
PUSHJ P,SCTSUB ; Fix up the costs
MOVEM T2,(P1) ; Store the entry
AOJ P1, ; Bump to the next entry
ADDX X,$LDLEN-1 ; Point to next
AOBJN X,SCTC.0 ; Loop for all the entries
; Now we must build column 0 of the table.
MOVE P1,MATRIX ; Reset P1
MOVE X,OLDLDP ; Get the old pointer
MOVE Y,NEWLDP ; Get the pointer to the new lines
SCTC.1: MOVE T1,(P1) ; Get the previous entry
XCT $CRCIL(CRT) ; Get the insert cost
MOVE T2,(P1) ; Get the previous entry
PUSHJ P,SCTSUB ; Fix it up
ADD P1,NUMCOL ; Move to next row
MOVEM T2,(P1) ; Store the entry
ADDX Y,$LDLEN-1 ; Bump to next line
AOBJN Y,SCTC.1 ; Loop for all of the lines
$CHTYI(NOWAIT) ; Check for type ahead
JRST .+2 ; None, continue on
JRST SCTC.E ; Go abort
MOVE Y,NEWLDP ; Reset Y
MOVE P1,MATRIX ; And P1
SETZM UPCSFL ; Flag we only want the cost now
; Here to loop for all of the new lines. Reset the pointers
;to the old lines, and set up P2 to point to the new row of the
;matrix. P1 enters pointing to the previous row, column 0.
SCTC.2: AOS P2,P1 ; Bump to the correct column and copy
ADD P2,NUMCOL ; And make it point to the correct row
MOVE X,OLDLDP ; Get the line pointer
; Here to loop for all of the old lines, comparing them to
;a given new line.
SCTC.3: LOAD. T1,LDBLIN,(X) ; Get the number of the old line
CFMN. T2,LDBLIN,(Y),T1 ; Different?
JRST SCTC.4 ; No, we already did this cost
HRRZ T1,X ; Get the old line
HRRZ T2,Y ; And the new one
PUSHJ P,LINCST ; Get the cost to convert one to the other
JRST SCTC.5 ; Go check for accept or replace
SCTC.4: ADD T1,CSTLST ; Get the address of the remembered cost
MOVE T1,(T1) ; And get the cost
SCTC.5: MOVX T2,<INSVL.($OPRCH,CS$OPR)> ; Assume we can do an accept
STOR. T1,CSTCST,+T2 ; Store the cost
JUMPN T1,.+2 ; Is it a replace?
MOVX T2,<INSVL.($OPACH,CS$OPR)> ; Replace operation
MOVE T1,T2 ; Get the operator
MOVE T2,-1(P1) ; Get the previous operation
LOAD. T3,CSTDEP,+T2 ; Get the terminal dependent field
STOR. T3,CSTDEP,+T1 ; Save in new item
PUSHJ P,SCTSUB ; Get the total cost
DMOVE P3,T1 ; Get the cost and the entry
MOVE T1,(P1) ; Get the previous entry
XCT $CRCIL(CRT) ; And calculate the insert line cost
MOVE T2,(P1) ; Get the old entry back
PUSHJ P,SCTSUB ; Get the real cost
CAMGE T1,P3 ; Is this cheaper than the replace or accept?
DMOVE P3,T1 ; Yes, get the values
MOVE T1,-1(P2) ; Get the previous to
XCT $CRCDL(CRT) ; get the delete cost
MOVE T2,-1(P2) ; Get the previous entry back
PUSHJ P,SCTSUB ; Get the total cost
CAMGE T1,P3 ; Cheaper this way?
DMOVE P3,T1 ; Yes, get the args
MOVEM P4,(P2) ; Store the chosen method of updating
; Here after finishing one entry, step to the new column in this row
$CHTYI(NOWAIT) ; Check for type ahead
JRST .+2 ; None
JRST SCTC.E ; Go abort
AOJ P1, ; Bump the previous row pointer
AOJ P2, ; And the previous column pointer
ADDX X,$LDLEN-1 ; Bump almost to the next line
AOBJN X,SCTC.3 ; Loop unless done with this row
; Here after finishing a row, step to the next
ADDX Y,$LDLEN-1 ; Increment to the next new line
AOBJN Y,SCTC.2 ; And loop if any left
IFN FTDEBUG,PUSHJ P,D$OMTX ; Output the matrix
SOS T1,P2 ; Get the address of the last entry
LOAD. T2,CSTCST,(P2) ; Get the cost
MOVEM T2,TOTCST ; Save it
SETO T2, ; Flag this is a line by line matrix
PUSHJ P,BLDFNC ; Build the function block
MOVE P1,T2 ; Save the function block address
MOVE T1,MATRIX ; Get the line matrix address
PUSHJ P,M$RBLK ; Return the core
MOVE T1,P1 ; Get the function pointer back
POPJ P, ; And return
; Here if we are aborting due to type ahead. Return the matrix
;and return a zero for the function block
SCTC.E: MOVE T1,MATRIX ; Get the address
PUSHJ P,M$RBLK ; Return the block
SETZB T1,TOTCST ; Clear the function block address
POPJ P, ; And return
SUBTTL Screen editing -- SCTCST -- SCTRPL
; Here to calculate best way of updating terminals which can only move
;the screen by using a line feed to scroll the screen upwards.
; This will get the cost for each possibility of lines scrolling.
SCTRPL: SKIPN T1,TOTCST ; Get the total cost
POPJ P, ; Screens are the same, just return
HLRE T2,OLDLDP ; Get the length of the old screen
MOVN T2,T2 ; Make it positive
SETZ T1, ; Clear this
CAME T2,SCRNLN ; Is this for the whole screen?
POPJ P, ; No, can't do any fancy things
SETZM BEGACC ; Clear number of scrolls to do
MOVE X,OLDLDP ; Get the pointer to the old lines
ADDX X,<XWD 1,$LDLEN> ; Bump it to the second line
MOVE Y,NEWLDP ; Get the new line pointer
MOVEI P4,1 ; Get the cost of one scroll (one char)
SCTR.0: MOVE P3,P4 ; Get the base cost
DMOVE P1,X ; Get the pointers
SCTR.1: MOVEI T1,(P1) ; Get the old line
MOVEI T2,(P2) ; And the new
PUSHJ P,LINCST ; Get the difference
ADD P3,T1 ; Include the cost
CAML P3,TOTCST ; Is this more than the cheapest so far?
JRST SCTR.3 ; Yes, try the next
ADDX P2,<XWD 1,$LDLEN> ; No, advance the pointer
ADDX P1,$LDLEN-1 ; This one also
AOBJN P1,SCTR.1 ; And loop
SCTR.2: LOAD. T1,LDBNUM,(P2) ; Get the number of chars on this line
ADD P3,T1 ; Total them in
CAML P3,TOTCST ; Too expensive?
JRST SCTR.3 ; Yes, try next
ADDX P2,$LDLEN-1 ; No, advance to the next buffer
AOBJN P2,SCTR.2 ; And loop
MOVEM P3,TOTCST ; If we get here it must be cheaper
MOVEM P4,BEGACC ; Store the number
SCTR.3: AOJ P4, ; Bump the scroll cost
ADDX X,$LDLEN-1 ; And advance to the next
AOBJN X,SCTR.0 ; loop for all the lines
; Now check if we should do the reverse line feed
TXNN CRT,CR$RLF ; Terminal have reverse line feed
JRST SCTR.4 ; Continue on
; Terminal has a reverse scroll operation. We will now calculate the
;costs of scrolling the screen down with the reverse line feed.
;This is done by calculating the lower diagonal of the cost matrix.
SETZM ENDACC ; Clear the count
MOVE X,OLDLDP ; Get the old LDB pointer
MOVE Y,NEWLDP ; And the new one
ADDX Y,<XWD 1,$LDLEN> ; Bump to the next line
SETZ P4, ; Clear the initial cost
SCTR.5: LOAD. T1,LDBNUM,-$LDLEN(Y) ; Get the cost of writing out the previous line
ADDX P4,<XWD 1,0> ; Count the number of operations
ADDI P4,(T1) ; Add in the cost of writing the line
XCT $CRCIL(CRT) ; Get the cost of inserting one line
ADDI P4,(T1) ; Get the total so far
MOVEI P3,(P4) ; Get the amount
CAML P3,TOTCST ; Past the total already?
JRST SCTR.7 ; Yes, punt out now
DMOVE P1,X ; Get the pointers
SCTR.6: MOVEI T1,(P1) ; Get the old LDB
MOVEI T2,(P2) ; And the new one
PUSHJ P,LINCST ; Calc the cost
ADD P3,T1 ; Total the cost
CAML P3,TOTCST ; Too much yet?
JRST SCTR.8 ; Yes, try again
ADDX P1,<XWD 1,$LDLEN> ; Bump to the next line
ADDX P2,$LDLEN-1 ; Bump this one also
AOBJN P2,SCTR.6 ; And loop
; If we succeed in falling out of the above loop, we now have a cheaper
;way of updating the screen. We must store the info and the cost.
MOVEM P3,TOTCST ; Total the cost
HLRZM P4,ENDACC ; And the number of inserts
SETZM BEGACC ; No delete stuff
SCTR.8: ADDX Y,$LDLEN-1 ; Bump the starting line address
AOBJN Y,SCTR.5 ; And loop
SCTR.7: SKIPN P3,ENDACC ; Did we decide to do it this way?
JRST SCTR.4 ; No, go check for the other case
MOVX P4,<INSVL.($OPSDN,CS$OPR)> ; Get the operation
JRST SCTR.9 ; And go generate the function block
; Here to check if we decided to scroll the screen up
SCTR.4: SKIPN T1,BEGACC ; Any scroll functions?
POPJ P, ; No, return
MOVX P4,<INSVL.($OPSUP,CS$OPR)> ; Get the operation
MOVE P3,BEGACC ; And the repeat count
; Now to set up a function block. This will be a block as follows:
; Scroll up BEGACC lines using the whole screen
; Replace SCRNLN-BEGACC lines
; End scroll up of BEGACC lines
SCTR.9: MOVX T1,3 ; No, get a three word block
MOVX T2,.BTGEN ; Get the block type
PUSHJ P,M$GBLK ; Get the block
MOVE T2,SCRNLN ; Get the number of lines
MOVE T3,P4 ; Get the function
STOR. T2,CSTDEP,+T3 ; Store the offset from first line to last
STOR. P3,CSTRPT,+T3 ; Store it
MOVEM T3,(T1) ; Store the function word
MOVX T3,<INSVL.($OPRCH,CS$OPR)> ; Get the accept function
MOVE T2,SCRNLN ; Get the number of replaces to do
SUB T2,P3 ; Minus the number of scrolls
STOR. T2,CSTRPT,+T3 ; Store the number
MOVEM T3,1(T1) ; Store the word
STOR. P3,CSTDEP,+P4 ; Store in dependent field for end of scroll
MOVEM P4,2(T1) ; Save the word
HRLI T1,-3 ; Set up the length
POPJ P, ; And return
SUBTTL Screen editing -- SCTSUB - Fix up a matrix entry
;+
;.HL2 SCTSUB
; This routine is called to fix up a cost matrix entry returned from
;the terminal dependent routines. It will add the previous cost, any
;cost due to a required positioning operation, and set the repeat
;count for the entry correctly.
;.b.lit
;
; Usage:
; MOVE T1,New entry from terminal dependent routine
; MOVE T2,Previous entry
; PUSHJ P,SCTSUB
; (Return, T1= cost in characters, T2=updated new entry)
;
;.end literal
;-
SCTSUB: LOAD. T3,CSTOPR,+T2 ; Get the previous operation
LOAD. T4,CSTOPR,+T1 ; Get the new operation
CAME T3,T4 ; Same operation?
JRST SCTS.0 ; No, check for positioning cost
LOAD. T3,CSTRPT,+T2 ; Get the repeat count
AOSA T3 ; Plus one
SCTS.1: MOVEI T3,1 ; Here if starting a new operation, this is first one
STOR. T3,CSTRPT,+T1 ; Store the new repeat count
LOAD. T3,CSTCST,+T2 ; Get the old cost
MOVE T2,T1 ; Copy the new entry
LOAD. T1,CSTCST,+T2 ; Get the new cost
ADD T1,T3 ; Make the total cost
CAXE T4,$OPICH ; Insert function?
TDZA T3,T3 ; No, extra cost is 0
LOAD. T3,LDBNUM,(Y) ; Yes, extra cost is the number of chars on the line
ADD T1,T3 ; Add the extra cost
CAXL T1,<1_<WID(CS$CST)>-1> ; Is it the maximum possible cost?
MOVX T1,.INFIN ; Yes, get infinity
STOR. T1,CSTCST,+T2 ; Store the total cost
POPJ P, ; And return
; Here when we are starting a new operation
SCTS.0: CAXE T3,$OPACH ; Was the previous operation an accept?
JRST SCTS.1 ; No, no position cost needed
PUSH P,T2 ; Save the old entry
PUSH P,T1 ; And the new
MOVX T1,<XWD 1,1> ; Set up to calculate the position cost
LOAD. T2,CSTRPT,+T2 ; Get the number of accepts we are ending
ADD T2,T1 ; Make the correct position
XCT $CRCPP(CRT) ; Get the positioning cost
POP P,T2 ; Get the new entry back
LOAD. T3,CSTCST,+T2 ; Get the cost from that
ADD T1,T3 ; Get the total
LOAD. T3,CSTCST,(P) ; Get the old cost
ADD T1,T3 ; Add that also
CFXE. T4,CSTOPR,+T2,$OPICH ; Insert function?
TDZA T3,T3 ; No, extra cost is 0
LOAD. T3,LDBNUM,(Y) ; Yes, extra cost is the number of chars on the line
ADD T1,T3 ; Add the extra cost
POP P,(P) ; Fix the stack
CAXL T1,<1_<WID(CS$CST)>-1> ; Is it the maximum possible cost?
MOVX T1,.INFIN ; Yes, get infinity
STOR. T1,CSTCST,+T2 ; Store the total cost
STORI. 1,T3,CSTRPT,+T2 ; Store the new repeat count
POPJ P, ; And return
SUBTTL Screen update routines -- LINCST - Calculate best way of line update
;+
;.HL1
; This routine will calculate the cheapest way of changing one line into
;another. If the two lines are the same relative lines on the screen, it
;will calculate the method using insert and delete character operations,
;if the terminal has them. Otherwise, it will just use replace and
;accept operations.
;.b.lit
;
; Usage:
; MOVE T1,OLD.LDB.address
; MOVE T2,NEW.LDB.address
; PUSHJ P,LINCST
; (return, T1= Cost in characters, T2=AOBJx pointer to function block or 0)
;
;.end literal
;-
LINCST: $SAVE <P1,P2,P3,P4> ; Save some room
$SAVE <X,Y,CRT> ; Save X and Y
MOVEM T1,OLDLDB ; Save the old LDB address
MOVEM T2,NEWLDB ; And the new LDB address
FALL LNCRPL ; Fall into the accept/replace cost calcuation
; Here to calculate the cost of changing the line based only
;on accept and replace operations.
LNCRPL: LOAD. P3,LDBTXT,(T1) ; Get the old text address
HRLI P3,(POINT 7,) ; Make it a byte pointer
LOAD. P4,LDBTXT,(T2) ; Get the new text address
HRLI P4,(POINT 7,) ; Make it a byte pointer
MOVEM P3,OLDPTR ; Save the old byte pointer
MOVEM P4,NEWPTR ; And the new byte pointer
LOAD. X,LDBNUM,(T1) ; Get the number of old characters
LOAD. Y,LDBNUM,(T2) ; and in the new line
MOVE T1,X ; Get the length of the old line
SUB T1,Y ; Get the difference in the lengths
JUMPL T1,LNCR.1 ; If old string is shorter, go handle it
IDIVI T1,5 ; New string shorter, calculate how much to bump old pointer
MOVE P4,P3 ; Get the old byte pointer
HLL P4,BTAB-1(T2) ; Set up the old pointer
ADDI P4,(T1) ; And fix the address
DMOVE T1,[ILDB T1,P4 ; Get the instruction to fetch second character
MOVE P2,Y] ; And the instruction to fetch the offset
JRST LNCR.2 ; Go store common things
LNCR.1: MOVN T1,T1 ; Get the number of chars to bump the pointer
IDIVI T1,5 ; Get the number of words and bytes
HLL P4,BTAB-1(T2) ; Fix the byte pointer
ADDI P4,(T1) ; And bump the address
DMOVE T1,[ILDB T2,P4 ; Get the instruction to use
MOVE P2,X] ; And the instruction to fetch the offset
; Here after P4 is set up with proper byte pointer and T1 with instruction
;to fetch the character into the correct ac
LNCR.2: DMOVEM T1,LNCXCT ; Save the instructions
SETZ P1, ; Clear number of first different character
XCT T2 ; And suffix counters
SETZB T3,T4 ; Clear the cost and number of accepts
MOVEI P3,1 ; . . .
; Now loop for all the characters
LNCR.3: SOJL X,LNCR.X ; Old string run out?
SOJL Y,LNCR.Y ; No, how about the new one?
ILDB T1,OLDPTR ; Get the old character
ILDB T2,NEWPTR ; And the new one
CAIN T1,(T2) ; Same characters?
AOJA T3,LNCR.5 ; Yes, just count it
; Here for different characters
JUMPE T3,LNCR.4 ; If no previous accepts, skip the position cost
PUSH P,T1 ; Save T1
PUSH P,T2 ; And T2
PUSH P,T4 ; And T4
MOVSI T2,(T3) ; Get the number of accepts
MOVX T1,<XWD 1,1> ; Get the funny postition
ADD T2,T1 ; To avoid special case
XCT $CRCPP(CRT) ; Get the position cost
POP P,T4 ; Restore T4
ADD T4,T1 ; Add it in
POP P,T2 ; And T2
POP P,T1 ; And T1
SETZ T3, ; Clear the number of accepts
LNCR.4: AOJ T4, ; Bump the cost for the replace
JUMPG P1,LNCR.5 ; Have a first different character yet?
MOVE P1,P3 ; No, get the number of the character
; Here to compare the suffixes of the strings
LNCR.5: XCT LNCXCT ; Get the other character
CAIE T1,(T2) ; Are these the same?
XCT LNCXC2 ; Get the position
AOJA P3,LNCR.3 ; And go try for the next characters
; Here if the old string ran out first
LNCR.X: ADD T4,Y ; Make the total cost
JUMPLE Y,LNCR.E ; If no new characters left either, go handle it
JUMPG P1,LNCR.7 ; No, go check for other special cases
MOVE T1,Y ; Yes, get the number of additional chars to type
SETZ T2, ; And clear the function pointer
POPJ P, ; And return
; Here if old string is not a prefix of the new one
LNCR.7: TXNN CRT,CR$DIC ; Have insert and delete character ops?
JRST LNCR.E ; No, go return the correct cost
MOVE P3,OLDLDB ; Get the old LDB address
MOVE P4,NEWLDB ; Get the address of the new lines LDB
LOAD. T2,LDBNUM,(P3) ; And get the number of characters
CAME P2,T2 ; Is old line suffix of new?
JRST LNCR.8 ; No, try for insert in middle
MOVEI T1,2 ; Get the number of words we need
MOVX T2,.BTGEN ; And the block type
SKIPL UPCSFL ; Caller want the blocks?
SKIPA T1,[EXP FNCTMP] ; No, use the temp
PUSHJ P,M$GBLK ; Get a block
MOVE P1,T1 ; Remember the address
MOVX T2,<INSVL.($OPICH,CS$OPR)> ; Get the operation
STOR. Y,CSTRPT,+T2 ; Store the repeat count
MOVEM T2,(P1) ; Save the function word
MOVX T2,<INSVL.($OPACH,CS$OPR)> ; Get the accept operation
STOR. P2,CSTRPT,+T2 ; Store the repeat count
MOVEM T2,1(P1) ; Store the word
MOVN Y,Y ; Get the number of inserts we need
HRLI Y,(Y) ; Put in left half
SETZ X, ; Flag we are staring from left margin
MOVX P3,<INSVL.($OPACH,CS$OPR)> ; Get the initial function
LNCR.9: MOVE T1,P3 ; Get the old operation
XCT $CRCIC(CRT) ; And get the insert cost
MOVE T2,P3 ; Get the old word back
PUSHJ P,LINSUB ; And do the cost and repeat count rot
DMOVE P2,T1 ; Save the items
AOBJN Y,LNCR.9 ; Loop for all the inserts
MOVE T1,P2 ; Get the total cost
MOVE T2,P1 ; And the function block
HRLI T2,-2 ; Make it an AOBJx pointer
POPJ P, ; And return
; Here if line is neither suffix or prefix of new line. Check if the
;new line is made by just inserting text into the old line.
LNCR.8: SOJ P1, ; Make P1 the number of initial accepts
MOVE P3,P2 ; Get the number of final accepts
ADD P3,P1 ; Plus intial accepts
CAMGE P3,T2 ; Does this account for the entire old line?
JRST LNCR.6 ; No, must perform cost algorithm to get it correct
MOVE P2,T2 ; Get the length of the old line
SUB P2,P1 ; And make the actual number of final accepts needed
MOVEI T1,3 ; Get the number of words we need
MOVX T2,.BTGEN ; Get the block type
SKIPL UPCSFL ; Caller want the blocks?
SKIPA T1,[EXP FNCTMP] ; No, use the temp
PUSHJ P,M$GBLK ; Get a block
MOVX T2,<INSVL.($OPACH,CS$OPR)> ; Get the accept operation
STOR. P1,CSTRPT,+T2 ; Store the repeat count
MOVEM T2,(T1) ; Store the function word
STOR. P2,CSTRPT,+T2 ; Store the repeat count
MOVEM T2,2(T1) ; Store the function
MOVX T2,<INSVL.($OPICH,CS$OPR)> ; Get the insert function
STOR. Y,CSTRPT,+T2 ; Store the repeat count
MOVEM T2,1(T1) ; Store the function
MOVN Y,Y ; Get the number of inserts
HRLI Y,(Y) ; Into the left half
HRRI Y,(P1) ; Stuff the number of accepts in the right half
MOVEI X,(P1) ; Here also
MOVE P1,T1 ; Remember the address of the block
MOVE P3,(P1) ; Get the insert word
PUSHJ P,LNCR.9 ; Calcualte the cost
HRLI T2,-3 ; Set the number of operations
POPJ P, ; And return
; Here if new line was shorter than the old line.
LNCR.Y: AOJ X, ; Correct back to right value
MOVE T1,X ; Yes, get the number of old chars left
XCT $CRCDE(CRT) ; Get the cost of deleting to the end of line
ADD T4,T1 ; Get the total cost
JUMPG P1,LNCR.B ; No, try other cases
MOVE T1,T4 ; Get the cost
SETZ T2, ; Clear the function block
POPJ P, ; And return
; Here if the new line is not a complete prefix of the old
; Check if it is a suffix of the old line
LNCR.B: TXNN CRT,CR$DIC ; Any delete and insert character functions?
JRST LNCR.E ; No, can't do anything else
MOVE P4,NEWLDB ; Get the new line LDB address
LOAD. T2,LDBNUM,(P4) ; And get the number of characters on the line
CAME T2,P2 ; All of the characters match?
JRST LNCR.C ; No, go check for just deleting some chars
MOVEI T1,2 ; Yes, need a two word block
MOVX T2,.BTGEN ; Get the block type
SKIPL UPCSFL ; Caller want the blocks?
SKIPA T1,[EXP FNCTMP] ; No, use the temp
PUSHJ P,M$GBLK ; And get a block of text
MOVX T2,<INSVL.($OPDCH,CS$OPR)> ; Get the delete character operation
STOR. X,CSTRPT,+T2 ; Store the count
MOVEM T2,(T1) ; And store the function word
MOVX T2,<INSVL.($OPACH,CS$OPR)> ; Get the accept operator
STOR. P2,CSTRPT,+T2 ; Store the repeat count
MOVEM T2,1(T1) ; And store the function word
MOVN X,X ; Make the AOBJx pointer
MOVSI X,(X) ; . . .
SETZ Y, ; Clear the new position
MOVE P1,T1 ; Get the block address
MOVE P3,(T1) ; Get the function word
MOVE T1,1(T1) ; Get the accept function for the first
LNCR.D: XCT $CRCDC(CRT) ; Get the delete character
MOVE T2,P3 ; Get the previous word again
PUSHJ P,LINSUB ; Get the total cost and repeat count
DMOVE P2,T1 ; Get the args
MOVE T1,P3 ; Get the previous function
AOBJN X,LNCR.D ; Loop for all the deletes
MOVE T1,P2 ; Get the cost
MOVE T2,P1 ; Get the function block address
HRLI T2,-2 ; set up the counter
POPJ P, ; And return
; Here if it might be possible to just delete a string somewhere internal
;to the string
LNCR.C: SOS P3,P1 ; Get the number of initial accepts
ADD P3,P2 ; And make the total
CAMGE P3,T2 ; Can we just delete a portion of the old line to get the new one?
JRST LNCR.6 ; No, must only check a small
MOVE P3,T2 ; Get the number of new chars
SUB P3,P1 ; Get the number of chars left after initial insert
MOVEI T1,3 ; Get the number of functions we need
MOVX T2,.BTGEN ; Get the block type
SKIPL UPCSFL ; Caller want the blocks?
SKIPA T1,[EXP FNCTMP] ; No, use the temp
PUSHJ P,M$GBLK ; Get a block
MOVX T2,<INSVL.($OPACH,CS$OPR)> ; Get the function type
STOR. P1,CSTRPT,+T2 ; Store the repeat count
MOVEM T2,(T1) ; And store the word
STOR. P3,CSTRPT,+T2 ; Store the final repeat count
MOVEM T2,2(T1) ; And remember the final accepts
MOVX T2,<INSVL.($OPDCH,CS$OPR)> ; Get the middle function (delete)
STOR. X,CSTRPT,+T2 ; And store the repeat coutn
MOVEM T2,1(T1) ; Store the function word
MOVE P1,T1 ; Get the block address into the correct place
MOVE T1,(T1) ; Get the initial function word
MOVE P3,T1 ; Get the initial cost
MOVN X,X ; Make the AOBJx pointer
MOVSI X,(X) ; . . .
SETZ Y, ; Clear the new position
PUSHJ P, LNCR.D ; And calc the cost
HRLI T2,-3 ; Get the number of functions
POPJ P, ; And return
; Here if a portion of the old line is mapped into a portion of the new line.
LNCR.E: SOJ P1, ; Decrement to be the number of initial accepts
LNCR.6: MOVE P3,OLDLDB ; Get the old LDB address
MOVE P4,NEWLDB ; And the new
MOVE T1,P1 ; Get the number of initial accepts
IDIVI T1,5 ; Make it the word and byte offsets to skip
LOAD. T3,LDBTXT,(P3) ; Get the old text address
HLL T3,BTAB-1(T2) ; And set up the correct byte pointer
ADDI T3,(T1) ; . . .
MOVEM T3,OLDPTR ; Save it
MOVEM T3,OLDSPT ; Also save here to reset OLDPTR after each column
LOAD. T3,LDBTXT,(P4) ; Get the address of the new text
HLL T3,BTAB-1(T2) ; Get the byte pointer set up
ADDI T3,(T1) ; . . .
MOVEM T3,NEWPTR ; Store the pointer
LOAD. X,LDBNUM,(P3) ; Get the number of old chars
LOAD. Y,LDBNUM,(P4) ; And of new ones
SUB X,P1 ; Get the number which we are not accepting
SUB X,P2 ; . . .
SUB Y,P1 ; . . .
SUB Y,P2 ; . . .
; Here to calculate the cost based on insert/delete characters as well
;as accept and replace operations.
; The algorithm used is basically that given by Wagner and Fischer
;in "The String-to-String Correction Problem", JACM, January 1974,
;volume 21, no. 1.
;This implementation of the algorithm also carries along the operation
;which had the minimum cost at each point in the matrix, and the number
;of times any operation is repeated. This allows it to account for
;terminals which allow a single command to delete more than one character,
;require the terminal to be put into insert mode, or to include the
;cost of the positioning that is required after accepting characters.
;
; The algorithm works by creating a matrix of n columns by m rows,
;where n is the number of characters in the old line, and m is
;the number of characters in the new line.
;
;AC usage:
; P1/ Address of matrix entry (row-1,column)
; P2/ Address of matrix entry (row,column)
; P3/ Minimum cost for this entry so far
; P4/ Corresponding matrix entry
; X/ Column index
; Y/ Row index
; CH/ Character new line for current position
; CRT/ CRT block address
;
;Low segment locations:
;
; OLDPTR/ Byte pointer to old line text
; NEWPTR/ Byte pointer to new line text
; OLDLDB/ Address of old LDB
; NEWLDB/ Address of new LDB
;
; First we must set up column 0 and row 0 of the matrix. We do this
; by first calling the terminal dependent routine for get the initial
; entry (0,0). We then loop for the rest of row 0, calling the
; terminal dependent delete cost routine to get each entry based on the
; previous. Finally we loop for the rest of column 0, calling the
; terminal dependent insert cost routine for each entry.
LINC.0: SETZ T2, ; Clear the function block address
MOVE T1,T4 ; And get a copy of the cost
JUMPE X,.POPJ ; Return if no string to worry about
JUMPE Y,.POPJ ; For either one
SKIPGE UPCSFL ; Want full algorithm?
TXNN CRT,CR$DIC ; Have delete and insert character?
POPJ P, ; Either not the same line or no insert/delete char
MOVE T3,TRMSPD ; Get the speed of the terminal
$CHTYI(NOWAIT) ; Check for type ahead
CAMG T1,LNCSPT(T3) ; Is the replacement cost low enough to just use that?
POPJ P, ; Yes, return
$SAVE <BEGACC,ENDACC,NUMCOL,MATRIX> ; Save the beginning and ending accept locations
MOVEM P1,BEGACC ; And save the correct values
MOVEM P2,ENDACC ; . . .
AOJ X, ; Get the number of columns total
MOVEM X,NUMCOL ; Save it
MOVN X,X ; Get the negative
MOVSI X,(X) ; And make an AOBJx pointer
MOVEM X,COLPTR ; Save it
AOS P1,Y ; Make this correct
MOVN Y,Y ; Get the negative
MOVSI Y,(Y) ; And make the row AOBJx pointer
MOVEM Y,ROWPTR ; Save it
IMUL P1,NUMCOL ; Multiply the number of row by the number of columns
; Now check if we should do the complete algorithm. P1 contains the
;number of iterations, and we have an estimate of the time per
;iteration. If the estimated time to perform this algorithm exceeds
;the assembly time constant, we will not bother doing it at all, and
;just return the replacement cost.
NDS. D$LNCT, <^D4*^D1000>/^D24 ; Max time is about 4 seconds for whole screen
MOVE T3,LITRTM ; Get the time per iteration (in milliseconds)
MUL T3,P1 ; Get the total estimate
MOVEM P1,NUMITR ; Save the number of iterations
DIVX T3,^D1000 ; Get the real estimate for this time
CAXL T3,D$LNCT ; Will it take too long?
POPJ P, ; Yes, just return now
MOVX T1,%NSUPT ; Get the current system up time
GETTAB T1, ; Get it
SETZ T1, ; Couldn't?
MULX T1,^D1000 ; Convert to milli-jiffies
DIV T1,JIFSEC ; And to milli-seconds
MOVEM T1,LBGUPT ; Save the time for later
MOVE T1,P1 ; No, get the number of entries we need
MOVX T2,.BTGEN ; Get the block type
PUSHJ P,M$GBLK ; And get the matrix
MOVEM T1,MATRIX ; Save the address
MOVE P1,T1 ; Get the address of the first element
XCT $CRCIN(CRT) ; Get the initial cost
MOVEM T1,(P1) ; Store it and point to row 0, column 1
AOJ P1, ; Point to correct entry
AOBJP X,.+1 ; Bump the pointer
LINC.1: MOVE T1,-1(P1) ; Get the previous entry
XCT $CRCDC(CRT) ; Get the delete cost
MOVE T2,-1(P1) ; Get the previous entry back
PUSHJ P,LINSUB ; Set the correct repeat info
MOVEM T2,(P1) ; Store the entry and point to the next
AOJ P1, ; Point to correct entry
AOBJN X,LINC.1 ; And loop for all the entrys
; Now set up column 0
MOVE P1,MATRIX ; Get the matrix address back
MOVE P2,P1 ; Get a copy
ADD P2,NUMCOL ; Point to the first row column 0
MOVE X,COLPTR ; Reset the column number
AOBJP Y,.+1 ; And bump to row 1, column 0
LINC.2: MOVE T1,(P1) ; Get the previous entry
XCT $CRCIC(CRT) ; Get the insert cost
MOVE T2,(P1) ; Get the previous entry back
PUSHJ P,LINSUB ; Get the repeat count correct
MOVEM T2,(P2) ; Store the entry
ADD P1,NUMCOL ; Move down a row
ADD P2,NUMCOL ; . . .
AOBJN Y,LINC.2 ; Loop for all the insert entries
; Now to loop through the rest of the matrix to find the cheapest
;path.
MOVE Y,ROWPTR ; Get the pointer to the row
AOBJP Y,.+1 ; Point to the row 1
MOVE P1,MATRIX ; Set up P1
; Here to start a new row. Reset the necessary pointers
LINC.3: MOVE X,COLPTR ; Get the column pointer
AOBJP X,.+1 ; Point to column 1
AOS P2,P1 ; Skip column 0 and get a copy
ADD P2,NUMCOL ; And point to the correct row
MOVE T1,OLDSPT ; Get the byte pointer
MOVEM T1,OLDPTR ; And reset the running copy
ILDB CH,NEWPTR ; Get the next character from the new string
; Here to do the next entry in the column
LINC.4: ILDB T1,OLDPTR ; Get an old character
CAIE T1,(CH) ; Is the character the same?
JRST LINC.A ; No, must try replacing it
MOVE T1,-1(P1) ; Yes, get the diagonal entry
STORI. $OPACH,T2,CSTOPR,+T1 ; Store the operation
ZERO. ,CSTCST,+T1 ; Clear the cost
JRST LINC.B ; And go join common code
; Here to try a replace operation
LINC.A: MOVE T1,-1(P1) ; Get the entry up the diagonal
XCT $CRCRP(CRT) ; And get the replace cost
; Here for either a replace or accept operation. Get any extra costs, and
;save as cheapest so far.
LINC.B: MOVE T2,-1(P1) ; Get the previous entry back
PUSHJ P,LINSUB ; Add any positioning cost and update repeat count
DMOVE P3,T1 ; Remember this as cheapest so far
; Now try an insert operation
MOVE T1,(P1) ; Get the entry above the current one
XCT $CRCIC(CRT) ; And get the insert cost
MOVE T2,(P1) ; Get the previous entry back
PUSHJ P,LINSUB ; Do positioning and repeat count stuff
CAMG T1,P3 ; Is the insert cheaper than the replace or accept?
DMOVE P3,T1 ; Yes, remember it instead
; Now to try the delete character operation
MOVE T1,-1(P2) ; Get the previous column entry
XCT $CRCDC(CRT) ; Get the delete cost
MOVE T2,-1(P2) ; Get the previous entry back
PUSHJ P,LINSUB ; Set repeat count and correct cost
CAMG T1,P3 ; Is this better than the cheapest so far?
DMOVE P3,T1 ; Yes, get the entry
MOVEM P4,(P2) ; Save the cheapest one we found
AOJ P1, ; Bump the previous row pointer
AOJ P2, ; And the current pointer
LINC.Z: AOBJN X,LINC.4 ; Loop for all of the columns on this row
AOBJN Y,LINC.3 ; All done with this row, step to the next
; Here after the matrix is built. Now we must build the function
;block by traversing the matrix backwards.
;We will build the function block in the matrix. The method for
;building the function block is to start at the final entry in the matrix
;and work backwards. The entries which are used from that point on are
;found by working backwards using the operations and the repeat counts.
; We come in with P2= the address of the final entry +1
SOJ P2, ; Back up to the final entry
LOAD. P4,CSTCST,(P2) ; Remember the cost to return later
MOVX T1,%NSUPT ; Get the uptime now
GETTAB T1, ; . . .
MOVX T1,<D$LNCE*^D60>/^D1000 ; Use our estimate
MULX T1,^D1000 ; Muliply by a thousand
DIV T1,JIFSEC ; Convert to milliseconds
SUB T1,LBGUPT ; Get the elapsed time
MULX T1,^D1000 ; Times a thousand
DIV T1,NUMITR ; And get the time per thousand iterations
MOVEM T1,LITRTM ; Save it for next call
MOVE T1,P2 ; Get the address of the last entry
PUSHJ P,BLDFNC ; And build the function block
MOVE T1,P4 ; Get the total cost
DMOVE P1,T1 ; Get the return values
MOVE T1,MATRIX ; Get the address of the matrix
PUSHJ P,M$RBLK ; Return the block
DMOVE T1,P1 ; Get back the return values
POPJ P, ; And return
SUBTTL Screen editing -- BLDFNC - Build a function block from a matrix
;+
;.hl2 BLDFNC
; This routine will build a function block from a cost calculation
;matrix.
;.b.lit
;
; Usage:
; MOVE T1,Address of last entry in matrix
; PUSHJ P,BLDFNC
; (return, T1= AOBJx pointer to function block)
;
;.end literal
;-
BLDFNC: $SAVE <P1,P2,P3> ; Save some room
SETZ P3, ; Initialize the count of functions
MOVE P1,T1 ; Get a copy of the address
MOVE P2,T1 ; Here also
BLDF.0: MOVE T1,(P2) ; Get the entry
LOAD. T2,CSTOPR,+T1 ; Get the operation
LOAD. T3,CSTRPT,+T1 ; And the repeat count
CAXN T2,$OPACH ; Is it an accept operation?
JUMPE T3,BLDF.D ; Yes, if the repeat count is zero we are
; done (back at row 0, column 0)
IFN FTDEBUG,<
SKIPN T3 ; Have a repeat count?
STOPCD ZRC,<Zero function repeat count found in BLDFNC>
CAML P1,MATRIX ; Make sure this is ok
CAMG P2,MATRIX ; Make sure we haven't gone back too far
STOPCD BFL,<BLDFNC lost start of cost matrix>
> ; End of IFN FTDEBUG
MOVEM T1,(P1) ; Store the operation
SOJ P1, ; Back up one entry
AOJ P3, ; Count that we used it
XCT BLFTBL(T2) ; Move to the next entry
JRST BLDF.0 ; And go process it
TABDEF BLF,$OP
TABENT ACH,<PUSHJ P,BLFACH> ; Accept character, move up diagonal
TABENT RCH,<PUSHJ P,BLFACH> ; Replace character, also up diagonal
TABENT ICH,<PUSHJ P,BLFICH> ; Insert character, move up n rows
TABENT DCH,<SUB P2,T3> ; Delete character, move back n columns
TABEND
; Here for accept or replace operations. We must move up the diagonal
BLFACH: SUB P2,T3 ; Move over the correct number of columns
; Join in here for insert character operations. This must just move up
;the correct number of rows
BLFICH: IMUL T3,NUMCOL ; Calculate the amount for the upward movement
SUB P2,T3 ; And move up the correct amount
POPJ P, ; Return
; Here after the functions have been collected in the matrix. P3
;contains the number of entries, P1 the address of the first.
BLDF.D: MOVE T1,P3 ; Get the number of words we need
CAIN T1,1 ; Only need one word?
JRST [SETZB T2,T1 ; Since can only be replace or accept
POPJ P,] ; Just return the cost
SKIPE BEGACC ; Any starting accepts to add?
AOS T1,P3 ; Yes, count them
SKIPE ENDACC ; Any ending accepts to add?
AOS T1,P3 ; Yes, count it
MOVX T2,.BTGEN ; Get the block type
PUSHJ P,M$GBLK ; Get the core
MOVE T2,T1 ; Save a copy
MOVN T3,P3 ; Get the number of entries
HRLI T2,(T3) ; And make the AOBJx pointer
SKIPN T3,BEGACC ; Any starting accepts?
JRST BLDF.F ; No, skip this
LSH T3,<ALIGN.(CS$RPT)> ; Yes, put into correct place for repeat count
TXO T3,<INSVL.($OPACH,CS$OPR)> ; Flag it is an accept
MOVEM T3,(T1) ; Store the first accepts and point to the next
AOJ T1, ; . . .
SOJ P3, ; And one less to BLT
BLDF.F: MOVE T3,T1 ; Get a copy of the address
HRLI T1,1(P1) ; Get where we are coming from
ADD T3,P3 ; And make the final address +1
SKIPE ENDACC ; Any ending accepts?
SOJ T3, ; Yes, BLT one less
BLT T1,-1(T3) ; Move the functions
SKIPN T1,ENDACC ; Any ending line accepts?
POPJ P, ; No, all done
LSH T1,<ALIGN.(CS$RPT)> ; Yes, put into correct place for repeat count
TXO T1,<INSVL.($OPACH,CS$OPR)> ; Flag it is an accept
MOVEM T1,(T3) ; Store the first accepts
POPJ P, ; And return it
SUBTTL Screen editing -- LNCSPT -- Table of minimum costs
; This table is used to determine whether the insert/delete character
;cost algorithm should be used. The table is indexed by the terminal
;transmit speed. Anytime the replacement cost will take less than
;D$ICSP milli seconds, the replacement will be done instead of the
;insert/delete algoritm.
NDS. D$ICSP, ^D100 ; Number of milliseconds to update a line
DEFINE ENT(SPEED,CPS,IDX),<
TABENT SPEED,<<CPS*D$ICSP>/^D1000>
>
RADIX 10 ; Go to base 10 for this table
TABDEF LNCSPT,.TS,0
TSPEED ; Expand the macro
TABEND
RADIX 8 ; Back to octal
SUBTTL Screen updating routines -- LINCST -- LINSUB - Fix up a matrix entry
;+
;.HL2 LINSUB
; This routine is called to fix up a cost matrix entry returned from
;the terminal dependent routines. It will add the previous cost, any
;cost due to a required positioning operation, and set the repeat
;count for the entry correctly.
;.b.lit
;
; Usage:
; MOVE T1,New entry from terminal dependent routine
; MOVE T2,Previous entry
; PUSHJ P,LINSUB
; (Return, T1= cost in characters, T2=updated new entry)
;
;.end literal
;-
LINSUB: LOAD. T3,CSTOPR,+T2 ; Get the previous operation
CFME. T4,CSTOPR,+T1,T3 ; Was it the same as the new one?
JRST LINS.0 ; No, check for positioning cost
LOAD. T3,CSTRPT,+T2 ; Get the repeat count
AOSA T3 ; Plus one
LINS.1: MOVEI T3,1 ; Here if starting a new operation, this is first one
STOR. T3,CSTRPT,+T1 ; Store the new repeat count
LOAD. T3,CSTCST,+T2 ; Get the old cost
MOVE T2,T1 ; Copy the new entry
LOAD. T1,CSTCST,+T2 ; Get the new cost
ADD T1,T3 ; Make the total cost
CAXL T1,<1_<WID(CS$CST)>-1> ; Is it the maximum possible cost?
MOVX T1,.INFIN ; Yes, get infinity
STOR. T1,CSTCST,+T2 ; Store the total cost
POPJ P, ; And return
; Here when we are starting a new operation
LINS.0: CAXE T3,$OPACH ; Was the previous operation an accept?
JRST LINS.1 ; No, no position cost needed
PUSH P,T2 ; Save the old entry
PUSH P,T1 ; And the new
MOVX T1,<XWD 1,1> ; Set up to calculate the position cost
LOADS. T2,CSTRPT,+T2 ; Get the number of accepts we are ending
ADD T2,T1 ; Make the correct position
XCT $CRCPP(CRT) ; Get the positioning cost
POP P,T2 ; Get the new entry back
LOAD. T3,CSTCST,+T2 ; Get the cost from that
ADD T1,T3 ; Get the total
LOAD. T3,CSTCST,(P) ; Get the old cost
ADD T1,T3 ; Add that also
CAXL T1,<1_<WID(CS$CST)>-1> ; Is it the maximum possible cost?
MOVX T1,.INFIN ; Yes, get infinity
STOR. T1,CSTCST,+T2 ; Store the total cost
POP P,(P) ; Fix the stack
STORI. 1,T3,CSTRPT,+T2 ; Store the new repeat count
POPJ P, ; nd return
SUBTTL Screen editing -- Debugging output routines -- D$LINS
;+
;.HL1 Debugging output routines
; The following routines are used when debugging to output the
;screen update information for use in debugging the cost calculation
;routines.
;.hl2 D$LINS
; This routine will output the lines which are being changed.
;.lit
;
;Usage:
; X/ Pointer to old LDB's
; Y/ Pointer to new LDB's
; PUSHJ P,D$LINS
; (return, all ac's intact)
;
;.end lit
;-
IFN FTDEBUG,<
D$LINS: SKIPN UPDDEB ; Want debugging output?
POPJ P, ; No, skip this
$SAVE <T1,T2,T3,T4,X,Y,CH> ; Save some ac's
DLIN.1: LOAD. T4,LDBLIN,(X) ; Get the old line number
XMOVEI T1,[$STRING(<^X/LOGC.0/old^D/T4/:^I/9/ ^N>)] ; Get the string to type
PUSHJ P,T$TYPE ; Output the data
LOAD. T4,LDBTXT,(X) ; Get the address of the text
LOAD. T3,LDBNUM,(X) ; And get the character count
PUSHJ P,DLIN.S ; Type the text and a CRLF
LOAD. T4,LDBLIN,(Y) ; Get the new line number
XMOVEI T1,[$STRING(<^X/LOGC.0/new^D/T4/:^I/9/ ^N>)] ; Get what to type
PUSHJ P,T$TYPE ; Send the output
LOAD. T4,LDBTXT,(Y) ; Get the address of the text
LOAD. T3,LDBNUM,(Y) ; Get the number of chars to output
PUSHJ P,DLIN.S ; Output the text
ADDX X,$LDLEN ; Advance the pointers
ADDX Y,$LDLEN-1 ; . . .
AOBJN Y,DLIN.1 ; And loop for all the lines
XMOVEI T1,[$STRING(<^X/LOGC.0/------------------>)] ; Delimit the lines
PUSHJ P,T$TYPE ; Type it out
POPJ P, ; And return
; Subroutine to output the text of the lines
DLIN.S: JUMPE T3,D$CRLF ; Any chars?
TXO T4,<POINT 7,> ; Yes, set up the byte pointer
DLIN.U: ILDB CH,T4 ; Get a character
PUSHJ P,LOGC.0 ; Output it
SOJG T3,DLIN.U ; Loop for all the characters
D$CRLF: MOVX CH,.CHCRT ; Get a CR
PUSHJ P,LOGC.0 ; Output the character
MOVX CH,.CHLFD ; Get the LF
PJRST LOGC.0 ; And output it
> ; End of IFN FTDEBUG
SUBTTL Screen editing -- Debugging output routines -- D$OMTX
;+
;.HL2 D$OMTX
; This routine will output a cost matrix.
;-
IFN FTDEBUG,<
D$OMTX: SKIPN UPDDEB ; Want debugging output?
POPJ P, ; No, all done
$SAVE <T1,T2,T3,T4,P1,P2,P3,P4,CH,X,Y> ; Save some ac's
MOVE P1,MATRIX ; Get the pointer to the matrix
MOVN X,NUMROW ; Get the number of rows
MOVSI X,(X) ; Set up the row counter
; Loop for each row
OMTX.1: MOVN Y,NUMCOL ; Get the number of columns it has
MOVSI Y,(Y) ; Set up as a counter
SETZ P2, ; Clear the count per line
OMTX.2: SOJG P2,OMTX.3 ; Room for more?
PUSHJ P,D$CRLF ; No, do a CRLF
MOVE P2,UPDDEB ; Get the number of items/line
OMTX.3: MOVEI T2,(X) ; Get the current row number
MOVEI T3,(Y) ; And the current column
LOAD. T4,CSTOPR,(P1) ; Get the operation
XMOVEI T4,D$OPRT(T4) ; Get the pointer to the text
LOAD. P3,CSTRPT,(P1) ; Get the repeat count
LOAD. P4,CSTDEP,(P1) ; And the dependent info
LOAD. CH,CSTCST,(P1) ; And the cost
XMOVEI T1,[$STRING(<^X/LOGC.0/(^D/T2/,^D/T3/):^T/(T4)/-^D/P3/,D=^O/P4/,C=^D/CH/ ^N>)]
PUSHJ P,T$TYPE ; Type the row and column
AOJ P1, ; Increment the pointer
AOBJN Y,OMTX.2 ; And loop for everything in this row
PUSHJ P,D$CRLF ; Do an extra CRLF
AOBJN X,OMTX.1 ; And loop for all rows
XMOVEI T1,[$STRING(<^X/LOGC.0/=========================>)]
PJRST T$TYPE ; Type the separtion and return
TABDEF D$OPRT,$OP,<ASCIZ |??|>
TABENT DCH,<ASCII |DL|>
TABENT ICH,<ASCII |IN|>
TABENT RCH,<ASCII |RP|>
TABENT ACH,<ASCII |AC|>
TABENT SUP,<ASCII |SU|>
TABENT SDN,<ASCII |SD|>
TABENT NOP,<ASCII |NO|>
TABEND
> ; End of IFN FTDEBUG
SUBTTL Screen editing -- Update a line
;+
;.HL1 UPDLIN
;This routine will use a function block to update a line. It will
;call the terminal dependent routines to delete to the end of a line
;and to insert/delete characters and postion the cursor.
;.literal
;
; Usage:
; MOVEI T1,Function.block.address
; MOVEI T2,Old.LDB.address
; MOVEI T3,New.LDB.address
; PUSHJ P,UPDLIN
; (Return)
;
;.end literal
;-
UPDLIN: $SAVE <P1,P2,P3,P4> ; Save a few registers
PUSH P,T1 ; Save the block address
MOVE P1,T1 ; Get the block address again
SETZ X, ; Clear the X offset
LOAD. P2,LDBTXT,(T2) ; Get the address of the text block
HRLI P2,(POINT 7) ; Build the byte pointer
LOAD. P3,LDBTXT,(T3) ; Get the address of the text block
HRLI P3,(POINT 7) ; Build the byte pointer
LOAD. P4,LDBNUM,(T2) ; Get the number of characters on this line
LOAD. T2,LDBNUM,(T3) ; And the other
JUMPE T1,UPDL.1 ; If no function block dumb terminal
; Here is the main function processing loop
UPDL.0: LOAD. T1,CSTRPT,(P1) ; Get the repeat count
LOAD. T2,CSTOPR,(P1) ; Get the operation
PUSHJ P,@UPLTBL(T2) ; Dispatch to the correct routine
AOBJN P1,UPDL.0 ; Loop for all functions
POP P,T1 ; Restore the block address
PJRST M$RBLK ; Return the block
; Here if there is no function block to use. Therefore we must do
; everthing the hard way. Just check character by character to see
; if we should accept or replace the character.
; Enter with acs as follows:
; P2/ byte pointer to old line
; P3/ byte pointer to new line
; P4/ number of characters on old line
; T2/ number of characters on new line
UPDL.1: POP P,(P) ; Remove the zero
MOVE T1,T3 ; Get the new LDB address
PJUMPE P4,SC$WLN ; If there were no characters on the old line, just write out the new one
MOVE T3,T2 ; Assume new line is shorter
CAMGE P4,T3 ; Is it?
MOVE T3,P4 ; No, use length of old line
SUBM T2,P4 ; Make the new length - old length
SETZB X,T4 ; Starting at the beginning of the line
; First loop through the number of characters that are on both lines
UPDL.2: MOVE T2,CH ; Save a copy of the character
SOJL T3,UPDL.4 ; Have any characters on shortest line?
ILDB CH,P3 ; Yes, get the new character
ILDB T1,P2 ; And the old one
CAIN CH,(T1) ; Same character?
AOJA T4,UPDL.2 ; Yes, loop for next character
JUMPE T4,UPDL.3 ; Is this the first different character after
; a run of like ones?
CAIE T4,1 ; Only one character?
JRST UPDL.7 ; No, go handle it
EXCH T2,CH ; Switch the two characters
XCT $CRTCH(CRT) ; Type the character
EXCH T2,CH ; Switch them back
SETZ T4, ; Clear the number to increment X
UPDL.7: ADD X,T4 ; Increment the position
SETZ T4, ; And clear the count
UPDL.3: XCT $CRTCH(CRT) ; No, type the character
JRST UPDL.2 ; And go for the next
; Here after beginning of line is done. Now we either have to do a delete
; to end of line or finish writing the text
UPDL.4: JUMPL P4,UPDL.6 ; If old line was longer, go do a delete to end of line
JRST .+2 ; Skip in the first time
UPDL.5: MOVX T2," " ; After first character, forward spacing is done with a space
SOJL P4,.POPJ ; Loop for all the characters
ILDB CH,P3 ; Get a character
CAIN CH," " ; Is it a space?
AOJA T4,UPDL.5 ; Yes, just increment the position
JUMPE T4,UPDL.9 ; Any spaces first?
CAIE T4,1 ; Only one?
JRST UPDL.A ; No, skip this
EXCH T2,CH ; Save CH
PUSHJ P,SC$CHR ; Type the character
EXCH T2,CH ; Restore the character
SETZ T4, ; Clear the offset
UPDL.A: ADD X,T4 ; Increment the position
SETZ T4, ; And clear the count
UPDL.9: PUSHJ P,SC$CHR ; And type the character
JRST UPDL.5 ; Loop for all the characters
; Here to do the delete to end of line
UPDL.6: ADD X,T4 ; Correct the position
PUSHJ P,SC$POS ; Position the cursor
MOVM T1,P4 ; Get the number of characters to delete
XCT $CRDEL(CRT) ; Delete to end of line
POPJ P, ; Return
; The following is the dispatch table for the operations that are
; being preformed on the line
TABDEF UPL,$OP
TABENT SUP,<EXP UPLSUP> ; Scroll up (Section only item)
TABENT SDN,<EXP UPLSDN> ; Scroll down (Section only item)
TABENT ACH,<EXP UPLACH> ; Accept the character
TABENT DCH,<EXP UPLDCH> ; Delete the character
TABENT ICH,<EXP UPLICH> ; Insert the character
TABENT RCH,<EXP UPLRCH> ; Replace the character
TABENT NOP,<EXP UPLNOP> ; No-op operation
TABEND
SUBTTL Screen editing -- Update a line -- Scroll up
;+
;.HL2 UPLSUP
;This routine is not expected to be executed. If it does then an internal
;error has occured.
;-
UPLSUP: STOPCD SUL,<Attempt to scroll up a line>
SUBTTL Screen editing -- Update a line -- Scroll down
;+
;.HL2 UPLSDN
;This routine is not expected to be executed. If it does then an internal
;error has occured.
;-
UPLSDN: STOPCD SDL,<Attempt to scroll down a line>
SUBTTL Screen editing -- Update a line -- Accept
;+
;.HL2 UPLACH
; This routine will accept the character given. It will update the byte
;pointers that are being kept and update the line position.
;.literal
;
; Usage:
; LOAD. T1,CSTRPT,(P1)
; PUSHJ P,UPLACH
; (Return)
;
;.end literal
;-
UPLACH: ADD X,T1 ; Update the X position
IDIVI T1,5 ; Determine the number of words
ADD P2,T1 ; Update the address
ADD P3,T1 ; . . .
UPLA.0: SOJL T2,.POPJ ; Return if no more bytes
IBP P2 ; Increment the byte pointers
IBP P3 ; . . .
JRST UPLA.0 ; Loop
SUBTTL Screen editing -- Update a line -- Delete
;+
;.HL2 UPLDCH
;This routine will delete characters from the screen. It will update the
;number of characters that are on the line and then position the cursor
;and delete the characters by calling a terminal dependent routine.
;.literal
;
; Usage:
; LOAD. T1,CSTRPT,(P1)
; PUSHJ P,UPLDCH
; (Return)
;
;.end literal
;-
UPLDCH: SUB P4,T1 ; Decrement the number of characters on the line
PUSHJ P,UPLBYT ; Update the byte pointer
PUSHJ P,SC$POS ; Update the cursor postion
TXC P1,LH.ALF ; Is this the last function ?
TXCN P1,LH.ALF ; . . .
JRST UPLD.0 ; Yes, Then just do a DEL
XCT $CRDCH(CRT) ; Cause the characters to go away
POPJ P, ; Return to the caller
UPLD.0: XCT $CRDEL(CRT) ; Delete to the end of the line
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Update a line -- Replace
;+
;.HL2 UPLRCH
;This routine will replace characters that are on the screen. It will
;first update the byte pointer(Old LDB) and then position the cursor
;to the correct place. After that is done it will read characters
;from the new LDB and print them on the terminal.
;.literal
;
; Usage:
; LOAD. T1,CSTRPT,(P1) ; Get the repeat count
; PUSHJ P,UPLRCH
; (Return)
;
;.end literal
;-
UPLRCH: PUSHJ P,UPLBYT ; Update the byte pointer
PUSHJ P,SC$POS ; Update the position
UPLR.0: ILDB CH,P3 ; Get the first character to type
XCT $CRTCH(CRT) ; Type a character
SOJG T1,UPLR.0 ; Loop for all the characters
POPJ P, ; Return if done
SUBTTL Screen editing -- Update a line -- Insert
;+
;.HL2 UPLICH
;This routine will cause characters to be inserted on the line. It will
;update the number of characters that are on the line first. If the number
;of characters exceeds the number allowed on a line it will search the function
;block for a delete function. It will cause the delete to happen and then
;see if there is room for the characters on the line. After that is
;done the characters will be inserted on the line.
;-
UPLICH: $SAVE <P1> ; Save P1
ADD P4,T1 ; Update the number of characters on the line
CAMLE P4,SCRWID ; Is there room on the line ?
PUSHJ P,UPLISB ; No, Call the subroutine to handle this case
TXC P1,LH.ALF ; Is this the last function on the line ?
TXCN P1,LH.ALF ; . . .
JRST UPLI.1 ; Yes, Just type the characters
MOVE P1,T1 ; Get the count
UPLI.0: ILDB CH,P3 ; Get the character to insert
PUSHJ P,SC$POS ; Position to correct place
XCT $CRICH(CRT) ; Cause the character to be inserted
SOJG P1,UPLI.0 ; Loop back
POPJ P, ; Return to the caller
UPLI.1: ILDB CH,P3 ; Get a character
PUSHJ P,SC$CHR ; Type the character on the terminal
SOJG T1,UPLI.1 ; Loop for all character
POPJ P, ; Return to the caller
; Here to handle the case of not enough space on the line to insert the
; characters. First try and delete the characters so that the insert will
; not cause characters to fall off of the end of the line. (Into the
; bit bucket!!)
UPLISB: $SAVE <X,P1,P2,T1> ; Save a few registers
UPLI.2: AOBJP P1,.POPJ ; If no more give up (What else STOPCD ?)
LOAD. T2,CSTOPR,(P1) ; Get the operation
LOAD. T1,CSTRPT,(P1) ; Get the repeat count
CAXN T2,$OPDCH ; Is this a delete ?
JRST UPLI.3 ; Yes, Go process it
CAXE T2,$OPICH ; Is this an insert ?
CAXN T2,$OPNOP ; Or a converted function ?
JRST UPLI.2 ; Yes, ignore these functions
ADD X,T1 ; Update the X position
JRST UPLI.2 ; Loop back
UPLI.3: MOVX T2,$OPNOP ; Convert the operation to a no-op
STOR. T2,CSTOPR,(P1) ; . . .
PUSHJ P,UPLDCH ; Cause the delete to happen
CAMG P4,SCRWID ; Insert fit yet ?
POPJ P, ; Yes, Return and do it
JRST UPLI.2 ; No, Try again
SUBTTL Screen editing -- Update a line -- No-op
;+
;.HL2 UPLNOP
;This routine will just advance the byte pointer to the next position
;since it could not be done in the insert code.
;.literal
;
; Usage:
; LOAD. T1,CSTRPT,(P1) ; Get the repeat count
; PUSHJ P,UPLNOP
; (Return)
;
;.end literal
;-
UPLNOP: SKIPA ; Skip enter into the routine
FALL UPLBYT ; Make sure the routine is next
SUBTTL Screen editing -- Update a line -- Subroutines -- UPLBYT
;+
;.HL3 UPLBYT
;This routine will advance the old byte pointer.
;.literal
;
; Usage:
; LOAD. T1,CSTRPT,(P1)
; PUSHJ P,UPLBYT
; (Return)
;
;.end literal
;This routine will not smash T1.
;-
UPLBYT: $SAVE <T1> ; Save T1
IDIVI T1,5 ; Compute the number of words
ADD P2,T1 ; Update the address field
UPLB.0: SOJL T2,.POPJ ; Return if done
IBP P2 ; Increment the byte pointer
JRST UPLB.0 ; Loop back if not done yet
SUBTTL Screen editing -- SC$WRT - Write a character to the screen buffer
;+
;.hl1 SC$WRT
; This routine will write a character into the screen buffer.
;It will do any conversion into printable characters that is needed.
;.b.literal
; Usage:
; MOVE T4,Byte.pointer
; MOVEI CH,Character
; MOVE X,X position
; PUSHJ P,SC$WRT
; (return, T4 and X updated)
;
;.end literal
;-
SC$WRT: CAXN CH,.CHESC ; Is this an escapse?
MOVX CH,"$" ; Yes, use a dollar sign
CAXN CH,.CHDEL ; Delete?
SETO CH, ; Yes, make it one less than a null
CAXL CH," " ; Special processing ?
JRST SWRT.3 ; No - Just continue
CAXE CH,.CHTAB ; Is this a tab ?
JRST SWRT.2 ; No - Just a control character
; Here because TABs need special processing. We must determine
; how many of the spaces that must be output
MOVX CH," " ; Get the character to output
SWRT.1: PUSHJ P,SWRT.3 ; Output the character and update X
TXNE X,7 ; . . .
JRST SWRT.1 ; Not at the tab stop - loop
POPJ P, ; All done, return
; Here if the character to be output is a control character
; save the character output a "^" and then the control character +40
SWRT.2: PUSH P,CH ; Save the character
MOVX CH,"^" ; Get the character to output
PUSHJ P,SWRT.3 ; Output the character
POP P,CH ; Restore the character
ADDX CH,"A"-.CHCNA ; Convert to upper case equivalent
SWRT.3: IDPB CH,T4 ; Store the character
AOJA X,.POPJ ; Return with X updated
SUBTTL Screen editing -- Subroutines -- SC$WLN - Write a line
;+
;.hl1 SC$WLN
; This routine will output a line to the screen. It should be used when
;it is known that the line on the screen is already blank.
;.b.literal
;
; Usage:
; MOVE T1,LDB.address
; PUSHJ P,SC$WLN
; (return, line written)
;
;.end lit
;-
SC$WLN: $SAVE <P1,P2,P3,P4> ; Save some ac's
$SAVE <X,Y> ; Save X and Y also
$SAVE <CH> ; And CH
MOVE P1,T1 ; Get the argument
LOAD. Y,LDBLIN,(P1) ; Get the line number
SETZ X, ; Clear the column
LOAD. P2,LDBTXT,(P1) ; Get the text address
HRLI P2,(POINT 7,) ; Set up the byte pointer
LOAD. P3,LDBNUM,(P1) ; And get the number of chars
MOVX P4,.MINFI ; Get negative infinty
SWLN.1: CAML X,P3 ; Done yet?
POPJ P, ; Yes, return
ILDB CH,P2 ; No, get a character
CAIN CH," " ; Is it a printing character?
AOJA P4,[AOJA X,SWLN.1] ; No, count it and continue
JUMPLE P4,SWLN.2 ; Any spaces first?
HRL T1,CURPOS+$OFSX ; Get the current X position
HRR T1,CURPOS+$OFSY ; And the line number
HRLI T2,(X) ; Put in correct half
HRRI T2,(Y) ; . . .
XCT $CRCPP(CRT) ; Get the position cost
CAMG T1,P4 ; Cheaper to output the spaces?
JRST SWLN.2 ; No, go do the position
SUB X,P4 ; Put in correct place
PUSH P,CH ; Save the character
MOVEI CH," " ; Get a space
PUSHJ P,SC$CHR ; Output it
SOJG P4,.-1 ; And loop for all that are necessary
POP P,CH ; Restore CH
SWLN.2: SETZ P4, ; Clear the count of spaces
PUSHJ P,SC$CHR ; Output the character
JRST SWLN.1 ; And go for the next
SUBTTL Screen editing -- Subroutines -- DISPLY - Deterine what to display
;+
;.HL1 DISPLY
;This routine will determine what should be displayed on the users screen.
;It will attempt to center the lines around the current PT for that
;text buffer.
;.literal
;
; Usage:
; MOVE T2,QRG address
; MOVE T1,Character address to center around
; PUSHJ P,DISPLY
; (Return)
;
; Or
;
; MOVE T2,QRG block address
; MOVE T1,Character address of start of line
; MOVE T3,Line number to fix display with
; PUSHJ P,FDSPLY
; (Return)
;
;
; Returns:
; T1 - Character address of the first line
; T2 - Character address of the end of the last line
;
;.end literal
;-
DS$FDS==1B1 ; Flag in P2 that this is an FDSPLY call
DS$BLN==1B2 ; Flag in P2 to leave last line blank
DS$CMD==1B3 ; Flag that this is the command buffer
DS$FIX==1B4 ; Flag that the start of this is fixed
; This will cause blank lines to appear on the
; bottom of the section at times
FDSPLY: $SAVE <P1,P2,P3,P4> ; Save the Pn registers
$SAVE <A1,A2> ; Save the argument processing registers
DMOVE P1,T1 ; Copy the arguments
TXO P2,DS$FDS ; Flag this is an FDSPLY call
IFN FTXADR,TXO P2,IFIW ; Make this a local address
LOAD. P3,QRGNLN,(P2) ; Get the number of lines
LOAD. T1,QRGOFS,(P2) ; Get the offset
SUB T3,T1 ; Remove the offset (Make it a relative line)
MOVE P4,T3 ; Copy for later
PJRST DISP.0 ; Enter the routine
DISPLY: $SAVE (<P1,P2,P3,P4>) ; Save the Px ac's
$SAVE (<A1,A2>) ; Save the arg ac's
DMOVE P1,T1 ; Get the args
IFN FTXADR,TXO P2,IFIW ; Make this a local address
TXZ P2,DS$FDS ; Flag DISPLY entry point
LOAD. P3,QRGNLN,(P2) ; Get the number of lines in the buffer
MOVE P4,P3 ; Get a copy
ASH P4,-1 ; Get half the size
; Enter here from the alternate entry point
DISP.0: JUMPE P3,.RET0 ; No cost if no lines
MOVX T1,QR$FIX ; Check if we have a specific position
TDNN T1,$QRFLG(P2) ; . . .
JRST DISP.K ; Go join common routine
TXO P2,DS$FIX ; Yes, flag it
LOAD. T2,QRGVAL,(P2) ; Get the fixed starting point
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the address of the buffer
LOAD. P4,QRGFLN,(P2) ; Get the line to fix this on
CFMLE. ,BLKFST,(T1),T2 ; If not after last mod
JRST DISP.Q ; Then use value as it is
SUB T2,.BKOED(T1) ; After last mod, fix up to new position
ADD T2,.BKEND(T1) ; . . .
DISP.Q: CFME. ,BLKEND,(T1),T2 ; Is the fixed position =Z?
JRST DISP.R ; No, all is fine
SOSGE T3,T2 ; Get the position
POPJ P, ; Nothing there, punt out now
CFMGE. ,BLKEND,(T1),T2 ; Within bounds of buffer?
JRST [TXZ P2,DS$FIX ; No, flag we aren't fixing this in place
JRST DISP.K] ; And continue on
SOJL T3,DISP.R ; If only one character, no problem with CRLF
IDIVI T3,^D5 ; Otherwise, convert to a byte pointer
TDO T3,BTAB(T4) ; . . .
ADD T3,T1 ; Plus the buffer address
ADDX T3,.BKTLN ; And the offset
LDB CH,T3 ; Get the next to last character
CAXE CH,.CHCRT ; CR?
JRST DISP.R ; No, can't be CRLF
ILDB CH,T3 ; Get the last character
CAXN CH,.CHLFD ; LF of the CRLF?
SOJ T2, ; Yes, back up one more character
DISP.R: MOVE P1,T2 ; Get the valid value
DISP.K: HRRZ T1,P2 ; Get the QRG address
CAIN T1,CMDBUF ; Is this the command buffer?
TXO P2,DS$CMD ; Yes, flag it
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the text buffer address
LOAD. T2,BLKEND,(T1) ; Get the end address
JUMPE T2,.RET0 ; If no text in buffer, return a zero
CAMLE P1,T2 ; Is the position to use valid?
JRST [LOAD. P1,BLKPT,(T1) ; No, get one that is
TXZ P2,DS$FIX ; Flag this is not a fixed update
JRST .+1] ; And continue
LOAD T3,$QRFLG(P2),QR$DLC ; Get "Display last CRLF" flag
STOR T3,P2,DS$BLN ; Store as blank line flag
CFME. ,BLKPT,(T1),T2 ; Current pointer at end of buffer?
TXZ P2,DS$BLN ; No, forget the flag
SOJ T2, ; Point at the last character
IDIVI T2,5 ; Get the position
HLL T2,BTAB(T3) ; Get the byte pointer
ADDI T2,.BKTLN(T1) ; . . .
LDB CH,T2 ; Get the last character
PUSHJ P,CKTRM ; Check if terminator
TXZ P2,DS$BLN ; Clear the flag
; Build pointers to the stack which we will use for storing the line
;bounds until we have found the top and bottom lines.
; Macro to allocate pointers to the sections on the stack
DEFINE XXX(THING),<
LSTOF. ;; Turn the listing off
IRP <THING>,<
MOVEM T4,THING'PTR ;; Save for pointing to the THING's
HRRM T4,THING'BLT ;; Store for moving the THING's down one
AOJ T4, ;; Make the other half of the pointer
HRLM T4,THING'BLT ;; Store it
ADDI T4,-1(P3) ;; Point to the next block
HRRM T4,THING'POP ;; Store the pointer
AOJ T4, ;; Point back to the next block
>;; End of IRP THING
LSTON. ;; Turn the listing on again
> ; end of DEFINE XXX
MOVX T4,<Z (P3)> ; Get the index reg
HRRI T4,1(P) ; And the address on the stack
XXX <BEG,END,FLG,NUM> ; Generate the pointers
MOVE T4,P3 ; Get the total number of lines
TXO T4,(1B0) ; Turn on the sign bit
HRLM T4,BEGPOP ; And store for the POP loop
HRLM T4,ENDPOP ; Here also
HRLM T4,FLGPOP ; . . .
HRLM T4,NUMPOP ; . . .
MOVEI T4,1(P3) ; Get the number again
IMULI T4,4 ; Mult by the number of items to store
; on the stack
IFN FTKL,<
ADJSP P,(T4) ; Make the space on the stack
> ; End of IFN FTKL
IFE FTKL,<
HRLI T4,(T4) ; Make the XWD to add
ADD P,T4 ; And adjust the stack pointer
> ; End of IFE FTKL
HRR T1,BEGPTR ; Get the address of the first
SETZM (T1) ; Clear it
HRLI T1,1(T1) ; Build a BLT pointer
MOVSS T1 ; Move it to the correct halfs
BLT T1,-1(P) ; Clear the stack
SUBM P4,P3 ; Make the number of lines on the bottom
HRLI P3,(P3) ; And make the AOBJx pointer
HRRI P3,(P4) ; And get the center line offset
TXNN P2,DS$BLN ; Want a blank line on the bottom?
JRST DISP.J ; No, Skip this
SOJ P4, ; Yes, one less line on top
TXC P3,LH.ALF ; Make sure this isn't just one line
TXCE P3,LH.ALF ; If so, ignore FDSPLY call bit
TXNN P2,DS$FDS ; FDISPLY call?
JUMPL P4,[SETOM @BEGPTR ; Clear the pointer
SETOM @ENDPTR ; . . .
SETZM @FLGPTR ; . . .
SETZM @NUMPTR ; . . .
JRST DISP.9] ; All done
SUBI P3,1 ; Start the loop one higher
JUMPG P4,DISP.J ; If any lines left on top, continue on
TXC P3,LH.ALF ; Check if only one line on bottom
TXCN P3,LH.ALF ; . . .
JRST DISP.J ; Yes, we must have it right already
AOJ P4, ; No, bump it up one
AOBJN P3,DISP.J ; And reset P3
STOPCD FNL,<Funny number of lines in section>
; First we must find the line which contains PT. To do this we find the
;beginning of the line in the buffer which contains the pointer, then
;we start getting screen sized lines until we find the line on the
;screen with the pointer. Any lines before this we remember in the block
;of BEG's and END's, moving them up toward the top of the screen while
;doing so.
DISP.J: TXNE P2,DS$FDS ; If FDSPLY call, we have the address to start with
JRST DISP.G ; Got it, go set things up
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
MOVE T2,P1 ; Get the pointer
CFME. ,BLKEND,(T1),P1 ; At the end of the buffer?
JRST DISP.I ; No, go handle it
SUBI T2,2 ; Yes, back up one more
IDIVX T2,5 ; And make the byte pointer to the last
HLL T2,BTAB(T3) ; character of the buffer
ADDI T2,.BKTLN(T1) ; And point to the correct word
LDB CH,T2 ; Get the character
CAXE CH,.CHCRT ; Was this a carriage return?
JRST DISP.H ; No, skip this
ILDB CH,T2 ; Get the next character
CAXN CH,.CHLFD ; Is it a line feed?
SOJ P1, ; Yes, back up by one
JRST .+2 ; Skip in
DISP.H: ILDB CH,T2 ; Get the next character (last one in buffer)
PUSHJ P,CKTRM ; Check if a line terminator
JRST DISP.F ; Not, skip
SOJA P1,DISP.F ; It is, back up over it
DISP.I: SOJ T2, ; Back up one character
IDIVX T2,5 ; Get the offset to the character
HLL T2,BTAB(T3) ; Get the byte pointer
ADDI T2,.BKTLN(T1) ; And get the address
LDB CH,T2 ; Get the character
CAXE CH,.CHCRT ; Is it a carriage return?
JRST DISP.F ; No, skip this
ILDB CH,T2 ; Yes, get the character at the pointer
CAXN CH,.CHLFD ; Is it a line feed?
SUBI P1,2 ; Yes, back up the point we are looking for
DISP.F: STOR. P1,BLKPT,(T1) ; Store the pointer for GETVID
PUSHJ P,GETVID ; And get the line bounds
SKIPA T2,A2 ; Get the start of the line
DISP.G: MOVE T2,P1 ; Get the start we were given
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
PUSHJ P,SETLIN ; And set up to return the lines
DISP.1: LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
PUSHJ P,RTNLIN ; And fine the bounds of the screen line
STOPCD (PTD,<PT disappeared>)
MOVEM T1,@BEGPTR ; Store the start
MOVEM T2,@ENDPTR ; And the end
MOVEM T3,@NUMPTR ; Store the number of positions
TXNE P2,DS$CMD ; Is this the command buffer?
TXO T4,LD$CMD ; Yes, flag this is part of the command
MOVEM T4,@FLGPTR ; Store the flags
CAMG P1,T2 ; Is the pointer within this line?
JRST DISP.2 ; Yes, go build down from here
MOVE T3,BEGBLT ; Get the BLT pointer
MOVEI T4,@BEGPTR ; Check where we are at currently
CAIGE T4,(T3) ; Doing the BLT make sense?
SOJA P4,DISP.1 ; No, just count the line and try again
BLT T3,@BEGPTR ; Yes, move the BEG's
DEFINE XXX(THING),<
LSTOF. ;; Turn the listing off
IRP THING,<
MOVE T3,THING'BLT ;; Get the BLT pointer
BLT T3,@THING'PTR ;; And move the section
> ;; End of IRP
LSTON. ;; Turn the listing on again
> ; End of DEFINE XXX
XXX(<END,FLG,NUM>) ; And move the rest
SOJA P4,DISP.1 ; Loop for the next line
; Now we must fill the bottom of the screen. At this point P4 has
;the number left to fill on the top of the screen and P3 has the
;AOBJx pointer to the bottom of the screen.
DISP.2: AOBJP P3,DISP.3 ; Need to do any here?
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
PUSHJ P,RTNLIN ; Get the line bounds
JRST DISP.6 ; Hit the end of the screen first
MOVEM T1,@BEGPTR ; Store the start
MOVEM T3,@NUMPTR ; Store the length
MOVEM T2,@ENDPTR ; And the end of this line
TXNE P2,DS$CMD ; Is this the command buffer?
TXO T4,LD$CMD ; Yes, flag this is part of the command
MOVEM T4,@FLGPTR ; Store the LDB flags
JRST DISP.2 ; Try again
; Now we must fill out the top of the screen. We must take the beginning
;of the top line we have and back up from there. We enter with
;P4 = the number of lines we have to fill on the top of the screen
;If P4 is negative or zero we are done and can go get the screen
;bounds out of our table.
DISP.3: PUSH P,P1 ; Save the current pointer
EXCH P3,P4 ; And set up so that the xxxPTR words work
JUMPLE P3,DISP.A ; If nothing left, don't even try to get the pointer
DISP.4: MOVE P1,@BEGPTR ; Get the current pointer
SOJL P3,DISP.A ; Go return the bounds
SOJL P1,DISP.7 ; Minus one to get to the previous line
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
STOR. P1,BLKPT,(T1) ; Store for GETVID
PUSHJ P,GETVID ; Find it
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
MOVE P1,A1 ; Get the end of the line
MOVE T2,A1 ; Get the end address of the line
SUBI T2,1 ; Minus two to get before any CRLF
IDIVI T2,5 ; Convert to word/byte index
ADDI T2,.BKTLN(T1) ; Point to the correct word
HLL T2,BTAB(T3) ; And get the correct byte pointer
LDB T3,T2 ; Get the character
CAXE T3,.CHCRT ; Is it a carriage return?
JRST DISP.E ; No, skip this
ILDB T3,T2 ; Get the next character
CAXN T3,.CHLFD ; Is it a line feed
SUBI P1,2 ; Yes, there will be two non-displayed chars
DISP.E: MOVE T2,A2 ; And the character address
PUSHJ P,SETLIN ; And set up to get the lines
DISP.5: LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
PUSHJ P,RTNLIN ; Get the line bounds
STOPCD (EBB,<End of buffer while going backwards>)
MOVEM T1,@BEGPTR ; Store the start
MOVEM T2,@ENDPTR ; And the end
MOVEM T3,@NUMPTR ; Store the length
TXNE P2,DS$CMD ; Is this the command buffer?
TXO T4,LD$CMD ; Yes, flag this is part of the command
MOVEM T4,@FLGPTR ; Store the flags
CAMGE P1,T2 ; Hit the end of this line yet?
JRST DISP.4 ; Yes, go try the next
MOVE T3,BEGBLT ; No, get the BLT pointer
CAIGE T4,(T3) ; Make sense to BLT?
JRST DISP.5 ; No, skip it
BLT T3,@BEGPTR ; Yes, move the beg's
XXX(<END,FLG,NUM>) ; Move the rest
JRST DISP.5 ; And try again
; Here if we hit the end of the screen while trying to fill the bottom
;of the screen. We will move all of the BEG/END pairs down to the bottom of
;the screen and try to fill the top.
DISP.6: TXNE P2,DS$FIX ; If this is fixed, then leave the white space
JRST DISP.3 ; Just do the top of the screen now
JUMPLE P4,DISP.9 ; Done?
DEFINE XXX(STK),<
LSTOF. ;; Turn the listing off
IRP <STK>,<
MOVE T4,STK'POP ;; Set up to move the STK's
HLRE T1,P3 ;; Get the amount we need to move them
IFN FTKL,<
ADJSP T4,(T1) ;; Fix it up for the number to move
MOVN T1,T1 ;; . . .
> ;; End of IFN FTKL
IFE FTKL,<
MOVN T1,T1 ;; Make positive
HRLI T1,(T1) ;; And make the XWD
SUB T4,T1 ;; Fix the pointer
> ;; End of IFE FTKL
HRLI T1,(POP T4,(T4)) ;; Put in the pop instruction
XCT T1 ;; Do the POP loop
JUMPL T4,.-1 ;; . . .
>;; End of IRP <STK>
LSTON. ;; Turn the listing back on
>; End of XXX macro definition
XXX (<BEG,END,FLG,NUM>) ; Move the areas
ADDI P4,(T1) ; Fix now for the amount we still need to do on the top
ADDI P3,(T1) ; Also here
TXZ P3,LH.ALF ; And flag we are done
JRST DISP.3 ; Go try to fill the bottom
; Here if we hit the beginning of the buffer before the top of the
;screen was filled. We move what we already have up to the top and then
;fill the bottom of the screen up.
DISP.7: POP P,P1 ; Get the pointer back
EXCH P3,P4 ; And fix these up once more
MOVE T3,BEGBLT ; Set up to move to the top of the screen
MOVSI T4,(P4) ; Get the amount to add
ADD T3,T4 ; Fix where to move from
HRRI T4,(P4) ; Make it an XWD
SUB P3,T4 ; And fix the AOBJx pointer
SUB P3,[XWD 2,2] ; Back off to correct line
MOVEI T4,@BEGPTR ; Check if it really makes sense to do the BLT
CAIGE T4,(T3) ; Make sense?
JRST DISP.8 ; No, skip it
BLT T3,@BEGPTR ; Yes, do the blt
DEFINE XXX(THING),<
LSTOF. ;; Turn the listing off
IRP THING,<
MOVE T3,THING'BLT ;; Get the other BLT pointer
MOVSI T4,(P4) ;; Get the amount to move
ADD T3,T4 ;; Fix the BLT pointer
BLT T3,@THING'PTR ;; And move the THING's
> ;; End of IRP THING
LSTON. ;; Turn the listing on
> ; End of DEFINE
XXX(<END,FLG,NUM>) ; Move the other sections
DISP.8: SETZ P4, ; Flag that we are done with the top
MOVE T2,@ENDPTR ; Get the end of the previous line
MOVE T1,@FLGPTR ; And the flags
TXNE T1,LD$CRLF ; Line end with a CRLF?
ADDI T2,2 ; Yes, skip over the CRLF
LOAD. T1,TPTADR,+$QRTPT(P2) ; Get the buffer address
PUSHJ P,SETLIN ; Set up the line for next call to RTNLIN
JRST DISP.2 ; And try again
; Here when we are done. Return the limits from the blocks
DISP.A: POP P,P1 ; Restore the pointer
EXCH P3,P4 ; And put the ac's back
DISP.9: LOAD. T1,QRGOFS,(P2) ; Get the offset to the first line
IMULX T1,$LDLEN ; Make it the address
ADD T1,SCRNAD ; . . .
LOAD. T2,QRGNLN,(P2) ; Get the number of lines
MOVN T2,T2 ; Make it negative
HRLI T1,(T2) ; And make the AOBJx pointer
MOVNI P3,(P3) ; Make the pointer to the limits
MOVSI P3,(P3) ; And make it an AOBJx pointer
DEFINE XXX(THING),<
LSTOF. ;; Turn the listing off
IRP THING,<
MOVE T2,@THING'PTR ;; Get the THING
STOR. T2,LDB'THING,(T1) ;; Store it
> ;; End of IRP
LSTON. ;; Turn the listing on again
> ; End of DEFINE XXX
DISP.B: XXX(<BEG,END,FLG,NUM>) ; Move the values
ADDX T1,$LDLEN-1 ; Bump to the next
AOBJP T1,DISP.C ; Run out yet?
AOBJN P3,DISP.B ; No, get the next pair
DISP.D: ONES. ,LDBBEG,(T1) ; Flag nothing on this line
ONES. ,LDBEND,(T1) ; . . .
ZERO. ,LDBFLG,(T1) ; . . .
ZERO. ,LDBNUM,(T1) ; . . .
ADDX T1,$LDLEN-1 ; Bump to next
AOBJN T1,DISP.D ; Loop for all the lines
DISP.C: LOAD. T3,QRGNLN,(P2) ; Get the number of lines
AOJ T3, ; Plus one
ASH T3,2 ; Time four
HRLI T3,(T3) ; Make the XWD
SUB P,T3 ; And fix the stack
POPJ P, ; And return
SUBTTL Screen editing -- Subroutines -- SETLIN and RTNLIN
;+
;.hl1 SETLIN
;This routine will do the initialization for the RTNLIN routine. This
;routine is called with a character position and the text buffer address
;for the RTNLIN routine.
;.literal
;
; Usage:
; MOVE T1,Text buffer address
; MOVE T2,Character address
; PUSHJ P,RTNLIN
; (Return)
;.end literal
;.HL1 RTNLIN
;This routine will return the character addresses for the beginning of the
;line and the end of the line. It will also return the number of character
;positions taked up by the characters on the line.
;.literal
;
; Usage:
; MOVE T1,Text buffer address
; PUSHJ P,RTNLIN
; (Return -- Failed)
; (Return -- T1 = Beginning address, T2 = Ending, T3 = Number of positions
; T4 = LDB flags)
;.end literal
;-
SETLIN: STOR. T2,BLKPT,(T1) ; Store the position
IDIVI T2,5 ; Break into word/char offset
HLL T2,BTAB-1(T3) ; Get the byte pointer
ADDI T2,.BKTLN(T1) ; And make it absolute
STOR. T2,BLKPTR,(T1) ; Store the byte pointer
POPJ P, ; Return
RTNLIN: $SAVE <CH> ; Save the character AC
$SAVE <P1,P2,P3> ; Save a few other registers
SETZB P3,CH ; Clear the number of positions
LOAD. P1,BLKPT,(T1) ; Get the beginning address
RTNL.0: CAML P3,SCRWID ; Is this the end ?
JRST RTNL.3 ; Yes - Just return
MOVE T3,P3 ; Copy the old character position
MOVE T2,CH ; Copy the last character
PUSHJ P,GETINC ; Get the next character
JRST RTNL.1 ; Failed - This must be the end
CAXN CH,.CHTAB ; Is this a tab
JRST [TXO P3,7 ; And round up
ADDI P3,1 ; And round up
JRST RTNL.0] ; Try for the next character
CAXN CH,.CHDEL ; Delete?
AOJ P3, ; Yes, counts for two positions (prints as ^?)
CAXE CH,.CHESC ; Is this an escape
CAXL CH," " ; No, Is this a control character ?
AOJA P3,RTNL.0 ; Either an escape or normal character
ADDI P3,2 ; Control character
PUSHJ P,CKTRM ; Is this a line terminator ?
JRST RTNL.0 ; No - Skip this then
LOAD. P2,BLKPT,(T1) ; Get the current pointer
CAXE CH,.CHCRT ; Was the character string CRLF ?
JRST RTNL.2 ; No - Skip this
PUSHJ P,GETINC ; Get the next character
JRST RTNL.2 ; And return a zero flag word
CAXE CH,.CHLFD ; Is this a line feed ?
JRST [PUSHJ P,RTNL.A ; No - Back up the one
JRST RTNL.2] ; And return a zero flag word
SUBI P2,1 ; Yes - Back up the pointer one
SUBI P3,2 ; And two positions
RTNL.Z: SKIPA T4,[EXP LD$CRLF] ; And return a CRLF flag
; Here to move the arguments and return a zero for the flag
RTNL.2: SETZ T4, ; Clear the flag
RTNL.Y: DMOVE T1,P1 ; Copy the arguments
MOVE T3,P3 ; To return
JRST .POPJ1 ; And give a good return
; Here if the getting of the next character failed
RTNL.1: LOAD. P2,BLKPT,(T1) ; Get the pointer
JUMPE P3,.POPJ ; Return if nothing
JRST RTNL.2 ; Just get out
; Here if the position is equal to the width of the screen
; Check to see if the next two characters a <CR><LF> if so eat
; them and return, else return that the line wraps around to the next
; line.
RTNL.3: LOAD. P2,BLKPT,(T1) ; Get the current pointer
PUSHJ P,GETINC ; Get the next character
JRST RTNL.7 ; Failed - Back up and fail later
CAXE CH,.CHCRT ; Is this a <CR> ?
JRST RTNL.6 ; No - Must be a wrap
PUSHJ P,GETINC ; Get the next charcter for the <LF>
JRST RTNL.6 ; Nothing - Back up one charcter and return
; wrap around flag
CAXN CH,.CHLFD ; Is this a line feed ?
JRST RTNL.Z ; Yes - Return the CRLF flag
RTNL.4: PUSHJ P,RTNL.A ; Decrement the pointer
RTNL.6: PUSHJ P,RTNL.A ; And again
RTNL.7: MOVX T4,LD$WAP ; Get the wrap around flag
JRST RTNL.Y ; And return the information
; Here to decrement the pointers
RTNL.A: DECR. T2,BLKPT,(T1) ; Decrement the pointer
PJRST SETLIN ; Set up the line getter
SUBTTL Screen editing -- Subroutines -- FLSLDB - Flush an LDB
;+
;.HL1 FLSLDB
;This routine will first clear the LDB beginning and end pointers,
;the number of character being displayed and the flags. It will
;then call CLRLDB to move spaces into the LDB that is being used.
;.literal
;
; Usage:
; MOVE T1,LDB.address
; PUSHJ P,FLSLDB
; (Return)
;.end literal
;-
FLSLDB: ZERO. ,LDBFLG,(T1) ; Clear the flags
ZERO. ,LDBNUM,(T1) ; . . .
ONES. ,LDBBEG,(T1) ; Set the beginning and the end
ONES. ,LDBEND,(T1) ; to minus one
FALL CLRLDB ; Fall into CLRLDB
SUBTTL Screen editing -- Subroutines -- CLRLDB - Clear an LDB
;+
;.HL1 CLRLDB
;This routine will set the LDBTXT line to blanks.
;.literal
;
; Usage:
; MOVE T1,LDB address
; PUSHJ P,CLRLDB
; (Return)
;
; -- or --
;
; MOVE T1,Line address
; PUSHJ P,CLRL.0
; (return)
;.end literal
;-
CLRLDB: LOAD. T1,LDBTXT,(T1) ; Get the address
CLRL.0:
IFN FTDEBUG,<
CAIG T1,IMPEND ; Is this at least in the real data area ?
STOPCD ACR,<Attempt to clear registers in CLRLDB>
>; End of IFN FTDEBUG
MOVX T2,<ASCII | |> ; Get the blanks to store
MOVEM T2,(T1) ; Store them into the LDB
HRL T1,T1 ; Build the BLT pointer
ADDI T1,1 ; . . .
MOVE T2,LINWDS ; Get the number of words per line
SOJLE T2,.POPJ ; Don't need the BLT if only one word
ADDI T2,(T1) ; Point to the last word
BLT T1,-1(T2) ; Set the block to spaces
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Subroutines -- CKTRM - Check for a line terminator
;+
;.HL1 CKTRM
;This routine will work like CKEOL except that the terminator characters
;are defined as the following: Carriage return, Line feed, Form feed, and
;vertical tab.
;.literal
;
; Usage:
; MOVE CH,Character to check
; PUSHJ P,CKTRM
; (Return - Not a terminator)
; (Return - Terminator)
;
;.end literal
;-
CKTRM: CAXE CH,.CHCRT ; Is this a carriage return ?
CAXN CH,.CHLFD ; Or a line feed
JRST .POPJ1 ; Yes - Return (Most likely case if any)
CAXE CH,.CHVTB ; Is this a vertical tab ?
CAXN CH,.CHFFD ; Or a form feed ?
AOS (P) ; Yes - Increment the return address
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Subroutines -- FNDLDB - Find the LDB
;+
;.HL1 FNDLDB
;This routine will find the LDB associated with the character address.
;.literal
;
; Usage:
; MOVE T1,Character address
; MOVE T2,QRG block address
; PUSHJ P,FNDLDB
; (Failure return)
; (Good return)
;
; On failure:
; T1 = 0 if not on screen
; T1 = -1 if not being displayed at all
;
; On success:
; T1 = Address of the LDB
;.end literal
;-
FNDLDB: $SAVE <P1,P2> ; Save P1 and P2
DMOVE P1,T1 ; Copy the address
MOVX T1,QR$VID ; Is this being displayed ?
TDNN T1,$QRFLG(P2) ; . . .
JRST [SETO T1, ; Return a minus one
POPJ P,] ; And return
LOAD. T1,QRGOFS,(P2) ; Get the first line offset
IMULX T1,$LDLEN ; Compute the address of the first LDB
ADD T1,SCRNAD ; Add in the LDB list address
LOAD. T2,QRGNLN,(P2) ; Get the number of lines
MOVN T2,T2 ; Make it negative
HRL T1,T2 ; Make this an AOBJN pointer
MOVX T2,LD$CRLF ; Get the CRLF flag to check
FNDL.0: CFMLE. ,LDBBEG,(T1),P1 ; Is this the LDB ?
JRST FNDL.1 ; Out of range - Return
LOAD. T3,LDBEND,(T1) ; Get the ending character address
TDNE T2,$LDFLG(T1) ; End with a CRLF ?
ADDI T3,2 ; Yes - Increment the end
CAMGE P1,T3 ; On this line ?
JRST .POPJ1 ; Give a good return
ADDX T1,$LDLEN-1 ; Point to the next entry minus one
AOBJN T1,FNDL.0 ; Loop for all LDBs
LOAD. T2,TPTADR,+$QRTPT(P2) ; Get the text address
CFME. ,BLKEND,(T2),T3 ; At end of buffer?
JRST FNDL.1 ; No, not displayed
CAMN P1,T3 ; Yes, exactly right place?
AOJA T1,.POPJ ; Yes, return the LDB address
FNDL.1: SETZ T1, ; Clear not on the screen
POPJ P, ; Return to the caller
SUBTTL Screen editing -- Subroutines -- FNDPOS
;+
;.hl1 FNDPOS
; This routine will find the X position of a given character address on a
;line.
;.b.lit
;
; Usage:
; MOVEI T1,LDB address
; MOVE T2,Character address
; MOVE T3,Text buffer address
; PUSHJ P,FNDPOS
; (return here, T1/T2 containing X and Y positions)
;
;.end literal
;-
FNDPOS: $SAVE <P1,P2,P3,P4> ; Save some room
DMOVE P1,T1 ; Get the arguments
MOVE P3,T3 ; Get the text buffer address
LOAD. P4,BLKPT,(P3) ; Get the current pointer
MOVE T1,P3 ; Get the text buffer address
LOAD. T2,LDBBEG,(P1) ; And the character address to start at
PUSHJ P,SETLIN ; Set up to get the characters
LOAD. T1,LDBBEG,(P1) ; Get the character address of the start of the line
SUB P2,T1 ; Get the number of characters to skip
SETZ T4, ; Clear the position
; Loop until we find the right character
FNDP.1: SOJGE P2,FNDP.0 ; Count the character
FNDP.3: MOVE T1,T4 ; Get the position within the line
LOAD. T2,LDBLIN,(P1) ; And the line number
STOR. P4,BLKPT,(P3) ; Store the pointer back
POPJ P, ; And return
FNDP.0: MOVE T1,P3 ; Get the buffer address
PUSHJ P,GETINC ; And get a character
JRST FNDP.3 ; All done, go return the value
CAXN CH,.CHDEL ; Delete ?
AOJ T4, ; Yes, prints as ^?
CAIE CH,.CHESC ; Escape?
CAIL CH," " ; Control character?
AOJA T4,FNDP.1 ; No, takes one space
PUSHJ P,CKTRM ; Yes, is it a line terminator?
JRST FNDP.2 ; No, check for a tab
ADDI T4,2 ; Yes, bump by two
CAIE P2,1 ; Is this the last character?
CAXE CH,.CHCRT ; Carriage return?
JRST FNDP.1 ; No, go count the character
SETZ T4, ; Yes, move back to right margin
JRST FNDP.1 ; And go count it
FNDP.2: CAXE CH,.CHTAB ; Is it a tab?
AOJA T4,.+2 ; No, bump by one and skip
TXO T4,7 ; Yes, move to the tab stop
AOJA T4,FNDP.1 ; Go check if done
SUBTTL FNDCHP - Find the position of a given character
;+
;.HL1 FNDCHP
; This routine will attempt to find the position on the screen of a given
;character.
;.lit
;
; Usage:
; T1/ Character address
; T2/ QRG.address
; PUSHJ P,FNDCHP
; (not on screen return)
; (On screen, T1/T2 = corrdinates)
;
;.end lit
;-
FNDCHP: $SAVE <P1,P2,P3> ; Save some ac's
DMOVE P1,T1 ; Get a copy of the arguments
PUSHJ P,FNDLDB ; Find what line it is on
PJRST FNDC.2 ; If not on the screen, use CMDPOS
LOAD. T3,TPTADR,+$QRTPT+TXTBUF ; Get the buffer address back
MOVE T2,P1 ; Get the position we want
PUSHJ P,FNDPOS ; Find the position on the line
PJRST .POPJ1 ; And give the skip return
; Here if it does not seem to be on the screen
FNDC.2: JUMPL T1,.POPJ ; If not displayed, punt
JUMPN P1,FNDC.3 ; Special case of first character?
LOAD. T1,QRGOFS,(P2) ; Get the offset to the first line
IMULX T1,$LDLEN ; . . .
ADD T1,SCRNAD ; Get the LDB address
CFME. T2,LDBQRG,(T1),P2 ; Correct item?
JRST FNDC.3 ; No, can't put at start of buffer
CFXLE. ,LDBBEG,(T1),0 ; Is the first character in the buffer on the screen?
JRST FNDC.3 ; No, ignore this
LOAD. T2,LDBLIN,(T1) ; Yes, get the first line number
SETZ T1, ; And clear the X position
PJRST .POPJ1 ; And return
FNDC.3: LOAD. P3,TPTADR,+$QRTPT(P2) ; Get the address of the buffer
CFME. ,BLKEND,(P3),P1 ; Pointer at the end of the buffer?
POPJ P, ; No, this address is not displayed
MOVE T1,P1 ; Get the character address
SOJ T1, ; Decrement to point to the last char
IDIVX T1,5 ; Convert to word/byte offset
HLL T1,BTAB(T2) ; Get the byte pointer
ADDI T1,.BKTLN(P3) ; And make the absolute address
LDB CH,T1 ; Get the final character
LOAD. T1,QRGOFS,(P2) ; Get the offset to the first line
IMULX T1,$LDLEN ; Convert to LDB offset
ADD T1,SCRNAD ; Make the absolute address
LOAD. T2,QRGNLN,(P2) ; Get the number of lines
MOVN T2,T2 ; Make it negative
HRLI T1,(T2) ; And make the AOBJx pointer
FNDC.7: LOAD. T2,LDBEND,(T1) ; Get the end pointer
JUMPL T2,FNDC.8 ; Is it valid?
ADDX T1,$LDLEN-1 ; Yes, bump to the next
AOBJN T1,FNDC.7 ; And loop for all the LDB's
; If we get here, all of the lines of the window are used. The only
;special case we need to check now is if the last line does not end with an
;end of line character.
PUSHJ P,CKTRM ; And check if it is a line terminator
JRST .+2 ; Skip
POPJ P, ; Give not found return
LOAD. T2,LDBLIN,-$LDLEN(T1) ; Get the line number
LOAD. T1,LDBNUM,-$LDLEN(T1) ; And get the number of chars on the line
PJRST .POPJ1 ; Give a good return
; Here if there are blank lines in the window. Find the correct place to put
;the pointer.
FNDC.8: PUSHJ P,CKTRM ; Check if last char was a line terminator
SUBX T1,$LDLEN ; No, back up one line
LOAD. T2,LDBLIN,(T1) ; Get the line number
LOAD. T1,LDBNUM,(T1) ; Get the position on the line
PJRST .POPJ1 ; Return
SUBTTL Screen editing -- Subroutines -- VIDPOS - Return the command position
;+
;.hl1 VIDPOS
;This routine will return the X position of in the current command buffer.
;It is used for the command processing.
;.literal
;
; Usage:
; PUSHJ P,VIDPOS
; (Return - T1 contains the X position,
; T2 contains the END character address
; T3 contians the BEG character address
; T4 contians the flags)
;
;.end literal
;-
VIDPOS: $SAVE <A1,A2> ; Save the argument registers
LOAD. T1,TPTADR,+CMDBUF+$QRTPT ; Get the text buffer address
PUSHJ P,GETVID ; Get the address
LOAD. T1,TPTADR,+CMDBUF+$QRTPT ; Get the text buffer again
LOAD. A1,BLKPT,(T1) ; Save the current pointer
MOVE T2,A2 ; Get the pointer address
PUSHJ P,SETLIN ; Set up RTLINE calls
VIDP.0: LOAD. T1,TPTADR,+CMDBUF+$QRTPT ; Get the text buffer address again
PUSHJ P,RTNLIN ; Call RTLINE to return the position
JRST VIDP.1 ; End of buffer, return zeros
TXNE T4,LD$CRLF ; End of a CRLF ?
ADDI T2,2 ; Yes, increment the position
CAMLE A1,T2 ; Is this the line we wanted?
JRST VIDP.0 ; No, try again
EXCH T1,T3 ; Yes, Get the position
POPJ P, ; Return to the caller
; Here if there are no characters on this line
VIDP.1: SETZB T1,T2 ; Clear the position
SETZB T3,T4 ; And the others
POPJ P, ; And return
SUBTTL Screen editing -- Subroutines -- GETVID
;+
;.hl2 GETVID
; This routine is a generallized GETARG or GETCMD routine. It will
;expect to be given the text buffer that is to be used for looking
;up the lines.
;.literal
;
; Usage:
; MOVE T1,TPT.address
; PUSHJ P,GETVID
; (Return -- A1 and A2 set up)
;.end literal
;-
GETVID: $SAVE <CH,P1> ; Save CH and P1
MOVE P1,T1 ; Copy the TPT address
LOAD. T1,BLKPT,(P1) ; Get the pointer
SOSGE T4,T1 ; Minus one character
JRST GETV.5 ; If negative we don't have to look any further
IDIVI T1,5 ; And split into word/character indices
ADDI T1,.BKTLN(P1) ; Make the word address
HLL T1,BTAB(T2) ; And the byte pointer
LOAD. T2,BLKEND,(P1) ; Get the end pointer
SOJ T2, ; And check if we are pointing there
SETO CH, ; Assume we are at the end
CAML T4,T2 ; Are we?
JRST GETV.4 ; And continue on
PUSH P,T1 ; Save the byte pointer
ILDB CH,T1 ; Get the character after this
POP P,T1 ; Restore the byte pointer
GETV.4: MOVE T2,CH ; Copy the old character
LDB CH,T1 ; Get the character
PUSHJ P,CKTRM ; Check if end of line
JRST GETV.7 ; Nope, back up the byte pointer and try again
CAXN CH,.CHCRT ; Is this a carriage return?
CAXE T2,.CHLFD ; Yes, was it paired with a line feed?
JRST GETV.5 ; Yes, all done
GETV.7: ADDX T1,<INSVL.(7,BP.PFL)> ; Back up the position
JUMPG T1,GETV.8 ; Need to go over word boundary?
SOJ T1, ; Yes, do it
TXZ T1,BP.PFL ; Clear out the position field
TXO T1,<INSVL.(1,BP.PFL)> ; And put in a one
GETV.8: SOJGE T4,GETV.4 ; And loop unless we hit the start of the buffer
GETV.5: AOS A2,T4 ; Get the start of the string
LOAD. A1,BLKPT,(P1) ; And the end
POPJ P, ; And return
SUBTTL Screen editing -- Subroutines -- CHKTYI - Check if any type ahead
;+
;.hl1 CHKTYI
; This routine is called to check if the user has typed any characters
;yet. This is so that the screen updating can be aborted when the user
;starts typing the next command.
;.b.lit
;
; PUSHJ P,CHKTYI
; (return, no characters waiting)
; (return, characters waiting for input)
;
;.end literal
;-
CHTYI0: SKIPE NOTYIA ; Type-ahead disabled?
POPJ P, ; Yes, give up
SKIPN TYIFLG ; Any type-ahead?
PUSHJ P,T$CTYI ; Check for type-in
POPJ P, ; No type-ahead
SETOM TYIFLG ; Remember we have it
PJRST .POPJ1 ; We have type-ahead
CHKTYI: SKIPE NOTYIA ; Type-ahead disabled?
POPJ P, ; Yes, return now
SKIPE TYIFLG ; Already have type ahead
PJRST .POPJ1 ; Yes, give the type ahead seen return
PUSHJ P,T$CTYI ; Check for type-in
JRST CHKT.1 ; None yet, check if any output in the buffer
SETOM TYIFLG ; Yes, flag it
JRST .POPJ1 ; Give the waiting return
; Here to check whether the output buffer is empty. If it isn't and
;we are on a slow terminal, we should HIBERnate a little bit before
;continuing. This makes it possible to have typeahead abort the update
;and not have half the screen update still be in the monitors output
;buffers.
ND D$SLOW,.TS120 ; 600 baud and below are slow terminals
ND D$WTIM,^D100 ; Wait a tenth of a second before trying again
ND D$FTIM,^D50 ; Number of mill-seconds to fudge calculated time
CHKT.1: TXNE F,F.TYOF ; Any typeout in the buffers?
PUSHJ P,TTYOUT ; Yes, must also account for that
$SAVE <P1,P2> ; Save P1
MOVE P1,TRMSPD ; Get the terminal speed
CAXLE P1,D$SLOW ; Is it a slow terminal?
POPJ P, ; No, forget this
CHKT.2: MOVE P1,[XWD 2,TRMTOC] ; Get the pointer
TRMOP. P1, ; Get the number of characters in the output buffer
JRST CHKT.5 ; Can't, check if output present at all
IMULX P1,^D1000 ; Get the number of chars*1000
MOVE P2,TRMSPD ; Get the speed
IDIV P1,CPSTBL(P2) ; And determine the time it will take to type them
SUBX P1,D$FTIM ; Fudge time for chars which typed out now
JUMPG P1,CHKT.5 ; If we must wait, go do it
JRST CHKT.3 ; Otherwise go check for input again
; Here if .TOTOC TRMOP. doesn't work
CHKT.5: MOVE P1,[XWD 2,TRMSOP] ; Get the TRMOP args
TRMOP. P1, ; Any output present?
JRST CHKT.3 ; No, go check if there is typeahead now
MOVX P1,HB.RTC!D$WTIM ; Yes, get the wait time
CHKT.4: HIBER P1, ; Wait a bit
JFCL ; Ignore it
JRST CHKT.2 ; And go check if there is still output
; Here after checking the output buffer to check for typeahead again
CHKT.3: PUSHJ P,T$CTYI ; Check for type-in
POPJ P, ; No, just return
SETOM TYIFLG ; Yes, flag we have some
PJRST .POPJ1 ; And give the type ahead return
SUBTTL Low segment for TECUPD
$IMPURE ; Do the impure storage
LOWVER(UPD,1) ; Low segment version number of this module
; CRT data
FNCLST: BLOCK 1 ; Function list for updating lines
FNCBLK: BLOCK 1 ; Address of function block for overall update
FNCTMP: BLOCK 3 ; Temp function list for UPDSCT
TYIFLG: BLOCK 1 ; Flag whether type ahead has been seen yet
NOTYIA: BLOCK 1 ; Type-ahead abort disabled
IDLCNT: BLOCK 1 ; Insert/delete line counter for UPDSCT
; For DISPLY
BEGPTR: BLOCK 1 ; Pointer into block of line BEG's
ENDPTR: BLOCK 1 ; Pointer into block of line END's
FLGPTR: BLOCK 1 ; Pointer into block of line FLG's
NUMPTR: BLOCK 1 ; " for line lengths
BEGBLT: BLOCK 1 ; BLT pointer for moving BEG's toward top of screen
ENDBLT: BLOCK 1 ; BLT pointer for END's
FLGBLT: BLOCK 1 ; BLT pointer for FLG's
NUMBLT: BLOCK 1 ; " for line lengths
BEGPOP: BLOCK 1 ; POP loop pointer for BEG's
ENDPOP: BLOCK 1 ; POP loop pointer for END's
FLGPOP: BLOCK 1 ; POP loop pointer for FLG's
NUMPOP: BLOCK 1 ; " for line lengths
; For LINCST
OLDSPT: BLOCK 1 ; Saved byte pointer to old text
OLDPTR: BLOCK 1 ; Running byte pointer to old text
NEWPTR: BLOCK 1 ; Running byte pointer to new text
LNCXCT: BLOCK 2 ; Correct ILDB instruction for LNCRPL
LNCXC2==LNCXCT+1 ; Correct instruction to fetch number of chars left in suffix of string
LITRTM: BLOCK 1 ; LINCST time estimate per 1000 iterations
LBGUPT: BLOCK 1 ; Uptime in milli-seconds saved when
; LINCST loop was started
NUMITR: BLOCK 1 ; Number of iterations being performed by LINCST
OLDLDB: BLOCK 1 ; Address of old lines LDB
NEWLDB: BLOCK 1 ; Address of new lines LDB
COLPTR: BLOCK 1 ; AOBJx pointer to column
ROWPTR: BLOCK 1 ; AOBJx pointer to row
NUMCOL: BLOCK 1 ; Number of columns in table. This is the amount
; to add to go down one row.
MATRIX: BLOCK 1 ; Matrix used to calculate min cost
IFN FTDEBUG,<
NUMROW: BLOCK 1 ; Number of rows in matrix
UPDDEB: BLOCK 1 ; Update debugging output flag
> ; End of IFN FTDEBUG
; For SCTCST
OLDLDP: BLOCK 1 ; AOBJx pointer to old lines
NEWLDP: BLOCK 1 ; AOBJx pointer to new lines
TOTCST: BLOCK 1 ; Running minimum cost for SCTRPL
ENDACC: BLOCK 1 ; Number of accepts to end with
BEGACC: BLOCK 1 ; Number of accepts to start with
CSTLST: BLOCK 1 ; Address of list of line to line replacement costs
UPCSFL: BLOCK 1 ; Flag -1 indicates doing update,
; +0 indicates doing cost calc
SUBTTL End of TECUPD
END ; End of TECUPD