;FIND.ASM 
;
;	06/23/79
;ORIGINALLY WRITTEN BY WARD CHRISTENSEN
;	01/27/80
;PUT IN CTL-C BREAK
;	02/27/80
;TRANSLATE FILE READ CHARS TO UPPER CASE
;SO CASE DOESN'T MATTER IN FILE CONTENTS.
;ALSO PUT IN "JUST IN CASE" TEST FOR LINE
;LONGER THAN 128.
;	03/18/80
;MAKE "_" MATCH A TAB; MAKE "|" AN "OR"
;AS IN: FIND B:*.ASM _IN_|_OUT_
;	----------------
;USED TO DO A CHARACTER STRING SEARCH
;OF ONE OR MORE FILES.  ANY ASCII STRING
;MAY BE SEARCHED FOR.  CASE DOESN'T MATTER.
;
;COMMAND FORMAT:
;
;	FIND FILENAME STRING
;
;FILENAME MAY BE AMBIGUOUS, 
;	E.G. *.ASM OR CBBS*.ASM
;
;"_" IN STRING WILL MATCH A TAB.
;
CR	EQU	0DH
LF	EQU	0AH
EOF	EQU	1AH
TAB	EQU	9
;
MF	SET	0	;SHOW MOVE NOT REQUESTED
CF	SET	0	;SHOW COMP NOT REQUESTED
;
;(FROM EQU8.LIB...)
;DEFINE SOME MACROS TO MAKE THINGS EASIER
;
;DEFINE DATA MOVE MACRO: MOVE from,to,length
;	from may be addr, or quoted string
;
MOVE	MACRO	?F,?T,?L
	IF	NOT NUL ?F
	IRPC	?C,?F
?Q	SET	'&?C&?C' ;;TEST FOR QUOTE
	EXITM
	ENDM
	IF	?Q EQ ''''
	LOCAL	?B,?Z
	CALL	?Z
?B	DB	?F
?Z	POP	H	;GET FROM
	LXI	B,?Z-?B	;GET LEN
	ELSE
	LXI	H,?F
	ENDIF
	ENDIF
	IF	NOT NUL ?T
	LXI	D,?T
	ENDIF
	IF	NOT NUL ?L
	LXI	B,?L
	ENDIF
	CALL	MOVER
MF	SET	-1	;;SHOW EXPANSION
	ENDM
;COMPARE MACRO
COMP	MACRO	?F,?T,?L
	IF	NOT NUL ?F
	IRPC	?C,?F
?Q	SET	'&?C&?C' ;;TEST FOR QUOTE
	EXITM
	ENDM
	IF	?Q EQ ''''
	LOCAL	?B,?Z
	CALL	?Z
?B	DB	?F
?Z	POP	H	;GET FROM
	LXI	B,?Z-?B	;GET LEN
	ELSE
	LXI	H,?F
	ENDIF
	ENDIF
	IF	NOT NUL ?T
	LXI	D,?T
	ENDIF
	IF	NOT NUL ?L
	LXI	B,?L
	ENDIF
	IF	NOT NUL ?I
	LOCAL	?B,?Z
	CALL	?Z
?B	DB	?I
?Z	POP	D	;GET TO
	LXI	B,?Z-?B
	ENDIF
	CALL	COMPR
CF	SET	-1	;;SHOW EXPANSION
	ENDM
;
;DEFINE CP/M MACRO - CPM FNC,PARM
;
CPM	MACRO	?F,?P
	PUSH	B
	PUSH	D
	PUSH	H
	IF	NOT NUL ?F
	MVI	C,?F
	ENDIF
	IF	NOT NUL ?P
	LXI	D,?P
	ENDIF
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	ENDM
;
	ORG	100H
	CALL	START
	DB	'FIND.COM '
	DB	'03/18/80'
	DB	0DH,0AH,'$'
START	POP	D	;GET ID
	MVI	C,PRINT
	CALL	BDOS	;PRINT ID
;
;INIT LOCAL STACK
;
	LXI	H,0
	DAD	SP
	SHLD	STACK
	LXI	SP,STACK
;
;START OF PROGRAM EXECUTION
;
	LDA	FCB+1
	CPI	' '
	JNZ	GETSTR
	CALL	ERXIT
	DB	'++NO FILE NAME++$'
