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