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