/* * _tracef(format, args) * * Writes tracing information to file "trace.out" if tracing is * enabled. Formatting follows printf conventions with some * minor differences: * %b unsigned binary integer * %c character, output as 'x' * %d signed decimal integer * %o unsigned octal integer * %s string (terminated by EOS), output as "xxx" * %*s counted string (takes two args), output as "xxx" * %x unsigned hex integer * Field and width parameters (as in printf) aren't permitted. * traceon() turns on tracing * traceoff() turns off tracing * * Note: #ifdef decus stuff hasn't been tested. */ #include #define FALSE 0 #define TRUE 1 #define EOS '\0' #ifdef decus static FILE tracefd; #else static int tracefd; #endif static int tracing = FALSE; static int file_opened = FALSE; traceon() /* * Turn on tracing, opening the trace file if necessary. */ { #ifndef decus extern int errno; extern char *sys_errlist[]; #endif if (!file_opened) { file_opened = TRUE; #ifdef decus if ((tracefd = fopen("trace.out", "w")) == NULL) { perror("trace.out"); error("trace: can't create trace.out\n"); } #else if ((tracefd = creat("trace.out", 0644)) < 0) { write(2, "trace: Can't open \"trace.out\" file: ", 36); write(2, sys_errlist[errno], strlen(sys_errlist[errno])); write(2, "\n", 1); exit(1); } #endif } _tracef("traceon() called"); tracing = TRUE; } traceoff() { _tracef("traceoff() called"); tracing = FALSE; } /* * XBUFSIZE is the length of a printed line in the trace output file. */ #define XBUFSIZE 80 static char xbuffer[XBUFSIZE + 2]; static char *xbufp; _tracef(fmt, args) char *fmt; int args; { int *parm; char buffer[512]; auto char *bufp; char *bufe; char bytebuff[]; /* Bytes stored here for output */ char *bytep; /* Pointer into bytebuff[] */ int stringcount; /* Count for %*s format */ char *stringp; /* String pointer for %*s */ parm = &args; bufp = buffer; if (!tracing) return; while (*fmt) { if (*fmt == '%') { fmt++; switch (*fmt) { case 'b': addnum(&bufp, *(parm++), 2); break; case 'd': addnum(&bufp, *(parm++), 10); break; case 'o': addnum(&bufp, *(parm++), 8); break; case 'x': addnum(&bufp, *(parm++), 16); break; case 'c': *(bufp++) = '\''; *(bufp++) = *(parm++); *(bufp++) = '\''; break; case '*': /* Counted string */ if (fmt[1] != 's') break; fmt++; stringcount = *(parm++); *(bufp++) = '"'; stringp = *(parm++); if (stringp == NULL) { strcpy(bufp, "?NULL?"); bufp += 6; } else while (--stringcount) { *bufp++ = *stringp++; } *bufp++ = '"'; break; case 's': if (*parm) { *(bufp++) = '"'; strcpy(bufp, *parm); bufp += strlen(*parm); *(bufp++) = '"'; } else { strcpy(bufp, "NULL"); bufp += 4; } parm++; break; } } else { *(bufp++) = *fmt; } fmt++; } *(bufp++) = '\n'; /* * Write the buffer in datascope mode. */ bufe = bufp; xbufp = xbuffer; for (bufp = buffer; bufp < bufe; bufp++) { bytep = bytebuff; *bufp &= 0377; if (*bufp == '\n') _traceout("\n"); else if (*bufp == '\033') _traceout(""); else { if (*bufp >= 0177) { *bytep++ = '~'; *bufp -= 0200; } if (*bufp < ' ' && *bufp != '\t') { *bytep++ = '^'; *bytep++ = (*bufp + '@'); } else *bytep++ = *bufp; *bytep = '\0'; _traceout(bytebuff); } } _traceout(NULL); } #define GUARD 4 static _traceout(string) char *string; /* * Output routine for _tracef() -- * "\n" End of line from user. * NULL end of text. Dump current buffer if non-empty * string Stuff it if there's room, else get a new line. */ { if (string == NULL) { if (xbufp > xbuffer) { write(tracefd, xbuffer, xbufp - xbuffer); xbufp = xbuffer; } } else if (string[0] == '\n' && string[1] == '\0') { *xbufp++ = '\n'; write(tracefd, xbuffer, xbufp - xbuffer); xbufp = xbuffer; } else if (xbufp + strlen(string) < &xbuffer[XBUFSIZE - GUARD]) { while (*string != '\0') { *xbufp++ = *string++; } } else { while (xbufp < &xbuffer[XBUFSIZE - GUARD]) *xbufp++ = ' '; strcpy(xbufp, "|<--\n"); write(tracefd, xbuffer, strlen(xbuffer)); strcpy(xbuffer, string); xbufp = &xbuffer[strlen(string)]; } } static addnum(bufp, num, base) char **bufp; /* Output pointer */ int num; /* To be converted */ int base; /* Output base */ /* * Convert the number to ascii. Note: base 10 is signed, others are * unsigned. */ { register unsigned int temp; if (base == 10 && num < 0) { num = -num; *((*bufp)++) = '-'; if (num < 0) { /* * The dreaded 32768 -- the following will not work * everywhere, but will do for now. */ #if (0x8000 < 0) *((*bufp)++) = '3'; /* 16 bit twos-complement */ num = 2768; #else *((*bufp)++) = '2'; /* 32 bit twos-complement */ num = 147483648; #endif } } if ((temp = ((unsigned) num) / base) != 0) addnum(bufp, temp, base); *((*bufp)++) = "0123456789abcdef"[((unsigned) num) % base]; }