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