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
parse_opt(int key,char * arg,struct argp_state * state)90 parse_opt (int key, char *arg,
91 struct argp_state *state __attribute__ ((unused)))
92 {
93 switch (key)
94 {
95 case OPT_COLOR:
96 if (arg == NULL)
97 color_mode = color_always;
98 else
99 {
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 for (i = 0; i < nvalues; ++i)
119 if (strcmp (arg, values[i].str) == 0)
120 {
121 color_mode = values[i].mode;
122 if (color_mode == color_auto)
123 color_mode
124 = isatty (STDOUT_FILENO) ? color_always : color_never;
125 break;
126 }
127 if (i == nvalues)
128 {
129 error (0, 0, _("\
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 argp_help (&color_argp, stderr, ARGP_HELP_SEE,
137 (char *) program_invocation_short_name);
138 exit (EXIT_FAILURE);
139 }
140 }
141
142 if (color_mode == color_always)
143 {
144 const char *env = getenv ("ELFUTILS_COLORS");
145 if (env != NULL)
146 {
147 do
148 {
149 const char *start = env;
150 while (*env != '=' && *env != '\0')
151 ++env;
152 if (*env == '=' && env != start)
153 {
154 size_t name_len = env - start;
155 const char *val = ++env;
156 env = strchrnul (env, ':');
157 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 for (size_t i = 0; i < nknown; ++i)
188 if (name_len == known[i].len
189 && memcmp (start, known[i].name, name_len) == 0)
190 {
191 if (asprintf (known[i].varp, "\e[%.*sm",
192 (int) (env - val), val) < 0)
193 error (EXIT_FAILURE, errno,
194 _("cannot allocate memory"));
195 break;
196 }
197 }
198 if (*env == ':')
199 ++env;
200 }
201 }
202 while (*env != '\0');
203
204 if (color_operand != NULL)
205 {
206 if (color_operand1[0] == '\0')
207 color_operand1 = color_operand;
208 if (color_operand2[0] == '\0')
209 color_operand2 = color_operand;
210 if (color_operand3[0] == '\0')
211 color_operand3 = color_operand;
212 if (color_operand4[0] == '\0')
213 color_operand4 = color_operand;
214 if (color_operand5[0] == '\0')
215 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 }
239