Exemple #1
0
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;
}
Exemple #2
0
static int
qgrep_grepat(int fd, const char *file, const char *label,
		struct qgrep_grepargs *a)
{
	FILE *newfp;
	int need_separator = 0;
	int count = 0;
	int lineno = 0;
	char remaining_after_context = 0;
	char status = 1;
	char *p;
	bool per_file_output;

	/* do we report results once per file or per line ? */
	per_file_output =
		a->do_count || (a->do_list && (!verbose || a->invert_list));

	if (fd >= 0) {
		int sfd = openat(fd, file, O_RDONLY|O_CLOEXEC);
		newfp = sfd >= 0 ? fdopen(sfd, "r") : NULL;
	} else {
		newfp = fopen(file, "r");
	}
	if (newfp == NULL)
		return status;

	count = 0;
	/* if there have been some matches already, then a
	 * separator will be needed */
	need_separator =
		!status && (a->num_lines_before || a->num_lines_after);
	/* whatever is in the circular buffers list is no more a
	 * valid context */
	qgrep_buf_list_invalidate(a->buf_list);

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

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

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

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

		/* four ways to match a line (with/without inversion
		 * and regexp) */
		if (!a->invert_match) {
			if (a->do_regex == 0) {
				if (a->strfunc(a->buf_list->buf, a->query) == NULL)
					goto print_after_context;
			} else {
				if (regexec(&a->preg, a->buf_list->buf, 0, NULL, 0) != 0)
					goto print_after_context;
			}
		} else {
			if (a->do_regex == 0) {
				if (a->strfunc(a->buf_list->buf, a->query) != NULL)
					goto print_after_context;
			} else {
				if (regexec(&a->preg, a->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)
				&& (a->num_lines_before || a->num_lines_after))
			printf("--\n");
		/* "need_separator" is not a flag, but a counter, so that
		 * adjacent contextes are not separated */
		need_separator = 0 - a->num_lines_before;
		if (!a->do_list) {
			/* print the leading context */
			qgrep_print_before_context(a->buf_list,
					a->num_lines_before, label,
					((verbose > 1) ? lineno : -1));
			/* print matching line */
			if (a->invert_match || *RED == '\0')
				qgrep_print_matching_line_nocolor(a->buf_list, label,
						((verbose > 1) ? lineno : -1));
			else if (a->do_regex)
				qgrep_print_matching_line_regcolor(a->buf_list, label,
						((verbose > 1) ? lineno : -1), &a->preg);
			else
				qgrep_print_matching_line_strcolor(a->buf_list, label,
						((verbose > 1) ? lineno : -1), a->strfunc,
						a->query);
		} 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 = a->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(a->buf_list, label,
					((verbose > 1) ? lineno : -1));
			--remaining_after_context;
		}
	}
	fclose(newfp);
	if (per_file_output) {
		/* matches were already displayed, line per line */
		if (a->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 && !a->invert_list) ||
				(!count && a->invert_list))
		{
			printf("%s\n", label);
		}
		/* do_list == 1, or we wouldn't be here */
	}

	return status;
}