NEW
  AUTO 3,1
				.LIST OFF	
*--------------------------------------
X.MAX.RECURSE	.EQ 8
*--------------------------------------
* Uses: (pData)
*  hDIRs		.BS X.MAX.RECURSE+1
*  hDIRENTs		.BS X.MAX.RECURSE+1
*  Index		.BS 1
*  hSrcBasePath	.BS 1
*  hDstBasePath	.BS 1				(optional)
*  STAT			.BS S.STAT
*  hFilter		.BS 1
*  hExclude		.BS 1
*--------------------------------------
* Compare a ZPFileName against hFilter (e.g. '*test?.*')
* CC : match
* CS : no match
*--------------------------------------
FilterMatch		>LDA.G index
				dec
				bne FilterMatch.CLCRTS	in a subdir, match everything

				clc
				.HS B0					BCS

ExcludeMatch	sec
				php
				lda #hFilter
				adc #0
				tay
				lda (pData),y
				plp
				
				tax
				
				beq	FilterMatch.RTS		No filter....exit with CS  excluded

				>SYSCALL GetMemPtr
				>STYA ZPPtr2

				ldy #S.STAT.FSID
				lda (ZPFileStat),y
				tax						if 0, Regular ProDOS....
				bne .10
				
				>LDYA ZPPtr2			... so CI compare
				>SYSCALL StrUpr
				
.10				lda (ZPPtr2)			Get first pattern byte
				beq .8                  Match always if empty

				ldy #0
				bra .2

.1				jsr FilterMatch.NextPtr2	get next pattern char 
				beq .41					end of pattern...

.2				cmp #'*' 
				beq .5
										
.3				lda (ZPFileName),y		we must match ? or regular char, check if at end of string 
				beq .9                  no char left, exit with error 
										
				lda (ZPPtr2)       		get back pattern char 
				cmp #'?' 
				beq .4                  no need to compare, any char will match 

				jsr FilterMatch.CmpPtr2CharPtr1Y	Regular Char, compare with string at Y 
				bne .9                  no match, exit 

.4				iny                     advance to next char to compare                                   
				bra .1					continue if remaining char in pattern 

.41				lda (ZPFileName),y 		end of pattern, but end of string ? 
				beq .8					yes, string matched entirely 
*										no, remaining char in string, no match 
.9              sec 
				rts 

.5				jsr FilterMatch.NextPtr2		we have '*', last char of pattern ? 
				beq .8					yes, match everything, including empty string 
										
				cmp #'*'				another '*' ? 
				beq .5					yes, '**' = '*', go next char 

				cmp #'?'				'*?' ? we must match a least one char 
				beq .3 
										
.7				lda (ZPFileName),y		we need at least one remaining char in string, check if at end of string 
				beq .9					no chance to match ? or regular char 
										
				iny 
				jsr FilterMatch.CmpPtr2CharPtr1Y	compare with char in string 
				bne .7  	            not equal to next non wildcard in pattern 

				iny
				bra .1                  go check remaining char in pattern... 
										
.8				
FilterMatch.CLCRTS
				clc
FilterMatch.RTS
				rts 
*--------------------------------------
FilterMatch.CmpPtr2CharPtr1Y
				phx
				plx
				bne .2					Foreign FS or ProDOS.FX : CS compare

				lda (ZPFileName),y
				cmp #'a'
				bcc .1

				cmp #'z'+1
				bcs .1

				eor #$20
				
.1				cmp (ZPPtr2)
				rts
				
.2				lda (ZPPtr2)
				cmp (ZPFileName),y
				rts
*--------------------------------------
FilterMatch.NextPtr2
				inc ZPPtr2				Make PTR2 advance to next char 
				bne .1 

				inc ZPPtr2+1

.1				lda (ZPPtr2)
				rts
*--------------------------------------
InitSrcDirYA	>PUSHYA
				>PUSHWI 0				Allocate
				>SYSCALL RealPath
				bcs FilterMatch.RTS

				>STYA ZPPtr1
				txa
				>STA.G hFullPath

				ldy #1
				lda (ZPPtr1),y
				beq .5					we have '/'

				>PUSHW ZPPtr1
				>PUSHEA.G STAT
				>SYSCALL Stat
				bcs .1					File/DIR does not exists, go extract pattern

				.DO X.ENTER.SUBDIR=1
				>LDA.G STAT+S.STAT.MODE+1
				and #$F0
				cmp /S.STAT.MODE.DIR
				bne .4					TYPE not a DIR, extract....

				bra .5					TYPE=DIR, do not extract pattern
				.ELSE
				bra .4
				.FIN

.1				cmp #MLI.E.INVPATH
				beq .11

				jmp .9
	
.11				jsr GetPtr1Len			TYPE is not DIR, check if wc

				dey

				ldx #0					Init Wildcard count

.2				lda	(ZPPtr1),y			search backward for a /
				cmp #'/'
				beq .3

				cmp #'?'				Test if some wildcard chars....
				beq .21

				cmp #'*'
				bne .22

.21				inx						inc wildcard count
.22				dey
				bne .2

