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