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