source: mainline/kernel/generic/src/printf/printf_core.c@ 8800b13

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8800b13 was af60409, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Modify PADDn macros so that their use is easier to parse.

  • Property mode set to 100644
File size: 22.6 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 generic
32 * @{
33 */
34/**
35 * @file
36 * @brief Printing functions.
37 */
38
39#include <printf/printf_core.h>
40#include <print.h>
41#include <stdarg.h>
42#include <macros.h>
43#include <stddef.h>
44#include <str.h>
45#include <arch.h>
46
47/** show prefixes 0x or 0 */
48#define __PRINTF_FLAG_PREFIX 0x00000001
49
50/** signed / unsigned number */
51#define __PRINTF_FLAG_SIGNED 0x00000002
52
53/** print leading zeroes */
54#define __PRINTF_FLAG_ZEROPADDED 0x00000004
55
56/** align to left */
57#define __PRINTF_FLAG_LEFTALIGNED 0x00000010
58
59/** always show + sign */
60#define __PRINTF_FLAG_SHOWPLUS 0x00000020
61
62/** print space instead of plus */
63#define __PRINTF_FLAG_SPACESIGN 0x00000040
64
65/** show big characters */
66#define __PRINTF_FLAG_BIGCHARS 0x00000080
67
68/** number has - sign */
69#define __PRINTF_FLAG_NEGATIVE 0x00000100
70
71/**
72 * Buffer big enough for 64-bit number printed in base 2, sign, prefix and 0
73 * to terminate string... (last one is only for better testing end of buffer by
74 * zero-filling subroutine)
75 */
76#define PRINT_NUMBER_BUFFER_SIZE (64 + 5)
77
78/** Get signed or unsigned integer argument */
79#define PRINTF_GET_INT_ARGUMENT(type, ap, flags) \
80 ({ \
81 unsigned type res; \
82 \
83 if ((flags) & __PRINTF_FLAG_SIGNED) { \
84 signed type arg = va_arg((ap), signed type); \
85 \
86 if (arg < 0) { \
87 res = -arg; \
88 (flags) |= __PRINTF_FLAG_NEGATIVE; \
89 } else \
90 res = arg; \
91 } else \
92 res = va_arg((ap), unsigned type); \
93 \
94 res; \
95 })
96
97/** Enumeration of possible arguments types.
98 */
99typedef enum {
100 PrintfQualifierByte = 0,
101 PrintfQualifierShort,
102 PrintfQualifierInt,
103 PrintfQualifierLong,
104 PrintfQualifierLongLong,
105 PrintfQualifierPointer,
106 PrintfQualifierSize,
107 PrintfQualifierMax
108} qualifier_t;
109
110static const char *nullstr = "(NULL)";
111static const char *digits_small = "0123456789abcdef";
112static const char *digits_big = "0123456789ABCDEF";
113static const char invalch = U_SPECIAL;
114
115/** Print one or more characters without adding newline.
116 *
117 * @param buf Buffer holding characters with size of
118 * at least size bytes. NULL is not allowed!
119 * @param size Size of the buffer in bytes.
120 * @param ps Output method and its data.
121 *
122 * @return Number of characters printed.
123 *
124 */
125static int printf_putnchars(const char *buf, size_t size,
126 printf_spec_t *ps)
127{
128 return ps->str_write((void *) buf, size, ps->data);
129}
130
131/** Print one or more wide characters without adding newline.
132 *
133 * @param buf Buffer holding wide characters with size of
134 * at least size bytes. NULL is not allowed!
135 * @param size Size of the buffer in bytes.
136 * @param ps Output method and its data.
137 *
138 * @return Number of wide characters printed.
139 *
140 */
141static int printf_wputnchars(const wchar_t *buf, size_t size,
142 printf_spec_t *ps)
143{
144 return ps->wstr_write((void *) buf, size, ps->data);
145}
146
147/** Print string without adding a newline.
148 *
149 * @param str String to print.
150 * @param ps Write function specification and support data.
151 *
152 * @return Number of characters printed.
153 *
154 */
155static int printf_putstr(const char *str, printf_spec_t *ps)
156{
157 if (str == NULL)
158 return printf_putnchars(nullstr, str_size(nullstr), ps);
159
160 return ps->str_write((void *) str, str_size(str), ps->data);
161}
162
163/** Print one ASCII character.
164 *
165 * @param c ASCII character to be printed.
166 * @param ps Output method.
167 *
168 * @return Number of characters printed.
169 *
170 */
171static int printf_putchar(const char ch, printf_spec_t *ps)
172{
173 if (!ascii_check(ch))
174 return ps->str_write((void *) &invalch, 1, ps->data);
175
176 return ps->str_write(&ch, 1, ps->data);
177}
178
179/** Print one wide character.
180 *
181 * @param c Wide character to be printed.
182 * @param ps Output method.
183 *
184 * @return Number of characters printed.
185 *
186 */
187static int printf_putwchar(const wchar_t ch, printf_spec_t *ps)
188{
189 if (!chr_check(ch))
190 return ps->str_write((void *) &invalch, 1, ps->data);
191
192 return ps->wstr_write(&ch, sizeof(wchar_t), ps->data);
193}
194
195/** Print one formatted ASCII character.
196 *
197 * @param ch Character to print.
198 * @param width Width modifier.
199 * @param flags Flags that change the way the character is printed.
200 *
201 * @return Number of characters printed, negative value on failure.
202 *
203 */
204static int print_char(const char ch, int width, uint32_t flags, printf_spec_t *ps)
205{
206 size_t counter = 0;
207 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
208 while (--width > 0) {
209 /*
210 * One space is consumed by the character itself, hence
211 * the predecrement.
212 */
213 if (printf_putchar(' ', ps) > 0)
214 counter++;
215 }
216 }
217
218 if (printf_putchar(ch, ps) > 0)
219 counter++;
220
221 while (--width > 0) {
222 /*
223 * One space is consumed by the character itself, hence
224 * the predecrement.
225 */
226 if (printf_putchar(' ', ps) > 0)
227 counter++;
228 }
229
230 return (int) (counter);
231}
232
233/** Print one formatted wide character.
234 *
235 * @param ch Character to print.
236 * @param width Width modifier.
237 * @param flags Flags that change the way the character is printed.
238 *
239 * @return Number of characters printed, negative value on failure.
240 *
241 */
242static int print_wchar(const wchar_t ch, int width, uint32_t flags, printf_spec_t *ps)
243{
244 size_t counter = 0;
245 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
246 while (--width > 0) {
247 /*
248 * One space is consumed by the character itself, hence
249 * the predecrement.
250 */
251 if (printf_putchar(' ', ps) > 0)
252 counter++;
253 }
254 }
255
256 if (printf_putwchar(ch, ps) > 0)
257 counter++;
258
259 while (--width > 0) {
260 /*
261 * One space is consumed by the character itself, hence
262 * the predecrement.
263 */
264 if (printf_putchar(' ', ps) > 0)
265 counter++;
266 }
267
268 return (int) (counter);
269}
270
271/** Print string.
272 *
273 * @param str String to be printed.
274 * @param width Width modifier.
275 * @param precision Precision modifier.
276 * @param flags Flags that modify the way the string is printed.
277 *
278 * @return Number of characters printed, negative value on failure.
279 */
280static int print_str(char *str, int width, unsigned int precision,
281 uint32_t flags, printf_spec_t *ps)
282{
283 if (str == NULL)
284 return printf_putstr(nullstr, ps);
285
286 /* Print leading spaces. */
287 size_t strw = str_length(str);
288 if ((precision == 0) || (precision > strw))
289 precision = strw;
290
291 /* Left padding */
292 size_t counter = 0;
293 width -= precision;
294 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
295 while (width-- > 0) {
296 if (printf_putchar(' ', ps) == 1)
297 counter++;
298 }
299 }
300
301 /* Part of @a str fitting into the alloted space. */
302 int retval;
303 size_t size = str_lsize(str, precision);
304 if ((retval = printf_putnchars(str, size, ps)) < 0)
305 return -counter;
306
307 counter += retval;
308
309 /* Right padding */
310 while (width-- > 0) {
311 if (printf_putchar(' ', ps) == 1)
312 counter++;
313 }
314
315 return ((int) counter);
316
317}
318
319/** Print wide string.
320 *
321 * @param str Wide string to be printed.
322 * @param width Width modifier.
323 * @param precision Precision modifier.
324 * @param flags Flags that modify the way the string is printed.
325 *
326 * @return Number of wide characters printed, negative value on failure.
327 */
328static int print_wstr(wchar_t *str, int width, unsigned int precision,
329 uint32_t flags, printf_spec_t *ps)
330{
331 if (str == NULL)
332 return printf_putstr(nullstr, ps);
333
334 /* Print leading spaces. */
335 size_t strw = wstr_length(str);
336 if ((precision == 0) || (precision > strw))
337 precision = strw;
338
339 /* Left padding */
340 size_t counter = 0;
341 width -= precision;
342 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
343 while (width-- > 0) {
344 if (printf_putchar(' ', ps) == 1)
345 counter++;
346 }
347 }
348
349 /* Part of @a wstr fitting into the alloted space. */
350 int retval;
351 size_t size = wstr_lsize(str, precision);
352 if ((retval = printf_wputnchars(str, size, ps)) < 0)
353 return -counter;
354
355 counter += retval;
356
357 /* Right padding */
358 while (width-- > 0) {
359 if (printf_putchar(' ', ps) == 1)
360 counter++;
361 }
362
363 return ((int) counter);
364}
365
366/** Print a number in a given base.
367 *
368 * Print significant digits of a number in given base.
369 *
370 * @param num Number to print.
371 * @param width Width modifier.
372 * @param precision Precision modifier.
373 * @param base Base to print the number in (must be between 2 and 16).
374 * @param flags Flags that modify the way the number is printed.
375 *
376 * @return Number of characters printed.
377 *
378 */
379static int print_number(uint64_t num, int width, int precision, int base,
380 uint32_t flags, printf_spec_t *ps)
381{
382 const char *digits;
383 if (flags & __PRINTF_FLAG_BIGCHARS)
384 digits = digits_big;
385 else
386 digits = digits_small;
387
388 char data[PRINT_NUMBER_BUFFER_SIZE];
389 char *ptr = &data[PRINT_NUMBER_BUFFER_SIZE - 1];
390
391 /* Size of number with all prefixes and signs */
392 int size = 0;
393
394 /* Put zero at end of string */
395 *ptr-- = 0;
396
397 if (num == 0) {
398 *ptr-- = '0';
399 size++;
400 } else {
401 do {
402 *ptr-- = digits[num % base];
403 size++;
404 } while (num /= base);
405 }
406
407 /* Size of plain number */
408 int number_size = size;
409
410 /*
411 * Collect the sum of all prefixes/signs/etc. to calculate padding and
412 * leading zeroes.
413 */
414 if (flags & __PRINTF_FLAG_PREFIX) {
415 switch (base) {
416 case 2:
417 /* Binary formating is not standard, but usefull */
418 size += 2;
419 break;
420 case 8:
421 size++;
422 break;
423 case 16:
424 size += 2;
425 break;
426 }
427 }
428
429 char sgn = 0;
430 if (flags & __PRINTF_FLAG_SIGNED) {
431 if (flags & __PRINTF_FLAG_NEGATIVE) {
432 sgn = '-';
433 size++;
434 } else if (flags & __PRINTF_FLAG_SHOWPLUS) {
435 sgn = '+';
436 size++;
437 } else if (flags & __PRINTF_FLAG_SPACESIGN) {
438 sgn = ' ';
439 size++;
440 }
441 }
442
443 if (flags & __PRINTF_FLAG_LEFTALIGNED)
444 flags &= ~__PRINTF_FLAG_ZEROPADDED;
445
446 /*
447 * If the number is left-aligned or precision is specified then
448 * padding with zeros is ignored.
449 */
450 if (flags & __PRINTF_FLAG_ZEROPADDED) {
451 if ((precision == 0) && (width > size))
452 precision = width - size + number_size;
453 }
454
455 /* Print leading spaces */
456 if (number_size > precision) {
457 /* Print the whole number, not only a part */
458 precision = number_size;
459 }
460
461 width -= precision + size - number_size;
462 size_t counter = 0;
463
464 if (!(flags & __PRINTF_FLAG_LEFTALIGNED)) {
465 while (width-- > 0) {
466 if (printf_putchar(' ', ps) == 1)
467 counter++;
468 }
469 }
470
471 /* Print sign */
472 if (sgn) {
473 if (printf_putchar(sgn, ps) == 1)
474 counter++;
475 }
476
477 /* Print prefix */
478 if (flags & __PRINTF_FLAG_PREFIX) {
479 switch (base) {
480 case 2:
481 /* Binary formating is not standard, but usefull */
482 if (printf_putchar('0', ps) == 1)
483 counter++;
484 if (flags & __PRINTF_FLAG_BIGCHARS) {
485 if (printf_putchar('B', ps) == 1)
486 counter++;
487 } else {
488 if (printf_putchar('b', ps) == 1)
489 counter++;
490 }
491 break;
492 case 8:
493 if (printf_putchar('o', ps) == 1)
494 counter++;
495 break;
496 case 16:
497 if (printf_putchar('0', ps) == 1)
498 counter++;
499 if (flags & __PRINTF_FLAG_BIGCHARS) {
500 if (printf_putchar('X', ps) == 1)
501 counter++;
502 } else {
503 if (printf_putchar('x', ps) == 1)
504 counter++;
505 }
506 break;
507 }
508 }
509
510 /* Print leading zeroes */
511 precision -= number_size;
512 while (precision-- > 0) {
513 if (printf_putchar('0', ps) == 1)
514 counter++;
515 }
516
517 /* Print the number itself */
518 int retval;
519 if ((retval = printf_putstr(++ptr, ps)) > 0)
520 counter += retval;
521
522 /* Print trailing spaces */
523
524 while (width-- > 0) {
525 if (printf_putchar(' ', ps) == 1)
526 counter++;
527 }
528
529 return ((int) counter);
530}
531
532/** Print formatted string.
533 *
534 * Print string formatted according to the fmt parameter and variadic arguments.
535 * Each formatting directive must have the following form:
536 *
537 * \% [ FLAGS ] [ WIDTH ] [ .PRECISION ] [ TYPE ] CONVERSION
538 *
539 * FLAGS:@n
540 * - "#" Force to print prefix. For \%o conversion, the prefix is 0, for
541 * \%x and \%X prefixes are 0x and 0X and for conversion \%b the
542 * prefix is 0b.
543 *
544 * - "-" Align to left.
545 *
546 * - "+" Print positive sign just as negative.
547 *
548 * - " " If the printed number is positive and "+" flag is not set,
549 * print space in place of sign.
550 *
551 * - "0" Print 0 as padding instead of spaces. Zeroes are placed between
552 * sign and the rest of the number. This flag is ignored if "-"
553 * flag is specified.
554 *
555 * WIDTH:@n
556 * - Specify the minimal width of a printed argument. If it is bigger,
557 * width is ignored. If width is specified with a "*" character instead of
558 * number, width is taken from parameter list. And integer parameter is
559 * expected before parameter for processed conversion specification. If
560 * this value is negative its absolute value is taken and the "-" flag is
561 * set.
562 *
563 * PRECISION:@n
564 * - Value precision. For numbers it specifies minimum valid numbers.
565 * Smaller numbers are printed with leading zeroes. Bigger numbers are not
566 * affected. Strings with more than precision characters are cut off. Just
567 * as with width, an "*" can be used used instead of a number. An integer
568 * value is then expected in parameters. When both width and precision are
569 * specified using "*", the first parameter is used for width and the
570 * second one for precision.
571 *
572 * TYPE:@n
573 * - "hh" Signed or unsigned char.@n
574 * - "h" Signed or unsigned short.@n
575 * - "" Signed or unsigned int (default value).@n
576 * - "l" Signed or unsigned long int.@n
577 * If conversion is "c", the character is wint_t (wide character).@n
578 * If conversion is "s", the string is wchar_t * (wide string).@n
579 * - "ll" Signed or unsigned long long int.@n
580 * - "z" Signed or unsigned ssize_t or site_t.@n
581 *
582 * CONVERSION:@n
583 * - % Print percentile character itself.
584 *
585 * - c Print single character. The character is expected to be plain
586 * ASCII (e.g. only values 0 .. 127 are valid).@n
587 * If type is "l", then the character is expected to be wide character
588 * (e.g. values 0 .. 0x10ffff are valid).
589 *
590 * - s Print zero terminated string. If a NULL value is passed as
591 * value, "(NULL)" is printed instead.@n
592 * If type is "l", then the string is expected to be wide string.
593 *
594 * - P, p Print value of a pointer. Void * value is expected and it is
595 * printed in hexadecimal notation with prefix (as with
596 * \%#0.8X / \%#0.8x for 32-bit or \%#0.16lX / \%#0.16lx for 64-bit
597 * long pointers).
598 *
599 * - b Print value as unsigned binary number. Prefix is not printed by
600 * default. (Nonstandard extension.)
601 *
602 * - o Print value as unsigned octal number. Prefix is not printed by
603 * default.
604 *
605 * - d, i Print signed decimal number. There is no difference between d
606 * and i conversion.
607 *
608 * - u Print unsigned decimal number.
609 *
610 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
611 * not printed by default.
612 *
613 * All other characters from fmt except the formatting directives are printed
614 * verbatim.
615 *
616 * @param fmt Format NULL-terminated string.
617 *
618 * @return Number of characters printed, negative value on failure.
619 *
620 */
621int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
622{
623 size_t i; /* Index of the currently processed character from fmt */
624 size_t nxt = 0; /* Index of the next character from fmt */
625 size_t j = 0; /* Index to the first not printed nonformating character */
626
627 size_t counter = 0; /* Number of characters printed */
628 int retval; /* Return values from nested functions */
629
630 while (true) {
631 i = nxt;
632 wchar_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
633
634 if (uc == 0)
635 break;
636
637 /* Control character */
638 if (uc == '%') {
639 /* Print common characters if any processed */
640 if (i > j) {
641 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
642 /* Error */
643 counter = -counter;
644 goto out;
645 }
646 counter += retval;
647 }
648
649 j = i;
650
651 /* Parse modifiers */
652 uint32_t flags = 0;
653 bool end = false;
654
655 do {
656 i = nxt;
657 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
658 switch (uc) {
659 case '#':
660 flags |= __PRINTF_FLAG_PREFIX;
661 break;
662 case '-':
663 flags |= __PRINTF_FLAG_LEFTALIGNED;
664 break;
665 case '+':
666 flags |= __PRINTF_FLAG_SHOWPLUS;
667 break;
668 case ' ':
669 flags |= __PRINTF_FLAG_SPACESIGN;
670 break;
671 case '0':
672 flags |= __PRINTF_FLAG_ZEROPADDED;
673 break;
674 default:
675 end = true;
676 }
677 } while (!end);
678
679 /* Width & '*' operator */
680 int width = 0;
681 if (isdigit(uc)) {
682 while (true) {
683 width *= 10;
684 width += uc - '0';
685
686 i = nxt;
687 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
688 if (uc == 0)
689 break;
690 if (!isdigit(uc))
691 break;
692 }
693 } else if (uc == '*') {
694 /* Get width value from argument list */
695 i = nxt;
696 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
697 width = (int) va_arg(ap, int);
698 if (width < 0) {
699 /* Negative width sets '-' flag */
700 width *= -1;
701 flags |= __PRINTF_FLAG_LEFTALIGNED;
702 }
703 }
704
705 /* Precision and '*' operator */
706 int precision = 0;
707 if (uc == '.') {
708 i = nxt;
709 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
710 if (isdigit(uc)) {
711 while (true) {
712 precision *= 10;
713 precision += uc - '0';
714
715 i = nxt;
716 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
717 if (uc == 0)
718 break;
719 if (!isdigit(uc))
720 break;
721 }
722 } else if (uc == '*') {
723 /* Get precision value from the argument list */
724 i = nxt;
725 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
726 precision = (int) va_arg(ap, int);
727 if (precision < 0) {
728 /* Ignore negative precision */
729 precision = 0;
730 }
731 }
732 }
733
734 qualifier_t qualifier;
735
736 switch (uc) {
737 case 't':
738 /* ptrdiff_t */
739 if (sizeof(ptrdiff_t) == sizeof(int32_t))
740 qualifier = PrintfQualifierInt;
741 else
742 qualifier = PrintfQualifierLongLong;
743 i = nxt;
744 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
745 break;
746 case 'h':
747 /* Char or short */
748 qualifier = PrintfQualifierShort;
749 i = nxt;
750 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
751 if (uc == 'h') {
752 i = nxt;
753 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
754 qualifier = PrintfQualifierByte;
755 }
756 break;
757 case 'l':
758 /* Long or long long */
759 qualifier = PrintfQualifierLong;
760 i = nxt;
761 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
762 if (uc == 'l') {
763 i = nxt;
764 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
765 qualifier = PrintfQualifierLongLong;
766 }
767 break;
768 case 'z':
769 qualifier = PrintfQualifierSize;
770 i = nxt;
771 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
772 break;
773 case 'j':
774 qualifier = PrintfQualifierMax;
775 i = nxt;
776 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
777 break;
778 default:
779 /* Default type */
780 qualifier = PrintfQualifierInt;
781 }
782
783 unsigned int base = 10;
784
785 switch (uc) {
786 /*
787 * String and character conversions.
788 */
789 case 's':
790 if (qualifier == PrintfQualifierLong)
791 retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
792 else
793 retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
794
795 if (retval < 0) {
796 counter = -counter;
797 goto out;
798 }
799
800 counter += retval;
801 j = nxt;
802 continue;
803 case 'c':
804 if (qualifier == PrintfQualifierLong)
805 retval = print_wchar(va_arg(ap, wint_t), width, flags, ps);
806 else
807 retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
808
809 if (retval < 0) {
810 counter = -counter;
811 goto out;
812 }
813
814 counter += retval;
815 j = nxt;
816 continue;
817
818 /*
819 * Integer values
820 */
821 case 'P':
822 /* Pointer */
823 flags |= __PRINTF_FLAG_BIGCHARS;
824 /* Fallthrough */
825 case 'p':
826 flags |= __PRINTF_FLAG_PREFIX;
827 flags |= __PRINTF_FLAG_ZEROPADDED;
828 base = 16;
829 qualifier = PrintfQualifierPointer;
830 break;
831 case 'b':
832 base = 2;
833 break;
834 case 'o':
835 base = 8;
836 break;
837 case 'd':
838 case 'i':
839 flags |= __PRINTF_FLAG_SIGNED;
840 /* Fallthrough */
841 case 'u':
842 break;
843 case 'X':
844 flags |= __PRINTF_FLAG_BIGCHARS;
845 /* Fallthrough */
846 case 'x':
847 base = 16;
848 break;
849
850 /* Percentile itself */
851 case '%':
852 j = i;
853 continue;
854
855 /*
856 * Bad formatting.
857 */
858 default:
859 /*
860 * Unknown format. Now, j is the index of '%'
861 * so we will print whole bad format sequence.
862 */
863 continue;
864 }
865
866 /* Print integers */
867 size_t size;
868 uint64_t number;
869
870 switch (qualifier) {
871 case PrintfQualifierByte:
872 size = sizeof(unsigned char);
873 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
874 break;
875 case PrintfQualifierShort:
876 size = sizeof(unsigned short);
877 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
878 break;
879 case PrintfQualifierInt:
880 size = sizeof(unsigned int);
881 number = PRINTF_GET_INT_ARGUMENT(int, ap, flags);
882 break;
883 case PrintfQualifierLong:
884 size = sizeof(unsigned long);
885 number = PRINTF_GET_INT_ARGUMENT(long, ap, flags);
886 break;
887 case PrintfQualifierLongLong:
888 size = sizeof(unsigned long long);
889 number = PRINTF_GET_INT_ARGUMENT(long long, ap, flags);
890 break;
891 case PrintfQualifierPointer:
892 size = sizeof(void *);
893 precision = size << 1;
894 number = (uint64_t) (uintptr_t) va_arg(ap, void *);
895 break;
896 case PrintfQualifierSize:
897 size = sizeof(size_t);
898 number = (uint64_t) va_arg(ap, size_t);
899 break;
900 case PrintfQualifierMax:
901 size = sizeof(uintmax_t);
902 number = (uint64_t) va_arg(ap, uintmax_t);
903 break;
904 default:
905 /* Unknown qualifier */
906 counter = -counter;
907 goto out;
908 }
909
910 if ((retval = print_number(number, width, precision,
911 base, flags, ps)) < 0) {
912 counter = -counter;
913 goto out;
914 }
915
916 counter += retval;
917 j = nxt;
918 }
919 }
920
921 if (i > j) {
922 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
923 /* Error */
924 counter = -counter;
925 goto out;
926 }
927 counter += retval;
928 }
929
930out:
931 return ((int) counter);
932}
933
934/** @}
935 */
Note: See TracBrowser for help on using the repository browser.