    NAME ccyibm
; File CCYIBM.ASM
; Edit History:
;   Mar.21,1991:
;    * Add MASM Option /DCGA in serval places. The goal is to make ZUnet-PBX 
;        can be run in different CCDOS versions(Such as: CCDOS213,LIANXIAN,
;        STCDOS,CGA17,etc.) on different video adapers( such as CGA,EGA,VGA 
;        and MDA).
;      In this program Macro Conditions "IFDEF  CGA ... ENDIF" and "IFNDEF CGA 
;        ... ENDIF" are used.
;      Option CGA is used only when you want to build a program used in PC/XT
;        (CGA or MDA adapter).Maybe it can be used in VGA adapter. [zqf]
;   1990:
;    * Program is modified in many places to suit for different CCDOS versions.
;        You can check them by indexing 'zqf' or 'CCDOS'. [zqf]

;CHINESE
ifdef   MSDOS
        include msyibm.dat
else
        include ccyibm.dat
endif

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
        extrn   tekrint:near
ifdef   DEBG
;        extrn   debgp:near
endif
        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!

        call    scrseg                  ; test running in an Environment
        call    scrmod                  ; read video state, get crt_mode
        mov     ax,low_rgt              ; lower right corner of screen
        mov     al,crt_mode
        mov     crt_norm,al             ; save as normal mode
        mov     savflg,ax
        mov     ah,conout               ; output a space to set background
        mov     dl,' '                  ; and foreground screen colors
        int     dos
        mov     ah,3                    ; get current cursor position into dx
        mov     bh,0
        int     screen
        dec     dl                      ; backup to the space
        mov     ah,2                    ; set cursor
        int     screen
        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
        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     ch,0
        mov     cl,byte ptr low_rgt
        inc     cl                      ; 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    vsinit                  ; init terminal emulator module MSZ
        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     lclyin3                 ; 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     lclyin3                 ; 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      lclyin3                 ; e = yes
        mov     crt_norm,7              ; else use mode 7 for mono
lclyin3:ret
lclyini endp

scrini  proc    near                    ; init screen stuff
        call    scrseg                  ; update screen segment tv_seg(s/o)
        call    scrmod                  ; get screen mode, low_rgt
        mov     ah,3                    ; get cursor position and type
        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
        jne     scrin1                  ; ne = different, initialize
        jmp     scrin3                  ; same, skip initialization
                                        ; Re-initialize screen buffers
scrin1: 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

        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     scrin2                  ; 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     scrin2                  ; 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      scrin2                  ; e = yes
        mov     crt_norm,7              ; else use mode 7 for mono
scrin2: mov     ah,oldattr              ; get init time attributes
        mov     curattr,ah              ; and set nice screen attribute
        mov     scbattr,ah
        mov     cursor,0                ; cursor to upper left corner
        cmp     flags.vtflg,0           ; terminal type of None?
        ja      scrin3                  ; a = no, emulating
        mov     dh,byte ptr low_rgt+1
        inc     dh                      ; bottom
        mov     dl,0                    ;  left corner
        jmp     short scrin5
                                        ; Common finish code
scrin3: mov     dx,cursor               ; use old cursor, if any
        cmp     flags.vtflg,0           ; emulating?
        je      scrin4                  ; e = no
        cmp     dh,byte ptr low_rgt+1   ; past logical end of screen?
        jbe     scrin4                  ; be = no, keep going
        mov     dh,byte ptr low_rgt+1   ; yes, just use lower right corner
scrin4: cmp     dl,byte ptr low_rgt     ; maybe past right margin
        jbe     scrin5                  ; be = no, use the way it is
        mov     dl,byte ptr low_rgt
scrin5: mov     cursor,dx               ; init cursor
        mov     ah,2                    ; set cursor position
        xor     bh,bh                   ; page zero
; ---------don't set cursor in CCDOS. Dec.12,1990 [zqf]
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        cmp     isccdos,1               ; is in CCDOS ?
        je      scrin6                  ; e = yes, skip 
ENDIF
        int     screen                  ; set cursor in case it moved
scrin6:
; -----------
        test    flags1,inited           ; have we run yet?
        jz      scrin7                  ; z = no, so no saved screen yet
        call    restscr                 ; restore screen[zqf]Dec.13,1990
scrin7: or      flags1,inited           ; remember we've run already
        cmp     flags.modflg,1          ; is mode line on and locally owned?
        ja      scrin10                 ; a = host owned, leave intact
        cmp     flags.vtflg,0           ; emulating a terminal?
        jne     scrin8                  ; ne = yes, can have mode line
        or      yflags,modoff           ; for no emulation say toggled off
        cmp     trmtyp,0                ; previous terminal type = none?
        jne     scrin9                  ; ne = no. need to clear mode line
        jmp     scrin10                 ; yes, let 25th line be intact
scrin8: cmp     flags.modflg,0          ; is mode line disabled?
        je      scrin9                  ; e = yes, clear it
        test    yflags,modoff           ; is mode line toggled off?
        jnz     scrin9                  ; nz = yes, clear the line
        call    modlin                  ; turn on mode line
        jmp     short scrin10
scrin9: call    clrmod                  ; ensure its off
scrin10:cmp     flags.vtflg,0           ; current terminal type = None?
        je      scrin12                 ; e = yes, nothing to init
        mov     al,yflags               ; tell emulator we are back
        cmp     vtclear,0               ; screen need clearing?
        jne     scrin10a                ; yes, do emulator reinit now
        cmp     vtinited,inited         ; inited emulator yet?
        je      scrin11                 ; e = yes
        cmp     tekflg,0                ; Tek mode still active?
        jne     scrin12                 ; ne = yes, no re-init here
