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

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

Kernel should have stddef.h

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