xref: /linux/tools/perf/util/color.c (revision f3539c12d8196ce0a1993364d30b3a18908470d1)
1 #include <linux/kernel.h>
2 #include "cache.h"
3 #include "config.h"
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include "color.h"
7 #include <math.h>
8 #include <unistd.h>
9 
10 int perf_use_color_default = -1;
11 
12 int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
13 {
14 	if (value) {
15 		if (!strcasecmp(value, "never"))
16 			return 0;
17 		if (!strcasecmp(value, "always"))
18 			return 1;
19 		if (!strcasecmp(value, "auto"))
20 			goto auto_color;
21 	}
22 
23 	/* Missing or explicit false to turn off colorization */
24 	if (!perf_config_bool(var, value))
25 		return 0;
26 
27 	/* any normal truth value defaults to 'auto' */
28  auto_color:
29 	if (stdout_is_tty < 0)
30 		stdout_is_tty = isatty(1);
31 	if (stdout_is_tty || pager_in_use()) {
32 		char *term = getenv("TERM");
33 		if (term && strcmp(term, "dumb"))
34 			return 1;
35 	}
36 	return 0;
37 }
38 
39 int perf_color_default_config(const char *var, const char *value,
40 			      void *cb __maybe_unused)
41 {
42 	if (!strcmp(var, "color.ui")) {
43 		perf_use_color_default = perf_config_colorbool(var, value, -1);
44 		return 0;
45 	}
46 
47 	return 0;
48 }
49 
50 static int __color_vsnprintf(char *bf, size_t size, const char *color,
51 			     const char *fmt, va_list args, const char *trail)
52 {
53 	int r = 0;
54 
55 	/*
56 	 * Auto-detect:
57 	 */
58 	if (perf_use_color_default < 0) {
59 		if (isatty(1) || pager_in_use())
60 			perf_use_color_default = 1;
61 		else
62 			perf_use_color_default = 0;
63 	}
64 
65 	if (perf_use_color_default && *color)
66 		r += scnprintf(bf, size, "%s", color);
67 	r += vscnprintf(bf + r, size - r, fmt, args);
68 	if (perf_use_color_default && *color)
69 		r += scnprintf(bf + r, size - r, "%s", PERF_COLOR_RESET);
70 	if (trail)
71 		r += scnprintf(bf + r, size - r, "%s", trail);
72 	return r;
73 }
74 
75 /* Colors are not included in return value */
76 static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
77 		va_list args)
78 {
79 	int r = 0;
80 
81 	/*
82 	 * Auto-detect:
83 	 */
84 	if (perf_use_color_default < 0) {
85 		if (isatty(fileno(fp)) || pager_in_use())
86 			perf_use_color_default = 1;
87 		else
88 			perf_use_color_default = 0;
89 	}
90 
91 	if (perf_use_color_default && *color)
92 		fprintf(fp, "%s", color);
93 	r += vfprintf(fp, fmt, args);
94 	if (perf_use_color_default && *color)
95 		fprintf(fp, "%s", PERF_COLOR_RESET);
96 	return r;
97 }
98 
99 int color_vsnprintf(char *bf, size_t size, const char *color,
100 		    const char *fmt, va_list args)
101 {
102 	return __color_vsnprintf(bf, size, color, fmt, args, NULL);
103 }
104 
105 int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
106 {
107 	return __color_vfprintf(fp, color, fmt, args);
108 }
109 
110 int color_snprintf(char *bf, size_t size, const char *color,
111 		   const char *fmt, ...)
112 {
113 	va_list args;
114 	int r;
115 
116 	va_start(args, fmt);
117 	r = color_vsnprintf(bf, size, color, fmt, args);
118 	va_end(args);
119 	return r;
120 }
121 
122 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
123 {
124 	va_list args;
125 	int r;
126 
127 	va_start(args, fmt);
128 	r = color_vfprintf(fp, color, fmt, args);
129 	va_end(args);
130 	return r;
131 }
132 
133 /*
134  * This function splits the buffer by newlines and colors the lines individually.
135  *
136  * Returns 0 on success.
137  */
138 int color_fwrite_lines(FILE *fp, const char *color,
139 		size_t count, const char *buf)
140 {
141 	if (!*color)
142 		return fwrite(buf, count, 1, fp) != 1;
143 
144 	while (count) {
145 		char *p = memchr(buf, '\n', count);
146 
147 		if (p != buf && (fputs(color, fp) < 0 ||
148 				fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 ||
149 				fputs(PERF_COLOR_RESET, fp) < 0))
150 			return -1;
151 		if (!p)
152 			return 0;
153 		if (fputc('\n', fp) < 0)
154 			return -1;
155 		count -= p + 1 - buf;
156 		buf = p + 1;
157 	}
158 	return 0;
159 }
160 
161 const char *get_percent_color(double percent)
162 {
163 	const char *color = PERF_COLOR_NORMAL;
164 
165 	/*
166 	 * We color high-overhead entries in red, mid-overhead
167 	 * entries in green - and keep the low overhead places
168 	 * normal:
169 	 */
170 	if (fabs(percent) >= MIN_RED)
171 		color = PERF_COLOR_RED;
172 	else {
173 		if (fabs(percent) > MIN_GREEN)
174 			color = PERF_COLOR_GREEN;
175 	}
176 	return color;
177 }
178 
179 int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
180 {
181 	int r;
182 	const char *color;
183 
184 	color = get_percent_color(percent);
185 	r = color_fprintf(fp, color, fmt, percent);
186 
187 	return r;
188 }
189 
190 int value_color_snprintf(char *bf, size_t size, const char *fmt, double value)
191 {
192 	const char *color = get_percent_color(value);
193 	return color_snprintf(bf, size, color, fmt, value);
194 }
195 
196 int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
197 {
198 	va_list args;
199 	double percent;
200 
201 	va_start(args, fmt);
202 	percent = va_arg(args, double);
203 	va_end(args);
204 	return value_color_snprintf(bf, size, fmt, percent);
205 }
206 
207 int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...)
208 {
209 	va_list args;
210 	int len;
211 	double percent;
212 	const char *color;
213 
214 	va_start(args, fmt);
215 	len = va_arg(args, int);
216 	percent = va_arg(args, double);
217 	va_end(args);
218 
219 	color = get_percent_color(percent);
220 	return color_snprintf(bf, size, color, fmt, len, percent);
221 }
222