scrin10a:call   vtinit                  ; init it now
        mov     vtclear,0               ; say screen is clear
        jmp     short scrin12
scrin11:call    ansrei                  ; reinit the emulator
        call    ansflg                  ; and get its flags
scrin12:mov     al,flags.vtflg          ; current terminal type
        mov     trmtyp,al               ; place to remember it til next time
        cmp     flags.vtflg,tttek       ; Tek mode?
        je      scrin13                 ; e = yes
        cmp     tekflg,0                ; Tek mode active within DEC stuff?
        je      scrin14                 ; e = no
scrin13:call    tekini                  ; reinit to get graphics screen
scrin14:ret
scrini  endp

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

vtinit  proc    near
        mov     holdscr,0               ; clear holdscreen
        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     bx,argadr               ; Get address of argument block
        mov     dl,[bx].flgs
        and     dl,lclecho
        and     yflags,not lclecho
        or      yflags,dl
        mov     al,yflags               ; Pass the flags
        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
        or      dh,07H                  ; Just say 7 data bits
        test    flags.remflg,d8bit      ; eight bit display?
        jz      vtini1                  ; z = no
        inc     dh                      ; set low four bits to value 8
vtini1: call    ansini                  ; call startup routine in mszibm
vtinix: clc
        ret
vtini2: call    tekrint                 ; reinitialize Tek emulator
        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
  ; ************************** Change Connect Mode Line, Oct.8,1990 [zqf].
        cmp     isccdos, 0              ; if in MS-DOS or CC-DOS ?
        je      modl0                   ; e = in MS-DOS
        jmp     cmodl0                  ; in CC-DOS
  ; ***
  ; ******** in MS-DOS below
modl0:  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
        shl     al,1                    ; each is 4 bytes long
        shl     al,1
        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
  ; **** 
        jmp     modwrt
  ; ******** in CC-DOS below
cmodl0:  mov     al,esc_ch
        mov     cmodbuf.cm_echr,' '       ; first char is initial space
        mov     cmodbuf.cm_hlp,' '        ; goes here too
        cmp     al,32                   ; printable?
        jnb     cmodl1                   ; yes, keep going
        add     al,40h                  ; made printable
        mov     cmodbuf.cm_echr,5eh       ; caret, note control char
        mov     cmodbuf.cm_hlp,5eh
cmodl1:  mov     cmodbuf.cm_echr+1,al      ; fill in character
        mov     cmodbuf.cm_hlp+1,al
        mov     bx,argadr               ; get argument block
        mov     al,[bx].baudb           ; get baud bits
        mov     si,offset cunkbaud       ; assume unknown baud
        cmp     al,baudnsiz             ; too big?
        jnb     cmodl2                   ; nb = yes, use default
        mov     cl,size cm_baud          ; each is 5 bytes long
        mul     cl
        mov     ah,0
        add     ax,offset baudn
        mov     si,ax
cmodl2:  mov     cx,size cm_baud          ; length of baud space
        mov     di,offset cmodbuf.cm_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
        shl     al,1                    ; each is 4 bytes long
        shl     al,1
        mov     ah,0
        add     ax,offset cparnams       ; names of parity settings
        mov     si,ax
        mov     cx,4                    ; each is 4 long
        mov     di,offset cmodbuf.cm_par
        rep     movsb
        mov     si,offset cremmsg        ; Assume remote echoing
        test    yflags,lclecho          ; Is remote side echoing?
        jz      cmodl4                   ; Yes, keep going
        mov     si,offset clclmsg        ; Else it's local echoing.
cmodl4:  mov     cx,4                    ; size of on/off
        mov     di,offset cmodbuf.cm_echo
        rep     movsb
        mov     al,portno               ; communications port
        cmp     al,' '                  ; binary (non-printable)?
        jae     cmodl5                   ; ae = no, ascii
        add     al,'0'                  ; convert to ascii
cmodl5:  mov     cmodbuf.cm_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 cmodbuf.cm_term ; destination
        rep     movsb                   ; copy it in
        mov     cmodbuf.cm_prn,' '        ; assume not printing the screen
        mov     cmodbuf.cm_prn+1,' '
        mov     cmodbuf.cm_prn+2,' '
        test    anspflg,prtscr          ; doing a print the screen?
        jz      cmodl5a                  ; z = no
        mov     cmodbuf.cm_prn,'P'        ; yes. display PRN at end of line
        mov     cmodbuf.cm_prn+1,'R'
        mov     cmodbuf.cm_prn+2,'N'
cmodl5a: mov     cx,size cmodfrm          ; this is size of mode line
        mov     si,offset cmodbuf        ; mode line image
        pop     es
  ; **************************  Oct.8,1990 [zqf].
                        ; 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
;**** Modify to suit CCDOS. Sept 5,1990 [zqf]
        cmp     isccdos,1               ; if in CCDOS ?
        jne     modl5b                  ; ne = No, in MS-DOS
        mov     ax,cx                   ; in CCDOS
        mov     bx,dx
        call    atsclr                  ; clear mode line in CC-DOS
        jmp     modl5c 
modl5b: int     screen                  ; clear mode line in MS-DOS
modl5c:
;****
        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
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
;**** Modify to suit CCDOS. June 25,1990 [zqf]
        mov     ax,cx
        mov     bx,dx
        call    atsclr
;       int     screen                  ; clear mode line
;****
        or      yflags,modoff           ; turn on flag
        ret
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 regs
        push    bx
        mov     al,yflags
        call    anstat                  ; Get status and attributes
        mov     ansflgs,bh              ; Save
        test    ansflgs,dececho         ; does host want us to do local echo?
        jz      ansflg1                 ; z = no, use working default
        or      yflags,lclecho          ; turn on local echoing
