@@ -23,6 +23,12 @@ static struct keyword_entry keywords[] = {
23
23
{ "error" , GIT_COLOR_BOLD_RED },
24
24
};
25
25
26
+ static enum {
27
+ ALLOW_NO_CONTROL_CHARACTERS = 0 ,
28
+ ALLOW_ALL_CONTROL_CHARACTERS = 1 ,
29
+ ALLOW_ANSI_COLOR_SEQUENCES = 2
30
+ } allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES ;
31
+
26
32
/* Returns a color setting (GIT_COLOR_NEVER, etc). */
27
33
static int use_sideband_colors (void )
28
34
{
@@ -36,6 +42,25 @@ static int use_sideband_colors(void)
36
42
if (use_sideband_colors_cached >= 0 )
37
43
return use_sideband_colors_cached ;
38
44
45
+ switch (git_config_get_maybe_bool ("sideband.allowcontrolcharacters" , & i )) {
46
+ case 0 : /* Boolean value */
47
+ allow_control_characters = i ? ALLOW_ALL_CONTROL_CHARACTERS :
48
+ ALLOW_NO_CONTROL_CHARACTERS ;
49
+ break ;
50
+ case -1 : /* non-Boolean value */
51
+ if (git_config_get_string ("sideband.allowcontrolcharacters" ,
52
+ & value ))
53
+ ; /* huh? `get_maybe_bool()` returned -1 */
54
+ else if (!strcmp (value , "color" ))
55
+ allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES ;
56
+ else
57
+ warning (_ ("unrecognized value for `sideband."
58
+ "allowControlCharacters`: '%s'" ), value );
59
+ break ;
60
+ default :
61
+ break ; /* not configured */
62
+ }
63
+
39
64
if (!git_config_get_string (key , & value )) {
40
65
use_sideband_colors_cached = git_config_colorbool (key , value );
41
66
} else if (!git_config_get_string ("color.ui" , & value )) {
@@ -64,6 +89,55 @@ void list_config_color_sideband_slots(struct string_list *list, const char *pref
64
89
list_config_item (list , prefix , keywords [i ].keyword );
65
90
}
66
91
92
+ static int handle_ansi_color_sequence (struct strbuf * dest , const char * src , int n )
93
+ {
94
+ int i ;
95
+
96
+ /*
97
+ * Valid ANSI color sequences are of the form
98
+ *
99
+ * ESC [ [<n> [; <n>]*] m
100
+ */
101
+
102
+ if (allow_control_characters != ALLOW_ANSI_COLOR_SEQUENCES ||
103
+ n < 3 || src [0 ] != '\x1b' || src [1 ] != '[' )
104
+ return 0 ;
105
+
106
+ for (i = 2 ; i < n ; i ++ ) {
107
+ if (src [i ] == 'm' ) {
108
+ strbuf_add (dest , src , i + 1 );
109
+ return i ;
110
+ }
111
+ if (!isdigit (src [i ]) && src [i ] != ';' )
112
+ break ;
113
+ }
114
+
115
+ return 0 ;
116
+ }
117
+
118
+ static void strbuf_add_sanitized (struct strbuf * dest , const char * src , int n )
119
+ {
120
+ int i ;
121
+
122
+ if (allow_control_characters == ALLOW_ALL_CONTROL_CHARACTERS ) {
123
+ strbuf_add (dest , src , n );
124
+ return ;
125
+ }
126
+
127
+ strbuf_grow (dest , n );
128
+ for (; n && * src ; src ++ , n -- ) {
129
+ if (!iscntrl (* src ) || * src == '\t' || * src == '\n' )
130
+ strbuf_addch (dest , * src );
131
+ else if ((i = handle_ansi_color_sequence (dest , src , n ))) {
132
+ src += i ;
133
+ n -= i ;
134
+ } else {
135
+ strbuf_addch (dest , '^' );
136
+ strbuf_addch (dest , 0x40 + * src );
137
+ }
138
+ }
139
+ }
140
+
67
141
/*
68
142
* Optionally highlight one keyword in remote output if it appears at the start
69
143
* of the line. This should be called for a single line only, which is
@@ -79,7 +153,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
79
153
int i ;
80
154
81
155
if (!want_color_stderr (use_sideband_colors ())) {
82
- strbuf_add (dest , src , n );
156
+ strbuf_add_sanitized (dest , src , n );
83
157
return ;
84
158
}
85
159
@@ -112,7 +186,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
112
186
}
113
187
}
114
188
115
- strbuf_add (dest , src , n );
189
+ strbuf_add_sanitized (dest , src , n );
116
190
}
117
191
118
192
0 commit comments