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 /*****************************************************************************/