;
;		    VLIST.ASM - V1.1
;		    by Charles Strom
;		   (revised 10/16/80)
;
; NOTE: REQUIRES 'MAC' AND SEQIO.LIB TO ASSEMBLE
;
; This program lists any size ASCII file by name, reading
; up to 16k of the file into memory at one time, in order
; to minimize disk activity during printout.  The scrolling
; speed may be set from the console.
;
; Allows listing of multiple files by using normal CP/M
; ambiguous file names (i.e., VLIST *.ASM).  Before each
; file is printed, the FILENAME.TYPE is displayed.
;
; Use CTL-S to pause, CTL-C to abort.  To vary scrolling
; speed, type CTL-H (fastest, default), CTL-J, CTL-K,
; CTL-L (slowest).  Other characters are ignored.
;
; This program is based on 'MLIST' by Keith Petersen, W8SDZ.
;
;PROGRAM HISTORY (in reverse order to minimize read time):
;
;10/16/80 Modified to optimize delay routine code (Keith
;	  Petersen, W8SDZ)
;
;10/15/80 First written by Charles Strom.
;
; THE FOLLOWING DELAYS MAY BE MODIFIED TO SUIT TASTE
; AND CLOCK SPEED.
;
D1	EQU	0300H	;SHORT DELAY
D2	EQU	0600H	;MEDIUM DELAY
D3	EQU	1200H	;LONG DELAY
;
	ORG	100H
;
	MACLIB	SEQIO	;DEFINE MACRO LIBRARY
;
START:	JMP	START2	;JMP AROUND IDENT
	DB	'VLIST.COM ver 1.1  10/16/80'
;
START2:	LXI	H,0
	DAD	SP	;GET OLD STACK
	SHLD	OLDSTK	;SAVE IT
	LXI	SP,STACK;SET NEW STACK
	LHLD	1	;POINT TO CP/M'S JMP TABLE
	LXI	D,3	;READY FOR ADD
	DAD	D	;POINT TO CONSOLE STATUS
	SHLD	CSTSC+1	;MODIFY CALL ADDRESS
	DAD	D	;POINT TO CONSOLE INPUT
	SHLD	CIC+1	;MODIFY CALL ADDRESS
	CALL	ILPRT	;PRINT:
	DB	'VLIST ver 1.1',CR,LF
	DB	'CTL-S pauses, CTL-C aborts',CR,LF
	DB	'Type ^H,^J,^K,^L to vary speed',0
	LDA	FCB+1
	CPI	' '	;SEE IF FILENAME THERE
	JNZ	MORE
	CALL	ILPRT	;PRINT:
	DB	'++NO FILE NAME SPECIFIED++',0
	JMP	EXIT
;
MORE:	CALL	MFNAME
	JNC	MOVNAM	;ANOTHER FILE FOUND, PRINT IT
	LDA	MFFLG1	;NOTHING FOUND, CHECK...
	ORA	A	;... FIRST TIME FLAG
	JZ	DONE	;AT LEAST ONE WAS FOUND
	CALL	ILPRT	;PRINT:
	DB	'++FILE NOT FOUND++',0
	JMP	EXIT
;
DONE	CALL	ILPRT	;PRINT:
	DB	'DONE',0
	JMP	EXIT
;
;MOVE FILENAME FROM FCB+1 TO FNAME
MOVNAM	LXI	H,FCB+1
	LXI	D,FNAME
	LXI	B,8
	CALL	MOVER
;MOVE FILETYPE FROM FCB+9 TO FNAME+9
	LXI	H,FCB+9
	LXI	D,FNAME+9
	LXI	B,3
	CALL	MOVER
	CALL	ILPRT	;PRINT:
	DB	CR,LF,'--> FILE: '
FNAME	DB	'XXXXXXXX.XXX'
	DB	CR,LF,0
;
; DEFINE SOURCE FILE:
;
;	INFILE	= INPUT FILE MODE
;	DISKIN = INTERNAL NAME
;	(NUL)	= DEFAULT DISK DRIVE
;	1	= FIRST DEFAULT NAME (TFCB)
;	(NUL)	=   "      "    TYPE
;	16384	= BUFFER SIZE
;	DSKBUF	= DISK BUFFER AREA
;
	FILE	INFILE,DISKIN,,1,,16384,DSKBUF
;
;CHECK HERE FOR .COM FILE, WHICH CAN'T BE PRINTED
;
	LXI	H,FCB+11 ;POINT TO LAST CHAR IN FCB
	MOV	A,M	;GET IT
	CPI	'M'	;WAS LAST CHAR AN 'M'?
	JNZ	OBJCHK	;IF NOT, CHK FOR '.OBJ' TYPE
	DCX	H
	MOV	A,M	;CHK NEXT
	ANI	7FH	;STRIP CP/M 2.x ATTR
	CPI	'O'	;AN 'O'?
	JNZ	READLP	;IF NOT IT'S OK TO PRINT
	DCX	H
	MOV	A,M	;WAS 'O', CHK NEXT CHAR
	ANI	7FH	;STRIP CP/M 2.x ATTR
	CPI	'C'	; 'C' AS IN '.COM'?
	JNZ	READLP	;IF NOT, IT'S OK TO PRINT
	CALL	ILPRT	;PRINT:
	DB	'++CAN''T LIST A .COM FILE++',0
	JMP	MORE	;MORE TO PRINT?
