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))
+);