xref: /curl/lib/mprintf.c (revision b70e8f4b)
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  * SPDX-License-Identifier: curl
22  *
23  */
24 
25 #include "curl_setup.h"
26 #include "dynbuf.h"
27 #include "curl_printf.h"
28 
29 #include "curl_memory.h"
30 /* The last #include file should be: */
31 #include "memdebug.h"
32 
33 /*
34  * If SIZEOF_SIZE_T has not been defined, default to the size of long.
35  */
36 
37 #ifdef HAVE_LONGLONG
38 #  define LONG_LONG_TYPE long long
39 #  define HAVE_LONG_LONG_TYPE
40 #else
41 #  if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
42 #    define LONG_LONG_TYPE __int64
43 #    define HAVE_LONG_LONG_TYPE
44 #  else
45 #    undef LONG_LONG_TYPE
46 #    undef HAVE_LONG_LONG_TYPE
47 #  endif
48 #endif
49 
50 /*
51  * Max integer data types that mprintf.c is capable
52  */
53 
54 #ifdef HAVE_LONG_LONG_TYPE
55 #  define mp_intmax_t LONG_LONG_TYPE
56 #  define mp_uintmax_t unsigned LONG_LONG_TYPE
57 #else
58 #  define mp_intmax_t long
59 #  define mp_uintmax_t unsigned long
60 #endif
61 
62 #define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
63                         fit negative DBL_MAX (317 letters) */
64 #define MAX_PARAMETERS 128 /* number of input arguments */
65 #define MAX_SEGMENTS   128 /* number of output segments */
66 
67 #ifdef __AMIGA__
68 # undef FORMAT_INT
69 #endif
70 
71 /* Lower-case digits.  */
72 static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
73 
74 /* Upper-case digits.  */
75 static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
76 
77 #define OUTCHAR(x)                                      \
78   do {                                                  \
79     if(!stream((unsigned char)x, userp))                \
80       done++;                                           \
81     else                                                \
82       return done; /* return on failure */              \
83   } while(0)
84 
85 /* Data type to read from the arglist */
86 typedef enum {
87   FORMAT_STRING,
88   FORMAT_PTR,
89   FORMAT_INTPTR,
90   FORMAT_INT,
91   FORMAT_LONG,
92   FORMAT_LONGLONG,
93   FORMAT_INTU,
94   FORMAT_LONGU,
95   FORMAT_LONGLONGU,
96   FORMAT_DOUBLE,
97   FORMAT_LONGDOUBLE,
98   FORMAT_WIDTH,
99   FORMAT_PRECISION
100 } FormatType;
101 
102 /* conversion and display flags */
103 enum {
104   FLAGS_SPACE      = 1 << 0,
105   FLAGS_SHOWSIGN   = 1 << 1,
106   FLAGS_LEFT       = 1 << 2,
107   FLAGS_ALT        = 1 << 3,
108   FLAGS_SHORT      = 1 << 4,
109   FLAGS_LONG       = 1 << 5,
110   FLAGS_LONGLONG   = 1 << 6,
111   FLAGS_LONGDOUBLE = 1 << 7,
112   FLAGS_PAD_NIL    = 1 << 8,
113   FLAGS_UNSIGNED   = 1 << 9,
114   FLAGS_OCTAL      = 1 << 10,
115   FLAGS_HEX        = 1 << 11,
116   FLAGS_UPPER      = 1 << 12,
117   FLAGS_WIDTH      = 1 << 13, /* '*' or '*<num>$' used */
118   FLAGS_WIDTHPARAM = 1 << 14, /* width PARAMETER was specified */
119   FLAGS_PREC       = 1 << 15, /* precision was specified */
120   FLAGS_PRECPARAM  = 1 << 16, /* precision PARAMETER was specified */
121   FLAGS_CHAR       = 1 << 17, /* %c story */
122   FLAGS_FLOATE     = 1 << 18, /* %e or %E */
123   FLAGS_FLOATG     = 1 << 19, /* %g or %G */
124   FLAGS_SUBSTR     = 1 << 20  /* no input, only substring */
125 };
126 
127 enum {
128   DOLLAR_UNKNOWN,
129   DOLLAR_NOPE,
130   DOLLAR_USE
131 };
132 
133 /*
134  * Describes an input va_arg type and hold its value.
135  */
136 struct va_input {
137   FormatType type; /* FormatType */
138   union {
139     char *str;
140     void *ptr;
141     mp_intmax_t nums; /* signed */
142     mp_uintmax_t numu; /* unsigned */
143     double dnum;
144   } val;
145 };
146 
147 /*
148  * Describes an output segment.
149  */
150 struct outsegment {
151   int width;     /* width OR width parameter number */
152   int precision; /* precision OR precision parameter number */
153   unsigned int flags;
154   unsigned int input; /* input argument array index */
155   char *start;      /* format string start to output */
156   size_t outlen;     /* number of bytes from the format string to output */
157 };
158 
159 struct nsprintf {
160   char *buffer;
161   size_t length;
162   size_t max;
163 };
164 
165 struct asprintf {
166   struct dynbuf *b;
167   char merr;
168 };
169 
170 /* the provided input number is 1-based but this returns the number 0-based.
171 
172    returns -1 if no valid number was provided.
173 */
dollarstring(char * input,char ** end)174 static int dollarstring(char *input, char **end)
175 {
176   if(ISDIGIT(*input)) {
177     int number = 0;
178     do {
179       if(number < MAX_PARAMETERS) {
180         number *= 10;
181         number += *input - '0';
182       }
183       input++;
184     } while(ISDIGIT(*input));
185 
186     if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) {
187       *end = ++input;
188       return number - 1;
189     }
190   }
191   return -1;
192 }
193 
194 /*
195  * Parse the format string.
196  *
197  * Create two arrays. One describes the inputs, one describes the outputs.
198  *
199  * Returns zero on success.
200  */
201 
202 #define PFMT_OK          0
203 #define PFMT_DOLLAR      1 /* bad dollar for main param */
204 #define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */
205 #define PFMT_DOLLARPREC  3 /* bad dollar use for precision */
206 #define PFMT_MANYARGS    4 /* too many input arguments used */
207 #define PFMT_PREC        5 /* precision overflow */
208 #define PFMT_PRECMIX     6 /* bad mix of precision specifiers */
209 #define PFMT_WIDTH       7 /* width overflow */
210 #define PFMT_INPUTGAP    8 /* gap in arguments */
211 #define PFMT_WIDTHARG    9 /* attempted to use same arg twice, for width */
212 #define PFMT_PRECARG    10 /* attempted to use same arg twice, for prec */
213 #define PFMT_MANYSEGS   11 /* maxed out output segments */
214 
parsefmt(const char * format,struct outsegment * out,struct va_input * in,int * opieces,int * ipieces,va_list arglist)215 static int parsefmt(const char *format,
216                     struct outsegment *out,
217                     struct va_input *in,
218                     int *opieces,
219                     int *ipieces, va_list arglist)
220 {
221   char *fmt = (char *)format;
222   int param_num = 0;
223   int param;
224   int width;
225   int precision;
226   unsigned int flags;
227   FormatType type;
228   int max_param = -1;
229   int i;
230   int ocount = 0;
231   unsigned char usedinput[MAX_PARAMETERS/8];
232   size_t outlen = 0;
233   struct outsegment *optr;
234   int use_dollar = DOLLAR_UNKNOWN;
235   char *start = fmt;
236 
237   /* clear, set a bit for each used input */
238   memset(usedinput, 0, sizeof(usedinput));
239 
240   while(*fmt) {
241     if(*fmt == '%') {
242       struct va_input *iptr;
243       bool loopit = TRUE;
244       fmt++;
245       outlen = (size_t)(fmt - start - 1);
246       if(*fmt == '%') {
247         /* this means a %% that should be output only as %. Create an output
248            segment. */
249         if(outlen) {
250           optr = &out[ocount++];
251           if(ocount > MAX_SEGMENTS)
252             return PFMT_MANYSEGS;
253           optr->input = 0;
254           optr->flags = FLAGS_SUBSTR;
255           optr->start = start;
256           optr->outlen = outlen;
257         }
258         start = fmt;
259         fmt++;
260         continue; /* while */
261       }
262 
263       flags = 0;
264       width = precision = 0;
265 
266       if(use_dollar != DOLLAR_NOPE) {
267         param = dollarstring(fmt, &fmt);
268         if(param < 0) {
269           if(use_dollar == DOLLAR_USE)
270             /* illegal combo */
271             return PFMT_DOLLAR;
272 
273           /* we got no positional, just get the next arg */
274           param = -1;
275           use_dollar = DOLLAR_NOPE;
276         }
277         else
278           use_dollar = DOLLAR_USE;
279       }
280       else
281         param = -1;
282 
283       /* Handle the flags */
284       while(loopit) {
285         switch(*fmt++) {
286         case ' ':
287           flags |= FLAGS_SPACE;
288           break;
289         case '+':
290           flags |= FLAGS_SHOWSIGN;
291           break;
292         case '-':
293           flags |= FLAGS_LEFT;
294           flags &= ~(unsigned int)FLAGS_PAD_NIL;
295           break;
296         case '#':
297           flags |= FLAGS_ALT;
298           break;
299         case '.':
300           if('*' == *fmt) {
301             /* The precision is picked from a specified parameter */
302             flags |= FLAGS_PRECPARAM;
303             fmt++;
304 
305             if(use_dollar == DOLLAR_USE) {
306               precision = dollarstring(fmt, &fmt);
307               if(precision < 0)
308                 /* illegal combo */
309                 return PFMT_DOLLARPREC;
310             }
311             else
312               /* get it from the next argument */
313               precision = -1;
314           }
315           else {
316             bool is_neg = FALSE;
317             flags |= FLAGS_PREC;
318             precision = 0;
319             if('-' == *fmt) {
320               is_neg = TRUE;
321               fmt++;
322             }
323             while(ISDIGIT(*fmt)) {
324               if(precision > INT_MAX/10)
325                 return PFMT_PREC;
326               precision *= 10;
327               precision += *fmt - '0';
328               fmt++;
329             }
330             if(is_neg)
331               precision = -precision;
332           }
333           if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
334              (FLAGS_PREC | FLAGS_PRECPARAM))
335             /* it is not permitted to use both kinds of precision for the same
336                argument */
337             return PFMT_PRECMIX;
338           break;
339         case 'h':
340           flags |= FLAGS_SHORT;
341           break;
342 #if defined(_WIN32) || defined(_WIN32_WCE)
343         case 'I':
344           /* Non-ANSI integer extensions I32 I64 */
345           if((fmt[0] == '3') && (fmt[1] == '2')) {
346             flags |= FLAGS_LONG;
347             fmt += 2;
348           }
349           else if((fmt[0] == '6') && (fmt[1] == '4')) {
350             flags |= FLAGS_LONGLONG;
351             fmt += 2;
352           }
353           else {
354 #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
355             flags |= FLAGS_LONGLONG;
356 #else
357             flags |= FLAGS_LONG;
358 #endif
359           }
360           break;
361 #endif /* _WIN32 || _WIN32_WCE */
362         case 'l':
363           if(flags & FLAGS_LONG)
364             flags |= FLAGS_LONGLONG;
365           else
366             flags |= FLAGS_LONG;
367           break;
368         case 'L':
369           flags |= FLAGS_LONGDOUBLE;
370           break;
371         case 'q':
372           flags |= FLAGS_LONGLONG;
373           break;
374         case 'z':
375           /* the code below generates a warning if -Wunreachable-code is
376              used */
377 #if (SIZEOF_SIZE_T > SIZEOF_LONG)
378           flags |= FLAGS_LONGLONG;
379 #else
380           flags |= FLAGS_LONG;
381 #endif
382           break;
383         case 'O':
384 #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
385           flags |= FLAGS_LONGLONG;
386 #else
387           flags |= FLAGS_LONG;
388 #endif
389           break;
390         case '0':
391           if(!(flags & FLAGS_LEFT))
392             flags |= FLAGS_PAD_NIL;
393           FALLTHROUGH();
394         case '1': case '2': case '3': case '4':
395         case '5': case '6': case '7': case '8': case '9':
396           flags |= FLAGS_WIDTH;
397           width = 0;
398           fmt--;
399           do {
400             if(width > INT_MAX/10)
401               return PFMT_WIDTH;
402             width *= 10;
403             width += *fmt - '0';
404             fmt++;
405           } while(ISDIGIT(*fmt));
406           break;
407         case '*':  /* read width from argument list */
408           flags |= FLAGS_WIDTHPARAM;
409           if(use_dollar == DOLLAR_USE) {
410             width = dollarstring(fmt, &fmt);
411             if(width < 0)
412               /* illegal combo */
413               return PFMT_DOLLARWIDTH;
414           }
415           else
416             /* pick from the next argument */
417             width = -1;
418           break;
419         default:
420           loopit = FALSE;
421           fmt--;
422           break;
423         } /* switch */
424       } /* while */
425 
426       switch(*fmt) {
427       case 'S':
428         flags |= FLAGS_ALT;
429         FALLTHROUGH();
430       case 's':
431         type = FORMAT_STRING;
432         break;
433       case 'n':
434         type = FORMAT_INTPTR;
435         break;
436       case 'p':
437         type = FORMAT_PTR;
438         break;
439       case 'd':
440       case 'i':
441         if(flags & FLAGS_LONGLONG)
442           type = FORMAT_LONGLONG;
443         else if(flags & FLAGS_LONG)
444           type = FORMAT_LONG;
445         else
446           type = FORMAT_INT;
447         break;
448       case 'u':
449         if(flags & FLAGS_LONGLONG)
450           type = FORMAT_LONGLONGU;
451         else if(flags & FLAGS_LONG)
452           type = FORMAT_LONGU;
453         else
454           type = FORMAT_INTU;
455         flags |= FLAGS_UNSIGNED;
456         break;
457       case 'o':
458         type = FORMAT_INT;
459         flags |= FLAGS_OCTAL;
460         break;
461       case 'x':
462         type = FORMAT_INTU;
463         flags |= FLAGS_HEX|FLAGS_UNSIGNED;
464         break;
465       case 'X':
466         type = FORMAT_INTU;
467         flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
468         break;
469       case 'c':
470         type = FORMAT_INT;
471         flags |= FLAGS_CHAR;
472         break;
473       case 'f':
474         type = FORMAT_DOUBLE;
475         break;
476       case 'e':
477         type = FORMAT_DOUBLE;
478         flags |= FLAGS_FLOATE;
479         break;
480       case 'E':
481         type = FORMAT_DOUBLE;
482         flags |= FLAGS_FLOATE|FLAGS_UPPER;
483         break;
484       case 'g':
485         type = FORMAT_DOUBLE;
486         flags |= FLAGS_FLOATG;
487         break;
488       case 'G':
489         type = FORMAT_DOUBLE;
490         flags |= FLAGS_FLOATG|FLAGS_UPPER;
491         break;
492       default:
493         /* invalid instruction, disregard and continue */
494         continue;
495       } /* switch */
496 
497       if(flags & FLAGS_WIDTHPARAM) {
498         if(width < 0)
499           width = param_num++;
500         else {
501           /* if this identifies a parameter already used, this
502              is illegal */
503           if(usedinput[width/8] & (1 << (width&7)))
504             return PFMT_WIDTHARG;
505         }
506         if(width >= MAX_PARAMETERS)
507           return PFMT_MANYARGS;
508         if(width >= max_param)
509           max_param = width;
510 
511         in[width].type = FORMAT_WIDTH;
512         /* mark as used */
513         usedinput[width/8] |= (unsigned char)(1 << (width&7));
514       }
515 
516       if(flags & FLAGS_PRECPARAM) {
517         if(precision < 0)
518           precision = param_num++;
519         else {
520           /* if this identifies a parameter already used, this
521              is illegal */
522           if(usedinput[precision/8] & (1 << (precision&7)))
523             return PFMT_PRECARG;
524         }
525         if(precision >= MAX_PARAMETERS)
526           return PFMT_MANYARGS;
527         if(precision >= max_param)
528           max_param = precision;
529 
530         in[precision].type = FORMAT_PRECISION;
531         usedinput[precision/8] |= (unsigned char)(1 << (precision&7));
532       }
533 
534       /* Handle the specifier */
535       if(param < 0)
536         param = param_num++;
537       if(param >= MAX_PARAMETERS)
538         return PFMT_MANYARGS;
539       if(param >= max_param)
540         max_param = param;
541 
542       iptr = &in[param];
543       iptr->type = type;
544 
545       /* mark this input as used */
546       usedinput[param/8] |= (unsigned char)(1 << (param&7));
547 
548       fmt++;
549       optr = &out[ocount++];
550       if(ocount > MAX_SEGMENTS)
551         return PFMT_MANYSEGS;
552       optr->input = (unsigned int)param;
553       optr->flags = flags;
554       optr->width = width;
555       optr->precision = precision;
556       optr->start = start;
557       optr->outlen = outlen;
558       start = fmt;
559     }
560     else
561       fmt++;
562   }
563 
564   /* is there a trailing piece */
565   outlen = (size_t)(fmt - start);
566   if(outlen) {
567     optr = &out[ocount++];
568     if(ocount > MAX_SEGMENTS)
569       return PFMT_MANYSEGS;
570     optr->input = 0;
571     optr->flags = FLAGS_SUBSTR;
572     optr->start = start;
573     optr->outlen = outlen;
574   }
575 
576   /* Read the arg list parameters into our data list */
577   for(i = 0; i < max_param + 1; i++) {
578     struct va_input *iptr = &in[i];
579     if(!(usedinput[i/8] & (1 << (i&7))))
580       /* bad input */
581       return PFMT_INPUTGAP;
582 
583     /* based on the type, read the correct argument */
584     switch(iptr->type) {
585     case FORMAT_STRING:
586       iptr->val.str = va_arg(arglist, char *);
587       break;
588 
589     case FORMAT_INTPTR:
590     case FORMAT_PTR:
591       iptr->val.ptr = va_arg(arglist, void *);
592       break;
593 
594     case FORMAT_LONGLONGU:
595       iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
596       break;
597 
598     case FORMAT_LONGLONG:
599       iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t);
600       break;
601 
602     case FORMAT_LONGU:
603       iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long);
604       break;
605 
606     case FORMAT_LONG:
607       iptr->val.nums = (mp_intmax_t)va_arg(arglist, long);
608       break;
609 
610     case FORMAT_INTU:
611       iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int);
612       break;
613 
614     case FORMAT_INT:
615     case FORMAT_WIDTH:
616     case FORMAT_PRECISION:
617       iptr->val.nums = (mp_intmax_t)va_arg(arglist, int);
618       break;
619 
620     case FORMAT_DOUBLE:
621       iptr->val.dnum = va_arg(arglist, double);
622       break;
623 
624     default:
625       DEBUGASSERT(NULL); /* unexpected */
626       break;
627     }
628   }
629   *ipieces = max_param + 1;
630   *opieces = ocount;
631 
632   return PFMT_OK;
633 }
634 
635 /*
636  * formatf() - the general printf function.
637  *
638  * It calls parsefmt() to parse the format string. It populates two arrays;
639  * one that describes the input arguments and one that describes a number of
640  * output segments.
641  *
642  * On success, the input array describes the type of all arguments and their
643  * values.
644  *
645  * The function then iterates over the output segments and outputs them one
646  * by one until done. Using the appropriate input arguments (if any).
647  *
648  * All output is sent to the 'stream()' callback, one byte at a time.
649  */
650 
formatf(void * userp,int (* stream)(unsigned char,void *),const char * format,va_list ap_save)651 static int formatf(
652   void *userp, /* untouched by format(), just sent to the stream() function in
653                   the second argument */
654   /* function pointer called for each output character */
655   int (*stream)(unsigned char, void *),
656   const char *format,    /* %-formatted string */
657   va_list ap_save) /* list of parameters */
658 {
659   static const char nilstr[] = "(nil)";
660   const char *digits = lower_digits;   /* Base-36 digits for numbers.  */
661   int done = 0;   /* number of characters written  */
662   int i;
663   int ocount = 0; /* number of output segments */
664   int icount = 0; /* number of input arguments */
665 
666   struct outsegment output[MAX_SEGMENTS];
667   struct va_input input[MAX_PARAMETERS];
668   char work[BUFFSIZE];
669 
670   /* 'workend' points to the final buffer byte position, but with an extra
671      byte as margin to avoid the (false?) warning Coverity gives us
672      otherwise */
673   char *workend = &work[sizeof(work) - 2];
674 
675   /* Parse the format string */
676   if(parsefmt(format, output, input, &ocount, &icount, ap_save))
677     return 0;
678 
679   for(i = 0; i < ocount; i++) {
680     struct outsegment *optr = &output[i];
681     struct va_input *iptr;
682     bool is_alt;            /* Format spec modifiers.  */
683     int width;              /* Width of a field.  */
684     int prec;               /* Precision of a field.  */
685     bool is_neg;            /* Decimal integer is negative.  */
686     unsigned long base;     /* Base of a number to be written.  */
687     mp_uintmax_t num;       /* Integral values to be written.  */
688     mp_intmax_t signed_num; /* Used to convert negative in positive.  */
689     char *w;
690     size_t outlen = optr->outlen;
691     unsigned int flags = optr->flags;
692 
693     if(outlen) {
694       char *str = optr->start;
695       for(; outlen && *str; outlen--)
696         OUTCHAR(*str++);
697       if(optr->flags & FLAGS_SUBSTR)
698         /* this is just a substring */
699         continue;
700     }
701 
702     /* pick up the specified width */
703     if(flags & FLAGS_WIDTHPARAM) {
704       width = (int)input[optr->width].val.nums;
705       if(width < 0) {
706         /* "A negative field width is taken as a '-' flag followed by a
707            positive field width." */
708         if(width == INT_MIN)
709           width = INT_MAX;
710         else
711           width = -width;
712         flags |= FLAGS_LEFT;
713         flags &= ~(unsigned int)FLAGS_PAD_NIL;
714       }
715     }
716     else
717       width = optr->width;
718 
719     /* pick up the specified precision */
720     if(flags & FLAGS_PRECPARAM) {
721       prec = (int)input[optr->precision].val.nums;
722       if(prec < 0)
723         /* "A negative precision is taken as if the precision were
724            omitted." */
725         prec = -1;
726     }
727     else if(flags & FLAGS_PREC)
728       prec = optr->precision;
729     else
730       prec = -1;
731 
732     is_alt = (flags & FLAGS_ALT) ? 1 : 0;
733     iptr = &input[optr->input];
734 
735     switch(iptr->type) {
736     case FORMAT_INTU:
737     case FORMAT_LONGU:
738     case FORMAT_LONGLONGU:
739       flags |= FLAGS_UNSIGNED;
740       FALLTHROUGH();
741     case FORMAT_INT:
742     case FORMAT_LONG:
743     case FORMAT_LONGLONG:
744       num = iptr->val.numu;
745       if(flags & FLAGS_CHAR) {
746         /* Character.  */
747         if(!(flags & FLAGS_LEFT))
748           while(--width > 0)
749             OUTCHAR(' ');
750         OUTCHAR((char) num);
751         if(flags & FLAGS_LEFT)
752           while(--width > 0)
753             OUTCHAR(' ');
754         break;
755       }
756       if(flags & FLAGS_OCTAL) {
757         /* Octal unsigned integer */
758         base = 8;
759         is_neg = FALSE;
760       }
761       else if(flags & FLAGS_HEX) {
762         /* Hexadecimal unsigned integer */
763         digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
764         base = 16;
765         is_neg = FALSE;
766       }
767       else if(flags & FLAGS_UNSIGNED) {
768         /* Decimal unsigned integer */
769         base = 10;
770         is_neg = FALSE;
771       }
772       else {
773         /* Decimal integer.  */
774         base = 10;
775 
776         is_neg = (iptr->val.nums < (mp_intmax_t)0);
777         if(is_neg) {
778           /* signed_num might fail to hold absolute negative minimum by 1 */
779           signed_num = iptr->val.nums + (mp_intmax_t)1;
780           signed_num = -signed_num;
781           num = (mp_uintmax_t)signed_num;
782           num += (mp_uintmax_t)1;
783         }
784       }
785 number:
786       /* Supply a default precision if none was given.  */
787       if(prec == -1)
788         prec = 1;
789 
790       /* Put the number in WORK.  */
791       w = workend;
792       switch(base) {
793       case 10:
794         while(num > 0) {
795           *w-- = (char)('0' + (num % 10));
796           num /= 10;
797         }
798         break;
799       default:
800         while(num > 0) {
801           *w-- = digits[num % base];
802           num /= base;
803         }
804         break;
805       }
806       width -= (int)(workend - w);
807       prec -= (int)(workend - w);
808 
809       if(is_alt && base == 8 && prec <= 0) {
810         *w-- = '0';
811         --width;
812       }
813 
814       if(prec > 0) {
815         width -= prec;
816         while(prec-- > 0 && w >= work)
817           *w-- = '0';
818       }
819 
820       if(is_alt && base == 16)
821         width -= 2;
822 
823       if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
824         --width;
825 
826       if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL))
827         while(width-- > 0)
828           OUTCHAR(' ');
829 
830       if(is_neg)
831         OUTCHAR('-');
832       else if(flags & FLAGS_SHOWSIGN)
833         OUTCHAR('+');
834       else if(flags & FLAGS_SPACE)
835         OUTCHAR(' ');
836 
837       if(is_alt && base == 16) {
838         OUTCHAR('0');
839         if(flags & FLAGS_UPPER)
840           OUTCHAR('X');
841         else
842           OUTCHAR('x');
843       }
844 
845       if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL))
846         while(width-- > 0)
847           OUTCHAR('0');
848 
849       /* Write the number.  */
850       while(++w <= workend) {
851         OUTCHAR(*w);
852       }
853 
854       if(flags & FLAGS_LEFT)
855         while(width-- > 0)
856           OUTCHAR(' ');
857       break;
858 
859     case FORMAT_STRING: {
860       const char *str;
861       size_t len;
862 
863       str = (char *)iptr->val.str;
864       if(!str) {
865         /* Write null string if there is space.  */
866         if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
867           str = nilstr;
868           len = sizeof(nilstr) - 1;
869           /* Disable quotes around (nil) */
870           flags &= ~(unsigned int)FLAGS_ALT;
871         }
872         else {
873           str = "";
874           len = 0;
875         }
876       }
877       else if(prec != -1)
878         len = (size_t)prec;
879       else if(*str == '\0')
880         len = 0;
881       else
882         len = strlen(str);
883 
884       width -= (len > INT_MAX) ? INT_MAX : (int)len;
885 
886       if(flags & FLAGS_ALT)
887         OUTCHAR('"');
888 
889       if(!(flags & FLAGS_LEFT))
890         while(width-- > 0)
891           OUTCHAR(' ');
892 
893       for(; len && *str; len--)
894         OUTCHAR(*str++);
895       if(flags & FLAGS_LEFT)
896         while(width-- > 0)
897           OUTCHAR(' ');
898 
899       if(flags & FLAGS_ALT)
900         OUTCHAR('"');
901       break;
902     }
903 
904     case FORMAT_PTR:
905       /* Generic pointer.  */
906       if(iptr->val.ptr) {
907         /* If the pointer is not NULL, write it as a %#x spec.  */
908         base = 16;
909         digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
910         is_alt = TRUE;
911         num = (size_t) iptr->val.ptr;
912         is_neg = FALSE;
913         goto number;
914       }
915       else {
916         /* Write "(nil)" for a nil pointer.  */
917         const char *point;
918 
919         width -= (int)(sizeof(nilstr) - 1);
920         if(flags & FLAGS_LEFT)
921           while(width-- > 0)
922             OUTCHAR(' ');
923         for(point = nilstr; *point != '\0'; ++point)
924           OUTCHAR(*point);
925         if(!(flags & FLAGS_LEFT))
926           while(width-- > 0)
927             OUTCHAR(' ');
928       }
929       break;
930 
931     case FORMAT_DOUBLE: {
932       char formatbuf[32]="%";
933       char *fptr = &formatbuf[1];
934       size_t left = sizeof(formatbuf)-strlen(formatbuf);
935       int len;
936 
937       if(flags & FLAGS_WIDTH)
938         width = optr->width;
939 
940       if(flags & FLAGS_PREC)
941         prec = optr->precision;
942 
943       if(flags & FLAGS_LEFT)
944         *fptr++ = '-';
945       if(flags & FLAGS_SHOWSIGN)
946         *fptr++ = '+';
947       if(flags & FLAGS_SPACE)
948         *fptr++ = ' ';
949       if(flags & FLAGS_ALT)
950         *fptr++ = '#';
951 
952       *fptr = 0;
953 
954       if(width >= 0) {
955         size_t dlen;
956         if(width >= (int)sizeof(work))
957           width = sizeof(work)-1;
958         /* RECURSIVE USAGE */
959         dlen = (size_t)curl_msnprintf(fptr, left, "%d", width);
960         fptr += dlen;
961         left -= dlen;
962       }
963       if(prec >= 0) {
964         /* for each digit in the integer part, we can have one less
965            precision */
966         size_t maxprec = sizeof(work) - 2;
967         double val = iptr->val.dnum;
968         if(width > 0 && prec <= width)
969           maxprec -= (size_t)width;
970         while(val >= 10.0) {
971           val /= 10;
972           maxprec--;
973         }
974 
975         if(prec > (int)maxprec)
976           prec = (int)maxprec-1;
977         if(prec < 0)
978           prec = 0;
979         /* RECURSIVE USAGE */
980         len = curl_msnprintf(fptr, left, ".%d", prec);
981         fptr += len;
982       }
983       if(flags & FLAGS_LONG)
984         *fptr++ = 'l';
985 
986       if(flags & FLAGS_FLOATE)
987         *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E' : 'e');
988       else if(flags & FLAGS_FLOATG)
989         *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
990       else
991         *fptr++ = 'f';
992 
993       *fptr = 0; /* and a final null-termination */
994 
995 #ifdef __clang__
996 #pragma clang diagnostic push
997 #pragma clang diagnostic ignored "-Wformat-nonliteral"
998 #endif
999       /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
1000          output characters */
1001 #ifdef HAVE_SNPRINTF
1002       (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum);
1003 #else
1004       (sprintf)(work, formatbuf, iptr->val.dnum);
1005 #endif
1006 #ifdef __clang__
1007 #pragma clang diagnostic pop
1008 #endif
1009       DEBUGASSERT(strlen(work) <= sizeof(work));
1010       for(fptr = work; *fptr; fptr++)
1011         OUTCHAR(*fptr);
1012       break;
1013     }
1014 
1015     case FORMAT_INTPTR:
1016       /* Answer the count of characters written.  */
1017 #ifdef HAVE_LONG_LONG_TYPE
1018       if(flags & FLAGS_LONGLONG)
1019         *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done;
1020       else
1021 #endif
1022         if(flags & FLAGS_LONG)
1023           *(long *) iptr->val.ptr = (long)done;
1024       else if(!(flags & FLAGS_SHORT))
1025         *(int *) iptr->val.ptr = (int)done;
1026       else
1027         *(short *) iptr->val.ptr = (short)done;
1028       break;
1029 
1030     default:
1031       break;
1032     }
1033   }
1034   return done;
1035 }
1036 
1037 /* fputc() look-alike */
addbyter(unsigned char outc,void * f)1038 static int addbyter(unsigned char outc, void *f)
1039 {
1040   struct nsprintf *infop = f;
1041   if(infop->length < infop->max) {
1042     /* only do this if we have not reached max length yet */
1043     *infop->buffer++ = (char)outc; /* store */
1044     infop->length++; /* we are now one byte larger */
1045     return 0;     /* fputc() returns like this on success */
1046   }
1047   return 1;
1048 }
1049 
curl_mvsnprintf(char * buffer,size_t maxlength,const char * format,va_list ap_save)1050 int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1051                     va_list ap_save)
1052 {
1053   int retcode;
1054   struct nsprintf info;
1055 
1056   info.buffer = buffer;
1057   info.length = 0;
1058   info.max = maxlength;
1059 
1060   retcode = formatf(&info, addbyter, format, ap_save);
1061   if(info.max) {
1062     /* we terminate this with a zero byte */
1063     if(info.max == info.length) {
1064       /* we are at maximum, scrap the last letter */
1065       info.buffer[-1] = 0;
1066       DEBUGASSERT(retcode);
1067       retcode--; /* do not count the nul byte */
1068     }
1069     else
1070       info.buffer[0] = 0;
1071   }
1072   return retcode;
1073 }
1074 
curl_msnprintf(char * buffer,size_t maxlength,const char * format,...)1075 int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1076 {
1077   int retcode;
1078   va_list ap_save; /* argument pointer */
1079   va_start(ap_save, format);
1080   retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1081   va_end(ap_save);
1082   return retcode;
1083 }
1084 
1085 /* fputc() look-alike */
alloc_addbyter(unsigned char outc,void * f)1086 static int alloc_addbyter(unsigned char outc, void *f)
1087 {
1088   struct asprintf *infop = f;
1089   CURLcode result = Curl_dyn_addn(infop->b, &outc, 1);
1090   if(result) {
1091     infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
1092     return 1 ; /* fail */
1093   }
1094   return 0;
1095 }
1096 
1097 /* appends the formatted string, returns MERR error code */
Curl_dyn_vprintf(struct dynbuf * dyn,const char * format,va_list ap_save)1098 int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
1099 {
1100   struct asprintf info;
1101   info.b = dyn;
1102   info.merr = MERR_OK;
1103 
1104   (void)formatf(&info, alloc_addbyter, format, ap_save);
1105   if(info.merr) {
1106     Curl_dyn_free(info.b);
1107     return info.merr;
1108   }
1109   return 0;
1110 }
1111 
curl_mvaprintf(const char * format,va_list ap_save)1112 char *curl_mvaprintf(const char *format, va_list ap_save)
1113 {
1114   struct asprintf info;
1115   struct dynbuf dyn;
1116   info.b = &dyn;
1117   Curl_dyn_init(info.b, DYN_APRINTF);
1118   info.merr = MERR_OK;
1119 
1120   (void)formatf(&info, alloc_addbyter, format, ap_save);
1121   if(info.merr) {
1122     Curl_dyn_free(info.b);
1123     return NULL;
1124   }
1125   if(Curl_dyn_len(info.b))
1126     return Curl_dyn_ptr(info.b);
1127   return strdup("");
1128 }
1129 
curl_maprintf(const char * format,...)1130 char *curl_maprintf(const char *format, ...)
1131 {
1132   va_list ap_save;
1133   char *s;
1134   va_start(ap_save, format);
1135   s = curl_mvaprintf(format, ap_save);
1136   va_end(ap_save);
1137   return s;
1138 }
1139 
storebuffer(unsigned char outc,void * f)1140 static int storebuffer(unsigned char outc, void *f)
1141 {
1142   char **buffer = f;
1143   **buffer = (char)outc;
1144   (*buffer)++;
1145   return 0;
1146 }
1147 
curl_msprintf(char * buffer,const char * format,...)1148 int curl_msprintf(char *buffer, const char *format, ...)
1149 {
1150   va_list ap_save; /* argument pointer */
1151   int retcode;
1152   va_start(ap_save, format);
1153   retcode = formatf(&buffer, storebuffer, format, ap_save);
1154   va_end(ap_save);
1155   *buffer = 0; /* we terminate this with a zero byte */
1156   return retcode;
1157 }
1158 
fputc_wrapper(unsigned char outc,void * f)1159 static int fputc_wrapper(unsigned char outc, void *f)
1160 {
1161   int out = outc;
1162   FILE *s = f;
1163   int rc = fputc(out, s);
1164   return rc == EOF;
1165 }
1166 
curl_mprintf(const char * format,...)1167 int curl_mprintf(const char *format, ...)
1168 {
1169   int retcode;
1170   va_list ap_save; /* argument pointer */
1171   va_start(ap_save, format);
1172 
1173   retcode = formatf(stdout, fputc_wrapper, format, ap_save);
1174   va_end(ap_save);
1175   return retcode;
1176 }
1177 
curl_mfprintf(FILE * whereto,const char * format,...)1178 int curl_mfprintf(FILE *whereto, const char *format, ...)
1179 {
1180   int retcode;
1181   va_list ap_save; /* argument pointer */
1182   va_start(ap_save, format);
1183   retcode = formatf(whereto, fputc_wrapper, format, ap_save);
1184   va_end(ap_save);
1185   return retcode;
1186 }
1187 
curl_mvsprintf(char * buffer,const char * format,va_list ap_save)1188 int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1189 {
1190   int retcode = formatf(&buffer, storebuffer, format, ap_save);
1191   *buffer = 0; /* we terminate this with a zero byte */
1192   return retcode;
1193 }
1194 
curl_mvprintf(const char * format,va_list ap_save)1195 int curl_mvprintf(const char *format, va_list ap_save)
1196 {
1197   return formatf(stdout, fputc_wrapper, format, ap_save);
1198 }
1199 
curl_mvfprintf(FILE * whereto,const char * format,va_list ap_save)1200 int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1201 {
1202   return formatf(whereto, fputc_wrapper, format, ap_save);
1203 }
1204