Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 1997-2010, 2012-2015 Wind River Systems, Inc.
3 : : * Copyright (c) 2020 Nordic Semiconductor ASA
4 : : *
5 : : * SPDX-License-Identifier: Apache-2.0
6 : : */
7 : :
8 : : #include <ctype.h>
9 : : #include <errno.h>
10 : : #include <inttypes.h>
11 : : #include <limits.h>
12 : : #include <stdarg.h>
13 : : #include <stdbool.h>
14 : : #include <stddef.h>
15 : : #include <stdint.h>
16 : : #include <string.h>
17 : : #include <toolchain.h>
18 : : #include <sys/types.h>
19 : : #include <sys/util.h>
20 : : #include <sys/cbprintf.h>
21 : :
22 : : /* newlib doesn't declare this function unless __POSIX_VISIBLE >= 200809. No
23 : : * idea how to make that happen, so lets put it right here.
24 : : */
25 : : size_t strnlen(const char *s, size_t maxlen);
26 : :
27 : : /* Provide typedefs used for signed and unsigned integral types
28 : : * capable of holding all convertible integral values.
29 : : */
30 : : #ifdef CONFIG_CBPRINTF_FULL_INTEGRAL
31 : : typedef intmax_t sint_value_type;
32 : : typedef uintmax_t uint_value_type;
33 : : #else
34 : : typedef int32_t sint_value_type;
35 : : typedef uint32_t uint_value_type;
36 : : #endif
37 : :
38 : : /* The maximum buffer size required is for octal formatting: one character for
39 : : * every 3 bits. Neither EOS nor alternate forms are required.
40 : : */
41 : : #define CONVERTED_INT_BUFLEN ((CHAR_BIT * sizeof(uint_value_type) + 2) / 3)
42 : :
43 : : /* The float code may extract up to 16 digits, plus a prefix, a
44 : : * leading 0, a dot, and an exponent in the form e+xxx for a total of
45 : : * 24. Add a trailing NULL so the buffer length required is 25.
46 : : */
47 : : #define CONVERTED_FP_BUFLEN 25U
48 : :
49 : : #ifdef CONFIG_CBPRINTF_FP_SUPPORT
50 : : #define CONVERTED_BUFLEN MAX(CONVERTED_INT_BUFLEN, CONVERTED_FP_BUFLEN)
51 : : #else
52 : : #define CONVERTED_BUFLEN CONVERTED_INT_BUFLEN
53 : : #endif
54 : :
55 : : /* The allowed types of length modifier. */
56 : : enum length_mod_enum {
57 : : LENGTH_NONE, /* int */
58 : : LENGTH_HH, /* char */
59 : : LENGTH_H, /* short */
60 : : LENGTH_L, /* long */
61 : : LENGTH_LL, /* long long */
62 : : LENGTH_J, /* intmax */
63 : : LENGTH_Z, /* size_t */
64 : : LENGTH_T, /* ptrdiff_t */
65 : : LENGTH_UPPER_L, /* long double */
66 : : };
67 : :
68 : : /* Categories of conversion specifiers. */
69 : : enum specifier_cat_enum {
70 : : /* unrecognized */
71 : : SPECIFIER_INVALID,
72 : : /* d, i */
73 : : SPECIFIER_SINT,
74 : : /* c, o, u, x, X */
75 : : SPECIFIER_UINT,
76 : : /* n, p, s */
77 : : SPECIFIER_PTR,
78 : : /* a, A, e, E, f, F, g, G */
79 : : SPECIFIER_FP,
80 : : };
81 : :
82 : : #define CHAR_IS_SIGNED (CHAR_MIN != 0)
83 : : #if CHAR_IS_SIGNED
84 : : #define CASE_SINT_CHAR case 'c':
85 : : #define CASE_UINT_CHAR
86 : : #else
87 : : #define CASE_SINT_CHAR
88 : : #define CASE_UINT_CHAR case 'c':
89 : : #endif
90 : :
91 : : /* We need two pieces of information about wchar_t:
92 : : * * WCHAR_IS_SIGNED: whether it's signed or unsigned;
93 : : * * WINT_TYPE: the type to use when extracting it from va_args
94 : : *
95 : : * The former can be determined from the value of WCHAR_MIN if it's defined.
96 : : * It's not for minimal libc, so treat it as whatever char is.
97 : : *
98 : : * The latter should be wint_t, but minimal libc doesn't provide it. We can
99 : : * substitute wchar_t as long as that type does not undergo default integral
100 : : * promotion as an argument. But it does for at least one toolchain (xtensa),
101 : : * and where it does we need to use the promoted type in va_arg() to avoid
102 : : * build errors, otherwise we can use the base type. We can tell that
103 : : * integral promotion occurs if WCHAR_MAX is strictly less than INT_MAX.
104 : : */
105 : : #ifndef WCHAR_MIN
106 : : #define WCHAR_IS_SIGNED CHAR_IS_SIGNED
107 : : #if WCHAR_IS_SIGNED
108 : : #define WINT_TYPE int
109 : : #else /* wchar signed */
110 : : #define WINT_TYPE unsigned int
111 : : #endif /* wchar signed */
112 : : #else /* WCHAR_MIN defined */
113 : : #define WCHAR_IS_SIGNED ((WCHAR_MIN - 0) != 0)
114 : : #if WCHAR_MAX < INT_MAX
115 : : /* Signed or unsigned, it'll be int */
116 : : #define WINT_TYPE int
117 : : #else /* wchar rank vs int */
118 : : #define WINT_TYPE wchar_t
119 : : #endif /* wchar rank vs int */
120 : : #endif /* WCHAR_MIN defined */
121 : :
122 : : /* Case label to identify conversions for signed integral values. The
123 : : * corresponding argument_value tag is sint and category is
124 : : * SPECIFIER_SINT.
125 : : */
126 : : #define SINT_CONV_CASES \
127 : : 'd': \
128 : : CASE_SINT_CHAR \
129 : : case 'i'
130 : :
131 : : /* Case label to identify conversions for signed integral arguments.
132 : : * The corresponding argument_value tag is uint and category is
133 : : * SPECIFIER_UINT.
134 : : */
135 : : #define UINT_CONV_CASES \
136 : : 'o': \
137 : : CASE_UINT_CHAR \
138 : : case 'u': \
139 : : case 'x': \
140 : : case 'X'
141 : :
142 : : /* Case label to identify conversions for floating point arguments.
143 : : * The corresponding argument_value tag is either dbl or ldbl,
144 : : * depending on length modifier, and the category is SPECIFIER_FP.
145 : : */
146 : : #define FP_CONV_CASES \
147 : : 'a': \
148 : : case 'A': \
149 : : case 'e': \
150 : : case 'E': \
151 : : case 'f': \
152 : : case 'F': \
153 : : case 'g': \
154 : : case 'G'
155 : :
156 : : /* Case label to identify conversions for pointer arguments. The
157 : : * corresponding argument_value tag is ptr and the category is
158 : : * SPECIFIER_PTR.
159 : : */
160 : : #define PTR_CONV_CASES \
161 : : 'n': \
162 : : case 'p': \
163 : : case 's'
164 : :
165 : : /* Storage for an argument value. */
166 : : union argument_value {
167 : : /* For SINT conversions */
168 : : sint_value_type sint;
169 : :
170 : : /* For UINT conversions */
171 : : uint_value_type uint;
172 : :
173 : : /* For FP conversions without L length */
174 : : double dbl;
175 : :
176 : : /* For FP conversions with L length */
177 : : long double ldbl;
178 : :
179 : : /* For PTR conversions */
180 : : void *ptr;
181 : : };
182 : :
183 : : /* Structure capturing all attributes of a conversion
184 : : * specification.
185 : : *
186 : : * Initial values come from the specification, but are updated during
187 : : * the conversion.
188 : : */
189 : : struct conversion {
190 : : /** Indicates flags are inconsistent */
191 : : bool invalid: 1;
192 : :
193 : : /** Indicates flags are valid but not supported */
194 : : bool unsupported: 1;
195 : :
196 : : /** Left-justify value in width */
197 : : bool flag_dash: 1;
198 : :
199 : : /** Explicit sign */
200 : : bool flag_plus: 1;
201 : :
202 : : /** Space for non-negative sign */
203 : : bool flag_space: 1;
204 : :
205 : : /** Alternative form */
206 : : bool flag_hash: 1;
207 : :
208 : : /** Pad with leading zeroes */
209 : : bool flag_zero: 1;
210 : :
211 : : /** Width field present */
212 : : bool width_present: 1;
213 : :
214 : : /** Width value from int argument
215 : : *
216 : : * width_value is set to the absolute value of the argument.
217 : : * If the argument is negative flag_dash is also set.
218 : : */
219 : : bool width_star: 1;
220 : :
221 : : /** Precision field present */
222 : : bool prec_present: 1;
223 : :
224 : : /** Precision from int argument
225 : : *
226 : : * prec_value is set to the value of a non-negative argument.
227 : : * If the argument is negative prec_present is cleared.
228 : : */
229 : : bool prec_star: 1;
230 : :
231 : : /** Length modifier (value from length_mod_enum) */
232 : : unsigned int length_mod: 4;
233 : :
234 : : /** Indicates an a or A conversion specifier.
235 : : *
236 : : * This affects how precision is handled.
237 : : */
238 : : bool specifier_a: 1;
239 : :
240 : : /** Conversion specifier category (value from specifier_cat_enum) */
241 : : unsigned int specifier_cat: 3;
242 : :
243 : : /** If set alternate form requires 0 before octal. */
244 : : bool altform_0: 1;
245 : :
246 : : /** If set alternate form requires 0x before hex. */
247 : : bool altform_0c: 1;
248 : :
249 : : /** Set when pad0_value zeroes are to be to be inserted after
250 : : * the decimal point in a floating point conversion.
251 : : */
252 : : bool pad_postdp: 1;
253 : :
254 : : /** Set for floating point values that have a non-zero
255 : : * pad0_prefix or pad0_pre_exp.
256 : : */
257 : : bool pad_fp: 1;
258 : :
259 : : /** Conversion specifier character */
260 : : unsigned char specifier;
261 : :
262 : : union {
263 : : /** Width value from specification.
264 : : *
265 : : * Valid until conversion begins.
266 : : */
267 : : int width_value;
268 : :
269 : : /** Number of extra zeroes to be inserted around a
270 : : * formatted value:
271 : : *
272 : : * * before a formatted integer value due to precision
273 : : * and flag_zero; or
274 : : * * before a floating point mantissa decimal point
275 : : * due to precision; or
276 : : * * after a floating point mantissa decimal point due
277 : : * to precision.
278 : : *
279 : : * For example for zero-padded hexadecimal integers
280 : : * this would insert where the angle brackets are in:
281 : : * 0x<>hhhh.
282 : : *
283 : : * For floating point numbers this would insert at
284 : : * either <1> or <2> depending on #pad_postdp:
285 : : * VVV<1>.<2>FFFFeEEE
286 : : *
287 : : * Valid after conversion begins.
288 : : */
289 : : int pad0_value;
290 : : };
291 : :
292 : : union {
293 : : /** Precision from specification.
294 : : *
295 : : * Valid until conversion begins.
296 : : */
297 : : int prec_value;
298 : :
299 : : /** Number of extra zeros to be inserted after a decimal
300 : : * point due to precision.
301 : : *
302 : : * Inserts at <> in: VVVV.FFFF<>eEE
303 : : *
304 : : * Valid after conversion begins.
305 : : */
306 : : int pad0_pre_exp;
307 : : };
308 : : };
309 : :
310 : : /** Get a size represented as a sequence of decimal digits.
311 : : *
312 : : * @param[inout] str where to read from. Updated to point to the first
313 : : * unconsumed character. There must be at least one non-digit character in
314 : : * the referenced text.
315 : : *
316 : : * @return the decoded integer value.
317 : : */
318 : 133519 : static size_t extract_decimal(const char **str)
319 : : {
320 : 133519 : const char *sp = *str;
321 : 133519 : size_t val = 0;
322 : :
323 [ + + ]: 253403 : while (isdigit((int)(unsigned char)*sp)) {
324 : 119884 : val = 10U * val + *sp++ - '0';
325 : : }
326 : 133519 : *str = sp;
327 : 133519 : return val;
328 : : }
329 : :
330 : : /** Extract C99 conversion specification flags.
331 : : *
332 : : * @param conv pointer to the conversion being defined.
333 : : *
334 : : * @param sp pointer to the first character after the % of a conversion
335 : : * specifier.
336 : : *
337 : : * @return a pointer the first character that follows the flags.
338 : : */
339 : 133519 : static inline const char *extract_flags(struct conversion *conv,
340 : : const char *sp)
341 : : {
342 : 133519 : bool loop = true;
343 : :
344 : : do {
345 [ - - - - : 253403 : switch (*sp) {
+ + ]
346 : 0 : case '-':
347 : 0 : conv->flag_dash = true;
348 : 0 : break;
349 : 0 : case '+':
350 : 0 : conv->flag_plus = true;
351 : 0 : break;
352 : 0 : case ' ':
353 : 0 : conv->flag_space = true;
354 : 0 : break;
355 : 0 : case '#':
356 : 0 : conv->flag_hash = true;
357 : 0 : break;
358 : 119884 : case '0':
359 : 119884 : conv->flag_zero = true;
360 : 119884 : break;
361 : 133519 : default:
362 : 133519 : loop = false;
363 : : }
364 [ + + ]: 253403 : if (loop) {
365 : 119884 : ++sp;
366 : : }
367 [ + + ]: 253403 : } while (loop);
368 : :
369 : : /* zero && dash => !zero */
370 [ + + - + ]: 133519 : if (conv->flag_zero && conv->flag_dash) {
371 : 0 : conv->flag_zero = false;
372 : : }
373 : :
374 : : /* space && plus => !plus, handled in emitter code */
375 : :
376 : 133519 : return sp;
377 : : }
378 : :
379 : : /** Extract a C99 conversion specification width.
380 : : *
381 : : * @param conv pointer to the conversion being defined.
382 : : *
383 : : * @param sp pointer to the first character after the flags element of a
384 : : * conversion specification.
385 : : *
386 : : * @return a pointer the first character that follows the width.
387 : : */
388 : 133519 : static inline const char *extract_width(struct conversion *conv,
389 : : const char *sp)
390 : : {
391 : 133519 : conv->width_present = true;
392 : :
393 [ - + ]: 133519 : if (*sp == '*') {
394 : 0 : conv->width_star = true;
395 : 0 : return ++sp;
396 : : }
397 : :
398 : 133519 : const char *wp = sp;
399 : 133519 : size_t width = extract_decimal(&sp);
400 : :
401 [ + + ]: 133519 : if (sp != wp) {
402 : 119884 : conv->width_present = true;
403 : 119884 : conv->width_value = width;
404 : 119884 : conv->unsupported |= ((conv->width_value < 0)
405 [ + - - + ]: 119884 : || (width != (size_t)conv->width_value));
406 : : }
407 : :
408 : 133519 : return sp;
409 : : }
410 : :
411 : : /** Extract a C99 conversion specification precision.
412 : : *
413 : : * @param conv pointer to the conversion being defined.
414 : : *
415 : : * @param sp pointer to the first character after the width element of a
416 : : * conversion specification.
417 : : *
418 : : * @return a pointer the first character that follows the precision.
419 : : */
420 : 133519 : static inline const char *extract_prec(struct conversion *conv,
421 : : const char *sp)
422 : : {
423 : 133519 : conv->prec_present = (*sp == '.');
424 : :
425 [ + - ]: 133519 : if (!conv->prec_present) {
426 : 133519 : return sp;
427 : : }
428 : 0 : ++sp;
429 : :
430 [ # # ]: 0 : if (*sp == '*') {
431 : 0 : conv->prec_star = true;
432 : 0 : return ++sp;
433 : : }
434 : :
435 : 0 : size_t prec = extract_decimal(&sp);
436 : :
437 : 0 : conv->prec_value = prec;
438 : 0 : conv->unsupported |= ((conv->prec_value < 0)
439 [ # # # # ]: 0 : || (prec != (size_t)conv->prec_value));
440 : :
441 : 0 : return sp;
442 : : }
443 : :
444 : : /** Extract a C99 conversion specification length.
445 : : *
446 : : * @param conv pointer to the conversion being defined.
447 : : *
448 : : * @param sp pointer to the first character after the precision element of a
449 : : * conversion specification.
450 : : *
451 : : * @return a pointer the first character that follows the precision.
452 : : */
453 : 133519 : static inline const char *extract_length(struct conversion *conv,
454 : : const char *sp)
455 : : {
456 [ - - - - : 133519 : switch (*sp) {
- - + ]
457 : 0 : case 'h':
458 [ # # ]: 0 : if (*++sp == 'h') {
459 : 0 : conv->length_mod = LENGTH_HH;
460 : 0 : ++sp;
461 : : } else {
462 : 0 : conv->length_mod = LENGTH_H;
463 : : }
464 : 0 : break;
465 : 0 : case 'l':
466 [ # # ]: 0 : if (*++sp == 'l') {
467 : 0 : conv->length_mod = LENGTH_LL;
468 : 0 : ++sp;
469 : : } else {
470 : 0 : conv->length_mod = LENGTH_L;
471 : : }
472 : 0 : break;
473 : 0 : case 'j':
474 : 0 : conv->length_mod = LENGTH_J;
475 : 0 : ++sp;
476 : 0 : break;
477 : 0 : case 'z':
478 : 0 : conv->length_mod = LENGTH_Z;
479 : 0 : ++sp;
480 : 0 : break;
481 : 0 : case 't':
482 : 0 : conv->length_mod = LENGTH_T;
483 : 0 : ++sp;
484 : 0 : break;
485 : 0 : case 'L':
486 : 0 : conv->length_mod = LENGTH_UPPER_L;
487 : 0 : ++sp;
488 : :
489 : : /* We recognize and consume these, but can't format
490 : : * them.
491 : : */
492 : 0 : conv->unsupported = true;
493 : 0 : break;
494 : 133519 : default:
495 : 133519 : conv->length_mod = LENGTH_NONE;
496 : 133519 : break;
497 : : }
498 : 133519 : return sp;
499 : : }
500 : :
501 : : /* Extract a C99 conversion specifier.
502 : : *
503 : : * This is the character that identifies the representation of the converted
504 : : * value.
505 : : *
506 : : * @param conv pointer to the conversion being defined.
507 : : *
508 : : * @param sp pointer to the first character after the length element of a
509 : : * conversion specification.
510 : : *
511 : : * @return a pointer the first character that follows the specifier.
512 : : */
513 : 133519 : static inline const char *extract_specifier(struct conversion *conv,
514 : : const char *sp)
515 : : {
516 : 133519 : bool unsupported = false;
517 : :
518 : 133519 : conv->specifier = *sp++;
519 : :
520 [ + + - - : 133519 : switch (conv->specifier) {
+ - ]
521 : 1 : case SINT_CONV_CASES:
522 : 1 : conv->specifier_cat = SPECIFIER_SINT;
523 : 1 : goto int_conv;
524 : 133510 : case UINT_CONV_CASES:
525 : 133510 : conv->specifier_cat = SPECIFIER_UINT;
526 : 133511 : int_conv:
527 : : /* L length specifier not acceptable */
528 [ - + ]: 133511 : if (conv->length_mod == LENGTH_UPPER_L) {
529 : 0 : conv->invalid = true;
530 : : }
531 : :
532 : : /* For c LENGTH_NONE and LENGTH_L would be ok,
533 : : * but we don't support formatting wide characters.
534 : : */
535 [ + + ]: 133511 : if (conv->specifier == 'c') {
536 : 13624 : unsupported = (conv->length_mod != LENGTH_NONE);
537 : : } else if (!IS_ENABLED(CONFIG_CBPRINTF_FULL_INTEGRAL)) {
538 : : /* Disable conversion that might produce truncated
539 : : * results with buffers sized for 32 bits.
540 : : */
541 : : switch (conv->length_mod) {
542 : : case LENGTH_L:
543 : : unsupported = sizeof(long) > 4;
544 : : break;
545 : : case LENGTH_LL:
546 : : unsupported = sizeof(long long) > 4;
547 : : break;
548 : : case LENGTH_J:
549 : : unsupported = sizeof(uintmax_t) > 4;
550 : : break;
551 : : case LENGTH_Z:
552 : : unsupported = sizeof(size_t) > 4;
553 : : break;
554 : : case LENGTH_T:
555 : : unsupported = sizeof(ptrdiff_t) > 4;
556 : : break;
557 : : default:
558 : : /* Add an empty default with break, this is a defensive
559 : : * programming. Static analysis tool won't raise a violation
560 : : * if default is empty, but has that comment.
561 : : */
562 : : break;
563 : : }
564 : : } else {
565 : : ;
566 : : }
567 : 133511 : break;
568 : :
569 : 0 : case FP_CONV_CASES:
570 : 0 : conv->specifier_cat = SPECIFIER_FP;
571 : :
572 : : /* Don't support if disabled */
573 : : if (!IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
574 : 0 : unsupported = true;
575 : 0 : break;
576 : : }
577 : :
578 : : /* When FP enabled %a support is still conditional. */
579 : : conv->specifier_a = (conv->specifier == 'a')
580 : : || (conv->specifier == 'A');
581 : : if (conv->specifier_a
582 : : && !IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)) {
583 : : unsupported = true;
584 : : break;
585 : : }
586 : :
587 : : /* The l specifier has no effect. Otherwise length
588 : : * modifiers other than L are invalid.
589 : : */
590 : : if (conv->length_mod == LENGTH_L) {
591 : : conv->length_mod = LENGTH_NONE;
592 : : } else if ((conv->length_mod != LENGTH_NONE)
593 : : && (conv->length_mod != LENGTH_UPPER_L)) {
594 : : conv->invalid = true;
595 : : } else {
596 : : ;
597 : : }
598 : :
599 : : break;
600 : :
601 : : /* PTR cases are distinct */
602 : 0 : case 'n':
603 : 0 : conv->specifier_cat = SPECIFIER_PTR;
604 : : /* Anything except L */
605 [ # # ]: 0 : if (conv->length_mod == LENGTH_UPPER_L) {
606 : 0 : unsupported = true;
607 : : }
608 : 0 : break;
609 : :
610 : 8 : case 's':
611 : : case 'p':
612 : 8 : conv->specifier_cat = SPECIFIER_PTR;
613 : :
614 : : /* p: only LENGTH_NONE
615 : : *
616 : : * s: LENGTH_NONE or LENGTH_L but wide
617 : : * characters not supported.
618 : : */
619 [ - + ]: 8 : if (conv->length_mod != LENGTH_NONE) {
620 : 0 : unsupported = true;
621 : : }
622 : 8 : break;
623 : :
624 : 0 : default:
625 : 0 : conv->invalid = true;
626 : 0 : break;
627 : : }
628 : :
629 : 133519 : conv->unsupported |= unsupported;
630 : :
631 : 133519 : return sp;
632 : : }
633 : :
634 : : /* Extract the complete C99 conversion specification.
635 : : *
636 : : * @param conv pointer to the conversion being defined.
637 : : *
638 : : * @param sp pointer to the % that introduces a conversion specification.
639 : : *
640 : : * @return pointer to the first character that follows the specification.
641 : : */
642 : 133519 : static inline const char *extract_conversion(struct conversion *conv,
643 : : const char *sp)
644 : : {
645 : 133519 : *conv = (struct conversion) {
646 : : .invalid = false,
647 : : };
648 : :
649 : : /* Skip over the opening %. If the conversion specifier is %,
650 : : * that's the only thing that should be there, so
651 : : * fast-exit.
652 : : */
653 : 133519 : ++sp;
654 [ - + ]: 133519 : if (*sp == '%') {
655 : 0 : conv->specifier = *sp++;
656 : 0 : return sp;
657 : : }
658 : :
659 : 133519 : sp = extract_flags(conv, sp);
660 : 133519 : sp = extract_width(conv, sp);
661 : 133519 : sp = extract_prec(conv, sp);
662 : 133519 : sp = extract_length(conv, sp);
663 : 133519 : sp = extract_specifier(conv, sp);
664 : :
665 : 133519 : return sp;
666 : : }
667 : :
668 : : #ifdef CONFIG_64BIT
669 : :
670 : : static void _ldiv5(uint64_t *v)
671 : : {
672 : : /* The compiler can optimize this on its own on 64-bit architectures */
673 : : *v /= 5U;
674 : : }
675 : :
676 : : #else /* CONFIG_64BIT */
677 : :
678 : : /*
679 : : * Tiny integer divide-by-five routine. The full 64 bit division
680 : : * implementations in libgcc are very large on some architectures, and
681 : : * currently nothing in Zephyr pulls it into the link. So it makes
682 : : * sense to define this much smaller special case here to avoid
683 : : * including it just for printf.
684 : : *
685 : : * It works by multiplying v by the reciprocal of 5 i.e.:
686 : : *
687 : : * result = v * ((1 << 64) / 5) / (1 << 64)
688 : : *
689 : : * This produces a 128-bit result, but we drop the bottom 64 bits which
690 : : * accounts for the division by (1 << 64). The product is kept to 64 bits
691 : : * by summing partial multiplications and shifting right by 32 which on
692 : : * most 32-bit architectures means only a register drop.
693 : : *
694 : : * Here the multiplier is: (1 << 64) / 5 = 0x3333333333333333
695 : : * i.e. a 62 bits value. To compensate for the reduced precision, we
696 : : * add an initial bias of 1 to v. This conveniently allows for keeping
697 : : * the multiplier in a single 32-bit register given its pattern.
698 : : * Enlarging the multiplier to 64 bits would also work but carry handling
699 : : * on the summing of partial mults would be necessary, and a final right
700 : : * shift would be needed, requiring more instructions.
701 : : */
702 : 0 : static void _ldiv5(uint64_t *v)
703 : : {
704 : 0 : uint32_t v_lo = *v;
705 : 0 : uint32_t v_hi = *v >> 32;
706 : 0 : uint32_t m = 0x33333333;
707 : : uint64_t result;
708 : :
709 : : /*
710 : : * Force the multiplier constant into a register and make it
711 : : * opaque to the compiler, otherwise gcc tries to be too smart
712 : : * for its own good with a large expansion of adds and shifts.
713 : : */
714 : 0 : __asm__ ("" : "+r" (m));
715 : :
716 : : /*
717 : : * Apply a bias of 1 to v. We can't add it to v as this would overflow
718 : : * it when at max range. Factor it out with the multiplier upfront.
719 : : */
720 : 0 : result = ((uint64_t)m << 32) | m;
721 : :
722 : : /* The actual multiplication. */
723 : 0 : result += (uint64_t)v_lo * m;
724 : 0 : result >>= 32;
725 : 0 : result += (uint64_t)v_lo * m;
726 : 0 : result += (uint64_t)v_hi * m;
727 : 0 : result >>= 32;
728 : 0 : result += (uint64_t)v_hi * m;
729 : :
730 : 0 : *v = result;
731 : 0 : }
732 : :
733 : : #endif /* CONFIG_64BIT */
734 : :
735 : : /* Division by 10 */
736 : 0 : static void _ldiv10(uint64_t *v)
737 : : {
738 : 0 : *v >>= 1;
739 : 0 : _ldiv5(v);
740 : 0 : }
741 : :
742 : : /* Extract the next decimal character in the converted representation of a
743 : : * fractional component.
744 : : */
745 : 0 : static char _get_digit(uint64_t *fr, int *digit_count)
746 : : {
747 : : char rval;
748 : :
749 [ # # ]: 0 : if (*digit_count > 0) {
750 : 0 : --*digit_count;
751 : 0 : *fr *= 10U;
752 : 0 : rval = ((*fr >> 60) & 0xF) + '0';
753 : 0 : *fr &= (BIT64(60) - 1U);
754 : : } else {
755 : 0 : rval = '0';
756 : : }
757 : :
758 : 0 : return rval;
759 : : }
760 : :
761 : 119887 : static inline size_t conversion_radix(char specifier)
762 : : {
763 [ + - + ]: 119887 : switch (specifier) {
764 : 3 : default:
765 : : case 'd':
766 : : case 'i':
767 : : case 'u':
768 : 3 : return 10;
769 : 0 : case 'o':
770 : 0 : return 8;
771 : 119884 : case 'p':
772 : : case 'x':
773 : : case 'X':
774 : 119884 : return 16;
775 : : }
776 : : }
777 : :
778 : : /* Writes the given value into the buffer in the specified base.
779 : : *
780 : : * Precision is applied *ONLY* within the space allowed.
781 : : *
782 : : * Alternate form value is applied to o, x, and X conversions.
783 : : *
784 : : * The buffer is filled backwards, so the input bpe is the end of the
785 : : * generated representation. The returned pointer is to the first
786 : : * character of the representation.
787 : : */
788 : 119887 : static char *encode_uint(uint_value_type value,
789 : : struct conversion *conv,
790 : : char *bps,
791 : : const char *bpe)
792 : : {
793 : 119887 : bool upcase = isupper((int)conv->specifier);
794 : 119887 : const unsigned int radix = conversion_radix(conv->specifier);
795 : 119887 : char *bp = bps + (bpe - bps);
796 : :
797 : : do {
798 : 146108 : unsigned int lsv = (unsigned int)(value % radix);
799 : :
800 [ + + - + ]: 168148 : *--bp = (lsv <= 9) ? ('0' + lsv)
801 : 22040 : : upcase ? ('A' + lsv - 10) : ('a' + lsv - 10);
802 : 146108 : value /= radix;
803 [ + + + - ]: 146108 : } while ((value != 0) && (bps < bp));
804 : :
805 : : /* Record required alternate forms. This can be determined
806 : : * from the radix without re-checking specifier.
807 : : */
808 [ - + ]: 119887 : if (conv->flag_hash) {
809 [ # # ]: 0 : if (radix == 8) {
810 : 0 : conv->altform_0 = true;
811 [ # # ]: 0 : } else if (radix == 16) {
812 : 0 : conv->altform_0c = true;
813 : : } else {
814 : : ;
815 : : }
816 : : }
817 : :
818 : 119887 : return bp;
819 : : }
820 : :
821 : : /* Number of bits in the fractional part of an IEEE 754-2008 double
822 : : * precision float.
823 : : */
824 : : #define FRACTION_BITS 52
825 : :
826 : : /* Number of hex "digits" in the fractional part of an IEEE 754-2008
827 : : * double precision float.
828 : : */
829 : : #define FRACTION_HEX ceiling_fraction(FRACTION_BITS, 4)
830 : :
831 : : /* Number of bits in the exponent of an IEEE 754-2008 double precision
832 : : * float.
833 : : */
834 : : #define EXPONENT_BITS 11
835 : :
836 : : /* Mask for the sign (negative) bit of an IEEE 754-2008 double precision
837 : : * float.
838 : : */
839 : : #define SIGN_MASK BIT64(63)
840 : :
841 : : /* Mask for the high-bit of a uint64_t representation of a fractional
842 : : * value.
843 : : */
844 : : #define BIT_63 BIT64(63)
845 : :
846 : : /* Convert the IEEE 754-2008 double to text format.
847 : : *
848 : : * @param value the 64-bit floating point value.
849 : : *
850 : : * @param conv details about how the conversion is to proceed. Some fields
851 : : * are adjusted based on the value being converted.
852 : : *
853 : : * @param precision the precision for the conversion (generally digits past
854 : : * the decimal point).
855 : : *
856 : : * @param bps pointer to the first character in a buffer that will hold the
857 : : * converted value.
858 : : *
859 : : * @param bpe On entry this points to the end of the buffer reserved to hold
860 : : * the converted value. On exit it is updated to point just past the
861 : : * converted value.
862 : : *
863 : : * return a pointer to the start of the converted value. This may not be @p
864 : : * bps but will be consistent with the exit value of *bpe.
865 : : */
866 : 0 : static char *encode_float(double value,
867 : : struct conversion *conv,
868 : : int precision,
869 : : char *sign,
870 : : char *bps,
871 : : const char **bpe)
872 : : {
873 : : union {
874 : : uint64_t u64;
875 : : double dbl;
876 : 0 : } u = {
877 : : .dbl = value,
878 : : };
879 : 0 : bool prune_zero = false;
880 : 0 : char *buf = bps;
881 : :
882 : : /* Prepend the sign: '-' if negative, flags control
883 : : * non-negative behavior.
884 : : */
885 [ # # ]: 0 : if ((u.u64 & SIGN_MASK) != 0U) {
886 : 0 : *sign = '-';
887 [ # # ]: 0 : } else if (conv->flag_plus) {
888 : 0 : *sign = '+';
889 [ # # ]: 0 : } else if (conv->flag_space) {
890 : 0 : *sign = ' ';
891 : : } else {
892 : : ;
893 : : }
894 : :
895 : : /* Extract the non-negative offset exponent and fraction. Record
896 : : * whether the value is subnormal.
897 : : */
898 : 0 : char c = conv->specifier;
899 : 0 : int expo = (u.u64 >> FRACTION_BITS) & BIT_MASK(EXPONENT_BITS);
900 : 0 : uint64_t fract = u.u64 & BIT64_MASK(FRACTION_BITS);
901 [ # # # # ]: 0 : bool is_subnormal = (expo == 0) && (fract != 0);
902 : :
903 : : /* Exponent of all-ones signals infinity or NaN, which are
904 : : * text constants regardless of specifier.
905 : : */
906 [ # # ]: 0 : if (expo == BIT_MASK(EXPONENT_BITS)) {
907 [ # # ]: 0 : if (fract == 0) {
908 [ # # ]: 0 : if (isupper((int)c)) {
909 : 0 : *buf++ = 'I';
910 : 0 : *buf++ = 'N';
911 : 0 : *buf++ = 'F';
912 : : } else {
913 : 0 : *buf++ = 'i';
914 : 0 : *buf++ = 'n';
915 : 0 : *buf++ = 'f';
916 : : }
917 : : } else {
918 [ # # ]: 0 : if (isupper((int)c)) {
919 : 0 : *buf++ = 'N';
920 : 0 : *buf++ = 'A';
921 : 0 : *buf++ = 'N';
922 : : } else {
923 : 0 : *buf++ = 'n';
924 : 0 : *buf++ = 'a';
925 : 0 : *buf++ = 'n';
926 : : }
927 : : }
928 : :
929 : : /* No zero-padding with text values */
930 : 0 : conv->flag_zero = false;
931 : :
932 : 0 : *bpe = buf;
933 : 0 : return bps;
934 : : }
935 : :
936 : : /* The case of an F specifier is no longer relevant. */
937 [ # # ]: 0 : if (c == 'F') {
938 : 0 : c = 'f';
939 : : }
940 : :
941 : : /* Handle converting to the hex representation. */
942 : : if (IS_ENABLED(CONFIG_CBPRINTF_FP_A_SUPPORT)
943 : : && (IS_ENABLED(CONFIG_CBPRINTF_FP_ALWAYS_A)
944 : : || conv->specifier_a)) {
945 : : *buf++ = '0';
946 : : *buf++ = 'x';
947 : :
948 : : /* Remove the offset from the exponent, and store the
949 : : * non-fractional value. Subnormals require increasing the
950 : : * exponent as first bit isn't the implicit bit.
951 : : */
952 : : expo -= 1023;
953 : : if (is_subnormal) {
954 : : *buf++ = '0';
955 : : ++expo;
956 : : } else {
957 : : *buf++ = '1';
958 : : }
959 : :
960 : : /* If we didn't get precision from a %a specification then we
961 : : * treat it as from a %a specification with no precision: full
962 : : * range, zero-pruning enabled.
963 : : *
964 : : * Otherwise we have to cap the precision of the generated
965 : : * fraction, or possibly round it.
966 : : */
967 : : if (!(conv->specifier_a && conv->prec_present)) {
968 : : precision = FRACTION_HEX;
969 : : prune_zero = true;
970 : : } else if (precision > FRACTION_HEX) {
971 : : conv->pad0_pre_exp = precision - FRACTION_HEX;
972 : : conv->pad_fp = true;
973 : : precision = FRACTION_HEX;
974 : : } else if ((fract != 0)
975 : : && (precision < FRACTION_HEX)) {
976 : : size_t pos = 4 * (FRACTION_HEX - precision) - 1;
977 : : uint64_t mask = BIT64(pos);
978 : :
979 : : /* Round only if the bit that would round is
980 : : * set.
981 : : */
982 : : if (fract & mask) {
983 : : fract += mask;
984 : : }
985 : : }
986 : :
987 : : /* Record whether we must retain the decimal point even if we
988 : : * can prune zeros.
989 : : */
990 : : bool require_dp = ((fract != 0) || conv->flag_hash);
991 : :
992 : : if (require_dp || (precision != 0)) {
993 : : *buf++ = '.';
994 : : }
995 : :
996 : : /* Get the fractional value as a hexadecimal string, using x
997 : : * for a and X for A.
998 : : */
999 : : struct conversion aconv = {
1000 : : .specifier = isupper((int)c) ? 'X' : 'x',
1001 : : };
1002 : : const char *spe = *bpe;
1003 : : char *sp = bps + (spe - bps);
1004 : :
1005 : : if (fract != 0) {
1006 : : sp = encode_uint(fract, &aconv, buf, spe);
1007 : : }
1008 : :
1009 : : /* Pad out to full range since this is below the decimal
1010 : : * point.
1011 : : */
1012 : : while ((spe - sp) < FRACTION_HEX) {
1013 : : *--sp = '0';
1014 : : }
1015 : :
1016 : : /* Append the leading significant "digits". */
1017 : : while ((sp < spe) && (precision > 0)) {
1018 : : *buf++ = *sp++;
1019 : : --precision;
1020 : : }
1021 : :
1022 : : if (prune_zero) {
1023 : : while (*--buf == '0') {
1024 : : ;
1025 : : }
1026 : : if ((*buf != '.') || require_dp) {
1027 : : ++buf;
1028 : : }
1029 : : }
1030 : :
1031 : : *buf++ = 'p';
1032 : : if (expo >= 0) {
1033 : : *buf++ = '+';
1034 : : } else {
1035 : : *buf++ = '-';
1036 : : expo = -expo;
1037 : : }
1038 : :
1039 : : aconv.specifier = 'i';
1040 : : sp = encode_uint(expo, &aconv, buf, spe);
1041 : :
1042 : : while (sp < spe) {
1043 : : *buf++ = *sp++;
1044 : : }
1045 : :
1046 : : *bpe = buf;
1047 : : return bps;
1048 : : }
1049 : :
1050 : : /* Remainder of code operates on a 64-bit fraction, so shift up (and
1051 : : * discard garbage from the exponent where the implicit 1 would be
1052 : : * stored).
1053 : : */
1054 : 0 : fract <<= EXPONENT_BITS;
1055 : 0 : fract &= ~SIGN_MASK;
1056 : :
1057 : : /* Non-zero values need normalization. */
1058 [ # # ]: 0 : if ((expo | fract) != 0) {
1059 [ # # ]: 0 : if (is_subnormal) {
1060 : : /* Fraction is subnormal. Normalize it and correct
1061 : : * the exponent.
1062 : : */
1063 [ # # ]: 0 : while (((fract <<= 1) & BIT_63) == 0) {
1064 : 0 : expo--;
1065 : : }
1066 : : }
1067 : : /* Adjust the offset exponent to be signed rather than offset,
1068 : : * and set the implicit 1 bit in the (shifted) 53-bit
1069 : : * fraction.
1070 : : */
1071 : 0 : expo -= (1023 - 1); /* +1 since .1 vs 1. */
1072 : 0 : fract |= BIT_63;
1073 : : }
1074 : :
1075 : : /*
1076 : : * Let's consider:
1077 : : *
1078 : : * value = fract * 2^expo * 10^decexp
1079 : : *
1080 : : * Initially decexp = 0. The goal is to bring exp between
1081 : : * 0 and -2 as the magnitude of a fractional decimal digit is 3 bits.
1082 : : */
1083 : 0 : int decexp = 0;
1084 : :
1085 [ # # ]: 0 : while (expo < -2) {
1086 : : /*
1087 : : * Make room to allow a multiplication by 5 without overflow.
1088 : : * We test only the top part for faster code.
1089 : : */
1090 : : do {
1091 : 0 : fract >>= 1;
1092 : 0 : expo++;
1093 [ # # ]: 0 : } while ((uint32_t)(fract >> 32) >= (UINT32_MAX / 5U));
1094 : :
1095 : : /* Perform fract * 5 * 2 / 10 */
1096 : 0 : fract *= 5U;
1097 : 0 : expo++;
1098 : 0 : decexp--;
1099 : : }
1100 : :
1101 [ # # ]: 0 : while (expo > 0) {
1102 : : /*
1103 : : * Perform fract / 5 / 2 * 10.
1104 : : * The +2 is there to do round the result of the division
1105 : : * by 5 not to lose too much precision in extreme cases.
1106 : : */
1107 : 0 : fract += 2;
1108 : 0 : _ldiv5(&fract);
1109 : 0 : expo--;
1110 : 0 : decexp++;
1111 : :
1112 : : /* Bring back our fractional number to full scale */
1113 : : do {
1114 : 0 : fract <<= 1;
1115 : 0 : expo--;
1116 [ # # ]: 0 : } while (!(fract & BIT_63));
1117 : : }
1118 : :
1119 : : /*
1120 : : * The binary fractional point is located somewhere above bit 63.
1121 : : * Move it between bits 59 and 60 to give 4 bits of room to the
1122 : : * integer part.
1123 : : */
1124 : 0 : fract >>= (4 - expo);
1125 : :
1126 [ # # # # ]: 0 : if ((c == 'g') || (c == 'G')) {
1127 : : /* Use the specified precision and exponent to select the
1128 : : * representation and correct the precision and zero-pruning
1129 : : * in accordance with the ISO C rule.
1130 : : */
1131 [ # # # # ]: 0 : if (decexp < (-4 + 1) || decexp > precision) {
1132 : 0 : c += 'e' - 'g'; /* e or E */
1133 [ # # ]: 0 : if (precision > 0) {
1134 : 0 : precision--;
1135 : : }
1136 : : } else {
1137 : 0 : c = 'f';
1138 : 0 : precision -= decexp;
1139 : : }
1140 [ # # # # ]: 0 : if (!conv->flag_hash && (precision > 0)) {
1141 : 0 : prune_zero = true;
1142 : : }
1143 : : }
1144 : :
1145 : : int decimals;
1146 [ # # ]: 0 : if (c == 'f') {
1147 : 0 : decimals = precision + decexp;
1148 [ # # ]: 0 : if (decimals < 0) {
1149 : 0 : decimals = 0;
1150 : : }
1151 : : } else {
1152 : 0 : decimals = precision + 1;
1153 : : }
1154 : :
1155 : 0 : int digit_count = 16;
1156 : :
1157 [ # # ]: 0 : if (decimals > 16) {
1158 : 0 : decimals = 16;
1159 : : }
1160 : :
1161 : : /* Round the value to the last digit being printed. */
1162 : 0 : uint64_t round = BIT64(59); /* 0.5 */
1163 [ # # ]: 0 : while (decimals--) {
1164 : 0 : _ldiv10(&round);
1165 : : }
1166 : 0 : fract += round;
1167 : : /* Make sure rounding didn't make fract >= 1.0 */
1168 [ # # ]: 0 : if (fract >= BIT64(60)) {
1169 : 0 : _ldiv10(&fract);
1170 : 0 : decexp++;
1171 : : }
1172 : :
1173 [ # # ]: 0 : if (c == 'f') {
1174 [ # # ]: 0 : if (decexp > 0) {
1175 : : /* Emit the digits above the decimal point. */
1176 [ # # # # ]: 0 : while (decexp > 0 && digit_count > 0) {
1177 : 0 : *buf++ = _get_digit(&fract, &digit_count);
1178 : 0 : decexp--;
1179 : : }
1180 : :
1181 : 0 : conv->pad0_value = decexp;
1182 : :
1183 : 0 : decexp = 0;
1184 : : } else {
1185 : 0 : *buf++ = '0';
1186 : : }
1187 : :
1188 : : /* Emit the decimal point only if required by the alternative
1189 : : * format, or if more digits are to follow.
1190 : : */
1191 [ # # # # ]: 0 : if (conv->flag_hash || (precision > 0)) {
1192 : 0 : *buf++ = '.';
1193 : : }
1194 : :
1195 [ # # # # ]: 0 : if (decexp < 0 && precision > 0) {
1196 : 0 : conv->pad0_value = -decexp;
1197 [ # # ]: 0 : if (conv->pad0_value > precision) {
1198 : 0 : conv->pad0_value = precision;
1199 : : }
1200 : :
1201 : 0 : precision -= conv->pad0_value;
1202 : 0 : conv->pad_postdp = (conv->pad0_value > 0);
1203 : : }
1204 : : } else { /* e or E */
1205 : : /* Emit the one digit before the decimal. If it's not zero,
1206 : : * this is significant so reduce the base-10 exponent.
1207 : : */
1208 : 0 : *buf = _get_digit(&fract, &digit_count);
1209 [ # # ]: 0 : if (*buf++ != '0') {
1210 : 0 : decexp--;
1211 : : }
1212 : :
1213 : : /* Emit the decimal point only if required by the alternative
1214 : : * format, or if more digits are to follow.
1215 : : */
1216 [ # # # # ]: 0 : if (conv->flag_hash || (precision > 0)) {
1217 : 0 : *buf++ = '.';
1218 : : }
1219 : : }
1220 : :
1221 [ # # # # ]: 0 : while (precision > 0 && digit_count > 0) {
1222 : 0 : *buf++ = _get_digit(&fract, &digit_count);
1223 : 0 : precision--;
1224 : : }
1225 : :
1226 : 0 : conv->pad0_pre_exp = precision;
1227 : :
1228 [ # # ]: 0 : if (prune_zero) {
1229 : 0 : conv->pad0_pre_exp = 0;
1230 [ # # ]: 0 : while (*--buf == '0') {
1231 : : ;
1232 : : }
1233 [ # # ]: 0 : if (*buf != '.') {
1234 : 0 : buf++;
1235 : : }
1236 : : }
1237 : :
1238 : : /* Emit the explicit exponent, if format requires it. */
1239 [ # # # # ]: 0 : if ((c == 'e') || (c == 'E')) {
1240 : 0 : *buf++ = c;
1241 [ # # ]: 0 : if (decexp < 0) {
1242 : 0 : decexp = -decexp;
1243 : 0 : *buf++ = '-';
1244 : : } else {
1245 : 0 : *buf++ = '+';
1246 : : }
1247 : :
1248 : : /* At most 3 digits to the decimal. Spit them out. */
1249 [ # # ]: 0 : if (decexp >= 100) {
1250 : 0 : *buf++ = (decexp / 100) + '0';
1251 : 0 : decexp %= 100;
1252 : : }
1253 : :
1254 : 0 : *buf++ = (decexp / 10) + '0';
1255 : 0 : *buf++ = (decexp % 10) + '0';
1256 : : }
1257 : :
1258 : : /* Cache whether there's padding required */
1259 : 0 : conv->pad_fp = (conv->pad0_value > 0)
1260 [ # # # # ]: 0 : || (conv->pad0_pre_exp > 0);
1261 : :
1262 : : /* Set the end of the encoded sequence, and return its start. Also
1263 : : * store EOS as a non-digit/non-decimal value so we don't have to
1264 : : * check against bpe when iterating in multiple places.
1265 : : */
1266 : 0 : *bpe = buf;
1267 : 0 : *buf = 0;
1268 : 0 : return bps;
1269 : : }
1270 : :
1271 : : /* Store a count into the pointer provided in a %n specifier.
1272 : : *
1273 : : * @param conv the specifier that indicates the size of the value into which
1274 : : * the count will be stored.
1275 : : *
1276 : : * @param dp where the count should be stored.
1277 : : *
1278 : : * @param count the count to be stored.
1279 : : */
1280 : 0 : static inline void store_count(const struct conversion *conv,
1281 : : void *dp,
1282 : : int count)
1283 : : {
1284 [ # # # # : 0 : switch ((enum length_mod_enum)conv->length_mod) {
# # # #
# ]
1285 : 0 : case LENGTH_NONE:
1286 : 0 : *(int *)dp = count;
1287 : 0 : break;
1288 : 0 : case LENGTH_HH:
1289 : 0 : *(signed char *)dp = (signed char)count;
1290 : 0 : break;
1291 : 0 : case LENGTH_H:
1292 : 0 : *(short *)dp = (short)count;
1293 : 0 : break;
1294 : 0 : case LENGTH_L:
1295 : 0 : *(long *)dp = (long)count;
1296 : 0 : break;
1297 : 0 : case LENGTH_LL:
1298 : 0 : *(long long *)dp = (long long)count;
1299 : 0 : break;
1300 : 0 : case LENGTH_J:
1301 : 0 : *(intmax_t *)dp = (intmax_t)count;
1302 : 0 : break;
1303 : 0 : case LENGTH_Z:
1304 : 0 : *(size_t *)dp = (size_t)count;
1305 : 0 : break;
1306 : 0 : case LENGTH_T:
1307 : 0 : *(ptrdiff_t *)dp = (ptrdiff_t)count;
1308 : 0 : break;
1309 : 0 : default:
1310 : : /* Add an empty default with break, this is a defensive programming.
1311 : : * Static analysis tool won't raise a violation if default is empty,
1312 : : * but has that comment.
1313 : : */
1314 : 0 : break;
1315 : : }
1316 : 0 : }
1317 : :
1318 : : /* Outline function to emit all characters in [sp, ep). */
1319 : 133519 : static int outs(cbprintf_cb out,
1320 : : void *ctx,
1321 : : const char *sp,
1322 : : const char *ep)
1323 : : {
1324 : 133519 : size_t count = 0;
1325 : :
1326 [ + + - + : 293307 : while ((sp < ep) || ((ep == NULL) && *sp)) {
- - ]
1327 : 159788 : int rc = out((int)*sp++, ctx);
1328 : :
1329 [ - + ]: 159788 : if (rc < 0) {
1330 : 0 : return rc;
1331 : : }
1332 : 159788 : ++count;
1333 : : }
1334 : :
1335 : 133519 : return (int)count;
1336 : : }
1337 : :
1338 : 133520 : int cbvprintf(cbprintf_cb out, void *ctx, const char *fp, va_list ap)
1339 : : {
1340 : : char buf[CONVERTED_BUFLEN];
1341 : 133520 : size_t count = 0;
1342 : : sint_value_type sint;
1343 : :
1344 : : /* Output character, returning EOF if output failed, otherwise
1345 : : * updating count.
1346 : : *
1347 : : * NB: c is evaluated exactly once: side-effects are OK
1348 : : */
1349 : : #define OUTC(c) do { \
1350 : : int rc = (*out)((int)(c), ctx); \
1351 : : \
1352 : : if (rc < 0) { \
1353 : : return rc; \
1354 : : } \
1355 : : ++count; \
1356 : : } while (false)
1357 : :
1358 : : /* Output sequence of characters, returning a negative error if output
1359 : : * failed.
1360 : : */
1361 : :
1362 : : #define OUTS(_sp, _ep) do { \
1363 : : int rc = outs(out, ctx, _sp, _ep); \
1364 : : \
1365 : : if (rc < 0) { \
1366 : : return rc; \
1367 : : } \
1368 : : count += rc; \
1369 : : } while (false)
1370 : :
1371 [ + + ]: 387404 : while (*fp != 0) {
1372 [ + + ]: 253884 : if (*fp != '%') {
1373 [ - + ]: 120365 : OUTC(*fp++);
1374 : 120365 : continue;
1375 : : }
1376 : :
1377 : : /* Force union into RAM with conversion state to
1378 : : * mitigate LLVM code generation bug.
1379 : : */
1380 : : struct {
1381 : : union argument_value value;
1382 : : struct conversion conv;
1383 : 133519 : } state = {
1384 : : .value = {
1385 : : .uint = 0,
1386 : : },
1387 : : };
1388 : 133519 : struct conversion *const conv = &state.conv;
1389 : 133519 : union argument_value *const value = &state.value;
1390 : 133519 : const char *sp = fp;
1391 : 133519 : int width = -1;
1392 : 133519 : int precision = -1;
1393 : 133519 : const char *bps = NULL;
1394 : 133519 : const char *bpe = buf + sizeof(buf);
1395 : 133519 : char sign = 0;
1396 : :
1397 : 133519 : fp = extract_conversion(conv, sp);
1398 : :
1399 : : /* If dynamic width is specified, process it,
1400 : : * otherwise set width if present.
1401 : : */
1402 [ - + ]: 133519 : if (conv->width_star) {
1403 : 0 : width = va_arg(ap, int);
1404 : :
1405 [ # # ]: 0 : if (width < 0) {
1406 : 0 : conv->flag_dash = true;
1407 : 0 : width = -width;
1408 : : }
1409 [ + - ]: 133519 : } else if (conv->width_present) {
1410 : 133519 : width = conv->width_value;
1411 : : } else {
1412 : : ;
1413 : : }
1414 : :
1415 : : /* If dynamic precision is specified, process it, otherwise
1416 : : * set precision if present. For floating point where
1417 : : * precision is not present use 6.
1418 : : */
1419 [ - + ]: 133519 : if (conv->prec_star) {
1420 : 0 : int arg = va_arg(ap, int);
1421 : :
1422 [ # # ]: 0 : if (arg < 0) {
1423 : 0 : conv->prec_present = false;
1424 : : } else {
1425 : 0 : precision = arg;
1426 : : }
1427 [ - + ]: 133519 : } else if (conv->prec_present) {
1428 : 0 : precision = conv->prec_value;
1429 : : } else {
1430 : : ;
1431 : : }
1432 : :
1433 : : /* Reuse width and precision memory in conv for value
1434 : : * padding counts.
1435 : : */
1436 : 133519 : conv->pad0_value = 0;
1437 : 133519 : conv->pad0_pre_exp = 0;
1438 : :
1439 : : /* FP conversion requires knowing the precision. */
1440 : : if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)
1441 : : && (conv->specifier_cat == SPECIFIER_FP)
1442 : : && !conv->prec_present) {
1443 : : if (conv->specifier_a) {
1444 : : precision = FRACTION_HEX;
1445 : : } else {
1446 : : precision = 6;
1447 : : }
1448 : : }
1449 : :
1450 : : /* Get the value to be converted from the args.
1451 : : *
1452 : : * This can't be extracted to a helper function because
1453 : : * passing a pointer to va_list doesn't work on x86_64. See
1454 : : * https://stackoverflow.com/a/8048892.
1455 : : */
1456 : 133519 : enum specifier_cat_enum specifier_cat
1457 : 133519 : = (enum specifier_cat_enum)conv->specifier_cat;
1458 : 133519 : enum length_mod_enum length_mod
1459 : 133519 : = (enum length_mod_enum)conv->length_mod;
1460 : :
1461 : : /* Extract the value based on the argument category and length.
1462 : : *
1463 : : * Note that the length modifier doesn't affect the value of a
1464 : : * pointer argument.
1465 : : */
1466 [ + + ]: 133519 : if (specifier_cat == SPECIFIER_SINT) {
1467 [ + - - - : 1 : switch (length_mod) {
- ]
1468 : 1 : default:
1469 : : case LENGTH_NONE:
1470 : : case LENGTH_HH:
1471 : : case LENGTH_H:
1472 : 1 : value->sint = va_arg(ap, int);
1473 : 1 : break;
1474 : 0 : case LENGTH_L:
1475 : : if (WCHAR_IS_SIGNED
1476 : : && (conv->specifier == 'c')) {
1477 : : value->sint = (wchar_t)va_arg(ap,
1478 : : WINT_TYPE);
1479 : : } else {
1480 : 0 : value->sint = va_arg(ap, long);
1481 : : }
1482 : 0 : break;
1483 : 0 : case LENGTH_LL:
1484 : 0 : value->sint =
1485 : 0 : (sint_value_type)va_arg(ap, long long);
1486 : 0 : break;
1487 : 0 : case LENGTH_J:
1488 : 0 : value->sint =
1489 : 0 : (sint_value_type)va_arg(ap, intmax_t);
1490 : 0 : break;
1491 : 0 : case LENGTH_Z: /* size_t */
1492 : : case LENGTH_T: /* ptrdiff_t */
1493 : : /* Though ssize_t is the signed equivalent of
1494 : : * size_t for POSIX, there is no uptrdiff_t.
1495 : : * Assume that size_t and ptrdiff_t are the
1496 : : * unsigned and signed equivalents of each
1497 : : * other. This can be checked in a platform
1498 : : * test.
1499 : : */
1500 : 0 : value->sint =
1501 : 0 : (sint_value_type)va_arg(ap, ptrdiff_t);
1502 : 0 : break;
1503 : : }
1504 [ - + ]: 1 : if (length_mod == LENGTH_HH) {
1505 : 0 : value->sint = (char)value->sint;
1506 [ - + ]: 1 : } else if (length_mod == LENGTH_H) {
1507 : 0 : value->sint = (short)value->sint;
1508 : : }
1509 [ + + ]: 133518 : } else if (specifier_cat == SPECIFIER_UINT) {
1510 [ + - - - : 133510 : switch (length_mod) {
- ]
1511 : 133510 : default:
1512 : : case LENGTH_NONE:
1513 : : case LENGTH_HH:
1514 : : case LENGTH_H:
1515 : 133510 : value->uint = va_arg(ap, unsigned int);
1516 : 133510 : break;
1517 : 0 : case LENGTH_L:
1518 : 0 : if ((!WCHAR_IS_SIGNED)
1519 [ # # ]: 0 : && (conv->specifier == 'c')) {
1520 : 0 : value->uint = (wchar_t)va_arg(ap,
1521 : : WINT_TYPE);
1522 : : } else {
1523 : 0 : value->uint = va_arg(ap, unsigned long);
1524 : : }
1525 : 0 : break;
1526 : 0 : case LENGTH_LL:
1527 : 0 : value->uint =
1528 : 0 : (uint_value_type)va_arg(ap,
1529 : : unsigned long long);
1530 : 0 : break;
1531 : 0 : case LENGTH_J:
1532 : 0 : value->uint =
1533 : 0 : (uint_value_type)va_arg(ap,
1534 : : uintmax_t);
1535 : 0 : break;
1536 : 0 : case LENGTH_Z: /* size_t */
1537 : : case LENGTH_T: /* ptrdiff_t */
1538 : 0 : value->uint =
1539 : 0 : (uint_value_type)va_arg(ap, size_t);
1540 : 0 : break;
1541 : : }
1542 [ - + ]: 133510 : if (length_mod == LENGTH_HH) {
1543 : 0 : value->uint = (unsigned char)value->uint;
1544 [ - + ]: 133510 : } else if (length_mod == LENGTH_H) {
1545 : 0 : value->uint = (unsigned short)value->uint;
1546 : : }
1547 [ - + ]: 8 : } else if (specifier_cat == SPECIFIER_FP) {
1548 [ # # ]: 0 : if (length_mod == LENGTH_UPPER_L) {
1549 : 0 : value->ldbl = va_arg(ap, long double);
1550 : : } else {
1551 : 0 : value->dbl = va_arg(ap, double);
1552 : : }
1553 [ + - ]: 8 : } else if (specifier_cat == SPECIFIER_PTR) {
1554 : 8 : value->ptr = va_arg(ap, void *);
1555 : : }
1556 : :
1557 : : /* We've now consumed all arguments related to this
1558 : : * specification. If the conversion is invalid, or is
1559 : : * something we don't support, then output the original
1560 : : * specification and move on.
1561 : : */
1562 [ + - - + ]: 133519 : if (conv->invalid || conv->unsupported) {
1563 [ # # ]: 0 : OUTS(sp, fp);
1564 : 0 : continue;
1565 : : }
1566 : :
1567 : : /* Do formatting, either into the buffer or
1568 : : * referencing external data.
1569 : : */
1570 [ - + + + : 133519 : switch (conv->specifier) {
+ - - -
- ]
1571 : 0 : case '%':
1572 [ # # ]: 0 : OUTC('%');
1573 : 0 : break;
1574 : 8 : case 's': {
1575 : 8 : bps = (const char *)value->ptr;
1576 : :
1577 : : size_t len;
1578 : :
1579 [ - + ]: 8 : if (precision >= 0) {
1580 : 0 : len = strnlen(bps, precision);
1581 : : } else {
1582 : 8 : len = strlen(bps);
1583 : : }
1584 : :
1585 : 8 : bpe = bps + len;
1586 : 8 : precision = -1;
1587 : :
1588 : 8 : break;
1589 : : }
1590 : 13624 : case 'c':
1591 : 13624 : bps = buf;
1592 : 13624 : buf[0] = CHAR_IS_SIGNED ? value->sint : value->uint;
1593 : 13624 : bpe = buf + 1;
1594 : 13624 : break;
1595 : 1 : case 'd':
1596 : : case 'i':
1597 [ - + ]: 1 : if (conv->flag_plus) {
1598 : 0 : sign = '+';
1599 [ - + ]: 1 : } else if (conv->flag_space) {
1600 : 0 : sign = ' ';
1601 : : }
1602 : :
1603 : : /* sint/uint overlay in the union, and so
1604 : : * can't appear in read and write operations
1605 : : * in the same statement.
1606 : : */
1607 : 1 : sint = value->sint;
1608 [ - + ]: 1 : if (sint < 0) {
1609 : 0 : sign = '-';
1610 : 0 : value->uint = (uint_value_type)-sint;
1611 : : } else {
1612 : 1 : value->uint = (uint_value_type)sint;
1613 : : }
1614 : :
1615 : : __fallthrough;
1616 : : case 'o':
1617 : : case 'u':
1618 : : case 'x':
1619 : : case 'X':
1620 : 119887 : bps = encode_uint(value->uint, conv, buf, bpe);
1621 : :
1622 : 119887 : prec_int_pad0:
1623 : : /* Update pad0 values based on precision and converted
1624 : : * length. Note that a non-empty sign is not in the
1625 : : * converted sequence, but it does not affect the
1626 : : * padding size.
1627 : : */
1628 [ - + ]: 119887 : if (precision >= 0) {
1629 : 0 : size_t len = bpe - bps;
1630 : :
1631 : : /* Zero-padding flag is ignored for integer
1632 : : * conversions with precision.
1633 : : */
1634 : 0 : conv->flag_zero = false;
1635 : :
1636 : : /* Set pad0_value to satisfy precision */
1637 [ # # ]: 0 : if (len < (size_t)precision) {
1638 : 0 : conv->pad0_value = precision - (int)len;
1639 : : }
1640 : : }
1641 : :
1642 : 119887 : break;
1643 : 0 : case 'p':
1644 : : /* Implementation-defined: null is "(nil)", non-null
1645 : : * has 0x prefix followed by significant address hex
1646 : : * digits, no leading zeros.
1647 : : */
1648 [ # # ]: 0 : if (value->ptr != NULL) {
1649 : 0 : bps = encode_uint((uintptr_t)value->ptr, conv,
1650 : : buf, bpe);
1651 : :
1652 : : /* Use 0x prefix */
1653 : 0 : conv->altform_0c = true;
1654 : 0 : conv->specifier = 'x';
1655 : :
1656 : 0 : goto prec_int_pad0;
1657 : : }
1658 : :
1659 : 0 : bps = "(nil)";
1660 : 0 : bpe = bps + 5;
1661 : :
1662 : 0 : break;
1663 : 0 : case 'n':
1664 : : if (IS_ENABLED(CONFIG_CBPRINTF_N_SPECIFIER)) {
1665 : 0 : store_count(conv, value->ptr, count);
1666 : : }
1667 : :
1668 : 0 : break;
1669 : :
1670 : 0 : case FP_CONV_CASES:
1671 : : if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
1672 : : bps = encode_float(value->dbl, conv, precision,
1673 : : &sign, buf, &bpe);
1674 : : }
1675 : 0 : break;
1676 : 0 : default:
1677 : : /* Add an empty default with break, this is a defensive
1678 : : * programming. Static analysis tool won't raise a violation
1679 : : * if default is empty, but has that comment.
1680 : : */
1681 : 0 : break;
1682 : : }
1683 : :
1684 : : /* If we don't have a converted value to emit, move
1685 : : * on.
1686 : : */
1687 [ - + ]: 133519 : if (bps == NULL) {
1688 : 0 : continue;
1689 : : }
1690 : :
1691 : : /* The converted value is now stored in [bps, bpe), excluding
1692 : : * any required zero padding.
1693 : : *
1694 : : * The unjustified output will be:
1695 : : *
1696 : : * * any sign character (sint-only)
1697 : : * * any altform prefix
1698 : : * * for FP:
1699 : : * * any pre-decimal content from the converted value
1700 : : * * any pad0_value padding (!postdp)
1701 : : * * any decimal point in the converted value
1702 : : * * any pad0_value padding (postdp)
1703 : : * * any pre-exponent content from the converted value
1704 : : * * any pad0_pre_exp padding
1705 : : * * any exponent content from the converted value
1706 : : * * for non-FP:
1707 : : * * any pad0_prefix
1708 : : * * the converted value
1709 : : */
1710 : 133519 : size_t nj_len = (bpe - bps);
1711 : 133519 : int pad_len = 0;
1712 : :
1713 [ - + ]: 133519 : if (sign != 0) {
1714 : 0 : nj_len += 1U;
1715 : : }
1716 : :
1717 [ - + ]: 133519 : if (conv->altform_0c) {
1718 : 0 : nj_len += 2U;
1719 [ - + ]: 133519 : } else if (conv->altform_0) {
1720 : 0 : nj_len += 1U;
1721 : : }
1722 : :
1723 : 133519 : nj_len += conv->pad0_value;
1724 [ - + ]: 133519 : if (conv->pad_fp) {
1725 : 0 : nj_len += conv->pad0_pre_exp;
1726 : : }
1727 : :
1728 : : /* If we have a width update width to hold the padding we need
1729 : : * for justification. The result may be negative, which will
1730 : : * result in no padding.
1731 : : *
1732 : : * If a non-negative padding width is present and we're doing
1733 : : * right-justification, emit the padding now.
1734 : : */
1735 [ + + ]: 133519 : if (width > 0) {
1736 : 119884 : width -= (int)nj_len;
1737 : :
1738 [ + - ]: 119884 : if (!conv->flag_dash) {
1739 : 119884 : char pad = ' ';
1740 : :
1741 : : /* If we're zero-padding we have to emit the
1742 : : * sign first.
1743 : : */
1744 [ + - ]: 119884 : if (conv->flag_zero) {
1745 [ - + ]: 119884 : if (sign != 0) {
1746 [ # # ]: 0 : OUTC(sign);
1747 : 0 : sign = 0;
1748 : : }
1749 : 119884 : pad = '0';
1750 : : }
1751 : :
1752 [ + + ]: 213547 : while (width-- > 0) {
1753 [ - + ]: 93663 : OUTC(pad);
1754 : : }
1755 : : }
1756 : : }
1757 : :
1758 : : /* If we have a sign that hasn't been emitted, now's the
1759 : : * time....
1760 : : */
1761 [ - + ]: 133519 : if (sign != 0) {
1762 [ # # ]: 0 : OUTC(sign);
1763 : : }
1764 : :
1765 : : if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT) && conv->pad_fp) {
1766 : : const char *cp = bps;
1767 : :
1768 : : if (conv->specifier_a) {
1769 : : /* Only padding is pre_exp */
1770 : : while (*cp != 'p') {
1771 : : OUTC(*cp++);
1772 : : }
1773 : : } else {
1774 : : while (isdigit((int)*cp)) {
1775 : : OUTC(*cp++);
1776 : : }
1777 : :
1778 : : pad_len = conv->pad0_value;
1779 : : if (!conv->pad_postdp) {
1780 : : while (pad_len-- > 0) {
1781 : : OUTC('0');
1782 : : }
1783 : : }
1784 : :
1785 : : if (*cp == '.') {
1786 : : OUTC(*cp++);
1787 : : /* Remaining padding is
1788 : : * post-dp.
1789 : : */
1790 : : while (pad_len-- > 0) {
1791 : : OUTC('0');
1792 : : }
1793 : : }
1794 : : while (isdigit((int)*cp)) {
1795 : : OUTC(*cp++);
1796 : : }
1797 : : }
1798 : :
1799 : : pad_len = conv->pad0_pre_exp;
1800 : : while (pad_len-- > 0) {
1801 : : OUTC('0');
1802 : : }
1803 : :
1804 : : OUTS(cp, bpe);
1805 : : } else {
1806 [ - + ]: 133519 : if (conv->altform_0c | conv->altform_0) {
1807 [ # # ]: 0 : OUTC('0');
1808 : : }
1809 : :
1810 [ - + ]: 133519 : if (conv->altform_0c) {
1811 [ # # ]: 0 : OUTC(conv->specifier);
1812 : : }
1813 : :
1814 : 133519 : pad_len = conv->pad0_value;
1815 [ - + ]: 133519 : while (pad_len-- > 0) {
1816 [ # # ]: 0 : OUTC('0');
1817 : : }
1818 : :
1819 [ - + ]: 133519 : OUTS(bps, bpe);
1820 : : }
1821 : :
1822 : : /* Finish left justification */
1823 [ - + ]: 133519 : while (width > 0) {
1824 [ # # ]: 0 : OUTC(' ');
1825 : 0 : --width;
1826 : : }
1827 : : }
1828 : :
1829 : 133520 : return count;
1830 : : #undef OUTS
1831 : : #undef OUTC
1832 : : }
|