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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 06b785f was 06b785f, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

strlen() → str_size().

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