+2025-09-17 Bruno Haible <bruno@clisp.org>
+
+ stdio-h: Work around [v][f]printf bugs in mingw with msvcrt.
+ Reported by 松延 英樹 <maznobu@gmail.com> in
+ <https://github.com/mlocati/gettext-iconv-windows/issues/52>.
+ * lib/stdio.in.h (gl_consolesafe_fprintf, gl_consolesafe_printf,
+ gl_consolesafe_vfprintf, gl_consolesafe_vprintf): New declarations.
+ (fprintf): When msvcrt is in use, use gl_consolesafe_fprintf.
+ (printf): When msvcrt is in use, use gl_consolesafe_printf.
+ (vfprintf): When msvcrt is in use, use gl_consolesafe_vfprintf.
+ (vprintf): When msvcrt is in use, use gl_consolesafe_vprintf.
+ * lib/stdio-consolesafe.c: Include fseterr.h.
+ (gl_consolesafe_fprintf, gl_consolesafe_printf, gl_consolesafe_vfprintf,
+ gl_consolesafe_vprintf): New functions.
+ * lib/stdio-write.c (vfprintf): When msvcrt is in use, use
+ gl_consolesafe_vfprintf.
+ * modules/stdio-h (Depends-on): Add fseterr.
+ * doc/posix-functions/fprintf.texi: Document the mingw bug.
+ * doc/posix-functions/printf.texi: Likewise.
+ * doc/posix-functions/vfprintf.texi: Likewise.
+ * doc/posix-functions/vprintf.texi: Likewise.
+
2025-09-17 Bruno Haible <bruno@clisp.org>
stdio-h: Work around fwrite bug in msvcrt.
@mindex nonblocking
@mindex sigpipe
+Portability problems fixed by either Gnulib module @code{stdio-h} or @code{fprintf-posix} or @code{fprintf-gnu}:
+@itemize
+@item
+This function does not support non-ASCII characters in double-byte encoding,
+corresponding to the locale, on some platforms:
+@c https://github.com/mlocati/gettext-iconv-windows/issues/52
+mingw with @code{__USE_MINGW_ANSI_STDIO} in combination with msvcrt,
+when the output goes to a Windows console.
+@end itemize
+
Portability problems fixed by either Gnulib module @code{fprintf-posix} or @code{fprintf-gnu}:
@itemize
@item
@mindex nonblocking
@mindex sigpipe
+Portability problems fixed by either Gnulib module @code{stdio-h} or @code{fprintf-posix} or @code{fprintf-gnu}:
+@itemize
+@item
+This function does not support non-ASCII characters in double-byte encoding,
+corresponding to the locale, on some platforms:
+@c https://github.com/mlocati/gettext-iconv-windows/issues/52
+mingw with @code{__USE_MINGW_ANSI_STDIO} in combination with msvcrt,
+when the output goes to a Windows console.
+@end itemize
+
Portability problems fixed by either Gnulib module @code{printf-posix} or @code{printf-gnu}:
@itemize
@item
@mindex nonblocking
@mindex sigpipe
+Portability problems fixed by either Gnulib module @code{stdio-h} or @code{fprintf-posix} or @code{fprintf-gnu}:
+@itemize
+@item
+This function does not support non-ASCII characters in double-byte encoding,
+corresponding to the locale, on some platforms:
+@c https://github.com/mlocati/gettext-iconv-windows/issues/52
+mingw with @code{__USE_MINGW_ANSI_STDIO} in combination with msvcrt,
+when the output goes to a Windows console.
+@end itemize
+
Portability problems fixed by either Gnulib module @code{vfprintf-posix} or @code{vfprintf-gnu}:
@itemize
@item
@mindex nonblocking
@mindex sigpipe
+Portability problems fixed by either Gnulib module @code{stdio-h} or @code{fprintf-posix} or @code{fprintf-gnu}:
+@itemize
+@item
+This function does not support non-ASCII characters in double-byte encoding,
+corresponding to the locale, on some platforms:
+@c https://github.com/mlocati/gettext-iconv-windows/issues/52
+mingw with @code{__USE_MINGW_ANSI_STDIO} in combination with msvcrt,
+when the output goes to a Windows console.
+@end itemize
+
Portability problems fixed by either Gnulib module @code{vprintf-posix} or @code{vprintf-gnu}:
@itemize
@item
size_t written = workaround_fwrite0 (tmp, nbytes, fp);
return written / size;
}
+
+#if defined __MINGW32__ && __USE_MINGW_ANSI_STDIO
+
+# include "fseterr.h"
+
+/* Bypass the functions __mingw_[v][f]printf, that trigger a bug in msvcrt,
+ but without losing the support for modern format specifiers added by
+ __mingw_*printf. */
+
+int
+gl_consolesafe_fprintf (FILE *restrict fp, const char *restrict format, ...)
+{
+ va_list args;
+ char *tmpstring;
+ va_start (args, format);
+ int result = vasprintf (&tmpstring, format, args);
+ va_end (args);
+ if (result >= 0)
+ {
+ if (workaround_fwrite0 (tmpstring, result, fp) < result)
+ result = -1;
+ }
+ else
+ fseterr (fp);
+ return result;
+}
+
+int
+gl_consolesafe_printf (const char *restrict format, ...)
+{
+ va_list args;
+ char *tmpstring;
+ va_start (args, format);
+ int result = vasprintf (&tmpstring, format, args);
+ va_end (args);
+ if (result >= 0)
+ {
+ if (workaround_fwrite0 (tmpstring, result, stdout) < result)
+ result = -1;
+ }
+ else
+ fseterr (stdout);
+ return result;
+}
+
+int
+gl_consolesafe_vfprintf (FILE *restrict fp,
+ const char *restrict format, va_list args)
+{
+ char *tmpstring;
+ int result = vasprintf (&tmpstring, format, args);
+ if (result >= 0)
+ {
+ if (workaround_fwrite0 (tmpstring, result, fp) < result)
+ result = -1;
+ }
+ else
+ fseterr (fp);
+ return result;
+}
+
+int
+gl_consolesafe_vprintf (const char *restrict format, va_list args)
+{
+ char *tmpstring;
+ int result = vasprintf (&tmpstring, format, args);
+ if (result >= 0)
+ {
+ if (workaround_fwrite0 (tmpstring, result, stdout) < result)
+ result = -1;
+ }
+ else
+ fseterr (stdout);
+ return result;
+}
+
+#endif
int
vfprintf (FILE *stream, const char *format, va_list args)
#undef vfprintf
+#if defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
+# define vfprintf gl_consolesafe_vfprintf
+#endif
{
CALL_WITH_SIGPIPE_EMULATION (int, vfprintf (stream, format, args), ret == EOF)
}
_GL_FUNCDECL_SYS (gl_consolesafe_fwrite, size_t,
(const void *ptr, size_t size, size_t nmemb, FILE *fp),
_GL_ARG_NONNULL ((1, 4)));
+# if defined __MINGW32__
+_GL_FUNCDECL_SYS (gl_consolesafe_fprintf, int,
+ (FILE *restrict fp, const char *restrict format, ...),
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_FUNCDECL_SYS (gl_consolesafe_printf, int,
+ (const char *restrict format, ...),
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 2)
+ _GL_ARG_NONNULL ((1)));
+_GL_FUNCDECL_SYS (gl_consolesafe_vfprintf, int,
+ (FILE *restrict fp,
+ const char *restrict format, va_list args),
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
+ _GL_ARG_NONNULL ((1, 2)));
+_GL_FUNCDECL_SYS (gl_consolesafe_vprintf, int,
+ (const char *restrict format, va_list args),
+ _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (1, 0)
+ _GL_ARG_NONNULL ((1)));
+# endif
#endif
# if __GLIBC__ >= 2
_GL_CXXALIASWARN (fprintf);
# endif
+#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef fprintf
+# define fprintf gl_consolesafe_fprintf
+# endif
#endif
#if !@GNULIB_FPRINTF_POSIX@ && defined GNULIB_POSIXCHECK
# if !GNULIB_overrides_fprintf
# if __GLIBC__ >= 2
_GL_CXXALIASWARN (printf);
# endif
+#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef printf
+# define printf gl_consolesafe_printf
+# endif
#endif
#if !@GNULIB_PRINTF_POSIX@ && defined GNULIB_POSIXCHECK
# if !GNULIB_overrides_printf
# if __GLIBC__ >= 2
_GL_CXXALIASWARN (vfprintf);
# endif
+#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef vfprintf
+# define vfprintf gl_consolesafe_vfprintf
+# endif
#endif
#if !@GNULIB_VFPRINTF_POSIX@ && defined GNULIB_POSIXCHECK
# if !GNULIB_overrides_vfprintf
# if __GLIBC__ >= 2
_GL_CXXALIASWARN (vprintf);
# endif
+#elif defined __MINGW32__ && !defined _UCRT && __USE_MINGW_ANSI_STDIO
+# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+# undef vprintf
+# define vprintf gl_consolesafe_vprintf
+# endif
#endif
#if !@GNULIB_VPRINTF_POSIX@ && defined GNULIB_POSIXCHECK
# if !GNULIB_overrides_vprintf
stddef-h
sys_types-h
stdckdint-h
+fseterr
configure.ac-early:
gl_STDIO_H_EARLY