1 /* Copyright (C) 1991-2022 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, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <array_length.h>
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 <libc-lock.h>
29 #include <sys/param.h>
30 #include <_itoa.h>
31 #include <locale/localeinfo.h>
32 #include <stdio.h>
33 #include <scratch_buffer.h>
34 #include <intprops.h>
35 
36 /* This code is shared between the standard stdio implementation found
37    in GNU C library and the libio implementation originally found in
38    GNU libg++.
39 
40    Beside this it is also shared between the normal and wide character
41    implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995.  */
42 
43 #include <libioP.h>
44 
45 #ifdef COMPILE_WPRINTF
46 #include <wctype.h>
47 #endif
48 
49 #define ARGCHECK(S, Format) \
50   do									      \
51     {									      \
52       /* Check file argument for consistence.  */			      \
53       CHECK_FILE (S, -1);						      \
54       if (S->_flags & _IO_NO_WRITES)					      \
55 	{								      \
56 	  S->_flags |= _IO_ERR_SEEN;					      \
57 	  __set_errno (EBADF);						      \
58 	  return -1;							      \
59 	}								      \
60       if (Format == NULL)						      \
61 	{								      \
62 	  __set_errno (EINVAL);						      \
63 	  return -1;							      \
64 	}								      \
65     } while (0)
66 #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
67 
68 #if __HAVE_FLOAT128_UNLIKE_LDBL
69 # define PARSE_FLOAT_VA_ARG_EXTENDED(INFO)				      \
70   do									      \
71     {									      \
72       if (is_long_double						      \
73 	  && (mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0)		      \
74 	{								      \
75 	  INFO.is_binary128 = 1;					      \
76 	  the_arg.pa_float128 = va_arg (ap, _Float128);			      \
77 	}								      \
78       else								      \
79 	{								      \
80 	  PARSE_FLOAT_VA_ARG (INFO);					      \
81 	}								      \
82     }									      \
83   while (0)
84 #else
85 # define PARSE_FLOAT_VA_ARG_EXTENDED(INFO)				      \
86   PARSE_FLOAT_VA_ARG (INFO);
87 #endif
88 
89 #define PARSE_FLOAT_VA_ARG(INFO)					      \
90   do									      \
91     {									      \
92       INFO.is_binary128 = 0;						      \
93       if (is_long_double)						      \
94 	the_arg.pa_long_double = va_arg (ap, long double);		      \
95       else								      \
96 	the_arg.pa_double = va_arg (ap, double);			      \
97     }									      \
98   while (0)
99 
100 #if __HAVE_FLOAT128_UNLIKE_LDBL
101 # define SETUP_FLOAT128_INFO(INFO)					      \
102   do									      \
103     {									      \
104       if ((mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0)		      \
105 	INFO.is_binary128 = is_long_double;				      \
106       else								      \
107 	INFO.is_binary128 = 0;						      \
108     }									      \
109   while (0)
110 #else
111 # define SETUP_FLOAT128_INFO(INFO)					      \
112   do									      \
113     {									      \
114       INFO.is_binary128 = 0;						      \
115     }									      \
116   while (0)
117 #endif
118 
119 /* Add LENGTH to DONE.  Return the new value of DONE, or -1 on
120    overflow (and set errno accordingly).  */
121 static inline int
done_add_func(size_t length,int done)122 done_add_func (size_t length, int done)
123 {
124   if (done < 0)
125     return done;
126   int ret;
127   if (INT_ADD_WRAPV (done, length, &ret))
128     {
129       __set_errno (EOVERFLOW);
130       return -1;
131     }
132   return ret;
133 }
134 
135 #define done_add(val)							\
136   do									\
137     {									\
138       /* Ensure that VAL has a type similar to int.  */			\
139       _Static_assert (sizeof (val) == sizeof (int), "value int size");	\
140       _Static_assert ((__typeof__ (val)) -1 < 0, "value signed");	\
141       done = done_add_func ((val), done);				\
142       if (done < 0)							\
143 	goto all_done;							\
144     }									\
145   while (0)
146 
147 #ifndef COMPILE_WPRINTF
148 # define vfprintf	__vfprintf_internal
149 # define CHAR_T		char
150 # define OTHER_CHAR_T   wchar_t
151 # define UCHAR_T	unsigned char
152 # define INT_T		int
153 typedef const char *THOUSANDS_SEP_T;
154 # define L_(Str)	Str
155 # define ISDIGIT(Ch)	((unsigned int) ((Ch) - '0') < 10)
156 # define STR_LEN(Str)	strlen (Str)
157 
158 # define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
159 # define PUTC(C, F)	_IO_putc_unlocked (C, F)
160 # define ORIENT		if (_IO_vtable_offset (s) == 0 && _IO_fwide (s, -1) != -1)\
161 			  return -1
162 # define CONVERT_FROM_OTHER_STRING __wcsrtombs
163 #else
164 # define vfprintf	__vfwprintf_internal
165 # define CHAR_T		wchar_t
166 # define OTHER_CHAR_T   char
167 /* This is a hack!!!  There should be a type uwchar_t.  */
168 # define UCHAR_T	unsigned int /* uwchar_t */
169 # define INT_T		wint_t
170 typedef wchar_t THOUSANDS_SEP_T;
171 # define L_(Str)	L##Str
172 # define ISDIGIT(Ch)	((unsigned int) ((Ch) - L'0') < 10)
173 # define STR_LEN(Str)	__wcslen (Str)
174 
175 # include <_itowa.h>
176 
177 # define PUT(F, S, N)	_IO_sputn ((F), (S), (N))
178 # define PUTC(C, F)	_IO_putwc_unlocked (C, F)
179 # define ORIENT		if (_IO_fwide (s, 1) != 1) return -1
180 # define CONVERT_FROM_OTHER_STRING __mbsrtowcs
181 
182 # undef _itoa
183 # define _itoa(Val, Buf, Base, Case) _itowa (Val, Buf, Base, Case)
184 # define _itoa_word(Val, Buf, Base, Case) _itowa_word (Val, Buf, Base, Case)
185 # undef EOF
186 # define EOF WEOF
187 #endif
188 
189 static inline int
pad_func(FILE * s,CHAR_T padchar,int width,int done)190 pad_func (FILE *s, CHAR_T padchar, int width, int done)
191 {
192   if (width > 0)
193     {
194       ssize_t written;
195 #ifndef COMPILE_WPRINTF
196       written = _IO_padn (s, padchar, width);
197 #else
198       written = _IO_wpadn (s, padchar, width);
199 #endif
200       if (__glibc_unlikely (written != width))
201 	return -1;
202       return done_add_func (width, done);
203     }
204   return done;
205 }
206 
207 #define PAD(Padchar)							\
208   do									\
209     {									\
210       done = pad_func (s, (Padchar), width, done);			\
211       if (done < 0)							\
212 	goto all_done;							\
213     }									\
214   while (0)
215 
216 #include "_i18n_number.h"
217 
218 /* Include the shared code for parsing the format string.  */
219 #include "printf-parse.h"
220 
221 
222 #define	outchar(Ch)							      \
223   do									      \
224     {									      \
225       const INT_T outc = (Ch);						      \
226       if (PUTC (outc, s) == EOF || done == INT_MAX)			      \
227 	{								      \
228 	  done = -1;							      \
229 	  goto all_done;						      \
230 	}								      \
231       ++done;								      \
232     }									      \
233   while (0)
234 
235 static inline int
outstring_func(FILE * s,const UCHAR_T * string,size_t length,int done)236 outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done)
237 {
238   assert ((size_t) done <= (size_t) INT_MAX);
239   if ((size_t) PUT (s, string, length) != (size_t) (length))
240     return -1;
241   return done_add_func (length, done);
242 }
243 
244 #define outstring(String, Len)						\
245   do									\
246     {									\
247       const void *string_ = (String);					\
248       done = outstring_func (s, string_, (Len), done);			\
249       if (done < 0)							\
250 	goto all_done;							\
251     }									\
252    while (0)
253 
254 /* Write the string SRC to S.  If PREC is non-negative, write at most
255    PREC bytes.  If LEFT is true, perform left justification.  */
256 static int
outstring_converted_wide_string(FILE * s,const OTHER_CHAR_T * src,int prec,int width,bool left,int done)257 outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
258 				 int width, bool left, int done)
259 {
260   /* Use a small buffer to combine processing of multiple characters.
261      CONVERT_FROM_OTHER_STRING expects the buffer size in (wide)
262      characters, and buf_length counts that.  */
263   enum { buf_length = 256 / sizeof (CHAR_T) };
264   CHAR_T buf[buf_length];
265   _Static_assert (sizeof (buf) > MB_LEN_MAX,
266 		  "buffer is large enough for a single multi-byte character");
267 
268   /* Add the initial padding if needed.  */
269   if (width > 0 && !left)
270     {
271       /* Make a first pass to find the output width, so that we can
272 	 add the required padding.  */
273       mbstate_t mbstate = { 0 };
274       const OTHER_CHAR_T *src_copy = src;
275       size_t total_written;
276       if (prec < 0)
277 	total_written = CONVERT_FROM_OTHER_STRING
278 	  (NULL, &src_copy, 0, &mbstate);
279       else
280 	{
281 	  /* The source might not be null-terminated.  Enforce the
282 	     limit manually, based on the output length.  */
283 	  total_written = 0;
284 	  size_t limit = prec;
285 	  while (limit > 0 && src_copy != NULL)
286 	    {
287 	      size_t write_limit = buf_length;
288 	      if (write_limit > limit)
289 		write_limit = limit;
290 	      size_t written = CONVERT_FROM_OTHER_STRING
291 		(buf, &src_copy, write_limit, &mbstate);
292 	      if (written == (size_t) -1)
293 		return -1;
294 	      if (written == 0)
295 		break;
296 	      total_written += written;
297 	      limit -= written;
298 	    }
299 	}
300 
301       /* Output initial padding.  */
302       if (total_written < width)
303 	{
304 	  done = pad_func (s, L_(' '), width - total_written, done);
305 	  if (done < 0)
306 	    return done;
307 	}
308     }
309 
310   /* Convert the input string, piece by piece.  */
311   size_t total_written = 0;
312   {
313     mbstate_t mbstate = { 0 };
314     /* If prec is negative, remaining is not decremented, otherwise,
315       it serves as the write limit.  */
316     size_t remaining = -1;
317     if (prec >= 0)
318       remaining = prec;
319     while (remaining > 0 && src != NULL)
320       {
321 	size_t write_limit = buf_length;
322 	if (remaining < write_limit)
323 	  write_limit = remaining;
324 	size_t written = CONVERT_FROM_OTHER_STRING
325 	  (buf, &src, write_limit, &mbstate);
326 	if (written == (size_t) -1)
327 	  return -1;
328 	if (written == 0)
329 	  break;
330 	done = outstring_func (s, (const UCHAR_T *) buf, written, done);
331 	if (done < 0)
332 	  return done;
333 	total_written += written;
334 	if (prec >= 0)
335 	  remaining -= written;
336       }
337   }
338 
339   /* Add final padding.  */
340   if (width > 0 && left && total_written < width)
341     return pad_func (s, L_(' '), width - total_written, done);
342   return done;
343 }
344 
345 /* Calls __printf_fp or __printf_fphex based on the value of the
346    format specifier INFO->spec.  */
347 static inline int
__printf_fp_spec(FILE * fp,const struct printf_info * info,const void * const * args)348 __printf_fp_spec (FILE *fp, const struct printf_info *info,
349 		  const void *const *args)
350 {
351   if (info->spec == 'a' || info->spec == 'A')
352     return __printf_fphex (fp, info, args);
353   else
354     return __printf_fp (fp, info, args);
355 }
356 
357 /* For handling long_double and longlong we use the same flag.  If
358    `long' and `long long' are effectively the same type define it to
359    zero.  */
360 #if LONG_MAX == LONG_LONG_MAX
361 # define is_longlong 0
362 #else
363 # define is_longlong is_long_double
364 #endif
365 
366 /* If `long' and `int' is effectively the same type we don't have to
367    handle `long separately.  */
368 #if INT_MAX == LONG_MAX
369 # define is_long_num	0
370 #else
371 # define is_long_num	is_long
372 #endif
373 
374 
375 /* Global constants.  */
376 static const CHAR_T null[] = L_("(null)");
377 
378 /* Size of the work_buffer variable (in characters, not bytes.  */
379 enum { WORK_BUFFER_SIZE = 1000 / sizeof (CHAR_T) };
380 
381 /* This table maps a character into a number representing a class.  In
382    each step there is a destination label for each class.  */
383 static const uint8_t jump_table[] =
384   {
385     /* ' ' */  1,            0,            0, /* '#' */  4,
386 	       0, /* '%' */ 14,            0, /* '\''*/  6,
387 	       0,            0, /* '*' */  7, /* '+' */  2,
388 	       0, /* '-' */  3, /* '.' */  9,            0,
389     /* '0' */  5, /* '1' */  8, /* '2' */  8, /* '3' */  8,
390     /* '4' */  8, /* '5' */  8, /* '6' */  8, /* '7' */  8,
391     /* '8' */  8, /* '9' */  8,            0,            0,
392 	       0,            0,            0,            0,
393 	       0, /* 'A' */ 26, /* 'B' */ 30, /* 'C' */ 25,
394 	       0, /* 'E' */ 19, /* F */   19, /* 'G' */ 19,
395 	       0, /* 'I' */ 29,            0,            0,
396     /* 'L' */ 12,            0,            0,            0,
397 	       0,            0,            0, /* 'S' */ 21,
398 	       0,            0,            0,            0,
399     /* 'X' */ 18,            0, /* 'Z' */ 13,            0,
400 	       0,            0,            0,            0,
401 	       0, /* 'a' */ 26, /* 'b' */ 30, /* 'c' */ 20,
402     /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19,
403     /* 'h' */ 10, /* 'i' */ 15, /* 'j' */ 28,            0,
404     /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17,
405     /* 'p' */ 22, /* 'q' */ 12,            0, /* 's' */ 21,
406     /* 't' */ 27, /* 'u' */ 16,            0,            0,
407     /* 'x' */ 18,            0, /* 'z' */ 13
408   };
409 
410 #define NOT_IN_JUMP_RANGE(Ch) ((Ch) < L_(' ') || (Ch) > L_('z'))
411 #define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
412 #define LABEL(Name) do_##Name
413 #ifdef SHARED
414   /* 'int' is enough and it saves some space on 64 bit systems.  */
415 # define JUMP_TABLE_TYPE const int
416 # define JUMP_TABLE_BASE_LABEL do_form_unknown
417 # define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
418 # define JUMP(ChExpr, table)						      \
419       do								      \
420 	{								      \
421 	  int offset;							      \
422 	  void *ptr;							      \
423 	  spec = (ChExpr);						      \
424 	  offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)	      \
425 	    : table[CHAR_CLASS (spec)];					      \
426 	  ptr = &&JUMP_TABLE_BASE_LABEL + offset;			      \
427 	  goto *ptr;							      \
428 	}								      \
429       while (0)
430 #else
431 # define JUMP_TABLE_TYPE const void *const
432 # define REF(Name) &&do_##Name
433 # define JUMP(ChExpr, table)						      \
434       do								      \
435 	{								      \
436 	  const void *ptr;						      \
437 	  spec = (ChExpr);						      \
438 	  ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown)		      \
439 	    : table[CHAR_CLASS (spec)];					      \
440 	  goto *ptr;							      \
441 	}								      \
442       while (0)
443 #endif
444 
445 #define STEP0_3_TABLE							      \
446     /* Step 0: at the beginning.  */					      \
447     static JUMP_TABLE_TYPE step0_jumps[31] =				      \
448     {									      \
449       REF (form_unknown),						      \
450       REF (flag_space),		/* for ' ' */				      \
451       REF (flag_plus),		/* for '+' */				      \
452       REF (flag_minus),		/* for '-' */				      \
453       REF (flag_hash),		/* for '<hash>' */			      \
454       REF (flag_zero),		/* for '0' */				      \
455       REF (flag_quote),		/* for '\'' */				      \
456       REF (width_asterics),	/* for '*' */				      \
457       REF (width),		/* for '1'...'9' */			      \
458       REF (precision),		/* for '.' */				      \
459       REF (mod_half),		/* for 'h' */				      \
460       REF (mod_long),		/* for 'l' */				      \
461       REF (mod_longlong),	/* for 'L', 'q' */			      \
462       REF (mod_size_t),		/* for 'z', 'Z' */			      \
463       REF (form_percent),	/* for '%' */				      \
464       REF (form_integer),	/* for 'd', 'i' */			      \
465       REF (form_unsigned),	/* for 'u' */				      \
466       REF (form_octal),		/* for 'o' */				      \
467       REF (form_hexa),		/* for 'X', 'x' */			      \
468       REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
469       REF (form_character),	/* for 'c' */				      \
470       REF (form_string),	/* for 's', 'S' */			      \
471       REF (form_pointer),	/* for 'p' */				      \
472       REF (form_number),	/* for 'n' */				      \
473       REF (form_strerror),	/* for 'm' */				      \
474       REF (form_wcharacter),	/* for 'C' */				      \
475       REF (form_floathex),	/* for 'A', 'a' */			      \
476       REF (mod_ptrdiff_t),      /* for 't' */				      \
477       REF (mod_intmax_t),       /* for 'j' */				      \
478       REF (flag_i18n),		/* for 'I' */				      \
479       REF (form_binary),	/* for 'B', 'b' */			      \
480     };									      \
481     /* Step 1: after processing width.  */				      \
482     static JUMP_TABLE_TYPE step1_jumps[31] =				      \
483     {									      \
484       REF (form_unknown),						      \
485       REF (form_unknown),	/* for ' ' */				      \
486       REF (form_unknown),	/* for '+' */				      \
487       REF (form_unknown),	/* for '-' */				      \
488       REF (form_unknown),	/* for '<hash>' */			      \
489       REF (form_unknown),	/* for '0' */				      \
490       REF (form_unknown),	/* for '\'' */				      \
491       REF (form_unknown),	/* for '*' */				      \
492       REF (form_unknown),	/* for '1'...'9' */			      \
493       REF (precision),		/* for '.' */				      \
494       REF (mod_half),		/* for 'h' */				      \
495       REF (mod_long),		/* for 'l' */				      \
496       REF (mod_longlong),	/* for 'L', 'q' */			      \
497       REF (mod_size_t),		/* for 'z', 'Z' */			      \
498       REF (form_percent),	/* for '%' */				      \
499       REF (form_integer),	/* for 'd', 'i' */			      \
500       REF (form_unsigned),	/* for 'u' */				      \
501       REF (form_octal),		/* for 'o' */				      \
502       REF (form_hexa),		/* for 'X', 'x' */			      \
503       REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
504       REF (form_character),	/* for 'c' */				      \
505       REF (form_string),	/* for 's', 'S' */			      \
506       REF (form_pointer),	/* for 'p' */				      \
507       REF (form_number),	/* for 'n' */				      \
508       REF (form_strerror),	/* for 'm' */				      \
509       REF (form_wcharacter),	/* for 'C' */				      \
510       REF (form_floathex),	/* for 'A', 'a' */			      \
511       REF (mod_ptrdiff_t),      /* for 't' */				      \
512       REF (mod_intmax_t),       /* for 'j' */				      \
513       REF (form_unknown),       /* for 'I' */				      \
514       REF (form_binary),	/* for 'B', 'b' */			      \
515     };									      \
516     /* Step 2: after processing precision.  */				      \
517     static JUMP_TABLE_TYPE step2_jumps[31] =				      \
518     {									      \
519       REF (form_unknown),						      \
520       REF (form_unknown),	/* for ' ' */				      \
521       REF (form_unknown),	/* for '+' */				      \
522       REF (form_unknown),	/* for '-' */				      \
523       REF (form_unknown),	/* for '<hash>' */			      \
524       REF (form_unknown),	/* for '0' */				      \
525       REF (form_unknown),	/* for '\'' */				      \
526       REF (form_unknown),	/* for '*' */				      \
527       REF (form_unknown),	/* for '1'...'9' */			      \
528       REF (form_unknown),	/* for '.' */				      \
529       REF (mod_half),		/* for 'h' */				      \
530       REF (mod_long),		/* for 'l' */				      \
531       REF (mod_longlong),	/* for 'L', 'q' */			      \
532       REF (mod_size_t),		/* for 'z', 'Z' */			      \
533       REF (form_percent),	/* for '%' */				      \
534       REF (form_integer),	/* for 'd', 'i' */			      \
535       REF (form_unsigned),	/* for 'u' */				      \
536       REF (form_octal),		/* for 'o' */				      \
537       REF (form_hexa),		/* for 'X', 'x' */			      \
538       REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
539       REF (form_character),	/* for 'c' */				      \
540       REF (form_string),	/* for 's', 'S' */			      \
541       REF (form_pointer),	/* for 'p' */				      \
542       REF (form_number),	/* for 'n' */				      \
543       REF (form_strerror),	/* for 'm' */				      \
544       REF (form_wcharacter),	/* for 'C' */				      \
545       REF (form_floathex),	/* for 'A', 'a' */			      \
546       REF (mod_ptrdiff_t),      /* for 't' */				      \
547       REF (mod_intmax_t),       /* for 'j' */				      \
548       REF (form_unknown),       /* for 'I' */				      \
549       REF (form_binary),	/* for 'B', 'b' */			      \
550     };									      \
551     /* Step 3a: after processing first 'h' modifier.  */		      \
552     static JUMP_TABLE_TYPE step3a_jumps[31] =				      \
553     {									      \
554       REF (form_unknown),						      \
555       REF (form_unknown),	/* for ' ' */				      \
556       REF (form_unknown),	/* for '+' */				      \
557       REF (form_unknown),	/* for '-' */				      \
558       REF (form_unknown),	/* for '<hash>' */			      \
559       REF (form_unknown),	/* for '0' */				      \
560       REF (form_unknown),	/* for '\'' */				      \
561       REF (form_unknown),	/* for '*' */				      \
562       REF (form_unknown),	/* for '1'...'9' */			      \
563       REF (form_unknown),	/* for '.' */				      \
564       REF (mod_halfhalf),	/* for 'h' */				      \
565       REF (form_unknown),	/* for 'l' */				      \
566       REF (form_unknown),	/* for 'L', 'q' */			      \
567       REF (form_unknown),	/* for 'z', 'Z' */			      \
568       REF (form_percent),	/* for '%' */				      \
569       REF (form_integer),	/* for 'd', 'i' */			      \
570       REF (form_unsigned),	/* for 'u' */				      \
571       REF (form_octal),		/* for 'o' */				      \
572       REF (form_hexa),		/* for 'X', 'x' */			      \
573       REF (form_unknown),	/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
574       REF (form_unknown),	/* for 'c' */				      \
575       REF (form_unknown),	/* for 's', 'S' */			      \
576       REF (form_unknown),	/* for 'p' */				      \
577       REF (form_number),	/* for 'n' */				      \
578       REF (form_unknown),	/* for 'm' */				      \
579       REF (form_unknown),	/* for 'C' */				      \
580       REF (form_unknown),	/* for 'A', 'a' */			      \
581       REF (form_unknown),       /* for 't' */				      \
582       REF (form_unknown),       /* for 'j' */				      \
583       REF (form_unknown),       /* for 'I' */				      \
584       REF (form_binary),	/* for 'B', 'b' */			      \
585     };									      \
586     /* Step 3b: after processing first 'l' modifier.  */		      \
587     static JUMP_TABLE_TYPE step3b_jumps[31] =				      \
588     {									      \
589       REF (form_unknown),						      \
590       REF (form_unknown),	/* for ' ' */				      \
591       REF (form_unknown),	/* for '+' */				      \
592       REF (form_unknown),	/* for '-' */				      \
593       REF (form_unknown),	/* for '<hash>' */			      \
594       REF (form_unknown),	/* for '0' */				      \
595       REF (form_unknown),	/* for '\'' */				      \
596       REF (form_unknown),	/* for '*' */				      \
597       REF (form_unknown),	/* for '1'...'9' */			      \
598       REF (form_unknown),	/* for '.' */				      \
599       REF (form_unknown),	/* for 'h' */				      \
600       REF (mod_longlong),	/* for 'l' */				      \
601       REF (form_unknown),	/* for 'L', 'q' */			      \
602       REF (form_unknown),	/* for 'z', 'Z' */			      \
603       REF (form_percent),	/* for '%' */				      \
604       REF (form_integer),	/* for 'd', 'i' */			      \
605       REF (form_unsigned),	/* for 'u' */				      \
606       REF (form_octal),		/* for 'o' */				      \
607       REF (form_hexa),		/* for 'X', 'x' */			      \
608       REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
609       REF (form_character),	/* for 'c' */				      \
610       REF (form_string),	/* for 's', 'S' */			      \
611       REF (form_pointer),	/* for 'p' */				      \
612       REF (form_number),	/* for 'n' */				      \
613       REF (form_strerror),	/* for 'm' */				      \
614       REF (form_wcharacter),	/* for 'C' */				      \
615       REF (form_floathex),	/* for 'A', 'a' */			      \
616       REF (form_unknown),       /* for 't' */				      \
617       REF (form_unknown),       /* for 'j' */				      \
618       REF (form_unknown),       /* for 'I' */				      \
619       REF (form_binary),	/* for 'B', 'b' */			      \
620     }
621 
622 #define STEP4_TABLE							      \
623     /* Step 4: processing format specifier.  */				      \
624     static JUMP_TABLE_TYPE step4_jumps[31] =				      \
625     {									      \
626       REF (form_unknown),						      \
627       REF (form_unknown),	/* for ' ' */				      \
628       REF (form_unknown),	/* for '+' */				      \
629       REF (form_unknown),	/* for '-' */				      \
630       REF (form_unknown),	/* for '<hash>' */			      \
631       REF (form_unknown),	/* for '0' */				      \
632       REF (form_unknown),	/* for '\'' */				      \
633       REF (form_unknown),	/* for '*' */				      \
634       REF (form_unknown),	/* for '1'...'9' */			      \
635       REF (form_unknown),	/* for '.' */				      \
636       REF (form_unknown),	/* for 'h' */				      \
637       REF (form_unknown),	/* for 'l' */				      \
638       REF (form_unknown),	/* for 'L', 'q' */			      \
639       REF (form_unknown),	/* for 'z', 'Z' */			      \
640       REF (form_percent),	/* for '%' */				      \
641       REF (form_integer),	/* for 'd', 'i' */			      \
642       REF (form_unsigned),	/* for 'u' */				      \
643       REF (form_octal),		/* for 'o' */				      \
644       REF (form_hexa),		/* for 'X', 'x' */			      \
645       REF (form_float),		/* for 'E', 'e', 'F', 'f', 'G', 'g' */	      \
646       REF (form_character),	/* for 'c' */				      \
647       REF (form_string),	/* for 's', 'S' */			      \
648       REF (form_pointer),	/* for 'p' */				      \
649       REF (form_number),	/* for 'n' */				      \
650       REF (form_strerror),	/* for 'm' */				      \
651       REF (form_wcharacter),	/* for 'C' */				      \
652       REF (form_floathex),	/* for 'A', 'a' */			      \
653       REF (form_unknown),       /* for 't' */				      \
654       REF (form_unknown),       /* for 'j' */				      \
655       REF (form_unknown),       /* for 'I' */				      \
656       REF (form_binary),	/* for 'B', 'b' */			      \
657     }
658 
659 /* Helper function to provide temporary buffering for unbuffered streams.  */
660 static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
661 			      unsigned int)
662      __THROW __attribute__ ((noinline));
663 
664 /* Handle positional format specifiers.  */
665 static int printf_positional (FILE *s,
666 			      const CHAR_T *format, int readonly_format,
667 			      va_list ap, va_list *ap_savep, int done,
668 			      int nspecs_done, const UCHAR_T *lead_str_end,
669 			      CHAR_T *work_buffer, int save_errno,
670 			      const char *grouping,
671 			      THOUSANDS_SEP_T thousands_sep,
672 			      unsigned int mode_flags);
673 
674 /* Handle unknown format specifier.  */
675 static int printf_unknown (FILE *, const struct printf_info *) __THROW;
676 
677 /* Group digits of number string.  */
678 static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
679 			     THOUSANDS_SEP_T);
680 
681 /* The function itself.  */
682 int
vfprintf(FILE * s,const CHAR_T * format,va_list ap,unsigned int mode_flags)683 vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
684 {
685   /* The character used as thousands separator.  */
686   THOUSANDS_SEP_T thousands_sep = 0;
687 
688   /* The string describing the size of groups of digits.  */
689   const char *grouping;
690 
691   /* Place to accumulate the result.  */
692   int done;
693 
694   /* Current character in format string.  */
695   const UCHAR_T *f;
696 
697   /* End of leading constant string.  */
698   const UCHAR_T *lead_str_end;
699 
700   /* Points to next format specifier.  */
701   const UCHAR_T *end_of_spec;
702 
703   /* Buffer intermediate results.  */
704   CHAR_T work_buffer[WORK_BUFFER_SIZE];
705   CHAR_T *workend;
706 
707   /* We have to save the original argument pointer.  */
708   va_list ap_save;
709 
710   /* Count number of specifiers we already processed.  */
711   int nspecs_done;
712 
713   /* For the %m format we may need the current `errno' value.  */
714   int save_errno = errno;
715 
716   /* 1 if format is in read-only memory, -1 if it is in writable memory,
717      0 if unknown.  */
718   int readonly_format = 0;
719 
720   /* Orient the stream.  */
721 #ifdef ORIENT
722   ORIENT;
723 #endif
724 
725   /* Sanity check of arguments.  */
726   ARGCHECK (s, format);
727 
728 #ifdef ORIENT
729   /* Check for correct orientation.  */
730   if (_IO_vtable_offset (s) == 0
731       && _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
732       != (sizeof (CHAR_T) == 1 ? -1 : 1))
733     /* The stream is already oriented otherwise.  */
734     return EOF;
735 #endif
736 
737   if (UNBUFFERED_P (s))
738     /* Use a helper function which will allocate a local temporary buffer
739        for the stream and then call us again.  */
740     return buffered_vfprintf (s, format, ap, mode_flags);
741 
742   /* Initialize local variables.  */
743   done = 0;
744   grouping = (const char *) -1;
745 #ifdef __va_copy
746   /* This macro will be available soon in gcc's <stdarg.h>.  We need it
747      since on some systems `va_list' is not an integral type.  */
748   __va_copy (ap_save, ap);
749 #else
750   ap_save = ap;
751 #endif
752   nspecs_done = 0;
753 
754 #ifdef COMPILE_WPRINTF
755   /* Find the first format specifier.  */
756   f = lead_str_end = __find_specwc ((const UCHAR_T *) format);
757 #else
758   /* Find the first format specifier.  */
759   f = lead_str_end = __find_specmb ((const UCHAR_T *) format);
760 #endif
761 
762   /* Lock stream.  */
763   _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
764   _IO_flockfile (s);
765 
766   /* Write the literal text before the first format.  */
767   outstring ((const UCHAR_T *) format,
768 	     lead_str_end - (const UCHAR_T *) format);
769 
770   /* If we only have to print a simple string, return now.  */
771   if (*f == L_('\0'))
772     goto all_done;
773 
774   /* Use the slow path in case any printf handler is registered.  */
775   if (__glibc_unlikely (__printf_function_table != NULL
776 			|| __printf_modifier_table != NULL
777 			|| __printf_va_arg_table != NULL))
778     goto do_positional;
779 
780   /* Process whole format string.  */
781   do
782     {
783       STEP0_3_TABLE;
784       STEP4_TABLE;
785 
786       int is_negative;	/* Flag for negative number.  */
787       union
788       {
789 	unsigned long long int longlong;
790 	unsigned long int word;
791       } number;
792       int base;
793       union printf_arg the_arg;
794       CHAR_T *string;	/* Pointer to argument string.  */
795       int alt = 0;	/* Alternate format.  */
796       int space = 0;	/* Use space prefix if no sign is needed.  */
797       int left = 0;	/* Left-justify output.  */
798       int showsign = 0;	/* Always begin with plus or minus sign.  */
799       int group = 0;	/* Print numbers according grouping rules.  */
800       /* Argument is long double/long long int.  Only used if
801 	 double/long double or long int/long long int are distinct.  */
802       int is_long_double __attribute__ ((unused)) = 0;
803       int is_short = 0;	/* Argument is short int.  */
804       int is_long = 0;	/* Argument is long int.  */
805       int is_char = 0;	/* Argument is promoted (unsigned) char.  */
806       int width = 0;	/* Width of output; 0 means none specified.  */
807       int prec = -1;	/* Precision of output; -1 means none specified.  */
808       /* This flag is set by the 'I' modifier and selects the use of the
809 	 `outdigits' as determined by the current locale.  */
810       int use_outdigits = 0;
811       UCHAR_T pad = L_(' ');/* Padding character.  */
812       CHAR_T spec;
813 
814       workend = work_buffer + WORK_BUFFER_SIZE;
815 
816       /* Get current character in format string.  */
817       JUMP (*++f, step0_jumps);
818 
819       /* ' ' flag.  */
820     LABEL (flag_space):
821       space = 1;
822       JUMP (*++f, step0_jumps);
823 
824       /* '+' flag.  */
825     LABEL (flag_plus):
826       showsign = 1;
827       JUMP (*++f, step0_jumps);
828 
829       /* The '-' flag.  */
830     LABEL (flag_minus):
831       left = 1;
832       pad = L_(' ');
833       JUMP (*++f, step0_jumps);
834 
835       /* The '#' flag.  */
836     LABEL (flag_hash):
837       alt = 1;
838       JUMP (*++f, step0_jumps);
839 
840       /* The '0' flag.  */
841     LABEL (flag_zero):
842       if (!left)
843 	pad = L_('0');
844       JUMP (*++f, step0_jumps);
845 
846       /* The '\'' flag.  */
847     LABEL (flag_quote):
848       group = 1;
849 
850       if (grouping == (const char *) -1)
851 	{
852 #ifdef COMPILE_WPRINTF
853 	  thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
854 					    _NL_NUMERIC_THOUSANDS_SEP_WC);
855 #else
856 	  thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
857 #endif
858 
859 	  grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
860 	  if (*grouping == '\0' || *grouping == CHAR_MAX
861 #ifdef COMPILE_WPRINTF
862 	      || thousands_sep == L'\0'
863 #else
864 	      || *thousands_sep == '\0'
865 #endif
866 	      )
867 	    grouping = NULL;
868 	}
869       JUMP (*++f, step0_jumps);
870 
871     LABEL (flag_i18n):
872       use_outdigits = 1;
873       JUMP (*++f, step0_jumps);
874 
875       /* Get width from argument.  */
876     LABEL (width_asterics):
877       {
878 	const UCHAR_T *tmp;	/* Temporary value.  */
879 
880 	tmp = ++f;
881 	if (ISDIGIT (*tmp))
882 	  {
883 	    int pos = read_int (&tmp);
884 
885 	    if (pos == -1)
886 	      {
887 		__set_errno (EOVERFLOW);
888 		done = -1;
889 		goto all_done;
890 	      }
891 
892 	    if (pos && *tmp == L_('$'))
893 	      /* The width comes from a positional parameter.  */
894 	      goto do_positional;
895 	  }
896 	width = va_arg (ap, int);
897 
898 	/* Negative width means left justified.  */
899 	if (width < 0)
900 	  {
901 	    width = -width;
902 	    pad = L_(' ');
903 	    left = 1;
904 	  }
905       }
906       JUMP (*f, step1_jumps);
907 
908       /* Given width in format string.  */
909     LABEL (width):
910       width = read_int (&f);
911 
912       if (__glibc_unlikely (width == -1))
913 	{
914 	  __set_errno (EOVERFLOW);
915 	  done = -1;
916 	  goto all_done;
917 	}
918 
919       if (*f == L_('$'))
920 	/* Oh, oh.  The argument comes from a positional parameter.  */
921 	goto do_positional;
922       JUMP (*f, step1_jumps);
923 
924     LABEL (precision):
925       ++f;
926       if (*f == L_('*'))
927 	{
928 	  const UCHAR_T *tmp;	/* Temporary value.  */
929 
930 	  tmp = ++f;
931 	  if (ISDIGIT (*tmp))
932 	    {
933 	      int pos = read_int (&tmp);
934 
935 	      if (pos == -1)
936 		{
937 		  __set_errno (EOVERFLOW);
938 		  done = -1;
939 		  goto all_done;
940 		}
941 
942 	      if (pos && *tmp == L_('$'))
943 		/* The precision comes from a positional parameter.  */
944 		goto do_positional;
945 	    }
946 	  prec = va_arg (ap, int);
947 
948 	  /* If the precision is negative the precision is omitted.  */
949 	  if (prec < 0)
950 	    prec = -1;
951 	}
952       else if (ISDIGIT (*f))
953 	{
954 	  prec = read_int (&f);
955 
956 	  /* The precision was specified in this case as an extremely
957 	     large positive value.  */
958 	  if (prec == -1)
959 	    {
960 	      __set_errno (EOVERFLOW);
961 	      done = -1;
962 	      goto all_done;
963 	    }
964 	}
965       else
966 	prec = 0;
967       JUMP (*f, step2_jumps);
968 
969       /* Process 'h' modifier.  There might another 'h' following.  */
970     LABEL (mod_half):
971       is_short = 1;
972       JUMP (*++f, step3a_jumps);
973 
974       /* Process 'hh' modifier.  */
975     LABEL (mod_halfhalf):
976       is_short = 0;
977       is_char = 1;
978       JUMP (*++f, step4_jumps);
979 
980       /* Process 'l' modifier.  There might another 'l' following.  */
981     LABEL (mod_long):
982       is_long = 1;
983       JUMP (*++f, step3b_jumps);
984 
985       /* Process 'L', 'q', or 'll' modifier.  No other modifier is
986 	 allowed to follow.  */
987     LABEL (mod_longlong):
988       is_long_double = 1;
989       is_long = 1;
990       JUMP (*++f, step4_jumps);
991 
992     LABEL (mod_size_t):
993       is_long_double = sizeof (size_t) > sizeof (unsigned long int);
994       is_long = sizeof (size_t) > sizeof (unsigned int);
995       JUMP (*++f, step4_jumps);
996 
997     LABEL (mod_ptrdiff_t):
998       is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);
999       is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
1000       JUMP (*++f, step4_jumps);
1001 
1002     LABEL (mod_intmax_t):
1003       is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);
1004       is_long = sizeof (intmax_t) > sizeof (unsigned int);
1005       JUMP (*++f, step4_jumps);
1006 
1007       /* Process current format.  */
1008       while (1)
1009 	{
1010 #define process_arg_int() va_arg (ap, int)
1011 #define process_arg_long_int() va_arg (ap, long int)
1012 #define process_arg_long_long_int() va_arg (ap, long long int)
1013 #define process_arg_pointer() va_arg (ap, void *)
1014 #define process_arg_string() va_arg (ap, const char *)
1015 #define process_arg_unsigned_int() va_arg (ap, unsigned int)
1016 #define process_arg_unsigned_long_int() va_arg (ap, unsigned long int)
1017 #define process_arg_unsigned_long_long_int() va_arg (ap, unsigned long long int)
1018 #define process_arg_wchar_t() va_arg (ap, wchar_t)
1019 #define process_arg_wstring() va_arg (ap, const wchar_t *)
1020 #include "vfprintf-process-arg.c"
1021 #undef process_arg_int
1022 #undef process_arg_long_int
1023 #undef process_arg_long_long_int
1024 #undef process_arg_pointer
1025 #undef process_arg_string
1026 #undef process_arg_unsigned_int
1027 #undef process_arg_unsigned_long_int
1028 #undef process_arg_unsigned_long_long_int
1029 #undef process_arg_wchar_t
1030 #undef process_arg_wstring
1031 
1032 	LABEL (form_float):
1033 	LABEL (form_floathex):
1034 	  {
1035 	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
1036 	      is_long_double = 0;
1037 
1038 	    struct printf_info info =
1039 	      {
1040 		.prec = prec,
1041 		.width = width,
1042 		.spec = spec,
1043 		.is_long_double = is_long_double,
1044 		.is_short = is_short,
1045 		.is_long = is_long,
1046 		.alt = alt,
1047 		.space = space,
1048 		.left = left,
1049 		.showsign = showsign,
1050 		.group = group,
1051 		.pad = pad,
1052 		.extra = 0,
1053 		.i18n = use_outdigits,
1054 		.wide = sizeof (CHAR_T) != 1,
1055 		.is_binary128 = 0
1056 	      };
1057 
1058 	    PARSE_FLOAT_VA_ARG_EXTENDED (info);
1059 	    const void *ptr = &the_arg;
1060 
1061 	    int function_done = __printf_fp_spec (s, &info, &ptr);
1062 	    if (function_done < 0)
1063 	      {
1064 		done = -1;
1065 		goto all_done;
1066 	      }
1067 	    done_add (function_done);
1068 	  }
1069 	  break;
1070 
1071 	LABEL (form_unknown):
1072 	  if (spec == L_('\0'))
1073 	    {
1074 	      /* The format string ended before the specifier is complete.  */
1075 	      __set_errno (EINVAL);
1076 	      done = -1;
1077 	      goto all_done;
1078 	    }
1079 
1080 	  /* If we are in the fast loop force entering the complicated
1081 	     one.  */
1082 	  goto do_positional;
1083 	}
1084 
1085       /* The format is correctly handled.  */
1086       ++nspecs_done;
1087 
1088       /* Look for next format specifier.  */
1089 #ifdef COMPILE_WPRINTF
1090       f = __find_specwc ((end_of_spec = ++f));
1091 #else
1092       f = __find_specmb ((end_of_spec = ++f));
1093 #endif
1094 
1095       /* Write the following constant string.  */
1096       outstring (end_of_spec, f - end_of_spec);
1097     }
1098   while (*f != L_('\0'));
1099 
1100   /* Unlock stream and return.  */
1101   goto all_done;
1102 
1103   /* Hand off processing for positional parameters.  */
1104 do_positional:
1105   done = printf_positional (s, format, readonly_format, ap, &ap_save,
1106 			    done, nspecs_done, lead_str_end, work_buffer,
1107 			    save_errno, grouping, thousands_sep, mode_flags);
1108 
1109  all_done:
1110   /* Unlock the stream.  */
1111   _IO_funlockfile (s);
1112   _IO_cleanup_region_end (0);
1113 
1114   return done;
1115 }
1116 
1117 static int
printf_positional(FILE * s,const CHAR_T * format,int readonly_format,va_list ap,va_list * ap_savep,int done,int nspecs_done,const UCHAR_T * lead_str_end,CHAR_T * work_buffer,int save_errno,const char * grouping,THOUSANDS_SEP_T thousands_sep,unsigned int mode_flags)1118 printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
1119 		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
1120 		   const UCHAR_T *lead_str_end,
1121 		   CHAR_T *work_buffer, int save_errno,
1122 		   const char *grouping, THOUSANDS_SEP_T thousands_sep,
1123 		   unsigned int mode_flags)
1124 {
1125   /* For positional argument handling.  */
1126   struct scratch_buffer specsbuf;
1127   scratch_buffer_init (&specsbuf);
1128   struct printf_spec *specs = specsbuf.data;
1129   size_t specs_limit = specsbuf.length / sizeof (specs[0]);
1130 
1131   /* Used as a backing store for args_value, args_size, args_type
1132      below.  */
1133   struct scratch_buffer argsbuf;
1134   scratch_buffer_init (&argsbuf);
1135 
1136   /* Array with information about the needed arguments.  This has to
1137      be dynamically extensible.  */
1138   size_t nspecs = 0;
1139 
1140   /* The number of arguments the format string requests.  This will
1141      determine the size of the array needed to store the argument
1142      attributes.  */
1143   size_t nargs = 0;
1144 
1145   /* Positional parameters refer to arguments directly.  This could
1146      also determine the maximum number of arguments.  Track the
1147      maximum number.  */
1148   size_t max_ref_arg = 0;
1149 
1150   /* Just a counter.  */
1151   size_t cnt;
1152 
1153   if (grouping == (const char *) -1)
1154     {
1155 #ifdef COMPILE_WPRINTF
1156       thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
1157 					_NL_NUMERIC_THOUSANDS_SEP_WC);
1158 #else
1159       thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
1160 #endif
1161 
1162       grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1163       if (*grouping == '\0' || *grouping == CHAR_MAX)
1164 	grouping = NULL;
1165     }
1166 
1167   for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
1168        f = specs[nspecs++].next_fmt)
1169     {
1170       if (nspecs == specs_limit)
1171 	{
1172 	  if (!scratch_buffer_grow_preserve (&specsbuf))
1173 	    {
1174 	      done = -1;
1175 	      goto all_done;
1176 	    }
1177 	  specs = specsbuf.data;
1178 	  specs_limit = specsbuf.length / sizeof (specs[0]);
1179 	}
1180 
1181       /* Parse the format specifier.  */
1182 #ifdef COMPILE_WPRINTF
1183       nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
1184 #else
1185       nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
1186 #endif
1187     }
1188 
1189   /* Determine the number of arguments the format string consumes.  */
1190   nargs = MAX (nargs, max_ref_arg);
1191 
1192   union printf_arg *args_value;
1193   int *args_size;
1194   int *args_type;
1195   {
1196     /* Calculate total size needed to represent a single argument
1197        across all three argument-related arrays.  */
1198     size_t bytes_per_arg
1199       = sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
1200     if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
1201       {
1202 	done = -1;
1203 	goto all_done;
1204       }
1205     args_value = argsbuf.data;
1206     /* Set up the remaining two arrays to each point past the end of
1207        the prior array, since space for all three has been allocated
1208        now.  */
1209     args_size = &args_value[nargs].pa_int;
1210     args_type = &args_size[nargs];
1211     memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0',
1212 	    nargs * sizeof (*args_type));
1213   }
1214 
1215   /* XXX Could do sanity check here: If any element in ARGS_TYPE is
1216      still zero after this loop, format is invalid.  For now we
1217      simply use 0 as the value.  */
1218 
1219   /* Fill in the types of all the arguments.  */
1220   for (cnt = 0; cnt < nspecs; ++cnt)
1221     {
1222       /* If the width is determined by an argument this is an int.  */
1223       if (specs[cnt].width_arg != -1)
1224 	args_type[specs[cnt].width_arg] = PA_INT;
1225 
1226       /* If the precision is determined by an argument this is an int.  */
1227       if (specs[cnt].prec_arg != -1)
1228 	args_type[specs[cnt].prec_arg] = PA_INT;
1229 
1230       switch (specs[cnt].ndata_args)
1231 	{
1232 	case 0:		/* No arguments.  */
1233 	  break;
1234 	case 1:		/* One argument; we already have the
1235 			   type and size.  */
1236 	  args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
1237 	  args_size[specs[cnt].data_arg] = specs[cnt].size;
1238 	  break;
1239 	default:
1240 	  /* We have more than one argument for this format spec.
1241 	     We must call the arginfo function again to determine
1242 	     all the types.  */
1243 	  (void) (*__printf_arginfo_table[specs[cnt].info.spec])
1244 	    (&specs[cnt].info,
1245 	     specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
1246 	     &args_size[specs[cnt].data_arg]);
1247 	  break;
1248 	}
1249     }
1250 
1251   /* Now we know all the types and the order.  Fill in the argument
1252      values.  */
1253   for (cnt = 0; cnt < nargs; ++cnt)
1254     switch (args_type[cnt])
1255       {
1256 #define T(tag, mem, type)				\
1257 	case tag:					\
1258 	  args_value[cnt].mem = va_arg (*ap_savep, type); \
1259 	  break
1260 
1261 	T (PA_WCHAR, pa_wchar, wint_t);
1262       case PA_CHAR:				/* Promoted.  */
1263       case PA_INT|PA_FLAG_SHORT:		/* Promoted.  */
1264 #if LONG_MAX == INT_MAX
1265       case PA_INT|PA_FLAG_LONG:
1266 #endif
1267 	T (PA_INT, pa_int, int);
1268 #if LONG_MAX == LONG_LONG_MAX
1269       case PA_INT|PA_FLAG_LONG:
1270 #endif
1271 	T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
1272 #if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX
1273 # error "he?"
1274 #endif
1275       case PA_FLOAT:				/* Promoted.  */
1276 	T (PA_DOUBLE, pa_double, double);
1277       case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
1278 	if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
1279 	  {
1280 	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
1281 	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
1282 	  }
1283 #if __HAVE_FLOAT128_UNLIKE_LDBL
1284 	else if ((mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0)
1285 	  args_value[cnt].pa_float128 = va_arg (*ap_savep, _Float128);
1286 #endif
1287 	else
1288 	  args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
1289 	break;
1290       case PA_STRING:				/* All pointers are the same */
1291       case PA_WSTRING:			/* All pointers are the same */
1292 	T (PA_POINTER, pa_pointer, void *);
1293 #undef T
1294       default:
1295 	if ((args_type[cnt] & PA_FLAG_PTR) != 0)
1296 	  args_value[cnt].pa_pointer = va_arg (*ap_savep, void *);
1297 	else if (__glibc_unlikely (__printf_va_arg_table != NULL)
1298 		 && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
1299 	  {
1300 	    args_value[cnt].pa_user = alloca (args_size[cnt]);
1301 	    (*__printf_va_arg_table[args_type[cnt] - PA_LAST])
1302 	      (args_value[cnt].pa_user, ap_savep);
1303 	  }
1304 	else
1305 	  memset (&args_value[cnt], 0, sizeof (args_value[cnt]));
1306 	break;
1307       case -1:
1308 	/* Error case.  Not all parameters appear in N$ format
1309 	   strings.  We have no way to determine their type.  */
1310 	assert ((mode_flags & PRINTF_FORTIFY) != 0);
1311 	__libc_fatal ("*** invalid %N$ use detected ***\n");
1312       }
1313 
1314   /* Now walk through all format specifiers and process them.  */
1315   for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
1316     {
1317       STEP4_TABLE;
1318 
1319       int is_negative;
1320       union
1321       {
1322 	unsigned long long int longlong;
1323 	unsigned long int word;
1324       } number;
1325       int base;
1326       CHAR_T *string;		/* Pointer to argument string.  */
1327 
1328       /* Fill variables from values in struct.  */
1329       int alt = specs[nspecs_done].info.alt;
1330       int space = specs[nspecs_done].info.space;
1331       int left = specs[nspecs_done].info.left;
1332       int showsign = specs[nspecs_done].info.showsign;
1333       int group = specs[nspecs_done].info.group;
1334       int is_long_double __attribute__ ((unused))
1335 	= specs[nspecs_done].info.is_long_double;
1336       int is_short = specs[nspecs_done].info.is_short;
1337       int is_char = specs[nspecs_done].info.is_char;
1338       int is_long = specs[nspecs_done].info.is_long;
1339       int width = specs[nspecs_done].info.width;
1340       int prec = specs[nspecs_done].info.prec;
1341       int use_outdigits = specs[nspecs_done].info.i18n;
1342       char pad = specs[nspecs_done].info.pad;
1343       CHAR_T spec = specs[nspecs_done].info.spec;
1344 
1345       CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
1346 
1347       /* Fill in last information.  */
1348       if (specs[nspecs_done].width_arg != -1)
1349 	{
1350 	  /* Extract the field width from an argument.  */
1351 	  specs[nspecs_done].info.width =
1352 	    args_value[specs[nspecs_done].width_arg].pa_int;
1353 
1354 	  if (specs[nspecs_done].info.width < 0)
1355 	    /* If the width value is negative left justification is
1356 	       selected and the value is taken as being positive.  */
1357 	    {
1358 	      specs[nspecs_done].info.width *= -1;
1359 	      left = specs[nspecs_done].info.left = 1;
1360 	    }
1361 	  width = specs[nspecs_done].info.width;
1362 	}
1363 
1364       if (specs[nspecs_done].prec_arg != -1)
1365 	{
1366 	  /* Extract the precision from an argument.  */
1367 	  specs[nspecs_done].info.prec =
1368 	    args_value[specs[nspecs_done].prec_arg].pa_int;
1369 
1370 	  if (specs[nspecs_done].info.prec < 0)
1371 	    /* If the precision is negative the precision is
1372 	       omitted.  */
1373 	    specs[nspecs_done].info.prec = -1;
1374 
1375 	  prec = specs[nspecs_done].info.prec;
1376 	}
1377 
1378       /* Process format specifiers.  */
1379       while (1)
1380 	{
1381 	  int function_done;
1382 
1383 	  if (spec <= UCHAR_MAX
1384 	      && __printf_function_table != NULL
1385 	      && __printf_function_table[(size_t) spec] != NULL)
1386 	    {
1387 	      const void **ptr = alloca (specs[nspecs_done].ndata_args
1388 					 * sizeof (const void *));
1389 
1390 	      /* Fill in an array of pointers to the argument values.  */
1391 	      for (unsigned int i = 0; i < specs[nspecs_done].ndata_args;
1392 		   ++i)
1393 		ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
1394 
1395 	      /* Call the function.  */
1396 	      function_done = __printf_function_table[(size_t) spec]
1397 		(s, &specs[nspecs_done].info, ptr);
1398 
1399 	      if (function_done != -2)
1400 		{
1401 		  /* If an error occurred we don't have information
1402 		     about # of chars.  */
1403 		  if (function_done < 0)
1404 		    {
1405 		      /* Function has set errno.  */
1406 		      done = -1;
1407 		      goto all_done;
1408 		    }
1409 
1410 		  done_add (function_done);
1411 		  break;
1412 		}
1413 	    }
1414 
1415 	  JUMP (spec, step4_jumps);
1416 
1417 #define process_arg_data args_value[specs[nspecs_done].data_arg]
1418 #define process_arg_int() process_arg_data.pa_int
1419 #define process_arg_long_int() process_arg_data.pa_long_int
1420 #define process_arg_long_long_int() process_arg_data.pa_long_long_int
1421 #define process_arg_pointer() process_arg_data.pa_pointer
1422 #define process_arg_string() process_arg_data.pa_string
1423 #define process_arg_unsigned_int() process_arg_data.pa_u_int
1424 #define process_arg_unsigned_long_int() process_arg_data.pa_u_long_int
1425 #define process_arg_unsigned_long_long_int() process_arg_data.pa_u_long_long_int
1426 #define process_arg_wchar_t() process_arg_data.pa_wchar
1427 #define process_arg_wstring() process_arg_data.pa_wstring
1428 #include "vfprintf-process-arg.c"
1429 #undef process_arg_data
1430 #undef process_arg_int
1431 #undef process_arg_long_int
1432 #undef process_arg_long_long_int
1433 #undef process_arg_pointer
1434 #undef process_arg_string
1435 #undef process_arg_unsigned_int
1436 #undef process_arg_unsigned_long_int
1437 #undef process_arg_unsigned_long_long_int
1438 #undef process_arg_wchar_t
1439 #undef process_arg_wstring
1440 
1441 	  LABEL (form_float):
1442 	  LABEL (form_floathex):
1443 	  {
1444 	    const void *ptr
1445 	      = (const void *) &args_value[specs[nspecs_done].data_arg];
1446 	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
1447 	      {
1448 		specs[nspecs_done].data_arg_type = PA_DOUBLE;
1449 		specs[nspecs_done].info.is_long_double = 0;
1450 	      }
1451 	    SETUP_FLOAT128_INFO (specs[nspecs_done].info);
1452 
1453 	    int function_done
1454 	      = __printf_fp_spec (s, &specs[nspecs_done].info, &ptr);
1455 	    if (function_done < 0)
1456 	      {
1457 		/* Error in print handler; up to handler to set errno.  */
1458 		done = -1;
1459 		goto all_done;
1460 	      }
1461 	    done_add (function_done);
1462 	  }
1463 	  break;
1464 
1465 	  LABEL (form_unknown):
1466 	  {
1467 	    int function_done = printf_unknown (s, &specs[nspecs_done].info);
1468 
1469 	    /* If an error occurred we don't have information about #
1470 	       of chars.  */
1471 	    if (function_done < 0)
1472 	      {
1473 		/* Function has set errno.  */
1474 		done = -1;
1475 		goto all_done;
1476 	      }
1477 
1478 	    done_add (function_done);
1479 	  }
1480 	  break;
1481 	}
1482 
1483       /* Write the following constant string.  */
1484       outstring (specs[nspecs_done].end_of_fmt,
1485 		 specs[nspecs_done].next_fmt
1486 		 - specs[nspecs_done].end_of_fmt);
1487     }
1488  all_done:
1489   scratch_buffer_free (&argsbuf);
1490   scratch_buffer_free (&specsbuf);
1491   return done;
1492 }
1493 
1494 /* Handle an unknown format specifier.  This prints out a canonicalized
1495    representation of the format spec itself.  */
1496 static int
printf_unknown(FILE * s,const struct printf_info * info)1497 printf_unknown (FILE *s, const struct printf_info *info)
1498 {
1499   int done = 0;
1500   CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
1501   CHAR_T *const workend
1502     = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
1503   CHAR_T *w;
1504 
1505   outchar (L_('%'));
1506 
1507   if (info->alt)
1508     outchar (L_('#'));
1509   if (info->group)
1510     outchar (L_('\''));
1511   if (info->showsign)
1512     outchar (L_('+'));
1513   else if (info->space)
1514     outchar (L_(' '));
1515   if (info->left)
1516     outchar (L_('-'));
1517   if (info->pad == L_('0'))
1518     outchar (L_('0'));
1519   if (info->i18n)
1520     outchar (L_('I'));
1521 
1522   if (info->width != 0)
1523     {
1524       w = _itoa_word (info->width, workend, 10, 0);
1525       while (w < workend)
1526 	outchar (*w++);
1527     }
1528 
1529   if (info->prec != -1)
1530     {
1531       outchar (L_('.'));
1532       w = _itoa_word (info->prec, workend, 10, 0);
1533       while (w < workend)
1534 	outchar (*w++);
1535     }
1536 
1537   if (info->spec != L_('\0'))
1538     outchar (info->spec);
1539 
1540  all_done:
1541   return done;
1542 }
1543 
1544 /* Group the digits from W to REAR_PTR according to the grouping rules
1545    of the current locale.  The interpretation of GROUPING is as in
1546    `struct lconv' from <locale.h>.  The grouped number extends from
1547    the returned pointer until REAR_PTR.  FRONT_PTR to W is used as a
1548    scratch area.  */
1549 static CHAR_T *
group_number(CHAR_T * front_ptr,CHAR_T * w,CHAR_T * rear_ptr,const char * grouping,THOUSANDS_SEP_T thousands_sep)1550 group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
1551 	      const char *grouping, THOUSANDS_SEP_T thousands_sep)
1552 {
1553   /* Length of the current group.  */
1554   int len;
1555 #ifndef COMPILE_WPRINTF
1556   /* Length of the separator (in wide mode, the separator is always a
1557      single wide character).  */
1558   int tlen = strlen (thousands_sep);
1559 #endif
1560 
1561   /* We treat all negative values like CHAR_MAX.  */
1562 
1563   if (*grouping == CHAR_MAX || *grouping <= 0)
1564     /* No grouping should be done.  */
1565     return w;
1566 
1567   len = *grouping++;
1568 
1569   /* Copy existing string so that nothing gets overwritten.  */
1570   memmove (front_ptr, w, (rear_ptr - w) * sizeof (CHAR_T));
1571   CHAR_T *s = front_ptr + (rear_ptr - w);
1572 
1573   w = rear_ptr;
1574 
1575   /* Process all characters in the string.  */
1576   while (s > front_ptr)
1577     {
1578       *--w = *--s;
1579 
1580       if (--len == 0 && s > front_ptr)
1581 	{
1582 	  /* A new group begins.  */
1583 #ifdef COMPILE_WPRINTF
1584 	  if (w != s)
1585 	    *--w = thousands_sep;
1586 	  else
1587 	    /* Not enough room for the separator.  */
1588 	    goto copy_rest;
1589 #else
1590 	  int cnt = tlen;
1591 	  if (tlen < w - s)
1592 	    do
1593 	      *--w = thousands_sep[--cnt];
1594 	    while (cnt > 0);
1595 	  else
1596 	    /* Not enough room for the separator.  */
1597 	    goto copy_rest;
1598 #endif
1599 
1600 	  if (*grouping == CHAR_MAX
1601 #if CHAR_MIN < 0
1602 		   || *grouping < 0
1603 #endif
1604 		   )
1605 	    {
1606 	    copy_rest:
1607 	      /* No further grouping to be done.  Copy the rest of the
1608 		 number.  */
1609 	      w -= s - front_ptr;
1610 	      memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T));
1611 	      break;
1612 	    }
1613 	  else if (*grouping != '\0')
1614 	    len = *grouping++;
1615 	  else
1616 	    /* The previous grouping repeats ad infinitum.  */
1617 	    len = grouping[-1];
1618 	}
1619     }
1620   return w;
1621 }
1622 
1623 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
1624 struct helper_file
1625   {
1626     struct _IO_FILE_plus _f;
1627 #ifdef COMPILE_WPRINTF
1628     struct _IO_wide_data _wide_data;
1629 #endif
1630     FILE *_put_stream;
1631 #ifdef _IO_MTSAFE_IO
1632     _IO_lock_t lock;
1633 #endif
1634   };
1635 
1636 static int
_IO_helper_overflow(FILE * s,int c)1637 _IO_helper_overflow (FILE *s, int c)
1638 {
1639   FILE *target = ((struct helper_file*) s)->_put_stream;
1640 #ifdef COMPILE_WPRINTF
1641   int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
1642   if (used)
1643     {
1644       size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, used);
1645       if (written == 0 || written == WEOF)
1646 	return WEOF;
1647       __wmemmove (s->_wide_data->_IO_write_base,
1648 		  s->_wide_data->_IO_write_base + written,
1649 		  used - written);
1650       s->_wide_data->_IO_write_ptr -= written;
1651     }
1652 #else
1653   int used = s->_IO_write_ptr - s->_IO_write_base;
1654   if (used)
1655     {
1656       size_t written = _IO_sputn (target, s->_IO_write_base, used);
1657       if (written == 0 || written == EOF)
1658 	return EOF;
1659       memmove (s->_IO_write_base, s->_IO_write_base + written,
1660 	       used - written);
1661       s->_IO_write_ptr -= written;
1662     }
1663 #endif
1664   return PUTC (c, s);
1665 }
1666 
1667 #ifdef COMPILE_WPRINTF
1668 static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
1669 {
1670   JUMP_INIT_DUMMY,
1671   JUMP_INIT (finish, _IO_wdefault_finish),
1672   JUMP_INIT (overflow, _IO_helper_overflow),
1673   JUMP_INIT (underflow, _IO_default_underflow),
1674   JUMP_INIT (uflow, _IO_default_uflow),
1675   JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
1676   JUMP_INIT (xsputn, _IO_wdefault_xsputn),
1677   JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
1678   JUMP_INIT (seekoff, _IO_default_seekoff),
1679   JUMP_INIT (seekpos, _IO_default_seekpos),
1680   JUMP_INIT (setbuf, _IO_default_setbuf),
1681   JUMP_INIT (sync, _IO_default_sync),
1682   JUMP_INIT (doallocate, _IO_wdefault_doallocate),
1683   JUMP_INIT (read, _IO_default_read),
1684   JUMP_INIT (write, _IO_default_write),
1685   JUMP_INIT (seek, _IO_default_seek),
1686   JUMP_INIT (close, _IO_default_close),
1687   JUMP_INIT (stat, _IO_default_stat)
1688 };
1689 #else
1690 static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
1691 {
1692   JUMP_INIT_DUMMY,
1693   JUMP_INIT (finish, _IO_default_finish),
1694   JUMP_INIT (overflow, _IO_helper_overflow),
1695   JUMP_INIT (underflow, _IO_default_underflow),
1696   JUMP_INIT (uflow, _IO_default_uflow),
1697   JUMP_INIT (pbackfail, _IO_default_pbackfail),
1698   JUMP_INIT (xsputn, _IO_default_xsputn),
1699   JUMP_INIT (xsgetn, _IO_default_xsgetn),
1700   JUMP_INIT (seekoff, _IO_default_seekoff),
1701   JUMP_INIT (seekpos, _IO_default_seekpos),
1702   JUMP_INIT (setbuf, _IO_default_setbuf),
1703   JUMP_INIT (sync, _IO_default_sync),
1704   JUMP_INIT (doallocate, _IO_default_doallocate),
1705   JUMP_INIT (read, _IO_default_read),
1706   JUMP_INIT (write, _IO_default_write),
1707   JUMP_INIT (seek, _IO_default_seek),
1708   JUMP_INIT (close, _IO_default_close),
1709   JUMP_INIT (stat, _IO_default_stat)
1710 };
1711 #endif
1712 
1713 static int
buffered_vfprintf(FILE * s,const CHAR_T * format,va_list args,unsigned int mode_flags)1714 buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
1715 		   unsigned int mode_flags)
1716 {
1717   CHAR_T buf[BUFSIZ];
1718   struct helper_file helper;
1719   FILE *hp = (FILE *) &helper._f;
1720   int result, to_flush;
1721 
1722   /* Orient the stream.  */
1723 #ifdef ORIENT
1724   ORIENT;
1725 #endif
1726 
1727   /* Initialize helper.  */
1728   helper._put_stream = s;
1729 #ifdef COMPILE_WPRINTF
1730   hp->_wide_data = &helper._wide_data;
1731   _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
1732   hp->_mode = 1;
1733 #else
1734   _IO_setp (hp, buf, buf + sizeof buf);
1735   hp->_mode = -1;
1736 #endif
1737   hp->_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK;
1738 #if _IO_JUMPS_OFFSET
1739   hp->_vtable_offset = 0;
1740 #endif
1741 #ifdef _IO_MTSAFE_IO
1742   hp->_lock = NULL;
1743 #endif
1744   hp->_flags2 = s->_flags2;
1745   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
1746 
1747   /* Now print to helper instead.  */
1748   result = vfprintf (hp, format, args, mode_flags);
1749 
1750   /* Lock stream.  */
1751   __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
1752   _IO_flockfile (s);
1753 
1754   /* Now flush anything from the helper to the S. */
1755 #ifdef COMPILE_WPRINTF
1756   if ((to_flush = (hp->_wide_data->_IO_write_ptr
1757 		   - hp->_wide_data->_IO_write_base)) > 0)
1758     {
1759       if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
1760 	  != to_flush)
1761 	result = -1;
1762     }
1763 #else
1764   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
1765     {
1766       if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
1767 	result = -1;
1768     }
1769 #endif
1770 
1771   /* Unlock the stream.  */
1772   _IO_funlockfile (s);
1773   __libc_cleanup_region_end (0);
1774 
1775   return result;
1776 }
1777