ansflg1: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
        mov     bx,portval              ; port data structure address
        mov     bx,[bx].flowc           ; get flow control chars (bl=xoff)
        mov     flowon,bh
        mov     flowoff,bl              ; save for later
        mov     oldsp,sp                ; remember stack for i/o failure,
                                        ;  used by procedure  endcon
lp:     call    prtchr                  ; char at port?
         jmp    short lpinp             ; yes, go handle
         nop                            ; else look at kbd
lpkbd:  mov     fairness,0              ; say kbd was examined
        call    keybd                   ; call keyboard translator in msu
        jnc     lp                      ; nc = no char or have processed it
        jmp     short quit              ; carry set = quit connect mode
lpinp:  and     al,parmsk               ; apply 8/7 bit parity mask
        call    outtty                  ; print on terminal
        inc     fairness                ; say read port but not kbd, again
        cmp     fairness,100            ; this many port reads before kbd?
        jb      lp                      ; b = no, read port again
        jmp     short lpkbd             ; yes, let user have a chance too

quit:   
        call    pntflsh                 ; flush printer buffer
        call    tekend                  ; cleanup Tektronix mode [bjh]
        mov     ah,3                    ; get cursor position into dx
        xor     bh,bh                   ; page 0
        int     screen
        mov     cursor,dx               ; save position
        cmp     flags.vtflg,0           ; terminal type of none?
        ja      quit1                   ; a = yes
        test    yflags,modoff           ; is modeline still toggled off?
        jnz     quit1                   ; nz = yes
        call    clrmod                  ; clear it before storing screen
quit1:  nop
;****************** 
        call    savescr                 ; save screen in MS-DOS
;*******************
        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
;**** Modify to suit CCDOS. June 25,1990 [zqf]
        mov     ax,cx
        mov     bx,dx
        call    atsclr
;       int     screen                  ; clear mode line
;****
        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
; ---------don't set cursor in CCDOS. Dec.12,1990 [zqf]
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        cmp     isccdos,1               ; is in CCDOS ?
        je      quit4                  ; e = yes, skip 
ENDIF
        int     screen                  ; Do it
quit4:
; -----------
        mov     al,yflags
        and     al,not lclecho          ; don't copy host's echo flag
        mov     bx,argadr
        mov     ah,[bx].flgs            ; get user's flag settings
        and     ah,lclecho              ; clear all but local echo bit
        or      [bx].flgs,al            ; update flags in arg block
        ret
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
        call    pntchr                  ; queue char for printer
        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     vtroll,0                ; auto roll back allowed?
        jz      outnp6                  ; z = no, leave screen as is
        cmp     tekflg,0                ; Tek mode active?
        jne     outnp6                  ; ne = yes, skip screen rolling
        cmp     bwnd.lcnt,0             ; is screen rolled back? [dlk]
        je      outnp6                  ; e = no
; ---------don't set cursor in CCDOS. Dec.12,1990 [zqf]
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        cmp     isccdos,1               ; is in CCDOS ?
        je      outnpa                  ; e = yes, skip 
ENDIF
        call    endwnd                  ; restore screen before writing [dlk]
outnpa:
; -----------
outnp6: cmp     flags.vtflg,0           ; emulating a terminal?
        jne     outnop1                 ; ne = 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: push    ax
        int     screen
        pop     ax
        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

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
         jmp    endcon                  ; failure, end connection
         nop
        clc                             ; carry clear for success
        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
         jmp    endcon                  ; failure, end connection
         nop
        clc                             ; carry clear for success
        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
         jmp    endcon                  ; failure, end connection
         nop
        clc                             ; carry clear for success
        ret
outprt  endp

; Jump here to exit Connect mode and execute macros 'TERMINALR' (vtrmac) or
; 'TERMINALS' (vtsmac). Does nothing if macro does not exist.
; Preserves registers except ax. Returns to TELNET caller with 'C' in kbdflg.
vtrmac  proc    near                    ; RESET macro
        mov     ax,offset vtrname       ; select macro name
        mov     vtmacname,ax
        mov     vtmaclen,vtrlen         ; and its length
        jmp     short vtmacro           ; finish in common code
vtrmac  endp

vtsmac  proc    near                    ; SET macro
        mov     ax,offset vtsname
        mov     vtmacname,ax
        mov     vtmaclen,vtslen
        jmp     short vtmacro
vtsmac  endp

;
; Reference     Macro structure for     db      number of entries (mac names)
;  is file       table mcctab      |->  db      length of macroname, excl '$'
;  mssset.asm           each entry |->  db      'macroname','$'
;  where these                     |->  dw      offset of definition string
;  are stored.
;               Definition string in    db      length of <string with null>
;                buffer macbuf          db      'string with trailing null'
;
vtmacro proc    near                    ; common code for macros vtsmac,vtrmac
        push    bx
        push    cx
        push    si
        mov     bx,offset mcctab        ; table of macro names
        mov     cl,[bx]                 ; number of names in table
        xor     ch,ch
        jcxz    vtmacx                  ; z = empty table, do nothing
        inc     bx                      ; point to length of first name