;
;HERE WE CHECK FOR AN ATTEMPT TO LIST AN OBJECT FILE
;
OBJCHK	CPI	'J'	;WAS LAST CHAR AN 'J' THEN?
	JNZ	READLP	;IF NOT, OK TO LIST
	DCX	H
	MOV	A,M	;MIGHT BE '.OBJ', CHK NEXT CHR
	ANI	7FH	;STRIP CP/M 2.x ATTR
	CPI	'B'	;IS IT A 'B'?
	JNZ	READLP	;IF NOT, LIST
	DCX	H
	MOV	A,M	;WAS, CHK FIRST CHAR
	ANI	7FH	;STRIP CP/M 2.x ATTR
	CPI	'O'	; 'O' AS IN '.OBJ'?
	JNZ	READLP	;IF NOT, PRINT THE FILE, IF SO
	CALL	ILPRT	;PRINT:
	DB	'++CAN''T LIST AN .OBJ FILE++',0
	JMP	MORE	;MORE TO PRINT?
;
;WRITE THE FILE TO CONSOLE
;
READLP:	GET	DISKIN
	CPI	EOF	;END OF FILE?
	JZ	MORE	;YES, MORE FILES TO PRINT?
	CALL	TYPE	;SEND CHAR TO CONSOLE
	CALL	CSTS	;KEY PRESSED?
	ORA	A
	CNZ	CKKB	;CHECK WHAT KEY
	JMP	READLP
;
CKKB	CALL	CI	;SEE WHAT CHAR
	CPI	'S'-40H	;CTL-S?
	CZ	CI	;YES, GET VALUE
	CPI	'C'-40H	;ABORT?
	JZ	EXITA	;YES, PRINT ABORT MSG, EXIT
	CPI	'H'-40H	;IS IT A CTL-H?
	JNZ	CK1
	MVI	A,0	;YES, SO PUT A 0
	JMP	CKR	;INTO DELVAL
;
CK1	CPI	'J'-40H	;IS IT A CTL-J?
	JNZ	CK2
	MVI	A,1	;YES, SO PUT A 1
	JMP	CKR	;INTO DELVAL
;
CK2	CPI	'K'-40H	;IS IT A CTL-K?
	JNZ	CK3
	MVI	A,2	;YES, SO PUT A 2
	JMP	CKR	;INTO DELVAL
;
CK3	CPI	'L'-40H	;IS IT A CTL-L?
	RNZ		;IGNORE IF NONE OF THE ABOVE
	MVI	A,3	;YES, SO PUT A 3 INTO DELVAL
;
CKR	STA	DELVAL	;SAVE DELAY VALUE
	RET
;
CSTS	PUSH	B
	PUSH	D
	PUSH	H
CSTSC	CALL	$-$	;CHANGED BY INIT
	POP	H
	POP	D
	POP	B
	RET		;FROM "CSTS"
;
CI	PUSH	B
	PUSH	D
	PUSH	H
CIC	CALL	$-$	;CHANGED BY INIT
	POP	H
	POP	D
	POP	B
	RET		;FROM "CI"
;
;
;INLINE PRINT ROUTINE
;	CALL	ILPRT
;	DB	'MSG',0
;
ILPRT	MVI	A,CR
	CALL	TYPE
	MVI	A,LF
	CALL	TYPE
	XTHL		;SAVE HL, GET MSG
;
ILPLP	MOV	A,M	;GET CHAR
	CALL	TYPE	;OUTPUT IT
	INX	H	;POINT TO NEXT
	MOV	A,M	;TEST
	ORA	A	;..FOR END
	JNZ	ILPLP
	MVI	A,CR
	CALL	TYPE
	MVI	A,LF
	CALL	TYPE
	XTHL		;RESTORE HL, RET ADDR
	RET		;RET PAST MSG
;
;TYPE CHAR IN A
;
TYPE:	PUSH	B
	PUSH	D
	PUSH	H
	PUSH	PSW
	LDA	DELVAL	;GET DELAY VALUE
	ORA	A	;IS IT A 0?
	JZ	TYPE2	;YES, SO JUMP AROUND DELAY
	LXI	D,D1	;SHORT DELAY VALUE
	CPI	1	;IS IT A 1?
	JZ	DELAY
	LXI	D,D2	;MEDIUM DELAY VALUE
	CPI	2	;IS IT A 2?
	JZ	DELAY
	LXI	D,D3	;LONG DELAY VALUE
