1/* Handling of color output. 2 Copyright (C) 2011 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 Written by Ulrich Drepper <drepper@redhat.com>, 2011. 5 6 Red Hat elfutils is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by the 8 Free Software Foundation; version 2 of the License. 9 10 Red Hat elfutils is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with Red Hat elfutils; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 18 19 Red Hat elfutils is an included package of the Open Invention Network. 20 An included package of the Open Invention Network is a package for which 21 Open Invention Network licensees cross-license their patents. No patent 22 license is granted, either expressly or impliedly, by designation as an 23 included package. Should you wish to participate in the Open Invention 24 Network licensing program, please visit www.openinventionnetwork.com 25 <http://www.openinventionnetwork.com>. */ 26 27#ifdef HAVE_CONFIG_H 28# include <config.h> 29#endif 30 31#include <argp.h> 32#include <error.h> 33#include <libintl.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37#include "system.h" 38 39 40/* Prototype for option handler. */ 41static error_t parse_opt (int key, char *arg, struct argp_state *state); 42 43/* Option values. */ 44#define OPT_COLOR 0x100100 45 46/* Definitions of arguments for argp functions. */ 47static const struct argp_option options[] = 48{ 49 { "color", OPT_COLOR, "WHEN", OPTION_ARG_OPTIONAL, 50 N_("colorize the output. WHEN defaults to 'always' or can be 'auto' or 'never'"), 0 }, 51 52 { NULL, 0, NULL, 0, NULL, 0 } 53}; 54 55/* Parser data structure. */ 56const struct argp color_argp = 57 { 58 options, parse_opt, NULL, NULL, NULL, NULL, NULL 59 }; 60 61/* Coloring mode. */ 62enum color_enum color_mode; 63 64/* Colors to use for the various components. */ 65char *color_address = ""; 66char *color_bytes = ""; 67char *color_mnemonic = ""; 68char *color_operand = NULL; 69char *color_operand1 = ""; 70char *color_operand2 = ""; 71char *color_operand3 = ""; 72char *color_label = ""; 73char *color_undef = ""; 74char *color_undef_tls = ""; 75char *color_undef_weak = ""; 76char *color_symbol = ""; 77char *color_tls = ""; 78char *color_weak = ""; 79 80const char color_off[] = "\e[0m"; 81 82 83/* Handle program arguments. */ 84static error_t 85parse_opt (int key, char *arg, 86 struct argp_state *state __attribute__ ((unused))) 87{ 88 switch (key) 89 { 90 case OPT_COLOR: 91 if (arg == NULL) 92 color_mode = color_always; 93 else 94 { 95 static const struct 96 { 97 const char str[7]; 98 enum color_enum mode; 99 } values[] = 100 { 101 { "always", color_always }, 102 { "yes", color_always }, 103 { "force", color_always }, 104 { "never", color_never }, 105 { "no", color_never }, 106 { "none", color_never }, 107 { "auto", color_auto }, 108 { "tty", color_auto }, 109 { "if-tty", color_auto } 110 }; 111 const int nvalues = sizeof (values) / sizeof (values[0]); 112 int i; 113 for (i = 0; i < nvalues; ++i) 114 if (strcmp (arg, values[i].str) == 0) 115 { 116 color_mode = values[i].mode; 117 if (color_mode == color_auto) 118 color_mode 119 = isatty (STDOUT_FILENO) ? color_always : color_never; 120 break; 121 } 122 if (i == nvalues) 123 { 124 error (0, 0, dgettext ("elfutils", "\ 125%s: invalid argument '%s' for '--color'\n\ 126valid arguments are:\n\ 127 - 'always', 'yes', 'force'\n\ 128 - 'never', 'no', 'none'\n\ 129 - 'auto', 'tty', 'if-tty'\n"), 130 program_invocation_short_name, arg); 131 argp_help (&color_argp, stderr, ARGP_HELP_SEE, 132 program_invocation_short_name); 133 exit (EXIT_FAILURE); 134 } 135 } 136 137 if (color_mode == color_always) 138 { 139 const char *env = getenv ("ELFUTILS_COLORS"); 140 if (env != NULL) 141 { 142 do 143 { 144 const char *start = env; 145 while (*env != '=' && *env != '\0') 146 ++env; 147 if (*env == '=' && env != start) 148 { 149 size_t name_len = env - start; 150 const char *val = ++env; 151 env = strchrnul (env, ':'); 152 if (val != env) 153 { 154 static const struct 155 { 156 unsigned char len; 157 const char name[sizeof (char *) - 1]; 158 char **varp; 159 } known[] = 160 { 161#define E(name, var) { sizeof (#name) - 1, #name, &color_##var } 162 E (a, address), 163 E (b, bytes), 164 E (m, mnemonic), 165 E (o, operand), 166 E (o1, operand1), 167 E (o1, operand2), 168 E (o1, operand3), 169 E (l, label), 170 E (u, undef), 171 E (ut, undef_tls), 172 E (uw, undef_weak), 173 E (sy, symbol), 174 E (st, tls), 175 E (sw, weak), 176 }; 177 const size_t nknown = (sizeof (known) 178 / sizeof (known[0])); 179 180 for (size_t i = 0; i < nknown; ++i) 181 if (name_len == known[i].len 182 && memcmp (start, known[i].name, name_len) == 0) 183 { 184 if (asprintf (known[i].varp, "\e[%.*sm", 185 (int) (env - val), val) < 0) 186 error (EXIT_FAILURE, errno, 187 gettext ("cannot allocate memory")); 188 break; 189 } 190 } 191 if (*env == ':') 192 ++env; 193 } 194 } 195 while (*env != '\0'); 196 197 if (color_operand != NULL) 198 { 199 if (color_operand1[0] == '\0') 200 color_operand1 = color_operand; 201 if (color_operand2[0] == '\0') 202 color_operand2 = color_operand; 203 if (color_operand3[0] == '\0') 204 color_operand3 = color_operand; 205 } 206 } 207#if 0 208 else 209 { 210 // XXX Just for testing. 211 color_address = xstrdup ("\e[38;5;166;1m"); 212 color_bytes = xstrdup ("\e[38;5;141m"); 213 color_mnemonic = xstrdup ("\e[38;5;202;1m"); 214 color_operand1 = xstrdup ("\e[38;5;220m"); 215 color_operand2 = xstrdup ("\e[38;5;48m"); 216 color_operand3 = xstrdup ("\e[38;5;112m"); 217 color_label = xstrdup ("\e[38;5;21m"); 218 } 219#endif 220 } 221 break; 222 223 default: 224 return ARGP_ERR_UNKNOWN; 225 } 226 return 0; 227} 228