@@ -26,30 +26,109 @@ const char *column_colors_ansi[] = {
26
26
/* Ignore the RESET at the end when giving the size */
27
27
const int column_colors_ansi_max = ARRAY_SIZE (column_colors_ansi ) - 1 ;
28
28
29
- static int parse_color (const char * name , int len )
29
+ /* An individual foreground or background color. */
30
+ struct color {
31
+ enum {
32
+ COLOR_UNSPECIFIED = 0 ,
33
+ COLOR_NORMAL ,
34
+ COLOR_ANSI , /* basic 0-7 ANSI colors */
35
+ COLOR_256 ,
36
+ COLOR_RGB
37
+ } type ;
38
+ /* The numeric value for ANSI and 256-color modes */
39
+ unsigned char value ;
40
+ /* 24-bit RGB color values */
41
+ unsigned char red , green , blue ;
42
+ };
43
+
44
+ /*
45
+ * "word" is a buffer of length "len"; does it match the NUL-terminated
46
+ * "match" exactly?
47
+ */
48
+ static int match_word (const char * word , int len , const char * match )
30
49
{
50
+ return !strncasecmp (word , match , len ) && !match [len ];
51
+ }
52
+
53
+ static int get_hex_color (const char * in , unsigned char * out )
54
+ {
55
+ unsigned int val ;
56
+ val = (hexval (in [0 ]) << 4 ) | hexval (in [1 ]);
57
+ if (val & ~0xff )
58
+ return -1 ;
59
+ * out = val ;
60
+ return 0 ;
61
+ }
62
+
63
+ static int parse_color (struct color * out , const char * name , int len )
64
+ {
65
+ /* Positions in array must match ANSI color codes */
31
66
static const char * const color_names [] = {
32
- "normal" , " black" , "red" , "green" , "yellow" ,
67
+ "black" , "red" , "green" , "yellow" ,
33
68
"blue" , "magenta" , "cyan" , "white"
34
69
};
35
70
char * end ;
36
71
int i ;
72
+ long val ;
73
+
74
+ /* First try the special word "normal"... */
75
+ if (match_word (name , len , "normal" )) {
76
+ out -> type = COLOR_NORMAL ;
77
+ return 0 ;
78
+ }
79
+
80
+ /* Try a 24-bit RGB value */
81
+ if (len == 7 && name [0 ] == '#' ) {
82
+ if (!get_hex_color (name + 1 , & out -> red ) &&
83
+ !get_hex_color (name + 3 , & out -> green ) &&
84
+ !get_hex_color (name + 5 , & out -> blue )) {
85
+ out -> type = COLOR_RGB ;
86
+ return 0 ;
87
+ }
88
+ }
89
+
90
+ /* Then pick from our human-readable color names... */
37
91
for (i = 0 ; i < ARRAY_SIZE (color_names ); i ++ ) {
38
- const char * str = color_names [i ];
39
- if (!strncasecmp (name , str , len ) && !str [len ])
40
- return i - 1 ;
92
+ if (match_word (name , len , color_names [i ])) {
93
+ out -> type = COLOR_ANSI ;
94
+ out -> value = i ;
95
+ return 0 ;
96
+ }
97
+ }
98
+
99
+ /* And finally try a literal 256-color-mode number */
100
+ val = strtol (name , & end , 10 );
101
+ if (end - name == len ) {
102
+ /*
103
+ * Allow "-1" as an alias for "normal", but other negative
104
+ * numbers are bogus.
105
+ */
106
+ if (val < -1 )
107
+ ; /* fall through to error */
108
+ else if (val < 0 ) {
109
+ out -> type = COLOR_NORMAL ;
110
+ return 0 ;
111
+ /* Rewrite low numbers as more-portable standard colors. */
112
+ } else if (val < 8 ) {
113
+ out -> type = COLOR_ANSI ;
114
+ out -> value = val ;
115
+ } else if (val < 256 ) {
116
+ out -> type = COLOR_256 ;
117
+ out -> value = val ;
118
+ return 0 ;
119
+ }
41
120
}
42
- i = strtol (name , & end , 10 );
43
- if (end - name == len && i >= -1 && i <= 255 )
44
- return i ;
45
- return -2 ;
121
+
122
+ return -1 ;
46
123
}
47
124
48
125
static int parse_attr (const char * name , int len )
49
126
{
50
- static const int attr_values [] = { 1 , 2 , 4 , 5 , 7 };
127
+ static const int attr_values [] = { 1 , 2 , 4 , 5 , 7 ,
128
+ 22 , 22 , 24 , 25 , 27 };
51
129
static const char * const attr_names [] = {
52
- "bold" , "dim" , "ul" , "blink" , "reverse"
130
+ "bold" , "dim" , "ul" , "blink" , "reverse" ,
131
+ "nobold" , "nodim" , "noul" , "noblink" , "noreverse"
53
132
};
54
133
int i ;
55
134
for (i = 0 ; i < ARRAY_SIZE (attr_names ); i ++ ) {
@@ -65,13 +144,44 @@ int color_parse(const char *value, char *dst)
65
144
return color_parse_mem (value , strlen (value ), dst );
66
145
}
67
146
147
+ /*
148
+ * Write the ANSI color codes for "c" to "out"; the string should
149
+ * already have the ANSI escape code in it. "out" should have enough
150
+ * space in it to fit any color.
151
+ */
152
+ static char * color_output (char * out , const struct color * c , char type )
153
+ {
154
+ switch (c -> type ) {
155
+ case COLOR_UNSPECIFIED :
156
+ case COLOR_NORMAL :
157
+ break ;
158
+ case COLOR_ANSI :
159
+ * out ++ = type ;
160
+ * out ++ = '0' + c -> value ;
161
+ break ;
162
+ case COLOR_256 :
163
+ out += sprintf (out , "%c8;5;%d" , type , c -> value );
164
+ break ;
165
+ case COLOR_RGB :
166
+ out += sprintf (out , "%c8;2;%d;%d;%d" , type ,
167
+ c -> red , c -> green , c -> blue );
168
+ break ;
169
+ }
170
+ return out ;
171
+ }
172
+
173
+ static int color_empty (const struct color * c )
174
+ {
175
+ return c -> type <= COLOR_NORMAL ;
176
+ }
177
+
68
178
int color_parse_mem (const char * value , int value_len , char * dst )
69
179
{
70
180
const char * ptr = value ;
71
181
int len = value_len ;
72
182
unsigned int attr = 0 ;
73
- int fg = -2 ;
74
- int bg = -2 ;
183
+ struct color fg = { COLOR_UNSPECIFIED } ;
184
+ struct color bg = { COLOR_UNSPECIFIED } ;
75
185
76
186
if (!strncasecmp (value , "reset" , len )) {
77
187
strcpy (dst , GIT_COLOR_RESET );
@@ -81,6 +191,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
81
191
/* [fg [bg]] [attr]... */
82
192
while (len > 0 ) {
83
193
const char * word = ptr ;
194
+ struct color c ;
84
195
int val , wordlen = 0 ;
85
196
86
197
while (len > 0 && !isspace (word [wordlen ])) {
@@ -94,14 +205,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
94
205
len -- ;
95
206
}
96
207
97
- val = parse_color (word , wordlen );
98
- if (val >= -1 ) {
99
- if (fg == -2 ) {
100
- fg = val ;
208
+ if (!parse_color (& c , word , wordlen )) {
209
+ if (fg .type == COLOR_UNSPECIFIED ) {
210
+ fg = c ;
101
211
continue ;
102
212
}
103
- if (bg == -2 ) {
104
- bg = val ;
213
+ if (bg . type == COLOR_UNSPECIFIED ) {
214
+ bg = c ;
105
215
continue ;
106
216
}
107
217
goto bad ;
@@ -113,7 +223,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
113
223
goto bad ;
114
224
}
115
225
116
- if (attr || fg >= 0 || bg >= 0 ) {
226
+ if (attr || ! color_empty ( & fg ) || ! color_empty ( & bg ) ) {
117
227
int sep = 0 ;
118
228
int i ;
119
229
@@ -127,27 +237,19 @@ int color_parse_mem(const char *value, int value_len, char *dst)
127
237
attr &= ~bit ;
128
238
if (sep ++ )
129
239
* dst ++ = ';' ;
130
- * dst ++ = '0' + i ;
240
+ dst += sprintf ( dst , "%d" , i ) ;
131
241
}
132
- if (fg >= 0 ) {
242
+ if (! color_empty ( & fg ) ) {
133
243
if (sep ++ )
134
244
* dst ++ = ';' ;
135
- if (fg < 8 ) {
136
- * dst ++ = '3' ;
137
- * dst ++ = '0' + fg ;
138
- } else {
139
- dst += sprintf (dst , "38;5;%d" , fg );
140
- }
245
+ /* foreground colors are all in the 3x range */
246
+ dst = color_output (dst , & fg , '3' );
141
247
}
142
- if (bg >= 0 ) {
248
+ if (! color_empty ( & bg ) ) {
143
249
if (sep ++ )
144
250
* dst ++ = ';' ;
145
- if (bg < 8 ) {
146
- * dst ++ = '4' ;
147
- * dst ++ = '0' + bg ;
148
- } else {
149
- dst += sprintf (dst , "48;5;%d" , bg );
150
- }
251
+ /* background colors are all in the 4x range */
252
+ dst = color_output (dst , & bg , '4' );
151
253
}
152
254
* dst ++ = 'm' ;
153
255
}
0 commit comments