xbmc
dirent.h
1 /*
2  * dirent.h - dirent API for Microsoft Visual Studio
3  *
4  * Copyright (C) 2006-2012 Toni Ronkko
5  *
6  * SPDX-License-Identifier: MIT
7  * See LICENSES/README.md for more information.
8  *
9  * Version 1.13, Dec 12 2012, Toni Ronkko
10  * Use traditional 8+3 file name if the name cannot be represented in the
11  * default ANSI code page. Now compiles again with MSVC 6.0. Thanks to
12  * Konstantin Khomoutov for testing.
13  *
14  * Version 1.12.1, Oct 1 2012, Toni Ronkko
15  * Bug fix: renamed wide-character DIR structure _wDIR to _WDIR (with
16  * capital W) in order to maintain compatibility with MingW.
17  *
18  * Version 1.12, Sep 30 2012, Toni Ronkko
19  * Define PATH_MAX and NAME_MAX. Added wide-character variants _wDIR,
20  * _wdirent, _wopendir(), _wreaddir(), _wclosedir() and _wrewinddir().
21  * Thanks to Edgar Buerkle and Jan Nijtmans for ideas and code.
22  *
23  * Do not include windows.h. This allows dirent.h to be integrated more
24  * easily into programs using winsock. Thanks to Fernando Azaldegui.
25  *
26  * Version 1.11, Mar 15, 2011, Toni Ronkko
27  * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
28  *
29  * Version 1.10, Aug 11, 2010, Toni Ronkko
30  * Added d_type and d_namlen fields to dirent structure. The former is
31  * especially useful for determining whether directory entry represents a
32  * file or a directory. For more information, see
33  * http://www.delorie.com/gnu/docs/glibc/libc_270.html
34  *
35  * Improved conformance to the standards. For example, errno is now set
36  * properly on failure and assert() is never used. Thanks to Peter Brockam
37  * for suggestions.
38  *
39  * Fixed a bug in rewinddir(): when using relative directory names, change
40  * of working directory no longer causes rewinddir() to fail.
41  *
42  * Version 1.9, Dec 15, 2009, John Cunningham
43  * Added rewinddir member function
44  *
45  * Version 1.8, Jan 18, 2008, Toni Ronkko
46  * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
47  * between multi-byte and unicode representations. This makes the
48  * code simpler and also allows the code to be compiled under MingW. Thanks
49  * to Azriel Fasten for the suggestion.
50  *
51  * Mar 4, 2007, Toni Ronkko
52  * Bug fix: due to the strncpy_s() function this file only compiled in
53  * Visual Studio 2005. Using the new string functions only when the
54  * compiler version allows.
55  *
56  * Nov 2, 2006, Toni Ronkko
57  * Major update: removed support for Watcom C, MS-DOS and Turbo C to
58  * simplify the file, updated the code to compile cleanly on Visual
59  * Studio 2005 with both unicode and multi-byte character strings,
60  * removed rewinddir() as it had a bug.
61  *
62  * Aug 20, 2006, Toni Ronkko
63  * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified
64  * comments by removing SGML tags.
65  *
66  * May 14 2002, Toni Ronkko
67  * Embedded the function definitions directly to the header so that no
68  * source modules need to be included in the Visual Studio project. Removed
69  * all the dependencies to other projects so that this header file can be
70  * used independently.
71  *
72  * May 28 1998, Toni Ronkko
73  * First version.
74  */
75 
76 #pragma once
77 
78 #if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86)
79 # define _X86_
80 #endif
81 #include <stdio.h>
82 #include <stdarg.h>
83 #include <windef.h>
84 #include <winbase.h>
85 #include <wchar.h>
86 #include <string.h>
87 #include <stdlib.h>
88 #include <malloc.h>
89 #include <sys/types.h>
90 #include <sys/stat.h>
91 #include <errno.h>
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 #if !defined(PATH_MAX)
156 # define PATH_MAX MAX_PATH
157 #endif
158 #if !defined(FILENAME_MAX)
159 # define FILENAME_MAX MAX_PATH
160 #endif
161 #if !defined(NAME_MAX)
162 # define NAME_MAX FILENAME_MAX
163 #endif
164 
165 /* File type flags for d_type */
166 #define DT_UNKNOWN 0
167 #define DT_REG S_IFREG
168 #define DT_DIR S_IFDIR
169 #define DT_FIFO S_IFIFO
170 #define DT_SOCK S_IFSOCK
171 #define DT_CHR S_IFCHR
172 #define DT_BLK S_IFBLK
173 
174 /* Macros for converting between st_mode and d_type */
175 #define IFTODT(mode) ((mode) & S_IFMT)
176 #define DTTOIF(type) (type)
177 
178 /*
179  * File type macros. Note that block devices, sockets and links cannot be
180  * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
181  * only defined for compatibility. These macros should always return false
182  * on Windows.
183  */
184 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
185 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
186 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
187 #define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
188 #define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
189 #define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
190 #define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
191 
192 /* Return the exact length of d_namlen without zero terminator */
193 #define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
194 
195 /* Return number of bytes needed to store d_namlen */
196 #define _D_ALLOC_NAMLEN(p) (PATH_MAX + 1)
197 
198 
199 #ifdef __cplusplus
200 extern "C" {
201 #endif
202 
203 
204 /* Wide-character version */
205 struct _wdirent {
206  long d_ino; /* Always zero */
207  unsigned short d_reclen; /* Structure size */
208  size_t d_namlen; /* Length of name without \0 */
209  int d_type; /* File type */
210  wchar_t d_name[PATH_MAX + 1]; /* File name */
211 };
212 typedef struct _wdirent _wdirent;
213 
214 struct _WDIR {
215  struct _wdirent ent; /* Current directory entry */
216  WIN32_FIND_DATAW data; /* Private file data */
217  int cached; /* True if data is valid */
218  HANDLE handle; /* Win32 search handle */
219  wchar_t *patt; /* Initial directory name */
220 };
221 typedef struct _WDIR _WDIR;
222 
223 static _WDIR *_wopendir (const wchar_t *dirname);
224 static struct _wdirent *_wreaddir (_WDIR *dirp);
225 static int _wclosedir (_WDIR *dirp);
226 static void _wrewinddir (_WDIR* dirp);
227 
228 
229 /* For compatibility with Symbian */
230 #define wdirent _wdirent
231 #define WDIR _WDIR
232 #define wopendir _wopendir
233 #define wreaddir _wreaddir
234 #define wclosedir _wclosedir
235 #define wrewinddir _wrewinddir
236 
237 
238 /* Multi-byte character versions */
239 struct dirent {
240  long d_ino; /* Always zero */
241  unsigned short d_reclen; /* Structure size */
242  size_t d_namlen; /* Length of name without \0 */
243  int d_type; /* File type */
244  char d_name[PATH_MAX + 1]; /* File name */
245 };
246 typedef struct dirent dirent;
247 
248 struct DIR {
249  struct dirent ent;
250  struct _WDIR *wdirp;
251 };
252 typedef struct DIR DIR;
253 
254 static DIR *opendir (const char *dirname);
255 static struct dirent *readdir (DIR *dirp);
256 static int closedir (DIR *dirp);
257 static void rewinddir (DIR* dirp);
258 
259 
260 /* Internal utility functions */
261 static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
262 static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
263 
264 static int dirent_mbstowcs_s(
265  size_t *pReturnValue,
266  wchar_t *wcstr,
267  size_t sizeInWords,
268  const char *mbstr,
269  size_t count);
270 
271 static int dirent_wcstombs_s(
272  size_t *pReturnValue,
273  char *mbstr,
274  size_t sizeInBytes,
275  const wchar_t *wcstr,
276  size_t count);
277 
278 static void dirent_set_errno (int error);
279 
280 /*
281  * Open directory stream DIRNAME for read and return a pointer to the
282  * internal working area that is used to retrieve individual directory
283  * entries.
284  */
285 static _WDIR*
286 _wopendir(
287  const wchar_t *dirname)
288 {
289  _WDIR *dirp = NULL;
290  int error;
291 
292  /* Must have directory name */
293  if (dirname == NULL || dirname[0] == '\0') {
294  dirent_set_errno (ENOENT);
295  return NULL;
296  }
297 
298  /* Allocate new _WDIR structure */
299  dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
300  if (dirp != NULL) {
301  DWORD n;
302 
303  /* Reset _WDIR structure */
304  dirp->handle = INVALID_HANDLE_VALUE;
305  dirp->patt = NULL;
306  dirp->cached = 0;
307 
308  /* Compute the length of full path plus zero terminator */
309  n = GetFullPathNameW (dirname, 0, NULL, NULL);
310 
311  /* Allocate room for absolute directory name and search pattern */
312  dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
313  if (dirp->patt) {
314 
315  /*
316  * Convert relative directory name to an absolute one. This
317  * allows rewinddir() to function correctly even when current
318  * working directory is changed between opendir() and rewinddir().
319  */
320  n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
321  if (n > 0) {
322  wchar_t *p;
323 
324  /* Append search pattern \* to the directory name */
325  p = dirp->patt + n;
326  if (dirp->patt < p) {
327  switch (p[-1]) {
328  case '\\':
329  case '/':
330  case ':':
331  /* Directory ends in path separator, e.g. c:\temp\ */
332  /*NOP*/;
333  break;
334 
335  default:
336  /* Directory name doesn't end in path separator */
337  *p++ = '\\';
338  }
339  }
340  *p++ = '*';
341  *p = '\0';
342 
343  /* Open directory stream and retrieve the first entry */
344  if (dirent_first (dirp)) {
345  /* Directory stream opened successfully */
346  error = 0;
347  } else {
348  /* Cannot retrieve first entry */
349  error = 1;
350  dirent_set_errno (ENOENT);
351  }
352 
353  } else {
354  /* Cannot retrieve full path name */
355  dirent_set_errno (ENOENT);
356  error = 1;
357  }
358 
359  } else {
360  /* Cannot allocate memory for search pattern */
361  error = 1;
362  }
363 
364  } else {
365  /* Cannot allocate _WDIR structure */
366  error = 1;
367  }
368 
369  /* Clean up in case of error */
370  if (error && dirp) {
371  _wclosedir (dirp);
372  dirp = NULL;
373  }
374 
375  return dirp;
376 }
377 
378 /*
379  * Read next directory entry. The directory entry is returned in dirent
380  * structure in the d_name field. Individual directory entries returned by
381  * this function include regular files, sub-directories, pseudo-directories
382  * "." and ".." as well as volume labels, hidden files and system files.
383  */
384 static struct _wdirent*
385 _wreaddir(
386  _WDIR *dirp)
387 {
388  WIN32_FIND_DATAW *datap;
389  struct _wdirent *entp;
390 
391  /* Read next directory entry */
392  datap = dirent_next (dirp);
393  if (datap) {
394  size_t n;
395  DWORD attr;
396 
397  /* Pointer to directory entry to return */
398  entp = &dirp->ent;
399 
400  /*
401  * Copy file name as wide-character string. If the file name is too
402  * long to fit in to the destination buffer, then truncate file name
403  * to PATH_MAX characters and zero-terminate the buffer.
404  */
405  n = 0;
406  while (n < PATH_MAX && datap->cFileName[n] != 0) {
407  entp->d_name[n] = datap->cFileName[n];
408  n++;
409  }
410  dirp->ent.d_name[n] = 0;
411 
412  /* Length of file name excluding zero terminator */
413  entp->d_namlen = n;
414 
415  /* File type */
416  attr = datap->dwFileAttributes;
417  if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
418  entp->d_type = DT_CHR;
419  } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
420  entp->d_type = DT_DIR;
421  } else {
422  entp->d_type = DT_REG;
423  }
424 
425  /* Reset dummy fields */
426  entp->d_ino = 0;
427  entp->d_reclen = sizeof (struct _wdirent);
428 
429  } else {
430 
431  /* Last directory entry read */
432  entp = NULL;
433 
434  }
435 
436  return entp;
437 }
438 
439 /*
440  * Close directory stream opened by opendir() function. This invalidates the
441  * DIR structure as well as any directory entry read previously by
442  * _wreaddir().
443  */
444 static int
445 _wclosedir(
446  _WDIR *dirp)
447 {
448  int ok;
449  if (dirp) {
450 
451  /* Release search handle */
452  if (dirp->handle != INVALID_HANDLE_VALUE) {
453  FindClose (dirp->handle);
454  dirp->handle = INVALID_HANDLE_VALUE;
455  }
456 
457  /* Release search pattern */
458  if (dirp->patt) {
459  free (dirp->patt);
460  dirp->patt = NULL;
461  }
462 
463  /* Release directory structure */
464  free (dirp);
465  ok = /*success*/0;
466 
467  } else {
468  /* Invalid directory stream */
469  dirent_set_errno (EBADF);
470  ok = /*failure*/-1;
471  }
472  return ok;
473 }
474 
475 /*
476  * Rewind directory stream such that _wreaddir() returns the very first
477  * file name again.
478  */
479 static void
480 _wrewinddir(
481  _WDIR* dirp)
482 {
483  if (dirp) {
484  /* Release existing search handle */
485  if (dirp->handle != INVALID_HANDLE_VALUE) {
486  FindClose (dirp->handle);
487  }
488 
489  /* Open new search handle */
490  dirent_first (dirp);
491  }
492 }
493 
494 /* Get first directory entry (internal) */
495 static WIN32_FIND_DATAW*
496 dirent_first(
497  _WDIR *dirp)
498 {
499  WIN32_FIND_DATAW *datap;
500 
501  /* Open directory and retrieve the first entry */
502  dirp->handle = FindFirstFileW (dirp->patt, &dirp->data);
503  if (dirp->handle != INVALID_HANDLE_VALUE) {
504 
505  /* a directory entry is now waiting in memory */
506  datap = &dirp->data;
507  dirp->cached = 1;
508 
509  } else {
510 
511  /* Failed to re-open directory: no directory entry in memory */
512  dirp->cached = 0;
513  datap = NULL;
514 
515  }
516  return datap;
517 }
518 
519 /* Get next directory entry (internal) */
520 static WIN32_FIND_DATAW*
521 dirent_next(
522  _WDIR *dirp)
523 {
524  WIN32_FIND_DATAW *p;
525 
526  /* Get next directory entry */
527  if (dirp->cached != 0) {
528 
529  /* A valid directory entry already in memory */
530  p = &dirp->data;
531  dirp->cached = 0;
532 
533  } else if (dirp->handle != INVALID_HANDLE_VALUE) {
534 
535  /* Get the next directory entry from stream */
536  if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
537  /* Got a file */
538  p = &dirp->data;
539  } else {
540  /* The very last entry has been processed or an error occurred */
541  FindClose (dirp->handle);
542  dirp->handle = INVALID_HANDLE_VALUE;
543  p = NULL;
544  }
545 
546  } else {
547 
548  /* End of directory stream reached */
549  p = NULL;
550 
551  }
552 
553  return p;
554 }
555 
556 /*
557  * Open directory stream using plain old C-string.
558  */
559 static DIR*
560 opendir(
561  const char *dirname)
562 {
563  struct DIR *dirp;
564  int error;
565 
566  /* Must have directory name */
567  if (dirname == NULL || dirname[0] == '\0') {
568  dirent_set_errno (ENOENT);
569  return NULL;
570  }
571 
572  /* Allocate memory for DIR structure */
573  dirp = (DIR*) malloc (sizeof (struct DIR));
574  if (dirp) {
575  wchar_t wname[PATH_MAX + 1];
576  size_t n;
577 
578  /* Convert directory name to wide-character string */
579  error = dirent_mbstowcs_s(
580  &n, wname, PATH_MAX + 1, dirname, PATH_MAX);
581  if (!error) {
582 
583  /* Open directory stream using wide-character name */
584  dirp->wdirp = _wopendir (wname);
585  if (dirp->wdirp) {
586  /* Directory stream opened */
587  error = 0;
588  } else {
589  /* Failed to open directory stream */
590  error = 1;
591  }
592 
593  } else {
594  /*
595  * Cannot convert file name to wide-character string. This
596  * occurs if the string contains invalid multi-byte sequences or
597  * the output buffer is too small to contain the resulting
598  * string.
599  */
600  error = 1;
601  }
602 
603  } else {
604  /* Cannot allocate DIR structure */
605  error = 1;
606  }
607 
608  /* Clean up in case of error */
609  if (error && dirp) {
610  free (dirp);
611  dirp = NULL;
612  }
613 
614  return dirp;
615 }
616 
617 /*
618  * Read next directory entry.
619  *
620  * When working with text consoles, please note that file names returned by
621  * readdir() are represented in the default ANSI code page while any output to
622  * console is typically formatted on another code page. Thus, non-ASCII
623  * characters in file names will not usually display correctly on console. The
624  * problem can be fixed in two ways: (1) change the character set of console
625  * to 1252 using chcp utility and use Lucida Console font, or (2) use
626  * _cprintf function when writing to console. The _cprinf() will re-encode
627  * ANSI strings to the console code page so many non-ASCII characters will
628  * display correctly.
629  */
630 static struct dirent*
631 readdir(
632  DIR *dirp)
633 {
634  WIN32_FIND_DATAW *datap;
635  struct dirent *entp;
636 
637  /* Read next directory entry */
638  datap = dirent_next (dirp->wdirp);
639  if (datap) {
640  size_t n;
641  int error;
642 
643  /* Attempt to convert file name to multi-byte string */
644  error = dirent_wcstombs_s(
645  &n, dirp->ent.d_name, MAX_PATH + 1, datap->cFileName, MAX_PATH);
646 
647  /*
648  * If the file name cannot be represented by a multi-byte string,
649  * then attempt to use old 8+3 file name. This allows traditional
650  * Unix-code to access some file names despite of unicode
651  * characters, although file names may seem unfamiliar to the user.
652  *
653  * Be ware that the code below cannot come up with a short file
654  * name unless the file system provides one. At least
655  * VirtualBox shared folders fail to do this.
656  */
657  if (error && datap->cAlternateFileName[0] != '\0') {
658  error = dirent_wcstombs_s(
659  &n, dirp->ent.d_name, MAX_PATH + 1, datap->cAlternateFileName,
660  sizeof (datap->cAlternateFileName) /
661  sizeof (datap->cAlternateFileName[0]));
662  }
663 
664  if (!error) {
665  DWORD attr;
666 
667  /* Initialize directory entry for return */
668  entp = &dirp->ent;
669 
670  /* Length of file name excluding zero terminator */
671  entp->d_namlen = n - 1;
672 
673  /* File attributes */
674  attr = datap->dwFileAttributes;
675  if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
676  entp->d_type = DT_CHR;
677  } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
678  entp->d_type = DT_DIR;
679  } else {
680  entp->d_type = DT_REG;
681  }
682 
683  /* Reset dummy fields */
684  entp->d_ino = 0;
685  entp->d_reclen = sizeof (struct dirent);
686 
687  } else {
688  /*
689  * Cannot convert file name to multi-byte string so construct
690  * an erroneous directory entry and return that. Note that
691  * we cannot return NULL as that would stop the processing
692  * of directory entries completely.
693  */
694  entp = &dirp->ent;
695  entp->d_name[0] = '?';
696  entp->d_name[1] = '\0';
697  entp->d_namlen = 1;
698  entp->d_type = DT_UNKNOWN;
699  entp->d_ino = 0;
700  entp->d_reclen = 0;
701  }
702 
703  } else {
704  /* No more directory entries */
705  entp = NULL;
706  }
707 
708  return entp;
709 }
710 
711 /*
712  * Close directory stream.
713  */
714 static int
715 closedir(
716  DIR *dirp)
717 {
718  int ok;
719  if (dirp) {
720 
721  /* Close wide-character directory stream */
722  ok = _wclosedir (dirp->wdirp);
723  dirp->wdirp = NULL;
724 
725  /* Release multi-byte character version */
726  free (dirp);
727 
728  } else {
729 
730  /* Invalid directory stream */
731  dirent_set_errno (EBADF);
732  ok = /*failure*/-1;
733 
734  }
735  return ok;
736 }
737 
738 /*
739  * Rewind directory stream to beginning.
740  */
741 static void
742 rewinddir(
743  DIR* dirp)
744 {
745  /* Rewind wide-character string directory stream */
746  _wrewinddir (dirp->wdirp);
747 }
748 
749 /* Convert multi-byte string to wide character string */
750 static int
751 dirent_mbstowcs_s(
752  size_t *pReturnValue,
753  wchar_t *wcstr,
754  size_t sizeInWords,
755  const char *mbstr,
756  size_t count)
757 {
758  int error;
759 
760 #if defined(_MSC_VER) && _MSC_VER >= 1400
761 
762  /* Microsoft Visual Studio 2005 or later */
763  error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
764 
765 #else
766 
767  /* Older Visual Studio or non-Microsoft compiler */
768  size_t n;
769 
770  /* Convert to wide-character string */
771  n = mbstowcs (wcstr, mbstr, count);
772  if (n < sizeInWords) {
773 
774  /* Zero-terminate output buffer */
775  if (wcstr) {
776  wcstr[n] = 0;
777  }
778 
779  /* Length of resulting multi-byte string WITH zero terminator */
780  if (pReturnValue) {
781  *pReturnValue = n + 1;
782  }
783 
784  /* Success */
785  error = 0;
786 
787  } else {
788 
789  /* Could not convert string */
790  error = 1;
791 
792  }
793 
794 #endif
795 
796  return error;
797 }
798 
799 /* Convert wide-character string to multi-byte string */
800 static int
801 dirent_wcstombs_s(
802  size_t *pReturnValue,
803  char *mbstr,
804  size_t sizeInBytes,
805  const wchar_t *wcstr,
806  size_t count)
807 {
808  int error;
809 
810 #if defined(_MSC_VER) && _MSC_VER >= 1400
811 
812  /* Microsoft Visual Studio 2005 or later */
813  error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
814 
815 #else
816 
817  /* Older Visual Studio or non-Microsoft compiler */
818  size_t n;
819 
820  /* Convert to multi-byte string */
821  n = wcstombs (mbstr, wcstr, count);
822  if (n < sizeInBytes) {
823 
824  /* Zero-terminate output buffer */
825  if (mbstr) {
826  mbstr[n] = '\0';
827  }
828 
829  /* Length of resulting multi-bytes string WITH zero-terminator */
830  if (pReturnValue) {
831  *pReturnValue = n + 1;
832  }
833 
834  /* Success */
835  error = 0;
836 
837  } else {
838 
839  /* Cannot convert string */
840  error = 1;
841 
842  }
843 
844 #endif
845 
846  return error;
847 }
848 
849 /* Set errno variable */
850 static void
851 dirent_set_errno(
852  int error)
853 {
854 #if defined(_MSC_VER)
855 
856  /* Microsoft Visual Studio */
857  _set_errno (error);
858 
859 #else
860 
861  /* Non-Microsoft compiler */
862  errno = error;
863 
864 #endif
865 }
866 
867 
868 #ifdef __cplusplus
869 }
870 #endif
871 
Definition: XHandle.h:21
Definition: dirent.h:39
Definition: dirent.c:34
Definition: dirent.h:205
Definition: dirent.h:214