1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2011 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or (at
8 // your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 
19 #include <common/ac/stdio.h>
20 #include <common/ac/stdlib.h>
21 
22 #include <common/env.h>
23 #include <common/language.h>
24 #include <common/progname.h>
25 #include <common/quit.h>
26 #include <common/rsrc_limits.h>
27 #include <libaegis/change/file.h>
28 #include <libaegis/change/identifier.h>
29 #include <libaegis/help.h>
30 #include <libaegis/os.h>
31 #include <libaegis/version.h>
32 
33 #include <aegrep/arglex3.h>
34 
35 #include <sys/types.h>
36 #include <sys/wait.h>
37 
38 
39 static void
grep_usage(void)40 grep_usage(void)
41 {
42     const char *progname = progname_get();
43     fprintf(stderr, "Usage: %s [ <option>... ] <pattern>\n", progname);
44     fprintf(stderr, "       %s -Help\n", progname);
45     quit(1);
46 }
47 
48 
49 static void
grep_help(void)50 grep_help(void)
51 {
52     help((char *)0, grep_usage);
53 }
54 
55 
56 int
main(int argc,char ** argv)57 main(int argc, char **argv)
58 {
59     resource_limits_init();
60     os_become_init_mortal();
61     arglex3_init(argc, argv);
62     env_initialize();
63     language_init();
64 
65     switch (arglex())
66     {
67     case arglex_token_help:
68         grep_help();
69         quit(0);
70 
71     case arglex_token_version:
72         version();
73         quit(0);
74     }
75 
76     change_identifier cid;
77     nstring pattern;
78     nstring grep_options;
79     while (arglex_token != arglex_token_eoln)
80     {
81         switch (arglex_token)
82         {
83         default:
84             generic_argument(grep_usage);
85             continue;
86 
87         case arglex_token_baseline:
88         case arglex_token_branch:
89         case arglex_token_change:
90         case arglex_token_delta:
91         case arglex_token_delta_date:
92         case arglex_token_delta_from_change:
93         case arglex_token_development_directory:
94         case arglex_token_grandparent:
95         case arglex_token_number:
96         case arglex_token_project:
97         case arglex_token_trunk:
98             cid.command_line_parse(grep_usage);
99             continue;
100 
101         case arglex_token_string:
102             if (!pattern.empty())
103                 grep_usage();
104             pattern = arglex_value.alv_string;
105             break;
106 
107         case arglex_token_base_relative:
108         case arglex_token_current_relative:
109             user_ty::relative_filename_preference_argument(grep_usage);
110             break;
111 
112         case arglex_token_after_context:
113             if (arglex() != arglex_token_string)
114                 option_needs_string(arglex_token_after_context, grep_usage);
115             grep_options += " --after-context="
116                 + nstring(arglex_value.alv_string).quote_shell();
117             break;
118 
119         case arglex_token_basic_regexp:
120             grep_options += " --basic-regexp";
121             break;
122 
123         case arglex_token_before_context:
124             if (arglex() != arglex_token_string)
125                 option_needs_string(arglex_token_before_context, grep_usage);
126             grep_options += " --before-context="
127                 + nstring(arglex_value.alv_string).quote_shell();
128             break;
129 
130         case arglex_token_binary:
131             grep_options += " --binary";
132             break;
133 
134         case arglex_token_binary_files:
135             if (arglex() != arglex_token_string)
136                 option_needs_string(arglex_token_binary_files, grep_usage);
137             grep_options += " --binary-files="
138                 + nstring(arglex_value.alv_string).quote_shell();
139             break;
140 
141         case arglex_token_byte_offset:
142             grep_options += " --byte-offset";
143             break;
144 
145         case arglex_token_color:
146             grep_options += " --color";
147             break;
148 
149         case arglex_token_context:
150             if (arglex() != arglex_token_number)
151                 option_needs_number(arglex_token_context, grep_usage);
152             grep_options +=
153                 nstring::format(" --context=%ld", arglex_value.alv_number);
154             break;
155 
156         case arglex_token_count:
157             grep_options += " --count";
158             break;
159 
160         case arglex_token_extended_regexp:
161             grep_options += " --extended-regexp";
162             break;
163 
164         case arglex_token_files_with_matches:
165             grep_options += " --files-with-matches";
166             break;
167 
168         case arglex_token_files_without_matches:
169             grep_options += " --files-without-match"; // [sic]
170             break;
171 
172         case arglex_token_fixed_strings:
173             grep_options += " --fixed-strings";
174             break;
175 
176         case arglex_token_ignore_case:
177             grep_options += " --ignore-case";
178             break;
179 
180         case arglex_token_invert_match:
181             grep_options += " --invert-match";
182             break;
183 
184         case arglex_token_initial_tab:
185             grep_options += " --initial-tab";
186             break;
187 
188         case arglex_token_line_buffered:
189             grep_options += " --line-buffered";
190             break;
191 
192         case arglex_token_line_number:
193             grep_options += " --line-number";
194             break;
195 
196         case arglex_token_line_regexp:
197             grep_options += " --line-regexp";
198             break;
199 
200         case arglex_token_maximum_count:
201             if (arglex() != arglex_token_number)
202                 option_needs_number(arglex_token_maximum_count, grep_usage);
203             grep_options +=
204                 nstring::format(" --max-count=%ld", arglex_value.alv_number);
205             break;
206 
207         case arglex_token_no_messages:
208             grep_options += " --no-messages";
209             break;
210 
211         case arglex_token_null:
212             grep_options += " --null";
213             break;
214 
215         case arglex_token_null_data:
216             grep_options += " --null-data";
217             break;
218 
219         case arglex_token_only_matching:
220             grep_options += " --only-matching";
221             break;
222 
223         case arglex_token_perl_regexp:
224             grep_options += " --perl-regexp";
225             break;
226 
227         case arglex_token_quiet:
228             grep_options += " --quiet";
229             break;
230 
231         case arglex_token_text:
232             grep_options += " --text";
233             break;
234 
235         case arglex_token_unix_byte_offsets:
236             grep_options += " --unix-byte-offsets";
237             break;
238 
239         case arglex_token_word_regexp:
240             grep_options += " --word-regexp";
241             break;
242 
243         case arglex_token_list:
244             grep_options += " --files-with-matches";
245             break;
246 
247         // FIXME: --exclude
248         // FIXME: --include
249         }
250         arglex();
251     }
252     cid.command_line_check(grep_usage);
253     if (pattern.empty())
254         grep_usage();
255 
256     //
257     // Grope each source file.
258     //
259     for (size_t j = 0; ; ++j)
260     {
261         fstate_src_ty *src =
262             change_file_nth(cid.get_cp(), j, view_path_extreme);
263         if (!src)
264             break;
265         nstring fn(src->file_name);
266         int unlink_p = 0;
267         nstring rfn(change_file_version_path(cid.get_cp(), src, &unlink_p));
268         nstring command =
269             "cat " + rfn.quote_shell() + " | grep --label=" + fn.quote_shell()
270             + " -H " + grep_options + nstring(pattern[0] == '-' ? "-e" : "")
271             + " " + pattern.quote_shell();
272         // Note: we deliberately don't echo the command.
273         int n = system(command.c_str());
274         if (unlink_p)
275             os_unlink_errok(rfn);
276         if (!WIFEXITED(n) || WEXITSTATUS(n) >= 2)
277             quit(1);
278     }
279 
280     //
281     // report success
282     //
283     quit(0);
284     return 0;
285 }
286