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