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