1 //
2 // aegis - project change supervisor
3 // Copyright (C) 2005-2008, 2010, 2012 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
16 // along 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 <common/trace.h>
28 #include <libaegis/arglex2.h>
29 #include <libaegis/arglex/change.h>
30 #include <libaegis/arglex/project.h>
31 #include <libaegis/change/file.h>
32 #include <libaegis/change/identifier.h>
33 #include <libaegis/change.h>
34 #include <libaegis/fstate.fmtgen.h>
35 #include <libaegis/help.h>
36 #include <libaegis/os.h>
37 #include <libaegis/project/file.h>
38 #include <libaegis/project.h>
39 #include <libaegis/sub.h>
40 #include <libaegis/user.h>
41 #include <libaegis/version.h>
42
43
44 enum
45 {
46 arglex_token_usage = ARGLEX2_MAX,
47 arglex_token_usage_not,
48 arglex_token_action,
49 arglex_token_action_not,
50 arglex_token_quote_c,
51 arglex_token_quote_cook,
52 arglex_token_quote_shell,
53 ARGLEX3_MAX
54 };
55
56 static arglex_table_ty argtab[] =
57 {
58 { "-ACtion", arglex_token_action, },
59 { "-Not_ACtion", arglex_token_action_not, },
60 { "-USAge", arglex_token_usage, },
61 { "-Not_USAge", arglex_token_usage_not, },
62 { "-Quote_C", arglex_token_quote_c },
63 { "-Quote_COok", arglex_token_quote_cook },
64 { "-Quote_Shell", arglex_token_quote_shell },
65 ARGLEX_END_MARKER
66 };
67
68
69 static void
list_usage(void)70 list_usage(void)
71 {
72 const char *progname = progname_get();
73 fprintf(stderr, "Usage: %s [ <option>... ]\n", progname);
74 fprintf(stderr, " %s -Help\n", progname);
75 quit(1);
76 }
77
78
79 static void
list_help(void)80 list_help(void)
81 {
82 help((char *)0, list_usage);
83 }
84
85
86 static int
find_action(void)87 find_action(void)
88 {
89 int curtok = arglex_token;
90 if (arglex() != arglex_token_string)
91 option_needs_name(curtok, list_usage);
92 string_ty *s = str_from_c(arglex_value.alv_string);
93 file_action_ty fa;
94 if (file_action_type.enum_parse(s, &fa))
95 {
96 str_free(s);
97 return (1 << fa);
98 }
99 string_ty *s2 = file_action_type.fuzzy(s);
100 if (s2)
101 {
102 sub_context_ty sc;
103 sc.var_set_string("Name", s);
104 sc.var_set_string("Guess", s2);
105 sc.fatal_intl(i18n("no \"$name\", guessing \"$guess\""));
106 // NOTREACHED
107 }
108 else
109 {
110 sub_context_ty sc;
111 sc.var_set_string("Name", s);
112 sc.fatal_intl(i18n("the name \"$name\" is undefined"));
113 // NOTREACHED
114 }
115 return 0;
116 }
117
118
119 static int
find_usage(void)120 find_usage(void)
121 {
122 int curtok = arglex_token;
123 if (arglex() != arglex_token_string)
124 option_needs_name(curtok, list_usage);
125 string_ty *s = str_from_c(arglex_value.alv_string);
126 file_usage_ty fu;
127 if (file_usage_type.enum_parse(s, &fu))
128 {
129 str_free(s);
130 return (1 << fu);
131 }
132 string_ty *s2 = file_usage_type.fuzzy(s);
133 if (s2)
134 {
135 sub_context_ty sc;
136 sc.var_set_string("Name", s);
137 sc.var_set_string("Guess", s2);
138 sc.fatal_intl(i18n("no \"$name\", guessing \"$guess\""));
139 // NOTREACHED
140 }
141 else
142 {
143 sub_context_ty sc;
144 sc.var_set_string("Name", s);
145 sc.fatal_intl(i18n("the name \"$name\" is undefined"));
146 // NOTREACHED
147 }
148 return 0;
149 }
150
151
152 int
main(int argc,char ** argv)153 main(int argc, char **argv)
154 {
155 resource_limits_init();
156 os_become_init_mortal();
157 arglex2_init3(argc, argv, argtab);
158 env_initialize();
159 language_init();
160
161 switch (arglex())
162 {
163 case arglex_token_help:
164 list_help();
165 quit(0);
166
167 case arglex_token_version:
168 version();
169 quit(0);
170 }
171
172 change_identifier cid;
173 int action = 0;
174 int action_not = 0;
175 int usage = 0;
176 int usage_not = 0;
177
178 enum quote_t
179 {
180 quote_none,
181 quote_c,
182 quote_cook,
183 quote_shell
184 };
185 quote_t quote = quote_none;
186
187 while (arglex_token != arglex_token_eoln)
188 {
189 switch (arglex_token)
190 {
191 default:
192 generic_argument(list_usage);
193 continue;
194
195 case arglex_token_baseline:
196 case arglex_token_branch:
197 case arglex_token_change:
198 case arglex_token_delta:
199 case arglex_token_delta_date:
200 case arglex_token_delta_name:
201 case arglex_token_number:
202 case arglex_token_project:
203 case arglex_token_trunk:
204 cid.command_line_parse(list_usage);
205 continue;
206
207 case arglex_token_action:
208 action |= find_action();
209 break;
210
211 case arglex_token_action_not:
212 action_not |= find_action();
213 break;
214
215 case arglex_token_usage:
216 usage |= find_usage();
217 break;
218
219 case arglex_token_usage_not:
220 usage_not |= find_usage();
221 break;
222
223 case arglex_token_quote_c:
224 quote = quote_c;
225 break;
226
227 case arglex_token_quote_cook:
228 quote = quote_cook;
229 break;
230
231 case arglex_token_quote_shell:
232 quote = quote_shell;
233 break;
234 }
235 arglex();
236 }
237 cid.command_line_check(list_usage);
238
239 //
240 // Construct the file action mask.
241 //
242 // If the user specified no particular file actions to include or
243 // exclude, then by default we will exclude removed files.
244 //
245 if (action == 0 && action_not == 0)
246 action_not = 1 << file_action_remove;
247 if (action == 0)
248 action = ~0;
249 action &= ~action_not;
250
251 //
252 // Construct the file usage mask.
253 //
254 if (usage == 0)
255 usage = ~0;
256 usage &= ~usage_not;
257
258 //
259 // emit the listing
260 //
261 for (size_t j = 0; ; ++j)
262 {
263 trace(("j = %ld\n", long(j)));
264 fstate_src_ty *src = cid.get_pp()->file_nth(j, view_path_simple);
265 if (!src)
266 break;
267 trace(("src = %p\n", src));
268 if (src->deleted_by)
269 continue;
270
271 // Note: this particular logic must be identical to the logic
272 // used in the libaegis/ael/project/files.cc file, since this is
273 // simply meant to be a more efficient version of that code.
274 if (cid.set() && cid.get_cp()->file_find(src, view_path_first))
275 continue;
276
277 if ((action & (1 << src->action)) && (usage & (1 << src->usage)))
278 {
279 nstring filename(src->file_name);
280 switch (quote)
281 {
282 default:
283 case quote_none:
284 break;
285
286 case quote_c:
287 filename = filename.quote_c();
288 break;
289
290 case quote_cook:
291 filename = filename.quote_cook();
292 break;
293
294 case quote_shell:
295 filename = filename.quote_shell();
296 break;
297 }
298 printf("%s\n", filename.c_str());
299 }
300 }
301
302 //
303 // report success
304 //
305 quit(0);
306 return 0;
307 }
308
309
310 // vim: set ts=8 sw=4 et :
311