]> git.saurik.com Git - wxWidgets.git/blob - src/mac/classic/morefile/IterateDirectory.c
classic/carbon split
[wxWidgets.git] / src / mac / classic / morefile / IterateDirectory.c
1 /*
2 File: IterateDirectory.c
3
4 Contains: File Manager directory iterator routines.
5
6 Version: MoreFiles
7
8 Copyright: © 1995-2001 by Jim Luther and Apple Computer, Inc., all rights reserved.
9
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.
17
18 File Ownership:
19
20 DRI: Apple Macintosh Developer Technical Support
21
22 Other Contact: Apple Macintosh Developer Technical Support
23 <http://developer.apple.com/bugreporter/>
24
25 Technology: DTS Sample Code
26
27 Writers:
28
29 (JL) Jim Luther
30
31 Change History (most recent first):
32
33 <2> 2/7/01 JL Added standard header. Updated names of includes.
34 <1> 12/06/99 JL MoreFiles 1.5.
35 */
36
37 #include <MacTypes.h>
38 #include <MacErrors.h>
39 #include <Files.h>
40
41 #define __COMPILINGMOREFILES
42
43 #include "MoreFilesExtras.h"
44 #include "IterateDirectory.h"
45
46 /*
47 ** Type definitions
48 */
49
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.
53 */
54 #if PRAGMA_STRUCT_ALIGN
55 #pragma options align=mac68k
56 #endif
57 struct IterateGlobals
58 {
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 */
67 };
68 #if PRAGMA_STRUCT_ALIGN
69 #pragma options align=reset
70 #endif
71
72 typedef struct IterateGlobals IterateGlobals;
73 typedef IterateGlobals *IterateGlobalsPtr;
74
75 /*****************************************************************************/
76
77 /* Static Prototype */
78
79 static void IterateDirectoryLevel(long dirID,
80 IterateGlobals *theGlobals);
81
82 /*****************************************************************************/
83
84 /*
85 ** Functions
86 */
87
88 static void IterateDirectoryLevel(long dirID,
89 IterateGlobals *theGlobals)
90 {
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 */
93 {
94 short index = 1;
95
96 ++theGlobals->currentLevel; /* go to next level */
97
98 do
99 { /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
100
101 /* Get next source item at the current directory level */
102
103 theGlobals->cPB.dirInfo.ioFDirIndex = index;
104 theGlobals->cPB.dirInfo.ioDrDirID = dirID;
105 theGlobals->result = PBGetCatInfoSync((CInfoPBPtr)&theGlobals->cPB);
106
107 if ( theGlobals->result == noErr )
108 {
109 /* Call the IterateFilterProc */
110 CallIterateFilterProc(theGlobals->iterateFilter, &theGlobals->cPB, &theGlobals->quitFlag, theGlobals->yourDataPtr);
111
112 /* Is it a directory? */
113 if ( (theGlobals->cPB.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
114 {
115 /* We have a directory */
116 if ( !theGlobals->quitFlag )
117 {
118 /* Dive again if the IterateFilterProc didn't say "quit" */
119 IterateDirectoryLevel(theGlobals->cPB.dirInfo.ioDrDirID, theGlobals);
120 }
121 }
122 }
123
124 ++index; /* prepare to get next item */
125 } while ( (theGlobals->result == noErr) && (!theGlobals->quitFlag) ); /* time to fall back a level? */
126
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 */
129 {
130 theGlobals->result = noErr;
131 }
132
133 --theGlobals->currentLevel; /* return to previous level as we leave */
134 }
135 }
136
137 /*****************************************************************************/
138
139 pascal OSErr IterateDirectory(short vRefNum,
140 long dirID,
141 ConstStr255Param name,
142 unsigned short maxLevels,
143 IterateFilterProcPtr iterateFilter,
144 void *yourDataPtr)
145 {
146 IterateGlobals theGlobals;
147 OSErr result;
148 long theDirID;
149 short theVRefNum;
150 Boolean isDirectory;
151
152 /* Make sure there is a IterateFilter */
153 if ( iterateFilter != NULL )
154 {
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 )
158 {
159 if ( isDirectory == true )
160 {
161 /* Get the real vRefNum */
162 result = DetermineVRefNum(name, vRefNum, &theVRefNum);
163 if ( result == noErr )
164 {
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;
175
176 /* Here we go into recursion land... */
177 IterateDirectoryLevel(theDirID, &theGlobals);
178
179 result = theGlobals.result; /* set the result */
180 }
181 }
182 else
183 {
184 result = dirNFErr; /* a file was passed instead of a directory */
185 }
186 }
187 }
188 else
189 {
190 result = paramErr; /* iterateFilter was NULL */
191 }
192
193 return ( result );
194 }
195
196 /*****************************************************************************/
197
198 pascal OSErr FSpIterateDirectory(const FSSpec *spec,
199 unsigned short maxLevels,
200 IterateFilterProcPtr iterateFilter,
201 void *yourDataPtr)
202 {
203 return ( IterateDirectory(spec->vRefNum, spec->parID, spec->name,
204 maxLevels, iterateFilter, yourDataPtr) );
205 }
206
207 /*****************************************************************************/