diff options
author | 2019-10-13 13:50:38 +0200 | |
---|---|---|
committer | 2019-10-13 07:50:38 -0400 | |
commit | 0837e7451a84f95c29dbdb9bd6b8b931fee1635d (patch) | |
tree | 626bcbd250a7fbebdf5958a288d2f438d4f9fb5a /3rdparty/bx/include/compat/msvc/dirent.h | |
parent | c913ccb59d713ce0b91135520719ac5385e54358 (diff) |
WIP: sync bgfx, bx and bimg with latest upstream (#5723)
* Sync with bgfx upstream revision b91d0b6
* Sync with bx upstream revision d60912b
* Sync with bimg upstream revision bd81f60
* Add astc-codec decoder
* Rename VertexDecl to VertexLayout
* Rename UniformType enum Int1 to Sampler.
* Add NVN stub
* Fix unused-const-variable error on macOS
* Drop redundant explicit language parameters
buildoptions_cpp are only applied to c++ files and buildoptions_objcpp are only
applied to objective c++ files. As such, hardcoding -x offers no benefit while
preventing overrides (such as one needed by 3rdparty/bgfx/src/renderer_vk.cpp on
macOS) from working.
* Re-introduce -x c++ in places where C code is compiled as C++ to prevent clang from throwing a warning
* Build bgfx as Objective-C++ on macOS
It is needed due to included headers
* Enable Direct3D12 and Vulkan bgfx rendering backends
* Enable building of spirv shaders
* Properly escape /c in cmd call
* Comment out dx12 bgfx renderer
* Honor VERBOSE setting during shaders build
* Only invert hlsl shader XYZ_TO_sRGB matrix for opengl
* Add spirv shaders
* OpenGL ES needs transposed matrix too
* Metal needs transposed matrix as well
Diffstat (limited to '3rdparty/bx/include/compat/msvc/dirent.h')
-rw-r--r-- | 3rdparty/bx/include/compat/msvc/dirent.h | 1044 |
1 files changed, 707 insertions, 337 deletions
diff --git a/3rdparty/bx/include/compat/msvc/dirent.h b/3rdparty/bx/include/compat/msvc/dirent.h index a08d0fa4df3..3177d335f75 100644 --- a/3rdparty/bx/include/compat/msvc/dirent.h +++ b/3rdparty/bx/include/compat/msvc/dirent.h @@ -1,28 +1,10 @@ /* - * dirent.h - dirent API for Microsoft Visual Studio + * Dirent interface for Microsoft Visual Studio * - * Copyright (C) 2006-2012 Toni Ronkko - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * ``Software''), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * $Id: dirent.h,v 1.20 2014/03/19 17:52:23 tronkko Exp $ + * Copyright (C) 1998-2019 Toni Ronkko + * This file is part of dirent. Dirent may be freely distributed + * under the MIT license. For all details and documentation, see + * https://github.com/tronkko/dirent */ #ifndef DIRENT_H #define DIRENT_H @@ -36,21 +18,16 @@ #endif // _MSC_VER /* - * Define architecture flags so we don't need to include windows.h. - * Avoiding windows.h makes it simpler to use windows sockets in conjunction - * with dirent.h. + * Include windows.h without Windows Sockets 1.1 to prevent conflicts with + * Windows Sockets 2.0. */ -#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) -# define _X86_ -#endif -#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64) -#define _AMD64_ +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN #endif +#include <windows.h> #include <stdio.h> #include <stdarg.h> -#include <windef.h> -#include <winbase.h> #include <wchar.h> #include <string.h> #include <stdlib.h> @@ -70,54 +47,109 @@ # define FILE_ATTRIBUTE_DEVICE 0x40 #endif -/* File type and permission flags for stat() */ +/* File type and permission flags for stat(), general mask */ #if !defined(S_IFMT) -# define S_IFMT _S_IFMT /* File type mask */ +# define S_IFMT _S_IFMT #endif + +/* Directory bit */ #if !defined(S_IFDIR) -# define S_IFDIR _S_IFDIR /* Directory */ +# define S_IFDIR _S_IFDIR #endif + +/* Character device bit */ #if !defined(S_IFCHR) -# define S_IFCHR _S_IFCHR /* Character device */ +# define S_IFCHR _S_IFCHR #endif + +/* Pipe bit */ #if !defined(S_IFFIFO) -# define S_IFFIFO _S_IFFIFO /* Pipe */ +# define S_IFFIFO _S_IFFIFO #endif + +/* Regular file bit */ #if !defined(S_IFREG) -# define S_IFREG _S_IFREG /* Regular file */ +# define S_IFREG _S_IFREG #endif + +/* Read permission */ #if !defined(S_IREAD) -# define S_IREAD _S_IREAD /* Read permission */ +# define S_IREAD _S_IREAD #endif + +/* Write permission */ #if !defined(S_IWRITE) -# define S_IWRITE _S_IWRITE /* Write permission */ +# define S_IWRITE _S_IWRITE #endif + +/* Execute permission */ #if !defined(S_IEXEC) -# define S_IEXEC _S_IEXEC /* Execute permission */ +# define S_IEXEC _S_IEXEC #endif + +/* Pipe */ #if !defined(S_IFIFO) -# define S_IFIFO _S_IFIFO /* Pipe */ +# define S_IFIFO _S_IFIFO #endif + +/* Block device */ #if !defined(S_IFBLK) -# define S_IFBLK 0 /* Block device */ +# define S_IFBLK 0 #endif + +/* Link */ #if !defined(S_IFLNK) -# define S_IFLNK 0 /* Link */ +# define S_IFLNK 0 #endif + +/* Socket */ #if !defined(S_IFSOCK) -# define S_IFSOCK 0 /* Socket */ +# define S_IFSOCK 0 +#endif + +/* Read user permission */ +#if !defined(S_IRUSR) +# define S_IRUSR S_IREAD +#endif + +/* Write user permission */ +#if !defined(S_IWUSR) +# define S_IWUSR S_IWRITE +#endif + +/* Execute user permission */ +#if !defined(S_IXUSR) +# define S_IXUSR 0 +#endif + +/* Read group permission */ +#if !defined(S_IRGRP) +# define S_IRGRP 0 +#endif + +/* Write group permission */ +#if !defined(S_IWGRP) +# define S_IWGRP 0 #endif -#if defined(_MSC_VER) -# define S_IRUSR S_IREAD /* Read user */ -# define S_IWUSR S_IWRITE /* Write user */ -# define S_IXUSR 0 /* Execute user */ -# define S_IRGRP 0 /* Read group */ -# define S_IWGRP 0 /* Write group */ -# define S_IXGRP 0 /* Execute group */ -# define S_IROTH 0 /* Read others */ -# define S_IWOTH 0 /* Write others */ -# define S_IXOTH 0 /* Execute others */ +/* Execute group permission */ +#if !defined(S_IXGRP) +# define S_IXGRP 0 +#endif + +/* Read others permission */ +#if !defined(S_IROTH) +# define S_IROTH 0 +#endif + +/* Write others permission */ +#if !defined(S_IWOTH) +# define S_IWOTH 0 +#endif + +/* Execute others permission */ +#if !defined(S_IXOTH) +# define S_IXOTH 0 #endif /* Maximum length of file name */ @@ -132,14 +164,14 @@ #endif /* File type flags for d_type */ -#define DT_UNKNOWN 0 -#define DT_REG S_IFREG -#define DT_DIR S_IFDIR -#define DT_FIFO S_IFIFO -#define DT_SOCK S_IFSOCK -#define DT_CHR S_IFCHR -#define DT_BLK S_IFBLK -#define DT_LNK S_IFLNK +#define DT_UNKNOWN 0 +#define DT_REG S_IFREG +#define DT_DIR S_IFDIR +#define DT_FIFO S_IFIFO +#define DT_SOCK S_IFSOCK +#define DT_CHR S_IFCHR +#define DT_BLK S_IFBLK +#define DT_LNK S_IFLNK /* Macros for converting between st_mode and d_type */ #define IFTODT(mode) ((mode) & S_IFMT) @@ -151,39 +183,33 @@ * only defined for compatibility. These macros should always return false * on Windows. */ -#ifndef S_ISFIFO +#if !defined(S_ISFIFO) # define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO) #endif - -#ifndef S_ISDIR -# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +#if !defined(S_ISDIR) +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) #endif - -#ifndef S_ISREG -# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#if !defined(S_ISREG) +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) #endif - -#ifndef S_ISLNK -# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) +#if !defined(S_ISLNK) +# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK) #endif - -#ifndef S_ISSOCK +#if !defined(S_ISSOCK) # define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK) #endif - -#ifndef S_ISCHR -# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) +#if !defined(S_ISCHR) +# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR) #endif - -#ifndef S_ISBLK -# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) +#if !defined(S_ISBLK) +# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK) #endif -/* Return the exact length of d_namlen without zero terminator */ +/* Return the exact length of the file name without zero terminator */ #define _D_EXACT_NAMLEN(p) ((p)->d_namlen) -/* Return number of bytes needed to store d_namlen */ -#define _D_ALLOC_NAMLEN(p) (PATH_MAX) +/* Return the maximum size of a file name */ +#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1) #ifdef __cplusplus @@ -193,45 +219,63 @@ extern "C" { /* Wide-character version */ struct _wdirent { - long d_ino; /* Always zero */ - unsigned short d_reclen; /* Structure size */ - size_t d_namlen; /* Length of name without \0 */ - int d_type; /* File type */ - wchar_t d_name[PATH_MAX]; /* File name */ + /* Always zero */ + long d_ino; + + /* File position within stream */ + long d_off; + + /* Structure size */ + unsigned short d_reclen; + + /* Length of name without \0 */ + size_t d_namlen; + + /* File type */ + int d_type; + + /* File name */ + wchar_t d_name[PATH_MAX+1]; }; typedef struct _wdirent _wdirent; struct _WDIR { - struct _wdirent ent; /* Current directory entry */ - WIN32_FIND_DATAW data; /* Private file data */ - int cached; /* True if data is valid */ - HANDLE handle; /* Win32 search handle */ - wchar_t *patt; /* Initial directory name */ + /* Current directory entry */ + struct _wdirent ent; + + /* Private file data */ + WIN32_FIND_DATAW data; + + /* True if data is valid */ + int cached; + + /* Win32 search handle */ + HANDLE handle; + + /* Initial directory name */ + wchar_t *patt; }; typedef struct _WDIR _WDIR; -static _WDIR *_wopendir (const wchar_t *dirname); -static struct _wdirent *_wreaddir (_WDIR *dirp); -static int _wclosedir (_WDIR *dirp); -static void _wrewinddir (_WDIR* dirp); +/* Multi-byte character version */ +struct dirent { + /* Always zero */ + long d_ino; + /* File position within stream */ + long d_off; -/* For compatibility with Symbian */ -#define wdirent _wdirent -#define WDIR _WDIR -#define wopendir _wopendir -#define wreaddir _wreaddir -#define wclosedir _wclosedir -#define wrewinddir _wrewinddir + /* Structure size */ + unsigned short d_reclen; + /* Length of name without \0 */ + size_t d_namlen; -/* Multi-byte character versions */ -struct dirent { - long d_ino; /* Always zero */ - unsigned short d_reclen; /* Structure size */ - size_t d_namlen; /* Length of name without \0 */ - int d_type; /* File type */ - char d_name[PATH_MAX]; /* File name */ + /* File type */ + int d_type; + + /* File name */ + char d_name[PATH_MAX+1]; }; typedef struct dirent dirent; @@ -241,10 +285,41 @@ struct DIR { }; typedef struct DIR DIR; + +/* Dirent functions */ static DIR *opendir (const char *dirname); +static _WDIR *_wopendir (const wchar_t *dirname); + static struct dirent *readdir (DIR *dirp); +static struct _wdirent *_wreaddir (_WDIR *dirp); + +static int readdir_r( + DIR *dirp, struct dirent *entry, struct dirent **result); +static int _wreaddir_r( + _WDIR *dirp, struct _wdirent *entry, struct _wdirent **result); + static int closedir (DIR *dirp); +static int _wclosedir (_WDIR *dirp); + static void rewinddir (DIR* dirp); +static void _wrewinddir (_WDIR* dirp); + +static int scandir (const char *dirname, struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)); + +static int alphasort (const struct dirent **a, const struct dirent **b); + +static int versionsort (const struct dirent **a, const struct dirent **b); + + +/* For compatibility with Symbian */ +#define wdirent _wdirent +#define WDIR _WDIR +#define wopendir _wopendir +#define wreaddir _wreaddir +#define wclosedir _wclosedir +#define wrewinddir _wrewinddir /* Internal utility functions */ @@ -267,6 +342,7 @@ static int dirent_wcstombs_s( static void dirent_set_errno (int error); + /* * Open directory stream DIRNAME for read and return a pointer to the * internal working area that is used to retrieve individual directory @@ -277,7 +353,8 @@ _wopendir( const wchar_t *dirname) { _WDIR *dirp = NULL; - int error; + DWORD n; + wchar_t *p; /* Must have directory name */ if (dirname == NULL || dirname[0] == '\0') { @@ -287,96 +364,120 @@ _wopendir( /* Allocate new _WDIR structure */ dirp = (_WDIR*) malloc (sizeof (struct _WDIR)); - if (dirp != NULL) { - DWORD n; - - /* Reset _WDIR structure */ - dirp->handle = INVALID_HANDLE_VALUE; - dirp->patt = NULL; - dirp->cached = 0; - - /* Compute the length of full path plus zero terminator */ - n = GetFullPathNameW (dirname, 0, NULL, NULL); - - /* Allocate room for absolute directory name and search pattern */ - dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); - if (dirp->patt) { - - /* - * Convert relative directory name to an absolute one. This - * allows rewinddir() to function correctly even when current - * working directory is changed between opendir() and rewinddir(). - */ - n = GetFullPathNameW (dirname, n, dirp->patt, NULL); - if (n > 0) { - wchar_t *p; - - /* Append search pattern \* to the directory name */ - p = dirp->patt + n; - if (dirp->patt < p) { - switch (p[-1]) { - case '\\': - case '/': - case ':': - /* Directory ends in path separator, e.g. c:\temp\ */ - /*NOP*/; - break; - - default: - /* Directory name doesn't end in path separator */ - *p++ = '\\'; - } - } - *p++ = '*'; - *p = '\0'; + if (!dirp) { + return NULL; + } - /* Open directory stream and retrieve the first entry */ - if (dirent_first (dirp)) { - /* Directory stream opened successfully */ - error = 0; - } else { - /* Cannot retrieve first entry */ - error = 1; - dirent_set_errno (ENOENT); - } + /* Reset _WDIR structure */ + dirp->handle = INVALID_HANDLE_VALUE; + dirp->patt = NULL; + dirp->cached = 0; + + /* + * Compute the length of full path plus zero terminator + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PHONE_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + /* WinRT */ + n = wcslen (dirname); +#else + /* Regular Windows */ + n = GetFullPathNameW (dirname, 0, NULL, NULL); +#endif - } else { - /* Cannot retrieve full path name */ - dirent_set_errno (ENOENT); - error = 1; - } + /* Allocate room for absolute directory name and search pattern */ + dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16); + if (dirp->patt == NULL) { + goto exit_closedir; + } - } else { - /* Cannot allocate memory for search pattern */ - error = 1; - } + /* + * Convert relative directory name to an absolute one. This + * allows rewinddir() to function correctly even when current + * working directory is changed between opendir() and rewinddir(). + * + * Note that on WinRT there's no way to convert relative paths + * into absolute paths, so just assume it is an absolute path. + */ +#if defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_PHONE_APP) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + /* WinRT */ + wcsncpy_s (dirp->patt, n+1, dirname, n); +#else + /* Regular Windows */ + n = GetFullPathNameW (dirname, n, dirp->patt, NULL); + if (n <= 0) { + goto exit_closedir; + } +#endif - } else { - /* Cannot allocate _WDIR structure */ - error = 1; + /* Append search pattern \* to the directory name */ + p = dirp->patt + n; + switch (p[-1]) { + case '\\': + case '/': + case ':': + /* Directory ends in path separator, e.g. c:\temp\ */ + /*NOP*/; + break; + + default: + /* Directory name doesn't end in path separator */ + *p++ = '\\'; } + *p++ = '*'; + *p = '\0'; - /* Clean up in case of error */ - if (error && dirp) { - _wclosedir (dirp); - dirp = NULL; + /* Open directory stream and retrieve the first entry */ + if (!dirent_first (dirp)) { + goto exit_closedir; } + /* Success */ return dirp; + + /* Failure */ +exit_closedir: + _wclosedir (dirp); + return NULL; } /* - * Read next directory entry. The directory entry is returned in dirent - * structure in the d_name field. Individual directory entries returned by - * this function include regular files, sub-directories, pseudo-directories - * "." and ".." as well as volume labels, hidden files and system files. + * Read next directory entry. + * + * Returns pointer to static directory entry which may be overwritten by + * subsequent calls to _wreaddir(). */ static struct _wdirent* _wreaddir( _WDIR *dirp) { + struct _wdirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) _wreaddir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry. + * + * Returns zero on success. If end of directory stream is reached, then sets + * result to NULL and returns zero. + */ +static int +_wreaddir_r( + _WDIR *dirp, + struct _wdirent *entry, + struct _wdirent **result) +{ WIN32_FIND_DATAW *datap; - struct _wdirent *entp; /* Read next directory entry */ datap = dirent_next (dirp); @@ -384,46 +485,47 @@ _wreaddir( size_t n; DWORD attr; - /* Pointer to directory entry to return */ - entp = &dirp->ent; - /* * Copy file name as wide-character string. If the file name is too * long to fit in to the destination buffer, then truncate file name * to PATH_MAX characters and zero-terminate the buffer. */ n = 0; - while (n + 1 < PATH_MAX && datap->cFileName[n] != 0) { - entp->d_name[n] = datap->cFileName[n]; + while (n < PATH_MAX && datap->cFileName[n] != 0) { + entry->d_name[n] = datap->cFileName[n]; n++; } - dirp->ent.d_name[n] = 0; + entry->d_name[n] = 0; /* Length of file name excluding zero terminator */ - entp->d_namlen = n; + entry->d_namlen = n; /* File type */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { - entp->d_type = DT_CHR; + entry->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - entp->d_type = DT_DIR; + entry->d_type = DT_DIR; } else { - entp->d_type = DT_REG; + entry->d_type = DT_REG; } /* Reset dummy fields */ - entp->d_ino = 0; - entp->d_reclen = sizeof (struct _wdirent); + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct _wdirent); + + /* Set result address */ + *result = entry; } else { - /* Last directory entry read */ - entp = NULL; + /* Return NULL to indicate end of directory */ + *result = NULL; } - return entp; + return /*OK*/0; } /* @@ -441,23 +543,21 @@ _wclosedir( /* Release search handle */ if (dirp->handle != INVALID_HANDLE_VALUE) { FindClose (dirp->handle); - dirp->handle = INVALID_HANDLE_VALUE; } /* Release search pattern */ - if (dirp->patt) { - free (dirp->patt); - dirp->patt = NULL; - } + free (dirp->patt); /* Release directory structure */ free (dirp); ok = /*success*/0; } else { + /* Invalid directory stream */ dirent_set_errno (EBADF); ok = /*failure*/-1; + } return ok; } @@ -487,9 +587,12 @@ dirent_first( _WDIR *dirp) { WIN32_FIND_DATAW *datap; + DWORD error; /* Open directory and retrieve the first entry */ - dirp->handle = FindFirstFileW (dirp->patt, &dirp->data); + dirp->handle = FindFirstFileExW( + dirp->patt, FindExInfoStandard, &dirp->data, + FindExSearchNameMatch, NULL, 0); if (dirp->handle != INVALID_HANDLE_VALUE) { /* a directory entry is now waiting in memory */ @@ -498,15 +601,38 @@ dirent_first( } else { - /* Failed to re-open directory: no directory entry in memory */ + /* Failed to open directory: no directory entry in memory */ dirp->cached = 0; datap = NULL; + /* Set error code */ + error = GetLastError (); + switch (error) { + case ERROR_ACCESS_DENIED: + /* No read access to directory */ + dirent_set_errno (EACCES); + break; + + case ERROR_DIRECTORY: + /* Directory name is invalid */ + dirent_set_errno (ENOTDIR); + break; + + case ERROR_PATH_NOT_FOUND: + default: + /* Cannot find the file */ + dirent_set_errno (ENOENT); + } + } return datap; } -/* Get next directory entry (internal) */ +/* + * Get next directory entry (internal). + * + * Returns + */ static WIN32_FIND_DATAW* dirent_next( _WDIR *dirp) @@ -527,7 +653,7 @@ dirent_next( /* Got a file */ p = &dirp->data; } else { - /* The very last entry has been processed or an error occured */ + /* The very last entry has been processed or an error occurred */ FindClose (dirp->handle); dirp->handle = INVALID_HANDLE_VALUE; p = NULL; @@ -552,6 +678,8 @@ opendir( { struct DIR *dirp; int error; + wchar_t wname[PATH_MAX + 1]; + size_t n; /* Must have directory name */ if (dirname == NULL || dirname[0] == '\0') { @@ -561,67 +689,71 @@ opendir( /* Allocate memory for DIR structure */ dirp = (DIR*) malloc (sizeof (struct DIR)); - if (dirp) { - wchar_t wname[PATH_MAX]; - size_t n; - - /* Convert directory name to wide-character string */ - error = dirent_mbstowcs_s (&n, wname, PATH_MAX, dirname, PATH_MAX); - if (!error) { - - /* Open directory stream using wide-character name */ - dirp->wdirp = _wopendir (wname); - if (dirp->wdirp) { - /* Directory stream opened */ - error = 0; - } else { - /* Failed to open directory stream */ - error = 1; - } - - } else { - /* - * Cannot convert file name to wide-character string. This - * occurs if the string contains invalid multi-byte sequences or - * the output buffer is too small to contain the resulting - * string. - */ - error = 1; - } + if (!dirp) { + return NULL; + } - } else { - /* Cannot allocate DIR structure */ - error = 1; + /* Convert directory name to wide-character string */ + error = dirent_mbstowcs_s( + &n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1); + if (error) { + /* + * Cannot convert file name to wide-character string. This + * occurs if the string contains invalid multi-byte sequences or + * the output buffer is too small to contain the resulting + * string. + */ + goto exit_free; } - /* Clean up in case of error */ - if (error && dirp) { - free (dirp); - dirp = NULL; + + /* Open directory stream using wide-character name */ + dirp->wdirp = _wopendir (wname); + if (!dirp->wdirp) { + goto exit_free; } + /* Success */ return dirp; + + /* Failure */ +exit_free: + free (dirp); + return NULL; } /* * Read next directory entry. - * - * When working with text consoles, please note that file names returned by - * readdir() are represented in the default ANSI code page while any output to - * console is typically formatted on another code page. Thus, non-ASCII - * characters in file names will not usually display correctly on console. The - * problem can be fixed in two ways: (1) change the character set of console - * to 1252 using chcp utility and use Lucida Console font, or (2) use - * _cprintf function when writing to console. The _cprinf() will re-encode - * ANSI strings to the console code page so many non-ASCII characters will - * display correcly. */ static struct dirent* readdir( DIR *dirp) { + struct dirent *entry; + + /* + * Read directory entry to buffer. We can safely ignore the return value + * as entry will be set to NULL in case of error. + */ + (void) readdir_r (dirp, &dirp->ent, &entry); + + /* Return pointer to statically allocated directory entry */ + return entry; +} + +/* + * Read next directory entry into called-allocated buffer. + * + * Returns zero on success. If the end of directory stream is reached, then + * sets result to NULL and returns zero. + */ +static int +readdir_r( + DIR *dirp, + struct dirent *entry, + struct dirent **result) +{ WIN32_FIND_DATAW *datap; - struct dirent *entp; /* Read next directory entry */ datap = dirent_next (dirp->wdirp); @@ -631,7 +763,7 @@ readdir( /* Attempt to convert file name to multi-byte string */ error = dirent_wcstombs_s( - &n, dirp->ent.d_name, PATH_MAX, datap->cFileName, PATH_MAX); + &n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1); /* * If the file name cannot be represented by a multi-byte string, @@ -645,55 +777,60 @@ readdir( */ if (error && datap->cAlternateFileName[0] != '\0') { error = dirent_wcstombs_s( - &n, dirp->ent.d_name, PATH_MAX, - datap->cAlternateFileName, PATH_MAX); + &n, entry->d_name, PATH_MAX + 1, + datap->cAlternateFileName, PATH_MAX + 1); } if (!error) { DWORD attr; - /* Initialize directory entry for return */ - entp = &dirp->ent; - /* Length of file name excluding zero terminator */ - entp->d_namlen = n - 1; + entry->d_namlen = n - 1; /* File attributes */ attr = datap->dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) { - entp->d_type = DT_CHR; + entry->d_type = DT_CHR; } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) { - entp->d_type = DT_DIR; + entry->d_type = DT_DIR; } else { - entp->d_type = DT_REG; + entry->d_type = DT_REG; } /* Reset dummy fields */ - entp->d_ino = 0; - entp->d_reclen = sizeof (struct dirent); + entry->d_ino = 0; + entry->d_off = 0; + entry->d_reclen = sizeof (struct dirent); } else { + /* * Cannot convert file name to multi-byte string so construct - * an errornous directory entry and return that. Note that + * an erroneous directory entry and return that. Note that * we cannot return NULL as that would stop the processing * of directory entries completely. */ - entp = &dirp->ent; - entp->d_name[0] = '?'; - entp->d_name[1] = '\0'; - entp->d_namlen = 1; - entp->d_type = DT_UNKNOWN; - entp->d_ino = 0; - entp->d_reclen = 0; + entry->d_name[0] = '?'; + entry->d_name[1] = '\0'; + entry->d_namlen = 1; + entry->d_type = DT_UNKNOWN; + entry->d_ino = 0; + entry->d_off = -1; + entry->d_reclen = 0; + } + /* Return pointer to directory entry */ + *result = entry; + } else { + /* No more directory entries */ - entp = NULL; + *result = NULL; + } - return entp; + return /*OK*/0; } /* @@ -734,6 +871,162 @@ rewinddir( _wrewinddir (dirp->wdirp); } +/* + * Scan directory for entries. + */ +static int +scandir( + const char *dirname, + struct dirent ***namelist, + int (*filter)(const struct dirent*), + int (*compare)(const struct dirent**, const struct dirent**)) +{ + struct dirent **files = NULL; + size_t size = 0; + size_t allocated = 0; + const size_t init_size = 1; + DIR *dir = NULL; + struct dirent *entry; + struct dirent *tmp = NULL; + size_t i; + int result = 0; + + /* Open directory stream */ + dir = opendir (dirname); + if (dir) { + + /* Read directory entries to memory */ + while (1) { + + /* Enlarge pointer table to make room for another pointer */ + if (size >= allocated) { + void *p; + size_t num_entries; + + /* Compute number of entries in the enlarged pointer table */ + if (size < init_size) { + /* Allocate initial pointer table */ + num_entries = init_size; + } else { + /* Double the size */ + num_entries = size * 2; + } + + /* Allocate first pointer table or enlarge existing table */ + p = realloc (files, sizeof (void*) * num_entries); + if (p != NULL) { + /* Got the memory */ + files = (dirent**) p; + allocated = num_entries; + } else { + /* Out of memory */ + result = -1; + break; + } + + } + + /* Allocate room for temporary directory entry */ + if (tmp == NULL) { + tmp = (struct dirent*) malloc (sizeof (struct dirent)); + if (tmp == NULL) { + /* Cannot allocate temporary directory entry */ + result = -1; + break; + } + } + + /* Read directory entry to temporary area */ + if (readdir_r (dir, tmp, &entry) == /*OK*/0) { + + /* Did we get an entry? */ + if (entry != NULL) { + int pass; + + /* Determine whether to include the entry in result */ + if (filter) { + /* Let the filter function decide */ + pass = filter (tmp); + } else { + /* No filter function, include everything */ + pass = 1; + } + + if (pass) { + /* Store the temporary entry to pointer table */ + files[size++] = tmp; + tmp = NULL; + + /* Keep up with the number of files */ + result++; + } + + } else { + + /* + * End of directory stream reached => sort entries and + * exit. + */ + qsort (files, size, sizeof (void*), + (int (*) (const void*, const void*)) compare); + break; + + } + + } else { + /* Error reading directory entry */ + result = /*Error*/ -1; + break; + } + + } + + } else { + /* Cannot open directory */ + result = /*Error*/ -1; + } + + /* Release temporary directory entry */ + free (tmp); + + /* Release allocated memory on error */ + if (result < 0) { + for (i = 0; i < size; i++) { + free (files[i]); + } + free (files); + files = NULL; + } + + /* Close directory stream */ + if (dir) { + closedir (dir); + } + + /* Pass pointer table to caller */ + if (namelist) { + *namelist = files; + } + return result; +} + +/* Alphabetical sorting */ +static int +alphasort( + const struct dirent **a, const struct dirent **b) +{ + return strcoll ((*a)->d_name, (*b)->d_name); +} + +/* Sort versions */ +static int +versionsort( + const struct dirent **a, const struct dirent **b) +{ + /* FIXME: implement strverscmp and use that */ + return alphasort (a, b); +} + /* Convert multi-byte string to wide character string */ static int dirent_mbstowcs_s( @@ -744,46 +1037,87 @@ dirent_mbstowcs_s( size_t count) { int error; - -#if defined(_MSC_VER) && _MSC_VER >= 1400 - - /* Microsoft Visual Studio 2005 or later */ - error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count); - + int n; + size_t len; + UINT cp; + DWORD flags; + + /* Determine code page for multi-byte string */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + if (AreFileApisANSI ()) { + /* Default ANSI code page */ + cp = GetACP (); + } else { + /* Default OEM code page */ + cp = GetOEMCP (); + } #else + cp = CP_ACP; +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + + /* + * Determine flags based on the character set. For more information, + * please see https://docs.microsoft.com/fi-fi/windows/desktop/api/stringapiset/nf-stringapiset-multibytetowidechar + */ + switch (cp) { + case 42: + case 50220: + case 50221: + case 50222: + case 50225: + case 50227: + case 50229: + case 57002: + case 57003: + case 57004: + case 57005: + case 57006: + case 57007: + case 57008: + case 57009: + case 57010: + case 57011: + case 65000: + /* MultiByteToWideChar does not support MB_ERR_INVALID_CHARS */ + flags = 0; + break; + + default: + /* + * Ask MultiByteToWideChar to return an error if a multi-byte + * character cannot be converted to a wide-character. + */ + flags = MB_ERR_INVALID_CHARS; + } - /* Older Visual Studio or non-Microsoft compiler */ - size_t n; + /* Compute the length of input string without zero-terminator */ + len = 0; + while (mbstr[len] != '\0' && len < count) { + len++; + } - /* Convert to wide-character string (or count characters) */ - n = mbstowcs (wcstr, mbstr, sizeInWords); - if (!wcstr || n < count) { + /* Convert to wide-character string */ + n = MultiByteToWideChar( + /* Source code page */ cp, + /* Flags */ flags, + /* Pointer to string to convert */ mbstr, + /* Size of multi-byte string */ (int) len, + /* Pointer to output buffer */ wcstr, + /* Size of output buffer */ (int)sizeInWords - 1 + ); - /* Zero-terminate output buffer */ - if (wcstr && sizeInWords) { - if (n >= sizeInWords) { - n = sizeInWords - 1; - } - wcstr[n] = 0; - } + /* Ensure that output buffer is zero-terminated */ + wcstr[n] = '\0'; - /* Length of resuting multi-byte string WITH zero terminator */ - if (pReturnValue) { - *pReturnValue = n + 1; - } + /* Return length of wide-character string with zero-terminator */ + *pReturnValue = (size_t) (n + 1); - /* Success */ + /* Return zero if conversion succeeded */ + if (n > 0) { error = 0; - } else { - - /* Could not convert string */ error = 1; - } - -#endif - return error; } @@ -796,47 +1130,82 @@ dirent_wcstombs_s( const wchar_t *wcstr, size_t count) { + int n; int error; - -#if defined(_MSC_VER) && _MSC_VER >= 1400 - - /* Microsoft Visual Studio 2005 or later */ - error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count); - + UINT cp; + size_t len; + BOOL flag = 0; + LPBOOL pflag; + + /* Determine code page for multi-byte string */ +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) + if (AreFileApisANSI ()) { + /* Default ANSI code page */ + cp = GetACP (); + } else { + /* Default OEM code page */ + cp = GetOEMCP (); + } #else + cp = CP_ACP; +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - /* Older Visual Studio or non-Microsoft compiler */ - size_t n; - /* Convert to multi-byte string (or count the number of bytes needed) */ - n = wcstombs (mbstr, wcstr, sizeInBytes); - if (!mbstr || n < count) { + /* Compute the length of input string without zero-terminator */ + len = 0; + while (wcstr[len] != '\0' && len < count) { + len++; + } - /* Zero-terminate output buffer */ - if (mbstr && sizeInBytes) { - if (n >= sizeInBytes) { - n = sizeInBytes - 1; - } - mbstr[n] = '\0'; - } + /* + * Determine if we can ask WideCharToMultiByte to return information on + * broken characters. For more information, please see + * https://docs.microsoft.com/en-us/windows/desktop/api/stringapiset/nf-stringapiset-widechartomultibyte + */ + switch (cp) { + case CP_UTF7: + case CP_UTF8: + /* + * WideCharToMultiByte fails if we request information on default + * characters. This is just a nuisance but doesn't affect the + * conversion: if Windows is configured to use UTF-8, then the default + * character should not be needed anyway. + */ + pflag = NULL; + break; - /* Lenght of resulting multi-bytes string WITH zero-terminator */ - if (pReturnValue) { - *pReturnValue = n + 1; - } + default: + /* + * Request that WideCharToMultiByte sets the flag if it uses the + * default character. + */ + pflag = &flag; + } - /* Success */ + /* Convert wide-character string to multi-byte character string */ + n = WideCharToMultiByte( + /* Target code page */ cp, + /* Flags */ 0, + /* Pointer to unicode string */ wcstr, + /* Length of unicode string */ (int) len, + /* Pointer to output buffer */ mbstr, + /* Size of output buffer */ (int)sizeInBytes - 1, + /* Default character */ NULL, + /* Whether default character was used or not */ pflag + ); + + /* Ensure that output buffer is zero-terminated */ + mbstr[n] = '\0'; + + /* Return length of multi-byte string with zero-terminator */ + *pReturnValue = (size_t) (n + 1); + + /* Return zero if conversion succeeded without using default characters */ + if (n > 0 && flag == 0) { error = 0; - } else { - - /* Cannot convert string */ error = 1; - } - -#endif - return error; } @@ -858,6 +1227,7 @@ dirent_set_errno( #endif } + #ifdef __cplusplus } #endif |