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