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

aremmell / libsir / 212

24 Aug 2023 01:36PM UTC coverage: 94.835% (+0.002%) from 94.833%
212

Pull #225

gitlab-ci

johnsonjh
Support building with Oracle C++

Tested on Oracle Studio C++ on Linux

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #225: Portability enhancements

97 of 97 new or added lines in 11 files covered. (100.0%)

3048 of 3214 relevant lines covered (94.84%)

1608268.24 hits per line

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

90.85
/src/sirfilecache.c
1
/*
2
 * sirfilecache.c
3
 *
4
 * Author:    Ryan M. Lederman <lederman@gmail.com>
5
 * Copyright: Copyright (c) 2018-2023
6
 * Version:   2.2.3
7
 * License:   The MIT License (MIT)
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
10
 * this software and associated documentation files (the "Software"), to deal in
11
 * the Software without restriction, including without limitation the rights to
12
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13
 * the Software, and to permit persons to whom the Software is furnished to do so,
14
 * subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
#include "sir/filecache.h"
27
#include "sir/filesystem.h"
28
#include "sir/internal.h"
29
#include "sir/defaults.h"
30

31
sirfileid _sir_addfile(const char* path, sir_levels levels, sir_options opts) {
34,901✔
32
    (void)_sir_seterror(_SIR_E_NOERROR);
34,901✔
33

34
    if (!_sir_sanity())
34,901✔
35
        return 0;
×
36

37
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, 0);
34,901✔
38

39
    _sir_defaultlevels(&levels, sir_file_def_lvls);
34,901✔
40
    _sir_defaultopts(&opts, sir_file_def_opts);
34,901✔
41

42
    sirfileid retval = _sir_fcache_add(sfc, path, levels, opts);
34,901✔
43
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
34,901✔
44

45
    return retval;
34,901✔
46
}
47

48
bool _sir_updatefile(sirfileid id, sir_update_config_data* data) {
34,179✔
49
    (void)_sir_seterror(_SIR_E_NOERROR);
34,179✔
50

51
    if (!_sir_sanity() || !_sir_validfileid(id) || !_sir_validupdatedata(data))
34,179✔
52
        return false;
3✔
53

54
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
34,176✔
55
    bool retval = _sir_fcache_update(sfc, id, data);
34,176✔
56
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
34,176✔
57

58
    return retval;
34,174✔
59
}
60

61
bool _sir_remfile(sirfileid id) {
34,741✔
62
    (void)_sir_seterror(_SIR_E_NOERROR);
34,741✔
63

64
    if (!_sir_sanity() || !_sir_validfileid(id))
34,741✔
65
        return false;
74✔
66

67
    _SIR_LOCK_SECTION(sirfcache, sfc, SIRMI_FILECACHE, false);
34,664✔
68
    bool retval = _sir_fcache_rem(sfc, id);
34,664✔
69
    _SIR_UNLOCK_SECTION(SIRMI_FILECACHE);
34,664✔
70

71
    return retval;
34,664✔
72
}
73

74
sirfile* _sirfile_create(const char* path, sir_levels levels, sir_options opts) {
34,808✔
75
    if (!_sir_validstr(path) || !_sir_validlevels(levels) || !_sir_validopts(opts))
34,808✔
76
        return NULL;
×
77

78
    sirfile* sf = (sirfile*)calloc(1, sizeof(sirfile));
34,808✔
79
    if (!sf) {
34,808✔
80
        (void)_sir_handleerr(errno);
29✔
81
        return NULL;
29✔
82
    }
83

84
    sf->path = strndup(path, strnlen(path, SIR_MAXPATH));
34,779✔
85
    if (!sf->path) {
34,779✔
86
        (void)_sir_handleerr(errno);
33✔
87
        _sir_safefree(&sf);
33✔
88
        return NULL;
33✔
89
    }
90

91
    sf->levels = levels;
34,746✔
92
    sf->opts   = opts;
34,746✔
93

94
    if (!_sirfile_open(sf) || !_sirfile_validate(sf)) {
34,746✔
95
        _sirfile_destroy(&sf);
67✔
96
        return NULL;
67✔
97
    }
98

99
    return sf;
34,679✔
100
}
101

102
bool _sirfile_open(sirfile* sf) {
34,780✔
103
    if (!_sir_validptr(sf) && !_sir_validstr(sf->path))
34,780✔
104
        return false;
×
105

106
    FILE* f  = NULL;
34,780✔
107
    bool open = _sir_openfile(&f, sf->path, SIR_FOPENMODE, SIR_PATH_REL_TO_CWD);
34,780✔
108
    if (!open || !f)
34,780✔
109
        return false;
61✔
110

111
    _sirfile_close(sf);
34,713✔
112

113
    sf->f  = f;
34,713✔
114
    sf->id = FNV32_1a((const uint8_t*)sf->path, strnlen(sf->path, SIR_MAXPATH));
34,713✔
115

116
    return true;
34,713✔
117
}
118

119
void _sirfile_close(sirfile* sf) {
69,459✔
120
    if (!_sir_validptrnofail(sf) || !_sir_validptrnofail(sf->f))
69,459✔
121
        return;
34,746✔
122

123
    _sir_safefclose(&sf->f);
34,713✔
124
}
125

126
bool _sirfile_write(sirfile* sf, const char* output) {
1,281,720✔
127
    if (!_sirfile_validate(sf) || !_sir_validstr(output))
1,281,720✔
128
        return false;
×
129

130
    if (_sirfile_needsroll(sf)) {
1,281,720✔
131
        bool rolled   = false;
107✔
132
        char* newpath = NULL;
110✔
133

134
        _sir_selflog("file (path: '%s', id: %" PRIx32") reached ~%d bytes in size;"
109✔
135
                     " rolling...", sf->path, sf->id, SIR_FROLLSIZE);
136

137
        _sir_fflush(sf->f);
110✔
138

139
        if (_sirfile_roll(sf, &newpath)) {
110✔
140
            char header[SIR_MAXFHEADER] = {0};
34✔
141
            (void)snprintf(header, SIR_MAXFHEADER, SIR_FHROLLED, newpath);
34✔
142
            rolled = _sirfile_writeheader(sf, header);
34✔
143
        }
144

145
        _sir_safefree(&newpath);
110✔
146
        if (!rolled) /* write anyway; don't want to lose data. */
