Annotation of embedaddon/curl/lib/mprintf.c, revision 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>