As discussed in the thread starting at
<https://lists.gnu.org/archive/html/bug-gnulib/2024-04/msg00352.html>,
I'm adding *zs*printf modules, that are like the existing variants
without 'z', except that
  - they support returning results of length > INT_MAX,
  - thus the length type is changed to 'ptrdiff_t' from 'int',
  - an attempt to return a result > PTRDIFF_MAX produces an error
    ENOMEM (consistently with malloc, calloc) instead of EOVERFLOW.

For file stream and file descriptor based function, a similar thing
will be done, with 'off64_t' (instead of ptrdiff_t) replacing 'int'.

Here comes the first part of the string functions.

     snprintf -> vzsnprintf
     zsnprintf -> vasnprintf
     sprintf -> vzsprintf
     zsprintf -> vasnprintf
     vasprintf -> vazsprintf
     vazsprintf -> vasnprintf
     vsnprintf -> vzsnprintf
     vzsnprintf -> vasnprintf
     vsprintf -> vzsprintf
     vzsprintf -> vasnprintf
     xvasprintf -> vazsprintf

Note that the last patch, in xvasprintf, also fixes a long-standing bug:
The code was examining errno after vasprintf failed, but vasprintf is
not documented to set errno upon failure.


2024-06-22  Bruno Haible  <br...@clisp.org>

        xvasprintf: Guarantee a non-NULL result.
        * lib/xvasprintf.h: Clarify the programmer's responsibilities.
        (xasprintf, xvasprintf): Declare as returning non-NULL.
        * lib/xvasprintf.c: Include <stdlib.h>.
        (xstrcat): Allow results longer than INT_MAX characters. Upon size
        overflow, invoke xalloc_die.
        (xvasprintf): Call vazsprintf instead of vasprintf. When some other
        error occurs, emit an error message and abort.
        * m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
        from gl_FUNC_STRERRORNAME_NP.
        (gl_FUNC_STRERRORNAME_NP): Invoke it.
        (gl_OPTIONAL_STRERRORNAME_NP): New macro.
        * m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
        * modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
        (Depends-on): Add extensions, vazsprintf. Remove vasprintf.
        * NEWS: Mention the change.

2024-06-22  Bruno Haible  <br...@clisp.org>

        vasprintf: Make return convention consistent with other modules.
        * lib/vasprintf.c: Include <stdint.h>.
        (vasprintf): If the length is > PTRDIFF_MAX, fail with ENOMEM, not
        EOVERFLOW.
        * modules/vasprintf (Depends-on): Add stdint.

        vazsprintf: New module.
        * lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
        * lib/vazsprintf.c: New file, based on lib/vasprintf.c.
        * lib/azsprintf.c: New file, based on lib/asprintf.c.
        * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
        GNULIB_VAZSPRINTF.
        * modules/stdio (Makefile.am): Substitute GNULIB_VAZSPRINTF.
        * modules/vazsprintf: New file.

2024-06-22  Bruno Haible  <br...@clisp.org>

        sprintf-posix: Use vzsprintf.
        * lib/stdio.in.h (sprintf): Move specification to here.
        * lib/sprintf.c: Don't include <stdlib.h>, vasnprintf.h. Include
        <stdint.h>.
        (sprintf): Implement based on vzsprintf.
        * modules/sprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.

        zsprintf: New module.
        * lib/stdio.in.h (zsprintf): New declaration, based on
        lib/sprintf.c.
        * lib/zsprintf.c: New file, based on lib/sprintf.c.
        * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
        GNULIB_ZSPRINTF.
        * modules/stdio (Makefile.am): Substitute GNULIB_ZSPRINTF.
        * modules/zsprintf: New file.

2024-06-22  Bruno Haible  <br...@clisp.org>

        vsprintf-posix: Use vzsprintf.
        * lib/stdio.in.h (vsprintf): Move specification to here.
        * lib/vsprintf.c: Don't include <stdlib.h>, vasnprintf.h.
        (SIZE_MAX): Remove macro.
        (vsprintf): Implement based on vzsprintf.
        * modules/vsprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.

        vzsprintf: New module.
        * lib/stdio.in.h (vzsprintf): New declaration, based on
        lib/vsprintf.c.
        * lib/vzsprintf.c: New file, based on lib/vsprintf.c.
        * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
        GNULIB_VZSPRINTF.
        * modules/stdio (Makefile.am): Substitute GNULIB_VZSPRINTF.
        * modules/vzsprintf: New file.

2024-06-22  Bruno Haible  <br...@clisp.org>

        snprintf: Use vzsnprintf.
        * lib/stdio.in.h (snprintf): Move specification to here.
        * lib/snprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
        Include <stdint.h>.
        (snprintf): Implement based on vzsnprintf.
        * modules/snprintf (Depends-on): Add stdint, vzsnprintf. Remove
        vasnprintf.

        zsnprintf: New module.
        * lib/stdio.in.h (zsnprintf): New declaration, based on
        lib/snprintf.c.
        * lib/zsnprintf.c: New file, based on lib/snprintf.c.
        * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
        GNULIB_ZSNPRINTF.
        * modules/stdio (Makefile.am): Substitute GNULIB_ZSNPRINTF.
        * modules/zsnprintf: New file.

2024-06-22  Bruno Haible  <br...@clisp.org>

        vsnprintf: Use vzsnprintf.
        * lib/stdio.in.h (vsnprintf): Move specification to here.
        * lib/vsnprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
        Include <stdint.h>.
        (vsnprintf): Implement based on vzsnprintf.
        * modules/vsnprintf (Depends-on): Add stdint, vzsnprintf. Remove
        vasnprintf.

        vzsnprintf: New module.
        * lib/stdio.in.h (vzsnprintf): New declaration, based on
        lib/vsnprintf.c.
        * lib/vzsnprintf.c: New file, based on lib/vsnprintf.c.
        * m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
        GNULIB_VZSNPRINTF.
        * modules/stdio (Makefile.am): Substitute GNULIB_VZSNPRINTF.
        * modules/vzsnprintf: New file.

>From 599f3ed9963c52be0122b6a5f01b33a13cdcbdda Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:14:41 +0200
Subject: [PATCH 01/11] vzsnprintf: New module.

* lib/stdio.in.h (vzsnprintf): New declaration, based on
lib/vsnprintf.c.
* lib/vzsnprintf.c: New file, based on lib/vsnprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VZSNPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VZSNPRINTF.
* modules/vzsnprintf: New file.
---
 ChangeLog          | 11 ++++++++
 lib/stdio.in.h     | 19 ++++++++++++++
 lib/vzsnprintf.c   | 65 ++++++++++++++++++++++++++++++++++++++++++++++
 m4/stdio_h.m4      |  3 ++-
 modules/stdio      |  1 +
 modules/vzsnprintf | 27 +++++++++++++++++++
 6 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 lib/vzsnprintf.c
 create mode 100644 modules/vzsnprintf

diff --git a/ChangeLog b/ChangeLog
index 8e82912063..60ed445021 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22  Bruno Haible  <br...@clisp.org>
+
+	vzsnprintf: New module.
+	* lib/stdio.in.h (vzsnprintf): New declaration, based on
+	lib/vsnprintf.c.
+	* lib/vzsnprintf.c: New file, based on lib/vsnprintf.c.
+	* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+	GNULIB_VZSNPRINTF.
+	* modules/stdio (Makefile.am): Substitute GNULIB_VZSNPRINTF.
+	* modules/vzsnprintf: New file.
+
 2024-06-20  Bruno Haible  <br...@clisp.org>
 
 	test-framework-sh: Fix side effect on dfa tests (regression 2024-06-11).
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 1c0c9661bf..d8d27a56c5 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1769,6 +1769,25 @@ _GL_CXXALIASWARN (vscanf);
 # endif
 #endif
 
