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

tstack / lnav / 17589970077-2502

09 Sep 2025 05:00PM UTC coverage: 65.196% (-5.0%) from 70.225%
17589970077-2502

push

github

tstack
[format] add fields for source file/line

Knowing the source file/line context in a log
message can help find log messages when using
log2src.

56 of 70 new or added lines in 2 files covered. (80.0%)

13954 existing lines in 210 files now uncovered.

45516 of 69814 relevant lines covered (65.2%)

404154.37 hits per line

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

63.53
/src/data_scanner.cc
1
/**
2
 * Copyright (c) 2007-2012, 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 <algorithm>
31

32
#include "data_scanner.hh"
33

34
#include "config.h"
35

36
void
37
data_scanner::capture_t::ltrim(const char* str)
×
38
{
39
    while (this->c_begin < this->c_end && isspace(str[this->c_begin])) {
×
40
        this->c_begin += 1;
×
41
    }
42
}
43

44
static struct {
45
    const char* name;
46
} MATCHERS[DT_TERMINAL_MAX] = {
47
    {
48
        "quot",
49
    },
50
    {
51
        "comm",
52
    },
53
    {
54
        "url",
55
    },
56
    {
57
        "path",
58
    },
59
    {
60
        "mac",
61
    },
62
    {
63
        "date",
64
    },
65
    {
66
        "time",
67
    },
68
    {
69
        "dt",
70
    },
71
    /* { "qual", pcrepp("\\A([^\\s:=]+:[^\\s:=,]+(?!,)(?::[^\\s:=,]+)*)"), }, */
72
    {
73
        "ipv6",
74
    },
75
    {
76
        "hexd",
77
    },
78

79
    {
80
        "xmld",
81
    },
82
    {
83
        "xmlt",
84
    },
85
    {
86
        "xmlo",
87
    },
88

89
    {
90
        "xmlc",
91
    },
92

93
    {
94
        "h1",
95
    },
96
    {
97
        "h2",
98
    },
99
    {
100
        "h3",
101
    },
102

103
    {
104
        "coln",
105
    },
106
    {
107
        "eq",
108
    },
109
    {
110
        "comm",
111
    },
112
    {
113
        "semi",
114
    },
115
    {
116
        "emda",
117
    },
118

119
    {
120
        "empt",
121
    },
122

123
    {
124
        "lcur",
125
    },
126
    {
127
        "rcur",
128
    },
129

130
    {
131
        "lsqu",
132
    },
133
    {
134
        "rsqu",
135
    },
136

137
    {
138
        "lpar",
139
    },
140
    {
141
        "rpar",
142
    },
143

144
    {
145
        "lang",
146
    },
147
    {
148
        "rang",
149
    },
150

151
    {
152
        "ipv4",
153
    },
154

155
    {
156
        "uuid",
157
    },
158

159
    {
160
        "cc",
161
    },
162
    {
163
        "vers",
164
    },
165
    {
166
        "oct",
167
    },
168
    {
169
        "pcnt",
170
    },
171
    {
172
        "num",
173
    },
174
    {
175
        "hex",
176
    },
177

178
    {
179
        "mail",
180
    },
181
    {
182
        "cnst",
183
    },
184
    {
185
        "word",
186
    },
187
    {
188
        "id",
189
    },
190
    {
191
        "sym",
192
    },
193
    {
194
        "unit",
195
    },
196
    {
197
        "line",
198
    },
199
    {
200
        "wspc",
201
    },
202
    {
203
        "dot",
204
    },
205
    {
206
        "escc",
207
    },
208
    {
209
        "csi",
210
    },
211

212
    {
213
        "gbg",
214
    },
215
    {
216
        "zwsp",
217
    },
218
    {
219
        "dffi",
220
    },
221
    {
222
        "dfch",
223
    },
224
    {
225
        "code",
226
    },
227
    {
228
        "anch",
229
    },
230
};
231

232
const char* DNT_NAMES[DNT_MAX - DNT_KEY] = {
233
    "key",
234
    "pair",
235
    "val",
236
    "row",
237
    "unit",
238
    "meas",
239
    "var",
240
    "rang",
241
    "grp",
242
};
243

244
const char*
245
data_scanner::token2name(data_token_t token)
4,708✔
246
{
247
    if (token < 0) {
4,708✔
248
        return "inv";
448✔
249
    }
250
    if (token < DT_TERMINAL_MAX) {
4,260✔
251
        return MATCHERS[token].name;
2,303✔
252
    }
253
    if (token == DT_ANY) {
1,957✔
UNCOV
254
        return "any";
×
255
    }
256
    return DNT_NAMES[token - DNT_KEY];
1,957✔
257
}
258

