Fossil SCM
type integrate latest version of dirent.h
Commit
8e50ff0c303872249114df3fd71f4ac4f0256d48
Parent
d5261ae5f0ce74c…
2 files changed
+1
-1
+398
-204
+1
-1
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -1144,11 +1144,11 @@ | ||
| 1144 | 1144 | } |
| 1145 | 1145 | |
| 1146 | 1146 | /* So that older versions of Fossil (that do not understand delta- |
| 1147 | 1147 | ** manifest) can continue to use this repository, do not create a new |
| 1148 | 1148 | ** delta-manifest unless this repository already contains one or more |
| 1149 | - ** delta-manifets, or unless the delta-manifest is explicitly requested | |
| 1149 | + ** delta-manifests, or unless the delta-manifest is explicitly requested | |
| 1150 | 1150 | ** by the --delta option. |
| 1151 | 1151 | */ |
| 1152 | 1152 | if( !forceDelta && !db_get_boolean("seen-delta-manifest",0) ){ |
| 1153 | 1153 | forceBaseline = 1; |
| 1154 | 1154 | } |
| 1155 | 1155 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1144,11 +1144,11 @@ | |
| 1144 | } |
| 1145 | |
| 1146 | /* So that older versions of Fossil (that do not understand delta- |
| 1147 | ** manifest) can continue to use this repository, do not create a new |
| 1148 | ** delta-manifest unless this repository already contains one or more |
| 1149 | ** delta-manifets, or unless the delta-manifest is explicitly requested |
| 1150 | ** by the --delta option. |
| 1151 | */ |
| 1152 | if( !forceDelta && !db_get_boolean("seen-delta-manifest",0) ){ |
| 1153 | forceBaseline = 1; |
| 1154 | } |
| 1155 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1144,11 +1144,11 @@ | |
| 1144 | } |
| 1145 | |
| 1146 | /* So that older versions of Fossil (that do not understand delta- |
| 1147 | ** manifest) can continue to use this repository, do not create a new |
| 1148 | ** delta-manifest unless this repository already contains one or more |
| 1149 | ** delta-manifests, or unless the delta-manifest is explicitly requested |
| 1150 | ** by the --delta option. |
| 1151 | */ |
| 1152 | if( !forceDelta && !db_get_boolean("seen-delta-manifest",0) ){ |
| 1153 | forceBaseline = 1; |
| 1154 | } |
| 1155 |
+398
-204
| --- win/include/dirent.h | ||
| +++ win/include/dirent.h | ||
| @@ -20,21 +20,24 @@ | ||
| 20 | 20 | * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 21 | 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 22 | 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 23 | 23 | * OTHER DEALINGS IN THE SOFTWARE. |
| 24 | 24 | * |
| 25 | + * | |
| 26 | + * Version 1.13, Dec 12 2012, Toni Ronkko | |
| 27 | + * Use traditional 8+3 file name if the name cannot be represented in the | |
| 28 | + * default ANSI code page. Now compiles again with MSVC 6.0. Thanks to | |
| 29 | + * Konstantin Khomoutov for testing. | |
| 25 | 30 | * |
| 26 | 31 | * Version 1.12.1, Oct 1 2012, Toni Ronkko |
| 27 | 32 | * Bug fix: renamed wide-character DIR structure _wDIR to _WDIR (with |
| 28 | 33 | * capital W) in order to maintain compatibility with MingW. |
| 29 | 34 | * |
| 30 | 35 | * Version 1.12, Sep 30 2012, Toni Ronkko |
| 31 | - * Define PATH_MAX and NAME_MAX. | |
| 32 | - * | |
| 33 | - * Added wide-character variants _wDIR, _wdirent, _wopendir(), | |
| 34 | - * _wreaddir(), _wclosedir() and _wrewinddir(). Thanks to Edgar Buerkle | |
| 35 | - * and Jan Nijtmans for ideas and code. | |
| 36 | + * Define PATH_MAX and NAME_MAX. Added wide-character variants _wDIR, | |
| 37 | + * _wdirent, _wopendir(), _wreaddir(), _wclosedir() and _wrewinddir(). | |
| 38 | + * Thanks to Edgar Buerkle and Jan Nijtmans for ideas and code. | |
| 36 | 39 | * |
| 37 | 40 | * Do not include windows.h. This allows dirent.h to be integrated more |
| 38 | 41 | * easily into programs using winsock. Thanks to Fernando Azaldegui. |
| 39 | 42 | * |
| 40 | 43 | * Version 1.11, Mar 15, 2011, Toni Ronkko |
| @@ -88,48 +91,72 @@ | ||
| 88 | 91 | *****************************************************************************/ |
| 89 | 92 | #ifndef DIRENT_H |
| 90 | 93 | #define DIRENT_H |
| 91 | 94 | |
| 92 | 95 | #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) |
| 93 | -#define _X86_ | |
| 96 | +# define _X86_ | |
| 94 | 97 | #endif |
| 95 | 98 | #include <stdio.h> |
| 96 | 99 | #include <stdarg.h> |
| 97 | 100 | #include <windef.h> |
| 98 | 101 | #include <winbase.h> |
| 99 | 102 | #include <wchar.h> |
| 100 | -#include <winnls.h> | |
| 101 | 103 | #include <string.h> |
| 102 | 104 | #include <stdlib.h> |
| 105 | +#include <malloc.h> | |
| 103 | 106 | #include <sys/types.h> |
| 104 | 107 | #include <sys/stat.h> |
| 105 | 108 | #include <errno.h> |
| 106 | 109 | |
| 107 | -/* Windows 8 wide-character string functions */ | |
| 108 | -#if (_WIN32_WINNT >= 0x0602) | |
| 109 | -# include <stringapiset.h> | |
| 110 | -#endif | |
| 110 | +/* Indicates that d_type field is available in dirent structure */ | |
| 111 | +#define _DIRENT_HAVE_D_TYPE | |
| 112 | + | |
| 113 | +/* Indicates that d_namlen field is available in dirent structure */ | |
| 114 | +#define _DIRENT_HAVE_D_NAMLEN | |
| 111 | 115 | |
| 112 | 116 | /* Entries missing from MSVC 6.0 */ |
| 113 | 117 | #if !defined(FILE_ATTRIBUTE_DEVICE) |
| 114 | -# define FILE_ATTRIBUTE_DEVICE 0x40 | |
| 118 | +# define FILE_ATTRIBUTE_DEVICE 0x40 | |
| 115 | 119 | #endif |
| 116 | 120 | |
| 117 | 121 | /* File type and permission flags for stat() */ |
| 118 | -#if defined(_MSC_VER) && !defined(S_IREAD) | |
| 122 | +#if !defined(S_IFMT) | |
| 119 | 123 | # define S_IFMT _S_IFMT /* File type mask */ |
| 124 | +#endif | |
| 125 | +#if !defined(S_IFDIR) | |
| 120 | 126 | # define S_IFDIR _S_IFDIR /* Directory */ |
| 127 | +#endif | |
| 128 | +#if !defined(S_IFCHR) | |
| 121 | 129 | # define S_IFCHR _S_IFCHR /* Character device */ |
| 130 | +#endif | |
| 131 | +#if !defined(S_IFFIFO) | |
| 122 | 132 | # define S_IFFIFO _S_IFFIFO /* Pipe */ |
| 133 | +#endif | |
| 134 | +#if !defined(S_IFREG) | |
| 123 | 135 | # define S_IFREG _S_IFREG /* Regular file */ |
| 136 | +#endif | |
| 137 | +#if !defined(S_IREAD) | |
| 124 | 138 | # define S_IREAD _S_IREAD /* Read permission */ |
| 139 | +#endif | |
| 140 | +#if !defined(S_IWRITE) | |
| 125 | 141 | # define S_IWRITE _S_IWRITE /* Write permission */ |
| 142 | +#endif | |
| 143 | +#if !defined(S_IEXEC) | |
| 126 | 144 | # define S_IEXEC _S_IEXEC /* Execute permission */ |
| 127 | 145 | #endif |
| 128 | -#define S_IFBLK 0 /* Block device */ | |
| 129 | -#define S_IFLNK 0 /* Link */ | |
| 130 | -#define S_IFSOCK 0 /* Socket */ | |
| 146 | +#if !defined(S_IFIFO) | |
| 147 | +# define S_IFIFO _S_IFIFO /* Pipe */ | |
| 148 | +#endif | |
| 149 | +#if !defined(S_IFBLK) | |
| 150 | +# define S_IFBLK 0 /* Block device */ | |
| 151 | +#endif | |
| 152 | +#if !defined(S_IFLNK) | |
| 153 | +# define S_IFLNK 0 /* Link */ | |
| 154 | +#endif | |
| 155 | +#if !defined(S_IFSOCK) | |
| 156 | +# define S_IFSOCK 0 /* Socket */ | |
| 157 | +#endif | |
| 131 | 158 | |
| 132 | 159 | #if defined(_MSC_VER) |
| 133 | 160 | # define S_IRUSR S_IREAD /* Read user */ |
| 134 | 161 | # define S_IWUSR S_IWRITE /* Write user */ |
| 135 | 162 | # define S_IXUSR 0 /* Execute user */ |
| @@ -139,18 +166,26 @@ | ||
| 139 | 166 | # define S_IROTH 0 /* Read others */ |
| 140 | 167 | # define S_IWOTH 0 /* Write others */ |
| 141 | 168 | # define S_IXOTH 0 /* Execute others */ |
| 142 | 169 | #endif |
| 143 | 170 | |
| 144 | -/* Indicates that d_type field is available in dirent structure */ | |
| 145 | -#define _DIRENT_HAVE_D_TYPE | |
| 171 | +/* Maximum length of file name */ | |
| 172 | +#if !defined(PATH_MAX) | |
| 173 | +# define PATH_MAX MAX_PATH | |
| 174 | +#endif | |
| 175 | +#if !defined(FILENAME_MAX) | |
| 176 | +# define FILENAME_MAX MAX_PATH | |
| 177 | +#endif | |
| 178 | +#if !defined(NAME_MAX) | |
| 179 | +# define NAME_MAX FILENAME_MAX | |
| 180 | +#endif | |
| 146 | 181 | |
| 147 | 182 | /* File type flags for d_type */ |
| 148 | 183 | #define DT_UNKNOWN 0 |
| 149 | 184 | #define DT_REG S_IFREG |
| 150 | 185 | #define DT_DIR S_IFDIR |
| 151 | -#define DT_FIFO S_IFFIFO | |
| 186 | +#define DT_FIFO S_IFIFO | |
| 152 | 187 | #define DT_SOCK S_IFSOCK |
| 153 | 188 | #define DT_CHR S_IFCHR |
| 154 | 189 | #define DT_BLK S_IFBLK |
| 155 | 190 | |
| 156 | 191 | /* Macros for converting between st_mode and d_type */ |
| @@ -161,41 +196,31 @@ | ||
| 161 | 196 | * File type macros. Note that block devices, sockets and links cannot be |
| 162 | 197 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are |
| 163 | 198 | * only defined for compatibility. These macros should always return false |
| 164 | 199 | * on Windows. |
| 165 | 200 | */ |
| 166 | -#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO) | |
| 201 | +#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) | |
| 167 | 202 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) |
| 168 | 203 | #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) |
| 169 | 204 | #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) |
| 170 | 205 | #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) |
| 171 | 206 | #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) |
| 172 | 207 | #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) |
| 173 | 208 | |
| 174 | -/* For compatiblity with Unix */ | |
| 175 | -#if !defined(PATH_MAX) | |
| 176 | -# define PATH_MAX MAX_PATH | |
| 177 | -#endif | |
| 178 | -#if !defined(FILENAME_MAX) | |
| 179 | -# define FILENAME_MAX MAX_PATH | |
| 180 | -#endif | |
| 181 | -#if !defined(NAME_MAX) | |
| 182 | -# define NAME_MAX FILENAME_MAX | |
| 183 | -#endif | |
| 184 | - | |
| 185 | -/* Set errno variable */ | |
| 186 | -#if defined(_MSC_VER) | |
| 187 | -#define DIRENT_SET_ERRNO(x) _set_errno (x) | |
| 188 | -#else | |
| 189 | -#define DIRENT_SET_ERRNO(x) (errno = (x)) | |
| 190 | -#endif | |
| 209 | +/* Return the exact length of d_namlen without zero terminator */ | |
| 210 | +#define _D_EXACT_NAMLEN(p) ((p)->d_namlen) | |
| 211 | + | |
| 212 | +/* Return number of bytes needed to store d_namlen */ | |
| 213 | +#define _D_ALLOC_NAMLEN(p) (PATH_MAX + 1) | |
| 214 | + | |
| 191 | 215 | |
| 192 | 216 | #ifdef __cplusplus |
| 193 | 217 | extern "C" { |
| 194 | 218 | #endif |
| 195 | 219 | |
| 196 | -/* Wide-character versions */ | |
| 220 | + | |
| 221 | +/* Wide-character version */ | |
| 197 | 222 | struct _wdirent { |
| 198 | 223 | long d_ino; /* Always zero */ |
| 199 | 224 | unsigned short d_reclen; /* Structure size */ |
| 200 | 225 | size_t d_namlen; /* Length of name without \0 */ |
| 201 | 226 | int d_type; /* File type */ |
| @@ -203,11 +228,11 @@ | ||
| 203 | 228 | }; |
| 204 | 229 | typedef struct _wdirent _wdirent; |
| 205 | 230 | |
| 206 | 231 | struct _WDIR { |
| 207 | 232 | struct _wdirent ent; /* Current directory entry */ |
| 208 | - WIN32_FIND_DATAW find_data; /* Private file data */ | |
| 233 | + WIN32_FIND_DATAW data; /* Private file data */ | |
| 209 | 234 | int cached; /* True if data is valid */ |
| 210 | 235 | HANDLE handle; /* Win32 search handle */ |
| 211 | 236 | wchar_t *patt; /* Initial directory name */ |
| 212 | 237 | }; |
| 213 | 238 | typedef struct _WDIR _WDIR; |
| @@ -214,10 +239,11 @@ | ||
| 214 | 239 | |
| 215 | 240 | static _WDIR *_wopendir (const wchar_t *dirname); |
| 216 | 241 | static struct _wdirent *_wreaddir (_WDIR *dirp); |
| 217 | 242 | static int _wclosedir (_WDIR *dirp); |
| 218 | 243 | static void _wrewinddir (_WDIR* dirp); |
| 244 | + | |
| 219 | 245 | |
| 220 | 246 | /* For compatibility with Symbian */ |
| 221 | 247 | #define wdirent _wdirent |
| 222 | 248 | #define WDIR _WDIR |
| 223 | 249 | #define wopendir _wopendir |
| @@ -246,10 +272,30 @@ | ||
| 246 | 272 | static struct dirent *readdir (DIR *dirp); |
| 247 | 273 | static int closedir (DIR *dirp); |
| 248 | 274 | static void rewinddir (DIR* dirp); |
| 249 | 275 | |
| 250 | 276 | |
| 277 | +/* Internal utility functions */ | |
| 278 | +static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); | |
| 279 | +static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); | |
| 280 | + | |
| 281 | +static int dirent_mbstowcs_s( | |
| 282 | + size_t *pReturnValue, | |
| 283 | + wchar_t *wcstr, | |
| 284 | + size_t sizeInWords, | |
| 285 | + const char *mbstr, | |
| 286 | + size_t count); | |
| 287 | + | |
| 288 | +static int dirent_wcstombs_s( | |
| 289 | + size_t *pReturnValue, | |
| 290 | + char *mbstr, | |
| 291 | + size_t sizeInBytes, | |
| 292 | + const wchar_t *wcstr, | |
| 293 | + size_t count); | |
| 294 | + | |
| 295 | +static void dirent_set_errno (int error); | |
| 296 | + | |
| 251 | 297 | /* |
| 252 | 298 | * Open directory stream DIRNAME for read and return a pointer to the |
| 253 | 299 | * internal working area that is used to retrieve individual directory |
| 254 | 300 | * entries. |
| 255 | 301 | */ |
| @@ -256,31 +302,38 @@ | ||
| 256 | 302 | static _WDIR* |
| 257 | 303 | _wopendir( |
| 258 | 304 | const wchar_t *dirname) |
| 259 | 305 | { |
| 260 | 306 | _WDIR *dirp = NULL; |
| 261 | - int error = 0; | |
| 307 | + int error; | |
| 308 | + | |
| 309 | + /* Must have directory name */ | |
| 310 | + if (dirname == NULL || dirname[0] == '\0') { | |
| 311 | + dirent_set_errno (ENOENT); | |
| 312 | + return NULL; | |
| 313 | + } | |
| 262 | 314 | |
| 263 | 315 | /* Allocate new _WDIR structure */ |
| 264 | 316 | dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); |
| 265 | 317 | if (dirp != NULL) { |
| 266 | 318 | DWORD n; |
| 267 | 319 | |
| 268 | 320 | /* Reset _WDIR structure */ |
| 269 | 321 | dirp->handle = INVALID_HANDLE_VALUE; |
| 270 | 322 | dirp->patt = NULL; |
| 323 | + dirp->cached = 0; | |
| 271 | 324 | |
| 272 | 325 | /* Compute the length of full path plus zero terminator */ |
| 273 | 326 | n = GetFullPathNameW (dirname, 0, NULL, NULL); |
| 274 | 327 | |
| 275 | - /* Allocate room for full path and search patterns */ | |
| 328 | + /* Allocate room for absolute directory name and search pattern */ | |
| 276 | 329 | dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); |
| 277 | 330 | if (dirp->patt) { |
| 278 | 331 | |
| 279 | 332 | /* |
| 280 | 333 | * Convert relative directory name to an absolute one. This |
| 281 | - * allows rewinddir() to function correctly when the current | |
| 334 | + * allows rewinddir() to function correctly even when current | |
| 282 | 335 | * working directory is changed between opendir() and rewinddir(). |
| 283 | 336 | */ |
| 284 | 337 | n = GetFullPathNameW (dirname, n, dirp->patt, NULL); |
| 285 | 338 | if (n > 0) { |
| 286 | 339 | wchar_t *p; |
| @@ -303,25 +356,22 @@ | ||
| 303 | 356 | } |
| 304 | 357 | *p++ = '*'; |
| 305 | 358 | *p = '\0'; |
| 306 | 359 | |
| 307 | 360 | /* Open directory stream and retrieve the first entry */ |
| 308 | - dirp->handle = FindFirstFileW (dirp->patt, &dirp->find_data); | |
| 309 | - if (dirp->handle != INVALID_HANDLE_VALUE) { | |
| 310 | - | |
| 311 | - /* Directory entry is now waiting in memory */ | |
| 312 | - dirp->cached = 1; | |
| 313 | - | |
| 361 | + if (dirent_first (dirp)) { | |
| 362 | + /* Directory stream opened successfully */ | |
| 363 | + error = 0; | |
| 314 | 364 | } else { |
| 315 | - /* Search pattern is not a directory name? */ | |
| 316 | - DIRENT_SET_ERRNO (ENOENT); | |
| 365 | + /* Cannot retrieve first entry */ | |
| 317 | 366 | error = 1; |
| 367 | + dirent_set_errno (ENOENT); | |
| 318 | 368 | } |
| 319 | 369 | |
| 320 | 370 | } else { |
| 321 | - /* Cannot convert directory name to wide character string */ | |
| 322 | - DIRENT_SET_ERRNO (ENOENT); | |
| 371 | + /* Cannot retrieve full path name */ | |
| 372 | + dirent_set_errno (ENOENT); | |
| 323 | 373 | error = 1; |
| 324 | 374 | } |
| 325 | 375 | |
| 326 | 376 | } else { |
| 327 | 377 | /* Cannot allocate memory for search pattern */ |
| @@ -350,70 +400,59 @@ | ||
| 350 | 400 | */ |
| 351 | 401 | static struct _wdirent* |
| 352 | 402 | _wreaddir( |
| 353 | 403 | _WDIR *dirp) |
| 354 | 404 | { |
| 355 | - DWORD attr; | |
| 356 | - errno_t error; | |
| 357 | - | |
| 358 | - /* Get next directory entry */ | |
| 359 | - if (dirp->cached != 0) { | |
| 360 | - /* A valid directory entry already in memory */ | |
| 361 | - dirp->cached = 0; | |
| 362 | - } else { | |
| 363 | - /* Get the next directory entry from stream */ | |
| 364 | - if (dirp->handle == INVALID_HANDLE_VALUE) { | |
| 365 | - return NULL; | |
| 366 | - } | |
| 367 | - if (FindNextFileW (dirp->handle, &dirp->find_data) == FALSE) { | |
| 368 | - /* The very last entry has been processed or an error occured */ | |
| 369 | - FindClose (dirp->handle); | |
| 370 | - dirp->handle = INVALID_HANDLE_VALUE; | |
| 371 | - return NULL; | |
| 372 | - } | |
| 373 | - } | |
| 374 | - | |
| 375 | - /* Copy file name as a wide-character string */ | |
| 376 | - error = wcsncpy_s( | |
| 377 | - dirp->ent.d_name, /* Destination string */ | |
| 378 | - PATH_MAX, /* Size of dest in words */ | |
| 379 | - dirp->find_data.cFileName, /* Source string */ | |
| 380 | - PATH_MAX + 1); /* Max # of chars to copy */ | |
| 381 | - if (!error) { | |
| 382 | - | |
| 383 | - /* Compute the length of name */ | |
| 384 | - dirp->ent.d_namlen = wcsnlen (dirp->ent.d_name, PATH_MAX); | |
| 385 | - | |
| 386 | - /* Determine file type */ | |
| 387 | - attr = dirp->find_data.dwFileAttributes; | |
| 405 | + WIN32_FIND_DATAW *datap; | |
| 406 | + struct _wdirent *entp; | |
| 407 | + | |
| 408 | + /* Read next directory entry */ | |
| 409 | + datap = dirent_next (dirp); | |
| 410 | + if (datap) { | |
| 411 | + size_t n; | |
| 412 | + DWORD attr; | |
| 413 | + | |
| 414 | + /* Pointer to directory entry to return */ | |
| 415 | + entp = &dirp->ent; | |
| 416 | + | |
| 417 | + /* | |
| 418 | + * Copy file name as wide-character string. If the file name is too | |
| 419 | + * long to fit in to the destination buffer, then truncate file name | |
| 420 | + * to PATH_MAX characters and zero-terminate the buffer. | |
| 421 | + */ | |
| 422 | + n = 0; | |
| 423 | + while (n < PATH_MAX && datap->cFileName[n] != 0) { | |
| 424 | + entp->d_name[n] = datap->cFileName[n]; | |
| 425 | + n++; | |
| 426 | + } | |
| 427 | + dirp->ent.d_name[n] = 0; | |
| 428 | + | |
| 429 | + /* Length of file name excluding zero terminator */ | |
| 430 | + entp->d_namlen = n; | |
| 431 | + | |
| 432 | + /* File type */ | |
| 433 | + attr = datap->dwFileAttributes; | |
| 388 | 434 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { |
| 389 | - dirp->ent.d_type = DT_CHR; | |
| 435 | + entp->d_type = DT_CHR; | |
| 390 | 436 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 391 | - dirp->ent.d_type = DT_DIR; | |
| 437 | + entp->d_type = DT_DIR; | |
| 392 | 438 | } else { |
| 393 | - dirp->ent.d_type = DT_REG; | |
| 439 | + entp->d_type = DT_REG; | |
| 394 | 440 | } |
| 395 | 441 | |
| 396 | 442 | /* Reset dummy fields */ |
| 397 | - dirp->ent.d_ino = 0; | |
| 398 | - dirp->ent.d_reclen = sizeof (dirp->ent); | |
| 443 | + entp->d_ino = 0; | |
| 444 | + entp->d_reclen = sizeof (struct _wdirent); | |
| 399 | 445 | |
| 400 | 446 | } else { |
| 401 | 447 | |
| 402 | - /* | |
| 403 | - * Cannot copy file name from find_data to ent. Construct a | |
| 404 | - * dummy _wdirent structure to pass error to caller. | |
| 405 | - */ | |
| 406 | - dirp->ent.d_name[0] = '?'; | |
| 407 | - dirp->ent.d_name[1] = '\0'; | |
| 408 | - dirp->ent.d_namlen = 1; | |
| 409 | - dirp->ent.d_type = DT_UNKNOWN; | |
| 410 | - dirp->ent.d_ino = 0; | |
| 411 | - dirp->ent.d_reclen = 0; | |
| 448 | + /* Last directory entry read */ | |
| 449 | + entp = NULL; | |
| 450 | + | |
| 412 | 451 | } |
| 413 | 452 | |
| 414 | - return &dirp->ent; | |
| 453 | + return entp; | |
| 415 | 454 | } |
| 416 | 455 | |
| 417 | 456 | /* |
| 418 | 457 | * Close directory stream opened by opendir() function. This invalidates the |
| 419 | 458 | * DIR structure as well as any directory entry read previously by |
| @@ -442,11 +481,11 @@ | ||
| 442 | 481 | free (dirp); |
| 443 | 482 | ok = /*success*/0; |
| 444 | 483 | |
| 445 | 484 | } else { |
| 446 | 485 | /* Invalid directory stream */ |
| 447 | - DIRENT_SET_ERRNO (EBADF); | |
| 486 | + dirent_set_errno (EBADF); | |
| 448 | 487 | ok = /*failure*/-1; |
| 449 | 488 | } |
| 450 | 489 | return ok; |
| 451 | 490 | } |
| 452 | 491 | |
| @@ -456,26 +495,81 @@ | ||
| 456 | 495 | */ |
| 457 | 496 | static void |
| 458 | 497 | _wrewinddir( |
| 459 | 498 | _WDIR* dirp) |
| 460 | 499 | { |
| 461 | - if (dirp != NULL) { | |
| 462 | - /* release search handle */ | |
| 500 | + if (dirp) { | |
| 501 | + /* Release existing search handle */ | |
| 463 | 502 | if (dirp->handle != INVALID_HANDLE_VALUE) { |
| 464 | 503 | FindClose (dirp->handle); |
| 465 | 504 | } |
| 466 | 505 | |
| 467 | - /* Open new search handle and retrieve the first directory entry */ | |
| 468 | - dirp->handle = FindFirstFileW (dirp->patt, &dirp->find_data); | |
| 469 | - if (dirp->handle != INVALID_HANDLE_VALUE) { | |
| 470 | - /* a directory entry is now waiting in memory */ | |
| 471 | - dirp->cached = 1; | |
| 506 | + /* Open new search handle */ | |
| 507 | + dirent_first (dirp); | |
| 508 | + } | |
| 509 | +} | |
| 510 | + | |
| 511 | +/* Get first directory entry (internal) */ | |
| 512 | +static WIN32_FIND_DATAW* | |
| 513 | +dirent_first( | |
| 514 | + _WDIR *dirp) | |
| 515 | +{ | |
| 516 | + WIN32_FIND_DATAW *datap; | |
| 517 | + | |
| 518 | + /* Open directory and retrieve the first entry */ | |
| 519 | + dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); | |
| 520 | + if (dirp->handle != INVALID_HANDLE_VALUE) { | |
| 521 | + | |
| 522 | + /* a directory entry is now waiting in memory */ | |
| 523 | + datap = &dirp->data; | |
| 524 | + dirp->cached = 1; | |
| 525 | + | |
| 526 | + } else { | |
| 527 | + | |
| 528 | + /* Failed to re-open directory: no directory entry in memory */ | |
| 529 | + dirp->cached = 0; | |
| 530 | + datap = NULL; | |
| 531 | + | |
| 532 | + } | |
| 533 | + return datap; | |
| 534 | +} | |
| 535 | + | |
| 536 | +/* Get next directory entry (internal) */ | |
| 537 | +static WIN32_FIND_DATAW* | |
| 538 | +dirent_next( | |
| 539 | + _WDIR *dirp) | |
| 540 | +{ | |
| 541 | + WIN32_FIND_DATAW *p; | |
| 542 | + | |
| 543 | + /* Get next directory entry */ | |
| 544 | + if (dirp->cached != 0) { | |
| 545 | + | |
| 546 | + /* A valid directory entry already in memory */ | |
| 547 | + p = &dirp->data; | |
| 548 | + dirp->cached = 0; | |
| 549 | + | |
| 550 | + } else if (dirp->handle != INVALID_HANDLE_VALUE) { | |
| 551 | + | |
| 552 | + /* Get the next directory entry from stream */ | |
| 553 | + if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { | |
| 554 | + /* Got a file */ | |
| 555 | + p = &dirp->data; | |
| 472 | 556 | } else { |
| 473 | - /* Failed to re-open directory: no directory entry in memory */ | |
| 474 | - dirp->cached = 0; | |
| 557 | + /* The very last entry has been processed or an error occured */ | |
| 558 | + FindClose (dirp->handle); | |
| 559 | + dirp->handle = INVALID_HANDLE_VALUE; | |
| 560 | + p = NULL; | |
| 475 | 561 | } |
| 562 | + | |
| 563 | + } else { | |
| 564 | + | |
| 565 | + /* End of directory stream reached */ | |
| 566 | + p = NULL; | |
| 567 | + | |
| 476 | 568 | } |
| 569 | + | |
| 570 | + return p; | |
| 477 | 571 | } |
| 478 | 572 | |
| 479 | 573 | /* |
| 480 | 574 | * Open directory stream using plain old C-string. |
| 481 | 575 | */ |
| @@ -482,58 +576,34 @@ | ||
| 482 | 576 | static DIR* |
| 483 | 577 | opendir( |
| 484 | 578 | const char *dirname) |
| 485 | 579 | { |
| 486 | 580 | struct DIR *dirp; |
| 487 | - errno_t error = 0; | |
| 581 | + int error; | |
| 488 | 582 | |
| 489 | 583 | /* Must have directory name */ |
| 490 | - if (dirname == NULL) { | |
| 491 | - DIRENT_SET_ERRNO (ENOENT); | |
| 584 | + if (dirname == NULL || dirname[0] == '\0') { | |
| 585 | + dirent_set_errno (ENOENT); | |
| 492 | 586 | return NULL; |
| 493 | 587 | } |
| 494 | 588 | |
| 495 | - /* Allocate memory for multi-byte string directory structures */ | |
| 589 | + /* Allocate memory for DIR structure */ | |
| 496 | 590 | dirp = (DIR*) malloc (sizeof (struct DIR)); |
| 497 | 591 | if (dirp) { |
| 498 | 592 | wchar_t wname[PATH_MAX + 1]; |
| 499 | 593 | size_t n; |
| 500 | 594 | |
| 501 | - /* | |
| 502 | - * Convert directory name to wide-character string. | |
| 503 | - * | |
| 504 | - * Be ware of the return schemantics of MultiByteToWideChar() -- | |
| 505 | - * the function basically returns the number of characters written to | |
| 506 | - * output buffer or zero if the conversion fails. However, the | |
| 507 | - * function does not necessarily zero-terminate the output | |
| 508 | - * buffer and may return 0xFFFD if the string contains invalid | |
| 509 | - * characters! | |
| 510 | - */ | |
| 511 | - n = MultiByteToWideChar( | |
| 512 | - CP_ACP, /* Input code page */ | |
| 513 | - MB_PRECOMPOSED, /* Conversion flags */ | |
| 514 | - dirname, /* Input string */ | |
| 515 | - -1, /* Length of input string */ | |
| 516 | - wname, /* Output buffer */ | |
| 517 | - PATH_MAX); /* Size of output buffer */ | |
| 518 | - if (n > 0 && n < PATH_MAX) { | |
| 519 | - | |
| 520 | - /* Zero-terminate output buffer */ | |
| 521 | - wname[n] = '\0'; | |
| 522 | - | |
| 523 | - /* Open directory stream with wide-character string file name */ | |
| 595 | + /* Convert directory name to wide-character string */ | |
| 596 | + error = dirent_mbstowcs_s( | |
| 597 | + &n, wname, PATH_MAX + 1, dirname, PATH_MAX); | |
| 598 | + if (!error) { | |
| 599 | + | |
| 600 | + /* Open directory stream using wide-character name */ | |
| 524 | 601 | dirp->wdirp = _wopendir (wname); |
| 525 | 602 | if (dirp->wdirp) { |
| 526 | - | |
| 527 | - /* Initialize directory structure */ | |
| 528 | - dirp->ent.d_name[0] = '\0'; | |
| 529 | - dirp->ent.d_namlen = 0; | |
| 530 | - dirp->ent.d_type = 0; | |
| 531 | - dirp->ent.d_ino = 0; | |
| 532 | - dirp->ent.d_reclen = 0; | |
| 533 | - | |
| 534 | - | |
| 603 | + /* Directory stream opened */ | |
| 604 | + error = 0; | |
| 535 | 605 | } else { |
| 536 | 606 | /* Failed to open directory stream */ |
| 537 | 607 | error = 1; |
| 538 | 608 | } |
| 539 | 609 | |
| @@ -562,95 +632,99 @@ | ||
| 562 | 632 | } |
| 563 | 633 | |
| 564 | 634 | /* |
| 565 | 635 | * Read next directory entry. |
| 566 | 636 | * |
| 567 | - * When working with console, please note that file names returned by | |
| 568 | - * readdir() are represented in the default ANSI code page while the | |
| 569 | - * console typically runs on another code page. Thus, non-ASCII characters | |
| 570 | - * will not usually display correctly. The problem can be fixed in two ways: | |
| 571 | - * (1) change the character set of console to 1252 using chcp utility and use | |
| 572 | - * Lucida Console font, or (2) always use _cprintf function when writing to | |
| 573 | - * console. The _cprinf() will re-encode ANSI strings to the console code | |
| 574 | - * page so non-ASCII characters will display correcly. | |
| 637 | + * When working with text consoles, please note that file names returned by | |
| 638 | + * readdir() are represented in the default ANSI code page while any output to | |
| 639 | + * console is typically formatted on another code page. Thus, non-ASCII | |
| 640 | + * characters in file names will not usually display correctly on console. The | |
| 641 | + * problem can be fixed in two ways: (1) change the character set of console | |
| 642 | + * to 1252 using chcp utility and use Lucida Console font, or (2) use | |
| 643 | + * _cprintf function when writing to console. The _cprinf() will re-encode | |
| 644 | + * ANSI strings to the console code page so many non-ASCII characters will | |
| 645 | + * display correcly. | |
| 575 | 646 | */ |
| 576 | 647 | static struct dirent* |
| 577 | 648 | readdir( |
| 578 | 649 | DIR *dirp) |
| 579 | 650 | { |
| 580 | - struct dirent *p; | |
| 581 | - struct _wdirent *wp; | |
| 651 | + WIN32_FIND_DATAW *datap; | |
| 652 | + struct dirent *entp; | |
| 582 | 653 | |
| 583 | - /* Read next directory entry using wide-character string functions */ | |
| 584 | - wp = _wreaddir (dirp->wdirp); | |
| 585 | - if (wp) { | |
| 654 | + /* Read next directory entry */ | |
| 655 | + datap = dirent_next (dirp->wdirp); | |
| 656 | + if (datap) { | |
| 586 | 657 | size_t n; |
| 658 | + int error; | |
| 659 | + | |
| 660 | + /* Attempt to convert file name to multi-byte string */ | |
| 661 | + error = dirent_wcstombs_s( | |
| 662 | + &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH); | |
| 587 | 663 | |
| 588 | 664 | /* |
| 589 | - * Convert file name to multi-byte string. | |
| 590 | - * | |
| 591 | - * Be ware of the return schemantics of WideCharToMultiByte() -- | |
| 592 | - * the function basically returns the number of bytes | |
| 593 | - * written to output buffer or zero if the conversion fails. | |
| 594 | - * However, the function does not necessarily zero-terminate the | |
| 595 | - * buffer and it may even return 0xFFFD the string contains | |
| 596 | - * invalid characters! | |
| 665 | + * If the file name cannot be represented by a multi-byte string, | |
| 666 | + * then attempt to use old 8+3 file name. This allows traditional | |
| 667 | + * Unix-code to access some file names despite of unicode | |
| 668 | + * characters, although file names may seem unfamiliar to the user. | |
| 669 | + * | |
| 670 | + * Be ware that the code below cannot come up with a short file | |
| 671 | + * name unless the file system provides one. At least | |
| 672 | + * VirtualBox shared folders fail to do this. | |
| 597 | 673 | */ |
| 598 | - n = WideCharToMultiByte( | |
| 599 | - CP_ACP, /* Output code page */ | |
| 600 | - 0, /* Conversion flags */ | |
| 601 | - wp->d_name, /* Input string */ | |
| 602 | - wp->d_namlen, /* Length of input string */ | |
| 603 | - dirp->ent.d_name, /* Output buffer */ | |
| 604 | - PATH_MAX, /* Size of output buffer */ | |
| 605 | - NULL, /* Replacement character */ | |
| 606 | - NULL); /* If chars were replaced */ | |
| 607 | - if (n > 0 && n < PATH_MAX) { | |
| 608 | - | |
| 609 | - /* Zero-terminate buffer */ | |
| 610 | - dirp->ent.d_name[n] = '\0'; | |
| 674 | + if (error && datap->cAlternateFileName[0] != '\0') { | |
| 675 | + error = dirent_wcstombs_s( | |
| 676 | + &n, dirp->ent.d_name, MAX_PATH + 1, datap->cAlternateFileName, | |
| 677 | + sizeof (datap->cAlternateFileName) / | |
| 678 | + sizeof (datap->cAlternateFileName[0])); | |
| 679 | + } | |
| 680 | + | |
| 681 | + if (!error) { | |
| 682 | + DWORD attr; | |
| 611 | 683 | |
| 612 | 684 | /* Initialize directory entry for return */ |
| 613 | - p = &dirp->ent; | |
| 685 | + entp = &dirp->ent; | |
| 614 | 686 | |
| 615 | - /* Compute length */ | |
| 616 | - p->d_namlen = strnlen (dirp->ent.d_name, PATH_MAX); | |
| 687 | + /* Length of file name excluding zero terminator */ | |
| 688 | + entp->d_namlen = n - 1; | |
| 617 | 689 | |
| 618 | - /* Copy file attributes */ | |
| 619 | - p->d_type = wp->d_type; | |
| 690 | + /* File attributes */ | |
| 691 | + attr = datap->dwFileAttributes; | |
| 692 | + if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { | |
| 693 | + entp->d_type = DT_CHR; | |
| 694 | + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { | |
| 695 | + entp->d_type = DT_DIR; | |
| 696 | + } else { | |
| 697 | + entp->d_type = DT_REG; | |
| 698 | + } | |
| 620 | 699 | |
| 621 | 700 | /* Reset dummy fields */ |
| 622 | - p->d_ino = 0; | |
| 623 | - p->d_reclen = sizeof (dirp->ent); | |
| 624 | - | |
| 701 | + entp->d_ino = 0; | |
| 702 | + entp->d_reclen = sizeof (struct dirent); | |
| 625 | 703 | |
| 626 | 704 | } else { |
| 627 | - | |
| 628 | 705 | /* |
| 629 | 706 | * Cannot convert file name to multi-byte string so construct |
| 630 | 707 | * an errornous directory entry and return that. Note that |
| 631 | 708 | * we cannot return NULL as that would stop the processing |
| 632 | 709 | * of directory entries completely. |
| 633 | 710 | */ |
| 634 | - p = &dirp->ent; | |
| 635 | - p->d_name[0] = '?'; | |
| 636 | - p->d_name[1] = '\0'; | |
| 637 | - p->d_namlen = 1; | |
| 638 | - p->d_type = DT_UNKNOWN; | |
| 639 | - p->d_ino = 0; | |
| 640 | - p->d_reclen = 0; | |
| 641 | - | |
| 711 | + entp = &dirp->ent; | |
| 712 | + entp->d_name[0] = '?'; | |
| 713 | + entp->d_name[1] = '\0'; | |
| 714 | + entp->d_namlen = 1; | |
| 715 | + entp->d_type = DT_UNKNOWN; | |
| 716 | + entp->d_ino = 0; | |
| 717 | + entp->d_reclen = 0; | |
| 642 | 718 | } |
| 643 | 719 | |
| 644 | 720 | } else { |
| 645 | - | |
| 646 | - /* End of directory stream */ | |
| 647 | - p = NULL; | |
| 648 | - | |
| 721 | + /* No more directory entries */ | |
| 722 | + entp = NULL; | |
| 649 | 723 | } |
| 650 | 724 | |
| 651 | - return p; | |
| 725 | + return entp; | |
| 652 | 726 | } |
| 653 | 727 | |
| 654 | 728 | /* |
| 655 | 729 | * Close directory stream. |
| 656 | 730 | */ |
| @@ -667,13 +741,15 @@ | ||
| 667 | 741 | |
| 668 | 742 | /* Release multi-byte character version */ |
| 669 | 743 | free (dirp); |
| 670 | 744 | |
| 671 | 745 | } else { |
| 746 | + | |
| 672 | 747 | /* Invalid directory stream */ |
| 673 | - DIRENT_SET_ERRNO (EBADF); | |
| 748 | + dirent_set_errno (EBADF); | |
| 674 | 749 | ok = /*failure*/-1; |
| 750 | + | |
| 675 | 751 | } |
| 676 | 752 | return ok; |
| 677 | 753 | } |
| 678 | 754 | |
| 679 | 755 | /* |
| @@ -684,12 +760,130 @@ | ||
| 684 | 760 | DIR* dirp) |
| 685 | 761 | { |
| 686 | 762 | /* Rewind wide-character string directory stream */ |
| 687 | 763 | _wrewinddir (dirp->wdirp); |
| 688 | 764 | } |
| 765 | + | |
| 766 | +/* Convert multi-byte string to wide character string */ | |
| 767 | +static int | |
| 768 | +dirent_mbstowcs_s( | |
| 769 | + size_t *pReturnValue, | |
| 770 | + wchar_t *wcstr, | |
| 771 | + size_t sizeInWords, | |
| 772 | + const char *mbstr, | |
| 773 | + size_t count) | |
| 774 | +{ | |
| 775 | + int error; | |
| 776 | + | |
| 777 | +#if defined(_MSC_VER) && _MSC_VER >= 1400 | |
| 778 | + | |
| 779 | + /* Microsoft Visual Studio 2005 or later */ | |
| 780 | + error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); | |
| 781 | + | |
| 782 | +#else | |
| 783 | + | |
| 784 | + /* Older Visual Studio or non-Microsoft compiler */ | |
| 785 | + size_t n; | |
| 786 | + | |
| 787 | + /* Convert to wide-character string */ | |
| 788 | + n = mbstowcs (wcstr, mbstr, count); | |
| 789 | + if (n < sizeInWords) { | |
| 790 | + | |
| 791 | + /* Zero-terminate output buffer */ | |
| 792 | + if (wcstr) { | |
| 793 | + wcstr[n] = 0; | |
| 794 | + } | |
| 795 | + | |
| 796 | + /* Length of resuting multi-byte string WITH zero terminator */ | |
| 797 | + if (pReturnValue) { | |
| 798 | + *pReturnValue = n + 1; | |
| 799 | + } | |
| 800 | + | |
| 801 | + /* Success */ | |
| 802 | + error = 0; | |
| 803 | + | |
| 804 | + } else { | |
| 805 | + | |
| 806 | + /* Could not convert string */ | |
| 807 | + error = 1; | |
| 808 | + | |
| 809 | + } | |
| 810 | + | |
| 811 | +#endif | |
| 812 | + | |
| 813 | + return error; | |
| 814 | +} | |
| 815 | + | |
| 816 | +/* Convert wide-character string to multi-byte string */ | |
| 817 | +static int | |
| 818 | +dirent_wcstombs_s( | |
| 819 | + size_t *pReturnValue, | |
| 820 | + char *mbstr, | |
| 821 | + size_t sizeInBytes, | |
| 822 | + const wchar_t *wcstr, | |
| 823 | + size_t count) | |
| 824 | +{ | |
| 825 | + int error; | |
| 826 | + | |
| 827 | +#if defined(_MSC_VER) && _MSC_VER >= 1400 | |
| 828 | + | |
| 829 | + /* Microsoft Visual Studio 2005 or later */ | |
| 830 | + error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); | |
| 831 | + | |
| 832 | +#else | |
| 833 | + | |
| 834 | + /* Older Visual Studio or non-Microsoft compiler */ | |
| 835 | + size_t n; | |
| 836 | + | |
| 837 | + /* Convert to multi-byte string */ | |
| 838 | + n = wcstombs (mbstr, wcstr, count); | |
| 839 | + if (n < sizeInBytes) { | |
| 840 | + | |
| 841 | + /* Zero-terminate output buffer */ | |
| 842 | + if (mbstr) { | |
| 843 | + mbstr[n] = '\0'; | |
| 844 | + } | |
| 845 | + | |
| 846 | + /* Lenght of resulting multi-bytes string WITH zero-terminator */ | |
| 847 | + if (pReturnValue) { | |
| 848 | + *pReturnValue = n + 1; | |
| 849 | + } | |
| 850 | + | |
| 851 | + /* Success */ | |
| 852 | + error = 0; | |
| 853 | + | |
| 854 | + } else { | |
| 855 | + | |
| 856 | + /* Cannot convert string */ | |
| 857 | + error = 1; | |
| 858 | + | |
| 859 | + } | |
| 860 | + | |
| 861 | +#endif | |
| 862 | + | |
| 863 | + return error; | |
| 864 | +} | |
| 865 | + | |
| 866 | +/* Set errno variable */ | |
| 867 | +static void | |
| 868 | +dirent_set_errno( | |
| 869 | + int error) | |
| 870 | +{ | |
| 871 | +#if defined(_MSC_VER) | |
| 872 | + | |
| 873 | + /* Microsoft Visual Studio */ | |
| 874 | + _set_errno (error); | |
| 875 | + | |
| 876 | +#else | |
| 877 | + | |
| 878 | + /* Non-Microsoft compiler */ | |
| 879 | + errno = error; | |
| 880 | + | |
| 881 | +#endif | |
| 882 | +} | |
| 689 | 883 | |
| 690 | 884 | |
| 691 | 885 | #ifdef __cplusplus |
| 692 | 886 | } |
| 693 | 887 | #endif |
| 694 | 888 | #endif /*DIRENT_H*/ |
| 695 | 889 | |
| 696 | 890 |
| --- win/include/dirent.h | |
| +++ win/include/dirent.h | |
| @@ -20,21 +20,24 @@ | |
| 20 | * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 23 | * OTHER DEALINGS IN THE SOFTWARE. |
| 24 | * |
| 25 | * |
| 26 | * Version 1.12.1, Oct 1 2012, Toni Ronkko |
| 27 | * Bug fix: renamed wide-character DIR structure _wDIR to _WDIR (with |
| 28 | * capital W) in order to maintain compatibility with MingW. |
| 29 | * |
| 30 | * Version 1.12, Sep 30 2012, Toni Ronkko |
| 31 | * Define PATH_MAX and NAME_MAX. |
| 32 | * |
| 33 | * Added wide-character variants _wDIR, _wdirent, _wopendir(), |
| 34 | * _wreaddir(), _wclosedir() and _wrewinddir(). Thanks to Edgar Buerkle |
| 35 | * and Jan Nijtmans for ideas and code. |
| 36 | * |
| 37 | * Do not include windows.h. This allows dirent.h to be integrated more |
| 38 | * easily into programs using winsock. Thanks to Fernando Azaldegui. |
| 39 | * |
| 40 | * Version 1.11, Mar 15, 2011, Toni Ronkko |
| @@ -88,48 +91,72 @@ | |
| 88 | *****************************************************************************/ |
| 89 | #ifndef DIRENT_H |
| 90 | #define DIRENT_H |
| 91 | |
| 92 | #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) |
| 93 | #define _X86_ |
| 94 | #endif |
| 95 | #include <stdio.h> |
| 96 | #include <stdarg.h> |
| 97 | #include <windef.h> |
| 98 | #include <winbase.h> |
| 99 | #include <wchar.h> |
| 100 | #include <winnls.h> |
| 101 | #include <string.h> |
| 102 | #include <stdlib.h> |
| 103 | #include <sys/types.h> |
| 104 | #include <sys/stat.h> |
| 105 | #include <errno.h> |
| 106 | |
| 107 | /* Windows 8 wide-character string functions */ |
| 108 | #if (_WIN32_WINNT >= 0x0602) |
| 109 | # include <stringapiset.h> |
| 110 | #endif |
| 111 | |
| 112 | /* Entries missing from MSVC 6.0 */ |
| 113 | #if !defined(FILE_ATTRIBUTE_DEVICE) |
| 114 | # define FILE_ATTRIBUTE_DEVICE 0x40 |
| 115 | #endif |
| 116 | |
| 117 | /* File type and permission flags for stat() */ |
| 118 | #if defined(_MSC_VER) && !defined(S_IREAD) |
| 119 | # define S_IFMT _S_IFMT /* File type mask */ |
| 120 | # define S_IFDIR _S_IFDIR /* Directory */ |
| 121 | # define S_IFCHR _S_IFCHR /* Character device */ |
| 122 | # define S_IFFIFO _S_IFFIFO /* Pipe */ |
| 123 | # define S_IFREG _S_IFREG /* Regular file */ |
| 124 | # define S_IREAD _S_IREAD /* Read permission */ |
| 125 | # define S_IWRITE _S_IWRITE /* Write permission */ |
| 126 | # define S_IEXEC _S_IEXEC /* Execute permission */ |
| 127 | #endif |
| 128 | #define S_IFBLK 0 /* Block device */ |
| 129 | #define S_IFLNK 0 /* Link */ |
| 130 | #define S_IFSOCK 0 /* Socket */ |
| 131 | |
| 132 | #if defined(_MSC_VER) |
| 133 | # define S_IRUSR S_IREAD /* Read user */ |
| 134 | # define S_IWUSR S_IWRITE /* Write user */ |
| 135 | # define S_IXUSR 0 /* Execute user */ |
| @@ -139,18 +166,26 @@ | |
| 139 | # define S_IROTH 0 /* Read others */ |
| 140 | # define S_IWOTH 0 /* Write others */ |
| 141 | # define S_IXOTH 0 /* Execute others */ |
| 142 | #endif |
| 143 | |
| 144 | /* Indicates that d_type field is available in dirent structure */ |
| 145 | #define _DIRENT_HAVE_D_TYPE |
| 146 | |
| 147 | /* File type flags for d_type */ |
| 148 | #define DT_UNKNOWN 0 |
| 149 | #define DT_REG S_IFREG |
| 150 | #define DT_DIR S_IFDIR |
| 151 | #define DT_FIFO S_IFFIFO |
| 152 | #define DT_SOCK S_IFSOCK |
| 153 | #define DT_CHR S_IFCHR |
| 154 | #define DT_BLK S_IFBLK |
| 155 | |
| 156 | /* Macros for converting between st_mode and d_type */ |
| @@ -161,41 +196,31 @@ | |
| 161 | * File type macros. Note that block devices, sockets and links cannot be |
| 162 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are |
| 163 | * only defined for compatibility. These macros should always return false |
| 164 | * on Windows. |
| 165 | */ |
| 166 | #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO) |
| 167 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) |
| 168 | #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) |
| 169 | #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) |
| 170 | #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) |
| 171 | #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) |
| 172 | #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) |
| 173 | |
| 174 | /* For compatiblity with Unix */ |
| 175 | #if !defined(PATH_MAX) |
| 176 | # define PATH_MAX MAX_PATH |
| 177 | #endif |
| 178 | #if !defined(FILENAME_MAX) |
| 179 | # define FILENAME_MAX MAX_PATH |
| 180 | #endif |
| 181 | #if !defined(NAME_MAX) |
| 182 | # define NAME_MAX FILENAME_MAX |
| 183 | #endif |
| 184 | |
| 185 | /* Set errno variable */ |
| 186 | #if defined(_MSC_VER) |
| 187 | #define DIRENT_SET_ERRNO(x) _set_errno (x) |
| 188 | #else |
| 189 | #define DIRENT_SET_ERRNO(x) (errno = (x)) |
| 190 | #endif |
| 191 | |
| 192 | #ifdef __cplusplus |
| 193 | extern "C" { |
| 194 | #endif |
| 195 | |
| 196 | /* Wide-character versions */ |
| 197 | struct _wdirent { |
| 198 | long d_ino; /* Always zero */ |
| 199 | unsigned short d_reclen; /* Structure size */ |
| 200 | size_t d_namlen; /* Length of name without \0 */ |
| 201 | int d_type; /* File type */ |
| @@ -203,11 +228,11 @@ | |
| 203 | }; |
| 204 | typedef struct _wdirent _wdirent; |
| 205 | |
| 206 | struct _WDIR { |
| 207 | struct _wdirent ent; /* Current directory entry */ |
| 208 | WIN32_FIND_DATAW find_data; /* Private file data */ |
| 209 | int cached; /* True if data is valid */ |
| 210 | HANDLE handle; /* Win32 search handle */ |
| 211 | wchar_t *patt; /* Initial directory name */ |
| 212 | }; |
| 213 | typedef struct _WDIR _WDIR; |
| @@ -214,10 +239,11 @@ | |
| 214 | |
| 215 | static _WDIR *_wopendir (const wchar_t *dirname); |
| 216 | static struct _wdirent *_wreaddir (_WDIR *dirp); |
| 217 | static int _wclosedir (_WDIR *dirp); |
| 218 | static void _wrewinddir (_WDIR* dirp); |
| 219 | |
| 220 | /* For compatibility with Symbian */ |
| 221 | #define wdirent _wdirent |
| 222 | #define WDIR _WDIR |
| 223 | #define wopendir _wopendir |
| @@ -246,10 +272,30 @@ | |
| 246 | static struct dirent *readdir (DIR *dirp); |
| 247 | static int closedir (DIR *dirp); |
| 248 | static void rewinddir (DIR* dirp); |
| 249 | |
| 250 | |
| 251 | /* |
| 252 | * Open directory stream DIRNAME for read and return a pointer to the |
| 253 | * internal working area that is used to retrieve individual directory |
| 254 | * entries. |
| 255 | */ |
| @@ -256,31 +302,38 @@ | |
| 256 | static _WDIR* |
| 257 | _wopendir( |
| 258 | const wchar_t *dirname) |
| 259 | { |
| 260 | _WDIR *dirp = NULL; |
| 261 | int error = 0; |
| 262 | |
| 263 | /* Allocate new _WDIR structure */ |
| 264 | dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); |
| 265 | if (dirp != NULL) { |
| 266 | DWORD n; |
| 267 | |
| 268 | /* Reset _WDIR structure */ |
| 269 | dirp->handle = INVALID_HANDLE_VALUE; |
| 270 | dirp->patt = NULL; |
| 271 | |
| 272 | /* Compute the length of full path plus zero terminator */ |
| 273 | n = GetFullPathNameW (dirname, 0, NULL, NULL); |
| 274 | |
| 275 | /* Allocate room for full path and search patterns */ |
| 276 | dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); |
| 277 | if (dirp->patt) { |
| 278 | |
| 279 | /* |
| 280 | * Convert relative directory name to an absolute one. This |
| 281 | * allows rewinddir() to function correctly when the current |
| 282 | * working directory is changed between opendir() and rewinddir(). |
| 283 | */ |
| 284 | n = GetFullPathNameW (dirname, n, dirp->patt, NULL); |
| 285 | if (n > 0) { |
| 286 | wchar_t *p; |
| @@ -303,25 +356,22 @@ | |
| 303 | } |
| 304 | *p++ = '*'; |
| 305 | *p = '\0'; |
| 306 | |
| 307 | /* Open directory stream and retrieve the first entry */ |
| 308 | dirp->handle = FindFirstFileW (dirp->patt, &dirp->find_data); |
| 309 | if (dirp->handle != INVALID_HANDLE_VALUE) { |
| 310 | |
| 311 | /* Directory entry is now waiting in memory */ |
| 312 | dirp->cached = 1; |
| 313 | |
| 314 | } else { |
| 315 | /* Search pattern is not a directory name? */ |
| 316 | DIRENT_SET_ERRNO (ENOENT); |
| 317 | error = 1; |
| 318 | } |
| 319 | |
| 320 | } else { |
| 321 | /* Cannot convert directory name to wide character string */ |
| 322 | DIRENT_SET_ERRNO (ENOENT); |
| 323 | error = 1; |
| 324 | } |
| 325 | |
| 326 | } else { |
| 327 | /* Cannot allocate memory for search pattern */ |
| @@ -350,70 +400,59 @@ | |
| 350 | */ |
| 351 | static struct _wdirent* |
| 352 | _wreaddir( |
| 353 | _WDIR *dirp) |
| 354 | { |
| 355 | DWORD attr; |
| 356 | errno_t error; |
| 357 | |
| 358 | /* Get next directory entry */ |
| 359 | if (dirp->cached != 0) { |
| 360 | /* A valid directory entry already in memory */ |
| 361 | dirp->cached = 0; |
| 362 | } else { |
| 363 | /* Get the next directory entry from stream */ |
| 364 | if (dirp->handle == INVALID_HANDLE_VALUE) { |
| 365 | return NULL; |
| 366 | } |
| 367 | if (FindNextFileW (dirp->handle, &dirp->find_data) == FALSE) { |
| 368 | /* The very last entry has been processed or an error occured */ |
| 369 | FindClose (dirp->handle); |
| 370 | dirp->handle = INVALID_HANDLE_VALUE; |
| 371 | return NULL; |
| 372 | } |
| 373 | } |
| 374 | |
| 375 | /* Copy file name as a wide-character string */ |
| 376 | error = wcsncpy_s( |
| 377 | dirp->ent.d_name, /* Destination string */ |
| 378 | PATH_MAX, /* Size of dest in words */ |
| 379 | dirp->find_data.cFileName, /* Source string */ |
| 380 | PATH_MAX + 1); /* Max # of chars to copy */ |
| 381 | if (!error) { |
| 382 | |
| 383 | /* Compute the length of name */ |
| 384 | dirp->ent.d_namlen = wcsnlen (dirp->ent.d_name, PATH_MAX); |
| 385 | |
| 386 | /* Determine file type */ |
| 387 | attr = dirp->find_data.dwFileAttributes; |
| 388 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { |
| 389 | dirp->ent.d_type = DT_CHR; |
| 390 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 391 | dirp->ent.d_type = DT_DIR; |
| 392 | } else { |
| 393 | dirp->ent.d_type = DT_REG; |
| 394 | } |
| 395 | |
| 396 | /* Reset dummy fields */ |
| 397 | dirp->ent.d_ino = 0; |
| 398 | dirp->ent.d_reclen = sizeof (dirp->ent); |
| 399 | |
| 400 | } else { |
| 401 | |
| 402 | /* |
| 403 | * Cannot copy file name from find_data to ent. Construct a |
| 404 | * dummy _wdirent structure to pass error to caller. |
| 405 | */ |
| 406 | dirp->ent.d_name[0] = '?'; |
| 407 | dirp->ent.d_name[1] = '\0'; |
| 408 | dirp->ent.d_namlen = 1; |
| 409 | dirp->ent.d_type = DT_UNKNOWN; |
| 410 | dirp->ent.d_ino = 0; |
| 411 | dirp->ent.d_reclen = 0; |
| 412 | } |
| 413 | |
| 414 | return &dirp->ent; |
| 415 | } |
| 416 | |
| 417 | /* |
| 418 | * Close directory stream opened by opendir() function. This invalidates the |
| 419 | * DIR structure as well as any directory entry read previously by |
| @@ -442,11 +481,11 @@ | |
| 442 | free (dirp); |
| 443 | ok = /*success*/0; |
| 444 | |
| 445 | } else { |
| 446 | /* Invalid directory stream */ |
| 447 | DIRENT_SET_ERRNO (EBADF); |
| 448 | ok = /*failure*/-1; |
| 449 | } |
| 450 | return ok; |
| 451 | } |
| 452 | |
| @@ -456,26 +495,81 @@ | |
| 456 | */ |
| 457 | static void |
| 458 | _wrewinddir( |
| 459 | _WDIR* dirp) |
| 460 | { |
| 461 | if (dirp != NULL) { |
| 462 | /* release search handle */ |
| 463 | if (dirp->handle != INVALID_HANDLE_VALUE) { |
| 464 | FindClose (dirp->handle); |
| 465 | } |
| 466 | |
| 467 | /* Open new search handle and retrieve the first directory entry */ |
| 468 | dirp->handle = FindFirstFileW (dirp->patt, &dirp->find_data); |
| 469 | if (dirp->handle != INVALID_HANDLE_VALUE) { |
| 470 | /* a directory entry is now waiting in memory */ |
| 471 | dirp->cached = 1; |
| 472 | } else { |
| 473 | /* Failed to re-open directory: no directory entry in memory */ |
| 474 | dirp->cached = 0; |
| 475 | } |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | /* |
| 480 | * Open directory stream using plain old C-string. |
| 481 | */ |
| @@ -482,58 +576,34 @@ | |
| 482 | static DIR* |
| 483 | opendir( |
| 484 | const char *dirname) |
| 485 | { |
| 486 | struct DIR *dirp; |
| 487 | errno_t error = 0; |
| 488 | |
| 489 | /* Must have directory name */ |
| 490 | if (dirname == NULL) { |
| 491 | DIRENT_SET_ERRNO (ENOENT); |
| 492 | return NULL; |
| 493 | } |
| 494 | |
| 495 | /* Allocate memory for multi-byte string directory structures */ |
| 496 | dirp = (DIR*) malloc (sizeof (struct DIR)); |
| 497 | if (dirp) { |
| 498 | wchar_t wname[PATH_MAX + 1]; |
| 499 | size_t n; |
| 500 | |
| 501 | /* |
| 502 | * Convert directory name to wide-character string. |
| 503 | * |
| 504 | * Be ware of the return schemantics of MultiByteToWideChar() -- |
| 505 | * the function basically returns the number of characters written to |
| 506 | * output buffer or zero if the conversion fails. However, the |
| 507 | * function does not necessarily zero-terminate the output |
| 508 | * buffer and may return 0xFFFD if the string contains invalid |
| 509 | * characters! |
| 510 | */ |
| 511 | n = MultiByteToWideChar( |
| 512 | CP_ACP, /* Input code page */ |
| 513 | MB_PRECOMPOSED, /* Conversion flags */ |
| 514 | dirname, /* Input string */ |
| 515 | -1, /* Length of input string */ |
| 516 | wname, /* Output buffer */ |
| 517 | PATH_MAX); /* Size of output buffer */ |
| 518 | if (n > 0 && n < PATH_MAX) { |
| 519 | |
| 520 | /* Zero-terminate output buffer */ |
| 521 | wname[n] = '\0'; |
| 522 | |
| 523 | /* Open directory stream with wide-character string file name */ |
| 524 | dirp->wdirp = _wopendir (wname); |
| 525 | if (dirp->wdirp) { |
| 526 | |
| 527 | /* Initialize directory structure */ |
| 528 | dirp->ent.d_name[0] = '\0'; |
| 529 | dirp->ent.d_namlen = 0; |
| 530 | dirp->ent.d_type = 0; |
| 531 | dirp->ent.d_ino = 0; |
| 532 | dirp->ent.d_reclen = 0; |
| 533 | |
| 534 | |
| 535 | } else { |
| 536 | /* Failed to open directory stream */ |
| 537 | error = 1; |
| 538 | } |
| 539 | |
| @@ -562,95 +632,99 @@ | |
| 562 | } |
| 563 | |
| 564 | /* |
| 565 | * Read next directory entry. |
| 566 | * |
| 567 | * When working with console, please note that file names returned by |
| 568 | * readdir() are represented in the default ANSI code page while the |
| 569 | * console typically runs on another code page. Thus, non-ASCII characters |
| 570 | * will not usually display correctly. The problem can be fixed in two ways: |
| 571 | * (1) change the character set of console to 1252 using chcp utility and use |
| 572 | * Lucida Console font, or (2) always use _cprintf function when writing to |
| 573 | * console. The _cprinf() will re-encode ANSI strings to the console code |
| 574 | * page so non-ASCII characters will display correcly. |
| 575 | */ |
| 576 | static struct dirent* |
| 577 | readdir( |
| 578 | DIR *dirp) |
| 579 | { |
| 580 | struct dirent *p; |
| 581 | struct _wdirent *wp; |
| 582 | |
| 583 | /* Read next directory entry using wide-character string functions */ |
| 584 | wp = _wreaddir (dirp->wdirp); |
| 585 | if (wp) { |
| 586 | size_t n; |
| 587 | |
| 588 | /* |
| 589 | * Convert file name to multi-byte string. |
| 590 | * |
| 591 | * Be ware of the return schemantics of WideCharToMultiByte() -- |
| 592 | * the function basically returns the number of bytes |
| 593 | * written to output buffer or zero if the conversion fails. |
| 594 | * However, the function does not necessarily zero-terminate the |
| 595 | * buffer and it may even return 0xFFFD the string contains |
| 596 | * invalid characters! |
| 597 | */ |
| 598 | n = WideCharToMultiByte( |
| 599 | CP_ACP, /* Output code page */ |
| 600 | 0, /* Conversion flags */ |
| 601 | wp->d_name, /* Input string */ |
| 602 | wp->d_namlen, /* Length of input string */ |
| 603 | dirp->ent.d_name, /* Output buffer */ |
| 604 | PATH_MAX, /* Size of output buffer */ |
| 605 | NULL, /* Replacement character */ |
| 606 | NULL); /* If chars were replaced */ |
| 607 | if (n > 0 && n < PATH_MAX) { |
| 608 | |
| 609 | /* Zero-terminate buffer */ |
| 610 | dirp->ent.d_name[n] = '\0'; |
| 611 | |
| 612 | /* Initialize directory entry for return */ |
| 613 | p = &dirp->ent; |
| 614 | |
| 615 | /* Compute length */ |
| 616 | p->d_namlen = strnlen (dirp->ent.d_name, PATH_MAX); |
| 617 | |
| 618 | /* Copy file attributes */ |
| 619 | p->d_type = wp->d_type; |
| 620 | |
| 621 | /* Reset dummy fields */ |
| 622 | p->d_ino = 0; |
| 623 | p->d_reclen = sizeof (dirp->ent); |
| 624 | |
| 625 | |
| 626 | } else { |
| 627 | |
| 628 | /* |
| 629 | * Cannot convert file name to multi-byte string so construct |
| 630 | * an errornous directory entry and return that. Note that |
| 631 | * we cannot return NULL as that would stop the processing |
| 632 | * of directory entries completely. |
| 633 | */ |
| 634 | p = &dirp->ent; |
| 635 | p->d_name[0] = '?'; |
| 636 | p->d_name[1] = '\0'; |
| 637 | p->d_namlen = 1; |
| 638 | p->d_type = DT_UNKNOWN; |
| 639 | p->d_ino = 0; |
| 640 | p->d_reclen = 0; |
| 641 | |
| 642 | } |
| 643 | |
| 644 | } else { |
| 645 | |
| 646 | /* End of directory stream */ |
| 647 | p = NULL; |
| 648 | |
| 649 | } |
| 650 | |
| 651 | return p; |
| 652 | } |
| 653 | |
| 654 | /* |
| 655 | * Close directory stream. |
| 656 | */ |
| @@ -667,13 +741,15 @@ | |
| 667 | |
| 668 | /* Release multi-byte character version */ |
| 669 | free (dirp); |
| 670 | |
| 671 | } else { |
| 672 | /* Invalid directory stream */ |
| 673 | DIRENT_SET_ERRNO (EBADF); |
| 674 | ok = /*failure*/-1; |
| 675 | } |
| 676 | return ok; |
| 677 | } |
| 678 | |
| 679 | /* |
| @@ -684,12 +760,130 @@ | |
| 684 | DIR* dirp) |
| 685 | { |
| 686 | /* Rewind wide-character string directory stream */ |
| 687 | _wrewinddir (dirp->wdirp); |
| 688 | } |
| 689 | |
| 690 | |
| 691 | #ifdef __cplusplus |
| 692 | } |
| 693 | #endif |
| 694 | #endif /*DIRENT_H*/ |
| 695 | |
| 696 |
| --- win/include/dirent.h | |
| +++ win/include/dirent.h | |
| @@ -20,21 +20,24 @@ | |
| 20 | * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 21 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| 22 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| 23 | * OTHER DEALINGS IN THE SOFTWARE. |
| 24 | * |
| 25 | * |
| 26 | * Version 1.13, Dec 12 2012, Toni Ronkko |
| 27 | * Use traditional 8+3 file name if the name cannot be represented in the |
| 28 | * default ANSI code page. Now compiles again with MSVC 6.0. Thanks to |
| 29 | * Konstantin Khomoutov for testing. |
| 30 | * |
| 31 | * Version 1.12.1, Oct 1 2012, Toni Ronkko |
| 32 | * Bug fix: renamed wide-character DIR structure _wDIR to _WDIR (with |
| 33 | * capital W) in order to maintain compatibility with MingW. |
| 34 | * |
| 35 | * Version 1.12, Sep 30 2012, Toni Ronkko |
| 36 | * Define PATH_MAX and NAME_MAX. Added wide-character variants _wDIR, |
| 37 | * _wdirent, _wopendir(), _wreaddir(), _wclosedir() and _wrewinddir(). |
| 38 | * Thanks to Edgar Buerkle and Jan Nijtmans for ideas and code. |
| 39 | * |
| 40 | * Do not include windows.h. This allows dirent.h to be integrated more |
| 41 | * easily into programs using winsock. Thanks to Fernando Azaldegui. |
| 42 | * |
| 43 | * Version 1.11, Mar 15, 2011, Toni Ronkko |
| @@ -88,48 +91,72 @@ | |
| 91 | *****************************************************************************/ |
| 92 | #ifndef DIRENT_H |
| 93 | #define DIRENT_H |
| 94 | |
| 95 | #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) |
| 96 | # define _X86_ |
| 97 | #endif |
| 98 | #include <stdio.h> |
| 99 | #include <stdarg.h> |
| 100 | #include <windef.h> |
| 101 | #include <winbase.h> |
| 102 | #include <wchar.h> |
| 103 | #include <string.h> |
| 104 | #include <stdlib.h> |
| 105 | #include <malloc.h> |
| 106 | #include <sys/types.h> |
| 107 | #include <sys/stat.h> |
| 108 | #include <errno.h> |
| 109 | |
| 110 | /* Indicates that d_type field is available in dirent structure */ |
| 111 | #define _DIRENT_HAVE_D_TYPE |
| 112 | |
| 113 | /* Indicates that d_namlen field is available in dirent structure */ |
| 114 | #define _DIRENT_HAVE_D_NAMLEN |
| 115 | |
| 116 | /* Entries missing from MSVC 6.0 */ |
| 117 | #if !defined(FILE_ATTRIBUTE_DEVICE) |
| 118 | # define FILE_ATTRIBUTE_DEVICE 0x40 |
| 119 | #endif |
| 120 | |
| 121 | /* File type and permission flags for stat() */ |
| 122 | #if !defined(S_IFMT) |
| 123 | # define S_IFMT _S_IFMT /* File type mask */ |
| 124 | #endif |
| 125 | #if !defined(S_IFDIR) |
| 126 | # define S_IFDIR _S_IFDIR /* Directory */ |
| 127 | #endif |
| 128 | #if !defined(S_IFCHR) |
| 129 | # define S_IFCHR _S_IFCHR /* Character device */ |
| 130 | #endif |
| 131 | #if !defined(S_IFFIFO) |
| 132 | # define S_IFFIFO _S_IFFIFO /* Pipe */ |
| 133 | #endif |
| 134 | #if !defined(S_IFREG) |
| 135 | # define S_IFREG _S_IFREG /* Regular file */ |
| 136 | #endif |
| 137 | #if !defined(S_IREAD) |
| 138 | # define S_IREAD _S_IREAD /* Read permission */ |
| 139 | #endif |
| 140 | #if !defined(S_IWRITE) |
| 141 | # define S_IWRITE _S_IWRITE /* Write permission */ |
| 142 | #endif |
| 143 | #if !defined(S_IEXEC) |
| 144 | # define S_IEXEC _S_IEXEC /* Execute permission */ |
| 145 | #endif |
| 146 | #if !defined(S_IFIFO) |
| 147 | # define S_IFIFO _S_IFIFO /* Pipe */ |
| 148 | #endif |
| 149 | #if !defined(S_IFBLK) |
| 150 | # define S_IFBLK 0 /* Block device */ |
| 151 | #endif |
| 152 | #if !defined(S_IFLNK) |
| 153 | # define S_IFLNK 0 /* Link */ |
| 154 | #endif |
| 155 | #if !defined(S_IFSOCK) |
| 156 | # define S_IFSOCK 0 /* Socket */ |
| 157 | #endif |
| 158 | |
| 159 | #if defined(_MSC_VER) |
| 160 | # define S_IRUSR S_IREAD /* Read user */ |
| 161 | # define S_IWUSR S_IWRITE /* Write user */ |
| 162 | # define S_IXUSR 0 /* Execute user */ |
| @@ -139,18 +166,26 @@ | |
| 166 | # define S_IROTH 0 /* Read others */ |
| 167 | # define S_IWOTH 0 /* Write others */ |
| 168 | # define S_IXOTH 0 /* Execute others */ |
| 169 | #endif |
| 170 | |
| 171 | /* Maximum length of file name */ |
| 172 | #if !defined(PATH_MAX) |
| 173 | # define PATH_MAX MAX_PATH |
| 174 | #endif |
| 175 | #if !defined(FILENAME_MAX) |
| 176 | # define FILENAME_MAX MAX_PATH |
| 177 | #endif |
| 178 | #if !defined(NAME_MAX) |
| 179 | # define NAME_MAX FILENAME_MAX |
| 180 | #endif |
| 181 | |
| 182 | /* File type flags for d_type */ |
| 183 | #define DT_UNKNOWN 0 |
| 184 | #define DT_REG S_IFREG |
| 185 | #define DT_DIR S_IFDIR |
| 186 | #define DT_FIFO S_IFIFO |
| 187 | #define DT_SOCK S_IFSOCK |
| 188 | #define DT_CHR S_IFCHR |
| 189 | #define DT_BLK S_IFBLK |
| 190 | |
| 191 | /* Macros for converting between st_mode and d_type */ |
| @@ -161,41 +196,31 @@ | |
| 196 | * File type macros. Note that block devices, sockets and links cannot be |
| 197 | * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are |
| 198 | * only defined for compatibility. These macros should always return false |
| 199 | * on Windows. |
| 200 | */ |
| 201 | #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) |
| 202 | #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) |
| 203 | #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) |
| 204 | #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) |
| 205 | #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) |
| 206 | #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) |
| 207 | #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) |
| 208 | |
| 209 | /* Return the exact length of d_namlen without zero terminator */ |
| 210 | #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) |
| 211 | |
| 212 | /* Return number of bytes needed to store d_namlen */ |
| 213 | #define _D_ALLOC_NAMLEN(p) (PATH_MAX + 1) |
| 214 | |
| 215 | |
| 216 | #ifdef __cplusplus |
| 217 | extern "C" { |
| 218 | #endif |
| 219 | |
| 220 | |
| 221 | /* Wide-character version */ |
| 222 | struct _wdirent { |
| 223 | long d_ino; /* Always zero */ |
| 224 | unsigned short d_reclen; /* Structure size */ |
| 225 | size_t d_namlen; /* Length of name without \0 */ |
| 226 | int d_type; /* File type */ |
| @@ -203,11 +228,11 @@ | |
| 228 | }; |
| 229 | typedef struct _wdirent _wdirent; |
| 230 | |
| 231 | struct _WDIR { |
| 232 | struct _wdirent ent; /* Current directory entry */ |
| 233 | WIN32_FIND_DATAW data; /* Private file data */ |
| 234 | int cached; /* True if data is valid */ |
| 235 | HANDLE handle; /* Win32 search handle */ |
| 236 | wchar_t *patt; /* Initial directory name */ |
| 237 | }; |
| 238 | typedef struct _WDIR _WDIR; |
| @@ -214,10 +239,11 @@ | |
| 239 | |
| 240 | static _WDIR *_wopendir (const wchar_t *dirname); |
| 241 | static struct _wdirent *_wreaddir (_WDIR *dirp); |
| 242 | static int _wclosedir (_WDIR *dirp); |
| 243 | static void _wrewinddir (_WDIR* dirp); |
| 244 | |
| 245 | |
| 246 | /* For compatibility with Symbian */ |
| 247 | #define wdirent _wdirent |
| 248 | #define WDIR _WDIR |
| 249 | #define wopendir _wopendir |
| @@ -246,10 +272,30 @@ | |
| 272 | static struct dirent *readdir (DIR *dirp); |
| 273 | static int closedir (DIR *dirp); |
| 274 | static void rewinddir (DIR* dirp); |
| 275 | |
| 276 | |
| 277 | /* Internal utility functions */ |
| 278 | static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp); |
| 279 | static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp); |
| 280 | |
| 281 | static int dirent_mbstowcs_s( |
| 282 | size_t *pReturnValue, |
| 283 | wchar_t *wcstr, |
| 284 | size_t sizeInWords, |
| 285 | const char *mbstr, |
| 286 | size_t count); |
| 287 | |
| 288 | static int dirent_wcstombs_s( |
| 289 | size_t *pReturnValue, |
| 290 | char *mbstr, |
| 291 | size_t sizeInBytes, |
| 292 | const wchar_t *wcstr, |
| 293 | size_t count); |
| 294 | |
| 295 | static void dirent_set_errno (int error); |
| 296 | |
| 297 | /* |
| 298 | * Open directory stream DIRNAME for read and return a pointer to the |
| 299 | * internal working area that is used to retrieve individual directory |
| 300 | * entries. |
| 301 | */ |
| @@ -256,31 +302,38 @@ | |
| 302 | static _WDIR* |
| 303 | _wopendir( |
| 304 | const wchar_t *dirname) |
| 305 | { |
| 306 | _WDIR *dirp = NULL; |
| 307 | int error; |
| 308 | |
| 309 | /* Must have directory name */ |
| 310 | if (dirname == NULL || dirname[0] == '\0') { |
| 311 | dirent_set_errno (ENOENT); |
| 312 | return NULL; |
| 313 | } |
| 314 | |
| 315 | /* Allocate new _WDIR structure */ |
| 316 | dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); |
| 317 | if (dirp != NULL) { |
| 318 | DWORD n; |
| 319 | |
| 320 | /* Reset _WDIR structure */ |
| 321 | dirp->handle = INVALID_HANDLE_VALUE; |
| 322 | dirp->patt = NULL; |
| 323 | dirp->cached = 0; |
| 324 | |
| 325 | /* Compute the length of full path plus zero terminator */ |
| 326 | n = GetFullPathNameW (dirname, 0, NULL, NULL); |
| 327 | |
| 328 | /* Allocate room for absolute directory name and search pattern */ |
| 329 | dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); |
| 330 | if (dirp->patt) { |
| 331 | |
| 332 | /* |
| 333 | * Convert relative directory name to an absolute one. This |
| 334 | * allows rewinddir() to function correctly even when current |
| 335 | * working directory is changed between opendir() and rewinddir(). |
| 336 | */ |
| 337 | n = GetFullPathNameW (dirname, n, dirp->patt, NULL); |
| 338 | if (n > 0) { |
| 339 | wchar_t *p; |
| @@ -303,25 +356,22 @@ | |
| 356 | } |
| 357 | *p++ = '*'; |
| 358 | *p = '\0'; |
| 359 | |
| 360 | /* Open directory stream and retrieve the first entry */ |
| 361 | if (dirent_first (dirp)) { |
| 362 | /* Directory stream opened successfully */ |
| 363 | error = 0; |
| 364 | } else { |
| 365 | /* Cannot retrieve first entry */ |
| 366 | error = 1; |
| 367 | dirent_set_errno (ENOENT); |
| 368 | } |
| 369 | |
| 370 | } else { |
| 371 | /* Cannot retrieve full path name */ |
| 372 | dirent_set_errno (ENOENT); |
| 373 | error = 1; |
| 374 | } |
| 375 | |
| 376 | } else { |
| 377 | /* Cannot allocate memory for search pattern */ |
| @@ -350,70 +400,59 @@ | |
| 400 | */ |
| 401 | static struct _wdirent* |
| 402 | _wreaddir( |
| 403 | _WDIR *dirp) |
| 404 | { |
| 405 | WIN32_FIND_DATAW *datap; |
| 406 | struct _wdirent *entp; |
| 407 | |
| 408 | /* Read next directory entry */ |
| 409 | datap = dirent_next (dirp); |
| 410 | if (datap) { |
| 411 | size_t n; |
| 412 | DWORD attr; |
| 413 | |
| 414 | /* Pointer to directory entry to return */ |
| 415 | entp = &dirp->ent; |
| 416 | |
| 417 | /* |
| 418 | * Copy file name as wide-character string. If the file name is too |
| 419 | * long to fit in to the destination buffer, then truncate file name |
| 420 | * to PATH_MAX characters and zero-terminate the buffer. |
| 421 | */ |
| 422 | n = 0; |
| 423 | while (n < PATH_MAX && datap->cFileName[n] != 0) { |
| 424 | entp->d_name[n] = datap->cFileName[n]; |
| 425 | n++; |
| 426 | } |
| 427 | dirp->ent.d_name[n] = 0; |
| 428 | |
| 429 | /* Length of file name excluding zero terminator */ |
| 430 | entp->d_namlen = n; |
| 431 | |
| 432 | /* File type */ |
| 433 | attr = datap->dwFileAttributes; |
| 434 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { |
| 435 | entp->d_type = DT_CHR; |
| 436 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 437 | entp->d_type = DT_DIR; |
| 438 | } else { |
| 439 | entp->d_type = DT_REG; |
| 440 | } |
| 441 | |
| 442 | /* Reset dummy fields */ |
| 443 | entp->d_ino = 0; |
| 444 | entp->d_reclen = sizeof (struct _wdirent); |
| 445 | |
| 446 | } else { |
| 447 | |
| 448 | /* Last directory entry read */ |
| 449 | entp = NULL; |
| 450 | |
| 451 | } |
| 452 | |
| 453 | return entp; |
| 454 | } |
| 455 | |
| 456 | /* |
| 457 | * Close directory stream opened by opendir() function. This invalidates the |
| 458 | * DIR structure as well as any directory entry read previously by |
| @@ -442,11 +481,11 @@ | |
| 481 | free (dirp); |
| 482 | ok = /*success*/0; |
| 483 | |
| 484 | } else { |
| 485 | /* Invalid directory stream */ |
| 486 | dirent_set_errno (EBADF); |
| 487 | ok = /*failure*/-1; |
| 488 | } |
| 489 | return ok; |
| 490 | } |
| 491 | |
| @@ -456,26 +495,81 @@ | |
| 495 | */ |
| 496 | static void |
| 497 | _wrewinddir( |
| 498 | _WDIR* dirp) |
| 499 | { |
| 500 | if (dirp) { |
| 501 | /* Release existing search handle */ |
| 502 | if (dirp->handle != INVALID_HANDLE_VALUE) { |
| 503 | FindClose (dirp->handle); |
| 504 | } |
| 505 | |
| 506 | /* Open new search handle */ |
| 507 | dirent_first (dirp); |
| 508 | } |
| 509 | } |
| 510 | |
| 511 | /* Get first directory entry (internal) */ |
| 512 | static WIN32_FIND_DATAW* |
| 513 | dirent_first( |
| 514 | _WDIR *dirp) |
| 515 | { |
| 516 | WIN32_FIND_DATAW *datap; |
| 517 | |
| 518 | /* Open directory and retrieve the first entry */ |
| 519 | dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); |
| 520 | if (dirp->handle != INVALID_HANDLE_VALUE) { |
| 521 | |
| 522 | /* a directory entry is now waiting in memory */ |
| 523 | datap = &dirp->data; |
| 524 | dirp->cached = 1; |
| 525 | |
| 526 | } else { |
| 527 | |
| 528 | /* Failed to re-open directory: no directory entry in memory */ |
| 529 | dirp->cached = 0; |
| 530 | datap = NULL; |
| 531 | |
| 532 | } |
| 533 | return datap; |
| 534 | } |
| 535 | |
| 536 | /* Get next directory entry (internal) */ |
| 537 | static WIN32_FIND_DATAW* |
| 538 | dirent_next( |
| 539 | _WDIR *dirp) |
| 540 | { |
| 541 | WIN32_FIND_DATAW *p; |
| 542 | |
| 543 | /* Get next directory entry */ |
| 544 | if (dirp->cached != 0) { |
| 545 | |
| 546 | /* A valid directory entry already in memory */ |
| 547 | p = &dirp->data; |
| 548 | dirp->cached = 0; |
| 549 | |
| 550 | } else if (dirp->handle != INVALID_HANDLE_VALUE) { |
| 551 | |
| 552 | /* Get the next directory entry from stream */ |
| 553 | if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) { |
| 554 | /* Got a file */ |
| 555 | p = &dirp->data; |
| 556 | } else { |
| 557 | /* The very last entry has been processed or an error occured */ |
| 558 | FindClose (dirp->handle); |
| 559 | dirp->handle = INVALID_HANDLE_VALUE; |
| 560 | p = NULL; |
| 561 | } |
| 562 | |
| 563 | } else { |
| 564 | |
| 565 | /* End of directory stream reached */ |
| 566 | p = NULL; |
| 567 | |
| 568 | } |
| 569 | |
| 570 | return p; |
| 571 | } |
| 572 | |
| 573 | /* |
| 574 | * Open directory stream using plain old C-string. |
| 575 | */ |
| @@ -482,58 +576,34 @@ | |
| 576 | static DIR* |
| 577 | opendir( |
| 578 | const char *dirname) |
| 579 | { |
| 580 | struct DIR *dirp; |
| 581 | int error; |
| 582 | |
| 583 | /* Must have directory name */ |
| 584 | if (dirname == NULL || dirname[0] == '\0') { |
| 585 | dirent_set_errno (ENOENT); |
| 586 | return NULL; |
| 587 | } |
| 588 | |
| 589 | /* Allocate memory for DIR structure */ |
| 590 | dirp = (DIR*) malloc (sizeof (struct DIR)); |
| 591 | if (dirp) { |
| 592 | wchar_t wname[PATH_MAX + 1]; |
| 593 | size_t n; |
| 594 | |
| 595 | /* Convert directory name to wide-character string */ |
| 596 | error = dirent_mbstowcs_s( |
| 597 | &n, wname, PATH_MAX + 1, dirname, PATH_MAX); |
| 598 | if (!error) { |
| 599 | |
| 600 | /* Open directory stream using wide-character name */ |
| 601 | dirp->wdirp = _wopendir (wname); |
| 602 | if (dirp->wdirp) { |
| 603 | /* Directory stream opened */ |
| 604 | error = 0; |
| 605 | } else { |
| 606 | /* Failed to open directory stream */ |
| 607 | error = 1; |
| 608 | } |
| 609 | |
| @@ -562,95 +632,99 @@ | |
| 632 | } |
| 633 | |
| 634 | /* |
| 635 | * Read next directory entry. |
| 636 | * |
| 637 | * When working with text consoles, please note that file names returned by |
| 638 | * readdir() are represented in the default ANSI code page while any output to |
| 639 | * console is typically formatted on another code page. Thus, non-ASCII |
| 640 | * characters in file names will not usually display correctly on console. The |
| 641 | * problem can be fixed in two ways: (1) change the character set of console |
| 642 | * to 1252 using chcp utility and use Lucida Console font, or (2) use |
| 643 | * _cprintf function when writing to console. The _cprinf() will re-encode |
| 644 | * ANSI strings to the console code page so many non-ASCII characters will |
| 645 | * display correcly. |
| 646 | */ |
| 647 | static struct dirent* |
| 648 | readdir( |
| 649 | DIR *dirp) |
| 650 | { |
| 651 | WIN32_FIND_DATAW *datap; |
| 652 | struct dirent *entp; |
| 653 | |
| 654 | /* Read next directory entry */ |
| 655 | datap = dirent_next (dirp->wdirp); |
| 656 | if (datap) { |
| 657 | size_t n; |
| 658 | int error; |
| 659 | |
| 660 | /* Attempt to convert file name to multi-byte string */ |
| 661 | error = dirent_wcstombs_s( |
| 662 | &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH); |
| 663 | |
| 664 | /* |
| 665 | * If the file name cannot be represented by a multi-byte string, |
| 666 | * then attempt to use old 8+3 file name. This allows traditional |
| 667 | * Unix-code to access some file names despite of unicode |
| 668 | * characters, although file names may seem unfamiliar to the user. |
| 669 | * |
| 670 | * Be ware that the code below cannot come up with a short file |
| 671 | * name unless the file system provides one. At least |
| 672 | * VirtualBox shared folders fail to do this. |
| 673 | */ |
| 674 | if (error && datap->cAlternateFileName[0] != '\0') { |
| 675 | error = dirent_wcstombs_s( |
| 676 | &n, dirp->ent.d_name, MAX_PATH + 1, datap->cAlternateFileName, |
| 677 | sizeof (datap->cAlternateFileName) / |
| 678 | sizeof (datap->cAlternateFileName[0])); |
| 679 | } |
| 680 | |
| 681 | if (!error) { |
| 682 | DWORD attr; |
| 683 | |
| 684 | /* Initialize directory entry for return */ |
| 685 | entp = &dirp->ent; |
| 686 | |
| 687 | /* Length of file name excluding zero terminator */ |
| 688 | entp->d_namlen = n - 1; |
| 689 | |
| 690 | /* File attributes */ |
| 691 | attr = datap->dwFileAttributes; |
| 692 | if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { |
| 693 | entp->d_type = DT_CHR; |
| 694 | } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| 695 | entp->d_type = DT_DIR; |
| 696 | } else { |
| 697 | entp->d_type = DT_REG; |
| 698 | } |
| 699 | |
| 700 | /* Reset dummy fields */ |
| 701 | entp->d_ino = 0; |
| 702 | entp->d_reclen = sizeof (struct dirent); |
| 703 | |
| 704 | } else { |
| 705 | /* |
| 706 | * Cannot convert file name to multi-byte string so construct |
| 707 | * an errornous directory entry and return that. Note that |
| 708 | * we cannot return NULL as that would stop the processing |
| 709 | * of directory entries completely. |
| 710 | */ |
| 711 | entp = &dirp->ent; |
| 712 | entp->d_name[0] = '?'; |
| 713 | entp->d_name[1] = '\0'; |
| 714 | entp->d_namlen = 1; |
| 715 | entp->d_type = DT_UNKNOWN; |
| 716 | entp->d_ino = 0; |
| 717 | entp->d_reclen = 0; |
| 718 | } |
| 719 | |
| 720 | } else { |
| 721 | /* No more directory entries */ |
| 722 | entp = NULL; |
| 723 | } |
| 724 | |
| 725 | return entp; |
| 726 | } |
| 727 | |
| 728 | /* |
| 729 | * Close directory stream. |
| 730 | */ |
| @@ -667,13 +741,15 @@ | |
| 741 | |
| 742 | /* Release multi-byte character version */ |
| 743 | free (dirp); |
| 744 | |
| 745 | } else { |
| 746 | |
| 747 | /* Invalid directory stream */ |
| 748 | dirent_set_errno (EBADF); |
| 749 | ok = /*failure*/-1; |
| 750 | |
| 751 | } |
| 752 | return ok; |
| 753 | } |
| 754 | |
| 755 | /* |
| @@ -684,12 +760,130 @@ | |
| 760 | DIR* dirp) |
| 761 | { |
| 762 | /* Rewind wide-character string directory stream */ |
| 763 | _wrewinddir (dirp->wdirp); |
| 764 | } |
| 765 | |
| 766 | /* Convert multi-byte string to wide character string */ |
| 767 | static int |
| 768 | dirent_mbstowcs_s( |
| 769 | size_t *pReturnValue, |
| 770 | wchar_t *wcstr, |
| 771 | size_t sizeInWords, |
| 772 | const char *mbstr, |
| 773 | size_t count) |
| 774 | { |
| 775 | int error; |
| 776 | |
| 777 | #if defined(_MSC_VER) && _MSC_VER >= 1400 |
| 778 | |
| 779 | /* Microsoft Visual Studio 2005 or later */ |
| 780 | error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); |
| 781 | |
| 782 | #else |
| 783 | |
| 784 | /* Older Visual Studio or non-Microsoft compiler */ |
| 785 | size_t n; |
| 786 | |
| 787 | /* Convert to wide-character string */ |
| 788 | n = mbstowcs (wcstr, mbstr, count); |
| 789 | if (n < sizeInWords) { |
| 790 | |
| 791 | /* Zero-terminate output buffer */ |
| 792 | if (wcstr) { |
| 793 | wcstr[n] = 0; |
| 794 | } |
| 795 | |
| 796 | /* Length of resuting multi-byte string WITH zero terminator */ |
| 797 | if (pReturnValue) { |
| 798 | *pReturnValue = n + 1; |
| 799 | } |
| 800 | |
| 801 | /* Success */ |
| 802 | error = 0; |
| 803 | |
| 804 | } else { |
| 805 | |
| 806 | /* Could not convert string */ |
| 807 | error = 1; |
| 808 | |
| 809 | } |
| 810 | |
| 811 | #endif |
| 812 | |
| 813 | return error; |
| 814 | } |
| 815 | |
| 816 | /* Convert wide-character string to multi-byte string */ |
| 817 | static int |
| 818 | dirent_wcstombs_s( |
| 819 | size_t *pReturnValue, |
| 820 | char *mbstr, |
| 821 | size_t sizeInBytes, |
| 822 | const wchar_t *wcstr, |
| 823 | size_t count) |
| 824 | { |
| 825 | int error; |
| 826 | |
| 827 | #if defined(_MSC_VER) && _MSC_VER >= 1400 |
| 828 | |
| 829 | /* Microsoft Visual Studio 2005 or later */ |
| 830 | error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); |
| 831 | |
| 832 | #else |
| 833 | |
| 834 | /* Older Visual Studio or non-Microsoft compiler */ |
| 835 | size_t n; |
| 836 | |
| 837 | /* Convert to multi-byte string */ |
| 838 | n = wcstombs (mbstr, wcstr, count); |
| 839 | if (n < sizeInBytes) { |
| 840 | |
| 841 | /* Zero-terminate output buffer */ |
| 842 | if (mbstr) { |
| 843 | mbstr[n] = '\0'; |
| 844 | } |
| 845 | |
| 846 | /* Lenght of resulting multi-bytes string WITH zero-terminator */ |
| 847 | if (pReturnValue) { |
| 848 | *pReturnValue = n + 1; |
| 849 | } |
| 850 | |
| 851 | /* Success */ |
| 852 | error = 0; |
| 853 | |
| 854 | } else { |
| 855 | |
| 856 | /* Cannot convert string */ |
| 857 | error = 1; |
| 858 | |
| 859 | } |
| 860 | |
| 861 | #endif |
| 862 | |
| 863 | return error; |
| 864 | } |
| 865 | |
| 866 | /* Set errno variable */ |
| 867 | static void |
| 868 | dirent_set_errno( |
| 869 | int error) |
| 870 | { |
| 871 | #if defined(_MSC_VER) |
| 872 | |
| 873 | /* Microsoft Visual Studio */ |
| 874 | _set_errno (error); |
| 875 | |
| 876 | #else |
| 877 | |
| 878 | /* Non-Microsoft compiler */ |
| 879 | errno = error; |
| 880 | |
| 881 | #endif |
| 882 | } |
| 883 | |
| 884 | |
| 885 | #ifdef __cplusplus |
| 886 | } |
| 887 | #endif |
| 888 | #endif /*DIRENT_H*/ |
| 889 | |
| 890 |