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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16