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

aremmell / libsir / 429

04 Sep 2023 10:54PM UTC coverage: 94.551% (-0.3%) from 94.865%
429

Pull #257

gitlab-ci

aremmell
no _sir_getthreadname for __ORANGEC__
Pull Request #257: WIP

239 of 239 new or added lines in 12 files covered. (100.0%)

3019 of 3193 relevant lines covered (94.55%)

628119.79 hits per line

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

91.67
/include/sir/helpers.h
1
/*
2
 * helpers.h
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
#ifndef _SIR_HELPERS_H_INCLUDED
27
# define _SIR_HELPERS_H_INCLUDED
28

29
# include "sir/types.h"
30
# include "sir/errors.h"
31

32
/** Computes the size of an array. */
33
# define _sir_countof(arr) (sizeof(arr) / sizeof(arr[0]))
34

35
/** Evil macro used for _sir_lv wrappers. */
36
# define _SIR_L_START(format) \
37
    bool ret = false; \
38
    va_list args; \
39
    do { \
40
        if (!_sir_validptr(format)) \
41
            return false; \
42
        va_start(args, format); \
43
    } while (false)
44

45
/** Evil macro used for _sir_lv wrappers. */
46
# define _SIR_L_END() \
47
    va_end(args)
48

49
/** Evil macros used to enter/leave locked sections. */
50
# define _SIR_LOCK_SECTION(type, name, mid, ret) \
51
    type* name = _sir_locksection(mid); \
52
    do { \
53
        if (!name) { \
54
            (void)_sir_seterror(_SIR_E_INTERNAL); \
55
            return ret; \
56
        } \
57
    } while (false)
58

59
/** Evil macros used to enter/leave locked sections. */
60
# define _SIR_UNLOCK_SECTION(mid) \
61
    _sir_unlocksection(mid)
62

63
/** Squelches warnings about unreferenced parameters. */
64
# define SIR_UNUSED(param) (void)param
65

66
/** Combines SIR_ASSERT and SIR_UNUSED, which are frequently used together. */
67
# define SIR_ASSERT_UNUSED(assertion, var) SIR_ASSERT(assertion); SIR_UNUSED(var)
68

69
/** Returns a printable string even if NULL. */
70
# define _SIR_PRNSTR(str) (str ? str : "<null>")
71

72
/** Even more evil macros used for binary searching arrays. */
73
# define _SIR_DECLARE_BIN_SEARCH(low, high) \
74
    size_t _low = low, _high = high; \
75
    size_t _mid = (_low + _high) / 2
76

77
# define _SIR_BEGIN_BIN_SEARCH() do {
78

79
# define _SIR_ITERATE_BIN_SEARCH(comparison) \
80
    if (_low == _high) \
81
        break; \
82
    if (0 > comparison && (_mid - 1) >= _low) { \
83
        _high = _mid - 1; \
84
    } else if ((_mid + 1) <= _high) { \
85
        _low = _mid + 1; \
86
    } else { \
87
        break; \
88
    } \
89
    _mid = (_low + _high) / 2
90

91
# define _SIR_END_BIN_SEARCH() \
92
    } while (true)
93

94
/* Validates a pointer and optionally fails if it's invalid. */
95
static inline
96
bool __sir_validptr(const void* restrict p, bool fail) {
82,278,511✔
97
    bool valid = NULL != p;
82,278,511✔
98
    if (fail && !valid) {
82,278,511✔
99
        (void)_sir_seterror(_SIR_E_NULLPTR);
154✔
100
        SIR_ASSERT(!valid && fail);
133✔
101
    }
102
    return valid;
82,279,075✔
103
}
104

105
/** Validates a pointer-to-pointer and optionally fails if it's invalid. */
106
static inline
107
bool __sir_validptrptr(const void* restrict* pp, bool fail) {
245,885✔
108
    bool valid = NULL != pp;
245,885✔
109
    if (fail && !valid) {
245,885✔
110
        (void)_sir_seterror(_SIR_E_NULLPTR);
×
111
        SIR_ASSERT(!valid && fail);
×
112
    }
113
    return valid;
245,885✔
114
}
115

116
/** Validates a pointer but ignores whether it's invalid. */
117
# define _sir_validptrnofail(p) __sir_validptr(p, false)
118

119
/** Validates a pointer and fails if it's invalid. */
120
# define _sir_validptr(p) __sir_validptr((const void* restrict)p, true)
121

