Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1999 - 2017, 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 /*
     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 
    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 
    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 
    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 
    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 */
    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 
    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 
   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 */
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1165 int curl_mvprintf(const char *format, va_list ap_save)
   1166 {
   1167   return dprintf_formatf(stdout, fputc, format, ap_save);
   1168 }
   1169 
   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