Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / mprintf.c
blob46253c819341a5277a509413769a0a1706a9e392
1 /****************************************************************************
3 * $Id: mprintf.c,v 1.5 2007/03/15 19:22:13 andy Exp $
5 *************************************************************************
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
16 * Purpose:
17 * A merge of Bjorn Reese's format() function and Daniel's dsprintf()
18 * 1.0. A full blooded printf() clone with full support for <num>$
19 * everywhere (parameters, widths and precisions) including variabled
20 * sized parameters (like doubles, long longs, long doubles and even
21 * void * in 64-bit architectures).
23 * Current restrictions:
24 * - Max 128 parameters
25 * - No 'long double' support.
27 * If you ever want truly portable and good *printf() clones, the project that
28 * took on from here is named 'Trio' and you find more details on the trio web
29 * page at http://daniel.haxx.se/trio/
33 #include "setup.h"
34 #include <sys/types.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdarg.h>
38 #include <ctype.h>
39 #include <string.h>
41 #if defined(DJGPP) && (DJGPP_MINOR < 4)
42 #undef _MPRINTF_REPLACE /* don't use x_was_used() here */
43 #endif
45 #include <curl/mprintf.h>
47 #ifndef SIZEOF_LONG_DOUBLE
48 #define SIZEOF_LONG_DOUBLE 0
49 #endif
51 #ifndef SIZEOF_SIZE_T
52 /* default to 4 bytes for size_t unless defined in the config.h */
53 #define SIZEOF_SIZE_T 4
54 #endif
56 #ifdef DPRINTF_DEBUG
57 #define HAVE_LONGLONG
58 #define LONG_LONG long long
59 #define ENABLE_64BIT
60 #endif
62 #include "memory.h"
63 /* The last #include file should be: */
64 #include "memdebug.h"
66 #define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
67 #define MAX_PARAMETERS 128 /* lame static limit */
69 #undef TRUE
70 #undef FALSE
71 #undef BOOL
72 #ifdef __cplusplus
73 # define TRUE true
74 # define FALSE false
75 # define BOOL bool
76 #else
77 # define TRUE ((char)(1 == 1))
78 # define FALSE ((char)(0 == 1))
79 # define BOOL char
80 #endif
82 #ifdef _AMIGASF
83 # undef FORMAT_INT
84 #endif
86 /* Lower-case digits. */
87 static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
89 /* Upper-case digits. */
90 static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
92 #define OUTCHAR(x) \
93 do{ \
94 if(stream((unsigned char)(x), (FILE *)data) != -1) \
95 done++; \
96 else \
97 return done; /* return immediately on failure */ \
98 } while(0)
100 /* Data type to read from the arglist */
101 typedef enum {
102 FORMAT_UNKNOWN = 0,
103 FORMAT_STRING,
104 FORMAT_PTR,
105 FORMAT_INT,
106 FORMAT_INTPTR,
107 FORMAT_LONG,
108 FORMAT_LONGLONG,
109 FORMAT_DOUBLE,
110 FORMAT_LONGDOUBLE,
111 FORMAT_WIDTH /* For internal use */
112 } FormatType;
114 /* convertion and display flags */
115 enum {
116 FLAGS_NEW = 0,
117 FLAGS_SPACE = 1<<0,
118 FLAGS_SHOWSIGN = 1<<1,
119 FLAGS_LEFT = 1<<2,
120 FLAGS_ALT = 1<<3,
121 FLAGS_SHORT = 1<<4,
122 FLAGS_LONG = 1<<5,
123 FLAGS_LONGLONG = 1<<6,
124 FLAGS_LONGDOUBLE = 1<<7,
125 FLAGS_PAD_NIL = 1<<8,
126 FLAGS_UNSIGNED = 1<<9,
127 FLAGS_OCTAL = 1<<10,
128 FLAGS_HEX = 1<<11,
129 FLAGS_UPPER = 1<<12,
130 FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */
131 FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
132 FLAGS_PREC = 1<<15, /* precision was specified */
133 FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */
134 FLAGS_CHAR = 1<<17, /* %c story */
135 FLAGS_FLOATE = 1<<18, /* %e or %E */
136 FLAGS_FLOATG = 1<<19 /* %g or %G */
139 typedef struct {
140 FormatType type;
141 int flags;
142 long width; /* width OR width parameter number */
143 long precision; /* precision OR precision parameter number */
144 union {
145 char *str;
146 void *ptr;
147 long num;
148 #ifdef ENABLE_64BIT
149 LONG_LONG lnum;
150 #endif
151 double dnum;
152 } data;
153 } va_stack_t;
155 struct nsprintf {
156 char *buffer;
157 size_t length;
158 size_t max;
161 struct asprintf {
162 char *buffer; /* allocated buffer */
163 size_t len; /* length of string */
164 size_t alloc; /* length of alloc */
165 bool fail; /* TRUE if an alloc has failed and thus the output is not
166 the complete data */
169 int curl_msprintf(char *buffer, const char *format, ...);
171 static long dprintf_DollarString(char *input, char **end)
173 int number=0;
174 while(ISDIGIT(*input)) {
175 number *= 10;
176 number += *input-'0';
177 input++;
179 if(number && ('$'==*input++)) {
180 *end = input;
181 return number;
183 return 0;
186 static BOOL dprintf_IsQualifierNoDollar(char c)
188 switch (c) {
189 case '-': case '+': case ' ': case '#': case '.':
190 case '0': case '1': case '2': case '3': case '4':
191 case '5': case '6': case '7': case '8': case '9':
192 case 'h': case 'l': case 'L': case 'z': case 'q':
193 case '*': case 'O':
194 return TRUE;
195 default:
196 return FALSE;
200 #ifdef DPRINTF_DEBUG2
201 int dprintf_Pass1Report(va_stack_t *vto, int max)
203 int i;
204 char buffer[128];
205 int bit;
206 int flags;
208 for(i=0; i<max; i++) {
209 char *type;
210 switch(vto[i].type) {
211 case FORMAT_UNKNOWN:
212 type = "unknown";
213 break;
214 case FORMAT_STRING:
215 type ="string";
216 break;
217 case FORMAT_PTR:
218 type ="pointer";
219 break;
220 case FORMAT_INT:
221 type = "int";
222 break;
223 case FORMAT_LONG:
224 type = "long";
225 break;
226 case FORMAT_LONGLONG:
227 type = "long long";
228 break;
229 case FORMAT_DOUBLE:
230 type = "double";
231 break;
232 case FORMAT_LONGDOUBLE:
233 type = "long double";
234 break;
238 buffer[0]=0;
240 for(bit=0; bit<31; bit++) {
241 flags = vto[i].flags & (1<<bit);
243 if(flags & FLAGS_SPACE)
244 strcat(buffer, "space ");
245 else if(flags & FLAGS_SHOWSIGN)
246 strcat(buffer, "plus ");
247 else if(flags & FLAGS_LEFT)
248 strcat(buffer, "left ");
249 else if(flags & FLAGS_ALT)
250 strcat(buffer, "alt ");
251 else if(flags & FLAGS_SHORT)
252 strcat(buffer, "short ");
253 else if(flags & FLAGS_LONG)
254 strcat(buffer, "long ");
255 else if(flags & FLAGS_LONGLONG)
256 strcat(buffer, "longlong ");
257 else if(flags & FLAGS_LONGDOUBLE)
258 strcat(buffer, "longdouble ");
259 else if(flags & FLAGS_PAD_NIL)
260 strcat(buffer, "padnil ");
261 else if(flags & FLAGS_UNSIGNED)
262 strcat(buffer, "unsigned ");
263 else if(flags & FLAGS_OCTAL)
264 strcat(buffer, "octal ");
265 else if(flags & FLAGS_HEX)
266 strcat(buffer, "hex ");
267 else if(flags & FLAGS_UPPER)
268 strcat(buffer, "upper ");
269 else if(flags & FLAGS_WIDTH)
270 strcat(buffer, "width ");
271 else if(flags & FLAGS_WIDTHPARAM)
272 strcat(buffer, "widthparam ");
273 else if(flags & FLAGS_PREC)
274 strcat(buffer, "precision ");
275 else if(flags & FLAGS_PRECPARAM)
276 strcat(buffer, "precparam ");
277 else if(flags & FLAGS_CHAR)
278 strcat(buffer, "char ");
279 else if(flags & FLAGS_FLOATE)
280 strcat(buffer, "floate ");
281 else if(flags & FLAGS_FLOATG)
282 strcat(buffer, "floatg ");
284 printf("REPORT: %d. %s [%s]\n", i, type, buffer);
290 #endif
292 /******************************************************************
294 * Pass 1:
295 * Create an index with the type of each parameter entry and its
296 * value (may vary in size)
298 ******************************************************************/
300 static long dprintf_Pass1(char *format, va_stack_t *vto, char **endpos,
301 va_list arglist)
303 char *fmt = format;
304 int param_num = 0;
305 long this_param;
306 long width;
307 long precision;
308 int flags;
309 long max_param=0;
310 long i;
312 while (*fmt) {
313 if (*fmt++ == '%') {
314 if (*fmt == '%') {
315 fmt++;
316 continue; /* while */
319 flags = FLAGS_NEW;
321 /* Handle the positional case (N$) */
323 param_num++;
325 this_param = dprintf_DollarString(fmt, &fmt);
326 if (0 == this_param)
327 /* we got no positional, get the next counter */
328 this_param = param_num;
330 if (this_param > max_param)
331 max_param = this_param;
334 * The parameter with number 'i' should be used. Next, we need
335 * to get SIZE and TYPE of the parameter. Add the information
336 * to our array.
339 width = 0;
340 precision = 0;
342 /* Handle the flags */
344 while (dprintf_IsQualifierNoDollar(*fmt)) {
345 switch (*fmt++) {
346 case ' ':
347 flags |= FLAGS_SPACE;
348 break;
349 case '+':
350 flags |= FLAGS_SHOWSIGN;
351 break;
352 case '-':
353 flags |= FLAGS_LEFT;
354 flags &= ~FLAGS_PAD_NIL;
355 break;
356 case '#':
357 flags |= FLAGS_ALT;
358 break;
359 case '.':
360 flags |= FLAGS_PREC;
361 if ('*' == *fmt) {
362 /* The precision is picked from a specified parameter */
364 flags |= FLAGS_PRECPARAM;
365 fmt++;
366 param_num++;
368 i = dprintf_DollarString(fmt, &fmt);
369 if (i)
370 precision = i;
371 else
372 precision = param_num;
374 if (precision > max_param)
375 max_param = precision;
377 else {
378 flags |= FLAGS_PREC;
379 precision = strtol(fmt, &fmt, 10);
381 break;
382 case 'h':
383 flags |= FLAGS_SHORT;
384 break;
385 case 'l':
386 if (flags & FLAGS_LONG)
387 flags |= FLAGS_LONGLONG;
388 else
389 flags |= FLAGS_LONG;
390 break;
391 case 'L':
392 flags |= FLAGS_LONGDOUBLE;
393 break;
394 case 'q':
395 flags |= FLAGS_LONGLONG;
396 break;
397 case 'z':
398 /* the code below generates a warning if -Wunreachable-code is
399 used */
400 #if SIZEOF_SIZE_T>4
401 flags |= FLAGS_LONGLONG;
402 #else
403 flags |= FLAGS_LONG;
404 #endif
405 break;
406 case 'O':
407 #if SIZEOF_CURL_OFF_T > 4
408 flags |= FLAGS_LONGLONG;
409 #else
410 flags |= FLAGS_LONG;
411 #endif
412 break;
413 case '0':
414 if (!(flags & FLAGS_LEFT))
415 flags |= FLAGS_PAD_NIL;
416 /* FALLTHROUGH */
417 case '1': case '2': case '3': case '4':
418 case '5': case '6': case '7': case '8': case '9':
419 flags |= FLAGS_WIDTH;
420 width = strtol(fmt-1, &fmt, 10);
421 break;
422 case '*': /* Special case */
423 flags |= FLAGS_WIDTHPARAM;
424 param_num++;
426 i = dprintf_DollarString(fmt, &fmt);
427 if(i)
428 width = i;
429 else
430 width = param_num;
431 if(width > max_param)
432 max_param=width;
433 break;
434 default:
435 break;
437 } /* switch */
439 /* Handle the specifier */
441 i = this_param - 1;
443 switch (*fmt) {
444 case 'S':
445 flags |= FLAGS_ALT;
446 /* FALLTHROUGH */
447 case 's':
448 vto[i].type = FORMAT_STRING;
449 break;
450 case 'n':
451 vto[i].type = FORMAT_INTPTR;
452 break;
453 case 'p':
454 vto[i].type = FORMAT_PTR;
455 break;
456 case 'd': case 'i':
457 vto[i].type = FORMAT_INT;
458 break;
459 case 'u':
460 vto[i].type = FORMAT_INT;
461 flags |= FLAGS_UNSIGNED;
462 break;
463 case 'o':
464 vto[i].type = FORMAT_INT;
465 flags |= FLAGS_OCTAL;
466 break;
467 case 'x':
468 vto[i].type = FORMAT_INT;
469 flags |= FLAGS_HEX;
470 break;
471 case 'X':
472 vto[i].type = FORMAT_INT;
473 flags |= FLAGS_HEX|FLAGS_UPPER;
474 break;
475 case 'c':
476 vto[i].type = FORMAT_INT;
477 flags |= FLAGS_CHAR;
478 break;
479 case 'f':
480 vto[i].type = FORMAT_DOUBLE;
481 break;
482 case 'e':
483 vto[i].type = FORMAT_DOUBLE;
484 flags |= FLAGS_FLOATE;
485 break;
486 case 'E':
487 vto[i].type = FORMAT_DOUBLE;
488 flags |= FLAGS_FLOATE|FLAGS_UPPER;
489 break;
490 case 'g':
491 vto[i].type = FORMAT_DOUBLE;
492 flags |= FLAGS_FLOATG;
493 break;
494 case 'G':
495 vto[i].type = FORMAT_DOUBLE;
496 flags |= FLAGS_FLOATG|FLAGS_UPPER;
497 break;
498 default:
499 vto[i].type = FORMAT_UNKNOWN;
500 break;
501 } /* switch */
503 vto[i].flags = flags;
504 vto[i].width = width;
505 vto[i].precision = precision;
507 if (flags & FLAGS_WIDTHPARAM) {
508 /* we have the width specified from a parameter, so we make that
509 parameter's info setup properly */
510 vto[i].width = width - 1;
511 i = width - 1;
512 vto[i].type = FORMAT_WIDTH;
513 vto[i].flags = FLAGS_NEW;
514 vto[i].precision = vto[i].width = 0; /* can't use width or precision
515 of width! */
517 if (flags & FLAGS_PRECPARAM) {
518 /* we have the precision specified from a parameter, so we make that
519 parameter's info setup properly */
520 vto[i].precision = precision - 1;
521 i = precision - 1;
522 vto[i].type = FORMAT_WIDTH;
523 vto[i].flags = FLAGS_NEW;
524 vto[i].precision = vto[i].width = 0; /* can't use width or precision
525 of width! */
527 *endpos++ = fmt + 1; /* end of this sequence */
531 #ifdef DPRINTF_DEBUG2
532 dprintf_Pass1Report(vto, max_param);
533 #endif
535 /* Read the arg list parameters into our data list */
536 for (i=0; i<max_param; i++) {
537 if ((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH))
539 /* Width/precision arguments must be read before the main argument
540 * they are attached to
542 vto[i + 1].data.num = va_arg(arglist, int);
545 switch (vto[i].type)
547 case FORMAT_STRING:
548 vto[i].data.str = va_arg(arglist, char *);
549 break;
551 case FORMAT_INTPTR:
552 case FORMAT_UNKNOWN:
553 case FORMAT_PTR:
554 vto[i].data.ptr = va_arg(arglist, void *);
555 break;
557 case FORMAT_INT:
558 #ifdef ENABLE_64BIT
559 if(vto[i].flags & FLAGS_LONGLONG)
560 vto[i].data.lnum = va_arg(arglist, LONG_LONG);
561 else
562 #endif
563 if(vto[i].flags & FLAGS_LONG)
564 vto[i].data.num = va_arg(arglist, long);
565 else
566 vto[i].data.num = va_arg(arglist, int);
567 break;
569 case FORMAT_DOUBLE:
570 vto[i].data.dnum = va_arg(arglist, double);
571 break;
573 case FORMAT_WIDTH:
574 /* Argument has been read. Silently convert it into an integer
575 * for later use
577 vto[i].type = FORMAT_INT;
578 break;
580 default:
581 break;
585 return max_param;
589 static int dprintf_formatf(
590 void *data, /* untouched by format(), just sent to the stream() function in
591 the second argument */
592 /* function pointer called for each output character */
593 int (*stream)(int, FILE *),
594 const char *format, /* %-formatted string */
595 va_list ap_save) /* list of parameters */
597 /* Base-36 digits for numbers. */
598 const char *digits = lower_digits;
600 /* Pointer into the format string. */
601 char *f;
603 /* Number of characters written. */
604 int done = 0;
606 long param; /* current parameter to read */
607 long param_num=0; /* parameter counter */
609 va_stack_t vto[MAX_PARAMETERS];
610 char *endpos[MAX_PARAMETERS];
611 char **end;
613 char work[BUFFSIZE];
615 va_stack_t *p;
617 /* Do the actual %-code parsing */
618 dprintf_Pass1((char *)format, vto, endpos, ap_save);
620 end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
621 created for us */
623 f = (char *)format;
624 while (*f != '\0') {
625 /* Format spec modifiers. */
626 char alt;
628 /* Width of a field. */
629 long width;
631 /* Precision of a field. */
632 long prec;
634 /* Decimal integer is negative. */
635 char is_neg;
637 /* Base of a number to be written. */
638 long base;
640 /* Integral values to be written. */
641 #ifdef ENABLE_64BIT
642 unsigned LONG_LONG num;
643 #else
644 unsigned long num;
645 #endif
646 long signed_num;
648 if (*f != '%') {
649 /* This isn't a format spec, so write everything out until the next one
650 OR end of string is reached. */
651 do {
652 OUTCHAR(*f);
653 } while(*++f && ('%' != *f));
654 continue;
657 ++f;
659 /* Check for "%%". Note that although the ANSI standard lists
660 '%' as a conversion specifier, it says "The complete format
661 specification shall be `%%'," so we can avoid all the width
662 and precision processing. */
663 if (*f == '%') {
664 ++f;
665 OUTCHAR('%');
666 continue;
669 /* If this is a positional parameter, the position must follow imediately
670 after the %, thus create a %<num>$ sequence */
671 param=dprintf_DollarString(f, &f);
673 if(!param)
674 param = param_num;
675 else
676 --param;
678 param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
679 third %s will pick the 3rd argument */
681 p = &vto[param];
683 /* pick up the specified width */
684 if(p->flags & FLAGS_WIDTHPARAM)
685 width = vto[p->width].data.num;
686 else
687 width = p->width;
689 /* pick up the specified precision */
690 if(p->flags & FLAGS_PRECPARAM)
691 prec = vto[p->precision].data.num;
692 else if(p->flags & FLAGS_PREC)
693 prec = p->precision;
694 else
695 prec = -1;
697 alt = (p->flags & FLAGS_ALT)?TRUE:FALSE;
699 switch (p->type) {
700 case FORMAT_INT:
701 num = p->data.num;
702 if(p->flags & FLAGS_CHAR) {
703 /* Character. */
704 if (!(p->flags & FLAGS_LEFT))
705 while (--width > 0)
706 OUTCHAR(' ');
707 OUTCHAR((char) num);
708 if (p->flags & FLAGS_LEFT)
709 while (--width > 0)
710 OUTCHAR(' ');
711 break;
713 if(p->flags & FLAGS_UNSIGNED) {
714 /* Decimal unsigned integer. */
715 base = 10;
716 goto unsigned_number;
718 if(p->flags & FLAGS_OCTAL) {
719 /* Octal unsigned integer. */
720 base = 8;
721 goto unsigned_number;
723 if(p->flags & FLAGS_HEX) {
724 /* Hexadecimal unsigned integer. */
726 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
727 base = 16;
728 goto unsigned_number;
731 /* Decimal integer. */
732 base = 10;
734 #ifdef ENABLE_64BIT
735 if(p->flags & FLAGS_LONGLONG) {
736 /* long long */
737 is_neg = p->data.lnum < 0;
738 num = is_neg ? (- p->data.lnum) : p->data.lnum;
740 else
741 #endif
743 signed_num = (long) num;
744 is_neg = signed_num < 0;
745 num = is_neg ? (- signed_num) : signed_num;
747 goto number;
749 unsigned_number:
750 /* Unsigned number of base BASE. */
751 is_neg = 0;
753 number:
754 /* Number of base BASE. */
756 char *workend = &work[sizeof(work) - 1];
757 char *w;
759 /* Supply a default precision if none was given. */
760 if (prec == -1)
761 prec = 1;
763 /* Put the number in WORK. */
764 w = workend;
765 while (num > 0) {
766 *w-- = digits[num % base];
767 num /= base;
769 width -= (long)(workend - w);
770 prec -= (long)(workend - w);
772 if (alt && base == 8 && prec <= 0) {
773 *w-- = '0';
774 --width;
777 if (prec > 0) {
778 width -= prec;
779 while (prec-- > 0)
780 *w-- = '0';
783 if (alt && base == 16)
784 width -= 2;
786 if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
787 --width;
789 if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
790 while (width-- > 0)
791 OUTCHAR(' ');
793 if (is_neg)
794 OUTCHAR('-');
795 else if (p->flags & FLAGS_SHOWSIGN)
796 OUTCHAR('+');
797 else if (p->flags & FLAGS_SPACE)
798 OUTCHAR(' ');
800 if (alt && base == 16) {
801 OUTCHAR('0');
802 if(p->flags & FLAGS_UPPER)
803 OUTCHAR('X');
804 else
805 OUTCHAR('x');
808 if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
809 while (width-- > 0)
810 OUTCHAR('0');
812 /* Write the number. */
813 while (++w <= workend) {
814 OUTCHAR(*w);
817 if (p->flags & FLAGS_LEFT)
818 while (width-- > 0)
819 OUTCHAR(' ');
821 break;
823 case FORMAT_STRING:
824 /* String. */
826 static const char null[] = "(nil)";
827 const char *str;
828 size_t len;
830 str = (char *) p->data.str;
831 if ( str == NULL) {
832 /* Write null[] if there's space. */
833 if (prec == -1 || prec >= (long) sizeof(null) - 1) {
834 str = null;
835 len = sizeof(null) - 1;
836 /* Disable quotes around (nil) */
837 p->flags &= (~FLAGS_ALT);
839 else {
840 str = "";
841 len = 0;
844 else
845 len = strlen(str);
847 if (prec != -1 && (size_t) prec < len)
848 len = prec;
849 width -= (long)len;
851 if (p->flags & FLAGS_ALT)
852 OUTCHAR('"');
854 if (!(p->flags&FLAGS_LEFT))
855 while (width-- > 0)
856 OUTCHAR(' ');
858 while (len-- > 0)
859 OUTCHAR(*str++);
860 if (p->flags&FLAGS_LEFT)
861 while (width-- > 0)
862 OUTCHAR(' ');
864 if (p->flags & FLAGS_ALT)
865 OUTCHAR('"');
867 break;
869 case FORMAT_PTR:
870 /* Generic pointer. */
872 void *ptr;
873 ptr = (void *) p->data.ptr;
874 if (ptr != NULL) {
875 /* If the pointer is not NULL, write it as a %#x spec. */
876 base = 16;
877 digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
878 alt = 1;
879 num = (size_t) ptr;
880 is_neg = 0;
881 goto number;
883 else {
884 /* Write "(nil)" for a nil pointer. */
885 static const char strnil[] = "(nil)";
886 const char *point;
888 width -= sizeof(strnil) - 1;
889 if (p->flags & FLAGS_LEFT)
890 while (width-- > 0)
891 OUTCHAR(' ');
892 for (point = strnil; *point != '\0'; ++point)
893 OUTCHAR(*point);
894 if (! (p->flags & FLAGS_LEFT))
895 while (width-- > 0)
896 OUTCHAR(' ');
899 break;
901 case FORMAT_DOUBLE:
903 char formatbuf[32]="%";
904 char *fptr;
905 size_t left = sizeof(formatbuf)-strlen(formatbuf);
906 int len;
908 width = -1;
909 if (p->flags & FLAGS_WIDTH)
910 width = p->width;
911 else if (p->flags & FLAGS_WIDTHPARAM)
912 width = vto[p->width].data.num;
914 prec = -1;
915 if (p->flags & FLAGS_PREC)
916 prec = p->precision;
917 else if (p->flags & FLAGS_PRECPARAM)
918 prec = vto[p->precision].data.num;
920 if (p->flags & FLAGS_LEFT)
921 strcat(formatbuf, "-");
922 if (p->flags & FLAGS_SHOWSIGN)
923 strcat(formatbuf, "+");
924 if (p->flags & FLAGS_SPACE)
925 strcat(formatbuf, " ");
926 if (p->flags & FLAGS_ALT)
927 strcat(formatbuf, "#");
929 fptr=&formatbuf[strlen(formatbuf)];
931 if(width >= 0) {
932 /* RECURSIVE USAGE */
933 len = curl_msnprintf(fptr, left, "%ld", width);
934 fptr += len;
935 left -= len;
937 if(prec >= 0) {
938 /* RECURSIVE USAGE */
939 len = curl_msnprintf(fptr, left, ".%ld", prec);
940 fptr += len;
941 left -= len;
943 if (p->flags & FLAGS_LONG)
944 *fptr++ = 'l';
946 if (p->flags & FLAGS_FLOATE)
947 *fptr++ = p->flags&FLAGS_UPPER ? 'E':'e';
948 else if (p->flags & FLAGS_FLOATG)
949 *fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g';
950 else
951 *fptr++ = 'f';
953 *fptr = 0; /* and a final zero termination */
955 /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number
956 of output characters */
957 (sprintf)(work, formatbuf, p->data.dnum);
959 for(fptr=work; *fptr; fptr++)
960 OUTCHAR(*fptr);
962 break;
964 case FORMAT_INTPTR:
965 /* Answer the count of characters written. */
966 #ifdef ENABLE_64BIT
967 if (p->flags & FLAGS_LONGLONG)
968 *(LONG_LONG *) p->data.ptr = (LONG_LONG)done;
969 else
970 #endif
971 if (p->flags & FLAGS_LONG)
972 *(long *) p->data.ptr = (long)done;
973 else if (!(p->flags & FLAGS_SHORT))
974 *(int *) p->data.ptr = (int)done;
975 else
976 *(short *) p->data.ptr = (short)done;
977 break;
979 default:
980 break;
982 f = *end++; /* goto end of %-code */
985 return done;
988 /* fputc() look-alike */
989 static int addbyter(int output, FILE *data)
991 struct nsprintf *infop=(struct nsprintf *)data;
992 unsigned char outc = (unsigned char)output;
994 if(infop->length < infop->max) {
995 /* only do this if we haven't reached max length yet */
996 infop->buffer[0] = outc; /* store */
997 infop->buffer++; /* increase pointer */
998 infop->length++; /* we are now one byte larger */
999 return outc; /* fputc() returns like this on success */
1001 return -1;
1004 int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
1005 va_list ap_save)
1007 int retcode;
1008 struct nsprintf info;
1010 info.buffer = buffer;
1011 info.length = 0;
1012 info.max = maxlength;
1014 retcode = dprintf_formatf(&info, addbyter, format, ap_save);
1015 if(info.max) {
1016 /* we terminate this with a zero byte */
1017 if(info.max == info.length)
1018 /* we're at maximum, scrap the last letter */
1019 info.buffer[-1] = 0;
1020 else
1021 info.buffer[0] = 0;
1023 return retcode;
1026 int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
1028 int retcode;
1029 va_list ap_save; /* argument pointer */
1030 va_start(ap_save, format);
1031 retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
1032 va_end(ap_save);
1033 return retcode;
1036 /* fputc() look-alike */
1037 static int alloc_addbyter(int output, FILE *data)
1039 struct asprintf *infop=(struct asprintf *)data;
1040 unsigned char outc = (unsigned char)output;
1042 if(!infop->buffer) {
1043 infop->buffer=(char *)malloc(32);
1044 if(!infop->buffer) {
1045 infop->fail = TRUE;
1046 return -1; /* fail */
1048 infop->alloc = 32;
1049 infop->len =0;
1051 else if(infop->len+1 >= infop->alloc) {
1052 char *newptr;
1054 newptr = (char *)realloc(infop->buffer, infop->alloc*2);
1056 if(!newptr) {
1057 infop->fail = TRUE;
1058 return -1;
1060 infop->buffer = newptr;
1061 infop->alloc *= 2;
1064 infop->buffer[ infop->len ] = outc;
1066 infop->len++;
1068 return outc; /* fputc() returns like this on success */
1071 char *curl_maprintf(const char *format, ...)
1073 va_list ap_save; /* argument pointer */
1074 int retcode;
1075 struct asprintf info;
1077 info.buffer = NULL;
1078 info.len = 0;
1079 info.alloc = 0;
1080 info.fail = FALSE;
1082 va_start(ap_save, format);
1083 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1084 va_end(ap_save);
1085 if((-1 == retcode) || info.fail) {
1086 if(info.alloc)
1087 free(info.buffer);
1088 return NULL;
1090 if(info.alloc) {
1091 info.buffer[info.len] = 0; /* we terminate this with a zero byte */
1092 return info.buffer;
1094 else
1095 return strdup("");
1098 char *curl_mvaprintf(const char *format, va_list ap_save)
1100 int retcode;
1101 struct asprintf info;
1103 info.buffer = NULL;
1104 info.len = 0;
1105 info.alloc = 0;
1106 info.fail = FALSE;
1108 retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
1109 if((-1 == retcode) || info.fail) {
1110 if(info.alloc)
1111 free(info.buffer);
1112 return NULL;
1115 if(info.alloc) {
1116 info.buffer[info.len] = 0; /* we terminate this with a zero byte */
1117 return info.buffer;
1119 else
1120 return strdup("");
1123 static int storebuffer(int output, FILE *data)
1125 char **buffer = (char **)data;
1126 unsigned char outc = (unsigned char)output;
1127 **buffer = outc;
1128 (*buffer)++;
1129 return outc; /* act like fputc() ! */
1132 int curl_msprintf(char *buffer, const char *format, ...)
1134 va_list ap_save; /* argument pointer */
1135 int retcode;
1136 va_start(ap_save, format);
1137 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1138 va_end(ap_save);
1139 *buffer=0; /* we terminate this with a zero byte */
1140 return retcode;
1143 int curl_mprintf(const char *format, ...)
1145 int retcode;
1146 va_list ap_save; /* argument pointer */
1147 va_start(ap_save, format);
1149 retcode = dprintf_formatf(stdout, fputc, format, ap_save);
1150 va_end(ap_save);
1151 return retcode;
1154 int curl_mfprintf(FILE *whereto, const char *format, ...)
1156 int retcode;
1157 va_list ap_save; /* argument pointer */
1158 va_start(ap_save, format);
1159 retcode = dprintf_formatf(whereto, fputc, format, ap_save);
1160 va_end(ap_save);
1161 return retcode;
1164 int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
1166 int retcode;
1167 retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
1168 *buffer=0; /* we terminate this with a zero byte */
1169 return retcode;
1172 int curl_mvprintf(const char *format, va_list ap_save)
1174 return dprintf_formatf(stdout, fputc, format, ap_save);
1177 int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1179 return dprintf_formatf(whereto, fputc, format, ap_save);
1182 #ifdef DPRINTF_DEBUG
1183 int main()
1185 char buffer[129];
1186 char *ptr;
1187 #ifdef ENABLE_64BIT
1188 long long one=99;
1189 long long two=100;
1190 long long test = 0x1000000000LL;
1191 curl_mprintf("%lld %lld %lld\n", one, two, test);
1192 #endif
1194 curl_mprintf("%3d %5d\n", 10, 1998);
1196 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);
1198 puts(ptr);
1200 memset(ptr, 55, strlen(ptr)+1);
1202 free(ptr);
1204 #if 1
1205 curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988);
1206 puts(buffer);
1208 curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65);
1210 printf("%s %#08x\n", "dummy", 65);
1212 double tryout = 3.14156592;
1213 curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout);
1214 puts(buffer);
1215 printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout);
1217 #endif
1219 return 0;
1222 #endif