]> Savannah Git Hosting - gnulib.git/commitdiff
vasnwprintf: New module.
authorBruno Haible <bruno@clisp.org>
Fri, 17 Mar 2023 11:25:37 +0000 (12:25 +0100)
committerBruno Haible <bruno@clisp.org>
Fri, 17 Mar 2023 11:26:29 +0000 (12:26 +0100)
* lib/vasnprintf.c: Enable more code for WIDE_CHAR_VERSION, because
snwprintf()/_snwprintf() (Windows) and swprintf() (Unix) don't return
the needed buffer size, like snprintf does.
* lib/wprintf-parse.h: New file, based on lib/printf-parse.h and
gettext/gettext-runtime/intl/wprintf-parse.h.
* lib/wprintf-parse.c: New file, based on
gettext/gettext-runtime/intl/printf.c.
* lib/vasnwprintf.h: New file, based on lib/vasnprintf.h and
gettext/gettext-runtime/intl/vasnwprintf.h.
* lib/vasnwprintf.c: New file.
* lib/asnwprintf.c: New file, based on lib/asnprintf.c.
* m4/vasnprintf.m4 (gl_FUNC_VASNWPRINTF): New macro.
(gl_PREREQ_VASNXPRINTF): New macro, extracted from gl_PREREQ_VASNPRINTF.
(gl_PREREQ_VASNPRINTF): Invoke it. Don't test for wcsnlen and mbrtowc.
(gl_PREREQ_VASNWPRINTF): New macro.
* modules/vasnwprintf: New file, based on modules/vasnprintf.

ChangeLog
lib/asnwprintf.c [new file with mode: 0644]
lib/vasnprintf.c
lib/vasnwprintf.c [new file with mode: 0644]
lib/vasnwprintf.h [new file with mode: 0644]
lib/wprintf-parse.c [new file with mode: 0644]
lib/wprintf-parse.h [new file with mode: 0644]
m4/vasnprintf.m4
modules/vasnwprintf [new file with mode: 0644]

index 40f92591133833413e29f2604d2bd547558eb762..d1e72224414a8f9b3bead15216d85824eba3b18e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2023-03-17  Bruno Haible  <bruno@clisp.org>
+
+       vasnwprintf: New module.
+       * lib/vasnprintf.c: Enable more code for WIDE_CHAR_VERSION, because
+       snwprintf()/_snwprintf() (Windows) and swprintf() (Unix) don't return
+       the needed buffer size, like snprintf does.
+       * lib/wprintf-parse.h: New file, based on lib/printf-parse.h and
+       gettext/gettext-runtime/intl/wprintf-parse.h.
+       * lib/wprintf-parse.c: New file, based on
+       gettext/gettext-runtime/intl/printf.c.
+       * lib/vasnwprintf.h: New file, based on lib/vasnprintf.h and
+       gettext/gettext-runtime/intl/vasnwprintf.h.
+       * lib/vasnwprintf.c: New file.
+       * lib/asnwprintf.c: New file, based on lib/asnprintf.c.
+       * m4/vasnprintf.m4 (gl_FUNC_VASNWPRINTF): New macro.
+       (gl_PREREQ_VASNXPRINTF): New macro, extracted from gl_PREREQ_VASNPRINTF.
+       (gl_PREREQ_VASNPRINTF): Invoke it. Don't test for wcsnlen and mbrtowc.
+       (gl_PREREQ_VASNWPRINTF): New macro.
+       * modules/vasnwprintf: New file, based on modules/vasnprintf.
+
 2023-03-16  Bruno Haible  <bruno@clisp.org>
 
        strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant.
diff --git a/lib/asnwprintf.c b/lib/asnwprintf.c
new file mode 100644 (file)
index 0000000..a252426
--- /dev/null
@@ -0,0 +1,34 @@
+/* Formatted output to strings.
+   Copyright (C) 1999-2023 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 "vasnwprintf.h"
+
+#include <stdarg.h>
+
+wchar_t *
+asnwprintf (wchar_t *resultbuf, size_t *lengthp, const wchar_t *format, ...)
+{
+  va_list args;
+  wchar_t *result;
+
+  va_start (args, format);
+  result = vasnwprintf (resultbuf, lengthp, format, args);
+  va_end (args);
+  return result;
+}
index 72b8cdbfa6b9742aa4a2886eddf1f2ca60906b52..4354fbe67ce2c1793b68980bea08079ec38c9380 100644 (file)
@@ -241,7 +241,7 @@ local_strnlen (const char *string, size_t maxlen)
 # endif
 #endif
 
-#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
+#if (((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
 # if HAVE_WCSLEN
 #  define local_wcslen wcslen
 # else
@@ -264,7 +264,7 @@ local_wcslen (const wchar_t *s)
 # endif
 #endif
 
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
+#if (!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
 # if HAVE_WCSNLEN
 #  define local_wcsnlen wcsnlen
 # else
@@ -1604,7 +1604,7 @@ is_borderline (const char *digits, size_t precision)
 
 #endif
 
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
 
 /* Use a different function name, to make it possible that the 'wchar_t'
    parametrization and the 'char' parametrization get compiled in the same
@@ -2394,7 +2394,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   }
               }
 #endif
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T
+#if (!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T
             else if (dp->conversion == 's'
 # if WIDE_CHAR_VERSION
                      && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -4723,10 +4723,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 int has_width;
 #endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 size_t width;
 #endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
                 int has_precision;
                 size_t precision;
 #endif
@@ -4755,7 +4755,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 has_width = 0;
 #endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
                 width = 0;
                 if (dp->width_start != dp->width_end)
                   {
@@ -4789,7 +4789,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                   }
 #endif
 
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
                 has_precision = 0;
                 precision = 6;
                 if (dp->precision_start != dp->precision_end)
@@ -4988,47 +4988,63 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
 #endif
                   *fbp = dp->conversion;
 #if USE_SNPRINTF
-# if ((HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99)            \
+                /* Decide whether to pass %n in the format string
+                   to SNPRINTF.  */
+# if ((!WIDE_CHAR_VERSION                                                   \
+       && (HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99))       \
       || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3))       \
           && !defined __UCLIBC__)                                           \
       || (defined __APPLE__ && defined __MACH__)                            \
       || defined __ANDROID__                                                \
       || (defined _WIN32 && ! defined __CYGWIN__))
-                /* On systems where we know that snprintf's return value
-                   conforms to ISO C 99 (HAVE_SNPRINTF_RETVAL_C99) and that
-                   snprintf always produces NUL-terminated strings
-                   (HAVE_SNPRINTF_TRUNCATION_C99), it is possible to avoid
-                   using %n.  And it is desirable to do so, because more and
-                   more platforms no longer support %n, for "security reasons".
-                   In particular, the following platforms:
+                /* We can avoid passing %n and instead rely on SNPRINTF's
+                   return value if
+                     - !WIDE_CHAR_VERSION, because if WIDE_CHAR_VERSION,
+                       snwprintf()/_snwprintf() (Windows) and swprintf() (Unix)
+                       don't return the needed buffer size, and
+                     - we're compiling for a system where we know
+                       - that snprintf's return value conforms to ISO C 99
+                         (HAVE_SNPRINTF_RETVAL_C99) and
+                       - that snprintf always produces NUL-terminated strings
+                         (HAVE_SNPRINTF_TRUNCATION_C99).
+                   And it is desirable to do so, because more and more platforms
+                   no longer support %n, for "security reasons".  */
+                /* On specific platforms, listed below, we *must* avoid %n.
+                   In the case
+                     !WIDE_CHAR_VERSION && HAVE_SNPRINTF_RETVAL_C99 && !USE_MSVC__SNPRINTF
+                   we can rely on the return value of snprintf instead.  Whereas
+                   in the opposite case
+                     WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
+                   we need to make room based on an estimation, computed by
+                   MAX_ROOM_NEEDED.  */
+                /* The following platforms forbid %n:
                      - On glibc2 systems from 2004-10-18 or newer, the use of
                        %n in format strings in writable memory may crash the
                        program (if compiled with _FORTIFY_SOURCE=2).
-                     - On Mac OS X 10.13 or newer, the use of %n in format
+                     - On macOS 10.13 or newer, the use of %n in format
                        strings in writable memory by default crashes the
                        program.
                      - On Android, starting on 2018-03-07, the use of %n in
                        format strings produces a fatal error (see
                        <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>).
-                   On these platforms, HAVE_SNPRINTF_RETVAL_C99 and
-                   HAVE_SNPRINTF_TRUNCATION_C99 are 1. We have listed them
-                   explicitly in the condition above, in case of cross-
-                   compilation (just to be sure).  */
-                /* On native Windows systems (such as mingw), we can avoid using
-                   %n because:
+                     - On native Windows systems (such as mingw) where the OS is
+                       Windows Vista, the use of %n in format strings by default
+                       crashes the program. See
+                         <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
+                         <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
+                   On the first three of these platforms, if !WIDE_CHAR_VERSION,
+                   it is not a big deal to avoid %n, because on these platforms,
+                   HAVE_SNPRINTF_RETVAL_C99 and HAVE_SNPRINTF_TRUNCATION_C99 are
+                   1.
+                   On native Windows, if !WIDE_CHAR_VERSION, it's not a big deal
+                   either because:
                      - Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
                        snprintf does not write more than the specified number
                        of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes
                        '4', '5', '6' into buf, not '4', '5', '\0'.)
                      - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
                        allows us to recognize the case of an insufficient
-                       buffer size: it returns -1 in this case.
-                   On native Windows systems (such as mingw) where the OS is
-                   Windows Vista, the use of %n in format strings by default
-                   crashes the program. See
-                     <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
-                     <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
-                   So we should avoid %n in this situation.  */
+                       buffer size: it returns -1 in this case.  */
                 fbp[1] = '\0';
 # else           /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
                 fbp[1] = '%';
