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