VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/mprintf.c@ 105945

Last change on this file since 105945 was 104083, checked in by vboxsync, 8 months ago

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

  • Property svn:eol-style set to native
File size: 30.7 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 */
24
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. */
73static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
74
75/* Upper-case digits. */
76static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
77
78#define OUTCHAR(x) \
79 do { \
80 if(!stream(x, userp)) \
81 done++; \
82 else \
83 return done; /* return on failure */ \
84 } while(0)
85
86/* Data type to read from the arglist */
87typedef 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 */
104enum {
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
128enum {
129 DOLLAR_UNKNOWN,
130 DOLLAR_NOPE,
131 DOLLAR_USE
132};
133
134/*
135 * Describes an input va_arg type and hold its value.
136 */
137struct 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 */
151struct 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
160struct nsprintf {
161 char *buffer;
162 size_t length;
163 size_t max;
164};
165
166struct 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*/
175static 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
216static 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 = 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 = 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 &= ~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 = 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 = 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
651static 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 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 &= ~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 }
785number:
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's 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 &= (~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 if(width >= (int)sizeof(work))
956 width = sizeof(work)-1;
957 /* RECURSIVE USAGE */
958 len = curl_msnprintf(fptr, left, "%d", width);
959 fptr += len;
960 left -= len;
961 }
962 if(prec >= 0) {
963 /* for each digit in the integer part, we can have one less
964 precision */
965 size_t maxprec = sizeof(work) - 2;
966 double val = iptr->val.dnum;
967 if(width > 0 && prec <= width)
968 maxprec -= width;
969 while(val >= 10.0) {
970 val /= 10;
971 maxprec--;
972 }
973
974 if(prec > (int)maxprec)
975 prec = (int)maxprec-1;
976 if(prec < 0)
977 prec = 0;
978 /* RECURSIVE USAGE */
979 len = curl_msnprintf(fptr, left, ".%d", prec);
980 fptr += len;
981 }
982 if(flags & FLAGS_LONG)
983 *fptr++ = 'l';
984
985 if(flags & FLAGS_FLOATE)
986 *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E':'e');
987 else if(flags & FLAGS_FLOATG)
988 *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
989 else
990 *fptr++ = 'f';
991
992 *fptr = 0; /* and a final null-termination */
993
994#ifdef __clang__
995#pragma clang diagnostic push
996#pragma clang diagnostic ignored "-Wformat-nonliteral"
997#endif
998 /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
999 output characters */
1000#ifdef HAVE_SNPRINTF
1001 (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum);
1002#else
1003 (sprintf)(work, formatbuf, iptr->val.dnum);
1004#endif
1005#ifdef __clang__
1006#pragma clang diagnostic pop
1007#endif
1008 DEBUGASSERT(strlen(work) <= sizeof(work));
1009 for(fptr = work; *fptr; fptr++)
1010 OUTCHAR(*fptr);
1011 break;
1012 }
1013
1014 case FORMAT_INTPTR:
1015 /* Answer the count of characters written. */
1016#ifdef HAVE_LONG_LONG_TYPE
1017 if(flags & FLAGS_LONGLONG)
1018 *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done;
1019 else
1020#endif
1021 if(flags & FLAGS_LONG)
1022 *(long *) iptr->val.ptr = (long)done;
1023 else if(!(flags & FLAGS_SHORT))
1024 *(int *) iptr->val.ptr = (int)done;
1025 else
1026 *(short *) iptr->val.ptr = (short)done;
1027 break;
1028
1029 default:
1030 break;
1031 }
1032 }
1033 return done;
1034}
1035
1036/* fputc() look-alike */
1037static int addbyter(unsigned char outc, void *f)
1038{
1039 struct nsprintf *infop = f;
1040 if(infop->length < infop->max) {
1041 /* only do this if we haven't reached max length yet */
1042 *infop->buffer++ = outc; /* store */
1043 infop->length++; /* we are now one byte larger */
1044 return 0; /* fputc() returns like this on success */
1045 }
1046 return 1;
1047}
1048
1049int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1050 va_list ap_save)
1051{
1052 int retcode;
1053 struct nsprintf info;
1054
1055 info.buffer = buffer;
1056 info.length = 0;
1057 info.max = maxlength;
1058
1059 retcode = formatf(&info, addbyter, format, ap_save);
1060 if(info.max) {
1061 /* we terminate this with a zero byte */
1062 if(info.max == info.length) {
1063 /* we're at maximum, scrap the last letter */
1064 info.buffer[-1] = 0;
1065 DEBUGASSERT(retcode);
1066 retcode--; /* don't count the nul byte */
1067 }
1068 else
1069 info.buffer[0] = 0;
1070 }
1071 return retcode;
1072}
1073
1074int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1075{
1076 int retcode;
1077 va_list ap_save; /* argument pointer */
1078 va_start(ap_save, format);
1079 retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1080 va_end(ap_save);
1081 return retcode;
1082}
1083
1084/* fputc() look-alike */
1085static int alloc_addbyter(unsigned char outc, void *f)
1086{
1087 struct asprintf *infop = f;
1088 CURLcode result = Curl_dyn_addn(infop->b, &outc, 1);
1089 if(result) {
1090 infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
1091 return 1 ; /* fail */
1092 }
1093 return 0;
1094}
1095
1096/* appends the formatted string, returns MERR error code */
1097int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
1098{
1099 struct asprintf info;
1100 info.b = dyn;
1101 info.merr = MERR_OK;
1102
1103 (void)formatf(&info, alloc_addbyter, format, ap_save);
1104 if(info.merr) {
1105 Curl_dyn_free(info.b);
1106 return info.merr;
1107 }
1108 return 0;
1109}
1110
1111char *curl_mvaprintf(const char *format, va_list ap_save)
1112{
1113 struct asprintf info;
1114 struct dynbuf dyn;
1115 info.b = &dyn;
1116 Curl_dyn_init(info.b, DYN_APRINTF);
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 NULL;
1123 }
1124 if(Curl_dyn_len(info.b))
1125 return Curl_dyn_ptr(info.b);
1126 return strdup("");
1127}
1128
1129char *curl_maprintf(const char *format, ...)
1130{
1131 va_list ap_save;
1132 char *s;
1133 va_start(ap_save, format);
1134 s = curl_mvaprintf(format, ap_save);
1135 va_end(ap_save);
1136 return s;
1137}
1138
1139static int storebuffer(unsigned char outc, void *f)
1140{
1141 char **buffer = f;
1142 **buffer = outc;
1143 (*buffer)++;
1144 return 0;
1145}
1146
1147int curl_msprintf(char *buffer, const char *format, ...)
1148{
1149 va_list ap_save; /* argument pointer */
1150 int retcode;
1151 va_start(ap_save, format);
1152 retcode = formatf(&buffer, storebuffer, format, ap_save);
1153 va_end(ap_save);
1154 *buffer = 0; /* we terminate this with a zero byte */
1155 return retcode;
1156}
1157
1158static int fputc_wrapper(unsigned char outc, void *f)
1159{
1160 int out = outc;
1161 FILE *s = f;
1162 int rc = fputc(out, s);
1163 if(rc == out)
1164 return 0;
1165 return 1;
1166}
1167
1168int 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
1179int 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
1189int 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
1196int curl_mvprintf(const char *format, va_list ap_save)
1197{
1198 return formatf(stdout, fputc_wrapper, format, ap_save);
1199}
1200
1201int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1202{
1203 return formatf(whereto, fputc_wrapper, format, ap_save);
1204}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette