00001 /***************************************************************************** 00002 * dirent.h - dirent API for Microsoft Visual Studio 00003 * 00004 * Copyright (C) 2006 Toni Ronkko 00005 * 00006 * Permission is hereby granted, free of charge, to any person obtaining 00007 * a copy of this software and associated documentation files (the 00008 * ``Software''), to deal in the Software without restriction, including 00009 * without limitation the rights to use, copy, modify, merge, publish, 00010 * distribute, sublicense, and/or sell copies of the Software, and to 00011 * permit persons to whom the Software is furnished to do so, subject to 00012 * the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included 00015 * in all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS 00018 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00020 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR 00021 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00022 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00023 * OTHER DEALINGS IN THE SOFTWARE. 00024 * 00025 * Dec 15, 2009, John Cunningham 00026 * Added rewinddir member function 00027 * 00028 * Jan 18, 2008, Toni Ronkko 00029 * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string 00030 * between multi-byte and unicode representations. This makes the 00031 * code simpler and also allows the code to be compiled under MingW. Thanks 00032 * to Azriel Fasten for the suggestion. 00033 * 00034 * Mar 4, 2007, Toni Ronkko 00035 * Bug fix: due to the strncpy_s() function this file only compiled in 00036 * Visual Studio 2005. Using the new string functions only when the 00037 * compiler version allows. 00038 * 00039 * Nov 2, 2006, Toni Ronkko 00040 * Major update: removed support for Watcom C, MS-DOS and Turbo C to 00041 * simplify the file, updated the code to compile cleanly on Visual 00042 * Studio 2005 with both unicode and multi-byte character strings, 00043 * removed rewinddir() as it had a bug. 00044 * 00045 * Aug 20, 2006, Toni Ronkko 00046 * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified 00047 * comments by removing SGML tags. 00048 * 00049 * May 14 2002, Toni Ronkko 00050 * Embedded the function definitions directly to the header so that no 00051 * source modules need to be included in the Visual Studio project. Removed 00052 * all the dependencies to other projects so that this very header can be 00053 * used independently. 00054 * 00055 * May 28 1998, Toni Ronkko 00056 * First version. 00057 *****************************************************************************/ 00058 #ifndef DIRENT_H 00059 #define DIRENT_H 00060 00061 #include <windows.h> 00062 #include <string.h> 00063 #include <assert.h> 00064 00065 00066 typedef struct dirent 00067 { 00068 char d_name[MAX_PATH + 1]; /* current dir entry (multi-byte char string) */ 00069 WIN32_FIND_DATAA data; /* file attributes */ 00070 } dirent; 00071 00072 00073 typedef struct DIR 00074 { 00075 dirent current; /* Current directory entry */ 00076 int cached; /* Indicates un-processed entry in memory */ 00077 HANDLE search_handle; /* File search handle */ 00078 char patt[MAX_PATH + 3]; /* search pattern (3 = pattern + "\\*\0") */ 00079 } DIR; 00080 00081 00082 /* Forward declarations */ 00083 static DIR *opendir (const char *dirname); 00084 static struct dirent *readdir (DIR *dirp); 00085 static int closedir (DIR *dirp); 00086 static void rewinddir(DIR* dirp); 00087 00088 00089 /* Use the new safe string functions introduced in Visual Studio 2005 */ 00090 #if defined(_MSC_VER) && _MSC_VER >= 1400 00091 # define STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE) 00092 #else 00093 # define STRNCPY(dest,src,size) strncpy((dest),(src),(size)) 00094 #endif 00095 00096 00097 /***************************************************************************** 00098 * Open directory stream DIRNAME for read and return a pointer to the 00099 * internal working area that is used to retrieve individual directory 00100 * entries. 00101 */ 00102 static DIR *opendir(const char *dirname) 00103 { 00104 DIR *dirp; 00105 assert (dirname != NULL); 00106 assert (strlen (dirname) < MAX_PATH); 00107 00108 /* construct new DIR structure */ 00109 dirp = (DIR*) malloc (sizeof (struct DIR)); 00110 if (dirp != NULL) { 00111 char *p; 00112 00113 /* take directory name... */ 00114 STRNCPY (dirp->patt, dirname, sizeof(dirp->patt)); 00115 dirp->patt[MAX_PATH] = '\0'; 00116 00117 /* ... and append search pattern to it */ 00118 p = strchr (dirp->patt, '\0'); 00119 if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') { 00120 *p++ = '\\'; 00121 } 00122 *p++ = '*'; 00123 *p = '\0'; 00124 00125 /* open stream and retrieve first file */ 00126 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data); 00127 if (dirp->search_handle == INVALID_HANDLE_VALUE) { 00128 /* invalid search pattern? */ 00129 free (dirp); 00130 return NULL; 00131 } 00132 00133 /* there is an un-processed directory entry in memory now */ 00134 dirp->cached = 1; 00135 } 00136 00137 return dirp; 00138 } 00139 00140 00141 /***************************************************************************** 00142 * Read a directory entry, and return a pointer to a dirent structure 00143 * containing the name of the entry in d_name field. Individual directory 00144 * entries returned by this very function include regular files, 00145 * sub-directories, pseudo-directories "." and "..", but also volume labels, 00146 * hidden files and system files may be returned. 00147 */ 00148 static struct dirent *readdir(DIR *dirp) 00149 { 00150 assert (dirp != NULL); 00151 00152 if (dirp->search_handle == INVALID_HANDLE_VALUE) { 00153 /* directory stream was opened/rewound incorrectly or ended normally */ 00154 return NULL; 00155 } 00156 00157 /* get next directory entry */ 00158 if (dirp->cached != 0) { 00159 /* a valid directory entry already in memory */ 00160 dirp->cached = 0; 00161 } else { 00162 /* read next directory entry from disk */ 00163 if (FindNextFileA (dirp->search_handle, &dirp->current.data) == FALSE) { 00164 /* the very last file has been processed or an error occured */ 00165 FindClose (dirp->search_handle); 00166 dirp->search_handle = INVALID_HANDLE_VALUE; 00167 return NULL; 00168 } 00169 } 00170 00171 /* copy as a multibyte character string */ 00172 STRNCPY ( dirp->current.d_name, 00173 dirp->current.data.cFileName, 00174 sizeof(dirp->current.d_name) ); 00175 dirp->current.d_name[MAX_PATH] = '\0'; 00176 00177 return &dirp->current; 00178 } 00179 00180 00181 /***************************************************************************** 00182 * Close directory stream opened by opendir() function. Close of the 00183 * directory stream invalidates the DIR structure as well as any previously 00184 * read directory entry. 00185 */ 00186 static int closedir(DIR *dirp) 00187 { 00188 assert (dirp != NULL); 00189 00190 /* release search handle */ 00191 if (dirp->search_handle != INVALID_HANDLE_VALUE) { 00192 FindClose (dirp->search_handle); 00193 dirp->search_handle = INVALID_HANDLE_VALUE; 00194 } 00195 00196 /* release directory handle */ 00197 free (dirp); 00198 return 0; 00199 } 00200 00201 00202 /***************************************************************************** 00203 * Resets the position of the directory stream to which dirp refers to the 00204 * beginning of the directory. It also causes the directory stream to refer 00205 * to the current state of the corresponding directory, as a call to opendir() 00206 * would have done. If dirp does not refer to a directory stream, the effect 00207 * is undefined. 00208 */ 00209 static void rewinddir(DIR* dirp) 00210 { 00211 /* release search handle */ 00212 if (dirp->search_handle != INVALID_HANDLE_VALUE) { 00213 FindClose (dirp->search_handle); 00214 dirp->search_handle = INVALID_HANDLE_VALUE; 00215 } 00216 00217 /* open new search handle and retrieve first file */ 00218 dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->current.data); 00219 if (dirp->search_handle == INVALID_HANDLE_VALUE) { 00220 /* invalid search pattern? */ 00221 free (dirp); 00222 return; 00223 } 00224 00225 /* there is an un-processed directory entry in memory now */ 00226 dirp->cached = 1; 00227 } 00228 00229 00230 #endif /*DIRENT_H*/