;
DELAY	DCX	D
	ORA	D
	JP	DELAY
;
TYPE2	POP	PSW
	ANI	7FH	;STRIP PARITY BIT
	MOV	E,A	;CHARACTER TO E FOR CP/M
	MVI	C,WRCON
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;
EXITA	MVI	C,CSTAT	;GET CONSOLE STATUS
	CALL	BDOS
	ORA	A	;CHARACTER WAITING?
	MVI	C,RDCON
	CNZ	BDOS	;YES, CLEAR CHARACTER FROM CP/M
	CALL	ILPRT	;PRINT:
	DB	CR,LF,'++ABORTED++',0
;
EXIT	MVI	C,CSTAT
	CALL	BDOS
	ORA	A
	MVI	C,RDCON
	CNZ	BDOS
	LXI	D,80H	;SET DMA ADDRESS TO NORMAL
	MVI	C,STDMA	;FUNCTION NUMBER TO DO IT
	CALL	BDOS	;DO IT
	LHLD	OLDSTK	;GET OLD STACK
	SPHL		;RESTORE IT
	RET		;RETURN TO CP/M
;
;MULTI-FILE ACCESS SUBROUTINE.  ALLOWS PROCESSING
;OF MULTIPLE FILES (I.E. *.ASM) FROM DISK.  THIS
;ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH
;TIME IT IS CALLED. CARRY IS SET IF NO MORE NAMES
;CAN BE FOUND. THE ROUTINE IS COMMENTED IN PSEUDO
;CODE, EACH PSEUDO CODE STATEMENT IS IN <<...>>
;
MFNAME:	;<<INIT DMA ADDR, FCB>>
	MVI	C,STDMA
	LXI	D,80H
	CALL	BDOS
	XRA	A
	STA	FCBEXT
	STA	FCBRNO
;<<IF FIRST TIME>>
	LDA	MFFLG1
	ORA	A
	JZ	MFN01
;<<SAVE THE REQUESTED NAME>>
;SAVE ORIG REQ
	LXI	H,FCB
	LXI	D,MFREQ
	LXI	B,12
	CALL	MOVER
	LDA	FCB
	STA	MFCUR	;SAVE DISK IN CURR FCB
;<<SRCHF REQ NAME>>
	LXI	H,MFREQ
	LXI	D,FCB
	LXI	B,12
	CALL	MOVER
	MVI	C,SRCHF
	LXI	D,FCB
	CALL	BDOS
;<<ELSE>>
	JMP	MFN02
;
MFN01:	;<<SRCHF CURR NAME>>
	LXI	H,MFCUR
	LXI	D,FCB
	LXI	B,12
	CALL	MOVER
	MVI	C,SRCHF
	LXI	D,FCB
	CALL	BDOS
;<<SRCHN REQ NAME>>
	LXI	H,MFREQ
	LXI	D,FCB
	LXI	B,12
	CALL	MOVER
	MVI	C,SRCHN
	LXI	D,FCB
	CALL	BDOS
;<<ENDIF>>
MFN02:	;<<RETURN CARRY IF NOT FOUND>>
	INR	A
	STC
	RZ
;<<MOVE NAME FOUND TO CURR>>
	DCR	A
	ANI	3
	ADD	A
	ADD	A
	ADD	A
	ADD	A
	ADD	A
	ADI	81H
	MOV	L,A
	MVI	H,0
	PUSH	H	;SAVE NAME POINTER
	LXI	D,MFCUR+1
	LXI	B,11
	CALL	MOVER
;<<MOVE NAME FOUND TO FCB>>
	POP	H
	LXI	D,FCB+1
	LXI	B,11
	CALL	MOVER
;<<SETUP FCB>>
	XRA	A
	STA	FCBEXT
	STA	FCBRNO
	STA	MFFLG1	;TURN OFF 1ST TIME SW
;<<RETURN>>
	RET
;------------------------------------------------
;
;MOVE SUBROUTINE
;
MOVER	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MOVER
	RET
;
;MULTI-FILE ACCESS WORK AREA
;
MFFLG1	DB	1	;1ST TIME SW
MFREQ	DS	12	;REQ NAME
MFCUR	DS	12	;CURR NAME
DELVAL	DB	0	;DELAY VALUE 
;
	DS	60	;STACK AREA
STACK:	EQU	$
OLDSTK:	DS	2	;OLD STACK POINTER SAVED HERE
;
DSKBUF:	DS	16384	;16K BUFFER
;
;BDOS/CBIOS EQUATES
;
RDCON	EQU	1
WRCON	EQU	2
PRINT	EQU	9
CSTAT	EQU	11
OPEN	EQU	15
SRCHF	EQU	17
SRCHN	EQU	18
STDMA	EQU	26
BDOS	EQU	5
FCB	EQU	5CH 
FCBEXT	EQU	FCB+12
FCBRNO	EQU	FCB+32
;
	END

