source: mainline/kernel/generic/src/printf/printf_core.c@ 525c5ac

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 525c5ac was dc12262, checked in by Martin Decky <martin@…>, 8 years ago

add standardized case fallthrough comment annotations, add actual missing breaks

GCC 7.1's attribute((fallthrough)) would be more elegant, but unfortunatelly this annotation is incompatible with previous versions of GCC (it generates an empty declaration error)

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