@@ -26,23 +26,77 @@ 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+ } 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 )
3046{
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 */
3153 static const char * const color_names [] = {
32- "normal" , " black" , "red" , "green" , "yellow" ,
54+ "black" , "red" , "green" , "yellow" ,
3355 "blue" , "magenta" , "cyan" , "white"
3456 };
3557 char * end ;
3658 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... */
3768 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+ }
4174 }
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 ;
46100}
47101
48102static int parse_attr (const char * name , int len )
@@ -65,13 +119,43 @@ int color_parse(const char *value, char *dst)
65119 return color_parse_mem (value , strlen (value ), dst );
66120}
67121
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+
68152int color_parse_mem (const char * value , int value_len , char * dst )
69153{
70154 const char * ptr = value ;
71155 int len = value_len ;
72156 unsigned int attr = 0 ;
73- int fg = -2 ;
74- int bg = -2 ;
157+ struct color fg = { COLOR_UNSPECIFIED } ;
158+ struct color bg = { COLOR_UNSPECIFIED } ;
75159
76160 if (!strncasecmp (value , "reset" , len )) {
77161 strcpy (dst , GIT_COLOR_RESET );
@@ -81,6 +165,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
81165 /* [fg [bg]] [attr]... */
82166 while (len > 0 ) {
83167 const char * word = ptr ;
168+ struct color c ;
84169 int val , wordlen = 0 ;
85170
86171 while (len > 0 && !isspace (word [wordlen ])) {
@@ -94,14 +179,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
94179 len -- ;
95180 }
96181
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 ;
101185 continue ;
102186 }
103- if (bg == -2 ) {
104- bg = val ;
187+ if (bg . type == COLOR_UNSPECIFIED ) {
188+ bg = c ;
105189 continue ;
106190 }
107191 goto bad ;
@@ -113,7 +197,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
113197 goto bad ;
114198 }
115199
116- if (attr || fg >= 0 || bg >= 0 ) {
200+ if (attr || ! color_empty ( & fg ) || ! color_empty ( & bg ) ) {
117201 int sep = 0 ;
118202 int i ;
119203
@@ -129,25 +213,15 @@ int color_parse_mem(const char *value, int value_len, char *dst)
129213 * dst ++ = ';' ;
130214 * dst ++ = '0' + i ;
131215 }
132- if (fg >= 0 ) {
216+ if (! color_empty ( & fg ) ) {
133217 if (sep ++ )
134218 * 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 );
141220 }
142- if (bg >= 0 ) {
221+ if (! color_empty ( & bg ) ) {
143222 if (sep ++ )
144223 * 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 );
151225 }
152226 * dst ++ = 'm' ;
153227 }
0 commit comments