aboutsummaryrefslogtreecommitdiff
path: root/stdio-common/vfprintf-internal.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common/vfprintf-internal.c')
-rw-r--r--stdio-common/vfprintf-internal.c2364
1 files changed, 2364 insertions, 0 deletions
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
new file mode 100644
index 0000000000..b0c86e99bd
--- /dev/null
+++ b/stdio-common/vfprintf-internal.c
@@ -0,0 +1,2364 @@
+/* Copyright (C) 1991-2018 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <ctype.h>
+#include <limits.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <wchar.h>
+#include <libc-lock.h>
+#include <sys/param.h>
+#include <_itoa.h>
+#include <locale/localeinfo.h>
+#include <stdio.h>
+#include <scratch_buffer.h>
+
+/* This code is shared between the standard stdio implementation found
+ in GNU C library and the libio implementation originally found in
+ GNU libg++.
+
+ Beside this it is also shared between the normal and wide character
+ implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995. */
+
+#include <libioP.h>
+
+#ifdef COMPILE_WPRINTF
+#include <wctype.h>
+#endif
+
+/* In some cases we need extra space for all the output which is not
+ counted in the width of the string. We assume 32 characters is
+ enough. */
+#define EXTSIZ 32
+#define ARGCHECK(S, Format) \
+ do \
+ { \
+ /* Check file argument for consistence. */ \
+ CHECK_FILE (S, -1); \
+ if (S->_flags & _IO_NO_WRITES) \
+ { \
+ S->_flags |= _IO_ERR_SEEN; \
+ __set_errno (EBADF); \
+ return -1; \
+ } \
+ if (Format == NULL) \
+ { \
+ __set_errno (EINVAL); \
+ return -1; \
+ } \
+ } while (0)
+#define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
+
+#define done_add(val) \
+ do { \
+ unsigned int _val = val; \
+ assert ((unsigned int) done < (unsigned int) INT_MAX); \
+ if (__glibc_unlikely (INT_MAX - done < _val)) \
+ { \
+ done = -1; \
+ __set_errno (EOVERFLOW); \
+ goto all_done; \
+ } \
+ done += _val; \
+ } while (0)
+
+#ifndef COMPILE_WPRINTF
+# define vfprintf __vfprintf_internal
+# define CHAR_T char
+# define UCHAR_T unsigned char
+# define INT_T int
+typedef const char *THOUSANDS_SEP_T;
+# define L_(Str) Str
+# define ISDIGIT(Ch) ((unsigned int) ((Ch) - '0') < 10)
+# define STR_LEN(Str) strlen (Str)
+
+# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
+# define PAD(Padchar) \
+ do { \
+ if (width > 0) \
+ { \
+ ssize_t written = _IO_padn (s, (Padchar), width); \
+ if (__glibc_unlikely (written != width)) \
+ { \
+ done = -1; \
+ goto all_done; \
+ } \
+ done_add (written); \
+ } \
+ } while (0)
+# define PUTC(C, F) _IO_putc_unlocked (C, F)
+# define ORIENT if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
+ return -1
+#else
+# define vfprintf __vfwprintf_internal
+# define CHAR_T wchar_t
+/* This is a hack!!! There should be a type uwchar_t. */
+# define UCHAR_T unsigned int /* uwchar_t */
+# define INT_T wint_t
+typedef wchar_t THOUSANDS_SEP_T;
+# define L_(Str) L##Str
+# define ISDIGIT(Ch) ((unsigned int) ((Ch) - L'0') < 10)
+# define STR_LEN(Str) __wcslen (Str)
+
+# include <_itowa.h>
+
+# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
+# define PAD(Padchar) \
+ do { \
+ if (width > 0) \
+ { \
+ ssize_t written = _IO_wpadn (s, (Padchar), width); \
+ if (__glibc_unlikely (written != width)) \
+ { \
+ done = -1; \
+ goto all_done; \
+ } \
+ done_add (written); \
+ } \
+ } while (0)
+# define PUTC(C, F) _IO_putwc_unlocked (C, F)
+# define ORIENT if (_IO_fwide (s, 1) != 1) return -1
+
+# undef _itoa
+# define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
+# define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
+# undef EOF
+# define EOF WEOF
+#endif
+
+#include "_i18n_number.h"
+
+/* Include the shared code for parsing the format string. */
+#include "printf-parse.h"
+
+
+#define outchar(Ch) \
+ do \
+ { \
+ const INT_T outc = (Ch); \
+ if (PUTC (outc, s) == EOF || done == INT_MAX) \
+ { \
+ done = -1; \
+ goto all_done; \
+ } \
+ ++done; \
+ } \
+ while (0)
+
+#define outstring(String, Len) \
+ do \
+ { \
+ assert ((size_t) done <= (size_t) INT_MAX); \
+ if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len)) \
+ { \
+ done = -1; \
+ goto all_done; \
+ } \
+ if (__glibc_unlikely (INT_MAX - done < (Len))) \
+ { \
+ done = -1; \
+ __set_errno (EOVERFLOW); \
+ goto all_done; \
+ } \
+ done += (Len); \
+ } \
+ while (0)
+
+/* For handling long_double and longlong we use the same flag. If
+ `long' and `long long' are effectively the same type define it to
+ zero. */
+#if LONG_MAX == LONG_LONG_MAX
+# define is_longlong 0
+#else
+# define is_longlong is_long_double
+#endif
+
+/* If `long' and `int' is effectively the same type we don't have to
+ handle `long separately. */
+#if INT_MAX == LONG_MAX
+# define is_long_num 0
+#else
+# define is_long_num is_long
+#endif
+
+
+/* Global constants. */
+static const CHAR_T null[] = L_("(null)");
+
+/* Size of the work_buffer variable (in characters, not bytes. */
+enum { WORK_BUFFER_SIZE = 1000 / sizeof (CHAR_T) };
+
+/* This table maps a character into a number representing a class. In
+ each step there is a destination label for each class. */
+static const uint8_t jump_table[] =
+ {
+ /* ' ' */ 1, 0, 0, /* '#' */ 4,
+ 0, /* '%' */ 14, 0, /* '\''*/ 6,
+ 0, 0, /* '*' */ 7, /* '+' */ 2,
+ 0, /* '-' */ 3, /* '.' */ 9, 0,
+ /* '0' */ 5, /* '1' */ 8, /* '2' */ 8, /* '3' */ 8,
+ /* '4' */ 8, /* '5' */ 8, /* '6' */ 8, /* '7' */ 8,
+ /* '8' */ 8, /* '9' */ 8, 0, 0,
+ 0, 0, 0, 0,
+ 0, /* 'A' */ 26, 0, /* 'C' */ 25,
+ 0, /* 'E' */ 19, /* F */ 19, /* 'G' */ 19,
+ 0, /* 'I' */ 29, 0, 0,
+ /* 'L' */ 12, 0, 0, 0,
+ 0, 0, 0, /* 'S' */ 21,
+ 0, 0, 0, 0,
+ /* 'X' */ 18, 0, /* 'Z' */ 13, 0,
+ 0, 0, 0, 0,
+ 0, /* 'a' */ 26, 0, /* 'c' */ 20,
+ /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
+ /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28, 0,
+ /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
+ /* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21,
+ /* 't' */ 27, /* 'u' */ 16, 0, 0,
+ /* 'x' */ 18, 0, /* 'z' */ 13
+ };
+
+#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z'))
+#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
+#define LABEL(Name) do_##Name
+#ifdef SHARED
+ /* 'int' is enough and it saves some space on 64 bit systems. */
+# define JUMP_TABLE_TYPE const int
+# define JUMP_TABLE_BASE_LABEL do_form_unknown
+# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
+# define JUMP(ChExpr, table) \
+ do \
+ { \
+ int offset; \
+ void *ptr; \
+ spec = (ChExpr); \
+ offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
+ : table[CHAR_CLASS (spec)]; \
+ ptr = &&JUMP_TABLE_BASE_LABEL + offset; \
+ goto *ptr; \
+ } \
+ while (0)
+#else
+# define JUMP_TABLE_TYPE const void *const
+# define REF(Name) &&do_##Name
+# define JUMP(ChExpr, table) \
+ do \
+ { \
+ const void *ptr; \
+ spec = (ChExpr); \
+ ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
+ : table[CHAR_CLASS (spec)]; \
+ goto *ptr; \
+ } \
+ while (0)
+#endif
+
+#define STEP0_3_TABLE \
+ /* Step 0: at the beginning. */ \
+ static JUMP_TABLE_TYPE step0_jumps[30] = \
+ { \
+ REF (form_unknown), \
+ REF (flag_space), /* for ' ' */ \
+ REF (flag_plus), /* for '+' */ \
+ REF (flag_minus), /* for '-' */ \
+ REF (flag_hash), /* for '<hash>' */ \
+ REF (flag_zero), /* for '0' */ \
+ REF (flag_quote), /* for '\'' */ \
+ REF (width_asterics), /* for '*' */ \
+ REF (width), /* for '1'...'9' */ \
+ REF (precision), /* for '.' */ \
+ REF (mod_half), /* for 'h' */ \
+ REF (mod_long), /* for 'l' */ \
+ REF (mod_longlong), /* for 'L', 'q' */ \
+ REF (mod_size_t), /* for 'z', 'Z' */ \
+ REF (form_percent), /* for '%' */ \
+ REF (form_integer), /* for 'd', 'i' */ \
+ REF (form_unsigned), /* for 'u' */ \
+ REF (form_octal), /* for 'o' */ \
+ REF (form_hexa), /* for 'X', 'x' */ \
+ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \
+ REF (form_character), /* for 'c' */ \
+ REF (form_string), /* for 's', 'S' */ \
+ REF (form_pointer), /* for 'p' */ \
+ REF (form_number), /* for 'n' */ \
+ REF (form_strerror), /* for 'm' */ \
+ REF (form_wcharacter), /* for 'C' */ \
+ REF (form_floathex), /* for 'A', 'a' */ \
+ REF (mod_ptrdiff_t), /* for 't' */ \
+ REF (mod_intmax_t), /* for 'j' */ \
+ REF (flag_i18n), /* for 'I' */ \
+ }; \
+ /* Step 1: after processing width. */ \
+ static JUMP_TABLE_TYPE step1_jumps[30] = \
+ { \
+ REF (form_unknown), \
+ REF (form_unknown), /* for ' ' */ \
+ REF (form_unknown), /* for '+' */ \
+ REF (form_unknown), /* for '-' */ \
+ REF (form_unknown), /* for '<hash>' */ \
+ REF (form_unknown), /* for '0' */ \
+ REF (form_unknown), /* for '\'' */ \
+ REF (form_unknown), /* for '*' */ \
+ REF (form_unknown), /* for '1'...'9' */ \
+ REF (precision), /* for '.' */ \
+ REF (mod_half), /* for 'h' */ \
+ REF (mod_long), /* for 'l' */ \
+ REF (mod_longlong), /* for 'L', 'q' */ \
+ REF (mod_size_t), /* for 'z', 'Z' */ \
+ REF (form_percent), /* for '%' */ \
+ REF (form_integer), /* for 'd', 'i' */ \
+ REF (form_unsigned), /* for 'u' */ \
+ REF (form_octal), /* for 'o' */ \
+ REF (form_hexa), /* for 'X', 'x' */ \
+ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \
+ REF (form_character), /* for 'c' */ \
+ REF (form_string), /* for 's', 'S' */ \
+ REF (form_pointer), /* for 'p' */ \
+ REF (form_number), /* for 'n' */ \
+ REF (form_strerror), /* for 'm' */ \
+ REF (form_wcharacter), /* for 'C' */ \
+ REF (form_floathex), /* for 'A', 'a' */ \
+ REF (mod_ptrdiff_t), /* for 't' */ \
+ REF (mod_intmax_t), /* for 'j' */ \
+ REF (form_unknown) /* for 'I' */ \
+ }; \
+ /* Step 2: after processing precision. */ \
+ static JUMP_TABLE_TYPE step2_jumps[30] = \
+ { \
+ REF (form_unknown), \
+ REF (form_unknown), /* for ' ' */ \
+ REF (form_unknown), /* for '+' */ \
+ REF (form_unknown), /* for '-' */ \
+ REF (form_unknown), /* for '<hash>' */ \
+ REF (form_unknown), /* for '0' */ \
+ REF (form_unknown), /* for '\'' */ \
+ REF (form_unknown), /* for '*' */ \
+ REF (form_unknown), /* for '1'...'9' */ \
+ REF (form_unknown), /* for '.' */ \
+ REF (mod_half), /* for 'h' */ \
+ REF (mod_long), /* for 'l' */ \
+ REF (mod_longlong), /* for 'L', 'q' */ \
+ REF (mod_size_t), /* for 'z', 'Z' */ \
+ REF (form_percent), /* for '%' */ \
+ REF (form_integer), /* for 'd', 'i' */ \
+ REF (form_unsigned), /* for 'u' */ \
+ REF (form_octal), /* for 'o' */ \
+ REF (form_hexa), /* for 'X', 'x' */ \
+ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \
+ REF (form_character), /* for 'c' */ \
+ REF (form_string), /* for 's', 'S' */ \
+ REF (form_pointer), /* for 'p' */ \
+ REF (form_number), /* for 'n' */ \
+ REF (form_strerror), /* for 'm' */ \
+ REF (form_wcharacter), /* for 'C' */ \
+ REF (form_floathex), /* for 'A', 'a' */ \
+ REF (mod_ptrdiff_t), /* for 't' */ \
+ REF (mod_intmax_t), /* for 'j' */ \
+ REF (form_unknown) /* for 'I' */ \
+ }; \
+ /* Step 3a: after processing first 'h' modifier. */ \
+ static JUMP_TABLE_TYPE step3a_jumps[30] = \
+ { \
+ REF (form_unknown), \
+ REF (form_unknown), /* for ' ' */ \
+ REF (form_unknown), /* for '+' */ \
+ REF (form_unknown), /* for '-' */ \
+ REF (form_unknown), /* for '<hash>' */ \
+ REF (form_unknown), /* for '0' */ \
+ REF (form_unknown), /* for '\'' */ \
+ REF (form_unknown), /* for '*' */ \
+ REF (form_unknown), /* for '1'...'9' */ \
+ REF (form_unknown), /* for '.' */ \
+ REF (mod_halfhalf), /* for 'h' */ \
+ REF (form_unknown), /* for 'l' */ \
+ REF (form_unknown), /* for 'L', 'q' */ \
+ REF (form_unknown), /* for 'z', 'Z' */ \
+ REF (form_percent), /* for '%' */ \
+ REF (form_integer), /* for 'd', 'i' */ \
+ REF (form_unsigned), /* for 'u' */ \
+ REF (form_octal), /* for 'o' */ \
+ REF (form_hexa), /* for 'X', 'x' */ \
+ REF (form_unknown), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \
+ REF (form_unknown), /* for 'c' */ \
+ REF (form_unknown), /* for 's', 'S' */ \
+ REF (form_unknown), /* for 'p' */ \
+ REF (form_number), /* for 'n' */ \
+ REF (form_unknown), /* for 'm' */ \
+ REF (form_unknown), /* for 'C' */ \
+ REF (form_unknown), /* for 'A', 'a' */ \
+ REF (form_unknown), /* for 't' */ \
+ REF (form_unknown), /* for 'j' */ \
+ REF (form_unknown) /* for 'I' */ \
+ }; \
+ /* Step 3b: after processing first 'l' modifier. */ \
+ static JUMP_TABLE_TYPE step3b_jumps[30] = \
+ { \
+ REF (form_unknown), \
+ REF (form_unknown), /* for ' ' */ \
+ REF (form_unknown), /* for '+' */ \
+ REF (form_unknown), /* for '-' */ \
+ REF (form_unknown), /* for '<hash>' */ \
+ REF (form_unknown), /* for '0' */ \
+ REF (form_unknown), /* for '\'' */ \
+ REF (form_unknown), /* for '*' */ \
+ REF (form_unknown), /* for '1'...'9' */ \
+ REF (form_unknown), /* for '.' */ \
+ REF (form_unknown), /* for 'h' */ \
+ REF (mod_longlong), /* for 'l' */ \
+ REF (form_unknown), /* for 'L', 'q' */ \
+ REF (form_unknown), /* for 'z', 'Z' */ \
+ REF (form_percent), /* for '%' */ \
+ REF (form_integer), /* for 'd', 'i' */ \
+ REF (form_unsigned), /* for 'u' */ \
+ REF (form_octal), /* for 'o' */ \
+ REF (form_hexa), /* for 'X', 'x' */ \
+ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \
+ REF (form_character), /* for 'c' */ \
+ REF (form_string), /* for 's', 'S' */ \
+ REF (form_pointer), /* for 'p' */ \
+ REF (form_number), /* for 'n' */ \
+ REF (form_strerror), /* for 'm' */ \
+ REF (form_wcharacter), /* for 'C' */ \
+ REF (form_floathex), /* for 'A', 'a' */ \
+ REF (form_unknown), /* for 't' */ \
+ REF (form_unknown), /* for 'j' */ \
+ REF (form_unknown) /* for 'I' */ \
+ }
+
+#define STEP4_TABLE \
+ /* Step 4: processing format specifier. */ \
+ static JUMP_TABLE_TYPE step4_jumps[30] = \
+ { \
+ REF (form_unknown), \
+ REF (form_unknown), /* for ' ' */ \
+ REF (form_unknown), /* for '+' */ \
+ REF (form_unknown), /* for '-' */ \
+ REF (form_unknown), /* for '<hash>' */ \
+ REF (form_unknown), /* for '0' */ \
+ REF (form_unknown), /* for '\'' */ \
+ REF (form_unknown), /* for '*' */ \
+ REF (form_unknown), /* for '1'...'9' */ \
+ REF (form_unknown), /* for '.' */ \
+ REF (form_unknown), /* for 'h' */ \
+ REF (form_unknown), /* for 'l' */ \
+ REF (form_unknown), /* for 'L', 'q' */ \
+ REF (form_unknown), /* for 'z', 'Z' */ \
+ REF (form_percent), /* for '%' */ \
+ REF (form_integer), /* for 'd', 'i' */ \
+ REF (form_unsigned), /* for 'u' */ \
+ REF (form_octal), /* for 'o' */ \
+ REF (form_hexa), /* for 'X', 'x' */ \
+ REF (form_float), /* for 'E', 'e', 'F', 'f', 'G', 'g' */ \
+ REF (form_character), /* for 'c' */ \
+ REF (form_string), /* for 's', 'S' */ \
+ REF (form_pointer), /* for 'p' */ \
+ REF (form_number), /* for 'n' */ \
+ REF (form_strerror), /* for 'm' */ \
+ REF (form_wcharacter), /* for 'C' */ \
+ REF (form_floathex), /* for 'A', 'a' */ \
+ REF (form_unknown), /* for 't' */ \
+ REF (form_unknown), /* for 'j' */ \
+ REF (form_unknown) /* for 'I' */ \
+ }
+
+
+#define process_arg(fspec) \
+ /* 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; \
+ \
+ if (fspec == NULL) \
+ signed_number = va_arg (ap, long long int); \
+ else \
+ signed_number = args_value[fspec->data_arg].pa_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 (fspec == NULL) \
+ { \
+ if (is_long_num) \
+ signed_number = va_arg (ap, long int); \
+ else if (is_char) \
+ signed_number = (signed char) va_arg (ap, unsigned int); \
+ else if (!is_short) \
+ signed_number = va_arg (ap, int); \
+ else \
+ signed_number = (short int) va_arg (ap, unsigned int); \
+ } \
+ else \
+ if (is_long_num) \
+ signed_number = args_value[fspec->data_arg].pa_long_int; \
+ else if (is_char) \
+ signed_number = (signed char) \
+ args_value[fspec->data_arg].pa_u_int; \
+ else if (!is_short) \
+ signed_number = args_value[fspec->data_arg].pa_int; \
+ else \
+ signed_number = (short int) \
+ args_value[fspec->data_arg].pa_u_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; \
+ \
+ 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) \
+ { \
+ if (fspec == NULL) \
+ number.longlong = va_arg (ap, unsigned long long int); \
+ else \
+ number.longlong = args_value[fspec->data_arg].pa_u_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 (fspec == NULL) \
+ { \
+ if (is_long_num) \
+ number.word = va_arg (ap, unsigned long int); \
+ else if (is_char) \
+ number.word = (unsigned char) va_arg (ap, unsigned int); \
+ else if (!is_short) \
+ number.word = va_arg (ap, unsigned int); \
+ else \
+ number.word = (unsigned short int) va_arg (ap, unsigned int); \
+ } \
+ else \
+ if (is_long_num) \
+ number.word = args_value[fspec->data_arg].pa_u_long_int; \
+ else if (is_char) \
+ number.word = (unsigned char) \
+ args_va