grep.c 17 KB

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