/*
 * euses is the first working incarnation of something
 * I called `guses' (for Gentoo uses, see
 * <http://www.xs4all.nl/~rooversj/gentoo/guses>) which
 * is a bash script I wrote that searches crudely for USE
 * flags in use.desc (UD) and use.local.desc (ULD) and returns the
 * matching lines with some fancy colouring.
 * I originally intended that to be the ultimate, but I
 * opted to learn a bit of C instead and have a much
 * faster working program. Not that speed matters much in
 * this case...
 *
 * It should compile on any basic Linux system.
 *
 * Thanks to KillerFox and #gentoo-hppa for their programming clues. :)
 *
 * This program was written by JeR in 2005, released first on May 9,
 * 2005 and is distributed under the GNU General Public License
 * version 2, a copy of which may be found at
 * <http://www.gnu.org/licenses/gpl.txt>.
 *
 * Mail your suggestions, improvements, complaints and questions to
 * jer at xs4all dot nl
 *
 * TODO: Add code to check a per user .euses file for the saved value of
 * PORTDIR -- Saves lots of time as opposed to opening a shell every time.
 * TODO: Add a reading pipe to obtain a (list of) string(s).
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define LINE_LENGTH 1024
#define UD "use.desc"
#define ULD "use.local.desc"
#define PROFILES "/profiles/"
#define EMF "/etc/make.conf"

/*Color definitions: */
#define BG "\033[01;32m"	/* Bright Green */
#define FC "\033[00m"		/* Normal       */
#define BW "\033[01;29m"	/* Bright White */
#define NC "\033[00;36m"	/* Normal Cyan  */
#define BR "\033[01;31m"	/* Bright Red   */

void usage()
{
	(void)puts("Usage:  euses <string>");
	(void)
	    puts
	    ("euses displays descriptions from use.[local.]desc of USE flags matching <string>");
	(void)printf("euses %s    Copyright JeR 2005\n", VERSION);
	exit(EXIT_SUCCESS);
}

void err_no(int err_no)
{
	switch (err_no) {
	case 0:
		printf("%s not found\n", EMF);
		break;
	case 1:
		printf("%s not found\n", UD);
		break;
	case 2:
		printf("%s not found\n", ULD);
		break;
	default:
		puts("Do you Gentoo?\n");
		break;
	}
	exit(EXIT_FAILURE);
}

void ud_format(char *use_line)
{
	int i;
	size_t len;
	len = strlen(use_line);
	(void)printf("%s", BG);
	for (i = 0; i < (int)len; ++i) {
		if (use_line[i] == ' ') {
			(void)printf("%s", FC);
		}
		(void)printf("%c", use_line[i]);
	}
	return;
}

void uld_format(char *use_line)
{
	int i;
	size_t len;
	int past_colon = 0;
	len = strlen(use_line);
	(void)printf("%s", NC);
	for (i = 0; i < (int)len; ++i) {
		if (&use_line[i] >= strstr(use_line, ":")) {
			switch (use_line[i]) {
			case ':':{
					if (past_colon == 0)
						(void)printf("%s%c%s", FC,
							     use_line[i], BG);
				}
				past_colon = 1;
				break;
			case ' ':
				(void)printf("%s%c", FC, use_line[i]);
				break;
			default:
				(void)printf("%c", use_line[i]);
				break;
			}
		} else
			printf("%c", use_line[i]);

	}
	return;
}

void getportdir(char *portdir)
{
	FILE *ptr;
	ptr = popen("source /etc/make.conf; echo -n ${PORTDIR}", "r");
	if (fgets(portdir, LINE_LENGTH, ptr) == NULL)
		err_no(0);
	if (strlen(portdir) == 0)
		(void)strcat(portdir, "/usr/portage");
	(void)pclose(ptr);
}

void ud_flag_fest(char *use_line, char *flag)
{
	int i = 0;
	int j = 0;

	while (use_line[i] != '\0') {
		while (use_line[i] != ' ') {
			flag[j++] = use_line[i++];
			continue;
		}
		break;
	}
}

void uld_flag_fest(char *use_line, char *flag)
{
	int i = 0;
	int j = 0;
	int chr_copy = 0;

	/* Remove the package name at the beginning */
	while (use_line[i] != '\0') {
		while (use_line[i] != ' ') {
			if (use_line[i] == ':') {
				chr_copy = 1;
				++i;
			} else {
			}
			if (chr_copy == 1)
				flag[j++] = use_line[i];
			++i;
			continue;
		}
		break;
	}
}

int filter_comments(char *line)
{
	if (line[0] == '#' || line[0] == '\n' || line[0] == ' ')
		return 1;
	else
		return 0;
}

