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