;
;FIND START OF STRING IN TBUFF
;
GETSTR	LXI	D,80H	;DE=TBUFF
	LDAX	D	;LENGTH
	MOV	C,A	;SAVE LENGTH
	MVI	B,0	;SETUP BC FOR MOVE
	INX	D	;PAST LENGTH
	MOV	L,A	;L=LENGTH
	MVI	H,0	;HL=LENGTH
	DAD	D	;HL=LAST CHAR
	MVI	M,0	;STORE END DELIM
;
;SCAN FOR START OF STRING
;
	XCHG		;START TO HL
SCAN	INX	H	;TO NEXT CHAR
	MOV	A,M	;LOOK FOR ' '
	ORA	A	;END?
	JZ	BADSTR	;..YES, BAD
	CPI	' '
	JNZ	SCAN	;NOT AT ' '
	INX	H	;TO STRING
;
	MOVE	,STRING, ;HL = FROM, BC=LENGTH
NEXTFL	CALL	MFNAME	;GET NEXT
	JC	EXIT
	CPM	OPEN,FCB
	INR	A
	JZ	EXIT
	MOVE	'   0',LINENO
	MOVE	FCB+1,FNAME,8
	MOVE	FCB+9,FNAME+9,3
	CALL	ILPRT
	DB	'----> FILE '
FNAME	DB	'XXXXXXXX.XXX'
	DB	CR,LF,0
	LXI	H,0
	SHLD	EFCBCT	;ZERO COUNT
;
;BUMP ASCII LINE #
;
NEXTLN	LXI	H,LINENO+3
NEXTADD	MOV	A,M	;GET DIGIT
	ORI	'0'	;MAKE ASCII
	INR	A
	MOV	M,A
	CPI	'9'+1	;CARRY?
	JNZ	NEXTNC
	MVI	M,'0'
	DCX	H
	JMP	NEXTADD
;
NEXTNC	LXI	H,LINE
	MVI	B,0FFH	;SO LONG LINE WON'T BLOW
NEXTLC	INR	B
	JM	LONG	;TOO LONG A LINE
	PUSH	B
	PUSH	H
	LXI	H,EFCB
	CALL	RDBYTE
	POP	H
	POP	B
	MOV	M,A
	INX	H
	CPI	EOF
	JZ	NEXTFL	;NEXT FILE
	CPI	LF
	JNZ	NEXTLC
	JMP	EOL
;
;GOT A LONG LINE - STICK CRLF IN MIDDLE
;
LONG	MVI	M,0DH
	INX	H
	MVI	M,0AH
EOL	CPM	CONST	;TEST FOR ABORT
	ORA	A
	JNZ	CHREXIT	;ABORT REQUESTED
;
;READ IN A LINE, NOW SCAN FOR THE STRING
;
	LXI	H,STRING
ORLINE	SHLD	STRPTR
	LXI	H,LINE
NEXTST	XCHG
	LHLD	STRPTR
	XCHG
	PUSH	H
NEXTC	LDAX	D
	CPI	'_'
	JNZ	NOTAB
	MVI	A,TAB
NOTAB	INX	D
	ORA	A	;END OF STRING?
	JZ	MATCHED
	CPI	'|'
	JZ	MATCHED	;FIRST PART
	MOV	C,M	;FOR LOWER CASE TEST
	CMP	M
	INX	H
	JZ	NEXTC
	MOV	B,A	;SAVE CHAR
	MOV	A,C	;GET CHAR
	CPI	61H	;LOWER?
	JC	NOTEQ	;NO, SO NO MATCH
	CPI	7BH
	JNC	NOTEQ
	ANI	5FH	;MAKE UPPER CASE
	CMP	B
	JZ	NEXTC	;MATCHED
NOTEQ	POP	H	;RESTORE ADDR
	INX	H
	MOV	A,M
	CPI	CR
	JNZ	NEXTST
;
;IF AN "OR" (|) IS IN THE LINE, SCAN FOR IT
;
	LHLD	STRPTR
FINDOR	MOV	A,M
	INX	H
	CPI	'|'
	JZ	ORLINE
	ORA	A
	JNZ	FINDOR
	JMP	NEXTLN
;
;GOT MATCH, PRINT IT
;
MATCHED	POP	H	;KILL STACKED ADDR
	CALL	ILPRT
LINENO	DB	'    ',TAB,0
;
	LXI	H,LINE
