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