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.  */
108static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
109
110/* Upper-case digits.  */
111static 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 */
122typedef 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 */
136enum {
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
160typedef 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
176struct nsprintf {
177  char *buffer;
178  size_t length;
179  size_t max;
180};
181
182struct 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
190static 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
205static 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
237static 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
555static 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 */
951static 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
966int 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
988int 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 */
999static 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
1033char *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
1060char *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
1085static 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
1094int 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
1105int 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
1116int 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
1126int 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
1134int curl_mvprintf(const char *format, va_list ap_save)
1135{
1136  return dprintf_formatf(stdout, fputc, format, ap_save);
1137}
1138
1139int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
1140{
1141  return dprintf_formatf(whereto, fputc, format, ap_save);
1142}
1143