// // dirent.h - dirent API for Microsoft Visual Studio // // Copyright (C) 2006 Toni Ronkko // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // ``Software''), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // // Jan 18, 2008, Toni Ronkko // Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string // between multi-byte and unicode representations. This makes the // code simpler and also allows the code to be compiled under MingW. Thanks // to Azriel Fasten for the suggestion. // // Mar 4, 2007, Toni Ronkko // Bug fix: due to the strncpy_s() function this file only compiled in // Visual Studio 2005. Using the new string functions only when the // compiler version allows. // // Nov 2, 2006, Toni Ronkko // Major update: removed support for Watcom C, MS-DOS and Turbo C to // simplify the file, updated the code to compile cleanly on Visual // Studio 2005 with both unicode and multi-byte character strings, // removed rewinddir() as it had a bug. // // Aug 20, 2006, Toni Ronkko // Removed all remarks about MSVC 1.0, which is antiqued now. Simplified // comments by removing SGML tags. // // May 14 2002, Toni Ronkko // Embedded the function definitions directly to the header so that no // source modules need to be included in the Visual Studio project. Removed // all the dependencies to other projects so that this very header can be // used independently. // // May 28 1998, Toni Ronkko // First version. // #ifndef DIRENT_H #define DIRENT_H #include #include #include typedef struct dirent { // name of current directory entry (a multi-byte character string) char d_name[MAX_PATH + 1]; // file attributes WIN32_FIND_DATAA data; } dirent; typedef struct DIR { // current directory entry dirent current; // is there an un-processed entry in current? int cached; // file search handle HANDLE search_handle; // search pattern (3 = zero terminator + pattern "\\*") char patt[MAX_PATH + 3]; } DIR; static DIR *opendir( const char *dirname ); static struct dirent *readdir( DIR *dirp ); static int closedir( DIR *dirp ); // use the new safe string functions introduced in Visual Studio 2005 #if defined ( _MSC_VER ) && _MSC_VER >= 1400 # define STRNCPY( dest, src, size ) strncpy_s( ( dest ), ( size ), ( src ), _TRUNCATE ) #else # define STRNCPY( dest, src, size ) strncpy( ( dest ), ( src ), ( size ) ) #endif // // Open directory stream DIRNAME for read and return a pointer to the // internal working area that is used to retrieve individual directory // entries. // static DIR* opendir( const char *dirname ) { DIR *dirp; assert( dirname != NULL ); assert( strlen( dirname ) < MAX_PATH ); // construct new DIR structure dirp = (DIR *) malloc( sizeof ( struct DIR ) ); if ( dirp != NULL ) { char *p; // take directory name... STRNCPY( dirp->patt, dirname, sizeof ( dirp->patt ) ); dirp->patt[MAX_PATH] = '\0'; // ... and append search pattern to it p = strchr( dirp->patt, '\0' ); if ( dirp->patt < p && *( p - 1 ) != '\\' && *( p - 1 ) != ':' ) { *p++ = '\\'; } *p++ = '*'; *p = '\0'; // open stream and retrieve first file dirp->search_handle = FindFirstFileA( dirp->patt, &dirp->current.data ); if ( dirp->search_handle == INVALID_HANDLE_VALUE ) { // invalid search pattern? free( dirp ); return NULL; } // there is an un-processed directory entry in memory now dirp->cached = 1; } return dirp; } // // Read a directory entry, and return a pointer to a dirent structure // containing the name of the entry in d_name field. Individual directory // entries returned by this very function include regular files, // sub-directories, pseudo-directories "." and "..", but also volume labels, // hidden files and system files may be returned. // static struct dirent * readdir( DIR *dirp ) { assert( dirp != NULL ); if ( dirp->search_handle == INVALID_HANDLE_VALUE ) { // directory stream was opened/rewound incorrectly or it ended normally return NULL; } // get next directory entry if ( dirp->cached != 0 ) { // a valid directory entry already in memory dirp->cached = 0; } else { // read next directory entry from disk if ( FindNextFileA( dirp->search_handle, &dirp->current.data ) == FALSE ) { // the very last file has been processed or an error occured FindClose( dirp->search_handle ); dirp->search_handle = INVALID_HANDLE_VALUE; return NULL; } } // copy as a multibyte character string STRNCPY( dirp->current.d_name, dirp->current.data.cFileName, sizeof ( dirp->current.d_name ) ); dirp->current.d_name[MAX_PATH] = '\0'; return &dirp->current; } // // Close directory stream opened by opendir() function. Close of the // directory stream invalidates the DIR structure as well as any previously // read directory entry. // static int closedir( DIR *dirp ) { assert( dirp != NULL ); // release search handle if ( dirp->search_handle != INVALID_HANDLE_VALUE ) { FindClose( dirp->search_handle ); dirp->search_handle = INVALID_HANDLE_VALUE; } // release directory handle free( dirp ); return 0; } #endif //DIRENT_H