From e2fc18ae456593efe2b968d4af1b8ebfe869d807 Mon Sep 17 00:00:00 2001 From: Gediminas Jakutis Date: Tue, 12 Nov 2019 14:36:56 +0200 Subject: diagnostic: use format strings instead. flags are now dropped in place of per-stream format strings. Signed-off-by: Gediminas Jakutis --- include/rin/diagnostic.h | 2 +- src/diagnostic/diagnostic.c | 158 ++++++++++++++++++++++++++++-------- src/diagnostic/diagnostic_private.h | 3 +- test/diagnostic.c | 54 ++++-------- test/meson.build | 4 +- 5 files changed, 146 insertions(+), 75 deletions(-) diff --git a/include/rin/diagnostic.h b/include/rin/diagnostic.h index ccec0b8..6fe9c3b 100644 --- a/include/rin/diagnostic.h +++ b/include/rin/diagnostic.h @@ -43,7 +43,7 @@ enum rin_diag_outstream { }; void rin_diag_init(void); -int rin_diag_flags(int flag, int action); +int rin_diag_format(enum rin_diag_outstream, const char *format); int rin_diag_set_outstream(enum rin_diag_outstream channel, FILE *stream); void __rin_err(const char *func_name, const char *format, ...) FORMAT_STRING(2, 3); 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 #include #include #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); } diff --git a/src/diagnostic/diagnostic_private.h b/src/diagnostic/diagnostic_private.h index 4f0033f..04778b5 100644 --- a/src/diagnostic/diagnostic_private.h +++ b/src/diagnostic/diagnostic_private.h @@ -28,6 +28,7 @@ #define RIN_NEED_GETTID #include "rin/compat.h" -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); +static void rin_diag_cleanup(void); #endif /* LIBRIN_DIAGNOSTIC_PRIVATE_INCLUDED */ diff --git a/test/diagnostic.c b/test/diagnostic.c index 35866df..363743b 100644 --- a/test/diagnostic.c +++ b/test/diagnostic.c @@ -36,13 +36,11 @@ static int err_test(void); static int warn_test(void); static int fixme_test(void); static int info_test(void); -static int prefix_test(void); -static int thread_test(void); -static int clean_test(void); +static int format_test(void); static struct stdiocap capture_stdio_start(FILE *stream); static void capture_stdio_stop(struct stdiocap *cap); static char *visible_newlines(const char * const in); -static int test_default_channels(const char * const in, const char * const expected, size_t i, int usearg, void (*func)(const char *, const char *, ...)); +static int test_default_channels(const char * const in, const char * const expected, size_t i, int usearg, const char *func_name, void (*func)(const char *, const char *, ...)); int diagnostic_test(char *testname) { @@ -51,9 +49,7 @@ int diagnostic_test(char *testname) {"warn", warn_test}, {"fixme", fixme_test}, {"info", info_test}, - {"prefix", prefix_test}, - {"thread", thread_test}, - {"clean", clean_test} }; + {"format", format_test}}; size_t i; for (i = 0; i < arrlen(tests); ++i) { @@ -72,11 +68,11 @@ static int err_test(void) int ret; static const char *in[] = {"", "test", "test number is %zu", "%zu tests ran"}; - static const char *expected[] = {"error:\n", "error:test\n", "error:test number is 3\n", "error:4 tests ran\n"}; + static const char *expected[] = {"error:err_test:\n", "error:err_test:test\n", "error:err_test:test number is 3\n", "error:err_test:4 tests ran\n"}; for (i = 0; i < arrlen(in); ++i) { usearg = i < (arrlen(in) / 2) ? 0 : 1; - ret = test_default_channels(in[i], expected[i], i, usearg, __rin_err); + ret = test_default_channels(in[i], expected[i], i, usearg, __func__, __rin_err); } return ret; @@ -89,11 +85,11 @@ static int warn_test(void) int ret; static const char *in[] = {"", "test", "test number is %zu", "%zu tests ran"}; - static const char *expected[] = {"warning:\n", "warning:test\n", "warning:test number is 3\n", "warning:4 tests ran\n"}; + static const char *expected[] = {"warning:warn_test:\n", "warning:warn_test:test\n", "warning:warn_test:test number is 3\n", "warning:warn_test:4 tests ran\n"}; for (i = 0; i < arrlen(in); ++i) { usearg = i < (arrlen(in) / 2) ? 0 : 1; - ret = test_default_channels(in[i], expected[i], i, usearg, __rin_warn); + ret = test_default_channels(in[i], expected[i], i, usearg, __func__, __rin_warn); } return ret; @@ -106,11 +102,11 @@ static int fixme_test(void) int ret; static const char *in[] = {"", "test", "test number is %zu", "%zu tests ran"}; - static const char *expected[] = {"fixme:\n", "fixme:test\n", "fixme:test number is 3\n", "fixme:4 tests ran\n"}; + static const char *expected[] = {"fixme:fixme_test:\n", "fixme:fixme_test:test\n", "fixme:fixme_test:test number is 3\n", "fixme:fixme_test:4 tests ran\n"}; for (i = 0; i < arrlen(in); ++i) { usearg = i < (arrlen(in) / 2) ? 0 : 1; - ret = test_default_channels(in[i], expected[i], i, usearg, __rin_fixme); + ret = test_default_channels(in[i], expected[i], i, usearg, __func__, __rin_fixme); } return ret; @@ -123,14 +119,14 @@ static int info_test(void) int ret; static const char *in[] = {"", "test", "test number is %zu", "%zu tests ran"}; - static const char *expected[] = {"info:\n", "info:test\n", "info:test number is 3\n", "info:4 tests ran\n"}; + static const char *expected[] = {"info:info_test:\n", "info:info_test:test\n", "info:info_test:test number is 3\n", "info:info_test:4 tests ran\n"}; /* `ninja test` seems to be intercepting stdout, so we cannot test the default outstream */ rin_diag_set_outstream(rin_diag_info, stderr); for (i = 0; i < arrlen(in); ++i) { usearg = i < (arrlen(in) / 2) ? 0 : 1; - ret = test_default_channels(in[i], expected[i], i, usearg, __rin_info); + ret = test_default_channels(in[i], expected[i], i, usearg, __func__, __rin_info); } /* restore the default, kind of */ @@ -139,17 +135,7 @@ static int info_test(void) return ret; } -static int prefix_test(void) -{ - return 77; -} - -static int thread_test(void) -{ - return 77; -} - -static int clean_test(void) +static int format_test(void) { return 77; } @@ -221,16 +207,12 @@ static char *visible_newlines(const char * const in) return ret; } -static int test_default_channels(const char * const in, const char * const expected, size_t i, int usearg, void (*func)(const char *, const char *, ...)) +static int test_default_channels(const char * const in, const char * const expected, size_t i, int usearg, const char *func_name, void (*func)(const char *, const char *, ...)) { - char buf[32] = {0}; + char buf[64] = {0}; struct stdiocap cap; - size_t len; int ret = 0; - len = strlen(expected); - ++len; - cap = capture_stdio_start(stderr); if (!cap.pipe) { @@ -239,12 +221,12 @@ static int test_default_channels(const char * const in, const char * const expec } if (usearg) { - func(NULL, in, i + 1); + func(func_name, in, i + 1); } else { - func(NULL, in); + func(func_name, in); } - if (!(fgets(buf, sizeof(buf) < len ? sizeof(buf) : len, cap.pipe))) { + if (!(fgets(buf, sizeof(buf), cap.pipe))) { ret = 1; goto fail; } @@ -257,7 +239,7 @@ fail: } else { char *tmp[2]; - ret = strncmp(buf, expected, sizeof(buf) < len ? sizeof(buf) : len); + ret = strncmp(buf, expected, sizeof(buf)); tmp[0] = visible_newlines(buf); tmp[1] = visible_newlines(expected); diff --git a/test/meson.build b/test/meson.build index 7864166..3ca8a08 100644 --- a/test/meson.build +++ b/test/meson.build @@ -20,9 +20,7 @@ test('diagnostic err', test_e, args : ['diagnostic', 'err']) test('diagnostic warn', test_e, args : ['diagnostic', 'warn']) test('diagnostic fixme', test_e, args : ['diagnostic', 'fixme']) test('diagnostic info', test_e, args : ['diagnostic', 'info']) -test('diagnostic prefix', test_e, args : ['diagnostic', 'prefix']) -test('diagnostic thread', test_e, args : ['diagnostic', 'thread']) -test('diagnostic clean', test_e, args : ['diagnostic', 'clean']) +test('diagnostic format', test_e, args : ['diagnostic', 'format']) test('timespec add', test_e, args : ['time', 'timespec add']) test('timespec subtract', test_e, args : ['time', 'timespec sub']) test('timespec normalize', test_e, args : ['time', 'timespec normalize']) -- cgit v1.2.3