// // aegis - project change supervisor // Copyright (C) 1991-2014 Peter Miller // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see // . // #include #include #include #include #include #include #include #include #include #include #include #include #define INDENT 2 struct known_ty { string_ty *filename; int flag; int *flag_p; known_ty *next; }; static string_ty *file_name; static int line_number; static int page_width; static known_ty *known; static int depth; static string_ty * base_name(const char *file) { const char *cp1; const char *cp2; cp1 = strrchr(file, '/'); if (cp1) ++cp1; else cp1 = file; cp2 = strrchr(cp1, '.'); if (!cp2) cp2 = cp1 + strlen(cp1); if (cp2 > cp1 + 6) return str_n_from_c(cp1, 6); return str_n_from_c(cp1, cp2 - cp1); } int trace_pretest(const char *file, int *result) { string_ty *s; known_ty *kp; s = base_name(file); for (kp = known; kp; kp = kp->next) { if (str_equal(s, kp->filename)) { str_free(s); break; } } if (!kp) { kp = (known_ty *)mem_alloc(sizeof(known_ty)); kp->filename = s; kp->next = known; kp->flag = 2; // disabled known = kp; } kp->flag_p = result; *result = kp->flag; return *result; } void trace_where(const char *file, int line) { string_ty *s; // // take new name fist, because will probably be same as last // thus saving a free and a malloc (which are slow) // s = base_name(file); if (file_name) str_free(file_name); file_name = s; line_number = line; } static void trace_putchar(int c) { static char buffer[200]; static char *cp; static int in_col; static int out_col; if (!page_width) { // don't use last column, many terminals are dumb page_width = 79; // allow for progname, filename and line number (8 each) page_width -= 24; if (page_width < 16) page_width = 16; } if (!cp) { cp = strendcpy(buffer, progname_get(), buffer + sizeof(buffer)); if (cp > buffer + 6) cp = buffer + 6; *cp++ = ':'; *cp++ = '\t'; cp = strendcpy(cp, file_name->str_text, buffer + sizeof(buffer)); *cp++ = ':'; *cp++ = '\t'; snprintf(cp, buffer + sizeof(buffer) - cp, "%d:\t", line_number); cp += strlen(cp); in_col = 0; out_col = 0; } switch (c) { case '\n': *cp++ = '\n'; *cp = 0; fflush(stdout); fputs(buffer, stderr); fflush(stderr); if (ferror(stderr)) nfatal("(stderr)"); cp = 0; break; case ' ': if (out_col) ++in_col; break; case '\t': if (out_col) in_col = (in_col/INDENT + 1) * INDENT; break; case '}': case ')': case ']': if (depth > 0) --depth; // fall through default: if (!out_col) { if (c != '#') // modulo so never too long in_col = (INDENT * depth) % page_width; else in_col = 0; } if (in_col >= page_width) { trace_putchar('\n'); trace_putchar(c); return; } while (((out_col + 8) & -8) <= in_col && out_col + 1 < in_col) { *cp++ = '\t'; out_col = (out_col + 8) & -8; } while (out_col < in_col) { *cp++ = ' '; ++out_col; } if (c == '{' || c == '(' || c == '[') ++depth; *cp++ = c; in_col++; out_col++; break; } } void trace_printf(const char *s, ...) { va_list ap; char buffer[3000]; va_start(ap, s); vsnprintf(buffer, sizeof(buffer), s, ap); va_end(ap); for (s = buffer; *s; ++s) trace_putchar(*s); } const char * trace_args(void) { static nstring args; if (args.empty()) { for (known_ty *kp = known; kp; kp = kp->next) { if (kp->flag != 3) continue; if (args.empty()) args += " --trace"; args += " "; args += kp->filename->str_text; } } return args.c_str(); } void trace_enable(const char *file) { string_ty *s; known_ty *kp; s = base_name(file); for (kp = known; kp; kp = kp->next) { if (str_equal(s, kp->filename)) { str_free(s); break; } } if (!kp) { kp = (known_ty *)mem_alloc(sizeof(known_ty)); kp->filename = s; kp->flag_p = 0; kp->next = known; known = kp; } kp->flag = 3; // enabled if (kp->flag_p) *kp->flag_p = kp->flag; // // this silences a warning... // #ifdef DEBUG trace_pretest_result = 1; #endif } void trace_bool_real(const char *name, const bool &value) { if (name && *name) trace_printf("%s = ", name); trace_printf("%s", (value ? "true" : "false")); trace_printf(name && *name ? ";\n" : ",\n"); } void trace_char_real(const char *name, const char *vp) { trace_printf("%s = '", name); if (!isprint((unsigned char)*vp) || strchr("(){}[]", *vp)) { const char *s = strchr("\bb\nn\tt\rr\ff", *vp); if (s) { trace_putchar('\\'); trace_putchar(s[1]); } else trace_printf("\\%03o", (unsigned char)*vp); } else { if (strchr("'\\", *vp)) trace_putchar('\\'); trace_putchar(*vp); } trace_printf("'; /* 0x%02X, %d */\n", (unsigned char)*vp, *vp); } void trace_char_unsigned_real(const char *name, const unsigned char *vp) { trace_printf("%s = '", name); if (!isprint((unsigned char)*vp) || strchr("(){}[]", *vp)) { const char *s = strchr("\bb\nn\tt\rr\ff", *vp); if (s) { trace_putchar('\\'); trace_putchar(s[1]); } else trace_printf("\\%03o", *vp); } else { if (strchr("'\\", *vp)) trace_putchar('\\'); trace_putchar(*vp); } trace_printf("'; /* 0x%02X, %d */\n", *vp, *vp); } void trace_int_real(const char *name, const int *vp) { trace_printf("%s = %d;\n", name, *vp); } void trace_int_unsigned_real(const char *name, const unsigned int *vp) { trace_printf("%s = %u;\n", name, *vp); } void trace_long_real(const char *name, const long *vp) { if (name && *name) trace_printf("%s = ", name); trace_printf("%ld", *vp); trace_printf(name && *name ? ";\n" : ",\n"); } void trace_long_unsigned_real(const char *name, const unsigned long *vp) { trace_printf("%s = %lu;\n", name, *vp); } void trace_pointer_real(const char *name, const void *vptrptr) { const void *ptr; const void *const *ptr_ptr = (const void *const *)vptrptr; ptr = *ptr_ptr; if (!ptr) trace_printf("%s = NULL;\n", name); else trace_printf("%s = 0x%p;\n", name, ptr); } void trace_short_real(const char *name, const short *vp) { trace_printf("%s = %hd;\n", name, *vp); } void trace_short_unsigned_real(const char *name, const unsigned short *vp) { trace_printf("%s = %hu;\n", name, *vp); } void trace_string_real(const char *name, const nstring &value) { trace_string_real(name, value.c_str()); } void trace_string_real(const char *name, const string_ty *value) { trace_string_real(name, (value ? value->str_text : 0)); } void trace_string_real(const char *name, const char *vp) { const char *s; long count; if (name && *name) trace_printf("%s = ", name); if (!vp) { trace_printf("NULL"); } else { trace_printf("\""); count = 0; for (s = vp; *s; ++s) { switch (*s) { case '(': case '[': case '{': ++count; break; case ')': case ']': case '}': --count; break; } } if (count > 0) count = -count; else count = 0; for (s = vp; *s; ++s) { unsigned char c = *s; if (!isprint(c)) { const char *cp; cp = strchr("\bb\ff\nn\rr\tt", c); if (cp) trace_printf("\\%c", cp[1]); else { escape: trace_printf("\\%03o", c); } } else { switch (c) { case '(': case '[': case '{': ++count; if (count <= 0) goto escape; break; case ')': case ']': case '}': --count; if (count < 0) goto escape; break; case '\\': case '"': trace_printf("\\"); break; } trace_printf("%c", c); } } trace_printf("\""); } trace_printf(name && *name ? ";\n" : ",\n"); } void trace_indent_reset(void) { depth = 0; } const char * unctrl(int c) { static char buffer[30]; if (c < 0 || c >= 256) snprintf(buffer, sizeof(buffer), "%d", c); else { int cc; switch (c) { case '\a': cc = 'a'; goto escaped; case '\b': cc = 'b'; goto escaped; case '\f': cc = 'f'; goto escaped; case '\n': cc = 'n'; goto escaped; case '\r': cc = 'r'; goto escaped; case '\t': cc = 't'; goto escaped; case '\v': cc = 'v'; goto escaped; case '\'': case '\\': cc = c; escaped: snprintf(buffer, sizeof(buffer), "0x%02X '\\%c'", c, cc); break; case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '(': case ')': case '*': case '+': case ',': case '-': case '.': case '/': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ':': case ';': case '<': case '=': case '>': case '?': case '@': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '[': case ']': case '^': case '_': case '`': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case '{': case '|': case '}': case '~': snprintf(buffer, sizeof(buffer), "0x%02X '%c'", c, c); break; default: snprintf(buffer, sizeof(buffer), "0x%02X '\\%o'", c, c); break; } } return buffer; } void trace_time_real(const char *name, long fake) { if (name && *name) trace_printf("%s = ", name); time_t value = (time_t)fake; trace_printf("%ld /* %.24s */", fake, ctime(&value)); trace_printf(name && *name ? ";\n" : ",\n"); } void trace_double_real(const char *name, const double &value) { if (name && *name) trace_printf("%s = ", name); trace_printf("%g", value); trace_printf(name && *name ? ";\n" : ",\n"); } void trace_hexdump(const void *data, size_t data_size) { const unsigned char *data_p = (const unsigned char *)data; for (size_t j = 0; j < data_size; j += 16) { trace(("%04lX:", j)); for (size_t k = 0; k < 16; ++k) { if (j + k >= data_size) trace((" ")); else { unsigned char c = data_p[j + k]; trace(("%02X", c)); (void)c; } } trace((" ")); for (size_t k = 0; k < 16 && j + k < data_size; ++k) { unsigned char c = data_p[j + k]; c &= 0x7F; if ( c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' ) c = '_'; else if (!isprint(c)) c = '.'; trace(("%c", c)); } trace(("\n")); } } // vim: set ts=8 sw=4 et :