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

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

unify printf implementations

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