📄 grep.c
字号:
finish_grep: done_on_match -= not_text; out_quiet -= not_text; if ((not_text & ~out_quiet) && nlines != 0) printf (_("Binary file %s matches\n"), filename); return nlines;}static intgrepfile (char const *file, struct stats *stats){ int desc; int count; int status; if (! file) { desc = 0; filename = label ? label : _("(standard input)"); } else { while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR) continue; if (desc < 0) { int e = errno; if (is_EISDIR (e, file) && directories == RECURSE_DIRECTORIES) { if (stat (file, &stats->stat) != 0) { error (0, errno, "%s", file); return 1; } return grepdir (file, stats); } if (!suppress_errors) { if (directories == SKIP_DIRECTORIES) switch (e) {#if defined(EISDIR) case EISDIR: return 1;#endif case EACCES: /* When skipping directories, don't worry about directories that can't be opened. */ if (isdir (file)) return 1; break; } } suppressible_error (file, e); return 1; } filename = file; }#if defined(SET_BINARY) /* Set input to binary mode. Pipes are simulated with files on DOS, so this includes the case of "foo | grep bar". */ if (!isatty (desc)) SET_BINARY (desc);#endif count = grep (desc, file, stats); if (count < 0) status = count + 2; else { if (count_matches) { if (out_file) printf ("%s%c", filename, ':' & filename_mask); printf ("%d\n", count); } status = !count; if (list_files == 1 - 2 * status) printf ("%s%c", filename, '\n' & filename_mask); if (! file) { off_t required_offset = outleft ? bufoffset : after_last_match; if ((bufmapped || required_offset != bufoffset) && lseek (desc, required_offset, SEEK_SET) < 0 && S_ISREG (stats->stat.st_mode)) error (0, errno, "%s", filename); } else while (close (desc) != 0) if (errno != EINTR) { error (0, errno, "%s", file); break; } } return status;}static intgrepdir (char const *dir, struct stats const *stats){ int status = 1; struct stats const *ancestor; char *name_space; /* Mingw32 does not support st_ino. No known working hosts use zero for st_ino, so assume that the Mingw32 bug applies if it's zero. */ if (stats->stat.st_ino) for (ancestor = stats; (ancestor = ancestor->parent) != 0; ) if (ancestor->stat.st_ino == stats->stat.st_ino && ancestor->stat.st_dev == stats->stat.st_dev) { if (!suppress_errors) error (0, 0, _("warning: %s: %s\n"), dir, _("recursive directory loop")); return 1; } name_space = savedir (dir, stats->stat.st_size, included_patterns, excluded_patterns); if (! name_space) { if (errno) suppressible_error (dir, errno); else xalloc_die (); } else { size_t dirlen = strlen (dir); int needs_slash = ! (dirlen == FILESYSTEM_PREFIX_LEN (dir) || IS_SLASH (dir[dirlen - 1])); char *file = NULL; char const *namep = name_space; struct stats child; child.parent = stats; out_file += !no_filenames; while (*namep) { size_t namelen = strlen (namep); file = xrealloc (file, dirlen + 1 + namelen + 1); strcpy (file, dir); file[dirlen] = '/'; strcpy (file + dirlen + needs_slash, namep); namep += namelen + 1; status &= grepfile (file, &child); } out_file -= !no_filenames; if (file) free (file); free (name_space); } return status;}static voidusage (int status){ if (status != 0) { fprintf (stderr, _("Usage: %s [OPTION]... PATTERN [FILE]...\n"), program_name); fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); } else { printf (_("Usage: %s [OPTION]... PATTERN [FILE] ...\n"), program_name); printf (_("\Search for PATTERN in each FILE or standard input.\n\Example: %s -i 'hello world' menu.h main.c\n\\n\Regexp selection and interpretation:\n"), program_name); printf (_("\ -E, --extended-regexp PATTERN is an extended regular expression\n\ -F, --fixed-strings PATTERN is a set of newline-separated strings\n\ -G, --basic-regexp PATTERN is a basic regular expression\n\ -P, --perl-regexp PATTERN is a Perl regular expression\n")); printf (_("\ -e, --regexp=PATTERN use PATTERN as a regular expression\n\ -f, --file=FILE obtain PATTERN from FILE\n\ -i, --ignore-case ignore case distinctions\n\ -w, --word-regexp force PATTERN to match only whole words\n\ -x, --line-regexp force PATTERN to match only whole lines\n\ -z, --null-data a data line ends in 0 byte, not newline\n")); printf (_("\\n\Miscellaneous:\n\ -s, --no-messages suppress error messages\n\ -v, --invert-match select non-matching lines\n\ -V, --version print version information and exit\n\ --help display this help and exit\n\ --mmap use memory-mapped input if possible\n")); printf (_("\\n\Output control:\n\ -m, --max-count=NUM stop after NUM matches\n\ -b, --byte-offset print the byte offset with output lines\n\ -n, --line-number print line number with output lines\n\ --line-buffered flush output on every line\n\ -H, --with-filename print the filename for each match\n\ -h, --no-filename suppress the prefixing filename on output\n\ --label=LABEL print LABEL as filename for standard input\n\ -o, --only-matching show only the part of a line matching PATTERN\n\ -q, --quiet, --silent suppress all normal output\n\ --binary-files=TYPE assume that binary files are TYPE\n\ TYPE is 'binary', 'text', or 'without-match'\n\ -a, --text equivalent to --binary-files=text\n\ -I equivalent to --binary-files=without-match\n\ -d, --directories=ACTION how to handle directories\n\ ACTION is 'read', 'recurse', or 'skip'\n\ -D, --devices=ACTION how to handle devices, FIFOs and sockets\n\ ACTION is 'read' or 'skip'\n\ -R, -r, --recursive equivalent to --directories=recurse\n\ --include=PATTERN files that match PATTERN will be examined\n\ --exclude=PATTERN files that match PATTERN will be skipped.\n\ --exclude-from=FILE files that match PATTERN in FILE will be skipped.\n\ -L, --files-without-match only print FILE names containing no match\n\ -l, --files-with-matches only print FILE names containing matches\n\ -c, --count only print a count of matching lines per FILE\n\ -Z, --null print 0 byte after FILE name\n")); printf (_("\\n\Context control:\n\ -B, --before-context=NUM print NUM lines of leading context\n\ -A, --after-context=NUM print NUM lines of trailing context\n\ -C, --context=NUM print NUM lines of output context\n\ -NUM same as --context=NUM\n\ --color[=WHEN],\n\ --colour[=WHEN] use markers to distinguish the matching string\n\ WHEN may be `always', `never' or `auto'.\n\ -U, --binary do not strip CR characters at EOL (MSDOS)\n\ -u, --unix-byte-offsets report offsets as if CRs were not there (MSDOS)\n\\n\`egrep' means `grep -E'. `fgrep' means `grep -F'.\n\With no FILE, or when FILE is -, read standard input. If less than\n\two FILEs given, assume -h. Exit status is 0 if match, 1 if no match,\n\and 2 if trouble.\n")); printf (_("\nReport bugs to <bug-gnu-utils@gnu.org>.\n")); } exit (status);}/* Set the matcher to M, reporting any conflicts. */static voidsetmatcher (char const *m){ if (matcher && strcmp (matcher, m) != 0) error (2, 0, _("conflicting matchers specified")); matcher = m;}/* Go through the matchers vector and look for the specified matcher. If we find it, install it in compile and execute, and return 1. */static intinstall_matcher (char const *name){ int i;#if defined(HAVE_SETRLIMIT) struct rlimit rlim;#endif for (i = 0; matchers[i].compile; i++) if (strcmp (name, matchers[i].name) == 0) { compile = matchers[i].compile; execute = matchers[i].execute;#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK) /* I think every platform needs to do this, so that regex.c doesn't oveflow the stack. The default value of `re_max_failures' is too large for some platforms: it needs more than 3MB-large stack. The test for HAVE_SETRLIMIT should go into `configure'. */ if (!getrlimit (RLIMIT_STACK, &rlim)) { long newlim; extern long int re_max_failures; /* from regex.c */ /* Approximate the amount regex.c needs, plus some more. */ newlim = re_max_failures * 2 * 20 * sizeof (char *); if (newlim > rlim.rlim_max) { newlim = rlim.rlim_max; re_max_failures = newlim / (2 * 20 * sizeof (char *)); } if (rlim.rlim_cur < newlim) { rlim.rlim_cur = newlim; setrlimit (RLIMIT_STACK, &rlim); } }#endif return 1; } return 0;}/* Find the white-space-separated options specified by OPTIONS, and using BUF to store copies of these options, set ARGV[0], ARGV[1], etc. to the option copies. Return the number N of options found. Do not set ARGV[N] to NULL. If ARGV is NULL, do not store ARGV[0] etc. Backslash can be used to escape whitespace (and backslashes). */static intprepend_args (char const *options, char *buf, char **argv){ char const *o = options; char *b = buf; int n = 0; for (;;) { while (ISSPACE ((unsigned char) *o)) o++; if (!*o) return n; if (argv) argv[n] = b; n++; do if ((*b++ = *o++) == '\\' && *o) b[-1] = *o++; while (*o && ! ISSPACE ((unsigned char) *o)); *b++ = '\0'; }}/* Prepend the whitespace-separated options in OPTIONS to the argument vector of a main program with argument count *PARGC and argument vector *PARGV. */static voidprepend_default_options (char const *options, int *pargc, char ***pargv){ if (options) { char *buf = xmalloc (strlen (options) + 1); int prepended = prepend_args (options, buf, (char **) NULL); int argc = *pargc; char * const *argv = *pargv; char **pp = (char **) xmalloc ((prepended + argc + 1) * sizeof *pp); *pargc = prepended + argc; *pargv = pp; *pp++ = *argv++; pp += prepend_args (options, buf, pp); while ((*pp++ = *argv++)) continue; }}/* Get the next non-digit option from ARGC and ARGV. Return -1 if there are no more options. Process any digit options that were encountered on the way, and store the resulting integer into *DEFAULT_CONTEXT. */static intget_nondigit_option (int argc, char *const *argv, int *default_context){ int opt; char buf[sizeof (uintmax_t) * CHAR_BIT + 4]; char *p = buf; /* Set buf[0] to anything but '0', for the leading-zero test below. */ buf[0] = '\0'; while (opt = getopt_long (argc, argv, short_options, long_options, NULL), '0' <= opt && opt <= '9') { /* Suppress trivial leading zeros, to avoid incorrect diagnostic on strings like 00000000000. */ p -= buf[0] == '0'; *p++ = opt; if (p == buf + sizeof buf - 4) { /* Too many digits. Append "..." to make context_length_arg complain about "X...", where X contains the digits seen so far. */ strcpy (p, "..."); p += 3; break; } } if (p != buf) { *p = '\0'; context_length_arg (buf, default_context); } return opt;}intmain (int argc, char **argv){ char *keys; size_t keycc, oldcc, keyalloc; int with_filenames; int opt, cc, status; int default_context; FILE *fp; extern char *optarg; extern int optind; initialize_main (&argc, &argv); program_name = argv[0]; if (program_name && strrchr (program_name, '/')) program_name = strrchr (program_name, '/') + 1; if (!strcmp(program_name, "egrep")) setmatcher ("egrep"); if (!strcmp(program_name, "fgrep")) setmatcher ("fgrep");#if defined(__MSDOS__) || defined(_WIN32) /* DOS and MS-Windows use backslashes as directory separators, and usually have an .exe suffix. They also have case-insensitive filesystems. */ if (program_name) { char *p = program_name; char *bslash = strrchr (argv[0], '\\'); if (bslash && bslash >= program_name) /* for mixed forward/backslash case */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -