	  PAGE	  60,132
	  .MODEL  small
	  .DATA
	  EXTRN	  statatr:BYTE,scrnatr:BYTE,sbuffer:WORD,pbuffer:WORD
	  EXTRN	  fsize:WORD,cell:WORD,statline:BYTE,linenum:WORD
	  EXTRN	  rows:WORD,vidadr:WORD,cga:BYTE

	  .CODE
	  PUBLIC  Pager,isEGA

; Procedure Pager
; Purpose   Displays status and	text lines
; Input	    Stack variable: lines to scroll (negative up, positive down)
;	    Global variables: "sbuffer", "pbuffer", "linenum"
; Output    To screen

Pager	  PROC
	  push	  bp
	  mov	  bp,sp

	  mov	  es,sbuffer		; Initialize buffer position
	  mov	  di,pbuffer

	  mov	  cx,[bp+4]		; Get count argument
	  mov	  ax,10			; Search for linefeed

	  or	  cx,cx			; Argument 0?
	  jg	  forward		; If above, forward
	  jl	  backward		; If below, backward
	  jmp	  SHORT	show		; If equal, done

backward: call	  GoBack		; Adjust backward
	  jmp	  SHORT	show		; Show screen
forward:  call	  GoForwd		; Adjust forward

; Write	line number to status line

show:	  cld				; Go forward
	  push	  di
	  push	  es
	  push	  ds			; Load DS to ES
	  pop	  es

; BinToStr (linenum,OFFSET statline[7])

	  push	  linenum		; Arg 1
	  mov	  ax,OFFSET statline[7]
	  push	  ax			; Arg 2
	  call	  BinToStr		; Convert to string

; Fill in status line

	  mov	  cx,7			; Seven	spaces to fill
	  sub	  cx,ax			; Subtract those already done
	  mov	  al," "		; Fill with space
	  rep	  stosb
	  pop	  es

	  mov	  bl,statatr		; Load status attribute
	  mov	  BYTE PTR cell[1],bl

; CellWrt (DS,OFFSET statline,0,cell)

	  push	  ds			; Arg 1
	  mov	  ax,OFFSET statline	; Arg 2
	  push	  ax
	  sub	  ax,ax			; Arg 3
	  push	  ax
	  push	  cell			; Arg 4
	  call	  CellWrt		; Write	status line

	  pop	  di
	  mov	  bl,scrnatr		; Load screen attribute
	  mov	  BYTE PTR cell[1],bl
	  mov	  si,di			; Update position
	  mov	  cx,rows		; Lines	per screen

show1:	  mov	  bx,rows		; Lines	of text
	  inc	  bx			; Adjust for 0
	  sub	  bx,cx			; Calculate current row
	  push	  cx			; Save line number

; CellWrt (sbuffer,position,line,cell)

	  push	  sbuffer		; Arg 1
	  push	  si			; Arg 2
	  push	  bx			; Arg 3
	  push	  cell			; Arg 4
	  call	  cellwrt		; Write	line

	  push	  ss			; Restore DS from SS
	  pop	  ds

	  pop	  cx			; Restore line number
	  mov	  si,ax			; Get returned position

	  cmp	  ax,fsize		; Beyond end of	file?
	  jae	  fillout		; Yes? Fill screen with	spaces
	  loop	  show1			;    else next line
	  jmp	  SHORT	pagedone	; Get out if done

; Fill the rest	with spaces

fillout:  dec	  cx			; Adjust
	  jcxz	  pagedone
	  mov	  al,80			; Columns times	remaining lines
	  mul	  cl

; CellFil (sbuffer,count,cell)

	  push	  sbuffer		; Arg 1
	  push	  ax			; Arg 2
	  push	  cell			; Arg 3
	  call	  CellFil		; Fill screen with spaces

	  push	  ss			; Restore DS from SS
	  pop	  ds

pagedone: pop	  bp
	  ret	  2
Pager	  ENDP

; Procedure CellWrt (segment,offset,line,cell)
; Purpose   Writes a line to screen buffer
; Input	    Stack variables: 1 - segment of line
;			     2 - offset
;			     3 - line number
;			     4 - attribute
; Output    Line to screen buffer

CellWrt	  PROC
	  push	  bp
	  mov	  bp,sp
	  sub	  dx,dx			; Clear	as flag	for scan
	  cmp	  cga,1			; CGA?
	  jne	  noscan
	  mov	  dx,03DAh		; Load port #

noscan:	  mov	  es,vidadr		; Load screen buffer segment
	  mov	  ds,[bp+10]		; Buffer segment
	  mov	  si,[bp+8]		; Buffer position
	  mov	  cx,80			; Cells	per row
	  mov	  ax,[bp+6]		; Starting row
	  mov	  bx,80*2		; Bytes	per row
	  mul	  bl			; Figure columns per row
	  mov	  di,ax			; Load as destination
	  mov	  bx,di			; Save start for tab calculation
	  mov	  ax,[bp+4]		; Attribute
