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_ALIGN_SUPPORTED 
  37 #pragma options align=mac68k 
  41         IterateFilterProcPtr    iterateFilter
;  /* pointer to IterateFilterProc */ 
  42         CInfoPBRec                              cPB
;                    /* the parameter block used for PBGetCatInfo calls */ 
  43         Str63                                   itemName
;               /* the name of the current item */ 
  44         OSErr                                   result
;                 /* temporary holder of results - saves 2 bytes of stack each level */ 
  45         Boolean                                 quitFlag
;               /* set to true if filter wants to kill interation */ 
  46         unsigned short                  maxLevels
;              /* Maximum levels to iterate through */ 
  47         unsigned short                  currentLevel
;   /* The current level IterateLevel is on */ 
  48         void                                    *yourDataPtr
;   /* A pointer to caller data the filter may need to access */ 
  50 #if PRAGMA_ALIGN_SUPPORTED 
  51 #pragma options align=reset 
  54 typedef struct IterateGlobals IterateGlobals
; 
  55 typedef IterateGlobals 
*IterateGlobalsPtr
; 
  57 /*****************************************************************************/ 
  59 /*      Static Prototype */ 
  61 static  void    IterateDirectoryLevel(long dirID
, 
  62                                                                           IterateGlobals 
*theGlobals
); 
  64 /*****************************************************************************/ 
  70 static  void    IterateDirectoryLevel(long dirID
, 
  71                                                                           IterateGlobals 
*theGlobals
) 
  73         if ( (theGlobals
->maxLevels 
== 0) ||                                            /* if maxLevels is zero, we aren't checking levels */ 
  74                  (theGlobals
->currentLevel 
< theGlobals
->maxLevels
) )   /* if currentLevel < maxLevels, look at this level */ 
  78                 ++theGlobals
->currentLevel
;     /* go to next level */ 
  81                 {       /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */ 
  83                         /* Get next source item at the current directory level */ 
  85                         theGlobals
->cPB
.dirInfo
.ioFDirIndex 
= index
; 
  86                         theGlobals
->cPB
.dirInfo
.ioDrDirID 
= dirID
; 
  87                         theGlobals
->result 
= PBGetCatInfoSync((CInfoPBPtr
)&theGlobals
->cPB
);             
  89                         if ( theGlobals
->result 
== noErr 
) 
  91                                 /* Call the IterateFilterProc */ 
  92                                 CallIterateFilterProc(theGlobals
->iterateFilter
, &theGlobals
->cPB
, &theGlobals
->quitFlag
, theGlobals
->yourDataPtr
); 
  94                                 /* Is it a directory? */ 
  95                                 if ( (theGlobals
->cPB
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0 ) 
  97                                         /* We have a directory */ 
  98                                         if ( !theGlobals
->quitFlag 
) 
 100                                                 /* Dive again if the IterateFilterProc didn't say "quit" */ 
 101                                                 IterateDirectoryLevel(theGlobals
->cPB
.dirInfo
.ioDrDirID
, theGlobals
); 
 106                         ++index
; /* prepare to get next item */ 
 107                 } while ( (theGlobals
->result 
== noErr
) && (!theGlobals
->quitFlag
) ); /* time to fall back a level? */ 
 109                 if ( (theGlobals
->result 
== fnfErr
) ||  /* fnfErr is OK - it only means we hit the end of this level */ 
 110                          (theGlobals
->result 
== afpAccessDenied
) ) /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */ 
 112                         theGlobals
->result 
= noErr
; 
 115                 --theGlobals
->currentLevel
;     /* return to previous level as we leave */ 
 119 /*****************************************************************************/ 
 121 pascal  OSErr   
IterateDirectory(short vRefNum
, 
 123                                                                  ConstStr255Param name
, 
 124                                                                  unsigned short maxLevels
, 
 125                                                                  IterateFilterProcPtr iterateFilter
, 
 128         IterateGlobals  theGlobals
; 
 134         /* Make sure there is a IterateFilter */ 
 135         if ( iterateFilter 
!= NULL 
) 
 137                 /* Get the real directory ID and make sure it is a directory */ 
 138                 result 
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
); 
 139                 if ( result 
== noErr 
) 
 141                         if ( isDirectory 
== true ) 
 143                                 /* Get the real vRefNum */ 
 144                                 result 
= DetermineVRefNum(name
, vRefNum
, &theVRefNum
); 
 145                                 if ( result 
== noErr 
) 
 147                                         /* Set up the globals we need to access from the recursive routine. */ 
 148                                         theGlobals
.iterateFilter 
= iterateFilter
; 
 149                                         theGlobals
.cPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)&theGlobals
.itemName
; 
 150                                         theGlobals
.cPB
.hFileInfo
.ioVRefNum 
= theVRefNum
; 
 151                                         theGlobals
.itemName
[0] = 0; 
 152                                         theGlobals
.result 
= noErr
; 
 153                                         theGlobals
.quitFlag 
= false; 
 154                                         theGlobals
.maxLevels 
= maxLevels
; 
 155                                         theGlobals
.currentLevel 
= 0;    /* start at level 0 */ 
 156                                         theGlobals
.yourDataPtr 
= yourDataPtr
; 
 158                                         /* Here we go into recursion land... */ 
 159                                         IterateDirectoryLevel(theDirID
, &theGlobals
); 
 161                                         result 
= theGlobals
.result
;     /* set the result */ 
 166                                 result 
= dirNFErr
;      /* a file was passed instead of a directory */ 
 172                 result 
= paramErr
;      /* iterateFilter was NULL */ 
 178 /*****************************************************************************/ 
 180 pascal  OSErr   
FSpIterateDirectory(const FSSpec 
*spec
, 
 181                                                                         unsigned short maxLevels
, 
 182                                                                         IterateFilterProcPtr iterateFilter
, 
 185         return ( IterateDirectory(spec
->vRefNum
, spec
->parID
, spec
->name
, 
 186                                                 maxLevels
, iterateFilter
, yourDataPtr
) ); 
 189 /*****************************************************************************/