From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: Florian Weimer <fweimer@redhat.com>, libc-alpha@sourceware.org
Subject: Re: [PATCH 05/26] vfprintf: Move argument processing into vfprintf-process-arg.c
Date: Fri, 20 May 2022 10:28:10 -0300 [thread overview]
Message-ID: <6512211a-d03a-6340-9298-d039ef81f821@linaro.org> (raw)
In-Reply-To: <3a9b3ee97eb11de190ffbeb21091c8671201eb75.1647544751.git.fweimer@redhat.com>
On 17/03/2022 16:28, Florian Weimer via Libc-alpha wrote:
> This simplies formatting and helps with debugging. It also allows
> the use of localized COMPILE_WPRINTF preprocessor conditionals.
LGTM, this no an usual way to decompose the function, but I think trying to
make it as an functions will also likely result in way more refactoring.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> stdio-common/vfprintf-internal.c | 501 +--------------------------
> stdio-common/vfprintf-process-arg.c | 515 ++++++++++++++++++++++++++++
> 2 files changed, 517 insertions(+), 499 deletions(-)
> create mode 100644 stdio-common/vfprintf-process-arg.c
>
> diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
> index 59bd76c890..1986c4bdb5 100644
> --- a/stdio-common/vfprintf-internal.c
> +++ b/stdio-common/vfprintf-internal.c
> @@ -656,501 +656,6 @@ static const uint8_t jump_table[] =
> REF (form_binary), /* for 'B', 'b' */ \
> }
>
> -/* Before invoking this macro, process_arg_int etc. macros have to be
> - defined to extract one argument of the appropriate type. */
> -#define process_arg() \
> - /* Start real work. We know about all flags and modifiers and \
> - now process the wanted format specifier. */ \
> - LABEL (form_percent): \
> - /* Write a literal "%". */ \
> - outchar (L_('%')); \
> - break; \
> - \
> - LABEL (form_integer): \
> - /* Signed decimal integer. */ \
> - base = 10; \
> - \
> - if (is_longlong) \
> - { \
> - long long int signed_number = process_arg_long_long_int (); \
> - is_negative = signed_number < 0; \
> - number.longlong = is_negative ? (- signed_number) : signed_number; \
> - \
> - goto LABEL (longlong_number); \
> - } \
> - else \
> - { \
> - long int signed_number; \
> - if (is_long_num) \
> - signed_number = process_arg_long_int (); \
> - else if (is_char) \
> - signed_number = (signed char) process_arg_unsigned_int (); \
> - else if (!is_short) \
> - signed_number = process_arg_int (); \
> - else \
> - signed_number = (short int) process_arg_unsigned_int (); \
> - \
> - is_negative = signed_number < 0; \
> - number.word = is_negative ? (- signed_number) : signed_number; \
> - \
> - goto LABEL (number); \
> - } \
> - /* NOTREACHED */ \
> - \
> - LABEL (form_unsigned): \
> - /* Unsigned decimal integer. */ \
> - base = 10; \
> - goto LABEL (unsigned_number); \
> - /* NOTREACHED */ \
> - \
> - LABEL (form_octal): \
> - /* Unsigned octal integer. */ \
> - base = 8; \
> - goto LABEL (unsigned_number); \
> - /* NOTREACHED */ \
> - \
> - LABEL (form_hexa): \
> - /* Unsigned hexadecimal integer. */ \
> - base = 16; \
> - goto LABEL (unsigned_number); \
> - /* NOTREACHED */ \
> - \
> - LABEL (form_binary): \
> - /* Unsigned binary integer. */ \
> - base = 2; \
> - goto LABEL (unsigned_number); \
> - /* NOTREACHED */ \
> - \
> - LABEL (unsigned_number): /* Unsigned number of base BASE. */ \
> - \
> - /* ISO specifies the `+' and ` ' flags only for signed \
> - conversions. */ \
> - is_negative = 0; \
> - showsign = 0; \
> - space = 0; \
> - \
> - if (is_longlong) \
> - { \
> - number.longlong = process_arg_unsigned_long_long_int (); \
> - \
> - LABEL (longlong_number): \
> - if (prec < 0) \
> - /* Supply a default precision if none was given. */ \
> - prec = 1; \
> - else \
> - /* We have to take care for the '0' flag. If a precision \
> - is given it must be ignored. */ \
> - pad = L_(' '); \
> - \
> - /* If the precision is 0 and the number is 0 nothing has to \
> - be written for the number, except for the 'o' format in \
> - alternate form. */ \
> - if (prec == 0 && number.longlong == 0) \
> - { \
> - string = workend; \
> - if (base == 8 && alt) \
> - *--string = L_('0'); \
> - } \
> - else \
> - { \
> - /* Put the number in WORK. */ \
> - string = _itoa (number.longlong, workend, base, \
> - spec == L_('X')); \
> - if (group && grouping) \
> - string = group_number (work_buffer, string, workend, \
> - grouping, thousands_sep); \
> - if (use_outdigits && base == 10) \
> - string = _i18n_number_rewrite (string, workend, workend); \
> - } \
> - /* Simplify further test for num != 0. */ \
> - number.word = number.longlong != 0; \
> - } \
> - else \
> - { \
> - if (is_long_num) \
> - number.word = process_arg_unsigned_long_int (); \
> - else if (is_char) \
> - number.word = (unsigned char) process_arg_unsigned_int (); \
> - else if (!is_short) \
> - number.word = process_arg_unsigned_int (); \
> - else \
> - number.word = (unsigned short int) process_arg_unsigned_int (); \
> - \
> - LABEL (number): \
> - if (prec < 0) \
> - /* Supply a default precision if none was given. */ \
> - prec = 1; \
> - else \
> - /* We have to take care for the '0' flag. If a precision \
> - is given it must be ignored. */ \
> - pad = L_(' '); \
> - \
> - /* If the precision is 0 and the number is 0 nothing has to \
> - be written for the number, except for the 'o' format in \
> - alternate form. */ \
> - if (prec == 0 && number.word == 0) \
> - { \
> - string = workend; \
> - if (base == 8 && alt) \
> - *--string = L_('0'); \
> - } \
> - else \
> - { \
> - /* Put the number in WORK. */ \
> - string = _itoa_word (number.word, workend, base, \
> - spec == L_('X')); \
> - if (group && grouping) \
> - string = group_number (work_buffer, string, workend, \
> - grouping, thousands_sep); \
> - if (use_outdigits && base == 10) \
> - string = _i18n_number_rewrite (string, workend, workend); \
> - } \
> - } \
> - \
> - if (prec <= workend - string && number.word != 0 && alt && base == 8) \
> - /* Add octal marker. */ \
> - *--string = L_('0'); \
> - \
> - prec = MAX (0, prec - (workend - string)); \
> - \
> - if (!left) \
> - { \
> - width -= workend - string + prec; \
> - \
> - if (number.word != 0 && alt && (base == 16 || base == 2)) \
> - /* Account for 0X, 0x, 0B or 0b hex or binary marker. */ \
> - width -= 2; \
> - \
> - if (is_negative || showsign || space) \
> - --width; \
> - \
> - if (pad == L_(' ')) \
> - { \
> - PAD (L_(' ')); \
> - width = 0; \
> - } \
> - \
> - if (is_negative) \
> - outchar (L_('-')); \
> - else if (showsign) \
> - outchar (L_('+')); \
> - else if (space) \
> - outchar (L_(' ')); \
> - \
> - if (number.word != 0 && alt && (base == 16 || base == 2)) \
> - { \
> - outchar (L_('0')); \
> - outchar (spec); \
> - } \
> - \
> - width += prec; \
> - PAD (L_('0')); \
> - \
> - outstring (string, workend - string); \
> - \
> - break; \
> - } \
> - else \
> - { \
> - if (is_negative) \
> - { \
> - outchar (L_('-')); \
> - --width; \
> - } \
> - else if (showsign) \
> - { \
> - outchar (L_('+')); \
> - --width; \
> - } \
> - else if (space) \
> - { \
> - outchar (L_(' ')); \
> - --width; \
> - } \
> - \
> - if (number.word != 0 && alt && (base == 16 || base == 2)) \
> - { \
> - outchar (L_('0')); \
> - outchar (spec); \
> - width -= 2; \
> - } \
> - \
> - width -= workend - string + prec; \
> - \
> - if (prec > 0) \
> - { \
> - int temp = width; \
> - width = prec; \
> - PAD (L_('0')); \
> - width = temp; \
> - } \
> - \
> - outstring (string, workend - string); \
> - \
> - PAD (L_(' ')); \
> - break; \
> - } \
> - \
> - LABEL (form_pointer): \
> - /* Generic pointer. */ \
> - { \
> - const void *ptr = process_arg_pointer (); \
> - if (ptr != NULL) \
> - { \
> - /* If the pointer is not NULL, write it as a %#x spec. */ \
> - base = 16; \
> - number.word = (unsigned long int) ptr; \
> - is_negative = 0; \
> - alt = 1; \
> - group = 0; \
> - spec = L_('x'); \
> - goto LABEL (number); \
> - } \
> - else \
> - { \
> - /* Write "(nil)" for a nil pointer. */ \
> - string = (CHAR_T *) L_("(nil)"); \
> - /* Make sure the full string "(nil)" is printed. */ \
> - if (prec < 5) \
> - prec = 5; \
> - /* This is a wide string iff compiling wprintf. */ \
> - is_long = sizeof (CHAR_T) > 1; \
> - goto LABEL (print_string); \
> - } \
> - } \
> - /* NOTREACHED */ \
> - \
> - LABEL (form_number): \
> - if ((mode_flags & PRINTF_FORTIFY) != 0) \
> - { \
> - if (! readonly_format) \
> - { \
> - extern int __readonly_area (const void *, size_t) \
> - attribute_hidden; \
> - readonly_format \
> - = __readonly_area (format, ((STR_LEN (format) + 1) \
> - * sizeof (CHAR_T))); \
> - } \
> - if (readonly_format < 0) \
> - __libc_fatal ("*** %n in writable segment detected ***\n"); \
> - } \
> - /* Answer the count of characters written. */ \
> - void *ptrptr = process_arg_pointer (); \
> - if (is_longlong) \
> - *(long long int *) ptrptr = done; \
> - else if (is_long_num) \
> - *(long int *) ptrptr = done; \
> - else if (is_char) \
> - *(char *) ptrptr = done; \
> - else if (!is_short) \
> - *(int *) ptrptr = done; \
> - else \
> - *(short int *) ptrptr = done; \
> - break; \
> - \
> - LABEL (form_strerror): \
> - /* Print description of error ERRNO. */ \
> - if (alt) \
> - string = (CHAR_T *) __get_errname (save_errno); \
> - else \
> - string = (CHAR_T *) __strerror_r (save_errno, (char *) work_buffer, \
> - WORK_BUFFER_SIZE * sizeof (CHAR_T));\
> - if (string == NULL) \
> - { \
> - /* Print as a decimal number. */ \
> - base = 10; \
> - is_negative = save_errno < 0; \
> - number.word = save_errno; \
> - if (is_negative) \
> - number.word = -number.word; \
> - goto LABEL (number); \
> - } \
> - else \
> - { \
> - is_long = 0; /* This is no wide-char string. */ \
> - goto LABEL (print_string); \
> - }
> -
> -#ifdef COMPILE_WPRINTF
> -# define process_string_arg() \
> - LABEL (form_character): \
> - /* Character. */ \
> - if (is_long) \
> - goto LABEL (form_wcharacter); \
> - --width; /* Account for the character itself. */ \
> - if (!left) \
> - PAD (L' '); \
> - outchar (__btowc ((unsigned char) process_arg_int ())); /* Promoted. */ \
> - if (left) \
> - PAD (L' '); \
> - break; \
> - \
> - LABEL (form_wcharacter): \
> - { \
> - /* Wide character. */ \
> - --width; \
> - if (!left) \
> - PAD (L' '); \
> - outchar (process_arg_wchar_t ()); \
> - if (left) \
> - PAD (L' '); \
> - } \
> - break; \
> - \
> - LABEL (form_string): \
> - { \
> - size_t len; \
> - \
> - /* The string argument could in fact be `char *' or `wchar_t *'. \
> - But this should not make a difference here. */ \
> - string = (CHAR_T *) process_arg_wstring (); \
> - \
> - /* Entry point for printing other strings. */ \
> - LABEL (print_string): \
> - \
> - if (string == NULL) \
> - { \
> - /* Write "(null)" if there's space. */ \
> - if (prec == -1 || prec >= (int) array_length (null) - 1) \
> - { \
> - string = (CHAR_T *) null; \
> - len = array_length (null) - 1; \
> - } \
> - else \
> - { \
> - string = (CHAR_T *) L""; \
> - len = 0; \
> - } \
> - } \
> - else if (!is_long && spec != L_('S')) \
> - { \
> - done = outstring_converted_wide_string \
> - (s, (const char *) string, prec, width, left, done); \
> - if (done < 0) \
> - goto all_done; \
> - /* The padding has already been written. */ \
> - break; \
> - } \
> - else \
> - { \
> - if (prec != -1) \
> - /* Search for the end of the string, but don't search past \
> - the length specified by the precision. */ \
> - len = __wcsnlen (string, prec); \
> - else \
> - len = __wcslen (string); \
> - } \
> - \
> - if ((width -= len) < 0) \
> - { \
> - outstring (string, len); \
> - break; \
> - } \
> - \
> - if (!left) \
> - PAD (L' '); \
> - outstring (string, len); \
> - if (left) \
> - PAD (L' '); \
> - } \
> - break;
> -#else
> -# define process_string_arg() \
> - LABEL (form_character): \
> - /* Character. */ \
> - if (is_long) \
> - goto LABEL (form_wcharacter); \
> - --width; /* Account for the character itself. */ \
> - if (!left) \
> - PAD (' '); \
> - outchar ((unsigned char) process_arg_int ()); /* Promoted. */ \
> - if (left) \
> - PAD (' '); \
> - break; \
> - \
> - LABEL (form_wcharacter): \
> - { \
> - /* Wide character. */ \
> - char buf[MB_LEN_MAX]; \
> - mbstate_t mbstate; \
> - size_t len; \
> - \
> - memset (&mbstate, '\0', sizeof (mbstate_t)); \
> - len = __wcrtomb (buf, process_arg_wchar_t (), &mbstate); \
> - if (len == (size_t) -1) \
> - { \
> - /* Something went wrong during the conversion. Bail out. */ \
> - done = -1; \
> - goto all_done; \
> - } \
> - width -= len; \
> - if (!left) \
> - PAD (' '); \
> - outstring (buf, len); \
> - if (left) \
> - PAD (' '); \
> - } \
> - break; \
> - \
> - LABEL (form_string): \
> - { \
> - size_t len; \
> - \
> - /* The string argument could in fact be `char *' or `wchar_t *'. \
> - But this should not make a difference here. */ \
> - string = (char *) process_arg_string (); \
> - \
> - /* Entry point for printing other strings. */ \
> - LABEL (print_string): \
> - \
> - if (string == NULL) \
> - { \
> - /* Write "(null)" if there's space. */ \
> - if (prec == -1 || prec >= (int) sizeof (null) - 1) \
> - { \
> - string = (char *) null; \
> - len = sizeof (null) - 1; \
> - } \
> - else \
> - { \
> - string = (char *) ""; \
> - len = 0; \
> - } \
> - } \
> - else if (!is_long && spec != L_('S')) \
> - { \
> - if (prec != -1) \
> - /* Search for the end of the string, but don't search past \
> - the length (in bytes) specified by the precision. */ \
> - len = __strnlen (string, prec); \
> - else \
> - len = strlen (string); \
> - } \
> - else \
> - { \
> - done = outstring_converted_wide_string \
> - (s, (const wchar_t *) string, prec, width, left, done); \
> - if (done < 0) \
> - goto all_done; \
> - /* The padding has already been written. */ \
> - break; \
> - } \
> - \
> - if ((width -= len) < 0) \
> - { \
> - outstring (string, len); \
> - break; \
> - } \
> - \
> - if (!left) \
> - PAD (' '); \
> - outstring (string, len); \
> - if (left) \
> - PAD (' '); \
> - } \
> - break;
> -#endif
> -
> /* Helper function to provide temporary buffering for unbuffered streams. */
> static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
> unsigned int)
> @@ -1513,8 +1018,7 @@ vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
> #define process_arg_unsigned_long_long_int() va_arg (ap, unsigned long long int)
> #define process_arg_wchar_t() va_arg (ap, wchar_t)
> #define process_arg_wstring() va_arg (ap, const wchar_t *)
> - process_arg ();
> - process_string_arg ();
> +#include "vfprintf-process-arg.c"
> #undef process_arg_int
> #undef process_arg_long_int
> #undef process_arg_long_long_int
> @@ -1923,8 +1427,7 @@ printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
> #define process_arg_unsigned_long_long_int() process_arg_data.pa_u_long_long_int
> #define process_arg_wchar_t() process_arg_data.pa_wchar
> #define process_arg_wstring() process_arg_data.pa_wstring
> - process_arg ();
> - process_string_arg ();
> +#include "vfprintf-process-arg.c"
> #undef process_arg_data
> #undef process_arg_int
> #undef process_arg_long_int
> diff --git a/stdio-common/vfprintf-process-arg.c b/stdio-common/vfprintf-process-arg.c
> new file mode 100644
> index 0000000000..a28afce7de
> --- /dev/null
> +++ b/stdio-common/vfprintf-process-arg.c
> @@ -0,0 +1,515 @@
> +/* Argument-processing fragment for vfprintf.
> + Copyright (C) 1991-2022 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library 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.
> +
> + The GNU C Library 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 the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +/* This file is included twice from vfprintf-internal.c, for standard
> + and GNU-style positional (%N$) arguments. Before that,
> + process_arg_int etc. macros have to be defined to extract one
> + argument of the appropriate type, in addition to the file-specific
> + macros in vfprintf-internal.c. */
> +
> +{
> + /* Start real work. We know about all flags and modifiers and
> + now process the wanted format specifier. */
> +LABEL (form_percent):
> + /* Write a literal "%". */
> + outchar (L_('%'));
> + break;
> +
> +LABEL (form_integer):
> + /* Signed decimal integer. */
> + base = 10;
> +
> + if (is_longlong)
> + {
> + long long int signed_number = process_arg_long_long_int ();
> + is_negative = signed_number < 0;
> + number.longlong = is_negative ? (- signed_number) : signed_number;
> +
> + goto LABEL (longlong_number);
> + }
> + else
> + {
> + long int signed_number;
> + if (is_long_num)
> + signed_number = process_arg_long_int ();
> + else if (is_char)
> + signed_number = (signed char) process_arg_unsigned_int ();
> + else if (!is_short)
> + signed_number = process_arg_int ();
> + else
> + signed_number = (short int) process_arg_unsigned_int ();
> +
> + is_negative = signed_number < 0;
> + number.word = is_negative ? (- signed_number) : signed_number;
> +
> + goto LABEL (number);
> + }
> + /* NOTREACHED */
> +
> +LABEL (form_unsigned):
> + /* Unsigned decimal integer. */
> + base = 10;
> + goto LABEL (unsigned_number);
> + /* NOTREACHED */
> +
> +LABEL (form_octal):
> + /* Unsigned octal integer. */
> + base = 8;
> + goto LABEL (unsigned_number);
> + /* NOTREACHED */
> +
> +LABEL (form_hexa):
> + /* Unsigned hexadecimal integer. */
> + base = 16;
> + goto LABEL (unsigned_number);
> + /* NOTREACHED */
> +
> +LABEL (form_binary):
> + /* Unsigned binary integer. */
> + base = 2;
> + goto LABEL (unsigned_number);
> + /* NOTREACHED */
> +
> +LABEL (unsigned_number): /* Unsigned number of base BASE. */
> +
> + /* ISO specifies the `+' and ` ' flags only for signed
> + conversions. */
> + is_negative = 0;
> + showsign = 0;
> + space = 0;
> +
> + if (is_longlong)
> + {
> + number.longlong = process_arg_unsigned_long_long_int ();
> +
> + LABEL (longlong_number):
> + if (prec < 0)
> + /* Supply a default precision if none was given. */
> + prec = 1;
> + else
> + /* We have to take care for the '0' flag. If a precision
> + is given it must be ignored. */
> + pad = L_(' ');
> +
> + /* If the precision is 0 and the number is 0 nothing has to
> + be written for the number, except for the 'o' format in
> + alternate form. */
> + if (prec == 0 && number.longlong == 0)
> + {
> + string = workend;
> + if (base == 8 && alt)
> + *--string = L_('0');
> + }
> + else
> + {
> + /* Put the number in WORK. */
> + string = _itoa (number.longlong, workend, base,
> + spec == L_('X'));
> + if (group && grouping)
> + string = group_number (work_buffer, string, workend,
> + grouping, thousands_sep);
> + if (use_outdigits && base == 10)
> + string = _i18n_number_rewrite (string, workend, workend);
> + }
> + /* Simplify further test for num != 0. */
> + number.word = number.longlong != 0;
> + }
> + else
> + {
> + if (is_long_num)
> + number.word = process_arg_unsigned_long_int ();
> + else if (is_char)
> + number.word = (unsigned char) process_arg_unsigned_int ();
> + else if (!is_short)
> + number.word = process_arg_unsigned_int ();
> + else
> + number.word = (unsigned short int) process_arg_unsigned_int ();
> +
> + LABEL (number):
> + if (prec < 0)
> + /* Supply a default precision if none was given. */
> + prec = 1;
> + else
> + /* We have to take care for the '0' flag. If a precision
> + is given it must be ignored. */
> + pad = L_(' ');
> +
> + /* If the precision is 0 and the number is 0 nothing has to
> + be written for the number, except for the 'o' format in
> + alternate form. */
> + if (prec == 0 && number.word == 0)
> + {
> + string = workend;
> + if (base == 8 && alt)
> + *--string = L_('0');
> + }
> + else
> + {
> + /* Put the number in WORK. */
> + string = _itoa_word (number.word, workend, base,
> + spec == L_('X'));
> + if (group && grouping)
> + string = group_number (work_buffer, string, workend,
> + grouping, thousands_sep);
> + if (use_outdigits && base == 10)
> + string = _i18n_number_rewrite (string, workend, workend);
> + }
> + }
> +
> + if (prec <= workend - string && number.word != 0 && alt && base == 8)
> + /* Add octal marker. */
> + *--string = L_('0');
> +
> + prec = MAX (0, prec - (workend - string));
> +
> + if (!left)
> + {
> + width -= workend - string + prec;
> +
> + if (number.word != 0 && alt && (base == 16 || base == 2))
> + /* Account for 0X, 0x, 0B or 0b hex or binary marker. */
> + width -= 2;
> +
> + if (is_negative || showsign || space)
> + --width;
> +
> + if (pad == L_(' '))
> + {
> + PAD (L_(' '));
> + width = 0;
> + }
> +
> + if (is_negative)
> + outchar (L_('-'));
> + else if (showsign)
> + outchar (L_('+'));
> + else if (space)
> + outchar (L_(' '));
> +
> + if (number.word != 0 && alt && (base == 16 || base == 2))
> + {
> + outchar (L_('0'));
> + outchar (spec);
> + }
> +
> + width += prec;
> + PAD (L_('0'));
> +
> + outstring (string, workend - string);
> +
> + break;
> + }
> + else
> + {
> + if (is_negative)
> + {
> + outchar (L_('-'));
> + --width;
> + }
> + else if (showsign)
> + {
> + outchar (L_('+'));
> + --width;
> + }
> + else if (space)
> + {
> + outchar (L_(' '));
> + --width;
> + }
> +
> + if (number.word != 0 && alt && (base == 16 || base == 2))
> + {
> + outchar (L_('0'));
> + outchar (spec);
> + width -= 2;
> + }
> +
> + width -= workend - string + prec;
> +
> + if (prec > 0)
> + {
> + int temp = width;
> + width = prec;
> + PAD (L_('0'));
> + width = temp;
> + }
> +
> + outstring (string, workend - string);
> +
> + PAD (L_(' '));
> + break;
> + }
> +
> +LABEL (form_pointer):
> + /* Generic pointer. */
> + {
> + const void *ptr = process_arg_pointer ();
> + if (ptr != NULL)
> + {
> + /* If the pointer is not NULL, write it as a %#x spec. */
> + base = 16;
> + number.word = (unsigned long int) ptr;
> + is_negative = 0;
> + alt = 1;
> + group = 0;
> + spec = L_('x');
> + goto LABEL (number);
> + }
> + else
> + {
> + /* Write "(nil)" for a nil pointer. */
> + string = (CHAR_T *) L_("(nil)");
> + /* Make sure the full string "(nil)" is printed. */
> + if (prec < 5)
> + prec = 5;
> + /* This is a wide string iff compiling wprintf. */
> + is_long = sizeof (CHAR_T) > 1;
> + goto LABEL (print_string);
> + }
> + }
> + /* NOTREACHED */
> +
> +LABEL (form_number):
> + if ((mode_flags & PRINTF_FORTIFY) != 0)
> + {
> + if (! readonly_format)
> + {
> + extern int __readonly_area (const void *, size_t)
> + attribute_hidden;
> + readonly_format
> + = __readonly_area (format, ((STR_LEN (format) + 1)
> + * sizeof (CHAR_T)));
> + }
> + if (readonly_format < 0)
> + __libc_fatal ("*** %n in writable segment detected ***\n");
> + }
> + /* Answer the count of characters written. */
> + void *ptrptr = process_arg_pointer ();
> + if (is_longlong)
> + *(long long int *) ptrptr = done;
> + else if (is_long_num)
> + *(long int *) ptrptr = done;
> + else if (is_char)
> + *(char *) ptrptr = done;
> + else if (!is_short)
> + *(int *) ptrptr = done;
> + else
> + *(short int *) ptrptr = done;
> + break;
> +
> +LABEL (form_strerror):
> + /* Print description of error ERRNO. */
> + if (alt)
> + string = (CHAR_T *) __get_errname (save_errno);
> + else
> + string = (CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,
> + WORK_BUFFER_SIZE * sizeof (CHAR_T));
> + if (string == NULL)
> + {
> + /* Print as a decimal number. */
> + base = 10;
> + is_negative = save_errno < 0;
> + number.word = save_errno;
> + if (is_negative)
> + number.word = -number.word;
> + goto LABEL (number);
> + }
> + else
> + {
> + is_long = 0; /* This is no wide-char string. */
> + goto LABEL (print_string);
> + }
> +
> +#ifdef COMPILE_WPRINTF
> +LABEL (form_character):
> + /* Character. */
> + if (is_long)
> + goto LABEL (form_wcharacter);
> + --width; /* Account for the character itself. */
> + if (!left)
> + PAD (L' ');
> + outchar (__btowc ((unsigned char) process_arg_int ())); /* Promoted. */
> + if (left)
> + PAD (L' ');
> + break;
> +
> +LABEL (form_wcharacter):
> + {
> + /* Wide character. */
> + --width;
> + if (!left)
> + PAD (L' ');
> + outchar (process_arg_wchar_t ());
> + if (left)
> + PAD (L' ');
> + }
> + break;
> +
> +LABEL (form_string):
> + {
> + size_t len;
> +
> + /* The string argument could in fact be `char *' or `wchar_t *'.
> + But this should not make a difference here. */
> + string = (CHAR_T *) process_arg_wstring ();
> +
> + /* Entry point for printing other strings. */
> + LABEL (print_string):
> +
> + if (string == NULL)
> + {
> + /* Write "(null)" if there's space. */
> + if (prec == -1 || prec >= (int) array_length (null) - 1)
> + {
> + string = (CHAR_T *) null;
> + len = array_length (null) - 1;
> + }
> + else
> + {
> + string = (CHAR_T *) L"";
> + len = 0;
> + }
> + }
> + else if (!is_long && spec != L_('S'))
> + {
> + done = outstring_converted_wide_string
> + (s, (const char *) string, prec, width, left, done);
> + if (done < 0)
> + goto all_done;
> + /* The padding has already been written. */
> + break;
> + }
> + else
> + {
> + if (prec != -1)
> + /* Search for the end of the string, but don't search past
> + the length specified by the precision. */
> + len = __wcsnlen (string, prec);
> + else
> + len = __wcslen (string);
> + }
> +
> + if ((width -= len) < 0)
> + {
> + outstring (string, len);
> + break;
> + }
> +
> + if (!left)
> + PAD (L' ');
> + outstring (string, len);
> + if (left)
> + PAD (L' ');
> + }
> + break;
> +#else /* !COMPILE_WPRINTF */
> +LABEL (form_character):
> + /* Character. */
> + if (is_long)
> + goto LABEL (form_wcharacter);
> + --width; /* Account for the character itself. */
> + if (!left)
> + PAD (' ');
> + outchar ((unsigned char) process_arg_int ()); /* Promoted. */
> + if (left)
> + PAD (' ');
> + break;
> +
> +LABEL (form_wcharacter):
> + {
> + /* Wide character. */
> + char buf[MB_LEN_MAX];
> + mbstate_t mbstate;
> + size_t len;
> +
> + memset (&mbstate, '\0', sizeof (mbstate_t));
> + len = __wcrtomb (buf, process_arg_wchar_t (), &mbstate);
> + if (len == (size_t) -1)
> + {
> + /* Something went wrong during the conversion. Bail out. */
> + done = -1;
> + goto all_done;
> + }
> + width -= len;
> + if (!left)
> + PAD (' ');
> + outstring (buf, len);
> + if (left)
> + PAD (' ');
> + }
> + break;
> +
> +LABEL (form_string):
> + {
> + size_t len;
> +
> + /* The string argument could in fact be `char *' or `wchar_t *'.
> + But this should not make a difference here. */
> + string = (char *) process_arg_string ();
> +
> + /* Entry point for printing other strings. */
> + LABEL (print_string):
> +
> + if (string == NULL)
> + {
> + /* Write "(null)" if there's space. */
> + if (prec == -1 || prec >= (int) sizeof (null) - 1)
> + {
> + string = (char *) null;
> + len = sizeof (null) - 1;
> + }
> + else
> + {
> + string = (char *) "";
> + len = 0;
> + }
> + }
> + else if (!is_long && spec != L_('S'))
> + {
> + if (prec != -1)
> + /* Search for the end of the string, but don't search past
> + the length (in bytes) specified by the precision. */
> + len = __strnlen (string, prec);
> + else
> + len = strlen (string);
> + }
> + else
> + {
> + done = outstring_converted_wide_string
> + (s, (const wchar_t *) string, prec, width, left, done);
> + if (done < 0)
> + goto all_done;
> + /* The padding has already been written. */
> + break;
> + }
> +
> + if ((width -= len) < 0)
> + {
> + outstring (string, len);
> + break;
> + }
> +
> + if (!left)
> + PAD (' ');
> + outstring (string, len);
> + if (left)
> + PAD (' ');
> + }
> + break;
> +#endif /* !COMPILE_WPRINTF */
> +}
next prev parent reply other threads:[~2022-05-20 13:28 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-17 19:28 [PATCH 00/26] vfprintf rework to remove vtables Florian Weimer
2022-03-17 19:28 ` [PATCH 01/26] libio: Convert tst_swprintf to the test framework Florian Weimer
2022-03-18 17:40 ` Adhemerval Zanella
2022-03-17 19:28 ` [PATCH 02/26] libio: Flush-only _IO_str_overflow must not return EOF (bug 28949) Florian Weimer
2022-03-18 18:11 ` Adhemerval Zanella
2022-03-17 19:28 ` [PATCH 03/26] stdio-common: Add wide stream coverage to tst-vfprintf-user-type Florian Weimer
2022-03-18 18:30 ` Adhemerval Zanella
2022-03-18 19:19 ` Florian Weimer
2022-03-17 19:28 ` [PATCH 04/26] stdio-common: Add tst-printf-width-i18n to cover numeric field width Florian Weimer
2022-05-20 13:22 ` Adhemerval Zanella
2022-05-20 13:33 ` Adhemerval Zanella
2022-05-23 6:39 ` Florian Weimer
2022-03-17 19:28 ` [PATCH 05/26] vfprintf: Move argument processing into vfprintf-process-arg.c Florian Weimer
2022-05-20 13:28 ` Adhemerval Zanella [this message]
2022-03-17 19:28 ` [PATCH 06/26] vfprintf: Consolidate some multibyte/wide character processing Florian Weimer
2022-05-20 14:16 ` Adhemerval Zanella
2022-03-17 19:29 ` [PATCH 07/26] __printf_fphex always uses LC_NUMERIC Florian Weimer
2022-05-20 14:21 ` Adhemerval Zanella
2022-05-23 6:55 ` Florian Weimer
2022-03-17 19:29 ` [PATCH 08/26] stdio-common: Add tst-memstream-string for open_memstream overflow Florian Weimer
2022-05-20 17:44 ` Adhemerval Zanella
2022-05-23 7:03 ` Florian Weimer
2022-03-17 19:29 ` [PATCH 09/26] stdio-common: Add printf specifier registry to <printf.h> Florian Weimer
2022-05-20 17:49 ` Adhemerval Zanella
2022-03-17 19:30 ` [PATCH 10/26] stdio-common: Move union printf_arg int <printf.h> Florian Weimer
2022-05-20 17:51 ` Adhemerval Zanella
2022-03-17 19:30 ` [PATCH 11/26] stdio-common: Simplify printf_unknown interface in vfprintf-internal.c Florian Weimer
2022-05-20 18:07 ` Adhemerval Zanella
2022-03-17 19:30 ` [PATCH 12/26] locale: Call _nl_unload_locale from _nl_archive_subfreeres Florian Weimer
2022-05-20 18:09 ` Adhemerval Zanella
2022-05-23 7:14 ` Florian Weimer
2022-03-17 19:30 ` [PATCH 13/26] locale: Remove cleanup function pointer from struct __localedata Florian Weimer
2022-05-20 18:16 ` Adhemerval Zanella
2022-03-17 19:30 ` [PATCH 14/26] locale: Remove private union from struct __locale_data Florian Weimer
2022-05-20 18:22 ` Adhemerval Zanella
2022-03-17 19:30 ` [PATCH 15/26] locale: Add more cached data to LC_CTYPE Florian Weimer
2022-05-20 18:29 ` Adhemerval Zanella
2022-05-23 7:20 ` Florian Weimer
2022-03-17 19:31 ` [PATCH 16/26] locale: Implement struct grouping_iterator Florian Weimer
2022-03-17 19:31 ` [PATCH 17/26] stdio-common: Introduce buffers for implementing printf Florian Weimer
2022-03-17 19:31 ` [PATCH 18/26] stdio-common: Add __printf_function_invoke Florian Weimer
2022-03-17 19:31 ` [PATCH 19/26] stdio-common: Add __translated_number_width Florian Weimer
2022-03-17 19:31 ` [PATCH 20/26] stdio-common: Convert vfprintf and related functions to buffers Florian Weimer
2022-03-17 19:31 ` [PATCH 21/26] stdio-common: Add lock optimization to vfprintf and vfwprintf Florian Weimer
2022-03-17 19:31 ` [PATCH 22/26] libio: Convert __vsprintf_internal to buffers Florian Weimer
2022-03-17 19:31 ` [PATCH 23/26] libio: Convert __vasprintf_internal " Florian Weimer
2022-03-17 19:31 ` [PATCH 24/26] libio: Convert __vdprintf_internal " Florian Weimer
2022-03-17 19:32 ` [PATCH 25/26] libio: Convert __obstack_vprintf_internal to buffers (bug 27124) Florian Weimer
2022-03-17 19:32 ` [PATCH 26/26] libio: Convert __vswprintf_internal to buffers (bug 27857) Florian Weimer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6512211a-d03a-6340-9298-d039ef81f821@linaro.org \
--to=adhemerval.zanella@linaro.org \
--cc=fweimer@redhat.com \
--cc=libc-alpha@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).