.3				txa
				beq .91					no wc, file not found....

.4				jsr GetPtr1Len			Search end of string.....

				lda #'/'

.42				dey
				cmp (ZPPtr1),y			Search backward /
				bne .42

				tya
				sec						+1 to skip '/'
				adc ZPPtr1
				sta ZPPtr2
				tay
				lda ZPPtr1+1
				adc #0
				sta ZPPtr2+1

				>SYSCALL StrDup
				bcs .9

				txa
				>STA.G hFilter

				lda #0
				sta (ZPPtr2)

.5				>LDYAI 256
				>SYSCALL GetMem			Get a 256 buffer to store BasePath
				bcs .9

				>STYA ZPPtr2
				txa
				>STA.G hSrcBasePath

				jsr StrcpyPtr1ptr2

				dey
				lda #'/'
				cmp (ZPPtr2),y
				beq .7

				iny
				sta (ZPPtr2),y
				iny
				lda #0
				sta (ZPPtr2),y

.7				>LDYA ZPPtr2
				>SYSCALL OpenDir
				bcs .9

				ldy #hDIRs
				sta (pData),y			set hDIRs[0] = Src Hdir
				ldy #index
				lda #1
				sta (pData),y			index=hDIRs[0]

				jsr .9					Cleanup

				clc
				rts

.91				lda #MLI.E.FNOTFND

.9				pha
				>LDA.G hFullPath
				>SYSCALL FreeMem
				pla
				sec
InitSrcDirYA.RTS
				rts	
*--------------------------------------
ResetSrcDir		jsr GethDIR

				>SYSCALL CloseDir
				
				>LDA.G hSrcBasePath
				>SYSCALL GetMemPtr
				>SYSCALL OpenDir
				bcs .9
				
				pha

				>LDA.G index
				clc
				adc #hDIRs-1
				tay

				pla
				sta (pData),y

*				clc
.9				rts
*--------------------------------------
				.DO X.COPY.TO.DEST=1
InitDstDirYA	>PUSHYA
				>PUSHWI 0				Allocate
				>SYSCALL RealPath
				bcs InitSrcDirYA.RTS

				>STYA ZPPtr1
				txa
				>STA.G hFullPath
				>PUSHW ZPPtr1			
				>PUSHEA.G STAT
				>SYSCALL Stat
				bcs .1					File/DIR does not exists, go extract DstFileName

				>LDA.G STAT+S.STAT.MODE+1
				and #$F0
				cmp /S.STAT.MODE.DIR
				beq .5					Dst is a directory...no destfilename

.1				jsr GetPtr1Len			Search end of string.....

				lda #'/'

.2				dey
				cmp (ZPPtr1),y			Search backward /
				bne .2

				tya
				sec						+1 to skip '/'
				adc ZPPtr1
				sta ZPPtr2
				tay
				lda ZPPtr1+1
				adc #0
				sta ZPPtr2+1

				>SYSCALL StrDup
				bcs .9

				txa
				>STA.G hDstFileName

				lda #0
				sta (ZPPtr2)

.5				>LDYAI 256
				>SYSCALL GetMem			Get a 256 buffer to store DstBasePath
				bcs .9

				>STYA ZPPtr2
				txa
				>STA.G hDstBasePath

				jsr StrcpyPtr1ptr2

				dey

				lda #'/'
				cmp (ZPPtr2),y
				beq .7

				iny
				sta (ZPPtr2),y
				iny
				lda #0
				sta (ZPPtr2),y
	
.7				jsr .9					Cleanup

				clc
.99				rts
			
.9				pha
				>LDA.G hFullPath
				>SYSCALL FreeMem
				pla
				sec
				rts	
				.FIN
*--------------------------------------
GetNextEntry	jsr GetEntry
				bcs .9

				jsr GetFilenameLen		Save actual file len for setting up
				pha						new offset later
				lda ZPFileStat
				clc
				adc #S.STAT
				sta ZPFileName
				lda ZPFileStat+1
				adc /S.STAT
				sta ZPFileName+1		Make nDIRENTs[i] point to next DIRENT

				jsr GetFilenameLen		are we at end of this buffer ?
				beq .1					yes, go read next one ...

				jsr SetFileStatPtr

				jsr GetoDIRENT

				pla						Get back previous file len
				sec
				adc (pData),y
				sta (pData),y
				iny

				lda #0
				adc (pData),y
				sta (pData),y
				dey
				lda #S.STAT
				clc
				adc (pData),y
				sta (pData),y
				iny

				lda /S.STAT
				adc (pData),y
				sta (pData),y
				clc
				rts

.1				pla
				jsr GetEntry.ReadDir
				bcs .9

				jsr GetFilenameLen
				beq .99

				jsr SetFileStatPtr

				clc
.9				rts

.99				sec
				rts
*--------------------------------------
GetEntry		jsr GethDIRENT
				bne .1					we have a buffer to scan

				jsr GetEntry.ReadDir	First run, get first block
				bcs .9					ZPFileName = start of buffer

				lda (ZPFileName)		Empty !!!
				bne .8

				sec
				rts

