	NAME	msyz10
; File MSYZ10.ASM
	include mssdef.h
;       Copyright (C) 1982,1991, 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.
; Kermit system dependent module for Heath/Zenith Z100
; Edit history
; 2 March 1991 version 3.10
; Last change: 3 November 1990.
; Minor changes to outtty and outprt.  Added setchtab, modified termtb.
; Putcirc and getcirc have been modified from msyibm and added but remains
; untested and inactive.  VTS and VTSTAT and most of the corresponding data
; is kept in msx in order to allow assemly of this file , msy, with MASM 4.
; Procedures savescr, restscr, atsclr and setcol added and calls to these
; added to scrini and quit.  Procedure revscn (2 variants) added.
; Procedure dumpscr moved from msxz10.asm and restructured to allow general
; use of some code now put in local subroutines rdset, rdlne and endfix. 
; Procedure scroll added, to allow 26 lines scrolling entirely in video
; memory, provided 64k video ram chips are installed.
; Handling of ESC E and ESC J in outtty for the S-100 ports, COM3/COM4,
; refined.
; Getpos and setpos corrected (dl = col, dh = row, comments incorrect in 
; msyibm.asm).
;
; Bo Gedda
;

	public	term, lclyini, holdscr, scroll, savescr, restscr, atsclr
	public	outprt, prtbout, chrout, vclick, vtemu, yflags
	public	cquit, udkclear, low_rgt, vtclear, getpos, setpos
	public	csrtype, termtb, comptab, ontab, beltab
	public	scrtab, curtab, chatab, cntltab, kpamtab, dirtab
	public	vtbell, dumpscr, fcsrtype
	public	f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, sf0
	public	sf1, sf2, sf3, sf4, sf5, sf6, sf7, sf8, sf9, sf10, sf11
	public	i_chr, d_chr, i_line, d_line
	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, cstatus, cquit
	public	out8bit, trnmod, cdos, cquery, chang, trnprs, dmpscn
	public	homwnd, endwnd, dnwpg, upwpg, upone, dnone, klogon, klogof
	public	snull, doscol, setcol, revscn, lincur
	public	belltype, vtroll, setchtab
	public	extmacro, vtmacname, vtmaclen

true		equ	1
false		equ	0
delaycount	equ	1fffh	; Range 1h to 0h (ffffh + 1h = 0h!)

; Entry points to ROM monitor

MTR_SEG	SEGMENT	AT 0FE01H	; Segment addr for Monitor ROM calls
	ORG	000H
  MTR_RES	LABEL	FAR	; Reset function
	ORG	005H
  MTR_MON	LABEL	FAR	; Monitor call
	ORG	00AH
  MTR_SWIM	LABEL	FAR	; Trace/breakpoint handler
	ORG	00FH
  MTR_DCRT	LABEL	FAR	; Dumb display output
	ORG	014H
  MTR_DKBD	LABEL	FAR	; Dumb keyboard handler
	ORG	019H
  MTR_SCRT	LABEL	FAR	; Smart display output
	ORG	01EH
  MTR_SKBD	LABEL	FAR	; Smart keyboard input
	ORG	023H
  MTR_TTY_INTR	LABEL	FAR	; Vertical retrace interrupt handler
MTR_SEG	ENDS

MTR_D_SEG SEGMENT AT 0		; Monitor data segment(not really at 0)
	ORG	000H

; Monitor Parameters
  MTR_WIP	LABEL	FAR	; Far jump to wild interrupt handler
		DB 5 DUP(?)	; the far jump
  MTR_VER	DB ?		; BCD version of ROM monitor
    MTR_CVER	  EQU 01H	  ; Lowest version BIOS can run on
  MTR_DS_SIZE	DW ?		; Size of the ROM monitor data segment

; Boot parameters
  MTR_BINDX	DB ?		; Boot device index
  MTR_BPORT	DB ?		; Boot device base port number
  MTR_BSTRING	DB 80 DUP(?)	; Boot string
  MTR_BUNIT	DB ?		; Boot unit number


; Pointers to All sorts of things
  MTR_DCI	DD ?		; Addr of Display Character Initialization
  MTR_DFC	DD ?		; Addr of Display Font Character Routine
  MTR_DXMTC	DD ?		; Addr of Dumb Keyboard Transmit Character
  MTR_EDC	DD ?		; Addr of Erase Display Character Routine
  MTR_EMEC	DD ?		; Addr of Escape Character Handler Routine
  MTR_FONT	DD ?		; Addr of Character Font table
    MTR_FNT_SIZE  EQU 9*(256-' ') ; Size of reserved font table
				  ;  number of bytes copied from rom font
				  ;  area if version = 1)
  MTR_MDC	DD ?		; Addr of Move Display Characters Routine
  MTR_MDL	DD ?		; Addr of Move Display Line Routine
  MTR_PROMPT	DD ?		; Addr of Display ROM Monitor Prompt Routine
  MTR_RDC	DD ?		; Addr of Read Displayed Character Routine
  MTR_SXMTC	DD ?		; Addr of Smart Keyboard Transmit Character
  MTR_UIES	DD ?		; Addr of Unimplemented Escape Sequence
  MTR_XCA	DD ?		; Addr of Transmit Character Attributes
  MTR_FNTSIZ	DW ?		; Size of FONT in bytes (If version > 1)
  MTR_KYB	DB 256 DUP (?)	; Keyboard map table
  MTR_CHR	DB 256 DUP (?)	; Display map table
  MTR_HORP	DB ?		; Horizontal position of cursor (column)
  MTR_VERP	DB ?		; Vertical position of cursor (row)
  MTR_MIB	DB ?		; Base interrupt number for master
  MTR_SIB	DB ?		; Base interrupt number for slave
  MTR_RESF	DB ?		; Reset flag to re-enter monitor

; Color structure
	ORG	2A1H
 FORE		DB ?		; Current foreground color
 BACK		DB ?		; Current backpround color
 MSK		DB ?		; Color to mask
 CLEAR		DB ?		; Color to clear
 PAINTED	DB ?		; Color to paint
 PFONT		DB ?		; Color to set to font pattern
 COMP_FONT	DB ?		; Color to set to complement of font pattern
; These are the new ones
 BACK_CB	DB ?		; Back control bits
 BACK_SEG	DW ?		; Back segment
 CP_BACK_CB	DB ?		; Complement back control bits
 CP_BACK_SEG	DW ?		; Complement back segment
 CLEAR_CB	DB ?		; Clear control bits
 CLEAR_SEG	DW ?		; Clear segment
 PAINTED_CB	DB ?		; Painted control bits
 PAINTED_SEG	DW ?		; Painted segment
 PFONT_CB	DB ?		; Font control bits
 PFONT_SEG	DW ?		; Font segment
 CP_FONT_CB	DB ?		; Complement font control bits
 CP_FONT_SEG	DW ?		; Complement font segment

; CRT-C display structure
	ORG	2BDH
  DISP_START	DW ?		; CRT-C display start address
  DISP_UPDATE	DB ?		; FF to request update

; H-19 mode structure
	ORG	2D1H
  BWO		DB ?		; Black/white optimization
	ORG	2DBH
  STATUS	DB ?		; FF modeline on, 0 modline off

; H-19 parameter structure
	ORG	2E1H
  PROVRAM	DB ?		; 0 = monochrome, 3 = color
	ORG	2E6H
  VRAM_SIZE	DB ?		; 0 = 32k, 1 = 64k
MTR_D_SEG ENDS

IPAGE_SEG SEGMENT AT 0		; The interrupt area page
	ORG	03FEH
  MTR_DS	LABEL WORD	; Location that contains monitor DS value
IPAGE_SEG ENDS

;bios definitions
BIOS_SEG SEGMENT AT 40H		; Define segment where BIOS really is
	ORG	1*3
BIOS_STATUS	LABEL FAR	; Console input status
	ORG	2*3
BIOS_CONIN	LABEL FAR	; Console input
	ORG	3*3
BIOS_CONOUT	LABEL FAR	; Console output
	ORG	4*3
BIOS_PRINT	LABEL FAR	; Printer output
	ORG	6*3
BIOS_AUXOUT	LABEL FAR	; AUX output routine
	ORG	25*3
BIOS_PRNFUNC	LABEL FAR	; PRN: FUNCTION
	ORG	26*3
BIOS_AUXFUNC	LABEL FAR	; AUX: function
	ORG	27*3
BIOS_CONFUNC	LABEL FAR	; CON: function
BIOS_SEG ENDS

;  Define functions of BIOS_CONFUNC, BIOS_PRNFUNC, and BIOS_AUXFUNC
CHR_WRITE	EQU 0		; Write function
CHR_READ	EQU CHR_WRITE+1 ; Read function
CHR_STATUS	EQU CHR_READ+1	; Status function
  CHR_SFGS	  EQU 0		  ; Get status subfunction
    CHRS_WA	    EQU 00000001B   ; <ETX> sent, waiting for <ACK>
    CHRS_WD	    EQU 00000010B   ; <DC3> seen, waiting for <DC1>
    CHRS_SN	    EQU 00000100B   ; Sending nulls
    CHRS_TXR	    EQU 10000000B   ; Transmitter ready to send data
    CHRS_RXR	    EQU 01000000B   ; Receiver has data 
    CHRS_RXOF	    EQU 00100000B   ; Receiver queue overflow
    CHRS_RXE	    EQU 00010000B   ; Other type of reciver error
    CHRS_TXE	    EQU 00001000B   ; Transmitter error
  CHR_SFGC	  EQU CHR_SFGS+1  ; Get configuration info subfunction
CHR_CONTROL	EQU CHR_STATUS+1 ; Control function
  CHR_CFSU	  EQU 0		  ; Setup new configuration parms subfunction
  CHR_CFCI	  EQU CHR_CFSU+1  ; Clear input subfunction
  CHR_CFCO	  EQU CHR_CFCI+1  ; Clear output subfunction
CHR_LOOK	EQU CHR_CONTROL+1; Nondestructive read function
CHR_FMAX	EQU CHR_LOOK	; Maximum function number

; Z-100 Keyboard commands
keyrst	equ	00h		; reset
keyrpon equ	01h		; auto repeat on
keyrpof equ	02h		; auto repeat off
keyclon equ	03h		; click on
keyclof equ	04h		; click off
keyclr	equ	05h		; clear buffer
keycli	equ	06h		; make key click
keybel	equ	07h		; make bell sound
keyena	equ	08h		; enable keyboard
keydis	equ	09h		; disable keyboard
keyeve	equ	0ah		; make keyboard event driven (up/down mode)
keyasc	equ	0bh		; make keyboard scan ascii
keyiena equ	0ch		; enable interrupt
keyidis equ	0dh		; disable interrupt

