diff --git a/include/log.h b/include/log.h index dc5afc2..531ff30 100644 --- a/include/log.h +++ b/include/log.h @@ -15,4 +15,14 @@ void liftoff_log(enum liftoff_log_importance verbosity, const char *format, ...) _LIFTOFF_ATTRIB_PRINTF(2, 3); void liftoff_log_errno(enum liftoff_log_importance verbosity, const char *msg); +struct liftoff_log_buffer { + char *data; + size_t len, cap; +}; + +void liftoff_log_buffer_append(struct liftoff_log_buffer *buf, + const char *fmt, ...); +void liftoff_log_buffer_flush(struct liftoff_log_buffer *buf, + enum liftoff_log_importance verbosity); + #endif diff --git a/log.c b/log.c index 957517f..59356d2 100644 --- a/log.c +++ b/log.c @@ -1,5 +1,6 @@ #include #include +#include #include #include "log.h" @@ -45,3 +46,68 @@ void liftoff_log_errno(enum liftoff_log_importance verbosity, const char *msg) { liftoff_log(verbosity, "%s: %s", msg, strerror(errno)); } + +void liftoff_log_buffer_append(struct liftoff_log_buffer *buf, + const char *fmt, ...) +{ + if (!buf) { + return; + } + + va_list args; + va_start(args, fmt); + + if (buf->data == NULL) { + buf->data = malloc(4096); + if (buf->data == NULL) { + liftoff_log_errno(LIFTOFF_ERROR, "malloc"); + goto cleanup_out; + } + buf->len = 4096 / sizeof(char); + } + + do { + size_t max_len = buf->len - buf->cap; + int ret; + + ret = vsnprintf(buf->data + buf->cap, max_len, fmt, args); + if (ret < 0) { + goto cleanup_out; + } + + if (ret - (int)max_len > 0) { + buf->cap = buf->len; + buf->len *= 2; + + if (realloc(buf->data, buf->len) == NULL) { + liftoff_log_errno(LIFTOFF_ERROR, "realloc"); + goto cleanup_out; + } + } else { + buf->cap += ret; + goto final_out; + } + } while (1); + +cleanup_out: + free(buf->data); + buf->data = NULL; + buf->cap = 0; + buf->len = 0; + +final_out: + va_end(args); +} + +void liftoff_log_buffer_flush(struct liftoff_log_buffer *buf, + enum liftoff_log_importance verbosity) +{ + if (!buf || !buf->data || buf->len == 0) { + return; + } + liftoff_log(verbosity, "%s\n", buf->data); + free(buf->data); + buf->data = NULL; + buf->cap = 0; + buf->len = 0; +}