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>
28 #include <libc-lock.h>
29 #include <sys/param.h>
31 #include <locale/localeinfo.h>
33 #include <scratch_buffer.h>
36 /* This code is shared between the standard stdio implementation found
37 in GNU C library and the libio implementation originally found in
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. */
45 #ifdef COMPILE_WPRINTF
49 #define ARGCHECK(S, Format) \
52 /* Check file argument for consistence. */ \
54 if (S->_flags & _IO_NO_WRITES) \
56 S->_flags |= _IO_ERR_SEEN; \
57 __set_errno (EBADF); \
62 __set_errno (EINVAL); \
66 #define UNBUFFERED_P(S) ((S)->_flags & _IO_UNBUFFERED)
68 #if __HAVE_FLOAT128_UNLIKE_LDBL
69 # define PARSE_FLOAT_VA_ARG_EXTENDED(INFO) \
73 && (mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0) \
75 INFO.is_binary128 = 1; \
76 the_arg.pa_float128 = va_arg (ap, _Float128); \
80 PARSE_FLOAT_VA_ARG (INFO); \
85 # define PARSE_FLOAT_VA_ARG_EXTENDED(INFO) \
86 PARSE_FLOAT_VA_ARG (INFO);
89 #define PARSE_FLOAT_VA_ARG(INFO) \
92 INFO.is_binary128 = 0; \
94 the_arg.pa_long_double = va_arg (ap, long double); \
96 the_arg.pa_double = va_arg (ap, double); \
100 #if __HAVE_FLOAT128_UNLIKE_LDBL
101 # define SETUP_FLOAT128_INFO(INFO) \
104 if ((mode_flags & PRINTF_LDBL_USES_FLOAT128) != 0) \
105 INFO.is_binary128 = is_long_double; \
107 INFO.is_binary128 = 0; \
111 # define SETUP_FLOAT128_INFO(INFO) \
114 INFO.is_binary128 = 0; \
119 /* Add LENGTH to DONE. Return the new value of DONE, or -1 on
120 overflow (and set errno accordingly). */
122 done_add_func (size_t length
, int done
)
127 if (INT_ADD_WRAPV (done
, length
, &ret
))
129 __set_errno (EOVERFLOW
);
135 #define done_add(val) \
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); \
147 #ifndef COMPILE_WPRINTF
148 # define vfprintf __vfprintf_internal
150 # define OTHER_CHAR_T wchar_t
151 # define UCHAR_T unsigned char
153 typedef const char *THOUSANDS_SEP_T
;
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)\
162 # define CONVERT_FROM_OTHER_STRING __wcsrtombs
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)
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
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)
190 pad_func (FILE *s
, CHAR_T padchar
, int width
, int done
)
195 #ifndef COMPILE_WPRINTF
196 written
= _IO_padn (s
, padchar
, width
);
198 written
= _IO_wpadn (s
, padchar
, width
);
200 if (__glibc_unlikely (written
!= width
))
202 return done_add_func (width
, done
);
207 #define PAD(Padchar) \
210 done = pad_func (s, (Padchar), width, done); \
216 #include "_i18n_number.h"
218 /* Include the shared code for parsing the format string. */
219 #include "printf-parse.h"
222 #define outchar(Ch) \
225 const INT_T outc = (Ch); \
226 if (PUTC (outc, s) == EOF || done == INT_MAX) \
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
))
241 return done_add_func (length
, done
);
244 #define outstring(String, Len) \
247 const void *string_ = (String); \
248 done = outstring_func (s, string_, (Len), done); \
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. */
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
;
277 total_written
= CONVERT_FROM_OTHER_STRING
278 (NULL
, &src_copy
, 0, &mbstate
);
281 /* The source might not be null-terminated. Enforce the
282 limit manually, based on the output length. */
285 while (limit
> 0 && src_copy
!= NULL
)
287 size_t write_limit
= buf_length
;
288 if (write_limit
> limit
)
290 size_t written
= CONVERT_FROM_OTHER_STRING
291 (buf
, &src_copy
, write_limit
, &mbstate
);
292 if (written
== (size_t) -1)
296 total_written
+= written
;
301 /* Output initial padding. */
302 if (total_written
< width
)
304 done
= pad_func (s
, L_(' '), width
- total_written
, 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;
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)
330 done
= outstring_func (s
, (const UCHAR_T
*) buf
, written
, done
);
333 total_written
+= written
;
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
);
345 /* Calls __printf_fp or __printf_fphex based on the value of the
346 format specifier INFO->spec. */
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
);
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
360 #if LONG_MAX == LONG_LONG_MAX
361 # define is_longlong 0
363 # define is_longlong is_long_double
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
371 # define is_long_num is_long
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,
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,
399 /* 'X' */ 18, 0, /* 'Z' */ 13, 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
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) \
424 offset = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
425 : table[CHAR_CLASS (spec)]; \
426 ptr = &&JUMP_TABLE_BASE_LABEL + offset; \
431 # define JUMP_TABLE_TYPE const void *const
432 # define REF(Name) &&do_##Name
433 # define JUMP(ChExpr, table) \
438 ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
439 : table[CHAR_CLASS (spec)]; \
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' */ \
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' */ \
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' */ \
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' */ \
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,
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 *,
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. */
694 /* Current character in format string. */
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
];
707 /* We have to save the original argument pointer. */
710 /* Count number of specifiers we already processed. */
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,
718 int readonly_format
= 0;
720 /* Orient the stream. */
725 /* Sanity check of arguments. */
726 ARGCHECK (s
, format
);
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. */
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. */
744 grouping
= (const char *) -1;
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
);
754 #ifdef COMPILE_WPRINTF
755 /* Find the first format specifier. */
756 f
= lead_str_end
= __find_specwc ((const UCHAR_T
*) format
);
758 /* Find the first format specifier. */
759 f
= lead_str_end
= __find_specmb ((const UCHAR_T
*) format
);
763 _IO_cleanup_region_start ((void (*) (void *)) &_IO_funlockfile
, 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. */
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
))
780 /* Process whole format string. */
786 int is_negative
; /* Flag for negative number. */
789 unsigned long long int longlong
;
790 unsigned long int word
;
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. */
814 workend
= work_buffer
+ WORK_BUFFER_SIZE
;
816 /* Get current character in format string. */
817 JUMP (*++f
, step0_jumps
);
822 JUMP (*++f
, step0_jumps
);
827 JUMP (*++f
, step0_jumps
);
833 JUMP (*++f
, step0_jumps
);
838 JUMP (*++f
, step0_jumps
);
844 JUMP (*++f
, step0_jumps
);
850 if (grouping
== (const char *) -1)
852 #ifdef COMPILE_WPRINTF
853 thousands_sep
= _NL_CURRENT_WORD (LC_NUMERIC
,
854 _NL_NUMERIC_THOUSANDS_SEP_WC
);
856 thousands_sep
= _NL_CURRENT (LC_NUMERIC
, THOUSANDS_SEP
);
859 grouping
= _NL_CURRENT (LC_NUMERIC
, GROUPING
);
860 if (*grouping
== '\0' || *grouping
== CHAR_MAX
861 #ifdef COMPILE_WPRINTF
862 || thousands_sep
== L
'\0'
864 || *thousands_sep
== '\0'
869 JUMP (*++f
, step0_jumps
);
873 JUMP (*++f
, step0_jumps
);
875 /* Get width from argument. */
876 LABEL (width_asterics
):
878 const UCHAR_T
*tmp
; /* Temporary value. */
883 int pos
= read_int (&tmp
);
887 __set_errno (EOVERFLOW
);
892 if (pos
&& *tmp
== L_('$'))
893 /* The width comes from a positional parameter. */
896 width
= va_arg (ap
, int);
898 /* Negative width means left justified. */
906 JUMP (*f
, step1_jumps
);
908 /* Given width in format string. */
910 width
= read_int (&f
);
912 if (__glibc_unlikely (width
== -1))
914 __set_errno (EOVERFLOW
);
920 /* Oh, oh. The argument comes from a positional parameter. */
922 JUMP (*f
, step1_jumps
);
928 const UCHAR_T
*tmp
; /* Temporary value. */
933 int pos
= read_int (&tmp
);
937 __set_errno (EOVERFLOW
);
942 if (pos
&& *tmp
== L_('$'))
943 /* The precision comes from a positional parameter. */
946 prec
= va_arg (ap
, int);
948 /* If the precision is negative the precision is omitted. */
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. */
960 __set_errno (EOVERFLOW
);
967 JUMP (*f
, step2_jumps
);
969 /* Process 'h' modifier. There might another 'h' following. */
972 JUMP (*++f
, step3a_jumps
);
974 /* Process 'hh' modifier. */
975 LABEL (mod_halfhalf
):
978 JUMP (*++f
, step4_jumps
);
980 /* Process 'l' modifier. There might another 'l' following. */
983 JUMP (*++f
, step3b_jumps
);
985 /* Process 'L', 'q', or 'll' modifier. No other modifier is
986 allowed to follow. */
987 LABEL (mod_longlong
):
990 JUMP (*++f
, step4_jumps
);
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. */
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
1033 LABEL (form_floathex
):
1035 if (__glibc_unlikely ((mode_flags
& PRINTF_LDBL_IS_DBL
) != 0))
1038 struct printf_info info
=
1043 .is_long_double
= is_long_double
,
1044 .is_short
= is_short
,
1049 .showsign
= showsign
,
1053 .i18n
= use_outdigits
,
1054 .wide
= sizeof (CHAR_T
) != 1,
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)
1067 done_add (function_done
);
1071 LABEL (form_unknown
):
1072 if (spec
== L_('\0'))
1074 /* The format string ended before the specifier is complete. */
1075 __set_errno (EINVAL
);
1080 /* If we are in the fast loop force entering the complicated
1085 /* The format is correctly handled. */
1088 /* Look for next format specifier. */
1089 #ifdef COMPILE_WPRINTF
1090 f
= __find_specwc ((end_of_spec
= ++f
));
1092 f
= __find_specmb ((end_of_spec
= ++f
));
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. */
1103 /* Hand off processing for positional parameters. */
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
);
1110 /* Unlock the stream. */
1111 _IO_funlockfile (s
);
1112 _IO_cleanup_region_end (0);
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
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. */
1140 /* The number of arguments the format string requests. This will
1141 determine the size of the array needed to store the argument
1145 /* Positional parameters refer to arguments directly. This could
1146 also determine the maximum number of arguments. Track the
1148 size_t max_ref_arg
= 0;
1150 /* Just a counter. */
1153 if (grouping
== (const char *) -1)
1155 #ifdef COMPILE_WPRINTF
1156 thousands_sep
= _NL_CURRENT_WORD (LC_NUMERIC
,
1157 _NL_NUMERIC_THOUSANDS_SEP_WC
);
1159 thousands_sep
= _NL_CURRENT (LC_NUMERIC
, THOUSANDS_SEP
);
1162 grouping
= _NL_CURRENT (LC_NUMERIC
, GROUPING
);
1163 if (*grouping
== '\0' || *grouping
== CHAR_MAX
)
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
))
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
);
1185 nargs
+= __parse_one_specmb (f
, nargs
, &specs
[nspecs
], &max_ref_arg
);
1189 /* Determine the number of arguments the format string consumes. */
1190 nargs
= MAX (nargs
, max_ref_arg
);
1192 union printf_arg
*args_value
;
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
))
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
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. */
1234 case 1: /* One argument; we already have the
1236 args_type
[specs
[cnt
].data_arg
] = specs
[cnt
].data_arg_type
;
1237 args_size
[specs
[cnt
].data_arg
] = specs
[cnt
].size
;
1240 /* We have more than one argument for this format spec.
1241 We must call the arginfo function again to determine
1243 (void) (*__printf_arginfo_table
[specs
[cnt
].info
.spec
])
1245 specs
[cnt
].ndata_args
, &args_type
[specs
[cnt
].data_arg
],
1246 &args_size
[specs
[cnt
].data_arg
]);
1251 /* Now we know all the types and the order. Fill in the argument
1253 for (cnt
= 0; cnt
< nargs
; ++cnt
)
1254 switch (args_type
[cnt
])
1256 #define T(tag, mem, type) \
1258 args_value[cnt].mem = va_arg (*ap_savep, type); \
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
:
1267 T (PA_INT
, pa_int
, int);
1268 #if LONG_MAX == LONG_LONG_MAX
1269 case PA_INT
|PA_FLAG_LONG
:
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
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
);
1288 args_value
[cnt
].pa_long_double
= va_arg (*ap_savep
, long double);
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 *);
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
);
1305 memset (&args_value
[cnt
], 0, sizeof (args_value
[cnt
]));
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
)
1322 unsigned long long int longlong
;
1323 unsigned long int word
;
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
1373 specs
[nspecs_done
].info
.prec
= -1;
1375 prec
= specs
[nspecs_done
].info
.prec
;
1378 /* Process format specifiers. */
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
;
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. */
1410 done_add (function_done
);
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
1442 LABEL (form_floathex
):
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
);
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. */
1461 done_add (function_done
);
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 #
1471 if (function_done
< 0)
1473 /* Function has set errno. */
1478 done_add (function_done
);
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
);
1489 scratch_buffer_free (&argsbuf
);
1490 scratch_buffer_free (&specsbuf
);
1494 /* Handle an unknown format specifier. This prints out a canonicalized
1495 representation of the format spec itself. */
1497 printf_unknown (FILE *s
, const struct printf_info
*info
)
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
)];
1513 else if (info
->space
)
1517 if (info
->pad
== L_('0'))
1522 if (info
->width
!= 0)
1524 w
= _itoa_word (info
->width
, workend
, 10, 0);
1529 if (info
->prec
!= -1)
1532 w
= _itoa_word (info
->prec
, workend
, 10, 0);
1537 if (info
->spec
!= L_('\0'))
1538 outchar (info
->spec
);
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
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. */
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
);
1561 /* We treat all negative values like CHAR_MAX. */
1563 if (*grouping
== CHAR_MAX
|| *grouping
<= 0)
1564 /* No grouping should be done. */
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
);
1575 /* Process all characters in the string. */
1576 while (s
> front_ptr
)
1580 if (--len
== 0 && s
> front_ptr
)
1582 /* A new group begins. */
1583 #ifdef COMPILE_WPRINTF
1585 *--w
= thousands_sep
;
1587 /* Not enough room for the separator. */
1593 *--w
= thousands_sep
[--cnt
];
1596 /* Not enough room for the separator. */
1600 if (*grouping
== CHAR_MAX
1607 /* No further grouping to be done. Copy the rest of the
1610 memmove (w
, front_ptr
, (s
- front_ptr
) * sizeof (CHAR_T
));
1613 else if (*grouping
!= '\0')
1616 /* The previous grouping repeats ad infinitum. */
1623 /* Helper "class" for `fprintf to unbuffered': creates a temporary buffer. */
1626 struct _IO_FILE_plus _f
;
1627 #ifdef COMPILE_WPRINTF
1628 struct _IO_wide_data _wide_data
;
1631 #ifdef _IO_MTSAFE_IO
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
;
1644 size_t written
= _IO_sputn (target
, s
->_wide_data
->_IO_write_base
, used
);
1645 if (written
== 0 || written
== WEOF
)
1647 __wmemmove (s
->_wide_data
->_IO_write_base
,
1648 s
->_wide_data
->_IO_write_base
+ written
,
1650 s
->_wide_data
->_IO_write_ptr
-= written
;
1653 int used
= s
->_IO_write_ptr
- s
->_IO_write_base
;
1656 size_t written
= _IO_sputn (target
, s
->_IO_write_base
, used
);
1657 if (written
== 0 || written
== EOF
)
1659 memmove (s
->_IO_write_base
, s
->_IO_write_base
+ written
,
1661 s
->_IO_write_ptr
-= written
;
1667 #ifdef COMPILE_WPRINTF
1668 static const struct _IO_jump_t _IO_helper_jumps libio_vtable
=
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
)
1690 static const struct _IO_jump_t _IO_helper_jumps libio_vtable
=
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
)
1714 buffered_vfprintf (FILE *s
, const CHAR_T
*format
, va_list args
,
1715 unsigned int mode_flags
)
1718 struct helper_file helper
;
1719 FILE *hp
= (FILE *) &helper
._f
;
1720 int result
, to_flush
;
1722 /* Orient the stream. */
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
));
1734 _IO_setp (hp
, buf
, buf
+ sizeof buf
);
1737 hp
->_flags
= _IO_MAGIC
|_IO_NO_READS
|_IO_USER_LOCK
;
1738 #if _IO_JUMPS_OFFSET
1739 hp
->_vtable_offset
= 0;
1741 #ifdef _IO_MTSAFE_IO
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
);
1751 __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile
, 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
)
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
)
1771 /* Unlock the stream. */
1772 _IO_funlockfile (s
);
1773 __libc_cleanup_region_end (0);