1 .\" Copyright (C) 2022 Alejandro Colomar <alx.manpages@gmail.com>
3 .\" SPDX-License-Identifier: Linux-man-pages-copyleft
5 .TH printf.h 3head 2022-09-18 "Linux man-pages (unreleased)"
8 \%register_printf_specifier,
9 \%register_printf_modifier,
10 \%register_printf_type,
12 \%printf_arginfo_size_function,
13 \%printf_va_arg_function,
25 \%PA_FLAG_LONG_DOUBLE,
29 \- define custom behavior for printf-like functions
32 .RI ( libc ", " \-lc )
35 .B #include <printf.h>
37 .BI "int register_printf_specifier(int " spec ", printf_function " func ,
38 .BI " printf_arginfo_size_function " arginfo );
39 .BI "int register_printf_modifier(const wchar_t *" str );
40 .BI "int register_printf_type(printf_va_arg_function " fct );
44 .BI "typedef int printf_function(FILE *" stream ", const struct printf_info *" info ,
45 .BI " const void *const " args []);
46 .BI "typedef int printf_arginfo_size_function(const struct printf_info *" info ,
47 .BI " size_t " n ", int " argtypes [ n "], int " size [ n ]);
48 .BI "typedef void printf_va_arg_function(void *" mem ", va_list *" ap );
52 .B struct printf_info {
53 .BR " int prec; " "// Precision"
54 .BR " int width; " "// Width"
55 .BR " wchar_t spec; " "// Format letter"
56 .BR " unsigned int is_long_double:1;" "// " L " or " ll " flag"
57 .BR " unsigned int is_short:1; " "// " h " flag"
58 .BR " unsigned int is_long:1; " "// " l " flag"
59 .BR " unsigned int alt:1; " "// " # " flag"
60 .BR " unsigned int space:1; " "// Space flag"
61 .BR " unsigned int left:1; " "// " - " flag"
62 .BR " unsigned int showsign:1; " "// " + " flag"
63 .BR " unsigned int group:1; " "// " \[aq] " flag"
64 .BR " unsigned int extra:1; " "// For special use"
65 .BR " unsigned int is_char:1; " "// " hh " flag"
66 .BR " unsigned int wide:1; " "// True for wide character streams"
67 .BR " unsigned int i18n:1; " "// " I " flag"
68 .BR " unsigned int is_binary128:1; " "/* Floating-point argument is"
69 .BR " " " ABI-compatible with"
70 .BR " " " IEC 60559 binary128 */"
71 .BR " unsigned short user; " "// Bits for user-installed modifiers"
72 .BR " wchar_t pad; " "// Padding character"
77 .BR "#define PA_FLAG_LONG_LONG " "/* ... */"
78 .BR "#define PA_FLAG_LONG_DOUBLE " "/* ... */"
79 .BR "#define PA_FLAG_LONG " "/* ... */"
80 .BR "#define PA_FLAG_SHORT " "/* ... */"
81 .BR "#define PA_FLAG_PTR " "/* ... */"
84 These functions serve to extend and/or modify the behavior of the
87 .SS register_printf_specifier()
88 This function registers a custom conversion specifier for the
93 The character which will be used as a conversion specifier in the format string.
96 Callback function that will be executed by the
99 to format the input arguments into the output
104 Output stream where the formatted output should be printed.
105 This stream transparently represents the output,
106 even in the case of functions that write to a string.
109 Structure that holds context information,
110 including the modifiers specified in the format string.
111 This holds the same contents as in
115 Array of pointers to the arguments to the
121 Callback function that will be executed by the
124 to know how many arguments should be parsed for the custom specifier
125 and also their types.
129 Structure that holds context information,
130 including the modifiers specified in the format string.
131 This holds the same contents as in
135 Number of arguments remaining to be parsed.
138 This array should be set to
139 define the type of each of the arguments that will be parsed.
140 Each element in the array represents one of the arguments to be parsed,
141 in the same order that they are passed to the
144 Each element should be set to a base type
148 and optionally ORed with an appropriate length modifier
152 The type is determined by using one of the following constants:
166 .IR "const char\~*" ,
167 a \(aq\e0\(aq-terminated string.
170 .IR "const wchar_t\~*" ,
171 a wide character L\(aq\e0\(aq-terminated string.
187 For user-defined types,
188 the size of the type (in bytes) should also be specified through this array.
189 Otherwise, leave it unused.
195 and prepares some information needed to call
197 .SS register_printf_modifier()
199 .SS register_printf_type()
202 .BR \%register_printf_specifier (),
203 .BR \%register_printf_modifier (),
205 .BR \%register_printf_type ()
206 return zero on success, or \-1 on error.
210 should return the number of characters written,
214 .I \%printf_arginfo_size_function
215 should return the number of arguments to be parsed by this specifier.
216 It also passes information about the type of those arguments
217 to the caller through
219 On error, it should return \-1.
223 The specifier was not a valid character.
227 .BR \%register_printf_function (3)
228 is an older function similar to
229 .BR \%register_printf_specifier (),
230 and is now deprecated.
231 That function can't handle user-defined types.
233 .BR \%register_printf_specifier ()
235 .BR \%register_printf_function (3).
237 The following example program registers the 'b' and 'B' specifiers
238 to print integers in binary format,
239 mirroring rules for other unsigned conversion specifiers like 'x' and 'u'.
240 This can be used to print in binary prior to C23.
242 .\" SRC BEGIN (register_printf_specifier.c)
244 /* This code is in the public domain */
253 #include <sys/param.h>
257 #define GROUP_SEP \[aq]\e\[aq]\[aq]
264 static int b_printf(FILE *stream, const struct printf_info *info,
265 const void *const args[]);
266 static int b_arginf_sz(const struct printf_info *info,
267 size_t n, int argtypes[n], int size[n]);
269 static uintmax_t b_value(const struct printf_info *info,
271 static size_t b_bin_repr(char bin[UINTMAX_WIDTH],
272 const struct printf_info *info, const void *arg);
273 static size_t b_bin_len(const struct printf_info *info,
275 static size_t b_pad_len(const struct printf_info *info,
277 static ssize_t b_print_prefix(FILE *stream,
278 const struct printf_info *info);
279 static ssize_t b_pad_zeros(FILE *stream, const struct printf_info *info,
281 static ssize_t b_print_number(FILE *stream,
282 const struct printf_info *info,
283 const char bin[UINTMAX_WIDTH],
284 size_t min_len, size_t bin_len);
285 static char pad_ch(const struct printf_info *info);
286 static ssize_t pad_spaces(FILE *stream, size_t pad_len);
291 if (register_printf_specifier(\[aq]b\[aq], b_printf, b_arginf_sz) == \-1)
292 err(EXIT_FAILURE, "register_printf_specifier(\[aq]b\[aq], ...)");
293 if (register_printf_specifier(\[aq]B\[aq], b_printf, b_arginf_sz) == \-1)
294 err(EXIT_FAILURE, "register_printf_specifier(\[aq]B\[aq], ...)");
296 printf("....----....----....----....----\en");
297 printf("%llb;\en", 0x5Ellu);
298 printf("%lB;\en", 0x5Elu);
299 printf("%b;\en", 0x5Eu);
300 printf("%hB;\en", 0x5Eu);
301 printf("%hhb;\en", 0x5Eu);
302 printf("%jb;\en", (uintmax_t)0x5E);
303 printf("%zb;\en", (size_t)0x5E);
304 printf("....----....----....----....----\en");
305 printf("%#b;\en", 0x5Eu);
306 printf("%#B;\en", 0x5Eu);
307 printf("....----....----....----....----\en");
308 printf("%10b;\en", 0x5Eu);
309 printf("%010b;\en", 0x5Eu);
310 printf("%.10b;\en", 0x5Eu);
311 printf("....----....----....----....----\en");
312 printf("%\-10B;\en", 0x5Eu);
313 printf("....----....----....----....----\en");
314 printf("%\[aq]B;\en", 0x5Eu);
315 printf("....----....----....----....----\en");
316 printf("....----....----....----....----\en");
317 printf("%#16.12b;\en", 0xAB);
318 printf("%\-#\[aq]20.12b;\en", 0xAB);
319 printf("%#\[aq]020B;\en", 0xAB);
320 printf("....----....----....----....----\en");
321 printf("%#020B;\en", 0xAB);
322 printf("%\[aq]020B;\en", 0xAB);
323 printf("%020B;\en", 0xAB);
324 printf("....----....----....----....----\en");
325 printf("%#021B;\en", 0xAB);
326 printf("%\[aq]021B;\en", 0xAB);
327 printf("%021B;\en", 0xAB);
328 printf("....----....----....----....----\en");
329 printf("%#022B;\en", 0xAB);
330 printf("%\[aq]022B;\en", 0xAB);
331 printf("%022B;\en", 0xAB);
332 printf("....----....----....----....----\en");
333 printf("%#023B;\en", 0xAB);
334 printf("%\[aq]023B;\en", 0xAB);
335 printf("%023B;\en", 0xAB);
336 printf("....----....----....----....----\en");
337 printf("%\-#\[aq]19.11b;\en", 0xAB);
338 printf("%#\[aq]019B;\en", 0xAB);
339 printf("%#019B;\en", 0xAB);
340 printf("....----....----....----....----\en");
341 printf("%\[aq]019B;\en", 0xAB);
342 printf("%019B;\en", 0xAB);
343 printf("%#016b;\en", 0xAB);
344 printf("....----....----....----....----\en");
350 b_printf(FILE *stream, const struct printf_info *info,
351 const void *const args[])
353 char bin[UINTMAX_WIDTH];
354 size_t min_len, bin_len;
356 struct Printf_Pad pad = {0};
360 min_len = b_bin_repr(bin, info, args[0]);
361 bin_len = b_bin_len(info, min_len);
363 pad.ch = pad_ch(info);
364 if (pad.ch == \[aq] \[aq])
365 pad.len = b_pad_len(info, bin_len);
367 /* Padding with \[aq] \[aq] (right aligned) */
368 if ((pad.ch == \[aq] \[aq]) && !info->left) {
369 tmp = pad_spaces(stream, pad.len);
375 /* "0b"/"0B" prefix */
377 tmp = b_print_prefix(stream, info);
383 /* Padding with \[aq]0\[aq] */
384 if (pad.ch == \[aq]0\[aq]) {
385 tmp = b_pad_zeros(stream, info, min_len);
391 /* Print number (including leading 0s to fill precision) */
392 tmp = b_print_number(stream, info, bin, min_len, bin_len);
397 /* Padding with \[aq] \[aq] (left aligned) */
399 tmp = pad_spaces(stream, pad.len);
409 b_arginf_sz(const struct printf_info *info, size_t n, int argtypes[n],
410 [[maybe_unused]] int size[n])
415 if (info\->is_long_double)
416 argtypes[0] = PA_INT | PA_FLAG_LONG_LONG;
417 else if (info\->is_long)
418 argtypes[0] = PA_INT | PA_FLAG_LONG;
420 argtypes[0] = PA_INT;
426 b_value(const struct printf_info *info, const void *arg)
428 if (info\->is_long_double)
429 return *(const unsigned long long *)arg;
431 return *(const unsigned long *)arg;
433 /* short and char are both promoted to int */
434 return *(const unsigned int *)arg;
438 b_bin_repr(char bin[UINTMAX_WIDTH],
439 const struct printf_info *info, const void *arg)
444 val = b_value(info, arg);
446 bin[0] = \[aq]0\[aq];
447 for (min_len = 0; val; min_len++) {
448 bin[min_len] = \[aq]0\[aq] + (val % 2);
452 return MAX(min_len, 1);
456 b_bin_len(const struct printf_info *info, ptrdiff_t min_len)
458 return MAX(info\->prec, min_len);
462 b_pad_len(const struct printf_info *info, ptrdiff_t bin_len)
466 pad_len = info\->width \- bin_len;
470 pad_len \-= (bin_len \- 1) / 4;
472 return MAX(pad_len, 0);
476 b_print_prefix(FILE *stream, const struct printf_info *info)
481 if (fputc(\[aq]0\[aq], stream) == EOF)
484 if (fputc(info\->spec, stream) == EOF)
492 b_pad_zeros(FILE *stream, const struct printf_info *info,
499 tmp = info\->width \- (info\->alt * 2);
501 tmp \-= tmp / 5 \- !(tmp % 5);
502 for (ptrdiff_t i = tmp \- 1; i > min_len \- 1; i\-\-) {
503 if (fputc(\[aq]0\[aq], stream) == EOF)
507 if (!info\->group || (i % 4))
509 if (fputc(GROUP_SEP, stream) == EOF)
518 b_print_number(FILE *stream, const struct printf_info *info,
519 const char bin[UINTMAX_WIDTH],
520 size_t min_len, size_t bin_len)
526 /* Print leading zeros to fill precision */
527 for (size_t i = bin_len \- 1; i > min_len \- 1; i\-\-) {
528 if (fputc(\[aq]0\[aq], stream) == EOF)
532 if (!info\->group || (i % 4))
534 if (fputc(GROUP_SEP, stream) == EOF)
540 for (size_t i = min_len \- 1; i < min_len; i\-\-) {
541 if (fputc(bin[i], stream) == EOF)
545 if (!info\->group || (i % 4) || !i)
547 if (fputc(GROUP_SEP, stream) == EOF)
556 pad_ch(const struct printf_info *info)
558 if ((info\->prec != \-1) || (info\->pad == \[aq] \[aq]) || info\->left)
564 pad_spaces(FILE *stream, size_t pad_len)
569 for (size_t i = pad_len - 1; i < pad_len; i\-\-) {
570 if (fputc(\[aq] \[aq], stream) == EOF)