diff options
Diffstat (limited to 'src/diagnostic/diagnostic.c')
-rw-r--r-- | src/diagnostic/diagnostic.c | 158 |
1 files changed, 124 insertions, 34 deletions
diff --git a/src/diagnostic/diagnostic.c b/src/diagnostic/diagnostic.c index 1258711..a5d7149 100644 --- a/src/diagnostic/diagnostic.c +++ b/src/diagnostic/diagnostic.c @@ -20,41 +20,109 @@ #include "diagnostic_private.h" +#include <stdlib.h> #include <string.h> #include <time.h> #include "rin/diagnostic.h" #include "rin/time.h" #include "rin/definitions.h" +static const char default_format[] = "C:F:mn"; +static const char valid_format[] = "CFtTn:m"; + static struct iostate { + char pidconv[8]; struct timespec start; FILE *err; FILE *warn; FILE *fixme; FILE *info; - unsigned int flags; - char pidconv[8]; -} state = {{0, 0}, NULL, NULL, NULL, NULL, RIN_DIAG_PREFIX, "%08x:"}; + char *err_format; + char *warn_format; + char *fixme_format; + char *info_format; +} state = {"%08x:", {0, 0}, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +void rin_diag_cleanup(void) +{ + char *tmp; + + tmp = state.err_format; + state.err_format = NULL; + free(tmp); + + tmp = state.warn_format; + state.warn_format = NULL; + free(tmp); + + tmp = state.fixme_format; + state.fixme_format = NULL; + free(tmp); + + tmp = state.info_format; + state.info_format = NULL; + free(tmp); +} void rin_diag_init(void) { static const char convstr[8] = "%04hx:"; + clock_gettime(RIN_CLOCK_WALL_COUNTER, &state.start); + if (sizeof(pid_t) == 4) { memcpy(state.pidconv, convstr, sizeof(convstr)); } - clock_gettime(RIN_CLOCK_WALL_COUNTER, &state.start); + atexit(rin_diag_cleanup); } -int rin_diag_flags(int flag, int action) +int rin_diag_format(enum rin_diag_outstream channel, const char *format) { - /* checking for non-existent flags */ - if (flag & ~(RIN_DIAG_ALLFLAGS)) { - return EINVAL; + char *tmp; + size_t i, j; + + if (!format) { + tmp = NULL; + } else { + for (i = 0; format[i]; ++i) { + int valid = 0; + + for (j = 0; valid_format[j]; ++j) { + if (valid_format[j] == format [i]) { + valid = 1; + break; + } + } + + if (!valid) { + return EINVAL; + } + } + + tmp = strdup(format); } - state.flags = action ? (state.flags | flag) : (state.flags & ~(flag)); + switch (channel) { + case rin_diag_err: + free(state.err_format); + state.err_format = tmp; + break; + case rin_diag_warn: + free(state.warn_format); + state.warn_format = tmp; + break; + case rin_diag_fixme: + free(state.fixme_format); + state.fixme_format = tmp; + break; + case rin_diag_info: + free(state.info_format); + state.info_format = tmp; + break; + default: + return EINVAL; + } return 0; } @@ -86,7 +154,9 @@ void __rin_err(const char *func_name, const char *format, ...) va_list args; va_start(args, format); - __rin_msg(state.err ? state.err : stderr, "error", func_name, format, args); + __rin_msg(state.err ? state.err : stderr, "error", func_name, + state.err_format ? state.err_format : default_format, + format, args); } void __rin_warn(const char *func_name, const char *format, ...) @@ -94,7 +164,9 @@ void __rin_warn(const char *func_name, const char *format, ...) va_list args; va_start(args, format); - __rin_msg(state.warn ? state.warn : stderr, "warning", func_name, format, args); + __rin_msg(state.warn ? state.warn : stderr, "warning", func_name, + state.warn_format ? state.warn_format : default_format, + format, args); } void __rin_fixme(const char *func_name, const char *format, ...) @@ -102,7 +174,9 @@ void __rin_fixme(const char *func_name, const char *format, ...) va_list args; va_start(args, format); - __rin_msg(state.fixme ? state.fixme : stderr, "fixme", func_name, format, args); + __rin_msg(state.fixme ? state.fixme : stderr, "fixme", func_name, + state.fixme_format ? state.fixme_format : default_format, + format, args); } void __rin_info(const char *func_name, const char *format, ...) @@ -110,30 +184,46 @@ void __rin_info(const char *func_name, const char *format, ...) va_list args; va_start(args, format); - __rin_msg(state.info ? state.info : stdout, "info", func_name, format, args); + __rin_msg(state.info ? state.info : stdout, "info", func_name, + state.info_format ? state.info_format : default_format, + format, args); } -static void __rin_msg(FILE *stream, const char *prefix, const char *func_name, const char *format, va_list args) +static void __rin_msg(FILE *stream, const char *prefix, const char *func_name, const char *rin_format, const char *format, va_list args) { - if (state.flags & RIN_DIAG_PREFIX) { - fprintf(stream, "%s:", prefix); - } - - if (state.flags & RIN_DIAG_THREADNUM) { - fprintf(stream, state.pidconv, gettid()); - } - - if (state.flags & RIN_DIAG_FUNC) { - fprintf(stream, "%s:", func_name); - } - - if (state.flags & RIN_DIAG_TIME) { - struct timespec t; - clock_gettime(RIN_CLOCK_WALL_COUNTER, &t); - t = rin_time_sub(&t, &state.start); - fprintf(stream, "%lu.%lu:", t.tv_sec, t.tv_nsec); + struct timespec t; + size_t i; + int gottime = 0; + + for (i = 0; rin_format[i]; ++i) { + switch (rin_format[i]) { + case 'C': + fprintf(stream, "%s", prefix); + break; + case 'F': + fprintf(stream, "%s", func_name); + break; + case 't': + fprintf(stream, state.pidconv, gettid()); + break; + case 'T': + if (!gottime) { + clock_gettime(RIN_CLOCK_WALL_COUNTER, &t); + t = rin_time_sub(&t, &state.start); + gottime = 1; + } + + fprintf(stream, "%lus%06lu.%03luµs", t.tv_sec, t.tv_nsec / 1000, t.tv_nsec % 1000); + break; + case 'n': + fprintf(stream, "\n"); + break; + case ':': + fprintf(stream, ":"); + break; + case 'm': + vfprintf(stream, format, args); + break; + } } - - vfprintf(stream, format, args); - fputc('\n', stream); } |