1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
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
|