        title term

; edit history:
;     7-DEC-85  ORIGINAL        BGP
;    20-FEB-86  CORRECTED FOR ERROR IN PUTMOD IN MSXV9000       (BGP)
;    22-FEB-86  CLEANED UP CHARACTER SET FOR TEK EMULATION      (BGP)
;    22-FEB-86  ADDED CODE TO SWALLOW ANSI ESCAPE SEQUENCES IN
;               HEATH EMULATION MODE                            (BGP)
; *********************************************************************
;
; Remove segment Graph and replace it with memory dynamically allocated
; from DOS via procedure sbrk in mssker. Do allocation, initialize scrseg,
; and clear the area, all done in lclyini. 17 March 86 Joe R. Doupnik
;
; SPECIAL VERSION WITH NEAR COMPLETE SUPPORT OF TEKTRONIX 4010 EMULATION

        public  term, lclyini                   ; entry points
        include mssdef.h

;  Some extra ASCII definitions
ENQ     EQU     5
ETB     EQU     17H
VTAB    EQU     0BH
SUB     EQU     1AH
GS      EQU     1DH
US      EQU     1FH

CLEAR   EQU     0F1H                    ; Key to clear screen
CURSOR_CHR EQU  '_'                     ; The cursor character
CURSOR_TIME EQU 100                     ; cursor on countdown period
;       this is the number of unsuccessful tries on getting a charcter
;       from the input port before turning on the cursor.

X_MAX   EQU     799
Y_MAX   EQU     399
TEK_X_MAX EQU   1023
TEK_Y_MAX EQU   780
TEXT_X_MAX EQU  789
TEXT_Y_MAX EQU  389
RPLINE  EQU     11                      ; rows per text line
CPCHAR  EQU     11                      ; columns per text character
R_MARG  EQU     781                     ; right margin position
CUR_LEN EQU     10                      ; length of arms on graphics cursor

FALSE   EQU     0
TRUE    EQU     1

SEG_CRTC EQU    0E800H                  ; segment for crt controller
OFF_CRTC EQU    0                       ; offset for crt controller

modfrm  struc                           ; format of mode line
        db      ' Esc chr: '
m_echr  db      2 dup (?)
        db      ', Port: '
m_prt   db      1 dup (?)
        db      ', Speed: '
m_baud  db      4 dup (?)
        db      ', Parity: '
m_par   db      4 dup (?)
        db      ', Echo: '
m_echo  db      3 dup (?)
        db      ', Type '
m_hlp   db      2 dup (?)
        db      '? for Help'
        db      ' $'                    ; must be dollar terminated
modfrm  ends

DATAS   segment public 'datas'

; stuff for screen routines
flags   db      ?                       ; status flags...
flags1  db      0                       ; internal flags.
prtscr  equ     80h                     ; print screen pressed
inited  equ     08h                     ; been here before...
wrapped equ     04h                     ; on if wrapped on last char...
esc_ch  db      ?
argadr  dw      ?                       ; address of arg blk
crt_cols db     ?
crt_lins db     ?
modbuf  modfrm  <>                      ; mode line buffer
; routine to call for captured output
captrtn dw      ?
; some static data for mode line
unkbaud db      'Unk '                  ; must be 4 chars...
baudn   db      '45.5'
        db      '  50'
        db      '  75'
        db      ' 110'
        db      ' 135'
        db      ' 150'
        db      ' 300'
        db      ' 600'
        db      '1200'
        db      '1800'
        db      '2000'
        db      '2400'
        db      '4800'
        db      '9600'
        db      '19.2'
        db      '38.4'
baudnsiz  equ   16                      ; # of baud rates known (tbl size / 4)
parnams db      'Even'
        db      'Mark'
        db      'None'
        db      'Odd '                  ; must be 4 chars
        db      'Spc '
offmsg  db      'Off'
onmsg   db      'On '
lclmsg  db      'Lcl'
remmsg  db      'Rem'

portno  db      ?