259
bool
260
data_scanner::is_credit_card(string_fragment cc) const
4✔
261
{
262
    auto cc_no_spaces = cc.to_string();
4✔
263
    auto new_end = std::remove_if(cc_no_spaces.begin(),
4✔
264
                                  cc_no_spaces.end(),
265
                                  [](auto ch) { return ch == ' '; });
67✔
266
    cc_no_spaces.erase(new_end, cc_no_spaces.end());
4✔
267
    int len = cc_no_spaces.size();
4✔
268
    int double_even_sum = 0;
4✔
269

270
    // Step 1: double every second digit, starting from right.
271
    // if results in 2 digit number, add the digits to obtain single digit
272
    // number. sum all answers to obtain 'double_even_sum'
273

274
    for (int lpc = len - 2; lpc >= 0; lpc = lpc - 2) {
36✔
275
        int dbl = ((cc_no_spaces[lpc] - '0') * 2);
32✔
276
        if (dbl > 9) {
32✔
277
            dbl = (dbl / 10) + (dbl % 10);
2✔
278
        }
279
        double_even_sum += dbl;
32✔
280
    }
281

282
    // Step 2: add every odd placed digit from right to double_even_sum's value
283

284
    for (int lpc = len - 1; lpc >= 0; lpc = lpc - 2) {
36✔
285
        double_even_sum += (cc_no_spaces[lpc] - 48);
32✔
286
    }
287

288
    // Step 3: check if final 'double_even_sum' is multiple of 10
289
    // if yes, it is valid.
290

291
    return double_even_sum % 10 == 0;
4✔
292
}
4✔
293

294
void
295
data_scanner::cleanup_end()
1,331✔
296
{
297
    auto done = false;
1,331✔
298

299
    while (!this->ds_input.empty() && !done) {
2,788✔
300
        switch (this->ds_input.back()) {
1,457✔
301
            case '.':
206✔
302
            case ' ':
303
            case '\r':
304
            case '\n':
305
                this->ds_input.pop_back();
206✔
306
                break;
206✔
307
            default:
1,251✔
308
                done = true;
1,251✔
309
                break;
1,251✔
310
        }
311
    }
312
}
1,331✔
313

314
std::optional<data_scanner::tokenize_result>
315
data_scanner::tokenize2(text_format_t tf)
76,491✔
316
{
317
    auto retval = this->tokenize_int(tf);
76,491✔
318

319
    if (this->ds_last_bracket_matched) {
76,491✔
320
        this->ds_matching_brackets.pop_back();
1,696✔
321
        this->ds_last_bracket_matched = false;
1,696✔
322
    }
323
    if (retval) {
76,491✔
324
        auto dt = retval.value().tr_token;
74,953✔
325
        switch (dt) {
74,953✔
326
            case DT_LSQUARE:
1,728✔
327
            case DT_LCURLY:
328
            case DT_LPAREN:
329
                this->ds_matching_brackets.emplace_back(retval.value());
1,728✔
330
                break;
1,728✔
331
            case DT_RSQUARE:
1,805✔
332
            case DT_RCURLY:
333
            case DT_RPAREN:
334
                if (!this->ds_matching_brackets.empty()
1,805✔
335
                    && this->ds_matching_brackets.back().tr_token
3,515✔
336
                        == to_opener(dt))
1,710✔
337
                {
338
                    this->ds_last_bracket_matched = true;
1,696✔
339
                }
340
                break;
1,805✔
341
            default:
71,420✔
342
                break;
71,420✔
343
        }
344
    }
345

346
    return retval;
76,491✔
347
}
348

349
std::optional<data_scanner::tokenize_result>
350
data_scanner::find_matching_bracket(text_format_t tf, tokenize_result tr)
×
351
{
352
    switch (tr.tr_token) {
×
353
        case DT_LSQUARE:
×
354
        case DT_LCURLY:
355
        case DT_LPAREN: {
UNCOV
356
            auto curr_size = this->ds_matching_brackets.size();
×
357
            while (true) {
358
                auto tok_res = this->tokenize2(tf);
×
UNCOV
359
                if (!tok_res) {
×
360
                    break;
×
361
                }
362

UNCOV
363
                if (this->ds_matching_brackets.size() == curr_size
×
364
                    && this->ds_last_bracket_matched)
×
365
                {
UNCOV
366
                    return tokenize_result{
×
367
                        DNT_GROUP,
368
                        {
369
                            tr.tr_capture.c_begin,
370
                            tok_res->tr_capture.c_end,
×
371
                        },
372
                        {
373
                            tr.tr_capture.c_begin,
374
                            tok_res->tr_capture.c_end,
×
375
                        },
376
                        tr.tr_data,
×
377
                    };
378
                }
379
            }
380
            break;
×
381
        }
UNCOV
382
        case DT_RSQUARE:
×
383
        case DT_RCURLY:
384
        case DT_RPAREN: {
UNCOV
385
            for (auto riter = this->ds_matching_brackets.rbegin();
×
UNCOV
386
                 riter != this->ds_matching_brackets.rend();
×
387
                 ++riter)
×
388
            {
UNCOV
389
                if (riter->tr_token == to_opener(tr.tr_token)) {
×
UNCOV
390
                    return data_scanner::tokenize_result{
×
391
                        DNT_GROUP,
392
                        {
UNCOV
393
                            riter->tr_capture.c_begin,
×
394
                            tr.tr_capture.c_end,
395
                        },
396
                        {
UNCOV
397
                            riter->tr_capture.c_begin,
×
398
                            tr.tr_capture.c_end,
399
                        },
400
                        tr.tr_data,
×
401
                    };
402
                }
403
            }
404
            break;
×
405
        }
UNCOV
406
        default:
×
UNCOV
407
            break;
×
408
    }
409

UNCOV
410
    return std::nullopt;
×
411
}
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