aboutsummaryrefslogtreecommitdiff
path: root/findutils/grep.c
diff options
context:
space:
mode:
authorMark Whitley <markw@lineo.com>2000-06-28 22:00:26 +0000
committerMark Whitley <markw@lineo.com>2000-06-28 22:00:26 +0000
commitd37218941c37795cc8e96ddb3312d83fb2269d5a (patch)
treef0b2aa0f49da8e0d4fb76a81a491e1d1ee5c4a05 /findutils/grep.c
parent268b8c4f387b9019bbb3591fb07403925d55d0c5 (diff)
downloadbusybox-w32-d37218941c37795cc8e96ddb3312d83fb2269d5a.tar.gz
busybox-w32-d37218941c37795cc8e96ddb3312d83fb2269d5a.tar.bz2
busybox-w32-d37218941c37795cc8e96ddb3312d83fb2269d5a.zip
Brand, spankin', new grep that uses libc regex routines instead of the
hand-rolled ones. Sed still needs to be replaced and then the regexp stuff can be axed.
Diffstat (limited to 'findutils/grep.c')
-rw-r--r--findutils/grep.c255
1 files changed, 155 insertions, 100 deletions
diff --git a/findutils/grep.c b/findutils/grep.c
index 0e495ff87..aca469e2f 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -1,10 +1,8 @@
1/* vi: set sw=4 ts=4: */
2/* 1/*
3 * Mini grep implementation for busybox 2 * Mini grep implementation for busybox using libc regex.
4 *
5 * 3 *
6 * Copyright (C) 1999,2000 by Lineo, inc. 4 * Copyright (C) 1999,2000 by Lineo, inc.
7 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org> 5 * Written by Mark Whitley <markw@lineo.com>, <markw@enol.com>
8 * 6 *
9 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -22,149 +20,206 @@
22 * 20 *
23 */ 21 */
24 22
25/*
26 18-Dec-1999 Konstantin Boldyshev <konst@voshod.com>
27
28 + -q option (be quiet)
29 + exit code depending on grep result (TRUE or FALSE)
30 (useful for scripts)
31*/
32
33#include "internal.h"
34#include "regexp.h"
35#include <stdio.h> 23#include <stdio.h>
36#include <dirent.h> 24#include <stdlib.h>
25#include <unistd.h> /* for getopt() */
26#include <regex.h>
27#include <string.h> /* for strerror() */
37#include <errno.h> 28#include <errno.h>
38#include <fcntl.h> 29#include "internal.h"
39#include <signal.h> 30
40#include <time.h> 31extern int optind; /* in unistd.h */
41#include <ctype.h> 32extern int errno; /* for use with strerror() */
42#define BB_DECLARE_EXTERN
43#define bb_need_too_few_args
44#include "messages.c"
45 33
46static const char grep_usage[] = 34static const char grep_usage[] =
47 "grep [OPTIONS]... PATTERN [FILE]...\n" 35 "grep [-ihHnqvs] pattern [files...]\n"
48#ifndef BB_FEATURE_TRIVIAL_HELP 36#ifndef BB_FEATURE_TRIVIAL_HELP
49 "\nSearch for PATTERN in each FILE or standard input.\n\n" 37 "\nSearch for PATTERN in each FILE or standard input.\n\n"
50 "OPTIONS:\n" 38 "OPTIONS:\n"
39 "\t-H\tprefix output lines with filename where match was found\n"
51 "\t-h\tsuppress the prefixing filename on output\n" 40 "\t-h\tsuppress the prefixing filename on output\n"
52 "\t-i\tignore case distinctions\n" 41 "\t-i\tignore case distinctions\n"
53 "\t-n\tprint line number with output lines\n" 42 "\t-n\tprint line number with output lines\n"
54 "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" 43 "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n"
55 "\t-v\tselect non-matching lines\n\n" 44 "\t-v\tselect non-matching lines\n"
56#if defined BB_REGEXP 45 "\t-s\tsuppress file open/read error messages\n\n"
57 "This version of grep matches full regular expressions.\n";
58#else
59 "This version of grep matches strings (not regular expressions).\n"
60#endif
61#endif 46#endif
62 ; 47 ;
63 48
64static int match = FALSE, beQuiet = FALSE; 49static const int GROWBY = 80; /* how large we will grow strings by */
50
51/* options */
52static int ignore_case = 0;
53static int print_filename = 0;
54static int print_line_num = 0;
55static int be_quiet = 0;
56static int invert_search = 0;
57static int suppress_err_msgs = 0;
58
59/* globals */
60static regex_t regex; /* storage space for compiled regular expression */
61static int nmatches = 0; /* keeps track of the number of matches */
62static char *cur_file = NULL; /* the current file we are reading */
63
65 64
66static void do_grep(FILE * fp, char *needle, char *fileName, int tellName, 65/* This returns a malloc'ed char * which must be stored and free'ed */
67 int ignoreCase, int tellLine, int invertSearch) 66/* XXX: This function should probably go in a 'common'/'util'/'misc' file
67 * somewhere so it can be used by other folks. */
68static char *get_line_from_file(FILE *file)
68{ 69{
69 long line = 0; 70 int ch;
70 char *haystack; 71 int idx = 0;
71 int truth = !invertSearch; 72 char *linebuf = NULL;
73 int linebufsz = 0;
74
75 while (1) {
76 ch = fgetc(file);
77 if (ch == EOF)
78 break;
79 /* grow the line buffer as necessary */
80 if (idx > linebufsz-1)
81 linebuf = realloc(linebuf, linebufsz += GROWBY);
82 linebuf[idx++] = (char)ch;
83 if ((char)ch == '\n')
84 break;
85 }
86
87 if (idx == 0)
88 return NULL;
89
90 linebuf[idx] = 0;
91 return linebuf;
92}
93
94static void print_matched_line(char *line, int linenum)
95{
96 if (print_filename)
97 printf("%s:", cur_file);
98 if (print_line_num)
99 printf("%i:", linenum);
100
101 printf("%s", line);
102}
72 103
73 while ((haystack = cstring_lineFromFile(fp))) { 104static void grep_file(FILE *file)
74 line++; 105{
75 if (find_match(haystack, needle, ignoreCase) == truth) { 106 char *line = NULL;
76 if (tellName == TRUE) 107 int ret;
77 printf("%s:", fileName); 108 int linenum = 0;
109
110 while ((line = get_line_from_file(file)) != NULL) {
111 linenum++;
112 ret = regexec(&regex, line, 0, NULL, 0);
113 if (ret == 0 && !invert_search) { /* match */
114
115 /* if we found a match but were told to be quiet, stop here and
116 * return success */
117 if (be_quiet) {
118 regfree(&regex);
119 exit(0);
120 }
78 121
79 if (tellLine == TRUE) 122 nmatches++;
80 printf("%ld:", line);
81 123
82 if (beQuiet == FALSE) 124 print_matched_line(line, linenum);
83 fputs(haystack, stdout);
84 125
85 match = TRUE; 126 } else if (ret == REG_NOMATCH && invert_search) {
127 print_matched_line(line, linenum);
86 } 128 }
87 free(haystack); 129
130 free(line);
88 } 131 }
89} 132}
90 133
91
92extern int grep_main(int argc, char **argv) 134extern int grep_main(int argc, char **argv)
93{ 135{
94 FILE *fp; 136 int opt;
95 char *needle; 137 int reflags;
96 char *fileName; 138 int ret;
97 int tellName = TRUE; 139
98 int ignoreCase = FALSE; 140 /* do special-case option parsing */
99 int tellLine = FALSE; 141 if (argv[1] && (strcmp(argv[1], "--help") == 0))
100 int invertSearch = FALSE;
101
102 if (argc < 1) {
103 usage(grep_usage); 142 usage(grep_usage);
104 }
105 argv++;
106 143
107 while (--argc >= 0 && *argv && (**argv == '-')) { 144 /* do normal option parsing */
108 while (*++(*argv)) { 145 while ((opt = getopt(argc, argv, "iHhnqvs")) > 0) {
109 switch (**argv) { 146 switch (opt) {
110 case 'i': 147 case 'i':
111 ignoreCase = TRUE; 148 ignore_case++;
149 break;
150 case 'H':
151 print_filename++;
112 break; 152 break;
113
114 case 'h': 153 case 'h':
115 tellName = FALSE; 154 print_filename--;
116 break; 155 break;
117
118 case 'n': 156 case 'n':
119 tellLine = TRUE; 157 print_line_num++;
120 break; 158 break;
121
122 case 'q': 159 case 'q':
123 beQuiet = TRUE; 160 be_quiet++;
124 break; 161 break;
125
126 case 'v': 162 case 'v':
127 invertSearch = TRUE; 163 invert_search++;
164 break;
165 case 's':
166 suppress_err_msgs++;
128 break; 167 break;
129
130 default:
131 usage(grep_usage);
132 }
133 } 168 }
134 argv++;
135 } 169 }
136 170
137 if (argc == 0 || *argv == NULL) { 171 /* argv[optind] should be the regex pattern; no pattern, no worky */
138 fatalError(too_few_args, "grep"); 172 if (argv[optind] == NULL)
173 usage(grep_usage);
174
175 /* compile the regular expression */
176 reflags = REG_NOSUB; /* we're not going to mess with sub-expressions */
177 if (ignore_case)
178 reflags |= REG_ICASE;
179 if ((ret = regcomp(&regex, argv[optind], reflags)) != 0) {
180 int errmsgsz = regerror(ret, &regex, NULL, 0);
181 char *errmsg = malloc(errmsgsz);
182 if (errmsg == NULL) {
183 fprintf(stderr, "grep: memory error\n");
184 regfree(&regex);
185 exit(1);
186 }
187 regerror(ret, &regex, errmsg, errmsgsz);
188 fprintf(stderr, "grep: %s\n", errmsg);
189 free(errmsg);
190 regfree(&regex);
191 exit(1);
139 } 192 }
140 193
141 needle = *argv++; 194 /* argv[(optind+1)..(argc-1)] should be names of file to grep through. If
142 argc--; 195 * there is more than one file to grep, we will print the filenames */
196 if ((argc-1) - (optind+1) > 0)
197 print_filename++;
143 198
144 if (argc == 0) { 199 /* If no files were specified, take input from stdin. Otherwise, we grep
145 do_grep(stdin, needle, "stdin", FALSE, ignoreCase, tellLine, invertSearch); 200 * through all the files specified. */
201 if (argv[optind+1] == NULL) {
202 grep_file(stdin);
146 } else { 203 } else {
147 /* Never print the filename for just one file */ 204 int i;
148 if (argc == 1) 205 FILE *file;
149 tellName = FALSE; 206 for (i = optind + 1; i < argc; i++) {
150 while (argc-- > 0) { 207 cur_file = argv[i];
151 fileName = *argv++; 208 file = fopen(cur_file, "r");
152 209 if (file == NULL) {
153 fp = fopen(fileName, "r"); 210 if (!suppress_err_msgs)
154 if (fp == NULL) { 211 fprintf(stderr, "grep: %s: %s\n", cur_file, strerror(errno));
155 perror(fileName); 212 } else {
156 continue; 213 grep_file(file);
214 fclose(file);
157 } 215 }
158
159 do_grep(fp, needle, fileName, tellName, ignoreCase, tellLine, invertSearch);
160
161 if (ferror(fp))
162 perror(fileName);
163 fclose(fp);
164 } 216 }
165 } 217 }
166 return(match);
167}
168 218
219 regfree(&regex);
169 220
170/* END CODE */ 221 if (nmatches == 0)
222 return 1;
223
224 return 0;
225}