DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦b0b5f0d62⟧ TextFile

    Length: 116489 (0x1c709)
    Types: TextFile
    Names: »msyibm.asm«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦71044c191⟧ »EurOpenD3/misc/kermit.ms-2.32.tar.Z« 
        └─⟦31f2d420d⟧ 
            └─⟦this⟧ »msyibm.asm« 

TextFile

        NAME msyibm
; File MSYIBM.ASM
; edit history:
; Last edit 30 Nov 1988
; 30 Nov 1988 Add SET TERM CLEAR screen clearing support.
; 28 Nov 1988 Accomodate Tseng Labs UltraPAK mono/Herc board w/132 cols.
;  132 column mode is 18h. Requires Tseng's BIGSCR.COM (use BIGSCR /R:25
;  to enable 132x25 feature). Thanks to Tseng Labs for technical support.
; 21 Nov 1988 Version 2.32
; 14 Nov 1988 Write a space during lclini to obtain default screen colors.
; 12 Nov 1988 Add procs vtrmac and vtsmac to allow exit from Connect mode and
;  invokation of macros TERMINALR and TERMINALS by reception of escape seqs
;  in file mszibm.asm or by keyboard verbs.
; 7 Oct 1988 Reverse left/right arrow key codes when writing right to left.
; 24 Sept 1988 Make output to printer be buffered and flow controlled.
; 1 July 1988 Version 2.31
; 19 June 1988 Add Everex EVGA support, from Terry Kennedy.
; 10 June 1988 Add oldsp and procedure endcon to exit Connect mode if output
;  fails, mostly for networking (but we don't know that here).
; 23 May 1988 Add Everex EV-659 ega board test from Alex Zliu. Fixed incorrect
;  screen width assumption at startup.
; 29 March 1988 Include flag ttyact to group string bytes into one net packet,
;  thanks to Paul Fox of AT&T.
; 23 March 1988 Add "fairness" word to let serial port deliver max chars
;  between kbd reads, for connect mode only. [jrd]
; 10 Feb 1988 Revise getcirc and vtscrX routines to do proper scrolling with
;  MS Window 1.0x/2.0x [jrd].
; 9 Feb 1988 Mode line again. Make flags.modflg 0 for off, 1 for on and owned
;  by Kermit, and 2 for on and owned by remote host (toggling suppressed).
; 25 Jan 1988 Add global byte SCROLL, set in msz, to control emulator screen
;  scrolling for higher speeds. [jrd]
; 5 Jan 1988 Restore cursor codes broken by Tek code additions. [jrd]
; 1 Jan 1988 version 2.30

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

        public  vtemu, crt_mode, scbattr, refresh, low_rgt      ; data
        public  savescr, restscr, pntchr, pntchk, pntflsh       ; code
        include mssdef.h

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

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


datas   segment public 'datas'
        extrn flags:byte, mar_top:byte, mar_bot:byte, portval:word
        extrn filtst:byte, dmpname:byte, kbdflg:byte, rxtable:byte
        extrn anspflg:byte, tekflg:byte, scroll:byte, ttyact:byte
        extrn holdscr:byte, taklev:byte, takadr:word, mcctab:byte

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

vid7id  db      'VEGA BIOS Code, '      ; Video 7 Vega version string subset
vid7len equ     $-vid7id                ; length of string
vid7id2 db      'Video Seven BIOS Code, ' ; Video 7 VGA board
vid7len2 equ    $-vid7id2
atiwid  db      'ATI EGA Wonder Bios,'  ; ATI EGA wonder version string subset
atilen  equ     $-atiwid                ; length of string, inc terminator
tsngid  db      'Tseng'                 ; Tseng Labs EVA (& Orchid Designer)
tsnglen equ     $-tsngid
evrxid  db      'Everex'                ; Everex Micro Enhancer Deluxe EGA
evrxlen equ     $-evrxid
evgid   db      'VGA EV673'             ; Everex EVGA EV-673
evglen  equ     $-evgid
ega_mode db     0                       ; non-zero if IBM EGA is in use
tvhere  equ     0feh                    ; Topview active query
tvsynch equ     0ffh                    ; Topview resynch request
tv_segs dw      ?                       ; Topview virtual screen, segment
tv_sego dw      ?                       ; and offset
tv_mode db      0                       ; flag, 0 = no Topview
savadr  dw      2 dup (?)               ; offset then segment of saved screen
savflg  dw      0                       ; low_rgt at time of screen save

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


vtemu   emulst  <>                      ; emulator flags
ansflgs db      0                       ; ANSI flags
trmtyp  db      0                       ; most recent terminal type
mtty    db      '  TTY   '              ; no terminal type (mode line)
fairness dw     0
lincur  dw      ?                       ; cursor type save area
scbattr db      ?                       ; Screen background attribute
oldattr db      ?                       ; screen attributes at init time
curattr db      ?                       ; current attribute
oldsp   dw      0                       ; offset to longjmp to for i/o failure
temp    dw      ?                       ; scratch storage
modtemp db      0                       ; temp to hold Kermit modeline status
captrtn dw      ?                       ; routine to call for captured output
dmphand dw      -1                      ; screen dump file handle
dumplen equ     132
dumpbuf db      dumplen dup (?), cr, lf ; 134 byte dump work buffer
dumpsep db      FF,cr,lf                ; screen image separators
dmperr  db      ' Cannot open file to save screen to disk $'
crlf    db      cr,lf,'$'
flowon  db      0                       ; flow control chars xon
flowoff db      0                       ;  and xoff (or both null if none)
pntmsg  db      'Printer not ready, printing request skipped.'
pntmsgl equ     $-pntmsg                ; length of pntmsg
pntptr  dw      dumpbuf                 ; pointer to next free byte in buffer

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

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

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

twnd    cbuf    <>                      ; top screen spill-buffer struct
bwnd    cbuf    <>                      ; bottom screen spill buffer struct
vtrname db      'TERMINALR'             ; a macro name, must be Upper Case
vtrlen  equ     $-vtrname
vtsname db      'TERMINALS'             ; a macro name, must be Upper Case
vtslen  equ     $-vtsname

vtmacname dw    vtrname                 ; pointer to selected macro name
vtmaclen db     vtrlen
datas   ends

code    segment public 'code'
        extrn   beep:near, prtchr:near, outchr:near, sbrk:near, pcwait:near
        extrn   isfile:near, strlen:near, strcpy:near   ; in mssfil
        extrn   anstty:near,ansini:near,ansrei:near     ; in mszibm
        extrn   anstat:near,anskbi:near,ansdsl:near     ; in mszibm
        extrn   ans52t:near, vsinit:near                ; in mszibm
        extrn   msuinit:near, keybd:near                ; in msuibm
        extrn   tekini:near,tekcls:near,tekemu:near,tekend:near ;in msgibm
        extrn   tekrint:near
        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
        int     screen                  ; set cursor in case it moved
        test    flags1,inited           ; have we run yet?
        jz      scrin7                  ; z = no, so no saved screen yet
        call    restscr                 ; restore screen
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
        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
                        ; alternate entry to write an alternate mode line
modwrt: push    cx
        push    si                      ; save mode line and size
        mov     ah,3                    ; read cursor position
        xor     bx,bx                   ; screen page 0
        int     screen
        mov     cursor,dx               ; save cursor position
        call    trmatt                  ; Get terminal attributes
        and     ah,77h                  ; omit blinking/bold attributes
        mov     bh,ah                   ; get video attribute
        mov     dx,low_rgt              ; right most column
        inc     dh                      ; refer to status line
        mov     ch,dh                   ; bottom line [dlk]
        mov     cl,0                    ; left col = 0 (first) [dlk]
        mov     ax,600h                 ; scroll to clear the line
        int     screen
        mov     dh,byte ptr low_rgt+1   ; refer to status line
        inc     dh
        xor     dl,dl                   ; left most column
        mov     bh,0
        mov     ah,2                    ; set cursor position
        int     screen
        pop     si
        pop     cx                      ; restore these
        cmp     cl,crt_cols             ; mode line longer than screen?
        jbe     modl6                   ; le = no
        mov     cl,crt_cols             ; else do just one line's worth
        dec     cx                      ; don't let screen scroll
modl6:  cld
        lodsb                           ; get a byte
        mov     ah,14                   ; write to terminal
        mov     bh,0                    ; page 0
        int     screen
        loop    modl6                   ; write out entire mode line
        cmp     flags.vtflg,0           ; emulating?
        je      modl7                   ; e = no
        and     yflags,not modoff       ; update local flags (mode line on)
        mov     al,yflags               ; Yes - update flags also
        call    ansdsl                  ; get extras from emulator
modl7:  mov     dx,cursor
        mov     ah,2
        mov     bh,0
        int     screen                  ; put cursor back where it belongs
        ret
modlin  endp

clrmod  proc    near                    ; clear mode line
        call    trmatt                  ; Get terminal screen attributes
        mov     bh,al                   ; Use screen background attribute
        mov     ax,600h                 ; blank window
        mov     dx,low_rgt              ; right most column
        inc     dh                      ; refer to status line
        mov     cx,dx                   ; bottom line [dlk]
        xor     cl,cl                   ; left most column
        int     screen                  ; clear mode line
        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:  call    savescr                 ; save screen
        mov     ax,0600h                ; clear mode line with old attributes
        mov     bh,oldattr              ; attributes
        mov     dx,low_rgt              ; right most column
        inc     dh                      ; refer to status line
        mov     cx,dx                   ; bottom line [dlk]
        xor     cl,cl                   ; left most column
        int     screen                  ; clear the mode line
        mov     ah,oldattr              ; attributes at init time
        mov     scbattr,ah              ; background = original state
                                        ; for ega in non-standard # lines
        cmp     ega_mode,0              ; ega board active?
        je      quit2                   ; e = no
        cmp     byte ptr low_rgt+1,23   ; is screen standard length?
        je      quit2                   ; e = yes, so regular cursor set is ok
        push    es                      ; turn off ega cursor emulation
        mov     ax,40h                  ; byte 40:87H is ega Info byte
        mov     es,ax
        push    es:[87h]                ; save info byte around call
        or      byte ptr es:[87h],1     ; set emulation off (low bit = 1)
        mov     cx,lincur               ; cursor shape to set
        mov     ah,1                    ; set the shape
        int     screen                  ;   back to starting value
        pop     es:[87h]                ; recover original Info byte
        pop     es                      ; and our work reg
        jmp     short quit3             ; skip regular mode cursor setting
quit2:                                  ; for regular sized screen
        mov     cx,lincur               ; cursor type at startup
        mov     ah,1
        int     screen                  ; restore cursor type
quit3:  mov     ah,2                    ; Position cursor
        mov     bh,0                    ; Page 0
        mov     dx,low_rgt              ; bottom line
        inc     dh                      ; status line position
        xor     dl,dl                   ; left most column
        int     screen                  ; Do it
        mov     al,yflags
        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
        call    endwnd                  ; restore screen before writing [dlk]
outnp6: cmp     flags.vtflg,0           ; emulating a terminal?
        jnz     outnop1                 ; nz = yup, go do something smart
        test    yflags,trnctl           ; debug? if so use Bios tty mode
        jz      outnp4                  ; z = no
        mov     ah,biostty              ; Bios tty screen write
        cmp     al,7fh                  ; Ascii Del char or greater?
        jb      outnp1                  ; b = no
        je      outnp0                  ; e = Del char
        push    ax                      ; save the char
        mov     al,7eh                  ; output a tilde for 8th bit
        int     screen
        pop     ax                      ; restore char
        and     al,7fh                  ; strip high bit
outnp0: cmp     al,7fh                  ; is char now a DEL?
        jne     outnp1                  ; ne = no
        and     al,3fH                  ; strip next highest bit (Del --> '?')
        jmp     outnp2                  ; send, preceded by caret
outnp1: cmp     al,' '                  ; control char?
        jae     outnp3                  ; ae = no
        add     al,'A'-1                ; make visible
outnp2: push    ax                      ; save char
        mov     al,5eh                  ; caret
        int     screen                  ; display it
        pop     ax                      ; recover the non-printable char
outnp3: int     screen
        ret
outnp4: cmp     al,bell                 ; bell (Control G)?
        jne     outnp5                  ; ne = no
        jmp     beep                    ; use short beep, avoid char loss
outnp5: mov     dl,al                   ; write without intervention
        mov     ah,conout
        int     dos                     ; else let dos display char
        ret

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
        clc                             ; clear carry bit
        jb      pntchrx                 ; b = no, just return
        jmp     pntflsh                 ; go flush the buffer
pntchrx: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
        mov     cx,pntmsgl              ; length
        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
        call    scrseg                  ; get screen segment in ax and es:di
        push    ax                      ; save screen segment
        mov     si,0
        mov     di,scrsav               ; place to put screen (memory buff)
        mov     savadr+2,di             ; working seg address for restore
        mov     savadr,0                ; and no offset for memory buffer

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

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

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

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

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

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

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


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

; 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
        jcxz    vscru3                  ; z = nothing to do
        cmp     mar_top,0               ; scrolling the top screen line?
        ja      vscru2                  ; a = no. don't save anything
        push    si
        push    di
        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
        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
        int     screen                  ;  and do in parts
        pop     ax
        sub     al,bl
        jmp     short vscru2a           ; do next part
vscru2b:int     screen                  ; scroll up that region
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     al,2                    ; 1 = mono, 2 = color, above = ega
        jb      cnv7fn3                 ; b = mono
        mov     bx,4fh                  ; presume med res color 132x25
        je      cnv7fn3                 ; e = med res color
        mov     bx,41h                  ; ega high res 132x25
cnv7fn3:push    bx
        mov     ah,0eh                  ; get current mode
        int     screen
        mov     ax,6f05h                ; set special mode found in bl
        cmp     byte ptr temp,0         ; resetting to 80 column mode?
        jne     cnv7fn4                 ; ne = no, setting 132x25
        mov     al,crt_norm             ; get normal mode
        mov     ah,0                    ; set mode
cnv7fn4:pop     bx                      ; recover special mode
        int     screen
        mov     cx,0f00h                ; a nop screen bios command
        jmp     ckexit

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