2 ** IterateDirectory: File Manager directory iterator routines.
6 ** File: IterateDirectory.c
8 ** Copyright © 1995-1998 Jim Luther and Apple Computer, Inc.
9 ** All rights reserved.
11 ** You may incorporate this sample code into your applications without
12 ** restriction, though the sample code has been provided "AS IS" and the
13 ** responsibility for its operation is 100% yours.
15 ** IterateDirectory is designed to drop into the MoreFiles sample code
16 ** library I wrote while in Apple Developer Technical Support
23 #define __COMPILINGMOREFILES
32 /* The IterateGlobals structure is used to minimize the amount of
33 ** stack space used when recursively calling IterateDirectoryLevel
34 ** and to hold global information that might be needed at any time.
36 #if PRAGMA_STRUCT_ALIGN
37 #pragma options align=mac68k
38 #elif PRAGMA_STRUCT_PACKPUSH
40 #elif PRAGMA_STRUCT_PACK
46 IterateFilterProcPtr iterateFilter
; /* pointer to IterateFilterProc */
47 CInfoPBRec cPB
; /* the parameter block used for PBGetCatInfo calls */
48 Str63 itemName
; /* the name of the current item */
49 OSErr result
; /* temporary holder of results - saves 2 bytes of stack each level */
50 Boolean quitFlag
; /* set to true if filter wants to kill interation */
51 unsigned short maxLevels
; /* Maximum levels to iterate through */
52 unsigned short currentLevel
; /* The current level IterateLevel is on */
53 void *yourDataPtr
; /* A pointer to caller data the filter may need to access */
56 #if PRAGMA_STRUCT_ALIGN
57 #pragma options align=reset
58 #elif PRAGMA_STRUCT_PACKPUSH
60 #elif PRAGMA_STRUCT_PACK
64 typedef struct IterateGlobals IterateGlobals
;
65 typedef IterateGlobals
*IterateGlobalsPtr
;
67 /*****************************************************************************/
69 /* Static Prototype */
71 static void IterateDirectoryLevel(long dirID
,
72 IterateGlobals
*theGlobals
);
74 /*****************************************************************************/
80 static void IterateDirectoryLevel(long dirID
,
81 IterateGlobals
*theGlobals
)
83 if ( (theGlobals
->maxLevels
== 0) || /* if maxLevels is zero, we aren't checking levels */
84 (theGlobals
->currentLevel
< theGlobals
->maxLevels
) ) /* if currentLevel < maxLevels, look at this level */
88 ++theGlobals
->currentLevel
; /* go to next level */
91 { /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
93 /* Get next source item at the current directory level */
95 theGlobals
->cPB
.dirInfo
.ioFDirIndex
= index
;
96 theGlobals
->cPB
.dirInfo
.ioDrDirID
= dirID
;
97 theGlobals
->result
= PBGetCatInfoSync((CInfoPBPtr
)&theGlobals
->cPB
);
99 if ( theGlobals
->result
== noErr
)
101 /* Call the IterateFilterProc */
102 CallIterateFilterProc(theGlobals
->iterateFilter
, &theGlobals
->cPB
, &theGlobals
->quitFlag
, theGlobals
->yourDataPtr
);
104 /* Is it a directory? */
105 if ( (theGlobals
->cPB
.hFileInfo
.ioFlAttrib
& ioDirMask
) != 0 )
107 /* We have a directory */
108 if ( !theGlobals
->quitFlag
)
110 /* Dive again if the IterateFilterProc didn't say "quit" */
111 IterateDirectoryLevel(theGlobals
->cPB
.dirInfo
.ioDrDirID
, theGlobals
);
116 ++index
; /* prepare to get next item */
117 } while ( (theGlobals
->result
== noErr
) && (!theGlobals
->quitFlag
) ); /* time to fall back a level? */
119 if ( (theGlobals
->result
== fnfErr
) || /* fnfErr is OK - it only means we hit the end of this level */
120 (theGlobals
->result
== afpAccessDenied
) ) /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
122 theGlobals
->result
= noErr
;
125 --theGlobals
->currentLevel
; /* return to previous level as we leave */
129 /*****************************************************************************/
131 pascal OSErr
IterateDirectory(short vRefNum
,
133 ConstStr255Param name
,
134 unsigned short maxLevels
,
135 IterateFilterProcPtr iterateFilter
,
138 IterateGlobals theGlobals
;
144 /* Make sure there is a IterateFilter */
145 if ( iterateFilter
!= NULL
)
147 /* Get the real directory ID and make sure it is a directory */
148 result
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
);
149 if ( result
== noErr
)
151 if ( isDirectory
== true )
153 /* Get the real vRefNum */
154 result
= DetermineVRefNum(name
, vRefNum
, &theVRefNum
);
155 if ( result
== noErr
)
157 /* Set up the globals we need to access from the recursive routine. */
158 theGlobals
.iterateFilter
= iterateFilter
;
159 theGlobals
.cPB
.hFileInfo
.ioNamePtr
= (StringPtr
)&theGlobals
.itemName
;
160 theGlobals
.cPB
.hFileInfo
.ioVRefNum
= theVRefNum
;
161 theGlobals
.itemName
[0] = 0;
162 theGlobals
.result
= noErr
;
163 theGlobals
.quitFlag
= false;
164 theGlobals
.maxLevels
= maxLevels
;
165 theGlobals
.currentLevel
= 0; /* start at level 0 */
166 theGlobals
.yourDataPtr
= yourDataPtr
;
168 /* Here we go into recursion land... */
169 IterateDirectoryLevel(theDirID
, &theGlobals
);
171 result
= theGlobals
.result
; /* set the result */
176 result
= dirNFErr
; /* a file was passed instead of a directory */
182 result
= paramErr
; /* iterateFilter was NULL */
188 /*****************************************************************************/
190 pascal OSErr
FSpIterateDirectory(const FSSpec
*spec
,
191 unsigned short maxLevels
,
192 IterateFilterProcPtr iterateFilter
,
195 return ( IterateDirectory(spec
->vRefNum
, spec
->parID
, spec
->name
,
196 maxLevels
, iterateFilter
, yourDataPtr
) );
199 /*****************************************************************************/