Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / libgmp / mpn / generic / set_str.c
1 /* mpn_set_str (mp_ptr res_ptr, const char *str, size_t str_len, int base)
2    -- Convert a STR_LEN long base BASE byte string pointed to by STR to a
3    limb vector pointed to by RES_PTR.  Return the number of limbs in
4    RES_PTR.
5
6 Copyright (C) 1991, 1992, 1993, 1994, 1996 Free Software Foundation, Inc.
7
8 This file is part of the GNU MP Library.
9
10 The GNU MP Library is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Library General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or (at your
13 option) any later version.
14
15 The GNU MP Library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
18 License for more details.
19
20 You should have received a copy of the GNU Library General Public License
21 along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
23 MA 02111-1307, USA. */
24
25 #include "gmp.h"
26 #include "gmp-impl.h"
27
28 mp_size_t
29 mpn_set_str (xp, str, str_len, base)
30      mp_ptr xp;
31      const unsigned char *str;
32      size_t str_len;
33      int base;
34 {
35   mp_size_t size;
36   mp_limb_t big_base;
37   int indigits_per_limb;
38   mp_limb_t res_digit;
39
40   big_base = __mp_bases[base].big_base;
41   indigits_per_limb = __mp_bases[base].chars_per_limb;
42
43 /*   size = str_len / indigits_per_limb + 1;  */
44
45   size = 0;
46
47   if ((base & (base - 1)) == 0)
48     {
49       /* The base is a power of 2.  Read the input string from
50          least to most significant character/digit.  */
51
52       const unsigned char *s;
53       int next_bitpos;
54       int bits_per_indigit = big_base;
55
56       res_digit = 0;
57       next_bitpos = 0;
58
59       for (s = str + str_len - 1; s >= str; s--)
60         {
61           int inp_digit = *s;
62
63           res_digit |= (mp_limb_t) inp_digit << next_bitpos;
64           next_bitpos += bits_per_indigit;
65           if (next_bitpos >= BITS_PER_MP_LIMB)
66             {
67               xp[size++] = res_digit;
68               next_bitpos -= BITS_PER_MP_LIMB;
69               res_digit = inp_digit >> (bits_per_indigit - next_bitpos);
70             }
71         }
72
73       if (res_digit != 0)
74         xp[size++] = res_digit;
75     }
76   else
77     {
78       /* General case.  The base is not a power of 2.  */
79
80       size_t i;
81       int j;
82       mp_limb_t cy_limb;
83
84       for (i = indigits_per_limb; i < str_len; i += indigits_per_limb)
85         {
86           res_digit = *str++;
87           if (base == 10)
88             { /* This is a common case.
89                  Help the compiler to avoid multiplication.  */
90               for (j = 1; j < indigits_per_limb; j++)
91                 res_digit = res_digit * 10 + *str++;
92             }
93           else
94             {
95               for (j = 1; j < indigits_per_limb; j++)
96                 res_digit = res_digit * base + *str++;
97             }
98
99           if (size == 0)
100             {
101               if (res_digit != 0)
102                 {
103                   xp[0] = res_digit;
104                   size = 1;
105                 }
106             }
107           else
108             {
109               cy_limb = mpn_mul_1 (xp, xp, size, big_base);
110               cy_limb += mpn_add_1 (xp, xp, size, res_digit);
111               if (cy_limb != 0)
112                 xp[size++] = cy_limb;
113             }
114         }
115
116       big_base = base;
117       res_digit = *str++;
118       if (base == 10)
119         { /* This is a common case.
120              Help the compiler to avoid multiplication.  */
121           for (j = 1; j < str_len - (i - indigits_per_limb); j++)
122             {
123               res_digit = res_digit * 10 + *str++;
124               big_base *= 10;
125             }
126         }
127       else
128         {
129           for (j = 1; j < str_len - (i - indigits_per_limb); j++)
130             {
131               res_digit = res_digit * base + *str++;
132               big_base *= base;
133             }
134         }
135
136       if (size == 0)
137         {
138           if (res_digit != 0)
139             {
140               xp[0] = res_digit;
141               size = 1;
142             }
143         }
144       else
145         {
146           cy_limb = mpn_mul_1 (xp, xp, size, big_base);
147           cy_limb += mpn_add_1 (xp, xp, size, res_digit);
148           if (cy_limb != 0)
149             xp[size++] = cy_limb;
150         }
151     }
152
153   return size;
154 }