/* Support for diagnostic traces. Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Future: Would like commas printed between limbs in hex or binary, but perhaps not always since it might upset cutting and pasting into bc or whatever. */ #include #include #include /* for strlen */ #include "gmp.h" #include "gmp-impl.h" #include "tests.h" /* Number base for the various trace printing routines. Set this in main() or with the debugger. If hexadecimal is going to be fed into GNU bc, remember to use -16 because bc requires upper case. */ int mp_trace_base = 10; void mp_trace_start (const char *name) { if (name != NULL && name[0] != '\0') printf ("%s=", name); switch (ABS (mp_trace_base)) { case 2: printf ("bin:"); break; case 8: printf ("oct:"); break; case 10: break; case 16: printf ("0x"); break; default: printf ("base%d:", ABS (mp_trace_base)); break; } } /* Print "name=value\n" to stdout for an mpq_t value. */ void mpq_trace (const char *name, mpq_srcptr q) { mp_trace_start (name); if (q == NULL) { printf ("NULL\n"); return; } mpq_out_str (stdout, mp_trace_base, q); printf ("\n"); } /* Print "name=value\n" to stdout for an mpz_t value. */ void mpz_trace (const char *name, mpz_srcptr z) { mpq_t q; mp_limb_t one; if (z == NULL) { mpq_trace (name, NULL); return; } q->_mp_num._mp_alloc = ALLOC(z); q->_mp_num._mp_size = SIZ(z); q->_mp_num._mp_d = PTR(z); one = 1; q->_mp_den._mp_alloc = 1; q->_mp_den._mp_size = 1; q->_mp_den._mp_d = &one; mpq_trace(name, q); } /* Print "name=value\n" to stdout for an mpf_t value. */ void mpf_trace (const char *name, mpf_srcptr f) { mp_trace_start (name); if (f == NULL) { printf ("NULL\n"); return; } mpf_out_str (stdout, ABS (mp_trace_base), 0, f); printf ("\n"); } /* Print "namenum=value\n" to stdout for an mpz_t value. "name" should have a "%d" to get the number. */ void mpz_tracen (const char *name, int num, mpz_srcptr z) { if (name != NULL && name[0] != '\0') { printf (name, num); putchar ('='); } mpz_trace (NULL, z); } /* Print "name=value\n" to stdout for an mpn style ptr,size. */ void mpn_trace (const char *name, mp_srcptr ptr, mp_size_t size) { mpz_t z; if (ptr == NULL) { mpz_trace (name, NULL); return; } MPN_NORMALIZE (ptr, size); PTR(z) = (mp_ptr) ptr; SIZ(z) = size; ALLOC(z) = size; mpz_trace (name, z); } /* Print "name=value\n" to stdout for a limb, nail doesn't have to be zero. */ void mp_limb_trace (const char *name, mp_limb_t n) { #if GMP_NAIL_BITS != 0 mp_limb_t a[2]; a[0] = n & GMP_NUMB_MASK; a[1] = n >> GMP_NUMB_BITS; mpn_trace (name, a, (mp_size_t) 2); #else mpn_trace (name, &n, (mp_size_t) 1); #endif } /* Print "namenum=value\n" to stdout for an mpn style ptr,size. "name" should have a "%d" to get the number. */ void mpn_tracen (const char *name, int num, mp_srcptr ptr, mp_size_t size) { if (name != NULL && name[0] != '\0') { printf (name, num); putchar ('='); } mpn_trace (NULL, ptr, size); } /* Print "namenum=value\n" to stdout for an array of mpn style ptr,size. "a" is an array of pointers, each a[i] is a pointer to "size" many limbs. The formal parameter isn't mp_srcptr because that causes compiler warnings, but the values aren't modified. "name" should have a printf style "%d" to get the array index. */ void mpn_tracea (const char *name, const mp_ptr *a, int count, mp_size_t size) { int i; for (i = 0; i < count; i++) mpn_tracen (name, i, a[i], size); } /* Print "value\n" to a file for an mpz_t value. Any previous contents of the file are overwritten, so you need different file names each time this is called. Overwriting the file is a feature, it means you get old data replaced when you run a test program repeatedly. */ void mpn_trace_file (const char *filename, mp_srcptr ptr, mp_size_t size) { FILE *fp; mpz_t z; fp = fopen (filename, "w"); if (fp == NULL) { perror ("fopen"); abort(); } MPN_NORMALIZE (ptr, size); PTR(z) = (mp_ptr) ptr; SIZ(z) = (int) size; mpz_out_str (fp, mp_trace_base, z); fprintf (fp, "\n"); if (ferror (fp) || fclose (fp) != 0) { printf ("error writing %s\n", filename); abort(); } } /* Print "value\n" to a set of files, one file for each element of the given array of mpn style ptr,size. Any previous contents of the files are overwritten, so you need different file names each time this is called. Each file is "filenameN" where N is 0 to count-1. "a" is an array of pointers, each a[i] is a pointer to "size" many limbs. The formal parameter isn't mp_srcptr because that causes compiler warnings, but the values aren't modified. Overwriting the files is a feature, it means you get old data replaced when you run a test program repeatedly. The output style isn't particularly pretty, but at least it gets something out, and you can cat the files into bc, or whatever. */ void mpn_tracea_file (const char *filename, const mp_ptr *a, int count, mp_size_t size) { char *s; int i; TMP_DECL; TMP_MARK; s = (char *) TMP_ALLOC (strlen (filename) + 50); for (i = 0; i < count; i++) { sprintf (s, "%s%d", filename, i); mpn_trace_file (s, a[i], size); } TMP_FREE; } void byte_trace (const char *name, const void *ptr, mp_size_t size) { char *fmt; mp_size_t i; mp_trace_start (name); switch (mp_trace_base) { case 8: fmt = " %o"; break; case 10: fmt = " %d"; break; case 16: fmt = " %x"; break; case -16: fmt = " %X"; break; default: printf ("Oops, unsupported base in byte_trace\n"); abort (); break; } for (i = 0; i < size; i++) printf (fmt, (int) ((unsigned char *) ptr)[i]); printf ("\n"); } void byte_tracen (const char *name, int num, const void *ptr, mp_size_t size) { if (name != NULL && name[0] != '\0') { printf (name, num); putchar ('='); } byte_trace (NULL, ptr, size); } void d_trace (const char *name, double d) { union { double d; unsigned char b[sizeof(double)]; } u; int i; if (name != NULL && name[0] != '\0') printf ("%s=", name); u.d = d; printf ("["); for (i = 0; i < sizeof (u.b); i++) { if (i != 0) printf (" "); printf ("%02X", (int) u.b[i]); } printf ("] %.20g\n", d); }