+#if @GNULIB_VZSNPRINTF@
+/* Prints formatted output to string STR.  Similar to sprintf, but the
+   additional parameter SIZE limits how much is written into STR.
+   STR may be NULL, in which case nothing will be written.
+   Returns the string length of the formatted string (which may be larger
+   than SIZE).  Upon failure, returns -1 with errno set.
+   Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+   Therefore, if the format string is valid and does not use %ls/%lc
+   directives nor widths, the only possible failure code is ENOMEM.  */
+_GL_FUNCDECL_SYS (vzsnprintf, ptrdiff_t,
+                  (char *restrict str, size_t size,
+                   const char *restrict format, va_list args)
+                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 0)
+                  _GL_ARG_NONNULL ((3)));
+_GL_CXXALIAS_SYS (vzsnprintf, ptrdiff_t,
+                  (char *restrict str, size_t size,
+                   const char *restrict format, va_list args));
+#endif
+
 #if @GNULIB_VSNPRINTF@
 # if @REPLACE_VSNPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/lib/vzsnprintf.c b/lib/vzsnprintf.c
new file mode 100644
index 0000000000..96e240bdb7
--- /dev/null
+++ b/lib/vzsnprintf.c
@@ -0,0 +1,65 @@
+/* Formatted output to strings.
+   Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
+   Written by Simon Josefsson and Yoann Vandoorselaere <yo...@prelude-ids.org>.
+
+   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 <https://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+vzsnprintf (char *str, size_t size, const char *format, va_list args)
+{
+  char *output;
+  size_t len;
+  size_t lenbuf = size;
+
+  output = vasnprintf (str, &lenbuf, format, args);
+  len = lenbuf;
+
+  if (!output)
+    return -1;
+
+  if (output != str)
+    {
+      if (size)
+        {
+          size_t pruned_len = (len < size ? len : size - 1);
+          memcpy (str, output, pruned_len);
+          str[pruned_len] = '\0';
+        }
+
+      free (output);
+    }
+
+  if (len > PTRDIFF_MAX)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 8eb5816ad7..9c631f172f 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
 # stdio_h.m4
-# serial 63
+# serial 64
 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -186,6 +186,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VPRINTF_POSIX])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
     dnl Support Microsoft deprecated alias function names by default.
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
diff --git a/modules/stdio b/modules/stdio
index 45ae9824ed..63ea9a908e 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -121,6 +121,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
 	      -e 's/@''GNULIB_VPRINTF_POSIX''@/$(GNULIB_VPRINTF_POSIX)/g' \
 	      -e 's/@''GNULIB_VSNPRINTF''@/$(GNULIB_VSNPRINTF)/g' \
 	      -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GNULIB_VSPRINTF_POSIX)/g' \
+	      -e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
 	      -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
 	      -e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
 	      -e 's/@''GNULIB_MDA_FILENO''@/$(GNULIB_MDA_FILENO)/g' \
diff --git a/modules/vzsnprintf b/modules/vzsnprintf
new file mode 100644
index 0000000000..853d88210d
--- /dev/null
+++ b/modules/vzsnprintf
@@ -0,0 +1,27 @@
+Description:
+vzsnprintf() function: print formatted output from an stdarg argument list
+to a fixed length string (without INT_MAX limitation)
+
+Files:
+lib/vzsnprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([vzsnprintf])
+
+Makefile.am:
+lib_SOURCES += vzsnprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.34.1

>From 7a34ce4ce5652715bd9dc9d2b3a82a2ea97ed4bc Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:14:52 +0200
Subject: [PATCH 02/11] vsnprintf: Use vzsnprintf.

* lib/stdio.in.h (vsnprintf): Move specification to here.
* lib/vsnprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
Include <stdint.h>.
(vsnprintf): Implement based on vzsnprintf.
* modules/vsnprintf (Depends-on): Add stdint, vzsnprintf. Remove
vasnprintf.
---
 ChangeLog         |  8 ++++++++
 lib/stdio.in.h    |  5 +++++
 lib/vsnprintf.c   | 39 ++++++---------------------------------
 modules/vsnprintf |  5 +++--
 4 files changed, 22 insertions(+), 35 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 60ed445021..28833003fb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
+	vsnprintf: Use vzsnprintf.
+	* lib/stdio.in.h (vsnprintf): Move specification to here.
+	* lib/vsnprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
+	Include <stdint.h>.
+	(vsnprintf): Implement based on vzsnprintf.
+	* modules/vsnprintf (Depends-on): Add stdint, vzsnprintf. Remove
+	vasnprintf.
+
 	vzsnprintf: New module.
 	* lib/stdio.in.h (vzsnprintf): New declaration, based on
 	lib/vsnprintf.c.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index d8d27a56c5..8d6cd21fd5 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1789,6 +1789,11 @@ _GL_CXXALIAS_SYS (vzsnprintf, ptrdiff_t,
 #endif
 
 #if @GNULIB_VSNPRINTF@
+/* Prints formatted output to string STR.  Similar to vsprintf, but the
+   additional parameter SIZE limits how much is written into STR.
+   STR may be NULL, in which case nothing will be written.
+   Returns the string length of the formatted string (which may be larger
+   than SIZE).  Upon failure, returns a negative value.  */
 # if @REPLACE_VSNPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define vsnprintf rpl_vsnprintf
diff --git a/lib/vsnprintf.c b/lib/vsnprintf.c
index e6676a1ffa..1954dcea26 100644
--- a/lib/vsnprintf.c
+++ b/lib/vsnprintf.c
@@ -1,6 +1,5 @@
 /* Formatted output to strings.
    Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
-   Written by Simon Josefsson and Yoann Vandoorselaere <yo...@prelude-ids.org>.
 
    This file is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
@@ -25,46 +24,20 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <stdint.h>
 
-#include "vasnprintf.h"
-
-/* Print formatted output to string STR.  Similar to vsprintf, but
-   additional length SIZE limit how much is written into STR.  Returns
-   string length of formatted string (which may be larger than SIZE).
-   STR may be NULL, in which case nothing will be written.  On error,
-   return a negative value.  */
 int
 vsnprintf (char *str, size_t size, const char *format, va_list args)
 {
-  char *output;
-  size_t len;
-  size_t lenbuf = size;
-
-  output = vasnprintf (str, &lenbuf, format, args);
-  len = lenbuf;
-
-  if (!output)
-    return -1;
-
-  if (output != str)
-    {
-      if (size)
-        {
-          size_t pruned_len = (len < size ? len : size - 1);
-          memcpy (str, output, pruned_len);
-          str[pruned_len] = '\0';
-        }
-
-      free (output);
-    }
+  ptrdiff_t ret = vzsnprintf (str, size, format, args);
 
-  if (len > INT_MAX)
+#if PTRDIFF_MAX > INT_MAX
+  if (ret > INT_MAX)
     {
       errno = EOVERFLOW;
       return -1;
     }
+#endif
 
-  return len;
+  return ret;
 }
diff --git a/modules/vsnprintf b/modules/vsnprintf
index 053b10c32a..de2a86e285 100644
--- a/modules/vsnprintf
+++ b/modules/vsnprintf
@@ -9,8 +9,9 @@ m4/printf.m4
 
 Depends-on:
 stdio
