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