crt: Add fallback _scprintf() implementation
Original MSVC 6.0 msvcrt.dll library does not provide _scprintf()
function. Add fallback _scprintf() implementation like for _vscprintf().
Signed-off-by: Martin Storsjö <martin@martin.st>
diff --git a/mingw-w64-crt/Makefile.am b/mingw-w64-crt/Makefile.am
index 83e841d..e68d4f7 100644
--- a/mingw-w64-crt/Makefile.am
+++ b/mingw-w64-crt/Makefile.am
@@ -284,6 +284,7 @@
misc/_get_current_locale.c \
misc/lc_locale_func.c \
misc/wassert.c \
+ stdio/_scprintf.c \
stdio/_vscprintf.c
src_msvcrt64=\
diff --git a/mingw-w64-crt/lib-common/msvcrt.def.in b/mingw-w64-crt/lib-common/msvcrt.def.in
index ec1f2cd..942c4c4 100644
--- a/mingw-w64-crt/lib-common/msvcrt.def.in
+++ b/mingw-w64-crt/lib-common/msvcrt.def.in
@@ -930,7 +930,7 @@
F_X64(_scalbf)
_scanf_l
_scanf_s_l
-_scprintf
+F_NON_I386(_scprintf) ; i386 _scprintf replaced by emu
_scprintf_l
_scprintf_p_l
_scwprintf
diff --git a/mingw-w64-crt/stdio/_scprintf.c b/mingw-w64-crt/stdio/_scprintf.c
new file mode 100644
index 0000000..eb3044a
--- /dev/null
+++ b/mingw-w64-crt/stdio/_scprintf.c
@@ -0,0 +1,57 @@
+/**
+ * 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 <msvcrt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+/* mingw-w64 always provides _vscprintf() implementation, so use it */
+static int __cdecl emu_scprintf(const char * __restrict__ format, ...)
+{
+ va_list arglist;
+ int ret;
+
+ va_start(arglist, format);
+ ret = _vscprintf(format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+static int __cdecl init_scprintf(const char * __restrict__ format, ...);
+
+int (__cdecl *__MINGW_IMP_SYMBOL(_scprintf))(const char * __restrict__, ...) = init_scprintf;
+
+__attribute__((used))
+static void resolve_scprintf(void)
+{
+ HMODULE msvcrt = __mingw_get_msvcrt_handle();
+ int (__cdecl *func)(const char * __restrict__, ...) = NULL;
+
+ if (msvcrt)
+ func = (int (__cdecl *)(const char * __restrict__, ...))GetProcAddress(msvcrt, "_scprintf");
+
+ if (!func)
+ func = emu_scprintf;
+
+ __MINGW_IMP_SYMBOL(_scprintf) = 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_scprintf) ";\t.scl\t3;\t.type\t32;\t.endef\n"
+ASM_SYM(init_scprintf) ":\n\t"
+ "pushal\n\t"
+ "call\t" ASM_SYM(resolve_scprintf) "\n\t"
+ "popal\n\t"
+ /* fallthrough */
+".globl\t" ASM_SYM(_scprintf) "\n\t"
+".def\t" ASM_SYM(_scprintf) ";\t.scl\t2;\t.type\t32;\t.endef\n"
+ASM_SYM(_scprintf) ":\n\t"
+ "jmp\t*" ASM_SYM(__MINGW_IMP_SYMBOL(_scprintf))
+);