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