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