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 *-------------------------------------- .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 GetNextEntry.99 jsr SetFileStatPtr clc .9 rts GetNextEntry.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