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