color.c 6.8 KB

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