1 1.16 andvar /* $NetBSD: grep.c,v 1.16 2022/10/15 21:53:22 andvar Exp $ */ 2 1.4 joerg /* $FreeBSD: head/usr.bin/grep/grep.c 211519 2010-08-19 22:55:17Z delphij $ */ 3 1.4 joerg /* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */ 4 1.2 cjep 5 1.1 cjep /*- 6 1.4 joerg * Copyright (c) 1999 James Howard and Dag-Erling Codan Smrgrav 7 1.4 joerg * Copyright (C) 2008-2009 Gabor Kovesdan <gabor (at) FreeBSD.org> 8 1.1 cjep * All rights reserved. 9 1.1 cjep * 10 1.1 cjep * Redistribution and use in source and binary forms, with or without 11 1.1 cjep * modification, are permitted provided that the following conditions 12 1.1 cjep * are met: 13 1.1 cjep * 1. Redistributions of source code must retain the above copyright 14 1.1 cjep * notice, this list of conditions and the following disclaimer. 15 1.1 cjep * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cjep * notice, this list of conditions and the following disclaimer in the 17 1.1 cjep * documentation and/or other materials provided with the distribution. 18 1.1 cjep * 19 1.1 cjep * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cjep * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cjep * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cjep * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 1.1 cjep * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cjep * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cjep * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cjep * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cjep * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cjep * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cjep * SUCH DAMAGE. 30 1.1 cjep */ 31 1.2 cjep 32 1.5 joerg #if HAVE_NBTOOL_CONFIG_H 33 1.5 joerg #include "nbtool_config.h" 34 1.5 joerg #endif 35 1.5 joerg 36 1.2 cjep #include <sys/cdefs.h> 37 1.16 andvar __RCSID("$NetBSD: grep.c,v 1.16 2022/10/15 21:53:22 andvar Exp $"); 38 1.1 cjep 39 1.4 joerg #include <sys/stat.h> 40 1.1 cjep #include <sys/types.h> 41 1.1 cjep 42 1.4 joerg #include <ctype.h> 43 1.1 cjep #include <err.h> 44 1.1 cjep #include <errno.h> 45 1.1 cjep #include <getopt.h> 46 1.2 cjep #include <limits.h> 47 1.4 joerg #include <libgen.h> 48 1.4 joerg #include <locale.h> 49 1.4 joerg #include <stdbool.h> 50 1.1 cjep #include <stdio.h> 51 1.1 cjep #include <stdlib.h> 52 1.1 cjep #include <string.h> 53 1.1 cjep #include <unistd.h> 54 1.1 cjep 55 1.1 cjep #include "grep.h" 56 1.1 cjep 57 1.4 joerg #ifndef WITHOUT_NLS 58 1.4 joerg #include <nl_types.h> 59 1.4 joerg nl_catd catalog; 60 1.4 joerg #endif 61 1.4 joerg 62 1.4 joerg /* 63 1.16 andvar * Default messages to use when NLS is disabled or no catalogue 64 1.4 joerg * is found. 65 1.2 cjep */ 66 1.4 joerg const char *errstr[] = { 67 1.4 joerg "", 68 1.4 joerg /* 1*/ "(standard input)", 69 1.4 joerg /* 2*/ "cannot read bzip2 compressed file", 70 1.4 joerg /* 3*/ "unknown %s option", 71 1.8 joerg /* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZz] [-A num] [-B num] [-C[num]]\n", 72 1.4 joerg /* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n", 73 1.4 joerg /* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n", 74 1.8 joerg /* 7*/ "\t[pattern] [file ...]\n", 75 1.4 joerg /* 8*/ "Binary file %s matches\n", 76 1.4 joerg /* 9*/ "%s (BSD grep) %s\n", 77 1.4 joerg }; 78 1.2 cjep 79 1.1 cjep /* Flags passed to regcomp() and regexec() */ 80 1.4 joerg int cflags = 0; 81 1.4 joerg int eflags = REG_STARTEND; 82 1.4 joerg 83 1.4 joerg /* Searching patterns */ 84 1.4 joerg unsigned int patterns, pattern_sz; 85 1.4 joerg char **pattern; 86 1.4 joerg regex_t *r_pattern; 87 1.4 joerg fastgrep_t *fg_pattern; 88 1.4 joerg 89 1.4 joerg /* Filename exclusion/inclusion patterns */ 90 1.4 joerg unsigned int fpatterns, fpattern_sz; 91 1.4 joerg unsigned int dpatterns, dpattern_sz; 92 1.4 joerg struct epat *dpattern, *fpattern; 93 1.1 cjep 94 1.1 cjep /* For regex errors */ 95 1.4 joerg char re_error[RE_ERROR_BUF + 1]; 96 1.1 cjep 97 1.1 cjep /* Command-line flags */ 98 1.4 joerg unsigned long long Aflag; /* -A x: print x lines trailing each match */ 99 1.4 joerg unsigned long long Bflag; /* -B x: print x lines leading each match */ 100 1.4 joerg bool Hflag; /* -H: always print file name */ 101 1.4 joerg bool Lflag; /* -L: only show names of files with no matches */ 102 1.4 joerg bool bflag; /* -b: show block numbers for each match */ 103 1.4 joerg bool cflag; /* -c: only show a count of matching lines */ 104 1.4 joerg bool hflag; /* -h: don't print filename headers */ 105 1.4 joerg bool iflag; /* -i: ignore case */ 106 1.4 joerg bool lflag; /* -l: only show names of files with matches */ 107 1.4 joerg bool mflag; /* -m x: stop reading the files after x matches */ 108 1.4 joerg unsigned long long mcount; /* count for -m */ 109 1.4 joerg bool nflag; /* -n: show line numbers in front of matching lines */ 110 1.4 joerg bool oflag; /* -o: print only matching part */ 111 1.4 joerg bool qflag; /* -q: quiet mode (don't output anything) */ 112 1.4 joerg bool sflag; /* -s: silent mode (ignore errors) */ 113 1.4 joerg bool vflag; /* -v: only show non-matching lines */ 114 1.4 joerg bool wflag; /* -w: pattern must start and end on word boundaries */ 115 1.4 joerg bool xflag; /* -x: pattern must match entire line */ 116 1.4 joerg bool lbflag; /* --line-buffered */ 117 1.4 joerg bool nullflag; /* --null */ 118 1.8 joerg bool nulldataflag; /* --null-data */ 119 1.8 joerg unsigned char line_sep = '\n'; /* 0 for --null-data */ 120 1.4 joerg char *label; /* --label */ 121 1.4 joerg const char *color; /* --color */ 122 1.4 joerg int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */ 123 1.4 joerg int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */ 124 1.4 joerg int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */ 125 1.4 joerg int devbehave = DEV_READ; /* -D: handling of devices */ 126 1.4 joerg int dirbehave = DIR_READ; /* -dRr: handling of directories */ 127 1.4 joerg int linkbehave = LINK_READ; /* -OpS: handling of symlinks */ 128 1.4 joerg 129 1.4 joerg bool dexclude, dinclude; /* --exclude-dir and --include-dir */ 130 1.4 joerg bool fexclude, finclude; /* --exclude and --include */ 131 1.2 cjep 132 1.2 cjep enum { 133 1.2 cjep BIN_OPT = CHAR_MAX + 1, 134 1.4 joerg COLOR_OPT, 135 1.8 joerg DECOMPRESS_OPT, 136 1.2 cjep HELP_OPT, 137 1.4 joerg MMAP_OPT, 138 1.4 joerg LINEBUF_OPT, 139 1.2 cjep LABEL_OPT, 140 1.4 joerg R_EXCLUDE_OPT, 141 1.4 joerg R_INCLUDE_OPT, 142 1.4 joerg R_DEXCLUDE_OPT, 143 1.4 joerg R_DINCLUDE_OPT 144 1.2 cjep }; 145 1.1 cjep 146 1.4 joerg static inline const char *init_color(const char *); 147 1.4 joerg 148 1.1 cjep /* Housekeeping */ 149 1.4 joerg int tail; /* lines left to print */ 150 1.4 joerg bool notfound; /* file not found */ 151 1.4 joerg 152 1.4 joerg extern char *__progname; 153 1.1 cjep 154 1.4 joerg /* 155 1.4 joerg * Prints usage information and returns 2. 156 1.4 joerg */ 157 1.10 joerg __dead static void 158 1.1 cjep usage(void) 159 1.1 cjep { 160 1.4 joerg fprintf(stderr, getstr(4), __progname); 161 1.4 joerg fprintf(stderr, "%s", getstr(5)); 162 1.4 joerg fprintf(stderr, "%s", getstr(6)); 163 1.4 joerg fprintf(stderr, "%s", getstr(7)); 164 1.1 cjep exit(2); 165 1.1 cjep } 166 1.1 cjep 167 1.8 joerg static const char optstr[] = 168 1.8 joerg "0123456789A:B:C:D:EFGHIJLOPSRUVZabcd:e:f:hilm:nopqrsuvwxyz"; 169 1.1 cjep 170 1.2 cjep struct option long_options[] = 171 1.1 cjep { 172 1.4 joerg {"binary-files", required_argument, NULL, BIN_OPT}, 173 1.15 christos #ifndef WITHOUT_GZIP 174 1.8 joerg {"decompress", no_argument, NULL, DECOMPRESS_OPT}, 175 1.15 christos #endif 176 1.4 joerg {"help", no_argument, NULL, HELP_OPT}, 177 1.4 joerg {"mmap", no_argument, NULL, MMAP_OPT}, 178 1.4 joerg {"line-buffered", no_argument, NULL, LINEBUF_OPT}, 179 1.4 joerg {"label", required_argument, NULL, LABEL_OPT}, 180 1.4 joerg {"color", optional_argument, NULL, COLOR_OPT}, 181 1.4 joerg {"colour", optional_argument, NULL, COLOR_OPT}, 182 1.4 joerg {"exclude", required_argument, NULL, R_EXCLUDE_OPT}, 183 1.4 joerg {"include", required_argument, NULL, R_INCLUDE_OPT}, 184 1.4 joerg {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT}, 185 1.4 joerg {"include-dir", required_argument, NULL, R_DINCLUDE_OPT}, 186 1.4 joerg {"after-context", required_argument, NULL, 'A'}, 187 1.4 joerg {"text", no_argument, NULL, 'a'}, 188 1.4 joerg {"before-context", required_argument, NULL, 'B'}, 189 1.4 joerg {"byte-offset", no_argument, NULL, 'b'}, 190 1.4 joerg {"context", optional_argument, NULL, 'C'}, 191 1.4 joerg {"count", no_argument, NULL, 'c'}, 192 1.4 joerg {"devices", required_argument, NULL, 'D'}, 193 1.4 joerg {"directories", required_argument, NULL, 'd'}, 194 1.4 joerg {"extended-regexp", no_argument, NULL, 'E'}, 195 1.4 joerg {"regexp", required_argument, NULL, 'e'}, 196 1.4 joerg {"fixed-strings", no_argument, NULL, 'F'}, 197 1.4 joerg {"file", required_argument, NULL, 'f'}, 198 1.4 joerg {"basic-regexp", no_argument, NULL, 'G'}, 199 1.4 joerg {"no-filename", no_argument, NULL, 'h'}, 200 1.4 joerg {"with-filename", no_argument, NULL, 'H'}, 201 1.4 joerg {"ignore-case", no_argument, NULL, 'i'}, 202 1.14 christos #ifndef WITHOUT_BZ2 203 1.4 joerg {"bz2decompress", no_argument, NULL, 'J'}, 204 1.14 christos #endif 205 1.4 joerg {"files-with-matches", no_argument, NULL, 'l'}, 206 1.4 joerg {"files-without-match", no_argument, NULL, 'L'}, 207 1.4 joerg {"max-count", required_argument, NULL, 'm'}, 208 1.4 joerg {"line-number", no_argument, NULL, 'n'}, 209 1.4 joerg {"only-matching", no_argument, NULL, 'o'}, 210 1.4 joerg {"quiet", no_argument, NULL, 'q'}, 211 1.4 joerg {"silent", no_argument, NULL, 'q'}, 212 1.4 joerg {"recursive", no_argument, NULL, 'r'}, 213 1.4 joerg {"no-messages", no_argument, NULL, 's'}, 214 1.4 joerg {"binary", no_argument, NULL, 'U'}, 215 1.4 joerg {"unix-byte-offsets", no_argument, NULL, 'u'}, 216 1.4 joerg {"invert-match", no_argument, NULL, 'v'}, 217 1.4 joerg {"version", no_argument, NULL, 'V'}, 218 1.4 joerg {"word-regexp", no_argument, NULL, 'w'}, 219 1.4 joerg {"line-regexp", no_argument, NULL, 'x'}, 220 1.8 joerg {"null", no_argument, NULL, 'Z'}, 221 1.8 joerg {"null-data", no_argument, NULL, 'z'}, 222 1.4 joerg {NULL, no_argument, NULL, 0} 223 1.1 cjep }; 224 1.1 cjep 225 1.4 joerg /* 226 1.4 joerg * Adds a searching pattern to the internal array. 227 1.4 joerg */ 228 1.1 cjep static void 229 1.1 cjep add_pattern(char *pat, size_t len) 230 1.1 cjep { 231 1.4 joerg 232 1.11 joerg /* TODO: Check for empty patterns and shortcut */ 233 1.11 joerg 234 1.4 joerg /* Increase size if necessary */ 235 1.1 cjep if (patterns == pattern_sz) { 236 1.1 cjep pattern_sz *= 2; 237 1.4 joerg pattern = grep_realloc(pattern, ++pattern_sz * 238 1.4 joerg sizeof(*pattern)); 239 1.1 cjep } 240 1.4 joerg if (len > 0 && pat[len - 1] == '\n') 241 1.1 cjep --len; 242 1.4 joerg /* pat may not be NUL-terminated */ 243 1.2 cjep pattern[patterns] = grep_malloc(len + 1); 244 1.4 joerg memcpy(pattern[patterns], pat, len); 245 1.1 cjep pattern[patterns][len] = '\0'; 246 1.1 cjep ++patterns; 247 1.1 cjep } 248 1.1 cjep 249 1.4 joerg /* 250 1.4 joerg * Adds a file include/exclude pattern to the internal array. 251 1.4 joerg */ 252 1.1 cjep static void 253 1.4 joerg add_fpattern(const char *pat, int mode) 254 1.4 joerg { 255 1.4 joerg 256 1.4 joerg /* Increase size if necessary */ 257 1.4 joerg if (fpatterns == fpattern_sz) { 258 1.4 joerg fpattern_sz *= 2; 259 1.4 joerg fpattern = grep_realloc(fpattern, ++fpattern_sz * 260 1.4 joerg sizeof(struct epat)); 261 1.4 joerg } 262 1.4 joerg fpattern[fpatterns].pat = grep_strdup(pat); 263 1.4 joerg fpattern[fpatterns].mode = mode; 264 1.4 joerg ++fpatterns; 265 1.4 joerg } 266 1.4 joerg 267 1.4 joerg /* 268 1.4 joerg * Adds a directory include/exclude pattern to the internal array. 269 1.4 joerg */ 270 1.4 joerg static void 271 1.4 joerg add_dpattern(const char *pat, int mode) 272 1.4 joerg { 273 1.4 joerg 274 1.4 joerg /* Increase size if necessary */ 275 1.4 joerg if (dpatterns == dpattern_sz) { 276 1.4 joerg dpattern_sz *= 2; 277 1.4 joerg dpattern = grep_realloc(dpattern, ++dpattern_sz * 278 1.4 joerg sizeof(struct epat)); 279 1.4 joerg } 280 1.4 joerg dpattern[dpatterns].pat = grep_strdup(pat); 281 1.4 joerg dpattern[dpatterns].mode = mode; 282 1.4 joerg ++dpatterns; 283 1.4 joerg } 284 1.4 joerg 285 1.4 joerg /* 286 1.4 joerg * Reads searching patterns from a file and adds them with add_pattern(). 287 1.4 joerg */ 288 1.4 joerg static void 289 1.4 joerg read_patterns(const char *fn) 290 1.1 cjep { 291 1.1 cjep FILE *f; 292 1.1 cjep char *line; 293 1.1 cjep size_t len; 294 1.6 joerg ssize_t rlen; 295 1.1 cjep 296 1.1 cjep if ((f = fopen(fn, "r")) == NULL) 297 1.2 cjep err(2, "%s", fn); 298 1.6 joerg line = NULL; 299 1.6 joerg len = 0; 300 1.6 joerg while ((rlen = getline(&line, &len, f)) != -1) 301 1.6 joerg add_pattern(line, *line == '\n' ? 0 : (size_t)rlen); 302 1.6 joerg free(line); 303 1.1 cjep if (ferror(f)) 304 1.2 cjep err(2, "%s", fn); 305 1.1 cjep fclose(f); 306 1.1 cjep } 307 1.1 cjep 308 1.4 joerg static inline const char * 309 1.4 joerg init_color(const char *d) 310 1.2 cjep { 311 1.4 joerg char *c; 312 1.2 cjep 313 1.4 joerg c = getenv("GREP_COLOR"); 314 1.4 joerg return (c != NULL ? c : d); 315 1.2 cjep } 316 1.2 cjep 317 1.1 cjep int 318 1.1 cjep main(int argc, char *argv[]) 319 1.1 cjep { 320 1.4 joerg char **aargv, **eargv, *eopts; 321 1.4 joerg char *ep; 322 1.4 joerg unsigned long long l; 323 1.9 joerg unsigned int aargc, eargc, i, j; 324 1.4 joerg int c, lastc, needpattern, newarg, prevoptind; 325 1.4 joerg 326 1.4 joerg setlocale(LC_ALL, ""); 327 1.4 joerg 328 1.4 joerg #ifndef WITHOUT_NLS 329 1.4 joerg catalog = catopen("grep", NL_CAT_LOCALE); 330 1.4 joerg #endif 331 1.4 joerg 332 1.4 joerg /* Check what is the program name of the binary. In this 333 1.16 andvar way we can have all the functionalities in one binary 334 1.4 joerg without the need of scripting and using ugly hacks. */ 335 1.4 joerg switch (__progname[0]) { 336 1.2 cjep case 'e': 337 1.4 joerg grepbehave = GREP_EXTENDED; 338 1.2 cjep break; 339 1.2 cjep case 'f': 340 1.4 joerg grepbehave = GREP_FIXED; 341 1.2 cjep break; 342 1.2 cjep case 'g': 343 1.4 joerg grepbehave = GREP_BASIC; 344 1.2 cjep break; 345 1.15 christos #ifndef WITHOUT_GZIP 346 1.2 cjep case 'z': 347 1.4 joerg filebehave = FILE_GZIP; 348 1.4 joerg switch(__progname[1]) { 349 1.2 cjep case 'e': 350 1.4 joerg grepbehave = GREP_EXTENDED; 351 1.2 cjep break; 352 1.2 cjep case 'f': 353 1.4 joerg grepbehave = GREP_FIXED; 354 1.2 cjep break; 355 1.2 cjep case 'g': 356 1.4 joerg grepbehave = GREP_BASIC; 357 1.2 cjep break; 358 1.2 cjep } 359 1.2 cjep break; 360 1.15 christos #endif 361 1.2 cjep } 362 1.1 cjep 363 1.4 joerg lastc = '\0'; 364 1.4 joerg newarg = 1; 365 1.4 joerg prevoptind = 1; 366 1.4 joerg needpattern = 1; 367 1.4 joerg 368 1.4 joerg eopts = getenv("GREP_OPTIONS"); 369 1.4 joerg 370 1.4 joerg /* support for extra arguments in GREP_OPTIONS */ 371 1.4 joerg eargc = 0; 372 1.4 joerg if (eopts != NULL) { 373 1.4 joerg char *str; 374 1.4 joerg 375 1.4 joerg /* make an estimation of how many extra arguments we have */ 376 1.9 joerg for (j = 0; j < strlen(eopts); j++) 377 1.4 joerg if (eopts[j] == ' ') 378 1.4 joerg eargc++; 379 1.4 joerg 380 1.4 joerg eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1)); 381 1.4 joerg 382 1.4 joerg eargc = 0; 383 1.4 joerg /* parse extra arguments */ 384 1.4 joerg while ((str = strsep(&eopts, " ")) != NULL) 385 1.4 joerg eargv[eargc++] = grep_strdup(str); 386 1.4 joerg 387 1.4 joerg aargv = (char **)grep_calloc(eargc + argc + 1, 388 1.4 joerg sizeof(char *)); 389 1.4 joerg 390 1.4 joerg aargv[0] = argv[0]; 391 1.4 joerg for (i = 0; i < eargc; i++) 392 1.4 joerg aargv[i + 1] = eargv[i]; 393 1.9 joerg for (j = 1; j < (unsigned int)argc; j++, i++) 394 1.4 joerg aargv[i + 1] = argv[j]; 395 1.4 joerg 396 1.4 joerg aargc = eargc + argc; 397 1.4 joerg } else { 398 1.4 joerg aargv = argv; 399 1.4 joerg aargc = argc; 400 1.4 joerg } 401 1.4 joerg 402 1.4 joerg while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) != 403 1.4 joerg -1)) { 404 1.1 cjep switch (c) { 405 1.4 joerg case '0': case '1': case '2': case '3': case '4': 406 1.4 joerg case '5': case '6': case '7': case '8': case '9': 407 1.4 joerg if (newarg || !isdigit(lastc)) 408 1.4 joerg Aflag = 0; 409 1.4 joerg else if (Aflag > LLONG_MAX / 10) { 410 1.4 joerg errno = ERANGE; 411 1.4 joerg err(2, NULL); 412 1.4 joerg } 413 1.4 joerg Aflag = Bflag = (Aflag * 10) + (c - '0'); 414 1.1 cjep break; 415 1.1 cjep case 'C': 416 1.4 joerg if (optarg == NULL) { 417 1.1 cjep Aflag = Bflag = 2; 418 1.4 joerg break; 419 1.4 joerg } 420 1.4 joerg /* FALLTHROUGH */ 421 1.4 joerg case 'A': 422 1.4 joerg /* FALLTHROUGH */ 423 1.4 joerg case 'B': 424 1.4 joerg errno = 0; 425 1.4 joerg l = strtoull(optarg, &ep, 10); 426 1.4 joerg if (((errno == ERANGE) && (l == ULLONG_MAX)) || 427 1.4 joerg ((errno == EINVAL) && (l == 0))) 428 1.4 joerg err(2, NULL); 429 1.4 joerg else if (ep[0] != '\0') { 430 1.4 joerg errno = EINVAL; 431 1.4 joerg err(2, NULL); 432 1.4 joerg } 433 1.4 joerg if (c == 'A') 434 1.4 joerg Aflag = l; 435 1.4 joerg else if (c == 'B') 436 1.4 joerg Bflag = l; 437 1.1 cjep else 438 1.4 joerg Aflag = Bflag = l; 439 1.1 cjep break; 440 1.1 cjep case 'a': 441 1.4 joerg binbehave = BINFILE_TEXT; 442 1.1 cjep break; 443 1.1 cjep case 'b': 444 1.4 joerg bflag = true; 445 1.1 cjep break; 446 1.1 cjep case 'c': 447 1.4 joerg cflag = true; 448 1.4 joerg break; 449 1.4 joerg case 'D': 450 1.4 joerg if (strcasecmp(optarg, "skip") == 0) 451 1.4 joerg devbehave = DEV_SKIP; 452 1.4 joerg else if (strcasecmp(optarg, "read") == 0) 453 1.4 joerg devbehave = DEV_READ; 454 1.4 joerg else 455 1.4 joerg errx(2, getstr(3), "--devices"); 456 1.1 cjep break; 457 1.2 cjep case 'd': 458 1.4 joerg if (strcasecmp("recurse", optarg) == 0) { 459 1.4 joerg Hflag = true; 460 1.4 joerg dirbehave = DIR_RECURSE; 461 1.4 joerg } else if (strcasecmp("skip", optarg) == 0) 462 1.4 joerg dirbehave = DIR_SKIP; 463 1.4 joerg else if (strcasecmp("read", optarg) == 0) 464 1.4 joerg dirbehave = DIR_READ; 465 1.4 joerg else 466 1.4 joerg errx(2, getstr(3), "--directories"); 467 1.4 joerg break; 468 1.4 joerg case 'E': 469 1.4 joerg grepbehave = GREP_EXTENDED; 470 1.2 cjep break; 471 1.1 cjep case 'e': 472 1.1 cjep add_pattern(optarg, strlen(optarg)); 473 1.4 joerg needpattern = 0; 474 1.4 joerg break; 475 1.4 joerg case 'F': 476 1.4 joerg grepbehave = GREP_FIXED; 477 1.1 cjep break; 478 1.1 cjep case 'f': 479 1.1 cjep read_patterns(optarg); 480 1.4 joerg needpattern = 0; 481 1.4 joerg break; 482 1.4 joerg case 'G': 483 1.4 joerg grepbehave = GREP_BASIC; 484 1.4 joerg break; 485 1.4 joerg case 'H': 486 1.4 joerg Hflag = true; 487 1.1 cjep break; 488 1.1 cjep case 'h': 489 1.4 joerg Hflag = false; 490 1.4 joerg hflag = true; 491 1.4 joerg break; 492 1.4 joerg case 'I': 493 1.4 joerg binbehave = BINFILE_SKIP; 494 1.1 cjep break; 495 1.1 cjep case 'i': 496 1.1 cjep case 'y': 497 1.4 joerg iflag = true; 498 1.1 cjep cflags |= REG_ICASE; 499 1.1 cjep break; 500 1.14 christos #ifndef WITHOUT_BZ2 501 1.4 joerg case 'J': 502 1.4 joerg filebehave = FILE_BZIP; 503 1.4 joerg break; 504 1.14 christos #endif 505 1.4 joerg case 'L': 506 1.4 joerg lflag = false; 507 1.4 joerg Lflag = true; 508 1.4 joerg break; 509 1.1 cjep case 'l': 510 1.4 joerg Lflag = false; 511 1.4 joerg lflag = true; 512 1.1 cjep break; 513 1.2 cjep case 'm': 514 1.4 joerg mflag = true; 515 1.4 joerg errno = 0; 516 1.4 joerg mcount = strtoull(optarg, &ep, 10); 517 1.4 joerg if (((errno == ERANGE) && (mcount == ULLONG_MAX)) || 518 1.4 joerg ((errno == EINVAL) && (mcount == 0))) 519 1.4 joerg err(2, NULL); 520 1.4 joerg else if (ep[0] != '\0') { 521 1.4 joerg errno = EINVAL; 522 1.4 joerg err(2, NULL); 523 1.4 joerg } 524 1.2 cjep break; 525 1.1 cjep case 'n': 526 1.4 joerg nflag = true; 527 1.4 joerg break; 528 1.4 joerg case 'O': 529 1.4 joerg linkbehave = LINK_EXPLICIT; 530 1.1 cjep break; 531 1.1 cjep case 'o': 532 1.4 joerg oflag = true; 533 1.4 joerg break; 534 1.4 joerg case 'p': 535 1.4 joerg linkbehave = LINK_SKIP; 536 1.1 cjep break; 537 1.1 cjep case 'q': 538 1.4 joerg qflag = true; 539 1.4 joerg break; 540 1.4 joerg case 'S': 541 1.4 joerg linkbehave = LINK_READ; 542 1.4 joerg break; 543 1.4 joerg case 'R': 544 1.4 joerg case 'r': 545 1.4 joerg dirbehave = DIR_RECURSE; 546 1.4 joerg Hflag = true; 547 1.1 cjep break; 548 1.1 cjep case 's': 549 1.4 joerg sflag = true; 550 1.4 joerg break; 551 1.4 joerg case 'U': 552 1.4 joerg binbehave = BINFILE_BIN; 553 1.1 cjep break; 554 1.4 joerg case 'u': 555 1.4 joerg case MMAP_OPT: 556 1.4 joerg /* noop, compatibility */ 557 1.4 joerg break; 558 1.4 joerg case 'V': 559 1.4 joerg printf(getstr(9), __progname, VERSION); 560 1.4 joerg exit(0); 561 1.1 cjep case 'v': 562 1.4 joerg vflag = true; 563 1.1 cjep break; 564 1.1 cjep case 'w': 565 1.4 joerg wflag = true; 566 1.1 cjep break; 567 1.1 cjep case 'x': 568 1.4 joerg xflag = true; 569 1.1 cjep break; 570 1.4 joerg case 'Z': 571 1.8 joerg nullflag = true; 572 1.8 joerg break; 573 1.8 joerg case 'z': 574 1.8 joerg nulldataflag = true; 575 1.8 joerg line_sep = '\0'; 576 1.2 cjep break; 577 1.2 cjep case BIN_OPT: 578 1.4 joerg if (strcasecmp("binary", optarg) == 0) 579 1.4 joerg binbehave = BINFILE_BIN; 580 1.4 joerg else if (strcasecmp("without-match", optarg) == 0) 581 1.4 joerg binbehave = BINFILE_SKIP; 582 1.4 joerg else if (strcasecmp("text", optarg) == 0) 583 1.4 joerg binbehave = BINFILE_TEXT; 584 1.4 joerg else 585 1.4 joerg errx(2, getstr(3), "--binary-files"); 586 1.4 joerg break; 587 1.4 joerg case COLOR_OPT: 588 1.4 joerg color = NULL; 589 1.4 joerg if (optarg == NULL || strcasecmp("auto", optarg) == 0 || 590 1.4 joerg strcasecmp("tty", optarg) == 0 || 591 1.4 joerg strcasecmp("if-tty", optarg) == 0) { 592 1.4 joerg char *term; 593 1.4 joerg 594 1.4 joerg term = getenv("TERM"); 595 1.4 joerg if (isatty(STDOUT_FILENO) && term != NULL && 596 1.4 joerg strcasecmp(term, "dumb") != 0) 597 1.4 joerg color = init_color("01;31"); 598 1.4 joerg } else if (strcasecmp("always", optarg) == 0 || 599 1.4 joerg strcasecmp("yes", optarg) == 0 || 600 1.4 joerg strcasecmp("force", optarg) == 0) { 601 1.4 joerg color = init_color("01;31"); 602 1.4 joerg } else if (strcasecmp("never", optarg) != 0 && 603 1.4 joerg strcasecmp("none", optarg) != 0 && 604 1.4 joerg strcasecmp("no", optarg) != 0) 605 1.4 joerg errx(2, getstr(3), "--color"); 606 1.2 cjep break; 607 1.15 christos #ifndef WITHOUT_GZIP 608 1.8 joerg case DECOMPRESS_OPT: 609 1.8 joerg filebehave = FILE_GZIP; 610 1.8 joerg break; 611 1.15 christos #endif 612 1.2 cjep case LABEL_OPT: 613 1.4 joerg label = optarg; 614 1.4 joerg break; 615 1.4 joerg case LINEBUF_OPT: 616 1.4 joerg lbflag = true; 617 1.2 cjep break; 618 1.4 joerg case R_INCLUDE_OPT: 619 1.4 joerg finclude = true; 620 1.4 joerg add_fpattern(optarg, INCL_PAT); 621 1.4 joerg break; 622 1.4 joerg case R_EXCLUDE_OPT: 623 1.4 joerg fexclude = true; 624 1.4 joerg add_fpattern(optarg, EXCL_PAT); 625 1.4 joerg break; 626 1.4 joerg case R_DINCLUDE_OPT: 627 1.4 joerg dinclude = true; 628 1.4 joerg add_dpattern(optarg, INCL_PAT); 629 1.4 joerg break; 630 1.4 joerg case R_DEXCLUDE_OPT: 631 1.4 joerg dexclude = true; 632 1.4 joerg add_dpattern(optarg, EXCL_PAT); 633 1.2 cjep break; 634 1.2 cjep case HELP_OPT: 635 1.1 cjep default: 636 1.1 cjep usage(); 637 1.1 cjep } 638 1.4 joerg lastc = c; 639 1.4 joerg newarg = optind != prevoptind; 640 1.4 joerg prevoptind = optind; 641 1.1 cjep } 642 1.4 joerg aargc -= optind; 643 1.4 joerg aargv += optind; 644 1.1 cjep 645 1.4 joerg /* Fail if we don't have any pattern */ 646 1.4 joerg if (aargc == 0 && needpattern) 647 1.1 cjep usage(); 648 1.4 joerg 649 1.4 joerg /* Process patterns from command line */ 650 1.4 joerg if (aargc != 0 && needpattern) { 651 1.4 joerg add_pattern(*aargv, strlen(*aargv)); 652 1.4 joerg --aargc; 653 1.4 joerg ++aargv; 654 1.1 cjep } 655 1.1 cjep 656 1.4 joerg switch (grepbehave) { 657 1.4 joerg case GREP_FIXED: 658 1.4 joerg case GREP_BASIC: 659 1.4 joerg break; 660 1.4 joerg case GREP_EXTENDED: 661 1.2 cjep cflags |= REG_EXTENDED; 662 1.4 joerg break; 663 1.4 joerg default: 664 1.4 joerg /* NOTREACHED */ 665 1.4 joerg usage(); 666 1.4 joerg } 667 1.4 joerg 668 1.4 joerg fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern)); 669 1.4 joerg r_pattern = grep_calloc(patterns, sizeof(*r_pattern)); 670 1.4 joerg /* 671 1.4 joerg * XXX: fgrepcomp() and fastcomp() are workarounds for regexec() performance. 672 1.4 joerg * Optimizations should be done there. 673 1.4 joerg */ 674 1.4 joerg /* Check if cheating is allowed (always is for fgrep). */ 675 1.4 joerg if (grepbehave == GREP_FIXED) { 676 1.4 joerg for (i = 0; i < patterns; ++i) 677 1.4 joerg fgrepcomp(&fg_pattern[i], pattern[i]); 678 1.4 joerg } else { 679 1.4 joerg for (i = 0; i < patterns; ++i) { 680 1.4 joerg if (fastcomp(&fg_pattern[i], pattern[i])) { 681 1.4 joerg /* Fall back to full regex library */ 682 1.4 joerg c = regcomp(&r_pattern[i], pattern[i], cflags); 683 1.4 joerg if (c != 0) { 684 1.4 joerg regerror(c, &r_pattern[i], re_error, 685 1.4 joerg RE_ERROR_BUF); 686 1.4 joerg errx(2, "%s", re_error); 687 1.4 joerg } 688 1.4 joerg } 689 1.1 cjep } 690 1.1 cjep } 691 1.1 cjep 692 1.13 christos if (lbflag) { 693 1.13 christos #ifdef _IOLBF 694 1.13 christos setvbuf(stdout, NULL, _IOLBF, 0); 695 1.13 christos #else 696 1.4 joerg setlinebuf(stdout); 697 1.13 christos #endif 698 1.13 christos } 699 1.1 cjep 700 1.4 joerg if ((aargc == 0 || aargc == 1) && !Hflag) 701 1.4 joerg hflag = true; 702 1.2 cjep 703 1.4 joerg if (aargc == 0) 704 1.4 joerg exit(!procfile("-")); 705 1.2 cjep 706 1.4 joerg if (dirbehave == DIR_RECURSE) 707 1.4 joerg c = grep_tree(aargv); 708 1.1 cjep else 709 1.4 joerg for (c = 0; aargc--; ++aargv) { 710 1.4 joerg if ((finclude || fexclude) && !file_matching(*aargv)) 711 1.4 joerg continue; 712 1.4 joerg c+= procfile(*aargv); 713 1.4 joerg } 714 1.1 cjep 715 1.4 joerg #ifndef WITHOUT_NLS 716 1.4 joerg catclose(catalog); 717 1.4 joerg #endif 718 1.4 joerg 719 1.4 joerg /* Find out the correct return value according to the 720 1.4 joerg results and the command line option. */ 721 1.4 joerg exit(c ? (notfound ? (qflag ? 0 : 2) : 0) : (notfound ? 2 : 1)); 722 1.1 cjep } 723