xref: /freebsd/contrib/pkgconf/libpkgconf/win-dirent.h (revision a3cefe7f2b4df0f70ff92d4570ce18e517af43ec)
1*a3cefe7fSPierre Pronchery /*
2*a3cefe7fSPierre Pronchery  * Dirent interface for Microsoft Visual Studio
3*a3cefe7fSPierre Pronchery  *
4*a3cefe7fSPierre Pronchery  * Copyright (C) 1998-2019 Toni Ronkko
5*a3cefe7fSPierre Pronchery  * This file is part of dirent.  Dirent may be freely distributed
6*a3cefe7fSPierre Pronchery  * under the MIT license.  For all details and documentation, see
7*a3cefe7fSPierre Pronchery  * https://github.com/tronkko/dirent
8*a3cefe7fSPierre Pronchery  */
9*a3cefe7fSPierre Pronchery #ifndef DIRENT_H
10*a3cefe7fSPierre Pronchery #define DIRENT_H
11*a3cefe7fSPierre Pronchery 
12*a3cefe7fSPierre Pronchery /* Hide warnings about unreferenced local functions */
13*a3cefe7fSPierre Pronchery #if defined(__clang__)
14*a3cefe7fSPierre Pronchery #	pragma clang diagnostic ignored "-Wunused-function"
15*a3cefe7fSPierre Pronchery #elif defined(_MSC_VER)
16*a3cefe7fSPierre Pronchery #	pragma warning(disable:4505)
17*a3cefe7fSPierre Pronchery #elif defined(__GNUC__)
18*a3cefe7fSPierre Pronchery #	pragma GCC diagnostic ignored "-Wunused-function"
19*a3cefe7fSPierre Pronchery #endif
20*a3cefe7fSPierre Pronchery 
21*a3cefe7fSPierre Pronchery /*
22*a3cefe7fSPierre Pronchery  * Include windows.h without Windows Sockets 1.1 to prevent conflicts with
23*a3cefe7fSPierre Pronchery  * Windows Sockets 2.0.
24*a3cefe7fSPierre Pronchery  */
25*a3cefe7fSPierre Pronchery #ifndef WIN32_LEAN_AND_MEAN
26*a3cefe7fSPierre Pronchery #	define WIN32_LEAN_AND_MEAN
27*a3cefe7fSPierre Pronchery #endif
28*a3cefe7fSPierre Pronchery #include <windows.h>
29*a3cefe7fSPierre Pronchery 
30*a3cefe7fSPierre Pronchery #include <stdio.h>
31*a3cefe7fSPierre Pronchery #include <stdarg.h>
32*a3cefe7fSPierre Pronchery #include <wchar.h>
33*a3cefe7fSPierre Pronchery #include <string.h>
34*a3cefe7fSPierre Pronchery #include <stdlib.h>
35*a3cefe7fSPierre Pronchery #include <malloc.h>
36*a3cefe7fSPierre Pronchery #include <sys/types.h>
37*a3cefe7fSPierre Pronchery #include <sys/stat.h>
38*a3cefe7fSPierre Pronchery #include <errno.h>
39*a3cefe7fSPierre Pronchery #include <ctype.h>
40*a3cefe7fSPierre Pronchery 
41*a3cefe7fSPierre Pronchery /* Indicates that d_type field is available in dirent structure */
42*a3cefe7fSPierre Pronchery #define _DIRENT_HAVE_D_TYPE
43*a3cefe7fSPierre Pronchery 
44*a3cefe7fSPierre Pronchery /* Indicates that d_namlen field is available in dirent structure */
45*a3cefe7fSPierre Pronchery #define _DIRENT_HAVE_D_NAMLEN
46*a3cefe7fSPierre Pronchery 
47*a3cefe7fSPierre Pronchery /* Entries missing from MSVC 6.0 */
48*a3cefe7fSPierre Pronchery #if !defined(FILE_ATTRIBUTE_DEVICE)
49*a3cefe7fSPierre Pronchery #	define FILE_ATTRIBUTE_DEVICE 0x40
50*a3cefe7fSPierre Pronchery #endif
51*a3cefe7fSPierre Pronchery 
52*a3cefe7fSPierre Pronchery /* File type and permission flags for stat(), general mask */
53*a3cefe7fSPierre Pronchery #if !defined(S_IFMT)
54*a3cefe7fSPierre Pronchery #	define S_IFMT _S_IFMT
55*a3cefe7fSPierre Pronchery #endif
56*a3cefe7fSPierre Pronchery 
57*a3cefe7fSPierre Pronchery /* Directory bit */
58*a3cefe7fSPierre Pronchery #if !defined(S_IFDIR)
59*a3cefe7fSPierre Pronchery #	define S_IFDIR _S_IFDIR
60*a3cefe7fSPierre Pronchery #endif
61*a3cefe7fSPierre Pronchery 
62*a3cefe7fSPierre Pronchery /* Character device bit */
63*a3cefe7fSPierre Pronchery #if !defined(S_IFCHR)
64*a3cefe7fSPierre Pronchery #	define S_IFCHR _S_IFCHR
65*a3cefe7fSPierre Pronchery #endif
66*a3cefe7fSPierre Pronchery 
67*a3cefe7fSPierre Pronchery /* Pipe bit */
68*a3cefe7fSPierre Pronchery #if !defined(S_IFFIFO)
69*a3cefe7fSPierre Pronchery #	define S_IFFIFO _S_IFFIFO
70*a3cefe7fSPierre Pronchery #endif
71*a3cefe7fSPierre Pronchery 
72*a3cefe7fSPierre Pronchery /* Regular file bit */
73*a3cefe7fSPierre Pronchery #if !defined(S_IFREG)
74*a3cefe7fSPierre Pronchery #	define S_IFREG _S_IFREG
75*a3cefe7fSPierre Pronchery #endif
76*a3cefe7fSPierre Pronchery 
77*a3cefe7fSPierre Pronchery /* Read permission */
78*a3cefe7fSPierre Pronchery #if !defined(S_IREAD)
79*a3cefe7fSPierre Pronchery #	define S_IREAD _S_IREAD
80*a3cefe7fSPierre Pronchery #endif
81*a3cefe7fSPierre Pronchery 
82*a3cefe7fSPierre Pronchery /* Write permission */
83*a3cefe7fSPierre Pronchery #if !defined(S_IWRITE)
84*a3cefe7fSPierre Pronchery #	define S_IWRITE _S_IWRITE
85*a3cefe7fSPierre Pronchery #endif
86*a3cefe7fSPierre Pronchery 
87*a3cefe7fSPierre Pronchery /* Execute permission */
88*a3cefe7fSPierre Pronchery #if !defined(S_IEXEC)
89*a3cefe7fSPierre Pronchery #	define S_IEXEC _S_IEXEC
90*a3cefe7fSPierre Pronchery #endif
91*a3cefe7fSPierre Pronchery 
92*a3cefe7fSPierre Pronchery /* Pipe */
93*a3cefe7fSPierre Pronchery #if !defined(S_IFIFO)
94*a3cefe7fSPierre Pronchery #	define S_IFIFO _S_IFIFO
95*a3cefe7fSPierre Pronchery #endif
96*a3cefe7fSPierre Pronchery 
97*a3cefe7fSPierre Pronchery /* Block device */
98*a3cefe7fSPierre Pronchery #if !defined(S_IFBLK)
99*a3cefe7fSPierre Pronchery #	define S_IFBLK 0
100*a3cefe7fSPierre Pronchery #endif
101*a3cefe7fSPierre Pronchery 
102*a3cefe7fSPierre Pronchery /* Link */
103*a3cefe7fSPierre Pronchery #if !defined(S_IFLNK)
104*a3cefe7fSPierre Pronchery #	define S_IFLNK 0
105*a3cefe7fSPierre Pronchery #endif
106*a3cefe7fSPierre Pronchery 
107*a3cefe7fSPierre Pronchery /* Socket */
108*a3cefe7fSPierre Pronchery #if !defined(S_IFSOCK)
109*a3cefe7fSPierre Pronchery #	define S_IFSOCK 0
110*a3cefe7fSPierre Pronchery #endif
111*a3cefe7fSPierre Pronchery 
112*a3cefe7fSPierre Pronchery /* Read user permission */
113*a3cefe7fSPierre Pronchery #if !defined(S_IRUSR)
114*a3cefe7fSPierre Pronchery #	define S_IRUSR S_IREAD
115*a3cefe7fSPierre Pronchery #endif
116*a3cefe7fSPierre Pronchery 
117*a3cefe7fSPierre Pronchery /* Write user permission */
118*a3cefe7fSPierre Pronchery #if !defined(S_IWUSR)
119*a3cefe7fSPierre Pronchery #	define S_IWUSR S_IWRITE
120*a3cefe7fSPierre Pronchery #endif
121*a3cefe7fSPierre Pronchery 
122*a3cefe7fSPierre Pronchery /* Execute user permission */
123*a3cefe7fSPierre Pronchery #if !defined(S_IXUSR)
124*a3cefe7fSPierre Pronchery #	define S_IXUSR 0
125*a3cefe7fSPierre Pronchery #endif
126*a3cefe7fSPierre Pronchery 
127*a3cefe7fSPierre Pronchery /* Read group permission */
128*a3cefe7fSPierre Pronchery #if !defined(S_IRGRP)
129*a3cefe7fSPierre Pronchery #	define S_IRGRP 0
130*a3cefe7fSPierre Pronchery #endif
131*a3cefe7fSPierre Pronchery 
132*a3cefe7fSPierre Pronchery /* Write group permission */
133*a3cefe7fSPierre Pronchery #if !defined(S_IWGRP)
134*a3cefe7fSPierre Pronchery #	define S_IWGRP 0
135*a3cefe7fSPierre Pronchery #endif
136*a3cefe7fSPierre Pronchery 
137*a3cefe7fSPierre Pronchery /* Execute group permission */
138*a3cefe7fSPierre Pronchery #if !defined(S_IXGRP)
139*a3cefe7fSPierre Pronchery #	define S_IXGRP 0
140*a3cefe7fSPierre Pronchery #endif
141*a3cefe7fSPierre Pronchery 
142*a3cefe7fSPierre Pronchery /* Read others permission */
143*a3cefe7fSPierre Pronchery #if !defined(S_IROTH)
144*a3cefe7fSPierre Pronchery #	define S_IROTH 0
145*a3cefe7fSPierre Pronchery #endif
146*a3cefe7fSPierre Pronchery 
147*a3cefe7fSPierre Pronchery /* Write others permission */
148*a3cefe7fSPierre Pronchery #if !defined(S_IWOTH)
149*a3cefe7fSPierre Pronchery #	define S_IWOTH 0
150*a3cefe7fSPierre Pronchery #endif
151*a3cefe7fSPierre Pronchery 
152*a3cefe7fSPierre Pronchery /* Execute others permission */
153*a3cefe7fSPierre Pronchery #if !defined(S_IXOTH)
154*a3cefe7fSPierre Pronchery #	define S_IXOTH 0
155*a3cefe7fSPierre Pronchery #endif
156*a3cefe7fSPierre Pronchery 
157*a3cefe7fSPierre Pronchery /* Maximum length of file name */
158*a3cefe7fSPierre Pronchery #if !defined(PATH_MAX)
159*a3cefe7fSPierre Pronchery #	define PATH_MAX MAX_PATH
160*a3cefe7fSPierre Pronchery #endif
161*a3cefe7fSPierre Pronchery #if !defined(FILENAME_MAX)
162*a3cefe7fSPierre Pronchery #	define FILENAME_MAX MAX_PATH
163*a3cefe7fSPierre Pronchery #endif
164*a3cefe7fSPierre Pronchery #if !defined(NAME_MAX)
165*a3cefe7fSPierre Pronchery #	define NAME_MAX FILENAME_MAX
166*a3cefe7fSPierre Pronchery #endif
167*a3cefe7fSPierre Pronchery 
168*a3cefe7fSPierre Pronchery /* File type flags for d_type */
169*a3cefe7fSPierre Pronchery #define DT_UNKNOWN 0
170*a3cefe7fSPierre Pronchery #define DT_REG S_IFREG
171*a3cefe7fSPierre Pronchery #define DT_DIR S_IFDIR
172*a3cefe7fSPierre Pronchery #define DT_FIFO S_IFIFO
173*a3cefe7fSPierre Pronchery #define DT_SOCK S_IFSOCK
174*a3cefe7fSPierre Pronchery #define DT_CHR S_IFCHR
175*a3cefe7fSPierre Pronchery #define DT_BLK S_IFBLK
176*a3cefe7fSPierre Pronchery #define DT_LNK S_IFLNK
177*a3cefe7fSPierre Pronchery 
178*a3cefe7fSPierre Pronchery /* Macros for converting between st_mode and d_type */
179*a3cefe7fSPierre Pronchery #define IFTODT(mode) ((mode) & S_IFMT)
180*a3cefe7fSPierre Pronchery #define DTTOIF(type) (type)
181*a3cefe7fSPierre Pronchery 
182*a3cefe7fSPierre Pronchery /*
183*a3cefe7fSPierre Pronchery  * File type macros.  Note that block devices, sockets and links cannot be
184*a3cefe7fSPierre Pronchery  * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
185*a3cefe7fSPierre Pronchery  * only defined for compatibility.  These macros should always return false
186*a3cefe7fSPierre Pronchery  * on Windows.
187*a3cefe7fSPierre Pronchery  */
188*a3cefe7fSPierre Pronchery #if !defined(S_ISFIFO)
189*a3cefe7fSPierre Pronchery #	define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
190*a3cefe7fSPierre Pronchery #endif
191*a3cefe7fSPierre Pronchery #if !defined(S_ISDIR)
192*a3cefe7fSPierre Pronchery #	define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
193*a3cefe7fSPierre Pronchery #endif
194*a3cefe7fSPierre Pronchery #if !defined(S_ISREG)
195*a3cefe7fSPierre Pronchery #	define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
196*a3cefe7fSPierre Pronchery #endif
197*a3cefe7fSPierre Pronchery #if !defined(S_ISLNK)
198*a3cefe7fSPierre Pronchery #	define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
199*a3cefe7fSPierre Pronchery #endif
200*a3cefe7fSPierre Pronchery #if !defined(S_ISSOCK)
201*a3cefe7fSPierre Pronchery #	define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
202*a3cefe7fSPierre Pronchery #endif
203*a3cefe7fSPierre Pronchery #if !defined(S_ISCHR)
204*a3cefe7fSPierre Pronchery #	define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
205*a3cefe7fSPierre Pronchery #endif
206*a3cefe7fSPierre Pronchery #if !defined(S_ISBLK)
207*a3cefe7fSPierre Pronchery #	define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
208*a3cefe7fSPierre Pronchery #endif
209*a3cefe7fSPierre Pronchery 
210*a3cefe7fSPierre Pronchery /* Return the exact length of the file name without zero terminator */
211*a3cefe7fSPierre Pronchery #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
212*a3cefe7fSPierre Pronchery 
213*a3cefe7fSPierre Pronchery /* Return the maximum size of a file name */
214*a3cefe7fSPierre Pronchery #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
215*a3cefe7fSPierre Pronchery 
216*a3cefe7fSPierre Pronchery 
217*a3cefe7fSPierre Pronchery #ifdef __cplusplus
218*a3cefe7fSPierre Pronchery extern "C" {
219*a3cefe7fSPierre Pronchery #endif
220*a3cefe7fSPierre Pronchery 
221*a3cefe7fSPierre Pronchery 
222*a3cefe7fSPierre Pronchery /* Wide-character version */
223*a3cefe7fSPierre Pronchery struct _wdirent {
224*a3cefe7fSPierre Pronchery 	/* Always zero */
225*a3cefe7fSPierre Pronchery 	long d_ino;
226*a3cefe7fSPierre Pronchery 
227*a3cefe7fSPierre Pronchery 	/* File position within stream */
228*a3cefe7fSPierre Pronchery 	long d_off;
229*a3cefe7fSPierre Pronchery 
230*a3cefe7fSPierre Pronchery 	/* Structure size */
231*a3cefe7fSPierre Pronchery 	unsigned short d_reclen;
232*a3cefe7fSPierre Pronchery 
233*a3cefe7fSPierre Pronchery 	/* Length of name without \0 */
234*a3cefe7fSPierre Pronchery 	size_t d_namlen;
235*a3cefe7fSPierre Pronchery 
236*a3cefe7fSPierre Pronchery 	/* File type */
237*a3cefe7fSPierre Pronchery 	int d_type;
238*a3cefe7fSPierre Pronchery 
239*a3cefe7fSPierre Pronchery 	/* File name */
240*a3cefe7fSPierre Pronchery 	wchar_t d_name[PATH_MAX+1];
241*a3cefe7fSPierre Pronchery };
242*a3cefe7fSPierre Pronchery typedef struct _wdirent _wdirent;
243*a3cefe7fSPierre Pronchery 
244*a3cefe7fSPierre Pronchery struct _WDIR {
245*a3cefe7fSPierre Pronchery 	/* Current directory entry */
246*a3cefe7fSPierre Pronchery 	struct _wdirent ent;
247*a3cefe7fSPierre Pronchery 
248*a3cefe7fSPierre Pronchery 	/* Private file data */
249*a3cefe7fSPierre Pronchery 	WIN32_FIND_DATAW data;
250*a3cefe7fSPierre Pronchery 
251*a3cefe7fSPierre Pronchery 	/* True if data is valid */
252*a3cefe7fSPierre Pronchery 	int cached;
253*a3cefe7fSPierre Pronchery 
254*a3cefe7fSPierre Pronchery 	/* Win32 search handle */
255*a3cefe7fSPierre Pronchery 	HANDLE handle;
256*a3cefe7fSPierre Pronchery 
257*a3cefe7fSPierre Pronchery 	/* Initial directory name */
258*a3cefe7fSPierre Pronchery 	wchar_t *patt;
259*a3cefe7fSPierre Pronchery };
260*a3cefe7fSPierre Pronchery typedef struct _WDIR _WDIR;
261*a3cefe7fSPierre Pronchery 
262*a3cefe7fSPierre Pronchery /* Multi-byte character version */
263*a3cefe7fSPierre Pronchery struct dirent {
264*a3cefe7fSPierre Pronchery 	/* Always zero */
265*a3cefe7fSPierre Pronchery 	long d_ino;
266*a3cefe7fSPierre Pronchery 
267*a3cefe7fSPierre Pronchery 	/* File position within stream */
268*a3cefe7fSPierre Pronchery 	long d_off;
269*a3cefe7fSPierre Pronchery 
270*a3cefe7fSPierre Pronchery 	/* Structure size */
271*a3cefe7fSPierre Pronchery 	unsigned short d_reclen;
272*a3cefe7fSPierre Pronchery 
273*a3cefe7fSPierre Pronchery 	/* Length of name without \0 */
274*a3cefe7fSPierre Pronchery 	size_t d_namlen;
275*a3cefe7fSPierre Pronchery 
276*a3cefe7fSPierre Pronchery 	/* File type */
277*a3cefe7fSPierre Pronchery 	int d_type;
278*a3cefe7fSPierre Pronchery 
279*a3cefe7fSPierre Pronchery 	/* File name */
280*a3cefe7fSPierre Pronchery 	char d_name[PATH_MAX+1];
281*a3cefe7fSPierre Pronchery };
282*a3cefe7fSPierre Pronchery typedef struct dirent dirent;
283*a3cefe7fSPierre Pronchery 
284*a3cefe7fSPierre Pronchery struct DIR {
285*a3cefe7fSPierre Pronchery 	struct dirent ent;
286*a3cefe7fSPierre Pronchery 	struct _WDIR *wdirp;
287*a3cefe7fSPierre Pronchery };
288*a3cefe7fSPierre Pronchery typedef struct DIR DIR;
289*a3cefe7fSPierre Pronchery 
290*a3cefe7fSPierre Pronchery 
291*a3cefe7fSPierre Pronchery /* Dirent functions */
292*a3cefe7fSPierre Pronchery static DIR *opendir(const char *dirname);
293*a3cefe7fSPierre Pronchery static _WDIR *_wopendir(const wchar_t *dirname);
294*a3cefe7fSPierre Pronchery 
295*a3cefe7fSPierre Pronchery static struct dirent *readdir(DIR *dirp);
296*a3cefe7fSPierre Pronchery static struct _wdirent *_wreaddir(_WDIR *dirp);
297*a3cefe7fSPierre Pronchery 
298*a3cefe7fSPierre Pronchery static int readdir_r(
299*a3cefe7fSPierre Pronchery 	DIR *dirp, struct dirent *entry, struct dirent **result);
300*a3cefe7fSPierre Pronchery static int _wreaddir_r(
301*a3cefe7fSPierre Pronchery 	_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result);
302*a3cefe7fSPierre Pronchery 
303*a3cefe7fSPierre Pronchery static int closedir(DIR *dirp);
304*a3cefe7fSPierre Pronchery static int _wclosedir(_WDIR *dirp);
305*a3cefe7fSPierre Pronchery 
306*a3cefe7fSPierre Pronchery static void rewinddir(DIR* dirp);
307*a3cefe7fSPierre Pronchery static void _wrewinddir(_WDIR* dirp);
308*a3cefe7fSPierre Pronchery 
309*a3cefe7fSPierre Pronchery static int scandir(const char *dirname, struct dirent ***namelist,
310*a3cefe7fSPierre Pronchery 	int (*filter)(const struct dirent*),
311*a3cefe7fSPierre Pronchery 	int (*compare)(const struct dirent**, const struct dirent**));
312*a3cefe7fSPierre Pronchery 
313*a3cefe7fSPierre Pronchery static int alphasort(const struct dirent **a, const struct dirent **b);
314*a3cefe7fSPierre Pronchery 
315*a3cefe7fSPierre Pronchery static int versionsort(const struct dirent **a, const struct dirent **b);
316*a3cefe7fSPierre Pronchery 
317*a3cefe7fSPierre Pronchery static int strverscmp(const char *a, const char *b);
318*a3cefe7fSPierre Pronchery 
319*a3cefe7fSPierre Pronchery /* For compatibility with Symbian */
320*a3cefe7fSPierre Pronchery #define wdirent _wdirent
321*a3cefe7fSPierre Pronchery #define WDIR _WDIR
322*a3cefe7fSPierre Pronchery #define wopendir _wopendir
323*a3cefe7fSPierre Pronchery #define wreaddir _wreaddir
324*a3cefe7fSPierre Pronchery #define wclosedir _wclosedir
325*a3cefe7fSPierre Pronchery #define wrewinddir _wrewinddir
326*a3cefe7fSPierre Pronchery 
327*a3cefe7fSPierre Pronchery /* Compatibility with older Microsoft compilers and non-Microsoft compilers */
328*a3cefe7fSPierre Pronchery #if !defined(_MSC_VER) || _MSC_VER < 1400
329*a3cefe7fSPierre Pronchery #	define wcstombs_s dirent_wcstombs_s
330*a3cefe7fSPierre Pronchery #	define mbstowcs_s dirent_mbstowcs_s
331*a3cefe7fSPierre Pronchery #endif
332*a3cefe7fSPierre Pronchery 
333*a3cefe7fSPierre Pronchery /* Optimize dirent_set_errno() away on modern Microsoft compilers */
334*a3cefe7fSPierre Pronchery #if defined(_MSC_VER) && _MSC_VER >= 1400
335*a3cefe7fSPierre Pronchery #	define dirent_set_errno _set_errno
336*a3cefe7fSPierre Pronchery #endif
337*a3cefe7fSPierre Pronchery 
338*a3cefe7fSPierre Pronchery 
339*a3cefe7fSPierre Pronchery /* Internal utility functions */
340*a3cefe7fSPierre Pronchery static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
341*a3cefe7fSPierre Pronchery static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
342*a3cefe7fSPierre Pronchery 
343*a3cefe7fSPierre Pronchery #if !defined(_MSC_VER) || _MSC_VER < 1400
344*a3cefe7fSPierre Pronchery static int dirent_mbstowcs_s(
345*a3cefe7fSPierre Pronchery 	size_t *pReturnValue, wchar_t *wcstr, size_t sizeInWords,
346*a3cefe7fSPierre Pronchery 	const char *mbstr, size_t count);
347*a3cefe7fSPierre Pronchery #endif
348*a3cefe7fSPierre Pronchery 
349*a3cefe7fSPierre Pronchery #if !defined(_MSC_VER) || _MSC_VER < 1400
350*a3cefe7fSPierre Pronchery static int dirent_wcstombs_s(
351*a3cefe7fSPierre Pronchery 	size_t *pReturnValue, char *mbstr, size_t sizeInBytes,
352*a3cefe7fSPierre Pronchery 	const wchar_t *wcstr, size_t count);
353*a3cefe7fSPierre Pronchery #endif
354*a3cefe7fSPierre Pronchery 
355*a3cefe7fSPierre Pronchery #if !defined(_MSC_VER) || _MSC_VER < 1400
356*a3cefe7fSPierre Pronchery static void dirent_set_errno(int error);
357*a3cefe7fSPierre Pronchery #endif
358*a3cefe7fSPierre Pronchery 
359*a3cefe7fSPierre Pronchery 
360*a3cefe7fSPierre Pronchery /*
361*a3cefe7fSPierre Pronchery  * Open directory stream DIRNAME for read and return a pointer to the
362*a3cefe7fSPierre Pronchery  * internal working area that is used to retrieve individual directory
363*a3cefe7fSPierre Pronchery  * entries.
364*a3cefe7fSPierre Pronchery  */
_wopendir(const wchar_t * dirname)365*a3cefe7fSPierre Pronchery static _WDIR *_wopendir(const wchar_t *dirname)
366*a3cefe7fSPierre Pronchery {
367*a3cefe7fSPierre Pronchery 	wchar_t *p;
368*a3cefe7fSPierre Pronchery 
369*a3cefe7fSPierre Pronchery 	/* Must have directory name */
370*a3cefe7fSPierre Pronchery 	if (dirname == NULL || dirname[0] == '\0') {
371*a3cefe7fSPierre Pronchery 		dirent_set_errno(ENOENT);
372*a3cefe7fSPierre Pronchery 		return NULL;
373*a3cefe7fSPierre Pronchery 	}
374*a3cefe7fSPierre Pronchery 
375*a3cefe7fSPierre Pronchery 	/* Allocate new _WDIR structure */
376*a3cefe7fSPierre Pronchery 	_WDIR *dirp = (_WDIR*) malloc(sizeof(struct _WDIR));
377*a3cefe7fSPierre Pronchery 	if (!dirp)
378*a3cefe7fSPierre Pronchery 		return NULL;
379*a3cefe7fSPierre Pronchery 
380*a3cefe7fSPierre Pronchery 	/* Reset _WDIR structure */
381*a3cefe7fSPierre Pronchery 	dirp->handle = INVALID_HANDLE_VALUE;
382*a3cefe7fSPierre Pronchery 	dirp->patt = NULL;
383*a3cefe7fSPierre Pronchery 	dirp->cached = 0;
384*a3cefe7fSPierre Pronchery 
385*a3cefe7fSPierre Pronchery 	/*
386*a3cefe7fSPierre Pronchery 	 * Compute the length of full path plus zero terminator
387*a3cefe7fSPierre Pronchery 	 *
388*a3cefe7fSPierre Pronchery 	 * Note that on WinRT there's no way to convert relative paths
389*a3cefe7fSPierre Pronchery 	 * into absolute paths, so just assume it is an absolute path.
390*a3cefe7fSPierre Pronchery 	 */
391*a3cefe7fSPierre Pronchery #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
392*a3cefe7fSPierre Pronchery 	/* Desktop */
393*a3cefe7fSPierre Pronchery 	DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL);
394*a3cefe7fSPierre Pronchery #else
395*a3cefe7fSPierre Pronchery 	/* WinRT */
396*a3cefe7fSPierre Pronchery 	size_t n = wcslen(dirname);
397*a3cefe7fSPierre Pronchery #endif
398*a3cefe7fSPierre Pronchery 
399*a3cefe7fSPierre Pronchery 	/* Allocate room for absolute directory name and search pattern */
400*a3cefe7fSPierre Pronchery 	dirp->patt = (wchar_t*) malloc(sizeof(wchar_t) * n + 16);
401*a3cefe7fSPierre Pronchery 	if (dirp->patt == NULL)
402*a3cefe7fSPierre Pronchery 		goto exit_closedir;
403*a3cefe7fSPierre Pronchery 
404*a3cefe7fSPierre Pronchery 	/*
405*a3cefe7fSPierre Pronchery 	 * Convert relative directory name to an absolute one.  This
406*a3cefe7fSPierre Pronchery 	 * allows rewinddir() to function correctly even when current
407*a3cefe7fSPierre Pronchery 	 * working directory is changed between opendir() and rewinddir().
408*a3cefe7fSPierre Pronchery 	 *
409*a3cefe7fSPierre Pronchery 	 * Note that on WinRT there's no way to convert relative paths
410*a3cefe7fSPierre Pronchery 	 * into absolute paths, so just assume it is an absolute path.
411*a3cefe7fSPierre Pronchery 	 */
412*a3cefe7fSPierre Pronchery #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
413*a3cefe7fSPierre Pronchery 	/* Desktop */
414*a3cefe7fSPierre Pronchery 	n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
415*a3cefe7fSPierre Pronchery 	if (n <= 0)
416*a3cefe7fSPierre Pronchery 		goto exit_closedir;
417*a3cefe7fSPierre Pronchery #else
418*a3cefe7fSPierre Pronchery 	/* WinRT */
419*a3cefe7fSPierre Pronchery 	wcsncpy_s(dirp->patt, n+1, dirname, n);
420*a3cefe7fSPierre Pronchery #endif
421*a3cefe7fSPierre Pronchery 
422*a3cefe7fSPierre Pronchery 	/* Append search pattern \* to the directory name */
423*a3cefe7fSPierre Pronchery 	p = dirp->patt + n;
424*a3cefe7fSPierre Pronchery 	switch (p[-1]) {
425*a3cefe7fSPierre Pronchery 	case '\\':
426*a3cefe7fSPierre Pronchery 	case '/':
427*a3cefe7fSPierre Pronchery 	case ':':
428*a3cefe7fSPierre Pronchery 		/* Directory ends in path separator, e.g. c:\temp\ */
429*a3cefe7fSPierre Pronchery 		/*NOP*/;
430*a3cefe7fSPierre Pronchery 		break;
431*a3cefe7fSPierre Pronchery 
432*a3cefe7fSPierre Pronchery 	default:
433*a3cefe7fSPierre Pronchery 		/* Directory name doesn't end in path separator */
434*a3cefe7fSPierre Pronchery 		*p++ = '\\';
435*a3cefe7fSPierre Pronchery 	}
436*a3cefe7fSPierre Pronchery 	*p++ = '*';
437*a3cefe7fSPierre Pronchery 	*p = '\0';
438*a3cefe7fSPierre Pronchery 
439*a3cefe7fSPierre Pronchery 	/* Open directory stream and retrieve the first entry */
440*a3cefe7fSPierre Pronchery 	if (!dirent_first(dirp))
441*a3cefe7fSPierre Pronchery 		goto exit_closedir;
442*a3cefe7fSPierre Pronchery 
443*a3cefe7fSPierre Pronchery 	/* Success */
444*a3cefe7fSPierre Pronchery 	return dirp;
445*a3cefe7fSPierre Pronchery 
446*a3cefe7fSPierre Pronchery 	/* Failure */
447*a3cefe7fSPierre Pronchery exit_closedir:
448*a3cefe7fSPierre Pronchery 	_wclosedir(dirp);
449*a3cefe7fSPierre Pronchery 	return NULL;
450*a3cefe7fSPierre Pronchery }
451*a3cefe7fSPierre Pronchery 
452*a3cefe7fSPierre Pronchery /*
453*a3cefe7fSPierre Pronchery  * Read next directory entry.
454*a3cefe7fSPierre Pronchery  *
455*a3cefe7fSPierre Pronchery  * Returns pointer to static directory entry which may be overwritten by
456*a3cefe7fSPierre Pronchery  * subsequent calls to _wreaddir().
457*a3cefe7fSPierre Pronchery  */
_wreaddir(_WDIR * dirp)458*a3cefe7fSPierre Pronchery static struct _wdirent *_wreaddir(_WDIR *dirp)
459*a3cefe7fSPierre Pronchery {
460*a3cefe7fSPierre Pronchery 	/*
461*a3cefe7fSPierre Pronchery 	 * Read directory entry to buffer.  We can safely ignore the return
462*a3cefe7fSPierre Pronchery 	 * value as entry will be set to NULL in case of error.
463*a3cefe7fSPierre Pronchery 	 */
464*a3cefe7fSPierre Pronchery 	struct _wdirent *entry;
465*a3cefe7fSPierre Pronchery 	(void) _wreaddir_r(dirp, &dirp->ent, &entry);
466*a3cefe7fSPierre Pronchery 
467*a3cefe7fSPierre Pronchery 	/* Return pointer to statically allocated directory entry */
468*a3cefe7fSPierre Pronchery 	return entry;
469*a3cefe7fSPierre Pronchery }
470*a3cefe7fSPierre Pronchery 
471*a3cefe7fSPierre Pronchery /*
472*a3cefe7fSPierre Pronchery  * Read next directory entry.
473*a3cefe7fSPierre Pronchery  *
474*a3cefe7fSPierre Pronchery  * Returns zero on success.  If end of directory stream is reached, then sets
475*a3cefe7fSPierre Pronchery  * result to NULL and returns zero.
476*a3cefe7fSPierre Pronchery  */
_wreaddir_r(_WDIR * dirp,struct _wdirent * entry,struct _wdirent ** result)477*a3cefe7fSPierre Pronchery static int _wreaddir_r(
478*a3cefe7fSPierre Pronchery 	_WDIR *dirp, struct _wdirent *entry, struct _wdirent **result)
479*a3cefe7fSPierre Pronchery {
480*a3cefe7fSPierre Pronchery 	/* Read next directory entry */
481*a3cefe7fSPierre Pronchery 	WIN32_FIND_DATAW *datap = dirent_next(dirp);
482*a3cefe7fSPierre Pronchery 	if (!datap) {
483*a3cefe7fSPierre Pronchery 		/* Return NULL to indicate end of directory */
484*a3cefe7fSPierre Pronchery 		*result = NULL;
485*a3cefe7fSPierre Pronchery 		return /*OK*/0;
486*a3cefe7fSPierre Pronchery 	}
487*a3cefe7fSPierre Pronchery 
488*a3cefe7fSPierre Pronchery 	/*
489*a3cefe7fSPierre Pronchery 	 * Copy file name as wide-character string.  If the file name is too
490*a3cefe7fSPierre Pronchery 	 * long to fit in to the destination buffer, then truncate file name
491*a3cefe7fSPierre Pronchery 	 * to PATH_MAX characters and zero-terminate the buffer.
492*a3cefe7fSPierre Pronchery 	 */
493*a3cefe7fSPierre Pronchery 	size_t n = 0;
494*a3cefe7fSPierre Pronchery 	while (n < PATH_MAX && datap->cFileName[n] != 0) {
495*a3cefe7fSPierre Pronchery 		entry->d_name[n] = datap->cFileName[n];
496*a3cefe7fSPierre Pronchery 		n++;
497*a3cefe7fSPierre Pronchery 	}
498*a3cefe7fSPierre Pronchery 	entry->d_name[n] = 0;
499*a3cefe7fSPierre Pronchery 
500*a3cefe7fSPierre Pronchery 	/* Length of file name excluding zero terminator */
501*a3cefe7fSPierre Pronchery 	entry->d_namlen = n;
502*a3cefe7fSPierre Pronchery 
503*a3cefe7fSPierre Pronchery 	/* File type */
504*a3cefe7fSPierre Pronchery 	DWORD attr = datap->dwFileAttributes;
505*a3cefe7fSPierre Pronchery 	if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
506*a3cefe7fSPierre Pronchery 		entry->d_type = DT_CHR;
507*a3cefe7fSPierre Pronchery 	else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
508*a3cefe7fSPierre Pronchery 		entry->d_type = DT_DIR;
509*a3cefe7fSPierre Pronchery 	else
510*a3cefe7fSPierre Pronchery 		entry->d_type = DT_REG;
511*a3cefe7fSPierre Pronchery 
512*a3cefe7fSPierre Pronchery 	/* Reset dummy fields */
513*a3cefe7fSPierre Pronchery 	entry->d_ino = 0;
514*a3cefe7fSPierre Pronchery 	entry->d_off = 0;
515*a3cefe7fSPierre Pronchery 	entry->d_reclen = sizeof(struct _wdirent);
516*a3cefe7fSPierre Pronchery 
517*a3cefe7fSPierre Pronchery 	/* Set result address */
518*a3cefe7fSPierre Pronchery 	*result = entry;
519*a3cefe7fSPierre Pronchery 	return /*OK*/0;
520*a3cefe7fSPierre Pronchery }
521*a3cefe7fSPierre Pronchery 
522*a3cefe7fSPierre Pronchery /*
523*a3cefe7fSPierre Pronchery  * Close directory stream opened by opendir() function.  This invalidates the
524*a3cefe7fSPierre Pronchery  * DIR structure as well as any directory entry read previously by
525*a3cefe7fSPierre Pronchery  * _wreaddir().
526*a3cefe7fSPierre Pronchery  */
_wclosedir(_WDIR * dirp)527*a3cefe7fSPierre Pronchery static int _wclosedir(_WDIR *dirp)
528*a3cefe7fSPierre Pronchery {
529*a3cefe7fSPierre Pronchery 	if (!dirp) {
530*a3cefe7fSPierre Pronchery 		dirent_set_errno(EBADF);
531*a3cefe7fSPierre Pronchery 		return /*failure*/-1;
532*a3cefe7fSPierre Pronchery 	}
533*a3cefe7fSPierre Pronchery 
534*a3cefe7fSPierre Pronchery 	/* Release search handle */
535*a3cefe7fSPierre Pronchery 	if (dirp->handle != INVALID_HANDLE_VALUE)
536*a3cefe7fSPierre Pronchery 		FindClose(dirp->handle);
537*a3cefe7fSPierre Pronchery 
538*a3cefe7fSPierre Pronchery 	/* Release search pattern */
539*a3cefe7fSPierre Pronchery 	free(dirp->patt);
540*a3cefe7fSPierre Pronchery 
541*a3cefe7fSPierre Pronchery 	/* Release directory structure */
542*a3cefe7fSPierre Pronchery 	free(dirp);
543*a3cefe7fSPierre Pronchery 	return /*success*/0;
544*a3cefe7fSPierre Pronchery }
545*a3cefe7fSPierre Pronchery 
546*a3cefe7fSPierre Pronchery /*
547*a3cefe7fSPierre Pronchery  * Rewind directory stream such that _wreaddir() returns the very first
548*a3cefe7fSPierre Pronchery  * file name again.
549*a3cefe7fSPierre Pronchery  */
_wrewinddir(_WDIR * dirp)550*a3cefe7fSPierre Pronchery static void _wrewinddir(_WDIR* dirp)
551*a3cefe7fSPierre Pronchery {
552*a3cefe7fSPierre Pronchery 	if (!dirp)
553*a3cefe7fSPierre Pronchery 		return;
554*a3cefe7fSPierre Pronchery 
555*a3cefe7fSPierre Pronchery 	/* Release existing search handle */
556*a3cefe7fSPierre Pronchery 	if (dirp->handle != INVALID_HANDLE_VALUE)
557*a3cefe7fSPierre Pronchery 		FindClose(dirp->handle);
558*a3cefe7fSPierre Pronchery 
559*a3cefe7fSPierre Pronchery 	/* Open new search handle */
560*a3cefe7fSPierre Pronchery 	dirent_first(dirp);
561*a3cefe7fSPierre Pronchery }
562*a3cefe7fSPierre Pronchery 
563*a3cefe7fSPierre Pronchery /* Get first directory entry */
dirent_first(_WDIR * dirp)564*a3cefe7fSPierre Pronchery static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp)
565*a3cefe7fSPierre Pronchery {
566*a3cefe7fSPierre Pronchery 	if (!dirp)
567*a3cefe7fSPierre Pronchery 		return NULL;
568*a3cefe7fSPierre Pronchery 
569*a3cefe7fSPierre Pronchery 	/* Open directory and retrieve the first entry */
570*a3cefe7fSPierre Pronchery 	dirp->handle = FindFirstFileExW(
571*a3cefe7fSPierre Pronchery 		dirp->patt, FindExInfoStandard, &dirp->data,
572*a3cefe7fSPierre Pronchery 		FindExSearchNameMatch, NULL, 0);
573*a3cefe7fSPierre Pronchery 	if (dirp->handle == INVALID_HANDLE_VALUE)
574*a3cefe7fSPierre Pronchery 		goto error;
575*a3cefe7fSPierre Pronchery 
576*a3cefe7fSPierre Pronchery 	/* A directory entry is now waiting in memory */
577*a3cefe7fSPierre Pronchery 	dirp->cached = 1;
578*a3cefe7fSPierre Pronchery 	return &dirp->data;
579*a3cefe7fSPierre Pronchery 
580*a3cefe7fSPierre Pronchery error:
581*a3cefe7fSPierre Pronchery 	/* Failed to open directory: no directory entry in memory */
582*a3cefe7fSPierre Pronchery 	dirp->cached = 0;
583*a3cefe7fSPierre Pronchery 
584*a3cefe7fSPierre Pronchery 	/* Set error code */
585*a3cefe7fSPierre Pronchery 	DWORD errorcode = GetLastError();
586*a3cefe7fSPierre Pronchery 	switch (errorcode) {
587*a3cefe7fSPierre Pronchery 	case ERROR_ACCESS_DENIED:
588*a3cefe7fSPierre Pronchery 		/* No read access to directory */
589*a3cefe7fSPierre Pronchery 		dirent_set_errno(EACCES);
590*a3cefe7fSPierre Pronchery 		break;
591*a3cefe7fSPierre Pronchery 
592*a3cefe7fSPierre Pronchery 	case ERROR_DIRECTORY:
593*a3cefe7fSPierre Pronchery 		/* Directory name is invalid */
594*a3cefe7fSPierre Pronchery 		dirent_set_errno(ENOTDIR);
595*a3cefe7fSPierre Pronchery 		break;
596*a3cefe7fSPierre Pronchery 
597*a3cefe7fSPierre Pronchery 	case ERROR_PATH_NOT_FOUND:
598*a3cefe7fSPierre Pronchery 	default:
599*a3cefe7fSPierre Pronchery 		/* Cannot find the file */
600*a3cefe7fSPierre Pronchery 		dirent_set_errno(ENOENT);
601*a3cefe7fSPierre Pronchery 	}
602*a3cefe7fSPierre Pronchery 	return NULL;
603*a3cefe7fSPierre Pronchery }
604*a3cefe7fSPierre Pronchery 
605*a3cefe7fSPierre Pronchery /* Get next directory entry */
dirent_next(_WDIR * dirp)606*a3cefe7fSPierre Pronchery static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp)
607*a3cefe7fSPierre Pronchery {
608*a3cefe7fSPierre Pronchery 	/* Is the next directory entry already in cache? */
609*a3cefe7fSPierre Pronchery 	if (dirp->cached) {
610*a3cefe7fSPierre Pronchery 		/* Yes, a valid directory entry found in memory */
611*a3cefe7fSPierre Pronchery 		dirp->cached = 0;
612*a3cefe7fSPierre Pronchery 		return &dirp->data;
613*a3cefe7fSPierre Pronchery 	}
614*a3cefe7fSPierre Pronchery 
615*a3cefe7fSPierre Pronchery 	/* No directory entry in cache */
616*a3cefe7fSPierre Pronchery 	if (dirp->handle == INVALID_HANDLE_VALUE)
617*a3cefe7fSPierre Pronchery 		return NULL;
618*a3cefe7fSPierre Pronchery 
619*a3cefe7fSPierre Pronchery 	/* Read the next directory entry from stream */
620*a3cefe7fSPierre Pronchery 	if (FindNextFileW(dirp->handle, &dirp->data) == FALSE)
621*a3cefe7fSPierre Pronchery 		goto exit_close;
622*a3cefe7fSPierre Pronchery 
623*a3cefe7fSPierre Pronchery 	/* Success */
624*a3cefe7fSPierre Pronchery 	return &dirp->data;
625*a3cefe7fSPierre Pronchery 
626*a3cefe7fSPierre Pronchery 	/* Failure */
627*a3cefe7fSPierre Pronchery exit_close:
628*a3cefe7fSPierre Pronchery 	FindClose(dirp->handle);
629*a3cefe7fSPierre Pronchery 	dirp->handle = INVALID_HANDLE_VALUE;
630*a3cefe7fSPierre Pronchery 	return NULL;
631*a3cefe7fSPierre Pronchery }
632*a3cefe7fSPierre Pronchery 
633*a3cefe7fSPierre Pronchery /* Open directory stream using plain old C-string */
opendir(const char * dirname)634*a3cefe7fSPierre Pronchery static DIR *opendir(const char *dirname)
635*a3cefe7fSPierre Pronchery {
636*a3cefe7fSPierre Pronchery 	/* Must have directory name */
637*a3cefe7fSPierre Pronchery 	if (dirname == NULL || dirname[0] == '\0') {
638*a3cefe7fSPierre Pronchery 		dirent_set_errno(ENOENT);
639*a3cefe7fSPierre Pronchery 		return NULL;
640*a3cefe7fSPierre Pronchery 	}
641*a3cefe7fSPierre Pronchery 
642*a3cefe7fSPierre Pronchery 	/* Allocate memory for DIR structure */
643*a3cefe7fSPierre Pronchery 	struct DIR *dirp = (DIR*) malloc(sizeof(struct DIR));
644*a3cefe7fSPierre Pronchery 	if (!dirp)
645*a3cefe7fSPierre Pronchery 		return NULL;
646*a3cefe7fSPierre Pronchery 
647*a3cefe7fSPierre Pronchery 	/* Convert directory name to wide-character string */
648*a3cefe7fSPierre Pronchery 	wchar_t wname[PATH_MAX + 1];
649*a3cefe7fSPierre Pronchery 	size_t n;
650*a3cefe7fSPierre Pronchery 	int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1);
651*a3cefe7fSPierre Pronchery 	if (error)
652*a3cefe7fSPierre Pronchery 		goto exit_failure;
653*a3cefe7fSPierre Pronchery 
654*a3cefe7fSPierre Pronchery 	/* Open directory stream using wide-character name */
655*a3cefe7fSPierre Pronchery 	dirp->wdirp = _wopendir(wname);
656*a3cefe7fSPierre Pronchery 	if (!dirp->wdirp)
657*a3cefe7fSPierre Pronchery 		goto exit_failure;
658*a3cefe7fSPierre Pronchery 
659*a3cefe7fSPierre Pronchery 	/* Success */
660*a3cefe7fSPierre Pronchery 	return dirp;
661*a3cefe7fSPierre Pronchery 
662*a3cefe7fSPierre Pronchery 	/* Failure */
663*a3cefe7fSPierre Pronchery exit_failure:
664*a3cefe7fSPierre Pronchery 	free(dirp);
665*a3cefe7fSPierre Pronchery 	return NULL;
666*a3cefe7fSPierre Pronchery }
667*a3cefe7fSPierre Pronchery 
668*a3cefe7fSPierre Pronchery /* Read next directory entry */
readdir(DIR * dirp)669*a3cefe7fSPierre Pronchery static struct dirent *readdir(DIR *dirp)
670*a3cefe7fSPierre Pronchery {
671*a3cefe7fSPierre Pronchery 	/*
672*a3cefe7fSPierre Pronchery 	 * Read directory entry to buffer.  We can safely ignore the return
673*a3cefe7fSPierre Pronchery 	 * value as entry will be set to NULL in case of error.
674*a3cefe7fSPierre Pronchery 	 */
675*a3cefe7fSPierre Pronchery 	struct dirent *entry;
676*a3cefe7fSPierre Pronchery 	(void) readdir_r(dirp, &dirp->ent, &entry);
677*a3cefe7fSPierre Pronchery 
678*a3cefe7fSPierre Pronchery 	/* Return pointer to statically allocated directory entry */
679*a3cefe7fSPierre Pronchery 	return entry;
680*a3cefe7fSPierre Pronchery }
681*a3cefe7fSPierre Pronchery 
682*a3cefe7fSPierre Pronchery /*
683*a3cefe7fSPierre Pronchery  * Read next directory entry into called-allocated buffer.
684*a3cefe7fSPierre Pronchery  *
685*a3cefe7fSPierre Pronchery  * Returns zero on success.  If the end of directory stream is reached, then
686*a3cefe7fSPierre Pronchery  * sets result to NULL and returns zero.
687*a3cefe7fSPierre Pronchery  */
readdir_r(DIR * dirp,struct dirent * entry,struct dirent ** result)688*a3cefe7fSPierre Pronchery static int readdir_r(
689*a3cefe7fSPierre Pronchery 	DIR *dirp, struct dirent *entry, struct dirent **result)
690*a3cefe7fSPierre Pronchery {
691*a3cefe7fSPierre Pronchery 	/* Read next directory entry */
692*a3cefe7fSPierre Pronchery 	WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp);
693*a3cefe7fSPierre Pronchery 	if (!datap) {
694*a3cefe7fSPierre Pronchery 		/* No more directory entries */
695*a3cefe7fSPierre Pronchery 		*result = NULL;
696*a3cefe7fSPierre Pronchery 		return /*OK*/0;
697*a3cefe7fSPierre Pronchery 	}
698*a3cefe7fSPierre Pronchery 
699*a3cefe7fSPierre Pronchery 	/* Attempt to convert file name to multi-byte string */
700*a3cefe7fSPierre Pronchery 	size_t n;
701*a3cefe7fSPierre Pronchery 	int error = wcstombs_s(
702*a3cefe7fSPierre Pronchery 		&n, entry->d_name, PATH_MAX + 1,
703*a3cefe7fSPierre Pronchery 		datap->cFileName, PATH_MAX + 1);
704*a3cefe7fSPierre Pronchery 
705*a3cefe7fSPierre Pronchery 	/*
706*a3cefe7fSPierre Pronchery 	 * If the file name cannot be represented by a multi-byte string, then
707*a3cefe7fSPierre Pronchery 	 * attempt to use old 8+3 file name.  This allows the program to
708*a3cefe7fSPierre Pronchery 	 * access files although file names may seem unfamiliar to the user.
709*a3cefe7fSPierre Pronchery 	 *
710*a3cefe7fSPierre Pronchery 	 * Be ware that the code below cannot come up with a short file name
711*a3cefe7fSPierre Pronchery 	 * unless the file system provides one.  At least VirtualBox shared
712*a3cefe7fSPierre Pronchery 	 * folders fail to do this.
713*a3cefe7fSPierre Pronchery 	 */
714*a3cefe7fSPierre Pronchery 	if (error && datap->cAlternateFileName[0] != '\0') {
715*a3cefe7fSPierre Pronchery 		error = wcstombs_s(
716*a3cefe7fSPierre Pronchery 			&n, entry->d_name, PATH_MAX + 1,
717*a3cefe7fSPierre Pronchery 			datap->cAlternateFileName, PATH_MAX + 1);
718*a3cefe7fSPierre Pronchery 	}
719*a3cefe7fSPierre Pronchery 
720*a3cefe7fSPierre Pronchery 	if (!error) {
721*a3cefe7fSPierre Pronchery 		/* Length of file name excluding zero terminator */
722*a3cefe7fSPierre Pronchery 		entry->d_namlen = n - 1;
723*a3cefe7fSPierre Pronchery 
724*a3cefe7fSPierre Pronchery 		/* File attributes */
725*a3cefe7fSPierre Pronchery 		DWORD attr = datap->dwFileAttributes;
726*a3cefe7fSPierre Pronchery 		if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
727*a3cefe7fSPierre Pronchery 			entry->d_type = DT_CHR;
728*a3cefe7fSPierre Pronchery 		else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
729*a3cefe7fSPierre Pronchery 			entry->d_type = DT_DIR;
730*a3cefe7fSPierre Pronchery 		else
731*a3cefe7fSPierre Pronchery 			entry->d_type = DT_REG;
732*a3cefe7fSPierre Pronchery 
733*a3cefe7fSPierre Pronchery 		/* Reset dummy fields */
734*a3cefe7fSPierre Pronchery 		entry->d_ino = 0;
735*a3cefe7fSPierre Pronchery 		entry->d_off = 0;
736*a3cefe7fSPierre Pronchery 		entry->d_reclen = sizeof(struct dirent);
737*a3cefe7fSPierre Pronchery 	} else {
738*a3cefe7fSPierre Pronchery 		/*
739*a3cefe7fSPierre Pronchery 		 * Cannot convert file name to multi-byte string so construct
740*a3cefe7fSPierre Pronchery 		 * an erroneous directory entry and return that.  Note that
741*a3cefe7fSPierre Pronchery 		 * we cannot return NULL as that would stop the processing
742*a3cefe7fSPierre Pronchery 		 * of directory entries completely.
743*a3cefe7fSPierre Pronchery 		 */
744*a3cefe7fSPierre Pronchery 		entry->d_name[0] = '?';
745*a3cefe7fSPierre Pronchery 		entry->d_name[1] = '\0';
746*a3cefe7fSPierre Pronchery 		entry->d_namlen = 1;
747*a3cefe7fSPierre Pronchery 		entry->d_type = DT_UNKNOWN;
748*a3cefe7fSPierre Pronchery 		entry->d_ino = 0;
749*a3cefe7fSPierre Pronchery 		entry->d_off = -1;
750*a3cefe7fSPierre Pronchery 		entry->d_reclen = 0;
751*a3cefe7fSPierre Pronchery 	}
752*a3cefe7fSPierre Pronchery 
753*a3cefe7fSPierre Pronchery 	/* Return pointer to directory entry */
754*a3cefe7fSPierre Pronchery 	*result = entry;
755*a3cefe7fSPierre Pronchery 	return /*OK*/0;
756*a3cefe7fSPierre Pronchery }
757*a3cefe7fSPierre Pronchery 
758*a3cefe7fSPierre Pronchery /* Close directory stream */
closedir(DIR * dirp)759*a3cefe7fSPierre Pronchery static int closedir(DIR *dirp)
760*a3cefe7fSPierre Pronchery {
761*a3cefe7fSPierre Pronchery 	int ok;
762*a3cefe7fSPierre Pronchery 
763*a3cefe7fSPierre Pronchery 	if (!dirp)
764*a3cefe7fSPierre Pronchery 		goto exit_failure;
765*a3cefe7fSPierre Pronchery 
766*a3cefe7fSPierre Pronchery 	/* Close wide-character directory stream */
767*a3cefe7fSPierre Pronchery 	ok = _wclosedir(dirp->wdirp);
768*a3cefe7fSPierre Pronchery 	dirp->wdirp = NULL;
769*a3cefe7fSPierre Pronchery 
770*a3cefe7fSPierre Pronchery 	/* Release multi-byte character version */
771*a3cefe7fSPierre Pronchery 	free(dirp);
772*a3cefe7fSPierre Pronchery 	return ok;
773*a3cefe7fSPierre Pronchery 
774*a3cefe7fSPierre Pronchery exit_failure:
775*a3cefe7fSPierre Pronchery 	/* Invalid directory stream */
776*a3cefe7fSPierre Pronchery 	dirent_set_errno(EBADF);
777*a3cefe7fSPierre Pronchery 	return /*failure*/-1;
778*a3cefe7fSPierre Pronchery }
779*a3cefe7fSPierre Pronchery 
780*a3cefe7fSPierre Pronchery /* Rewind directory stream to beginning */
rewinddir(DIR * dirp)781*a3cefe7fSPierre Pronchery static void rewinddir(DIR* dirp)
782*a3cefe7fSPierre Pronchery {
783*a3cefe7fSPierre Pronchery 	if (!dirp)
784*a3cefe7fSPierre Pronchery 		return;
785*a3cefe7fSPierre Pronchery 
786*a3cefe7fSPierre Pronchery 	/* Rewind wide-character string directory stream */
787*a3cefe7fSPierre Pronchery 	_wrewinddir(dirp->wdirp);
788*a3cefe7fSPierre Pronchery }
789*a3cefe7fSPierre Pronchery 
790*a3cefe7fSPierre Pronchery /* Scan directory for entries */
scandir(const char * dirname,struct dirent *** namelist,int (* filter)(const struct dirent *),int (* compare)(const struct dirent **,const struct dirent **))791*a3cefe7fSPierre Pronchery static int scandir(
792*a3cefe7fSPierre Pronchery 	const char *dirname, struct dirent ***namelist,
793*a3cefe7fSPierre Pronchery 	int (*filter)(const struct dirent*),
794*a3cefe7fSPierre Pronchery 	int (*compare)(const struct dirent**, const struct dirent**))
795*a3cefe7fSPierre Pronchery {
796*a3cefe7fSPierre Pronchery 	int result;
797*a3cefe7fSPierre Pronchery 
798*a3cefe7fSPierre Pronchery 	/* Open directory stream */
799*a3cefe7fSPierre Pronchery 	DIR *dir = opendir(dirname);
800*a3cefe7fSPierre Pronchery 	if (!dir) {
801*a3cefe7fSPierre Pronchery 		/* Cannot open directory */
802*a3cefe7fSPierre Pronchery 		return /*Error*/ -1;
803*a3cefe7fSPierre Pronchery 	}
804*a3cefe7fSPierre Pronchery 
805*a3cefe7fSPierre Pronchery 	/* Read directory entries to memory */
806*a3cefe7fSPierre Pronchery 	struct dirent *tmp = NULL;
807*a3cefe7fSPierre Pronchery 	struct dirent **files = NULL;
808*a3cefe7fSPierre Pronchery 	size_t size = 0;
809*a3cefe7fSPierre Pronchery 	size_t allocated = 0;
810*a3cefe7fSPierre Pronchery 	while (1) {
811*a3cefe7fSPierre Pronchery 		/* Allocate room for a temporary directory entry */
812*a3cefe7fSPierre Pronchery 		if (!tmp) {
813*a3cefe7fSPierre Pronchery 			tmp = (struct dirent*) malloc(sizeof(struct dirent));
814*a3cefe7fSPierre Pronchery 			if (!tmp)
815*a3cefe7fSPierre Pronchery 				goto exit_failure;
816*a3cefe7fSPierre Pronchery 		}
817*a3cefe7fSPierre Pronchery 
818*a3cefe7fSPierre Pronchery 		/* Read directory entry to temporary area */
819*a3cefe7fSPierre Pronchery 		struct dirent *entry;
820*a3cefe7fSPierre Pronchery 		if (readdir_r(dir, tmp, &entry) != /*OK*/0)
821*a3cefe7fSPierre Pronchery 			goto exit_failure;
822*a3cefe7fSPierre Pronchery 
823*a3cefe7fSPierre Pronchery 		/* Stop if we already read the last directory entry */
824*a3cefe7fSPierre Pronchery 		if (entry == NULL)
825*a3cefe7fSPierre Pronchery 			goto exit_success;
826*a3cefe7fSPierre Pronchery 
827*a3cefe7fSPierre Pronchery 		/* Determine whether to include the entry in results */
828*a3cefe7fSPierre Pronchery 		if (filter && !filter(tmp))
829*a3cefe7fSPierre Pronchery 			continue;
830*a3cefe7fSPierre Pronchery 
831*a3cefe7fSPierre Pronchery 		/* Enlarge pointer table to make room for another pointer */
832*a3cefe7fSPierre Pronchery 		if (size >= allocated) {
833*a3cefe7fSPierre Pronchery 			/* Compute number of entries in the new table */
834*a3cefe7fSPierre Pronchery 			size_t num_entries = size * 2 + 16;
835*a3cefe7fSPierre Pronchery 
836*a3cefe7fSPierre Pronchery 			/* Allocate new pointer table or enlarge existing */
837*a3cefe7fSPierre Pronchery 			void *p = realloc(files, sizeof(void*) * num_entries);
838*a3cefe7fSPierre Pronchery 			if (!p)
839*a3cefe7fSPierre Pronchery 				goto exit_failure;
840*a3cefe7fSPierre Pronchery 
841*a3cefe7fSPierre Pronchery 			/* Got the memory */
842*a3cefe7fSPierre Pronchery 			files = (dirent**) p;
843*a3cefe7fSPierre Pronchery 			allocated = num_entries;
844*a3cefe7fSPierre Pronchery 		}
845*a3cefe7fSPierre Pronchery 
846*a3cefe7fSPierre Pronchery 		/* Store the temporary entry to ptr table */
847*a3cefe7fSPierre Pronchery 		files[size++] = tmp;
848*a3cefe7fSPierre Pronchery 		tmp = NULL;
849*a3cefe7fSPierre Pronchery 	}
850*a3cefe7fSPierre Pronchery 
851*a3cefe7fSPierre Pronchery exit_failure:
852*a3cefe7fSPierre Pronchery 	/* Release allocated file entries */
853*a3cefe7fSPierre Pronchery 	for (size_t i = 0; i < size; i++) {
854*a3cefe7fSPierre Pronchery 		free(files[i]);
855*a3cefe7fSPierre Pronchery 	}
856*a3cefe7fSPierre Pronchery 
857*a3cefe7fSPierre Pronchery 	/* Release the pointer table */
858*a3cefe7fSPierre Pronchery 	free(files);
859*a3cefe7fSPierre Pronchery 	files = NULL;
860*a3cefe7fSPierre Pronchery 
861*a3cefe7fSPierre Pronchery 	/* Exit with error code */
862*a3cefe7fSPierre Pronchery 	result = /*error*/ -1;
863*a3cefe7fSPierre Pronchery 	goto exit_status;
864*a3cefe7fSPierre Pronchery 
865*a3cefe7fSPierre Pronchery exit_success:
866*a3cefe7fSPierre Pronchery 	/* Sort directory entries */
867*a3cefe7fSPierre Pronchery 	qsort(files, size, sizeof(void*),
868*a3cefe7fSPierre Pronchery 		(int (*) (const void*, const void*)) compare);
869*a3cefe7fSPierre Pronchery 
870*a3cefe7fSPierre Pronchery 	/* Pass pointer table to caller */
871*a3cefe7fSPierre Pronchery 	if (namelist)
872*a3cefe7fSPierre Pronchery 		*namelist = files;
873*a3cefe7fSPierre Pronchery 
874*a3cefe7fSPierre Pronchery 	/* Return the number of directory entries read */
875*a3cefe7fSPierre Pronchery 	result = (int) size;
876*a3cefe7fSPierre Pronchery 
877*a3cefe7fSPierre Pronchery exit_status:
878*a3cefe7fSPierre Pronchery 	/* Release temporary directory entry, if we had one */
879*a3cefe7fSPierre Pronchery 	free(tmp);
880*a3cefe7fSPierre Pronchery 
881*a3cefe7fSPierre Pronchery 	/* Close directory stream */
882*a3cefe7fSPierre Pronchery 	closedir(dir);
883*a3cefe7fSPierre Pronchery 	return result;
884*a3cefe7fSPierre Pronchery }
885*a3cefe7fSPierre Pronchery 
886*a3cefe7fSPierre Pronchery /* Alphabetical sorting */
alphasort(const struct dirent ** a,const struct dirent ** b)887*a3cefe7fSPierre Pronchery static int alphasort(const struct dirent **a, const struct dirent **b)
888*a3cefe7fSPierre Pronchery {
889*a3cefe7fSPierre Pronchery 	return strcoll((*a)->d_name, (*b)->d_name);
890*a3cefe7fSPierre Pronchery }
891*a3cefe7fSPierre Pronchery 
892*a3cefe7fSPierre Pronchery /* Sort versions */
versionsort(const struct dirent ** a,const struct dirent ** b)893*a3cefe7fSPierre Pronchery static int versionsort(const struct dirent **a, const struct dirent **b)
894*a3cefe7fSPierre Pronchery {
895*a3cefe7fSPierre Pronchery 	return strverscmp((*a)->d_name, (*b)->d_name);
896*a3cefe7fSPierre Pronchery }
897*a3cefe7fSPierre Pronchery 
898*a3cefe7fSPierre Pronchery /* Compare strings */
strverscmp(const char * a,const char * b)899*a3cefe7fSPierre Pronchery static int strverscmp(const char *a, const char *b)
900*a3cefe7fSPierre Pronchery {
901*a3cefe7fSPierre Pronchery 	size_t i = 0;
902*a3cefe7fSPierre Pronchery 	size_t j;
903*a3cefe7fSPierre Pronchery 
904*a3cefe7fSPierre Pronchery 	/* Find first difference */
905*a3cefe7fSPierre Pronchery 	while (a[i] == b[i]) {
906*a3cefe7fSPierre Pronchery 		if (a[i] == '\0') {
907*a3cefe7fSPierre Pronchery 			/* No difference */
908*a3cefe7fSPierre Pronchery 			return 0;
909*a3cefe7fSPierre Pronchery 		}
910*a3cefe7fSPierre Pronchery 		++i;
911*a3cefe7fSPierre Pronchery 	}
912*a3cefe7fSPierre Pronchery 
913*a3cefe7fSPierre Pronchery 	/* Count backwards and find the leftmost digit */
914*a3cefe7fSPierre Pronchery 	j = i;
915*a3cefe7fSPierre Pronchery 	while (j > 0 && isdigit((unsigned char)a[j-1])) {
916*a3cefe7fSPierre Pronchery 		--j;
917*a3cefe7fSPierre Pronchery 	}
918*a3cefe7fSPierre Pronchery 
919*a3cefe7fSPierre Pronchery 	/* Determine mode of comparison */
920*a3cefe7fSPierre Pronchery 	if (a[j] == '0' || b[j] == '0') {
921*a3cefe7fSPierre Pronchery 		/* Find the next non-zero digit */
922*a3cefe7fSPierre Pronchery 		while (a[j] == '0' && a[j] == b[j]) {
923*a3cefe7fSPierre Pronchery 			j++;
924*a3cefe7fSPierre Pronchery 		}
925*a3cefe7fSPierre Pronchery 
926*a3cefe7fSPierre Pronchery 		/* String with more digits is smaller, e.g 002 < 01 */
927*a3cefe7fSPierre Pronchery 		if (isdigit((unsigned char)a[j])) {
928*a3cefe7fSPierre Pronchery 			if (!isdigit((unsigned char)b[j])) {
929*a3cefe7fSPierre Pronchery 				return -1;
930*a3cefe7fSPierre Pronchery 			}
931*a3cefe7fSPierre Pronchery 		} else if ((unsigned char)isdigit(b[j])) {
932*a3cefe7fSPierre Pronchery 			return 1;
933*a3cefe7fSPierre Pronchery 		}
934*a3cefe7fSPierre Pronchery 	} else if ((unsigned char)isdigit(a[j]) &&
935*a3cefe7fSPierre Pronchery 	    isdigit((unsigned char)b[j])) {
936*a3cefe7fSPierre Pronchery 		/* Numeric comparison */
937*a3cefe7fSPierre Pronchery 		size_t k1 = j;
938*a3cefe7fSPierre Pronchery 		size_t k2 = j;
939*a3cefe7fSPierre Pronchery 
940*a3cefe7fSPierre Pronchery 		/* Compute number of digits in each string */
941*a3cefe7fSPierre Pronchery 		while (isdigit((unsigned char)a[k1])) {
942*a3cefe7fSPierre Pronchery 			k1++;
943*a3cefe7fSPierre Pronchery 		}
944*a3cefe7fSPierre Pronchery 		while (isdigit((unsigned char)b[k2])) {
945*a3cefe7fSPierre Pronchery 			k2++;
946*a3cefe7fSPierre Pronchery 		}
947*a3cefe7fSPierre Pronchery 
948*a3cefe7fSPierre Pronchery 		/* Number with more digits is bigger, e.g 999 < 1000 */
949*a3cefe7fSPierre Pronchery 		if (k1 < k2)
950*a3cefe7fSPierre Pronchery 			return -1;
951*a3cefe7fSPierre Pronchery 		else if (k1 > k2)
952*a3cefe7fSPierre Pronchery 			return 1;
953*a3cefe7fSPierre Pronchery 	}
954*a3cefe7fSPierre Pronchery 
955*a3cefe7fSPierre Pronchery 	/* Alphabetical comparison */
956*a3cefe7fSPierre Pronchery 	return (int) ((unsigned char) a[i]) - ((unsigned char) b[i]);
957*a3cefe7fSPierre Pronchery }
958*a3cefe7fSPierre Pronchery 
959*a3cefe7fSPierre Pronchery /* Convert multi-byte string to wide character string */
960*a3cefe7fSPierre Pronchery #if !defined(_MSC_VER) || _MSC_VER < 1400
dirent_mbstowcs_s(size_t * pReturnValue,wchar_t * wcstr,size_t sizeInWords,const char * mbstr,size_t count)961*a3cefe7fSPierre Pronchery static int dirent_mbstowcs_s(
962*a3cefe7fSPierre Pronchery 	size_t *pReturnValue, wchar_t *wcstr,
963*a3cefe7fSPierre Pronchery 	size_t sizeInWords, const char *mbstr, size_t count)
964*a3cefe7fSPierre Pronchery {
965*a3cefe7fSPierre Pronchery 	/* Older Visual Studio or non-Microsoft compiler */
966*a3cefe7fSPierre Pronchery 	size_t n = mbstowcs(wcstr, mbstr, sizeInWords);
967*a3cefe7fSPierre Pronchery 	if (wcstr && n >= count)
968*a3cefe7fSPierre Pronchery 		return /*error*/ 1;
969*a3cefe7fSPierre Pronchery 
970*a3cefe7fSPierre Pronchery 	/* Zero-terminate output buffer */
971*a3cefe7fSPierre Pronchery 	if (wcstr && sizeInWords) {
972*a3cefe7fSPierre Pronchery 		if (n >= sizeInWords)
973*a3cefe7fSPierre Pronchery 			n = sizeInWords - 1;
974*a3cefe7fSPierre Pronchery 		wcstr[n] = 0;
975*a3cefe7fSPierre Pronchery 	}
976*a3cefe7fSPierre Pronchery 
977*a3cefe7fSPierre Pronchery 	/* Length of multi-byte string with zero terminator */
978*a3cefe7fSPierre Pronchery 	if (pReturnValue) {
979*a3cefe7fSPierre Pronchery 		*pReturnValue = n + 1;
980*a3cefe7fSPierre Pronchery 	}
981*a3cefe7fSPierre Pronchery 
982*a3cefe7fSPierre Pronchery 	/* Success */
983*a3cefe7fSPierre Pronchery 	return 0;
984*a3cefe7fSPierre Pronchery }
985*a3cefe7fSPierre Pronchery #endif
986*a3cefe7fSPierre Pronchery 
987*a3cefe7fSPierre Pronchery /* Convert wide-character string to multi-byte string */
988*a3cefe7fSPierre Pronchery #if !defined(_MSC_VER) || _MSC_VER < 1400
dirent_wcstombs_s(size_t * pReturnValue,char * mbstr,size_t sizeInBytes,const wchar_t * wcstr,size_t count)989*a3cefe7fSPierre Pronchery static int dirent_wcstombs_s(
990*a3cefe7fSPierre Pronchery 	size_t *pReturnValue, char *mbstr,
991*a3cefe7fSPierre Pronchery 	size_t sizeInBytes, const wchar_t *wcstr, size_t count)
992*a3cefe7fSPierre Pronchery {
993*a3cefe7fSPierre Pronchery 	/* Older Visual Studio or non-Microsoft compiler */
994*a3cefe7fSPierre Pronchery 	size_t n = wcstombs(mbstr, wcstr, sizeInBytes);
995*a3cefe7fSPierre Pronchery 	if (mbstr && n >= count)
996*a3cefe7fSPierre Pronchery 		return /*error*/1;
997*a3cefe7fSPierre Pronchery 
998*a3cefe7fSPierre Pronchery 	/* Zero-terminate output buffer */
999*a3cefe7fSPierre Pronchery 	if (mbstr && sizeInBytes) {
1000*a3cefe7fSPierre Pronchery 		if (n >= sizeInBytes) {
1001*a3cefe7fSPierre Pronchery 			n = sizeInBytes - 1;
1002*a3cefe7fSPierre Pronchery 		}
1003*a3cefe7fSPierre Pronchery 		mbstr[n] = '\0';
1004*a3cefe7fSPierre Pronchery 	}
1005*a3cefe7fSPierre Pronchery 
1006*a3cefe7fSPierre Pronchery 	/* Length of resulting multi-bytes string WITH zero-terminator */
1007*a3cefe7fSPierre Pronchery 	if (pReturnValue) {
1008*a3cefe7fSPierre Pronchery 		*pReturnValue = n + 1;
1009*a3cefe7fSPierre Pronchery 	}
1010*a3cefe7fSPierre Pronchery 
1011*a3cefe7fSPierre Pronchery 	/* Success */
1012*a3cefe7fSPierre Pronchery 	return 0;
1013*a3cefe7fSPierre Pronchery }
1014*a3cefe7fSPierre Pronchery #endif
1015*a3cefe7fSPierre Pronchery 
1016*a3cefe7fSPierre Pronchery /* Set errno variable */
1017*a3cefe7fSPierre Pronchery #if !defined(_MSC_VER) || _MSC_VER < 1400
dirent_set_errno(int error)1018*a3cefe7fSPierre Pronchery static void dirent_set_errno(int error)
1019*a3cefe7fSPierre Pronchery {
1020*a3cefe7fSPierre Pronchery 	/* Non-Microsoft compiler or older Microsoft compiler */
1021*a3cefe7fSPierre Pronchery 	errno = error;
1022*a3cefe7fSPierre Pronchery }
1023*a3cefe7fSPierre Pronchery #endif
1024*a3cefe7fSPierre Pronchery 
1025*a3cefe7fSPierre Pronchery #ifdef __cplusplus
1026*a3cefe7fSPierre Pronchery }
1027*a3cefe7fSPierre Pronchery #endif
1028*a3cefe7fSPierre Pronchery #endif /*DIRENT_H*/
1029