Trivial typo fixes and cosmetic cleanups.
[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  * \return -1 on errors, 1 on success.
51  *
52  * Format of \a value: [fg [bg]] [attr].
53  */
54 int color_parse(const char *value, char *dst)
55 {
56         const char *ptr = value;
57         int attr = -1;
58         int fg = -2;
59         int bg = -2;
60
61         if (!strcasecmp(value, "reset")) {
62                 strcpy(dst, COLOR_RESET);
63                 return 1;
64         }
65
66         /* [fg [bg]] [attr] */
67         while (*ptr) {
68                 const char *word = ptr;
69                 int val, len = 0;
70
71                 while (word[len] && !para_isspace(word[len]))
72                         len++;
73
74                 ptr = word + len;
75                 while (*ptr && para_isspace(*ptr))
76                         ptr++;
77
78                 val = parse_color(word, len);
79                 if (val >= -1) {
80                         if (fg == -2) {
81                                 fg = val;
82                                 continue;
83                         }
84                         if (bg == -2) {
85                                 bg = val;
86                                 continue;
87                         }
88                         goto bad;
89                 }
90                 val = parse_attr(word, len);
91                 if (val < 0 || attr != -1)
92                         goto bad;
93                 attr = val;
94         }
95
96         if (attr >= 0 || fg >= 0 || bg >= 0) {
97                 int sep = 0;
98
99                 *dst++ = '\033';
100                 *dst++ = '[';
101                 if (attr >= 0) {
102                         *dst++ = '0' + attr;
103                         sep++;
104                 }
105                 if (fg >= 0) {
106                         if (sep++)
107                                 *dst++ = ';';
108                         if (fg < 8) {
109                                 *dst++ = '3';
110                                 *dst++ = '0' + fg;
111                         } else {
112                                 dst += sprintf(dst, "38;5;%d", fg);
113                         }
114                 }
115                 if (bg >= 0) {
116                         if (sep)
117                                 *dst++ = ';';
118                         if (bg < 8) {
119                                 *dst++ = '4';
120                                 *dst++ = '0' + bg;
121                         } else {
122                                 dst += sprintf(dst, "48;5;%d", bg);
123                         }
124                 }
125                 *dst++ = 'm';
126         }
127         *dst = 0;
128         return 1;
129 bad:
130         PARA_ERROR_LOG("bad color value '%s'\n", value);
131         return -1;
132 }