NEW AUTO 3,1 .LIST OFF *-------------------------------------- X.MAX.RECURSE .EQ 8 *-------------------------------------- * Uses: * (ZP) * ZPPtr1 .BS 2 * ZPPtr2 .BS 2 * ZPFileName .BS 2 * ZPFileStat .BS 2 * (pData) * Index .BS 1 * hDIRs .BS X.MAX.RECURSE+1 * hDIRENTs .BS X.MAX.RECURSE+1 * oDIRENTs .BS X.MAX.RECURSE*2 * STATBUF .BS S.STAT * hSrcBasePath .BS 1 * hDstBasePath .BS 1 (optional) * hInclude .BS 1 * hIgnore .BS 1 *-------------------------------------- * Compare a ZPFileName against hInclude (e.g. '*test?.*') * CC : match * CS : no match *-------------------------------------- X.IncludeMatch >LDA.G index dec bne X.FilterMatch.CLCRTS in a subdir, match everything clc .HS B0 BCS X.IgnoreMatch sec ldy #hInclude bcc .11 iny hIgnore .11 lda (pData),y beq X.FilterMatch.RTS No filter....exit with passed carry >SYSCALL GetMemPtr >STYA ZPPtr2 ldy #S.STAT.FSID lda (ZPFileStat),y if 0, Regular ProDOS.... pha save FSID for comparing later bne .10 >LDYA ZPPtr2 ... so CI compare >SYSCALL StrUpr .10 plx get back FSID lda (ZPPtr2) Get first pattern byte beq .8 Match always if empty ldy #0 bra .2 .1 jsr X.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 X.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 X.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 X.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 X.FilterMatch.CLCRTS clc X.FilterMatch.RTS rts *-------------------------------------- X.FilterMatch.CmpPtr2CharPtr1Y lda (ZPFileName),y phx plx bne .1 Foreign FS or ProDOS.FX : CS compare jsr X.ToUpper .1 cmp (ZPPtr2) rts *-------------------------------------- X.FilterMatch.NextPtr2 inc ZPPtr2 Make PTR2 advance to next char bne .1 inc ZPPtr2+1 .1 lda (ZPPtr2) rts *-------------------------------------- X.InitSrcDirYA >STYA ZPPtr1 X.InitSrcDirPtr1 jsr X.InitGetBuf Get a 256 buffer to store BasePath bcs .99 >STA.G hSrcBasePath ldy #1 lda (ZPPtr2),y beq .8 we have '/' jsr X.Init.Stat bcs .1 File/DIR does not exists, go extract pattern .DO X.ENTER.SUBDIR=1 >LDA.G STATBUF+S.STAT.MODE+1 and #$F0 cmp /S.STAT.MODE.DIR bne .7 Not a dir.... jsr X.GetPtr2Len dey lda #'/' cmp (ZPPtr2),y beq .8 iny sta (ZPPtr2),y iny lda #0 sta (ZPPtr2),y bra .8 TYPE=DIR, do not extract pattern .ELSE bra .7 .FIN .1 cmp #MLI.E.INVPATH bne .98 jsr X.GetPtr2Len TYPE is not DIR, check if wc dey ldx #0 Init Wildcard count .2 lda (ZPPtr2),y search backward for a / cmp #'/' beq .6 cmp #'?' Test if some wildcard chars.... beq .3 cmp #'*' bne .4 .3 inx inc wildcard count .4 dey bne .2 .6 txa beq .97 no wc, file not found.... .7 jsr X.InitSplitBuf bcs .99 >STA.G hInclude .8 >LDYA ZPPtr2 >SYSCALL OpenDir bcs .99 ldy #hDIRs sta (pData),y set hDIRs[0] = Src Hdir ldy #index lda #1 sta (pData),y index=hDIRs[0] * clc rts .97 lda #MLI.E.INVPATH .98 sec .99 rts *-------------------------------------- .DO X.RESET.SRC.DIR=1 X.ResetSrcDir jsr X.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 .FIN *-------------------------------------- .DO X.COPY.TO.DEST=1 X.InitDstDirYA >STYA ZPPtr1 X.InitDstDirPtr1 jsr X.InitGetBuf Get a 256 buffer to store BasePath bcs .99 >STA.G hDstBasePath jsr X.Init.Stat bcs .1 File/DIR does not exists, go extract DstFileName >LDA.G STATBUF+S.STAT.MODE+1 and #$F0 cmp /S.STAT.MODE.DIR beq .8 Dst is a directory...no hDstFileName .1 jsr X.InitSplitBuf bcs .99 >STA.G hDstFileName .8 jmp X.NormalizePtr2 .99 rts .FIN *-------------------------------------- X.InitGetBuf >LDYAI 256 >SYSCALL GetMem Get a 256 buffer to store BasePath bcs .99 >STYA ZPPtr2 phx >PUSHW ZPPtr1 >PUSHW ZPPtr2 >SYSCALL RealPath bcs .98 pla hBuf * clc rts .98 plx pha txa >SYSCALL FreeMem pla sec .99 rts *-------------------------------------- X.Init.Stat >PUSHW ZPPtr2 >PUSHEA.G STATBUF >SYSCALL Stat rts *-------------------------------------- X.InitSplitBuf jsr X.GetPtr2Len Search end of string..... lda #'/' .1 dey cmp (ZPPtr2),y Search backward / bne .1 tya sec +1 to skip '/' adc ZPPtr2 sta ZPPtr1 lda ZPPtr2+1 adc #0 sta ZPPtr1+1 lda (ZPPtr1) beq .8 path is /dir/ >LDYA ZPPtr1 >SYSCALL StrDup bcs .99 lda #0 sta (ZPPtr1) txa .8 clc .99 rts *-------------------------------------- X.GetNextEntry jsr X.GetEntry bcs .9 jsr X.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 X.GetFilenameLen are we at end of this buffer ? beq .1 yes, go read next one ... jsr X.SetFileStatPtr jsr X.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 X.GetEntry.ReadDir bcs .9 jsr X.GetFilenameLen beq .99 jsr X.SetFileStatPtr clc .9 rts .99 sec rts *-------------------------------------- X.GetEntry jsr X.GethDIRENT bne .1 we have a buffer to scan jsr X.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 X.GetoDIRENT lda ZPFileName clc adc (pData),y sta ZPFileName iny lda ZPFileName+1 adc (pData),y sta ZPFileName+1 ZPFileName=ZPFileName+oDIRENT .8 jsr X.GetFilenameLen jsr X.SetFileStatPtr clc .9 rts *-------------------------------------- X.GetEntry.ReadDir jsr X.GethDIRENT beq .1 pha lda #0 sta (pData),y reset hDIRENT pla >SYSCALL FreeMem discard previous hDIRENT .1 jsr X.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 X.GetoDIRENT lda #0 and reset offset for this buffer sta (pData),y iny sta (pData),y clc .9 rts *-------------------------------------- X.EnterSubDirYA >STYA ZPPtr1 save SUBDIR for StrCat >LDA.G index cmp #X.MAX.RECURSE beq .9 ldy #hSrcBasePath jsr X.EnterSubDirY >LDYA ZPPtr2 >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 X.EnterSubDirY .FIN clc .9 rts *-------------------------------------- X.EnterSubDirY lda (pData),y >SYSCALL GetMemPtr >STYA ZPPtr2 save full path >PUSHW ZPPtr2 >PUSHW ZPPtr1 >SYSCALL StrCat X.NormalizePtr2 jsr X.GetPtr2Len dey lda #'/' cmp (ZPPtr2),y beq .8 iny sta (ZPPtr2),y iny lda #0 sta (ZPPtr2),y .8 clc rts *-------------------------------------- X.LeaveSubDir >LDA.G index beq .7 jsr X.GethDIRENT.A jsr X.LeaveSubDir.free jsr X.GethDIR beq .1 pha lda #0 sta (pData),y pla >SYSCALL CloseDir .1 >DEC.G index bne .8 .7 >LDA.G hSrcBasePath jsr X.LeaveSubDir.free .DO X.COPY.TO.DEST=1 >LDA.G hDstBasePath jsr X.LeaveSubDir.free .FIN sec rts .8 clc rts *-------------------------------------- X.LeaveSubDir.free tax beq .8 lda #0 sta (pData),y txa >SYSCALL FreeMem .8 rts *-------------------------------------- X.BasePath.. .DO X.COPY.TO.DEST=1 ldy #hDstBasePath jsr X.BasePath..1 .FIN ldy #hSrcBasePath X.BasePath..1 lda (pData),y >SYSCALL GetMemPtr >STYA ZPPtr2 save full path jsr X.GetPtr2Len get len dey discard ending / .2 dey lda (ZPPtr2),y cmp #'/' bne .2 iny lda #0 sta (ZPPtr2),y cut DIR2/ from /dir1/DIR2/ rts *-------------------------------------- X.ToUpper cmp #'a' bcc .8 cmp #'z'+1 bcs .8 eor #$20 .8 rts *-------------------------------------- X.GetPtr2Len ldy #$ff .1 iny lda (ZPPtr2),y get len bne .1 rts *-------------------------------------- X.GetFilenameLen ldy #$ff .1 iny lda (ZPFileName),y bne .1 tya rts *-------------------------------------- X.SetFileStatPtr sec adc ZPFileName sta ZPFileStat lda ZPFileName+1 adc #0 sta ZPFileStat+1 rts *-------------------------------------- X.GethDIR >LDA.G index clc adc #hDIRs-1 tay lda (pData),y rts *-------------------------------------- X.GethDIRENT >LDA.G index X.GethDIRENT.A clc adc #hDIRENTs-1 tay lda (pData),y rts *-------------------------------------- X.GetoDIRENT >LDA.G index asl clc adc #oDIRENTs-1 tay rts *-------------------------------------- MAN SAVE usr/src/shared/x.fileenum.s LOAD usr/src/bin/ls.s ASM