// recurse.c #include #include #include #include #include #include #include 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; ippatarray[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; ippatarray); 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; ippatarray[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 #include 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