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

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