Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1999 - 2016, Daniel Stenberg, <daniel (at) 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 
    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 
    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 
    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 
    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 */
    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 
    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 
   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 */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1161 int curl_mvprintf(const char *format, va_list ap_save)
   1162 {
   1163   return dprintf_formatf(stdout, fputc, format, ap_save);
   1164 }
   1165 
   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