@@ -26,23 +26,77 @@ 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
+ } type ;
37
+ /* The numeric value for ANSI and 256-color modes */
38
+ unsigned char value ;
39
+ };
40
+
41
+ /*
42
+ * "word" is a buffer of length "len"; does it match the NUL-terminated
43
+ * "match" exactly?
44
+ */
45
+ static int match_word (const char * word , int len , const char * match )
30
46
{
47
+ return !strncasecmp (word , match , len ) && !match [len ];
48
+ }
49
+
50
+ static int parse_color (struct color * out , const char * name , int len )
51
+ {
52
+ /* Positions in array must match ANSI color codes */
31
53
static const char * const color_names [] = {
32
- "normal" , " black" , "red" , "green" , "yellow" ,
54
+ "black" , "red" , "green" , "yellow" ,
33
55
"blue" , "magenta" , "cyan" , "white"
34
56
};
35
57
char * end ;
36
58
int i ;
59
+ long val ;
60
+
61
+ /* First try the special word "normal"... */
62
+ if (match_word (name , len , "normal" )) {
63
+ out -> type = COLOR_NORMAL ;
64
+ return 0 ;
65
+ }
66
+
67
+ /* Then pick from our human-readable color names... */
37
68
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 ;
69
+ if (match_word (name , len , color_names [i ])) {
70
+ out -> type = COLOR_ANSI ;
71
+ out -> value = i ;
72
+ return 0 ;
73
+ }
41
74
}
42
- i = strtol (name , & end , 10 );
43
- if (end - name == len && i >= -1 && i <= 255 )
44
- return i ;
45
- return -2 ;
75
+
76
+ /* And finally try a literal 256-color-mode number */
77
+ val = strtol (name , & end , 10 );
78
+ if (end - name == len ) {
79
+ /*
80
+ * Allow "-1" as an alias for "normal", but other negative
81
+ * numbers are bogus.
82
+ */
83
+ if (val < -1 )
84
+ ; /* fall through to error */
85
+ else if (val < 0 ) {
86
+ out -> type = COLOR_NORMAL ;
87
+ return 0 ;
88
+ /* Rewrite low numbers as more-portable standard colors. */
89
+ } else if (val < 8 ) {
90
+ out -> type = COLOR_ANSI ;
91
+ out -> value = val ;
92
+ } else if (val < 256 ) {
93
+ out -> type = COLOR_256 ;
94
+ out -> value = val ;
95
+ return 0 ;
96
+ }
97
+ }
98
+
99
+ return -1 ;
46
100
}
47
101
48
102
static int parse_attr (const char * name , int len )
@@ -65,13 +119,43 @@ int color_parse(const char *value, char *dst)
65
119
return color_parse_mem (value , strlen (value ), dst );
66
120
}
67
121
122
+ #define COLOR_FOREGROUND '3'
123
+ #define COLOR_BACKGROUND '4'
124
+
125
+ /*
126
+ * Write the ANSI color codes for "c" to "out"; the string should
127
+ * already have the ANSI escape code in it. "out" should have enough
128
+ * space in it to fit any color.
129
+ */
130
+ static char * color_output (char * out , const struct color * c , char type )
131
+ {
132
+ switch (c -> type ) {
133
+ case COLOR_UNSPECIFIED :
134
+ case COLOR_NORMAL :
135
+ break ;
136
+ case COLOR_ANSI :
137
+ * out ++ = type ;
138
+ * out ++ = '0' + c -> value ;
139
+ break ;
140
+ case COLOR_256 :
141
+ out += sprintf (out , "%c8;5;%d" , type , c -> value );
142
+ break ;
143
+ }
144
+ return out ;
145
+ }
146
+
147
+ static int color_empty (const struct color * c )
148
+ {
149
+ return c -> type <= COLOR_NORMAL ;
150
+ }
151
+
68
152
int color_parse_mem (const char * value , int value_len , char * dst )
69
153
{
70
154
const char * ptr = value ;
71
155
int len = value_len ;
72
156
unsigned int attr = 0 ;
73
- int fg = -2 ;
74
- int bg = -2 ;
157
+ struct color fg = { COLOR_UNSPECIFIED } ;
158
+ struct color bg = { COLOR_UNSPECIFIED } ;
75
159
76
160
if (!strncasecmp (value , "reset" , len )) {
77
161
strcpy (dst , GIT_COLOR_RESET );
@@ -81,6 +165,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
81
165
/* [fg [bg]] [attr]... */
82
166
while (len > 0 ) {
83
167
const char * word = ptr ;
168
+ struct color c ;
84
169
int val , wordlen = 0 ;
85
170
86
171
while (len > 0 && !isspace (word [wordlen ])) {
@@ -94,14 +179,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
94
179
len -- ;
95
180
}
96
181
97
- val = parse_color (word , wordlen );
98
- if (val >= -1 ) {
99
- if (fg == -2 ) {
100
- fg = val ;
182
+ if (!parse_color (& c , word , wordlen )) {
183
+ if (fg .type == COLOR_UNSPECIFIED ) {
184
+ fg = c ;
101
185
continue ;
102
186
}
103
- if (bg == -2 ) {
104
- bg = val ;
187
+ if (bg . type == COLOR_UNSPECIFIED ) {
188
+ bg = c ;
105
189
continue ;
106
190
}
107
191
goto bad ;
@@ -113,7 +197,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
113
197
goto bad ;
114
198
}
115
199
116
- if (attr || fg >= 0 || bg >= 0 ) {
200
+ if (attr || ! color_empty ( & fg ) || ! color_empty ( & bg ) ) {
117
201
int sep = 0 ;
118
202
int i ;
119
203
@@ -129,25 +213,15 @@ int color_parse_mem(const char *value, int value_len, char *dst)
129
213
* dst ++ = ';' ;
130
214
* dst ++ = '0' + i ;
131
215
}
132
- if (fg >= 0 ) {
216
+ if (! color_empty ( & fg ) ) {
133
217
if (sep ++ )
134
218
* dst ++ = ';' ;
135
- if (fg < 8 ) {
136
- * dst ++ = '3' ;
137
- * dst ++ = '0' + fg ;
138
- } else {
139
- dst += sprintf (dst , "38;5;%d" , fg );
140
- }
219
+ dst = color_output (dst , & fg , COLOR_FOREGROUND );
141
220
}
142
- if (bg >= 0 ) {
221
+ if (! color_empty ( & bg ) ) {
143
222
if (sep ++ )
144
223
* dst ++ = ';' ;
145
- if (bg < 8 ) {
146
- * dst ++ = '4' ;
147
- * dst ++ = '0' + bg ;
148
- } else {
149
- dst += sprintf (dst , "48;5;%d" , bg );
150
- }
224
+ dst = color_output (dst , & bg , COLOR_BACKGROUND );
151
225
}
152
226
* dst ++ = 'm' ;
153
227
}
0 commit comments