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