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

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

fix printout of signed integer arguments (thx Jiri Zarevucky)
synchronize printf implementations between boot, kernel and uspace

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