/[gentoo-projects]/portage-utils/qdepends.c
Gentoo

Contents of /portage-utils/qdepends.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.57 - (show annotations) (download) (as text)
Sat Nov 10 06:35:21 2012 UTC (22 months ago) by vapier
Branch: MAIN
Changes since 1.56: +3 -2 lines
File MIME type: text/x-csrc
qdepends: fix by Andreas Fink for --all handling #440048

1 /*
2 * Copyright 2005-2010 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/portage-utils/qdepends.c,v 1.56 2011/12/21 21:54:44 vapier Exp $
5 *
6 * Copyright 2005-2010 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2005-2010 Mike Frysinger - <vapier@gentoo.org>
8 */
9
10 #ifdef APPLET_qdepends
11
12 #define QDEPENDS_FLAGS "drpaNk:Q:" COMMON_FLAGS
13 static struct option const qdepends_long_opts[] = {
14 {"depend", no_argument, NULL, 'd'},
15 {"rdepend", no_argument, NULL, 'r'},
16 {"pdepend", no_argument, NULL, 'p'},
17 {"key", a_argument, NULL, 'k'},
18 {"query", a_argument, NULL, 'Q'},
19 {"name-only", no_argument, NULL, 'N'},
20 {"all", no_argument, NULL, 'a'},
21 COMMON_LONG_OPTS
22 };
23 static const char * const qdepends_opts_help[] = {
24 "Show DEPEND info (default)",
25 "Show RDEPEND info",
26 "Show PDEPEND info",
27 "User defined vdb key",
28 "Query reverse deps",
29 "Only show package name",
30 "Show all DEPEND info",
31 COMMON_OPTS_HELP
32 };
33 static const char qdepends_rcsid[] = "$Id: qdepends.c,v 1.56 2011/12/21 21:54:44 vapier Exp $";
34 #define qdepends_usage(ret) usage(ret, QDEPENDS_FLAGS, qdepends_long_opts, qdepends_opts_help, lookup_applet_idx("qdepends"))
35
36 static char qdep_name_only = 0;
37
38 /* structures / types / etc ... */
39 typedef enum {
40 DEP_NULL = 0,
41 DEP_NORM = 1,
42 DEP_USE = 2,
43 DEP_OR = 3,
44 DEP_GROUP = 4
45 } dep_type;
46 #ifdef EBUG
47 static const char * const _dep_names[] = { "NULL", "NORM", "USE", "OR", "GROUP" };
48 #endif
49
50 struct _dep_node {
51 dep_type type;
52 char *info;
53 char info_on_heap;
54 depend_atom *atom;
55 struct _dep_node *parent;
56 struct _dep_node *neighbor;
57 struct _dep_node *children;
58 };
59 typedef struct _dep_node dep_node;
60
61 /* prototypes */
62 #define dep_dump_tree(r) _dep_dump_tree(r,0)
63 void _dep_dump_tree(dep_node *root, int space);
64 dep_node *dep_grow_tree(char *depend);
65 void dep_burn_tree(dep_node *root);
66 void dep_prune_use(dep_node *root, char *use);
67 char *dep_flatten_tree(dep_node *root);
68 dep_node *_dep_grow_node(dep_type type, char *info, size_t info_len);
69 void _dep_attach(dep_node *root, dep_node *attach_me, int type);
70 void _dep_flatten_tree(dep_node *root, char *buf, size_t *pos);
71 void _dep_burn_node(dep_node *node);
72 int qdepends_main_vdb(const char *depend_file, int argc, char **argv);
73 int qdepends_vdb_deep(const char *depend_file, const char *query);
74
75 #ifdef EBUG
76 void print_word(char *ptr, int num);
77 void print_word(char *ptr, int num)
78 {
79 while (num--)
80 printf("%c", *ptr++);
81 printf("\n");
82 }
83 #endif
84
85 dep_node *_dep_grow_node(dep_type type, char *info, size_t info_len)
86 {
87 dep_node *ret;
88 size_t len;
89
90 if (type == DEP_OR || type == DEP_GROUP)
91 info = NULL;
92
93 len = sizeof(*ret);
94 if (info) {
95 if (!info_len)
96 info_len = strlen(info);
97 len += info_len + 1;
98 }
99 ret = xmalloc(len);
100 memset(ret, 0x00, len);
101
102 ret->type = type;
103 if (info) {
104 ret->info = ((char*)ret) + sizeof(*ret);
105 memcpy(ret->info, info, info_len);
106 if (type == DEP_NORM)
107 ret->atom = atom_explode(info);
108 }
109
110 return ret;
111 }
112
113 void _dep_burn_node(dep_node *node)
114 {
115 assert(node);
116 if (node->info_on_heap) free(node->info);
117 if (node->atom) atom_implode(node->atom);
118 free(node);
119 }
120
121 enum {
122 _DEP_NEIGH = 1,
123 _DEP_CHILD = 2
124 };
125
126 void _dep_attach(dep_node *root, dep_node *attach_me, int type)
127 {
128 if (type == _DEP_NEIGH) {
129 if (!root->neighbor) {
130 root->neighbor = attach_me;
131 attach_me->parent = root->parent;
132 } else
133 _dep_attach(root->neighbor, attach_me, _DEP_NEIGH);
134 } else {
135 if (!root->children) {
136 root->children = attach_me;
137 attach_me->parent = root;
138 } else
139 _dep_attach(root->children, attach_me, _DEP_NEIGH);
140 }
141 }
142
143 dep_node *dep_grow_tree(char *depend)
144 {
145 signed long paren_balanced;
146 char *word, *ptr, *p;
147 int curr_attach;
148 dep_node *ret, *curr_node, *new_node;
149 dep_type prev_type;
150
151 ret = curr_node = new_node = NULL;
152 prev_type = DEP_NULL;
153 paren_balanced = 0;
154 curr_attach = _DEP_NEIGH;
155 word = NULL;
156
157 p = strrchr(depend, '\n');
158 if (p != NULL) *p = 0;
159
160 #define _maybe_consume_word(t) \
161 do { \
162 if (!word) break; \
163 /*printf("Found word:%i ", curr_attach);*/ \
164 /*print_word(word, ptr-word);*/ \
165 new_node = _dep_grow_node(t, word, ptr-word); \
166 if (!ret) \
167 ret = curr_node = new_node; \
168 else { \
169 _dep_attach(curr_node, new_node, curr_attach); \
170 curr_attach = _DEP_NEIGH; \
171 curr_node = new_node; \
172 } \
173 prev_type = t; \
174 word = NULL; \
175 } while (0)
176
177 for (ptr = depend; *ptr; ++ptr) {
178 if (isspace(*ptr)) {
179 _maybe_consume_word(DEP_NORM);
180 continue;
181 }
182
183 switch (*ptr) {
184 case '?': {
185 if (word == NULL) {
186 warnf("Found a ? but no USE flag");
187 goto error_out;
188 }
189 _maybe_consume_word(DEP_USE);
190 curr_attach = _DEP_CHILD;
191 continue;
192 }
193 case '|': {
194 if (ptr[1] != '|') {
195 warnf("Found a | but not ||");
196 goto error_out;
197 }
198 word = ptr++;
199 _maybe_consume_word(DEP_OR);
200 curr_attach = _DEP_CHILD;
201 continue;
202 }
203 case '(': {
204 ++paren_balanced;
205 if (prev_type == DEP_OR || prev_type == DEP_USE) {
206 _maybe_consume_word(DEP_NORM);
207 prev_type = DEP_NULL;
208 } else {
209 if (word) {
210 warnf("New group has word in queue");
211 goto error_out;
212 }
213 word = ptr;
214 _maybe_consume_word(DEP_GROUP);
215 curr_attach = _DEP_CHILD;
216 }
217 break;
218 }
219 case ')': {
220 --paren_balanced;
221 _maybe_consume_word(DEP_NORM);
222
223 if (curr_node->parent == NULL) {
224 warnf("Group lacks a parent");
225 goto error_out;
226 }
227 curr_node = curr_node->parent;
228 curr_attach = _DEP_NEIGH;
229 break;
230 }
231 default:
232 if (!word)
233 word = ptr;
234 }
235
236 /* fall through to the paren failure below */
237 if (paren_balanced < 0)
238 break;
239 }
240
241 if (paren_balanced != 0) {
242 warnf("Parenthesis unbalanced");
243 goto error_out;
244 }
245
246 /* if the depend buffer wasnt terminated with a space,
247 * we may have a word sitting in the buffer to consume */
248 _maybe_consume_word(DEP_NORM);
249
250 #undef _maybe_consume_word
251
252 return ret;
253
254 error_out:
255 warnf("DEPEND: %s", depend);
256 if (ret) {
257 dep_dump_tree(ret);
258 dep_burn_tree(ret);
259 }
260 return NULL;
261 }
262
263 #ifdef EBUG
264 void _dep_dump_tree(dep_node *root, int space)
265 {
266 int spaceit = space;
267 assert(root);
268 if (root->type == DEP_NULL) goto this_node_sucks;
269
270 while (spaceit--) printf("\t");
271 printf("Node [%s]: ", _dep_names[root->type]);
272 /*printf("Node %p [%s] %p %p %p: ", root, _dep_names[root->type], root->parent, root->neighbor, root->children);*/
273 if (root->info) printf("'%s'", root->info);
274 printf("\n");
275
276 if (root->children) _dep_dump_tree(root->children, space+1);
277 this_node_sucks:
278 if (root->neighbor) _dep_dump_tree(root->neighbor, space);
279 }
280 #else
281 void _dep_dump_tree(_q_unused_ dep_node *root, _q_unused_ int space) {;}
282 #endif
283
284 void dep_burn_tree(dep_node *root)
285 {
286 assert(root);
287 if (root->children) dep_burn_tree(root->children);
288 if (root->neighbor) dep_burn_tree(root->neighbor);
289 _dep_burn_node(root);
290 }
291
292 void dep_prune_use(dep_node *root, char *use)
293 {
294 if (root->neighbor) dep_prune_use(root->neighbor, use);
295 if (root->type == DEP_USE) {
296 char *useflag = NULL;
297 int notfound, invert = (root->info[0] == '!' ? 1 : 0);
298 xasprintf(&useflag, " %s ", root->info+invert);
299 notfound = (strstr(use, useflag) == NULL ? 1 : 0);
300 free(useflag);
301 if (notfound ^ invert) {
302 root->type = DEP_NULL;
303 return;
304 }
305 }
306 if (root->children) dep_prune_use(root->children, use);
307 }
308
309 void _dep_flatten_tree(dep_node *root, char *buf, size_t *pos)
310 {
311 if (root->type == DEP_NULL) goto this_node_sucks;
312 if (root->type == DEP_NORM) {
313 size_t len = strlen(root->info);
314 #if 1
315 if (*root->info == 'v')
316 if (strncmp(root->info, "virtual/", 8) == 0) {
317 if (virtuals == NULL)
318 virtuals = resolve_virtuals();
319 IF_DEBUG(fprintf(stderr, "(%s->%s)", root->info, virtual(root->info, virtuals)));
320 }
321 #endif
322 memcpy(buf + *pos, root->info, len);
323 *pos += len+1;
324 buf[*pos-1] = ' ';
325 }
326 if (root->children) _dep_flatten_tree(root->children, buf, pos);
327 this_node_sucks:
328 if (root->neighbor) _dep_flatten_tree(root->neighbor, buf, pos);
329 }
330
331 char *dep_flatten_tree(dep_node *root)
332 {
333 static char flat[8192];
334 size_t pos = 0;
335 _dep_flatten_tree(root, flat, &pos);
336 if (pos == 0) {
337 /* all the nodes were squashed ... for example:
338 * USE=-selinux RDEPEND="selinux? ( sys-libs/libselinux )"
339 */
340 return NULL;
341 }
342 flat[pos-1] = '\0';
343 return flat;
344 }
345
346 struct qdepends_opt_state {
347 int argc;
348 char **argv;
349 const char *depend_file;
350 const char *query;
351 };
352
353 _q_static int qdepends_main_vdb_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
354 {
355 struct qdepends_opt_state *state = priv;
356 const char *catname = pkg_ctx->cat_ctx->name;
357 const char *pkgname = pkg_ctx->name;
358 size_t len;
359 int i;
360 char *ptr;
361 char buf[_Q_PATH_MAX];
362 char depend[65536], use[8192];
363 dep_node *dep_tree;
364
365 /* see if this cat/pkg is requested */
366 for (i = optind; i < state->argc; ++i) {
367 snprintf(buf, sizeof(buf), "%s/%s", catname, pkgname);
368 if (rematch(state->argv[i], buf, REG_EXTENDED) == 0)
369 break;
370 if (rematch(state->argv[i], pkgname, REG_EXTENDED) == 0)
371 break;
372 }
373 if (i == state->argc)
374 return 0;
375
376 IF_DEBUG(warn("matched %s/%s", catname, pkgname));
377
378 if (!eat_file_at(pkg_ctx->fd, state->depend_file, depend, sizeof(depend)))
379 return 0;
380
381 IF_DEBUG(warn("growing tree..."));
382 dep_tree = dep_grow_tree(depend);
383 if (dep_tree == NULL)
384 return 0;
385 IF_DEBUG(puts(depend));
386 IF_DEBUG(dep_dump_tree(dep_tree));
387
388 if (qdep_name_only) {
389 depend_atom *atom = NULL;
390 snprintf(buf, sizeof(buf), "%s/%s", catname, pkgname);
391 if ((atom = atom_explode(buf)) != NULL) {
392 printf("%s%s/%s%s%s: ", BOLD, catname, BLUE, atom->PN, NORM);
393 atom_implode(atom);
394 }
395 } else {
396 printf("%s%s/%s%s%s: ", BOLD, catname, BLUE, pkgname, NORM);
397 }
398
399 if (!eat_file_at(pkg_ctx->fd, "USE", use, sizeof(use))) {
400 warn("Could not eat_file(%s), you'll prob have incorrect output", buf);
401 } else {
402 for (ptr = use; *ptr; ++ptr)
403 if (*ptr == '\n' || *ptr == '\t')
404 *ptr = ' ';
405 len = strlen(use);
406 assert(len+1 < sizeof(use));
407 use[len] = ' ';
408 use[len+1] = '\0';
409 memmove(use+1, use, len);
410 use[0] = ' ';
411
412 dep_prune_use(dep_tree, use);
413 }
414
415 /*dep_dump_tree(dep_tree);*/
416 ptr = dep_flatten_tree(dep_tree);
417 printf("%s\n", (ptr == NULL ? "" : ptr));
418
419 dep_burn_tree(dep_tree);
420
421 return EXIT_SUCCESS;
422 }
423
424 _q_static int qdepends_vdb_deep_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
425 {
426 struct qdepends_opt_state *state = priv;
427 const char *catname = pkg_ctx->cat_ctx->name;
428 const char *pkgname = pkg_ctx->name;
429 size_t len;
430 char *ptr;
431 char buf[_Q_PATH_MAX];
432 char depend[16384], use[8192];
433 dep_node *dep_tree;
434
435 IF_DEBUG(warn("matched %s/%s", catname, pkgname));
436
437 if (!eat_file_at(pkg_ctx->fd, state->depend_file, depend, sizeof(depend)))
438 return 0;
439
440 IF_DEBUG(warn("growing tree..."));
441 dep_tree = dep_grow_tree(depend);
442 if (dep_tree == NULL)
443 return 0;
444 IF_DEBUG(puts(depend));
445 IF_DEBUG(dep_dump_tree(dep_tree));
446
447 if (eat_file_at(pkg_ctx->fd, "USE", use, sizeof(use)) == 1)
448 use[0] = ' ';
449
450 for (ptr = use; *ptr; ++ptr)
451 if (*ptr == '\n' || *ptr == '\t')
452 *ptr = ' ';
453 len = strlen(use);
454 assert(len+1 < sizeof(use));
455 use[len] = ' ';
456 use[len+1] = '\0';
457 memmove(use+1, use, len);
458 use[0] = ' ';
459
460 dep_prune_use(dep_tree, use);
461
462 ptr = dep_flatten_tree(dep_tree);
463 if (ptr && rematch(state->query, ptr, REG_EXTENDED) == 0) {
464 if (qdep_name_only) {
465 depend_atom *atom = NULL;
466 snprintf(buf, sizeof(buf), "%s/%s", catname, pkgname);
467 if ((atom = atom_explode(buf)) != NULL) {
468 printf("%s%s/%s%s%s%c", BOLD, catname, BLUE, atom->PN, NORM, verbose ? ':' : '\n');
469 atom_implode(atom);
470 }
471 } else {
472 printf("%s%s/%s%s%s%c", BOLD, catname, BLUE, pkgname, NORM, verbose ? ':' : '\n');
473 }
474 if (verbose)
475 printf(" %s\n", ptr);
476 }
477 dep_burn_tree(dep_tree);
478
479 return EXIT_SUCCESS;
480 }
481
482 int qdepends_main(int argc, char **argv)
483 {
484 struct qdepends_opt_state state = {
485 .argc = argc,
486 .argv = argv,
487 };
488 q_vdb_pkg_cb *cb;
489 int i;
490 const char *query = NULL;
491 const char *depend_file;
492 const char *depend_files[] = { "DEPEND", "RDEPEND", "PDEPEND", NULL, NULL };
493
494 depend_file = depend_files[0];
495
496 DBG("argc=%d argv[0]=%s argv[1]=%s",
497 argc, argv[0], argc > 1 ? argv[1] : "NULL?");
498
499 while ((i = GETOPT_LONG(QDEPENDS, qdepends, "")) != -1) {
500 switch (i) {
501 COMMON_GETOPTS_CASES(qdepends)
502
503 case 'd': depend_file = depend_files[0]; break;
504 case 'r': depend_file = depend_files[1]; break;
505 case 'p': depend_file = depend_files[2]; break;
506 case 'k': depend_file = optarg; break;
507 case 'a': depend_file = NULL; break;
508 case 'Q': query = optarg; break;
509 case 'N': qdep_name_only = 1; break;
510 }
511 }
512 if ((argc == optind) && (query == NULL))
513 qdepends_usage(EXIT_FAILURE);
514
515 state.depend_file = depend_file;
516 state.query = query;
517 cb = query ? qdepends_vdb_deep_cb : qdepends_main_vdb_cb;
518
519 if (!depend_file) {
520 int ret = 0;
521 for (i = 0; depend_files[i]; ++i) {
522 printf(" %s*%s %s\n", GREEN, NORM, depend_files[i]);
523 state.depend_file = depend_files[i];
524 ret += q_vdb_foreach_pkg(cb, &state, NULL);
525 }
526 return ret;
527 }
528
529 return q_vdb_foreach_pkg(cb, &state, NULL);
530 }
531
532 #else
533 DEFINE_APPLET_STUB(qdepends)
534 #endif

  ViewVC Help
Powered by ViewVC 1.1.20