github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/printf/repl-vsnprintf.c (about)

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