-vasnprintf      [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
 errno           [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
+stdint          [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
+vzsnprintf      [test $ac_cv_func_vsnprintf = no || test $REPLACE_VSNPRINTF = 1]
 
 configure.ac:
 gl_FUNC_VSNPRINTF
@@ -25,4 +26,4 @@ License:
 LGPLv2+
 
 Maintainer:
-Yoann Vandoorselaere
+all
-- 
2.34.1

>From c85fa7f8a128437cca30f396df8392af1c1b7632 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:15:32 +0200
Subject: [PATCH 03/11] zsnprintf: New module.

* lib/stdio.in.h (zsnprintf): New declaration, based on
lib/snprintf.c.
* lib/zsnprintf.c: New file, based on lib/snprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_ZSNPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_ZSNPRINTF.
* modules/zsnprintf: New file.
---
 ChangeLog         | 11 ++++++++
 lib/stdio.in.h    | 19 ++++++++++++++
 lib/zsnprintf.c   | 66 +++++++++++++++++++++++++++++++++++++++++++++++
 m4/stdio_h.m4     |  3 ++-
 modules/stdio     |  1 +
 modules/zsnprintf | 27 +++++++++++++++++++
 6 files changed, 126 insertions(+), 1 deletion(-)
 create mode 100644 lib/zsnprintf.c
 create mode 100644 modules/zsnprintf

diff --git a/ChangeLog b/ChangeLog
index 28833003fb..458561b9fe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22  Bruno Haible  <br...@clisp.org>
+
+	zsnprintf: New module.
+	* lib/stdio.in.h (zsnprintf): New declaration, based on
+	lib/snprintf.c.
+	* lib/zsnprintf.c: New file, based on lib/snprintf.c.
+	* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+	GNULIB_ZSNPRINTF.
+	* modules/stdio (Makefile.am): Substitute GNULIB_ZSNPRINTF.
+	* modules/zsnprintf: New file.
+
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
 	vsnprintf: Use vzsnprintf.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 8d6cd21fd5..4a942a92ed 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1433,6 +1433,25 @@ _GL_CXXALIASWARN (scanf);
 # endif
 #endif
 
+#if @GNULIB_ZSNPRINTF@
+/* Prints formatted output to string STR.  Similar to sprintf, but the
+   additional parameter SIZE limits how much is written into STR.
+   STR may be NULL, in which case nothing will be written.
+   Returns the string length of the formatted string (which may be larger
+   than SIZE).  Upon failure, returns -1 with errno set.
+   Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+   Therefore, if the format string is valid and does not use %ls/%lc
+   directives nor widths, the only possible failure code is ENOMEM.  */
+_GL_FUNCDECL_SYS (zsnprintf, ptrdiff_t,
+                  (char *restrict str, size_t size,
+                   const char *restrict format, ...)
+                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (3, 4)
+                  _GL_ARG_NONNULL ((3)));
+_GL_CXXALIAS_SYS (zsnprintf, ptrdiff_t,
+                  (char *restrict str, size_t size,
+                   const char *restrict format, ...));
+#endif
+
 #if @GNULIB_SNPRINTF@
 # if @REPLACE_SNPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/lib/zsnprintf.c b/lib/zsnprintf.c
new file mode 100644
index 0000000000..894631d16a
--- /dev/null
+++ b/lib/zsnprintf.c
@@ -0,0 +1,66 @@
+/* Formatted output to strings.
+   Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
+   Written by Simon Josefsson and Paul Eggert.
+
+   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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+zsnprintf (char *str, size_t size, const char *format, ...)
+{
+  char *output;
+  size_t len;
+  size_t lenbuf = size;
+  va_list args;
+
+  va_start (args, format);
+  output = vasnprintf (str, &lenbuf, format, args);
+  len = lenbuf;
+  va_end (args);
+
+  if (!output)
+    return -1;
+
+  if (output != str)
+    {
+      if (size)
+        {
+          size_t pruned_len = (len < size ? len : size - 1);
+          memcpy (str, output, pruned_len);
+          str[pruned_len] = '\0';
+        }
+
+      free (output);
+    }
+
+  if (len > PTRDIFF_MAX)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 9c631f172f..28d1c96c74 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
 # stdio_h.m4
-# serial 64
+# serial 65
 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -187,6 +187,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF])
     dnl Support Microsoft deprecated alias function names by default.
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
diff --git a/modules/stdio b/modules/stdio
index 63ea9a908e..9e676681dd 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -122,6 +122,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
 	      -e 's/@''GNULIB_VSNPRINTF''@/$(GNULIB_VSNPRINTF)/g' \
 	      -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GNULIB_VSPRINTF_POSIX)/g' \
 	      -e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
+	      -e 's/@''GNULIB_ZSNPRINTF''@/$(GNULIB_ZSNPRINTF)/g' \
 	      -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
 	      -e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
 	      -e 's/@''GNULIB_MDA_FILENO''@/$(GNULIB_MDA_FILENO)/g' \
diff --git a/modules/zsnprintf b/modules/zsnprintf
new file mode 100644
index 0000000000..40fd329e0e
--- /dev/null
+++ b/modules/zsnprintf
@@ -0,0 +1,27 @@
+Description:
+zsnprintf() function: print formatted output to a fixed length string
+(without INT_MAX limitation)
+
+Files:
+lib/zsnprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([zsnprintf])
+
+Makefile.am:
+lib_SOURCES += zsnprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.34.1

>From fdcddac143b28818efadd52f2f3c840778eda0bb Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:15:38 +0200
Subject: [PATCH 04/11] snprintf: Use vzsnprintf.

* lib/stdio.in.h (snprintf): Move specification to here.
* lib/snprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
Include <stdint.h>.
(snprintf): Implement based on vzsnprintf.
* modules/snprintf (Depends-on): Add stdint, vzsnprintf. Remove
vasnprintf.
---
 ChangeLog        |  8 ++++++++
 lib/snprintf.c   | 39 +++++++--------------------------------
 lib/stdio.in.h   |  5 +++++
 modules/snprintf |  5 +++--
 4 files changed, 23 insertions(+), 34 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 458561b9fe..68677a44ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
+	snprintf: Use vzsnprintf.
+	* lib/stdio.in.h (snprintf): Move specification to here.
+	* lib/snprintf.c: Don't include <stdlib.h>, <string.h>, vasnprintf.h.
+	Include <stdint.h>.
+	(snprintf): Implement based on vzsnprintf.
+	* modules/snprintf (Depends-on): Add stdint, vzsnprintf. Remove
+	vasnprintf.
+
 	zsnprintf: New module.
 	* lib/stdio.in.h (zsnprintf): New declaration, based on
 	lib/snprintf.c.
diff --git a/lib/snprintf.c b/lib/snprintf.c
index c1b93562ec..80f69225ac 100644
--- a/lib/snprintf.c
+++ b/lib/snprintf.c
@@ -1,6 +1,5 @@
 /* Formatted output to strings.
    Copyright (C) 2004, 2006-2024 Free Software Foundation, Inc.
-   Written by Simon Josefsson and Paul Eggert.
 
    This file is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
@@ -23,49 +22,25 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
+#include <stdint.h>
 
-#include "vasnprintf.h"
-
-/* Print formatted output to string STR.  Similar to sprintf, but
-   additional length SIZE limit how much is written into STR.  Returns
-   string length of formatted string (which may be larger than SIZE).
-   STR may be NULL, in which case nothing will be written.  On error,
-   return a negative value.  */
 int
 snprintf (char *str, size_t size, const char *format, ...)
 {
-  char *output;
-  size_t len;
-  size_t lenbuf = size;
   va_list args;
+  ptrdiff_t ret;
 
   va_start (args, format);
-  output = vasnprintf (str, &lenbuf, format, args);
-  len = lenbuf;
+  ret = vzsnprintf (str, size, format, args);
   va_end (args);
 
-  if (!output)
-    return -1;
-
-  if (output != str)
-    {
-      if (size)
-        {
-          size_t pruned_len = (len < size ? len : size - 1);
-          memcpy (str, output, pruned_len);
-          str[pruned_len] = '\0';
-        }
-
-      free (output);
-    }
-
-  if (INT_MAX < len)
+#if PTRDIFF_MAX > INT_MAX
+  if (ret > INT_MAX)
     {
       errno = EOVERFLOW;
       return -1;
     }
+#endif
 
-  return len;
+  return ret;
 }
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 4a942a92ed..d0479c10ae 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1453,6 +1453,11 @@ _GL_CXXALIAS_SYS (zsnprintf, ptrdiff_t,
 #endif
 
 #if @GNULIB_SNPRINTF@
+/* Prints formatted output to string STR.  Similar to sprintf, but the
+   additional parameter SIZE limits how much is written into STR.
+   STR may be NULL, in which case nothing will be written.
+   Returns the string length of the formatted string (which may be larger
+   than SIZE).  Upon failure, returns a negative value.  */
 # if @REPLACE_SNPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define snprintf rpl_snprintf
diff --git a/modules/snprintf b/modules/snprintf
index 102d629706..cd4eb6b2c4 100644
--- a/modules/snprintf
+++ b/modules/snprintf
@@ -8,8 +8,9 @@ m4/printf.m4
 
 Depends-on:
 stdio
-vasnprintf      [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
 errno           [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
+stdint          [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
+vzsnprintf      [test $ac_cv_func_snprintf = no || test $REPLACE_SNPRINTF = 1]
 
 configure.ac:
 gl_FUNC_SNPRINTF
@@ -25,4 +26,4 @@ License:
 LGPLv2+
 
 Maintainer:
-Simon Josefsson, Paul Eggert
+all
-- 
2.34.1

>From 058db602ad919d2c4c46264a988b94ed6c1c2b05 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:16:00 +0200
Subject: [PATCH 05/11] vzsprintf: New module.

* lib/stdio.in.h (vzsprintf): New declaration, based on
lib/vsprintf.c.
* lib/vzsprintf.c: New file, based on lib/vsprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VZSPRINTF.
* modules/vzsprintf: New file.
---
 ChangeLog         | 11 ++++++++
 lib/stdio.in.h    | 17 +++++++++++++
 lib/vzsprintf.c   | 64 +++++++++++++++++++++++++++++++++++++++++++++++
 m4/stdio_h.m4     |  3 ++-
 modules/stdio     |  1 +
 modules/vzsprintf | 27 ++++++++++++++++++++
 6 files changed, 122 insertions(+), 1 deletion(-)
 create mode 100644 lib/vzsprintf.c
 create mode 100644 modules/vzsprintf

diff --git a/ChangeLog b/ChangeLog
index 68677a44ad..470192143c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22  Bruno Haible  <br...@clisp.org>
+
+	vzsprintf: New module.
+	* lib/stdio.in.h (vzsprintf): New declaration, based on
+	lib/vsprintf.c.
+	* lib/vzsprintf.c: New file, based on lib/vsprintf.c.
+	* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+	GNULIB_VZSPRINTF.
+	* modules/stdio (Makefile.am): Substitute GNULIB_VZSPRINTF.
+	* modules/vzsprintf: New file.
+
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
 	snprintf: Use vzsnprintf.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index d0479c10ae..2d7e20e3d1 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1854,6 +1854,23 @@ _GL_WARN_ON_USE (vsnprintf, "vsnprintf is unportable - "
 # endif
 #endif
 
+#if @GNULIB_VZSPRINTF@
+/* Prints formatted output to string STR.
+   Returns the string length of the formatted string.  Upon failure,
+   returns -1 with errno set.
+   Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+   Therefore, if the format string is valid and does not use %ls/%lc
+   directives nor widths, the only possible failure code is ENOMEM.  */
+_GL_FUNCDECL_SYS (vzsprintf, ptrdiff_t,
+                  (char *restrict str,
+                   const char *restrict format, va_list args)
+                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
+                  _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (vzsprintf, ptrdiff_t,
+                  (char *restrict str,
+                   const char *restrict format, va_list args));
+#endif
+
 #if @GNULIB_VSPRINTF_POSIX@
 # if @REPLACE_VSPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
diff --git a/lib/vzsprintf.c b/lib/vzsprintf.c
new file mode 100644
index 0000000000..549543070c
--- /dev/null
+++ b/lib/vzsprintf.c
@@ -0,0 +1,64 @@
+/* Formatted output to strings.
+   Copyright (C) 2004, 2006-2024 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 3 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 <https://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+vzsprintf (char *str, const char *format, va_list args)
+{
+  char *output;
+  size_t len;
+  size_t lenbuf;
+
+  /* Set lenbuf = min (SIZE_MAX, - (uintptr_t) str - 1).  */
+  lenbuf = SIZE_MAX;
+  if (lenbuf >= ~ (uintptr_t) str)
+    lenbuf = ~ (uintptr_t) str;
+
+  output = vasnprintf (str, &lenbuf, format, args);
+  len = lenbuf;
+
+  if (!output)
+    return -1;
+
+  if (output != str)
+    {
+      /* len is near SIZE_MAX.  */
+      free (output);
+      errno = ENOMEM;
+      return -1;
+    }
+
+  if (len > PTRDIFF_MAX)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 28d1c96c74..f549ca4810 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
 # stdio_h.m4
-# serial 65
+# serial 66
 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -187,6 +187,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSNPRINTF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSPRINTF_POSIX])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSPRINTF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF])
     dnl Support Microsoft deprecated alias function names by default.
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
diff --git a/modules/stdio b/modules/stdio
index 9e676681dd..4e41ae13e8 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -122,6 +122,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
 	      -e 's/@''GNULIB_VSNPRINTF''@/$(GNULIB_VSNPRINTF)/g' \
 	      -e 's/@''GNULIB_VSPRINTF_POSIX''@/$(GNULIB_VSPRINTF_POSIX)/g' \
 	      -e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
+	      -e 's/@''GNULIB_VZSPRINTF''@/$(GNULIB_VZSPRINTF)/g' \
 	      -e 's/@''GNULIB_ZSNPRINTF''@/$(GNULIB_ZSNPRINTF)/g' \
 	      -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
 	      -e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
diff --git a/modules/vzsprintf b/modules/vzsprintf
new file mode 100644
index 0000000000..6564c020f1
--- /dev/null
+++ b/modules/vzsprintf
@@ -0,0 +1,27 @@
+Description:
+vzsprintf() function: print formatted output from an stdarg argument list
+to a string (without INT_MAX limitation)
+
+Files:
+lib/vzsprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([vzsprintf])
+
+Makefile.am:
+lib_SOURCES += vzsprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPL
+
+Maintainer:
+all
-- 
2.34.1

>From 587920f982d6c3e777ee1f98ce36b403ee85c565 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:16:06 +0200
Subject: [PATCH 06/11] vsprintf-posix: Use vzsprintf.

* lib/stdio.in.h (vsprintf): Move specification to here.
* lib/vsprintf.c: Don't include <stdlib.h>, vasnprintf.h.
(SIZE_MAX): Remove macro.
(vsprintf): Implement based on vzsprintf.
* modules/vsprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
---
 ChangeLog              |  7 +++++++
 lib/stdio.in.h         |  3 +++
 lib/vsprintf.c         | 44 +++++-------------------------------------
 modules/vsprintf-posix |  2 +-
 4 files changed, 16 insertions(+), 40 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 470192143c..c823d86fbc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
+	vsprintf-posix: Use vzsprintf.
+	* lib/stdio.in.h (vsprintf): Move specification to here.
+	* lib/vsprintf.c: Don't include <stdlib.h>, vasnprintf.h.
+	(SIZE_MAX): Remove macro.
+	(vsprintf): Implement based on vzsprintf.
+	* modules/vsprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
+
 	vzsprintf: New module.
 	* lib/stdio.in.h (vzsprintf): New declaration, based on
 	lib/vsprintf.c.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 2d7e20e3d1..858ab47736 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1872,6 +1872,9 @@ _GL_CXXALIAS_SYS (vzsprintf, ptrdiff_t,
 #endif
 
 #if @GNULIB_VSPRINTF_POSIX@
+/* Prints formatted output to string STR.
+   Returns the string length of the formatted string.  Upon failure,
+   returns a negative value.  */
 # if @REPLACE_VSPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define vsprintf rpl_vsprintf
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 181bc9814f..065ed74222 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -25,53 +25,19 @@
 #include <limits.h>
 #include <stdarg.h>
 #include <stdint.h>
-#include <stdlib.h>
 
-#include "vasnprintf.h"
-
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-
-/* Print formatted output to string STR.
-   Return string length of formatted string.  On error, return a negative
-   value.  */
 int
 vsprintf (char *str, const char *format, va_list args)
 {
-  char *output;
-  size_t len;
-  size_t lenbuf;
-
-  /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger
-     than INT_MAX (if that fits into a 'size_t' at all).
-     Also note that glibc's iconv fails with E2BIG when we pass a length that
-     is so large that str + lenbuf wraps around, i.e.
-     (uintptr_t) (str + lenbuf) < (uintptr_t) str.
-     Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1).  */
-  lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
-  if (lenbuf > ~ (uintptr_t) str)
-    lenbuf = ~ (uintptr_t) str;
-
-  output = vasnprintf (str, &lenbuf, format, args);
-  len = lenbuf;
-
-  if (!output)
-    return -1;
+  ptrdiff_t ret = vzsprintf (str, format, args);
 
-  if (output != str)
-    {
-      /* len is near SIZE_MAX.  */
-      free (output);
-      errno = EOVERFLOW;
-      return -1;
-    }
-
-  if (len > INT_MAX)
+#if PTRDIFF_MAX > INT_MAX
+  if (ret > INT_MAX)
     {
       errno = EOVERFLOW;
       return -1;
     }
+#endif
 
-  return len;
+  return ret;
 }
diff --git a/modules/vsprintf-posix b/modules/vsprintf-posix
index a3ef9998ed..2bbb36055b 100644
--- a/modules/vsprintf-posix
+++ b/modules/vsprintf-posix
@@ -18,7 +18,7 @@ stdio
 nocrash
 printf-safe
 multiarch
-vasnprintf      [test $REPLACE_VSPRINTF = 1]
+vzsprintf       [test $REPLACE_VSPRINTF = 1]
 isnand-nolibm   [test $REPLACE_VSPRINTF = 1]
 isnanl-nolibm   [test $REPLACE_VSPRINTF = 1]
 frexp-nolibm    [test $REPLACE_VSPRINTF = 1]
-- 
2.34.1

>From f89f459b49563a6dfb82b5deac70d87086a390f3 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:16:24 +0200
Subject: [PATCH 07/11] zsprintf: New module.

* lib/stdio.in.h (zsprintf): New declaration, based on
lib/sprintf.c.
* lib/zsprintf.c: New file, based on lib/sprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_ZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_ZSPRINTF.
* modules/zsprintf: New file.
---
 ChangeLog        | 11 ++++++++
 lib/stdio.in.h   | 17 ++++++++++++
 lib/zsprintf.c   | 67 ++++++++++++++++++++++++++++++++++++++++++++++++
 m4/stdio_h.m4    |  3 ++-
 modules/stdio    |  1 +
 modules/zsprintf | 27 +++++++++++++++++++
 6 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 lib/zsprintf.c
 create mode 100644 modules/zsprintf

diff --git a/ChangeLog b/ChangeLog
index c823d86fbc..96dc1dff2c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22  Bruno Haible  <br...@clisp.org>
+
+	zsprintf: New module.
+	* lib/stdio.in.h (zsprintf): New declaration, based on
+	lib/sprintf.c.
+	* lib/zsprintf.c: New file, based on lib/sprintf.c.
+	* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+	GNULIB_ZSPRINTF.
+	* modules/stdio (Makefile.am): Substitute GNULIB_ZSPRINTF.
+	* modules/zsprintf: New file.
+
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
 	vsprintf-posix: Use vzsprintf.
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 858ab47736..17c662f45a 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1494,6 +1494,23 @@ _GL_WARN_ON_USE (snprintf, "snprintf is unportable - "
 # endif
 #endif
 
+#if @GNULIB_ZSPRINTF@
+/* Prints formatted output to string STR.
+   Returns the string length of the formatted string.  Upon failure,
+   returns -1 with errno set.
+   Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+   Therefore, if the format string is valid and does not use %ls/%lc
+   directives nor widths, the only possible failure code is ENOMEM.  */
+_GL_FUNCDECL_SYS (zsprintf, ptrdiff_t,
+                  (char *restrict str,
+                   const char *restrict format, ...)
+                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
+                  _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (zsprintf, ptrdiff_t,
+                  (char *restrict str,
+                   const char *restrict format, ...));
+#endif
+
 /* Some people would argue that all sprintf uses should be warned about
    (for example, OpenBSD issues a link warning for it),
    since it can cause security holes due to buffer overruns.
diff --git a/lib/zsprintf.c b/lib/zsprintf.c
new file mode 100644
index 0000000000..f004ed7238
--- /dev/null
+++ b/lib/zsprintf.c
@@ -0,0 +1,67 @@
+/* Formatted output to strings.
+   Copyright (C) 2004, 2006-2024 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 3 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 <https://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+zsprintf (char *str, const char *format, ...)
+{
+  char *output;
+  size_t len;
+  size_t lenbuf;
+  va_list args;
+
+  /* Set lenbuf = min (SIZE_MAX, - (uintptr_t) str - 1).  */
+  lenbuf = SIZE_MAX;
+  if (lenbuf >= ~ (uintptr_t) str)
+    lenbuf = ~ (uintptr_t) str;
+
+  va_start (args, format);
+  output = vasnprintf (str, &lenbuf, format, args);
+  len = lenbuf;
+  va_end (args);
+
+  if (!output)
+    return -1;
+
+  if (output != str)
+    {
+      /* len is near SIZE_MAX.  */
+      free (output);
+      errno = ENOMEM;
+      return -1;
+    }
+
+  if (len > PTRDIFF_MAX)
+    {
+      errno = ENOMEM;
+      return -1;
+    }
+
+  return len;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index f549ca4810..69d4b88b4b 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
 # stdio_h.m4
-# serial 66
+# serial 67
 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -189,6 +189,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSNPRINTF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VZSPRINTF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSNPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ZSPRINTF])
     dnl Support Microsoft deprecated alias function names by default.
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FCLOSEALL], [1])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_FDOPEN], [1])
diff --git a/modules/stdio b/modules/stdio
index 4e41ae13e8..29ed8e0bfa 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -124,6 +124,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
 	      -e 's/@''GNULIB_VZSNPRINTF''@/$(GNULIB_VZSNPRINTF)/g' \
 	      -e 's/@''GNULIB_VZSPRINTF''@/$(GNULIB_VZSPRINTF)/g' \
 	      -e 's/@''GNULIB_ZSNPRINTF''@/$(GNULIB_ZSNPRINTF)/g' \
+	      -e 's/@''GNULIB_ZSPRINTF''@/$(GNULIB_ZSPRINTF)/g' \
 	      -e 's/@''GNULIB_MDA_FCLOSEALL''@/$(GNULIB_MDA_FCLOSEALL)/g' \
 	      -e 's/@''GNULIB_MDA_FDOPEN''@/$(GNULIB_MDA_FDOPEN)/g' \
 	      -e 's/@''GNULIB_MDA_FILENO''@/$(GNULIB_MDA_FILENO)/g' \
diff --git a/modules/zsprintf b/modules/zsprintf
new file mode 100644
index 0000000000..7da8687ea4
--- /dev/null
+++ b/modules/zsprintf
@@ -0,0 +1,27 @@
+Description:
+zsprintf() function: print formatted output to a string (without INT_MAX
+limitation)
+
+Files:
+lib/zsprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([zsprintf])
+
+Makefile.am:
+lib_SOURCES += zsprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPL
+
+Maintainer:
+all
-- 
2.34.1

>From 8a31e0648af657347c4ef3b8d823c464eced4b5a Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:16:30 +0200
Subject: [PATCH 08/11] sprintf-posix: Use vzsprintf.

* lib/stdio.in.h (sprintf): Move specification to here.
* lib/sprintf.c: Don't include <stdlib.h>, vasnprintf.h. Include
<stdint.h>.
(sprintf): Implement based on vzsprintf.
* modules/sprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
---
 ChangeLog             |  7 +++++++
 lib/sprintf.c         | 44 ++++++-------------------------------------
 lib/stdio.in.h        |  3 +++
 modules/sprintf-posix |  2 +-
 4 files changed, 17 insertions(+), 39 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 96dc1dff2c..76c8dc4dce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
+	sprintf-posix: Use vzsprintf.
+	* lib/stdio.in.h (sprintf): Move specification to here.
+	* lib/sprintf.c: Don't include <stdlib.h>, vasnprintf.h. Include
+	<stdint.h>.
+	(sprintf): Implement based on vzsprintf.
+	* modules/sprintf-posix (Depends-on): Add vzsprintf. Remove vasnprintf.
+
 	zsprintf: New module.
 	* lib/stdio.in.h (zsprintf): New declaration, based on
 	lib/sprintf.c.
diff --git a/lib/sprintf.c b/lib/sprintf.c
index ba0108d08c..d781b8c7b5 100644
--- a/lib/sprintf.c
+++ b/lib/sprintf.c
@@ -25,56 +25,24 @@
 #include <limits.h>
 #include <stdarg.h>
 #include <stdint.h>
-#include <stdlib.h>
 
-#include "vasnprintf.h"
-
-#ifndef SIZE_MAX
-# define SIZE_MAX ((size_t) -1)
-#endif
-
-/* Print formatted output to string STR.
-   Return string length of formatted string.  On error, return a negative
-   value.  */
 int
 sprintf (char *str, const char *format, ...)
 {
-  char *output;
-  size_t len;
-  size_t lenbuf;
   va_list args;
-
-  /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger
-     than INT_MAX (if that fits into a 'size_t' at all).
-     Also note that glibc's iconv fails with E2BIG when we pass a length that
-     is so large that str + lenbuf wraps around, i.e.
-     (uintptr_t) (str + lenbuf) < (uintptr_t) str.
-     Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1).  */
-  lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
-  if (lenbuf > ~ (uintptr_t) str)
-    lenbuf = ~ (uintptr_t) str;
+  ptrdiff_t ret;
 
   va_start (args, format);
-  output = vasnprintf (str, &lenbuf, format, args);
-  len = lenbuf;
+  ret = vzsprintf (str, format, args);
   va_end (args);
 
-  if (!output)
-    return -1;
-
-  if (output != str)
-    {
-      /* len is near SIZE_MAX.  */
-      free (output);
-      errno = EOVERFLOW;
-      return -1;
-    }
-
-  if (len > INT_MAX)
+#if PTRDIFF_MAX > INT_MAX
+  if (ret > INT_MAX)
     {
       errno = EOVERFLOW;
       return -1;
     }
+#endif
 
-  return len;
+  return ret;
 }
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 17c662f45a..5a70aa20ba 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1521,6 +1521,9 @@ _GL_CXXALIAS_SYS (zsprintf, ptrdiff_t,
    GNULIB_POSIXCHECK is defined.  */
 
 #if @GNULIB_SPRINTF_POSIX@
+/* Prints formatted output to string STR.
+   Returns the string length of the formatted string.  Upon failure,
+   returns a negative value.  */
 # if @REPLACE_SPRINTF@
 #  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
 #   define sprintf rpl_sprintf
diff --git a/modules/sprintf-posix b/modules/sprintf-posix
index 589ad104ce..a1eb6127ad 100644
--- a/modules/sprintf-posix
+++ b/modules/sprintf-posix
@@ -18,7 +18,7 @@ stdio
 nocrash
 printf-safe
 multiarch
-vasnprintf      [test $REPLACE_SPRINTF = 1]
+vzsprintf       [test $REPLACE_SPRINTF = 1]
 isnand-nolibm   [test $REPLACE_SPRINTF = 1]
 isnanl-nolibm   [test $REPLACE_SPRINTF = 1]
 frexp-nolibm    [test $REPLACE_SPRINTF = 1]
-- 
2.34.1

>From cf5774e94a80589b8fd92fd7166dea82c925cfcc Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:17:02 +0200
Subject: [PATCH 09/11] vazsprintf: New module.

* lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
* lib/vazsprintf.c: New file, based on lib/vasprintf.c.
* lib/azsprintf.c: New file, based on lib/asprintf.c.
* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
GNULIB_VAZSPRINTF.
* modules/stdio (Makefile.am): Substitute GNULIB_VAZSPRINTF.
* modules/vazsprintf: New file.
---
 ChangeLog          | 11 +++++++++++
 lib/azsprintf.c    | 34 ++++++++++++++++++++++++++++++++++
 lib/stdio.in.h     | 23 +++++++++++++++++++++++
 lib/vazsprintf.c   | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 m4/stdio_h.m4      |  3 ++-
 modules/stdio      |  1 +
 modules/vazsprintf | 30 ++++++++++++++++++++++++++++++
 7 files changed, 147 insertions(+), 1 deletion(-)
 create mode 100644 lib/azsprintf.c
 create mode 100644 lib/vazsprintf.c
 create mode 100644 modules/vazsprintf

diff --git a/ChangeLog b/ChangeLog
index 76c8dc4dce..b38ebee8a3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2024-06-22  Bruno Haible  <br...@clisp.org>
+
+	vazsprintf: New module.
+	* lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
+	* lib/vazsprintf.c: New file, based on lib/vasprintf.c.
+	* lib/azsprintf.c: New file, based on lib/asprintf.c.
+	* m4/stdio_h.m4 (gl_STDIO_H_REQUIRE_DEFAULTS): Initialize
+	GNULIB_VAZSPRINTF.
+	* modules/stdio (Makefile.am): Substitute GNULIB_VAZSPRINTF.
+	* modules/vazsprintf: New file.
+
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
 	sprintf-posix: Use vzsprintf.
diff --git a/lib/azsprintf.c b/lib/azsprintf.c
new file mode 100644
index 0000000000..9489854cb9
--- /dev/null
+++ b/lib/azsprintf.c
@@ -0,0 +1,34 @@
+/* Formatted output to strings.
+   Copyright (C) 1999-2024 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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdio.h>
+
+#include <stdarg.h>
+
+ptrdiff_t
+azsprintf (char **resultp, const char *format, ...)
+{
+  va_list args;
+  ptrdiff_t result;
+
+  va_start (args, format);
+  result = vazsprintf (resultp, format, args);
+  va_end (args);
+  return result;
+}
diff --git a/lib/stdio.in.h b/lib/stdio.in.h
index 5a70aa20ba..4844ea1ebf 100644
--- a/lib/stdio.in.h
+++ b/lib/stdio.in.h
@@ -1603,6 +1603,29 @@ _GL_WARN_ON_USE (tmpfile, "tmpfile is not usable on mingw - "
 # endif
 #endif
 
+#if @GNULIB_VAZSPRINTF@
+/* Prints formatted output to a string dynamically allocated with malloc().
+   If the memory allocation succeeds, it stores the address of the string in
+   *RESULT and returns the number of resulting bytes, excluding the trailing
+   NUL.  Upon memory allocation error, or some other error, it returns -1
+   with errno set.
+   Failure code EOVERFLOW can only occur when a width > INT_MAX is used.
+   Therefore, if the format string is valid and does not use %ls/%lc
+   directives nor widths, the only possible failure code is ENOMEM.  */
+_GL_FUNCDECL_SYS (azsprintf, ptrdiff_t,
+                  (char **result, const char *format, ...)
+                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 3)
+                  _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (azsprintf, ptrdiff_t,
+                  (char **result, const char *format, ...));
+_GL_FUNCDECL_SYS (vazsprintf, ptrdiff_t,
+                  (char **result, const char *format, va_list args)
+                  _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD (2, 0)
+                  _GL_ARG_NONNULL ((1, 2)));
+_GL_CXXALIAS_SYS (vazsprintf, ptrdiff_t,
+                  (char **result, const char *format, va_list args));
+#endif
+
 #if @GNULIB_VASPRINTF@
 /* Write formatted output to a string dynamically allocated with malloc().
    If the memory allocation succeeds, store the address of the string in
diff --git a/lib/vazsprintf.c b/lib/vazsprintf.c
new file mode 100644
index 0000000000..73002a17d5
--- /dev/null
+++ b/lib/vazsprintf.c
@@ -0,0 +1,46 @@
+/* Formatted output to strings.
+   Copyright (C) 1999-2024 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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <stdio.h>
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "vasnprintf.h"
+
+ptrdiff_t
+vazsprintf (char **resultp, const char *format, va_list args)
+{
+  size_t length;
+  char *result = vasnprintf (NULL, &length, format, args);
+  if (result == NULL)
+    return -1;
+
+  if (length > PTRDIFF_MAX)
+    {
+      free (result);
+      errno = ENOMEM;
+      return -1;
+    }
+
+  *resultp = result;
+  /* Return the number of resulting bytes, excluding the trailing NUL.  */
+  return length;
+}
diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4
index 69d4b88b4b..aa06d77027 100644
--- a/m4/stdio_h.m4
+++ b/m4/stdio_h.m4
@@ -1,5 +1,5 @@
 # stdio_h.m4
