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