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