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