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