-# serial 67
+# serial 68
 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -177,6 +177,7 @@ AC_DEFUN([gl_STDIO_H_REQUIRE_DEFAULTS]
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STDIO_H_SIGPIPE])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_TMPFILE])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VASPRINTF])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VAZSPRINTF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VFSCANF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VSCANF])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_VDPRINTF])
diff --git a/modules/stdio b/modules/stdio
index 29ed8e0bfa..b0cf4ea207 100644
--- a/modules/stdio
+++ b/modules/stdio
@@ -112,6 +112,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H)
 	      -e 's/@''GNULIB_STDIO_H_SIGPIPE''@/$(GNULIB_STDIO_H_SIGPIPE)/g' \
 	      -e 's/@''GNULIB_TMPFILE''@/$(GNULIB_TMPFILE)/g' \
 	      -e 's/@''GNULIB_VASPRINTF''@/$(GNULIB_VASPRINTF)/g' \
+	      -e 's/@''GNULIB_VAZSPRINTF''@/$(GNULIB_VAZSPRINTF)/g' \
 	      -e 's/@''GNULIB_VDPRINTF''@/$(GNULIB_VDPRINTF)/g' \
 	      -e 's/@''GNULIB_VFPRINTF''@/$(GNULIB_VFPRINTF)/g' \
 	      -e 's/@''GNULIB_VFPRINTF_POSIX''@/$(GNULIB_VFPRINTF_POSIX)/g' \