@@ -5271,12 +5287,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
                             /* Look at the snprintf() return value.  */
                             if (retcount < 0)
                               {
-# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
+# if WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
                                 /* HP-UX 10.20 snprintf() is doubly deficient:
                                    It doesn't understand the '%n' directive,
                                    *and* it returns -1 (rather than the length
                                    that would have been required) when the
                                    buffer is too small.
+                                   Likewise, in case of WIDE_CHAR_VERSION, the
+                                   functions snwprintf()/_snwprintf() (Windows)
+                                   or swprintf() (Unix).
                                    But a failure at this point can also come
                                    from other reasons than a too small buffer,
                                    such as an invalid wide string argument to
@@ -5697,7 +5716,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
     errno = ENOMEM;
     goto fail_with_errno;
 
-#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T)
+#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T)
   fail_with_EILSEQ:
     errno = EILSEQ;
     goto fail_with_errno;
diff --git a/lib/vasnwprintf.c b/lib/vasnwprintf.c
new file mode 100644 (file)
index 0000000..db958e0
--- /dev/null
@@ -0,0 +1,18 @@
+/* vswprintf with automatic memory allocation.
+   Copyright (C) 2003-2023 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/>.  */
+
+#define WIDE_CHAR_VERSION 1
+#include "vasnprintf.c"
diff --git a/lib/vasnwprintf.h b/lib/vasnwprintf.h
new file mode 100644 (file)
index 0000000..783eaf8
--- /dev/null
@@ -0,0 +1,63 @@
+/* vswprintf with automatic memory allocation.
+   Copyright (C) 2002-2023 Free Software Foundation, Inc.
+
+   This program 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 program 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/>.  */
+
+#ifndef _VASNWPRINTF_H
+#define _VASNWPRINTF_H
+
+/* Get va_list.  */
+#include <stdarg.h>
+
+/* Get wchar_t, size_t.  */
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Write formatted output to a string dynamically allocated with malloc().
+   You can pass a preallocated buffer for the result in RESULTBUF and its
+   size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
+   If successful, return the address of the string (this may be = RESULTBUF
+   if no dynamic memory allocation was necessary) and set *LENGTHP to the
+   number of resulting bytes, excluding the trailing NUL.  Upon error, set
+   errno and return NULL.
+
+   When dynamic memory allocation occurs, the preallocated buffer is left
+   alone (with possibly modified contents).  This makes it possible to use
+   a statically allocated or stack-allocated buffer, like this:
+
+          wchar_t buf[100];
+          size_t len = sizeof (buf) / sizeof (wchar_t);
+          wchar_t *output = vasnwprintf (buf, &len, format, args);
+          if (output == NULL)
+            ... error handling ...;
+          else
+            {
+              ... use the output string ...;
+              if (output != buf)
+                free (output);
+            }
+  */
+extern wchar_t * asnwprintf (wchar_t *resultbuf, size_t *lengthp,
+                             const wchar_t *format, ...);
+extern wchar_t * vasnwprintf (wchar_t *resultbuf, size_t *lengthp,
+                              const wchar_t *format, va_list args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VASNWPRINTF_H */
diff --git a/lib/wprintf-parse.c b/lib/wprintf-parse.c
new file mode 100644 (file)
index 0000000..f7b72c9
--- /dev/null
@@ -0,0 +1,31 @@
+/* Formatted output to strings.
+   Copyright (C) 2003-2023 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/>.  */
+
+/* This file can be parametrized with the following macros:
+     STATIC             Set to 'static' to declare the function static.  */
+
+#ifndef STATIC
+# include <config.h>
+#endif
+
+/* Specification.  */
+#include "wprintf-parse.h"
+
+#define PRINTF_PARSE wprintf_parse
+#define CHAR_T wchar_t
+#define DIRECTIVE wchar_t_directive
+#define DIRECTIVES wchar_t_directives
+#include "printf-parse.c"
diff --git a/lib/wprintf-parse.h b/lib/wprintf-parse.h
new file mode 100644 (file)
index 0000000..05799b8
--- /dev/null
@@ -0,0 +1,86 @@
+/* Parse wprintf format string.
+   Copyright (C) 1999-2023 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/>.  */
+
+/* This file can be parametrized with the following macros:
+     STATIC             Set to 'static' to declare the function static.  */
+#ifndef _WPRINTF_PARSE_H
+#define _WPRINTF_PARSE_H
+
+#if HAVE_FEATURES_H
+# include <features.h> /* for __GLIBC__, __UCLIBC__ */
+#endif
+
+#include "printf-args.h"
+
+
+/* Flags */
+#define FLAG_GROUP       1      /* ' flag */
+#define FLAG_LEFT        2      /* - flag */
+#define FLAG_SHOWSIGN    4      /* + flag */
+#define FLAG_SPACE       8      /* space flag */
+#define FLAG_ALT        16      /* # flag */
+#define FLAG_ZERO       32
+#if __GLIBC__ >= 2 && !defined __UCLIBC__
+# define FLAG_LOCALIZED 64      /* I flag, uses localized digits */
+#endif
+
+/* arg_index value indicating that no argument is consumed.  */
+#define ARG_NONE        (~(size_t)0)
+
+/* Number of directly allocated directives (no malloc() needed).  */
+#define N_DIRECT_ALLOC_DIRECTIVES 7
+
+/* A parsed directive.  */
+typedef struct
+{
+  const wchar_t* dir_start;
+  const wchar_t* dir_end;
+  int flags;
+  const wchar_t* width_start;
+  const wchar_t* width_end;
+  size_t width_arg_index;
+  const wchar_t* precision_start;
+  const wchar_t* precision_end;
+  size_t precision_arg_index;
+  wchar_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
+  size_t arg_index;
+}
+wchar_t_directive;
+
+/* A parsed format string.  */
+typedef struct
+{
+  size_t count;
+  wchar_t_directive *dir;
+  size_t max_width_length;
+  size_t max_precision_length;
+  wchar_t_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES];
+}
+wchar_t_directives;
+
+
+/* Parses the format string.  Fills in the number N of directives, and fills
+   in directives[0], ..., directives[N-1], and sets directives[N].dir_start
+   to the end of the format string.  Also fills in the arg_type fields of the
+   arguments and the needed count of arguments.  */
+#ifdef STATIC
+STATIC
+#else
+extern
+#endif
+int wprintf_parse (const wchar_t *format, wchar_t_directives *d, arguments *a);
+
+#endif /* _WPRINTF_PARSE_H */
index fda90c402b4565f0b927162971e8fbec191c4766..cf451f9b030e3941b31f5c6397a36c647d30bb56 100644 (file)
@@ -1,4 +1,4 @@
-# vasnprintf.m4 serial 39
+# vasnprintf.m4 serial 40
 dnl Copyright (C) 2002-2004, 2006-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -29,6 +29,15 @@ AC_DEFUN([gl_REPLACE_VASNPRINTF],
   gl_PREREQ_ASNPRINTF
 ])
 
