diff options
Diffstat (limited to 'liblog_vxlog.c')
| -rw-r--r-- | liblog_vxlog.c | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/liblog_vxlog.c b/liblog_vxlog.c new file mode 100644 index 0000000..4093c59 --- /dev/null +++ b/liblog_vxlog.c @@ -0,0 +1,121 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif + +static int +ensure_fit(struct messagebuf *msg, size_t extent) +{ + size_t new_size; + void *new; + if (extent >= msg->size - msg->len) { + new_size = msg->len + extent + 1; + new = realloc(msg->text, new_size); + if (!new) + return -1; + msg->text = new; + msg->size = new_size; + } + return 0; +} + +int +liblog_vxlog(struct liblog_context *ctx, enum liblog_level level, unsigned flags, const char *fmt, va_list args) +{ + /* TODO optionally avoid allocating and deallocating for each call */ + /* TODO respect logmask */ + + struct messagebuf msgbuf = MESSAGEBUF_INIT, *msg; + int corked; + size_t old_len; + + if (!ctx || (level & (enum liblog_level)~0x001F)) { + einval: + errno = EINVAL; + return -1; + } + if (!fmt && !(flags & (XLOG_NOT_INLINE - 1U) & LIBLOG_XLOG_NO_TEXT)) + goto einval; + if ((flags & (LIBLOG_XLOG_CORK | LIBLOG_XLOG_UNCORK)) == (LIBLOG_XLOG_CORK | LIBLOG_XLOG_UNCORK)) + goto einval; + if ((flags & (LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_BACKTRACE)) == (LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_BACKTRACE)) + goto einval; + + msg = ctx->internal_state ? &ctx->internal_state->msg : &msgbuf; + corked = !!msg->prefix; + old_len = msg->len; + + /* TODO ctx->internal_state must be allocated */ + + if (!msg->prefix) { + /* TODO implement: prefix */ + } + + if (!(flags & LIBLOG_XLOG_NO_BACKTRACE)) { + if (flags & LIBLOG_XLOG_BACKTRACE) { + unsigned levels = (flags / XLOG_NOT_INLINE) + 1U; + if (liblog_trace__(&msg->text, &msg->len, &msg->size, (size_t)levels, NULL)) + return -1; + } + } + + if (!(flags & LIBLOG_XLOG_NO_TEXT)) { + int len; + va_list args2; + va_copy(args2, args); + len = snprintf(NULL, 0, fmt, args2); + va_end(args2); + if (len < 0) + return -1; + if (ensure_fit(msg, (size_t)len)) + return -1; + if (snprintf(&msg->text[msg->len], (size_t)len + 1, fmt, args) != len) + abort(); + msg->len += (size_t)len; + } + + if (flags & LIBLOG_XLOG_UNCORK) { + if (msg == &ctx->internal_state->msg) { + memcpy(&msgbuf, msg, sizeof(*msg)); + ctx->internal_state->msg = MESSAGEBUF_INIT; + msg = &msgbuf; + } + goto output; + } else if (flags & LIBLOG_XLOG_CORK) { + if (msg != &ctx->internal_state->msg) + memcpy(&ctx->internal_state->msg, msg, sizeof(*msg)); + } else if (corked) { + /* do nothing, internal state already set */ + } else { + output: + if (msg->len && msg->text[msg->len - 1] != '\n') { + if (ensure_fit(msg, 0)) + goto fail; + msg->text[msg->len++] = '\n'; + } + if (liblog_flush__(ctx, msg)) + goto fail; + free(msg->prefix); + free(msg->text); + *msg = MESSAGEBUF_INIT; + } + + return 0; + +fail: + if (msg != &ctx->internal_state->msg) { + free(msg->prefix); + free(msg->text); + } + msg->len = old_len; + return -1; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif |
