powerpc64: Remove old strncmp optimization
[glibc.git] / stdio-common / vfprintf-internal.c
blobfb94961f37265940b19f909901a10d89672988e9
1 /* Copyright (C) 1991-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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/>. */
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>
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++.
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. */
43 #include <libioP.h>
45 #ifdef COMPILE_WPRINTF
46 #include <wctype.h>
47 #endif
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)
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
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)
100 #if __HAVE_FLOAT128_UNLIKE_LDBL
101 # define SETUP_FLOAT128_INFO(INFO) \
102 do \
104 if ((mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0) \
105 INFO.is_binary128 = is_long_double; \
106 else \
107 INFO.is_binary128 = 0; \
109 while (0)
110 #else
111 # define SETUP_FLOAT128_INFO(INFO) \
112 do \
114 INFO.is_binary128 = 0; \
116 while (0)
117 #endif
119 /* Add LENGTH to DONE. Return the new value of DONE, or -1 on
120 overflow (and set errno accordingly). */
121 static inline int
122 done_add_func (size_t length, int done)
124 if (done < 0)
125 return done;
126 int ret;
127 if (INT_ADD_WRAPV (done, length, &ret))
129 __set_errno (EOVERFLOW);
130 return -1;
132 return ret;
135 #define done_add(val) \
136 do \
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; \
145 while (0)
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)
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)
175 # include <_itowa.h>
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
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
189 static inline int
190 pad_func (FILE *s, CHAR_T padchar, int width, int done)
192 if (width > 0)
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);
204 return done;
207 #define PAD(Padchar) \
208 do \
210 done = pad_func (s, (Padchar), width, done); \
211 if (done < 0) \
212 goto all_done; \
214 while (0)
216 #include "_i18n_number.h"
218 /* Include the shared code for parsing the format string. */
219 #include "printf-parse.h"
222 #define outchar(Ch) \
223 do \
225 const INT_T outc = (Ch); \
226 if (PUTC (outc, s) == EOF || done == INT_MAX) \
228 done = -1; \
229 goto all_done; \
231 ++done; \
233 while (0)
235 static inline int
236 outstring_func (FILE *s, const UCHAR_T *string, size_t length, int done)
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);
244 #define outstring(String, Len) \
245 do \
247 const void *string_ = (String); \
248 done = outstring_func (s, string_, (Len), done); \
249 if (done < 0) \
250 goto all_done; \
252 while (0)
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
257 outstring_converted_wide_string (FILE *s, const OTHER_CHAR_T *src, int prec,
258 int width, bool left, int done)
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");
268 /* Add the initial padding if needed. */
269 if (width > 0 && !left)
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
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)
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;
301 /* Output initial padding. */
302 if (total_written < width)
304 done = pad_func (s, L_(' '), width - total_written, done);
305 if (done < 0)
306 return done;
310 /* Convert the input string, piece by piece. */
311 size_t total_written = 0;
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)
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;
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;
345 /* Calls __printf_fp or __printf_fphex based on the value of the
346 format specifier INFO->spec. */
347 static inline int
348 __printf_fp_spec (FILE *fp, const struct printf_info *info,
349 const void *const *args)
351 if (info->spec == 'a' || info->spec == 'A')
352 return __printf_fphex (fp, info, args);
353 else
354 return __printf_fp (fp, info, args);
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
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
375 /* Global constants. */
376 static const CHAR_T null[] = L_("(null)");
378 /* Size of the work_buffer variable (in characters, not bytes. */
379 enum { WORK_BUFFER_SIZE = 1000 / sizeof (CHAR_T) };
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[] =
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
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 \
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; \
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 \
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; \
442 while (0)
443 #endif
445 #define STEP0_3_TABLE \
446 /* Step 0: at the beginning. */ \
447 static JUMP_TABLE_TYPE step0_jumps[31] = \
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] = \
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] = \
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] = \
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] = \
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' */ \
622 #define STEP4_TABLE \
623 /* Step 4: processing format specifier. */ \
624 static JUMP_TABLE_TYPE step4_jumps[31] = \
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' */ \
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));
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);
674 /* Handle unknown format specifier. */
675 static int printf_unknown (FILE *, const struct printf_info *) __THROW;
677 /* Group digits of number string. */
678 static CHAR_T *group_number (CHAR_T *, CHAR_T *, CHAR_T *, const char *,
679 THOUSANDS_SEP_T);
681 /* The function itself. */
683 vfprintf (FILE *s, const CHAR_T *format, va_list ap, unsigned int mode_flags)
685 /* The character used as thousands separator. */
686 THOUSANDS_SEP_T thousands_sep = 0;
688 /* The string describing the size of groups of digits. */
689 const char *grouping;
691 /* Place to accumulate the result. */
692 int done;
694 /* Current character in format string. */
695 const UCHAR_T *f;
697 /* End of leading constant string. */
698 const UCHAR_T *lead_str_end;
700 /* Points to next format specifier. */
701 const UCHAR_T *end_of_spec;
703 /* Buffer intermediate results. */
704 CHAR_T work_buffer[WORK_BUFFER_SIZE];
705 CHAR_T *workend;
707 /* We have to save the original argument pointer. */
708 va_list ap_save;
710 /* Count number of specifiers we already processed. */
711 int nspecs_done;
713 /* For the %m format we may need the current `errno' value. */
714 int save_errno = errno;
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;
720 /* Orient the stream. */
721 #ifdef ORIENT
722 ORIENT;
723 #endif
725 /* Sanity check of arguments. */
726 ARGCHECK (s, format);
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
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);
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;
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
762 /* Lock stream. */
763 _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile, s);
764 _IO_flockfile (s);
766 /* Write the literal text before the first format. */
767 outstring ((const UCHAR_T *) format,
768 lead_str_end - (const UCHAR_T *) format);
770 /* If we only have to print a simple string, return now. */
771 if (*f == L_('\0'))
772 goto all_done;
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;
780 /* Process whole format string. */
783 STEP0_3_TABLE;
784 STEP4_TABLE;
786 int is_negative; /* Flag for negative number. */
787 union
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;
814 workend = work_buffer + WORK_BUFFER_SIZE;
816 /* Get current character in format string. */
817 JUMP (*++f, step0_jumps);
819 /* ' ' flag. */
820 LABEL (flag_space):
821 space = 1;
822 JUMP (*++f, step0_jumps);
824 /* '+' flag. */
825 LABEL (flag_plus):
826 showsign = 1;
827 JUMP (*++f, step0_jumps);
829 /* The '-' flag. */
830 LABEL (flag_minus):
831 left = 1;
832 pad = L_(' ');
833 JUMP (*++f, step0_jumps);
835 /* The '#' flag. */
836 LABEL (flag_hash):
837 alt = 1;
838 JUMP (*++f, step0_jumps);
840 /* The '0' flag. */
841 LABEL (flag_zero):
842 if (!left)
843 pad = L_('0');
844 JUMP (*++f, step0_jumps);
846 /* The '\'' flag. */
847 LABEL (flag_quote):
848 group = 1;
850 if (grouping == (const char *) -1)
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
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
867 grouping = NULL;
869 JUMP (*++f, step0_jumps);
871 LABEL (flag_i18n):
872 use_outdigits = 1;
873 JUMP (*++f, step0_jumps);
875 /* Get width from argument. */
876 LABEL (width_asterics):
878 const UCHAR_T *tmp; /* Temporary value. */
880 tmp = ++f;
881 if (ISDIGIT (*tmp))
883 int pos = read_int (&tmp);
885 if (pos == -1)
887 __set_errno (EOVERFLOW);
888 done = -1;
889 goto all_done;
892 if (pos && *tmp == L_('$'))
893 /* The width comes from a positional parameter. */
894 goto do_positional;
896 width = va_arg (ap, int);
898 /* Negative width means left justified. */
899 if (width < 0)
901 width = -width;
902 pad = L_(' ');
903 left = 1;
906 JUMP (*f, step1_jumps);
908 /* Given width in format string. */
909 LABEL (width):
910 width = read_int (&f);
912 if (__glibc_unlikely (width == -1))
914 __set_errno (EOVERFLOW);
915 done = -1;
916 goto all_done;
919 if (*f == L_('$'))
920 /* Oh, oh. The argument comes from a positional parameter. */
921 goto do_positional;
922 JUMP (*f, step1_jumps);
924 LABEL (precision):
925 ++f;
926 if (*f == L_('*'))
928 const UCHAR_T *tmp; /* Temporary value. */
930 tmp = ++f;
931 if (ISDIGIT (*tmp))
933 int pos = read_int (&tmp);
935 if (pos == -1)
937 __set_errno (EOVERFLOW);
938 done = -1;
939 goto all_done;
942 if (pos && *tmp == L_('$'))
943 /* The precision comes from a positional parameter. */
944 goto do_positional;
946 prec = va_arg (ap, int);
948 /* If the precision is negative the precision is omitted. */
949 if (prec < 0)
950 prec = -1;
952 else if (ISDIGIT (*f))
954 prec = read_int (&f);
956 /* The precision was specified in this case as an extremely
957 large positive value. */
958 if (prec == -1)
960 __set_errno (EOVERFLOW);
961 done = -1;
962 goto all_done;
965 else
966 prec = 0;
967 JUMP (*f, step2_jumps);
969 /* Process 'h' modifier. There might another 'h' following. */
970 LABEL (mod_half):
971 is_short = 1;
972 JUMP (*++f, step3a_jumps);
974 /* Process 'hh' modifier. */
975 LABEL (mod_halfhalf):
976 is_short = 0;
977 is_char = 1;
978 JUMP (*++f, step4_jumps);
980 /* Process 'l' modifier. There might another 'l' following. */
981 LABEL (mod_long):
982 is_long = 1;
983 JUMP (*++f, step3b_jumps);
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);
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);
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);
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);
1007 /* Process current format. */
1008 while (1)
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
1032 LABEL (form_float):
1033 LABEL (form_floathex):
1035 if (__glibc_unlikely ((mode_flags & PRINTF_LDBL_IS_DBL) != 0))
1036 is_long_double = 0;
1038 struct printf_info info =
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
1058 PARSE_FLOAT_VA_ARG_EXTENDED (info);
1059 const void *ptr = &the_arg;
1061 int function_done = __printf_fp_spec (s, &info, &ptr);
1062 if (function_done < 0)
1064 done = -1;
1065 goto all_done;
1067 done_add (function_done);
1069 break;
1071 LABEL (form_unknown):
1072 if (spec == L_('\0'))
1074 /* The format string ended before the specifier is complete. */
1075 __set_errno (EINVAL);
1076 done = -1;
1077 goto all_done;
1080 /* If we are in the fast loop force entering the complicated
1081 one. */
1082 goto do_positional;
1085 /* The format is correctly handled. */
1086 ++nspecs_done;
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
1095 /* Write the following constant string. */
1096 outstring (end_of_spec, f - end_of_spec);
1098 while (*f != L_('\0'));
1100 /* Unlock stream and return. */
1101 goto all_done;
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);
1109 all_done:
1110 /* Unlock the stream. */
1111 _IO_funlockfile (s);
1112 _IO_cleanup_region_end (0);
1114 return done;
1117 static int
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)
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]);
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);
1136 /* Array with information about the needed arguments. This has to
1137 be dynamically extensible. */
1138 size_t nspecs = 0;
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;
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;
1150 /* Just a counter. */
1151 size_t cnt;
1153 if (grouping == (const char *) -1)
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
1162 grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);
1163 if (*grouping == '\0' || *grouping == CHAR_MAX)
1164 grouping = NULL;
1167 for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
1168 f = specs[nspecs++].next_fmt)
1170 if (nspecs == specs_limit)
1172 if (!scratch_buffer_grow_preserve (&specsbuf))
1174 done = -1;
1175 goto all_done;
1177 specs = specsbuf.data;
1178 specs_limit = specsbuf.length / sizeof (specs[0]);
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
1189 /* Determine the number of arguments the format string consumes. */
1190 nargs = MAX (nargs, max_ref_arg);
1192 union printf_arg *args_value;
1193 int *args_size;
1194 int *args_type;
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))
1202 done = -1;
1203 goto all_done;
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));
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. */
1219 /* Fill in the types of all the arguments. */
1220 for (cnt = 0; cnt < nspecs; ++cnt)
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;
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;
1230 switch (specs[cnt].ndata_args)
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;
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])
1256 #define T(tag, mem, type) \
1257 case tag: \
1258 args_value[cnt].mem = va_arg (*ap_savep, type); \
1259 break
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))
1280 args_value[cnt].pa_double = va_arg (*ap_savep, double);
1281 args_type[cnt] &= ~PA_FLAG_LONG_DOUBLE;
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)
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);
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");
1314 /* Now walk through all format specifiers and process them. */
1315 for (; (size_t) nspecs_done < nspecs; ++nspecs_done)
1317 STEP4_TABLE;
1319 int is_negative;
1320 union
1322 unsigned long long int longlong;
1323 unsigned long int word;
1324 } number;
1325 int base;
1326 CHAR_T *string; /* Pointer to argument string. */
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;
1345 CHAR_T *workend = work_buffer + WORK_BUFFER_SIZE;
1347 /* Fill in last information. */
1348 if (specs[nspecs_done].width_arg != -1)
1350 /* Extract the field width from an argument. */
1351 specs[nspecs_done].info.width =
1352 args_value[specs[nspecs_done].width_arg].pa_int;
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. */
1358 specs[nspecs_done].info.width *= -1;
1359 left = specs[nspecs_done].info.left = 1;
1361 width = specs[nspecs_done].info.width;
1364 if (specs[nspecs_done].prec_arg != -1)
1366 /* Extract the precision from an argument. */
1367 specs[nspecs_done].info.prec =
1368 args_value[specs[nspecs_done].prec_arg].pa_int;
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;
1375 prec = specs[nspecs_done].info.prec;
1378 /* Process format specifiers. */
1379 while (1)
1381 int function_done;
1383 if (spec <= UCHAR_MAX
1384 && __printf_function_table != NULL
1385 && __printf_function_table[(size_t) spec] != NULL)
1387 const void **ptr = alloca (specs[nspecs_done].ndata_args
1388 * sizeof (const void *));
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];
1395 /* Call the function. */
1396 function_done = __printf_function_table[(size_t) spec]
1397 (s, &specs[nspecs_done].info, ptr);
1399 if (function_done != -2)
1401 /* If an error occurred we don't have information
1402 about # of chars. */
1403 if (function_done < 0)
1405 /* Function has set errno. */
1406 done = -1;
1407 goto all_done;
1410 done_add (function_done);
1411 break;
1415 JUMP (spec, step4_jumps);
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
1441 LABEL (form_float):
1442 LABEL (form_floathex):
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))
1448 specs[nspecs_done].data_arg_type = PA_DOUBLE;
1449 specs[nspecs_done].info.is_long_double = 0;
1451 SETUP_FLOAT128_INFO (specs[nspecs_done].info);
1453 int function_done
1454 = __printf_fp_spec (s, &specs[nspecs_done].info, &ptr);
1455 if (function_done < 0)
1457 /* Error in print handler; up to handler to set errno. */
1458 done = -1;
1459 goto all_done;
1461 done_add (function_done);
1463 break;
1465 LABEL (form_unknown):
1467 int function_done = printf_unknown (s, &specs[nspecs_done].info);
1469 /* If an error occurred we don't have information about #
1470 of chars. */
1471 if (function_done < 0)
1473 /* Function has set errno. */
1474 done = -1;
1475 goto all_done;
1478 done_add (function_done);
1480 break;
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);
1488 all_done:
1489 scratch_buffer_free (&argsbuf);
1490 scratch_buffer_free (&specsbuf);
1491 return done;
1494 /* Handle an unknown format specifier. This prints out a canonicalized
1495 representation of the format spec itself. */
1496 static int
1497 printf_unknown (FILE *s, const struct printf_info *info)
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;
1505 outchar (L_('%'));
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'));
1522 if (info->width != 0)
1524 w = _itoa_word (info->width, workend, 10, 0);
1525 while (w < workend)
1526 outchar (*w++);
1529 if (info->prec != -1)
1531 outchar (L_('.'));
1532 w = _itoa_word (info->prec, workend, 10, 0);
1533 while (w < workend)
1534 outchar (*w++);
1537 if (info->spec != L_('\0'))
1538 outchar (info->spec);
1540 all_done:
1541 return done;
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 *
1550 group_number (CHAR_T *front_ptr, CHAR_T *w, CHAR_T *rear_ptr,
1551 const char *grouping, THOUSANDS_SEP_T thousands_sep)
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
1561 /* We treat all negative values like CHAR_MAX. */
1563 if (*grouping == CHAR_MAX || *grouping <= 0)
1564 /* No grouping should be done. */
1565 return w;
1567 len = *grouping++;
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);
1573 w = rear_ptr;
1575 /* Process all characters in the string. */
1576 while (s > front_ptr)
1578 *--w = *--s;
1580 if (--len == 0 && s > front_ptr)
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)
1593 *--w = thousands_sep[--cnt];
1594 while (cnt > 0);
1595 else
1596 /* Not enough room for the separator. */
1597 goto copy_rest;
1598 #endif
1600 if (*grouping == CHAR_MAX
1601 #if CHAR_MIN < 0
1602 || *grouping < 0
1603 #endif
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;
1613 else if (*grouping != '\0')
1614 len = *grouping++;
1615 else
1616 /* The previous grouping repeats ad infinitum. */
1617 len = grouping[-1];
1620 return w;
1623 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer. */
1624 struct helper_file
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
1636 static int
1637 _IO_helper_overflow (FILE *s, int c)
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)
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;
1652 #else
1653 int used = s->_IO_write_ptr - s->_IO_write_base;
1654 if (used)
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;
1663 #endif
1664 return PUTC (c, s);
1667 #ifdef COMPILE_WPRINTF
1668 static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
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)
1689 #else
1690 static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
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)
1711 #endif
1713 static int
1714 buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
1715 unsigned int mode_flags)
1717 CHAR_T buf[BUFSIZ];
1718 struct helper_file helper;
1719 FILE *hp = (FILE *) &helper._f;
1720 int result, to_flush;
1722 /* Orient the stream. */
1723 #ifdef ORIENT
1724 ORIENT;
1725 #endif
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;
1747 /* Now print to helper instead. */
1748 result = vfprintf (hp, format, args, mode_flags);
1750 /* Lock stream. */
1751 __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, s);
1752 _IO_flockfile (s);
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)
1759 if ((int) _IO_sputn (s, hp->_wide_data->_IO_write_base, to_flush)
1760 != to_flush)
1761 result = -1;
1763 #else
1764 if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0)
1766 if ((int) _IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush)
1767 result = -1;
1769 #endif
1771 /* Unlock the stream. */
1772 _IO_funlockfile (s);
1773 __libc_cleanup_region_end (0);
1775 return result;