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

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

cleanup, string changes

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