xref: /reactos/base/applications/cmdutils/find/find.c (revision 84ccccab)
1 /* find.c */
2 
3 /* Copyright (C) 1994-2002, Jim Hall <jhall@freedos.org> */
4 
5 /* Adapted for ReactOS */
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 
33 #include <windef.h>
34 #include <winbase.h>
35 #include <winuser.h>
36 
37 //#include <io.h>
38 #include <dos.h>
39 
40 #include "resource.h"
41 
42 /* Symbol definition */
43 #define MAX_STR 1024
44 
45 /* This function prints out all lines containing a substring.  There are some
46  * conditions that may be passed to the function.
47  *
48  * RETURN: If the string was found at least once, returns 1.
49  * If the string was not found at all, returns 0.
50  */
51 int
52 find_str (char *sz, FILE *p, int invert_search,
53           int count_lines, int number_output, int ignore_case)
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   WCHAR wszUsage[4096];
129   char oemUsage[4096];
130 
131   LoadStringW (GetModuleHandleW (NULL), IDS_USAGE, wszUsage, sizeof(wszUsage) / sizeof(wszUsage[0]));
132   CharToOemW (wszUsage, oemUsage);
133   fputs (oemUsage, stdout);
134 }
135 
136 
137 /* Main program */
138 int
139 main (int argc, char **argv)
140 {
141   char *opt, *needle = NULL;
142   int ret = 0;
143   WCHAR wszMessage[4096];
144   char oemMessage[4096];
145 
146   int invert_search = 0;		/* flag to invert the search */
147   int count_lines = 0;			/* flag to whether/not count lines */
148   int number_output = 0;		/* flag to print line numbers */
149   int ignore_case = 0;			/* flag to be case insensitive */
150 
151   FILE *pfile;				/* file pointer */
152   int hfind;				/* search handle */
153   struct _finddata_t finddata;		/* _findfirst, filenext block */
154 
155   /* Scan the command line */
156   while ((--argc) && (needle == NULL))
157     {
158       if (*(opt = *++argv) == '/')
159         {
160           switch (opt[1])
161 	    {
162 	      case 'c':
163 	      case 'C':		/* Count */
164 	        count_lines = 1;
165 	        break;
166 
167 	      case 'i':
168 	      case 'I':		/* Ignore */
169 	        ignore_case = 1;
170 	        break;
171 
172 	      case 'n':
173 	      case 'N':		/* Number */
174 	        number_output = 1;
175 	        break;
176 
177 	      case 'v':
178 	      case 'V':		/* Not with */
179 	        invert_search = 1;
180 	        break;
181 
182 	      default:
183 	        usage ();
184 	        exit (2);		/* syntax error .. return error 2 */
185 	        break;
186 	    }
187         }
188       else
189         {
190           /* Get the string */
191 	  if (needle == NULL)
192 	    {
193               /* Assign the string to find */
194               needle = *argv;
195 	    }
196 	}
197     }
198 
199   /* Check for search string */
200   if (needle == NULL)
201     {
202       /* No string? */
203       usage ();
204       exit (1);
205     }
206 
207   /* Scan the files for the string */
208   if (argc == 0)
209     {
210       ret = find_str (needle, stdin, invert_search, count_lines,
211                       number_output, ignore_case);
212     }
213 
214   while (--argc >= 0)
215     {
216       hfind = _findfirst (*++argv, &finddata);
217       if (hfind < 0)
218 	{
219 	  /* We were not able to find a file. Display a message and
220 	     set the exit status. */
221 	  LoadStringW (GetModuleHandleW (NULL), IDS_NO_SUCH_FILE, wszMessage, sizeof(wszMessage) / sizeof(wszMessage[0]));
222 	  CharToOemW (wszMessage, oemMessage);
223 	  fprintf (stderr, oemMessage, *argv);
224 	}
225       else
226         {
227           /* repeat find next file to match the filemask */
228 	  do
229             {
230               /* We have found a file, so try to open it */
231 	      if ((pfile = fopen (finddata.name, "r")) != NULL)
232 	        {
233 	          printf ("---------------- %s\n", finddata.name);
234 	          ret = find_str (needle, pfile, invert_search, count_lines,
235 	                          number_output, ignore_case);
236 	          fclose (pfile);
237 	        }
238  	      else
239 	        {
240 	          LoadStringW (GetModuleHandleW (NULL), IDS_CANNOT_OPEN, wszMessage, sizeof(wszMessage) / sizeof(wszMessage[0]));
241 	          CharToOemW (wszMessage, oemMessage);
242 	          fprintf (stderr, oemMessage,
243 		           finddata.name);
244                 }
245 	    }
246           while (_findnext(hfind, &finddata) > 0);
247         }
248       _findclose(hfind);
249     } /* for each argv */
250 
251  /* RETURN: If the string was found at least once, returns 0.
252   * If the string was not found at all, returns 1.
253   * (Note that find_str.c returns the exact opposite values.)
254   */
255   exit ( (ret ? 0 : 1) );
256 }
257