PUBLIC	.CAPS,	Escape_Character, FillParagraph, GetColumn

EXTRN	CYSave:Near, CDELK:Near, .Error0:Near, CCenter:Near
EXTRN	.ERROR1:NEAR, CDELK:Near, .MakeSpace:Near, FillColumn:Word
EXTRN	PreviousScreen:NEAR, ScrollDown:NEAR
;---------------------------------------------------------------------------

	Page ,132
NAME	FESC

TITLE Escape Character Handler

IF2
	%OUT *Pass 2*
ENDIF


Program SEGMENT PARA	PUBLIC  'code'
	ASSUME  CS:Program, DS:Program, ES:Program, SS:Program

INCLUDE	FDEF.DEF

MJTable	dw	Offset	MInvalid	; ^@
dw	Offset	MInvalid		; ^A
dw	Offset	MInvalid		; ^B
dw	Offset	MInvalid		; ^C
dw	Offset	MInvalid		; ^D
dw	Offset	MInvalid		; ^E
dw	Offset	MInvalid		; ^F
dw	Offset	MInvalid		; ^G
dw	Offset	MRubWord		; ^H
dw	Offset	MInvalid		; ^I
dw	Offset	MInvalid		; ^J
dw	Offset	MInvalid		; ^K
dw	Offset	MInvalid		; ^L
dw	Offset	MInvalid		; ^M
dw	Offset	MInvalid		; ^N
dw	Offset	MInvalid		; ^O
dw	Offset	MInvalid		; ^P
dw	Offset	MInvalid		; ^Q
dw	Offset	MInvalid		; ^R
dw	Offset	MInvalid		; ^S
dw	Offset	MInvalid		; ^T
dw	Offset	MInvalid		; ^U
dw	Offset	MInvalid		; ^V
dw	Offset	MInvalid		; ^W
dw	Offset	MInvalid		; ^X
dw	Offset	MInvalid		; ^Y
dw	Offset	MInvalid		; ^Z
dw	Offset	MInvalid		; ^[
dw	Offset	MInvalid		; ^\
dw	Offset	MInvalid		; ^]
dw	Offset	MInvalid		; ^^
dw	Offset	MInvalid		; ^_
dw	Offset	MInvalid		; ' '
dw	Offset	MInvalid		; !
dw	Offset	MInvalid		; "
dw	Offset	MInvalid		; #
dw	Offset	MInvalid		; $
dw	Offset	MInvalid		; %
dw	Offset	MInvalid		; &
dw	Offset	MInvalid		; `
dw	Offset	MInvalid		; (
dw	Offset	MInvalid		; )
dw	Offset	MInvalid		; *
dw	Offset	MInvalid		; +
dw	Offset	MInvalid		; `
dw	Offset	MInvalid		; -
dw	Offset	MInvalid		; .
dw	Offset	MInvalid		; \
dw	Offset	MInvalid		; 0
dw	Offset	MInvalid		; 1
dw	Offset	MInvalid		; 2
dw	Offset	MInvalid		; 3
dw	Offset	MInvalid		; 4
dw	Offset	MInvalid		; 5
dw	Offset	MInvalid		; 6
dw	Offset	MInvalid		; 7
dw	Offset	MInvalid		; 8
dw	Offset	MInvalid		; 9
dw	Offset	MInvalid		; :
dw	Offset	MInvalid		; ;
dw	Offset	CStartFile		; <
dw	Offset	MInvalid		; =
dw	Offset	CEndFile		; >
dw	Offset	MInvalid		; ?
dw	Offset	MInvalid		; @
dw	Offset	MInvalid		; A
dw	Offset	WBackward		; B
dw	Offset	WCapitalize		; C
dw	Offset	MDelWord		; D
dw	Offset	MInvalid		; E
dw	Offset	WForward		; F
dw	Offset	MInvalid		; G
dw	Offset	MInvalid		; H
dw	Offset	MInvalid		; I
dw	Offset	MInvalid		; J
dw	Offset	MInvalid		; K
dw	Offset	MInvalid		; L
dw	Offset	MInvalid		; M
dw	Offset	MInvalid		; N
dw	Offset	MInvalid		; O
dw	Offset	MInvalid		; P
dw	Offset	FillParagraph		; Q
dw	Offset	MInvalid		; R
dw	Offset	MInvalid		; S
dw	Offset	MInvalid		; T
dw	Offset	WUppercase		; U
dw	Offset	PreviousScreen		; V
dw	Offset	MInvalid		; W
dw	Offset	MInvalid		; X
dw	Offset	MInvalid		; Y
dw	Offset	ScrollDown		; Z
dw	Offset	MInvalid		; [
dw	Offset	MInvalid		; \
dw	Offset	MInvalid		; ]
dw	Offset	MInvalid		; ^
dw	Offset	MInvalid		; _
dw	Offset	MInvalid		; '
					; lowercase trapped

