source: mainline/common/printf/printf_core.c@ 5b110a9

Last change on this file since 5b110a9 was 694ca3d6, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Deduplicate printf_core()

  • Property mode set to 100644
File size: 41.4 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * Copyright (c) 2006 Josef Cejka
4 * Copyright (c) 2009 Martin Decky
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libc
32 * @{
33 */
34/**
35 * @file
36 * @brief Printing functions.
37 */
38
39#include <stdio.h>
40#include <stddef.h>
41#include <stdlib.h>
42#include <printf_core.h>
43#include <ctype.h>
44#include <str.h>
45#include <assert.h>
46#include <macros.h>
47#include <uchar.h>
48
49/* Disable float support in kernel, because we usually disable floating operations there. */
50#if __STDC_HOSTED__
51#define HAS_FLOAT
52#endif
53
54#ifdef HAS_FLOAT
55#include <double_to_str.h>
56#include <ieee_double.h>
57#endif
58
59/** show prefixes 0x or 0 */
60#define __PRINTF_FLAG_PREFIX 0x00000001
61
62/** show the decimal point even if no fractional digits present */
63#define __PRINTF_FLAG_DECIMALPT 0x00000001
64
65/** signed / unsigned number */
66#define __PRINTF_FLAG_SIGNED 0x00000002
67
68/** print leading zeroes */
69#define __PRINTF_FLAG_ZEROPADDED 0x00000004
70
71/** align to left */
72#define __PRINTF_FLAG_LEFTALIGNED 0x00000010
73
74/** always show + sign */
75#define __PRINTF_FLAG_SHOWPLUS 0x00000020
76
77/** print space instead of plus */
78#define __PRINTF_FLAG_SPACESIGN 0x00000040
79
80/** show big characters */
81#define __PRINTF_FLAG_BIGCHARS 0x00000080
82
83/** number has - sign */
84#define __PRINTF_FLAG_NEGATIVE 0x00000100
85
86/** don't print trailing zeros in the fractional part */
87#define __PRINTF_FLAG_NOFRACZEROS 0x00000200
88
89/**
90 * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
91 * to terminate string... (last one is only for better testing end of buffer by
92 * zero-filling subroutine)
93 */
94#define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
95
96/** Get signed or unsigned integer argument */
97#define PRINTF_GET_INT_ARGUMENT(type, ap, flags) \
98 ({ \
99 unsigned type res; \
100 \
101 if ((flags) & __PRINTF_FLAG_SIGNED) { \
102 signed type arg = va_arg((ap), signed type); \
103 \
104 if (arg < 0) { \
105 res = -arg; \
106 (flags) |= __PRINTF_FLAG_NEGATIVE; \
107 } else \
108 res = arg; \
109 } else \
110 res = va_arg((ap), unsigned type); \
111 \
112 res; \
113 })
114
115/** Enumeration of possible arguments types.
116 */
117typedef enum {
118 PrintfQualifierByte = 0,
119 PrintfQualifierShort,
120 PrintfQualifierInt,
121 PrintfQualifierLong,
122 PrintfQualifierLongLong,
123 PrintfQualifierPointer,
124 PrintfQualifierSize,
125 PrintfQualifierMax
126} qualifier_t;
127
128static const char *nullstr = "(NULL)";
129static const char *digits_small = "0123456789abcdef";
130static const char *digits_big = "0123456789ABCDEF";
131static const char invalch = U_SPECIAL;
132
133/** Print one or more characters without adding newline.
134 *
135 * @param buf Buffer holding characters with size of
136 * at least size bytes. NULL is not allowed!
137 * @param size Size of the buffer in bytes.
138 * @param ps Output method and its data.
139 *
140 * @return Number of characters printed.
141 *
142 */
143static int printf_putnchars(const char *buf, size_t size,
144 printf_spec_t *ps)
145{
146 return ps->str_write((void *) buf, size, ps->data);
147}
148
149/** Print one or more wide characters without adding newline.
150 *
151 * @param buf Buffer holding wide characters with size of
152 * at least size bytes. NULL is not allowed!
153 * @param size Size of the buffer in bytes.
154 * @param ps Output method and its data.
155 *
156 * @return Number of wide characters printed.
157 *
158 */
159static int printf_wputnchars(const char32_t *buf, size_t size,
160 printf_spec_t *ps)
161{
162 return ps->wstr_write((void *) buf, size, ps->data);
163}
164
165/** Print string without adding a newline.
166 *
167 * @param str String to print.
168 * @param ps Write function specification and support data.
169 *
170 * @return Number of characters printed.
171 *
172 */
173static int printf_putstr(const char *str, printf_spec_t *ps)
174{
175 if (str == NULL)
176 return printf_putnchars(nullstr, str_size(nullstr), ps);
177
178 return ps->str_write((void *) str, str_size(str), ps->data);
179}
180
181/** Print one ASCII character.
182 *
183 * @param c ASCII character to be printed.
184 * @param ps Output method.
185 *
186 * @return Number of characters printed.
187 *
188 */
189static int printf_putchar(const char ch, printf_spec_t *ps)
190{
191 if (!ascii_check(ch))
192 return ps->str_write((void *) &invalch, 1, ps->data);
193
194 return ps->str_write(&ch, 1, ps->data);
195}
196
197/** Print one wide character.
198 *
199 * @param c Wide character to be printed.
200 * @param ps Output method.
201 *
202 * @return Number of characters printed.
203 *
204 */
205static int printf_putuchar(const char32_t ch, printf_spec_t *ps)
206{
207 if (!chr_check(ch))
208 return ps->str_write((void *) &invalch, 1, ps->data);
209
210 return ps->wstr_write(&ch, sizeof(char32_t), ps->data);
211}
212
213/** Print one formatted ASCII character.
214 *
215 * @param ch Character to print.
216 * @param width Width modifier.
217 * @param flags Flags that change the way the character is printed.
218 *
219 * @return Number of characters printed, negative value on failure.
220 *
221 */
222static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
223{
224 size_t counter = 0;
225 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
226 while (--width > 0) {
227 /*
228 * One space is consumed by the character itself, hence
229 * the predecrement.
230 */
231 if (printf_putchar(' ', ps) > 0)
232 counter++;
233 }
234 }
235
236 if (printf_putchar(ch, ps) > 0)
237 counter++;
238
239 while (--width > 0) {
240 /*
241 * One space is consumed by the character itself, hence
242 * the predecrement.
243 */
244 if (printf_putchar(' ', ps) > 0)
245 counter++;
246 }
247
248 return (int) (counter);
249}
250
251/** Print one formatted wide character.
252 *
253 * @param ch Character to print.
254 * @param width Width modifier.
255 * @param flags Flags that change the way the character is printed.
256 *
257 * @return Number of characters printed, negative value on failure.
258 *
259 */
260static int print_wchar(const char32_t ch, int width, uint32_t flags, printf_spec_t *ps)
261{
262 size_t counter = 0;
263 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
264 while (--width > 0) {
265 /*
266 * One space is consumed by the character itself, hence
267 * the predecrement.
268 */
269 if (printf_putchar(' ', ps) > 0)
270 counter++;
271 }
272 }
273
274 if (printf_putuchar(ch, ps) > 0)
275 counter++;
276
277 while (--width > 0) {
278 /*
279 * One space is consumed by the character itself, hence
280 * the predecrement.
281 */
282 if (printf_putchar(' ', ps) > 0)
283 counter++;
284 }
285
286 return (int) (counter);
287}
288
289/** Print string.
290 *
291 * @param str String to be printed.
292 * @param width Width modifier.
293 * @param precision Precision modifier.
294 * @param flags Flags that modify the way the string is printed.
295 *
296 * @return Number of characters printed, negative value on failure.
297 */
298static int print_str(char *str, int width, unsigned int precision,
299 uint32_t flags, printf_spec_t *ps)
300{
301 if (str == NULL)
302 return printf_putstr(nullstr, ps);
303
304 size_t strw = str_length(str);
305
306 /* Precision unspecified - print everything. */
307 if ((precision == 0) || (precision > strw))
308 precision = strw;
309
310 /* Left padding */
311 size_t counter = 0;
312 width -= precision;
313 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
314 while (width-- > 0) {
315 if (printf_putchar(' ', ps) == 1)
316 counter++;
317 }
318 }
319
320 /* Part of @a str fitting into the alloted space. */
321 int retval;
322 size_t size = str_lsize(str, precision);
323 if ((retval = printf_putnchars(str, size, ps)) < 0)
324 return -counter;
325
326 counter += retval;
327
328 /* Right padding */
329 while (width-- > 0) {
330 if (printf_putchar(' ', ps) == 1)
331 counter++;
332 }
333
334 return ((int) counter);
335
336}
337
338/** Print wide string.
339 *
340 * @param str Wide string to be printed.
341 * @param width Width modifier.
342 * @param precision Precision modifier.
343 * @param flags Flags that modify the way the string is printed.
344 *
345 * @return Number of wide characters printed, negative value on failure.
346 */
347static int print_wstr(char32_t *str, int width, unsigned int precision,
348 uint32_t flags, printf_spec_t *ps)
349{
350 if (str == NULL)
351 return printf_putstr(nullstr, ps);
352
353 size_t strw = wstr_length(str);
354
355 /* Precision not specified - print everything. */
356 if ((precision == 0) || (precision > strw))
357 precision = strw;
358
359 /* Left padding */
360 size_t counter = 0;
361 width -= precision;
362 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
363 while (width-- > 0) {
364 if (printf_putchar(' ', ps) == 1)
365 counter++;
366 }
367 }
368
369 /* Part of @a wstr fitting into the alloted space. */
370 int retval;
371 size_t size = wstr_lsize(str, precision);
372 if ((retval = printf_wputnchars(str, size, ps)) < 0)
373 return -counter;
374
375 counter += retval;
376
377 /* Right padding */
378 while (width-- > 0) {
379 if (printf_putchar(' ', ps) == 1)
380 counter++;
381 }
382
383 return ((int) counter);
384}
385
386/** Print a number in a given base.
387 *
388 * Print significant digits of a number in given base.
389 *
390 * @param num Number to print.
391 * @param width Width modifier.
392 * @param precision Precision modifier.
393 * @param base Base to print the number in (must be between 2 and 16).
394 * @param flags Flags that modify the way the number is printed.
395 *
396 * @return Number of characters printed.
397 *
398 */
399static int print_number(uint64_t num, int width, int precision, int base,
400 uint32_t flags, printf_spec_t *ps)
401{
402 /* Precision not specified. */
403 if (precision < 0) {
404 precision = 0;
405 }
406
407 const char *digits;
408 if (flags & __PRINTF_FLAG_BIGCHARS)
409 digits = digits_big;
410 else
411 digits = digits_small;
412
413 char data[PRINT_NUMBER_BUFFER_SIZE];
414 char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
415
416 /* Size of number with all prefixes and signs */
417 int size = 0;
418
419 /* Put zero at end of string */
420 *ptr-- = 0;
421
422 if (num == 0) {
423 *ptr-- = '0';
424 size++;
425 } else {
426 do {
427 *ptr-- = digits[num % base];
428 size++;
429 } while (num /= base);
430 }
431
432 /* Size of plain number */
433 int number_size = size;
434
435 /*
436 * Collect the sum of all prefixes/signs/etc. to calculate padding and
437 * leading zeroes.
438 */
439 if (flags & __PRINTF_FLAG_PREFIX) {
440 switch (base) {
441 case 2:
442 /* Binary formating is not standard, but usefull */
443 size += 2;
444 break;
445 case 8:
446 size++;
447 break;
448 case 16:
449 size += 2;
450 break;
451 }
452 }
453
454 char sgn = 0;
455 if (flags & __PRINTF_FLAG_SIGNED) {
456 if (flags & __PRINTF_FLAG_NEGATIVE) {
457 sgn = '-';
458 size++;
459 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
460 sgn = '+';
461 size++;
462 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
463 sgn = ' ';
464 size++;
465 }
466 }
467
468 if (flags & __PRINTF_FLAG_LEFTALIGNED)
469 flags &= ~__PRINTF_FLAG_ZEROPADDED;
470
471 /*
472 * If the number is left-aligned or precision is specified then
473 * padding with zeros is ignored.
474 */
475 if (flags & __PRINTF_FLAG_ZEROPADDED) {
476 if ((precision == 0) && (width > size))
477 precision = width - size + number_size;
478 }
479
480 /* Print leading spaces */
481 if (number_size > precision) {
482 /* Print the whole number, not only a part */
483 precision = number_size;
484 }
485
486 width -= precision + size - number_size;
487 size_t counter = 0;
488
489 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
490 while (width-- > 0) {
491 if (printf_putchar(' ', ps) == 1)
492 counter++;
493 }
494 }
495
496 /* Print sign */
497 if (sgn) {
498 if (printf_putchar(sgn, ps) == 1)
499 counter++;
500 }
501
502 /* Print prefix */
503 if (flags & __PRINTF_FLAG_PREFIX) {
504 switch (base) {
505 case 2:
506 /* Binary formating is not standard, but usefull */
507 if (printf_putchar('0', ps) == 1)
508 counter++;
509 if (flags & __PRINTF_FLAG_BIGCHARS) {
510 if (printf_putchar('B', ps) == 1)
511 counter++;
512 } else {
513 if (printf_putchar('b', ps) == 1)
514 counter++;
515 }
516 break;
517 case 8:
518 if (printf_putchar('o', ps) == 1)
519 counter++;
520 break;
521 case 16:
522 if (printf_putchar('0', ps) == 1)
523 counter++;
524 if (flags & __PRINTF_FLAG_BIGCHARS) {
525 if (printf_putchar('X', ps) == 1)
526 counter++;
527 } else {
528 if (printf_putchar('x', ps) == 1)
529 counter++;
530 }
531 break;
532 }
533 }
534
535 /* Print leading zeroes */
536 precision -= number_size;
537 while (precision-- > 0) {
538 if (printf_putchar('0', ps) == 1)
539 counter++;
540 }
541
542 /* Print the number itself */
543 int retval;
544 if ((retval = printf_putstr(++ptr, ps)) > 0)
545 counter += retval;
546
547 /* Print trailing spaces */
548
549 while (width-- > 0) {
550 if (printf_putchar(' ', ps) == 1)
551 counter++;
552 }
553
554 return ((int) counter);
555}
556
557#ifdef HAS_FLOAT
558
559/** Unformatted double number string representation. */
560typedef struct {
561 /** Buffer with len digits, no sign or leading zeros. */
562 char *str;
563 /** Number of digits in str. */
564 int len;
565 /** Decimal exponent, ie number = str * 10^dec_exp */
566 int dec_exp;
567 /** True if negative. */
568 bool neg;
569} double_str_t;
570
571/** Returns the sign character or 0 if no sign should be printed. */
572static int get_sign_char(bool negative, uint32_t flags)
573{
574 if (negative) {
575 return '-';
576 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
577 return '+';
578 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
579 return ' ';
580 } else {
581 return 0;
582 }
583}
584
585/** Prints count times character ch. */
586static int print_padding(char ch, int count, printf_spec_t *ps)
587{
588 for (int i = 0; i < count; ++i) {
589 if (ps->str_write(&ch, 1, ps->data) < 0) {
590 return -1;
591 }
592 }
593
594 return count;
595}
596
597/** Prints a special double (ie NaN, infinity) padded to width characters. */
598static int print_special(ieee_double_t val, int width, uint32_t flags,
599 printf_spec_t *ps)
600{
601 assert(val.is_special);
602
603 char sign = get_sign_char(val.is_negative, flags);
604
605 const int str_len = 3;
606 const char *str;
607
608 if (flags & __PRINTF_FLAG_BIGCHARS) {
609 str = val.is_infinity ? "INF" : "NAN";
610 } else {
611 str = val.is_infinity ? "inf" : "nan";
612 }
613
614 int padding_len = max(0, width - ((sign ? 1 : 0) + str_len));
615
616 int counter = 0;
617 int ret;
618
619 /* Leading padding. */
620 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
621 if ((ret = print_padding(' ', padding_len, ps)) < 0)
622 return -1;
623
624 counter += ret;
625 }
626
627 if (sign) {
628 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
629 return -1;
630
631 counter += ret;
632 }
633
634 if ((ret = ps->str_write(str, str_len, ps->data)) < 0)
635 return -1;
636
637 counter += ret;
638
639 /* Trailing padding. */
640 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
641 if ((ret = print_padding(' ', padding_len, ps)) < 0)
642 return -1;
643
644 counter += ret;
645 }
646
647 return counter;
648}
649
650/** Trims trailing zeros but leaves a single "0" intact. */
651static void fp_trim_trailing_zeros(char *buf, int *len, int *dec_exp)
652{
653 /* Cut the zero off by adjusting the exponent. */
654 while (2 <= *len && '0' == buf[*len - 1]) {
655 --*len;
656 ++*dec_exp;
657 }
658}
659
660/** Textually round up the last digit thereby eliminating it. */
661static void fp_round_up(char *buf, int *len, int *dec_exp)
662{
663 assert(1 <= *len);
664
665 char *last_digit = &buf[*len - 1];
666
667 int carry = ('5' <= *last_digit);
668
669 /* Cut the digit off by adjusting the exponent. */
670 --*len;
671 ++*dec_exp;
672 --last_digit;
673
674 if (carry) {
675 /* Skip all the digits to cut off/round to zero. */
676 while (buf <= last_digit && '9' == *last_digit) {
677 --last_digit;
678 }
679
680 /* last_digit points to the last digit to round but not '9' */
681 if (buf <= last_digit) {
682 *last_digit += 1;
683 int new_len = last_digit - buf + 1;
684 *dec_exp += *len - new_len;
685 *len = new_len;
686 } else {
687 /* All len digits rounded to 0. */
688 buf[0] = '1';
689 *dec_exp += *len;
690 *len = 1;
691 }
692 } else {
693 /* The only digit was rounded to 0. */
694 if (last_digit < buf) {
695 buf[0] = '0';
696 *dec_exp = 0;
697 *len = 1;
698 }
699 }
700}
701
702/** Format and print the double string repressentation according
703 * to the %f specifier.
704 */
705static int print_double_str_fixed(double_str_t *val_str, int precision, int width,
706 uint32_t flags, printf_spec_t *ps)
707{
708 int len = val_str->len;
709 char *buf = val_str->str;
710 int dec_exp = val_str->dec_exp;
711
712 assert(0 < len);
713 assert(0 <= precision);
714 assert(0 <= dec_exp || -dec_exp <= precision);
715
716 /* Number of integral digits to print (at least leading zero). */
717 int int_len = max(1, len + dec_exp);
718
719 char sign = get_sign_char(val_str->neg, flags);
720
721 /* Fractional portion lengths. */
722 int last_frac_signif_pos = max(0, -dec_exp);
723 int leading_frac_zeros = max(0, last_frac_signif_pos - len);
724 int signif_frac_figs = min(last_frac_signif_pos, len);
725 int trailing_frac_zeros = precision - last_frac_signif_pos;
726 char *buf_frac = buf + len - signif_frac_figs;
727
728 if (flags & __PRINTF_FLAG_NOFRACZEROS) {
729 trailing_frac_zeros = 0;
730 }
731
732 int frac_len = leading_frac_zeros + signif_frac_figs + trailing_frac_zeros;
733
734 bool has_decimal_pt = (0 < frac_len) || (flags & __PRINTF_FLAG_DECIMALPT);
735
736 /* Number of non-padding chars to print. */
737 int num_len = (sign ? 1 : 0) + int_len + (has_decimal_pt ? 1 : 0) + frac_len;
738
739 int padding_len = max(0, width - num_len);
740 int ret = 0;
741 int counter = 0;
742
743 /* Leading padding and sign. */
744
745 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
746 if ((ret = print_padding(' ', padding_len, ps)) < 0)
747 return -1;
748
749 counter += ret;
750 }
751
752 if (sign) {
753 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
754 return -1;
755
756 counter += ret;
757 }
758
759 if (flags & __PRINTF_FLAG_ZEROPADDED) {
760 if ((ret = print_padding('0', padding_len, ps)) < 0)
761 return -1;
762
763 counter += ret;
764 }
765
766 /* Print the intergral part of the buffer. */
767
768 int buf_int_len = min(len, len + dec_exp);
769
770 if (0 < buf_int_len) {
771 if ((ret = ps->str_write(buf, buf_int_len, ps->data)) < 0)
772 return -1;
773
774 counter += ret;
775
776 /* Print trailing zeros of the integral part of the number. */
777 if ((ret = print_padding('0', int_len - buf_int_len, ps)) < 0)
778 return -1;
779 } else {
780 /* Single leading integer 0. */
781 char ch = '0';
782 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
783 return -1;
784 }
785
786 counter += ret;
787
788 /* Print the decimal point and the fractional part. */
789 if (has_decimal_pt) {
790 char ch = '.';
791
792 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
793 return -1;
794
795 counter += ret;
796
797 /* Print leading zeros of the fractional part of the number. */
798 if ((ret = print_padding('0', leading_frac_zeros, ps)) < 0)
799 return -1;
800
801 counter += ret;
802
803 /* Print significant digits of the fractional part of the number. */
804 if (0 < signif_frac_figs) {
805 if ((ret = ps->str_write(buf_frac, signif_frac_figs, ps->data)) < 0)
806 return -1;
807
808 counter += ret;
809 }
810
811 /* Print trailing zeros of the fractional part of the number. */
812 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
813 return -1;
814
815 counter += ret;
816 }
817
818 /* Trailing padding. */
819 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
820 if ((ret = print_padding(' ', padding_len, ps)) < 0)
821 return -1;
822
823 counter += ret;
824 }
825
826 return counter;
827}
828
829/** Convert, format and print a double according to the %f specifier.
830 *
831 * @param g Double to print.
832 * @param precision Number of fractional digits to print. If 0 no
833 * decimal point will be printed unless the flag
834 * __PRINTF_FLAG_DECIMALPT is specified.
835 * @param width Minimum number of characters to display. Pads
836 * with '0' or ' ' depending on the set flags;
837 * @param flags Printf flags.
838 * @param ps Printing functions.
839 *
840 * @return The number of characters printed; negative on failure.
841 */
842static int print_double_fixed(double g, int precision, int width, uint32_t flags,
843 printf_spec_t *ps)
844{
845 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
846 flags &= ~__PRINTF_FLAG_ZEROPADDED;
847 }
848
849 if (flags & __PRINTF_FLAG_DECIMALPT) {
850 flags &= ~__PRINTF_FLAG_NOFRACZEROS;
851 }
852
853 ieee_double_t val = extract_ieee_double(g);
854
855 if (val.is_special) {
856 return print_special(val, width, flags, ps);
857 }
858
859 char buf[MAX_DOUBLE_STR_BUF_SIZE];
860 const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
861 double_str_t val_str;
862
863 val_str.str = buf;
864 val_str.neg = val.is_negative;
865
866 if (0 <= precision) {
867 /*
868 * Request one more digit so we can round the result. The last
869 * digit it returns may have an error of at most +/- 1.
870 */
871 val_str.len = double_to_fixed_str(val, -1, precision + 1, buf, buf_size,
872 &val_str.dec_exp);
873
874 /*
875 * Round using the last digit to produce precision fractional digits.
876 * If less than precision+1 fractional digits were output the last
877 * digit is definitely inaccurate so also round to get rid of it.
878 */
879 fp_round_up(buf, &val_str.len, &val_str.dec_exp);
880
881 /* Rounding could have introduced trailing zeros. */
882 if (flags & __PRINTF_FLAG_NOFRACZEROS) {
883 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
884 }
885 } else {
886 /* Let the implementation figure out the proper precision. */
887 val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
888
889 /* Precision needed for the last significant digit. */
890 precision = max(0, -val_str.dec_exp);
891 }
892
893 return print_double_str_fixed(&val_str, precision, width, flags, ps);
894}
895
896/** Prints the decimal exponent part of a %e specifier formatted number. */
897static int print_exponent(int exp_val, uint32_t flags, printf_spec_t *ps)
898{
899 int counter = 0;
900 int ret;
901
902 char exp_ch = (flags & __PRINTF_FLAG_BIGCHARS) ? 'E' : 'e';
903
904 if ((ret = ps->str_write(&exp_ch, 1, ps->data)) < 0)
905 return -1;
906
907 counter += ret;
908
909 char exp_sign = (exp_val < 0) ? '-' : '+';
910
911 if ((ret = ps->str_write(&exp_sign, 1, ps->data)) < 0)
912 return -1;
913
914 counter += ret;
915
916 /* Print the exponent. */
917 exp_val = abs(exp_val);
918
919 char exp_str[4] = { 0 };
920
921 exp_str[0] = '0' + exp_val / 100;
922 exp_str[1] = '0' + (exp_val % 100) / 10;
923 exp_str[2] = '0' + (exp_val % 10);
924
925 int exp_len = (exp_str[0] == '0') ? 2 : 3;
926 const char *exp_str_start = &exp_str[3] - exp_len;
927
928 if ((ret = ps->str_write(exp_str_start, exp_len, ps->data)) < 0)
929 return -1;
930
931 counter += ret;
932
933 return counter;
934}
935
936/** Format and print the double string repressentation according
937 * to the %e specifier.
938 */
939static int print_double_str_scient(double_str_t *val_str, int precision,
940 int width, uint32_t flags, printf_spec_t *ps)
941{
942 int len = val_str->len;
943 int dec_exp = val_str->dec_exp;
944 char *buf = val_str->str;
945
946 assert(0 < len);
947
948 char sign = get_sign_char(val_str->neg, flags);
949 bool has_decimal_pt = (0 < precision) || (flags & __PRINTF_FLAG_DECIMALPT);
950 int dec_pt_len = has_decimal_pt ? 1 : 0;
951
952 /* Fractional part lengths. */
953 int signif_frac_figs = len - 1;
954 int trailing_frac_zeros = precision - signif_frac_figs;
955
956 if (flags & __PRINTF_FLAG_NOFRACZEROS) {
957 trailing_frac_zeros = 0;
958 }
959
960 int frac_len = signif_frac_figs + trailing_frac_zeros;
961
962 int exp_val = dec_exp + len - 1;
963 /* Account for exponent sign and 'e'; minimum 2 digits. */
964 int exp_len = 2 + (abs(exp_val) >= 100 ? 3 : 2);
965
966 /* Number of non-padding chars to print. */
967 int num_len = (sign ? 1 : 0) + 1 + dec_pt_len + frac_len + exp_len;
968
969 int padding_len = max(0, width - num_len);
970 int ret = 0;
971 int counter = 0;
972
973 if (!(flags & (__PRINTF_FLAG_LEFTALIGNED | __PRINTF_FLAG_ZEROPADDED))) {
974 if ((ret = print_padding(' ', padding_len, ps)) < 0)
975 return -1;
976
977 counter += ret;
978 }
979
980 if (sign) {
981 if ((ret = ps->str_write(&sign, 1, ps->data)) < 0)
982 return -1;
983
984 counter += ret;
985 }
986
987 if (flags & __PRINTF_FLAG_ZEROPADDED) {
988 if ((ret = print_padding('0', padding_len, ps)) < 0)
989 return -1;
990
991 counter += ret;
992 }
993
994 /* Single leading integer. */
995 if ((ret = ps->str_write(buf, 1, ps->data)) < 0)
996 return -1;
997
998 counter += ret;
999
1000 /* Print the decimal point and the fractional part. */
1001 if (has_decimal_pt) {
1002 char ch = '.';
1003
1004 if ((ret = ps->str_write(&ch, 1, ps->data)) < 0)
1005 return -1;
1006
1007 counter += ret;
1008
1009 /* Print significant digits of the fractional part of the number. */
1010 if (0 < signif_frac_figs) {
1011 if ((ret = ps->str_write(buf + 1, signif_frac_figs, ps->data)) < 0)
1012 return -1;
1013
1014 counter += ret;
1015 }
1016
1017 /* Print trailing zeros of the fractional part of the number. */
1018 if ((ret = print_padding('0', trailing_frac_zeros, ps)) < 0)
1019 return -1;
1020
1021 counter += ret;
1022 }
1023
1024 /* Print the exponent. */
1025 if ((ret = print_exponent(exp_val, flags, ps)) < 0)
1026 return -1;
1027
1028 counter += ret;
1029
1030 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
1031 if ((ret = print_padding(' ', padding_len, ps)) < 0)
1032 return -1;
1033
1034 counter += ret;
1035 }
1036
1037 return counter;
1038}
1039
1040/** Convert, format and print a double according to the %e specifier.
1041 *
1042 * Note that if g is large, the output may be huge (3e100 prints
1043 * with at least 100 digits).
1044 *
1045 * %e style: [-]d.dddde+dd
1046 * left-justified: [-]d.dddde+dd[space_pad]
1047 * right-justified: [space_pad][-][zero_pad]d.dddde+dd
1048 *
1049 * @param g Double to print.
1050 * @param precision Number of fractional digits to print, ie
1051 * precision + 1 significant digits to display. If 0 no
1052 * decimal point will be printed unless the flag
1053 * __PRINTF_FLAG_DECIMALPT is specified. If negative
1054 * the shortest accurate number will be printed.
1055 * @param width Minimum number of characters to display. Pads
1056 * with '0' or ' ' depending on the set flags;
1057 * @param flags Printf flags.
1058 * @param ps Printing functions.
1059 *
1060 * @return The number of characters printed; negative on failure.
1061 */
1062static int print_double_scientific(double g, int precision, int width,
1063 uint32_t flags, printf_spec_t *ps)
1064{
1065 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
1066 flags &= ~__PRINTF_FLAG_ZEROPADDED;
1067 }
1068
1069 ieee_double_t val = extract_ieee_double(g);
1070
1071 if (val.is_special) {
1072 return print_special(val, width, flags, ps);
1073 }
1074
1075 char buf[MAX_DOUBLE_STR_BUF_SIZE];
1076 const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
1077 double_str_t val_str;
1078
1079 val_str.str = buf;
1080 val_str.neg = val.is_negative;
1081
1082 if (0 <= precision) {
1083 /*
1084 * Request one more digit (in addition to the leading integer)
1085 * so we can round the result. The last digit it returns may
1086 * have an error of at most +/- 1.
1087 */
1088 val_str.len = double_to_fixed_str(val, precision + 2, -1, buf, buf_size,
1089 &val_str.dec_exp);
1090
1091 /*
1092 * Round the extra digit to produce precision+1 significant digits.
1093 * If less than precision+2 significant digits were returned the last
1094 * digit is definitely inaccurate so also round to get rid of it.
1095 */
1096 fp_round_up(buf, &val_str.len, &val_str.dec_exp);
1097
1098 /* Rounding could have introduced trailing zeros. */
1099 if (flags & __PRINTF_FLAG_NOFRACZEROS) {
1100 fp_trim_trailing_zeros(buf, &val_str.len, &val_str.dec_exp);
1101 }
1102 } else {
1103 /* Let the implementation figure out the proper precision. */
1104 val_str.len = double_to_short_str(val, buf, buf_size, &val_str.dec_exp);
1105
1106 /* Use all produced digits. */
1107 precision = val_str.len - 1;
1108 }
1109
1110 return print_double_str_scient(&val_str, precision, width, flags, ps);
1111}
1112
1113/** Convert, format and print a double according to the %g specifier.
1114 *
1115 * %g style chooses between %f and %e.
1116 *
1117 * @param g Double to print.
1118 * @param precision Number of significant digits to display; excluding
1119 * any leading zeros from this count. If negative
1120 * the shortest accurate number will be printed.
1121 * @param width Minimum number of characters to display. Pads
1122 * with '0' or ' ' depending on the set flags;
1123 * @param flags Printf flags.
1124 * @param ps Printing functions.
1125 *
1126 * @return The number of characters printed; negative on failure.
1127 */
1128static int print_double_generic(double g, int precision, int width,
1129 uint32_t flags, printf_spec_t *ps)
1130{
1131 ieee_double_t val = extract_ieee_double(g);
1132
1133 if (val.is_special) {
1134 return print_special(val, width, flags, ps);
1135 }
1136
1137 char buf[MAX_DOUBLE_STR_BUF_SIZE];
1138 const size_t buf_size = MAX_DOUBLE_STR_BUF_SIZE;
1139 int dec_exp;
1140 int len;
1141
1142 /* Honor the user requested number of significant digits. */
1143 if (0 <= precision) {
1144 /*
1145 * Do a quick and dirty conversion of a single digit to determine
1146 * the decimal exponent.
1147 */
1148 len = double_to_fixed_str(val, 1, -1, buf, buf_size, &dec_exp);
1149 assert(0 < len);
1150
1151 precision = max(1, precision);
1152
1153 if (-4 <= dec_exp && dec_exp < precision) {
1154 precision = precision - (dec_exp + 1);
1155 return print_double_fixed(g, precision, width,
1156 flags | __PRINTF_FLAG_NOFRACZEROS, ps);
1157 } else {
1158 --precision;
1159 return print_double_scientific(g, precision, width,
1160 flags | __PRINTF_FLAG_NOFRACZEROS, ps);
1161 }
1162 } else {
1163 /* Convert to get the decimal exponent and digit count. */
1164 len = double_to_short_str(val, buf, buf_size, &dec_exp);
1165 assert(0 < len);
1166
1167 if (flags & __PRINTF_FLAG_LEFTALIGNED) {
1168 flags &= ~__PRINTF_FLAG_ZEROPADDED;
1169 }
1170
1171 double_str_t val_str;
1172 val_str.str = buf;
1173 val_str.len = len;
1174 val_str.neg = val.is_negative;
1175 val_str.dec_exp = dec_exp;
1176
1177 int first_digit_pos = len + dec_exp;
1178 int last_digit_pos = dec_exp;
1179
1180 /* The whole number (15 digits max) fits between dec places 15 .. -6 */
1181 if (len <= 15 && -6 <= last_digit_pos && first_digit_pos <= 15) {
1182 /* Precision needed for the last significant digit. */
1183 precision = max(0, -val_str.dec_exp);
1184 return print_double_str_fixed(&val_str, precision, width, flags, ps);
1185 } else {
1186 /* Use all produced digits. */
1187 precision = val_str.len - 1;
1188 return print_double_str_scient(&val_str, precision, width, flags, ps);
1189 }
1190 }
1191}
1192
1193/** Convert, format and print a double according to the specifier.
1194 *
1195 * Depending on the specifier it prints the double using the styles
1196 * %g, %f or %e by means of print_double_generic(), print_double_fixed(),
1197 * print_double_scientific().
1198 *
1199 * @param g Double to print.
1200 * @param spec Specifier of the style to print in; one of: 'g','G','f','F',
1201 * 'e','E'.
1202 * @param precision Number of fractional digits to display. If negative
1203 * the shortest accurate number will be printed for style %g;
1204 * negative precision defaults to 6 for styles %f, %e.
1205 * @param width Minimum number of characters to display. Pads
1206 * with '0' or ' ' depending on the set flags;
1207 * @param flags Printf flags.
1208 * @param ps Printing functions.
1209 *
1210 * @return The number of characters printed; negative on failure.
1211 */
1212static int print_double(double g, char spec, int precision, int width,
1213 uint32_t flags, printf_spec_t *ps)
1214{
1215 switch (spec) {
1216 case 'F':
1217 flags |= __PRINTF_FLAG_BIGCHARS;
1218 /* Fallthrough */
1219 case 'f':
1220 precision = (precision < 0) ? 6 : precision;
1221 return print_double_fixed(g, precision, width, flags, ps);
1222
1223 case 'E':
1224 flags |= __PRINTF_FLAG_BIGCHARS;
1225 /* Fallthrough */
1226 case 'e':
1227 precision = (precision < 0) ? 6 : precision;
1228 return print_double_scientific(g, precision, width, flags, ps);
1229
1230 case 'G':
1231 flags |= __PRINTF_FLAG_BIGCHARS;
1232 /* Fallthrough */
1233 case 'g':
1234 return print_double_generic(g, precision, width, flags, ps);
1235
1236 default:
1237 assert(false);
1238 return -1;
1239 }
1240}
1241
1242#endif
1243
1244/** Print formatted string.
1245 *
1246 * Print string formatted according to the fmt parameter and variadic arguments.
1247 * Each formatting directive must have the following form:
1248 *
1249 * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
1250 *
1251 * FLAGS:@n
1252 * - "#" Force to print prefix. For \%o conversion, the prefix is 0, for
1253 * \%x and \%X prefixes are 0x and 0X and for conversion \%b the
1254 * prefix is 0b.
1255 *
1256 * - "-" Align to left.
1257 *
1258 * - "+" Print positive sign just as negative.
1259 *
1260 * - " " If the printed number is positive and "+" flag is not set,
1261 * print space in place of sign.
1262 *
1263 * - "0" Print 0 as padding instead of spaces. Zeroes are placed between
1264 * sign and the rest of the number. This flag is ignored if "-"
1265 * flag is specified.
1266 *
1267 * WIDTH:@n
1268 * - Specify the minimal width of a printed argument. If it is bigger,
1269 * width is ignored. If width is specified with a "*" character instead of
1270 * number, width is taken from parameter list. And integer parameter is
1271 * expected before parameter for processed conversion specification. If
1272 * this value is negative its absolute value is taken and the "-" flag is
1273 * set.
1274 *
1275 * PRECISION:@n
1276 * - Value precision. For numbers it specifies minimum valid numbers.
1277 * Smaller numbers are printed with leading zeroes. Bigger numbers are not
1278 * affected. Strings with more than precision characters are cut off. Just
1279 * as with width, an "*" can be used used instead of a number. An integer
1280 * value is then expected in parameters. When both width and precision are
1281 * specified using "*", the first parameter is used for width and the
1282 * second one for precision.
1283 *
1284 * TYPE:@n
1285 * - "hh" Signed or unsigned char.@n
1286 * - "h" Signed or unsigned short.@n
1287 * - "" Signed or unsigned int (default value).@n
1288 * - "l" Signed or unsigned long int.@n
1289 * If conversion is "c", the character is wint_t (wide character).@n
1290 * If conversion is "s", the string is char32_t * (wide string).@n
1291 * - "ll" Signed or unsigned long long int.@n
1292 * - "z" Signed or unsigned ssize_t or site_t.@n
1293 *
1294 * CONVERSION:@n
1295 * - % Print percentile character itself.
1296 *
1297 * - c Print single character. The character is expected to be plain
1298 * ASCII (e.g. only values 0 .. 127 are valid).@n
1299 * If type is "l", then the character is expected to be wide character
1300 * (e.g. values 0 .. 0x10ffff are valid).
1301 *
1302 * - s Print zero terminated string. If a NULL value is passed as
1303 * value, "(NULL)" is printed instead.@n
1304 * If type is "l", then the string is expected to be wide string.
1305 *
1306 * - P, p Print value of a pointer. Void * value is expected and it is
1307 * printed in hexadecimal notation with prefix (as with
1308 * \%#0.8X / \%#0.8x for 32-bit or \%#0.16lX / \%#0.16lx for 64-bit
1309 * long pointers).
1310 *
1311 * - b Print value as unsigned binary number. Prefix is not printed by
1312 * default. (Nonstandard extension.)
1313 *
1314 * - o Print value as unsigned octal number. Prefix is not printed by
1315 * default.
1316 *
1317 * - d, i Print signed decimal number. There is no difference between d
1318 * and i conversion.
1319 *
1320 * - u Print unsigned decimal number.
1321 *
1322 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
1323 * not printed by default.
1324 *
1325 * All other characters from fmt except the formatting directives are printed
1326 * verbatim.
1327 *
1328 * @param fmt Format NULL-terminated string.
1329 *
1330 * @return Number of characters printed, negative value on failure.
1331 *
1332 */
1333int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
1334{
1335 size_t i; /* Index of the currently processed character from fmt */
1336 size_t nxt = 0; /* Index of the next character from fmt */
1337 size_t j = 0; /* Index to the first not printed nonformating character */
1338
1339 size_t counter = 0; /* Number of characters printed */
1340 int retval; /* Return values from nested functions */
1341
1342 while (true) {
1343 i = nxt;
1344 char32_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1345
1346 if (uc == 0)
1347 break;
1348
1349 /* Control character */
1350 if (uc == '%') {
1351 /* Print common characters if any processed */
1352 if (i > j) {
1353 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
1354 /* Error */
1355 counter = -counter;
1356 goto out;
1357 }
1358 counter += retval;
1359 }
1360
1361 j = i;
1362
1363 /* Parse modifiers */
1364 uint32_t flags = 0;
1365 bool end = false;
1366
1367 do {
1368 i = nxt;
1369 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1370 switch (uc) {
1371 case '#':
1372 flags |= __PRINTF_FLAG_PREFIX;
1373 flags |= __PRINTF_FLAG_DECIMALPT;
1374 break;
1375 case '-':
1376 flags |= __PRINTF_FLAG_LEFTALIGNED;
1377 break;
1378 case '+':
1379 flags |= __PRINTF_FLAG_SHOWPLUS;
1380 break;
1381 case ' ':
1382 flags |= __PRINTF_FLAG_SPACESIGN;
1383 break;
1384 case '0':
1385 flags |= __PRINTF_FLAG_ZEROPADDED;
1386 break;
1387 default:
1388 end = true;
1389 }
1390 } while (!end);
1391
1392 /* Width & '*' operator */
1393 int width = 0;
1394 if (isdigit(uc)) {
1395 while (true) {
1396 width *= 10;
1397 width += uc - '0';
1398
1399 i = nxt;
1400 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1401 if (uc == 0)
1402 break;
1403 if (!isdigit(uc))
1404 break;
1405 }
1406 } else if (uc == '*') {
1407 /* Get width value from argument list */
1408 i = nxt;
1409 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1410 width = (int) va_arg(ap, int);
1411 if (width < 0) {
1412 /* Negative width sets '-' flag */
1413 width *= -1;
1414 flags |= __PRINTF_FLAG_LEFTALIGNED;
1415 }
1416 }
1417
1418 /* Precision and '*' operator */
1419 int precision = -1;
1420 if (uc == '.') {
1421 i = nxt;
1422 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1423 if (isdigit(uc)) {
1424 precision = 0;
1425 while (true) {
1426 precision *= 10;
1427 precision += uc - '0';
1428
1429 i = nxt;
1430 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1431 if (uc == 0)
1432 break;
1433 if (!isdigit(uc))
1434 break;
1435 }
1436 } else if (uc == '*') {
1437 /* Get precision value from the argument list */
1438 i = nxt;
1439 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1440 precision = (int) va_arg(ap, int);
1441 if (precision < 0) {
1442 /* Ignore negative precision - use default instead */
1443 precision = -1;
1444 }
1445 }
1446 }
1447
1448 qualifier_t qualifier;
1449
1450 switch (uc) {
1451 case 't':
1452 /* ptrdiff_t */
1453 if (sizeof(ptrdiff_t) == sizeof(int32_t))
1454 qualifier = PrintfQualifierInt;
1455 else
1456 qualifier = PrintfQualifierLongLong;
1457 i = nxt;
1458 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1459 break;
1460 case 'h':
1461 /* Char or short */
1462 qualifier = PrintfQualifierShort;
1463 i = nxt;
1464 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1465 if (uc == 'h') {
1466 i = nxt;
1467 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1468 qualifier = PrintfQualifierByte;
1469 }
1470 break;
1471 case 'l':
1472 /* Long or long long */
1473 qualifier = PrintfQualifierLong;
1474 i = nxt;
1475 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1476 if (uc == 'l') {
1477 i = nxt;
1478 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1479 qualifier = PrintfQualifierLongLong;
1480 }
1481 break;
1482 case 'z':
1483 qualifier = PrintfQualifierSize;
1484 i = nxt;
1485 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1486 break;
1487 case 'j':
1488 qualifier = PrintfQualifierMax;
1489 i = nxt;
1490 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
1491 break;
1492 default:
1493 /* Default type */
1494 qualifier = PrintfQualifierInt;
1495 }
1496
1497 unsigned int base = 10;
1498
1499 switch (uc) {
1500 /*
1501 * String and character conversions.
1502 */
1503 case 's':
1504 precision = max(0, precision);
1505
1506 if (qualifier == PrintfQualifierLong)
1507 retval = print_wstr(va_arg(ap, char32_t *), width, precision, flags, ps);
1508 else
1509 retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
1510
1511 if (retval < 0) {
1512 counter = -counter;
1513 goto out;
1514 }
1515
1516 counter += retval;
1517 j = nxt;
1518 continue;
1519 case 'c':
1520 if (qualifier == PrintfQualifierLong)
1521 retval = print_wchar(va_arg(ap, wint_t), width, flags, ps);
1522 else
1523 retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
1524
1525 if (retval < 0) {
1526 counter = -counter;
1527 goto out;
1528 }
1529
1530 counter += retval;
1531 j = nxt;
1532 continue;
1533
1534#ifdef HAS_FLOAT
1535 /*
1536 * Floating point values
1537 */
1538 case 'G':
1539 case 'g':
1540 case 'F':
1541 case 'f':
1542 case 'E':
1543 case 'e':
1544 retval = print_double(va_arg(ap, double), uc, precision,
1545 width, flags, ps);
1546
1547 if (retval < 0) {
1548 counter = -counter;
1549 goto out;
1550 }
1551
1552 counter += retval;
1553 j = nxt;
1554 continue;
1555#endif
1556
1557 /*
1558 * Integer values
1559 */
1560 case 'P':
1561 /* Pointer */
1562 flags |= __PRINTF_FLAG_BIGCHARS;
1563 /* Fallthrough */
1564 case 'p':
1565 flags |= __PRINTF_FLAG_PREFIX;
1566 flags |= __PRINTF_FLAG_ZEROPADDED;
1567 base = 16;
1568 qualifier = PrintfQualifierPointer;
1569 break;
1570 case 'b':
1571 base = 2;
1572 break;
1573 case 'o':
1574 base = 8;
1575 break;
1576 case 'd':
1577 case 'i':
1578 flags |= __PRINTF_FLAG_SIGNED;
1579 /* Fallthrough */
1580 case 'u':
1581 break;
1582 case 'X':
1583 flags |= __PRINTF_FLAG_BIGCHARS;
1584 /* Fallthrough */
1585 case 'x':
1586 base = 16;
1587 break;
1588
1589 case '%':
1590 /* Percentile itself */
1591 j = i;
1592 continue;
1593
1594 /*
1595 * Bad formatting.
1596 */
1597 default:
1598 /*
1599 * Unknown format. Now, j is the index of '%'
1600 * so we will print whole bad format sequence.
1601 */
1602 continue;
1603 }
1604
1605 /* Print integers */
1606 size_t size;
1607 uint64_t number;
1608
1609 switch (qualifier) {
1610 case PrintfQualifierByte:
1611 size = sizeof(unsigned char);
1612 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
1613 break;
1614 case PrintfQualifierShort:
1615 size = sizeof(unsigned short);
1616 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
1617 break;
1618 case PrintfQualifierInt:
1619 size = sizeof(unsigned int);
1620 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
1621 break;
1622 case PrintfQualifierLong:
1623 size = sizeof(unsigned long);
1624 number = PRINTF_GET_INT_ARGUMENT(long, ap, flags);
1625 break;
1626 case PrintfQualifierLongLong:
1627 size = sizeof(unsigned long long);
1628 number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags);
1629 break;
1630 case PrintfQualifierPointer:
1631 size = sizeof(void *);
1632 precision = size << 1;
1633 number = (uint64_t) (uintptr_t) va_arg(ap, void *);
1634 break;
1635 case PrintfQualifierSize:
1636 size = sizeof(size_t);
1637 number = (uint64_t) va_arg(ap, size_t);
1638 break;
1639 case PrintfQualifierMax:
1640 size = sizeof(uintmax_t);
1641 number = (uint64_t) va_arg(ap, uintmax_t);
1642 break;
1643 default:
1644 /* Unknown qualifier */
1645 counter = -counter;
1646 goto out;
1647 }
1648
1649 if ((retval = print_number(number, width, precision,
1650 base, flags, ps)) < 0) {
1651 counter = -counter;
1652 goto out;
1653 }
1654
1655 counter += retval;
1656 j = nxt;
1657 }
1658 }
1659
1660 if (i > j) {
1661 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
1662 /* Error */
1663 counter = -counter;
1664 goto out;
1665 }
1666 counter += retval;
1667 }
1668
1669out:
1670 return ((int) counter);
1671}
1672
1673/** @}
1674 */
Note: See TracBrowser for help on using the repository browser.