2 File: IterateDirectory.c
4 Contains: File Manager directory iterator routines.
8 Copyright: © 1995-2001 by Jim Luther and Apple Computer, Inc., all rights reserved.
10 You may incorporate this sample code into your applications without
11 restriction, though the sample code has been provided "AS IS" and the
12 responsibility for its operation is 100% yours. However, what you are
13 not permitted to do is to redistribute the source as "DSC Sample Code"
14 after having made changes. If you're going to re-distribute the source,
15 we require that you make it clear in the source that the code was
16 descended from Apple Sample Code, but that you've made changes.
20 DRI: Apple Macintosh Developer Technical Support
22 Other Contact: Apple Macintosh Developer Technical Support
23 <http://developer.apple.com/bugreporter/>
25 Technology: DTS Sample Code
31 Change History (most recent first):
33 <2> 2/7/01 JL Added standard header. Updated names of includes.
34 <1> 12/06/99 JL MoreFiles 1.5.
38 #include <MacErrors.h>
41 #define __COMPILINGMOREFILES
43 #include "MoreFilesExtras.h"
44 #include "IterateDirectory.h"
50 /* The IterateGlobals structure is used to minimize the amount of
51 ** stack space used when recursively calling IterateDirectoryLevel
52 ** and to hold global information that might be needed at any time.
54 #if PRAGMA_STRUCT_ALIGN
55 #pragma options align=mac68k
59 IterateFilterProcPtr iterateFilter
; /* pointer to IterateFilterProc */
60 CInfoPBRec cPB
; /* the parameter block used for PBGetCatInfo calls */
61 Str63 itemName
; /* the name of the current item */
62 OSErr result
; /* temporary holder of results - saves 2 bytes of stack each level */
63 Boolean quitFlag
; /* set to true if filter wants to kill interation */
64 unsigned short maxLevels
; /* Maximum levels to iterate through */
65 unsigned short currentLevel
; /* The current level IterateLevel is on */
66 void *yourDataPtr
; /* A pointer to caller data the filter may need to access */
68 #if PRAGMA_STRUCT_ALIGN
69 #pragma options align=reset
72 typedef struct IterateGlobals IterateGlobals
;
73 typedef IterateGlobals
*IterateGlobalsPtr
;
75 /*****************************************************************************/
77 /* Static Prototype */
79 static void IterateDirectoryLevel(long dirID
,
80 IterateGlobals
*theGlobals
);
82 /*****************************************************************************/
88 static void IterateDirectoryLevel(long dirID
,
89 IterateGlobals
*theGlobals
)
91 if ( (theGlobals
->maxLevels
== 0) || /* if maxLevels is zero, we aren't checking levels */
92 (theGlobals
->currentLevel
< theGlobals
->maxLevels
) ) /* if currentLevel < maxLevels, look at this level */
96 ++theGlobals
->currentLevel
; /* go to next level */
99 { /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
101 /* Get next source item at the current directory level */
103 theGlobals
->cPB
.dirInfo
.ioFDirIndex
= index
;
104 theGlobals
->cPB
.dirInfo
.ioDrDirID
= dirID
;
105 theGlobals
->result
= PBGetCatInfoSync((CInfoPBPtr
)&theGlobals
->cPB
);
107 if ( theGlobals
->result
== noErr
)
109 /* Call the IterateFilterProc */
110 CallIterateFilterProc(theGlobals
->iterateFilter
, &theGlobals
->cPB
, &theGlobals
->quitFlag
, theGlobals
->yourDataPtr
);
112 /* Is it a directory? */
113 if ( (theGlobals
->cPB
.hFileInfo
.ioFlAttrib
& kioFlAttribDirMask
) != 0 )
115 /* We have a directory */
116 if ( !theGlobals
->quitFlag
)
118 /* Dive again if the IterateFilterProc didn't say "quit" */
119 IterateDirectoryLevel(theGlobals
->cPB
.dirInfo
.ioDrDirID
, theGlobals
);
124 ++index
; /* prepare to get next item */
125 } while ( (theGlobals
->result
== noErr
) && (!theGlobals
->quitFlag
) ); /* time to fall back a level? */
127 if ( (theGlobals
->result
== fnfErr
) || /* fnfErr is OK - it only means we hit the end of this level */
128 (theGlobals
->result
== afpAccessDenied
) ) /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
130 theGlobals
->result
= noErr
;
133 --theGlobals
->currentLevel
; /* return to previous level as we leave */
137 /*****************************************************************************/
139 pascal OSErr
IterateDirectory(short vRefNum
,
141 ConstStr255Param name
,
142 unsigned short maxLevels
,
143 IterateFilterProcPtr iterateFilter
,
146 IterateGlobals theGlobals
;
152 /* Make sure there is a IterateFilter */
153 if ( iterateFilter
!= NULL
)
155 /* Get the real directory ID and make sure it is a directory */
156 result
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
);
157 if ( result
== noErr
)
159 if ( isDirectory
== true )
161 /* Get the real vRefNum */
162 result
= DetermineVRefNum(name
, vRefNum
, &theVRefNum
);
163 if ( result
== noErr
)
165 /* Set up the globals we need to access from the recursive routine. */
166 theGlobals
.iterateFilter
= iterateFilter
;
167 theGlobals
.cPB
.hFileInfo
.ioNamePtr
= (StringPtr
)&theGlobals
.itemName
;
168 theGlobals
.cPB
.hFileInfo
.ioVRefNum
= theVRefNum
;
169 theGlobals
.itemName
[0] = 0;
170 theGlobals
.result
= noErr
;
171 theGlobals
.quitFlag
= false;
172 theGlobals
.maxLevels
= maxLevels
;
173 theGlobals
.currentLevel
= 0; /* start at level 0 */
174 theGlobals
.yourDataPtr
= yourDataPtr
;
176 /* Here we go into recursion land... */
177 IterateDirectoryLevel(theDirID
, &theGlobals
);
179 result
= theGlobals
.result
; /* set the result */
184 result
= dirNFErr
; /* a file was passed instead of a directory */
190 result
= paramErr
; /* iterateFilter was NULL */
196 /*****************************************************************************/
198 pascal OSErr
FSpIterateDirectory(const FSSpec
*spec
,
199 unsigned short maxLevels
,
200 IterateFilterProcPtr iterateFilter
,
203 return ( IterateDirectory(spec
->vRefNum
, spec
->parID
, spec
->name
,
204 maxLevels
, iterateFilter
, yourDataPtr
) );
207 /*****************************************************************************/