	title	whereis
;+
;
; Find file(s) matching a wildcard.
;
; Things to fix:
;
; It would be nice to be able to search only a subtree.
;
; Output should be sorted out so that the dir being searched goes to STDERR,
; but actual matches go to STDOUT, without all the blanks and stuff, so that
; it's worthwhile to redirect the output to a file.
;
; By John Wilson.
;
; 03/18/94	JMBW	Created.
;
;-
	.radix	8
;
bs=	10
lf=	12
cr=	15
;
code	segment
	assume	cs:code
	org	100h
start:	jmp	short start1
	db	bs,bs,'By John Wilson',32
start1:	cld			;DF=0
	mov	al,byte ptr ds:5Ch ;get drive #
	or	al,al		;is there one?
	jnz	gotdsk		;yes
	mov	ah,19h		;func=get logged in disk
	int	21h
	inc	ax		;+1 to conform to format
gotdsk:	add	al,'A'-1	;convert to letter
	mov	byte ptr ds:wbuf,al ;save
	mov	di,offset wbuf+3 ;include slash when printing root dir name
	call	sroot		;search root directory recursively
	mov	di,offset wbuf	;write null name to blank last one
	call	pname
	int	20h
;+
;
; Search a directory recursively.
;
; DS:WBUF contains a path prefix, DS:WPTR points past the end of the prefix.
;
;-
sdir:	mov	di,ds:wptr	;get end of prefix
	dec	di		;-1 to remove slash (looks funny)
sroot:	; enter here to include slash for root directory
	call	pname		;print dir name
	mov	di,ds:wptr	;get and save end of prefix
	push	di
	mov	byte ptr [di-1],'/' ;add slash (PNAME may have nuked it)
	; first search for matches
	mov	di,ds:wptr	;pt at tail
	mov	si,5Ch+1	;pt at FCB #1
	mov	cx,8d		;copy up to 8 chars
	call	copy
	mov	al,'.'		;.
	stosb
	mov	cl,3		;copy up to 3 more
	call	copy
	xor	al,al		;NUL
	stosb
	mov	dx,offset wbuf	;point at buf
	xor	cx,cx		;match all attrs
	mov	ah,4Eh		;func=find first
	int	21h
	jc	sdir4		;nothing found, skip
sdir1:	; display this match
	mov	si,80h+1Eh	;point at filename in DTA
	mov	di,ds:wptr	;point into free space
sdir2:	lodsb			;get a byte
	or	al,al		;is this end?
	jz	sdir3
	stosb			;no, save it
	jmp	short sdir2
sdir3:	call	pname		;print the name
	mov	dl,lf		;print a lf
	mov	ah,02h		;func=CONOUT
	int	21h
	mov	byte ptr ds:wid,0 ;blank line
	mov	dx,80h		;pt at DTA (??? shouldn't be needed)
	mov	ah,4Fh		;func=find next
	int	21h
	jnc	sdir1		;found one, display it
sdir4:	; now search for directories into which to recurse
	mov	di,ds:wptr	;pt at tail
	mov	ax,".*"		;*.*<NUL>
	stosw
	mov	ax,'*'
	stosw
	mov	di,ds:hptr	;get and save heap ptr
	push	di
	mov	dx,offset wbuf	;pt at wildcard
	mov	cx,10h		;attr=directory
	mov	ah,4Eh		;func=find first
	int	21h
	jc	sdir10		;not found, skip
sdir5:	; found a match, save on heap if dir unless . or ..
	test	byte ptr ds:80h+15h,10h ;is it a dir entry?
	jz	sdir7
	mov	si,80h+1Eh	;yes, point at filename in DTA
	cmp	byte ptr [si],'.' ;starts with .?  (. or ..)
	je	sdir7		;yes, ignore
sdir6:	lodsb			;get a byte
	stosb			;save it
	or	al,al		;copy up to NUL
	jnz	sdir6
sdir7:	; look for next match
	mov	dx,80h		;pt at DTA (DOS Tech Help says req'd 3.0+ ????)
	mov	ah,4Fh		;func=find next
	int	21h
	jnc	sdir5		;loop if another match found
	xor	al,al		;mark end of list with null file
	stosb
	mov	si,di		;copy final heap ptr
	xchg	si,ds:hptr	;update HPTR, get ptr to begn
sdir8:	; recurse for each entry we found
	lodsb			;get a byte
	or	al,al		;end of list?
	jz	sdir10
	mov	di,ds:wptr	;pt at buffer
	push	di		;save ptr
sdir9:	stosb			;save
	lodsb			;get next byte
	or	al,al		;end of dir name?
	jnz	sdir9		;loop if not
	mov	al,'/'		;add a slash
	stosb
	mov	ds:wptr,di	;set ptr
	push	si		;save list ptr
	call	sdir		;recurse
	pop	si		;restore list ptr
	pop	ds:wptr		;restore wildcard ptr
	jmp	short sdir8
sdir10:	pop	ds:hptr		;flush stuff we put on heap
	pop	ds:wptr		;restore
	ret
;+
;
; Copy non-blank chars of a filename element.
;
;-
copy:	lodsb			;get a char
	cmp	al,' '		;blank?
	je	$+3		;yes, skip
	 stosb			;otherwise save
	loop	copy		;loop
	ret
;+
;
; Print a dir or file name, blanking out the previous one if there was one.
;
; di	pointer past end of name (WBUF is beginning)
;
;-
pname:	mov	dx,offset wbuf	;pt at name
	mov	cx,di		;copy
	sub	cx,dx		;find length
	mov	bx,cx		;copy
	xchg	bl,ds:wid	;get width of previous name
	cmp	cl,bl		;is current name longer or equal?
	jae	pname1		;yes, no need to clear
	sub	cx,bx		;find # blanks to add
	neg	cx
	mov	al,' '		;load blank
	rep	stosb		;pad
pname1:	mov	al,cr		;cr
	stosb
	mov	cx,di		;copy
	sub	cx,dx		;find length
	mov	bx,0001h	;handle=STDOUT
	mov	ah,40h		;func=write
	int	21h
	ret
;
hptr	dw	heap		;curr free loc in heap
wid	db	0		;width of dir name displayed
wptr	dw	wbuf+3		;ptr to where to add filename
wbuf	db	'?:/',256d dup(?) ;wildcard buffer
heap	label	byte		;heap starts here
;
code	ends
	end	start
