aboutsummaryrefslogtreecommitdiff
path: root/stdio-common/vfprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common/vfprintf.c')
-rw-r--r--stdio-common/vfprintf.c2351
1 files changed, 7 insertions, 2344 deletions
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index ae412e4b84..13a10db99b 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -15,2350 +15,13 @@
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>
+#include <libio/libioP.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>
-
-/* 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 _IO_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 _IO_vfwprintf
-# 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_value[fspec->data_arg].pa_u_int; \
- else if (!is_short) \
- number.word = args_value[fspec->data_arg].pa_u_int; \
- else \
- number.word = (unsigned short int) \
- args_value[fspec->data_arg].pa_u_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'); \