aGrUM  0.13.2
dirent.h
Go to the documentation of this file.
1 /*
2  * Dirent interface for Microsoft Visual Studio
3  * Version 1.21
4  *
5  * Copyright (C) 2006-2012 Toni Ronkko
6  * This file is part of dirent. Dirent may be freely distributed
7  * under the MIT license. For all details and documentation, see
8  * https://github.com/tronkko/dirent
9  */
10 #ifndef DIRENT_H
11 #define DIRENT_H
12 
13 #ifndef DOXYGEN_SHOULD_SKIP_THIS
14 
15 /*
16  * Define architecture flags so we don't need to include windows.h.
17  * Avoiding windows.h makes it simpler to use windows sockets in conjunction
18  * with dirent.h.
19  */
20 # if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) \
21  && !defined(_AMD64_) && defined(_M_IX86)
22 # define _X86_
23 # endif
24 # if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) \
25  && !defined(_AMD64_) && defined(_M_AMD64)
26 # define _AMD64_
27 # endif
28 
29 // clang-format off
30 // clang-format may change headers order. We do not want it here.
31 #include <stdio.h>
32 #include <stdarg.h>
33 #include <windef.h>
34 #include <winbase.h>
35 #include <wchar.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <malloc.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <errno.h>
42 // clang-format on
43 
44 /* Indicates that d_type field is available in dirent structure */
45 # define _DIRENT_HAVE_D_TYPE
46 
47 /* Indicates that d_namlen field is available in dirent structure */
48 # define _DIRENT_HAVE_D_NAMLEN
49 
50 /* Entries missing from MSVC 6.0 */
51 # if !defined(FILE_ATTRIBUTE_DEVICE)
52 # define FILE_ATTRIBUTE_DEVICE 0x40
53 # endif
54 
55 /* File type and permission flags for stat(), general mask */
56 # if !defined(S_IFMT)
57 # define S_IFMT _S_IFMT
58 # endif
59 
60 /* Directory bit */
61 # if !defined(S_IFDIR)
62 # define S_IFDIR _S_IFDIR
63 # endif
64 
65 /* Character device bit */
66 # if !defined(S_IFCHR)
67 # define S_IFCHR _S_IFCHR
68 # endif
69 
70 /* Pipe bit */
71 # if !defined(S_IFFIFO)
72 # define S_IFFIFO _S_IFFIFO
73 # endif
74 
75 /* Regular file bit */
76 # if !defined(S_IFREG)
77 # define S_IFREG _S_IFREG
78 # endif
79 
80 /* Read permission */
81 # if !defined(S_IREAD)
82 # define S_IREAD _S_IREAD
83 # endif
84 
85 /* Write permission */
86 # if !defined(S_IWRITE)
87 # define S_IWRITE _S_IWRITE
88 # endif
89 
90 /* Execute permission */
91 # if !defined(S_IEXEC)
92 # define S_IEXEC _S_IEXEC
93 # endif
94 
95 /* Pipe */
96 # if !defined(S_IFIFO)
97 # define S_IFIFO _S_IFIFO
98 # endif
99 
100 /* Block device */
101 # if !defined(S_IFBLK)
102 # define S_IFBLK 0
103 # endif
104 
105 /* Link */
106 # if !defined(S_IFLNK)
107 # define S_IFLNK 0
108 # endif
109 
110 /* Socket */
111 # if !defined(S_IFSOCK)
112 # define S_IFSOCK 0
113 # endif
114 
115 /* Read user permission */
116 # if !defined(S_IRUSR)
117 # define S_IRUSR S_IREAD
118 # endif
119 
120 /* Write user permission */
121 # if !defined(S_IWUSR)
122 # define S_IWUSR S_IWRITE
123 # endif
124 
125 /* Execute user permission */
126 # if !defined(S_IXUSR)
127 # define S_IXUSR 0
128 # endif
129 
130 /* Read group permission */
131 # if !defined(S_IRGRP)
132 # define S_IRGRP 0
133 # endif
134 
135 /* Write group permission */
136 # if !defined(S_IWGRP)
137 # define S_IWGRP 0
138 # endif
139 
140 /* Execute group permission */
141 # if !defined(S_IXGRP)
142 # define S_IXGRP 0
143 # endif
144 
145 /* Read others permission */
146 # if !defined(S_IROTH)
147 # define S_IROTH 0
148 # endif
149 
150 /* Write others permission */
151 # if !defined(S_IWOTH)
152 # define S_IWOTH 0
153 # endif
154 
155 /* Execute others permission */
156 # if !defined(S_IXOTH)
157 # define S_IXOTH 0
158 # endif
159 
160 /* Maximum length of file name */
161 # if !defined(PATH_MAX)
162 # define PATH_MAX MAX_PATH
163 # endif
164 # if !defined(FILENAME_MAX)
165 # define FILENAME_MAX MAX_PATH
166 # endif
167 # if !defined(NAME_MAX)
168 # define NAME_MAX FILENAME_MAX
169 # endif
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 # if !defined(S_ISFIFO)
192 # define S_ISFIFO(mode) (((mode)&S_IFMT) == S_IFIFO)
193 # endif
194 # if !defined(S_ISDIR)
195 # define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
196 # endif
197 # if !defined(S_ISREG)
198 # define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)
199 # endif
200 # if !defined(S_ISLNK)
201 # define S_ISLNK(mode) (((mode)&S_IFMT) == S_IFLNK)
202 # endif
203 # if !defined(S_ISSOCK)
204 # define S_ISSOCK(mode) (((mode)&S_IFMT) == S_IFSOCK)
205 # endif
206 # if !defined(S_ISCHR)
207 # define S_ISCHR(mode) (((mode)&S_IFMT) == S_IFCHR)
208 # endif
209 # if !defined(S_ISBLK)
210 # define S_ISBLK(mode) (((mode)&S_IFMT) == S_IFBLK)
211 # endif
212 
213 /* Return the exact length of d_namlen without zero terminator */
214 # define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
215 
216 /* Return number of bytes needed to store d_namlen */
217 # define _D_ALLOC_NAMLEN(p) (PATH_MAX)
218 
219 
220 # ifdef __cplusplus
221 extern "C" {
222 # endif
223 
224 
225 /* Wide-character version */
226 struct _wdirent {
227  /* Always zero */
228  long d_ino;
229 
230  /* Structure size */
231  unsigned short d_reclen;
232 
233  /* Length of name without \0 */
234  size_t d_namlen;
235 
236  /* File type */
237  int d_type;
238 
239  /* File name */
240  wchar_t d_name[PATH_MAX];
241 };
242 typedef struct _wdirent _wdirent;
243 
244 struct _WDIR {
245  /* Current directory entry */
246  struct _wdirent ent;
247 
248  /* Private file data */
249  WIN32_FIND_DATAW data;
250 
251  /* True if data is valid */
252  int cached;
253 
254  /* Win32 search handle */
255  HANDLE handle;
256 
257  /* Initial directory name */
258  wchar_t* patt;
259 };
260 typedef struct _WDIR _WDIR;
261 
262 static _WDIR* _wopendir(const wchar_t* dirname);
263 static struct _wdirent* _wreaddir(_WDIR* dirp);
264 static int _wclosedir(_WDIR* dirp);
265 static void _wrewinddir(_WDIR* dirp);
266 
267 
268 /* For compatibility with Symbian */
269 # define wdirent _wdirent
270 # define WDIR _WDIR
271 # define wopendir _wopendir
272 # define wreaddir _wreaddir
273 # define wclosedir _wclosedir
274 # define wrewinddir _wrewinddir
275 
276 
277 /* Multi-byte character versions */
278 struct dirent {
279  /* Always zero */
280  long d_ino;
281 
282  /* Structure size */
283  unsigned short d_reclen;
284 
285  /* Length of name without \0 */
286  size_t d_namlen;
287 
288  /* File type */
289  int d_type;
290 
291  /* File name */
292  char d_name[PATH_MAX];
293 };
294 typedef struct dirent dirent;
295 
296 struct DIR {
297  struct dirent ent;
298  struct _WDIR* wdirp;
299 };
300 typedef struct DIR DIR;
301 
302 static DIR* opendir(const char* dirname);
303 static struct dirent* readdir(DIR* dirp);
304 static int closedir(DIR* dirp);
305 static void rewinddir(DIR* dirp);
306 
307 
308 /* Internal utility functions */
309 static WIN32_FIND_DATAW* dirent_first(_WDIR* dirp);
310 static WIN32_FIND_DATAW* dirent_next(_WDIR* dirp);
311 
312 static int dirent_mbstowcs_s(size_t* pReturnValue,
313  wchar_t* wcstr,
314  size_t sizeInWords,
315  const char* mbstr,
316  size_t count);
317 
318 static int dirent_wcstombs_s(size_t* pReturnValue,
319  char* mbstr,
320  size_t sizeInBytes,
321  const wchar_t* wcstr,
322  size_t count);
323 
324 static void dirent_set_errno(int error);
325 
326 /*
327  * Open directory stream DIRNAME for read and return a pointer to the
328  * internal working area that is used to retrieve individual directory
329  * entries.
330  */
331 static _WDIR* _wopendir(const wchar_t* dirname) {
332  _WDIR* dirp = NULL;
333  int error;
334 
335  /* Must have directory name */
336  if (dirname == NULL || dirname[0] == '\0') {
337  dirent_set_errno(ENOENT);
338  return NULL;
339  }
340 
341  /* Allocate new _WDIR structure */
342  dirp = (_WDIR*)malloc(sizeof(struct _WDIR));
343  if (dirp != NULL) {
344  DWORD n;
345 
346  /* Reset _WDIR structure */
347  dirp->handle = INVALID_HANDLE_VALUE;
348  dirp->patt = NULL;
349  dirp->cached = 0;
350 
351  /* Compute the length of full path plus zero terminator */
352  n = GetFullPathNameW(dirname, 0, NULL, NULL);
353 
354  /* Allocate room for absolute directory name and search pattern */
355  dirp->patt = (wchar_t*)malloc(sizeof(wchar_t) * n + 16);
356  if (dirp->patt) {
357  /*
358  * Convert relative directory name to an absolute one. This
359  * allows rewinddir() to function correctly even when current
360  * working directory is changed between opendir() and rewinddir().
361  */
362  n = GetFullPathNameW(dirname, n, dirp->patt, NULL);
363  if (n > 0) {
364  wchar_t* p;
365 
366  /* Append search pattern \* to the directory name */
367  p = dirp->patt + n;
368  if (dirp->patt < p) {
369  switch (p[-1]) {
370  case '\\':
371  case '/':
372  case ':':
373  /* Directory ends in path separator, e.g. c:\temp\ */
374  /*NOP*/;
375  break;
376 
377  default:
378  /* Directory name doesn't end in path separator */
379  *p++ = '\\';
380  }
381  }
382  *p++ = '*';
383  *p = '\0';
384 
385  /* Open directory stream and retrieve the first entry */
386  if (dirent_first(dirp)) {
387  /* Directory stream opened successfully */
388  error = 0;
389  } else {
390  /* Cannot retrieve first entry */
391  error = 1;
392  dirent_set_errno(ENOENT);
393  }
394 
395  } else {
396  /* Cannot retrieve full path name */
397  dirent_set_errno(ENOENT);
398  error = 1;
399  }
400 
401  } else {
402  /* Cannot allocate memory for search pattern */
403  error = 1;
404  }
405 
406  } else {
407  /* Cannot allocate _WDIR structure */
408  error = 1;
409  }
410 
411  /* Clean up in case of error */
412  if (error && dirp) {
413  _wclosedir(dirp);
414  dirp = NULL;
415  }
416 
417  return dirp;
418 }
419 
420 /*
421  * Read next directory entry. The directory entry is returned in dirent
422  * structure in the d_name field. Individual directory entries returned by
423  * this function include regular files, sub-directories, pseudo-directories
424  * "." and ".." as well as volume labels, hidden files and system files.
425  */
426 static struct _wdirent* _wreaddir(_WDIR* dirp) {
427  WIN32_FIND_DATAW* datap;
428  struct _wdirent* entp;
429 
430  /* Read next directory entry */
431  datap = dirent_next(dirp);
432  if (datap) {
433  size_t n;
434  DWORD attr;
435 
436  /* Pointer to directory entry to return */
437  entp = &dirp->ent;
438 
439  /*
440  * Copy file name as wide-character string. If the file name is too
441  * long to fit in to the destination buffer, then truncate file name
442  * to PATH_MAX characters and zero-terminate the buffer.
443  */
444  n = 0;
445  while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {
446  entp->d_name[n] = datap->cFileName[n];
447  n++;
448  }
449  dirp->ent.d_name[n] = 0;
450 
451  /* Length of file name excluding zero terminator */
452  entp->d_namlen = n;
453 
454  /* File type */
455  attr = datap->dwFileAttributes;
456  if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
457  entp->d_type = DT_CHR;
458  } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
459  entp->d_type = DT_DIR;
460  } else {
461  entp->d_type = DT_REG;
462  }
463 
464  /* Reset dummy fields */
465  entp->d_ino = 0;
466  entp->d_reclen = sizeof(struct _wdirent);
467 
468  } else {
469  /* Last directory entry read */
470  entp = NULL;
471  }
472 
473  return entp;
474 }
475 
476 /*
477  * Close directory stream opened by opendir() function. This invalidates the
478  * DIR structure as well as any directory entry read previously by
479  * _wreaddir().
480  */
481 static int _wclosedir(_WDIR* dirp) {
482  int ok;
483  if (dirp) {
484  /* Release search handle */
485  if (dirp->handle != INVALID_HANDLE_VALUE) {
486  FindClose(dirp->handle);
487  dirp->handle = INVALID_HANDLE_VALUE;
488  }
489 
490  /* Release search pattern */
491  if (dirp->patt) {
492  free(dirp->patt);
493  dirp->patt = NULL;
494  }
495 
496  /* Release directory structure */
497  free(dirp);
498  ok = /*success*/ 0;
499 
500  } else {
501  /* Invalid directory stream */
502  dirent_set_errno(EBADF);
503  ok = /*failure*/ -1;
504  }
505  return ok;
506 }
507 
508 /*
509  * Rewind directory stream such that _wreaddir() returns the very first
510  * file name again.
511  */
512 static void _wrewinddir(_WDIR* dirp) {
513  if (dirp) {
514  /* Release existing search handle */
515  if (dirp->handle != INVALID_HANDLE_VALUE) { FindClose(dirp->handle); }
516 
517  /* Open new search handle */
518  dirent_first(dirp);
519  }
520 }
521 
522 /* Get first directory entry (internal) */
523 static WIN32_FIND_DATAW* dirent_first(_WDIR* dirp) {
524  WIN32_FIND_DATAW* datap;
525 
526  /* Open directory and retrieve the first entry */
527  dirp->handle = FindFirstFileW(dirp->patt, &dirp->data);
528  if (dirp->handle != INVALID_HANDLE_VALUE) {
529  /* a directory entry is now waiting in memory */
530  datap = &dirp->data;
531  dirp->cached = 1;
532 
533  } else {
534  /* Failed to re-open directory: no directory entry in memory */
535  dirp->cached = 0;
536  datap = NULL;
537  }
538  return datap;
539 }
540 
541 /* Get next directory entry (internal) */
542 static WIN32_FIND_DATAW* dirent_next(_WDIR* dirp) {
543  WIN32_FIND_DATAW* p;
544 
545  /* Get next directory entry */
546  if (dirp->cached != 0) {
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  /* Get the next directory entry from stream */
553  if (FindNextFileW(dirp->handle, &dirp->data) != FALSE) {
554  /* Got a file */
555  p = &dirp->data;
556  } else {
557  /* The very last entry has been processed or an error occured */
558  FindClose(dirp->handle);
559  dirp->handle = INVALID_HANDLE_VALUE;
560  p = NULL;
561  }
562 
563  } else {
564  /* End of directory stream reached */
565  p = NULL;
566  }
567 
568  return p;
569 }
570 
571 /*
572  * Open directory stream using plain old C-string.
573  */
574 static DIR* opendir(const char* dirname) {
575  struct DIR* dirp;
576  int error;
577 
578  /* Must have directory name */
579  if (dirname == NULL || dirname[0] == '\0') {
580  dirent_set_errno(ENOENT);
581  return NULL;
582  }
583 
584  /* Allocate memory for DIR structure */
585  dirp = (DIR*)malloc(sizeof(struct DIR));
586  if (dirp) {
587  wchar_t wname[PATH_MAX];
588  size_t n;
589 
590  /* Convert directory name to wide-character string */
591  error = dirent_mbstowcs_s(&n, wname, PATH_MAX, dirname, PATH_MAX);
592  if (!error) {
593  /* Open directory stream using wide-character name */
594  dirp->wdirp = _wopendir(wname);
595  if (dirp->wdirp) {
596  /* Directory stream opened */
597  error = 0;
598  } else {
599  /* Failed to open directory stream */
600  error = 1;
601  }
602 
603  } else {
604  /*
605  * Cannot convert file name to wide-character string. This
606  * occurs if the string contains invalid multi-byte sequences or
607  * the output buffer is too small to contain the resulting
608  * string.
609  */
610  error = 1;
611  }
612 
613  } else {
614  /* Cannot allocate DIR structure */
615  error = 1;
616  }
617 
618  /* Clean up in case of error */
619  if (error && dirp) {
620  free(dirp);
621  dirp = NULL;
622  }
623 
624  return dirp;
625 }
626 
627 /*
628  * Read next directory entry.
629  *
630  * When working with text consoles, please note that file names returned by
631  * readdir() are represented in the default ANSI code page while any output to
632  * console is typically formatted on another code page. Thus, non-ASCII
633  * characters in file names will not usually display correctly on console. The
634  * problem can be fixed in two ways: (1) change the character set of console
635  * to 1252 using chcp utility and use Lucida Console font, or (2) use
636  * _cprintf function when writing to console. The _cprinf() will re-encode
637  * ANSI strings to the console code page so many non-ASCII characters will
638  * display correcly.
639  */
640 static struct dirent* readdir(DIR* dirp) {
641  WIN32_FIND_DATAW* datap;
642  struct dirent* entp;
643 
644  /* Read next directory entry */
645  datap = dirent_next(dirp->wdirp);
646  if (datap) {
647  size_t n;
648  int error;
649 
650  /* Attempt to convert file name to multi-byte string */
651  error = dirent_wcstombs_s(
652  &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
653 
654  /*
655  * If the file name cannot be represented by a multi-byte string,
656  * then attempt to use old 8+3 file name. This allows traditional
657  * Unix-code to access some file names despite of unicode
658  * characters, although file names may seem unfamiliar to the user.
659  *
660  * Be ware that the code below cannot come up with a short file
661  * name unless the file system provides one. At least
662  * VirtualBox shared folders fail to do this.
663  */
664  if (error && datap->cAlternateFileName[0] != '\0') {
665  error = dirent_wcstombs_s(
666  &n, dirp->ent.d_name, PATH_MAX, datap->cAlternateFileName, PATH_MAX);
667  }
668 
669  if (!error) {
670  DWORD attr;
671 
672  /* Initialize directory entry for return */
673  entp = &dirp->ent;
674 
675  /* Length of file name excluding zero terminator */
676  entp->d_namlen = n - 1;
677 
678  /* File attributes */
679  attr = datap->dwFileAttributes;
680  if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
681  entp->d_type = DT_CHR;
682  } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
683  entp->d_type = DT_DIR;
684  } else {
685  entp->d_type = DT_REG;
686  }
687 
688  /* Reset dummy fields */
689  entp->d_ino = 0;
690  entp->d_reclen = sizeof(struct dirent);
691 
692  } else {
693  /*
694  * Cannot convert file name to multi-byte string so construct
695  * an errornous directory entry and return that. Note that
696  * we cannot return NULL as that would stop the processing
697  * of directory entries completely.
698  */
699  entp = &dirp->ent;
700  entp->d_name[0] = '?';
701  entp->d_name[1] = '\0';
702  entp->d_namlen = 1;
703  entp->d_type = DT_UNKNOWN;
704  entp->d_ino = 0;
705  entp->d_reclen = 0;
706  }
707 
708  } else {
709  /* No more directory entries */
710  entp = NULL;
711  }
712 
713  return entp;
714 }
715 
716 /*
717  * Close directory stream.
718  */
719 static int closedir(DIR* dirp) {
720  int ok;
721  if (dirp) {
722  /* Close wide-character directory stream */
723  ok = _wclosedir(dirp->wdirp);
724  dirp->wdirp = NULL;
725 
726  /* Release multi-byte character version */
727  free(dirp);
728 
729  } else {
730  /* Invalid directory stream */
731  dirent_set_errno(EBADF);
732  ok = /*failure*/ -1;
733  }
734  return ok;
735 }
736 
737 /*
738  * Rewind directory stream to beginning.
739  */
740 static void rewinddir(DIR* dirp) {
741  /* Rewind wide-character string directory stream */
742  _wrewinddir(dirp->wdirp);
743 }
744 
745 /* Convert multi-byte string to wide character string */
746 static int dirent_mbstowcs_s(size_t* pReturnValue,
747  wchar_t* wcstr,
748  size_t sizeInWords,
749  const char* mbstr,
750  size_t count) {
751  int error;
752 
753 # if defined(_MSC_VER) && _MSC_VER >= 1400
754 
755  /* Microsoft Visual Studio 2005 or later */
756  error = mbstowcs_s(pReturnValue, wcstr, sizeInWords, mbstr, count);
757 
758 # else
759 
760  /* Older Visual Studio or non-Microsoft compiler */
761  size_t n;
762 
763  /* Convert to wide-character string (or count characters) */
764  n = mbstowcs(wcstr, mbstr, sizeInWords);
765  if (!wcstr || n < count) {
766  /* Zero-terminate output buffer */
767  if (wcstr && sizeInWords) {
768  if (n >= sizeInWords) { n = sizeInWords - 1; }
769  wcstr[n] = 0;
770  }
771 
772  /* Length of resuting multi-byte string WITH zero terminator */
773  if (pReturnValue) { *pReturnValue = n + 1; }
774 
775  /* Success */
776  error = 0;
777 
778  } else {
779  /* Could not convert string */
780  error = 1;
781  }
782 
783 # endif
784 
785  return error;
786 }
787 
788 /* Convert wide-character string to multi-byte string */
789 static int dirent_wcstombs_s(size_t* pReturnValue,
790  char* mbstr,
791  size_t sizeInBytes, /* max size of mbstr */
792  const wchar_t* wcstr,
793  size_t count) {
794  int error;
795 
796 # if defined(_MSC_VER) && _MSC_VER >= 1400
797 
798  /* Microsoft Visual Studio 2005 or later */
799  error = wcstombs_s(pReturnValue, mbstr, sizeInBytes, wcstr, count);
800 
801 # else
802 
803  /* Older Visual Studio or non-Microsoft compiler */
804  size_t n;
805 
806  /* Convert to multi-byte string (or count the number of bytes needed) */
807  n = wcstombs(mbstr, wcstr, sizeInBytes);
808  if (!mbstr || n < count) {
809  /* Zero-terminate output buffer */
810  if (mbstr && sizeInBytes) {
811  if (n >= sizeInBytes) { n = sizeInBytes - 1; }
812  mbstr[n] = '\0';
813  }
814 
815  /* Lenght of resulting multi-bytes string WITH zero-terminator */
816  if (pReturnValue) { *pReturnValue = n + 1; }
817 
818  /* Success */
819  error = 0;
820 
821  } else {
822  /* Cannot convert string */
823  error = 1;
824  }
825 
826 # endif
827 
828  return error;
829 }
830 
831 /* Set errno variable */
832 static void dirent_set_errno(int error) {
833 # if defined(_MSC_VER) && _MSC_VER >= 1400
834 
835  /* Microsoft Visual Studio 2005 and later */
836  _set_errno(error);
837 
838 # else
839 
840  /* Non-Microsoft compiler or older Microsoft compiler */
841  errno = error;
842 
843 # endif
844 }
845 
846 
847 # ifdef __cplusplus
848 }
849 # endif
850 
851 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
852 
853 #endif /*DIRENT_H*/