DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

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

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T m

⟦5df8c1112⟧ TextFile

    Length: 158846 (0x26c7e)
    Types: TextFile
    Names: »msz55x.asm«

Derivation

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

TextFile

      NAME      msz55x
; File MSZ55X.ASM
; System dependent file for Sanyo 55x series.
; Done by Robert W. Babcock and Joe H. White.
; For version which replaces the BIOS keycode translation table,
;  use -dMODIFIED flag to MASM.
    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 20 April 1988, add color trans. table for monochrome systems [rwb]
; 15 Sept 1987 version which runs with or without optional video board [rwb]
; Use bios calls for video output.  Also change test for monochrome [jhw]
; monitor from crt_mode = 7 to 2. Set swidth and slen back to 80 and 25 [jhw]
; Make vtsound public so it can be called from msx55x. [rwb]
;
; 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    vtsound                ; [rwb]
    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 usevb:byte
    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)
trtbl    db    0h,1h,2h,3h,1h,2h,3h,7h      ; color translation table
    db    7h,9h,0ah,0bh,9h,0ah,0bh,0fh
    db    10h,14h,15h,16h,14h,15h,16h,18h
    db    18h,19h,1ah,1bh,1ch,1dh,1eh,1fh
    db    20h,24h,25h,26h,24h,25h,26h,28h
    db    28h,29h,2ah,2bh,2ch,2dh,2eh,2fh
    db    30h,34h,35h,36h,34h,35h,36h,38h
    db    38h,39h,3ah,3bh,3ch,3dh,3eh,3fh
    db    41h,41h,42h,43h,41h,42h,43h,47h
    db    47h,49h,4ah,4bh,49h,4ah,4bh,4fh
    db    51h,51h,52h,53h,51h,52h,53h,57h
    db    57h,59h,5ah,5bh,59h,5ah,5bh,5fh
    db    61h,61h,62h,63h,61h,62h,63h,67h
    db    67h,69h,6ah,6bh,69h,6ah,6bh,6fh
    db    70h,74h,75h,76h,74h,75h,76h,78h
    db    78h,79h,7ah,7bh,7ch,7dh,7eh,7fh


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,8            ; 5000 Hertz [rwb]
    mov    bx,1            ; For 3 milliseconds. [rwb]
    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,45            ; 880 Hertz [rwb]
    mov    bx,22            ; For 70 ms. [rwb]
    call    vtsound            ; Do it.
    pop    bx
    pop    di
    ret
vtbell    endp

; Routine to make noise of arbitrary frequency for arbitrary duration.
; Derived from a routine in December 1984 Soft Sector, page 28. [rwb]
; Frequency and duration parameters are different than in the IBM ver. [rwb]
; Sound is generated by toggling the break bit in the keyboard UART [rwb]
;
; Call:        di/    frequency is 40KHz / di value [rwb]
;        bx/    duration is 3.2 msec * bx value [rwb]
;         These approximate values break down badly for di < 10 [rwb]
;         or if an accelerator board is installed. [rwb]

vtsound proc    near
    push    ax            ; Save regs.
    push    bx
    push    cx
    mov    ax,35h            ; UART cmd with break bit off
vtsou1: mov    cx,di
    xor    al,8            ; toggle break bit
    out    3ah,al            ; send it to UART
vtsou2: dec    ah
    jnz    vtsou3
    dec    bx            ; count down duration
    jz    vtsou4
vtsou3: loop    vtsou2            ; frequency count down
    jmp    vtsou1
vtsou4: mov    al,35h
    out    3ah,al            ; turn off break bit on exit
    pop    cx            ; Restore regs.
    pop    bx
    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,2        ; monochrome display adapter mode?
    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.
; When a monochrome monitor is used on a Sanyo with a video board, some [rwb]
; "colors" are completely invisible.  Following code guarantees all text
; is visible.
    test    usevb,1            ; video board in use?
    jz    addat2            ; z = no
    cmp    crt_mode,2        ; monochrome?
    jne    addat2            ; ne = no
    push    bx
    mov    bx,offset trtbl        ; point at translate table
    xchg    al,ah            ; get original attribute in al
    and    al,7fH            ; translate table only half length
    xlat                ; translate attribute
    xchg    al,ah            ; return in ah
    pop    bx
addat2:

    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
;                            [begin jhw]
; Modified to use bios calls for Sanyo without video board
;

revscn: test    usevb,1            ; video board in use?
    jz    revscnv            ; z = no
    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
revscnv:mov    ax,0300h        ; save cursor position on stack
    int    screen
    push    dx
    mov    dx,0
revs1:    mov    ax,0200h
    int    screen
    mov    ax,0800h        ; read character at cursor
    int    screen
    mov    bh,al            ; char/attrib in al/ah
    call    brkatt            ; redo the attribute
    rol    ah,1
    rol    ah,1
    rol    ah,1
    rol    ah,1
    call    addatt            ; reassemble attributes
    mov    bl,ah            ; set up char/attrib in al/bl
    mov    al,bh            ;
    mov    cx,1
    mov    ah,09h            ; write char/attrib to screen
    int    screen
    cmp    dl,79            ; end of line?
    jae    revs7            ; yes, go to next line
    inc    dl            ; else, go to next char
    jmp    revs1
revs7:    mov    dl,0
    cmp    dh,24            ; bottom of screen? (done?)
    jae    revs8            ; yes, finish up
    inc    dh            ; no, go to next line
    jmp    revs1
revs8:    pop    dx            ; restore cursor to where it was
    mov    ax,0200h
    int    screen            ; end jhw        [end jhw]
    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
;;;##
    test    yflags,modoff        ; is mode line disabled?
    jz    ated0d            ; z = yes, don't extend erase
    inc    bh            ; yes, extend erase to 25th line
ated0d:
;;;##
    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
;;;##
    test    yflags,modoff        ; is mode line disabled?
    jz    ated3b            ; z = yes, don't extend erase
    inc    bh            ; yes, extend erase to 25th line
ated3b:
;;;##


    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,2        ; 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
    test    usevb,1            ; video board in use?
    jz    atdelv1            ; z = no
    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
    jmp short atdelv2
;            modify to use Sanyo bios sideways shift [begin jhw]
;                (can't write to video RAM)
atdelv1:mov    al,ansargs        ; no. of positions to shift
    mov    ah,73h            ; Sanyo bios sideways scroll
    mov    cx,dx            ; cursor position -- now
    mov    dl,79            ; end of line coord. in dx
    mov    bh,scbattr        ; attribute for cleared position
    int    screen            ;            [end jhw]
atdelv2:
    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
    test    usevb,1            ; video board in use?
    jnz    insv1            ; nz = yes
    push    ax            ;
    mov    al,1            ; shift one space (for use later)
insv1:
    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
    test    usevb,1            ; video board in use?
    jnz    insv2            ; nz= yes
    mov    al,2            ; and the number of cols to shift
insv2:
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]
    test    usevb,1            ; video board in use?
    jz    insv3            ; z = no
    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
    jmp short insv4
;                use bios calls since Sanyo can't write
;                    to video RAM    [begin jhw]
insv3:    mov    ah,72h            ; Sanyo sideways bios scroll
    mov    cx,dx            ; set left end of scroll region
    mov    dl,79            ; set right end
    mov    bh,scbattr        ; attributes of cleared region
    int    screen            ; [end jhw]
insv4:
insch1: mov    dx,cursor
    test    usevb,1            ; video board in use?
    jnz    insv5            ; nz = yes
    pop    ax            ; [jhw]
insv5:
    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