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