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