1 /* Support for diagnostic traces.
2 
3 Copyright 1999-2005 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 
21 /* Future: Would like commas printed between limbs in hex or binary, but
22    perhaps not always since it might upset cutting and pasting into bc or
23    whatever.  */
24 
25 
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 
40 int  mp_trace_base = 10;
41 
42 
43 void
mp_trace_start(const char * name)44 mp_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.  */
59 void
mpq_trace(const char * name,mpq_srcptr q)60 mpq_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.  */
75 void
mpz_trace(const char * name,mpz_srcptr z)76 mpz_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. */
101 void
mpf_trace(const char * name,mpf_srcptr f)102 mpf_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. */
118 void
mpz_tracen(const char * name,int num,mpz_srcptr z)119 mpz_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. */
131 void
mpn_trace(const char * name,mp_srcptr ptr,mp_size_t size)132 mpn_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. */
148 void
mp_limb_trace(const char * name,mp_limb_t n)149 mp_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.  */
164 void
mpn_tracen(const char * name,int num,mp_srcptr ptr,mp_size_t size)165 mpn_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 
184 void
mpn_tracea(const char * name,const mp_ptr * a,int count,mp_size_t size)185 mpn_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 
200 void
mpn_trace_file(const char * filename,mp_srcptr ptr,mp_size_t size)201 mpn_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 
242 void
mpn_tracea_file(const char * filename,const mp_ptr * a,int count,mp_size_t size)243 mpn_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 
263 void
byte_trace(const char * name,const void * ptr,mp_size_t size)264 byte_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 
284 void
byte_tracen(const char * name,int num,const void * ptr,mp_size_t size)285 byte_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 
296 void
d_trace(const char * name,double d)297 d_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