1printf.h(3head) printf.h(3head)
2
3
4
6 printf.h, register_printf_specifier, register_printf_modifier,
7 register_printf_type, printf_function, printf_arginfo_size_function,
8 printf_va_arg_function, printf_info, PA_INT, PA_CHAR, PA_WCHAR,
9 PA_STRING, PA_WSTRING, PA_POINTER, PA_FLOAT, PA_DOUBLE, PA_LAST,
10 PA_FLAG_LONG_LONG, PA_FLAG_LONG_DOUBLE, PA_FLAG_LONG, PA_FLAG_SHORT,
11 PA_FLAG_PTR - define custom behavior for printf-like functions
12
14 Standard C library (libc, -lc)
15
17 #include <printf.h>
18
19 int register_printf_specifier(int spec, printf_function func,
20 printf_arginfo_size_function arginfo);
21 int register_printf_modifier(const wchar_t *str);
22 int register_printf_type(printf_va_arg_function fct);
23
24 Callbacks
25 typedef int printf_function(FILE *stream, const struct printf_info *info,
26 const void *const args[]);
27 typedef int printf_arginfo_size_function(const struct printf_info *info,
28 size_t n, int argtypes[n], int size[n]);
29 typedef void printf_va_arg_function(void *mem, va_list *ap);
30
31 Types
32 struct printf_info {
33 int prec; // Precision
34 int width; // Width
35 wchar_t spec; // Format letter
36 unsigned int is_long_double:1;// L or ll flag
37 unsigned int is_short:1; // h flag
38 unsigned int is_long:1; // l flag
39 unsigned int alt:1; // # flag
40 unsigned int space:1; // Space flag
41 unsigned int left:1; // - flag
42 unsigned int showsign:1; // + flag
43 unsigned int group:1; // ' flag
44 unsigned int extra:1; // For special use
45 unsigned int is_char:1; // hh flag
46 unsigned int wide:1; // True for wide character streams
47 unsigned int i18n:1; // I flag
48 unsigned int is_binary128:1; /* Floating-point argument is
49 ABI-compatible with
50 IEC 60559 binary128 */
51 unsigned short user; // Bits for user-installed modifiers
52 wchar_t pad; // Padding character
53 };
54
55 Constants
56 #define PA_FLAG_LONG_LONG /* ... */
57 #define PA_FLAG_LONG_DOUBLE /* ... */
58 #define PA_FLAG_LONG /* ... */
59 #define PA_FLAG_SHORT /* ... */
60 #define PA_FLAG_PTR /* ... */
61
63 These functions serve to extend and/or modify the behavior of the
64 printf(3) family of functions.
65
66 register_printf_specifier()
67 This function registers a custom conversion specifier for the printf(3)
68 family of functions.
69
70 spec The character which will be used as a conversion specifier in
71 the format string.
72
73 func Callback function that will be executed by the printf(3) family
74 of functions to format the input arguments into the output
75 stream.
76
77 stream Output stream where the formatted output should be
78 printed. This stream transparently represents the out‐
79 put, even in the case of functions that write to a
80 string.
81
82 info Structure that holds context information, including the
83 modifiers specified in the format string. This holds the
84 same contents as in arginfo.
85
86 args Array of pointers to the arguments to the printf(3)-like
87 function.
88
89 arginfo
90 Callback function that will be executed by the printf(3) family
91 of functions to know how many arguments should be parsed for the
92 custom specifier and also their types.
93
94 info Structure that holds context information, including the
95 modifiers specified in the format string. This holds the
96 same contents as in func.
97
98 n Number of arguments remaining to be parsed.
99
100 argtypes
101 This array should be set to define the type of each of
102 the arguments that will be parsed. Each element in the
103 array represents one of the arguments to be parsed, in
104 the same order that they are passed to the printf(3)-like
105 function. Each element should be set to a base type
106 (PA_*) from the enum above, or a custom one, and option‐
107 ally ORed with an appropriate length modifier
108 (PA_FLAG_*).
109
110 The type is determined by using one of the following con‐
111 stants:
112
113 PA_INT int.
114
115 PA_CHAR
116 int, cast to char.
117
118 PA_WCHAR
119 wchar_t.
120
121 PA_STRING
122 const char *, a '\0'-terminated string.
123
124 PA_WSTRING
125 const wchar_t *, a wide character L'\0'-terminated
126 string.
127
128 PA_POINTER
129 void *.
130
131 PA_FLOAT
132 float.
133
134 PA_DOUBLE
135 double.
136
137 PA_LAST
138 TODO.
139
140 size For user-defined types, the size of the type (in bytes)
141 should also be specified through this array. Otherwise,
142 leave it unused.
143
144 arginfo is called before func, and prepares some information needed to
145 call func.
146
147 register_printf_modifier()
148 TODO
149
150 register_printf_type()
151 TODO
152
154 register_printf_specifier(), register_printf_modifier(), and
155 register_printf_type() return zero on success, or -1 on error.
156
157 Callbacks
158 The callback of type printf_function should return the number of char‐
159 acters written, or -1 on error.
160
161 The callback of type printf_arginfo_size_function should return the
162 number of arguments to be parsed by this specifier. It also passes in‐
163 formation about the type of those arguments to the caller through
164 argtypes. On error, it should return -1.
165
167 EINVAL The specifier was not a valid character.
168
170 GNU.
171
173 register_printf_function(3) is an older function similar to
174 register_printf_specifier(), and is now deprecated. That function
175 can't handle user-defined types.
176
177 register_printf_specifier() superseeds register_printf_function(3).
178
180 The following example program registers the 'b' and 'B' specifiers to
181 print integers in binary format, mirroring rules for other unsigned
182 conversion specifiers like 'x' and 'u'. This can be used to print in
183 binary prior to C23.
184
185 /* This code is in the public domain */
186
187 #include <err.h>
188 #include <limits.h>
189 #include <stddef.h>
190 #include <stdint.h>
191 #include <stdio.h>
192 #include <stdlib.h>
193 #include <string.h>
194 #include <sys/param.h>
195
196 #include <printf.h>
197
198 #define GROUP_SEP '\''
199
200 struct Printf_Pad {
201 char ch;
202 size_t len;
203 };
204
205 static int b_printf(FILE *stream, const struct printf_info *info,
206 const void *const args[]);
207 static int b_arginf_sz(const struct printf_info *info,
208 size_t n, int argtypes[n], int size[n]);
209
210 static uintmax_t b_value(const struct printf_info *info,
211 const void *arg);
212 static size_t b_bin_repr(char bin[UINTMAX_WIDTH],
213 const struct printf_info *info, const void *arg);
214 static size_t b_bin_len(const struct printf_info *info,
215 ptrdiff_t min_len);
216 static size_t b_pad_len(const struct printf_info *info,
217 ptrdiff_t bin_len);
218 static ssize_t b_print_prefix(FILE *stream,
219 const struct printf_info *info);
220 static ssize_t b_pad_zeros(FILE *stream, const struct printf_info *info,
221 ptrdiff_t min_len);
222 static ssize_t b_print_number(FILE *stream,
223 const struct printf_info *info,
224 const char bin[UINTMAX_WIDTH],
225 size_t min_len, size_t bin_len);
226 static char pad_ch(const struct printf_info *info);
227 static ssize_t pad_spaces(FILE *stream, size_t pad_len);
228
229 int
230 main(void)
231 {
232 if (register_printf_specifier('b', b_printf, b_arginf_sz) == -1)
233 err(EXIT_FAILURE, "register_printf_specifier('b', ...)");
234 if (register_printf_specifier('B', b_printf, b_arginf_sz) == -1)
235 err(EXIT_FAILURE, "register_printf_specifier('B', ...)");
236
237 printf("....----....----....----....----\n");
238 printf("%llb;\n", 0x5Ellu);
239 printf("%lB;\n", 0x5Elu);
240 printf("%b;\n", 0x5Eu);
241 printf("%hB;\n", 0x5Eu);
242 printf("%hhb;\n", 0x5Eu);
243 printf("%jb;\n", (uintmax_t)0x5E);
244 printf("%zb;\n", (size_t)0x5E);
245 printf("....----....----....----....----\n");
246 printf("%#b;\n", 0x5Eu);
247 printf("%#B;\n", 0x5Eu);
248 printf("....----....----....----....----\n");
249 printf("%10b;\n", 0x5Eu);
250 printf("%010b;\n", 0x5Eu);
251 printf("%.10b;\n", 0x5Eu);
252 printf("....----....----....----....----\n");
253 printf("%-10B;\n", 0x5Eu);
254 printf("....----....----....----....----\n");
255 printf("%'B;\n", 0x5Eu);
256 printf("....----....----....----....----\n");
257 printf("....----....----....----....----\n");
258 printf("%#16.12b;\n", 0xAB);
259 printf("%-#'20.12b;\n", 0xAB);
260 printf("%#'020B;\n", 0xAB);
261 printf("....----....----....----....----\n");
262 printf("%#020B;\n", 0xAB);
263 printf("%'020B;\n", 0xAB);
264 printf("%020B;\n", 0xAB);
265 printf("....----....----....----....----\n");
266 printf("%#021B;\n", 0xAB);
267 printf("%'021B;\n", 0xAB);
268 printf("%021B;\n", 0xAB);
269 printf("....----....----....----....----\n");
270 printf("%#022B;\n", 0xAB);
271 printf("%'022B;\n", 0xAB);
272 printf("%022B;\n", 0xAB);
273 printf("....----....----....----....----\n");
274 printf("%#023B;\n", 0xAB);
275 printf("%'023B;\n", 0xAB);
276 printf("%023B;\n", 0xAB);
277 printf("....----....----....----....----\n");
278 printf("%-#'19.11b;\n", 0xAB);
279 printf("%#'019B;\n", 0xAB);
280 printf("%#019B;\n", 0xAB);
281 printf("....----....----....----....----\n");
282 printf("%'019B;\n", 0xAB);
283 printf("%019B;\n", 0xAB);
284 printf("%#016b;\n", 0xAB);
285 printf("....----....----....----....----\n");
286
287 return 0;
288 }
289
290 static int
291 b_printf(FILE *stream, const struct printf_info *info,
292 const void *const args[])
293 {
294 char bin[UINTMAX_WIDTH];
295 size_t min_len, bin_len;
296 ssize_t len, tmp;
297 struct Printf_Pad pad = {0};
298
299 len = 0;
300
301 min_len = b_bin_repr(bin, info, args[0]);
302 bin_len = b_bin_len(info, min_len);
303
304 pad.ch = pad_ch(info);
305 if (pad.ch == ' ')
306 pad.len = b_pad_len(info, bin_len);
307
308 /* Padding with ' ' (right aligned) */
309 if ((pad.ch == ' ') && !info->left) {
310 tmp = pad_spaces(stream, pad.len);
311 if (tmp == EOF)
312 return EOF;
313 len += tmp;
314 }
315
316 /* "0b"/"0B" prefix */
317 if (info->alt) {
318 tmp = b_print_prefix(stream, info);
319 if (tmp == EOF)
320 return EOF;
321 len += tmp;
322 }
323
324 /* Padding with '0' */
325 if (pad.ch == '0') {
326 tmp = b_pad_zeros(stream, info, min_len);
327 if (tmp == EOF)
328 return EOF;
329 len += tmp;
330 }
331
332 /* Print number (including leading 0s to fill precision) */
333 tmp = b_print_number(stream, info, bin, min_len, bin_len);
334 if (tmp == EOF)
335 return EOF;
336 len += tmp;
337
338 /* Padding with ' ' (left aligned) */
339 if (info->left) {
340 tmp = pad_spaces(stream, pad.len);
341 if (tmp == EOF)
342 return EOF;
343 len += tmp;
344 }
345
346 return len;
347 }
348
349 static int
350 b_arginf_sz(const struct printf_info *info, size_t n, int argtypes[n],
351 [[maybe_unused]] int size[n])
352 {
353 if (n < 1)
354 return -1;
355
356 if (info->is_long_double)
357 argtypes[0] = PA_INT | PA_FLAG_LONG_LONG;
358 else if (info->is_long)
359 argtypes[0] = PA_INT | PA_FLAG_LONG;
360 else
361 argtypes[0] = PA_INT;
362
363 return 1;
364 }
365
366 static uintmax_t
367 b_value(const struct printf_info *info, const void *arg)
368 {
369 if (info->is_long_double)
370 return *(const unsigned long long *)arg;
371 if (info->is_long)
372 return *(const unsigned long *)arg;
373
374 /* short and char are both promoted to int */
375 return *(const unsigned int *)arg;
376 }
377
378 static size_t
379 b_bin_repr(char bin[UINTMAX_WIDTH],
380 const struct printf_info *info, const void *arg)
381 {
382 size_t min_len;
383 uintmax_t val;
384
385 val = b_value(info, arg);
386
387 bin[0] = '0';
388 for (min_len = 0; val; min_len++) {
389 bin[min_len] = '0' + (val % 2);
390 val >>= 1;
391 }
392
393 return MAX(min_len, 1);
394 }
395
396 static size_t
397 b_bin_len(const struct printf_info *info, ptrdiff_t min_len)
398 {
399 return MAX(info->prec, min_len);
400 }
401
402 static size_t
403 b_pad_len(const struct printf_info *info, ptrdiff_t bin_len)
404 {
405 ptrdiff_t pad_len;
406
407 pad_len = info->width - bin_len;
408 if (info->alt)
409 pad_len -= 2;
410 if (info->group)
411 pad_len -= (bin_len - 1) / 4;
412
413 return MAX(pad_len, 0);
414 }
415
416 static ssize_t
417 b_print_prefix(FILE *stream, const struct printf_info *info)
418 {
419 ssize_t len;
420
421 len = 0;
422 if (fputc('0', stream) == EOF)
423 return EOF;
424 len++;
425 if (fputc(info->spec, stream) == EOF)
426 return EOF;
427 len++;
428
429 return len;
430 }
431
432 static ssize_t
433 b_pad_zeros(FILE *stream, const struct printf_info *info,
434 ptrdiff_t min_len)
435 {
436 ssize_t len;
437 ptrdiff_t tmp;
438
439 len = 0;
440 tmp = info->width - (info->alt * 2);
441 if (info->group)
442 tmp -= tmp / 5 - !(tmp % 5);
443 for (ptrdiff_t i = tmp - 1; i > min_len - 1; i--) {
444 if (fputc('0', stream) == EOF)
445 return EOF;
446 len++;
447
448 if (!info->group || (i % 4))
449 continue;
450 if (fputc(GROUP_SEP, stream) == EOF)
451 return EOF;
452 len++;
453 }
454
455 return len;
456 }
457
458 static ssize_t
459 b_print_number(FILE *stream, const struct printf_info *info,
460 const char bin[UINTMAX_WIDTH],
461 size_t min_len, size_t bin_len)
462 {
463 ssize_t len;
464
465 len = 0;
466
467 /* Print leading zeros to fill precision */
468 for (size_t i = bin_len - 1; i > min_len - 1; i--) {
469 if (fputc('0', stream) == EOF)
470 return EOF;
471 len++;
472
473 if (!info->group || (i % 4))
474 continue;
475 if (fputc(GROUP_SEP, stream) == EOF)
476 return EOF;
477 len++;
478 }
479
480 /* Print number */
481 for (size_t i = min_len - 1; i < min_len; i--) {
482 if (fputc(bin[i], stream) == EOF)
483 return EOF;
484 len++;
485
486 if (!info->group || (i % 4) || !i)
487 continue;
488 if (fputc(GROUP_SEP, stream) == EOF)
489 return EOF;
490 len++;
491 }
492
493 return len;
494 }
495
496 static char
497 pad_ch(const struct printf_info *info)
498 {
499 if ((info->prec != -1) || (info->pad == ' ') || info->left)
500 return ' ';
501 return '0';
502 }
503
504 static ssize_t
505 pad_spaces(FILE *stream, size_t pad_len)
506 {
507 ssize_t len;
508
509 len = 0;
510 for (size_t i = pad_len - 1; i < pad_len; i--) {
511 if (fputc(' ', stream) == EOF)
512 return EOF;
513 len++;
514 }
515
516 return len;
517 }
518
520 asprintf(3), printf(3), wprintf(3)
521
522
523
524Linux man-pages 6.04 2022-09-18 printf.h(3head)