.1				>SYSCALL GetMemPtr
				>STYA ZPFileName		
				jsr GetoDIRENT

				lda ZPFileName
				clc
				adc (pData),y
				sta ZPFileName

				iny

				lda ZPFileName+1
				adc (pData),y
				sta ZPFileName+1		ZPFileName=ZPFileName+oDIRENT

.8				jsr GetFilenameLen

				jsr SetFileStatPtr
			
				clc
.9				rts
*--------------------------------------
GetEntry.ReadDir
				jsr GethDIRENT
				beq .1

				pha
				lda #0
				sta (pData),y			reset hDIRENT
				pla
				>SYSCALL FreeMem		discard previous hDIRENT

.1				jsr GethDIR
				>SYSCALL ReadDir
				bcs .9

				>STYA ZPFileName
				ldy #index
				lda (pData),y
				clc
				adc #hDIRENTs-1
				tay
				txa						get hDIRENT in A
				sta (pData),y

				jsr GetoDIRENT

				lda #0					and reset offset for this buffer
				sta (pData),y
				iny
				sta (pData),y
				clc
.9				rts
*--------------------------------------
EnterSubDirYA	>STYA ZPPtr2			save SUBDIR for StrCat

				>LDA.G index
				cmp #X.MAX.RECURSE
				beq .9

				ldy #hSrcBasePath
				jsr EnterSubDirY
				>LDYA ZPPtr1
				>SYSCALL OpenDir
				bcs .9

				pha
				>INC.G index
				tax
*				clc						from BCS
				adc #hDIRs-1
				tay
				pla
				sta (pData),y
				txa						make sure hDIRENTs[i] is closed
				adc #hDIRENTs-1
				tay
				lda #0
				sta (pData),y

				.DO X.COPY.TO.DEST=1
				ldy #hDstBasePath
				jsr EnterSubDirY
				.FIN

				clc
.9				rts

EnterSubDirY	lda (pData),y
				>SYSCALL GetMemPtr
				>STYA ZPPtr1			save full path

				jsr .1					Make sure ending with /

				>PUSHW ZPPtr1
				>PUSHW ZPPtr2
				>SYSCALL StrCat

.1				jsr GetPtr1Len

				dey
				lda #'/'
				cmp (ZPPtr1),y
				beq .8

				iny
				sta (ZPPtr1),y
				iny
				lda #0
				sta (ZPPtr1),y

.8				rts
*--------------------------------------
LeaveSubDir		>LDA.G index
				beq .9

				jsr GethDIRENT.A
				beq .1

				pha
				lda #0
				sta (pData),y
				pla
				>SYSCALL FreeMem

.1				jsr GethDIR

				pha
				lda #0
				sta (pData),y
				pla
				>SYSCALL CloseDir

				>DEC.G index
				bne .8

				ldy #hSrcBasePath
				lda (pData),y
				>SYSCALL FreeMem

				.DO X.COPY.TO.DEST=1
				ldy #hDstBasePath
				lda (pData),y
				>SYSCALL FreeMem
				.FIN

.9				sec
				rts

.8				clc
				rts
*--------------------------------------
BasePath..		.DO X.COPY.TO.DEST=1

				ldy #hDstBasePath
				jsr BasePath..1
				.FIN
				ldy #hSrcBasePath
				
BasePath..1		lda (pData),y
				>SYSCALL GetMemPtr
				>STYA ZPPtr1			save full path

				jsr GetPtr1Len			get len

				dey 					discard ending /
				
.2				dey
				lda (ZPPtr1),y
				cmp #'/'
				bne .2

				iny
				lda #0
				sta (ZPPtr1),y			cut DIR2/ from /dir1/DIR2/

				rts
*--------------------------------------
GetPtr1Len		ldy #$ff

.1				iny

				lda (ZPPtr1),y			get len
				bne .1

				rts
*--------------------------------------
StrcpyPtr1ptr2	ldy #$ff

.1				iny
				lda (ZPPtr1),y
				sta (ZPPtr2),y
				bne .1

				rts
*--------------------------------------
GetFilenameLen	ldy #$ff

.1				iny
				lda (ZPFileName),y
				bne .1

				tya
				rts
*--------------------------------------
SetFileStatPtr	sec
				adc ZPFileName
				sta ZPFileStat
				lda ZPFileName+1
				adc #0
				sta ZPFileStat+1
				rts
*--------------------------------------
GethDIR			ldy #index
				lda (pData),y
				clc
				adc #hDIRs-1
				tay
				lda (pData),y
				rts
*--------------------------------------
GethDIRENT		ldy #index
				lda (pData),y

GethDIRENT.A	clc
				adc #hDIRENTs-1
				tay
				lda (pData),y
				rts
*--------------------------------------
GetoDIRENT		ldy #index
				lda (pData),y
				asl
				clc
				adc #oDIRENTs-1
				tay
				rts
*--------------------------------------
MAN
SAVE usr/src/shared/x.fileenum.s
LOAD usr/src/bin/ls.s
ASM
