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