Home | History | Annotate | Download | only in lib
      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 (at) 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 }
    228