1printf.h(3head)                                                printf.h(3head)
2
3
4

NAME

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

LIBRARY

14       Standard C library (libc, -lc)
15

SYNOPSIS

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

DESCRIPTION

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

RETURN VALUE

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

ERRORS

167       EINVAL The specifier was not a valid character.
168

STANDARDS

170       GNU.
171

HISTORY

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

EXAMPLES

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

SEE ALSO

520       asprintf(3), printf(3), wprintf(3)
521
522
523
524Linux man-pages 6.05              2022-09-18                   printf.h(3head)
Impressum