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

biojppm / rapidyaml / 18162524607

01 Oct 2025 12:42PM UTC coverage: 97.638% (-0.01%) from 97.65%
18162524607

Pull #503

github

web-flow
Merge 4bf898896 into 653eac974
Pull Request #503: Improve error model, callbacks

1795 of 1842 new or added lines in 32 files covered. (97.45%)

38 existing lines in 4 files now uncovered.

13597 of 13926 relevant lines covered (97.64%)

534874.49 hits per line

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

99.27
/src/c4/yml/common.cpp
1
#include "c4/yml/common.hpp"
2
#include "c4/yml/error.hpp"
3
#include "c4/yml/error.def.hpp"
4

5
#ifndef RYML_NO_DEFAULT_CALLBACKS
6
#   include <stdlib.h>
7
#   include <stdio.h>
8
#endif // RYML_NO_DEFAULT_CALLBACKS
9
#ifdef _RYML_EXCEPTIONS
10
#       include <stdexcept>
11
#endif
12

13

14
namespace c4 {
15
namespace yml {
16

17
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
18
C4_SUPPRESS_WARNING_MSVC_WITH_PUSH(4702/*unreachable code*/) // on the call to the unreachable macro
19

20
namespace {
21
Callbacks s_default_callbacks;
22

23
#ifndef RYML_NO_DEFAULT_CALLBACKS
24

25
C4_NO_INLINE void dump2stderr(csubstr s)
931✔
26
{
27
    // using fwrite() is more portable than using fprintf("%.*s") which
28
    // is not available in some embedded platforms
29
    if(s.len)
931✔
30
        fwrite(s.str, 1, s.len, stderr); // NOLINT
931✔
31
}
931✔
32
C4_NO_INLINE void endmsg()
37✔
33
{
34
    fputc('\n', stderr); // NOLINT
37✔
35
    fflush(stderr); // NOLINT
37✔
36
}
37✔
37

38
[[noreturn]] C4_NO_INLINE void error_basic_impl(csubstr msg, ErrorDataBasic const& errdata, void * /*user_data*/)
9✔
39
{
40
    err_basic_format(dump2stderr, msg, errdata);
9✔
41
    endmsg();
9✔
42
    #ifdef _RYML_WITH_EXCEPTIONS
43
    throw ExceptionBasic(msg, errdata);
9✔
44
    #else
45
    abort(); // LCOV_EXCL_LINE
46
    #endif
47
}
48

49
[[noreturn]] C4_NO_INLINE void error_parse_impl(csubstr msg, ErrorDataParse const& errdata, void * /*user_data*/)
14✔
50
{
51
    err_parse_format(dump2stderr, msg, errdata);
14✔
52
    endmsg();
14✔
53
    #ifdef _RYML_WITH_EXCEPTIONS
54
    throw ExceptionParse(msg, errdata);
14✔
55
    #else
56
    abort(); // LCOV_EXCL_LINE
57
    #endif
58
}
59

60
[[noreturn]] C4_NO_INLINE void error_visit_impl(csubstr msg, ErrorDataVisit const& errdata, void * /*user_data*/)
14✔
61
{
62
    err_visit_format(dump2stderr, msg, errdata);
14✔
63
    endmsg();
14✔
64
    #ifdef _RYML_WITH_EXCEPTIONS
65
    throw ExceptionVisit(msg, errdata);
14✔
66
    #else
67
    abort(); // LCOV_EXCL_LINE
68
    #endif
69
}
70

71
void* allocate_impl(size_t length, void * /*hint*/, void * /*user_data*/)
1,776,878✔
72
{
73
    void *mem = ::malloc(length);
1,776,878✔
74
    if(mem == nullptr)
1,776,878✔
75
        error_basic_impl("could not allocate memory", ErrorDataBasic{RYML_LOC_HERE()}, nullptr); // LCOV_EXCL_LINE
76
    return mem;
1,776,878✔
77
}
78

79
void free_impl(void *mem, size_t /*length*/, void * /*user_data*/)
1,773,966✔
80
{
81
    ::free(mem);
1,773,966✔
82
}
1,773,966✔
83

84
#endif // RYML_NO_DEFAULT_CALLBACKS
85

86
} // anon namespace
87

88

89
void set_callbacks(Callbacks const& c)
75,600✔
90
{
91
    s_default_callbacks = c;
75,600✔
92
}
75,600✔
93

94
Callbacks const& get_callbacks()
5,998,134✔
95
{
96
    return s_default_callbacks;
5,998,134✔
97
}
98

99
void reset_callbacks()
408✔
100
{
101
    set_callbacks(Callbacks());
408✔
102
}
408✔
103

104

105
Callbacks::Callbacks() noexcept
101,508✔
106
    :
107
    m_user_data(nullptr),
101,508✔
108
    #ifndef RYML_NO_DEFAULT_CALLBACKS
109
    m_allocate(allocate_impl),
101,508✔
110
    m_free(free_impl),
101,508✔
111
    m_error_basic(error_basic_impl),
101,508✔
112
    m_error_parse(error_parse_impl),
101,508✔
113
    m_error_visit(error_visit_impl)
101,508✔
114
    #else
115
    m_allocate(nullptr),
116
    m_free(nullptr),
117
    m_error_basic(nullptr),
118
    m_error_parse(nullptr),
119
    m_error_visit(nullptr)
120
    #endif
121
{
122
}
101,508✔
123

124
Callbacks::Callbacks(void *user_data, pfn_allocate alloc_, pfn_free free_, pfn_error_basic error_basic_)
6✔
125
    :
126
    m_user_data(user_data),
6✔
127
    #ifndef RYML_NO_DEFAULT_CALLBACKS
128
    m_allocate(alloc_ ? alloc_ : allocate_impl),
6✔
129
    m_free(free_ ? free_ : free_impl),
6✔
130
    m_error_basic(error_basic_ ? error_basic_ : error_basic_impl),
6✔
131
    m_error_parse(error_parse_impl),
6✔
132
    m_error_visit(error_visit_impl)
6✔
133
    #else
134
    m_allocate(alloc_),
135
    m_free(free_),
136
    m_error_basic(error_),
137
    m_error_parse(nullptr),
138
    m_error_visit(nullptr),
139
    #endif
140
{
141
}
6✔
142

143

144
Callbacks& Callbacks::set_user_data(void* user_data)
65,610✔
145
{
146
    m_user_data = user_data;
65,610✔
147
    return *this;
65,610✔
148
}
149

150
Callbacks& Callbacks::set_allocate(pfn_allocate allocate)
462✔
151
{
152
    m_allocate = allocate;
462✔
153
    #ifndef RYML_NO_DEFAULT_CALLBACKS
154
    m_allocate = m_allocate ? m_allocate : allocate_impl;
462✔
155
    #endif
156
    return *this;
462✔
157
}
158

159
Callbacks& Callbacks::set_free(pfn_free free)
462✔
160
{
161
    m_free = free;
462✔
162
    #ifndef RYML_NO_DEFAULT_CALLBACKS
163
    m_free = m_free ? m_free : free_impl;
462✔
164
    #endif
165
    return *this;
462✔
166
}
167

168
Callbacks& Callbacks::set_error_basic(pfn_error_basic error_basic)
81,612✔
169
{
170
    m_error_basic = error_basic;
81,612✔
171
    #ifndef RYML_NO_DEFAULT_CALLBACKS
172
    m_error_basic = m_error_basic ? m_error_basic : error_basic_impl;
81,612✔
173
    #endif
174
    return *this;
81,612✔
175
}
176

177
Callbacks& Callbacks::set_error_parse(pfn_error_parse error_parse)
81,612✔
178
{
179
    m_error_parse = error_parse;
81,612✔
180
    #ifndef RYML_NO_DEFAULT_CALLBACKS
181
    m_error_parse = m_error_parse ? m_error_parse : error_parse_impl;
81,612✔
182
    #endif
183
    return *this;
81,612✔
184
}
185

186
Callbacks& Callbacks::set_error_visit(pfn_error_visit error_visit)
81,612✔
187
{
188
    m_error_visit = error_visit;
81,612✔
189
    #ifndef RYML_NO_DEFAULT_CALLBACKS
190
    m_error_visit = m_error_visit ? m_error_visit : error_visit_impl;
81,612✔
191
    #endif
192
    return *this;
81,612✔
193
}
194

195

196
C4_NORETURN C4_NO_INLINE void err_basic(ErrorDataBasic const& errdata, const char* msg)
1,565✔
197
{
198
    err_basic(get_callbacks(), errdata, msg);
1,565✔
199
    C4_UNREACHABLE_AFTER_ERR();
200
}
201
C4_NORETURN C4_NO_INLINE void err_basic(Callbacks const& callbacks, ErrorDataBasic const& errdata, const char* msg_)
2,705✔
202
{
203
    csubstr msg = to_csubstr(msg_);
1,791✔
204
    callbacks.m_error_basic(msg, errdata, callbacks.m_user_data);
2,705✔
205
    abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
206
    C4_UNREACHABLE_AFTER_ERR();
207
}
208

209

210
C4_NORETURN C4_NO_INLINE void err_parse(ErrorDataParse const& errdata, const char *msg)
64✔
211
{
212
    err_parse(get_callbacks(), errdata, msg);
64✔
213
    C4_UNREACHABLE_AFTER_ERR();
214
}
215
C4_NORETURN C4_NO_INLINE void err_parse(Callbacks const& callbacks, ErrorDataParse const& errdata, const char *msg_)
23,884✔
216
{
217
    csubstr msg = to_csubstr(msg_);
15,924✔
218
    if(callbacks.m_error_parse)
23,884✔
219
        callbacks.m_error_parse(msg, errdata, callbacks.m_user_data);
23,860✔
220
    // fall to basic error if there is no parse handler set
221
    else if(callbacks.m_error_basic)
24✔
222
        callbacks.m_error_basic(msg, errdata.ymlloc, callbacks.m_user_data);
24✔
223
    abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
224
    C4_UNREACHABLE_AFTER_ERR();
225
}
226

227

228
C4_NORETURN C4_NO_INLINE void err_visit(ErrorDataVisit const& errdata, const char *msg)
64✔
229
{
230
    err_visit(get_callbacks(), errdata, msg);
64✔
231
    C4_UNREACHABLE_AFTER_ERR();
232
}
233
C4_NORETURN C4_NO_INLINE void err_visit(Callbacks const& callbacks, ErrorDataVisit const& errdata, const char *msg_)
5,898✔
234
{
235
    csubstr msg = to_csubstr(msg_);
3,934✔
236
    if(callbacks.m_error_visit)
5,898✔
237
        callbacks.m_error_visit(msg, errdata, callbacks.m_user_data);
5,868✔
238
    // fall to basic error if there is no visit handler set
239
    else if(callbacks.m_error_basic)
30✔
240
        callbacks.m_error_basic(msg, errdata.cpploc, callbacks.m_user_data);
30✔
241
    abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
242
    C4_UNREACHABLE_AFTER_ERR();
243
}
244

245

246

247
#ifdef _RYML_WITH_EXCEPTIONS
248
ExceptionBasic::ExceptionBasic(csubstr msg_, ErrorDataBasic const& errdata_) noexcept
106✔
249
    : errdata_basic(errdata_)
106✔
250
    , msg()
108,650✔
251
{
252
    msg[0] = '\0';
106✔
253
    if(msg_.len)
106✔
254
    {
255
        if(msg_.len >= sizeof(msg))
106✔
256
        {
257
            static_assert(sizeof(msg) > 6u, "message buffer too small");
258
            msg_.len = sizeof(msg) - 6u;
3✔
259
            msg[msg_.len     ] = '[';
3✔
260
            msg[msg_.len + 1u] = '.';
3✔
261
            msg[msg_.len + 2u] = '.';
3✔
262
            msg[msg_.len + 3u] = '.';
3✔
263
            msg[msg_.len + 4u] = ']';
3✔
264
            msg[msg_.len + 5u] = '\0';
3✔
265
        }
266
        memcpy(msg, msg_.str, msg_.len);
106✔
267
    }
268
}
106✔
269
ExceptionParse::ExceptionParse(csubstr msg_, ErrorDataParse const& errdata_) noexcept
31✔
270
    : ExceptionBasic(msg_, {errdata_.ymlloc})
31✔
271
    , errdata_parse(errdata_)
31✔
272
{
273
}
31✔
274
ExceptionVisit::ExceptionVisit(csubstr msg_, ErrorDataVisit const& errdata_) noexcept
31✔
275
    : ExceptionBasic(msg_, {errdata_.cpploc})
31✔
276
    , errdata_visit(errdata_)
31✔
277
{
278
}
31✔
279
#endif // _RYML_WITH_EXCEPTIONS
280

281

282
namespace detail {
283
RYML_EXPORT csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
7,400✔
284
{
285
    if(pos > text.len)
7,400✔
286
        return text.last(0);
1,068✔
287
    size_t before = text.first(pos).last_of('\n');
6,332✔
288
    size_t before_count = 0;
6,332✔
289
    while((before != npos) && (++before_count <= num_lines_before))
9,754✔
290
    {
291
        if(before == 0)
3,422✔
NEW
292
            break;
×
293
        before = text.first(--before).last_of('\n');
6,844✔
294
    }
295
    if(before < text.len || before == npos)
6,332✔
296
        ++before;
6,332✔
297
    size_t after = text.first_of('\n', pos);
6,332✔
298
    size_t after_count = 0;
6,332✔
299
    while((after != npos) && (++after_count <= num_lines_after))
6,392✔
300
    {
301
        ++after;
96✔
302
        if(after >= text.len)
96✔
303
            break;
36✔
304
        after = text.first_of('\n', after);
60✔
305
    }
306
    return before <= after ? text.range(before, after) : text.first(0);
12,664✔
307
}
308
} // namespace detail
309

310
C4_SUPPRESS_WARNING_MSVC_POP
311
C4_SUPPRESS_WARNING_GCC_CLANG_POP
312

313
} // namespace yml
314
} // namespace c4
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