1 /*
2 
3 Copyright 2012-2014, 2016, 2020 Free Software Foundation, Inc.
4 
5 This file is part of the GNU MP Library test suite.
6 
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11 
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19 
20 #include <assert.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "testutils.h"
27 
28 #define MAXBITS 400
29 #define COUNT 2000
30 
31 #define GMP_LIMB_BITS (sizeof(mp_limb_t) * CHAR_BIT)
32 #define MAXLIMBS ((MAXBITS + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS)
33 
34 static void
test_small(void)35 test_small (void)
36 {
37   struct {
38     const char *input;
39     const char *decimal;
40   } data[] = {
41     { "183407", "183407" },
42     { " 763959", "763959 " },
43     { "9 81999", "981999" },
44     { "10\t7398 ", "107398" },
45     { "-9585 44", "-00958544" },
46     { "-0", "0000" },
47     { " -000  ", "0" },
48     { "0704436", "231710" },
49     /* Check the case of large number of leading zeros. */
50     { "0000000000000000000000000", "0000000000000000000000000" },
51     { "000000000000000000000000704436", "000000000000000000000000231710" },
52     { " 02503517", "689999" },
53     { "0 1312143", "365667" },
54     { "-03 274062", "-882738" },
55     { "012\t242", "005282" },
56     { "0b11010111110010001111", "883855" },
57     { " 0b11001010010100001", "103585" },
58     { "-0b101010110011101111", "-175343" },
59     { "0b 1111111011011100110", "521958" },
60     { "0b1 1111110111001000011", "1044035" },
61     { " 0x53dfc", "343548" },
62     { "0xfA019", "1024025" },
63     { "0x 642d1", "410321" },
64     { "0x5 8067", "360551" },
65     { "-0xd6Be6", "-879590" },
66     { "\t0B1110000100000000011", "460803" },
67     { "0B\t1111110010010100101", "517285" },
68     { "0B1\t010111101101110100", "359284" },
69     { "-0B101\t1001101111111001", "-367609" },
70     { "0B10001001010111110000", "562672" },
71     { "0Xe4B7e", "936830" },
72     { "0X1E4bf", "124095" },
73     { "-0Xfdb90", "-1039248" },
74     { "0X7fc47", "523335" },
75     { "0X8167c", "530044" },
76     /* Some invalid inputs */
77     { "", NULL },
78     { "0x", NULL },
79     { "0b", NULL },
80     { "0z", NULL },
81     { "-", NULL },
82     { "-0x ", NULL },
83     { "0|1", NULL },
84     { "4+4", NULL },
85     { "0ab", NULL },
86     { "10x0", NULL },
87     { "0xxab", NULL },
88     { "ab", NULL },
89     { "0%#", NULL },
90     { "$foo", NULL },
91     { NULL, NULL }
92   };
93   unsigned i;
94   mpz_t a, b;
95   mpz_init (b);
96 
97   for (i = 0; data[i].input; i++)
98     {
99       int res = mpz_init_set_str (a, data[i].input, 0);
100       if (data[i].decimal)
101           {
102             if (res != 0)
103               {
104                 fprintf (stderr, "mpz_set_str returned -1, input: %s\n",
105                            data[i].input);
106                 abort ();
107               }
108             if (mpz_set_str (b, data[i].decimal, 10) != 0)
109               {
110                 fprintf (stderr, "mpz_set_str returned -1, decimal input: %s\n",
111                            data[i].input);
112                 abort ();
113               }
114             if (mpz_cmp (a, b) != 0)
115               {
116                 fprintf (stderr, "mpz_set_str failed for input: %s\n",
117                            data[i].input);
118 
119                 dump ("got", a);
120                 dump ("ref", b);
121                 abort ();
122               }
123           }
124       else if (res != -1)
125           {
126             fprintf (stderr, "mpz_set_str returned %d, invalid input: %s\n",
127                        res, data[i].input);
128             abort ();
129           }
130       mpz_clear (a);
131     }
132 
133   mpz_clear (b);
134 }
135 
136 void
testmain(int argc,char ** argv)137 testmain (int argc, char **argv)
138 {
139   unsigned i;
140   char *ap;
141   char *bp;
142   char *rp;
143   size_t bn, rn, arn;
144 
145   mpz_t a, b;
146 
147   FILE *tmp;
148 
149   test_small ();
150 
151   mpz_init (a);
152   mpz_init (b);
153 
154   tmp = tmpfile ();
155   if (!tmp)
156     fprintf (stderr,
157                "Failed to create temporary file. Skipping mpz_out_str tests.\n");
158 
159   if (mpz_out_str (tmp, 63, a) != 0)
160     {
161       printf ("mpz_out_str did not return 0 (error) with base > 62\n");
162       abort ();
163     }
164 
165   if (mpz_out_str (tmp, -37, a) != 0)
166     {
167       printf ("mpz_out_str did not return 0 (error) with base < -37\n");
168       abort ();
169     }
170 
171   for (i = 0; i < COUNT; i++)
172     {
173       int base;
174       for (base = 0; base <= 62; base += 1 + (base == 0))
175           {
176             hex_random_str_op (MAXBITS, (i&1 || base > 36) ? base: -base, &ap, &rp);
177             if (mpz_set_str (a, ap, 16) != 0)
178               {
179                 fprintf (stderr, "mpz_set_str failed on input %s\n", ap);
180                 abort ();
181               }
182 
183             rn = strlen (rp);
184             arn = rn - (rp[0] == '-');
185 
186             bn = mpz_sizeinbase (a, base ? base : 10);
187             if (bn < arn || bn > (arn + 1))
188               {
189                 fprintf (stderr, "mpz_sizeinbase failed:\n");
190                 dump ("a", a);
191                 fprintf (stderr, "r = %s\n", rp);
192                 fprintf (stderr, "  base %d, correct size %u, got %u\n",
193                            base, (unsigned) arn, (unsigned)bn);
194                 abort ();
195               }
196             bp = mpz_get_str (NULL, (i&1 || base > 36) ? base: -base, a);
197             if (strcmp (bp, rp))
198               {
199                 fprintf (stderr, "mpz_get_str failed:\n");
200                 dump ("a", a);
201                 fprintf (stderr, "b = %s\n", bp);
202                 fprintf (stderr, "  base = %d\n", base);
203                 fprintf (stderr, "r = %s\n", rp);
204                 abort ();
205               }
206 
207             /* Just a few tests with file i/o. */
208             if (tmp && i < 20)
209               {
210                 size_t tn;
211                 rewind (tmp);
212                 tn = mpz_out_str (tmp, (i&1 || base > 36) ? base: -base, a);
213                 if (tn != rn)
214                     {
215                       fprintf (stderr, "mpz_out_str, bad return value:\n");
216                       dump ("a", a);
217                       fprintf (stderr, "r = %s\n", rp);
218                       fprintf (stderr, "  base %d, correct size %u, got %u\n",
219                                  base, (unsigned) rn, (unsigned)tn);
220                       abort ();
221                     }
222                 rewind (tmp);
223                 memset (bp, 0, rn);
224                 tn = fread (bp, 1, rn, tmp);
225                 if (tn != rn)
226                     {
227                       fprintf (stderr,
228                                  "fread failed, expected %lu bytes, got only %lu.\n",
229                                  (unsigned long) rn, (unsigned long) tn);
230                       abort ();
231                     }
232 
233                 if (memcmp (bp, rp, rn) != 0)
234                     {
235                       fprintf (stderr, "mpz_out_str failed:\n");
236                       dump ("a", a);
237                       fprintf (stderr, "b = %s\n", bp);
238                       fprintf (stderr, "  base = %d\n", base);
239                       fprintf (stderr, "r = %s\n", rp);
240                       abort ();
241                     }
242               }
243 
244             mpz_set_str (b, rp, base);
245 
246             if (mpz_cmp (a, b))
247               {
248                 fprintf (stderr, "mpz_set_str failed:\n");
249                 fprintf (stderr, "r = %s\n", rp);
250                 fprintf (stderr, "  base = %d\n", base);
251                 fprintf (stderr, "r = %s\n", ap);
252                 fprintf (stderr, "  base = 16\n");
253                 dump ("b", b);
254                 dump ("r", a);
255                 abort ();
256               }
257 
258             /* Test mpn interface */
259             if (base && mpz_sgn (a))
260               {
261                 size_t i;
262                 const char *absr;
263                 mp_limb_t t[MAXLIMBS];
264                 size_t tn = mpz_size (a);
265 
266                 assert (tn <= MAXLIMBS);
267                 mpn_copyi (t, a->_mp_d, tn);
268 
269                 bn = mpn_get_str ((unsigned char *) bp, base, t, tn);
270                 if (bn != arn)
271                     {
272                       fprintf (stderr, "mpn_get_str failed:\n");
273                       fprintf (stderr, "returned length: %lu (bad)\n", (unsigned long) bn);
274                       fprintf (stderr, "expected: %lu\n", (unsigned long) arn);
275                       fprintf (stderr, "  base = %d\n", base);
276                       fprintf (stderr, "r = %s\n", ap);
277                       fprintf (stderr, "  base = 16\n");
278                       dump ("b", b);
279                       dump ("r", a);
280                       abort ();
281                     }
282                 absr = rp + (rp[0] == '-');
283 
284                 for (i = 0; i < bn; i++)
285                     {
286                       unsigned char digit = absr[i];
287                       char value;
288                       if (digit >= '0' && digit <= '9')
289                         value = digit - '0';
290                       else if (digit >= 'a' && digit <= 'z')
291                         value = digit - 'a' + ((base > 36) ? 36 : 10);
292                       else if (digit >= 'A' && digit <= 'Z')
293                         value = digit - 'A' + 10;
294                       else
295                         {
296                           fprintf (stderr, "Internal error in test.\n");
297                           abort();
298                         }
299                       if (bp[i] != value)
300                         {
301                           fprintf (stderr, "mpn_get_str failed:\n");
302                           fprintf (stderr, "digit %lu: %d (bad)\n", (unsigned long) i, bp[i]);
303                           fprintf (stderr, "expected: %d\n", value);
304                           fprintf (stderr, "  base = %d\n", base);
305                           fprintf (stderr, "r = %s\n", ap);
306                           fprintf (stderr, "  base = 16\n");
307                           dump ("b", b);
308                           dump ("r", a);
309                           abort ();
310                         }
311                     }
312                 tn = mpn_set_str (t, (unsigned char *) bp, bn, base);
313                 if (tn != mpz_size (a) || mpn_cmp (t, a->_mp_d, tn))
314                     {
315                       fprintf (stderr, "mpn_set_str failed:\n");
316                       fprintf (stderr, "r = %s\n", rp);
317                       fprintf (stderr, "  base = %d\n", base);
318                       fprintf (stderr, "r = %s\n", ap);
319                       fprintf (stderr, "  base = 16\n");
320                       dump ("r", a);
321                       abort ();
322                     }
323               }
324             free (ap);
325             free (rp);
326             testfree (bp);
327           }
328     }
329   mpz_clear (a);
330   mpz_clear (b);
331 }
332