1272651Sbapt/* Support for diagnostic traces.
2272651Sbapt
3272651SbaptCopyright 1999-2005 Free Software Foundation, Inc.
4272651Sbapt
5272651SbaptThis file is part of the GNU MP Library test suite.
6272651Sbapt
7272651SbaptThe GNU MP Library test suite is free software; you can redistribute it
8272651Sbaptand/or modify it under the terms of the GNU General Public License as
9272651Sbaptpublished by the Free Software Foundation; either version 3 of the License,
10272651Sbaptor (at your option) any later version.
11272651Sbapt
12272651SbaptThe GNU MP Library test suite is distributed in the hope that it will be
13272651Sbaptuseful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14272651SbaptMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15272651SbaptPublic License for more details.
16272651Sbapt
17272651SbaptYou should have received a copy of the GNU General Public License along with
18272651Sbaptthe GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19272651Sbapt
20272651Sbapt
21272651Sbapt/* Future: Would like commas printed between limbs in hex or binary, but
22272651Sbapt   perhaps not always since it might upset cutting and pasting into bc or
23272651Sbapt   whatever.  */
24272651Sbapt
25272651Sbapt
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h> /* for strlen */
29
30#include "gmp-impl.h"
31
32#include "tests.h"
33
34
35/* Number base for the various trace printing routines.
36   Set this in main() or with the debugger.
37   If hexadecimal is going to be fed into GNU bc, remember to use -16
38   because bc requires upper case.  */
39
40int  mp_trace_base = 10;
41
42
43void
44mp_trace_start (const char *name)
45{
46  if (name != NULL && name[0] != '\0')
47    printf ("%s=", name);
48
49  switch (ABS (mp_trace_base)) {
50  case  2: printf ("bin:");                         break;
51  case  8: printf ("oct:");                         break;
52  case 10:                                          break;
53  case 16: printf ("0x");                           break;
54  default: printf ("base%d:", ABS (mp_trace_base)); break;
55  }
56}
57
58/* Print "name=value\n" to stdout for an mpq_t value.  */
59void
60mpq_trace (const char *name, mpq_srcptr q)
61{
62  mp_trace_start (name);
63  if (q == NULL)
64    {
65      printf ("NULL\n");
66      return;
67    }
68
69  mpq_out_str (stdout, mp_trace_base, q);
70  printf ("\n");
71}
72
73
74/* Print "name=value\n" to stdout for an mpz_t value.  */
75void
76mpz_trace (const char *name, mpz_srcptr z)
77{
78  mpq_t      q;
79  mp_limb_t  one;
80
81  if (z == NULL)
82    {
83      mpq_trace (name, NULL);
84      return;
85    }
86
87  q->_mp_num._mp_alloc = ALLOC(z);
88  q->_mp_num._mp_size = SIZ(z);
89  q->_mp_num._mp_d = PTR(z);
90
91  one = 1;
92  q->_mp_den._mp_alloc = 1;
93  q->_mp_den._mp_size = 1;
94  q->_mp_den._mp_d = &one;
95
96  mpq_trace(name, q);
97}
98
99
100/* Print "name=value\n" to stdout for an mpf_t value. */
101void
102mpf_trace (const char *name, mpf_srcptr f)
103{
104  mp_trace_start (name);
105  if (f == NULL)
106    {
107      printf ("NULL\n");
108      return;
109    }
110
111  mpf_out_str (stdout, ABS (mp_trace_base), 0, f);
112  printf ("\n");
113}
114
115
116/* Print "namenum=value\n" to stdout for an mpz_t value.
117   "name" should have a "%d" to get the number. */
118void
119mpz_tracen (const char *name, int num, mpz_srcptr z)
120{
121  if (name != NULL && name[0] != '\0')
122    {
123      printf (name, num);
124      putchar ('=');
125    }
126  mpz_trace (NULL, z);
127}
128
129
130/* Print "name=value\n" to stdout for an mpn style ptr,size. */
131void
132mpn_trace (const char *name, mp_srcptr ptr, mp_size_t size)
133{
134  mpz_t  z;
135  if (ptr == NULL)
136    {
137      mpz_trace (name, NULL);
138      return;
139    }
140  MPN_NORMALIZE (ptr, size);
141  PTR(z) = (mp_ptr) ptr;
142  SIZ(z) = size;
143  ALLOC(z) = size;
144  mpz_trace (name, z);
145}
146
147/* Print "name=value\n" to stdout for a limb, nail doesn't have to be zero. */
148void
149mp_limb_trace (const char *name, mp_limb_t n)
150{
151#if GMP_NAIL_BITS != 0
152  mp_limb_t  a[2];
153  a[0] = n & GMP_NUMB_MASK;
154  a[1] = n >> GMP_NUMB_BITS;
155  mpn_trace (name, a, (mp_size_t) 2);
156#else
157  mpn_trace (name, &n, (mp_size_t) 1);
158#endif
159}
160
161
162/* Print "namenum=value\n" to stdout for an mpn style ptr,size.
163   "name" should have a "%d" to get the number.  */
164void
165mpn_tracen (const char *name, int num, mp_srcptr ptr, mp_size_t size)
166{
167  if (name != NULL && name[0] != '\0')
168    {
169      printf (name, num);
170      putchar ('=');
171    }
172  mpn_trace (NULL, ptr, size);
173}
174
175
176/* Print "namenum=value\n" to stdout for an array of mpn style ptr,size.
177
178   "a" is an array of pointers, each a[i] is a pointer to "size" many limbs.
179   The formal parameter isn't mp_srcptr because that causes compiler
180   warnings, but the values aren't modified.
181
182   "name" should have a printf style "%d" to get the array index.  */
183
184void
185mpn_tracea (const char *name, const mp_ptr *a, int count, mp_size_t size)
186{
187  int i;
188  for (i = 0; i < count; i++)
189    mpn_tracen (name, i, a[i], size);
190}
191
192
193/* Print "value\n" to a file for an mpz_t value.  Any previous contents of
194   the file are overwritten, so you need different file names each time this
195   is called.
196
197   Overwriting the file is a feature, it means you get old data replaced
198   when you run a test program repeatedly.  */
199
200void
201mpn_trace_file (const char *filename, mp_srcptr ptr, mp_size_t size)
202{
203  FILE   *fp;
204  mpz_t  z;
205
206  fp = fopen (filename, "w");
207  if (fp == NULL)
208    {
209      perror ("fopen");
210      abort();
211    }
212
213  MPN_NORMALIZE (ptr, size);
214  PTR(z) = (mp_ptr) ptr;
215  SIZ(z) = (int) size;
216
217  mpz_out_str (fp, mp_trace_base, z);
218  fprintf (fp, "\n");
219
220  if (ferror (fp) || fclose (fp) != 0)
221    {
222      printf ("error writing %s\n", filename);
223      abort();
224    }
225}
226
227
228/* Print "value\n" to a set of files, one file for each element of the given
229   array of mpn style ptr,size.  Any previous contents of the files are
230   overwritten, so you need different file names each time this is called.
231   Each file is "filenameN" where N is 0 to count-1.
232
233   "a" is an array of pointers, each a[i] is a pointer to "size" many limbs.
234   The formal parameter isn't mp_srcptr because that causes compiler
235   warnings, but the values aren't modified.
236
237   Overwriting the files is a feature, it means you get old data replaced
238   when you run a test program repeatedly.  The output style isn't
239   particularly pretty, but at least it gets something out, and you can cat
240   the files into bc, or whatever. */
241
242void
243mpn_tracea_file (const char *filename,
244                 const mp_ptr *a, int count, mp_size_t size)
245{
246  char  *s;
247  int   i;
248  TMP_DECL;
249
250  TMP_MARK;
251  s = (char *) TMP_ALLOC (strlen (filename) + 50);
252
253  for (i = 0; i < count; i++)
254    {
255      sprintf (s, "%s%d", filename, i);
256      mpn_trace_file (s, a[i], size);
257    }
258
259  TMP_FREE;
260}
261
262
263void
264byte_trace (const char *name, const void *ptr, mp_size_t size)
265{
266  const char *fmt;
267  mp_size_t  i;
268
269  mp_trace_start (name);
270
271  switch (mp_trace_base) {
272  case   8: fmt = " %o"; break;
273  case  10: fmt = " %d"; break;
274  case  16: fmt = " %x"; break;
275  case -16: fmt = " %X"; break;
276  default: printf ("Oops, unsupported base in byte_trace\n"); abort (); break;
277  }
278
279  for (i = 0; i < size; i++)
280    printf (fmt, (int) ((unsigned char *) ptr)[i]);
281  printf ("\n");
282}
283
284void
285byte_tracen (const char *name, int num, const void *ptr, mp_size_t size)
286{
287  if (name != NULL && name[0] != '\0')
288    {
289      printf (name, num);
290      putchar ('=');
291    }
292  byte_trace (NULL, ptr, size);
293}
294
295
296void
297d_trace (const char *name, double d)
298{
299  union {
300    double         d;
301    unsigned char  b[sizeof(double)];
302  } u;
303  int  i;
304
305  if (name != NULL && name[0] != '\0')
306    printf ("%s=", name);
307
308  u.d = d;
309  printf ("[");
310  for (i = 0; i < sizeof (u.b); i++)
311    {
312      if (i != 0)
313        printf (" ");
314      printf ("%02X", (int) u.b[i]);
315    }
316  printf ("] %.20g\n", d);
317}
318