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