254 lines
8.2 KiB
C
254 lines
8.2 KiB
C
|
// recurse.c
|
||
|
|
||
|
#include <ctype.h>
|
||
|
#include <direct.h>
|
||
|
#include <malloc.h>
|
||
|
#include <string.h>
|
||
|
#include <windows.h>
|
||
|
#include <assert.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
typedef struct patarray_s {
|
||
|
HANDLE hfind; // handle for FindFirstFile/FindNextFile
|
||
|
BOOLEAN find_next_file; // TRUE if FindNextFile is to be called
|
||
|
BOOLEAN IsDir; // TRUE if current found file is a dir
|
||
|
char szfile[MAX_PATH];// Name of file/dir found
|
||
|
} patarray_t;
|
||
|
|
||
|
typedef struct dirstack_s {
|
||
|
struct dirstack_s *next; // Next element in stack
|
||
|
struct dirstack_s *prev; // Previous element in stack
|
||
|
HANDLE hfind;
|
||
|
patarray_t *ppatarray; // pointer to an array of pattern records
|
||
|
char szdir[1]; // Directory name
|
||
|
} dirstack_t; // Directory stack
|
||
|
|
||
|
#define FA_ATTR(x) ((x).dwFileAttributes)
|
||
|
#define FA_CCHNAME(x) MAX_PATH
|
||
|
#define FA_NAME(x) ((x).cFileName)
|
||
|
#define FA_ALL (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
|
||
|
FILE_ATTRIBUTE_SYSTEM)
|
||
|
#define FA_DIR FILE_ATTRIBUTE_DIRECTORY
|
||
|
|
||
|
static dirstack_t *pdircur = NULL; // Current directory pointer
|
||
|
|
||
|
void
|
||
|
makename(
|
||
|
char *pszfile,
|
||
|
char *pszname
|
||
|
)
|
||
|
{
|
||
|
dirstack_t *pdir; // Directory stack pointer
|
||
|
|
||
|
*pszfile = '\0'; // Start with null string
|
||
|
pdir = pdircur; // Point at last entry
|
||
|
if (pdir->next != pdircur) { // If not only entry
|
||
|
do {
|
||
|
pdir = pdir->next; // Advance to next subdirectory
|
||
|
strcat(pszfile,pdir->szdir);// Add the subdirectory
|
||
|
} while (pdir != pdircur); // Do until current directory
|
||
|
} else
|
||
|
strcpy(pszfile, pdircur->szdir);
|
||
|
|
||
|
strcat(pszfile,pszname);
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
filematch(
|
||
|
char *pszfile,
|
||
|
char **ppszpat,
|
||
|
int cpat,
|
||
|
int fsubdirs
|
||
|
)
|
||
|
{
|
||
|
WIN32_FIND_DATA fi, fi2;
|
||
|
BOOL b;
|
||
|
int i;
|
||
|
dirstack_t *pdir;
|
||
|
patarray_t *pPatFind;
|
||
|
char drive[_MAX_DRIVE];
|
||
|
char dir[_MAX_DIR];
|
||
|
char fname[_MAX_FNAME];
|
||
|
char ext[_MAX_EXT];
|
||
|
|
||
|
assert(INVALID_HANDLE_VALUE != NULL);
|
||
|
|
||
|
if (pdircur == NULL) {
|
||
|
|
||
|
// If stack empty
|
||
|
if ((pdircur = (dirstack_t *) malloc(sizeof(dirstack_t)+MAX_PATH+1)) == NULL)
|
||
|
return(-1); // Fail if allocation fails
|
||
|
|
||
|
if ((pdircur->ppatarray =
|
||
|
(patarray_t *) malloc(sizeof(patarray_t)*cpat)) == NULL) {
|
||
|
free(pdircur);
|
||
|
return(-1);
|
||
|
}
|
||
|
pdircur->szdir[0] = '\0'; // Root has no name
|
||
|
pdircur->hfind = INVALID_HANDLE_VALUE; // No search handle yet
|
||
|
pdircur->next = pdircur->prev = pdircur; // Entry points to self
|
||
|
|
||
|
_splitpath(ppszpat[0], drive, dir, fname, ext);
|
||
|
|
||
|
strcpy(pdircur->szdir, drive);
|
||
|
strcat(pdircur->szdir, dir);
|
||
|
|
||
|
strcpy(ppszpat[0], fname);
|
||
|
strcat(ppszpat[0], ext);
|
||
|
|
||
|
for (i=1; i<cpat; i++) {
|
||
|
_splitpath(ppszpat[i], drive, dir, fname, ext);
|
||
|
strcpy(ppszpat[i], fname);
|
||
|
strcat(ppszpat[i], ext);
|
||
|
}
|
||
|
|
||
|
for (i=0; i<cpat; i++) {
|
||
|
pdircur->ppatarray[i].hfind = INVALID_HANDLE_VALUE;
|
||
|
pdircur->ppatarray[i].szfile[0] = '\0';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (pdircur != NULL) {
|
||
|
// While directories remain
|
||
|
|
||
|
b = TRUE;
|
||
|
|
||
|
if (pdircur->hfind == INVALID_HANDLE_VALUE) {
|
||
|
// If no handle yet
|
||
|
|
||
|
makename(pszfile,"*.*"); // Make search name
|
||
|
|
||
|
pdircur->hfind = FindFirstFile((LPSTR) pszfile,
|
||
|
(LPWIN32_FIND_DATA) &fi); // Find first matching entry
|
||
|
} else
|
||
|
|
||
|
b = FindNextFile(pdircur->hfind,
|
||
|
(LPWIN32_FIND_DATA) &fi); // Else find next matching entry
|
||
|
|
||
|
if (b == FALSE || pdircur->hfind == INVALID_HANDLE_VALUE) {
|
||
|
// If search fails
|
||
|
|
||
|
if (pdircur->hfind != INVALID_HANDLE_VALUE)
|
||
|
FindClose(pdircur->hfind);
|
||
|
pdir = pdircur; // Point at record to delete
|
||
|
if ((pdircur = pdir->prev) != pdir) {
|
||
|
// If no parent directory
|
||
|
|
||
|
pdircur->next = pdir->next; // Delete record from list
|
||
|
pdir->next->prev = pdircur;
|
||
|
} else
|
||
|
pdircur = NULL; // Else cause search to stop
|
||
|
|
||
|
pPatFind = pdir->ppatarray;
|
||
|
for (i=0; i<cpat; i++) {
|
||
|
if (pPatFind[i].hfind != NULL &&
|
||
|
pPatFind[i].hfind != INVALID_HANDLE_VALUE)
|
||
|
FindClose(pPatFind[i].hfind);
|
||
|
}
|
||
|
free(pdir->ppatarray);
|
||
|
free(pdir); // Free the record
|
||
|
continue; // Top of loop
|
||
|
}
|
||
|
|
||
|
|
||
|
if (FA_ATTR(fi) & FA_DIR) {
|
||
|
// If subdirectory found
|
||
|
|
||
|
if (fsubdirs &&
|
||
|
strcmp(FA_NAME(fi),".") != 0 && strcmp(FA_NAME(fi),"..") != 0 &&
|
||
|
(pdir = (dirstack_t *) malloc(sizeof(dirstack_t)+FA_CCHNAME(fi)+1)) != NULL)
|
||
|
{
|
||
|
if ((pdir->ppatarray =
|
||
|
(patarray_t *) malloc(sizeof(patarray_t)*cpat)) == NULL) {
|
||
|
free(pdir);
|
||
|
continue;
|
||
|
}
|
||
|
// If not "." nor ".." and alloc okay
|
||
|
|
||
|
strcpy(pdir->szdir,FA_NAME(fi)); // Copy name to buffer
|
||
|
strcat(pdir->szdir,"\\"); // Add trailing backslash
|
||
|
pdir->hfind = INVALID_HANDLE_VALUE; // No search handle yet
|
||
|
pdir->next = pdircur->next; // Insert entry in linked list
|
||
|
pdir->prev = pdircur;
|
||
|
for (i=0; i<cpat; i++) {
|
||
|
pdir->ppatarray[i].hfind = INVALID_HANDLE_VALUE;
|
||
|
pdir->ppatarray[i].szfile[0] = '\0';
|
||
|
}
|
||
|
pdircur->next = pdir;
|
||
|
pdir->next->prev = pdir;
|
||
|
pdircur = pdir; // Make new entry current
|
||
|
}
|
||
|
continue; // Top of loop
|
||
|
}
|
||
|
|
||
|
pPatFind = pdircur->ppatarray;
|
||
|
for (i = cpat; i-- > 0; ) {
|
||
|
// Loop to see if we care
|
||
|
b = (pPatFind[i].hfind != NULL);
|
||
|
for (;;) {
|
||
|
if (pPatFind[i].hfind == INVALID_HANDLE_VALUE) {
|
||
|
makename(pszfile, ppszpat[i]);
|
||
|
pPatFind[i].hfind = FindFirstFile(pszfile, &fi2);
|
||
|
b = (pPatFind[i].hfind != INVALID_HANDLE_VALUE);
|
||
|
pPatFind[i].find_next_file = FALSE;
|
||
|
if (b) {
|
||
|
strcpy(pPatFind[i].szfile, FA_NAME(fi2));
|
||
|
pPatFind[i].IsDir = (BOOLEAN)(FA_ATTR(fi2) & FA_DIR);
|
||
|
}
|
||
|
} else if (pPatFind[i].find_next_file) {
|
||
|
b = FindNextFile(pPatFind[i].hfind, &fi2);
|
||
|
pPatFind[i].find_next_file = FALSE;
|
||
|
if (b) {
|
||
|
strcpy(pPatFind[i].szfile, FA_NAME(fi2));
|
||
|
pPatFind[i].IsDir = (BOOLEAN)(FA_ATTR(fi2) & FA_DIR);
|
||
|
}
|
||
|
}
|
||
|
if (b) {
|
||
|
if (pPatFind[i].IsDir) {
|
||
|
pPatFind[i].find_next_file = TRUE;
|
||
|
} else
|
||
|
break; // found a file to do matching
|
||
|
} else {
|
||
|
if (pPatFind[i].hfind != NULL &&
|
||
|
pPatFind[i].hfind != INVALID_HANDLE_VALUE) {
|
||
|
FindClose(pPatFind[i].hfind);
|
||
|
pPatFind[i].hfind = NULL;
|
||
|
}
|
||
|
pPatFind[i].find_next_file = FALSE;
|
||
|
break; // exhausted all entries
|
||
|
}
|
||
|
} // for
|
||
|
|
||
|
if (b) {
|
||
|
if (strcmp(FA_NAME(fi), pPatFind[i].szfile) == 0) {
|
||
|
pPatFind[i].find_next_file = TRUE;
|
||
|
makename(pszfile, FA_NAME(fi));
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return(-1); // No match found
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef TEST
|
||
|
#include <process.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
void
|
||
|
main(
|
||
|
int carg,
|
||
|
char **ppszarg
|
||
|
)
|
||
|
{
|
||
|
char szfile[MAX_PATH]; // if OS2: CCHPATHMAX];
|
||
|
|
||
|
while (filematch(szfile,ppszarg,carg) >= 0)
|
||
|
printf("%s\n",szfile);
|
||
|
exit(0);
|
||
|
}
|
||
|
#endif
|