1 |
commit: 032bd7e9200d1071b79f3a5d33906020fc805048 |
2 |
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
3 |
AuthorDate: Fri Dec 27 16:55:58 2019 +0000 |
4 |
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org> |
5 |
CommitDate: Fri Dec 27 16:55:58 2019 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=032bd7e9 |
7 |
|
8 |
main: add masks support |
9 |
|
10 |
Expose masks via q -m, store masks in preparation for applying masks |
11 |
when listing available ebuilds. |
12 |
|
13 |
Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org> |
14 |
|
15 |
main.c | 221 +++++++++++++++++++++++++++++++++-------------------- |
16 |
main.h | 2 + |
17 |
man/include/q.desc | 2 + |
18 |
man/q.1 | 13 +++- |
19 |
q.c | 56 +++++++++++++- |
20 |
5 files changed, 209 insertions(+), 85 deletions(-) |
21 |
|
22 |
diff --git a/main.c b/main.c |
23 |
index 869bf31..b5404cb 100644 |
24 |
--- a/main.c |
25 |
+++ b/main.c |
26 |
@@ -22,6 +22,7 @@ |
27 |
#include "eat_file.h" |
28 |
#include "rmspace.h" |
29 |
#include "scandirat.h" |
30 |
+#include "set.h" |
31 |
#include "xasprintf.h" |
32 |
|
33 |
/* variables to control runtime behavior */ |
34 |
@@ -354,10 +355,12 @@ set_portage_env_var(env_vars *var, const char *value, const char *src) |
35 |
} |
36 |
} |
37 |
|
38 |
-/* Helper to read a portage env file (e.g. make.conf), or recursively if |
39 |
- * it points to a directory */ |
40 |
+/* Helper to read a portage file (e.g. make.conf, package.mask), or |
41 |
+ * recursively if it points to a directory (we don't care about EAPI for |
42 |
+ * dirs, basically PMS 5.2.5 EAPI restriction is ignored) */ |
43 |
+enum portage_file_type { ENV_FILE, PMASK_FILE }; |
44 |
static void |
45 |
-read_portage_env_file(const char *file, env_vars vars[]) |
46 |
+read_portage_file(const char *file, enum portage_file_type type, void *data) |
47 |
{ |
48 |
FILE *fp; |
49 |
struct dirent **dents; |
50 |
@@ -368,6 +371,8 @@ read_portage_env_file(const char *file, env_vars vars[]) |
51 |
size_t buflen = 0; |
52 |
size_t line; |
53 |
int i; |
54 |
+ env_vars *vars = data; |
55 |
+ set *masks = data; |
56 |
|
57 |
if (getenv("DEBUG")) |
58 |
fprintf(stderr, "profile %s\n", file); |
59 |
@@ -384,7 +389,7 @@ read_portage_env_file(const char *file, env_vars vars[]) |
60 |
d->d_name[strlen(d->d_name) - 1] == '~') |
61 |
continue; |
62 |
snprintf(npath, sizeof(npath), "%s/%s", file, d->d_name); |
63 |
- read_portage_env_file(npath, vars); |
64 |
+ read_portage_file(npath, type, data); |
65 |
} |
66 |
scandir_free(dents, dentslen); |
67 |
goto done; |
68 |
@@ -402,84 +407,107 @@ read_portage_env_file(const char *file, env_vars vars[]) |
69 |
continue; |
70 |
|
71 |
/* Handle "source" keyword */ |
72 |
- if (strncmp(buf, "source ", 7) == 0) { |
73 |
- const char *sfile = buf + 7; |
74 |
- char npath[_Q_PATH_MAX * 2]; |
75 |
+ if (type == ENV_FILE) { |
76 |
+ if (strncmp(buf, "source ", 7) == 0) { |
77 |
+ const char *sfile = buf + 7; |
78 |
+ char npath[_Q_PATH_MAX * 2]; |
79 |
|
80 |
- if (sfile[0] != '/') { |
81 |
- /* handle relative paths */ |
82 |
- size_t file_path_len; |
83 |
+ if (sfile[0] != '/') { |
84 |
+ /* handle relative paths */ |
85 |
+ size_t file_path_len; |
86 |
|
87 |
- s = strrchr(file, '/'); |
88 |
- file_path_len = s - file + 1; |
89 |
+ s = strrchr(file, '/'); |
90 |
+ file_path_len = s - file + 1; |
91 |
|
92 |
- snprintf(npath, sizeof(npath), "%.*s/%s", |
93 |
- (int)file_path_len, file, sfile); |
94 |
- sfile = npath; |
95 |
- } |
96 |
- |
97 |
- read_portage_env_file(sfile, vars); |
98 |
- continue; |
99 |
- } |
100 |
+ snprintf(npath, sizeof(npath), "%.*s/%s", |
101 |
+ (int)file_path_len, file, sfile); |
102 |
+ sfile = npath; |
103 |
+ } |
104 |
|
105 |
- /* look for our desired variables and grab their value */ |
106 |
- for (i = 0; vars[i].name; ++i) { |
107 |
- if (buf[vars[i].name_len] != '=' && buf[vars[i].name_len] != ' ') |
108 |
- continue; |
109 |
- if (strncmp(buf, vars[i].name, vars[i].name_len)) |
110 |
+ read_portage_file(sfile, type, data); |
111 |
continue; |
112 |
+ } |
113 |
|
114 |
- /* make sure we handle spaces between the varname, the =, |
115 |
- * and the value: |
116 |
- * VAR=val VAR = val VAR="val" |
117 |
- */ |
118 |
- s = buf + vars[i].name_len; |
119 |
- if ((p = strchr(s, '=')) != NULL) |
120 |
- s = p + 1; |
121 |
- while (isspace(*s)) |
122 |
- ++s; |
123 |
- if (*s == '"' || *s == '\'') { |
124 |
- char *endq; |
125 |
- char q = *s; |
126 |
- |
127 |
- /* make sure we handle spacing/comments after the quote */ |
128 |
- endq = strchr(s + 1, q); |
129 |
- if (!endq) { |
130 |
- /* If the last char is not a quote, then we span lines */ |
131 |
- size_t abuflen; |
132 |
- char *abuf; |
133 |
- |
134 |
- abuf = NULL; |
135 |
- while (getline(&abuf, &abuflen, fp) != -1) { |
136 |
- buf = xrealloc(buf, buflen + abuflen); |
137 |
- endq = strchr(abuf, q); |
138 |
- if (endq) |
139 |
- *endq = '\0'; |
140 |
- |
141 |
- strcat(buf, abuf); |
142 |
- buflen += abuflen; |
143 |
- |
144 |
- if (endq) |
145 |
- break; |
146 |
- } |
147 |
- free(abuf); |
148 |
- |
149 |
- if (!endq) |
150 |
- warn("%s:%zu: %s: quote mismatch", |
151 |
- file, line, vars[i].name); |
152 |
+ /* look for our desired variables and grab their value */ |
153 |
+ for (i = 0; vars[i].name; i++) { |
154 |
+ if (buf[vars[i].name_len] != '=' && |
155 |
+ buf[vars[i].name_len] != ' ') |
156 |
+ continue; |
157 |
+ if (strncmp(buf, vars[i].name, vars[i].name_len)) |
158 |
+ continue; |
159 |
|
160 |
- s = buf + vars[i].name_len + 2; |
161 |
+ /* make sure we handle spaces between the varname, the =, |
162 |
+ * and the value: |
163 |
+ * VAR=val VAR = val VAR="val" |
164 |
+ */ |
165 |
+ s = buf + vars[i].name_len; |
166 |
+ if ((p = strchr(s, '=')) != NULL) |
167 |
+ s = p + 1; |
168 |
+ while (isspace(*s)) |
169 |
+ s++; |
170 |
+ if (*s == '"' || *s == '\'') { |
171 |
+ char *endq; |
172 |
+ char q = *s; |
173 |
+ |
174 |
+ /* make sure we handle spacing/comments after the quote */ |
175 |
+ endq = strchr(s + 1, q); |
176 |
+ if (!endq) { |
177 |
+ /* if the last char is not a quote, |
178 |
+ * then we span lines */ |
179 |
+ size_t abuflen; |
180 |
+ char *abuf; |
181 |
+ |
182 |
+ abuf = NULL; |
183 |
+ while (getline(&abuf, &abuflen, fp) != -1) { |
184 |
+ buf = xrealloc(buf, buflen + abuflen); |
185 |
+ endq = strchr(abuf, q); |
186 |
+ if (endq) |
187 |
+ *endq = '\0'; |
188 |
+ |
189 |
+ strcat(buf, abuf); |
190 |
+ buflen += abuflen; |
191 |
+ |
192 |
+ if (endq) |
193 |
+ break; |
194 |
+ } |
195 |
+ free(abuf); |
196 |
+ |
197 |
+ if (!endq) |
198 |
+ warn("%s:%zu: %s: quote mismatch", |
199 |
+ file, line, vars[i].name); |
200 |
+ |
201 |
+ s = buf + vars[i].name_len + 2; |
202 |
+ } else { |
203 |
+ *endq = '\0'; |
204 |
+ s++; |
205 |
+ } |
206 |
} else { |
207 |
- *endq = '\0'; |
208 |
- ++s; |
209 |
+ /* no quotes, so chop the spacing/comments ourselves */ |
210 |
+ size_t off = strcspn(s, "# \t\n"); |
211 |
+ s[off] = '\0'; |
212 |
} |
213 |
+ |
214 |
+ set_portage_env_var(&vars[i], s, file); |
215 |
+ } |
216 |
+ } else if (type == PMASK_FILE) { |
217 |
+ /* trim leading space */ |
218 |
+ for (s = buf; isspace((int)*s); s++) |
219 |
+ ; |
220 |
+ if (*s == '\0') |
221 |
+ continue; |
222 |
+ if (*s == '-') { |
223 |
+ /* negation/removal, lookup and drop mask if it exists; |
224 |
+ * note that this only supports exact matches (PMS |
225 |
+ * 5.2.5) so we don't even have to parse and use |
226 |
+ * atom-compare here */ |
227 |
+ s++; |
228 |
+ if ((p = del_set(s, masks, NULL)) != NULL) |
229 |
+ free(p); |
230 |
} else { |
231 |
- /* no quotes, so chop the spacing/comments ourselves */ |
232 |
- size_t off = strcspn(s, "# \t\n"); |
233 |
- s[off] = '\0'; |
234 |
+ p = xstrdup(file); |
235 |
+ if (add_set_value(s, p, masks) != NULL) |
236 |
+ free(p); |
237 |
} |
238 |
- |
239 |
- set_portage_env_var(&vars[i], s, file); |
240 |
} |
241 |
} |
242 |
|
243 |
@@ -490,9 +518,10 @@ read_portage_env_file(const char *file, env_vars vars[]) |
244 |
|
245 |
/* Helper to recursively read stacked make.defaults in profiles */ |
246 |
static void |
247 |
-read_portage_profile(const char *profile, env_vars vars[]) |
248 |
+read_portage_profile(const char *profile, env_vars vars[], set *masks) |
249 |
{ |
250 |
char profile_file[_Q_PATH_MAX * 3]; |
251 |
+ char rpath[_Q_PATH_MAX]; |
252 |
size_t profile_len; |
253 |
char *s; |
254 |
char *p; |
255 |
@@ -548,7 +577,9 @@ read_portage_profile(const char *profile, env_vars vars[]) |
256 |
snprintf(profile_file + profile_len, |
257 |
sizeof(profile_file) - profile_len, "%s", s); |
258 |
} |
259 |
- read_portage_profile(profile_file, vars); |
260 |
+ read_portage_profile( |
261 |
+ realpath(profile_file, rpath) == NULL ? profile_file : rpath, |
262 |
+ vars, masks); |
263 |
/* restore original path in case we were repointed by profile */ |
264 |
if (p != NULL) |
265 |
snprintf(profile_file, sizeof(profile_file), "%s/", profile); |
266 |
@@ -557,9 +588,11 @@ read_portage_profile(const char *profile, env_vars vars[]) |
267 |
|
268 |
free(buf); |
269 |
|
270 |
- /* now consume *this* profile's make.defaults */ |
271 |
+ /* now consume *this* profile's make.defaults and package.mask */ |
272 |
strcpy(profile_file + profile_len, "make.defaults"); |
273 |
- read_portage_env_file(profile_file, vars); |
274 |
+ read_portage_file(profile_file, ENV_FILE, vars); |
275 |
+ strcpy(profile_file + profile_len, "package.mask"); |
276 |
+ read_portage_file(profile_file, PMASK_FILE, masks); |
277 |
} |
278 |
|
279 |
static bool nocolor = 0; |
280 |
@@ -598,6 +631,7 @@ env_vars vars_to_read[] = { |
281 |
|
282 |
#undef _Q_EV |
283 |
}; |
284 |
+set *package_masks = NULL; |
285 |
|
286 |
/* Handle a single file in the repos.conf format. */ |
287 |
static void |
288 |
@@ -716,10 +750,11 @@ initialize_portage_env(void) |
289 |
const char *s; |
290 |
env_vars *var; |
291 |
char pathbuf[_Q_PATH_MAX]; |
292 |
+ char rpathbuf[_Q_PATH_MAX]; |
293 |
const char *configroot = getenv("PORTAGE_CONFIGROOT"); |
294 |
char *primary_overlay = NULL; |
295 |
|
296 |
- /* initialize all the strings with their default value */ |
297 |
+ /* initialize all the properties with their default value */ |
298 |
for (i = 0; vars_to_read[i].name; ++i) { |
299 |
var = &vars_to_read[i]; |
300 |
if (var->type != _Q_BOOL) |
301 |
@@ -727,6 +762,8 @@ initialize_portage_env(void) |
302 |
var->src = xstrdup(STR_DEFAULT); |
303 |
} |
304 |
|
305 |
+ package_masks = create_set(); |
306 |
+ |
307 |
/* figure out where to find our config files */ |
308 |
if (!configroot) |
309 |
configroot = CONFIG_EPREFIX; |
310 |
@@ -737,7 +774,7 @@ initialize_portage_env(void) |
311 |
i--; |
312 |
|
313 |
/* read overlays first so we can resolve repo references in profile |
314 |
- * parent files */ |
315 |
+ * parent files (non PMS feature?) */ |
316 |
snprintf(pathbuf, sizeof(pathbuf), "%.*s", (int)i, configroot); |
317 |
read_repos_conf(pathbuf, "/usr/share/portage/config/repos.conf", |
318 |
&primary_overlay); |
319 |
@@ -747,23 +784,41 @@ initialize_portage_env(void) |
320 |
snprintf(pathbuf, sizeof(pathbuf), |
321 |
"%.*s/usr/share/portage/config/make.globals", |
322 |
(int)i, configroot); |
323 |
- read_portage_env_file(pathbuf, vars_to_read); |
324 |
+ read_portage_file(pathbuf, ENV_FILE, vars_to_read); |
325 |
+ |
326 |
+ /* start with base masks, Portage behaviour PMS 5.2.8 */ |
327 |
+ if (primary_overlay != NULL) { |
328 |
+ char *overlay; |
329 |
+ size_t n; |
330 |
+ array_for_each(overlay_names, n, overlay) { |
331 |
+ if (overlay == primary_overlay) { |
332 |
+ snprintf(pathbuf, sizeof(pathbuf), "%s/profiles/package.mask", |
333 |
+ (char *)array_get_elem(overlays, n)); |
334 |
+ read_portage_file(pathbuf, PMASK_FILE, package_masks); |
335 |
+ break; |
336 |
+ } |
337 |
+ } |
338 |
+ } |
339 |
|
340 |
/* walk all the stacked profiles */ |
341 |
snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/make.profile", |
342 |
(int)i, configroot); |
343 |
- read_portage_profile(pathbuf, vars_to_read); |
344 |
+ read_portage_profile( |
345 |
+ realpath(pathbuf, rpathbuf) == NULL ? pathbuf : rpathbuf, |
346 |
+ vars_to_read, package_masks); |
347 |
snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/portage/make.profile", |
348 |
(int)i, configroot); |
349 |
- read_portage_profile(pathbuf, vars_to_read); |
350 |
+ read_portage_profile( |
351 |
+ realpath(pathbuf, rpathbuf) == NULL ? pathbuf : rpathbuf, |
352 |
+ vars_to_read, package_masks); |
353 |
|
354 |
- /* now read all the config files */ |
355 |
+ /* now read all Portage's config files */ |
356 |
snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/make.conf", |
357 |
(int)i, configroot); |
358 |
- read_portage_env_file(pathbuf, vars_to_read); |
359 |
+ read_portage_file(pathbuf, ENV_FILE, vars_to_read); |
360 |
snprintf(pathbuf, sizeof(pathbuf), "%.*s/etc/portage/make.conf", |
361 |
(int)i, configroot); |
362 |
- read_portage_env_file(pathbuf, vars_to_read); |
363 |
+ read_portage_file(pathbuf, ENV_FILE, vars_to_read); |
364 |
|
365 |
/* finally, check the env */ |
366 |
for (i = 0; vars_to_read[i].name; i++) { |
367 |
|
368 |
diff --git a/main.h b/main.h |
369 |
index 98e5cbb..68b9795 100644 |
370 |
--- a/main.h |
371 |
+++ b/main.h |
372 |
@@ -24,6 +24,7 @@ |
373 |
|
374 |
#include "colors.h" |
375 |
#include "i18n.h" |
376 |
+#include "set.h" |
377 |
|
378 |
extern const char *argv0; |
379 |
|
380 |
@@ -152,5 +153,6 @@ typedef struct { |
381 |
char *src; |
382 |
} env_vars; |
383 |
extern env_vars vars_to_read[]; |
384 |
+extern set *package_masks; |
385 |
|
386 |
#endif |
387 |
|
388 |
diff --git a/man/include/q.desc b/man/include/q.desc |
389 |
index 7109c46..7d38ba2 100644 |
390 |
--- a/man/include/q.desc |
391 |
+++ b/man/include/q.desc |
392 |
@@ -6,3 +6,5 @@ After version 0.74 of portage-utils, the cache functionality was removed |
393 |
in favour of using various trees directly, and optionally the caches |
394 |
therein. As such the \fB-r\fR and \fB-m\fR options were removed. It is |
395 |
no longer necessary to initialise the cache at any time. |
396 |
+.P |
397 |
+After version 0.82, the \fB-m\fR flag got repurposed for listing masks. |
398 |
|
399 |
diff --git a/man/q.1 b/man/q.1 |
400 |
index 886b00f..21a09b3 100644 |
401 |
--- a/man/q.1 |
402 |
+++ b/man/q.1 |
403 |
@@ -1,5 +1,5 @@ |
404 |
.\" generated by mkman.py, please do NOT edit! |
405 |
-.TH q "1" "Nov 2019" "Gentoo Foundation" "q" |
406 |
+.TH q "1" "Dec 2019" "Gentoo Foundation" "q" |
407 |
.SH NAME |
408 |
q \- invoke a portage utility applet |
409 |
.SH SYNOPSIS |
410 |
@@ -14,6 +14,8 @@ After version 0.74 of portage-utils, the cache functionality was removed |
411 |
in favour of using various trees directly, and optionally the caches |
412 |
therein. As such the \fB-r\fR and \fB-m\fR options were removed. It is |
413 |
no longer necessary to initialise the cache at any time. |
414 |
+.P |
415 |
+After version 0.82, the \fB-m\fR flag got repurposed for listing masks. |
416 |
.SH OPTIONS |
417 |
.TP |
418 |
\fB\-i\fR, \fB\-\-install\fR |
419 |
@@ -26,6 +28,15 @@ see the source (file) where the overlay was declared. |
420 |
\fB\-e\fR, \fB\-\-envvar\fR |
421 |
Print used environment variables and found values. Use \fI-v\fR to |
422 |
see the source (file, environment) where the variable was declared. |
423 |
+Additional arguments are treated as variable names to print the |
424 |
+values for. If just one name is given, only the value is printed if |
425 |
+matched. When no arguments or more than one argument is given, the |
426 |
+variable name and the value is printed as a shell-style declaration. |
427 |
+.TP |
428 |
+\fB\-m\fR, \fB\-\-masks\fR |
429 |
+Print the masks from package.mask files found. Use \fI-v\fR to see |
430 |
+the source (file) where the mask was declared. Additional arguments |
431 |
+are treated as atom selectors which must match the masks. |
432 |
.TP |
433 |
\fB\-\-root\fR \fI<arg>\fR |
434 |
Set the ROOT env var. |
435 |
|
436 |
diff --git a/q.c b/q.c |
437 |
index f137b04..4a2fd62 100644 |
438 |
--- a/q.c |
439 |
+++ b/q.c |
440 |
@@ -19,21 +19,24 @@ |
441 |
#include <libproc.h> |
442 |
#endif |
443 |
|
444 |
+#include "atom.h" |
445 |
#include "basename.h" |
446 |
#include "eat_file.h" |
447 |
#include "rmspace.h" |
448 |
|
449 |
-#define Q_FLAGS "ioe" COMMON_FLAGS |
450 |
+#define Q_FLAGS "ioem" COMMON_FLAGS |
451 |
static struct option const q_long_opts[] = { |
452 |
{"install", no_argument, NULL, 'i'}, |
453 |
{"overlays", no_argument, NULL, 'o'}, |
454 |
{"envvar", no_argument, NULL, 'e'}, |
455 |
+ {"masks", no_argument, NULL, 'm'}, |
456 |
COMMON_LONG_OPTS |
457 |
}; |
458 |
static const char * const q_opts_help[] = { |
459 |
"Install symlinks for applets", |
460 |
"Print available overlays (read from repos.conf)", |
461 |
"Print used variables and their found values", |
462 |
+ "Print (package.)masks for the current profile", |
463 |
COMMON_OPTS_HELP |
464 |
}; |
465 |
#define q_usage(ret) usage(ret, Q_FLAGS, q_long_opts, q_opts_help, NULL, lookup_applet_idx("q")) |
466 |
@@ -81,6 +84,7 @@ int q_main(int argc, char **argv) |
467 |
bool install; |
468 |
bool print_overlays; |
469 |
bool print_vars; |
470 |
+ bool print_masks; |
471 |
const char *p; |
472 |
APPLET func; |
473 |
|
474 |
@@ -100,12 +104,14 @@ int q_main(int argc, char **argv) |
475 |
install = false; |
476 |
print_overlays = false; |
477 |
print_vars = false; |
478 |
+ print_masks = false; |
479 |
while ((i = GETOPT_LONG(Q, q, "+")) != -1) { |
480 |
switch (i) { |
481 |
COMMON_GETOPTS_CASES(q) |
482 |
case 'i': install = true; break; |
483 |
case 'o': print_overlays = true; break; |
484 |
case 'e': print_vars = true; break; |
485 |
+ case 'm': print_masks = true; break; |
486 |
} |
487 |
} |
488 |
|
489 |
@@ -258,6 +264,54 @@ int q_main(int argc, char **argv) |
490 |
return 0; |
491 |
} |
492 |
|
493 |
+ if (print_masks) { |
494 |
+ DECLARE_ARRAY(masks); |
495 |
+ DECLARE_ARRAY(files); |
496 |
+ char *mask; |
497 |
+ size_t n; |
498 |
+ int j; |
499 |
+ bool match; |
500 |
+ depend_atom *atom; |
501 |
+ depend_atom *qatom; |
502 |
+ |
503 |
+ array_set(package_masks, masks); |
504 |
+ values_set(package_masks, files); |
505 |
+ |
506 |
+ array_for_each(masks, n, mask) { |
507 |
+ if ((atom = atom_explode(mask)) == NULL) |
508 |
+ continue; |
509 |
+ |
510 |
+ match = true; |
511 |
+ if (argc > optind) { |
512 |
+ match = false; |
513 |
+ for (j = optind; j < argc; j++) { |
514 |
+ qatom = atom_explode(argv[j]); |
515 |
+ if (qatom != NULL && atom_compare(atom, qatom) == EQUAL) |
516 |
+ match = true; |
517 |
+ atom_implode(qatom); |
518 |
+ if (match) |
519 |
+ break; |
520 |
+ } |
521 |
+ } |
522 |
+ if (!match) |
523 |
+ continue; |
524 |
+ |
525 |
+ printf("%s", atom_format( |
526 |
+ "%[pfx]%[CAT]%[PF]%[SLOT]%[SUBSLOT]%[sfx]%[USE]%[REPO]", |
527 |
+ atom)); |
528 |
+ if (verbose) |
529 |
+ printf(" [%s]\n", (char *)array_get_elem(files, n)); |
530 |
+ else |
531 |
+ printf("\n"); |
532 |
+ atom_implode(atom); |
533 |
+ } |
534 |
+ |
535 |
+ xarrayfree_int(masks); |
536 |
+ xarrayfree_int(files); |
537 |
+ |
538 |
+ return 0; |
539 |
+ } |
540 |
+ |
541 |
if (argc == optind) |
542 |
q_usage(EXIT_FAILURE); |
543 |
if ((func = lookup_applet(argv[optind])) == NULL) |