@@ -26,30 +26,109 @@ const char *column_colors_ansi[] = {
2626/* Ignore the RESET at the end when giving the size */
2727const int column_colors_ansi_max = ARRAY_SIZE (column_colors_ansi ) - 1 ;
2828
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 )
3049{
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 */
3166 static const char * const color_names [] = {
32- "normal" , " black" , "red" , "green" , "yellow" ,
67+ "black" , "red" , "green" , "yellow" ,
3368 "blue" , "magenta" , "cyan" , "white"
3469 };
3570 char * end ;
3671 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... */
3791 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+ }
41120 }
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 ;
46123}
47124
48125static int parse_attr (const char * name , int len )
49126{
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 };
51129 static const char * const attr_names [] = {
52- "bold" , "dim" , "ul" , "blink" , "reverse"
130+ "bold" , "dim" , "ul" , "blink" , "reverse" ,
131+ "nobold" , "nodim" , "noul" , "noblink" , "noreverse"
53132 };
54133 int i ;
55134 for (i = 0 ; i < ARRAY_SIZE (attr_names ); i ++ ) {
@@ -65,13 +144,44 @@ int color_parse(const char *value, char *dst)
65144 return color_parse_mem (value , strlen (value ), dst );
66145}
67146
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+
68178int color_parse_mem (const char * value , int value_len , char * dst )
69179{
70180 const char * ptr = value ;
71181 int len = value_len ;
72182 unsigned int attr = 0 ;
73- int fg = -2 ;
74- int bg = -2 ;
183+ struct color fg = { COLOR_UNSPECIFIED } ;
184+ struct color bg = { COLOR_UNSPECIFIED } ;
75185
76186 if (!strncasecmp (value , "reset" , len )) {
77187 strcpy (dst , GIT_COLOR_RESET );
@@ -81,6 +191,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
81191 /* [fg [bg]] [attr]... */
82192 while (len > 0 ) {
83193 const char * word = ptr ;
194+ struct color c ;
84195 int val , wordlen = 0 ;
85196
86197 while (len > 0 && !isspace (word [wordlen ])) {
@@ -94,14 +205,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
94205 len -- ;
95206 }
96207
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 ;
101211 continue ;
102212 }
103- if (bg == -2 ) {
104- bg = val ;
213+ if (bg . type == COLOR_UNSPECIFIED ) {
214+ bg = c ;
105215 continue ;
106216 }
107217 goto bad ;
@@ -113,7 +223,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
113223 goto bad ;
114224 }
115225
116- if (attr || fg >= 0 || bg >= 0 ) {
226+ if (attr || ! color_empty ( & fg ) || ! color_empty ( & bg ) ) {
117227 int sep = 0 ;
118228 int i ;
119229
@@ -127,27 +237,19 @@ int color_parse_mem(const char *value, int value_len, char *dst)
127237 attr &= ~bit ;
128238 if (sep ++ )
129239 * dst ++ = ';' ;
130- * dst ++ = '0' + i ;
240+ dst += sprintf ( dst , "%d" , i ) ;
131241 }
132- if (fg >= 0 ) {
242+ if (! color_empty ( & fg ) ) {
133243 if (sep ++ )
134244 * 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' );
141247 }
142- if (bg >= 0 ) {
248+ if (! color_empty ( & bg ) ) {
143249 if (sep ++ )
144250 * 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' );
151253 }
152254 * dst ++ = 'm' ;
153255 }
0 commit comments