From 43cd111198d7839684f81a47cb12874a59b1c65b Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 27 May 2012 23:46:30 +0200 Subject: [PATCH] Add support for an application defined logging function. An application can now register an application defined callback function, which will perform the actual logging. This provides additional flexibility compared to logging to stderr with a hardcoded format. Applications can now easily display the messages in their user interface, customize the format, etc. Although the internal logging function is a printf like function, the arguments are converted into a plain string before being passed to the callback function. This greatly improves interoperability with programming languages which don't support C style variadic functions (e.g. Python, C#, etc). --- include/libdivecomputer/context.h | 5 +++++ src/context.c | 34 ++++++++++++++++++++++++++++++- src/libdivecomputer.symbols | 1 + 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/libdivecomputer/context.h b/include/libdivecomputer/context.h index 10f21b4..861dbeb 100644 --- a/include/libdivecomputer/context.h +++ b/include/libdivecomputer/context.h @@ -39,6 +39,8 @@ typedef enum dc_loglevel_t { DC_LOGLEVEL_ALL } dc_loglevel_t; +typedef void (*dc_logfunc_t) (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *message, void *userdata); + dc_status_t dc_context_new (dc_context_t **context); @@ -48,6 +50,9 @@ dc_context_free (dc_context_t *context); dc_status_t dc_context_set_loglevel (dc_context_t *context, dc_loglevel_t loglevel); +dc_status_t +dc_context_set_logfunc (dc_context_t *context, dc_logfunc_t logfunc, void *userdata); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/context.c b/src/context.c index f9d720a..2e0c62b 100644 --- a/src/context.c +++ b/src/context.c @@ -28,8 +28,19 @@ struct dc_context_t { dc_loglevel_t loglevel; + dc_logfunc_t logfunc; + void *userdata; + char msg[4096]; }; +static void +logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata) +{ + const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"}; + + fprintf (stderr, "%s: %s [in %s:%d (%s)]\n", loglevels[loglevel], msg, file, line, function); +} + dc_status_t dc_context_new (dc_context_t **out) { @@ -43,6 +54,10 @@ dc_context_new (dc_context_t **out) return DC_STATUS_NOMEMORY; context->loglevel = DC_LOGLEVEL_WARNING; + context->logfunc = logfunc; + context->userdata = NULL; + + memset (context->msg, 0, sizeof (context->msg)); *out = context; @@ -68,6 +83,18 @@ dc_context_set_loglevel (dc_context_t *context, dc_loglevel_t loglevel) return DC_STATUS_SUCCESS; } +dc_status_t +dc_context_set_logfunc (dc_context_t *context, dc_logfunc_t logfunc, void *userdata) +{ + if (context == NULL) + return DC_STATUS_INVALIDARGS; + + context->logfunc = logfunc; + context->userdata = userdata; + + return DC_STATUS_SUCCESS; +} + dc_status_t dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...) { @@ -79,9 +106,14 @@ dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, if (loglevel > context->loglevel) return DC_STATUS_SUCCESS; + if (context->logfunc == NULL) + return DC_STATUS_SUCCESS; + va_start (ap, format); - vfprintf (stderr, format, ap); + vsnprintf (context->msg, sizeof (context->msg), format, ap); va_end (ap); + context->logfunc (context, loglevel, file, line, function, context->msg, context->userdata); + return DC_STATUS_SUCCESS; } diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index fbc599d..652c011 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -20,6 +20,7 @@ dc_datetime_mktime dc_context_new dc_context_free dc_context_set_loglevel +dc_context_set_logfunc dc_iterator_next dc_iterator_free