diff --git a/modules/vazsprintf b/modules/vazsprintf
new file mode 100644
index 0000000000..787825aa71
--- /dev/null
+++ b/modules/vazsprintf
@@ -0,0 +1,30 @@
+Description:
+vsprintf (without INT_MAX limitation) with automatic memory allocation
+
+Files:
+lib/vazsprintf.c
+lib/azsprintf.c
+
+Depends-on:
+stdio
+vasnprintf
+errno
+stdint
+
+configure.ac:
+gl_STDIO_MODULE_INDICATOR([vazsprintf])
+m4_ifdef([AM_XGETTEXT_OPTION],
+  [AM_][XGETTEXT_OPTION([--flag=azsprintf:2:c-format])
+   AM_][XGETTEXT_OPTION([--flag=vazsprintf:2:c-format])])
+
+Makefile.am:
+lib_SOURCES += vazsprintf.c azsprintf.c
+
+Include:
+<stdio.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.34.1

>From 134cfb88c06b0a427f3b4c60acb664c9cc5ec2d9 Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:17:10 +0200
Subject: [PATCH 10/11] vasprintf: Make return convention consistent with other
 modules.

* lib/vasprintf.c: Include <stdint.h>.
(vasprintf): If the length is > PTRDIFF_MAX, fail with ENOMEM, not
EOVERFLOW.
* modules/vasprintf (Depends-on): Add stdint.
---
 ChangeLog         |  6 ++++++
 lib/vasprintf.c   | 12 +++++++++++-
 modules/vasprintf |  1 +
 3 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/ChangeLog b/ChangeLog
