aft: Remember current audio file after SIGHUP.
[paraslash.git] / color.c
1 /** \file color.c Functions for printing colored messages. */
2
3 /*
4  * Mostly taken from the git source tree, version 1.6.1.76, January 2009.
5  */
6
7 #include "para.h"
8 #include "color.h"
9
10 static int parse_color(const char *name, int len)
11 {
12         static const char * const color_names[] = {
13                 "normal", "black", "red", "green", "yellow",
14                 "blue", "magenta", "cyan", "white"
15         };
16         char *end;
17         int i;
18         for (i = 0; i < ARRAY_SIZE(color_names); i++) {
19                 const char *str = color_names[i];
20                 if (!strncasecmp(name, str, len) && !str[len])
21                         return i - 1;
22         }
23         i = strtol(name, &end, 10);
24         if (end - name == len && i >= -1 && i <= 255)
25                 return i;
26         return -2;
27 }
28
29 static int parse_attr(const char *name, int len)
30 {
31         static const int attr_values[] = { 1, 2, 4, 5, 7 };
32         static const char * const attr_names[] = {
33                 "bold", "dim", "ul", "blink", "reverse"
34         };
35         int i;
36         for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
37                 const char *str = attr_names[i];
38                 if (!strncasecmp(name, str, len) && !str[len])
39                         return attr_values[i];
40         }
41         return -1;
42 }
43
44 /**
45  * Create an escape sequence for colored output.
46  *
47  * \param value Human-readable color spec.
48  * \param dst Result pointer for the escape sequence.
49  *
50  * Format of \a value: [fg [bg]] [attr].
51  */
52 void color_parse_or_die(const char *value, char *dst)
53 {
54         const char *ptr = value;
55         int attr = -1;
56         int fg = -2;
57         int bg = -2;
58
59         if (!strcasecmp(value, "reset")) {
60                 strcpy(dst, COLOR_RESET);
61                 return;
62         }
63
64         /* [fg [bg]] [attr] */
65         while (*ptr) {
66                 const char *word = ptr;
67                 int val, len = 0;
68
69                 while (word[len] && !para_isspace(word[len]))
70                         len++;
71
72                 ptr = word + len;
73                 while (*ptr && para_isspace(*ptr))
74                         ptr++;
75
76                 val = parse_color(word, len);
77                 if (val >= -1) {
78                         if (fg == -2) {
79                                 fg = val;
80                                 continue;
81                         }
82                         if (bg == -2) {
83                                 bg = val;
84                                 continue;
85                         }
86                         goto bad;
87                 }
88                 val = parse_attr(word, len);
89                 if (val < 0 || attr != -1)
90                         goto bad;
91                 attr = val;
92         }
93
94         if (attr >= 0 || fg >= 0 || bg >= 0) {
95                 int sep = 0;
96
97                 *dst++ = '\033';
98                 *dst++ = '[';
99                 if (attr >= 0) {
100                         *dst++ = '0' + attr;
101                         sep++;
102                 }
103                 if (fg >= 0) {
104                         if (sep++)
105                                 *dst++ = ';';
106                         if (fg < 8) {
107                                 *dst++ = '3';
108                                 *dst++ = '0' + fg;
109                         } else {
110                                 dst += sprintf(dst, "38;5;%d", fg);
111                         }
112                 }
113                 if (bg >= 0) {
114                         if (sep)
115                                 *dst++ = ';';
116                         if (bg < 8) {
117                                 *dst++ = '4';
118                                 *dst++ = '0' + bg;
119                         } else {
120                                 dst += sprintf(dst, "48;5;%d", bg);
121                         }
122                 }
123                 *dst++ = 'm';
124         }
125         *dst = 0;
126         return;
127 bad:
128         PARA_EMERG_LOG("bad color value '%s'\n", value);
129         exit(EXIT_FAILURE);
130 }