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