+/*----- Trace messages ----------------------------------------------------*/
+
+#if defined(TRACING) || !defined(NDEBUG)
+
+/* --- Static data --- */
+
+static FILE *tracefp = 0; /* Where does debugging go? */
+static unsigned int tracelvl = 0; /* How much tracing gets done? */
+
+/* --- @trace@ --- *
+ *
+ * Arguments: @unsigned int lvl@ = trace level for output
+ * @const char *f@ = a @printf@-style format string
+ * @...@ = other arguments
+ *
+ * Returns: ---
+ *
+ * Use: Reports a message to the trace output.
+ */
+
+void trace(unsigned int lvl, const char *f, ...)
+{
+ va_list ap;
+ if ((lvl & tracing()) == 0)
+ return;
+ va_start(ap, f);
+ fprintf(tracefp, "*** %s: ", myname);
+ vfprintf(tracefp, f, ap);
+ va_end(ap);
+ putc('\n', tracefp);
+}
+
+/* --- @traceblk@ --- *
+ *
+ * Arguments: @unsigned int lvl@ = trace level for output
+ * @const char *hdr@ = some header string to write
+ * @const void *blk@ = pointer to a block of memory to dump
+ * @size_t sz@ = size of the block of memory
+ *
+ * Returns: ---
+ *
+ * Use: Dumps the contents of a block to the trace output.
+ */
+
+void traceblk(unsigned int lvl, const char *hdr, const void *blk, size_t sz)
+{
+ const unsigned char *p = blk;
+ size_t i;
+ unsigned long o = 0;
+ size_t c;
+
+ /* --- Skip if the trace level is too high --- */
+
+ if ((lvl & tracing()) == 0)
+ return;
+
+ /* --- Now start work --- */
+
+ fprintf(tracefp, "*** %s: %s\n", myname, hdr);
+
+ while (sz) {
+ fprintf(tracefp, "*** %s: %08lu : ", myname, o);
+ for (i = 0; i < 8; i++) {
+ if (i < sz)
+ fprintf(tracefp, "%02x ", p[i]);
+ else
+ fputs("** ", tracefp);
+ }
+ fputs(": ", tracefp);
+ for (i = 0; i < 8; i++) {
+ if (i < sz)
+ fputc(isprint(p[i]) ? p[i] : '.', tracefp);
+ else
+ fputc('*', tracefp);
+ }
+ fputc('\n', tracefp);
+ c = (sz >= 8) ? 8 : sz;
+ sz -= c, p += c, o += c;
+ }
+}
+
+
+/* --- @traceon@ --- *
+ *
+ * Arguments: @FILE *fp@ = a file to trace on
+ * @unsigned int lvl@ = trace level to set
+ *
+ * Returns: ---
+ *
+ * Use: Enables tracing to a file.
+ */
+
+void traceon(FILE *fp, unsigned int lvl)
+{
+ tracefp = fp;
+ if (!tracelvl)
+ tracelvl = lvl;
+}
+
+/* --- @tracesetlvl@ --- *
+ *
+ * Arguments: @unsigned int lvl@ = trace level to set
+ *
+ * Returns: ---
+ *
+ * Use: Sets the tracing level.
+ */
+
+void tracesetlvl(unsigned int lvl) { tracelvl = lvl; }
+
+/* --- @tracing@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: Zero if not tracing, tracing level if tracing.
+ *
+ * Use: Informs the caller whether tracing is enabled.
+ */
+
+unsigned int tracing(void) { return (tracefp ? tracelvl : 0u); }
+
+#endif
+