Coverage Report

Created: 2023-12-08 06:48

/src/curl/lib/mprintf.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) 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.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
 * SPDX-License-Identifier: curl
22
 *
23
 *
24
 * Purpose:
25
 *  A merge of Bjorn Reese's format() function and Daniel's dsprintf()
26
 *  1.0. A full blooded printf() clone with full support for <num>$
27
 *  everywhere (parameters, widths and precisions) including variabled
28
 *  sized parameters (like doubles, long longs, long doubles and even
29
 *  void * in 64-bit architectures).
30
 *
31
 * Current restrictions:
32
 * - Max 128 parameters
33
 * - No 'long double' support.
34
 *
35
 * If you ever want truly portable and good *printf() clones, the project that
36
 * took on from here is named 'Trio' and you find more details on the trio web
37
 * page at https://daniel.haxx.se/projects/trio/
38
 */
39
40
#include "curl_setup.h"
41
#include "dynbuf.h"
42
#include <curl/mprintf.h>
43
44
#include "curl_memory.h"
45
/* The last #include file should be: */
46
#include "memdebug.h"
47
48
/*
49
 * If SIZEOF_SIZE_T has not been defined, default to the size of long.
50
 */
51
52
#ifdef HAVE_LONGLONG
53
1.83k
#  define LONG_LONG_TYPE long long
54
#  define HAVE_LONG_LONG_TYPE
55
#else
56
#  if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
57
#    define LONG_LONG_TYPE __int64
58
#    define HAVE_LONG_LONG_TYPE
59
#  else
60
#    undef LONG_LONG_TYPE
61
#    undef HAVE_LONG_LONG_TYPE
62
#  endif
63
#endif
64
65
/*
66
 * Non-ANSI integer extensions
67
 */
68
69
#if (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
1.83k
#  define mp_intmax_t LONG_LONG_TYPE
81
1.83k
#  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
5.31k
#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
2.65k
  do {                                                 \
103
2.65k
    if(stream((unsigned char)(x), (FILE *)data) != -1) \
104
2.65k
      done++;                                          \
105
2.65k
    else                                               \
106
2.65k
      return done; /* return immediately on failure */ \
107
2.65k
  } 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
struct va_stack {
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
};
163
164
struct nsprintf {
165
  char *buffer;
166
  size_t length;
167
  size_t max;
168
};
169
170
struct asprintf {
171
  struct dynbuf *b;
172
  bool fail; /* if an alloc has failed and thus the output is not the complete
173
                data */
174
};
175
176
static long dprintf_DollarString(char *input, char **end)
177
2.12k
{
178
2.12k
  int number = 0;
179
2.12k
  while(ISDIGIT(*input)) {
180
0
    if(number < MAX_PARAMETERS) {
181
0
      number *= 10;
182
0
      number += *input - '0';
183
0
    }
184
0
    input++;
185
0
  }
186
2.12k
  if(number <= MAX_PARAMETERS && ('$' == *input)) {
187
0
    *end = ++input;
188
0
    return number;
189
0
  }
190
2.12k
  return 0;
191
2.12k
}
192
193
static bool dprintf_IsQualifierNoDollar(const char *fmt)
194
1.10k
{
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
1.10k
  switch(*fmt) {
202
0
  case '-': case '+': case ' ': case '#': case '.':
203
0
  case '0': case '1': case '2': case '3': case '4':
204
0
  case '5': case '6': case '7': case '8': case '9':
205
38
  case 'h': case 'l': case 'L': case 'z': case 'q':
206
38
  case '*': case 'O':
207
#if defined(MP_HAVE_INT_EXTENSIONS)
208
  case 'I':
209
#endif
210
38
    return TRUE;
211
212
1.06k
  default:
213
1.06k
    return FALSE;
214
1.10k
  }
215
1.10k
}
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, struct va_stack *vto,
228
                         char **endpos, va_list arglist)
