5e480ad52b78a9dccecdd8ca393fd181d66ae3db
[platform/upstream/glibc.git] / stdio-common / vfprintf.c
1 /* Copyright (C) 1991-2002, 2003, 2004 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <ctype.h>
20 #include <limits.h>
21 #include <printf.h>
22 #include <stdarg.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <wchar.h>
28 #include <bits/libc-lock.h>
29 #include <sys/param.h>
30 #include "_itoa.h"
31 #include <locale/localeinfo.h>
32 #include <stdio.h>
33
34 /* This code is shared between the standard stdio implementation found
35    in GNU C library and the libio implementation originally found in
36    GNU libg++.
37
38    Beside this it is also shared between the normal and wide character
39    implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995.  */
40
41
42 #include <libioP.h>
43 #define FILE            _IO_FILE
44 #undef va_list
45 #define va_list _IO_va_list
46 #undef BUFSIZ
47 #define BUFSIZ          _IO_BUFSIZ
48 #define ARGCHECK(S, Format) \
49   do                                                                          \
50     {                                                                         \
51       /* Check file argument for consistence.  */                             \
52       CHECK_FILE (S, -1);                                                     \
53       if (S->_flags & _IO_NO_WRITES)                                          \
54         {                                                                     \
55           __set_errno (EBADF);                                                \
56           return -1;                                                          \
57         }                                                                     \
58       if (Format == NULL)                                                     \
59         {                                                                     \
60           MAYBE_SET_EINVAL;                                                   \
61           return -1;                                                          \
62         }                                                                     \
63     } while (0)
64 #define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED)
65
66 #ifndef COMPILE_WPRINTF
67 # define vfprintf       _IO_vfprintf
68 # define CHAR_T         char
69 # define UCHAR_T        unsigned char
70 # define INT_T          int
71 # define L_(Str)        Str
72 # define ISDIGIT(Ch)    ((unsigned int) ((Ch) - '0') < 10)
73 # define STR_LEN(Str)   strlen (Str)
74
75 # define PUT(F, S, N)   _IO_sputn ((F), (S), (N))
76 # define PAD(Padchar) \
77   if (width > 0)                                                              \
78     done += INTUSE(_IO_padn) (s, (Padchar), width)
79 # define PUTC(C, F)     _IO_putc_unlocked (C, F)
80 # define ORIENT         if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
81                           return -1
82 #else
83 # define vfprintf       _IO_vfwprintf
84 # define CHAR_T         wchar_t
85 /* This is a hack!!!  There should be a type uwchar_t.  */
86 # define UCHAR_T        unsigned int /* uwchar_t */
87 # define INT_T          wint_t
88 # define L_(Str)        L##Str
89 # define ISDIGIT(Ch)    ((unsigned int) ((Ch) - L'0') < 10)
90 # define STR_LEN(Str)   __wcslen (Str)
91
92 # include "_itowa.h"
93
94 # define PUT(F, S, N)   _IO_sputn ((F), (S), (N))
95 # define PAD(Padchar) \
96   if (width > 0)                                                              \
97     done += _IO_wpadn (s, (Padchar), width)
98 # define PUTC(C, F)     _IO_putwc_unlocked (C, F)
99 # define ORIENT         if (_IO_fwide (s, 1) != 1) return -1
100
101 # define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
102 # define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
103 # undef EOF
104 # define EOF WEOF
105 #endif
106
107 #include "_i18n_number.h"
108
109 /* Include the shared code for parsing the format string.  */
110 #include "printf-parse.h"
111
112
113 #define outchar(Ch)                                                           \
114   do                                                                          \
115     {                                                                         \
116       register const INT_T outc = (Ch);                                       \
117       if (PUTC (outc, s) == EOF)                                              \
118         {                                                                     \
119           done = -1;                                                          \
120           goto all_done;                                                      \
121         }                                                                     \
122       else                                                                    \
123         ++done;                                                               \
124     }                                                                         \
125   while (0)
126
127 #define outstring(String, Len)                                                \
128   do                                                                          \
129     {                                                                         \
130       if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len))                \
131         {                                                                     \
132           done = -1;                                                          \
133           goto all_done;                                                      \
134         }                                                                     \
135       done += (Len);                                                          \
136     }                                                                         \
137   while (0)
138
139 /* For handling long_double and longlong we use the same flag.  If
140    `long' and `long long' are effectively the same type define it to
141    zero.  */
142 #if LONG_MAX == LONG_LONG_MAX
143 # define is_longlong 0
144 #else
145 # define is_longlong is_long_double
146 #endif
147
148 /* If `long' and `int' is effectively the same type we don't have to
149    handle `long separately.  */
150 #if INT_MAX == LONG_MAX
151 # define is_long_num    0
152 #else
153 # define is_long_num    is_long
154 #endif
155
156
157 /* Global variables.  */
158 static const CHAR_T null[] = L_("(null)");
159
160
161 /* Helper function to provide temporary buffering for unbuffered streams.  */
162 static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list)
163      __THROW __attribute__ ((noinline)) internal_function;
164
165 /* Handle unknown format specifier.  */
166 static int printf_unknown (FILE *, const struct printf_info *,
167                            const void *const *) __THROW;
168
169 /* Group digits of number string.  */
170 #ifdef COMPILE_WPRINTF
171 static CHAR_T *group_number (CHAR_T *, CHAR_T *, const char *, wchar_t)
172      __THROW internal_function;
173 #else
174 static CHAR_T *group_number (CHAR_T *, CHAR_T *, const char *, const char *)
175      __THROW internal_function;
176 #endif
177
178
179 /* The function itself.  */
180 int
181 vfprintf (FILE *s, const CHAR_T *format, va_list ap)
182 {
183   /* The character used as thousands separator.  */
184 #ifdef COMPILE_WPRINTF
185   wchar_t thousands_sep = L'\0';
186 #else
187   const char *thousands_sep = NULL;
188 #endif
189
190   /* The string describing the size of groups of digits.  */
191   const char *grouping;
192
193   /* Place to accumulate the result.  */
194   int done;
195
196   /* Current character in format string.  */
197   const UCHAR_T *f;
198
199   /* End of leading constant string.  */
200   const UCHAR_T *lead_str_end;
201
202   /* Points to next format specifier.  */
203   const UCHAR_T *end_of_spec;
204
205   /* Buffer intermediate results.  */
206   CHAR_T work_buffer[1000];
207   CHAR_T *workstart = NULL;
208   CHAR_T *workend;
209
210   /* State for restartable multibyte character handling functions.  */
211 #ifndef COMPILE_WPRINTF
212   mbstate_t mbstate;
213 #endif
214
215   /* We have to save the original argument pointer.  */
216   va_list ap_save;
217
218   /* Count number of specifiers we already processed.  */
219   int nspecs_done;
220
221   /* For the %m format we may need the current `errno' value.  */
222   int save_errno = errno;
223
224   /* 1 if format is in read-only memory, -1 if it is in writable memory,
225      0 if unknown.  */
226   int readonly_format = 0;
227
228   /* This table maps a character into a number representing a
229      class.  In each step there is a destination label for each
230      class.  */
231   static const int jump_table[] =
232   {
233     /* ' ' */  1,            0,            0, /* '#' */  4,
234                0, /* '%' */ 14,            0, /* '\''*/  6,
235                0,            0, /* '*' */  7, /* '+' */  2,
236                0, /* '-' */  3, /* '.' */  9,            0,
237     /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
238     /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
239     /* '8' */  8, /* '9' */  8,            0,            0,
240                0,            0,            0,            0,
241                0, /* 'A' */ 26,            0, /* 'C' */ 25,
242                0, /* 'E' */ 19, /* F */   19, /* 'G' */ 19,
243                0, /* 'I' */ 29,            0,            0,
244     /* 'L' */ 12,            0,            0,            0,
245                0,            0,            0, /* 'S' */ 21,
246                0,            0,            0,            0,
247     /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
248                0,            0,            0,            0,
249                0, /* 'a' */ 26,            0, /* 'c' */ 20,
250     /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
251     /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28,            0,
252     /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
253     /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
254     /* 't' */ 27, /* 'u' */ 16,            0,            0,
255     /* 'x' */ 18,            0, /* 'z' */ 13
256   };
257
258 #define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z'))
259 #define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
260 #if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED
261   /* 'int' is enough and it saves some space on 64 bit systems.  */
262 # define JUMP_TABLE_TYPE const int
263 # define JUMP(ChExpr, table)                                                  \
264       do                                                                      \
265         {                                                                     \
266           int offset;                                                         \
267           void *__unbounded ptr;                                              \
268           spec = (ChExpr);                                                    \
269           offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)              \
270             : table[CHAR_CLASS (spec)];                                       \
271           ptr = &&do_form_unknown + offset;                                   \
272           goto *ptr;                                                          \
273         }                                                                     \
274       while (0)
275 #else
276 # define JUMP_TABLE_TYPE const void *const
277 # define JUMP(ChExpr, table)                                                  \
278       do                                                                      \
279         {                                                                     \
280           const void *__unbounded ptr;                                        \
281           spec = (ChExpr);                                                    \
282           ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)                 \
283             : table[CHAR_CLASS (spec)];                                       \
284           goto *ptr;                                                          \
285         }                                                                     \
286       while (0)
287 #endif
288
289 #define STEP0_3_TABLE                                                         \
290     /* Step 0: at the beginning.  */                                          \
291     static JUMP_TABLE_TYPE step0_jumps[30] =                                  \
292     {                                                                         \
293       REF (form_unknown),                                                     \
294       REF (flag_space),         /* for ' ' */                                 \
295       REF (flag_plus),          /* for '+' */                                 \
296       REF (flag_minus),         /* for '-' */                                 \
297       REF (flag_hash),          /* for '<hash>' */                            \
298       REF (flag_zero),          /* for '0' */                                 \
299       REF (flag_quote),         /* for '\'' */                                \
300       REF (width_asterics),     /* for '*' */                                 \
301       REF (width),              /* for '1'...'9' */                           \
302       REF (precision),          /* for '.' */                                 \
303       REF (mod_half),           /* for 'h' */                                 \
304       REF (mod_long),           /* for 'l' */                                 \
305       REF (mod_longlong),       /* for 'L', 'q' */                            \
306       REF (mod_size_t),         /* for 'z', 'Z' */                            \
307       REF (form_percent),       /* for '%' */                                 \
308       REF (form_integer),       /* for 'd', 'i' */                            \
309       REF (form_unsigned),      /* for 'u' */                                 \
310       REF (form_octal),         /* for 'o' */                                 \
311       REF (form_hexa),          /* for 'X', 'x' */                            \
312       REF (form_float),         /* for 'E', 'e', 'F', 'f', 'G', 'g' */        \
313       REF (form_character),     /* for 'c' */                                 \
314       REF (form_string),        /* for 's', 'S' */                            \
315       REF (form_pointer),       /* for 'p' */                                 \
316       REF (form_number),        /* for 'n' */                                 \
317       REF (form_strerror),      /* for 'm' */                                 \
318       REF (form_wcharacter),    /* for 'C' */                                 \
319       REF (form_floathex),      /* for 'A', 'a' */                            \
320       REF (mod_ptrdiff_t),      /* for 't' */                                 \
321       REF (mod_intmax_t),       /* for 'j' */                                 \
322       REF (flag_i18n),          /* for 'I' */                                 \
323     };                                                                        \
324     /* Step 1: after processing width.  */                                    \
325     static JUMP_TABLE_TYPE step1_jumps[30] =                                  \
326     {                                                                         \
327       REF (form_unknown),                                                     \
328       REF (form_unknown),       /* for ' ' */                                 \
329       REF (form_unknown),       /* for '+' */                                 \
330       REF (form_unknown),       /* for '-' */                                 \
331       REF (form_unknown),       /* for '<hash>' */                            \
332       REF (form_unknown),       /* for '0' */                                 \
333       REF (form_unknown),       /* for '\'' */                                \
334       REF (form_unknown),       /* for '*' */                                 \
335       REF (form_unknown),       /* for '1'...'9' */                           \
336       REF (precision),          /* for '.' */                                 \
337       REF (mod_half),           /* for 'h' */                                 \
338       REF (mod_long),           /* for 'l' */                                 \
339       REF (mod_longlong),       /* for 'L', 'q' */                            \
340       REF (mod_size_t),         /* for 'z', 'Z' */                            \
341       REF (form_percent),       /* for '%' */                                 \
342       REF (form_integer),       /* for 'd', 'i' */                            \
343       REF (form_unsigned),      /* for 'u' */                                 \
344       REF (form_octal),         /* for 'o' */                                 \
345       REF (form_hexa),          /* for 'X', 'x' */                            \
346       REF (form_float),         /* for 'E', 'e', 'F', 'f', 'G', 'g' */        \
347       REF (form_character),     /* for 'c' */                                 \
348       REF (form_string),        /* for 's', 'S' */                            \
349       REF (form_pointer),       /* for 'p' */                                 \
350       REF (form_number),        /* for 'n' */                                 \
351       REF (form_strerror),      /* for 'm' */                                 \
352       REF (form_wcharacter),    /* for 'C' */                                 \
353       REF (form_floathex),      /* for 'A', 'a' */                            \
354       REF (mod_ptrdiff_t),      /* for 't' */                                 \
355       REF (mod_intmax_t),       /* for 'j' */                                 \
356       REF (form_unknown)        /* for 'I' */                                 \
357     };                                                                        \
358     /* Step 2: after processing precision.  */                                \
359     static JUMP_TABLE_TYPE step2_jumps[30] =                                  \
360     {                                                                         \
361       REF (form_unknown),                                                     \
362       REF (form_unknown),       /* for ' ' */                                 \
363       REF (form_unknown),       /* for '+' */                                 \
364       REF (form_unknown),       /* for '-' */                                 \
365       REF (form_unknown),       /* for '<hash>' */                            \
366       REF (form_unknown),       /* for '0' */                                 \
367       REF (form_unknown),       /* for '\'' */                                \
368       REF (form_unknown),       /* for '*' */                                 \
369       REF (form_unknown),       /* for '1'...'9' */                           \
370       REF (form_unknown),       /* for '.' */                                 \
371       REF (mod_half),           /* for 'h' */                                 \
372       REF (mod_long),           /* for 'l' */                                 \
373       REF (mod_longlong),       /* for 'L', 'q' */                            \
374       REF (mod_size_t),         /* for 'z', 'Z' */                            \
375       REF (form_percent),       /* for '%' */                                 \
376       REF (form_integer),       /* for 'd', 'i' */                            \
377       REF (form_unsigned),      /* for 'u' */                                 \
378       REF (form_octal),         /* for 'o' */                                 \
379       REF (form_hexa),          /* for 'X', 'x' */                            \
380       REF (form_float),         /* for 'E', 'e', 'F', 'f', 'G', 'g' */        \
381       REF (form_character),     /* for 'c' */                                 \
382       REF (form_string),        /* for 's', 'S' */                            \
383       REF (form_pointer),       /* for 'p' */                                 \
384       REF (form_number),        /* for 'n' */                                 \
385       REF (form_strerror),      /* for 'm' */                                 \
386       REF (form_wcharacter),    /* for 'C' */                                 \
387       REF (form_floathex),      /* for 'A', 'a' */                            \
388       REF (mod_ptrdiff_t),      /* for 't' */                                 \
389       REF (mod_intmax_t),       /* for 'j' */                                 \
390       REF (form_unknown)        /* for 'I' */                                 \
391     };                                                                        \
392     /* Step 3a: after processing first 'h' modifier.  */                      \
393     static JUMP_TABLE_TYPE step3a_jumps[30] =                                 \
394     {                                                                         \
395       REF (form_unknown),                                                     \
396       REF (form_unknown),       /* for ' ' */                                 \
397       REF (form_unknown),       /* for '+' */                                 \
398       REF (form_unknown),       /* for '-' */                                 \
399       REF (form_unknown),       /* for '<hash>' */                            \
400       REF (form_unknown),       /* for '0' */                                 \
401       REF (form_unknown),       /* for '\'' */                                \
402       REF (form_unknown),       /* for '*' */                                 \
403       REF (form_unknown),       /* for '1'...'9' */                           \
404       REF (form_unknown),       /* for '.' */                                 \
405       REF (mod_halfhalf),       /* for 'h' */                                 \
406       REF (form_unknown),       /* for 'l' */                                 \
407       REF (form_unknown),       /* for 'L', 'q' */                            \
408       REF (form_unknown),       /* for 'z', 'Z' */                            \
409       REF (form_percent),       /* for '%' */                                 \
410       REF (form_integer),       /* for 'd', 'i' */                            \
411       REF (form_unsigned),      /* for 'u' */                                 \
412       REF (form_octal),         /* for 'o' */                                 \
413       REF (form_hexa),          /* for 'X', 'x' */                            \
414       REF (form_unknown),       /* for 'E', 'e', 'F', 'f', 'G', 'g' */        \
415       REF (form_unknown),       /* for 'c' */                                 \
416       REF (form_unknown),       /* for 's', 'S' */                            \
417       REF (form_unknown),       /* for 'p' */                                 \
418       REF (form_number),        /* for 'n' */                                 \
419       REF (form_unknown),       /* for 'm' */                                 \
420       REF (form_unknown),       /* for 'C' */                                 \
421       REF (form_unknown),       /* for 'A', 'a' */                            \
422       REF (form_unknown),       /* for 't' */                                 \
423       REF (form_unknown),       /* for 'j' */                                 \
424       REF (form_unknown)        /* for 'I' */                                 \
425     };                                                                        \
426     /* Step 3b: after processing first 'l' modifier.  */                      \
427     static JUMP_TABLE_TYPE step3b_jumps[30] =                                 \
428     {                                                                         \
429       REF (form_unknown),                                                     \
430       REF (form_unknown),       /* for ' ' */                                 \
431       REF (form_unknown),       /* for '+' */                                 \
432       REF (form_unknown),       /* for '-' */                                 \
433       REF (form_unknown),       /* for '<hash>' */                            \
434       REF (form_unknown),       /* for '0' */                                 \
435       REF (form_unknown),       /* for '\'' */                                \
436       REF (form_unknown),       /* for '*' */                                 \
437       REF (form_unknown),       /* for '1'...'9' */                           \
438       REF (form_unknown),       /* for '.' */                                 \
439       REF (form_unknown),       /* for 'h' */                                 \
440       REF (mod_longlong),       /* for 'l' */                                 \
441       REF (form_unknown),       /* for 'L', 'q' */                            \
442       REF (form_unknown),       /* for 'z', 'Z' */                            \
443       REF (form_percent),       /* for '%' */                                 \
444       REF (form_integer),       /* for 'd', 'i' */                            \
445       REF (form_unsigned),      /* for 'u' */                                 \
446       REF (form_octal),         /* for 'o' */                                 \
447       REF (form_hexa),          /* for 'X', 'x' */                            \
448       REF (form_float),         /* for 'E', 'e', 'F', 'f', 'G', 'g' */        \
449       REF (form_character),     /* for 'c' */                                 \
450       REF (form_string),        /* for 's', 'S' */                            \
451       REF (form_pointer),       /* for 'p' */                                 \
452       REF (form_number),        /* for 'n' */                                 \
453       REF (form_strerror),      /* for 'm' */                                 \
454       REF (form_wcharacter),    /* for 'C' */                                 \
455       REF (form_floathex),      /* for 'A', 'a' */                            \
456       REF (form_unknown),       /* for 't' */                                 \
457       REF (form_unknown),       /* for 'j' */                                 \
458       REF (form_unknown)        /* for 'I' */                                 \
459     }
460
461 #define STEP4_TABLE                                                           \
462     /* Step 4: processing format specifier.  */                               \
463     static JUMP_TABLE_TYPE step4_jumps[30] =                                  \
464     {                                                                         \
465       REF (form_unknown),                                                     \
466       REF (form_unknown),       /* for ' ' */                                 \
467       REF (form_unknown),       /* for '+' */                                 \
468       REF (form_unknown),       /* for '-' */                                 \
469       REF (form_unknown),       /* for '<hash>' */                            \
470       REF (form_unknown),       /* for '0' */                                 \
471       REF (form_unknown),       /* for '\'' */                                \
472       REF (form_unknown),       /* for '*' */                                 \
473       REF (form_unknown),       /* for '1'...'9' */                           \
474       REF (form_unknown),       /* for '.' */                                 \
475       REF (form_unknown),       /* for 'h' */                                 \
476       REF (form_unknown),       /* for 'l' */                                 \
477       REF (form_unknown),       /* for 'L', 'q' */                            \
478       REF (form_unknown),       /* for 'z', 'Z' */                            \
479       REF (form_percent),       /* for '%' */                                 \
480       REF (form_integer),       /* for 'd', 'i' */                            \
481       REF (form_unsigned),      /* for 'u' */                                 \
482       REF (form_octal),         /* for 'o' */                                 \
483       REF (form_hexa),          /* for 'X', 'x' */                            \
484       REF (form_float),         /* for 'E', 'e', 'F', 'f', 'G', 'g' */        \
485       REF (form_character),     /* for 'c' */                                 \
486       REF (form_string),        /* for 's', 'S' */                            \
487       REF (form_pointer),       /* for 'p' */                                 \
488       REF (form_number),        /* for 'n' */                                 \
489       REF (form_strerror),      /* for 'm' */                                 \
490       REF (form_wcharacter),    /* for 'C' */                                 \
491       REF (form_floathex),      /* for 'A', 'a' */                            \
492       REF (form_unknown),       /* for 't' */                                 \
493       REF (form_unknown),       /* for 'j' */                                 \
494       REF (form_unknown)        /* for 'I' */                                 \
495     }
496
497
498 #define process_arg(fspec)                                                    \
499       /* Start real work.  We know about all flags and modifiers and          \
500          now process the wanted format specifier.  */                         \
501     LABEL (form_percent):                                                     \
502       /* Write a literal "%".  */                                             \
503       outchar (L_('%'));                                                      \
504       break;                                                                  \
505                                                                               \
506     LABEL (form_integer):                                                     \
507       /* Signed decimal integer.  */                                          \
508       base = 10;                                                              \
509                                                                               \
510       if (is_longlong)                                                        \
511         {                                                                     \
512           long long int signed_number;                                        \
513                                                                               \
514           if (fspec == NULL)                                                  \
515             signed_number = va_arg (ap, long long int);                       \
516           else                                                                \
517             signed_number = args_value[fspec->data_arg].pa_long_long_int;     \
518                                                                               \
519           is_negative = signed_number < 0;                                    \
520           number.longlong = is_negative ? (- signed_number) : signed_number;  \
521                                                                               \
522           goto LABEL (longlong_number);                                       \
523         }                                                                     \
524       else                                                                    \
525         {                                                                     \
526           long int signed_number;                                             \
527                                                                               \
528           if (fspec == NULL)                                                  \
529             {                                                                 \
530               if (is_long_num)                                                \
531                 signed_number = va_arg (ap, long int);                        \
532               else  /* `char' and `short int' will be promoted to `int'.  */  \
533                 signed_number = va_arg (ap, int);                             \
534             }                                                                 \
535           else                                                                \
536             if (is_long_num)                                                  \
537               signed_number = args_value[fspec->data_arg].pa_long_int;        \
538             else  /* `char' and `short int' will be promoted to `int'.  */    \
539               signed_number = args_value[fspec->data_arg].pa_int;             \
540                                                                               \
541           is_negative = signed_number < 0;                                    \
542           number.word = is_negative ? (- signed_number) : signed_number;      \
543                                                                               \
544           goto LABEL (number);                                                \
545         }                                                                     \
546       /* NOTREACHED */                                                        \
547                                                                               \
548     LABEL (form_unsigned):                                                    \
549       /* Unsigned decimal integer.  */                                        \
550       base = 10;                                                              \
551       goto LABEL (unsigned_number);                                           \
552       /* NOTREACHED */                                                        \
553                                                                               \
554     LABEL (form_octal):                                                       \
555       /* Unsigned octal integer.  */                                          \
556       base = 8;                                                               \
557       goto LABEL (unsigned_number);                                           \
558       /* NOTREACHED */                                                        \
559                                                                               \
560     LABEL (form_hexa):                                                        \
561       /* Unsigned hexadecimal integer.  */                                    \
562       base = 16;                                                              \
563                                                                               \
564     LABEL (unsigned_number):      /* Unsigned number of base BASE.  */        \
565                                                                               \
566       /* ISO specifies the `+' and ` ' flags only for signed                  \
567          conversions.  */                                                     \
568       is_negative = 0;                                                        \
569       showsign = 0;                                                           \
570       space = 0;                                                              \
571                                                                               \
572       if (is_longlong)                                                        \
573         {                                                                     \
574           if (fspec == NULL)                                                  \
575             number.longlong = va_arg (ap, unsigned long long int);            \
576           else                                                                \
577             number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \
578                                                                               \
579         LABEL (longlong_number):                                              \
580           if (prec < 0)                                                       \
581             /* Supply a default precision if none was given.  */              \
582             prec = 1;                                                         \
583           else                                                                \
584             /* We have to take care for the '0' flag.  If a precision         \
585                is given it must be ignored.  */                               \
586             pad = L_(' ');                                                    \
587                                                                               \
588           /* If the precision is 0 and the number is 0 nothing has to         \
589              be written for the number, except for the 'o' format in          \
590              alternate form.  */                                              \
591           if (prec == 0 && number.longlong == 0)                              \
592             {                                                                 \
593               string = workend;                                               \
594               if (base == 8 && alt)                                           \
595                 *--string = L_('0');                                          \
596             }                                                                 \
597           else                                                                \
598             {                                                                 \
599               /* Put the number in WORK.  */                                  \
600               string = _itoa (number.longlong, workend, base,                 \
601                               spec == L_('X'));                               \
602               if (group && grouping)                                          \
603                 string = group_number (string, workend, grouping,             \
604                                        thousands_sep);                        \
605                                                                               \
606               if (use_outdigits && base == 10)                                \
607                 string = _i18n_number_rewrite (string, workend);              \
608             }                                                                 \
609           /* Simplify further test for num != 0.  */                          \
610           number.word = number.longlong != 0;                                 \
611         }                                                                     \
612       else                                                                    \
613         {                                                                     \
614           if (fspec == NULL)                                                  \
615             {                                                                 \
616               if (is_long_num)                                                \
617                 number.word = va_arg (ap, unsigned long int);                 \
618               else if (is_char)                                               \
619                 number.word = (unsigned char) va_arg (ap, unsigned int);      \
620               else if (!is_short)                                             \
621                 number.word = va_arg (ap, unsigned int);                      \
622               else                                                            \
623                 number.word = (unsigned short int) va_arg (ap, unsigned int); \
624             }                                                                 \
625           else                                                                \
626             if (is_long_num)                                                  \
627               number.word = args_value[fspec->data_arg].pa_u_long_int;        \
628             else if (is_char)                                                 \
629               number.word = (unsigned char)                                   \
630                 args_value[fspec->data_arg].pa_u_int;                         \
631             else if (!is_short)                                               \
632               number.word = args_value[fspec->data_arg].pa_u_int;             \
633             else                                                              \
634               number.word = (unsigned short int)                              \
635                 args_value[fspec->data_arg].pa_u_int;                         \
636                                                                               \
637         LABEL (number):                                                       \
638           if (prec < 0)                                                       \
639             /* Supply a default precision if none was given.  */              \
640             prec = 1;                                                         \
641           else                                                                \
642             /* We have to take care for the '0' flag.  If a precision         \
643                is given it must be ignored.  */                               \
644             pad = L_(' ');                                                    \
645                                                                               \
646           /* If the precision is 0 and the number is 0 nothing has to         \
647              be written for the number, except for the 'o' format in          \
648              alternate form.  */                                              \
649           if (prec == 0 && number.word == 0)                                  \
650             {                                                                 \
651               string = workend;                                               \
652               if (base == 8 && alt)                                           \
653                 *--string = L_('0');                                          \
654             }                                                                 \
655           else                                                                \
656             {                                                                 \
657               /* Put the number in WORK.  */                                  \
658               string = _itoa_word (number.word, workend, base,                \
659                                    spec == L_('X'));                          \
660               if (group && grouping)                                          \
661                 string = group_number (string, workend, grouping,             \
662                                        thousands_sep);                        \
663                                                                               \
664               if (use_outdigits && base == 10)                                \
665                 string = _i18n_number_rewrite (string, workend);              \
666             }                                                                 \
667         }                                                                     \
668                                                                               \
669       if (prec <= workend - string && number.word != 0 && alt && base == 8)   \
670         /* Add octal marker.  */                                              \
671         *--string = L_('0');                                                  \
672                                                                               \
673       prec = MAX (0, prec - (workend - string));                              \
674                                                                               \
675       if (!left)                                                              \
676         {                                                                     \
677           width -= workend - string + prec;                                   \
678                                                                               \
679           if (number.word != 0 && alt && base == 16)                          \
680             /* Account for 0X hex marker.  */                                 \
681             width -= 2;                                                       \
682                                                                               \
683           if (is_negative || showsign || space)                               \
684             --width;                                                          \
685                                                                               \
686           if (pad == L_(' '))                                                 \
687             {                                                                 \
688               PAD (L_(' '));                                                  \
689               width = 0;                                                      \
690             }                                                                 \
691                                                                               \
692           if (is_negative)                                                    \
693             outchar (L_('-'));                                                \
694           else if (showsign)                                                  \
695             outchar (L_('+'));                                                \
696           else if (space)                                                     \
697             outchar (L_(' '));                                                \
698                                                                               \
699           if (number.word != 0 && alt && base == 16)                          \
700             {                                                                 \
701               outchar (L_('0'));                                              \
702               outchar (spec);                                                 \
703             }                                                                 \
704                                                                               \
705           width += prec;                                                      \
706           PAD (L_('0'));                                                      \
707                                                                               \
708           outstring (string, workend - string);                               \
709                                                                               \
710           break;                                                              \
711         }                                                                     \
712       else                                                                    \
713         {                                                                     \
714           if (is_negative)                                                    \
715             {                                                                 \
716               outchar (L_('-'));                                              \
717               --width;                                                        \
718             }                                                                 \
719           else if (showsign)                                                  \
720             {                                                                 \
721               outchar (L_('+'));                                              \
722               --width;                                                        \
723             }                                                                 \
724           else if (space)                                                     \
725             {                                                                 \
726               outchar (L_(' '));                                              \
727               --width;                                                        \
728             }                                                                 \
729                                                                               \
730           if (number.word != 0 && alt && base == 16)                          \
731             {                                                                 \
732               outchar (L_('0'));                                              \
733               outchar (spec);                                                 \
734               width -= 2;                                                     \
735             }                                                                 \
736                                                                               \
737           width -= workend - string + prec;                                   \
738                                                                               \
739           if (prec > 0)                                                       \
740             {                                                                 \
741               int temp = width;                                               \
742               width = prec;                                                   \
743               PAD (L_('0'));;                                                 \
744               width = temp;                                                   \
745             }                                                                 \
746                                                                               \
747           outstring (string, workend - string);                               \
748                                                                               \
749           PAD (L_(' '));                                                      \
750           break;                                                              \
751         }                                                                     \
752                                                                               \
753     LABEL (form_float):                                                       \
754       {                                                                       \
755         /* Floating-point number.  This is handled by printf_fp.c.  */        \
756         const void *ptr;                                                      \
757         int function_done;                                                    \
758                                                                               \
759         if (fspec == NULL)                                                    \
760           {                                                                   \
761             struct printf_info info = { .prec = prec,                         \
762                                         .width = width,                       \
763                                         .spec = spec,                         \
764                                         .is_long_double = is_long_double,     \
765                                         .is_short = is_short,                 \
766                                         .is_long = is_long,                   \
767                                         .alt = alt,                           \
768                                         .space = space,                       \
769                                         .left = left,                         \
770                                         .showsign = showsign,                 \
771                                         .group = group,                       \
772                                         .pad = pad,                           \
773                                         .extra = 0,                           \
774                                         .i18n = use_outdigits,                \
775                                         .wide = sizeof (CHAR_T) != 1 };       \
776                                                                               \
777             if (is_long_double)                                               \
778               the_arg.pa_long_double = va_arg (ap, long double);              \
779             else                                                              \
780               the_arg.pa_double = va_arg (ap, double);                        \
781             ptr = (const void *) &the_arg;                                    \
782                                                                               \
783             function_done = __printf_fp (s, &info, &ptr);                     \
784           }                                                                   \
785         else                                                                  \
786           {                                                                   \
787             ptr = (const void *) &args_value[fspec->data_arg];                \
788                                                                               \
789             function_done = __printf_fp (s, &fspec->info, &ptr);              \
790           }                                                                   \
791                                                                               \
792         if (function_done < 0)                                                \
793           {                                                                   \
794             /* Error in print handler.  */                                    \
795             done = -1;                                                        \
796             goto all_done;                                                    \
797           }                                                                   \
798                                                                               \
799         done += function_done;                                                \
800       }                                                                       \
801       break;                                                                  \
802                                                                               \
803     LABEL (form_floathex):                                                    \
804       {                                                                       \
805         /* Floating point number printed as hexadecimal number.  */           \
806         const void *ptr;                                                      \
807         int function_done;                                                    \
808                                                                               \
809         if (fspec == NULL)                                                    \
810           {                                                                   \
811             struct printf_info info = { .prec = prec,                         \
812                                         .width = width,                       \
813                                         .spec = spec,                         \
814                                         .is_long_double = is_long_double,     \
815                                         .is_short = is_short,                 \
816                                         .is_long = is_long,                   \
817                                         .alt = alt,                           \
818                                         .space = space,                       \
819                                         .left = left,                         \
820                                         .showsign = showsign,                 \
821                                         .group = group,                       \
822                                         .pad = pad,                           \
823                                         .extra = 0,                           \
824                                         .wide = sizeof (CHAR_T) != 1 };       \
825                                                                               \
826             if (is_long_double)                                               \
827               the_arg.pa_long_double = va_arg (ap, long double);              \
828             else                                                              \
829               the_arg.pa_double = va_arg (ap, double);                        \
830             ptr = (const void *) &the_arg;                                    \
831                                                                               \
832             function_done = __printf_fphex (s, &info, &ptr);                  \
833           }                                                                   \
834         else                                                                  \
835           {                                                                   \
836             ptr = (const void *) &args_value[fspec->data_arg];                \
837                                                                               \
838             function_done = __printf_fphex (s, &fspec->info, &ptr);           \
839           }                                                                   \
840                                                                               \
841         if (function_done < 0)                                                \
842           {                                                                   \
843             /* Error in print handler.  */                                    \
844             done = -1;                                                        \
845             goto all_done;                                                    \
846           }                                                                   \
847                                                                               \
848         done += function_done;                                                \
849       }                                                                       \
850       break;                                                                  \
851                                                                               \
852     LABEL (form_pointer):                                                     \
853       /* Generic pointer.  */                                                 \
854       {                                                                       \
855         const void *ptr;                                                      \
856         if (fspec == NULL)                                                    \
857           ptr = va_arg (ap, void *);                                          \
858         else                                                                  \
859           ptr = args_value[fspec->data_arg].pa_pointer;                       \
860         if (ptr != NULL)                                                      \
861           {                                                                   \
862             /* If the pointer is not NULL, write it as a %#x spec.  */        \
863             base = 16;                                                        \
864             number.word = (unsigned long int) ptr;                            \
865             is_negative = 0;                                                  \
866             alt = 1;                                                          \
867             group = 0;                                                        \
868             spec = L_('x');                                                   \
869             goto LABEL (number);                                              \
870           }                                                                   \
871         else                                                                  \
872           {                                                                   \
873             /* Write "(nil)" for a nil pointer.  */                           \
874             string = (CHAR_T *) L_("(nil)");                                  \
875             /* Make sure the full string "(nil)" is printed.  */              \
876             if (prec < 5)                                                     \
877               prec = 5;                                                       \
878             is_long = 0;        /* This is no wide-char string.  */           \
879             goto LABEL (print_string);                                        \
880           }                                                                   \
881       }                                                                       \
882       /* NOTREACHED */                                                        \
883                                                                               \
884     LABEL (form_number):                                                      \
885       if (s->_flags2 & _IO_FLAGS2_CHECK_PERCENT_N)                            \
886         {                                                                     \
887           if (! readonly_format)                                              \
888             {                                                                 \
889               extern int __readonly_area (const void *, size_t)               \
890                 attribute_hidden;                                             \
891               readonly_format                                                 \
892                 = __readonly_area (format, (STR_LEN (format) + 1)             \
893                                            * sizeof (CHAR_T));                \
894             }                                                                 \
895           if (readonly_format < 0)                                            \
896             __chk_fail ();                                                    \
897         }                                                                     \
898       /* Answer the count of characters written.  */                          \
899       if (fspec == NULL)                                                      \
900         {                                                                     \
901           if (is_longlong)                                                    \
902             *(long long int *) va_arg (ap, void *) = done;                    \
903           else if (is_long_num)                                               \
904             *(long int *) va_arg (ap, void *) = done;                         \
905           else if (is_char)                                                   \
906             *(char *) va_arg (ap, void *) = done;                             \
907           else if (!is_short)                                                 \
908             *(int *) va_arg (ap, void *) = done;                              \
909           else                                                                \
910             *(short int *) va_arg (ap, void *) = done;                        \
911         }                                                                     \
912       else                                                                    \
913         if (is_longlong)                                                      \
914           *(long long int *) args_value[fspec->data_arg].pa_pointer = done;   \
915         else if (is_long_num)                                                 \
916           *(long int *) args_value[fspec->data_arg].pa_pointer = done;        \
917         else if (is_char)                                                     \
918           *(char *) args_value[fspec->data_arg].pa_pointer = done;            \
919         else if (!is_short)                                                   \
920           *(int *) args_value[fspec->data_arg].pa_pointer = done;             \
921         else                                                                  \
922           *(short int *) args_value[fspec->data_arg].pa_pointer = done;       \
923       break;                                                                  \
924                                                                               \
925     LABEL (form_strerror):                                                    \
926       /* Print description of error ERRNO.  */                                \
927       string =                                                                \
928         (CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,            \
929                                  sizeof work_buffer);                         \
930       is_long = 0;              /* This is no wide-char string.  */           \
931       goto LABEL (print_string)
932
933 #ifdef COMPILE_WPRINTF
934 # define process_string_arg(fspec) \
935     LABEL (form_character):                                                   \
936       /* Character.  */                                                       \
937       if (is_long)                                                            \
938         goto LABEL (form_wcharacter);                                         \
939       --width;  /* Account for the character itself.  */                      \
940       if (!left)                                                              \
941         PAD (L' ');                                                           \
942       if (fspec == NULL)                                                      \
943         outchar (__btowc ((unsigned char) va_arg (ap, int))); /* Promoted. */ \
944       else                                                                    \
945         outchar (__btowc ((unsigned char)                                     \
946                           args_value[fspec->data_arg].pa_int));               \
947       if (left)                                                               \
948         PAD (L' ');                                                           \
949       break;                                                                  \
950                                                                               \
951     LABEL (form_wcharacter):                                                  \
952       {                                                                       \
953         /* Wide character.  */                                                \
954         --width;                                                              \
955         if (!left)                                                            \
956           PAD (L' ');                                                         \
957         if (fspec == NULL)                                                    \
958           outchar (va_arg (ap, wchar_t));                                     \
959         else                                                                  \
960           outchar (args_value[fspec->data_arg].pa_wchar);                     \
961         if (left)                                                             \
962           PAD (L' ');                                                         \
963       }                                                                       \
964       break;                                                                  \
965                                                                               \
966     LABEL (form_string):                                                      \
967       {                                                                       \
968         size_t len;                                                           \
969         int string_malloced;                                                  \
970                                                                               \
971         /* The string argument could in fact be `char *' or `wchar_t *'.      \
972            But this should not make a difference here.  */                    \
973         if (fspec == NULL)                                                    \
974           string = (CHAR_T *) va_arg (ap, const wchar_t *);                   \
975         else                                                                  \
976           string = (CHAR_T *) args_value[fspec->data_arg].pa_wstring;         \
977                                                                               \
978         /* Entry point for printing other strings.  */                        \
979       LABEL (print_string):                                                   \
980                                                                               \
981         string_malloced = 0;                                                  \
982         if (string == NULL)                                                   \
983           {                                                                   \
984             /* Write "(null)" if there's space.  */                           \
985             if (prec == -1                                                    \
986                 || prec >= (int) (sizeof (null) / sizeof (null[0])) - 1)      \
987               {                                                               \
988                 string = (CHAR_T *) null;                                     \
989                 len = (sizeof (null) / sizeof (null[0])) - 1;                 \
990               }                                                               \
991             else                                                              \
992               {                                                               \
993                 string = (CHAR_T *) L"";                                      \
994                 len = 0;                                                      \
995               }                                                               \
996           }                                                                   \
997         else if (!is_long && spec != L_('S'))                                 \
998           {                                                                   \
999             /* This is complicated.  We have to transform the multibyte       \
1000                string into a wide character string.  */                       \
1001             const char *mbs = (const char *) string;                          \
1002             mbstate_t mbstate;                                                \
1003                                                                               \
1004             len = prec != -1 ? (size_t) prec : strlen (mbs);                  \
1005                                                                               \
1006             /* Allocate dynamically an array which definitely is long         \
1007                enough for the wide character version.  */                     \
1008             if (__libc_use_alloca (len * sizeof (wchar_t)))                   \
1009               string = (CHAR_T *) alloca (len * sizeof (wchar_t));            \
1010             else if ((string = (CHAR_T *) malloc (len * sizeof (wchar_t)))    \
1011                      == NULL)                                                 \
1012               {                                                               \
1013                 done = -1;                                                    \
1014                 goto all_done;                                                \
1015               }                                                               \
1016             else                                                              \
1017               string_malloced = 1;                                            \
1018                                                                               \
1019             memset (&mbstate, '\0', sizeof (mbstate_t));                      \
1020             len = __mbsrtowcs (string, &mbs, len, &mbstate);                  \
1021             if (len == (size_t) -1)                                           \
1022               {                                                               \
1023                 /* Illegal multibyte character.  */                           \
1024                 done = -1;                                                    \
1025                 goto all_done;                                                \
1026               }                                                               \
1027           }                                                                   \
1028         else                                                                  \
1029           {                                                                   \
1030             if (prec != -1)                                                   \
1031               /* Search for the end of the string, but don't search past      \
1032                  the length specified by the precision.  */                   \
1033               len = __wcsnlen (string, prec);                                 \
1034             else                                                              \
1035               len = __wcslen (string);                                        \
1036           }                                                                   \
1037                                                                               \
1038         if ((width -= len) < 0)                                               \
1039           {                                                                   \
1040             outstring (string, len);                                          \
1041             break;                                                            \
1042           }                                                                   \
1043                                                                               \
1044         if (!left)                                                            \
1045           PAD (L' ');                                                         \
1046         outstring (string, len);                                              \
1047         if (left)                                                             \
1048           PAD (L' ');                                                         \
1049         if (__builtin_expect (string_malloced, 0))                            \
1050           free (string);                                                      \
1051       }                                                                       \
1052       break;
1053 #else
1054 # define process_string_arg(fspec) \
1055     LABEL (form_character):                                                   \
1056       /* Character.  */                                                       \
1057       if (is_long)                                                            \
1058         goto LABEL (form_wcharacter);                                         \
1059       --width;  /* Account for the character itself.  */                      \
1060       if (!left)                                                              \
1061         PAD (' ');                                                            \
1062       if (fspec == NULL)                                                      \
1063         outchar ((unsigned char) va_arg (ap, int)); /* Promoted.  */          \
1064       else                                                                    \
1065         outchar ((unsigned char) args_value[fspec->data_arg].pa_int);         \
1066       if (left)                                                               \
1067         PAD (' ');                                                            \
1068       break;                                                                  \
1069                                                                               \
1070     LABEL (form_wcharacter):                                                  \
1071       {                                                                       \
1072         /* Wide character.  */                                                \
1073         char buf[MB_CUR_MAX];                                                 \
1074         mbstate_t mbstate;                                                    \
1075         size_t len;                                                           \
1076                                                                               \
1077         memset (&mbstate, '\0', sizeof (mbstate_t));                          \
1078         len = __wcrtomb (buf, (fspec == NULL ? va_arg (ap, wchar_t)           \
1079                                : args_value[fspec->data_arg].pa_wchar),       \
1080                          &mbstate);                                           \
1081         if (len == (size_t) -1)                                               \
1082           {                                                                   \
1083             /* Something went wron gduring the conversion.  Bail out.  */     \
1084             done = -1;                                                        \
1085             goto all_done;                                                    \
1086           }                                                                   \
1087         width -= len;                                                         \
1088         if (!left)                                                            \
1089           PAD (' ');                                                          \
1090         outstring (buf, len);                                                 \
1091         if (left)                                                             \
1092           PAD (' ');                                                          \
1093       }                                                                       \
1094       break;                                                                  \
1095                                                                               \
1096     LABEL (form_string):                                                      \
1097       {                                                                       \
1098         size_t len;                                                           \
1099         int string_malloced;                                                  \
1100                                                                               \
1101         /* The string argument could in fact be `char *' or `wchar_t *'.      \
1102            But this should not make a difference here.  */                    \
1103         if (fspec == NULL)                                                    \
1104           string = (char *) va_arg (ap, const char *);                        \
1105         else                                                                  \
1106           string = (char *) args_value[fspec->data_arg].pa_string;            \
1107                                                                               \
1108         /* Entry point for printing other strings.  */                        \
1109       LABEL (print_string):                                                   \
1110                                                                               \
1111         string_malloced = 0;                                                  \
1112         if (string == NULL)                                                   \
1113           {                                                                   \
1114             /* Write "(null)" if there's space.  */                           \
1115             if (prec == -1 || prec >= (int) sizeof (null) - 1)                \
1116               {                                                               \
1117                 string = (char *) null;                                       \
1118                 len = sizeof (null) - 1;                                      \
1119               }                                                               \
1120             else                                                              \
1121               {                                                               \
1122                 string = (char *) "";                                         \
1123                 len = 0;                                                      \
1124               }                                                               \
1125           }                                                                   \
1126         else if (!is_long && spec != L_('S'))                                 \
1127           {                                                                   \
1128             if (prec != -1)                                                   \
1129               {                                                               \
1130                 /* Search for the end of the string, but don't search past    \
1131                    the length (in bytes) specified by the precision.  Also    \
1132                    don't use incomplete characters.  */                       \
1133                 if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX) == 1)   \
1134                   len = __strnlen (string, prec);                             \
1135                 else                                                          \
1136                   {                                                           \
1137                     /* In case we have a multibyte character set the          \
1138                        situation is more compilcated.  We must not copy       \
1139                        bytes at the end which form an incomplete character. */\
1140                     wchar_t ignore[prec];                                     \
1141                     const char *str2 = string;                                \
1142                     mbstate_t ps;                                             \
1143                                                                               \
1144                     memset (&ps, '\0', sizeof (ps));                          \
1145                     if (__mbsnrtowcs (ignore, &str2, prec, prec, &ps)         \
1146                         == (size_t) -1)                                       \
1147                       {                                                       \
1148                         done = -1;                                            \
1149                         goto all_done;                                        \
1150                       }                                                       \
1151                     if (str2 == NULL)                                         \
1152                       len = strlen (string);                                  \
1153                     else                                                      \
1154                       len = str2 - string - (ps.__count & 7);                 \
1155                   }                                                           \
1156               }                                                               \
1157             else                                                              \
1158               len = strlen (string);                                          \
1159           }                                                                   \
1160         else                                                                  \
1161           {                                                                   \
1162             const wchar_t *s2 = (const wchar_t *) string;                     \
1163             mbstate_t mbstate;                                                \
1164                                                                               \
1165             memset (&mbstate, '\0', sizeof (mbstate_t));                      \
1166                                                                               \
1167             if (prec >= 0)                                                    \
1168               {                                                               \
1169                 /* The string `s2' might not be NUL terminated.  */           \
1170                 if (__libc_use_alloca (prec))                                 \
1171                   string = (char *) alloca (prec);                            \
1172                 else if ((string = (char *) malloc (prec)) == NULL)           \
1173                   {                                                           \
1174                     done = -1;                                                \
1175                     goto all_done;                                            \
1176                   }                                                           \
1177                 else                                                          \
1178                   string_malloced = 1;                                        \
1179                 len = __wcsrtombs (string, &s2, prec, &mbstate);              \
1180               }                                                               \
1181             else                                                              \
1182               {                                                               \
1183                 len = __wcsrtombs (NULL, &s2, 0, &mbstate);                   \
1184                 if (len != (size_t) -1)                                       \
1185                   {                                                           \
1186                     assert (__mbsinit (&mbstate));                            \
1187                     s2 = (const wchar_t *) string;                            \
1188                     if (__libc_use_alloca (len + 1))                          \
1189                       string = (char *) alloca (len + 1);                     \
1190                     else if ((string = (char *) malloc (len + 1)) == NULL)    \
1191                       {                                                       \
1192                         done = -1;                                            \
1193                         goto all_done;                                        \
1194                       }                                                       \
1195                     else                                                      \
1196                       string_malloced = 1;                                    \
1197                     (void) __wcsrtombs (string, &s2, len + 1, &mbstate);      \
1198                   }                                                           \
1199               }                                                               \
1200                                                                               \
1201             if (len == (size_t) -1)                                           \
1202               {                                                               \
1203                 /* Illegal wide-character string.  */                         \
1204                 done = -1;                                                    \
1205                 goto all_done;                                                \
1206               }                                                               \
1207           }                                                                   \
1208                                                                               \
1209         if ((width -= len) < 0)                                               \
1210           {                                                                   \
1211             outstring (string, len);                                          \
1212             break;                                                            \
1213           }                                                                   \
1214                                                                               \
1215         if (!left)                                                            \
1216           PAD (' ');                                                          \
1217         outstring (string, len);                                              \
1218         if (left)                                                             \
1219           PAD (' ');                                                          \
1220         if (__builtin_expect (string_malloced, 0))                            \
1221           free (string);                                                      \
1222       }                                                                       \
1223       break;
1224 #endif
1225
1226   /* Orient the stream.  */
1227 #ifdef ORIENT
1228   ORIENT;
1229 #endif
1230
1231   /* Sanity check of arguments.  */
1232   ARGCHECK (s, format);
1233
1234 #ifdef ORIENT
1235   /* Check for correct orientation.  */
1236   if (_IO_vtable_offset (s) == 0 &&
1237       _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
1238       != (sizeof (CHAR_T) == 1 ? -1 : 1))
1239     /* The stream is already oriented otherwise.  */
1240     return EOF;
1241 #endif
1242
1243   if (UNBUFFERED_P (s))
1244     /* Use a helper function which will allocate a local temporary buffer
1245        for the stream and then call us again.  */
1246     return buffered_vfprintf (s, format, ap);
1247
1248   /* Initialize local variables.  */
1249   done = 0;
1250   grouping = (const char *) -1;
1251 #ifdef __va_copy
1252   /* This macro will be available soon in gcc's <stdarg.h>.  We need it
1253      since on some systems `va_list' is not an integral type.  */
1254   __va_copy (ap_save, ap);
1255 #else
1256   ap_save = ap;
1257 #endif
1258   nspecs_done = 0;
1259
1260 #ifdef COMPILE_WPRINTF
1261   /* Find the first format specifier.  */
1262   f = lead_str_end = __find_specwc ((const UCHAR_T *) format);
1263 #else
1264   /* Put state for processing format string in initial state.  */
1265   memset (&mbstate, '\0', sizeof (mbstate_t));
1266
1267   /* Find the first format specifier.  */
1268   f = lead_str_end = __find_specmb (format, &mbstate);
1269 #endif
1270
1271   /* Lock stream.  */
1272   _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
1273   _IO_flockfile (s);
1274
1275   /* Write the literal text before the first format.  */
1276   outstring ((const UCHAR_T *) format,
1277              lead_str_end - (const UCHAR_T *) format);
1278
1279   /* If we only have to print a simple string, return now.  */
1280   if (*f == L_('\0'))
1281     goto all_done;
1282
1283   /* Process whole format string.  */
1284   do
1285     {
1286 #if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED
1287 # define REF(Name) &&do_##Name - &&do_form_unknown
1288 #else
1289 # define REF(Name) &&do_##Name
1290 #endif
1291 #define LABEL(Name) do_##Name
1292       STEP0_3_TABLE;
1293       STEP4_TABLE;
1294
1295       union printf_arg *args_value;     /* This is not used here but ... */
1296       int is_negative;  /* Flag for negative number.  */
1297       union
1298       {
1299         unsigned long long int longlong;
1300         unsigned long int word;
1301       } number;
1302       int base;
1303       union printf_arg the_arg;
1304       CHAR_T *string;   /* Pointer to argument string.  */
1305       int alt = 0;      /* Alternate format.  */
1306       int space = 0;    /* Use space prefix if no sign is needed.  */
1307       int left = 0;     /* Left-justify output.  */
1308       int showsign = 0; /* Always begin with plus or minus sign.  */
1309       int group = 0;    /* Print numbers according grouping rules.  */
1310       int is_long_double = 0; /* Argument is long double/ long long int.  */
1311       int is_short = 0; /* Argument is short int.  */
1312       int is_long = 0;  /* Argument is long int.  */
1313       int is_char = 0;  /* Argument is promoted (unsigned) char.  */
1314       int width = 0;    /* Width of output; 0 means none specified.  */
1315       int prec = -1;    /* Precision of output; -1 means none specified.  */
1316       /* This flag is set by the 'I' modifier and selects the use of the
1317          `outdigits' as determined by the current locale.  */
1318       int use_outdigits = 0;
1319       UCHAR_T pad = L_(' ');/* Padding character.  */
1320       CHAR_T spec;
1321
1322       workstart = NULL;
1323       workend = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
1324
1325       /* Get current character in format string.  */
1326       JUMP (*++f, step0_jumps);
1327
1328       /* ' ' flag.  */
1329     LABEL (flag_space):
1330       space = 1;
1331       JUMP (*++f, step0_jumps);
1332
1333       /* '+' flag.  */
1334     LABEL (flag_plus):
1335       showsign = 1;
1336       JUMP (*++f, step0_jumps);
1337
1338       /* The '-' flag.  */
1339     LABEL (flag_minus):
1340       left = 1;
1341       pad = L_(' ');
1342       JUMP (*++f, step0_jumps);
1343
1344       /* The '#' flag.  */
1345     LABEL (flag_hash):
1346       alt = 1;
1347       JUMP (*++f, step0_jumps);
1348
1349       /* The '0' flag.  */
1350     LABEL (flag_zero):
1351       if (!left)
1352         pad = L_('0');
1353       JUMP (*++f, step0_jumps);
1354
1355       /* The '\'' flag.  */
1356     LABEL (flag_quote):
1357       group = 1;
1358
1359       if (grouping == (const char *) -1)
1360         {
1361 #ifdef COMPILE_WPRINTF
1362           thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
1363                                             _NL_NUMERIC_THOUSANDS_SEP_WC);
1364 #else
1365           thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
1366 #endif
1367
1368           grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1369           if (*grouping == '\0' || *grouping == CHAR_MAX
1370 #ifdef COMPILE_WPRINTF
1371               || thousands_sep == L'\0'
1372 #else
1373               || *thousands_sep == '\0'
1374 #endif
1375               )
1376             grouping = NULL;
1377         }
1378       JUMP (*++f, step0_jumps);
1379
1380     LABEL (flag_i18n):
1381       use_outdigits = 1;
1382       JUMP (*++f, step0_jumps);
1383
1384       /* Get width from argument.  */
1385     LABEL (width_asterics):
1386       {
1387         const UCHAR_T *tmp;     /* Temporary value.  */
1388
1389         tmp = ++f;
1390         if (ISDIGIT (*tmp) && read_int (&tmp) && *tmp == L_('$'))
1391           /* The width comes from a positional parameter.  */
1392           goto do_positional;
1393
1394         width = va_arg (ap, int);
1395
1396         /* Negative width means left justified.  */
1397         if (width < 0)
1398           {
1399             width = -width;
1400             pad = L_(' ');
1401             left = 1;
1402           }
1403
1404         if (width + 32 >= (int) (sizeof (work_buffer)
1405                                  / sizeof (work_buffer[0])))
1406           {
1407             /* We have to use a special buffer.  The "32" is just a safe
1408                bet for all the output which is not counted in the width.  */
1409             if (__libc_use_alloca ((width + 32) * sizeof (CHAR_T)))
1410               workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
1411                          + (width + 32));
1412             else
1413               {
1414                 workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T));
1415                 if (workstart == NULL)
1416                   {
1417                     done = -1;
1418                     goto all_done;
1419                   }
1420                 workend = workstart + (width + 32);
1421               }
1422           }
1423       }
1424       JUMP (*f, step1_jumps);
1425
1426       /* Given width in format string.  */
1427     LABEL (width):
1428       width = read_int (&f);
1429
1430       if (width + 32 >= (int) (sizeof (work_buffer) / sizeof (work_buffer[0])))
1431         {
1432           /* We have to use a special buffer.  The "32" is just a safe
1433              bet for all the output which is not counted in the width.  */
1434           if (__libc_use_alloca ((width + 32) * sizeof (CHAR_T)))
1435             workend = ((CHAR_T *) alloca ((width + 32) * sizeof (CHAR_T))
1436                        + (width + 32));
1437           else
1438             {
1439               workstart = (CHAR_T *) malloc ((width + 32) * sizeof (CHAR_T));
1440               if (workstart == NULL)
1441                 {
1442                   done = -1;
1443                   goto all_done;
1444                 }
1445               workend = workstart + (width + 32);
1446             }
1447         }
1448       if (*f == L_('$'))
1449         /* Oh, oh.  The argument comes from a positional parameter.  */
1450         goto do_positional;
1451       JUMP (*f, step1_jumps);
1452
1453     LABEL (precision):
1454       ++f;
1455       if (*f == L_('*'))
1456         {
1457           const UCHAR_T *tmp;   /* Temporary value.  */
1458
1459           tmp = ++f;
1460           if (ISDIGIT (*tmp) && read_int (&tmp) > 0 && *tmp == L_('$'))
1461             /* The precision comes from a positional parameter.  */
1462             goto do_positional;
1463
1464           prec = va_arg (ap, int);
1465
1466           /* If the precision is negative the precision is omitted.  */
1467           if (prec < 0)
1468             prec = -1;
1469         }
1470       else if (ISDIGIT (*f))
1471         prec = read_int (&f);
1472       else
1473         prec = 0;
1474       if (prec > width
1475           && prec + 32 > (int)(sizeof (work_buffer) / sizeof (work_buffer[0])))
1476         {
1477           if (__libc_use_alloca ((prec + 32) * sizeof (CHAR_T)))
1478             workend = ((CHAR_T *) alloca ((prec + 32) * sizeof (CHAR_T)))
1479                       + (prec + 32);
1480           else
1481             {
1482               workstart = (CHAR_T *) malloc ((prec + 32) * sizeof (CHAR_T));
1483               if (workstart == NULL)
1484                 {
1485                   done = -1;
1486                   goto all_done;
1487                 }
1488               workend = workstart + (prec + 32);
1489             }
1490         }
1491       JUMP (*f, step2_jumps);
1492
1493       /* Process 'h' modifier.  There might another 'h' following.  */
1494     LABEL (mod_half):
1495       is_short = 1;
1496       JUMP (*++f, step3a_jumps);
1497
1498       /* Process 'hh' modifier.  */
1499     LABEL (mod_halfhalf):
1500       is_short = 0;
1501       is_char = 1;
1502       JUMP (*++f, step4_jumps);
1503
1504       /* Process 'l' modifier.  There might another 'l' following.  */
1505     LABEL (mod_long):
1506       is_long = 1;
1507       JUMP (*++f, step3b_jumps);
1508
1509       /* Process 'L', 'q', or 'll' modifier.  No other modifier is
1510          allowed to follow.  */
1511     LABEL (mod_longlong):
1512       is_long_double = 1;
1513       is_long = 1;
1514       JUMP (*++f, step4_jumps);
1515
1516     LABEL (mod_size_t):
1517       is_long_double = sizeof (size_t) > sizeof (unsigned long int);
1518       is_long = sizeof (size_t) > sizeof (unsigned int);
1519       JUMP (*++f, step4_jumps);
1520
1521     LABEL (mod_ptrdiff_t):
1522       is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);
1523       is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
1524       JUMP (*++f, step4_jumps);
1525
1526     LABEL (mod_intmax_t):
1527       is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);
1528       is_long = sizeof (intmax_t) > sizeof (unsigned int);
1529       JUMP (*++f, step4_jumps);
1530
1531       /* Process current format.  */
1532       while (1)
1533         {
1534           process_arg (((struct printf_spec *) NULL));
1535           process_string_arg (((struct printf_spec *) NULL));
1536
1537         LABEL (form_unknown):
1538           if (spec == L_('\0'))
1539             {
1540               /* The format string ended before the specifier is complete.  */
1541               done = -1;
1542               goto all_done;
1543             }
1544
1545           /* If we are in the fast loop force entering the complicated
1546              one.  */
1547           goto do_positional;
1548         }
1549
1550       /* The format is correctly handled.  */
1551       ++nspecs_done;
1552
1553       if (__builtin_expect (workstart != NULL, 0))
1554         free (workstart);
1555       workstart = NULL;
1556
1557       /* Look for next format specifier.  */
1558 #ifdef COMPILE_WPRINTF
1559       f = __find_specwc ((end_of_spec = ++f));
1560 #else
1561       f = __find_specmb ((end_of_spec = ++f), &mbstate);
1562 #endif
1563
1564       /* Write the following constant string.  */
1565       outstring (end_of_spec, f - end_of_spec);
1566     }
1567   while (*f != L_('\0'));
1568
1569   /* Unlock stream and return.  */
1570   goto all_done;
1571
1572   /* Here starts the more complex loop to handle positional parameters.  */
1573 do_positional:
1574   {
1575     /* Array with information about the needed arguments.  This has to
1576        be dynamically extensible.  */
1577     size_t nspecs = 0;
1578     size_t nspecs_max = 32;     /* A more or less arbitrary start value.  */
1579     struct printf_spec *specs
1580       = alloca (nspecs_max * sizeof (struct printf_spec));
1581
1582     /* The number of arguments the format string requests.  This will
1583        determine the size of the array needed to store the argument
1584        attributes.  */
1585     size_t nargs = 0;
1586     int *args_type;
1587     union printf_arg *args_value = NULL;
1588
1589     /* Positional parameters refer to arguments directly.  This could
1590        also determine the maximum number of arguments.  Track the
1591        maximum number.  */
1592     size_t max_ref_arg = 0;
1593
1594     /* Just a counter.  */
1595     size_t cnt;
1596
1597
1598     if (grouping == (const char *) -1)
1599       {
1600 #ifdef COMPILE_WPRINTF
1601         thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
1602                                           _NL_NUMERIC_THOUSANDS_SEP_WC);
1603 #else
1604         thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
1605 #endif
1606
1607         grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1608         if (*grouping == '\0' || *grouping == CHAR_MAX)
1609           grouping = NULL;
1610       }
1611
1612     for (f = lead_str_end; *f != L_('\0'); f = specs[nspecs++].next_fmt)
1613       {
1614         if (nspecs >= nspecs_max)
1615           {
1616             /* Extend the array of format specifiers.  */
1617             struct printf_spec *old = specs;
1618
1619             nspecs_max *= 2;
1620             specs = alloca (nspecs_max * sizeof (struct printf_spec));
1621
1622             if (specs == &old[nspecs])
1623               /* Stack grows up, OLD was the last thing allocated;
1624                  extend it.  */
1625               nspecs_max += nspecs_max / 2;
1626             else
1627               {
1628                 /* Copy the old array's elements to the new space.  */
1629                 memcpy (specs, old, nspecs * sizeof (struct printf_spec));
1630                 if (old == &specs[nspecs])
1631                   /* Stack grows down, OLD was just below the new
1632                      SPECS.  We can use that space when the new space
1633                      runs out.  */
1634                   nspecs_max += nspecs_max / 2;
1635               }
1636           }
1637
1638         /* Parse the format specifier.  */
1639 #ifdef COMPILE_WPRINTF
1640         nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
1641 #else
1642         nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg,
1643                                      &mbstate);
1644 #endif
1645       }
1646
1647     /* Determine the number of arguments the format string consumes.  */
1648     nargs = MAX (nargs, max_ref_arg);
1649
1650     /* Allocate memory for the argument descriptions.  */
1651     args_type = alloca (nargs * sizeof (int));
1652     memset (args_type, 0, nargs * sizeof (int));
1653     args_value = alloca (nargs * sizeof (union printf_arg));
1654
1655     /* XXX Could do sanity check here: If any element in ARGS_TYPE is
1656        still zero after this loop, format is invalid.  For now we
1657        simply use 0 as the value.  */
1658
1659     /* Fill in the types of all the arguments.  */
1660     for (cnt = 0; cnt < nspecs; ++cnt)
1661       {
1662         /* If the width is determined by an argument this is an int.  */
1663         if (specs[cnt].width_arg != -1)
1664           args_type[specs[cnt].width_arg] = PA_INT;
1665
1666         /* If the precision is determined by an argument this is an int.  */
1667         if (specs[cnt].prec_arg != -1)
1668           args_type[specs[cnt].prec_arg] = PA_INT;
1669
1670         switch (specs[cnt].ndata_args)
1671           {
1672           case 0:               /* No arguments.  */
1673             break;
1674           case 1:               /* One argument; we already have the type.  */
1675             args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
1676             break;
1677           default:
1678             /* We have more than one argument for this format spec.
1679                We must call the arginfo function again to determine
1680                all the types.  */
1681             (void) (*__printf_arginfo_table[specs[cnt].info.spec])
1682               (&specs[cnt].info,
1683                specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]);
1684             break;
1685           }
1686       }
1687
1688     /* Now we know all the types and the order.  Fill in the argument
1689        values.  */
1690     for (cnt = 0; cnt < nargs; ++cnt)
1691       switch (args_type[cnt])
1692         {
1693 #define T(tag, mem, type)                                                     \
1694         case tag:                                                             \
1695           args_value[cnt].mem = va_arg (ap_save, type);                       \
1696           break
1697
1698         T (PA_CHAR, pa_int, int); /* Promoted.  */
1699         T (PA_WCHAR, pa_wchar, wint_t);
1700         T (PA_INT|PA_FLAG_SHORT, pa_int, int); /* Promoted.  */
1701         T (PA_INT, pa_int, int);
1702         T (PA_INT|PA_FLAG_LONG, pa_long_int, long int);
1703         T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
1704         T (PA_FLOAT, pa_double, double);        /* Promoted.  */
1705         T (PA_DOUBLE, pa_double, double);
1706         T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double);
1707         T (PA_STRING, pa_string, const char *);
1708         T (PA_WSTRING, pa_wstring, const wchar_t *);
1709         T (PA_POINTER, pa_pointer, void *);
1710 #undef T
1711         default:
1712           if ((args_type[cnt] & PA_FLAG_PTR) != 0)
1713             args_value[cnt].pa_pointer = va_arg (ap_save, void *);
1714           else
1715             args_value[cnt].pa_long_double = 0.0;
1716           break;
1717         }
1718
1719     /* Now walk through all format specifiers and process them.  */
1720     for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
1721       {
1722 #undef REF
1723 #if defined HAVE_SUBTRACT_LOCAL_LABELS && defined SHARED
1724 # define REF(Name) &&do2_##Name - &&do_form_unknown
1725 #else
1726 # define REF(Name) &&do2_##Name
1727 #endif
1728 #undef LABEL
1729 #define LABEL(Name) do2_##Name
1730         STEP4_TABLE;
1731
1732         int is_negative;
1733         union
1734         {
1735           unsigned long long int longlong;
1736           unsigned long int word;
1737         } number;
1738         int base;
1739         union printf_arg the_arg;
1740         CHAR_T *string;         /* Pointer to argument string.  */
1741
1742         /* Fill variables from values in struct.  */
1743         int alt = specs[nspecs_done].info.alt;
1744         int space = specs[nspecs_done].info.space;
1745         int left = specs[nspecs_done].info.left;
1746         int showsign = specs[nspecs_done].info.showsign;
1747         int group = specs[nspecs_done].info.group;
1748         int is_long_double = specs[nspecs_done].info.is_long_double;
1749         int is_short = specs[nspecs_done].info.is_short;
1750         int is_char = specs[nspecs_done].info.is_char;
1751         int is_long = specs[nspecs_done].info.is_long;
1752         int width = specs[nspecs_done].info.width;
1753         int prec = specs[nspecs_done].info.prec;
1754         int use_outdigits = specs[nspecs_done].info.i18n;
1755         char pad = specs[nspecs_done].info.pad;
1756         CHAR_T spec = specs[nspecs_done].info.spec;
1757         CHAR_T *workstart = NULL;
1758
1759         /* Fill in last information.  */
1760         if (specs[nspecs_done].width_arg != -1)
1761           {
1762             /* Extract the field width from an argument.  */
1763             specs[nspecs_done].info.width =
1764               args_value[specs[nspecs_done].width_arg].pa_int;
1765
1766             if (specs[nspecs_done].info.width < 0)
1767               /* If the width value is negative left justification is
1768                  selected and the value is taken as being positive.  */
1769               {
1770                 specs[nspecs_done].info.width *= -1;
1771                 left = specs[nspecs_done].info.left = 1;
1772               }
1773             width = specs[nspecs_done].info.width;
1774           }
1775
1776         if (specs[nspecs_done].prec_arg != -1)
1777           {
1778             /* Extract the precision from an argument.  */
1779             specs[nspecs_done].info.prec =
1780               args_value[specs[nspecs_done].prec_arg].pa_int;
1781
1782             if (specs[nspecs_done].info.prec < 0)
1783               /* If the precision is negative the precision is
1784                  omitted.  */
1785               specs[nspecs_done].info.prec = -1;
1786
1787             prec = specs[nspecs_done].info.prec;
1788           }
1789
1790         /* Maybe the buffer is too small.  */
1791         if (MAX (prec, width) + 32 > (int) (sizeof (work_buffer)
1792                                             / sizeof (CHAR_T)))
1793           {
1794             if (__libc_use_alloca ((MAX (prec, width) + 32)
1795                                    * sizeof (CHAR_T)))
1796               workend = ((CHAR_T *) alloca ((MAX (prec, width) + 32)
1797                                             * sizeof (CHAR_T))
1798                          + (MAX (prec, width) + 32));
1799             else
1800               {
1801                 workstart = (CHAR_T *) malloc ((MAX (prec, width) + 32)
1802                                                * sizeof (CHAR_T));
1803                 workend = workstart + (MAX (prec, width) + 32);
1804               }
1805           }
1806
1807         /* Process format specifiers.  */
1808         while (1)
1809           {
1810             JUMP (spec, step4_jumps);
1811
1812             process_arg ((&specs[nspecs_done]));
1813             process_string_arg ((&specs[nspecs_done]));
1814
1815           LABEL (form_unknown):
1816             {
1817               extern printf_function **__printf_function_table;
1818               int function_done;
1819               printf_function *function;
1820               unsigned int i;
1821               const void **ptr;
1822
1823               function =
1824                 (__printf_function_table == NULL ? NULL :
1825                  __printf_function_table[specs[nspecs_done].info.spec]);
1826
1827               if (function == NULL)
1828                 function = &printf_unknown;
1829
1830               ptr = alloca (specs[nspecs_done].ndata_args
1831                             * sizeof (const void *));
1832
1833               /* Fill in an array of pointers to the argument values.  */
1834               for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
1835                 ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
1836
1837               /* Call the function.  */
1838               function_done = (*function) (s, &specs[nspecs_done].info, ptr);
1839
1840               /* If an error occurred we don't have information about #
1841                  of chars.  */
1842               if (function_done < 0)
1843                 {
1844                   done = -1;
1845                   goto all_done;
1846                 }
1847
1848               done += function_done;
1849             }
1850             break;
1851           }
1852
1853         if (__builtin_expect (workstart != NULL, 0))
1854           free (workstart);
1855         workstart = NULL;
1856
1857         /* Write the following constant string.  */
1858         outstring (specs[nspecs_done].end_of_fmt,
1859                    specs[nspecs_done].next_fmt
1860                    - specs[nspecs_done].end_of_fmt);
1861       }
1862   }
1863
1864 all_done:
1865   if (__builtin_expect (workstart != NULL, 0))
1866     free (workstart);
1867   /* Unlock the stream.  */
1868   _IO_funlockfile (s);
1869   _IO_cleanup_region_end (0);
1870
1871   return done;
1872 }
1873 \f
1874 /* Handle an unknown format specifier.  This prints out a canonicalized
1875    representation of the format spec itself.  */
1876 static int
1877 printf_unknown (FILE *s, const struct printf_info *info,
1878                 const void *const *args)
1879
1880 {
1881   int done = 0;
1882   CHAR_T work_buffer[MAX (info->width, info->spec) + 32];
1883   CHAR_T *const workend
1884     = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
1885   register CHAR_T *w;
1886
1887   outchar (L_('%'));
1888
1889   if (info->alt)
1890     outchar (L_('#'));
1891   if (info->group)
1892     outchar (L_('\''));
1893   if (info->showsign)
1894     outchar (L_('+'));
1895   else if (info->space)
1896     outchar (L_(' '));
1897   if (info->left)
1898     outchar (L_('-'));
1899   if (info->pad == L_('0'))
1900     outchar (L_('0'));
1901   if (info->i18n)
1902     outchar (L_('I'));
1903
1904   if (info->width != 0)
1905     {
1906       w = _itoa_word (info->width, workend, 10, 0);
1907       while (w < workend)
1908         outchar (*w++);
1909     }
1910
1911   if (info->prec != -1)
1912     {
1913       outchar (L_('.'));
1914       w = _itoa_word (info->prec, workend, 10, 0);
1915       while (w < workend)
1916         outchar (*w++);
1917     }
1918
1919   if (info->spec != L_('\0'))
1920     outchar (info->spec);
1921
1922  all_done:
1923   return done;
1924 }
1925 \f
1926 /* Group the digits according to the grouping rules of the current locale.
1927    The interpretation of GROUPING is as in `struct lconv' from <locale.h>.  */
1928 static CHAR_T *
1929 internal_function
1930 group_number (CHAR_T *w, CHAR_T *rear_ptr, const char *grouping,
1931 #ifdef COMPILE_WPRINTF
1932               wchar_t thousands_sep
1933 #else
1934               const char *thousands_sep
1935 #endif
1936               )
1937 {
1938   int len;
1939   CHAR_T *src, *s;
1940 #ifndef COMPILE_WPRINTF
1941   int tlen = strlen (thousands_sep);
1942 #endif
1943
1944   /* We treat all negative values like CHAR_MAX.  */
1945
1946   if (*grouping == CHAR_MAX || *grouping <= 0)
1947     /* No grouping should be done.  */
1948     return w;
1949
1950   len = *grouping++;
1951
1952   /* Copy existing string so that nothing gets overwritten.  */
1953   src = (CHAR_T *) alloca ((rear_ptr - w) * sizeof (CHAR_T));
1954   s = (CHAR_T *) __mempcpy (src, w,
1955                             (rear_ptr - w) * sizeof (CHAR_T));
1956   w = rear_ptr;
1957
1958   /* Process all characters in the string.  */
1959   while (s > src)
1960     {
1961       *--w = *--s;
1962
1963       if (--len == 0 && s > src)
1964         {
1965           /* A new group begins.  */
1966 #ifdef COMPILE_WPRINTF
1967           *--w = thousands_sep;
1968 #else
1969           int cnt = tlen;
1970           do
1971             *--w = thousands_sep[--cnt];
1972           while (cnt > 0);
1973 #endif
1974
1975           if (*grouping == CHAR_MAX
1976 #if CHAR_MIN < 0
1977                    || *grouping < 0
1978 #endif
1979                    )
1980             {
1981               /* No further grouping to be done.
1982                  Copy the rest of the number.  */
1983               do
1984                 *--w = *--s;
1985               while (s > src);
1986               break;
1987             }
1988           else if (*grouping != '\0')
1989             /* The previous grouping repeats ad infinitum.  */
1990             len = *grouping++;
1991           else
1992             len = grouping[-1];
1993         }
1994     }
1995   return w;
1996 }
1997 \f
1998 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
1999 struct helper_file
2000   {
2001     struct _IO_FILE_plus _f;
2002 #ifdef COMPILE_WPRINTF
2003     struct _IO_wide_data _wide_data;
2004 #endif
2005     _IO_FILE *_put_stream;
2006 #ifdef _IO_MTSAFE_IO
2007     _IO_lock_t lock;
2008 #endif
2009   };
2010
2011 static int
2012 _IO_helper_overflow (_IO_FILE *s, int c)
2013 {
2014   _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
2015 #ifdef COMPILE_WPRINTF
2016   int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
2017   if (used)
2018     {
2019       _IO_size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base,
2020                                       used);
2021       s->_wide_data->_IO_write_ptr -= written;
2022     }
2023 #else
2024   int used = s->_IO_write_ptr - s->_IO_write_base;
2025   if (used)
2026     {
2027       _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
2028       s->_IO_write_ptr -= written;
2029     }
2030 #endif
2031   return PUTC (c, s);
2032 }
2033
2034 #ifdef COMPILE_WPRINTF
2035 static const struct _IO_jump_t _IO_helper_jumps =
2036 {
2037   JUMP_INIT_DUMMY,
2038   JUMP_INIT (finish, INTUSE(_IO_wdefault_finish)),
2039   JUMP_INIT (overflow, _IO_helper_overflow),
2040   JUMP_INIT (underflow, _IO_default_underflow),
2041   JUMP_INIT (uflow, INTUSE(_IO_default_uflow)),
2042   JUMP_INIT (pbackfail, (_IO_pbackfail_t) INTUSE(_IO_wdefault_pbackfail)),
2043   JUMP_INIT (xsputn, INTUSE(_IO_wdefault_xsputn)),
2044   JUMP_INIT (xsgetn, INTUSE(_IO_wdefault_xsgetn)),
2045   JUMP_INIT (seekoff, _IO_default_seekoff),
2046   JUMP_INIT (seekpos, _IO_default_seekpos),
2047   JUMP_INIT (setbuf, _IO_default_setbuf),
2048   JUMP_INIT (sync, _IO_default_sync),
2049   JUMP_INIT (doallocate, INTUSE(_IO_wdefault_doallocate)),
2050   JUMP_INIT (read, _IO_default_read),
2051   JUMP_INIT (write, _IO_default_write),
2052   JUMP_INIT (seek, _IO_default_seek),
2053   JUMP_INIT (close, _IO_default_close),
2054   JUMP_INIT (stat, _IO_default_stat)
2055 };
2056 #else
2057 static const struct _IO_jump_t _IO_helper_jumps =
2058 {
2059   JUMP_INIT_DUMMY,
2060   JUMP_INIT (finish, INTUSE(_IO_default_finish)),
2061   JUMP_INIT (overflow, _IO_helper_overflow),
2062   JUMP_INIT (underflow, _IO_default_underflow),
2063   JUMP_INIT (uflow, INTUSE(_IO_default_uflow)),
2064   JUMP_INIT (pbackfail, INTUSE(_IO_default_pbackfail)),
2065   JUMP_INIT (xsputn, INTUSE(_IO_default_xsputn)),
2066   JUMP_INIT (xsgetn, INTUSE(_IO_default_xsgetn)),
2067   JUMP_INIT (seekoff, _IO_default_seekoff),
2068   JUMP_INIT (seekpos, _IO_default_seekpos),
2069   JUMP_INIT (setbuf, _IO_default_setbuf),
2070   JUMP_INIT (sync, _IO_default_sync),
2071   JUMP_INIT (doallocate, INTUSE(_IO_default_doallocate)),
2072   JUMP_INIT (read, _IO_default_read),
2073   JUMP_INIT (write, _IO_default_write),
2074   JUMP_INIT (seek, _IO_default_seek),
2075   JUMP_INIT (close, _IO_default_close),
2076   JUMP_INIT (stat, _IO_default_stat)
2077 };
2078 #endif
2079
2080 static int
2081 internal_function
2082 buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format,
2083                    _IO_va_list args)
2084 {
2085   CHAR_T buf[_IO_BUFSIZ];
2086   struct helper_file helper;
2087   register _IO_FILE *hp = (_IO_FILE *) &helper._f;
2088   int result, to_flush;
2089
2090   /* Orient the stream.  */
2091 #ifdef ORIENT
2092   ORIENT;
2093 #endif
2094
2095   /* Initialize helper.  */
2096   helper._put_stream = s;
2097 #ifdef COMPILE_WPRINTF
2098   hp->_wide_data = &helper._wide_data;
2099   _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
2100   hp->_mode = 1;
2101 #else
2102   _IO_setp (hp, buf, buf + sizeof buf);
2103   hp->_mode = -1;
2104 #endif
2105   hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK;
2106 #if _IO_JUMPS_OFFSET
2107   hp->_vtable_offset = 0;
2108 #endif
2109 #ifdef _IO_MTSAFE_IO
2110   hp->_lock = NULL;
2111 #endif
2112   hp->_flags2 = s->_flags2;
2113   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
2114
2115   /* Now print to helper instead.  */
2116 #ifndef COMPILE_WPRINTF
2117   result = INTUSE(_IO_vfprintf) (hp, format, args);
2118 #else
2119   result = vfprintf (hp, format, args);
2120 #endif
2121
2122   /* Lock stream.  */
2123   __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
2124   _IO_flockfile (s);
2125
2126   /* Now flush anything from the helper to the S. */
2127 #ifdef COMPILE_WPRINTF
2128   if ((to_flush = (hp->_wide_data->_IO_write_ptr
2129                    - hp->_wide_data->_IO_write_base)) > 0)
2130     {
2131       if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
2132           != to_flush)
2133         result = -1;
2134     }
2135 #else
2136   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
2137     {
2138       if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
2139         result = -1;
2140     }
2141 #endif
2142
2143   /* Unlock the stream.  */
2144   _IO_funlockfile (s);
2145   __libc_cleanup_region_end (0);
2146
2147   return result;
2148 }
2149
2150 #undef vfprintf
2151 #ifdef strong_alias
2152 /* This is for glibc.  */
2153 # ifdef COMPILE_WPRINTF
2154 strong_alias (_IO_vfwprintf, __vfwprintf);
2155 weak_alias (_IO_vfwprintf, vfwprintf);
2156 # else
2157 strong_alias (_IO_vfprintf, vfprintf);
2158 libc_hidden_def (vfprintf)
2159 INTDEF(_IO_vfprintf)
2160 # endif
2161 #else
2162 # if defined __ELF__ || defined __GNU_LIBRARY__
2163 #  include <gnu-stabs.h>
2164 #  ifdef weak_alias
2165 #   ifdef COMPILE_WPRINTF
2166 weak_alias (_IO_vfwprintf, vfwprintf);
2167 #   else
2168 weak_alias (_IO_vfprintf, vfprintf);
2169 #   endif
2170 #  endif
2171 # endif
2172 #endif