index b38ebee8a3..7c720ba885 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
+	vasprintf: Make return convention consistent with other modules.
+	* lib/vasprintf.c: Include <stdint.h>.
+	(vasprintf): If the length is > PTRDIFF_MAX, fail with ENOMEM, not
+	EOVERFLOW.
+	* modules/vasprintf (Depends-on): Add stdint.
+
 	vazsprintf: New module.
 	* lib/stdio.in.h (azsprintf, vazsprintf): New declarations.
 	* lib/vazsprintf.c: New file, based on lib/vasprintf.c.
diff --git a/lib/vasprintf.c b/lib/vasprintf.c
index e52aaca586..757d1c740a 100644
--- a/lib/vasprintf.c
+++ b/lib/vasprintf.c
@@ -25,6 +25,7 @@
 
 #include <errno.h>
 #include <limits.h>
+#include <stdint.h>
 #include <stdlib.h>
 
 #include "vasnprintf.h"
@@ -37,12 +38,21 @@ vasprintf (char **resultp, const char *format, va_list args)
   if (result == NULL)
     return -1;
 
+#if PTRDIFF_MAX > INT_MAX
   if (length > INT_MAX)
     {
       free (result);
-      errno = EOVERFLOW;
+      errno = (length > PTRDIFF_MAX ? ENOMEM : EOVERFLOW);
       return -1;
     }
