Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage-utils:master commit in: man/, tests/quse/, /, man/include/
Date: Thu, 02 May 2019 08:29:32
Message-Id: 1556785669.da9cb1c25e743601521274130e023f82dab1621e.grobian@gentoo
1 commit: da9cb1c25e743601521274130e023f82dab1621e
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Thu May 2 08:27:49 2019 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Thu May 2 08:27:49 2019 +0000
6 URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=da9cb1c2
7
8 quse: rewrite using libc/cache
9
10 - dropped -K/KEYWORDS search, this should be done using qkeywords (qcache)
11 - unified colouring/naming packages
12 - added listing per package mode (-v)
13
14 Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>
15
16 TODO.md | 1 +
17 man/include/quse.desc | 2 +-
18 man/include/quse.optdesc.yaml | 9 +-
19 man/quse.1 | 21 +-
20 quse.c | 820 ++++++++++++++++++++++++------------------
21 tests/quse/dotest | 55 +--
22 tests/quse/list01.good | 4 +-
23 7 files changed, 498 insertions(+), 414 deletions(-)
24
25 diff --git a/TODO.md b/TODO.md
26 index 38778b0..3a3c26a 100644
27 --- a/TODO.md
28 +++ b/TODO.md
29 @@ -98,3 +98,4 @@
30
31 # quse
32 - make -v faster by calling searcg funcs once per package match
33 +- make -v only print requested USE-flag when flags given
34
35 diff --git a/man/include/quse.desc b/man/include/quse.desc
36 index 7492774..84a4ba2 100644
37 --- a/man/include/quse.desc
38 +++ b/man/include/quse.desc
39 @@ -1,2 +1,2 @@
40 -\fIquse\fR searches in ebuilds for a match in IUSE, KEYWORDS or LICENSE.
41 +\fIquse\fR searches in ebuilds for a match in IUSE or LICENSE.
42 It can also search for USE-flags and show their descriptions.
43
44 diff --git a/man/include/quse.optdesc.yaml b/man/include/quse.optdesc.yaml
45 index 2a3675d..79a98fa 100644
46 --- a/man/include/quse.optdesc.yaml
47 +++ b/man/include/quse.optdesc.yaml
48 @@ -1,11 +1,6 @@
49 exact: Search for exact string, e.g.\ do not use regular expression matching.
50 -format: |
51 - Advanced option to manually override the variable searched for in
52 - ebuilds. By default, the search is \fIIUSE=\fR, the \fB\-K\fR and
53 - \fB\-L\fR override that to \fIKEYWORDS=\fR and \fILICENSE=\fR
54 - respectively. This option, sets the search to any variable. Note
55 - that the equals sign is part of the search, and needs to be set.
56 verbose: |
57 - Show problems encountered during parsing. These are mostly
58 + Show descriptions for USE-flags for packages that match the search.
59 + Also shows problems encountered during parsing. These are mostly
60 diagnostic and indicate possible incorrectness in the results.
61 quiet: Ignored for compatibility with other qapplets.
62
63 diff --git a/man/quse.1 b/man/quse.1
64 index 6292f8c..bb02306 100644
65 --- a/man/quse.1
66 +++ b/man/quse.1
67 @@ -1,12 +1,12 @@
68 .\" generated by mkman.py, please do NOT edit!
69 -.TH quse "1" "Apr 2019" "Gentoo Foundation" "quse"
70 +.TH quse "1" "May 2019" "Gentoo Foundation" "quse"
71 .SH NAME
72 quse \- find pkgs using useflags
73 .SH SYNOPSIS
74 .B quse
75 \fI[opts] <useflag>\fR
76 .SH DESCRIPTION
77 -\fIquse\fR searches in ebuilds for a match in IUSE, KEYWORDS or LICENSE.
78 +\fIquse\fR searches in ebuilds for a match in IUSE or LICENSE.
79 It can also search for USE-flags and show their descriptions.
80 .SH OPTIONS
81 .TP
82 @@ -16,30 +16,21 @@ Search for exact string, e.g.\ do not use regular expression matching.
83 \fB\-a\fR, \fB\-\-all\fR
84 List all ebuilds, don't match anything.
85 .TP
86 -\fB\-K\fR, \fB\-\-keywords\fR
87 -Use the KEYWORDS vs IUSE.
88 -.TP
89 \fB\-L\fR, \fB\-\-license\fR
90 Use the LICENSE vs IUSE.
91 .TP
92 \fB\-D\fR, \fB\-\-describe\fR
93 Describe the USE flag.
94 .TP
95 -\fB\-F\fR \fI<arg>\fR, \fB\-\-format\fR \fI<arg>\fR
96 -Advanced option to manually override the variable searched for in
97 -ebuilds. By default, the search is \fIIUSE=\fR, the \fB\-K\fR and
98 -\fB\-L\fR override that to \fIKEYWORDS=\fR and \fILICENSE=\fR
99 -respectively. This option, sets the search to any variable. Note
100 -that the equals sign is part of the search, and needs to be set.
101 -.TP
102 -\fB\-N\fR, \fB\-\-name\-only\fR
103 -Only show package name.
104 +\fB\-p\fR \fI<arg>\fR, \fB\-\-package\fR \fI<arg>\fR
105 +Restrict matching to package or category.
106 .TP
107 \fB\-\-root\fR \fI<arg>\fR
108 Set the ROOT env var.
109 .TP
110 \fB\-v\fR, \fB\-\-verbose\fR
111 -Show problems encountered during parsing. These are mostly
112 +Show descriptions for USE-flags for packages that match the search.
113 +Also shows problems encountered during parsing. These are mostly
114 diagnostic and indicate possible incorrectness in the results.
115 .TP
116 \fB\-q\fR, \fB\-\-quiet\fR
117
118 diff --git a/quse.c b/quse.c
119 index c5f44ed..fbf61cf 100644
120 --- a/quse.c
121 +++ b/quse.c
122 @@ -18,6 +18,7 @@
123 #include <sys/stat.h>
124 #include <fcntl.h>
125 #include <dirent.h>
126 +#include <ctype.h>
127 #include <assert.h>
128
129 #include "cache.h"
130 @@ -25,434 +26,565 @@
131 #include "xarray.h"
132 #include "xregex.h"
133
134 -/*
135 - quse -CKe -- '-*' {'~',-,}{alpha,amd64,hppa,ia64,ppc,ppc64,sparc,x86}
136 - quse -Ke -- nls
137 -*/
138 -
139 -#define QUSE_FLAGS "eavKLDF:N" COMMON_FLAGS
140 +#define QUSE_FLAGS "eaLDp:" COMMON_FLAGS
141 static struct option const quse_long_opts[] = {
142 {"exact", no_argument, NULL, 'e'},
143 {"all", no_argument, NULL, 'a'},
144 - {"keywords", no_argument, NULL, 'K'},
145 {"license", no_argument, NULL, 'L'},
146 {"describe", no_argument, NULL, 'D'},
147 - {"format", a_argument, NULL, 'F'},
148 - {"name-only", no_argument, NULL, 'N'},
149 + {"package", a_argument, NULL, 'p'},
150 COMMON_LONG_OPTS
151 };
152 static const char * const quse_opts_help[] = {
153 "Show exact non regexp matching using strcmp",
154 "List all ebuilds, don't match anything",
155 - "Use the KEYWORDS vs IUSE",
156 "Use the LICENSE vs IUSE",
157 "Describe the USE flag",
158 - "Use your own variable formats. -F NAME=",
159 - "Only show package name",
160 + "Restrict matching to package or category",
161 COMMON_OPTS_HELP
162 };
163 #define quse_usage(ret) usage(ret, QUSE_FLAGS, quse_long_opts, quse_opts_help, NULL, lookup_applet_idx("quse"))
164
165 -char quse_name_only = 0;
166 +struct quse_state {
167 + int argc;
168 + char **argv;
169 + const char *overlay;
170 + bool do_all:1;
171 + bool do_regex:1;
172 + bool do_describe:1;
173 + bool do_licence:1;
174 + bool do_list:1;
175 + depend_atom *match;
176 + regex_t *pregv;
177 +};
178
179 -static void
180 -print_highlighted_use_flags(char *string, int ind, int argc, char **argv)
181 +static char *_quse_getline_buf = NULL;
182 +static size_t _quse_getline_buflen = 0;
183 +#define GETLINE(FD, BUF, LEN) \
184 + LEN = getline(&_quse_getline_buf, &_quse_getline_buflen, FD); \
185 + BUF = _quse_getline_buf
186 +
187 +static bool
188 +quse_search_use_local_desc(int portdirfd, struct quse_state *state)
189 {
190 - char *str, *p;
191 - char buf[BUFSIZ];
192 - size_t pos, len;
193 - short highlight = 0;
194 + int fd;
195 + FILE *f;
196 + ssize_t linelen;
197 + char *buf;
198 + char *p;
199 + char *q;
200 int i;
201 + bool match = false;
202 + bool ret = false;
203 + depend_atom *atom;
204 +
205 + fd = openat(portdirfd, "profiles/use.local.desc", O_RDONLY | O_CLOEXEC);
206 + if (fd == -1)
207 + return false;
208 +
209 + f = fdopen(fd, "r");
210 + if (f == NULL) {
211 + close(fd);
212 + return false;
213 + }
214
215 - if (quse_name_only)
216 - return;
217 + /* use.local.desc: <pkg>:<use> - <desc> */
218 + do {
219 + GETLINE(f, buf, linelen);
220 + if (linelen < 0)
221 + break;
222 +
223 + rmspace_len(buf, (size_t)linelen);
224 + if (buf[0] == '#' || buf[0] == '\0')
225 + continue;
226
227 - snprintf(buf, sizeof(buf), "%.*s", (int)sizeof(buf) - 1, string);
228 - str = buf;
229 - remove_extra_space(str);
230 - rmspace(str);
231 + if ((p = strchr(buf, ':')) == NULL)
232 + continue;
233 + *p++ = '\0';
234
235 - if (*WHITE == '\0') {
236 - printf("%s", str);
237 - return;
238 - }
239 + q = strchr(p, ' ');
240 + if (q == NULL || q[1] != '-')
241 + continue;
242 + *q = '\0';
243 + q += 3; /* " - " */
244
245 - len = strlen(str);
246 - for (pos = 0; pos < len; pos++) {
247 - highlight = 0;
248 - if ((p = strchr(str, ' ')) != NULL)
249 - *p = 0;
250 - pos += strlen(str);
251 - for (i = ind; i < argc; ++i)
252 - if (strcmp(str, argv[i]) == 0)
253 - highlight = 1;
254 - if (highlight)
255 - printf("%s%s%s ", BOLD, str, NORM);
256 - else
257 - printf("%s%s%s%s ", NORM, MAGENTA, str, NORM);
258 - if (p != NULL)
259 - str = p + 1;
260 - }
261 + match = false;
262 + for (i = 0; i < state->argc; i++) {
263 + if (state->do_regex) {
264 + if (regexec(&state->pregv[i], p, 0, NULL, 0) != 0)
265 + continue;
266 + } else {
267 + if (strcmp(p, state->argv[i]) != 0)
268 + continue;
269 + }
270 + match = true;
271 + break;
272 + }
273 +
274 + if (match) {
275 + if ((atom = atom_explode(buf)) == NULL)
276 + continue;
277 +
278 + if (state->match == NULL ||
279 + atom_compare(atom, state->match) == EQUAL)
280 + {
281 + if (state->do_list)
282 + printf(" %s%s%s %s\n", MAGENTA, p, NORM, q);
283 + else
284 + printf("%s%s/%s%s%s[%s%s%s] %s\n",
285 + BOLD, atom->CATEGORY,
286 + BLUE, atom->PN, NORM,
287 + MAGENTA, p, NORM, q);
288 + }
289 +
290 + atom_implode(atom);
291 + ret = true;
292 + }
293 + } while (1);
294 +
295 + fclose(f);
296 + return ret;
297 }
298
299 -static void
300 -quse_describe_flag(const char *overlay, unsigned int ind, unsigned int argc, char **argv)
301 +static bool
302 +quse_search_use_desc(int portdirfd, struct quse_state *state)
303 {
304 -#define NUM_SEARCH_FILES ARRAY_SIZE(search_files)
305 - int linelen;
306 - size_t buflen;
307 - char *buf, *p;
308 - unsigned int i, f;
309 - size_t s;
310 - const char * const search_files[] = {
311 - "use.desc",
312 - "use.local.desc",
313 - "arch.list"
314 - };
315 - FILE *fp[NUM_SEARCH_FILES];
316 - int dfd, fd;
317 - DIR *d;
318 - struct dirent *de;
319 + int fd;
320 + FILE *f;
321 + ssize_t linelen;
322 + char *buf;
323 + char *p;
324 + int i;
325 + bool match = false;
326 + bool ret = false;
327
328 - /* pick 1000 arbitrarily long enough for all files under desc/ */
329 - buflen = strlen(overlay) + 1000;
330 - buf = xmalloc(buflen);
331 + fd = openat(portdirfd, "profiles/use.desc", O_RDONLY | O_CLOEXEC);
332 + if (fd == -1)
333 + return false;
334
335 - for (i = 0; i < NUM_SEARCH_FILES; ++i) {
336 - snprintf(buf, buflen, "%s/profiles/%s", overlay, search_files[i]);
337 - fp[i] = fopen(buf, "r");
338 - if (verbose && fp[i] == NULL)
339 - warnp("skipping %s", buf);
340 + f = fdopen(fd, "r");
341 + if (f == NULL) {
342 + close(fd);
343 + return false;
344 }
345
346 - for (i = ind; i < argc; i++) {
347 - s = strlen(argv[i]);
348 + /* use.desc: <use> - <desc> */
349 + do {
350 + GETLINE(f, buf, linelen);
351 + if (linelen < 0)
352 + break;
353
354 - for (f = 0; f < NUM_SEARCH_FILES; ++f) {
355 - if (fp[f] == NULL)
356 - continue;
357 + rmspace_len(buf, (size_t)linelen);
358 + if (buf[0] == '#' || buf[0] == '\0')
359 + continue;
360 +
361 + p = strchr(buf, ' ');
362 + if (p == NULL || p[1] != '-')
363 + continue;
364 + *p = '\0';
365 + p += 3; /* " - " */
366
367 - while ((linelen = getline(&buf, &buflen, fp[f])) >= 0) {
368 - rmspace_len(buf, (size_t)linelen);
369 - if (buf[0] == '#' || buf[0] == '\0')
370 + match = false;
371 + for (i = 0; i < state->argc; i++) {
372 + if (state->do_regex) {
373 + if (regexec(&state->pregv[i], buf, 0, NULL, 0) != 0)
374 continue;
375 + } else {
376 + if (strcmp(buf, state->argv[i]) != 0)
377 + continue;
378 + }
379 + match = true;
380 + break;
381 + }
382
383 - switch (f) {
384 - case 0: /* Global use.desc */
385 - if (!strncmp(buf, argv[i], s))
386 - if (buf[s] == ' ' && buf[s + 1] == '-') {
387 - printf(" %sglobal%s:%s%s%s: %s\n",
388 - BOLD, NORM, BLUE, argv[i], NORM,
389 - buf + s + 3);
390 - goto skip_file;
391 - }
392 - break;
393 + if (match) {
394 + if (state->do_list)
395 + printf(" %s%s%s %s\n", MAGENTA, buf, NORM, p);
396 + else
397 + printf("%sglobal%s[%s%s%s] %s\n",
398 + BOLD, NORM, MAGENTA, buf, NORM, p);
399
400 - case 1: /* Local use.local.desc */
401 - if ((p = strchr(buf, ':')) == NULL)
402 - break;
403 - ++p;
404 - if (!strncmp(p, argv[i], s)) {
405 - if (p[s] == ' ' && p[s + 1] == '-') {
406 - *p = '\0';
407 - printf(" %slocal%s:%s%s%s:%s%s%s %s\n",
408 - BOLD, NORM, BLUE, argv[i], NORM,
409 - BOLD, buf, NORM, p + s + 3);
410 - }
411 - }
412 - break;
413 + ret = true;
414 + }
415 + } while (1);
416
417 - case 2: /* Architectures arch.list */
418 - if (!strcmp(buf, argv[i])) {
419 - printf(" %sarch%s:%s%s%s: %s architecture\n",
420 - BOLD, NORM, BLUE, argv[i], NORM, argv[i]);
421 - goto skip_file;
422 - }
423 - break;
424 - }
425 - }
426 + fclose(f);
427 + return ret;
428 +}
429
430 - skip_file:
431 - rewind(fp[f]);
432 - }
433 - }
434 +static bool
435 +quse_search_profiles_desc(
436 + int portdirfd,
437 + struct quse_state *state)
438 +{
439 + int fd;
440 + FILE *f;
441 + ssize_t linelen;
442 + char *buf;
443 + char *p;
444 + int i;
445 + bool match = false;
446 + bool ret = false;
447 + size_t namelen;
448 + size_t arglen;
449 + char ubuf[_Q_PATH_MAX];
450 + struct dirent *de;
451 + DIR *d;
452 + int dfd;
453
454 - for (f = 0; f < NUM_SEARCH_FILES; ++f)
455 - if (fp[f] != NULL)
456 - fclose(fp[f]);
457 -
458 - /* now scan the desc dir */
459 - snprintf(buf, buflen, "%s/profiles/desc/", overlay);
460 - dfd = open(buf, O_RDONLY|O_CLOEXEC);
461 - if (dfd == -1) {
462 - if (verbose)
463 - warnp("skipping %s", buf);
464 - goto done;
465 - }
466 - d = fdopendir(dfd);
467 + fd = openat(portdirfd, "profiles/desc", O_RDONLY|O_CLOEXEC);
468 + if (fd == -1)
469 + return false;
470 + d = fdopendir(fd);
471 if (!d) {
472 - close(dfd);
473 - goto done;
474 + close(fd);
475 + return false;
476 }
477
478 - while ((de = readdir(d)) != NULL) {
479 - s = strlen(de->d_name);
480 - if (s < 6)
481 - continue;
482 - p = de->d_name + s - 5;
483 - if (strcmp(p, ".desc"))
484 - continue;
485 + if (_quse_getline_buf == NULL) {
486 + _quse_getline_buflen = _Q_PATH_MAX;
487 + _quse_getline_buf = xmalloc(sizeof(char) * _quse_getline_buflen);
488 + }
489
490 - fd = openat(dfd, de->d_name, O_RDONLY|O_CLOEXEC);
491 - if (fd == -1) {
492 - if (verbose)
493 - warnp("skipping %s/profiles/desc/%s", overlay, de->d_name);
494 + while ((de = readdir(d))) {
495 + if (de->d_name[0] == '.')
496 continue;
497 - }
498 - fp[0] = fdopen(fd, "r");
499 - if (!fp[0]) {
500 +
501 + namelen = strlen(de->d_name);
502 + if (namelen <= 5 || strcmp(de->d_name + namelen - 5, ".desc") != 0)
503 + return false;
504 +
505 + snprintf(_quse_getline_buf, _quse_getline_buflen,
506 + "profiles/desc/%s", de->d_name);
507 + dfd = openat(portdirfd, _quse_getline_buf, O_RDONLY | O_CLOEXEC);
508 + if (dfd == -1)
509 + return false;
510 +
511 + f = fdopen(dfd, "r");
512 + if (f == NULL) {
513 close(fd);
514 - continue;
515 + return false;
516 }
517
518 - /* Chop the trailing .desc for better display */
519 - *p = '\0';
520 + /* remove trailing .desc */
521 + namelen -= 5;
522 +
523 + /* use.desc: <use> - <desc> */
524 + do {
525 + GETLINE(f, buf, linelen);
526 + if (linelen < 0)
527 + break;
528
529 - while ((linelen = getline(&buf, &buflen, fp[0])) >= 0) {
530 rmspace_len(buf, (size_t)linelen);
531 if (buf[0] == '#' || buf[0] == '\0')
532 continue;
533
534 - if ((p = strchr(buf, '-')) == NULL) {
535 - invalid_line:
536 - warn("Invalid line in '%s': %s", de->d_name, buf);
537 + p = strchr(buf, ' ');
538 + if (p == NULL || p[1] != '-')
539 continue;
540 + *p = '\0';
541 + p += 3; /* " - " */
542 +
543 + match = false;
544 + for (i = 0; i < state->argc; i++) {
545 + arglen = strlen(state->argv[i]);
546 + if (arglen > namelen) {
547 + /* nginx_modules_http_lua = NGINX_MODULES_HTTP[lua] */
548 + match = strncmp(state->argv[i], de->d_name, namelen) == 0;
549 + if (match && state->argv[i][namelen] == '_') {
550 + match = strcmp(&state->argv[i][namelen + 1], buf) == 0;
551 + } else {
552 + match = false;
553 + }
554 + if (match)
555 + break;
556 + }
557 +
558 + if (state->do_regex) {
559 + if (regexec(&state->pregv[i], buf, 0, NULL, 0) != 0)
560 + continue;
561 + } else {
562 + if (strcmp(buf, state->argv[i]) != 0)
563 + continue;
564 + }
565 + match = true;
566 + break;
567 }
568 - while (p[-1] != ' ' && p[1] != ' ') {
569 - /* maybe the flag has a '-' in it ... */
570 - if ((p = strchr(p + 1, '-')) == NULL)
571 - goto invalid_line;
572 +
573 + if (match) {
574 + const char *r = de->d_name;
575 + char *s = ubuf;
576 + do {
577 + *s++ = (char)toupper((int)*r);
578 + } while (++r < (de->d_name + namelen));
579 + *s = '\0';
580 + if (state->do_list)
581 + printf(" %s=%s%s%s %s\n", ubuf, MAGENTA, buf, NORM, p);
582 + else
583 + printf("%s%s%s[%s%s%s] %s\n",
584 + BOLD, ubuf, NORM, MAGENTA, buf, NORM, p);
585 +
586 + ret = true;
587 }
588 - p[-1] = '\0';
589 - p += 2;
590 + } while (1);
591
592 - for (i = ind; i < argc; i++)
593 - if (!strcmp(argv[i], buf))
594 - printf(" %s%s%s:%s%s%s: %s\n",
595 - BOLD, de->d_name, NORM, BLUE, argv[i], NORM, p);
596 - }
597 - fclose(fp[0]);
598 + fclose(f);
599 }
600 closedir(d);
601
602 - done:
603 - free(buf);
604 + return ret;
605 }
606
607 -int quse_main(int argc, char **argv)
608 +static void
609 +quse_describe_flag(const char *root, const char *overlay,
610 + struct quse_state *state)
611 {
612 - FILE *fp;
613 - const char *cache_file = NULL;
614 - char *p;
615 + char buf[_Q_PATH_MAX];
616 + int portdirfd;
617
618 - char buf0[_Q_PATH_MAX];
619 - char buf1[_Q_PATH_MAX];
620 - char buf2[_Q_PATH_MAX];
621 + snprintf(buf, sizeof(buf), "%s/%s", root, overlay);
622 + portdirfd = open(buf, O_RDONLY|O_CLOEXEC|O_PATH);
623 + if (portdirfd == -1)
624 + return;
625
626 - int linelen;
627 - size_t ebuildlen;
628 - char *ebuild;
629 + quse_search_use_desc(portdirfd, state);
630 + quse_search_use_local_desc(portdirfd, state);
631 + quse_search_profiles_desc(portdirfd, state);
632
633 - const char *search_var = NULL;
634 - const char *search_vars[] = {
635 - "IUSE=",
636 - "KEYWORDS=",
637 - "LICENSE=",
638 - search_var
639 - };
640 - short quse_all = 0;
641 - int regexp_matching = 1, i, idx = 0;
642 - size_t search_len;
643 - size_t n;
644 - const char *overlay;
645 + close(portdirfd);
646 +}
647
648 - while ((i = GETOPT_LONG(QUSE, quse, "")) != -1) {
649 - switch (i) {
650 - case 'e': regexp_matching = 0; break;
651 - case 'a': quse_all = 1; break;
652 - case 'K': idx = 1; break;
653 - case 'L': idx = 2; break;
654 - case 'D': idx = -1; break;
655 - case 'F': idx = 3, search_vars[idx] = xstrdup(optarg); break;
656 - case 'N': quse_name_only = 1; break;
657 - COMMON_GETOPTS_CASES(quse)
658 +static int
659 +quse_results_cb(cache_pkg_ctx *pkg_ctx, void *priv)
660 +{
661 + struct quse_state *state = (struct quse_state *)priv;
662 + depend_atom *atom = NULL; /* pacify compiler */
663 + char buf[8192];
664 + cache_pkg_meta *meta;
665 + bool match;
666 + char *p;
667 + char *q;
668 + char *s;
669 + char *v;
670 + char *w;
671 + int i;
672 + int len;
673 + int portdirfd = -1; /* pacify compiler */
674 +
675 + if (state->match || verbose) {
676 + snprintf(buf, sizeof(buf), "%s/%s",
677 + pkg_ctx->cat_ctx->name, pkg_ctx->name);
678 + atom = atom_explode(buf);
679 + if (atom == NULL)
680 + return 0;
681 +
682 + if (state->match) {
683 + match = atom_compare(atom, state->match) == EQUAL;
684 + if (!verbose || !match)
685 + atom_implode(atom);
686 +
687 + if (!match)
688 + return 0;
689 }
690 }
691 - if (argc == optind && !quse_all && idx >= 0)
692 - quse_usage(EXIT_FAILURE);
693
694 - if (idx == -1) {
695 - array_for_each(overlays, n, overlay)
696 - quse_describe_flag(overlay, optind, argc, argv);
697 + meta = cache_pkg_read(pkg_ctx);
698 + if (meta == NULL)
699 return 0;
700 - }
701
702 - if (quse_all) optind = argc;
703 + if (meta->IUSE == NULL)
704 + return 0;
705
706 - search_len = strlen(search_vars[idx]);
707 - assert(search_len < sizeof(buf0));
708 + if (verbose) {
709 + portdirfd = openat(pkg_ctx->cat_ctx->ctx->portroot_fd,
710 + state->overlay, O_RDONLY | O_CLOEXEC | O_PATH);
711 + if (portdirfd == -1)
712 + return 0;
713 + }
714
715 - array_for_each(overlays, n, overlay) {
716 - int overlay_fd;
717 + match = false;
718 + q = p = state->do_licence ? meta->LICENSE : meta->IUSE;
719 + buf[0] = '\0';
720 + v = buf;
721 + w = buf + sizeof(buf);
722 +
723 + if (state->do_all) {
724 + match = true;
725 + v = q;
726 + } else {
727 + do {
728 + if (*p == ' ' || *p == '\0') {
729 + /* skip over consequtive whitespace */
730 + if (p == q) {
731 + q++;
732 + continue;
733 + }
734
735 - /* FIXME: use libq/cache here */ if (1 == 1) {
736 - warnp("could not read cache: %s", cache_file);
737 - continue;
738 - }
739 + s = q;
740 + if (*q == '-' || *q == '+' || *q == '@')
741 + q++;
742 + if (state->do_regex) {
743 + char r;
744 + for (i = 0; i < state->argc; i++) {
745 + r = *p;
746 + *p = '\0';
747 + if (regexec(&state->pregv[i], q, 0, NULL, 0) == 0) {
748 + *p = r;
749 + v += snprintf(v, w - v, "%s%.*s%s%c",
750 + RED, (int)(p - s), s, NORM, *p);
751 + match = true;
752 + break;
753 + }
754 + *p = r;
755 + }
756 + } else {
757 + for (i = 0; i < state->argc; i++) {
758 + len = strlen(state->argv[i]);
759 + if (len == (int)(p - q) &&
760 + strncmp(q, state->argv[i], len) == 0)
761 + {
762 + v += snprintf(v, w - v, "%s%.*s%s%c",
763 + RED, (int)(p - s), s, NORM, *p);
764 + match = true;
765 + break;
766 + }
767 + }
768 + }
769 + if (i == state->argc)
770 + v += snprintf(v, w - v, "%.*s%c", (int)(p - s), s, *p);
771 + q = p + 1;
772 + }
773 + } while (*p++ != '\0' && v < w);
774 + v = buf;
775 + }
776
777 - overlay_fd = open(overlay, O_RDONLY|O_CLOEXEC|O_PATH);
778 + if (match) {
779 + if (quiet) {
780 + printf("%s%s/%s%s%s\n", BOLD, pkg_ctx->cat_ctx->name,
781 + BLUE, pkg_ctx->name, NORM);
782 + } else if (verbose) {
783 + /* multi-line result, printing USE-flags with their descs */
784 + struct quse_state us = {
785 + .do_regex = false,
786 + .do_describe = false,
787 + .do_list = true,
788 + .match = atom,
789 + .argc = 1,
790 + .argv = NULL,
791 + .overlay = NULL,
792 + };
793 +
794 + printf("%s%s/%s%s%s:\n", BOLD, pkg_ctx->cat_ctx->name,
795 + BLUE, pkg_ctx->name, NORM);
796 +
797 + q = p = state->do_licence ? meta->LICENSE : meta->IUSE;
798 + buf[0] = '\0';
799 + do {
800 + if (*p == ' ' || *p == '\0') {
801 + s = q;
802 + if (*q == '-' || *q == '+' || *q == '@')
803 + q++;
804 +
805 + snprintf(buf, sizeof(buf), "%.*s", (int)(p - q), q);
806 + v = buf;
807 + us.argv = &v;
808 +
809 + /* print at most one match for each flag, this is
810 + * why we can't setup all flags in argc/argv,
811 + * because then we either print way to few, or way
812 + * too many, possible opt: when argv would be
813 + * modified by search funcs so they remove what they
814 + * matched */
815 + if (!quse_search_use_local_desc(portdirfd, &us))
816 + if (!quse_search_use_desc(portdirfd, &us))
817 + quse_search_profiles_desc(portdirfd, &us);
818 +
819 + q = p + 1;
820 + }
821 + } while (*p++ != '\0');
822 + } else {
823 + printf("%s%s/%s%s%s: %s\n", BOLD, pkg_ctx->cat_ctx->name,
824 + BLUE, pkg_ctx->name, NORM, v);
825 + }
826 + }
827
828 - ebuild = NULL;
829 - while ((linelen = getline(&ebuild, &ebuildlen, fp)) >= 0) {
830 - FILE *newfp;
831 - int fd;
832 + cache_close_meta(meta);
833 + if (state->match || verbose)
834 + atom_implode(atom);
835 + if (verbose)
836 + close(portdirfd);
837
838 - rmspace_len(ebuild, (size_t)linelen);
839 + return EXIT_SUCCESS;
840 +}
841
842 - fd = openat(overlay_fd, ebuild, O_RDONLY|O_CLOEXEC);
843 - if (fd < 0)
844 - continue;
845 - newfp = fdopen(fd, "r");
846 - if (newfp != NULL) {
847 - unsigned int lineno = 0;
848 +int quse_main(int argc, char **argv)
849 +{
850 + int i;
851 + size_t n;
852 + const char *overlay;
853 + char *match = NULL;
854 + struct quse_state state = {
855 + .do_all = false,
856 + .do_regex = true,
857 + .do_describe = false,
858 + .do_licence = false,
859 + .match = NULL,
860 + .overlay = NULL,
861 + };
862
863 - while (fgets(buf0, sizeof(buf0), newfp) != NULL) {
864 - int ok = 0;
865 - char warned = 0;
866 - lineno++;
867 + while ((i = GETOPT_LONG(QUSE, quse, "")) != -1) {
868 + switch (i) {
869 + case 'e': state.do_regex = false; break;
870 + case 'a': state.do_all = true; break;
871 + case 'L': state.do_licence = true; break;
872 + case 'D': state.do_describe = true; break;
873 + case 'p': match = optarg; break;
874 + COMMON_GETOPTS_CASES(quse)
875 + }
876 + }
877 + if (argc == optind && !state.do_all) {
878 + if (match != NULL) {
879 + /* default to printing everything if just package is given */
880 + state.do_all = true;
881 + } else {
882 + quse_usage(EXIT_FAILURE);
883 + }
884 + }
885
886 - if (strncmp(buf0, search_vars[idx], search_len) != 0)
887 - continue;
888 + state.argc = argc - optind;
889 + state.argv = &argv[optind];
890
891 - if ((p = strchr(buf0, '\n')) != NULL)
892 - *p = 0;
893 - if ((p = strchr(buf0, '#')) != NULL) {
894 - if (buf0 != p && p[-1] == ' ')
895 - p[-1] = 0;
896 - else
897 - *p = 0;
898 - }
899 - if (verbose > 1) {
900 - if ((strchr(buf0, '\t') != NULL)
901 - || (strchr(buf0, '$') != NULL)
902 - || (strchr(buf0, '\\') != NULL)
903 - || (strchr(buf0, '\'') != NULL)
904 - || (strstr(buf0, " ") != NULL)) {
905 - warned = 1;
906 - warn("# Line %d of %s has an annoying %s",
907 - lineno, ebuild, buf0);
908 - }
909 - }
910 -#ifdef THIS_SUCKS
911 - if ((p = strrchr(&buf0[search_len + 1], '\\')) != NULL) {
912 -
913 - multiline:
914 - *p = ' ';
915 -
916 - if (fgets(buf1, sizeof(buf1), newfp) == NULL)
917 - continue;
918 - lineno++;
919 -
920 - if ((p = strchr(buf1, '\n')) != NULL)
921 - *p = 0;
922 - snprintf(buf2, sizeof(buf2), "%s %s", buf0, buf1);
923 - remove_extra_space(buf2);
924 - strcpy(buf0, buf2);
925 - if ((p = strrchr(buf1, '\\')) != NULL)
926 - goto multiline;
927 - }
928 -#else
929 - remove_extra_space(buf0);
930 -#endif
931 - while ((p = strrchr(&buf0[search_len + 1], '"')) != NULL) *p = 0;
932 - while ((p = strrchr(&buf0[search_len + 1], '\'')) != NULL) *p = 0;
933 - while ((p = strrchr(&buf0[search_len + 1], '\\')) != NULL) *p = ' ';
934 -
935 - if (verbose && warned == 0) {
936 - if ((strchr(buf0, '$') != NULL) || (strchr(buf0, '\\') != NULL)) {
937 - warned = 1;
938 - warn("# Line %d of %s has an annoying %s",
939 - lineno, ebuild, buf0);
940 - }
941 - }
942 + if (match != NULL) {
943 + state.match = atom_explode(match);
944 + if (state.match == NULL)
945 + errf("invalid atom: %s", match);
946 + }
947
948 - if (strlen(buf0) < search_len + 1) {
949 - /* warnf("err '%s'/%zu <= %zu; line %u\n", buf0, strlen(buf0), search_len + 1, lineno); */
950 - continue;
951 - }
952 + if (state.do_regex) {
953 + state.pregv = xmalloc(sizeof(state.pregv[0]) * state.argc);
954 + for (i = 0; i < state.argc; i++)
955 + xregcomp(&state.pregv[i], state.argv[i], REG_EXTENDED | REG_NOSUB);
956 + }
957
958 - if ((argc == optind) || (quse_all)) {
959 - ok = 1;
960 - } else {
961 - ok = 0;
962 - if (regexp_matching) {
963 - for (i = optind; i < argc; ++i) {
964 - if (rematch(argv[i], &buf0[search_len + 1], REG_NOSUB) == 0) {
965 - ok = 1;
966 - break;
967 - }
968 - }
969 - } else {
970 - remove_extra_space(buf0);
971 - strcpy(buf1, &buf0[search_len + 1]);
972 -
973 - for (i = (size_t) optind; i < argc && argv[i] != NULL; i++) {
974 - if (strcmp(buf1, argv[i]) == 0) {
975 - ok = 1;
976 - break;
977 - }
978 - }
979 - if (ok == 0) while ((p = strchr(buf1, ' ')) != NULL) {
980 - *p = 0;
981 - for (i = (size_t) optind; i < argc && argv[i] != NULL; i++) {
982 - if (strcmp(buf1, argv[i]) == 0) {
983 - ok = 1;
984 - break;
985 - }
986 - }
987 - strcpy(buf2, p + 1);
988 - strcpy(buf1, buf2);
989 - if (strchr(buf1, ' ') == NULL)
990 - for (i = (size_t) optind; i < argc && argv[i] != NULL; i++) {
991 - if (strcmp(buf1, argv[i]) == 0)
992 - ok = 1;
993 - }
994 - }
995 - }
996 - }
997 - if (ok) {
998 - printf("%s%s%s ", CYAN, ebuild, NORM);
999 - print_highlighted_use_flags(&buf0[search_len + 1],
1000 - optind, argc, argv);
1001 - puts(NORM);
1002 - if (verbose > 1) {
1003 - char **ARGV;
1004 - int ARGC;
1005 - makeargv(&buf0[search_len + 1], &ARGC, &ARGV);
1006 - quse_describe_flag(overlay, 1, ARGC, ARGV);
1007 - freeargv(ARGC, ARGV);
1008 - }
1009 - }
1010 - break;
1011 - }
1012 - fclose(newfp);
1013 - } else {
1014 - warnf("missing cache, please (re)generate");
1015 - }
1016 + if (state.do_describe) {
1017 + array_for_each(overlays, n, overlay)
1018 + quse_describe_flag(portroot, overlay, &state);
1019 + } else {
1020 + array_for_each(overlays, n, overlay) {
1021 + state.overlay = overlay;
1022 + cache_foreach_pkg_sorted(portroot, overlay,
1023 + quse_results_cb, &state, NULL, NULL);
1024 }
1025 - fclose(fp);
1026 - close(overlay_fd);
1027 }
1028
1029 + if (state.do_regex) {
1030 + for (i = 0; i < state.argc; i++)
1031 + regfree(&state.pregv[i]);
1032 + free(state.pregv);
1033 + }
1034 +
1035 + if (state.match != NULL)
1036 + atom_implode(state.match);
1037 +
1038 return EXIT_SUCCESS;
1039 }
1040
1041 diff --git a/tests/quse/dotest b/tests/quse/dotest
1042 index 0dadd8f..ed0511d 100755
1043 --- a/tests/quse/dotest
1044 +++ b/tests/quse/dotest
1045 @@ -13,30 +13,16 @@ entries() {
1046 sed -e 's:#.*::' -e '/^$/d' "$1"
1047 }
1048
1049 -# check arch.list
1050 -f="$d/arch.list"
1051 -all=$(entries "$f")
1052 -for x in ${all} ; do
1053 - quse -CD $x > x
1054 - echo " arch:$x: $x architecture" > good
1055 - cat good >> all.good
1056 - diff -u x good
1057 -done
1058 -quse -CD ${all} > x
1059 -diff -u x all.good
1060 -rm x good all.good
1061 -tpass "arch.list"
1062 -
1063 # check use.desc
1064 f="$d/use.desc"
1065 all=$(entries "$f" | awk '{print $1}')
1066 for x in ${all} ; do
1067 - quse -CD $x > x
1068 - sed -n -e "/^$x - /{s|^[^ ]* - | global:$x: |;p}" "$f" > good
1069 + quse -eCD $x > x
1070 + sed -n -e "/^$x - /{s|^[^ ]* - |global[$x] |;p}" "$f" > good
1071 cat good >> all.good
1072 diff -u x good
1073 done
1074 -quse -CD ${all} > x
1075 +quse -eCD ${all} > x
1076 diff -u x all.good
1077 rm x good all.good
1078 tpass "use.desc"
1079 @@ -45,12 +31,12 @@ tpass "use.desc"
1080 f="$d/use.local.desc"
1081 all=$(entries "$f" | awk '{print $1}' | cut -f2 -d:)
1082 for x in ${all} ; do
1083 - quse -CD $x > x
1084 - sed -n -e "/^[^:]*:$x - /{s|^\([^:]*\):[^ ]* - | local:$x:\1: |;p}" "$f" > good
1085 + quse -eCD $x > x
1086 + sed -n -e "/^[^:]*:$x - /{s|^\([^:]*\):[^ ]* - |\1[$x] |;p}" "$f" > good
1087 cat good >> all.good
1088 diff -u x good
1089 done
1090 -quse -CD ${all} > x
1091 +quse -eCD ${all} > x
1092 diff -u x all.good
1093 rm x good all.good
1094 tpass "use.local.desc"
1095 @@ -59,14 +45,15 @@ tpass "use.local.desc"
1096 f="$d/desc/elibc.desc"
1097 all=$(entries "$f" | awk '{print $1}')
1098 for x in ${all} ; do
1099 - quse -CD $x > x
1100 + quse -eCD $x > x
1101 dispf=${f##*/}
1102 dispf=${dispf%.desc}
1103 - sed -n -e "/^$x - /{s|^[^ ]* - | ${dispf}:$x: |;p}" "$f" > good
1104 + dispf=${dispf^^}
1105 + sed -n -e "/^$x - /{s|^[^ ]* - |${dispf}[$x] |;p}" "$f" > good
1106 cat good >> all.good
1107 diff -u x good
1108 done
1109 -quse -CD ${all} > x
1110 +quse -eCD ${all} > x
1111 diff -u x all.good
1112 rm x good all.good
1113 tpass "desc/elibc.desc"
1114 @@ -82,25 +69,3 @@ tpass "multi file match"
1115
1116 cleantmpdir
1117
1118 -###### faster test needed.########
1119 -end
1120 -##################################
1121 -type -p mksquashfs || exit 0
1122 -
1123 -export PORTDIR=$(portageq envvar PORTDIR) ;
1124 -
1125 -arches="x86 amd64 ppc"
1126 -
1127 -for arch in $arches; do
1128 - mkdir -p PORTDIR-${arch}
1129 - cd PORTDIR-${arch} || exit 1
1130 - [[ ! -e arch.${arch} ]] && quse -CKe ${arch} > arch.${arch} ;
1131 - awk '{print $1}' < arch.${arch} | cut -d / -f 1-2 | uniq | while read cpn ; do mkdir -p $cpn ; done ;
1132 - for ebuild in $(awk '{print $1}' < arch.${arch}) ; do cp $PORTDIR/$ebuild ./$ebuild; done ;
1133 - quse -CKe ${arch} | awk '{print $1}' | cut -d / -f 1-2 | uniq | while read cpn ; do cp -a $PORTDIR/$cpn/files ./$cpn/; done ;
1134 - cp -a $PORTDIR/{eclass,profiles,licences} . ; sync ;
1135 - mksquashfs ./ ../PORTDIR-${arch}.squashfs -noappend -e arch.${arch} ;
1136 - rm -rf *-*
1137 - cd -
1138 -done
1139 -ls -lh PORTDIR-*.squashfs
1140
1141 diff --git a/tests/quse/list01.good b/tests/quse/list01.good
1142 index 5a2172e..ae16f87 100644
1143 --- a/tests/quse/list01.good
1144 +++ b/tests/quse/list01.good
1145 @@ -1,2 +1,2 @@
1146 - one:abc: cow
1147 - two:abc: pig
1148 +ONE[abc] cow
1149 +TWO[abc] pig