vtmac2: mov     al,[bx]                 ; length of this name
        xor     ah,ah
        cmp     al,vtmaclen             ; length same as desired keyword?
        jne     vtmac3                  ; ne = no, search again
        mov     si,bx
        inc     si                      ; point at first char of name
        push    cx                      ; save name counter
        push    di                      ; save reg
        mov     cl,vtmaclen             ; length of name, excluding '$'
        xor     ch,ch
        mov     di,vtmacname            ; point at desired macro name
        push    es                      ; save reg
        push    ds
        pop     es                      ; make es use datas segment
        cld
        repe    cmpsb                   ; match strings
        pop     es                      ; need current si below
        pop     cx
        pop     di                      ; recover saved regs
        je      vtmac4                  ; e = matched
vtmac3: add     bx,ax                   ; step to next name, add name length
        add     bx,4                    ; + count, dollar sign, def word ptr
        loop    vtmac2                  ; try next name
vtmacx: pop     si                      ; no macro, return to Connect mode
        pop     cx
        pop     bx
        ret

vtmac4: cmp     taklev,maxtak           ; room in Take level?
        jge     vtmacx                  ; ge = no, exit with no action
        inc     taklev                  ; increment take level
        add     takadr,size takinfo     ; make a new Take entry/macro
        mov     bx,takadr               ; point to current macro structure
        inc     si                      ; skip dollar sign after name
        mov     si,[si]                 ; get definition address
        mov     [bx].takbuf,si          ; address of definition string struc
        mov     cl,[si]                 ; length byte of definition
        xor     ch,ch
        mov     [bx].takcnt,cx          ; number of chars in definition
        inc     si                      ; address of definition text proper
        mov     [bx].takptr,si          ; where to read next command char
        mov     [bx].taktyp,0ffh        ; flag as a macro
        pop     si
        pop     cx
        pop     bx
        jmp     endcon                  ; exit Connect mode
vtmacro endp

; Error recovery routine used when outchr reports unable to send character
;  or when vtmacro requests exiting Connect mode.
; Exit Connect mode cleanly, despite layers of intermediate calls.
endcon  proc    near
        mov     kbdflg,'C'              ; report 'C' to TERM's caller
        mov     sp,oldsp                ; recover startup stack pointer
                                        ; TERM caller's return address is now
                                        ; on the top of stack. A longjmp.
        jmp     quit                    ; exit Connect mode cleanly
endcon  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'
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      comarr                  ; z = yes
        mov     al,'D'                  ; reverse sense of keys
        jmp     short comarr
lfarr:  mov     al,'D'
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      comarr                  ; z = yes
        mov     al,'C'                  ; reverse sense of keys
comarr: push    ax                      ; save final char
        mov     ttyact,0                ; network, group chars for packet
        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
        mov     ttyact,1                ; network, restore tty active flag
        call    outprt                  ; Output to port (echo permitted)
        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     ttyact,0                ; network, group chars for packet
        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
        mov     ttyact,1                ; network, restore tty active flag
        call    prtbout                 ; Output to port
        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     ttyact,0                ; network, group chars for packet
        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: mov     ttyact,1                ; network, restore tty active flag
        call    prtbout                 ; send it
        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
        jmp     prtbout                 ; send without logging and local echo
snull   endp

khold:  xor     holdscr,1               ; toggle Hold screen byte for msx
        clc
        ret
                                        ; 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
        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,1          ; mode line enabled and owned by us?
        jne     trnm2                   ; ne = 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
trnm1:  and     yflags,not modoff       ; Clear flag first
        cmp     flags.vtflg,0           ; terminal type of none?
        ja      trnm3
        push    dx                      ; scroll screen to save bottom line
        mov     ah,prstr                ; for terminal type none
        mov     dx,offset crlf
        int     dos
        pop     dx
trnm3:  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

; Print on PRN the char in register al. On success return with C bit clear.
; On failure do procedure pntchk and return its C bit (typically C set).
; Uses buffer dumpbuf (screen dump).
pntchr  proc    near
        push    bx                      ; buffer the character
        mov     bx,pntptr               ; offset of next free byte in buffer
        mov     [bx],al                 ; store the character
        inc     bx                      ; update pointer
        mov     pntptr,bx               ; save pointer
        cmp     bx,offset dumpbuf+dumplen ; buffer full yet?
        pop     bx
        jb      pntchrx                 ; b = no, just return
        jmp     pntflsh                 ; go flush the buffer
pntchrx:clc                             ; clear carry bit
        ret
pntchr  endp

; Flush printer buffer. Return carry clear if success.
; On failure do procedure pntchk and return its C bit (typically C set).
; Uses buffer dumpbuf (screen dump).
pntflsh proc    near
        cmp     pntptr,offset dumpbuf   ; any text in buffer?
        jne     pntfls1                 ; ne = yes
        ret                             ; else nothing to do
pntfls1:push    ax
        push    bx
        push    cx
        push    dx
        mov     bx,portval
        mov     bx,[bx].flowc           ; get flow control chars (bl=xoff)
        mov     flowon,bh
        mov     flowoff,bl              ; save for later
        mov     al,bl                   ; get flow control char
        cmp     al,0                    ; flow control active?
        je      pntfls2                 ; e = no, not using xoff
        call    prtbout                 ; output xoff (al), no echo
pntfls2:mov     ah,write2
        mov     bx,4                    ; file handle for DOS printer PRN
        mov     cx,pntptr               ; next free byte in buffer
        mov     dx,offset dumpbuf       ; start of buffer
        mov     pntptr,dx               ; reset buffer pointer
        sub     cx,dx                   ; cx = current byte count
        jcxz    pntfls3                 ; z = empty, do nothing
        int     dos                     ; write buffer to printer
pntfls3:pushf                           ; save carry status bit
        mov     al,flowon
        cmp     al,0                    ; flow control active?
        je      pntfls4                 ; e = no, not using xon
        call    prtbout                 ; output xon (al), no echo
