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