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
parse_opt(int key,char * arg,struct argp_state * state)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 }
228