GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: grep.c,v 1.55 2015/11/28 01:17:12 gsoares Exp $ */ |
||
2 |
|||
3 |
/*- |
||
4 |
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav |
||
5 |
* All rights reserved. |
||
6 |
* |
||
7 |
* Redistribution and use in source and binary forms, with or without |
||
8 |
* modification, are permitted provided that the following conditions |
||
9 |
* are met: |
||
10 |
* 1. Redistributions of source code must retain the above copyright |
||
11 |
* notice, this list of conditions and the following disclaimer. |
||
12 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
13 |
* notice, this list of conditions and the following disclaimer in the |
||
14 |
* documentation and/or other materials provided with the distribution. |
||
15 |
* |
||
16 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
||
17 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
18 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
19 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
||
20 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
21 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
22 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
23 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
24 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
25 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
26 |
* SUCH DAMAGE. |
||
27 |
*/ |
||
28 |
|||
29 |
#include <sys/types.h> |
||
30 |
#include <sys/stat.h> |
||
31 |
#include <sys/queue.h> |
||
32 |
|||
33 |
#include <ctype.h> |
||
34 |
#include <err.h> |
||
35 |
#include <errno.h> |
||
36 |
#include <getopt.h> |
||
37 |
#include <regex.h> |
||
38 |
#include <stdio.h> |
||
39 |
#include <stdlib.h> |
||
40 |
#include <string.h> |
||
41 |
#include <unistd.h> |
||
42 |
|||
43 |
#include "grep.h" |
||
44 |
|||
45 |
/* Flags passed to regcomp() and regexec() */ |
||
46 |
int cflags; |
||
47 |
int eflags = REG_STARTEND; |
||
48 |
|||
49 |
int matchall; /* shortcut */ |
||
50 |
int patterns, pattern_sz; |
||
51 |
char **pattern; |
||
52 |
regex_t *r_pattern; |
||
53 |
fastgrep_t *fg_pattern; |
||
54 |
|||
55 |
/* For regex errors */ |
||
56 |
char re_error[RE_ERROR_BUF + 1]; |
||
57 |
|||
58 |
/* Command-line flags */ |
||
59 |
int Aflag; /* -A x: print x lines trailing each match */ |
||
60 |
int Bflag; /* -B x: print x lines leading each match */ |
||
61 |
int Eflag; /* -E: interpret pattern as extended regexp */ |
||
62 |
int Fflag; /* -F: interpret pattern as list of fixed strings */ |
||
63 |
int Hflag; /* -H: always print filename header */ |
||
64 |
int Lflag; /* -L: only show names of files with no matches */ |
||
65 |
int Rflag; /* -R: recursively search directory trees */ |
||
66 |
#ifndef NOZ |
||
67 |
int Zflag; /* -Z: decompress input before processing */ |
||
68 |
#endif |
||
69 |
int bflag; /* -b: show block numbers for each match */ |
||
70 |
int cflag; /* -c: only show a count of matching lines */ |
||
71 |
int hflag; /* -h: don't print filename headers */ |
||
72 |
int iflag; /* -i: ignore case */ |
||
73 |
int lflag; /* -l: only show names of files with matches */ |
||
74 |
int nflag; /* -n: show line numbers in front of matching lines */ |
||
75 |
int oflag; /* -o: print each match */ |
||
76 |
int qflag; /* -q: quiet mode (don't output anything) */ |
||
77 |
int sflag; /* -s: silent mode (ignore errors) */ |
||
78 |
int vflag; /* -v: only show non-matching lines */ |
||
79 |
int wflag; /* -w: pattern must start and end on word boundaries */ |
||
80 |
int xflag; /* -x: pattern must match entire line */ |
||
81 |
int lbflag; /* --line-buffered */ |
||
82 |
|||
83 |
int binbehave = BIN_FILE_BIN; |
||
84 |
|||
85 |
enum { |
||
86 |
BIN_OPT = CHAR_MAX + 1, |
||
87 |
HELP_OPT, |
||
88 |
MMAP_OPT, |
||
89 |
LINEBUF_OPT |
||
90 |
}; |
||
91 |
|||
92 |
/* Housekeeping */ |
||
93 |
int first; /* flag whether or not this is our first match */ |
||
94 |
int tail; /* lines left to print */ |
||
95 |
int file_err; /* file reading error */ |
||
96 |
|||
97 |
struct patfile { |
||
98 |
const char *pf_file; |
||
99 |
SLIST_ENTRY(patfile) pf_next; |
||
100 |
}; |
||
101 |
SLIST_HEAD(, patfile) patfilelh; |
||
102 |
|||
103 |
extern char *__progname; |
||
104 |
|||
105 |
static void |
||
106 |
usage(void) |
||
107 |
{ |
||
108 |
fprintf(stderr, |
||
109 |
#ifdef NOZ |
||
110 |
"usage: %s [-abcEFGHhIiLlnoqRsUVvwx] [-A num] [-B num] [-C[num]]\n" |
||
111 |
#else |
||
112 |
"usage: %s [-abcEFGHhIiLlnoqRsUVvwxZ] [-A num] [-B num] [-C[num]]\n" |
||
113 |
#endif |
||
114 |
"\t[-e pattern] [-f file] [--binary-files=value] [--context[=num]]\n" |
||
115 |
"\t[--line-buffered] [pattern] [file ...]\n", __progname); |
||
116 |
exit(2); |
||
117 |
} |
||
118 |
|||
119 |
#ifdef NOZ |
||
120 |
static const char optstr[] = "0123456789A:B:CEFGHILRUVabce:f:hilnoqrsuvwxy"; |
||
121 |
#else |
||
122 |
static const char optstr[] = "0123456789A:B:CEFGHILRUVZabce:f:hilnoqrsuvwxy"; |
||
123 |
#endif |
||
124 |
|||
125 |
static const struct option long_options[] = |
||
126 |
{ |
||
127 |
{"binary-files", required_argument, NULL, BIN_OPT}, |
||
128 |
{"help", no_argument, NULL, HELP_OPT}, |
||
129 |
{"mmap", no_argument, NULL, MMAP_OPT}, |
||
130 |
{"line-buffered", no_argument, NULL, LINEBUF_OPT}, |
||
131 |
{"after-context", required_argument, NULL, 'A'}, |
||
132 |
{"before-context", required_argument, NULL, 'B'}, |
||
133 |
{"context", optional_argument, NULL, 'C'}, |
||
134 |
{"devices", required_argument, NULL, 'D'}, |
||
135 |
{"extended-regexp", no_argument, NULL, 'E'}, |
||
136 |
{"fixed-strings", no_argument, NULL, 'F'}, |
||
137 |
{"basic-regexp", no_argument, NULL, 'G'}, |
||
138 |
{"with-filename", no_argument, NULL, 'H'}, |
||
139 |
{"binary", no_argument, NULL, 'U'}, |
||
140 |
{"version", no_argument, NULL, 'V'}, |
||
141 |
{"text", no_argument, NULL, 'a'}, |
||
142 |
{"byte-offset", no_argument, NULL, 'b'}, |
||
143 |
{"count", no_argument, NULL, 'c'}, |
||
144 |
{"regexp", required_argument, NULL, 'e'}, |
||
145 |
{"file", required_argument, NULL, 'f'}, |
||
146 |
{"no-filename", no_argument, NULL, 'h'}, |
||
147 |
{"ignore-case", no_argument, NULL, 'i'}, |
||
148 |
{"files-without-match", no_argument, NULL, 'L'}, |
||
149 |
{"files-with-matches", no_argument, NULL, 'l'}, |
||
150 |
{"line-number", no_argument, NULL, 'n'}, |
||
151 |
{"quiet", no_argument, NULL, 'q'}, |
||
152 |
{"silent", no_argument, NULL, 'q'}, |
||
153 |
{"recursive", no_argument, NULL, 'r'}, |
||
154 |
{"no-messages", no_argument, NULL, 's'}, |
||
155 |
{"revert-match", no_argument, NULL, 'v'}, |
||
156 |
{"word-regexp", no_argument, NULL, 'w'}, |
||
157 |
{"line-regexp", no_argument, NULL, 'x'}, |
||
158 |
{"unix-byte-offsets", no_argument, NULL, 'u'}, |
||
159 |
#ifndef NOZ |
||
160 |
{"decompress", no_argument, NULL, 'Z'}, |
||
161 |
#endif |
||
162 |
{NULL, no_argument, NULL, 0} |
||
163 |
}; |
||
164 |
|||
165 |
|||
166 |
static void |
||
167 |
add_pattern(char *pat, size_t len) |
||
168 |
371 |
{ |
|
169 |
✓✗✓✗ ✗✓ |
371 |
if (!xflag && (len == 0 || matchall)) { |
170 |
matchall = 1; |
||
171 |
return; |
||
172 |
} |
||
173 |
✓✗ | 371 |
if (patterns == pattern_sz) { |
174 |
371 |
pattern_sz *= 2; |
|
175 |
371 |
pattern = grep_reallocarray(pattern, ++pattern_sz, sizeof(*pattern)); |
|
176 |
} |
||
177 |
✓✗✗✓ |
371 |
if (len > 0 && pat[len - 1] == '\n') |
178 |
--len; |
||
179 |
/* pat may not be NUL-terminated */ |
||
180 |
✗✓✗✗ |
371 |
if (wflag && !Fflag) { |
181 |
int bol = 0, eol = 0, extra; |
||
182 |
if (pat[0] == '^') |
||
183 |
bol = 1; |
||
184 |
if (len > 0 && pat[len - 1] == '$') |
||
185 |
eol = 1; |
||
186 |
extra = Eflag ? 2 : 4; |
||
187 |
pattern[patterns] = grep_malloc(len + 15 + extra); |
||
188 |
snprintf(pattern[patterns], len + 15 + extra, |
||
189 |
"%s[[:<:]]%s%.*s%s[[:>:]]%s", |
||
190 |
bol ? "^" : "", |
||
191 |
Eflag ? "(" : "\\(", |
||
192 |
(int)len - bol - eol, pat + bol, |
||
193 |
Eflag ? ")" : "\\)", |
||
194 |
eol ? "$" : ""); |
||
195 |
len += 14 + extra; |
||
196 |
} else { |
||
197 |
371 |
pattern[patterns] = grep_malloc(len + 1); |
|
198 |
371 |
memcpy(pattern[patterns], pat, len); |
|
199 |
371 |
pattern[patterns][len] = '\0'; |
|
200 |
} |
||
201 |
371 |
++patterns; |
|
202 |
} |
||
203 |
|||
204 |
static void |
||
205 |
add_patterns(char *pats) |
||
206 |
371 |
{ |
|
207 |
char *nl; |
||
208 |
|||
209 |
✗✓ | 742 |
while ((nl = strchr(pats, '\n')) != NULL) { |
210 |
add_pattern(pats, nl - pats); |
||
211 |
pats = nl + 1; |
||
212 |
} |
||
213 |
371 |
add_pattern(pats, strlen(pats)); |
|
214 |
371 |
} |
|
215 |
|||
216 |
static void |
||
217 |
read_patterns(const char *fn) |
||
218 |
{ |
||
219 |
FILE *f; |
||
220 |
char *line; |
||
221 |
size_t len; |
||
222 |
|||
223 |
if ((f = fopen(fn, "r")) == NULL) |
||
224 |
err(2, "%s", fn); |
||
225 |
while ((line = fgetln(f, &len)) != NULL) |
||
226 |
add_pattern(line, *line == '\n' ? 0 : len); |
||
227 |
if (ferror(f)) |
||
228 |
err(2, "%s", fn); |
||
229 |
fclose(f); |
||
230 |
} |
||
231 |
|||
232 |
int |
||
233 |
main(int argc, char *argv[]) |
||
234 |
351 |
{ |
|
235 |
int c, lastc, prevoptind, newarg, i, needpattern, exprs, expr_sz; |
||
236 |
struct patfile *patfile, *pf_next; |
||
237 |
long l; |
||
238 |
char **expr; |
||
239 |
const char *errstr; |
||
240 |
|||
241 |
✗✓ | 351 |
if (pledge("stdio rpath wpath cpath", NULL) == -1) |
242 |
err(2, "pledge"); |
||
243 |
|||
244 |
351 |
SLIST_INIT(&patfilelh); |
|
245 |
✗✗✗✓ |
351 |
switch (__progname[0]) { |
246 |
case 'e': |
||
247 |
Eflag = 1; |
||
248 |
break; |
||
249 |
case 'f': |
||
250 |
Fflag = 1; |
||
251 |
break; |
||
252 |
#ifndef NOZ |
||
253 |
case 'z': |
||
254 |
Zflag = 1; |
||
255 |
switch(__progname[1]) { |
||
256 |
case 'e': |
||
257 |
Eflag = 1; |
||
258 |
break; |
||
259 |
case 'f': |
||
260 |
Fflag = 1; |
||
261 |
break; |
||
262 |
} |
||
263 |
break; |
||
264 |
#endif |
||
265 |
} |
||
266 |
|||
267 |
351 |
lastc = '\0'; |
|
268 |
351 |
newarg = 1; |
|
269 |
351 |
prevoptind = 1; |
|
270 |
351 |
needpattern = 1; |
|
271 |
351 |
expr_sz = exprs = 0; |
|
272 |
351 |
expr = NULL; |
|
273 |
✓✓ | 1049 |
while ((c = getopt_long(argc, argv, optstr, |
274 |
long_options, NULL)) != -1) { |
||
275 |
✗✗✗✓ ✗✗✗✗ ✗✗✗✓ ✗✗✗✓ ✓✗✗✗ ✗✗✗✓ ✗✓✗✗ ✗✗✗✗ |
349 |
switch (c) { |
276 |
case '0': case '1': case '2': case '3': case '4': |
||
277 |
case '5': case '6': case '7': case '8': case '9': |
||
278 |
if (newarg || !isdigit(lastc)) |
||
279 |
Aflag = 0; |
||
280 |
else if (Aflag > INT_MAX / 10) |
||
281 |
errx(2, "context out of range"); |
||
282 |
Aflag = Bflag = (Aflag * 10) + (c - '0'); |
||
283 |
break; |
||
284 |
case 'A': |
||
285 |
case 'B': |
||
286 |
l = strtonum(optarg, 1, INT_MAX, &errstr); |
||
287 |
if (errstr != NULL) |
||
288 |
errx(2, "context %s", errstr); |
||
289 |
if (c == 'A') |
||
290 |
Aflag = (int)l; |
||
291 |
else |
||
292 |
Bflag = (int)l; |
||
293 |
break; |
||
294 |
case 'C': |
||
295 |
if (optarg == NULL) |
||
296 |
Aflag = Bflag = 2; |
||
297 |
else { |
||
298 |
l = strtonum(optarg, 1, INT_MAX, &errstr); |
||
299 |
if (errstr != NULL) |
||
300 |
errx(2, "context %s", errstr); |
||
301 |
Aflag = Bflag = (int)l; |
||
302 |
} |
||
303 |
break; |
||
304 |
case 'E': |
||
305 |
22 |
Fflag = 0; |
|
306 |
22 |
Eflag = 1; |
|
307 |
22 |
break; |
|
308 |
case 'F': |
||
309 |
Eflag = 0; |
||
310 |
Fflag = 1; |
||
311 |
break; |
||
312 |
case 'G': |
||
313 |
Eflag = Fflag = 0; |
||
314 |
break; |
||
315 |
case 'H': |
||
316 |
Hflag = 1; |
||
317 |
break; |
||
318 |
case 'I': |
||
319 |
binbehave = BIN_FILE_SKIP; |
||
320 |
break; |
||
321 |
case 'L': |
||
322 |
lflag = 0; |
||
323 |
Lflag = qflag = 1; |
||
324 |
break; |
||
325 |
case 'R': |
||
326 |
case 'r': |
||
327 |
Rflag = 1; |
||
328 |
break; |
||
329 |
case 'U': |
||
330 |
binbehave = BIN_FILE_BIN; |
||
331 |
break; |
||
332 |
case 'V': |
||
333 |
2 |
fprintf(stderr, "grep version %u.%u\n", VER_MAJ, VER_MIN); |
|
334 |
2 |
exit(0); |
|
335 |
break; |
||
336 |
#ifndef NOZ |
||
337 |
case 'Z': |
||
338 |
Zflag = 1; |
||
339 |
break; |
||
340 |
#endif |
||
341 |
case 'a': |
||
342 |
binbehave = BIN_FILE_TEXT; |
||
343 |
break; |
||
344 |
case 'b': |
||
345 |
bflag = 1; |
||
346 |
break; |
||
347 |
case 'c': |
||
348 |
5 |
cflag = 1; |
|
349 |
5 |
break; |
|
350 |
case 'e': |
||
351 |
/* defer adding of expressions until all arguments are parsed */ |
||
352 |
✓✗ | 44 |
if (exprs == expr_sz) { |
353 |
44 |
expr_sz *= 2; |
|
354 |
44 |
expr = grep_reallocarray(expr, ++expr_sz, |
|
355 |
sizeof(*expr)); |
||
356 |
} |
||
357 |
44 |
needpattern = 0; |
|
358 |
44 |
expr[exprs] = optarg; |
|
359 |
44 |
++exprs; |
|
360 |
44 |
break; |
|
361 |
case 'f': |
||
362 |
patfile = grep_malloc(sizeof(*patfile)); |
||
363 |
patfile->pf_file = optarg; |
||
364 |
SLIST_INSERT_HEAD(&patfilelh, patfile, pf_next); |
||
365 |
needpattern = 0; |
||
366 |
break; |
||
367 |
case 'h': |
||
368 |
hflag = 1; |
||
369 |
break; |
||
370 |
case 'i': |
||
371 |
case 'y': |
||
372 |
iflag = 1; |
||
373 |
cflags |= REG_ICASE; |
||
374 |
break; |
||
375 |
case 'l': |
||
376 |
Lflag = 0; |
||
377 |
lflag = qflag = 1; |
||
378 |
break; |
||
379 |
case 'n': |
||
380 |
nflag = 1; |
||
381 |
break; |
||
382 |
case 'o': |
||
383 |
oflag = 1; |
||
384 |
break; |
||
385 |
case 'q': |
||
386 |
18 |
qflag = 1; |
|
387 |
18 |
break; |
|
388 |
case 's': |
||
389 |
sflag = 1; |
||
390 |
break; |
||
391 |
case 'v': |
||
392 |
258 |
vflag = 1; |
|
393 |
258 |
break; |
|
394 |
case 'w': |
||
395 |
wflag = 1; |
||
396 |
break; |
||
397 |
case 'x': |
||
398 |
xflag = 1; |
||
399 |
break; |
||
400 |
case BIN_OPT: |
||
401 |
if (strcmp("binary", optarg) == 0) |
||
402 |
binbehave = BIN_FILE_BIN; |
||
403 |
else if (strcmp("without-match", optarg) == 0) |
||
404 |
binbehave = BIN_FILE_SKIP; |
||
405 |
else if (strcmp("text", optarg) == 0) |
||
406 |
binbehave = BIN_FILE_TEXT; |
||
407 |
else |
||
408 |
errx(2, "Unknown binary-files option"); |
||
409 |
break; |
||
410 |
case 'u': |
||
411 |
case MMAP_OPT: |
||
412 |
/* default, compatibility */ |
||
413 |
break; |
||
414 |
case LINEBUF_OPT: |
||
415 |
lbflag = 1; |
||
416 |
break; |
||
417 |
case HELP_OPT: |
||
418 |
default: |
||
419 |
usage(); |
||
420 |
} |
||
421 |
347 |
lastc = c; |
|
422 |
347 |
newarg = optind != prevoptind; |
|
423 |
347 |
prevoptind = optind; |
|
424 |
} |
||
425 |
349 |
argc -= optind; |
|
426 |
349 |
argv += optind; |
|
427 |
|||
428 |
✓✓ | 393 |
for (i = 0; i < exprs; i++) |
429 |
44 |
add_patterns(expr[i]); |
|
430 |
349 |
free(expr); |
|
431 |
349 |
expr = NULL; |
|
432 |
|||
433 |
✗✓ | 698 |
for (patfile = SLIST_FIRST(&patfilelh); patfile != NULL; |
434 |
patfile = pf_next) { |
||
435 |
pf_next = SLIST_NEXT(patfile, pf_next); |
||
436 |
read_patterns(patfile->pf_file); |
||
437 |
free(patfile); |
||
438 |
} |
||
439 |
|||
440 |
✗✓ | 349 |
if (argc == 0 && needpattern) |
441 |
usage(); |
||
442 |
|||
443 |
✓✓ | 349 |
if (argc != 0 && needpattern) { |
444 |
327 |
add_patterns(*argv); |
|
445 |
327 |
--argc; |
|
446 |
327 |
++argv; |
|
447 |
} |
||
448 |
|||
449 |
✗✓ | 349 |
if (Rflag && argc == 0) |
450 |
warnx("warning: recursive search of stdin"); |
||
451 |
✓✓ | 349 |
if (Eflag) |
452 |
22 |
cflags |= REG_EXTENDED; |
|
453 |
✗✓ | 349 |
if (Fflag) |
454 |
cflags |= REG_NOSPEC; |
||
455 |
#ifdef SMALL |
||
456 |
/* Sorry, this won't work */ |
||
457 |
if (Fflag && wflag) |
||
458 |
errx(1, "Can't use small fgrep with -w"); |
||
459 |
#endif |
||
460 |
349 |
fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); |
|
461 |
349 |
r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); |
|
462 |
✓✓ | 720 |
for (i = 0; i < patterns; ++i) { |
463 |
/* Check if cheating is allowed (always is for fgrep). */ |
||
464 |
#ifndef SMALL |
||
465 |
✗✓ | 371 |
if (Fflag) { |
466 |
fgrepcomp(&fg_pattern[i], pattern[i]); |
||
467 |
} else |
||
468 |
#endif |
||
469 |
{ |
||
470 |
✓✓ | 371 |
if (fastcomp(&fg_pattern[i], pattern[i])) { |
471 |
/* Fall back to full regex library */ |
||
472 |
277 |
c = regcomp(&r_pattern[i], pattern[i], cflags); |
|
473 |
✗✓ | 277 |
if (c != 0) { |
474 |
regerror(c, &r_pattern[i], re_error, |
||
475 |
RE_ERROR_BUF); |
||
476 |
errx(2, "%s", re_error); |
||
477 |
} |
||
478 |
} |
||
479 |
} |
||
480 |
} |
||
481 |
|||
482 |
✗✓ | 349 |
if (lbflag) |
483 |
setvbuf(stdout, NULL, _IOLBF, 0); |
||
484 |
|||
485 |
✓✗✓✗ ✓✗ |
349 |
if ((argc == 0 || argc == 1) && !Rflag && !Hflag) |
486 |
349 |
hflag = 1; |
|
487 |
|||
488 |
✓✓ | 349 |
if (argc == 0) |
489 |
82 |
exit(!procfile(NULL)); |
|
490 |
|||
491 |
✗✓ | 267 |
if (Rflag) |
492 |
c = grep_tree(argv); |
||
493 |
else |
||
494 |
✓✓ | 534 |
for (c = 0; argc--; ++argv) |
495 |
267 |
c += procfile(*argv); |
|
496 |
|||
497 |
✓✓✗✓ ✗✗✗✓ |
267 |
exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1)); |
498 |
} |
Generated by: GCOVR (Version 3.3) |