MInvalidT0	db	'*** ESC-'
MInvalidT1	db	'? unknown ***'
$Error1	 	db	'*** FileStart ***'
$Error2	 	db	'*** FileEnd ***'
Confusedbreak	db	'*** Can not break Line ***'
PStart		dw	100h
PEnd		dw	101h


;---------------------------------------------------------------------------
Escape_Character	PROC	Near

	call	.CAPS

	cmp	AL, 'z'
	ja	MInvalid1
	
MParse:	xor	AH, AH			; clear insignificant
	add	AX, AX			; dw index
	mov	BX, AX			; get the index
	jmp	CS:MJTable [BX]		; and jump
MInvalid:
	shr	AL, 1			; to adjust for the jump table
MInvalid1:
	mov	CS:MInvalidT1, AL
	mov	SI, Offset MInvalidT0
	mov	CX, 21
	jmp	.Error0

Escape_Character  ENDP

;-------------------Escape-Sequences-Processing---------------------------
CStartFile	PROC	Near

	mov	DS:BCB.FCursor, 100h
	ret

CStartFile	ENDP
;...........................................................................
CEndFile	PROC	Near

	mov	AX, DS:BCB.FEnd
	mov	DS:BCB.FCursor, AX
	ret

CEndFile	ENDP
;---------------------------------------------------------------------------
WUppercase	PROC	NEAR
	mov	DS:BCB.Dirty, TRUE
	call	.?WBackWard
	mov	DX, DS:BCB.FCursor
WUp1:	mov	AL, DS:[BX]
	call	.CAPS
	mov	DS:[BX], AL
	inc	BX
	cmp	BX, DX
	jbe	WUp1
	ret
WUppercase	ENDP
;...........................................................................
WCapitalize	PROC	NEAR
	mov	DS:BCB.Dirty, TRUE
	mov	DX, DS:BCB.FCursor
	call	.?WBackWard
	mov	AL, DS:[BX]
	call	.CAPS
	mov	DS:[BX], AL
	inc	BX
	cmp	BX, DX
	ja	WCap3
WCap2:	mov	AL, DS:[BX]
	call	.NOCAPS
	mov	DS:[BX], AL
	inc	BX
	cmp	BX, DX
	jbe	WCap2
WCap3:	ret

WCapitalize	ENDP
;---------------------------------------------------------------------------
.CAPS  PROC	Near
	cmp	AL, 'a'
	jb	.Caps1
	cmp	AL, 'z'
	ja	.Caps1
	sub	AL, 'a'-'A'
.Caps1: ret
.CAPS  ENDP
;...........................................................................
.NOCAPS	PROC	NEAR
	cmp	AL, 'A'
	jb	.NOCAPS1
	cmp	AL, 'Z'
	ja	.NOCAPS1
	add	AL, 'a'-'A'
.NoCaps1:
	ret
.NoCAPS	ENDP

;---------------------------------------------------------------------------
WBackWard	PROC	NEAR

	call	.?WBackWard
	cmp	BX, 0
	je	WBErr
	mov	DS:BCB.FCursor, BX
	ret

WBErr:  mov	SI, Offset $Error1
	mov	CX, 17
	jmp	.Error0

WBackward	ENDP

;...........................................................................
WForward	PROC	Near

	call	.?WForward
	cmp	BX, 0
	je	WFErr
	mov	DS:BCB.FCursor, BX
	ret

WFErr:  mov	SI, Offset $Error2
	mov	CX, 16
	jmp	.Error0

WForward	ENDP

;...........................................................................
MRubWord	PROC	Near

	call	.?WBackWard
	cmp	BX, 0
	je	MRubWErr
	mov	SI, BX
	mov	CX, DS:BCB.FCursor
	sub	CX, BX
	mov	DS:BCB.FCursor, SI
	call	CYSave
	jmp	CDelK

MRubWErr:
	mov	SI, Offset $Error1
	mov	CX, 16
	jmp	.Error0

MRubWord	ENDP

;...........................................................................
MDelWord	PROC	Near
	call	.?WForWard
	cmp	BX, 0
	je	MDelWErr
	mov	SI, DS:BCB.FCursor
	mov	CX, BX
	sub	CX, SI

	call	CYSave
	jmp	CDelK

MDelWErr:
	mov	SI, Offset $Error2
	mov	CX, 16
	jmp	.Error0

