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