(root)/
gmp-6.3.0/
printf/
snprntffuns.c
       1  /* __gmp_snprintf_funs -- support for gmp_snprintf and gmp_vsnprintf.
       2  
       3     THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY.  THEY'RE ALMOST
       4     CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
       5     FUTURE GNU MP RELEASES.
       6  
       7  Copyright 2001, 2002, 2018 Free Software Foundation, Inc.
       8  
       9  This file is part of the GNU MP Library.
      10  
      11  The GNU MP Library is free software; you can redistribute it and/or modify
      12  it under the terms of either:
      13  
      14    * the GNU Lesser General Public License as published by the Free
      15      Software Foundation; either version 3 of the License, or (at your
      16      option) any later version.
      17  
      18  or
      19  
      20    * the GNU General Public License as published by the Free Software
      21      Foundation; either version 2 of the License, or (at your option) any
      22      later version.
      23  
      24  or both in parallel, as here.
      25  
      26  The GNU MP Library is distributed in the hope that it will be useful, but
      27  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      28  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      29  for more details.
      30  
      31  You should have received copies of the GNU General Public License and the
      32  GNU Lesser General Public License along with the GNU MP Library.  If not,
      33  see https://www.gnu.org/licenses/.  */
      34  
      35  #include <stdarg.h>
      36  #include <stdio.h>
      37  #include <string.h>
      38  
      39  #include "gmp-impl.h"
      40  
      41  
      42  #if ! HAVE_VSNPRINTF
      43  #define vsnprintf  __gmp_replacement_vsnprintf
      44  #endif
      45  
      46  
      47  /* glibc 2.0.x vsnprintf returns either -1 or size-1 for an overflow, with
      48     no indication how big the output would have been.  It's necessary to
      49     re-run to determine that size.
      50  
      51     "size-1" would mean success from a C99 vsnprintf, and the re-run is
      52     unnecessary in this case, but we don't bother to try to detect what sort
      53     of vsnprintf we've got.  size-1 should occur rarely in normal
      54     circumstances.
      55  
      56     vsnprintf might trash it's given ap (it does for instance in glibc 2.1.3
      57     on powerpc), so copy it in case we need to use it to probe for the size
      58     output that would have been produced.  Note there's no need to preserve
      59     it for our callers, just for ourselves.  */
      60  
      61  static int
      62  gmp_snprintf_format (struct gmp_snprintf_t *d, const char *fmt,
      63                       va_list orig_ap)
      64  {
      65    int      ret;
      66    size_t   step, alloc, avail;
      67    va_list  ap;
      68    char     *p;
      69  
      70    ASSERT (d->size >= 0);
      71  
      72    avail = d->size;
      73    if (avail > 1)
      74      {
      75        va_copy (ap, orig_ap);
      76        ret = vsnprintf (d->buf, avail, fmt, ap);
      77        if (ret == -1)
      78          return ret;
      79  
      80        step = MIN (ret, avail-1);
      81        d->size -= step;
      82        d->buf += step;
      83  
      84        if (ret != avail-1)
      85          return ret;
      86  
      87        /* probably glibc 2.0.x truncated output, probe for actual size */
      88        alloc = MAX (128, ret);
      89      }
      90    else
      91      {
      92        /* no space to write anything, just probe for size */
      93        alloc = 128;
      94      }
      95  
      96    do
      97      {
      98        alloc *= 2;
      99        p = __GMP_ALLOCATE_FUNC_TYPE (alloc, char);
     100        va_copy (ap, orig_ap);
     101        ret = vsnprintf (p, alloc, fmt, ap);
     102        __GMP_FREE_FUNC_TYPE (p, alloc, char);
     103      }
     104    while (ret == alloc-1);
     105  
     106    return ret;
     107  }
     108  
     109  static int
     110  gmp_snprintf_memory (struct gmp_snprintf_t *d, const char *str, size_t len)
     111  {
     112    size_t n;
     113  
     114    ASSERT (d->size >= 0);
     115  
     116    if (d->size > 1)
     117      {
     118        n = MIN (d->size-1, len);
     119        memcpy (d->buf, str, n);
     120        d->buf += n;
     121        d->size -= n;
     122      }
     123    return len;
     124  }
     125  
     126  static int
     127  gmp_snprintf_reps (struct gmp_snprintf_t *d, int c, int reps)
     128  {
     129    size_t n;
     130  
     131    ASSERT (reps >= 0);
     132    ASSERT (d->size >= 0);
     133  
     134    if (d->size > 1)
     135      {
     136        n = MIN (d->size-1, reps);
     137        memset (d->buf, c, n);
     138        d->buf += n;
     139        d->size -= n;
     140      }
     141    return reps;
     142  }
     143  
     144  static int
     145  gmp_snprintf_final (struct gmp_snprintf_t *d)
     146  {
     147    if (d->size >= 1)
     148      d->buf[0] = '\0';
     149    return 0;
     150  }
     151  
     152  const struct doprnt_funs_t  __gmp_snprintf_funs = {
     153    (doprnt_format_t) gmp_snprintf_format,
     154    (doprnt_memory_t) gmp_snprintf_memory,
     155    (doprnt_reps_t)   gmp_snprintf_reps,
     156    (doprnt_final_t)  gmp_snprintf_final
     157  };