void print_ud(int colour, char *use_line)
{
	if (colour == 1)
		(void)ud_format(use_line);
	else
		printf("      %s: %s", UD, use_line);
}

int match_ud(char *string,
	     char *use_line, char *ud_path, int ud_matches, int colour)
{
	FILE *ptr = NULL;
	int matches = 0;	/* Local match counter */
	char ud_flag[LINE_LENGTH];	/* The UD flag from use_line */
	char *match_chr;	/* Pointer to first matching character */

	ptr = fopen(ud_path, "r");
	if (ptr == NULL)
		err_no(1);
	while (feof(ptr) == 0) {
		while (fgets(use_line, LINE_LENGTH, ptr) != NULL) {
			if (filter_comments(use_line) == 0) {
				(void)ud_flag_fest(use_line, ud_flag);
				match_chr = strstr(ud_flag, string);
				(void)memset(ud_flag, 0, sizeof(ud_flag));
				if (match_chr != 0) {
					matches++;
					print_ud(colour, use_line);
				}
			}
		}
	}
	(void)fclose(ptr);
	ptr = NULL;
	if (matches > 0)
		ud_matches++;
	return ud_matches;
}

void match_err(int colour, char *string)
{
	if (colour == 1)
		printf("No matches for: %s%s%s\n", BR, string, FC);
	else
		printf("No matches for: %s\n", string);
}

void print_uld(int colour, char *use_line)
{
	if (colour == 1)
		(void)uld_format(use_line);
	else
		printf("%s: %s", ULD, use_line);
}

int match_uld(char *string, char *use_line, char *uld_path, int uld_matches,
	      int colour)
{
	FILE *ptr = NULL;
	int matches = 0;	/* Local match counter */
	char uld_flag[LINE_LENGTH];	/* The ULD flag from use_line */
	char *match_chr;	/* Pointer to first matching character */

	ptr = fopen(uld_path, "r");
	if (ptr == NULL)
		err_no(2);
	while (feof(ptr) == 0) {
		while (fgets(use_line, LINE_LENGTH, ptr) != NULL) {
			if (filter_comments(use_line) == 0) {
				(void)uld_flag_fest(use_line, uld_flag);
				match_chr = strstr(uld_flag, string);
				(void)memset(uld_flag, 0, sizeof(uld_flag));
				if (match_chr != 0) {
					matches++;
					print_uld(colour, use_line);
				}

			}
		}
	}
	(void)fclose(ptr);
	ptr = NULL;
	if (matches > 0)
		uld_matches++;
	return uld_matches;
}

int main(int argc, char **argv)
{
	int i;
	int colour = 0;		/* True if tty, otherwise False */
	int flag_matches = 0;	/* Counts the total number of matches */
	int ud_matches = 0;	/* Counter for the number of UD matches */
	int uld_matches = 0;	/* Counter for the number of ULD matches */
	char ud_path[LINE_LENGTH * 2];	/* Path to UD  */
	char uld_path[LINE_LENGTH * 2];	/* Path to ULD */
	char use_line[LINE_LENGTH];	/* A single line from UD or ULD */
	char path[LINE_LENGTH];	/* Stores a path */
	char *portdir = path;	/* Points to stored path */
	char ud_flag[LINE_LENGTH];	/* The UD flag from use_line */
	char uld_flag[LINE_LENGTH];	/* The ULD flag from use_line */

	(void)memset(ud_path, 0, sizeof(ud_path));
	(void)memset(uld_path, 0, sizeof(uld_path));
	(void)memset(ud_flag, 0, sizeof(ud_flag));
	(void)memset(uld_flag, 0, sizeof(uld_flag));

	/* Check in EMF where Portage is */
	getportdir(portdir);

	strcat(ud_path, portdir);
	strcat(ud_path, PROFILES);
	strcat(ud_path, UD);

	strcat(uld_path, portdir);
	strcat(uld_path, PROFILES);
	strcat(uld_path, ULD);

	if (isatty(STDOUT_FILENO) == 1)
		colour = 1;

	if (argc < 2)
		usage();
	else {
		for (i = 1; i < argc; ++i) {
			ud_matches = 0;
			ud_matches =
			    match_ud(argv[i], use_line, ud_path, ud_matches,
				     colour);
			uld_matches = 0;
			uld_matches =
			    match_uld(argv[i], use_line, uld_path, uld_matches,
				      colour);
			if (ud_matches > 0 || uld_matches > 0)
				flag_matches++;
			else
				match_err(colour, argv[i]);
		}
	}
	if (flag_matches != argc - 1)
		exit(EXIT_FAILURE);
	else
		exit(EXIT_SUCCESS);
}


syntax highlighted by Code2HTML, v. 0.9.1