Add color commands for stuff in util
Signed-off-by: Daniel Wallace <daniel.wallace@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@archlinux.org> + * Copyright (c) 2002-2006 by Judd Vinet <jvinet@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 ", _("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(" "); + 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(' '); + } +} + +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 ", _("None")); + } else { + const alpm_list_t *i; + /* Print the first element */ + indentprint((const char *)list->data, len, maxcols); + printf(" "); + /* 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(" "); + } + } +} + +/* 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(" "); + + 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(" "); + + /* 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 "), 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 "), size, label); + } + if(rsize > 0 && isize == 0) { + size = humanize_size(rsize, 'M', 2, &label); + color_printf(COLOR_WHITE_COLON, _("Total Removed Size: %.2f %s "), 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 "), 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 "), 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, " "); + 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 is missing, resulting in broken output (FS#27909) */ + if(!isatty(fileno(stdin))) { + fprintf(stream, "%s ", 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] = ' '; + + 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, " |