xref: /btstack/3rd-party/tinydir/tinydir.h (revision 98cd9557da96230d06c9149ea591e10cc3829288)
1*98cd9557SMatthias Ringwald /*
2*98cd9557SMatthias Ringwald Copyright (c) 2013-2017, tinydir authors:
3*98cd9557SMatthias Ringwald - Cong Xu
4*98cd9557SMatthias Ringwald - Lautis Sun
5*98cd9557SMatthias Ringwald - Baudouin Feildel
6*98cd9557SMatthias Ringwald - Andargor <[email protected]>
7*98cd9557SMatthias Ringwald All rights reserved.
8*98cd9557SMatthias Ringwald 
9*98cd9557SMatthias Ringwald Redistribution and use in source and binary forms, with or without
10*98cd9557SMatthias Ringwald modification, are permitted provided that the following conditions are met:
11*98cd9557SMatthias Ringwald 
12*98cd9557SMatthias Ringwald 1. Redistributions of source code must retain the above copyright notice, this
13*98cd9557SMatthias Ringwald    list of conditions and the following disclaimer.
14*98cd9557SMatthias Ringwald 2. Redistributions in binary form must reproduce the above copyright notice,
15*98cd9557SMatthias Ringwald    this list of conditions and the following disclaimer in the documentation
16*98cd9557SMatthias Ringwald    and/or other materials provided with the distribution.
17*98cd9557SMatthias Ringwald 
18*98cd9557SMatthias Ringwald THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19*98cd9557SMatthias Ringwald ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20*98cd9557SMatthias Ringwald WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21*98cd9557SMatthias Ringwald DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22*98cd9557SMatthias Ringwald ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23*98cd9557SMatthias Ringwald (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24*98cd9557SMatthias Ringwald LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25*98cd9557SMatthias Ringwald ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*98cd9557SMatthias Ringwald (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27*98cd9557SMatthias Ringwald SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*98cd9557SMatthias Ringwald */
29*98cd9557SMatthias Ringwald #ifndef TINYDIR_H
30*98cd9557SMatthias Ringwald #define TINYDIR_H
31*98cd9557SMatthias Ringwald 
32*98cd9557SMatthias Ringwald #ifdef __cplusplus
33*98cd9557SMatthias Ringwald extern "C" {
34*98cd9557SMatthias Ringwald #endif
35*98cd9557SMatthias Ringwald 
36*98cd9557SMatthias Ringwald #if ((defined _UNICODE) && !(defined UNICODE))
37*98cd9557SMatthias Ringwald #define UNICODE
38*98cd9557SMatthias Ringwald #endif
39*98cd9557SMatthias Ringwald 
40*98cd9557SMatthias Ringwald #if ((defined UNICODE) && !(defined _UNICODE))
41*98cd9557SMatthias Ringwald #define _UNICODE
42*98cd9557SMatthias Ringwald #endif
43*98cd9557SMatthias Ringwald 
44*98cd9557SMatthias Ringwald #include <errno.h>
45*98cd9557SMatthias Ringwald #include <stdlib.h>
46*98cd9557SMatthias Ringwald #include <string.h>
47*98cd9557SMatthias Ringwald #ifdef _MSC_VER
48*98cd9557SMatthias Ringwald # define WIN32_LEAN_AND_MEAN
49*98cd9557SMatthias Ringwald # include <windows.h>
50*98cd9557SMatthias Ringwald # include <tchar.h>
51*98cd9557SMatthias Ringwald # pragma warning(push)
52*98cd9557SMatthias Ringwald # pragma warning (disable : 4996)
53*98cd9557SMatthias Ringwald #else
54*98cd9557SMatthias Ringwald # include <dirent.h>
55*98cd9557SMatthias Ringwald # include <libgen.h>
56*98cd9557SMatthias Ringwald # include <sys/stat.h>
57*98cd9557SMatthias Ringwald # include <stddef.h>
58*98cd9557SMatthias Ringwald #endif
59*98cd9557SMatthias Ringwald #ifdef __MINGW32__
60*98cd9557SMatthias Ringwald # include <tchar.h>
61*98cd9557SMatthias Ringwald #endif
62*98cd9557SMatthias Ringwald 
63*98cd9557SMatthias Ringwald 
64*98cd9557SMatthias Ringwald /* types */
65*98cd9557SMatthias Ringwald 
66*98cd9557SMatthias Ringwald /* Windows UNICODE wide character support */
67*98cd9557SMatthias Ringwald #if defined _MSC_VER || defined __MINGW32__
68*98cd9557SMatthias Ringwald # define _tinydir_char_t TCHAR
69*98cd9557SMatthias Ringwald # define TINYDIR_STRING(s) _TEXT(s)
70*98cd9557SMatthias Ringwald # define _tinydir_strlen _tcslen
71*98cd9557SMatthias Ringwald # define _tinydir_strcpy _tcscpy
72*98cd9557SMatthias Ringwald # define _tinydir_strcat _tcscat
73*98cd9557SMatthias Ringwald # define _tinydir_strcmp _tcscmp
74*98cd9557SMatthias Ringwald # define _tinydir_strrchr _tcsrchr
75*98cd9557SMatthias Ringwald # define _tinydir_strncmp _tcsncmp
76*98cd9557SMatthias Ringwald #else
77*98cd9557SMatthias Ringwald # define _tinydir_char_t char
78*98cd9557SMatthias Ringwald # define TINYDIR_STRING(s) s
79*98cd9557SMatthias Ringwald # define _tinydir_strlen strlen
80*98cd9557SMatthias Ringwald # define _tinydir_strcpy strcpy
81*98cd9557SMatthias Ringwald # define _tinydir_strcat strcat
82*98cd9557SMatthias Ringwald # define _tinydir_strcmp strcmp
83*98cd9557SMatthias Ringwald # define _tinydir_strrchr strrchr
84*98cd9557SMatthias Ringwald # define _tinydir_strncmp strncmp
85*98cd9557SMatthias Ringwald #endif
86*98cd9557SMatthias Ringwald 
87*98cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
88*98cd9557SMatthias Ringwald # include <windows.h>
89*98cd9557SMatthias Ringwald # define _TINYDIR_PATH_MAX MAX_PATH
90*98cd9557SMatthias Ringwald #elif defined  __linux__
91*98cd9557SMatthias Ringwald # include <limits.h>
92*98cd9557SMatthias Ringwald # define _TINYDIR_PATH_MAX PATH_MAX
93*98cd9557SMatthias Ringwald #elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
94*98cd9557SMatthias Ringwald # include <sys/param.h>
95*98cd9557SMatthias Ringwald # if defined(BSD)
96*98cd9557SMatthias Ringwald #  include <limits.h>
97*98cd9557SMatthias Ringwald #  define _TINYDIR_PATH_MAX PATH_MAX
98*98cd9557SMatthias Ringwald # endif
99*98cd9557SMatthias Ringwald #endif
100*98cd9557SMatthias Ringwald 
101*98cd9557SMatthias Ringwald #ifndef _TINYDIR_PATH_MAX
102*98cd9557SMatthias Ringwald #define _TINYDIR_PATH_MAX 4096
103*98cd9557SMatthias Ringwald #endif
104*98cd9557SMatthias Ringwald 
105*98cd9557SMatthias Ringwald #ifdef _MSC_VER
106*98cd9557SMatthias Ringwald /* extra chars for the "\\*" mask */
107*98cd9557SMatthias Ringwald # define _TINYDIR_PATH_EXTRA 2
108*98cd9557SMatthias Ringwald #else
109*98cd9557SMatthias Ringwald # define _TINYDIR_PATH_EXTRA 0
110*98cd9557SMatthias Ringwald #endif
111*98cd9557SMatthias Ringwald 
112*98cd9557SMatthias Ringwald #define _TINYDIR_FILENAME_MAX 256
113*98cd9557SMatthias Ringwald 
114*98cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
115*98cd9557SMatthias Ringwald #define _TINYDIR_DRIVE_MAX 3
116*98cd9557SMatthias Ringwald #endif
117*98cd9557SMatthias Ringwald 
118*98cd9557SMatthias Ringwald #ifdef _MSC_VER
119*98cd9557SMatthias Ringwald # define _TINYDIR_FUNC static __inline
120*98cd9557SMatthias Ringwald #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
121*98cd9557SMatthias Ringwald # define _TINYDIR_FUNC static __inline__
122*98cd9557SMatthias Ringwald #else
123*98cd9557SMatthias Ringwald # define _TINYDIR_FUNC static inline
124*98cd9557SMatthias Ringwald #endif
125*98cd9557SMatthias Ringwald 
126*98cd9557SMatthias Ringwald /* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
127*98cd9557SMatthias Ringwald #ifdef TINYDIR_USE_READDIR_R
128*98cd9557SMatthias Ringwald 
129*98cd9557SMatthias Ringwald /* readdir_r is a POSIX-only function, and may not be available under various
130*98cd9557SMatthias Ringwald  * environments/settings, e.g. MinGW. Use readdir fallback */
131*98cd9557SMatthias Ringwald #if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
132*98cd9557SMatthias Ringwald 	_POSIX_SOURCE
133*98cd9557SMatthias Ringwald # define _TINYDIR_HAS_READDIR_R
134*98cd9557SMatthias Ringwald #endif
135*98cd9557SMatthias Ringwald #if _POSIX_C_SOURCE >= 200112L
136*98cd9557SMatthias Ringwald # define _TINYDIR_HAS_FPATHCONF
137*98cd9557SMatthias Ringwald # include <unistd.h>
138*98cd9557SMatthias Ringwald #endif
139*98cd9557SMatthias Ringwald #if _BSD_SOURCE || _SVID_SOURCE || \
140*98cd9557SMatthias Ringwald 	(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
141*98cd9557SMatthias Ringwald # define _TINYDIR_HAS_DIRFD
142*98cd9557SMatthias Ringwald # include <sys/types.h>
143*98cd9557SMatthias Ringwald #endif
144*98cd9557SMatthias Ringwald #if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
145*98cd9557SMatthias Ringwald 	defined _PC_NAME_MAX
146*98cd9557SMatthias Ringwald # define _TINYDIR_USE_FPATHCONF
147*98cd9557SMatthias Ringwald #endif
148*98cd9557SMatthias Ringwald #if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
149*98cd9557SMatthias Ringwald 	!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
150*98cd9557SMatthias Ringwald # define _TINYDIR_USE_READDIR
151*98cd9557SMatthias Ringwald #endif
152*98cd9557SMatthias Ringwald 
153*98cd9557SMatthias Ringwald /* Use readdir by default */
154*98cd9557SMatthias Ringwald #else
155*98cd9557SMatthias Ringwald # define _TINYDIR_USE_READDIR
156*98cd9557SMatthias Ringwald #endif
157*98cd9557SMatthias Ringwald 
158*98cd9557SMatthias Ringwald /* MINGW32 has two versions of dirent, ASCII and UNICODE*/
159*98cd9557SMatthias Ringwald #ifndef _MSC_VER
160*98cd9557SMatthias Ringwald #if (defined __MINGW32__) && (defined _UNICODE)
161*98cd9557SMatthias Ringwald #define _TINYDIR_DIR _WDIR
162*98cd9557SMatthias Ringwald #define _tinydir_dirent _wdirent
163*98cd9557SMatthias Ringwald #define _tinydir_opendir _wopendir
164*98cd9557SMatthias Ringwald #define _tinydir_readdir _wreaddir
165*98cd9557SMatthias Ringwald #define _tinydir_closedir _wclosedir
166*98cd9557SMatthias Ringwald #else
167*98cd9557SMatthias Ringwald #define _TINYDIR_DIR DIR
168*98cd9557SMatthias Ringwald #define _tinydir_dirent dirent
169*98cd9557SMatthias Ringwald #define _tinydir_opendir opendir
170*98cd9557SMatthias Ringwald #define _tinydir_readdir readdir
171*98cd9557SMatthias Ringwald #define _tinydir_closedir closedir
172*98cd9557SMatthias Ringwald #endif
173*98cd9557SMatthias Ringwald #endif
174*98cd9557SMatthias Ringwald 
175*98cd9557SMatthias Ringwald /* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
176*98cd9557SMatthias Ringwald #if    defined(_TINYDIR_MALLOC) &&  defined(_TINYDIR_FREE)
177*98cd9557SMatthias Ringwald #elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
178*98cd9557SMatthias Ringwald #else
179*98cd9557SMatthias Ringwald #error "Either define both alloc and free or none of them!"
180*98cd9557SMatthias Ringwald #endif
181*98cd9557SMatthias Ringwald 
182*98cd9557SMatthias Ringwald #if !defined(_TINYDIR_MALLOC)
183*98cd9557SMatthias Ringwald 	#define _TINYDIR_MALLOC(_size) malloc(_size)
184*98cd9557SMatthias Ringwald 	#define _TINYDIR_FREE(_ptr)    free(_ptr)
185*98cd9557SMatthias Ringwald #endif /* !defined(_TINYDIR_MALLOC) */
186*98cd9557SMatthias Ringwald 
187*98cd9557SMatthias Ringwald typedef struct tinydir_file
188*98cd9557SMatthias Ringwald {
189*98cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
190*98cd9557SMatthias Ringwald 	_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
191*98cd9557SMatthias Ringwald 	_tinydir_char_t *extension;
192*98cd9557SMatthias Ringwald 	int is_dir;
193*98cd9557SMatthias Ringwald 	int is_reg;
194*98cd9557SMatthias Ringwald 
195*98cd9557SMatthias Ringwald #ifndef _MSC_VER
196*98cd9557SMatthias Ringwald #ifdef __MINGW32__
197*98cd9557SMatthias Ringwald 	struct _stat _s;
198*98cd9557SMatthias Ringwald #else
199*98cd9557SMatthias Ringwald 	struct stat _s;
200*98cd9557SMatthias Ringwald #endif
201*98cd9557SMatthias Ringwald #endif
202*98cd9557SMatthias Ringwald } tinydir_file;
203*98cd9557SMatthias Ringwald 
204*98cd9557SMatthias Ringwald typedef struct tinydir_dir
205*98cd9557SMatthias Ringwald {
206*98cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
207*98cd9557SMatthias Ringwald 	int has_next;
208*98cd9557SMatthias Ringwald 	size_t n_files;
209*98cd9557SMatthias Ringwald 
210*98cd9557SMatthias Ringwald 	tinydir_file *_files;
211*98cd9557SMatthias Ringwald #ifdef _MSC_VER
212*98cd9557SMatthias Ringwald 	HANDLE _h;
213*98cd9557SMatthias Ringwald 	WIN32_FIND_DATA _f;
214*98cd9557SMatthias Ringwald #else
215*98cd9557SMatthias Ringwald 	_TINYDIR_DIR *_d;
216*98cd9557SMatthias Ringwald 	struct _tinydir_dirent *_e;
217*98cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
218*98cd9557SMatthias Ringwald 	struct _tinydir_dirent *_ep;
219*98cd9557SMatthias Ringwald #endif
220*98cd9557SMatthias Ringwald #endif
221*98cd9557SMatthias Ringwald } tinydir_dir;
222*98cd9557SMatthias Ringwald 
223*98cd9557SMatthias Ringwald 
224*98cd9557SMatthias Ringwald /* declarations */
225*98cd9557SMatthias Ringwald 
226*98cd9557SMatthias Ringwald _TINYDIR_FUNC
227*98cd9557SMatthias Ringwald int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
228*98cd9557SMatthias Ringwald _TINYDIR_FUNC
229*98cd9557SMatthias Ringwald int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
230*98cd9557SMatthias Ringwald _TINYDIR_FUNC
231*98cd9557SMatthias Ringwald void tinydir_close(tinydir_dir *dir);
232*98cd9557SMatthias Ringwald 
233*98cd9557SMatthias Ringwald _TINYDIR_FUNC
234*98cd9557SMatthias Ringwald int tinydir_next(tinydir_dir *dir);
235*98cd9557SMatthias Ringwald _TINYDIR_FUNC
236*98cd9557SMatthias Ringwald int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
237*98cd9557SMatthias Ringwald _TINYDIR_FUNC
238*98cd9557SMatthias Ringwald int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
239*98cd9557SMatthias Ringwald _TINYDIR_FUNC
240*98cd9557SMatthias Ringwald int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
241*98cd9557SMatthias Ringwald 
242*98cd9557SMatthias Ringwald _TINYDIR_FUNC
243*98cd9557SMatthias Ringwald int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
244*98cd9557SMatthias Ringwald _TINYDIR_FUNC
245*98cd9557SMatthias Ringwald void _tinydir_get_ext(tinydir_file *file);
246*98cd9557SMatthias Ringwald _TINYDIR_FUNC
247*98cd9557SMatthias Ringwald int _tinydir_file_cmp(const void *a, const void *b);
248*98cd9557SMatthias Ringwald #ifndef _MSC_VER
249*98cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
250*98cd9557SMatthias Ringwald _TINYDIR_FUNC
251*98cd9557SMatthias Ringwald size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
252*98cd9557SMatthias Ringwald #endif
253*98cd9557SMatthias Ringwald #endif
254*98cd9557SMatthias Ringwald 
255*98cd9557SMatthias Ringwald 
256*98cd9557SMatthias Ringwald /* definitions*/
257*98cd9557SMatthias Ringwald 
258*98cd9557SMatthias Ringwald _TINYDIR_FUNC
259*98cd9557SMatthias Ringwald int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
260*98cd9557SMatthias Ringwald {
261*98cd9557SMatthias Ringwald #ifndef _MSC_VER
262*98cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
263*98cd9557SMatthias Ringwald 	int error;
264*98cd9557SMatthias Ringwald 	int size;	/* using int size */
265*98cd9557SMatthias Ringwald #endif
266*98cd9557SMatthias Ringwald #else
267*98cd9557SMatthias Ringwald 	_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
268*98cd9557SMatthias Ringwald #endif
269*98cd9557SMatthias Ringwald 	_tinydir_char_t *pathp;
270*98cd9557SMatthias Ringwald 
271*98cd9557SMatthias Ringwald 	if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
272*98cd9557SMatthias Ringwald 	{
273*98cd9557SMatthias Ringwald 		errno = EINVAL;
274*98cd9557SMatthias Ringwald 		return -1;
275*98cd9557SMatthias Ringwald 	}
276*98cd9557SMatthias Ringwald 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
277*98cd9557SMatthias Ringwald 	{
278*98cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
279*98cd9557SMatthias Ringwald 		return -1;
280*98cd9557SMatthias Ringwald 	}
281*98cd9557SMatthias Ringwald 
282*98cd9557SMatthias Ringwald 	/* initialise dir */
283*98cd9557SMatthias Ringwald 	dir->_files = NULL;
284*98cd9557SMatthias Ringwald #ifdef _MSC_VER
285*98cd9557SMatthias Ringwald 	dir->_h = INVALID_HANDLE_VALUE;
286*98cd9557SMatthias Ringwald #else
287*98cd9557SMatthias Ringwald 	dir->_d = NULL;
288*98cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
289*98cd9557SMatthias Ringwald 	dir->_ep = NULL;
290*98cd9557SMatthias Ringwald #endif
291*98cd9557SMatthias Ringwald #endif
292*98cd9557SMatthias Ringwald 	tinydir_close(dir);
293*98cd9557SMatthias Ringwald 
294*98cd9557SMatthias Ringwald 	_tinydir_strcpy(dir->path, path);
295*98cd9557SMatthias Ringwald 	/* Remove trailing slashes */
296*98cd9557SMatthias Ringwald 	pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
297*98cd9557SMatthias Ringwald 	while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
298*98cd9557SMatthias Ringwald 	{
299*98cd9557SMatthias Ringwald 		*pathp = TINYDIR_STRING('\0');
300*98cd9557SMatthias Ringwald 		pathp++;
301*98cd9557SMatthias Ringwald 	}
302*98cd9557SMatthias Ringwald #ifdef _MSC_VER
303*98cd9557SMatthias Ringwald 	_tinydir_strcpy(path_buf, dir->path);
304*98cd9557SMatthias Ringwald 	_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
305*98cd9557SMatthias Ringwald #if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
306*98cd9557SMatthias Ringwald 	dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
307*98cd9557SMatthias Ringwald #else
308*98cd9557SMatthias Ringwald 	dir->_h = FindFirstFile(path_buf, &dir->_f);
309*98cd9557SMatthias Ringwald #endif
310*98cd9557SMatthias Ringwald 	if (dir->_h == INVALID_HANDLE_VALUE)
311*98cd9557SMatthias Ringwald 	{
312*98cd9557SMatthias Ringwald 		errno = ENOENT;
313*98cd9557SMatthias Ringwald #else
314*98cd9557SMatthias Ringwald 	dir->_d = _tinydir_opendir(path);
315*98cd9557SMatthias Ringwald 	if (dir->_d == NULL)
316*98cd9557SMatthias Ringwald 	{
317*98cd9557SMatthias Ringwald #endif
318*98cd9557SMatthias Ringwald 		goto bail;
319*98cd9557SMatthias Ringwald 	}
320*98cd9557SMatthias Ringwald 
321*98cd9557SMatthias Ringwald 	/* read first file */
322*98cd9557SMatthias Ringwald 	dir->has_next = 1;
323*98cd9557SMatthias Ringwald #ifndef _MSC_VER
324*98cd9557SMatthias Ringwald #ifdef _TINYDIR_USE_READDIR
325*98cd9557SMatthias Ringwald 	dir->_e = _tinydir_readdir(dir->_d);
326*98cd9557SMatthias Ringwald #else
327*98cd9557SMatthias Ringwald 	/* allocate dirent buffer for readdir_r */
328*98cd9557SMatthias Ringwald 	size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
329*98cd9557SMatthias Ringwald 	if (size == -1) return -1;
330*98cd9557SMatthias Ringwald 	dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
331*98cd9557SMatthias Ringwald 	if (dir->_ep == NULL) return -1;
332*98cd9557SMatthias Ringwald 
333*98cd9557SMatthias Ringwald 	error = readdir_r(dir->_d, dir->_ep, &dir->_e);
334*98cd9557SMatthias Ringwald 	if (error != 0) return -1;
335*98cd9557SMatthias Ringwald #endif
336*98cd9557SMatthias Ringwald 	if (dir->_e == NULL)
337*98cd9557SMatthias Ringwald 	{
338*98cd9557SMatthias Ringwald 		dir->has_next = 0;
339*98cd9557SMatthias Ringwald 	}
340*98cd9557SMatthias Ringwald #endif
341*98cd9557SMatthias Ringwald 
342*98cd9557SMatthias Ringwald 	return 0;
343*98cd9557SMatthias Ringwald 
344*98cd9557SMatthias Ringwald bail:
345*98cd9557SMatthias Ringwald 	tinydir_close(dir);
346*98cd9557SMatthias Ringwald 	return -1;
347*98cd9557SMatthias Ringwald }
348*98cd9557SMatthias Ringwald 
349*98cd9557SMatthias Ringwald _TINYDIR_FUNC
350*98cd9557SMatthias Ringwald int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
351*98cd9557SMatthias Ringwald {
352*98cd9557SMatthias Ringwald 	/* Count the number of files first, to pre-allocate the files array */
353*98cd9557SMatthias Ringwald 	size_t n_files = 0;
354*98cd9557SMatthias Ringwald 	if (tinydir_open(dir, path) == -1)
355*98cd9557SMatthias Ringwald 	{
356*98cd9557SMatthias Ringwald 		return -1;
357*98cd9557SMatthias Ringwald 	}
358*98cd9557SMatthias Ringwald 	while (dir->has_next)
359*98cd9557SMatthias Ringwald 	{
360*98cd9557SMatthias Ringwald 		n_files++;
361*98cd9557SMatthias Ringwald 		if (tinydir_next(dir) == -1)
362*98cd9557SMatthias Ringwald 		{
363*98cd9557SMatthias Ringwald 			goto bail;
364*98cd9557SMatthias Ringwald 		}
365*98cd9557SMatthias Ringwald 	}
366*98cd9557SMatthias Ringwald 	tinydir_close(dir);
367*98cd9557SMatthias Ringwald 
368*98cd9557SMatthias Ringwald 	if (tinydir_open(dir, path) == -1)
369*98cd9557SMatthias Ringwald 	{
370*98cd9557SMatthias Ringwald 		return -1;
371*98cd9557SMatthias Ringwald 	}
372*98cd9557SMatthias Ringwald 
373*98cd9557SMatthias Ringwald 	dir->n_files = 0;
374*98cd9557SMatthias Ringwald 	dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
375*98cd9557SMatthias Ringwald 	if (dir->_files == NULL)
376*98cd9557SMatthias Ringwald 	{
377*98cd9557SMatthias Ringwald 		goto bail;
378*98cd9557SMatthias Ringwald 	}
379*98cd9557SMatthias Ringwald 	while (dir->has_next)
380*98cd9557SMatthias Ringwald 	{
381*98cd9557SMatthias Ringwald 		tinydir_file *p_file;
382*98cd9557SMatthias Ringwald 		dir->n_files++;
383*98cd9557SMatthias Ringwald 
384*98cd9557SMatthias Ringwald 		p_file = &dir->_files[dir->n_files - 1];
385*98cd9557SMatthias Ringwald 		if (tinydir_readfile(dir, p_file) == -1)
386*98cd9557SMatthias Ringwald 		{
387*98cd9557SMatthias Ringwald 			goto bail;
388*98cd9557SMatthias Ringwald 		}
389*98cd9557SMatthias Ringwald 
390*98cd9557SMatthias Ringwald 		if (tinydir_next(dir) == -1)
391*98cd9557SMatthias Ringwald 		{
392*98cd9557SMatthias Ringwald 			goto bail;
393*98cd9557SMatthias Ringwald 		}
394*98cd9557SMatthias Ringwald 
395*98cd9557SMatthias Ringwald 		/* Just in case the number of files has changed between the first and
396*98cd9557SMatthias Ringwald 		second reads, terminate without writing into unallocated memory */
397*98cd9557SMatthias Ringwald 		if (dir->n_files == n_files)
398*98cd9557SMatthias Ringwald 		{
399*98cd9557SMatthias Ringwald 			break;
400*98cd9557SMatthias Ringwald 		}
401*98cd9557SMatthias Ringwald 	}
402*98cd9557SMatthias Ringwald 
403*98cd9557SMatthias Ringwald 	qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
404*98cd9557SMatthias Ringwald 
405*98cd9557SMatthias Ringwald 	return 0;
406*98cd9557SMatthias Ringwald 
407*98cd9557SMatthias Ringwald bail:
408*98cd9557SMatthias Ringwald 	tinydir_close(dir);
409*98cd9557SMatthias Ringwald 	return -1;
410*98cd9557SMatthias Ringwald }
411*98cd9557SMatthias Ringwald 
412*98cd9557SMatthias Ringwald _TINYDIR_FUNC
413*98cd9557SMatthias Ringwald void tinydir_close(tinydir_dir *dir)
414*98cd9557SMatthias Ringwald {
415*98cd9557SMatthias Ringwald 	if (dir == NULL)
416*98cd9557SMatthias Ringwald 	{
417*98cd9557SMatthias Ringwald 		return;
418*98cd9557SMatthias Ringwald 	}
419*98cd9557SMatthias Ringwald 
420*98cd9557SMatthias Ringwald 	memset(dir->path, 0, sizeof(dir->path));
421*98cd9557SMatthias Ringwald 	dir->has_next = 0;
422*98cd9557SMatthias Ringwald 	dir->n_files = 0;
423*98cd9557SMatthias Ringwald 	_TINYDIR_FREE(dir->_files);
424*98cd9557SMatthias Ringwald 	dir->_files = NULL;
425*98cd9557SMatthias Ringwald #ifdef _MSC_VER
426*98cd9557SMatthias Ringwald 	if (dir->_h != INVALID_HANDLE_VALUE)
427*98cd9557SMatthias Ringwald 	{
428*98cd9557SMatthias Ringwald 		FindClose(dir->_h);
429*98cd9557SMatthias Ringwald 	}
430*98cd9557SMatthias Ringwald 	dir->_h = INVALID_HANDLE_VALUE;
431*98cd9557SMatthias Ringwald #else
432*98cd9557SMatthias Ringwald 	if (dir->_d)
433*98cd9557SMatthias Ringwald 	{
434*98cd9557SMatthias Ringwald 		_tinydir_closedir(dir->_d);
435*98cd9557SMatthias Ringwald 	}
436*98cd9557SMatthias Ringwald 	dir->_d = NULL;
437*98cd9557SMatthias Ringwald 	dir->_e = NULL;
438*98cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
439*98cd9557SMatthias Ringwald 	_TINYDIR_FREE(dir->_ep);
440*98cd9557SMatthias Ringwald 	dir->_ep = NULL;
441*98cd9557SMatthias Ringwald #endif
442*98cd9557SMatthias Ringwald #endif
443*98cd9557SMatthias Ringwald }
444*98cd9557SMatthias Ringwald 
445*98cd9557SMatthias Ringwald _TINYDIR_FUNC
446*98cd9557SMatthias Ringwald int tinydir_next(tinydir_dir *dir)
447*98cd9557SMatthias Ringwald {
448*98cd9557SMatthias Ringwald 	if (dir == NULL)
449*98cd9557SMatthias Ringwald 	{
450*98cd9557SMatthias Ringwald 		errno = EINVAL;
451*98cd9557SMatthias Ringwald 		return -1;
452*98cd9557SMatthias Ringwald 	}
453*98cd9557SMatthias Ringwald 	if (!dir->has_next)
454*98cd9557SMatthias Ringwald 	{
455*98cd9557SMatthias Ringwald 		errno = ENOENT;
456*98cd9557SMatthias Ringwald 		return -1;
457*98cd9557SMatthias Ringwald 	}
458*98cd9557SMatthias Ringwald 
459*98cd9557SMatthias Ringwald #ifdef _MSC_VER
460*98cd9557SMatthias Ringwald 	if (FindNextFile(dir->_h, &dir->_f) == 0)
461*98cd9557SMatthias Ringwald #else
462*98cd9557SMatthias Ringwald #ifdef _TINYDIR_USE_READDIR
463*98cd9557SMatthias Ringwald 	dir->_e = _tinydir_readdir(dir->_d);
464*98cd9557SMatthias Ringwald #else
465*98cd9557SMatthias Ringwald 	if (dir->_ep == NULL)
466*98cd9557SMatthias Ringwald 	{
467*98cd9557SMatthias Ringwald 		return -1;
468*98cd9557SMatthias Ringwald 	}
469*98cd9557SMatthias Ringwald 	if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
470*98cd9557SMatthias Ringwald 	{
471*98cd9557SMatthias Ringwald 		return -1;
472*98cd9557SMatthias Ringwald 	}
473*98cd9557SMatthias Ringwald #endif
474*98cd9557SMatthias Ringwald 	if (dir->_e == NULL)
475*98cd9557SMatthias Ringwald #endif
476*98cd9557SMatthias Ringwald 	{
477*98cd9557SMatthias Ringwald 		dir->has_next = 0;
478*98cd9557SMatthias Ringwald #ifdef _MSC_VER
479*98cd9557SMatthias Ringwald 		if (GetLastError() != ERROR_SUCCESS &&
480*98cd9557SMatthias Ringwald 			GetLastError() != ERROR_NO_MORE_FILES)
481*98cd9557SMatthias Ringwald 		{
482*98cd9557SMatthias Ringwald 			tinydir_close(dir);
483*98cd9557SMatthias Ringwald 			errno = EIO;
484*98cd9557SMatthias Ringwald 			return -1;
485*98cd9557SMatthias Ringwald 		}
486*98cd9557SMatthias Ringwald #endif
487*98cd9557SMatthias Ringwald 	}
488*98cd9557SMatthias Ringwald 
489*98cd9557SMatthias Ringwald 	return 0;
490*98cd9557SMatthias Ringwald }
491*98cd9557SMatthias Ringwald 
492*98cd9557SMatthias Ringwald _TINYDIR_FUNC
493*98cd9557SMatthias Ringwald int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
494*98cd9557SMatthias Ringwald {
495*98cd9557SMatthias Ringwald 	if (dir == NULL || file == NULL)
496*98cd9557SMatthias Ringwald 	{
497*98cd9557SMatthias Ringwald 		errno = EINVAL;
498*98cd9557SMatthias Ringwald 		return -1;
499*98cd9557SMatthias Ringwald 	}
500*98cd9557SMatthias Ringwald #ifdef _MSC_VER
501*98cd9557SMatthias Ringwald 	if (dir->_h == INVALID_HANDLE_VALUE)
502*98cd9557SMatthias Ringwald #else
503*98cd9557SMatthias Ringwald 	if (dir->_e == NULL)
504*98cd9557SMatthias Ringwald #endif
505*98cd9557SMatthias Ringwald 	{
506*98cd9557SMatthias Ringwald 		errno = ENOENT;
507*98cd9557SMatthias Ringwald 		return -1;
508*98cd9557SMatthias Ringwald 	}
509*98cd9557SMatthias Ringwald 	if (_tinydir_strlen(dir->path) +
510*98cd9557SMatthias Ringwald 		_tinydir_strlen(
511*98cd9557SMatthias Ringwald #ifdef _MSC_VER
512*98cd9557SMatthias Ringwald 			dir->_f.cFileName
513*98cd9557SMatthias Ringwald #else
514*98cd9557SMatthias Ringwald 			dir->_e->d_name
515*98cd9557SMatthias Ringwald #endif
516*98cd9557SMatthias Ringwald 		) + 1 + _TINYDIR_PATH_EXTRA >=
517*98cd9557SMatthias Ringwald 		_TINYDIR_PATH_MAX)
518*98cd9557SMatthias Ringwald 	{
519*98cd9557SMatthias Ringwald 		/* the path for the file will be too long */
520*98cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
521*98cd9557SMatthias Ringwald 		return -1;
522*98cd9557SMatthias Ringwald 	}
523*98cd9557SMatthias Ringwald 	if (_tinydir_strlen(
524*98cd9557SMatthias Ringwald #ifdef _MSC_VER
525*98cd9557SMatthias Ringwald 			dir->_f.cFileName
526*98cd9557SMatthias Ringwald #else
527*98cd9557SMatthias Ringwald 			dir->_e->d_name
528*98cd9557SMatthias Ringwald #endif
529*98cd9557SMatthias Ringwald 		) >= _TINYDIR_FILENAME_MAX)
530*98cd9557SMatthias Ringwald 	{
531*98cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
532*98cd9557SMatthias Ringwald 		return -1;
533*98cd9557SMatthias Ringwald 	}
534*98cd9557SMatthias Ringwald 
535*98cd9557SMatthias Ringwald 	_tinydir_strcpy(file->path, dir->path);
536*98cd9557SMatthias Ringwald 	_tinydir_strcat(file->path, TINYDIR_STRING("/"));
537*98cd9557SMatthias Ringwald 	_tinydir_strcpy(file->name,
538*98cd9557SMatthias Ringwald #ifdef _MSC_VER
539*98cd9557SMatthias Ringwald 		dir->_f.cFileName
540*98cd9557SMatthias Ringwald #else
541*98cd9557SMatthias Ringwald 		dir->_e->d_name
542*98cd9557SMatthias Ringwald #endif
543*98cd9557SMatthias Ringwald 	);
544*98cd9557SMatthias Ringwald 	_tinydir_strcat(file->path, file->name);
545*98cd9557SMatthias Ringwald #ifndef _MSC_VER
546*98cd9557SMatthias Ringwald #ifdef __MINGW32__
547*98cd9557SMatthias Ringwald 	if (_tstat(
548*98cd9557SMatthias Ringwald #else
549*98cd9557SMatthias Ringwald 	if (stat(
550*98cd9557SMatthias Ringwald #endif
551*98cd9557SMatthias Ringwald 		file->path, &file->_s) == -1)
552*98cd9557SMatthias Ringwald 	{
553*98cd9557SMatthias Ringwald 		return -1;
554*98cd9557SMatthias Ringwald 	}
555*98cd9557SMatthias Ringwald #endif
556*98cd9557SMatthias Ringwald 	_tinydir_get_ext(file);
557*98cd9557SMatthias Ringwald 
558*98cd9557SMatthias Ringwald 	file->is_dir =
559*98cd9557SMatthias Ringwald #ifdef _MSC_VER
560*98cd9557SMatthias Ringwald 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
561*98cd9557SMatthias Ringwald #else
562*98cd9557SMatthias Ringwald 		S_ISDIR(file->_s.st_mode);
563*98cd9557SMatthias Ringwald #endif
564*98cd9557SMatthias Ringwald 	file->is_reg =
565*98cd9557SMatthias Ringwald #ifdef _MSC_VER
566*98cd9557SMatthias Ringwald 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
567*98cd9557SMatthias Ringwald 		(
568*98cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
569*98cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
570*98cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
571*98cd9557SMatthias Ringwald #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
572*98cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
573*98cd9557SMatthias Ringwald #endif
574*98cd9557SMatthias Ringwald #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
575*98cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
576*98cd9557SMatthias Ringwald #endif
577*98cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
578*98cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
579*98cd9557SMatthias Ringwald #else
580*98cd9557SMatthias Ringwald 		S_ISREG(file->_s.st_mode);
581*98cd9557SMatthias Ringwald #endif
582*98cd9557SMatthias Ringwald 
583*98cd9557SMatthias Ringwald 	return 0;
584*98cd9557SMatthias Ringwald }
585*98cd9557SMatthias Ringwald 
586*98cd9557SMatthias Ringwald _TINYDIR_FUNC
587*98cd9557SMatthias Ringwald int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
588*98cd9557SMatthias Ringwald {
589*98cd9557SMatthias Ringwald 	if (dir == NULL || file == NULL)
590*98cd9557SMatthias Ringwald 	{
591*98cd9557SMatthias Ringwald 		errno = EINVAL;
592*98cd9557SMatthias Ringwald 		return -1;
593*98cd9557SMatthias Ringwald 	}
594*98cd9557SMatthias Ringwald 	if (i >= dir->n_files)
595*98cd9557SMatthias Ringwald 	{
596*98cd9557SMatthias Ringwald 		errno = ENOENT;
597*98cd9557SMatthias Ringwald 		return -1;
598*98cd9557SMatthias Ringwald 	}
599*98cd9557SMatthias Ringwald 
600*98cd9557SMatthias Ringwald 	memcpy(file, &dir->_files[i], sizeof(tinydir_file));
601*98cd9557SMatthias Ringwald 	_tinydir_get_ext(file);
602*98cd9557SMatthias Ringwald 
603*98cd9557SMatthias Ringwald 	return 0;
604*98cd9557SMatthias Ringwald }
605*98cd9557SMatthias Ringwald 
606*98cd9557SMatthias Ringwald _TINYDIR_FUNC
607*98cd9557SMatthias Ringwald int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
608*98cd9557SMatthias Ringwald {
609*98cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
610*98cd9557SMatthias Ringwald 	if (dir == NULL)
611*98cd9557SMatthias Ringwald 	{
612*98cd9557SMatthias Ringwald 		errno = EINVAL;
613*98cd9557SMatthias Ringwald 		return -1;
614*98cd9557SMatthias Ringwald 	}
615*98cd9557SMatthias Ringwald 	if (i >= dir->n_files || !dir->_files[i].is_dir)
616*98cd9557SMatthias Ringwald 	{
617*98cd9557SMatthias Ringwald 		errno = ENOENT;
618*98cd9557SMatthias Ringwald 		return -1;
619*98cd9557SMatthias Ringwald 	}
620*98cd9557SMatthias Ringwald 
621*98cd9557SMatthias Ringwald 	_tinydir_strcpy(path, dir->_files[i].path);
622*98cd9557SMatthias Ringwald 	tinydir_close(dir);
623*98cd9557SMatthias Ringwald 	if (tinydir_open_sorted(dir, path) == -1)
624*98cd9557SMatthias Ringwald 	{
625*98cd9557SMatthias Ringwald 		return -1;
626*98cd9557SMatthias Ringwald 	}
627*98cd9557SMatthias Ringwald 
628*98cd9557SMatthias Ringwald 	return 0;
629*98cd9557SMatthias Ringwald }
630*98cd9557SMatthias Ringwald 
631*98cd9557SMatthias Ringwald /* Open a single file given its path */
632*98cd9557SMatthias Ringwald _TINYDIR_FUNC
633*98cd9557SMatthias Ringwald int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
634*98cd9557SMatthias Ringwald {
635*98cd9557SMatthias Ringwald 	tinydir_dir dir;
636*98cd9557SMatthias Ringwald 	int result = 0;
637*98cd9557SMatthias Ringwald 	int found = 0;
638*98cd9557SMatthias Ringwald 	_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
639*98cd9557SMatthias Ringwald 	_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
640*98cd9557SMatthias Ringwald 	_tinydir_char_t *dir_name;
641*98cd9557SMatthias Ringwald 	_tinydir_char_t *base_name;
642*98cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
643*98cd9557SMatthias Ringwald 	_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
644*98cd9557SMatthias Ringwald 	_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
645*98cd9557SMatthias Ringwald #endif
646*98cd9557SMatthias Ringwald 
647*98cd9557SMatthias Ringwald 	if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
648*98cd9557SMatthias Ringwald 	{
649*98cd9557SMatthias Ringwald 		errno = EINVAL;
650*98cd9557SMatthias Ringwald 		return -1;
651*98cd9557SMatthias Ringwald 	}
652*98cd9557SMatthias Ringwald 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
653*98cd9557SMatthias Ringwald 	{
654*98cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
655*98cd9557SMatthias Ringwald 		return -1;
656*98cd9557SMatthias Ringwald 	}
657*98cd9557SMatthias Ringwald 
658*98cd9557SMatthias Ringwald 	/* Get the parent path */
659*98cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
660*98cd9557SMatthias Ringwald #if ((defined _MSC_VER) && (_MSC_VER >= 1400))
661*98cd9557SMatthias Ringwald 		_tsplitpath_s(
662*98cd9557SMatthias Ringwald 			path,
663*98cd9557SMatthias Ringwald 			drive_buf, _TINYDIR_DRIVE_MAX,
664*98cd9557SMatthias Ringwald 			dir_name_buf, _TINYDIR_FILENAME_MAX,
665*98cd9557SMatthias Ringwald 			file_name_buf, _TINYDIR_FILENAME_MAX,
666*98cd9557SMatthias Ringwald 			ext_buf, _TINYDIR_FILENAME_MAX);
667*98cd9557SMatthias Ringwald #else
668*98cd9557SMatthias Ringwald 		_tsplitpath(
669*98cd9557SMatthias Ringwald 			path,
670*98cd9557SMatthias Ringwald 			drive_buf,
671*98cd9557SMatthias Ringwald 			dir_name_buf,
672*98cd9557SMatthias Ringwald 			file_name_buf,
673*98cd9557SMatthias Ringwald 			ext_buf);
674*98cd9557SMatthias Ringwald #endif
675*98cd9557SMatthias Ringwald 
676*98cd9557SMatthias Ringwald /* _splitpath_s not work fine with only filename and widechar support */
677*98cd9557SMatthias Ringwald #ifdef _UNICODE
678*98cd9557SMatthias Ringwald 		if (drive_buf[0] == L'\xFEFE')
679*98cd9557SMatthias Ringwald 			drive_buf[0] = '\0';
680*98cd9557SMatthias Ringwald 		if (dir_name_buf[0] == L'\xFEFE')
681*98cd9557SMatthias Ringwald 			dir_name_buf[0] = '\0';
682*98cd9557SMatthias Ringwald #endif
683*98cd9557SMatthias Ringwald 
684*98cd9557SMatthias Ringwald 	if (errno)
685*98cd9557SMatthias Ringwald 	{
686*98cd9557SMatthias Ringwald 		errno = EINVAL;
687*98cd9557SMatthias Ringwald 		return -1;
688*98cd9557SMatthias Ringwald 	}
689*98cd9557SMatthias Ringwald 	/* Emulate the behavior of dirname by returning "." for dir name if it's
690*98cd9557SMatthias Ringwald 	empty */
691*98cd9557SMatthias Ringwald 	if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
692*98cd9557SMatthias Ringwald 	{
693*98cd9557SMatthias Ringwald 		_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
694*98cd9557SMatthias Ringwald 	}
695*98cd9557SMatthias Ringwald 	/* Concatenate the drive letter and dir name to form full dir name */
696*98cd9557SMatthias Ringwald 	_tinydir_strcat(drive_buf, dir_name_buf);
697*98cd9557SMatthias Ringwald 	dir_name = drive_buf;
698*98cd9557SMatthias Ringwald 	/* Concatenate the file name and extension to form base name */
699*98cd9557SMatthias Ringwald 	_tinydir_strcat(file_name_buf, ext_buf);
700*98cd9557SMatthias Ringwald 	base_name = file_name_buf;
701*98cd9557SMatthias Ringwald #else
702*98cd9557SMatthias Ringwald 	_tinydir_strcpy(dir_name_buf, path);
703*98cd9557SMatthias Ringwald 	dir_name = dirname(dir_name_buf);
704*98cd9557SMatthias Ringwald 	_tinydir_strcpy(file_name_buf, path);
705*98cd9557SMatthias Ringwald 	base_name =basename(file_name_buf);
706*98cd9557SMatthias Ringwald #endif
707*98cd9557SMatthias Ringwald 
708*98cd9557SMatthias Ringwald 	/* Open the parent directory */
709*98cd9557SMatthias Ringwald 	if (tinydir_open(&dir, dir_name) == -1)
710*98cd9557SMatthias Ringwald 	{
711*98cd9557SMatthias Ringwald 		return -1;
712*98cd9557SMatthias Ringwald 	}
713*98cd9557SMatthias Ringwald 
714*98cd9557SMatthias Ringwald 	/* Read through the parent directory and look for the file */
715*98cd9557SMatthias Ringwald 	while (dir.has_next)
716*98cd9557SMatthias Ringwald 	{
717*98cd9557SMatthias Ringwald 		if (tinydir_readfile(&dir, file) == -1)
718*98cd9557SMatthias Ringwald 		{
719*98cd9557SMatthias Ringwald 			result = -1;
720*98cd9557SMatthias Ringwald 			goto bail;
721*98cd9557SMatthias Ringwald 		}
722*98cd9557SMatthias Ringwald 		if (_tinydir_strcmp(file->name, base_name) == 0)
723*98cd9557SMatthias Ringwald 		{
724*98cd9557SMatthias Ringwald 			/* File found */
725*98cd9557SMatthias Ringwald 			found = 1;
726*98cd9557SMatthias Ringwald 			break;
727*98cd9557SMatthias Ringwald 		}
728*98cd9557SMatthias Ringwald 		tinydir_next(&dir);
729*98cd9557SMatthias Ringwald 	}
730*98cd9557SMatthias Ringwald 	if (!found)
731*98cd9557SMatthias Ringwald 	{
732*98cd9557SMatthias Ringwald 		result = -1;
733*98cd9557SMatthias Ringwald 		errno = ENOENT;
734*98cd9557SMatthias Ringwald 	}
735*98cd9557SMatthias Ringwald 
736*98cd9557SMatthias Ringwald bail:
737*98cd9557SMatthias Ringwald 	tinydir_close(&dir);
738*98cd9557SMatthias Ringwald 	return result;
739*98cd9557SMatthias Ringwald }
740*98cd9557SMatthias Ringwald 
741*98cd9557SMatthias Ringwald _TINYDIR_FUNC
742*98cd9557SMatthias Ringwald void _tinydir_get_ext(tinydir_file *file)
743*98cd9557SMatthias Ringwald {
744*98cd9557SMatthias Ringwald 	_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
745*98cd9557SMatthias Ringwald 	if (period == NULL)
746*98cd9557SMatthias Ringwald 	{
747*98cd9557SMatthias Ringwald 		file->extension = &(file->name[_tinydir_strlen(file->name)]);
748*98cd9557SMatthias Ringwald 	}
749*98cd9557SMatthias Ringwald 	else
750*98cd9557SMatthias Ringwald 	{
751*98cd9557SMatthias Ringwald 		file->extension = period + 1;
752*98cd9557SMatthias Ringwald 	}
753*98cd9557SMatthias Ringwald }
754*98cd9557SMatthias Ringwald 
755*98cd9557SMatthias Ringwald _TINYDIR_FUNC
756*98cd9557SMatthias Ringwald int _tinydir_file_cmp(const void *a, const void *b)
757*98cd9557SMatthias Ringwald {
758*98cd9557SMatthias Ringwald 	const tinydir_file *fa = (const tinydir_file *)a;
759*98cd9557SMatthias Ringwald 	const tinydir_file *fb = (const tinydir_file *)b;
760*98cd9557SMatthias Ringwald 	if (fa->is_dir != fb->is_dir)
761*98cd9557SMatthias Ringwald 	{
762*98cd9557SMatthias Ringwald 		return -(fa->is_dir - fb->is_dir);
763*98cd9557SMatthias Ringwald 	}
764*98cd9557SMatthias Ringwald 	return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
765*98cd9557SMatthias Ringwald }
766*98cd9557SMatthias Ringwald 
767*98cd9557SMatthias Ringwald #ifndef _MSC_VER
768*98cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
769*98cd9557SMatthias Ringwald /*
770*98cd9557SMatthias Ringwald The following authored by Ben Hutchings <[email protected]>
771*98cd9557SMatthias Ringwald from https://womble.decadent.org.uk/readdir_r-advisory.html
772*98cd9557SMatthias Ringwald */
773*98cd9557SMatthias Ringwald /* Calculate the required buffer size (in bytes) for directory      *
774*98cd9557SMatthias Ringwald * entries read from the given directory handle.  Return -1 if this  *
775*98cd9557SMatthias Ringwald * this cannot be done.                                              *
776*98cd9557SMatthias Ringwald *                                                                   *
777*98cd9557SMatthias Ringwald * This code does not trust values of NAME_MAX that are less than    *
778*98cd9557SMatthias Ringwald * 255, since some systems (including at least HP-UX) incorrectly    *
779*98cd9557SMatthias Ringwald * define it to be a smaller value.                                  */
780*98cd9557SMatthias Ringwald _TINYDIR_FUNC
781*98cd9557SMatthias Ringwald size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
782*98cd9557SMatthias Ringwald {
783*98cd9557SMatthias Ringwald 	long name_max;
784*98cd9557SMatthias Ringwald 	size_t name_end;
785*98cd9557SMatthias Ringwald 	/* parameter may be unused */
786*98cd9557SMatthias Ringwald 	(void)dirp;
787*98cd9557SMatthias Ringwald 
788*98cd9557SMatthias Ringwald #if defined _TINYDIR_USE_FPATHCONF
789*98cd9557SMatthias Ringwald 	name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
790*98cd9557SMatthias Ringwald 	if (name_max == -1)
791*98cd9557SMatthias Ringwald #if defined(NAME_MAX)
792*98cd9557SMatthias Ringwald 		name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
793*98cd9557SMatthias Ringwald #else
794*98cd9557SMatthias Ringwald 		return (size_t)(-1);
795*98cd9557SMatthias Ringwald #endif
796*98cd9557SMatthias Ringwald #elif defined(NAME_MAX)
797*98cd9557SMatthias Ringwald  	name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
798*98cd9557SMatthias Ringwald #else
799*98cd9557SMatthias Ringwald #error "buffer size for readdir_r cannot be determined"
800*98cd9557SMatthias Ringwald #endif
801*98cd9557SMatthias Ringwald 	name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
802*98cd9557SMatthias Ringwald 	return (name_end > sizeof(struct _tinydir_dirent) ?
803*98cd9557SMatthias Ringwald 		name_end : sizeof(struct _tinydir_dirent));
804*98cd9557SMatthias Ringwald }
805*98cd9557SMatthias Ringwald #endif
806*98cd9557SMatthias Ringwald #endif
807*98cd9557SMatthias Ringwald 
808*98cd9557SMatthias Ringwald #ifdef __cplusplus
809*98cd9557SMatthias Ringwald }
810*98cd9557SMatthias Ringwald #endif
811*98cd9557SMatthias Ringwald 
812*98cd9557SMatthias Ringwald # if defined (_MSC_VER)
813*98cd9557SMatthias Ringwald # pragma warning(pop)
814*98cd9557SMatthias Ringwald # endif
815*98cd9557SMatthias Ringwald 
816*98cd9557SMatthias Ringwald #endif
817