]> git.saurik.com Git - wxWidgets.git/blob - src/mac/morefile/IterateD.cpp
yet another file I added on the wxUniv branch and forgot to merge
[wxWidgets.git] / src / mac / morefile / IterateD.cpp
1 /*
2 ** IterateDirectory: File Manager directory iterator routines.
3 **
4 ** by Jim Luther
5 **
6 ** File: IterateDirectory.c
7 **
8 ** Copyright © 1995-1998 Jim Luther and Apple Computer, Inc.
9 ** All rights reserved.
10 **
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.
14 **
15 ** IterateDirectory is designed to drop into the MoreFiles sample code
16 ** library I wrote while in Apple Developer Technical Support
17 */
18
19 #include <Types.h>
20 #include <Errors.h>
21 #include <Files.h>
22
23 #define __COMPILINGMOREFILES
24
25 #include "moreextr.h"
26 #include "iterated.h"
27
28 /*
29 ** Type definitions
30 */
31
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.
35 */
36 #if PRAGMA_STRUCT_ALIGN
37 #pragma options align=mac68k
38 #elif PRAGMA_STRUCT_PACKPUSH
39 #pragma pack(push, 2)
40 #elif PRAGMA_STRUCT_PACK
41 #pragma pack(2)
42 #endif
43
44 struct IterateGlobals
45 {
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 */
54 };
55
56 #if PRAGMA_STRUCT_ALIGN
57 #pragma options align=reset
58 #elif PRAGMA_STRUCT_PACKPUSH
59 #pragma pack(pop)
60 #elif PRAGMA_STRUCT_PACK
61 #pragma pack()
62 #endif
63
64 typedef struct IterateGlobals IterateGlobals;
65 typedef IterateGlobals *IterateGlobalsPtr;
66
67 /*****************************************************************************/
68
69 /* Static Prototype */
70
71 static void IterateDirectoryLevel(long dirID,
72 IterateGlobals *theGlobals);
73
74 /*****************************************************************************/
75
76 /*
77 ** Functions
78 */
79
80 static void IterateDirectoryLevel(long dirID,
81 IterateGlobals *theGlobals)
82 {
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 */
85 {
86 short index = 1;
87
88 ++theGlobals->currentLevel; /* go to next level */
89
90 do
91 { /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
92
93 /* Get next source item at the current directory level */
94
95 theGlobals->cPB.dirInfo.ioFDirIndex = index;
96 theGlobals->cPB.dirInfo.ioDrDirID = dirID;
97 theGlobals->result = PBGetCatInfoSync((CInfoPBPtr)&theGlobals->cPB);
98
99 if ( theGlobals->result == noErr )
100 {
101 /* Call the IterateFilterProc */
102 CallIterateFilterProc(theGlobals->iterateFilter, &theGlobals->cPB, &theGlobals->quitFlag, theGlobals->yourDataPtr);
103
104 /* Is it a directory? */
105 if ( (theGlobals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
106 {
107 /* We have a directory */
108 if ( !theGlobals->quitFlag )
109 {
110 /* Dive again if the IterateFilterProc didn't say "quit" */
111 IterateDirectoryLevel(theGlobals->cPB.dirInfo.ioDrDirID, theGlobals);
112 }
113 }
114 }
115
116 ++index; /* prepare to get next item */
117 } while ( (theGlobals->result == noErr) && (!theGlobals->quitFlag) ); /* time to fall back a level? */
118
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 */
121 {
122 theGlobals->result = noErr;
123 }
124
125 --theGlobals->currentLevel; /* return to previous level as we leave */
126 }
127 }
128
129 /*****************************************************************************/
130
131 pascal OSErr IterateDirectory(short vRefNum,
132 long dirID,
133 ConstStr255Param name,
134 unsigned short maxLevels,
135 IterateFilterProcPtr iterateFilter,
136 void *yourDataPtr)
137 {
138 IterateGlobals theGlobals;
139 OSErr result;
140 long theDirID;
141 short theVRefNum;
142 Boolean isDirectory;
143
144 /* Make sure there is a IterateFilter */
145 if ( iterateFilter != NULL )
146 {
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 )
150 {
151 if ( isDirectory == true )
152 {
153 /* Get the real vRefNum */
154 result = DetermineVRefNum(name, vRefNum, &theVRefNum);
155 if ( result == noErr )
156 {
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;
167
168 /* Here we go into recursion land... */
169 IterateDirectoryLevel(theDirID, &theGlobals);
170
171 result = theGlobals.result; /* set the result */
172 }
173 }
174 else
175 {
176 result = dirNFErr; /* a file was passed instead of a directory */
177 }
178 }
179 }
180 else
181 {
182 result = paramErr; /* iterateFilter was NULL */
183 }
184
185 return ( result );
186 }
187
188 /*****************************************************************************/
189
190 pascal OSErr FSpIterateDirectory(const FSSpec *spec,
191 unsigned short maxLevels,
192 IterateFilterProcPtr iterateFilter,
193 void *yourDataPtr)
194 {
195 return ( IterateDirectory(spec->vRefNum, spec->parID, spec->name,
196 maxLevels, iterateFilter, yourDataPtr) );
197 }
198
199 /*****************************************************************************/