Imported Upstream version 0.153
[platform/upstream/elfutils.git] / lib / color.c
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 }