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>