Home | History | Annotate | Download | only in util
      1 #include <linux/kernel.h>
      2 #include "cache.h"
      3 #include "color.h"
      4 
      5 int perf_use_color_default = -1;
      6 
      7 static int parse_color(const char *name, int len)
      8 {
      9 	static const char * const color_names[] = {
     10 		"normal", "black", "red", "green", "yellow",
     11 		"blue", "magenta", "cyan", "white"
     12 	};
     13 	char *end;
     14 	int i;
     15 
     16 	for (i = 0; i < (int)ARRAY_SIZE(color_names); i++) {
     17 		const char *str = color_names[i];
     18 		if (!strncasecmp(name, str, len) && !str[len])
     19 			return i - 1;
     20 	}
     21 	i = strtol(name, &end, 10);
     22 	if (end - name == len && i >= -1 && i <= 255)
     23 		return i;
     24 	return -2;
     25 }
     26 
     27 static int parse_attr(const char *name, int len)
     28 {
     29 	static const int attr_values[] = { 1, 2, 4, 5, 7 };
     30 	static const char * const attr_names[] = {
     31 		"bold", "dim", "ul", "blink", "reverse"
     32 	};
     33 	unsigned int i;
     34 
     35 	for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
     36 		const char *str = attr_names[i];
     37 		if (!strncasecmp(name, str, len) && !str[len])
     38 			return attr_values[i];
     39 	}
     40 	return -1;
     41 }
     42 
     43 void color_parse(const char *value, const char *var, char *dst)
     44 {
     45 	color_parse_mem(value, strlen(value), var, dst);
     46 }
     47 
     48 void color_parse_mem(const char *value, int value_len, const char *var,
     49 		char *dst)
     50 {
     51 	const char *ptr = value;
     52 	int len = value_len;
     53 	int attr = -1;
     54 	int fg = -2;
     55 	int bg = -2;
     56 
     57 	if (!strncasecmp(value, "reset", len)) {
     58 		strcpy(dst, PERF_COLOR_RESET);
     59 		return;
     60 	}
     61 
     62 	/* [fg [bg]] [attr] */
     63 	while (len > 0) {
     64 		const char *word = ptr;
     65 		int val, wordlen = 0;
     66 
     67 		while (len > 0 && !isspace(word[wordlen])) {
     68 			wordlen++;
     69 			len--;
     70 		}
     71 
     72 		ptr = word + wordlen;
     73 		while (len > 0 && isspace(*ptr)) {
     74 			ptr++;
     75 			len--;
     76 		}
     77 
     78 		val = parse_color(word, wordlen);
     79 		if (val >= -1) {
     80 			if (fg == -2) {
     81 				fg = val;
     82 				continue;
     83 			}
     84 			if (bg == -2) {
     85 				bg = val;
     86 				continue;
     87 			}
     88 			goto bad;
     89 		}
     90 		val = parse_attr(word, wordlen);
     91 		if (val < 0 || attr != -1)
     92 			goto bad;
     93 		attr = val;
     94 	}
     95 
     96 	if (attr >= 0 || fg >= 0 || bg >= 0) {
     97 		int sep = 0;
     98 
     99 		*dst++ = '\033';
    100 		*dst++ = '[';
    101 		if (attr >= 0) {
    102 			*dst++ = '0' + attr;
    103 			sep++;
    104 		}
    105 		if (fg >= 0) {
    106 			if (sep++)
    107 				*dst++ = ';';
    108 			if (fg < 8) {
    109 				*dst++ = '3';
    110 				*dst++ = '0' + fg;
    111 			} else {
    112 				dst += sprintf(dst, "38;5;%d", fg);
    113 			}
    114 		}
    115 		if (bg >= 0) {
    116 			if (sep++)
    117 				*dst++ = ';';
    118 			if (bg < 8) {
    119 				*dst++ = '4';
    120 				*dst++ = '0' + bg;
    121 			} else {
    122 				dst += sprintf(dst, "48;5;%d", bg);
    123 			}
    124 		}
    125 		*dst++ = 'm';
    126 	}
    127 	*dst = 0;
    128 	return;
    129 bad:
    130 	die("bad color value '%.*s' for variable '%s'", value_len, value, var);
    131 }
    132 
    133 int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
    134 {
    135 	if (value) {
    136 		if (!strcasecmp(value, "never"))
    137 			return 0;
    138 		if (!strcasecmp(value, "always"))
    139 			return 1;
    140 		if (!strcasecmp(value, "auto"))
    141 			goto auto_color;
    142 	}
    143 
    144 	/* Missing or explicit false to turn off colorization */
    145 	if (!perf_config_bool(var, value))
    146 		return 0;
    147 
    148 	/* any normal truth value defaults to 'auto' */
    149  auto_color:
    150 	if (stdout_is_tty < 0)
    151 		stdout_is_tty = isatty(1);
    152 	if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
    153 		char *term = getenv("TERM");
    154 		if (term && strcmp(term, "dumb"))
    155 			return 1;
    156 	}
    157 	return 0;
    158 }
    159 
    160 int perf_color_default_config(const char *var, const char *value, void *cb)
    161 {
    162 	if (!strcmp(var, "color.ui")) {
    163 		perf_use_color_default = perf_config_colorbool(var, value, -1);
    164 		return 0;
    165 	}
    166 
    167 	return perf_default_config(var, value, cb);
    168 }
    169 
    170 static int __color_vsnprintf(char *bf, size_t size, const char *color,
    171 			     const char *fmt, va_list args, const char *trail)
    172 {
    173 	int r = 0;
    174 
    175 	/*
    176 	 * Auto-detect:
    177 	 */
    178 	if (perf_use_color_default < 0) {
    179 		if (isatty(1) || pager_in_use())
    180 			perf_use_color_default = 1;
    181 		else
    182 			perf_use_color_default = 0;
    183 	}
    184 
    185 	if (perf_use_color_default && *color)
    186 		r += scnprintf(bf, size, "%s", color);
    187 	r += vscnprintf(bf + r, size - r, fmt, args);
    188 	if (perf_use_color_default && *color)
    189 		r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
    190 	if (trail)
    191 		r += scnprintf(bf + r, size - r, "%s", trail);
    192 	return r;
    193 }
    194 
    195 static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
    196 		va_list args, const char *trail)
    197 {
    198 	int r = 0;
    199 
    200 	/*
    201 	 * Auto-detect:
    202 	 */
    203 	if (perf_use_color_default < 0) {
    204 		if (isatty(fileno(fp)) || pager_in_use())
    205 			perf_use_color_default = 1;
    206 		else
    207 			perf_use_color_default = 0;
    208 	}
    209 
    210 	if (perf_use_color_default && *color)
    211 		r += fprintf(fp, "%s", color);
    212 	r += vfprintf(fp, fmt, args);
    213 	if (perf_use_color_default && *color)
    214 		r += fprintf(fp, "%s", PERF_COLOR_RESET);
    215 	if (trail)
    216 		r += fprintf(fp, "%s", trail);
    217 	return r;
    218 }
    219 
    220 int color_vsnprintf(char *bf, size_t size, const char *color,
    221 		    const char *fmt, va_list args)
    222 {
    223 	return __color_vsnprintf(bf, size, color, fmt, args, NULL);
    224 }
    225 
    226 int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
    227 {
    228 	return __color_vfprintf(fp, color, fmt, args, NULL);
    229 }
    230 
    231 int color_snprintf(char *bf, size_t size, const char *color,
    232 		   const char *fmt, ...)
    233 {
    234 	va_list args;
    235 	int r;
    236 
    237 	va_start(args, fmt);
    238 	r = color_vsnprintf(bf, size, color, fmt, args);
    239 	va_end(args);
    240 	return r;
    241 }
    242 
    243 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
    244 {
    245 	va_list args;
    246 	int r;
    247 
    248 	va_start(args, fmt);
    249 	r = color_vfprintf(fp, color, fmt, args);
    250 	va_end(args);
    251 	return r;
    252 }
    253 
    254 int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
    255 {
    256 	va_list args;
    257 	int r;
    258 	va_start(args, fmt);
    259 	r = __color_vfprintf(fp, color, fmt, args, "\n");
    260 	va_end(args);
    261 	return r;
    262 }
    263 
    264 /*
    265  * This function splits the buffer by newlines and colors the lines individually.
    266  *
    267  * Returns 0 on success.
    268  */
    269 int color_fwrite_lines(FILE *fp, const char *color,
    270 		size_t count, const char *buf)
    271 {
    272 	if (!*color)
    273 		return fwrite(buf, count, 1, fp) != 1;
    274 
    275 	while (count) {
    276 		char *p = memchr(buf, '\n', count);
    277 
    278 		if (p != buf && (fputs(color, fp) < 0 ||
    279 				fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
    280 				fputs(PERF_COLOR_RESET, fp) < 0))
    281 			return -1;
    282 		if (!p)
    283 			return 0;
    284 		if (fputc('\n', fp) < 0)
    285 			return -1;
    286 		count -= p + 1 - buf;
    287 		buf = p + 1;
    288 	}
    289 	return 0;
    290 }
    291 
    292 const char *get_percent_color(double percent)
    293 {
    294 	const char *color = PERF_COLOR_NORMAL;
    295 
    296 	/*
    297 	 * We color high-overhead entries in red, mid-overhead
    298 	 * entries in green - and keep the low overhead places
    299 	 * normal:
    300 	 */
    301 	if (percent >= MIN_RED)
    302 		color = PERF_COLOR_RED;
    303 	else {
    304 		if (percent > MIN_GREEN)
    305 			color = PERF_COLOR_GREEN;
    306 	}
    307 	return color;
    308 }
    309 
    310 int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
    311 {
    312 	int r;
    313 	const char *color;
    314 
    315 	color = get_percent_color(percent);
    316 	r = color_fprintf(fp, color, fmt, percent);
    317 
    318 	return r;
    319 }
    320 
    321 int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
    322 {
    323 	va_list args;
    324 	double percent;
    325 	const char *color;
    326 
    327 	va_start(args, fmt);
    328 	percent = va_arg(args, double);
    329 	va_end(args);
    330 	color = get_percent_color(percent);
    331 	return color_snprintf(bf, size, color, fmt, percent);
    332 }
    333