;FIND.ASM 
;
;03/Aug/82 ADDED DETECT OF CONTROL X TO SKIP TO NEXT FILE
;	   AFTER DISASSEMBLING A VERSION OF FIND DATED
;	   8/Nov/80 (FOR WHICH I DIDN'T HAVE THE SOURCE)
;	   AND FINDING THAT FEATURE IMPLEMENTED. Bill Bolton
;
;01/Aug/82 DOING "FIND *.* [any garbage string]" ON AN RCPM
;	   SYSTEM WOULD GIVE A DIRECTORY OF ALL FILES ON THE
;	   DISK, INCLUDING TAGGED AND SYSTEM FILES WHICH MAY
;	   HAVE BEEN INTENDED TO BE "INVISIBLE". ADDED FILE
;	   TYPE AND ATTRIBUTE CHECKING FROM "DISPLAY" TO
;	   PREVENT THIS HAPPENING. FILES WITH TYPE "ALL" 
;	   (WHICH I USE FOR CATALOGUES) WILL BE SCANNED NO
;	   MATTER WHAT ATTRIBUTES ARE SET. THIS ALLOWS THE
;	   CATALOGUES TO BE "FIND"ed AND "DISPLAY"ed BUT NOT
;	   "TYPE"ed OR "XMODEM"ed. IMPLEMENTED FOR CONDITIONAL
;	   ASSEMBLY. ALSO CHANGED ABORT TO ONLY RESPOND TO
;	   CONTROL-C OR CONTROL-K TO ELIMINATE PROBLEMS ON
;	   REMOTE SYSTEMS WITH SUPRIOUS CHARACTERS OFF THE LINE
;	   PREMATURELY ABORTING A "FIND". CHANGED THE ABORT CHECK
;	   TO DIRECT CONSOLE INPUT (BDOS 6) SO THE A CP/M VERSION
;	   NUMBER CHECK WAS ADDED. Bill Bolton
;	
;18/Mar/80 MAKE "_" MATCH A TAB; MAKE "|" AN "OR"
;	   AS IN: FIND B:*.ASM _IN_|_OUT_
;
;27/Feb/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.
;
;27/Jan/80 PUT IN CTL-C BREAK
;
;23/Jun/79 ORIGINALLY WRITTEN BY WARD CHRISTENSEN
;	----------------
;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
CNTRLC	EQU	3
TAB	EQU	9
CNTRLK	EQU	11
CNTRLS	EQU	19
CNTRLX	EQU	24
;
FALSE	EQU	0
TRUE	EQU	NOT FALSE
;
RCPM	EQU	TRUE	;True for restricted filetype search
;
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/Aug/82'
	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
;
	CPM	VERSION
	MOV	A,L	;A <---- VERSION NUMBER
	CPI	20H
	JNC	CHECK$NAME
	CALL	ERXIT
	DB	'++ CP/M Version 2.0 or later is required to run FIND$'
;
CHECK$NAME:
	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

	IF	RCPM
;
;Check for .ALL file, which can always be scanned
;
ALLCHK:
	LDA	FCB+11	
	CPI	'L'		;WAS LAST CHAR AN 'L'?
	JNZ	CKFIL		;IF NOT, TRY NEXT TEST
	LDA	FCB+10		;CHK NEXT
	ANI	07FH		;Forget attributes for this test
	CPI	'L'		;AN 'L'?
	JNZ	CKFIL		;IF NOT, TRY NEXT TEST
	LDA	FCB+9		;WAS 'L', CHK NEXT CHAR
	ANI	07FH		;Forget attributes for this test
	CPI	'A'		; 'A' AS IN '.ALL'?
	JZ	OK$SCAN		;YES, GO SCAN IT
;
;Check for file protected by CP/M 2.x f2' attribute
;
CKFIL:	LDA	FCB+2		;POINT TO TAG FILE ATTR
	ANI	80H		;IS IT TAGGED?
	JZ	CKFIL2		;IF NOT, CONTINUE
;
PROXIT:
	JMP	NEXTFL		;SEE IF ANOTHER
;
CKFIL2:	LDA	FCB+10		;POINT TO SYS FILE ATTR
	ANI	80H		;IS IT SYS?
	JNZ	PROXIT		;SYS file, can't print it
;
;Check for .COM file, which can't be scanned
;
	LDA	FCB+11
	CPI	'M'		;WAS LAST CHAR AN 'M'?
	JNZ	OBJCHK		;IF NOT, CHK FOR '.OBJ' TYPE
	LDA	FCB+10
	ANI	7FH		;STRIP CP/M 2.x ATTR
	CPI	'O'		;AN 'O'?
	JNZ	OK$SCAN		;IF NOT IT'S OK TO SCAN
	LDA	FCB+9
	ANI	7FH		;STRIP CP/M 2.x ATTR
	CPI	'C'		;'C' AS IN '.COM'?
	JNZ	OK$SCAN		;IF NOT, IT'S OK TO SCAN
	JMP	NEXTFL		;MORE TO PRINT?
;
;Check for .OBJ file, which can't be scanned
;
OBJCHK:
	CPI	'J'		;WAS LAST CHAR AN 'J' ?
	JNZ	OK$SCAN		;IF NOT, OK TO SCAN
	LDA	FCB+10		;MIGHT BE '.OBJ', CHK NEXT CHR
	ANI	7FH		;STRIP CP/M 2.x ATTR
	CPI	'B'		;IS IT A 'B'?
	JNZ	OK$SCAN		;IF NOT, SCAN
	LDA	FCB+9		;WAS, CHK FIRST CHAR
	ANI	7FH		;STRIP CP/M 2.x ATTR
	CPI	'O'		;'O' AS IN '.OBJ'?
	JNZ	OK$SCAN		;IF NOT, SCAN THE FILE, IF SO
	JMP	NEXTFL		;MORE TO SCAN?

	ENDIF	;RCPM
;
OK$SCAN:
	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	DIRECT,0FFH	;TEST FOR USER COMMAND
	ORA	A
	CNZ	CHREXIT		;PARSE COMMAND
	JC	NEXTFL
;
;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:
	CPI	CNTRLC	;ABORT?
	JZ	ABORT
	CPI	CNTRLK	;ABORT?
	JZ	ABORT
	CPI	CNTRLX	;SKIP TO NEXT FILE?
	STC
	RZ
	CPI	CNTRLS	;PAUSE?
	JZ	PLOOP
	ORA	A	;RESET CARRY FLAG
	RET
;
PLOOP:
	CPM	DIRECT,0FFH
	ORA	A
	JZ	PLOOP
	JMP	CHREXIT
;
ABORT:
	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	200	;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
DIRECT	EQU	6
PRINT	EQU	9
RDCONBF	EQU	10
CONST	EQU	11
VERSION	EQU	12
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
