PUBLIC	NextScreen, SCrollUp, PreviousScreen, ScrollDown

EXTRN	NUMWinsSCR:WORD, GETCOLUMN:NEAR, .Error0:NEAR, FSCREEN:NEAR
EXTRN	WindowStart:Word, WindowEnd:Word
;---------------------------------------------------------------------------
	Page ,132
NAME	FSCRADVANCE

TITLE Global Commands to advance screen

Program SEGMENT PARA	PUBLIC  'code'
	ASSUME  CS:Program, DS:Program, ES:Program, SS:Program

INCLUDE FDEF.DEF

;---------------------------------------------------------------------------
ScreenEndMessage	db	'*** File End ***'
ScreenStartMessage	db	'*** File Start ***'
DesiredLines		dw	19
OldScrStart		dw	0
;---------------------------------------------------------------------------
ScrollUp	PROC	NEAR

	mov	BX, DS:BCB.FCursor
	cmp	BX, DS:BCB.FEnd
	jae	SUErr

	mov	BX, DS:BCB.ScrStart	; get the current screenstart

	call	Advancephysicalline

	mov	DS:BCB.ScrStart, BX
	cmp	BX, DS:BCB.FCursor
	jb	SUEnd
	mov	DS:BCB.FCursor, BX

SUEnd:	cmp	BX, DS:BCB.FEnd
	ja	SUErr
	ret

SUErr:	mov	SI, Offset ScreenEndMessage ; if we would pass the end, error
	mov	CX, 16
	jmp	.Error0

ScrollUp	ENDP
;---------------------------------------------------------------------------
%OUT	NEXTSCREEN ();

NextScreen	PROC	NEAR

	mov	BX, DS:BCB.ScrStart	; get the current screenstart
	xor	BP, BP			; zero lines advanced

	cmp	CS:NumWinsScr, 0	; find out how many lines forward
	je	Onewindow1
Twowindow:
	mov	CS:DesiredLines, HalfWindow-2
	jmp	CNLoop2
OneWindow1:
	mov	CS:Desiredlines, Fullwindow-2


CNLoop2:call	Advancephysicalline	; advance this many lines
	inc	BP
	cmp	BP, CS:DesiredLines
	ja	CNEnd
	cmp	BX, DS:BCB.FEnd
	jb	CNLoop2
	mov	SI, Offset ScreenEndMessage ; if we would pass the end, error
	mov	CX, 16
	jmp	.Error0

CNEnd:	mov	DS:BCB.ScrStart, BX	; found next screen start, so announce
	mov	DS:BCB.FCursor, BX
	ret

Nextscreen	ENDP
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
;...........................................................................
AdvancePhysicalLine	PROC	NEAR
	xor	DX, DX
APL0:	cmp	Byte Ptr DS:[BX], TAB
	jne	APL1
						; adjust for a TAB
	push	CX			; DX:= DX+(8- [(DX-1) mod 8])
	push	DX
	dec	DX
	and	DX, 111b
	mov	CX, 8
	sub	CX, DX
	pop	DX
	add	DX, CX
	pop	CX
	dec	DX			; will be incremented right again
	jmp	APL3

APL1:	cmp	Byte Ptr DS:[BX], ' '
	jae	APL2
	inc	DX				; adjust for a ^Character

APL2:	cmp	Word Ptr DS:[BX], CRLF
	jne	APL3
	add	BX, 2
	ret					; we have found it at CR

APL3:	inc	DX
	inc	BX
	cmp	DX, 79
	jb	APL0

	ret					; we have found it at wrap

AdvancePhysicalLine	ENDP
;---------------------------------------------------------------------------
ScrollDown	PROC	NEAR

	mov	BX, DS:BCB.ScrStart	; get the current screenstart
	cmp	BX, 100h
	jbe	SDErr

	mov	CS:OldScrStart, BX
	dec	BX
SDAgain:call	Retreatphysicalline
	cmp	Word Ptr DS:[BX+1], CRLF
	jne	SD1
	cmp	Byte Ptr DS:[BX], LF
	jne	SD1
	inc	BX			; bug we are on >LF< CR LF
SD1:	call	FindLineStart
	cmp	BX, CS:OldScrStart
	je	SDAgain

	mov	DS:BCB.ScrStart, BX

	mov     DX, CS:WindowEnd
	mov     DI, CS:WindowStart
	mov     SI, DS:BCB.ScrStart
	call	FScreen				; to find out the new end

	mov	BX, DS:BCB.ScrEnd
	cmp	BX, DS:BCB.FCursor
	ja	SDEnd
	dec	BX
	cmp	Byte Ptr DS:[BX], LF
	jne	SD2
	dec	BX
SD2:	mov	DS:BCB.FCursor, BX

SDEnd:	ret



SDErr:	mov	SI, Offset ScreenStartMessage	; if we would pass the
	mov	CX, 18				; start, error
	jmp	.Error0

ScrollDown	ENDP

