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