Annotation of embedaddon/curl/lib/mprintf.c, revision 1.1.1.1

1.1       misho       1: /***************************************************************************
                      2:  *                                  _   _ ____  _
                      3:  *  Project                     ___| | | |  _ \| |
                      4:  *                             / __| | | | |_) | |
                      5:  *                            | (__| |_| |  _ <| |___
                      6:  *                             \___|\___/|_| \_\_____|
                      7:  *
                      8:  * Copyright (C) 1999 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
                      9:  *
                     10:  * This software is licensed as described in the file COPYING, which
                     11:  * you should have received as part of this distribution. The terms
                     12:  * are also available at https://curl.haxx.se/docs/copyright.html.
                     13:  *
                     14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
                     15:  * copies of the Software, and permit persons to whom the Software is
                     16:  * furnished to do so, under the terms of the COPYING file.
                     17:  *
                     18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
                     19:  * KIND, either express or implied.
                     20:  *
                     21:  *
                     22:  * Purpose:
                     23:  *  A merge of Bjorn Reese's format() function and Daniel's dsprintf()
                     24:  *  1.0. A full blooded printf() clone with full support for <num>$
                     25:  *  everywhere (parameters, widths and precisions) including variabled
                     26:  *  sized parameters (like doubles, long longs, long doubles and even
                     27:  *  void * in 64-bit architectures).
                     28:  *
                     29:  * Current restrictions:
                     30:  * - Max 128 parameters
                     31:  * - No 'long double' support.
                     32:  *
                     33:  * If you ever want truly portable and good *printf() clones, the project that
                     34:  * took on from here is named 'Trio' and you find more details on the trio web
                     35:  * page at https://daniel.haxx.se/projects/trio/
                     36:  */
                     37: 
                     38: #include "curl_setup.h"
                     39: #include <curl/mprintf.h>
                     40: 
                     41: #include "curl_memory.h"
                     42: /* The last #include file should be: */
                     43: #include "memdebug.h"
                     44: 
                     45: /*
                     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(0)
                    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:         for(; len && *str; len--)
                    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: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>