1 /* Copyright (C) 1991-2021 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 /* Before invoking this macro, process_arg_int etc. macros have to be
660    defined to extract one argument of the appropriate type.  */
661 #define process_arg()						              \
662       /* Start real work.  We know about all flags and modifiers and	      \
663 	 now process the wanted format specifier.  */			      \
664     LABEL (form_percent):						      \
665       /* Write a literal "%".  */					      \
666       outchar (L_('%'));						      \
667       break;								      \
668 									      \
669     LABEL (form_integer):						      \
670       /* Signed decimal integer.  */					      \
671       base = 10;							      \
672 									      \
673       if (is_longlong)							      \
674 	{								      \
675 	  long long int signed_number = process_arg_long_long_int ();	      \
676 	  is_negative = signed_number < 0;				      \
677 	  number.longlong = is_negative ? (- signed_number) : signed_number;  \
678 									      \
679 	  goto LABEL (longlong_number);					      \
680 	}								      \
681       else								      \
682 	{								      \
683 	  long int signed_number;					      \
684 	  if (is_long_num)						      \
685 	    signed_number = process_arg_long_int ();			      \
686 	  else if (is_char)						      \
687 	    signed_number = (signed char) process_arg_unsigned_int ();	      \
688 	  else if (!is_short)						      \
689 	    signed_number = process_arg_int ();				      \
690 	  else								      \
691 	    signed_number = (short int) process_arg_unsigned_int ();	      \
692 									      \
693 	  is_negative = signed_number < 0;				      \
694 	  number.word = is_negative ? (- signed_number) : signed_number;      \
695 									      \
696 	  goto LABEL (number);						      \
697 	}								      \
698       /* NOTREACHED */							      \
699 									      \
700     LABEL (form_unsigned):						      \
701       /* Unsigned decimal integer.  */					      \
702       base = 10;							      \
703       goto LABEL (unsigned_number);					      \
704       /* NOTREACHED */							      \
705 									      \
706     LABEL (form_octal):							      \
707       /* Unsigned octal integer.  */					      \
708       base = 8;								      \
709       goto LABEL (unsigned_number);					      \
710       /* NOTREACHED */							      \
711 									      \
712     LABEL (form_hexa):							      \
713       /* Unsigned hexadecimal integer.  */				      \
714       base = 16;							      \
715       goto LABEL (unsigned_number);					      \
716       /* NOTREACHED */							      \
717 									      \
718     LABEL (form_binary):						      \
719       /* Unsigned binary integer.  */					      \
720       base = 2;								      \
721       goto LABEL (unsigned_number);					      \
722       /* NOTREACHED */							      \
723 									      \
724     LABEL (unsigned_number):	  /* Unsigned number of base BASE.  */	      \
725 									      \
726       /* ISO specifies the `+' and ` ' flags only for signed		      \
727 	 conversions.  */						      \
728       is_negative = 0;							      \
729       showsign = 0;							      \
730       space = 0;							      \
731 									      \
732       if (is_longlong)							      \
733 	{								      \
734 	  number.longlong = process_arg_unsigned_long_long_int ();	      \
735 									      \
736 	LABEL (longlong_number):					      \
737 	  if (prec < 0)							      \
738 	    /* Supply a default precision if none was given.  */	      \
739 	    prec = 1;							      \
740 	  else								      \
741 	    /* We have to take care for the '0' flag.  If a precision	      \
742 	       is given it must be ignored.  */				      \
743 	    pad = L_(' ');						      \
744 									      \
745 	  /* If the precision is 0 and the number is 0 nothing has to	      \
746 	     be written for the number, except for the 'o' format in	      \
747 	     alternate form.  */					      \
748 	  if (prec == 0 && number.longlong == 0)			      \
749 	    {								      \
750 	      string = workend;						      \
751 	      if (base == 8 && alt)					      \
752 		*--string = L_('0');					      \
753 	    }								      \
754 	  else								      \
755 	    {								      \
756 	      /* Put the number in WORK.  */				      \
757 	      string = _itoa (number.longlong, workend, base,		      \
758 			      spec == L_('X'));				      \
759 	      if (group && grouping)					      \
760 		string = group_number (work_buffer, string, workend,	      \
761 				       grouping, thousands_sep);	      \
762 	      if (use_outdigits && base == 10)				      \
763 		string = _i18n_number_rewrite (string, workend, workend);     \
764 	    }								      \
765 	  /* Simplify further test for num != 0.  */			      \
766 	  number.word = number.longlong != 0;				      \
767 	}								      \
768       else								      \
769 	{								      \
770 	  if (is_long_num)						      \
771 	    number.word = process_arg_unsigned_long_int ();		      \
772 	  else if (is_char)						      \
773 	    number.word = (unsigned char) process_arg_unsigned_int ();	      \
774 	  else if (!is_short)						      \
775 	    number.word = process_arg_unsigned_int ();			      \
776 	  else								      \
777 	    number.word = (unsigned short int) process_arg_unsigned_int ();   \
778 									      \
779 	LABEL (number):							      \
780 	  if (prec < 0)							      \
781 	    /* Supply a default precision if none was given.  */	      \
782 	    prec = 1;							      \
783 	  else								      \
784 	    /* We have to take care for the '0' flag.  If a precision	      \
785 	       is given it must be ignored.  */				      \
786 	    pad = L_(' ');						      \
787 									      \
788 	  /* If the precision is 0 and the number is 0 nothing has to	      \
789 	     be written for the number, except for the 'o' format in	      \
790 	     alternate form.  */					      \
791 	  if (prec == 0 && number.word == 0)				      \
792 	    {								      \
793 	      string = workend;						      \
794 	      if (base == 8 && alt)					      \
795 		*--string = L_('0');					      \
796 	    }								      \
797 	  else								      \
798 	    {								      \
799 	      /* Put the number in WORK.  */				      \
800 	      string = _itoa_word (number.word, workend, base,		      \
801 				   spec == L_('X'));			      \
802 	      if (group && grouping)					      \
803 		string = group_number (work_buffer, string, workend,	      \
804 				       grouping, thousands_sep);	      \
805 	      if (use_outdigits && base == 10)				      \
806 		string = _i18n_number_rewrite (string, workend, workend);     \
807 	    }								      \
808 	}								      \
809 									      \
810       if (prec <= workend - string && number.word != 0 && alt && base == 8)   \
811 	/* Add octal marker.  */					      \
812 	*--string = L_('0');						      \
813 									      \
814       prec = MAX (0, prec - (workend - string));			      \
815 									      \
816       if (!left)							      \
817 	{								      \
818 	  width -= workend - string + prec;				      \
819 									      \
820 	  if (number.word != 0 && alt && (base == 16 || base == 2))	      \
821 	    /* Account for 0X, 0x, 0B or 0b hex or binary marker.  */	      \
822 	    width -= 2;							      \
823 									      \
824 	  if (is_negative || showsign || space)				      \
825 	    --width;							      \
826 									      \
827 	  if (pad == L_(' '))						      \
828 	    {								      \
829 	      PAD (L_(' '));						      \
830 	      width = 0;						      \
831 	    }								      \
832 									      \
833 	  if (is_negative)						      \
834 	    outchar (L_('-'));						      \
835 	  else if (showsign)						      \
836 	    outchar (L_('+'));						      \
837 	  else if (space)						      \
838 	    outchar (L_(' '));						      \
839 									      \
840 	  if (number.word != 0 && alt && (base == 16 || base == 2))	      \
841 	    {								      \
842 	      outchar (L_('0'));					      \
843 	      outchar (spec);						      \
844 	    }								      \
845 									      \
846 	  width += prec;						      \
847 	  PAD (L_('0'));						      \
848 									      \
849 	  outstring (string, workend - string);				      \
850 									      \
851 	  break;							      \
852 	}								      \
853       else								      \
854 	{								      \
855 	  if (is_negative)						      \
856 	    {								      \
857 	      outchar (L_('-'));					      \
858 	      --width;							      \
859 	    }								      \
860 	  else if (showsign)						      \
861 	    {								      \
862 	      outchar (L_('+'));					      \
863 	      --width;							      \
864 	    }								      \
865 	  else if (space)						      \
866 	    {								      \
867 	      outchar (L_(' '));					      \
868 	      --width;							      \
869 	    }								      \
870 									      \
871 	  if (number.word != 0 && alt && (base == 16 || base == 2))	      \
872 	    {								      \
873 	      outchar (L_('0'));					      \
874 	      outchar (spec);						      \
875 	      width -= 2;						      \
876 	    }								      \
877 									      \
878 	  width -= workend - string + prec;				      \
879 									      \
880 	  if (prec > 0)							      \
881 	    {								      \
882 	      int temp = width;						      \
883 	      width = prec;						      \
884 	      PAD (L_('0'));						      \
885 	      width = temp;						      \
886 	    }								      \
887 									      \
888 	  outstring (string, workend - string);				      \
889 									      \
890 	  PAD (L_(' '));						      \
891 	  break;							      \
892 	}								      \
893 									      \
894     LABEL (form_pointer):						      \
895       /* Generic pointer.  */						      \
896       {									      \
897 	const void *ptr = process_arg_pointer ();			      \
898 	if (ptr != NULL)						      \
899 	  {								      \
900 	    /* If the pointer is not NULL, write it as a %#x spec.  */	      \
901 	    base = 16;							      \
902 	    number.word = (unsigned long int) ptr;			      \
903 	    is_negative = 0;						      \
904 	    alt = 1;							      \
905 	    group = 0;							      \
906 	    spec = L_('x');						      \
907 	    goto LABEL (number);					      \
908 	  }								      \
909 	else								      \
910 	  {								      \
911 	    /* Write "(nil)" for a nil pointer.  */			      \
912 	    string = (CHAR_T *) L_("(nil)");				      \
913 	    /* Make sure the full string "(nil)" is printed.  */	      \
914 	    if (prec < 5)						      \
915 	      prec = 5;							      \
916 	    /* This is a wide string iff compiling wprintf.  */		      \
917 	    is_long = sizeof (CHAR_T) > 1;				      \
918 	    goto LABEL (print_string);					      \
919 	  }								      \
920       }									      \
921       /* NOTREACHED */							      \
922 									      \
923     LABEL (form_number):						      \
924       if ((mode_flags & PRINTF_FORTIFY) != 0)				      \
925 	{								      \
926 	  if (! readonly_format)					      \
927 	    {								      \
928 	      extern int __readonly_area (const void *, size_t)		      \
929 		attribute_hidden;					      \
930 	      readonly_format						      \
931 		= __readonly_area (format, ((STR_LEN (format) + 1)	      \
932 					    * sizeof (CHAR_T)));	      \
933 	    }								      \
934 	  if (readonly_format < 0)					      \
935 	    __libc_fatal ("*** %n in writable segment detected ***\n");	      \
936 	}								      \
937       /* Answer the count of characters written.  */			      \
938       void *ptrptr = process_arg_pointer ();				      \
939       if (is_longlong)							      \
940 	*(long long int *) ptrptr = done;				      \
941       else if (is_long_num)						      \
942 	*(long int *) ptrptr = done;					      \
943       else if (is_char)							      \
944 	*(char *) ptrptr = done;					      \
945       else if (!is_short)						      \
946 	*(int *) ptrptr = done;						      \
947       else								      \
948 	*(short int *) ptrptr = done;					      \
949       break;								      \
950 									      \
951     LABEL (form_strerror):						      \
952       /* Print description of error ERRNO.  */				      \
953       if (alt)								      \
954 	string = (CHAR_T *) __get_errname (save_errno);			      \
955       else								      \
956 	string = (CHAR_T *) __strerror_r (save_errno, (char *) work_buffer,   \
957 					  WORK_BUFFER_SIZE * sizeof (CHAR_T));\
958       if (string == NULL)						\
959 	{								      \
960           /* Print as a decimal number. */				      \
961           base = 10;							      \
962 	  is_negative = save_errno < 0;					      \
963 	  number.word = save_errno;					      \
964 	  if (is_negative)						      \
965 	    number.word = -number.word;					      \
966 	  goto LABEL (number);						      \
967 	}								      \
968       else								      \
969 	{								      \
970 	  is_long = 0;	/* This is no wide-char string.  */		      \
971 	  goto LABEL (print_string);					      \
972 	}
973 
974 #ifdef COMPILE_WPRINTF
975 # define process_string_arg()						      \
976     LABEL (form_character):						      \
977       /* Character.  */							      \
978       if (is_long)							      \
979 	goto LABEL (form_wcharacter);					      \
980       --width;	/* Account for the character itself.  */		      \
981       if (!left)							      \
982 	PAD (L' ');							      \
983       outchar (__btowc ((unsigned char) process_arg_int ())); /* Promoted. */ \
984       if (left)								      \
985 	PAD (L' ');							      \
986       break;								      \
987 									      \
988     LABEL (form_wcharacter):						      \
989       {									      \
990 	/* Wide character.  */						      \
991 	--width;							      \
992 	if (!left)							      \
993 	  PAD (L' ');							      \
994 	outchar (process_arg_wchar_t ());				      \
995 	if (left)							      \
996 	  PAD (L' ');							      \
997       }									      \
998       break;								      \
999 									      \
1000     LABEL (form_string):						      \
1001       {									      \
1002 	size_t len;							      \
1003 									      \
1004 	/* The string argument could in fact be `char *' or `wchar_t *'.      \
1005 	   But this should not make a difference here.  */		      \
1006 	string = (CHAR_T *) process_arg_wstring ();			      \
1007 									      \
1008 	/* Entry point for printing other strings.  */			      \
1009       LABEL (print_string):						      \
1010 									      \
1011 	if (string == NULL)						      \
1012 	  {								      \
1013 	    /* Write "(null)" if there's space.  */			      \
1014 	    if (prec == -1 || prec >= (int) array_length (null) - 1)          \
1015 	      {								      \
1016 		string = (CHAR_T *) null;				      \
1017 		len = array_length (null) - 1;				      \
1018 	      }								      \
1019 	    else							      \
1020 	      {								      \
1021 		string = (CHAR_T *) L"";				      \
1022 		len = 0;						      \
1023 	      }								      \
1024 	  }								      \
1025 	else if (!is_long && spec != L_('S'))				      \
1026 	  {								      \
1027 	    done = outstring_converted_wide_string			      \
1028 	      (s, (const char *) string, prec, width, left, done);	      \
1029 	    if (done < 0)						      \
1030 	      goto all_done;						      \
1031 	    /* The padding has already been written.  */		      \
1032 	    break;							      \
1033 	  }								      \
1034 	else								      \
1035 	  {								      \
1036 	    if (prec != -1)						      \
1037 	      /* Search for the end of the string, but don't search past      \
1038 		 the length specified by the precision.  */		      \
1039 	      len = __wcsnlen (string, prec);				      \
1040 	    else							      \
1041 	      len = __wcslen (string);					      \
1042 	  }								      \
1043 									      \
1044 	if ((width -= len) < 0)						      \
1045 	  {								      \
1046 	    outstring (string, len);					      \
1047 	    break;							      \
1048 	  }								      \
1049 									      \
1050 	if (!left)							      \
1051 	  PAD (L' ');							      \
1052 	outstring (string, len);					      \
1053 	if (left)							      \
1054 	  PAD (L' ');							      \
1055       }									      \
1056       break;
1057 #else
1058 # define process_string_arg()						      \
1059     LABEL (form_character):						      \
1060       /* Character.  */							      \
1061       if (is_long)							      \
1062 	goto LABEL (form_wcharacter);					      \
1063       --width;	/* Account for the character itself.  */		      \
1064       if (!left)							      \
1065 	PAD (' ');							      \
1066       outchar ((unsigned char) process_arg_int ()); /* Promoted.  */	      \
1067       if (left)								      \
1068 	PAD (' ');							      \
1069       break;								      \
1070 									      \
1071     LABEL (form_wcharacter):						      \
1072       {									      \
1073 	/* Wide character.  */						      \
1074 	char buf[MB_LEN_MAX];						      \
1075 	mbstate_t mbstate;						      \
1076 	size_t len;							      \
1077 									      \
1078 	memset (&mbstate, '\0', sizeof (mbstate_t));			      \
1079 	len = __wcrtomb (buf, process_arg_wchar_t (), &mbstate);	      \
1080 	if (len == (size_t) -1)						      \
1081 	  {								      \
1082 	    /* Something went wrong during the conversion.  Bail out.  */     \
1083 	    done = -1;							      \
1084 	    goto all_done;						      \
1085 	  }								      \
1086 	width -= len;							      \
1087 	if (!left)							      \
1088 	  PAD (' ');							      \
1089 	outstring (buf, len);						      \
1090 	if (left)							      \
1091 	  PAD (' ');							      \
1092       }									      \
1093       break;								      \
1094 									      \
1095     LABEL (form_string):						      \
1096       {									      \
1097 	size_t len;							      \
1098 									      \
1099 	/* The string argument could in fact be `char *' or `wchar_t *'.      \
1100 	   But this should not make a difference here.  */		      \
1101 	string = (char *) process_arg_string ();			      \
1102 									      \
1103 	/* Entry point for printing other strings.  */			      \
1104       LABEL (print_string):						      \
1105 									      \
1106 	if (string == NULL)						      \
1107 	  {								      \
1108 	    /* Write "(null)" if there's space.  */			      \
1109 	    if (prec == -1 || prec >= (int) sizeof (null) - 1)		      \
1110 	      {								      \
1111 		string = (char *) null;					      \
1112 		len = sizeof (null) - 1;				      \
1113 	      }								      \
1114 	    else							      \
1115 	      {								      \
1116 		string = (char *) "";					      \
1117 		len = 0;						      \
1118 	      }								      \
1119 	  }								      \
1120 	else if (!is_long && spec != L_('S'))				      \
1121 	  {								      \
1122 	    if (prec != -1)						      \
1123 	      /* Search for the end of the string, but don't search past      \
1124 		 the length (in bytes) specified by the precision.  */	      \
1125 	      len = __strnlen (string, prec);				      \
1126 	    else							      \
1127 	      len = strlen (string);					      \
1128 	  }								      \
1129 	else								      \
1130 	  {								      \
1131 	    done = outstring_converted_wide_string			      \
1132 	      (s, (const wchar_t *) string, prec, width, left, done);	      \
1133 	    if (done < 0)						      \
1134 	      goto all_done;						      \
1135 	    /* The padding has already been written.  */		      \
1136 	    break;							      \
1137 	  }								      \
1138 									      \
1139 	if ((width -= len) < 0)						      \
1140 	  {								      \
1141 	    outstring (string, len);					      \
1142 	    break;							      \
1143 	  }								      \
1144 									      \
1145 	if (!left)							      \
1146 	  PAD (' ');							      \
1147 	outstring (string, len);					      \
1148 	if (left)							      \
1149 	  PAD (' ');							      \
1150       }									      \
1151       break;
1152 #endif
1153 
1154 /* Helper function to provide temporary buffering for unbuffered streams.  */
1155 static int buffered_vfprintf (FILE *stream, const CHAR_T *fmt, va_list,
1156 			      unsigned int)
1157      __THROW __attribute__ ((noinline));
1158 
1159 /* Handle positional format specifiers.  */
1160 static int printf_positional (FILE *s,
1161 			      const CHAR_T *format, int readonly_format,
1162 			      va_list ap, va_list *ap_savep, int done,
1163 			      int nspecs_done, const UCHAR_T *lead_str_end,
1164 			      CHAR_T *work_buffer, int save_errno,
1165 			      const char *grouping,
1166 			      THOUSANDS_SEP_T thousands_sep,
1167 			      unsigned int mode_flags);
1168 
1169 /* Handle unknown format specifier.  */
1170 static int printf_unknown (FILE *, const struct printf_info *,
1171 			   const void *const *) __THROW;
1172 
1173 /* Group digits of number string.  */
1174 static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
1175 			     THOUSANDS_SEP_T);
1176 
1177 /* The function itself.  */
1178 int
vfprintf(FILE * s,const CHAR_T * format,va_list ap,unsigned int mode_flags)1179 vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
1180 {
1181   /* The character used as thousands separator.  */
1182   THOUSANDS_SEP_T thousands_sep = 0;
1183 
1184   /* The string describing the size of groups of digits.  */
1185   const char *grouping;
1186 
1187   /* Place to accumulate the result.  */
1188   int done;
1189 
1190   /* Current character in format string.  */
1191   const UCHAR_T *f;
1192 
1193   /* End of leading constant string.  */
1194   const UCHAR_T *lead_str_end;
1195 
1196   /* Points to next format specifier.  */
1197   const UCHAR_T *end_of_spec;
1198 
1199   /* Buffer intermediate results.  */
1200   CHAR_T work_buffer[WORK_BUFFER_SIZE];
1201   CHAR_T *workend;
1202 
1203   /* We have to save the original argument pointer.  */
1204   va_list ap_save;
1205 
1206   /* Count number of specifiers we already processed.  */
1207   int nspecs_done;
1208 
1209   /* For the %m format we may need the current `errno' value.  */
1210   int save_errno = errno;
1211 
1212   /* 1 if format is in read-only memory, -1 if it is in writable memory,
1213      0 if unknown.  */
1214   int readonly_format = 0;
1215 
1216   /* Orient the stream.  */
1217 #ifdef ORIENT
1218   ORIENT;
1219 #endif
1220 
1221   /* Sanity check of arguments.  */
1222   ARGCHECK (s, format);
1223 
1224 #ifdef ORIENT
1225   /* Check for correct orientation.  */
1226   if (_IO_vtable_offset (s) == 0
1227       && _IO_fwide (s, sizeof (CHAR_T) == 1 ? -1 : 1)
1228       != (sizeof (CHAR_T) == 1 ? -1 : 1))
1229     /* The stream is already oriented otherwise.  */
1230     return EOF;
1231 #endif
1232 
1233   if (UNBUFFERED_P (s))
1234     /* Use a helper function which will allocate a local temporary buffer
1235        for the stream and then call us again.  */
1236     return buffered_vfprintf (s, format, ap, mode_flags);
1237 
1238   /* Initialize local variables.  */
1239   done = 0;
1240   grouping = (const char *) -1;
1241 #ifdef __va_copy
1242   /* This macro will be available soon in gcc's <stdarg.h>.  We need it
1243      since on some systems `va_list' is not an integral type.  */
1244   __va_copy (ap_save, ap);
1245 #else
1246   ap_save = ap;
1247 #endif
1248   nspecs_done = 0;
1249 
1250 #ifdef COMPILE_WPRINTF
1251   /* Find the first format specifier.  */
1252   f = lead_str_end = __find_specwc ((const UCHAR_T *) format);
1253 #else
1254   /* Find the first format specifier.  */
1255   f = lead_str_end = __find_specmb ((const UCHAR_T *) format);
1256 #endif
1257 
1258   /* Lock stream.  */
1259   _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
1260   _IO_flockfile (s);
1261 
1262   /* Write the literal text before the first format.  */
1263   outstring ((const UCHAR_T *) format,
1264 	     lead_str_end - (const UCHAR_T *) format);
1265 
1266   /* If we only have to print a simple string, return now.  */
1267   if (*f == L_('\0'))
1268     goto all_done;
1269 
1270   /* Use the slow path in case any printf handler is registered.  */
1271   if (__glibc_unlikely (__printf_function_table != NULL
1272 			|| __printf_modifier_table != NULL
1273 			|| __printf_va_arg_table != NULL))
1274     goto do_positional;
1275 
1276   /* Process whole format string.  */
1277   do
1278     {
1279       STEP0_3_TABLE;
1280       STEP4_TABLE;
1281 
1282       int is_negative;	/* Flag for negative number.  */
1283       union
1284       {
1285 	unsigned long long int longlong;
1286 	unsigned long int word;
1287       } number;
1288       int base;
1289       union printf_arg the_arg;
1290       CHAR_T *string;	/* Pointer to argument string.  */
1291       int alt = 0;	/* Alternate format.  */
1292       int space = 0;	/* Use space prefix if no sign is needed.  */
1293       int left = 0;	/* Left-justify output.  */
1294       int showsign = 0;	/* Always begin with plus or minus sign.  */
1295       int group = 0;	/* Print numbers according grouping rules.  */
1296       /* Argument is long double/long long int.  Only used if
1297 	 double/long double or long int/long long int are distinct.  */
1298       int is_long_double __attribute__ ((unused)) = 0;
1299       int is_short = 0;	/* Argument is short int.  */
1300       int is_long = 0;	/* Argument is long int.  */
1301       int is_char = 0;	/* Argument is promoted (unsigned) char.  */
1302       int width = 0;	/* Width of output; 0 means none specified.  */
1303       int prec = -1;	/* Precision of output; -1 means none specified.  */
1304       /* This flag is set by the 'I' modifier and selects the use of the
1305 	 `outdigits' as determined by the current locale.  */
1306       int use_outdigits = 0;
1307       UCHAR_T pad = L_(' ');/* Padding character.  */
1308       CHAR_T spec;
1309 
1310       workend = work_buffer + WORK_BUFFER_SIZE;
1311 
1312       /* Get current character in format string.  */
1313       JUMP (*++f, step0_jumps);
1314 
1315       /* ' ' flag.  */
1316     LABEL (flag_space):
1317       space = 1;
1318       JUMP (*++f, step0_jumps);
1319 
1320       /* '+' flag.  */
1321     LABEL (flag_plus):
1322       showsign = 1;
1323       JUMP (*++f, step0_jumps);
1324 
1325       /* The '-' flag.  */
1326     LABEL (flag_minus):
1327       left = 1;
1328       pad = L_(' ');
1329       JUMP (*++f, step0_jumps);
1330 
1331       /* The '#' flag.  */
1332     LABEL (flag_hash):
1333       alt = 1;
1334       JUMP (*++f, step0_jumps);
1335 
1336       /* The '0' flag.  */
1337     LABEL (flag_zero):
1338       if (!left)
1339 	pad = L_('0');
1340       JUMP (*++f, step0_jumps);
1341 
1342       /* The '\'' flag.  */
1343     LABEL (flag_quote):
1344       group = 1;
1345 
1346       if (grouping == (const char *) -1)
1347 	{
1348 #ifdef COMPILE_WPRINTF
1349 	  thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
1350 					    _NL_NUMERIC_THOUSANDS_SEP_WC);
1351 #else
1352 	  thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
1353 #endif
1354 
1355 	  grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1356 	  if (*grouping == '\0' || *grouping == CHAR_MAX
1357 #ifdef COMPILE_WPRINTF
1358 	      || thousands_sep == L'\0'
1359 #else
1360 	      || *thousands_sep == '\0'
1361 #endif
1362 	      )
1363 	    grouping = NULL;
1364 	}
1365       JUMP (*++f, step0_jumps);
1366 
1367     LABEL (flag_i18n):
1368       use_outdigits = 1;
1369       JUMP (*++f, step0_jumps);
1370 
1371       /* Get width from argument.  */
1372     LABEL (width_asterics):
1373       {
1374 	const UCHAR_T *tmp;	/* Temporary value.  */
1375 
1376 	tmp = ++f;
1377 	if (ISDIGIT (*tmp))
1378 	  {
1379 	    int pos = read_int (&tmp);
1380 
1381 	    if (pos == -1)
1382 	      {
1383 		__set_errno (EOVERFLOW);
1384 		done = -1;
1385 		goto all_done;
1386 	      }
1387 
1388 	    if (pos && *tmp == L_('$'))
1389 	      /* The width comes from a positional parameter.  */
1390 	      goto do_positional;
1391 	  }
1392 	width = va_arg (ap, int);
1393 
1394 	/* Negative width means left justified.  */
1395 	if (width < 0)
1396 	  {
1397 	    width = -width;
1398 	    pad = L_(' ');
1399 	    left = 1;
1400 	  }
1401       }
1402       JUMP (*f, step1_jumps);
1403 
1404       /* Given width in format string.  */
1405     LABEL (width):
1406       width = read_int (&f);
1407 
1408       if (__glibc_unlikely (width == -1))
1409 	{
1410 	  __set_errno (EOVERFLOW);
1411 	  done = -1;
1412 	  goto all_done;
1413 	}
1414 
1415       if (*f == L_('$'))
1416 	/* Oh, oh.  The argument comes from a positional parameter.  */
1417 	goto do_positional;
1418       JUMP (*f, step1_jumps);
1419 
1420     LABEL (precision):
1421       ++f;
1422       if (*f == L_('*'))
1423 	{
1424 	  const UCHAR_T *tmp;	/* Temporary value.  */
1425 
1426 	  tmp = ++f;
1427 	  if (ISDIGIT (*tmp))
1428 	    {
1429 	      int pos = read_int (&tmp);
1430 
1431 	      if (pos == -1)
1432 		{
1433 		  __set_errno (EOVERFLOW);
1434 		  done = -1;
1435 		  goto all_done;
1436 		}
1437 
1438 	      if (pos && *tmp == L_('$'))
1439 		/* The precision comes from a positional parameter.  */
1440 		goto do_positional;
1441 	    }
1442 	  prec = va_arg (ap, int);
1443 
1444 	  /* If the precision is negative the precision is omitted.  */
1445 	  if (prec < 0)
1446 	    prec = -1;
1447 	}
1448       else if (ISDIGIT (*f))
1449 	{
1450 	  prec = read_int (&f);
1451 
1452 	  /* The precision was specified in this case as an extremely
1453 	     large positive value.  */
1454 	  if (prec == -1)
1455 	    {
1456 	      __set_errno (EOVERFLOW);
1457 	      done = -1;
1458 	      goto all_done;
1459 	    }
1460 	}
1461       else
1462 	prec = 0;
1463       JUMP (*f, step2_jumps);
1464 
1465       /* Process 'h' modifier.  There might another 'h' following.  */
1466     LABEL (mod_half):
1467       is_short = 1;
1468       JUMP (*++f, step3a_jumps);
1469 
1470       /* Process 'hh' modifier.  */
1471     LABEL (mod_halfhalf):
1472       is_short = 0;
1473       is_char = 1;
1474       JUMP (*++f, step4_jumps);
1475 
1476       /* Process 'l' modifier.  There might another 'l' following.  */
1477     LABEL (mod_long):
1478       is_long = 1;
1479       JUMP (*++f, step3b_jumps);
1480 
1481       /* Process 'L', 'q', or 'll' modifier.  No other modifier is
1482 	 allowed to follow.  */
1483     LABEL (mod_longlong):
1484       is_long_double = 1;
1485       is_long = 1;
1486       JUMP (*++f, step4_jumps);
1487 
1488     LABEL (mod_size_t):
1489       is_long_double = sizeof (size_t) > sizeof (unsigned long int);
1490       is_long = sizeof (size_t) > sizeof (unsigned int);
1491       JUMP (*++f, step4_jumps);
1492 
1493     LABEL (mod_ptrdiff_t):
1494       is_long_double = sizeof (ptrdiff_t) > sizeof (unsigned long int);
1495       is_long = sizeof (ptrdiff_t) > sizeof (unsigned int);
1496       JUMP (*++f, step4_jumps);
1497 
1498     LABEL (mod_intmax_t):
1499       is_long_double = sizeof (intmax_t) > sizeof (unsigned long int);
1500       is_long = sizeof (intmax_t) > sizeof (unsigned int);
1501       JUMP (*++f, step4_jumps);
1502 
1503       /* Process current format.  */
1504       while (1)
1505 	{
1506 #define process_arg_int() va_arg (ap, int)
1507 #define process_arg_long_int() va_arg (ap, long int)
1508 #define process_arg_long_long_int() va_arg (ap, long long int)
1509 #define process_arg_pointer() va_arg (ap, void *)
1510 #define process_arg_string() va_arg (ap, const char *)
1511 #define process_arg_unsigned_int() va_arg (ap, unsigned int)
1512 #define process_arg_unsigned_long_int() va_arg (ap, unsigned long int)
1513 #define process_arg_unsigned_long_long_int() va_arg (ap, unsigned long long int)
1514 #define process_arg_wchar_t() va_arg (ap, wchar_t)
1515 #define process_arg_wstring() va_arg (ap, const wchar_t *)
1516 	  process_arg ();
1517 	  process_string_arg ();
1518 #undef process_arg_int
1519 #undef process_arg_long_int
1520 #undef process_arg_long_long_int
1521 #undef process_arg_pointer
1522 #undef process_arg_string
1523 #undef process_arg_unsigned_int
1524 #undef process_arg_unsigned_long_int
1525 #undef process_arg_unsigned_long_long_int
1526 #undef process_arg_wchar_t
1527 #undef process_arg_wstring
1528 
1529 	LABEL (form_float):
1530 	LABEL (form_floathex):
1531 	  {
1532 	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
1533 	      is_long_double = 0;
1534 
1535 	    struct printf_info info =
1536 	      {
1537 		.prec = prec,
1538 		.width = width,
1539 		.spec = spec,
1540 		.is_long_double = is_long_double,
1541 		.is_short = is_short,
1542 		.is_long = is_long,
1543 		.alt = alt,
1544 		.space = space,
1545 		.left = left,
1546 		.showsign = showsign,
1547 		.group = group,
1548 		.pad = pad,
1549 		.extra = 0,
1550 		.i18n = use_outdigits,
1551 		.wide = sizeof (CHAR_T) != 1,
1552 		.is_binary128 = 0
1553 	      };
1554 
1555 	    PARSE_FLOAT_VA_ARG_EXTENDED (info);
1556 	    const void *ptr = &the_arg;
1557 
1558 	    int function_done = __printf_fp_spec (s, &info, &ptr);
1559 	    if (function_done < 0)
1560 	      {
1561 		done = -1;
1562 		goto all_done;
1563 	      }
1564 	    done_add (function_done);
1565 	  }
1566 	  break;
1567 
1568 	LABEL (form_unknown):
1569 	  if (spec == L_('\0'))
1570 	    {
1571 	      /* The format string ended before the specifier is complete.  */
1572 	      __set_errno (EINVAL);
1573 	      done = -1;
1574 	      goto all_done;
1575 	    }
1576 
1577 	  /* If we are in the fast loop force entering the complicated
1578 	     one.  */
1579 	  goto do_positional;
1580 	}
1581 
1582       /* The format is correctly handled.  */
1583       ++nspecs_done;
1584 
1585       /* Look for next format specifier.  */
1586 #ifdef COMPILE_WPRINTF
1587       f = __find_specwc ((end_of_spec = ++f));
1588 #else
1589       f = __find_specmb ((end_of_spec = ++f));
1590 #endif
1591 
1592       /* Write the following constant string.  */
1593       outstring (end_of_spec, f - end_of_spec);
1594     }
1595   while (*f != L_('\0'));
1596 
1597   /* Unlock stream and return.  */
1598   goto all_done;
1599 
1600   /* Hand off processing for positional parameters.  */
1601 do_positional:
1602   done = printf_positional (s, format, readonly_format, ap, &ap_save,
1603 			    done, nspecs_done, lead_str_end, work_buffer,
1604 			    save_errno, grouping, thousands_sep, mode_flags);
1605 
1606  all_done:
1607   /* Unlock the stream.  */
1608   _IO_funlockfile (s);
1609   _IO_cleanup_region_end (0);
1610 
1611   return done;
1612 }
1613 
1614 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)1615 printf_positional (FILE *s, const CHAR_T *format, int readonly_format,
1616 		   va_list ap, va_list *ap_savep, int done, int nspecs_done,
1617 		   const UCHAR_T *lead_str_end,
1618 		   CHAR_T *work_buffer, int save_errno,
1619 		   const char *grouping, THOUSANDS_SEP_T thousands_sep,
1620 		   unsigned int mode_flags)
1621 {
1622   /* For positional argument handling.  */
1623   struct scratch_buffer specsbuf;
1624   scratch_buffer_init (&specsbuf);
1625   struct printf_spec *specs = specsbuf.data;
1626   size_t specs_limit = specsbuf.length / sizeof (specs[0]);
1627 
1628   /* Used as a backing store for args_value, args_size, args_type
1629      below.  */
1630   struct scratch_buffer argsbuf;
1631   scratch_buffer_init (&argsbuf);
1632 
1633   /* Array with information about the needed arguments.  This has to
1634      be dynamically extensible.  */
1635   size_t nspecs = 0;
1636 
1637   /* The number of arguments the format string requests.  This will
1638      determine the size of the array needed to store the argument
1639      attributes.  */
1640   size_t nargs = 0;
1641 
1642   /* Positional parameters refer to arguments directly.  This could
1643      also determine the maximum number of arguments.  Track the
1644      maximum number.  */
1645   size_t max_ref_arg = 0;
1646 
1647   /* Just a counter.  */
1648   size_t cnt;
1649 
1650   if (grouping == (const char *) -1)
1651     {
1652 #ifdef COMPILE_WPRINTF
1653       thousands_sep = _NL_CURRENT_WORD (LC_NUMERIC,
1654 					_NL_NUMERIC_THOUSANDS_SEP_WC);
1655 #else
1656       thousands_sep = _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);
1657 #endif
1658 
1659       grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1660       if (*grouping == '\0' || *grouping == CHAR_MAX)
1661 	grouping = NULL;
1662     }
1663 
1664   for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
1665        f = specs[nspecs++].next_fmt)
1666     {
1667       if (nspecs == specs_limit)
1668 	{
1669 	  if (!scratch_buffer_grow_preserve (&specsbuf))
1670 	    {
1671 	      done = -1;
1672 	      goto all_done;
1673 	    }
1674 	  specs = specsbuf.data;
1675 	  specs_limit = specsbuf.length / sizeof (specs[0]);
1676 	}
1677 
1678       /* Parse the format specifier.  */
1679 #ifdef COMPILE_WPRINTF
1680       nargs += __parse_one_specwc (f, nargs, &specs[nspecs], &max_ref_arg);
1681 #else
1682       nargs += __parse_one_specmb (f, nargs, &specs[nspecs], &max_ref_arg);
1683 #endif
1684     }
1685 
1686   /* Determine the number of arguments the format string consumes.  */
1687   nargs = MAX (nargs, max_ref_arg);
1688 
1689   union printf_arg *args_value;
1690   int *args_size;
1691   int *args_type;
1692   {
1693     /* Calculate total size needed to represent a single argument
1694        across all three argument-related arrays.  */
1695     size_t bytes_per_arg
1696       = sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
1697     if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
1698       {
1699 	done = -1;
1700 	goto all_done;
1701       }
1702     args_value = argsbuf.data;
1703     /* Set up the remaining two arrays to each point past the end of
1704        the prior array, since space for all three has been allocated
1705        now.  */
1706     args_size = &args_value[nargs].pa_int;
1707     args_type = &args_size[nargs];
1708     memset (args_type, (mode_flags & PRINTF_FORTIFY) != 0 ? '\xff' : '\0',
1709 	    nargs * sizeof (*args_type));
1710   }
1711 
1712   /* XXX Could do sanity check here: If any element in ARGS_TYPE is
1713      still zero after this loop, format is invalid.  For now we
1714      simply use 0 as the value.  */
1715 
1716   /* Fill in the types of all the arguments.  */
1717   for (cnt = 0; cnt < nspecs; ++cnt)
1718     {
1719       /* If the width is determined by an argument this is an int.  */
1720       if (specs[cnt].width_arg != -1)
1721 	args_type[specs[cnt].width_arg] = PA_INT;
1722 
1723       /* If the precision is determined by an argument this is an int.  */
1724       if (specs[cnt].prec_arg != -1)
1725 	args_type[specs[cnt].prec_arg] = PA_INT;
1726 
1727       switch (specs[cnt].ndata_args)
1728 	{
1729 	case 0:		/* No arguments.  */
1730 	  break;
1731 	case 1:		/* One argument; we already have the
1732 			   type and size.  */
1733 	  args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;
1734 	  args_size[specs[cnt].data_arg] = specs[cnt].size;
1735 	  break;
1736 	default:
1737 	  /* We have more than one argument for this format spec.
1738 	     We must call the arginfo function again to determine
1739 	     all the types.  */
1740 	  (void) (*__printf_arginfo_table[specs[cnt].info.spec])
1741 	    (&specs[cnt].info,
1742 	     specs[cnt].ndata_args, &args_type[specs[cnt].data_arg],
1743 	     &args_size[specs[cnt].data_arg]);
1744 	  break;
1745 	}
1746     }
1747 
1748   /* Now we know all the types and the order.  Fill in the argument
1749      values.  */
1750   for (cnt = 0; cnt < nargs; ++cnt)
1751     switch (args_type[cnt])
1752       {
1753 #define T(tag, mem, type)				\
1754 	case tag:					\
1755 	  args_value[cnt].mem = va_arg (*ap_savep, type); \
1756 	  break
1757 
1758 	T (PA_WCHAR, pa_wchar, wint_t);
1759       case PA_CHAR:				/* Promoted.  */
1760       case PA_INT|PA_FLAG_SHORT:		/* Promoted.  */
1761 #if LONG_MAX == INT_MAX
1762       case PA_INT|PA_FLAG_LONG:
1763 #endif
1764 	T (PA_INT, pa_int, int);
1765 #if LONG_MAX == LONG_LONG_MAX
1766       case PA_INT|PA_FLAG_LONG:
1767 #endif
1768 	T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);
1769 #if LONG_MAX != INT_MAX && LONG_MAX != LONG_LONG_MAX
1770 # error "he?"
1771 #endif
1772       case PA_FLOAT:				/* Promoted.  */
1773 	T (PA_DOUBLE, pa_double, double);
1774       case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
1775 	if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
1776 	  {
1777 	    args_value[cnt].pa_double = va_arg (*ap_savep, double);
1778 	    args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
1779 	  }
1780 #if __HAVE_FLOAT128_UNLIKE_LDBL
1781 	else if ((mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0)
1782 	  args_value[cnt].pa_float128 = va_arg (*ap_savep, _Float128);
1783 #endif
1784 	else
1785 	  args_value[cnt].pa_long_double = va_arg (*ap_savep, long double);
1786 	break;
1787       case PA_STRING:				/* All pointers are the same */
1788       case PA_WSTRING:			/* All pointers are the same */
1789 	T (PA_POINTER, pa_pointer, void *);
1790 #undef T
1791       default:
1792 	if ((args_type[cnt] & PA_FLAG_PTR) != 0)
1793 	  args_value[cnt].pa_pointer = va_arg (*ap_savep, void *);
1794 	else if (__glibc_unlikely (__printf_va_arg_table != NULL)
1795 		 && __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
1796 	  {
1797 	    args_value[cnt].pa_user = alloca (args_size[cnt]);
1798 	    (*__printf_va_arg_table[args_type[cnt] - PA_LAST])
1799 	      (args_value[cnt].pa_user, ap_savep);
1800 	  }
1801 	else
1802 	  memset (&args_value[cnt], 0, sizeof (args_value[cnt]));
1803 	break;
1804       case -1:
1805 	/* Error case.  Not all parameters appear in N$ format
1806 	   strings.  We have no way to determine their type.  */
1807 	assert ((mode_flags & PRINTF_FORTIFY) != 0);
1808 	__libc_fatal ("*** invalid %N$ use detected ***\n");
1809       }
1810 
1811   /* Now walk through all format specifiers and process them.  */
1812   for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
1813     {
1814       STEP4_TABLE;
1815 
1816       int is_negative;
1817       union
1818       {
1819 	unsigned long long int longlong;
1820 	unsigned long int word;
1821       } number;
1822       int base;
1823       CHAR_T *string;		/* Pointer to argument string.  */
1824 
1825       /* Fill variables from values in struct.  */
1826       int alt = specs[nspecs_done].info.alt;
1827       int space = specs[nspecs_done].info.space;
1828       int left = specs[nspecs_done].info.left;
1829       int showsign = specs[nspecs_done].info.showsign;
1830       int group = specs[nspecs_done].info.group;
1831       int is_long_double __attribute__ ((unused))
1832 	= specs[nspecs_done].info.is_long_double;
1833       int is_short = specs[nspecs_done].info.is_short;
1834       int is_char = specs[nspecs_done].info.is_char;
1835       int is_long = specs[nspecs_done].info.is_long;
1836       int width = specs[nspecs_done].info.width;
1837       int prec = specs[nspecs_done].info.prec;
1838       int use_outdigits = specs[nspecs_done].info.i18n;
1839       char pad = specs[nspecs_done].info.pad;
1840       CHAR_T spec = specs[nspecs_done].info.spec;
1841 
1842       CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
1843 
1844       /* Fill in last information.  */
1845       if (specs[nspecs_done].width_arg != -1)
1846 	{
1847 	  /* Extract the field width from an argument.  */
1848 	  specs[nspecs_done].info.width =
1849 	    args_value[specs[nspecs_done].width_arg].pa_int;
1850 
1851 	  if (specs[nspecs_done].info.width < 0)
1852 	    /* If the width value is negative left justification is
1853 	       selected and the value is taken as being positive.  */
1854 	    {
1855 	      specs[nspecs_done].info.width *= -1;
1856 	      left = specs[nspecs_done].info.left = 1;
1857 	    }
1858 	  width = specs[nspecs_done].info.width;
1859 	}
1860 
1861       if (specs[nspecs_done].prec_arg != -1)
1862 	{
1863 	  /* Extract the precision from an argument.  */
1864 	  specs[nspecs_done].info.prec =
1865 	    args_value[specs[nspecs_done].prec_arg].pa_int;
1866 
1867 	  if (specs[nspecs_done].info.prec < 0)
1868 	    /* If the precision is negative the precision is
1869 	       omitted.  */
1870 	    specs[nspecs_done].info.prec = -1;
1871 
1872 	  prec = specs[nspecs_done].info.prec;
1873 	}
1874 
1875       /* Process format specifiers.  */
1876       while (1)
1877 	{
1878 	  extern printf_function **__printf_function_table;
1879 	  int function_done;
1880 
1881 	  if (spec <= UCHAR_MAX
1882 	      && __printf_function_table != NULL
1883 	      && __printf_function_table[(size_t) spec] != NULL)
1884 	    {
1885 	      const void **ptr = alloca (specs[nspecs_done].ndata_args
1886 					 * sizeof (const void *));
1887 
1888 	      /* Fill in an array of pointers to the argument values.  */
1889 	      for (unsigned int i = 0; i < specs[nspecs_done].ndata_args;
1890 		   ++i)
1891 		ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
1892 
1893 	      /* Call the function.  */
1894 	      function_done = __printf_function_table[(size_t) spec]
1895 		(s, &specs[nspecs_done].info, ptr);
1896 
1897 	      if (function_done != -2)
1898 		{
1899 		  /* If an error occurred we don't have information
1900 		     about # of chars.  */
1901 		  if (function_done < 0)
1902 		    {
1903 		      /* Function has set errno.  */
1904 		      done = -1;
1905 		      goto all_done;
1906 		    }
1907 
1908 		  done_add (function_done);
1909 		  break;
1910 		}
1911 	    }
1912 
1913 	  JUMP (spec, step4_jumps);
1914 
1915 #define process_arg_data args_value[specs[nspecs_done].data_arg]
1916 #define process_arg_int() process_arg_data.pa_int
1917 #define process_arg_long_int() process_arg_data.pa_long_int
1918 #define process_arg_long_long_int() process_arg_data.pa_long_long_int
1919 #define process_arg_pointer() process_arg_data.pa_pointer
1920 #define process_arg_string() process_arg_data.pa_string
1921 #define process_arg_unsigned_int() process_arg_data.pa_u_int
1922 #define process_arg_unsigned_long_int() process_arg_data.pa_u_long_int
1923 #define process_arg_unsigned_long_long_int() process_arg_data.pa_u_long_long_int
1924 #define process_arg_wchar_t() process_arg_data.pa_wchar
1925 #define process_arg_wstring() process_arg_data.pa_wstring
1926 	  process_arg ();
1927 	  process_string_arg ();
1928 #undef process_arg_data
1929 #undef process_arg_int
1930 #undef process_arg_long_int
1931 #undef process_arg_long_long_int
1932 #undef process_arg_pointer
1933 #undef process_arg_string
1934 #undef process_arg_unsigned_int
1935 #undef process_arg_unsigned_long_int
1936 #undef process_arg_unsigned_long_long_int
1937 #undef process_arg_wchar_t
1938 #undef process_arg_wstring
1939 
1940 	  LABEL (form_float):
1941 	  LABEL (form_floathex):
1942 	  {
1943 	    const void *ptr
1944 	      = (const void *) &args_value[specs[nspecs_done].data_arg];
1945 	    if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
1946 	      {
1947 		specs[nspecs_done].data_arg_type = PA_DOUBLE;
1948 		specs[nspecs_done].info.is_long_double = 0;
1949 	      }
1950 	    SETUP_FLOAT128_INFO (specs[nspecs_done].info);
1951 
1952 	    int function_done
1953 	      = __printf_fp_spec (s, &specs[nspecs_done].info, &ptr);
1954 	    if (function_done < 0)
1955 	      {
1956 		/* Error in print handler; up to handler to set errno.  */
1957 		done = -1;
1958 		goto all_done;
1959 	      }
1960 	    done_add (function_done);
1961 	  }
1962 	  break;
1963 
1964 	  LABEL (form_unknown):
1965 	  {
1966 	    unsigned int i;
1967 	    const void **ptr;
1968 
1969 	    ptr = alloca (specs[nspecs_done].ndata_args
1970 			  * sizeof (const void *));
1971 
1972 	    /* Fill in an array of pointers to the argument values.  */
1973 	    for (i = 0; i < specs[nspecs_done].ndata_args; ++i)
1974 	      ptr[i] = &args_value[specs[nspecs_done].data_arg + i];
1975 
1976 	    /* Call the function.  */
1977 	    function_done = printf_unknown (s, &specs[nspecs_done].info,
1978 					    ptr);
1979 
1980 	    /* If an error occurred we don't have information about #
1981 	       of chars.  */
1982 	    if (function_done < 0)
1983 	      {
1984 		/* Function has set errno.  */
1985 		done = -1;
1986 		goto all_done;
1987 	      }
1988 
1989 	    done_add (function_done);
1990 	  }
1991 	  break;
1992 	}
1993 
1994       /* Write the following constant string.  */
1995       outstring (specs[nspecs_done].end_of_fmt,
1996 		 specs[nspecs_done].next_fmt
1997 		 - specs[nspecs_done].end_of_fmt);
1998     }
1999  all_done:
2000   scratch_buffer_free (&argsbuf);
2001   scratch_buffer_free (&specsbuf);
2002   return done;
2003 }
2004 
2005 /* Handle an unknown format specifier.  This prints out a canonicalized
2006    representation of the format spec itself.  */
2007 static int
printf_unknown(FILE * s,const struct printf_info * info,const void * const * args)2008 printf_unknown (FILE *s, const struct printf_info *info,
2009 		const void *const *args)
2010 
2011 {
2012   int done = 0;
2013   CHAR_T work_buffer[MAX (sizeof (info->width), sizeof (info->prec)) * 3];
2014   CHAR_T *const workend
2015     = &work_buffer[sizeof (work_buffer) / sizeof (CHAR_T)];
2016   CHAR_T *w;
2017 
2018   outchar (L_('%'));
2019 
2020   if (info->alt)
2021     outchar (L_('#'));
2022   if (info->group)
2023     outchar (L_('\''));
2024   if (info->showsign)
2025     outchar (L_('+'));
2026   else if (info->space)
2027     outchar (L_(' '));
2028   if (info->left)
2029     outchar (L_('-'));
2030   if (info->pad == L_('0'))
2031     outchar (L_('0'));
2032   if (info->i18n)
2033     outchar (L_('I'));
2034 
2035   if (info->width != 0)
2036     {
2037       w = _itoa_word (info->width, workend, 10, 0);
2038       while (w < workend)
2039 	outchar (*w++);
2040     }
2041 
2042   if (info->prec != -1)
2043     {
2044       outchar (L_('.'));
2045       w = _itoa_word (info->prec, workend, 10, 0);
2046       while (w < workend)
2047 	outchar (*w++);
2048     }
2049 
2050   if (info->spec != L_('\0'))
2051     outchar (info->spec);
2052 
2053  all_done:
2054   return done;
2055 }
2056 
2057 /* Group the digits from W to REAR_PTR according to the grouping rules
2058    of the current locale.  The interpretation of GROUPING is as in
2059    `struct lconv' from <locale.h>.  The grouped number extends from
2060    the returned pointer until REAR_PTR.  FRONT_PTR to W is used as a
2061    scratch area.  */
2062 static CHAR_T *
group_number(CHAR_T * front_ptr,CHAR_T * w,CHAR_T * rear_ptr,const char * grouping,THOUSANDS_SEP_T thousands_sep)2063 group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
2064 	      const char *grouping, THOUSANDS_SEP_T thousands_sep)
2065 {
2066   /* Length of the current group.  */
2067   int len;
2068 #ifndef COMPILE_WPRINTF
2069   /* Length of the separator (in wide mode, the separator is always a
2070      single wide character).  */
2071   int tlen = strlen (thousands_sep);
2072 #endif
2073 
2074   /* We treat all negative values like CHAR_MAX.  */
2075 
2076   if (*grouping == CHAR_MAX || *grouping <= 0)
2077     /* No grouping should be done.  */
2078     return w;
2079 
2080   len = *grouping++;
2081 
2082   /* Copy existing string so that nothing gets overwritten.  */
2083   memmove (front_ptr, w, (rear_ptr - w) * sizeof (CHAR_T));
2084   CHAR_T *s = front_ptr + (rear_ptr - w);
2085 
2086   w = rear_ptr;
2087 
2088   /* Process all characters in the string.  */
2089   while (s > front_ptr)
2090     {
2091       *--w = *--s;
2092 
2093       if (--len == 0 && s > front_ptr)
2094 	{
2095 	  /* A new group begins.  */
2096 #ifdef COMPILE_WPRINTF
2097 	  if (w != s)
2098 	    *--w = thousands_sep;
2099 	  else
2100 	    /* Not enough room for the separator.  */
2101 	    goto copy_rest;
2102 #else
2103 	  int cnt = tlen;
2104 	  if (tlen < w - s)
2105 	    do
2106 	      *--w = thousands_sep[--cnt];
2107 	    while (cnt > 0);
2108 	  else
2109 	    /* Not enough room for the separator.  */
2110 	    goto copy_rest;
2111 #endif
2112 
2113 	  if (*grouping == CHAR_MAX
2114 #if CHAR_MIN < 0
2115 		   || *grouping < 0
2116 #endif
2117 		   )
2118 	    {
2119 	    copy_rest:
2120 	      /* No further grouping to be done.  Copy the rest of the
2121 		 number.  */
2122 	      w -= s - front_ptr;
2123 	      memmove (w, front_ptr, (s - front_ptr) * sizeof (CHAR_T));
2124 	      break;
2125 	    }
2126 	  else if (*grouping != '\0')
2127 	    len = *grouping++;
2128 	  else
2129 	    /* The previous grouping repeats ad infinitum.  */
2130 	    len = grouping[-1];
2131 	}
2132     }
2133   return w;
2134 }
2135 
2136 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer.  */
2137 struct helper_file
2138   {
2139     struct _IO_FILE_plus _f;
2140 #ifdef COMPILE_WPRINTF
2141     struct _IO_wide_data _wide_data;
2142 #endif
2143     FILE *_put_stream;
2144 #ifdef _IO_MTSAFE_IO
2145     _IO_lock_t lock;
2146 #endif
2147   };
2148 
2149 static int
_IO_helper_overflow(FILE * s,int c)2150 _IO_helper_overflow (FILE *s, int c)
2151 {
2152   FILE *target = ((struct helper_file*) s)->_put_stream;
2153 #ifdef COMPILE_WPRINTF
2154   int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
2155   if (used)
2156     {
2157       size_t written = _IO_sputn (target, s->_wide_data->_IO_write_base, used);
2158       if (written == 0 || written == WEOF)
2159 	return WEOF;
2160       __wmemmove (s->_wide_data->_IO_write_base,
2161 		  s->_wide_data->_IO_write_base + written,
2162 		  used - written);
2163       s->_wide_data->_IO_write_ptr -= written;
2164     }
2165 #else
2166   int used = s->_IO_write_ptr - s->_IO_write_base;
2167   if (used)
2168     {
2169       size_t written = _IO_sputn (target, s->_IO_write_base, used);
2170       if (written == 0 || written == EOF)
2171 	return EOF;
2172       memmove (s->_IO_write_base, s->_IO_write_base + written,
2173 	       used - written);
2174       s->_IO_write_ptr -= written;
2175     }
2176 #endif
2177   return PUTC (c, s);
2178 }
2179 
2180 #ifdef COMPILE_WPRINTF
2181 static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
2182 {
2183   JUMP_INIT_DUMMY,
2184   JUMP_INIT (finish, _IO_wdefault_finish),
2185   JUMP_INIT (overflow, _IO_helper_overflow),
2186   JUMP_INIT (underflow, _IO_default_underflow),
2187   JUMP_INIT (uflow, _IO_default_uflow),
2188   JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
2189   JUMP_INIT (xsputn, _IO_wdefault_xsputn),
2190   JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
2191   JUMP_INIT (seekoff, _IO_default_seekoff),
2192   JUMP_INIT (seekpos, _IO_default_seekpos),
2193   JUMP_INIT (setbuf, _IO_default_setbuf),
2194   JUMP_INIT (sync, _IO_default_sync),
2195   JUMP_INIT (doallocate, _IO_wdefault_doallocate),
2196   JUMP_INIT (read, _IO_default_read),
2197   JUMP_INIT (write, _IO_default_write),
2198   JUMP_INIT (seek, _IO_default_seek),
2199   JUMP_INIT (close, _IO_default_close),
2200   JUMP_INIT (stat, _IO_default_stat)
2201 };
2202 #else
2203 static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
2204 {
2205   JUMP_INIT_DUMMY,
2206   JUMP_INIT (finish, _IO_default_finish),
2207   JUMP_INIT (overflow, _IO_helper_overflow),
2208   JUMP_INIT (underflow, _IO_default_underflow),
2209   JUMP_INIT (uflow, _IO_default_uflow),
2210   JUMP_INIT (pbackfail, _IO_default_pbackfail),
2211   JUMP_INIT (xsputn, _IO_default_xsputn),
2212   JUMP_INIT (xsgetn, _IO_default_xsgetn),
2213   JUMP_INIT (seekoff, _IO_default_seekoff),
2214   JUMP_INIT (seekpos, _IO_default_seekpos),
2215   JUMP_INIT (setbuf, _IO_default_setbuf),
2216   JUMP_INIT (sync, _IO_default_sync),
2217   JUMP_INIT (doallocate, _IO_default_doallocate),
2218   JUMP_INIT (read, _IO_default_read),
2219   JUMP_INIT (write, _IO_default_write),
2220   JUMP_INIT (seek, _IO_default_seek),
2221   JUMP_INIT (close, _IO_default_close),
2222   JUMP_INIT (stat, _IO_default_stat)
2223 };
2224 #endif
2225 
2226 static int
buffered_vfprintf(FILE * s,const CHAR_T * format,va_list args,unsigned int mode_flags)2227 buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
2228 		   unsigned int mode_flags)
2229 {
2230   CHAR_T buf[BUFSIZ];
2231   struct helper_file helper;
2232   FILE *hp = (FILE *) &helper._f;
2233   int result, to_flush;
2234 
2235   /* Orient the stream.  */
2236 #ifdef ORIENT
2237   ORIENT;
2238 #endif
2239 
2240   /* Initialize helper.  */
2241   helper._put_stream = s;
2242 #ifdef COMPILE_WPRINTF
2243   hp->_wide_data = &helper._wide_data;
2244   _IO_wsetp (hp, buf, buf + sizeof buf / sizeof (CHAR_T));
2245   hp->_mode = 1;
2246 #else
2247   _IO_setp (hp, buf, buf + sizeof buf);
2248   hp->_mode = -1;
2249 #endif
2250   hp->_flags = _IO_MAGIC|_IO_NO_READS|_IO_USER_LOCK;
2251 #if _IO_JUMPS_OFFSET
2252   hp->_vtable_offset = 0;
2253 #endif
2254 #ifdef _IO_MTSAFE_IO
2255   hp->_lock = NULL;
2256 #endif
2257   hp->_flags2 = s->_flags2;
2258   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
2259 
2260   /* Now print to helper instead.  */
2261   result = vfprintf (hp, format, args, mode_flags);
2262 
2263   /* Lock stream.  */
2264   __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
2265   _IO_flockfile (s);
2266 
2267   /* Now flush anything from the helper to the S. */
2268 #ifdef COMPILE_WPRINTF
2269   if ((to_flush = (hp->_wide_data->_IO_write_ptr
2270 		   - hp->_wide_data->_IO_write_base)) > 0)
2271     {
2272       if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
2273 	  != to_flush)
2274 	result = -1;
2275     }
2276 #else
2277   if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
2278     {
2279       if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
2280 	result = -1;
2281     }
2282 #endif
2283 
2284   /* Unlock the stream.  */
2285   _IO_funlockfile (s);
2286   __libc_cleanup_region_end (0);
2287 
2288   return result;
2289 }
2290