1 /* Argument-processing fragment for vfprintf.
2 Copyright (C) 1991-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 /* This file is included twice from vfprintf-internal.c, for standard
20 and GNU-style positional (%N$) arguments. Before that,
21 process_arg_int etc. macros have to be defined to extract one
22 argument of the appropriate type, in addition to the file-specific
23 macros in vfprintf-internal.c. */
26 /* Start real work. We know about all flags and modifiers and
27 now process the wanted format specifier. */
29 /* Write a literal "%". */
30 Xprintf_buffer_putc (buf
, L_('%'));
34 /* Signed decimal integer. */
39 long long int signed_number
= process_arg_long_long_int ();
40 is_negative
= signed_number
< 0;
41 number
.longlong
= is_negative
? (- signed_number
) : signed_number
;
43 goto LABEL (longlong_number
);
47 long int signed_number
;
49 signed_number
= process_arg_long_int ();
51 signed_number
= (signed char) process_arg_unsigned_int ();
53 signed_number
= process_arg_int ();
55 signed_number
= (short int) process_arg_unsigned_int ();
57 is_negative
= signed_number
< 0;
58 number
.word
= is_negative
? (- signed_number
) : signed_number
;
64 LABEL (form_unsigned
):
65 /* Unsigned decimal integer. */
67 goto LABEL (unsigned_number
);
71 /* Unsigned octal integer. */
73 goto LABEL (unsigned_number
);
77 /* Unsigned hexadecimal integer. */
79 goto LABEL (unsigned_number
);
83 /* Unsigned binary integer. */
85 goto LABEL (unsigned_number
);
88 LABEL (unsigned_number
): /* Unsigned number of base BASE. */
90 /* ISO specifies the `+' and ` ' flags only for signed
98 number
.longlong
= process_arg_unsigned_long_long_int ();
100 LABEL (longlong_number
):
102 /* Supply a default precision if none was given. */
105 /* We have to take care for the '0' flag. If a precision
106 is given it must be ignored. */
109 /* If the precision is 0 and the number is 0 nothing has to
110 be written for the number, except for the 'o' format in
112 if (prec
== 0 && number
.longlong
== 0)
115 if (base
== 8 && alt
)
119 /* Put the number in WORK. */
120 string
= _itoa (number
.longlong
, workend
, base
, spec
== L_('X'));
121 /* Simplify further test for num != 0. */
122 number
.word
= number
.longlong
!= 0;
127 number
.word
= process_arg_unsigned_long_int ();
129 number
.word
= (unsigned char) process_arg_unsigned_int ();
131 number
.word
= process_arg_unsigned_int ();
133 number
.word
= (unsigned short int) process_arg_unsigned_int ();
137 /* Supply a default precision if none was given. */
140 /* We have to take care for the '0' flag. If a precision
141 is given it must be ignored. */
144 /* If the precision is 0 and the number is 0 nothing has to
145 be written for the number, except for the 'o' format in
147 if (prec
== 0 && number
.word
== 0)
150 if (base
== 8 && alt
)
154 /* Put the number in WORK. */
155 string
= _itoa_word (number
.word
, workend
, base
,
159 /* Grouping is also used for outdigits translation. */
160 struct grouping_iterator iter
;
161 bool number_slow_path
= group
|| (use_outdigits
&& base
== 10);
163 __grouping_iterator_init (&iter
, LC_NUMERIC
, _NL_CURRENT_LOCALE
,
165 else if (use_outdigits
&& base
== 10)
166 __grouping_iterator_init_none (&iter
, workend
- string
);
169 #ifndef COMPILE_WPRINTF
170 if (use_outdigits
&& base
== 10)
171 number_length
= __translated_number_width (_NL_CURRENT_LOCALE
,
174 number_length
= workend
- string
;
176 number_length
+= iter
.separators
* strlen (thousands_sep
);
178 number_length
= workend
- string
;
179 /* All wide separators have length 1. */
180 if (group
&& thousands_sep
!= L
'\0')
181 number_length
+= iter
.separators
;
184 /* The marker comes right before the number, but is not subject
186 bool octal_marker
= (prec
<= number_length
&& number
.word
!= 0
187 && alt
&& base
== 8);
189 /* At this point prec_inc is the additional bytes required for the
190 specificed precision. It is 0 if the precision would not have
191 required additional bytes i.e. the number of input digits is more
192 than the precision. It is greater than zero if the precision is
193 more than the number of digits without grouping (precision only
194 considers digits). */
195 unsigned int prec_inc
= MAX (0, prec
- (workend
- string
));
199 width
-= number_length
+ prec_inc
;
201 if (number
.word
!= 0 && alt
&& (base
== 16 || base
== 2))
202 /* Account for 0X, 0x, 0B or 0b hex or binary marker. */
208 if (is_negative
|| showsign
|| space
)
213 Xprintf_buffer_pad (buf
, L_(' '), width
);
218 Xprintf_buffer_putc (buf
, L_('-'));
220 Xprintf_buffer_putc (buf
, L_('+'));
222 Xprintf_buffer_putc (buf
, L_(' '));
224 if (number
.word
!= 0 && alt
&& (base
== 16 || base
== 2))
226 Xprintf_buffer_putc (buf
, L_('0'));
227 Xprintf_buffer_putc (buf
, spec
);
231 Xprintf_buffer_pad (buf
, L_('0'), width
);
234 Xprintf_buffer_putc (buf
, L_('0'));
236 if (number_slow_path
)
237 group_number (buf
, &iter
, string
, workend
, thousands_sep
,
238 use_outdigits
&& base
== 10);
240 Xprintf_buffer_write (buf
, string
, workend
- string
);
246 /* Perform left justification adjustments. */
250 Xprintf_buffer_putc (buf
, L_('-'));
255 Xprintf_buffer_putc (buf
, L_('+'));
260 Xprintf_buffer_putc (buf
, L_(' '));
264 if (number
.word
!= 0 && alt
&& (base
== 16 || base
== 2))
266 Xprintf_buffer_putc (buf
, L_('0'));
267 Xprintf_buffer_putc (buf
, spec
);
274 /* Adjust the width by subtracting the number of bytes
275 required to represent the number with grouping characters
276 (NUMBER_LENGTH) and any additional bytes required for
278 width
-= number_length
+ prec_inc
;
280 Xprintf_buffer_pad (buf
, L_('0'), prec_inc
);
283 Xprintf_buffer_putc (buf
, L_('0'));
285 if (number_slow_path
)
286 group_number (buf
, &iter
, string
, workend
, thousands_sep
,
287 use_outdigits
&& base
== 10);
289 Xprintf_buffer_write (buf
, string
, workend
- string
);
291 Xprintf_buffer_pad (buf
, L_(' '), width
);
295 LABEL (form_pointer
):
296 /* Generic pointer. */
298 const void *ptr
= process_arg_pointer ();
301 /* If the pointer is not NULL, write it as a %#x spec. */
303 number
.word
= (unsigned long int) ptr
;
312 /* Write "(nil)" for a nil pointer. */
313 string
= (CHAR_T
*) L_("(nil)");
314 /* Make sure the full string "(nil)" is printed. */
317 /* This is a wide string iff compiling wprintf. */
318 is_long
= sizeof (CHAR_T
) > 1;
319 goto LABEL (print_string
);
325 if ((mode_flags
& PRINTF_FORTIFY
) != 0)
327 if (! readonly_format
)
329 extern int __readonly_area (const void *, size_t)
332 = __readonly_area (format
, ((STR_LEN (format
) + 1)
335 if (readonly_format
< 0)
336 __libc_fatal ("*** %n in writable segment detected ***\n");
338 /* Answer the count of characters written. */
339 void *ptrptr
= process_arg_pointer ();
340 unsigned int written
= Xprintf_buffer_done (buf
);
342 *(long long int *) ptrptr
= written
;
343 else if (is_long_num
)
344 *(long int *) ptrptr
= written
;
346 *(char *) ptrptr
= written
;
348 *(int *) ptrptr
= written
;
350 *(short int *) ptrptr
= written
;
353 LABEL (form_strerror
):
354 /* Print description of error ERRNO. */
356 string
= (CHAR_T
*) __get_errname (save_errno
);
358 string
= (CHAR_T
*) __strerror_r (save_errno
, (char *) work_buffer
,
359 WORK_BUFFER_SIZE
* sizeof (CHAR_T
));
362 /* Print as a decimal number. */
364 is_negative
= save_errno
< 0;
365 number
.word
= save_errno
;
367 number
.word
= -number
.word
;
372 is_long
= 0; /* This is no wide-char string. */
373 goto LABEL (print_string
);
376 LABEL (form_character
):
379 goto LABEL (form_wcharacter
);
380 --width
; /* Account for the character itself. */
382 Xprintf_buffer_pad (buf
, L_(' '), width
);
383 #ifdef COMPILE_WPRINTF
384 __wprintf_buffer_putc (buf
, __btowc ((unsigned char) /* Promoted. */
385 process_arg_int ()));
387 __printf_buffer_putc (buf
, (unsigned char) /* Promoted. */
391 Xprintf_buffer_pad (buf
, L_(' '), width
);
398 /* The string argument could in fact be `char *' or `wchar_t *'.
399 But this should not make a difference here. */
400 #ifdef COMPILE_WPRINTF
401 string
= (CHAR_T
*) process_arg_wstring ();
403 string
= (CHAR_T
*) process_arg_string ();
405 /* Entry point for printing other strings. */
406 LABEL (print_string
):
410 /* Write "(null)" if there's space. */
411 if (prec
== -1 || prec
>= (int) array_length (null
) - 1)
413 string
= (CHAR_T
*) null
;
414 len
= array_length (null
) - 1;
418 string
= (CHAR_T
*) L
"";
422 else if (!is_long
&& spec
!= L_('S'))
424 #ifdef COMPILE_WPRINTF
425 outstring_converted_wide_string (buf
, (const char *) string
,
427 /* The padding has already been written. */
431 /* Search for the end of the string, but don't search past
432 the length (in bytes) specified by the precision. */
433 len
= __strnlen (string
, prec
);
435 len
= strlen (string
);
440 #ifdef COMPILE_WPRINTF
442 /* Search for the end of the string, but don't search past
443 the length specified by the precision. */
444 len
= __wcsnlen (string
, prec
);
446 len
= __wcslen (string
);
448 outstring_converted_wide_string (buf
, (const wchar_t *) string
,
450 /* The padding has already been written. */
455 if ((width
-= len
) < 0)
457 Xprintf_buffer_write (buf
, string
, len
);
462 Xprintf_buffer_pad (buf
, L_(' '), width
);
463 Xprintf_buffer_write (buf
, string
, len
);
465 Xprintf_buffer_pad (buf
, L_(' '), width
);
469 #ifdef COMPILE_WPRINTF
470 LABEL (form_wcharacter
):
472 /* Wide character. */
475 Xprintf_buffer_pad (buf
, L_(' '), width
);
476 Xprintf_buffer_putc (buf
, process_arg_wchar_t ());
478 Xprintf_buffer_pad (buf
, L_(' '), width
);
482 #else /* !COMPILE_WPRINTF */
483 LABEL (form_wcharacter
):
485 /* Wide character. */
486 char wcbuf
[MB_LEN_MAX
];
490 memset (&mbstate
, '\0', sizeof (mbstate_t));
491 len
= __wcrtomb (wcbuf
, process_arg_wchar_t (), &mbstate
);
492 if (len
== (size_t) -1)
494 /* Something went wrong during the conversion. Bail out. */
495 __printf_buffer_mark_failed (buf
);
500 Xprintf_buffer_pad (buf
, L_(' '), width
);
501 Xprintf_buffer_write (buf
, wcbuf
, len
);
503 Xprintf_buffer_pad (buf
, L_(' '), width
);
506 #endif /* !COMPILE_WPRINTF */