1/* mpz_set_str(mp_dest, string, base) -- Convert the \0-terminated
2   string STRING in base BASE to multiple precision integer in
3   MP_DEST.  Allow white space in the string.  If BASE == 0 determine
4   the base in the C standard way, i.e.  0xhh...h means base 16,
5   0oo...o means base 8, otherwise assume base 10.
6
7Copyright 1991, 1993, 1994, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005
8Free Software Foundation, Inc.
9
10This file is part of the GNU MP Library.
11
12The GNU MP Library is free software; you can redistribute it and/or modify
13it under the terms of the GNU Lesser General Public License as published by
14the Free Software Foundation; either version 3 of the License, or (at your
15option) any later version.
16
17The GNU MP Library is distributed in the hope that it will be useful, but
18WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
20License for more details.
21
22You should have received a copy of the GNU Lesser General Public License
23along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
24
25#include <string.h>
26#include <ctype.h>
27#include "gmp.h"
28#include "gmp-impl.h"
29
30extern const unsigned char __gmp_digit_value_tab[];
31#define digit_value_tab __gmp_digit_value_tab
32
33int
34mpz_set_str (mpz_ptr x, const char *str, int base)
35{
36  size_t str_size;
37  char *s, *begs;
38  size_t i;
39  mp_size_t xsize;
40  int c;
41  int negative;
42  const unsigned char *digit_value;
43  TMP_DECL;
44
45  digit_value = digit_value_tab;
46  if (base > 36)
47    {
48      /* For bases > 36, use the collating sequence
49	 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.  */
50      digit_value += 224;
51      if (base > 62)
52	return -1;		/* too large base */
53    }
54
55  /* Skip whitespace.  */
56  do
57    c = (unsigned char) *str++;
58  while (isspace (c));
59
60  negative = 0;
61  if (c == '-')
62    {
63      negative = 1;
64      c = (unsigned char) *str++;
65    }
66
67  if (digit_value[c] >= (base == 0 ? 10 : base))
68    return -1;			/* error if no valid digits */
69
70  /* If BASE is 0, try to find out the base by looking at the initial
71     characters.  */
72  if (base == 0)
73    {
74      base = 10;
75      if (c == '0')
76	{
77	  base = 8;
78	  c = (unsigned char) *str++;
79	  if (c == 'x' || c == 'X')
80	    {
81	      base = 16;
82	      c = (unsigned char) *str++;
83	    }
84	  else if (c == 'b' || c == 'B')
85	    {
86	      base = 2;
87	      c = (unsigned char) *str++;
88	    }
89	}
90    }
91
92  /* Skip leading zeros and white space.  */
93  while (c == '0' || isspace (c))
94    c = (unsigned char) *str++;
95  /* Make sure the string does not become empty, mpn_set_str would fail.  */
96  if (c == 0)
97    {
98      x->_mp_size = 0;
99      return 0;
100    }
101
102  TMP_MARK;
103  str_size = strlen (str - 1);
104  s = begs = (char *) TMP_ALLOC (str_size + 1);
105
106  /* Remove spaces from the string and convert the result from ASCII to a
107     byte array.  */
108  for (i = 0; i < str_size; i++)
109    {
110      if (!isspace (c))
111	{
112	  int dig = digit_value[c];
113	  if (dig >= base)
114	    {
115	      TMP_FREE;
116	      return -1;
117	    }
118	  *s++ = dig;
119	}
120      c = (unsigned char) *str++;
121    }
122
123  str_size = s - begs;
124
125  xsize = 2 + (mp_size_t)
126    (str_size / (GMP_NUMB_BITS * mp_bases[base].chars_per_bit_exactly));
127  MPZ_REALLOC (x, xsize);
128
129  /* Convert the byte array in base BASE to our bignum format.  */
130  xsize = mpn_set_str (x->_mp_d, (unsigned char *) begs, str_size, base);
131  x->_mp_size = negative ? -xsize : xsize;
132
133  TMP_FREE;
134  return 0;
135}
136