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