xref: /reactos/base/applications/findstr/findstr.c (revision 1de09c47)
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 
296