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

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

tiny cstyle modifications (no change in functionality)

  • Property mode set to 100644
File size: 21.8 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 \%#X / \%#x
573 * for 32-bit or \%#X / \%#x for 64-bit long pointers).
574 *
575 * - b Print value as unsigned binary number. Prefix is not printed by
576 * default. (Nonstandard extension.)
577 *
578 * - o Print value as unsigned octal number. Prefix is not printed by
579 * default.
580 *
581 * - d, i Print signed decimal number. There is no difference between d
582 * and i conversion.
583 *
584 * - u Print unsigned decimal number.
585 *
586 * - X, x Print hexadecimal number with upper- or lower-case. Prefix is
587 * not printed by default.
588 *
589 * All other characters from fmt except the formatting directives are printed
590 * verbatim.
591 *
592 * @param fmt Format NULL-terminated string.
593 *
594 * @return Number of characters printed, negative value on failure.
595 *
596 */
597int printf_core(const char *fmt, printf_spec_t *ps, va_list ap)
598{
599 size_t i; /* Index of the currently processed character from fmt */
600 size_t nxt = 0; /* Index of the next character from fmt */
601 size_t j = 0; /* Index to the first not printed nonformating character */
602
603 size_t counter = 0; /* Number of characters printed */
604 int retval; /* Return values from nested functions */
605
606 while (true) {
607 i = nxt;
608 wchar_t uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
609
610 if (uc == 0)
611 break;
612
613 /* Control character */
614 if (uc == '%') {
615 /* Print common characters if any processed */
616 if (i > j) {
617 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
618 /* Error */
619 counter = -counter;
620 goto out;
621 }
622 counter += retval;
623 }
624
625 j = i;
626
627 /* Parse modifiers */
628 uint32_t flags = 0;
629 bool end = false;
630
631 do {
632 i = nxt;
633 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
634 switch (uc) {
635 case '#':
636 flags |= __PRINTF_FLAG_PREFIX;
637 break;
638 case '-':
639 flags |= __PRINTF_FLAG_LEFTALIGNED;
640 break;
641 case '+':
642 flags |= __PRINTF_FLAG_SHOWPLUS;
643 break;
644 case ' ':
645 flags |= __PRINTF_FLAG_SPACESIGN;
646 break;
647 case '0':
648 flags |= __PRINTF_FLAG_ZEROPADDED;
649 break;
650 default:
651 end = true;
652 };
653 } while (!end);
654
655 /* Width & '*' operator */
656 int width = 0;
657 if (isdigit(uc)) {
658 while (true) {
659 width *= 10;
660 width += uc - '0';
661
662 i = nxt;
663 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
664 if (uc == 0)
665 break;
666 if (!isdigit(uc))
667 break;
668 }
669 } else if (uc == '*') {
670 /* Get width value from argument list */
671 i = nxt;
672 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
673 width = (int) va_arg(ap, int);
674 if (width < 0) {
675 /* Negative width sets '-' flag */
676 width *= -1;
677 flags |= __PRINTF_FLAG_LEFTALIGNED;
678 }
679 }
680
681 /* Precision and '*' operator */
682 int precision = 0;
683 if (uc == '.') {
684 i = nxt;
685 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
686 if (isdigit(uc)) {
687 while (true) {
688 precision *= 10;
689 precision += uc - '0';
690
691 i = nxt;
692 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
693 if (uc == 0)
694 break;
695 if (!isdigit(uc))
696 break;
697 }
698 } else if (uc == '*') {
699 /* Get precision value from the argument list */
700 i = nxt;
701 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
702 precision = (int) va_arg(ap, int);
703 if (precision < 0) {
704 /* Ignore negative precision */
705 precision = 0;
706 }
707 }
708 }
709
710 qualifier_t qualifier;
711
712 switch (uc) {
713 /** @todo Unimplemented qualifiers:
714 * t ptrdiff_t - ISO C 99
715 */
716 case 'h':
717 /* Char or short */
718 qualifier = PrintfQualifierShort;
719 i = nxt;
720 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
721 if (uc == 'h') {
722 i = nxt;
723 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
724 qualifier = PrintfQualifierByte;
725 }
726 break;
727 case 'l':
728 /* Long or long long */
729 qualifier = PrintfQualifierLong;
730 i = nxt;
731 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
732 if (uc == 'l') {
733 i = nxt;
734 uc = str_decode(fmt, &nxt, STR_NO_LIMIT);
735 qualifier = PrintfQualifierLongLong;
736 }
737 break;
738 default:
739 /* Default type */
740 qualifier = PrintfQualifierInt;
741 }
742
743 unsigned int base = 10;
744
745 switch (uc) {
746 /*
747 * String and character conversions.
748 */
749 case 's':
750 if (qualifier == PrintfQualifierLong)
751 retval = print_wstr(va_arg(ap, wchar_t *), width, precision, flags, ps);
752 else
753 retval = print_str(va_arg(ap, char *), width, precision, flags, ps);
754
755 if (retval < 0) {
756 counter = -counter;
757 goto out;
758 }
759
760 counter += retval;
761 j = nxt;
762 goto next_char;
763 case 'c':
764 if (qualifier == PrintfQualifierLong)
765 retval = print_wchar(va_arg(ap, wchar_t), width, flags, ps);
766 else
767 retval = print_char(va_arg(ap, unsigned int), width, flags, ps);
768
769 if (retval < 0) {
770 counter = -counter;
771 goto out;
772 };
773
774 counter += retval;
775 j = nxt;
776 goto next_char;
777
778 /*
779 * Integer values
780 */
781 case 'P':
782 /* Pointer */
783 flags |= __PRINTF_FLAG_BIGCHARS;
784 case 'p':
785 flags |= __PRINTF_FLAG_PREFIX;
786 base = 16;
787 qualifier = PrintfQualifierPointer;
788 break;
789 case 'b':
790 base = 2;
791 break;
792 case 'o':
793 base = 8;
794 break;
795 case 'd':
796 case 'i':
797 flags |= __PRINTF_FLAG_SIGNED;
798 case 'u':
799 break;
800 case 'X':
801 flags |= __PRINTF_FLAG_BIGCHARS;
802 case 'x':
803 base = 16;
804 break;
805
806 /* Percentile itself */
807 case '%':
808 j = i;
809 goto next_char;
810
811 /*
812 * Bad formatting.
813 */
814 default:
815 /*
816 * Unknown format. Now, j is the index of '%'
817 * so we will print whole bad format sequence.
818 */
819 goto next_char;
820 }
821
822 /* Print integers */
823 size_t size;
824 uint64_t number;
825 switch (qualifier) {
826 case PrintfQualifierByte:
827 size = sizeof(unsigned char);
828 number = (uint64_t) va_arg(ap, unsigned int);
829 break;
830 case PrintfQualifierShort:
831 size = sizeof(unsigned short);
832 number = (uint64_t) va_arg(ap, unsigned int);
833 break;
834 case PrintfQualifierInt:
835 size = sizeof(unsigned int);
836 number = (uint64_t) va_arg(ap, unsigned int);
837 break;
838 case PrintfQualifierLong:
839 size = sizeof(unsigned long);
840 number = (uint64_t) va_arg(ap, unsigned long);
841 break;
842 case PrintfQualifierLongLong:
843 size = sizeof(unsigned long long);
844 number = (uint64_t) va_arg(ap, unsigned long long);
845 break;
846 case PrintfQualifierPointer:
847 size = sizeof(void *);
848 number = (uint64_t) (unsigned long) va_arg(ap, void *);
849 break;
850 default:
851 /* Unknown qualifier */
852 counter = -counter;
853 goto out;
854 }
855
856 if (flags & __PRINTF_FLAG_SIGNED) {
857 if (number & (0x1 << (size * 8 - 1))) {
858 flags |= __PRINTF_FLAG_NEGATIVE;
859
860 if (size == sizeof(uint64_t)) {
861 number = -((int64_t) number);
862 } else {
863 number = ~number;
864 number &=
865 ~(0xFFFFFFFFFFFFFFFFll <<
866 (size * 8));
867 number++;
868 }
869 }
870 }
871
872 if ((retval = print_number(number, width, precision,
873 base, flags, ps)) < 0) {
874 counter = -counter;
875 goto out;
876 }
877
878 counter += retval;
879 j = nxt;
880 }
881next_char:
882 ;
883 }
884
885 if (i > j) {
886 if ((retval = printf_putnchars(&fmt[j], i - j, ps)) < 0) {
887 /* Error */
888 counter = -counter;
889 goto out;
890 }
891 counter += retval;
892 }
893
894out:
895 return ((int) counter);
896}
897
898/** @}
899 */
Note: See TracBrowser for help on using the repository browser.