movechar: lodsb				; Get character
	  cmp	  al,13			; CR?
	  je	  fillspc
	  cmp	  al,9			; Tab?
	  jne	  notab
	  call	  filltab		; Yes? fill with spaces
	  jcxz	  nextline		; If beyond limit done
	  jmp	  SHORT	movechar

notab:	  or	  dx,dx			; CGA?
	  je	  notab2
	  call	  Retrace		; Yes? Write during retrace
	  loop	  movechar
	  jmp	  SHORT	nextline

notab2:	  stosw				; Write
	  loop	  movechar
	  jmp	  SHORT	nextline	; Done

fillspc:  mov	  al," "		; Fill with space

	  or	  dx,dx			; CGA?
	  je	  space2
space1:	  call	  Retrace		; Yes? Write during retrace
	  loop	  space1
	  inc	  si			; Adjust
	  jmp	  SHORT	exit		; Done

space2:	  rep	  stosw			; Write
	  inc	  si			; Adjust for LF
	  jmp	  SHORT	exit		; Done

nextline: mov	  ah,10			; Search for next line feed
chklf:	  lodsb				; Load and compare
	  cmp	  al,ah
	  loopne  chklf

exit:	  mov	  ax,si			; Return position
	  pop	  bp
	  ret	  8
CellWrt	  ENDP

; Procedure CellFil (segment,count,cell)
; Purpose   Fills screen with character
; Input	    Stack variables: 1 - segment of text (offset 0)
;			     2 - number	of characters
;			     3 - attribute and character
; Output    Characters to screen buffer

CellFil	  PROC
	  push	  bp
	  mov	  bp,sp
	  sub	  dx,dx			; Clear	as flag	for scan
	  cmp	  cga,1			; CGA?
	  jne	  noscan2
	  mov	  dx,03DAh		; Load port #

noscan2:  mov	  es,vidadr		; Load screen buffer segment
	  mov	  ds,[bp+8]		; Buffer segment (position 0)
	  mov	  cx,[bp+6]		; Characters to	fill
	  mov	  ax,[bp+4]		; Attribute
	  or	  dx,dx			; CGA?
	  je	  fillem2
fillem1:  call	  Retrace		; Yes? Write during retrace
	  loop	  fillem1
	  jmp	  SHORT	filled		; Done
fillem2:  rep	  stosw			; Write

filled:	  pop	  bp
	  ret	  6
CellFil	  ENDP

; Procedure FillTab
; Purpose   Writes spaces for tab to screen
; Input	    BX points to start of line,	DI points to current position
; Output    Spaces to screen buffer

FillTab	  PROC
	  push	  bx
	  push	  cx

	  sub	  bx,di			; Get current position in line
	  neg	  bx
	  shr	  bx,1			; Divide by 2 bytes per	character

	  mov	  cx,8			; Default count	8
	  and	  bx,7			; Get modulus
	  sub	  cx,bx			; Subtract
	  mov	  bx,cx			; Save modulus

	  mov	  al," "		; Spaces
	  or	  dx,dx			; CGA?
	  je	  tabem2

tabem1:	  call	  Retrace		; Yes? Write during retrace
	  loop	  tabem1
	  jmp	  SHORT	tabbed
tabem2:	  rep	  stosw			; Write

tabbed:	  pop	  cx
	  sub	  cx,bx			; Adjust count
	  jns	  nomore		; Make negative	count 0
	  sub	  cx,cx
nomore:	  pop	  bx
	  ret
FillTab	  ENDP

; Procedure GoBack
; Purpose   Searches backward through buffer
; Input	    CX has number of lines; ES:DI has buffer position
; Output    Updates "linenum" and "pbuffer"

GoBack	  PROC
	  std				; Go backward
	  neg	  cx			; Make count positive
	  mov	  dx,cx			; Save a copy
	  inc	  cx			; One extra to go up one
	  or	  di,di			; Start	of file?
	  je	  exback		; If so, ignore
findb:	  push	  cx			;   else save count
	  mov	  cx,0FFh		; Load maximum character count
	  cmp	  cx,di			; Near start of	buffer?
	  jl	  notnear		; No? Continue
	  mov	  cx,di			;   else search	only to	start
notnear:  repne	  scasb			; Find last previous LF
	  jcxz	  atstart		; If not found,	must be	at start
	  pop	  cx
	  loop	  findb
	  cmp	  linenum,0FFFFh	; End of file flag?
	  jne	  notend		; No? Continue
	  add	  di,2			; Adjust for cr/lf
	  mov	  pbuffer,di		; Save position
	  call	  EndCount		; Count	back to	get line number
	  ret

notend:	  sub	  linenum,dx		; Calculate line number
	  jg	  positive
	  mov	  linenum,1		; Set to 1 if negative
positive: add	  di,2			; Adjust for cr/lf
	  mov	  pbuffer,di		; Save position
	  ret

atstart:  pop	  cx
	  sub	  di,di			; Load start of	file
	  mov	  linenum,1		; Line 1
	  mov	  pbuffer,di		; Save position
exback:	  ret
GoBack	  ENDP

; Procedure GoForwd
; Purpose   Searches forward through a buffer
; Input	    CX has number of lines; ES:DI has buffer position
; Output    Updates "linenum" and "pbuffer"

GoForwd	  PROC
	  cld				; Go forward
	  mov	  dx,cx			; Copy count
findf:	  push	  cx			; Save count
	  mov	  cx,0FFh		; Load maximum character count
	  repne	  scasb			; Find next LF
	  jcxz	  atend			; If not found,	must be	at end
	  cmp	  di,fsize		; Beyond end?
	  jae	  atend
	  pop	  cx
	  loop	  findf
	  add	  linenum,dx		; Calulate line	number
	  mov	  pbuffer,di		; Save position
	  ret

atend:	  pop	  cx
	  mov	  di,pbuffer		; Restore position
	  ret
GoForwd	  ENDP

; Procedure EndCount
; Purpose   Counts backward to count lines in file
; Input	    ES:DI has buffer position
; Output    Modifies "linenum"

EndCount  PROC
	  push	  di

	  mov	  al,13			; Search for CR
	  mov	  linenum,0		; Initialize

findstrt: inc	  linenum		; Adjust count
	  mov	  cx,0FFh		; Load maximum character count
	  cmp	  cx,di			; Near start of	buffer?
	  jl	  notnear2		; No? Continue
	  mov	  cx,di			;   else search	only to	start
notnear2: repne	  scasb			; Find last previous cr
	  jcxz	  found			; If not found,	must be	at start
	  jmp	  SHORT	findstrt

found:	  pop	  di
	  ret
EndCount  ENDP

; Procedure isEGA
; Purpose   Determines if an EGA is active
; Input	    None
; Output    0 if no; lines per screen if yes

isEGA	  PROC
	  push	  bp
	  push	  es
	  mov	  ah,12h		; Call EGA status function
	  mov	  bl,10h
	  sub	  cx,cx			; Clear	status bits
	  int	  10h
	  sub	  ax,ax			; Segment 0 and	assume no EGA
	  jcxz	  noega			; If status still clear, no EGA

	  mov	  es,ax			; ES=0
	  test	  BYTE PTR es:[487h],1000b ; Test active bit
	  jnz	  noega			; If set, not active
	  mov	  ax,1130h		; Get EGA information
	  int	  10h
	  mov	  al,dl			; Return lines per screen
	  cbw

noega:	  pop	  es
	  pop	  bp
	  ret
isEGA	  ENDP

; Procedure BinToStr (number,address)
; Purpose   Converts integer to	string
; Input	    Stack arguments: 1 - Number	to convert; 2 -	Near address for write
; Output    AX has characters written

BinToStr  PROC
	  push	  bp
	  mov	  bp,sp
	  mov	  ax,[bp+6]		; Arg 1
	  mov	  di,[bp+4]		; Arg 2

	  sub	  cx,cx			; Clear	counter
	  mov	  bx,10			; Divide by 10

; Convert and save on stack backwards

getdigit: sub	  dx,dx			; Clear	top
	  div	  bx			; Divide to get	last digit as remainder
	  add	  dl,"0"		; Convert to ASCII
	  push	  dx			; Save on stack
	  or	  ax,ax			; Quotient 0?
	  loopnz  getdigit		; No? Get another

; Take off the stack and store forward

	  neg	  cx			; Negate and save count
	  mov	  dx,cx
putdigit: pop	  ax			; Get character
	  stosb				; Store	it
	  loop	  putdigit
	  mov	  ax,dx			; Return digit count

	  pop	  bp
	  ret	  4
BinToStr  ENDP

; Procedure Retrace
; Purpose   Writes cell	during horizontal retrace (CGA)
; Input	    ES:DI has screen buffer position, AX has cell
; Output    Character to screen	buffer

Retrace	  PROC
	  push	  bx
	  mov	  bx,ax			; Save character
lscan2:	  in	  al,dx			; Look in the port
	  shr	  al,1			;   until it goes low
	  jc	  lscan2
	  cli
hscan2:	  in	  al,dx			; Look in the port
	  shr	  al,1			;   until it goes high
	  jnc	  hscan2
	  mov	  ax,bx			; Restore and write it
	  stosw
	  sti
	  pop	  bx
	  ret
Retrace	  ENDP

	  END
