コード例 #1
0
ファイル: qatom.c プロジェクト: gentoo/portage-utils
int qatom_main(int argc, char **argv)
{
	enum qatom_atom { _EXPLODE=0, _COMPARE, _PRINT } action = _EXPLODE;
	const char *format = QATOM_FORMAT;
	depend_atom *atom;
	depend_atom *atomc;
	int i;

	while ((i = GETOPT_LONG(QATOM, qatom, "")) != -1) {
		switch (i) {
		case 'F': format = optarg; break;
		case 'c': action = _COMPARE; break;
		case 'p': action = _PRINT; break;
		COMMON_GETOPTS_CASES(qatom)
		}
	}

	if (argc == optind)
		qatom_usage(EXIT_FAILURE);

	if (action == _COMPARE && (argc - optind) % 2)
		err("compare needs even number of arguments");

	for (i = optind; i < argc; ++i) {
		atom = atom_explode(argv[i]);
		if (atom == NULL) {
			warnf("invalid atom: %s\n", argv[i]);
			continue;
		}

		switch (action) {
		case _COMPARE:
			i++;
			atomc = atom_explode(argv[i]);
			if (atomc == NULL) {
				warnf("invalid atom: %s\n", argv[i]);
				break;
			}
			printf("%s %s ",
					atom_to_string(atom),
					booga[atom_compare(atom, atomc)]);
			printf("%s\n",
					atom_to_string(atomc));
			atom_implode(atomc);
			break;
		case _EXPLODE:
			qatom_printf(format, atom, verbose);
			putchar('\n');
			break;
		case _PRINT:
			printf("%s\n", atom_to_string(atom));
			break;
		}

		atom_implode(atom);
	}

	return EXIT_SUCCESS;
}
コード例 #2
0
ファイル: qgrep.c プロジェクト: den4ix/portage-utils
char qgrep_name_match(const char* name, const int argc, depend_atom** argv)
{
	depend_atom* atom;
	int i;

	if ((atom = atom_explode(name)) == NULL)
		return 0;

	for (i = 0; i < argc; i++) {
		if (argv[i] == NULL)
			continue;
		if (atom->CATEGORY && argv[i]->CATEGORY && *(argv[i]->CATEGORY)
				&& strcmp(atom->CATEGORY, argv[i]->CATEGORY))
			continue;
		if (atom->PN && argv[i]->PN && *(argv[i]->PN)
				&& strcmp(atom->PN, argv[i]->PN))
			continue;
		if (atom->PVR && argv[i]->PVR && *(argv[i]->PVR)
				&& strcmp(atom->PVR, argv[i]->PVR))
			continue;
		atom_implode(atom);
		return 1;
	}

	atom_implode(atom);
	return 0;
}
コード例 #3
0
ファイル: qgrep.c プロジェクト: gentoo/portage-utils
static int
qgrep_cache_cb(cache_pkg_ctx *pkg_ctx, void *priv)
{
	struct qgrep_grepargs *data = (struct qgrep_grepargs *)priv;
	char buf[_Q_PATH_MAX];
	char name[_Q_PATH_MAX];
	char *label;
	depend_atom *patom = NULL;
	cache_ctx *cctx;
	int ret;
	int pfd;

	snprintf(buf, sizeof(buf), "%s/%s",
			pkg_ctx->cat_ctx->name, pkg_ctx->name);
	patom = atom_explode(buf);
	if (patom == NULL)
		return EXIT_FAILURE;

	if (data->include_atoms != NULL) {
		depend_atom **d;
		for (d = data->include_atoms; *d != NULL; d++) {
			if (atom_compare(patom, *d) == EQUAL)
				break;
		}
		if (*d == NULL) {
			atom_implode(patom);
			return EXIT_FAILURE;
		}
	}

	/* need to construct path in portdir to ebuild, pass it to grep */
	cctx = (cache_ctx *)(pkg_ctx->cat_ctx->ctx);
	if (cctx->cachetype == CACHE_EBUILD) {
		pfd = cctx->vdb_fd;
	} else {
		pfd = openat(cctx->vdb_fd, "../..", O_RDONLY|O_CLOEXEC);
	}

	/* cat/pkg/pkg-ver.ebuild */
	snprintf(buf, sizeof(buf), "%s/%s/%s.ebuild",
			patom->CATEGORY, patom->PN, patom->P);

	label = NULL;
	if (data->show_name) {
		char *repo = data->show_repo ? cctx->repo : NULL;
		snprintf(name, sizeof(name), "%s%s/%s%s%s%s%s%s",
				BOLD, patom->CATEGORY, BLUE, patom->P, GREEN,
				repo ? "::" : "", repo ? repo : "", NORM);
		label = name;
	} else if (data->show_filename) {
		label = buf;
	}

	ret = qgrep_grepat(pfd, buf, label, data);

	atom_implode(patom);

	return ret;
}
コード例 #4
0
ファイル: qgrep.c プロジェクト: gentoo/portage-utils
static int
qgrep_vdb_cb(q_vdb_pkg_ctx *pkg_ctx, void *priv)
{
	struct qgrep_grepargs *data = (struct qgrep_grepargs *)priv;
	char buf[_Q_PATH_MAX];
	char name[_Q_PATH_MAX];
	char *label;
	depend_atom *patom = NULL;
	int ret;
	int pfd;

	snprintf(buf, sizeof(buf), "%s/%s",
			pkg_ctx->cat_ctx->name, pkg_ctx->name);
	patom = atom_explode(buf);
	if (patom == NULL)
		return EXIT_FAILURE;

	if (data->include_atoms != NULL) {
		depend_atom **d;
		for (d = data->include_atoms; *d != NULL; d++) {
			if (atom_compare(patom, *d) == EQUAL)
				break;
		}
		if (*d == NULL) {
			atom_implode(patom);
			return EXIT_FAILURE;
		}
	}

	/* get path to portdir */
	pfd = openat(pkg_ctx->cat_ctx->ctx->portroot_fd,
			data->portdir, O_RDONLY|O_CLOEXEC);

	/* cat/pkg/pkg-ver.ebuild */
	snprintf(buf, sizeof(buf), "%s/%s/%s.ebuild",
			patom->CATEGORY, patom->PN, patom->P);

	label = NULL;
	if (data->show_name) {
		snprintf(name, sizeof(name), "%s%s/%s%s%s",
				BOLD, patom->CATEGORY, BLUE, patom->P, NORM);
		label = name;
	} else if (data->show_filename) {
		label = buf;
	}

	ret = qgrep_grepat(pfd, buf, label, data);

	atom_implode(patom);

	return ret;
}
コード例 #5
0
ファイル: qpkg.c プロジェクト: gentoo/portage-utils
static int
qpkg_cb(cache_pkg_ctx *pkg_ctx, void *priv)
{
	set *vdb = (set *)priv;
	depend_atom *atom;
	char buf[_Q_PATH_MAX];

	snprintf(buf, sizeof(buf), "%s/%s", pkg_ctx->cat_ctx->name, pkg_ctx->name);
	atom = atom_explode(buf);
	if (atom == NULL)
		return 0;

	vdb = add_set(buf, vdb);

	return 1;
}
コード例 #6
0
ファイル: qpkg.c プロジェクト: gentoo/portage-utils
int qpkg_main(int argc, char **argv)
{
	q_vdb_ctx *ctx;
	q_vdb_cat_ctx *cat_ctx;
	q_vdb_pkg_ctx *pkg_ctx;
	size_t s, pkgs_made;
	int i;
	struct stat st;
	char buf[BUFSIZE];
	const char *bindir;
	depend_atom *atom;
	int restrict_chmod = 0;
	int qclean = 0;

	while ((i = GETOPT_LONG(QPKG, qpkg, "")) != -1) {
		switch (i) {
		case 'E': eclean = qclean = 1; break;
		case 'c': qclean = 1; break;
		case 'p': pretend = 1; break;
		case 'P':
			restrict_chmod = 1;
			free(qpkg_bindir);
			qpkg_bindir = xstrdup(optarg);
			if (access(qpkg_bindir, W_OK) != 0)
				errp("%s", qpkg_bindir);
			break;
		COMMON_GETOPTS_CASES(qpkg)
		}
	}
	if (qclean)
		return qpkg_clean(qpkg_bindir == NULL ? pkgdir : qpkg_bindir);

	if (argc == optind)
		qpkg_usage(EXIT_FAILURE);

	/* setup temp dirs */
	i = 0;
	bindir = qpkg_get_bindir();
	if (*bindir != '/')
		err("'%s' is not a valid package destination", bindir);
retry_mkdir:
	if (mkdir(bindir, 0750) == -1) {
		lstat(bindir, &st);
		if (!S_ISDIR(st.st_mode)) {
			unlink(bindir);
			if (!i++) goto retry_mkdir;
			errp("could not create temp bindir '%s'", bindir);
		}
		if (!restrict_chmod)
			if (chmod(bindir, 0750))
				errp("could not chmod(0750) temp bindir '%s'", bindir);
	}

	/* we have to change to the root so that we can feed the full paths
	 * to tar when we create the binary package. */
	xchdir(portroot);

	/* first process any arguments which point to /var/db/pkg */
	pkgs_made = 0;
	s = strlen(portvdb);
	for (i = optind; i < argc; ++i) {
		size_t asize = strlen(argv[i]);
		if (asize == 0) {
			argv[i] = NULL;
			continue;
		}
		if (argv[i][asize-1] == '/')
			argv[i][asize-1] = '\0';
		if (!strncmp(portvdb, argv[i], s))
			memmove(argv[i], argv[i]+s+1, asize-s);
		else if (argv[i][0] == '/' && !strncmp(portvdb, argv[i]+1, s))
			memmove(argv[i], argv[i]+s+2, asize-s-1);
		else
			continue;

		atom = atom_explode(argv[i]);
		if (atom) {
			if (!qpkg_make(atom)) ++pkgs_made;
			atom_implode(atom);
		} else
			warn("could not explode '%s'", argv[i]);
		argv[i] = NULL;
	}

	/* now try to run through vdb and locate matches for user inputs */
	ctx = q_vdb_open(portroot, portvdb);
	if (!ctx)
		return EXIT_FAILURE;

	/* scan all the categories */
	while ((cat_ctx = q_vdb_next_cat(ctx))) {
		/* scan all the packages in this category */
		const char *catname = cat_ctx->name;
		while ((pkg_ctx = q_vdb_next_pkg(cat_ctx))) {
			const char *pkgname = pkg_ctx->name;

			/* see if user wants any of these packages */
			snprintf(buf, sizeof(buf), "%s/%s", catname, pkgname);
			atom = atom_explode(buf);
			if (!atom) {
				warn("could not explode '%s'", buf);
				goto next_pkg;
			}
			snprintf(buf, sizeof(buf), "%s/%s", atom->CATEGORY, atom->PN);
			for (i = optind; i < argc; ++i) {
				if (!argv[i]) continue;

				if (!strcmp(argv[i], atom->PN) ||
						!strcmp(argv[i], atom->P) ||
						!strcmp(argv[i], buf) ||
						!strcmp(argv[i], "world"))
					if (!qpkg_make(atom))
						++pkgs_made;
			}
			atom_implode(atom);

 next_pkg:
			q_vdb_close_pkg(pkg_ctx);
		}
	}

	s = (argc - optind) - pkgs_made;
	if (s && !pretend)
		printf(" %s*%s %i package%s could not be matched :/\n",
				RED, NORM, (int)s, (s > 1 ? "s" : ""));
	if (pkgs_made)
		qprintf(" %s*%s Packages can be found in %s\n", GREEN, NORM, bindir);

	return (pkgs_made ? EXIT_SUCCESS : EXIT_FAILURE);
}
コード例 #7
0
ファイル: qgrep.c プロジェクト: den4ix/portage-utils
int qgrep_main(int argc, char **argv)
{
	int i;
	int count = 0;
	char *p;
	char do_count, do_regex, do_eclass, do_installed, do_list;
	char show_filename, skip_comments, invert_list, show_name;
	char per_file_output;
	FILE *fp = NULL;
	DIR *eclass_dir = NULL;
	DIR *vdb_dir = NULL;
	DIR *cat_dir = NULL;
	struct dirent *dentry;
	char ebuild[_Q_PATH_MAX];
	char name[_Q_PATH_MAX];
	char *label;
	int reflags = 0;
	char invert_match = 0;
	regex_t preg, skip_preg;
	char *skip_pattern = NULL;
	depend_atom** include_atoms = NULL;
	unsigned long int context_optarg;
	char num_lines_before = 0;
	char num_lines_after = 0;
	qgrep_buf_t *buf_list;
	int need_separator = 0;
	char status = 1;

	QGREP_STR_FUNC strfunc = strstr;

	do_count = do_regex = do_eclass = do_installed = do_list = 0;
	show_filename = skip_comments = invert_list = show_name = 0;

	while ((i = GETOPT_LONG(QGREP, qgrep, "")) != -1) {
		switch (i) {
		case 'I': invert_match = 1; break;
		case 'i':
			strfunc = strcasestr;
			reflags |= REG_ICASE;
			break;
		case 'c': do_count = 1; break;
		case 'l': do_list = 1; break;
		case 'L': do_list = invert_list = 1; break;
		case 'e': do_regex = 1; break;
		case 'x':
			do_regex = 1;
			reflags |= REG_EXTENDED;
			break;
		case 'J': do_installed = 1; break;
		case 'E': do_eclass = 1; break;
		case 'H': show_filename = 1; break;
		case 'N': show_name = 1; break;
		case 's': skip_comments = 1; break;
		case 'S': skip_pattern = optarg; break;
		case 'B':
		case 'A':
			errno = 0;
			context_optarg = strtol(optarg, &p, 10);
			if (errno != 0)
				errp("%s: not a valid integer", optarg);
			else if (p == optarg || *p != '\0')
				err("%s: not a valid integer", optarg);
			if (context_optarg > 254)
				err("%s: silly value!", optarg);
			if (i == 'B')
				num_lines_before = context_optarg;
			else
				num_lines_after = context_optarg;
			break;
		COMMON_GETOPTS_CASES(qgrep)
		}
	}
	if (argc == optind)
		qgrep_usage(EXIT_FAILURE);

	if (do_list && do_count) {
		warn("%s and --count are incompatible options. The former wins.",
				(invert_list ? "--invert-list" : "--list"));
		do_count = 0;
	}

	if (show_name && show_filename) {
		warn("--with-name and --with-filename are incompatible options. The former wins.");
		show_filename = 0;
	}

	if (do_list && num_lines_before) {
		warn("%s and --before are incompatible options. The former wins.",
				(invert_list ? "--invert-list" : "--list"));
		num_lines_before = 0;
	}

	if (do_list && num_lines_after) {
		warn("%s and --after are incompatible options. The former wins.",
				(invert_list ? "--invert-list" : "--list"));
		num_lines_after = 0;
	}

	if (do_count && num_lines_before) {
		warn("--count and --before are incompatible options. The former wins.");
		num_lines_before = 0;
	}

	if (do_count && num_lines_after) {
		warn("--count and --after are incompatible options. The former wins.");
		num_lines_after = 0;
	}

	if (do_installed && do_eclass) {
		warn("--installed and --eclass are incompatible options. The former wins.");
		do_eclass = 0;
	}

	/* do we report results once per file or per line ? */
	per_file_output = do_count || (do_list && (!verbose || invert_list));
	/* label for prefixing matching lines or listing matching files */
	label = (show_name ? name : ((verbose || show_filename || do_list) ? ebuild : NULL));

	if (argc > (optind + 1)) {
		include_atoms = xcalloc(sizeof(depend_atom*), (argc - optind - 1));
		for (i = (optind + 1); i < argc; i++)
			if ((include_atoms[i - optind - 1] = atom_explode(argv[i])) == NULL)
				warn("%s: invalid atom, will be ignored", argv[i]);
	}

	/* pre-compile regexps once for all */
	if (do_regex) {
		if (invert_match || *RED == '\0')
			reflags |= REG_NOSUB;
		xregcomp(&preg, argv[optind], reflags);
		reflags |= REG_NOSUB;
		if (skip_pattern)
			xregcomp(&skip_preg, skip_pattern, reflags);
	}

	/* allocate a circular buffers list for --before */
	buf_list = qgrep_buf_list_alloc(num_lines_before + 1);

	size_t n;
	char *overlay;
	array_for_each(overlays, n, overlay) {

		/* go look either in ebuilds or eclasses or VDB */
		if (!do_eclass && !do_installed) {
			fp = fopen(initialize_flat(overlay, CACHE_EBUILD, false), "re");
			if (fp == NULL)
				continue;
			xchdir(overlay);
		} else if (do_eclass) {
			xchdir(overlay);
			if ((eclass_dir = opendir("eclass")) == NULL) {
				if (errno != ENOENT)
					warnp("opendir(\"%s/eclass\") failed", overlay);
				continue;
			}
		} else { /* if (do_install) */
			char buf[_Q_PATH_MAX];
			snprintf(buf, sizeof(buf), "%s/%s", portroot, portvdb);
			xchdir(buf);
			if ((vdb_dir = opendir(".")) == NULL)
				errp("could not opendir(%s/%s) for ROOT/VDB", portroot, portvdb);
		}

		/* iteration is either over ebuilds or eclasses */
		while (do_eclass
				? ((dentry = readdir(eclass_dir))
					&& snprintf(ebuild, sizeof(ebuild), "eclass/%s", dentry->d_name))
				: (do_installed
					? (get_next_installed_ebuild(ebuild, vdb_dir, &dentry, &cat_dir) != NULL)
					: (fgets(ebuild, sizeof(ebuild), fp) != NULL))) {
			FILE *newfp;

			/* filter badly named files, prepare eclass or package name, etc. */
			if (do_eclass) {
				if ((p = strrchr(ebuild, '.')) == NULL)
					continue;
				if (strcmp(p, ".eclass"))
					continue;
				if (show_name || (include_atoms != NULL)) {
					/* cut ".eclass" */
					*p = '\0';
					/* and skip "eclass/" */
					snprintf(name, sizeof(name), "%s", ebuild + 7);
					/* restore the filepath */
					*p = '.';
				}
			} else {
				if ((p = strchr(ebuild, '\n')) != NULL)
					*p = '\0';
				if (show_name || (include_atoms != NULL)) {
					/* cut ".ebuild" */
					if (p == NULL)
						p = ebuild + strlen(ebuild);
					*(p-7) = '\0';
					/* cut "/foo/" from "cat/foo/foo-x.y" */
					if ((p = strchr(ebuild, '/')) == NULL)
						continue;
					*(p++) = '\0';
					/* find head of the ebuild basename */
					if ((p = strchr(p, '/')) == NULL)
						continue;
					/* find	start of the pkg name */
					snprintf(name, sizeof(name), "%s/%s", ebuild, (p+1));
					/* restore the filepath */
					*p = '/';
					*(p + strlen(p)) = '.';
					ebuild[strlen(ebuild)] = '/';
				}
			}

			/* filter the files we grep when there are extra args */
			if (include_atoms != NULL)
				if (!qgrep_name_match(name, (argc - optind - 1), include_atoms))
					continue;

			if ((newfp = fopen(ebuild, "r")) != NULL) {
				int lineno = 0;
				char remaining_after_context = 0;
				count = 0;
				/* if there have been some matches already, then a separator will be needed */
				need_separator = (!status) && (num_lines_before || num_lines_after);
				/* whatever is in the circular buffers list is no more a valid context */
				qgrep_buf_list_invalidate(buf_list);

				/* reading a new line always happen in the next buffer of the list */
				while ((buf_list = buf_list->next)
						&& (fgets(buf_list->buf, sizeof(buf_list->buf), newfp)) != NULL) {
					lineno++;
					buf_list->valid = 1;

					/* cleanup EOL */
					if ((p = strrchr(buf_list->buf, '\n')) != NULL)
						*p = 0;
					if ((p = strrchr(buf_list->buf, '\r')) != NULL)
						*p = 0;

					if (skip_comments) {
						/* reject comments line ("^[ \t]*#") */
						p = buf_list->buf;
						while (*p == ' ' || *p == '\t') p++;
						if (*p == '#')
							goto print_after_context;
					}

					if (skip_pattern) {
						/* reject some other lines which match an optional pattern */
						if (!do_regex) {
							if (strfunc(buf_list->buf, skip_pattern) != NULL)
								goto print_after_context;
						} else {
							if (regexec(&skip_preg, buf_list->buf, 0, NULL, 0) == 0)
								goto print_after_context;
						}
					}

					/* four ways to match a line (with/without inversion and regexp) */
					if (!invert_match) {
						if (do_regex == 0) {
							if (strfunc(buf_list->buf, argv[optind]) == NULL)
								goto print_after_context;
						} else {
							if (regexec(&preg, buf_list->buf, 0, NULL, 0) != 0)
								goto print_after_context;
						}
					} else {
						if (do_regex == 0) {
							if (strfunc(buf_list->buf, argv[optind]) != NULL)
								goto print_after_context;
						} else {
							if (regexec(&preg, buf_list->buf, 0, NULL, 0) == 0)
								goto print_after_context;
						}
					}

					count++;
					status = 0; /* got a match, exit status should be 0 */
					if (per_file_output)
						continue; /* matching files are listed out of this loop */

					if ((need_separator > 0)
							&& (num_lines_before || num_lines_after))
						printf("--\n");
					/* "need_separator" is not a flag, but a counter, so that
					 * adjacent contextes are not separated */
					need_separator = 0 - num_lines_before;
					if (!do_list) {
						/* print the leading context */
						qgrep_print_before_context(buf_list, num_lines_before, label,
								((verbose > 1) ? lineno : -1));
						/* print matching line */
						if (invert_match || *RED == '\0')
							qgrep_print_matching_line_nocolor(buf_list, label,
								((verbose > 1) ? lineno : -1));
						else if (do_regex)
							qgrep_print_matching_line_regcolor(buf_list, label,
								((verbose > 1) ? lineno : -1), &preg);
						else
							qgrep_print_matching_line_strcolor(buf_list, label,
								((verbose > 1) ? lineno : -1), strfunc, argv[optind]);
					} else {
						/* in verbose do_list mode, list the file once per match */
						printf("%s", label);
						if (verbose > 1)
							printf(":%d", lineno);
						putchar('\n');
					}
					/* init count down of trailing context lines */
					remaining_after_context = num_lines_after;
					continue;

 print_after_context:
					/* print some trailing context lines when needed */
					if (!remaining_after_context) {
						if (!status)
							/* we're getting closer to the need of a separator between
							 * current match block and the next one */
							++need_separator;
					} else {
						qgrep_print_context_line(buf_list, label,
								((verbose > 1) ? lineno : -1));
						--remaining_after_context;
					}
				}
				fclose(newfp);
				if (!per_file_output)
					continue; /* matches were already displayed, line per line */
				if (do_count && count) {
					if (label != NULL)
						/* -c without -v/-N/-H only outputs
						 * the matches count of the file */
						printf("%s:", label);
					printf("%d\n", count);
				} else if ((count && !invert_list) || (!count && invert_list))
					printf("%s\n", label); /* do_list == 1, or we wouldn't be here */
			}
		}
		if (do_eclass)
			closedir(eclass_dir);
		else if (!do_installed)
			fclose(fp);

		if (do_installed)
			break;
	}

	if (do_regex)
		regfree(&preg);
	if (do_regex && skip_pattern)
		regfree(&skip_preg);
	if (include_atoms != NULL) {
		for (i = 0; i < (argc - optind - 1); i++)
			if (include_atoms[i] != NULL)
				atom_implode(include_atoms[i]);
		free(include_atoms);
	}
	qgrep_buf_list_free(buf_list);

	return status;
}
コード例 #8
0
ファイル: qgrep.c プロジェクト: gentoo/portage-utils
int qgrep_main(int argc, char **argv)
{
	int i;
	char *p;
	bool do_eclass;
	bool do_installed;
	DIR *eclass_dir = NULL;
	struct dirent *dentry = NULL;
	int reflags = 0;
	unsigned long int context_optarg;
	char status = 1;
	size_t n;
	char *overlay;

	struct qgrep_grepargs args = {
		.do_count = 0,
		.do_regex = 0,
		.do_list = 0,
		.show_filename = 0,
		.show_name = 0,
		.skip_comments = 0,
		.invert_list = 0,
		.invert_match = 0,
		.skip_pattern = NULL,
		.num_lines_before = 0,
		.num_lines_after = 0,
		.buf_list = NULL,
		.query = NULL,
		.strfunc = strstr,
		.include_atoms = NULL,
		.portdir = NULL,
	};

	do_eclass = do_installed = 0;

	while ((i = GETOPT_LONG(QGREP, qgrep, "")) != -1) {
		switch (i) {
		case 'I': args.invert_match = true;               break;
		case 'i':
			args.strfunc = strcasestr;
			reflags |= REG_ICASE;
			break;
		case 'c': args.do_count = true;                   break;
		case 'l': args.do_list = true;                    break;
		case 'L': args.do_list = args.invert_list = true; break;
		case 'e': args.do_regex = true;                   break;
		case 'x':
			args.do_regex = true;
			reflags |= REG_EXTENDED;
			break;
		case 'J': do_installed = true;                    break;
		case 'E': do_eclass = true;                       break;
		case 'H': args.show_filename = true;              break;
		case 'N': args.show_name = true;                  break;
		case 's': args.skip_comments = true;              break;
		case 'R': args.show_repo = args.show_name = true; break;
		case 'S': args.skip_pattern = optarg;             break;
		case 'B':
		case 'A':
			errno = 0;
			context_optarg = strtol(optarg, &p, 10);
			if (errno != 0)
				errp("%s: not a valid integer", optarg);
			else if (p == optarg || *p != '\0')
				err("%s: not a valid integer", optarg);
			if (context_optarg > 254)
				err("%s: silly value!", optarg);
			if (i == 'B')
				args.num_lines_before = context_optarg;
			else
				args.num_lines_after = context_optarg;
			break;
		COMMON_GETOPTS_CASES(qgrep)
		}
	}
	if (argc == optind)
		qgrep_usage(EXIT_FAILURE);

	if (args.do_list && args.do_count) {
		warn("%s and --count are incompatible options. The former wins.",
				(args.invert_list ? "--invert-list" : "--list"));
		args.do_count = false;
	}

	if (args.show_name && args.show_filename) {
		warn("--with-name and --with-filename are incompatible options. "
				"The former wins.");
		args.show_filename = false;
	}

	if (args.do_list && args.num_lines_before) {
		warn("%s and --before are incompatible options. The former wins.",
				(args.invert_list ? "--invert-list" : "--list"));
		args.num_lines_before = 0;
	}

	if (args.do_list && args.num_lines_after) {
		warn("%s and --after are incompatible options. The former wins.",
				(args.invert_list ? "--invert-list" : "--list"));
		args.num_lines_after = 0;
	}

	if (args.do_count && args.num_lines_before) {
		warn("--count and --before are incompatible options. The former wins.");
		args.num_lines_before = 0;
	}

	if (args.do_count && args.num_lines_after) {
		warn("--count and --after are incompatible options. The former wins.");
		args.num_lines_after = 0;
	}

	if (do_installed && do_eclass) {
		warn("--installed and --eclass are incompatible options. "
				"The former wins.");
		do_eclass = false;
	}

	if (argc > (optind + 1)) {
		depend_atom **d = args.include_atoms =
			xcalloc(sizeof(depend_atom *), (argc - optind - 1) + 1);
		for (i = (optind + 1); i < argc; i++) {
			*d = atom_explode(argv[i]);
			if (*d == NULL) {
				warn("%s: invalid atom, will be ignored", argv[i]);
			} else {
				d++;
			}
		}
		*d = NULL;
	}

	/* make it easier to see what needs to be printed */
	if (!args.show_name && (verbose || args.do_list))
		args.show_filename = true;

	/* pre-compile regexps once for all */
	if (args.do_regex) {
		if (args.invert_match || *RED == '\0')
			reflags |= REG_NOSUB;
		xregcomp(&args.preg, argv[optind], reflags);
		reflags |= REG_NOSUB;
		if (args.skip_pattern)
			xregcomp(&args.skip_preg, args.skip_pattern, reflags);
	}
	args.query = argv[optind];

	/* allocate a circular buffers list for --before */
	args.buf_list = qgrep_buf_list_alloc(args.num_lines_before + 1);

	array_for_each(overlays, n, overlay) {
		args.portdir = overlay;
		if (do_eclass) {
			char buf[_Q_PATH_MAX];
			char name[_Q_PATH_MAX];
			char *label;
			int efd;

			snprintf(buf, sizeof(buf), "%s/%s/eclass", portroot, overlay);
			efd = open(buf, O_RDONLY|O_CLOEXEC);
			if (efd == -1 || (eclass_dir = fdopendir(efd)) == NULL) {
				if (errno != ENOENT)
					warnp("opendir(\"%s/eclass\") failed", overlay);
				continue;
			}
			while ((dentry = readdir(eclass_dir)) != NULL) {
				if (strstr(dentry->d_name, ".eclass") == NULL)
					continue;
				/* filter the files we grep when there are extra args */
				if (args.include_atoms != NULL) {
					depend_atom **d;
					for (d = args.include_atoms; *d != NULL; d++) {
						if ((*d)->PN != NULL && strncmp(dentry->d_name,
									(*d)->PN, strlen((*d)->PN)) == 0)
							break;
					}
					if (*d == NULL)
						continue;
				}

				label = NULL;
				if (args.show_name) {
					snprintf(name, sizeof(name), "%s%.*s%s", BLUE,
							(int)(strlen(dentry->d_name) - 7), dentry->d_name,
							NORM);
					label = name;
				} else if (args.show_filename) {
					snprintf(name, sizeof(name), "eclass/%s", dentry->d_name);
					label = name;
				}
				status = qgrep_grepat(efd, dentry->d_name, label, &args);
			}
			closedir(eclass_dir);
		} else if (do_installed) {
			status = q_vdb_foreach_pkg(portroot, portvdb,
					qgrep_vdb_cb, &args, NULL);
		} else { /* do_ebuild */
			status = cache_foreach_pkg(portroot, overlay,
					qgrep_cache_cb, &args, NULL);
		}
	}

	if (args.do_regex)
		regfree(&args.preg);
	if (args.do_regex && args.skip_pattern)
		regfree(&args.skip_preg);
	if (args.include_atoms != NULL) {
		for (i = 0; i < (argc - optind - 1); i++)
			if (args.include_atoms[i] != NULL)
				atom_implode(args.include_atoms[i]);
		free(args.include_atoms);
	}
	qgrep_buf_list_free(args.buf_list);

	return status;
}