e9ff91b3ee3d52dd8df100ac29e28c7a0aff5435
[platform/upstream/busybox.git] / grep.c
1 /*
2  * Mini grep implementation for busybox using libc regex.
3  *
4  * Copyright (C) 1999,2000 by Lineo, inc.
5  * Written by Mark Whitley <markw@lineo.com>, <markw@codepoet.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <getopt.h>
26 #include <regex.h>
27 #include <string.h> /* for strerror() */
28 #include <errno.h>
29 #include "busybox.h"
30
31 extern void xregcomp(regex_t *preg, const char *regex, int cflags);
32
33 extern int optind; /* in unistd.h */
34 extern int errno;  /* for use with strerror() */
35
36 /* options */
37 static int ignore_case       = 0;
38 static int print_filename    = 0;
39 static int print_line_num    = 0;
40 static int print_count_only  = 0;
41 static int be_quiet          = 0;
42 static int invert_search     = 0;
43 static int suppress_err_msgs = 0;
44
45 /* globals */
46 static regex_t regex; /* storage space for compiled regular expression */
47 static int matched; /* keeps track of whether we ever matched */
48 static char *cur_file = NULL; /* the current file we are reading */
49
50
51 static void print_matched_line(char *line, int linenum)
52 {
53         if (print_count_only)
54                 return;
55
56         if (print_filename)
57                 printf("%s:", cur_file);
58         if (print_line_num)
59                 printf("%i:", linenum);
60
61         puts(line);
62 }
63
64 static void grep_file(FILE *file)
65 {
66         char *line = NULL;
67         int ret;
68         int linenum = 0;
69         int nmatches = 0;
70
71         while ((line = get_line_from_file(file)) != NULL) {
72                 if (line[strlen(line)-1] == '\n')
73                         line[strlen(line)-1] = '\0';
74                 linenum++;
75                 ret = regexec(&regex, line, 0, NULL, 0);
76                 if (ret == 0 && !invert_search) { /* match */
77
78                         /* if we found a match but were told to be quiet, stop here and
79                          * return success */
80                         if (be_quiet) {
81                                 regfree(&regex);
82                                 exit(0);
83                         }
84
85                         nmatches++;
86                         print_matched_line(line, linenum);
87
88                 }
89                 else if (ret == REG_NOMATCH && invert_search) {
90                         if (be_quiet) {
91                                 regfree(&regex);
92                                 exit(0);
93                         }
94
95                         nmatches++;
96                         print_matched_line(line, linenum);
97                 }
98
99                 free(line);
100         }
101
102         /* special-case post processing */
103         if (print_count_only) {
104                 if (print_filename)
105                         printf("%s:", cur_file);
106                 printf("%i\n", nmatches);
107         }
108
109         /* record if we matched */
110         if (nmatches != 0)
111                 matched = 1;
112 }
113
114 extern int grep_main(int argc, char **argv)
115 {
116         int opt;
117         int reflags;
118
119         /* do normal option parsing */
120         while ((opt = getopt(argc, argv, "iHhnqvsc")) > 0) {
121                 switch (opt) {
122                         case 'i':
123                                 ignore_case++;
124                                 break;
125                         case 'H':
126                                 print_filename++;
127                                 break;
128                         case 'h':
129                                 print_filename--;
130                                 break;
131                         case 'n':
132                                 print_line_num++;
133                                 break;
134                         case 'q':
135                                 be_quiet++;
136                                 break;
137                         case 'v':
138                                 invert_search++;
139                                 break;
140                         case 's':
141                                 suppress_err_msgs++;
142                                 break;
143                         case 'c':
144                                 print_count_only++;
145                                 break;
146                 }
147         }
148
149         /* argv[optind] should be the regex pattern; no pattern, no worky */
150         if (argv[optind] == NULL)
151                 usage(grep_usage);
152
153         /* compile the regular expression
154          * we're not going to mess with sub-expressions, and we need to
155          * treat newlines right. */
156         reflags = REG_NOSUB; 
157         if (ignore_case)
158                 reflags |= REG_ICASE;
159         xregcomp(&regex, argv[optind], reflags);
160
161         /* argv[(optind+1)..(argc-1)] should be names of file to grep through. If
162          * there is more than one file to grep, we will print the filenames */
163         if ((argc-1) - (optind+1) > 0)
164                 print_filename++;
165
166         /* If no files were specified, or '-' was specified, take input from
167          * stdin. Otherwise, we grep through all the files specified. */
168         if (argv[optind+1] == NULL || (strcmp(argv[optind+1], "-") == 0)) {
169                 grep_file(stdin);
170         }
171         else {
172                 int i;
173                 FILE *file;
174                 for (i = optind + 1; i < argc; i++) {
175                         cur_file = argv[i];
176                         file = fopen(cur_file, "r");
177                         if (file == NULL) {
178                                 if (!suppress_err_msgs)
179                                         perror_msg("%s", cur_file);
180                         }
181                         else {
182                                 grep_file(file);
183                                 fclose(file);
184                         }
185                 }
186         }
187
188         regfree(&regex);
189
190         if (!matched)
191                 return 1;
192
193         return 0;
194 }