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