Coverage Report

Created: 2025-06-15 00:57

/src/cmp_tool/lib/common/cmp_error.h
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file   cmp_error.h
3
 * @author Dominik Loidolt (dominik.loidolt@univie.ac.at)
4
 * @date   2024
5
 *
6
 * @copyright GPLv2
7
 * This program is free software; you can redistribute it and/or modify it
8
 * under the terms and conditions of the GNU General Public License,
9
 * version 2, as published by the Free Software Foundation.
10
 *
11
 * This program is distributed in the hope it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14
 * more details.
15
 *
16
 * @brief collection of macros to handling errors
17
 * This is heavy inspired by the error handling of zstd (lib/common/error_private.h) by
18
 * @author Yann Collet et al.
19
 * https://github.com/facebook/zstd/blob/dev/
20
 */
21
22
#ifndef CMP_ERROR_H
23
#define CMP_ERROR_H
24
25
26
#include <stdint.h>
27
28
29
/**
30
 * @brief add the CMP_ERROR prefix to the error name
31
 *
32
 * @param name the name to concatenate with cmp error prefix
33
 */
34
35
445k
#define PREFIX_CMP_ERRROR(name) CMP_ERROR_##name
36
37
38
/**
39
 * @brief generate a return value of a error
40
 *
41
 * @param name   error name without CMP_ERROR prefix to create an error code for
42
 */
43
44
445k
#define CMP_ERROR(name) ((uint32_t)-PREFIX_CMP_ERRROR(name))
45
46
47
/**
48
 * @brief ignore this is an internal helper
49
 *
50
 * this is a helper function to help force c99-correctness during compilation
51
 * under strict compilation modes variadic macro arguments can't be empty
52
 * however variadic function arguments can be using a function therefore lets
53
 * us statically check that at least one string argument was passed
54
 * independent of the compilation flags
55
 */
56
57
0
static __inline void _force_has_format_string(const char *format, ...) {
58
0
  (void)format;
59
0
}
Unexecuted instantiation: cmp_error.c:_force_has_format_string
Unexecuted instantiation: cmp_icu.c:_force_has_format_string
60
61
62
/**
63
 * @brief ignore this is an internal helper
64
 *
65
 * we want to force this function invocation to be syntactically correct but
66
 * we don't want to force runtime evaluation of its arguments
67
 */
68
69
__extension__
70
#define _FORCE_HAS_FORMAT_STRING(...)       \
71
1.38k
  do {             \
72
1.38k
    if (0) {         \
73
0
      _force_has_format_string(__VA_ARGS__);  \
74
0
    }            \
75
1.38k
  } while (0)
76
77
#define ERR_QUOTE(str) #str
78
79
80
/**
81
 * @brief return the specified error if the condition evaluates to true
82
 *
83
 * @param cond   the condition to evaluate
84
 * @param err the error to return if the condition is true
85
 * @param ...  additional arguments for error logging
86
 *
87
 * in debug modes (DEBUGLEVEL>=3) prints additional information
88
 */
89
90
__extension__
91
#define RETURN_ERROR_IF(cond, err, ...)               \
92
656k
  do {                     \
93
923k
    if (cond) {                 \
94
832
      debug_print_level(3, "%s:%d: Error: check %s failed, returning %s",  \
95
832
            __FILE__, __LINE__, ERR_QUOTE(cond),      \
96
832
            ERR_QUOTE(CMP_ERROR(err)));       \
97
832
      _FORCE_HAS_FORMAT_STRING(__VA_ARGS__);          \
98
832
      debug_print_level(3, "-> " __VA_ARGS__);       \
99
832
      return CMP_ERROR(err);              \
100
832
    }                    \
101
656k
  } while (0)
102
103
104
/**
105
 * @brief unconditionally return the specified error
106
 *
107
 * @param err the error to return unconditionally
108
 * @param ... additional arguments for error logging
109
 *
110
 * in debug modes (DEBUGLEVEL>=3) prints additional information
111
 */
112
113
__extension__
114
#define RETURN_ERROR(err, ...)                  \
115
0
  do {                     \
116
0
    debug_print_level(3, "%s:%d: Error: unconditional check failed, returning %s", \
117
0
          __FILE__, __LINE__, ERR_QUOTE(ERROR(err)));     \
118
0
    _FORCE_HAS_FORMAT_STRING(__VA_ARGS__);            \
119
0
    debug_print_level(3, "-> " __VA_ARGS__);         \
120
0
    return CMP_ERROR(err);                \
121
0
  } while(0)
122
123
124
/**
125
 * @brief if the provided expression evaluates to an error code returns that error code
126
 *
127
 * @param err the error expression to evaluate
128
 * @param ... additional arguments for error logging
129
 *
130
 * in debug modes (DEBUGLEVEL>=3) prints additional information
131
 */
132
133
__extension__
134
#define FORWARD_IF_ERROR(err, ...)              \
135
128k
  do {                   \
136
128k
    uint32_t const err_code = (err);          \
137
128k
    if (cmp_is_error(err_code)) {           \
138
556
      debug_print_level(3, "%s:%d: Error: forwarding error in %s: %s",\
139
556
            __FILE__, __LINE__, ERR_QUOTE(err),   \
140
556
            cmp_get_error_name(err_code));    \
141
556
      _FORCE_HAS_FORMAT_STRING(__VA_ARGS__);        \
142
556
      debug_print_level(3, "--> " __VA_ARGS__);      \
143
556
      return err_code;            \
144
556
    }                  \
145
128k
  } while(0)
146
147
148
#endif /* CMP_ERROR_H */