;---------------------------------------------------------------------------
; This only approximates the right place by assessing a TAB to be always
; 6 characters

PreviousScreen	PROC	NEAR

	mov	BX, DS:BCB.ScrStart	; get the current screenstart
	xor	BP, BP			; zero lines retreated

	cmp	CS:NumWinsScr, 0	; find out how many lines forward
	je	P1Window
P2window:
	mov	CS:DesiredLines, HalfWindow-2
	jmp	PLoop2
P1Window:
	mov	CS:Desiredlines, Fullwindow-2


PLoop2:	call	Retreatphysicalline	; retreat this many lines
	inc	BP
	cmp	BP, CS:DesiredLines
	ja	PEnd
	cmp	BX, 100h
	jae	PLoop2

	mov	SI, Offset ScreenStartMessage	; if we would pass the start,
	mov	CX, 18				; error
	jmp	.Error0

PEnd:	call	FindLineStart
	mov	DS:BCB.ScrStart, BX	; found next screen start, so announce
	mov	DS:BCB.FCursor, BX
	ret

PreviousScreen	ENDP
;---------------------------------------------------------------------------
RetreatPhysicalLine	PROC	NEAR

	xor	DX, DX

RPL0:	cmp	Byte Ptr DS:[BX], TAB
	jne	RPL1
	add	DX, 5			; we assume a TAB to be about 6 chars
	jmp	RPL3

RPL1:	cmp	Byte Ptr DS:[BX], ' '
	jae	RPL2
	inc	DX				; adjust for a ^Character

RPL2:	cmp	Word Ptr DS:[BX], CRLF
	jne	RPL3
	dec	BX
	ret					; we have found it at CR

RPL3:	dec	BX
	inc	DX
	cmp	DX, 79
	jb	RPL0

	ret					; we have found it at wrap

RetreatPhysicalLine	ENDP
;---------------------------------------------------------------------------
; most of this code is copied from ccenter
;
FindLineStart	PROC	NEAR

	call	GetColumn		; BX holds cursor
	call	Findcolumn1		; returns in DX what the real
					; column should be

FLLoop:	call	GetColumn		; this will go back until
	cmp	CX, DX			; it hits the real start
	jbe	AtLineStart
	dec	BX
	jmp	FLLoop

AtLinestart:
	mov	DS:BCB.ScrStart, BX
	cmp	CX, DX
	jb	HitTabLine
	ret

HitTabLine:	inc	BX
	ret

FindColumn1	PROC	NEAR
; CX holds a column - I want to know the column number of the first character
; on this line.
	mov	DX, 1

FAgain:	add	DX, 79
	cmp	DX, CX
	jbe	FAgain
	sub	DX, 79		; return the real start
	ret
FindColumn1	ENDP


FindLineStart	ENDP

;***************************************************************************
;---------------------------------------------------------------------------
; IN:	CX	column we want to get to.
;	BX	points to any character on this line
; OUT:	BX	pointer to character which comes closest, but is not greater
;		than CX
;	DX	actual column of BX

MOVEtoCOLUMN	PROC	NEAR

	call	GoToLineStart		; finds the start of the line of {BX}

	mov	DX, 1

MTC0:	cmp	DX, CX			; we are ready when we either hit the
	jae	MTCFound1		; column we want, or when we

	mov	AX, DS:[BX]		; hit the CRLF
	cmp	AX, CRLF
	je	MTCFound2

	cmp	AH, TAB			; if we have hit a TAB, we need to ad
	jne	MTC1			; just more spaces

	push	CX			; DX:= DX+(8- [(DX-1) mod 8])
	push	DX
	dec	DX
	and	DX, 111b
	mov	CX, 8
	sub	CX, DX
	pop	DX
	add	DX, CX
	pop	CX
	dec	DX			; will be incremented right again
	jmp	MTC2

MTC1:	cmp	AL, ' '			; if we hit a control character
	jae	MTC2			; we need an extra forward

	inc	DX

MTC2:	inc	DX			; and forward, and try again
	jmp	MTC0

MTCFound1:				; we have reached a column greater
	cmp	DX, CX			; or equal what we want
	je	MTCFoundIdeal
	dec	BX			; a TAB or ^Character is hiding the
					; column we want
	push	CX			; so we pass the one before
	call	GetColumn		; whose column is
	mov	DX, CX			; and of course not pass back in CX
	pop	CX
MTCFoundIdeal:
	ret

MTCFound2:				; we have hit a CRLF before our col
	ret				; which will return correct DX / BX

MoveTOcolumn	ENDP
;---------------------------------------------------------------------------
; This will reset BX to the start of the line on which it is.
;
GoToLineStart	PROC	NEAR
	cmp	Word Ptr DS:[BX-2], CRLF
	je	GTLS1
	cmp	BX, 100h
	jbe	GTLS1
	dec	BX
	jmp	GoToLineStart
GTLS1:	ret
GoToLineStart	ENDP

PROGRAM	ENDS
	end

