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