229
294
{
230
294
  char *fmt = (char *)format;
231
294
  int param_num = 0;
232
294
  long this_param;
233
294
  long width;
234
294
  long precision;
235
294
  int flags;
236
294
  long max_param = 0;
237
294
  long i;
238
239
3.18k
  while(*fmt) {
240
2.89k
    if(*fmt++ == '%') {
241
1.06k
      if(*fmt == '%') {
242
0
        fmt++;
243
0
        continue; /* while */
244
0
      }
245
246
1.06k
      flags = FLAGS_NEW;
247
248
      /* Handle the positional case (N$) */
249
250
1.06k
      param_num++;
251
252
1.06k
      this_param = dprintf_DollarString(fmt, &fmt);
253
1.06k
      if(0 == this_param)
254
        /* we got no positional, get the next counter */
255
1.06k
        this_param = param_num;
256
257
1.06k
      if(this_param > max_param)
258
1.06k
        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
1.06k
      width = 0;
267
1.06k
      precision = 0;
268
269
      /* Handle the flags */
270
271
1.10k
      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
38
        switch(*fmt++) {
285
0
        case ' ':
286
0
          flags |= FLAGS_SPACE;
287
0
          break;
288
0
        case '+':
289
0
          flags |= FLAGS_SHOWSIGN;
290
0
          break;
291
0
        case '-':
292
0
          flags |= FLAGS_LEFT;
293
0
          flags &= ~FLAGS_PAD_NIL;
294
0
          break;
295
0
        case '#':
296
0
          flags |= FLAGS_ALT;
297
0
          break;
298
0
        case '.':
299
0
          if('*' == *fmt) {
300
            /* The precision is picked from a specified parameter */
301
302
0
            flags |= FLAGS_PRECPARAM;
303
0
            fmt++;
304
0
            param_num++;
305
306
0
            i = dprintf_DollarString(fmt, &fmt);
307
0
            if(i)
308
0
              precision = i;
309
0
            else
310
0
              precision = param_num;
311
312
0
            if(precision > max_param)
313
0
              max_param = precision;
314
0
          }
315
0
          else {
316
0
            flags |= FLAGS_PREC;
317
0
            precision = strtol(fmt, &fmt, 10);
318
0
          }
319
0
          if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
320
0
             (FLAGS_PREC | FLAGS_PRECPARAM))
321
            /* it is not permitted to use both kinds of precision for the same
322
               argument */
323
0
            return 1;
324
0
          break;
325
0
        case 'h':
326
0
          flags |= FLAGS_SHORT;
327
0
          break;
328
#if defined(MP_HAVE_INT_EXTENSIONS)
329
        case 'I':
330
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
331
          flags |= FLAGS_LONGLONG;
332
#else
333
          flags |= FLAGS_LONG;
334
#endif
335
          break;
336
#endif
337
38
        case 'l':
338
38
          if(flags & FLAGS_LONG)
339
0
            flags |= FLAGS_LONGLONG;
340
38
          else
341
38
            flags |= FLAGS_LONG;
342
38
          break;
343
0
        case 'L':
344
0
          flags |= FLAGS_LONGDOUBLE;
345
0
          break;
346
0
        case 'q':
347
0
          flags |= FLAGS_LONGLONG;
348
0
          break;
349
0
        case 'z':
350
          /* the code below generates a warning if -Wunreachable-code is
351
             used */
352
#if (SIZEOF_SIZE_T > SIZEOF_LONG)
353
          flags |= FLAGS_LONGLONG;
354
#else
355
0
          flags |= FLAGS_LONG;
356
0
#endif
357
0
          break;
358
0
        case 'O':
359
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
360
          flags |= FLAGS_LONGLONG;
361
#else
362
0
          flags |= FLAGS_LONG;
363
0
#endif
364
0
          break;
365
0
        case '0':
366
0
          if(!(flags & FLAGS_LEFT))
367
0
            flags |= FLAGS_PAD_NIL;
368
          /* FALLTHROUGH */
369
0
        case '1': case '2': case '3': case '4':
370
0
        case '5': case '6': case '7': case '8': case '9':
371
0
          flags |= FLAGS_WIDTH;
372
0
          width = strtol(fmt-1, &fmt, 10);
373
0
          break;
374
0
        case '*':  /* Special case */
375
0
          flags |= FLAGS_WIDTHPARAM;
376
0
          param_num++;
377
378
0
          i = dprintf_DollarString(fmt, &fmt);
379
0
          if(i)
380
0
            width = i;
381
0
          else
382
0
            width = param_num;
383
0
          if(width > max_param)
384
0
            max_param = width;
385
0
          break;
386
0
        case '\0':
387
0
          fmt--;
388
0
        default:
389
0
          break;
390
38
        }
391
38
      } /* switch */
392
393
      /* Handle the specifier */
394
395
1.06k
      i = this_param - 1;
396
397
1.06k
      if((i < 0) || (i >= MAX_PARAMETERS))
398
        /* out of allowed range */
399
0
        return 1;
400
401
1.06k
      switch(*fmt) {
402
0
      case 'S':
403
0
        flags |= FLAGS_ALT;
404
        /* FALLTHROUGH */
405
0
      case 's':
406
0
        vto[i].type = FORMAT_STRING;
407
0
        break;
408
0
      case 'n':
409
0
        vto[i].type = FORMAT_INTPTR;
410
0
        break;
411
0
      case 'p':
412
0
        vto[i].type = FORMAT_PTR;
413
0
        break;
414
38
      case 'd': case 'i':
415
38
        vto[i].type = FORMAT_INT;
416
38
        break;
417
1.02k
      case 'u':
418
1.02k
        vto[i].type = FORMAT_INT;
419
1.02k
        flags |= FLAGS_UNSIGNED;
420
1.02k
        break;
421
0
      case 'o':
422
0
        vto[i].type = FORMAT_INT;
423
0
        flags |= FLAGS_OCTAL;
424
0
        break;
425
0
      case 'x':
426
0
        vto[i].type = FORMAT_INT;
427
0
        flags |= FLAGS_HEX|FLAGS_UNSIGNED;
428
0
        break;
429
0
      case 'X':
430
0
        vto[i].type = FORMAT_INT;
431
0
        flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
432
0
        break;
433
0
      case 'c':
434
0
        vto[i].type = FORMAT_INT;
435
0
        flags |= FLAGS_CHAR;
436
0
        break;
437
0
      case 'f':
438
0
        vto[i].type = FORMAT_DOUBLE;
439
0
        break;
440
0
      case 'e':
441
0
        vto[i].type = FORMAT_DOUBLE;
442
0
        flags |= FLAGS_FLOATE;
443
0
        break;
444
0
      case 'E':
445
0
        vto[i].type = FORMAT_DOUBLE;
446
0
        flags |= FLAGS_FLOATE|FLAGS_UPPER;
447
0
        break;
448
0
      case 'g':
449
0
        vto[i].type = FORMAT_DOUBLE;
450
0
        flags |= FLAGS_FLOATG;
451
0
        break;
452
0
      case 'G':
453
0
        vto[i].type = FORMAT_DOUBLE;
454
0
        flags |= FLAGS_FLOATG|FLAGS_UPPER;
455
0
        break;
456
0
      default:
457
0
        vto[i].type = FORMAT_UNKNOWN;
458
0
        break;
459
1.06k
      } /* switch */
460
461
1.06k
      vto[i].flags = flags;
462
1.06k
      vto[i].width = width;
463
1.06k
      vto[i].precision = precision;
464
465
1.06k
      if(flags & FLAGS_WIDTHPARAM) {
466
        /* we have the width specified from a parameter, so we make that
467
           parameter's info setup properly */
468
0
        long k = width - 1;
469
0
        if((k < 0) || (k >= MAX_PARAMETERS))
470
          /* out of allowed range */
471
0
          return 1;
472
0
        vto[i].width = k;
473
0
        vto[k].type = FORMAT_WIDTH;
474
0
        vto[k].flags = FLAGS_NEW;
475
        /* can't use width or precision of width! */
476
0
        vto[k].width = 0;
477
0
        vto[k].precision = 0;
478
0
      }
479
1.06k
      if(flags & FLAGS_PRECPARAM) {
480
        /* we have the precision specified from a parameter, so we make that
481
           parameter's info setup properly */
482
0
        long k = precision - 1;
483
0
        if((k < 0) || (k >= MAX_PARAMETERS))
484
          /* out of allowed range */
485
0
          return 1;
486
0
        vto[i].precision = k;
487
0
        vto[k].type = FORMAT_WIDTH;
488
0
        vto[k].flags = FLAGS_NEW;
489
        /* can't use width or precision of width! */
490
0
        vto[k].width = 0;
491
0
        vto[k].precision = 0;
492
0
      }
493
1.06k
      *endpos++ = fmt + ((*fmt == '\0') ? 0 : 1); /* end of this sequence */
494
1.06k
    }
