	page	78,132
	title	Monochrome Display I/O driver for Monitor

LineLen		=	132
nCols		=	80
nRows		=	25
MonoBase	=	0

	.model	small
	.code
	.data
InitSeg segment byte public
InitSeg ends

	public	LineBuf

LineBuf		db	LineLen dup(0)
MonoPtr		dd	0B0000000H

DGroup	group	_TEXT,_DATA,InitSeg

	.code

	public	InBuf, OutCh, InCh, CrLf

	extrn	Backup:near, Command:near

;Get input line
	assume	cs:DGroup,ds:DGroup

INBUF:
	MOV	DI,offset DGroup:LINEBUF	;Next empty buffer location
	XOR	CX,CX		;Character count
GETCH:
	CALL	InCh		;Get input character
	CMP	AL,20H		;Check for control characters
	JC	CONTROL
	CMP	AL,7FH		;RUBOUT is a backspace
	JZ	BACKSP
	CALL	OutCh		;Echo character
	STOSB			;Put in input buffer
	INC	CX		;Bump character count
	CMP	CX,LineLen	;Buffer full?
	JBE	GETCH		;Drop in to backspace if full
BACKSP:
	JCXZ	GETCH		;Can't backspace over nothing
	DEC	DI		;Drop pointer
	DEC	CX		;and character count
	CALL	BACKUP		;Send physical backspace
	jmp	GETCH		;Get next char.

CONTROL:
	CMP	AL,3		;Ctrl-C?
	JZ	KILL
	cmp	al,1BH		;ESC?
	jz	Kill
	CMP	AL,8		;Check for backspace
	JZ	BACKSP
	CMP	AL,13		;Check for carriage return
	JNZ	GETCH		;Ignore all other control char.
	STOSB			;Put the car. ret. in buffer
;Convert unquoted input to upper case
	MOV	SI,offset DGroup:LINEBUF
	mov	di,si
CaseChk:
	lodsb
	cmp	al,"a"
	jb	NoConv
	cmp	al,"z"
	ja	NoConv
	sub	al,"a"-"A"		;Convert to upper case
NoConv:
	stosb				;Put it back where we got it
	cmp	al,13			;End of line?
	jz	InDone
	cmp	al,'"'
	jz	QuotScan
	cmp	al,"'"
	jnz	CaseChk
QuotScan:
	mov	ah,al			;Remember which quote mark
KillStr:
	lodsb
	stosb
	cmp	al,13
	jz	InDone
	cmp	al,ah
	jnz	KillStr
	jmp	CaseChk

InDone:
	mov	si,offset DGroup:LINEBUF ;Set up SI for command processing

;Output CR/LF sequence

CRLF:
	MOV	AL,13
	CALL	OutCh
	MOV	AL,10
	jmp	short OutCh

;Cancel input line

KILL:
	CALL	CRLF
CommandJ:
	JMP	COMMAND

;Character input routine

InCh:
	MOV	AH,0
	INT	22		;Call ROM BIOS for a character
	RET


;Console output of character in AL
	assume	ds:nothing,es:nothing,ss:nothing

DELAY	macro
	jmp	short $+2
	endm

OutCh:
	push	ax
	push	dx
	push	es
	push	di
	and	al,7FH
	les	di,[MonoPtr]
	cmp	al,13
	jz	MonoCr
	cmp	al,10
	jz	MonoLf
	cmp	al,9
	jz	MonoTab
	cmp	al,8
	jz	MonoBs
	cmp	al,7
	jz	MonoBell
	mov	ah,7
	stosw
ScrollTest:
	cmp	di,MonoBase+(nRows*nCols*2)
	jb	SavePtr
;Scroll screen
	sub	di,nCols*2
	push	ds
	push	si
	push	cx
	push	di
	push	es
	pop	ds
	mov	si,MonoBase+(nCols*2)
	mov	di,MonoBase
	mov	cx,(nRows-1)*nCols
rep	movsw
	mov	cx,nCols
	mov	ax,7*100H + " "		;Fill with low-intensity blank
rep	stosw
	pop	di
	pop	cx
	pop	si
	pop	ds
SavePtr:
	mov	word ptr [MonoPtr],di
;Set cursor register
	mov	dx,3B4H			;6845 index register I/O port
	mov	al,15			;Cursor addr., low
	out	dx,al
	xchg	ax,di			;Address to ax
	shr	ax,1			;6845 thinks it's 1 byte/char
	inc	dx			;Pick data register
	DELAY
	out	dx,al
	mov	al,14			;Cursor addr., high
	dec	dx
	out	dx,al
	mov	al,ah
	inc	dx
	DELAY
	out	dx,al
	pop	di
	pop	es
	pop	dx
	pop	ax
	ret

MonoCr:
;Compute start of this line
	mov	ax,di
	xor	dx,dx			;Extend to 32 bits
	mov	di,nCols*2
	div	di			;Compute row number
	mul	di			;Offset of start of row
	mov	di,ax
	jmp	SavePtr

MonoLf:
	add	di,nCols*2
	jmp	ScrollTest

MonoTab:
	mov	ax,di
	xor	dx,dx			;Extend to 32 bits
	mov	di,8*2			;Tabs every 8
	div	di			;Compute tab position
;Remainder in dx tells us how far into the tab stop we are
	sub	di,dx			;Amount to move forward to next tab
	add	di,word ptr [MonoPtr]
	jmp	SavePtr

MonoBs:
	dec	di
	dec	di
	jmp	SavePtr

MonoBell:
	jmp	SavePtr

;************************************************************

InitSeg	segment
	assume	cs:DGroup,ds:DGroup

;Clear screen
	les	di,[MonoPtr]
	mov	ax," "+7*100H		;Fill with low-intensity blanks
	mov	cx,80*25
rep	stosw				;Clear screen
	xor	di,di
InitSeg	ends

	end
