Signed-off-by: Daniel Wallace <[email protected]>
---
 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 <[email protected]>
+ *  Copyright (c) 2002-2006 by Judd Vinet <[email protected]>
+ *
+ *  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


Reply via email to