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