495
2.89k
  }
496
497
  /* Read the arg list parameters into our data list */
498
1.35k
  for(i = 0; i<max_param; i++) {
499
    /* Width/precision arguments must be read before the main argument
500
       they are attached to */
501
1.06k
    if(vto[i].flags & FLAGS_WIDTHPARAM) {
502
0
      vto[vto[i].width].data.num.as_signed =
503
0
        (mp_intmax_t)va_arg(arglist, int);
504
0
    }
505
1.06k
    if(vto[i].flags & FLAGS_PRECPARAM) {
506
0
      vto[vto[i].precision].data.num.as_signed =
507
0
        (mp_intmax_t)va_arg(arglist, int);
508
0
    }
509
510
1.06k
    switch(vto[i].type) {
511
0
    case FORMAT_STRING:
512
0
      vto[i].data.str = va_arg(arglist, char *);
513
0
      break;
514
515
0
    case FORMAT_INTPTR:
516
0
    case FORMAT_UNKNOWN:
517
0
    case FORMAT_PTR:
518
0
      vto[i].data.ptr = va_arg(arglist, void *);
519
0
      break;
520
521
1.06k
    case FORMAT_INT:
522
1.06k
#ifdef HAVE_LONG_LONG_TYPE
523
1.06k
      if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
524
0
        vto[i].data.num.as_unsigned =
525
0
          (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
526
1.06k
      else if(vto[i].flags & FLAGS_LONGLONG)
527
0
        vto[i].data.num.as_signed =
528
0
          (mp_intmax_t)va_arg(arglist, mp_intmax_t);
529
1.06k
      else
530
1.06k
#endif
531
1.06k
      {
532
1.06k
        if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
533
0
          vto[i].data.num.as_unsigned =
534
0
            (mp_uintmax_t)va_arg(arglist, unsigned long);
535
1.06k
        else if(vto[i].flags & FLAGS_LONG)
536
38
          vto[i].data.num.as_signed =
537
38
            (mp_intmax_t)va_arg(arglist, long);
538
1.02k
        else if(vto[i].flags & FLAGS_UNSIGNED)
539
1.02k
          vto[i].data.num.as_unsigned =
540
1.02k
            (mp_uintmax_t)va_arg(arglist, unsigned int);
541
0
        else
542
0
          vto[i].data.num.as_signed =
543
0
            (mp_intmax_t)va_arg(arglist, int);
544
1.06k
      }
545
1.06k
      break;
546
547
0
    case FORMAT_DOUBLE:
548
0
      vto[i].data.dnum = va_arg(arglist, double);
549
0
      break;
550
551
0
    case FORMAT_WIDTH:
552
      /* Argument has been read. Silently convert it into an integer
553
       * for later use
554
       */
555
0
      vto[i].type = FORMAT_INT;
556
0
      break;
557
558
0
    default:
559
0
      break;
560
1.06k
    }
561
1.06k
  }
562
563
294
  return 0;
564
565
294
}
566
567
static int dprintf_formatf(
568
  void *data, /* untouched by format(), just sent to the stream() function in
569
                 the second argument */
570
  /* function pointer called for each output character */
571
  int (*stream)(int, FILE *),
572
  const char *format,    /* %-formatted string */
573
  va_list ap_save) /* list of parameters */
