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 *known[i].varp =
192 xasprintf ("\e[%.*sm", (int) (env - val), val);
193 break;
194 }
195 }
196 if (*env == ':')
197 ++env;
198 }
199 }
200 while (*env != '\0');
201
202 if (color_operand != NULL)
203 {
204 if (color_operand1[0] == '\0')
205 color_operand1 = color_operand;
206 if (color_operand2[0] == '\0')
207 color_operand2 = color_operand;
208 if (color_operand3[0] == '\0')
209 color_operand3 = color_operand;
210 if (color_operand4[0] == '\0')
211 color_operand4 = color_operand;
212 if (color_operand5[0] == '\0')
213 color_operand5 = color_operand;
214 }
215 }
216 #if 0
217 else
218 {
219 // XXX Just for testing.
220 color_address = xstrdup ("\e[38;5;166;1m");
221 color_bytes = xstrdup ("\e[38;5;141m");
222 color_mnemonic = xstrdup ("\e[38;5;202;1m");
223 color_operand1 = xstrdup ("\e[38;5;220m");
224 color_operand2 = xstrdup ("\e[38;5;48m");
225 color_operand = xstrdup ("\e[38;5;112m");
226 color_label = xstrdup ("\e[38;5;21m");
227 }
228 #endif
229 }
230 break;
231
232 default:
233 return ARGP_ERR_UNKNOWN;
234 }
235 return 0;
236 }
237