ResKnife/External/MoreFiles/IterateDirectory.c
2002-03-29 14:59:03 +00:00

1 line
6.3 KiB
C
Executable File

/*
File: IterateDirectory.c
Contains: File Manager directory iterator routines.
Version: MoreFiles
Copyright: © 1995-2001 by Jim Luther and Apple Computer, Inc., all rights reserved.
You may incorporate this sample code into your applications without
restriction, though the sample code has been provided "AS IS" and the
responsibility for its operation is 100% yours. However, what you are
not permitted to do is to redistribute the source as "DSC Sample Code"
after having made changes. If you're going to re-distribute the source,
we require that you make it clear in the source that the code was
descended from Apple Sample Code, but that you've made changes.
File Ownership:
DRI: Apple Macintosh Developer Technical Support
Other Contact: Apple Macintosh Developer Technical Support
<http://developer.apple.com/bugreporter/>
Technology: DTS Sample Code
Writers:
(JL) Jim Luther
Change History (most recent first):
<2> 2/7/01 JL Added standard header. Updated names of includes.
<1> 12/06/99 JL MoreFiles 1.5.
*/
#include <MacTypes.h>
#include <MacErrors.h>
#include <Files.h>
#define __COMPILINGMOREFILES
#include "MoreFilesExtras.h"
#include "IterateDirectory.h"
/*
** Type definitions
*/
/* The IterateGlobals structure is used to minimize the amount of
** stack space used when recursively calling IterateDirectoryLevel
** and to hold global information that might be needed at any time.
*/
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#endif
struct IterateGlobals
{
IterateFilterProcPtr iterateFilter; /* pointer to IterateFilterProc */
CInfoPBRec cPB; /* the parameter block used for PBGetCatInfo calls */
Str63 itemName; /* the name of the current item */
OSErr result; /* temporary holder of results - saves 2 bytes of stack each level */
Boolean quitFlag; /* set to true if filter wants to kill interation */
unsigned short maxLevels; /* Maximum levels to iterate through */
unsigned short currentLevel; /* The current level IterateLevel is on */
void *yourDataPtr; /* A pointer to caller data the filter may need to access */
};
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#endif
typedef struct IterateGlobals IterateGlobals;
typedef IterateGlobals *IterateGlobalsPtr;
/*****************************************************************************/
/* Static Prototype */
static void IterateDirectoryLevel(long dirID,
IterateGlobals *theGlobals);
/*****************************************************************************/
/*
** Functions
*/
static void IterateDirectoryLevel(long dirID,
IterateGlobals *theGlobals)
{
if ( (theGlobals->maxLevels == 0) || /* if maxLevels is zero, we aren't checking levels */
(theGlobals->currentLevel < theGlobals->maxLevels) ) /* if currentLevel < maxLevels, look at this level */
{
short index = 1;
++theGlobals->currentLevel; /* go to next level */
do
{ /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
/* Get next source item at the current directory level */
theGlobals->cPB.dirInfo.ioFDirIndex = index;
theGlobals->cPB.dirInfo.ioDrDirID = dirID;
theGlobals->result = PBGetCatInfoSync((CInfoPBPtr)&theGlobals->cPB);
if ( theGlobals->result == noErr )
{
/* Call the IterateFilterProc */
CallIterateFilterProc(theGlobals->iterateFilter, &theGlobals->cPB, &theGlobals->quitFlag, theGlobals->yourDataPtr);
/* Is it a directory? */
if ( (theGlobals->cPB.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
{
/* We have a directory */
if ( !theGlobals->quitFlag )
{
/* Dive again if the IterateFilterProc didn't say "quit" */
IterateDirectoryLevel(theGlobals->cPB.dirInfo.ioDrDirID, theGlobals);
}
}
}
++index; /* prepare to get next item */
} while ( (theGlobals->result == noErr) && (!theGlobals->quitFlag) ); /* time to fall back a level? */
if ( (theGlobals->result == fnfErr) || /* fnfErr is OK - it only means we hit the end of this level */
(theGlobals->result == afpAccessDenied) ) /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
{
theGlobals->result = noErr;
}
--theGlobals->currentLevel; /* return to previous level as we leave */
}
}
/*****************************************************************************/
pascal OSErr IterateDirectory(short vRefNum,
long dirID,
ConstStr255Param name,
unsigned short maxLevels,
IterateFilterProcPtr iterateFilter,
void *yourDataPtr)
{
IterateGlobals theGlobals;
OSErr result;
long theDirID;
short theVRefNum;
Boolean isDirectory;
/* Make sure there is a IterateFilter */
if ( iterateFilter != NULL )
{
/* Get the real directory ID and make sure it is a directory */
result = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory);
if ( result == noErr )
{
if ( isDirectory == true )
{
/* Get the real vRefNum */
result = DetermineVRefNum(name, vRefNum, &theVRefNum);
if ( result == noErr )
{
/* Set up the globals we need to access from the recursive routine. */
theGlobals.iterateFilter = iterateFilter;
theGlobals.cPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName;
theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
theGlobals.itemName[0] = 0;
theGlobals.result = noErr;
theGlobals.quitFlag = false;
theGlobals.maxLevels = maxLevels;
theGlobals.currentLevel = 0; /* start at level 0 */
theGlobals.yourDataPtr = yourDataPtr;
/* Here we go into recursion land... */
IterateDirectoryLevel(theDirID, &theGlobals);
result = theGlobals.result; /* set the result */
}
}
else
{
result = dirNFErr; /* a file was passed instead of a directory */
}
}
}
else
{
result = paramErr; /* iterateFilter was NULL */
}
return ( result );
}
/*****************************************************************************/
pascal OSErr FSpIterateDirectory(const FSSpec *spec,
unsigned short maxLevels,
IterateFilterProcPtr iterateFilter,
void *yourDataPtr)
{
return ( IterateDirectory(spec->vRefNum, spec->parID, spec->name,
maxLevels, iterateFilter, yourDataPtr) );
}
/*****************************************************************************/