5858#define PATCH "patch"
5959#endif
6060
61+ /* ANSI color codes for diff output */
62+ #define COLOR_RESET "\033[0m"
63+ #define COLOR_HEADER "\033[1m" /* Bold for headers */
64+ #define COLOR_FILE "\033[1m" /* Bold for filenames */
65+ #define COLOR_HUNK "\033[36m" /* Cyan for hunk headers */
66+ #define COLOR_ADDED "\033[32m" /* Green for added lines */
67+ #define COLOR_REMOVED "\033[31m" /* Red for removed lines */
68+ #define COLOR_CONTEXT "" /* No color for context lines */
69+
70+ /* Line type for coloring */
71+ enum line_type {
72+ LINE_CONTEXT ,
73+ LINE_ADDED ,
74+ LINE_REMOVED ,
75+ LINE_HEADER ,
76+ LINE_FILE ,
77+ LINE_HUNK
78+ };
79+
6180/* This can be invoked as interdiff, combinediff, or flipdiff. */
6281static enum {
6382 mode_inter ,
@@ -98,11 +117,62 @@ static int ignore_components = 0;
98117static int ignore_components_specified = 0 ;
99118static int unzip = 0 ;
100119static int no_revert_omitted = 0 ;
120+ static int use_colors = 0 ;
121+ static int color_option_specified = 0 ;
101122static int debug = 0 ;
102123
103124static struct patlist * pat_drop_context = NULL ;
104125
105126static struct file_list * files_done = NULL ;
127+
128+ /*
129+ * Colorize a line based on its type and whether colors are enabled.
130+ * Returns a newly allocated string that must be freed by the caller.
131+ * Only colorizes when outputting to a terminal (stdout is a TTY).
132+ */
133+ static char *
134+ colorize_line (const char * line , enum line_type type , FILE * output_file )
135+ {
136+ const char * color_start = "" ;
137+ const char * color_end = "" ;
138+ char * result ;
139+
140+ /* Only colorize if colors are enabled AND we're outputting to stdout */
141+ if (!use_colors || output_file != stdout ) {
142+ return xstrdup (line );
143+ }
144+
145+ switch (type ) {
146+ case LINE_CONTEXT :
147+ color_start = COLOR_CONTEXT ;
148+ break ;
149+ case LINE_ADDED :
150+ color_start = COLOR_ADDED ;
151+ break ;
152+ case LINE_REMOVED :
153+ color_start = COLOR_REMOVED ;
154+ break ;
155+ case LINE_HEADER :
156+ color_start = COLOR_HEADER ;
157+ break ;
158+ case LINE_FILE :
159+ color_start = COLOR_FILE ;
160+ break ;
161+ case LINE_HUNK :
162+ color_start = COLOR_HUNK ;
163+ break ;
164+ }
165+
166+ if (color_start [0 ] != '\0' ) {
167+ color_end = COLOR_RESET ;
168+ }
169+
170+ if (asprintf (& result , "%s%s%s" , color_start , line , color_end ) < 0 ) {
171+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
172+ }
173+
174+ return result ;
175+ }
106176static struct file_list * files_in_patch2 = NULL ;
107177static struct file_list * files_in_patch1 = NULL ;
108178
@@ -982,7 +1052,9 @@ trim_context (FILE *f /* positioned at start of @@ line */,
9821052
9831053 if (line [0 ] == '\\' ) {
9841054 /* Pass '\' lines through unaltered. */
985- fputs (line , out );
1055+ char * colored_line = colorize_line (line , LINE_CONTEXT , out );
1056+ fputs (colored_line , out );
1057+ free (colored_line );
9861058 continue ;
9871059 }
9881060
@@ -1050,13 +1122,35 @@ trim_context (FILE *f /* positioned at start of @@ line */,
10501122 printf ("Trim: %lu,%lu\n" , strip_pre , strip_post );
10511123
10521124 fsetpos (f , & pos );
1053- fprintf (out , "@@ -%lu" , orig_offset );
1054- if (new_orig_count != 1 )
1055- fprintf (out , ",%lu" , new_orig_count );
1056- fprintf (out , " +%lu" , new_offset );
1057- if (new_new_count != 1 )
1058- fprintf (out , ",%lu" , new_new_count );
1059- fprintf (out , " @@\n" );
1125+ {
1126+ char * hunk_header ;
1127+ char * colored_hunk ;
1128+ if (new_orig_count != 1 && new_new_count != 1 ) {
1129+ if (asprintf (& hunk_header , "@@ -%lu,%lu +%lu,%lu @@\n" ,
1130+ orig_offset , new_orig_count , new_offset , new_new_count ) < 0 ) {
1131+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
1132+ }
1133+ } else if (new_orig_count != 1 ) {
1134+ if (asprintf (& hunk_header , "@@ -%lu,%lu +%lu @@\n" ,
1135+ orig_offset , new_orig_count , new_offset ) < 0 ) {
1136+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
1137+ }
1138+ } else if (new_new_count != 1 ) {
1139+ if (asprintf (& hunk_header , "@@ -%lu +%lu,%lu @@\n" ,
1140+ orig_offset , new_offset , new_new_count ) < 0 ) {
1141+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
1142+ }
1143+ } else {
1144+ if (asprintf (& hunk_header , "@@ -%lu +%lu @@\n" ,
1145+ orig_offset , new_offset ) < 0 ) {
1146+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
1147+ }
1148+ }
1149+ colored_hunk = colorize_line (hunk_header , LINE_HUNK , out );
1150+ fputs (colored_hunk , out );
1151+ free (hunk_header );
1152+ free (colored_hunk );
1153+ }
10601154
10611155 while (total_count -- ) {
10621156 ssize_t got = getline (& line , & linelen , f );
@@ -1070,7 +1164,25 @@ trim_context (FILE *f /* positioned at start of @@ line */,
10701164 if (total_count < strip_post )
10711165 continue ;
10721166
1073- fwrite (line , (size_t ) got , 1 , out );
1167+ {
1168+ enum line_type type ;
1169+ switch (line [0 ]) {
1170+ case '+' :
1171+ type = LINE_ADDED ;
1172+ break ;
1173+ case '-' :
1174+ type = LINE_REMOVED ;
1175+ break ;
1176+ case ' ' :
1177+ case '\n' :
1178+ default :
1179+ type = LINE_CONTEXT ;
1180+ break ;
1181+ }
1182+ char * colored_line = colorize_line (line , type , out );
1183+ fputs (colored_line , out );
1184+ free (colored_line );
1185+ }
10741186 }
10751187 }
10761188
@@ -1253,6 +1365,7 @@ output_delta (FILE *p1, FILE *p2, FILE *out)
12531365 /* First character */
12541366 if (human_readable ) {
12551367 char * p , * q , c , d ;
1368+ char * header_line ;
12561369 c = d = '\0' ; /* shut gcc up */
12571370 p = strchr (oldname + 4 , '\t' );
12581371 if (p ) {
@@ -1264,13 +1377,35 @@ output_delta (FILE *p1, FILE *p2, FILE *out)
12641377 d = * q ;
12651378 * q = '\0' ;
12661379 }
1267- fprintf (out , DIFF " %s %s %s\n" , options , oldname + 4 ,
1268- newname + 4 );
1380+ if (asprintf (& header_line , DIFF " %s %s %s\n" , options , oldname + 4 ,
1381+ newname + 4 ) < 0 ) {
1382+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
1383+ }
1384+ char * colored_header = colorize_line (header_line , LINE_HEADER , out );
1385+ fputs (colored_header , out );
1386+ free (header_line );
1387+ free (colored_header );
12691388 if (p ) * p = c ;
12701389 if (q ) * q = d ;
12711390 }
1272- fprintf (out , "--- %s\n" , oldname + 4 );
1273- fprintf (out , "+++ %s\n" , newname + 4 );
1391+ {
1392+ char * old_line , * new_line ;
1393+ char * colored_old , * colored_new ;
1394+ if (asprintf (& old_line , "--- %s\n" , oldname + 4 ) < 0 ) {
1395+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
1396+ }
1397+ if (asprintf (& new_line , "+++ %s\n" , newname + 4 ) < 0 ) {
1398+ error (EXIT_FAILURE , errno , "Memory allocation failed" );
1399+ }
1400+ colored_old = colorize_line (old_line , LINE_FILE , out );
1401+ colored_new = colorize_line (new_line , LINE_FILE , out );
1402+ fputs (colored_old , out );
1403+ fputs (colored_new , out );
1404+ free (old_line );
1405+ free (new_line );
1406+ free (colored_old );
1407+ free (colored_new );
1408+ }
12741409 rewind (tmpdiff );
12751410 trim_context (tmpdiff , file .unline , out );
12761411 fclose (tmpdiff );
@@ -2284,8 +2419,9 @@ main (int argc, char *argv[])
22842419 color_mode = isatty (STDOUT_FILENO ) ? "always" : "never" ;
22852420 }
22862421
2287- if (asprintf (diff_opts + num_diff_opts ++ , "--color=%s" , color_mode ) < 0 )
2288- error (EXIT_FAILURE , errno , "Memory allocation failed" );
2422+ /* Set our internal color flag instead of passing to diff */
2423+ use_colors = (strcmp (color_mode , "always" ) == 0 );
2424+ color_option_specified = 1 ;
22892425 break ;
22902426 }
22912427 case 1000 + 'I' :
@@ -2317,17 +2453,9 @@ main (int argc, char *argv[])
23172453 error (EXIT_FAILURE , 0 ,
23182454 "-z and --in-place are mutually exclusive." );
23192455
2320- /* Add default color=always if no color option was specified and we're in a terminal */
2321- int has_color_option = 0 ;
2322- for (int i = 0 ; i < num_diff_opts ; i ++ ) {
2323- if (strncmp (diff_opts [i ], "--color" , 7 ) == 0 ) {
2324- has_color_option = 1 ;
2325- break ;
2326- }
2327- }
2328- if (!has_color_option && isatty (STDOUT_FILENO )) {
2329- if (asprintf (diff_opts + num_diff_opts ++ , "--color=always" ) < 0 )
2330- error (EXIT_FAILURE , errno , "Memory allocation failed" );
2456+ /* Set default color behavior if no color option was specified */
2457+ if (!color_option_specified && isatty (STDOUT_FILENO )) {
2458+ use_colors = 1 ;
23312459 }
23322460
23332461 if (optind + 2 != argc )
0 commit comments