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