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