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

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

remove redundant index_t and count_t types (which were always quite ambiguous and not actually needed)

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