>From cc90bee0e183c03c0ad05a14f69e59e20c1a6392 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 17 Mar 2023 12:25:37 +0100 Subject: [PATCH 1/6] 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. --- ChangeLog | 20 +++++++++++ lib/asnwprintf.c | 34 ++++++++++++++++++ lib/vasnprintf.c | 83 ++++++++++++++++++++++++++----------------- lib/vasnwprintf.c | 18 ++++++++++ lib/vasnwprintf.h | 63 +++++++++++++++++++++++++++++++++ lib/wprintf-parse.c | 31 ++++++++++++++++ lib/wprintf-parse.h | 86 +++++++++++++++++++++++++++++++++++++++++++++ m4/vasnprintf.m4 | 44 ++++++++++++++++++----- modules/vasnwprintf | 53 ++++++++++++++++++++++++++++ 9 files changed, 391 insertions(+), 41 deletions(-) create mode 100644 lib/asnwprintf.c create mode 100644 lib/vasnwprintf.c create mode 100644 lib/vasnwprintf.h create mode 100644 lib/wprintf-parse.c create mode 100644 lib/wprintf-parse.h create mode 100644 modules/vasnwprintf diff --git a/ChangeLog b/ChangeLog index 40f9259113..d1e7222441 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2023-03-17 Bruno Haible + + 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 strtol, strtoll, strtoul, strtoull: Make ISO C 23 compliant. diff --git a/lib/asnwprintf.c b/lib/asnwprintf.c new file mode 100644 index 0000000000..a2524263e6 --- /dev/null +++ b/lib/asnwprintf.c @@ -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 . */ + +#include + +/* Specification. */ +#include "vasnwprintf.h" + +#include + +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; +} diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index 72b8cdbfa6..4354fbe67c 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -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 ). - 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 + and + + 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 - and - - 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 index 0000000000..db958e049d --- /dev/null +++ b/lib/vasnwprintf.c @@ -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 . */ + +#define WIDE_CHAR_VERSION 1 +#include "vasnprintf.c" diff --git a/lib/vasnwprintf.h b/lib/vasnwprintf.h new file mode 100644 index 0000000000..783eaf8be9 --- /dev/null +++ b/lib/vasnwprintf.h @@ -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 . */ + +#ifndef _VASNWPRINTF_H +#define _VASNWPRINTF_H + +/* Get va_list. */ +#include + +/* Get wchar_t, size_t. */ +#include + +#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 index 0000000000..f7b72c9ef3 --- /dev/null +++ b/lib/wprintf-parse.c @@ -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 . */ + +/* This file can be parametrized with the following macros: + STATIC Set to 'static' to declare the function static. */ + +#ifndef STATIC +# include +#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 index 0000000000..05799b8f15 --- /dev/null +++ b/lib/wprintf-parse.h @@ -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 . */ + +/* 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 /* 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 */ diff --git a/m4/vasnprintf.m4 b/m4/vasnprintf.m4 index fda90c402b..cf451f9b03 100644 --- a/m4/vasnprintf.m4 +++ b/m4/vasnprintf.m4 @@ -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 ]]) - 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 ]]) + 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 index 0000000000..544d7144a4 --- /dev/null +++ b/modules/vasnwprintf @@ -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 -- 2.34.1