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 type = FORMAT_INT;
459 flags |= FLAGS_OCTAL;
460 break;
461 case 'x':
462 type = FORMAT_INTU;
463 flags |= FLAGS_HEX|FLAGS_UNSIGNED;
464 break;
465 case 'X':
466 type = FORMAT_INTU;
467 flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
468 break;
469 case 'c':
470 type = FORMAT_INT;
471 flags |= FLAGS_CHAR;
472 break;
473 case 'f':
474 type = FORMAT_DOUBLE;
475 break;
476 case 'e':
477 type = FORMAT_DOUBLE;
478 flags |= FLAGS_FLOATE;
479 break;
480 case 'E':
481 type = FORMAT_DOUBLE;
482 flags |= FLAGS_FLOATE|FLAGS_UPPER;
483 break;
484 case 'g':
485 type = FORMAT_DOUBLE;
486 flags |= FLAGS_FLOATG;
487 break;
488 case 'G':
489 type = FORMAT_DOUBLE;
490 flags |= FLAGS_FLOATG|FLAGS_UPPER;
491 break;
492 default:
493 /* invalid instruction, disregard and continue */
494 continue;
495 } /* switch */
496
497 if(flags & FLAGS_WIDTHPARAM) {
498 if(width < 0)
499 width = param_num++;
500 else {
501 /* if this identifies a parameter already used, this
502 is illegal */
503 if(usedinput[width/8] & (1 << (width&7)))
504 return PFMT_WIDTHARG;
505 }
506 if(width >= MAX_PARAMETERS)
507 return PFMT_MANYARGS;
508 if(width >= max_param)
509 max_param = width;
510
511 in[width].type = FORMAT_WIDTH;
512 /* mark as used */
513 usedinput[width/8] |= (unsigned char)(1 << (width&7));
514 }
515
516 if(flags & FLAGS_PRECPARAM) {
517 if(precision < 0)
518 precision = param_num++;
519 else {
520 /* if this identifies a parameter already used, this
521 is illegal */
522 if(usedinput[precision/8] & (1 << (precision&7)))
523 return PFMT_PRECARG;
524 }
525 if(precision >= MAX_PARAMETERS)
526 return PFMT_MANYARGS;
527 if(precision >= max_param)
528 max_param = precision;
529
530 in[precision].type = FORMAT_PRECISION;
531 usedinput[precision/8] |= (unsigned char)(1 << (precision&7));
532 }
533
534 /* Handle the specifier */
535 if(param < 0)
536 param = param_num++;
537 if(param >= MAX_PARAMETERS)
538 return PFMT_MANYARGS;
539 if(param >= max_param)
540 max_param = param;
541
542 iptr = &in[param];
543 iptr->type = type;
544
545 /* mark this input as used */
546 usedinput[param/8] |= (unsigned char)(1 << (param&7));
547
548 fmt++;
549 optr = &out[ocount++];
550 if(ocount > MAX_SEGMENTS)
551 return PFMT_MANYSEGS;
552 optr->input = (unsigned int)param;
553 optr->flags = flags;
554 optr->width = width;
555 optr->precision = precision;
556 optr->start = start;
557 optr->outlen = outlen;
558 start = fmt;
559 }
560 else
561 fmt++;
562 }
563
564 /* is there a trailing piece */
565 outlen = (size_t)(fmt - start);
566 if(outlen) {
567 optr = &out[ocount++];
568 if(ocount > MAX_SEGMENTS)
569 return PFMT_MANYSEGS;
570 optr->input = 0;
571 optr->flags = FLAGS_SUBSTR;
572 optr->start = start;
573 optr->outlen = outlen;
574 }
575
576 /* Read the arg list parameters into our data list */
577 for(i = 0; i < max_param + 1; i++) {
578 struct va_input *iptr = &in[i];
579 if(!(usedinput[i/8] & (1 << (i&7))))
580 /* bad input */
581 return PFMT_INPUTGAP;
582
583 /* based on the type, read the correct argument */
584 switch(iptr->type) {
585 case FORMAT_STRING:
586 iptr->val.str = va_arg(arglist, char *);
587 break;
588
589 case FORMAT_INTPTR:
590 case FORMAT_PTR:
591 iptr->val.ptr = va_arg(arglist, void *);
592 break;
593
594 case FORMAT_LONGLONGU:
595 iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
596 break;
597
598 case FORMAT_LONGLONG:
599 iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t);
600 break;
601
602 case FORMAT_LONGU:
603 iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long);
604 break;
605
606 case FORMAT_LONG:
607 iptr->val.nums = (mp_intmax_t)va_arg(arglist, long);
608 break;
609
610 case FORMAT_INTU:
611 iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int);
612 break;
613
614 case FORMAT_INT:
615 case FORMAT_WIDTH:
616 case FORMAT_PRECISION:
617 iptr->val.nums = (mp_intmax_t)va_arg(arglist, int);
618 break;
619
620 case FORMAT_DOUBLE:
621 iptr->val.dnum = va_arg(arglist, double);
622 break;
623
624 default:
625 DEBUGASSERT(NULL); /* unexpected */
626 break;
627 }
628 }
629 *ipieces = max_param + 1;
630 *opieces = ocount;
631
632 return PFMT_OK;
633 }
634
635 /*
636 * formatf() - the general printf function.
637 *
638 * It calls parsefmt() to parse the format string. It populates two arrays;
639 * one that describes the input arguments and one that describes a number of
640 * output segments.
641 *
642 * On success, the input array describes the type of all arguments and their
643 * values.
644 *
645 * The function then iterates over the output segments and outputs them one
646 * by one until done. Using the appropriate input arguments (if any).
647 *
648 * All output is sent to the 'stream()' callback, one byte at a time.
649 */
650
formatf(void * userp,int (* stream)(unsigned char,void *),const char * format,va_list ap_save)651 static int formatf(
652 void *userp, /* untouched by format(), just sent to the stream() function in
653 the second argument */
654 /* function pointer called for each output character */
655 int (*stream)(unsigned char, void *),
656 const char *format, /* %-formatted string */
657 va_list ap_save) /* list of parameters */
658 {
659 static const char nilstr[] = "(nil)";
660 const char *digits = lower_digits; /* Base-36 digits for numbers. */
661 int done = 0; /* number of characters written */
662 int i;
663 int ocount = 0; /* number of output segments */
664 int icount = 0; /* number of input arguments */
665
666 struct outsegment output[MAX_SEGMENTS];
667 struct va_input input[MAX_PARAMETERS];
668 char work[BUFFSIZE];
669
670 /* 'workend' points to the final buffer byte position, but with an extra
671 byte as margin to avoid the (false?) warning Coverity gives us
672 otherwise */
673 char *workend = &work[sizeof(work) - 2];
674
675 /* Parse the format string */
676 if(parsefmt(format, output, input, &ocount, &icount, ap_save))
677 return 0;
678
679 for(i = 0; i < ocount; i++) {
680 struct outsegment *optr = &output[i];
681 struct va_input *iptr;
682 bool is_alt; /* Format spec modifiers. */
683 int width; /* Width of a field. */
684 int prec; /* Precision of a field. */
685 bool is_neg; /* Decimal integer is negative. */
686 unsigned long base; /* Base of a number to be written. */
687 mp_uintmax_t num; /* Integral values to be written. */
688 mp_intmax_t signed_num; /* Used to convert negative in positive. */
689 char *w;
690 size_t outlen = optr->outlen;
691 unsigned int flags = optr->flags;
692
693 if(outlen) {
694 char *str = optr->start;
695 for(; outlen && *str; outlen--)
696 OUTCHAR(*str++);
697 if(optr->flags & FLAGS_SUBSTR)
698 /* this is just a substring */
699 continue;
700 }
701
702 /* pick up the specified width */
703 if(flags & FLAGS_WIDTHPARAM) {
704 width = (int)input[optr->width].val.nums;
705 if(width < 0) {
706 /* "A negative field width is taken as a '-' flag followed by a
707 positive field width." */
708 if(width == INT_MIN)
709 width = INT_MAX;
710 else
711 width = -width;
712 flags |= FLAGS_LEFT;
713 flags &= ~(unsigned int)FLAGS_PAD_NIL;
714 }
715 }
716 else
717 width = optr->width;
718
719 /* pick up the specified precision */
720 if(flags & FLAGS_PRECPARAM) {
721 prec = (int)input[optr->precision].val.nums;
722 if(prec < 0)
723 /* "A negative precision is taken as if the precision were
724 omitted." */
725 prec = -1;
726 }
727 else if(flags & FLAGS_PREC)
728 prec = optr->precision;
729 else
730 prec = -1;
731
732 is_alt = (flags & FLAGS_ALT) ? 1 : 0;
733 iptr = &input[optr->input];
734
735 switch(iptr->type) {
736 case FORMAT_INTU:
737 case FORMAT_LONGU:
738 case FORMAT_LONGLONGU:
739 flags |= FLAGS_UNSIGNED;
740 FALLTHROUGH();
741 case FORMAT_INT:
742 case FORMAT_LONG:
743 case FORMAT_LONGLONG:
744 num = iptr->val.numu;
745 if(flags & FLAGS_CHAR) {
746 /* Character. */
747 if(!(flags & FLAGS_LEFT))
748 while(--width > 0)
749 OUTCHAR(' ');
750 OUTCHAR((char) num);
751 if(flags & FLAGS_LEFT)
752 while(--width > 0)
753 OUTCHAR(' ');
754 break;
755 }
756 if(flags & FLAGS_OCTAL) {
757 /* Octal unsigned integer */
758 base = 8;
759 is_neg = FALSE;
760 }
761 else if(flags & FLAGS_HEX) {
762 /* Hexadecimal unsigned integer */
763 digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
764 base = 16;
765 is_neg = FALSE;
766 }
767 else if(flags & FLAGS_UNSIGNED) {
768 /* Decimal unsigned integer */
769 base = 10;
770 is_neg = FALSE;
771 }
772 else {
773 /* Decimal integer. */
774 base = 10;
775
776 is_neg = (iptr->val.nums < (mp_intmax_t)0);
777 if(is_neg) {
778 /* signed_num might fail to hold absolute negative minimum by 1 */
779 signed_num = iptr->val.nums + (mp_intmax_t)1;
780 signed_num = -signed_num;
781 num = (mp_uintmax_t)signed_num;
782 num += (mp_uintmax_t)1;
783 }
784 }
785 number:
786 /* Supply a default precision if none was given. */
787 if(prec == -1)
788 prec = 1;
789
790 /* Put the number in WORK. */
791 w = workend;
792 switch(base) {
793 case 10:
794 while(num > 0) {
795 *w-- = (char)('0' + (num % 10));
796 num /= 10;
797 }
798 break;
799 default:
800 while(num > 0) {
801 *w-- = digits[num % base];
802 num /= base;
803 }
804 break;
805 }
806 width -= (int)(workend - w);
807 prec -= (int)(workend - w);
808
809 if(is_alt && base == 8 && prec <= 0) {
810 *w-- = '0';
811 --width;
812 }
813
814 if(prec > 0) {
815 width -= prec;
816 while(prec-- > 0 && w >= work)
817 *w-- = '0';
818 }
819
820 if(is_alt && base == 16)
821 width -= 2;
822
823 if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
824 --width;
825
826 if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL))
827 while(width-- > 0)
828 OUTCHAR(' ');
829
830 if(is_neg)
831 OUTCHAR('-');
832 else if(flags & FLAGS_SHOWSIGN)
833 OUTCHAR('+');
834 else if(flags & FLAGS_SPACE)
835 OUTCHAR(' ');
836
837 if(is_alt && base == 16) {
838 OUTCHAR('0');
839 if(flags & FLAGS_UPPER)
840 OUTCHAR('X');
841 else
842 OUTCHAR('x');
843 }
844
845 if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL))
846 while(width-- > 0)
847 OUTCHAR('0');
848
849 /* Write the number. */
850 while(++w <= workend) {
851 OUTCHAR(*w);
852 }
853
854 if(flags & FLAGS_LEFT)
855 while(width-- > 0)
856 OUTCHAR(' ');
857 break;
858
859 case FORMAT_STRING: {
860 const char *str;
861 size_t len;
862
863 str = (char *)iptr->val.str;
864 if(!str) {
865 /* Write null string if there is space. */
866 if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
867 str = nilstr;
868 len = sizeof(nilstr) - 1;
869 /* Disable quotes around (nil) */
870 flags &= ~(unsigned int)FLAGS_ALT;
871 }
872 else {
873 str = "";
874 len = 0;
875 }
876 }
877 else if(prec != -1)
878 len = (size_t)prec;
879 else if(*str == '\0')
880 len = 0;
881 else
882 len = strlen(str);
883
884 width -= (len > INT_MAX) ? INT_MAX : (int)len;
885
886 if(flags & FLAGS_ALT)
887 OUTCHAR('"');
888
889 if(!(flags & FLAGS_LEFT))
890 while(width-- > 0)
891 OUTCHAR(' ');
892
893 for(; len && *str; len--)
894 OUTCHAR(*str++);
895 if(flags & FLAGS_LEFT)
896 while(width-- > 0)
897 OUTCHAR(' ');
898
899 if(flags & FLAGS_ALT)
900 OUTCHAR('"');
901 break;
902 }
903
904 case FORMAT_PTR:
905 /* Generic pointer. */
906 if(iptr->val.ptr) {
907 /* If the pointer is not NULL, write it as a %#x spec. */
908 base = 16;
909 digits = (flags & FLAGS_UPPER) ? upper_digits : lower_digits;
910 is_alt = TRUE;
911 num = (size_t) iptr->val.ptr;
912 is_neg = FALSE;
913 goto number;
914 }
915 else {
916 /* Write "(nil)" for a nil pointer. */
917 const char *point;
918
919 width -= (int)(sizeof(nilstr) - 1);
920 if(flags & FLAGS_LEFT)
921 while(width-- > 0)
922 OUTCHAR(' ');
923 for(point = nilstr; *point != '\0'; ++point)
924 OUTCHAR(*point);
925 if(!(flags & FLAGS_LEFT))
926 while(width-- > 0)
927 OUTCHAR(' ');
928 }
929 break;
930
931 case FORMAT_DOUBLE: {
932 char formatbuf[32]="%";
933 char *fptr = &formatbuf[1];
934 size_t left = sizeof(formatbuf)-strlen(formatbuf);
935 int len;
936
937 if(flags & FLAGS_WIDTH)
938 width = optr->width;
939
940 if(flags & FLAGS_PREC)
941 prec = optr->precision;
942
943 if(flags & FLAGS_LEFT)
944 *fptr++ = '-';
945 if(flags & FLAGS_SHOWSIGN)
946 *fptr++ = '+';
947 if(flags & FLAGS_SPACE)
948 *fptr++ = ' ';
949 if(flags & FLAGS_ALT)
950 *fptr++ = '#';
951
952 *fptr = 0;
953
954 if(width >= 0) {
955 size_t dlen;
956 if(width >= (int)sizeof(work))
957 width = sizeof(work)-1;
958 /* RECURSIVE USAGE */
959 dlen = (size_t)curl_msnprintf(fptr, left, "%d", width);
960 fptr += dlen;
961 left -= dlen;
962 }
963 if(prec >= 0) {
964 /* for each digit in the integer part, we can have one less
965 precision */
966 size_t maxprec = sizeof(work) - 2;
967 double val = iptr->val.dnum;
968 if(width > 0 && prec <= width)
969 maxprec -= (size_t)width;
970 while(val >= 10.0) {
971 val /= 10;
972 maxprec--;
973 }
974
975 if(prec > (int)maxprec)
976 prec = (int)maxprec-1;
977 if(prec < 0)
978 prec = 0;
979 /* RECURSIVE USAGE */
980 len = curl_msnprintf(fptr, left, ".%d", prec);
981 fptr += len;
982 }
983 if(flags & FLAGS_LONG)
984 *fptr++ = 'l';
985
986 if(flags & FLAGS_FLOATE)
987 *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E' : 'e');
988 else if(flags & FLAGS_FLOATG)
989 *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
990 else
991 *fptr++ = 'f';
992
993 *fptr = 0; /* and a final null-termination */
994
995 #ifdef __clang__
996 #pragma clang diagnostic push
997 #pragma clang diagnostic ignored "-Wformat-nonliteral"
998 #endif
999 /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
1000 output characters */
1001 #ifdef HAVE_SNPRINTF
1002 (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum);
1003 #else
1004 (sprintf)(work, formatbuf, iptr->val.dnum);
1005 #endif
1006 #ifdef __clang__
1007 #pragma clang diagnostic pop
1008 #endif
1009 DEBUGASSERT(strlen(work) <= sizeof(work));
1010 for(fptr = work; *fptr; fptr++)
1011 OUTCHAR(*fptr);
1012 break;
1013 }
1014
1015 case FORMAT_INTPTR:
1016 /* Answer the count of characters written. */
1017 #ifdef HAVE_LONG_LONG_TYPE
1018 if(flags & FLAGS_LONGLONG)
1019 *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done;
1020 else
1021 #endif
1022 if(flags & FLAGS_LONG)
1023 *(long *) iptr->val.ptr = (long)done;
1024 else if(!(flags & FLAGS_SHORT))
1025 *(int *) iptr->val.ptr = (int)done;
1026 else
1027 *(short *) iptr->val.ptr = (short)done;
1028 break;
1029
1030 default:
1031 break;
1032 }
1033 }
1034 return done;
1035 }
1036
1037 /* fputc() look-alike */
addbyter(unsigned char outc,void * f)1038 static int addbyter(unsigned char outc, void *f)
1039 {
1040 struct nsprintf *infop = f;
1041 if(infop->length < infop->max) {
1042 /* only do this if we have not reached max length yet */
1043 *infop->buffer++ = (char)outc; /* store */
1044 infop->length++; /* we are now one byte larger */
1045 return 0; /* fputc() returns like this on success */
1046 }
1047 return 1;
1048 }
1049
curl_mvsnprintf(char * buffer,size_t maxlength,const char * format,va_list ap_save)1050 int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1051 va_list ap_save)
1052 {
1053 int retcode;
1054 struct nsprintf info;
1055
1056 info.buffer = buffer;
1057 info.length = 0;
1058 info.max = maxlength;
1059
1060 retcode = formatf(&info, addbyter, format, ap_save);
1061 if(info.max) {
1062 /* we terminate this with a zero byte */
1063 if(info.max == info.length) {
1064 /* we are at maximum, scrap the last letter */
1065 info.buffer[-1] = 0;
1066 DEBUGASSERT(retcode);
1067 retcode--; /* do not count the nul byte */
1068 }
1069 else
1070 info.buffer[0] = 0;
1071 }
1072 return retcode;
1073 }
1074
curl_msnprintf(char * buffer,size_t maxlength,const char * format,...)1075 int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1076 {
1077 int retcode;
1078 va_list ap_save; /* argument pointer */
1079 va_start(ap_save, format);
1080 retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1081 va_end(ap_save);
1082 return retcode;
1083 }
1084
1085 /* fputc() look-alike */
alloc_addbyter(unsigned char outc,void * f)1086 static int alloc_addbyter(unsigned char outc, void *f)
1087 {
1088 struct asprintf *infop = f;
1089 CURLcode result = Curl_dyn_addn(infop->b, &outc, 1);
1090 if(result) {
1091 infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
1092 return 1 ; /* fail */
1093 }
1094 return 0;
1095 }
1096
1097 /* appends the formatted string, returns MERR error code */
Curl_dyn_vprintf(struct dynbuf * dyn,const char * format,va_list ap_save)1098 int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
1099 {
1100 struct asprintf info;
1101 info.b = dyn;
1102 info.merr = MERR_OK;
1103
1104 (void)formatf(&info, alloc_addbyter, format, ap_save);
1105 if(info.merr) {
1106 Curl_dyn_free(info.b);
1107 return info.merr;
1108 }
1109 return 0;
1110 }
1111
curl_mvaprintf(const char * format,va_list ap_save)1112 char *curl_mvaprintf(const char *format, va_list ap_save)
1113 {
1114 struct asprintf info;
1115 struct dynbuf dyn;
1116 info.b = &dyn;
1117 Curl_dyn_init(info.b, DYN_APRINTF);
1118 info.merr = MERR_OK;
1119
1120 (void)formatf(&info, alloc_addbyter, format, ap_save);
1121 if(info.merr) {
1122 Curl_dyn_free(info.b);
1123 return NULL;
1124 }
1125 if(Curl_dyn_len(info.b))
1126 return Curl_dyn_ptr(info.b);
1127 return strdup("");
1128 }
1129
curl_maprintf(const char * format,...)1130 char *curl_maprintf(const char *format, ...)
1131 {
1132 va_list ap_save;
1133 char *s;
1134 va_start(ap_save, format);
1135 s = curl_mvaprintf(format, ap_save);
1136 va_end(ap_save);
1137 return s;
1138 }
1139
storebuffer(unsigned char outc,void * f)1140 static int storebuffer(unsigned char outc, void *f)
1141 {
1142 char **buffer = f;
1143 **buffer = (char)outc;
1144 (*buffer)++;
1145 return 0;
1146 }
1147
curl_msprintf(char * buffer,const char * format,...)1148 int curl_msprintf(char *buffer, const char *format, ...)
1149 {
1150 va_list ap_save; /* argument pointer */
1151 int retcode;
1152 va_start(ap_save, format);
1153 retcode = formatf(&buffer, storebuffer, format, ap_save);
1154 va_end(ap_save);
1155 *buffer = 0; /* we terminate this with a zero byte */
1156 return retcode;
1157 }
1158
fputc_wrapper(unsigned char outc,void * f)1159 static int fputc_wrapper(unsigned char outc, void *f)
1160 {
1161 int out = outc;
1162 FILE *s = f;
1163 int rc = fputc(out, s);
1164 return rc == EOF;
1165 }
1166
curl_mprintf(const char * format,...)1167 int curl_mprintf(const char *format, ...)
1168 {
1169 int retcode;
1170 va_list ap_save; /* argument pointer */
1171 va_start(ap_save, format);
1172
1173 retcode = formatf(stdout, fputc_wrapper, format, ap_save);
1174 va_end(ap_save);
1175 return retcode;
1176 }
1177
curl_mfprintf(FILE * whereto,const char * format,...)1178 int curl_mfprintf(FILE *whereto, const char *format, ...)
1179 {
1180 int retcode;
1181 va_list ap_save; /* argument pointer */
1182 va_start(ap_save, format);
1183 retcode = formatf(whereto, fputc_wrapper, format, ap_save);
1184 va_end(ap_save);
1185 return retcode;
1186 }
1187
curl_mvsprintf(char * buffer,const char * format,va_list ap_save)1188 int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1189 {
1190 int retcode = formatf(&buffer, storebuffer, format, ap_save);
1191 *buffer = 0; /* we terminate this with a zero byte */
1192 return retcode;
1193 }
1194
curl_mvprintf(const char * format,va_list ap_save)1195 int curl_mvprintf(const char *format, va_list ap_save)
1196 {
1197 return formatf(stdout, fputc_wrapper, format, ap_save);
1198 }
1199
curl_mvfprintf(FILE * whereto,const char * format,va_list ap_save)1200 int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1201 {
1202 return formatf(whereto, fputc_wrapper, format, ap_save);
1203 }
1204