• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

saitoha / libsixel / 19918707358

04 Dec 2025 05:12AM UTC coverage: 38.402% (-4.0%) from 42.395%
19918707358

push

github

saitoha
tests: fix meson msys dll lookup

9738 of 38220 branches covered (25.48%)

12841 of 33438 relevant lines covered (38.4%)

782420.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

32.67
/src/logger.c
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright (c) 2025 libsixel developers. See `AUTHORS`.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 */
24

25
#include "config.h"
26

27
#include <stdarg.h>
28
#include <stdint.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32

33
#ifndef _WIN32
34
#include <pthread.h>
35
#endif
36

37
#include "assessment.h"
38
#include "logger.h"
39

40
static sixel_logger_t *sixel_logger_active;
41
static int sixel_logger_refcount;
42

43
static unsigned long long
44
sixel_logger_thread_id(void)
×
45
{
46
#ifndef _WIN32
47
    return (unsigned long long)(uintptr_t)pthread_self();
×
48
#else
49
    return 0ULL;
50
#endif
51
}
52

53
static void
54
sixel_logger_escape(char const *message, char *buffer, size_t size)
×
55
{
56
    size_t i;
×
57
    size_t written;
×
58

59
    if (buffer == NULL || size == 0) {
×
60
        return;
61
    }
62
    buffer[0] = '\0';
×
63
    if (message == NULL) {
×
64
        return;
65
    }
66
    written = 0;
67
    for (i = 0; message[i] != '\0' && written + 2 < size; ++i) {
×
68
        if (message[i] == '\"' || message[i] == '\\') {
×
69
            buffer[written++] = '\\';
×
70
            if (written + 1 >= size) {
×
71
                break;
72
            }
73
        }
74
        buffer[written++] = message[i];
×
75
    }
76
    buffer[written] = '\0';
×
77
}
×
78

79
void
80
sixel_logger_init(sixel_logger_t *logger)
3,730✔
81
{
82
    if (logger == NULL) {
3,100!
83
        return;
84
    }
85
    logger->delegate = NULL;
3,730✔
86
    logger->file = NULL;
3,730✔
87
    logger->mutex_ready = 0;
3,730✔
88
    logger->active = 0;
3,730✔
89
    logger->started_at = 0.0;
3,100✔
90
}
91

92
void
93
sixel_logger_close(sixel_logger_t *logger)
453✔
94
{
95
    if (logger == NULL) {
453!
96
        return;
97
    }
98
    if (logger->delegate != NULL) {
453!
99
        if (logger->delegate == sixel_logger_active &&
×
100
                sixel_logger_refcount > 0) {
×
101
            --sixel_logger_refcount;
×
102
            if (sixel_logger_refcount != 0) {
×
103
                logger->delegate = NULL;
×
104
                logger->active = 0;
×
105
                return;
×
106
            }
107
            logger = logger->delegate;
×
108
            logger->delegate = NULL;
×
109
        } else {
110
            logger->delegate = NULL;
×
111
            logger->active = 0;
×
112
            return;
×
113
        }
114
    }
115
    if (logger == sixel_logger_active && sixel_logger_refcount > 1) {
453!
116
        --sixel_logger_refcount;
×
117
        return;
×
118
    }
119
    if (logger->mutex_ready) {
453!
120
#if SIXEL_ENABLE_THREADS
121
        sixel_mutex_destroy(&logger->mutex);
122
#endif  /* SIXEL_ENABLE_THREADS */
123
        logger->mutex_ready = 0;
×
124
    }
125
    if (logger->file != NULL) {
453!
126
        fclose(logger->file);
×
127
        logger->file = NULL;
×
128
    }
129
    if (logger == sixel_logger_active && sixel_logger_refcount > 0) {
453!
130
        sixel_logger_refcount = 0;
×
131
        sixel_logger_active = NULL;
×
132
    }
133
    logger->active = 0;
453✔
134
}
135

136
SIXELSTATUS
137
sixel_logger_open(sixel_logger_t *logger, char const *path)
×
138
{
139
    if (logger == NULL) {
×
140
        return SIXEL_BAD_ARGUMENT;
141
    }
142
    if (path == NULL || path[0] == '\0') {
×
143
        return SIXEL_OK;
144
    }
145
    logger->file = fopen(path, "w");
×
146
    if (logger->file == NULL) {
×
147
        return SIXEL_RUNTIME_ERROR;
148
    }
149
#if SIXEL_ENABLE_THREADS
150
    if (sixel_mutex_init(&logger->mutex) != 0) {
×
151
        fclose(logger->file);
152
        logger->file = NULL;
153
        return SIXEL_RUNTIME_ERROR;
154
    }
155
#endif  /* SIXEL_ENABLE_THREADS */
156
    logger->mutex_ready = 1;
×
157
    logger->active = 1;
×
158
    logger->started_at = sixel_assessment_timer_now();
×
159
    setvbuf(logger->file, NULL, _IOLBF, 0);
×
160
    sixel_logger_active = logger;
×
161
    sixel_logger_refcount = 1;
×
162
    return SIXEL_OK;
×
163
}
164

