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

tstack / lnav / 11872214087-1756

16 Nov 2024 06:12PM UTC coverage: 70.243% (+0.5%) from 69.712%
11872214087-1756

push

github

tstack
[build] disable regex101

46266 of 65866 relevant lines covered (70.24%)

467515.63 hits per line

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

70.59
/src/md4cpp.cc
1
/**
2
 * Copyright (c) 2022, Timothy Stack
3
 *
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * * Redistributions of source code must retain the above copyright notice, this
10
 * list of conditions and the following disclaimer.
11
 * * Redistributions in binary form must reproduce the above copyright notice,
12
 * this list of conditions and the following disclaimer in the documentation
13
 * and/or other materials provided with the distribution.
14
 * * Neither the name of Timothy Stack nor the names of its contributors
15
 * may be used to endorse or promote products derived from this software
16
 * without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29

30
#include "md4cpp.hh"
31

32
#include "base/is_utf8.hh"
33
#include "base/lnav_log.hh"
34
#include "emojis-json.h"
35
#include "xml-entities-json.h"
36
#include "yajlpp/yajlpp_def.hh"
37

38
namespace md4cpp {
39

40
static const typed_json_path_container<xml_entity> xml_entity_handlers = {
41
    yajlpp::property_handler("characters").for_field(&xml_entity::xe_chars),
42
};
43

44
static const typed_json_path_container<xml_entity_map> xml_entity_map_handlers
45
    = {
46
        yajlpp::pattern_property_handler("(?<var_name>\\&\\w+;?)")
47
            .with_synopsis("<name>")
48
            .with_path_provider<xml_entity_map>(
49
                [](struct xml_entity_map* xem,
×
50
                   std::vector<std::string>& paths_out) {
51
                    for (const auto& iter : xem->xem_entities) {
×
52
                        paths_out.emplace_back(iter.first);
×
53
                    }
54
                })
×
55
            .with_obj_provider<xml_entity, xml_entity_map>(
56
                [](const yajlpp_provider_context& ypc, xml_entity_map* xem) {
348,036✔
57
                    auto entity_name = ypc.get_substr(0);
348,036✔
58
                    return &xem->xem_entities[entity_name];
696,072✔
59
                })
348,036✔
60
            .with_children(xml_entity_handlers),
61
};
62

63
static const typed_json_path_container<emoji> emoji_handlers = {
64
    yajlpp::property_handler("emoji").for_field(&emoji::e_value),
65
    yajlpp::property_handler("shortname").for_field(&emoji::e_shortname),
66
};
67

68
static const typed_json_path_container<emoji_map> emoji_map_handlers = {
69
    yajlpp::property_handler("emojis#")
70
        .for_field(&emoji_map::em_emojis)
71
        .with_children(emoji_handlers),
72
};
73

74
static xml_entity_map
75
load_xml_entity_map()
26✔
76
{
77
    static const intern_string_t name
78
        = intern_string::lookup(xml_entities_json.get_name());
26✔
79
    auto parse_res
80
        = xml_entity_map_handlers.parser_for(name).with_ignore_unused(true).of(
26✔
81
            xml_entities_json.to_string_fragment());
26✔
82

83
    assert(parse_res.isOk());
84

85
    return parse_res.unwrap();
52✔
86
}
26✔
87

88
const xml_entity_map&
89
get_xml_entity_map()
26✔
90
{
91
    static const auto retval = load_xml_entity_map();
26✔
92

93
    return retval;
26✔
94
}
95

96
static emoji_map
97
load_emoji_map()
29✔
98
{
99
    static const intern_string_t name
100
        = intern_string::lookup(emojis_json.get_name());
29✔
101
    auto parse_res
102
        = emoji_map_handlers.parser_for(name).with_ignore_unused(true).of(
29✔
103
            emojis_json.to_string_fragment());
29✔
104

105
    assert(parse_res.isOk());
106

107
    auto retval = parse_res.unwrap();
29✔
108
    for (auto& em : retval.em_emojis) {
116,957✔
109
        retval.em_shortname2emoji.emplace(em.e_shortname, em);
116,928✔
110
    }
111

112
    return retval;
58✔
113
}
29✔
114

115
const emoji_map&
116
get_emoji_map()
95✔
117
{
118
    static const auto retval = load_emoji_map();
95✔
119

120
    return retval;
95✔
121
}
122

123
std::string
124
escape_html(const std::string& content)
×
125
{
126
    std::string retval;
×
127

128
    retval.reserve(content.size());
×
129
    for (auto ch : content) {
×
130
        switch (ch) {
×
131
            case '"':
×
132
                retval.append("&quot;");
×
133
                break;
×
134
            case '\'':
×
135
                retval.append("&apos;");
×
136
                break;
×
137
            case '<':
×
138
                retval.append("&lt;");
×
139
                break;
×
140
            case '>':
×
141
                retval.append("&gt;");
×
142
                break;
×
143
            case '&':
×
144
                retval.append("&amp;");
×
145
                break;
×
146
            default:
×
147
                retval.push_back(ch);
×
148
                break;
×
149
        }
150
    }
151

152
    return retval;
×
153
}
×
154

155
struct parse_userdata {
156
    event_handler& pu_handler;
157
    std::string pu_error_msg;
158
};
159

160
static event_handler::block
161
build_block(MD_BLOCKTYPE type, void* detail)
6,974✔
162
{
163
    switch (type) {
6,974✔
164
        case MD_BLOCK_DOC:
134✔
165
            return event_handler::block_doc{};
134✔
166
        case MD_BLOCK_QUOTE:
30✔
167
            return event_handler::block_quote{};
30✔
168
        case MD_BLOCK_UL:
182✔
169
            return static_cast<MD_BLOCK_UL_DETAIL*>(detail);
182✔
170
        case MD_BLOCK_OL:
10✔
171
            return static_cast<MD_BLOCK_OL_DETAIL*>(detail);
10✔
172
        case MD_BLOCK_LI:
724✔
173
            return static_cast<MD_BLOCK_LI_DETAIL*>(detail);
724✔
174
        case MD_BLOCK_HR:
×
175
            return event_handler::block_hr{};
×
176
        case MD_BLOCK_H:
422✔
177
            return static_cast<MD_BLOCK_H_DETAIL*>(detail);
422✔
178
        case MD_BLOCK_CODE:
282✔
179
            return static_cast<MD_BLOCK_CODE_DETAIL*>(detail);
282✔
180
        case MD_BLOCK_HTML:
26✔
181
            return event_handler::block_html{};
26✔
182
        case MD_BLOCK_P:
1,204✔
183
            return event_handler::block_p{};
1,204✔
184
        case MD_BLOCK_TABLE:
140✔
185
            return static_cast<MD_BLOCK_TABLE_DETAIL*>(detail);
140✔
186
        case MD_BLOCK_THEAD:
140✔
187
            return event_handler::block_thead{};
140✔
188
        case MD_BLOCK_TBODY:
140✔
189
            return event_handler::block_tbody{};
140✔
190
        case MD_BLOCK_TR:
1,180✔
191
            return event_handler::block_tr{};
1,180✔
192
        case MD_BLOCK_TH:
280✔
193
            return event_handler::block_th{};
280✔
194
        case MD_BLOCK_TD:
2,080✔
195
            return static_cast<MD_BLOCK_TD_DETAIL*>(detail);
2,080✔
196
    }
197

198
    return {};
×
199
}
200

201
static event_handler::span
202
build_span(MD_SPANTYPE type, void* detail)
1,736✔
203
{
204
    switch (type) {
1,736✔
205
        case MD_SPAN_EM:
×
206
            return event_handler::span_em{};
×
207
        case MD_SPAN_STRONG:
180✔
208
            return event_handler::span_strong{};
180✔
209
        case MD_SPAN_A:
430✔
210
            return static_cast<MD_SPAN_A_DETAIL*>(detail);
430✔
211
        case MD_SPAN_IMG:
70✔
212
            return static_cast<MD_SPAN_IMG_DETAIL*>(detail);
70✔
213
        case MD_SPAN_CODE:
1,032✔
214
            return event_handler::span_code{};
1,032✔
215
        case MD_SPAN_DEL:
×
216
            return event_handler::span_del{};
×
217
        case MD_SPAN_U:
24✔
218
            return event_handler::span_u{};
24✔
219
        default:
×
220
            break;
×
221
    }
222

223
    return {};
×
224
}
225

226
static int
227
md4cpp_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata)
3,487✔
228
{
229
    auto* pu = static_cast<parse_userdata*>(userdata);
3,487✔
230

231
    auto enter_res = pu->pu_handler.enter_block(build_block(type, detail));
3,487✔
232
    if (enter_res.isErr()) {
3,487✔
233
        pu->pu_error_msg = enter_res.unwrapErr();
×
234
        return 1;
×
235
    }
236

237
    return 0;
3,487✔
238
}
3,487✔
239

240
static int
241
md4cpp_leave_block(MD_BLOCKTYPE type, void* detail, void* userdata)
3,487✔
242
{
243
    auto* pu = static_cast<parse_userdata*>(userdata);
3,487✔
244

245
    auto leave_res = pu->pu_handler.leave_block(build_block(type, detail));
3,487✔
246
    if (leave_res.isErr()) {
3,487✔
247
        pu->pu_error_msg = leave_res.unwrapErr();
×
248
        return 1;
×
249
    }
250

251
    return 0;
3,487✔
252
}
3,487✔
253

254
static int
255
md4cpp_enter_span(MD_SPANTYPE type, void* detail, void* userdata)
868✔
256
{
257
    auto* pu = static_cast<parse_userdata*>(userdata);
868✔
258

259
    auto enter_res = pu->pu_handler.enter_span(build_span(type, detail));
868✔
260
    if (enter_res.isErr()) {
868✔
261
        pu->pu_error_msg = enter_res.unwrapErr();
×
262
        return 1;
×
263
    }
264

265
    return 0;
868✔
266
}
868✔
267

268
static int
269
md4cpp_leave_span(MD_SPANTYPE type, void* detail, void* userdata)
868✔
270
{
271
    auto* pu = static_cast<parse_userdata*>(userdata);
868✔
272

273
    auto leave_res = pu->pu_handler.leave_span(build_span(type, detail));
868✔
274
    if (leave_res.isErr()) {
868✔
275
        pu->pu_error_msg = leave_res.unwrapErr();
×
276
        return 1;
×
277
    }
278

279
    return 0;
868✔
280
}
868✔
281

282
static int
283
md4cpp_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* userdata)
6,420✔
284
{
285
    auto* pu = static_cast<parse_userdata*>(userdata);
6,420✔
286
    auto text_res = pu->pu_handler.text(type, string_fragment(text, 0, size));
6,420✔
287
    if (text_res.isErr()) {
6,420✔
288
        pu->pu_error_msg = text_res.unwrapErr();
×
289
        return 1;
×
290
    }
291

292
    return 0;
6,420✔
293
}
6,420✔
294

295
namespace details {
296
Result<void, std::string>
297
parse(const string_fragment& sf, event_handler& eh)
69✔
298
{
299
    auto scan_res = is_utf8(sf);
69✔
300
    if (!scan_res.is_valid()) {
69✔
301
        return Err(
2✔
302
            fmt::format(FMT_STRING("file has invalid UTF-8 at offset {}: {}"),
10✔
303
                        scan_res.usr_valid_frag.sf_end,
2✔
304
                        scan_res.usr_message));
2✔
305
    }
306

2✔
307
    MD_PARSER parser = {0};
308
    auto pu = parse_userdata{eh};
309

67✔
310
    parser.abi_version = 0;
67✔
311
    parser.flags = (MD_DIALECT_GITHUB | MD_FLAG_UNDERLINE)
312
        & ~(MD_FLAG_PERMISSIVEAUTOLINKS);
67✔
313
    parser.enter_block = md4cpp_enter_block;
67✔
314
    parser.leave_block = md4cpp_leave_block;
315
    parser.enter_span = md4cpp_enter_span;
67✔
316
    parser.leave_span = md4cpp_leave_span;
67✔
317
    parser.text = md4cpp_text;
67✔
318

67✔
319
    auto rc = md_parse(sf.data(), sf.length(), &parser, &pu);
67✔
320

321
    if (rc == 0) {
67✔
322
        return Ok();
323
    }
67✔
324

67✔
325
    return Err(pu.pu_error_msg);
326
}
327
}  // namespace details
×
328

67✔
329
}  // namespace md4cpp
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