122
/** Validates a pointer-to-function and fails if it's invalid. */
123
# define _sir_validfnptr(fnp) __sir_validptrptr((const void* restrict*)&fnp, true)
124

125
/** Validates a pointer-to-pointer and fails if it's invalid. */
126
# define _sir_validptrptr(pp) __sir_validptrptr((const void* restrict*)pp, true)
127

128
/** Checks a bitmask for a specific set of bits. */
129
static inline
130
bool _sir_bittest(uint32_t flags, uint32_t test) {
24,173,815✔
131
    return (flags & test) == test;
24,173,815✔
132
}
133

134
/** Sets a specific set of bits high in a bitmask. */
135
static inline
136
bool _sir_setbitshigh(uint32_t* flags, uint32_t set) {
582✔
137
    if (!flags)
582✔
138
        return false;
×
139

140
    *flags |= set;
582✔
141
    return true;
582✔
142
}
143

144
/** Sets a specific set of bits low in a bitmask. */
145
static inline
146
bool _sir_setbitslow(uint32_t* flags, uint32_t set) {
356✔
147
    if (!flags)
356✔
148
        return false;
×
149

150
    *flags &= ~set;
356✔
151
    return true;
356✔
152
}
153

154
/** Calls free and sets the pointer to NULL. */
155
void __sir_safefree(void** pp);
156

157
/** Wraps __sir_safefree with a cast to void**. */
158
# define _sir_safefree(pp) __sir_safefree((void**)pp)
159

160
/** Calls close and sets the descriptor to -1. */
161
void _sir_safeclose(int* restrict fd);
162

163
/** Calls fclose and sets the stream pointer to NULL. */
164
void _sir_safefclose(FILE* restrict* restrict f);
165

166
/** Validates a log file descriptor. */
167
bool _sir_validfd(int fd);
168

169
/** Validates a file identifier */
170
static inline
171
bool _sir_validfileid(sirfileid id) {
4,228,438✔
172
    return 0U != id;
4,228,438✔
173
}
174

175
/** Validates a plugin identifier */
176
static inline
177
bool _sir_validpluginid(sirpluginid id) {
178
    return 0U != id;
179
}
180

181
/** Validates a sir_update_config_data structure. */
182
bool _sir_validupdatedata(sir_update_config_data* data);
183

184
/** Validates a set of ::sir_level flags. */
185
bool _sir_validlevels(sir_levels levels);
186

187
/** Validates a single ::sir_level. */
188
bool _sir_validlevel(sir_level level);
189

190
/** Applies default ::sir_level flags if applicable. */
191
static inline
192
void _sir_defaultlevels(sir_levels* levels, sir_levels def) {
38,175✔
193
    if (levels && SIRL_DEFAULT == *levels)
38,175✔
194
        *levels = def;
626✔
195
}
38,175✔
196

197
/** Applies default ::sir_options flags if applicable. */
198
static inline
199
void _sir_defaultopts(sir_options* opts, sir_options def) {
139,774✔
200
    if (opts && SIRO_DEFAULT == *opts)
139,774✔
201
        *opts = def;
1,924✔
202
}
139,774✔
203

204
/** Validates a set of ::sir_option flags. */
205
bool _sir_validopts(sir_options opts);
206

207
/** Validates a ::sir_textattr. */
208
bool _sir_validtextattr(sir_textattr attr);
209

210
/** Validates a ::sir_textcolor based on color mode. */
211
bool _sir_validtextcolor(sir_colormode mode, sir_textcolor color);
212

213
/** Validates a ::sir_colormode. */
214
bool _sir_validcolormode(sir_colormode mode);
215

216
/** Converts a SIRTC_* value to a 16-color mode ANSI foreground color. */
217
static inline
218
sir_textcolor _sir_mkansifgcolor(sir_textcolor fg) {
296,354✔
219
    return SIRTC_DEFAULT == fg ? 39 : fg < 8 ? fg + 30 : fg + 82;
296,354✔
220
}
221

222
/** Converts a SIRTC_* value to a 16-color mode ANSI background color. */
223
static inline
224
sir_textcolor _sir_mkansibgcolor(sir_textcolor bg) {
296,354✔
225
    return SIRTC_DEFAULT == bg ? 49 : bg < 8 ? bg + 40 : bg + 92;
296,354✔
226
}
227

228
/** Returns the appropriate ANSI command for the specified foreground color. */
229
static inline
230
sir_textcolor _sir_getansifgcmd(sir_textcolor fg) {
11,616✔
231
    return SIRTC_DEFAULT == fg ? 39 : 38;
11,616✔
232
}
233

