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