Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tinydir.h Source File

tinydir.h

00001 /*
00002 Copyright (c) 2013-2017, tinydir authors:
00003 - Cong Xu
00004 - Lautis Sun
00005 - Baudouin Feildel
00006 - Andargor <andargor@yahoo.com>
00007 All rights reserved.
00008 
00009 Redistribution and use in source and binary forms, with or without
00010 modification, are permitted provided that the following conditions are met:
00011 
00012 1. Redistributions of source code must retain the above copyright notice, this
00013    list of conditions and the following disclaimer.
00014 2. Redistributions in binary form must reproduce the above copyright notice,
00015    this list of conditions and the following disclaimer in the documentation
00016    and/or other materials provided with the distribution.
00017 
00018 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00019 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00020 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00022 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00023 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00024 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00025 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00027 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028 */
00029 #ifndef TINYDIR_H
00030 #define TINYDIR_H
00031 
00032 #ifdef __cplusplus
00033 extern "C" {
00034 #endif
00035 
00036 #if ((defined _UNICODE) && !(defined UNICODE))
00037 #define UNICODE
00038 #endif
00039 
00040 #if ((defined UNICODE) && !(defined _UNICODE))
00041 #define _UNICODE
00042 #endif
00043 
00044 #include <errno.h>
00045 #include <stdlib.h>
00046 #include <string.h>
00047 #ifdef _MSC_VER
00048 # define WIN32_LEAN_AND_MEAN
00049 # include <windows.h>
00050 # include <tchar.h>
00051 # pragma warning(push)
00052 # pragma warning (disable : 4996)
00053 #else
00054 # include <dirent.h>
00055 # include <libgen.h>
00056 # include <sys/stat.h>
00057 # include <stddef.h>
00058 #endif
00059 #ifdef __MINGW32__
00060 # include <tchar.h>
00061 #endif
00062 
00063 
00064 /* types */
00065 
00066 /* Windows UNICODE wide character support */
00067 #if defined _MSC_VER || defined __MINGW32__
00068 #define _tinydir_char_t TCHAR
00069 #define TINYDIR_STRING(s) _TEXT(s)
00070 #define _tinydir_strlen _tcslen
00071 #define _tinydir_strcpy _tcscpy
00072 #define _tinydir_strcat _tcscat
00073 #define _tinydir_strcmp _tcscmp
00074 #define _tinydir_strrchr _tcsrchr
00075 #define _tinydir_strncmp _tcsncmp
00076 #else
00077 #define _tinydir_char_t char
00078 #define TINYDIR_STRING(s) s
00079 #define _tinydir_strlen strlen
00080 #define _tinydir_strcpy strcpy
00081 #define _tinydir_strcat strcat
00082 #define _tinydir_strcmp strcmp
00083 #define _tinydir_strrchr strrchr
00084 #define _tinydir_strncmp strncmp
00085 #endif
00086 
00087 #if (defined _MSC_VER || defined __MINGW32__)
00088 #include <windows.h>
00089 #define _TINYDIR_PATH_MAX MAX_PATH
00090 #elif defined  __linux__
00091 #include <linux/limits.h>
00092 #define _TINYDIR_PATH_MAX PATH_MAX
00093 #else
00094 #define _TINYDIR_PATH_MAX 4096
00095 #endif
00096 
00097 #ifdef _MSC_VER
00098 /* extra chars for the "\\*" mask */
00099 # define _TINYDIR_PATH_EXTRA 2
00100 #else
00101 # define _TINYDIR_PATH_EXTRA 0
00102 #endif
00103 
00104 #define _TINYDIR_FILENAME_MAX 256
00105 
00106 #if (defined _MSC_VER || defined __MINGW32__)
00107 #define _TINYDIR_DRIVE_MAX 3
00108 #endif
00109 
00110 #ifdef _MSC_VER
00111 # define _TINYDIR_FUNC static __inline
00112 #elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
00113 # define _TINYDIR_FUNC static __inline__
00114 #else
00115 # define _TINYDIR_FUNC static inline
00116 #endif
00117 
00118 /* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
00119 #ifdef TINYDIR_USE_READDIR_R
00120 
00121 /* readdir_r is a POSIX-only function, and may not be available under various
00122  * environments/settings, e.g. MinGW. Use readdir fallback */
00123 #if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
00124     _POSIX_SOURCE
00125 # define _TINYDIR_HAS_READDIR_R
00126 #endif
00127 #if _POSIX_C_SOURCE >= 200112L
00128 # define _TINYDIR_HAS_FPATHCONF
00129 # include <unistd.h>
00130 #endif
00131 #if _BSD_SOURCE || _SVID_SOURCE || \
00132     (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
00133 # define _TINYDIR_HAS_DIRFD
00134 # include <sys/types.h>
00135 #endif
00136 #if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
00137     defined _PC_NAME_MAX
00138 # define _TINYDIR_USE_FPATHCONF
00139 #endif
00140 #if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
00141     !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
00142 # define _TINYDIR_USE_READDIR
00143 #endif
00144 
00145 /* Use readdir by default */
00146 #else
00147 # define _TINYDIR_USE_READDIR
00148 #endif
00149 
00150 /* MINGW32 has two versions of dirent, ASCII and UNICODE*/
00151 #ifndef _MSC_VER
00152 #if (defined __MINGW32__) && (defined _UNICODE)
00153 #define _TINYDIR_DIR _WDIR
00154 #define _tinydir_dirent _wdirent
00155 #define _tinydir_opendir _wopendir
00156 #define _tinydir_readdir _wreaddir
00157 #define _tinydir_closedir _wclosedir
00158 #else
00159 #define _TINYDIR_DIR DIR
00160 #define _tinydir_dirent dirent
00161 #define _tinydir_opendir opendir
00162 #define _tinydir_readdir readdir
00163 #define _tinydir_closedir closedir
00164 #endif
00165 #endif
00166 
00167 /* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
00168 #if    defined(_TINYDIR_MALLOC) &&  defined(_TINYDIR_FREE)
00169 #elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
00170 #else
00171 #error "Either define both alloc and free or none of them!"
00172 #endif
00173 
00174 #if !defined(_TINYDIR_MALLOC)
00175     #define _TINYDIR_MALLOC(_size) malloc(_size)
00176     #define _TINYDIR_FREE(_ptr)    free(_ptr)
00177 #endif /* !defined(_TINYDIR_MALLOC) */
00178 
00179 typedef struct tinydir_file
00180 {
00181     _tinydir_char_t path[_TINYDIR_PATH_MAX];
00182     _tinydir_char_t name[_TINYDIR_FILENAME_MAX];
00183     _tinydir_char_t *extension;
00184     int is_dir;
00185     int is_reg;
00186 
00187 #ifndef _MSC_VER
00188 #ifdef __MINGW32__
00189     struct _stat _s;
00190 #else
00191     struct stat _s;
00192 #endif
00193 #endif
00194 } tinydir_file;
00195 
00196 typedef struct tinydir_dir
00197 {
00198     _tinydir_char_t path[_TINYDIR_PATH_MAX];
00199     int has_next;
00200     size_t n_files;
00201 
00202     tinydir_file *_files;
00203 #ifdef _MSC_VER
00204     HANDLE _h;
00205     WIN32_FIND_DATA _f;
00206 #else
00207     _TINYDIR_DIR *_d;
00208     struct _tinydir_dirent *_e;
00209 #ifndef _TINYDIR_USE_READDIR
00210     struct _tinydir_dirent *_ep;
00211 #endif
00212 #endif
00213 } tinydir_dir;
00214 
00215 
00216 /* declarations */
00217 
00218 _TINYDIR_FUNC
00219 int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
00220 _TINYDIR_FUNC
00221 int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
00222 _TINYDIR_FUNC
00223 void tinydir_close(tinydir_dir *dir);
00224 
00225 _TINYDIR_FUNC
00226 int tinydir_next(tinydir_dir *dir);
00227 _TINYDIR_FUNC
00228 int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
00229 _TINYDIR_FUNC
00230 int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
00231 _TINYDIR_FUNC
00232 int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
00233 
00234 _TINYDIR_FUNC
00235 int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
00236 _TINYDIR_FUNC
00237 void _tinydir_get_ext(tinydir_file *file);
00238 _TINYDIR_FUNC
00239 int _tinydir_file_cmp(const void *a, const void *b);
00240 #ifndef _MSC_VER
00241 #ifndef _TINYDIR_USE_READDIR
00242 _TINYDIR_FUNC
00243 size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
00244 #endif
00245 #endif
00246 
00247 
00248 /* definitions*/
00249 
00250 _TINYDIR_FUNC
00251 int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
00252 {
00253 #ifndef _MSC_VER
00254 #ifndef _TINYDIR_USE_READDIR
00255     int error;
00256     int size;   /* using int size */
00257 #endif
00258 #else
00259     _tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
00260 #endif
00261     _tinydir_char_t *pathp;
00262 
00263     if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
00264     {
00265         errno = EINVAL;
00266         return -1;
00267     }
00268     if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
00269     {
00270         errno = ENAMETOOLONG;
00271         return -1;
00272     }
00273 
00274     /* initialise dir */
00275     dir->_files = NULL;
00276 #ifdef _MSC_VER
00277     dir->_h = INVALID_HANDLE_VALUE;
00278 #else
00279     dir->_d = NULL;
00280 #ifndef _TINYDIR_USE_READDIR
00281     dir->_ep = NULL;
00282 #endif
00283 #endif
00284     tinydir_close(dir);
00285 
00286     _tinydir_strcpy(dir->path, path);
00287     /* Remove trailing slashes */
00288     pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
00289     while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
00290     {
00291         *pathp = TINYDIR_STRING('\0');
00292         pathp++;
00293     }
00294 #ifdef _MSC_VER
00295     _tinydir_strcpy(path_buf, dir->path);
00296     _tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
00297 #if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
00298     dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
00299 #else
00300     dir->_h = FindFirstFile(path_buf, &dir->_f);
00301 #endif
00302     if (dir->_h == INVALID_HANDLE_VALUE)
00303     {
00304         errno = ENOENT;
00305 #else
00306     dir->_d = _tinydir_opendir(path);
00307     if (dir->_d == NULL)
00308     {
00309 #endif
00310         goto bail;
00311     }
00312 
00313     /* read first file */
00314     dir->has_next = 1;
00315 #ifndef _MSC_VER
00316 #ifdef _TINYDIR_USE_READDIR
00317     dir->_e = _tinydir_readdir(dir->_d);
00318 #else
00319     /* allocate dirent buffer for readdir_r */
00320     size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
00321     if (size == -1) return -1;
00322     dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
00323     if (dir->_ep == NULL) return -1;
00324 
00325     error = readdir_r(dir->_d, dir->_ep, &dir->_e);
00326     if (error != 0) return -1;
00327 #endif
00328     if (dir->_e == NULL)
00329     {
00330         dir->has_next = 0;
00331     }
00332 #endif
00333 
00334     return 0;
00335 
00336 bail:
00337     tinydir_close(dir);
00338     return -1;
00339 }
00340 
00341 _TINYDIR_FUNC
00342 int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
00343 {
00344     /* Count the number of files first, to pre-allocate the files array */
00345     size_t n_files = 0;
00346     if (tinydir_open(dir, path) == -1)
00347     {
00348         return -1;
00349     }
00350     while (dir->has_next)
00351     {
00352         n_files++;
00353         if (tinydir_next(dir) == -1)
00354         {
00355             goto bail;
00356         }
00357     }
00358     tinydir_close(dir);
00359 
00360     if (tinydir_open(dir, path) == -1)
00361     {
00362         return -1;
00363     }
00364 
00365     dir->n_files = 0;
00366     dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
00367     if (dir->_files == NULL)
00368     {
00369         goto bail;
00370     }
00371     while (dir->has_next)
00372     {
00373         tinydir_file *p_file;
00374         dir->n_files++;
00375 
00376         p_file = &dir->_files[dir->n_files - 1];
00377         if (tinydir_readfile(dir, p_file) == -1)
00378         {
00379             goto bail;
00380         }
00381 
00382         if (tinydir_next(dir) == -1)
00383         {
00384             goto bail;
00385         }
00386 
00387         /* Just in case the number of files has changed between the first and
00388         second reads, terminate without writing into unallocated memory */
00389         if (dir->n_files == n_files)
00390         {
00391             break;
00392         }
00393     }
00394 
00395     qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
00396 
00397     return 0;
00398 
00399 bail:
00400     tinydir_close(dir);
00401     return -1;
00402 }
00403 
00404 _TINYDIR_FUNC
00405 void tinydir_close(tinydir_dir *dir)
00406 {
00407     if (dir == NULL)
00408     {
00409         return;
00410     }
00411 
00412     memset(dir->path, 0, sizeof(dir->path));
00413     dir->has_next = 0;
00414     dir->n_files = 0;
00415     _TINYDIR_FREE(dir->_files);
00416     dir->_files = NULL;
00417 #ifdef _MSC_VER
00418     if (dir->_h != INVALID_HANDLE_VALUE)
00419     {
00420         FindClose(dir->_h);
00421     }
00422     dir->_h = INVALID_HANDLE_VALUE;
00423 #else
00424     if (dir->_d)
00425     {
00426         _tinydir_closedir(dir->_d);
00427     }
00428     dir->_d = NULL;
00429     dir->_e = NULL;
00430 #ifndef _TINYDIR_USE_READDIR
00431     _TINYDIR_FREE(dir->_ep);
00432     dir->_ep = NULL;
00433 #endif
00434 #endif
00435 }
00436 
00437 _TINYDIR_FUNC
00438 int tinydir_next(tinydir_dir *dir)
00439 {
00440     if (dir == NULL)
00441     {
00442         errno = EINVAL;
00443         return -1;
00444     }
00445     if (!dir->has_next)
00446     {
00447         errno = ENOENT;
00448         return -1;
00449     }
00450 
00451 #ifdef _MSC_VER
00452     if (FindNextFile(dir->_h, &dir->_f) == 0)
00453 #else
00454 #ifdef _TINYDIR_USE_READDIR
00455     dir->_e = _tinydir_readdir(dir->_d);
00456 #else
00457     if (dir->_ep == NULL)
00458     {
00459         return -1;
00460     }
00461     if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
00462     {
00463         return -1;
00464     }
00465 #endif
00466     if (dir->_e == NULL)
00467 #endif
00468     {
00469         dir->has_next = 0;
00470 #ifdef _MSC_VER
00471         if (GetLastError() != ERROR_SUCCESS &&
00472             GetLastError() != ERROR_NO_MORE_FILES)
00473         {
00474             tinydir_close(dir);
00475             errno = EIO;
00476             return -1;
00477         }
00478 #endif
00479     }
00480 
00481     return 0;
00482 }
00483 
00484 _TINYDIR_FUNC
00485 int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
00486 {
00487     if (dir == NULL || file == NULL)
00488     {
00489         errno = EINVAL;
00490         return -1;
00491     }
00492 #ifdef _MSC_VER
00493     if (dir->_h == INVALID_HANDLE_VALUE)
00494 #else
00495     if (dir->_e == NULL)
00496 #endif
00497     {
00498         errno = ENOENT;
00499         return -1;
00500     }
00501     if (_tinydir_strlen(dir->path) +
00502         _tinydir_strlen(
00503 #ifdef _MSC_VER
00504             dir->_f.cFileName
00505 #else
00506             dir->_e->d_name
00507 #endif
00508         ) + 1 + _TINYDIR_PATH_EXTRA >=
00509         _TINYDIR_PATH_MAX)
00510     {
00511         /* the path for the file will be too long */
00512         errno = ENAMETOOLONG;
00513         return -1;
00514     }
00515     if (_tinydir_strlen(
00516 #ifdef _MSC_VER
00517             dir->_f.cFileName
00518 #else
00519             dir->_e->d_name
00520 #endif
00521         ) >= _TINYDIR_FILENAME_MAX)
00522     {
00523         errno = ENAMETOOLONG;
00524         return -1;
00525     }
00526 
00527     _tinydir_strcpy(file->path, dir->path);
00528     _tinydir_strcat(file->path, TINYDIR_STRING("/"));
00529     _tinydir_strcpy(file->name,
00530 #ifdef _MSC_VER
00531         dir->_f.cFileName
00532 #else
00533         dir->_e->d_name
00534 #endif
00535     );
00536     _tinydir_strcat(file->path, file->name);
00537 #ifndef _MSC_VER
00538 #ifdef __MINGW32__
00539     if (_tstat(
00540 #else
00541     if (stat(
00542 #endif
00543         file->path, &file->_s) == -1)
00544     {
00545         return -1;
00546     }
00547 #endif
00548     _tinydir_get_ext(file);
00549 
00550     file->is_dir =
00551 #ifdef _MSC_VER
00552         !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
00553 #else
00554         S_ISDIR(file->_s.st_mode);
00555 #endif
00556     file->is_reg =
00557 #ifdef _MSC_VER
00558         !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
00559         (
00560             !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
00561             !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
00562             !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
00563 #ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
00564             !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
00565 #endif
00566 #ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
00567             !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
00568 #endif
00569             !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
00570             !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
00571 #else
00572         S_ISREG(file->_s.st_mode);
00573 #endif
00574 
00575     return 0;
00576 }
00577 
00578 _TINYDIR_FUNC
00579 int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
00580 {
00581     if (dir == NULL || file == NULL)
00582     {
00583         errno = EINVAL;
00584         return -1;
00585     }
00586     if (i >= dir->n_files)
00587     {
00588         errno = ENOENT;
00589         return -1;
00590     }
00591 
00592     memcpy(file, &dir->_files[i], sizeof(tinydir_file));
00593     _tinydir_get_ext(file);
00594 
00595     return 0;
00596 }
00597 
00598 _TINYDIR_FUNC
00599 int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
00600 {
00601     _tinydir_char_t path[_TINYDIR_PATH_MAX];
00602     if (dir == NULL)
00603     {
00604         errno = EINVAL;
00605         return -1;
00606     }
00607     if (i >= dir->n_files || !dir->_files[i].is_dir)
00608     {
00609         errno = ENOENT;
00610         return -1;
00611     }
00612 
00613     _tinydir_strcpy(path, dir->_files[i].path);
00614     tinydir_close(dir);
00615     if (tinydir_open_sorted(dir, path) == -1)
00616     {
00617         return -1;
00618     }
00619 
00620     return 0;
00621 }
00622 
00623 /* Open a single file given its path */
00624 _TINYDIR_FUNC
00625 int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
00626 {
00627     tinydir_dir dir;
00628     int result = 0;
00629     int found = 0;
00630     _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
00631     _tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
00632     _tinydir_char_t *dir_name;
00633     _tinydir_char_t *base_name;
00634 #if (defined _MSC_VER || defined __MINGW32__)
00635     _tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
00636     _tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
00637 #endif
00638 
00639     if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
00640     {
00641         errno = EINVAL;
00642         return -1;
00643     }
00644     if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
00645     {
00646         errno = ENAMETOOLONG;
00647         return -1;
00648     }
00649 
00650     /* Get the parent path */
00651 #if (defined _MSC_VER || defined __MINGW32__)
00652 #if ((defined _MSC_VER) && (_MSC_VER >= 1400))
00653         _tsplitpath_s(
00654             path,
00655             drive_buf, _TINYDIR_DRIVE_MAX,
00656             dir_name_buf, _TINYDIR_FILENAME_MAX,
00657             file_name_buf, _TINYDIR_FILENAME_MAX,
00658             ext_buf, _TINYDIR_FILENAME_MAX);
00659 #else
00660         _tsplitpath(
00661             path,
00662             drive_buf,
00663             dir_name_buf,
00664             file_name_buf,
00665             ext_buf);
00666 #endif
00667 
00668 /* _splitpath_s not work fine with only filename and widechar support */
00669 #ifdef _UNICODE
00670         if (drive_buf[0] == L'\xFEFE')
00671             drive_buf[0] = '\0';
00672         if (dir_name_buf[0] == L'\xFEFE')
00673             dir_name_buf[0] = '\0';
00674 #endif
00675 
00676     if (errno)
00677     {
00678         errno = EINVAL;
00679         return -1;
00680     }
00681     /* Emulate the behavior of dirname by returning "." for dir name if it's
00682     empty */
00683     if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
00684     {
00685         _tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
00686     }
00687     /* Concatenate the drive letter and dir name to form full dir name */
00688     _tinydir_strcat(drive_buf, dir_name_buf);
00689     dir_name = drive_buf;
00690     /* Concatenate the file name and extension to form base name */
00691     _tinydir_strcat(file_name_buf, ext_buf);
00692     base_name = file_name_buf;
00693 #else
00694     _tinydir_strcpy(dir_name_buf, path);
00695     dir_name = dirname(dir_name_buf);
00696     _tinydir_strcpy(file_name_buf, path);
00697     base_name =basename(file_name_buf);
00698 #endif
00699 
00700     /* Open the parent directory */
00701     if (tinydir_open(&dir, dir_name) == -1)
00702     {
00703         return -1;
00704     }
00705 
00706     /* Read through the parent directory and look for the file */
00707     while (dir.has_next)
00708     {
00709         if (tinydir_readfile(&dir, file) == -1)
00710         {
00711             result = -1;
00712             goto bail;
00713         }
00714         if (_tinydir_strcmp(file->name, base_name) == 0)
00715         {
00716             /* File found */
00717             found = 1;
00718             break;
00719         }
00720         tinydir_next(&dir);
00721     }
00722     if (!found)
00723     {
00724         result = -1;
00725         errno = ENOENT;
00726     }
00727 
00728 bail:
00729     tinydir_close(&dir);
00730     return result;
00731 }
00732 
00733 _TINYDIR_FUNC
00734 void _tinydir_get_ext(tinydir_file *file)
00735 {
00736     _tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
00737     if (period == NULL)
00738     {
00739         file->extension = &(file->name[_tinydir_strlen(file->name)]);
00740     }
00741     else
00742     {
00743         file->extension = period + 1;
00744     }
00745 }
00746 
00747 _TINYDIR_FUNC
00748 int _tinydir_file_cmp(const void *a, const void *b)
00749 {
00750     const tinydir_file *fa = (const tinydir_file *)a;
00751     const tinydir_file *fb = (const tinydir_file *)b;
00752     if (fa->is_dir != fb->is_dir)
00753     {
00754         return -(fa->is_dir - fb->is_dir);
00755     }
00756     return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
00757 }
00758 
00759 #ifndef _MSC_VER
00760 #ifndef _TINYDIR_USE_READDIR
00761 /*
00762 The following authored by Ben Hutchings <ben@decadent.org.uk>
00763 from https://womble.decadent.org.uk/readdir_r-advisory.html
00764 */
00765 /* Calculate the required buffer size (in bytes) for directory      *
00766 * entries read from the given directory handle.  Return -1 if this  *
00767 * this cannot be done.                                              *
00768 *                                                                   *
00769 * This code does not trust values of NAME_MAX that are less than    *
00770 * 255, since some systems (including at least HP-UX) incorrectly    *
00771 * define it to be a smaller value.                                  */
00772 _TINYDIR_FUNC
00773 size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
00774 {
00775     long name_max;
00776     size_t name_end;
00777     /* parameter may be unused */
00778     (void)dirp;
00779 
00780 #if defined _TINYDIR_USE_FPATHCONF
00781     name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00782     if (name_max == -1)
00783 #if defined(NAME_MAX)
00784         name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
00785 #else
00786         return (size_t)(-1);
00787 #endif
00788 #elif defined(NAME_MAX)
00789     name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
00790 #else
00791 #error "buffer size for readdir_r cannot be determined"
00792 #endif
00793     name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
00794     return (name_end > sizeof(struct _tinydir_dirent) ?
00795         name_end : sizeof(struct _tinydir_dirent));
00796 }
00797 #endif
00798 #endif
00799 
00800 #ifdef __cplusplus
00801 }
00802 #endif
00803 
00804 # if defined (_MSC_VER)
00805 # pragma warning(pop)
00806 # endif
00807 
00808 #endif