1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/kernel.h> |
3 | #include <subcmd/pager.h> |
4 | #include <stdlib.h> |
5 | #include <stdio.h> |
6 | #include <string.h> |
7 | #include "color.h" |
8 | #include <math.h> |
9 | #include <unistd.h> |
10 | |
11 | int perf_use_color_default = -1; |
12 | |
13 | static int __color_vsnprintf(char *bf, size_t size, const char *color, |
14 | const char *fmt, va_list args, const char *trail) |
15 | { |
16 | int r = 0; |
17 | |
18 | /* |
19 | * Auto-detect: |
20 | */ |
21 | if (perf_use_color_default < 0) { |
22 | if (isatty(1) || pager_in_use()) |
23 | perf_use_color_default = 1; |
24 | else |
25 | perf_use_color_default = 0; |
26 | } |
27 | |
28 | if (perf_use_color_default && *color) |
29 | r += scnprintf(buf: bf, size, fmt: "%s" , color); |
30 | r += vscnprintf(buf: bf + r, size: size - r, fmt, args); |
31 | if (perf_use_color_default && *color) |
32 | r += scnprintf(buf: bf + r, size: size - r, fmt: "%s" , PERF_COLOR_RESET); |
33 | if (trail) |
34 | r += scnprintf(buf: bf + r, size: size - r, fmt: "%s" , trail); |
35 | return r; |
36 | } |
37 | |
38 | /* Colors are not included in return value */ |
39 | static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, |
40 | va_list args) |
41 | { |
42 | int r = 0; |
43 | |
44 | /* |
45 | * Auto-detect: |
46 | */ |
47 | if (perf_use_color_default < 0) { |
48 | if (isatty(fileno(fp)) || pager_in_use()) |
49 | perf_use_color_default = 1; |
50 | else |
51 | perf_use_color_default = 0; |
52 | } |
53 | |
54 | if (perf_use_color_default && *color) |
55 | fprintf(fp, "%s" , color); |
56 | r += vfprintf(fp, fmt, args); |
57 | if (perf_use_color_default && *color) |
58 | fprintf(fp, "%s" , PERF_COLOR_RESET); |
59 | return r; |
60 | } |
61 | |
62 | int color_vsnprintf(char *bf, size_t size, const char *color, |
63 | const char *fmt, va_list args) |
64 | { |
65 | return __color_vsnprintf(bf, size, color, fmt, args, NULL); |
66 | } |
67 | |
68 | int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) |
69 | { |
70 | return __color_vfprintf(fp, color, fmt, args); |
71 | } |
72 | |
73 | int color_snprintf(char *bf, size_t size, const char *color, |
74 | const char *fmt, ...) |
75 | { |
76 | va_list args; |
77 | int r; |
78 | |
79 | va_start(args, fmt); |
80 | r = color_vsnprintf(bf, size, color, fmt, args); |
81 | va_end(args); |
82 | return r; |
83 | } |
84 | |
85 | int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) |
86 | { |
87 | va_list args; |
88 | int r; |
89 | |
90 | va_start(args, fmt); |
91 | r = color_vfprintf(fp, color, fmt, args); |
92 | va_end(args); |
93 | return r; |
94 | } |
95 | |
96 | /* |
97 | * This function splits the buffer by newlines and colors the lines individually. |
98 | * |
99 | * Returns 0 on success. |
100 | */ |
101 | int color_fwrite_lines(FILE *fp, const char *color, |
102 | size_t count, const char *buf) |
103 | { |
104 | if (!*color) |
105 | return fwrite(buf, count, 1, fp) != 1; |
106 | |
107 | while (count) { |
108 | char *p = memchr(buf, '\n', count); |
109 | |
110 | if (p != buf && (fputs(color, fp) < 0 || |
111 | fwrite(buf, p ? (size_t)(p - buf) : count, 1, fp) != 1 || |
112 | fputs(PERF_COLOR_RESET, fp) < 0)) |
113 | return -1; |
114 | if (!p) |
115 | return 0; |
116 | if (fputc('\n', fp) < 0) |
117 | return -1; |
118 | count -= p + 1 - buf; |
119 | buf = p + 1; |
120 | } |
121 | return 0; |
122 | } |
123 | |
124 | const char *get_percent_color(double percent) |
125 | { |
126 | const char *color = PERF_COLOR_NORMAL; |
127 | |
128 | /* |
129 | * We color high-overhead entries in red, mid-overhead |
130 | * entries in green - and keep the low overhead places |
131 | * normal: |
132 | */ |
133 | if (fabs(percent) >= MIN_RED) |
134 | color = PERF_COLOR_RED; |
135 | else { |
136 | if (fabs(percent) > MIN_GREEN) |
137 | color = PERF_COLOR_GREEN; |
138 | } |
139 | return color; |
140 | } |
141 | |
142 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent) |
143 | { |
144 | int r; |
145 | const char *color; |
146 | |
147 | color = get_percent_color(percent); |
148 | r = color_fprintf(fp, color, fmt, percent); |
149 | |
150 | return r; |
151 | } |
152 | |
153 | int value_color_snprintf(char *bf, size_t size, const char *fmt, double value) |
154 | { |
155 | const char *color = get_percent_color(percent: value); |
156 | return color_snprintf(bf, size, color, fmt, value); |
157 | } |
158 | |
159 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) |
160 | { |
161 | va_list args; |
162 | double percent; |
163 | |
164 | va_start(args, fmt); |
165 | percent = va_arg(args, double); |
166 | va_end(args); |
167 | return value_color_snprintf(bf, size, fmt, value: percent); |
168 | } |
169 | |
170 | int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...) |
171 | { |
172 | va_list args; |
173 | int len; |
174 | double percent; |
175 | const char *color; |
176 | |
177 | va_start(args, fmt); |
178 | len = va_arg(args, int); |
179 | percent = va_arg(args, double); |
180 | va_end(args); |
181 | |
182 | color = get_percent_color(percent); |
183 | return color_snprintf(bf, size, color, fmt, len, percent); |
184 | } |
185 | |