pntfls4:popf
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        jnc     pntflsx                 ; nc = success
        call    pntchk                  ; c = error (printer not ready)
pntflsx:ret
pntflsh endp

; Check for PRN (DOS's printer) being ready. If ready, return with C clear
; Otherwise, write Not Ready msg on mode line and return with C bit set.
; N.B. DOS Critical Error will occur here if PRN is not ready.  [jrd]
pntchk  proc    near
        push    dx
        push    cx
        push    ax
        mov     cx,10                   ; ten retries before declaring error
pntchk0:mov     ah,ioctl                ; get printer status, via DOS
        mov     al,7                    ; status for output
        push    bx
        mov     bx,4                    ; std handle for DOS system printer
        int     dos
        pop     bx
        jc      pntchk1                 ; c = call failed
        cmp     al,0ffh                 ; code for Ready?
        je      pntchk3                 ; e = yes, assume printer is ready
pntchk1:push    cx                      ; save counter, just in case
        mov     ax,100                  ; wait 100 millisec
        call    pcwait
        pop     cx
        loop    pntchk0                 ; and try a few more times
                                        ; get here when printer is not ready
        test    yflags,modoff           ; is mode line off?
        jnz     pntchk2                 ; nz = off, skip msg
        push    bx
        push    si
;        mov     si,offset pntmsg        ; say printer not ready
        mcmsgsi pntmsg, cpntmsg
        mov     cx,pntmsgl              ; length
        cmp     isccdos,0
        je      pntchk11
        mov     cx,cpntmsgl
pntchk11:
        call    modwrt                  ; write alternate mode line
        pop     si
        pop     bx
pntchk2:pop     ax
        pop     cx
        pop     dx
        stc                             ; say printer not ready
        ret
pntchk3:pop     ax
        pop     cx
        pop     dx
        clc                             ; say printer is ready
        ret
pntchk  endp

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

; computes screen location to ax, given row and col in [dh,dl], resp.

scrloc  proc    near
        mov     al,dh                   ; get row
        mul     crt_cols                ; multiply by number of columns
        add     al,dl                   ; plus current column number
        adc     ah,0                    ; ripple carry
        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]
; Sense crt_mode 18h as Tseng Labs UltraPAK mono board in 132 column mode.
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
        cmp     crt_mode,18h            ; Tseng UltraPAK mono board?
        je      csrty3                  ; e = yes, use mono cursor
        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
; ****************** if in CC-DOS mode? Nov.1990 [zqf]
        cmp     isccdos,1               ; if CC-DOS ?
        jne     savsc0                  ; ne = No.
IFNDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        call    savccscr                ; yes, call CCDOS screen save proc
ENDIF
        jmp     savsc4                  ; return
savsc0:
; **********************
        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
savsc4:
        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
; ****************** if in CC-DOS mode? Nov.1990 [zqf]
        cmp     isccdos,1               ; if CC-DOS ?
        jne     rstscr0                 ; ne = No.
IFNDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        call    rstccscr                ; yes, call CCDOS screen restore proc
ENDIF
        ret                             ; return
rstscr0:
; **********************
        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

;**************************** used in CC-DOS Nov.28,1990 [zqf]
; SAVCCSCR ---- called by <savescr> of module "ccyibm.asm".
;               which save screen char & attr in buffer pointed
;               by scrsav in CC-DOS. Nov 28,1990 [zqf]
; All registers are reserved.
;********************************

SAVCCSCR proc    near
        push    ax
        push    bx
        push    cx
        push    dx
        push    di
        push    es
        
        mov     ax,scrsav       ; buffer segment address, offset is zero
        mov     es,ax
        mov     di,0
        mov     savadr+2,es
        mov     savadr,di
; read current cursor
        mov     bh,0
        mov     ah,3
        int     10h             ; read current cursor pos. & type.
        mov     curpos,dx      ; saved in <curattr>
        mov     curtyp,cx      ;
; save screen
        mov     bh,0
        mov     dx,0
savccscr1:  mov     ah,2
        int     10h             ; set cursor position <DH,DL>---<row,col>
        mov     ah,8
        int     10h             ; read char & attr in current cursor pos.
        mov     es:[di],ax      ; save in scrbuf
        inc     dl
        cmp     dl,crt_cols     ; crt_cols:number of screen cols (typ 80)
        jl      savccscr2
        mov     dl,0
        inc     dh
        cmp     dh,crt_lins     ; crt_lins:number of rows-1 (typ 24)
        jg      savccscr3
savccscr2:
        inc     di
        inc     di
        jmp     savccscr1
savccscr3:  
        pop     es
        pop     di
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
SAVCCSCR endp
;*******************************

;**************************** used in CC-DOS Nov.28,1990 [zqf]
; RSTCCSCR ---- called by <restscr> of module "ccyibm.asm".
;               which restore screen char & attr in buffer pointed
;               by savadr in CC-DOS. Nov 28,1990 [zqf]
; All registers are reserved.
;********************************
RSTCCSCR  proc
        push    ax
        push    bx
        push    cx
        push    dx
        push    di
        push    es
        mov     ax,savadr+2             ; segment address of buffer
        mov     es,ax
        mov     di,savadr               ; offset address of buffer
; restore screen
        mov     bh,0
        mov     dx,0
rstccscr1:mov     ah,2
        int     10h             ; set cursor position <DH,DL>---<row,col>
        mov     ax,es:[di]      ; restore from scrbuf
        mov     bl,ah
        mov     cx,1
        mov     ah,9
        int     10h             ; write char & attr in current cursor pos.
        inc     dl
        cmp     dl,crt_cols     ; crt_cols:number of screen cols (typ 80)
        jl      rstccscr2
        mov     dl,0
        inc     dh
        cmp     dh,crt_lins     ; crt_lins:number of rows-1 (typ 24)
        jg      rstccscr3
