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