+#else
+  if (length > PTRDIFF_MAX)
+    {
+      free (result);
+      errno = ENOMEM;
+      return -1;
+    }
+#endif
 
   *resultp = result;
   /* Return the number of resulting bytes, excluding the trailing NUL.  */
diff --git a/modules/vasprintf b/modules/vasprintf
index 91d082bd27..46bfcc51ba 100644
--- a/modules/vasprintf
+++ b/modules/vasprintf
@@ -11,6 +11,7 @@ stdio
 extensions
 vasnprintf      [test $HAVE_VASPRINTF = 0 || test $REPLACE_VASPRINTF = 1]
 errno           [test $HAVE_VASPRINTF = 0 || test $REPLACE_VASPRINTF = 1]
+stdint          [test $HAVE_VASPRINTF = 0 || test $REPLACE_VASPRINTF = 1]
 
 configure.ac:
 gl_FUNC_VASPRINTF
-- 
2.34.1

>From 53549b9b9198f1309f9559cf377e344cf5ea784c Mon Sep 17 00:00:00 2001
From: Bruno Haible <br...@clisp.org>
Date: Sat, 22 Jun 2024 12:17:51 +0200
Subject: [PATCH 11/11] xvasprintf: Guarantee a non-NULL result.

* lib/xvasprintf.h: Clarify the programmer's responsibilities.
(xasprintf, xvasprintf): Declare as returning non-NULL.
* lib/xvasprintf.c: Include <stdlib.h>.
(xstrcat): Allow results longer than INT_MAX characters. Upon size
overflow, invoke xalloc_die.
(xvasprintf): Call vazsprintf instead of vasprintf. When some other
error occurs, emit an error message and abort.
* m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
from gl_FUNC_STRERRORNAME_NP.
(gl_FUNC_STRERRORNAME_NP): Invoke it.
(gl_OPTIONAL_STRERRORNAME_NP): New macro.
* m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
* modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
(Depends-on): Add extensions, vazsprintf. Remove vasprintf.
* NEWS: Mention the change.
---
 ChangeLog             | 19 ++++++++++++++++++
 NEWS                  |  4 ++++
 lib/xvasprintf.c      | 46 ++++++++++++++++++++++++++++++++-----------
 lib/xvasprintf.h      | 25 +++++++++++++++--------
 m4/strerrorname_np.m4 | 33 ++++++++++++++++++++++++++-----
 m4/xvasprintf.m4      |  6 ++++--
 modules/xvasprintf    |  4 +++-
 7 files changed, 110 insertions(+), 27 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7c720ba885..ef21dcc222 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2024-06-22  Bruno Haible  <br...@clisp.org>
+
+	xvasprintf: Guarantee a non-NULL result.
+	* lib/xvasprintf.h: Clarify the programmer's responsibilities.
+	(xasprintf, xvasprintf): Declare as returning non-NULL.
+	* lib/xvasprintf.c: Include <stdlib.h>.
+	(xstrcat): Allow results longer than INT_MAX characters. Upon size
+	overflow, invoke xalloc_die.
+	(xvasprintf): Call vazsprintf instead of vasprintf. When some other
+	error occurs, emit an error message and abort.
+	* m4/strerrorname_np.m4 (gl_CHECK_STRERRORNAME_NP): New macro, extracted
+	from gl_FUNC_STRERRORNAME_NP.
+	(gl_FUNC_STRERRORNAME_NP): Invoke it.
+	(gl_OPTIONAL_STRERRORNAME_NP): New macro.
+	* m4/xvasprintf.m4 (gl_XVASPRINTF): Invoke gl_OPTIONAL_STRERRORNAME_NP.
+	* modules/xvasprintf (Files): Add m4/strerrorname_np.m4.
+	(Depends-on): Add extensions, vazsprintf. Remove vasprintf.
+	* NEWS: Mention the change.
+
 2024-06-22  Bruno Haible  <br...@clisp.org>
 
 	vasprintf: Make return convention consistent with other modules.
diff --git a/NEWS b/NEWS
index 57540c8375..36ffbb64f8 100644
--- a/NEWS
+++ b/NEWS
@@ -74,6 +74,10 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2024-06-22  xvasprintf      It is now the programmer's responsibility to pass
+                            a valid format string without %ls, %lc directives
+                            and that all widths are >= -INT_MAX and <= INT_MAX.
+
 2024-05-16  putenv          This module is renamed to 'putenv-gnu'.
 
 2024-02-21  *printf-posix   These modules no longer support the 'n' directive
diff --git a/lib/xvasprintf.c b/lib/xvasprintf.c
index 6cf6d36a58..97f24eb297 100644
--- a/lib/xvasprintf.c
+++ b/lib/xvasprintf.c
@@ -21,8 +21,9 @@
 
 #include <errno.h>
 #include <limits.h>
-#include <string.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include "xalloc.h"
 
@@ -48,14 +49,10 @@ xstrcat (size_t argcount, va_list args)
     }
   va_end (ap);
 
-  /* Test for overflow in the summing pass above or in (totalsize + 1) below.
-     Also, don't return a string longer than INT_MAX, for consistency with
-     vasprintf().  */
-  if (totalsize == SIZE_MAX || totalsize > INT_MAX)
-    {
-      errno = EOVERFLOW;
-      return NULL;
-    }
+  /* Test for overflow in the summing pass above or in (totalsize + 1)
+     below.  */
+  if (totalsize == SIZE_MAX)
+    xalloc_die ();
 
   /* Allocate and fill the result string.  */
   result = XNMALLOC (totalsize + 1, char);
@@ -99,11 +96,38 @@ xvasprintf (const char *format, va_list args)
       }
   }
 
-  if (vasprintf (&result, format, args) < 0)
+  if (vazsprintf (&result, format, args) < 0)
     {
       if (errno == ENOMEM)
         xalloc_die ();
-      return NULL;
+      else
+        {
+          /* The programmer ought to have ensured that none of the other errors
+             can occur.  */
+          int err = errno;
+          char errbuf[20];
+          const char *errname;
+#if HAVE_WORKING_STRERRORNAME_NP
+          errname = strerrorname_np (err);
+          if (errname == NULL)
+#else
+          if (err == EINVAL)
+            errname = "EINVAL";
+          else if (err == EILSEQ)
+            errname = "EILSEQ";
+          else if (err == EOVERFLOW)
+            errname = "EOVERFLOW";
+          else
+#endif
+            {
+              sprintf (errbuf, "%d", err);
+              errname = errbuf;
+            }
+          fprintf (stderr, "vasprintf failed! format=\"%s\", errno=%s\n",
+                   format, errname);
+          fflush (stderr);
+          abort ();
+        }
     }
 
   return result;
diff --git a/lib/xvasprintf.h b/lib/xvasprintf.h
index 937f97ba4b..fac633c549 100644
--- a/lib/xvasprintf.h
+++ b/lib/xvasprintf.h
@@ -17,7 +17,8 @@
 #ifndef _XVASPRINTF_H
 #define _XVASPRINTF_H
 
-/* This file uses _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_MALLOC.  */
+/* This file uses _GL_ATTRIBUTE_FORMAT, _GL_ATTRIBUTE_MALLOC,
+   _GL_ATTRIBUTE_RETURNS_NONNULL.  */
 #if !_GL_CONFIG_H_INCLUDED
  #error "Please include config.h first."
 #endif
@@ -35,19 +36,27 @@
 extern "C" {
 #endif
 
-/* Write formatted output to a string dynamically allocated with malloc(),
-   and return it.  Upon [ENOMEM] memory allocation error, call xalloc_die.
-   On some other error
-     - [EOVERFLOW] resulting string length is > INT_MAX,
+/* Prints formatted output to a string dynamically allocated with malloc(),
+   and returns it.  Upon [ENOMEM] memory allocation error, it calls xalloc_die.
+
+   It is the responsibility of the programmer to ensure that
+     - the format string is valid,
+     - the format string does not use %ls or %lc directives, and
+     - all widths in the format string and passed as arguments are >= -INT_MAX
+       and <= INT_MAX,
+   so that other errors
      - [EINVAL] invalid format string,
      - [EILSEQ] error during conversion between wide and multibyte characters,
-   return NULL.  */
+     - [EOVERFLOW] some specified width is > INT_MAX,
+   cannot occur.  */
 extern char *xasprintf (const char *format, ...)
        _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
-       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 2));
+       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 2))
+       _GL_ATTRIBUTE_RETURNS_NONNULL;
 extern char *xvasprintf (const char *format, va_list args)
        _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE
-       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 0));
+       _GL_ATTRIBUTE_FORMAT ((_GL_ATTRIBUTE_SPEC_PRINTF_STANDARD, 1, 0))
+       _GL_ATTRIBUTE_RETURNS_NONNULL;
 
 #ifdef __cplusplus
 }
diff --git a/m4/strerrorname_np.m4 b/m4/strerrorname_np.m4
index 9725155bae..ac0211715a 100644
--- a/m4/strerrorname_np.m4
+++ b/m4/strerrorname_np.m4
@@ -1,5 +1,5 @@
 # strerrorname_np.m4
-# serial 5
+# serial 6
 dnl Copyright (C) 2020-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -9,6 +9,21 @@ AC_DEFUN([gl_FUNC_STRERRORNAME_NP]
 [
   AC_REQUIRE([gl_STRING_H_DEFAULTS])
 
+  AC_REQUIRE([gl_CHECK_STRERRORNAME_NP])
+  if test $ac_cv_func_strerrorname_np = yes; then
+    case "$gl_cv_func_strerrorname_np_works" in
+      *yes) ;;
+      *) REPLACE_STRERRORNAME_NP=1 ;;
+    esac
+  else
+    HAVE_STRERRORNAME_NP=0
+  fi
+])
+
+# Check for a working strerrorname_np function.
+# Sets ac_cv_func_strerrorname_np, gl_cv_func_strerrorname_np_works.
+AC_DEFUN([gl_CHECK_STRERRORNAME_NP],
+[
   dnl Persuade glibc <string.h> to declare strerrorname_np().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
@@ -54,11 +69,19 @@ AC_DEFUN([gl_FUNC_STRERRORNAME_NP]
           esac
          ])
       ])
+  fi
+])
+
+# Prerequisite for using strerrorname_np when available.
+AC_DEFUN_ONCE([gl_OPTIONAL_STRERRORNAME_NP],
+[
+  AC_REQUIRE([gl_CHECK_STRERRORNAME_NP])
+  if test $ac_cv_func_strerrorname_np = yes; then
     case "$gl_cv_func_strerrorname_np_works" in
-      *yes) ;;
-      *) REPLACE_STRERRORNAME_NP=1 ;;
+      *yes)
+        AC_DEFINE([HAVE_WORKING_STRERRORNAME_NP], [1],
+          [Define to 1 if the function strerrorname_np exists and works.])
+        ;;
     esac
-  else
-    HAVE_STRERRORNAME_NP=0
   fi
 ])
diff --git a/m4/xvasprintf.m4 b/m4/xvasprintf.m4
index f492e990cb..a3c15966d9 100644
--- a/m4/xvasprintf.m4
+++ b/m4/xvasprintf.m4
@@ -1,9 +1,11 @@
 # xvasprintf.m4
-# serial 2
+# serial 3
 dnl Copyright (C) 2006, 2009-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
 dnl Prerequisites of lib/xvasprintf.c.
-AC_DEFUN([gl_XVASPRINTF], [:])
+AC_DEFUN([gl_XVASPRINTF], [
+  gl_OPTIONAL_STRERRORNAME_NP
+])
diff --git a/modules/xvasprintf b/modules/xvasprintf
index b322890876..bb537ce3ee 100644
--- a/modules/xvasprintf
+++ b/modules/xvasprintf
@@ -7,10 +7,12 @@ lib/xvasprintf.c
 lib/xasprintf.c
 lib/xalloc.h
 m4/xvasprintf.m4
+m4/strerrorname_np.m4
 
 Depends-on:
+extensions
 stdio
-vasprintf
+vazsprintf
 xalloc
 xalloc-die
 extern-inline
-- 
2.34.1

Reply via email to