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