1 /*
2 * Copyright (c) 2008-2014 Travis Geiselbrecht
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #include <assert.h>
24 #include <limits.h>
25 #include <printf.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #ifdef UTEST_BUILD
32 #include "test_includes/printf_test.h"
33 #endif
34
35 #if WITH_NO_FP
36 #define FLOAT_PRINTF 0
37 #else
38 #define FLOAT_PRINTF 1
39 #endif
40
41 static int _printf_unfiltered_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap);
42
sprintf(char * str,const char * fmt,...)43 int sprintf(char *str, const char *fmt, ...)
44 {
45 int err;
46
47 va_list ap;
48 va_start(ap, fmt);
49 err = vsprintf(str, fmt, ap);
50 va_end(ap);
51
52 return err;
53 }
54
snprintf(char * str,size_t len,const char * fmt,...)55 int snprintf(char *str, size_t len, const char *fmt, ...)
56 {
57 int err;
58
59 va_list ap;
60 va_start(ap, fmt);
61 err = vsnprintf(str, len, fmt, ap);
62 va_end(ap);
63
64 return err;
65 }
66
snprintf_filtered(char * str,size_t len,const char * fmt,...)67 int snprintf_filtered(char *str, size_t len, const char *fmt, ...)
68 {
69 int err;
70
71 va_list ap;
72 va_start(ap, fmt);
73 err = vsnprintf_filtered(str, len, fmt, ap);
74 va_end(ap);
75
76 return err;
77 }
78
vsprintf(char * str,const char * fmt,va_list ap)79 int vsprintf(char *str, const char *fmt, va_list ap)
80 {
81 return vsnprintf(str, INT_MAX, fmt, ap);
82 }
83
84 struct _output_args {
85 char *outstr;
86 size_t len;
87 size_t pos;
88 };
89
_vsnprintf_output(const char * str,size_t len,void * state)90 static int _vsnprintf_output(const char *str, size_t len, void *state)
91 {
92 struct _output_args *args = state;
93
94 size_t count = 0;
95 while (count < len) {
96 if (args->pos < args->len) {
97 args->outstr[args->pos++] = *str;
98 }
99
100 str++;
101 count++;
102 }
103
104 return count;
105 }
106
vsnprintf(char * str,size_t len,const char * fmt,va_list ap)107 int vsnprintf(char *str, size_t len, const char *fmt, va_list ap)
108 {
109 struct _output_args args;
110 int wlen;
111
112 args.outstr = str;
113 args.len = len;
114 args.pos = 0;
115
116 wlen = _printf_unfiltered_engine(&_vsnprintf_output, (void *)&args, fmt, ap);
117 if(len > 0) {
118 if (args.pos >= len)
119 str[len-1] = '\0';
120 else
121 str[wlen] = '\0';
122 }
123
124 return wlen;
125 }
126
vsnprintf_filtered(char * str,size_t len,const char * fmt,va_list ap)127 int vsnprintf_filtered(char *str, size_t len, const char *fmt, va_list ap)
128 {
129 struct _output_args args;
130 int wlen;
131
132 args.outstr = str;
133 args.len = len;
134 args.pos = 0;
135
136 wlen = _printf_engine(&_vsnprintf_output, (void *)&args, fmt, ap);
137 if (args.pos >= len)
138 str[len-1] = '\0';
139 else
140 str[wlen] = '\0';
141 return wlen;
142 }
143
144 #define LONGFLAG 0x00000001
145 #define LONGLONGFLAG 0x00000002
146 #define HALFFLAG 0x00000004
147 #define HALFHALFFLAG 0x00000008
148 #define SIZETFLAG 0x00000010
149 #define INTMAXFLAG 0x00000020
150 #define PTRDIFFFLAG 0x00000040
151 #define ALTFLAG 0x00000080
152 #define CAPSFLAG 0x00000100
153 #define SHOWSIGNFLAG 0x00000200
154 #define SIGNEDFLAG 0x00000400
155 #define LEFTFORMATFLAG 0x00000800
156 #define LEADZEROFLAG 0x00001000
157 #define BLANKPOSFLAG 0x00002000
158 #define FILTERED_ON_RELEASE 0x00004000
159
longlong_to_string(char * buf,unsigned long long n,size_t len,uint flag,char * signchar)160 __NO_INLINE static char *longlong_to_string(char *buf, unsigned long long n, size_t len, uint flag, char *signchar)
161 {
162 size_t pos = len;
163 int negative = 0;
164 long long signed_n = (long long)n;
165
166 if ((flag & SIGNEDFLAG) && signed_n < 0) {
167 negative = 1;
168 n = -signed_n;
169 }
170
171 buf[--pos] = 0;
172 #if RELEASE_BUILD
173 if (flag & FILTERED_ON_RELEASE) {
174 if (n > 4096) {
175 buf[--pos] = '*';
176 buf[--pos] = '*';
177 buf[--pos] = '*';
178 return &buf[pos];
179 }
180 }
181 #endif
182
183 /* only do the math if the number is >= 10 */
184 while (n >= 10) {
185 int digit = n % 10;
186
187 n /= 10;
188
189 buf[--pos] = digit + '0';
190 }
191 buf[--pos] = n + '0';
192
193 if (negative)
194 *signchar = '-';
195 else if ((flag & SHOWSIGNFLAG))
196 *signchar = '+';
197 else if ((flag & BLANKPOSFLAG))
198 *signchar = ' ';
199 else
200 *signchar = '\0';
201
202 return &buf[pos];
203 }
204
205 static const char hextable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
206 static const char hextable_caps[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
207
longlong_to_hexstring(char * buf,unsigned long long u,size_t len,uint flag)208 __NO_INLINE static char *longlong_to_hexstring(char *buf, unsigned long long u, size_t len, uint flag)
209 {
210 size_t pos = len;
211 const char *table = (flag & CAPSFLAG) ? hextable_caps : hextable;
212
213 buf[--pos] = 0;
214 #if RELEASE_BUILD
215 if (flag & FILTERED_ON_RELEASE) {
216 if ((u > 4096) &&
217 (u < (unsigned long long)(-4096))) {
218 buf[--pos] = '*';
219 buf[--pos] = '*';
220 buf[--pos] = '*';
221 return &buf[pos];
222 }
223 }
224 #endif
225 do {
226 unsigned int digit = u % 16;
227 u /= 16;
228
229 buf[--pos] = table[digit];
230 } while (u != 0);
231
232 return &buf[pos];
233 }
234
235 #if FLOAT_PRINTF
236 union double_int {
237 double d;
238 uint64_t i;
239 };
240
241 #define OUT(c) buf[pos++] = (c)
242 #define OUTSTR(str) do { for (size_t i = 0; (str)[i] != 0; i++) OUT((str)[i]); } while (0)
243
244 /* print up to a 4 digit exponent as string, with sign */
exponent_to_string(char * buf,int32_t exponent)245 __NO_INLINE static size_t exponent_to_string(char *buf, int32_t exponent)
246 {
247 size_t pos = 0;
248
249 /* handle sign */
250 if (exponent < 0) {
251 OUT('-');
252 exponent = -exponent;
253 } else {
254 OUT('+');
255 }
256
257 /* see how far we need to bump into the string to print from the right */
258 if (exponent >= 1000) pos += 4;
259 else if (exponent >= 100) pos += 3;
260 else if (exponent >= 10) pos += 2;
261 else pos++;
262
263 /* print decimal string, from the right */
264 uint i = pos;
265 do {
266 uint digit = (uint32_t)exponent % 10;
267
268 buf[--i] = digit + '0';
269
270 exponent /= 10;
271 } while (exponent != 0);
272
273 /* return number of characters printed */
274 return pos;
275 }
276
double_to_string(char * buf,size_t len,double d,uint flag)277 __NO_INLINE static char *double_to_string(char *buf, size_t len, double d, uint flag)
278 {
279 size_t pos = 0;
280 union double_int u = { d };
281
282 uint32_t exponent = (u.i >> 52) & 0x7ff;
283 uint64_t fraction = (u.i & ((1ULL << 52) - 1));
284 bool neg = !!(u.i & (1ULL << 63));
285
286 /* start constructing the string */
287 if (neg) {
288 OUT('-');
289 d = -d;
290 }
291
292 /* longest:
293 * 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000o
294 */
295
296 /* look for special cases */
297 if (exponent == 0x7ff) {
298 if (fraction == 0) {
299 /* infinity */
300 if (flag & CAPSFLAG) OUTSTR("INF");
301 else OUTSTR("inf");
302 } else {
303 /* NaN */
304 if (flag & CAPSFLAG) OUTSTR("NAN");
305 else OUTSTR("nan");
306 }
307 } else if (exponent == 0) {
308 if (fraction == 0) {
309 /* zero */
310 OUTSTR("0.000000");
311 } else {
312 /* denormalized */
313 /* XXX does not handle */
314 if (flag & CAPSFLAG) OUTSTR("DEN");
315 else OUTSTR("den");
316 }
317 } else {
318 /* see if it's in the range of floats we can easily print */
319 int exponent_signed = exponent - 1023;
320 if (exponent_signed < -52 || exponent_signed > 52) {
321 OUTSTR("<range>");
322 } else {
323 /* start by walking backwards through the string */
324 #define OUTREV(c) do { if (&buf[pos] == buf) goto done; else buf[--pos] = (c); } while (0)
325 pos = len;
326 OUTREV(0);
327
328 /* reserve space for the fractional component first */
329 for (int i = 0; i <= 6; i++)
330 OUTREV('0');
331 size_t decimal_spot = pos;
332
333 /* print the integer portion */
334 uint64_t u;
335 if (exponent_signed >= 0) {
336 u = fraction;
337 u |= (1ULL<<52);
338 u >>= (52 - exponent_signed);
339
340 char *s = longlong_to_string(buf, u, pos + 1, flag, &(char) {0});
341
342 pos = s - buf;
343 } else {
344 /* exponent is negative */
345 u = 0;
346 OUTREV('0');
347 }
348
349 buf[decimal_spot] = '.';
350
351 /* handle the fractional part */
352 uint32_t frac = ((d - u) * 1000000) + .5;
353
354 uint i = decimal_spot + 6 + 1;
355 while (frac != 0) {
356 uint digit = frac % 10;
357
358 buf[--i] = digit + '0';
359
360 frac /= 10;
361 }
362
363 if (neg)
364 OUTREV('-');
365
366 done:
367 /* separate return path, since we've been walking backwards through the string */
368 return &buf[pos];
369 }
370 #undef OUTREV
371 }
372
373 buf[pos] = 0;
374 return buf;
375 }
376
double_to_hexstring(char * buf,size_t len,double d,uint flag)377 __NO_INLINE static char *double_to_hexstring(char *buf, size_t len, double d, uint flag)
378 {
379 size_t pos = 0;
380 union double_int u = { d };
381
382 uint32_t exponent = (u.i >> 52) & 0x7ff;
383 uint64_t fraction = (u.i & ((1ULL << 52) - 1));
384 bool neg = !!(u.i & (1ULL << 63));
385
386 /* start constructing the string */
387 if (neg) {
388 OUT('-');
389 }
390
391 /* look for special cases */
392 if (exponent == 0x7ff) {
393 if (fraction == 0) {
394 /* infinity */
395 if (flag & CAPSFLAG) OUTSTR("INF");
396 else OUTSTR("inf");
397 } else {
398 /* NaN */
399 if (flag & CAPSFLAG) OUTSTR("NAN");
400 else OUTSTR("nan");
401 }
402 } else if (exponent == 0) {
403 if (fraction == 0) {
404 /* zero */
405 if (flag & CAPSFLAG) OUTSTR("0X0P+0");
406 else OUTSTR("0x0p+0");
407 } else {
408 /* denormalized */
409 /* XXX does not handle */
410 if (flag & CAPSFLAG) OUTSTR("DEN");
411 else OUTSTR("den");
412 }
413 } else {
414 /* regular normalized numbers:
415 * 0x1p+1
416 * 0x1.0000000000001p+1
417 * 0X1.FFFFFFFFFFFFFP+1023
418 * 0x1.FFFFFFFFFFFFFP+1023
419 */
420 int exponent_signed = exponent - 1023;
421
422 /* implicit 1. */
423 if (flag & CAPSFLAG) OUTSTR("0X1");
424 else OUTSTR("0x1");
425
426 /* select the appropriate hex case table */
427 const char *table = (flag & CAPSFLAG) ? hextable_caps : hextable;
428
429 int zero_count = 0;
430 bool output_dot = false;
431 for (int i = 52 - 4; i >= 0; i -= 4) {
432 uint digit = (fraction >> i) & 0xf;
433
434 if (digit == 0) {
435 zero_count++;
436 } else {
437 /* output a . the first time we output a char */
438 if (!output_dot) {
439 OUT('.');
440 output_dot = true;
441 }
442 /* if we have a non zero digit, see if we need to output a string of zeros */
443 while (zero_count > 0) {
444 OUT('0');
445 zero_count--;
446 }
447 buf[pos++] = table[digit];
448 }
449 }
450
451 /* handle the exponent */
452 buf[pos++] = (flag & CAPSFLAG) ? 'P' : 'p';
453 pos += exponent_to_string(&buf[pos], exponent_signed);
454 }
455
456 buf[pos] = 0;
457 return buf;
458 }
459
460 #undef OUT
461 #undef OUTSTR
462
463 #endif // FLOAT_PRINTF
464
465 /* Currently only doing a 1 char lookahead for the modifiers*/
parse_extra_modifiers(const char ** format_string,int * flags,bool use_filter_modifiers)466 static void parse_extra_modifiers(const char **format_string, int *flags, bool use_filter_modifiers)
467 {
468 char currChar;
469
470 /* Because this function is called only when we are parsing
471 * and actual format specifier, this value will either point
472 * to the printable string or at most to the NULL terminator.
473 */
474 currChar = **format_string;
475 if (currChar == 0) {
476 return;
477 }
478 /* This is a not filtered call, we should not "eat" the extra x.*/
479 if (!use_filter_modifiers) {
480 return;
481 }
482 switch(currChar) {
483 case 'x':
484 /* Found an x modifier; we really want to print this value.*/
485 *flags &= ~FILTERED_ON_RELEASE;
486 /* We are consuming this character, advance format string.
487 * Advancing is safe because the current character is a
488 * printable one, so worst case we will advance to the end
489 * of the string and the original algorithm was prepared to
490 * handling advancing to end of string before starting to
491 * parse.
492 */
493 (*format_string)++;
494 break;
495 default:
496 /* We didn't understood the next character,
497 * normal parsing code will take care of it
498 */
499 break;
500 }
501 }
502
_printf_engine_internal(_printf_engine_output_func out,void * state,const char * fmt,va_list ap,bool filtered)503 static int _printf_engine_internal(_printf_engine_output_func out, void *state, const char *fmt, va_list ap, bool filtered)
504 {
505 int err = 0;
506 char c;
507 unsigned char uc;
508 const char *s;
509 size_t string_len;
510 unsigned long long n;
511 void *ptr;
512 int flags;
513 unsigned int format_num;
514 char signchar;
515 size_t chars_written = 0;
516 char num_buffer[32];
517
518 #define OUTPUT_STRING(str, len) do { err = out(str, len, state); if (err < 0) { goto exit; } else { chars_written += err; } } while(0)
519 #define OUTPUT_CHAR(c) do { char __temp[1] = { c }; OUTPUT_STRING(__temp, 1); } while (0)
520
521 for (;;) {
522 /* reset the format state */
523 if (filtered) {
524 flags = FILTERED_ON_RELEASE;
525 } else {
526 flags = 0;
527 }
528 format_num = 0;
529 signchar = '\0';
530
531 /* handle regular chars that aren't format related */
532 s = fmt;
533 string_len = 0;
534 while ((c = *fmt++) != 0) {
535 if (c == '%')
536 break; /* we saw a '%', break and start parsing format */
537 string_len++;
538 }
539
540 /* output the string we've accumulated */
541 OUTPUT_STRING(s, string_len);
542
543 /* make sure we haven't just hit the end of the string */
544 if (c == 0)
545 break;
546
547 next_format:
548 /* grab the next format character */
549 c = *fmt++;
550 if (c == 0)
551 break;
552
553 switch (c) {
554 case '0'...'9':
555 if (c == '0' && format_num == 0)
556 flags |= LEADZEROFLAG;
557 format_num *= 10;
558 format_num += c - '0';
559 goto next_format;
560 case '.':
561 /* XXX for now eat numeric formatting */
562 goto next_format;
563 case '%':
564 OUTPUT_CHAR('%');
565 break;
566 case 'c':
567 uc = va_arg(ap, unsigned int);
568 OUTPUT_CHAR(uc);
569 break;
570 case '*':
571 {
572 /* indirect format */
573 int f = va_arg(ap, int);
574 if(f < 0) {
575 format_num = (unsigned int) (-f);
576 flags |= LEFTFORMATFLAG;
577 } else {
578 format_num = (unsigned int) (f);
579 }
580 goto next_format;
581 }
582 case 's':
583 s = va_arg(ap, const char *);
584 if (s == 0)
585 s = "<null>";
586 flags &= ~LEADZEROFLAG; /* doesn't make sense for strings */
587 goto _output_string;
588 case '-':
589 flags |= LEFTFORMATFLAG;
590 goto next_format;
591 case '+':
592 flags |= SHOWSIGNFLAG;
593 goto next_format;
594 case ' ':
595 flags |= BLANKPOSFLAG;
596 goto next_format;
597 case '#':
598 flags |= ALTFLAG;
599 goto next_format;
600 case 'l':
601 if (flags & LONGFLAG)
602 flags |= LONGLONGFLAG;
603 flags |= LONGFLAG;
604 goto next_format;
605 case 'h':
606 if (flags & HALFFLAG)
607 flags |= HALFHALFFLAG;
608 flags |= HALFFLAG;
609 goto next_format;
610 case 'z':
611 flags |= SIZETFLAG;
612 goto next_format;
613 case 'j':
614 flags |= INTMAXFLAG;
615 goto next_format;
616 case 't':
617 flags |= PTRDIFFFLAG;
618 goto next_format;
619 case 'i':
620 case 'd':
621 n = (unsigned long long)((flags & LONGLONGFLAG) ? va_arg(ap, long long) :
622 (flags & LONGFLAG) ? va_arg(ap, long) :
623 (flags & HALFHALFFLAG) ? (signed char)va_arg(ap, int) :
624 (flags & HALFFLAG) ? (short)va_arg(ap, int) :
625 (flags & SIZETFLAG) ? va_arg(ap, ssize_t) :
626 (flags & INTMAXFLAG) ? va_arg(ap, intmax_t) :
627 (flags & PTRDIFFFLAG) ? va_arg(ap, ptrdiff_t) :
628 va_arg(ap, int));
629 flags |= SIGNEDFLAG;
630 parse_extra_modifiers(&fmt, &flags, filtered);
631 s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar);
632 goto _output_string;
633 case 'u':
634 n = (unsigned long long)((flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) :
635 (flags & LONGFLAG) ? va_arg(ap, unsigned long) :
636 (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) :
637 (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) :
638 (flags & SIZETFLAG) ? va_arg(ap, size_t) :
639 (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) :
640 (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) :
641 va_arg(ap, unsigned int));
642 parse_extra_modifiers(&fmt, &flags, filtered);
643 s = longlong_to_string(num_buffer, n, sizeof(num_buffer), flags, &signchar);
644 goto _output_string;
645 case 'p':
646 flags |= LONGFLAG | ALTFLAG;
647 goto hex;
648 case 'X':
649 flags |= CAPSFLAG;
650 goto hex;
651 case 'x':
652 hex:
653 n = (flags & LONGLONGFLAG) ? va_arg(ap, unsigned long long) :
654 (flags & LONGFLAG) ? va_arg(ap, unsigned long) :
655 (flags & HALFHALFFLAG) ? (unsigned char)va_arg(ap, unsigned int) :
656 (flags & HALFFLAG) ? (unsigned short)va_arg(ap, unsigned int) :
657 (flags & SIZETFLAG) ? va_arg(ap, size_t) :
658 (flags & INTMAXFLAG) ? va_arg(ap, uintmax_t) :
659 (flags & PTRDIFFFLAG) ? (uintptr_t)va_arg(ap, ptrdiff_t) :
660 va_arg(ap, unsigned int);
661 parse_extra_modifiers(&fmt, &flags, filtered);
662 s = longlong_to_hexstring(num_buffer, n, sizeof(num_buffer), flags);
663 if (flags & ALTFLAG) {
664 OUTPUT_CHAR('0');
665 OUTPUT_CHAR((flags & CAPSFLAG) ? 'X': 'x');
666 }
667 goto _output_string;
668 case 'n':
669 ptr = va_arg(ap, void *);
670 if (flags & LONGLONGFLAG)
671 *(long long *)ptr = chars_written;
672 else if (flags & LONGFLAG)
673 *(long *)ptr = chars_written;
674 else if (flags & HALFHALFFLAG)
675 *(signed char *)ptr = chars_written;
676 else if (flags & HALFFLAG)
677 *(short *)ptr = chars_written;
678 else if (flags & SIZETFLAG)
679 *(size_t *)ptr = chars_written;
680 else
681 *(int *)ptr = chars_written;
682 break;
683 #if FLOAT_PRINTF
684 case 'F':
685 flags |= CAPSFLAG;
686 __FALLTHROUGH;
687 case 'f': {
688 double d = va_arg(ap, double);
689 s = double_to_string(num_buffer, sizeof(num_buffer), d, flags);
690 goto _output_string;
691 }
692 case 'A':
693 flags |= CAPSFLAG;
694 __FALLTHROUGH;
695 case 'a': {
696 double d = va_arg(ap, double);
697 s = double_to_hexstring(num_buffer, sizeof(num_buffer), d, flags);
698 goto _output_string;
699 }
700 #endif
701 default:
702 OUTPUT_CHAR('%');
703 OUTPUT_CHAR(c);
704 break;
705 }
706
707 /* move on to the next field */
708 continue;
709
710 /* shared output code */
711 _output_string:
712 string_len = strlen(s);
713
714 if (flags & LEFTFORMATFLAG) {
715 /* left justify the text */
716 OUTPUT_STRING(s, string_len);
717 uint written = err;
718
719 /* pad to the right (if necessary) */
720 for (; format_num > written; format_num--)
721 OUTPUT_CHAR(' ');
722 } else {
723 /* right justify the text (digits) */
724
725 /* if we're going to print a sign digit,
726 it'll chew up one byte of the format size */
727 if (signchar != '\0' && format_num > 0)
728 format_num--;
729
730 /* output the sign char before the leading zeros */
731 if (flags & LEADZEROFLAG && signchar != '\0')
732 OUTPUT_CHAR(signchar);
733
734 /* pad according to the format string */
735 for (; format_num > string_len; format_num--)
736 OUTPUT_CHAR(flags & LEADZEROFLAG ? '0' : ' ');
737
738 /* if not leading zeros, output the sign char just before the number */
739 if (!(flags & LEADZEROFLAG) && signchar != '\0')
740 OUTPUT_CHAR(signchar);
741
742 /* output the string */
743 OUTPUT_STRING(s, string_len);
744 }
745 continue;
746 }
747
748 #undef OUTPUT_STRING
749 #undef OUTPUT_CHAR
750
751 exit:
752 return (err < 0) ? err : (int)chars_written;
753 }
754
_printf_engine(_printf_engine_output_func out,void * state,const char * fmt,va_list ap)755 int _printf_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap)
756 {
757 return _printf_engine_internal(out, state, fmt, ap, true);
758 }
759
_printf_unfiltered_engine(_printf_engine_output_func out,void * state,const char * fmt,va_list ap)760 static int _printf_unfiltered_engine(_printf_engine_output_func out, void *state, const char *fmt, va_list ap)
761 {
762 return _printf_engine_internal(out, state, fmt, ap, false);
763 }
764