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