summaryrefslogtreecommitdiffstats
path: root/liblog_vxlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'liblog_vxlog.c')
-rw-r--r--liblog_vxlog.c121
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