1/* Test mpz_inp_raw and mpz_out_raw.
2
3Copyright 2001 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19
20#include "config.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#if HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28
29#include "gmp.h"
30#include "gmp-impl.h"
31#include "tests.h"
32
33#define FILENAME  "t-io_raw.tmp"
34
35
36/* In the fopen, "b" selects binary mode on DOS systems, meaning no
37   conversion of '\n' to and from CRLF.  It's believed systems without such
38   nonsense will simply ignore the "b", but in case that's not so a plain
39   "w+" is attempted if "w+b" fails.  */
40
41FILE *
42fopen_wplusb_or_die (const char *filename)
43{
44  FILE  *fp;
45  fp = fopen (filename, "w+b");
46  if (fp == NULL)
47    fp = fopen (filename, "w+");
48
49  if (fp == NULL)
50    {
51      printf ("Cannot create file %s\n", filename);
52      abort ();
53    }
54  return fp;
55}
56
57/* use 0x80 to check nothing bad happens with sign extension etc */
58#define BYTEVAL(i)  (((i) + 1) | 0x80)
59
60void
61check_in (void)
62{
63  int        i, j, zeros, neg, error = 0;
64  mpz_t      want, got;
65  size_t     want_ret, got_ret;
66  mp_size_t  size;
67  FILE       *fp;
68
69  mpz_init (want);
70  mpz_init (got);
71
72  for (i = 0; i < 32; i++)
73    {
74      for (zeros = 0; zeros < 8; zeros++)
75	{
76	  for (neg = 0; neg <= 1; neg++)
77	    {
78	      want_ret = i + zeros + 4;
79
80	      /* need this to get the twos complement right */
81	      ASSERT_ALWAYS (sizeof (size) >= 4);
82
83	      size = i + zeros;
84	      if (neg)
85		size = -size;
86
87	      fp = fopen_wplusb_or_die (FILENAME);
88	      for (j = 3; j >= 0; j--)
89		ASSERT_ALWAYS (putc ((size >> (j*8)) & 0xFF, fp) != EOF);
90	      for (j = 0; j < zeros; j++)
91		ASSERT_ALWAYS (putc ('\0', fp) != EOF);
92	      for (j = 0; j < i; j++)
93		ASSERT_ALWAYS (putc (BYTEVAL (j), fp) != EOF);
94	      /* and some trailing garbage */
95	      ASSERT_ALWAYS (putc ('x', fp) != EOF);
96	      ASSERT_ALWAYS (putc ('y', fp) != EOF);
97	      ASSERT_ALWAYS (putc ('z', fp) != EOF);
98	      ASSERT_ALWAYS (fflush (fp) == 0);
99	      rewind (fp);
100
101	      got_ret = mpz_inp_raw (got, fp);
102	      ASSERT_ALWAYS (! ferror(fp));
103	      ASSERT_ALWAYS (fclose (fp) == 0);
104
105	      MPZ_CHECK_FORMAT (got);
106
107	      if (got_ret != want_ret)
108		{
109		  printf ("check_in: return value wrong\n");
110		  error = 1;
111		}
112	      if (mpz_cmp (got, want) != 0)
113		{
114		  printf ("check_in: result wrong\n");
115		  error = 1;
116		}
117	      if (error)
118		{
119		  printf    ("  i=%d zeros=%d neg=%d\n", i, zeros, neg);
120		  printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
121		  printf    ("  want_ret %lu\n", (unsigned long) want_ret);
122		  mpz_trace ("  got      ", got);
123		  mpz_trace ("  want     ", want);
124		  abort ();
125		}
126
127	      mpz_neg (want, want);
128	    }
129	}
130      mpz_mul_2exp (want, want, 8);
131      mpz_add_ui (want, want, (unsigned long) BYTEVAL (i));
132    }
133
134  mpz_clear (want);
135  mpz_clear (got);
136}
137
138
139void
140check_out (void)
141{
142  int        i, j, neg, error = 0;
143  mpz_t      z;
144  char       want[256], got[256], *p;
145  size_t     want_len, got_ret, got_read;
146  mp_size_t  size;
147  FILE       *fp;
148
149  mpz_init (z);
150
151  for (i = 0; i < 32; i++)
152    {
153      for (neg = 0; neg <= 1; neg++)
154	{
155	  want_len = i + 4;
156
157	  /* need this to get the twos complement right */
158	  ASSERT_ALWAYS (sizeof (size) >= 4);
159
160	  size = i;
161	  if (neg)
162	    size = -size;
163
164	  p = want;
165	  for (j = 3; j >= 0; j--)
166	    *p++ = size >> (j*8);
167	  for (j = 0; j < i; j++)
168	    *p++ = BYTEVAL (j);
169	  ASSERT_ALWAYS (p <= want + sizeof (want));
170
171	  fp = fopen_wplusb_or_die (FILENAME);
172	  got_ret = mpz_out_raw (fp, z);
173	  ASSERT_ALWAYS (fflush (fp) == 0);
174	  rewind (fp);
175	  got_read = fread (got, 1, sizeof(got), fp);
176	  ASSERT_ALWAYS (! ferror(fp));
177	  ASSERT_ALWAYS (fclose (fp) == 0);
178
179	  if (got_ret != want_len)
180	    {
181	      printf ("check_out: wrong return value\n");
182	      error = 1;
183	    }
184	  if (got_read != want_len)
185	    {
186	      printf ("check_out: wrong number of bytes read back\n");
187	      error = 1;
188	    }
189	  if (memcmp (want, got, want_len) != 0)
190	    {
191	      printf ("check_out: wrong data\n");
192	      error = 1;
193	    }
194	  if (error)
195	    {
196	      printf    ("  i=%d neg=%d\n", i, neg);
197	      mpz_trace ("  z", z);
198	      printf    ("  got_ret  %lu\n", (unsigned long) got_ret);
199	      printf    ("  got_read %lu\n", (unsigned long) got_read);
200	      printf    ("  want_len %lu\n", (unsigned long) want_len);
201	      printf    ("  want");
202	      for (j = 0; j < want_len; j++)
203		printf (" %02X", (unsigned) (unsigned char) want[j]);
204	      printf    ("\n");
205	      printf    ("  got ");
206	      for (j = 0; j < want_len; j++)
207		printf (" %02X", (unsigned) (unsigned char) got[j]);
208	      printf    ("\n");
209	      abort ();
210	    }
211
212	  mpz_neg (z, z);
213	}
214      mpz_mul_2exp (z, z, 8);
215      mpz_add_ui (z, z, (unsigned long) BYTEVAL (i));
216    }
217
218  mpz_clear (z);
219}
220
221
222void
223check_rand (void)
224{
225  gmp_randstate_ptr  rands = RANDS;
226  int        i, error = 0;
227  mpz_t      got, want;
228  size_t     inp_ret, out_ret;
229  FILE       *fp;
230
231  mpz_init (want);
232  mpz_init (got);
233
234  for (i = 0; i < 500; i++)
235    {
236      mpz_erandomb (want, rands, 10*GMP_LIMB_BITS);
237      mpz_negrandom (want, rands);
238
239      fp = fopen_wplusb_or_die (FILENAME);
240      out_ret = mpz_out_raw (fp, want);
241      ASSERT_ALWAYS (fflush (fp) == 0);
242      rewind (fp);
243      inp_ret = mpz_inp_raw (got, fp);
244      ASSERT_ALWAYS (fclose (fp) == 0);
245
246      MPZ_CHECK_FORMAT (got);
247
248      if (inp_ret != out_ret)
249	{
250	  printf ("check_rand: different inp/out return values\n");
251	  error = 1;
252	}
253      if (mpz_cmp (got, want) != 0)
254	{
255	  printf ("check_rand: wrong result\n");
256	  error = 1;
257	}
258      if (error)
259	{
260	  printf    ("  out_ret %lu\n", (unsigned long) out_ret);
261	  printf    ("  inp_ret %lu\n", (unsigned long) inp_ret);
262	  mpz_trace ("  want", want);
263	  mpz_trace ("  got ", got);
264	  abort ();
265	}
266    }
267
268  mpz_clear (got);
269  mpz_clear (want);
270}
271
272
273int
274main (void)
275{
276  tests_start ();
277  mp_trace_base = -16;
278
279  check_in ();
280  check_out ();
281  check_rand ();
282
283  unlink (FILENAME);
284  tests_end ();
285
286  exit (0);
287}
288