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