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