109✔
147
            _sir_selflog("error: failed to roll file (path: '%s', id: %" PRIx32")!",
76✔
148
                sf->path, sf->id);
149
    }
150

151
    size_t writeLen = strnlen(output, SIR_MAXFHEADER);
1,281,720✔
152
    size_t write    = fwrite(output, sizeof(char), writeLen, sf->f);
1,281,720✔
153

154
    SIR_ASSERT(write == writeLen);
1,264,381✔
155

156
    if (write < writeLen) {
1,281,720✔
157
        (void)_sir_handleerr(errno);
×
158
        clearerr(sf->f);
×
159
    }
160

161
    return write == writeLen;
1,281,720✔
162
}
163

164
bool _sirfile_writeheader(sirfile* sf, const char* msg) {
34,696✔
165
    if (!_sirfile_validate(sf) || !_sir_validstr(msg))
34,696✔
166
        return false;
×
167

168
    time_t now = -1;
34,696✔
169
    time(&now);
34,696✔
170

171
    char timestamp[SIR_MAXTIME] = {0};
34,696✔
172
    bool fmttime = _sir_formattime(now, timestamp, SIR_FHTIMEFORMAT);
34,696✔
173
    if (!fmttime)
34,696✔
174
        return false;
2,069✔
175

176
    char header[SIR_MAXFHEADER] = {0};
32,627✔
177
    (void)snprintf(header, SIR_MAXFHEADER, SIR_FHFORMAT, msg, timestamp);
26,551✔
178

179
    return _sirfile_write(sf, header);
32,627✔
180
}
181

