[pacman-dev] [PATCH 02/11] Add color commands for stuff in util

Daniel Wallace daniel.wallace at gatech.edu
Sun Aug 5 05:46:38 EDT 2012


Signed-off-by: Daniel Wallace <daniel.wallace at gatech.edu>
---
 src/pacman/color.c | 728 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/pacman/color.h |  70 ++++++
 src/pacman/util.c  |  35 ++-
 src/pacman/util.h  |   6 +
 4 files changed, 830 insertions(+), 9 deletions(-)
 create mode 100644 src/pacman/color.c
 create mode 100644 src/pacman/color.h

diff --git a/src/pacman/color.c b/src/pacman/color.c
new file mode 100644
index 0000000..d1b2d5e
--- /dev/null
+++ b/src/pacman/color.c
@@ -0,0 +1,728 @@
+/*
+ *  util.c
+ *
+ *  Copyright (c) 2006-2012 Pacman Development Team <pacman-dev at archlinux.org>
+ *  Copyright (c) 2002-2006 by Judd Vinet <jvinet at zeroflux.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h> /* intmax_t */
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <limits.h>
+#include <wchar.h>
+#ifdef HAVE_TERMIOS_H
+#include <termios.h> /* tcflush */
+#endif
+
+#include <alpm.h>
+#include <alpm_list.h>
+
+/* pacman */
+#include "util.h"
+#include "conf.h"
+#include "callback.h"
+#include "color.h"
+
+#define COLOR_LEN 8
+
+typedef struct __colortab_t {
+	char red[COLOR_LEN + 1];
+	char green[COLOR_LEN + 1];
+	char yellow[COLOR_LEN + 1];
+	char blue[COLOR_LEN + 1];
+	char magenta[COLOR_LEN + 1];
+	char cyan[COLOR_LEN + 1];
+	char white[COLOR_LEN + 1];
+	char none[COLOR_LEN + 1];
+} colortab_t;
+
+static colortab_t colortab;
+
+
+void color_list_display(const colordata_t *colors_title, const char *title, const alpm_list_t *list,
+		unsigned short maxcols)
+{
+	const alpm_list_t *i;
+	size_t len = 0;
+
+	if(title) {
+		len = string_length(title) + 1;
+		color_printf(colors_title, "%s ", title);
+	}
+
+	if(!list) {
+		printf("%s\n", _("None"));
+	} else {
+		size_t cols = len;
+		const char *str = list->data;
+		fputs(str, stdout);
+		cols += string_length(str);
+		for(i = alpm_list_next(list); i; i = alpm_list_next(i)) {
+			str = i->data;
+			size_t s = string_length(str);
+			/* wrap only if we have enough usable column space */
+			if(maxcols > len && cols + s + 2 >= maxcols) {
+				size_t j;
+				cols = len;
+				printf("\n");
+				for(j = 1; j <= len; j++) {
+					printf(" ");
+				}
+			} else if(cols != len) {
+				/* 2 spaces are added if this is not the first element on a line. */
+				printf("  ");
+				cols += 2;
+			}
+			fputs(str, stdout);
+			cols += s;
+		}
+		putchar('\n');
+	}
+}
+
+void color_list_display_linebreak(const colordata_t *colors_title, const char *title, const alpm_list_t *list,
+		unsigned short maxcols)
+{
+	unsigned short len = 0;
+
+	if(title) {
+		len = (unsigned short)string_length(title) + 1;
+		color_printf(colors_title, "%s ", title);
+	}
+
+	if(!list) {
+		printf("%s\n", _("None"));
+	} else {
+		const alpm_list_t *i;
+		/* Print the first element */
+		indentprint((const char *)list->data, len, maxcols);
+		printf("\n");
+		/* Print the rest */
+		for(i = alpm_list_next(list); i; i = alpm_list_next(i)) {
+			size_t j;
+			for(j = 1; j <= len; j++) {
+				printf(" ");
+			}
+			indentprint((const char *)i->data, len, maxcols);
+			printf("\n");
+		}
+	}
+}
+
+/* prepare a list of pkgs to display */
+void _color_display_targets(alpm_list_t *targets, int verbose)
+{
+	char *str;
+	const char *label;
+	double size;
+	off_t isize = 0, rsize = 0, dlsize = 0;
+	unsigned short cols;
+	alpm_list_t *i, *rows = NULL, *names = NULL;
+
+	if(!targets) {
+		return;
+	}
+
+	/* gather package info */
+	for(i = targets; i; i = alpm_list_next(i)) {
+		pm_target_t *target = i->data;
+
+		if(target->install) {
+			dlsize += alpm_pkg_download_size(target->install);
+			isize += alpm_pkg_get_isize(target->install);
+		}
+		if(target->remove) {
+			/* add up size of all removed packages */
+			rsize += alpm_pkg_get_isize(target->remove);
+		}
+	}
+
+	/* form data for both verbose and non-verbose display */
+	for(i = targets; i; i = alpm_list_next(i)) {
+		pm_target_t *target = i->data;
+
+		rows = alpm_list_add(rows, create_verbose_row(target));
+		if(target->install) {
+			pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(target->install),
+					alpm_pkg_get_version(target->install));
+		} else if(isize == 0) {
+			pm_asprintf(&str, "%s-%s", alpm_pkg_get_name(target->remove),
+					alpm_pkg_get_version(target->remove));
+		} else {
+			pm_asprintf(&str, "%s-%s [removal]", alpm_pkg_get_name(target->remove),
+					alpm_pkg_get_version(target->remove));
+		}
+		names = alpm_list_add(names, str);
+	}
+
+	/* print to screen */
+	pm_asprintf(&str, _("Targets (%d):"), alpm_list_count(targets));
+	printf("\n");
+
+	cols = getcols(fileno(stdout));
+	if(verbose) {
+		alpm_list_t *header = create_verbose_header();
+		if(table_display(str, header, rows, cols) != 0) {
+			/* fallback to list display if table wouldn't fit */
+			color_list_display(COLOR_YELLOW_ALL, str, names, cols);
+		}
+		alpm_list_free(header);
+	} else {
+		color_list_display(COLOR_YELLOW_ALL, str, names, cols);
+	}
+	printf("\n");
+
+	/* rows is a list of lists of strings, free inner lists here */
+	for(i = rows; i; i = alpm_list_next(i)) {
+		alpm_list_t *lp = i->data;
+		FREELIST(lp);
+	}
+	alpm_list_free(rows);
+	FREELIST(names);
+	free(str);
+
+	if(dlsize > 0 || config->op_s_downloadonly) {
+		size = humanize_size(dlsize, 'M', 2, &label);
+		color_printf(COLOR_WHITE_COLON, _("Total Download Size:    %.2f %s\n"), size, label);
+	}
+	if(!config->op_s_downloadonly) {
+		if(isize > 0) {
+			size = humanize_size(isize, 'M', 2, &label);
+			color_printf(COLOR_WHITE_COLON, _("Total Installed Size:   %.2f %s\n"), size, label);
+		}
+		if(rsize > 0 && isize == 0) {
+			size = humanize_size(rsize, 'M', 2, &label);
+			color_printf(COLOR_WHITE_COLON, _("Total Removed Size:     %.2f %s\n"), size, label);
+		}
+		/* only show this net value if different from raw installed size */
+		if(isize > 0 && rsize > 0) {
+			size = humanize_size(isize - rsize, 'M', 2, &label);
+			color_printf(COLOR_WHITE_COLON, _("Net Upgrade Size:       %.2f %s\n"), size, label);
+		}
+	}
+}
+void color_display_repo_list(const char *dbname, alpm_list_t *list,
+		unsigned short cols)
+{
+	const char *prefix= "  ";
+
+	color_printf(COLOR_BLUE_ALL, ":: ");
+	color_printf(COLOR_WHITE_ALL, _("Repository %s\n"), dbname);
+	color_list_display(NULL, prefix, list, cols);
+}
+
+/* presents a prompt and gets a Y/N answer */
+static int color_question(const colordata_t *colors, short preset, char *fmt, va_list args)
+{
+	char response[32];
+	FILE *stream;
+
+	if(config->noconfirm) {
+		stream = stdout;
+	} else {
+		/* Use stderr so questions are always displayed when redirecting output */
+		stream = stderr;
+	}
+
+	/* ensure all text makes it to the screen before we prompt the user */
+	fflush(stdout);
+	fflush(stderr);
+
+	color_vfprintf(stream, colors, fmt, args);
+
+	if(preset) {
+		fprintf(stream, " %s ", _("[Y/n]"));
+	} else {
+		fprintf(stream, " %s ", _("[y/N]"));
+	}
+
+	if(config->noconfirm) {
+		fprintf(stream, "\n");
+		return preset;
+	}
+
+	fflush(stream);
+	flush_term_input(fileno(stdin));
+
+	if(fgets(response, sizeof(response), stdin)) {
+		strtrim(response);
+		if(strlen(response) == 0) {
+			return preset;
+		}
+
+		/* if stdin is piped, response does not get printed out, and as a result
+		 * a \n is missing, resulting in broken output (FS#27909) */
+		if(!isatty(fileno(stdin))) {
+			fprintf(stream, "%s\n", response);
+		}
+
+		if(strcasecmp(response, _("Y")) == 0 || strcasecmp(response, _("YES")) == 0) {
+			return 1;
+		} else if(strcasecmp(response, _("N")) == 0 || strcasecmp(response, _("NO")) == 0) {
+			return 0;
+		}
+	}
+	return 0;
+}
+
+int color_yesno(const colordata_t *colors, char *fmt, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, fmt);
+	ret = color_question(colors, 1, fmt, args);
+	va_end(args);
+
+	return ret;
+}
+
+int color_noyes(const colordata_t *colors, char *fmt, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, fmt);
+	ret = color_question(colors, 0, fmt, args);
+	va_end(args);
+
+	return ret;
+}
+
+int color_pm_vasprintf(char **string, alpm_loglevel_t level, const char *format, va_list args)
+{
+	int ret = 0;
+	char *msg = NULL;
+
+	/* if current logmask does not overlap with level, do not print msg */
+	if(!(config->logmask & level)) {
+		return ret;
+	}
+
+	/* print the message using va_arg list */
+	ret = vasprintf(&msg, format, args);
+
+	/* print a prefix to the message */
+	if(isatty(fileno(stdout))) {
+		switch(level) {
+			case ALPM_LOG_ERROR:
+				pm_asprintf(string, "%s%s%s%s", colortab.red, _("error: "), colortab.none, msg);
+				break;
+			case ALPM_LOG_WARNING:
+				pm_asprintf(string, "%s%s%s%s", colortab.yellow, _("warning: "), colortab.none, msg);
+				break;
+			case ALPM_LOG_DEBUG:
+				pm_asprintf(string, "debug: %s", msg);
+				break;
+			case ALPM_LOG_FUNCTION:
+				pm_asprintf(string, "function: %s", msg);
+				break;
+			default:
+				pm_asprintf(string, "%s", msg);
+				break;
+		}
+	} else {
+		switch(level) {
+			case ALPM_LOG_ERROR:
+				pm_asprintf(string, _("error: %s"), msg);
+				break;
+			case ALPM_LOG_WARNING:
+				pm_asprintf(string, _("warning: %s"), msg);
+				break;
+			case ALPM_LOG_DEBUG:
+				pm_asprintf(string, "debug: %s", msg);
+				break;
+			case ALPM_LOG_FUNCTION:
+				pm_asprintf(string, "function: %s", msg);
+				break;
+			default:
+				pm_asprintf(string, "%s", msg);
+				break;
+		}
+	}
+	free(msg);
+
+	return ret;
+}
+
+int color_pm_vfprintf(FILE *stream, alpm_loglevel_t level, const char *format, va_list args)
+{
+	int ret = 0;
+
+	/* if current logmask does not overlap with level, do not print msg */
+	if(!(config->logmask & level)) {
+		return ret;
+	}
+
+#if defined(PACMAN_DEBUG)
+	/* If debug is on, we'll timestamp the output */
+	if(config->logmask & ALPM_LOG_DEBUG) {
+		time_t t;
+		struct tm *tmp;
+		char timestr[10] = {0};
+
+		t = time(NULL);
+		tmp = localtime(&t);
+		strftime(timestr, 9, "%H:%M:%S", tmp);
+		timestr[8] = '\0';
+
+		fprintf(stream, "[%s] ", timestr);
+	}
+#endif
+
+	/* print a prefix to the message */
+	switch(level) {
+		case ALPM_LOG_ERROR:
+			color_fprintf(stream, COLOR_RED_ALL, _("error: "));
+			break;
+		case ALPM_LOG_WARNING:
+			color_fprintf(stream, COLOR_YELLOW_ALL, _("warning: "));
+			break;
+		case ALPM_LOG_DEBUG:
+			fprintf(stream, "debug: ");
+			break;
+		case ALPM_LOG_FUNCTION:
+			fprintf(stream, "function: ");
+			break;
+		default:
+			break;
+	}
+
+	/* print the message using va_arg list */
+	ret = vfprintf(stream, format, args);
+	return ret;
+}
+
+/* pacman-color */
+
+int _set_color_sequence(const char* name, char* dest)
+{
+	int ret = 0;
+
+	if(strcmp(name, "black") == 0) {
+		strncpy(dest, "\033[0;30m", COLOR_LEN);
+	} else if(strcmp(name, "red") == 0) {
+		strncpy(dest, "\033[0;31m", COLOR_LEN);
+	} else if(strcmp(name, "green") == 0) {
+		strncpy(dest, "\033[0;32m", COLOR_LEN);
+	} else if(strcmp(name, "yellow") == 0) {
+		strncpy(dest, "\033[0;33m", COLOR_LEN);
+	} else if(strcmp(name, "blue") == 0) {
+		strncpy(dest, "\033[0;34m", COLOR_LEN);
+	} else if(strcmp(name, "magenta") == 0) {
+		strncpy(dest, "\033[0;35m", COLOR_LEN);
+	} else if(strcmp(name, "cyan") == 0) {
+		strncpy(dest, "\033[0;36m", COLOR_LEN);
+	} else if(strcmp(name, "white") == 0) {
+		strncpy(dest, "\033[0;37m", COLOR_LEN);
+	} else if(strcmp(name, "gray") == 0) {
+		strncpy(dest, "\033[1;30m", COLOR_LEN);
+	} else if(strcmp(name, "intensive red") == 0) {
+		strncpy(dest, "\033[1;31m", COLOR_LEN);
+	} else if(strcmp(name, "intensive green") == 0) {
+		strncpy(dest, "\033[1;32m", COLOR_LEN);
+	} else if(strcmp(name, "intensive yellow") == 0) {
+		strncpy(dest, "\033[1;33m", COLOR_LEN);
+	} else if(strcmp(name, "intensive blue") == 0) {
+		strncpy(dest, "\033[1;34m", COLOR_LEN);
+	} else if(strcmp(name, "intensive magenta") == 0) {
+		strncpy(dest, "\033[1;35m", COLOR_LEN);
+	} else if(strcmp(name, "intensive cyan") == 0) {
+		strncpy(dest, "\033[1;36m", COLOR_LEN);
+	} else if(strcmp(name, "intensive white") == 0) {
+		strncpy(dest, "\033[1;37m", COLOR_LEN);
+	} else if(strcmp(name, "intensive foreground") == 0) {
+		strncpy(dest, "\033[m\033[1m", COLOR_LEN);
+	} else if(strcmp(name, "none") == 0) {
+		strncpy(dest, "\033[m", COLOR_LEN);
+	} else {
+		ret = 1;
+	}
+	dest[COLOR_LEN] = '\0';
+	return(ret);
+}
+
+void _insert_color(FILE* stream, color_t color)
+{
+	switch(color) {
+		case COLOR_RED:
+			fprintf(stream, colortab.red);
+			break;
+		case COLOR_GREEN:
+			fprintf(stream, colortab.green);
+			break;
+		case COLOR_YELLOW:
+			fprintf(stream, colortab.yellow);
+			break;
+		case COLOR_BLUE:
+			fprintf(stream, colortab.blue);
+			break;
+		case COLOR_MAGENTA:
+			fprintf(stream, colortab.magenta);
+			break;
+		case COLOR_CYAN:
+			fprintf(stream, colortab.cyan);
+			break;
+		case COLOR_WHITE:
+			fprintf(stream, colortab.white);
+			break;
+		case COLOR_NONE:
+			fprintf(stream, colortab.none);
+			break;
+		default:;
+	}
+}
+
+int _parsecolorconfig(colortab_t* colortab, char* file)
+{
+	_set_color_sequence("intensive red", colortab->red);
+	_set_color_sequence("intensive green", colortab->green);
+	_set_color_sequence("intensive yellow", colortab->yellow);
+	_set_color_sequence("intensive blue", colortab->blue);
+	_set_color_sequence("intensive magenta", colortab->magenta);
+	_set_color_sequence("intensive cyan", colortab->cyan);
+	_set_color_sequence("intensive foreground", colortab->white);
+	_set_color_sequence("none", colortab->none);
+
+	FILE* fp = NULL;
+	int linenum = 0;
+	char line[PATH_MAX+1];
+	char* ptr;
+
+	fp = fopen(file, "r");
+	if(fp == NULL) {
+		pm_printf(ALPM_LOG_ERROR, _("config file %s could not be read.\n"), file);
+		return 1;
+	}
+	while(fgets(line, PATH_MAX, fp)) {
+		linenum++;
+		strtrim(line);
+
+		if(strlen(line) == 0 || line[0] == '#') {
+			continue;
+		}
+		if((ptr = strchr(line, '#'))) {
+			*ptr = '\0';
+		}
+
+		char* key = line;
+		ptr = line;
+		strsep(&ptr, "=");
+		strtrim(key);
+		strtrim(ptr);
+
+		if(key == NULL) {
+			pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: syntax error in config file- missing key.\n"),
+					file, linenum);
+			return 1;
+		}
+		if(strcmp(key, "Red") == 0) {
+			if(_set_color_sequence(ptr, colortab->red)) {
+				pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: color '%s' not recognized.\n"),
+							file, linenum, ptr);
+			}
+		} else if(strcmp(key, "Green") == 0) {
+			if(_set_color_sequence(ptr, colortab->green)) {
+				pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: color '%s' not recognized.\n"),
+							file, linenum, ptr);
+			}
+		} else if(strcmp(key, "Yellow") == 0) {
+			if(_set_color_sequence(ptr, colortab->yellow)) {
+				pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: color '%s' not recognized.\n"),
+							file, linenum, ptr);
+			}
+		} else if(strcmp(key, "Blue") == 0) {
+			if(_set_color_sequence(ptr, colortab->blue)) {
+				pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: color '%s' not recognized.\n"),
+							file, linenum, ptr);
+			}
+		} else if(strcmp(key, "Magenta") == 0) {
+			if(_set_color_sequence(ptr, colortab->magenta)) {
+				pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: color '%s' not recognized.\n"),
+							file, linenum, ptr);
+			}
+		} else if(strcmp(key, "Cyan") == 0) {
+			if(_set_color_sequence(ptr, colortab->cyan)) {
+				pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: color '%s' not recognized.\n"),
+							file, linenum, ptr);
+			}
+		} else if(strcmp(key, "White") == 0) {
+			if(_set_color_sequence(ptr, colortab->white)) {
+				pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: color '%s' not recognized.\n"),
+							file, linenum, ptr);
+			}
+		} else {
+			pm_printf(ALPM_LOG_ERROR, _("config file %s, line %d: directive '%s' not recognized.\n"),
+					file, linenum, key);
+			return(1);
+		}
+	}
+	return(0);
+}
+
+int parsecolorconfig()
+{
+	return(_parsecolorconfig(&colortab, config->colorfile));
+}
+
+int color_vfprintf(FILE* stream, const colordata_t* colors, const char* format, va_list args)
+{
+	int ret = 0;
+
+	if(isatty(fileno(stream)) && colors) {
+		char* msg = NULL;
+		ret = vasprintf(&msg, format, args);
+		if(msg == NULL) {
+			return(ret);
+		}
+
+		const colordata_t* colorpos = colors;
+		color_t colorlast = COLOR_NONE;
+		int len = strlen(msg) + 1;
+		wchar_t* wcstr = calloc(len, sizeof(wchar_t));
+		len = mbstowcs(wcstr, msg, len);
+		free(msg);
+		const wchar_t *strpos = wcstr;
+
+		while(*strpos) {
+			if(colorpos->color != COLOR_END &&
+				((colorpos->separator == SEP_ANY) ||
+				 (colorpos->separator == SEP_LINE && *strpos == L'\n') ||
+				 (colorpos->separator == SEP_COLON && (*strpos == L':' || *strpos == L':')))) {
+				_insert_color(stream, colorpos->color);
+				colorlast = colorpos->color;
+				colorpos++;
+			}
+			fprintf(stream, "%lc", (wint_t)*strpos);
+			strpos++;
+		}
+		free(wcstr);
+
+		if(colorlast != COLOR_NONE) {
+			_insert_color(stream, COLOR_NONE);
+		}
+	} else {
+		ret = vfprintf(stream, format, args);
+	}
+	return(ret);
+}
+
+int color_fprintf(FILE* stream, const colordata_t* colors, const char* format, ...)
+{
+	int ret;
+	va_list args;
+	va_start(args, format);
+	ret = color_vfprintf(stream, colors, format, args);
+	va_end(args);
+	return(ret);
+}
+
+int color_printf(const colordata_t* colors, const char* format, ...)
+{
+	int ret;
+	va_list args;
+	va_start(args, format);
+	ret = color_vfprintf(stdout, colors, format, args);
+	va_end(args);
+	return(ret);
+}
+
+void color_string_display(const colordata_t* colors_title, const char* title, const colordata_t* colors_string, const char* string)
+{
+	if(title) {
+		color_printf(colors_title, "%s ", title);
+	}
+	if(string == NULL || string[0] == '\0') {
+		printf(_("None"));
+	} else {
+		color_printf(colors_string, "%s", string);
+	}
+	printf("\n");
+}
+
+const colordata_t COLOR_WHITE_ALL[] = {
+	{ SEP_ANY, COLOR_WHITE },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_GREEN_ALL[] = {
+	{ SEP_ANY, COLOR_GREEN },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_RED_ALL[] = {
+	{ SEP_ANY, COLOR_RED },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_BLUE_ALL[] = {
+	{ SEP_ANY, COLOR_BLUE },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_YELLOW_ALL[] = {
+	{ SEP_ANY, COLOR_YELLOW },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_MAGENTA_ALL[] = {
+	{ SEP_ANY, COLOR_MAGENTA },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_CYAN_ALL[] = {
+	{ SEP_ANY, COLOR_CYAN },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_DOUBLECOLON[] = {
+	{ SEP_ANY, COLOR_BLUE },
+	{ SEP_ANY, COLOR_SAME },
+	{ SEP_ANY, COLOR_WHITE },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_DOUBLECOLON2[] = {
+	{ SEP_ANY, COLOR_BLUE },
+	{ SEP_ANY, COLOR_SAME },
+	{ SEP_ANY, COLOR_WHITE },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_BLUE },
+	{ SEP_ANY, COLOR_SAME },
+	{ SEP_ANY, COLOR_WHITE },
+	{ SEP_LINE, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+const colordata_t COLOR_WHITE_COLON[] = {
+	{ SEP_ANY, COLOR_WHITE },
+	{ SEP_COLON, COLOR_SAME },
+	{ SEP_ANY, COLOR_NONE },
+	{ SEP_ANY, COLOR_END } };
+
+/* vim: set ts=2 sw=2 noet: */
diff --git a/src/pacman/color.h b/src/pacman/color.h
new file mode 100644
index 0000000..c833e2e
--- /dev/null
+++ b/src/pacman/color.h
@@ -0,0 +1,70 @@
+#ifndef _PM_COLOR_H
+#define _PM_COLOR_H
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <alpm_list.h>
+
+/* pacman-color */
+typedef enum _separator_t {
+	SEP_ANY = 0,
+	SEP_LINE,
+	SEP_COLON,
+} separator_t;
+
+typedef enum _color_t {
+	COLOR_END = 0,
+	COLOR_SAME,
+	COLOR_RED,
+	COLOR_GREEN,
+	COLOR_YELLOW,
+	COLOR_BLUE,
+	COLOR_MAGENTA,
+	COLOR_CYAN,
+	COLOR_WHITE,
+	COLOR_NONE,
+} color_t;
+
+typedef struct _colordata_t {
+	separator_t separator;
+	color_t color;
+} colordata_t;
+
+extern const colordata_t COLOR_WHITE_ALL[];
+extern const colordata_t COLOR_GREEN_ALL[];
+extern const colordata_t COLOR_RED_ALL[];
+extern const colordata_t COLOR_BLUE_ALL[];
+extern const colordata_t COLOR_YELLOW_ALL[];
+extern const colordata_t COLOR_MAGENTA_ALL[];
+extern const colordata_t COLOR_CYAN_ALL[];
+extern const colordata_t COLOR_DOUBLECOLON[];
+extern const colordata_t COLOR_DOUBLECOLON2[];
+extern const colordata_t COLOR_WHITE_COLON[];
+
+/* util.c */
+
+void color_list_display(const colordata_t *colors_title, const char *title, const alpm_list_t *list,
+		unsigned short maxcols);
+void color_list_display_linebreak(const colordata_t *colors_title, const char *title, const alpm_list_t *list,
+		unsigned short maxcols);
+void _color_display_targets(alpm_list_t *targets, int verbose);
+void color_display_repo_list(const char *dbname, alpm_list_t *list,
+		unsigned short col);
+int color_yesno(const colordata_t *colors, char *fmt, ...);
+int color_noyes(const colordata_t *colors, char *fmt, ...);
+int color_pm_vasprintf(char **string, alpm_loglevel_t level, const char *format, va_list args);
+int color_pm_vfprintf(FILE *stream, alpm_loglevel_t level, const char *format, va_list args);
+int _set_color_sequence(const char* name, char* dest);
+void _insert_color(FILE* stream, color_t color);
+int parsecolorconfig();
+int color_fprintf(FILE* stream, const colordata_t* colors, const char* format, ...) __attribute__((format(printf,3,4)));
+int color_printf(const colordata_t* colors, const char* format, ...) __attribute__((format(printf,2,3)));
+
+int color_vfprintf(FILE* stream, const colordata_t* colors, const char* format, va_list args) __attribute__((format(printf,3,0)));
+
+void color_string_display(const colordata_t* colors_title, const char* title, const colordata_t* colors_string, const char* string);
+
+#endif
+/* vim: set ts=2 sw=2 noet: */
diff --git a/src/pacman/util.c b/src/pacman/util.c
index 7f7f6a7..f750542 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -45,6 +45,7 @@
 #include "util.h"
 #include "conf.h"
 #include "callback.h"
+#include "color.h"
 
 
 int trans_init(alpm_transflag_t flags, int check_valid)
@@ -130,7 +131,7 @@ int check_syncdbs(size_t need_repos, int check_valid)
 }
 
 /* discard unhandled input on the terminal's input buffer */
-static int flush_term_input(int fd) {
+int flush_term_input(int fd) {
 #ifdef HAVE_TCFLUSH
 	if(isatty(fd)) {
 		return tcflush(fd, TCIFLUSH);
@@ -442,7 +443,7 @@ alpm_list_t *strsplit(const char *str, const char splitchar)
 	return list;
 }
 
-static size_t string_length(const char *s)
+size_t string_length(const char *s)
 {
 	int len;
 	wchar_t *wcstr;
@@ -605,7 +606,7 @@ static size_t table_calc_widths(const alpm_list_t *header,
  * @param cols the number of columns available in the terminal
  * @return -1 if not enough terminal cols available, else 0
  */
-static int table_display(const char *title, const alpm_list_t *header,
+int table_display(const char *title, const alpm_list_t *header,
 		const alpm_list_t *rows, unsigned short cols)
 {
 	const unsigned short padding = 2;
@@ -794,7 +795,7 @@ void signature_display(const char *title, alpm_siglist_t *siglist,
 }
 
 /* creates a header row for use with table_display */
-static alpm_list_t *create_verbose_header(void)
+alpm_list_t *create_verbose_header(void)
 {
 	alpm_list_t *res = NULL;
 	char *str;
@@ -814,7 +815,7 @@ static alpm_list_t *create_verbose_header(void)
 }
 
 /* returns package info as list of strings */
-static alpm_list_t *create_verbose_row(pm_target_t *target)
+alpm_list_t *create_verbose_row(pm_target_t *target)
 {
 	char *str;
 	off_t size = 0;
@@ -1007,7 +1008,11 @@ void display_targets(void)
 	}
 
 	targets = alpm_list_msort(targets, alpm_list_count(targets), target_cmp);
-	_display_targets(targets, config->verbosepkglists);
+	if (config->color) {
+		_color_display_targets(targets, config->verbosepkglists);
+	} else {
+		_display_targets(targets, config->verbosepkglists);
+	}
 	FREELIST(targets);
 }
 
@@ -1263,7 +1268,11 @@ void select_display(const alpm_list_t *pkglist)
 		if(!dbname)
 			dbname = alpm_db_get_name(db);
 		if(strcmp(alpm_db_get_name(db), dbname) != 0) {
-			display_repo_list(dbname, list, cols);
+			if (config->color) {
+				color_display_repo_list(dbname, list, cols);
+			} else {
+				display_repo_list(dbname, list, cols);
+			}
 			FREELIST(list);
 			dbname = alpm_db_get_name(db);
 		}
@@ -1272,7 +1281,11 @@ void select_display(const alpm_list_t *pkglist)
 		list = alpm_list_add(list, string);
 		nth++;
 	}
-	display_repo_list(dbname, list, cols);
+	if (config->color) {
+		color_display_repo_list(dbname, list, cols);
+	} else {
+		display_repo_list(dbname, list, cols);
+	}
 	FREELIST(list);
 }
 
@@ -1551,7 +1564,11 @@ int pm_printf(alpm_loglevel_t level, const char *format, ...)
 
 	/* print the message using va_arg list */
 	va_start(args, format);
-	ret = pm_vfprintf(stderr, level, format, args);
+	if (config->color) {
+		ret = color_pm_vfprintf(stderr, level, format, args);
+	} else {
+		ret = pm_vfprintf(stderr, level, format, args);
+	}
 	va_end(args);
 
 	return ret;
diff --git a/src/pacman/util.h b/src/pacman/util.h
index 0dfdc85..d15164f 100644
--- a/src/pacman/util.h
+++ b/src/pacman/util.h
@@ -47,6 +47,7 @@ int trans_init(alpm_transflag_t flags, int check_valid);
 int trans_release(void);
 int needs_root(void);
 int check_syncdbs(size_t need_repos, int check_valid);
+int flush_term_input(int fd);
 unsigned short getcols(int fd);
 int rmrf(const char *path);
 const char *mbasename(const char *path);
@@ -55,15 +56,20 @@ void indentprint(const char *str, unsigned short indent, unsigned short cols);
 size_t strtrim(char *str);
 char *strreplace(const char *str, const char *needle, const char *replace);
 alpm_list_t *strsplit(const char *str, const char splitchar);
+size_t string_length(const char *s);
 void string_display(const char *title, const char *string, unsigned short cols);
 double humanize_size(off_t bytes, const char target_unit, int precision,
 		const char **label);
+int table_display(const char *title, const alpm_list_t *header,
+		const alpm_list_t *rows, unsigned short cols);
 void list_display(const char *title, const alpm_list_t *list,
 		unsigned short maxcols);
 void list_display_linebreak(const char *title, const alpm_list_t *list,
 		unsigned short maxcols);
 void signature_display(const char *title, alpm_siglist_t *siglist,
 		unsigned short maxcols);
+alpm_list_t *create_verbose_header(void);
+alpm_list_t *create_verbose_row(pm_target_t *target);
 void display_targets(void);
 int str_cmp(const void *s1, const void *s2);
 void display_new_optdepends(alpm_pkg_t *oldpkg, alpm_pkg_t *newpkg);
-- 
1.7.11.4



More information about the pacman-dev mailing list