tscreen dw      1920 dup (?)            ; place to save text screen
tcurloc db      2 dup (?)               ; column,row
tscrseg dw      0F000H
rptcur  db      27,'n$'                 ; request cursor location
escseq  db      0                       ; ANSI escape sequence indicator
                                        ; 0=none, 1=escape, 2=[

; stuff for the Tektronix emulation
;;;[jrd]scrloc  dw      screen
;;;[jrd]scrseg  dw      seg graph               ; screen segment
                                        ;Order is essential:scrloc then scrseg
scrloc  dw      0                       ; offset of screen memory [jrd]
scrseg  dw      0                       ; segment for screen memory [jrd]

first_in db     TRUE                    ; this is the first time emulating
intens  db      14                      ; CRT intensity setting
status_line dw  80 dup (?)              ; for CRT status line

bit_mask db     1,2,4,8,16,32,64,128
combine dw      pixel_or
t_combine dw    word_or
start   dw      0,0                     ; vector start point
endpt   dw      0,0                     ; end point (victor coords)
cur_x   dw      0                       ; tek coordinates of current point
cur_y   dw      780
text_x  dw      0                       ; text cursor location (victor coords)
text_y  dw      0                       ; upper left corner
cursor_cnt dw   0                       ; cursor countdown
cursor  db      FALSE                   ; cursor state flag
full_flag db    FALSE                   ; flags page full condition
x_inc   dw      1
y_inc   dw      1
delta_x dw      0
delta_y dw      0
part_accum dw   0                       ; accumulator for line
temp    dw      0                       ; temporary storage
c_mask  dw      0                       ; mask for character work
cur_stp dw      1                       ; graphics cursor step
crs_hor dw      0,0,0                   ; cursor horizontal line (x1,x2,y)
crs_ver dw      0,0,0                   ; cursor vertical line (y1,y2,x)
prtesc  db      FALSE                   ; escape from port in GIN mode
trmesc  db      FALSE                   ; escape from terminal in GIN mode


graph_mode db   FALSE                   ; graphics mode flag
echo_supp db    FALSE                   ; echoplex suppression flag
visible db      0                       ; 0 to move, 1 to draw
hiy     dw      0
loy     db      0
hix     dw      0
lox     db      0
lsb     db      0
escflag db      0
tekjump dw      TEKTXT,TEKESC,TEKHIY,TEKHIX

; The next variable defines the bit masks for the text font
font    dw      0,20H,70H,20H,20H,0,20H,20H,0,0,0 ; !
        dw      0,88H,88H,88H,0,0,0,0,0,0,0 ; "
        dw      0,88H,88H,3FEH,88H,3FEH,88H,88H,0,0,0 ; #
        dw      0,1FCH,222H,22H,1FCH,220H,222H,1FCH,0,0,0 ; $
        dw      0,10CH,8CH,40H,20H,10H,188H,184H,0,0,0 ; %
        dw      0,10H,28H,10H,28H,144H,84H,178H,0,0,0 ; &
        dw      0,30H,30H,20H,10H,0,0,0,0,0,0 ; '
        dw      0,40H,20H,10H,10H,10H,20H,40H,0,0,0 ; (
        dw      0,10H,20H,40H,40H,40H,20H,10H,0,0,0 ; )
        dw      0,104H,88H,50H,3FEH,50H,88H,104H,0,0,0 ; *
        dw      0,20H,20H,20H,3FEH,20H,20H,20H,0,0,0 ; +
        dw      0,0,0,0,0,0,30H,30H,20H,10H,0 ; ,
        dw      0,0,0,0,3FEH,0,0,0,0,0,0 ; -
        dw      0,0,0,0,0,0,30H,30H,0,0,0 ; .
        dw      0,100H,80H,40H,20H,10H,8,4,0,0,0 ; /
        dw      0,0F8H,184H,242H,222H,212H,10CH,0F8H,0,0,0 ; 0
        dw      0,20H,30H,20H,20H,20H,20H,70H,0,0,0 ; 1
        dw      0,1FCH,202H,200H,1FCH,2,2,3FEH,0,0,0 ; 2
        dw      0,3FEH,100H,80H,1C0H,200H,202H,1FCH,0,0,0 ; 3
        dw      0,102H,102H,102H,3FEH,100H,100H,100H,0,0,0 ; 4
        dw      0,3FEH,2,2,1FEH,200H,200H,1FEH,0,0,0 ; 5
        dw      0,1FCH,2,2,1FEH,202H,202H,1FCH,0,0,0 ; 6
        dw      0,3FEH,100H,80H,40H,20H,20H,20H,0,0,0 ; 7
        dw      0,0F8H,104H,88H,1FCH,202H,202H,1FCH,0,0,0 ; 8
        dw      0,1FCH,202H,202H,3FCH,200H,200H,1FCH,0,0,0 ; 9
        dw      0,0,30H,30H,0,0,30H,30H,0,0,0 ; :
        dw      0,0,30H,30H,0,0,30H,30H,20H,10H,0 ; ;
        dw      0,80H,40H,20H,10H,20H,40H,80H,0,0,0 ; <
        dw      0,0,0,3FEH,0,3FEH,0,0,0,0,0 ; =
        dw      0,8,10H,20H,40H,20H,10H,8,0,0,0 ; >
        dw      0,1FCH,202H,200H,1E0H,20H,0,20H,0,0,0 ; ?
        dw      0,1FCH,202H,3E2H,212H,1E2H,2,1FCH,0,0,0 ; @
        dw      0,70H,88H,104H,3FEH,202H,202H,202H,0,0,0 ; A
        dw      0,0FEH,102H,102H,1FEH,202H,202H,1FEH,0,0,0 ; B
        dw      0,1FCH,202H,2,2,2,202H,1FCH,0,0,0 ; C
        dw      0,1FEH,202H,202H,202H,202H,202H,1FEH,0,0,0 ; D
        dw      0,3FEH,2,2,7EH,2,2,3FEH,0,0,0 ; E
        dw      0,3FEH,2,2,7EH,2,2,2,0,0,0 ; F
        dw      0,1FCH,202H,2,382H,202H,202H,3FCH,0,0,0 ; G
        dw      0,202H,202H,202H,3FEH,202H,202H,202H,0,0,0 ; H
        dw      0,0F8H,20H,20H,20H,20H,20H,0F8H,0,0,0 ; I
        dw      0,3E0H,80H,80H,80H,80H,84H,78H,0,0,0 ; J
        dw      0,202H,102H,82H,7EH,82H,102H,202H,0,0,0 ; K
        dw      0,2,2,2,2,2,2,3FEH,0,0,0 ; L
        dw      0,306H,28AH,252H,222H,202H,202H,202H,0,0,0 ; M
        dw      0,206H,20AH,212H,222H,242H,282H,302H,0,0,0 ; N
        dw      0,1FCH,202H,202H,202H,202H,202H,1FCH,0,0,0 ; O
        dw      0,1FEH,202H,202H,1FEH,2,2,2,0,0,0 ; P
        dw      0,1FCH,202H,202H,202H,282H,102H,2FCH,0,0,0 ; Q
        dw      0,1FEH,202H,202H,1FEH,82H,102H,202H,0,0,0 ; R
        dw      0,1FCH,202H,2,1FCH,200H,202H,1FCH,0,0,0 ; S
        dw      0,3FEH,20H,20H,20H,20H,20H,20H,0,0,0 ; T
        dw      0,202H,202H,202H,202H,202H,302H,2FCH,0,0,0 ; U
        dw      0,202H,202H,202H,104H,88H,50H,20H,0,0,0 ; V
        dw      0,202H,202H,202H,222H,222H,154H,88H,0,0,0 ; W
        dw      0,104H,88H,50H,20H,50H,88H,104H,0,0,0 ; X
        dw      0,202H,104H,88H,50H,20H,20H,20H,0,0,0 ; Y
        dw      0,3FEH,80H,40H,20H,10H,8,3FEH,0,0,0 ; Z
        dw      0,70H,10H,10H,10H,10H,10H,70H,0,0,0 ; [
        dw      0,4,8,10H,20H,40H,80H,100H,0,0,0 ; \
        dw      0,70H,40H,40H,40H,40H,40H,70H,0,0,0 ; ]
        dw      0,20H,70H,0A8H,124H,20H,20H,20H,0,0,0 ; ^
        dw      0,0,0,0,0,0,0,0,0,0,7FFH ; _
        dw      0,10H,20H,40H,0,0,0,0,0,0,0 ; `
        dw      0,0,0,0F8H,100H,1F8H,104H,2F8H,0,0,0 ; a
        dw      0,4,4,0FCH,104H,104H,104H,0FCH,0,0,0 ; b
        dw      0,0,0,0F8H,104H,4,4,1F8H,0,0,0 ; c
        dw      0,100H,100H,1F8H,104H,104H,104H,1F8H,0,0,0 ; d
        dw      0,0,0,0F8H,104H,1FCH,4,1F8H,0,0,0 ; e
        dw      0,20H,50H,10H,38H,10H,10H,10H,0,0,0 ; f
        dw      0,0,0,1F8H,104H,104H,104H,1F8H,100H,100H,0F8H ; g
        dw      0,4,4,0FCH,104H,104H,104H,104H,0,0,0 ; h
        dw      0,0,20H,0,20H,20H,20H,20H,0,0,0 ; i
        dw      0,0,40H,0,40H,40H,40H,40H,40H,50H,20H ; j
        dw      0,4,4,44H,24H,3CH,44H,84H,0,0,0 ; k
        dw      0,30H,20H,20H,20H,20H,20H,0F8H,0,0,0 ; l
        dw      0,0,0,1DEH,222H,222H,222H,222H,0,0,0 ; m
        dw      0,0,0,0FCH,104H,104H,104H,104H,0,0,0 ; n
        dw      0,0,0,0F8H,104H,104H,104H,0F8H,0,0,0 ; o
        dw      0,0,0,0FCH,104H,104H,104H,0FCH,4,4,4 ; p
        dw      0,0,0,1F8H,104H,104H,104H,1F8H,100H,300H,100H ; q
        dw      0,0,0,0FCH,104H,4,4,4,0,0,0 ; r
        dw      0,0,0,0F8H,4,0F8H,100H,0FCH,0,0,0 ; s
        dw      0,10H,10H,78H,10H,10H,50H,20H,0,0,0 ; t
        dw      0,0,0,84H,84H,84H,84H,178H,0,0,0 ; u
        dw      0,0,0,104H,104H,88H,50H,20H,0,0,0 ; v
        dw      0,0,0,222H,222H,222H,222H,1DCH,0,0,0 ; w
        dw      0,0,0,88H,50H,20H,50H,88H,0,0,0 ; x
        dw      0,0,0,104H,104H,104H,104H,1F8H,100H,100H,0F8H ; y
        dw      0,0,0,0F8H,40H,20H,10H,0F8H,0,0,0 ; z
        dw      0,0C0H,20H,20H,10H,20H,20H,0C0H,0,0,0 ; {
        dw      0,20H,20H,20H,20H,20H,20H,20H,0,0,0 ; |
        dw      0,18H,20H,20H,40H,20H,20H,18H,0,0,0 ; }
        dw      0,0,1CH,222H,1C0H,0,0,0,0,0,0 ; ~

DATAS   ends

;;;[jrd]GRAPH   segment public 'graph'
;;;[jrd]
;;;[jrd]screen  db      40000 dup (?)           ; area for screen
;;;[jrd]
;;;[jrd]GRAPH   ends

CODE    segment public                  ; code segment
        extrn   prtchr:near,outchr:near,cmblnk:near,poscur:near
        extrn   putmod:near,clrmod:near,beep:near, sbrk:near    ; [jrd]
        assume  cs:code,ds:datas,es:datas

; do initialization local to this module...
; Modified by [jrd] to allocate memory dynamically rather than via a static
; program segment (Graph). Allocation is paragraph aligned.

LCLYINI proc    near
        mov     ax,40000D               ; # memory (bytes) for screen [jrd]
        call    sbrk                    ; memory allocator proc in mssker
        mov     scrseg,ax               ; segment returned by DOS [jrd]
        push    es
        mov     es,scrseg               ; need to clear the memory
        mov     di,0                    ; start at zero offset
        mov     cx,20000D               ; repeat count (# words)
        xor     ax,ax                   ; fill with nulls
        rep     stosw                   ; store them. end of mod. [jrd]
        pop     es
        ret
LCLYINI endp

; We need to save the arguments to TERM where they are a little more
; accessible than in the way they were passed

ARGINI  proc    near                    ; read passed arguments
        mov     bx,argadr               ; base of argument block
        mov     al,[bx].flgs            ; get flags
        and     al,CAPT+EMHEATH+HAVTT+TRNCTL+LCLECHO+MODOFF+LNWRAP
        mov     flags,al                ; mask for allowable and save
        and     flags1,not (PRTSCR)     ; these are allowable
                                        ; (others remain).
        mov     al,[bx].prt
        cmp     al,portno               ; using same port?
        je      argin1                  ; yes, go on
        and     flags1,not inited       ; else re-init stuff
        mov     first_in,TRUE           ; graphics too...
argin1:
        mov     portno,al               ; update port number
        mov     al,[bx].cols
        mov     crt_cols,al
        mov     al,[bx].rows
        mov     crt_lins,al             ; init # of rows and cols
        mov     ax,[bx].captr
        mov     captrtn,ax              ; buffer capture routine
        mov     al,[bx].escc
        mov     esc_ch,al
        ret                             ; that's it
ARGINI  endp

; We need to generate the mode line and output it

MODLIN  proc    near                    ; turn on mode line
        push    ds
        pop     es                      ; make sure es is correct
        mov     al,esc_ch
        mov     modbuf.m_echr,' '       ; first char is initial space
        mov     modbuf.m_hlp,' '        ; goes here too.
        cmp     al,32                   ; printable?
        jnb     modl1                   ; yes, keep going
        add     al,40h                  ; made printable
        mov     modbuf.m_echr,'^'       ; note control char
        mov     modbuf.m_hlp,'^'
modl1:
        mov     modbuf.m_echr+1,al      ; fill in character
        mov     modbuf.m_hlp+1,al
        mov     bx,argadr               ; get argument block
        mov     al,[bx].baudb           ; get baud bits
        mov     si,offset unkbaud       ; assume unknown baud
        cmp     al,baudnsiz             ; too big?
        jnb     modl2                   ; yes, use default
        mov     cl,2                    ; each is 4 bytes long
        shl     al,cl
        mov     ah,0
        add     ax,offset baudn
        mov     si,ax
modl2:
        mov     cx,size m_baud          ; length of baud space
        mov     di,offset modbuf.m_baud
        rep     movsb                   ; copy in baud rate
        mov     al,[bx].parity          ; get parity code
        mov     cl,2                    ; each is 4 bytes long...
        shl     al,cl
        mov     ah,0
        add     ax,offset parnams       ; names of parity settings
        mov     si,ax
        mov     cx,4                    ; each is 4 long
        mov     di,offset modbuf.m_par
        rep     movsb
        mov     si,offset remmsg        ; Assume remote echoing.
        test    flags,lclecho           ; Is remote side echoing?
        jz      modl4                   ; Yes, keep going
        mov     si,offset lclmsg        ; Else it's local echoing.
modl4:
        mov     cx,3                    ; size of on/off
        mov     di,offset modbuf.m_echo
        rep     movsb
        mov     al,'1'
        cmp     portno,1                ; port 1?
        je      modl5                   ; yes, keep going
        mov     al,'2'
modl5:
        mov     modbuf.m_prt,al         ; fill in port number
        mov     dx,offset modbuf        ; where it is
        call    putmod
        ret
MODLIN  endp

; This is the entry point for terminal emulation

TERM    proc    near                    ; terminal emulator entry point
        mov     argadr,ax               ; save argument ptr
        push    es                      ; save caller's extra segment address
        mov     ax,seg datas
        mov     es,ax
        call    argini                  ; init options from arg address
        test    flags,EMHEATH           ; emulating heath?
        jnz     term1                   ; yes, just be yourself
        call    tek4010                 ; nope, do something smart (TEK4010)
        jmp     quit1
term1:
        test    flags1,inited           ; have we run yet?
        jz      term2                   ; no, forget this part
        call    restscr                 ; restore screen
        jmp     term3
term2:
        call    cmblnk                  ; start with it clear
term3:
        or      flags1,inited           ; remember we've run already.
        call    clrmod                  ; empty mode line
        test    flags,MODOFF            ; is mode line disabled?
        jnz     lp                      ; yes, skip it
        call    modlin                  ; turn on mode line
lp:
        call    portchr                 ; char at port?
         jnc    chkinp                  ; no, keep going
; we want to swallow any ANSI escapes that come for now
;    they are all of the form ESC [ nn ; nn ; nn ; nn a
;    where n is a numeric character, and a is a non-numeric character
        cmp     escseq,0                ; escape sequence in progress?
        jne     eat_esc_seq             ; yes
        cmp     al,ESC                  ; got an escape?
        jne     no_esc                  ; no
        mov     escseq,1                ; yes, flag it
        jmp     chkinp
eat_esc_seq:
        cmp     escseq,1                ; got [?
        jne     eat_esc_seq2            ; yes
        cmp     al,'['
        je      eat_esc_seq1
        push    ax                      ; not [, print esc and char
        mov     al,ESC
        call    outtty                  ; send the escape
        pop     ax                      ; and the following character
        mov     escseq,0                ; no escape sequence
        jmp     no_esc
eat_esc_seq1:
        mov     escseq,2                ; flag [
        jmp     chkinp
eat_esc_seq2:
        cmp     al,';'                  ; check for terminator
        je      chkinp
        cmp     al,'0'
        jl      end_esc
        cmp     al,'9'
        jg      end_esc
        jmp     chkinp                  ; no terminator, keep eating
end_esc:
        mov     escseq,0                ; end of sequence
        jmp     chkinp
no_esc:
        call    outtty                  ; print on terminal
chkinp:
        mov     ah,DCONIO               ; Get it with no checking
        mov     dl,0FFH
        int     DOS
        cmp     al,0                    ; anything there?
        je      lp                      ; no...
        cmp     al,esc_ch               ; escape character?
        je      quit                    ; yes, stop here
        call    outprt
        jmp     chkinp                  ; and keep going
quit:
        call    clrmod                  ; erase mode line
        call    savescr                 ; save screen
quit1:
        mov     al,flags
        mov     bx,argadr
        mov     [bx].flgs,al            ; update flags in arg block
        pop     es                      ; restore segment register
        ret                             ; and return to caller
TERM    endp

; Save the screen so we can restore it

SAVESCR proc    near
        mov     dx,offset rptcur
        mov     ah,PRSTR
        int     DOS
        mov     ah,CONINQ               ; input no check
        int     DOS                     ; gets the ESC
        int     DOS                     ; gets the Y
        int     DOS
        sub     al,32
        mov     tcurloc+1,al            ; this is line number
        int     DOS
        sub     al,32
        mov     tcurloc,al              ; this is column number
        mov     bx,SEG_CRTC             ; where crt controller is
        mov     es,bx
        mov     bx,OFF_CRTC
        mov     byte ptr es:[bx],12
        mov     ah,es:1[bx]
        and     ah,7                    ; only want bottom 3 bits
        mov     byte ptr es:[bx],13
        mov     al,es:1[bx]
        shl     ax,1                    ; multiply by 2 (was word address)
        mov     si,ax
        push    ds
        pop     es
        mov     ds,tscrseg
        mov     di,offset tscreen
        mov     cx,1920
        rep     movsw
        push    es
        pop     ds
        call    cmblnk                  ; let them start with a blank one
        ret                             ; and return
SAVESCR endp

; Restore screen from scrsav buffer

RESTSCR proc    near
        call    cmblnk                  ; start with a screen screen
        mov     si,offset tscreen
        mov     es,tscrseg
        xor     di,di                   ; start at start
        mov     cx,1920                 ; 1920 words to go
        rep     movsw
        mov     dx,word ptr tcurloc     ; get cursor location
        call    poscur
        ret
RESTSCR endp

; Come to here to act somewhat like a Tektronix 4010 terminal...
TEK4010 proc    near
        push    es                      ; this will be used repeatedly
        mov     es,scrseg
        cmp     first_in,FALSE          ; been here before?
        je      tek0                    ; yes
        call    clrscr                  ; be sure screen is clear
        mov     first_in,FALSE          ; flag it
tek0:
        call    set_hires               ; set to hires screen
teklp:
        cmp     full_flag,FALSE         ; page full condition
        jne     tekcki                  ; yes, I can't accept anything
        call    portchr                 ; char at port?
         jnc    tekcki                  ; no, keep going
        call    tekhandle               ; go handle the character
tekcki:
        dec     cursor_cnt              ; decrement cursor countdown
        jnz     tekcki1                 ; not ready
        call    cursor_on               ; turn on cursor
tekcki1:
        mov     ah,DCONIO               ; Get it with no checking
        mov     dl,0FFH
        int     DOS
        cmp     al,0                    ; anything there?
        je      teklp                   ; no...
        cmp     al,esc_ch               ; escape character?
        je      tekquit                 ; yes, stop here
        cmp     al,CLEAR                ; is it the clear key?
        jne     tekcki2
        call    clrscr
        jmp     tekcki1
tekcki2:
        call    outprt
        jmp     tekcki1                 ; and keep going
tekquit:
        call    reset_hires             ; reset to normal screen
        pop     es
        ret
TEK4010 endp

; Take care of an incoming character

TEKHANDLE proc  near
        call    capture                 ; in case we should
        cmp     al,GS                   ; Group Separator?
        je      tek2graf                ; ->graphics with pen up
        cmp     al,ESC                  ; Escape?
        je      tek2esc                 ; ->handle special commands
        mov     bl,escflag
        xor     bh,bh
        call    tekjump[bx]             ; Go to right routine
        mov     cursor_cnt,CURSOR_TIME  ; init cursor countdown
        ret
;
tek2graf:
        mov     visible,0               ; Pen up
        mov     escflag,4               ; Get HIY next
        mov     graph_mode,TRUE
        ret
tek2esc:
        mov     escflag,2               ; ESC handler next
        ret
TEKHANDLE endp

; TEXT mode - just put text on screen

TEKTXT  proc    near
        call    cursor_off              ; be sure this is off
        cmp     text_x,TEXT_X_MAX       ; off screen?
        jle     tektxta
        mov     text_x,0                ; to left margin
        add     text_y,RPLINE
tektxta:
        cmp     text_y,TEXT_Y_MAX
        jle     tektxtb
        call    page_full               ; page is full!
        ret                             ; lost that character, oh well...
tektxtb:
        cmp     al,DEL                  ; Is it delete?
        jne     tektxt1
        ret
tektxt1:
        cmp     al,' '                  ; Is it control?
        jl      tektxt3
        cmp     echo_supp,FALSE         ; In echoplex suppression?
        jne     tektxt2                 ; Yes, don't print it
        call    character               ; Output it
        call    inc_char
tektxt2:
        ret
tektxt3:
        cmp     al,BELL
        jne     tektxt4
        call    beep
        mov     echo_supp,FALSE         ; Clear suppression
        ret
tektxt4:
        cmp     al,BS
        jne     tektxt6
        sub     text_x,CPCHAR           ; back up one
        cmp     text_x,0
        jge     tektxt5                 ; ok
        mov     text_x,R_MARG           ; right margin
        sub     text_y,RPLINE           ; back one line
        cmp     text_y,0                ; top?
        jge     tektxt5
        mov     text_y,0                ; top of screen
tektxt5:
        mov     echo_supp,FALSE         ; Clear suppression
        ret
tektxt6:
        cmp     al,TAB
        jne     tektxt7
        call    inc_char
        mov     echo_supp,FALSE         ; Clear suppression
        ret
tektxt7:
        cmp     al,LF                   ; Line feed?
        jne     tektxt9
        add     text_y,RPLINE           ; Down one line
        cmp     text_y,TEXT_Y_MAX       ; Past end?
        jle     tektxt8
        call    page_full               ; can't go any further!
        ret
tektxt8:
        mov     echo_supp,FALSE         ; Clear suppression
        ret
tektxt9:
        cmp     al,VTAB
        jne     tektxt11
        sub     text_y,RPLINE           ; Up one line
        cmp     text_y,0                ; Past top?
        jge     tektxt10
        mov     text_y,0
tektxt10:
        mov     echo_supp,FALSE         ; Clear suppression
        ret
tektxt11:
        cmp     al,CR                   ; It is return?
        jne     tektxt12
        mov     text_x,0                ; to left margin
        mov     echo_supp,FALSE         ; Clear suppression
        ret
tektxt12:
        ret
TEKTXT  endp

; Move the text position by one char, perform auto wrap, and
; check for page full

INC_CHAR proc   near
        add     text_x,CPCHAR           ; Move to next column
        cmp     text_x,TEXT_X_MAX       ; Past end?
        jle     inc_char0
        mov     text_x,0                ; Left margin
        add     text_y,RPLINE
        cmp     text_y,TEXT_Y_MAX       ; Past end?
        jle     inc_char0
        call    page_full               ; Take no more!
inc_char0:
        ret
INC_CHAR endp

; ESC mode - check what to do

TEKESC  proc    near
        cmp     al,FF                   ; Form feed?
        jne     tekesc1
        call    clrscr
        mov     echo_supp,FALSE         ; Clear suppression
        jmp     tekescq
tekesc1:
        cmp     al,SUB                  ; Control-Z?
        jne     tekesc2
        mov     escflag,0               ; Just in case
        mov     echo_supp,TRUE          ; echoplex suppression
        call    tekcrs                  ; Go to cross hairs
        ret                             ; Last char does its thing
tekesc2:
        cmp     al,ETB                  ; Make copy?
        jne     tekesc2a
        mov     echo_supp,FALSE         ; Clear suppression
        jmp     tekescq
tekesc2a:
        cmp     al,ENQ                  ; enquire?
        jne     tekesc3
        mov     echo_supp,TRUE          ; echoplex suppression
        call    send_stat
        jmp     tekescq                 ; do nothing for now ***
tekesc3:
        call    tektxt                  ; It's just text...
tekescq:
        mov     escflag,0               ; Now in full text mode
        mov     graph_mode,FALSE
        ret
TEKESC  endp

; Get coordinates  escflag=4->expect hiy, escflag=6->expect hix

TEKHIY  proc    near
tekhix:
        call    cursor_off              ; make sure it is off
        cmp     al,CR                   ; should we exit?
        jne     tekhi1
        mov     cur_x,0                 ; go to left margin
        mov     echo_supp,FALSE         ; Clear suppression
        jmp     go2text
tekhi1:
        cmp     al,US                   ; another exit?
        jne     tekhi2
        mov     echo_supp,FALSE         ; Clear suppression
        jmp     go2text
tekhi2:
        cmp     al,FF
        jne     tekhi3
        call    clrscr
        mov     echo_supp,FALSE         ; Clear suppression
        jmp     go2text
tekhi3:
        cmp     echo_supp,FALSE         ; In suppression
        jne     tekhi4                  ; Yes, ignore this...
        cmp     al,20H                  ; control character?
        jl      tekhi4
        cmp     al,40H
        jl      tekhi5                  ; 20-3F are HIX or HIY
        cmp     al,60H
        jl      tekhi7                  ; 40-5F are LOX
;  Get to here must be 60-7F -> LOY
        mov     ah,loy                  ; copy old loy
        mov     lsb,ah                  ; to lsb (in case 4014)
        and     al,1FH                  ; low 5 bits
        mov     loy,al
        cmp     escflag,6               ; 2nd in a row?
        je      tekhi4                  ; then previous was lsb anyway
        mov     lsb,0                   ; clear lsb
        mov     escflag,6               ; expect HIX next
tekhi4:
        ret
; Get either HIX or HIY depending on escflag
tekhi5:
        and     ax,1FH
        mov     cl,5
        shl     ax,cl                   ; multiply by 32
        cmp     escflag,4               ; looking for HIY?
        jne     tekhi6                  ; no, HIX
        mov     hiy,ax
        ret                             ; leave escflag=4
tekhi6:
        mov     hix,ax
        mov     escflag,4               ; look for HIY next
        ret
; Get LOX and do the movement
tekhi7:
        and     al,1FH
        mov     lox,al
        mov     ax,hix
        or      al,lox
        mov     cur_x,ax
        mov     dx,hiy
        or      dl,loy
        mov     cur_y,dx
        call    tek2victor              ; convert the coords
        mov     endpt,ax
        mov     endpt+2,dx              ; save them
        cmp     visible,0
        je      tekhi8
        call    line                    ; draw the line
tekhi8:
        mov     visible,1
        mov     ax,endpt
        mov     start,ax
        mov     ax,endpt+2
        mov     start+2,ax              ; end is now start
        mov     escflag,4               ; want HIY next
        ret
;
go2text:
        mov     escflag,0
        mov     graph_mode,FALSE
        mov     ax,cur_x
        mov     dx,cur_y
        call    tek2victor
        mov     text_x,ax
        sub     dx,10                   ; mov to upper left corner
        cmp     dx,0
        jge     go2text1
        xor     dx,dx
go2text1:
        mov     text_y,dx
        ret
TEKHIY  endp

; Go to CURSOR mode

TEKCRS  proc    near
        call    cursor_off
        mov     combine,offset pixel_xor
        mov     trmesc,FALSE
        mov     prtesc,FALSE
tekcrs_dr:
        mov     ax,cur_x                ; get x
        sub     ax,CUR_LEN              ; minus a little
        cmp     ax,0
        jge     tekcrs_dr1
        mov     ax,0
tekcrs_dr1:
        mov     dx,cur_y
        call    tek2victor
        mov     crs_hor,ax
        mov     crs_hor+4,dx
        mov     ax,cur_x
        add     ax,CUR_LEN              ; add a little
        cmp     ax,TEK_X_MAX
        jle     tekcrs_dr2
        mov     ax,TEK_X_MAX
tekcrs_dr2:
        mov     dx,cur_y
        call    tek2victor
        mov     crs_hor+2,ax
        mov     dx,cur_y                ; now y's
        sub     dx,CUR_LEN              ; minus a little
        cmp     dx,0
        jge     tekcrs_dr3
        mov     dx,0
tekcrs_dr3:
        mov     ax,cur_x
        call    tek2victor
        mov     crs_ver,dx
        mov     crs_ver+4,ax
        mov     dx,cur_y
        add     dx,CUR_LEN              ; plus a little
        cmp     dx,TEK_Y_MAX
        jle     tekcrs_dr4
        mov     dx,TEK_Y_MAX
tekcrs_dr4:
        mov     ax,cur_x
        call    tek2victor
        mov     crs_ver+2,dx
        call    draw_cursor             ; put it on
tekcrs_lp:
        mov     dl,0FFH
        mov     ah,DCONIO               ; get character
        int     DOS
        cmp     al,0                    ; anything?
        jne     tekcrs_hnd              ; take care of it
        call    portchr                 ; check port character
        jnc     tekcrs_lp               ; nothing there
        cmp     prtesc,FALSE            ; received escape?
        je      tekcrs_lp1              ; no
        mov     prtesc,FALSE
        cmp     al,FF
        je      tekcrs_abt
        cmp     al,ETB
        je      tekcrs_abt
        cmp     al,ENQ
        jne     tekcrs_lp
        call    send_stat               ; send status
        jmp     tekcrs_lp
tekcrs_lp1:
        cmp     al,BELL                 ; check for control and clear...
        je      tekcrs_abt
        cmp     al,BS
        je      tekcrs_abt
        cmp     al,CR
        je      tekcrs_abt
        cmp     al,TAB
        je      tekcrs_abt
        cmp     al,LF
        je      tekcrs_abt
        cmp     al,US
        je      tekcrs_abt
        cmp     al,ESC
        jne     tekcrs_lp               ; try for more
        mov     prtesc,TRUE
        jmp     tekcrs_lp
tekcrs_abt:
        mov     echo_supp,FALSE         ; clear echo suppression
        mov     escflag,0               ; and text mode
        jmp     tekcrs_xt               ; and leave
;
tekcrs_hnd:
        cmp     trmesc,FALSE            ; received escapes yet?
        jne     tekcrs_hnd2
        cmp     al,ESC                  ; escape character?
        je      tekcrs_hnd1
        jmp     tekcrs_done             ; finished
tekcrs_hnd1:
        mov     trmesc,TRUE             ; flag it
        jmp     tekcrs_lp
tekcrs_hnd2:
        cmp     al,'1'                  ; change step?
        jge     tekcrs_hnd2z
        jmp     tekcrs_done
tekcrs_hnd2z:
        cmp     al,'9'
        jle     tekcrs_hnd3
        cmp     al,'A'
        jne     tekcrs_hnd2a
        mov     ax,cur_stp
        add     cur_y,ax
        jmp     tekcrs_und              ; remove old and redraw
tekcrs_hnd2a:
        cmp     al,'B'
        jne     tekcrs_hnd2b
        mov     ax,cur_stp
        sub     cur_y,ax
        jmp     tekcrs_und              ; remove old and redraw
tekcrs_hnd2b:
        cmp     al,'C'
        jne     tekcrs_hnd2c
        mov     ax,cur_stp
        add     cur_x,ax
        jmp     tekcrs_und
tekcrs_hnd2c:
        cmp     al,'D'
        jne     tekcrs_hnd2d
        mov     ax,cur_stp
        sub     cur_x,ax
        jmp     tekcrs_und
tekcrs_hnd2d:
        jmp     tekcrs_done             ; its the one to send
tekcrs_hnd3:
        sub     al,'0'                  ; convert to number
        xor     ah,ah
        mov     cur_stp,ax              ; new step value
        mov     trmesc,FALSE
        jmp     tekcrs_lp
tekcrs_und:
        cmp     cur_x,0                 ; check for validity
        jge     tekcrs_und1
        mov     cur_x,0
        jmp     tekcrs_und2
tekcrs_und1:
        cmp     cur_x,TEK_X_MAX
        jle     tekcrs_und2
        mov     cur_x,TEK_X_MAX
tekcrs_und2:
        cmp     cur_y,0
        jge     tekcrs_und3
        mov     cur_y,0
        jmp     tekcrs_und4
tekcrs_und3:
        cmp     cur_y,TEK_Y_MAX
        jle     tekcrs_und4
        mov     cur_y,TEK_Y_MAX
tekcrs_und4:
        call    draw_cursor             ; remove the cursor
        mov     trmesc,FALSE
        jmp     tekcrs_dr               ; and draw new one
tekcrs_done:
        push    cur_y                   ; want current coords
        push    cur_x                   ; for sending
        call    send_coord              ; send character and coords
tekcrs_xt:
        call    draw_cursor             ; remove the cursor
        mov     ax,cur_x
        mov     dx,cur_y                ; need to set start point
        call    tek2victor
        mov     start,ax
        mov     start+2,dx
        mov     text_x,ax               ; set text point also
        sub     dx,10                   ; move to upper left corner
        cmp     dx,0
        jge     tekcrs_xt1
        xor     dx,dx
tekcrs_xt1:
        mov     text_y,dx
        mov     combine,offset pixel_or
        ret
TEKCRS  endp

; DRAW CURSOR expects to have the appropriate endpoints in CRS_HOR for
; the horizontal line (x1,x2,y) and CRS_VER for the vertical line (y1,y2,x)

DRAW_CURSOR proc near
        mov     ax,crs_hor
        mov     start,ax
        mov     ax,crs_hor+4
        mov     start+2,ax
        mov     endpt+2,ax
        mov     ax,crs_hor+2
        mov     endpt,ax
        call    line                    ; draw horizontal line
        mov     ax,crs_ver
        mov     start+2,ax
        mov     ax,crs_ver+4
        mov     start,ax
        mov     endpt,ax
        mov     ax,crs_ver+2
        mov     endpt+2,ax
        call    line                    ; draw vertical line
        ret
DRAW_CURSOR endp

; Convert TEK coords to VICTOR coords
;  entry:  ax=x, dx=y (tek)
;  exit:   ax=x, dx=y (victor)

TEK2VICTOR proc near
        push    dx                      ; save y for now
        mov     bx,X_MAX
        mul     bx
        mov     bx,TEK_X_MAX
        div     bx
        cmp     dx,TEK_X_MAX/2          ; need to round up?
        jl      tek2vic1
        inc     ax
tek2vic1:
        pop     dx
        push    ax                      ; save x now
        mov     ax,dx
        mov     bx,Y_MAX
        mul     bx
        mov     bx,TEK_Y_MAX
        div     bx
        cmp     dx,TEK_Y_MAX/2          ; need to round up?
        jl      tek2vic2
        inc     ax
tek2vic2:
        sub     ax,Y_MAX                ; need to swap it
        neg     ax
        mov     dx,ax
        pop     ax
        ret
TEK2VICTOR endp

; Set the CRT to hires mode

SET_HIRES proc  near
        push    es
        call    crt_lo_inten            ; so you don't see so much jump
        mov     ah,DCONIO
        mov     dl,27
        int     DOS
        mov     dl,'E'
        int     DOS                     ; let's start with a clear screen
        push    ds
        pop     es
        mov     ax,0F000H               ; this is status line
        mov     ds,ax
        mov     di,offset status_line   ; where to put it
        mov     si,3840
        cld
        mov     cx,80                   ; 80 words
        rep     movsw
        push    es
        pop     ds                      ; restore ds
        mov     bx,0E800H               ; CRT controller segment
        mov     es,bx
        mov     word ptr es:0,03A00H    ; reg 0
        mov     word ptr es:0,03201H
        mov     word ptr es:0,03402H
        mov     word ptr es:0,0C903H
        mov     word ptr es:0,0200AH    ; no cursor
        xor     ah,ah                   ; assume using lower bank of memory
        test    scrseg,1000H            ; really?
        jz      set_hires1
        mov     ah,10H
set_hires1:
        or      ah,20H
        mov     al,0CH                  ; reg 12
        mov     es:0,ax
        mov     word ptr es:0,0000DH
        mov     word ptr es:0,0000EH
        mov     word ptr es:0,0000FH
        mov     cx,4e2H                 ; 1250 locations to set
        mov     ax,scrseg               ; where screen is
        shr     ax,1                    ; /2
        mov     di,0F000H               ; in screen ram
        mov     es,di
        xor     di,di
set_hires2:
        stosw                           ; set one
        inc     ax                      ; next one
        loop    set_hires2
        call    crt_hi_inten
        pop     es
        ret
SET_HIRES endp

; Reset the CRT to lores mode

RESET_HIRES proc near
        push    es
        call    crt_lo_inten            ; to minimize jump
        mov     bx,0E800H               ; segment for CRT controller
        mov     es,bx
        mov     word ptr es:0,05C00H    ; reg 0
        mov     word ptr es:0,05001H
        mov     word ptr es:0,05102H
        mov     word ptr es:0,0CF03H
        mov     word ptr es:0,0000AH    ; steady, block cursor
        mov     word ptr es:0,0000CH
        mov     word ptr es:0,0000DH
        mov     word ptr es:0,0000EH
        mov     word ptr es:0,0000FH
        mov     ah,DCONIO
        mov     dl,27
        int     DOS
        mov     dl,'E'
        int     DOS                     ; insure screen is clear
        mov     ax,0F000H               ; restore status line
        mov     es,ax
        mov     si,offset status_line
        mov     di,3840
        cld
        mov     cx,80                   ; one line
        rep     movsw
        call    crt_hi_inten
        pop     es
        ret
RESET_HIRES endp

; Set to lo intensity

CRT_LO_INTEN proc near
        mov     bx,0E804H               ; CRT controller segment
        mov     es,bx
        mov     al,es:0                 ; get current setting
        mov     ah,al                   ; save it
        and     al,1CH
        mov     intens,al               ; store it
        mov     al,ah
        and     al,0E3H                 ; zero intensity
        mov     es:0,al
        ret
CRT_LO_INTEN endp

; Set to hi intensity

CRT_HI_INTEN proc near
        mov     bx,0E804H               ; Crt controller segment
        mov     es,bx
        mov     al,es:0                 ; Get current setting
        and     al,0E3H                 ; Clear intensity
        or      al,intens               ; Set to correct value
        mov     es:0,al
        ret
CRT_HI_INTEN endp

; Clear the hires screen area

CLRSCR  proc    near
        les     di,dword ptr scrloc     ; get right location
        cld                             ; increment
        mov     cx,20000                ; 40000 bytes
        mov     ax,0
        rep     stosw                   ; doing it
        mov     cur_x,0                 ; set to home position
        mov     cur_y,780
        mov     hix,0
        mov     hiy,0
        mov     lox,0
        mov     loy,0
        mov     lsb,0
        mov     start,0
        mov     start+2,0
        mov     text_x,0
        mov     text_y,0
        mov     full_flag,FALSE         ; page isn't full
        mov     cursor,FALSE            ; cursor isn't on
        mov     cursor_cnt,CURSOR_TIME  ; set up cursor countdown
        ret
CLRSCR  endp

; Put the character in al on the screen at location pointed at by
; text_x,text_y.  Use combination routine pointed at by t_combine

CHARACTER proc  near
        cmp     al,' '                  ; is it a space?
        jne     character1              ; no
        ret                             ; just return...
character1:
        and     al,07FH                 ; Be sure it is in range...
        cmp     al,07FH                 ; Is it delete?
        jl      character1a
        ret                             ; Don't do it...
character1a:
        push    ax                      ; save the character
        mov     ax,text_y
        mov     dx,text_x
        call    convert_loc             ; get to where we are going
        les     di,dword ptr scrloc     ; get screen location
        add     si,di                   ; now we are in the right place
        mov     cx,text_y
        and     cx,0FH                  ; need mod(y,16)
        sub     cx,16
        neg     cx                      ; how many to do in this section
        cmp     cx,RPLINE               ; more than one line?
        jle     character1b
        mov     cx,RPLINE               ; make it just one line
character1b:
        mov     temp,cx                 ; need to remember this
        pop     ax                      ; get back the character
        sub     ax,'!'                  ; start with exclamation mark
        xor     ah,ah
        mov     dl,RPLINE               ; number of entries per character
        shl     dl,1                    ; they are word entries
        mul     dl
        mov     di,ax                   ; where to get bit patterns
        mov     dx,cx                   ; how many to do
        mov     cx,bx                   ; this is the number to shift
        or      cx,cx                   ; look at it
        jnz     character1c
        jmp     character8              ; no shifts necessary
character1c:
        cmp     cx,5                    ; this goes within one word
        jg      character4              ; spans word boundaries
character2:
        mov     bx,font[di]
        or      bx,bx                   ; is it zero?
        jz      character3
;;;[jrd]        cmp     si,offset screen        ; too low?
        cmp     si,0                    ; too low? (starts at 0 offset) [jrd]
        jb      character3
;;;[jrd]        cmp     si,offset screen+39999  ; too high?
        cmp     si,39999                ; too high? [jrd]
        jae     character3
        shl     bx,cl                   ; shift to right place
        call    t_combine
character3:
        inc     di
        inc     di
        inc     si
        inc     si
        dec     dx                      ; done one row
        jnz     character2
        add     si,1568                 ; go to top of next major row
        mov     dx,RPLINE               ; how many we needed to do
        sub     dx,temp                 ; minus how many done
        mov     temp,RPLINE             ; claim we have done them all
        jg      character2              ; do the rest
        jmp     character10
character4:
        sub     cx,16                   ; convert to right shift
        neg     cx
        mov     ax,0FFFFH               ; need to build mask
        shl     ax,cl
        not     ax
        mov     c_mask,ax
character5:
        mov     bx,font[di]
        or      bx,bx                   ; zero?
        jz      character5a
;;;[jrd]        cmp     si,offset screen        ; too low?
        cmp     si,0                    ; too low? (starts at 0 offset) [jrd]
        jb      character5a
;;;[jrd]        cmp     si,offset screen+39999  ; too high?
        cmp     si,39999                ; too high? [jrd]
        jae     character5a
        jmp     character6
character5a:
        inc     si
        inc     si
        jmp     character7
character6:
        and     bx,c_mask               ; mask upper bits
        ror     bx,cl                   ; get first batch
        call    t_combine
        add     si,32                   ; next word column
        mov     bx,font[di]
        shr     bx,cl
        call    t_combine
        sub     si,30                   ; back to right column, plus 2
character7:
        inc     di
        inc     di
        dec     dx                      ; done one row
        jnz     character5
        add     si,1568                 ; go to top of next major row
        mov     dx,RPLINE               ; how many we needed to do
        sub     dx,temp                 ; minus how many done
        mov     temp,RPLINE             ; claim we have done them all
        jg      character5              ; do the rest
        jmp     character10
character8:
        mov     bx,font[di]
        or      bx,bx                   ; is it zero?
        jz      character9
;;;[jrd]        cmp     si,offset screen        ; too low?
        cmp     si,0                    ; too low? (starts at 0 offset) [jrd]
        jb      character9
;;;[jrd]        cmp     si,offset screen+39999  ; too high?
        cmp     si,39999                ; too high? [jrd]
        jae     character9
        call    t_combine
character9:
        inc     di
        inc     di
        inc     si
        inc     si
        dec     dx                      ; done one row
        jnz     character8
        add     si,1568                 ; go to top of next major row
        mov     dx,RPLINE               ; how many we needed to do
        sub     dx,temp                 ; minus how many done
        mov     temp,RPLINE             ; claim we have done them all
        jg      character8              ; do the rest
        jmp     character10
character10:
        ret
CHARACTER endp

; Cursor on - turn on the cursor if it isn't already on

CURSOR_ON proc  near
        cmp     cursor,FALSE
        jne     c_on_end                ; already on
        push    ax                      ; save this just in case
        mov     t_combine,offset word_xor ; set combine rule
        mov     ax,CURSOR_CHR
        call    character               ; print without advancing
        mov     t_combine,offset word_or ; set combine rule
        mov     cursor,TRUE             ; flag it
        pop     ax
c_on_end:
        ret
CURSOR_ON endp

; Cursor off - erase the cursor if it is there

CURSOR_OFF proc near
        cmp     cursor,FALSE
        je      c_off_end               ; already off
        push    ax
        mov     t_combine,offset word_xor ; set combine rule
        mov     ax,CURSOR_CHR
        call    character               ; print without advancing
        mov     t_combine,offset word_or ; set combine rule
        mov     cursor,FALSE            ; flag it
        pop     ax
c_off_end:
        ret
CURSOR_OFF endp

; Notify the user that the page is full, and set flag to wait for
; him to clear it.

PAGE_FULL proc  near
        mov     full_flag,TRUE          ; page is full!
        call    beep                    ; make some noise about it
        les     di,dword ptr scrloc     ; get screen location
        add     di,38424                ; lower left corner
        mov     ax,0FFFFH               ; set them all!
        or      es:[di],ax
        inc     di
        inc     di
        or      es:[di],ax
        inc     di
        inc     di
        or      es:[di],ax
        inc     di
        inc     di
        or      es:[di],ax
        ret
PAGE_FULL endp

; Connect points: start=startx, start+2=starty, endpt=endx, endpt+2=endy
;  Uses combination routine pointed at by combine

LINE    proc    near
        mov     dx,start                ; start x
        mov     ax,endpt                ; end x
        mov     x_inc,1                 ; assume incrementing
        sub     ax,dx
        jnb     line1                   ; correct
        neg     x_inc
        neg     ax
line1:
        mov     delta_x,ax              ; save delta
        mov     dx,start+2              ; start y
        mov     ax,endpt+2              ; end y
        mov     y_inc,1                 ; assume incrementing
        sub     ax,dx
        jnb     line2                   ; correct
        neg     y_inc
        neg     ax
line2:
        mov     delta_y,ax              ; save delta
        les     di,dword ptr scrloc     ; point at bit map region
        mov     dx,start
        mov     ax,start+2
        call    set_pixel               ; set start point
        mov     ax,delta_y
        cmp     ax,delta_x              ; which should we step on
        ja      line_y
;
line_x:
        mov     cx,delta_x              ; number of steps
        jcxz    line_x_done             ; nothing to do
        mov     ax,cx
        shr     ax,1                    ; delta_x/2
        mov     part_accum,ax
line_x_loop:
        mov     ax,x_inc
        add     start,ax
        mov     ax,delta_y
        sub     part_accum,ax
        jge     line_x_ok
        mov     ax,y_inc
        add     start+2,ax
        mov     ax,delta_x
        add     part_accum,ax
line_x_ok:
        mov     dx,start
        mov     ax,start+2
        call    set_pixel
        loop    line_x_loop
line_x_done:
        ret
;
line_y:
        mov     cx,delta_y              ; number of steps
        jcxz    line_y_done             ; nothing to do
        mov     ax,cx
        shr     ax,1                    ; delta_y/2
        mov     part_accum,ax
line_y_loop:
        mov     ax,y_inc
        add     start+2,ax
        mov     ax,delta_x
        sub     part_accum,ax
        jge     line_y_ok
        mov     ax,x_inc
        add     start,ax
        mov     ax,delta_y
        add     part_accum,ax
line_y_ok:
        mov     dx,start
        mov     ax,start+2
        call    set_pixel
        loop    line_y_loop
line_y_done:
        ret
LINE    endp

; Set pixel at location dx,ax

SET_PIXEL proc  near
        cmp     dx,X_MAX
        ja      set_range
        cmp     ax,Y_MAX
        ja      set_range
        call    convert_loc
        cmp     bx,8                    ; top byte?
        jb      set_noinc               ; no
        inc     si
        sub     bx,8
set_noinc:
        add     si,di                   ; correct offset to segment
        mov     bl,bit_mask[bx]
        call    combine
        ret
set_range:
        pop     bx                      ; pop one return address
        ret                             ; do nothing if off the screen
SET_PIXEL endp

; Convert x and y to word location and word bit number
;  entry: dx=x, ax=y, exit: si=byte number, bx=bit number

CONVERT_LOC proc near
        mov     si,ax
        and     si,0FH                  ; mod(y,16)
        mov     bx,ax
        and     bx,0FFF0H               ; 16*int(y/16)
        shl     bx,1                    ; *2 (need 50 times)
        add     si,bx                   ; that's 2
        shl     bx,1                    ; *4
        shl     bx,1                    ; *8
        shl     bx,1                    ; *16
        add     si,bx                   ; that's 18
        shl     bx,1                    ; *32
        add     si,bx                   ; that's 50
        mov     bx,dx
        and     bx,0FFF0H               ; 16*int(x/16)
        add     si,bx
        shl     si,1                    ; byte address
        mov     bx,dx
        and     bx,0FH                  ; mod(x,16)
        ret
CONVERT_LOC endp

; Or the mask in bl into byte at es:[si]

PIXEL_OR proc   near
        or      es:[si],bl
        ret
PIXEL_OR endp

; Exclusive-or mask in bl into byte at es:[si]

PIXEL_XOR proc  near
        xor     es:[si],bl
        ret
PIXEL_XOR endp

; Or the word in bx into word at es:[si]

WORD_OR proc    near
        or      es:[si],bx
        ret
WORD_OR endp

; Exclusive-or the word in bx into word at es:[si]

WORD_XOR proc   near
        xor     es:[si],bx
        ret
WORD_XOR endp

; Send the status out the back

SEND_STAT proc  near
        cmp     graph_mode,FALSE        ; in graph mode?
        je      send_stat1              ; No
        push    cur_y                   ; push current point, y first
        push    cur_x                   ; then x
        mov     al,39H                  ; bit 7=0, bit 6=1, bit 5=1 (no hcopy)
                                        ; bit 4=1 (ready for vector)
                                        ; bit 3=0 (graph mode)
                                        ; bit 2=0 (margin 0), bit 1=1
        call    send_coord              ; send it out
        ret
;
send_stat1:
        mov     ax,text_y               ; get current point
        add     ax,10                   ; move to lower left corner
        sub     ax,Y_MAX                ; need to swap it
        neg     ax
        mov     bx,TEK_Y_MAX            ; convert to tek coords
        mul     bx
        mov     bx,Y_MAX
        div     bx
        cmp     dx,Y_MAX/2              ; need to round up?
        jl      send_stat2
        inc     ax
send_stat2:
        cmp     ax,TEK_Y_MAX            ; up too far?
        jbe     send_stat3              ; okay
        mov     ax,TEK_Y_MAX
send_stat3:
        push    ax                      ; save y
        mov     ax,text_x
        mov     bx,TEK_X_MAX            ; convert to tek coords
        mul     bx
        mov     bx,X_MAX
        div     bx
        cmp     dx,X_MAX/2              ; need to round up?
        jl      send_stat4
        inc     ax
send_stat4:
        cmp     ax,TEK_X_MAX            ; up too far?
        jbe     send_stat5              ; okay
        mov     ax,TEK_X_MAX
send_stat5:
        push    ax                      ; save x
        mov     al,3DH                  ; bit 7=0, bit 6=1, bit 5=1 (no hcopy)
                                        ; bit 4=1 (ready for vector)
                                        ; bit 3=1 (not graph mode)
                                        ; bit 2=0 (margin 0), bit 1=1
        call    send_coord              ; send it out
        ret
SEND_STAT endp

; Send the byte currently in the al register out the port, then follow
; it by the coordinates - x is the first on the stack, y is the second
; on the stack (i.e., x was pushed last, and popped first)

SEND_COORD proc near
        call    outprt                  ; send byte in al
        pop     cx                      ; this is the return address
        pop     ax                      ; this is x coord
        pop     bx                      ; this is y coord
        push    cx                      ; return back on
        push    bx                      ; y back on
        push    ax                      ; x back on
        mov     cl,5                    ; shift to hix
        shr     ax,cl
        and     al,31                   ; keep 5 bits
        or      al,32                   ; this is hix now
        call    outprt
        pop     ax                      ; x again
        and     al,31
        or      al,64                   ; this is lox now
        call    outprt
        pop     ax                      ; get y coordinate
        push    ax                      ; save it again for a flash
        mov     cl,5                    ; shift to hiy
        shr     ax,cl
        and     al,31                   ; keep 5 bits
        or      al,32                   ; this is hiy now
        call    outprt
        pop     ax                      ; y again
        and     al,31
        or      al,96                   ; this is loy now
        call    outprt
;  Now for the termination string - use CR,EOT - this is the default for
;  the 4051 microcomputer which is supposed to look like a 4012 - I hope
;  they know what they are doing...
        mov     al,13
        call    outprt
        mov     al,4
        call    outprt
        ret
SEND_COORD endp

; Send the character in al out to the serial port
; Handle echoing also...

OUTPRT  proc    near
        test    flags,LCLECHO           ; echoing?
        jz      outpr3                  ; no, forget it
        push    ax                      ; save char
        test    flags,EMHEATH           ; emulating heath?
        jnz     outpr1                  ; yes, just be yourself
        cmp     full_flag,FALSE         ; page full?
        jne     outpr2                  ; forget this
        call    tekhandle               ; do the job in a smart way
        jmp     outpr2
outpr1:
        call    outtty                  ; print it
outpr2:
        pop     ax                      ; restore
outpr3:
        mov     ah,al                   ; this is where outchr expects it
        call    outchr                  ; output to the port
         nop
         nop
         nop                            ; skip returns...
        ret
OUTPRT  endp

; Get a character from the serial port in al
; returns with carry on if a character is available

PORTCHR proc    near
        call    prtchr                  ; character at port?
         jmp    short portc1            ; yes, go handle
        nop                             ; skip return is stupid...
        clc                             ; no carry -> no character
        ret                             ; and return...
portc1:
        and     al,7fh                  ; we don't worry about parity here
        stc                             ; have a character
        ret                             ; and return
PORTCHR endp

; Put the character in al to the screen

OUTTTY  proc    near
        call    capture
        mov     dl,al
        mov     ah,DCONIO               ; no checking!!
        int     DOS                     ; else let dos print char
        ret                             ; and return
OUTTTY  endp

; Capture char in al to a file if we are supposed to

CAPTURE proc    near
        test    flags,CAPT              ; capturing output?
        jz      nocap                   ; no, forget this part
        push    ax                      ; save char
        call    captrtn                 ; give it captured character
        pop     ax                      ; restore character and keep going
nocap:
        test    flags1,PRTSCR           ; should we be printing?
        jz      noprt                   ; no, keep going
        push    ax
        mov     ah,LSTOUT
        mov     dl,al                   ; put character here for dos...
        int     DOS
        pop     ax
noprt:
        ret
CAPTURE endp

CODE    ends

        end
