source: mainline/uspace/lib/c/generic/io/printf_core.c@ c05642d

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