Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
dirent_portable.h
Go to the documentation of this file.
1/*
2 * This file was originally: "dirent for Visual C++" from: http://softagalleria.net/dirent.php (version 1.20.1)
3 * However I've modified it to <dirent_portable.h> by adding:
4 *
5 * a fallback to <dirent.h> if _WIN32 is not defined
6 * two missing methods: scandir(...) and alphasort(...)
7 * and some other minor modifications (see below)
8 *
9 *
10 * Original license from http://softagalleria.net/dirent.php
11 *
12 *========================================================================
13 *
14 * dirent.h - dirent API for Microsoft Visual Studio
15 *
16 * Copyright (C) 2006-2012 Toni Ronkko
17 *
18 * Permission is hereby granted, free of charge, to any person obtaining
19 * a copy of this software and associated documentation files (the
20 * ``Software''), to deal in the Software without restriction, including
21 * without limitation the rights to use, copy, modify, merge, publish,
22 * distribute, sublicense, and/or sell copies of the Software, and to
23 * permit persons to whom the Software is furnished to do so, subject to
24 * the following conditions:
25 *
26 * The above copyright notice and this permission notice shall be included
27 * in all copies or substantial portions of the Software.
28 *
29 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
30 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
32 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
33 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
34 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
35 * OTHER DEALINGS IN THE SOFTWARE.
36 *
37 * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $
38 *
39 * =========================================================================
40 * Added:
41 * -> some undefs to prevent possible compiler warnings
42 * -> the scandir(...) and alphasort(...) methods
43 * -> the optional DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS definition (needed for browsing with short ASCII paths instead of long UTF8 paths).
44 * WARNING: in my tests the usage of the long UTF8 paths is not fully functional (patches are welcome)
45 * All these additions have been made to made <dirent_portable.h> usage for Windows consistent
46 * with what I get using <direct.h> under my Ubuntu Linux OS.
47 * =========================================================================
48 *
49 * The code of the scandir(...) method come from the musl library (http://www.musl-libc.org/)
50 * (MIT licensed, Copyright © 2005-2014 Rich Felker, et al.).
51 *
52 * The code of the alphasort(...) method and of all the other minor modifications is in the public domain.
53 *
54 */
55
56#if (!defined(_WIN32) && !defined(_WIN64))
57# include <dirent.h>
58#else // #if (!defined(_WIN32) && !defined(_WIN64))
59
60#ifndef DIRENT_H
61#define DIRENT_H
62
63/*
64 * Define architecture flags so we don't need to include windows.h.
65 * Avoiding windows.h makes it simpler to use windows sockets in conjunction
66 * with dirent.h.
67 */
68#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)
69# define _X86_
70#endif
71#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64)
72#define _AMD64_
73#endif
74
75#include <stdio.h>
76#include <stdarg.h>
77#include <windef.h> // MAX_PATH is defined here,
78#include <WinBase.h>
79#include <wchar.h>
80#include <string.h>
81#include <stdlib.h>
82#include <malloc.h>
83#include <sys/types.h>
84#include <sys/stat.h>
85#include <errno.h>
86#if (!defined(SIZE_MAX) && !defined(INT_MAX))
87#include <limits.h> // INT_MAX
88#endif //(!defined(SIZE_MAX) && !defined(INT_MAX))
89
90
91//#define DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS // set it globally, not just here]
92
93/* Indicates that d_type field is available in dirent structure */
94#define _DIRENT_HAVE_D_TYPE
95
96/* Indicates that d_namlen field is available in dirent structure */
97#define _DIRENT_HAVE_D_NAMLEN
98
99/* Entries missing from MSVC 6.0 */
100#if !defined(FILE_ATTRIBUTE_DEVICE)
101# define FILE_ATTRIBUTE_DEVICE 0x40
102#endif
103
104/* File type and permission flags for stat() */
105#if !defined(S_IFMT)
106# define S_IFMT _S_IFMT /* File type mask */
107#endif
108#if !defined(S_IFDIR)
109# define S_IFDIR _S_IFDIR /* Directory */
110#endif
111#if !defined(S_IFCHR)
112# define S_IFCHR _S_IFCHR /* Character device */
113#endif
114#if !defined(S_IFFIFO)
115# define S_IFFIFO _S_IFFIFO /* Pipe */
116#endif
117#if !defined(S_IFREG)
118# define S_IFREG _S_IFREG /* Regular file */
119#endif
120#if !defined(S_IREAD)
121# define S_IREAD _S_IREAD /* Read permission */
122#endif
123#if !defined(S_IWRITE)
124# define S_IWRITE _S_IWRITE /* Write permission */
125#endif
126#if !defined(S_IEXEC)
127# define S_IEXEC _S_IEXEC /* Execute permission */
128#endif
129#if !defined(S_IFIFO)
130# define S_IFIFO _S_IFIFO /* Pipe */
131#endif
132#if !defined(S_IFBLK)
133# define S_IFBLK 0 /* Block device */
134#endif
135#if !defined(S_IFLNK)
136# define S_IFLNK 0 /* Link */
137#endif
138#if !defined(S_IFSOCK)
139# define S_IFSOCK 0 /* Socket */
140#endif
141
142#if defined(_MSC_VER)
143# define S_IRUSR S_IREAD /* Read user */
144# define S_IWUSR S_IWRITE /* Write user */
145# define S_IXUSR 0 /* Execute user */
146# define S_IRGRP 0 /* Read group */
147# define S_IWGRP 0 /* Write group */
148# define S_IXGRP 0 /* Execute group */
149# define S_IROTH 0 /* Read others */
150# define S_IWOTH 0 /* Write others */
151# define S_IXOTH 0 /* Execute others */
152#endif
153
154/* Maximum length of file name */
155#ifndef DIRENT_MAX_PATH
156# ifndef MAX_PATH
157# define MAX_PATH PATH_MAX // it should be in <limits.h> AFAIK
158# endif //MAX_PATH
159# ifndef DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS // utf8 strings can have up to 4 bytes per char
160# define DIRENT_MAX_PATH (MAX_PATH*4)
161# else //DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
162# define DIRENT_MAX_PATH (MAX_PATH)
163# endif //DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
164#endif //DIRENT_MAX_PATH
165
166/* File type flags for d_type */
167#define DT_UNKNOWN 0
168#define DT_REG S_IFREG
169#define DT_DIR S_IFDIR
170#define DT_FIFO S_IFIFO
171#define DT_SOCK S_IFSOCK
172#define DT_CHR S_IFCHR
173#define DT_BLK S_IFBLK
174#define DT_LNK S_IFLNK
175
176/* Macros for converting between st_mode and d_type */
177#define IFTODT(mode) ((mode) & S_IFMT)
178#define DTTOIF(type) (type)
179
180/*
181 * File type macros. Note that block devices, sockets and links cannot be
182 * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
183 * only defined for compatibility. These macros should always return false
184 * on Windows.
185 */
186
187// Added some undefs to prevent possible compiler warnings
188#undef S_ISFIFO
189#undef S_ISDIR
190#undef S_ISREG
191#undef S_ISLNK
192#undef S_ISSOCK
193#undef S_ISSOCK
194#undef S_ISCHR
195#undef S_ISBLK
196
197#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
198#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
199#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
200#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
201#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
202#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
203#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
204
205/* Return the exact length of d_namlen without zero terminator */
206#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
207
208/* Return number of bytes needed to store d_namlen */
209#define _D_ALLOC_NAMLEN(p) (DIRENT_MAX_PATH)
210
211
212#ifdef __cplusplus
213extern "C" {
214#endif
215
216
217/* Wide-character version */
218struct _wdirent {
219 long d_ino; /* Always zero */
220 unsigned short d_reclen; /* Structure size */
221 size_t d_namlen; /* Length of name without \0 */
222 int d_type; /* File type */
223 wchar_t d_name[DIRENT_MAX_PATH]; /* File name */
224};
225typedef struct _wdirent _wdirent;
226
227struct _WDIR {
228 struct _wdirent ent; /* Current directory entry */
229 WIN32_FIND_DATAW data; /* Private file data */
230 int cached; /* True if data is valid */
231 HANDLE handle; /* Win32 search handle */
232 wchar_t *patt; /* Initial directory name */
233};
234typedef struct _WDIR _WDIR;
235
236static _WDIR *_wopendir (const wchar_t *dirname);
237static struct _wdirent *_wreaddir (_WDIR *dirp);
238static int _wclosedir (_WDIR *dirp);
239static void _wrewinddir (_WDIR* dirp);
240
241
242/* For compatibility with Symbian */
243#define wdirent _wdirent
244#define WDIR _WDIR
245#define wopendir _wopendir
246#define wreaddir _wreaddir
247#define wclosedir _wclosedir
248#define wrewinddir _wrewinddir
249
250
251/* Multi-byte character versions */
252struct dirent {
253 long d_ino; /* Always zero */
254 unsigned short d_reclen; /* Structure size */
255 size_t d_namlen; /* Length of name without \0 */
256 int d_type; /* File type */
257 char d_name[DIRENT_MAX_PATH]; /* File name */
258};
259typedef struct dirent dirent;
260
261struct DIR {
262 struct dirent ent;
263 struct _WDIR *wdirp;
264};
265typedef struct DIR DIR;
266
267static DIR *opendir (const char *dirname);
268static struct dirent *readdir (DIR *dirp);
269static int closedir (DIR *dirp);
270static void rewinddir (DIR* dirp);
271
272
273/* Internal utility functions */
274static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
275static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
276
277static int dirent_mbstowcs_s(
278 size_t *pReturnValue,
279 wchar_t *wcstr,
280 size_t sizeInWords,
281 const char *mbstr,
282 size_t count);
283
284static int dirent_wcstombs_s(
285 size_t *pReturnValue,
286 char *mbstr,
287 size_t sizeInBytes,
288 const wchar_t *wcstr,
289 size_t count);
290
291static void dirent_set_errno (int error);
292
293/*
294 * Open directory stream DIRNAME for read and return a pointer to the
295 * internal working area that is used to retrieve individual directory
296 * entries.
297 */
298static _WDIR*
299_wopendir(
300 const wchar_t *dirname)
301{
302 _WDIR *dirp = NULL;
303 int error;
304
305 /* Must have directory name */
306 if (dirname == NULL || dirname[0] == '\0') {
307 dirent_set_errno (ENOENT);
308 return NULL;
309 }
310
311 /* Allocate new _WDIR structure */
312 dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
313 if (dirp != NULL) {
314 DWORD n;
315
316 /* Reset _WDIR structure */
317 dirp->handle = INVALID_HANDLE_VALUE;
318 dirp->patt = NULL;
319 dirp->cached = 0;
320
321 /* Compute the length of full path plus zero terminator */
322 n = GetFullPathNameW (dirname, 0, NULL, NULL);
323
324 /* Allocate room for absolute directory name and search pattern */
325 dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
326 if (dirp->patt) {
327
328 /*
329 * Convert relative directory name to an absolute one. This
330 * allows rewinddir() to function correctly even when current
331 * working directory is changed between opendir() and rewinddir().
332 */
333 n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
334 if (n > 0) {
335 wchar_t *p;
336
337 /* Append search pattern \* to the directory name */
338 p = dirp->patt + n;
339 if (dirp->patt < p) {
340 switch (p[-1]) {
341 case '\\':
342 case '/':
343 case ':':
344 /* Directory ends in path separator, e.g. c:\temp\ */
345 /*NOP*/;
346 break;
347
348 default:
349 /* Directory name doesn't end in path separator */
350 *p++ = '\\';
351 }
352 }
353 *p++ = '*';
354 *p = '\0';
355
356 /* Open directory stream and retrieve the first entry */
357 if (dirent_first (dirp)) {
358 /* Directory stream opened successfully */
359 error = 0;
360 } else {
361 /* Cannot retrieve first entry */
362 error = 1;
363 dirent_set_errno (ENOENT);
364 }
365
366 } else {
367 /* Cannot retrieve full path name */
368 dirent_set_errno (ENOENT);
369 error = 1;
370 }
371
372 } else {
373 /* Cannot allocate memory for search pattern */
374 error = 1;
375 }
376
377 } else {
378 /* Cannot allocate _WDIR structure */
379 error = 1;
380 }
381
382 /* Clean up in case of error */
383 if (error && dirp) {
384 _wclosedir (dirp);
385 dirp = NULL;
386 }
387
388 return dirp;
389}
390
391/*
392 * Read next directory entry. The directory entry is returned in dirent
393 * structure in the d_name field. Individual directory entries returned by
394 * this function include regular files, sub-directories, pseudo-directories
395 * "." and ".." as well as volume labels, hidden files and system files.
396 */
397static struct _wdirent*
398_wreaddir(
399 _WDIR *dirp)
400{
401 WIN32_FIND_DATAW *datap;
402 struct _wdirent *entp;
403
404 /* Read next directory entry */
405 datap = dirent_next (dirp);
406 if (datap) {
407 size_t n;
408 DWORD attr;
409
410 /* Pointer to directory entry to return */
411 entp = &dirp->ent;
412
413 /*
414 * Copy file name as wide-character string. If the file name is too
415 * long to fit in to the destination buffer, then truncate file name
416 * to DIRENT_MAX_PATH characters and zero-terminate the buffer.
417 */
418 n = 0;
419 while (n + 1 < DIRENT_MAX_PATH && datap->cFileName[n] != 0) {
420 entp->d_name[n] = datap->cFileName[n];
421 n++;
422 }
423 dirp->ent.d_name[n] = 0;
424
425 /* Length of file name excluding zero terminator */
426 entp->d_namlen = n;
427
428 /* File type */
429 attr = datap->dwFileAttributes;
430 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
431 entp->d_type = DT_CHR;
432 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
433 entp->d_type = DT_DIR;
434 } else {
435 entp->d_type = DT_REG;
436 }
437
438 /* Reset dummy fields */
439 entp->d_ino = 0;
440 entp->d_reclen = sizeof (struct _wdirent);
441
442 } else {
443
444 /* Last directory entry read */
445 entp = NULL;
446
447 }
448
449 return entp;
450}
451
452/*
453 * Close directory stream opened by opendir() function. This invalidates the
454 * DIR structure as well as any directory entry read previously by
455 * _wreaddir().
456 */
457static int
458_wclosedir(
459 _WDIR *dirp)
460{
461 int ok;
462 if (dirp) {
463
464 /* Release search handle */
465 if (dirp->handle != INVALID_HANDLE_VALUE) {
466 FindClose (dirp->handle);
467 dirp->handle = INVALID_HANDLE_VALUE;
468 }
469
470 /* Release search pattern */
471 if (dirp->patt) {
472 free (dirp->patt);
473 dirp->patt = NULL;
474 }
475
476 /* Release directory structure */
477 free (dirp);
478 ok = /*success*/0;
479
480 } else {
481 /* Invalid directory stream */
482 dirent_set_errno (EBADF);
483 ok = /*failure*/-1;
484 }
485 return ok;
486}
487
488/*
489 * Rewind directory stream such that _wreaddir() returns the very first
490 * file name again.
491 */
492static void
493_wrewinddir(
494 _WDIR* dirp)
495{
496 if (dirp) {
497 /* Release existing search handle */
498 if (dirp->handle != INVALID_HANDLE_VALUE) {
499 FindClose (dirp->handle);
500 }
501
502 /* Open new search handle */
503 dirent_first (dirp);
504 }
505}
506
507/* Get first directory entry (internal) */
508static WIN32_FIND_DATAW*
509dirent_first(
510 _WDIR *dirp)
511{
512 WIN32_FIND_DATAW *datap;
513
514 /* Open directory and retrieve the first entry */
515 dirp->handle = FindFirstFileW (dirp->patt, &dirp->data);
516 if (dirp->handle != INVALID_HANDLE_VALUE) {
517
518 /* a directory entry is now waiting in memory */
519 datap = &dirp->data;
520 dirp->cached = 1;
521
522 } else {
523
524 /* Failed to re-open directory: no directory entry in memory */
525 dirp->cached = 0;
526 datap = NULL;
527
528 }
529 return datap;
530}
531
532/* Get next directory entry (internal) */
533static WIN32_FIND_DATAW*
534dirent_next(
535 _WDIR *dirp)
536{
537 WIN32_FIND_DATAW *p;
538
539 /* Get next directory entry */
540 if (dirp->cached != 0) {
541
542 /* A valid directory entry already in memory */
543 p = &dirp->data;
544 dirp->cached = 0;
545
546 } else if (dirp->handle != INVALID_HANDLE_VALUE) {
547
548 /* Get the next directory entry from stream */
549 if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
550 /* Got a file */
551 p = &dirp->data;
552 } else {
553 /* The very last entry has been processed or an error occured */
554 FindClose (dirp->handle);
555 dirp->handle = INVALID_HANDLE_VALUE;
556 p = NULL;
557 }
558
559 } else {
560
561 /* End of directory stream reached */
562 p = NULL;
563
564 }
565
566 return p;
567}
568
569/*
570 * Open directory stream using plain old C-string.
571 */
572static DIR*
573opendir(
574 const char *dirname)
575{
576 struct DIR *dirp;
577 int error;
578
579 /* Must have directory name */
580 if (dirname == NULL || dirname[0] == '\0') {
581 dirent_set_errno (ENOENT);
582 return NULL;
583 }
584
585 /* Allocate memory for DIR structure */
586 dirp = (DIR*) malloc (sizeof (struct DIR));
587 if (dirp) {
588 wchar_t wname[DIRENT_MAX_PATH];
589 size_t n;
590
591 /* Convert directory name to wide-character string */
592 error = dirent_mbstowcs_s (&n, wname, DIRENT_MAX_PATH, dirname, DIRENT_MAX_PATH);
593 if (!error) {
594
595 /* Open directory stream using wide-character name */
596 dirp->wdirp = _wopendir (wname);
597 if (dirp->wdirp) {
598 /* Directory stream opened */
599 error = 0;
600 } else {
601 /* Failed to open directory stream */
602 error = 1;
603 }
604
605 } else {
606 /*
607 * Cannot convert file name to wide-character string. This
608 * occurs if the string contains invalid multi-byte sequences or
609 * the output buffer is too small to contain the resulting
610 * string.
611 */
612 error = 1;
613 }
614
615 } else {
616 /* Cannot allocate DIR structure */
617 error = 1;
618 }
619
620 /* Clean up in case of error */
621 if (error && dirp) {
622 free (dirp);
623 dirp = NULL;
624 }
625
626 return dirp;
627}
628
629/*
630 * Read next directory entry.
631 *
632 * When working with text consoles, please note that file names returned by
633 * readdir() are represented in the default ANSI code page while any output to
634 * console is typically formatted on another code page. Thus, non-ASCII
635 * characters in file names will not usually display correctly on console. The
636 * problem can be fixed in two ways: (1) change the character set of console
637 * to 1252 using chcp utility and use Lucida Console font, or (2) use
638 * _cprintf function when writing to console. The _cprinf() will re-encode
639 * ANSI strings to the console code page so many non-ASCII characters will
640 * display correcly.
641 */
642static struct dirent*
643readdir(
644 DIR *dirp)
645{
646 WIN32_FIND_DATAW *datap;
647 struct dirent *entp;
648
649 /* Read next directory entry */
650 datap = dirent_next (dirp->wdirp);
651 if (datap) {
652 size_t n;
653 int error;
654
655 /* Attempt to convert file name to multi-byte string */
656 error = dirent_wcstombs_s(
657 &n, dirp->ent.d_name, DIRENT_MAX_PATH, datap->cFileName, DIRENT_MAX_PATH);
658
659 /*
660 * If the file name cannot be represented by a multi-byte string,
661 * then attempt to use old 8+3 file name. This allows traditional
662 * Unix-code to access some file names despite of unicode
663 * characters, although file names may seem unfamiliar to the user.
664 *
665 * Be ware that the code below cannot come up with a short file
666 * name unless the file system provides one. At least
667 * VirtualBox shared folders fail to do this.
668 */
669 if (error && datap->cAlternateFileName[0] != '\0') {
670 error = dirent_wcstombs_s(
671 &n, dirp->ent.d_name, DIRENT_MAX_PATH,
672 datap->cAlternateFileName, DIRENT_MAX_PATH);
673 }
674
675 if (!error) {
676 DWORD attr;
677
678 /* Initialize directory entry for return */
679 entp = &dirp->ent;
680
681 /* Length of file name excluding zero terminator */
682 entp->d_namlen = n - 1;
683
684 /* File attributes */
685 attr = datap->dwFileAttributes;
686 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
687 entp->d_type = DT_CHR;
688 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
689 entp->d_type = DT_DIR;
690 } else {
691 entp->d_type = DT_REG;
692 }
693
694 /* Reset dummy fields */
695 entp->d_ino = 0;
696 entp->d_reclen = sizeof (struct dirent);
697
698 } else {
699 /*
700 * Cannot convert file name to multi-byte string so construct
701 * an errornous directory entry and return that. Note that
702 * we cannot return NULL as that would stop the processing
703 * of directory entries completely.
704 */
705 entp = &dirp->ent;
706 entp->d_name[0] = '?';
707 entp->d_name[1] = '\0';
708 entp->d_namlen = 1;
709 entp->d_type = DT_UNKNOWN;
710 entp->d_ino = 0;
711 entp->d_reclen = 0;
712 }
713
714 } else {
715 /* No more directory entries */
716 entp = NULL;
717 }
718
719 return entp;
720}
721
722/*
723 * Close directory stream.
724 */
725static int
726closedir(
727 DIR *dirp)
728{
729 int ok;
730 if (dirp) {
731
732 /* Close wide-character directory stream */
733 ok = _wclosedir (dirp->wdirp);
734 dirp->wdirp = NULL;
735
736 /* Release multi-byte character version */
737 free (dirp);
738
739 } else {
740
741 /* Invalid directory stream */
742 dirent_set_errno (EBADF);
743 ok = /*failure*/-1;
744
745 }
746 return ok;
747}
748
749/*
750 * Rewind directory stream to beginning.
751 */
752static void
753rewinddir(
754 DIR* dirp)
755{
756 /* Rewind wide-character string directory stream */
757 _wrewinddir (dirp->wdirp);
758}
759
760/* Convert multi-byte string to wide character string */
761static int
762dirent_mbstowcs_s(
763 size_t *pReturnValue,
764 wchar_t *wcstr,
765 size_t sizeInWords,
766 const char *mbstr,
767 size_t count)
768{
769 int error;
770#ifndef DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
771 // we don't use "count" at all: we assume mstr is zero terminated:
772 size_t n = (size_t) MultiByteToWideChar (CP_UTF8, 0, mbstr, -1, wcstr, 0);//sizeInWords);
773 if (n==0) {
774 error = 1;
775 if (sizeInWords>0) wcstr[0]=L'\0';
776 if (pReturnValue) *pReturnValue = 0;
777 }
778 else if (n<=sizeInWords) {
779 error = MultiByteToWideChar (CP_UTF8, 0, mbstr, -1, wcstr, n) == 0 ? 1 : 0;
780 if (pReturnValue) *pReturnValue = n;
781 }
782 else {
783 // Buffer too low:
784 if (sizeInWords>0) {
785 if (sizeInWords>1) MultiByteToWideChar (CP_UTF8, 0, mbstr, -1, wcstr, sizeInWords-1);
786 wcstr[sizeInWords-1] = L'\0';
787 }
788 if (pReturnValue) *pReturnValue = sizeInWords;
789 error = 1;
790 }
791
792 /*
793 if (!wcstr || n < count) {
794 // Zero-terminate output buffer
795 if (wcstr && sizeInWords) {
796 if (n >= sizeInWords) {
797 n = sizeInWords - 1;
798 }
799 wcstr[n] = 0;
800 }
801
802 // Length of resuting multi-byte string WITH zero terminator
803 if (pReturnValue) {
804 *pReturnValue = n + 1;
805 }
806
807 // Success
808 error = 0;
809
810 } else {
811
812 // Could not convert string
813 error = 1;
814
815 }
816 */
817#else //DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
818#if defined(_MSC_VER) && _MSC_VER >= 1400
819
820 /* Microsoft Visual Studio 2005 or later */
821 error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
822
823#else
824
825 /* Older Visual Studio or non-Microsoft compiler */
826 size_t n;
827
828 /* Convert to wide-character string (or count characters) */
829 n = mbstowcs (wcstr, mbstr, sizeInWords);
830 if (!wcstr || n < count) {
831
832 /* Zero-terminate output buffer */
833 if (wcstr && sizeInWords) {
834 if (n >= sizeInWords) {
835 n = sizeInWords - 1;
836 }
837 wcstr[n] = 0;
838 }
839
840 /* Length of resuting multi-byte string WITH zero terminator */
841 if (pReturnValue) {
842 *pReturnValue = n + 1;
843 }
844
845 /* Success */
846 error = 0;
847
848 } else {
849
850 /* Could not convert string */
851 error = 1;
852
853 }
854
855#endif
856#endif //DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
857
858 return error;
859}
860
861/* Convert wide-character string to multi-byte string */
862static int
863dirent_wcstombs_s(
864 size_t *pReturnValue,
865 char *mbstr,
866 size_t sizeInBytes, /* max size of mbstr */
867 const wchar_t *wcstr,
868 size_t count)
869{
870 int error;
871
872#ifndef DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
873 // we don't use "count" at all: we assume wcstr is zero terminated:
874 size_t n = (size_t) WideCharToMultiByte (CP_UTF8, 0, wcstr, -1, mbstr, 0,NULL,NULL);//sizeInBytes, NULL, NULL);
875 if (n==0) {
876 error = 1;
877 if (sizeInBytes>0) mbstr[0]='\0';
878 if (pReturnValue) *pReturnValue = 0;
879 }
880 else if (n<=sizeInBytes) {
881 error = WideCharToMultiByte (CP_UTF8, 0, wcstr, -1, mbstr, n, NULL, NULL) == 0 ? 1 : 0;
882 if (pReturnValue) *pReturnValue = n;
883 }
884 else {
885 // Buffer too low:
886 if (sizeInBytes>0) {
887 if (sizeInBytes>1) WideCharToMultiByte (CP_UTF8, 0, wcstr, -1, mbstr, sizeInBytes-1, NULL, NULL);
888 mbstr[sizeInBytes-1] = '\0';
889 }
890 if (pReturnValue) *pReturnValue = sizeInBytes;
891 error = 1;
892 }
893 /*
894 if (!mbstr || n < count) {
895
896 // Zero-terminate output buffer
897 if (mbstr && sizeInBytes) {
898 if (n >= sizeInBytes) {
899 n = sizeInBytes - 1;
900 }
901 mbstr[n] = '\0';
902 }
903
904 // Lenght of resulting multi-bytes string WITH zero-terminator
905 if (pReturnValue) {
906 *pReturnValue = n + 1;
907 }
908
909
910 // Success
911 error = 0;
912
913 } else {
914
915 // Cannot convert string
916 error = 1;
917
918 }
919 */
920#else //DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
921#if defined(_MSC_VER) && _MSC_VER >= 1400
922
923 /* Microsoft Visual Studio 2005 or later */
924 error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
925
926#else
927
928 /* Older Visual Studio or non-Microsoft compiler */
929 size_t n;
930
931 /* Convert to multi-byte string (or count the number of bytes needed) */
932 n = wcstombs (mbstr, wcstr, sizeInBytes);
933 if (!mbstr || n < count) {
934
935 /* Zero-terminate output buffer */
936 if (mbstr && sizeInBytes) {
937 if (n >= sizeInBytes) {
938 n = sizeInBytes - 1;
939 }
940 mbstr[n] = '\0';
941 }
942
943 /* Lenght of resulting multi-bytes string WITH zero-terminator */
944 if (pReturnValue) {
945 *pReturnValue = n + 1;
946 }
947
948 /* Success */
949 error = 0;
950
951 } else {
952
953 /* Cannot convert string */
954 error = 1;
955
956 }
957
958#endif
959#endif //DIRENT_USE_ASCII_SHORT_PATHS_ON_WINDOWS
960 return error;
961}
962
963/* Set errno variable */
964static void
965dirent_set_errno(
966 int error)
967{
968#if defined(_MSC_VER) && _MSC_VER >= 1400
969
970 /* Microsoft Visual Studio 2005 and later */
971 _set_errno (error);
972
973#else
974
975 /* Non-Microsoft compiler or older Microsoft compiler */
976 errno = error;
977
978#endif
979}
980
981
982// The code of this single method comes from the musl library
983// (MIT licensed, Copyright © 2005-2014 Rich Felker, et al.)
984# ifndef SIZE_MAX // Can't we just set it to INT_MAX or something like that ?
985# define SIZE_MAX_WAS_NOT_DEFINED
986# define SIZE_MAX INT_MAX // should be in limits.h AFAIK
987# endif //SIZE_MAX
988inline static int scandir(const char *path, struct dirent ***res,
989 int (*sel)(const struct dirent *),
990 int (*cmp)(const struct dirent **, const struct dirent **))
991{
992 DIR *d = opendir(path);
993 struct dirent *de, **names=0, **tmp;
994 size_t cnt=0, len=0;
995 int old_errno = errno;
996
997 if (!d) return -1;
998
999 while ((errno=0), (de = readdir(d))) {
1000 if (sel && !sel(de)) continue;
1001 if (cnt >= len) {
1002 len = 2*len+1;
1003 if (len > SIZE_MAX/sizeof *names) break;
1004 tmp = (dirent**)realloc(names, len * sizeof *names);
1005 if (!tmp) break;
1006 names = tmp;
1007 }
1008 names[cnt] = (dirent*)malloc(de->d_reclen);
1009 if (!names[cnt]) break;
1010 memcpy(names[cnt++], de, de->d_reclen);
1011 }
1012
1013 closedir(d);
1014
1015 if (errno) {
1016 if (names) while (cnt-->0) free(names[cnt]);
1017 free(names);
1018 return -1;
1019 }
1020 errno = old_errno;
1021
1022 if (cmp) qsort(names, cnt, sizeof *names, (int (*)(const void *, const void *))cmp);
1023 *res = names;
1024 return cnt;
1025}
1026#ifdef SIZE_MAX_WAS_NOT_DEFINED
1027# undef SIZE_MAX
1028# undef SIZE_MAX_WAS_NOT_DEFINED
1029#endif //SIZE_MAX_WAS_NOT_DEFINED
1030
1031// alphasort: Function to compare two `struct dirent's alphabetically.
1032inline static int alphasort (const struct dirent **e1,const struct dirent **e2) {
1033 return strcmp((*e1)->d_name,(*e2)->d_name);
1034}
1035
1036
1037#ifdef __cplusplus
1038}
1039#endif
1040#endif /*DIRENT_H*/
1041
1042#endif //#if (!defined(_WIN32) && !defined(_WIN64))
1043
1044
#define DIRENT_MAX_PATH