Include <string.h>.
[kopensolaris-gnu/glibc.git] / stdio-common / vfprintf.c
1 /* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 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 Library General Public License as
6    published by the Free Software Foundation; either version 2 of the
7    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    Library General Public License for more details.
13
14    You should have received a copy of the GNU Library General Public
15    License along with the GNU C Library; see the file COPYING.LIB.  If not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <ctype.h>
20 #include <limits.h>
21 #include <printf.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <wchar.h>
26 #include <libc-lock.h>
27 #include <sys/param.h>
28 #include "_itoa.h"
29 #include "../locale/localeinfo.h"
30
31 /* This code is shared between the standard stdio implementation found
32    in GNU C library and the libio implementation originally found in
33    GNU libg++.
34
35    Beside this it is also shared between the normal and wide character
36    implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995.  */
37
38 #ifndef COMPILE_WPRINTF
39 # define CHAR_T         char
40 # define UCHAR_T        unsigned char
41 # define INT_T          int
42 # define L_(Str)        Str
43 # define ISDIGIT(Ch)    isdigit (Ch)
44
45 # ifdef USE_IN_LIBIO
46 #  define PUT(F, S, N)  _IO_sputn ((F), (S), (N))
47 #  define PAD(Padchar)                                                        \
48   if (width > 0)                                                              \
49     done += _IO_padn (s, (Padchar), width)
50 # else
51 #  define PUTC(C, F)    putc (C, F)
52 ssize_t __printf_pad __P ((FILE *, char pad, size_t n));
53 # define PAD(Padchar)                                                         \
54   if (width > 0)                                                              \
55     { ssize_t __res = __printf_pad (s, (Padchar), width);                     \
56       if (__res == -1) return -1;                                             \
57       done += __res; }
58 # endif
59 #else
60 # define vfprintf       vfwprintf
61 # define CHAR_T         wchar_t
62 # define UCHAR_T        uwchar_t
63 # define INT_T          wint_t
64 # define L_(Str)        L##Str
65 # define ISDIGIT(Ch)    iswdigit (Ch)
66
67 # ifdef USE_IN_LIBIO
68 #  define PUT(F, S, N)  _IO_sputn ((F), (S), (N))
69 #  define PAD(Padchar)                                                        \
70   if (width > 0)                                                              \
71     done += _IO_wpadn (s, (Padchar), width)
72 # else
73 #  define PUTC(C, F)    wputc (C, F)
74 ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n));
75 #  define PAD(Padchar)                                                        \
76   if (width > 0)                                                              \
77     { ssize_t __res = __wprintf_pad (s, (Padchar), width);                    \
78       if (__res == -1) return -1;                                             \
79       done += __res; }
80 # endif
81 #endif
82
83 /* Include the shared code for parsing the format string.  */
84 #include "printf-parse.h"
85
86
87 #ifdef USE_IN_LIBIO
88 /* This code is for use in libio.  */
89 # include <libioP.h>
90 # define PUTC(C, F)     _IO_putc_unlocked (C, F)
91 # define vfprintf       _IO_vfprintf
92 # define FILE           _IO_FILE
93 # undef va_list
94 # define va_list        _IO_va_list
95 # undef BUFSIZ
96 # define BUFSIZ         _IO_BUFSIZ
97 # define ARGCHECK(S, Format)                                                  \
98   do                                                                          \
99     {                                                                         \
100       /* Check file argument for consistence.  */                             \
101       CHECK_FILE (S, -1);                                                     \
102       if (S->_flags & _IO_NO_WRITES)                                          \
103         {                                                                     \
104           __set_errno (EBADF);                                                \
105           return -1;                                                          \
106         }                                                                     \
107       if (Format == NULL)                                                     \
108         {                                                                     \
109           MAYBE_SET_EINVAL;                                                   \
110           return -1;                                                          \
111         }                                                                     \
112     } while (0)
113 # define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED)
114 #else /* ! USE_IN_LIBIO */
115 /* This code is for use in the GNU C library.  */
116 # include <stdio.h>
117 # define PUT(F, S, N)   fwrite (S, 1, N, F)
118 # define ARGCHECK(S, Format)                                                  \
119   do                                                                          \
120     {                                                                         \
121       /* Check file argument for consistence.  */                             \
122       if (!__validfp (S) || !S->__mode.__write)                               \
123         {                                                                     \
124           __set_errno (EBADF);                                                \
125           return -1;                                                          \
126         }                                                                     \
127       if (Format == NULL)                                                     \
128         {                                                                     \
129           __set_errno (EINVAL);                                               \
130           return -1;                                                          \
131         }                                                                     \
132       if (!S->__seen)                                                         \
133         {                                                                     \
134           if (__flshfp (S, EOF) == EOF)                                       \
135             return -1;                                                        \
136         }                                                                     \
137     }                                                                         \
138    while (0)
139 # define UNBUFFERED_P(s) ((s)->__buffer == NULL)
140
141 /* XXX These declarations should go as soon as the stdio header files
142    have these prototypes.   */
143 extern void __flockfile (FILE *);
144 extern void __funlockfile (FILE *);
145 #endif /* USE_IN_LIBIO */
146
147
148 #define outchar(Ch)                                                           \
149   do                                                                          \
150     {                                                                         \
151       register const int outc = (Ch);                                         \
152       if (PUTC (outc, s) == EOF)                                              \
153         return -1;                                                            \
154       else                                                                    \
155         ++done;                                                               \
156     }                                                                         \
157   while (0)
158
159 #define outstring(String, Len)                                                \
160   do                                                                          \
161     {                                                                         \
162       if ((size_t) PUT (s, (String), (Len)) != (size_t) (Len))                \
163         return -1;                                                            \
164       done += (Len);                                                          \
165     }                                                                         \
166   while (0)
167
168 /* For handling long_double and longlong we use the same flag.  */
169 #ifndef is_longlong
170 # define is_longlong is_long_double
171 #endif
172
173
174 /* Global variables.  */
175 static const char null[] = "(null)";
176
177
178 /* Helper function to provide temporary buffering for unbuffered streams.  */
179 static int buffered_vfprintf __P ((FILE *stream, const CHAR_T *fmt, va_list));
180
181 /* Handle unknown format specifier.  */
182 static int printf_unknown __P ((FILE *, const struct printf_info *,
183                                 const void *const *));
184
185 /* Group digits of number string.  */
186 static char *group_number __P ((CHAR_T *, CHAR_T *, const CHAR_T *, wchar_t));
187
188
189 /* The function itself.  */
190 int
191 vfprintf (FILE *s, const CHAR_T *format, va_list ap)
192 {
193   /* The character used as thousands separator.  */
194   wchar_t thousands_sep;
195
196   /* The string describing the size of groups of digits.  */
197   const char *grouping;
198
199   /* Place to accumulate the result.  */
200   int done;
201
202   /* Current character in format string.  */
203   const UCHAR_T *f;
204
205   /* End of leading constant string.  */
206   const UCHAR_T *lead_str_end;
207
208   /* Points to next format specifier.  */
209   const UCHAR_T *end_of_spec;
210
211   /* Buffer intermediate results.  */
212   char work_buffer[1000];
213 #define workend (&work_buffer[sizeof (work_buffer) - 1])
214
215   /* State for restartable multibyte character handling functions.  */
216   mbstate_t mbstate;
217
218   /* We have to save the original argument pointer.  */
219   va_list ap_save;
220
221   /* Count number of specifiers we already processed.  */
222   int nspecs_done;
223
224   /* For the %m format we may need the current `errno' value.  */
225   int save_errno = errno;
226
227
228   /* This table maps a character into a number representing a
229      class.  In each step there is a destination label for each
230      class.  */
231   static const int jump_table[] =
232   {
233     /* ' ' */  1,            0,            0, /* '#' */  4,
234                0, /* '%' */ 14,            0, /* '\''*/  6,
235                0,            0, /* '*' */  7, /* '+' */  2,
236                0, /* '-' */  3, /* '.' */  9,            0,
237     /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
238     /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
239     /* '8' */  8, /* '9' */  8,            0,            0,
240                0,            0,            0,            0,
241                0, /* 'A' */ 26,            0, /* 'C' */ 25,
242                0, /* 'E' */ 19,            0, /* 'G' */ 19,
243                0,            0,            0,            0,
244     /* 'L' */ 12,            0,            0,            0,
245                0,            0,            0, /* 'S' */ 21,
246                0,            0,            0,            0,
247     /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
248                0,            0,            0,            0,
249                0, /* 'a' */ 26,            0, /* 'c' */ 20,
250     /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
251     /* 'h' */ 10, /* 'i' */ 15,            0,            0,
252     /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
253     /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
254                0, /* 'u' */ 16,            0,            0,
255     /* 'x' */ 18
256   };
257
258 #define NOT_IN_JUMP_RANGE(Ch) ((Ch) < ' ' || (Ch) > 'x')
259 #define CHAR_CLASS(Ch) (jump_table[(int) (Ch) - ' '])
260 #define JUMP(ChExpr, table)                                                   \
261       do                                                                      \
262         {                                                                     \
263           const void *ptr;                                                    \
264           spec = (ChExpr);                                                    \
265           ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)                 \
266             : table[CHAR_CLASS (spec)];                                       \
267           goto *ptr;                                                          \
268         }                                                                     \
269       while (0)
270
271 #define STEP0_3_TABLE                                                         \
272     /* Step 0: at the beginning.  */                                          \
273     static const void *step0_jumps[27] =                                      \
274     {                                                                         \
275       REF (form_unknown),                                                     \
276       REF (flag_space),         /* for ' ' */                                 \
277       REF (flag_plus),          /* for '+' */                                 \
278       REF (flag_minus),         /* for '-' */                                 \
279       REF (flag_hash),          /* for '<hash>' */                            \
280       REF (flag_zero),          /* for '0' */                                 \
281       REF (flag_quote),         /* for '\'' */                                \
282       REF (width_asterics),     /* for '*' */                                 \
283       REF (width),              /* for '1'...'9' */                           \
284       REF (precision),          /* for '.' */                                 \
285       REF (mod_half),           /* for 'h' */                                 \
286       REF (mod_long),           /* for 'l' */                                 \
287       REF (mod_longlong),       /* for 'L', 'q' */                            \
288       REF (mod_size_t),         /* for 'Z' */                                 \
289       REF (form_percent),       /* for '%' */                                 \
290       REF (form_integer),       /* for 'd', 'i' */                            \
291       REF (form_unsigned),      /* for 'u' */                                 \
292       REF (form_octal),         /* for 'o' */                                 \
293       REF (form_hexa),          /* for 'X', 'x' */                            \
294       REF (form_float),         /* for 'E', 'e', 'f', 'G', 'g' */             \
295       REF (form_character),     /* for 'c' */                                 \
296       REF (form_string),        /* for 's', 'S' */                            \
297       REF (form_pointer),       /* for 'p' */                                 \
298       REF (form_number),        /* for 'n' */                                 \
299       REF (form_strerror),      /* for 'm' */                                 \
300       REF (form_wcharacter),    /* for 'C' */                                 \
301       REF (form_floathex)       /* for 'A', 'a' */                            \
302     };                                                                        \
303     /* Step 1: after processing width.  */                                    \
304     static const void *step1_jumps[27] =                                      \
305     {                                                                         \
306       REF (form_unknown),                                                     \
307       REF (form_unknown),       /* for ' ' */                                 \
308       REF (form_unknown),       /* for '+' */                                 \
309       REF (form_unknown),       /* for '-' */                                 \
310       REF (form_unknown),       /* for '<hash>' */                            \
311       REF (form_unknown),       /* for '0' */                                 \
312       REF (form_unknown),       /* for '\'' */                                \
313       REF (form_unknown),       /* for '*' */                                 \
314       REF (form_unknown),       /* for '1'...'9' */                           \
315       REF (precision),          /* for '.' */                                 \
316       REF (mod_half),           /* for 'h' */                                 \
317       REF (mod_long),           /* for 'l' */                                 \
318       REF (mod_longlong),       /* for 'L', 'q' */                            \
319       REF (mod_size_t),         /* for 'Z' */                                 \
320       REF (form_percent),       /* for '%' */                                 \
321       REF (form_integer),       /* for 'd', 'i' */                            \
322       REF (form_unsigned),      /* for 'u' */                                 \
323       REF (form_octal),         /* for 'o' */                                 \
324       REF (form_hexa),          /* for 'X', 'x' */                            \
325       REF (form_float),         /* for 'E', 'e', 'f', 'G', 'g' */             \
326       REF (form_character),     /* for 'c' */                                 \
327       REF (form_string),        /* for 's', 'S' */                            \
328       REF (form_pointer),       /* for 'p' */                                 \
329       REF (form_number),        /* for 'n' */                                 \
330       REF (form_strerror),      /* for 'm' */                                 \
331       REF (form_wcharacter),    /* for 'C' */                                 \
332       REF (form_floathex)       /* for 'A', 'a' */                            \
333     };                                                                        \
334     /* Step 2: after processing precision.  */                                \
335     static const void *step2_jumps[27] =                                      \
336     {                                                                         \
337       REF (form_unknown),                                                     \
338       REF (form_unknown),       /* for ' ' */                                 \
339       REF (form_unknown),       /* for '+' */                                 \
340       REF (form_unknown),       /* for '-' */                                 \
341       REF (form_unknown),       /* for '<hash>' */                            \
342       REF (form_unknown),       /* for '0' */                                 \
343       REF (form_unknown),       /* for '\'' */                                \
344       REF (form_unknown),       /* for '*' */                                 \
345       REF (form_unknown),       /* for '1'...'9' */                           \
346       REF (form_unknown),       /* for '.' */                                 \
347       REF (mod_half),           /* for 'h' */                                 \
348       REF (mod_long),           /* for 'l' */                                 \
349       REF (mod_longlong),       /* for 'L', 'q' */                            \
350       REF (mod_size_t),         /* for 'Z' */                                 \
351       REF (form_percent),       /* for '%' */                                 \
352       REF (form_integer),       /* for 'd', 'i' */                            \
353       REF (form_unsigned),      /* for 'u' */                                 \
354       REF (form_octal),         /* for 'o' */                                 \
355       REF (form_hexa),          /* for 'X', 'x' */                            \
356       REF (form_float),         /* for 'E', 'e', 'f', 'G', 'g' */             \
357       REF (form_character),     /* for 'c' */                                 \
358       REF (form_string),        /* for 's', 'S' */                            \
359       REF (form_pointer),       /* for 'p' */                                 \
360       REF (form_number),        /* for 'n' */                                 \
361       REF (form_strerror),      /* for 'm' */                                 \
362       REF (form_wcharacter),    /* for 'C' */                                 \
363       REF (form_floathex)       /* for 'A', 'a' */                            \
364     };                                                                        \
365     /* Step 3: after processing first 'l' modifier.  */                       \
366     static const void *step3_jumps[27] =                                      \
367     {                                                                         \
368       REF (form_unknown),                                                     \
369       REF (form_unknown),       /* for ' ' */                                 \
370       REF (form_unknown),       /* for '+' */                                 \
371       REF (form_unknown),       /* for '-' */                                 \
372       REF (form_unknown),       /* for '<hash>' */                            \
373       REF (form_unknown),       /* for '0' */                                 \
374       REF (form_unknown),       /* for '\'' */                                \
375       REF (form_unknown),       /* for '*' */                                 \
376       REF (form_unknown),       /* for '1'...'9' */                           \
377       REF (form_unknown),       /* for '.' */                                 \
378       REF (form_unknown),       /* for 'h' */                                 \
379       REF (mod_longlong),       /* for 'l' */                                 \
380       REF (form_unknown),       /* for 'L', 'q' */                            \
381       REF (form_unknown),       /* for 'Z' */                                 \
382       REF (form_percent),       /* for '%' */                                 \
383       REF (form_integer),       /* for 'd', 'i' */                            \
384       REF (form_unsigned),      /* for 'u' */                                 \
385       REF (form_octal),         /* for 'o' */                                 \
386       REF (form_hexa),          /* for 'X', 'x' */                            \
387       REF (form_float),         /* for 'E', 'e', 'f', 'G', 'g' */             \
388       REF (form_character),     /* for 'c' */                                 \
389       REF (form_string),        /* for 's', 'S' */                            \
390       REF (form_pointer),       /* for 'p' */                                 \
391       REF (form_number),        /* for 'n' */                                 \
392       REF (form_strerror),      /* for 'm' */                                 \
393       REF (form_wcharacter),    /* for 'C' */                                 \
394       REF (form_floathex)       /* for 'A', 'a' */                            \
395     }
396
397 #define STEP4_TABLE                                                           \
398     /* Step 4: processing format specifier.  */                               \
399     static const void *step4_jumps[27] =                                      \
400     {                                                                         \
401       REF (form_unknown),                                                     \
402       REF (form_unknown),       /* for ' ' */                                 \
403       REF (form_unknown),       /* for '+' */                                 \
404       REF (form_unknown),       /* for '-' */                                 \
405       REF (form_unknown),       /* for '<hash>' */                            \
406       REF (form_unknown),       /* for '0' */                                 \
407       REF (form_unknown),       /* for '\'' */                                \
408       REF (form_unknown),       /* for '*' */                                 \
409       REF (form_unknown),       /* for '1'...'9' */                           \
410       REF (form_unknown),       /* for '.' */                                 \
411       REF (form_unknown),       /* for 'h' */                                 \
412       REF (form_unknown),       /* for 'l' */                                 \
413       REF (form_unknown),       /* for 'L', 'q' */                            \
414       REF (form_unknown),       /* for 'Z' */                                 \
415       REF (form_percent),       /* for '%' */                                 \
416       REF (form_integer),       /* for 'd', 'i' */                            \
417       REF (form_unsigned),      /* for 'u' */                                 \
418       REF (form_octal),         /* for 'o' */                                 \
419       REF (form_hexa),          /* for 'X', 'x' */                            \
420       REF (form_float),         /* for 'E', 'e', 'f', 'G', 'g' */             \
421       REF (form_character),     /* for 'c' */                                 \
422       REF (form_string),        /* for 's', 'S' */                            \
423       REF (form_pointer),       /* for 'p' */                                 \
424       REF (form_number),        /* for 'n' */                                 \
425       REF (form_strerror),      /* for 'm' */                                 \
426       REF (form_wcharacter),    /* for 'C' */                                 \
427       REF (form_floathex)       /* for 'A', 'a' */                            \
428     }
429
430
431 #define process_arg(fspec)                                                    \
432       /* Start real work.  We know about all flags and modifiers and          \
433          now process the wanted format specifier.  */                         \
434     LABEL (form_percent):                                                     \
435       /* Write a literal "%".  */                                             \
436       outchar ('%');                                                          \
437       break;                                                                  \
438                                                                               \
439     LABEL (form_integer):                                                     \
440       /* Signed decimal integer.  */                                          \
441       base = 10;                                                              \
442                                                                               \
443       if (is_longlong)                                                        \
444         {                                                                     \
445           long long int signed_number;                                        \
446                                                                               \
447           if (fspec == NULL)                                                  \
448             signed_number = va_arg (ap, long long int);                       \
449           else                                                                \
450             signed_number = args_value[fspec->data_arg].pa_long_long_int;     \
451                                                                               \
452           is_negative = signed_number < 0;                                    \
453           number.longlong = is_negative ? (- signed_number) : signed_number;  \
454                                                                               \
455           goto LABEL (longlong_number);                                       \
456         }                                                                     \
457       else                                                                    \
458         {                                                                     \
459           long int signed_number;                                             \
460                                                                               \
461           if (fspec == NULL)                                                  \
462             if (is_long)                                                      \
463               signed_number = va_arg (ap, long int);                          \
464             else        /* `short int' will be promoted to `int'.  */         \
465               signed_number = va_arg (ap, int);                               \
466           else                                                                \
467             if (is_long)                                                      \
468               signed_number = args_value[fspec->data_arg].pa_long_int;        \
469             else                                                              \
470               signed_number = args_value[fspec->data_arg].pa_int;             \
471                                                                               \
472           is_negative = signed_number < 0;                                    \
473           number.word = is_negative ? (- signed_number) : signed_number;      \
474                                                                               \
475           goto LABEL (number);                                                \
476         }                                                                     \
477       /* NOTREACHED */                                                        \
478                                                                               \
479     LABEL (form_unsigned):                                                    \
480       /* Unsigned decimal integer.  */                                        \
481       base = 10;                                                              \
482       goto LABEL (unsigned_number);                                           \
483       /* NOTREACHED */                                                        \
484                                                                               \
485     LABEL (form_octal):                                                       \
486       /* Unsigned octal integer.  */                                          \
487       base = 8;                                                               \
488       goto LABEL (unsigned_number);                                           \
489       /* NOTREACHED */                                                        \
490                                                                               \
491     LABEL (form_hexa):                                                        \
492       /* Unsigned hexadecimal integer.  */                                    \
493       base = 16;                                                              \
494                                                                               \
495     LABEL (unsigned_number):      /* Unsigned number of base BASE.  */        \
496                                                                               \
497       /* ANSI specifies the `+' and ` ' flags only for signed                 \
498          conversions.  */                                                     \
499       is_negative = 0;                                                        \
500       showsign = 0;                                                           \
501       space = 0;                                                              \
502                                                                               \
503       if (is_longlong)                                                        \
504         {                                                                     \
505           if (fspec == NULL)                                                  \
506             number.longlong = va_arg (ap, unsigned long long int);            \
507           else                                                                \
508             number.longlong = args_value[fspec->data_arg].pa_u_long_long_int; \
509                                                                               \
510         LABEL (longlong_number):                                              \
511           if (prec < 0)                                                       \
512             /* Supply a default precision if none was given.  */              \
513             prec = 1;                                                         \
514           else                                                                \
515             /* We have to take care for the '0' flag.  If a precision         \
516                is given it must be ignored.  */                               \
517             pad = ' ';                                                        \
518                                                                               \
519           /* If the precision is 0 and the number is 0 nothing has to         \
520              be written for the number.  */                                   \
521           if (prec == 0 && number.longlong == 0)                              \
522             string = workend;                                                 \
523           else                                                                \
524             {                                                                 \
525               /* Put the number in WORK.  */                                  \
526               string = _itoa (number.longlong, workend + 1, base,             \
527                               spec == 'X');                                   \
528               string -= 1;                                                    \
529               if (group && grouping)                                          \
530                 string = group_number (string, workend, grouping,             \
531                                        thousands_sep);                        \
532             }                                                                 \
533           /* Simply further test for num != 0.  */                            \
534           number.word = number.longlong != 0;                                 \
535         }                                                                     \
536       else                                                                    \
537         {                                                                     \
538           if (fspec == NULL)                                                  \
539             if (is_long)                                                      \
540               number.word = va_arg (ap, unsigned long int);                   \
541             else if (!is_short)                                               \
542               number.word = va_arg (ap, unsigned int);                        \
543             else                                                              \
544               number.word = (unsigned short int) va_arg (ap, unsigned int);   \
545           else                                                                \
546             if (is_long)                                                      \
547               number.word = args_value[fspec->data_arg].pa_u_long_int;        \
548             else if (!is_short)                                               \
549               number.word = args_value[fspec->data_arg].pa_u_int;             \
550             else                                                              \
551               number.word = (unsigned short int)                              \
552                 args_value[fspec->data_arg].pa_u_short_int;                   \
553                                                                               \
554         LABEL (number):                                                       \
555           if (prec < 0)                                                       \
556             /* Supply a default precision if none was given.  */              \
557             prec = 1;                                                         \
558           else                                                                \
559             /* We have to take care for the '0' flag.  If a precision         \
560                is given it must be ignored.  */                               \
561             pad = ' ';                                                        \
562                                                                               \
563           /* If the precision is 0 and the number is 0 nothing has to         \
564              be written for the number.  */                                   \
565           if (prec == 0 && number.word == 0)                                  \
566             string = workend;                                                 \
567           else                                                                \
568             {                                                                 \
569               /* Put the number in WORK.  */                                  \
570               string = _itoa_word (number.word, workend + 1, base,            \
571                                    spec == 'X');                              \
572               string -= 1;                                                    \
573               if (group && grouping)                                          \
574                 string = group_number (string, workend, grouping,             \
575                                        thousands_sep);                        \
576             }                                                                 \
577         }                                                                     \
578                                                                               \
579       prec -= workend - string;                                               \
580                                                                               \
581       if (prec > 0)                                                           \
582         /* Add zeros to the precision.  */                                    \
583         while (prec-- > 0)                                                    \
584           *string-- = '0';                                                    \
585       else if (number.word != 0 && alt && base == 8)                          \
586         /* Add octal marker.  */                                              \
587         *string-- = '0';                                                      \
588                                                                               \
589       if (!left)                                                              \
590         {                                                                     \
591           width -= workend - string;                                          \
592                                                                               \
593           if (number.word != 0 && alt && base == 16)                          \
594             /* Account for 0X hex marker.  */                                 \
595             width -= 2;                                                       \
596                                                                               \
597           if (is_negative || showsign || space)                               \
598             --width;                                                          \
599                                                                               \
600           if (pad == '0')                                                     \
601             {                                                                 \
602               while (width-- > 0)                                             \
603                 *string-- = '0';                                              \
604                                                                               \
605               if (number.word != 0 && alt && base == 16)                      \
606                 {                                                             \
607                   *string-- = spec;                                           \
608                   *string-- = '0';                                            \
609                 }                                                             \
610                                                                               \
611               if (is_negative)                                                \
612                 *string-- = '-';                                              \
613               else if (showsign)                                              \
614                 *string-- = '+';                                              \
615               else if (space)                                                 \
616                 *string-- = ' ';                                              \
617             }                                                                 \
618           else                                                                \
619             {                                                                 \
620               if (number.word != 0 && alt && base == 16)                      \
621                 {                                                             \
622                   *string-- = spec;                                           \
623                   *string-- = '0';                                            \
624                 }                                                             \
625                                                                               \
626               if (is_negative)                                                \
627                 *string-- = '-';                                              \
628               else if (showsign)                                              \
629                 *string-- = '+';                                              \
630               else if (space)                                                 \
631                 *string-- = ' ';                                              \
632                                                                               \
633               while (width-- > 0)                                             \
634                 *string-- = ' ';                                              \
635             }                                                                 \
636                                                                               \
637           outstring (string + 1, workend - string);                           \
638                                                                               \
639           break;                                                              \
640         }                                                                     \
641       else                                                                    \
642         {                                                                     \
643           if (number.word != 0 && alt && base == 16)                          \
644             {                                                                 \
645               *string-- = spec;                                               \
646               *string-- = '0';                                                \
647             }                                                                 \
648                                                                               \
649           if (is_negative)                                                    \
650             *string-- = '-';                                                  \
651           else if (showsign)                                                  \
652             *string-- = '+';                                                  \
653           else if (space)                                                     \
654             *string-- = ' ';                                                  \
655                                                                               \
656           width -= workend - string;                                          \
657           outstring (string + 1, workend - string);                           \
658                                                                               \
659           PAD (' ');                                                          \
660           break;                                                              \
661         }                                                                     \
662                                                                               \
663     LABEL (form_float):                                                       \
664       {                                                                       \
665         /* Floating-point number.  This is handled by printf_fp.c.  */        \
666         extern int __printf_fp __P ((FILE *, const struct printf_info *,      \
667                                      const void **const));                    \
668         const void *ptr;                                                      \
669         int function_done;                                                    \
670                                                                               \
671         if (fspec == NULL)                                                    \
672           {                                                                   \
673             struct printf_info info = { prec: prec,                           \
674                                         width: width,                         \
675                                         spec: spec,                           \
676                                         is_long_double: is_long_double,       \
677                                         is_short: is_short,                   \
678                                         is_long: is_long,                     \
679                                         alt: alt,                             \
680                                         space: space,                         \
681                                         left: left,                           \
682                                         showsign: showsign,                   \
683                                         group: group,                         \
684                                         pad: pad,                             \
685                                         extra: 0 };                           \
686                                                                               \
687             if (is_long_double)                                               \
688               the_arg.pa_long_double = va_arg (ap, long double);              \
689             else                                                              \
690               the_arg.pa_double = va_arg (ap, double);                        \
691             ptr = (const void *) &the_arg;                                    \
692                                                                               \
693             function_done = __printf_fp (s, &info, &ptr);                     \
694           }                                                                   \
695         else                                                                  \
696           {                                                                   \
697             ptr = (const void *) &args_value[fspec->data_arg];                \
698                                                                               \
699             function_done = __printf_fp (s, &fspec->info, &ptr);              \
700           }                                                                   \
701                                                                               \
702         if (function_done < 0)                                                \
703           /* Error in print handler.  */                                      \
704           return -1;                                                          \
705                                                                               \
706         done += function_done;                                                \
707       }                                                                       \
708       break;                                                                  \
709                                                                               \
710     LABEL (form_floathex):                                                    \
711       {                                                                       \
712         /* FLoating point number printed as hexadecimal number.  */           \
713         extern int __printf_fphex __P ((FILE *, const struct printf_info *,   \
714                                         const void **const));                 \
715         const void *ptr;                                                      \
716         int function_done;                                                    \
717                                                                               \
718         if (fspec == NULL)                                                    \
719           {                                                                   \
720             struct printf_info info = { prec: prec,                           \
721                                         width: width,                         \
722                                         spec: spec,                           \
723                                         is_long_double: is_long_double,       \
724                                         is_short: is_short,                   \
725                                         is_long: is_long,                     \
726                                         alt: alt,                             \
727                                         space: space,                         \
728                                         left: left,                           \
729                                         showsign: showsign,                   \
730                                         group: group,                         \
731                                         pad: pad,                             \
732                                         extra: 0 };                           \
733                                                                               \
734             if (is_long_double)                                               \
735               the_arg.pa_long_double = va_arg (ap, long double);              \
736             else                                                              \
737               the_arg.pa_double = va_arg (ap, double);                        \
738             ptr = (const void *) &the_arg;                                    \
739                                                                               \
740             function_done = __printf_fphex (s, &info, &ptr);                  \
741           }                                                                   \
742         else                                                                  \
743           {                                                                   \
744             ptr = (const void *) &args_value[fspec->data_arg];                \
745                                                                               \
746             function_done = __printf_fphex (s, &fspec->info, &ptr);           \
747           }                                                                   \
748                                                                               \
749         if (function_done < 0)                                                \
750           /* Error in print handler.  */                                      \
751           return -1;                                                          \
752                                                                               \
753         done += function_done;                                                \
754       }                                                                       \
755       break;                                                                  \
756                                                                               \
757     LABEL (form_character):                                                   \
758       /* Character.  */                                                       \
759       if (is_long)                                                            \
760         goto LABEL (form_wcharacter);                                         \
761       --width;  /* Account for the character itself.  */                      \
762       if (!left)                                                              \
763         PAD (' ');                                                            \
764       if (fspec == NULL)                                                      \
765         outchar ((unsigned char) va_arg (ap, int)); /* Promoted.  */          \
766       else                                                                    \
767         outchar ((unsigned char) args_value[fspec->data_arg].pa_char);        \
768       if (left)                                                               \
769         PAD (' ');                                                            \
770       break;                                                                  \
771                                                                               \
772     LABEL (form_wcharacter):                                                  \
773       {                                                                       \
774         /* Wide character.  */                                                \
775         char buf[MB_CUR_MAX];                                                 \
776         mbstate_t mbstate;                                                    \
777         size_t len;                                                           \
778                                                                               \
779         len = __wcrtomb (buf, (fspec == NULL ? va_arg (ap, wint_t)            \
780                                : args_value[fspec->data_arg].pa_wchar),       \
781                          &mbstate);                                           \
782         width -= len;                                                         \
783         if (!left)                                                            \
784           PAD (' ');                                                          \
785         outstring (buf, len);                                                 \
786         if (left)                                                             \
787           PAD (' ');                                                          \
788       }                                                                       \
789       break;                                                                  \
790                                                                               \
791     LABEL (form_string):                                                      \
792       {                                                                       \
793         size_t len;                                                           \
794                                                                               \
795         /* The string argument could in fact be `char *' or `wchar_t *'.      \
796            But this should not make a difference here.  */                    \
797         if (fspec == NULL)                                                    \
798           string = (char *) va_arg (ap, const char *);                        \
799         else                                                                  \
800           string = (char *) args_value[fspec->data_arg].pa_string;            \
801                                                                               \
802         /* Entry point for printing other strings.  */                        \
803       LABEL (print_string):                                                   \
804                                                                               \
805         if (string == NULL)                                                   \
806           {                                                                   \
807             /* Write "(null)" if there's space.  */                           \
808             if (prec == -1 || prec >= (int) sizeof (null) - 1)                \
809               {                                                               \
810                 string = (char *) null;                                       \
811                 len = sizeof (null) - 1;                                      \
812               }                                                               \
813             else                                                              \
814               {                                                               \
815                 string = (char *) "";                                         \
816                 len = 0;                                                      \
817               }                                                               \
818           }                                                                   \
819         else if (!is_long && spec != L_('S'))                                 \
820           {                                                                   \
821             if (prec != -1)                                                   \
822               /* Search for the end of the string, but don't search past      \
823                  the length specified by the precision.  */                   \
824               len = strnlen (string, prec);                                   \
825             else                                                              \
826               len = strlen (string);                                          \
827           }                                                                   \
828         else                                                                  \
829           {                                                                   \
830             const wchar_t *s2 = (const wchar_t *) string;                     \
831             mbstate_t mbstate;                                                \
832                                                                               \
833             len = __wcsrtombs (NULL, &s2, 0, &mbstate);                       \
834             if (len == (size_t) -1)                                           \
835               /* Illegal wide-character string.  */                           \
836               return -1;                                                      \
837                                                                               \
838             s2 = (const wchar_t *) string;                                    \
839             string = alloca (len + 1);                                        \
840             (void) __wcsrtombs (string, &s2, prec != -1 ? prec : UINT_MAX,    \
841                                 &mbstate);                                    \
842           }                                                                   \
843                                                                               \
844         if ((width -= len) < 0)                                               \
845           {                                                                   \
846             outstring (string, len);                                          \
847             break;                                                            \
848           }                                                                   \
849                                                                               \
850         if (!left)                                                            \
851           PAD (' ');                                                          \
852         outstring (string, len);                                              \
853         if (left)                                                             \
854           PAD (' ');                                                          \
855       }                                                                       \
856       break;                                                                  \
857                                                                               \
858     LABEL (form_pointer):                                                     \
859       /* Generic pointer.  */                                                 \
860       {                                                                       \
861         const void *ptr;                                                      \
862         if (fspec == NULL)                                                    \
863           ptr = va_arg (ap, void *);                                          \
864         else                                                                  \
865           ptr = args_value[fspec->data_arg].pa_pointer;                       \
866         if (ptr != NULL)                                                      \
867           {                                                                   \
868             /* If the pointer is not NULL, write it as a %#x spec.  */        \
869             base = 16;                                                        \
870             number.word = (unsigned long int) ptr;                            \
871             is_negative = 0;                                                  \
872             alt = 1;                                                          \
873             group = 0;                                                        \
874             spec = 'x';                                                       \
875             goto LABEL (number);                                              \
876           }                                                                   \
877         else                                                                  \
878           {                                                                   \
879             /* Write "(nil)" for a nil pointer.  */                           \
880             string = (char *) "(nil)";                                        \
881             /* Make sure the full string "(nil)" is printed.  */              \
882             if (prec < 5)                                                     \
883               prec = 5;                                                       \
884             is_long = 0;        /* This is no wide-char string.  */           \
885             goto LABEL (print_string);                                        \
886           }                                                                   \
887       }                                                                       \
888       /* NOTREACHED */                                                        \
889                                                                               \
890     LABEL (form_number):                                                      \
891       /* Answer the count of characters written.  */                          \
892       if (fspec == NULL)                                                      \
893         if (is_longlong)                                                      \
894           *(long long int *) va_arg (ap, void *) = done;                      \
895         else if (is_long)                                                     \
896           *(long int *) va_arg (ap, void *) = done;                           \
897         else if (!is_short)                                                   \
898           *(int *) va_arg (ap, void *) = done;                                \
899         else                                                                  \
900           *(short int *) va_arg (ap, void *) = done;                          \
901       else                                                                    \
902         if (is_longlong)                                                      \
903           *(long long int *) args_value[fspec->data_arg].pa_pointer = done;   \
904         else if (is_long)                                                     \
905           *(long int *) args_value[fspec->data_arg].pa_pointer = done;        \
906         else if (!is_short)                                                   \
907           *(int *) args_value[fspec->data_arg].pa_pointer = done;             \
908         else                                                                  \
909           *(short int *) args_value[fspec->data_arg].pa_pointer = done;       \
910       break;                                                                  \
911                                                                               \
912     LABEL (form_strerror):                                                    \
913       /* Print description of error ERRNO.  */                                \
914       {                                                                       \
915         extern char *_strerror_internal __P ((int, char *buf, size_t));       \
916                                                                               \
917         string = (char *)                                                     \
918           _strerror_internal (save_errno, work_buffer, sizeof work_buffer);   \
919       }                                                                       \
920       is_long = 0;              /* This is no wide-char string.  */           \
921       goto LABEL (print_string)
922
923
924   /* Sanity check of arguments.  */
925   ARGCHECK (s, format);
926
927   if (UNBUFFERED_P (s))
928     /* Use a helper function which will allocate a local temporary buffer
929        for the stream and then call us again.  */
930     return buffered_vfprintf (s, format, ap);
931
932   /* Initialize local variables.  */
933   done = 0;
934   grouping = (const char *) -1;
935 #ifdef __va_copy
936   /* This macro will be available soon in gcc's <stdarg.h>.  We need it
937      since on some systems `va_list' is not an integral type.  */
938   __va_copy (ap_save, ap);
939 #else
940   ap_save = ap;
941 #endif
942   nspecs_done = 0;
943
944   /* Find the first format specifier.  */
945   f = lead_str_end = find_spec (format, &mbstate);
946
947   /* Lock stream.  */
948 #ifdef USE_IN_LIBIO
949   __libc_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
950   _IO_flockfile (s);
951 #else
952   __libc_cleanup_region_start ((void (*) (void *)) &__funlockfile, s);
953   __flockfile (s);
954 #endif
955
956   /* Write the literal text before the first format.  */
957   outstring ((const UCHAR_T *) format,
958              lead_str_end - (const UCHAR_T *) format);
959
960   /* If we only have to print a simple string, return now.  */
961   if (*f == L_('\0'))
962     goto all_done;
963
964   /* Process whole format string.  */
965   do
966     {
967 #define REF(Name) &&do_##Name
968 #define LABEL(Name) do_##Name
969       STEP0_3_TABLE;
970       STEP4_TABLE;
971
972       union printf_arg *args_value;     /* This is not used here but ... */
973       int is_negative;  /* Flag for negative number.  */
974       union
975       {
976         unsigned long long int longlong;
977         unsigned long int word;
978       } number;
979       int base;
980       union printf_arg the_arg;
981       char *string;     /* Pointer to argument string.  */
982       int alt = 0;      /* Alternate format.  */
983       int space = 0;    /* Use space prefix if no sign is needed.  */
984       int left = 0;     /* Left-justify output.  */
985       int showsign = 0; /* Always begin with plus or minus sign.  */
986       int group = 0;    /* Print numbers according grouping rules.  */
987       int is_long_double = 0; /* Argument is long double/ long long int.  */
988       int is_short = 0; /* Argument is long int.  */
989       int is_long = 0;  /* Argument is short int.  */
990       int width = 0;    /* Width of output; 0 means none specified.  */
991       int prec = -1;    /* Precision of output; -1 means none specified.  */
992       char pad = ' ';   /* Padding character.  */
993       CHAR_T spec;
994
995       /* Get current character in format string.  */
996       JUMP (*++f, step0_jumps);
997
998       /* ' ' flag.  */
999     LABEL (flag_space):
1000       space = 1;
1001       JUMP (*++f, step0_jumps);
1002
1003       /* '+' flag.  */
1004     LABEL (flag_plus):
1005       showsign = 1;
1006       JUMP (*++f, step0_jumps);
1007
1008       /* The '-' flag.  */
1009     LABEL (flag_minus):
1010       left = 1;
1011       pad = L_(' ');
1012       JUMP (*++f, step0_jumps);
1013
1014       /* The '#' flag.  */
1015     LABEL (flag_hash):
1016       alt = 1;
1017       JUMP (*++f, step0_jumps);
1018
1019       /* The '0' flag.  */
1020     LABEL (flag_zero):
1021       if (!left)
1022         pad = L_('0');
1023       JUMP (*++f, step0_jumps);
1024
1025       /* The '\'' flag.  */
1026     LABEL (flag_quote):
1027       group = 1;
1028
1029       /* XXX Completely wrong.  Use wctob.  */
1030       if (grouping == (const char *) -1)
1031         {
1032           /* Figure out the thousands separator character.  */
1033           if (mbtowc (&thousands_sep,
1034                       _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
1035                       strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
1036             thousands_sep = (wchar_t)
1037               *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
1038           grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1039           if (*grouping == '\0' || *grouping == CHAR_MAX
1040               || thousands_sep == L'\0')
1041             grouping = NULL;
1042         }
1043       JUMP (*++f, step0_jumps);
1044
1045       /* Get width from argument.  */
1046     LABEL (width_asterics):
1047       {
1048         const UCHAR_T *tmp;     /* Temporary value.  */
1049
1050         tmp = ++f;
1051         if (ISDIGIT (*tmp) && read_int (&tmp) && *tmp == L_('$'))
1052           /* The width comes from a positional parameter.  */
1053           goto do_positional;
1054
1055         width = va_arg (ap, int);
1056
1057         /* Negative width means left justified.  */
1058         if (width < 0)
1059           {
1060             width = -width;
1061             pad = L_(' ');
1062             left = 1;
1063           }
1064       }
1065       JUMP (*f, step1_jumps);
1066
1067       /* Given width in format string.  */
1068     LABEL (width):
1069       width = read_int (&f);
1070       if (*f == L_('$'))
1071         /* Oh, oh.  The argument comes from a positional parameter.  */
1072         goto do_positional;
1073       JUMP (*f, step1_jumps);
1074
1075     LABEL (precision):
1076       ++f;
1077       if (*f == L_('*'))
1078         {
1079           const UCHAR_T *tmp;   /* Temporary value.  */
1080
1081           tmp = ++f;
1082           if (ISDIGIT (*tmp) && read_int (&tmp) > 0 && *tmp == L_('$'))
1083             /* The precision comes from a positional parameter.  */
1084             goto do_positional;
1085
1086           prec = va_arg (ap, int);
1087
1088           /* If the precision is negative the precision is omitted.  */
1089           if (prec < 0)
1090             prec = -1;
1091         }
1092       else if (ISDIGIT (*f))
1093         prec = read_int (&f);
1094       else
1095         prec = 0;
1096       JUMP (*f, step2_jumps);
1097
1098       /* Process 'h' modifier.  No other modifier is allowed to
1099          follow.  */
1100     LABEL (mod_half):
1101       is_short = 1;
1102       JUMP (*++f, step4_jumps);
1103
1104       /* Process 'l' modifier.  There might another 'l' follow.  */
1105     LABEL (mod_long):
1106       is_long = 1;
1107       JUMP (*++f, step3_jumps);
1108
1109       /* Process 'L', 'q', or 'll' modifier.  No other modifier is
1110          allowed to follow.  */
1111     LABEL (mod_longlong):
1112       is_long_double = 1;
1113       JUMP (*++f, step4_jumps);
1114
1115     LABEL (mod_size_t):
1116       is_longlong = sizeof (size_t) > sizeof (unsigned long int);
1117       is_long = sizeof (size_t) > sizeof (unsigned int);
1118       JUMP (*++f, step4_jumps);
1119
1120       /* Process current format.  */
1121       while (1)
1122         {
1123           process_arg (((struct printf_spec *) NULL));
1124
1125         LABEL (form_unknown):
1126           if (spec == L_('\0'))
1127             {
1128               /* The format string ended before the specifier is complete.  */
1129               done = -1;
1130               goto all_done;
1131             }
1132
1133           /* If we are in the fast loop force entering the complicated
1134              one.  */
1135           goto do_positional;
1136         }
1137
1138       /* The format is correctly handled.  */
1139       ++nspecs_done;
1140
1141       /* Look for next format specifier.  */
1142       f = find_spec ((end_of_spec = ++f), &mbstate);
1143
1144       /* Write the following constant string.  */
1145       outstring (end_of_spec, f - end_of_spec);
1146     }
1147   while (*f != L_('\0'));
1148
1149   /* Unlock stream and return.  */
1150   goto all_done;
1151
1152   /* Here starts the more complex loop to handle positional parameters.  */
1153 do_positional:
1154   {
1155     /* Array with information about the needed arguments.  This has to
1156        be dynamically extensible.  */
1157     size_t nspecs = 0;
1158     size_t nspecs_max = 32;     /* A more or less arbitrary start value.  */
1159     struct printf_spec *specs
1160       = alloca (nspecs_max * sizeof (struct printf_spec));
1161
1162     /* The number of arguments the format string requests.  This will
1163        determine the size of the array needed to store the argument
1164        attributes.  */
1165     size_t nargs = 0;
1166     int *args_type;
1167     union printf_arg *args_value;
1168
1169     /* Positional parameters refer to arguments directly.  This could
1170        also determine the maximum number of arguments.  Track the
1171        maximum number.  */
1172     size_t max_ref_arg = 0;
1173
1174     /* Just a counter.  */
1175     size_t cnt;
1176
1177
1178     if (grouping == (const char *) -1)
1179       {
1180         /* XXX Use wctob.  But this is incompatible for now.  */
1181         /* Figure out the thousands separator character.  */
1182         if (mbtowc (&thousands_sep,
1183                     _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),
1184                     strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)
1185           thousands_sep = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
1186         grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1187         if (*grouping == '\0' || *grouping == CHAR_MAX
1188             || thousands_sep == L'\0')
1189           grouping = NULL;
1190       }
1191
1192     for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt)
1193       {
1194         if (nspecs >= nspecs_max)
1195           {
1196             /* Extend the array of format specifiers.  */
1197             struct printf_spec *old = specs;
1198
1199             nspecs_max *= 2;
1200             specs = alloca (nspecs_max * sizeof (struct printf_spec));
1201
1202             if (specs == &old[nspecs])
1203               /* Stack grows up, OLD was the last thing allocated;
1204                  extend it.  */
1205               nspecs_max += nspecs_max / 2;
1206             else
1207               {
1208                 /* Copy the old array's elements to the new space.  */
1209                 memcpy (specs, old, nspecs * sizeof (struct printf_spec));
1210                 if (old == &specs[nspecs])
1211                   /* Stack grows down, OLD was just below the new
1212                      SPECS.  We can use that space when the new space
1213                      runs out.  */
1214                   nspecs_max += nspecs_max / 2;
1215               }
1216           }
1217
1218         /* Parse the format specifier.  */
1219         nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg,
1220                                  &mbstate);
1221       }
1222
1223     /* Determine the number of arguments the format string consumes.  */
1224     nargs = MAX (nargs, max_ref_arg);
1225
1226     /* Allocate memory for the argument descriptions.  */
1227     args_type = alloca (nargs * sizeof (int));
1228     memset (args_type, 0, nargs * sizeof (int));
1229     args_value = alloca (nargs * sizeof (union printf_arg));
1230
1231     /* XXX Could do sanity check here: If any element in ARGS_TYPE is
1232        still zero after this loop, format is invalid.  For now we
1233        simply use 0 as the value.  */
1234
1235     /* Fill in the types of all the arguments.  */
1236     for (cnt = 0; cnt < nspecs; ++cnt)
1237       {
1238         /* If the width is determined by an argument this is an int.  */
1239         if (specs[cnt].width_arg != -1)
1240           args_type[specs[cnt].width_arg] = PA_INT;
1241
1242         /* If the precision is determined by an argument this is an int.  */
1243         if (specs[cnt].prec_arg != -1)
1244           args_type[specs[cnt].prec_arg] = PA_INT;
1245
1246         switch (specs[cnt].ndata_args)
1247           {
1248           case 0:               /* No arguments.  */
1249             break;
1250           case 1:               /* One argument; we already have the type.  */
1251             args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
1252             break;
1253           default:
1254             /* We have more than one argument for this format spec.
1255                We must call the arginfo function again to determine
1256                all the types.  */
1257             (void) (*__printf_arginfo_table[specs[cnt].info.spec])
1258               (&specs[cnt].info,
1259                specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]);
1260             break;
1261           }
1262       }
1263
1264     /* Now we know all the types and the order.  Fill in the argument
1265        values.  */
1266     for (cnt = 0; cnt < nargs; ++cnt)
1267       switch (args_type[cnt])
1268         {
1269 #define T(tag, mem, type)                                                     \
1270         case tag:                                                             \
1271           args_value[cnt].mem = va_arg (ap_save, type);                       \
1272           break
1273
1274         T (PA_CHAR, pa_char, int); /* Promoted.  */
1275         T (PA_WCHAR, pa_wchar, wint_t);
1276         T (PA_INT|PA_FLAG_SHORT, pa_short_int, int); /* Promoted.  */
1277         T (PA_INT, pa_int, int);
1278         T (PA_INT|PA_FLAG_LONG, pa_long_int, long int);
1279         T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
1280         T (PA_FLOAT, pa_float, double); /* Promoted.  */
1281         T (PA_DOUBLE, pa_double, double);
1282         T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double);
1283         T (PA_STRING, pa_string, const char *);
1284         T (PA_WSTRING, pa_wstring, const wchar_t *);
1285         T (PA_POINTER, pa_pointer, void *);
1286 #undef T
1287         default:
1288           if ((args_type[cnt] & PA_FLAG_PTR) != 0)
1289             args_value[cnt].pa_pointer = va_arg (ap_save, void *);
1290           else
1291             args_value[cnt].pa_long_double = 0.0;
1292           break;
1293         }
1294
1295     /* Now walk through all format specifiers and process them.  */
1296     for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
1297       {
1298 #undef REF
1299 #define REF(Name) &&do2_##Name
1300 #undef LABEL
1301 #define LABEL(Name) do2_##Name
1302         STEP4_TABLE;
1303
1304         int is_negative;
1305         union
1306         {
1307           unsigned long long int longlong;
1308           unsigned long int word;
1309         } number;
1310         int base;
1311         union printf_arg the_arg;
1312         char *string;   /* Pointer to argument string.  */
1313
1314         /* Fill variables from values in struct.  */
1315         int alt = specs[nspecs_done].info.alt;
1316         int space = specs[nspecs_done].info.space;
1317         int left = specs[nspecs_done].info.left;
1318         int showsign = specs[nspecs_done].info.showsign;
1319         int group = specs[nspecs_done].info.group;
1320         int is_long_double = specs[nspecs_done].info.is_long_double;
1321         int is_short = specs[nspecs_done].info.is_short;
1322         int is_long = specs[nspecs_done].info.is_long;
1323         int width = specs[nspecs_done].info.width;
1324         int prec = specs[nspecs_done].info.prec;
1325         char pad = specs[nspecs_done].info.pad;
1326         CHAR_T spec = specs[nspecs_done].info.spec;
1327
1328         /* Fill in last information.  */
1329         if (specs[nspecs_done].width_arg != -1)
1330           {
1331             /* Extract the field width from an argument.  */
1332             specs[nspecs_done].info.width =
1333               args_value[specs[nspecs_done].width_arg].pa_int;
1334
1335             if (specs[nspecs_done].info.width < 0)
1336               /* If the width value is negative left justification is
1337                  selected and the value is taken as being positive.  */
1338               {
1339                 specs[nspecs_done].info.width *= -1;
1340                 left = specs[nspecs_done].info.left = 1;
1341               }
1342             width = specs[nspecs_done].info.width;
1343           }
1344
1345         if (specs[nspecs_done].prec_arg != -1)
1346           {
1347             /* Extract the precision from an argument.  */
1348             specs[nspecs_done].info.prec =
1349               args_value[specs[nspecs_done].prec_arg].pa_int;
1350
1351             if (specs[nspecs_done].info.prec < 0)
1352               /* If the precision is negative the precision is
1353                  omitted.  */
1354               specs[nspecs_done].info.prec = -1;
1355
1356             prec = specs[nspecs_done].info.prec;
1357           }
1358
1359         /* Process format specifiers.  */
1360         while (1)
1361           {
1362             JUMP (spec, step4_jumps);
1363
1364             process_arg ((&specs[nspecs_done]));
1365
1366           LABEL (form_unknown):
1367             {
1368               extern printf_function **__printf_function_table;
1369               int function_done;
1370               printf_function *function;
1371               unsigned int i;
1372               const void **ptr;
1373
1374               function =
1375                 (__printf_function_table == NULL ? NULL :
1376                  __printf_function_table[specs[nspecs_done].info.spec]);
1377
1378               if (function == NULL)
1379                 function = &printf_unknown;
1380
1381               ptr = alloca (specs[nspecs_done].ndata_args
1382                             * sizeof (const void *));
1383
1384               /* Fill in an array of pointers to the argument values.  */
1385               for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
1386                 ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
1387
1388               /* Call the function.  */
1389               function_done = (*function) (s, &specs[nspecs_done].info, ptr);
1390
1391               /* If an error occurred we don't have information about #
1392                  of chars.  */
1393               if (function_done < 0)
1394                 {
1395                   done = -1;
1396                   goto all_done;
1397                 }
1398
1399               done += function_done;
1400             }
1401             break;
1402           }
1403
1404         /* Write the following constant string.  */
1405         outstring (specs[nspecs_done].end_of_fmt,
1406                    specs[nspecs_done].next_fmt
1407                    - specs[nspecs_done].end_of_fmt);
1408       }
1409   }
1410
1411 all_done:
1412   /* Unlock the stream.  */
1413   __libc_cleanup_region_end (1);
1414
1415   return done;
1416 }
1417
1418 #ifdef USE_IN_LIBIO
1419 # undef vfprintf
1420 # ifdef strong_alias
1421 /* This is for glibc.  */
1422 strong_alias (_IO_vfprintf, vfprintf);
1423 # else
1424 #  if defined __ELF__ || defined __GNU_LIBRARY__
1425 #   include <gnu-stabs.h>
1426 #   ifdef weak_alias
1427 weak_alias (_IO_vfprintf, vfprintf);
1428 #   endif
1429 #  endif
1430 # endif
1431 #endif
1432 \f
1433 /* Handle an unknown format specifier.  This prints out a canonicalized
1434    representation of the format spec itself.  */
1435 static int
1436 printf_unknown (FILE *s, const struct printf_info *info,
1437                 const void *const *args)
1438
1439 {
1440   int done = 0;
1441   char work_buffer[BUFSIZ];
1442   register char *w;
1443
1444   outchar ('%');
1445
1446   if (info->alt)
1447     outchar ('#');
1448   if (info->group)
1449     outchar ('\'');
1450   if (info->showsign)
1451     outchar ('+');
1452   else if (info->space)
1453     outchar (' ');
1454   if (info->left)
1455     outchar ('-');
1456   if (info->pad == '0')
1457     outchar ('0');
1458
1459   if (info->width != 0)
1460     {
1461       w = _itoa_word (info->width, workend + 1, 10, 0);
1462       while (w <= workend)
1463         outchar (*w++);
1464     }
1465
1466   if (info->prec != -1)
1467     {
1468       outchar ('.');
1469       w = _itoa_word (info->prec, workend + 1, 10, 0);
1470       while (w <= workend)
1471         outchar (*w++);
1472     }
1473
1474   if (info->spec != '\0')
1475     outchar (info->spec);
1476
1477   return done;
1478 }
1479 \f
1480 /* Group the digits according to the grouping rules of the current locale.
1481    The interpretation of GROUPING is as in `struct lconv' from <locale.h>.  */
1482 static char *
1483 group_number (CHAR_T *w, CHAR_T *rear_ptr, const CHAR_T *grouping,
1484               wchar_t thousands_sep)
1485 {
1486   int len;
1487   char *src, *s;
1488
1489   /* We treat all negative values like CHAR_MAX.  */
1490
1491   if (*grouping == CHAR_MAX || *grouping <= 0)
1492     /* No grouping should be done.  */
1493     return w;
1494
1495   len = *grouping;
1496
1497   /* Copy existing string so that nothing gets overwritten.  */
1498   src = (char *) alloca (rear_ptr - w);
1499   memcpy (src, w + 1, rear_ptr - w);
1500   s = &src[rear_ptr - w - 1];
1501   w = rear_ptr;
1502
1503   /* Process all characters in the string.  */
1504   while (s >= src)
1505     {
1506       *w-- = *s--;
1507
1508       if (--len == 0 && s >= src)
1509         {
1510           /* A new group begins.  */
1511           *w-- = thousands_sep;
1512
1513           len = *grouping++;
1514           if (*grouping == '\0')
1515             /* The previous grouping repeats ad infinitum.  */
1516             --grouping;
1517           else if (*grouping == CHAR_MAX || *grouping < 0)
1518             {
1519               /* No further grouping to be done.
1520                  Copy the rest of the number.  */
1521               do
1522                 *w-- = *s--;
1523               while (s >= src);
1524               break;
1525             }
1526         }
1527     }
1528   return w;
1529 }
1530 \f
1531 #ifdef USE_IN_LIBIO
1532 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
1533 struct helper_file
1534   {
1535     struct _IO_FILE_plus _f;
1536     _IO_FILE *_put_stream;
1537 #ifdef _IO_MTSAFE_IO
1538     _IO_lock_t lock;
1539 #endif
1540   };
1541
1542 static int
1543 _IO_helper_overflow (_IO_FILE *s, int c)
1544 {
1545   _IO_FILE *target = ((struct helper_file*) s)->_put_stream;
1546   int used = s->_IO_write_ptr - s->_IO_write_base;
1547   if (used)
1548     {
1549       _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used);
1550       s->_IO_write_ptr -= written;
1551     }
1552   return PUTC (c, s);
1553 }
1554
1555 static const struct _IO_jump_t _IO_helper_jumps =
1556 {
1557   JUMP_INIT_DUMMY,
1558   JUMP_INIT (finish, _IO_default_finish),
1559   JUMP_INIT (overflow, _IO_helper_overflow),
1560   JUMP_INIT (underflow, _IO_default_underflow),
1561   JUMP_INIT (uflow, _IO_default_uflow),
1562   JUMP_INIT (pbackfail, _IO_default_pbackfail),
1563   JUMP_INIT (xsputn, _IO_default_xsputn),
1564   JUMP_INIT (xsgetn, _IO_default_xsgetn),
1565   JUMP_INIT (seekoff, _IO_default_seekoff),
1566   JUMP_INIT (seekpos, _IO_default_seekpos),
1567   JUMP_INIT (setbuf, _IO_default_setbuf),
1568   JUMP_INIT (sync, _IO_default_sync),
1569   JUMP_INIT (doallocate, _IO_default_doallocate),
1570   JUMP_INIT (read, _IO_default_read),
1571   JUMP_INIT (write, _IO_default_write),
1572   JUMP_INIT (seek, _IO_default_seek),
1573   JUMP_INIT (close, _IO_default_close),
1574   JUMP_INIT (stat, _IO_default_stat)
1575 };
1576
1577 static int
1578 buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format,
1579                    _IO_va_list args)
1580 {
1581   char buf[_IO_BUFSIZ];
1582   struct helper_file helper;
1583   register _IO_FILE *hp = (_IO_FILE *) &helper;
1584   int result, to_flush;
1585
1586   /* Initialize helper.  */
1587   helper._put_stream = s;
1588   hp->_IO_write_base = buf;
1589   hp->_IO_write_ptr = buf;
1590   hp->_IO_write_end = buf + sizeof buf;
1591   hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS;
1592 #ifdef _IO_MTSAFE_IO
1593   hp->_lock = &helper.lock;
1594   __libc_lock_init (*hp->_lock);
1595 #endif
1596   _IO_JUMPS (hp) = (struct _IO_jump_t *) &_IO_helper_jumps;
1597
1598   /* Now print to helper instead.  */
1599   result = _IO_vfprintf (hp, format, args);
1600
1601   /* Now flush anything from the helper to the S. */
1602   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
1603     {
1604       if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
1605         return -1;
1606     }
1607
1608   return result;
1609 }
1610
1611 #else /* !USE_IN_LIBIO */
1612
1613 static int
1614 buffered_vfprintf (register FILE *s, const CHAR_T *format, va_list args)
1615 {
1616   char buf[BUFSIZ];
1617   int result;
1618
1619   s->__bufp = s->__buffer = buf;
1620   s->__bufsize = sizeof buf;
1621   s->__put_limit = s->__buffer + s->__bufsize;
1622   s->__get_limit = s->__buffer;
1623
1624   /* Now use buffer to print.  */
1625   result = vfprintf (s, format, args);
1626
1627   if (fflush (s) == EOF)
1628     result = -1;
1629   s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL;
1630   s->__bufsize = 0;
1631
1632   return result;
1633 }
1634 \f
1635 /* Pads string with given number of a specified character.
1636    This code is taken from iopadn.c of the GNU I/O library.  */
1637 #define PADSIZE 16
1638 static const CHAR_T blanks[PADSIZE] =
1639 { L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '),
1640   L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ') };
1641 static const CHAR_T zeroes[PADSIZE] =
1642 { L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'),
1643   L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0') };
1644
1645 ssize_t
1646 #ifndef COMPILE_WPRINTF
1647 __printf_pad (FILE *s, char pad, size_t count)
1648 #else
1649 __wprintf_pad (FILE *s, wchar_t pad, size_t count)
1650 #endif
1651 {
1652   const CHAR_T *padptr;
1653   register size_t i;
1654
1655   padptr = pad == L_(' ') ? blanks : zeroes;
1656
1657   for (i = count; i >= PADSIZE; i -= PADSIZE)
1658     if (PUT (s, padptr, PADSIZE) != PADSIZE)
1659       return -1;
1660   if (i > 0)
1661     if (PUT (s, padptr, i) != i)
1662       return -1;
1663
1664   return count;
1665 }
1666 #undef PADSIZE
1667 #endif /* USE_IN_LIBIO */