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

⟦da05f50c0⟧ TextFile

    Length: 188909 (0x2e1ed)
    Types: TextFile
    Names: »mszibm.asm«

Derivation

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

TextFile

        NAME    mszibm
; File MSZIBM.ASM
        page 60,132
; Terminal emulator module for IBM PC's and compatibles. Emulates Heath-19,
; VT52, and VT102. Original version done by James Harvey, Indiana Purdue
; Univ, for MS Kermit 2.27. Taken from there by Joe Doupnik, Utah State Univ
; for MS Kermit 2.29 et seq.
; Edit history
; Last edit 29 Nov 1988
; 29 Nov 1988 Revise detection of Transparent Print on/off to permit multiple
;  arguments in the escape sequences ESC [ 5/4 i. Arguments are executed in
;  their order of appearance.
; 26 Nov 1988 Correct setup of cursor type (block/underline) in atsctyp.
; 21 Nov 1988 Version 2.32
; 12 Nov 1988 Add ESC [ ? 34 h and l as set (h) and reset (l) which invoke
;  procedures vtsmac and vtrmac, resp, in file msy.
; 28 Oct 1988 Let screen scroll up (into rollback buffer) when full screen
;  erase ESC [ 2 J  is received. Suggested by David Lassner.
; 9 Oct 1988 Add byte vtemu.vtchset to hold choices for VT102 emulator
;  character sets (US, UK, or Alternate-ROM). Tnx to Baruch Cochavy [bk].
;  Thus, bit vsshift3 in vtemu.vtflgop is now unused. Alt-ROM is defined as
;  changing characters 60h-7ah (accent grave and lower case) to be 80h-9ah.
; 5 Oct 1988 Add controls to write from right to left, using bit vswdir in
;  the setup bytes vtemu.vtflgst and vtemu.vtflgop. The concept was invented
;  by Baruch Cochavy, IIT, Haifa, Israel; the current code is by [jrd].
;  If vswdir is non-zero writing is done starting on the visual right side.
;  Procedures direction and vtsclr accomdate most directional details. The
;  implementation here retains DX and CURSOR as logical values while the
;  physical screen coordinates are conditioned via proc direction and
;  several sections of special code. Screen printing is done full width if
;  writing right to left. Outside mszibm the logical cursor = physical. [jrd]
; 25 Sept 1988 Absorb ESC * char, ESC + char, and ESC <left curly brace>,
;  thanks to Terry Kennedy who says the VT102 ROM does this.
; 24 Sept 1988 Move printer output routines to file msyibm to permit buffering
;  and flow control.
; 1 July 1988 Version 2.31
; 10 June 1988 Add oldscrn to sense changes in physical screen sizes.
; 29 May 1988 Prevent ESC [ Pn @ (ANSI insert spaces) from wrapping. Tnx to
;  Brian Holley.
; 27 April 1988 Stop ESC [ 4 m (underscore) from toggling.
; 20 March 1988 Add ESC [ 1 2 h/l to control local echoing. Use bit 80h in
;  ansflgs to preserve state of this bit. [jrd]
; 9 Feb 1988 Mode line again. Make flags.modflg=0 for off, 1 for on and owned
;  by Kermit, and 2 for on and owned by remote host (toggling suppressed).
; 25 Jan 1988 Add global byte SCROLL to tell msy routines how many lines
;  to scroll. This speeds insert/delete line operations. [jrd]
; 6 Jan 1988 Remove erasing into mode line on to-end-of-screen calls. [jrd]
; 1 Jan 1988 version 2.30
;    [Joe R. Doupnik, Utah State Univ]
;

        public  anstty, ansini, ansrei, ansdsl, anstat, anskbi ; Entry points
        public  ans52t, vclick, vsinit
        public  mar_top, mar_bot, anspflg, scroll       ; 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     60                      ; 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
;dececho equ     80H                     ; ANSI local echo on (1)

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

; VT100 SETUP mode flags
;vswdir          equ     80H             ; Writing direction (0=left to right)
;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
;vtchset db     1       ; value of default character set (1=US-ascii)
;att_ptr dw     0       ; pointer to normal & reverse video attributes
;emulst ends
;;;;;;;;;;;;;;;;  end references ;;;;;;;;;;;;;;;;;;;;

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

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


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

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

; Heath-19 mode escape follower table

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

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

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

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

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','*','+',7bh         ; 7bh is left curly brace
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,atpriv,atnorm


; 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',0               ; VT102
dastr   db      escape,'[?6c',0         ; shortened to help some mainframes
        db      5 dup (0)               ; patch space

; Identify response used while in VT52 compatibility mode
v52str  db      escape,'/Z',0
        db      5 dup (0)               ; patch space

; Identify response when a Heath-19 terminal
h19str  db      escape,'/K',0
        db      5 dup (0)               ; patch space

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

mcoffs  db      24 dup (0)              ; received chars in sequence
mccnt   dw      0                       ; 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
lbaudtab        equ     $-baudtab

belcol  db      ?                       ; column at which to ring margin bell
yflags  db      ?                       ; Flags from MSYxxx term routine
oldbatr db      ?                       ; old scbattr
oldterm db      ?                       ; terminal type from previous entry
escdec  db      0                       ; DEC private sequence (ESC [ ?) seen
decmode equ     80H                     ; "?" seen in lead-in
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)
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"
alcset  equ     3                       ; Set 4 = "Alt. Character Set" [bk]
svattr_index    equ 0                   ; To set saved cursor attribute only

curattr db      07h                     ; Cursor attribute
cursor  dw      0                       ; Cursor position
video_state db  0                       ; video state (0=normal,1=reversed)
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)
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
linetype db     slen dup (0)

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)
oldscrn dw      0                       ; old screen. hi=rows-1, low=cols-1
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
scroll  db      1                       ; lines to scroll

led_col equ     65                      ; column position for "LEDs" display
led_off equ     '.'                     ; "Off" LED
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
nansarg db      0                       ; Index for ANSI argument list
ansargs db      16 dup (0)              ; Room for 16 ANSI arguments
lansarg equ     $-ansargs               ; Max number of ANSI arguments
                                        ; printer support data
anspflg db      0                       ; printer flag bits and definitions
vtautop equ     1                       ; autoprint enabled (1)
vtcntp  equ     2                       ; controller print enabled (1)
vtextp  equ     4                       ; printer extent set (1)
vtffp   equ     8                       ; form feed wanted at end of print (1)

datas   ends


code    segment public 'code'
        extrn   prtbout:near, prtnout:near, csrtype:near, trnmod:near
        extrn   scrmod:near, scrseg:near, scrsync:near, scroff:near
        extrn   scron:near, atsclr:near, vtscru:near, vtscrd:near
        extrn   modwrt:near, telmsy:near, scrloc:near, pcwait:near
        extrn   chgdsp:near, trnprs:near, cptchr:near, tekesc:near
        extrn   pntchr:near, pntchk:near, pntflsh:near
                                ; extrn procedures are all in module msyibm
        extrn   tekini:near, tekemu:near, tekend:near, vtrmac:near,vtsmac: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
        mov     deftabs,0               ; Column 1 has no tab stop
        mov     ansflgs,0
        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
        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
        call    cpytabs                 ; copy default to active
        mov     vtemu.att_ptr,offset att_normal  ; ptr to video attributes
        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
        mov     vtflags,ah
        mov     vttabs,offset deftabs   ; tab stop pointer
        mov     vtemu.vttbst,offset tabs; store here for STATUS
        mov     al,flags.vtflg          ; get current terminal type
        mov     oldterm,al              ; remember it here for soft restarts
        mov     insmod,0                ; turn off insert mode
        mov     h19l25,0                ; clear Heath 25th line enable
        mov     h19ctyp,1               ; set Heath cursor to underline, on
        mov     anspflg,0               ; clear printer flag
        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
        mov     oldscrn,cx              ; remember old screen dimensions
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
        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                  ; physical = logical cursor here
        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: test    vtemu.vtflgop,vswdir    ; writing right to left?
        jz      ansre4                  ; z = no, left to right
        sub     dl,byte ptr low_rgt     ; reflect cursor from right side
        neg     dl
        mov     cursor,dx               ; store as logical position
ansre4: push    cx                      ; save current physical screen size
        call    stblmds                 ; Check settable modes, set flags
        pop     cx
        cmp     cx,oldscrn              ; has screen size changed?
        je      ansre3                  ; e = no, same as last time
        mov     oldscrn,cx              ; remember new size
        mov     mar_top,0               ; reset scrolling region
        mov     al,byte ptr low_rgt+1
        mov     mar_bot,al
        jmp     atres2                  ; better do soft reset
ansre3: 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
        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+dececho ; 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
        mov     ah,vtemu.vtchset        ; select char set from setup byte
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
        mov     ah,2                    ; set cursor
        mov     bh,0                    ; page 0
        mov     dx,cursor
        call    direction               ; set cursor for writing direction
        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 regs.
; Use same routine in msy to more closely track screen width.
;;scrloc        proc    near
;;      push    bx                      ; We will use bx
;;      mov     al,dh                   ; Get row
;;      mov     bl,swidth               ; And length of a line
;;      mul     bl                      ; Offset for this row
;;      mov     dh,0                    ; Clear row
;;      add     ax,dx                   ; Word offset for this position
;;      sal     ax,1                    ; Make it a byte offset
;;      pop     bx                      ; Restore bx
;;      ret                             ; And return
;;scrloc        endp



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

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


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

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

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

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


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

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

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

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

; Routine to toggle VT100/VT52/Heath-19 modes. No arguments.
; Use & update global byte flags.vtflg for terminal type and update local
; bit decanm. Note: shifting to Heath-19 here does Not reset the scrolling
; margins mar_top & mar_bot nor reset the double char linetype array.
; [jrd]
ans52t  proc    near
        cmp     tekflg,0                ; in Tek sub mode?
        jne     ans52c                  ; ne = yes, get out now
        cmp     flags.vtflg,ttvt100     ; in VT100 mode?
        jne     ans52a                  ; ne = no
        and     ansflgs,not decanm      ; reset VT100 ansi mode
        mov     flags.vtflg,ttvt52      ; say VT52 now (clears vt100 bit)
        mov     oldterm,ttvt52          ; and remember it
        jmp     ans52e
ans52a: cmp     flags.vtflg,ttvt52      ; in VT52 mode?
        jne     ans52b                  ; ne = no
        mov     flags.vtflg,ttheath     ; say Heath-19 now
        mov     oldterm,ttheath
        jmp     ans52e
ans52b: cmp     flags.vtflg,ttheath     ; in Heath-19 mode?
        jne     ans52c                  ; ne = no
        test    denyflg,tekxflg         ; is Tek mode disabled?
        jz      ans52f                  ; z = no, enabled
        mov     flags.vtflg,ttvt100     ; say VT100 now
        mov     oldterm,ttvt100
        or      ansflgs,decanm          ; set, go to VT100 mode
        jmp     short ans52e
ans52f: 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?
        je      ans52e                  ; e = yes, disabled
        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
        cmp     flags.modflg,1          ; mode line on and owned by us?
        ja      disled2                 ; a = no, leave it intact
        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
        call    direction               ; do Bios screen operation
        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
        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

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?
        jz      atdeb0                  ; z = not set
        push    ax                      ; Save the character for a second
        mov     al,7eh                  ; Output a tilde
        call    atnrm2
        pop     ax                      ; Restore character
        and     al,7fh                  ; and remove high bit
atdeb0: cmp     al,del                  ; A DELETE?
        je      atdeb1                  ; Yes - output "^?"
        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
        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],ascset    ; standard US ascii?
        je      atnrm2                  ; e = yes
        cmp     byte ptr [bx],alcset    ; Alternate character set? [bk]
        jne     atnrm0b                 ; ne = no [bk]
        cmp     al,('a'-1)              ; replace a..z with 128d - (a..z) [bk]
        jb      atnrm2                  ; b = out of range
        cmp     al,'z'
        ja      atnrm2                  ; a = out of range
        add     al,(80h-('a'-1))        ; map up by 20h
        jmp     short atnrm2

atnrm0b: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?
        je      atnrm3                  ; e = yes
        push    ax                      ; save char
        call    inschr                  ; open a char space in this line
        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?
        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)
        call    direction               ; do Bios screen operation
        pop     ax                      ; recover the char
        mov     ah,9                    ; Output char in al to screen
        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
        call    direction               ; do Bios screen operation
        mov     al,' '                  ; use a space for doubling
        mov     ah,9                    ; Output to screen
        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
        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:mov     scroll,1                ; scroll count = 1 line
        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
atscu4a: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
        and     yflags,not modoff       ; now say it's on (owned by host)
        pop     dx
atscu8: mov     flags.modflg,2          ; say mode line is owned by host
        mov     al,yflags               ; place to communicate
        call    telmsy                  ; tell msy the news

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
        call    direction               ; do Bios screen operation
        shr     dl,1                    ; restore dl (logical column)
        jmp     short atscu5b
atscu5a:call    direction               ; do Bios screen operation
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?
        ja      atcci0                  ; a = 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     scroll,1
        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     scroll,1                ; 1 line
        mov     ax,offset atscru        ; Yes, indicate scroll up required
atcci6: mov     dh,mar_bot              ; Set to bottom margin
        pop     cx
        ret
atcci7: pop     cx                      ; old pos was outside scrolling region
        jmp     atccpc                  ; do full screen check and return

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

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

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

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

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


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

revscn: mov     dh,byte ptr low_rgt+1   ; Compute last screen offset in ax
        inc     dh                      ; One more row to catch mode line
        mov     dl,crt_cols             ; physical width
        dec     dl                      ; and we count from 0
        call    scrloc
        mov     cx,ax                   ; Save it in cx for a minute
        mov     dx,0                    ; Compute first screen offset in ax
        call    scrloc
        sub     cx,ax                   ; Compute number of locs to change.
        add     cx,2
        sar     cx,1                    ; In 16-bit words please
        push    di                      ; Save some more acs
        push    es
        push    cx                      ; save word count for Topview
        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
        call    scrsync                 ; synch with Topview
        call    scron                   ; Turn screen back on if color card
        pop     es                      ; Restore segment register
        pop     di                      ; And destination index
        ret


; Reset-everything routine.

atreset:mov     al,0                    ; Make cursor disappear for a while
;;      call    csrtype
        mov     cursor,0                ; Cursor is at 0,0
        mov     ansflgs,0               ; reset these flags
        mov     escdec,0
        cmp     flags.vtflg,ttvt100     ; VT100?
        jne     atres7                  ; ne = no
        mov     ansflgs,decanm          ; turn on ANSI mode flag
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
        mov     h19l25,0                ; clear heath 25th line enable
        mov     h19ctyp,1               ; Heath-19 cursor to underline
        mov     anspflg,0               ; clear printer flag
        mov     cx,4                    ; Initialize the "LEDs"
        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
        pop     es
        call    disleds                 ; update mode line
        mov     vttabs,offset deftabs
        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
        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
        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    vtemu.vtflgop,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,vtemu.vtchset        ; get setup default character 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?
        je      atht2                   ; e = yes. handle specially
        mov     ch,0
        mov     cl,byte ptr low_rgt
        cmp     dl,cl                   ; At or beyond last column?
        jae     atbs1                   ; Yes, check range, set cursor and ret
        mov     bh,0                    ; Make an index
        mov     bl,dl                   ; For column
        sub     cl,dl                   ; number of columns to examine
atht1:  inc     bx                      ; Tab always moves at least one space
        cmp     tabs[bx],0              ; Look for non-zero
        loopz   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?
        je      atlf2                   ; e = yes
        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     escdec,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?
        jne     atv52f                  ; ne = not VT100, try others
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?
        je      ath19f                  ; e = yes. Use Heath esc seqs
        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     ch,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      escdec,decmode          ; Yes - say DEC modes are coming
        ret                             ; And return
atpaa2a:cmp     al,'>'                  ; Heath private mode?
        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] 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?
        jne     atscs5                  ; ne = no
        mov     al,alcset               ; use Alternate character set
        ret

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

                                        ; ESC # Pn  series
atsdhl: mov     ttstate,offset atsdbl   ; set up to parse argument
        ret
atsdbl: cmp     al,'3'                  ; Double high lines. Top half?
        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?
        jne     atcup6                  ; ne = no [hlk]
        cmp     h19l25,0                ; Heath 25th line enabled?
        je      atcup5                  ; e = no
atcup6: mov     dh,byte ptr low_rgt+1   ; bottom normal line
        inc     dh                      ; the 25th line
        jmp     atscu4                  ; set cursor position and return
atcup5: call    atccpc                  ; Check position
        jmp     atscu5                  ; Set cursor position and return

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

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

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

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

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

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

ated3:  cmp     ansargs[si],2           ; Was arg two?
        jne     ated1                   ; ne = no, else erase entire screen
        mov     al,byte ptr low_rgt+1   ; number of lines on screen
        mov     scroll,al
        call    atscru                  ; scroll them up before erasure
                                        ; removes double w/h lines too.
        mov     ax,0                    ; erase from here (home)
        mov     bx,low_rgt
        mov     bl,crt_cols
        dec     bl                      ; physical width (to here)
        call    vtsclr                  ; clear screen
        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    vtsclr                  ; 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    vtsclr                  ; 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    vtsclr                  ; 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
        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                  ; ne = no
        or      al,att_underline        ; Yes, set underscore
        cmp     crt_mode,7              ; monochrome display adapter mode?
        je      atsgr3a                 ; e = yes. Otherwise reverse video
                        ; use reversed video rather than blue on black
        and     al,not att_underline    ; clear underline and
        rol     ah,1                    ; reverse the colors
        rol     ah,1
        rol     ah,1
        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?
        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?
        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,20                   ; assumed length of asciiz string
        mov     si,offset dastr         ; Point to the string
        cmp     flags.vtflg,ttvt100     ; VT100?
        je      decid1                  ; e = yes
        mov     si,offset v52str        ; No - try VT52 i.d.
        cmp     flags.vtflg,ttvt52      ; Heath-19 mode?
        je      decid1                  ; e = yes
        mov     si,offset h19str        ; say Heath-19
decid1: cld
        lodsb                           ; Get a byte
        cmp     al,0                    ; end of string?
        je      decid2                  ; e = yes
        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
decid2: 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"
        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
        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?
        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    escdec,decmode          ; Printer status report from
        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
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    escdec,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
        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?
        jne     atrsmc                  ; ne = no
        mov     al,modeset              ; set/reset insert mode
        mov     insmod,al               ; store it
        ret
atrsmc: cmp     al,12                   ; 12? Control local echo
        jne     atrsmx                  ; ne = no
        cmp     modeset,0               ; resetting mode (ESC [ 12 l)?
        jne     atrsmc1                 ; ne = no
        or      ansflgs,dececho         ; remember state here too
        or      yflags,lclecho          ; (l) turn on local echoing
        jmp     short atrsmc2
atrsmc1:and     yflags,not lclecho      ; (h) turn off local echoing
        and     ansflgs,not dececho
atrsmc2:mov     al,yflags
        call    telmsy                  ; inform msy about echoing state
        test    yflags,modoff           ; is mode line off?
        jnz     atrsmx                  ; 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
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?
        je      atrsm5a                 ; e = yes, handle specially
        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?
        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
        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
        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?
        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,34                   ; ESC [ ? 34 h/l? Invoke special macro
        jne     atrsm10                 ; ne = no
        cmp     modeset,0               ; resetting?
        jne     atrsm9a                 ; ne = no, setting
        jmp     vtrmac                  ; jump to perform on-line macro
                                        ;  code is located in file msy
atrsm9a:jmp     vtsmac                  ; do set macro

atrsm10:cmp     al,38                   ; 38? Enter Tek sub-mode. VT340 seq
        jne     atrsm11                 ; ne = no
        cmp     modeset,1               ; setting mode (ESC [ ? 38 h)?
        jne     atrsm11                 ; ne = no, ignore sequence
        test    denyflg,200h            ; is auto Tek mode disabled?
        jnz     atrsm11                 ; 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

atrsm11:ret
                ; Heath-19  ESC [ > Ps h or l where Ps = 1, 4, 7, or 9
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     vtsclr                  ; 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?
        jz      atrsfx                  ; z = no
        cmp     flags.vtflg,ttheath     ; in Heath-19 mode?
        je      atrsfx                  ; e = yes, don't flip terminal kinds
        mov     flags.vtflg,ttvt100     ; say VT100 now
        jmp     short atrsfx
atrsf1: not     al                      ; Complement
        and     ansflgs,al              ; Clear the bit
        not     al                      ; recover the bit
        test    al,decanm               ; Changing terminal type?
        jz      atrsfx                  ; z = no
        cmp     flags.vtflg,ttheath     ; in Heath-19 mode?
        je      atrsfx                  ; e = yes, don't flip terminal kinds
        mov     flags.vtflg,ttvt52      ; say VT52 now
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
        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)

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      escdec,decmode          ; simulate ESC [ ? 5 i
        jmp     ansprt                  ; process command

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

v52pcb: mov     ansargs,5               ; Enter printer controller on
        or      escdec,decmode          ; simulate ESC [ ? 5 i
        jmp     ansprt                  ; process command

v52pce: mov     ansargs,4               ; Exit printer controller on
        or      escdec,decmode          ; simulate ESC [ ? 4 i
        jmp     ansprt                  ; process command

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

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

                                        ; Heath-19 special functions

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     vtsclr                  ; Clear it
                                        ; 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     vtsclr                  ; 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     vtsclr                  ; 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     vtsclr                  ; 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

inslin: cmp     ansargs,0               ; insert line(s). Any args?
        jne     insli1                  ; ne = yes. If no arg use 1
        mov     ansargs,1               ; insert one line
insli1: mov     dl,ansargs
        mov     scroll,dl
        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
insli2: call    atscrd                  ; scroll down
        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?
        jne     delli1                  ; no arg; use 1
        mov     ansargs,1               ; insert one line
delli1: mov     dl,ansargs
        mov     scroll,dl               ; line count
        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
delli2: call    atscru                  ; scroll up
        pop     word ptr mar_top        ; restore scrolling margins
        jmp     atscu5                  ; restore cursor and return
delli3: ret

                                        ; Delete character(s)
atdelc: cmp     ansargs,0               ; zero becomes one operation
        jne     atdelc1
        mov     ansargs,1               ; delete one char. Heath ESC N
atdelc1:mov     cl,byte ptr low_rgt     ; number of columns on screen
        mov     dx,cursor               ; get present cursor position
        push    bx
        mov     bl,dh                   ; get row
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        je      atdelc5                 ; e = yes
        shl     dl,1                    ; double the column number
        mov     bl,ansargs
        shl     bl,1                    ; double # chars to delete
        mov     ansargs,bl
atdelc5:pop     bx
        sub     cl,dl                   ; end of screen - current column #
        xor     ch,ch                   ; cx = number of chars to move
        cmp     cx,0                    ; zero means just this char
        ja      atdelc4
        inc     cx                      ; say one, this one
atdelc4:push    es
        push    cx                      ; save word count for Topview
        cld
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      atdelc4a                ; z = yes
        sub     dl,byte ptr low_rgt     ; reflect about logical right column
        neg     dl                      ; convert to positive value
atdelc4a:
        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 implies one
atdelc3:shl     ax,1                    ; double: char and its attribute byte
        push    di                      ; destination offset
        cld                             ; assume forward for left to right
        test    vtemu.vtflgop,vswdir    ; writing left to right
        jz      atdelc3a                ; z = yes
        neg     ax                      ; minus ax, work the other way
        std                             ; movement reverses too
atdelc3a:
        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
        cld                             ; reset direction to forward
        pop     ds                      ; recover normal ds
        pop     cx                      ; count for Topview
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      atdelc6                 ; z = yes
        sub     di,cx                   ; get correct es:di ending address
        sub     di,cx                   ; for scrsync
atdelc6:call    scrsync                 ; synch Topview
        pop     es
        call    scron
        mov     ax,cursor               ; get current row
        mov     bx,cursor
        mov     bl,byte ptr low_rgt     ; last col on screen
        mov     al,bl
        sub     al,ansargs              ; minus number of locations cleared
        inc     al
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      atdelc7                 ; z = yes
        mov     cl,byte ptr low_rgt     ; reflect about logical right margin
        sub     cl,al
        mov     bl,cl                   ; end of line to be cleared
        mov     al,0                    ; start of line to be cleared
atdelc7:call    atsclr                  ; clear end of line
atdelcx:mov     dx,cursor
        jmp     atscu5                  ; reposition cursor

inschr: mov     dx,cursor               ; open one char space in current line
        push    bx
        mov     bl,dh                   ; get row
        mov     bh,0
        cmp     linetype [bx],0         ; single width line?
        je      insch2                  ; e = yes
        shl     dl,1                    ; double the column number
insch2: pop     bx
        mov     ch,0
        mov     cl,byte ptr low_rgt     ; number of columns on screen
        push    dx
        mov     dh,0
        sub     cx,dx                   ; compute distance to end
        pop     dx
        or      cx,cx
        jle     insch1                  ; le = nothing to move [dlk]
        mov     dl,byte ptr low_rgt
        dec     dl                      ; last col to move
        push    ax                      ; save regs
        push    es                      ; ditto
        push    cx                      ; save count for Topview
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      insch3                  ; z = yes
        mov     dl,1                    ; right-to-left physical EOL-1
        call    scrloc                  ; compute position of end of line-1
        push    ax                      ; save offset
        cld                             ; remember to move forward
        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
        sub     di,2                    ;   is one char over
        jmp short insch4                ; join common code
insch3:                                 ; do normal left to right material
        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
insch4: 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
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      insch5                  ; z = yes
        add     di,cx                   ; get correct es:di ending address
        add     di,cx                   ; for scrsync
insch5: call    scrsync                 ; synch Topview
        pop     es                      ; restore regs
        pop     ax                      ; ditto
        call    scron                   ; turn on screen again
        cld                             ; reset direction
insch1: mov     dx,cursor
        jmp     atscu5                  ; position cursor

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

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

ansich  proc    near                    ; ANSI insert characters ESC [ Pn @
        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
        mov     ah,ansflgs              ; save flags in ah
        and     ansflgs,not decawm      ; turn off autowrap
        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
        mov     ansflgs,ah              ; recover flags
        mov     ah,0                    ; clear register
        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
; scroll has number of lines to scroll
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
        push    si
        xor     bh,bh
        mov     bl,mar_top              ; top line to move
        xor     ch,ch
        mov     cl,scroll               ; number of lines to move
        jcxz    atscru5                 ; cx = 0. nothing to do
        mov     al,mar_bot              ; bottom line to scroll
        sub     al,bl                   ; number of lines minus 1
        inc     al                      ; number of lines
        cmp     al,cl                   ; scrolling region smaller than scroll?
        jge     atscru1                 ; ge = no, is ok
        mov     scroll,al               ; limit to region
        cmp     al,1                    ; at least one line to scroll?
        jge     atscru1                 ; ge = yes
        mov     scroll,1                ; no, force one
atscru1:push    bx
        mov     bl,dh                   ; get row of cursor
        mov     bh,0
        cmp     linetype[bx],0          ; single width?
        pop     bx
        je      atscru7                 ; e = yes
        shr     dl,1                    ; reindex to single width columns
atscru7:mov     al,scroll
        xor     ah,ah
        cmp     al,byte ptr low_rgt+1   ; number of lines on screen
        jbe     atscru8                 ; be = scrolling not more than that
        mov     al,byte ptr low_rgt+1   ; limit to screen length
        mov     scroll,al
atscru8:mov     si,ax                   ; scroll interval
        mov     bl,mar_top
        mov     cl,mar_bot
        sub     cl,bl
        inc     cl                      ; number  of lines in region
        sub     cl,scroll               ; cx = those needing movement
        jcxz    atscru3
atscru2:mov     al,linetype[bx+si]      ; get old type
        mov     linetype[bx],al         ; copy to new higher position
        inc     bx
        loop    atscru2
atscru3:mov     bl,mar_bot              ; set fresh lines to single attribute
        mov     cl,scroll
        mov     ch,0
        inc     cx
atscru4:mov     linetype[bx],0
        dec     bx
        loop    atscru4                 ; clear old bottom lines
atscru5:pop     si
        pop     cx
        pop     bx
        pop     ax
        test    anspflg,vtcntp          ; controller print active?
        jz      atscru6                 ; z = no, ok to change screen
        ret                             ;  else keep screen intact
atscru6: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
        push    si
        xor     ch,ch
        mov     cl,scroll               ; number of lines to scroll
        jcxz    atscrd5                 ; cx = 0. nothing to do
        xor     bh,bh
        mov     bl,mar_bot              ; bottom line to move
        mov     al,bl
        mov     ah,0
        sub     al,mar_top              ; number of lines minus 1
        inc     al                      ; number of lines
        cmp     al,cl                   ; scrolling region smaller than scroll?
        jge     atscrd1                 ; ge = no, is ok
        mov     scroll,al               ; limit to region
        cmp     al,1                    ; at least one line to scroll?
        jge     atscrd1                 ; ge = yes
        mov     scroll,1                ; no, force one
atscrd1:push    bx
        mov     bl,dh                   ; get row of cursor
        mov     bh,0
        cmp     linetype[bx],0          ; single width?
        pop     bx
        je      atscrd7                 ; e = yes
        shr     dl,1                    ; reindex to single wide columns
atscrd7:mov     al,scroll
        mov     si,ax                   ; si = scroll
        sub     bl,scroll               ; si + this bx will be new bottom line
        mov     cl,bl
        sub     cl,mar_top
        inc     cl                      ; number of movements
        jcxz    atscrd3
atscrd2:mov     al,linetype[bx]         ; get old line's type
        mov     linetype[bx+si],al      ; copy to new lower position
        dec     bx
        loop    atscrd2
atscrd3:mov     bl,mar_top
        mov     bh,0
        mov     cl,scroll
        mov     ch,0
        inc     cx
atscrd4:mov     linetype[bx],0          ; clear new top lines
        inc     bx
        loop    atscrd4
atscrd5:pop     si
        pop     cx
        pop     bx
        pop     ax
        test    anspflg,vtcntp          ; controller print active?
        jz      atscrd6                 ; z = no, ok to change screen
        ret                             ;  else keep screen intact
atscrd6: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     cl,byte ptr low_rgt     ; number of columns on screen
        inc     cl
        shr     cl,1                    ; number of columns to do
        mov     ch,0
        push    cx                      ; save around loop below
linsgl1:push    cx                      ; save loop counter
        shl     dl,1                    ; double column number
        mov     ah,2                    ; set cursor
        xor     bh,bh                   ; page 0
        call    direction               ; do Bios screen operation
        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
        call    direction               ; do Bios screen operation
        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
        pop     cx                      ; recover column counter
        mov     dl,cl
linsgl2:push    cx                      ; save counter
        mov     ah,2                    ; set cursor
        call    direction               ; do Bios screen operation
        mov     bh,0
        mov     bl,scbattr              ; screen background
        mov     al,' '
        mov     ah,9                    ; write char
        mov     cx,1                    ; do one character
        call    direction               ; do Bios screen operation
        inc     dl                      ; next column
        pop     cx
        loop    linsgl2                 ; repeat for all characters
        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     cl,byte ptr low_rgt     ; number of columns on the screen
        inc     cl
        mov     ch,0
        shr     cl,1                    ; number of items to do
        mov     dl,cl
        dec     dl
        call    scroff                  ; turn off the video
lindbl1:push    cx                      ; save loop counter
        mov     ah,2                    ; set cursor
        mov     bh,0                    ; page 0
        call    direction               ; do Bios screen operation
        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
        call    direction               ; do Bios screen operation
        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
        call    direction               ; do Bios screen operation
        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
        mov     di,offset ansprt0       ; routine to process arguments
        call    atreps                  ; Repeat for all parms
        ret

ansprt0:mov     ah,ansargs[si]          ; Pick up the argument
        cmp     ah,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     ah,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
        call    pntflsh                 ; flush printer buffer
anspr1a:jmp     atscu5                  ; reposition cursor and return

ansprt4:cmp     ah,4                    ; 4 (auto print disable)?
        jne     ansprt5                 ; ne = no
        test    escdec,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
        and     anspflg,not vtautop     ; auto-print disable
        call    trnprs                  ; toggle mode line PRN indicator
anspr4a:jmp     ansprtx

ansprt5:cmp     ah,5                    ; 5 (auto print enable)?
        jne     ansprtx                 ; ne = no
        call    pntchk                  ; check printer, ignore carry ret
        jc      ansprtx                 ; c = printer not ready
        test    escdec,decmode          ; was it ESC [ ? 5 i
        jz      anspr5a                 ; z = no
        test    anspflg,vtautop         ; is print already enabled?
        jnz     ansprtx                 ; nz = yes, leave trnprs intact
        or      anspflg,vtautop         ; auto-print enabled
        jmp     short anspr5b
anspr5a:test    anspflg,vtcntp          ; controller print already enabled?
        jnz     ansprtx                 ; nz = yes
        or      anspflg,vtcntp          ; controller print enabled
anspr5b:call    trnprs                  ; toggle on mode line PRN indicator
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,escape               ; start of MC Off sequence?
        jne     ansmc1                  ; ne = no
        call    ansmc6                  ; playback previously matched chars
        mov     mccnt,1                 ; count matched chars (one now)
        mov     mcoffs,al               ; save full character, with high bit
        mov     ansargs,0               ; clear first ansi argument
        mov     nansarg,0               ; number of arguments
        ret

ansmc1: mov     bx,mccnt                ; number of chars matched in MC Off
        cmp     bx,0                    ; have first?
        jne     ansmc1a                 ; ne = yes, one or more
        jmp     pntchr                  ; print it, ignore errors

ansmc1a:mov     mcoffs[bx],al           ; save this char, with high bit
        inc     mccnt                   ; count saved characters
        and     al,7fh                  ; strip high bit
        cmp     al,'0'                  ; A digit?
        jge     ansmc2                  ; ge = maybe
        jmp     ansmc6                  ; b = out of range for everything
ansmc2: cmp     al,'9'                  ; maybe, separator or final char?
        ja      ansmc3                  ; a = perhaps, go check it out
        mov     cl,al                   ; digit, convert ASCII to binary
        sub     cl,'0'
        mov     ch,0
        mov     bl,nansarg              ; put index in bx
        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     ansmc2a                 ; be = ok [dlk]
        mov     al,0ffh                 ; set to max value [dlk]
ansmc2a:mov     ansargs[bx],al          ; Put result back for next time [dlk]
        ret                             ; And return

ansmc3: cmp     al,'['                  ; ANSI sequence?
        jne     ansmc4                  ; ne = no, check further
        cmp     mccnt,2                 ; is it the second character?
        je      ansmc3a                 ; e = yes, accept and continue
        jmp     ansmc6                  ; no, end match
ansmc3a:ret                             ; continue

ansmc4: cmp     al,';'                  ; Argument separator?
        jne     ansmc5                  ; ne = no, check for final char
        inc     nansarg                 ; yes, count it
        mov     bl,nansarg              ; get argument index
        mov     bh,0
        mov     ansargs[bx],0           ; clear next arg field
        cmp     bl,lansarg              ; too many?
        jl      ansmc4a                 ; l = no, continue
        dec     nansarg                 ; yes, do not add more
        jmp     ansmc6                  ; end match now
ansmc4a:ret                             ; accept separator and continue

ansmc5: cmp     al,'i'                  ; sequence terminator?
        jne     ansmc6                  ; ne = no, end match
        mov     bx,-1
        mov     cl,nansarg              ; number of argument values
        mov     ch,0
        inc     cx                      ; no args is same as one
ansmc5a:inc     bx
        mov     al,ansargs[bx]          ; get ansi argument
        mov     ansargs[bx],0ffh        ; and zap it to absorb early values
        cmp     al,4                    ; MC OFF value?
        loopne  ansmc5a                 ; ne = no, examine all non-matches
        jne     ansmc6                  ; ne = no match, end matching
                                        ; MC OFF sequence discovered
        mov     mccnt,0                 ; clear counter
        call    pntflsh                 ; flush printer buffer
        test    anspflg,vtcntp          ; was printing active?
        jz      ansmc5b                 ; z = no, do nothing
        and     anspflg,not vtcntp      ; yes, disable print controller
        call    trnprs                  ; toggle mode line PRN indicator
ansmc5b:jmp     ansprt                  ;  done, process arguments in order

                                        ; MC OFF sequence not found, playback
ansmc6: push    ax                      ; save break char (in al)
        push    cx                      ; playback partial sequence to printer
        mov     cx,mccnt                ; number of chars matched before break
        jcxz    ansmc6b                 ; z = none
        push    si
        mov     si,offset mcoffs        ; string to be played back
        cld
ansmc6a:lodsb                           ; get a char into al
        call    pntchr                  ; print it, ignore errors
        loop    ansmc6a                 ; do all that came in previously
        pop     si
ansmc6b:pop     cx
        pop     ax                      ; recover break char
        mov     mccnt,0                 ; reset to no match and exit
        mov     nansarg,0
        ret
ansmc   endp

pntlin  proc    near                    ; print whole line given by dx
        push    ax
        push    bx
        push    cx
        push    dx
        xor     ch,ch
        mov     cl,byte ptr low_rgt     ; number of columns
        mov     dl,cl                   ; Bios column counter, dh = row
        inc     cl                      ; actual line length, count it down
        test    vtemu.vtflgop,vswdir    ; writing right to left?
        jnz     pntlin2                 ; nz = yes, do not trim spaces
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

; Do Bios screen operation with consideration for writing direction.
; Enter with normal registers set, preserves register dx.

direction proc  near
        push    dx
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      direct1                 ; z = yes, do Bios function
        sub     dl,byte ptr low_rgt     ; right margin column number
        neg     dl                      ; make a positive value again
direct1:int     screen
        pop     dx
        ret
direction endp

; Clear screen from AX to BX, where AH = row, AL = column, ditto for BX.
; This routine accomdates right to left writing. BX >= AX.
vtsclr  proc    near
        test    vtemu.vtflgop,vswdir    ; writing left to right?
        jz      vtsclr4                 ; z = yes
        cmp     bh,ah                   ; same row?
        je      vtsclr2                 ; e = yes
        push    ax                      ; multiple lines
        push    bx                      ; save both coordinates
        mov     bl,byte ptr low_rgt     ; get right most logical column
        mov     bh,ah                   ; pick just top line
        call    vtsclr2                 ; delete fraction of top line
        pop     bx                      ; recover ending position
        push    bx
        inc     ah                      ; omit top row, now done
        dec     bh                      ; omit last line, could be fractional
        cmp     bh,ah                   ; any whole lines remaining to delete?
        jb      vtsclr1                 ; b = no, finish up
        mov     bl,byte ptr low_rgt     ; get right most physical column
        mov     al,0                    ; to end of line (on left)
        call    atsclr                  ; clear top line and whole remainders
vtsclr1:pop     bx                      ; setup for last line to be cleared
        push    bx                      ; get last row again
        mov     al,0                    ; start at logical left margin
        jmp     short vtsclr3           ; ax and bx are already pushed

vtsclr2:push    ax                      ; erase single line, whole or part
        push    bx
vtsclr3:mov     ah,byte ptr low_rgt     ; borrow reg ah (same as bh)
        sub     ah,bl                   ; reflect right to left
        mov     bl,ah
        or      bl,bl                   ; overflow?
        jns     vtsclr5                 ; ns = no, is ok
        mov     bl,0                    ; limit to logical screen
vtsclr5:mov     ah,byte ptr low_rgt
        sub     ah,al
        mov     al,ah
        jns     vtsclr6
        mov     al,byte ptr low_rgt     ; limit to logical screen
vtsclr6:mov     ah,bh                   ; restore ah
        xchg    al,bl                   ; reverse to get physical ax < bx
        call    atsclr                  ; erase part/all of single line
        pop     bx
        pop     ax
        ret
                                        ; for writing left to right
vtsclr4:jmp     atsclr                  ; do normal erasure and return
vtsclr  endp


code    ends

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

        end