+AC_DEFUN([gl_FUNC_VASNWPRINTF],
+[
+  AC_LIBOBJ([printf-args])
+  gl_PREREQ_PRINTF_ARGS
+  gl_PREREQ_PRINTF_PARSE
+  gl_PREREQ_VASNWPRINTF
+  gl_PREREQ_ASNPRINTF
+])
+
 # Prerequisites of lib/printf-args.h, lib/printf-args.c.
 AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
 [
@@ -37,6 +46,7 @@ AC_DEFUN([gl_PREREQ_PRINTF_ARGS],
 ])
 
 # Prerequisites of lib/printf-parse.h, lib/printf-parse.c.
+# Prerequisites of lib/wprintf-parse.h, lib/wprintf-parse.c.
 AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
 [
   AC_REQUIRE([gl_FEATURES_H])
@@ -50,19 +60,13 @@ AC_DEFUN([gl_PREREQ_PRINTF_PARSE],
   AC_REQUIRE([gt_AC_TYPE_INTMAX_T])
 ])
 
-# Prerequisites of lib/vasnprintf.c.
+# Prerequisites of lib/vasnprintf.c if !WIDE_CHAR_VERSION.
 AC_DEFUN_ONCE([gl_PREREQ_VASNPRINTF],
 [
-  AC_REQUIRE([AC_FUNC_ALLOCA])
-  AC_REQUIRE([gt_TYPE_WCHAR_T])
-  AC_REQUIRE([gt_TYPE_WINT_T])
-  AC_CHECK_FUNCS([snprintf strnlen wcslen wcsnlen mbrtowc wcrtomb])
+  AC_CHECK_FUNCS([snprintf strnlen wcrtomb])
   dnl Use the _snprintf function only if it is declared (because on NetBSD it
   dnl is defined as a weak alias of snprintf; we prefer to use the latter).
   AC_CHECK_DECLS([_snprintf], , , [[#include <stdio.h>]])
-  dnl Knowing DBL_EXPBIT0_WORD and DBL_EXPBIT0_BIT enables an optimization
-  dnl in the code for NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE.
-  AC_REQUIRE([gl_DOUBLE_EXPONENT_LOCATION])
   dnl We can avoid a lot of code by assuming that snprintf's return value
   dnl conforms to ISO C99. So check that.
   AC_REQUIRE([gl_SNPRINTF_RETVAL_C99])
@@ -84,6 +88,27 @@ AC_DEFUN_ONCE([gl_PREREQ_VASNPRINTF],
          terminated.])
       ;;
   esac
+  gl_PREREQ_VASNXPRINTF
+])
+
+# Prerequisites of lib/vasnwprintf.c.
+AC_DEFUN_ONCE([gl_PREREQ_VASNWPRINTF],
+[
+  AC_CHECK_FUNCS([wcsnlen mbrtowc])
+  AC_CHECK_DECLS([_snwprintf], , , [[#include <stdio.h>]])
+  gl_PREREQ_VASNXPRINTF
+])
+
+# Common prerequisites of lib/vasnprintf.c and lib/vasnwprintf.c.
+AC_DEFUN_ONCE([gl_PREREQ_VASNXPRINTF],
+[
+  AC_REQUIRE([AC_FUNC_ALLOCA])
+  AC_REQUIRE([gt_TYPE_WCHAR_T])
+  AC_REQUIRE([gt_TYPE_WINT_T])
+  AC_CHECK_FUNCS([wcslen])
+  dnl Knowing DBL_EXPBIT0_WORD and DBL_EXPBIT0_BIT enables an optimization
+  dnl in the code for NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE.
+  AC_REQUIRE([gl_DOUBLE_EXPONENT_LOCATION])
 ])
 
 # Extra prerequisites of lib/vasnprintf.c for supporting 'long double'
@@ -293,6 +318,7 @@ AC_DEFUN([gl_PREREQ_VASNPRINTF_WITH_EXTRAS],
 ])
 
 # Prerequisites of lib/asnprintf.c.
+# Prerequisites of lib/asnwprintf.c.
 AC_DEFUN([gl_PREREQ_ASNPRINTF],
 [
 ])
diff --git a/modules/vasnwprintf b/modules/vasnwprintf
new file mode 100644 (file)
index 0000000..544d714
--- /dev/null
@@ -0,0 +1,53 @@
+Description:
+vswprintf with automatic memory allocation and bounded output size.
+
+Files:
+lib/float+.h
+lib/printf-args.h
+lib/printf-args.c
+lib/wprintf-parse.h
+lib/wprintf-parse.c
+lib/printf-parse.c
+lib/vasnwprintf.h
+lib/vasnwprintf.c
+lib/vasnprintf.c
+lib/asnwprintf.c
+m4/wchar_t.m4
+m4/wint_t.m4
+m4/intmax_t.m4
+m4/stdint_h.m4
+m4/inttypes_h.m4
+m4/vasnprintf.m4
+m4/printf.m4
+m4/math_h.m4
+m4/exponentd.m4
+
+Depends-on:
+stdio
+alloca-opt
+attribute
+float
+free-posix
+stdint
+xsize
+errno
+memchr
+assert-h
+wchar
+
+configure.ac:
+AC_REQUIRE([AC_C_RESTRICT])
+gl_FUNC_VASNWPRINTF
+
+Makefile.am:
+lib_SOURCES += wprintf-parse.c vasnwprintf.c
+lib_SOURCES += asnwprintf.c
+
+Include:
+"vasnwprintf.h"
+
+License:
+LGPLv2+
+
+Maintainer:
+all