f93d40b1c203aaa54309e3957f6ba019ded6d73f
[linux-2.6-block.git] / tools / perf / ui / browser.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "../util/util.h"
3 #include "../util/string2.h"
4 #include "../util/config.h"
5 #include "libslang.h"
6 #include "ui.h"
7 #include "util.h"
8 #include <linux/compiler.h>
9 #include <linux/list.h>
10 #include <linux/rbtree.h>
11 #include <linux/string.h>
12 #include <stdlib.h>
13 #include <sys/ttydefaults.h>
14 #include "browser.h"
15 #include "helpline.h"
16 #include "keysyms.h"
17 #include "../util/color.h"
18 #include <linux/ctype.h>
19 #include <linux/zalloc.h>
20
21 static int ui_browser__percent_color(struct ui_browser *browser,
22                                      double percent, bool current)
23 {
24         if (current && (!browser->use_navkeypressed || browser->navkeypressed))
25                 return HE_COLORSET_SELECTED;
26         if (percent >= MIN_RED)
27                 return HE_COLORSET_TOP;
28         if (percent >= MIN_GREEN)
29                 return HE_COLORSET_MEDIUM;
30         return HE_COLORSET_NORMAL;
31 }
32
33 int ui_browser__set_color(struct ui_browser *browser, int color)
34 {
35         int ret = browser->current_color;
36         browser->current_color = color;
37         SLsmg_set_color(color);
38         return ret;
39 }
40
41 void ui_browser__set_percent_color(struct ui_browser *browser,
42                                    double percent, bool current)
43 {
44          int color = ui_browser__percent_color(browser, percent, current);
45          ui_browser__set_color(browser, color);
46 }
47
48 void ui_browser__gotorc_title(struct ui_browser *browser, int y, int x)
49 {
50         SLsmg_gotorc(browser->y + y, browser->x + x);
51 }
52
53 void ui_browser__gotorc(struct ui_browser *browser, int y, int x)
54 {
55         SLsmg_gotorc(browser->y + y + browser->extra_title_lines, browser->x + x);
56 }
57
58 void ui_browser__write_nstring(struct ui_browser *browser __maybe_unused, const char *msg,
59                                unsigned int width)
60 {
61         slsmg_write_nstring(msg, width);
62 }
63
64 void ui_browser__vprintf(struct ui_browser *browser __maybe_unused, const char *fmt, va_list args)
65 {
66         slsmg_vprintf(fmt, args);
67 }
68
69 void ui_browser__printf(struct ui_browser *browser __maybe_unused, const char *fmt, ...)
70 {
71         va_list args;
72
73         va_start(args, fmt);
74         ui_browser__vprintf(browser, fmt, args);
75         va_end(args);
76 }
77
78 static struct list_head *
79 ui_browser__list_head_filter_entries(struct ui_browser *browser,
80                                      struct list_head *pos)
81 {
82         do {
83                 if (!browser->filter || !browser->filter(browser, pos))
84                         return pos;
85                 pos = pos->next;
86         } while (pos != browser->entries);
87
88         return NULL;
89 }
90
91 static struct list_head *
92 ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
93                                           struct list_head *pos)
94 {
95         do {
96                 if (!browser->filter || !browser->filter(browser, pos))
97                         return pos;
98                 pos = pos->prev;
99         } while (pos != browser->entries);
100
101         return NULL;
102 }
103
104 void ui_browser__list_head_seek(struct ui_browser *browser, off_t offset, int whence)
105 {
106         struct list_head *head = browser->entries;
107         struct list_head *pos;
108
109         if (browser->nr_entries == 0)
110                 return;
111
112         switch (whence) {
113         case SEEK_SET:
114                 pos = ui_browser__list_head_filter_entries(browser, head->next);
115                 break;
116         case SEEK_CUR:
117                 pos = browser->top;
118                 break;
119         case SEEK_END:
120                 pos = ui_browser__list_head_filter_prev_entries(browser, head->prev);
121                 break;
122         default:
123                 return;
124         }
125
126         assert(pos != NULL);
127
128         if (offset > 0) {
129                 while (offset-- != 0)
130                         pos = ui_browser__list_head_filter_entries(browser, pos->next);
131         } else {
132                 while (offset++ != 0)
133                         pos = ui_browser__list_head_filter_prev_entries(browser, pos->prev);
134         }
135
136         browser->top = pos;
137 }
138
139 void ui_browser__rb_tree_seek(struct ui_browser *browser, off_t offset, int whence)
140 {
141         struct rb_root *root = browser->entries;
142         struct rb_node *nd;
143
144         switch (whence) {
145         case SEEK_SET:
146                 nd = rb_first(root);
147                 break;
148         case SEEK_CUR:
149                 nd = browser->top;
150                 break;
151         case SEEK_END:
152                 nd = rb_last(root);
153                 break;
154         default:
155                 return;
156         }
157
158         if (offset > 0) {
159                 while (offset-- != 0)
160                         nd = rb_next(nd);
161         } else {
162                 while (offset++ != 0)
163                         nd = rb_prev(nd);
164         }
165
166         browser->top = nd;
167 }
168
169 unsigned int ui_browser__rb_tree_refresh(struct ui_browser *browser)
170 {
171         struct rb_node *nd;
172         int row = 0;
173
174         if (browser->top == NULL)
175                 browser->top = rb_first(browser->entries);
176
177         nd = browser->top;
178
179         while (nd != NULL) {
180                 ui_browser__gotorc(browser, row, 0);
181                 browser->write(browser, nd, row);
182                 if (++row == browser->rows)
183                         break;
184                 nd = rb_next(nd);
185         }
186
187         return row;
188 }
189
190 bool ui_browser__is_current_entry(struct ui_browser *browser, unsigned row)
191 {
192         return browser->top_idx + row == browser->index;
193 }
194
195 void ui_browser__refresh_dimensions(struct ui_browser *browser)
196 {
197         browser->width = SLtt_Screen_Cols - 1;
198         browser->height = browser->rows = SLtt_Screen_Rows - 2;
199         browser->rows -= browser->extra_title_lines;
200         browser->y = 1;
201         browser->x = 0;
202 }
203
204 void ui_browser__handle_resize(struct ui_browser *browser)
205 {
206         ui__refresh_dimensions(false);
207         ui_browser__show(browser, browser->title, ui_helpline__current);
208         ui_browser__refresh(browser);
209 }
210
211 int ui_browser__warning(struct ui_browser *browser, int timeout,
212                         const char *format, ...)
213 {
214         va_list args;
215         char *text;
216         int key = 0, err;
217
218         va_start(args, format);
219         err = vasprintf(&text, format, args);
220         va_end(args);
221
222         if (err < 0) {
223                 va_start(args, format);
224                 ui_helpline__vpush(format, args);
225                 va_end(args);
226         } else {
227                 while ((key = ui__question_window("Warning!", text,
228                                                    "Press any key...",
229                                                    timeout)) == K_RESIZE)
230                         ui_browser__handle_resize(browser);
231                 free(text);
232         }
233
234         return key;
235 }
236
237 int ui_browser__help_window(struct ui_browser *browser, const char *text)
238 {
239         int key;
240
241         while ((key = ui__help_window(text)) == K_RESIZE)
242                 ui_browser__handle_resize(browser);
243
244         return key;
245 }
246
247 bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
248 {
249         int key;
250
251         while ((key = ui__dialog_yesno(text)) == K_RESIZE)
252                 ui_browser__handle_resize(browser);
253
254         return key == K_ENTER || toupper(key) == 'Y';
255 }
256
257 void ui_browser__reset_index(struct ui_browser *browser)
258 {
259         browser->index = browser->top_idx = 0;
260         browser->seek(browser, 0, SEEK_SET);
261 }
262
263 void __ui_browser__show_title(struct ui_browser *browser, const char *title)
264 {
265         SLsmg_gotorc(0, 0);
266         ui_browser__set_color(browser, HE_COLORSET_ROOT);
267         ui_browser__write_nstring(browser, title, browser->width + 1);
268 }
269
270 void ui_browser__show_title(struct ui_browser *browser, const char *title)
271 {
272         pthread_mutex_lock(&ui__lock);
273         __ui_browser__show_title(browser, title);
274         pthread_mutex_unlock(&ui__lock);
275 }
276
277 int ui_browser__show(struct ui_browser *browser, const char *title,
278                      const char *helpline, ...)
279 {
280         int err;
281         va_list ap;
282
283         if (browser->refresh_dimensions == NULL)
284                 browser->refresh_dimensions = ui_browser__refresh_dimensions;
285
286         browser->refresh_dimensions(browser);
287
288         pthread_mutex_lock(&ui__lock);
289         __ui_browser__show_title(browser, title);
290
291         browser->title = title;
292         zfree(&browser->helpline);
293
294         va_start(ap, helpline);
295         err = vasprintf(&browser->helpline, helpline, ap);
296         va_end(ap);
297         if (err > 0)
298                 ui_helpline__push(browser->helpline);
299         pthread_mutex_unlock(&ui__lock);
300         return err ? 0 : -1;
301 }
302
303 void ui_browser__hide(struct ui_browser *browser)
304 {
305         pthread_mutex_lock(&ui__lock);
306         ui_helpline__pop();
307         zfree(&browser->helpline);
308         pthread_mutex_unlock(&ui__lock);
309 }
310
311 static void ui_browser__scrollbar_set(struct ui_browser *browser)
312 {
313         int height = browser->height, h = 0, pct = 0,
314             col = browser->width,
315             row = 0;
316
317         if (browser->nr_entries > 1) {
318                 pct = ((browser->index * (browser->height - 1)) /
319                        (browser->nr_entries - 1));
320         }
321
322         SLsmg_set_char_set(1);
323
324         while (h < height) {
325                 ui_browser__gotorc(browser, row++, col);
326                 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
327                 ++h;
328         }
329
330         SLsmg_set_char_set(0);
331 }
332
333 static int __ui_browser__refresh(struct ui_browser *browser)
334 {
335         int row;
336         int width = browser->width;
337
338         row = browser->refresh(browser);
339         ui_browser__set_color(browser, HE_COLORSET_NORMAL);
340
341         if (!browser->use_navkeypressed || browser->navkeypressed)
342                 ui_browser__scrollbar_set(browser);
343         else
344                 width += 1;
345
346         SLsmg_fill_region(browser->y + row + browser->extra_title_lines, browser->x,
347                           browser->rows - row, width, ' ');
348
349         if (browser->nr_entries == 0 && browser->no_samples_msg)
350                 __ui__info_window(NULL, browser->no_samples_msg, NULL);
351         return 0;
352 }
353
354 int ui_browser__refresh(struct ui_browser *browser)
355 {
356         pthread_mutex_lock(&ui__lock);
357         __ui_browser__refresh(browser);
358         pthread_mutex_unlock(&ui__lock);
359
360         return 0;
361 }
362
363 /*
364  * Here we're updating nr_entries _after_ we started browsing, i.e.  we have to
365  * forget about any reference to any entry in the underlying data structure,
366  * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
367  * after an output_resort and hist decay.
368  */
369 void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
370 {
371         off_t offset = nr_entries - browser->nr_entries;
372
373         browser->nr_entries = nr_entries;
374
375         if (offset < 0) {
376                 if (browser->top_idx < (u64)-offset)
377                         offset = -browser->top_idx;
378
379                 browser->index += offset;
380                 browser->top_idx += offset;
381         }
382
383         browser->top = NULL;
384         browser->seek(browser, browser->top_idx, SEEK_SET);
385 }
386
387 int ui_browser__run(struct ui_browser *browser, int delay_secs)
388 {
389         int err, key;
390
391         while (1) {
392                 off_t offset;
393
394                 pthread_mutex_lock(&ui__lock);
395                 err = __ui_browser__refresh(browser);
396                 SLsmg_refresh();
397                 pthread_mutex_unlock(&ui__lock);
398                 if (err < 0)
399                         break;
400
401                 key = ui__getch(delay_secs);
402
403                 if (key == K_RESIZE) {
404                         ui__refresh_dimensions(false);
405                         browser->refresh_dimensions(browser);
406                         __ui_browser__show_title(browser, browser->title);
407                         ui_helpline__puts(browser->helpline);
408                         continue;
409                 }
410
411                 if (browser->use_navkeypressed && !browser->navkeypressed) {
412                         if (key == K_DOWN || key == K_UP ||
413                             (browser->columns && (key == K_LEFT || key == K_RIGHT)) ||
414                             key == K_PGDN || key == K_PGUP ||
415                             key == K_HOME || key == K_END ||
416                             key == ' ') {
417                                 browser->navkeypressed = true;
418                                 continue;
419                         } else
420                                 return key;
421                 }
422
423                 switch (key) {
424                 case K_DOWN:
425                         if (browser->index == browser->nr_entries - 1)
426                                 break;
427                         ++browser->index;
428                         if (browser->index == browser->top_idx + browser->rows) {
429                                 ++browser->top_idx;
430                                 browser->seek(browser, +1, SEEK_CUR);
431                         }
432                         break;
433                 case K_UP:
434                         if (browser->index == 0)
435                                 break;
436                         --browser->index;
437                         if (browser->index < browser->top_idx) {
438                                 --browser->top_idx;
439                                 browser->seek(browser, -1, SEEK_CUR);
440                         }
441                         break;
442                 case K_RIGHT:
443                         if (!browser->columns)
444                                 goto out;
445                         if (browser->horiz_scroll < browser->columns - 1)
446                                 ++browser->horiz_scroll;
447                         break;
448                 case K_LEFT:
449                         if (!browser->columns)
450                                 goto out;
451                         if (browser->horiz_scroll != 0)
452                                 --browser->horiz_scroll;
453                         break;
454                 case K_PGDN:
455                 case ' ':
456                         if (browser->top_idx + browser->rows > browser->nr_entries - 1)
457                                 break;
458
459                         offset = browser->rows;
460                         if (browser->index + offset > browser->nr_entries - 1)
461                                 offset = browser->nr_entries - 1 - browser->index;
462                         browser->index += offset;
463                         browser->top_idx += offset;
464                         browser->seek(browser, +offset, SEEK_CUR);
465                         break;
466                 case K_PGUP:
467                         if (browser->top_idx == 0)
468                                 break;
469
470                         if (browser->top_idx < browser->rows)
471                                 offset = browser->top_idx;
472                         else
473                                 offset = browser->rows;
474
475                         browser->index -= offset;
476                         browser->top_idx -= offset;
477                         browser->seek(browser, -offset, SEEK_CUR);
478                         break;
479                 case K_HOME:
480                         ui_browser__reset_index(browser);
481                         break;
482                 case K_END:
483                         offset = browser->rows - 1;
484                         if (offset >= browser->nr_entries)
485                                 offset = browser->nr_entries - 1;
486
487                         browser->index = browser->nr_entries - 1;
488                         browser->top_idx = browser->index - offset;
489                         browser->seek(browser, -offset, SEEK_END);
490                         break;
491                 default:
492                 out:
493                         return key;
494                 }
495         }
496         return -1;
497 }
498
499 unsigned int ui_browser__list_head_refresh(struct ui_browser *browser)
500 {
501         struct list_head *pos;
502         struct list_head *head = browser->entries;
503         int row = 0;
504
505         if (browser->top == NULL || browser->top == browser->entries)
506                 browser->top = ui_browser__list_head_filter_entries(browser, head->next);
507
508         pos = browser->top;
509
510         list_for_each_from(pos, head) {
511                 if (!browser->filter || !browser->filter(browser, pos)) {
512                         ui_browser__gotorc(browser, row, 0);
513                         browser->write(browser, pos, row);
514                         if (++row == browser->rows)
515                                 break;
516                 }
517         }
518
519         return row;
520 }
521
522 static struct ui_browser_colorset {
523         const char *name, *fg, *bg;
524         int colorset;
525 } ui_browser__colorsets[] = {
526         {
527                 .colorset = HE_COLORSET_TOP,
528                 .name     = "top",
529                 .fg       = "red",
530                 .bg       = "default",
531         },
532         {
533                 .colorset = HE_COLORSET_MEDIUM,
534                 .name     = "medium",
535                 .fg       = "green",
536                 .bg       = "default",
537         },
538         {
539                 .colorset = HE_COLORSET_NORMAL,
540                 .name     = "normal",
541                 .fg       = "default",
542                 .bg       = "default",
543         },
544         {
545                 .colorset = HE_COLORSET_SELECTED,
546                 .name     = "selected",
547                 .fg       = "black",
548                 .bg       = "yellow",
549         },
550         {
551                 .colorset = HE_COLORSET_JUMP_ARROWS,
552                 .name     = "jump_arrows",
553                 .fg       = "blue",
554                 .bg       = "default",
555         },
556         {
557                 .colorset = HE_COLORSET_ADDR,
558                 .name     = "addr",
559                 .fg       = "magenta",
560                 .bg       = "default",
561         },
562         {
563                 .colorset = HE_COLORSET_ROOT,
564                 .name     = "root",
565                 .fg       = "white",
566                 .bg       = "blue",
567         },
568         {
569                 .name = NULL,
570         }
571 };
572
573
574 static int ui_browser__color_config(const char *var, const char *value,
575                                     void *data __maybe_unused)
576 {
577         char *fg = NULL, *bg;
578         int i;
579
580         /* same dir for all commands */
581         if (!strstarts(var, "colors.") != 0)
582                 return 0;
583
584         for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
585                 const char *name = var + 7;
586
587                 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
588                         continue;
589
590                 fg = strdup(value);
591                 if (fg == NULL)
592                         break;
593
594                 bg = strchr(fg, ',');
595                 if (bg == NULL)
596                         break;
597
598                 *bg = '\0';
599                 bg = skip_spaces(bg + 1);
600                 ui_browser__colorsets[i].bg = bg;
601                 ui_browser__colorsets[i].fg = fg;
602                 return 0;
603         }
604
605         free(fg);
606         return -1;
607 }
608
609 void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
610 {
611         switch (whence) {
612         case SEEK_SET:
613                 browser->top = browser->entries;
614                 break;
615         case SEEK_CUR:
616                 browser->top = (char **)browser->top + offset;
617                 break;
618         case SEEK_END:
619                 browser->top = (char **)browser->entries + browser->nr_entries - 1 + offset;
620                 break;
621         default:
622                 return;
623         }
624         assert((char **)browser->top < (char **)browser->entries + browser->nr_entries);
625         assert((char **)browser->top >= (char **)browser->entries);
626 }
627
628 unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
629 {
630         unsigned int row = 0, idx = browser->top_idx;
631         char **pos;
632
633         if (browser->top == NULL)
634                 browser->top = browser->entries;
635
636         pos = (char **)browser->top;
637         while (idx < browser->nr_entries &&
638                row < (unsigned)SLtt_Screen_Rows - 1) {
639                 assert(pos < (char **)browser->entries + browser->nr_entries);
640                 if (!browser->filter || !browser->filter(browser, *pos)) {
641                         ui_browser__gotorc(browser, row, 0);
642                         browser->write(browser, pos, row);
643                         if (++row == browser->rows)
644                                 break;
645                 }
646
647                 ++idx;
648                 ++pos;
649         }
650
651         return row;
652 }
653
654 void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
655                          u16 start, u16 end)
656 {
657         SLsmg_set_char_set(1);
658         ui_browser__gotorc(browser, start, column);
659         SLsmg_draw_vline(end - start + 1);
660         SLsmg_set_char_set(0);
661 }
662
663 void ui_browser__write_graph(struct ui_browser *browser __maybe_unused,
664                              int graph)
665 {
666         SLsmg_set_char_set(1);
667         SLsmg_write_char(graph);
668         SLsmg_set_char_set(0);
669 }
670
671 static void __ui_browser__line_arrow_up(struct ui_browser *browser,
672                                         unsigned int column,
673                                         u64 start, u64 end)
674 {
675         unsigned int row, end_row;
676
677         SLsmg_set_char_set(1);
678
679         if (start < browser->top_idx + browser->rows) {
680                 row = start - browser->top_idx;
681                 ui_browser__gotorc(browser, row, column);
682                 SLsmg_write_char(SLSMG_LLCORN_CHAR);
683                 ui_browser__gotorc(browser, row, column + 1);
684                 SLsmg_draw_hline(2);
685
686                 if (row-- == 0)
687                         goto out;
688         } else
689                 row = browser->rows - 1;
690
691         if (end > browser->top_idx)
692                 end_row = end - browser->top_idx;
693         else
694                 end_row = 0;
695
696         ui_browser__gotorc(browser, end_row, column);
697         SLsmg_draw_vline(row - end_row + 1);
698
699         ui_browser__gotorc(browser, end_row, column);
700         if (end >= browser->top_idx) {
701                 SLsmg_write_char(SLSMG_ULCORN_CHAR);
702                 ui_browser__gotorc(browser, end_row, column + 1);
703                 SLsmg_write_char(SLSMG_HLINE_CHAR);
704                 ui_browser__gotorc(browser, end_row, column + 2);
705                 SLsmg_write_char(SLSMG_RARROW_CHAR);
706         }
707 out:
708         SLsmg_set_char_set(0);
709 }
710
711 static void __ui_browser__line_arrow_down(struct ui_browser *browser,
712                                           unsigned int column,
713                                           u64 start, u64 end)
714 {
715         unsigned int row, end_row;
716
717         SLsmg_set_char_set(1);
718
719         if (start >= browser->top_idx) {
720                 row = start - browser->top_idx;
721                 ui_browser__gotorc(browser, row, column);
722                 SLsmg_write_char(SLSMG_ULCORN_CHAR);
723                 ui_browser__gotorc(browser, row, column + 1);
724                 SLsmg_draw_hline(2);
725
726                 if (++row == 0)
727                         goto out;
728         } else
729                 row = 0;
730
731         if (end >= browser->top_idx + browser->rows)
732                 end_row = browser->rows - 1;
733         else
734                 end_row = end - browser->top_idx;
735
736         ui_browser__gotorc(browser, row, column);
737         SLsmg_draw_vline(end_row - row + 1);
738
739         ui_browser__gotorc(browser, end_row, column);
740         if (end < browser->top_idx + browser->rows) {
741                 SLsmg_write_char(SLSMG_LLCORN_CHAR);
742                 ui_browser__gotorc(browser, end_row, column + 1);
743                 SLsmg_write_char(SLSMG_HLINE_CHAR);
744                 ui_browser__gotorc(browser, end_row, column + 2);
745                 SLsmg_write_char(SLSMG_RARROW_CHAR);
746         }
747 out:
748         SLsmg_set_char_set(0);
749 }
750
751 void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
752                               u64 start, u64 end)
753 {
754         if (start > end)
755                 __ui_browser__line_arrow_up(browser, column, start, end);
756         else
757                 __ui_browser__line_arrow_down(browser, column, start, end);
758 }
759
760 void ui_browser__mark_fused(struct ui_browser *browser, unsigned int column,
761                             unsigned int row, bool arrow_down)
762 {
763         unsigned int end_row;
764
765         if (row >= browser->top_idx)
766                 end_row = row - browser->top_idx;
767         else
768                 return;
769
770         SLsmg_set_char_set(1);
771
772         if (arrow_down) {
773                 ui_browser__gotorc(browser, end_row, column - 1);
774                 SLsmg_write_char(SLSMG_ULCORN_CHAR);
775                 ui_browser__gotorc(browser, end_row, column);
776                 SLsmg_draw_hline(2);
777                 ui_browser__gotorc(browser, end_row + 1, column - 1);
778                 SLsmg_write_char(SLSMG_LTEE_CHAR);
779         } else {
780                 ui_browser__gotorc(browser, end_row, column - 1);
781                 SLsmg_write_char(SLSMG_LTEE_CHAR);
782                 ui_browser__gotorc(browser, end_row, column);
783                 SLsmg_draw_hline(2);
784         }
785
786         SLsmg_set_char_set(0);
787 }
788
789 void ui_browser__init(void)
790 {
791         int i = 0;
792
793         perf_config(ui_browser__color_config, NULL);
794
795         while (ui_browser__colorsets[i].name) {
796                 struct ui_browser_colorset *c = &ui_browser__colorsets[i++];
797                 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
798         }
799 }