MATCHLP	MOV	A,M
	MOV	E,A
	CPM	WRCON
	MOV	A,M
	INX	H
	CPI	LF
	JNZ	MATCHLP
	JMP	NEXTLN
;
;INLINE PRINT - CALL ILPRT FOLLOWED BY MSG,
;WHICH ENDS IN A: 0
;
ILPRT	XTHL		;GET MSG ADDR, SAVE HL
ILPLP	MOV	E,M
	CPM	WRCON
	INX	H
	MOV	A,M
	ORA	A	;END?
	JNZ	ILPLP
	XTHL
	RET
;
BADSTR	CALL	ERXIT
	DB	'++BAD STRING++$'
;
;FOLLOWING FROM 'EQU8.LIB'---->
;
;MOVE, COMPARE SUBROUTINES
;
	IF	MF	;MACRO EXPANSION FLAG SET?
;
MOVER	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MOVER
	RET
	ENDIF
;
	IF	CF	;MACRO EXPANSION FLAG SET?
COMPR	LDAX	D
	CMP	M
	RNZ
	INX	D
	INX	H
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	COMPR
	RET
	ENDIF
;
;	FROM EQU8.LIB: AS OF 05/06/79
;
;RDBYTE, HL POINTS TO EXTENDED FCB:
;
;	2 BYTE BUFFER ADDR
;	2 BYTE "BYTES LEFT" (INIT TO 0)
;	1 BYTE BUFFER SIZE (IN PAGES)
;	2 BYTE FCB ADDRESS
;
RDBYTE	MOV	E,M
	INX	H
	MOV	D,M	;GET BUFFER ADDR
	INX	H
	MOV	C,M
	INX	H
	MOV	B,M	;BC = BYTES LEFT
	MOV	A,B	;GET COUNT
	ORA	C
	JNZ	RDBNORD	;NO READ
;
	INX	H	;TO BUFFER SIZE
	MOV	A,M	;GET COUNT
	ADD	A	;MULTIPLY BY 2
	MOV	B,A	;SECTOR COUNT IN B
	INX	H	;TO FCB
	PUSH	H	;SAVE FCB POINTER
	MOV	A,M	;GET..
	INX	H	;..FCB..
	MOV	H,M	;..ADDR..
	MOV	L,A	;..TO HL
;
RDBLP	MVI	A,1AH	;GET EOF CHAR
	STAX	D	;SAVE IN CASE EOF
	PUSH	D	;SAVE DMA ADDR
	PUSH	H	;SAVE FCB ADDR
	CPM	STDMA	;SET DMA ADDR
	POP	D	;GET FCB
	CPM	READ
	ORA	A
	POP	H	;HL=DMA, DE=FCB
	JNZ	RDBRET	;GOT EOF
	MOV	A,L
	ADI	80H	;TO NEXT BUFF
	MOV	L,A
	MOV	A,H
	ACI	0
	MOV	H,A
	XCHG		;DMA TO DE, FCB TO HL
	DCR	B	;MORE SECTORS?
	JNZ	RDBLP	;YES, MORE
RDBRET	POP	H	;GET FCB POINTER
	DCX	H	;TO LENGTH
	MOV	A,M	;GET LENGTH
	DCX	H	;TO COUNT
	MOV	M,A	;SET PAGE COUNT
	DCX	H	;TO LO COUNT
	DCX	H	;TO HI FCB
	DCX	H	;TO EFCB START
	JMP	RDBYTE	;LOOP THRU AGAIN
;
RDBNORD	INX	H	;TO LENGTH
	MOV	A,M	;GET LENGTH (PAGES)
	XCHG		;BUFF TO HL
	ADD	H
	MOV	H,A	;HL = END OF BUFF
	MOV	A,L
	SUB	C
	MOV	L,A
	MOV	A,H
	SBB	B
	MOV	H,A	;HL = DATA POINTER
	MOV	A,M	;GET BYTE
	XCHG		;EFCB BACK TO HL
	CPI	1AH	;EOF?
	RZ		;YES, LEAVE POINTERS
	DCX	B	;DECR COUNT
	DCX	H	;BACK TO "BYTES LEFT"
	MOV	M,B
	DCX	H
	MOV	M,C	;STORE BACK COUNT
	RET
