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