File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / mprintf.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>