165
SIXELSTATUS
166
sixel_logger_prepare_env(sixel_logger_t *logger)
1,714✔
167
{
168
    char const *path;
1,714✔
169
    SIXELSTATUS status;
1,714✔
170

171
    if (logger == NULL) {
1,714!
172
        return SIXEL_BAD_ARGUMENT;
173
    }
174

175
    /*
176
     * Reuse an already opened logger so the timeline is continuous.  Some
177
     * call sites share a logger instance across serial and pipeline phases;
178
     * reopening would truncate the file and reset timestamps, hiding early
179
     * stages from the timeline. Share the sink via a lightweight delegate
180
     * pointer instead of copying mutex state.
181
     */
182
    if (sixel_logger_active != NULL &&
1,714!
183
            sixel_logger_active->active &&
×
184
            sixel_logger_active->mutex_ready) {
×
185
        sixel_logger_init(logger);
×
186
        logger->delegate = sixel_logger_active;
×
187
        logger->active = sixel_logger_active->active;
×
188
        logger->started_at = sixel_logger_active->started_at;
×
189
        ++sixel_logger_refcount;
×
190
        return SIXEL_OK;
×
191
    }
192

193
    sixel_logger_init(logger);
1,714✔
194
    path = getenv("SIXEL_PARALLEL_LOG_PATH");
1,714✔
195
    if (path == NULL || path[0] == '\0') {
1,714!
196
        return SIXEL_OK;
197
    }
198
    status = sixel_logger_open(logger, path);
×
199
    if (SIXEL_FAILED(status)) {
×
200
        sixel_logger_close(logger);
×
201
    }
202

203
    return status;
204
}
205

206
void
207
sixel_logger_logf(sixel_logger_t *logger,
19,656✔
208
                           char const *role,
209
                           char const *worker,
210
                           char const *event,
211
                           int job_id,
212
                           int row_index,
213
                           int y0,
214
                           int y1,
215
                           int in0,
216
                           int in1,
217
                           char const *fmt,
218
                           ...)
219
{
220
    sixel_logger_t *target;
19,656✔
221
    char message[256];
19,656✔
222
    char escaped[512];
19,656✔
223
    va_list args;
19,656✔
224
    double timestamp;
19,656✔
225

226
    target = logger;
19,656✔
227
    if (logger != NULL && logger->delegate != NULL) {
19,656!
228
        target = logger->delegate;
×
229
    }
230
    if (target == NULL || !target->active || target->file == NULL
19,656!
231
            || !target->mutex_ready) {
×
232
        return;
19,656✔
233
    }
234

235
    va_start(args, fmt);
×
236
    if (fmt != NULL) {
×
237
#if defined(__clang__)
238
#pragma clang diagnostic push
239
#pragma clang diagnostic ignored "-Wformat-nonliteral"
240
#elif defined(__GNUC__)
241
#pragma GCC diagnostic push
242
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
243
#endif
244
        /*
245
         * The format strings are defined in our code paths.  Suppress the
246
         * nonliteral warning so we can forward variadic arguments safely.
247
         */
248
        (void)vsnprintf(message, sizeof(message), fmt, args);
×
249
#if defined(__clang__)
250
#pragma clang diagnostic pop
251
#elif defined(__GNUC__)
252
#pragma GCC diagnostic pop
253
#endif
254
    } else {
255
        message[0] = '\0';
×
256
    }
257
    va_end(args);
×
258

259
    sixel_logger_escape(message, escaped, sizeof(escaped));
×
260

261
#if SIXEL_ENABLE_THREADS
262
    sixel_mutex_lock(&target->mutex);
263
#endif  /* SIXEL_ENABLE_THREADS */
264
    timestamp = sixel_assessment_timer_now() - target->started_at;
×
265
    if (timestamp < 0.0) {
×
266
        timestamp = 0.0;
267
    }
268
    fprintf(target->file,
×
269
            "{\"ts\":%.6f,\"thread\":%llu,\"worker\":\"%s\","\
270
            "\"role\":\"%s\",\"event\":\"%s\",\"job\":%d,"\
271
            "\"row\":%d,\"y0\":%d,\"y1\":%d,\"in0\":%d,\"in1\":%d,"\
272
            "\"message\":\"%s\"}\n",
273
            timestamp,
274
            sixel_logger_thread_id(),
275
            worker != NULL ? worker : "",
×
276
            role != NULL ? role : "",
×
277
            event != NULL ? event : "",
×
278
            job_id,
279
            row_index,
280
            y0,
281
            y1,
282
            in0,
283
            in1,
284
            escaped);
285
    fflush(target->file);
×
286
#if SIXEL_ENABLE_THREADS
287
    sixel_mutex_unlock(&target->mutex);
288
#endif  /* SIXEL_ENABLE_THREADS */
289
}
1!
290

291
/* emacs Local Variables:      */
292
/* emacs mode: c               */
293
/* emacs tab-width: 4          */
294
/* emacs indent-tabs-mode: nil */
295
/* emacs c-basic-offset: 4     */
296
/* emacs End:                  */
297
/* vim: set expandtab ts=4 sts=4 sw=4 : */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc