Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / libgmp / 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 Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
5
6 This file is part of the GNU MP Library.
7
8 The GNU MP Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Library General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or (at your
11 option) any later version.
12
13 The GNU MP Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
16 License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21 MA 02111-1307, USA. */
22
23 #include <stdio.h>
24 #include <ctype.h>
25 #include "gmp.h"
26 #include "gmp-impl.h"
27
28 static int
29 digit_value_in_base (c, base)
30      int c;
31      int base;
32 {
33   int digit;
34
35   if (isdigit (c))
36     digit = c - '0';
37   else if (islower (c))
38     digit = c - 'a' + 10;
39   else if (isupper (c))
40     digit = c - 'A' + 10;
41   else
42     return -1;
43
44   if (digit < base)
45     return digit;
46   return -1;
47 }
48
49 size_t
50 #if __STDC__
51 mpz_inp_str (mpz_ptr dest, FILE *stream, int base)
52 #else
53 mpz_inp_str (dest, stream, base)
54      mpz_ptr dest;
55      FILE *stream;
56      int base;
57 #endif
58 {
59   char *str;
60   size_t alloc_size, str_size;
61   int c;
62   int negative;
63   mp_size_t dest_size;
64   size_t nread;
65
66   if (stream == 0)
67     stream = stdin;
68
69   alloc_size = 100;
70   str = (char *) (*_mp_allocate_func) (alloc_size);
71   str_size = 0;
72   nread = 0;
73
74   /* Skip whitespace.  */
75   do
76     {
77       c = getc (stream);
78       nread++;
79     }
80   while (isspace (c));
81
82   negative = 0;
83   if (c == '-')
84     {
85       negative = 1;
86       c = getc (stream);
87     }
88
89   if (digit_value_in_base (c, base == 0 ? 10 : base) < 0)
90     return 0;                   /* error if no digits */
91
92   /* If BASE is 0, try to find out the base by looking at the initial
93      characters.  */
94   if (base == 0)
95     {
96       base = 10;
97       if (c == '0')
98         {
99           base = 8;
100           c = getc (stream);
101           nread++;
102           if (c == 'x' || c == 'X')
103             {
104               base = 16;
105               c = getc (stream);
106               nread++;
107             }
108         }
109     }
110
111   for (;;)
112     {
113       int dig;
114       if (str_size >= alloc_size)
115         {
116           size_t old_alloc_size = alloc_size;
117           alloc_size = alloc_size * 3 / 2;
118           str = (char *) (*_mp_reallocate_func) (str, old_alloc_size, alloc_size);
119         }
120       dig = digit_value_in_base (c, base);
121       if (dig < 0)
122         break;
123       str[str_size++] = dig;
124       c = getc (stream);
125     }
126
127   ungetc (c, stream);
128
129   dest_size = str_size / __mp_bases[base].chars_per_limb + 1;
130   if (dest->_mp_alloc < dest_size)
131     _mpz_realloc (dest, dest_size);
132
133   dest_size = mpn_set_str (dest->_mp_d, (unsigned char *) str, str_size, base);
134   dest->_mp_size = negative ? -dest_size : dest_size;
135
136   (*_mp_free_func) (str, alloc_size);
137   return str_size + nread;
138 }