rstccscr2:  
        inc     di
        inc     di              ; adjust pointer
        jmp     rstccscr1
rstccscr3:  
; set original cursor pos &type
        mov     bh,0
        mov     cx,curtyp
        mov     ah,1 
        int     10h             ; build cursor type
        mov     bh,0
        mov     dx,curpos
        mov     ah,2
        int     10h             ; set original cursor pos.
        pop     es
        pop     di
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
RSTCCSCR  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
        mcmsg   dmperr, cdmperr

        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
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
        cmp     crt_mode,18h            ; Tseng UltraPAK mono in 132 col?
        je      scrse1                  ; e = yes, use seg B000H
        mov     ax,0B800H               ; No - video memory is here on color
        cmp     crt_mode,12             ; graphics set?
        jb      scrse1                  ; b = no
        cmp     crt_mode,18             ; end of ordinary 640x480 graphics
        ja      scrse1                  ; a = no, assume CGA segment
        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: mov     tv_segs,es              ; save segment
        mov     tv_sego,di              ; and offset
        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 regs
        pop     ax
scrofx: ret
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 regs
        pop     dx
        pop     ax
scronx: ret
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 regs
        push    cx
        push    dx

        CALL    PATSCLR             ; CALL PROC TO CLEAR LINE

        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 regs
        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

