;********************************************************
;*							*
;*	    FILE SCREEN PAGING UTILITY			*
;*							*
;********************************************************
;
;	By:	Bill Bolton
;		Software Tools,
;		P.O. Box 80,
;		Newport Beach,
;		NSW, 2106,
;		AUSTRALIA
;
;	Date:	July 1, 1980	Version 1.0
;
;		August 17, 1980	Version 1.1, modified to require a
;				different key to abort from that
;				pressed to advance to next page,
;				for those poor folks with bouncy
;				keyboards. Released concurrently
;				with version 1.0
;
;	Version: 1.1
;
TITLE	;YOU CAN'T ASSEMBLE THIS WITH MAC, USE ASM.COM
;
REVERSE	EQU	0		;NON ZERO FOR ADM-31 REVERSE VIDEO
PAGE	EQU	23		;LINES/PAGE
WIDTH	EQU	79		;CHARACTERS/LINE
WBOOT	EQU	0000H		;REBOOT ENTRY POINT
BDOS	EQU	0005H		;CPM ENTRY POINT
BUFFER	EQU	0080H		;TRANSIENT PROGRAM BUFFER 
TFCB	EQU	005CH		;TRANSIENT PROGRAM FCB
DIRECT	EQU	6		;DIRECT CONSOLE FUNCTION
STRING	EQU	9		;STRING PRINT FUNCTION
STATUS	EQU	11		;CONSOLE STATUS FUNCTION
VERSION	EQU	12		;VERSION NUMBER FUNCTION
OPEN	EQU	15		;OPEN FUNCTION CODE
READ	EQU	20		;READ FUNCTION CODE
CREAD	EQU	0FFH		;DIRECT CONSOLE INPUT
TAB	EQU	009H		;ASCII TAB
ALF	EQU	00AH		;ASCII LINE FEED
ACR	EQU	00DH		;ASCII CARRIAGE RETURN
ESC	EQU	01BH		;ASCII ESCAPE
SPACE	EQU	020H		;ASCII SPACE
DEVICE	EQU	2		;CP/M CONSOLE
;
;
	ORG	100H
;
START:
	LXI	SP,STAKTOP	;SET UP THE STACK
	MVI	C,VERSION	;CP/M VERSION FUNCTION
	CALL	BDOS
	MOV	A,L		;GET VERSION NUMBER
	CPI	20H		;>=VERSION 2.0?
	JC	ERROR3		;NO, EXIT	
	LXI	D,TFCB		;POINT TO FCB
	CALL	FOPEN		;OPEN FILE
	JC	ERROR1		;IF ERROR, EXIT
	CALL	RESET
LOOP:
	CALL	FETCH$BYTE	;GET NEXT BYTE FROM FILE
	JC	ERROR2		;EXIT IF ERROR
	CPI	1AH		;EOF?
	JZ	EXIT		;YES, EXIT
	CPI	ACR		;CR?
	JZ	CRET		;YES, UPDATE COLUMN COUNT
	CPI	ALF		;LF?
	JZ	LFEED		;YES, UPDATE LINE COUNT
	CPI	TAB		;TAB?
	JZ	TABMOV		;YES, DO IT
	CPI	SPACE		;ANOTHER CONTROL CHARACTER?
	JNC	DISPLAY		;NO, PRINT CHACTER
	JMP	LOOP		;YES, IGNORE IT
;
TABMOV:
	LXI	H,COL		;POINT TO COLUMN
TABLOOP:
	MVI	A,SPACE		;GET A SPACE
	CALL	DBYTE		;DISPLAY IT
	MOV	A,M		;GET CURRENT COLUMN
	ANI	07H		;MOD 8, AT TAB STOP?
	JNZ	TABLOOP		;NO, ANOTHER SPACE
	JMP	LOOP
;
DISPLAY:
	CALL	DBYTE		;DISPLAY THE CHARACTER
	JMP	LOOP
;
CRET:
	XRA	A
	STA	COL		;RESET COLUMN COUNT
	MVI	A,ACR		;GET A CARRIAGE RETURN
	JMP	DISPLAY
;
LFEED:
	LDA	LINE		;GET LINE COUNT
	CPI	PAGE		;SCREEN FULL?
	JZ	NEXTPAGE	;YES, WAIT FOR KEYPRESS
	INR	A		;NO, BUMP LINE COUNT
	STA	LINE		;SAVE NEW LINE COUNT
	MVI	A,ALF		;GET A LINE FEED
	JMP	DISPLAY
;
NEXTPAGE:
	CALL	KEYLOOP		;WAIT FOR KEYPRESS
	MVI	A,ALF		;GET A LINE FEED
	JMP	DISPLAY
;
KEYLOOP:
	CALL	KEY		;CHECK CONSOLE
	CPI	0		;KEY PRESSED ?
	JZ	KEYLOOP		;NO, WAIT FOR KEYPRESS
	STA	LAST$KEY	;SAVE FOR LATER
	CALL	RESET		;RESET COUNTERS
	RET
;
KEY:				
	PUSH	H		;SAVE
	PUSH	D		;  THE
	PUSH	B		;    ENVIRONMENT
	MVI	C,DIRECT	;DIRECT CONSOLE FUNCTION6
	MVI	E,CREAD		;CONSOLE INPUT
	CALL	BDOS
	POP	B		;RESTORE
	POP	D		;  THE
	POP	H		;    ENVIRONMENT
	RET
;
RESET:
	XRA	A
	STA	LINE		;RESET LINE COUNT
	STA	COL		;RESET COLUMN COUNT
	RET
