        NAME    mszibm
; File MSZIBM.ASM
        page 60,132
; Terminal emulator module for IBM PC's and compatibles. Emulates Heath-19,
; VT52, and VT102. Original version done by James Harvey, Indiana Purdue
; Univ, for MS Kermit 2.27. Taken from there by Joe Doupnik, Utah State Univ
; for MS Kermit 2.29 et seq.
; Edit history
; Last edit: 1 Jan 1988
; 6 Jan 1988 Remove erasing into mode line on to-end-of-screen calls. [jrd]
; 1 Jan 1988 version 2.30
; 29 Dec 1987 Absorb escape sequences of the form ESC [ ... <40h to 7fh>
;  to sense but not act on unknown legally formatted ANSI escapes. [jrd]
; 28 Dec 1987 Add corrections from Frank da Cruz: home cursor on select/desel
;  origin mode, make select/deselect ansi mode return to US ascii graphics
;  rendition sets (where is this item documented?). [jrd]
; 12 Dec 1987 Sense denyflg to supress automatic Tek mode when ESC Control-L
;  is received; part of ENABLE/DISABLE command. [jrd]
; 4 Dec 1987 Strip high bit of chars within escape sequences, test for end of
;  transparent print without high bit but playback 8 bit intermediates. [jrd]
; 16 Nov 1987 Add multiple timed retries on printer status. [jrd]
; 5 Nov 1987 Add Tektronix terminal type, including ESC FF branch to Tek
; mode and toggling among terminal types. [jrd]
; 28 Oct 1987 Remove NUL and DEL chars from normal logging and display,
;  ignore Control-X and -Z unless in an esc sequence. [jrd]
; 3 Oct 1987 Remove cursor action for DEL when local echo is on. [jrd]
; 11 Sept 1987 Remove Translation Input from emulator proper.
; 23 Aug 1987 Add byte vtemu.vtflgop to hold emulator runtime values as
;  distinct from the vtemu.vtflgst setup values so a reset restores setups.
; 19 Aug 1987 Make sure cursor type is correct on warm start, from Bob Babcock
; 18 Aug 1987 Change ESC to escape for MASM 4.5+. Add Heath graphics,
;  add screen alignment, redo line wrap material, size screen from crt_cols
;  and crt_rows given by MSYxxx. [jrd]
; 31 June 1987 Clear counter mccnt when completing transparent print. [jrd]
; 17 June 1987 Correct jump from atreset to atres2 when changing 80/132 cols
;  and always copy all 132 columns of tabs. [jrd]
; 16 June 1987 Fix bug in cursor positioning when outside scrolling region,
;  thanks to Richard Saxton. Remove global byte jwait (for msy), add code to
;  clear the status line when the Heath-19 is commanded to disable that line
;  (wierd, but Dave says that's the way H-19's work), thanks to Dave Tweten.
; 8 June 1987 Tell file msy... about change of keypad applications mode. [jrd]
; 31 May 1987 Correct several Heath-19 problems: use ansi escape table when
;  in ansi mode, reject ESC [ (hold screen mode), use correct cursor left,
;  remember cursor type (underline/block/on/off) separately from VT100 setup.
;  Thanks to Dave Tweten. [jrd]
; 10 May 1987 Move input translate table rxtable within this emulator,
;  don't translate if debug is active, don't translate escape sequences,
;  no translation if controller print is active, make byte anspflg global
;  so msyibm can sense print screen status. Add print controls for VT52. [jrd]
; 4 May 1987 Correct several jumps to be signed for scrolling region. [jrd]
; 7 April 1987 Fix cursor wrap for H-19's, from Mike Iglesias [uci]
;  Fix cursor wrap top to bottom when reverse indexing, from Matt Tomlinson.
;  Fix tests for cursor left of left margin for wide screens by comparing
;  column number exceeding 250D.  [jrd]
; 28 March 1987 Use global variable low_rgt vs proc call for it. [jrd]
; 24 March 1987 In vtsound, always use most recent port 61h state. [jrd]
; 22 March 1987 Add call to proc chgdsp (change display adapter) to shift
;  between 80 and 132 columns, from David L. Knoell. [jrd]
; 14 March 1987 Correct small bugs. Change signed jumps to unsigned plus
;  allow screen widths to 132 columns, thanks to David Knoell.
;  Add constants Swidth (132) and Slen (43) as max screen dimensions and
;  base screen ops on low_rgt (high = row, low = column of lower right corner,
;  counted from 0,0) dimensions stated by msyibm. [jrd]
; 6 March 87 Add transparent printing when ANSI Media Copy (ESC [ 5 i) is
;  active. [jrd]
; 19 Feb 1987 correct problem in atccic of cursor being forced into scrolling
;  region if starting point was outside the region. [jrd]
; 27 Oct 1986 correct typo for anspflg under atnrm3: [jrd]
; 16 Oct 1986 keep several ansflg bits under warm start, correct screen,
;  linewrap, and newline status under warm start.
; 1 Oct 1986 Version 2.29a
; 20 Sept 1986 revise procedure atccic to use proper scrolling limits. [jrd]
; 1 Sept 1986 Add 8 bit wide comms when parity = none. In debug mode high bit
;  set shows as tilde then rest of 7 bit code. [jrd]
; 27 August 1986 Add full VT102 printer support. DOS printer operations used
;  so printer can be redirected; requires Kermit's Critical Error routine in
;  mssker.asm to avoid "Abort, Retry, Ignore" msgs on screen. Shows printer
;  not ready msg on mode line and quits printing operation if PRN not ready.
; Correct indexing of cursor when it is outside limited scrolling region.[jrd]
; Fix parameter decanm not being updated in stblmds under soft reset.
;  21 May 1986 [jrd]
; [2.29] code frozen on 6 May 1986 [jrd]
;    [Joe R. Doupnik, Utah State Univ]
;

        public  anstty, ansini, ansrei, ansdsl, anstat, anskbi ; Entry points
        public  ans52t, vclick, vsinit
        public  mar_top, mar_bot, anspflg       ; data for msyibm
        include mssdef.h

; * Disclaimer *
;
; DEC and VT are trademarks of Digital Equipment Corporation.
;
; There is a naming convention
; for the ANSI and VT100 functions and flags; generally, the stuff in the
; symbol after "ans" or "at" is the function or mode mnemonic used in the
; VT100 manual.
;
; Every effort has been made to make the VT100 emulation as much like the
; real thing as possible.   The reference used was the VT100 User's Guide, 2nd
; ed. Jan. 1979, DEC part no. EK-VT100-UG.    Some aspects of the behavior
; of the terminal (e.g., the interaction of the "origin mode", limited
; scrolling region, and indexing), were gleaned from programming experiments
; on an actual VT100 terminal.  Implemented features include: (1) Limited
; scolling region, (2) Settable tab stops, (3) Special "graphics" character
; set and UK ASII set, (4) All graphic renditions (underline, blink, and
; high intensity), (5) Simulated "LEDs" on the mode line, (6) Screen mode
; (normal or reverse video), (7) All terminal reports (status, active position,
; terminal parameters, and device attributes), (8) The ANSI new-line mode and
; several of the DEC private modes, including keypad application, cursor key,
; screen, auto-wrap, and origin, (9) cursor position/graphic rendition/
; character set save/restore, and last (and probably least): (10) VT52 com-
; patibility mode.    Also, various details of behavior required by the ANSI
; standard (e.g. most control characters do not affect the interpretation of
; the current escape sequence, relative cursor positioning (up, down, left
; right, and of course tab) stop at the screen margins, etc.) have been
; scrupulously observed.
;
; This was the first thing I ever wrote in 8088 assembler (some of it was
; stolen from MSYIBM), and one of the constraints was that the emulator
; should work with a vanilla PC with a monochrome monitor. Given these and
; other constraints, no attempt was made to implement the following VT100
; features: (1) Smooth scolling, (2) 132 column lines, (3) Auto repeat,
; (5) Interlace/no interlace, (6) Double-width/double-height lines. The
; escape sequences to set and reset these are recognized, but ignored.
;
;       - James A. Harvey, IUPUI Computing Services, DEC Systems Group
;
; * End of Disclamer *
; ---------------------------------------------------------------------------
;
; Description of the global entry points and calls on external routines
; needed by this emulator.                                      [jrd]
;
; vsinit - start up routine called as Kermit initializes. Takes no arguments.
;          Sets up address pointers to tabs, reads default terminal parameters
;          reads current screen coloring. Examines and updates structure
;          "vtemu." which is how mssset communicates changed information
;          about many Set Term parameters; "flags." is a Kermit structure
;          carrying the other Set Term parameters.
; anstty - starting point for displaying a character, delivered in AL.
;          Returns when the display operation is completed and that may
;          take many many instructions. All normal "characters received by
;          the terminal" are provided by calling anstty with the char in AL.
; ansini - entry point to initialize the emulator. It requires information
;          from msy in four registers: the Kermit terminal routine flags
;          "yflags" (used mainly to sense debug mode and the mode line toggle)
;          "low_rgt" (bh = row, bl = column of the lower right display corner)
;          "lbaudtab" (index into baud rate table, for status reporting)
;          "lpartab" (index into parity table, for status reporting)
;          Ansini causes a full reset of the emulator, including screen
;          clearing and a beep. Ansini is also called by msy in response to
;          sensing the Alt = key combination to fully reset the emulator.
; ansrei - entry point to reinitialize the emulator. Nearly the same as
;          ansini except operating flags, tabs, etc are retained from the
;          previous emulator session. Items which can be changed by Set Term
;          are examined and updated. The msy flags "yflags" are needed.
;          This is the warm-restart entry point used when connect mode
;          is reentered gracefully. The screen is cleared only if the coloring
;          has changed. The starting cursor location is whereever msy puts it.
; ansdsl - display "led" (status line) information. Invoked by msy when
;          the mode line is constructed so the emulator can write the
;          terminal type and the VT100 led status lights when Connect mode
;          is started. Requires "yflags" from msy to sense whether the mode
;          line is to be shown.
; anstat - reports our working flags and screen coloring to msy. Nearly
;          obselete but not quite. Reads msy "yflags" and reports "mlbattr"
;          the video attributes used on the mode line, "scbattr" the video
;          attributes of an empty character cell (background), "curattr"
;          the video attributes of displayable characters, and "ansflgs"
;          the emulator's working flags (needed for keyboard translations
;          done in msy).
; anskbi - a routine called by msy to notify the emulator that a character
;          is available from the keyboard. No character is read, just flag
;          ttkbi is set. This is actually used only to beep when the cursor
;          goes beyond column 72 and the margin bell flag is on.
; ans52t - called by msy to change terminal types "on the fly" without
;          fully updating all operating parameters and without losing setup
;          information. Msy senses the Alt minus key and calls ans52t with
;          no arguments. Ans52t cycles among VT102, VT52 and Heath-19 modes.
; vclick - called by msy to cause a click sound. Simulates keyboard clicks,
;          sort of anyway. No arguments.
; other modules in msy are called by this file to handle screen scrolling
;          mode line on/off, output to the serial port (reports), screen
;          particulars (location, cursor shape, blanking). The list is
;          the set of code extrn procedures below; all are in file msy.
;
; data exchange is directly with msy to assist in scrolling (varaibles
;          "mar_top", "mar_bot") and in sensing the non-connect
;          mode screen coloring ("scbattr"). Screen coloring controlled by
;          the emulator is not permitted to influence the non-connect mode
;          screens whereas the emulator attempts to use the regular Kermit
;          screen colors as defaults. The kind of terminal to emulate is
;          held in byte "flags.vtflg" which is set by Set Term and by this
;          module for global information within Kermit.
;
; The emulator assumes the screen is laid out in the manner of a conventional
;          IBM monochrome or color graphics adapter running in 80 column TEXT
;          modes. That layout is one word per displayable location starting at
;          the upper left corner (0,0) and running contiguously to the lower
;          right corner (24,79). Each word holds the displayable character in
;          the low order byte and the display attributes in the high order
;          byte. Attributes are, from high to low bits: blinking on, back-
;          ground red, green, and blue on, high intensity, foreground red,
;          green, and blue on. Normal white chars on a black field is 07H.
;          The starting segment of screen memory is given by msy module
;          "scrseg" to be TopView/MS Windows compatible. Msy module "scrsync"
;          is used to inform these windowing environments of memory updates.
;          Variable "crt_mode" is set by msy to indicate which IBM display
;          mode is active; only the monochrome and CGA modes are recognized.
;          Direct reading and writing of display memory is done, compatibly
;          with TopView/Windows, to attain speed over Bios and DOS calls
;          when editing of previously entered text is needed. However, IBM
;          Bios interrupt 10H is used where possible for normal cursor
;          movement/sensing and writing of new characters. See the IBM PC
;          hardware Technical Reference Manuals for further details.
;
; Many things have been added, or modified since James Harvey donated this
;          code to Columbia University for use in Kermit.              [jrd]
; ---------------------------------------------------------------------------

screen  equ     10h                     ; Bios screen call
swidth  equ     132                     ; assumed max screen width [dlk]
slen    equ     43                      ; assumed max screen length [jrd]

att_low_mask    equ     06H             ; Various attribute-related equates
;;;att_reverse  equ     70H             ; these two are now storable items
;;;att_normal   equ     07H             ; to allow external settings. [jrd]
att_underline   equ     01H
att_intensity   equ     08H
att_blink       equ     80H

; VT100 status flags ansflg

;anslnm  equ     01H                     ; ANSI line feed/new line mode
;decckm  equ     02H                     ; VT100 cursor keys mode
;deckpam equ     04H                     ; VT100 keypad application mode
;decscnm equ     08H                     ; VT100 screen mode (n.y.i.)
;decom   equ     10H                     ; VT100 origin mode
;decawm  equ     20H                     ; VT100 autowrap mode
;decanm  equ     40H                     ; ANSI(VT100)/VT52 mode
;decmode equ     80H                     ; "?" seen in lead-in

;;;;;;;;;;;;;;;; items for reference from mssdef.h ;;;;;;;;;;;;;

; VT100 SETUP mode flags

;vsscreen        equ     40H             ; Screen mode (0 = normal video)
;vscursor        equ     20H             ; Cursor (0 = block)
;vsmarginbell    equ     10H             ; Margin bell (0 = off)
;vskeyclick      equ     08H             ; Keyclick (0 = off)
;vsshift3        equ     04H             ; Shift-3 (0 = American pound sign)
;vswrap          equ     02H             ; Line wrap around (0 = no wrap)
;vsnewline       equ     01H             ; ANSI new line (0 = off)

;vsdefaults      equ     0+vscursor

;[IU1] Definitions for terminal emulation
;TTGENRC EQU    0               ; Type 0 - TTY (no special emulation)
;TTHEATH EQU    1               ; Type 1 - HEATH 19
;TTVT52 EQU     2               ; Type 2 - VT52
;TTVT100 EQU    3               ; Type 3 - ANSI (VT100 subset)
;TTTEK  EQU     4               ; Type 4: Tektronix 4010
;TTTYPES equ    5               ; Number of terminal types defined

;emulst struc           ; structure of vtemu.xxx for VT100 emulator
;vtflgst db     0       ; VT100 setup flags (from SET)
;vtflgop db     0       ; VT100 runtime flags, like setup flags (here & STAT)
;vttbs  dw      0       ; pointer to default tab stops, for SET
;vttbst dw      0       ; pointer to active tab stops, for STATUS
;att_ptr dw     0       ; pointer to normal & reverse video attributes
;emulst ends
;;;;;;;;;;;;;;;;  end references ;;;;;;;;;;;;;;;;;;;;

datas   segment public 'datas'
        extrn vtemu:byte, crt_mode:byte, scbattr:byte, flags:byte
        extrn crt_lins:byte, crt_cols:byte, rxtable:byte, denyflg:word
        extrn tekflg:byte

; Early versions of MASM have a bug that causes it to consider the
; expression (offset foo) as non-relocatable if used in an arithmetic
; operation (for example, "sub di,offset foo"), and if foo is defined
; within the first 256 bytes of the data segment.


; ANSI special character table - 32 entries indexed by control char value

ansspc  dw      5 dup (atign)           ; ignore NUL,SOH,STX,ETX,EOT
        dw      atign                   ; ENQ - answerback message
        dw      atign                   ; ACK - ignore
        dw      atbel                   ; BEL - ring terminal bell
        dw      atbs                    ; BS - ANSI backspace
        dw      atht                    ; HT - ANSI tab
        dw      atlf                    ; LF - ANSI line feed
        dw      atlf                    ; VT - Interpreted as ANSI LF
        dw      atff                    ; FF - do as LF (but ESC FF does Tek)
        dw      atcr                    ; CR - ANSI carriage-return
        dw      atso                    ; SO - Select char set G1
        dw      atsi                    ; SI - Select char set G0
        dw      8 DUP (atign)   ; ignore DLE,DC1,DC2,DC3,DE4,NAK,SYN,ETB
        dw      atcan                   ; CAN - cancel ANSI sequence
        dw      atign                   ; EM - ignore
        dw      atcan                   ; SUB - treat as CAN
        dw      atesc                   ; ESC - ANSI CSI.
        dw      4 DUP (atign)           ; ignore FS,GS,RS,US

; Heath-19 mode escape follower table

h19esc  db      'YABCD', 'KIHJF', 'G=><Z', 'ELM'
        db      'NO@p', 'qvwjk', 'xynz', 'blor'
lh19esc equ     $-h19esc

; Dispatch table for Heath-19 escape sequence table h19esc.
; Two byte sequences of the form ESC char, where char is not in the
; table above, are completely ignored.

h19ejt  dw      v52pos,atcuu,h19cud,h19cuf,atbs         ; 'YABCD'
        dw      atel,atri,atcup,ated,v52egm             ; 'KIHJF'
        dw      v52xgm,atkpam,atkpnm,h19ans,decid       ; 'G=><Z'
        dw      h19clrs,inslin,dellin                   ; 'ELM'
        dw      atdelc,noins,entins,h19herv             ; 'NO@p'
        dw      h19hxrv,h19wrap,h19nowrp,atsc,atrc      ; 'qvwjk'
        dw      h19smod,h19cmod,hrcup,atreset           ; 'xynz'
        dw      h19erb,h19erl,h19ero,h19mbr             ; 'blor'

; Heath-19 special graphics characters. Use as offsets from caret (94D) [jrd]

hgrtab  db      249,17,179,196,197      ; caret,underscore,accent grave,a,b
        db      191,217,192,218,241     ; c,d,e,f,g
        db      26,219,246,25,220       ; h,i,j,k,l
        db      220,223,223,223,222     ; m,n,o,p,q
        db      16,203,185,202,204      ; r,s,t,u,v
        db      'X','/','\','-','-'     ; w,x,y,z,{
        db      221,222,20              ; |,},~

; VT52 compatibility mode escape follower table

v52esc  db      'Y','A','B','C','D'
        db      'K','I','H','J','F'
        db      'G','=','>','<','Z'
        db      '7','8','c','^','_'
        db      'W','X',']','V'
lv52esc equ     $-v52esc                ; length of table

; Dispatch for v52esc table

v52ejt  dw      v52pos,atcuu,atcud,atcuf,atcub
        dw      atel,atri,atcup,ated,v52egm
        dw      v52xgm,atkpam,atkpnm,v52ans,decid
        dw      atsc,atrc,v52ris,v52apb,v52ape
        dw      v52pcb,v52pce,v52ps,v52pl

; ANSI escape special character table

ansesc  db      '[','D','E','M','H'
        db      '7','8','=','>','c'
        db      '(',')','#','Z','<'
        db      'P','*'
lansesc equ     $-ansesc                ; length of table

; Dispatch for ansesc table

ansejt  dw      atcsi,atind,atnel,atri,athts
        dw      atsc,atrc,atkpam,atkpnm,atris
        dw      atsg0,atsg1,atsdhl,at52id,atnorm
        dw      atpriv,atpriv


; Final char table for ANSI escape sequences (ESC [ Pn ; ... Pm ch)

anstab  db      'H','A','B','C','D'
        db      'K','J','m','g','r'
        db      'c','q','x','n','f'
        db      'l','h','y','P','L'
        db      'M','i','s','u','z'
        db      '@'
lanstab equ     $-anstab                ; Define table length

; Dispatch for anstab table

ansjmp  dw      atcup,atcuu,atcud,atcuf,atcub
        dw      atel,ated,atsgr,attbc,atstbm
        dw      atda,atll,atreqt,atdsr,atcup
        dw      atrm,atsm,atctst,atdelc,inslin
        dw      dellin,ansprt,htsc,htrc,htrest
        dw      ansich

; "Special graphics" set translation table for characters 137 (octal)
; through 176 when the special graphics set is selected.  Some characters
; (142, 143, 144, 145, 150, 151, 157, 160, 162, 163, and 174) do not
; have exact equivalents in the available set on the IBM, so a (some-
; times reasonably close) substitution is made.  Table is indexed by
; ASCII char value minus 137 octal for chars 137-176 octal.

sgrtab  db      032,004,177,026,023
        db      027,025,248,241,021
        db      018,217,191,218,192
        db      197,196,196,196,196
        db      196,195,180,193,194
        db      179,243,242,227,157
        db      156,250

; Device attributes response string. (Note: If "with AVO" causes problems,
; change the last parameter from "2" to "0". The default is to indicate
; the AVO option is present because the emulator can set all of the graphic
; rendition attributes (bold, blink, etc.) independently). A VT100 reports
; as ESC [ ? 1 ; 2 c  but a VT102 uses ESC [ ? 6 ; 2 c.

dastr   db      escape,'[?6;2c'         ; VT102
ldastr  equ     $-dastr

; Identify response used while in VT52 compatibility mode...

v52str  db      escape,'/Z'
lv52str equ     $-v52str

; Identify response when a Heath-19 terminal. [jrd]

h19str  db      escape,'/K'
lh19str equ     $-h19str

; ANSI Escape sequence to turn off Media Copy (Print Controller Off)

mcoff   db      escape,'[4i'
mcofflen equ    $-mcoff                 ; length of sequence
mcoffs  db      4 dup (0)               ; received chars in sequence
mccnt   dw      ?                       ; counter of matched char in mcoff

; Parity code translation table

partab  db      5                       ; Even
        db      3                       ; Mark
        db      1                       ; None
        db      4                       ; Odd
        db      2                       ; Space
lpartab equ     $-partab

; Baud rate code translation table

baudtab db      0                       ; 45.5 - no VT100 code (call it 50)
        db      0                       ; 50
        db      8                       ; 75
        db      16                      ; 110
        db      24                      ; 134.5
        db      32                      ; 150
        db      48                      ; 300
        db      56                      ; 600
        db      64                      ; 1200
        db      72                      ; 1800
        db      80                      ; 2000
        db      88                      ; 2400
        db      104                     ; 4800
        db      112                     ; 9600
        db      120                     ; 19200
        db      128                     ; 38400  extended beyond DEC [jrd]
lbaudtab        equ     $-baudtab

belcol  db      ?                       ; column at which to ring margin bell
yflags  db      ?                       ; Flags from MSYxxx term routine.
video_state db  0                       ; video state (0=normal,1=reversed)
oldbatr db      ?                       ; old scbattr [jrd]
oldterm db      ?                       ; terminal type from previous entry
baudidx db      ?                       ; Index into baud rate table
parcode db      ?                       ; Parity code (0-4)
datbits db      ?                       ; Number of databits (7 or 8)
savflgs db      ?                       ; Saved flags for atsc/atrc.
modeset db      ?                       ; Temp for atsm/atrm.
h19mod  db      ?                       ; flag for atsm/atrm.
h19l25  db      ?                       ; Heath-19 25th line enabled flag
insmod  db      ?                       ; Insert mode on (1) or off (0).[jrd]
kbicsr  dw      ?                       ; Cursor when keyboard input typed
kbiflg  db      ?                       ; Set/reset for keyboard input
ttstate dw      offset atnrm            ; terminal automata state.

                                        ; Start of stuff to save for ESC 7 fxn
ukset   equ     0                       ; Set 1 = UK ASCII set
ascset  equ     1                       ; Set 2 = US ASCII set
sgrset  equ     2                       ; Set 3 = "Special graphics set"
svattr_index    equ 0                   ; To set saved cursor attribute only.

curattr db      07h                     ; Cursor attribute
cursor  dw      0                       ; Cursor position
chr_set dw      offset chr_sg0          ; Ptr. to currently selected char set
chr_sg0 db      ascset                  ; Current SG0 set
chr_sg1 db      ascset                  ; Current SG1 set
lsavecu equ     $-curattr               ; Length of stuff to save.

savecu  db      lsavecu dup (?)         ; Saved cursor, attr., charset, etc.
h19ctyp db      1                       ; H-19 cursor type (1=ul, 2=bk, 4=off)

att_normal      db      07H             ; retain order: normal then reverse
att_reverse     db      70H

mlbattr db      ?                       ; Mode line background attribute

ansflgs db      0                       ; ANSI/VT100 mode flags
; (flags are defined in mssdefs.h)

vtflags db      0                       ; VT100 SETUP flags
; (SETUP flags are defined in mssdefs.h)
tmpflags        db      0               ; (Temporary for asnrei/stblmds).

; (tab stops are stored here)           ; [jrd]
tabs    db      swidth dup (?)          ; active tab stops.
deftabs db      swidth dup (?)          ; default tab stops
vttabs  dw      0                       ; Pointer to default VT100 tab stops

; byte per line, type of line: 0=normal, 1=double wide, 2=double high [jrd]
linetype db     slen dup (?)

linelen db      79                      ; active screen line length (79, 131)
low_rgt dw      0                       ; text screen dimensions.
                                        ; byte low_rgt = max columns (79)
                                        ; byte low_rgt+1 = max rows (23)
ttkbi   db      0                       ; Flag for keyboard input seen.

; Scrolling region - do not separate or change order of mar_top & mar_bot.
mar_top db      ?                       ; Scrolling region top margin
mar_bot db      ?                       ; Scrolling region bottom margin

led_col equ     65                      ; column position for "LEDs" display
led_off equ     '.'                     ; "Off" LED. [jrd]
ansleds db      'VT102 ....'            ; "LEDs".Terminal ident (10 bytes)
v52leds db      '   VT52   '            ; This is used in VT52 mode.
h19leds db      ' Heath-19 '            ; For Heath-19 mode [jrd]
                                        ; message for mode line [jrd]
pntmsg  db      'Printer not ready, printing request skipped.'
pntmsgl equ     $-pntmsg                ; length of pntmsg

nansarg db      0                       ; Index for ANSI argument list
ansargs db      16 dup (0)              ; Room for 16 ANSI arguments
lansarg equ     $-ansargs               ; Max number of ANSI arguments
                                        ; printer support data
anspflg db      0                       ; printer flag bits and definitions
vtautop equ     1                       ; autoprint enabled (1)
vtcntp  equ     2                       ; controller print enabled (1)
vtextp  equ     4                       ; printer extent set (1)
vtffp   equ     8                       ; form feed wanted at end of print (1)

datas   ends


code    segment public 'code'
        extrn   prtbout:near, prtnout:near, csrtype:near, trnmod:near
        extrn   scrmod:near, scrseg:near, scrsync:near, scroff:near
        extrn   scron:near, atsclr:near, vtscru:near, vtscrd:near
        extrn   modwrt:near, telmsy:near, scrloc:near, pcwait:near
        extrn   chgdsp:near, trnprs:near, cptchr:near, tekesc:near
                                ; extrn procedures are all in module msyibm
        extrn   tekini:near, tekemu:near, tekend:near
        assume  cs:code, ds:datas, es:datas

; This routine initializes the VT100 setups at startup.  It is called from
; procedure lclyini in module msyibm.

vsinit  proc    near
        mov     vtemu.vtflgst,vsdefaults ; Init to defaults in mssdef.h
        mov     vtemu.vtflgop,vsdefaults ; Init runtime state to setup items
        mov     insmod,0                ; turn off insert mode. [jrd]
        mov     deftabs,0               ; Column 1 has no tab stop.
        mov     cl,crt_cols             ; physical screen width (80)
        dec     cl                      ; we count from column 0
        mov     ch,crt_lins             ; physical screen length-1
        dec     ch                      ; we count from row 0
        mov     low_rgt,cx              ; store active text area
        mov     cx,131
        mov     di,1                    ; Starting index for column 2.
vsini1: mov     al,0                    ; Assume we will clear this one.
        test    di,0007H                ; Index mod 8 equals 0?
        jnz     vsini2                  ; No, clear it.
        mov     al,0FFH                 ; Yes, set it.
vsini2: mov     deftabs[di],al          ; Set or clear a tab stop.
        inc     di                      ; Advance to next.
        loop    vsini1                  ; Loop for all.
        mov     cx,slen                 ; clear linetype array [jrd]
        mov     di,0
vsini3: mov     linetype[di],0
        inc     di
        loop    vsini3
        mov     vtemu.vttbst,offset deftabs ; addrs of active tabs for STATUS
        mov     vtemu.vttbs,offset deftabs  ; addrs of tabs for setup (SET)
        mov     vttabs,offset deftabs   ; initial source of tabs. [jrd]
        call    cpytabs                 ; copy default to active [jrd]
        mov     vtemu.att_ptr,offset att_normal  ; ptr to video attributes[jrd]
        mov     ah,8                    ; read current attributes
        xor     bh,bh                   ; page 0
        int     screen
        mov     scbattr,ah              ; save video attributes
        mov     att_normal,ah           ; set att_normal to present colors
        call    brkatt                  ; separate colors from blink/bold
        rol     ah,1                    ; reverse foreground & background
        rol     ah,1                    ; RGB bits.
        rol     ah,1
        rol     ah,1
        call    addatt                  ; reinsert bold/blink bits
        mov     att_reverse,ah          ; set att_reverse too.
        mov     ah,byte ptr low_rgt     ; right most column (counted from 0)
        sub     ah,8                    ; place marker 9 columns from margin
        mov     belcol,ah               ; store column number to ring bell
        ret                             ; And return.
vsinit  endp


; Initialization routine.
;
; Call:         al/     yflags byte that was passed to Term routine.
;               dl/     index for baud rate table
;               dh/     parity in bits 4-7, number of data bits in bits 0-3
;

ansini  proc    near
        mov     yflags,al               ; Always save flags
        mov     ah,vtemu.vtflgst        ; setup flags [jrd]
        mov     vtflags,ah
        mov     vttabs,offset deftabs   ; tab stop pointer.
        mov     vtemu.vttbst,offset tabs; store here for STATUS [jrd]
        mov     al,flags.vtflg          ; get current terminal type
        mov     oldterm,al              ; remember it here for soft restarts
        mov     insmod,0                ; turn off insert mode. [jrd]
        mov     h19l25,0                ; clear Heath 25th line enable. [jrd]
        mov     h19ctyp,1               ; set Heath cursor to underline, on
        mov     anspflg,0               ; clear printer flag [jrd]
        push    ax
        mov     ah,byte ptr low_rgt     ; right most column (counted from 0)
        sub     ah,8                    ; place marker 9 columns from margin
        mov     belcol,ah               ; store column number to ring bell
        pop     ax
        cmp     dl,lbaudtab             ; Wierd index?
        jb      ansin1                  ; No - OK - store it.
        mov     dl,lbaudtab-1           ; Yes - make it the maximum.
ansin1: mov     baudidx,dl              ; Save baud rate index
        mov     al,dh                   ; Get parity/number of databits
        and     al,0FH                  ; Isolate number of databits
        mov     datbits,al              ; Save.
        mov     cl,4                    ; Isolate parity code
        shr     dh,cl                   ; Isolate parity code
        cmp     dh,lpartab              ; Weird code?
        jb      ansin2                  ; No - OK - store it.
        mov     dh,lpartab-1            ; Yes - make it the maximum.
ansin2: mov     parcode,dh              ; Save.
        call    scrmod                  ; Get the screen mode, in MSYxxx
        mov     cl,crt_cols             ; physical screen number columns (80)
        dec     cl                      ; we count from column 0 here
        mov     ch,crt_lins             ; physical screen number rows-1 (24)
        dec     ch                      ; we count from row 0 here
        mov     low_rgt,cx              ; save as active text screen size
ansin3: call    atreset                 ; Reset everything
        mov     ttstate,offset atnrm    ; Reset state to "normal".
        ret                             ; And return.
ansini  endp


; Re-initialization routine.      Called when Term was called but screen was
; restored from a previously saved screen, etc.
;
; Call: al/     yflags byte that was passed from msyibm module.
;

ansrei  proc    near
        mov     yflags,al               ; Always save flags
        mov     ah,vtemu.vtflgop        ; get runtime flags [jrd]
        mov     tmpflags,ah
        call    scrmod                  ; Get the screen mode.
        call    atsctyp                 ; set cursor type [rbv]
        mov     ah,3                    ; get cursor position from msy
        mov     bh,0                    ; Page zero.
        int     screen
        mov     cursor,dx               ; dh = row, dl = column
        mov     cl,crt_cols             ; physical screen number columns (80)
        dec     cl                      ; we count from column 0 here
        mov     ch,crt_lins             ; physical screen number rows-1 (24)
        dec     ch                      ; we count from row 0 here
        mov     low_rgt,cx              ; save as active text screen size
        cmp     linelen,79              ; want 80 cols?
        ja      ansre2                  ; a = no
        cmp     byte ptr low_rgt,79     ; want 80 cols. Is active screen wider?
        jbe     ansre2                  ; be = no
        mov     byte ptr low_rgt,79     ; narrow down to 80 columns
ansre2: call    stblmds                 ; Check settable modes, set flags.
        ret
ansrei  endp


; This routine copies the new tab stops when they have changed.
; Copies all 132 columns.
cpytabs proc    near
        mov     cx,swidth               ; number of screen columns
        jcxz    cpytab1                 ; z = none to do
        mov     si,vttabs               ; Source.
        mov     di,offset tabs          ; Destination.
        push    es                      ; save es
        push    ds
        pop     es                      ; set es to datas segment
        cld
        rep     movsb                   ; Do the copy.
        pop     es                      ; recover es
cpytab1:ret
cpytabs endp


; This routine checks to see whether any of the settable modes have changed
; (things that can be changed in both SETUP and by host commands), and
; changes those that need to be changed.  TMPFLAGS has the new VT100 setup
; flags, VTFLAGS has the old. This routine also updates VTFLAGS.
; Revised by [jrd] to allow MSY to reset scbattr when not in connect mode,
; to do "soft reset" if terminal type has changed, and to do a screen clear
; reset if the actual screen colors have changed.

stblmds proc    near
        mov     al,flags.vtflg          ; get current terminal type [jrd]
        cmp     al,oldterm              ; same as before?
        je      stblm10                 ; e = yes, skip over soft reset.
        mov     oldterm,al              ; remember current terminal type
        mov     insmod,0                ; reset insert mode flag
        mov     h19l25,0                ; reset heath-19 25th line enable
        mov     mar_top,0               ; reset top scrolling margin
        mov     al,byte ptr low_rgt+1   ; and scrolling margin
        mov     mar_bot,al              ; to last normal line on screen
        mov     ah,byte ptr low_rgt     ; right most column (counted from 0)
        sub     ah,8                    ; place marker 9 columns from margin
        mov     belcol,ah               ; store column number to ring bell
        and     ansflgs,decckm+deckpam+decom ; save some flags
        push    bx                      ; save this register around loop
        mov     bx,offset linetype      ; setup to clear double width chars
        mov     cx,slen                 ; number of linetype slots to clear
        cmp     flags.vtflg,ttvt100     ; VT100 now?
        jne     stblm0                  ; ne = no
        or      ansflgs,decanm          ; set ansi flag bit
stblm0: mov     byte ptr [bx],0         ; clear the linetype array to single
        inc     bx                      ;  width characters.
        loop    stblm0                  ; do each line (1 byte per line)
        pop     bx                      ; restore bx
stblm10:mov     al,tmpflags             ; Get the new flags.
        and     ansflgs,not anslnm      ; assume we do not want newline
        test    al,vsnewline            ; is newline mode desired?
        jz      stblm1                  ; No - continue.
        or      ansflgs,anslnm          ; Yes - set corresponding mode flag.
stblm1: and     ansflgs,not decawm      ; assume not want wrap
        test    al,vswrap               ; Did wrap mode change?
        jz      stblm2                  ; No - continue.
        or      ansflgs,decawm          ; Yes - set corresponding mode flag.
stblm2: mov     ah,vtflags              ; old flags
        xor     ah,tmpflags             ; new flags
        test    ah,vsshift3             ; pick out char set bit
        jz      stblm4                  ; z = no change
        mov     ah,ascset               ; assume US ASCII.
        test    tmpflags,vsshift3       ; Want UK?
        jz      stblm3                  ; No - guessed right.
        mov     ah,ukset                ; Yes - use UK set.
stblm3: mov     chr_sg0,ah              ; Set the sets.
        mov     chr_sg1,ah
stblm4: mov     ah,oldbatr              ; get old screen background scbattr
        mov     scbattr,ah              ; and update working copy
        mov     ah,att_normal           ; get new attributes (Set Term Color)
        push    bx
        mov     bh,ah                   ; get new intensity bit of att_normal
        and     bh,att_intensity
        and     curattr,not att_intensity ; char attrs. clear intensity bit
        or      curattr,bh              ; set new intensity
        and     mlbattr,not att_intensity ; mode line attrs. clear intensity
        and     scbattr,not att_intensity ; screen background attribute
        or      scbattr,bh              ; set its intensity also
        mov     bl,scbattr
        mov     oldbatr,bl              ; and save it here as well
        pop     bx
        call    brkatt                  ; separate color and blink/bold
        rol     ah,1                    ; reverse fore/back color fields
        rol     ah,1
        rol     ah,1
        rol     ah,1
        call    addatt                  ; put back blink/bold
        push    bx                      ; check on color change
        mov     bh,ah                   ; new att_reverse pattern
        and     bh,not(att_intensity+att_blink) ; look at just color bits
        mov     bl,att_reverse          ; previous att_reverse pattern
        and     bl,not(att_intensity+att_blink) ; look at just color bits
        mov     att_reverse,ah          ; save new reverse pattern
        cmp     bh,bl                   ; have any color bits changed?
        pop     bx                      ; does not affect flags
        je      stblm9                  ; e = no
        mov     cursor,0                ; reset cursor position
        jmp     atres2                  ; go to semi-reset
stblm9:                                 ; check on screen normal/reversed.
        mov     al,tmpflags
        xor     al,vtflags              ; Find which ones have changed.
        test    al,vsscreen             ; How about screen background?
        jz      stblm8                  ; No - don't touch it.
        test    tmpflags,vsscreen       ; Flag to be set?
        jnz     stblm5                  ; Yes - go to it.
        and     ansflgs,not decscnm     ; No - cleared (normal video).
        and     savflgs,not decscnm
        mov     al,att_normal           ; No - get new background.
        jmp     short stblm6            ; And reverse everything.

stblm5: or      ansflgs,decscnm         ; Set (reverse video).
        or      savflgs,decscnm
        mov     al,att_reverse          ; No - set reverse video.
stblm6: call    atrss2                  ; Reverse screen and cursor attribute.
stblm7: mov     al,scbattr              ; Reset saved attribute also.
        mov     savecu+svattr_index,al
        mov     oldbatr,al              ; and save our attribute
stblm8: mov     al,tmpflags             ; Get new flags.
        mov     vtflags,al              ; Store them.
        ret
stblmds endp

; Return screen offset - given rol, col in dx, returns offset of the word
; for that character from the screen origin in ax.    Preserves all other acs.
; Use same routine in msy to more closely track screen width.  [jrd]
;;scrloc        proc    near
;;      push    bx                      ; We will use bx.
;;      mov     al,dh                   ; Get row.
;;      mov     bl,swidth               ; And length of a line
;;      mul     bl                      ; Offset for this row
;;      mov     dh,0                    ; Clear row.
;;      add     ax,dx                   ; Word offset for this position
;;      sal     ax,1                    ; Make it a byte offset
;;      pop     bx                      ; Restore bx.
;;      ret                             ; And return.
;;scrloc        endp



; Fetch status/attributes routine.
;
; Call:         al/     "yflags" byte from MSYxxx.
;
; Return:       ah/     mode line background attribute
;               al/     screen background attribute
;               bl/     current cursor attribute
;               bh/     ANSI (VT100) mode flags

anstat  proc    near
        mov     yflags,al               ; Mostly for disleds
        mov     ah,mlbattr              ; Return them our attrs, flags, etc.
        mov     al,scbattr
        mov     bl,curattr
        mov     bh,ansflgs
        ret
anstat  endp


; Routine called when something is typed on the keyboard
;
; Call:         No arguments
;

anskbi  proc    near
        mov     ttkbi,0FFH              ; Just set a flag
        ret
anskbi  endp

; Routine to do keyclick if flag is set.
;
; Call:         No arguments
;

vclick  proc    near
        test    vtflags,vskeyclick      ; Is the flag on?
        jz      vclick1                 ; No - just return
        push    bx                      ; Save some ACs
        push    di
        mov     di,500                  ; 500 Hertz [jrd]
        mov     bx,1                    ; For 1 milliseconds. [jrd]
        call    vtsound                 ; Do it.
        pop     di                      ; Restore the ACs
        pop     bx
vclick1:ret
vclick  endp


; Routine to do VT100-style bell.
;
; Call:         No arguments
;

vtbell  proc    near
        push    di
        push    bx
        mov     di,880                  ; 880 Hertz [jrd]
        mov     bx,40                   ; For 40 ms. [jrd]
        call    vtsound                 ; Do it.
        pop     bx
        pop     di
        ret
vtbell  endp

; Routine to make noise of arbitrary frequency for arbitrary duration.
; Similar to routine (with typo removed) in "IBM PC Assembly Language:
; A Guide for Programmers", Leo J. Scanlon, 1983 Robert J. Brady Co.,
; Bowie, MD., page 270. Modified by J R Doupnik to use 0.1 millsec interval.
;
; Call:         di/     frequency in Hertz.
;               bx/     duration in 1 millisecond units. [jrd]
;

vtsound proc    near
        push    ax                      ; Save regs.
        push    cx
        push    dx
        mov     al,0B6H                 ; Write timer mode register
        out     43H,al
        mov     dx,14H                  ; Timer divisor is
        mov     ax,4F38H                ; 1331000/frequency
        div     di
        out     42H,al                  ; Write timer 2 count low byte
        mov     al,ah
        out     42H,al                  ; Write timer 2 count high byte
        in      al,61H                  ; Get current port B setting
        or      al,3                    ; Turn speaker on.
        out     61H,al
        mov     ax,bx                   ; number of milliseconds to wait
        call    pcwait                  ; do the calibrated wait
        in      al,61H                  ; Get current port B setting
        and     al,0fch                 ; Turn off speaker and timer
        out     61H,al
        pop     dx                      ; Restore regs.
        pop     cx
        pop     ax
        ret
vtsound endp

; Routine to toggle VT100/VT52/Heath-19 modes. No arguments.
; Use & update global byte flags.vtflg for terminal type and update local
; bit decanm. Note: shifting to Heath-19 here does Not reset the scrolling
; margins mar_top & mar_bot nor reset the double char linetype array.
; [jrd]
ans52t  proc    near
        cmp     tekflg,0                ; in Tek sub mode?
        jne     ans52c                  ; ne = yes, get out now
        cmp     flags.vtflg,ttvt100     ; in VT100 mode?
        jne     ans52a                  ; ne = no
        and     ansflgs,not decanm      ; reset VT100 ansi mode
        mov     flags.vtflg,ttvt52      ; say VT52 now (clears vt100 bit)
        mov     oldterm,ttvt52          ; and remember it
        jmp     ans52e
ans52a: cmp     flags.vtflg,ttvt52      ; in VT52 mode?
        jne     ans52b                  ; ne = no
        mov     flags.vtflg,ttheath     ; say Heath-19 now
        mov     oldterm,ttheath
        jmp     ans52e
ans52b: cmp     flags.vtflg,ttheath     ; in Heath-19 mode?
        jne     ans52c                  ; ne = no
        call    atsc                    ; save cursor and associated data
        mov     flags.vtflg,tttek       ; set Tek mode
        call    tekini                  ; init Tek to switch screens
        jmp     atnorm                  ; normal state and return
ans52c: cmp     flags.vtflg,tttek       ; in Tek mode now?
        je      ans52d                  ; e = yes
        cmp     tekflg,0                ; doing Tek sub mode?
        jne     ans52d                  ; ne = yes
        jmp     atnorm                  ; else ignore this call

ans52d: call    tekend                  ; exit Tek graphics mode
        mov     tekflg,0                ; end Tek sub mode (do after tekend)
        mov     flags.vtflg,ttvt100     ; say VT100 now
        mov     oldterm,ttvt100
        or      ansflgs,decanm          ; set, go to VT100 mode
        call    atrc                    ; restore cursor etc
        cmp     flags.modflg,0          ; is mode line disabled? [jrd]
        je      ans52e                  ; e = yes, disabled [jrd]
        test    yflags,modoff           ; Mode line off?
        jnz     ans52e                  ; nz = yes - just return.
        mov     al,yflags               ; get current flags
        or      al,modoff               ; say mode line is off
        call    telmsy                  ; let msy hear the news
        call    trnmod                  ; turn it on
ans52e: call    chrdef                  ; Set default character sets
        call    atsc                    ; Save cursor etc.
        call    disleds                 ; Remove or redisplay "LEDs".
        jmp     atnorm                  ; Say state is "normal" and return.
ans52t  endp


; Display "LEDs" routine. Note that this routine
; is not used internally in this module (because it updates the flags from
; MSYIBM). Internally, disleds is used instead. The yflags from MSYIBM are
; needed because we have to know if the mode line is enabled.
;
; Call:         al/     yflags from MSYIBM
;
; Return:       Current state of "LEDs" displayed on line 25.
;

ansdsl  proc    near                    ; Update flags and display "LEDs"
        mov     yflags,al               ; Update the flags.
        call    disleds                 ; Display LEDs
        ret
ansdsl  endp

; Internal routine to display LEDs.

disleds:test    yflags,modoff           ; Mode line off?
        jnz     disled2                 ; Yes - just return.
;;      mov     al,0                    ; Turn cursor off.
;;      call    csrtype
        mov     ah,2                    ; Position cursor at (slen-1),70
        mov     bh,0                    ; Page zero.
        mov     dh,byte ptr low_rgt+1   ; last screen line - 1
        inc     dh                      ; status line
        mov     dl,led_col              ; column for led display
        int     screen
        mov     cx,10                   ; Length of byte array is ten
        mov     si,offset ansleds       ; The "LEDs"
        cmp     flags.vtflg,ttvt100     ; VT100 mode?
        je      disled1                 ; e = yes
        mov     si,offset v52leds       ; try VT52
        cmp     flags.vtflg,ttvt52      ; VT52?
        je      disled1                 ; e = yes
        mov     si,offset h19leds       ; use Heath-19
disled1:lodsb                           ; Get a character
        mov     ah,14                   ; Write character function
        mov     bh,0                    ; Page zero.
        int     screen                  ; ...
        loop    disled1                 ; Loop for all chars
        mov     ah,2                    ; Reposition cursor when finished
        mov     bh,0                    ; Page zero
        mov     dx,cursor
        int     screen
        call    atsctyp                 ; Reset right type of cursor.
disled2:ret


; ANSI terminal output routine.  Call with character in al.

anstty  proc    near                    ; ANSI terminal output.
        mov     dx,cursor               ; Some routines need cursor in dx.
        mov     kbiflg,0                ; Clear old flag value
        test    yflags,trnctl           ; Debug mode?
        jz      anstt1                  ; z = no
        jmp     atdeb                   ; Yes - just translate control chars.
anstt1: cmp     ttkbi,0                 ; New keyboard input?
        je      anstt2                  ; No - just continue
        mov     kbiflg,1                ; Yes - set flag
        mov     kbicsr,dx               ; Save old cursor
        mov     ttkbi,0                 ; Clear this flag.

anstt2: test    anspflg,vtcntp          ; print controller on?
        jz      anstt4                  ; z = no
        test    yflags,capt             ; capturing output?
        jz      anstt3                  ; z = no, forget this part
        push    ax                      ; save char
        call    cptchr                  ; give it captured character
        pop     ax                      ; restore character
anstt3: jmp     ansmc                   ; print transparently
                                        ; Set Display 7/8 bit filter
anstt4: test    flags.remflg,d8bit      ; keep 8 bits for displays?
        jnz     anstt5                  ; nz = yes, 8 bits if possible
        and     al,7fh                  ; remove high bit
anstt5: cmp     al,spc                  ; control char?
        jb      anstt6                  ; b = yes
        cmp     ttstate,offset atnrm    ; doing displayable text?
        jne     anstt7                  ; ne = no, no translation
                                        ; Set Translation filter
anstt6: cmp     rxtable+256,0           ; translation turned off?
        je      anstt7                  ; e = yes, no translation
        mov     bx,offset rxtable       ; address of translate table [jrd]
        xlatb                           ; new char is in al
anstt7: cmp     al,DEL                  ; ANSI Delete char?
        je      atdel                   ; e = yes, ignore it before logging
        cmp     al,0                    ; NUL char?
        je      atign                   ; e = yes, ignore it before logging
        test    yflags,capt             ; capturing output?
        jz      anstt8                  ; z = no, forget this part
        push    ax                      ; save char
        call    cptchr                  ; give it captured character
        pop     ax                      ; restore character and keep going
                                        ; Direct char to processor module
anstt8: cmp     al,20h                  ; Control character?
        jb      atctrl                  ; b = yes, handle it.
anstt9: jmp     ttstate                 ; Nope, dispatch according to state.

atign:  ret                             ; Something to be ignored.

atctrl: mov     ah,0                    ; Make sure this is zero..
        cmp     al,escape               ; an escape sequence starting?
        je      atctrl1                 ; e = yes, don't print it
        test    anspflg,vtautop+vtcntp  ; printing desired?
        jz      atctrl1                 ; z = no
        call    pntchr                  ; print char in al
atctrl1:mov     di,ax                   ; Put it in an index register
        shl     di,1                    ; Make it a word offset
        jmp     ansspc[di]              ; Dispatch.

atdel:  jmp     short atign             ; ignore DEL char
;;      test    yflags,lclecho          ; doing local echoing?
;;      jz      atign                   ; z = no, ignore character
;;      mov     ansargs,0               ; Delete one char to left [jrd]
;;      cmp     dl,0                    ; at column 0 already?
;;      je      atdel1                  ; e = yes
;;      dec     dl                      ; move back one column
;;atdel1:       call    atscu5                  ; move the cursor there and
;;      jmp     atdelc                  ; delete the char now under cursor

atdeb:  test    yflags,capt             ; capturing output?
        jz      atdeb3                  ; z = no, forget this part
        push    ax                      ; save char
        call    cptchr                  ; give it captured character
        pop     ax                      ; restore character and keep going
atdeb3: mov     bh,ansflgs              ; Save flags and attribute
        mov     bl,curattr
        push    bx
        push    word ptr mar_top        ; Save limited scrolling region
        push    ax                      ; Save character for a second
        mov     ah,curattr              ; Get attribute
        call    brkatt                  ; Break it up
        and     al,att_intensity        ; clear attributes, except bold bit
        call    addatt                  ; Put it back together
        mov     curattr,ah              ; Store
        or      ansflgs,decawm          ; Set autowrap temporarily
        mov     mar_top,0               ; Set scrolling region to entire page
        mov     al,byte ptr low_rgt+1
        mov     mar_bot,al
        pop     ax                      ; Restore character
        test    al,80h                  ; high bit set? [jrd]
        jz      atdeb0                  ; z = not set
        push    ax                      ; Save the character for a second
        mov     al,7eh                  ; Output a tilde [jrd]
        call    atnrm2
        pop     ax                      ; Restore character
        and     al,7fh                  ; and remove high bit
atdeb0: cmp     al,del                  ; A DELETE?
        je      atdeb1                  ; Yes - output "^?" [jrd]
        cmp     al,20h                  ; A control character?
        jnb     atdeb2                  ; No - just output char in al.
atdeb1: push    ax                      ; Save the character for a second
        mov     al,5eh                  ; Output a caret [jrd]
        call    atnrm2
        pop     ax                      ; Restore character
        add     al,40h                  ; Make ^letter (or ^? for DELETE)
        and     al,7fh                  ; Clear bit 7 (for DELETE)
atdeb2: call    atnrm2                  ; Output translated character
        pop     word ptr mar_top        ; Restore scrolling region
        pop     bx                      ; And flags and cursor attribute
        mov     curattr,bl
        mov     ansflgs,bh
        ret

atnorm: mov     ttstate,offset atnrm    ; Reset state to "normal".
        ret

                                        ; Normal character processor
atnrm:  mov     bx,chr_set              ; Get character set
        cmp     byte ptr [bx],sgrset    ; "Special" set?
        jne     atnrm1                  ; No - check UK.
        cmp     flags.vtflg,ttheath     ; Heath-19?
        je      atnrm0a                 ; e = yes
        cmp     al,137Q                 ; Yes - is it in the "special" range?
        jb      atnrm2                  ; No - just output the char in al.
        mov     bl,al                   ; Yes - compute index in bx.
        mov     bh,0
        sub     bx,137Q
        mov     al,sgrtab[bx]           ; Fetch translation.
        jmp     short atnrm2            ; Output it.

atnrm0a:cmp     al,94                   ; H-19, in range for special graphics?
        jb      atnrm2                  ; b = no
        cmp     al,126                  ; too large?
        ja      atnrm2                  ; a = too large
        sub     bx,94                   ; H-19, offset from caret
        mov     bl,al
        mov     bh,0
        sub     bx,94
        mov     al,hgrtab[bx]           ; fetch translation
        jmp     short atnrm2

atnrm1: cmp     al,'#'                  ; This thing?
        jne     atnrm2                  ; No - just output it
        cmp     byte ptr [bx],ukset     ; Yes - UK set?
        jne     atnrm2                  ; No - just output it.
        mov     al,156                  ; Yeah, show them our pound sign.
atnrm2:
        mov     dx,cursor               ; get cursor virtual position
        push    ax                      ; save character
        call    atscur                  ; set cursor physical position
        pop     ax

        cmp     insmod,0                ; insert mode off? [jrd]
        je      atnrm3                  ; e = yes [jrd]
        push    ax                      ; save char
        call    inschr                  ; open a char space in this line [jrd]
        push    bx
        mov     bx,cursor               ; get current row
        mov     bl,bh
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        je      atnrm2a                 ; e = yes
        call    inschr                  ; open second space for double width
atnrm2a:pop     bx
        pop     ax                      ; restore char
atnrm3:                                 ; set cursor before writing char
        mov     bl,dh                   ; check for double characteristic
        xor     bh,bh                   ; bx = row, in bl

        test    anspflg,vtautop         ; printing desired? [jrd]
        jz      atnrm4d                 ; e = no
        call    pntchr                  ; print char in al
        cmp     linetype [bx],0         ; normal characteristic?
        je      atnrm4d                 ; e = yes
        push    ax                      ; save current char
        mov     al,' '                  ; add a space for double width
        call    pntchr
        pop     ax                      ; recover char to be processed
atnrm4d:
        cmp     linetype [bx],0         ; normal characteristic?
        je      atnrm4a                 ; e = yes
        push    ax                      ; save char
        shl     dl,1                    ; double the column number
        mov     ah,2                    ; set cursor (bh = 0 from above)
        int     screen
        pop     ax                      ; recover the char
        mov     ah,9                    ; Output char in al to screen [jrd]
        mov     bh,0                    ; Page zero
        mov     bl,curattr              ; Current attribute
        mov     cx,1                    ; Only one character
        int     screen
        inc     dl                      ; next column
        mov     ah,2                    ; set cursor
        int     screen
        mov     al,' '                  ; use a space for doubling
        mov     ah,9                    ; Output to screen [jrd]
        mov     bh,0                    ; Page zero
        mov     bl,curattr              ; Current attribute
        mov     cx,1                    ; Only one character
        int     screen
        shr     dl,1                    ; keep "cursor" in single units
        jmp     atnrm4b                 ; check autowrap in double width mode

atnrm4a:mov     ah,9                    ; Output to screen [jrd]
        mov     bh,0                    ; Page zero
        mov     bl,curattr              ; Current attribute
        mov     cx,1                    ; Only one character
        int     screen
                                        ; set physical cursor after this char
atnrm4b:test    ansflgs,decawm          ; Autowrap?
        jz      atnrm5                  ; No, continue
        mov     cx,low_rgt              ; copy logical cursor margins to cx
        push    bx
        mov     bl,dh                   ; get row
        xor     bh,bh
        cmp     linetype[bx],0          ; single width line?
        pop     bx                      ; pop preserves flags
        je      atnrm4c                 ; e = yes, single
        shr     cl,1                    ; halve right column # for wide chars
atnrm4c:cmp     dl,cl                   ; wrote in right-most column?
        jb      atnrm5                  ; b = no
        inc     dl                      ; say want to use next column
        cmp     flags.vtflg,ttheath     ; emulating a H-19? [uci]
        je      atscur                  ; e = yes, show wrap now. [uci]
        mov     cursor,dx               ; virtual cursor position
        ret                             ; exit without moving cursor from eol
atnrm5: mov     dx,cursor               ; Restore cursor position
        inc     dl                      ; Bump cursor

atscur: cmp     dl,250                  ; To left of column zero?(wide screen)
        jb      atscu1                  ; b = no, continue
        mov     dl,0                    ; Yes - set at column zero.
atscu1: mov     cx,low_rgt              ; copy logical margins; cl=right col
        push    bx
        mov     bl,dh                   ; get row
        xor     bh,bh
        cmp     linetype [bx],0         ; single width lines?
        pop     bx
        je      atscu1a                 ; e = yes, single width
        shr     cl,1                    ; halve column # for double wides
atscu1a:cmp     dl,cl                   ; To right of right margin?
        jbe     atscu3                  ; be = no, continue
        mov     dl,cl                   ; Yes - assume no autowrap.
        test    ansflgs,decawm          ; Autowrap?
        jz      atscu3                  ; No, continue
        mov     dl,0                    ; Yes - set to column zero
        cmp     dh,byte ptr low_rgt+1   ; at bottom of screen?
        je      atscu1b                 ; e = yes
        cmp     dh,mar_bot              ; At bottom of scrolling region?
        jl      atscu2                  ; l = No - bump cursor and continue
atscu1b:call    atscru                  ; Scroll up.
        dec     dh                      ; offset inc dh below
atscu2: inc     dh                      ; Just bump it.
atscu3: cmp     dh,0                    ; Constrain row to valid range.
        jge     atscu4                  ; ge = non-negative row, ok
        mov     dh,0
atscu4: cmp     dh,byte ptr low_rgt+1   ; 25th line?
        jle     atscu5                  ; le = no
        mov     dh,byte ptr low_rgt+1   ; set to 24th line
        cmp     flags.vtflg,ttheath     ; emulating a Heath-19?
        jne     atscu4a                 ; ne = no [hlk]
        cmp     h19l25,0                ; Heath 25th line enabled?
        je      atscu5                  ; e = no
        jmp     short atscu4b           ; do 25th line
atscu4a:test    ansflgs,decom           ; Origin mode active?
;;;##   jz      atscu5                  ; z = no, no 25th line allowed
atscu4b:inc     dh                      ; yes, go to line 25 [hlk]
        test    yflags,modoff           ; is mode line off?
        jnz     atscu8                  ; nz = yes
        push    dx                      ; save cursor position
        call    trnmod                  ; no, turn it off now.
        pop     dx
atscu8: mov     flags.modflg,0          ; and disable mode line. [jrd]
        mov     al,yflags               ; place to communicate [jrd]
        call    telmsy                  ; tell msy the news. [jrd]

atscu5: push    cx                      ; save cx around screen call
        mov     cursor,dx               ; Set cursor and return.
        mov     ah,2                    ; setup for position cursor call.
        mov     bl,dh                   ; get row
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        je      atscu5a                 ; e = yes
        shl     dl,1                    ; double the column number
        int     screen                  ; set the physical cursor
        shr     dl,1                    ; restore dl (logical column)
        jmp     short atscu5b
atscu5a:int     screen
atscu5b:pop     cx
        cmp     kbiflg,0                ; Is keyboard input flag set?
        je      atscu6                  ; No - just return
        test    vtflags,vsmarginbell    ; Yes - do we care?
        jz      atscu6                  ; Return if no margin bell.
        mov     dx,cursor               ; Get new and old cursors
        mov     bx,kbicsr
        cmp     bh,dh                   ; Same row?
        jne     atscu6                  ; No - just return
        cmp     bl,belcol               ; Old cursor at or left of bell column?
        ja      atscu6                  ; a = no, just return
        cmp     dl,belcol               ; Yes - new cursor past bell column?
        jbe     atscu6                  ; be = no, just return
        call    vtbell                  ; Yes - ring the bell
atscu6: ret

; This routine is called to check the cursor position after any kind of cursor
; positioning command.  Note that cursor positioning does NOT cause scrolling
; on a VT100 (hence the need for a routine separate from this for "indexing".
;
; Call:         dx/     "new" cursor position (modified cursor)
;
; Return:       dx/     "new" cursor position adjusted for screen limits (if
;                       decom is reset), or scrolling region (if decom is set).
;
; Preserves ax, bx, and cx.
;

atccpc: push    bx                      ; save bx and cx
        push    cx
atccp7: mov     cx,low_rgt              ; margins, cl = right margin
        mov     bl,dh                   ; get row
        xor     bh,bh
        cmp     linetype [bx],0         ; single width line?
        je      atccp0                  ; e = yes, single width
        shr     cl,1                    ; halve right margin for double wides
atccp0: cmp     dl,250                  ; To left of left margin?(wide screen)
        jb      atccp1                  ; b = no, go check right
        mov     dl,0                    ; No, set to left margin
atccp1: cmp     dl,cl                   ; To right of right margin
        jbe     atccp2                  ; be = yes, go check top
        mov     dl,cl                   ; No, set to right margin
atccp2: test    ansflgs,decom           ; Origin mode set?
        jnz     atccp5                  ; Yes, can't go out of scrolling region
        cmp     dh,0                    ; Above top of screen?
        jge     atccp3                  ; ge = no, check bottom
        mov     dh,0                    ; Yes, stop here
atccp3: cmp     dh,byte ptr low_rgt+1   ; Below bottom of screen?
        jle     atccp4                  ; le = no, return
        mov     dh,byte ptr low_rgt+1   ; Yes, stop at bottom margin
        cmp     flags.vtflg,ttheath     ; Heath-19 mode?
        jne     atccp4                  ; ne = no
        cmp     h19l25,0                ; 25th line enabled?
        je      atccp4                  ; e = no
        inc     dh                      ; allow 25th line
atccp4: pop     cx
        pop     bx
        ret

atccp5: cmp     dh,mar_top              ; Above top of scrolling region?
        jge     atccp6                  ; ge = no, check bottom
        mov     dh,mar_top              ; Yes, stop there.
atccp6: cmp     dh,mar_bot              ; Below bottom perhaps?
        jle     atccp4                  ; le = no, return
        mov     dh,mar_bot              ; Yes, stop at the bottom margin
        pop     cx
        pop     bx
        ret


; This routine is called to adjust the cursor for the "indexing" like commands
; (e.g., index, reverse index, newline, etc.).  It contrains the cursor, and
; indicates if scrolling is necessary, and if so, in which direction.
;
; Call:         cursor/ "old" cursor position
;               dx/     "new" cursor position
;
; Return:       ax/     pointer to scrolling routine to call (or to a ret)
;               bx/     "old" cursor position
;               dx/     "new" cursor position adjusted for screen limits or
;                       scrolling region, depending on whether the original
;                       cursor position was inside or outside the scrolling
;                       region.
;
; On the VT100, a scroll does not occur unless the original cursor position
; was on the top or bottom margin.    This routine assumes that when decom is
; set the cursor position is set to the new origin, and that no other routine
; allows the cursor to be positioned outside the scrolling region as long
; as decom is set (which is the way a real VT100 works).  Note that for the
; normal case (no limited scrolling region defined) the margins are the same
; as the screen limits and scrolling occurs (as on a "normal" terminal) when
; an attempt is made to index off the screen.       Preserves cx.
; Revised 16 June 1987 [jrd]

atccic: push    cx
        mov     cx,low_rgt              ; get margins, cl = right margin
        mov     bl,dh                   ; get row
        xor     bh,bh
        cmp     bl,ch                   ; Below screen? [jrd]
        jg      atcci0                  ; g = yes, use single width line
        cmp     linetype[bx],0          ; single width chars?
        je      atcci0                  ; e = yes, single width
        shr     cl,1                    ; halve margin for double wides
atcci0: mov     ax,offset atign         ; Assume no scrolling necessary
        mov     bx,cursor               ; Get old cursor.
        cmp     dl,250                  ; To left of left margin?(wide screen)
        jb      atcci1                  ; b = no, go check right
        mov     dl,0                    ; No, set to left margin
atcci1: cmp     dl,cl                   ; To right of right margin
        jbe     atcci2                  ; be = yes, go check top
        mov     dl,cl                   ; No, set to right margin
atcci2: cmp     bh,mar_top              ; was old pos at scrolling top margin?
        jne     atcci5                  ; ne = no, check other end
        cmp     dh,mar_top              ; want to go above top margin?
        jge     atcci7                  ; ge = no
        mov     ax,offset atscrd        ; Yes, indicate scroll down required.
        mov     dh,mar_top              ; Set to top margin
        jmp     atcci7

atcci5: cmp     bh,mar_bot              ; Was old position at bottom margin?
        jne     atcci7                  ; ne = no, so don't trap cursor
        cmp     dh,mar_bot              ; want to go below?
        jb      atcci7                  ; b = no, nothing to worry about
        mov     ax,offset atscru        ; Yes, indicate scroll up required.
atcci6: mov     dh,mar_bot              ; Set to bottom margin
        pop     cx
        ret
atcci7: pop     cx                      ; old pos was outside scrolling region
        jmp     atccpc                  ; do full screen check and return

; This routine picks an attribute apart into its component "parts" - the
; base attribute for the screen and the "extras" - i.e., blink, intensity
; and underline.
;
; Call:         ah/     a cursor attribute
;
; Return:       ah/     base attribute for screen (07H normal, 70H reverse).
;               al/     "extra" attributes
;
; Note that there is a complementary routine, addatt, for putting attributes
; back together...
;

brkatt: mov     al,0                    ; Clear returned "extra" attributes
        cmp     crt_mode,7              ; monochrome display adapter mode?
        jne     brkat2                  ; ne = no. cut this short for color
        test    ah,att_low_mask         ; Any of these on?
        jnz     brkat1                  ; Yes, can't be underline
        test    ah,att_underline        ; Underline?
        jz      brkat2                  ; No, some kind of reverse video
        or      al,att_underline        ; Yes, say underline
        test    ah,70h ;;att_reverse    ; Reverse video + underline?
        jz      brkat1                  ; No, fix up low nibble
        and     ah,not att_underline    ; Yes, clear the underline bit in ah
        jmp short brkat2                ; And forge on.

brkat1: or      ah,att_normal           ; Normal - turn on all normal bits
brkat2: test    ah,att_intensity        ; Intensity attribute on?
        jz      brkat3                  ; No - check blink
        or      al,att_intensity        ; Yes - turn on the bit
brkat3: test    ah,att_blink            ; Blink on?
        jz      brkat4                  ; No - forge on
        or      al,att_blink            ; Yes - turn on the bit
brkat4: and     ah,not(att_intensity+att_blink) ;strip blink/bold, leave color
        ret

; This routine builds a cursor attribute given the base attribute for the
; screen background and the "extra" attributes we want (blink, etc.).
;
; Call:         ah/     base attribute for background (07H or 70H)
;               al/     "extra" attributes (89H for all three)
;
; Return:       ah/     base combined with "extras".
;

addatt: test    al,att_underline        ; Want underline?
        jz      addat1                  ; No - no need for hack
        and     ah,not att_low_mask     ; Yes - clear these bits
addat1: or      ah,al                   ; Or in the attributes.
        ret


; This routine is called when we want to reverse everything on the screen
; from normal to reverse video, or vice versa.  It is called only when
; the decscnm attribute is changed.
;
; Call:         no arguments.
;
; This routine may destroy ax-dx
;

revscn: mov     dh,byte ptr low_rgt+1   ; Compute last screen offset in ax
        inc     dh                      ; One more row to catch mode line
        mov     dl,crt_cols             ; physical width
        dec     dl                      ; and we count from 0
        call    scrloc
        mov     cx,ax                   ; Save it in cx for a minute
        mov     dx,0                    ; Compute first screen offset in ax
        call    scrloc
        sub     cx,ax                   ; Compute number of locs to change..
        add     cx,2
        sar     cx,1                    ; In 16-bit words please...
        push    di                      ; Save some more acs
        push    es
        push    cx                      ; save word count for Topview [jrd]
        push    ax                      ; save screen displacement
        call    scrseg                  ; Get address of screen in ax, es:di
        pop     ax                      ; recover displacement
        add     di,ax                   ; displacement addr of start of change
        call    scroff                  ; Turn screen off if color card.
revsc1: mov     ax,es:[di]              ; Fetch a word
        mov     bl,al                   ; Save the character
        call    brkatt                  ; Break up the attributes
        rol     ah,1                    ; Reverse the video
        rol     ah,1                    ; Reverse the video
        rol     ah,1                    ; Reverse the video
        rol     ah,1                    ; Reverse the video
        call    addatt                  ; Put attributes back together
        mov     al,bl                   ; Restore character
        mov     es:[di],ax              ; Stuff into screen memory.
        add     di,2                    ; Point di to next word of screen mem.
        loop    revsc1                  ; Loop for entire screen.
        pop     cx                      ; recover word count for Topview [jrd]
        call    scrsync                 ; synch with Topview
        call    scron                   ; Turn screen back on if color card.
        pop     es                      ; Restore segment register
        pop     di                      ; And destination index
        ret


; Reset-everything routine.

atreset:mov     al,0                    ; Make cursor disappear for a while.
;;      call    csrtype
        mov     cursor,0                ; Cursor is at 0,0
        mov     ansflgs,0               ; reset these flags[jrd]
        cmp     flags.vtflg,ttvt100     ; VT100? [jrd]
        jne     atres7                  ; ne = no. [jrd]
        mov     ansflgs,decanm          ; turn on ANSI mode flag. [jrd]
atres7: mov     mar_top,0               ; Reset scrolling region
        mov     al,byte ptr low_rgt+1
        mov     mar_bot,al
        mov     ah,vtemu.vtflgst
        mov     vtemu.vtflgop,ah
        mov     vtflags,ah
        mov     insmod,0                ; reset insert mode. [jrd]
        mov     h19l25,0                ; clear heath 25th line enable
        mov     h19ctyp,1               ; Heath-19 cursor to underline [jrd]
        mov     anspflg,0               ; clear printer flag [jrd]
        mov     cx,4                    ; Initialize the "LEDs". [jrd]
        mov     al,led_off              ; Turn them all off.
        mov     di,offset ansleds+6     ; Point to the "LEDs".
        push    es                      ; save es
        push    ds
        pop     es                      ; use datas segment for es:di below
        cld                             ; set forward direction
        rep     stosb                   ; Do it. [jrd]
        pop     es
        call    disleds                 ; update mode line. [jrd]
        mov     vttabs,offset deftabs   ; [jrd]
        call    cpytabs                 ; Initialize tab stops.
        call    chrdef                  ; Set default character set.
        call    vtbell                  ; Ding bell like VT100
        test    vtflags,vsnewline       ; Want ANSI newline mode?
        jz      atres1                  ; No.
        or      ansflgs,anslnm          ; Yes - set it in the mode flags.
atres1: test    vtflags,vswrap          ; How about autowrap?
        jz      atres2                  ; No.
        or      ansflgs,decawm          ; Yes - set it in the mode flags.
atres2: mov     ah,att_normal           ; get present normal coloring
        call    brkatt                  ; separate color and blink/bold
        rol     ah,1                    ; reverse fore/back color fields
        rol     ah,1
        rol     ah,1
        rol     ah,1
        call    addatt                  ; put back blink/bold
        mov     att_reverse,ah          ; this is the reverse video code
        mov     al,att_normal           ; Assume normal video.
        test    vtflags,vsscreen        ; Want reverse video?
        jz      atres3                  ; No.
        or      ansflgs,decscnm         ; Yes - turn on the mode flag...
        xchg    al,ah                   ; And reverse the video.
atres3: mov     cx,slen                 ; typically 24 but do max lines [jrd]
        mov     di,0
atres8: mov     linetype[di],0          ; clear the linetype array to single
        inc     di                      ; width/height characters.
        loop    atres8
        mov     curattr,al              ; Give cursor and screen nice
        mov     scbattr,al              ; attributes..
        mov     oldbatr,al              ; place to remember long term
        mov     mlbattr,ah              ; Give the other to the mode line.
        and     mlbattr,not att_intensity       ; turn off intensity bit
        mov     video_state,0           ; say normal video. [jrd]
        mov     ax,0                    ; Clear entire screen.
        mov     bx,low_rgt
        mov     bl,crt_cols
        dec     bl                      ; do physical screen
        call    atsclr
        mov     dx,cursor               ; Set cursor to 0,0.
        call    atscu5
        call    atsc                    ; Give saved cursor reasonable values.
        call    atsctyp                 ; Set right cursor type.
        mov     al,yflags
        call    telmsy                  ; update msy about ansflgs state

        test    yflags,modoff           ; is mode line off?
        jnz     atres9                  ; nz = yes
        push    dx                      ; save cursor position
        call    trnmod                  ; toggle off then on again so we
        call    trnmod                  ;   use it with current coloring
        pop     dx
atres9: ret

; Routine to set cursor type (block, underline).

atsctyp:cmp     flags.vtflg,ttheath     ; Heath-19?
        jne     atsct0                  ; ne = no
        mov     al,h19ctyp              ; get cursor kind and on/off bit
        test    al,4                    ; is cursor to be off?
        jz      atsct1                  ; z = no, al has kind
        mov     al,0                    ; turn off cursor
        jmp     short atsct1            ; do it
atsct0: mov     al,1                    ; Assume underline.
        test    vtflags,vscursor        ; Want block?
        jnz     atsct1                  ; nz = no, underline
        mov     al,2                    ; Yes.
atsct1: call    csrtype                 ; Do it.
        ret

; Routine to set default character set.

chrdef: mov     al,ascset               ; Assume US ASCII.
        test    vtflags,vsshift3        ; Want UK for default?
        jz      chrde1                  ; No.
        mov     al,ukset                ; Yes - use the UK set.
chrde1: mov     chr_sg0,al              ; Reset character sets.
        mov     chr_sg1,al
        mov     ax,offset chr_sg0       ; Select character set zero.
        mov     chr_set,ax
        ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; end of part one ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; start of part two ;;;;;;;;;;;;;;;;;;;;;;;;;;
; Routine to set special graphics character set (used in VT52 mode).

chrsgs: mov     al,sgrset               ; Select "graphics" set.
        jmp     chrde1                  ; Do it and return.

; Control-character handling routines

atbel:  call    vtbell                  ; Just ring bell and return.
        ret

atbs:   cmp     dl,0                    ; Backspace. too far?
        je      atbs1                   ; e = at column 0 already.
        dec     dl                      ; Backup cursor
atbs1:  call    atccpc                  ; Check range
        jmp     atscu5                  ; Set cursor and return

atht:   cmp     flags.vtflg,ttheath     ; Heath-19 mode? [jrd]
        je      atht2                   ; e = yes. handle specially. [jrd]
        cmp     dl,byte ptr low_rgt     ; At or beyond last column?
        jae     atbs1                   ; Yes, check range, set cursor and ret
        mov     al,0                    ; For ORing.
        mov     bh,0                    ; Make an index
        mov     bl,dl                   ; For column.
atht1:  inc     bx                      ; Tab always moves at least one space.
        or      al,tabs[bx]             ; Look for non-zero.
        jz      atht1                   ; ...
        mov     dl,bl                   ; Get the new row index
        jmp     atbs1                   ; Check range, set cursor, and return
atht2:  mov     dx,cursor               ; Heath-19. get cursor position
        add     dl,8                    ; tabs are every 8 columns
        and     dl,not 7                ; do modulo 8
        cmp     dl,byte ptr low_rgt     ; check against right edge
        jae     atht3                   ; ae = out of range
        jmp     atscu5                  ; set cursor and return
atht3:  test    ansflgs,decawm          ; doing line wrapping?
        jnz     atht4                   ; nz = yes. wrap to next line
        mov     dl,byte ptr low_rgt     ; else go to right margin
        jmp     atscu5                  ; set cursor and return
atht4:  inc     dh                      ; say want next line down
        xor     dl,dl                   ; and left margin
        call    atccic                  ; index check
        call    ax                      ; do any needed scrolling
atht4a: jmp     atscu5                  ; reset cursor

atlf:   cmp     flags.vtflg,ttheath     ; Heath-19 mode? [jrd]
        je      atlf2                   ; e = yes [jrd]
        test    ansflgs,anslnm          ; New-line mode?
        jz      atlf2                   ; No - just move to next line down
        mov     dl,0                    ; Yes - move to left margin also.
atlf2:  inc     dh                      ; Index line down
        call    atccic                  ; Check indexing
        call    ax                      ; Call scrolling routine
        jmp     atscu5                  ; Set cursor

atcr:   mov     dl,0                    ; Go to left margin
        jmp     atscu5                  ; Set cursor and return.

atff:   cmp     ttstate,offset atescf   ; parsing escape sequence?
        jne     atlf                    ; ne = no, do as line feed
        test    denyflg,200h            ; is auto Tek mode disabled?
        jnz     atlf                    ; nz = yes, treat as line feed.
        call    atsc                    ; save cursor and associated data
        JMP     TEKESC                  ; Jump to Tektronix Emulator, al=FF

atso:   mov     ax,offset chr_sg1       ; Select set G1 and return
        mov     chr_set,ax
        ret

atsi:   mov     ax,offset chr_sg0       ; Select set G0 and return
        mov     chr_set,ax
        ret

atcan:  cmp     ttstate,offset atnrm    ; doing normal chars (vs esc seq)?
        jne     atcan1                  ; ne = no, assume esc seq
        jmp     atign                   ; ignore ^X, ^Z in normal mode
atcan1: mov     ttstate,offset atnrm    ; Reset state to "normal".
        mov     al,sgrtab+2             ; replace CAN (^X) by checkerboard
        jmp     atnrm                   ; Process char as a normal one

atesc:  mov     nansarg,0               ; Clear ANSI arguments
        mov     al,0
        mov     cx,lansarg
        mov     di,offset ansargs
        push    es
        push    ds
        pop     es                      ; use datas segment for es:di below
        cld                             ; set direction forward
        rep     stosb
        pop     es
        and     ansflgs,not decmode     ; Clear "DEC modes" flag.
        mov     h19mod,0                ; clear Heath-19 mode flag
        mov     ttstate,offset atescf   ; Next state is escape follower
        ret

atescf: cmp     flags.vtflg,ttvt100     ; VT100? [jrd]
        jne     atv52f                  ; ne = not VT100, try others. [jrd]
atescf0:mov     cx,lansesc              ; Escape follower - get table length
        mov     di,offset ansesc        ; Point di at table
        push    es
        push    ds
        pop     es                      ; use datas segment for es:di below
        cld                             ; set direction forward
        repne   scasb                   ; Find it.
        pop     es
        je      atescf1                 ; Found - now go do something with it
        jmp     atnorm                  ; Not there - just ignore it.

atescf1:mov     di,lansesc - 1          ; Compute word index into jump table.
        sub     di,cx
        shl     di,1
        jmp     ansejt[di]              ; Dispatch to the routine.

atv52f: cmp     flags.vtflg,ttheath     ; Heath-19? [jrd]
        je      ath19f                  ; e = yes. Use Heath esc seqs. [jrd]
        mov     ttstate,offset atnrm    ; Assume state "normal" on return.
        mov     cx,lv52esc              ; Get table length
        mov     di,offset v52esc        ; Point di at table.
        push    es
        push    ds
        pop     es                      ; use datas segment for es:di below
        cld                             ; set direction forward
        repne   scasb                   ; Find it.
        pop     es
        je      atv52f1                 ; Found - do something with it.
        ret                             ; Not there - just ignore it.

atv52f1:mov     di,lv52esc - 1          ; Compute word index into jump table.
        sub     di,cx
        shl     di,1
        jmp     v52ejt[di]              ; Dispatch to the routine.

ath19f: mov     ttstate,offset atnrm    ; Assume state "normal" on return.
        test    ansflgs,decanm          ; ansi mode?
        jnz     atescf0                 ; nz = yes, use ansi table
        mov     cx,lh19esc              ; Get table length
        mov     di,offset h19esc        ; Point di at table.
        push    es
        push    ds
        pop     es                      ; use datas segment for es:di below
        cld                             ; set direction forward
        repne   scasb                   ; Find it.
        pop     es
        je      ath19f1                 ; Found - do something with it.
        ret                             ; Not there - just ignore it.

ath19f1:mov     di,lh19esc - 1          ; Compute word index into jump table.
        sub     di,cx
        shl     di,1
        jmp     h19ejt[di]              ; Dispatch to the routine.


; Escape follower routines.

atcsi:  mov     ttstate,offset atpaa    ; Next state is parse ansi args.
        ret

atpaa:  test    al,80h                  ; high bit set?
        jz      atpaa6                  ; z = no
        and     al,7fh                  ; strip high bit
        cmp     al,' '                  ; control code remainder?
        jae     atpaa6                  ; ae = no, use 7 bit result
        mov     ttstate,offset atnrm    ; reset state to normal text
        jmp     atctrl                  ; execute 7 bit control code
atpaa6: cmp     al,'0'                  ; A digit?
        jb      atpaa1                  ; No - just ignore it.
        cmp     al,'9'                  ; Maybe - A separator or final char?
        ja      atpaa2                  ; Perhaps - go check it out
        mov     cl,al                   ; A digit - convert ASCII to binary
        sub     cl,'0'
        mov     bl,nansarg              ; put index in bx [dlk]
        xor     bh,bh
        mov     al,ansargs[bx]          ; Pick up what we've done so far [dlk]
        shl     al,1                    ; multiply by 10.  2 * al
        mov     ah,al                   ; save
        shl     al,1                    ; 4 * al
        shl     al,1                    ; 8 * al
        add     al,ah                   ; 10 * al
        mov     ah,0                    ; clear high field
        add     ax,cx                   ; add in this digit [dlk]
        cmp     ax,0feh                 ; max value is 0ffh [dlk]
        jbe     atpaa0                  ; be = ok [dlk]
        mov     al,0ffh                 ; set to max value [dlk]
atpaa0: mov     ansargs[bx],al          ; Put result back for next time [dlk]
atpaa1: ret                             ; And return

atpaa2: cmp     al,'?'                  ; The deadly question mark?
        jne     atpaa2a                 ; No - check further.
        or      ansflgs,decmode         ; Yes - say DEC modes are coming.
        ret                             ; And return.
atpaa2a:cmp     al,'>'                  ; Heath private mode? [jrd]
        jne     atpaa3                  ; ne = no
        cmp     flags.vtflg,ttheath     ; emulating a Heath-19?
        jne     atpaa3                  ; ne = no, ignore this sequence
        mov     h19mod,1                ; say Heath mode sequence follows.
        ret

atpaa3: cmp     al,';'                  ; Argument separator?
        jne     atpaa4                  ; No - check for final char.
        mov     al,nansarg              ; Get argument index
        inc     al                      ; Bump it.
        cmp     al,lansarg              ; Too many?
        jl      atpa3a                  ; l = no, continue
        mov     ttstate,offset atnrm    ; Reset state to "normal".
        ret                             ; and pretend all is well [jrd]
; [jrd] jmp     atcan                   ; Yes - abandon sequence on error.
atpa3a: mov     nansarg,al              ; Save it.
        ret

atpaa4: mov     cx,lanstab
        mov     di,offset anstab        ; Look for it in the table
        push    es
        push    ds
        pop     es                      ; use datas segment for es:di below
        cld                             ; set direction forward
        repne   scasb
        pop     es
        je      atpaa5                  ; Found it - go dispatch
        cmp     al,40h                  ; in range for a legal terminator?
        jb      atpaa4a                 ; b = not in range, ignore
        cmp     al,7eh                  ; other end of the range
        ja      atpaa4a                 ; a = out of range, ignore
                                        ; in range, absorb and become normal
        mov     ttstate,offset atnrm    ; Put state back to normal
atpaa4a:ret                             ; Just return if it is unknown.

atpaa5: mov     ttstate,offset atnrm    ; Put state back to normal
        mov     di,lanstab - 1          ; Compute word index into jump table.
        sub     di,cx
        shl     di,1
        jmp     ansjmp[di]              ; Off into the wild blue...

atind:  inc     dh                      ; Index - move cursor down one.
atind1: call    atccic                  ; Check cursor position.
        call    ax                      ; Scroll if necessary.
        mov     ttstate,offset atnrm    ; Reset state.
        jmp     atscu5                  ; Set cursor, etc. and return.

atnel:  mov     dl,0                    ; Next line - sort of like CRLF...
        inc     dh                      ; ... all in one command
        jmp     atind1                  ; Check cursor, etc., and return.

atri:   dec     dh                      ; Reverse index...
        jmp     atind1                  ; Check cursor, etc., and return.

athts:  call    atccpc                  ; Make sure we have valid column number.
        mov     dh,0                    ; Zap row
        mov     al,0FFH                 ; Indicates a tab stop
        mov     di,dx                   ; Dumb specialized registers.
        mov     tabs[di],al             ; Store it.
        jmp     atnorm                  ; Reset state and return.

atsc:   mov     si,offset curattr       ; Save cursor, attribute, char set etc.
        mov     di,offset savecu        ; Place to save the stuff.
        mov     cx,lsavecu              ; Length of save area
        push    es                      ; save es
        push    ds
        pop     es                      ; set es to datas segment
        cld
        rep     movsb                   ; Save it.
        pop     es
        mov     cl,ansflgs              ; Save a copy of the flags.
        mov     savflgs,cl              ; ...
        jmp     atnorm                  ; Reset state and return.

atrc:   mov     si,offset savecu        ; Restore cursor, attributes, etc..
        mov     di,offset curattr       ; Where stuff goes
        mov     cx,lsavecu              ; Length of save area
        push    es                      ; save es
        push    ds
        pop     es                      ; set es to datas segment
        cld
        rep     movsb                   ; Put the stuff back.
        pop     es
        mov     al,savflgs              ; Get saved flags
        xor     al,ansflgs              ; Exclusive-or with current flags
        test    al,decscnm              ; Did screen mode change?
        jz      atrc1                   ; No, just reset saved flags and leave
        mov     ah,curattr              ; Get cursor attribute that was saved
        call    brkatt                  ; Break into background & extra stuff
        rol     ah,1                    ; Reverse the background
        rol     ah,1                    ; Reverse the background
        rol     ah,1                    ; Reverse the background
        rol     ah,1                    ; Reverse the background
        call    addatt                  ; Put it all back together
        mov     curattr,ah              ; Store
atrc1:  mov     al,ansflgs              ; Reset flags in case called again
        and     al, not(decckm+deckpam+decom)  ; remove old bits [dlk]
        and     savflgs,(decckm+deckpam+decom) ; remove all but new bits [dlk]
        or      al,savflgs              ; restore saved bits [dlk]
        mov     ansflgs,al              ; update these flags [dlk]
        mov     savflgs,al
        mov     dx,cursor               ; Get cursor
        mov     kbiflg,0                ; Don't bother them with beeps here
        call    atscu5                  ; Set cursor.
        jmp     atnorm                  ; Reset state and return.

atkpam: or      ansflgs,deckpam         ; Turn on the bit
        mov     al,yflags
        call    telmsy                  ; inform msy of new state
        jmp     atnorm                  ; Reset state and return.

atkpnm: and     ansflgs,not deckpam     ; Turn off the bit
        mov     al,yflags
        call    telmsy                  ; inform msy of new state
        jmp     atnorm                  ; Reset state and return.

atris:  call    atreset                 ; Reset everything
        jmp     atnorm                  ; And state too, return, etc.

atsg0:  mov     ttstate,offset atsg01   ; Setup to get last character
        ret

atsg01: call    atscs                   ; Get code for character set
        mov     chr_sg0,al              ; Store it.
        jmp     atnorm                  ; Reset state etc. and return

atsg1:  mov     ttstate,offset atsg11   ; Setup to get last character
        ret

atsg11: call    atscs                   ; Get code for character set
        mov     chr_sg1,al              ; Store it.
        jmp     atnorm                  ; Reset state etc. and return

atscs:  cmp     al,'A'                  ; UK ASCII set?
        jne     atscs1                  ; No.
        mov     al,ukset                ; Yes - give them that and return
        ret

atscs1: cmp     al,'B'                  ; US ASCII set?
        jne     atscs3                  ; No.
atscs2: mov     al,ascset               ; Yes - give them that and return
        ret

atscs3: cmp     al,'0'                  ; Special graphics set?
        jne     atscs4                  ; ne = no
        mov     al,sgrset               ; Yes - say that's what it is
        ret

atscs4: cmp     al,'1'                  ; alt char ROM, std char set? [jrd]
        jne     atscs5                  ; ne = no
        mov     al,ascset               ; use US ASCII set
        ret

atscs5: cmp     al,'2'                  ; alt char ROM, special graphics?[jrd]
        jne     atscs2                  ; ne = no, use US ASCII
        mov     al,sgrset               ; set graphics
        ret

                                        ; ESC # Pn  series. [jrd]
atsdhl: mov     ttstate,offset atsdbl   ; set up to parse argument
        ret
atsdbl: cmp     al,'3'                  ; Double high lines. Top half? [jrd]
        je      atsdh2                  ; e = yes
        cmp     al,'4'                  ; bottom half?
        je      atsdh2                  ; e = yes
        cmp     al,'5'                  ; restore line to single width?
        je      atsdh1                  ; e = yes
        cmp     al,'6'                  ; double width single height?
        je      atsdh2                  ; e = yes
        cmp     al,'8'                  ; screen alignment?
        je      atsdh8                  ; e = yes
        jmp     atnorm                  ; else ignore
atsdh1: call    linesgl                 ; set line to single width
        jmp     atnorm
atsdh2: call    linedbl                 ; expand the line to double width
        jmp     atnorm                  ; set state to normal and ret
atsdh8: call    atalign                 ; do screen alignment
        jmp     atnorm
atpriv: mov     ttstate,offset atnorm   ; ignore next char.
        ret                             ; and return to normal afterward.

atalign proc    near                    ; Fill screen with 'E'
        call    atreset                 ; clear system
        or      ansflgs,decawm          ; set wrap
        mov     cl,byte ptr low_rgt     ; number of columns-1
        inc     cl
        mov     al,byte ptr low_rgt+1   ; number of rows-1
        inc     al
        mul     cl                      ; ax = number of chars on screen
        mov     cx,ax
atalig1:push    cx
        mov     al,'E'                  ; write screen full of E's
        call    atnrm                   ; write the 'E'
        pop     cx
        loop    atalig1                 ; cx times
        ret
atalign endp

; This routine may be used to repeat a call to a selected action routine
; for all of the ANSI parameters given in a call.   When the action routine
; is called, si will contain the index for the current ANSI parameter (i.e.,
; the current ANSI parameter may be gotten using ansargs[si] for an effective
; address).     The action routine may modify any ACs it wants, but cx, si,
; and di are preserved over the call to the action routine, so these may
; not be used for building return values for the original caller.   Note that
; if there are no ANSI parameters, the effect is the same as if one ANSI
; parameter with a value of zero was given.
;
; Call:         di/     offset of action routine in code seqment
;

atreps: mov     cl,nansarg              ; Pick up number of parameters
        inc     cl                      ; Zero parms is same as 1 zero parm.
        mov     ch,0
        mov     si,0                    ; Init parm index
atrep1: push    cx                      ; Save important acs
        push    si
        push    di
        call    di                      ; Call indicated routine
        pop     di                      ; Restore acs
        pop     si
        pop     cx
        inc     si                      ; Advance to next parameter
        loop    atrep1                  ; Loop for all
        ret                             ; And return.


; Final char (ANSI) routines.

atcup:  mov     dh,ansargs              ; Get the two arguments
        mov     dl,ansargs+1
        cmp     dh,0                    ; Zero line number?
        jne     atcup1                  ; No - continue
        mov     dh,1                    ; Yes - default to one.
atcup1: cmp     dl,0                    ; Ditto for row
        jne     atcup2
        mov     dl,1
atcup2: dec     dh                      ; Now normalize
        dec     dl
        test    ansflgs,decom           ; Origin mode?
        jz      atcup4                  ; No - skip this stuff
        add     dh,mar_top              ; Yes - it was relative to top margin
        jno     atcup4                  ; If no overflow, continue
        mov     dh,byte ptr low_rgt+1   ; Otherwise just set to screen bottom
atcup4: cmp     dh,byte ptr low_rgt+1   ; going to 25th line? [hlk]
        jbe     atcup5                  ; be = no [dlk]
        cmp     flags.vtflg,ttheath     ; emulating a Heath-19? [jrd]
        jne     atcup6                  ; ne = no [hlk]
        cmp     h19l25,0                ; Heath 25th line enabled?
        je      atcup5                  ; e = no
        mov     dh,byte ptr low_rgt+1   ; [hlk]
        inc     dh                      ; go there
        jmp     atscu4                  ; set cursor position & mode line

atcup6: test    ansflgs,decom           ; origin mode? [jrd]
;;;##   jz      atcup5                  ; z = no, no 25th line stuff allowed
        mov     dh,byte ptr low_rgt+1   ; bottom normal line
        inc     dh                      ; the 25th line
        jmp     atscu4                  ; set cursor position and return
atcup5: call    atccpc                  ; Check position
        jmp     atscu5                  ; Set cursor position and return.

atcuarg:mov     al,ansargs              ; Get a cursor move argument
        cmp     al,0                    ; Zero?
        jne     atcua1                  ; No - return
        mov     al,1                    ; Yes - default to one.
atcua1: ret                             ; Return.
                                        ; Disallow movement to 25th line.
atcuu:  call    atcuarg                 ; Get cursor move argument in al
        sub     dh,al                   ; Compute new cursor position
        jnc     atcuu1                  ; nc = ok [dlk]
        xor     dh,dh                   ; overflow, restrict range. [dlk]
atcuu1: call    atccic                  ; check indexing, ignore action in ax
        jmp     atscu5                  ; set the cursor at its new position

atcud:  call    atcuarg                 ; Get the argument
        add     dh,al                   ; Compute new cursor position
        jnc     atcud1                  ; nc = ok [dlk]
        mov     dh,byte ptr low_rgt+1   ; default bottom [dlk]
atcud1: call    atccic                  ; check indexing, ignore action in ax
        jmp     atscu5                  ; set the cursor at its new position

                                        ; Allow horiz movement on 25th line.
atcuf:  call    atcuarg                 ; Get the argument
        add     dl,al                   ; Compute new cursor position
        jnc     atcup4                  ; If no carry, continue [dlk]
        mov     dl,byte ptr low_rgt     ; Else set to right margin
        jmp     atcup4                  ; Check/set cursor, return.

atcub:  call    atcuarg                 ; Get the argument
        sub     dl,al                   ; Compute new cursor position
        jnc     atcup4                  ; If no carry, continue [dlk]
        mov     dl,0                    ; Else set to left margin
        jmp     atcup4                  ; Check/set cursor, return.

ated:   mov     di,offset ated0         ; Routine to process parm.
        call    atreps                  ; Do all selected parms.
        ret

ated0:  cmp     ansargs[si],0           ; Was arg zero?
        jne     ated2                   ; No - continue
        mov     ax,dx               ; Yes - erase from cursor to end of screen
        push    dx                      ; save dx
        mov     bl,dh                   ; get row number
        xor     bh,bh
        cmp     linetype [bx],0         ; single width line?
        je      ated0a                  ; e = yes
        shl     dl,1                    ; physical column is twice logical
ated0a: or      dl,dl                   ; starting at left margin?
        je      ated0b                  ; e = yes, this goes to single width
        inc     bl                      ; else start on next line
ated0b: cmp     bl,byte ptr low_rgt+1   ; at the end of the screen?
        ja      ated0c                  ; a = yes, stop singling-up
        mov     byte ptr linetype [bx],0 ; set to single width
        inc     bx
        jmp     short ated0b            ; loop, reset lines to end of screen
ated0c: mov     bx,low_rgt              ; erase from cursor to end of screen
        mov     bl,crt_cols
        dec     bl                      ; do physical screen width
        call    atsclr                  ; Clear it.
        pop     dx                      ; restore dx
ated1:  ret

ated2:  cmp     ansargs[si],1           ; Was arg one?
        jne     ated3                   ; No - continue
        mov     ax,0                    ; Yes -  erase from start of screen...
                                        ; ...to cursor, inclusive
        xor     bx,bx                   ; start at top row (0)
ated2b: cmp     bl,dh                   ; check rows from the top down
        jae     ated2c                  ; ae = at or below current line
        mov     byte ptr linetype [bx],0; set line to single width
        inc     bx                      ; inc row
        jmp     short ated2b            ; look at next line
ated2c: or      dl,dl                   ; at left margin of current line?
        jne     ated2d                  ; ne = no, leave line width intact
        mov     byte ptr linetype [bx],0 ; convert to single width
ated2d: mov     bl,dh                   ; get row number
        xor     bh,bh
        cmp     linetype [bx],0         ; single width line?
        je      ated2a                  ; e = yes
        shl     dl,1                    ; physical column is twice logical
ated2a: mov     bx,dx                   ; cursor position to bx
        call    atsclr                  ; Clear it.
        ret

ated3:  cmp     ansargs[si],2           ; Was arg two?
        jne     ated1                   ; No - ignore it.
        mov     ax,0                    ; Yes - erase entire screen.
        mov     bx,low_rgt
        mov     bl,crt_cols
        dec     bl                      ; physical width
        call    atsclr                  ; Clear it.
        push    bx
        push    cx                      ; set all 24 lines to single width
        mov     cl,byte ptr low_rgt+1   ; number of last line
        xor     ch,ch
        inc     cx                      ; count from one
        xor     bx,bx
ated3a: mov     linetype [bx],0
        inc     bx
        loop    ated3a
        pop     cx
        pop     bx
        ret

atel:   mov     di,offset atel0         ; Get routine to call
        call    atreps                  ; Repeat for all parameters.
        ret

atel0:  cmp     ansargs[si],0           ; Was arg zero?
        jne     atel2                   ; No - continue
        mov     ax,dx                   ; Yes - erase from cursor...
        mov     bh,dh                   ; ...to end of line, inclusive
        push    bx
        mov     bl,bh                   ; get row
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        je      atel0a                  ; e = yes
        shl     al,1                    ; physical column is twice logical
atel0a: pop     bx
        mov     bl,byte ptr low_rgt
        call    atsclr                  ; Clear it.
atel1:  ret

atel2:  cmp     ansargs[si],1           ; Was arg one?
        jne     atel3                   ; No - continue
        mov     ah,dh                   ; Yes -  erase from start of line...
        mov     al,0
        mov     bx,dx                   ; ...to cursor, inclusive
        push    bx
        mov     bl,dh                   ; get row
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        pop     bx                      ; pop does not affect flags
        je      atel2a                  ; e = yes
        shl     bl,1                    ; physical column is twice logical
atel2a: call    atsclr                  ; Clear it.
        ret

atel3:  cmp     ansargs[si],2           ; Was arg two?
        jne     atel1                   ; No - ignore it.
        mov     ah,dh                   ; Yes - erase entire line.
        mov     al,0
        mov     bh,dh
        mov     bl,byte ptr low_rgt
        mov     bl,crt_cols
        dec     bl                      ; physical line
        call    atsclr                  ; Clear it.
        ret

atsgr:  mov     ah,curattr              ; Get current cursor attribute
        call    brkatt                  ; Break it apart.
        mov     di,offset atsgr1        ; Routine to call.
        call    atreps                  ; Repeat for all parms.
        call    addatt                  ; Put the attributes back together
        mov     curattr,ah              ; Store.
        ret

atsgr1: mov     bl,ansargs[si]          ; Fetch an argument
        cmp     bl,0                    ; Zero?
        jne     atsgr2                  ; No.
        mov     al,0                    ; Yes - clear the "extras"
        mov     ah,scbattr              ; And reset background.
        and     ah,77h                  ; clear blink/bold here
        mov     video_state,0           ; say normal video now. [jrd]
        ret

atsgr2: cmp     bl,1                    ; One?
        jne     atsgr3                  ; No.
        or      al,att_intensity        ; Yes - set bold
        ret

atsgr3: cmp     bl,4                    ; Four? Underline. Mods by [jrd]
        jne     atsgr4                  ; No.
        or      al,att_underline        ; Yes, set underscore.
        cmp     crt_mode,7              ; monochrome display adapter mode?
        je      atsgr3a                 ; e = yes. Otherwise reverse video
                        ; use reversed video rather than blue on black
        and     al,not att_underline    ; clear underline and [jrd]
        rol     ah,1                    ; reverse the colors [jrd]
        rol     ah,1                    ; [jrd]
        rol     ah,1                    ; [jrd]
        rol     ah,1
atsgr3a:ret

atsgr4: cmp     bl,5                    ; Five?
        jne     atsgr5                  ; No.
        or      al,att_blink            ; Yes - set blink
        ret

atsgr5: cmp     bl,7                    ; Seven?
        jne     atsgr6                  ; No - just ignore it.
        cmp     video_state,0           ; is video normal? [jrd]
        jne     atsgr6                  ; ne = no, reversed already, ignore
        rol     ah,1                    ; reverse the colors
        rol     ah,1
        rol     ah,1
        rol     ah,1
        mov     video_state,1           ; say reversed now.
        ret

atsgr6: cmp     bl,30                   ; ANSI color series? [jrd]
        jb      atsgrx                  ; b = no.
        cmp     bl,37                   ; foreground set (30-37)?
        ja      atsgr7                  ; a = no, try background set.
        sub     bl,30                   ; take away the bias
        and     ah,not 07H              ; clear foreground bits
        test    bl,1                    ; ANSI red?
        jz      atsgr6a                 ; z = no
        or      ah,4                    ; IBM red foreground bit
atsgr6a:test    bl,2                    ; ANSI & IBM green?
        jz      atsgr6b                 ; z = no
        or      ah,2                    ; IBM green foreground bit
atsgr6b:test    bl,4                    ; ANSI blue?
        jz      atsgr6c                 ; z = no
        or      ah,1                    ; IBM blue foreground bit
atsgr6c:ret

atsgr7: cmp     bl,40                   ; background color set?
        jb      atsgrx                  ; b = no
        cmp     bl,47                   ; background set is 40-47
        ja      atsgrx                  ; nb = no, not a color command.
        sub     bl,40                   ; take away the bias
        and     ah,not 70H              ; clear background bits
        test    bl,1                    ; ANSI red?
        jz      atsgr7a                 ; z = no
        or      ah,40h                  ; IBM red background bit
atsgr7a:test    bl,2                    ; ANSI & IBM green?
        jz      atsgr7b                 ; z = no
        or      ah,20h                  ; IBM green background bit
atsgr7b:test    bl,4                    ; ANSI blue?
        jz      atsgrx                  ; z = no
        or      ah,10h                  ; IBM blue background bit

atsgrx: ret

attbc:  call    atccpc                  ; Make sure cursor is kosher
        mov     di,offset attbc0        ; Routine to call
        call    atreps                  ; Do for all parms
        ret

attbc0: cmp     ansargs[si],0           ; Was argument zero?
        jne     attbc2                  ; No - check further
        mov     dh,0                    ; Zap row for indexing
        mov     di,dx
        mov     tabs[di],0              ; clear tab stop
attbc1: ret

attbc2: cmp     ansargs[si],3           ; Was arg 3 (clear all tab stops)?
        jne     attbc1                  ; No - just ignore it.
        mov     cx,swidth               ; Get ready to zap swidth columns
        mov     di,offset tabs          ; Point to the tab stop table.
        mov     al,0                    ; zero indicates no tab stop.
        push    es                      ; save es
        push    ds
        pop     es                      ; use datas segment for es:di below
        cld                             ; set direction forward
        rep     stosb                   ; Blit full of zeros.
        pop     es
        ret

atstbm: mov     al,ansargs              ; Get the two line number args
        mov     ah,ansargs+1
        cmp     al,0                    ; Was first zero?
        jne     atstb1                  ; No - continue
        mov     al,1                    ; Yes - default is one
atstb1: cmp     ah,0                    ; Was second zero?
        jne     atstb2                  ; No - continue
        mov     ah,byte ptr low_rgt+1   ; Yes - default is last line on screen
        inc     ah
atstb2: dec     al                      ; Normalize to our coord. system
        dec     ah
        cmp     ah,al                   ; Is size of region at least two lines?
        jbe     atstb3                  ; be = if not, indicate an error.
        cmp     al,0                    ; Check against screen limits.
        jl      atstb3
        cmp     ah,byte ptr low_rgt+1
        ja      atstb3
        mov     mar_top,al              ; Set the limits
        mov     mar_bot,ah
        mov     dx,0                    ; Home cursor
        call    atccpc                  ; Check cursor (get it inside window)
        jmp     atscu5                  ; Set cursor position and return.

atstb3: ret                             ; ignore bad requests
;;;     jmp     atcan                   ; Indicate error and return.

atda:   cmp     ansargs,0               ; Was argument zero?
        je      decid                   ; Yes - send the i.d. string.
        ret                             ; No - only an echo...
at52id: mov     ttstate,offset atnrm    ; ensure state is correct
decid:  mov     cx,ldastr               ; Length of the string
        mov     si,offset dastr         ; Point to the string
        cmp     flags.vtflg,ttvt100     ; VT100? [jrd]
        je      decid1                  ; e = yes [jrd]
        mov     cx,lv52str              ; No - try VT52 i.d. [jrd]
        mov     si,offset v52str
        cmp     flags.vtflg,ttvt52      ; Heath-19 mode? [jrd]
        je      decid1                  ; e = yes. [jrd]
        mov     cx,lh19str              ; length of Heath-19 ident string
        mov     si,offset h19str        ; say Heath-19. [jrd]
decid1: cld
        lodsb                           ; Get a byte
        push    cx                      ; Save the important registers
        push    si
        call    prtbout                 ; Send it to port with no local echo
        pop     si
        pop     cx
        loop    decid1                  ; Loop for all characters
        ret

atll:   mov     di,offset atleds        ; Get pointer to routine to call
        call    atreps                  ; Repeat for selective parameters.
        ret

atleds: cmp     ansargs[si],0           ; Zero argument?
        jne     atled3                  ; No - check further.
        mov     cx,4                    ; Reset the "LEDs". [jrd]
        mov     al,led_off              ; to all off.
        mov     di,offset ansleds+6     ; Point to the "LEDs".
        push    es                      ; save es
        push    ds
        pop     es                      ; make es:di point to datas seg
        cld                             ; move forward
        rep     stosb                   ; [jrd]
        pop     es
atled1: call    disleds                 ; Update "LEDs" display and return.
atled2: ret

atled3: mov     al,ansargs[si]          ; Get the argument
        cmp     al,1                    ; Must be .GE. 1
        jb      atled2                  ; If not just ignore it. [dlk]
        cmp     al,4                    ; Must be .LE. 4
        ja      atled2                  ; Ignore if not so. [dlk]
        dec     al                      ; Zero base it.
        cbw                             ; Convert to index in ax.
        mov     di,ax                   ; Dumb specialized registers.
        add     al,'1'                  ; add ascii offset for digit
        mov     ansleds[di+6],al        ; Turn the "LED" on by storing digit
        jmp     atled1                  ; Update display and return.

atreqt: cmp     ansargs,0               ; Want report?
        je      atreq1                  ; Yes - give report
        cmp     ansargs,1               ; Want report?
        je      atreq1                  ; Yes - give the report.
        ret                             ; Gee, must have been an echo...

atreq1: mov     al,escape               ; Send an escape to start off...
        call    prtbout
        mov     al,'['                  ; Then one of these...
        call    prtbout
        mov     al,'3'                  ; We only report on request...
        cmp     ansargs,0               ; was argument a zero?
        jne     atreq1a                 ; ne = no
        mov     al,'2'                  ; yes
atreq1a:call    prtbout
        mov     al,';'                  ; Separate
        call    prtbout
        mov     bl,parcode              ; Get the parity code
        mov     bh,0
        mov     al,partab[bx]           ; Get VT100 parity code
        push    ax                      ; save parity code
        call    prtnout                 ; Send number to the port..
        mov     al,';'                  ; Separate
        call    prtbout
        mov     al,'2'                  ; Assume 7 data bits
        pop     bx                      ; get parity code into bl
        cmp     bl,1                    ; is parity none?
        jne     atreq2                  ; ne = no, so 7 data bits
        test    flags.remflg,d8bit      ; 8 bit display?
        jz      atreq2                  ; z = no
        mov     al,'1'                  ; must be eight.
atreq2: call    prtbout                 ; Send it to the port
        mov     al,';'                  ; Separate
        call    prtbout
        mov     bl,baudidx              ; Baud rate index
        mov     bh,0
        mov     al,baudtab[bx]          ; Get DEC baud rate code
        push    ax
        call    prtnout                 ; Send it to the port
        mov     al,';'                  ; Separate
        call    prtbout                 ; Send it to the port
        pop     ax
        call    prtnout                 ; Send it to the port
        mov     al,';'                  ; Separate
        call    prtbout
        mov     al,'1'                  ; Clock rate multiplier is always 1
        call    prtbout
        mov     al,';'                  ; Separate (gasp - for the last time)
        call    prtbout
        mov     al,'0'                  ; Flags are always zero (no STP)
        call    prtbout
        mov     al,'x'                  ; Finally, say what this all was.
        call    prtbout
        ret

atdsr:  mov     di,offset atdsr1        ; Routine to call
        call    atreps                  ; Do for all parms.
        ret

atdsr1: cmp     ansargs[si],5           ; Want status?
        je      rpstat                  ; Yes - report status
        cmp     ansargs[si],6           ; Want cursor position?
        je      rpcup                   ; Yes - do it.
        cmp     ansargs[si],15          ; Printer status? [jrd]
        je      rpstap                  ; e = yes, do so.
        ret                             ; No - must have been an echo

rpstat: mov     al,escape               ; Tell them we think we are OK
        call    prtbout
        mov     al,'['
        call    prtbout
        mov     al,'0'
        call    prtbout
        mov     al,'n'
        call    prtbout
        ret

rpstap: test    ansflgs,decmode         ; Printer status report from    [jrd]
        jz      rpstap3                 ; ESC [ ? 15 n  request
        mov     al,escape
        call    prtbout
        mov     al,'['
        call    prtbout
        mov     al,'?'
        call    prtbout
        mov     al,'1'
        call    prtbout
        mov     ah,ioctl                ; get printer status, via DOS
        mov     al,7                    ; status for output
        push    bx
        mov     bx,4                    ; std handle for system printer
        int     dos
        pop     bx
        jc      rpstap1                 ; c = call failed
        cmp     al,0ffh                 ; code for Ready
        jne     rpstap1                 ; ne = not ready
        mov     al,'0'                  ; ready, send final digit
        jmp     rpstap2
rpstap1:mov     al,'3'                  ; not ready, say printer disconnected
rpstap2:call    prtbout
        mov     al,'n'                  ; final char of response
        call    prtbout
rpstap3:ret

rpcup:  mov     al,escape               ; Cursor position - send an escape
        call    prtbout
        mov     al,'['                  ; And one of these
        call    prtbout
        mov     al,byte ptr cursor+1    ; Get row
        inc     al                      ; They use coords that start at 1.
        test    ansflgs,decom           ; Origin mode set?
        jz      rpcup1                  ; No - continue
        sub     al,mar_top              ; Yes - subtract off top margin
rpcup1: call    prtnout                 ; Output the number.
        mov     al,';'                  ; Separate
        call    prtbout
        mov     al,byte ptr cursor      ; Now get the column number.
        inc     al                      ; Their coords start at 1.
        call    prtnout                 ; Send it off to the port.
        mov     al,'R'                  ; Finally end it with this
        call    prtbout
        ret

                                        ; ESC [ ? xxx h/l  series
atrm:   mov     modeset,0               ; Say we are resetting modes
        mov     di,offset atrsm         ; Reset/set modes.
        call    atreps                  ; Repeat for all parms.
        test    ansflgs,decanm          ; Did this get reset?
        jnz     atrm1                   ; No - return.
        cmp     flags.vtflg,ttheath     ; were we a Heath-19?
        je      atrm0                   ; e = yes, don't change terminal types
        mov     flags.vtflg,ttvt52      ; Yes. Say VT52 now. [jrd]
atrm0:  call    chrdef                  ; Yes - set default char sets.
        call    atsc                    ; Save cursor status.
        call    disleds                 ; update terminal type
atrm1:  ret

atsm:   mov     modeset,1               ; Say we are setting modes
        mov     di,offset atrsm         ; Reset/set modes.
        call    atreps                  ; Repeat for all parms.
        ret

atrsm:  mov     al,ansargs[si]          ; Pick up the argument.
        test    ansflgs,decmode         ; Is this DEC private mode ([ ?)stuff?
        jnz     atrsm1                  ; nz = yes - go check it out.
        cmp     h19mod,0                ; Heath-19 private mode ([ >)?
        je      atrsma                  ; e = no
        jmp     htrsm1                  ; yes, do Heath specific things.
atrsma: cmp     al,20                   ; No - ANSI new-line mode?
        jne     atrsm0                  ;  but try insert mode. [jrd]
        and     vtemu.vtflgop,not vsnewline ; assume resetting
        cmp     modeset,0               ; resetting?
        je      atrsmb                  ; e = yes
        or      vtemu.vtflgop,vsnewline ; setting
atrsmb: mov     al,anslnm               ; Yes - get the bit
        call    atrsflg                 ; Set or reset it
        ret
atrsm0: cmp     al,4                    ; toggle insert mode? [jrd]
        jne     atrsmx                  ; ne = no [jrd]
        mov     al,modeset              ; set/reset insert mode [jrd]
        mov     insmod,al               ; store it. [jrd]
atrsmx: ret

atrsm1: cmp     al,1                    ; Cursor keys mode?
        jne     atrsm2                  ; No - check some more
        mov     al,decckm               ; Yes - get the bit.
        jmp     atrsflg                 ; Set or reset it and return.

atrsm2: cmp     al,7                    ; Auto-wrap?
        jne     atrsm3                  ; No - check some more
        and     vtemu.vtflgop,not vswrap ; assume resetting line wrap
        cmp     modeset,0               ; resetting?
        je      atrsm2a                 ; e = yes
        or      vtemu.vtflgop,vswrap    ; set the bit
atrsm2a:mov     al,decawm               ; Yes - get the bit
        jmp     atrsflg                 ; Set or reset it and return.

atrsm3: cmp     al,6                    ; Origin mode?
        jne     atrsm4                  ; No - check for video change
        jmp     atrsom                  ; Yes - change decom and return.

atrsm4: cmp     al,5                    ; Change the video?
        jne     atrsm5                  ; No - check for VT52 mode set/reset.
        jmp     atrsscnm                ; Yes - change it if we have to and ret.

atrsm5: cmp     al,2                    ; Change VT52 compatibility mode?
        jne     atrsm6                  ; No - ignore unknown DEC private modes
        cmp     flags.vtflg,ttheath     ; Heath-19 mode? [jrd]
        je      atrsm5a                 ; e = yes, handle specially. [jrd]
        mov     al,ascset               ; return to US ascii graphics sets
        mov     chr_sg0,al              ; Store it.
        mov     chr_sg1,al              ; Store it.
        mov     al,decanm               ; Yes - get the flag.
        jmp     atrsflg                 ; Set or reset it and return.

atrsm5a:mov     modeset,0               ; Heath-19 ESC [ ? 2 h, reset ansi
        mov     al,decanm               ; the flag needing adjustment
        jmp     atrsflg                 ; reset the flag and return

atrsm6: cmp     al,3                    ; 132/80 column mode change? [jrd]
        jne     atrsm7                  ; ne = no
        mov     al,modeset              ; pass set/reset request to chgdsp[dlk]
        call    chgdsp                  ; call Change Display proc in msy [dlk]

        call    scrmod                  ; get current screen mode
        cmp     modeset,1               ; want 132 cols?
        jne     atrsm6n                 ; ne = no, so use 80 columns
        push    ax
        mov     al,crt_cols             ; get current physical screen width
        dec     al                      ; we count from column 0 here
        mov     byte ptr low_rgt,al     ; screen capability
        pop     ax
        mov     linelen,131             ; say using wide screen, if possible
        jmp     short atrsm6e
atrsm6n:mov     linelen,79              ; say using 80 columns
        cmp     byte ptr low_rgt,79     ; want 80 cols, is it wider?
        jbe     atrsm6e                 ; be = no
        mov     byte ptr low_rgt,79     ; narrow down to 80 columns
atrsm6e:
        CALL    ATRES2                  ; do partial reset of emulator
        xor     ax,ax                   ; clear screen from 0,0
        mov     bh,byte ptr low_rgt+1   ; to end of text lines (typ. line 24)
        mov     bl,crt_cols             ; physical width
        dec     bl                      ; we count from 0
        call    atsclr                  ; do the clear
        push    bx                      ; save regs. [jrd]
        push    cx
        mov     cl,byte ptr low_rgt+1   ; text lines (leave status line intact)
        mov     mar_top,0
        mov     mar_bot,cl              ; reset scrolling region
        xor     ch,ch
        xor     bx,bx
atrsm6a:mov     linetype [bx],0         ; reset linetype to single chars
        inc     bx
        loop    atrsm6a
        pop     cx
        pop     bx
        xor     dx,dx                   ; new cursor position is 0,0
        mov     cursor,dx
        jmp     atscu5                  ; place it there and return

atrsm7: cmp     al,18                   ; 18?  18 & 19 = printer support [jrd]
        jne     atrsm8                  ; ne = no
        cmp     modeset,0               ; resetting?
        jne     atrsm7a                 ; ne = no, setting
        and     anspflg,not vtffp       ; no form feed after printing
        ret
atrsm7a:or      anspflg,vtffp           ; use form feed after printing
        ret

atrsm8: cmp     al,19                   ; 19? [jrd]
        jne     atrsm9                  ; ne = no
        cmp     modeset,0               ; resetting?
        jne     atrsm8a                 ; ne = no, setting
        and     anspflg,not vtextp      ; reset print region to scrolling reg.
        ret
atrsm8a:or      anspflg,vtextp          ; set print region to whole screen
        ret

atrsm9: cmp     al,38                   ; 38? Enter Tek sub-mode. VT340 seq
        jne     atrsm10                 ; ne = no
        cmp     modeset,1               ; setting mode (ESC [ ? 38 h)?
        jne     atrsm10                 ; ne = no, ignore sequence
        test    denyflg,200h            ; is auto Tek mode disabled?
        jnz     atrsm10                 ; nz = yes, just ignore command
        call    atsc                    ; save cursor and associated data
        mov     al,0                    ; enter with this received character
        JMP     TEKEMU                  ; Jump to Tektronix Emulator, al=null

atrsm10:ret
                ; Heath-19  ESC [ > Ps h or l where Ps = 1, 4, 7, or 9. [jrd]
htrsm1: cmp     al,1                    ; 25th line?
        jne     htrsm4                  ; ne = no
        mov     al,modeset              ; set/reset flag
        mov     h19l25,al
        cmp     al,0                    ; resetting? Mods from Dave Tweten
        jne     htrsmx                  ; ne = no, enabling. we are done
        mov     ah,byte ptr low_rgt+1   ; point to status (25th) line
        inc     ah                      ;  which is here
        xor     al,al                   ; from column 0
        mov     bh,ah                   ; to same line
        mov     bl,crt_cols             ; physical width
        dec     bl                      ; we count from 0
        jmp     atsclr                  ; disabling status line clears it

htrsm4: cmp     al,4                    ; block/line cursor?
        jne     htrsm5                  ; ne = no
        and     h19ctyp,4               ; save on/off bit (4)
        cmp     modeset,0               ; reset?
        je      htrsm4a                 ; e = yes
        or      h19ctyp,2               ; remember block kind here
        jmp     atsctyp
htrsm4a:or      h19ctyp,1               ; remember underline kind here
        jmp     atsctyp

htrsm5: cmp     al,5                    ; on/off cursor?
        jne     htrsm7                  ; ne = no
        cmp     modeset,0               ; on?
        je      htrsm5a                 ; e = yes
        or      h19ctyp,4               ; remember off state in this bit
        jmp     atsctyp
htrsm5a:and     h19ctyp,not 4           ; set cursor on
        jmp     atsctyp

htrsm7: cmp     al,7                    ; alternate application keypad?
        jne     htrsm9                  ; ne = no
        mov     al,deckpam              ; get keypad application mode bit
        jmp     atrsflg                 ; set or reset appl keypad mode

htrsm9: cmp     al,9                    ; auto newline mode? (add cr to lf)
        jne     htrsmx                  ; ne = no
        mov     al,anslnm               ; get the bit
        jmp     atrsflg                 ; set or reset newline mode

htrsmx: ret                             ; ignore the code

atrsflg:cmp     modeset,0               ; Want to reset
        je      atrsf1                  ; Yes - reset it.
        or      ansflgs,al              ; No, set. OR in the flag
        test    al,decanm               ; Changing terminal type? [jrd]
        jz      atrsfx                  ; z = no [jrd]
        cmp     flags.vtflg,ttheath     ; in Heath-19 mode? [jrd]
        je      atrsfx                  ; e = yes, don't flip terminal kinds.
        mov     flags.vtflg,ttvt100     ; say VT100 now. [jrd]
        jmp     short atrsfx
atrsf1: not     al                      ; Complement
        and     ansflgs,al              ; Clear the bit
        not     al                      ; recover the bit. [jrd]
        test    al,decanm               ; Changing terminal type? [jrd]
        jz      atrsfx                  ; z = no
        cmp     flags.vtflg,ttheath     ; in Heath-19 mode? [jrd]
        je      atrsfx                  ; e = yes, don't flip terminal kinds.
        mov     flags.vtflg,ttvt52      ; say VT52 now. [jrd]
atrsfx: push    ax
        mov     al,yflags
        call    telmsy                  ; tell msy file about new state
        pop     ax
        ret

atrsom: cmp     modeset,0               ; Clearing DEC origin mode?
        jne     atrsom1                 ; ne = no, setting
        and     ansflgs,not (decom)     ; clear the bit
        mov     dx,0                    ; go to the home position
        jmp     atscu5                  ; set cursor and return
atrsom1:or      ansflgs,decom           ; Set Origin mode
        mov     dx,cursor               ; Get the cursor
        mov     dl,0                    ; go to right margin
        mov     dh,mar_top              ; go to home of scrolling region
        jmp     atscu5                  ; Set the cursor and return

atrsscnm:
        cmp     modeset,0               ; Setting or resetting?
        je      atrss1                  ; Do reset.
        test    ansflgs,decscnm         ; Setting. Is it set already?
        jnz     atrss3                  ; Yes. Don't do it again.
        or      ansflgs,decscnm         ; No. Set it.
        or      vtemu.vtflgop,vsscreen  ; tell Status display
        or      vtflags,vsscreen        ; and our local flags
        mov     al,att_reverse          ; Want reverse video.
        jmp     short atrss2            ; Do it.

atrss1: test    ansflgs,decscnm         ; Resetting. Is it reset already?
        jz      atrss3                  ; Yes.  Don't do it again.
        and     ansflgs,not decscnm     ; No. Clear it.
        and     vtemu.vtflgop,not vsscreen      ; tell Status display
        and     vtflags,not vsscreen    ; and our local flags
        mov     al,att_normal           ; Want normal video.
                                        ; Fall through to atrss2...

; Note: This is also called from the stblmds initialization routine.

atrss2: push    ax
        mov     scbattr,al              ; Set screen background attribute
        mov     oldbatr,al              ; update long term memory too.
        mov     ah,al                   ; place where brkatt works
        call    brkatt                  ; separate color and specials
        rol     ah,1                    ; Reverse the reversal (sic.)
        rol     ah,1                    ; Reverse the reversal (sic.)
        rol     ah,1                    ; Reverse the reversal (sic.)
        rol     ah,1                    ; Reverse the reversal (sic.)
        call    addatt                  ; put blink/bold bits back in
        mov     mlbattr,ah              ; For mode line background
        mov     ah,curattr              ; Get current cursor attribute
        call    brkatt                  ; Break it up
        rol     ah,1                    ; Reverse its background
        rol     ah,1                    ; Reverse its background
        rol     ah,1                    ; Reverse its background
        rol     ah,1                    ; Reverse its background
        call    addatt                  ; Put it back together.
        mov     curattr,ah              ; And store it.
        pop     ax
        call    revscn                  ; Reverse everything on the screen.
atrss3: ret


atctst: mov     al,0                    ; Init test weight
        mov     di,offset atcts2        ; Routine to call
        call    atreps                  ; Repeat for all parms
        test    al,80H                  ; Want to reset?
        jz      atcts1                  ; No - return.
        call    atreset                 ; Yes - reset everything.
atcts1: ret

atcts2: mov     ah,ansargs[si]          ; Pick up an argument.
        cmp     ah,0                    ; Zero?
        jne     atcts3                  ; No - ignore others.
        or      al,80H                  ; Yes - say we want reset
atcts3: ret


; VT52 compatibility mode routines.

; Return to ANSI mode.

v52ans: or      ansflgs,decanm          ; Turn ANSI flag back on.
        mov     flags.vtflg,ttvt100     ; Say VT100 now. [jrd]
        call    chrdef                  ; Set default char sets.
        call    atsc                    ; Save cursor status.
        call    disleds                 ; Put "LEDs" back.
        jmp     atnorm                  ; Reset state to normal and return.

; Reset VT52 (does NOT cause return to VT100 mode). [jrd]

v52ris: call    atreset                 ; Reset everything.
        call    disleds                 ; Put "LEDs" back.
        ret

; Enter VT52 "graphics" mode.

v52egm: call    chrsgs                  ; Set "graphics" char set.
        jmp     atnorm                  ; Reset state to normal and return.

; Exit VT52 "graphics" mode.

v52xgm: call    chrdef                  ; Set default character set.
        jmp     atnorm                  ; Reset state to normal and return.

; VT52 cursor positioning.

v52pos: mov     ttstate,offset v52pc1   ; Next state.
        ret

v52pc1: sub     al,' '-1                ; Minus offset.
        mov     ansargs,al              ; Stash it here.
        mov     ttstate,offset v52pc2   ; Next state.
        ret

v52pc2: sub     al,' '-1                ; Minus offset.
        mov     ansargs+1,al            ; Stash here.
        call    atnorm                  ; Reset state to "normal".
        jmp     atcup                   ; Position and return.

; VT52 print controls

v52apb: mov     ansargs,5               ; Enter auto print mode
        or      ansflgs,decmode         ; simulate ESC [ ? 5 i
        jmp     ansprt                  ; process command

v52ape: mov     ansargs,4               ; Exit auto print mode
        or      ansflgs,decmode         ; simulate ESC [ ? 4 i
        jmp     ansprt                  ; process command

v52pcb: mov     ansargs,5               ; Enter printer controller on
        and     ansflgs,not decmode     ; simulate ESC [ 5 i
        jmp     ansprt                  ; process command

v52pce: mov     ansargs,4               ; Exit printer controller on
        and     ansflgs,not decmode     ; simulate ESC [ 4 i
        jmp     ansprt                  ; process command

v52ps:  mov     ansargs,0               ; print screen
        and     ansflgs,not decmode     ; simulate ESC [ 0 i
        jmp     ansprt                  ; process command

v52pl:  mov     ansargs,1               ; print line
        or      ansflgs,decmode         ; simulate ESC [ ? 1 i
        jmp     ansprt                  ; process command

                                        ; Heath-19 special functions  [jrd]

h19ans: or      ansflgs,decanm          ; Turn on ANSI flag. ESC <
        call    chrdef                  ; Set default char sets.
        jmp     atnorm                  ; Reset state to normal and return.

                                        ; do several "ESC ["  ANSI commands
                                        ; but don't change terminal types
h19ansa:jmp     atcsi                   ; parse ansi arguments.

                                        ; clear screen and go home
h19clrs:mov     dx,0                    ; go to upper left corner
        call    atscu5                  ; do it
        mov     ax,0                    ; clear screen from (0,0)
        mov     bh,byte ptr low_rgt+1   ; to lower right corner
        mov     bl,crt_cols             ; physical width
        dec     bl                      ; we count from 0
        jmp     atsclr
                                        ; cursor down (scrolls)
h19cud: mov     dx,cursor               ; get cursor position
        inc     dh                      ; say next row down
        call    atccic                  ; check position cursor (scrolls)
        mov     cursor,dx
        call    ax                      ; do scrolling
        jmp     atscu5
                                        ; cursor forward (right). ESC C
h19cuf: mov     dx,cursor               ; get cursor position
        inc     dl                      ; move cursor right
        cmp     dl,byte ptr low_rgt     ; beyond right margin
        jb      h19cuf1                 ; b = no. do it
        test    ansflgs,decawm          ; wrap mode on?
        jz      h19cuf2                 ; z = no. just ignore movement
        xor     dl,dl                   ; set to left margin
        inc     dh                      ; and down a row
        call    atccic                  ; adjust position
        call    ax                      ; call scrolling routine
h19cuf1:jmp     atscu5                  ; do positioning and return
h19cuf2:ret                             ; just return

                                        ; set line wrap on
h19wrap:or      ansflgs,decawm          ; turn on the flag
        jmp     atnorm

                                        ; turn off line wrap
h19nowrp:and    ansflgs,not decawm      ; turn off the flag
        jmp     atnorm

h19erb: mov     bx,cursor               ; erase home to cursor, incl.
        xor     ax,ax                   ; home
        jmp     atsclr                  ; clear the area, cursor stays put???

h19erl: mov     bx,cursor               ; erase whole line
        mov     ax,bx                   ; get row
        xor     al,al                   ; column 0
        mov     bl,crt_cols             ; physical width
        dec     bl                      ; we count from 0
        jmp     atsclr                  ; erase whole line, cursor stays put

h19ero: mov     bx,cursor               ; erase start of line to cursor
        mov     ax,bx
        xor     al,al                   ; start in column 0
        jmp     atsclr                  ; clear that part of line

h19herv:cmp     video_state,0           ; is video normal? ESC p
        jne     h19hrv1                 ; ne = no, reversed already, ignore
        mov     ah,curattr              ; current cursor attributes
        call    brkatt                  ; breakup attributes byte
        rol     ah,1                    ; reverse foreground to background
        rol     ah,1
        rol     ah,1
        rol     ah,1
        call    addatt                  ; put things together again
        mov     curattr,ah              ; and store it
        mov     video_state,1           ; say we are reversed
h19hrv1:ret

h19hxrv:cmp     video_state,0           ; is video normal? ESC q
        je      h19hxr1                 ; e = yes, so just ignore
        mov     ah,curattr              ; current cursor attributes
        call    brkatt                  ; breakup attributes byte
        rol     ah,1                    ; reverse foreground to background
        rol     ah,1
        rol     ah,1
        rol     ah,1
        call    addatt                  ; put things together again
        mov     curattr,ah              ; and store it
        mov     video_state,0           ; say we are normal
h19hxr1:ret

h19mbr: mov     ttstate,offset hmbr     ; Modify baud rate ESC r char
        ret                             ; setup to parse next char
hmbr:   jmp     atnorm                  ; discard char (in al)

htsc:   cmp     flags.vtflg,ttheath     ; Heath-19? ESC [ s
        jne     htscx                   ; ne = no, ignore
        call    atsc                    ; store cursor position and attr.
htscx:  jmp     atnorm                  ; reset state & return

htrc:   cmp     flags.vtflg,ttheath     ; Heath-19? ESC [ u
        jne     htrcx                   ; ne = no, ignore
        call    atrc                    ; restore cursor pos and attr.
htrcx:  jmp     atnorm                  ; reset state & return

                                        ; Heath-19 set mode "ESC x "
h19smod:mov     ttstate,offset hsmod    ; setup to parse rest of seq
        ret

hsmod:  mov     modeset,1               ; say set mode
        mov     ttstate,offset atnrm
        sub     al,'0'                  ; remove ascii bias
        jmp     htrsm1                  ; perform mode set

h19cmod:mov     ttstate,offset hcmod    ; setup to parse rest of seq
        ret

hcmod:  mov     modeset,0               ; say reset mode
        mov     ttstate,offset atnrm
        sub     al,'0'                  ; remove ascii bias
        jmp     htrsm1                  ; perform mode reset

htrest: cmp     flags.vtflg,ttheath     ; Heath-19? ESC [ z
        jne     htrestx                 ; ne = no, ignore
        call    atreset                 ; do a hard reset
htrestx:jmp     atnorm                  ; reset state and return

hrcup:  mov     al,escape               ; send "ESC Y row col" cursor report
        call    prtbout                 ; send with no local echo
        mov     al,'Y'
        call    prtbout
        mov     al,byte ptr cursor+1    ; get row
        add     al,' '                  ; add ascii bias
        call    prtbout                 ; send it
        mov     al,byte ptr cursor      ; get column
        add     al,' '                  ; add ascii bias
        call    prtbout                 ; and send it too
        jmp     atnorm                  ; return to terminal mode

                                        ; Heath-19 and VT102 additions [jrd]

inslin: cmp     ansargs,0               ; insert line(s). Any args? [jrd]
        jne     insli1                  ; ne = yes. If no arg use 1
        mov     ansargs,1               ; insert one line.
insli1: mov     dx,cursor               ; current position
        cmp     dh,mar_bot              ; below bottom margin?
        jae     insli3                  ; ae = at or below bottom margin
        push    word ptr mar_top
        mov     mar_top,dh              ; call present position the top
        push    cx                      ; save a reg
        mov     cl,ansargs              ; get repeat count
        xor     ch,ch                   ; clear high byte
insli2: call    atscrd                  ; scroll down
        loop    insli2                  ; repeat until done (cx times)
        pop     cx                      ; restore reg
        pop     word ptr mar_top        ; restore margins
        xor     dl,dl                   ; go to left margin
        jmp     atscu5                  ; reposition cursor and return
insli3: ret

dellin: cmp     ansargs,0               ; delete line(s). Any args? [jrd]
        jne     delli1                  ; no arg; use 1
        mov     ansargs,1               ; insert one line.
delli1: mov     dx,cursor               ; where we are presently
        cmp     dh,mar_bot              ; at or below bottom margin?
        jae     delli3                  ; ae = yes.
        push    word ptr mar_top        ; save current scrolling margins
        mov     mar_top,dh              ; temp top margin is here
        push    cx                      ; save a reg
        mov     cl,ansargs              ; get repeat count
        xor     ch,ch                   ; clear high byte
delli2: call    atscru                  ; scroll up
        loop    delli2                  ; repeat until done (cx times)
        pop     cx                      ; restore reg
        pop     word ptr mar_top        ; restore scrolling margins.
        jmp     atscu5                  ; restore cursor and return
delli3: ret

                                        ; Delete character(s)
atdelc: cmp     ansargs,0               ; zero becomes one operation
        jne     atdelc1
        mov     ansargs,1               ; delete one char. Heath ESC N
atdelc1:mov     cl,byte ptr low_rgt     ; number of columns on screen.
        mov     dx,cursor               ; get present cursor position
        push    bx
        mov     bl,dh                   ; get row
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        je      atdelc5                 ; e = yes
        shl     dl,1                    ; double the column number
        mov     bl,ansargs
        shl     bl,1                    ; double # chars to delete
        mov     ansargs,bl
atdelc5:pop     bx
        sub     cl,dl                   ; end of screen - current column #
        xor     ch,ch                   ; cx = number of chars to move
        cmp     cx,0                    ; zero means just this char
        ja      atdelc4
        inc     cx                      ; say one, this one
atdelc4:push    es
        push    cx                      ; save word count for Topview
        cld
        call    scrloc                  ; compute current cursor location
        mov     di,ax                   ; temporary storage places
        mov     si,ax
        mov     al,ansargs              ; get delete count
        xor     ah,ah                   ; clear high byte of delete count
        cmp     al,cl                   ; clear more than rest of line?
        jb      atdelc2                 ; b = no. some chars left at end
        mov     al,cl                   ; say delete all to right, inclusive
atdelc2:cmp     al,0                    ; zero?
        jne     atdelc3
        inc     al                      ; none or 0 impiles one.
atdelc3:shl     ax,1                    ; double: char and its attribute byte
        push    di                      ; destination offset
        add     ax,si                   ; src offset = dest + # deleted words
        push    ax                      ; save it
        call    scroff
        call    scrseg                  ; pick up screen segment
        mov     si,di                   ; align memory addresses
        pop     ax                      ; recover source offset
        add     si,ax                   ; add to starting memory address
        pop     ax                      ; recover destination offset
        add     di,ax                   ; add to destination memory address
        push    ds                      ; save ds around the move
        push    es                      ; move es into ds to
        pop     ds                      ; make ds point to screen memory too
        rep     movsw
        pop     ds                      ; recover normal ds
        pop     cx                      ; count for Topview
        call    scrsync                 ; synch Topview
        pop     es
        call    scron
        mov     ax,cursor               ; get current row
        mov     bx,cursor
        mov     bl,byte ptr low_rgt     ; last col on screen
        mov     al,bl
        sub     al,ansargs              ; minus number of locations cleared
        inc     al
        call    atsclr                  ; clear end of line
atdelcx:mov     dx,cursor
        jmp     atscu5                  ; reposition cursor

inschr: mov     dx,cursor               ; open one char space in current line
        push    bx
        mov     bl,dh                   ; get row
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        je      insch2                  ; e = yes
        shl     dl,1                    ; double the column number
insch2: pop     bx
        mov     ch,0
        mov     cl,byte ptr low_rgt     ; number of columns on screen
        push    dx
        mov     dh,0
        sub     cx,dx                   ; compute distance to end
        pop     dx
        or      cx,cx
        jle     insch1                  ; le = nothing to move... [dlk]
        mov     dl,byte ptr low_rgt
        dec     dl                      ; last col to move
        push    ax                      ; save regs
        push    es                      ; ditto
        push    cx                      ; save count for Topview
        call    scrloc                  ; compute position of end of line-1
        push    ax                      ; save offset
        std                             ; remember to move backward
        call    scroff                  ; turn off color screen
        call    scrseg                  ; get memory address in es:di
        pop     ax                      ; recover offset
        add     di,ax                   ; source memory address
        mov     si,di                   ; align addresses. destination
        add     di,2                    ;   is one char over
        push    di
        push    ds                      ; save ds around move
        push    es                      ; put es into ds
        pop     ds                      ;   ds points to screen memory too
        rep     movsw
        pop     ds                      ; recover normal ds
        cld                             ; reset direction to be forward
        pop     di
        pop     cx                      ; count for Topview
        call    scrsync                 ; synch Topview
        pop     es                      ; restore regs
        pop     ax                      ; ditto
        call    scron                   ; turn on screen again
        cld                             ; reset direction
insch1: mov     dx,cursor
        jmp     atscu5                  ; position cursor

noins:  mov     insmod,0                ; turn off insert mode
        jmp     atnorm                  ; and return

entins: mov     insmod,0ffh             ; enter insert mode...
        jmp     atnorm                  ; and return

ansich  proc    near                    ; ANSI insert characters ESC [   @
        cmp     ansargs,0               ; any arguments?
        jne     ansic1                  ; ne = no, ignore
        mov     ansargs,1               ; use one
ansic1: push    dx                      ; save cursor
        mov     insmod,1                ; enter insert mode
        push    cx
        mov     cl,ansargs              ; get count of inserts
        mov     ch,0
        push    ax                      ; save char
ansic2: push    cx                      ; save counter
        mov     al,' '                  ; character to write
        call    atnrm                   ; do display
        pop     cx                      ; recover counter
        loop    ansic2                  ; do cx times
        pop     ax                      ; restore char
        pop     cx
        mov     insmod,0                ; turn off insert mode
        pop     dx                      ; get original cursor
        jmp     atscu5                  ; set cursor
ansich  endp

; routines supporting scrolling and double width/height chars [jrd]

atscru  proc    near                    ; scroll screen up one line
        push    ax                      ; assumes dx holds cursor position
        push    bx                      ; returns with dx = old row, new col
        push    cx
        xor     ch,ch
        mov     cl,mar_bot              ; bottom line to move
        xor     bh,bh
        mov     bl,mar_top              ; top line to move
        sub     cx,bx                   ; cx = number of lines to move
        jcxz    atscru2                 ; cx = 0. nothing to do
atscru1:mov     al,linetype[bx+1]
        mov     linetype[bx],al         ; move line types up one line
        inc     bx
        loop    atscru1
        mov     linetype[bx],0          ; clear new line's type
                                        ; reindex column of cursor
        cmp     linetype[bx-1],0        ; was old bottom line double wide?
        je      atscru2                 ; e = no
        shr     dl,1                    ; reindex to single wide columns
atscru2:pop     cx
        pop     bx
        pop     ax
        test    anspflg,vtcntp          ; controller print active?
        jz      atscru3                 ; z = no, ok to change screen
        ret                             ;  else keep screen intact
atscru3:jmp     vtscru                  ; call & ret the msy scroll routine
atscru  endp

atscrd  proc    near                    ; scroll screen down one line
        push    ax                      ; assumes dx holds cursor position
        push    bx                      ; returns with dx = old row, new col
        push    cx
        xor     ch,ch
        mov     cl,mar_top              ; top line to move
        xor     bh,bh
        mov     bl,mar_bot              ; bottom line to move
        sub     cx,bx
        neg     cx                      ; cx = number of lines to move
        jcxz    atscrd2                 ; cx = 0. nothing to do
atscrd1:mov     al,linetype[bx-1]
        mov     linetype[bx],al         ; move line types down one line
        dec     bx
        loop    atscrd1
        mov     linetype[bx],0          ; clear new line's type
                                        ; reindex column of cursor
        cmp     linetype[bx+1],0        ; was old top line double wide?
        je      atscrd2                 ; e = no
        shr     dl,1                    ; reindex to single wide columns
atscrd2:pop     cx
        pop     bx
        pop     ax
        test    anspflg,vtcntp          ; controller print active?
        jz      atscrd3                 ; z = no, ok to change screen
        ret                             ;  else keep screen intact
atscrd3:jmp     vtscrd                  ; call & ret the msy scroll routine
atscrd  endp

linesgl proc    near                    ; convert line to single width char
        push    ax
        push    bx
        push    cx
        push    dx
        mov     bx,cursor
        mov     bl,bh
        xor     bh,bh                   ; bx now holds row
        cmp     linetype [bx],0         ; is line already single width?
        je      linsglx                 ; e = yes
        mov     linetype [bx],0         ; say will be single now.
        call    scroff                  ; turn off video
        mov     dx,cursor
        mov     dl,0                    ; start in column 0
        mov     cx,40                   ; number of columns to do
linsgl1:push    cx                      ; save loop counter
        shl     dl,1                    ; double column number
        mov     ah,2                    ; set cursor
        xor     bh,bh                   ; page 0
        int     screen
        mov     ah,8                    ; read char and attribute
        int     screen
        push    ax                      ; save char and attribute
        shr     dl,1                    ; restore column
        mov     ah,2                    ; set cursor
        int     screen
        pop     ax                      ; recover char and attribute
        mov     bl,ah                   ; set attribute
        mov     cx,1                    ; one char
        mov     ah,9                    ; write char and attribute
        int     screen
        inc     dl                      ; next column
        pop     cx
        loop    linsgl1
        mov     cx,40
        mov     dl,40
        mov     ah,2                    ; set cursor
        int     screen
        mov     bl,scbattr              ; screen background
        mov     al,' '
        mov     ah,9                    ; write char
        int     screen                  ; write 40 spaces
        call    scron                   ; turn on the video
linsglx:pop     dx
        pop     cx
        pop     bx
        pop     ax
        jmp     atscur                  ; update cursor and return
linesgl endp

linedbl proc    near                    ; convert line to double width char
        push    ax                      ; must reset physical cursor
        push    bx                      ; to same char as before expansion
        push    cx                      ; but does not modify variable cursor
        push    dx
        mov     bx,cursor
        mov     bl,bh
        xor     bh,bh                   ; bx now holds row
        cmp     linetype [bx],0         ; is line single width?
        jne     lindblx                 ; ne = no. nothing to do
        mov     linetype [bx],1         ; say will be double width now.
        mov     dx,cursor
        mov     dl,39                   ; start with col 39
        mov     cx,40
        call    scroff                  ; turn off the video
lindbl1:push    cx                      ; save loop counter
        mov     ah,2                    ; set cursor
        mov     bh,0                    ; page 0
        int     screen
        mov     ah,8                    ; read char and attribute
        int     screen
        push    ax                      ; save char and attribute
        shl     dl,1                    ; double the column number
        mov     ah,2                    ; set cursor
        int     screen
        pop     ax                      ; recover char and attribute
        mov     bl,ah                   ; set attribute
        mov     cx,1                    ; one char
        mov     ah,9                    ; write char and attribute
        int     screen
        inc     dl                      ; move to second column of double.
        mov     ah,2                    ; set cursor
        int     screen
        mov     al,' '                  ; space as filler
        mov     ah,9                    ; write that char
        int     screen
        dec     dl
        shr     dl,1
        dec     dl
        pop     cx
        loop    lindbl1
        call    scron                   ; turn on the video
lindblx:pop     dx
        pop     cx
        pop     bx
        pop     ax
        jmp     atscur                  ; update the cursor and return
linedbl endp

anstty  endp

ansprt  proc near                       ; printer support routines. [jrd]
        cmp     ansargs,0               ; 0 (print all/part of screen)?
        jne     ansprt1                 ; ne = no
        call    pntchk                  ; check printer
        jc      ansprtx                 ; c = printer not ready
        call    pntext                  ; do whole screen or scrolling extent
        jmp     atscu5                  ; reposition cursor and return

ansprt1:cmp     ansargs,1               ; 1 (print current line)?
        jne     ansprt4                 ; ne = no
        call    pntchk                  ; check for printer ready
        jc      ansprtx                 ; c = printer not ready
        call    pntlin                  ; print current line
anspr1a:jmp     atscu5                  ; reposition cursor and return

ansprt4:cmp     ansargs,4               ; auto print disable?
        jne     ansprt5                 ; ne = no
        test    ansflgs,decmode         ; was it ESC [ ? 4 i
        jz      anspr4a                 ; z = no, so it was ESC [ 4 i
        test    anspflg,vtautop         ; check state of print flag
        jz      anspr4a                 ; z = off already
        call    trnprs                  ; toggle mode line PRN indicator
        and     anspflg,not vtautop     ; auto-print disable
anspr4a:jmp     ansprtx

ansprt5:cmp     ansargs,5               ; auto print enable?
        jne     ansprtx                 ; ne = no
        call    pntchk                  ; check printer, ignore carry ret
        jc      ansprtx                 ; c = printer not ready
        test    ansflgs,decmode         ; was it ESC [ ? 5 i
        jz      anspr5a                 ; z = no
        test    anspflg,vtautop         ; is print already enabled?
        jnz     ansprtx                 ; nz = yes, leave trnprs intact
        call    trnprs                  ; toggle on mode line PRN indicator
        or      anspflg,vtautop         ; auto-print enabled
        jmp     short ansprtx
anspr5a:or      anspflg,vtcntp          ; controller print enabled
ansprtx:jmp     atnorm
ansprt  endp

; State machine active while Media Copy On (Print Controller ON). Copies all
; chars to the printer until (and excluding) Media Copy Off (ESC [ 4 i) has
; been received or the emulator reset. New char is in al. 6 March 1987 [jrd]

ansmc   proc    near
        mov     ah,al                   ; copy active character
        and     ah,7fh                  ; strip high bit
        cmp     ah,byte ptr mcoff       ; start of MC Off sequence?
        jne     ansmc1                  ; ne = no
        call    ansmc4                  ; playback previously matched chars
        mov     mccnt,1                 ; count matched chars (one now)
        mov     mcoffs,al               ; save full character, with high bit
        jmp     short ansmcx            ;  and exit

ansmc1: push    bx                      ; check for char in MC Off sequence
        mov     bx,mccnt                ; number of chars matched in MC Off
        mov     mcoffs[bx],al           ; save this char, with high bit
        cmp     ah,byte ptr mcoff[bx]   ; match expected char in sequence?
        pop     bx
        jne     ansmc3                  ; ne = no, play back partial match
        inc     mccnt                   ; count new match
        cmp     mccnt,mcofflen          ; matched all char in sequence?
        jne     ansmcx                  ; ne = not yet, wait for more
        and     anspflg,not vtcntp      ; yes, disable print controller
        mov     mccnt,0                 ; clear counter
        jmp     short ansmcx            ;  all done

ansmc3: call    ansmc4                  ; playback previously matched chars
        call    pntchr                  ; print current char, ignore errors
        mov     mccnt,0                 ; reset to no match and exit
ansmcx: ret                             ; common exit

                                        ; local worker procedure
ansmc4: push    ax                      ; save break char (in al)
        push    cx                      ; playback partial sequence to printer
        mov     cx,mccnt                ; number of chars matched before break
        jcxz    ansmc4b                 ; z = none
        push    si
        mov     si,offset mcoffs        ; string to be played back
        cld
ansmc4a:lodsb                           ; get a char into al
        call    pntchr                  ; print it, ignore errors
        loop    ansmc4a                 ; do all that came in previously
        pop     si
ansmc4b:pop     cx
        pop     ax                      ; recover break char
        ret
ansmc   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 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
        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, in msy
        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

; Print on PRN the char in register al. On success return with C bit clear.
; On failure call procedure pntchk and return its C bit (typically C set).
pntchr  proc    near
        push    dx
        push    ax
        mov     ah,lstout               ; uses file handle 4
        mov     dl,al
        int     dos
        pop     ax
        pop     dx
        jnc     pntchr2                 ; nc = success
        call    pntchk                  ; c = error (printer not ready)
pntchr2:ret
pntchr  endp

pntlin  proc    near                    ; print whole line given by dx
        push    ax
        push    bx
        push    cx
        push    dx
        xor     dl,dl                   ; start in column 0
        xor     ch,ch
        mov     cl,byte ptr low_rgt     ; number of columns
        mov     dl,cl                   ; Bios column counter
        inc     cl                      ; actual line length, count it down
pntlin1:mov     ah,2                    ; set cursor
        xor     bh,bh                   ; page 0
        int     screen
        mov     ah,8                    ; read char (al) and attribute (ah)
        int     screen
        cmp     al,' '                  ; is this a space?
        jne     pntlin2                 ; no, we have the end of the line
        dec     dl                      ; else move left one column
        loop    pntlin1                 ; and keep looking for non-space

pntlin2:jcxz    pntlin4                 ; z = empty line
        xor     dl,dl                   ; start in column 0, do cl chars
pntlin3:mov     ah,2                    ; set cursor
        xor     bh,bh                   ; page 0
        int     screen
        mov     ah,8                    ; read char and attribute
        int     screen
        inc     dl                      ; inc to next column
        call    pntchr                  ; print the char (in al)
        jc      pntlin5                 ; c = printer error
        loop    pntlin3                 ; do cx columns
pntlin4:mov     al,cr                   ; add trailing cr/lf for printer
        call    pntchr
        jc      pntlin5
        mov     al,lf
        call    pntchr
pntlin5:pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret                             ; C bit controlled by pntchr
pntlin  endp

pntext  proc    near                    ; print an extent of lines, depending
        push    ax                      ; on flag bit vtextp.
        push    bx
        push    dx
        xor     dx,dx                   ; assume starting at top left
        mov     bx,low_rgt              ;  and extending to lower right
        test    anspflg,vtextp          ; full screen wanted?
        jnz     pntext1                 ; nz = yes, else scrolling region
        mov     dh,mar_top              ; top of scrolling region
        mov     bh,mar_bot              ; bottom of scrolling region
pntext1:call    pntlin                  ; print a line
        jc      pntext2                 ; c = printer error
        inc     dh
        cmp     dh,bh                   ; done all requested lines?
        jbe     pntext1                 ; be = not yet, do another
        test    anspflg,vtffp           ; form feed needed at end?
        jz      pntext2                 ; z = no.
        mov     al,ff
        call    pntchr                  ; print the form feed char
pntext2:pop     dx
        pop     bx
        pop     ax
        ret
pntext  endp

code    ends

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

        end

