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