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_STRUCT_ALIGN 
  37     #pragma options align=mac68k 
  38 #elif PRAGMA_STRUCT_PACKPUSH 
  40 #elif PRAGMA_STRUCT_PACK 
  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 */ 
  56 #if PRAGMA_STRUCT_ALIGN 
  57     #pragma options align=reset 
  58 #elif PRAGMA_STRUCT_PACKPUSH 
  60 #elif PRAGMA_STRUCT_PACK 
  64 typedef struct IterateGlobals IterateGlobals
; 
  65 typedef IterateGlobals 
*IterateGlobalsPtr
; 
  67 /*****************************************************************************/ 
  69 /*      Static Prototype */ 
  71 static  void    IterateDirectoryLevel(long dirID
, 
  72                                                                           IterateGlobals 
*theGlobals
); 
  74 /*****************************************************************************/ 
  80 static  void    IterateDirectoryLevel(long dirID
, 
  81                                                                           IterateGlobals 
*theGlobals
) 
  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 */ 
  88                 ++theGlobals
->currentLevel
;     /* go to next level */ 
  91                 {       /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */ 
  93                         /* Get next source item at the current directory level */ 
  95                         theGlobals
->cPB
.dirInfo
.ioFDirIndex 
= index
; 
  96                         theGlobals
->cPB
.dirInfo
.ioDrDirID 
= dirID
; 
  97                         theGlobals
->result 
= PBGetCatInfoSync((CInfoPBPtr
)&theGlobals
->cPB
);             
  99                         if ( theGlobals
->result 
== noErr 
) 
 101                                 /* Call the IterateFilterProc */ 
 102                                 CallIterateFilterProc(theGlobals
->iterateFilter
, &theGlobals
->cPB
, &theGlobals
->quitFlag
, theGlobals
->yourDataPtr
); 
 104                                 /* Is it a directory? */ 
 105                                 if ( (theGlobals
->cPB
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0 ) 
 107                                         /* We have a directory */ 
 108                                         if ( !theGlobals
->quitFlag 
) 
 110                                                 /* Dive again if the IterateFilterProc didn't say "quit" */ 
 111                                                 IterateDirectoryLevel(theGlobals
->cPB
.dirInfo
.ioDrDirID
, theGlobals
); 
 116                         ++index
; /* prepare to get next item */ 
 117                 } while ( (theGlobals
->result 
== noErr
) && (!theGlobals
->quitFlag
) ); /* time to fall back a level? */ 
 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 */ 
 122                         theGlobals
->result 
= noErr
; 
 125                 --theGlobals
->currentLevel
;     /* return to previous level as we leave */ 
 129 /*****************************************************************************/ 
 131 pascal  OSErr   
IterateDirectory(short vRefNum
, 
 133                                                                  ConstStr255Param name
, 
 134                                                                  unsigned short maxLevels
, 
 135                                                                  IterateFilterProcPtr iterateFilter
, 
 138         IterateGlobals  theGlobals
; 
 144         /* Make sure there is a IterateFilter */ 
 145         if ( iterateFilter 
!= NULL 
) 
 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 
) 
 151                         if ( isDirectory 
== true ) 
 153                                 /* Get the real vRefNum */ 
 154                                 result 
= DetermineVRefNum(name
, vRefNum
, &theVRefNum
); 
 155                                 if ( result 
== noErr 
) 
 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
; 
 168                                         /* Here we go into recursion land... */ 
 169                                         IterateDirectoryLevel(theDirID
, &theGlobals
); 
 171                                         result 
= theGlobals
.result
;     /* set the result */ 
 176                                 result 
= dirNFErr
;      /* a file was passed instead of a directory */ 
 182                 result 
= paramErr
;      /* iterateFilter was NULL */ 
 188 /*****************************************************************************/ 
 190 pascal  OSErr   
FSpIterateDirectory(const FSSpec 
*spec
, 
 191                                                                         unsigned short maxLevels
, 
 192                                                                         IterateFilterProcPtr iterateFilter
, 
 195         return ( IterateDirectory(spec
->vRefNum
, spec
->parID
, spec
->name
, 
 196                                                 maxLevels
, iterateFilter
, yourDataPtr
) ); 
 199 /*****************************************************************************/