; Definitions for cursor type.
; bit 0 set = 1 => Cursor on		cleared = 0 => Cursor off
; bit 1 set = 2 => Block cursor		cleared = 0 => Underline cursor 
; bit 2 set = 4 => Non blinking cursor	cleared = 0 => Blinking cursor
cur_on	equ	1		; 00000001b
cur_blo equ	2		; 00000010b
cur_nob equ	4		; 00000100b

; Miscellaneous scan codes used for functions
prscan	equ	0a2h		; print-screen scan code (F12)...
brkscan equ	0aah		; Break key

COLUMNS EQU	80		; Characters per screen line
ROWS	EQU	24		; Text lines per screen
VID_CMD EQU	0d8h		; Video-memory control port
VID_NOR	EQU	01111000b	; Video access on, individual color write
				;  only, all colors displayed
PAR_GRN EQU	0e000h		; Green video plane segment address
PAR_RED EQU	0d000h		; Red	video plane segment address
PAR_BLU EQU	0c000h		; Blue	video plane segment address

; Kinds of terminals available
;ttgenrc equ	0			; Type 0: no emulation done by Kermit
;ttheath equ	1			; Type 1: Heath-19
;ttvt52 equ	2			; Type 2: VT52
;ttvt100 equ	3			; Type 3: VT102
;TTTYPES equ	4			; Number of terminal types defined

; DEC emulator status flags (bits in words vtemu.vtflgst and vtemu.vtflgop)
;anslnm	 equ	1H			; ANSI line feed/new line mode
;decawm	 equ	2H			; DEC autowrap mode
;decscnm equ	80H			; DEC screen mode
;decckm	 equ	200H			; DEC cursor keys mode
;deckpam equ	400H			; DEC keypad application mode
;decom	 equ	800H			; DEC origin mode
;deccol equ	1000H			; DEC column mode (0=80 col)
;decanm	 equ	2000H			; ANSI mode
;dececho equ	4000H			; ANSI local echo on (1 = on)
;
; Terminal SETUP mode flags (joint with bits above, some name dups)
;vsnewline	equ	1H		; ANSI new line (0 = off)
;vswrap		equ	2H		; Line wrap around (0 = no wrap)
;vsnrcm		equ	4H		; National Rep Char set (0=none)
;vswdir		equ	8H		; Writing direction (0=left, 1 right)
;vskeyclick	equ	10H		; Keyclick (0 = off)
;vsmarginbell	equ	20H		; Margin bell (0 = off)
;vscursor	equ	40H		; Cursor (0 = block, 1 = underline)
;vsscreen	equ	80H		; Screen (0 = normal, 1 = rev. video)
;vscntl		equ	100h		; 8 or 7 bit controls (1 = 8-bit)

; bit for flag byte
havtt	equ 10h				; have translate table

modfrm	struc				; format of mode line
	db	'Esc chr: '
m_echr	db	2 dup (?)
	db	' Help: '
m_hlp	db	2 dup (?)
	db	'?'
	db	' Port: '
m_prt	db	1 dup (?)
	db	' Speed: '
m_baud	db	4 dup (?)
	db	' Parity: '
m_par	db	4 dup (?)
	db	' Echo: '
m_echo	db	3 dup (?)
	db	' '
m_emul	db	10 dup (?)
m_pad	db	1 dup (?)
	db	' '
m_prn	db	3 dup (?)
	db	'$'
modfrm	ends

data	segment
	extrn	flags:byte, caplft:byte, portval:word, trans:byte
	extrn	klen:word, ktab:word, krpl:word, flowon:byte, flowoff:byte
	extrn	dosnum:word, kbdflg:byte, kbcodes:byte, npages:word
	extrn	taklev:byte, takadr:word, mcctab:byte, dupflg:byte
	extrn	ttyact:byte, dmpname:byte, filtst:byte, rdbuf:byte
	extrn	prnhand:word

anspflg db	0			; printer flag bits and definitions

vtmacname dw	0			; pointer to selected macro name
vtmaclen db	0
udkseg	dw	18 dup (0)		; segment of user definable key defs
oldsp	dw	0			; offset to longjmp to for i/o failure
inited	equ	08h			; been here before
vtinited db	0			; flag for emulator having been inited
cursor	dw	0
lincur	dw	?			; cursor type save area
doscol	db	?,?			; foreground col, background col
tercol	db	6,0			; foreground col, background col
dosattr db	?			; screen attributes at init time
tv_segs dw	0			; Topview virtual screen, segment
tv_sego dw	0			; and offset
yflags	db	0			; status flags
argadr	dw	?			; address of arg blk
savadr	dw	2 dup (0)		; offset then segment of saved screen
trmtyp	dw	0			; most recent terminal type
vtclear db	0			; nonzero to redo emulator screen
insert	db	'O'			; flag for overwrite/insert mode, O/@
temp	dw	0			; scratch storage
pntmsg	db	'Printer not ready, printing request skipped$'
pntptr	dw	dumpbuf			; pointer to next free byte in buffer
dumplen equ	132
dumpbuf db	dumplen dup (?)		; / 134 byte dump work buffer
crlf	db	cr,lf,'$'		; \ needs these too
scbattr db	?			; screen background attribute
belltype db	0			; 0 = aural bell, 1 = visual
fairness dw	0
savattr db	78h			; cur. emul. attrib., 78h = all colors
fairprn dw	0
parmsk	db	0			; 8/7 bit parity mask, for reception
captrtn dw	0			; routine to call for captured output
portno	db	0
memerr	db	cr,lf,'Not enough memory for terminal emulator$'

vstate	db	0			; Video ram port-status at invocation.
int_cy	dw	0			; Vertical screen index (line number).
line	db	(COLUMNS+4) dup (0)	; Screen's line buffer.
lines	dw	0			; Number of lines valid on screen.
eos	db	0			; flag: 0= not end of screen, 1= yes.
dmphand dw	?			; screen dump file handle [jrd]
dmperr	db	cr,' Cannot open save screen file $'
dmperr1 db	cr,' Cannot write save screen file $'  
holdscr db	0		; Hold-Screen, non-zero to stop reading

; storage for multi-window stuff
swidth	equ	COLUMNS			; max screen width, 80
slen	equ	ROWS			; and length of text, 24
crt_norm db	3			; video mode for normal screen
crt_mode db	3			; video mode (typ 3, must be text)
crt_cols db	COLUMNS			; number of screen columns (typ 80)
crt_lins db	ROWS			; number of screen rows - 1 (typ 24)
low_rgt dw	174fh			; lower right corner of text window
startad	dw	0			; storage for CRTC Start Address
refresh	db	0			; screen refresh (0=wait for retrace)
vtroll	db	0			; auto roll back allowed (0 = no)

inipara dw	0			; initial paragraphs of scroll memory
	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)
lxtra	dw	0			; (BDT) "extra" lines rqd for screen
					; begin video ram complement storage
vidmsg	db	cr,' Cannot scroll, need 64k video ram $'
mtrmsg	db	cr,lf,'Monitor boot rom must be Version 2.5 or above.  Refer '
	db	'to your Z-100 Manual$',cr,lf
					; begin Terminal emulator data set
setchtab db	6			; Set File Character-Set table
	mkeyw	'CP437',437		; hardware default Code Page
	mkeyw	'CP850',850		; Multilingual CP
	mkeyw	'CP860',860		; Portuguese CP
	mkeyw	'CP863',863		; French Canadian CP
	mkeyw	'CP865',865		; Norwegian CP
	mkeyw	'CP866',866		; Latin5/Cryillic CP

termtb	db	2		; entries for Status, not Set
	mkeyw	'Heath-19',ttheath
	mkeyw	'none',ttgenrc

comptab db	12			 ; Twelve entries.
	mkeyw	'1',1	
	mkeyw	'2',2	    
	mkeyw	'3',3	    
	mkeyw	'4',4	    
	mkeyw	'COM1',1
	mkeyw	'COM2',2       
	mkeyw	'COM3',3       
	mkeyw	'COM4',4       
	mkeyw	'A',2
	mkeyw	'B',1	    
	mkeyw	'J1',2	
	mkeyw	'J2',1	     

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

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

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

chatab	db	14			; 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	'Italian',7
	mkeyw	'Norwegian/Danish',8
	mkeyw	'Portuguese',9
	mkeyw	'Spanish',10
	mkeyw	'Swedish',11
	mkeyw	'Swiss',12		; end of NRC proper
	mkeyw	'Transparent',14	; use native display adapter hardware

curtab	db	3			; cursor attributes
	mkeyw	'block',0
	mkeyw	'underline',1
	mkeyw	'none',2
     
beltab	db	3			; bell type
	mkeyw	'audible',0
	mkeyw	'visual',1
	mkeyw	'none',2

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

kpamtab db	2			; keypad, application
	mkeyw	'Numeric',0
	mkeyw	'Application',1

flags1	db	0			; internal flags
prtscr	equ	80h			; print screen pressed flag
escflg	db	0			; esc character received flag
padflg	db	0			; keypad mode changed flag
ansflgs dw	0			; ANSI/VT100 mode flags
; (flags are defined in mssdefs.h)

vtemu	emulst	<>			; emulator flags

eeolstr db	ESCAPE,'K$'	   ; Erase to end of line
enascan db	ESCAPE,'y?$'	   ; Enable scan codes, disable key expansion
disscan db	ESCAPE,'x?$'	   ; Disable scan codes, enable key expansion
enacurs db	ESCAPE,'y5$'	   ; Enable cursor
discurs db	ESCAPE,'x5$'	   ; Disable cursor
enablnk db	ESCAPE,'y;$'	   ; Enable cursor blink
disblnk db	ESCAPE,'x;$'	   ; Disable cursor blink
enabloc db	ESCAPE,'x4$'	   ; Enable block cursor
enaunde db	ESCAPE,'y4$'	   ; Enable underscore cursor
savcur	db	ESCAPE,'j$'	   ; Save current cursor position
begrev	db	ESCAPE,'p$'	   ; Enter reverse video
padpos	db	ESCAPE,'Y8k$'	   ; Row 25 column 75
endrev	db	ESCAPE,'q$'	   ; Exit reverse video
precur	db	ESCAPE,'k$'	   ; Restore cursor to previous position

modbuf	modfrm	<>			; mode line buffer

; some static data for mode line
unkbaud db	'Unk '			; must be 4 chars...
baudn	db	'45.5'
	db	'  50'
	db	'  75'
	db	' 110'
	db	' 135'
	db	' 150'
	db	' 300'
	db	' 600'
	db	'1200'
	db	'1800'
	db	'2000'
	db	'2400'
	db	'4800'
	db	'9600'
	db	' 19K'
	db	' 38K'

baudnsiz  equ	16			; # of baud rates known (tbl size / 4)

parnams db	'Even'
	db	'Mark'
	db	'None'
	db	'Odd '			; must be 4 chars
	db	'Spc '
lclmsg	db	'Lcl'
remmsg	db	'Rem'
prmsg	db	'PRN'
	db	'   '

noleds	db	'   None   '		; For no emulation
ansleds db	'VT102 ....'		; "LEDs". Terminal ident (10 bytes)
v52leds db	'   VT52   '		; This is used in VT52 mode
h19leds db	' Heath-19 '		; For Heath-19 mode

vtable	dw	ontab, ontab, chatab, dirtab ,ontab, ontab, curtab, scrtab
	dw	cntltab, kpamtab, 0
; which are	newline	 wrap	char   direct  key   margin  cursor  screen  
;		controls key-app

data	ends

code1	segment
fcsrtype proc	far
	ret
fcsrtype endp
code1	ends

code	segment
	extrn	prtchr:near,outchr:near,putmod:near,clrmod:near,sendbr:near
	extrn	sprtch:near, beep:near, pcwait:near, poscur:near, cmblnk:near
	extrn	msuinit:near, keybd:near, keycom:near, isfile:near, outch2:near
	extrn	atoi:near, strlen:near
	extrn	comnd:near, statc:near, replay:near, pntchr:near, pntflsh: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. [jrd]
lclyini proc	near
	mov	ax,ipage_seg		; the interrupt page
	mov	es,ax
	mov	es,word ptr es:mtr_ds	; find monitor data segment here
	cmp	es:MTR_VER,25		; Must be higher than Version 2.5
	jnl	lclyini1
	mov	ah,prstr		; Tell user and abort
	mov	dx,offset mtrmsg
	int	dos
	mov	ah,4ch 
	int 	dos
lclyini1:mov	ax,word ptr es:FORE	; get current colors
	mov	word ptr doscol,ax	; save it
	in	al,VID_CMD		; Get the current video status.
	mov	dosattr,al		; Save it.
	mov	al,VID_NOR		; Set up video to normal
	out	VID_CMD,al		;  suit us, normally all colors active
	call	msuinit			; initialize keyboard module msuxxx
	mov	al,1			; underscore
	call	csrtype			; turn on underline cursor
;	call	getpos			; get cursor position
;	mov	ax,1			; underline cursor
;	call	setpos			; set cursor position and type
					; screen roll back buffers
	mov	al,crt_lins		; physical length of user area
	mul	crt_cols		; physical width
	add	ax,7			; round up
	mov	cl,3
	shr	ax,cl			; bytes/screen to paragraphs/screen
	mov	si,ax			; save a copy in si
	mov	bx,npages		; number of roll back screens wanted
	inc	bx			; include current screen in count
	mul	bx			; total number of screens wanted
	mov	cx,ax			; save total wanted paragraphs in cx
	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	lclyin2			; c = not enough for it
	cmp	bx,si			; minimum roll back space left over?
	jle	lclyin2			; le = not even that much
	cmp	bx,cx			; got vs wanted paras for roll back
	jle	lclyin3			; le = enough but not more than needed
	mov	bx,cx			; limit to our actual needs
	jmp	short lclyin3		; ask for all we really want
lclyin2:xor	bx,bx			; use no space at all
	mov	cx,bx			; remember this new request
lclyin3:mov	ah,alloc
	int	dos
	mov	tv_segs,PAR_GRN		; the green video plane holds it all
	mov	tv_sego,0		;  and it starts at PAR_GRN:00
	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	lclyin4			; ae = enough
	mov	ah,prstr
	mov	dx,offset memerr	; say not enough memory to operate
	int	dos
	mov	flags.extflg,1		; set Kermit exit flag
lclyin4:call	bufadj			; set roll back buffer parameters
;	call	vsinit			; init terminal emulator module MSZ
;	mov	bx,vtemu.att_ptr	; attributes pointer
;	mov	ah,dosattr		; startup video attributes
;	and	ah,not att_intensity	; emulation intensity to normal
;	or	ah,userbold
;	mov	[bx],ah			; set initial emulation attributes
	ret
lclyini endp

; This is the terminal emulator.
term	proc	near			; terminal mode entry point
	mov	argadr,ax		; save argument ptr
	call	argini			; init options from arg address
	call	scrini			; init screen stuff
	or	kbcodes,80h		; set need-to-init flg for kbd xtlator
	mov	bx,portval		; port data structure address
	mov	bx,[bx].flowc		; get flow control chars (bl=xoff)
	mov	flowon,bh
	mov	flowoff,bl		; save for later
	mov	oldsp,sp		; remember stack for i/o failure,
					;  used by procedure  endcon
	mov	fairprn,0		; set printer buffer flush counter
lp:	call	prtchr			; char at port?
	jnc	short lpinp		; nc = yes, go handle
	cmp	flags.comflg,2		; check if S-100 ports
	ja	lpkbd			; yes, go do it the simple way
	push	bx
	mov	bx,portval		; port structure address
	cmp	[bx].portrdy,0		; is port ready for business?
	pop	bx
	jne	lpkbd			; ne = ready
	jmp	endcon			; end the communications now
lpkbd:	mov	fairness,0		; say kbd was examined
	inc	fairprn			; inc printer dump counter
	cmp	fairprn,1000		; been here enough times now?
	jb	lpkbd1			; b = no
	cmp	flags.comflg,2		; check if S-100 ports
	ja	lpkbd1			; yes, this will delay us too much
	call	pntflsh			; flush printer buffer
	mov	fairprn,0		; reset for next time
lpkbd1: call	keybd			; call keyboard translator in msu
	jnc	lp			; nc = no char or have processed it
	jmp	short quit		; carry set = quit connect mode
lpinp:	and	al,parmsk		; apply 8/7 bit parity mask
	call	outtty			; print on terminal
	inc	fairness		; say read port but not kbd, again
	cmp	fairness,100		; this many port reads before kbd?
	jb	lp			; b = no, read port again
	jmp	short lpkbd		; yes, let user have a chance too

quit:	mov	ah,scbattr		; current emulator attributes
	mov	savattr,ah		; save them here
	call	pntflsh			; flush printer buffer
	call	getpos			; get cursor position into dx
	mov	cursor,dx		; save position
	mov	al,1			; underscore
	call	csrtype			; turn on underline cursor
	cmp	flags.vtflg,0		; terminal type of none?
	je	quit1			; e = yes
	cmp	flags.modflg,2		; is modeline owned by remote host?
	je	quit1			; e = yes
	call	clrmod			; clear it before storing screen
quit1:	
	call	savescr			; save screen
      	mov	dh,byte ptr low_rgt+1	; bottom line
	xor	dl,dl			; left most column
	call	setpos			; set cursor position
	mov	dx,word ptr doscol	; set color back to dos values
	xchg	dl,dh			; get the sequence right
	call	setcol
	mov	al,VID_NOR		; reset video port
	out	VID_CMD,al
	mov	al,yflags
	and	al,not lclecho		; don't copy host's echo flag
	mov	bx,argadr
	mov	ah,[bx].flgs		; get user's flag settings
	and	ah,lclecho		; clear all but local echo bit
	or	[bx].flgs,al		; update flags in arg block
	ret
term	endp

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
	mov	crt_lins,ROWS		; init # of rows
	mov	ax,[bx].captr
	mov	captrtn,ax		; buffer capture routine
	mov	parmsk,0ffh		; parity mask, assume parity = None
	cmp	[bx].parity,parnon	; is parity None?
	je	argini1			; e = yes, keep all 8 bits
	mov	parmsk,07fh		; else keep lower 7 bits
argini1:ret				; that's it
argini	endp

scrini	proc	near			; init screen stuff
	mov	dx,word ptr tercol	; set terminal color
	xchg	dl,dh			; get the sequence right
	call	setcol
	call	clrmod			; clear mode line
	test	yflags,modoff		; is mode line disabled?
	jnz	scrin1			; yes, skip it
	call	modlin			; turn on mode line
scrin1: 
	cmp	flags.vtflg,0		; terminal type of None?
	ja	scrin3			; a = no, emulating

;some code?

scrin3: 
	in	al,VID_CMD		; Get the current video status.
	mov	savattr,al		; Save it.
	mov	scbattr,al		; Here too
	mov	dx,cursor		; use old cursor, if any
	call	restscr			; restore screen, if any saved
	call	setpos			; set cursor position
	or	flags1,inited		; remember we've run already
	cmp	flags.vtflg,0		; current terminal type = None?
	je	scrin13			; e = yes, nothing to init
	cmp	vtclear,2		; screen need clearing?
	jae	scrin10			; ae = yes, do emulator reinit now
	cmp	vtinited,inited		; inited emulator yet?
	je	scrin11			; e = yes
scrin10:call	vtinit			; init it now
	jmp	short scrin13
scrin11:
;	call	ansrei			; reinit the emulator

scrin13:mov	ax,flags.vtflg		; current terminal type
	mov	trmtyp,ax		; place to remember it til next time
	mov	vtclear,0		; say screen is updated
	ret
scrini	endp

; Routine to initialize VT102/52/Heath-19 terminal emulator.
vtinit	proc	near
	mov	holdscr,0		; clear holdscreen
	mov	ah,conout
	mov	dl,ESCAPE		; Take the
	int	dos			;  Z-100
	mov	dl,'y'			;  terminal
	int	dos			;  out of
	mov	dl,'3'			;  holdscreen
	int	dos			;  mode
	or	vtinited,inited
	cmp	flags.vtflg,0		; doing emulation?
	je	vtinix			; e = no
	mov	bx,argadr		; address of argument block
	mov	dl,[bx].flgs
	and	dl,lclecho		; local echo flag
	and	yflags,not lclecho
	or	yflags,dl
	mov	dl,[bx].baudb		; baud rate code in dl
	mov	dh,[bx].parity		; parity code in bits
	mov	cl,4			; 0-3 of dh
	shl	dh,cl
	or	dh,07H			; just say 7 data bits
	test	flags.remflg,d8bit	; eight bit display?
	jz	vtini1			; z = no
	inc	dh			; set low four bits to value 8
vtini1: 
;	call	ansini			; call startup routine
vtinix: clc
	ret
vtinit	endp


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

; Put the character in al to the screen.
; Monitor rom calls used in emulator mode for speed reasons.
; The Z-100 screen is very slow in the handling of esc E and esc J;
;  if esc E or esc J and S-100 modem, trap these and do it our own way
;  while polling port in order to avoid loosing characters at port.
; The esc sequencies esc x ?, esc y ? and esc y @ are trapped and defused
;  as these would either lock up the keyboard or interfere with the function
;  of the keys.
outtty	proc	near
	cmp	escflg,true	; Esc last time?
	jl	outtt04		; No, but maybe this time
	jz	outtt01		; Yes
	jmp	outtt31		; No, but earlier
outtt01:cmp	al,'='		; Is it =?
	jnz	outtt02		; No, go on
	mov	ansflgs,deckpam ; Yes, it is application keypad mode
	or	vtemu.vtflgop,deckpam	; here too
	mov	modbuf.m_pad,'A'; A for Application
	mov	padflg,true	; Keypad mode changed
	jmp	outtt03
outtt02:cmp	al,'>'		; Is it >?
	jnz	outtt1		; No, go on
	mov	ansflgs,false	; Yes, it is numeric keypad mode
	and	vtemu.vtflgop,not deckpam
	mov	modbuf.m_pad,'N'; N for Numeric
	mov	padflg,true	; Keypad mode changed
outtt03:mov	escflg,false	; reset
	jmp	outtt4		; Go display it
outtt04:cmp	al,ESCAPE	; Esc now?
	jnz	outtt05		; No
	mov	escflg,true
outtt05:jmp	outtt4		; Go display it
outtt1: inc	escflg		; Count
	cmp	escflg,true
	jnz	outtt11
	mov	escflg,false	; reset
outtt11:cmp	al,ESCAPE	; Esc now?
	jnz	outtt2		; No, just go on
	mov	escflg,true	; Yes, set escflg to 1
outtt2: cmp	al,'x'		; Yes, set modes?
	jz	outtt05		; Yes, just deliver
	cmp	al,'y'		; Reset modes?
	jz	outtt05		; Yes, just deliver
	mov	escflg,false	; reset
	cmp	flags.comflg,2	; check if S-100 ports
	jle	outtt4		; no, go do it the simple way
	cmp	al,'E'		; Is it E?
	jz	outtt3		; Yes, go handle
	cmp	al,'J'		; Is it J?
	jnz	outtt4		; No, go write the character
	push	ax		; Need this later
	jmp	short outtt3a	; Have ESC J
outtt3: push	ax		; Yes, we have ESC E
	mov	ah,conout	;  break it up into smaller parts,
	mov	dl,'H'		;  first, home cursor (ESC was sent before)
	int	dos
	mov	dl,ESCAPE	; Send ESC again (first part of ESC j)
	int	dos
outtt3a:			; This is where we handle ESC J
	mov	cx,1		; No delay for sprtch
	call	sprtch		; Go get possible char at port
	mov	ah,conout
	mov	dl,'j'		; Save cursor position (ESC was sent before) 
	int	dos
	mov	ah,prstr
	mov	dx,offset eeolstr ; Clear to the end of the current line
	int	dos	
	call	getpos		; Get cursor position
	xor	dl,dl		; Column 0
	cmp	dh,23		; Line 23 = the 24th line?
 	jae	outtt3d		; Yes, we are at 23 or 24 (24th or 25th), done
	push	dx		; Save cursor position
outtt3b:pop	dx		; Get cursor
	inc	dh		; Next line
	cmp	dh,24		; Will this one be line 24, the 25th line
	jae	outtt3c		; Yes, done
	push	dx		; Save it again
	mov	cx,1		; No delay
	call	sprtch		; Go get possible char at port
	pop	dx		; Get cursor back
	push	dx		; Save it again
	call	poscur		; Set cursor to beginning this new line 	
	mov	ah,prstr
	mov	dx,offset eeolstr ; Clear to the end of the current line
	int	dos
	jmp	short outtt3b
outtt3c:mov	dx,offset precur; Set cursor to 'original' position
	int	dos
outtt3d:mov	escflg,false	; reset
	jmp	outtt5
outtt31:mov	escflg,false	; reset
	cmp	al,'?'		; key expansion?
	jz	outtt32		; yes, inhibit it
	cmp	al,'@'		; event driven?
	jnz	outtt4		; no, just deliver
outtt32:xor	al,al		; put something harmless in
outtt4: push	ax		; Need it later
	test	flags.remflg,d8bit ; keep 8 bits for displays?
	jnz	outtt40		; nz = yes, 8 bits if possible
	and	al,7fh		; Strip parity
outtt40:test	yflags,emheath	; Are we using emulation?
	jnz	outtt41		; Yes, go on, do it fast
				; No, use dos to allow term. device driver
	mov	dl,al		; We need it here
	mov	ah,conout	; Write char in dl	; This may loose
	int	dos		;  do it		;  characters
	jmp	outtt5
outtt41:mov	ah,chr_write	; Write char in al	; This is faster
;	 call	 bios_confunc	 ; Do it fast
	call	MTR_SCRT	; Do it very fast	
outtt5: pop	ax		; Restore char
	test	yflags,capt	; capturing output?
	jz	outtt7		; no, forget it
	cmp	flowoff,0	; Are we doing flow control
	je	outtt6		; No, just continue
	cmp	caplft,1	; yes, one more space left in capture buffer?
	jnz	outtt6		; no, give it the char
	push	ax		; yes, send xoff first
	mov	bx,portval
	mov	ax,[bx].flowc	; ah gets xon al gets xoff
	call	outpr1
	cmp	flags.comflg,2	; check if S-100 ports
	jle	outtt51		; no, go do it the simple way
	mov	cx,delaycount	; delay to ensure that, in spite of possible
	call	sprtch		;  slow link, xoff is in effect
outtt51:pop	ax		; get char back
	push	ax		; save it again
	call	captrtn		; give it the captured char
	mov	bx,portval
	mov	ax,[bx].flowc	; ah gets xon al gets xoff
	mov	al,ah
	call	outpr1
	pop	ax
	jmp	outtt7		
outtt6: call	captrtn
outtt7: test	flags1,prtscr		; print screen?
	jz	outtt8			; no, keep going
	call	pntchr			; queue char for printer
	jnc	outtt8			; nc = successful print
	push	ax
	call	beep			; else make a noise and
	call	trnprs			;  turn off printing
	pop	ax
outtt8: test	padflg,true		; no, has keypad mode been changed?
	jz	outtt9			; no, skip it
	test	yflags,modoff		; is mode line disabled?
	jnz	outtt9			; yes, skip it
	call	dispad			; yes, display keypad mode
	mov	padflg,false		; reset flag
outtt9: ret
outtty	endp

; display the keypad mode information on the mode line
dispad	proc	near
	mov	ah,prstr		; print string
	mov	dx,offset savcur	; save cursor position
	int	dos
	mov	dx,offset begrev	; reverse video
	int	dos
	mov	dx,offset padpos	; position cursor
	int	dos
	mov	dl,modbuf.m_pad		; this is it
	mov	ah,conout
	int	dos
	mov	ah,prstr
	mov	dx,offset endrev	; normal video
	int	dos
	mov	dx,offset precur	; reposition cursor
	int	dos
	ret
dispad	endp

					; general character out for emulator
chrout: cmp	flags.vtflg,0		; emulating?
	je	chrou5			; e = no
;	call	anskbi			; 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	outprt			; output a carriage-return
	mov	al,lf			; followed by a line feed
	call	outprt			; send the LF
	pop	ax
	mov	trans.seol,ah		; restore eol char
	ret
chrou5: jmp	outprt

; 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
prtbout	label	near			; label used in msz
	test	yflags,lclecho		; echoing?
	jz	outpr1			; z = no, forget it
	push	ax			; save char
	call	outtty			; print it
	pop	ax			; restore
OUTPR1:	mov	ah,al			; outpr1 entry point used for no echo
		 			;  sending of char in al
	call	outchr			; output to the port
 	jc	outpr3			; c = failure
	ret
OUTPR2: mov	ah,al			; outpr2 entry point used for no echo
					;  no flow control sending of char
	call	outch2			; output to the port, no flow control
 	jc	outpr3			; c = failure
	ret
outpr3:	jmp	endcon			; failure, end connection
outprt	endp
					; Toggle Mode Line
trnmod	proc	near
	cmp	flags.modflg,1		; mode line enabled and owned by us?
	jne	trnm1			; ne = no, don't touch it
	test	yflags,modoff		; mode line already off?
	jnz	trnm2			; nz = yes, go turn on
	or	yflags,modoff		; say modeline is toggled off
	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
	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			; turn on mode line
	push	es
	mov	al,trans.escchr
	mov	modbuf.m_echr,' '	; first char is initial space
	mov	modbuf.m_hlp,' '	; goes here too.
	cmp	al,32			; printable?
	jnb	modl0			; yes, keep going
	add	al,40h			; made printable
	mov	modbuf.m_echr,'^'	; note control char
	mov	modbuf.m_hlp,'^'
modl0:	mov	modbuf.m_echr+1,al	; fill in character
	mov	modbuf.m_hlp+1,al
	mov	bx,argadr		; get argument block
	mov	al,[bx].baudb		; get baud bits
	mov	si,offset unkbaud	; assume unknown baud
	cmp	al,baudnsiz		; too big?
	jnb	modl3			; yes, use default
	shl	al,1			; each is 4 bytes long...
	shl	al,1
	mov	ah,0
	add	ax,offset baudn
	cmp	flags.comflg,2		; com1/com2?
	jna	modl2			; yes, jump
	add	ax,5*4			; no, starts 5 rates higher
modl2:	mov	si,ax
modl3:	mov	cx,size m_baud		; length of baud space
	mov	di,offset modbuf.m_baud
	push	ds
	pop	es
	cld
	rep	movsb			; copy in baud rate
	mov	al,[bx].parity		; get parity code
	shl	al,1			; each is 4 bytes long...
	shl	al,1
	mov	ah,0
	add	ax,offset parnams	; names of parity settings
	mov	si,ax
	mov	cx,4			; each is 4 long
	mov	di,offset modbuf.m_par
	rep	movsb
	mov	si,offset remmsg	; assume remote echoing
	test	yflags,lclecho		; echoing?
	jz	modl4			; no, keep going
	mov	si,offset lclmsg