574
294
{
575
  /* Base-36 digits for numbers.  */
576
294
  const char *digits = lower_digits;
577
578
  /* Pointer into the format string.  */
579
294
  char *f;
580
581
  /* Number of characters written.  */
582
294
  int done = 0;
583
584
294
  long param; /* current parameter to read */
585
294
  long param_num = 0; /* parameter counter */
586
587
294
  struct va_stack vto[MAX_PARAMETERS];
588
294
  char *endpos[MAX_PARAMETERS];
589
294
  char **end;
590
294
  char work[BUFFSIZE];
591
294
  struct va_stack *p;
592
593
  /* 'workend' points to the final buffer byte position, but with an extra
594
     byte as margin to avoid the (false?) warning Coverity gives us
595
     otherwise */
596
294
  char *workend = &work[sizeof(work) - 2];
597
598
  /* Do the actual %-code parsing */
599
294
  if(dprintf_Pass1(format, vto, endpos, ap_save))
600
0
    return 0;
601
602
294
  end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
603
                       created for us */
604
605
294
  f = (char *)format;
606
2.12k
  while(*f != '\0') {
607
    /* Format spec modifiers.  */
608
1.83k
    int is_alt;
609
610
    /* Width of a field.  */
611
1.83k
    long width;
612
613
    /* Precision of a field.  */
614
1.83k
    long prec;
615
616
    /* Decimal integer is negative.  */
617
1.83k
    int is_neg;
618
619
    /* Base of a number to be written.  */
620
1.83k
    unsigned long base;
621
622
    /* Integral values to be written.  */
623
1.83k
    mp_uintmax_t num;
624
625
    /* Used to convert negative in positive.  */
626
1.83k
    mp_intmax_t signed_num;
627
628
1.83k
    char *w;
629
630
1.83k
    if(*f != '%') {
631
      /* This isn't a format spec, so write everything out until the next one
632
         OR end of string is reached.  */
633
768
      do {
634
768
        OUTCHAR(*f);
635
768
      } while(*++f && ('%' != *f));
636
768
      continue;
637
768
    }
638
639
1.06k
    ++f;
640
641
    /* Check for "%%".  Note that although the ANSI standard lists
642
       '%' as a conversion specifier, it says "The complete format
643
       specification shall be `%%'," so we can avoid all the width
644
       and precision processing.  */
645
1.06k
    if(*f == '%') {
646
0
      ++f;
647
0
      OUTCHAR('%');
648
0
      continue;
649
0
    }
650
651
    /* If this is a positional parameter, the position must follow immediately
652
       after the %, thus create a %<num>$ sequence */
653
1.06k
    param = dprintf_DollarString(f, &f);
654
655
1.06k
    if(!param)
656
1.06k
      param = param_num;
657
0
    else
658
0
      --param;
659
660
1.06k
    param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
661
                    third %s will pick the 3rd argument */
662
663
1.06k
    p = &vto[param];
664
665
    /* pick up the specified width */
666
1.06k
    if(p->flags & FLAGS_WIDTHPARAM) {
667
0
      width = (long)vto[p->width].data.num.as_signed;
668
0
      param_num++; /* since the width is extracted from a parameter, we
669
                      must skip that to get to the next one properly */
670
0
      if(width < 0) {
671
        /* "A negative field width is taken as a '-' flag followed by a
672
           positive field width." */
673
0
        width = -width;
674
0
        p->flags |= FLAGS_LEFT;
675
0
        p->flags &= ~FLAGS_PAD_NIL;
676
0
      }
677
0
    }
678
1.06k
    else
679
1.06k
      width = p->width;
680
681
    /* pick up the specified precision */
682
1.06k
    if(p->flags & FLAGS_PRECPARAM) {
683
0
      prec = (long)vto[p->precision].data.num.as_signed;
684
0
      param_num++; /* since the precision is extracted from a parameter, we
685
                      must skip that to get to the next one properly */
686
0
      if(prec < 0)
687
        /* "A negative precision is taken as if the precision were
688
           omitted." */
689
0
        prec = -1;
690
0
    }
691
1.06k
    else if(p->flags & FLAGS_PREC)
692
0
      prec = p->precision;
693
1.06k
    else
694
1.06k
      prec = -1;
695
696
1.06k
    is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
697
698
1.06k
    switch(p->type) {
699
1.06k
    case FORMAT_INT:
700
1.06k
      num = p->data.num.as_unsigned;
701
1.06k
      if(p->flags & FLAGS_CHAR) {
702
        /* Character.  */
703
0
        if(!(p->flags & FLAGS_LEFT))
704
0
          while(--width > 0)
705
0
            OUTCHAR(' ');
706
0
        OUTCHAR((char) num);
707
0
        if(p->flags & FLAGS_LEFT)
708
0
          while(--width > 0)
709
0
            OUTCHAR(' ');
710
0
        break;
711
0
      }
712
1.06k
      if(p->flags & FLAGS_OCTAL) {
713
        /* Octal unsigned integer.  */
714
0
        base = 8;
715
0
        goto unsigned_number;
716
0
      }
717
1.06k
      else if(p->flags & FLAGS_HEX) {
718
        /* Hexadecimal unsigned integer.  */
719
720
0
        digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
721
0
        base = 16;
722
0
        goto unsigned_number;
723
0
      }
724
1.06k
      else if(p->flags & FLAGS_UNSIGNED) {
725
        /* Decimal unsigned integer.  */
726
1.02k
        base = 10;
727
1.02k
        goto unsigned_number;
728
1.02k
      }
729
730
      /* Decimal integer.  */
731
38
      base = 10;
732
733
38
      is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
734
38
      if(is_neg) {
735
        /* signed_num might fail to hold absolute negative minimum by 1 */
736
0
        signed_num = p->data.num.as_signed + (mp_intmax_t)1;
737
0
        signed_num = -signed_num;
738
0
        num = (mp_uintmax_t)signed_num;
739
0
        num += (mp_uintmax_t)1;
740
0
      }
741
742
38
      goto number;
743
744
1.02k
unsigned_number:
745
      /* Unsigned number of base BASE.  */
746
1.02k
      is_neg = 0;
747
748
1.06k
number:
749
      /* Number of base BASE.  */
750
751
      /* Supply a default precision if none was given.  */
752
1.06k
      if(prec == -1)
753
1.06k
        prec = 1;
754
755
      /* Put the number in WORK.  */
756
1.06k
      w = workend;
757
2.59k
      while(num > 0) {
758
1.52k
        *w-- = digits[num % base];
759
1.52k
        num /= base;
760
1.52k
      }
761
1.06k
      width -= (long)(workend - w);
762
1.06k
      prec -= (long)(workend - w);
763
764
1.06k
      if(is_alt && base == 8 && prec <= 0) {
765
0
        *w-- = '0';
766
0
        --width;
767
0
      }
768
769
1.06k
      if(prec > 0) {
770
357
        width -= prec;
771
714
        while(prec-- > 0 && w >= work)
772
357
          *w-- = '0';
773
357
      }
774
775
1.06k
      if(is_alt && base == 16)
776
0
        width -= 2;
777
778
1.06k
      if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
779
0
        --width;
780
781
1.06k
      if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
782
1.06k
        while(width-- > 0)
783
0
          OUTCHAR(' ');
784
785
1.06k
      if(is_neg)
786
0
        OUTCHAR('-');
787
1.06k
      else if(p->flags & FLAGS_SHOWSIGN)
788
0
        OUTCHAR('+');
789
1.06k
      else if(p->flags & FLAGS_SPACE)
790
0
        OUTCHAR(' ');
791
792
1.06k
      if(is_alt && base == 16) {
793
0
        OUTCHAR('0');
794
0
        if(p->flags & FLAGS_UPPER)
795
0
          OUTCHAR('X');
796
0
        else
797
0
          OUTCHAR('x');
798
0
      }
799
800
1.06k
      if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
801
0
        while(width-- > 0)
802
0
          OUTCHAR('0');
803
804
      /* Write the number.  */
805
2.94k
      while(++w <= workend) {
806
1.88k
        OUTCHAR(*w);
807
1.88k
      }
808
809
1.06k
      if(p->flags & FLAGS_LEFT)
810
0
        while(width-- > 0)
811
0
          OUTCHAR(' ');
812
1.06k
      break;
813
814
1.06k
    case FORMAT_STRING:
815
            /* String.  */
816
0
      {
817
0
        static const char null[] = "(nil)";
818
0
        const char *str;
819
0
        size_t len;
820
821
0
        str = (char *) p->data.str;
822
0
        if(!str) {
823
          /* Write null[] if there's space.  */
824
0
          if(prec == -1 || prec >= (long) sizeof(null) - 1) {
825
0
            str = null;
826
0
            len = sizeof(null) - 1;
827
            /* Disable quotes around (nil) */
828
0
            p->flags &= (~FLAGS_ALT);
829
0
          }
830
0
          else {
831
0
            str = "";
832
0
            len = 0;
833
0
          }
834
0
        }
835
0
        else if(prec != -1)
836
0
          len = (size_t)prec;
837
0
        else if(*str == '\0')
838
0
          len = 0;
839
0
        else
840
0
          len = strlen(str);
841
842
0
        width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
843
844
0
        if(p->flags & FLAGS_ALT)
845
0
          OUTCHAR('"');
846
847
0
        if(!(p->flags&FLAGS_LEFT))
848
0
          while(width-- > 0)
849
0
            OUTCHAR(' ');
850
851
0
        for(; len && *str; len--)
852
0
          OUTCHAR(*str++);
853
0
        if(p->flags&FLAGS_LEFT)
854
0
          while(width-- > 0)
855
0
            OUTCHAR(' ');
856
857
0
        if(p->flags & FLAGS_ALT)
858
0
          OUTCHAR('"');
859
0
      }
860
0
      break;
861
862
0
    case FORMAT_PTR:
863
      /* Generic pointer.  */
864
0
      {
865
0
        void *ptr;
866
0
        ptr = (void *) p->data.ptr;
867
0
        if(ptr) {
868
          /* If the pointer is not NULL, write it as a %#x spec.  */
869
0
          base = 16;
870
0
          digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
871
0
          is_alt = 1;
872
0
          num = (size_t) ptr;
873
0
          is_neg = 0;
874
0
          goto number;
875
0
        }
876
0
        else {
877
          /* Write "(nil)" for a nil pointer.  */
878
0
          static const char strnil[] = "(nil)";
879
0
          const char *point;
880
881
0
          width -= (long)(sizeof(strnil) - 1);
882
0
          if(p->flags & FLAGS_LEFT)
883
0
            while(width-- > 0)
884
0
              OUTCHAR(' ');
885
0
          for(point = strnil; *point != '\0'; ++point)
886
0
            OUTCHAR(*point);
887
0
          if(!(p->flags & FLAGS_LEFT))
888
0
            while(width-- > 0)
889
0
              OUTCHAR(' ');
890
0
        }
891
0
      }
892
0
      break;
893
894
0
    case FORMAT_DOUBLE:
895
0
      {
896
0
        char formatbuf[32]="%";
897
0
        char *fptr = &formatbuf[1];
898
0
        size_t left = sizeof(formatbuf)-strlen(formatbuf);
899
0
        int len;
900
901
0
        width = -1;
902
0
        if(p->flags & FLAGS_WIDTH)
903
0
          width = p->width;
904
0
        else if(p->flags & FLAGS_WIDTHPARAM)
905
0
          width = (long)vto[p->width].data.num.as_signed;
906
907
0
        prec = -1;
908
0
        if(p->flags & FLAGS_PREC)
909
0
          prec = p->precision;
910
0
        else if(p->flags & FLAGS_PRECPARAM)
911
0
          prec = (long)vto[p->precision].data.num.as_signed;
912
913
0
        if(p->flags & FLAGS_LEFT)
914
0
          *fptr++ = '-';
915
0
        if(p->flags & FLAGS_SHOWSIGN)
916
0
          *fptr++ = '+';
917
0
        if(p->flags & FLAGS_SPACE)
918
0
          *fptr++ = ' ';
919
0
        if(p->flags & FLAGS_ALT)
920
0
          *fptr++ = '#';
921
922
0
        *fptr = 0;
923
924
0
        if(width >= 0) {
925
0
          if(width >= (long)sizeof(work))
926
0
            width = sizeof(work)-1;
927
          /* RECURSIVE USAGE */
928
0
          len = curl_msnprintf(fptr, left, "%ld", width);
929
0
          fptr += len;
930
0
          left -= len;
931
0
        }
932
0
        if(prec >= 0) {
933
          /* for each digit in the integer part, we can have one less
934
             precision */
935
0
          size_t maxprec = sizeof(work) - 2;
936
0
          double val = p->data.dnum;
937
0
          if(width > 0 && prec <= width)
938
0
            maxprec -= width;
939
0
          while(val >= 10.0) {
940
0
            val /= 10;
941
0
            maxprec--;
942
0
          }
943
944
0
          if(prec > (long)maxprec)
945
0
            prec = (long)maxprec-1;
946
0
          if(prec < 0)
947
0
            prec = 0;
948
          /* RECURSIVE USAGE */
949
0
          len = curl_msnprintf(fptr, left, ".%ld", prec);
950
0
          fptr += len;
951
0
        }
952
0
        if(p->flags & FLAGS_LONG)
953
0
          *fptr++ = 'l';
954
955
0
        if(p->flags & FLAGS_FLOATE)
956
0
          *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
957
0
        else if(p->flags & FLAGS_FLOATG)
958
0
          *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g');
959
0
        else
960
0
          *fptr++ = 'f';
961
962
0
        *fptr = 0; /* and a final null-termination */
963
964
0
#ifdef __clang__
965
0
#pragma clang diagnostic push
966
0
#pragma clang diagnostic ignored "-Wformat-nonliteral"
967
0
#endif
968
        /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
969
           output characters */
970
0
#ifdef HAVE_SNPRINTF
971
0
        (snprintf)(work, sizeof(work), formatbuf, p->data.dnum);
972
#else
973
        (sprintf)(work, formatbuf, p->data.dnum);
974
#endif
975
0
#ifdef __clang__
976
0
#pragma clang diagnostic pop
977
0
#endif
978
0
        DEBUGASSERT(strlen(work) <= sizeof(work));
979
0
        for(fptr = work; *fptr; fptr++)
980
0
          OUTCHAR(*fptr);
981
0
      }
982
0
      break;
983
984
0
    case FORMAT_INTPTR:
985
      /* Answer the count of characters written.  */
986
0
#ifdef HAVE_LONG_LONG_TYPE
987
0
      if(p->flags & FLAGS_LONGLONG)
988
0
        *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done;
989
0
      else
990
0
#endif
991
0
        if(p->flags & FLAGS_LONG)
992
0
          *(long *) p->data.ptr = (long)done;
993
0
      else if(!(p->flags & FLAGS_SHORT))
994
0
        *(int *) p->data.ptr = (int)done;
995
0
      else
996
0
        *(short *) p->data.ptr = (short)done;
997
0
      break;
998
999
0
    default:
1000
0
      break;
1001
1.06k
    }
1002
1.06k
    f = *end++; /* goto end of %-code */
1003
1004
1.06k
  }
1005
294
  return done;
1006
294
}
1007
1008
/* fputc() look-alike */
1009
static int addbyter(int output, FILE *data)
1010
0
{
1011
0
  struct nsprintf *infop = (struct nsprintf *)data;
1012
0
  unsigned char outc = (unsigned char)output;
1013
1014
0
  if(infop->length < infop->max) {
1015
    /* only do this if we haven't reached max length yet */
1016
0
    infop->buffer[0] = outc; /* store */
1017
0
    infop->buffer++; /* increase pointer */
1018
0
    infop->length++; /* we are now one byte larger */
1019
0
    return outc;     /* fputc() returns like this on success */
1020
0
  }
1021
0
  return -1;
1022
0
}
1023
1024
int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1025
                    va_list ap_save)
