@@ -23,6 +23,12 @@ static struct keyword_entry keywords[] = {
2323 { "error" , GIT_COLOR_BOLD_RED },
2424};
2525
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+
2632/* Returns a color setting (GIT_COLOR_NEVER, etc). */
2733static int use_sideband_colors (void )
2834{
@@ -36,6 +42,25 @@ static int use_sideband_colors(void)
3642 if (use_sideband_colors_cached >= 0 )
3743 return use_sideband_colors_cached ;
3844
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+
3964 if (!git_config_get_string (key , & value )) {
4065 use_sideband_colors_cached = git_config_colorbool (key , value );
4166 } 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
6489 list_config_item (list , prefix , keywords [i ].keyword );
6590}
6691
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+
67141/*
68142 * Optionally highlight one keyword in remote output if it appears at the start
69143 * 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)
79153 int i ;
80154
81155 if (!want_color_stderr (use_sideband_colors ())) {
82- strbuf_add (dest , src , n );
156+ strbuf_add_sanitized (dest , src , n );
83157 return ;
84158 }
85159
@@ -112,7 +186,7 @@ static void maybe_colorize_sideband(struct strbuf *dest, const char *src, int n)
112186 }
113187 }
114188
115- strbuf_add (dest , src , n );
189+ strbuf_add_sanitized (dest , src , n );
116190}
117191
118192
0 commit comments