modl4:	mov	cx,3			; size of Rem & Lcl
	mov	di,offset modbuf.m_echo
	rep	movsb
	cmp	flags.comflg,1		; port 1 (port B)?
	mov	al,'B'			; enter 'B'
	je	modl5			; yes, keep going
	cmp	flags.comflg,3		; port 3 (S-100 port 1)
	mov	al,'3'			; enter '3'
	je	modl5			; yes, keep going
	cmp	flags.comflg,4		; port 4 (S-100 port 2)
	mov	al,'4'			; enter '4'
	je	modl5			; yes, keep going
	mov	al,'A'			; then must be port 2 (port A)!
modl5:	mov	modbuf.m_prt,al		; fill in port number
	mov	cx,3			; size of PRN
	mov	di,offset modbuf.m_prn
	test	flags1,prtscr		; print screen?
	mov	si,offset prmsg		; printer on msg
	jnz	modl6			; yes, prepare to display it
	add	si,3			; no, print blank
modl6:	rep	movsb
	mov	cx,10			; size of leds
	mov	di,offset modbuf.m_emul
	test	yflags,emheath		; are we using Heath-19 emulation?
	mov	si,offset noleds	; "None" message
	jz	modl7			; no, prepare to display it
	mov	si,offset h19leds	; Heath-19 emulation
modl7:	rep	movsb
	mov	modbuf.m_pad,'N'	; N for Numeric
	test	ansflgs,deckpam		; are we in keypad application mode?
	jz	modl8			; no, leave the blank in
	mov	modbuf.m_pad,'A'	; A for Application
modl8:	mov	cx,size modfrm		; this is size of mode line
	mov	si,offset modbuf	; mode line image
	mov	dx,offset modbuf
	call	putmod
	pop	es
	ret				; and return
modlin	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
	jmp	short vtmacro
extmacro endp
;
; Reference	Macro structure for	db	number of entries (mac names)
;  is file	 table mcctab	   |->	db	length of macroname, excl '$'
;  mssset.asm		each entry |->	db	'macroname','$'
;  where these			   |->	dw	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 rdbuf+1	; macro def buffer starts here
	mov	si,vtmacname		; pointer to macro name
	mov	cl,vtmaclen		; length of macro name<sp/null>text
	xor	ch,ch
	mov	[di-1],cl		; counted string field
	cld
	rep	movsb			; copy to rdbuf
	mov	byte ptr [di],0		; null terminator
	mov	si,offset rdbuf+1	; look for name-text separator
	mov	cl,vtmaclen
	xor	ch,ch
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 lenght correctly
vtmac1a:sub	si,offset rdbuf+1+1	; compute length of macro name
	mov	cx,si
	mov	vtmaclen,cl		; 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	al,[bx]			; length of this name
	xor	ah,ah
	cmp	al,vtmaclen		; length same as desired keyword?
	jne	vtmac3			; ne = no, search again
	mov	si,bx
	inc	si			; point at first char of name
	push	cx			; save name counter
	push	di			; save reg
	mov	cl,vtmaclen		; length of name, excluding '$'
	xor	ch,ch
	mov	di,vtmacname		; point at desired macro name
	push	es			; save reg
	push	ds
	pop	es			; make es use 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, dollar sign, 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
	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	cl,rdbuf		; length of whole string
	xor	ch,ch
	mov	[bx].takcnt,cx		; number of chars in definition
	mov	[bx].takargc,0		; our argument count
	mov	[bx].takptr,offset rdbuf+1 ; where to read next command char
	mov	[bx].taktyp,0ffh	; flag as a macro
	pop	es
	pop	di
	pop	si
	pop	cx
	pop	bx
	jmp	endcon			; exit Connect mode
vtmacro	endp

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


; 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

; 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).

bufadj	proc	near
	push	bx
	push	cx
	push	dx
	mov	lxtra,0			; assume no storage for "extra" lines
	xor	bh,bh			; (BDT) get bytes / line
	mov	bl,crt_cols		; (BDT) physical 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
	mov	ax,inipara		; (BDT) compute the number of lines
	xor	dx,dx
	div	bx			; (BDT)	 in the buffer
	mov	lmax,ax			; max line capacity of the buffer
	mov	linee,ax		; (BDT) save as number of total lines
	or	ax,ax			; is this zero?
	je	bufadj1			; e = 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
	mov	lxtra,bx		; (BDT) save as "extra" lines
	sub	lmax,bx			; (BDT) deduct "extra" lines req'd
	jg	bufadj1			; g = have some rollback space
	mov	lmax,0			; say none
	mov	lxtra,0			; say none of these too
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

; Routine to set cursor type.  Pass bits for cursor type in al:
; bit 0 set = 1 => Cursor on		cleared = 0 => Cursor off
; bit 1 set = 2 => Block cursor		cleared = 0 => Underline cursor 
; bit 2 set = 4 => Non blinking cursor	cleared = 0 => Blinking cursor
; Thus, in decimal form
; 0 = No cursor, 1 = Blinking underline cursor , 3 = Blinking block cursor
; 4 = No cursor, 5 = No blink underline cursor , 6 = No blink block cursor
csrtype proc	near
	mov	byte ptr lincur,al	; remember type set
	push	ax
	push	dx			; save the reg
	mov	ah,prstr
	test	al,cur_on		; any cursor at all?
	jz	csrty3			; z=no, go put it out
	mov	dx,offset enacurs	; enable cursor
	int	dos
	mov	dx,offset enablnk	; assume blink
	int	dos
	test	al,cur_nob		; non blinking?
	jnz	csrty1			; nz=no to no blink, leave as is
	mov	dx,offset disblnk	; set blink off
	int	dos
csrty1: mov	dx,offset enaunde	; assume underline
	int	dos
	test	al,cur_blo		; block?
	jz	csrty2			; z=no, leave as is 
	mov	dx,offset enabloc	; set block
	int	dos
csrty2: jmp short csrty4
csrty3: mov	dx,offset discurs	; disable cursor
	int	dos
csrty4: pop	dx
	pop	ax
	ret	
csrtype 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 PROC	NEAR			; dumpscr dumps sreen to file
	push	ax
	push	bx
	push	cx
	push	dx
	push	di
	push	si
	push	es
					; Open and prepare screen dump file
	mov	dmphand,-1		; preset illegal handle
	mov	dx,offset dmpname	; name of disk file, from mssset
	mov	ax,dx			; where isfile wants name ptr
	call	isfile			; what kind of file is this?
	jc	dmp1			; c = no such file, create it
	test	byte ptr filtst.dta+21,1fh ; file attributes, ok to write?
	jnz	dmp2			; nz = no, indicate open failure
	mov	al,1			; writing
	mov	ah,open2		; open existing file
	int	dos
	jc	dmp2			; c = failure, indicate open failure
	mov	dmphand,ax		; save file handle
	mov	bx,ax			; need handle here
	mov	cx,0			; setup file pointer
	mov	dx,0			; to end of file
	mov	al,2			; seek the end
	mov	ah,lseek
	int	dos
	jc	dmp2			; failure, indicate open failure
	jmp	short dmp3		; success
dmp1:	mov	ah,creat2		; file did not exist
	mov	cx,20h			; attributes, archive bit
	int	dos
	mov	dmphand,ax		; save file handle
	jnc	dmp3			; nc = ok
dmp2:	call	beep
	mov	ah,prstr		; print string
	mov	dx,offset dmperr	; cannot open file
	int	dos
	jmp	short dmp8		; Failure, exit
dmp3:	call	rdset			; Set up for screen reading
dmp4:	call	rdlne			; Read a screen line
	call	endfix			; Fix end of line and srceen
					; Write out the line
dmp5:	mov	dx,offset line		; array to be written
	mov	bx,dmphand		; need file handle
	mov	ah,write2		; write the line
	int	dos
	jc	dmp6			; Go if trouble.
	cmp	cx,ax			; Write as many bytes as requested?
	jnz	dmp6			; Go if trouble.
	cmp	eos,1			; End of screen?
	je	dmp7			; If yes, go.
	mov	ax,int_cy		; Else get the line index and set the
	shl	al,1			; pointer to the next line of screen
	shl	al,1			; data.
	shl	al,1
	mov	bh,al
	jmp	short dmp4		; Now loop back, do another line
dmp6:	call	beep			; Error writing file
	mov	ah,prstr		; print string
	mov	dx,offset dmperr1	; The message
	int	dos
dmp7:	mov	ah,close2		; close the file now
	mov	bx,dmphand		; file handle
	int	dos
	mov	al,vstate		; Restore the original video port
	out	VID_CMD,al		; state.
dmp8:	pop	es
	pop	si
	pop	di
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret				; Done with screen: return.
DUMPSCR ENDP

; Local routine rdset to set up for screen buffer reading.  Modifies ax, bx
; and es and enables acces to video memory.
RDSET:	cld				; Clear direction indicator.
	mov	eos,0			; Initialize end of screen flag to NO
	mov	lines,ROWS		; Assume 24 lines on the screen.
	mov	ax,IPAGE_SEG		; The interrupt page
	mov	es,ax			; Fetch the variable containing the
	mov	es,es:[MTR_DS]		; status of the 25th line:
	cmp	byte ptr es:[STATUS],0	; 00= disabled, FF= enabled.
	je	rdset1 
	inc	lines			; Set number of lines on screen to 25.
rdset1: in	al,VID_CMD		; Get the current video status.
	mov	vstate,al		; Save it.
	mov	al,78h			; Enable access to the memory.
	out	VID_CMD,al
	mov	ax,PAR_GRN		; Address the green plane, which is
	mov	es,ax			; where the characters are stored.
	mov	int_cy,0		; Start at line 0 on the screen.
	xor	bh,bh
	ret

; Local routine rdlne to read a screen line.  Enter with es pionting to
; the monitor interrup page.  Modifies ax, bx, si and di. 
RDLNE:	mov	bl,COLUMNS-1		; Offset of the last character.
	mov	di,COLUMNS-1		; Offset to the end of the line.
	xor	si,si			; Show no non-spaces found yet.
