xref: /btstack/3rd-party/tinydir/tinydir.h (revision ec8ca29f14e3b738f9bc53e3f9b016e8a472ef04)
198cd9557SMatthias Ringwald /*
2*ec8ca29fSMatthias Ringwald Copyright (c) 2013-2018, 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
4898cd9557SMatthias Ringwald # define WIN32_LEAN_AND_MEAN
4998cd9557SMatthias Ringwald # include <windows.h>
5098cd9557SMatthias Ringwald # include <tchar.h>
5198cd9557SMatthias Ringwald # pragma warning(push)
5298cd9557SMatthias Ringwald # pragma warning (disable : 4996)
5398cd9557SMatthias Ringwald #else
5498cd9557SMatthias Ringwald # include <dirent.h>
5598cd9557SMatthias Ringwald # include <libgen.h>
5698cd9557SMatthias Ringwald # include <sys/stat.h>
5798cd9557SMatthias Ringwald # include <stddef.h>
5898cd9557SMatthias Ringwald #endif
5998cd9557SMatthias Ringwald #ifdef __MINGW32__
6098cd9557SMatthias Ringwald # include <tchar.h>
6198cd9557SMatthias Ringwald #endif
6298cd9557SMatthias Ringwald 
6398cd9557SMatthias Ringwald 
6498cd9557SMatthias Ringwald /* types */
6598cd9557SMatthias Ringwald 
6698cd9557SMatthias Ringwald /* Windows UNICODE wide character support */
6798cd9557SMatthias Ringwald #if defined _MSC_VER || defined __MINGW32__
6898cd9557SMatthias Ringwald # define _tinydir_char_t TCHAR
6998cd9557SMatthias Ringwald # define TINYDIR_STRING(s) _TEXT(s)
7098cd9557SMatthias Ringwald # define _tinydir_strlen _tcslen
7198cd9557SMatthias Ringwald # define _tinydir_strcpy _tcscpy
7298cd9557SMatthias Ringwald # define _tinydir_strcat _tcscat
7398cd9557SMatthias Ringwald # define _tinydir_strcmp _tcscmp
7498cd9557SMatthias Ringwald # define _tinydir_strrchr _tcsrchr
7598cd9557SMatthias Ringwald # define _tinydir_strncmp _tcsncmp
7698cd9557SMatthias Ringwald #else
7798cd9557SMatthias Ringwald # define _tinydir_char_t char
7898cd9557SMatthias Ringwald # define TINYDIR_STRING(s) s
7998cd9557SMatthias Ringwald # define _tinydir_strlen strlen
8098cd9557SMatthias Ringwald # define _tinydir_strcpy strcpy
8198cd9557SMatthias Ringwald # define _tinydir_strcat strcat
8298cd9557SMatthias Ringwald # define _tinydir_strcmp strcmp
8398cd9557SMatthias Ringwald # define _tinydir_strrchr strrchr
8498cd9557SMatthias Ringwald # define _tinydir_strncmp strncmp
8598cd9557SMatthias Ringwald #endif
8698cd9557SMatthias Ringwald 
8798cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
8898cd9557SMatthias Ringwald # include <windows.h>
8998cd9557SMatthias Ringwald # define _TINYDIR_PATH_MAX MAX_PATH
9098cd9557SMatthias Ringwald #elif defined  __linux__
9198cd9557SMatthias Ringwald # include <limits.h>
92*ec8ca29fSMatthias Ringwald /* BK - only use PATH_MAX if defined */
93*ec8ca29fSMatthias Ringwald # if defined(PATH_MAX)
9498cd9557SMatthias Ringwald #  define _TINYDIR_PATH_MAX PATH_MAX
95*ec8ca29fSMatthias Ringwald # endif
9698cd9557SMatthias Ringwald #elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
9798cd9557SMatthias Ringwald # include <sys/param.h>
9898cd9557SMatthias Ringwald # if defined(BSD)
9998cd9557SMatthias Ringwald #  include <limits.h>
10098cd9557SMatthias Ringwald #  define _TINYDIR_PATH_MAX PATH_MAX
10198cd9557SMatthias Ringwald # endif
10298cd9557SMatthias Ringwald #endif
10398cd9557SMatthias Ringwald 
10498cd9557SMatthias Ringwald #ifndef _TINYDIR_PATH_MAX
10598cd9557SMatthias Ringwald #define _TINYDIR_PATH_MAX 4096
10698cd9557SMatthias Ringwald #endif
10798cd9557SMatthias Ringwald 
10898cd9557SMatthias Ringwald #ifdef _MSC_VER
10998cd9557SMatthias Ringwald /* extra chars for the "\\*" mask */
11098cd9557SMatthias Ringwald # define _TINYDIR_PATH_EXTRA 2
11198cd9557SMatthias Ringwald #else
11298cd9557SMatthias Ringwald # define _TINYDIR_PATH_EXTRA 0
11398cd9557SMatthias Ringwald #endif
11498cd9557SMatthias Ringwald 
11598cd9557SMatthias Ringwald #define _TINYDIR_FILENAME_MAX 256
11698cd9557SMatthias Ringwald 
11798cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
11898cd9557SMatthias Ringwald #define _TINYDIR_DRIVE_MAX 3
11998cd9557SMatthias Ringwald #endif
12098cd9557SMatthias Ringwald 
12198cd9557SMatthias Ringwald #ifdef _MSC_VER
12298cd9557SMatthias Ringwald # define _TINYDIR_FUNC static __inline
12398cd9557SMatthias Ringwald #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
12498cd9557SMatthias Ringwald # define _TINYDIR_FUNC static __inline__
12598cd9557SMatthias Ringwald #else
12698cd9557SMatthias Ringwald # define _TINYDIR_FUNC static inline
12798cd9557SMatthias Ringwald #endif
12898cd9557SMatthias Ringwald 
12998cd9557SMatthias Ringwald /* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
13098cd9557SMatthias Ringwald #ifdef TINYDIR_USE_READDIR_R
13198cd9557SMatthias Ringwald 
13298cd9557SMatthias Ringwald /* readdir_r is a POSIX-only function, and may not be available under various
13398cd9557SMatthias Ringwald  * environments/settings, e.g. MinGW. Use readdir fallback */
13498cd9557SMatthias Ringwald #if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
13598cd9557SMatthias Ringwald 	_POSIX_SOURCE
13698cd9557SMatthias Ringwald # define _TINYDIR_HAS_READDIR_R
13798cd9557SMatthias Ringwald #endif
13898cd9557SMatthias Ringwald #if _POSIX_C_SOURCE >= 200112L
13998cd9557SMatthias Ringwald # define _TINYDIR_HAS_FPATHCONF
14098cd9557SMatthias Ringwald # include <unistd.h>
14198cd9557SMatthias Ringwald #endif
14298cd9557SMatthias Ringwald #if _BSD_SOURCE || _SVID_SOURCE || \
14398cd9557SMatthias Ringwald 	(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
14498cd9557SMatthias Ringwald # define _TINYDIR_HAS_DIRFD
14598cd9557SMatthias Ringwald # include <sys/types.h>
14698cd9557SMatthias Ringwald #endif
14798cd9557SMatthias Ringwald #if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
14898cd9557SMatthias Ringwald 	defined _PC_NAME_MAX
14998cd9557SMatthias Ringwald # define _TINYDIR_USE_FPATHCONF
15098cd9557SMatthias Ringwald #endif
15198cd9557SMatthias Ringwald #if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
15298cd9557SMatthias Ringwald 	!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
15398cd9557SMatthias Ringwald # define _TINYDIR_USE_READDIR
15498cd9557SMatthias Ringwald #endif
15598cd9557SMatthias Ringwald 
15698cd9557SMatthias Ringwald /* Use readdir by default */
15798cd9557SMatthias Ringwald #else
15898cd9557SMatthias Ringwald # define _TINYDIR_USE_READDIR
15998cd9557SMatthias Ringwald #endif
16098cd9557SMatthias Ringwald 
16198cd9557SMatthias Ringwald /* MINGW32 has two versions of dirent, ASCII and UNICODE*/
16298cd9557SMatthias Ringwald #ifndef _MSC_VER
16398cd9557SMatthias Ringwald #if (defined __MINGW32__) && (defined _UNICODE)
16498cd9557SMatthias Ringwald #define _TINYDIR_DIR _WDIR
16598cd9557SMatthias Ringwald #define _tinydir_dirent _wdirent
16698cd9557SMatthias Ringwald #define _tinydir_opendir _wopendir
16798cd9557SMatthias Ringwald #define _tinydir_readdir _wreaddir
16898cd9557SMatthias Ringwald #define _tinydir_closedir _wclosedir
16998cd9557SMatthias Ringwald #else
17098cd9557SMatthias Ringwald #define _TINYDIR_DIR DIR
17198cd9557SMatthias Ringwald #define _tinydir_dirent dirent
17298cd9557SMatthias Ringwald #define _tinydir_opendir opendir
17398cd9557SMatthias Ringwald #define _tinydir_readdir readdir
17498cd9557SMatthias Ringwald #define _tinydir_closedir closedir
17598cd9557SMatthias Ringwald #endif
17698cd9557SMatthias Ringwald #endif
17798cd9557SMatthias Ringwald 
17898cd9557SMatthias Ringwald /* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
17998cd9557SMatthias Ringwald #if    defined(_TINYDIR_MALLOC) &&  defined(_TINYDIR_FREE)
18098cd9557SMatthias Ringwald #elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
18198cd9557SMatthias Ringwald #else
18298cd9557SMatthias Ringwald #error "Either define both alloc and free or none of them!"
18398cd9557SMatthias Ringwald #endif
18498cd9557SMatthias Ringwald 
18598cd9557SMatthias Ringwald #if !defined(_TINYDIR_MALLOC)
18698cd9557SMatthias Ringwald 	#define _TINYDIR_MALLOC(_size) malloc(_size)
18798cd9557SMatthias Ringwald 	#define _TINYDIR_FREE(_ptr)    free(_ptr)
18898cd9557SMatthias Ringwald #endif /* !defined(_TINYDIR_MALLOC) */
18998cd9557SMatthias Ringwald 
19098cd9557SMatthias Ringwald typedef struct tinydir_file
19198cd9557SMatthias Ringwald {
19298cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
19398cd9557SMatthias Ringwald 	_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
19498cd9557SMatthias Ringwald 	_tinydir_char_t *extension;
19598cd9557SMatthias Ringwald 	int is_dir;
19698cd9557SMatthias Ringwald 	int is_reg;
19798cd9557SMatthias Ringwald 
19898cd9557SMatthias Ringwald #ifndef _MSC_VER
19998cd9557SMatthias Ringwald #ifdef __MINGW32__
20098cd9557SMatthias Ringwald 	struct _stat _s;
20198cd9557SMatthias Ringwald #else
20298cd9557SMatthias Ringwald 	struct stat _s;
20398cd9557SMatthias Ringwald #endif
20498cd9557SMatthias Ringwald #endif
20598cd9557SMatthias Ringwald } tinydir_file;
20698cd9557SMatthias Ringwald 
20798cd9557SMatthias Ringwald typedef struct tinydir_dir
20898cd9557SMatthias Ringwald {
20998cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
21098cd9557SMatthias Ringwald 	int has_next;
21198cd9557SMatthias Ringwald 	size_t n_files;
21298cd9557SMatthias Ringwald 
21398cd9557SMatthias Ringwald 	tinydir_file *_files;
21498cd9557SMatthias Ringwald #ifdef _MSC_VER
21598cd9557SMatthias Ringwald 	HANDLE _h;
21698cd9557SMatthias Ringwald 	WIN32_FIND_DATA _f;
21798cd9557SMatthias Ringwald #else
21898cd9557SMatthias Ringwald 	_TINYDIR_DIR *_d;
21998cd9557SMatthias Ringwald 	struct _tinydir_dirent *_e;
22098cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
22198cd9557SMatthias Ringwald 	struct _tinydir_dirent *_ep;
22298cd9557SMatthias Ringwald #endif
22398cd9557SMatthias Ringwald #endif
22498cd9557SMatthias Ringwald } tinydir_dir;
22598cd9557SMatthias Ringwald 
22698cd9557SMatthias Ringwald 
22798cd9557SMatthias Ringwald /* declarations */
22898cd9557SMatthias Ringwald 
22998cd9557SMatthias Ringwald _TINYDIR_FUNC
23098cd9557SMatthias Ringwald int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
23198cd9557SMatthias Ringwald _TINYDIR_FUNC
23298cd9557SMatthias Ringwald int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
23398cd9557SMatthias Ringwald _TINYDIR_FUNC
23498cd9557SMatthias Ringwald void tinydir_close(tinydir_dir *dir);
23598cd9557SMatthias Ringwald 
23698cd9557SMatthias Ringwald _TINYDIR_FUNC
23798cd9557SMatthias Ringwald int tinydir_next(tinydir_dir *dir);
23898cd9557SMatthias Ringwald _TINYDIR_FUNC
23998cd9557SMatthias Ringwald int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
24098cd9557SMatthias Ringwald _TINYDIR_FUNC
24198cd9557SMatthias Ringwald int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
24298cd9557SMatthias Ringwald _TINYDIR_FUNC
24398cd9557SMatthias Ringwald int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
24498cd9557SMatthias Ringwald 
24598cd9557SMatthias Ringwald _TINYDIR_FUNC
24698cd9557SMatthias Ringwald int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
24798cd9557SMatthias Ringwald _TINYDIR_FUNC
24898cd9557SMatthias Ringwald void _tinydir_get_ext(tinydir_file *file);
24998cd9557SMatthias Ringwald _TINYDIR_FUNC
25098cd9557SMatthias Ringwald int _tinydir_file_cmp(const void *a, const void *b);
25198cd9557SMatthias Ringwald #ifndef _MSC_VER
25298cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
25398cd9557SMatthias Ringwald _TINYDIR_FUNC
25498cd9557SMatthias Ringwald size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
25598cd9557SMatthias Ringwald #endif
25698cd9557SMatthias Ringwald #endif
25798cd9557SMatthias Ringwald 
25898cd9557SMatthias Ringwald 
25998cd9557SMatthias Ringwald /* definitions*/
26098cd9557SMatthias Ringwald 
26198cd9557SMatthias Ringwald _TINYDIR_FUNC
26298cd9557SMatthias Ringwald int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
26398cd9557SMatthias Ringwald {
26498cd9557SMatthias Ringwald #ifndef _MSC_VER
26598cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
26698cd9557SMatthias Ringwald 	int error;
26798cd9557SMatthias Ringwald 	int size;	/* using int size */
26898cd9557SMatthias Ringwald #endif
26998cd9557SMatthias Ringwald #else
27098cd9557SMatthias Ringwald 	_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
27198cd9557SMatthias Ringwald #endif
27298cd9557SMatthias Ringwald 	_tinydir_char_t *pathp;
27398cd9557SMatthias Ringwald 
27498cd9557SMatthias Ringwald 	if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
27598cd9557SMatthias Ringwald 	{
27698cd9557SMatthias Ringwald 		errno = EINVAL;
27798cd9557SMatthias Ringwald 		return -1;
27898cd9557SMatthias Ringwald 	}
27998cd9557SMatthias Ringwald 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
28098cd9557SMatthias Ringwald 	{
28198cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
28298cd9557SMatthias Ringwald 		return -1;
28398cd9557SMatthias Ringwald 	}
28498cd9557SMatthias Ringwald 
28598cd9557SMatthias Ringwald 	/* initialise dir */
28698cd9557SMatthias Ringwald 	dir->_files = NULL;
28798cd9557SMatthias Ringwald #ifdef _MSC_VER
28898cd9557SMatthias Ringwald 	dir->_h = INVALID_HANDLE_VALUE;
28998cd9557SMatthias Ringwald #else
29098cd9557SMatthias Ringwald 	dir->_d = NULL;
29198cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
29298cd9557SMatthias Ringwald 	dir->_ep = NULL;
29398cd9557SMatthias Ringwald #endif
29498cd9557SMatthias Ringwald #endif
29598cd9557SMatthias Ringwald 	tinydir_close(dir);
29698cd9557SMatthias Ringwald 
29798cd9557SMatthias Ringwald 	_tinydir_strcpy(dir->path, path);
29898cd9557SMatthias Ringwald 	/* Remove trailing slashes */
29998cd9557SMatthias Ringwald 	pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
30098cd9557SMatthias Ringwald 	while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
30198cd9557SMatthias Ringwald 	{
30298cd9557SMatthias Ringwald 		*pathp = TINYDIR_STRING('\0');
30398cd9557SMatthias Ringwald 		pathp++;
30498cd9557SMatthias Ringwald 	}
30598cd9557SMatthias Ringwald #ifdef _MSC_VER
30698cd9557SMatthias Ringwald 	_tinydir_strcpy(path_buf, dir->path);
30798cd9557SMatthias Ringwald 	_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
30898cd9557SMatthias Ringwald #if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
30998cd9557SMatthias Ringwald 	dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
31098cd9557SMatthias Ringwald #else
31198cd9557SMatthias Ringwald 	dir->_h = FindFirstFile(path_buf, &dir->_f);
31298cd9557SMatthias Ringwald #endif
31398cd9557SMatthias Ringwald 	if (dir->_h == INVALID_HANDLE_VALUE)
31498cd9557SMatthias Ringwald 	{
31598cd9557SMatthias Ringwald 		errno = ENOENT;
31698cd9557SMatthias Ringwald #else
31798cd9557SMatthias Ringwald 	dir->_d = _tinydir_opendir(path);
31898cd9557SMatthias Ringwald 	if (dir->_d == NULL)
31998cd9557SMatthias Ringwald 	{
32098cd9557SMatthias Ringwald #endif
32198cd9557SMatthias Ringwald 		goto bail;
32298cd9557SMatthias Ringwald 	}
32398cd9557SMatthias Ringwald 
32498cd9557SMatthias Ringwald 	/* read first file */
32598cd9557SMatthias Ringwald 	dir->has_next = 1;
32698cd9557SMatthias Ringwald #ifndef _MSC_VER
32798cd9557SMatthias Ringwald #ifdef _TINYDIR_USE_READDIR
32898cd9557SMatthias Ringwald 	dir->_e = _tinydir_readdir(dir->_d);
32998cd9557SMatthias Ringwald #else
33098cd9557SMatthias Ringwald 	/* allocate dirent buffer for readdir_r */
33198cd9557SMatthias Ringwald 	size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
33298cd9557SMatthias Ringwald 	if (size == -1) return -1;
33398cd9557SMatthias Ringwald 	dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
33498cd9557SMatthias Ringwald 	if (dir->_ep == NULL) return -1;
33598cd9557SMatthias Ringwald 
33698cd9557SMatthias Ringwald 	error = readdir_r(dir->_d, dir->_ep, &dir->_e);
33798cd9557SMatthias Ringwald 	if (error != 0) return -1;
33898cd9557SMatthias Ringwald #endif
33998cd9557SMatthias Ringwald 	if (dir->_e == NULL)
34098cd9557SMatthias Ringwald 	{
34198cd9557SMatthias Ringwald 		dir->has_next = 0;
34298cd9557SMatthias Ringwald 	}
34398cd9557SMatthias Ringwald #endif
34498cd9557SMatthias Ringwald 
34598cd9557SMatthias Ringwald 	return 0;
34698cd9557SMatthias Ringwald 
34798cd9557SMatthias Ringwald bail:
34898cd9557SMatthias Ringwald 	tinydir_close(dir);
34998cd9557SMatthias Ringwald 	return -1;
35098cd9557SMatthias Ringwald }
35198cd9557SMatthias Ringwald 
35298cd9557SMatthias Ringwald _TINYDIR_FUNC
35398cd9557SMatthias Ringwald int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
35498cd9557SMatthias Ringwald {
35598cd9557SMatthias Ringwald 	/* Count the number of files first, to pre-allocate the files array */
35698cd9557SMatthias Ringwald 	size_t n_files = 0;
35798cd9557SMatthias Ringwald 	if (tinydir_open(dir, path) == -1)
35898cd9557SMatthias Ringwald 	{
35998cd9557SMatthias Ringwald 		return -1;
36098cd9557SMatthias Ringwald 	}
36198cd9557SMatthias Ringwald 	while (dir->has_next)
36298cd9557SMatthias Ringwald 	{
36398cd9557SMatthias Ringwald 		n_files++;
36498cd9557SMatthias Ringwald 		if (tinydir_next(dir) == -1)
36598cd9557SMatthias Ringwald 		{
36698cd9557SMatthias Ringwald 			goto bail;
36798cd9557SMatthias Ringwald 		}
36898cd9557SMatthias Ringwald 	}
36998cd9557SMatthias Ringwald 	tinydir_close(dir);
37098cd9557SMatthias Ringwald 
371*ec8ca29fSMatthias Ringwald 	if (n_files == 0 || tinydir_open(dir, path) == -1)
37298cd9557SMatthias Ringwald 	{
37398cd9557SMatthias Ringwald 		return -1;
37498cd9557SMatthias Ringwald 	}
37598cd9557SMatthias Ringwald 
37698cd9557SMatthias Ringwald 	dir->n_files = 0;
37798cd9557SMatthias Ringwald 	dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
37898cd9557SMatthias Ringwald 	if (dir->_files == NULL)
37998cd9557SMatthias Ringwald 	{
38098cd9557SMatthias Ringwald 		goto bail;
38198cd9557SMatthias Ringwald 	}
38298cd9557SMatthias Ringwald 	while (dir->has_next)
38398cd9557SMatthias Ringwald 	{
38498cd9557SMatthias Ringwald 		tinydir_file *p_file;
38598cd9557SMatthias Ringwald 		dir->n_files++;
38698cd9557SMatthias Ringwald 
38798cd9557SMatthias Ringwald 		p_file = &dir->_files[dir->n_files - 1];
38898cd9557SMatthias Ringwald 		if (tinydir_readfile(dir, p_file) == -1)
38998cd9557SMatthias Ringwald 		{
39098cd9557SMatthias Ringwald 			goto bail;
39198cd9557SMatthias Ringwald 		}
39298cd9557SMatthias Ringwald 
39398cd9557SMatthias Ringwald 		if (tinydir_next(dir) == -1)
39498cd9557SMatthias Ringwald 		{
39598cd9557SMatthias Ringwald 			goto bail;
39698cd9557SMatthias Ringwald 		}
39798cd9557SMatthias Ringwald 
39898cd9557SMatthias Ringwald 		/* Just in case the number of files has changed between the first and
39998cd9557SMatthias Ringwald 		second reads, terminate without writing into unallocated memory */
40098cd9557SMatthias Ringwald 		if (dir->n_files == n_files)
40198cd9557SMatthias Ringwald 		{
40298cd9557SMatthias Ringwald 			break;
40398cd9557SMatthias Ringwald 		}
40498cd9557SMatthias Ringwald 	}
40598cd9557SMatthias Ringwald 
40698cd9557SMatthias Ringwald 	qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
40798cd9557SMatthias Ringwald 
40898cd9557SMatthias Ringwald 	return 0;
40998cd9557SMatthias Ringwald 
41098cd9557SMatthias Ringwald bail:
41198cd9557SMatthias Ringwald 	tinydir_close(dir);
41298cd9557SMatthias Ringwald 	return -1;
41398cd9557SMatthias Ringwald }
41498cd9557SMatthias Ringwald 
41598cd9557SMatthias Ringwald _TINYDIR_FUNC
41698cd9557SMatthias Ringwald void tinydir_close(tinydir_dir *dir)
41798cd9557SMatthias Ringwald {
41898cd9557SMatthias Ringwald 	if (dir == NULL)
41998cd9557SMatthias Ringwald 	{
42098cd9557SMatthias Ringwald 		return;
42198cd9557SMatthias Ringwald 	}
42298cd9557SMatthias Ringwald 
42398cd9557SMatthias Ringwald 	memset(dir->path, 0, sizeof(dir->path));
42498cd9557SMatthias Ringwald 	dir->has_next = 0;
42598cd9557SMatthias Ringwald 	dir->n_files = 0;
42698cd9557SMatthias Ringwald 	_TINYDIR_FREE(dir->_files);
42798cd9557SMatthias Ringwald 	dir->_files = NULL;
42898cd9557SMatthias Ringwald #ifdef _MSC_VER
42998cd9557SMatthias Ringwald 	if (dir->_h != INVALID_HANDLE_VALUE)
43098cd9557SMatthias Ringwald 	{
43198cd9557SMatthias Ringwald 		FindClose(dir->_h);
43298cd9557SMatthias Ringwald 	}
43398cd9557SMatthias Ringwald 	dir->_h = INVALID_HANDLE_VALUE;
43498cd9557SMatthias Ringwald #else
43598cd9557SMatthias Ringwald 	if (dir->_d)
43698cd9557SMatthias Ringwald 	{
43798cd9557SMatthias Ringwald 		_tinydir_closedir(dir->_d);
43898cd9557SMatthias Ringwald 	}
43998cd9557SMatthias Ringwald 	dir->_d = NULL;
44098cd9557SMatthias Ringwald 	dir->_e = NULL;
44198cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
44298cd9557SMatthias Ringwald 	_TINYDIR_FREE(dir->_ep);
44398cd9557SMatthias Ringwald 	dir->_ep = NULL;
44498cd9557SMatthias Ringwald #endif
44598cd9557SMatthias Ringwald #endif
44698cd9557SMatthias Ringwald }
44798cd9557SMatthias Ringwald 
44898cd9557SMatthias Ringwald _TINYDIR_FUNC
44998cd9557SMatthias Ringwald int tinydir_next(tinydir_dir *dir)
45098cd9557SMatthias Ringwald {
45198cd9557SMatthias Ringwald 	if (dir == NULL)
45298cd9557SMatthias Ringwald 	{
45398cd9557SMatthias Ringwald 		errno = EINVAL;
45498cd9557SMatthias Ringwald 		return -1;
45598cd9557SMatthias Ringwald 	}
45698cd9557SMatthias Ringwald 	if (!dir->has_next)
45798cd9557SMatthias Ringwald 	{
45898cd9557SMatthias Ringwald 		errno = ENOENT;
45998cd9557SMatthias Ringwald 		return -1;
46098cd9557SMatthias Ringwald 	}
46198cd9557SMatthias Ringwald 
46298cd9557SMatthias Ringwald #ifdef _MSC_VER
46398cd9557SMatthias Ringwald 	if (FindNextFile(dir->_h, &dir->_f) == 0)
46498cd9557SMatthias Ringwald #else
46598cd9557SMatthias Ringwald #ifdef _TINYDIR_USE_READDIR
46698cd9557SMatthias Ringwald 	dir->_e = _tinydir_readdir(dir->_d);
46798cd9557SMatthias Ringwald #else
46898cd9557SMatthias Ringwald 	if (dir->_ep == NULL)
46998cd9557SMatthias Ringwald 	{
47098cd9557SMatthias Ringwald 		return -1;
47198cd9557SMatthias Ringwald 	}
47298cd9557SMatthias Ringwald 	if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
47398cd9557SMatthias Ringwald 	{
47498cd9557SMatthias Ringwald 		return -1;
47598cd9557SMatthias Ringwald 	}
47698cd9557SMatthias Ringwald #endif
47798cd9557SMatthias Ringwald 	if (dir->_e == NULL)
47898cd9557SMatthias Ringwald #endif
47998cd9557SMatthias Ringwald 	{
48098cd9557SMatthias Ringwald 		dir->has_next = 0;
48198cd9557SMatthias Ringwald #ifdef _MSC_VER
48298cd9557SMatthias Ringwald 		if (GetLastError() != ERROR_SUCCESS &&
48398cd9557SMatthias Ringwald 			GetLastError() != ERROR_NO_MORE_FILES)
48498cd9557SMatthias Ringwald 		{
48598cd9557SMatthias Ringwald 			tinydir_close(dir);
48698cd9557SMatthias Ringwald 			errno = EIO;
48798cd9557SMatthias Ringwald 			return -1;
48898cd9557SMatthias Ringwald 		}
48998cd9557SMatthias Ringwald #endif
49098cd9557SMatthias Ringwald 	}
49198cd9557SMatthias Ringwald 
49298cd9557SMatthias Ringwald 	return 0;
49398cd9557SMatthias Ringwald }
49498cd9557SMatthias Ringwald 
49598cd9557SMatthias Ringwald _TINYDIR_FUNC
49698cd9557SMatthias Ringwald int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
49798cd9557SMatthias Ringwald {
49898cd9557SMatthias Ringwald 	if (dir == NULL || file == NULL)
49998cd9557SMatthias Ringwald 	{
50098cd9557SMatthias Ringwald 		errno = EINVAL;
50198cd9557SMatthias Ringwald 		return -1;
50298cd9557SMatthias Ringwald 	}
50398cd9557SMatthias Ringwald #ifdef _MSC_VER
50498cd9557SMatthias Ringwald 	if (dir->_h == INVALID_HANDLE_VALUE)
50598cd9557SMatthias Ringwald #else
50698cd9557SMatthias Ringwald 	if (dir->_e == NULL)
50798cd9557SMatthias Ringwald #endif
50898cd9557SMatthias Ringwald 	{
50998cd9557SMatthias Ringwald 		errno = ENOENT;
51098cd9557SMatthias Ringwald 		return -1;
51198cd9557SMatthias Ringwald 	}
51298cd9557SMatthias Ringwald 	if (_tinydir_strlen(dir->path) +
51398cd9557SMatthias Ringwald 		_tinydir_strlen(
51498cd9557SMatthias Ringwald #ifdef _MSC_VER
51598cd9557SMatthias Ringwald 			dir->_f.cFileName
51698cd9557SMatthias Ringwald #else
51798cd9557SMatthias Ringwald 			dir->_e->d_name
51898cd9557SMatthias Ringwald #endif
51998cd9557SMatthias Ringwald 		) + 1 + _TINYDIR_PATH_EXTRA >=
52098cd9557SMatthias Ringwald 		_TINYDIR_PATH_MAX)
52198cd9557SMatthias Ringwald 	{
52298cd9557SMatthias Ringwald 		/* the path for the file will be too long */
52398cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
52498cd9557SMatthias Ringwald 		return -1;
52598cd9557SMatthias Ringwald 	}
52698cd9557SMatthias Ringwald 	if (_tinydir_strlen(
52798cd9557SMatthias Ringwald #ifdef _MSC_VER
52898cd9557SMatthias Ringwald 			dir->_f.cFileName
52998cd9557SMatthias Ringwald #else
53098cd9557SMatthias Ringwald 			dir->_e->d_name
53198cd9557SMatthias Ringwald #endif
53298cd9557SMatthias Ringwald 		) >= _TINYDIR_FILENAME_MAX)
53398cd9557SMatthias Ringwald 	{
53498cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
53598cd9557SMatthias Ringwald 		return -1;
53698cd9557SMatthias Ringwald 	}
53798cd9557SMatthias Ringwald 
53898cd9557SMatthias Ringwald 	_tinydir_strcpy(file->path, dir->path);
53998cd9557SMatthias Ringwald 	_tinydir_strcat(file->path, TINYDIR_STRING("/"));
54098cd9557SMatthias Ringwald 	_tinydir_strcpy(file->name,
54198cd9557SMatthias Ringwald #ifdef _MSC_VER
54298cd9557SMatthias Ringwald 		dir->_f.cFileName
54398cd9557SMatthias Ringwald #else
54498cd9557SMatthias Ringwald 		dir->_e->d_name
54598cd9557SMatthias Ringwald #endif
54698cd9557SMatthias Ringwald 	);
54798cd9557SMatthias Ringwald 	_tinydir_strcat(file->path, file->name);
54898cd9557SMatthias Ringwald #ifndef _MSC_VER
54998cd9557SMatthias Ringwald #ifdef __MINGW32__
55098cd9557SMatthias Ringwald 	if (_tstat(
55198cd9557SMatthias Ringwald #else
55298cd9557SMatthias Ringwald 	if (stat(
55398cd9557SMatthias Ringwald #endif
55498cd9557SMatthias Ringwald 		file->path, &file->_s) == -1)
55598cd9557SMatthias Ringwald 	{
55698cd9557SMatthias Ringwald 		return -1;
55798cd9557SMatthias Ringwald 	}
55898cd9557SMatthias Ringwald #endif
55998cd9557SMatthias Ringwald 	_tinydir_get_ext(file);
56098cd9557SMatthias Ringwald 
56198cd9557SMatthias Ringwald 	file->is_dir =
56298cd9557SMatthias Ringwald #ifdef _MSC_VER
56398cd9557SMatthias Ringwald 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
56498cd9557SMatthias Ringwald #else
56598cd9557SMatthias Ringwald 		S_ISDIR(file->_s.st_mode);
56698cd9557SMatthias Ringwald #endif
56798cd9557SMatthias Ringwald 	file->is_reg =
56898cd9557SMatthias Ringwald #ifdef _MSC_VER
56998cd9557SMatthias Ringwald 		!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
57098cd9557SMatthias Ringwald 		(
57198cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
57298cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
57398cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
57498cd9557SMatthias Ringwald #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
57598cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
57698cd9557SMatthias Ringwald #endif
57798cd9557SMatthias Ringwald #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
57898cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
57998cd9557SMatthias Ringwald #endif
58098cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
58198cd9557SMatthias Ringwald 			!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
58298cd9557SMatthias Ringwald #else
58398cd9557SMatthias Ringwald 		S_ISREG(file->_s.st_mode);
58498cd9557SMatthias Ringwald #endif
58598cd9557SMatthias Ringwald 
58698cd9557SMatthias Ringwald 	return 0;
58798cd9557SMatthias Ringwald }
58898cd9557SMatthias Ringwald 
58998cd9557SMatthias Ringwald _TINYDIR_FUNC
59098cd9557SMatthias Ringwald int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
59198cd9557SMatthias Ringwald {
59298cd9557SMatthias Ringwald 	if (dir == NULL || file == NULL)
59398cd9557SMatthias Ringwald 	{
59498cd9557SMatthias Ringwald 		errno = EINVAL;
59598cd9557SMatthias Ringwald 		return -1;
59698cd9557SMatthias Ringwald 	}
59798cd9557SMatthias Ringwald 	if (i >= dir->n_files)
59898cd9557SMatthias Ringwald 	{
59998cd9557SMatthias Ringwald 		errno = ENOENT;
60098cd9557SMatthias Ringwald 		return -1;
60198cd9557SMatthias Ringwald 	}
60298cd9557SMatthias Ringwald 
60398cd9557SMatthias Ringwald 	memcpy(file, &dir->_files[i], sizeof(tinydir_file));
60498cd9557SMatthias Ringwald 	_tinydir_get_ext(file);
60598cd9557SMatthias Ringwald 
60698cd9557SMatthias Ringwald 	return 0;
60798cd9557SMatthias Ringwald }
60898cd9557SMatthias Ringwald 
60998cd9557SMatthias Ringwald _TINYDIR_FUNC
61098cd9557SMatthias Ringwald int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
61198cd9557SMatthias Ringwald {
61298cd9557SMatthias Ringwald 	_tinydir_char_t path[_TINYDIR_PATH_MAX];
61398cd9557SMatthias Ringwald 	if (dir == NULL)
61498cd9557SMatthias Ringwald 	{
61598cd9557SMatthias Ringwald 		errno = EINVAL;
61698cd9557SMatthias Ringwald 		return -1;
61798cd9557SMatthias Ringwald 	}
61898cd9557SMatthias Ringwald 	if (i >= dir->n_files || !dir->_files[i].is_dir)
61998cd9557SMatthias Ringwald 	{
62098cd9557SMatthias Ringwald 		errno = ENOENT;
62198cd9557SMatthias Ringwald 		return -1;
62298cd9557SMatthias Ringwald 	}
62398cd9557SMatthias Ringwald 
62498cd9557SMatthias Ringwald 	_tinydir_strcpy(path, dir->_files[i].path);
62598cd9557SMatthias Ringwald 	tinydir_close(dir);
62698cd9557SMatthias Ringwald 	if (tinydir_open_sorted(dir, path) == -1)
62798cd9557SMatthias Ringwald 	{
62898cd9557SMatthias Ringwald 		return -1;
62998cd9557SMatthias Ringwald 	}
63098cd9557SMatthias Ringwald 
63198cd9557SMatthias Ringwald 	return 0;
63298cd9557SMatthias Ringwald }
63398cd9557SMatthias Ringwald 
63498cd9557SMatthias Ringwald /* Open a single file given its path */
63598cd9557SMatthias Ringwald _TINYDIR_FUNC
63698cd9557SMatthias Ringwald int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
63798cd9557SMatthias Ringwald {
63898cd9557SMatthias Ringwald 	tinydir_dir dir;
63998cd9557SMatthias Ringwald 	int result = 0;
64098cd9557SMatthias Ringwald 	int found = 0;
64198cd9557SMatthias Ringwald 	_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
64298cd9557SMatthias Ringwald 	_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
64398cd9557SMatthias Ringwald 	_tinydir_char_t *dir_name;
64498cd9557SMatthias Ringwald 	_tinydir_char_t *base_name;
64598cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
64698cd9557SMatthias Ringwald 	_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
64798cd9557SMatthias Ringwald 	_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
64898cd9557SMatthias Ringwald #endif
64998cd9557SMatthias Ringwald 
65098cd9557SMatthias Ringwald 	if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
65198cd9557SMatthias Ringwald 	{
65298cd9557SMatthias Ringwald 		errno = EINVAL;
65398cd9557SMatthias Ringwald 		return -1;
65498cd9557SMatthias Ringwald 	}
65598cd9557SMatthias Ringwald 	if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
65698cd9557SMatthias Ringwald 	{
65798cd9557SMatthias Ringwald 		errno = ENAMETOOLONG;
65898cd9557SMatthias Ringwald 		return -1;
65998cd9557SMatthias Ringwald 	}
66098cd9557SMatthias Ringwald 
66198cd9557SMatthias Ringwald 	/* Get the parent path */
66298cd9557SMatthias Ringwald #if (defined _MSC_VER || defined __MINGW32__)
66398cd9557SMatthias Ringwald #if ((defined _MSC_VER) && (_MSC_VER >= 1400))
664*ec8ca29fSMatthias Ringwald 		errno = _tsplitpath_s(
66598cd9557SMatthias Ringwald 			path,
66698cd9557SMatthias Ringwald 			drive_buf, _TINYDIR_DRIVE_MAX,
66798cd9557SMatthias Ringwald 			dir_name_buf, _TINYDIR_FILENAME_MAX,
66898cd9557SMatthias Ringwald 			file_name_buf, _TINYDIR_FILENAME_MAX,
66998cd9557SMatthias Ringwald 			ext_buf, _TINYDIR_FILENAME_MAX);
67098cd9557SMatthias Ringwald #else
67198cd9557SMatthias Ringwald 		_tsplitpath(
67298cd9557SMatthias Ringwald 			path,
67398cd9557SMatthias Ringwald 			drive_buf,
67498cd9557SMatthias Ringwald 			dir_name_buf,
67598cd9557SMatthias Ringwald 			file_name_buf,
67698cd9557SMatthias Ringwald 			ext_buf);
67798cd9557SMatthias Ringwald #endif
67898cd9557SMatthias Ringwald 
679*ec8ca29fSMatthias Ringwald if (errno)
680*ec8ca29fSMatthias Ringwald {
681*ec8ca29fSMatthias Ringwald 	return -1;
682*ec8ca29fSMatthias Ringwald }
683*ec8ca29fSMatthias Ringwald 
68498cd9557SMatthias Ringwald /* _splitpath_s not work fine with only filename and widechar support */
68598cd9557SMatthias Ringwald #ifdef _UNICODE
68698cd9557SMatthias Ringwald 		if (drive_buf[0] == L'\xFEFE')
68798cd9557SMatthias Ringwald 			drive_buf[0] = '\0';
68898cd9557SMatthias Ringwald 		if (dir_name_buf[0] == L'\xFEFE')
68998cd9557SMatthias Ringwald 			dir_name_buf[0] = '\0';
69098cd9557SMatthias Ringwald #endif
69198cd9557SMatthias Ringwald 
69298cd9557SMatthias Ringwald 	/* Emulate the behavior of dirname by returning "." for dir name if it's
69398cd9557SMatthias Ringwald 	empty */
69498cd9557SMatthias Ringwald 	if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
69598cd9557SMatthias Ringwald 	{
69698cd9557SMatthias Ringwald 		_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
69798cd9557SMatthias Ringwald 	}
69898cd9557SMatthias Ringwald 	/* Concatenate the drive letter and dir name to form full dir name */
69998cd9557SMatthias Ringwald 	_tinydir_strcat(drive_buf, dir_name_buf);
70098cd9557SMatthias Ringwald 	dir_name = drive_buf;
70198cd9557SMatthias Ringwald 	/* Concatenate the file name and extension to form base name */
70298cd9557SMatthias Ringwald 	_tinydir_strcat(file_name_buf, ext_buf);
70398cd9557SMatthias Ringwald 	base_name = file_name_buf;
70498cd9557SMatthias Ringwald #else
70598cd9557SMatthias Ringwald 	_tinydir_strcpy(dir_name_buf, path);
70698cd9557SMatthias Ringwald 	dir_name = dirname(dir_name_buf);
70798cd9557SMatthias Ringwald 	_tinydir_strcpy(file_name_buf, path);
70898cd9557SMatthias Ringwald 	base_name =basename(file_name_buf);
70998cd9557SMatthias Ringwald #endif
71098cd9557SMatthias Ringwald 
71198cd9557SMatthias Ringwald 	/* Open the parent directory */
71298cd9557SMatthias Ringwald 	if (tinydir_open(&dir, dir_name) == -1)
71398cd9557SMatthias Ringwald 	{
71498cd9557SMatthias Ringwald 		return -1;
71598cd9557SMatthias Ringwald 	}
71698cd9557SMatthias Ringwald 
71798cd9557SMatthias Ringwald 	/* Read through the parent directory and look for the file */
71898cd9557SMatthias Ringwald 	while (dir.has_next)
71998cd9557SMatthias Ringwald 	{
72098cd9557SMatthias Ringwald 		if (tinydir_readfile(&dir, file) == -1)
72198cd9557SMatthias Ringwald 		{
72298cd9557SMatthias Ringwald 			result = -1;
72398cd9557SMatthias Ringwald 			goto bail;
72498cd9557SMatthias Ringwald 		}
72598cd9557SMatthias Ringwald 		if (_tinydir_strcmp(file->name, base_name) == 0)
72698cd9557SMatthias Ringwald 		{
72798cd9557SMatthias Ringwald 			/* File found */
72898cd9557SMatthias Ringwald 			found = 1;
72998cd9557SMatthias Ringwald 			break;
73098cd9557SMatthias Ringwald 		}
73198cd9557SMatthias Ringwald 		tinydir_next(&dir);
73298cd9557SMatthias Ringwald 	}
73398cd9557SMatthias Ringwald 	if (!found)
73498cd9557SMatthias Ringwald 	{
73598cd9557SMatthias Ringwald 		result = -1;
73698cd9557SMatthias Ringwald 		errno = ENOENT;
73798cd9557SMatthias Ringwald 	}
73898cd9557SMatthias Ringwald 
73998cd9557SMatthias Ringwald bail:
74098cd9557SMatthias Ringwald 	tinydir_close(&dir);
74198cd9557SMatthias Ringwald 	return result;
74298cd9557SMatthias Ringwald }
74398cd9557SMatthias Ringwald 
74498cd9557SMatthias Ringwald _TINYDIR_FUNC
74598cd9557SMatthias Ringwald void _tinydir_get_ext(tinydir_file *file)
74698cd9557SMatthias Ringwald {
74798cd9557SMatthias Ringwald 	_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
74898cd9557SMatthias Ringwald 	if (period == NULL)
74998cd9557SMatthias Ringwald 	{
75098cd9557SMatthias Ringwald 		file->extension = &(file->name[_tinydir_strlen(file->name)]);
75198cd9557SMatthias Ringwald 	}
75298cd9557SMatthias Ringwald 	else
75398cd9557SMatthias Ringwald 	{
75498cd9557SMatthias Ringwald 		file->extension = period + 1;
75598cd9557SMatthias Ringwald 	}
75698cd9557SMatthias Ringwald }
75798cd9557SMatthias Ringwald 
75898cd9557SMatthias Ringwald _TINYDIR_FUNC
75998cd9557SMatthias Ringwald int _tinydir_file_cmp(const void *a, const void *b)
76098cd9557SMatthias Ringwald {
76198cd9557SMatthias Ringwald 	const tinydir_file *fa = (const tinydir_file *)a;
76298cd9557SMatthias Ringwald 	const tinydir_file *fb = (const tinydir_file *)b;
76398cd9557SMatthias Ringwald 	if (fa->is_dir != fb->is_dir)
76498cd9557SMatthias Ringwald 	{
76598cd9557SMatthias Ringwald 		return -(fa->is_dir - fb->is_dir);
76698cd9557SMatthias Ringwald 	}
76798cd9557SMatthias Ringwald 	return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
76898cd9557SMatthias Ringwald }
76998cd9557SMatthias Ringwald 
77098cd9557SMatthias Ringwald #ifndef _MSC_VER
77198cd9557SMatthias Ringwald #ifndef _TINYDIR_USE_READDIR
77298cd9557SMatthias Ringwald /*
77398cd9557SMatthias Ringwald The following authored by Ben Hutchings <[email protected]>
77498cd9557SMatthias Ringwald from https://womble.decadent.org.uk/readdir_r-advisory.html
77598cd9557SMatthias Ringwald */
77698cd9557SMatthias Ringwald /* Calculate the required buffer size (in bytes) for directory      *
77798cd9557SMatthias Ringwald * entries read from the given directory handle.  Return -1 if this  *
77898cd9557SMatthias Ringwald * this cannot be done.                                              *
77998cd9557SMatthias Ringwald *                                                                   *
78098cd9557SMatthias Ringwald * This code does not trust values of NAME_MAX that are less than    *
78198cd9557SMatthias Ringwald * 255, since some systems (including at least HP-UX) incorrectly    *
78298cd9557SMatthias Ringwald * define it to be a smaller value.                                  */
78398cd9557SMatthias Ringwald _TINYDIR_FUNC
78498cd9557SMatthias Ringwald size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
78598cd9557SMatthias Ringwald {
78698cd9557SMatthias Ringwald 	long name_max;
78798cd9557SMatthias Ringwald 	size_t name_end;
78898cd9557SMatthias Ringwald 	/* parameter may be unused */
78998cd9557SMatthias Ringwald 	(void)dirp;
79098cd9557SMatthias Ringwald 
79198cd9557SMatthias Ringwald #if defined _TINYDIR_USE_FPATHCONF
79298cd9557SMatthias Ringwald 	name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
79398cd9557SMatthias Ringwald 	if (name_max == -1)
79498cd9557SMatthias Ringwald #if defined(NAME_MAX)
79598cd9557SMatthias Ringwald 		name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
79698cd9557SMatthias Ringwald #else
79798cd9557SMatthias Ringwald 		return (size_t)(-1);
79898cd9557SMatthias Ringwald #endif
79998cd9557SMatthias Ringwald #elif defined(NAME_MAX)
80098cd9557SMatthias Ringwald  	name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
80198cd9557SMatthias Ringwald #else
80298cd9557SMatthias Ringwald #error "buffer size for readdir_r cannot be determined"
80398cd9557SMatthias Ringwald #endif
80498cd9557SMatthias Ringwald 	name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
80598cd9557SMatthias Ringwald 	return (name_end > sizeof(struct _tinydir_dirent) ?
80698cd9557SMatthias Ringwald 		name_end : sizeof(struct _tinydir_dirent));
80798cd9557SMatthias Ringwald }
80898cd9557SMatthias Ringwald #endif
80998cd9557SMatthias Ringwald #endif
81098cd9557SMatthias Ringwald 
81198cd9557SMatthias Ringwald #ifdef __cplusplus
81298cd9557SMatthias Ringwald }
81398cd9557SMatthias Ringwald #endif
81498cd9557SMatthias Ringwald 
81598cd9557SMatthias Ringwald # if defined (_MSC_VER)
81698cd9557SMatthias Ringwald # pragma warning(pop)
81798cd9557SMatthias Ringwald # endif
81898cd9557SMatthias Ringwald 
81998cd9557SMatthias Ringwald #endif
820