From b0afb8fe0ff1d87165af9df61501197a06240dda Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 28 Dec 2025 12:13:40 +0100 Subject: Sync with Gnulib stable-202507 code (a8ac9f9ce5) --- gl/stdio-consolesafe.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 gl/stdio-consolesafe.c (limited to 'gl/stdio-consolesafe.c') diff --git a/gl/stdio-consolesafe.c b/gl/stdio-consolesafe.c new file mode 100644 index 00000000..80561a6d --- /dev/null +++ b/gl/stdio-consolesafe.c @@ -0,0 +1,199 @@ +/* msvcrt workarounds. + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +/* Specification. */ +#include + +#include +#include +#include + +/* Outputs N bytes starting at S to FP. + These N bytes are known to be followed by a NUL. + Finally frees the string at S. + Returns the number of written bytes. */ +static size_t +workaround_fwrite0 (char *s, size_t n, FILE *fp) +{ + const char *ptr = s; + /* Use fputs instead of fwrite, which is buggy in msvcrt. */ + size_t written = 0; + while (n > 0) + { + size_t l = strlen (ptr); /* 0 <= l <= n */ + if (l > 0) + { + if (fputs (ptr, fp) == EOF) + break; + written += l; + n -= l; + } + if (n == 0) + break; + if (fputc ('\0', fp) == EOF) + break; + written++; + n--; + ptr += l + 1; + } + free (s); + return written; +} + +size_t +gl_consolesafe_fwrite (const void *ptr, size_t size, size_t nmemb, FILE *fp) +{ + size_t nbytes; + if (ckd_mul (&nbytes, size, nmemb) || nbytes == 0) + /* Overflow, or nothing to do. */ + return 0; + char *tmp = malloc (nbytes + 1); + if (tmp == NULL) + return 0; + memcpy (tmp, ptr, nbytes); + tmp[nbytes] = '\0'; + size_t written = workaround_fwrite0 (tmp, nbytes, fp); + return written / size; +} + +#if defined __MINGW32__ && __USE_MINGW_ANSI_STDIO + +# include "fseterr.h" +# include + +# if !HAVE_VASPRINTF + +# include + +/* The old mingw (before mingw-w64) does not have the vasprintf function. + Define a suitable replacement here, that supports the same format + specifiers as the mingw *printf functions. */ + +static int +vasprintf (char **resultp, const char *format, va_list args) +{ + /* First try: Use a stack-allocated buffer. */ + char buf[2048]; + size_t bufsize = sizeof (buf); + int ret = __mingw_vsnprintf (buf, bufsize, format, args); + if (ret < 0) + return -1; + size_t nbytes = ret; + char *mem = (char *) malloc (nbytes + 1); + if (mem == NULL) + { + errno = ENOMEM; + return -1; + } + if (ret < bufsize) + { + /* The buffer was sufficiently large. */ + memcpy (mem, buf, nbytes + 1); + } + else + { + /* Second try: Use the heap-allocated memory. */ + ret = __mingw_vsnprintf (mem, nbytes + 1, format, args); + if (ret < 0) + { + int saved_errno = errno; + free (mem); + errno = saved_errno; + return -1; + } + if (ret != nbytes) + abort (); + } + *resultp = mem; + return nbytes; +} + +# endif + +/* 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 -- cgit v1.2.3-74-g34f1