MDelWord	ENDP
;---------------------------------------------------------------------------
; BUGGY !!!
;CPScreen	PROC	NEAR

	mov	BX, DS:BCB.ScrStart
	mov	AH, 79
	mov	AL, 20
CPLoop1:
	cmp	Byte Ptr [BX], LF
	je	CPPhysical
	cmp	AH, 0
	je	CPPhysical
	cmp	BX, 100h
	je	CPErr
	dec	BX
	dec	AH
	jmp	CPLoop1

CPPhysical:					; now we are on the physical
	dec	AL				; and logical line, but still
	jz	CPPhysicalFound			; have to find the filestart
	mov	AH, 79
	cmp	Byte Ptr [BX], LF
	jne	CPLoop1
	dec	BX
	jmp	CPLoop1

CPPhysicalFound:				; this can probably be improvd
	cmp	Byte Ptr ds:[bx], LF
	jne	CPPhysicl0
	dec	bx
CPPhysicl0:
	mov	AL, 0
	mov	AH, 1
CPLoop2:
	dec	BX
	cmp	BX, 100h
	jbe	CPStartFound
	cmp	Byte Ptr [BX], LF
	je	CPStartFound
	inc	AL
	cmp	AL, 79
	jne	CPLoop2

	add	AH, 79
	mov	AL, 0
	jmp	CPLoop2

CPStartFound:
	cmp	BX, 100h
	ja	CPLoop3
	mov	BX, 100h
	jmp	CPEnd

CPLoop3:
	inc	BX
	dec	AH
	je	CPEnd
	jmp	CPLoop3

CPEnd:
	mov	DS:BCB.ScrStart, BX
	mov	DS:BCB.FCursor, BX
	ret

CPErrT  db	'>>>Incomplete ESC-V<<<'

CPErr:
	mov	DS:BCB.ScrStart, BX
	mov	DS:BCB.FCursor, BX
	mov	SI, Offset CPErrT
	mov	CX, 22
	jmp	.Error1


;CPScreen	ENDP

;---------------------------------------------------------------------------
.?WForward	PROC	Near

	mov	BX, DS:BCB.FCursor
	mov	DX, DS:BCB.FEnd
	dec	BX			; initialize

; find space character
.?WFL1:	cmp	BX, DX
	jae	.?WForwardErr
	inc	BX
	mov	AL, DS:[BX]
	cmp	AL, LF
	je	.?WFL2
	cmp	AL, CR
	je	.?WFL2
	cmp	AL, ' '
	je	.?WFL2
	cmp	AL, TAB
	je	.?WFL2
	jmp	.?WFL1

; find non space
.?WFL2:	cmp	BX, DX		  ; FEnd
	jae	.?WFL2Ex
	inc	BX
	mov	AL, DS:[BX]
	cmp	AL, LF
	je	.?WFL2
	cmp	AL, ' '
	je	.?WFL2
	cmp	AL, CR
	je	.?WFL2
	cmp	AL, TAB
	je	.?WFL2

.?WFL2Ex:ret		; BX points to first character of next word

.?WForwardErr:
	mov	BX, 0		; Error indicator
	ret

.?WForward	ENDP

;---------------------------------------------------------------------------
Comment %
	Back (1)
	if space then
			Back (nonspace)
			Back (space)
			Forward (1)
		 else
			Back (space)
			Forward (1)
	END
%

.?WBackward	PROC	Near

	mov	BX, DS:BCB.FCursor
	cmp	BX, 100h
	jbe	.?WBackwardErr
	dec	BX
	mov	AL, DS:[BX]
	cmp	AL, CR
	je	.?WSP
	cmp	AL, ' '
	je	.?WSP
	cmp	AL, TAB
	je	.?WSP
	cmp	AL, LF
	je	.?WSP
.?WBMerge:
	cmp	BX, 100h
	jb	.?WBM1
	dec	BX
	mov	AL, DS:[BX]
	cmp	AL, CR
	je	.?WBM1
	cmp	AL, LF
	je	.?WBM1
	cmp	AL, ' '
	je	.?WBM1
	cmp	AL, TAB
	je	.?WBM1
	jmp	.?WBMerge

.?WBM1: inc	BX
	ret
.?WBackwardErr:
	mov	BX, 0
	ret

.?WSP:  cmp	BX, 100h
	jb	.?WBMerge
	dec	BX
	mov	AL, DS:[BX]
	cmp	AL, CR
	je	.?WSP
	cmp	AL, LF
	je	.?WSP
	cmp	AL, ' '
	je	.?WSP
	cmp	AL, TAB
	je	.?WSP
	jmp	.?WBMerge

.?WBackward	ENDP

