        NAME msyibm
; File MSYIBM.ASM
; edit history:
; Last edit: 5 Jan 1988
; 5 Jan 1988 Restore cursor codes broken by Tek code additions. [jrd]
; 1 Jan 1988 version 2.30
; 24 Dec 1987 Restore startup screen attributes at Kermit prompts. [jrd]
; 21 Dec 1987 Fix memory size sign problem for >640K systems. From Edgar Butt
; 4 Dec 1987 cleanup mode switching, add more Video 7 material. [jrd]
; 8 Nov 1987 Add EGA mode switching, from Terry Kennedy.
; 1 Nov 1987 Add support for Tektronix, based on work by Brian Holley. [jrd]
; 13 Oct 1987 Revise memory allocation sequence to avoid small holes. [jrd]
; 2 Oct 1987 Make log file character width match Set Display but 8 bits when
;  debugging. [jrd]
; 12 Sept 1987 clarify sequence of translation and 8 bit display. [jrd]
; 27 Aug 1987 Do Translation before logging. [jrd]
; 18 Aug 1987 Change ESC to escape for MASM 4.5+ [jrd]
; 28 July 1987 Fix scron problem in screen save. [jrd]
; 16 June 1987 Remove global byte jwait (wait for vertical retrace), embedd
;  code for proc scrwait in proc scroff. Replace calls for scrwait with
;  calls to scron/scroff. Thanks to Dave Tweten (dt). [jrd]
; 11 June 1987 Add control of automatic screen roll back when new characters
;  are to be displayed; default is off (no roll back). [jrd]
; 8 June 1987 Add keypad application mode tests to emit single chars. [jrd]
; 10 May 1987 Move input translation into terminal emulator, leave copy
;  here for terminal type None, use mszibm byte anspflg to sense print
;  screen is active, print translated characters but don't translate if
;  debugging is active. [jrd]
; 28 March 1987 Make low_rgt screen coord word a global parameter.
;  Add support for variable length screens and cursor size changes with
;  EGA boards. Tests ok with 25, 35, 43, 50 lines with &/without MS Windows.
;  EGA Memory locations 40:84H and 40:87H are used in this process.
;  Use savadr dw as place to save screen: usually screen page 1 if screen
;  dimensions are non-standard (80x25), else memory buffer scrsav. [jrd]
; 21 March 1987 Translate arriving Connect mode chars via table rxtable. [jrd]
;  Add 132 Column support for Tseng Labs EVA board via procedure chgdsp,
;  add restore scrolled screen before writing to it. From David L. Knoell [dlk]
; Modify msy and msz to use variable screen length and widths. [dlk] and [jrd]
; 17 March 1987 Reduce screen roll back buffer to half the memory to do the
;  same number of screens. [jrd]
; 12 Jan 1987 Add keyboard translator, remove older code. [jrd]
; 1 Oct 1986 Version 2.29a

        public  term, lclyini                           ; entry points
        public  prtbout, prtnout, csrtype, scrmod, scrseg, scrsync
        public  scroff, scron, atsclr, vtscru, vtscrd, scrloc, trnmod, telmsy
        public  chgdsp, vtroll, crt_lins, crt_cols, getflgs, tv_mode
                        ; action verb procedures for keyboard translator
        public  uparrw, dnarrw, rtarr, lfarr, pf1, pf2, pf3, pf4
        public  kp0, kp1, kp2, kp3, kp4, kp5, kp6, kp7, kp8, kp9
        public  kpminus, kpcoma, kpenter, kpdot, chrout, cstatus, cquit
        public  cquery, dmpscn, vtans52, vtinit, dnwpg, upwpg, endwnd, homwnd
        public  upone, dnone, trnprs, dumpscr, modlin, modwrt, snull
        public  klogon, klogof, cdos, chang

        public  vtemu, crt_mode, scbattr, refresh, low_rgt  ; data
        public  savescr, restscr

        include mssdef.h

; some definitions
; hardware
crt_status equ  3dah                    ; CGA crt status port
disp_enb equ    8                       ; CGA display enable bit
crtmset equ     3D8H                    ; CGA CRT mode set port.
screen  equ     10h                     ; bios screen interrupt
biostty equ     0eh                     ; Bios screen tty write mode

modfrm  struc                           ; format of mode (status) line
        db      'Esc-chr: '             ; do not write in last column.
m_echr  db      2 dup (?)
        db      '  help: '
m_hlp   db      2 dup (?)
        db      '?  port:'
m_prt   db      1 dup (?)
        db      ' speed:'
m_baud  db      5 dup (?)
        db      ' parity:'
m_par   db      4 dup (?)
        db      ' echo:'
m_echo  db      3 dup (?)
m_term  db      13 dup (' ')            ; 13 bytes for term type
m_prn   db      3 dup (' ')             ; show PRN when printer is on
modfrm  ends


datas   segment public 'datas'
        extrn flags:byte, mar_top:byte, mar_bot:byte, portval:word
        extrn filtst:byte, dmpname:byte, kbdflg:byte, rxtable:byte
        extrn anspflg:byte, tekflg:byte

; stuff for screen routines
yflags  db      ?                       ; status flags...
flags1  db      0                       ; internal flags (but used in mszibm).
prtscr  equ     1                       ; print screen pressed
inited  equ     08h                     ; been here before...
vtinited db     0                       ; flag for emulator having been inited
cursor  dw      ?
esc_ch  db      ?
parmsk  db      ?                       ; 8/7 bit parity mask, for reception
argadr  dw      ?                       ; address of arg blk

vid7id  db      'VEGA BIOS Code, '      ; Video 7 Vega version string subset
vid7len equ     $-vid7id                ; length of string
atiwid  db      'ATI EGA Wonder Bios,'  ; ATI EGA wonder version string subset
atilen  equ     $-atiwid                ; length of string, inc terminator
tsngid  db      'Tseng'                 ; Tseng Labs EVA board
tsnglen equ     $-tsngid
ega_mode db     0                       ; non-zero if IBM EGA is in use.
tvhere  equ     0feh                    ; Topview active query
tvsynch equ     0ffh                    ; Topview resynch request
tv_segs dw      ?                       ; Topview virtual screen, segment
tv_sego dw      ?                       ; and offset
tv_mode db      0                       ; flag, 0 = no Topview.
savadr  dw      2 dup (?)               ; offset then segment of saved screen
savflg  dw      ?                       ; low_rgt at time of screen save


; The following are used to turn the display back on (after scrolling etc.)
msets   db      2CH,28H,2DH,29H,2AH,2EH,1EH,29H


vtemu   emulst  <>                      ; emulator flags
ansflgs db      0                       ; ANSI flags
trmtyp  db      0                       ; most recent terminal type
mtty    db      '  TTY   '              ; no terminal type (mode line)

lincur  dw      ?                       ; cursor type save area
scbattr db      ?                       ; Screen background attribute
oldattr db      ?                       ; screen attributes at init time
curattr db      ?                       ; current attribute
temp    dw      ?                       ; scratch storage
modtemp db      0                       ; temp to hold Kermit modeline status
captrtn dw      ?                       ; routine to call for captured output
dmphand dw      ?                       ; screen dump file handle
dumpbuf db      132 dup (?), cr, lf     ; 134 byte dump work buffer
dumpsep db      FF,cr,lf                ; screen image separators
dmperr  db      ' Cannot open file to save screen to disk $'
crlf    db      cr,lf,'$'

; some static data for mode line
modbuf  modfrm  <>                      ; mode line buffer
unkbaud db      'unkwn'                 ; must be 5 chars...
baudn   db      ' 45.5',' 50  ',' 75  ',' 110 ','134.5',' 150 ',' 300 ',' 600 '
        db      ' 1200',' 1800',' 2000',' 2400',' 4800',' 9600','19200','38400'
        db      '57.6K','115 K'
baudnsiz  equ   18                      ; # of baud rates known (tbl size / 4)
parnams db      'even','mark','none','odd ','spc '
lclmsg  db      'loc'
remmsg  db      'rem'
portno  db      ?

; storage for multi-window stuff
swidth  equ     80                      ; max screen width
slen    equ     24                      ; and length of text
npages  equ     10                      ; # of pages of scrolling on each side
crt_norm db     ?                       ; video mode for normal screen
crt_mode db     ?                       ; video mode (typ 3, must be text)
crt_cols db     ?                       ; number of screen columns (typ 80)
crt_lins db     24                      ; number of screen rows - 1 (typ 24)
low_rgt dw      ?                       ; lower right corner of text window
                                        ; high = row address (typ 23)
                                        ; low = column address (typ 79)
inipara dw      ?                       ; initial paragraphs of scroll memory
scrsav  dw      ?                       ; segment address of save area
refresh db      0                       ; screen refresh (0=wait for retrace)
vtroll  db      0                       ; auto roll back allowed (0 = no).

; circular buffer for screen roll back.
cbuf    struc
pp      dw      ?                       ; place ptr in buffer
bend    dw      ?                       ; end of buffer
orig    dw      ?                       ; buffer origin
lcnt    dw      0                       ; # of lines in buffer.
lmax    dw      ?                       ; max lines of buffer.
cbuf    ends

twnd    cbuf    <>                      ; top screen spill-buffer struct
bwnd    cbuf    <>                      ; bottom screen spill buffer struct

datas   ends

code    segment public 'code'
        extrn   beep:near, prtchr:near, outchr:near, sbrk:near, pcwait:near
        extrn   isfile:near, strlen:near, strcpy:near   ; in mssfil
        extrn   anstty:near,ansini:near,ansrei:near     ; in mszibm
        extrn   anstat:near,anskbi:near,ansdsl:near     ; in mszibm
        extrn   ans52t:near, vsinit:near                ; in mszibm
        extrn   msuinit:near, keybd:near                ; in msuibm
        extrn   tekini:near,tekcls:near,tekemu:near,tekend:near ;in msgibm

        assume  cs:code, ds:datas, es:datas

; do initialization local to this module...
; Dynamically allocates 4000 bytes for screen save/restore buffer plus
;  320 to 38400 bytes for screen scroll back buffers. Tries to leave space
;  for Command.com before enlarging buffers. [jrd]
lclyini proc    near
        call    msuinit                 ; initialize keyboard module msuxxx

        mov     ax,swidth*(slen+1)*2    ; (80 char + 80 attr) * 25 lines
        call    sbrk                    ; memory allocation routine (mssker)
                                        ;if we get here them we have the lines
        mov     scrsav,ax               ; memory segment for save screens
                                        ; screen roll back buffers
        mov     bx,0ffffh               ; ask for all of memory, to get size
        mov     ah,alloc                ; allocate all of memory (must fail)
        int     dos                     ; bx has # free paragraphs
        mov     ax,bx                   ; ax has copy of number free paragraphs
        sub     ax,24000D/16            ; space for Command.com copy #2
        jbe     lclyin1                 ; be = not enough for it. [ebb]
        cmp     ax,(swidth*slen+15)/16  ; minimum roll back space left over?
        jbe     lclyin1                 ; be = not even that much
        cmp     ax,(swidth*slen*npages+7)/8 ; paragraphs wanted for roll back
        jbe     lclyin2                 ; be = enough but not more than needed
        mov     ax,(swidth*slen*npages+7)/8 ; limit to our actual needs
        jmp     short lclyin2           ; ask for all we really want
lclyin1:mov     ax,(4*swidth+15)/16     ; use minimum needed paragraphs
lclyin2:mov     inipara,ax              ; save for later resizing of buffers
        mov     cl,4                    ; convert paragraphs to bytes
        shl     ax,cl                   ;  for sbrk
        call    sbrk                    ; ask for that many bytes
                                        ;if we get here them we have the space
        mov     bwnd.orig,ax            ; memory segment, bottom window area
        mov     twnd.orig,ax            ; top. same place for both buffers!
        mov     ax,inipara              ; # paragraphs allocated by DOS
        mov     cl,3                    ; 2**3 = 8
        shl     ax,cl                   ; paragraphs to words (char + attrib)
        xor     dx,dx                   ; clear extended size
        mov     cx,swidth               ; number of chars per line in buffer
        div     cx                      ; ax = number of lines in buffer
        mov     bwnd.lmax,ax            ; max lines per buffer (quotient)
        mov     twnd.lmax,ax            ; max lines per buffer
        add     cx,cx                   ; count char and attribute per item
        xor     dx,dx                   ; clear extended numerator
        mul     cx                      ; ax = effective # bytes per buffer
        dec     ax                      ; adjust for counting from zero
        mov     bwnd.bend,ax            ; offset of last byte in buffer
        mov     twnd.bend,ax            ; offset of last byte in buffer
        mov     bwnd.pp,0               ; offset of first byte in buffer
        mov     twnd.pp,0               ; offset of first byte in buffer
        mov     bwnd.lcnt,0             ; number of lines occupied in buffer
        mov     twnd.lcnt,0             ; number of lines occupied in buffer
        call    scrseg                  ; test running in an Environment
        call    scrmod                  ; read video state, get crt_mode.
        mov     al,crt_mode
        mov     crt_norm,al             ; save as normal mode
        mov     ah,8                    ; read current attributes
        xor     bh,bh                   ; page 0
        int     screen
        mov     scbattr,ah              ; save video attributes
        mov     oldattr,ah              ; and here too
        call    vsinit                  ; init terminal emulator module MSZ
        ret
lclyini endp

scrini  proc    near                    ; init screen stuff
        call    scrmod                  ; get screen mode, low_rgt
        mov     ah,3                    ; get cursor position and char.
        xor     bh,bh                   ; page 0
        int     screen
        mov     lincur,cx               ; save cursor type (scan line #'s)
        mov     ax,low_rgt              ; present screen text size
        cmp     ax,savflg               ;  vs size of saved screen
        je      scrin7                  ; e = same
        and     flags1,not(inited)      ; different, reinit screen (no restore)
        and     vtinited,not(inited)    ; re-init emulator and clear rollback
        mov     ax,inipara              ; paragraphs allotted to roll back
        mov     cl,3                    ; 2**3 = 8
        shl     ax,cl                   ; paragraphs to words (char + attrib)
        xor     dx,dx                   ; clear extended size
        mov     cl,byte ptr low_rgt     ; number of chars per line in buffer
        inc     cl                      ; chars per line
        xor     ch,ch                   ; clear high byte
        div     cx                      ; ax = number of lines in buffer
        mov     bwnd.lmax,ax            ; max lines per buffer (quotient)
        mov     twnd.lmax,ax            ; max lines per buffer
        add     cx,cx                   ; count char and attribute per item
        xor     dx,dx                   ; clear extended numerator
        mul     cx                      ; ax = effective # bytes per buffer
        dec     ax                      ; adjust for counting from zero
        mov     bwnd.bend,ax            ; offset of last byte in buffer
        mov     twnd.bend,ax            ; offset of last byte in buffer
        mov     bwnd.pp,0               ; offset of first byte in buffer
        mov     twnd.pp,0               ; offset of first byte in buffer
        mov     bwnd.lcnt,0             ; number of lines occupied in buffer
        mov     twnd.lcnt,0             ; number of lines occupied in buffer

scrin7:
        mov     dx,cursor               ; assume old cursor
        mov     ega_mode,0              ; assume no EGA.
        mov     ax,1200H                ; EGA: Bios alternate select
        mov     bl,10H                  ; Ask for EGA info
        mov     bh,0ffH                 ; Bad info, for testing
        mov     cl,0fH                  ; Reserved switch settings
        int     screen                  ; EGA, are you there?
        cmp     cl,0cH                  ; Test reserved switch settings
        jge     scrin6                  ; ge = no EGA in use.
        push    es
        mov     ax,40h                  ; check Bios 40:87h for ega being
        mov     es,ax                   ;  the active display adapter
        test    byte ptr es:[87h],8     ; is ega active?
        pop     es
        jnz     scrin6                  ; nz = no
        mov     ega_mode,1              ; yes, set flag to say so.
        mov     crt_norm,3              ; assume color monitor is attached
        cmp     bh,0                    ; is color mode in effect?
        je      scrin6                  ; e = yes
        mov     crt_norm,7              ; else use mode 7 for mono
scrin6: test    flags1,inited           ; have we been here before?
        jnz     scrin4                  ; nz = yes, use old cursor
        mov     ah,oldattr              ; get init time attributes
        mov     curattr,ah              ; and set nice screen attribute
        mov     scbattr,ah
        mov     ah,3                    ; figure out where cursor is
        xor     bh,bh                   ; page 0
        int     screen                  ; read cursor position, in dx
scrin4: cmp     dh,byte ptr low_rgt+1   ; past logical end of screen?
        jb      scrin2                  ; b = no, keep going
        mov     dh,byte ptr low_rgt+1   ; yes, just use lower right corner
scrin2: cmp     dl,byte ptr low_rgt     ; maybe past right margin
        jb      scrin3                  ; b = no, use the way it is
        mov     dl,byte ptr low_rgt
scrin3: mov     cursor,dx               ; init cursor
        mov     ah,2                    ; set cursor position
        xor     bh,bh                   ; page zero
        int     screen                  ; set cursor in case it moved
        ret
scrini  endp

; Routine to initialize VT102/52/Heath-19 terminal emulator.

vtinit  proc    near
        cmp     flags.vtflg,0           ; doing emulation?
        je      vtinix                  ; e = no
        cmp     tekflg,0                ; Tek mode active?
        jne     vtini2                  ; ne = yes, do it's reinit
        or      vtinited,inited
        call    ansflg                  ; update ansi flags
        mov     al,yflags               ; Pass the flags.
        mov     bx,argadr               ; Get address of argument block
        mov     dl,[bx].baudb           ; Baud rate code in dl
        mov     dh,[bx].parity          ; Parity code in bits
        mov     cl,4                    ; 0-3 of dh
        shl     dh,cl
        test    flags.remflg,d8bit      ; eight bit display?
        jnz     vtini1                  ; nz = yes
        or      dh,07H                  ; Just say 7 data bits.
        call    ansini                  ; call startup routine in mszibm.
        ret
vtini1: or      dh,8                    ; say 8 bits
        call    ansini
vtinix: clc
        ret
vtini2: call    tekcls                  ; clear Tek screen
        clc
        ret
vtinit  endp


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     yflags,al               ; mask for allowable and save
        mov     al,[bx].prt
        mov     portno,al               ; update port number
        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
        mov     parmsk,0ffh             ; parity mask, assume parity = None
        cmp     [bx].parity,parnon      ; is parity None?
        je      argini1                 ; e = yes, keep all 8 bits
        mov     parmsk,07fh             ; else keep lower 7 bits
argini1:ret                             ; that's it
argini  endp

modlin  proc    near                    ; turn on mode line
        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,5eh       ; caret, note control char
        mov     modbuf.m_hlp,5eh
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                   ; nb = yes, use default
        mov     cl,size m_baud          ; each is 5 bytes long
        mul     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
        push    es                      ; save es
        push    ds
        pop     es                      ; set es to datas segment
        cld
        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    yflags,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,portno               ; communications port
        cmp     al,' '                  ; binary (non-printable)?
        jae     modl5                   ; ae = no, ascii
        add     al,'0'                  ; convert to ascii
modl5:  mov     modbuf.m_prt,al         ; fill in port number
        mov     cx,8                    ; blank out terminal id field
        mov     si,offset mtty          ; assume no terminal emulation.
        mov     di,offset modbuf.m_term ; destination
        rep     movsb                   ; copy it in.
        mov     modbuf.m_prn,' '        ; assume not printing the screen
        mov     modbuf.m_prn+1,' '
        mov     modbuf.m_prn+2,' '
        test    anspflg,prtscr          ; doing a print the screen?
        jz      modl5a                  ; z = no.
        mov     modbuf.m_prn,'P'        ; yes. display PRN at end of line
        mov     modbuf.m_prn+1,'R'
        mov     modbuf.m_prn+2,'N'
modl5a: mov     cx,size modfrm          ; this is size of mode line
        mov     si,offset modbuf        ; mode line image
        pop     es
                        ; alternate entry to write an alternate mode line
modwrt: push    cx
        push    si                      ; save mode line and size
        mov     ah,3                    ; read cursor position
        xor     bx,bx                   ; screen page 0
        int     screen
        mov     cursor,dx               ; save cursor position
        call    trmatt                  ; Get terminal attributes
        and     ah,77h                  ; omit blinking/bold attributes
        mov     bh,ah                   ; get video attribute
        mov     dx,low_rgt              ; right most column
        inc     dh                      ; refer to status line
        mov     ch,dh                   ; bottom line [dlk]
        mov     cl,0                    ; left col = 0 (first) [dlk]
        mov     ax,600h                 ; scroll to clear the line
        int     screen
        mov     dh,byte ptr low_rgt+1   ; refer to status line
        inc     dh
        xor     dl,dl                   ; left most column
        mov     bh,0
        mov     ah,2                    ; set cursor position
        int     screen
        pop     si
        pop     cx                      ; restore these
        cmp     cl,crt_cols             ; mode line longer than screen?
        jbe     modl6                   ; le = no
        mov     cl,crt_cols             ; else do just one line's worth
        dec     cx                      ; don't let screen scroll
modl6:  cld
        lodsb                           ; get a byte
        mov     ah,14                   ; write to terminal
        mov     bh,0                    ; page 0
        int     screen
        loop    modl6                   ; write out entire mode line
        cmp     flags.vtflg,0           ; emulating?
        je      modl7                   ; e = no
        and     yflags,not modoff       ; update local flags (mode line on)
        mov     al,yflags               ; Yes - update flags also
        call    ansdsl                  ; get extras from emulator
modl7:  mov     dx,cursor
        mov     ah,2
        mov     bh,0
        int     screen                  ; put cursor back where it belongs
        ret                             ; and return
modlin  endp

clrmod  proc    near                    ; clear mode line
        call    trmatt                  ; Get terminal screen attributes
        mov     bh,al                   ; Use screen background attribute
        mov     ax,600h                 ; blank window
        mov     dx,low_rgt              ; right most column
        inc     dh                      ; refer to status line
        mov     cx,dx                   ; bottom line [dlk]
        xor     cl,cl                   ; left most column
        int     screen                  ; clear mode line
        ret                             ; and return
clrmod  endp


; Fetch screen attributes from emulator (if emulating). It exists mainly
; so that the reverse video will work.   Returns the current mode
; line background attribute in ah, the current screen background in al,
; and the current "cursor" (foreground) attribute in bl.  (Note: anstat
; returns status yflags in bh).

trmatt  proc    near                    ; Get attributes
        cmp     flags.vtflg,0           ; emulating?
        je      trmat1                  ; No, just do simple stuff.
        mov     al,yflags               ; anstat expects flags byte in al.
        call    anstat                  ; Fetch emulator status/attributes
        ret
trmat1: mov     al,scbattr              ; Background attributes.
        mov     bl,curattr              ; And cursor attribute.
        mov     ah,al                   ; where modlin needs them
        and     ah,77h                  ; get colors part, no blink/bold
        rol     ah,1                    ; reverse them
        rol     ah,1
        rol     ah,1
        rol     ah,1
        ret
trmatt  endp

; Get byte yflags of terminal emulator passed in AL. Used in mode line
; handling when 25th line is used by the emulator. [jrd]
telmsy  proc    near
        mov     yflags,al               ; get the updated flags
        call    ansflg                  ; and any other emulator info
        ret
telmsy  endp


;[IU2] This routine updates the ANSI status flags from the emulator,
; and passes the "yflags" byte to the VT100 emulator also.

ansflg  proc    near
        push    ax                      ; Save acs over call
        push    bx
        mov     al,yflags
        call    anstat                  ; Get status and attributes
        mov     ansflgs,bh              ; Save.
        pop     bx
        pop     ax
        ret
ansflg  endp

getflgs proc    near                    ; supply yflags for terminal emulators
        mov     al,yflags
        ret
getflgs endp

term    proc    near                    ; terminal mode entry point
        mov     argadr,ax               ; save argument ptr
        call    argini                  ; init options from arg address
        call    scrini                  ; init screen stuff

        test    flags1,inited           ; have we run yet?
        jz      term1                   ; z = no, so no saved screen yet
        call    restscr                 ; restore screen
term1:  or      flags1,inited           ; remember we've run already.
        cmp     flags.vtflg,0           ; current terminal type = None?
        je      term3a                  ; e = yes, nothing to init.
        mov     al,yflags               ; tell emulator we are back
        cmp     vtinited,inited         ; inited emulator yet?
        je      term3                   ; e = yes
        cmp     tekflg,0                ; Tek mode still active?
        jne     term3a                  ; ne = yes, no re-init here
        call    vtinit                  ; init it now
        jmp     term3a
term3:  call    ansrei                  ; reinit the emulator
        call    ansflg                  ; and get its flags
term3a: cmp     flags.modflg,0          ; is mode line disabled?
        je      term2a                  ; e = yes, disabled
        cmp     flags.vtflg,0           ; emulating a terminal?
        jne     term1a                  ; ne = yes, can have mode line
        cmp     trmtyp,0                ; previous terminal type = none?
        jne     term2                   ; ne = no. need to clear mode line.
        jmp     term2a                  ; yes, let 25th line be intact
term1a: test    yflags,modoff           ; is mode line toggled off?
        jnz     term2                   ; nz = yes, clear the line.
        cmp     flags.vtflg,tttek       ; going to be a Tek terminal?
        je      term2a                  ; e = yes, no mode line
        call    modlin                  ; turn on mode line
        jmp     term2a
term2:  call    clrmod                  ; ensure its off
term2a: mov     al,flags.vtflg          ; current terminal type
        mov     trmtyp,al               ; place to remember it til next time
        cmp     flags.vtflg,tttek       ; Tek mode?
        je      term4                   ; e = yes
        cmp     tekflg,0                ; Tek mode active within DEC stuff?
        je      lp                      ; e = no
term4:  call    tekini                  ; reinit to get graphics screen

lp:     call    portchr                 ; char at port?
         jnc    chkinp                  ; nc = no, keep going
         nop
        call    outtty                  ; print on terminal
chkinp: call    keybd                   ; call keyboard translator in msu
        jnc     lp                      ; nc = no char or have processed it
                                        ; carry set = quit Connect mode.

quit:   call    tekend                  ; [bjh]
        mov     ah,3                    ; get cursor position
        xor     bh,bh                   ; page 0
        int     screen
        mov     cursor,dx               ; save position
        call    savescr                 ; save screen
        cmp     flags.vtflg,0           ; emulating?
        je      quit1                   ; e = no
        mov     ax,0600h                ; clear mode line with old attributes
        mov     bh,oldattr              ; attributes
        mov     dx,low_rgt              ; right most column
        inc     dh                      ; refer to status line
        mov     cx,dx                   ; bottom line [dlk]
        xor     cl,cl                   ; left most column
        int     screen                  ; clear the mode line
quit1:  mov     ah,oldattr              ; attributes at init time
        mov     scbattr,ah              ; background = original state
                                        ; for ega in non-standard # lines
        cmp     ega_mode,0              ; ega board active?
        je      quit2                   ; e = no
        cmp     byte ptr low_rgt+1,23   ; is screen standard length?
        je      quit2                   ; e = yes, so regular cursor set is ok
        push    es                      ; turn off ega cursor emulation
        mov     ax,40h                  ; byte 40:87H is ega Info byte
        mov     es,ax
        push    es:[87h]                ; save info byte around call
        or      byte ptr es:[87h],1     ; set emulation off (low bit = 1)
        mov     cx,lincur               ; cursor shape to set
        mov     ah,1                    ; set the shape
        int     screen                  ;   back to starting value
        pop     es:[87h]                ; recover original Info byte
        pop     es                      ; and our work reg
        jmp     short quit3             ; skip regular mode cursor setting
quit2:                                  ; for regular sized screen
        mov     cx,lincur               ; cursor type at startup
        mov     ah,1
        int     screen                  ; restore cursor type
quit3:  mov     ah,2                    ; Position cursor
        mov     bh,0                    ; Page 0
        mov     dx,low_rgt              ; bottom line
        inc     dh                      ; status line position
        xor     dl,dl                   ; left most column
        int     screen                  ; Do it.
        mov     al,yflags
        mov     bx,argadr
        mov     [bx].flgs,al            ; update flags in arg block
        ret                             ; and return to caller
term    endp

; put the character in al to the screen
outtty  proc    near
        cmp     flags.vtflg,0           ; emulating a terminal?
        jne     outnoc                  ; ne = yes, emulator handles printing
        test    flags.remflg,d8bit      ; keep 8 bits for displays?
        jnz     outnp9                  ; nz = yes, 8 bits if possible
        and     al,7fh                  ; remove high bit
outnp9: cmp     rxtable+256,0           ; translation turned off?
        je      outnp7                  ; e = yes, no translation
        push    bx
        mov     bx,offset rxtable       ; address of translate table
        xlatb                           ; new char is in al
        pop     bx
outnp7: test    anspflg,prtscr          ; should we be printing?
        jz      outnop                  ; no, keep going
        push    ax
        mov     ah,lstout               ; write to system printer device
        mov     dl,al
        int     dos
        pop     ax
        jnc     outnop                  ; nc = successful print
        push    ax
        call    beep                    ; else make a noise and
        call    trnprs                  ;  turn off printing
        pop     ax
outnop: test    yflags,capt             ; capturing output?
        jz      outnoc                  ; no, forget this part
        push    ax                      ; save char
        call    captrtn                 ; give it captured character
        pop     ax                      ; restore character and keep going
outnoc: cmp     tekflg,0                ; Tek mode active?
        jne     outnp6                  ; ne = yes, skip screen rolling
        cmp     vtroll,0                ; auto roll back allowed?
        jz      outnp6                  ; z = no, leave screen as is.
        cmp     bwnd.lcnt,0             ; is screen rolled back? [dlk]
        je      outnp6                  ; e = no
        call    endwnd                  ; restore screen before writing [dlk]
outnp6: cmp     flags.vtflg,0           ; emulating a terminal?
        jnz     outnop1                 ; nz = yup, go do something smart
        test    yflags,trnctl           ; debug? if so use Bios tty mode
        jz      outnp4                  ; z = no
        mov     ah,biostty              ; Bios tty screen write
        cmp     al,7fh                  ; Ascii Del char or greater?
        jb      outnp1                  ; b = no
        je      outnp0                  ; e = Del char
        push    ax                      ; save the char
        mov     al,7eh                  ; output a tilde for 8th bit
        int     screen
        pop     ax                      ; restore char
        and     al,7fh                  ; strip high bit
outnp0: cmp     al,7fh                  ; is char now a DEL?
        jne     outnp1                  ; ne = no
        and     al,3fH                  ; strip next highest bit (Del --> '?')
        jmp     outnp2                  ; send, preceded by caret
outnp1: cmp     al,' '                  ; control char?
        jae     outnp3                  ; ae = no
        add     al,'A'-1                ; make visible
outnp2: push    ax                      ; save char
        mov     al,5eh                  ; caret
        int     screen                  ; display it
        pop     ax                      ; recover the non-printable char
outnp3: int     screen
        ret
outnp4: cmp     al,bell                 ; bell (Control G)?
        jne     outnp5                  ; ne = no
        jmp     beep                    ; use short beep, avoid char loss.
outnp5: mov     dl,al                   ; write without intervention.
        mov     ah,conout
        int     dos                     ; else let dos display char
        ret                             ; and return

outnop1:cmp     flags.vtflg,tttek       ; doing Tektronix emulation?
        je      outnop2                 ; e = yes, use Tek emulator
        cmp     tekflg,0                ; Tek submode active?
        jne     outnop2                 ; ne = yes, use Tek emulator
        jmp     anstty                  ; call terminal emulator routine & ret
outnop2:jmp     tekemu                  ; use Tek emulator and return

outtty  endp

;[IU2] Here to output character to port with no echo (like escape sequences
; sent by PF keys, responses to requests from the host, etc.   It is
; wrong thinking to echo these).

prtbout proc    near                    ; Global routine now.
        mov     ah,al                   ; This is where outchr expects it
        call    outchr
         nop                            ; Ignore skip return.
         nop
         nop
        ret
prtbout endp


;[IU2] Here to output an unsigned 8-bit number (in al) to the port without
; echoing. Used by terminal emulator escape sequence output.

prtnout proc    near
        mov     bl,10                   ; Output in base 10.
        jmp     prtno2                  ; Ensure at least a zero.

prtno1: cmp     al,0
        jne     prtno2                  ; Yes - do more digits
        ret                             ; No - return from recursive call.
prtno2: mov     ah,0                    ; Clear previous remainder.
        div     bl                      ; Divide off a digit
        push    ax                      ; Push remainder (in ah) on stack
        call    prtno1                  ; Recur.
        pop     ax                      ; Pop off a digit
        add     ah,'0'                  ; Make it ASCII
        call    outchr                  ; send to port
         nop
         nop
         nop
        ret
prtnout endp

; send the character in al out to the serial port; handle echoing.
; Can send an 8 bit char while displaying only 7 bits locally.
outprt  proc    near
        test    yflags,lclecho          ; echoing?
        jz      outpr1                  ; z = no, forget it
        push    ax                      ; save char
        call    outtty                  ; print it
        pop     ax                      ; restore
outpr1: mov     ah,al                   ; this is where outchr expects it
        call    outchr                  ; output to the port
         nop
         nop
         nop                            ; skip returns...
        ret
outprt  endp

; 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,parmsk               ; apply 8/7 bit parity mask
        stc                             ; have a character
        ret                             ; and return
portchr endp

;;; Action routines (verbs) for keyboard translator KEYBD in msuibm.
; These are invoked by a jump instruction. Return carry clear for normal
; processing, return carry set for invoking Quit (kbdflg has transfer char).
uparrw: mov     al,'A'                  ; cursor keys
        jmp     short comarr
dnarrw: mov     al,'B'
        jmp     short comarr
rtarr:  mov     al,'C'
        jmp     short comarr
lfarr:  mov     al,'D'
comarr: push    ax                      ; save final char
        mov     al,escape               ; Output an escape.
        call    outprt                  ; Output, echo permitted
        cmp     flags.vtflg,tttek       ; Tek terminal?
        je      comar0                  ; e = yes, use VT100 codes
        cmp     flags.vtflg,ttvt100     ; VT100 terminal emulation?
        jne     comar2                  ; No, do VT52/HEATH-19 sequence.
comar0: call    ansflg                  ; Update flags all around.
        mov     al,'['                  ; Maybe this next?
        test    ansflgs,decckm          ; Cursor key mode reset?
        je      comar1                  ; Yes, output the "["
        mov     al,'O'                  ; No, set, use the "O".
comar1: call    outprt                  ; Output it (echo permitted).
comar2: pop     ax                      ; recover final char
        call    outprt                  ; Output to port (echo permitted)
        clc
        ret

pf1:    mov     al,'P'                  ; keypad function keys 1-4
        jmp     short compf
pf2:    mov     al,'Q'
        jmp     short compf
pf3:    mov     al,'R'
        jmp     short compf
pf4:    mov     al,'S'
compf:  push    ax                      ; save final char
        mov     al,escape               ; Output an escape.
        call    prtbout
        call    ansflg                  ; get emulator flags
        test    ansflgs,decanm          ; ansi mode?
        jz      short compf1            ; z = no
        mov     al,'O'                  ; send an "O".
        call    prtbout                 ; Output it.
compf1: pop     ax                      ; Get the saved char back
        call    prtbout                 ; Output to port
        clc
        ret

kp0:    mov     al,'p'                  ; keypad numeric keys
        jmp     short comkp
kp1:    mov     al,'q'
        jmp     short comkp
kp2:    mov     al,'r'
        jmp     short comkp
kp3:    mov     al,'s'
        jmp     short comkp
kp4:    mov     al,'t'
        jmp     short comkp
kp5:    mov     al,'u'
        jmp     short comkp
kp6:    mov     al,'v'
        jmp     short comkp
kp7:    mov     al,'w'
        jmp     short comkp
kp8:    mov     al,'x'
        jmp     short comkp
kp9:    mov     al,'y'
        jmp     short comkp
kpminus:mov     al,'m'
        jmp     short comkp
kpcoma: mov     al,'l'
        jmp     short comkp
kpenter:mov     al,'M'
        jmp     short comkp
kpdot:  mov     al,'n'
comkp:  test    ansflgs,deckpam         ; keypad application mode active?
        jnz     comkp3                  ; nz = yes, use escape sequences
        sub     al,40h                  ; deduct offset to numeric symbols
        jmp     comkp0                  ; and send that single char
comkp3: push    ax                      ; save final char
        mov     al,escape               ; Output an escape.
        call    prtbout
        mov     al,'O'                  ; Output the "O"
        cmp     flags.vtflg,ttvt100     ; VT100 mode?
        je      comkp1                  ; e = yes, use "O" code
        cmp     flags.vtflg,tttek       ; Tek terminal
        je      comkp1                  ; e = yes, use VT100 codes
        test    ansflgs,decanm          ; ANSI (alt application keypad) mode?
        jnz     comkp1                  ; nz = yes, use "O"
comkp2: mov     al,'?'                  ; else use "?" instead of "O".
comkp1: call    prtbout
        pop     ax                      ; recover final char
comkp0: call    prtbout                 ; send it
        clc
        ret
klogon  proc    near                    ; resume logging (if any)
        test    flags.capflg,logses     ; session logging enabled?
        jz      klogn                   ; z = no, forget it
        or      argadr.flgs,capt        ; turn on capture flag
        or      yflags,capt             ; set local msy flag as well
        call    ansflg                  ; tell emulator
klogn:  clc
        ret
klogon  endp

klogof  proc    near                    ; suspend logging (if any)
        and     argadr.flgs,not capt    ; stop capturing
        and     yflags,not capt         ; reset local msy flag as well
        call    ansflg                  ; tell emulator
klogo:  clc
        ret
klogof  endp

snull   proc    near                    ; send a null byte
        mov     al,0                    ; the null
        call    prtbout                 ; send without logging and local echo
        clc
        ret
snull   endp
                                        ; general character out for emulator
chrout: cmp     flags.vtflg,0           ; emulating?
        je      chrou5                  ; e = no
        call    anskbi                  ; Yes, say we had keyboard input.
        cmp     al,cr                   ; A CR?
        jne     chrou5                  ; No - just output it and return
        call    ansflg                  ; Yes - update VT100 flags
        test    ansflgs,anslnm          ; ANSI new-line mode set?
        jz      chrou5                  ; No - just send the cr
        call    outprt                  ; Yes - output a carriage-return
        mov     al,lf                   ; Followed by a line feed.
chrou5: call    outprt
        clc
        ret

                                        ; these commands invoke Quit
cdos:   mov     al,'P'                  ; Push to DOS
        jmp     short cmdcom
cstatus:mov     al,'S'                  ; Status
        jmp     short cmdcom
cquit:  mov     al,'C'                  ; Exit Connect mode
        jmp     short cmdcom
cquery: mov     al,'?'                  ; Help
        jmp     short cmdcom
chang:  mov     al,'H'                  ; Hangup, drop DTR & RTS
        jmp     short cmdcom
cmdcom: mov     kbdflg,al               ; pass char to msster.asm via kbdflg
        stc                             ; signal that Quit is needed
        ret

dmpscn  proc    near                    ; dump screen to file
        call    savescr                 ; save screen to buffer
        call    dumpscr                 ; do buffer to file
        clc                             ; do not exit Connect mode
        ret
dmpscn  endp


;[IU2] Routine to toggle VT100/VT52/Heath-19 modes in VT100 emulator.

vtans52 proc    near
        cmp     flags.vtflg,0           ; emulating?
        je      vtans5                  ; e = no
        call    ans52t                  ; Call MSZ toggle-it routine.
        call    ansflg                  ; Update flags.
        clc                             ; clear c bit so don't exit Connect.
vtans5: ret
vtans52 endp
                                        ; Toggle Mode Line
trnmod: cmp     flags.modflg,0          ; is mode line enabled?
        je      trnm2                   ; e = no, don't touch it
        cmp     flags.vtflg,tttek       ; Tek mode?
        je      trnm2                   ; yes
        cmp     tekflg,0                ; Tek submode?
        jne     trnm2                   ; ne = yes, no mode line changes
        test    yflags,modoff           ; mode line already off?
        jnz     trnm1                   ; yes, go turn on
        call    clrmod                  ; no, clear mode line here
        or      yflags,modoff           ; turn on flag
        call    ansflg                  ; Update flags all around.
        clc                             ; clear c bit so don't exit Connect
        ret                             ; and return
trnm1:  and     yflags,not modoff       ; Clear flag first.
        call    modlin                  ; Then turn on mode line.
        call    ansflg                  ; Update flags all around.
trnm2:  clc
        ret

trnprs: push    ax                      ; toggle ^ PrtSc screen to printer
        test    anspflg,prtscr          ; are we currently printing?
        jnz     trnpr2                  ; nz = yes, its on and going off
        mov     ah,ioctl
        mov     al,7                    ; get output status of printer
        push    bx
        mov     bx,4                    ; file handle for system printer
        int     dos
        pop     bx
        jc      trnpr1                  ; c = printer not ready
        cmp     al,0ffh                 ; Ready status?
        je      trnpr2                  ; e = Ready
trnpr1: call    beep                    ; Not Ready, complain
        jmp     trnpr3                  ; and ignore request
trnpr2: xor     anspflg,prtscr          ; flip the flag
        test    yflags,modoff           ; mode line off?
        jnz     trnpr3                  ; nz = yes
        call    modlin                  ; else rewrite mode line
trnpr3: pop     ax
        clc                             ; return carry clear (don't quit)
        ret

;;;;; General screen management routines for IBM PC

; computes screen location to ax, given row and col in [dh,dl], resp.
; trashes dx
scrloc  proc    near
        mov     al,dh                   ; get row
        xor     ah,ah                   ; clear ah
        mul     crt_cols                ; multiply by number of columns
        xor     dh,dh                   ; clear row
        add     ax,dx                   ; this is current position
        shl     ax,1                    ; double for attributes
        ret
scrloc  endp

; Routine to set cursor type.  Pass cursor type in al: 0 = No cursor,
; 1 = Underline cursor, 2 = Block cursor.   All cursors blink due to hardware.
; Routine frags any ac that video ints frag.
; For EGA boards running in non-25 line mode the cursor emulation is turned
; off during cursor shape changing and restored afterward. It's another
; ega Feature. [jrd]
csrtype proc    near
        push    cx                      ; save the reg
        mov     ah,1                    ; Video fxn for set cursor type
        mov     cx,0F00H                ; Assume no cursor
        cmp     al,0                    ; No cursor?
        je      csrty2                  ; Right - set it and be done with it.
        cmp     crt_mode,7              ; B&W card?
        je      csrty3                  ; Yes - different sizes
        mov     cx,0607H                ; No, use CGA underline cursor
        cmp     al,2                    ; Block?
        jne     csrty2                  ; No - set it now.
csrty1: xor     ch,ch                   ; Yes - make it a block
csrty2: cmp     ega_mode,0              ; ega board active?
        je      csrty4                  ; e = no
        cmp     byte ptr low_rgt+1,23   ; standard screen length?
        je      csrty4                  ; e = yes, use regular cursor setting
        push    es                      ; EGA. turn off cursor emulation
        mov     ax,40h                  ; 40:87h is ega Info byte
        mov     es,ax
        push    es:[87h]                ; save Info byte around call
        or      byte ptr es:[87h],1     ; set emulation off (low bit = 1)
        mov     ah,1                    ; Video fxn for set cursor type
        int     screen
        pop     es:[87h]                ; restore Info byte
        pop     es                      ;  and our work register
        pop     cx
        ret
csrty4: int     screen                  ; regular cursor shape setting
        pop     cx
        ret
csrty3: mov     cx,0B0CH                ; Assume B&W underline cursor
        cmp     al,2                    ; Block?
        jne     csrty2                  ; No - set it now.
        jmp     csrty1                  ; Yes - make it a block
csrtype endp


; Save the entire screen in a buffer so we can restore and/or dump it.
; Saves regular (80x25) screens to memory buffer scrsav and other sized
; screens to video memory page 1. Resultant save place put into savadr
; (offset then segment) and current low_rgt size info in savflg. Note,
; some Environments (TopView/Windows etc) may not permit use of page 1. [jrd]
savescr proc    near
        push    es
        push    ds
        push    ax
        push    cx
        push    si
        push    di
        call    scrseg                  ; get screen segment in ax and es:di
        push    ax                      ; save screen segment
        mov     si,0
        mov     di,scrsav               ; place to put screen (memory buff)
        mov     savadr+2,di             ; working seg address for restore
        mov     savadr,0                ; and no offset for memory buffer

        call    scrmod                  ; ascertain video mode and screen
        mov     ax,low_rgt              ; text screen lower right (typ 23,79)
        mov     savflg,ax               ; save it for screen restore
        inc     al                      ; number of columns
        add     ah,2                    ;  plus status line = number of rows
        cmp     al,swidth               ; same as preset screen space (80)?
        ja      savsc1                  ; a = no, use screen video page 1
        cmp     ah,slen+1               ; same as preset screen length (24)?
        je      savsc3                  ; e = yes, use our memory buffer
savsc1: mul     ah                      ; times rows = characters on screen
        shl     ax,1                    ; times two for attributes = page 1
        mov     cx,ax                   ; cx = working copy of screen size
        and     cx,000fh                ; get lower four bits for offset part
        mov     savadr,cx               ; save offset in this word
        mov     cl,4
        shr     ax,cl                   ; compute number of paragraphs
        pop     di                      ; source screen address
        push    di                      ; restore again
        add     di,ax                   ; add paragraphs, point di to page 1
        mov     savadr+2,di             ; and save segment in this word
savsc3:
        mov     es,savadr+2             ; segment of storage area
        mov     di,savadr               ;  offset of same
        mov     ax,low_rgt              ; lower right of text screen
        inc     al                      ; number of columns on screen
        add     ah,2                    ; number of rows on screen
        mul     ah                      ; number of characters on the screen
        mov     cx,ax                   ; save this in counter cx
        call    scroff                  ; turn off screen [dt]
        pop     ds                      ; address screen
        cld
        rep     movsw                   ; save the screen
        pop     di
        pop     si
        pop     cx
        pop     ax
        pop     ds                      ; restore this
        call    scron                   ; turn on screen [dt]
        pop     es
        ret
savescr endp

; restore screen from buffer (offset and seg in savadr, text coord in savflg).
; Restores all screen lines. [jrd]
restscr proc    near
        push    es
        mov     ax,savflg               ; saved low_rgt text screen coord
        add     ah,2                    ; number of screen lines
        inc     al                      ; number of screen columns
        mul     ah                      ; columns time lines = # characters
        mov     cx,ax                   ; save this in counter cx
        push    cx                      ; save count
        call    scrseg                  ; get address of screen in es:di
        call    scroff                  ; turn off screen [dt]
        push    ds                      ; save original data segment
        mov     si,savadr               ; offset of storage area
        push    savadr+2                ; segment of same
        pop     ds                      ; put storage segment into ds
        cld
        rep     movsw                   ; restore data to screen
        pop     ds                      ; recover original data segment
        call    scron                   ; turn on screen [dt]
        pop     cx                      ; recover count
        call    scrsync                 ; synch Topview with new screen
        pop     es
        ret
restscr endp

; Save the screen to a buffer and then append buffer to a disk file. [jrd]
; Default filename is Kermit.scn; actual file can be a device too. Filename
; is determined by mssset and is passed as pointer dmpname.
; Dumpscr reads the screen image saved by savescr so call savescr call first.

dumpscr proc    near
        push    ax
        push    bx
        push    cx
        push    dx
        mov     dmphand,-1              ; preset illegal handle
        mov     dx,offset dmpname       ; name of disk file, from mssset
        mov     ax,dx                   ; where isfile wants name ptr
        call    isfile                  ; what kind of file is this?
        jc      dmp5                    ; c = no such file, create it
        test    byte ptr filtst.dta+21,1fh ; file attributes, ok to write?
        jnz     dmp0                    ; nz = no.
        mov     al,1                    ; writing
        mov     ah,open2                ; open existing file
        int     dos
        jc      dmp0                    ; c = failure
        mov     dmphand,ax              ; save file handle
        mov     bx,ax                   ; need handle here
        mov     cx,0ffffh               ; setup file pointer
        mov     dx,-1                   ; and offset
        mov     al,2                    ; move to eof minus one byte
        mov     ah,lseek                ; seek the end
        int     dos
        jmp     dmp1

dmp5:   test    filtst.fstat,80h        ; access problem?
        jnz     dmp0                    ; nz = yes
        mov     ah,creat2               ; file did not exist
        mov     cx,20h                  ; attributes, archive bit
        int     dos
        mov     dmphand,ax              ; save file handle
        jnc     dmp1                    ; nc = ok

dmp0:   mov     ah,3                    ; get cursor position
        xor     bx,bx                   ; page 0
        int     screen
        push    dx                      ; save it
        mov     dh,byte ptr low_rgt+1   ; go to status line
        inc     dh
        xor     dl,dl                   ; left most column
        mov     ah,2                    ; position cursor
        int     screen
        mov     dx,offset dmperr        ; say no can do
        mov     ah,prstr
        int     dos
        pop     dx                      ; get original cursor position
        mov     ah,2                    ; position cursor
        xor     bx,bx                   ; page 0
        int     screen
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        clc
        ret

dmp1:   mov     ah,ioctl                ; is destination ready for output?
        mov     al,7                    ; test output status
        mov     bx,dmphand              ; handle
        int     dos
        jc      dmp0                    ; c = error
        cmp     al,0ffh                 ; ready?
        jne     dmp0                    ; ne = not ready.
        push    di                      ; read screen buffer, write lines
        push    si
        push    es
        mov     cl,byte ptr low_rgt+1   ; number of lines - 2
        add     cl,2                    ; number of line on screen
        xor     ch,ch
        mov     si,savadr               ; offset in storage area
dmp2:   push    cx                      ; save outer loop counter
        mov     es,savadr+2             ; get storage segment
        mov     di,offset dumpbuf       ; data segment memory
        mov     cl,byte ptr savflg      ; number of columns on screen - 1
        inc     cl                      ; number of columns on screen
        xor     ch,ch
dmp3:   mov     ax,word ptr es:[si]     ; read char + attribute
        mov     byte ptr [di],al        ; store just char, don't use es:
        inc     si                      ; update pointers
        inc     si
        inc     di
        loop    dmp3                    ; do for each column
        std                             ; set scan backward
        mov     cl,byte ptr savflg      ; number of columns on screen - 1
        inc     cl                      ; number of columns on screen
        xor     ch,ch
        push    es
        mov     ax,ds
        mov     es,ax                   ; set es to data segment for es:di
        mov     di,offset dumpbuf       ; start of line
        add     di,cx                   ; plus length of line
        dec     di                      ; minus 1 equals end of line
        mov     al,' '                  ; thing to scan over
        repe    scasb                   ; scan until non-space
        cld                             ; set direction forward
        pop     es
        jz      dmp3a                   ; z = all spaces
        inc     cx
        inc     di
dmp3a:  mov     word ptr [di+1],0A0Dh   ; append cr/lf
        add     cx,2                    ; line count + cr/lf
        mov     dx,offset dumpbuf       ; array to be written
        mov     bx,dmphand              ; need file handle
        mov     ah,write2               ; write the line
        int     dos
        pop     cx                      ; get line counter again
        jc      dmp3b                   ; c = error
        loop    dmp2                    ; do next line
        mov     dx,offset dumpsep       ; put in formfeed/cr/lf
        mov     cx,3                    ; three bytes overall
        mov     ah,write2               ; write them
dmp3b:  mov     bx,dmphand              ; file handle
        int     dos
        mov     ah,close2               ; close the file now
        int     dos
dmp6:   pop     es
        pop     si
        pop     di
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        clc
        ret
dumpscr endp


; Get CRT mode - returns mode in variable crt_mode,
; updates crt_cols and low_rgt.
; For EGA active it looks in Bios work memory 40:84H for number of rows. [jrd]
scrmod  proc    near
        push    ax
        push    dx
        mov     ah,15                   ; Get current video state.
        int     screen
        mov     crt_mode,al             ; Store CRT mode value.
        mov     crt_cols,ah             ; store # of cols
        mov     dl,ah                   ; # of cols again
        mov     dh,crt_lins             ; and # of rows (constant from msster)
        cmp     ega_mode,0              ; ega active?
        je      scrmod4                 ; e = no
        push    es                      ; yes, permit different lengths
        mov     ax,40h                  ; refer to 40:84h for # ega rows
        mov     es,ax
        mov     ah,es:[84h]             ; get number of rows - 1 (typ 24)
        cmp     ah,20                   ; less than 20 rows?
        jb      scrmod3                 ; b = yes, ignore this length
        cmp     ah,80                   ; more than 80 rows?
        ja      scrmod3                 ; a = yes, ignore this length
        mov     dh,ah                   ; use this length
        mov     crt_lins,dh             ; update our working constant
scrmod3:pop     es
scrmod4:
        dec     dl                      ; max text column, count from zero
        dec     dh                      ; max text row, count from zero
        mov     low_rgt,dx              ; save away window address
        pop     dx
        pop     ax
        ret                             ; And return.
scrmod  endp


; Get screen segment - returns screen segment in ax, and full address in es:di

scrseg  proc    near
        xor     di,di                   ; start at beginning of screen (0,0)
        mov     ax,0B000H               ; Assume B&W card..
        cmp     crt_mode,7              ; Is it?
        je      scrse1                  ; e = yes
        mov     ax,0B800H               ; No - video memory is here on color
        cmp     crt_mode,12             ; graphics set?
        jb      scrse1                  ; b = no
        mov     ax,0A000H               ; graphics
scrse1: mov     es,ax           ; tell Topview our hardware address needs
        mov     tv_segs,es              ; save our hardware screen address
        mov     tv_sego,di              ; segment and offset form
        mov     tv_mode,1               ; assume we're running under Topview
        mov     ah,tvhere               ; query Topview for its presence
        int     screen
        mov     ax,es                   ; get its new segment for screen work
        cmp     ax,tv_segs              ; same as hardware?
        jne     scrse2                  ; ne = no, we are being mapped
        cmp     di,tv_sego              ; check this too.
        jne     scrse2          ; ne = no too. Use TV's work buf as screen.
        mov     tv_mode,0               ; else no Topview or no mapping.
scrse2: ret
scrseg  endp

; Synchronize a Topview provided virtual screen buffer with the image
; seen by the user. Requires cx = number of words written to screen
; (char & attribute bytes) and es:di = ENDING address of screen write.
; Changes ax and di.
scrsync proc    near
        cmp     tv_mode,0               ; Topview mode active?
        je      scrsyn1                 ; e = no, skip DOS call below
        sub     di,cx                   ; backup to start byte (cx = words)
        sub     di,cx                   ;  after storing words to screen
        mov     ah,tvsynch              ; tell Topview we have changed screen
        int     screen                  ;  so user sees updated screen
scrsyn1:ret
scrsync endp

; The following two routines are used to turn off the display while we
; are reading or writing the screen in one of the color card modes.
; Turn screen off for (known) color card modes only. All regs preserved.
; Includes code for old procedure scrwait. 16 June 1987 [jrd]
scroff  proc    near
        cmp     refresh,0               ; slow refresh?
        jne     scrofx                  ; ne = no wait
        cmp     ega_mode,0              ; Extended Graphics Adapter in use?
        jne     scrofx                  ; ne = yes, no waiting.
        cmp     tv_mode,0               ; Topview mode?
        jne     scrofx                  ; ne = yes, no waiting
        cmp     crt_mode,7              ; B&W card?
        jnb     scrofx                  ; Yes - just return.
        push    ax                      ; Save ax and dx.
        push    dx
        mov     dx,crt_status           ; CGA: Wait for vertical retrace
scrof1: in      al,dx
        test    al,disp_enb             ; display enabled?
        jnz     scrof1                  ; yes, keep waiting
scrof2: in      al,dx
        test    al,disp_enb             ; now wait for it to go off
        jz      scrof2                  ; so can have whole cycle
        mov     dx,crtmset              ; Output to CRT mode set port.
        mov     al,25H                  ; This shuts down the display
        out     dx,al                   ; Dumb, but card is too..
        pop     dx                      ; Restore acs.
        pop     ax
scrofx: ret                             ; And return.
scroff  endp


; Turn screen on for (known) color card modes only
; All registers are preserved.

scron   proc    near
        cmp     refresh,0               ; slow refresh?
        jne     scronx                  ; ne = no wait
        cmp     ega_mode,0              ; Extended Graphics Adapter in use?
        jne     scronx                  ; ne = yes, no waiting.
        cmp     tv_mode,0               ; Topview mode?
        jne     scronx                  ; ne = yes, no waiting
        cmp     crt_mode,7              ; B&W card?
        jnb     scronx                  ; Yes - just return.
        push    ax                      ; Save ax, dx, and si
        push    dx
        push    si
        mov     al,crt_mode             ; Convert crt_mode to a word
        xor     ah,ah
        mov     si,ax                   ; Get it in a usable register
        mov     al,msets[si]            ; Fetch the modeset byte
        mov     dx,crtmset              ; This port
        out     dx,al                   ; Flash it back on
        pop     si                      ; Restore acs.
        pop     dx
        pop     ax
scronx: ret                             ; And return.
scron   endp


; Screen clearing routine. [IU]
;
; Call:         ax/     coordinates of first screen location to be cleared.
;               bx/     coordinates of last location to be cleared.
; Coord: ah = row [0-24], al = column [0-79]. Preserves all registers. [jrd]

atsclr: push    ax                      ; Save some acs
        push    cx
        push    dx
        mov     dx,bx                   ; Compute last screen offset in ax
        push    ax
        call    scrmod                  ; update column length
        pop     ax                      ; scrmod zaps ax
        push    ax
        call    scrloc                  ; get screen start address in ax
        mov     cx,ax                   ; Save it in cx for a minute
        pop     dx                      ; Compute first screen offset in ax
        call    scrloc
        sub     cx,ax                   ; Compute number of locs to clear...
        add     cx,2
        sar     cx,1                    ; Make byte count a word count
        jle     atscl2                  ; If nothing to clear, then vamos.
        push    di                      ; Save some more acs
        push    es                      ; save es
        push    ax                      ; save around call
        call    scrseg                  ; Get address of screen in ax, es:di
        pop     ax                      ; recover displacement
        add     di,ax                   ; displacement memory address
        mov     ah,scbattr              ; Use current screen background attr.
        mov     al,' '                  ; Use space for fill
        mov     dl,byte ptr low_rgt     ; line length - 1
        inc     dl                      ; line length
        xor     dh,dh
        cmp     cx,dx                   ; Blanking a line or less??
        jg      atscl1                  ; No - make scroff disable display
atscl1: call    scroff                  ; Turn screen off if color card.
        push    cx                      ; save word count for Topview
        cld
        rep     stosw                   ; Blit... (excuse PDP-10ese please)
        pop     cx                      ; recover word count
        call    scrsync                 ; synch Topview
        call    scron                   ; Turn screen back on if color card.
        pop     es                      ; Restore segment register
        pop     di                      ; And destination index
atscl2: pop     dx                      ; restore regs
        pop     cx
        pop     ax
        ret

; Scrolling routines.  vtscru scrolls up one row, vtscrd scrolls down one
; row.  atsprep is called before scrolling up to save the top line in the
; circular buffer. All registers are preserved.

; Screen-roll down. Move text down one line, for terminal emulator only.

vtscrd: push    ax                      ; Upgraded by [jrd]
        push    bx
        push    cx
        push    dx
        mov     ax,701H                 ; scroll down one line
        mov     ch,mar_top              ; top margin line
        mov     cl,0                    ; left most column
        mov     dh,mar_bot              ; bottom margin line
        mov     dl,byte ptr low_rgt     ; right most column
        mov     bh,scbattr              ; attributes
        int     screen                  ; scroll it down
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        clc
        ret
                                        ; worker routine for vtscru/d
atsprep:push    es                      ; upgraded from older version  [jrd]
        call    scroff                  ; turn off color screen
        call    scrseg                  ; get display address in es:di
        mov     si,di                   ; si will be source
        mov     bx,offset twnd          ; this is where it goes
        call    putcirc                 ; put screen line in circular buffer
        pop     es                      ; and that
        call    scron                   ; turn on screen again
        ret                             ; and return


; Screen scroll up one line (text moves up) for terminal emulator use.

vtscru: push    ax                      ; Upgraded by  [jrd]
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        cmp     mar_top,0               ; scrolling the top screen line?
        ja      scru1                   ; a = no. don't save anything
        call    atsprep                 ; save top line
scru1:  mov     ax,601H                 ; scroll up one line
        mov     dh,mar_bot              ; bottom row
        mov     dl,byte ptr low_rgt     ; right most column
        mov     ch,mar_top              ; top row of scrolling region
        mov     cl,0                    ; left most column
        mov     bh,scbattr              ; background attributes
        int     screen                  ; scroll up that region
        pop     di                      ; Restore the rest of the regs.
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        clc
        ret                             ; And return

;screen text roll up, version for manual scrolling only

mscru:  push    ax                      ; Upgraded by  [jrd]
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        cmp     bwnd.lcnt,0             ; any lines in bottom window?
        je      mscru2                  ; e = no, so ignore request
        call    atsprep                 ; save top line
mscru1: mov     ax,601H                 ; scroll up one line
        mov     dx,low_rgt              ; lower right corner
        xor     cx,cx                   ; top row of scrolling region
        mov     bh,scbattr              ; background attributes
        int     screen                  ; scroll up that region
        call    scroff
        mov     dx,low_rgt
        mov     dl,0                    ; location is lower left corner
        call    scrloc                  ; get count from display start
        push    es
        push    ax                      ; save count
        call    scrseg                  ; get screen's segment into ax, es:di
        pop     ax                      ; recover count
        add     di,ax                   ; destination memory address (es:di)
        mov     bx,offset bwnd          ; source of lines
        call    getcirc                 ; get line from circ buf to screen
        pop     es                      ; restore es
        call    scron                   ; turn on the screen
mscru2: pop     di                      ; Restore the rest of the regs.
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret


; prep for screen scroll down.
; copies bottom scroll line from screen to bottom window buffer.
; destroys ax,cx,dx,si,di.
getbot proc near                        ; Upgraded from old version [jrd]
        push    es
        call    scroff                  ; turn off screen
        mov     dx,low_rgt              ; from screen location, row
        mov     dl,0                    ; starting in col 0
        call    scrseg                  ; get adaptor's offset into es:di
        call    scrloc                  ; get offset in display buffer in ax
        add     di,ax                   ; source addr in display buffer es:di
        mov     si,di                   ; screen is source (si)
        mov     bx,offset bwnd          ; buffer to use (bottom window)
        call    putcirc                 ; copy bottom screen line to circ buf
        pop     es
        call    scron                   ; turn on display again
        ret
getbot endp

;screen text scroll down, for manual mode only
mscrd:  push    ax                      ; Upgraded by [jrd]
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        cmp     twnd.lcnt,0             ; any lines left in top window?
        je      mscrd1                  ; e = no, ingore request
        call    getbot                  ; fetch bottom line from screen
        mov     ax,701H                 ; scroll down one line
        xor     cx,cx                   ; top left corner
        mov     dx,low_rgt              ; bottom right corner
        mov     bh,scbattr              ; attributes
        int     screen                  ; scroll it down
        call    scroff                  ; turn off display
        push    es
        call    scrseg                  ; get segment address of screen
        mov     bx,offset twnd          ; buffer to use (top window)
        call    getcirc                 ; copy from circ buf to screen
        pop     es
        call    scron                   ; turn on display again
mscrd1: pop     di                      ; Restore the rest of the ACs.
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret

; move viewing window down as much as possible (text moves up)
endwnd  proc    near                    ; go to end of scrolling text
        push    cx
        mov     cx,bwnd.lcnt            ; all bottom window lines [dlk]
        jmp     dnwp0                   ; and enter dwnpg
endwnd  endp

dnone   proc    near                    ; move text up one line [jrd]
        push    cx
        mov     cx,1
        jmp     dnwp0
dnone   endp

; scroll viewing window down (text moves up) one page (24 lines)
dnwpg   proc    near
        push    cx
        mov     cl,byte ptr low_rgt+1   ; number of rows, excl status
        inc     cl                      ; count from 1, not 0
        mov     ch,0
dnwp0:                                  ; additional entry point
        cmp     bwnd.lcnt,cx            ; enough lines in bottom line buffer?
        jge     dnwp1                   ; ge = we have that many lines stored
        mov     cx,bwnd.lcnt            ; do as many as we have
dnwp1:  jcxz    dnwp2                   ; z = nothing to do
        cmp     tekflg,0                ; Tek mode active?
        jne     dnwp2                   ; ne = yes, no scrolling
        call    mscru                   ; scroll up text one line
        loop    dnwp1
dnwp2:  pop     cx
        clc
        ret
dnwpg   endp

; home viewing window
homwnd  proc    near
        push    cx
        mov     cx,twnd.lcnt            ; all top window lines [dlk]
        jmp     upwp0                   ; join upwpg
homwnd  endp

upone   proc    near                    ; move text down one line [jrd]
        push    cx
        mov     cx,1
        jmp     upwp0
upone   endp

; scroll viewing window up (text moves down) a page (24 lines)
upwpg   proc    near
        push    cx
        mov     cl,byte ptr low_rgt+1   ; number of rows, excl status line
        inc     cl                      ; count from 1, not 0
        mov     ch,0
upwp0:                                  ; additional entry point
        cmp     twnd.lcnt,cx            ; enough lines in top line buffer?
        jae     upwp1                   ; ae = at least as many as requested
        mov     cx,twnd.lcnt            ; do only as many as are stored.
upwp1:  jcxz    upwp2                   ; z = no lines to scroll
        cmp     tekflg,0                ; Tek mode active?
        jne     upwp2                   ; ne = yes, no scrolling
        call    mscrd                   ; roll down text one line
        loop    upwp1
upwp2:  pop     cx
        clc
        ret
upwpg   endp


; Put a line into the circular buffer.  Pass the buffer structure in bx.
; Source is tv_segs:si which is the current screen address.
; Rewritten by [jrd]
putcirc proc    near
        push    es
        mov     cl,crt_cols             ; number of columns
        xor     ch,ch
        mov     es,[bx].orig            ; get segment of memory area
        cmp     bx,offset bwnd          ; bottom buffer?
        je      putci6                  ; e = yes
        mov     di,twnd.pp              ; pick up buffer ptr (offset from es)
        add     di,cx                   ; increment to next available slot
        add     di,cx                   ; char and attribute
        cmp     di,twnd.bend            ; would line extend beyond buffer?
        jb      putci1                  ; b = not beyond end
        mov     di,0                    ; else start at the beginning
putci1: mov     twnd.pp,di              ; update ptr
        cld                             ; set direction to forward
        push    ds                      ; save regular datas seg reg
        mov     ds,tv_segs              ; use screen segment for ds:si
        rep     movsw                   ; copy into buffer
        pop     ds                      ; restore regular datas segment
        mov     cx,twnd.lmax            ; line capacity of buffer
        dec     cx                      ; minus one work space line
        cmp     twnd.lcnt,cx            ; can we increment line count?
        jae     putci1b                 ; ae = no, keep going
        inc     twnd.lcnt               ; else count this line
putci1b:cmp     bwnd.lcnt,0             ; any lines in bottom buffer?
        je      putci2                  ; e = no
        mov     cx,bwnd.pp              ; see if we overlap bot buf
        cmp     cx,twnd.pp              ; is this line in bot buf area?
        jne     putci2                  ; ne = no
        add     cl,crt_cols             ; move bottom pointer one slot earlier
        adc     ch,0
        add     cl,crt_cols             ; words
        adc     ch,0
        cmp     cx,bwnd.bend            ; beyond end of buffer?
        jb      putci1a                 ; b = no
        mov     cx,0                    ; yes, start at beginning of buffer
putci1a:mov     bwnd.pp,cx              ; new bottom pointer
        dec     bwnd.lcnt               ; one less line in bottom buffer
putci2: pop     es
        ret
putci6:                                 ; bottom buffer
        add     cx,cx                   ; words worth
        cmp     bwnd.lcnt,0             ; any lines in the buffer yet?
        jne     putci7                  ; ne = yes
        mov     di,twnd.pp              ; get latest used slot of top buff
        add     di,cx                   ; where first free (?) slot starts
        cmp     di,bwnd.bend            ; are we now beyond the buffer?
        jb      putci6a                 ; b = no
        mov     di,0                    ; yes, start at beginning of buffer
putci6a:add     di,cx                   ; start of second free (?) slot
        cmp     di,bwnd.bend            ; are we now beyond the buffer?
        jb      putci6b                 ; b = no
        mov     di,0                    ; yes, start at beginning of buffer
putci6b:mov     cx,twnd.lmax            ; buffer line capacity
        sub     cx,twnd.lcnt            ; minus number used by top buffer
        sub     cx,2                    ; minus one work slot and one we need
        cmp     cx,0                    ; overused some slots?
        jge     putci8                  ; ge = enough to share
        add     twnd.lcnt,cx            ; steal these from top window beginning
        jmp     short putci8

putci7: mov     es,bwnd.orig            ; get segment of memory area
        mov     di,bwnd.pp              ; pick up buffer ptr (offset from es)
        cmp     di,0                    ; would line start before buffer?
        jne     putci7a                 ; ne = after start of buffer
        mov     di,bwnd.bend            ; else start at the end minus one slot
        inc     di
putci7a:sub     di,cx
putci8: mov     bwnd.pp,di              ; update ptr (this is latest used slot)
        mov     cl,crt_cols
        xor     ch,ch
        cld                             ; set direction to forward
        push    ds                      ; save regular datas seg reg
        mov     ds,tv_segs              ; use screen segment for ds:si
        rep     movsw                   ; copy into buffer
        pop     ds                      ; restore regular datas segment
        mov     cx,bwnd.lmax            ; line capacity of buffer
        cmp     bwnd.lcnt,cx            ; can we increment line count?
        jae     putci8b                 ; ae = no, keep going
        inc     bwnd.lcnt               ; else count this line
putci8b:cmp     twnd.lcnt,0             ; any lines in top line buf?
        je      putci9                  ; e = no
        mov     cx,twnd.pp              ; yes, see if we used last top line
        cmp     cx,bwnd.pp              ; where we just wrote
        jne     putci9                  ; not same place, so all is well
        dec     twnd.lcnt               ; one less line in top window
        cmp     cx,0                    ; currently at start of buffer?
        jne     putci8a                 ; ne = no
        mov     cx,twnd.bend            ; yes
        inc     cx
putci8a:sub     cl,crt_cols             ; back up top window
        sbb     ch,0
        sub     cl,crt_cols             ; by one line
        sbb     ch,0
        mov     twnd.pp,cx              ; next place to read
putci9: pop     es
        ret

putcirc endp

; Get a line from the circular buffer, removing it from the buffer.
; returns with carry on if the buffer is empty.
; Pass the buffer structure in bx.
; Destination preset in es:di which is the current screen address.
; Rewritten by [jrd]
getcirc proc    near
        cmp     [bx].lcnt,0             ; any lines in buffer?
        jne     getci1                  ; ne = yes, ok to take one out.
        stc                             ; else set carry
        ret                             ; and return
getci1:                                 ; top and bottom window common code
        mov     cl,crt_cols             ; # of chars to copy
        xor     ch,ch
        push    cx                      ; save around calls
        mov     si,[bx].pp              ; this is source
        cld                             ; set direction to forward
        push    ds                      ; save original ds
        mov     ds,[bx].orig            ; use seg address of buffer for si
        rep     movsw
        pop     ds                      ; recover original data segment
        pop     cx                      ; length for Topview
        push    cx                      ; save again
        call    scrsync                 ; synch Topview
        mov     si,[bx].pp              ; get ptr again
        pop     cx
        add     cx,cx                   ; words
        cmp     bx,offset bwnd          ; bottom window?
        je      getci6                  ; e = yes
        sub     si,cx                   ; top window, move back
        jnc     getcir2                 ; nc = still in buffer, continue
        mov     si,twnd.bend            ; else use end of buffer
        sub     si,cx                   ; minus length of a piece
        inc     si
getcir2:mov     twnd.pp,si              ; update ptr
        dec     twnd.lcnt               ; decrement # of lines in buffer
        clc                             ; make sure no carry
        ret
getci6:                                 ; bottom window
        add     si,cx                   ; words, move back (bot buf = reverse)
        cmp     si,bwnd.bend            ; still in buffer?
        jb      getci7                  ; b = yes
        mov     si,0                    ; else use beginning of buffer
getci7: mov     bwnd.pp,si              ; update ptr
        dec     bwnd.lcnt               ; decrement # of lines in buffer
        clc                             ; make sure no carry
        ret
getcirc endp

;
; CHKDSP - procedure to check for hardware support of 132 cols [dlk]
;
;  Supported hardware: EVA board from Tseng Labs w/132-col kit installed
;               Video 7 Vega Deluxe w/ 132X25.COM driver installed [tmk]
;               ATI EGA Wonder
;
;  The routine checks for the presence of a 132-column-capable adapter. If
;  one is found, its handler returns the proper vide mode in [CX]. The main-
;  line code then moves this to [AX] and issues the video interrupt.
;

chgdsp  proc    near
        push    es                      ; save all we use
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        mov     temp,ax                 ; save set/reset flag from msz
        mov     bx,portval              ; get flow control around mode sets
        mov     bx,[bx].flowc           ; bh=xon, bl=xoff, or both nulls
        mov     byte ptr temp+1,bh      ; save xon or null here
        cmp     bl,0                    ; no flow control?
        je      chgds0                  ; e = none
        mov     ah,bl                   ; get xoff
        call    outchr                  ; send it
         nop
         nop
         nop
        mov     ax,100                  ; wait 100 millisec for mode to finish
        call    pcwait
chgds0: call    ckteva                  ; try for Tseng Labs EVA
        jnc     chgds1                  ; nc = found
        call    ckv7vd                  ; try for Video 7 Vega Deluxe
        jnc     chgds1                  ; nc = found
        call    ckatiw                  ; try for ATI EGA Wonder
        jnc     chgds1                  ; nc = found
        jmp     chgdsx                  ; if not, exit
;
chgds1: mov     ax,cx                   ; get returned value in proper reg
        int     screen                  ; call the bios
        call    scrini                  ; reset parameters
        cmp     flags.modflg,0          ; is it enabled
        je      chgdsx                  ; e=not allowed
        test    yflags,modoff           ; is mode line toggled off
        jnz     chgdsx                  ; nz=yes its off so ignore it
        call    modlin                  ; make mode visible
chgdsx: cmp     byte ptr temp+1,0       ; no flow control?
        je      chgdsx1                 ; e = none
        mov     ah,byte ptr temp+1      ; get xon
        call    outchr                  ; send it
         nop
         nop
         nop
chgdsx1:pop     di                      ; restore what we saved
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        pop     es
        ret                             ; return to caller
chgdsp  endp

; Individual tests for various 132-column boards
                                        ;
                                        ; Tseng LABS EVA
ckteva: mov     ax,0c000h               ; seg addr for eva
        mov     es,ax                   ; set into es register
        mov     di,76h                  ; offset of board's string
        lea     si,tsngid               ; validation string
        mov     cx,tsnglen              ; length of validiation string
        cld
        repe    cmpsb                   ; compare strings
        jne     chnoad                  ; ne = strings differ
                                        ;
                                        ; an EVA board - check for 132 col kit
        cmp     byte ptr es:099h,0      ; check 132 col kit installed
        je      chnoad                  ; e=0=not installed
        jmp     catfnd                  ; do the mode change

chnoad: stc                             ; indicate adapter not present
        ret                             ; and exit
                                        ;
                                        ; ATI EGA Wonder
ckatiw: mov     ax,0c000h               ; seg addr for EGA Wonder
        mov     es,ax                   ; set into es register
        mov     di,012fh                ; offset of message in ROM
        lea     si,atiwid               ; offset of message here
        mov     cx,atilen               ; length of validation string
        cld
        repe    cmpsb                   ; compare strings
        jne     chnoad                  ; ne = strings differ
                                        ;
catfnd: mov     cx,0003h                ; prepare to reset video mode
        cmp     byte ptr temp,0         ; are we setting or resetting?
        je      ckexit                  ; e is reset, exit
        mov     cx,0023h                ; set to 132 cols (Set Mode 23H)
ckexit: clc                             ; carry clear means found
        ret
                                        ;
                                        ; Video 7 Vega Deluxe
ckv7vd: mov     ax,0c000h               ; seg addr for Vega rom bios
        mov     es,ax                   ; set into es register
        mov     di,002ah                ; offset of message in ROM
        lea     si,vid7id               ; offset of message here
        mov     cx,vid7len
        cld
        repe    cmpsb                   ; compare strings
        jne     chnoad                  ; ne = strings are different
                                        ;
        test    byte ptr es:[03ffeh],1  ; is this a 'Deluxe' Vega?
        jz      chnoad                  ; z = nope, can't do it
        mov     ah,35h                  ; DOS Get Vector
        mov     al,10h                  ; Bios video interrupt
        int     dos                     ; get it into es:bx
        mov     di,bx                   ; es:bx is returned int 10h entry pnt
        sub     di,5ah                  ; back offset to msg in 132X25.COM
        lea     si,vid7id               ; offset of validation message
        mov     cx,vid7len              ; length of validation string
        cld
cnv7fn1:repe    cmpsb                   ; Look for repeat of msg by 132X25.COM
        jne     cnv7fn2                 ; if different
        mov     cl,crt_mode             ; prepare to reset video mode
        mov     ch,0
        cmp     byte ptr temp,0         ; are we setting or resetting?
        je      ckexit                  ; e is reset, exit
        mov     cx,0000h                ; set to 132 cols (old 40x25)
        jmp     short ckexit            ; and exit

cnv7fn2:mov     ax,6f00h                ; check for VegaBios driver
        int     screen                  ;  run by ESU.EXE
        cmp     bx,'V7'                 ; Video 7 Bios presence response
        jne     chnoad                  ; ne = not there
        mov     ax,6f01h                ; al gets monitor type (mono,color,ega)
        int     screen
        mov     bx,51                   ; presume mono 132x25, page 0
        cmp     al,2                    ; 1=mono, 2=color, above=ega
        jb      cnv7fn3                 ; b = mono
        mov     bx,4fh                  ; presume med res color 132x25
        je      cnv7fn3                 ; e = med res color
        mov     bx,41h                  ; ega high res 132x25
cnv7fn3:push    bx
        mov     ah,0eh                  ; get current mode
        int     screen
        mov     ax,6f05h                ; set special mode found in bl
        cmp     byte ptr temp,0         ; resetting to 80 column mode?
        jne     cnv7fn4                 ; ne = no, setting 132x25
        mov     al,crt_norm             ; get normal mode
        mov     ah,0                    ; set mode
cnv7fn4:pop     bx                      ; recover special mode
        int     screen
        mov     cx,0f00h                ; a nop screen bios command
        clc
        ret

; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

RSKP    PROC    NEAR
        pop     bp
        add     bp,3
        push    bp
        ret
RSKP    ENDP

; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

code    ends

if1
        %out [End of pass 1]
else
        %out [End of assembly]
endif

        end
