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