;---------------------------------------------------------------------------

FillParagraph	PROC	Near
	mov	DS:BCB.Dirty, TRUE
	call	.FindLastParagraph		; fills PStart
	call	.FindEndParagraph		; fills PEnd
	call	.FillBetween			; fills the text
	ret
FillParagraph	ENDP

;---------------------------------------------------------------------------
.FindlastParagraph	PROC	Near
	mov	BX, DS:BCB.FCursor

Findit:	cmp	BX, 100h
	jbe	FoundlastParagraph

	cmp	Word Ptr DS:[BX-2], CRLF
	je	FoundLineStart
Findit2:
	dec	BX
	jmp	Findit

FoundLineStart:
	cmp	Word Ptr DS:[BX-4], CRLF
	jne	Findit2

FoundLastParagraph:
	mov	CS:PStart, BX
	ret
.FindLastParagraph	ENDP

;...........................................................................
.FindEndParagraph	PROC	Near
	mov	BX, CS:PStart

FindE:	cmp	BX, DS:BCB.FEnd
	jae	FoundEndParagraph

	cmp	Word Ptr DS:[BX], CRLF
	je	FoundLineStart2
FindE2:
	inc	BX
	jmp	FindE

FoundLineStart2:
	cmp	Word Ptr DS:[BX+2], CRLF
	jne	FindE2

FoundEndParagraph:
	mov	CS:PEnd, BX
	ret
.FindEndParagraph	ENDP

;---------------------------------------------------------------------------
.FillBetween	PROC	NEAR
	mov	BX, CS:PStart
	mov	DX, CS:PEnd		; where fill stops

F0:	cmp	BX, CS:Pend
	jae	EndFillBetween
	cmp	Word Ptr DS:[BX], CRLF
	jne	F1
	call	DeleteCRLF
F1:	call	GetColumn
	cmp	CX, CS:FillColumn
	jae	BreakLine
	inc	BX
	jmp	F0

EndFillBetween:
	ret

;--------
BreakLine:
RetreatToWord:
	mov	AL, DS:[BX]		; first go back until you find a
	cmp	AL, ' '			; Space
	je	AtSpace
	cmp	AL, TAB
	je	AtSpace
	cmp	AL, LF
	je	RTWErr
	dec	BX
	jmp	RetreatToWord

AtSpace:
					; now we are on one space in front of
					; a word
	push	DS:BCB.FCursor
	mov	DS:BCB.FCursor, BX	; allow the extra LF
	mov	CX, 1
	call	.MakeSpace
	pop	DS:BCB.FCursor
	mov	Word Ptr DS:[BX], CRLF
	cmp	BX, DS:BCB.FCursor
	ja	BLE
	inc	DS:BCB.FCursor
BLE:	inc	CS:Pend
	add	BX, 2
	jmp	F0

RTWErr:	mov	SI, Offset Confusedbreak
	mov	CX, 26
	jmp	.Error0
;...........................................................................
DeleteCRLF:
	cmp	BX, DS:BCB.FCursor
	jae	DCRLF1
	dec	DS:BCB.FCursor			; adjust the cursor
DCRLF1:	mov	SI, BX
	mov	CX, 1
	call	CDELK				; and delete 2 characters
	mov	Byte Ptr DS:[BX], ' '
	dec	CS:Pend				; adjust end of fill
	ret
;...........................................................................
.FillBetween	ENDP


;...........................................................................
GetColumn	PROC	NEAR
; on entry BX points to a character on a line. On Exit, CX holds the column
; on which BX is.

	push	DX
	mov	DX, BX			; remember where we started

GC1:	dec	BX			; first retreat to the CRLF
	cmp	Byte Ptr DS:[BX], LF
	je	GC2
	cmp	BX, 0FFh
	je	GC2
	jmp	GC1

;-------
GC2:	mov	CX, 1			; Column 1, Character 1 on line
	inc	BX


GC3:	cmp	BX, DX
	je	GCQ			; if we reach the cursor, we are fine

	cmp	Byte Ptr DS:[BX], TAB
	jne	GC4

	push	DX			; CX:= CX+(8- [(CX-1) mod 8])
	push	CX
	dec	CX			; CX:=CX-1
	and	CX, 111b		; CX:=CX mod 8
	mov	DX, 8			; DX:= 8-CX
	sub	DX, CX
	pop	CX
	add	CX, DX			; CX:=CX+DX
	pop	DX

	dec	CX
GC4:	inc	CX				; TAB = 8, Char = 1
	inc	BX
	jmp	GC3

GCQ:	pop	DX
	ret

GetColumn	ENDP

Program	ENDS
	END