182
bool _sirfile_needsroll(sirfile* sf) {
1,281,720✔
183
    if (!_sirfile_validate(sf))
1,281,720✔
184
        return false;
×
185

186
    struct stat st = {0};
1,281,720✔
187
    int getstat    = fstat(fileno(sf->f), &st);
1,281,720✔
188

189
    if (0 != getstat) { /* if fstat fails, try stat on the path. */
1,281,720✔
190
        getstat = stat(sf->path, &st);
17,542✔
191
        if (0 != getstat)
17,542✔
192
            return _sir_handleerr(errno);
×
193
    }
194

195
    return st.st_size + BUFSIZ >= SIR_FROLLSIZE ||
2,563,351✔
196
        SIR_FROLLSIZE - (st.st_size + BUFSIZ) <= BUFSIZ;
1,281,628✔
197
}
198

199
bool _sirfile_roll(sirfile* sf, char** newpath) {
110✔
200
    if (!_sirfile_validate(sf) || !_sir_validptrptr(newpath))
110✔
201
        return false;
×
202

203
    bool retval = false;
107✔
204
    char* name = NULL;
110✔
205
    char* ext  = NULL;
110✔
206

207
    bool split = _sirfile_splitpath(sf, &name, &ext);
110✔
208
    SIR_ASSERT(split);
109✔
209

210
    if (split) {
108✔
211
        time_t now = -1;
110✔
212

213
        time(&now);
110✔
214
        SIR_ASSERT(-1 != now);
109✔
215

216
        if (-1 != now) {
110✔
217
            char timestamp[SIR_MAXTIME] = {0};
34✔
218
            bool fmttime = _sir_formattime(now, timestamp, SIR_FNAMETIMEFORMAT);
34✔
219
            SIR_ASSERT(fmttime);
33✔
220

221
            if (fmttime) {
32✔
222
                *newpath = (char*)calloc(SIR_MAXPATH, sizeof(char));
34✔
223

224
                if (_sir_validptr(*newpath)) {
34✔
225
                    char seqbuf[7] = {0};
34✔
226
                    bool exists = false;
34✔
227
                    bool resolved = false;
31✔
228
                    uint16_t sequence = 0;
31✔
229

230
                    do {
231
                        (void)snprintf(*newpath, SIR_MAXPATH, SIR_FNAMEFORMAT, name,
58✔
232
                            timestamp, (sequence > 0 ? seqbuf : ""),
233
                            _sir_validstrnofail(ext) ? ext : "");
55✔
234

235
                        /* if less than one second has elapsed since the last roll
236
                         * operation, then we'll overwrite the last rolled log file,
237
                         * and that = data loss. make sure the target path does not
238
                         * already exist. */
239
                        if (!_sir_pathexists(*newpath, &exists, SIR_PATH_REL_TO_CWD)) {
55✔
240
                            /* failed to determine if the file already exists; it is better
241
                             * to continue logging to the same file than to possibly overwrite
242
                             * another (if it failed this time, it will again, so there's no
243
                             * way to definitively choose a good new path). */
244
                            break;
×
245
                        } else if (exists) {
55✔
246
                            /* the file already exists; add a number to the file name
247
                             * until one that does not exist is found. */
248
                            _sir_selflog("path: '%s' already exists; incrementing sequence", *newpath); //-V576
21✔
249
                            sequence++;
21✔
250
                        } else {
251
                            _sir_selflog("found good path: '%s'", *newpath);
33✔
252
                            resolved = true;
31✔
253
                            break;
31✔
254
                        }
255

256
                        if (sequence > 0)
21✔
257
                            (void)snprintf(seqbuf, 7, SIR_FNAMESEQFORMAT, sequence);
21✔
258

259
                    } while (sequence <= 999);
21✔
260

261
                    if (!resolved)
31✔
262
                        _sir_selflog("error: unable to determine suitable path for '%s';"
×
263
                                        " not rolling!", sf->path);
264

265
                    retval = resolved && _sirfile_archive(sf, *newpath);
34✔
266
                }
267
            }
268
        }
269
    }
270

271
    _sir_safefree(&name);
110✔
272
    _sir_safefree(&ext);
110✔
273

274
    return retval;
110✔
275

276
}
277

278
bool _sirfile_archive(sirfile* sf, const char* newpath) {
34✔
279
    if (!_sirfile_validate(sf) || !_sir_validstr(newpath))
34✔
280
        return false;
×
281

282
#if defined(__WIN__)
283
    /* apparently, need to close the old file first on windows. */
284
    _sirfile_close(sf);
285
#endif
286

287
    if (0 != rename(sf->path, newpath))
34✔
288
        return _sir_handleerr(errno);
×
289

290
    if (_sirfile_open(sf)) {
34✔
291
        _sir_selflog("archived '%s' " SIR_R_ARROW " '%s'", sf->path, newpath);
33✔
292
        return true;
33✔
293
    }
294

295
    return false;
×
296
}
297

298
bool _sirfile_splitpath(sirfile* sf, char** name, char** ext) {
110✔
299
    if (_sir_validptrptr(name))
110✔
300
        *name = NULL;
110✔
301
    if (_sir_validptrptr(ext))
110✔
302
        *ext = NULL;
110✔
303

304
    if (!_sirfile_validate(sf) || !_sir_validptrptr(name) || !_sir_validptrptr(ext))
110✔
305
        return false;
×
306

307
    char* tmp = strndup(sf->path, strnlen(sf->path, SIR_MAXPATH));
110✔
308
    if (!tmp)
110✔
309
        return _sir_handleerr(errno);
×
310

311
    char* lastfullstop = strrchr(tmp, '.');
110✔
312
    if (lastfullstop) {
110✔
313
        uintptr_t namesize = lastfullstop - tmp;
92✔
314
        SIR_ASSERT(namesize < SIR_MAXPATH);
91✔
315

316
        tmp[namesize] = '\0';
92✔
317
        *name = (char*)calloc(namesize + 1, sizeof(char));
92✔
318
        if (!*name) {
92✔
319
            _sir_safefree(&tmp);
×
320
            return _sir_handleerr(errno);
×
321
        }
322

323
        _sir_strncpy(*name, namesize + 1, tmp, namesize);
92✔
324
        *ext = strndup(sf->path + namesize, strnlen(sf->path + namesize, SIR_MAXPATH));
92✔
325
    } else {
326
        *name = strndup(sf->path, strnlen(sf->path, SIR_MAXPATH));
18✔
327
    }
328

329
    _sir_safefree(&tmp);
110✔
330
    return _sir_validstr(*name) && (!lastfullstop || _sir_validstr(*ext));
113✔
331
}
332

333
void _sirfile_destroy(sirfile** sf) {
34,746✔
334
    if (sf && *sf) {
34,746✔
335
        _sirfile_close(*sf);
34,746✔
336
        _sir_safefree(&(*sf)->path);
34,746✔
337
        _sir_safefree(sf);
34,746✔
338
    }
339
}
34,746✔
340

341
bool _sirfile_validate(sirfile* sf) {
4,027,505✔
342
    return _sir_validptrnofail(sf) && _sir_validptrnofail(sf->f) &&
12,082,257✔
343
           _sir_validstrnofail(sf->path) && _sir_validfileid(sf->id);
12,082,257✔
344
}
345

346
bool _sirfile_update(sirfile* sf, sir_update_config_data* data) {
34,176✔
347
    if (!_sirfile_validate(sf))
34,176✔
348
        return false;
×
349

350
    if (_sir_bittest(data->fields, SIRU_LEVELS)) {
34,176✔
351
        if (sf->levels != *data->levels) {
189✔
352
            _sir_selflog("updating file (id: %" PRIx32") levels from %04" PRIx16
177✔
353
                         " to %04" PRIx16, sf->id, sf->levels, *data->levels);
354
            sf->levels = *data->levels;
188✔
355
        } else {
356
            _sir_selflog("skipped superfluous update of file (id: %" PRIx32")"
1✔
357
                         " levels: %04" PRIx16, sf->id, sf->levels);
358
        }
359

360
        return true;
189✔
361
    }
362

363
    if (_sir_bittest(data->fields, SIRU_OPTIONS)) {
33,987✔
364
        if (sf->opts != *data->opts) {
33,987✔
365
            _sir_selflog("updating file (id: %" PRIx32") options from %08" PRIx32
16,221✔
366
                         " to %08" PRIx32, sf->id, sf->opts, *data->opts);
367
            sf->opts = *data->opts;
17,259✔
368
        } else {
369
            _sir_selflog("skipped superfluous update of file (id: %" PRIx32")"
15,753✔
370
                         " options: %08" PRIx32, sf->id, sf->opts);
371
        }
372

373
        return true;
33,987✔
374
    }
375

376
    return false;
×
377
}
378

379
sirfileid _sir_fcache_add(sirfcache* sfc, const char* path, sir_levels levels,
34,901✔
380
    sir_options opts) {
381
    if (!_sir_validptr(sfc) || !_sir_validstr(path) || !_sir_validlevels(levels) ||
40,995✔
382
        !_sir_validopts(opts))
34,880✔
383
        return 0;
21✔
384

385
    if (sfc->count >= SIR_MAXFILES)
34,880✔
386
        return _sir_seterror(_SIR_E_NOROOM);
18✔
387

388
    sirfile* existing = _sir_fcache_find(sfc, (const void*)path, _sir_fcache_pred_path);
34,862✔
389
    if (NULL != existing) {
34,862✔
390
        _sir_selflog("error: already have file (path: '%s', id: %" PRIx32")",
51✔
391
            path, existing->id);
392
        return _sir_seterror(_SIR_E_DUPITEM);
54✔
393
    }
394

395
    sirfile* sf = _sirfile_create(path, levels, opts);
34,808✔
396
    if (_sirfile_validate(sf)) {
34,808✔
397
        _sir_selflog("adding file (path: '%s', id: %" PRIx32"); count = %zu", //-V522
34,679✔
398
            sf->path, sf->id, sfc->count + 1);
399

400
        sfc->files[sfc->count++] = sf;
34,679✔
401

402
        if (!_sir_bittest(sf->opts, SIRO_NOHDR)) //-V522
34,679✔
403
            _sirfile_writeheader(sf, SIR_FHBEGIN);
34,662✔
404

405
        return sf->id;
34,679✔
406
    }
407

408
    _sir_safefree(&sf);
129✔
409

410
    return 0;
129✔
411
}
412

413
bool _sir_fcache_update(sirfcache* sfc, sirfileid id, sir_update_config_data* data) {
34,176✔
414
    if (!_sir_validptr(sfc) || !_sir_validfileid(id) || !_sir_validupdatedata(data))
34,176✔
415
        return false;
×
416

417
    sirfile* found = _sir_fcache_find(sfc, (const void*)&id, _sir_fcache_pred_id);
34,176✔
418
    return found ? _sirfile_update(found, data) : _sir_seterror(_SIR_E_NOITEM);
34,176✔
419
}
420

421
bool _sir_fcache_rem(sirfcache* sfc, sirfileid id) {
34,664✔
422
    if (!_sir_validptr(sfc) || !_sir_validfileid(id))
34,664✔
423
        return false;
×
424

425
    for (size_t n = 0; n < sfc->count; n++) {
94,573✔
426
        SIR_ASSERT(_sirfile_validate(sfc->files[n]));
89,596✔
427

428
        if (sfc->files[n]->id == id) {
94,552✔
429
            _sir_selflog("removing file (path: '%s', id: %" PRIx32"); count = %zu",
32,621✔
430
                sfc->files[n]->path, sfc->files[n]->id, sfc->count - 1);
431

432
            _sirfile_destroy(&sfc->files[n]);
34,643✔
433

434
            for (size_t i = n; i < sfc->count - 1; i++) {
65,611✔
435
                sfc->files[i] = sfc->files[i + 1];
30,968✔
436
                sfc->files[i + 1] = NULL;
30,968✔
437
            }
438

439
            sfc->count--;
34,643✔
440
            return true;
34,643✔
441
        }
442
    }
443

444
    return _sir_seterror(_SIR_E_NOITEM);
21✔
445
}
446

