aboutsummaryrefslogtreecommitdiff
path: root/include/compat/dirent_msvc.h
diff options
context:
space:
mode:
authorBrent Cook <busterb@gmail.com>2014-07-10 22:06:10 -0500
committerBrent Cook <bcook@openbsd.org>2015-07-21 12:08:18 -0500
commit5d8a1cf7155130bd8101090d7e1d0c2f90d9b123 (patch)
tree286f7d12e3647f94bd1e6e8e180a4bf6215a0740 /include/compat/dirent_msvc.h
parent7a4a37cf596697ae96eeb1c555989e6d1a443187 (diff)
downloadportable-5d8a1cf7155130bd8101090d7e1d0c2f90d9b123.tar.gz
portable-5d8a1cf7155130bd8101090d7e1d0c2f90d9b123.tar.bz2
portable-5d8a1cf7155130bd8101090d7e1d0c2f90d9b123.zip
add initial CMake and Visual Studio build support
This moves the compatibility include files from include to include/compat so we can use the awful MS C compiler <../include/> trick to emulate the GNU #include_next extension. This also removes a few old compat files we do not need anymore.
Diffstat (limited to 'include/compat/dirent_msvc.h')
-rw-r--r--include/compat/dirent_msvc.h748
1 files changed, 748 insertions, 0 deletions
diff --git a/include/compat/dirent_msvc.h b/include/compat/dirent_msvc.h
new file mode 100644
index 0000000..bf9cf1a
--- /dev/null
+++ b/include/compat/dirent_msvc.h
@@ -0,0 +1,748 @@
1/*
2 * dirent.h - dirent API for Microsoft Visual Studio
3 *
4 * Copyright (C) 2006-2012 Toni Ronkko
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * ``Software''), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 *
25 * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $
26 */
27#ifndef DIRENT_MSVC_H
28#define DIRENT_MSVC_H
29
30#include <windows.h>
31
32#include <../include/stdio.h>
33#include <../include/stdarg.h>
34#include <../include/wchar.h>
35#include <../include/string.h>
36#include <../include/stdlib.h>
37#include <../include/malloc.h>
38#include <../include/sys/types.h>
39#include <sys/stat.h>
40#include <../include/errno.h>
41
42/* Indicates that d_type field is available in dirent structure */
43#define _DIRENT_HAVE_D_TYPE
44
45/* Indicates that d_namlen field is available in dirent structure */
46#define _DIRENT_HAVE_D_NAMLEN
47
48/* Entries missing from MSVC 6.0 */
49#if !defined(FILE_ATTRIBUTE_DEVICE)
50# define FILE_ATTRIBUTE_DEVICE 0x40
51#endif
52
53/* Maximum length of file name */
54#if !defined(PATH_MAX)
55# define PATH_MAX MAX_PATH
56#endif
57#if !defined(FILENAME_MAX)
58# define FILENAME_MAX MAX_PATH
59#endif
60#if !defined(NAME_MAX)
61# define NAME_MAX FILENAME_MAX
62#endif
63
64/* Return the exact length of d_namlen without zero terminator */
65#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
66
67/* Return number of bytes needed to store d_namlen */
68#define _D_ALLOC_NAMLEN(p) (PATH_MAX)
69
70
71#ifdef __cplusplus
72extern "C" {
73#endif
74
75
76/* Wide-character version */
77struct _wdirent {
78 long d_ino; /* Always zero */
79 unsigned short d_reclen; /* Structure size */
80 size_t d_namlen; /* Length of name without \0 */
81 int d_type; /* File type */
82 wchar_t d_name[PATH_MAX]; /* File name */
83};
84typedef struct _wdirent _wdirent;
85
86struct _WDIR {
87 struct _wdirent ent; /* Current directory entry */
88 WIN32_FIND_DATAW data; /* Private file data */
89 int cached; /* True if data is valid */
90 HANDLE handle; /* Win32 search handle */
91 wchar_t *patt; /* Initial directory name */
92};
93typedef struct _WDIR _WDIR;
94
95static _WDIR *_wopendir (const wchar_t *dirname);
96static struct _wdirent *_wreaddir (_WDIR *dirp);
97static int _wclosedir (_WDIR *dirp);
98static void _wrewinddir (_WDIR* dirp);
99
100
101/* For compatibility with Symbian */
102#define wdirent _wdirent
103#define WDIR _WDIR
104#define wopendir _wopendir
105#define wreaddir _wreaddir
106#define wclosedir _wclosedir
107#define wrewinddir _wrewinddir
108
109
110/* Multi-byte character versions */
111struct dirent {
112 long d_ino; /* Always zero */
113 unsigned short d_reclen; /* Structure size */
114 size_t d_namlen; /* Length of name without \0 */
115 int d_type; /* File type */
116 char d_name[PATH_MAX]; /* File name */
117};
118typedef struct dirent dirent;
119
120struct DIR {
121 struct dirent ent;
122 struct _WDIR *wdirp;
123};
124typedef struct DIR DIR;
125
126static DIR *opendir (const char *dirname);
127static struct dirent *readdir (DIR *dirp);
128static int closedir (DIR *dirp);
129static void rewinddir (DIR* dirp);
130
131
132/* Internal utility functions */
133static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
134static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
135
136static int dirent_mbstowcs_s(
137 size_t *pReturnValue,
138 wchar_t *wcstr,
139 size_t sizeInWords,
140 const char *mbstr,
141 size_t count);
142
143static int dirent_wcstombs_s(
144 size_t *pReturnValue,
145 char *mbstr,
146 size_t sizeInBytes,
147 const wchar_t *wcstr,
148 size_t count);
149
150static void dirent_set_errno (int error);
151
152/*
153 * Open directory stream DIRNAME for read and return a pointer to the
154 * internal working area that is used to retrieve individual directory
155 * entries.
156 */
157static _WDIR*
158_wopendir(
159 const wchar_t *dirname)
160{
161 _WDIR *dirp = NULL;
162 int error;
163
164 /* Must have directory name */
165 if (dirname == NULL || dirname[0] == '\0') {
166 dirent_set_errno (ENOENT);
167 return NULL;
168 }
169
170 /* Allocate new _WDIR structure */
171 dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
172 if (dirp != NULL) {
173 DWORD n;
174
175 /* Reset _WDIR structure */
176 dirp->handle = INVALID_HANDLE_VALUE;
177 dirp->patt = NULL;
178 dirp->cached = 0;
179
180 /* Compute the length of full path plus zero terminator */
181 n = GetFullPathNameW (dirname, 0, NULL, NULL);
182
183 /* Allocate room for absolute directory name and search pattern */
184 dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
185 if (dirp->patt) {
186
187 /*
188 * Convert relative directory name to an absolute one. This
189 * allows rewinddir() to function correctly even when current
190 * working directory is changed between opendir() and rewinddir().
191 */
192 n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
193 if (n > 0) {
194 wchar_t *p;
195
196 /* Append search pattern \* to the directory name */
197 p = dirp->patt + n;
198 if (dirp->patt < p) {
199 switch (p[-1]) {
200 case '\\':
201 case '/':
202 case ':':
203 /* Directory ends in path separator, e.g. c:\temp\ */
204 /*NOP*/;
205 break;
206
207 default:
208 /* Directory name doesn't end in path separator */
209 *p++ = '\\';
210 }
211 }
212 *p++ = '*';
213 *p = '\0';
214
215 /* Open directory stream and retrieve the first entry */
216 if (dirent_first (dirp)) {
217 /* Directory stream opened successfully */
218 error = 0;
219 } else {
220 /* Cannot retrieve first entry */
221 error = 1;
222 dirent_set_errno (ENOENT);
223 }
224
225 } else {
226 /* Cannot retrieve full path name */
227 dirent_set_errno (ENOENT);
228 error = 1;
229 }
230
231 } else {
232 /* Cannot allocate memory for search pattern */
233 error = 1;
234 }
235
236 } else {
237 /* Cannot allocate _WDIR structure */
238 error = 1;
239 }
240
241 /* Clean up in case of error */
242 if (error && dirp) {
243 _wclosedir (dirp);
244 dirp = NULL;
245 }
246
247 return dirp;
248}
249
250/*
251 * Read next directory entry. The directory entry is returned in dirent
252 * structure in the d_name field. Individual directory entries returned by
253 * this function include regular files, sub-directories, pseudo-directories
254 * "." and ".." as well as volume labels, hidden files and system files.
255 */
256static struct _wdirent*
257_wreaddir(
258 _WDIR *dirp)
259{
260 WIN32_FIND_DATAW *datap;
261 struct _wdirent *entp;
262
263 /* Read next directory entry */
264 datap = dirent_next (dirp);
265 if (datap) {
266 size_t n;
267 DWORD attr;
268
269 /* Pointer to directory entry to return */
270 entp = &dirp->ent;
271
272 /*
273 * Copy file name as wide-character string. If the file name is too
274 * long to fit in to the destination buffer, then truncate file name
275 * to PATH_MAX characters and zero-terminate the buffer.
276 */
277 n = 0;
278 while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) {
279 entp->d_name[n] = datap->cFileName[n];
280 n++;
281 }
282 dirp->ent.d_name[n] = 0;
283
284 /* Length of file name excluding zero terminator */
285 entp->d_namlen = n;
286
287 /* File type */
288 attr = datap->dwFileAttributes;
289 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
290 entp->d_type = DT_CHR;
291 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
292 entp->d_type = DT_DIR;
293 } else {
294 entp->d_type = DT_REG;
295 }
296
297 /* Reset dummy fields */
298 entp->d_ino = 0;
299 entp->d_reclen = sizeof (struct _wdirent);
300
301 } else {
302
303 /* Last directory entry read */
304 entp = NULL;
305
306 }
307
308 return entp;
309}
310
311/*
312 * Close directory stream opened by opendir() function. This invalidates the
313 * DIR structure as well as any directory entry read previously by
314 * _wreaddir().
315 */
316static int
317_wclosedir(
318 _WDIR *dirp)
319{
320 int ok;
321 if (dirp) {
322
323 /* Release search handle */
324 if (dirp->handle != INVALID_HANDLE_VALUE) {
325 FindClose (dirp->handle);
326 dirp->handle = INVALID_HANDLE_VALUE;
327 }
328
329 /* Release search pattern */
330 if (dirp->patt) {
331 free (dirp->patt);
332 dirp->patt = NULL;
333 }
334
335 /* Release directory structure */
336 free (dirp);
337 ok = /*success*/0;
338
339 } else {
340 /* Invalid directory stream */
341 dirent_set_errno (EBADF);
342 ok = /*failure*/-1;
343 }
344 return ok;
345}
346
347/*
348 * Rewind directory stream such that _wreaddir() returns the very first
349 * file name again.
350 */
351static void
352_wrewinddir(
353 _WDIR* dirp)
354{
355 if (dirp) {
356 /* Release existing search handle */
357 if (dirp->handle != INVALID_HANDLE_VALUE) {
358 FindClose (dirp->handle);
359 }
360
361 /* Open new search handle */
362 dirent_first (dirp);
363 }
364}
365
366/* Get first directory entry (internal) */
367static WIN32_FIND_DATAW*
368dirent_first(
369 _WDIR *dirp)
370{
371 WIN32_FIND_DATAW *datap;
372
373 /* Open directory and retrieve the first entry */
374 dirp->handle = FindFirstFileW (dirp->patt, &dirp->data);
375 if (dirp->handle != INVALID_HANDLE_VALUE) {
376
377 /* a directory entry is now waiting in memory */
378 datap = &dirp->data;
379 dirp->cached = 1;
380
381 } else {
382
383 /* Failed to re-open directory: no directory entry in memory */
384 dirp->cached = 0;
385 datap = NULL;
386
387 }
388 return datap;
389}
390
391/* Get next directory entry (internal) */
392static WIN32_FIND_DATAW*
393dirent_next(
394 _WDIR *dirp)
395{
396 WIN32_FIND_DATAW *p;
397
398 /* Get next directory entry */
399 if (dirp->cached != 0) {
400
401 /* A valid directory entry already in memory */
402 p = &dirp->data;
403 dirp->cached = 0;
404
405 } else if (dirp->handle != INVALID_HANDLE_VALUE) {
406
407 /* Get the next directory entry from stream */
408 if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
409 /* Got a file */
410 p = &dirp->data;
411 } else {
412 /* The very last entry has been processed or an error occured */
413 FindClose (dirp->handle);
414 dirp->handle = INVALID_HANDLE_VALUE;
415 p = NULL;
416 }
417
418 } else {
419
420 /* End of directory stream reached */
421 p = NULL;
422
423 }
424
425 return p;
426}
427
428/*
429 * Open directory stream using plain old C-string.
430 */
431static DIR*
432opendir(
433 const char *dirname)
434{
435 struct DIR *dirp;
436 int error;
437
438 /* Must have directory name */
439 if (dirname == NULL || dirname[0] == '\0') {
440 dirent_set_errno (ENOENT);
441 return NULL;
442 }
443
444 /* Allocate memory for DIR structure */
445 dirp = (DIR*) malloc (sizeof (struct DIR));
446 if (dirp) {
447 wchar_t wname[PATH_MAX];
448 size_t n;
449
450 /* Convert directory name to wide-character string */
451 error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX);
452 if (!error) {
453
454 /* Open directory stream using wide-character name */
455 dirp->wdirp = _wopendir (wname);
456 if (dirp->wdirp) {
457 /* Directory stream opened */
458 error = 0;
459 } else {
460 /* Failed to open directory stream */
461 error = 1;
462 }
463
464 } else {
465 /*
466 * Cannot convert file name to wide-character string. This
467 * occurs if the string contains invalid multi-byte sequences or
468 * the output buffer is too small to contain the resulting
469 * string.
470 */
471 error = 1;
472 }
473
474 } else {
475 /* Cannot allocate DIR structure */
476 error = 1;
477 }
478
479 /* Clean up in case of error */
480 if (error && dirp) {
481 free (dirp);
482 dirp = NULL;
483 }
484
485 return dirp;
486}
487
488/*
489 * Read next directory entry.
490 *
491 * When working with text consoles, please note that file names returned by
492 * readdir() are represented in the default ANSI code page while any output to
493 * console is typically formatted on another code page. Thus, non-ASCII
494 * characters in file names will not usually display correctly on console. The
495 * problem can be fixed in two ways: (1) change the character set of console
496 * to 1252 using chcp utility and use Lucida Console font, or (2) use
497 * _cprintf function when writing to console. The _cprinf() will re-encode
498 * ANSI strings to the console code page so many non-ASCII characters will
499 * display correcly.
500 */
501static struct dirent*
502readdir(
503 DIR *dirp)
504{
505 WIN32_FIND_DATAW *datap;
506 struct dirent *entp;
507
508 /* Read next directory entry */
509 datap = dirent_next (dirp->wdirp);
510 if (datap) {
511 size_t n;
512 int error;
513
514 /* Attempt to convert file name to multi-byte string */
515 error = dirent_wcstombs_s(
516 &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX);
517
518 /*
519 * If the file name cannot be represented by a multi-byte string,
520 * then attempt to use old 8+3 file name. This allows traditional
521 * Unix-code to access some file names despite of unicode
522 * characters, although file names may seem unfamiliar to the user.
523 *
524 * Be ware that the code below cannot come up with a short file
525 * name unless the file system provides one. At least
526 * VirtualBox shared folders fail to do this.
527 */
528 if (error && datap->cAlternateFileName[0] != '\0') {
529 error = dirent_wcstombs_s(
530 &n, dirp->ent.d_name, PATH_MAX,
531 datap->cAlternateFileName, PATH_MAX);
532 }
533
534 if (!error) {
535 DWORD attr;
536
537 /* Initialize directory entry for return */
538 entp = &dirp->ent;
539
540 /* Length of file name excluding zero terminator */
541 entp->d_namlen = n - 1;
542
543 /* File attributes */
544 attr = datap->dwFileAttributes;
545 if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
546 entp->d_type = DT_CHR;
547 } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
548 entp->d_type = DT_DIR;
549 } else {
550 entp->d_type = DT_REG;
551 }
552
553 /* Reset dummy fields */
554 entp->d_ino = 0;
555 entp->d_reclen = sizeof (struct dirent);
556
557 } else {
558 /*
559 * Cannot convert file name to multi-byte string so construct
560 * an errornous directory entry and return that. Note that
561 * we cannot return NULL as that would stop the processing
562 * of directory entries completely.
563 */
564 entp = &dirp->ent;
565 entp->d_name[0] = '?';
566 entp->d_name[1] = '\0';
567 entp->d_namlen = 1;
568 entp->d_type = DT_UNKNOWN;
569 entp->d_ino = 0;
570 entp->d_reclen = 0;
571 }
572
573 } else {
574 /* No more directory entries */
575 entp = NULL;
576 }
577
578 return entp;
579}
580
581/*
582 * Close directory stream.
583 */
584static int
585closedir(
586 DIR *dirp)
587{
588 int ok;
589 if (dirp) {
590
591 /* Close wide-character directory stream */
592 ok = _wclosedir (dirp->wdirp);
593 dirp->wdirp = NULL;
594
595 /* Release multi-byte character version */
596 free (dirp);
597
598 } else {
599
600 /* Invalid directory stream */
601 dirent_set_errno (EBADF);
602 ok = /*failure*/-1;
603
604 }
605 return ok;
606}
607
608/*
609 * Rewind directory stream to beginning.
610 */
611static void
612rewinddir(
613 DIR* dirp)
614{
615 /* Rewind wide-character string directory stream */
616 _wrewinddir (dirp->wdirp);
617}
618
619/* Convert multi-byte string to wide character string */
620static int
621dirent_mbstowcs_s(
622 size_t *pReturnValue,
623 wchar_t *wcstr,
624 size_t sizeInWords,
625 const char *mbstr,
626 size_t count)
627{
628 int error;
629
630#if defined(_MSC_VER) && _MSC_VER >= 1400
631
632 /* Microsoft Visual Studio 2005 or later */
633 error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
634
635#else
636
637 /* Older Visual Studio or non-Microsoft compiler */
638 size_t n;
639
640 /* Convert to wide-character string (or count characters) */
641 n = mbstowcs (wcstr, mbstr, sizeInWords);
642 if (!wcstr || n < count) {
643
644 /* Zero-terminate output buffer */
645 if (wcstr && sizeInWords) {
646 if (n >= sizeInWords) {
647 n = sizeInWords - 1;
648 }
649 wcstr[n] = 0;
650 }
651
652 /* Length of resuting multi-byte string WITH zero terminator */
653 if (pReturnValue) {
654 *pReturnValue = n + 1;
655 }
656
657 /* Success */
658 error = 0;
659
660 } else {
661
662 /* Could not convert string */
663 error = 1;
664
665 }
666
667#endif
668
669 return error;
670}
671
672/* Convert wide-character string to multi-byte string */
673static int
674dirent_wcstombs_s(
675 size_t *pReturnValue,
676 char *mbstr,
677 size_t sizeInBytes, /* max size of mbstr */
678 const wchar_t *wcstr,
679 size_t count)
680{
681 int error;
682
683#if defined(_MSC_VER) && _MSC_VER >= 1400
684
685 /* Microsoft Visual Studio 2005 or later */
686 error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
687
688#else
689
690 /* Older Visual Studio or non-Microsoft compiler */
691 size_t n;
692
693 /* Convert to multi-byte string (or count the number of bytes needed) */
694 n = wcstombs (mbstr, wcstr, sizeInBytes);
695 if (!mbstr || n < count) {
696
697 /* Zero-terminate output buffer */
698 if (mbstr && sizeInBytes) {
699 if (n >= sizeInBytes) {
700 n = sizeInBytes - 1;
701 }
702 mbstr[n] = '\0';
703 }
704
705 /* Lenght of resulting multi-bytes string WITH zero-terminator */
706 if (pReturnValue) {
707 *pReturnValue = n + 1;
708 }
709
710 /* Success */
711 error = 0;
712
713 } else {
714
715 /* Cannot convert string */
716 error = 1;
717
718 }
719
720#endif
721
722 return error;
723}
724
725/* Set errno variable */
726static void
727dirent_set_errno(
728 int error)
729{
730#if defined(_MSC_VER) && _MSC_VER >= 1400
731
732 /* Microsoft Visual Studio 2005 and later */
733 _set_errno (error);
734
735#else
736
737 /* Non-Microsoft compiler or older Microsoft compiler */
738 errno = error;
739
740#endif
741}
742
743
744#ifdef __cplusplus
745}
746#endif
747#endif /*DIRENT_H*/
748