Sync with trunk r63831.
[reactos.git] / base / applications / findstr / findstr.c
1 /* findstr.c */
2
3 /* Copyright (C) 1994-2002, Jim Hall <jhall@freedos.org> */
4
5 /* Adapted for ReactOS -Edited for Findstr.exe K'Williams */
6
7 /*
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23
24 /* This program locates a string in a text file and prints those lines
25 * that contain the string. Multiple files are clearly separated.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 //#include <string.h>
31 //#include <ctype.h>
32 #include <windef.h>
33 #include <winbase.h>
34 #include <winuser.h>
35 //#include <io.h>
36 #include <dos.h>
37
38 #include "resource.h"
39
40 /* Symbol definition */
41 #define MAX_STR 1024
42
43
44 /* This function prints out all lines containing a substring. There are some
45 * conditions that may be passed to the function.
46 *
47 * RETURN: If the string was found at least once, returns 1.
48 * If the string was not found at all, returns 0.
49 */
50 int
51 find_str (char *sz, FILE *p, int invert_search,
52 int count_lines, int number_output, int ignore_case, int at_start, int literal_search,
53 int at_end, int reg_express, int exact_match, int sub_dirs, int only_fname)
54 {
55 int i, length;
56 long line_number = 0, total_lines = 0;
57 char *c, temp_str[MAX_STR], this_line[MAX_STR];
58
59 /* Convert to upper if needed */
60 if (ignore_case)
61 {
62 length = strlen (sz);
63 for (i = 0; i < length; i++)
64 sz[i] = toupper (sz[i]);
65 }
66
67 /* Scan the file until EOF */
68 while (fgets (temp_str, MAX_STR, p) != NULL)
69 {
70 /* Remove the trailing newline */
71 length = strlen (temp_str);
72 if (temp_str[length-1] == '\n')
73 {
74 temp_str[length-1] = '\0';
75 }
76
77 /* Increment number of lines */
78 line_number++;
79 strcpy (this_line, temp_str);
80
81 /* Convert to upper if needed */
82 if (ignore_case)
83 {
84 for (i = 0; i < length; i++)
85 {
86 temp_str[i] = toupper (temp_str[i]);
87 }
88 }
89
90 /* Locate the substring */
91
92 /* strstr() returns a pointer to the first occurrence in the
93 string of the substring */
94 c = strstr (temp_str, sz);
95
96 if ( ((invert_search) ? (c == NULL) : (c != NULL)) )
97 {
98 if (!count_lines)
99 {
100 if (number_output)
101 printf ("%ld:", line_number);
102
103 /* Print the line of text */
104 puts (this_line);
105 }
106
107 total_lines++;
108 } /* long if */
109 } /* while fgets */
110
111 if (count_lines)
112 {
113 /* Just show num. lines that contain the string */
114 printf ("%ld\n", total_lines);
115 }
116
117
118 /* RETURN: If the string was found at least once, returns 1.
119 * If the string was not found at all, returns 0.
120 */
121 return (total_lines > 0 ? 1 : 0);
122 }
123
124 /* Show usage */
125 void
126 usage (void)
127 {
128 TCHAR lpUsage[4096];
129
130 LoadString( GetModuleHandle(NULL), IDS_USAGE, (LPTSTR)lpUsage, 4096);
131 CharToOem(lpUsage, lpUsage);
132 printf( lpUsage );
133 }
134
135
136 /* Main program */
137 int
138 main (int argc, char **argv)
139 {
140 char *opt, *needle = NULL;
141 int ret = 0;
142 TCHAR lpMessage[4096];
143
144 int invert_search = 0; /* flag to invert the search */
145 int count_lines = 0; /* flag to whether/not count lines */
146 int number_output = 0; /* flag to print line numbers */
147 int ignore_case = 0; /* flag to be case insensitive */
148 int at_start = 0; /* flag to Match if at the beginning of a line. */
149 int at_end = 0; /* flag to Match if at the beginning of a line. */
150 int reg_express = 0; /* flag to use/not use regular expressions */
151 int exact_match = 0; /* flag to be exact match */
152 int sub_dirs= 0; /* this and all subdirectories */
153 int only_fname= 0; /* print only the name of the file*/
154 int literal_search=0;
155
156 FILE *pfile; /* file pointer */
157 int hfind; /* search handle */
158 struct _finddata_t finddata; /* _findfirst, filenext block */
159
160 /* Scan the command line */
161 while ((--argc) && (needle == NULL))
162 {
163 if (*(opt = *++argv) == '/')
164 {
165 switch (opt[1])
166 {
167 case 'b':
168 case 'B': /* Matches pattern if at the beginning of a line */
169 at_start = 1;
170 break;
171
172 //case 'c':
173 //case 'C': /* Literal? */
174 // literal_search = 1;
175 // break;
176
177 case 'e':
178 case 'E': /* matches pattern if at end of line */
179 at_end = 1;
180 break;
181
182 case 'i':
183 case 'I': /* Ignore */
184 ignore_case = 1;
185 break;
186
187 case 'm':
188 case 'M': /* only filename */
189 only_fname = 1;
190 break;
191
192 case 'n':
193 case 'N': /* Number */
194 number_output = 1;
195 break;
196
197 case 'r':
198 case 'R': /* search strings as regular expressions */
199 reg_express = 1;
200 break;
201
202 case 's':
203 case 'S': /* search files in child directory too*/
204 sub_dirs = 1;
205 break;
206
207 case 'v':
208 case 'V': /* Not with */
209 invert_search = 1;
210 break;
211
212 case 'x':
213 case 'X': /* exact match */
214 exact_match = 1;
215 break;
216
217 default:
218 usage ();
219 exit (2); /* syntax error .. return error 2 */
220 break;
221 }
222 }
223 else
224 {
225 /* Get the string */
226 if (needle == NULL)
227 {
228 /* Assign the string to find */
229 needle = *argv;
230 }
231 }
232 }
233
234 /* Check for search string */
235 if (needle == NULL)
236 {
237 /* No string? */
238 usage ();
239 exit (1);
240 }
241
242 /* Scan the files for the string */
243 if (argc == 0)
244 {
245 ret = find_str (needle, stdin, invert_search, count_lines,
246 number_output, ignore_case, at_start, literal_search, at_end, reg_express, exact_match,
247 sub_dirs, only_fname);
248 }
249
250 while (--argc >= 0)
251 {
252 hfind = _findfirst (*++argv, &finddata);
253 if (hfind < 0)
254 {
255 /* We were not able to find a file. Display a message and
256 set the exit status. */
257 LoadString( GetModuleHandle(NULL), IDS_NO_SUCH_FILE, (LPTSTR)lpMessage, 4096);
258 CharToOem(lpMessage, lpMessage);
259 fprintf (stderr, lpMessage, *argv);//
260 }
261 else
262 {
263 /* repeat find next file to match the filemask */
264 do
265 {
266 /* We have found a file, so try to open it */
267 if ((pfile = fopen (finddata.name, "r")) != NULL)
268 {
269 printf ("---------------- %s\n", finddata.name);
270 ret = find_str (needle, pfile, invert_search, count_lines,
271 number_output, ignore_case, at_start, literal_search, at_end, reg_express, exact_match,
272 sub_dirs, only_fname);
273 fclose (pfile);
274 }
275 else
276 {
277 LoadString(GetModuleHandle(NULL), IDS_CANNOT_OPEN, (LPTSTR)lpMessage, 4096);
278 CharToOem(lpMessage, lpMessage);
279 fprintf (stderr, lpMessage,
280 finddata.name);
281 }
282 }
283 while (_findnext(hfind, &finddata) > 0);
284 }
285 _findclose(hfind);
286 } /* for each argv */
287
288 /* RETURN: If the string was found at least once, returns 0.
289 * If the string was not found at all, returns 1.
290 * (Note that find_str.c returns the exact opposite values.)
291 */
292 exit ( (ret ? 0 : 1) );
293 }
294
295