; Screen clearing routine.Ver 2.00 Dec. 15,1989 [ZU]
; (Screen clearing by scroll whole bolck between <ah,al> and <bh,bl>
; Call      ax/     corrdinates of upon left location to be cleared.
;           <ah,al>--<row,col>
;       bx/     corrdinates of down right location to be cleared.
;           <bh,bl>--<row,col>
; Cord: ah=row [0-24], al = col [0-79]. Preserves all registers. [zqf]

patsclr proc    near
    push    ax
    push    bx
    push    cx
    push    dx
    push    si
    push    di
; check if clear block or a line ?
    cmp bh,ah
    jg patsclr_b     ; le= clear a block more than one line
    
; clear a block in one line
; read screen mode
patsclr_l:
    push    ax
    push    bx
    mov ah,15   ;state
    int video
    mov activepage,bh
;    mov cols,ah
    pop bx
    pop ax
; save current cursor
    push    ax
    push    bx
    mov bh,activepage
    mov ah,readcur
    int video
    mov currow,dh
    mov curcol,dl
    mov curtype,cx
    pop bx
    pop ax
; compute number of chars to clear in cx
    push    ax
    xor cx,cx
    mov dx,0
patscl1:    cmp bh,ah
    jle patscl2
    mov dl,80       ;cols
    sub dl,al
    add cx,dx
    xor al,al
    inc ah
    jmp patscl1
patscl2:    cmp bl,al
    jl  patscl3
    sub bl,al
    mov bh,0
    add cx,bx
    inc cx
patscl3:    pop ax
    cmp cx,0
    jle patscl10
; set cursor at start location of clearing area
    mov dx,ax
    mov bh,activepage
    mov ah,setcur
    int video
; clear screen < CX__number of chars >
    mov al,' '      ;space
    mov bh,activepage
    mov bl,scbattr
;    mov ah,writech  ; ????? different with 'writeach'
    mov ah,writeach
    int video

; restore current cursor
    mov dh,currow
    mov dl,curcol
    mov bh,activepage
    mov ah,setcur
    int video

patscl10:
    pop di
    pop si
    pop dx
    pop cx
    pop bx
    pop ax
    ret

; scroll window at location <ah,al> to <bh,bl>
patsclr_b:
    mov cx,ax
    mov dx,bx
    mov bh,scbattr
    mov al,0
    mov ah,06h
    int video
    jmp patscl10
patsclr endp

; Scrolling routines.  vtscru scrolls up, vtscrd scrolls down 'scroll'
; rows. The top line is saved in the circular buffer before scrolling up.
; When running under an Environment control number of line positions moved
; to be less than scrolling region. [jrd]
; 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     ah,7                    ; scroll down
        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
        mov     bl,dh
        sub     bl,ch                   ; region size - 1 line
        mov     al,scroll               ; number of lines to scroll, from msz
vscrd1: cmp     al,bl                   ; want to scroll more that than?
        jbe     vscrd2                  ; be = no
        push    ax
        mov     al,bl                   ; limit to region-1 for Windows
        int     screen                  ;  and do in parts
        pop     ax
        sub     al,bl                   ; get remainder
        jmp     short vscrd1            ; do next part
vscrd2: int     screen                  ; scroll it down
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret

; Screen scroll up one line (text moves up) for terminal emulator use.
; When running under an Environment control number of line positions moved
; to be less than scrolling region. [jrd]

vtscru: push    ax                      ; Upgraded by  [jrd]
        push    bx
        push    cx
        push    dx
        mov     cl,scroll               ; number of lines to scroll
        mov     ch,0
        cmp     cx,0
        jnz     vscru0
        jmp     vscru3                  ; z = nothing to do
vscru0:
        cmp     mar_top,0               ; scrolling the top screen line?
        ja      vscru2                  ; a = no. don't save anything
        push    si
        push    di
;******** test for CCDOS. Dec.12,1990 [zqf]
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
    cmp     isccdos,1               ; if CCDOS ?
    je      vscru1a                 ; e = yes, in CCDOS, skip
ENDIF
        call    scroff                  ; turn off color screen
        mov     si,tv_sego              ; screen offset for es:si
        mov     bx,offset twnd          ; put lines in top window buffer
vscru1: push    cx                      ; save count
        call    putcirc                 ; put screen line in circular buffer
        pop     cx
        loop    vscru1                  ; save 'scroll' number of lines
        call    scron                   ; turn on screen again
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
vscru1a:
ENDIF
;********
        pop     di
        pop     si                      ; now scroll the visible screen
vscru2: mov     ah,6                    ; scroll up
        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              ; attributes
        mov     bl,dh
        sub     bl,ch                   ; region size - 1 line
        mov     al,scroll               ; number of lines to scroll, from msz
vscru2a:cmp     al,bl                   ; want to scroll more that than?
        jbe     vscru2b                 ; be = no
        push    ax
        mov     al,bl                   ; limit to region - 1 for Windows
;******** test for CCDOS. Dec.12,1990 [zqf]
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        cmp     isccdos,1               ; if CCDOS ?
        je      vscru2c                 ; e = yes, in CCDOS, skip
ENDIF
        int     screen                  ;  and do in parts
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        jmp     vscru2d                 ; in MSDOS
vscru2c:
        push    dx
        mov     dl,0dh
        mov     ah,2
        int     21h
        mov     dl,0ah
        mov     ah,2
        int     21h
        pop     dx
vscru2d:
ENDIF
;********
        pop     ax
        sub     al,bl
        jmp     short vscru2a           ; do next part
vscru2b:
;******** test for CCDOS. Dec.12,1990 [zqf]
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        cmp     isccdos,1               ; if CCDOS ?
        je      vscru2e                 ; e = yes, in CCDOS, skip
ENDIF
        int     screen                  ;  and do in parts
IFDEF   CGA         ; Add Option CGA to servered screen.Mar.21,1991 [zqf]
        jmp     vscru2f                 ; in MSDOS
vscru2e:
        push    dx
        mov     dl,0dh
        mov     ah,2
        int     21h
        mov     dl,0ah
        mov     ah,2
        int     21h
        pop     dx
vscru2f:
ENDIF
;********
vscru3: pop     dx                      ; Restore the rest of the regs
        pop     cx
        pop     bx
        pop     ax
        ret

;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    scroff                  ; turn off color screen
        mov     bx,offset twnd          ; this is where it goes
        mov     si,tv_sego              ; screen offset for es:si
        call    putcirc                 ; put screen line in circular buffer
        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
        mov     dx,low_rgt
        mov     dl,0                    ; location is lower left corner
        call    scrloc                  ; get count from display start
        mov     di,ax
        push    es
        mov     bx,tv_segs              ; get screen's segment into, es:di
        mov     es,bx                   ; segment
        add     di,tv_sego              ; 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


;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    scroff                  ; turn off screen
        mov     dx,low_rgt              ; from screen location, row
        mov     dl,0                    ; starting in col 0
        call    scrloc                  ; get offset in display buffer in ax
        mov     si,tv_sego              ; screen offset for es:di
        add     si,ax                   ; source addr in display buffer es:si
        mov     bx,offset bwnd          ; buffer to use (bottom window)
        call    putcirc                 ; copy bottom screen line to circ buf
        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
        push    es
        mov     di,tv_segs              ; screen segment
        mov     es,di
        mov     di,tv_sego              ; screen offset, for es:di
        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 regs
        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
getci1:                                 ; top and bottom window common code
        mov     cl,crt_cols             ; # of chars to copy
        xor     ch,ch
        mov     si,[bx].pp              ; this is source
        push    si                      ; save around calls
        push    cx                      ; save around calls
        cld                             ; set direction to forward
        push    ds                      ; save original ds
        mov     ax,[bx].orig            ; use seg address of buffer for si
        mov     ds,ax
        rep     movsw                   ; destination = screen at es:di
        pop     ds                      ; recover original data segment
        pop     cx                      ; recover word count
        call    scrsync                 ; synch Topview
        pop     si                      ; get ptr again
        add     cx,cx                   ; words
        cmp     bx,offset bwnd          ; bottom window?
        je      getci7                  ; e = yes
        sub     si,cx                   ; top window, move back
        jnc     getci6                  ; nc = still in buffer, continue
        mov     si,twnd.bend            ; else use end of buffer
        sub     si,cx                   ; minus length of a piece
        inc     si
getci6: mov     twnd.pp,si              ; update ptr
        dec     twnd.lcnt               ; decrement # of lines in buffer
        clc                             ; make sure no carry
        ret
getci7:                                 ; bottom window
        add     si,cx                   ; words, move back (bot buf = reverse)
        cmp     si,bwnd.bend            ; still in buffer?
        jb      getci8                  ; b = yes
        mov     si,0                    ; else use beginning of buffer
getci8: 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
;               Tseng Labs UltraPAK mono/Herc board w/132 column modes.
;               Video 7 Vega Deluxe w/ 132X25.COM driver installed [tmk]
;               and VGA board, ATI EGA Wonder, Everex ev-659 and fvga-673.
;  The routine checks for the presence of a 132-column-capable adapter. If
;  one is found, its handler returns the proper video 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     ah,flowoff              ; get xoff
        cmp     ah,0                    ; flow control?
        je      chgds0                  ; e = none
        call    outchr                  ; send it
         nop                            ; avoid serial port interrupts while
         nop                            ; doing many rep scasb's below
         nop
        call    savescr                 ; save current screen
        mov     ax,40                   ; wait 40 millisec before video tests
        call    pcwait                  ; so don't mix screen and port intrpts

chgds0: call    ckteva                  ; try Tseng Labs EVA
        jnc     chgds1                  ; nc = found
        call    ckv7vd                  ; try Video 7 EGA Deluxe and VGA
        jnc     chgds1                  ; nc = found
        call    ckatiw                  ; try ATI EGA Wonder
        jnc     chgds1                  ; nc = found
        call    ckevrx                  ; try Everex Micro Enhancer Deluxe
        jnc     chgds1                  ; nc = found
        call    ckevga                  ; try Everex EVGA-673
        jnc     chgds1                  ; nc = found
        jmp     chgdsx                  ; if not, exit
                                        ; Perform mode change
chgds1: mov     ax,cx                   ; get returned value in proper reg
        int     screen                  ; call the bios
        cmp     flags.modflg,1          ; is mode line enabled?
        jbe     chgds2                  ; be = yes, and off or locally owned
        mov     flags.modflg,1          ; remove foreign ownership
chgds2: call    scrini                  ; reset parameters
chgdsx: mov     ah,flowon               ; get flowon byte
        cmp     ah,0                    ; using flow control?
        je      chgdsx1                 ; e = no
        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 and UltraPAK
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
        je      ckteva2                 ; e = strings match
        mov     ax,4d00h                ; check for UltraPAK mono driver
        int     screen
        cmp     ax,5aa5h                ; driver signature?
        jne     chnoad                  ; ne = no
        mov     cx,7                    ; default to mono (7) for this board
        cmp     byte ptr temp,0         ; setting 132 columns?
        je      ckteva1                 ; e = resetting to normal
        mov     cx,18h                  ; set to 132 cols (Set Mode 18H)
ckteva1:clc                             ; carry clear means found
        ret

ckteva2:                                ; 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
        je      cnv7fn0                 ; e = same
        mov     di,002ah                ; offset of ident string
        mov     si,offset vid7id2       ; Video 7 VGA board
        mov     cx,vid7len2
        repe    cmpsb
        je      cnv7fn2                 ; e = found
cnv7fx: jmp     chnoad                  ; ne = strings are different
                                        ;
cnv7fn0: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
        cmp     bx,'V7'                 ; Video 7 Bios presence response
        jne     cnv7fx                  ; ne = not there
        mov     ax,6f01h                ; al gets monitor type (mono,color,ega)
        int     screen
        mov     bx,51h                  ; presume mono 132x25, page 0
        cmp     crt_lins,42             ; 43 lines active?
        jb      cnv7fn2a                ; b = no
        inc     bx                      ; use bx = 52h for 132x43
cnv7fn2a:
        cmp     al,10h                  ; analogue fixed freq (IBM 85xx)?
        je      cnv7fx                  ; e = yes, no 132 columns
        cmp     al,2                    ; 1 = mono, 2 = color, above = ega
        jb      cnv7fn3                 ; b = mono or unknown
        mov     bx,4fh                  ; presume med res color 132x25
        je      cnv7fn3                 ; e = med res color, al = 2
        mov     bx,41h                  ; ega high res 132x25, enhanced mons
        cmp     crt_lins,42             ; 43 lines active?
        jb      cnv7fn3                 ; b = no
        inc     bx                      ; use bx = 42h for 132x43
cnv7fn3: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
        cmp     crt_lins,42             ; 43 lines active?
        jb      cnv7fn4                 ; b = no
        mov     bl,40h                  ; use Video 7 mode 40h 80x43 for color
        mov     ax,6f05h                ; and do special mode set
cnv7fn4:int     screen                  ; special mode is in bl
        mov     cx,0f00h                ; a nop screen bios command
        clc
        ret

ckevrx: mov     ax,0c000h               ; seg addr for Everex EV-659
        mov     es,ax                   ; set into es register
        mov     di,0047h                ; offset of message in ROM
        lea     si,evrxid               ; offset of message here
        mov     cx,evrxlen              ; length of validation string
        cld
        repe    cmpsb                   ; compare strings
        jne     ckfnr2                  ; ne = strings differ
        mov     ah,crt_lins             ; we recognize either 44 or 25 rows
        cmp     ah,43                   ; equal to 44-1 rows?
        jne     ckfnr1                  ; ne = no
        mov     cx,0070h                ; Everex extended mode ident
        mov     bl,09h                  ; prepare to reset video mode to 80x44
        cmp     byte ptr temp,0         ; are we setting or resetting?
        je      ckfnr4                  ; e is reset, exit
        mov     bl,0bh                  ; 132x44
        jmp     ckexit
ckfnr1: cmp     ah,24                   ; equal to 25-1 rows?
        je      ckfnr3                  ; e = yes
ckfnr2: jmp     chnoad                  ; ne = no
ckfnr3: mov     cx,0003h                ; prepare to reset video mode
        cmp     byte ptr temp,0         ; are we setting or resetting?
        je      ckfnr4                  ; e is reset, exit
        mov     cx,0070h                ; Everex extended mode ident
        mov     bl,0ah                  ; 132x25
ckfnr4: jmp     ckexit
ckevga: mov     ax,0c000h               ; Everex FVGA-673, rom segment
        mov     es,ax
        mov     di,76h                  ; offset in rom for board's id string
        lea     si,evgid                ; id string
        mov     cx,evglen               ; length of id string
        cld
        repe    cmpsb                   ; do they match?
        jne     ckevg2                  ; ne = no
        mov     cx,3                    ; prepare to reset video mode
        cmp     byte ptr temp,0         ; setting or resetting mode?
        je      ckevg1                  ; e = resetting, exit
        mov     cx,0070h                ; mode for 132x25
        mov     bl,0ah                  ; Everex mode 0ah
ckevg1: clc
        ret
ckevg2: stc                             ; say board not found
        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
