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 57struct 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 72typedef struct IterateGlobals IterateGlobals; 73typedef IterateGlobals *IterateGlobalsPtr; 74 75/*****************************************************************************/ 76 77/* Static Prototype */ 78 79static void IterateDirectoryLevel(long dirID, 80 IterateGlobals *theGlobals); 81 82/*****************************************************************************/ 83 84/* 85** Functions 86*/ 87 88static 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 139pascal 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 198pascal 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/*****************************************************************************/ 208