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
25 #include "curl_setup.h"
26 #include "dynbuf.h"
27 #include "curl_printf.h"
28
29 #include "curl_memory.h"
30 /* The last #include file should be: */
31 #include "memdebug.h"
32
33 /*
34 * If SIZEOF_SIZE_T has not been defined, default to the size of long.
35 */
36
37 #ifdef HAVE_LONGLONG
38 # define LONG_LONG_TYPE long long
39 # define HAVE_LONG_LONG_TYPE
40 #else
41 # if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
42 # define LONG_LONG_TYPE __int64
43 # define HAVE_LONG_LONG_TYPE
44 # else
45 # undef LONG_LONG_TYPE
46 # undef HAVE_LONG_LONG_TYPE
47 # endif
48 #endif
49
50 /*
51 * Max integer data types that mprintf.c is capable
52 */
53
54 #ifdef HAVE_LONG_LONG_TYPE
55 # define mp_intmax_t LONG_LONG_TYPE
56 # define mp_uintmax_t unsigned LONG_LONG_TYPE
57 #else
58 # define mp_intmax_t long
59 # define mp_uintmax_t unsigned long
60 #endif
61
62 #define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
63 fit negative DBL_MAX (317 letters) */
64 #define MAX_PARAMETERS 128 /* number of input arguments */
65 #define MAX_SEGMENTS 128 /* number of output segments */
66
67 #ifdef __AMIGA__
68 # undef FORMAT_INT
69 #endif
70
71 /* Lower-case digits. */
72 static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
73
74 /* Upper-case digits. */
75 static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
76
77 #define OUTCHAR(x) \
78 do { \
79 if(!stream((unsigned char)x, userp)) \
80 done++; \
81 else \
82 return done; /* return on failure */ \
83 } while(0)
84
85 /* Data type to read from the arglist */
86 typedef enum {
87 FORMAT_STRING,
88 FORMAT_PTR,
89 FORMAT_INTPTR,
90 FORMAT_INT,
91 FORMAT_LONG,
92 FORMAT_LONGLONG,
93 FORMAT_INTU,
94 FORMAT_LONGU,
95 FORMAT_LONGLONGU,
96 FORMAT_DOUBLE,
97 FORMAT_LONGDOUBLE,
98 FORMAT_WIDTH,
99 FORMAT_PRECISION
100 } FormatType;
101
102 /* conversion and display flags */
103 enum {
104 FLAGS_SPACE = 1 << 0,
105 FLAGS_SHOWSIGN = 1 << 1,
106 FLAGS_LEFT = 1 << 2,
107 FLAGS_ALT = 1 << 3,
108 FLAGS_SHORT = 1 << 4,
109 FLAGS_LONG = 1 << 5,
110 FLAGS_LONGLONG = 1 << 6,
111 FLAGS_LONGDOUBLE = 1 << 7,
112 FLAGS_PAD_NIL = 1 << 8,
113 FLAGS_UNSIGNED = 1 << 9,
114 FLAGS_OCTAL = 1 << 10,
115 FLAGS_HEX = 1 << 11,
116 FLAGS_UPPER = 1 << 12,
117 FLAGS_WIDTH = 1 << 13, /* '*' or '*<num>$' used */
118 FLAGS_WIDTHPARAM = 1 << 14, /* width PARAMETER was specified */
119 FLAGS_PREC = 1 << 15, /* precision was specified */
120 FLAGS_PRECPARAM = 1 << 16, /* precision PARAMETER was specified */
121 FLAGS_CHAR = 1 << 17, /* %c story */
122 FLAGS_FLOATE = 1 << 18, /* %e or %E */
123 FLAGS_FLOATG = 1 << 19, /* %g or %G */
124 FLAGS_SUBSTR = 1 << 20 /* no input, only substring */
125 };
126
127 enum {
128 DOLLAR_UNKNOWN,
129 DOLLAR_NOPE,
130 DOLLAR_USE
131 };
132
133 /*
134 * Describes an input va_arg type and hold its value.
135 */
136 struct va_input {
137 FormatType type; /* FormatType */
138 union {
139 char *str;
140 void *ptr;
141 mp_intmax_t nums; /* signed */
142 mp_uintmax_t numu; /* unsigned */
143 double dnum;
144 } val;
145 };
146
147 /*
148 * Describes an output segment.
149 */
150 struct outsegment {
151 int width; /* width OR width parameter number */
152 int precision; /* precision OR precision parameter number */
153 unsigned int flags;
154 unsigned int input; /* input argument array index */
155 char *start; /* format string start to output */
156 size_t outlen; /* number of bytes from the format string to output */
157 };
158
159 struct nsprintf {
160 char *buffer;
161 size_t length;
162 size_t max;
163 };
164
165 struct asprintf {
166 struct dynbuf *b;
167 char merr;
168 };
169
170 /* the provided input number is 1-based but this returns the number 0-based.
171
172 returns -1 if no valid number was provided.
173 */
dollarstring(char * input,char ** end)174 static int dollarstring(char *input, char **end)
175 {
176 if(ISDIGIT(*input)) {
177 int number = 0;
178 do {
179 if(number < MAX_PARAMETERS) {
180 number *= 10;
181 number += *input - '0';
182 }
183 input++;
184 } while(ISDIGIT(*input));
185
186 if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) {
187 *end = ++input;
188 return number - 1;
189 }
190 }
191 return -1;
192 }
193
194 /*
195 * Parse the format string.
196 *
197 * Create two arrays. One describes the inputs, one describes the outputs.
198 *
199 * Returns zero on success.
200 */
201
202 #define PFMT_OK 0
203 #define PFMT_DOLLAR 1 /* bad dollar for main param */
204 #define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */
205 #define PFMT_DOLLARPREC 3 /* bad dollar use for precision */
206 #define PFMT_MANYARGS 4 /* too many input arguments used */
207 #define PFMT_PREC 5 /* precision overflow */
208 #define PFMT_PRECMIX 6 /* bad mix of precision specifiers */
209 #define PFMT_WIDTH 7 /* width overflow */
210 #define PFMT_INPUTGAP 8 /* gap in arguments */
211 #define PFMT_WIDTHARG 9 /* attempted to use same arg twice, for width */
212 #define PFMT_PRECARG 10 /* attempted to use same arg twice, for prec */
213 #define PFMT_MANYSEGS 11 /* maxed out output segments */
214
parsefmt(const char * format,struct outsegment * out,struct va_input * in,int * opieces,int * ipieces,va_list arglist)215 static int parsefmt(const char *format,
216 struct outsegment *out,
217 struct va_input *in,
218 int *opieces,
219 int *ipieces, va_list arglist)
220 {
221 char *fmt = (char *)format;
222 int param_num = 0;
223 int param;
224 int width;
225 int precision;
226 unsigned int flags;
227 FormatType type;
228 int max_param = -1;
229 int i;
230 int ocount = 0;
231 unsigned char usedinput[MAX_PARAMETERS/8];
232 size_t outlen = 0;
233 struct outsegment *optr;
234 int use_dollar = DOLLAR_UNKNOWN;
235 char *start = fmt;
236
237 /* clear, set a bit for each used input */
238 memset(usedinput, 0, sizeof(usedinput));
239
240 while(*fmt) {
241 if(*fmt == '%') {
242 struct va_input *iptr;
243 bool loopit = TRUE;
244 fmt++;
245 outlen = (size_t)(fmt - start - 1);
246 if(*fmt == '%') {
247 /* this means a %% that should be output only as %. Create an output
248 segment. */
249 if(outlen) {
250 optr = &out[ocount++];
251 if(ocount > MAX_SEGMENTS)
252 return PFMT_MANYSEGS;
253 optr->input = 0;
254 optr->flags = FLAGS_SUBSTR;
255 optr->start = start;
256 optr->outlen = outlen;
257 }
258 start = fmt;
259 fmt++;
260 continue; /* while */
261 }
262
263 flags = 0;
264 width = precision = 0;
265
266 if(use_dollar != DOLLAR_NOPE) {
267 param = dollarstring(fmt, &fmt);
268 if(param < 0) {
269 if(use_dollar == DOLLAR_USE)
270 /* illegal combo */
271 return PFMT_DOLLAR;
272
273 /* we got no positional, just get the next arg */
274 param = -1;
275 use_dollar = DOLLAR_NOPE;
276 }
277 else
278 use_dollar = DOLLAR_USE;
279 }
280 else
281 param = -1;
282
283 /* Handle the flags */
284 while(loopit) {
285 switch(*fmt++) {
286 case ' ':
287 flags |= FLAGS_SPACE;
288 break;
289 case '+':
290 flags |= FLAGS_SHOWSIGN;
291 break;
292 case '-':
293 flags |= FLAGS_LEFT;
294 flags &= ~(unsigned int)FLAGS_PAD_NIL;
295 break;
296 case '#':
297 flags |= FLAGS_ALT;
298 break;
299 case '.':
300 if('*' == *fmt) {
301 /* The precision is picked from a specified parameter */
302 flags |= FLAGS_PRECPARAM;
303 fmt++;
304
305 if(use_dollar == DOLLAR_USE) {
306 precision = dollarstring(fmt, &fmt);
307 if(precision < 0)
308 /* illegal combo */
309 return PFMT_DOLLARPREC;
310 }
311 else
312 /* get it from the next argument */
313 precision = -1;
314 }
315 else {
316 bool is_neg = FALSE;
317 flags |= FLAGS_PREC;
318 precision = 0;
319 if('-' == *fmt) {
320 is_neg = TRUE;
321 fmt++;
322 }
323 while(ISDIGIT(*fmt)) {
324 if(precision > INT_MAX/10)
325 return PFMT_PREC;
326 precision *= 10;
327 precision += *fmt - '0';
328 fmt++;
329 }
330 if(is_neg)
331 precision = -precision;
332 }
333 if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
334 (FLAGS_PREC | FLAGS_PRECPARAM))
335 /* it is not permitted to use both kinds of precision for the same
336 argument */
337 return PFMT_PRECMIX;
338 break;
339 case 'h':
340 flags |= FLAGS_SHORT;
341 break;
342 #if defined(_WIN32) || defined(_WIN32_WCE)
343 case 'I':
344 /* Non-ANSI integer extensions I32 I64 */
345 if((fmt[0] == '3') && (fmt[1] == '2')) {
346 flags |= FLAGS_LONG;
347 fmt += 2;
348 }
349 else if((fmt[0] == '6') && (fmt[1] == '4')) {
350 flags |= FLAGS_LONGLONG;
351 fmt += 2;
352 }
353 else {
354 #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
355 flags |= FLAGS_LONGLONG;
356 #else
357 flags |= FLAGS_LONG;
358 #endif
359 }
360 break;
361 #endif /* _WIN32 || _WIN32_WCE */
362 case 'l':
363 if(flags & FLAGS_LONG)
364 flags |= FLAGS_LONGLONG;
365 else
366 flags |= FLAGS_LONG;
367 break;
368 case 'L':
369 flags |= FLAGS_LONGDOUBLE;
370 break;
371 case 'q':
372 flags |= FLAGS_LONGLONG;
373 break;
374 case 'z':
375 /* the code below generates a warning if -Wunreachable-code is
376 used */
377 #if (SIZEOF_SIZE_T > SIZEOF_LONG)
378 flags |= FLAGS_LONGLONG;
379 #else
380 flags |= FLAGS_LONG;
381 #endif
382 break;
383 case 'O':
384 #if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
385 flags |= FLAGS_LONGLONG;
386 #else
387 flags |= FLAGS_LONG;
388 #endif
389 break;
390 case '0':
391 if(!(flags & FLAGS_LEFT))
392 flags |= FLAGS_PAD_NIL;
393 FALLTHROUGH();
394 case '1': case '2': case '3': case '4':
395 case '5': case '6': case '7': case '8': case '9':
396 flags |= FLAGS_WIDTH;
397 width = 0;
398 fmt--;
399 do {
400 if(width > INT_MAX/10)
401 return PFMT_WIDTH;
402 width *= 10;
403 width += *fmt - '0';
404 fmt++;
405 } while(ISDIGIT(*fmt));
406 break;
407 case '*': /* read width from argument list */
408 flags |= FLAGS_WIDTHPARAM;
409 if(use_dollar == DOLLAR_USE) {
410 width = dollarstring(fmt, &fmt);
411 if(width < 0)
412 /* illegal combo */
413 return PFMT_DOLLARWIDTH;
414 }
415 else
416 /* pick from the next argument */
417 width = -1;
418 break;
419 default:
420 loopit = FALSE;
421 fmt--;
422 break;
423 } /* switch */
424 } /* while */
425
426 switch(*fmt) {
427 case 'S':
428 flags |= FLAGS_ALT;
429 FALLTHROUGH();
430 case 's':
431 type = FORMAT_STRING;
432 break;
433 case 'n':
434 type = FORMAT_INTPTR;
435 break;
436 case 'p':
437 type = FORMAT_PTR;
438 break;
439 case 'd':
440 case 'i':
441 if(flags & FLAGS_LONGLONG)
442 type = FORMAT_LONGLONG;
443 else if(flags & FLAGS_LONG)
444 type = FORMAT_LONG;
445 else
446 type = FORMAT_INT;
447 break;
448 case 'u':
449 if(flags & FLAGS_LONGLONG)
450 type = FORMAT_LONGLONGU;
451 else if(flags & FLAGS_LONG)
452 type = FORMAT_LONGU;
453 else
454 type = FORMAT_INTU;
455 flags |= FLAGS_UNSIGNED;
456 break;
457 case 'o':
458 if(flags & FLAGS_LONGLONG)
459 type = FORMAT_LONGLONGU;
460 else if(flags & FLAGS_LONG)
461 type = FORMAT_LONGU;
462 else
463 type = FORMAT_INTU;
464 flags |= FLAGS_OCTAL|FLAGS_UNSIGNED;
465 break;
466 case 'x':
467 if(flags & FLAGS_LONGLONG)
468 type = FORMAT_LONGLONGU;
469 else if(flags & FLAGS_LONG)
470 type = FORMAT_LONGU;
471 else
472 type = FORMAT_INTU;
473 flags |= FLAGS_HEX|FLAGS_UNSIGNED;
474 break;
475 case 'X':
476 if(flags & FLAGS_LONGLONG)
477 type = FORMAT_LONGLONGU;
478 else if(flags & FLAGS_LONG)
479 type = FORMAT_LONGU;
480 else
481 type = FORMAT_INTU;
482 flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
483 break;
484 case 'c':
485 type = FORMAT_INT;
486 flags |= FLAGS_CHAR;
487 break;
488 case 'f':
489 type = FORMAT_DOUBLE;
490 break;
491 case 'e':
492 type = FORMAT_DOUBLE;
493 flags |= FLAGS_FLOATE;
494 break;
495 case 'E':
496 type = FORMAT_DOUBLE;
497 flags |= FLAGS_FLOATE|FLAGS_UPPER;
498 break;
499 case 'g':
500 type = FORMAT_DOUBLE;
501 flags |= FLAGS_FLOATG;
502 break;
503 case 'G':
504 type = FORMAT_DOUBLE;
505 flags |= FLAGS_FLOATG|FLAGS_UPPER;
506 break;
507 default:
508 /* invalid instruction, disregard and continue */
509 continue;
510 } /* switch */
511
512 if(flags & FLAGS_WIDTHPARAM) {
513 if(width < 0)
514 width = param_num++;
515 else {
516 /* if this identifies a parameter already used, this
517 is illegal */
518 if(usedinput[width/8] & (1 << (width&7)))
519 return PFMT_WIDTHARG;
520 }
521 if(width >= MAX_PARAMETERS)
522 return PFMT_MANYARGS;
523 if(width >= max_param)
524 max_param = width;
525
526 in[width].type = FORMAT_WIDTH;
527 /* mark as used */
528 usedinput[width/8] |= (unsigned char)(1 << (width&7));
529 }
530
531 if(flags & FLAGS_PRECPARAM) {
532 if(precision < 0)
533 precision = param_num++;
534 else {
535 /* if this identifies a parameter already used, this
536 is illegal */
537 if(usedinput[precision/8] & (1 << (precision&7)))
538 return PFMT_PRECARG;
539 }
540 if(precision >= MAX_PARAMETERS)
541 return PFMT_MANYARGS;
542 if(precision >= max_param)
543 max_param = precision;
544
545 in[precision].type = FORMAT_PRECISION;
546 usedinput[precision/8] |= (unsigned char)(1 << (precision&7));
547 }
548
549 /* Handle the specifier */
550 if(param < 0)
551 param = param_num++;
552 if(param >= MAX_PARAMETERS)
553 return PFMT_MANYARGS;
554 if(param >= max_param)
555 max_param = param;
556
557 iptr = &in[param];
558 iptr->type = type;
559
560 /* mark this input as used */
561 usedinput[param/8] |= (unsigned char)(1 << (param&7));
562
563 fmt++;
564 optr = &out[ocount++];
565 if(ocount > MAX_SEGMENTS)
566 return PFMT_MANYSEGS;
567 optr->input = (unsigned int)param;
568 optr->flags = flags;
569 optr->width = width;
570 optr->precision = precision;
571 optr->start = start;
572 optr->outlen = outlen;
573 start = fmt;
574 }
575 else
576 fmt++;
577 }
578
579 /* is there a trailing piece */
580 outlen = (size_t)(fmt - start);
581 if(outlen) {
582 optr = &out[ocount++];
583 if(ocount > MAX_SEGMENTS)
584 return PFMT_MANYSEGS;
585 optr->input = 0;
586 optr->flags = FLAGS_SUBSTR;
587 optr->start = start;
588 optr->outlen = outlen;
589 }
590
591 /* Read the arg list parameters into our data list */
592 for(i = 0; i < max_param + 1; i++) {
593 struct va_input *iptr = &in[i];
594 if(!(usedinput[i/8] & (1 << (i&7))))
595 /* bad input */
596 return PFMT_INPUTGAP;
597
598 /* based on the type, read the correct argument */
599 switch(iptr->type) {
600 case FORMAT_STRING:
601 iptr->val.str = va_arg(arglist, char *);
602 break;
603
604 case FORMAT_INTPTR:
605 case FORMAT_PTR:
606 iptr->val.ptr = va_arg(arglist, void *);
607 break;
608
609 case FORMAT_LONGLONGU:
610 iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
611 break;
612
613 case FORMAT_LONGLONG:
614 iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t);
615 break;
616
617 case FORMAT_LONGU:
618 iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long);
619 break;
620
621 case FORMAT_LONG:
622 iptr->val.nums = (mp_intmax_t)va_arg(arglist, long);
623 break;
624
625 case FORMAT_INTU:
626 iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int);
627 break;
628
629 case FORMAT_INT:
630 case FORMAT_WIDTH:
631 case FORMAT_PRECISION:
632 iptr->val.nums = (mp_intmax_t)va_arg(arglist, int);
633 break;
634
635 case FORMAT_DOUBLE:
636 iptr->val.dnum = va_arg(arglist, double);
637 break;
638
639 default:
640 DEBUGASSERT(NULL); /* unexpected */
641 break;
642 }
643 }
644 *ipieces = max_param + 1;
645 *opieces = ocount;
646
647 return PFMT_OK;
648 }
649
650 /*
651 * formatf() - the general printf function.
652 *
653 * It calls parsefmt() to parse the format string. It populates two arrays;
654 * one that describes the input arguments and one that describes a number of
655 * output segments.
656 *
657 * On success, the input array describes the type of all arguments and their
658 * values.
659 *
660 * The function then iterates over the output segments and outputs them one
661 * by one until done. Using the appropriate input arguments (if any).
662 *
663 * All output is sent to the 'stream()' callback, one byte at a time.
664 */
665
formatf(void * userp,int (* stream)(unsigned char,void *),const char * format,va_list ap_save)666 static int formatf(
667 void *userp, /* untouched by format(), just sent to the stream() function in
668 the second argument */
669 /* function pointer called for each output character */
670 int (*stream)(unsigned char, void *),
671 const char *format, /* %-formatted string */
672 va_list ap_save) /* list of parameters */
673 {
674 static const char nilstr[] = "(nil)";
675 const char *digits = lower_digits; /* Base-36 digits for numbers. */
676 int done = 0; /* number of characters written */
677 int i;
678 int ocount = 0; /* number of output segments */
679 int icount = 0; /* number of input arguments */
680
681 struct outsegment output[MAX_SEGMENTS];
682 struct va_input input[MAX_PARAMETERS];
683 char work[BUFFSIZE];
684
685 /* 'workend' points to the final buffer byte position, but with an extra
686 byte as margin to avoid the (FALSE?) warning Coverity gives us
687 otherwise */
688 char *workend = &work[sizeof(work) - 2];
689
690 /* Parse the format string */
691 if(parsefmt(format, output, input, &ocount, &icount, ap_save))
692 return 0;
693
694 for(i = 0; i < ocount; i++) {
695 struct outsegment *optr = &output[i];
696 struct va_input *iptr;
697 bool is_alt; /* Format spec modifiers. */
698 int width; /* Width of a field. */
699 int prec; /* Precision of a field. */
700 bool is_neg; /* Decimal integer is negative. */
701 unsigned long base; /* Base of a number to be written. */
702 mp_uintmax_t num; /* Integral values to be written. */
703 mp_intmax_t signed_num; /* Used to convert negative in positive. */
704 char *w;
705 size_t outlen = optr->outlen;
706 unsigned int flags = optr->flags;
707
708 if(outlen) {
709 char *str = optr->start;
710 for(; outlen && *str; outlen--)
711 OUTCHAR(*str++);
712 if(optr->flags & FLAGS_SUBSTR)
713 /* this is just a substring */
714 continue;
715 }
716
717 /* pick up the specified width */
718 if(flags & FLAGS_WIDTHPARAM) {
719 width = (int)input[optr->width].val.nums;
720 if(width < 0) {
721 /* "A negative field width is taken as a '-' flag followed by a
722 positive field width." */
723 if(width == INT_MIN)
724 width = INT_MAX;
725 else
726 width = -width;
727 flags |= FLAGS_LEFT;
728 flags &= ~(unsigned int)FLAGS_PAD_NIL;
729 }
730 }
731 else
732 width = optr->width;
733
734 /* pick up the specified precision */
735 if(flags & FLAGS_PRECPARAM) {
736 prec = (int)input[optr->precision].val.nums;
737 if(prec < 0)
738 /* "A negative precision is taken as if the precision were
739 omitted." */
740 prec = -1;
741 }
742 else if(flags & FLAGS_PREC)
743 prec = optr->precision;
744 else
745 prec = -1;
746
747 is_alt = (flags & FLAGS_ALT) ? 1 : 0;
748 iptr = &input[optr->input];
749
750 switch(iptr->type) {
751 case FORMAT_INTU:
752 case FORMAT_LONGU:
753 case FORMAT_LONGLONGU:
754 flags |= FLAGS_UNSIGNED;
755 FALLTHROUGH();
756 case FORMAT_INT:
757 case FORMAT_LONG:
758 case FORMAT_LONGLONG:
759 num = iptr->val.numu;
760 if(flags & FLAGS_CHAR) {
761 /* Character. */
762 if(!(flags & FLAGS_LEFT))
763 while(--width > 0)
764 OUTCHAR(' ');
765 OUTCHAR((char) num);
766 if(flags & FLAGS_LEFT)
767 while(--width > 0)
768 OUTCHAR(' ');
769 break;
770 }
771 if(flags & FLAGS_OCTAL) {
772 /* Octal unsigned integer */
773 base = 8;
774 is_neg = FALSE;
775 }
776 else if(flags & FLAGS_HEX) {
777 /* Hexadecimal unsigned integer */
778 digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
779 base = 16;
780 is_neg = FALSE;
781 }
782 else if(flags & FLAGS_UNSIGNED) {
783 /* Decimal unsigned integer */
784 base = 10;
785 is_neg = FALSE;
786 }
787 else {
788 /* Decimal integer. */
789 base = 10;
790
791 is_neg = (iptr->val.nums < (mp_intmax_t)0);
792 if(is_neg) {
793 /* signed_num might fail to hold absolute negative minimum by 1 */
794 signed_num = iptr->val.nums + (mp_intmax_t)1;
795 signed_num = -signed_num;
796 num = (mp_uintmax_t)signed_num;
797 num += (mp_uintmax_t)1;
798 }
799 }
800 number:
801 /* Supply a default precision if none was given. */
802 if(prec == -1)
803 prec = 1;
804
805 /* Put the number in WORK. */
806 w = workend;
807 switch(base) {
808 case 10:
809 while(num > 0) {
810 *w-- = (char)('0' + (num % 10));
811 num /= 10;
812 }
813 break;
814 default:
815 while(num > 0) {
816 *w-- = digits[num % base];
817 num /= base;
818 }
819 break;
820 }
821 width -= (int)(workend - w);
822 prec -= (int)(workend - w);
823
824 if(is_alt && base == 8 && prec <= 0) {
825 *w-- = '0';
826 --width;
827 }
828
829 if(prec > 0) {
830 width -= prec;
831 while(prec-- > 0 && w >= work)
832 *w-- = '0';
833 }
834
835 if(is_alt && base == 16)
836 width -= 2;
837
838 if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
839 --width;
840
841 if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL))
842 while(width-- > 0)
843 OUTCHAR(' ');
844
845 if(is_neg)
846 OUTCHAR('-');
847 else if(flags & FLAGS_SHOWSIGN)
848 OUTCHAR('+');
849 else if(flags & FLAGS_SPACE)
850 OUTCHAR(' ');
851
852 if(is_alt && base == 16) {
853 OUTCHAR('0');
854 if(flags & FLAGS_UPPER)
855 OUTCHAR('X');
856 else
857 OUTCHAR('x');
858 }
859
860 if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL))
861 while(width-- > 0)
862 OUTCHAR('0');
863
864 /* Write the number. */
865 while(++w <= workend) {
866 OUTCHAR(*w);
867 }
868
869 if(flags & FLAGS_LEFT)
870 while(width-- > 0)
871 OUTCHAR(' ');
872 break;
873
874 case FORMAT_STRING: {
875 const char *str;
876 size_t len;
877
878 str = (char *)iptr->val.str;
879 if(!str) {
880 /* Write null string if there is space. */
881 if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
882 str = nilstr;
883 len = sizeof(nilstr) - 1;
884 /* Disable quotes around (nil) */
885 flags &= ~(unsigned int)FLAGS_ALT;
886 }
887 else {
888 str = "";
889 len = 0;
890 }
891 }
892 else if(prec != -1)
893 len = (size_t)prec;
894 else if(*str == '\0')
895 len = 0;
896 else
897 len = strlen(str);
898
899 width -= (len > INT_MAX) ? INT_MAX : (int)len;
900
901 if(flags & FLAGS_ALT)
902 OUTCHAR('"');
903
904 if(!(flags & FLAGS_LEFT))
905 while(width-- > 0)
906 OUTCHAR(' ');
907
908 for(; len && *str; len--)
909 OUTCHAR(*str++);
910 if(flags & FLAGS_LEFT)
911 while(width-- > 0)
912 OUTCHAR(' ');
913
914 if(flags & FLAGS_ALT)
915 OUTCHAR('"');
916 break;
917 }
918
919 case FORMAT_PTR:
920 /* Generic pointer. */
921 if(iptr->val.ptr) {
922 /* If the pointer is not NULL, write it as a %#x spec. */
923 base = 16;
924 digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
925 is_alt = TRUE;
926 num = (size_t) iptr->val.ptr;
927 is_neg = FALSE;
928 goto number;
929 }
930 else {
931 /* Write "(nil)" for a nil pointer. */
932 const char *point;
933
934 width -= (int)(sizeof(nilstr) - 1);
935 if(flags & FLAGS_LEFT)
936 while(width-- > 0)
937 OUTCHAR(' ');
938 for(point = nilstr; *point != '\0'; ++point)
939 OUTCHAR(*point);
940 if(!(flags & FLAGS_LEFT))
941 while(width-- > 0)
942 OUTCHAR(' ');
943 }
944 break;
945
946 case FORMAT_DOUBLE: {
947 char formatbuf[32]="%";
948 char *fptr = &formatbuf[1];
949 size_t left = sizeof(formatbuf)-strlen(formatbuf);
950 int len;
951
952 if(flags & FLAGS_WIDTH)
953 width = optr->width;
954
955 if(flags & FLAGS_PREC)
956 prec = optr->precision;
957
958 if(flags & FLAGS_LEFT)
959 *fptr++ = '-';
960 if(flags & FLAGS_SHOWSIGN)
961 *fptr++ = '+';
962 if(flags & FLAGS_SPACE)
963 *fptr++ = ' ';
964 if(flags & FLAGS_ALT)
965 *fptr++ = '#';
966
967 *fptr = 0;
968
969 if(width >= 0) {
970 size_t dlen;
971 if(width >= (int)sizeof(work))
972 width = sizeof(work)-1;
973 /* RECURSIVE USAGE */
974 dlen = (size_t)curl_msnprintf(fptr, left, "%d", width);
975 fptr += dlen;
976 left -= dlen;
977 }
978 if(prec >= 0) {
979 /* for each digit in the integer part, we can have one less
980 precision */
981 size_t maxprec = sizeof(work) - 2;
982 double val = iptr->val.dnum;
983 if(width > 0 && prec <= width)
984 maxprec -= (size_t)width;
985 while(val >= 10.0) {
986 val /= 10;
987 maxprec--;
988 }
989
990 if(prec > (int)maxprec)
991 prec = (int)maxprec-1;
992 if(prec < 0)
993 prec = 0;
994 /* RECURSIVE USAGE */
995 len = curl_msnprintf(fptr, left, ".%d", prec);
996 fptr += len;
997 }
998 if(flags & FLAGS_LONG)
999 *fptr++ = 'l';
1000
1001 if(flags & FLAGS_FLOATE)
1002 *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E' : 'e');
1003 else if(flags & FLAGS_FLOATG)
1004 *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
1005 else
1006 *fptr++ = 'f';
1007
1008 *fptr = 0; /* and a final null-termination */
1009
1010 #ifdef __clang__
1011 #pragma clang diagnostic push
1012 #pragma clang diagnostic ignored "-Wformat-nonliteral"
1013 #endif
1014 /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
1015 output characters */
1016 #ifdef HAVE_SNPRINTF
1017 (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum);
1018 #else
1019 (sprintf)(work, formatbuf, iptr->val.dnum);
1020 #endif
1021 #ifdef __clang__
1022 #pragma clang diagnostic pop
1023 #endif
1024 DEBUGASSERT(strlen(work) <= sizeof(work));
1025 for(fptr = work; *fptr; fptr++)
1026 OUTCHAR(*fptr);
1027 break;
1028 }
1029
1030 case FORMAT_INTPTR:
1031 /* Answer the count of characters written. */
1032 #ifdef HAVE_LONG_LONG_TYPE
1033 if(flags & FLAGS_LONGLONG)
1034 *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done;
1035 else
1036 #endif
1037 if(flags & FLAGS_LONG)
1038 *(long *) iptr->val.ptr = (long)done;
1039 else if(!(flags & FLAGS_SHORT))
1040 *(int *) iptr->val.ptr = (int)done;
1041 else
1042 *(short *) iptr->val.ptr = (short)done;
1043 break;
1044
1045 default:
1046 break;
1047 }
1048 }
1049 return done;
1050 }
1051
1052 /* fputc() look-alike */
addbyter(unsigned char outc,void * f)1053 static int addbyter(unsigned char outc, void *f)
1054 {
1055 struct nsprintf *infop = f;
1056 if(infop->length < infop->max) {
1057 /* only do this if we have not reached max length yet */
1058 *infop->buffer++ = (char)outc; /* store */
1059 infop->length++; /* we are now one byte larger */
1060 return 0; /* fputc() returns like this on success */
1061 }
1062 return 1;
1063 }
1064
curl_mvsnprintf(char * buffer,size_t maxlength,const char * format,va_list ap_save)1065 int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1066 va_list ap_save)
1067 {
1068 int retcode;
1069 struct nsprintf info;
1070
1071 info.buffer = buffer;
1072 info.length = 0;
1073 info.max = maxlength;
1074
1075 retcode = formatf(&info, addbyter, format, ap_save);
1076 if(info.max) {
1077 /* we terminate this with a zero byte */
1078 if(info.max == info.length) {
1079 /* we are at maximum, scrap the last letter */
1080 info.buffer[-1] = 0;
1081 DEBUGASSERT(retcode);
1082 retcode--; /* do not count the nul byte */
1083 }
1084 else
1085 info.buffer[0] = 0;
1086 }
1087 return retcode;
1088 }
1089
curl_msnprintf(char * buffer,size_t maxlength,const char * format,...)1090 int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1091 {
1092 int retcode;
1093 va_list ap_save; /* argument pointer */
1094 va_start(ap_save, format);
1095 retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1096 va_end(ap_save);
1097 return retcode;
1098 }
1099
1100 /* fputc() look-alike */
alloc_addbyter(unsigned char outc,void * f)1101 static int alloc_addbyter(unsigned char outc, void *f)
1102 {
1103 struct asprintf *infop = f;
1104 CURLcode result = Curl_dyn_addn(infop->b, &outc, 1);
1105 if(result) {
1106 infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
1107 return 1 ; /* fail */
1108 }
1109 return 0;
1110 }
1111
1112 /* appends the formatted string, returns MERR error code */
Curl_dyn_vprintf(struct dynbuf * dyn,const char * format,va_list ap_save)1113 int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
1114 {
1115 struct asprintf info;
1116 info.b = dyn;
1117 info.merr = MERR_OK;
1118
1119 (void)formatf(&info, alloc_addbyter, format, ap_save);
1120 if(info.merr) {
1121 Curl_dyn_free(info.b);
1122 return info.merr;
1123 }
1124 return 0;
1125 }
1126
curl_mvaprintf(const char * format,va_list ap_save)1127 char *curl_mvaprintf(const char *format, va_list ap_save)
1128 {
1129 struct asprintf info;
1130 struct dynbuf dyn;
1131 info.b = &dyn;
1132 Curl_dyn_init(info.b, DYN_APRINTF);
1133 info.merr = MERR_OK;
1134
1135 (void)formatf(&info, alloc_addbyter, format, ap_save);
1136 if(info.merr) {
1137 Curl_dyn_free(info.b);
1138 return NULL;
1139 }
1140 if(Curl_dyn_len(info.b))
1141 return Curl_dyn_ptr(info.b);
1142 return strdup("");
1143 }
1144
curl_maprintf(const char * format,...)1145 char *curl_maprintf(const char *format, ...)
1146 {
1147 va_list ap_save;
1148 char *s;
1149 va_start(ap_save, format);
1150 s = curl_mvaprintf(format, ap_save);
1151 va_end(ap_save);
1152 return s;
1153 }
1154
storebuffer(unsigned char outc,void * f)1155 static int storebuffer(unsigned char outc, void *f)
1156 {
1157 char **buffer = f;
1158 **buffer = (char)outc;
1159 (*buffer)++;
1160 return 0;
1161 }
1162
curl_msprintf(char * buffer,const char * format,...)1163 int curl_msprintf(char *buffer, const char *format, ...)
1164 {
1165 va_list ap_save; /* argument pointer */
1166 int retcode;
1167 va_start(ap_save, format);
1168 retcode = formatf(&buffer, storebuffer, format, ap_save);
1169 va_end(ap_save);
1170 *buffer = 0; /* we terminate this with a zero byte */
1171 return retcode;
1172 }
1173
fputc_wrapper(unsigned char outc,void * f)1174 static int fputc_wrapper(unsigned char outc, void *f)
1175 {
1176 int out = outc;
1177 FILE *s = f;
1178 int rc = fputc(out, s);
1179 return rc == EOF;
1180 }
1181
curl_mprintf(const char * format,...)1182 int curl_mprintf(const char *format, ...)
1183 {
1184 int retcode;
1185 va_list ap_save; /* argument pointer */
1186 va_start(ap_save, format);
1187
1188 retcode = formatf(stdout, fputc_wrapper, format, ap_save);
1189 va_end(ap_save);
1190 return retcode;
1191 }
1192
curl_mfprintf(FILE * whereto,const char * format,...)1193 int curl_mfprintf(FILE *whereto, const char *format, ...)
1194 {
1195 int retcode;
1196 va_list ap_save; /* argument pointer */
1197 va_start(ap_save, format);
1198 retcode = formatf(whereto, fputc_wrapper, format, ap_save);
1199 va_end(ap_save);
1200 return retcode;
1201 }
1202
curl_mvsprintf(char * buffer,const char * format,va_list ap_save)1203 int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1204 {
1205 int retcode = formatf(&buffer, storebuffer, format, ap_save);
1206 *buffer = 0; /* we terminate this with a zero byte */
1207 return retcode;
1208 }
1209
curl_mvprintf(const char * format,va_list ap_save)1210 int curl_mvprintf(const char *format, va_list ap_save)
1211 {
1212 return formatf(stdout, fputc_wrapper, format, ap_save);
1213 }
1214
curl_mvfprintf(FILE * whereto,const char * format,va_list ap_save)1215 int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1216 {
1217 return formatf(whereto, fputc_wrapper, format, ap_save);
1218 }
1219