/*
 * 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 and use.local.desc 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, but since it
 * is intended to search in two Gentoo-specific files (and
 * because right now the paths are hard-wired and no error-
 * checking is in place) compiling it (with whatever gcc
 * options you prefer) will probably simply work.
 *
 * Thanks to KillerFox and #gentoo-hppa for their programming clues. :)
 * 
 * This program was written by JeR in 2005, released on May 9, 2005
 * and is distributed under the GNU General Public License
 * version 2 or later.
 *
 * Mail your suggestions, improvements and complaints to
 * jer at xs4all dot nl
 */

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

#define MAX_LINE_LENGTH 1024

/*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 BB "\033[01;34m"	/* Bright Blue  */

void usage(char *program_name, int colour)
{
	if (program_name == NULL) program_name = "euses";
	/* Catch program name without slash. */
	else program_name = strrchr(program_name, '/') + 1;
	(void) printf("Usage: %s <USE flag to search>\n", program_name);
	(void) printf
	    ("%s searches use.desc and use.local.desc for your USE flag.\n",
	     program_name);
	exit(EXIT_SUCCESS);
}

void err_no(int err_no)
{
	switch (err_no) {
	case 0:
		puts("/etc/make.conf not found\n");
		break;
	case 1:
		puts("use.desc not found\n");
		break;
	case 2:
		puts("use.local.desc not found\n");
		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 *new_portdir)
{
	char etc_line[MAX_LINE_LENGTH * 2];
	FILE *ptr = NULL;
	const char *portdir_key = "PORTDIR=\"";
	const char *def_portdir = "/usr/portage";
	int i = 9;
	int j = 0;

	ptr = fopen("/etc/make.conf", "r");
	if (ptr == NULL) {
		err_no(0);
		exit(EXIT_FAILURE);
	}
/* This is turning out to be incredibly difficult: 
 * Difficult cases to parse are:
 * 
 * PORTDIR="/usr"; PORTDIR="${PORTDIR}/portage"
 * PORT\
 * and
 * DIR="/usr/portage"
 * to name but two. */

	while (feof(ptr) == 0) {
		while (fgets(etc_line, MAX_LINE_LENGTH, ptr) != NULL) {
			if (strstr(etc_line, portdir_key) != 0) {
				while (etc_line[i] != '\0') {
					if (etc_line[i] != '"')
						new_portdir[j++] =
						    etc_line[i++];
					else {
						++i;
						++j;
					}
				}
				new_portdir[j] = '\0';
			}
		}
		continue;
	}
	(void)fclose(ptr);
	ptr = NULL;
	if (strlen(new_portdir) == 0)
		strncpy(new_portdir, def_portdir, strlen(def_portdir));
}

int main(int argc, char **argv)
{
	FILE *ptr = NULL;
	char *match_chr;	/* Pointer to first matching character */
	int ud_match = 0;	/* True when at least one line in  UD matches */
	int uld_match = 0;	/* True when at least one line in ULD matches */
	char ud_path[MAX_LINE_LENGTH * 2];
	char uld_path[MAX_LINE_LENGTH * 2];
	const char *ud_file = "/profiles/use.desc";
	const char *uld_file = "/profiles/use.local.desc";
	int colour = 0;		/* True if tty, otherwise False */
	char use_line[MAX_LINE_LENGTH];
	char path[MAX_LINE_LENGTH];
	char *new_portdir = path;

	memset(ud_path, 0, sizeof(ud_path));
	memset(uld_path, 0, sizeof(uld_path));

	getportdir(new_portdir);	/* Check in /etc/make.conf where Portage is: */

	strcat(ud_path, new_portdir);
	strcat(ud_path, ud_file);
	strcat(uld_path, new_portdir);
	strcat(uld_path, uld_file);

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

	/* First look in use.desc: */

	if (argc < 2)
		usage(argv[0], colour);
	ptr = fopen(ud_path, "r");
	if (ptr == 0) {
		err_no(1);
		exit(EXIT_FAILURE);
	}
	while (feof(ptr) == 0) {
		while (fgets(use_line, MAX_LINE_LENGTH, ptr) != NULL) {
			if (use_line[0] == '#')
				continue;
			match_chr = strstr(use_line, argv[1]);
			if (match_chr != 0) {
				if (colour == 1) {
					if (ud_match == 0) {
						printf
						    (" %s*%s Found '%s%s%s' in %suse.desc%s:\n",
						     BG, FC, BW, argv[1], FC,
						     BB, FC);
						ud_match = 1;
					}
					(void)ud_format(use_line);	/* Format a single line */
				} else {
					printf("      use.desc: %s", use_line);	/* Don't format */
				}
			}
		}
	}
	(void)fclose(ptr);
	ptr = NULL;

	/* Then look in use.local.desc: */

	ptr = fopen(uld_path, "r");
	if (ptr == NULL) {
		err_no(2);
		exit(EXIT_FAILURE);
	}
	while (feof(ptr) == 0) {
		while (fgets(use_line, MAX_LINE_LENGTH, ptr) != NULL) {
			if (use_line[0] == '#')
				continue;
			if (strstr(use_line, argv[1]) != 0) {
				if (colour == 1) {
					if (uld_match == 0) {
						printf
						    (" %s*%s Found %s%s%s in %suse.local.desc%s:\n",
						     BG, FC, BW, argv[1], FC,
						     BB, FC);
						uld_match = 1;
					}
					(void)uld_format(use_line);
				} else {
					printf("use.local.desc: %s", use_line);
				}
			}
		}
	}
	(void)fclose(ptr);
	ptr = NULL;
	if (ud_match != 0 || uld_match != 0) exit(EXIT_SUCCESS);
	else exit(EXIT_FAILURE);
}


syntax highlighted by Code2HTML, v. 0.9.1