;
;SAMPLE EFCB:
;
;EFCB	DW	BUFF	;BUFFER ADDR
;	DW	0	;BYTES LEFT
;	DB	20	;BUFFER SIZE (IN PAGES)
;	DW	FCB	;FCB ADDRESS
;
;	MUST BE ASSEMBLED BY "MAC"
;
;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.  THIS COMMAND WOULD BE USED
;IN SUCH PROGRAMS AS MODEM TRANSFER, TAPE SAVE,
;ETC IN WHICH YOU WANT TO PROCESS SINGLE OR
;MULTIPLE FILES.
;
;JUST CALL "MFNAME" (Multiple File NAME) AND THE FCB
;WILL BE SET UP WITH THE NEXT NAME, READY TO
;DO NORMAL PROCESSING (OPEN, READ, ETC.)
;
;CARRY IS SET IF NO MORE NAMES CAN BE FOUND
;
;------------------------------------------------
;
;	MULTI-FILE ACCESS SUBROUTINE
;
;THE ROUTINE IS COMMENTED IN PSEUDO CODE,
;EACH PSEUDO CODE STATEMENT IS IN <<...>>
;
MFNAME:
;<<INIT DMA ADDR, FCB>>
 CPM STDMA,80H
 XRA A ! STA FCBEXT ! STA FCBRNO
;<<IF FIRST TIME>>
 LDA MFFLG1 ! ORA A ! JNZ MFN01
;  <<TURN OFF 1ST TIME SW>>
 MVI A,1 ! STA MFFLG1
;  <<SAVE THE REQUESTED NAME>>
 MOVE FCB,MFREQ,12 ;SAVE ORIG REQ
 LDA FCB ! STA MFCUR ;SAVE DISK IN CURR FCB
;  <<SRCHF REQ NAME>>
 MOVE MFREQ,FCB,12
 CPM SRCHF,FCB
;<<ELSE>>
 JMP MFN02
MFN01:
;  <<SRCHF CURR NAME>>
 MOVE MFCUR,FCB,12
 CPM SRCHF,FCB
;  <<SRCHN REQ NAME>>
 MOVE MFREQ,FCB,12
 CPM SRCHN,FCB
;<<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
 MOVE ,MFCUR+1,11
;<<MOVE NAME FOUND TO FCB>>
 POP H ! MOVE ,FCB+1,11
;<<SETUP FCB>>
 XRA A ! STA FCBEXT
;<<RETURN>>
 RET
;
;MULTI-FILE ACCESS WORK AREA
;
MFFLG1	DB	0	;1ST TIME SW
MFREQ	DS	12	;REQ NAME
MFCUR	DS	12	;CURR NAME
;------------------------------------------------
;
;EXIT, READING CHAR WHICH WAS TYPED TO INTERRUPT
;
CHREXIT	CPM	RDCON
	CALL	MSGEXIT
	DB	CR,LF,'++ABORT++$'
;
;EXIT WITH ERROR MESSAGE
;
MSGEXIT	EQU	$	;EXIT W/"INFORMATIONAL" MSG
ERXIT	POP	D	;GET MSG
	MVI	C,PRINT
	CALL	BDOS
;
;EXIT, RESTORING STACK AND RETURN
;
EXIT	LHLD	STACK
	SPHL
	RET		;TO CCP
;
EFCB	DW	BUFF	;BUFFER ADDR
EFCBCT	DW	0	;BYTES LEFT
	DB	20	;BUFFER SIZE (IN PAGES)
	DW	FCB	;FCB ADDRESS
;
STRING	DS	30	;WHAT TO SEARCH FOR
	DS	100	;STACK AREA
STACK	DS	2
STRPTR	DS	2	;POINTER FOR "|" SCAN
LINE	DS	133
BUFF	EQU	$	;DISK READ BUFER
;
;BDOS/CBIOS EQUATES (VERSION 8)	
;
RDCON	EQU	1
WRCON	EQU	2
PRINT	EQU	9
RDCONBF	EQU	10
CONST	EQU	11
OPEN	EQU	15
CLOSE	EQU	16
SRCHF	EQU	17
SRCHN	EQU	18
ERASE	EQU	19
READ	EQU	20
WRITE	EQU	21
MAKE	EQU	22
REN	EQU	23
STDMA	EQU	26
BDOS	EQU	5
FCB	EQU	5CH 
FCB2	EQU	6CH
FCBEXT	EQU	FCB+12
FCBRNO	EQU	FCB+32
