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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 338d54a7 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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