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