(root)/
gmp-6.3.0/
mpz/
inp_str.c
       1  /* mpz_inp_str(dest_integer, stream, base) -- Input a number in base
       2     BASE from stdio stream STREAM and store the result in DEST_INTEGER.
       3  
       4     OF THE FUNCTIONS IN THIS FILE, ONLY mpz_inp_str IS FOR EXTERNAL USE, THE
       5     REST ARE INTERNALS AND ARE ALMOST CERTAIN TO BE SUBJECT TO INCOMPATIBLE
       6     CHANGES OR DISAPPEAR COMPLETELY IN FUTURE GNU MP RELEASES.
       7  
       8  Copyright 1991, 1993, 1994, 1996, 1998, 2000-2003, 2011-2013 Free Software
       9  Foundation, Inc.
      10  
      11  This file is part of the GNU MP Library.
      12  
      13  The GNU MP Library is free software; you can redistribute it and/or modify
      14  it under the terms of either:
      15  
      16    * the GNU Lesser General Public License as published by the Free
      17      Software Foundation; either version 3 of the License, or (at your
      18      option) any later version.
      19  
      20  or
      21  
      22    * the GNU General Public License as published by the Free Software
      23      Foundation; either version 2 of the License, or (at your option) any
      24      later version.
      25  
      26  or both in parallel, as here.
      27  
      28  The GNU MP Library is distributed in the hope that it will be useful, but
      29  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      30  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      31  for more details.
      32  
      33  You should have received copies of the GNU General Public License and the
      34  GNU Lesser General Public License along with the GNU MP Library.  If not,
      35  see https://www.gnu.org/licenses/.  */
      36  
      37  #include <stdio.h>
      38  #include <ctype.h>
      39  #include "gmp-impl.h"
      40  #include "longlong.h"
      41  
      42  #define digit_value_tab __gmp_digit_value_tab
      43  
      44  size_t
      45  mpz_inp_str (mpz_ptr x, FILE *stream, int base)
      46  {
      47    int c;
      48    size_t nread;
      49  
      50    if (stream == 0)
      51      stream = stdin;
      52  
      53    nread = 0;
      54  
      55    /* Skip whitespace.  */
      56    do
      57      {
      58        c = getc (stream);
      59        nread++;
      60      }
      61    while (isspace (c));
      62  
      63    return mpz_inp_str_nowhite (x, stream, base, c, nread);
      64  }
      65  
      66  /* shared by mpq_inp_str */
      67  size_t
      68  mpz_inp_str_nowhite (mpz_ptr x, FILE *stream, int base, int c, size_t nread)
      69  {
      70    char *str;
      71    size_t alloc_size, str_size;
      72    int negative;
      73    mp_size_t xsize;
      74    const unsigned char *digit_value;
      75  
      76    ASSERT_ALWAYS (EOF == -1);	/* FIXME: handle this by adding explicit */
      77  				/* comparisons of c and EOF before each  */
      78  				/* read of digit_value[].  */
      79  
      80    digit_value = digit_value_tab;
      81    if (base > 36)
      82      {
      83        /* For bases > 36, use the collating sequence
      84  	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
      85        digit_value += 208;
      86        if (UNLIKELY (base > 62))
      87  	return 0;		/* too large base */
      88      }
      89  
      90    negative = 0;
      91    if (c == '-')
      92      {
      93        negative = 1;
      94        c = getc (stream);
      95        nread++;
      96      }
      97  
      98    if (c == EOF || digit_value[c] >= (base == 0 ? 10 : base))
      99      return 0;			/* error if no digits */
     100  
     101    /* If BASE is 0, try to find out the base by looking at the initial
     102       characters.  */
     103    if (base == 0)
     104      {
     105        base = 10;
     106        if (c == '0')
     107  	{
     108  	  base = 8;
     109  	  c = getc (stream);
     110  	  nread++;
     111  	  if (c == 'x' || c == 'X')
     112  	    {
     113  	      base = 16;
     114  	      c = getc (stream);
     115  	      nread++;
     116  	    }
     117  	  else if (c == 'b' || c == 'B')
     118  	    {
     119  	      base = 2;
     120  	      c = getc (stream);
     121  	      nread++;
     122  	    }
     123  	}
     124      }
     125  
     126    /* Skip leading zeros.  */
     127    while (c == '0')
     128      {
     129        c = getc (stream);
     130        nread++;
     131      }
     132  
     133    alloc_size = 100;
     134    str = __GMP_ALLOCATE_FUNC_TYPE (alloc_size, char);
     135    str_size = 0;
     136  
     137    while (c != EOF)
     138      {
     139        int dig;
     140        dig = digit_value[c];
     141        if (dig >= base)
     142  	break;
     143        if (str_size >= alloc_size)
     144  	{
     145  	  size_t old_alloc_size = alloc_size;
     146  	  alloc_size = alloc_size * 3 / 2;
     147  	  str = __GMP_REALLOCATE_FUNC_TYPE (str, old_alloc_size, alloc_size, char);
     148  	}
     149        str[str_size++] = dig;
     150        c = getc (stream);
     151      }
     152    nread += str_size;
     153  
     154    ungetc (c, stream);
     155    nread--;
     156  
     157    /* Make sure the string is not empty, mpn_set_str would fail.  */
     158    if (str_size == 0)
     159      {
     160        SIZ (x) = 0;
     161      }
     162    else
     163      {
     164        LIMBS_PER_DIGIT_IN_BASE (xsize, str_size, base);
     165        MPZ_NEWALLOC (x, xsize);
     166  
     167        /* Convert the byte array in base BASE to our bignum format.  */
     168        xsize = mpn_set_str (PTR (x), (unsigned char *) str, str_size, base);
     169        SIZ (x) = negative ? -xsize : xsize;
     170      }
     171    (*__gmp_free_func) (str, alloc_size);
     172    return nread;
     173  }