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