1026
0
{
1027
0
  int retcode;
1028
0
  struct nsprintf info;
1029
1030
0
  info.buffer = buffer;
1031
0
  info.length = 0;
1032
0
  info.max = maxlength;
1033
1034
0
  retcode = dprintf_formatf(&info, addbyter, format, ap_save);
1035
0
  if(info.max) {
1036
    /* we terminate this with a zero byte */
1037
0
    if(info.max == info.length) {
1038
      /* we're at maximum, scrap the last letter */
1039
0
      info.buffer[-1] = 0;
1040
0
      DEBUGASSERT(retcode);
1041
0
      retcode--; /* don't count the nul byte */
1042
0
    }
1043
0
    else
1044
0
      info.buffer[0] = 0;
1045
0
  }
1046
0
  return retcode;
1047
0
}
1048
1049
int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1050
0
{
1051
0
  int retcode;
1052
0
  va_list ap_save; /* argument pointer */
1053
0
  va_start(ap_save, format);
1054
0
  retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1055
0
  va_end(ap_save);
1056
0
  return retcode;
1057
0
}
1058
1059
/* fputc() look-alike */
1060
static int alloc_addbyter(int output, FILE *data)
1061
2.65k
{
1062
2.65k
  struct asprintf *infop = (struct asprintf *)data;
1063
2.65k
  unsigned char outc = (unsigned char)output;
1064
1065
2.65k
  if(Curl_dyn_addn(infop->b, &outc, 1)) {
1066
0
    infop->fail = 1;
1067
0
    return -1; /* fail */
1068
0
  }
1069
2.65k
  return outc; /* fputc() returns like this on success */
1070
2.65k
}
1071
1072
/* appends the formatted string, returns 0 on success, 1 on error */
1073
int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
1074
256
{
1075
256
  struct asprintf info;
1076
256
  info.b = dyn;
1077
256
  info.fail = 0;
1078
1079
256
  (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1080
256
  if(info.fail) {
1081
0
    Curl_dyn_free(info.b);
1082
0
    return 1;
1083
0
  }
1084
256
  return 0;
1085
256
}
1086
1087
char *curl_mvaprintf(const char *format, va_list ap_save)
1088
38
{
1089
38
  struct asprintf info;
1090
38
  struct dynbuf dyn;
1091
38
  info.b = &dyn;
1092
38
  Curl_dyn_init(info.b, DYN_APRINTF);
1093
38
  info.fail = 0;
1094
1095
38
  (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1096
38
  if(info.fail) {
1097
0
    Curl_dyn_free(info.b);
1098
0
    return NULL;
1099
0
  }
1100
38
  if(Curl_dyn_len(info.b))
1101
38
    return Curl_dyn_ptr(info.b);
1102
0
  return strdup("");
1103
38
}
1104
1105
char *curl_maprintf(const char *format, ...)
1106
38
{
1107
38
  va_list ap_save;
1108
38
  char *s;
1109
38
  va_start(ap_save, format);
1110
38
  s = curl_mvaprintf(format, ap_save);
1111
38
  va_end(ap_save);
1112
38
  return s;
1113
38
}
1114
1115
static int storebuffer(int output, FILE *data)
1116
0
{
1117
0
  char **buffer = (char **)data;
1118
0
  unsigned char outc = (unsigned char)output;
1119
0
  **buffer = outc;
1120
0
  (*buffer)++;
1121
0
  return outc; /* act like fputc() ! */
1122
0
}
1123
1124
int curl_msprintf(char *buffer, const char *format, ...)
1125
0
{
1126
0
  va_list ap_save; /* argument pointer */
1127
0
  int retcode;
1128
0
  va_start(ap_save, format);
1129
0
  retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1130
0
  va_end(ap_save);
1131
0
  *buffer = 0; /* we terminate this with a zero byte */
1132
0
  return retcode;
1133
0
}
1134
1135
int curl_mprintf(const char *format, ...)
1136
0
{
1137
0
  int retcode;
1138
0
  va_list ap_save; /* argument pointer */
1139
0
  va_start(ap_save, format);
1140
1141
0
  retcode = dprintf_formatf(stdout, fputc, format, ap_save);
1142
0
  va_end(ap_save);
1143
0
  return retcode;
1144
0
}
1145
1146
int curl_mfprintf(FILE *whereto, const char *format, ...)
1147
0
{
1148
0
  int retcode;
1149
0
  va_list ap_save; /* argument pointer */
1150
0
  va_start(ap_save, format);
1151
0
  retcode = dprintf_formatf(whereto, fputc, format, ap_save);
1152
0
  va_end(ap_save);
1153
0
  return retcode;
1154
0
}
1155
1156
int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1157
0
{
1158
0
  int retcode;
1159
0
  retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1160
0
  *buffer = 0; /* we terminate this with a zero byte */
1161
0
  return retcode;
1162
0
}
1163
1164
int curl_mvprintf(const char *format, va_list ap_save)
1165
0
{
1166
0
  return dprintf_formatf(stdout, fputc, format, ap_save);
1167
0
}
1168
1169
int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1170
0
{
1171
0
  return dprintf_formatf(whereto, fputc, format, ap_save);
1172
0
}