234
/** Returns the appropriate ANSI command for the specified background color. */
235
static inline
236
sir_textcolor _sir_getansibgcmd(sir_textcolor bg) {
11,616✔
237
    return SIRTC_DEFAULT == bg ? 49 : 48;
11,616✔
238
}
239

240
/** Extracts the red component out of an RGB color mode ::sir_textcolor. */
241
# define _sir_getredfromcolor(color) (uint8_t)(((color) >> 16) & 0x000000ffU)
242

243
/** Sets the red component in an RGB color mode ::sir_textcolor. */
244
# define _sir_setredincolor(color, red) (color |= (((red) << 16) & 0x00ff0000U))
245

246
/** Extracts the green component out of an RGB color mode ::sir_textcolor. */
247
# define _sir_getgreenfromcolor(color) (uint8_t)(((color) >> 8) & 0x000000ffU)
248

249
/** Sets the green component in an RGB color mode ::sir_textcolor. */
250
# define _sir_setgreenincolor(color, green) ((color) |= (((green) << 8) & 0x0000ff00U))
251

252
/** Extracts the blue component out of an RGB color mode ::sir_textcolor. */
253
# define _sir_getbluefromcolor(color) (uint8_t)((color) & 0x000000ffU)
254

255
/** Sets the blue component in an RGB color mode ::sir_textcolor. */
256
# define _sir_setblueincolor(color, blue) ((color) |= ((blue) & 0x000000ffU))
257

258
/** Sets the red, blue, and green components in an RGB color mode ::sir_textcolor. */
259
static inline
260
sir_textcolor _sir_makergb(sir_textcolor r, sir_textcolor g, sir_textcolor b) {
11,308✔
261
    sir_textcolor retval = 0;
9,766✔
262
    _sir_setredincolor(retval, r);
11,308✔
263
    _sir_setgreenincolor(retval, g);
11,308✔
264
    _sir_setblueincolor(retval, b);
11,308✔
265
    return retval;
11,308✔
266
}
267

268
/** Validates a string pointer and optionally fails if it's invalid. */
269
static inline
270
bool __sir_validstr(const char* restrict str, bool fail) {
51,502,442✔
271
    bool valid = str && *str != '\0';
51,502,442✔
272
    if (fail && !valid) {
51,502,442✔
273
        (void)_sir_seterror(_SIR_E_STRING);
8,021✔
274
        SIR_ASSERT(!valid && fail);
7,996✔
275
    }
276
    return valid;
51,502,323✔
277
}
278

279
/** Validates a string pointer and fails if it's invalid. */
280
# define _sir_validstr(str) __sir_validstr(str, true)
281

282
/** Validates a string pointer but ignores whether it's invalid. */
283
# define _sir_validstrnofail(str) __sir_validstr(str, false)
284

285
/** Places a null terminator at the first index in a string buffer. */
286
static inline
287
void _sir_resetstr(char* str) {
2,686,018✔
288
    if (NULL != str)
2,686,018✔
289
        *str = '\0';
2,686,018✔
290
}
2,686,018✔
291

292
/**
293
 * Wrapper for strncmp. Just easier to read and use if you only wish to
294
 * test for equality. Not case-sensitive.
295
 */
296
static inline
297
bool _sir_strsame(const char* lhs, const char* rhs, size_t count) {
84✔
298
    return 0 == strncmp(lhs, rhs, count);
84✔
299
}
300

301
/**
302
 * Wrapper for str[n,l]cpy/strncpy_s. Determines which one to use
303
 * based on preprocessor macros.
304
 */
305
int _sir_strncpy(char* restrict dest, size_t destsz,
306
    const char* restrict src, size_t count);
307

308
/**
309
 * Wrapper for str[n,l]cat/strncat_s. Determines which one to use
310
 * based on preprocessor macros.
311
 */
312
int _sir_strncat(char* restrict dest, size_t destsz,
313
    const char* restrict src, size_t count);
314

315
/**
316
 * Wrapper for fopen/fopen_s. Determines which one to use
317
 * based on preprocessor macros.
318
 */
319
int _sir_fopen(FILE* restrict* restrict streamptr, const char* restrict filename,
320
    const char* restrict mode);
321

322
/**
323
 * Wrapper for localtime[_s,_r]. Determines which one to use
324
 * based on preprocessor macros.
325
 */
326
static inline
327
struct tm* _sir_localtime(const time_t* timer, struct tm* buf) {
2,187,725✔
328
    if (!timer || !buf)
2,187,725✔
329
        return NULL;
×
330
# if defined(__HAVE_STDC_SECURE_OR_EXT1__) && !defined(__EMBARCADEROC__)
331
#  if !defined(__WIN__)
332
        struct tm* ret = localtime_s(timer, buf);
333
        if (!ret) {
334
            (void)_sir_handleerr(errno);
335
            return NULL;
336
        }
337
#  else /* __WIN__ */
338
        errno_t ret = localtime_s(buf, timer);
339
        if (0 != ret) {
340
            (void)_sir_handleerr(ret);
341
            return NULL;
342
        }
343
#  endif
344
        return buf;
345
# else /* !__HAVE_STDC_SECURE_OR_EXT1__ */
346
#  if !defined(__WIN__) || defined(__EMBARCADEROC__)
347
        struct tm* ret = localtime_r(timer, buf);
2,187,725✔
348
#  else
349
        struct tm* ret = localtime(timer);
350
#  endif
351
        if (!ret)
2,187,725✔
352
            (void)_sir_handleerr(errno);
×
353
        return ret;
2,157,849✔
354
# endif
355
}
356

357
/** Formats the current time as a string. */
358
# if defined(__GNUC__)
359
__attribute__ ((format (strftime, 3, 0)))
360
# endif
361
static inline
362
bool _sir_formattime(time_t now, char* buffer, const char* format) {
2,187,725✔
363
    if (!buffer || !format)
2,187,725✔
364
        return false;
×
365
# if defined(__GNUC__) && !defined(__clang__) && \
366
    !(defined(__OPEN64__) || defined(__OPENCC__))
367
#  pragma GCC diagnostic push
368
#  pragma GCC diagnostic ignored "-Wformat-nonliteral"
369
# endif
370
    struct tm timebuf;
371
    struct tm* ptb = _sir_localtime(&now, &timebuf);
2,187,725✔
372
    return NULL != ptb && 0 != strftime(buffer, SIR_MAXTIME, format, ptb);
2,187,725✔
373
# if defined(__GNUC__) && !defined(__clang__) && \
374
    !(defined(__OPEN64__) || defined(__OPENCC__))
375
#  pragma GCC diagnostic pop
376
# endif
377
}
378

379
/**
380
 * A portable "press any key to continue" implementation; On Windows, uses _getch().
381
 * otherwise, uses tcgetattr()/tcsetattr() and getchar().
382
 */
383
bool _sir_getchar(char* input);
384

385
/**
386
 * Wrapper for snprintf when truncation is intended.
387
 */
388
# define _sir_snprintf_trunc(dst, size, ...) \
389
    do { \
390
      volatile size_t _n = size; \
391
      if (!snprintf(dst, _n, __VA_ARGS__)) { (void)_n; }; \
392
    } while (false)
393

394
/**
395
 * Implementation of the 32-bit FNV-1a OWHF (http://isthe.com/chongo/tech/comp/fnv/)
396
 */
397
static inline
398
uint32_t FNV32_1a(const uint8_t* data, size_t len) {
34,944✔
399
    uint32_t hash = 2166136261U;
28,785✔
400
    for (size_t n = 0; n < len; n++) {
1,008,435✔
401
        hash ^= (uint32_t)data[n];
973,491✔
402
        hash = (uint32_t)(hash * 16777619ULL);
973,491✔
403
    }
404
    return hash;
34,944✔
405
}
406

407
/**
408
 * Implementation of the 64-bit FNV-1a OWHF (http://isthe.com/chongo/tech/comp/fnv/)
409
 * watered down to only handle null-terminated strings.
410
 */
411
# if defined(__clang__) /* only Clang has unsigned-integer-overflow; GCC BZ#96829 */
412
SANITIZE_SUPPRESS("unsigned-integer-overflow")
413
# endif
414
static inline
415
uint64_t FNV64_1a(const char* str) {
2,116,754✔
416
    uint64_t hash = 14695981039346656037ULL;
2,097,942✔
417
    for (const char* c = str; *c; c++) {
74,997,921✔
418
        hash ^= (uint64_t)(unsigned char)(*c);
72,881,167✔
419
        hash *= 1099511628211ULL; /* unsigned-integer-overflow */
72,881,167✔
420
    }
421
    return hash;
2,116,754✔
422
}
423

424
#endif /* !_SIR_HELPERS_H_INCLUDED */
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