	NAME msyibm
; File MSYIBM.ASM
	include mssdef.h
;       Copyright (C) 1982,1993, Trustees of Columbia University in the
;       City of New York.  Permission is granted to any individual or
;       institution to use, copy, or redistribute this software as long as
;       it is not sold for profit and this copyright notice is retained.
; edit history:
; 6 Sept 1991 version 3.11
; Last edit 9 June 1993
; 9 May 1993 Add test for Japanese DOS and if present avoid Int 15h. Presence
;  is held in tv_mode bit 20h.
; 12 April 1993 apply 5 dot compressed font (compressed text) to VT emulators
;  via option SET TERM COMPRESS GRAPHICS
; 14 Jan 1993 Add expanded memory usage for screen rollback buffer
; 25 June 1992 Multiple TCP/IP session support, revise segmenting, virtual
;  screens, horizontal scrolling, Connect mode macro at entry, DG support.
; 23 Dec 1990 Add Bert Tyler's (NIH) IBM XGA 132 column code.
; 9 May 1989 Add Bert Tyler's (NIH) new screen rollback routines.
; 21 Jan 1989 be more tolerate of propriatary video modes above 18 when
;  determining screen segment, Tnx to Terry Kennedy. Add check for IBM
;  85xx monitors on Video 7 boards, no 132 columns if it is the monitor.
;  Retain 43 rows on Video 7 boards.
; 30 Nov 1988 Add SET TERM CLEAR screen clearing support.
; 28 Nov 1988 Accomodate Tseng Labs UltraPAK mono/Herc board w/132 cols.
;  132 column mode is 18h. Requires Tseng's BIGSCR.COM (use BIGSCR /R:25
;  to enable 132x25 feature). Thanks to Tseng Labs for technical support.
; 21 Nov 1988 Version 2.32
; 14 Nov 1988 Write a space during lclini to obtain default screen colors.
; 12 Nov 1988 Add procs vtrmac and vtsmac to allow exit from Connect mode and
;  invokation of macros TERMINALR and TERMINALS by reception of escape seqs
;  in file mszibm.asm or by keyboard verbs.
; 7 Oct 1988 Reverse left/right arrow key codes when writing right to left.
; 24 Sept 1988 Make output to printer be buffered and flow controlled.
; 1 July 1988 Version 2.31
; 19 June 1988 Add Everex EVGA support, from Terry Kennedy.
; 10 June 1988 Add oldsp and procedure endcon to exit Connect mode if output
;  fails, mostly for networking (but we don't know that here).
; 23 May 1988 Add Everex EV-659 ega board test from Alex Zliu. Fixed incorrect
;  screen width assumption at startup.
; 29 March 1988 Include flag ttyact to group string bytes into one net packet,
;  thanks to Paul Fox of AT&T.
; 23 March 1988 Add "fairness" word to let serial port deliver max chars
;  between kbd reads, for connect mode only. [jrd]
; 10 Feb 1988 Revise getcirc and vtscrX routines to do proper scrolling with
;  MS Window 1.0x/2.0x [jrd].
; 9 Feb 1988 Mode line again. Make flags.modflg 0 for off, 1 for on and owned
;  by Kermit, and 2 for on and owned by remote host (toggling suppressed).
; 25 Jan 1988 Add global byte SCROLL, set in msz, to control emulator screen
;  scrolling for higher speeds. [jrd]
; 5 Jan 1988 Restore cursor codes broken by Tek code additions. [jrd]
; 1 Jan 1988 version 2.30

	public	term, lclyini, termswapout, termswapin, termswapdel
	public	prtbout, prtnout, csrtype, fcsrtype, scrseg
	public	atsclr, vtscru, vtscrd, trnmod, vclick, vtbell
	public	chgdsp, vtroll, crt_lins, crt_cols, tv_mode, vtclear
			; action verb procedures for keyboard translator
	public	uparrw, dnarrw, rtarr, lfarr, pf1, pf2, pf3, pf4
	public	kp0, kp1, kp2, kp3, kp4, kp5, kp6, kp7, kp8, kp9
	public	kpminus, kpcoma, kpenter, kpdot, chrout, cstatus, cquit
	public	cquery, dmpscn,	vtans52, vtinit, dnwpg, upwpg, endwnd, homwnd
	public	upone, dnone, trnprs, dumpscr, modlin, snull, ignore_key
	public	klogon, klogof, cdos, chang, khold, product
	public	vtksmac, vtkrmac, apcmacro, apcenable, vtenqenable
	public	decf6,decf7,decf8,decf9,decf10,decf11,decf12,decf13,decf14
	public	dechelp,decdo,decf17,decf18,decf19,decf20, udkclear
	public	decfind, decinsert, decremove, decselect, decprev
	public	decnext, setudk, extmacro, vtmacname, vtmaclen
	public	rtone, lfone, rtpage, lfpage, kbdcompose
	public	dgkc1,dgkc2,dgkc3,dgkc4,dgkf1,dgkf2,dgkf3,dgkf4,dgkf5
	public	dgkf6,dgkf7,dgkf8,dgkf9,dgkf10,dgkf11,dgkf12,dgkf13
	public	dgkf14,dgkf15, dgpoint, dgnckey

	public	vtemu, crt_mode, scbattr, refresh, low_rgt	; data
	public	setchtab, ftogmod, extattr, vtcpage
	public	setpos, getatch, setatch, yflags
	public	getbold, setbold, clrbold, getblink, setblink, clrblink
	public	getunder, setunder, clrunder, revideo, revscn, setcolor
	public	setrev, clrrev, frepaint, touchup
	public	vts, vtstat, termtb, modbuf		; terminal emulation
	public	nextses, vtinited, setprot, clrprot, qsetatch
	public	dgsettek

; some definitions
SIchar	equ	0fh
SOchar	equ	0eh
DGescape equ	1eh

; hardware
crt_status equ	3dah			; CGA crt status port
disp_enb equ	8			; CGA display enable bit
crtmset	equ	3D8H			; CGA CRT mode set port
screen	equ	10h			; Bios screen interrupt

emsint	equ	67h			; EMS interrupt
xmspresent equ	4300h			; EMS presence check for XMS mgr
emsmgrstat equ	40h			; EMS get manager status
emsgetseg equ	41h			; EMS get segment of page frame
emsgetnpgs equ	42h			; EMS get number free pages
emsalloc equ	43h			; EMS get handle and allocate memory
emsmapmem equ	44h			; EMS map memory
emsrelease equ	45h			; EMS release mapped memory
emsgetver equ	46h			; EMS get version number
emssetname equ	5301h			; EMS LIM 4, set name

att_bold	equ	08h		; bold		in main video word
att_blink	equ	80h		; blinking	in main video word
att_intensity	equ	08H
att_protect	equ	01h		; protected	in vsatt
att_uline	equ	02h		; underscored	in vsatt
att_rev		equ	04h		; reversed video  in vsatt

att_low_mask	equ	06H		; Various attribute-related equates
att_normal	equ	07h
att_underline	equ	01H		; for mono monitors, in video word

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

; structure for status information table sttab.
stent	struc
sttyp	dw	?		; type (actually routine to call)
msg	dw	?		; message to print
val2	dw	?		; needed value: another message, or tbl addr
tstcel	dw	?		; address of cell to test, in data segment
basval	dw	0		; base value, if non-zero
stent	ends


data	segment
	extrn	flags:byte, mar_top:byte, mar_bot:byte, portval:word
	extrn	filtst:byte, dmpname:byte, kbdflg:byte, rxtable:byte
	extrn	anspflg:byte, tekflg:byte, scroll:byte, ttyact:byte
	extrn	holdscr:byte, taklev:byte, takadr:word, mcctab:byte
	extrn	trans:byte, npages:word, comand:byte, apctrap:byte
	extrn	denyflg:word, tekgraf:byte, rdbuf:byte, dupflg:byte
	extrn	chcontrol:byte, kbcodes:byte, repflg:byte, tekcursor:byte
	extrn	decbuf:byte, param:word, nparam:word, prnhand:word
	extrn	upss:byte, comptab:byte, GRptr:word, G1set:byte, G2set:byte
	extrn	G3set:byte, kstatus:word, cursor:word, linescroll:byte
	extrn	sescur:word, tcphost:byte, savezlen:word, savezoff:word
	extrn	seslist:byte, savexoff:word, savexlen:word, savepoff:word
	extrn	saveplen:word, rollwidth:word, dgkbl:byte, apcstring:word
	extrn	blinkdis:byte, protectena:byte, dghscrdis:byte
	extrn	dgwindcomp:byte, cursorst:byte, dgcross:byte
	extrn	emsrbhandle:word, curattr:byte, saveuoff:word, saveulen:word
	extrn	savegoff:word, saveglen:word, dosnum:word
	extrn	parmsk:byte, flowon:byte, flowoff:byte, flowcnt:byte

inited	equ	08h			; been here before
prtscr	equ	1			; print screen pressed
; stuff for screen routines
;;;;;;;;;;;;;; start session save area
	even
saveyoff label	word
yflags	db	0			; status flags
vtemu	emulst	<>			; emulator flags
belltype db	0			; 0 = aural bell, 1 = visual
scbattr db	?			; screen background attribute
savattr	db	?			; current emulator attributes
extattr	db	0			; extended scbattr
crt_mode db	3			; video mode (typ 3, must be text)
					; keep crt_cols & crt_lins in order
crt_cols db	80			; number of screen columns (typ 80)
crt_lins db	24			; number of screen rows - 1 (typ 24)
low_rgt	dw	174fh			; lower right corner of text window
					; high = row address (typ 23)
					; low = column address (typ 79)
handhsc	db	0			; hand horizontal scroll
dosetcursor dw	-1			; place to set tekcursor, -1 = don't
vtinited db	0			; flag for emulator having been inited
vtclear	db	0			; nonzero to redo emulator screen
writemode db	0			; screen writing mode
vtcpage	dw	437			; terminal code page
apcenable db	1			; enable APC macro (default is on)
vtenqenable db	0			; enable Answerback
saveflag	flginfo <>		; copy of flags array
ytermtype dw	0
ymodetype db	0
saveylen dw	($ - saveyoff)
;;;;;;;;;;;;;;;;; end of session save area


modbuf	modfrm	<>			; mode line buffer
argadr	dw	0			; address of arg blk
skip	dw	0
inemulator db	0			; non-zero if term emlator active

vid7id	db	'VEGA BIOS Code, '	; Video 7 Vega version string subset
vid7len	equ	$-vid7id		; length of string
vid7id2	db	'Video Seven BIOS Code, ' ; Video 7 VGA board
vid7len2 equ	$-vid7id2
atiwid	db	'ATI EGA Wonder Bios,'	; ATI EGA wonder version string subset
atilen	equ	$-atiwid		; length of string, inc terminator
atiwid2	db	'761295520'		; ATI signature #2
atilen2	equ	$-atiwid2
tsngid	db	'Tseng'			; Tseng Labs EVA (& Orchid Designer)
tsnglen	equ	$-tsngid
stbvid	db	'TVGA'			; STB VGA/EM (also Tseng TVGA)
stbvlen	equ	$-stbvid
stavid	db	'4000'			; STB VGA/EM Plus (Tesng 4000)
stavlen equ	$-stavid
evrxid  db      'Everex'                ; Everex Micro Enhancer Deluxe EGA
evrxlen equ     $-evrxid
evgid	db	'VGA EV673'		; Everex EVGA EV-673
evglen	equ	$-evgid
evvid	db	'EV-678'		; Everex Viewpoint EV-678
evvlen	equ	$-evvid
attvdc6	db	'003116'		; AT&T video board, at c000:35h
attvdlen equ	$-attvdc6
attvdc7	db	'C02000'		; AT&T video board, at e000:10h
pmega1	db	'28190-A1001'		; Paradise AutoSwitch EGA Mono String1
pmegal1 equ	$-pmega1		
p30id	db	'VGA'			; VGA Plus, Plus 16, Professional
p30ln	equ	$-p30id			;  and VGA1024 by Paradise
emsrollname db	'KERMIT  ',0		; 8 byte EMS region name, + safety
pageready dw	-1			; ems page currently active
cols80	db	'COLS80.BAT',0		; to 80 column mode batch file
cols132	db	'COLS132.BAT',0		; to 132 column mode batch file
xga_reg_base dw	-1			; PS/2 MCA I/O register base
ega_mode db	0			; non-zero if IBM EGA is in use
tvhere	equ	0feh			; Topview active query
tvsynch	equ	0ffh			; Topview resynch request
tv_segs	dw	0			; Topview virtual screen, segment
tv_sego	dw	0			; and offset
tv_mode	db	0			; flag, 0 = no Topview or DESQview
vs_ptr	dd	0			; offset, segment of vscreen (dynamic)
vsat_ptr dd	0			; offset, segment of vs's attributes
; Note: (vswidth+1)/2 bytes of attributes/line, at two attributes/byte
vswidth	equ	207			; columns across DG virtual screen

; The following are used to turn the display back on (after scrolling etc.)
msets	db	2CH,28H,2DH,29H,2AH,2EH,1EH,29H
dgcurtab db	23,26,24,25		; ANSI to DG cursor converter
dgcrostab db	72,80,77,75		; DG cursor to PC scan for croshair

mtty	db	'  TTY   '		; no terminal type (mode line)
fairness dw	0
fairprn	dw	0
lincur	dw	?			; cursor type save area
dosattr	db	?			; screen attributes at init time
userbold db	0			; screen bold attribute at start up
dos_cols db	0			; screen width (crt_cols) at DOS
oldsp	dw	0			; offset to longjmp to for i/o failure
ten	db	10			; byte constant for key defines
temp	dw	0			; scratch storage
temp2	dw	0			; scratch storage
dmphand	dw	-1			; screen dump file handle
dumpsep	db	0ch,cr,lf		; screen image separators
dmperr	db	' Cannot open file to save screen to disk $'
memerr	db	cr,lf,'Not enough memory for terminal emulator$'
crlf	db	cr,lf,'$'
pntmsg	db	'Printer not ready, printing request skipped$'
upsshlp	db	' User Preferred Supplemental Set:'
	db	cr,lf, 'DEC-MCS, Latin-1, Hebrew-7, Hebrew-ISO$'
apchlp	db	cr,lf,'ON to allow APC cmd from host to invoke commands'
	db	' (default)'
	db	cr,lf,'OFF to prevent all use of APC from the host'
	db	cr,lf,'UNCHECKED to allow any command to be executed$'
enqhlp	db	cr,lf,'ON to permit Answerback to Control-E Enquire request'
	db	' (def=off)$'
; some static data for mode line
modmaster modfrm <>			; master template
unkbaud	db	'unkwn '		; must be 6 chars
baudn	db	' 45.5 ',' 50   ',' 75   ',' 110  ','134.5 ',' 150  ',' 300  '
	db	' 600  ',' 1200 ',' 1800 ',' 2000 ',' 2400 ',' 4800 ',' 9600 '
	db	'14400 ', '19200 ','28800 ', '38400 ','57.6K ','115 K '
	db	'75/12 '
baudnsiz  equ	21			; # of baud rates known (tbl size / 6)
repmsg	db	'REPLAY'		; REPLAY message for speed field
repmsgl	equ	$-repmsg
parnams	db	'even','mark','none','odd ','spc '
lclmsg	db	'loc'
remmsg	db	'rem'
portno	db	0

; storage for multi-window stuff
slen	equ	24			; and length of text
crt_norm db	3			; video mode for normal screen
					
inipara	dw	0			; initial paragraphs of scroll memory
					;  also is number ems pages for same
refresh	db	0			; screen refresh (0=wait for retrace)
vtroll	db	0			; auto roll back allowed (0 = no)
useexp	db	0			; non-zero to use exp mem for rollback
vsbuff_inited db 0			; non-zero if inited screen buffers
setnoshow db	0			; quiet setatch flag

vtkrname db	'KEYBOARDR'		; a macro name, must be Upper Case
vtkrlen	equ	$-vtkrname
vtksname db	'KEYBOARDS'		; a macro name, must be Upper Case
vtkslen	equ	$-vtksname
prodname db	'PRODUCT'
vtplen	equ	$-prodname
vtsesname db	'SESSION'
vtsesnum db	'1'
vtseslen equ	$-vtsesname

vtmacname dw	vtkrname		; pointer to selected macro name
vtmaclen dw	vtkrlen
udkseg	dw	18 dup (0)		; segment of user definable key defs
	even				; screen rollback material
iniseg	dw	?			; (BDT) initial seg of scroll memory
ppl	dw	0			; (BDT) paragraphs per line
lcnt	dw	0			; (BDT) number of "filled" buffer lines
linef	dw	0			; (BDT) "first" filled line is here
linec	dw	0			; (BDT) "current" screen line number
linee	dw	0			; (BDT) total # of lines in the buffer
lmax	dw	0			; (BDT) max lines in buff (less 1 scrn)
lineems	dw	0			; lines per EMS 16KB page frame

tsave	dw	6 dup (0)		; list of term swap paragraphs

					; DG SPCL three stroke Compose key
grab	dw	0			; zero if not grabbing output
grabbox	db	0,0			; store incoming pair of bytes

setchtab db	10			; Set File Character-Set table
	mkeyw	'CP437',437		; hardware default Code Page
	mkeyw	'CP850',850		; Multilingual CP
	mkeyw	'CP852',852		; Latin2 CP
	mkeyw	'CP860',860		; Portuguese CP
	mkeyw	'CP861',861		; Icelandic CP
	mkeyw	'CP862',862		; Hebrew CP
	mkeyw	'CP863',863		; French Canadian CP
	mkeyw	'CP865',865		; Norwegian CP
	mkeyw	'CP866',866		; Latin5/Cryillic CP
	mkeyw	'Shift-JIS',932		; Japanese Shift-JIS
;;	mkeyw	'User-defined',1	; User loadable table

					; begin Terminal emulator data set
termtb	db	tttypes			; entries for Status, not Set
	mkeyw	'VT320',ttvt320
	mkeyw	'VT220',ttvt220
	mkeyw	'VT102',ttvt102
	mkeyw	'VT100',ttvt100
	mkeyw	'VT52',ttvt52
	mkeyw	'Honeywell VIP7809',tthoney
	mkeyw	'Heath-19',ttheath
	mkeyw	'Tek4010',tttek
	mkeyw	'PT200',ttpt200
	mkeyw	'D463',ttd463
	mkeyw	'D470',ttd470
	mkeyw	'none',ttgenrc


vttbl	db	43			; number of entries
	mkeyw	'Answerback',vtenqctl
	mkeyw	'APC-macro',apcctl
	mkeyw	'Arrow-keys',flg11
	mkeyw	'Character-set',vtchar
	mkeyw	'Code-Page',vtcodepage
	mkeyw	'Compressed-text',flg14
	mkeyw	'Controls',flg9
	mkeyw	'Cursor-style',flg7
	mkeyw	'Direction',flg4
	mkeyw	'Expanded-memory',expmemory
	mkeyw	'Horizontal-scroll',flg13
	mkeyw	'Keyclick',flg5
	mkeyw	'Keypad',flg10
	mkeyw	'Margin-bell',flg6
	mkeyw	'Newline',flg1
	mkeyw	'Screen-background',flg8
	mkeyw	'Video-writing',scrwrite
	mkeyw	'Tabstops',tabmod
	mkeyw	'Width',flg12
	mkeyw	'Wrap-lines',flg2

	mkeyw	'Bell',vtbeep
	mkeyw	'Bytesize',vtbyte
	mkeyw	'Clear-screen',vtcls
	mkeyw	'Color',vtcolor
	mkeyw	'Display',vtbyte	; syn for set display 7/8
	mkeyw	'Graphics',vtgraph
	mkeyw	'Replay',replay
	mkeyw	'Rollback',vtrollbk
	mkeyw	'output-shift',vtshift
	mkeyw	'UPSS',vtupss
	mkeyw	'Type',vttype		; SET TERM TYPE
	mkeyw	'None',vttyp0
	mkeyw	'Heath-19',vttyp1
	mkeyw	'VT52',vttyp2
	mkeyw	'VT100',vttyp4
	mkeyw	'VT102',vttyp8
	mkeyw	'VT220',vttyp10
	mkeyw	'VT320',vttyp20
	mkeyw	'Tek4010',vttyp40
	mkeyw	'Honeywell',vttyp80
	mkeyw	'PT200',vttyp100
	mkeyw	'D463',vttyp200
	mkeyw	'D470',vttyp400

ontab	db	2			; two entries
	mkeyw	'off',0
	mkeyw	'on',1

beltab	db	3			; bell type
	mkeyw	'audible',0
	mkeyw	'visual',1
	mkeyw	'none',2

distab	db	2			; display
	mkeyw	'7-bit',0
	mkeyw	'8-bit',d8bit

scrtab	db	2			; screen attributes
	mkeyw	'normal',0
	mkeyw	'reverse',1

dirtab	db	2			; writing direction
	mkeyw	'left-to-right',0
	mkeyw	'right-to-left',1

writetab db	2			; writing
	mkeyw	'direct',0
	mkeyw	'Bios',1

curtab	db	2			; cursor attributes
	mkeyw	'block',0
	mkeyw	'underline',1

apctab	db	3			; three entries
	mkeyw	'off',0
	mkeyw	'on',1
	mkeyw	'unchecked',2
     
chatab	db	24			; National Replacement Character sets
	mkeyw	'ASCII',0		; ASCII is default (0, no NRC)
	mkeyw	'British',1		; start NRC set (1-12)
	mkeyw	'Dutch',2
	mkeyw	'Finnish',3
	mkeyw	'French',4
	mkeyw	'Fr-Canadian',5
	mkeyw	'German',6
	mkeyw	'Hebrew-7',13
	mkeyw	'Italian',7
	mkeyw	'Norwegian/Danish',8
	mkeyw	'Portuguese',9
	mkeyw	'Spanish',10
	mkeyw	'Swedish',11
	mkeyw	'Swiss',12		; end of NRC proper

	mkeyw	'Alternate-ROM',14	; Alternate-ROM character set
	mkeyw	'Transparent',15	; use native display adapter hardware
	mkeyw	'Latin1',16		; Latin-1 in GR
	mkeyw	'Latin2',23		; Latin-2 (will presume CP852)
	mkeyw	'Hebrew-ISO',24		; Hebrew-ISO (presumes CP862)
	mkeyw	'DEC-MCS',17		; DEC Supplemental Graphics in GR
	mkeyw	'DEC-Technical',18
	mkeyw	'DEC-Special',19
	mkeyw	'DG-International',20
	mkeyw	'DG-Line-Drawing',21
	mkeyw	'DG-Word-Processing',22

upsstab	db	4
	mkeyw	'DEC-MCS','5%'			; DEC Supplemental Graphics
	mkeyw	'Latin1','A'			; Latin-1
	mkeyw	'Hebrew-7','4"'			; DEC Hebrew-7
	mkeyw	'Hebrew-ISO','H'		; Hebrew-ISO

sidetab	db	4			; SET TERM CHAR <char set> Gn
	mkeyw	'G0','0'
	mkeyw	'G1','1'
	mkeyw	'G2','2'
	mkeyw	'G3','3'

shifttab db	5			; SET TERM OUTPUT-SHIFT
	mkeyw	'none',0
	mkeyw	'automatic',8
	mkeyw	'SI/SO',1
	mkeyw	'SS2',2
	mkeyw	'SS3',4

graftab	db	12
	mkeyw	'auto-sensing',0	; autosensing
	mkeyw	'CGA',1
	mkeyw	'EGA',2
	mkeyw	'VGA',3
	mkeyw	'Hercules',4
	mkeyw	'ATT',5
	mkeyw	'WyseA(1280x800)',6	; Wyse-700 1280 x 800 mode
	mkeyw	'WyseH(1280x780)',7	; Wyse-700 1280 x 780 mode
	mkeyw	'WyseT(1024x780)',8	; Wyse-700 1024 x 780 mode
	mkeyw	'character-writing',101h
	mkeyw	'color',103h
	mkeyw	'cursor',102h

gchrtab	db	2			; set term graphics char-writing
	mkeyw	'opaque',1
	mkeyw	'transparent',0

disatab	db	2			; Tek disable/enable table
	mkeyw	'disabled',1
	mkeyw	'enabled',0

tabtab	db	2			; label says it all!
	mkeyw	'at',0FFH		; For setting tab stops
	mkeyw	'Clear',0		; For clearing tab stops
     
alltab	db	2			; more tab command decoding
	mkeyw	'all',0
	mkeyw	'at',1

cntltab	db	2			; 8-bit controls
	mkeyw	'7-bit',0
	mkeyw	'8-bit',1

kpamtab	db	2			; keypad, application
	mkeyw	'numeric',0
	mkeyw	'application',1

arrtab	db	2			; cursor keys, application
	mkeyw	'cursor',0
	mkeyw	'application',1

widtab	db	2
	mkeyw	'80-columns',0
	mkeyw	'132-columns',1

hstab	db	2			; horizontal scrolling
	mkeyw	'auto',0
	mkeyw	'manual',1

cmptab	db	2
	mkeyw	'graphics',0
	mkeyw	'text-132',1

colortb	db	0,4,2,6,1,5,3,7		; color reversed-bit setting bytes
clrset	db	0			; Temp for SET Term Tabstops xxx

erms41	db	cr,lf,'?More parameters are needed$'
vthlp	db	' one of the following:',cr,lf
	db	'  TYPE of: None, Heath-19, Honeywell VIP7809, VT52,'
	db	' VT100, VT102, VT220,',cr,lf,'    VT320 (default), Tek4010,'
	db 	' PT200 (Prime), D463 or D470 (Data General)'
	db	cr,lf
	db	'  Newline-mode    Cursor-style        Character-set'
	db 	cr,lf
	db	'  Keyclick        Margin-bell         Screen-background'
	db	' (normal, reverse)',cr,lf
	db '  Tabstops        Wrap (long lines)   Color (fore & background)'
	db	cr,lf,'  Answerback response (on or off, default is off)'
	db	cr,lf,'  APC-macro  (APC cmd from host invokes local cmds)' 
	db	cr,lf,'  Arrow-keys  cursor (normal) or application mode'
	db	cr,lf,'  Bell  audible or visual or none'
	db	cr,lf,'  Clear-screen  (clears old startup screen)'
	db	cr,lf,'  Code-Page (overrides default)'
	db	cr,lf,'  Compressed-text  Graphics or Text-132 (for D463/D470)'
	db	cr,lf,'  Controls 7-bit or 8-bit  (permits VT320 to send'
	db	' 8-bit control sequences (C1))'
	db	cr,lf,'  Direction Left-to-right or Right-to-left'
	db	' (screen writing direction)'
	db	cr,lf,'  Display or Bytesize 7-bit or 8-bit'
	db	cr,lf,'  Expanded-memory (for screen rollback), default on'
	db	cr,lf,'  Graphics  (type of display adapter when in Tek4010'
	db	' mode, and char writing)'
	db	cr,lf,'  Horizontal scrolling, auto (default) or manual'
	db	cr,lf,'  Keypad numeric (normal) or application mode'
	db	cr,lf,'  Output-shift (prefix 8-bit data for 7-bit channel)'
;;;	db 	cr,lf,'  Replay filespec (display a file through the emulator)'
	db	cr,lf,'  Rollback  (undo screen roll back before writing new'
	db	' chars, default=off)'
	db	cr,lf,'  TEK ENABLE or DISABLE (activation by host command)'
	db	cr,lf,'  Width 80 or 132 columns, if the adapter can do it'
	db	cr,lf,'  Video-writing, Direct or via Bios$'
clrhlp	db	' one of the following:'
	db	cr,lf,'  AT #s  (to set tabs at column #s)    or'
	db	' AT start-column:spacing'
	db	cr,lf,'  Clear AT #s (clears individual tabs) or'
	db	' AT start-column:spacing'
	db	cr,lf,'  Clear ALL  (to clear all tabstops)'
clrhlp2	db	cr,lf,'  Ex: Set term tab at 10, 20, 34        sets tabs'
	db	cr,lf,'  Ex: Set term tab at 1:8        sets tabs at 1, 9,'
	db	cr,lf,'  Ex: Set term tab clear at 9, 17, 65   clears tabs'
	db	cr,lf,'  Ex: Set term tab clear at 1:8  clears tabs at 1, 9,'
	db	' 17,...$'
tbserr	db	cr,lf,'?Column number is not in range 1 to screen width-1$'
colhlp	db	cr,lf,'  Set Term Color  value, value, value, ...'
	db	cr,lf,'   0 no-snow mode on an IBM CGA and white on black'
	db	cr,lf,'   1 for high intensity foreground'
	db	cr,lf,'  10 for fast CGA screen updating (may cause snow)'
	db	cr,lf,'  Foreground color (30-37) = 30 + sum of colors'
	db	cr,lf,'  Background color (40-47) = 40 + sum of colors'
	db	cr,lf,'    where colors are  1 = red, 2 = green, 4 = blue'
	db	cr,lf,'  Ex: 0, 1, 37, 44   IBM CGA(0), bright(1) white(37)'
	db	' chars on a blue(44) field'
	db	cr,lf,'  Attributes are applied in order of appearance.$'
colerr	db	cr,lf,'?Value not in range of 0, 1, 10, 30-37, or 40-47$'
expmhlp	db	cr,lf,' Use expanded memory for screen rollback buffer,'
	db	' on or off$'
vtwrap	db	'Term wrap-lines: $'
vtbellm	db	'Term margin-bell: $'
vtnewln db	'Term newline: $'
vtcur	db	'Term cursor-style: $'
vtcset	db	'Term character-set: $'
vtclik	db	'Term key-click: $'
vtscrn	db	'Term screen-background: $'
colst1	db	'Term color  foregnd:3$'
colst2	db	' backgnd:4$'
vtgraf	db	'Term graphics: $'
vtrolst	db	'Term rollback: $'
vtdir	db	'Term direction: $'
vtcntst	db	'Term controls: $'
vtkpst	db	'Term keypad: $'
vtarst	db	'Term arrow-keys: $'
vtbset	db	'Term bell: $'
vtgchst	db	'Term graph char: $'
vtwdst	db	'Term width: $'
vtupsst	db	'Term UPSS: $'
vtshftst db	'Term output-shift: $'
vthscst	db	'Term horizontal-scroll: $'
vtapcst	db	'Term APC-macro: $'
vtenqst db	'Term Answerback: $'
vtwrtst	db	'Term video-writing: $'
vtexpmst db	'Term expanded-memory: $'	
vtcpagest db	'Term Code-Page: $'
vtcmptst db	'Term compressed-text: $'
							; terminal emulator
vtstbl	stent	<srchkw,vtenqst,ontab,vtenqenable>		; Answerback
	stent	<srchkw,vtapcst,apctab,apcenable>		; APC-macro
	stent	<srchkw,vtcset,chatab,vtemu.vtchset>		; char set
	stent	<srchkb,vtclik,ontab,vskeyclick,vtemu.vtflgop>	; keyclick
	stent	<colstat>					; colors
	stent	<srchkb,vtwrap,ontab,vswrap,vtemu.vtflgop>	; line wrap
	stent	<srchkb,vtcntst,cntltab,vscntl,vtemu.vtflgop>	; controls
	stent	<srchkb,vtbellm,ontab,vsmarginbell,vtemu.vtflgop>;margin bell
	stent	<srchkb,vtcur,curtab,vscursor,vtemu.vtflgop>	; cursor type
	stent	<srchkw,vtbset,beltab,belltype>			; bell
	stent	<srchkb,vtdir,dirtab,vswdir,vtemu.vtflgop>	; write direct
	stent	<srchkb,vtnewln,ontab,vsnewline,vtemu.vtflgop>	; newline
	stent	<srchkw,vtgraf,graftab,tekgraf>			; graphics
	stent	<srchkw,vtrolst,ontab,vtroll>			; rollback
	stent	<srchkw,vtgchst,gchrtab,chcontrol>		; chr cntrl
	stent	<srchkb,vtarst,arrtab,decckm,vtemu.vtflgop>	; arrow-keys
	stent	<srchkb,vtscrn,scrtab,vsscreen,vtemu.vtflgop>	; screen 
	stent	<srchkb,vtkpst,kpamtab,deckpam,vtemu.vtflgop>	; keypad
	stent	<srchkb,vtwdst,widtab,deccol,vtemu.vtflgop>	; width
	stent	<srchkww,vtupsst,upsstab,upss+1>		; UPSS
	stent	<srchkw,vtshftst,shifttab,flags.oshift>		; output-shift
	stent	<srchkb,vthscst,hstab,vshscroll,vtemu.vtflgop>	; Horz scroll
	stent	<srchkw,vtwrtst,writetab,writemode>		; Writing
	stent	<srchkw,vtexpmst,ontab,useexp>			; exp mem
	stent	<srchkww,vtcpagest,setchtab,vtcpage>		; Code-Page
	stent	<srchkb,vtcmptst,cmptab,vscompress,vtemu.vtflgop> ; compress

	stent	<tabstat>	; VT320 tab status - needs one whole line
	dw	0		; end of table

vtmacroptr	dd	vtmacro			; FAR pointer
ftogmod		dd	togmod			; FAR pointer
termlatch	db	0		; reentry block for session macros
data	ends

data1	segment
; structures below: byte cnt of combos, dw input combo list, db output list
; using DG International or Latin1 codes for output.
grl1dgi db	48			; case and order insensitive
	dw	'++','AA','((','//','/<','^ ','(-','/^',')-','<<'
	dw	'0^','* ','+-','>>','SS','/U','2^','3^','C/','C|'
	dw	'L-','L=','Y-','Y=','SO','S!','S0','XO','X0','A-'
	dw	'CO','C0','PP','P!','.^','O-','12','!!','??','T-'
	dw	'TM','FF','<=','>=',',-','""',2727h,'RO'
grc1dgi db	'#', '@', '[', '\', '\', '^', '{', '|', '}', 0b1h
	db	0bch,0bch,0b6h,0b0h,0fch,0a3h,0a4h,0a5h,0a7h,0a7h
	db	0a8h,0a8h,0b5h,0b5h,0bbh,0bbh,0bbh,0a6h,0a6h,0a9h
	db	0adh,0adh,0b2h,0b2h,0b9h,0aah,0a2h,0abh,0ach,0afh
	db	0b3h,0b4h,0b7h,0b8h,0a1h,0bdh,0beh, 0aeh

grl1lat db	44			; case and order insensitive
	dw	'<<','0^','* ','+-','>>','SS','/U','2^','3^','C/'
	dw	'C|','L-','L=','Y-','Y=','SO','S!','S0','XO','X0'
	dw	'A-','CO','C0','PP','P!','.^','O-','12','!!','??'
	dw	'TM',',-','""',2727h,'RO','||','--','-^',',,','34'
	dw	'XX','-:','1^','14'
grc1lat db	0abh,0b0h,0b0h,0b1h,0bbh,0dfh,0b5h,0b2h,0b3h,0a2h
	db	0a2h,0a3h,0a3h,0a5h,0a5h,0a7h,0a7h,0a7h,0a4h,0a4h
	db	0aah,0a9h,0a9h,0b6h,0b6h,0b7h,0bah,0bdh,0a1h,0bfh
	db	0aeh,0ach,0a8h,0b4h, 0aeh,0a6h,0adh,0afh,0b8h,0beh
	db	0d7h,0f7h,0b9h,0bch

grl2dgi	db	25			; case sensitive, order insensitive
	dw	'''A','`A','^A','"A','~A','*A','''E','`E','^E','"E'
	dw	'''I','`I','^I','"I','~N','''O','`O','^O','"O','~O'
	dw	'''U','`U','^U','"U','"Y'
grc2dgi	db	0c0h, 0c1h,0c2h,0c3h,0c4h,0c5h,0c8h, 0c9h,0cah,0cbh
	db	0cch, 0cdh,0ceh,0cfh,0d0h, 0d1h,0d2h,0d3h,0d4h,0d5h
	db	0d8h, 0d9h,0dah,0dbh,0ddh

grl2lat	db	25			; case sensitive, order insensitive
	dw	'''A','`A','^A','"A','~A','*A','''E','`E','^E','"E'
	dw	'''I','`I','^I','"I','~N','''O','`O','^O','"O','~O'
	dw	'''U','`U','^U','"U','''Y'
grc2lat	db	0c1h, 0c0h,0c2h,0c4h,0c3h,0c5h,0c9h, 0c8h,0cah,0cbh
	db	0cdh, 0cch,0ceh,0cfh,0d1h, 0d3h,0d2h,0d4h,0d6h,0d5h
	db	0dah, 0d9h,0d8h,0dch,0ddh

grl3dgi db	7			; case and order sensitive
	dw	'EO','AE',',C','/O','ae',',c','/o'
grc3dgi db	0d7h,0c6h,0c7h,0d6h,0e6h,0e7h,0f6h

grl3lat db	10			; case and order sensitive
	dw	'AE',',C','/O','HT','-D','ae',',c','/o','ht','-d'
grc3lat db	0c6h,0c7h,0d8h,0deh,0d0h,0e6h,0e7h,0f8h,0feh,0f0h
data1	ends
						; end of Terminal data set
code1	segment
	extrn	ans52t:far, vsinit:near		; in mszibm
	extrn	anstty:near, ansini:near, ansrei:near	; in mszibm
	extrn	anskbi:near, ansdsl:near	; in mszibm
	extrn	tabset:near, tabclr:near, dgnctoggle:far

fanskbi	proc	far
	call	anskbi				; in mszibm
	ret
fanskbi	endp
ftabset	proc	far
	call	tabset				; in mszibm
	ret
ftabset	endp
ftabclr	proc	far
	call	tabclr				; in mszibm
	ret
ftabclr	endp
code1	ends

code2	segment
	extrn   tekini:far, tekemu:far, tekend:far, tekrint:far ;in msgibm
	extrn	ttxtchr:far, ttxtline:far,teksetcursor:far,tekremcursor:far
	extrn	croshair:far, dgcrossrpt:far
code2	ends

code	segment
	extrn	prtchr:near, outchr:near, sbrk:near, pcwait:near
	extrn	isfile:near
	extrn	msuinit:near, keybd:near, kbhold:near	; in msuibm
	extrn	clrmod:near, putmod:near, cmblnk:near, cptchr:near
	extrn	telnet:near, srchkww:near
	extrn	atoi:near, strlen:near, srchkb:near, srchkw:near, pasz:near
	extrn	prompt:near, comnd:near, statc:near, replay:near
	extrn	crun:near, serini:near, spath:near, strcpy:near, tekdmp:near
	extrn	prttab:near, dec2di:near, tekgcptr:near
	extrn	pntchr:near, pntflsh:near, tcpstart:near, serrst:near
	assume	cs:code, ds:data, es:nothing

; do initialization local to this module
; Dynamically allocates 4000 bytes for screen save/restore buffer plus
;  320 to 38400 bytes for screen scroll back buffers. Tries to leave space
;  for Command.com before enlarging buffers.
lclyini	proc	near
	call	msuinit			; initialize keyboard module msuxxx
	call	far ptr flclyini	; far call specifics
	ret
lclyini	endp

					; begin Terminal set & status code
; SET Term parameters, especially for use with VT100 emulator.
; VTS is called only by mssset to set terminal type and characteristics.
; Exit carry set for failure.
VTS	proc	near			; SET TERM whatever
	mov	kstatus,kssuc		; success
	mov	ah,cmkey		; Parse another keyword
	mov	bx,offset vthlp		; Use this help
	mov	dx,offset vttbl		; Use this table
	call	comnd
	jnc	vset1			; nc = success
	ret				; failure
vset1:	call	bx			; dispatch to processing routine
	ret

vtcls:	mov	ah,cmeol		; Clear-screen
	call	comnd
	jc	vtclsx			; c = failure
	mov	vtclear,2		; set trigger for emulator clear scn
	clc				; success
vtclsx:	ret

					; SET TERM kind
vttyp0:	mov	bx,ttgenrc		; NONE
	jmp	short vsett1
vttyp1:	mov	bx,ttheath		; Heath-19
	jmp	short vsett1
vttyp2:	mov	bx,ttvt52		; VT52
	jmp	short vsett1
vttyp4:	mov	bx,ttvt100		; VT100
	jmp	short vsett1
vttyp8:	mov	bx,ttvt102		; VT102
	jmp	short vsett1
vttyp10:mov	bx,ttvt220		; VT220
	jmp	short vsett1
vttyp20:mov	bx,ttvt320		; VT320
	jmp	short vsett1
vttyp40:mov	bx,tttek		; Tek
	jmp	short vsett1
vttyp80:mov	bx,tthoney		; Honeywell VIP7809
	jmp	short vsett1
vttyp100:mov	bx,ttpt200		; Prime PT200
	jmp	short vsett1
vttyp200:mov	bx,ttd463		; Data General D463
	mov	vtemu.vtchset,0		; setup ASCII as char set in G0
	jmp	short vsett1
vttyp400:mov	bx,ttd470		; Data General D470
	mov	vtemu.vtchset,0		; setup ASCII as char set in G0
	jmp	short vsett1

vttype:	mov	ah,cmkey		; SET TERM TYPE
	xor	bx,bx			; table is help
	mov	dx,offset termtb	; use this table
	call	comnd
	jnc	vsett1			; nc = success
	ret				; failure

vsett1:	mov	temp,bx			; save terminal type
	mov	temp2,-1		; assume no enable/disable Tek
	cmp	bx,tttek		; set term tek?
	jne	vsett2			; ne = no
	mov	dx,offset disatab	; disable/enable keyword table
	xor	bx,bx			; help is the table
	mov	comand.cmcr,1		; allow bare CR's
        mov	ah,cmkey		; get enable/disable keyword
	call	comnd
	mov	comand.cmcr,0		; no more bare CR's
	jc	vsett2			; c = no such keyword
	mov	temp2,bx		; save enable/disable keyword value
	mov	bx,flags.vtflg		; get current terminal type
	mov	temp,bx			; and force it here

vsett2:	mov	ah,cmeol
	call	comnd			; get a confirm
	jc	vsettx			; c = failure
vsett3:	mov	bx,temp
	mov	flags.vtflg,bx		; Set the terminal emulation type
	mov	tekflg,0		; clear graphics mode
	or	vtemu.vtflgst,vscompress+vshscroll ; set compress to text-132
	or	vtemu.vtflgop,vscompress+vshscroll
					; and horz scroll to manual
	cmp	bx,tttek		; adjusting Tek?
	je	vsett4			; e = yes
	test	bx,ttd463+ttd470	; DG D463/470?
	jz	vsett6			; z = no
	and	vtemu.vtflgst,not (vscompress+vshscroll) ; comp = graphics,
	and	vtemu.vtflgop,not (vscompress+vshscroll) ; horz scroll = auto
vsett6:	cmp	temp2,-1		; just enable/disable tek?
	je	vsett5			; e = no
vsett4:	and	denyflg,not tekxflg	; enable Tek
	cmp	temp2,1			; ought we disable?
	jne	vsett5			; ne = no
	or	denyflg,tekxflg		; disable Tek
vsett5:	clc				; success
vsettx:	ret

vtchar: mov	ah,cmkey		; Set Term character set
	xor	bx,bx			; character set table for help 
	mov	temp,bx			; counter of trailing items
	mov	dx,offset chatab	; character set table
	call	comnd
	jc	vtcharx			; c = failure
	mov	decbuf,bl		; save here
	mov	ax,word ptr vtemu.vttable ; table of 4 overrides now
	mov	word ptr decbuf+1,ax	; copy them to temporary table
	mov	ax,word ptr vtemu.vttable+2
	mov	word ptr decbuf+3,ax
vtchar1:mov	comand.cmcr,1		; allow bare CR's
	mov	ah,cmkey
	xor	bx,bx
	mov	dx,offset sidetab	; read Gnumber item, if any
	call	comnd
	mov	comand.cmcr,0		; no bare CR's
	jc	vtchar2			; c = no match, get confirm
	inc	temp			; say have a trailing table number
	and	bx,3			; remove ASCII value encoding
	add	bx,offset decbuf+1	; address of slot to store info
	mov	al,decbuf		; set ident
	mov	[bx],al			; store table ident in G0..G3 slot
	jmp	short vtchar1		; repeat

; vtemu.vtchset:	changed to new set if no table trailers, else intact
; vtemu.vttable	db 4 dup(0ffh)	 char set numbers for G0..G3 as overrides,
;				use 0ffh to mean no override for table Gn
vtchar2:mov	ah,cmeol		; get EOL confirmation
	call	comnd
	jc	vtcharx			; c = failure, quit
	mov	vtemu.vtchop,-1		; say reinit char tables
	cmp	temp,0			; trailers (skip regular setup)?
	jne	vtchar3			; ne = yes
	mov	al,decbuf		; get character set
	mov	vtemu.vtchset,al	; set default character set
					; just overrides
vtchar3:mov	ax,word ptr decbuf+1	; first pair of char set idents
	mov	word ptr vtemu.vttable,ax
	mov	ax,word ptr decbuf+3	; second pair
	mov	word ptr vtemu.vttable+2,ax
	clc
vtcharx:ret

vtshift:mov	ah,cmkey		; Set Term Output-shift auto, none
	xor	bx,bx
	mov	dx,offset shifttab
	call	comnd
	jc	vtcharx			; c = failed
	mov	flags.oshift,bl		; store result
	ret

vtrollbk:mov	ah,cmkey		; Set Term Roll On/Off, auto roll back
	xor	bx,bx			; Use on/off table as help
	mov	dx,offset ontab		; Use on/off table
	call	comnd
	jc	vtrollx			; c = failure
	push	bx
	mov	ah,cmeol		; get a confirm
	call	comnd
	pop	bx
	jc	vtrollx			; c = failure
	mov	vtroll,bl		; set roll state (0=no auto rollback)
	clc
vtrollx:ret

				     ; Set Term Color foreground, background
vtcolor:mov	bx,vtemu.att_ptr	; get address of attributes byte
	mov	bl,[bx]			; get attributes
	mov	decbuf,bl		; save in work temp
	mov	al,vtclear		; screen clear state
	mov	ah,refresh		; refresh state
	mov	word ptr decbuf+1,ax	; save here
	call	vsetcol			; get and analyze colors
	jc	vtcolo1			; c = failure
	mov	al,decbuf		; get current attributes
	mov	bx,vtemu.att_ptr	; get address of attributes byte
	mov	[bx],al			; store attributes
	mov	savattr,al		; saved emulator attributes
	mov	ax,word ptr decbuf+1
	mov	vtclear,al		; update these items
	mov	refresh,ah
	clc
vtcolo1:ret
					; setup color information
vsetcol:mov	ah,cmword		; get number(s) after set term color
	mov	bx,offset colhlp	; use this help
	mov	dx,offset rdbuf		; temp buffer
	mov	rdbuf,0			; clear the buffer
	mov	comand.cmcr,1		; allow bare c/r's
	call	comnd
	jc	vsetco2			; c = failure
	or	ax,ax			; text given?
	jz	vsetco1			; z = no
	mov	si,offset rdbuf		; si = place where atoi wants text
	call	vsetco3			; analyze
	jmp	short vsetcol		; get more data
vsetco1:mov	ah,cmeol		; get end of line confirm
	call	comnd
vsetco2:ret				; c set if failure

vsetco3:mov	dx,si
	call	strlen			; get count for atoi
	mov	ah,cl			; count for atoi
	call	atoi			; convert text to numeric in ax
	jnc	vsetco3a		; got a value
	clc
	ret				; out of data
vsetco3a:or	ax,ax			; reset all? regular IBM CGA refresh
	jnz	vsetco4			; nz = no
	mov	decbuf+2,0		; Regular (slow) screen refresh
	mov	decbuf,07h		; clear all, set white on black
	mov	decbuf+1,2		; set trigger for emulator clear scrn
	jmp	short vsetco3

vsetco4:cmp	ax,1			; high intensity?
	jne	vsetco5			; e = no
	or	decbuf,08h		; set high intensity
	mov	decbuf+1,1		; set trigger for emulator keep screen
	jmp	short vsetco3

vsetco5:cmp	ax,10			; fast refresh?
	jne	vsetco6			; ne = no
	mov	decbuf+2,1		; Fast screen refresh
	jmp	short vsetco3

vsetco6:cmp	ax,30			; check range
	jb	vsetco8			; b = too small, complain
	cmp	ax,37
	ja	vsetco7			; 30-37 is foreground color
	sub	al,30			; remove foreground bias
	and	decbuf,not 07H		; clear foreground bits
	mov	bx,ax
	mov	al,colortb[bx]		; get reversed bit pattern
	or	decbuf,al		; load new bits
	mov	decbuf+1,2		; set trigger for emulator clear scn
	jmp	short vsetco3

vsetco7:cmp	ax,40
	jb	vsetco8			; b = bad value
	cmp	ax,47			; compare as unsigned
	ja	vsetco8			; 40-47 is background
	sub	al,40			; remove background bias
	and	decbuf,not 70H		; clear background bits
	mov	bx,ax
	mov	al,colortb[bx]		; get reversed bit pattern
	mov	cl,4			; rotate 4 positions
	rol	al,cl
	or	decbuf,al		; load new bits
	mov	decbuf+1,2		; set trigger for emulator clear scn
	jmp	vsetco3

vsetco8:mov	ah,prstr		; not in range - complain and exit
	mov	dx,offset colerr
	int	dos
	mov	kstatus,ksgen		; general failure
	stc				; error
	ret
	     

vtgraph:mov	ah,cmkey		; Set Term graphics
	xor	bx,bx			; Use graphics table as help
	mov	dx,offset graftab	; Use graphics table
	call	comnd
	jc	vtgrapx			; c = failure
	cmp	bx,100h			; in the special options area?
	ja	vtgrap1			; a = yes
	push	bx
	mov	ah,cmeol		; get a confirm
	call	comnd
	pop	bx
	jc	vtgrapx			; c = failure
	mov	tekgraf,bl		; set Tek graphics board type
	clc
vtgrapx:ret
vtgrap1:cmp	bx,101h			; character writing?
	jne	vtgrap2			; ne = no
	mov	ah,cmkey		; Set Term graphics char-writing
	xor	bx,bx			; no help
	mov	dx,offset gchrtab	; opaque/transparent table
	call	comnd
	jc	vtgrapx			; c = failure
	push	bx
	mov	ah,cmeol		; get a confirm
	call	comnd
	pop	bx
	jc	vtgrapx
	mov	chcontrol,bl		; set/reset opaque char control
	clc
	ret
vtgrap2:cmp	bx,102h			; cursor on/off?
	jne	vtgrap4			; ne = no
	mov	ah,cmkey		; Set Term graphics cursor on/off
	xor	bx,bx			; no help
	mov	dx,offset ontab		; on/off table
	call	comnd
	jc	vtgrapx			; c = failure
	push	bx
	mov	ah,cmeol		; get a confirm
	call	comnd
	pop	bx
	jc	vtgrapx
	mov	tekcursor,bl		; set Tek text cursor on/off
	clc
	ret

vtgrap4:cmp	bx,103h			; Color?
	jne	vtgrap6			; ne = no
	call	tekgcptr		; get pointer to active Tek color pal
	mov	al,[bx]			; get background attributes
	and	al,7			; discard intensity bit
	mov	cl,4
	shl	al,cl
	mov	ah,[bx+7]		; get foreground attributes
	or	al,ah
	mov	decbuf,al		; setup work temp for vsetcol
	push	bx			; save index
	call	vsetcol			; get and analyze colors
	pop	bx
	jnc	vtgrap5			; nc = ok
	ret
vtgrap5:mov	al,decbuf		; get current attributes
	mov	ah,al			; get background bits
	mov	cl,4
	shr	ah,cl			; just background here
	and	al,0fh			; just foreground here
	mov	[bx],ah			; store colpal[0] as background
	mov	[bx+7],al		; store colpal[7] as foreground
	clc				; success
vtgrap6:ret
	
vtbeep:	mov	ah,cmkey		; SET TERM BELL
	xor	bx,bx			; use table as help
	mov	dx,offset beltab	; use Bell table
	call	comnd
	jc	vtbeepx			; c = failure
	push	bx
	mov	ah,cmeol		; get a confirm
	call	comnd
	pop	bx
	jc	vtbeepx			; c = failure
	mov	belltype,bl		; set bell type
vtbeepx:ret				; return carry clear or set

					; SET TERM BYTESIZE {7-bit | 8-bit}
vtbyte:	mov	ah,cmkey		; SET TERM DISPLAY {7-bit | 8-bit}
	mov	dx,offset distab	; table
	xor	bx,bx			; help is table
	call	comnd
	jc	vtbytex			; c = failure
	push	bx
	mov	ah,cmeol		; get a confirm
	call	comnd
	pop	bx
	jc	vtbytex			; c = failure
	and	flags.remflg,not d8bit	; clear display 8-bit bit
	or	flags.remflg,bl		; set or clear the bit
vtbytex:ret

vtupss:	mov	ah,cmkey		; SET TERM UPSS
	mov	bx,offset upsshlp	; help
	mov	dx,offset upsstab	; UPSS table
	call	comnd			; get UPSS char set
	jc	vtupssx			; failure
	push	bx
	mov	ah,cmeol
	call	comnd
	pop	bx
	jc	vtupssx			; c = fail
	mov	al,96			; assume 96 byte set
	or	bh,bh			; one byte set identifier?
	jz	vtupss1			; z = yes
	mov	al,94			; a 94 byte set
vtupss1:mov	upss,al			; set length
	mov	word ptr upss+1,bx	; store set ident
	mov	vtemu.vtchop,-1		; clear operational char set to reinit
	clc
vtupssx:ret

apcctl:	mov	ah,cmkey		; SET TERM APC-macro enable, disable
	mov	bx,offset apchlp	; help
	mov	dx,offset apctab	; APC table
	call	comnd
	jc	apcctl1			; failure
	push	bx
	mov	ah,cmeol
	call	comnd
	pop	bx
	jc	apcctl1			; c = fail
	mov	apcenable,bl		; enable flag
	clc
apcctl1:ret

vtenqctl:mov	ah,cmkey		; SET TERM Answerback {ON, OFF}
	mov	bx,offset enqhlp	; help
	mov	dx,offset ontab		; on/off table
	call	comnd
	jc	vtenqctl1		; failure
	push	bx
	mov	ah,cmeol
	call	comnd
	pop	bx
	jc	vtenqctl1		; c = fail
	mov	vtenqenable,bl		; enable (1) flag
	clc
vtenqctl1:ret

scrwrite:mov	ah,cmkey		; SET TERM SCREEN-WRITING
	xor	bx,bx			; help
	mov	dx,offset writetab	; screen table
	call	comnd
	jc	scrwritx		; failure
	push	bx
	mov	ah,cmeol
	call	comnd
	pop	bx
	jc	vtupssx			; c = fail
	mov	writemode,bl		; store writing mode
	clc
scrwritx:ret

expmemory:mov	ah,cmkey		; EXPANDED-MEMORY {ON, OFF}
	mov	bx,offset expmhlp	; help
	mov	dx,offset ontab		; on/off table
	call	comnd
	jc	expmem2			; failure
	push	bx
	mov	ah,cmeol
	call	comnd
	pop	bx
	jc	expmem2			; c = fail
	cmp	useexp,bl		; changing kinds?
	je	expmem1			; e = no
	mov	vsbuff_inited,0		; say reinitialize buffer memory
	mov	useexp,bl		; enable (1) flag
expmem1:clc
expmem2:ret

vtcodepage:mov	ah,cmkey		; SET TERM CODE-PAGE
	xor	bx,bx			; help
	mov	dx,offset setchtab	; Code Page table
	call	comnd
	jc	vtcode1			; failure
	push	bx
	mov	ah,cmeol
	call	comnd
	pop	bx
	jc	vtcode1			; c = fail
	mov	vtcpage,bx		; new terminal Code Page
	mov	vtemu.vtchop,-1		; force change of working set
	clc
vtcode1:ret

; SET Term flags. These are the (near) equivalent of VT100 Setup mode values.
flg1:	mov	ax,vsnewline		; NEWLINE
	mov	dx,offset ontab
	jmp	short flgset
flg2:	mov	ax,vswrap		; WRAP
	mov	dx,offset ontab
	jmp	short flgset
flg4:	mov	ax,vswdir		; DIRECTION
	mov	dx,offset dirtab
	jmp	short flgset
flg5:	mov	ax,vskeyclick		; KEYCLICK
	mov	dx,offset ontab
	jmp	short flgset
flg6:	mov	ax,vsmarginbell		; MARGIN BELL
	mov	dx,offset ontab
	jmp	short flgset
flg7:	mov	ax,vscursor		; CURSOR
	mov	dx,offset curtab
	jmp	short flgset
flg8:	mov	ax,vsscreen		; SCREEN
	mov	dx,offset scrtab
	jmp	short flgset
flg9:	mov	ax,vscntl		; CONTROLS
	mov	dx,offset cntltab
	jmp	short flgset
flg10:	mov	ax,deckpam		; KEYPAD
	mov	dx,offset kpamtab
	jmp	short flgset
flg11:	mov	ax,decckm		; ARROW
	mov	dx,offset arrtab
	jmp	short flgset
flg12:	mov	ax,deccol		; WIDTH
	mov	dx,offset widtab
	jmp	short flgset
flg13:	mov	ax,vshscroll		; Horizontal scrolling
	mov	dx,offset hstab
	jmp	short flgset
flg14:	mov	ax,vscompress		; compressed text display
	mov	dx,offset cmptab
;;	jmp	short flgset

flgset:	push	ax			; save flag
	mov	ah,cmkey		; another keyword
	xor	bx,bx			; use default help, dx has table ptr
	call	comnd
	pop	ax			; recover index
	jc	flgse0			; c = failure
	push	ax
	push	bx			; save result of keyword
	mov	ah,cmeol		; get confirm
	call	comnd
	pop	bx
	pop	ax			; recover flag
	jc	flgse0			; c = failure
	or	bx,bx			; set or clear?
	jz	flgse1			; z = clear it
	or	vtemu.vtflgst,ax	; set the flag
	or	vtemu.vtflgop,ax	; in runtime flags too
flgse3:	test	ax,deccol		; modifying screen width?
	jz	flgse2			; z = no
	mov	al,crt_cols		; current width
	mov	dos_cols,al		; width to remember, for changes
flgse2:	clc				; success
flgse0:	ret     
flgse1: not	ax			; Complement
	and	vtemu.vtflgst,ax	; clear the indicated setup flag
	and	vtemu.vtflgop,ax	; clear the indicated runtime flag
	not	ax
	jmp	short flgse3		; test for screen change
     
;	SET Term Tabstops Clear ALL
;	SET Term Tabstops Clear AT n1, n2, ..., nx
;	SET Term Tabstops At n1, n2, ..., nx
     
tabmod:	mov	ah,cmkey		; parse keyword
	mov	bx,offset clrhlp	; help text
	mov	dx,offset tabtab	; table
	call	comnd
	jc	tabmo2			; c = failure
	mov	clrset,2		; 2 = code for set a tab
	or	bl,bl			; clear?
	jnz	tabmo4			; nz = no, SET. parse column number(s)
	mov	clrset,1		; code for clear at/all tab(s)
	mov	ah,cmkey		; CLEAR, parse ALL or AT
	mov	bx,offset clrhlp	; help text
	mov	dx,offset alltab	; parse ALL or AT
	call	comnd
	jc	tabmo2			; c = failure
	or	bx,bx			; ALL?
	jnz	tabmo4			; nz = AT, clear at specific places
	mov	ah,cmeol		; confirm the ALL
	call	comnd
	jc	tabmo2			; c = failure
	mov	cx,vswidth		; ALL, means clear all tab stops
tabmo1:	mov	dx,cx
	dec	dl			; column number, starting with 0
	mov	si,vtemu.vttbs		; the cold-start buffer
	call	ftabclr			; clear the tab
	loop	tabmo1			; do all columns
	mov	si,vtemu.vttbs
	mov	di,vtemu.vttbst		; and active buffer
	call	tabcpy			; update active tabs
	clc				; success
tabmo2:	ret				; a success/fail return point

tabmo4:	mov	si,vtemu.vttbs		; from the cold-start buffer
	mov	di,offset decbuf	; temp work buffer
	call	tabcpy			; make a working copy of the tabs
	mov	skip,0			; clear spacing-active flag
	mov	temp,0			; place where last tab was written
tabmo6:	mov	bx,offset clrhlp2	; tell them we want a column number
	mov	ah,cmword		; get line of text
	mov	dx,offset rdbuf		; temp buffer
	call	comnd
	jc	tabmo2			; c = failure
	or	ax,ax			; anything given?
	jnz	tabmo7			; nz = yes
	mov	ah,cmeol		; confirm end of line
	call	comnd
	jc	tabmo2			; failure
	mov	si,offset decbuf	; copy tabs from temp work buffer
	mov	di,vtemu.vttbs		; to the cold-start buffer
	call	tabcpy			; copy work to cold start
	mov	di,vtemu.vttbst		; and terminal emulator's active buf
	call	tabcpy
	clc
	ret

tbsbad:	mov	ah,prstr		; not in range - complain
	mov	dx,offset tbserr
	int	dos
	stc
	ret
     
tabmo7:	mov	si,offset rdbuf		; si = place where atoi wants text
tabmo8:	mov	dx,si
	call	strlen			; get length of this word
	jcxz	tabmo6			; empty, get more user input
	mov	ah,cl			; where atoi wants length
	call	atoi			; convert text to numeric in ax
	jnc	tabmo9			; nc = successful
	cmp	byte ptr [si],':'	; spacing separator?
	jne	tbsbad			; ne = no, no number available
	inc	si			; skip colon, do start:space analysis
	inc	skip			; set spacing-active flag
	jmp	short tabmo8		; get another token

tabmo9:	cmp	skip,0			; want spacing value now?
	jne	tabmo11			; ne = yes, go do it
	mov	dx,ax			; column (1-vswidth style)
	dec	dx			; put column in range 0-131
	or	dx,dx			; check range (1-vswidth-->0-...)
	js	tbsbad			; s = too small. complain
	cmp	dl,vswidth-1		; more than the right most column?
	ja	tbsbad			; a = yes, quit
	mov	temp,dx			; remember last written position
	jmp	tabmo15			; and write this member

tabmo11:mov	dx,temp			; continue spacing analysis
	mov	skip,0			; clear spacing-active flag
	mov	cx,ax			; "space" value
	or	cx,cx			; zero spacing?
	jnz	tabmo12			; nz = no
	inc	cx			; don't get caught with zero spacing
tabmo12:cmp	dx,vswidth-1		; largest tab stop
	ja	tabmo8			; a = done largest tab stop
	mov	temp,dx			; remember last written tabstop
	push	si
	mov	si,offset decbuf	; the work buffer
	cmp	clrset,2		; set?
	jne	tabmo13			; ne = no, clear
	call	ftabset			; set tabstop in column DL
	jmp	short tabmo14
tabmo13:call	ftabclr			; clear tabstop in column DL
tabmo14:add	dx,cx			; new column value
	pop	si
	jmp	short tabmo12		; finish spacing loop

tabmo15:push	si			; individual tabstop
	mov	si,offset decbuf	; the work buffer
	cmp	clrset,2		; set?
	jne	tabmo16			; ne = no, clear
	call	ftabset			; set tabstop in column DL
	jmp	short tabmo17		; get next command value
tabmo16:call	ftabclr			; clear tabstop in column DL
tabmo17:pop	si
	jmp	tabmo8			; get next command value

tabcpy:	push	es			; worker copy routine
	push	si
	push	di
	mov	cx,ds
	mov	es,cx
	mov	cx,(vswidth+7)/8	; update all active tab stops
	cld
	rep	movsb
	pop	di
	pop	si
	pop	es
	clc				; success
	ret
VTS	endp				; end of Set Term things

	      ; Terminal Status display, called within STAT0: in MSSSET
VTSTAT	proc	near			; enter with di within sttbuf, save bx
	mov	bx,offset vtstbl	; table of things to show
	jmp	statc			; status common code, in mssset
vtstat	endp

colstat proc	near			; worker for colstat
	push	si
	mov	si,offset colst1
	cld
colstd1:lodsb
	cmp	al,'$'			; end of string?
	je	colstd2			; e = yes
	stosb
	jmp	short colstd1
colstd2:mov	bx,vtemu.att_ptr	; pointer to attributes byte
	mov	bl,byte ptr[bx]
	xor	bh,bh
	push	bx
	and	bx,7			; get foreground set
	mov	al,colortb[bx]		; get reversed bit pattern
	add	al,'0'			; add ascii bias
	stosb
	pop	bx
	mov	si,offset colst2
colstd3:lodsb
	cmp	al,'$'
	je	colstd4
	stosb
	jmp	short colstd3
colstd4:mov	cl,4			; rotate 4 positions
	shr	bl,cl
	and	bx,7			; get background set
	mov	al,colortb[bx]		; get reversed bit pattern
	add	al,'0'			; add ascii bias
	stosb
	pop	si
	ret
colstat endp

tabstat proc	near			; worker,display tabs ruler for Status
	push	dx
	cld
	mov	al,cr
	stosb
	cmp	cl,10			; are we on a new line?
	jb	tabsta0			; b = no, do a lf now
	mov	al,lf
	stosb
tabsta0:xor	cl,cl			; column index
	xor	ax,ax			; ah = tens, al = units counter
tabsta1:mov	dl,'.'			; default position symbol
	inc	al
	cmp	al,10			; time to roll over?
	jb	tabsta2			; b = not yet
	xor	al,al			; modulo 10
	inc	ah
	mov	dl,ah			; display a tens-digit
	add	dl,'0'
	cmp	dl,'9'			; larger than 90?
	jbe	tabsta2			; be = no
	sub	dl,10			; roll over to 0, 1, etc
tabsta2:push	dx
	push	si
	mov	dl,cl			; column number, counted from 0
	mov	si,vtemu.vttbst		; the active buffer
	call	istabs			; is tab set here?
	pop	si
	pop	dx
	jnc	tabsta3			; nc = no
	mov	dl,'T'			; yes, display a 'T'
tabsta3:push	ax
	mov	al,dl
	stosb
	pop	ax
	inc	cl
	cmp	cl,byte ptr low_rgt	; done yet?
	jb	tabsta1			; b = not yet
	pop	dx
	ret
tabstat endp

; Returns carry set if column in DL is a tab stop, else carry clear.
; Enter with column number in DL (starts at column 0, max of vswidth-1)
; and tabstop buffer offset in SI.
istabs	proc	near
	push	bx
	push	cx
	mov	cl,dl			; column number (0 to swidth-1)
	and	cl,00000111b		; keep bit in byte (0-7)
	inc	cl			; map to 1-8
	mov	bl,dl			; column
	shr	bl,1			; bl / 8 to get byte
	shr	bl,1
	shr	bl,1
	xor	bh,bh			; clear high byte
	mov	bl,[si+bx]		; get a byte of tab bits
	ror	bl,cl			; rotate to put tab-set bit into carry
	pop	cx
	pop	bx
	ret
istabs	endp

filler	proc	near			; use space
	mov	cx,20
	mov	al,' '
	cld
	rep	stosb
	ret
filler	endp

; Jump here to exit Connect mode and execute macros 'KEYBOARDR' (vtkrmac) or
; 'KEYBOARDS' (vtksmac). Does nothing if macro does not exist.
; Preserves registers except ax. Returns to TELNET caller with 'C' in kbdflg.
vtkrmac	proc	near			; RESET macro
	mov	vtmacname,offset vtkrname ; select macro name
	mov	vtmaclen,vtkrlen	; and its length
	call	dword ptr vtmacroptr	; FAR pointer, finish in common code
	jc	vtkrmac1		; c = failure
	jmp	far ptr endcon		; end connect mode, do macro
vtkrmac1:ret
vtkrmac	endp

vtksmac	proc	near			; SET macro
	mov	vtmacname,offset vtksname
	mov	vtmaclen,vtkslen
	call	dword ptr vtmacroptr	; FAR pointer
	jc	vtksmac1		; c = failure
	jmp	far ptr endcon		; end connect mode, do macro
vtksmac1:ret
vtksmac	endp

; Invoked by keyboard translator when an unknown keyboard verb is used as
; a string definition, such as {\ktest}. Enter with vtmacname pointing to
; uppercased verb name, asciiz, and vtmaclen set to its length.
extmacro proc	near
	call	dword ptr vtmacroptr	; FAR pointer
	jc	extmac1			; c = failure
	jmp	far ptr endcon		; end connect mode, do macro
extmac1:ret
extmacro endp

; Invokes macro PRODUCT with variables \%1..\%9
; defined as the ascii renditions of the control sequence numeric paramters
; param[0]..param[8], and sets script ARGC item to one greater than this.

product	proc	near
	call	far ptr prodwork	; FAR pointer
	jc	prodmac1		; c = failure
	jmp	far ptr endcon		; end connect mode, do macro
prodmac1:ret
product	endp

				; support for vtmacro and fproduct
fdec2di	proc	far
	call	dec2di
	ret
fdec2di	endp

term	proc	near
	call	far ptr fterm
	ret
term	endp

fclrmod	proc	far
	call	clrmod
	ret
fclrmod	endp

fputmod	proc	far
	call	putmod
	ret
fputmod	endp

fcmblnk	proc	far
	call	cmblnk
	ret
fcmblnk	endp
fkbhold	proc	far
	call	kbhold
	ret
fkbhold	endp
fisfile	proc	far
	call	isfile
	ret
fisfile	endp
fprtchr	proc	far
	call	prtchr
	ret
fprtchr	endp
fkeybd	proc	far
	call	keybd
	ret
fkeybd	endp
fpntflsh proc	far
	call	pntflsh
	ret
fpntflsh endp
fpntchr	proc	far
	call	pntchr
	ret
fpntchr	endp
foutchr	proc	far
	call	outchr
	ret
foutchr	endp
fpcwait	proc	far
	call	pcwait
	ret
fpcwait	endp
fstrcpy	proc	far
	call	strcpy
	ret
fstrcpy	endp
fspath	proc	far
	call	spath
	ret
fspath	endp
fcrun	proc	far
	call	crun
	ret
fcrun	endp
fserini	proc	far
	call	serini
	ret
fserini	endp
vtinit	proc	near
	call	fvtinit
	ret
vtinit	endp

rtone	proc	near
	call	frtone
	ret
rtone	endp

rtpage	proc	near
	call	frtpage
	ret
rtpage	endp

lfone	proc	near
	call	flfone
	ret
lfone	endp

lfpage	proc	near
	call	flfpage
	ret
lfpage	endp

homwnd	proc	near
	call	fhomwnd
	ret
homwnd	endp
endwnd	proc	near
	call	fendwnd
	ret
endwnd	endp
dnwpg	proc	near
	call	fdnwpg
	ret
dnwpg	endp
dnone	proc	near
	call	fdnone
	ret
dnone	endp
upwpg	proc	near
	call	fupwpg
	ret
upwpg	endp
upone	proc	near
	call	fupone
	ret
upone	endp
fcptchr	proc	far
	call	cptchr
	ret
fcptchr	endp
fserrst	proc	far
	call	serrst
	ret
fserrst	endp
code	ends

code1	segment
	assume	cs:code1
					; Kermit startup time initialization
flclyini proc	far
	mov	ah,conout		; write a space to determine
	mov	dl,' '			; DOS's default cursor coloring
	int	dos
	call	getpcur			; get current cursor position into dx
	mov	lincur,cx		; save cursor type (scan line #'s)
	dec	dl			; backup to last char
	or	dl,dl
	jns	lclyin5			; ns = no problem
	xor	dl,dl			; else set cursor back to left margin
lclyin5:call	setpcur			; set the cursor
	call	getpcha			; read current attributes into AH
	mov	scbattr,ah		; save video attributes
	mov	savattr,ah		; and saved attributes
	mov	dosattr,ah		; and here too
	and	ah,att_bold		; select intensity bit
	mov	userbold,ah		; save bit for user Bold control
	mov	ega_mode,0		; assume no EGA
	mov	ax,1200H		; EGA: Bios alternate select
	mov	bl,10H			; Ask for EGA info
	mov	bh,0ffH			; Bad info, for testing
	mov	cl,0fH			; Reserved switch settings
	int	screen			; EGA, are you there?
	cmp	cl,0cH			; Test reserved switch settings
	jge	lclyin1			; ge = no EGA in use
	push	es
	mov	ax,40h			; check Bios 40:87h for ega being
	mov	es,ax			;  the active display adapter
	test	byte ptr es:[87h],8	; is ega active?
	pop	es
	jnz	lclyin1			; nz = no
	mov	ega_mode,1		; yes, set flag to say so
	mov	crt_norm,3		; assume color monitor is attached
	or	bh,bh			; is color mode in effect?
	jz	lclyin1			; z = yes
	mov	crt_norm,7		; else use mode 7 for mono
lclyin1:call	scrseg			; test running in an Environment
	call	dvtest			; test for running under DESQview
	call	scrmod			; read video state, get crt_mode
	mov	cursor,0		; initial cursor
	mov	dosetcursor,-1		; cursor position reminder, none
	mov	ax,low_rgt		; lower right corner of screen
	mov	al,crt_mode
	mov	crt_norm,al		; save as normal mode
	mov	ah,crt_cols
	mov	dos_cols,ah		; remember for exiting Connect mode
	call	vsalloc			; allocate memory for virtual screen
	jnc	lclyin4			; nc = success
	mov	ah,prstr
	mov	dx,offset memerr	; say not enough memory to operate
	int	dos
	mov	flags.extflg,1		; set Kermit exit flag
	ret

lclyin4:call	vsinit			; init terminal emulator module MSZ
	mov	bx,vtemu.att_ptr	; attributes pointer
	mov	ah,dosattr		; startup video attributes
	and	ah,not att_bold		; emulation intensity to normal
	or	ah,userbold
	mov	[bx],ah			; set initial emulation attributes
	and	vtemu.vtflgst,not deccol ; assume 80 column screen
	and	vtemu.vtflgop,not deccol
	cmp	crt_cols,80		; screen cols now, wide screen?
	jbe	lclyin6			; be = no
	or	vtemu.vtflgst,deccol	; say using 132 columns screen
	or	vtemu.vtflgop,deccol
lclyin6:ret
flclyini endp

; Allocate memory for virtual screen buffers vscreen and vsat.
; Return carry clear if success, else carry set. Removes older allocations.
vsalloc	proc	near
	call	vsalloc4		; free alloc'd memory, if any
	mov	al,crt_lins		; one minus number of screen rows
	inc	al
	mov	cl,vswidth		; virtual screen vscreen
	mul	cl			; lines time width, words for vscreen
	add	ax,ax			; need words
	add	ax,15			; round up
	mov	cl,4			; convert to paragraphs
	shr	ax,cl			; need words rather than bytes
	mov	cx,ax			; save total wanted paragraphs in cx
	mov	bx,ax			; ask for the memory
	mov	ah,alloc		; allocate memory
	int	dos			; bx has # free paragraphs
	mov	word ptr vs_ptr+2,ax	; seg of vsscreen (offset is zero)
	cmp	cx,bx			; got what we wanted
	jb	vsalloc5		; b = no
	push	es
	mov	es,ax
	xor	di,di
	shl	cx,1
	shl	cx,1
	shl	cx,1			; paragraphs to words
	mov	ah,scbattr
	mov	al,' '
	cld
	rep	stosw 			; clear the memory with def colors
	pop	es
	mov	al,crt_lins
	inc	al			; attributes (nibbles)
	mov	cl,(vswidth+1)/2	; lines time width, bytes for vsattr
	mul	cl
	add	ax,15			; round up
	mov	cl,4			; convert to paragraphs
	shr	ax,cl
	mov	cx,ax			; save total wanted paragraphs in cx
	mov	bx,ax			; ask for the memory
	mov	ah,alloc		; allocate the memory
	int	dos			; bx has # free paragraphs
	mov	word ptr vsat_ptr+2,ax	; seg of vsattr (offset is zero)
	cmp	cx,bx			; got what we wanted
	jb	vsalloc4		; b = no
	push	es
	mov	es,ax
	xor	di,di
	shl	cx,1
	shl	cx,1
	shl	cx,1
	shl	cx,1			; paragraphs to bytes
	xor	al,al
	rep	stosb 			; clear the memory with def extattr
	pop	es
	clc				; report success
	ret

vsalloc4:mov	ax,word ptr vsat_ptr+2	; seg of vsattr (offset is zero)
	or	ax,ax			; unused?
	jz	vsalloc5		; z = yes
	push	es
	mov	es,ax			; allocated segment
	mov	ah,freemem		; free it
	int	dos
	mov	word ptr vsat_ptr+2,0	; clear pointer too
	pop	es
vsalloc5:mov	ax,word ptr vs_ptr+2	; seg of vsscreen
	or	ax,ax			; unused?
	jz	vsalloc6		; z = yes
	push	es
	mov	es,ax			; allocated segment
	mov	ah,freemem		; free it
	int	dos
	mov	word ptr vs_ptr+2,0	; clear pointer too
	pop	es
vsalloc6:stc				; return failure
	ret
vsalloc	endp

; Allocate memory for screen rollback buffers.
; Return carry clear if success, else carry set to exit.
vsbuff	proc	near			; screen roll back buffers
	cmp	vsbuff_inited,0		; inited yet?
	je	vsbuff0			; e = no
	clc				; say success
	ret
vsbuff0:mov	vsbuff_inited,1		; say we are initializing
	cmp	emsrbhandle,-1		; valide EMS rollback handle?
	je	vsbuff20		; e = no
	mov	ah,emsrelease		; release pages
	mov	dx,emsrbhandle		; handle
	int	emsint
	mov	emsrbhandle,-1		; invalidate EMS rollback handle
	mov	iniseg,0		; and no segment for page frame
	jmp	short vsbuff21
vsbuff20:mov	ax,iniseg		; memory segment, window area
	or	ax,ax			; anything allocated?
	jz	vsbuff21		; z = no
	mov	es,ax
	mov	ah,freemem		; free regular memory segment
	int	dos
	mov	iniseg,0
vsbuff21:
	mov	bx,rollwidth		; columns to roll back
	or	bx,bx			; user override given?
	jnz	vsbuff1			; nz = yes, else physical screen
	mov	bl,crt_cols		; physical screen
	xor	bh,bh
	mov	rollwidth,bx		; set final roll width
vsbuff1:add	bx,7			; round up (cancel common times twos)
	mov	cl,3
	shr	bx,cl			; bytes/line to paragraphs/line
	mov	ppl,bx			; paragraphs/line
					; expanded memory
	cmp	useexp,0		; use expanded memory?
	je	vsbuff5			; e = no
	mov	ax,sp			; do push sp test for XT vs AT/386
	push	sp			; XT pushes sp-2, AT's push old sp
	pop	cx			; recover pushed value, clean stack
	xor	ax,cx			; same?
	jne	vsbuff5			; ne = no, XT. Don't do Int 2fh
	mov	ax,xmspresent		; XMS presence test
	int	2fh
	cmp	al,80h			; present?
	jne	vsbuff5			; ne = no
	mov	ah,getintv		; get interrupt vector
	mov	al,emsint		; EMS interrupt 67h
	int	dos			; to es:bx
	mov	ax,es
	or	ax,bx			; check for null
	jz	vsbuff5			; z = interrupt not activated
	mov	ah,emsmgrstat		; LIM 3.2 manager status
	int	emsint
	or	ah,ah			; ok?
	jnz	vsbuff5			; nz = not ok
	mov	ax,1024			; 1024 paragraphs per ems 16KB page
	xor	dx,dx
	div	ppl			; divide by paragraphs per line
	mov	lineems,ax		; lines per ems page, remember
	mov	al,crt_lins		; lines-1 per physical screen
	xor	ah,ah
	mov	cx,npages		; number of roll back screens wanted
	inc	cx			; include current screen
	mul	cx			; times number screens
	div	lineems			; lines total / (lines/emspage)
	or	dx,dx			; remainder?
	jz	vsbuff2			; z = no
	inc	ax			; add page for fraction
vsbuff2:push	ax			;  ax is number of emspages
	mov	ah,emsgetnpgs		; get number pages free
	int	emsint			; to bx
	pop	ax
	or	bx,bx			; any pages free?
	jz	vsbuff5			; z = no, use regular memory
	cmp	bx,ax			; enough?
	jb	vsbuff3			; b = less, use what we can get
	mov	bx,ax			; number of pages wanted
vsbuff3:mov	ah,emsalloc		; allocate bx pages
	int	emsint
	or	ah,ah			; successful?
	jnz	vsbuff5			; nz = no, failure
	mov	emsrbhandle,dx		; returned handle
	mov	ax,bx			; pages allocated
	mov	inipara,ax		; save for later resizing of buffers
	mov	ah,emsgetseg		; get segment of page frame
	int	emsint			;  to bx
	mov	iniseg,bx		; save here
	mov	ah,emsgetver		; get EMS version number
	int	emsint			; to al (high=major, low=minor)
	cmp	al,40h			; at least LIM 4.0?
	jb	vsbuff4			; b = no, so no name for our area
	mov	si,offset emsrollname	; point to name for rollback area
	mov	di,offset emsrollname+6	; add digits
	mov	dx,emsrbhandle
	mov	ax,dx
	call	fdec2di			; write to handle name
	mov	ax,emssetname		; set name for handle from ds:si
	int	emsint
vsbuff4:jmp	short vsbuff9
					; no ems, so use regular memory
vsbuff5:mov	useexp,0		; say no ems
	mov	bx,0ffffh		; ask for all of memory, to get size
	mov	ah,alloc		; allocate all of memory (must fail)
	int	dos			; bx has # free paragraphs
	mov	ax,bx			; ax has copy of number free paragraphs
	sub	bx,26000D/16		; space for Command.com copy #2
	jc	vsbuff7			; c = not enough for it
	mov	ax,ppl			; paragraphs / line
	mul	crt_lins		; times lines-1 on physical screen
	cmp	bx,ax			; minimum roll back space left over?
	jbe	vsbuff7			; be = not even that much
	mov	cx,npages		; number of roll back screens wanted
	inc	cx			; include current screen
	mul	cx			; total number of paragraphs wanted
	mov	cx,ax			; save in cx
	or	dx,dx			; want more than 1 MB of real memory?
	jz	vsbuff6			; e = no
	mov	cx,0ffffh		; set all of real memory
vsbuff6:cmp	bx,cx			; got vs wanted paras for roll back
	jbe	vsbuff8			; be = enough but not more than needed
	mov	bx,cx			; limit to our actual needs
	jmp	short vsbuff8		; ask for all we really want
vsbuff7:xor	bx,bx			; use no space at all
	mov	cx,bx			; remember this new request
vsbuff8:mov	ah,alloc
	int	dos
	mov	iniseg,ax		; (BDT) memory segment, window area
	mov	inipara,bx		; save for later resizing of buffers
	cmp	cx,bx			; paragraphs wanted vs delivered
	jae	vsbuff9			; ae = enough
	mov	ah,prstr
	mov	dx,offset memerr	; say not enough memory to operate
	int	dos
	stc				; carry set = fail
	ret
vsbuff9:call	bufadj 			; set roll back buffer parameters
	clc				; carry clear for success
	ret
vsbuff	endp

scrini	proc	far			; init screen stuff
	mov	al,crt_lins		; screen lines - 1 
	mov	ah,crt_mode		; preserve this too
	push	ax			; save
	call	scrmod			; get screen mode now
	mov	ax,100h			; assume 80 column mode, no-renter
	test	vtemu.vtflgop,deccol	; supposed to be in 80 col?
	jz	scrin5			; z = yes
	inc	al			; say want 132 cols
scrin5:	call	chgdsp			; set to 80/132 columns
	call	scrmod			; get crt_lins again
	pop	ax
	mov	crt_mode,ah		; restore in case in graphics now
	cmp	al,crt_lins		; changed?
	je	scrin2			; e = no
	mov	vtinited,0		; say must reinit emulator
	mov	cursor,0
	call	vsalloc			; reallocate virtual screen
	jnc	scrin2			; nc = success
	mov	ah,prstr
	mov	dx,offset memerr	; say not enough memory to operate
	int	dos
	mov	sp,oldsp
	ret				; must be Far return
	
scrin2:	mov	ega_mode,0		; assume no EGA
	mov	ax,1200H		; EGA: Bios alternate select
	mov	bl,10H			; Ask for EGA info
	mov	bh,0ffH			; Bad info, for testing
	mov	cl,0fH			; Reserved switch settings
	int	screen			; EGA, are you there?
	cmp	cl,0cH			; Test reserved switch settings
	jge	scrin1			; ge = no EGA in use
	push	es
	mov	ax,40h			; check Bios 40:87h for ega being
	mov	es,ax			;  the active display adapter
	test	byte ptr es:[87h],8	; is ega active?
	pop	es
	jnz	scrin1			; nz = no
	mov	ega_mode,1		; yes, set flag to say so
	mov	crt_norm,3		; assume color monitor is attached
	or	bh,bh			; is color mode in effect?
	jz	scrin1			; z = yes
	mov	crt_norm,7		; else use mode 7 for mono
scrin1:	mov	bx,vtemu.att_ptr	; attributes pointer
	mov	ah,[bx]
	and	ah,att_bold
	mov	userbold,ah		; remember old bold
	mov	ah,savattr		; saved emulator attributes
	mov	scbattr,ah		; restore active value
	call	scrseg			; update screen segment tv_seg(s/o)
	call	getpcur			; get cursor position DX and type CX
	cmp	flags.vtflg,0		; emulating anything?
	jne	scrin4			; ne = yes
	mov	cursor,dx		; use physical cursor
scrin4:	mov	dx,cursor		; use old cursor, if any
	call	setpos			; set cursor position
	cmp	vtinited,inited		; inited emulator yet?
	je	scrin11			; e = yes, do reinit
	call	fvtinit			; init it now
	call	repaint			; repaint screen
	ret

scrin11:cmp	flags.vtflg,tttek	; Tek mode?
	je	scrin12			; e = yes
;;	test	tekflg,tek_tek+tek_dec 	; Tek submode?
;;	jz	scrin14			; z = no
	cmp	tekflg,tek_tek+tek_dec 	; Tek submode?
	jne	scrin14			; ne = no
scrin12:call	tekini			; init graphics mode
	ret

scrin14:call	ansrei			; reinit the emulator
	call	repaint			; restore screen from vscreen
scrin15:ret
scrini	endp

; Initialize terminal emulators
fvtinit	proc	far
	mov	ax,apcstring		; seg of apcmacro memory area
	or	ax,ax			; empty?
	jz	vtini4			; z = yes
	mov	es,ax
	mov	ah,freemem
	int	dos			; free that memory
	mov	apcstring,0
vtini4:	mov	holdscr,0		; clear holdscreen
	mov	vtclear,0		; clear clear-screen indicator
	call	fkbhold			; tell DEC LK250 the state, in msuibm
	or	vtinited,inited
	mov	ax,vtemu.vtflgst	; Setup flags
	mov	vtemu.vtflgop,ax	; to operational
	mov	dosetcursor,0		; cursor position reminder, none
	mov	bx,portval
	mov	dl,[bx].ecoflg		; local echo flag
	and	yflags,not lclecho
	or	yflags,dl
	mov	bx,argadr		; address of argument block
	mov	dl,[bx].baudb		; baud rate code in dl
	mov	dh,[bx].parity		; parity code in bits
	mov	cl,4			; 0-3 of dh
	shl	dh,cl
	or	dh,07H			; just say 7 data bits
	test	flags.remflg,d8bit	; eight bit display?
	jz	vtini1			; z = no
	inc	dh			; set low four bits to value 8
vtini1:	cmp	flags.vtflg,0		; doing emulation?
	je	vtini3			; e = no
	cmp	tekflg,tek_active+tek_tek ; Tek graphics mode?
	je	vtini2			; e = yes, do it's reinit
	cmp	tekflg,tek_active+tek_dec ; Tek graphics submode?
	je	vtini2			; e = yes, do it's reinit
	xor	ax,ax			; assume 80 col mode (al=0)
	test	vtemu.vtflgst,deccol	; want wide display?
	jz	vtini1a			; z = no
	inc	al			; set AL to 1 for set 132 col mode
vtini1a:call	chgdsp			; set screen width
	call	ansini			; call startup routine in mszibm
	cmp	flags.vtflg,tttek	; full Tek mode?
	jne	vtinix			; ne = no
	or	tekflg,tek_tek		; say tek mode
	jmp	short vtini2		; e = yes
vtinix:	clc
	ret
vtini2:	call	tekrint			; reinitialize Tek emulator
	clc
	ret
vtini3:	call	fcmblnk			; clear the screen
	clc
	ret
fvtinit	endp

argini	proc	near			; read passed arguments
	mov	bx,argadr		; base of argument block
	mov	al,[bx].flgs		; get flags
	and	al,capt+emheath+trnctl+lclecho+modoff
	mov	yflags,al		; mask for allowable and save
	mov	al,[bx].prt
	mov	portno,al		; update port number
	ret
argini	endp

fterm	proc	FAR			; terminal mode entry point
	mov	argadr,ax		; save argument ptr
	mov	oldsp,sp		; remember stack for i/o failure,
	mov	apctrap,0		; un-trap certain commands
	cmp	flags.comflg,'t'	; doing internal Telnet?
	jne	fterm2			; ne = not Telnet
	cmp	termlatch,0		; have we been here for macro?
	jne	fterm2			; ne = yes, reset it and skip macro
	mov	termlatch,1		; arm reentry bypass
	mov	bx,sescur		; get session to bl
	call	vtsesmac		; this returns us to the Kermit prompt
	jc	fterm2			; c = no such macro
fterm1:	call	fserrst			; shut down serial port now
	mov	kbdflg,'C' 		; say exit Connect mode
	ret				; return, to process macro

fterm2:	mov	termlatch,0		; disable bypass, enable macro again
	mov	handhsc,0		; cancel hand scrolling
	call	vsbuff			; allocate screen buffer memory
	jc	fterm1			; c = failure, quit now
	call	argini			; init options from arg address
	mov	inemulator,1		; say in terminal emulator (local)
	call	scrini			; call screen setup
	mov	grab,0			; clear Compose/Spcl output grabber
	or	kbcodes,80h		; set need-to-init flg for kbd xtlator
	mov	fairprn,0		; set printer buffer flush counter
lp:	call	fprtchr			; char at port?
	jnc	short lpinp		; nc = yes, go handle
	cmp	tekflg,tek_active+tek_sg ; special graphics active?
	jne	lpcross			; ne = no, stay in idle loop
	mov	dx,dosetcursor		; preserved cursor position
	cmp	dx,-1			; should we set the cursor?
	je	lpcursor		; e = no
	call	teksetcursor		; set the cursor at dx
	mov	dosetcursor,-1		; turn off reminder

lpcursor:test	flags.vtflg,ttd463+ttd470 ; doing DG D463/D470 emulation?
	jz	lpcross			; z = not DG
	cmp	dgcross,0		; is DG crosshair active?
	je	lpcross			; e = no
	xor	al,al			; feed it a null command, to do mouse
	call	croshair		; call Tek crosshair to read mouse
lpcross:push	bx
	mov	bx,portval		; port structure address
	cmp	[bx].portrdy,0		; is port ready for business?
	pop	bx
	jne	lpkbd			; ne = ready
	jmp	quit			; end the communications now
lpkbd:	mov	fairness,0		; say kbd was examined
	call	dvpause			; tell DESQview we are not busy
	inc	fairprn			; inc printer dump counter
	cmp	fairprn,100		; been here enough times now?
	jb	lpkbd1			; b = no
	call	fpntflsh		; flush printer buffer
	jnc	lpkbd0			; nc = success
	call	pntdead			; call bad printer notifier
lpkbd0:	mov	fairprn,0		; reset for next time
lpkbd1:	call	fkeybd			; call keyboard translator in msu
	jc	quit			; carry set = quit connect mode
	jmp	short lp		; and repeat idle loop

lpinp:	and	al,parmsk		; apply 8/7 bit parity mask
	call	outtty			; print on terminal
	inc	fairness		; say read port but not kbd, again
	cmp	fairness,100		; this many port reads before kbd?
	jb	lp			; b = no, read port again
	jmp	short lpkbd		; yes, let user have a chance too

quit:	mov	sp,oldsp		; recover startup stack pointer
					; TERM caller's return address is now
					; on the top of stack. A longjmp.
	mov	ah,scbattr		; current emulator attributes
	mov	savattr,ah		; save them here
	call	fpntflsh		; flush printer buffer
	call    tekend			; cleanup Tektronix mode

	mov	inemulator,0		; say not in terminal emulator (local)
	mov	al,1
	call	csrtype			; turn on underline cursor
	mov	ah,dosattr		; attributes at init time
	mov	scbattr,ah		; background = original state
	call	fclrmod			; clear mode line with DOS attributes
	mov	ax,100h			; assume using 80 col screen
	cmp	dos_cols,80		; startup screen width
	jbe	quit1			; be = assume 80 columns
	inc	al			; say do 132 columns
quit1:
	push	vtemu.vtflgop
	or	vtemu.vtflgop,vscompress ; turn off compressed mode
	call	chgdsp			; reset display width to startup
	pop	vtemu.vtflgop
	call	scrmod			; update size info
					; for ega in non-standard # lines
	test	tv_mode,10h		; DV active?
	jnz	quit2			; nz = yes, it messes with the cursor
	cmp	ega_mode,0		; ega board active?
	je	quit2			; e = no
	cmp	byte ptr low_rgt+1,23	; is screen standard length?
	je	quit2			; e = yes, so regular cursor set is ok
	push	es			; turn off ega cursor emulation
	mov	ax,40h			; byte 40:87H is ega Info byte
	mov	es,ax
	push	es:[87h]		; save info byte around call
	or	byte ptr es:[87h],1	; set emulation off (low bit = 1)
	mov	cx,lincur		; cursor shape to set
	mov	ah,1			; set the shape
	int	screen			;   back to starting value
	pop	es:[87h]		; recover original Info byte
	pop	es			; and our work reg
	jmp	short quit3		; skip regular mode cursor setting
quit2:					; for regular sized screen
	mov	cx,lincur		; cursor type at startup
	mov	ah,1
	int	screen			; restore cursor type
quit3: 	mov	dh,byte ptr low_rgt+1	; bottom line -1
	xor	dl,dl			; left most column
	call	setpcur			; set cursor physical position
	mov	al,yflags
	mov	bx,argadr
	mov	[bx].flgs,al		; update flags in arg block
	call	dvpause			; tell DESQview we are not busy
	ret
fterm	endp

; put the character in al to the screen
outtty	proc	near
	test	flags.remflg,d8bit	; keep 8 bits for displays?
	jnz	outtt1			; nz = yes, 8 bits if possible
	and	al,7fh			; remove high bit
outtt1:	cmp	flags.vtflg,0		; emulating a terminal?
	je	outnp10			; e = no
	cmp	vtroll,0		; auto roll back allowed?
	je	outem1			; e = no, leave screen as is
	test	tekflg,tek_active	; Tek mode active?
	jnz	outem1			; nz = yes, skip screen rolling
	push	ax			; (BDT) save this for a tad
	mov	ax,linec		; (BDT) are we at the buffer end?
	cmp	ax,lcnt
	pop	ax			; (BDT) restore the register
        je      outem1			; (BDT) e = yes
	push	ax			; (BDT) save AX again
	call	fendwnd			; do END to roll screen to end of buf
	pop	ax			; (BDT) restore the register
outem1:	test	tekflg,tek_active	; graphics mode active?
	jz	outem2			; z = no
	test	tekflg,tek_tek+tek_dec	; Tek submode active for input?
	jnz	outem3			; nz = yes, use Tek emulator
outem2:	call	anstty			; call terminal emulator, char in AL
	ret
outem3:	call	tekemu			; use Tek emulator and return
	ret
     					; use DOS for screen output
outnp10:test	flags.remflg,d8bit	; keep 8 bits for displays?
	jnz	outnp9			; nz = yes, 8 bits if possible
	and	al,7fh			; remove high bit
outnp9:	cmp	rxtable+256,0		; translation turned off?
	je	outnp7			; e = yes, no translation
	push	bx
	mov	bx,offset rxtable	; address of translate table
	xlatb				; new char is in al
	pop	bx
outnp7:	test	anspflg,prtscr		; should we be printing?
	jz	outnp8			; no, keep going
	call	fpntchr			; queue char for printer
	jnc	outnp8			; nc = successful print
	push	ax
	call	vtbell			; else make a noise and
	call	ftrnprs			;  turn off printing
	pop	ax
outnp8:	test	yflags,capt		; capturing output?
	jz	outnp6			; no, forget this part
	call	fcptchr			; give it captured character
outnp6:	test	yflags,trnctl		; debug? if so use Bios tty mode
	jz	outnp4			; z = no
	mov	ah,conout		; DOS screen write
	cmp	al,7fh			; Ascii Del char or greater?
	jb	outnp1			; b = no
	je	outnp0			; e = Del char
	push	ax			; save the char
	mov	dl,7eh			; output a tilde for 8th bit
	int	dos
	pop	ax			; restore char
	and	al,7fh			; strip high bit
outnp0:	cmp	al,7fh			; is char now a DEL?
	jne	outnp1			; ne = no
	and	al,3fH			; strip next highest bit (Del --> '?')
	jmp	outnp2			; send, preceded by caret
outnp1:	cmp	al,' '			; control char?
	jae	outnp3			; ae = no
	add	al,'A'-1		; make visible
outnp2:	push	ax			; save char
	mov	dl,5eh			; caret
	int	dos			; display it
	pop	ax			; recover the non-printable char
outnp3:	push	ax
	mov	dl,al
	int	dos
	pop	ax
	ret
outnp4:	cmp	al,bell			; bell (Control G)?
	jne	outnp5			; ne = no
	jmp	vtbell			; use short beep, avoid char loss
outnp5:	mov	dl,al			; write without intervention
	mov	ah,conout
	int	dos			; else let dos display char
	ret
outtty	endp
     
;[IU2] Here to output an unsigned 8-bit number (in al) to the port
; Used by terminal emulator escape sequence output.
     
prtnout proc	near
	jmp	short prtno2		; ensure at least a zero
     
prtno1: or	al,al
	jnz	prtno2			; nz = yes, do more digits
	ret				; no, return from recursive call
prtno2: xor	ah,ah			; clear previous remainder
	mov	bl,10			; output in base 10
	div	bl			; divide off a digit
	push	ax			; push remainder (in ah) on stack
	call	prtno1			; recurse
	pop	ax			; pop off a digit
	add	ah,'0'			; make it ASCII
	mov	al,ah			; send to port, in ah
	call	outprt
	jc	prtno3			; failure, end connection
	ret
prtno3:	jmp	far ptr endcon
prtnout endp

; Send the character in al out to the serial port; handle echoing.
; Can send an 8 bit char while displaying only 7 bits locally.
outprt	proc	near
	mov	ah,1			; say local echo is permitted
	jmp	short outprt0

prtbout:xor	ah,ah			; no local echo

outprt0:cmp	grab,0			; grabbing output?
	je	outprt0a		; e = no
	call	fgrabber		; yes, give it to the guy
	ret
outprt0a:test	al,80h			; high bit set?
	jz	outpr2			; z = no
	test	flags.vtflg,ttd463+ttd470 ; Data General?
	jz	outprt4			; z = no
	test	flags.remflg,d8bit	; chop DG high bit?
	jnz	outpr2			; nz = no, send as-is
	and	al,7fh			; chop high bit
	jmp	short outpr1		; send with possible DG SI/SO brackets

outprt4:cmp	al,0a0h			; C1 area?
	jae	outpr1			; ae = no
	test	vtemu.vtflgop,vscntl	; sending 8-bit controls?
	jz	outprt5			; z = no, force use of 7-bit controls
	cmp	parmsk,7fh		; using parity?
	jne	outpr2			; ne = no, no need to force on that
outprt5:push	ax			; save char
	mov	al,Escape		; C1 as ESCAPE <char-40h>
	call	outpr2			; send ESCAPE
	pop	ax			; recover char
	sub	al,40h			; relocate the code
	jmp	short outpr2		; send the char
					; GRight printable characters
outpr1:	cmp	flags.vtflg,ttgenrc	; doing term type of NONE?
	je	outpr2			; e = yes, no tables (maybe SO/SI?)
	cmp	parmsk,7fh		; using parity?
	jne	outpr2			; ne = no, no shifts needed
	cmp	flags.oshift,0		; allowing shifts on output?
	je	outpr2			; e = no
	and	al,not 80h		; strip high bit
	test	flags.oshift,8		; Auto?
	jnz	outpr1a			; nz = yes
	test	flags.oshift,1		; force SI/SO?
	jnz	outpr8			; nz = yes
	jmp	short outpr1b		; else SS2/SS3
outpr1a:cmp	GRptr,offset G1set	; GR points to G1 char set?
	je	outpr8			; e = yes, use SO/char/SI
outpr1b:push	ax			; save char
	mov	al,Escape		; send SS2 as ESC N
	call	outpr2			; ESC N is Single Shift 2
	mov	al,'N'
	cmp	flags.oshift,4		; force SS3?
	jb	outpr7			; b = force SS2
	je	outpr1c			; e = force SS3
	cmp	GRptr,offset G2set	; GR points to G2 char set?
	je	outpr7			; e = yes, else use SS3 (ESC P)
outpr1c:inc	al			; use ESC P for Single Shift 3
outpr7:	call	outpr2
	pop	ax			; recover char
	jmp	short outpr2

outpr8:	push	ax			; save char
	mov	al,SOchar		; SO locking shift 1 for G1 to GL
	cmp	flags.vtflg,ttd463+ttd470 ; D463/D470?
	jz	outpr8a			; z = no
	mov	al,DGescape		; send SO as DG's  RS N
	call	outpr2
	mov	al,'N'
outpr8a:call	outpr2			; send it
	pop	ax
	push	ax			; preserve ah around call
	call	outpr2			; send real character (7 bit'd)
	pop	ax
	mov	al,SIchar		; shift back to normal
	test	flags.vtflg,ttd463+ttd470 ; D463/D470?
	jz	outpr2			; z = no
	mov	al,DGescape		; send SI as DG's  RS O
	call	outpr2
	mov	al,'O'

outpr2:	or	ah,ah			; local echo permitted?
	jz	outpr3			; z = no
	test	yflags,lclecho		; echoing?
	jz	outpr3			; z = no, forget it
	push	ax			; save char
	call	outtty			; display it
	pop	ax			; restore
	cmp	flags.comflg,'t'	; doing Telnet?
	jne	outpr3			; ne = no
	cmp	al,CR			; sending CR?
	jne	outpr3			; ne = no
	push	ax
	mov	al,LF			; locally show LF which we will send
	call	outtty
	pop	ax
outpr3:	mov	ah,al			; this is where outchr expects it
	call	foutchr			; output to the port
	jc	outpr4			; c = failure
	ret
outpr4:	jmp	far ptr endcon		; failure, end connection
outprt	endp

fansdsl	proc	far
	call	ansdsl
	ret
fansdsl	endp

foutprt	proc	far
	call	outprt
	ret
foutprt	endp

fprtbout proc	far
	call	prtbout
	ret
fprtbout endp

fprtnout proc	far
	call	prtnout
	ret
fprtnout endp

; Product macro worker
prodwork proc	far
	push	si
	push	di
	push	es
	mov	ax,ds
	mov	es,ax
	mov	di,offset decbuf+2	; macro def buffer starts here
	mov	si,offset prodname	; pointer to macro name
	mov	cx,vtplen		; length of macro name
	cld
	rep	movsb			; copy to rdbuf+2
	mov	byte ptr [di],0		; null terminator
	mov	cx,nparam		; number of parameters
	cmp	cx,9			; more than 9?
	jle	produc1			; le = no
	mov	cx,9			; limit to 9
produc1:jcxz	produc3			; z = none
	xor	bx,bx			; parameter subscript
produc2:push	bx
	push	cx
	mov	al,' '			; and a space separator
	stosb
	shl	bx,1			; address words
	mov	ax,param[bx]		; get parameter to use as definition
	call	fdec2di			; convert numerics to ascii string
	pop	cx
	pop	bx
	inc	bx
	loop	produc2
produc3:xor	al,al			; safety terminator
	mov	[di],al			; don't count in length
	mov	ax,di
	sub	ax,offset decbuf + 2	; compute length
	mov	vtmaclen,ax		; pass along to vtmacro
	mov	vtmacname,offset decbuf+2 ; say this is our macro text ptr
	pop	si
	pop	di
	pop	es
	jmp	short vtmacro
prodwork endp

;
; Reference	Macro structure for	db	number of entries (mac names)
;  is file	 table mcctab	   |->	dw	length of macroname
;  mssset.asm		each entry |-> 	db	'macroname'
;  where these			   |->	dw	segment:0 of definition string
;  are stored.					  (offset part is always 0)	
;		Definition string in 	db	length of <string with null>
;		 buffer macbuf	  	db	'string with trailing null'
;
vtmacro	proc	far			; common code for macros vtsmac,vtrmac
	push	bx			; and Product
	push	cx
	push	si
	push	di
	push	es
	mov	ax,ds
	mov	es,ax
	mov	di,offset decbuf+2	; macro def buffer starts here
	mov	si,vtmacname		; pointer to macro name
	mov	cx,vtmaclen		; length of macro name<sp/null>text
	mov	[di-2],cx		; counted string field
	cld
	rep	movsb			; copy to rdbuf
	mov	byte ptr [di],0		; null terminator
	mov	si,offset decbuf+2	; look for name-text separator
	mov	cx,vtmaclen
vtmac1:	lodsb
	cmp	al,' '			; space separator?
	je	vtmac1a			; e = yes, stop here
	or	al,al			; null terminator?
	jz	vtmac1a			; e = yes, stop here
	loop	vtmac1
	inc	si			; to do null length correctly
vtmac1a:sub	si,offset decbuf+2+1	; compute length of macro name
	mov	cx,si
	mov	vtmaclen,cx		; save a macro name length
					; check for existence of macro
	mov	bx,offset mcctab	; table of macro names
	mov	cl,[bx]			; number of names in table
	xor	ch,ch
	jcxz	vtmacx			; z = empty table, do nothing
	inc	bx			; point to length of first name
vtmac2:	mov	ax,[bx]			; length of this name
	cmp	ax,vtmaclen		; length same as desired keyword?
	jne	vtmac3			; ne = no, search again
	mov	si,bx
	add	si,2			; point at first char of name
	push	cx			; save name counter
	push	di			; save reg
	mov	cx,vtmaclen		; length of name
	mov	di,vtmacname		; point at desired macro name
	push	es			; save reg
	push	ds
	pop	es			; make es use data segment
	cld
	repe	cmpsb			; match strings
	pop	es			; need current si below
	pop	cx
	pop	di			; recover saved regs
	je	vtmac4			; e = matched
vtmac3:	add	bx,ax			; step to next name, add name length
	add	bx,4			; + count and def word ptr
	loop	vtmac2			; try next name
vtmacx:	pop	es
	pop	di
	pop	si			; no macro, return to Connect mode
	pop	cx
	pop	bx
	stc				; say failure
	ret

vtmac4:	cmp	taklev,maxtak		; room in Take level?
	jge	vtmacx			; ge = no, exit with no action
	inc	taklev			; increment take level
	add	takadr,size takinfo	; make a new Take entry/macro
	mov	bx,takadr		; point to current macro structure
	mov	ax,ds			; segment of rdbuf
	mov	[bx].takbuf,ax		; segment of definition string struc
	mov	cx,word ptr decbuf	; length of count + string
	mov	[bx].takcnt,cx		; number of chars in definition
	mov	[bx].takargc,0		; our argument count
	mov	[bx].takptr,offset decbuf+2 ; where to read next command char
	mov	[bx].taktyp,0ffh	; flag as a macro
	pop	es
	pop	di
	pop	si
	pop	cx
	pop	bx
	clc				; say success, can exit connect mode
	ret
vtmacro	endp

; APC macro
apcmacro proc	near
	cmp	taklev,maxtak		; room in take level?
	jb	apcmac1			; b = yes
	stc				; fail
	ret
apcmac1:inc	taklev			; increment take level
	add	takadr,size takinfo	; make a new Take entry/macro
	mov	bx,takadr		; point to current macro structure
	mov	ax,apcstring		; segment of buffer
	mov	[bx].takbuf,ax		; segment of definition string struc
	mov	[bx].takcnt,cx		; number of chars in definition
	mov	[bx].takargc,0		; our argument count
	mov	[bx].takptr,0 		; where to read next command char
	mov	[bx].taktyp,0ffh	; flag as a macro
	cmp	apcenable,2		; enable all commands?
	je	apcmac2			; e = yes
	mov	apctrap,1		; trap certain commands
apcmac2:jmp	far ptr endcon		; exit Connect mode cleanly
apcmacro endp

; Error recovery routine used when outchr reports unable to send character
;  or when vtmacro requests exiting Connect mode.
; Exit Connect mode cleanly, despite layers of intermediate calls.
endcon	proc	FAR
	mov	kbdflg,'C'		; report 'C' to TERM's caller
	mov	sp,oldsp		; recover startup stack pointer
					; TERM caller's return address is now
					; on the top of stack. A longjmp.
	jmp	quit			; exit Connect mode cleanly
endcon	endp
code1	ends

code	segment
	assume	cs:code
;;; Action routines (verbs) for keyboard translator KEYBD in msuibm.
; These are invoked by a jump instruction. Return carry clear for normal
; processing, return carry set for invoking Quit (kbdflg has transfer char).
uparrw:	mov	al,'A'			; cursor keys
	jmp	short comarr
dnarrw:	mov	al,'B'
	jmp	short comarr
rtarr:	mov	al,'C'
	test	vtemu.vtflgop,vswdir	; writing left to right?
	jz	comarr			; z = yes
	mov	al,'D'			; reverse sense of keys
	jmp	short comarr
lfarr:	mov	al,'D'
	test	vtemu.vtflgop,vswdir	; writing left to right?
	jz	comarr			; z = yes
	mov	al,'C'			; reverse sense of keys

comarr:	test	flags.vtflg,ttd463+ttd470 ; DG D463/D470?
	jz	comar4			; z = no
	sub	al,'A'			; translate to DG 463/470 form
	cmp	tekflg,tek_active+tek_sg ; in special graphics mode?
	jne	comar5			; ne = no
	test	dgcross,1		; DG crosshair active?
	jz	comar5			; z = no
	test	dgcross,2		; DG crosshair active for keypad?
	jz	comar5			; z = no
	mov	bx,offset dgcrostab	; use scan code table instead
	xlatb
	call	croshair		; send AL to graphics to move cursor
	ret

comar5:	mov	bx,offset dgcurtab	; VT to DG cursor code table
	xlatb
	push	ax			; setup for comar3
	jmp	short comar3

comar4:	push	ax			; save final char
	mov	ttyact,0		; network, group chars for packet
	test	vtemu.vtflgop,decanm	; ANSI mode?
	jz	comar2			; z = no
	mov	al,CSI			; CSI character
	test	vtemu.vtflgop,decckm	; cursor keys in application mode?
	jz	comar1			; z = no, in cursor mode
	mov	al,SS3			; SS3 character
comar1:	call	foutprt			; send in 7 or 8 bit form, with echo
	jmp	short comar3

comar2:	mov	al,escape		; do Heath/VT52 mode "ESC char"
	call	foutprt
comar3: pop	ax			; recover final char
	mov	ttyact,1		; network, restore tty active flag
	call	foutprt
	ret

pf1:	mov	al,'P'			; keypad function keys PF1-4
	jmp	short compf
pf2:	mov	al,'Q'
	jmp	short compf
pf3:	mov	al,'R'
	jmp	short compf
pf4:	mov	al,'S'
compf:	push	ax			; save final char
	mov	ttyact,0		; network, group chars for packet
	test	vtemu.vtflgop,decanm	; ansi mode?
	jz	short compf1		; z = no
	mov	al,SS3
	call	foutprt			; send 7 or 8 bit version
	jmp	short compf2
compf1:	mov	al,escape		; output ESC
	call	foutprt
compf2: pop	ax			; get the saved char
	mov	ttyact,1		; network, restore tty active flag
	call	foutprt
	ret

ignore_key:				; key is to be ignored
	ret

kp0:	mov	al,'p'			; keypad numeric keys
	jmp	short comkp
kp1:	mov	al,'q'
	jmp	short comkp
kp2:	mov	al,'r'
	jmp	short comkp
kp3:	mov	al,'s'
	jmp	short comkp
kp4:	mov	al,'t'
	jmp	short comkp
kp5:	mov	al,'u'
	jmp	short comkp
kp6:	mov	al,'v'
	jmp	short comkp
kp7:	mov	al,'w'
	jmp	short comkp
kp8:	mov	al,'x'
	jmp	short comkp
kp9:	mov	al,'y'
	jmp	short comkp
kpminus:mov	al,'m'
	jmp	short comkp
kpcoma:	mov	al,'l'
	jmp	short comkp
kpenter:mov	al,'M'
	jmp	short comkp
kpdot:	mov	al,'n'
comkp:	test	vtemu.vtflgop,deckpam	; keypad application mode active?
	jnz	comkp1			; nz = yes, use escape sequences
	sub	al,40h			; deduct offset to numeric symbols
	push	ax			; save final char
	jmp	short comkp3		; and send that single char
comkp1:	push	ax
	mov	ttyact,0		; network, group chars for packet
	test	vtemu.vtflgop,decanm	; ANSI mode?
	jz	comkp2			; z = no
	mov	al,SS3			; SS3 character
	call	foutprt			; send 7 or 8 bit version
	jmp	short comkp3
comkp2:	mov	al,escape		; output "ESC ?"
	call	foutprt
	mov	al,'?'
	call	foutprt
comkp3:	pop	ax			; recover final char
	mov	ttyact,1		; network, restore tty active flag
	call	foutprt			; send it
	ret

klogon	proc	near			; resume logging (if any)
	test	flags.capflg,logses	; session logging enabled?
	jz	klogn			; z = no, forget it
	push	bx
	mov	bx,argadr
	or	[bx].flgs,capt		; turn on capture flag
	pop	bx
	or	yflags,capt		; set local msy flag as well
klogn:	clc
	ret
klogon	endp

klogof	proc	near			; suspend logging (if any)
	push	bx
	mov	bx,argadr
	and	[bx].flgs,not capt	; stop capturing
	pop	bx
	and	yflags,not capt		; reset local msy flag as well
	clc
	ret
klogof	endp

snull	proc	near			; send a null byte
	xor	al,al			; the null
	call	fprtbout		; send without logging and local echo
	ret
snull	endp

khold:	xor	holdscr,1		; toggle Hold screen byte for msx
	call	kbhold			; tell DEC LK250 the hold kbd state
	clc				;  kbhold is in file msuibm.asm
	ret

; Data General "Fn" function keys
dgkf1:	mov	al,113			; F1 sends RS q
	jmp	short dgkeyccom
dgkf2:	mov	al,114			; F2 sends RS r
	jmp	short dgkeyccom
dgkf3:	mov	al,115			; F3 sends RS s
	jmp	short dgkeyccom
dgkf4:	mov	al,116			; F4 sends RS t
	jmp	short dgkeyccom
dgkf5:	mov	al,117			; F5 sends RS u
	jmp	short dgkeyccom
dgkf6:	mov	al,118			; F6 sends RS v
	jmp	short dgkeyccom
dgkf7:	mov	al,119			; F7 sends RS w
	jmp	short dgkeyccom
dgkf8:	mov	al,120			; F8 sends RS x
	jmp	short dgkeyccom
dgkf9:	mov	al,121			; F9 sends RS y
	jmp	short dgkeyccom
dgkf10:	mov	al,122			; F10 sends RS z
	jmp	short dgkeyccom
dgkf11:	mov	al,123			; F11 sends RS {
	jmp	short dgkeyccom
dgkf12:	mov	al,124			; F12 sends RS |
	jmp	short dgkeyccom
dgkf13:	mov	al,125			; F13 sends RS }
	jmp	short dgkeyccom
dgkf14:	mov	al,126			; F14 sends RS ~
	jmp	short dgkeyccom
dgkf15:	mov	al,112			; F15 sends RS p
	jmp	short dgkeyccom

; Data General "C" keys C1..C4
dgkc1:	mov	al,92			; C1 sends RS \
	jmp	short dgkeyccom
dgkc2:	mov	al,93			; C2 sends RS ]
	jmp	short dgkeyccom
dgkc3:	mov	al,95			; C3 sends RS ^
	jmp	short dgkeyccom
dgkc4:	mov	al,96			; C4 sends RS _
dgkeyccom:				; common code
	push	ax
	mov	al,DGescape		; send DG escape (RS)
	call	fprtbout		; with no echo
	pop	ax
	call	fprtbout		; send the second byte
	ret

; Keyboard "Compose" key to compose characters by the three stroke method
kbdcompose proc	near
	mov	grab,1			; say grabbing normal output
	call	togmod
	call	togmod			; update mode line
	ret
kbdcompose endp

; DG POINT (aka CMD CURSOR-TYPE)
dgpoint	proc	near
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	dgpoint1		; ne = no, ignore cmd
	call	dgcrossrpt		; send crosshair report
dgpoint1:ret
dgpoint	endp

; DG N/C (normal, compressed font) key
dgnckey proc	near
	test	flags.vtflg,ttd470+ttd463 ; DG terminal?
	jz	dgnckey1		; z = no, ignore
	call	dgnctoggle		; toggle normal/compressed mode
dgnckey1:clc
	ret
dgnckey endp

; Compose char lookup and reemitter.
fgrabber proc	far
	push	bx
	mov	bx,grab			; count chars grabbed (want two)
	dec	bx			; first char becomes bx=0
	mov	grabbox[bx],al		; stuff char in short buffer
	cmp	bx,1			; got both chars?
	pop	bx
	jae	fgrab2			; ae = yes, go produce output
	inc	grab			; keep grabbing
	ret				; return for the second
					; process the byte pair
fgrab2:	mov	grab,0			; say done grabbing output
	push	dx			; compose new single char result
	push	di
	push	es
	mov	di,seg data1
	mov	es,di
	mov	di,offset grl1lat	; use Latin1 ptr
	test	flags.vtflg,ttd463+ttd470 ; DG D463/D470?
	jz	fgrab3			; z = no
	cmp	dgkbl,16		; Latin1?
	je	fgrab3			; e = yes
	mov	di,offset grl1dgi	; get DG Internat ptr to structure
	cmp	dgkbl,20		; DG keyboard language, DG Internat?
	jne	fgrab15			; ne = no
fgrab3:	mov	ax,word ptr grabbox	; get pair of chars
	call	toupper			; convert AX to upper case
	call	match
	jnc	fgrab11			; nc = found
	xchg	ah,al
	call	match
	jnc	fgrab11			; nc = match

fgrab5:	mov	di,offset grl2lat	; use Latin1 ptr
	test	flags.vtflg,ttd463+ttd470 ; DG D463/D470?
	jz	fgrab6			; z = no
	cmp	dgkbl,16		; Latin1?
	je	fgrab6			; e = yes
	mov	di,offset grl2dgi	; get DG Internat ptr to structure
	cmp	dgkbl,20		; DG keyboard language, DG Internat?
	jne	fgrab15			; ne = no
fgrab6:	mov	ax,word ptr grabbox
	mov	dx,ax
	call	toupper			; convert AX to upper case
	call	match
	jnc	fgrab7			; nc = found
	xchg	ah,al			; try reversed order
	xchg	dh,dl
	call	match
	jc	fgrab8			; c = not found
fgrab7:	cmp	dl,'a'			; lower case char?
	jb	fgrab11			; b = no, upper case
	or	al,20h			; move to lower case output codes
	jmp	short fgrab11

fgrab8:	mov	di,offset grl3lat	; use Latin1 ptr
	test	flags.vtflg,ttd463+ttd470 ; DG D463/D470?
	jz	fgrab9			; z = no
	cmp	dgkbl,16		; Latin1?
	je	fgrab9			; e = yes
	mov	di,offset grl3dgi	; get DG Internat ptr to structure
	cmp	dgkbl,20		; DG keyboard language, DG Internat?
	jne	fgrab15			; ne = no
fgrab9:	mov	ax,word ptr grabbox
	xchg	ah,al
	call	match			; look for matching combination
	jc	fgrab16			; c = failed
fgrab11:call	foutprt			; send it to the host
fgrab15:call	togmod
	call	togmod			; update mode line
	pop	es
	pop	di
	pop	dx
	ret

fgrab16:call	fvtbell			; mismatch, beep, cancel
	jmp	short fgrab15		;  finish up
fgrabber endp

					; worker for above
match	proc	near
	push	bx
	push	si
	push	di
	mov	cl,es:[di]		; get count of pairs
	xor	ch,ch
	inc	di
	mov	si,di			; start of char lists
	jcxz	match2			; nothing to look at
	mov	si,di			; remember where pairs start
	mov	bx,di
	add	bx,cx
	add	bx,cx			; output singles start here
	cld
	push	cx			; save counter
	repne	scasw			; look for a match
	pop	cx
	jne	match2			; ne = no match
	sub	di,2			; backup to match
	sub	di,si			; get item count
	shr	di,1			; count bytes
	mov	al,es:[bx+di]		; get new output char
	pop	di
	pop	si
	pop	bx
	clc				; say success
	ret
match2:	pop	di
	pop	si
	pop	bx
	stc				; say no match
	ret
match	endp

toupper	proc	near
	cmp	ah,'a'			; less that lower A?
	jb	toupp1			; b = yes, leave untouched
	cmp	ah,'z'			; more than lower Z?
	ja	toupp1			; a = yes
	and	ah,not 20H		; convert to uppercase
toupp1:	cmp	al,'a'			; less that lower A?
	jb	toupp2			; b = yes, leave untouched
	cmp	al,'z'			; more than lower Z?
	ja	toupp2			; a = yes
	and	al,not 20H		; convert to uppercase
toupp2:	ret
toupper	endp

; DEC LK201 keyboard keys and "User Definable Keys" in VT3xx mode
decfind:mov	al,1			; Find
	jmp	udkout
decinsert:mov	al,2			; Insert
	jmp	udkout
decremove:mov	al,3			; Remove
	jmp	udkout
decselect:mov	al,4			; Select
	jmp	udkout
decprev:mov	al,5			; Previous screen
	jmp	udkout
decnext:mov	al,6			; Next screen
	jmp	udkout
decf6:	mov	al,17			; key ident for DEC F6
	jmp	udkout			; process it
decf7:	mov	al,18			; key ident for DEC F7
	jmp	udkout			; process it
decf8:	mov	al,19			; key ident for DEC F8
	jmp	udkout			; process it
decf9:	mov	al,20			; key ident for DEC F9
	jmp	udkout			; process it
decf10:	mov	al,21			; key ident for DEC F10
	jmp	udkout			; process it
decf11:	mov	al,23			; key ident for DEC F11
	jmp	udkout			; process it
decf12:	mov	al,24			; key ident for DEC F12
	jmp	udkout			; process it
decf13:	mov	al,25			; key ident for DEC F13
	jmp	udkout			; process it
decf14:	mov	al,26			; key ident for DEC F14
	jmp	udkout			; process it
dechelp:mov	al,28			; key ident for DEC HELP
	jmp	udkout			; process it
decdo:	mov	al,29			; key ident for DEC DO
	jmp	udkout			; process it
decf17:	mov	al,31			; key ident for DEC F17
	jmp	udkout			; process it
decf18:	mov	al,32			; key ident for DEC F18
	jmp	udkout			; process it
decf19:	mov	al,33			; key ident for DEC F19
	jmp	udkout			; process it
decf20:	mov	al,34			; key ident for DEC F20
	jmp	udkout			; process it

; common worker to output contents of User Definable Key definition strings
; Enter with al = key ident (17 - 34)
udkout	proc	near
	push	ax
	push	bx
	push	cx
	push	es
	test	flags.vtflg,ttvt320+ttvt220 ; VT320/VT220?
	jnz	udkout3			; nz = yes, else use VT100/VT52 default
	test	flags.vtflg,tttek	; Tek?
	jnz	udkout3			; nz = yes, try this
	cmp	al,23			; F11 sends ESC
	jne	udkou1a			; ne = not F11
	mov	al,escape
	call	foutprt
	jmp	udkoutx
udkou1a:cmp	al,24			; F12 sends BS
	jne	udkou1b			; ne = not F12
	mov	al,BS
	call	foutprt
	jmp	udkoutx
udkou1b:cmp	al,25			; F13 sends LF
	jne	udkou1c			; ne = not F13, ignore
	mov	al,LF
	call	foutprt
udkou1c:jmp	udkoutx

udkout3:mov	bl,al			; VT3XX key ident, UDK style (17-34)
	cmp	al,6			; is this the CSI 1-6 set?
	jbe	udkout4			; be = yes, do separately
	sub	bl,17			; minus starting offset of 17
	xor	bh,bh
	cmp	bl,17			; out of range?
	ja	udkoutx			; a = yes, ignore
	shl	bx,1			; index words
	mov	bx,udkseg[bx]		; segment of definition
	or	bx,bx			; anything there?
	jz	udkout4			; z = no, use DEC defaults below
	mov	es,bx			; definition segment
	xor	bx,bx			;  and offset
	mov	cl,es:[bx]		; get string length byte
	xor	ch,ch			; use cx as a counter
	jcxz	udkout4			; z = empty, use defaults
udkou3a:inc	bx			; es:bx is now the string text
	mov	al,es:[bx]		; get a char
	push	bx
	push	cx
	push	es
	call	foutprt			; output
	pop	es
	pop	cx
	pop	bx
	loop	udkou3a
	jmp	short udkoutx		; done

udkout4:push	ax			; VT320, use default definitions
	mov	al,CSI			; char to send
	call	foutprt			; send lead-in char in 7/8-bit form
	pop	ax
	call	fprtnout		; key ident (17-34) as ascii digits
	mov	al,7eh			; tilde terminator
	call	foutprt
udkoutx:pop	es
	pop	cx
	pop	bx
	pop	ax
	clc
	ret
udkout	endp

; Change Telnet sessions
nextses proc	near
	cmp	flags.comflg,'t'	; doing Telnet?
	je	nextses1		; e = yes
	clc				; do not exit Connect mode
	ret
nextses1:mov	bx,sescur		; current session ident
	mov	cx,6			; sessions to consider
nextses3:inc	bx
	cmp	bx,6			; over the top yet
	jb	nextses4			; b = no
	xor	bx,bx			; wrap
nextses4:cmp	seslist[bx],0		; is this session active?
	jge	nextses5		; ge = yes
	loop	nextses3
	clc
	ret				; do nothing

nextses5:push	bx
	mov	bx,sescur		; old session
	call	termswapout		; save current terminal items
	pop	bx
	mov	sescur,bx		; next session, from above
	call	tcpstart		; start session, ident in bl
	mov	bx,sescur		; new session
	call	termswapin		; get data structures
	mov	kbdflg,' '		; return Connect mode
	stc				; but exit Connect mode now
	ret
nextses endp

vtsesmac  proc	far			; SESSION macro
	mov	vtmacname,offset vtsesname
	mov	al,bl			; session number
	add	al,'1'			; to ascii, from 1
	mov	vtsesnum,al		; to name
	mov	vtmaclen,vtseslen
	call	dword ptr vtmacroptr	; FAR pointer
	ret
vtsesmac endp

; Call from mszibm DG components to put system into DG special graphics mode,
; and thus to cause incoming material to be still sent to the text emulator.
; This also unshifts the screen (as seen on the status line) before starting
; graphics so the column 81 stuff comes out right.
dgsettek proc	far
	cmp	tekflg,tek_active+tek_sg ; inited already?
	je	dgsettek3		; e = yes
	push	bx
	push	cx
	mov	cl,byte ptr low_rgt+1	; examine whole screen
	inc	cl			; lines in emulation part
	xor	ch,ch
	mov	bx,cx			; for status line
	xor	al,al
	xchg	al,linescroll[bx]	; status line scroll value
	or	al,al
	jz	dgsettek2		; z = no shift in effect
	xor	bx,bx			; start of screen
dgsettek1:sub	linescroll[bx],al	; unscroll by status line amount
	inc	bx			; next line
	loop	dgsettek1		; do all emulation lines
dgsettek2:pop	cx
	pop	bx
	or	tekflg,tek_sg		; set special graphics mode
	call	TEKINI			; go to Tektronix Emulator
dgsettek3:ret
dgsettek endp

code	ends

code1	segment
	assume	cs:code1

; Set (define) the DEC "User Definable Keys". Inserts text definitions for
; keyboard verbs \KdecF6 ...\KdecF14, \KdecHELP, \KdecDO, \KdecF17...\KdecF20.
; Enter with the DCS definition string as key-number/hex-chars. UDK key number
; is 17 for \KdecF6, et seq, the definition are pairs of hex digits converted
; here to a single byte per pair. The DCS definition string is pointed at by
; DS:SI, and the byte count is in CX.
; Example:  17/54657374204636   means key \KdecF6 sends string "Test F6"
setudk	proc	near
	push	ax
	push	bx
	push	cx
	push	si
	push	di
	push	es
	cld
	lodsb				; get key ident first byte
	sub	al,'0'			; ascii to binary
	mul	ten			; times 10
	xchg	ah,al			; to ah
	lodsb				; get key ident second byte
	sub	al,'0'			; ascii to binary
	add	al,ah			; plus high order part
	xor	ah,ah
	mov	bx,ax			; key ident, 17 - 34
	lodsb				; skip slash separator
	sub	cx,3			; three less bytes in the string
	jge	setudk0			; ge = had three or more bytes
	jmp	setudkx			; else error
setudk0:sub	bx,17			; remove key ident bias of 17
	cmp	bx,17			; out of range?
	ja	setudkx			; a = yes, ignore
	shl	bx,1			; index words
	cmp	udkseg[bx],0		; has a segment been allocated for it?
	je	setudk1			; e = no
	mov	ax,udkseg[bx]		; get segment to es
	mov	es,ax
	mov	ah,freemem		; deallocate old memory block, es:0
	int	dos
	mov	udkseg[bx],0		; clear table entry too
setudk1:and	cl,not 1		; force an even number of inputs
	jcxz	setudkx			; z = no definition, clear entry
	push	bx			; save index BX
	mov	bx,cx			; get string length
	shr	bx,1			; two hex digits per final byte
	add	bx,15+1			; round up plus length byte
	shr	bx,1			; convert to paragraphs
	shr	bx,1
	shr	bx,1
	shr	bx,1
	mov	di,bx			; remember request
	mov	ah,alloc		; allocate BX paragraphs
	int	dos
	jc	setudkx			; c = failure
	cmp	di,bx			; requested vs allocated
	pop	bx			; recover bx
	je	setudk2			; e = enough
	mov	ah,freemem		; return the memory, es is ptr
	int	dos
	jmp	short setudkx		; exit failure

setudk2:mov	es,ax			; segment of allocated memory
	mov	udkseg[bx],ax		; segment:0 of definition string
	xor	di,di
	cld
	mov	al,cl			; length of string
	shr	al,1			; two hex bytes per stored byte
	xor	ch,ch
	stosb				; store length byte
	jcxz	setudkx			; z = empty string
setukd3:lodsb				; get first hex digit
	dec	cx			; adjust count remaining
	or	al,20h			; to lower case
	cmp	al,'9'			; digit?
	jbe	setudk4			; be = yes
	sub	al,'a'-'9'-1		; hex letter to column three
setudk4:sub	al,'0'			; ascii to binary
	shl	al,1			; times 16
	shl	al,1
	shl	al,1
	shl	al,1
	mov	ah,al			; save in ah
	lodsb				; get second hex digit
	or	al,20h			; to lower case
	cmp	al,'9'			; digit?
	jbe	setudk5			; be = yes
	sub	al,'a'-'9'-1		; hex letter to column three
setudk5:sub	al,'0'			; ascii to binary
	add	al,ah			; join both parts
	stosb				; store final byte
	loop	setukd3
setudkx:pop	es
	pop	di
	pop	si
	pop	cx
	pop	bx
	pop	ax
	clc
	ret
setudk	endp

; Clear all User Definable Keys, deallocate memory for their definitions
udkclear proc	near
	push	ax
	push	bx
	push	cx
	push	es
	mov	cx,17			; 17 entries
	xor	bx,bx
udkcle1:mov	ax,udkseg[bx]		; segment of definition
	or	ax,ax			; segment defined?
	jz	udkcle2			; z = no, try next key
	mov	es,ax
	mov	udkseg[bx],0		; clear the entry
	mov	ah,freemem		; release the memory
	int	dos
udkcle2:add	bx,2			; word index
	loop	udkcle1			; do all
	pop	es
	pop	cx
	pop	bx
	pop	ax
	clc
	ret
udkclear endp

fsetpos	proc	far
	call	setpos
	ret
fsetpos	endp

frepaint proc	far
	call	repaint
	ret
frepaint endp
code1	ends

code	segment
	assume	cs:code
					; these commands invoke Quit
cdos:	mov	al,'P'			; Push to DOS
	jmp	short cmdcom
cstatus:mov	al,'S'			; Status
	jmp	short cmdcom
cquit:	mov	al,'C'			; Exit Connect mode
	jmp	short cmdcom
cquery:	mov	al,'?'			; Help
	jmp	short cmdcom
chang:	mov	al,'H'			; Hangup, drop DTR & RTS
	jmp	short cmdcom
cmdcom:	mov	kbdflg,al		; pass char to msster.asm via kbdflg
	stc				; signal that Quit is needed
	ret
					; general character out for emulator
chrout	proc	near
	cmp	flags.vtflg,0		; emulating?
	je	chrou5			; e = no
	call	fanskbi			; say we had keyboard input
	cmp	al,cr			; CR?
	jne	chrou5			; ne = no, just output it and return
	test	vtemu.vtflgop,anslnm	; ANSI new-line mode set?
	jz	chrou5			; z = no, just send the cr
	cmp	dupflg,0		; full duplex?
	je	chrou4			; e = yes
	cmp	al,trans.seol		; End of Line char?
	jne	chrou5			; ne = no
chrou4:	mov	ah,trans.seol		; save eol char
	push	ax			; save on stack
	mov	trans.seol,lf		; make LF the eol char
	call	foutprt			; output a carriage-return
	mov	al,lf			; followed by a line feed
	call	foutprt			; send the LF
	pop	ax
	mov	trans.seol,ah		; restore eol char
	ret
chrou5:	call	foutprt
	ret
chrout	endp

   					; Screen dump entry from keyboad xlat
dmpscn	proc	near			; dump screen to file
	cmp	flags.vtflg,tttek	; doing Tektronix emulation?
	je	dmpscn2			; e = yes, use Tek emulator
	cmp	tekflg,tek_active+tek_dec ; emulation a Tektronix?
	jne	dmpscn1			; ne = no
dmpscn2:call	tekdmp			; near-call Tek screen dump utility
	clc
	ret
dmpscn1:call	dumpscr			; do buffer to file
	clc				; do not exit Connect mode
	ret
dmpscn	endp

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

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

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

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

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

togmod	proc	FAR
	call	trnmod			; FAR callable trnmod
	ret
togmod	endp

					; Toggle Mode Line
trnmod	proc	near
	cmp	inemulator,0		; in terminal emulator?
	je	trnm1			; e = no, no mode line
	cmp	flags.modflg,1		; mode line enabled and owned by us?
	jne	trnm1			; ne = no, don't touch it
	cmp	flags.vtflg,tttek	; Tek mode?
	je	trnm1			; e = yes
	test	tekflg,tek_dec		; in Tek submode?
	jnz	trnm1			; nz = yes, no mode line changes
	test	yflags,modoff		; mode line already off?
	jnz	trnm2			; nz = yes, go turn on
	or	yflags,modoff		; say modeline is toggled off
	cmp	flags.vtflg,0		; emulating none?
	jne	trnm0			; ne = no
	push	dx
	call	fgetpcur		; get physical cursor
	mov	cursor,dx
	pop	dx
trnm0:	call	clrmod			; clear mode line
trnm1:	clc				; clear c bit so don't exit Connect
	ret
trnm2:	cmp	flags.vtflg,0		; emulating a terminal?
	jne	trnm3			; ne = yes
	push	dx			; scroll screen to save bottom line
	call	fgetpcur		; get physical cursor
	mov	cursor,dx
	mov	ah,prstr		; for terminal type none
	mov	dx,offset crlf
	int	dos
	pop	dx
trnm3:	call	modlin			; turn on modeline
	and	yflags,not modoff	; say modeline is not toggled off
	clc
	ret
trnmod	endp

modlin	proc	near
	push	si
	push	di
	push	es
	mov	ax,ds
	mov	es,ax
	mov	si,offset modmaster	; master template
	mov	di,offset modbuf	; working copy
	cld
modl20:	lodsb
	stosb
	cmp	al,'$'			; at end?
	jne	modl20			; ne = no
	mov	al,trans.escchr		; Connect mode escape character
	mov	modbuf.m_echr,' '	; first char is initial space
	mov	modbuf.m_hlp,' '	; goes here too
	cmp	al,32			; printable?
	jnb	modl1			; yes, keep going
	add	al,40h			; made printable
	mov	modbuf.m_echr,5eh	; caret, note control char
	mov	modbuf.m_hlp,5eh
modl1:	mov	modbuf.m_echr+1,al	; fill in character
	mov	modbuf.m_hlp+1,al
	mov	bx,argadr		; get argument block
	mov	al,[bx].baudb		; get baud bits
	mov	si,offset unkbaud	; assume unknown baud
	mov	cx,size m_baud		; length of baud space
	cmp	al,baudnsiz		; beyond end of table?
	jnb	modl2			; nb = yes, use default
	mul	cl
	xor	ah,ah
	add	ax,offset baudn
	mov	si,ax
modl2:	mov	di,offset modbuf.m_baud
	cld
	rep	movsb			; copy in baud rate
	mov	bx,portval
	mov	al,[bx].parflg		; get parity code
	shl	al,1			; each is 4 bytes long
	shl	al,1
	xor	ah,ah
	add	ax,offset parnams	; names of parity settings
	mov	si,ax
	mov	cx,4			; each is 4 long
	mov	di,offset modbuf.m_par
	rep	movsb
	mov	si,offset remmsg	; assume remote echoing
	test	yflags,lclecho		; local echo on?
	jz	modl3			; z = no
	mov	si,offset lclmsg	; say echo is local
modl3:	mov	cx,3			; size of on/off
	mov	di,offset modbuf.m_echo
	rep	movsb
	mov	al,portno		; communications port
	cmp	al,' '			; binary (non-printable)?
	jae	modl4			; ae = no, ascii
	add	al,'0'			; convert to ascii
modl4:	mov	modbuf.m_prt,al		; fill in port number
	mov	al,portno
	cmp	repflg,0		; REPLAY?
	je	modl5			; e = no
	mov	si,offset repmsg	; say "REPLAY"
	mov	cx,repmsgl		; its length
	mov	di,offset modbuf.m_prt
	mov	al,' '			; start with a space
	stosb
	mov	dx,12			; space to be filled
	sub	dx,cx			; amount we will use here
	rep	movsb			; copy string
	mov	cx,dx
	rep	stosb			; flesh out with spaces
	jmp	short modl10

modl5:	cmp	al,'4'			; in networks material?
	jbe	modl10			; be = no
	cmp	flags.comflg,'t'	; doing TCP/IP Telnet?
	jne	modl5d			; ne = no
	mov	si,offset tcphost	; name of host
	mov	di,offset modbuf.m_prt - 6 ; overwrite "port:"
	mov	ax,sescur		; ident of session
	add	al,'1'			; ascii, show as 1:nodename
	mov	ah,':'
	stosw				; store that much
	mov	cx,17			; bytes max
modl5a:	lodsb
	or	al,al 			; at null terminator?
	jz	modl5b			; z = yes
	stosb
	loop	modl5a
modl5b:	mov	al,' '			; fill out with spaces
	rep	stosb			; noop if cx == 0
	jmp	short modl5d		; done with tcp/ip 

modl5d:	mov	bx,offset comptab	; table of comms ports
	mov	cl,[bx]			; number of entries
	xor	ch,ch
	inc	bx
modl6:	mov	dx,[bx]			; length of this entry
	mov	si,bx
	add	si,2			; points to entry text string
	add	si,dx			; point to qualifier
	cmp	[si],al			; our port?
	je	modl7			; e = yes
	add	bx,[bx]			; add text length
	add	bx,4			; plus count and qualifier
	loop	modl6			; next entry
	jmp	short modl10		; no match, curious
modl7:	mov	si,bx			; point at entry
	add	si,2			; point at string
	mov	cx,[bx]			; length of string
	mov	di,offset modbuf.m_prt
	mov	al,' '			; start with a space
	stosb
	mov	dx,12			; space to be filled
	sub	dx,cx			; amount we will use here
	rep	movsb			; copy string
	mov	cx,dx
	rep	stosb			; flesh out with spaces
modl10:	mov	cx,8			; blank out terminal id field
	mov	si,offset mtty		; assume no terminal emulation
	mov	di,offset modbuf.m_term ; destination
	rep	movsb			; copy it in
	mov	word ptr modbuf.m_prn,'  '; assume not printing the screen
	mov	modbuf.m_prn+2,' '
	test	anspflg,prtscr+2	; print the screen? (msz uses 1 & 2)
	jz	modl10a			; z = no
	mov	word ptr modbuf.m_prn,'RP' ; yes. display PRN at end of line
	mov	modbuf.m_prn+2,'N'
modl10a:mov	modbuf.m_comp,' '	; flag for not-compose
	cmp	grab,0			; doing Compose grabbing?
	je	modl11			; e = no
	mov	modbuf.m_comp,'C'	; flag for compose
modl11:	cmp	inemulator,0		; in terminal emulator now?
	jne	modl11a			; ne = yes
	pop	es			; do nothing
	pop	di
	pop	si
	ret
modl11a:push	dx
	cmp	flags.vtflg,0		; emulating?
	je	modl12			; e = no
	and	yflags,not modoff	; update local flags (mode line on)
	call	fansdsl			; get extras from emulator
modl12:	mov	dx,offset modbuf	; mode line image ptr for putmod
	call	putmod			; display mode line
	mov	dx,cursor		; restore active cursor position
	call	fsetpos			; set cursor
	pop	dx
	pop	es
	pop	di
	pop	si
	ret
modlin	endp

fmodlin	proc	far
	call	modlin
	ret
fmodlin	endp

;[IU2] Routine to toggle VT100/VT52/Heath-19 modes in VT100 emulator.
vtans52 proc	near
	cmp	flags.vtflg,0		; emulating?
	je	vtans52a		; e = no
	call	ans52t			; call MSZ toggle-it routine
	cmp	flags.vtflg,tttek	; Tek now?
	je	vtans52a		; e = yes
	test	tekflg,tek_tek+tek_dec 	; Tek submode?
	jnz	vtans52a		; nz = yes
	call	scrini			; check on screen size changes
vtans52a:clc				; clear c bit so don't exit Connect
	ret
vtans52 endp

ftrnprs proc	far
	call	trnprs
	ret
ftrnprs	endp

trnprs	proc	near
	push	ax			; toggle ^ PrtSc screen to printer
	test	anspflg,prtscr		; are we currently printing?
	jnz	trnpr2			; nz = yes, its on and going off
	push	bx
	mov	bx,prnhand		; file handle for system printer
	mov	ah,ioctl
	mov	al,7			; get output status of printer
	int	dos
	pop	bx
	jc	trnpr1			; c = printer not ready
	cmp	al,0ffh			; Ready status?
	je	trnpr2			; e = Ready	
trnpr1:	call	fvtbell			; Not Ready, complain
	jmp	trnpr3			; and ignore request
trnpr2:	xor	anspflg,prtscr		; flip the flag
	test	yflags,modoff		; mode line off?
	jnz	trnpr3			; nz = yes
	call	fmodlin			; else rewrite mode line
trnpr3:	pop	ax
	clc				; return carry clear (don't quit)
	ret
trnprs	endp
code	ends

code1	segment
	assume	cs:code1

pntdead	proc	near			; display printer is inoperative msg
	push	ax
	test	yflags,modoff		; is mode line off?
	jnz	pntdea1			; nz = off, skip msg
	push	bx
	mov	dx,offset pntmsg	; say printer not ready
	call	fputmod			; write on mode line
	pop	bx
pntdea1:pop	ax
	stc				; say printer not ready
	ret
pntdead	endp

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

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

scrloc	proc	near
	push	cx
	mov	cl,crt_cols
	cmp	inemulator,0		; emulating?
	je	scrloc1			; e = no
	cmp	flags.vtflg,0		; emulating anything?
	je	scrloc1			; e = no
	mov	cl,vswidth
scrloc1:mov	al,dh			; get row
	mul	cl			; multiply by number of columns
	add	al,dl			; plus current column number
	adc	ah,0			; ripple carry
	shl	ax,1			; double for attributes
	pop	cx
	ret
scrloc	endp

; Routine to set cursor type.  Pass cursor type in al: 0,4 = No cursor,
; 1 = Underline cursor, 2 = Block cursor.   All cursors blink due to hardware.
; For EGA boards running in non-25 line mode the cursor emulation is turned
; off during cursor shape changing and restored afterward. It's another
; ega Feature. [jrd]
; Sense crt_mode 18h as Tseng Labs UltraPAK mono board in 132 column mode.
csrtype proc	near
	push	cx			; save the reg
	mov	cx,0F00H		; assume no cursor
	test	al,4			; no cursor?
	jz	csrtyp6			; z = no
	xor	al,al			; set type to invisible
csrtyp6:or	al,al			; no cursor?
	jz	csrty2			; z = yes, no cursor
	cmp	crt_mode,7		; B&W card?
	je	csrty3			; e = yes, different sizes
	cmp	crt_mode,18h		; Tseng UltraPAK mono board?
 	je	csrty3			; e = yes, use mono cursor
	mov	cx,0607H		; use CGA underline cursor
	cmp	al,2			; Block?
	jne	csrty2			; ne = no, set it now
csrty1: xor	ch,ch			; make cursor a block
csrty2:	cmp	ega_mode,0		; ega board active?
	je	csrty4			; e = no
	test	tv_mode,10h		; DV active?
	jnz	csrty4			; nz = yes, it messes with the cursor
	cmp	byte ptr low_rgt+1,23	; standard screen length?
	je	csrty4			; e = yes, use regular cursor setting
	push	es			; EGA. turn off cursor emulation
	mov	ax,40h			; 40:87h is ega Info byte
	mov	es,ax
	push	es:[87h]		; save Info byte around call
	or	byte ptr es:[87h],1	; set emulation off (low bit = 1)
	mov	ah,1			; video function for set cursor type
	int	screen
	pop	es:[87h]		; restore Info byte
	pop	es			;  and our work register
	pop	cx
	ret

csrty4:	push	ax
	mov	ah,1			; video function for set cursor type
	int	screen			; regular cursor shape setting
	pop	ax
csrty5:	pop	cx
	ret

csrty3: mov	cx,0B0CH		; assume B&W underline cursor
	cmp	al,2			; Block?
	jne	csrty2			; ne = no, set it now
	jmp	short csrty1		; make it a block
csrtype endp

fcsrtype proc	far
	call	csrtype
	ret
fcsrtype endp

; Get CRT mode - returns mode in variable crt_mode,
; updates crt_cols, and low_rgt.
; For EGA active it looks in Bios work memory 40:84H for number of rows
scrmod	proc	near
	push	ax
	push	dx
	mov	ah,0fh			; get current video state
	int	screen
	and	al,not 80h		; strip "preserve regen" bit 80h
	mov	crt_mode,al		; store CRT mode value
	mov	crt_cols,ah		; store # of cols
	mov	dl,ah			; # of cols again
	mov	dh,crt_lins		; and # of rows (constant from msster)
	cmp	tv_mode,0		; Topview active?
	je	scrmod2			; e = no
	test	tv_mode,20h		; Japanese DOS active?
	jnz	scrmod2			; nz = yes, do not do Int 15h
	push	cx
	push	bx
	mov	ah,12h			; TV, Get Object Length
	mov	bx,0901h		; object, BL = 01 = chars/line
	int	15h
	pop	ax			; chars/line from stack dword
	cmp	al,10			; keep things sane, chars per line
	ja	scrmod7			; a = might be sane
	pop	ax			; clean stack
	jmp	scrmod2			; wacko, ignore DV stuff

scrmod7:mov	crt_cols,al		; TV windowed screen columns
	pop	ax			; clear rest of dword from stack
	mov	ah,12h			; send
	mov	bx,1			; handle (0*256) + window (me, 1)
	int	15h
	pop	bx			; handle low word
	pop	bx			; handle high word to BX for next call
	mov	ax,1024h		; TV Get Virtual Screen Info
	int	15h
scrmod1:cmp	cx,128*25*2		; get sanity for DV big DOS window
	jbe	scrmod1a		; be = reasonable size
	shr	cx,1			; reduce size
	jmp	short scrmod1		;  and try again
scrmod1a:mov	ax,cx			; CX is virtual screen size, bytes
	mov	bl,crt_cols		; divide by columns to get width
	shl	bl,1			; get words (char and attribute)
	div	bl			; al = lines, ah = fractions of line
	dec	al			; count this from zero like the Bios
	mov	crt_lins,al		; visible screen lines -1 (24)
	mov	dh,al
	mov	dl,crt_cols		; visible screen columns (80)
	pop	bx
	pop	cx
	jmp	short scrmod4

scrmod2:cmp	ega_mode,0		; ega active?
	je	scrmod4			; e = no
	push	es			; yes, permit different lengths
	mov	ax,40h			; refer to 40:84h for # ega rows
	mov	es,ax
	mov	ah,es:[84h]		; get number of rows - 1 (typ 24)
	cmp	ah,20			; less than 20 rows?
	jb	scrmod3			; b = yes, ignore this length
	cmp	ah,80			; more than 80 rows?
	ja	scrmod3			; a = yes, ignore this length
	mov	dh,ah			; use this length
	mov	crt_lins,dh		; update our working constant
scrmod3:pop	es
scrmod4:dec	dl			; max text column, count from zero
	dec	dh			; max text row, count from zero
	cmp	flags.vtflg,ttgenrc	; no terminal emulation
	je	scrmod6			; e = yes
	cmp	tekflg,tek_active+tek_sg ; doing special graphics?
	jne	scrmod4a		; ne = no
	mov	crt_cols,128		; VT style special graphics uses this
scrmod4a:
	cmp	crt_cols,80		; doing wide now?
	ja	scrmod5			; a = yes
	mov	dl,80-1			; assume 80 column width
	test	vtemu.vtflgop,deccol	; 132 column mode set?
	jz	scrmod6			; z = no
scrmod5:mov	dl,132-1		; set to 132 column mode
scrmod6:mov	low_rgt,dx		; save away window address
	pop	dx
	pop	ax
	ret
scrmod	endp

; Get screen segment. Returns screen segment in ax, and full address in es:di
scrseg	proc	near
	xor	di,di			; start at beginning of screen (0,0)
	mov	ax,0B800H		; video memory is here on color
	cmp	crt_mode,7		; normal color modes?
	jb	scrse1			; b = yes
	mov	ax,0B000H		; assume B&W card
	cmp	crt_mode,12		; 
	jb	scrse1
	cmp	crt_mode,18h		; Tseng UltraPAK mono in 132 col?
	je	scrse1			; e = yes, use seg B000H
	cmp	crt_mode,56h		; Paradise EGA Mono in 132x43 mode?
	je 	scrse1			; e = yes, use seg B000H
	cmp	crt_mode,57h		; Paradise EGA Mono in 132x25 mode?
	je	scrse1			; e = yes, use seg B000H
	mov	ax,0B800H		; video memory is here on color
	cmp	crt_mode,18		; end of ordinary 640x480 graphics
	ja	scrse1			; a = no, assume CGA segment
	mov	ax,0A000H		; graphics
scrse1:	mov	es,ax		; tell Topview our hardware address needs
	mov	tv_segs,es		; save our hardware screen address
	mov	tv_sego,di		; segment and offset form
	or	tv_mode,1		; assume we're running under Topview
	mov	ah,tvhere		; query Topview for its presence
	int	screen
	mov	ax,es			; get its new segment for screen work
	cmp	ax,tv_segs		; same as hardware?
	jne	scrse2			; ne = no, we are being mapped
	cmp	di,tv_sego		; check this too
	jne	scrse2		; ne = no too. Use TV's work buf as screen
	and	tv_mode,not 1		; else no Topview or no mapping
scrse2:	mov	tv_segs,es		; save segment
	mov	tv_sego,di		; and offset
	ret
scrseg	endp

; Synchronize a Topview provided virtual screen buffer with the image
; seen by the user. Requires cx = number of words written to screen
; (char & attribute bytes) and es:di = ENDING address of screen write.
; Changes ax and di. Skip operations for DESQview
scrsync proc	near
	cmp	tv_mode,0		; Topview mode active?
	je	scrsyn1			; e = no, skip Bios call below
	push	ax
	push	cx
	push	di
	sub	di,cx			; backup to start byte (cx = words)
	sub	di,cx			;  after storing words to screen
	mov	ah,tvsynch		; tell Topview we have changed screen
	int	screen			;  so user sees updated screen
	pop	di
	pop	cx
	pop	ax
scrsyn1:ret
scrsync endp

; The following two routines are used to turn off the display while we
; are reading or writing the screen in one of the color card modes.
; Turn screen off for (known) color card modes only. All regs preserved.
; Includes code for old procedure scrwait. 16 June 1987 [jrd]
scroff	proc	near
	cmp	ega_mode,0		; Extended Graphics Adapter in use?
	jne	scrofx			; ne = yes, no waiting
	cmp	tv_mode,0		; Topview mode?
	jne	scrofx			; ne = yes, no waiting
	cmp	crt_mode,7		; B&W card?
	jnb	scrofx			; nb = yes - just return
	cmp	refresh,0		; slow refresh?
	jne	scrofx			; ne = no wait
	push	ax			; save ax and dx
	push	dx
	mov	dx,crt_status		; CGA: Wait for vertical retrace
scrof1:	in	al,dx
	test	al,disp_enb		; display enabled?
	jnz	scrof1			; yes, keep waiting
scrof2:	in	al,dx
	test	al,disp_enb		; now wait for it to go off
	jz	scrof2			; so can have whole cycle
	mov	dx,crtmset		; output to CRT mode set port
	mov	al,25H			; this shuts down the display
	out	dx,al
	pop	dx			; restore regs
	pop	ax
scrofx: ret
scroff	endp


; Turn screen on for (known) color card modes only
; All registers are preserved.

scron	proc	near
	cmp	ega_mode,0		; Extended Graphics Adapter in use?
	jne	scronx			; ne = yes, no waiting
	cmp	tv_mode,0		; Topview mode?
	jne	scronx			; ne = yes, no waiting
	cmp	crt_mode,7		; B&W card?
	jnb	scronx			; nb = yes - just return
	cmp	refresh,0		; slow refresh?
	jne	scronx			; ne = no wait
	push	ax			; save ax, dx, and si
	push	dx
	push	si
	mov	al,crt_mode		; convert crt_mode to a word
	xor	ah,ah
	mov	si,ax			; get it in a usable register
	mov	al,msets[si]		; fetch the modeset byte
	mov	dx,crtmset		; this port
	out	dx,al			; flash it back on
	pop	si
	pop	dx
	pop	ax
scronx: ret
scron	endp


; Determine screen roll back buffer parameters depending on current screen
; dimensions and available memory. Each rollback screen line has its own
; segment (lines start on segment boundaries for rollback). One full screen
; must be allocated to hold the current display, deduct this from lmax.

bufadj	proc	near
	push	bx
	push	cx
	push	dx
	mov	bx,rollwidth		; rollback line width
	add	bx,7			; (BDT) round up to paragraph boundary
	mov	cl,3			; (BDT) now convert to
	shr	bx,cl			; (BDT) paragraphs / line
	mov	ppl,bx			; (BDT) save this in buffer area
	xor	dx,dx			; high order dividend, clear it
	cmp	emsrbhandle,0		; using EMS?
	jle	bufadj2			; le = no (-1 means not used)
	mov	ax,1024			; 1024 paragraphs per ems 16KB page
	div	bx			; divide by paragraphs per line
	mov	lineems,ax		; lines per ems page, remember
	mul	inipara			; times number of ems pages
	jmp	short bufadj3		; ax has number of lines
					; conventional memory
bufadj2:mov	ax,inipara		; (BDT) compute the number of lines
	div	bx			; (BDT)  in the buffer

bufadj3:mov	lmax,ax			; max line capacity of the buffer
	mov	linee,ax		; (BDT) save as number of total lines
	or	ax,ax			; have any lines?
	jz	bufadj1			; z = yes, no space at all
	xor	bh,bh			; (BDT) get lines / screen
	mov	bl,byte ptr low_rgt+1	; (BDT) rows on user/host screen
	inc	bx			; (BDT) adjust for counting from 0
	sub	lmax,bx			; minus master "current" screen
	jg	bufadj1			; g = have some rollback space
	mov	lmax,0			; say none
bufadj1:mov     lcnt,0                  ; (BDT) # of lines filled in buffer
	mov	linef,0			; (BDT) first filled in line
	mov	linec,0			; (BDT) last  filled in line
	pop	dx
	pop	cx
	pop	bx
	ret
bufadj	endp

; Test for DESQview in operation, set tv_mode bit 10h to non-zero if so.
dvtest	proc	near
	and	tv_mode,not 30h		; assume no DV and no Japanese DOS
	push	ds
	mov	ax,ds			; preset es:si to start of data seg
	mov	es,ax			; as saftey factor after test
	xor	si,si
	mov	ax,6300h		; get Doublebyte Char Set Lead Table
	int	dos			; returns ptr in ds:si
	mov	bx,ds			; cannot trust al as return status
	mov	es,bx
	pop	ds
	mov	ax,ds			; current DS
	cmp	ax,bx			; same seg?
	je	dvtest4			; e = yes, test failed
	cmp	word ptr es:[si],0	; see if both bytes are also zeros
	je	dvtest4			; z = test failed
	or	tv_mode,20h		; say Japanese DOS is active
	ret				; do no Int 15h with Japanese DOS
dvtest4:xor	bx,bx			; for version number
	mov	cx,'DE'			; DV signature
	mov	dx,'SQ'
	mov	ax,2B01h		; DOS set date (with illegal value)
	int	dos
	cmp	al,0ffh			; DOS should say invalid if no DV
	je	dvtest2			; e = yes, invalid so no DV
	cmp	bx,2			; DV version 2.00?
	jne	dvtest1			; ne = no
	xchg	bh,bl			; get major version into bh
dvtest1:or	tv_mode,10h		; say using DV
dvtest2:ret
dvtest	endp

; Execute DESQview function call provided in BX.
dvcall	proc	near
	push	ax
	mov	ax,101ah		; switch to DV stack
	int	15h
	mov	ax,bx			; function to do
	int	15h
	mov	ax,1025h		; switch from DV stack
	int	15h
	pop	ax
	ret
dvcall	endp

; Call this to release the cpu during idle times
dvpause	proc	near
	test	tv_mode,10h		; in DV?
	jz	dvpaus1			; z = no
	push	bx
	mov	bx,1000h		; say release control
	call	dvcall			; to DV
	pop	bx
dvpaus1:cmp	byte ptr dosnum+1,5	; DOS verson, major high, minor low
	jb	dvpaus2			; b = too old for this operation
	mov	ax,1680h		; release current virtual machine
	int	2fh			;  time slice (Windows, OS/2, DPMI)
dvpaus2:ret
dvpause	endp

; Screen clearing routine
; Call:	ax = coordinates of first screen location to be cleared.
;	bx = coordinates of last location to be cleared.
; Coord: ah = row [0-24], al = column [0-206]. Preserves all registers.

atsclr	proc	near
	push	ax			; save regs 
	push	cx
	mov	ch,scbattr		; save current screen background attr
	push	cx
	push	dx
	mov	dx,bx			; compute last screen offset from bx
	push	ax
	call	scrloc			; get screen start address in ax
	mov	cx,ax			; save it in cx for a minute
	pop	dx			; compute first screen offset in ax
	call	scrloc
	sub	cx,ax			; compute number of locs to clear
	add	cx,2			; +1 for span, +1 for round up
	sar	cx,1			; make byte count a word count
	jle	atscl3			; le = nothing to clear
	push	di			; save regs
	push	es			; save es
	cmp	inemulator,0		; in terminal emulator now?
	je	atscl1			; e = no
	cmp	flags.vtflg,0		; emulating anything?
	je	atscl1			; e = no, using DOS
	les	di,vs_ptr		; es:di is virtual screen
	jmp	short atscl2
atscl1:	push	ax			; save displacement
	call	scroff			; turn screen off if color card
	call	scrseg			; get address of screen into es:di
	pop	ax
atscl2:	add	di,ax			; location in buffer
	mov	ah,scbattr		; use current screen background attr
	mov	al,' '			; use space for fill
	push	cx			; save word count for Topview
	cld
	rep	stosw			; copy to screen
	pop	cx			; recover word count
	cmp	inemulator,0		; in terminal emulator now?
	je	atscl2a			; e = no
	cmp	flags.vtflg,0		; emulating anything?
	jne	atscl2b			; ne = yes
atscl2a:call	scrsync			; synch Topview
	call	scron			; turn screen back on if color card
atscl2b:pop	es
	pop	di
atscl3:	pop	dx
	pop	cx
	mov	scbattr,ch		; recover current screen bkg attr
	pop	cx
	pop	ax			; back to regs at call time
	cmp	inemulator,0		; in terminal emulator now?
	je	atscl6			; e = no
	cmp	flags.vtflg,0		; emulating anything?
	je	atscl6			; e = no, using DOS
	push	dx			; do extended attributes
	push	ax
	push	bx
	push	cx
	mov	dx,ax			; starting place
	mov	al,dh			; row
	mov	cl,((vswidth+1)/2)*2	; row char cells
	mul	cl
	add	al,dl			; plus starting column
	adc	ah,0			; char cells to starting place
	mov	dx,ax			; save here
	mov	al,bh			; ending row
	mul	cl
	add	al,bl			; plus ending column
	adc	ah,0
	mov	bx,ax
	sub	bx,dx			; number of cells -1 to clear
	inc	bx
	mov	cx,bx			; cx = cells to clear
	xchg	bx,dx			; bx = start offset, dx=cells
	push	es
	push	di
	les	di,vsat_ptr		; where attributes are stored
	shr	cx,1			; cells to bytes, rounded down
	inc	bx			; round up
	shr	bx,1			; cells to bytes
	jc	atscl4			; c = no odd start, can do whole bytes
	and	byte ptr es:[di+bx-1],0fh ; clear initial (high) nibble
	dec	dx			; one less cell
atscl4:	add	di,bx			; offset plus start byte
	xor	al,al
	cld
	rep	stosb			; clear those bytes
	test	dl,1			; odd nibble at the end?
	jz	atscl5			; z = no, done
	and	byte ptr es:[di],0f0h	; clear last (low) nibble
atscl5:	pop	di
	pop	es
	pop	cx
	pop	bx
	pop	ax
	mov	dl,ah			; first row
	mov	dh,bh			; last row
	call	touchup			; repaint this part of the screen
	pop	dx			; finish cleaning stack
atscl6:	ret
atsclr	endp


; Screen-scrolling routines.
     
fhomwnd	proc	far			; "home" to start of the buffer
	mov	cl,byte ptr low_rgt+1	; save this many lines
	inc	cl			; full text screen
	xor	ch,ch
	call	putcirc			; save them
	mov	linec,0			; reset the current pointer
	call	getcirc			; now get the new screen
	clc
	ret
fhomwnd	endp
     
fendwnd	proc	far			; "end" to end of the buffer
	mov	cl,byte ptr low_rgt+1	; save this many lines
	inc	cl			; full text screen
	xor	ch,ch
	call	putcirc			; save them
	mov	ax,lcnt			; reset the current pointer
	mov	linec,ax		; save the results
	call	getcirc			; now get the new screen
	clc
	ret
fendwnd	endp
     
fdnwpg	proc	far			; scroll down 1 page
	mov	cl,byte ptr low_rgt+1	; save this many lines
	inc	cl			; full text screen
	xor	ch,ch
	call	putcirc			; save them
	mov	ax,linec		; reset the current pointer
	add	ax,cx
	cmp	ax,lcnt			; did we go past the end?
	jbe	dnwpg1			; be = no, we're OK
	mov	ax,lcnt			; yup, back up
dnwpg1:	mov	linec,ax		; save the results
	call	getcirc			; now get the new screen
	clc
	ret
fdnwpg	endp
     
fdnone	proc	far			; scroll down 1 line
	mov	cl,byte ptr low_rgt+1	; save this many lines
	inc	cl			; full text screen
	xor	ch,ch
	call	putcirc			; save them
	mov	ax,linec		; reset the current pointer
	inc	ax			;  to the next line
	cmp	ax,lcnt			; oops, did we go past the end?
	jbe	dnone1			; be = no, we're OK
	mov	ax,lcnt			; yup, back up
dnone1:	mov	linec,ax		; save the results
	call	getcirc			; now get the new screen
	clc
	ret
fdnone	endp
     
fupwpg	proc	far			; scroll up 1 page
	mov	cl,byte ptr low_rgt+1	; save this many lines
	inc	cl			; full text screen
	xor	ch,ch
	call	putcirc			; save a full screen
	mov	ax,linec		; reset the current pointer
	sub	ax,cx			;  to the previous page
	jge	upwpg1			; ge = not past end, we're OK
	xor	ax,ax			; stop at the beginning of the buffer
upwpg1:	mov	linec,ax		; line counter to use
	call	getcirc			; get the new screen
	clc
	ret
fupwpg	endp
     
fupone	proc	far			; scroll up 1 line
	mov	cl,byte ptr low_rgt+1	; save this many lines
	inc	cl			; full text screen
	xor	ch,ch
	call	putcirc			; save them
	mov	ax,linec		; reset the current pointer
	sub	ax,1			;  to the previous line
	jge	upone1			; ge = not past end, we're OK
	xor	ax,ax			; yup, back up
upone1:	mov	linec,ax		; save the results
	call	getcirc			; now get the new screen
	clc
	ret
fupone	endp

; Horizontal scrolling keyboard verbs
frtpage	proc	far
	mov	cx,20			; step size
	call	rtcommon
	ret
frtpage	endp

frtone	proc	far
	mov	cx,1
	call	rtcommon
	ret
frtone	endp

; Move screen to the right margin by CX columns
rtcommon proc	near
	push	bx
	mov	bl,byte ptr cursor+1	; current cursor row
	xor	bh,bh
	mov	al,linescroll[bx]	; horz scroll in effect for this line
	pop	bx
	add	al,handhsc 		; plus hand scrolling now present
	add	al,crt_cols		; right most char on visible screen
	adc	ah,0
	cmp	ax,vswidth		; too far already?
	ja	rtcomm2			; a = yes, do nothing
	sub	ax,vswidth		; available distance
	neg	ax
	cmp	ax,cx			; space vs desired scroll
	jbe	rtcomm1			; be = less than desired, use space
	mov	ax,cx			; enough room, use desired scroll
rtcomm1:add	handhsc,al		; indicate how much done by hand
	call	repaint
rtcomm2:clc
	ret
rtcommon endp

flfpage	proc	far
	mov	cx,20			; step size
	call	lfcommon
	ret
flfpage	endp

flfone	proc	far
	mov	cx,1			; step size
	call	lfcommon
	ret
flfone	endp

; Move screen toward left margin by CX columns
lfcommon proc	near
	push	bx
	mov	bl,byte ptr cursor+1	; current cursor row
	xor	bh,bh
	mov	al,linescroll[bx]	; horz scroll in effect for this line
	pop	bx
	add	al,handhsc		; available distance to move
	jz	lfcomm2			; z = no space to mov
	sub	al,cl			; minus out desired jump
	jge	lfcomm1			; ge = no overscroll the wrong way
	add	cl,al			; reduce cx request by overage
lfcomm1:sub	handhsc,cl		; successful, new handhsc
	call	repaint
lfcomm2:clc
	ret
lfcommon endp

; Scrolling routines.  vtscru scrolls up, vtscrd scrolls down 'scroll'
; rows. Top lines are saved in the circular buffer before scrolling up.
; When running under an Environment control number of line positions moved
; to be less than scrolling region.
; All registers are preserved.
;
; Screen scroll up "scroll" lines (text moves up) for terminal emulator use.
     
vtscru	proc	near
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	mov	al,mar_bot		; compute size of scroll
	sub	al,mar_top
	inc	al			; lines in scrolling region
	mov	dl,scroll		; desired scroll
	xor	dh,dh
	cmp	dl,al			; scrolling more than needed?
	jbe	vtscru1			; be = no
	mov	dl,al			; limit scrolling
	mov	scroll,al
vtscru1:or	dl,dl
	jnz	vtscru2	
	jmp	vtscru9			; z = nothing to do

vtscru2:cmp	mar_top,0		; scrolling the top screen line?
	jne	vtscru5			; ne = no, do not save in roll back
	mov	cx,dx			; cx is how many lines
	call	putcirc			; put screen lines in circular buffer
	
	add	linec,cx		; (BDT) increment the current line
	mov	cx,linec		; new current line number
	sub	cx,lcnt			; minus # in buf = qty new lines added
	jc	vtscru3			; c = not extending buffer
	add	lcnt,cx			; (BDT) increment the line counter
vtscru3:mov	cx,lcnt			; (BDT) check: are we
	cmp	cx,lmax			; (BDT) beyond the end?
	jb	vtscru5			; (BDT) b = no
	sub	cx,lmax			; (BDT) compute overflow count
	add	linef,cx		; (BDT) adjust the "first" line
	mov	cx,linef		; (BDT) check: time to wrap?
	cmp	cx,linee		; (BDT) ...
	jb	vtscru4			; (BDT) b = no
	sub	cx,linee		; (BDT) yup
	mov	linef,cx		; (BDT) adjust it
vtscru4:mov	cx,lmax			; (BDT) get the maximum line count
	mov	lcnt,cx			; (BDT) reset the line counter
	mov	linec,cx		; (BDT) reset the current line

vtscru5:mov	di,word ptr vs_ptr	; offset of virtual screen
	mov	cl,vswidth
	mov	al,mar_top		; top line number (from 0)
	mul	cl			; times chars/line
	add	ax,ax			; char + attribute
	add	di,ax			; destination (mar_top)
	mov	al,dl			; number of lines to scroll
	mov	cl,vswidth
	mul	cl			; vswidth * total lines to scroll
	mov	bx,ax			; number of cells to clear
	add	ax,ax			; bytes
	mov	si,di
	add	si,ax			; src is that many bytes down screen
	mov	al,mar_bot		; lines in scrolling region
	sub	al,mar_top
	inc	al
	sub	al,dl			; minus scrolled portion
	mul	cl			; times words per line
	mov	cx,ax			; number of cells to copy
	mov	dh,scbattr		; need this for later (in seg data)
	push	cx			; save number of words for attribute
	push	es
	push	ds
	mov	ax,word ptr vs_ptr+2	; segment of vscreen
	mov	ds,ax
	mov	es,ax
	cld
	rep	movsw			; copy src to dest
	mov	cx,bx			; count of words to clear
	mov	ah,dh			; default attriubte
	mov	al,' '			; filler for clearing a line
	rep	stosw			; store after new src
	pop	ds
	pop	es
					; bx is number of words cleared
	mov	di,word ptr vsat_ptr	; offset of attributes
	mov	cl,((vswidth+1)/2)*2	; char cells per attributes line
	mov	al,mar_top		; top line number (from 0)
	mul	cl			; times cells per line
	shr	ax,1			; two char's of attributes per byte
	add	di,ax			; destination (mar_top)
	mov	si,di

	mov	al,dl			; number of lines to scroll
	mov	cl,((vswidth+1)/2)*2	; cells/line for attributes
	mul	cl			; vswidth * total lines to scroll
	mov	bx,ax			; number of cells to clear
	shr	bx,1			; was char cells, now use bytes
	add	si,bx			; src is that many bytes down screen
	pop	cx			; number of vscreen cells copied
	shr	cx,1			; two cells per byte of attributes
	push	es
	push	ds
	mov	ax,word ptr vsat_ptr+2	; segment of vsatt
	mov	ds,ax
	mov	es,ax
	cld
	rep	movsb			; copy src to dest
	mov	cx,bx			; count of bytes to clear
	xor	al,al			; default attributes of none
	rep	stosb			; store after new src
	pop	ds
	pop	es
	cmp	writemode,0		; use direct screen writing?
	je	vscru5a			; e = yes
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	vscru5b			; ne = no

vscru5a:cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	vtscru8			; ne = no
	call	tekremcursor		; turn off text cursor
vscru5b:mov	dosetcursor,-1		; don't turn on automatically
	mov	al,' '			; write space
	mov	ah,scbattr		; in normal colors
	xor	dl,dl			; at mar_top, left margin
	mov	dh,mar_top		; to set normal text mode for the
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	vscru5d			; ne = no
	call	ttxtchr			; graphics adapter
vscru5d:mov	ax,0600h		; scroll up whole region
	mov	dh,mar_bot		; bottom row
	mov	dl,crt_cols
	cmp	dl,80			; more than physical screen?
	jbe	vscru5e			; be = no
	mov	dl,80
vscru5e:dec	dl			; right most physical col for scroll
	mov	ch,mar_top		; top row of scrolling region
	xor	cl,cl			; left most column
	mov	bh,scbattr		; attributes
	mov	bl,dh
	sub	bl,ch			; region size - 1 line
	jz	vscru2b			; z = region is 1 line, do one scroll
	mov	al,scroll		; number of lines to scroll, from msz
vscru2a:cmp	al,bl			; want to scroll more that than?
	jbe	vscru2b			; be = no
	push	ax
	mov	al,bl			; limit to region - 1 for Windows
	int	screen			;  and do in parts
	pop	ax
	sub	al,bl			; al = amount yet to scroll
	jmp	short vscru2a		; do next part
vscru2b:int	screen			; scroll up that region
	mov	dx,cursor
	mov	dosetcursor,dx		; reminder of where to set cursor
	jmp	short vtscru9

vtscru8:mov	dh,mar_bot		; real text mode
	mov	dl,mar_top		; setup touchup, lines changed
	call	touchup			; touch up real screen
vtscru9:pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
vtscru	endp

; Screen-roll down. Move text down scroll lines, for terminal emulator only.
vtscrd	proc	near
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	bp
	push	es
	les	si,vs_ptr		; source is top line of virtual screen
	mov	al,mar_top		; top margin line (0..)
	mov	cl,vswidth		; chars across vscreen
	mul	cl
	add	ax,ax			; words to bytes
	add	si,ax			; offset of start of top line
	mov	bp,si			; remember top line for later
	mov	cl,mar_bot		; compute number of lines to move
	sub	cl,mar_top
	inc	cl			; qty of lines in region
	mov	ch,scroll
	cmp	ch,cl			; want to scroll more than region?
	jbe	vtscrd1			; be = no
	mov	ch,cl			; set scroll to whole region
	mov	scroll,ch		; remember for attributes
vtscrd1:sub	cl,ch	 		; less lines to be skipped
	mov	bl,ch			; save effective scroll for below
	mov	al,vswidth		; number of character cells
	mul	cl
	mov	cx,ax			; number of words in the movement
	dec	ax			; compute to end word
	add	ax,ax			; number of bytes
	add	si,ax			; go to the end
	mov	di,si
	mov	al,vswidth		; words in a line buffer
	mul	bl			; number of chars dest is below src
	mov	bx,ax			; save number of chars here for clear
	add	ax,ax			; number of bytes (char + attribute)
	add	di,ax			; destination offset
	push	ds
	mov	ax,es
	mov	ds,ax
	std
	rep	movsw			; copy down the lines
	cld
	pop	ds
	mov	di,bp			; fill top line in scrolling region
	mov	ah,scbattr
	mov	al,' '
	mov	cx,bx			; number of char cells to clear
	rep	stosw			; fill top line(s) with spaces
					; do extended attributes the same way
	les	si,vsat_ptr		; source of extended attributes
	mov	al,mar_top		; top margin line (0..)
	mov	cl,((vswidth+1)/2)*2	; attribute cells/line
	mul	cl
	shr	ax,1			; two attributes per byte
	add	si,ax			; offset of start of top line
	mov	bp,si			; remember top line for later
	mov	cl,mar_bot		; compute number of lines to move
	sub	cl,mar_top
	inc	cl			; qty of lines in region
	mov	ch,scroll
	sub	cl,ch	 		; less lines to be skipped
	mov	bl,ch			; save effective scroll for below
	mov	al,((vswidth+1)/2)*2	; number of attribute cells/line
	mul	cl
	shr	ax,1			; two attributes per byte
	mov	cx,ax			; number of bytes in the movement
	dec	ax			; compute to end byte
	add	si,ax			; go to the end
	mov	di,si
	mov	al,((vswidth+1)/2)*2	; number of attribute cells/line
	mul	bl			; number of cells dest is below src
	shr	ax,1			; two attributes per byte
	mov	bx,ax			; save number of bytes here for clear
	add	di,ax			; destination offset
	push	ds
	mov	ax,es
	mov	ds,ax
	std
	rep	movsb			; copy down the lines
	cld
	pop	ds
	mov	di,bp			; fill top line in scrolling region
	xor	al,al			; null attributes for filler
	mov	cx,bx			; number of attributes bytes to clear
	rep	stosb			; fill top line(s) with spaces
	pop	es
	pop	bp
	cmp	writemode,0		; use direct screen writing?
	je	vscrd1			; e = yes
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	vscrd3a			; ne = no
vscrd1:	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	je	vscrd3			; e = yes
	mov	dl,mar_top		; setup touchup, lines changed
	mov	dh,mar_bot
	call	touchup			; touch up real screen
	jmp	short vscrd8

vscrd3:	call	tekremcursor		; turn off text cursor
vscrd3a:mov	dosetcursor,-1		; don't turn on automatically
	mov	al,' '			; write space
	mov	ah,scbattr		; in normal colors
	xor	dl,dl			; at mar_bot, left margin
	mov	dh,mar_bot		; to set normal text mode for the
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	vscrd3b			; ne = no
	call	ttxtchr			; graphics adapter
vscrd3b:mov	ax,0700h		; scroll down whole region
	mov	ch,mar_top		; top margin line
	xor	cl,cl			; left most column
	mov	dh,mar_bot		; bottom margin line
	mov	dl,crt_cols
	cmp	dl,80			; more than physical screen?
	jbe	vscrd3c			; be = no
	mov	dl,80
vscrd3c:dec	dl			; right most physical col for scroll
	mov	bh,scbattr		; attributes
	mov	bl,dh
	sub	bl,ch			; region size - 1 line
	jz	vscrd7 			; z = region is 1 line, do one scroll
	mov	al,scroll		; number of lines to scroll, from msz
vscrd7:	cmp	al,bl			; want to scroll more that than?
	jbe	vscrd2			; be = no
	push	ax
	mov	al,bl			; limit to region-1 for Windows
	int	screen			;  and do in parts
	pop	ax
	sub	al,bl			; get remainder
	jmp	short vscrd7		; do next part
vscrd2:	int	screen			; scroll it down
	mov	dx,cursor
	mov	dosetcursor,dx		; reminder of where to set cursor
vscrd8:	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
vtscrd	endp

; Put the top cx lines from the virtual screen in to the circular buffer
; starting at line index linec (counted from zero, modulo linee).
putcirc	proc	near
	jcxz	putcir6			; z = no lines to save
	cmp	lmax,0			; any buffer space?
	jne	putcir7			; ne = yes, have some
putcir6:ret
putcir7:push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	es
	cld
	mov	pageready,-1		; ems page number currently active
	mov	si,word ptr vs_ptr	; offset of screen buffer
	mov	bx,linef		; index of the first line
	add	bx,linec		; add the current line counter
	dec	bx
putcir1:inc	bx
	cmp	bx,linee		; at the end of the buffer now?
	jb	putcir2			; b = no
	sub	bx,linee		; backup to start of buffer
putcir2:mov	ax,bx			; line index
	call	emsfixup		; do expanded memory conversion work
	mul	ppl			; times paragraphs per line
	add	ax,iniseg		; plus initial seg of buffer
	mov	es,ax			; now we have the segment pointer
	xor	di,di			; buffer offset is always 0
	push	cx			; save the number of lines
	mov	cx,rollwidth		; get the number of characters to move
	push	si			; save starting vscreen offset
	push	ds			; get the offset of the screen
	cld
	mov	ds,word ptr vs_ptr+2	; seg of vscreen
	rep	movsw			; move them
	pop	ds			; restore DS
	pop	si			; vscreen offset
	add	si,vswidth*2		; inc to next vscreen line
	pop	cx			; restore the line count
	loop	putcir1			; go back for more
	pop	es
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	clc
	ret
putcirc	endp

; Get CX lines from the circular buffer, non destructively, starting at
; line index linec (counted from zero, modulo linee) and put them at
; the top of the virtual screen. Fewer lines are written if the buffer
; holds fewer than CX.
getcirc	proc	near
	or	cx,cx			; check on qty
	jnz	getcir0			; nz = some
	ret
getcir0:push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	es
	mov	pageready,-1		; ems page number currently active
	les	di,vs_ptr		; seg and offset of vscreen
	mov	bx,linef		; get the first line pointer
	add	bx,linec		; add the current line counter
	dec	bx
	cld
getcir1:inc	bx
	cmp	bx,linee		; at the end of the buffer now?
	jb	getcir2			; b = no
	sub	bx,linee		; backup to start of buffer
getcir2:mov	ax,bx			; line index
	call	emsfixup		; do expanded memory conversion work
	mul	ppl			; times paragraphs per line
	add	ax,iniseg		; plus initial seg of buffer
	xor	si,si			; initial offset is always 0
	push	cx			; save the number of lines
	mov	cx,rollwidth		; get the number of characters to move
	push	di			; save vscreen offset
	push	ds			; save DS for a tad
	mov	ds,ax			; now we have the segment pointer
	rep	movsw			; move them
	pop	ds			; restore DS
	pop	di			; recover vscreen offset
	add	di,vswidth*2		; next vscreen line
	pop	cx			; restore the line count
	loop	getcir1			; go back for more
	call	repaint			; repaint screen
	pop	es
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	clc
	ret
getcirc	endp

; Convert rollback line number in AX to line number in ems page, and invoke 
; that page. Destroys dx, returns ax as line number in page.
emsfixup proc	near
	cmp	emsrbhandle,0		; EMS in use?
	jg	emsfix1			; g = yes (-1 is not in use)
	ret
emsfix1:xor	dx,dx
	div	lineems			; line number / lines per ems page
	push	bx
	mov	bx,ax			; quotient, page number
	mov	ax,dx			; remainder, line in page
	cmp	bx,pageready		; is this page now present?
	je	emsfix2			; e = yes
	mov	pageready,bx		; remember
	push	ax
	mov	ah,emsmapmem		; map logical page in bx
	xor	al,al			;  to physical page zero
	mov	dx,emsrbhandle		; our ems rollback handle
	int	emsint
	pop	ax			; return ax as line in page
emsfix2:pop	bx
	ret
emsfixup endp

; Repaint screen from the vscreen buffer
repaint	proc	near
	push	dx
	xor	dl,dl			; top row
	mov	dh,crt_lins		; physical screen rows-1, incl status
	call	touchup
	pop	dx
	ret
repaint	endp

; Repaint part of screen from the vscreen buffer, with linescroll offset
; dh is bottom line number, dl is top line number (dh >= dl)
ftouchup proc	far
	call	touchup
	ret
ftouchup endp

touchup	proc	near			; get lines from virtual screen
	cmp	flags.vtflg,ttgenrc	; terminal type of none?
	jne	touch1			; ne = no
	ret
touch1:	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	es
	mov	cl,dh			; last row to change
	sub	cl,dl			; number of lines -1
	cmp	cl,crt_lins		; out of bounds value?
	jbe	touch1b			; be = no
	xor	cl,cl			; stay sane
touch1b:inc	cl			; number of lines to update
	xor	ch,ch
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	je	touch1c			; e = yes, skip text screen update
	test	tekflg,tek_active	; other graphics mode?
	jnz	touch9			; nz = yes, no touchup

	call	scroff			; turn off text screen
	mov	es,tv_segs		; get the segment of the screen
	mov	di,tv_sego		; initial screen offset
touch1c:mov	al,crt_cols		; physical screen width
	mul	dl			; chars into physical screen
	add	ax,ax			; chars to bytes
	add	di,ax			; offset of start of phy update area
	mov	si,word ptr vs_ptr
	mov	al,vswidth		; chars per line
	mul	dl			; ax = bytes to first vscreen line
	add	ax,ax			; chars to bytes
	add	si,ax			; si = starting vscreen line offset
	mov	bl,dl			; top line number
	xor	bh,bh			; index for linescroll
	cld
	push	dx
	mov	dh,dl			; set row into dh, temporarily
touch2:	push	si			; save the current line pointer
	push	cx			; save the number of lines
	mov	cl,crt_cols		; get the number of characters to move
	xor	ch,ch
	mov	al,linescroll[bx]	; get horiz scroll for this line
	add	al,handhsc		; hand done shift
	xor	ah,ah
	add	ax,ax			; char cells to words
	add	si,ax			; offset into vscreen
	cmp	writemode,0		; use direct writing?
	je	touch2a			; e = yes
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	je	touch2a			; e = yes
	call	tchbios			; Bios writing
	jmp	short touch4
touch2a:cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	touch3			; ne = no
	push	es
	mov	es,word ptr vs_ptr+2	; es:si is source of data
	call	ttxtline		; display whole line
	pop	es
	jmp	short touch4

touch3:	push	ds
	mov	ds,word ptr vs_ptr+2	; segment of vscreen
	rep	movsw			; from vscreen+hsc to real screen+0
	pop	ds

touch4:	pop	cx			; restore the line count
	pop	si			; restore the buffer counter
	inc	bx			; for next line
	add	si,vswidth*2		; point to next line
	inc	dh
	loop	touch2			; go back for more
	pop	dx
	cmp	writemode,0		; direct screen writing?
	jne	touch4a			; ne = no, Bios
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	touch5			; ne = no
touch4a:mov	ah,byte ptr cursor+1	; row of cursor
	cmp	ah,dl			; cursor before this line?
	jb	touch9			; b = yes, skip cursor
	cmp	ah,dh			; cursor after this line?
	ja	touch9			; a = yes, skip cursor
	mov	cursorst,0		; say cursor has been zapped off
	mov	dx,cursor
	call	setpcur			; reset the cursor
	jmp	short touch9		; and all done here

touch5:	cmp	tv_mode,0h		; TV active?
	je	touch8			; e = no
	mov	cl,dh			; tell Topview/Desqview
	sub	cl,dl			; number of lines -1
	cmp	cl,crt_lins		; out of bounds value?
	jbe	touch7			; be = no
	xor	cl,cl			; stay sane
touch7:	inc	cl			; number of lines to update
	mov	al,crt_cols		; chars/line
	mul	cl
	mov	cx,ax			; cx = words changed
	call	scrsync			; synch Topview
touch8:	call	scron			; turn on the screen
touch9:	pop	es
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
touchup	endp

; Write screen via Bios. Enter with SI pointing at starting screen buffer
; offset, dh is current screen row, cx has chars to write across a line.

tchbios proc	near
	push	bx
	xor	bh,bh			; video page zero
	push	dx
	mov	ah,3
	int	screen
	mov	temp,dx			; save current cursor
	pop	dx
	mov	cl,crt_cols
	xor	ch,ch
	xor	dl,dl			; column zero
	cld
	push	ds
	mov	ds,word ptr vs_ptr+2	; source is virtual screen buffer
	
tchbios1:push	cx
	mov	ah,2			; set cursor position to dx
	int	screen
	lodsw				; char+attribute
	mov	bl,ah			; attribute
	mov	cx,1			; one char
	mov	ah,9			; write char at cursor position
	int	screen			; do the Bios Int 10h call
	inc	dl			; next column
	pop	cx
	loop	tchbios1
	pop	ds
	push	dx
	mov	dx,temp			; starting cursor position
	mov	ah,2			; set it back there
	int	screen
	pop	dx
	pop	bx
	ret
tchbios	endp

; Character write/read and cursor manipulation routines for terminal emulator
; All registers other than returned values are preserved.

; Read char and attributes under virtual cursor (DH = row, DL = column).
; Returns AL = character, AH = video attributes, CL = logical attribute bit
; pair.
getatch	proc	near
	push	bx
	push	si
	push	es
	mov	al,vswidth		; width of vscreen line
	mul	dh			; count down rows (0..)
	add	al,dl			; add column
	adc	ah,0
	add	ax,ax			; times two for char and attrib
	mov	bx,ax			; address subscript
	les	si,vs_ptr		; main vscreen
	mov	ax,es:[si+bx]		; obtain char and attribute

	push	ax			; save ah attributes
	mov	al,((vswidth+1)/2)*2	; char cells/line for attributes
	mul	dh			; times rows
	add	al,dl			; add column
	adc	ah,0
	shr	ax,1			; two attributes per byte
	mov	bx,ax
	pop	ax
	les	si,vsat_ptr		; extended attributes
	mov	bh,es:[bx+si]		; obtain extended attribute byte
	test	dl,1			; odd column (needs shift)?
	jz	getatch1		; z = no, use lower nibble
	mov	cl,4			; four bits of shift
	shr	bh,cl
getatch1:and	bh,0fh			; have four extended attribute bits
	mov	cl,bh			; return in cl
	pop	es
	pop	si
	pop	bx
	ret
getatch	endp

; Set virtual cursor postion
; DL = column, DH = row, both counted from 0,0 at upper left corner.
; If not displaced, handhsc = 0, then scroll left if virtual > crt_cols.
; If displaced, handhsc != 0, then scroll right if virtual < handhsc.
; For the D463/D470 only, set carry bit (for setatch) if the cursor is off
; the visible screen and horizontal scrolling is disabled.

setpos	proc	near
	push	ax
	push	es
	mov	ax,40h			; look in Bios work area for phy cur
	mov	es,ax
	mov	ax,es:[50h]		; page zero cursor postion is here
	pop	es
	cmp	ax,dx			; same as where we are commanded?
	jne	setpos0			; ne = no, do the work
	pop	ax
	ret
setpos0:push	bx
	push	cx
	push	dx			; save outside virtual cursor
	mov	cl,crt_cols		; physical screen width
	push	cx			; save here
	cmp	inemulator,0		; emulating?
	je	setpos9			; e = no, no virtual screen
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	setpos1			; ne = no
	test	flags.vtflg,ttd463+ttd470 ; doing DG D463/D470 emulation?
	jz	setpos1			; z = no
	mov	bl,dh			; get row
	xor	bh,bh
	cmp	dgwindcomp[bx],0	; is this line compressed?
	je	setpos1			; e = no
	mov	crt_cols,128		; DG graphics, 5 dot chars, 128/line
setpos1:mov	ch,vswidth-1		; leftmost legal margin (207-1)
	sub	ch,crt_cols		; minus screen physical width
	xor	cl,cl		; cl is flag for repainting needed (if != 0)
	xchg	handhsc,cl		; hand-done horiz scroll, clear it
	or	cl,cl			; need to undo it?
	jz	setpos2			; z = no
	call	repaint			; repaint screen without hand scroll
	xor	cl,cl			; remove repaint indicator
setpos2:mov	bl,dh			; current row
	xor	bh,bh
	mov	ah,linescroll[bx]	; current horz scroll

setpos3:mov	al,dl			; virtual column where we ought to be
	sub	al,ah			; virtual - already scrolled	
	jc	setpos4			; c = cursor off screen to the left
	cmp	al,crt_cols		; beyond right physical screen?
	jb	setpos5			; b = no, use this
	mov	cl,1			; say need repaint
	inc	ah
	jc	setpos3a		; c = over did it
	cmp	ah,ch			; going beyond largest scroll?
	jbe	setpos3			; be = no
setpos3a:mov	ah,ch			; yes, stay here
	jmp	short setpos5		; done, do real operation

setpos4:mov	cl,1			; say repaint needed
	mov	ah,dl			; reduce horz scroll

setpos5:or	cl,cl			; repaint needed?
	jz	setpos8			; z = no
	test	flags.vtflg,ttd463+ttd470 ; D463/D470?
	jz	setpos5a		; z = no
	cmp	dghscrdis,0		; D463/D470 horz scroll disabled?
	je	setpos5a		; e = no, check auto vs manual
	stc				; c = do not show on real screen
	jmp	short setposx		; skip screen update

setpos5a:test	vtemu.vtflgop,vshscroll	; horizontal scrolling, manual?
	jnz	setpos9			; nz = yes, else auto

setpos5b:mov	bl,mar_top		; auto scrolling, top row
	xor	bh,bh
	mov	cl,mar_bot
	sub	cl,bl
	xor	ch,ch
	inc	cx			; lines in scrolling region
setpos6:cmp	linescroll[bx],ah	; any change?
	je	setpos7			; e = no
	mov	linescroll[bx],ah	; set scroll for this line
	push	dx
	mov	dl,bl
	mov	dh,bl
	call	touchup			; repaint this line
	pop	dx
setpos7:inc	bx
	loop	setpos6			; do all lines in window

setpos7a:push	ax			; now do status line
	push	si
	mov	cl,byte ptr low_rgt+1	; examine whole screen
	inc	cl			; lines in emulation part
	xor	ch,ch
	mov	bx,cx			; remember for status line
	mov	si,offset linescroll
	mov	ah,[si]			; smallest horizontal shift found
	cld
setpos10:lodsb				; current line scroll to al
	cmp	al,ah			; smaller than smallest?
	ja	setpos11		; a = no
	mov	ah,al			; remember smallest
	or	ah,ah			; zero?
	jz	setpos11a		; can't get any smaller than this
setpos11:loop	setpos10

setpos11a:cmp	linescroll[bx],ah	; status line, need to scroll?
	je	setpos12		; e = already smallest
	mov	linescroll[bx],ah	; modify status line
	push	dx
	mov	dl,bl
	mov	dh,bl
	call	touchup			; redraw status line
	pop	dx
setpos12:pop	si
	pop	ax
setpos8:sub	dl,ah			; virtual - horz scrolled column

setpos9:call	setpcur			; set physical cursor
	clc				; set status for ok to show
setposx:pop	cx
	mov	crt_cols,cl
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
setpos	endp

; Read physical cursor position
; DL = column, DH = row, both counted from 0,0 at upper left corner
; CX = cursor lines
getpcur	proc	near
	push	ax
	push	bx
	mov	ah,3			; get cursor position
	xor	bh,bh			; page 0
	int	screen
	pop	bx
	pop	ax
	ret
getpcur	endp

fgetpcur proc	far
	call	getpcur
	ret
fgetpcur endp

; Set physical cursor postion
; DL = column, DH = row, both counted from 0,0 at upper left corner
setpcur	proc	near
	push	dx
	cmp	dl,crt_cols		; out of bounds?
	jb	setpcur1		; b = ok
	mov	dl,crt_cols		; physical cols on screen
	dec	dl			; count from zero
setpcur1:cmp	inemulator,0		; emulating?
	je	setpcur4		; e = no, no virtual screen
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	setpcur4		; ne = no
	push	ax
	push	es
	mov	ax,40h
	mov	es,ax
	mov	ax,es:[50h]		; current position
	mov	es:[50h],dx		; text page 0 cursor, keep it tracking
	cmp	ax,dx			; same?
	pop	es
	pop	ax
	jne	setpcur2		; not same, draw cursor
	cmp	cursorst,0		; is cursor off now?
	jne	setpcur3		; ne = no, skip redrawing
setpcur2:mov	dosetcursor,dx		; reminder of where to set cursor
	call	tekremcursor		; ensure it's off
setpcur3:pop	dx
	ret

setpcur4:push	ax
	push	es
	mov	ax,40h
	mov	es,ax
	mov	ax,es:[50h]		; current position
	cmp	ax,dx			; same?
	pop	es
	jne	setpcur5		; ne = no
	pop	ax
	pop	dx
	ret
setpcur5:push	bx
	mov	ah,2			; set cursor
	xor	bh,bh			; page 0
	int	screen
	pop	bx
	pop	ax
	pop	dx
	ret
setpcur	endp

; Read char and attributes under physical cursor.
; Returns AL = character, AH = video attributes
getpcha	proc	near
	push	bx
	mov	ah,8			; read char and attributes
	xor	bh,bh			; page 0
	int	screen			; Bios video call
	pop	bx
	ret
getpcha	endp

; Write char and attribute to screen at cursor position, do not move cursor.
; AL = char, AH = video attribute, DL = column, DH = row, CL = logical 
; attribute bits. Does not update physical screen.
qsetatch proc	near
	mov	setnoshow,1		; turn off physical screen update
	jmp	setatch			; call with same args
qsetatch endp

; Write char and attribute to screen at cursor position, do not move cursor.
; AL = char, AH = video attribute, DL = column, DH = row, CL = logical 
; attribute bits. Turns off setnoshow at the end.

setatch	proc	near
	push	bx
	push	es
	push	cx			; save logical attribute
	push	ax			; save char and attribute
	cmp	setnoshow,0		; show on real screen?
	jne	setatc1			; ne = no, do just virtual screen
	call	setpos			; set cursor at dx location
	jc	setatc1			; c = do not show character
	cmp	inemulator,0		; emulating a terminal now?
	je	setatc4			; e = no
	cmp	tekflg,tek_active+tek_sg ; special graphics mode?
	jne	setatc4			; ne = no, text mode
	push	dx
	push	si
	push	di
	mov	bl,dh			; get row
	xor	bh,bh
	sub	dl,linescroll[bx] 	; deduct horizontal scroll
	call	ttxtchr			; display char in graphics mode
	pop	di
	pop	si
	pop	dx
	jmp	short setatc1
setatc4:
	mov	cx,1			; one char
	mov	bl,ah			; attribute
	xor	bh,bh			; page 0
	mov	ah,9			; write char, do not move cursor
	int	screen
setatc1:mov	setnoshow,0		; always reset this automatically
					; write same material to vscreen
	mov	al,vswidth		; width of vscreen line
	mul	dh			; count across rows (0..)
	xor	bh,bh
	mov	bl,dl			; get position
	add	bx,ax			; add column
	add	bx,bx			; times two for char and attrib
	pop	ax			; recover char and attribute
	pop	cx			; recover logical attribute
	cmp	inemulator,0		; in terminal emulator?
	je	setatc2			; e = no, so no virtual screen
	push	di
	les	di,vs_ptr		; virtual screen
	mov	es:[di+bx],ax		; store char and attribute
	push	ax			; save ah attributes
	mov	al,((vswidth+1)/2)*2	; char cells/line for attributes
	mul	dh			; times rows
	add	al,dl			; add column
	adc	ah,0
	shr	ax,1			; two attributes per byte
	mov	bx,ax
	les	di,vsat_ptr		; attributes nibble array
	mov	al,es:[bx+di]		; get two nibbles
	mov	ah,cl			; save extended attribute nibble
	xor	cl,cl			; shift amount, assume zero
	test	dl,1			; is this an odd column?
	jz	setatc3			; z = no
	mov	cl,4			; use only four lowest order bits
setatc3:ror	al,cl			; bring pair to low order
	and	al,not 0fh		; remove old
	and	ah,0fh			; just the new
	or	al,ah			; put new in place
	rol	al,cl			; rotate back
	mov	es:[bx+di],al		; store again
	pop	ax
	pop	di
setatc2:pop	es
	pop	bx
	ret
setatch	endp

; Get bold video attribute bit
; Returns AH = bold attribute bit (0 if not bold)
getbold	proc	near
	and	ah,att_bold
	test	flags.vtflg,ttd463+ttd470 ; D463/D470?
	jnz	getbold1		; nz = yes
	xor	ah,userbold		; invert with user bold
getbold1:ret
getbold endp

; Set bold video attribute bit, current video attribute supplied in AH
setbold proc	near
	or	ah,att_bold
	test	flags.vtflg,ttd463+ttd470 ; D463/D470?
	jnz	setbold1		; nz = yes
	xor	ah,userbold		; invert with user bold
setbold1:ret
setbold endp

; Clear bold video attribute bit, current video attribute supplied in AH
clrbold	proc	near
	and	ah,not att_bold
	test	flags.vtflg,ttd463+ttd470 ; D463/D470?
	jnz	clrbold1		; nz = yes
	or	ah,userbold		; invert with user bold
clrbold1:ret
clrbold	endp

; Get blink video attribute bit
; Returns AH = blink attribute bit
getblink proc	near
	and	ah,att_blink
	ret
getblink endp

; Set blink video attribute bit, current video attribute supplied in AH
setblink proc	near
	or	ah,att_blink
	ret
setblink endp

; Clear blink video attribute bit, current video attribute supplied in AH
clrblink proc	near
	and	ah,not att_blink
	ret
clrblink endp

; Set extended attribute for protection in extattr and in CL.
setprot	proc	near			; set protected mode
	or	extattr,att_protect
	or	cl,att_protect		; and in cl
	ret
setprot	endp

; Clear extended attribute for protection in extattr and in CL.
clrprot	proc	near			; clear protected mode
	and	extattr,not att_protect
	and	cl,not att_protect
	ret
clrprot endp

; Get underline video attribute bit from extattr
; Returns CL = underline attribute bit
getunder proc	near
	mov	cl,extattr		; get extended attribute
	and	cl,att_uline		; return underline status bit
	ret
getunder endp

; Set underline video attribute bit, current video attribute supplied in AH
; and extended attributes in extattr. Returns new AH and extattr in CL.
setunder proc	near
	test	extattr,att_uline	; extended attributes, on already?
	jz	setund1			; z = no
	ret				; else do nothing
setund1:or	extattr,att_uline	; set underline attribute for MSZ
	or	cl,att_uline
	cmp	crt_mode,7		; monochrome display adapter mode?
	je	setund6			; e = yes, otherwise xor video
	push	bx
	push	dx
	mov	bh,al			; preserve possible char in al
	mov	dl,scbattr		; screen fill
	and	dl,70h			; background colors
	mov	bl,extattr		; extended attributes
	and	bl,att_rev		; per char reversed video
	mov	dh,ah			; current character attributes
	and	dh,not 77h		; blink/bold attributes only
	and	ah,77h			; colors only
	mov	al,ah
	shr	al,1
	shr	al,1
	shr	al,1
	shr	al,1			; background to lower nibble
	and	ah,7			; foreground only
	or	bl,bl			; reversed video attribute?
	jz	setund3			; z = no, normal
	xchg	ah,al			; real background color to al
setund3:xor	al,ah			; modify background
	or	dl,dl			; case of black background?
	jnz	setund4			; nz = no
	mov	al,ah
	dec	al
	and	al,7			; background goes to (foreground-1)/8
	or	al,al			; still black?
	jnz	setund4			; nz = no
	mov	al,7			; force non-black (white foreground)
setund4:shl	al,1			; background to high nibble
	shl	al,1
	shl	al,1
	shl	al,1
	or	ah,al			; or new background
	or	bl,bl			; per char reversal?
	jz	setund5			; z = no
	rol	ah,1			; yes, flip fore/background again
	rol	ah,1
	rol	ah,1
	rol	ah,1
setund5:or	ah,dh			; restore blink and bold
	pop	dx
	mov	al,bh			; restore possible char
	pop	bx
	ret
setund6:call	brkatt			; break apart attributes
	or	al,att_uline		; set underline bit
	call	addatt			; reassemble attributes into ah
	ret
setunder endp

; Clear underline video attribute bit, current video attribute supplied in AH
; and extended attributes in extattr. Returns new AH and extattr in CL.
clrunder proc	near
	test	extattr,att_uline	; extended attributes, off already?
	jnz	clrund1			; nz = no
	ret				; else do nothing
clrund1:and	extattr,not att_uline	; clear underline attribute for MSZ
	and	cl,not att_uline
	cmp	crt_mode,7		; monochrome display adapter mode?
	je	clrund6			; e = yes, otherwise reverse video
	push	bx
	push	dx
	mov	bh,al			; save possible char in al
	xor	bl,bl
	mov	dl,scbattr		; screen fill
	and	dl,70h			; background colors
	mov	bl,extattr		; extended attributes
	and	bl,att_rev		; per char reversed video
	mov	dh,ah			; current char attributes
	and	dh,not 77h		; blink/bold attributes only
	and	ah,77h			; colors only
	mov	al,ah
	shr	al,1
	shr	al,1
	shr	al,1
	shr	al,1			; background to lower nibble
	and	ah,7			; foreground only
	or	bl,bl			; reversed video attribute?
	jz	clrund3			; z = no, normal
	xchg	ah,al			; real background color to al
clrund3:or	dl,dl			; case of black background?
	jz	clrund4			; z = yes, leave it black (empty)
	xor	al,ah
	shl	al,1			; background to high nibble
	shl	al,1
	shl	al,1
	shl	al,1
	or	ah,al			; or in new background
clrund4:or	bl,bl			; per char reversal?
	jz	clrund5			; z = no
	rol	ah,1			; yes, reverse nibbles again
	rol	ah,1
	rol	ah,1
	rol	ah,1
clrund5:or	ah,dh			; restore blink and bold
	pop	dx
	mov	al,bh			; restore possible char
	pop	bx
	ret	
clrund6:call	brkatt			; break apart attributes
	and	al,not att_uline	; turn off underline bit
	call	addatt			; reassemble attributes
	ret
clrunder endp

; Compute reversed video attributes, given displayables in AH and extended
; in extattr. Returns new attribute in AH and CL holding new extattr
setrev	proc	near
	test	extattr,att_rev		; reversed now?
	jnz	setrev1			; nz = yes
	call	revideo			; do reversal
	or	extattr,att_rev		; update extended attribute
	or	cl,att_rev
setrev1:ret
setrev	endp

; Compute un-reversed video attributes, given displayables in AH and extended
; in extattr. Returns new attribute in AH and CL holding new extattr
clrrev	proc	near
	test	extattr,att_rev		; reversed now?
	jz	clrrev1			; z = no
	call	revideo			; do reversal
	and	extattr,not att_rev	; update extended attribute
	and	cl,not att_rev		; update extended attribute
clrrev1:ret
clrrev	endp


; Compute reversed video attribute byte. Normally preserves blink/bold.
; Enter with AH = video attribute byte, returns new attribute byte in AH.
revideo	proc	near
	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
	ret
revideo	endp

; 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.
; enter with	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,ah			; copy displayables
	and	al,(att_blink+att_bold)	; get modifiers
	and	ah,not (att_bold+att_blink) ; strip blink/bold, leave color
	cmp	crt_mode,7		; monochrome display adapter mode?
	jne	brkat2			; ne = no, cut this short for color
	test	ah,att_low_mask		; are any of these on?
	jnz	brkat1			; nz = yes, can't be underline
	test	ah,att_underline	; underline?
	jz	brkat2			; z = no, some kind of reverse video
	or	al,att_underline	; say underline
	test	ah,70h 			; reverse video + underline?
	jz	brkat1			; z = no, fix up low nibble
	and	ah,not 07h		; clear the underline bit in ah
	ret
brkat1: or	ah,att_normal		; normal, turn on all normal bits
brkat2:	ret

; This routine builds a cursor attribute given the base attribute for the
; screen background and the "extra" attributes we want (blink, etc.).
; enter with	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			; z = no, no need for hack
	cmp	crt_mode,7		; monochrome display adapter mode?
	jne	addat1			; ne = no, cut this short for color
	and	ah,not att_low_mask	; clear background colors
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.

revscn	proc	near
	push	ax
	push	bx
	push	cx
	push	dx
	mov	dh,byte ptr low_rgt+1	; compute last screen offset in ax
	inc	dh			; one more row to catch mode line
	mov	dl,vswidth		; logical screen buffer
	dec	dl			; and we count from 0
	call	scrloc			; get screen offset into ax
	mov	cx,ax			; save it in cx for a minute
	add	cx,2
	sar	cx,1			; in 16-bit words please
	push	di			; Save some more acs
	push	es
	les	di,vs_ptr		; seg and offset of vscreen
	cld
revsc1:	mov	ax,es:[di]		; fetch a word
	mov	bl,al			; save the character
	call	revideo			; get reversed video attributes (AH)
	call	addatt			; put attributes back together
	mov	al,bl			; restore character
	stosw				; stuff into screen memory
	loop	revsc1			; loop for entire screen
	pop	es			; restore segment register
	pop	di			; and destination index
	pop	dx
	pop	cx
	pop	bx
	call	repaint
	pop	ax
	ret
revscn	endp

; Set coloring attributes.
; Enter with AH holding current video attribute byte,
; BL holding ANSI color code (30-37 or 40-47) where 30's are foreground,
; 40's are background. ANSI colors are 1 = red, 2 = green, 4 = blue.
; Return new attribute byte in AH.

setcolor proc	near
	test	extattr,att_rev		; normal video currently?
	jz	setcol0			; z = yes
	mov	al,ah			; make a copy
	and	ax,7788h		; strip bold,blink, keep both in al
	rol	ah,1			; get colors in right parts
	rol	ah,1			;  of ah = back, al = foreground
	rol	ah,1
	rol	ah,1
	call	setcol0			; set fore or background color
	rol	ah,1			; reverse coloring again
	rol	ah,1
	rol	ah,1
	rol	ah,1
	or	ah,al			; put back blink and bold
	ret

setcol0:cmp	bl,30			; ANSI color series?
	jb	setcol7			; b = no
	cmp	bl,37			; foreground set (30-37)?
	ja	setcol4			; 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	setcol1			; z = no
	or	ah,4			; IBM red foreground bit
setcol1:test	bl,2			; ANSI & IBM green?
	jz	setcol2			; z = no
	or	ah,2			; IBM green foreground bit
setcol2:test	bl,4			; ANSI blue?
	jz	setcol3			; z = no
	or	ah,1			; IBM blue foreground bit
setcol3:ret

setcol4:cmp	bl,40			; background color set?
	jb	setcol7			; b = no
	cmp	bl,47			; background set is 40-47
	ja	setcol7			; 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	setcol5			; z = no
	or	ah,40h			; IBM red background bit
setcol5:test	bl,2			; ANSI & IBM green?
	jz	setcol6			; z = no
	or	ah,20h			; IBM green background bit
setcol6:test	bl,4			; ANSI blue?
	jz	setcol7			; z = no
	or	ah,10h			; IBM blue background bit
setcol7:ret
setcolor endp

; Save terminal emulator, session is in BX.
; Delete older save buffer for this session, so that compressed vscreen
; can be saved properly.
termswapout proc far
	cmp	bx,6			; legal session number?
	jb	termso0			; b = yes
	stc
	ret
termso0:push	ax
	push	bx
	push	cx
	push	si
	push	di
	shl	bx,1			; to words
	mov	temp,bx			; save session ident
	cmp	tsave[bx],0		; have a storage buffer?
	je	termso9			; ne = no, create one now
	shr	bx,1			; get original BL session indicator
	call	termswapdel		; delete old save area
	shl	bx,1			; restore word indexing
termso9:call	getvssize		; get size of vscreen, compressed
	mov	ax,bx			; save bx
	call	getvasize		; size of attributes
	add	bx,ax
	add	bx,savexlen		; plus length of MSX save area
	add	bx,saveylen		; plus MSY save area
	add	bx,savezlen		; plus MSZ area
	add	bx,saveplen		; plus parser in MSSCMD
	add	bx,saveulen		; plus MSU area
	add	bx,saveglen		; plus MSG area
	add	bx,15			; round up
	mov	cl,4
	shr	bx,cl			; convert to paragraphs
	mov	cx,bx			; save request in cx
	mov	ah,alloc		; please, more space
	int	dos			; paragraph to ax, num paras to bx
	cmp	bx,cx			; given vs wanted
	jae	termso1			; ae = got it
	pop	di
	pop	si
	pop	cx
	pop	bx
	pop	ax
	stc				; fail
	ret
termso1:
	push	temp
	push	ax
	call	tekend			; exit graphics mode
	pop	ax
	pop	temp
	mov	bx,temp			; get session number (sescur)
	mov	tsave[bx],ax		; save starting paragraph
	push	es
	mov	cx,ds
	mov	es,cx
	mov	cx,size flginfo		; length of saved flags array
	mov	di,offset saveflag	; saved array
	mov	si,offset flags		; working array
	rep	movsb			; restore
	mov	ax,tsave[bx]		; starting paragraph for save area
	mov	es,ax			; save area is destination
	xor	di,di			; offset of save area

; virtual screen is saved as structure
; scr-len	dw	text screen length (typically 24 lines)
; with the items below repeated for each line (scr-len total lines)
; per-line	dw	saved chars on this line
;		dw	per-line dup (char & attribute)
; with the last saved char on each line being repeated to endofline on screen
	push	bx			; virtual screen saving
	mov	cl,byte ptr low_rgt+1	; number of text lines - 1
	inc	cl
	cmp	flags.modflg,2		; is mode line owned by host?
	jne	termso3a		; ne = no
	inc	cl			; yes, add it to the save material
termso3a:xor	ch,ch
	mov	ax,cx
	cld
	stosw				; store screen length as first word
	xor	bx,bx			; line counter
	mov	si,word ptr vs_ptr	; offset of vscreen
termso3:push	cx			; save line loop counter
	mov	cx,word ptr rdbuf[bx]	; get number of saveable chars on line
	mov	ax,cx			; store char count as first word
	stosw
	mov	ax,word ptr vs_ptr+2	; get vscreen segment
	push	si
	push	ds
	mov	ds,ax
	rep	movsw			; copy saveable chars
	pop	ds
	pop	si
	pop	cx			; recover line counter
	add	bx,2			; next line, get length info
	add	si,vswidth*2		; next line, offset of vscreen line
	loop	termso3
	pop	bx			; end of vscreen saving
					;
	push	bx			; virtual screen saving
	mov	cl,byte ptr low_rgt+1	; number of text lines - 1
	inc	cl
	cmp	flags.modflg,2		; is mode line owned by host?
	jne	termso3b		; ne = no
	inc	cl			; yes, add it to the save material
termso3b:xor	ch,ch
	mov	ax,cx
	cld
	stosw				; store screen length as first word
	xor	bx,bx			; line counter
	mov	si,word ptr vsat_ptr	; offset of vsattr
termso7:push	cx			; save line loop counter
	mov	cx,word ptr rdbuf[bx+120]; get num of saveable bytes on line
	mov	ax,cx			; store char count as first word
	stosw
	mov	ax,word ptr vsat_ptr+2	; get vsattr segment
	push	si
	push	ds
	mov	ds,ax
	shr	cx,1			; get odd byte count info
	jnc	termso7a		; nc = even count
	movsb
termso7a:rep	movsw			; copy saveable bytes
	pop	ds
	pop	si
	pop	cx			; recover line counter
	add	bx,2			; next line, get length info
	add	si,(vswidth+1)/2	; next line, offset of vsattr line
	loop	termso7
	pop	bx			; end of vsattr saving
					;
	mov	si,offset saveyoff	; offset of MSY save area
	mov	cx,saveylen		; length of MSY save area
	cld
	shr	cx,1			; even/odd?
	jnc	termso4			; nc = even
	movsb				; the odd byte
termso4:rep	movsw
	mov	si,offset savezoff	; offset of MSZ save area
	mov	cx,savezlen		; length of MSZ save area
	shr	cx,1
	jnc	termso5
	movsb
termso5:rep	movsw
	mov	si,offset savexoff	; offset of MSX save area
	mov	cx,savexlen		; length of MSX save area
	cld
	cli				; cautious about serial ints
	shr	cx,1			; even/odd?
	jnc	termso6			; nc = even
	movsb				; the odd byte
termso6:rep	movsw
	sti
	mov	si,offset savepoff	; offset of MSSCMD parser save area
	mov	cx,saveplen		; length of the area
	shr	cx,1
	jnc	termso6a
	movsb
termso6a:rep	movsw
	mov	si,offset saveuoff	; offset of MSUIBM kbd save area
	mov	cx,saveulen		; length of the area
	shr	cx,1
	jnc	termso6b
	movsb
termso6b:rep	movsw
	mov	si,offset savegoff	; offset of MSG save area
	mov	cx,saveglen		; length of MSG save area
	shr	cx,1			; graphics mode exited above
	jnc	termso6c
	movsb
termso6c:rep	movsw
	pop	es
	mov	ax,100h			; assume using 80 col screen
	cmp	dos_cols,80		; startup screen width
	jbe	termso8			; be = assume 80 columns
	inc	al			; say do 132 columns
termso8:push	vtemu.vtflgop
	or	vtemu.vtflgop,vscompress ; turn off compressed mode
	call	chgdsp			; reset display width to startup
	pop	vtemu.vtflgop
	pop	di
	pop	si
	pop	cx
	pop	bx
	pop	ax
	clc
	ret
termswapout endp

; Restore terminal emulator, session is BX
; Delete save buffer after restoration.
termswapin proc	far
	cmp	bx,6			; valid session?
	jb	termsi0			; b = yes
	stc
	ret
termsi0:push	bx
	shl	bx,1			; to words
	cmp	tsave[bx],0		; have a storage buffer?
	pop	bx
	jne	termsi1			; ne = yes, use it
	mov	vtinited,0		; say not inited
	stc				; fail
	ret

termsi1:push	ax
	push	bx
	push	cx
	push	si
	push	di
	push	es			; virtual screen restore
	test	tekflg,tek_active	; current graphics mode status
	jz	tswapin1a		; z = not in graphics mode
	push	bx
	call	tekend
	pop	bx
tswapin1a:
	les	di,vs_ptr		; seg and offset of vscreen
	shl	bx,1			; to words
	mov	ax,tsave[bx]		; starting paragraph of save area
	push	ds
	mov	ds,ax			; source segment is save area
	xor	si,si			; source offset is always zero
	cld
	lodsw				; get screen length
	mov	cx,ax			; counter of vscreen lines to do
tswapi2:push	cx			; save line counter
	lodsw				; get count of saved chars of line
	dec	ax			; omit repeated char til next step
	mov	cx,ax			; count for saved char writes
	rep	movsw			; copy saved chars except last one
	mov	cx,vswidth		; total line width (chars)
	sub	cx,ax			; minus those done
	lodsw				; get last char (this repeats to end)
	rep	stosw			; repeat last char
	pop	cx			; recover line counter
	loop	tswapi2			; do all text lines (omit status)
	pop	ds			; restore DS, SI is ready for nxt grp
					; end of virtual screen restoration
					; attributes, vsatt, for vscreen
	les	di,vsat_ptr		; seg and offset of vsatt
	mov	ax,tsave[bx]		; starting paragraph of save area
	push	ds
	mov	ds,ax			; source segment is save area
	lodsw				; get screen length
	mov	cx,ax			; counter of vsattr lines to do
tswapi7:push	cx			; save line counter
	lodsw				; get count of saved bytes of line
	dec	ax			; omit repeated byte til next step
	mov	cx,ax			; count for saved byte writes
	shr	cx,1			; do odd byte copy
	jnc	tswapi7a		; nc = even count
	movsb
tswapi7a:rep	movsw			; copy saved bytes except last one
	mov	cx,(vswidth+1)/2	; total line width (bytes)
	sub	cx,ax			; minus those done
	lodsb				; get last byte (this repeats to end)
	rep	stosb			; repeat last byte
	pop	cx			; recover line counter
	loop	tswapi7			; do all text lines (omit status)
	pop	ds			; restore DS, SI is ready for nxt grp
					; end of virtual screen restoration

	mov	ax,ds			; regular data seg "data"
	mov	es,ax			; new data seg
	mov	di,offset saveyoff	; offset of MSY save area
	mov	cx,saveylen		; length of MSY save area
	mov	ax,tsave[bx]		; starting paragraph of save area
	push	ds
	mov	ds,ax			; source segment is save area
	cld
	shr	cx,1			; even/odd?
	jnc	termsi3			; nc = even
	movsb				; the odd byte
termsi3:rep	movsw
	mov	di,offset savezoff	; offset of MSZ save area
	mov	cx,es:savezlen		; length of MSZ save area
	shr	cx,1
	jnc	termsi4
	movsb
termsi4:rep	movsw
	mov	di,offset savexoff	; offset of MSX save area
	mov	cx,es:savexlen		; length of MSX save area
	cli				; cautious about serial ints
	shr	cx,1
	jnc	termsi5
	movsb
termsi5:rep	movsw
	sti
	mov	di,offset savepoff	; offset of MSSCMD parser area
	mov	cx,es:saveplen		; length
	shr	cx,1
	jnc	termsi6
	movsb
termsi6:rep	movsw
	mov	di,offset saveuoff	; offset of MSUIBM kbd area
	mov	cx,es:saveulen		; length
	shr	cx,1
	jnc	termsi6a
	movsb
termsi6a:rep	movsw
	mov	di,offset savegoff	; offset of MSGIBM area
	mov	cx,es:saveglen		; length
	shr	cx,1
	jnc	termsi8
	movsb
termsi8:rep	movsw
	pop	ds
	mov	cx,ds
	mov	es,cx
	mov	cx,size flginfo		; length of saved flags array
	mov	si,offset saveflag	; saved array
	mov	di,offset flags		; working array
	rep	movsb			; restore
	mov	ah,savattr		; get saved coloring
	mov	scbattr,ah		; replace what DOS may have used
	and	tekflg,not tek_active	; say graphics is not active
	pop	es
	pop	di
	pop	si
	pop	cx
	pop	bx
	pop	ax
	call	termswapdel		; delete this saved area, BL=session
	clc
	ret
termswapin endp

; Remove saved terminal emulator buffers, BX is sescur (-1 means all)
termswapdel proc far
	push	ax
	push	bx
	shl	bx,1			; to words
	xor	ax,ax			; clearing indicator
	xchg	ax,tsave[bx]		; paragraph of save area
	or	ax,ax			; anything there?
	jnz	tswapd1			; nz = yes
	pop	bx
	pop	ax
	stc				; fail
	ret
tswapd1:push	es
	mov	es,ax			; set paragraph to es for DOS
	mov	ah,freemem
	int	dos
	pop	es
	pop	bx
	pop	ax
	clc				; succeed
	ret
termswapdel endp

; Examine vscreen line by line. Count number of characters by excluding the
; trailing repetitions (keep first example) on each line, sum them. Add to 
; the sum a word per line to hold the count of such characters and one more 
; word to hold the screen length.
; Return the number of bytes in register bx for malloc-ing.
getvssize proc	near
	push	cx
	push	dx
	push	di
	push	es
	les	di,vs_ptr		; pointer to vscreen
	xor	bx,bx			; line counter
	mov	cl,crt_lins		; lines on screen
	xor	ch,ch
	mov	dx,cx			; accumulated count <cnt, line>
	inc	dx			; count screen size word itself
	add	di,(vswidth - 1) * 2	; offset of last char on the line
getvssi1:push	cx			; save line counter
	mov	cx,vswidth-1		; chars on line - 1
	mov	ax,es:[di]		; get last char+attrib on the line
	push	di
	sub	di,2
	std				; scan backward
	repe	scasw			; scan while equal (trim trailing rpt)
	cld
	pop	di
	je	getvssi2		; e = ended on all same char
	inc	cx			; ne case gobbles extra char
getvssi2:inc	cx			; count the trailing char
	mov	word ptr rdbuf[bx],cx	; store number of words here
	add	dx,cx			; accumulate count of chars
	add	bx,2			; next line
	add	di,vswidth*2		; end of next line
	pop	cx			; line counter
	loop	getvssi1

	add	dx,dx			; chars to bytes accumulated
	mov	bx,dx			; return it in bx
	pop	es
	pop	di
	pop	dx
	pop	cx
	ret
getvssize endp

; Examine vsattr line by line. Count number of attributes by excluding the
; trailing repetitions (keep first example) on each line, sum them. Add to 
; the sum a word per line to hold the count of such characters and one more 
; word to hold the screen length. Stores temp length indicator in
; words rdbuf+120 et seq (one word per line).
; Return the number of bytes in register bx for malloc-ing.
getvasize proc	near
	push	ax
	push	cx
	push	dx
	push	di
	push	es
	les	di,vsat_ptr		; pointer to vsattr
	xor	bx,bx			; line counter
	mov	cl,byte ptr low_rgt+1	; lines on normal screen - 1
	add	cl,2			; include status line
	xor	ch,ch
	mov	dx,cx			; accumulated count <cnt, line>
	inc	dx			; count screen size word itself
	add	dx,dx			; convert to bytes used
	add	di,(((vswidth+1)/2) -1) ; offset of last attrib on the line
getvasi1:push	cx			; save line counter
	mov	cx,(((vswidth+1)/2) -1)	; bytes on line - 1
	mov	ax,es:[di]		; get last attribute byte on the line
	push	di
	dec	di
	std				; scan backward
	repe	scasb			; scan while equal (trim trailing rpt)
	cld
	pop	di
	je	getvasi2		; e = ended on all same byte
	inc	cx			; ne case gobbles extra byte
getvasi2:inc	cx			; count the trailing byte
	mov	word ptr rdbuf[bx+120],cx; store number of bytes here
	add	dx,cx			; accumulate count of bytes
	add	bx,2			; next line
	add	di,(vswidth+1)/2	; end of next line
	pop	cx			; line counter
	loop	getvasi1
	mov	bx,dx			; return bytes needed in bx
	pop	es
	pop	di
	pop	dx
	pop	cx
	pop	ax
	ret
getvasize endp

;
; CHKDSP - procedure to check for hardware support of 132 cols
;  Supported hardware:
;  ATI EGA and VGA Wonder
;  AT&T
;  Everex Viewpoint EV-659, FVGA-673, EV-678, Micro Enhancer Deluxe
;  IBM XGA
;  Paradise AutoSwitch EGA Mono, VGA Professional, VGA Plus, VGA Plus 16
;  STB VGA/EM (Tseng TVGA)
;  STB VGA/EM Plus (Tseng 4000), VGA/EM-16, VGA/EM-16 Plus
;  Tseng Labs EVA board w/132-col kit installed
;  Tseng Labs UltraPAK mono/Herc board w/132 column modes.
;  Tseng Labs ET4000 SVGA.
;  VESA compatible Bios'.
;  Video 7 Vega Deluxe w/ 132X25.COM driver installed and VGA board.
; The routine checks for the presence of a 132-column-capable adapter. If
; one is found its handler executes the desired mode setting and returns
; carry clear; it returns carry set otherwise.
; Adding new boards - place an identification string in the data segment,
; construct a mode setting routine and insert it in the call list below
; (setting 132 column mode is byte AL non-zero). Byte AH is non-zero to
; avoid saving old screen and running scrini; it is used to set the screen
; width when starting/exiting Connect mode
;
chgdsp	proc	near
	or	al,al			; 80 column mode?
	jnz	chgdsg1			; nz = no, want 132 cols
	test	tekflg,tek_active	; graphics mode active?
	jz	chgdsp_start		; z = no
	push	ax
	push	dx
	call	tekend			; exit special graphics
	call	scrmod			; update video mode info
	pop	dx
	pop	ax
	jmp	short chgdsp_start	; set 80 col mode

chgdsg1:test	vtemu.vtflgop,vscompress ; allowed to use graphics for it?
	jnz	chgdsp_start		; nz = no, use 132 column text mode
	cmp	tekflg,tek_active+tek_sg ; special graphics mode active?
	je	chgdsg3			; e = yes, no change needed
	mov	cl,byte ptr low_rgt+1	; examine whole screen
	add	cl,2			; lines in emulation part + status
	xor	ch,ch
	xor	bx,bx
chgdsg2:mov	dgwindcomp[bx],1	; set compressed mode flag non-zero
	inc	bx
	loop	chgdsg2
	call	dgsettek		; setup special graphics mode
	mov	byte ptr low_rgt,131	; 132 columns in special graphics
	mov	crt_cols,128		; but 128 physical columns
chgdsg3:ret

chgdsp_start:
	push	es			; save all we use
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	mov	temp,ax			; save set/reset flag from msz
	mov	ax,sp			; do push sp test for XT vs AT/386
	push	sp			; XT pushes sp-2, AT's push old sp
	pop	cx			; recover pushed value, clean stack
	xor	ax,cx			; same?
	jne	chgdspnw		; ne = no, XT. Don't do Int 2fh
	test	tv_mode,10h		; DESQview active?
	jz	chgdspndv		; z = no
	jmp	chgdsx1			; exit without screen change
chgdspndv:
	mov	ax,1683h		; Windows 3, get current virt machine
	int	2fh
	cmp	ax,1683h		; virtual machine, if any
	je	chgdspnw		; e = no Windows, do the video mode
	jmp	chgdsx1			; exit without screen change
chgdspnw:mov	ax,temp
	cmp	crt_cols,80		; are we narrow?
	jbe	chgds3			; be = narrow width now
	or	al,al			; resetting to narrow width?
	jz	chgds4			; z = yes, do it
	jmp	chgdsx1			; else we are there now
chgds3:	or	al,al			; resetting to narrow width?
	jnz	chgds4			; nz = no, setting to wide
	jmp	chgdsx1			; narrow width, we are there now
chgds4:	or	ah,ah			; are we connected now?
	jnz	chgds0			; nz = no, skip flow control etc
	mov	ah,flowoff		; get xoff
	or	ah,ah			; flow control?
	jz	chgds4a			; z = none
	call	foutchr			; send it
chgds4a:cmp	byte ptr temp+1,0	; exiting Connect mode?
	jne	chgds0			; ne = yes
	mov	ax,200			; wait 200 millisec before video tests
	call	fpcwait			; so don't mix screen and port intrpts

chgds0:	call	ckteva			; try Tseng Labs EVA
	jnc	chgds1			; nc = found
	call	ckstbv			; try STB VEGA/EM
	jnc	chgds1			; nc = found
	call    ckv7vd			; try Video 7 EGA Deluxe and VGA
	jnc	chgds1			; nc = found
	call    ckatiw			; try ATI EGA Wonder
	jnc	chgds1			; nc = found
	call    ckevrx                  ; try Everex Micro Enhancer Deluxe
	jnc     chgds1                  ; nc = found
	call	ckevga			; try Everex EVGA-673
	jnc     chgds1                  ; nc = found
	call	ckatt			; ATT boards
	jnc	chgds1			; nc = found
	call	chkpa			; Paradise EGA/VGA boards
	jnc	chgds1			; nc = found
	call	chkvesa			; VESA compatibles
	jnc	chgds1			; nc = found
	call	ckxga			; IBM XGA
	jnc	chgds1			; nc = found
	mov	si,offset cols80	; name of 80 column file
	cmp	byte ptr temp,0		; setting 80 cols?
	je	chgdsx2			; e = yes
	mov	si,offset cols132	; use 132 column file
chgdsx2:mov	di,offset decbuf	; a temp buffer for path= usage
	call	fstrcpy
	mov	ax,di			; spath wants ptr in ax
	call	fspath
	jc	chgdsx			; c = file not found
	mov	si,ax			; crun wants ptr in si
	call	fcrun			; run the batch file, si = filespec
	call	fserini			; reengage serial port, mode changes
	mov	ax,0c06h		; clear kbd buffer and do function
	mov	dl,0ffh			; console input
	int	dos			; discard character(s)
					; Perform mode change
chgds1:	cmp	byte ptr temp+1,0	; do without serial port xon/xoff?
	jne	chgdsx1			; ne = yes
	cmp	flags.modflg,1		; is mode line enabled?
	jbe	chgdsx			; be = yes, and off or locally owned
	mov	flags.modflg,1		; remove foreign ownership
chgdsx:	mov	ah,flowon		; get flow-on byte
	or	ah,ah			; using flow control?
	jz	chgdsx1			; z = no
	call	foutchr			; send it
chgdsx1:call	scrmod			; pick up current screen size
	pop	di			; restore what we saved
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	pop	es
	ret				; return to caller
     
; Individual tests for various 132-column boards
					; Tseng LABS EVA, UltraPAK, ET4000
ckteva: mov	ax,0c000h		; seg addr for EVA
	mov	es,ax			; set into es register
	mov	di,76h			; offset of board's string
	lea	si,tsngid		; validation string
	mov	cx,tsnglen		; length of validiation string
	cld
	repe	cmpsb			; compare strings
	je	ckteva2			; e = strings match
	mov	ax,4d00h		; check for UltraPAK mono driver
	int	screen
	cmp	ax,5aa5h		; driver signature?
 	jne	ckteva4			; ne = no
	mov	ax,7			; default to mono (7) for this board
	cmp	byte ptr temp,0		; setting 132 columns?
	je	ckteva1			; e = resetting to normal
	mov	ax,18h			; set to 132 cols (Set Mode 18H)
ckteva1:int	screen
	clc				; carry clear means success
	ret
					; an EVA board - check for 132 col kit
ckteva2:cmp	byte ptr es:099h,0	; check 132 col kit installed
	jne	catfnd			; ne = installed, do the mode change
ckteva3:stc				; indicate adapter not present
	ret				; and exit

ckteva4:mov	dx,03cdh		; ET4000 test
	in	al,dx			; Segment Select Register, get value
	push	ax
	xor	al,15h			; create test condition
	jmp	$+2
	jmp	$+2
	out	dx,al			; set condition
	jmp	$+2
	jmp	$+2
	mov	ah,al			; save condition
	in	al,dx			; get new condition
	jmp	$+2
	jmp	$+2
	cmp	ah,al			; did it work (same)?
	pop	ax
	out	dx,al			; restore original condition
	jne	ckteva3			; ne = no, ET4000 not present
	mov	ax,3			; default to cga 3
	cmp	byte ptr temp,0		; setting 132 columns?
	je	ckteva5			; e = resetting to normal
	mov	ax,23h			; set to 132 cols (Set Mode 23H)
ckteva5:int	screen
	clc
	ret
					;
ckstbv:	mov	ax,0c000h		; STB's VGA/EM, VGA/EM-16, EM-16 Plus
	mov	es,ax			;
	mov	di,70h			; where to look for signature
	lea	si,stbvid		; the signature
	mov	cx,stbvlen		;
	cld				;
	repe	cmpsb			; test
	je	catfnd			; e = found
	mov	di,70h			; where to look for signature
	lea	si,stavid		; the signature
	mov	cx,stavlen
	cld
	repe	cmpsb			; test
	je	catfnd			; e = found
	stc				; else say not there
	ret				;
					; ATI EGA Wonder
ckatiw:	mov	ax,0c000h		; seg addr for EGA Wonder
	mov	es,ax			; set into es register
	mov	di,012fh		; offset of message in ROM
	lea	si,atiwid		; offset of message here
	mov	cx,atilen		; length of validation string
	cld
	repe	cmpsb			; compare strings
	je	catfnd			; e = they match
	lea	si,atiwid2		; alternative signature
	mov	di,30h			; start at this offset
	mov	cx,atilen2		; alternative signature length
	mov	ax,es:[di]		; get first two bytes
	cmp	al,atiwid2		; string starts here?
 	je	ckatiw1			; e = yes
	inc	di			; try next location, just in case
	cmp	ah,atiwid2		; or here?
	je	ckatiw1			; e = yes
	stc				; strings differ
	ret
ckatiw1:repe	cmpsb			; check the whole string
	je	catfnd			; e = matches the whole thing
	stc				; fail on mismatch
	ret
catfnd:	mov	ax,0003h		; prepare to reset video mode
	cmp	byte ptr temp,0		; are we setting or resetting?
	je	catfnd1			; e is reset, exit
	mov	ax,0023h		; set to 132 cols (Set Mode 23H)
catfnd1:int	screen
	clc				; carry clear means success
	ret

chkpa:	mov	ax,0c000h		; load Paradise ROM BIOS address
	mov	es,ax
	mov	ax,0057h		; assume 132x25 mono display needed
	mov	di,0009h		; load EGA board identifier index
	lea	si,pmega1		; Paradise Autoswitch Mono ident
	mov	cx,pmegal1
	cld
	repe	cmpsb			; do identification strings match?
	je	chgpa2			; e = yes, check num of display lines
	mov	di,007dh		; no, load VGA board identifier index
	lea	si,p30id		; Paradise VGA, other flavors
	mov	cx,p30ln
	repe	cmpsb			; do identification strings match?
	je	chgpa1			; e = yes, check for color mode
	stc				; fail
	ret
chgpa1:	cmp	crt_norm,3		; is the "normal" screen in color?
	ja	chgpa2			; a = no, orig assumption is correct
	mov	ax,0055h		; assume 132x25 color required
chgpa2:	cmp	crt_lins,25		; is the "normal" screen 25 lines?
	jna	chgpa3			; na = yes, check num of cols needed
	dec	ax			; change assumption to 132x43
chgpa3:	cmp	byte ptr temp,0		; switching to a 132 column mode?
	jne	chgpa4			; ne = yes
	mov	al,crt_norm		; load "normal" display mode
chgpa4:	int	screen			; issue BIOS call to change display
	clc				; success
	ret
					; Video 7 Vega Deluxe
ckv7vd:	mov	ax,0c000h		; seg addr for Vega rom bios
	mov	es,ax			; set into es register
	mov	di,002ah		; offset of message in ROM
	lea	si,vid7id		; offset of message here
	mov	cx,vid7len
	cld
	repe	cmpsb			; compare strings
	je	cnv7fn1			; e = same
	mov	di,002ah		; offset of ident string
	mov	si,offset vid7id2	; Video 7 VGA board
	mov	cx,vid7len2
	repe	cmpsb
	je	cnv7fn2			; e = found
cnv7fx:	stc				; strings are different
	ret
					;
cnv7fn1:test	byte ptr es:[03ffeh],1	; is this a 'Deluxe' Vega?
	jz	cnv7fx			; z = nope, can't do it
	mov	ah,35h			; DOS Get Vector
	mov	al,10h			; Bios video interrupt
	int	dos			; get it into es:bx
	mov	di,bx			; es:bx is returned int 10h entry pnt
	sub	di,5ah			; back offset to msg in 132X25.COM
	lea	si,vid7id		; offset of validation message
	mov	cx,vid7len		; length of validation string
	cld
	repe	cmpsb			; Look for repeat of msg by 132X25.COM
	jne	cnv7fn2			; if different
	mov	al,crt_mode		; prepare to reset video mode
	xor	ah,ah
	cmp	byte ptr temp,0		; are we setting or resetting?
	je	cnv7fn2a		; e is reset
	mov	ax,0000h		; set to 132 cols (old 40x25)
cnv7fn1a:int	screen
	clc
	ret

cnv7fn2:mov	ax,6f00h		; check for VegaBios driver
	int	screen
	cmp	bx,'V7'			; Video 7 Bios presence response
	jne	cnv7fx			; ne = not there
	mov	ax,6f01h		; al gets monitor type (mono,color,ega)
	int	screen
	mov	bx,51h			; presume mono 132x25, page 0
	cmp	crt_lins,42		; 43 lines active?
	jb	cnv7fn2a		; b = no
	inc	bx			; use bx = 52h for 132x43
cnv7fn2a:
	cmp	al,10h			; analogue fixed freq (IBM 85xx)?
	je	cnv7fx			; e = yes, no 132 columns
	cmp	al,2			; 1 = mono, 2 = color, above = ega
	jb	cnv7fn3			; b = mono or unknown
	mov	bx,4fh			; presume med res color 132x25
	je	cnv7fn3			; e = med res color, al = 2
	mov	bx,41h			; ega high res 132x25, enhanced mons
	cmp	crt_lins,42		; 43 lines active?
	jb	cnv7fn3			; b = no
	inc	bx			; use bx = 42h for 132x43
cnv7fn3:mov	ax,6f05h		; set special mode found in bl
	cmp	byte ptr temp,0		; resetting to 80 column mode?
	jne	cnv7fn4			; ne = no, setting 132x25
	mov	al,crt_norm		; get normal mode
	xor	ah,ah			; set mode
	cmp	crt_lins,42		; 43 lines active?
	jb	cnv7fn4			; b = no
	mov	bl,40h			; use Video 7 mode 40h 80x43 for color
	mov	ax,6f05h		; and do special mode set
cnv7fn4:int	screen			; special mode is in bl
	mov	ax,0f00h		; a nop screen bios command
	int	screen
	clc
	ret

ckevrx: mov     ax,0c000h               ; seg addr for Everex EV-659
        mov     es,ax                   ; set into es register
        mov     di,0047h                ; offset of message in ROM
        lea     si,evrxid               ; offset of message here
        mov     cx,evrxlen              ; length of validation string
        cld
        repe    cmpsb                   ; compare strings
        jne     ckfnr2                  ; ne = strings differ
        mov     ah,crt_lins             ; we recognize either 44 or 25 rows
        cmp     ah,43                   ; equal to 44-1 rows?
        jne     ckfnr1                  ; ne = no
        mov     ax,0070h                ; Everex extended mode ident
        mov     bl,09h                  ; prepare to reset video mode to 80x44
        cmp     byte ptr temp,0         ; are we setting or resetting?
        je      ckfnr4                  ; e is reset, exit
        mov     bl,0bh                  ; 132x44
	int	screen
	clc
	ret
ckfnr1: cmp     ah,24                   ; equal to 25-1 rows?
	je	ckfnr3			; e = yes
ckfnr2:	stc				; return failure
	ret
ckfnr3:	mov     ax,0003h                ; prepare to reset video mode
        cmp     byte ptr temp,0         ; are we setting or resetting?
        je      ckfnr4                  ; e is reset, exit
        mov     ax,0070h                ; Everex extended mode ident
        mov     bl,0ah                  ; 132x25
ckfnr4:	int	screen
	clc
	ret
ckevga:	mov	ax,0c000h		; Everex FVGA-673, EV-678 rom segment
	mov	es,ax
	mov	di,76h			; offset in rom for board's id string
	lea	si,evgid		; id string
	mov	cx,evglen		; length of id string
	cld
	repe	cmpsb			; do they match?
	je	ckevg0			; e = yes
	mov	di,9dh			; offset in ROM for board's ID string
	lea	si,evvid		; ID string
	mov	cx,evvlen		; length of ID string
	cld
	repe	cmpsb			; do they match?
	jne	ckevg2			; ne = no
ckevg0:	mov	ax,3			; prepare to reset video mode
	cmp	byte ptr temp,0		; setting or resetting mode?
	je	ckevg1			; e = resetting, exit
	mov	ax,0070h		; mode for 132x25
	mov	bl,0ah			; Everex mode 0ah
ckevg1:	int	screen
	clc
	ret
ckevg2:	stc				; say board not found
	ret
					; AT&T EGA/VGA boards
ckatt:	mov	ax,0c000h		; seg of first signature
	mov	es,ax
	mov	si,offset attvdc6	; first pattern
	mov	di,35h			; test area
	cld
	mov	cx,attvdlen		; length
	repe	cmpsb
	je	ckatt2			; e = found
	mov	cx,attvdlen		; try second signature, same length
	mov	si,offset attvdc7
	mov	ax,0e000h		; seg of second signature
	mov	es,ax
	mov	di,10h			; test area
	repe	cmpsb
	je	ckatt2			; e = found
	stc				; not found
	ret
ckatt2:	mov	al,crt_norm		; old mode
	xor	ah,ah
	cmp	byte ptr temp,0		; resetting to 80 col?
	je	ckatt3			; e = yes
	mov	ax,0055h		; 132 cols, set mode 55h
ckatt3:	int	screen
	clc
	ret
					; VESA compatibles
chkvesa:mov	di,seg rdbuf		; es:di is buffer for results
	mov	es,di
	mov	di,offset rdbuf
	mov	ax,4f00h		; get SVGA information
	int	screen
	cmp	ax,4fh			; success?
	jne	chkvesax		; ne = no
	cmp	word ptr rdbuf,'EV'	; 'VESA'
	jne	chkvesax		; ne = no
	cmp	word ptr rdbuf+2,'AS'
	jne	chkvesax		; ne = no
	mov	ax,4f01h		; get mode info to es:di buffer
	mov	cx,109h			; 109h is 132x25 text
	int	screen
	cmp	ax,4fh			; success?
	jne	chkvesax		; ne = no
	mov	bx,3			; assume 80 columns
	cmp	byte ptr temp,0		; setting or resetting mode?
	je	chkvesa2		; e = resetting
	mov	bx,109h			; mode for 132x25
chkvesa2:mov	ax,4f02h		; set mode from bx
	int	screen
	cmp	ax,4fh			; success?
	jne	chkvesax		; ne = no
	clc				; say success
	ret
chkvesax:stc				; say failure
	ret

					; IBM XGA 132 columns
ckxga:	push	bp			; (old BIOSes are still around)
	push	ds			; set es to data segment
	pop	es
	mov	ax,1b00h		; get functionality table
	xor	bx,bx
	mov	di,offset decbuf	; es:di is 64 bytes of workspace
	int	screen
	cmp	al,1bh			; is this call supported?
	jne	ckxgax			; ne = no, fail
	les	bx,dword ptr decbuf	; get the address of the modes info
	test	byte ptr es:[bx+2],10h	; is mode 14h supported?
	jz	ckxman			; z = no, try manual method for now
	mov	ax,3			; assume resetting to mode 3, 80x25
	cmp	byte ptr temp,0		; setting 132 columns?
	je	ckxga1			; e = no, resetting to 80 columns
	mov	ax,14h			; invoke IBM XGA mode 14h, 132x25
ckxga1:	int	screen
ckxga2:	pop	bp
	clc				; say success
	ret
ckxgax:	pop	bp
	mov	xga_reg_base,-2		; flag saying no XGA Adapter found
	stc				; say failure
	ret

ckxman:	call	xgaman			; do tests/sets manually
	pop	bp
	jnc	ckxman1			; nc = success
	mov	xga_reg_base,-2		; flag saying no XGA Adapter found
ckxman1:ret
chgdsp	endp

; XGA mode setting via going to the hardware manually
; Code furnished by Bert Tyler, National Institue of Health

xgaman	proc	near
	cmp	xga_reg_base,-2		; has the XGA detector already failed?
	je	xgafail			; e = yes, fail again
	cmp	xga_reg_base,-1		; have we already found the XGA?
	je	xga_loc			; e = no
	jmp	xga_do1			; yes, process it
xga_loc:push	es
	mov	ah,35h			; DOS get interrupt vector
	mov	al,15h			; Int 15h
        int     dos                     ; returns vector in es:bx
	mov	ax,es			; segment part
	pop	es
	or	ax,ax			; undefined vector?
	jz	xgafail			; z = yes
	mov	dx,-1			; start with an invalid POS address
	mov	ax,0c400h		; look for POS base address
	int	15h			;  (Microchannel machines only)
	jc	xgafail			; c = error, not a MC machine
	mov	word ptr decbuf,dx	; save pos_base_address
	xor	cx,cx			; check all MCA slots & motherboard
	cmp	dx,-1			; do we have a good POS?
	jne	xga_lp1			; ne = yes, proceed with MCA checks
xgafail:stc				; fail
	ret

xga_lp1:cli				; no interrupts, please
	cmp	cx,0			; treat the motherboard differently?
	jne	xga_sk4			; ne = yes
	mov	al,0dfh			; enable the motherboard for setup
	mov	dx,94h
	out	dx,al
	jmp	short xga_sk5
xga_sk4:mov	ax,0c401h		; enable an MCA slot for setup
	mov	bx,cx			;  this slot
	int	15h
xga_sk5:mov	dx,word ptr decbuf	; get pos record for the slot
	in	ax,dx			;  ID
	mov	word ptr decbuf+2,ax
	add	dx,2			; compute IO Res Base
	in	al,dx			;  get POS data byte1
	and	ax,0eh			;  muck about with it to get reg base
	shl	ax,1
	shl	ax,1
	shl	ax,1
	add	ax,2100h
	mov	xga_reg_base,ax
	cmp	cx,0			; treat the motherboard differently?
	jne	xga_sk6			; ne = yes
	mov	al,0ffh			; enable the motherboard for normal
	out	094h,al
	jmp	short xga_sk7
xga_sk6:mov	ax,0c402h		; enable the MCA slot for normal
	mov	bx,cx			;  this slot
	int	15h
xga_sk7:sti				; interrupts on again

	mov	ax,word ptr decbuf+2	; is an XGA adapter on this slot?
	cmp	ax,08fd8h
	jae	xga_sk8			; ae = yes
	jmp	xga_lp2			; try another slot
xga_sk8:cmp	ax,08fdbh		; still within range?
	jbe	xga_sk9			; be = yes
	jmp	xga_lp2			; no, try another slot
xga_sk9:mov	dx,xga_reg_base		; is there a monitor on this slot?
	add	dx,0ah
	mov	al,052h
	out	dx,al
	mov	dx,xga_reg_base
	add	dx,0bh
	in	al,dx
	and	al,0fh
	cmp	al,0fh
	jne	xga_ska			; ne = yes
	jmp	xga_lp2			; no
xga_ska:mov	dx,xga_reg_base		; is this XGA in VGA mode?
	in	al,dx
	test	al,1
	jnz	xga_do1			; nz = yes, found it!

xga_lp2:inc	cx			; try another adapter?
	cmp	cx,9			; done all slots?
	ja	xga_no			; a = yes
	jmp	xga_lp1			; no, try another slot
xga_no:	jmp	xgafail			; fail

;	*finally* put the XGA into 132-column or 80-column mode

xga_do1:cmp	byte ptr temp,0		; setting 80-column mode?
	jne	xga_do2			; ne = no, 132 columns
	jmp	xga_do3			; do 80 column mode

					; 132-column mode routine
xga_do2:mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,1550h
	out	dx,ax
	mov	ax,1450h
	out	dx,ax
	mov	ax,0454h
	out	dx,ax
	mov	ax,1202h		; select 400 scan lines
	mov	bl,30h
	int	screen
	mov	ax,0+3			; set video mode 3
	int	screen

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	al,50h
	out	dx,al
	inc	dx
	in	al,dx
	or	al,1
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	al,50h
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0fdh
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	al,50h
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0fch
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	mov	al,3
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,0154h
	out	dx,ax
	mov	ax,8070h
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	al,50h
	out	dx,al
	inc	dx
	in	al,dx
	and	al,0efh
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,11h
	out	dx,al
	inc	dx
	in	al,dx
	and	al,7fh
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,0
	out	dx,al
	inc	dx
	mov	ax,0a4h
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,1
	out	dx,al
	inc	dx
	mov	ax,83h
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,2
	out	dx,al
	inc	dx
	mov	ax,84h
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,3
	out	dx,al
	inc	dx
	mov	ax,83h
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,4
	out	dx,al
	inc	dx
	mov	ax,90h
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,5
	out	dx,al
	inc	dx
	mov	ax,80h
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,0a31ah
	out	dx,ax
	mov	ax,001bh
	out	dx,ax

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	ax,13h
	out	dx,al
	inc	dx
	mov	ax,42h
	out	dx,al

	mov	dx,03d4h		; (the manual doesn't explain...)
	mov	al,11h
	out	dx,al
	inc	dx
	in	al,dx
	or	al,80h
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	al,50h
	out	dx,al
	inc	dx
	in	al,dx
	or	al,3
	out	dx,al

	mov	dx,03c4h		; (the manual doesn't explain...)
	mov	ax,1
	out	dx,al
	inc	dx
	in	al,dx
	or	al,1
	out	dx,al

	mov	dx,03dah		; (the manual doesn't explain...)
	in	al,dx

	mov	dx,003c0h		; (the manual doesn't explain...)
	mov	al,13h
	out	dx,al
	xor	al,al
	out	dx,al
	mov	al,20h
	out	dx,al

	mov	ax,40h			; tell the BIOS we have 132 columns
	mov	es,ax
	mov	byte ptr es:[4ah],132	; set Bios screen width data area
	clc				; return success
	ret
		    			; Set 80 column mode
xga_do3:mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,01h
	xor	al,al
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,4
	xor	al,al
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,5
	mov	al,0ffh
	out	dx,al

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,0ff64h
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,1550h
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,1450h
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,0051h
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,0454h
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,7f70h
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
	add	dx,0ah
	mov	ax,202ah
	out	dx,ax

	mov	dx,xga_reg_base		; (the manual doesn't explain...)
;;	add	dx,00h
	mov	al,1
	out	dx,al

	mov	dx,03c3h		; (the manual doesn't explain...)
	mov	al,1
	out	dx,al

	mov	ax,1202h		; select 400 scan lines
	mov	bl,30h
	int	screen
	mov	ax,0+3			; set video mode 3
	int	screen
	clc				; return success
	ret
xgaman	endp

; Routine to do keyclick if flag is set, no arguments
vclick	proc	near
	test	vtemu.vtflgop,vskeyclick ; is keyclick flag on?
	jz	vclick1			; z = no, just return
	push	bx
	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, no arguments
fvtbell	proc	far
	call	vtbell
	ret
fvtbell	endp

vtbell	proc	near
	cmp	belltype,1		; visual bell?
	je	vtbell1			; e = yes
	ja	vtbell2			; a = no bell
	push	di			; audible bell
	push	bx
	mov	di,880			; 880 Hertz
	mov	bx,40			; For 40 ms
	call	vtsound			; Do it
	pop	bx
	pop	di
	ret
vtbell1:call	revscn			; reverse screen
	push	ax
	mov	ax,40			; for 40 milliseconds
	call	fpcwait
	pop	ax
	call	revscn			; put back
vtbell2: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	fpcwait			; 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
code1	ends
	end
