13 #if defined(__clang__) 14 # pragma clang diagnostic ignored "-Wunused-function" 15 #elif defined(_MSC_VER) 16 # pragma warning(disable:4505) 17 #elif defined(__GNUC__) 18 # pragma GCC diagnostic ignored "-Wunused-function" 25 #ifndef WIN32_LEAN_AND_MEAN 26 # define WIN32_LEAN_AND_MEAN 36 #include <sys/types.h> 42 #define _DIRENT_HAVE_D_TYPE 45 #define _DIRENT_HAVE_D_NAMLEN 48 #if !defined(FILE_ATTRIBUTE_DEVICE) 49 # define FILE_ATTRIBUTE_DEVICE 0x40 54 # define S_IFMT _S_IFMT 59 # define S_IFDIR _S_IFDIR 64 # define S_IFCHR _S_IFCHR 68 #if !defined(S_IFFIFO) 69 # define S_IFFIFO _S_IFFIFO 74 # define S_IFREG _S_IFREG 79 # define S_IREAD _S_IREAD 83 #if !defined(S_IWRITE) 84 # define S_IWRITE _S_IWRITE 89 # define S_IEXEC _S_IEXEC 94 # define S_IFIFO _S_IFIFO 103 #if !defined(S_IFLNK) 108 #if !defined(S_IFSOCK) 113 #if !defined(S_IRUSR) 114 # define S_IRUSR S_IREAD 118 #if !defined(S_IWUSR) 119 # define S_IWUSR S_IWRITE 123 #if !defined(S_IXUSR) 128 #if !defined(S_IRGRP) 133 #if !defined(S_IWGRP) 138 #if !defined(S_IXGRP) 143 #if !defined(S_IROTH) 148 #if !defined(S_IWOTH) 153 #if !defined(S_IXOTH) 158 #if !defined(PATH_MAX) 159 # define PATH_MAX MAX_PATH 161 #if !defined(FILENAME_MAX) 162 # define FILENAME_MAX MAX_PATH 164 #if !defined(NAME_MAX) 165 # define NAME_MAX FILENAME_MAX 170 #define DT_REG S_IFREG 171 #define DT_DIR S_IFDIR 172 #define DT_FIFO S_IFIFO 173 #define DT_SOCK S_IFSOCK 174 #define DT_CHR S_IFCHR 175 #define DT_BLK S_IFBLK 176 #define DT_LNK S_IFLNK 179 #define IFTODT(mode) ((mode) & S_IFMT) 180 #define DTTOIF(type) (type) 188 #if !defined(S_ISFIFO) 189 # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) 191 #if !defined(S_ISDIR) 192 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 194 #if !defined(S_ISREG) 195 # define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) 197 #if !defined(S_ISLNK) 198 # define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) 200 #if !defined(S_ISSOCK) 201 # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) 203 #if !defined(S_ISCHR) 204 # define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) 206 #if !defined(S_ISBLK) 207 # define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) 211 #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) 214 #define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) 231 unsigned short d_reclen;
240 wchar_t d_name[PATH_MAX+1];
242 typedef struct _wdirent _wdirent;
249 WIN32_FIND_DATAW data;
260 typedef struct _WDIR _WDIR;
271 unsigned short d_reclen;
280 char d_name[PATH_MAX+1];
282 typedef struct dirent dirent;
288 typedef struct DIR DIR;
292 static DIR *opendir(
const char *dirname);
293 static _WDIR *_wopendir(
const wchar_t *dirname);
295 static struct dirent *readdir(DIR *dirp);
296 static struct _wdirent *_wreaddir(_WDIR *dirp);
298 static int readdir_r(
299 DIR *dirp,
struct dirent *entry,
struct dirent **result);
300 static int _wreaddir_r(
301 _WDIR *dirp,
struct _wdirent *entry,
struct _wdirent **result);
303 static int closedir(DIR *dirp);
304 static int _wclosedir(_WDIR *dirp);
306 static void rewinddir(DIR* dirp);
307 static void _wrewinddir(_WDIR* dirp);
309 static int scandir(
const char *dirname,
struct dirent ***namelist,
310 int (*filter)(
const struct dirent*),
311 int (*compare)(
const struct dirent**,
const struct dirent**));
313 static int alphasort(
const struct dirent **a,
const struct dirent **b);
315 static int versionsort(
const struct dirent **a,
const struct dirent **b);
317 static int strverscmp(
const char *a,
const char *b);
320 #define wdirent _wdirent 322 #define wopendir _wopendir 323 #define wreaddir _wreaddir 324 #define wclosedir _wclosedir 325 #define wrewinddir _wrewinddir 328 #if !defined(_MSC_VER) || _MSC_VER < 1400 329 # define wcstombs_s dirent_wcstombs_s 330 # define mbstowcs_s dirent_mbstowcs_s 334 #if defined(_MSC_VER) && _MSC_VER >= 1400 335 # define dirent_set_errno _set_errno 340 static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp);
341 static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp);
343 #if !defined(_MSC_VER) || _MSC_VER < 1400 344 static int dirent_mbstowcs_s(
345 size_t *pReturnValue,
wchar_t *wcstr,
size_t sizeInWords,
346 const char *mbstr,
size_t count);
349 #if !defined(_MSC_VER) || _MSC_VER < 1400 350 static int dirent_wcstombs_s(
351 size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes,
352 const wchar_t *wcstr,
size_t count);
355 #if !defined(_MSC_VER) || _MSC_VER < 1400 356 static void dirent_set_errno(
int error);
365 static _WDIR *_wopendir(
const wchar_t *dirname)
370 if (dirname == NULL || dirname[0] ==
'\0') {
371 dirent_set_errno(ENOENT);
376 _WDIR *dirp = (_WDIR*) malloc(
sizeof(
struct _WDIR));
381 dirp->handle = INVALID_HANDLE_VALUE;
391 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 393 DWORD n = GetFullPathNameW(dirname, 0, NULL, NULL);
396 size_t n = wcslen(dirname);
400 dirp->patt = (
wchar_t*) malloc(
sizeof(
wchar_t) * n + 16);
401 if (dirp->patt == NULL)
412 #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 414 n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
419 wcsncpy_s(dirp->patt, n+1, dirname, n);
440 if (!dirent_first(dirp))
458 static struct _wdirent *_wreaddir(_WDIR *dirp)
464 struct _wdirent *entry;
465 (void) _wreaddir_r(dirp, &dirp->ent, &entry);
477 static int _wreaddir_r(
478 _WDIR *dirp,
struct _wdirent *entry,
struct _wdirent **result)
481 WIN32_FIND_DATAW *datap = dirent_next(dirp);
494 while (n < PATH_MAX && datap->cFileName[n] != 0) {
495 entry->d_name[n] = datap->cFileName[n];
498 entry->d_name[n] = 0;
504 DWORD attr = datap->dwFileAttributes;
505 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
506 entry->d_type = DT_CHR;
507 else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
508 entry->d_type = DT_DIR;
510 entry->d_type = DT_REG;
515 entry->d_reclen =
sizeof(
struct _wdirent);
527 static int _wclosedir(_WDIR *dirp)
530 dirent_set_errno(EBADF);
535 if (dirp->handle != INVALID_HANDLE_VALUE)
536 FindClose(dirp->handle);
550 static void _wrewinddir(_WDIR* dirp)
556 if (dirp->handle != INVALID_HANDLE_VALUE)
557 FindClose(dirp->handle);
564 static WIN32_FIND_DATAW *dirent_first(_WDIR *dirp)
570 dirp->handle = FindFirstFileExW(
571 dirp->patt, FindExInfoStandard, &dirp->data,
572 FindExSearchNameMatch, NULL, 0);
573 if (dirp->handle == INVALID_HANDLE_VALUE)
585 DWORD errorcode = GetLastError();
587 case ERROR_ACCESS_DENIED:
589 dirent_set_errno(EACCES);
592 case ERROR_DIRECTORY:
594 dirent_set_errno(ENOTDIR);
597 case ERROR_PATH_NOT_FOUND:
600 dirent_set_errno(ENOENT);
606 static WIN32_FIND_DATAW *dirent_next(_WDIR *dirp)
616 if (dirp->handle == INVALID_HANDLE_VALUE)
620 if (FindNextFileW(dirp->handle, &dirp->data) == FALSE)
628 FindClose(dirp->handle);
629 dirp->handle = INVALID_HANDLE_VALUE;
634 static DIR *opendir(
const char *dirname)
637 if (dirname == NULL || dirname[0] ==
'\0') {
638 dirent_set_errno(ENOENT);
643 struct DIR *dirp = (DIR*) malloc(
sizeof(
struct DIR));
648 wchar_t wname[PATH_MAX + 1];
650 int error = mbstowcs_s(&n, wname, PATH_MAX + 1, dirname, PATH_MAX+1);
655 dirp->wdirp = _wopendir(wname);
669 static struct dirent *readdir(DIR *dirp)
675 struct dirent *entry;
676 (void) readdir_r(dirp, &dirp->ent, &entry);
688 static int readdir_r(
689 DIR *dirp,
struct dirent *entry,
struct dirent **result)
692 WIN32_FIND_DATAW *datap = dirent_next(dirp->wdirp);
701 int error = wcstombs_s(
702 &n, entry->d_name, PATH_MAX + 1,
703 datap->cFileName, PATH_MAX + 1);
714 if (error && datap->cAlternateFileName[0] !=
'\0') {
716 &n, entry->d_name, PATH_MAX + 1,
717 datap->cAlternateFileName, PATH_MAX + 1);
722 entry->d_namlen = n - 1;
725 DWORD attr = datap->dwFileAttributes;
726 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0)
727 entry->d_type = DT_CHR;
728 else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
729 entry->d_type = DT_DIR;
731 entry->d_type = DT_REG;
736 entry->d_reclen =
sizeof(
struct dirent);
744 entry->d_name[0] =
'?';
745 entry->d_name[1] =
'\0';
747 entry->d_type = DT_UNKNOWN;
759 static int closedir(DIR *dirp)
767 ok = _wclosedir(dirp->wdirp);
776 dirent_set_errno(EBADF);
781 static void rewinddir(DIR* dirp)
787 _wrewinddir(dirp->wdirp);
792 const char *dirname,
struct dirent ***namelist,
793 int (*filter)(
const struct dirent*),
794 int (*compare)(
const struct dirent**,
const struct dirent**))
799 DIR *dir = opendir(dirname);
806 struct dirent *tmp = NULL;
807 struct dirent **files = NULL;
809 size_t allocated = 0;
813 tmp = (
struct dirent*) malloc(
sizeof(
struct dirent));
819 struct dirent *entry;
820 if (readdir_r(dir, tmp, &entry) != 0)
828 if (filter && !filter(tmp))
832 if (size >= allocated) {
834 size_t num_entries = size * 2 + 16;
837 void *p = realloc(files,
sizeof(
void*) * num_entries);
842 files = (dirent**) p;
843 allocated = num_entries;
853 for (
size_t i = 0; i < size; i++) {
867 qsort(files, size,
sizeof(
void*),
868 (
int (*) (
const void*,
const void*)) compare);
887 static int alphasort(
const struct dirent **a,
const struct dirent **b)
889 return strcoll((*a)->d_name, (*b)->d_name);
893 static int versionsort(
const struct dirent **a,
const struct dirent **b)
895 return strverscmp((*a)->d_name, (*b)->d_name);
899 static int strverscmp(
const char *a,
const char *b)
905 while (a[i] == b[i]) {
915 while (j > 0 && isdigit(a[j-1])) {
920 if (a[j] ==
'0' || b[j] ==
'0') {
922 while (a[j] ==
'0' && a[j] == b[j]) {
928 if (!isdigit(b[j])) {
931 }
else if (isdigit(b[j])) {
934 }
else if (isdigit(a[j]) && isdigit(b[j])) {
940 while (isdigit(a[k1])) {
943 while (isdigit(b[k2])) {
955 return (
int) ((
unsigned char) a[i]) - ((
unsigned char) b[i]);
959 #if !defined(_MSC_VER) || _MSC_VER < 1400 960 static int dirent_mbstowcs_s(
961 size_t *pReturnValue,
wchar_t *wcstr,
962 size_t sizeInWords,
const char *mbstr,
size_t count)
965 size_t n = mbstowcs(wcstr, mbstr, sizeInWords);
966 if (wcstr && n >= count)
970 if (wcstr && sizeInWords) {
971 if (n >= sizeInWords)
978 *pReturnValue = n + 1;
987 #if !defined(_MSC_VER) || _MSC_VER < 1400 988 static int dirent_wcstombs_s(
989 size_t *pReturnValue,
char *mbstr,
990 size_t sizeInBytes,
const wchar_t *wcstr,
size_t count)
993 size_t n = wcstombs(mbstr, wcstr, sizeInBytes);
994 if (mbstr && n >= count)
998 if (mbstr && sizeInBytes) {
999 if (n >= sizeInBytes) {
1000 n = sizeInBytes - 1;
1007 *pReturnValue = n + 1;
1016 #if !defined(_MSC_VER) || _MSC_VER < 1400 1017 static void dirent_set_errno(
int error)