;
DBYTE:
	PUSH	H		;SAVE THE
	PUSH	B		;  ENVIRONMENT
	PUSH	PSW		;SAVE THE CHARACTER
	MOV	E,A		;COPY THE CHARACTER
	MVI	C,DEVICE	;GET FUNCTION
	CALL	BDOS
	POP	PSW		;RESTORE THE CHARACTER
	CPI	SPACE		;IS A CR OR LF?
	JC	CONT		;YES, DONT BUMP COLUMN COUNT
	LXI	H,COL		;GET COLUMN COUNT
	INR	M		;BUMP IT
	MOV	A,M		;GET NEW COLUMN COUNT
	CPI	WIDTH		;AT THE END OF A LINE?
	JNZ	CONT		;NO
	MVI	A,ACR		;GET A CARRIAGE RETURN
	CALL	DBYTE		;SEND IT
	LDA	LINE		;GET LINE NUMBER
	CPI	PAGE		;AT END OF PAGE
	JNZ	CONT2		;NO, DO LINE FEED
	CALL	KEYLOOP		;WAIT FOR KEYPRESS
CONT2:
	MVI	A,ALF		;GET A LINE FEED
	CALL	DBYTE
	LDA	LINE		;GET THE LINE COUNT
	INR	A		;BUMP IT
	STA	LINE		;SAVE THE LINE COUNT
CONT:
	CALL	KEY
	CPI	0		;KEY PRESSED?
	CNZ	CHECK$EXIT	;YES, CHECK IF EXIT NEEDED
	POP	B		;RESTORE THE
	POP	H		;  ENVIRONMENT
	RET
;
CHECK$EXIT:
	LXI	H,LAST$KEY	;POINT TO LAST KEY PRESSED
	CMP	M		;SAME?
	RZ			;YES, DONT QUIT
DONE:
	JMP	WBOOT		;QUIT
;
EXIT:
	LXI	D,MESSG4	;POINT TO EOF MESSAGE
	JMP	MESSAGE
;
ERROR3:	LXI	D,MESSG3	;POINT TO VERSION MESSAGE 
	JMP	MESSAGE
;
ERROR2:
	LXI	D,MESSG2	;POINT TO READ MESSAGE
	JMP	MESSAGE
;
ERROR1:
	LXI	D,MESSG1	;POINT TO OPEN MESSAGE
MESSAGE:
	MVI	C,STRING	;DISPLAY THE MESSAGE
	CALL	BDOS
	JMP	WBOOT
;
	DB	'FILE PAGE UTILITY, VERSION 1.1 '
	DB	'(C) Bill Bolton, Software Tools, August 1980'
;
;****************************************************************
;*								*
;*		ROUTINE TO OPEN A DISK FILE			*
;*								*
;****************************************************************
;
FOPEN:				;DE POINTS TO A FCB
	MVI	C,OPEN		;FILE OPEN FUNCTION
	CALL	BDOS
	CPI	0FFH		;OPEN FILE  ERROR?
	JZ	OPENERR		;YES, EXIT
	XRA	A		;CLEAR CARRY
	RET
OPENERR:
	STC			;SET CARRY
	RET
;
;
;****************************************************************
;*								*
;*		 ROUTINE TO READ A BYTE				*
;*								*
;****************************************************************
;
FETCH$BYTE:
	LXI	H,BUFFER+128
	XCHG			;BUFFER END ADDRESS IN DE
	LHLD	POINTER		;CURRENT POINTER IN HL
	MOV	A,H		;END OF BUFFER?
	CMP	D
	JNZ	NEXT$CHAR	;NO, GET ANOTHER CHARACTER
	MOV	A,L
	CMP	E
	JZ	NEXT$BLOCK	;YES, READ ANOTHER BLOCK
NEXT$CHAR:
	MOV	A,M		;GET CHARACTER
	INX	H		;BUMP POINTER
	SHLD	POINTER		;SAVE POINTER
	ORA	A		;RESET CARRY
	RET
;
NEXT$BLOCK:
	MVI	C,READ		;READ FUNCTION
	LXI	D,TFCB		;FCB ADDRESS
	CALL	BDOS
	CPI	0		;ERROR?
	JNZ	INERROR		;YES, EXIT
	LXI	H,BUFFER	;RESET BUFFER POINTER
	SHLD	POINTER
	JMP	NEXT$CHAR	;CONTINUE
;
INERROR:
	STC			;SET CARRY
	RET
;
;
COL:	DB	0		;COLUMN COUNTER
LINE:	DB	0		;LINE COUNTER
LAST$KEY:
	DB	0		;LAST KEY HIT
POINTER:DW	BUFFER+128	;INPUT POINTER
;
MESSG1:
	DB	'**** '
	if	REVERSE
	DB	ESC,'G4'
	endif
	DB	'File Open Error'
	if	REVERSE
	DB	ESC,'G0'
	endif
	DB	' ****'
	DB	ACR,ALF,'$'
;
MESSG2:
	DB	'**** '
	if	REVERSE
	DB	ESC,'G4'
	endif
	DB	'File Read Error'
	if	REVERSE
	DB	ESC,'G0'
	endif
	DB	' ****'
	DB	ACR,ALF,'$'
;
MESSG3:
	DB	TAB,'Sorry, you need CP/M Version'
	DB	' 2.0 or later to run PAGE !'
	DB	'$'
;
MESSG4:
	if	REVERSE
	DB	ESC,'G4'
	endif
	DB	' End of Input File Reached '
	if	REVERSE
	DB	ESC,'G0'
	endif
	DB	'$'
;
STACK:
	DS	40
STAKTOP	EQU	$
;
	END	START
