__ms_vsnwprintf() function now calls _vscwprintf() funcion. _vscwprintf() is not available in older msvcrt.dll version, so provide emulation of _scwprintf() and _vscwprintf() functions.
This emulation is similar to existing _scprintf and _vscprintf emulation. --- mingw-w64-crt/Makefile.am | 10 +++ mingw-w64-crt/lib-common/msvcrt.def.in | 4 +- mingw-w64-crt/stdio/_scwprintf.c | 67 ++++++++++++++++++++ mingw-w64-crt/stdio/_vscwprintf.c | 87 ++++++++++++++++++++++++++ 4 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 mingw-w64-crt/stdio/_scwprintf.c create mode 100644 mingw-w64-crt/stdio/_vscwprintf.c diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am index fc547e668e3d..63d9f4befad8 100644 --- a/mingw-w64-crt/Makefile.am +++ b/mingw-w64-crt/Makefile.am @@ -487,7 +487,9 @@ src_msvcrt32=\ misc/wctob.c \ stdio/_fstat64i32.c \ stdio/_scprintf.c \ + stdio/_scwprintf.c \ stdio/_vscprintf.c \ + stdio/_vscwprintf.c \ string/wcstok.c # Files included in libmsvcrt-os.a (for msvcrt.dll) on x86_64 @@ -745,7 +747,9 @@ src_crtdll=\ misc/wctype.c \ stdio/_filelengthi64.c \ stdio/_scprintf.c \ + stdio/_scwprintf.c \ stdio/_vscprintf.c \ + stdio/_vscwprintf.c \ stdio/atoll.c \ stdio/fgetpos.c \ stdio/fsetpos.c \ @@ -812,7 +816,9 @@ src_msvcrt10=\ misc/wctype.c \ stdio/_filelengthi64.c \ stdio/_scprintf.c \ + stdio/_scwprintf.c \ stdio/_vscprintf.c \ + stdio/_vscwprintf.c \ stdio/atoll.c \ stdio/fgetpos.c \ stdio/fsetpos.c \ @@ -860,7 +866,9 @@ src_msvcrt20=\ misc/wctype.c \ stdio/_filelengthi64.c \ stdio/_scprintf.c \ + stdio/_scwprintf.c \ stdio/_vscprintf.c \ + stdio/_vscwprintf.c \ stdio/atoll.c \ stdio/fgetpos.c \ stdio/fsetpos.c \ @@ -902,7 +910,9 @@ src_msvcrt40=\ misc/wctrans.c \ misc/wctype.c \ stdio/_scprintf.c \ + stdio/_scwprintf.c \ stdio/_vscprintf.c \ + stdio/_vscwprintf.c \ stdio/atoll.c \ stdio/fseeki64.c \ stdio/mingw_dummy__lock.c \ diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in index ab085571b498..e399f96ff12e 100644 --- a/mingw-w64-crt/lib-common/msvcrt.def.in +++ b/mingw-w64-crt/lib-common/msvcrt.def.in @@ -1214,7 +1214,7 @@ _getwche _putwch _resetstkoflw F_NON_I386(_scprintf) ; i386 _scprintf replaced by emu -_scwprintf +F_NON_I386(_scwprintf) ; i386 _scwprintf replaced by emu F_I386(_set_SSE2_enable) _snscanf _snwscanf @@ -1222,7 +1222,7 @@ F_NON_I386(_strtoi64) ; i386 _strtoi64 replaced by emu F_NON_I386(_strtoui64) ; i386 _strtoui64 replaced by emu _ungetwch F_NON_I386(_vscprintf) ; i386 _vscprintf replaced by emu -_vscwprintf +F_NON_I386(_vscwprintf) ; i386 _vscwprintf replaced by emu _wcserror F_NON_I386(_wcstoi64) ; i386 _wcstoi64 replaced by emu F_NON_I386(_wcstoui64) ; i386 _wcstoui64 replaced by emu diff --git a/mingw-w64-crt/stdio/_scwprintf.c b/mingw-w64-crt/stdio/_scwprintf.c new file mode 100644 index 000000000000..b132328ab7a1 --- /dev/null +++ b/mingw-w64-crt/stdio/_scwprintf.c @@ -0,0 +1,67 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#include <windows.h> +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +/* mingw-w64 always provides _vscwprintf() implementation, so use it */ +static int __cdecl emu_scwprintf(const wchar_t * __restrict__ format, ...) +{ + va_list arglist; + int ret; + + va_start(arglist, format); + ret = _vscwprintf(format, arglist); + va_end(arglist); + return ret; +} + +#ifndef __LIBMSVCRT_OS__ + +int __attribute__ ((alias ("emu_scwprintf"))) __cdecl _scwprintf (const wchar_t * __restrict__, ...); +int (__cdecl *__MINGW_IMP_SYMBOL(_scwprintf))(const wchar_t * __restrict__, ...) = _scwprintf; + +#else + +#include <msvcrt.h> + +static int __cdecl init_scwprintf(const wchar_t * __restrict__ format, ...); + +int (__cdecl *__MINGW_IMP_SYMBOL(_scwprintf))(const wchar_t * __restrict__, ...) = init_scwprintf; + +__attribute__((used)) +static void resolve_scwprintf(void) +{ + HMODULE msvcrt = __mingw_get_msvcrt_handle(); + int (__cdecl *func)(const wchar_t * __restrict__, ...) = NULL; + + if (msvcrt) + func = (int (__cdecl *)(const wchar_t * __restrict__, ...))GetProcAddress(msvcrt, "_scwprintf"); + + if (!func) + func = emu_scwprintf; + + __MINGW_IMP_SYMBOL(_scwprintf) = func; +} + +/* gcc does not provide an easy way to call another variadic function with reusing current arguments + * this source file is used only on i386, so do this function redirect via inline i386 assembly */ +#define ASM_SYM(sym) __MINGW64_STRINGIFY(__MINGW_USYMBOL(sym)) +asm ( +".def\t" ASM_SYM(init_scwprintf) ";\t.scl\t3;\t.type\t32;\t.endef\n" +ASM_SYM(init_scwprintf) ":\n\t" + "pushal\n\t" + "call\t" ASM_SYM(resolve_scwprintf) "\n\t" + "popal\n\t" + /* fallthrough */ +".globl\t" ASM_SYM(_scwprintf) "\n\t" +".def\t" ASM_SYM(_scwprintf) ";\t.scl\t2;\t.type\t32;\t.endef\n" +ASM_SYM(_scwprintf) ":\n\t" + "jmp\t*" ASM_SYM(__MINGW_IMP_SYMBOL(_scwprintf)) +); + +#endif diff --git a/mingw-w64-crt/stdio/_vscwprintf.c b/mingw-w64-crt/stdio/_vscwprintf.c new file mode 100644 index 000000000000..0fae7a16ab6d --- /dev/null +++ b/mingw-w64-crt/stdio/_vscwprintf.c @@ -0,0 +1,87 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#include <windows.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <wchar.h> +#include <errno.h> + +/* emulation of _vscwprintf() via _vsnwprintf() */ +static int __cdecl emu_vscwprintf(const wchar_t * __restrict__ format, va_list arglist) +{ + wchar_t *buffer, *new_buffer; + size_t size; + int ret = -1; + + /* if format is a null pointer, _vscwprintf() returns -1 and sets errno to EINVAL */ + if (!format) { + errno = EINVAL; + return -1; + } + + /* size for _vsnwprintf() must be non-zero and buffer must have place for terminating null character */ + size = (wcslen(format) * 2 + 1) * sizeof(wchar_t); + buffer = malloc(size); + + if (!buffer) { + errno = ENOMEM; + return -1; + } + + /* if the number of characters to write is greater than size, _vsnwprintf() returns -1 */ + while (size < SIZE_MAX/2 && (ret = _vsnwprintf(buffer, size, format, arglist)) < 0) { + /* in this case try with larger buffer */ + size *= 2; + new_buffer = realloc(buffer, size); + if (!new_buffer) + break; + buffer = new_buffer; + } + + free(buffer); + + if (ret < 0) { + errno = ENOMEM; + return -1; + } + + return ret; +} + +#ifndef __LIBMSVCRT_OS__ + +int __attribute__ ((alias ("emu_vscwprintf"))) __cdecl _vscwprintf (const wchar_t * __restrict__, va_list); +int (__cdecl *__MINGW_IMP_SYMBOL(_vscwprintf))(const wchar_t * __restrict__, va_list) = _vscwprintf; + +#else + +#include <msvcrt.h> + +static int __cdecl init_vscwprintf(const wchar_t * __restrict__ format, va_list arglist); + +int (__cdecl *__MINGW_IMP_SYMBOL(_vscwprintf))(const wchar_t * __restrict__, va_list) = init_vscwprintf; + +static int __cdecl init_vscwprintf(const wchar_t * __restrict__ format, va_list arglist) +{ + HMODULE msvcrt = __mingw_get_msvcrt_handle(); + int (__cdecl *func)(const wchar_t * __restrict__, va_list) = NULL; + + if (msvcrt) + func = (int (__cdecl *)(const wchar_t * __restrict__, va_list))GetProcAddress(msvcrt, "_vscwprintf"); + + if (!func) + func = emu_vscwprintf; + + return (__MINGW_IMP_SYMBOL(_vscwprintf) = func)(format, arglist); +} + +int __cdecl _vscwprintf(const wchar_t * __restrict__ format, va_list arglist) +{ + return __MINGW_IMP_SYMBOL(_vscwprintf)(format, arglist); +} + +#endif -- 2.20.1 _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public