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