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