Ben Cheng | 25b3c04 | 2013-11-20 14:45:36 -0800 | [diff] [blame] | 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. */ |
| 41 | static 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. */ |
| 47 | static 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. */ |
| 56 | const struct argp color_argp = |
| 57 | { |
| 58 | options, parse_opt, NULL, NULL, NULL, NULL, NULL |
| 59 | }; |
| 60 | |
| 61 | /* Coloring mode. */ |
| 62 | enum color_enum color_mode; |
| 63 | |
| 64 | /* Colors to use for the various components. */ |
| 65 | char *color_address = ""; |
| 66 | char *color_bytes = ""; |
| 67 | char *color_mnemonic = ""; |
| 68 | char *color_operand = NULL; |
| 69 | char *color_operand1 = ""; |
| 70 | char *color_operand2 = ""; |
| 71 | char *color_operand3 = ""; |
| 72 | char *color_label = ""; |
| 73 | char *color_undef = ""; |
| 74 | char *color_undef_tls = ""; |
| 75 | char *color_undef_weak = ""; |
| 76 | char *color_symbol = ""; |
| 77 | char *color_tls = ""; |
| 78 | char *color_weak = ""; |
| 79 | |
| 80 | const char color_off[] = "\e[0m"; |
| 81 | |
| 82 | |
| 83 | /* Handle program arguments. */ |
| 84 | static error_t |
| 85 | parse_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\ |
| 126 | valid 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 | } |