rdlne1: mov	al,es:[bx+9*128]	; Get the character's font index.
	add	al,' '			; Then make it into the character.
	cmp	al,' '			; Is the character a space?
	jne	rdlne2			; If not, go.
	and	si,si			; Any non-space found yet?
	jz	rdlne3			; If no, go.
rdlne2: mov	line[di],al		; Save the character.
	and	si,si			; Non-space found yet?
	jnz	rdlne3			; If yes, just go.
	lea	si,[di+1]		; Else keep the offset to the non-space.
rdlne3: dec	bl			; Go to next character.
	dec	di			; Decrement the offset to the line.
	jge	rdlne1			; Repeat this sequence for all chars.
	ret				; Reached the end of line:

; Local routine to add cr and lf at the end of each line and ff at the
; end of each page.  Modifies ax and cx.  Returns with number of chars
; in line buffer in cx.
endfix: mov	byte ptr line[si],CR	; Put in a CR
	mov	byte ptr line[si+1],LF	; Put in a LF
	lea	cx,[si+2]		; Set up the counter.
	inc	int_cy			; Up index to the next line and then
	mov	ax,int_cy		; get it.
	cmp	ax,lines		; Are we at the end of screen?
	jne	endfix1			; If not, go.
	mov	byte ptr line[si+2],FF	; Else store form feed for end of page.
	inc	cx			; Up length to print.
	mov	eos,1			; Turn on the end-of-screen flag.
endfix1:ret

; Save the entire screen in a buffer so we can restore it.
; Saves regular (80x25) screens to memory buffer allocated dynamically from
; DOS. Save address is savadr+2:savadr (seg:offset). A memory buffer is
; allocated as required.
savescr	proc	near
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	es
	mov	ax,low_rgt		; text screen lower right (typ 23,79)
	add	al,3			; plus 1 col, cr, lf
	add	ah,2			; plus 1 row plus status line
	mul	ah			; times rows = characters on screen
	inc	ax			;  plus the last one, ff
	mov	dx,ax			; save number of screen bytes in dx
	mov	ax,savadr+2		; seg of saved memory, if any
	or	ax,ax			; none?
	jnz	savsc4			; no, there is some
					; allocate and use DOS memory for save
savsc1:	mov	bx,dx			; bytes to do
	add	bx,16			; round up
	mov	cl,4
	shr	bx,cl			; bytes/screen to paragraphs/screen
	mov	ah,alloc		; allocate memory
	int	dos			; bx has # free paragraphs
	jc	savsc2			; c = not enough for it, skip
	mov	savadr+2,ax		; working seg address for restore
	jmp	short savsc4
savsc2:	mov	savadr+2,0		; then say no seg because no save
	jmp	short savsc7		; exit without saving screen
					; save the screen
savsc4:	mov	savadr,0		; no offset for memory buffer
	mov	cx,dx			; number of screen bytes
     	call	rdset			; Set up for screen reading
savsc5:	call	rdlne			; Read screen line
	call	endfix			; Add cr, lf and possibly ff
       	mov	ax,savadr+2		; Reached the end of line:
	push	es
	mov	es,ax			; Segment for buffer
	mov	si,offset line		; Array to be written
	mov	di,savadr		; We are here in buffer
	cld
	rep	movsb
	pop	es
	mov	savadr,di		; Save it for next line
	cmp	eos,1			; End of screen?
	je	savsc6			; If yes, go.
	mov	ax,int_cy		; Else get the line index and set the
	shl	al,1			; pointer to the next line of screen
	shl	al,1			; data.
	shl	al,1
	mov	bh,al
	jmp	short savsc5		; Now loop back, do another line
savsc6: mov	al,vstate		; Restore the original video port
	out	VID_CMD,al		; state.
savsc7:	pop	es
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
savescr	endp

; Restore screen from buffer (savadr+2:savadr, with number to write in savadr).
; Restores all screen lines.
restscr	proc	near
	push	ax
	push	bx
	xor	ax,ax			; upper left corner
	mov	bx,low_rgt
	call	atsclr			; blank screen
	mov	bx,dx			; holds cursor position
	mov	dx,ax			; upper left corner
	call	poscur			; set it
	cmp	savadr+2,0		; saved anything yet?
	mov	dx,ax			; restore it
	je	restsc2			; e = no
	push	cx
	push	bx			; this is in reality dx, cursor
	push	si
	push	di
	push	es
	mov	cx,savadr		; this many bytes to write
	sub	cx,3			;  but skip last cr,lf and ff
	mov	ax,savadr+2		; get segment for buffer
	mov	es,ax			;  into es
	xor	si,si			; offset zero for first char
restsc1:mov	al,byte ptr es:[si]	; get char
	push	cx			; MTR_SCRT messes up ax, bx, cx, dx,
	push	si			;  si, di and es, so we assume this
	call	MTR_DCRT		;  one is as bad.
	pop	si
	pop	cx
	mov	ax,savadr+2		; get segment for buffer
	mov	es,ax			;  into es
	inc	si			; next char
 	loop	restsc1	
	pop	es
	pop	di
	pop	si
	pop	dx
	pop	cx
restsc2:pop	bx
	pop	ax
	ret
restscr	endp

; Read cursor position
; DL = column, DH = row, both counted from 0,0 at upper left corner
getpos	proc	near
	push	bx
	push	es
	mov	bx,IPAGE_SEG		; the interrupt page
	mov	es,bx
	mov	es,word ptr es:MTR_DS	; find monitor data segment here
	mov	dl,byte ptr es:MTR_HORP ; column 0 to 79
	mov	dh,byte ptr es:MTR_VERP ; row	 0 to 24
	pop	es
	pop	bx
	ret
getpos	endp

; Screen clearing routine atsclr.
;
; Call:		ax/	coordinates of first screen location to be cleared.
;		bx/	coordinates of last location to be cleared.
; Coord: ah = row [0-24], al = column [0-79]. Preserves all registers.
ATSCLR	PROC	NEAR
       	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	bp
	push	es
      	push	ds
	mov	cx,IPAGE_SEG		; Get into es
	mov	es,cx
	mov	ds,es:[MTR_DS]		; Now get MTR_DS into ds and the
 	mov	bp,offset es:MTR_EDC	;  offset to the dword into bp
	mov	cx,ax			; Top left corner
	mov 	cl,ch			; Top line to cl
	xor	ch,ch			; Top line now in cx
	push	cx			; *   First parameter
	mov	cl,al			; Left column now in cx
	push	cx			; **  Second parameter
	sub	bh,ah			; Line count
	inc	bh			;  adjust
	sub	bl,al			; Char count
  	inc	bl			;  adjust
atsclr1:push	bx			; *** Third parameter in bl (and bh)
	call	dword ptr ds:[bp]	; Do a line
	sub	sp,2		; -2	; Point to first parameter, line
	pop	cx		; 0 	; Get it
	inc	cx			; Go to the next line
	push	cx		; -2	; Put it back into stack
	sub	sp,4		; -6	; The next param, left column, is ok
	pop	bx		; -4	; But we will check on the line count
	dec	bh			;  which we sneaked into here
	jnz	atsclr1			; If more lines left, do it again
	add	sp,4		; 0	; Don't waste time popping this junk
	pop	ds
	pop	es
	pop	bp
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
ATSCLR	ENDP

; Routine to do close to VT100-style bell, no arguments
vtbell	proc	near
	cmp	belltype,1		; visual bell?
	je	vtbell1			; e = yes
	call	beep
	ret
vtbell1:
	in	al,VID_CMD		; Get the current video status.
	mov	ah,al			; Save it.
	mov	al,0f0h			; Make screen all white
	out	VID_CMD,al		; Do it
	push	ax
	mov	ax,40			; for 40 milliseconds
	call	pcwait
	pop	ax
	mov	al,ah			; Get old status back
	out	VID_CMD,al		; Do it
	ret
vtbell	endp

comment @
; 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.  Preserves all registers.
; Call:		no arguments.
; This will work on graphics as well as text.  However, this is a true
; reverser meaning that ALL 'dark bits' will be 'lit upp' all 'lit up'
; ones will be 'darkened'.  This means for example that the reverse of
; yellow (green + red) on black (none) will be blue on white (all =
; blue + green + red).
revscn	proc	near
	push	ax
	push	cx
	push	si
	push	di
	push	ds
	push	es
	in	al,VID_CMD		; Get video port status
	push	ax			; Save it
	mov	al,7fh			; Turn off multiple access
	out	VID_CMD,al		;  and display
	mov	ax,PAR_GRN		; Green first
revscn0:mov	ds,ax			; Set up
	mov	es,ax			;  all
	xor	si,si			;  the
	mov	di,si			;  pointers
	mov	bx,8000h		; The whole plane
	mov	cx,40			; One line
	mov	dx,9			; 9 scan lines per char
	cld
revscn1:lodsw
	xor	ax,0ffffh
	stosw
	loop	revscn1			; A full scan line
	dec	dx			;  done
	jnz	revscn2			; A full char line?
	add	si,7*128		; Yes, skip the
	mov	di,si			;  7 next lines
	sub	bx,7*64			;  and adjust count
	mov	dx,9			; Prepare for next char line
revscn2:sub	bx,64			; Plane done?
	jz	revscn3			; z = yes, plane done
	add	si,48			; no, skip the non displayed
	mov	di,si			;  last 48
	mov	cx,40			; Prepare for next scan line
	jmp	short revscn1		;  and go do it
revscn3:mov	ax,ds			; Have we done
	cmp	ax,PAR_BLU		;  the blue?
	jz	revscn5			; Yes, all done, almost
	sub	ah,10h			; Go do next plane
	jmp	short revscn0 
revscn5:pop	ax			; Restore video
	out	VID_CMD,al		;  status
	pop	es
	pop	ds
	pop	di
	pop	si
	pop	cx
	pop	ax
	ret
revscn	endp
end comment @

; This is revscn which reverses the color attributes of characters currently
; displayed on the video screen.  It will only work on text and graphic
; characters.  Takes no arguments, preserves all registers.
REVSCN	PROC NEAR
       	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di
	push	bp
	push	es
	push	ds
	in	al,VID_CMD	; Read video state
	push	ax		; Save it
	mov	al,01111000b	; Mask current write bits, enable vram
	out	VID_CMD,al	; Set up 
	mov	ax,IPAGE_SEG	; Interrupt page
	mov	es,ax		;  into es
	mov	bp,offset es:MTR_DFC
	mov	ds,es:[MTR_DS]	; Monitor data segment
	mov	es,es:[MTR_DS]	; Monitor data segment
	xor	cx,cx		; Char index 0
