Home | History | Annotate | Line # | Download | only in printf
      1      1.1  mrg /* __gmp_replacement_vsnprintf -- for systems which don't have vsnprintf, or
      2      1.1  mrg    only have a broken one.
      3      1.1  mrg 
      4      1.1  mrg    THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
      5      1.1  mrg    CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
      6      1.1  mrg    FUTURE GNU MP RELEASES.
      7      1.1  mrg 
      8  1.1.1.3  mrg Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
      9      1.1  mrg 
     10      1.1  mrg This file is part of the GNU MP Library.
     11      1.1  mrg 
     12      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
     13  1.1.1.2  mrg it under the terms of either:
     14  1.1.1.2  mrg 
     15  1.1.1.2  mrg   * the GNU Lesser General Public License as published by the Free
     16  1.1.1.2  mrg     Software Foundation; either version 3 of the License, or (at your
     17  1.1.1.2  mrg     option) any later version.
     18  1.1.1.2  mrg 
     19  1.1.1.2  mrg or
     20  1.1.1.2  mrg 
     21  1.1.1.2  mrg   * the GNU General Public License as published by the Free Software
     22  1.1.1.2  mrg     Foundation; either version 2 of the License, or (at your option) any
     23  1.1.1.2  mrg     later version.
     24  1.1.1.2  mrg 
     25  1.1.1.2  mrg or both in parallel, as here.
     26      1.1  mrg 
     27      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     28      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     29  1.1.1.2  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     30  1.1.1.2  mrg for more details.
     31      1.1  mrg 
     32  1.1.1.2  mrg You should have received copies of the GNU General Public License and the
     33  1.1.1.2  mrg GNU Lesser General Public License along with the GNU MP Library.  If not,
     34  1.1.1.2  mrg see https://www.gnu.org/licenses/.  */
     35      1.1  mrg 
     36      1.1  mrg #include "config.h"
     37      1.1  mrg 
     38      1.1  mrg #define _GNU_SOURCE    /* for strnlen prototype */
     39      1.1  mrg 
     40      1.1  mrg #include <stdarg.h>
     41      1.1  mrg #include <ctype.h>     /* for isdigit */
     42      1.1  mrg #include <stddef.h>    /* for ptrdiff_t */
     43      1.1  mrg #include <string.h>
     44      1.1  mrg #include <stdio.h>     /* for NULL */
     45      1.1  mrg #include <stdlib.h>
     46      1.1  mrg 
     47      1.1  mrg #if HAVE_FLOAT_H
     48      1.1  mrg #include <float.h>     /* for DBL_MAX_10_EXP etc */
     49      1.1  mrg #endif
     50      1.1  mrg 
     51      1.1  mrg #if HAVE_INTTYPES_H
     52      1.1  mrg # include <inttypes.h> /* for intmax_t */
     53      1.1  mrg #else
     54      1.1  mrg # if HAVE_STDINT_H
     55      1.1  mrg #  include <stdint.h>
     56      1.1  mrg # endif
     57      1.1  mrg #endif
     58      1.1  mrg 
     59      1.1  mrg #if HAVE_SYS_TYPES_H
     60      1.1  mrg #include <sys/types.h> /* for quad_t */
     61      1.1  mrg #endif
     62      1.1  mrg 
     63      1.1  mrg #include "gmp-impl.h"
     64      1.1  mrg 
     65      1.1  mrg 
     66  1.1.1.3  mrg #if ! HAVE_VSNPRINTF   /* only need this file if we don't have vsnprintf */
     67  1.1.1.3  mrg 
     68      1.1  mrg /* Autoconf notes that AIX 4.3 has a broken strnlen, but fortunately it
     69      1.1  mrg    doesn't affect us since __gmp_replacement_vsnprintf is not required on
     70      1.1  mrg    that system.  */
     71      1.1  mrg #if ! HAVE_STRNLEN
     72      1.1  mrg static size_t
     73      1.1  mrg strnlen (const char *s, size_t n)
     74      1.1  mrg {
     75      1.1  mrg   size_t  i;
     76      1.1  mrg   for (i = 0; i < n; i++)
     77      1.1  mrg     if (s[i] == '\0')
     78      1.1  mrg       break;
     79      1.1  mrg   return i;
     80      1.1  mrg }
     81      1.1  mrg #endif
     82      1.1  mrg 
     83      1.1  mrg 
     84      1.1  mrg /* The approach here is to parse the fmt string, and decide how much space
     85      1.1  mrg    it requires, then use vsprintf into a big enough buffer.  The space
     86      1.1  mrg    calculated isn't an exact amount, but it's certainly no less than
     87      1.1  mrg    required.
     88      1.1  mrg 
     89      1.1  mrg    This code was inspired by GNU libiberty/vasprintf.c but we support more
     90      1.1  mrg    datatypes, when available.
     91      1.1  mrg 
     92      1.1  mrg    mingw32 - doesn't have vsnprintf, it seems.  Because gcc is used a full
     93      1.1  mrg        set of types are available, but "long double" is just a plain IEEE
     94      1.1  mrg        64-bit "double" and LDBL_MAX_EXP_10 is correspondingly defined, so we
     95      1.1  mrg        avoid the big 15-bit exponent estimate.  */
     96      1.1  mrg 
     97      1.1  mrg int
     98      1.1  mrg __gmp_replacement_vsnprintf (char *buf, size_t buf_size,
     99      1.1  mrg 			     const char *orig_fmt, va_list orig_ap)
    100      1.1  mrg {
    101      1.1  mrg   va_list     ap;
    102      1.1  mrg   const char  *fmt;
    103      1.1  mrg   size_t      total_width, integer_sizeof, floating_sizeof, len;
    104      1.1  mrg   char        fchar, type;
    105      1.1  mrg   int         width, prec, seen_prec, double_digits, long_double_digits;
    106      1.1  mrg   int         *value;
    107      1.1  mrg 
    108      1.1  mrg   /* preserve orig_ap for use after size estimation */
    109      1.1  mrg   va_copy (ap, orig_ap);
    110      1.1  mrg 
    111      1.1  mrg   fmt = orig_fmt;
    112      1.1  mrg   total_width = strlen (fmt) + 1;   /* 1 extra for the '\0' */
    113      1.1  mrg 
    114      1.1  mrg   integer_sizeof = sizeof (long);
    115      1.1  mrg #if HAVE_LONG_LONG
    116      1.1  mrg   integer_sizeof = MAX (integer_sizeof, sizeof (long long));
    117      1.1  mrg #endif
    118      1.1  mrg #if HAVE_QUAD_T
    119      1.1  mrg   integer_sizeof = MAX (integer_sizeof, sizeof (quad_t));
    120      1.1  mrg #endif
    121      1.1  mrg 
    122      1.1  mrg   floating_sizeof = sizeof (double);
    123      1.1  mrg #if HAVE_LONG_DOUBLE
    124      1.1  mrg   floating_sizeof = MAX (floating_sizeof, sizeof (long double));
    125      1.1  mrg #endif
    126      1.1  mrg 
    127      1.1  mrg   /* IEEE double or VAX G floats have an 11 bit exponent, so the default is
    128      1.1  mrg      a maximum 308 decimal digits.  VAX D floats have only an 8 bit
    129      1.1  mrg      exponent, but we don't bother trying to detect that directly.  */
    130      1.1  mrg   double_digits = 308;
    131      1.1  mrg #ifdef DBL_MAX_10_EXP
    132      1.1  mrg   /* but in any case prefer a value the compiler says */
    133      1.1  mrg   double_digits = DBL_MAX_10_EXP;
    134      1.1  mrg #endif
    135      1.1  mrg 
    136      1.1  mrg   /* IEEE 128-bit quad, Intel 80-bit temporary, or VAX H floats all have 15
    137      1.1  mrg      bit exponents, so the default is a maximum 4932 decimal digits.  */
    138      1.1  mrg   long_double_digits = 4932;
    139      1.1  mrg   /* but if double == long double, then go with that size */
    140      1.1  mrg #if HAVE_LONG_DOUBLE
    141      1.1  mrg   if (sizeof (double) == sizeof (long double))
    142      1.1  mrg     long_double_digits = double_digits;
    143      1.1  mrg #endif
    144      1.1  mrg #ifdef LDBL_MAX_10_EXP
    145      1.1  mrg   /* but in any case prefer a value the compiler says */
    146      1.1  mrg   long_double_digits = LDBL_MAX_10_EXP;
    147      1.1  mrg #endif
    148      1.1  mrg 
    149      1.1  mrg   for (;;)
    150      1.1  mrg     {
    151      1.1  mrg       fmt = strchr (fmt, '%');
    152      1.1  mrg       if (fmt == NULL)
    153      1.1  mrg 	break;
    154      1.1  mrg       fmt++;
    155      1.1  mrg 
    156      1.1  mrg       type = '\0';
    157      1.1  mrg       width = 0;
    158      1.1  mrg       prec = 6;
    159      1.1  mrg       seen_prec = 0;
    160      1.1  mrg       value = &width;
    161      1.1  mrg 
    162      1.1  mrg       for (;;)
    163      1.1  mrg 	{
    164      1.1  mrg 	  fchar = *fmt++;
    165      1.1  mrg 	  switch (fchar) {
    166      1.1  mrg 
    167      1.1  mrg 	  case 'c':
    168      1.1  mrg 	    /* char, already accounted for by strlen(fmt) */
    169      1.1  mrg 	    goto next;
    170      1.1  mrg 
    171      1.1  mrg 	  case 'd':
    172      1.1  mrg 	  case 'i':
    173      1.1  mrg 	  case 'o':
    174      1.1  mrg 	  case 'x':
    175      1.1  mrg 	  case 'X':
    176      1.1  mrg 	  case 'u':
    177      1.1  mrg 	    /* at most 3 digits per byte in hex, dec or octal, plus a sign */
    178      1.1  mrg 	    total_width += 3 * integer_sizeof + 1;
    179      1.1  mrg 
    180      1.1  mrg 	    switch (type) {
    181      1.1  mrg 	    case 'j':
    182      1.1  mrg 	      /* Let's assume uintmax_t is the same size as intmax_t. */
    183      1.1  mrg #if HAVE_INTMAX_T
    184      1.1  mrg 	      (void) va_arg (ap, intmax_t);
    185      1.1  mrg #else
    186      1.1  mrg 	      ASSERT_FAIL (intmax_t not available);
    187      1.1  mrg #endif
    188      1.1  mrg 	      break;
    189      1.1  mrg 	    case 'l':
    190      1.1  mrg 	      (void) va_arg (ap, long);
    191      1.1  mrg 	      break;
    192      1.1  mrg 	    case 'L':
    193      1.1  mrg #if HAVE_LONG_LONG
    194      1.1  mrg 	      (void) va_arg (ap, long long);
    195      1.1  mrg #else
    196      1.1  mrg 	      ASSERT_FAIL (long long not available);
    197      1.1  mrg #endif
    198      1.1  mrg 	      break;
    199      1.1  mrg 	    case 'q':
    200      1.1  mrg 	      /* quad_t is probably the same as long long, but let's treat
    201      1.1  mrg 		 it separately just to be sure.  Also let's assume u_quad_t
    202      1.1  mrg 		 will be the same size as quad_t.  */
    203      1.1  mrg #if HAVE_QUAD_T
    204      1.1  mrg 	      (void) va_arg (ap, quad_t);
    205      1.1  mrg #else
    206      1.1  mrg 	      ASSERT_FAIL (quad_t not available);
    207      1.1  mrg #endif
    208      1.1  mrg 	      break;
    209      1.1  mrg 	    case 't':
    210      1.1  mrg #if HAVE_PTRDIFF_T
    211      1.1  mrg 	      (void) va_arg (ap, ptrdiff_t);
    212      1.1  mrg #else
    213      1.1  mrg 	      ASSERT_FAIL (ptrdiff_t not available);
    214      1.1  mrg #endif
    215      1.1  mrg 	      break;
    216      1.1  mrg 	    case 'z':
    217      1.1  mrg 	      (void) va_arg (ap, size_t);
    218      1.1  mrg 	      break;
    219      1.1  mrg 	    default:
    220      1.1  mrg 	      /* default is an "int", and this includes h=short and hh=char
    221      1.1  mrg 		 since they're promoted to int in a function call */
    222      1.1  mrg 	      (void) va_arg (ap, int);
    223      1.1  mrg 	      break;
    224      1.1  mrg 	    }
    225      1.1  mrg 	    goto next;
    226      1.1  mrg 
    227      1.1  mrg 	  case 'E':
    228      1.1  mrg 	  case 'e':
    229      1.1  mrg 	  case 'G':
    230      1.1  mrg 	  case 'g':
    231      1.1  mrg 	    /* Requested decimals, sign, point and e, plus an overestimate
    232      1.1  mrg 	       of exponent digits (the assumption is all the float is
    233      1.1  mrg 	       exponent!).  */
    234      1.1  mrg 	    total_width += prec + 3 + floating_sizeof * 3;
    235      1.1  mrg 	    if (type == 'L')
    236      1.1  mrg 	      {
    237      1.1  mrg #if HAVE_LONG_DOUBLE
    238      1.1  mrg 		(void) va_arg (ap, long double);
    239      1.1  mrg #else
    240      1.1  mrg 		ASSERT_FAIL (long double not available);
    241      1.1  mrg #endif
    242      1.1  mrg 	      }
    243      1.1  mrg 	    else
    244      1.1  mrg 	      (void) va_arg (ap, double);
    245  1.1.1.3  mrg 	    goto next;
    246      1.1  mrg 
    247      1.1  mrg 	  case 'f':
    248      1.1  mrg 	    /* Requested decimals, sign and point, and a margin for error,
    249      1.1  mrg 	       then add the maximum digits that can be in the integer part,
    250      1.1  mrg 	       based on the maximum exponent value. */
    251      1.1  mrg 	    total_width += prec + 2 + 10;
    252      1.1  mrg 	    if (type == 'L')
    253      1.1  mrg 	      {
    254      1.1  mrg #if HAVE_LONG_DOUBLE
    255      1.1  mrg 		(void) va_arg (ap, long double);
    256      1.1  mrg 		total_width += long_double_digits;
    257      1.1  mrg #else
    258      1.1  mrg 		ASSERT_FAIL (long double not available);
    259      1.1  mrg #endif
    260      1.1  mrg 	      }
    261      1.1  mrg 	    else
    262      1.1  mrg 	      {
    263      1.1  mrg 		(void) va_arg (ap, double);
    264      1.1  mrg 		total_width += double_digits;
    265      1.1  mrg 	      }
    266  1.1.1.3  mrg 	    goto next;
    267      1.1  mrg 
    268      1.1  mrg 	  case 'h':  /* short or char */
    269      1.1  mrg 	  case 'j':  /* intmax_t */
    270      1.1  mrg 	  case 'L':  /* long long or long double */
    271      1.1  mrg 	  case 'q':  /* quad_t */
    272      1.1  mrg 	  case 't':  /* ptrdiff_t */
    273  1.1.1.2  mrg 	  case 'z':  /* size_t */
    274      1.1  mrg 	  set_type:
    275      1.1  mrg 	    type = fchar;
    276      1.1  mrg 	    break;
    277      1.1  mrg 
    278      1.1  mrg 	  case 'l':
    279      1.1  mrg 	    /* long or long long */
    280      1.1  mrg 	    if (type != 'l')
    281      1.1  mrg 	      goto set_type;
    282      1.1  mrg 	    type = 'L';   /* "ll" means "L" */
    283      1.1  mrg 	    break;
    284      1.1  mrg 
    285      1.1  mrg 	  case 'n':
    286      1.1  mrg 	    /* bytes written, no output as such */
    287      1.1  mrg 	    (void) va_arg (ap, void *);
    288      1.1  mrg 	    goto next;
    289      1.1  mrg 
    290      1.1  mrg 	  case 's':
    291      1.1  mrg 	    /* If no precision was given, then determine the string length
    292      1.1  mrg 	       and put it there, to be added to the total under "next".  If
    293      1.1  mrg 	       a precision was given then that's already the maximum from
    294      1.1  mrg 	       this field, but see whether the string is shorter than that,
    295      1.1  mrg 	       in case the limit was very big.  */
    296      1.1  mrg 	    {
    297      1.1  mrg 	      const char  *s = va_arg (ap, const char *);
    298      1.1  mrg 	      prec = (seen_prec ? strnlen (s, prec) : strlen (s));
    299      1.1  mrg 	    }
    300      1.1  mrg 	    goto next;
    301      1.1  mrg 
    302      1.1  mrg 	  case 'p':
    303      1.1  mrg 	    /* pointer, let's assume at worst it's octal with some padding */
    304      1.1  mrg 	    (void) va_arg (ap, const void *);
    305      1.1  mrg 	    total_width += 3 * sizeof (void *) + 16;
    306      1.1  mrg 	    goto next;
    307      1.1  mrg 
    308      1.1  mrg 	  case '%':
    309      1.1  mrg 	    /* literal %, already accounted for by strlen(fmt) */
    310      1.1  mrg 	    goto next;
    311      1.1  mrg 
    312      1.1  mrg 	  case '#':
    313      1.1  mrg 	    /* showbase, at most 2 for "0x" */
    314      1.1  mrg 	    total_width += 2;
    315      1.1  mrg 	    break;
    316      1.1  mrg 
    317      1.1  mrg 	  case '+':
    318      1.1  mrg 	  case ' ':
    319      1.1  mrg 	    /* sign, already accounted for under numerics */
    320      1.1  mrg 	    break;
    321      1.1  mrg 
    322      1.1  mrg 	  case '-':
    323      1.1  mrg 	    /* left justify, no effect on total width */
    324      1.1  mrg 	    break;
    325      1.1  mrg 
    326      1.1  mrg 	  case '.':
    327      1.1  mrg 	    seen_prec = 1;
    328      1.1  mrg 	    value = &prec;
    329      1.1  mrg 	    break;
    330      1.1  mrg 
    331      1.1  mrg 	  case '*':
    332      1.1  mrg 	    {
    333      1.1  mrg 	      /* negative width means left justify which can be ignored,
    334      1.1  mrg 		 negative prec would be invalid, just use absolute value */
    335      1.1  mrg 	      int n = va_arg (ap, int);
    336      1.1  mrg 	      *value = ABS (n);
    337      1.1  mrg 	    }
    338      1.1  mrg 	    break;
    339      1.1  mrg 
    340      1.1  mrg 	  case '0': case '1': case '2': case '3': case '4':
    341      1.1  mrg 	  case '5': case '6': case '7': case '8': case '9':
    342      1.1  mrg 	    /* process all digits to form a value */
    343      1.1  mrg 	    {
    344      1.1  mrg 	      int  n = 0;
    345      1.1  mrg 	      do {
    346      1.1  mrg 		n = n * 10 + (fchar-'0');
    347      1.1  mrg 		fchar = *fmt++;
    348      1.1  mrg 	      } while (isascii (fchar) && isdigit (fchar));
    349      1.1  mrg 	      fmt--; /* unget the non-digit */
    350      1.1  mrg 	      *value = n;
    351      1.1  mrg 	    }
    352      1.1  mrg 	    break;
    353      1.1  mrg 
    354      1.1  mrg 	  default:
    355      1.1  mrg 	    /* incomplete or invalid % sequence */
    356      1.1  mrg 	    ASSERT (0);
    357      1.1  mrg 	    goto next;
    358      1.1  mrg 	  }
    359      1.1  mrg 	}
    360      1.1  mrg 
    361      1.1  mrg     next:
    362      1.1  mrg       total_width += width;
    363      1.1  mrg       total_width += prec;
    364      1.1  mrg     }
    365      1.1  mrg 
    366      1.1  mrg   if (total_width <= buf_size)
    367      1.1  mrg     {
    368      1.1  mrg       vsprintf (buf, orig_fmt, orig_ap);
    369      1.1  mrg       len = strlen (buf);
    370      1.1  mrg     }
    371      1.1  mrg   else
    372      1.1  mrg     {
    373      1.1  mrg       char  *s;
    374      1.1  mrg 
    375      1.1  mrg       s = __GMP_ALLOCATE_FUNC_TYPE (total_width, char);
    376      1.1  mrg       vsprintf (s, orig_fmt, orig_ap);
    377      1.1  mrg       len = strlen (s);
    378      1.1  mrg       if (buf_size != 0)
    379      1.1  mrg 	{
    380      1.1  mrg 	  size_t  copylen = MIN (len, buf_size-1);
    381      1.1  mrg 	  memcpy (buf, s, copylen);
    382      1.1  mrg 	  buf[copylen] = '\0';
    383      1.1  mrg 	}
    384  1.1.1.3  mrg       __GMP_FREE_FUNC_TYPE (s, total_width, char);
    385      1.1  mrg     }
    386      1.1  mrg 
    387      1.1  mrg   /* If total_width was somehow wrong then chances are we've already
    388      1.1  mrg      clobbered memory, but maybe this check will still work.  */
    389      1.1  mrg   ASSERT_ALWAYS (len < total_width);
    390      1.1  mrg 
    391      1.1  mrg   return len;
    392      1.1  mrg }
    393      1.1  mrg 
    394      1.1  mrg #endif /* ! HAVE_VSNPRINTF */
    395