]>
Commit | Line | Data |
---|---|---|
0ba27b03 AC |
1 | .\" Copyright (C) 2022 Alejandro Colomar <alx.manpages@gmail.com> |
2 | .\" | |
3 | .\" SPDX-License-Identifier: Linux-man-pages-copyleft | |
4 | .\" | |
5 | .TH printf.h 3head 2022-09-18 "Linux man-pages (unreleased)" | |
6 | .SH NAME | |
7 | printf.h, | |
8 | \%register_printf_specifier, | |
9 | \%register_printf_modifier, | |
10 | \%register_printf_type, | |
11 | \%printf_function, | |
12 | \%printf_arginfo_size_function, | |
13 | \%printf_va_arg_function, | |
14 | \%printf_info, | |
15 | \%PA_INT, | |
16 | \%PA_CHAR, | |
17 | \%PA_WCHAR, | |
18 | \%PA_STRING, | |
19 | \%PA_WSTRING, | |
20 | \%PA_POINTER, | |
21 | \%PA_FLOAT, | |
22 | \%PA_DOUBLE, | |
23 | \%PA_LAST, | |
24 | \%PA_FLAG_LONG_LONG, | |
25 | \%PA_FLAG_LONG_DOUBLE, | |
26 | \%PA_FLAG_LONG, | |
27 | \%PA_FLAG_SHORT, | |
28 | \%PA_FLAG_PTR | |
29 | \- define custom behavior for printf-like functions | |
30 | .SH LIBRARY | |
31 | Standard C library | |
32 | .RI ( libc ", " \-lc ) | |
33 | .SH SYNOPSIS | |
34 | .nf | |
35 | .B #include <printf.h> | |
c6d039a3 | 36 | .P |
0ba27b03 AC |
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 ); | |
41 | .fi | |
42 | .SS Callbacks | |
43 | .nf | |
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 ); | |
49 | .fi | |
50 | .SS Types | |
51 | .EX | |
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" | |
73 | .B }; | |
74 | .EE | |
75 | .SS Constants | |
76 | .EX | |
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 " "/* ... */" | |
82 | .EE | |
83 | .SH DESCRIPTION | |
84 | These functions serve to extend and/or modify the behavior of the | |
85 | .BR printf (3) | |
86 | family of functions. | |
87 | .SS register_printf_specifier() | |
88 | This function registers a custom conversion specifier for the | |
89 | .BR printf (3) | |
90 | family of functions. | |
91 | .TP | |
92 | .I spec | |
93 | The character which will be used as a conversion specifier in the format string. | |
94 | .TP | |
95 | .I func | |
96 | Callback function that will be executed by the | |
97 | .BR printf (3) | |
98 | family of functions | |
99 | to format the input arguments into the output | |
100 | .IR stream . | |
101 | .RS | |
102 | .TP | |
103 | .I stream | |
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. | |
107 | .TP | |
108 | .I info | |
109 | Structure that holds context information, | |
110 | including the modifiers specified in the format string. | |
111 | This holds the same contents as in | |
112 | .IR arginfo . | |
113 | .TP | |
114 | .I args | |
115 | Array of pointers to the arguments to the | |
116 | .BR printf (3)\c | |
117 | -like function. | |
118 | .RE | |
119 | .TP | |
120 | .I arginfo | |
121 | Callback function that will be executed by the | |
122 | .BR printf (3) | |
123 | family of functions | |
124 | to know how many arguments should be parsed for the custom specifier | |
125 | and also their types. | |
126 | .RS | |
127 | .TP | |
128 | .I info | |
129 | Structure that holds context information, | |
130 | including the modifiers specified in the format string. | |
131 | This holds the same contents as in | |
132 | .IR func . | |
133 | .TP | |
134 | .I n | |
135 | Number of arguments remaining to be parsed. | |
136 | .TP | |
137 | .I argtypes | |
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 | |
142 | .BR printf (3)\c | |
143 | -like function. | |
144 | Each element should be set to a base type | |
145 | .RB ( PA_ *) | |
146 | from the enum above, | |
147 | or a custom one, | |
148 | and optionally ORed with an appropriate length modifier | |
149 | .RB ( PA_FLAG_ *). | |
150 | .RS | |
c6d039a3 | 151 | .P |
0ba27b03 AC |
152 | The type is determined by using one of the following constants: |
153 | .TP | |
154 | .B PA_INT | |
155 | .IR int . | |
156 | .TP | |
157 | .B PA_CHAR | |
158 | .IR int , | |
159 | cast to | |
160 | .IR char . | |
161 | .TP | |
7c6483b5 AC |
162 | .B PA_WCHAR |
163 | .IR wchar_t . | |
0ba27b03 AC |
164 | .TP |
165 | .B PA_STRING | |
7c6483b5 | 166 | .IR "const char\~*" , |
0ba27b03 AC |
167 | a \(aq\e0\(aq-terminated string. |
168 | .TP | |
169 | .B PA_WSTRING | |
7c6483b5 | 170 | .IR "const wchar_t\~*" , |
0ba27b03 AC |
171 | a wide character L\(aq\e0\(aq-terminated string. |
172 | .TP | |
173 | .B PA_POINTER | |
174 | .IR void\~* . | |
175 | .TP | |
176 | .B PA_FLOAT | |
177 | .IR float . | |
178 | .TP | |
179 | .B PA_DOUBLE | |
180 | .IR double . | |
181 | .TP | |
182 | .B PA_LAST | |
183 | TODO. | |
184 | .RE | |
185 | .TP | |
186 | .I size | |
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. | |
190 | .RE | |
c6d039a3 | 191 | .P |
0ba27b03 AC |
192 | .I arginfo |
193 | is called before | |
194 | .IR func , | |
195 | and prepares some information needed to call | |
196 | .IR func . | |
197 | .SS register_printf_modifier() | |
198 | TODO | |
199 | .SS register_printf_type() | |
200 | TODO | |
201 | .SH RETURN VALUE | |
202 | .BR \%register_printf_specifier (), | |
203 | .BR \%register_printf_modifier (), | |
204 | and | |
205 | .BR \%register_printf_type () | |
206 | return zero on success, or \-1 on error. | |
207 | .SS Callbacks | |
208 | The callback of type | |
209 | .I printf_function | |
210 | should return the number of characters written, | |
211 | or \-1 on error. | |
c6d039a3 | 212 | .P |
0ba27b03 AC |
213 | The callback of type |
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 | |
218 | .IR argtypes . | |
219 | On error, it should return \-1. | |
220 | .SH ERRORS | |
221 | .TP | |
222 | .B EINVAL | |
223 | The specifier was not a valid character. | |
4131356c AC |
224 | .SH STANDARDS |
225 | GNU. | |
226 | .SH HISTORY | |
0ba27b03 AC |
227 | .BR \%register_printf_function (3) |
228 | is an older function similar to | |
629aeb16 | 229 | .BR \%register_printf_specifier (), |
0ba27b03 AC |
230 | and is now deprecated. |
231 | That function can't handle user-defined types. | |
c6d039a3 | 232 | .P |
0ba27b03 AC |
233 | .BR \%register_printf_specifier () |
234 | superseeds | |
235 | .BR \%register_printf_function (3). | |
0ba27b03 AC |
236 | .SH EXAMPLES |
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. | |
c6d039a3 | 241 | .P |
0ba27b03 AC |
242 | .\" SRC BEGIN (register_printf_specifier.c) |
243 | .EX | |
244 | /* This code is in the public domain */ | |
fe5dba13 | 245 | \& |
0ba27b03 AC |
246 | #include <err.h> |
247 | #include <limits.h> | |
248 | #include <stddef.h> | |
249 | #include <stdint.h> | |
250 | #include <stdio.h> | |
251 | #include <stdlib.h> | |
252 | #include <string.h> | |
253 | #include <sys/param.h> | |
fe5dba13 | 254 | \& |
0ba27b03 | 255 | #include <printf.h> |
fe5dba13 | 256 | \& |
0ba27b03 | 257 | #define GROUP_SEP \[aq]\e\[aq]\[aq] |
fe5dba13 | 258 | \& |
0ba27b03 AC |
259 | struct Printf_Pad { |
260 | char ch; | |
261 | size_t len; | |
262 | }; | |
fe5dba13 | 263 | \& |
0ba27b03 AC |
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]); | |
fe5dba13 | 268 | \& |
0ba27b03 AC |
269 | static uintmax_t b_value(const struct printf_info *info, |
270 | const void *arg); | |
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, | |
274 | ptrdiff_t min_len); | |
275 | static size_t b_pad_len(const struct printf_info *info, | |
276 | ptrdiff_t bin_len); | |
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, | |
280 | ptrdiff_t min_len); | |
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); | |
fe5dba13 | 287 | \& |
0ba27b03 AC |
288 | int |
289 | main(void) | |
290 | { | |
88163675 | 291 | if (register_printf_specifier(\[aq]b\[aq], b_printf, b_arginf_sz) == \-1) |
0ba27b03 | 292 | err(EXIT_FAILURE, "register_printf_specifier(\[aq]b\[aq], ...)"); |
88163675 | 293 | if (register_printf_specifier(\[aq]B\[aq], b_printf, b_arginf_sz) == \-1) |
0ba27b03 | 294 | err(EXIT_FAILURE, "register_printf_specifier(\[aq]B\[aq], ...)"); |
fe5dba13 | 295 | \& |
0ba27b03 AC |
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"); | |
fe5dba13 | 345 | \& |
0ba27b03 AC |
346 | return 0; |
347 | } | |
fe5dba13 | 348 | \& |
0ba27b03 AC |
349 | static int |
350 | b_printf(FILE *stream, const struct printf_info *info, | |
351 | const void *const args[]) | |
352 | { | |
353 | char bin[UINTMAX_WIDTH]; | |
354 | size_t min_len, bin_len; | |
355 | ssize_t len, tmp; | |
356 | struct Printf_Pad pad = {0}; | |
fe5dba13 | 357 | \& |
0ba27b03 | 358 | len = 0; |
fe5dba13 | 359 | \& |
0ba27b03 AC |
360 | min_len = b_bin_repr(bin, info, args[0]); |
361 | bin_len = b_bin_len(info, min_len); | |
fe5dba13 | 362 | \& |
0ba27b03 AC |
363 | pad.ch = pad_ch(info); |
364 | if (pad.ch == \[aq] \[aq]) | |
365 | pad.len = b_pad_len(info, bin_len); | |
fe5dba13 | 366 | \& |
0ba27b03 AC |
367 | /* Padding with \[aq] \[aq] (right aligned) */ |
368 | if ((pad.ch == \[aq] \[aq]) && !info->left) { | |
369 | tmp = pad_spaces(stream, pad.len); | |
370 | if (tmp == EOF) | |
371 | return EOF; | |
372 | len += tmp; | |
373 | } | |
fe5dba13 | 374 | \& |
0ba27b03 AC |
375 | /* "0b"/"0B" prefix */ |
376 | if (info->alt) { | |
377 | tmp = b_print_prefix(stream, info); | |
378 | if (tmp == EOF) | |
379 | return EOF; | |
380 | len += tmp; | |
381 | } | |
fe5dba13 | 382 | \& |
0ba27b03 AC |
383 | /* Padding with \[aq]0\[aq] */ |
384 | if (pad.ch == \[aq]0\[aq]) { | |
385 | tmp = b_pad_zeros(stream, info, min_len); | |
386 | if (tmp == EOF) | |
387 | return EOF; | |
388 | len += tmp; | |
389 | } | |
fe5dba13 | 390 | \& |
0ba27b03 AC |
391 | /* Print number (including leading 0s to fill precision) */ |
392 | tmp = b_print_number(stream, info, bin, min_len, bin_len); | |
393 | if (tmp == EOF) | |
394 | return EOF; | |
395 | len += tmp; | |
fe5dba13 | 396 | \& |
0ba27b03 AC |
397 | /* Padding with \[aq] \[aq] (left aligned) */ |
398 | if (info\->left) { | |
399 | tmp = pad_spaces(stream, pad.len); | |
400 | if (tmp == EOF) | |
401 | return EOF; | |
402 | len += tmp; | |
403 | } | |
fe5dba13 | 404 | \& |
0ba27b03 AC |
405 | return len; |
406 | } | |
fe5dba13 | 407 | \& |
0ba27b03 AC |
408 | static int |
409 | b_arginf_sz(const struct printf_info *info, size_t n, int argtypes[n], | |
410 | [[maybe_unused]] int size[n]) | |
411 | { | |
412 | if (n < 1) | |
88163675 | 413 | return \-1; |
fe5dba13 | 414 | \& |
0ba27b03 AC |
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; | |
419 | else | |
420 | argtypes[0] = PA_INT; | |
fe5dba13 | 421 | \& |
0ba27b03 AC |
422 | return 1; |
423 | } | |
fe5dba13 | 424 | \& |
0ba27b03 AC |
425 | static uintmax_t |
426 | b_value(const struct printf_info *info, const void *arg) | |
427 | { | |
428 | if (info\->is_long_double) | |
429 | return *(const unsigned long long *)arg; | |
430 | if (info\->is_long) | |
431 | return *(const unsigned long *)arg; | |
fe5dba13 | 432 | \& |
0ba27b03 AC |
433 | /* short and char are both promoted to int */ |
434 | return *(const unsigned int *)arg; | |
435 | } | |
fe5dba13 | 436 | \& |
0ba27b03 AC |
437 | static size_t |
438 | b_bin_repr(char bin[UINTMAX_WIDTH], | |
439 | const struct printf_info *info, const void *arg) | |
440 | { | |
441 | size_t min_len; | |
442 | uintmax_t val; | |
fe5dba13 | 443 | \& |
0ba27b03 | 444 | val = b_value(info, arg); |
fe5dba13 | 445 | \& |
0ba27b03 AC |
446 | bin[0] = \[aq]0\[aq]; |
447 | for (min_len = 0; val; min_len++) { | |
448 | bin[min_len] = \[aq]0\[aq] + (val % 2); | |
449 | val >>= 1; | |
450 | } | |
fe5dba13 | 451 | \& |
0ba27b03 AC |
452 | return MAX(min_len, 1); |
453 | } | |
fe5dba13 | 454 | \& |
0ba27b03 AC |
455 | static size_t |
456 | b_bin_len(const struct printf_info *info, ptrdiff_t min_len) | |
457 | { | |
458 | return MAX(info\->prec, min_len); | |
459 | } | |
fe5dba13 | 460 | \& |
0ba27b03 AC |
461 | static size_t |
462 | b_pad_len(const struct printf_info *info, ptrdiff_t bin_len) | |
463 | { | |
464 | ptrdiff_t pad_len; | |
fe5dba13 | 465 | \& |
0ba27b03 AC |
466 | pad_len = info\->width \- bin_len; |
467 | if (info\->alt) | |
468 | pad_len \-= 2; | |
469 | if (info\->group) | |
470 | pad_len \-= (bin_len \- 1) / 4; | |
fe5dba13 | 471 | \& |
0ba27b03 AC |
472 | return MAX(pad_len, 0); |
473 | } | |
fe5dba13 | 474 | \& |
0ba27b03 AC |
475 | static ssize_t |
476 | b_print_prefix(FILE *stream, const struct printf_info *info) | |
477 | { | |
478 | ssize_t len; | |
fe5dba13 | 479 | \& |
0ba27b03 AC |
480 | len = 0; |
481 | if (fputc(\[aq]0\[aq], stream) == EOF) | |
482 | return EOF; | |
483 | len++; | |
484 | if (fputc(info\->spec, stream) == EOF) | |
485 | return EOF; | |
486 | len++; | |
fe5dba13 | 487 | \& |
0ba27b03 AC |
488 | return len; |
489 | } | |
fe5dba13 | 490 | \& |
0ba27b03 AC |
491 | static ssize_t |
492 | b_pad_zeros(FILE *stream, const struct printf_info *info, | |
493 | ptrdiff_t min_len) | |
494 | { | |
495 | ssize_t len; | |
496 | ptrdiff_t tmp; | |
fe5dba13 | 497 | \& |
0ba27b03 AC |
498 | len = 0; |
499 | tmp = info\->width \- (info\->alt * 2); | |
500 | if (info\->group) | |
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) | |
504 | return EOF; | |
505 | len++; | |
fe5dba13 | 506 | \& |
0ba27b03 AC |
507 | if (!info\->group || (i % 4)) |
508 | continue; | |
509 | if (fputc(GROUP_SEP, stream) == EOF) | |
510 | return EOF; | |
511 | len++; | |
512 | } | |
fe5dba13 | 513 | \& |
0ba27b03 AC |
514 | return len; |
515 | } | |
fe5dba13 | 516 | \& |
0ba27b03 AC |
517 | static ssize_t |
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) | |
521 | { | |
522 | ssize_t len; | |
fe5dba13 | 523 | \& |
0ba27b03 | 524 | len = 0; |
fe5dba13 | 525 | \& |
0ba27b03 AC |
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) | |
529 | return EOF; | |
530 | len++; | |
fe5dba13 | 531 | \& |
0ba27b03 AC |
532 | if (!info\->group || (i % 4)) |
533 | continue; | |
534 | if (fputc(GROUP_SEP, stream) == EOF) | |
535 | return EOF; | |
536 | len++; | |
537 | } | |
fe5dba13 | 538 | \& |
0ba27b03 AC |
539 | /* Print number */ |
540 | for (size_t i = min_len \- 1; i < min_len; i\-\-) { | |
541 | if (fputc(bin[i], stream) == EOF) | |
542 | return EOF; | |
543 | len++; | |
fe5dba13 | 544 | \& |
0ba27b03 AC |
545 | if (!info\->group || (i % 4) || !i) |
546 | continue; | |
547 | if (fputc(GROUP_SEP, stream) == EOF) | |
548 | return EOF; | |
549 | len++; | |
550 | } | |
fe5dba13 | 551 | \& |
0ba27b03 AC |
552 | return len; |
553 | } | |
fe5dba13 | 554 | \& |
0ba27b03 AC |
555 | static char |
556 | pad_ch(const struct printf_info *info) | |
557 | { | |
558 | if ((info\->prec != \-1) || (info\->pad == \[aq] \[aq]) || info\->left) | |
559 | return \[aq] \[aq]; | |
560 | return \[aq]0\[aq]; | |
561 | } | |
fe5dba13 | 562 | \& |
0ba27b03 AC |
563 | static ssize_t |
564 | pad_spaces(FILE *stream, size_t pad_len) | |
565 | { | |
566 | ssize_t len; | |
fe5dba13 | 567 | \& |
0ba27b03 AC |
568 | len = 0; |
569 | for (size_t i = pad_len - 1; i < pad_len; i\-\-) { | |
570 | if (fputc(\[aq] \[aq], stream) == EOF) | |
571 | return EOF; | |
572 | len++; | |
573 | } | |
fe5dba13 | 574 | \& |
0ba27b03 AC |
575 | return len; |
576 | } | |
577 | .EE | |
578 | .\" SRC END | |
579 | .SH SEE ALSO | |
580 | .BR asprintf (3), | |
581 | .BR printf (3), | |
582 | .BR wprintf (3) |