447
bool _sir_fcache_pred_path(const void* match, sirfile* iter) {
90,967✔
448
    const char* path = (const char*)match;
74,796✔
449
    bool equal       = false;
74,796✔
450

451
    _sir_selflog("comparing '%s' == '%s'", path, iter->path);
85,296✔
452

453
#if !defined(__WIN__)
454
    /* if we're able to stat both files then we can use that information for the
455
     * comparison. otherwise, fall back on comparing the canonical path strings
456
     * returned by realpath. */
457
    char resolved1[SIR_MAXPATH] = {0}, resolved2[SIR_MAXPATH] = {0};
90,967✔
458
    struct stat st1 = {0}, st2  = {0};
90,967✔
459

460
    char* real1 = realpath(path, resolved1);
74,796✔
461
    char* real2 = realpath(iter->path, resolved2);
90,967✔
462

463
    SIR_UNUSED(real1);
464
    SIR_UNUSED(real2);
465

466
    if ((!stat(resolved1, &st1) && !stat(resolved2, &st2)) ||
98,816✔
467
        (!stat(path, &st1) && !stat(iter->path, &st2))) {
7,849✔
468
        equal = st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
83,118✔
469
        _sir_selflog("returning %d for '%s' == '%s'", equal, path, iter->path);
83,118✔
470
    } else {
471
        _sir_selflog("falling back to canonical path string compare");
7,720✔
472
        equal = 0 == strncmp(resolved1, resolved2, SIR_MAXPATH);
7,849✔
473
        _sir_selflog("returning %d for '%s' == '%s'", equal, resolved1, resolved2);
7,720✔
474
    }
475

476
    return equal;
90,967✔
477
#else /* __WIN__ */
478
    /* open both files (only if they already exist) and compare their
479
     * filesystem info. failing that, fall back on conversion to canonical path
480
     * and string comparison. */
481
    DWORD sh_flags   = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
482
    DWORD open_type  = OPEN_EXISTING;
483
    DWORD attr_flags = FILE_ATTRIBUTE_NORMAL;
484
    BY_HANDLE_FILE_INFORMATION fi1 = {0}, fi2 = {0};
485

486
    HANDLE h1 = CreateFileA(path, 0, sh_flags, NULL, open_type, attr_flags, NULL);
487
    HANDLE h2 = CreateFileA(iter->path,0, sh_flags, NULL, open_type, attr_flags, NULL);
488

489
    if (INVALID_HANDLE_VALUE != h1 && INVALID_HANDLE_VALUE != h2 &&
490
        GetFileInformationByHandle(h1, &fi1) && GetFileInformationByHandle(h2, &fi2)) {
491
        equal = fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
492
                fi1.nFileIndexLow        == fi2.nFileIndexLow        &&
493
                fi1.nFileIndexHigh       == fi2.nFileIndexHigh;
494
        _sir_selflog("returning %d for '%s' == '%s'", equal, path, iter->path);
495
    } else {
496
        _sir_selflog("falling back to canonical path string compare");
497
        char resolved1[SIR_MAXPATH] = {0}, resolved2[SIR_MAXPATH] = {0};
498
        if (GetFullPathNameA(path, SIR_MAXPATH, resolved1, NULL) &&
499
            GetFullPathNameA(iter->path, SIR_MAXPATH, resolved2, NULL))
500
            equal = 0 == StrCmpIA(resolved1, resolved2);
501
        _sir_selflog("returning %d for '%s' == '%s'", equal, resolved1, resolved2);
502
    }
503

504
    if (INVALID_HANDLE_VALUE != h1)
505
        CloseHandle(h1);
506

507
    if (INVALID_HANDLE_VALUE != h2)
508
        CloseHandle(h2);
509

510
    return equal;
511
#endif
512
}
513

514
bool _sir_fcache_pred_id(const void* match, sirfile* iter) {
87,447✔
515
    sirfileid* id = (sirfileid*)match;
72,183✔
516
    return iter->id == *id;
87,447✔
517
}
518

519
sirfile* _sir_fcache_find(sirfcache* sfc, const void* match, sir_fcache_pred pred) {
69,038✔
520
    if (!_sir_validptr(sfc) || !_sir_validptr(match) || !_sir_validfnptr(pred))
69,038✔
521
        return NULL;
×
522

523
    for (size_t n = 0; n < sfc->count; n++) {
213,222✔
524
        if (pred(match, sfc->files[n]))
178,414✔
525
            return sfc->files[n];
34,230✔
526
    }
527

528
    return NULL;
28,726✔
529
}
530

531
bool _sir_fcache_destroy(sirfcache* sfc) {
680✔
532
    if (!_sir_validptr(sfc))
680✔
533
        return false;
×
534

535
    while (sfc->count > 0) {
716✔
536
        size_t idx = sfc->count - 1;
36✔
537
        SIR_ASSERT(_sirfile_validate(sfc->files[idx]));
34✔
538
        _sirfile_destroy(&sfc->files[idx]);
36✔
539
        sfc->files[idx] = NULL;
36✔
540
        sfc->count--;
36✔
541
    }
542

543
    memset(sfc, 0, sizeof(sirfcache));
581✔
544
    return true;
680✔
545
}
546

547
bool _sir_fcache_dispatch(sirfcache* sfc, sir_level level, sirbuf* buf,
2,119,314✔
548
    size_t* dispatched, size_t* wanted) {
549
    if (!_sir_validptr(sfc) || !_sir_validlevel(level) || !_sir_validptr(buf) ||
2,138,813✔
550
        !_sir_validptr(dispatched) || !_sir_validptr(wanted))
2,138,813✔
551
        return false;
×
552

553
    const char* write    = NULL;
2,099,815✔
554
    sir_options lastopts = 0;
2,099,815✔
555

556
    *dispatched = 0;
2,119,314✔
557
    *wanted     = 0;
2,119,314✔
558

559
    for (size_t n = 0; n < sfc->count; n++) {
3,370,580✔
560
        SIR_ASSERT(_sirfile_validate(sfc->files[n]));
1,235,822✔
561

562
        if (!_sir_bittest(sfc->files[n]->levels, level)) {
1,251,266✔
563
            _sir_selflog("level %04" PRIx32" not set in level mask (%04" PRIx16
2,044✔
564
                         ") for file (path: '%s', id: %" PRIx32"); skipping",
565
                         level, sfc->files[n]->levels, sfc->files[n]->path,
566
                         sfc->files[n]->id);
567
            continue;
2,173✔
568
        }
569

570
        (*wanted)++;
1,249,093✔
571

572
        if (!write || sfc->files[n]->opts != lastopts) {
1,249,093✔
573
            write = _sir_format(false, sfc->files[n]->opts, buf);
1,145,195✔
574
            SIR_ASSERT(write);
1,136,581✔
575
            lastopts = sfc->files[n]->opts;
1,145,195✔
576
        }
577

578
        if (write && _sirfile_write(sfc->files[n], write)) {
1,249,093✔
579
            (*dispatched)++;
1,249,093✔
580
        } else {
581
            _sir_selflog("error: write to file (path: '%s', id: %" PRIx32") failed!",
×
582
                sfc->files[n]->path, sfc->files[n]->id);
583
        }
584
    }
585

586
    return (*dispatched == *wanted);
2,119,314✔
587
}
588

589
void _sir_fflush(FILE* f) {
110✔
590
    if (_sir_validptr(f)) {
110✔
591
        if (0 != fflush(f))
110✔
592
            (void)_sir_handleerr(errno);
×
593
    }
594
}
110✔
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

© 2025 Coveralls, Inc