revscn1:push	cx		; Preserve around call to mtr rom
	push	es		; This too
    	mov	ax,cx		; Index here
	mov	bl,COLUMNS
	div	bl		; Line now in al and column in ah
	mov	bh,al		; Line in bh
	mov	bl,ah		; Parameter 1, column, in bl
	push	bx		; *    Parameter # 1 set
	xchg	bh,bl		; Parameter 2, line, from bh to bl
	push	bx		; **   Parameter # 2 set
	xchg	bh,bl		; Get right order back
	mov	ax,PAR_GRN	; Point to green plane
	mov	es,ax
	shl	bh,1
	shl	bh,1
	shl	bh,1
	mov	al,es:byte ptr [bx+9*128]	; Char index
	mov	ah,es:byte ptr [bx+10*128]	; Char attributes
	push	ax		; ***  Third param, al holds char index
	mov	dh,ah
	and	dh,111b		; Foreground color
	mov	dl,ah
	shr	dl,1
	shr	dl,1
	shr	dl,1
	and	dl,111b		; Background color
	cmp	cs:tempcol,dx	; New color or fresh start?
	jz	revscn2		; No, just skip all of this
	mov	cs:tempcol,dx	; Remember color
	xchg	dh,dl		; Reverse it
	call	setcol		; Set the reversed color
revscn2:mov	ax,0
	push	ax 		; **** Fourth, display it as is
 	call	dword ptr ds:[bp] ; Display char
	pop	es		; Get these
	pop	cx		;  back
	inc	cx
 	cmp	byte ptr es:[STATUS],0		; Status line not on?
	jz	revscn3				; No, go do 24 lines
	cmp	cx,COLUMNS * (ROWS + 1)		; < 80 * (24 + 1) = 2000?
	jb	revscn1				; Yes, go do next char
revscn3:cmp	cx,COLUMNS * ROWS		; < 80 * 24 = 1920?
	jb	revscn1				; Yes, go do next char
	pop	cx				; No, all done, almost
	out	VID_CMD,al	; Restore video
	mov	cs:tempcol,0ffffh ; Reset for next time
	pop	ds
	pop	es
	pop	bp
	pop	di
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax
	ret
tempcol	dw	0ffffh		; Storage for the last set colors
REVSCN	ENDP

; Set cursor postion.  Destroys dx.
; DL = column, DH = row, both counted from 0,0 at upper left corner
setpos	proc	near
	jmp	poscur
setpos	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
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
	test	bl,1			; ANSI red?
	jz	setcol1			; z = no
	or	ah,2			; Z-100 red foreground bit
setcol1:test	bl,2			; ANSI green?
	jz	setcol2			; z = no
	or	ah,4			; Z-100 green foreground bit
setcol2:test	bl,4			; ANSI blue?
	jz	setcol3			; z = no
	or	ah,1			; Z-100 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
	test	bl,1			; ANSI red?
	jz	setcol5			; z = no
	or	ah,10h			; Z-100 red background bit
setcol5:test	bl,2			; ANSI green?
	jz	setcol6			; z = no
	or	ah,20h			; Z-100 green background bit
setcol6:test	bl,4			; ANSI blue?
	jz	setcol7			; z = no
	or	ah,8h			; Z-100 blue background bit
setcol7:ret
setcolor endp

; Set screen color.  Destroys dx.
; DH = foregroung color, DL = backgrond color per Z-100 standards.
; 0 = black, 1 = blue, 2 = green, 3 = cyan, 4 = red, 5 = magenta,
; 6 = yellow, 7 = white
setcol	proc	near
	push	ax
	push	dx
	mov	ah,conout
	mov	dl,ESCAPE
	int	dos
	mov	dl,'m'
	int	dos
	pop	dx
	push	dx
	mov	dl,dh
	add	dl,'0'
	int	dos
	pop	dx
	add	dl,'0'
	int	dos
	pop	ax
	ret
setcol	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
	mov	dl,keycli	
	call	keycom
vclick1:ret
vclick	endp

;;; Action routines (verbs) for keyboard translator KEYBD in msuibm.
; These are invoked by a jump instruction. Return carry clear for normal
; processing, return carry set for invoking Quit (kbdflg has transfer char).
uparrw: mov	al,'A'			; cursor keys
	jmp	short comarr
dnarrw: mov	al,'B'
	jmp	short comarr
rtarr:	mov	al,'C'
	test	vtemu.vtflgop,vswdir	; writing left to right?
	jz	comarr			; z = yes
	mov	al,'D'			; reverse sense of keys
	jmp	short comarr
lfarr:	mov	al,'D'
	test	vtemu.vtflgop,vswdir	; writing left to right?
	jz	comarr			; z = yes
	mov	al,'C'			; reverse sense of keys
comarr: push	ax			; save final char
	mov	ttyact,0		; network, group chars for packet
	test	vtemu.vtflgop,decanm	; ANSI mode?
	jz	comar2			; z = no
	mov	al,CSI			; CSI character
	test	vtemu.vtflgop,decckm	; cursor key mode reset?
	jz	comar1			; z = yes
	mov	al,SS3			; SS3 character
comar1: call	out8bit			; send in 7 or 8 bit form
	jmp	short comar3

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

f0:	mov	al,'J'			; Z-100 function keys
	jmp	short comf
f1:	mov	al,'S'
	jmp	short comf
f2:	mov	al,'T'
	jmp	short comf
f3:	mov	al,'U'
	jmp	short comf
f4:	mov	al,'V'
	jmp	short comf
f5:	mov	al,'W'
	jmp	short comf
f6:	mov	al,'P'
	jmp	short comf
f7:	mov	al,'Q'
	jmp	short comf
f8:	mov	al,'R'
	jmp	short comf
f9:	mov	al,'I'
	jmp	short comf0
f10:	mov	al,'J'
	jmp	short comf0
f11:	mov	al,'K'
	jmp	short comf0
f12:	mov	al,'L'
	jmp	short comf0
sf0:	mov	al,'E'
comf:	mov	ah,0			; only one char
	jmp	short comf_
sf1:	mov	al,'A'
	jmp	short comf1
sf2:	mov	al,'B'
	jmp	short comf1
sf3:	mov	al,'C'
	jmp	short comf1
sf4:	mov	al,'D'
	jmp	short comf1
sf5:	mov	al,'E'
	jmp	short comf1
sf6:	mov	al,'F'
	jmp	short comf1
sf7:	mov	al,'G'
	jmp	short comf1
sf8:	mov	al,'H'
	jmp	short comf1
sf9:	mov	al,'I'
	jmp	short comf1
sf10:	mov	al,'J'
	jmp	short comf1
sf11:	mov	al,'K'
	jmp	short comf1
i_chr:	cmp	insert,'O'		; overwrite mode?
	mov	insert,'O'
	jnz	i_chr1			; no, make it overwrite
	mov	insert,'@'		; yes, make it insert
i_chr1: mov	al,insert
	jmp	short comf
d_chr:	mov	al,'N'
	jmp	short comf
i_line: mov	al,'L'
	jmp	short comf
d_line: mov	al,'M'	   
	jmp	short comf
comf0:	mov	ah,'0'			; second char is '0'
	jmp	short comf_
comf1:	mov	ah,'1'			; second char is '1'
comf_:	push	ax			; save final char
	mov	ttyact,0		; network, group chars for packet
	mov	al,escape		; output ESC
	call	prtbout
	pop	ax			; get the saved char
	cmp	ah,0			; only one char?
	jz	comf_1
	push	ax			; save it again
	xchg	al,ah			; need ah first
	call	prtbout
	pop	ax			; get the saved char
comf_1: mov	ttyact,1		; network, restore tty active flag
	call	prtbout
	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	out8bit			; send 7 or 8 bit version
	jmp	short compf2
compf1: mov	al,escape		; output ESC
	call	prtbout
compf2: pop	ax			; get the saved char
	mov	ttyact,1		; network, restore tty active flag
	call	prtbout
	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	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	out8bit			; send 7 or 8 bit version
	jmp	comkp3
comkp2: mov	al,escape		; output "ESC ?"
	call	prtbout
	mov	al,'?'
	call	prtbout
comkp3: pop	ax			; recover final char
	mov	ttyact,1		; network, restore tty active flag
	call	prtbout			; send it
	ret

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

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

snull	proc	near			; send a null byte
	xor	al,al			; the null
	jmp	prtbout			; send without logging and local echo
snull	endp

; output, no echo, 8-bit control chars as literals or "ESC char" form
out8bit proc	near
	mov	ttyact,0		; network, group chars for packet
	cmp	flags.vtflg,ttvt320	; VT320?
	jne	out8bi1			; ne = no
	cmp	parmsk,7fh		; using parity?
	je	out8bi1			; e = yes
	test	vtemu.vtflgop,vscntl	; doing 8-bit controls?
	jnz	out8bi2			; nz = yes, send 8-bit control char
out8bi1:test	al,80h			; in range for C1 controls?
	jz	out8bi2			; z = no
	cmp	al,9fh
	ja	out8bi2			; a = no
	push	ax
	mov	al,escape		; send ESCAPE
	call	prtbout
	pop	ax
	sub	al,40h			; compose second char
out8bi2:mov	ttyact,1		; network, restore single char mode
	jmp	prtbout			; send final char
out8bit endp
					; 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
cmdcom: mov	kbdflg,al		; pass char to msster.asm via kbdflg
	stc				; signal that Quit is needed
	ret

;SCROLL makes it possible to review the last screen (up to 26 lines).  F11
;invokes scroll and scrolling is done with BACK SPACE and LINE FEED keys.
;The RETURN key latches the screen in the new position, any other key restores
;to the original status.
scroll	proc near
	push	ax
	push	cx
	push	dx
	push	es
	mov	ax,ipage_seg		; the interrupt page
	mov	es,ax
	mov	es,word ptr es:mtr_ds	; find monitor data segment here
	cmp	byte ptr es:VRAM_SIZE,1	; Must be 1 for 64k video chips
	jz	scroll1			; Yes, go on
	mov	ah,prstr		; No, tell user, skip
	mov	dx,offset vidmsg
	int	dos
	jmp	short scroll6
scroll1:mov	dx,word ptr es:DISP_START ; get start address
	mov	startad,dx		; save it
scroll2:mov	dx,word ptr es:DISP_START ; get start address
	sub	dx,80			; assume 1 line backwards
	cmp	al,10			; line feed ^J
	jnz	scroll3			; no, backwards
	add	dx,160			; yes, forward
scroll3:mov	word ptr es:DISP_START,dx ; set new start address
	mov	dx,0ffh
	mov	byte ptr es:DISP_UPDATE,dl ; request update
	mov	ah,coninq
	int	dos
	cmp	al,8			; if back space ^H, go scroll up
	jz	scroll2
	cmp	al,10			; if line feed ^J, go scroll down
	jz	scroll2
	cmp	al,cr			; if carrage return, go latch it
	jz	scroll4
	mov	dx,startad		; else, just go back
	mov	word ptr es:DISP_START,dx ; set start address
	mov	dx,0ffh
	mov	byte ptr es:DISP_UPDATE,dl ; request update
	jmp	short scroll6
;
scroll4:
	mov	ax,word ptr es:DISP_START ; get start address
	mov	cl,4			; shift count
	shr	ax,cl			; al now has latch value
	out	0dah,al			; initialize latch
	mov	dx,1700h		; put cursor at beginning of last line
	call	poscur
	test	yflags,modoff		; is mode line disabled?
	jnz	scroll5			; yes, skip it
	call	modlin			; enable and write modline
	jmp	short scroll6
scroll5:call	clrmod			; clear mode line
scroll6:pop	es
	pop	dx
	pop	cx
	pop	ax
	ret
scroll	endp

; (BDT) new screen-scrolling routines.	Single, circular buffer
     
homwnd	proc	near			; "home" to start of the buffer
	push	cx			; save registers
	mov	cx,lxtra		; save this many lines
	call	putcirc			; save them
	mov	linec,0			; reset the current pointer
	call	getcirc			; now get the new screen
	pop	cx			; restore registers
	clc
	ret
homwnd	endp
     
endwnd	proc	near			; "end" to end of the buffer
	push	cx			; save registers
	mov	cx,lxtra		; save this many lines
	call	putcirc			; save them
	mov	cx,lcnt			; reset the current pointer
	mov	linec,cx		; save the results
	call	getcirc			; now get the new screen
	pop	cx			; restore registers
	clc
	ret
endwnd	endp
     
dnwpg	proc	near			; scroll down 1 page
	push	cx			; save registers
	mov	cx,lxtra		; save this many lines
	call	putcirc			; save them
	mov	cx,linec		; reset the current pointer
	add	cx,lxtra		;  to the next page
	cmp	cx,lcnt			; did we go past the end?
	jbe	dnwpg1			; be = no, we're OK
	mov	cx,lcnt			; yup, back up
dnwpg1:
	mov	linec,cx		; save the results
	call	getcirc			; now get the new screen
	pop	cx			; restore registers
	clc
	ret
dnwpg	endp
     
dnone	proc	near			; scroll down 1 line
	push	cx			; save registers
	mov	cx,lxtra		; save this many lines
	call	putcirc			; save them
	mov	cx,linec		; reset the current pointer
	inc	cx			;  to the next line
	cmp	cx,lcnt			; oops, did we go past the end?
	jbe	dnone1			; be = no, we're OK
	mov	cx,lcnt			; yup, back up
dnone1:
	mov	linec,cx		; save the results
	call	getcirc			; now get the new screen
	pop	cx			; restore registers
	clc
	ret
dnone	endp
     
upwpg	proc	near			; scroll up 1 page
	push	cx			; save registers
	mov	cx,lxtra		; save this many lines
	call	putcirc			; save them
	mov	cx,linec		; reset the current pointer
	sub	cx,lxtra		;  to the previous page
	cmp	cx,0			; oops, did we go past the end?
	jge	upwpg1			; ge = no, we're OK
	xor	cx,cx			; yup, back up
upwpg1:
	mov	linec,cx		; save the results
	call	getcirc			; now get the new screen
	pop	cx			; restore registers
	clc
	ret
upwpg	endp
     
upone	proc	near			; scroll up 1 line
	push	cx			; save registers
	mov	cx,lxtra		; save this many lines
	call	putcirc			; save them
	mov	cx,linec		; reset the current pointer
	dec	cx			;  to the previous line
	cmp	cx,0			; oops, did we go past the end?
	jge	upone1			; ge = no, we're OK
	xor	cx,cx			; yup, back up
upone1:
	mov	linec,cx		; save the results
	call	getcirc			; now get the new screen
	pop	cx			; restore registers
	clc
	ret
upone	endp
     
; Put cx lines into the circular buffer.  Characters are stored as a word
; containig the Z-100 font index (low) and the Z-100 attributes (high).
; Source segment is tv_segs which is set to point to the green video plane.
; Source offset for each char is calculated below based on the screen char
; index in si.	The index starts at 0 and ends at COLUMNS * ROWS - 1 = 1919,
; corresponding to 1920 characters.
putcirc proc	near			; put lines in the circular buffer
	jcxz	putcir9			; z = no lines to save
	push	es			; save ES for a tad
	xor	si,si			; Screen char index
	mov	ax,linef		; get the first line pointer
	add	ax,linec		; add the current line counter
	dec	ax			; get a running start
	sub	si,COLUMNS	    	; Here too
putcir1:inc	ax			; increment the current line pointer
	add	si,COLUMNS	      	; This many char per line
	cmp	ax,linee		; fallen off the end of the buffer?
	jb	putcir2			; b = no, proceed
	sub	ax,linee		; back up to the buffer start
putcir2:push	ax			; save the current line pointer
	mul	ppl			; compute the paragraph offset
	add	ax,iniseg		; add the initial segment
	mov	es,ax			; now we have the segment pointer
	xor	di,di			; initial buffer offset is 0
	push	cx			; save the number of lines
	push	si			; Save index
	xor	ch,ch			; get the number of characters to move
	mov	cl,COLUMNS		; One row
	push	ds			; get the offset of the screen
	mov	ds,tv_segs		; get the segment of the screen
    	mov	ax,si			; Index here
	div	cl			; Line now in al and column in ah
	mov	bh,al			; Line in bh
	mov	bl,ah			; Column in bl
	shl	bh,1
	shl	bh,1
	shl	bh,1
putcir3:mov	al,ds:byte ptr [bx+9*128]	; Char index
	mov	ah,ds:byte ptr [bx+10*128]	; Char attributes
	stosw
	inc	bl			; Next char
	loop	putcir3			; Go back for next char
	pop	ds			; restore DS
	pop	si			; Restore index
	pop	cx			; restore the line count
	pop	ax			; restore the buffer counter
	loop	putcir1			; go back for more
	pop	es			; restore ES
putcir9:ret				; Note, also used by getcirc below
putcirc endp
     
; Get CX lines from the circular buffer, non destructivly.  Destination
; segment is the green video plane and destination offset for each char
; is calculated below based on the screen char index in di.  The index
; starts at 0 and ends at COLUMNS * ROWS - 1 = 1919, corresponding to
; 1920 characters.  The call to MTR_DFC writes to the destination.
getcirc proc	near			; get lines from the circular buffer
	mov	cx,lxtra		; restore this many lines
	jcxz	putcir9			; z = nothing to do
	push	es			; save ES for a tad
	mov	ax,IPAGE_SEG		; Interrupt page
	mov	es,ax			;  into es
	mov	bp,offset es:MTR_DFC	; Need this pointer for our call
	mov	es,es:[MTR_DS]		; Monitor data segment
	xor	di,di			; Screen char index
	mov	ax,linef		; get the first line pointer
	add	ax,linec		; add the current line counter
	dec	ax			; get a running start
	sub	di,COLUMNS	    	; Here too
getcir1:inc	ax			; increment the current line pointer
	add	di,COLUMNS	      	; This many char per line
	cmp	ax,linee		; fallen off the end of the buffer?
	jb	getcir2			; b = no, proceed
	sub	ax,linee		; back up to the buffer start
getcir2:push	ax			; save the current line pointer
	mul	ppl			; compute the paragraph offset
	add	ax,iniseg		; add the initial segment
	xor	si,si			; initial offset is 0
	push	cx			; save the number of lines
	push	di			; Save index
	xor	ch,ch			; get the number of characters to move
	mov	cl,COLUMNS		; One row
	push	ds			; save DS for a tad
	push	es			; Save MTR_DS
	mov	ds,ax			; now we have the segment pointer
    	mov	ax,di			; Index here
	div	cl			; Line now in al and column in ah
	mov	bh,al			; Line in bh
	mov	bl,ah			; Parameter 1, column, in bl
	push	bx			; *    Parameter # 1 set
	xchg	bh,bl			; Parameter 2, line, from bh to bl
	push	bx			; **   Parameter # 2 set
	xchg	bh,bl			; Get right order back
getcir3:mov	bh,0			; Column now in bx
	shl	bx,1			; 2 bytes per cell in buffer
	mov	ax,word ptr ds:[di.bx]	; Get the char from buffer
	push	ax			; ***  Parameter # 3 set
	mov	dh,ah
	and	dh,111b			; Foreground color
	mov	dl,ah
	shr	dl,1
	shr	dl,1
	shr	dl,1
	and	dl,111b			; Background color
	cmp	cs:tempcol,dx		; New color or fresh start?
	jz	getcir4			; No, just skip all of this
	mov	cs:tempcol,dx		; Remember color
	call	setcol			; Set the color
getcir4:and	ah,80h			; Reverse video?
	mov	ax,0 			; Assume no
	jz	getcir5			; No, skip this
	mov	ax,0ffffh		; Set up parameter # 4
getcir5:push	ax			; **** Parameter # 4 set
 	call	dword ptr es:[bp]	; Display char
	pop	es			; We need this for our call
	push	es			; Save again
	sub	sp,2			; Point to first parameter
	pop	bx			; Get it back
	inc	bl			; Next char
	push	bx			; *    Parameter # 1 set
	sub	sp,2			; **   Parameter # 2 set, old value
	loop	getcir3
	add	sp,6
	pop	ds			; restore DS
	pop	di			; restore index
	pop	cx			; restore the line count
	loop	getcir1			; go back for more
	mov	cs:tempcol,0ffffh	; Restore for next time
	pop	es			; restore ES
getcir6:ret
getcirc endp
					; Screen dump entry from keyboad xlat
dmpscn	proc	near			; dump screen to file
	call	dumpscr			; do buffer to file
	clc				; do not exit Connect mode
	ret
dmpscn	endp

code	ends 
	end

