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