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