xref: /btstack/3rd-party/tinydir/tinydir.h (revision e9d8dc8bd8076b7b89b9c4687764374e98e2f843)
198cd9557SMatthias Ringwald /*
2*e9d8dc8bSDirk Helbig Copyright (c) 2013-2021, tinydir authors:
398cd9557SMatthias Ringwald - Cong Xu
498cd9557SMatthias Ringwald - Lautis Sun
598cd9557SMatthias Ringwald - Baudouin Feildel
698cd9557SMatthias Ringwald - Andargor <[email protected]>
798cd9557SMatthias Ringwald All rights reserved.
898cd9557SMatthias Ringwald 
998cd9557SMatthias Ringwald Redistribution and use in source and binary forms, with or without
1098cd9557SMatthias Ringwald modification, are permitted provided that the following conditions are met:
1198cd9557SMatthias Ringwald 
1298cd9557SMatthias Ringwald 1. Redistributions of source code must retain the above copyright notice, this
1398cd9557SMatthias Ringwald    list of conditions and the following disclaimer.
1498cd9557SMatthias Ringwald 2. Redistributions in binary form must reproduce the above copyright notice,
1598cd9557SMatthias Ringwald    this list of conditions and the following disclaimer in the documentation
1698cd9557SMatthias Ringwald    and/or other materials provided with the distribution.
1798cd9557SMatthias Ringwald 
1898cd9557SMatthias Ringwald THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
1998cd9557SMatthias Ringwald ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2098cd9557SMatthias Ringwald WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2198cd9557SMatthias Ringwald DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
2298cd9557SMatthias Ringwald ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2398cd9557SMatthias Ringwald (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2498cd9557SMatthias Ringwald LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2598cd9557SMatthias Ringwald ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2698cd9557SMatthias Ringwald (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2798cd9557SMatthias Ringwald SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2898cd9557SMatthias Ringwald */
2998cd9557SMatthias Ringwald #ifndef TINYDIR_H
3098cd9557SMatthias Ringwald #define TINYDIR_H
3198cd9557SMatthias Ringwald 
3298cd9557SMatthias Ringwald #ifdef __cplusplus
3398cd9557SMatthias Ringwald extern "C" {
3498cd9557SMatthias Ringwald #endif
3598cd9557SMatthias Ringwald 
3698cd9557SMatthias Ringwald #if ((defined _UNICODE) && !(defined UNICODE))
3798cd9557SMatthias Ringwald #define UNICODE
3898cd9557SMatthias Ringwald #endif
3998cd9557SMatthias Ringwald 
4098cd9557SMatthias Ringwald #if ((defined UNICODE) && !(defined _UNICODE))
4198cd9557SMatthias Ringwald #define _UNICODE
4298cd9557SMatthias Ringwald #endif
4398cd9557SMatthias Ringwald 
4498cd9557SMatthias Ringwald #include <errno.h>
4598cd9557SMatthias Ringwald #include <stdlib.h>
4698cd9557SMatthias Ringwald #include <string.h>
4798cd9557SMatthias Ringwald #ifdef _MSC_VER
48*e9d8dc8bSDirk Helbig # ifndef WIN32_LEAN_AND_MEAN
4998cd9557SMatthias Ringwald #  define WIN32_LEAN_AND_MEAN
50*e9d8dc8bSDirk Helbig # endif
5198cd9557SMatthias Ringwald # include <windows.h>
5298cd9557SMatthias Ringwald # include <tchar.h>
5398cd9557SMatthias Ringwald # pragma warning(push)
5498cd9557SMatthias Ringwald # pragma warning (disable : 4996)
5598cd9557SMatthias Ringwald #else
5698cd9557SMatthias Ringwald # include <dirent.h>
5798cd9557SMatthias Ringwald # include <libgen.h>
5898cd9557SMatthias Ringwald # include <sys/stat.h>
5998cd9557SMatthias Ringwald # include <stddef.h>
6098cd9557SMatthias Ringwald #endif
6198cd9557SMatthias Ringwald #ifdef __MINGW32__
6298cd9557SMatthias Ringwald # include <tchar.h>
6398cd9557SMatthias Ringwald #endif
6498cd9557SMatthias Ringwald 
6598cd9557SMatthias Ringwald 
6698cd9557SMatthias Ringwald /* types */
6798cd9557SMatthias Ringwald 
6898cd9557SMatthias Ringwald /* Windows UNICODE wide character support */
6998cd9557SMatthias Ringwald #if defined _MSC_VER || defined __MINGW32__
7098cd9557SMatthias Ringwald # define _tinydir_char_t TCHAR
7198cd9557SMatthias Ringwald # define TINYDIR_STRING(s) _TEXT(s)
7298cd9557SMatthias Ringwald # define _tinydir_strlen _tcslen
7398cd9557SMatthias Ringwald # define _tinydir_strcpy _tcscpy
7498cd9557SMatthias Ringwald # define _tinydir_strcat _tcscat
7598cd9557SMatthias Ringwald # define _tinydir_strcmp _tcscmp
7698cd9557SMatthias Ringwald # define _tinydir_strrchr _tcsrchr
7798cd9557SMatthias Ringwald # define _tinydir_strncmp _tcsncmp
7898cd9557SMatthias Ringwald #else
7998cd9557SMatthias Ringwald # define _tinydir_char_t char
8098cd9557SMatthias Ringwald # define TINYDIR_STRING(s) s
8198cd9557SMatthias Ringwald # define _tinydir_strlen strlen
8298cd9557SMatthias Ringwald # define _tinydir_strcpy strcpy
8398cd9557SMatthias Ringwald # define _tinydir_strcat strcat
8498cd9557SMatthias Ringwald # define _tinydir_strcmp strcmp
8598cd9557SMatthias Ringwald # define _tinydir_strrchr strrchr
8698cd9557SMatthias Ringwald # define _tinydir_strncmp strncmp
8798cd9557SMatthias Ringwald #endif
8898cd9557SMatthias Ringwald 
8998cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
9098cd9557SMatthias Ringwald # include <windows.h>
9198cd9557SMatthias Ringwald # define _TINYDIR_PATH_MAX MAX_PATH
9298cd9557SMatthias Ringwald #elif defined  __linux__
9398cd9557SMatthias Ringwald # include <limits.h>
94*e9d8dc8bSDirk Helbig # ifdef PATH_MAX
9598cd9557SMatthias Ringwald #  define _TINYDIR_PATH_MAX PATH_MAX
96ec8ca29fSMatthias Ringwald # endif
9798cd9557SMatthias Ringwald #elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
9898cd9557SMatthias Ringwald # include <sys/param.h>
9998cd9557SMatthias Ringwald # if defined(BSD)
10098cd9557SMatthias Ringwald #  include <limits.h>
101*e9d8dc8bSDirk Helbig #  ifdef PATH_MAX
10298cd9557SMatthias Ringwald #   define _TINYDIR_PATH_MAX PATH_MAX
10398cd9557SMatthias Ringwald #  endif
10498cd9557SMatthias Ringwald # endif
105*e9d8dc8bSDirk Helbig #endif
10698cd9557SMatthias Ringwald 
10798cd9557SMatthias Ringwald #ifndef _TINYDIR_PATH_MAX
10898cd9557SMatthias Ringwald #define _TINYDIR_PATH_MAX 4096
10998cd9557SMatthias Ringwald #endif
11098cd9557SMatthias Ringwald 
11198cd9557SMatthias Ringwald #ifdef _MSC_VER
11298cd9557SMatthias Ringwald /* extra chars for the "\\*" mask */
11398cd9557SMatthias Ringwald # define _TINYDIR_PATH_EXTRA 2
11498cd9557SMatthias Ringwald #else
11598cd9557SMatthias Ringwald # define _TINYDIR_PATH_EXTRA 0
11698cd9557SMatthias Ringwald #endif
11798cd9557SMatthias Ringwald 
11898cd9557SMatthias Ringwald #define _TINYDIR_FILENAME_MAX 256
11998cd9557SMatthias Ringwald 
12098cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
12198cd9557SMatthias Ringwald #define _TINYDIR_DRIVE_MAX 3
12298cd9557SMatthias Ringwald #endif
12398cd9557SMatthias Ringwald 
12498cd9557SMatthias Ringwald #ifdef _MSC_VER
12598cd9557SMatthias Ringwald # define _TINYDIR_FUNC static __inline
12698cd9557SMatthias Ringwald #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
12798cd9557SMatthias Ringwald # define _TINYDIR_FUNC static __inline__
128*e9d8dc8bSDirk Helbig #elif defined(__cplusplus)
12998cd9557SMatthias Ringwald # define _TINYDIR_FUNC static inline
130*e9d8dc8bSDirk Helbig #elif defined(__GNUC__)
131*e9d8dc8bSDirk Helbig /* Suppress unused function warning */
132*e9d8dc8bSDirk Helbig # define _TINYDIR_FUNC __attribute__((unused)) static
133*e9d8dc8bSDirk Helbig #else
134*e9d8dc8bSDirk Helbig # define _TINYDIR_FUNC static
13598cd9557SMatthias Ringwald #endif
13698cd9557SMatthias Ringwald 
13798cd9557SMatthias Ringwald /* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
13898cd9557SMatthias Ringwald #ifdef TINYDIR_USE_READDIR_R
13998cd9557SMatthias Ringwald 
14098cd9557SMatthias Ringwald /* readdir_r is a POSIX-only function, and may not be available under various
14198cd9557SMatthias Ringwald  * environments/settings, e.g. MinGW. Use readdir fallback */
14298cd9557SMatthias Ringwald #if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
14398cd9557SMatthias Ringwald 	_POSIX_SOURCE
14498cd9557SMatthias Ringwald # define _TINYDIR_HAS_READDIR_R
14598cd9557SMatthias Ringwald #endif
14698cd9557SMatthias Ringwald #if _POSIX_C_SOURCE >= 200112L
14798cd9557SMatthias Ringwald # define _TINYDIR_HAS_FPATHCONF
14898cd9557SMatthias Ringwald # include <unistd.h>
14998cd9557SMatthias Ringwald #endif
15098cd9557SMatthias Ringwald #if _BSD_SOURCE || _SVID_SOURCE || \
15198cd9557SMatthias Ringwald 	(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
15298cd9557SMatthias Ringwald # define _TINYDIR_HAS_DIRFD
15398cd9557SMatthias Ringwald # include <sys/types.h>
15498cd9557SMatthias Ringwald #endif
15598cd9557SMatthias Ringwald #if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
15698cd9557SMatthias Ringwald 	defined _PC_NAME_MAX
15798cd9557SMatthias Ringwald # define _TINYDIR_USE_FPATHCONF
15898cd9557SMatthias Ringwald #endif
15998cd9557SMatthias Ringwald #if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
16098cd9557SMatthias Ringwald 	!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
16198cd9557SMatthias Ringwald # define _TINYDIR_USE_READDIR
16298cd9557SMatthias Ringwald #endif
16398cd9557SMatthias Ringwald 
16498cd9557SMatthias Ringwald /* Use readdir by default */
16598cd9557SMatthias Ringwald #else
16698cd9557SMatthias Ringwald # define _TINYDIR_USE_READDIR
16798cd9557SMatthias Ringwald #endif
16898cd9557SMatthias Ringwald 
16998cd9557SMatthias Ringwald /* MINGW32 has two versions of dirent, ASCII and UNICODE*/
17098cd9557SMatthias Ringwald #ifndef _MSC_VER
17198cd9557SMatthias Ringwald #if (defined __MINGW32__) && (defined _UNICODE)
17298cd9557SMatthias Ringwald #define _TINYDIR_DIR _WDIR
17398cd9557SMatthias Ringwald #define _tinydir_dirent _wdirent
17498cd9557SMatthias Ringwald #define _tinydir_opendir _wopendir
17598cd9557SMatthias Ringwald #define _tinydir_readdir _wreaddir
17698cd9557SMatthias Ringwald #define _tinydir_closedir _wclosedir
17798cd9557SMatthias Ringwald #else
17898cd9557SMatthias Ringwald #define _TINYDIR_DIR DIR
17998cd9557SMatthias Ringwald #define _tinydir_dirent dirent
18098cd9557SMatthias Ringwald #define _tinydir_opendir opendir
18198cd9557SMatthias Ringwald #define _tinydir_readdir readdir
18298cd9557SMatthias Ringwald #define _tinydir_closedir closedir
18398cd9557SMatthias Ringwald #endif
18498cd9557SMatthias Ringwald #endif
18598cd9557SMatthias Ringwald 
18698cd9557SMatthias Ringwald /* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
18798cd9557SMatthias Ringwald #if    defined(_TINYDIR_MALLOC) &&  defined(_TINYDIR_FREE)
18898cd9557SMatthias Ringwald #elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
18998cd9557SMatthias Ringwald #else
19098cd9557SMatthias Ringwald #error "Either define both alloc and free or none of them!"
19198cd9557SMatthias Ringwald #endif
19298cd9557SMatthias Ringwald 
19398cd9557SMatthias Ringwald #if !defined(_TINYDIR_MALLOC)
19498cd9557SMatthias Ringwald 	#define _TINYDIR_MALLOC(_size) malloc(_size)
19598cd9557SMatthias Ringwald 	#define _TINYDIR_FREE(_ptr)    free(_ptr)
19698cd9557SMatthias Ringwald #endif /* !defined(_TINYDIR_MALLOC) */
19798cd9557SMatthias Ringwald 
19898cd9557SMatthias Ringwald typedef struct tinydir_file
19998cd9557SMatthias Ringwald {
20098cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
20198cd9557SMatthias Ringwald 	_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
20298cd9557SMatthias Ringwald 	_tinydir_char_t *extension;
20398cd9557SMatthias Ringwald 	int is_dir;
20498cd9557SMatthias Ringwald 	int is_reg;
20598cd9557SMatthias Ringwald 
20698cd9557SMatthias Ringwald #ifndef _MSC_VER
20798cd9557SMatthias Ringwald #ifdef __MINGW32__
20898cd9557SMatthias Ringwald 	struct _stat _s;
20998cd9557SMatthias Ringwald #else
21098cd9557SMatthias Ringwald 	struct stat _s;
21198cd9557SMatthias Ringwald #endif
21298cd9557SMatthias Ringwald #endif
21398cd9557SMatthias Ringwald } tinydir_file;
21498cd9557SMatthias Ringwald 
21598cd9557SMatthias Ringwald typedef struct tinydir_dir
21698cd9557SMatthias Ringwald {
21798cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
21898cd9557SMatthias Ringwald 	int has_next;
21998cd9557SMatthias Ringwald 	size_t n_files;
22098cd9557SMatthias Ringwald 
22198cd9557SMatthias Ringwald 	tinydir_file *_files;
22298cd9557SMatthias Ringwald #ifdef _MSC_VER
22398cd9557SMatthias Ringwald 	HANDLE _h;
22498cd9557SMatthias Ringwald 	WIN32_FIND_DATA _f;
22598cd9557SMatthias Ringwald #else
22698cd9557SMatthias Ringwald 	_TINYDIR_DIR *_d;
22798cd9557SMatthias Ringwald 	struct _tinydir_dirent *_e;
22898cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
22998cd9557SMatthias Ringwald 	struct _tinydir_dirent *_ep;
23098cd9557SMatthias Ringwald #endif
23198cd9557SMatthias Ringwald #endif
23298cd9557SMatthias Ringwald } tinydir_dir;
23398cd9557SMatthias Ringwald 
23498cd9557SMatthias Ringwald 
23598cd9557SMatthias Ringwald /* declarations */
23698cd9557SMatthias Ringwald 
23798cd9557SMatthias Ringwald _TINYDIR_FUNC
23898cd9557SMatthias Ringwald int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
23998cd9557SMatthias Ringwald _TINYDIR_FUNC
24098cd9557SMatthias Ringwald int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
24198cd9557SMatthias Ringwald _TINYDIR_FUNC
24298cd9557SMatthias Ringwald void tinydir_close(tinydir_dir *dir);
24398cd9557SMatthias Ringwald 
24498cd9557SMatthias Ringwald _TINYDIR_FUNC
24598cd9557SMatthias Ringwald int tinydir_next(tinydir_dir *dir);
24698cd9557SMatthias Ringwald _TINYDIR_FUNC
24798cd9557SMatthias Ringwald int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
24898cd9557SMatthias Ringwald _TINYDIR_FUNC
24998cd9557SMatthias Ringwald int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
25098cd9557SMatthias Ringwald _TINYDIR_FUNC
25198cd9557SMatthias Ringwald int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
25298cd9557SMatthias Ringwald 
25398cd9557SMatthias Ringwald _TINYDIR_FUNC
25498cd9557SMatthias Ringwald int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
25598cd9557SMatthias Ringwald _TINYDIR_FUNC
25698cd9557SMatthias Ringwald void _tinydir_get_ext(tinydir_file *file);
25798cd9557SMatthias Ringwald _TINYDIR_FUNC
25898cd9557SMatthias Ringwald int _tinydir_file_cmp(const void *a, const void *b);
25998cd9557SMatthias Ringwald #ifndef _MSC_VER
26098cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
26198cd9557SMatthias Ringwald _TINYDIR_FUNC
26298cd9557SMatthias Ringwald size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
26398cd9557SMatthias Ringwald #endif
26498cd9557SMatthias Ringwald #endif
26598cd9557SMatthias Ringwald 
26698cd9557SMatthias Ringwald 
26798cd9557SMatthias Ringwald /* definitions*/
26898cd9557SMatthias Ringwald 
26998cd9557SMatthias Ringwald _TINYDIR_FUNC
tinydir_open(tinydir_dir * dir,const _tinydir_char_t * path)27098cd9557SMatthias Ringwald int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
27198cd9557SMatthias Ringwald {
27298cd9557SMatthias Ringwald #ifndef _MSC_VER
27398cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
27498cd9557SMatthias Ringwald 	int error;
27598cd9557SMatthias Ringwald 	int size;	/* using int size */
27698cd9557SMatthias Ringwald #endif
27798cd9557SMatthias Ringwald #else
27898cd9557SMatthias Ringwald 	_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
27998cd9557SMatthias Ringwald #endif
28098cd9557SMatthias Ringwald 	_tinydir_char_t *pathp;
28198cd9557SMatthias Ringwald 
28298cd9557SMatthias Ringwald 	if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
28398cd9557SMatthias Ringwald 	{
28498cd9557SMatthias Ringwald 		errno = EINVAL;
28598cd9557SMatthias Ringwald 		return -1;
28698cd9557SMatthias Ringwald 	}
28798cd9557SMatthias Ringwald 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
28898cd9557SMatthias Ringwald 	{
28998cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
29098cd9557SMatthias Ringwald 		return -1;
29198cd9557SMatthias Ringwald 	}
29298cd9557SMatthias Ringwald 
29398cd9557SMatthias Ringwald 	/* initialise dir */
29498cd9557SMatthias Ringwald 	dir->_files = NULL;
29598cd9557SMatthias Ringwald #ifdef _MSC_VER
29698cd9557SMatthias Ringwald 	dir->_h = INVALID_HANDLE_VALUE;
29798cd9557SMatthias Ringwald #else
29898cd9557SMatthias Ringwald 	dir->_d = NULL;
29998cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
30098cd9557SMatthias Ringwald 	dir->_ep = NULL;
30198cd9557SMatthias Ringwald #endif
30298cd9557SMatthias Ringwald #endif
30398cd9557SMatthias Ringwald 	tinydir_close(dir);
30498cd9557SMatthias Ringwald 
30598cd9557SMatthias Ringwald 	_tinydir_strcpy(dir->path, path);
30698cd9557SMatthias Ringwald 	/* Remove trailing slashes */
30798cd9557SMatthias Ringwald 	pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
30898cd9557SMatthias Ringwald 	while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
30998cd9557SMatthias Ringwald 	{
31098cd9557SMatthias Ringwald 		*pathp = TINYDIR_STRING('\0');
31198cd9557SMatthias Ringwald 		pathp++;
31298cd9557SMatthias Ringwald 	}
31398cd9557SMatthias Ringwald #ifdef _MSC_VER
31498cd9557SMatthias Ringwald 	_tinydir_strcpy(path_buf, dir->path);
31598cd9557SMatthias Ringwald 	_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
31698cd9557SMatthias Ringwald #if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
31798cd9557SMatthias Ringwald 	dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
31898cd9557SMatthias Ringwald #else
31998cd9557SMatthias Ringwald 	dir->_h = FindFirstFile(path_buf, &dir->_f);
32098cd9557SMatthias Ringwald #endif
32198cd9557SMatthias Ringwald 	if (dir->_h == INVALID_HANDLE_VALUE)
32298cd9557SMatthias Ringwald 	{
32398cd9557SMatthias Ringwald 		errno = ENOENT;
32498cd9557SMatthias Ringwald #else
32598cd9557SMatthias Ringwald 	dir->_d = _tinydir_opendir(path);
32698cd9557SMatthias Ringwald 	if (dir->_d == NULL)
32798cd9557SMatthias Ringwald 	{
32898cd9557SMatthias Ringwald #endif
32998cd9557SMatthias Ringwald 		goto bail;
33098cd9557SMatthias Ringwald 	}
33198cd9557SMatthias Ringwald 
33298cd9557SMatthias Ringwald 	/* read first file */
33398cd9557SMatthias Ringwald 	dir->has_next = 1;
33498cd9557SMatthias Ringwald #ifndef _MSC_VER
33598cd9557SMatthias Ringwald #ifdef _TINYDIR_USE_READDIR
33698cd9557SMatthias Ringwald 	dir->_e = _tinydir_readdir(dir->_d);
33798cd9557SMatthias Ringwald #else
33898cd9557SMatthias Ringwald 	/* allocate dirent buffer for readdir_r */
33998cd9557SMatthias Ringwald 	size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
34098cd9557SMatthias Ringwald 	if (size == -1) return -1;
34198cd9557SMatthias Ringwald 	dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
34298cd9557SMatthias Ringwald 	if (dir->_ep == NULL) return -1;
34398cd9557SMatthias Ringwald 
34498cd9557SMatthias Ringwald 	error = readdir_r(dir->_d, dir->_ep, &dir->_e);
34598cd9557SMatthias Ringwald 	if (error != 0) return -1;
34698cd9557SMatthias Ringwald #endif
34798cd9557SMatthias Ringwald 	if (dir->_e == NULL)
34898cd9557SMatthias Ringwald 	{
34998cd9557SMatthias Ringwald 		dir->has_next = 0;
35098cd9557SMatthias Ringwald 	}
35198cd9557SMatthias Ringwald #endif
35298cd9557SMatthias Ringwald 
35398cd9557SMatthias Ringwald 	return 0;
35498cd9557SMatthias Ringwald 
35598cd9557SMatthias Ringwald bail:
35698cd9557SMatthias Ringwald 	tinydir_close(dir);
35798cd9557SMatthias Ringwald 	return -1;
35898cd9557SMatthias Ringwald }
35998cd9557SMatthias Ringwald 
36098cd9557SMatthias Ringwald _TINYDIR_FUNC
36198cd9557SMatthias Ringwald int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
36298cd9557SMatthias Ringwald {
36398cd9557SMatthias Ringwald 	/* Count the number of files first, to pre-allocate the files array */
36498cd9557SMatthias Ringwald 	size_t n_files = 0;
36598cd9557SMatthias Ringwald 	if (tinydir_open(dir, path) == -1)
36698cd9557SMatthias Ringwald 	{
36798cd9557SMatthias Ringwald 		return -1;
36898cd9557SMatthias Ringwald 	}
36998cd9557SMatthias Ringwald 	while (dir->has_next)
37098cd9557SMatthias Ringwald 	{
37198cd9557SMatthias Ringwald 		n_files++;
37298cd9557SMatthias Ringwald 		if (tinydir_next(dir) == -1)
37398cd9557SMatthias Ringwald 		{
37498cd9557SMatthias Ringwald 			goto bail;
37598cd9557SMatthias Ringwald 		}
37698cd9557SMatthias Ringwald 	}
37798cd9557SMatthias Ringwald 	tinydir_close(dir);
37898cd9557SMatthias Ringwald 
379ec8ca29fSMatthias Ringwald 	if (n_files == 0 || tinydir_open(dir, path) == -1)
38098cd9557SMatthias Ringwald 	{
38198cd9557SMatthias Ringwald 		return -1;
38298cd9557SMatthias Ringwald 	}
38398cd9557SMatthias Ringwald 
38498cd9557SMatthias Ringwald 	dir->n_files = 0;
38598cd9557SMatthias Ringwald 	dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
38698cd9557SMatthias Ringwald 	if (dir->_files == NULL)
38798cd9557SMatthias Ringwald 	{
38898cd9557SMatthias Ringwald 		goto bail;
38998cd9557SMatthias Ringwald 	}
39098cd9557SMatthias Ringwald 	while (dir->has_next)
39198cd9557SMatthias Ringwald 	{
39298cd9557SMatthias Ringwald 		tinydir_file *p_file;
39398cd9557SMatthias Ringwald 		dir->n_files++;
39498cd9557SMatthias Ringwald 
39598cd9557SMatthias Ringwald 		p_file = &dir->_files[dir->n_files - 1];
39698cd9557SMatthias Ringwald 		if (tinydir_readfile(dir, p_file) == -1)
39798cd9557SMatthias Ringwald 		{
39898cd9557SMatthias Ringwald 			goto bail;
39998cd9557SMatthias Ringwald 		}
40098cd9557SMatthias Ringwald 
40198cd9557SMatthias Ringwald 		if (tinydir_next(dir) == -1)
40298cd9557SMatthias Ringwald 		{
40398cd9557SMatthias Ringwald 			goto bail;
40498cd9557SMatthias Ringwald 		}
40598cd9557SMatthias Ringwald 
40698cd9557SMatthias Ringwald 		/* Just in case the number of files has changed between the first and
40798cd9557SMatthias Ringwald 		second reads, terminate without writing into unallocated memory */
40898cd9557SMatthias Ringwald 		if (dir->n_files == n_files)
40998cd9557SMatthias Ringwald 		{
41098cd9557SMatthias Ringwald 			break;
41198cd9557SMatthias Ringwald 		}
41298cd9557SMatthias Ringwald 	}
41398cd9557SMatthias Ringwald 
41498cd9557SMatthias Ringwald 	qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
41598cd9557SMatthias Ringwald 
41698cd9557SMatthias Ringwald 	return 0;
41798cd9557SMatthias Ringwald 
41898cd9557SMatthias Ringwald bail:
41998cd9557SMatthias Ringwald 	tinydir_close(dir);
42098cd9557SMatthias Ringwald 	return -1;
42198cd9557SMatthias Ringwald }
42298cd9557SMatthias Ringwald 
42398cd9557SMatthias Ringwald _TINYDIR_FUNC
42498cd9557SMatthias Ringwald void tinydir_close(tinydir_dir *dir)
42598cd9557SMatthias Ringwald {
42698cd9557SMatthias Ringwald 	if (dir == NULL)
42798cd9557SMatthias Ringwald 	{
42898cd9557SMatthias Ringwald 		return;
42998cd9557SMatthias Ringwald 	}
43098cd9557SMatthias Ringwald 
43198cd9557SMatthias Ringwald 	memset(dir->path, 0, sizeof(dir->path));
43298cd9557SMatthias Ringwald 	dir->has_next = 0;
43398cd9557SMatthias Ringwald 	dir->n_files = 0;
43498cd9557SMatthias Ringwald 	_TINYDIR_FREE(dir->_files);
43598cd9557SMatthias Ringwald 	dir->_files = NULL;
43698cd9557SMatthias Ringwald #ifdef _MSC_VER
43798cd9557SMatthias Ringwald 	if (dir->_h != INVALID_HANDLE_VALUE)
43898cd9557SMatthias Ringwald 	{
43998cd9557SMatthias Ringwald 		FindClose(dir->_h);
44098cd9557SMatthias Ringwald 	}
44198cd9557SMatthias Ringwald 	dir->_h = INVALID_HANDLE_VALUE;
44298cd9557SMatthias Ringwald #else
44398cd9557SMatthias Ringwald 	if (dir->_d)
44498cd9557SMatthias Ringwald 	{
44598cd9557SMatthias Ringwald 		_tinydir_closedir(dir->_d);
44698cd9557SMatthias Ringwald 	}
44798cd9557SMatthias Ringwald 	dir->_d = NULL;
44898cd9557SMatthias Ringwald 	dir->_e = NULL;
44998cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
45098cd9557SMatthias Ringwald 	_TINYDIR_FREE(dir->_ep);
45198cd9557SMatthias Ringwald 	dir->_ep = NULL;
45298cd9557SMatthias Ringwald #endif
45398cd9557SMatthias Ringwald #endif
45498cd9557SMatthias Ringwald }
45598cd9557SMatthias Ringwald 
45698cd9557SMatthias Ringwald _TINYDIR_FUNC
45798cd9557SMatthias Ringwald int tinydir_next(tinydir_dir *dir)
45898cd9557SMatthias Ringwald {
45998cd9557SMatthias Ringwald 	if (dir == NULL)
46098cd9557SMatthias Ringwald 	{
46198cd9557SMatthias Ringwald 		errno = EINVAL;
46298cd9557SMatthias Ringwald 		return -1;
46398cd9557SMatthias Ringwald 	}
46498cd9557SMatthias Ringwald 	if (!dir->has_next)
46598cd9557SMatthias Ringwald 	{
46698cd9557SMatthias Ringwald 		errno = ENOENT;
46798cd9557SMatthias Ringwald 		return -1;
46898cd9557SMatthias Ringwald 	}
46998cd9557SMatthias Ringwald 
47098cd9557SMatthias Ringwald #ifdef _MSC_VER
47198cd9557SMatthias Ringwald 	if (FindNextFile(dir->_h, &dir->_f) == 0)
47298cd9557SMatthias Ringwald #else
47398cd9557SMatthias Ringwald #ifdef _TINYDIR_USE_READDIR
47498cd9557SMatthias Ringwald 	dir->_e = _tinydir_readdir(dir->_d);
47598cd9557SMatthias Ringwald #else
47698cd9557SMatthias Ringwald 	if (dir->_ep == NULL)
47798cd9557SMatthias Ringwald 	{
47898cd9557SMatthias Ringwald 		return -1;
47998cd9557SMatthias Ringwald 	}
48098cd9557SMatthias Ringwald 	if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
48198cd9557SMatthias Ringwald 	{
48298cd9557SMatthias Ringwald 		return -1;
48398cd9557SMatthias Ringwald 	}
48498cd9557SMatthias Ringwald #endif
48598cd9557SMatthias Ringwald 	if (dir->_e == NULL)
48698cd9557SMatthias Ringwald #endif
48798cd9557SMatthias Ringwald 	{
48898cd9557SMatthias Ringwald 		dir->has_next = 0;
48998cd9557SMatthias Ringwald #ifdef _MSC_VER
49098cd9557SMatthias Ringwald 		if (GetLastError() != ERROR_SUCCESS &&
49198cd9557SMatthias Ringwald 			GetLastError() != ERROR_NO_MORE_FILES)
49298cd9557SMatthias Ringwald 		{
49398cd9557SMatthias Ringwald 			tinydir_close(dir);
49498cd9557SMatthias Ringwald 			errno = EIO;
49598cd9557SMatthias Ringwald 			return -1;
49698cd9557SMatthias Ringwald 		}
49798cd9557SMatthias Ringwald #endif
49898cd9557SMatthias Ringwald 	}
49998cd9557SMatthias Ringwald 
50098cd9557SMatthias Ringwald 	return 0;
50198cd9557SMatthias Ringwald }
50298cd9557SMatthias Ringwald 
50398cd9557SMatthias Ringwald _TINYDIR_FUNC
50498cd9557SMatthias Ringwald int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
50598cd9557SMatthias Ringwald {
506*e9d8dc8bSDirk Helbig 	const _tinydir_char_t *filename;
50798cd9557SMatthias Ringwald 	if (dir == NULL || file == NULL)
50898cd9557SMatthias Ringwald 	{
50998cd9557SMatthias Ringwald 		errno = EINVAL;
51098cd9557SMatthias Ringwald 		return -1;
51198cd9557SMatthias Ringwald 	}
51298cd9557SMatthias Ringwald #ifdef _MSC_VER
51398cd9557SMatthias Ringwald 	if (dir->_h == INVALID_HANDLE_VALUE)
51498cd9557SMatthias Ringwald #else
51598cd9557SMatthias Ringwald 	if (dir->_e == NULL)
51698cd9557SMatthias Ringwald #endif
51798cd9557SMatthias Ringwald 	{
51898cd9557SMatthias Ringwald 		errno = ENOENT;
51998cd9557SMatthias Ringwald 		return -1;
52098cd9557SMatthias Ringwald 	}
521*e9d8dc8bSDirk Helbig 	filename =
52298cd9557SMatthias Ringwald #ifdef _MSC_VER
523*e9d8dc8bSDirk Helbig 		dir->_f.cFileName;
52498cd9557SMatthias Ringwald #else
525*e9d8dc8bSDirk Helbig 		dir->_e->d_name;
52698cd9557SMatthias Ringwald #endif
527*e9d8dc8bSDirk Helbig 	if (_tinydir_strlen(dir->path) +
528*e9d8dc8bSDirk Helbig 		_tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >=
52998cd9557SMatthias Ringwald 		_TINYDIR_PATH_MAX)
53098cd9557SMatthias Ringwald 	{
53198cd9557SMatthias Ringwald 		/* the path for the file will be too long */
53298cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
53398cd9557SMatthias Ringwald 		return -1;
53498cd9557SMatthias Ringwald 	}
535*e9d8dc8bSDirk Helbig 	if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX)
53698cd9557SMatthias Ringwald 	{
53798cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
53898cd9557SMatthias Ringwald 		return -1;
53998cd9557SMatthias Ringwald 	}
54098cd9557SMatthias Ringwald 
54198cd9557SMatthias Ringwald 	_tinydir_strcpy(file->path, dir->path);
542*e9d8dc8bSDirk Helbig 	if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0)
54398cd9557SMatthias Ringwald 		_tinydir_strcat(file->path, TINYDIR_STRING("/"));
544*e9d8dc8bSDirk Helbig 	_tinydir_strcpy(file->name, filename);
545*e9d8dc8bSDirk Helbig 	_tinydir_strcat(file->path, filename);
54698cd9557SMatthias Ringwald #ifndef _MSC_VER
54798cd9557SMatthias Ringwald #ifdef __MINGW32__
54898cd9557SMatthias Ringwald 	if (_tstat(
549*e9d8dc8bSDirk Helbig #elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE)	\
550*e9d8dc8bSDirk Helbig 	|| ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500))	\
551*e9d8dc8bSDirk Helbig 	|| ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \
552*e9d8dc8bSDirk Helbig 	|| ((defined __APPLE__) && (defined __MACH__)) \
553*e9d8dc8bSDirk Helbig 	|| (defined BSD)
554*e9d8dc8bSDirk Helbig 	if (lstat(
55598cd9557SMatthias Ringwald #else
55698cd9557SMatthias Ringwald 	if (stat(
55798cd9557SMatthias Ringwald #endif
55898cd9557SMatthias Ringwald 		file->path, &file->_s) == -1)
55998cd9557SMatthias Ringwald 	{
56098cd9557SMatthias Ringwald 		return -1;
56198cd9557SMatthias Ringwald 	}
56298cd9557SMatthias Ringwald #endif
56398cd9557SMatthias Ringwald 	_tinydir_get_ext(file);
56498cd9557SMatthias Ringwald 
56598cd9557SMatthias Ringwald 	file->is_dir =
56698cd9557SMatthias Ringwald #ifdef _MSC_VER
56798cd9557SMatthias Ringwald 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
56898cd9557SMatthias Ringwald #else
56998cd9557SMatthias Ringwald 		S_ISDIR(file->_s.st_mode);
57098cd9557SMatthias Ringwald #endif
57198cd9557SMatthias Ringwald 	file->is_reg =
57298cd9557SMatthias Ringwald #ifdef _MSC_VER
57398cd9557SMatthias Ringwald 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
57498cd9557SMatthias Ringwald 		(
57598cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
57698cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
57798cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
57898cd9557SMatthias Ringwald #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
57998cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
58098cd9557SMatthias Ringwald #endif
58198cd9557SMatthias Ringwald #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
58298cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
58398cd9557SMatthias Ringwald #endif
58498cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
58598cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
58698cd9557SMatthias Ringwald #else
58798cd9557SMatthias Ringwald 		S_ISREG(file->_s.st_mode);
58898cd9557SMatthias Ringwald #endif
58998cd9557SMatthias Ringwald 
59098cd9557SMatthias Ringwald 	return 0;
59198cd9557SMatthias Ringwald }
59298cd9557SMatthias Ringwald 
59398cd9557SMatthias Ringwald _TINYDIR_FUNC
59498cd9557SMatthias Ringwald int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
59598cd9557SMatthias Ringwald {
59698cd9557SMatthias Ringwald 	if (dir == NULL || file == NULL)
59798cd9557SMatthias Ringwald 	{
59898cd9557SMatthias Ringwald 		errno = EINVAL;
59998cd9557SMatthias Ringwald 		return -1;
60098cd9557SMatthias Ringwald 	}
60198cd9557SMatthias Ringwald 	if (i >= dir->n_files)
60298cd9557SMatthias Ringwald 	{
60398cd9557SMatthias Ringwald 		errno = ENOENT;
60498cd9557SMatthias Ringwald 		return -1;
60598cd9557SMatthias Ringwald 	}
60698cd9557SMatthias Ringwald 
60798cd9557SMatthias Ringwald 	memcpy(file, &dir->_files[i], sizeof(tinydir_file));
60898cd9557SMatthias Ringwald 	_tinydir_get_ext(file);
60998cd9557SMatthias Ringwald 
61098cd9557SMatthias Ringwald 	return 0;
61198cd9557SMatthias Ringwald }
61298cd9557SMatthias Ringwald 
61398cd9557SMatthias Ringwald _TINYDIR_FUNC
61498cd9557SMatthias Ringwald int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
61598cd9557SMatthias Ringwald {
61698cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
61798cd9557SMatthias Ringwald 	if (dir == NULL)
61898cd9557SMatthias Ringwald 	{
61998cd9557SMatthias Ringwald 		errno = EINVAL;
62098cd9557SMatthias Ringwald 		return -1;
62198cd9557SMatthias Ringwald 	}
62298cd9557SMatthias Ringwald 	if (i >= dir->n_files || !dir->_files[i].is_dir)
62398cd9557SMatthias Ringwald 	{
62498cd9557SMatthias Ringwald 		errno = ENOENT;
62598cd9557SMatthias Ringwald 		return -1;
62698cd9557SMatthias Ringwald 	}
62798cd9557SMatthias Ringwald 
62898cd9557SMatthias Ringwald 	_tinydir_strcpy(path, dir->_files[i].path);
62998cd9557SMatthias Ringwald 	tinydir_close(dir);
63098cd9557SMatthias Ringwald 	if (tinydir_open_sorted(dir, path) == -1)
63198cd9557SMatthias Ringwald 	{
63298cd9557SMatthias Ringwald 		return -1;
63398cd9557SMatthias Ringwald 	}
63498cd9557SMatthias Ringwald 
63598cd9557SMatthias Ringwald 	return 0;
63698cd9557SMatthias Ringwald }
63798cd9557SMatthias Ringwald 
63898cd9557SMatthias Ringwald /* Open a single file given its path */
63998cd9557SMatthias Ringwald _TINYDIR_FUNC
64098cd9557SMatthias Ringwald int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
64198cd9557SMatthias Ringwald {
64298cd9557SMatthias Ringwald 	tinydir_dir dir;
64398cd9557SMatthias Ringwald 	int result = 0;
64498cd9557SMatthias Ringwald 	int found = 0;
64598cd9557SMatthias Ringwald 	_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
646*e9d8dc8bSDirk Helbig 	_tinydir_char_t file_name_buf[_TINYDIR_PATH_MAX];
64798cd9557SMatthias Ringwald 	_tinydir_char_t *dir_name;
64898cd9557SMatthias Ringwald 	_tinydir_char_t *base_name;
64998cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
65098cd9557SMatthias Ringwald 	_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
65198cd9557SMatthias Ringwald 	_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
65298cd9557SMatthias Ringwald #endif
65398cd9557SMatthias Ringwald 
65498cd9557SMatthias Ringwald 	if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
65598cd9557SMatthias Ringwald 	{
65698cd9557SMatthias Ringwald 		errno = EINVAL;
65798cd9557SMatthias Ringwald 		return -1;
65898cd9557SMatthias Ringwald 	}
65998cd9557SMatthias Ringwald 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
66098cd9557SMatthias Ringwald 	{
66198cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
66298cd9557SMatthias Ringwald 		return -1;
66398cd9557SMatthias Ringwald 	}
66498cd9557SMatthias Ringwald 
66598cd9557SMatthias Ringwald 	/* Get the parent path */
66698cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
66798cd9557SMatthias Ringwald #if ((defined _MSC_VER) && (_MSC_VER >= 1400))
668ec8ca29fSMatthias Ringwald 	errno = _tsplitpath_s(
66998cd9557SMatthias Ringwald 		path,
67098cd9557SMatthias Ringwald 		drive_buf, _TINYDIR_DRIVE_MAX,
67198cd9557SMatthias Ringwald 		dir_name_buf, _TINYDIR_FILENAME_MAX,
67298cd9557SMatthias Ringwald 		file_name_buf, _TINYDIR_FILENAME_MAX,
67398cd9557SMatthias Ringwald 		ext_buf, _TINYDIR_FILENAME_MAX);
67498cd9557SMatthias Ringwald #else
67598cd9557SMatthias Ringwald 	_tsplitpath(
67698cd9557SMatthias Ringwald 		path,
67798cd9557SMatthias Ringwald 		drive_buf,
67898cd9557SMatthias Ringwald 		dir_name_buf,
67998cd9557SMatthias Ringwald 		file_name_buf,
68098cd9557SMatthias Ringwald 		ext_buf);
68198cd9557SMatthias Ringwald #endif
68298cd9557SMatthias Ringwald 
683ec8ca29fSMatthias Ringwald 	if (errno)
684ec8ca29fSMatthias Ringwald 	{
685ec8ca29fSMatthias Ringwald 		return -1;
686ec8ca29fSMatthias Ringwald 	}
687ec8ca29fSMatthias Ringwald 
68898cd9557SMatthias Ringwald /* _splitpath_s not work fine with only filename and widechar support */
68998cd9557SMatthias Ringwald #ifdef _UNICODE
69098cd9557SMatthias Ringwald 	if (drive_buf[0] == L'\xFEFE')
69198cd9557SMatthias Ringwald 		drive_buf[0] = '\0';
69298cd9557SMatthias Ringwald 	if (dir_name_buf[0] == L'\xFEFE')
69398cd9557SMatthias Ringwald 		dir_name_buf[0] = '\0';
69498cd9557SMatthias Ringwald #endif
69598cd9557SMatthias Ringwald 
69698cd9557SMatthias Ringwald 	/* Emulate the behavior of dirname by returning "." for dir name if it's
69798cd9557SMatthias Ringwald 	empty */
69898cd9557SMatthias Ringwald 	if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
69998cd9557SMatthias Ringwald 	{
70098cd9557SMatthias Ringwald 		_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
70198cd9557SMatthias Ringwald 	}
70298cd9557SMatthias Ringwald 	/* Concatenate the drive letter and dir name to form full dir name */
70398cd9557SMatthias Ringwald 	_tinydir_strcat(drive_buf, dir_name_buf);
70498cd9557SMatthias Ringwald 	dir_name = drive_buf;
70598cd9557SMatthias Ringwald 	/* Concatenate the file name and extension to form base name */
70698cd9557SMatthias Ringwald 	_tinydir_strcat(file_name_buf, ext_buf);
70798cd9557SMatthias Ringwald 	base_name = file_name_buf;
70898cd9557SMatthias Ringwald #else
70998cd9557SMatthias Ringwald 	_tinydir_strcpy(dir_name_buf, path);
71098cd9557SMatthias Ringwald 	dir_name = dirname(dir_name_buf);
71198cd9557SMatthias Ringwald 	_tinydir_strcpy(file_name_buf, path);
71298cd9557SMatthias Ringwald 	base_name = basename(file_name_buf);
71398cd9557SMatthias Ringwald #endif
71498cd9557SMatthias Ringwald 
715*e9d8dc8bSDirk Helbig 	/* Special case: if the path is a root dir, open the parent dir as the file */
716*e9d8dc8bSDirk Helbig #if (defined _MSC_VER || defined __MINGW32__)
717*e9d8dc8bSDirk Helbig 	if (_tinydir_strlen(base_name) == 0)
718*e9d8dc8bSDirk Helbig #else
719*e9d8dc8bSDirk Helbig 	if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0)
720*e9d8dc8bSDirk Helbig #endif
721*e9d8dc8bSDirk Helbig 	{
722*e9d8dc8bSDirk Helbig 		memset(file, 0, sizeof * file);
723*e9d8dc8bSDirk Helbig 		file->is_dir = 1;
724*e9d8dc8bSDirk Helbig 		file->is_reg = 0;
725*e9d8dc8bSDirk Helbig 		_tinydir_strcpy(file->path, dir_name);
726*e9d8dc8bSDirk Helbig 		file->extension = file->path + _tinydir_strlen(file->path);
727*e9d8dc8bSDirk Helbig 		return 0;
728*e9d8dc8bSDirk Helbig 	}
729*e9d8dc8bSDirk Helbig 
73098cd9557SMatthias Ringwald 	/* Open the parent directory */
73198cd9557SMatthias Ringwald 	if (tinydir_open(&dir, dir_name) == -1)
73298cd9557SMatthias Ringwald 	{
73398cd9557SMatthias Ringwald 		return -1;
73498cd9557SMatthias Ringwald 	}
73598cd9557SMatthias Ringwald 
73698cd9557SMatthias Ringwald 	/* Read through the parent directory and look for the file */
73798cd9557SMatthias Ringwald 	while (dir.has_next)
73898cd9557SMatthias Ringwald 	{
73998cd9557SMatthias Ringwald 		if (tinydir_readfile(&dir, file) == -1)
74098cd9557SMatthias Ringwald 		{
74198cd9557SMatthias Ringwald 			result = -1;
74298cd9557SMatthias Ringwald 			goto bail;
74398cd9557SMatthias Ringwald 		}
74498cd9557SMatthias Ringwald 		if (_tinydir_strcmp(file->name, base_name) == 0)
74598cd9557SMatthias Ringwald 		{
74698cd9557SMatthias Ringwald 			/* File found */
74798cd9557SMatthias Ringwald 			found = 1;
74898cd9557SMatthias Ringwald 			break;
74998cd9557SMatthias Ringwald 		}
75098cd9557SMatthias Ringwald 		tinydir_next(&dir);
75198cd9557SMatthias Ringwald 	}
75298cd9557SMatthias Ringwald 	if (!found)
75398cd9557SMatthias Ringwald 	{
75498cd9557SMatthias Ringwald 		result = -1;
75598cd9557SMatthias Ringwald 		errno = ENOENT;
75698cd9557SMatthias Ringwald 	}
75798cd9557SMatthias Ringwald 
75898cd9557SMatthias Ringwald bail:
75998cd9557SMatthias Ringwald 	tinydir_close(&dir);
76098cd9557SMatthias Ringwald 	return result;
76198cd9557SMatthias Ringwald }
76298cd9557SMatthias Ringwald 
76398cd9557SMatthias Ringwald _TINYDIR_FUNC
76498cd9557SMatthias Ringwald void _tinydir_get_ext(tinydir_file *file)
76598cd9557SMatthias Ringwald {
76698cd9557SMatthias Ringwald 	_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
76798cd9557SMatthias Ringwald 	if (period == NULL)
76898cd9557SMatthias Ringwald 	{
76998cd9557SMatthias Ringwald 		file->extension = &(file->name[_tinydir_strlen(file->name)]);
77098cd9557SMatthias Ringwald 	}
77198cd9557SMatthias Ringwald 	else
77298cd9557SMatthias Ringwald 	{
77398cd9557SMatthias Ringwald 		file->extension = period + 1;
77498cd9557SMatthias Ringwald 	}
77598cd9557SMatthias Ringwald }
77698cd9557SMatthias Ringwald 
77798cd9557SMatthias Ringwald _TINYDIR_FUNC
77898cd9557SMatthias Ringwald int _tinydir_file_cmp(const void *a, const void *b)
77998cd9557SMatthias Ringwald {
78098cd9557SMatthias Ringwald 	const tinydir_file *fa = (const tinydir_file *)a;
78198cd9557SMatthias Ringwald 	const tinydir_file *fb = (const tinydir_file *)b;
78298cd9557SMatthias Ringwald 	if (fa->is_dir != fb->is_dir)
78398cd9557SMatthias Ringwald 	{
78498cd9557SMatthias Ringwald 		return -(fa->is_dir - fb->is_dir);
78598cd9557SMatthias Ringwald 	}
78698cd9557SMatthias Ringwald 	return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
78798cd9557SMatthias Ringwald }
78898cd9557SMatthias Ringwald 
78998cd9557SMatthias Ringwald #ifndef _MSC_VER
79098cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
79198cd9557SMatthias Ringwald /*
79298cd9557SMatthias Ringwald The following authored by Ben Hutchings <[email protected]>
79398cd9557SMatthias Ringwald from https://womble.decadent.org.uk/readdir_r-advisory.html
79498cd9557SMatthias Ringwald */
79598cd9557SMatthias Ringwald /* Calculate the required buffer size (in bytes) for directory      *
79698cd9557SMatthias Ringwald * entries read from the given directory handle.  Return -1 if this  *
79798cd9557SMatthias Ringwald * this cannot be done.                                              *
79898cd9557SMatthias Ringwald *                                                                   *
79998cd9557SMatthias Ringwald * This code does not trust values of NAME_MAX that are less than    *
80098cd9557SMatthias Ringwald * 255, since some systems (including at least HP-UX) incorrectly    *
80198cd9557SMatthias Ringwald * define it to be a smaller value.                                  */
80298cd9557SMatthias Ringwald _TINYDIR_FUNC
80398cd9557SMatthias Ringwald size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
80498cd9557SMatthias Ringwald {
80598cd9557SMatthias Ringwald 	long name_max;
80698cd9557SMatthias Ringwald 	size_t name_end;
80798cd9557SMatthias Ringwald 	/* parameter may be unused */
80898cd9557SMatthias Ringwald 	(void)dirp;
80998cd9557SMatthias Ringwald 
81098cd9557SMatthias Ringwald #if defined _TINYDIR_USE_FPATHCONF
81198cd9557SMatthias Ringwald 	name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
81298cd9557SMatthias Ringwald 	if (name_max == -1)
81398cd9557SMatthias Ringwald #if defined(NAME_MAX)
81498cd9557SMatthias Ringwald 		name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
81598cd9557SMatthias Ringwald #else
81698cd9557SMatthias Ringwald 		return (size_t)(-1);
81798cd9557SMatthias Ringwald #endif
81898cd9557SMatthias Ringwald #elif defined(NAME_MAX)
81998cd9557SMatthias Ringwald  	name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
82098cd9557SMatthias Ringwald #else
82198cd9557SMatthias Ringwald #error "buffer size for readdir_r cannot be determined"
82298cd9557SMatthias Ringwald #endif
82398cd9557SMatthias Ringwald 	name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
82498cd9557SMatthias Ringwald 	return (name_end > sizeof(struct _tinydir_dirent) ?
82598cd9557SMatthias Ringwald 		name_end : sizeof(struct _tinydir_dirent));
82698cd9557SMatthias Ringwald }
82798cd9557SMatthias Ringwald #endif
82898cd9557SMatthias Ringwald #endif
82998cd9557SMatthias Ringwald 
83098cd9557SMatthias Ringwald #ifdef __cplusplus
83198cd9557SMatthias Ringwald }
83298cd9557SMatthias Ringwald #endif
83398cd9557SMatthias Ringwald 
83498cd9557SMatthias Ringwald # if defined (_MSC_VER)
83598cd9557SMatthias Ringwald # pragma warning(pop)
83698cd9557SMatthias Ringwald # endif
83798cd9557SMatthias Ringwald 
83898cd9557SMatthias Ringwald #endif
839