| /* |
| * Mini grep implementation for busybox using libc regex. |
| * |
| * Copyright (C) 1999,2000 by Lineo, inc. |
| * Written by Mark Whitley <markw@lineo.com>, <markw@enol.com> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <unistd.h> /* for getopt() */ |
| #include <regex.h> |
| #include <string.h> /* for strerror() */ |
| #include <errno.h> |
| #include "internal.h" |
| |
| extern int optind; /* in unistd.h */ |
| extern int errno; /* for use with strerror() */ |
| |
| static const char grep_usage[] = |
| "grep [-ihHnqvs] pattern [files...]\n" |
| #ifndef BB_FEATURE_TRIVIAL_HELP |
| "\nSearch for PATTERN in each FILE or standard input.\n\n" |
| "OPTIONS:\n" |
| "\t-H\tprefix output lines with filename where match was found\n" |
| "\t-h\tsuppress the prefixing filename on output\n" |
| "\t-i\tignore case distinctions\n" |
| "\t-n\tprint line number with output lines\n" |
| "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" |
| "\t-v\tselect non-matching lines\n" |
| "\t-s\tsuppress file open/read error messages\n\n" |
| #endif |
| ; |
| |
| /* options */ |
| static int ignore_case = 0; |
| static int print_filename = 0; |
| static int print_line_num = 0; |
| static int be_quiet = 0; |
| static int invert_search = 0; |
| static int suppress_err_msgs = 0; |
| |
| /* globals */ |
| static regex_t regex; /* storage space for compiled regular expression */ |
| static int nmatches = 0; /* keeps track of the number of matches */ |
| static char *cur_file = NULL; /* the current file we are reading */ |
| |
| |
| static void print_matched_line(char *line, int linenum) |
| { |
| if (print_filename) |
| printf("%s:", cur_file); |
| if (print_line_num) |
| printf("%i:", linenum); |
| |
| printf("%s", line); |
| } |
| |
| static void grep_file(FILE *file) |
| { |
| char *line = NULL; |
| int ret; |
| int linenum = 0; |
| |
| while ((line = get_line_from_file(file)) != NULL) { |
| linenum++; |
| ret = regexec(®ex, line, 0, NULL, 0); |
| if (ret == 0 && !invert_search) { /* match */ |
| |
| /* if we found a match but were told to be quiet, stop here and |
| * return success */ |
| if (be_quiet) { |
| regfree(®ex); |
| exit(0); |
| } |
| |
| nmatches++; |
| |
| print_matched_line(line, linenum); |
| |
| } else if (ret == REG_NOMATCH && invert_search) { |
| print_matched_line(line, linenum); |
| } |
| |
| free(line); |
| } |
| } |
| |
| extern int grep_main(int argc, char **argv) |
| { |
| int opt; |
| int reflags; |
| int ret; |
| |
| /* do special-case option parsing */ |
| if (argv[1] && (strcmp(argv[1], "--help") == 0)) |
| usage(grep_usage); |
| |
| /* do normal option parsing */ |
| while ((opt = getopt(argc, argv, "iHhnqvs")) > 0) { |
| switch (opt) { |
| case 'i': |
| ignore_case++; |
| break; |
| case 'H': |
| print_filename++; |
| break; |
| case 'h': |
| print_filename--; |
| break; |
| case 'n': |
| print_line_num++; |
| break; |
| case 'q': |
| be_quiet++; |
| break; |
| case 'v': |
| invert_search++; |
| break; |
| case 's': |
| suppress_err_msgs++; |
| break; |
| } |
| } |
| |
| /* argv[optind] should be the regex pattern; no pattern, no worky */ |
| if (argv[optind] == NULL) |
| usage(grep_usage); |
| |
| /* compile the regular expression */ |
| reflags = REG_NOSUB; /* we're not going to mess with sub-expressions */ |
| if (ignore_case) |
| reflags |= REG_ICASE; |
| if ((ret = regcomp(®ex, argv[optind], reflags)) != 0) { |
| int errmsgsz = regerror(ret, ®ex, NULL, 0); |
| char *errmsg = malloc(errmsgsz); |
| if (errmsg == NULL) { |
| fprintf(stderr, "grep: memory error\n"); |
| regfree(®ex); |
| exit(1); |
| } |
| regerror(ret, ®ex, errmsg, errmsgsz); |
| fprintf(stderr, "grep: %s\n", errmsg); |
| free(errmsg); |
| regfree(®ex); |
| exit(1); |
| } |
| |
| /* argv[(optind+1)..(argc-1)] should be names of file to grep through. If |
| * there is more than one file to grep, we will print the filenames */ |
| if ((argc-1) - (optind+1) > 0) |
| print_filename++; |
| |
| /* If no files were specified, or '-' was specified, take input from |
| * stdin. Otherwise, we grep through all the files specified. */ |
| if (argv[optind+1] == NULL || (strcmp(argv[optind+1], "-") == 0)) { |
| grep_file(stdin); |
| } else { |
| int i; |
| FILE *file; |
| for (i = optind + 1; i < argc; i++) { |
| cur_file = argv[i]; |
| file = fopen(cur_file, "r"); |
| if (file == NULL) { |
| if (!suppress_err_msgs) |
| fprintf(stderr, "grep: %s: %s\n", cur_file, strerror(errno)); |
| } else { |
| grep_file(file); |
| fclose(file); |
| } |
| } |
| } |
| |
| regfree(®ex); |
| |
| if (nmatches == 0) |
| return 1; |
| |
| return 0; |
| } |