Index: usr.bin/diff/diff.h =================================================================== --- usr.bin/diff/diff.h +++ usr.bin/diff/diff.h @@ -90,12 +90,13 @@ struct excludes *next; }; -extern int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag; +extern int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag, colorflag; extern int diff_format, diff_context, status, ignore_file_case; extern int suppress_common; extern int tabsize, width; extern char *start, *ifdefname, *diffargs, *label[2], *ignore_pats; extern char *group_format; +extern const char *add_code, *del_code; extern struct stat stb1, stb2; extern struct excludes *excludes_list; extern regex_t ignore_re; Index: usr.bin/diff/diff.1 =================================================================== --- usr.bin/diff/diff.1 +++ usr.bin/diff/diff.1 @@ -44,6 +44,7 @@ .Fl n | q | u | y .Oc .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -71,6 +72,7 @@ .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern .Op Fl L Ar label | Fl -label Ar label .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -96,6 +98,7 @@ .Op Fl aBbdiltw .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -122,6 +125,7 @@ .Op Fl I Ar pattern | Fl -ignore-matching-lines Ar pattern .Op Fl L Ar label | Fl -label Ar label .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -ed .Op Fl -expand-tabs @@ -150,6 +154,7 @@ .Fl n | q | u .Oc .Op Fl -brief +.Op Fl -color Ns = Ns Ar when .Op Fl -changed-group-format Ar GFMT .Op Fl -context .Op Fl -ed @@ -184,6 +189,7 @@ .Ar dir1 dir2 .Nm diff .Op Fl aBbditwW +.Op Fl -color Ns = Ns Ar when .Op Fl -expand-tabs .Op Fl -ignore-all-blanks .Op Fl -ignore-blank-lines @@ -332,6 +338,17 @@ .It Fl b -ignore-space-change Causes trailing blanks (spaces and tabs) to be ignored, and other strings of blanks to compare equal. +.It Fl Fl color= Ns Oo Ar when Oc +Mark up the matching text with the expression stored in the +.Ev DIFFCOLOR +environment variable. +The possible values of +.Ar when +are +.Dq Cm never , +.Dq Cm always +and +.Dq Cm auto . .It Fl d -minimal Try very hard to produce a diff as small as possible. This may consume a lot of processing power and memory when processing Index: usr.bin/diff/diff.c =================================================================== --- usr.bin/diff/diff.c +++ usr.bin/diff/diff.c @@ -38,11 +38,12 @@ #include "diff.h" #include "xmalloc.h" -int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag; +int lflag, Nflag, Pflag, rflag, sflag, Tflag, cflag, Wflag, colorflag = 0; int diff_format, diff_context, status, ignore_file_case, suppress_common; int tabsize = 8, width = 130; char *start, *ifdefname, *diffargs, *label[2], *ignore_pats; char *group_format = NULL; +const char *add_code, *del_code; struct stat stb1, stb2; struct excludes *excludes_list; regex_t ignore_re; @@ -57,6 +58,7 @@ OPT_HORIZON_LINES, OPT_CHANGED_GROUP_FORMAT, OPT_SUPPRESS_COMMON, + OPT_COLOR, }; static struct option longopts[] = { @@ -97,6 +99,7 @@ { "tabsize", required_argument, NULL, OPT_TSIZE }, { "changed-group-format", required_argument, NULL, OPT_CHANGED_GROUP_FORMAT}, { "suppress-common-lines", no_argument, NULL, OPT_SUPPRESS_COMMON }, + { "color", optional_argument, NULL, OPT_COLOR }, { NULL, 0, 0, '\0'} }; @@ -106,6 +109,7 @@ void push_ignore_pats(char *); void read_excludes_file(char *file); void set_argstr(char **, char **); +static const char *init_code(int, const char *); int main(int argc, char **argv) @@ -301,6 +305,21 @@ case OPT_SUPPRESS_COMMON: suppress_common = 1; break; + case OPT_COLOR: + if (optarg == NULL || strncmp(optarg, "auto", 4) == 0) + colorflag = isatty(STDOUT_FILENO) ? 1 : 0; + else if (strncmp(optarg, "always", 6) == 0) + colorflag = 1; + else if (strncmp(optarg, "never", 5) == 0) + colorflag = 0; + else + errx(2, "unsupported --color value '%s' (must be always, auto, or never)", + optarg); + if (colorflag) { + add_code = init_code(1, "32"); + del_code = init_code(2, "31"); + } + break; default: usage(); break; @@ -550,3 +569,21 @@ fprintf(stderr, "error: conflicting output format options.\n"); usage(); } + +static const char * +init_code(int i, const char *rv) +{ + char *buf, *p, *env; + int j; + + env = getenv("DIFFCOLORS"); + if (env != NULL && *env != '\0') { + p = strdup(env); + for (j = 0; j < i; j++) + buf = strsep(&p, ":"); + free(p); + if (buf != NULL) + return buf; + } + return rv; +} Index: usr.bin/diff/diffreg.c =================================================================== --- usr.bin/diff/diffreg.c +++ usr.bin/diff/diffreg.c @@ -1183,13 +1183,23 @@ } } if (diff_format == D_SIDEBYSIDE) { + if (colorflag && (a>b)) + printf("\033[%sm", add_code); + else if (colorflag && (c>d)) + printf("\033[%sm", del_code); if (a > b) { print_space(0, hw + padding , *pflags); } else { nc = fetch(ixold, a, b, f1, '\0', 1, *pflags); print_space(nc, hw - nc + padding, *pflags); } + if (colorflag && (a>b)) + printf("\033[%sm", add_code); + else if (colorflag && (c>d)) + printf("\033[%sm", del_code); printf("%c", (a>b)? '>' : ((c>d)? '<' : '|')); + if (colorflag && (c>d)) + printf("\33[m"); print_space(hw + padding + 1 , padding, *pflags); fetch(ixnew, c, d, f2, '\0', 0, *pflags); printf("\n"); @@ -1263,6 +1273,10 @@ nc = hw; if ((diff_format != D_IFDEF && diff_format != D_GFORMAT) && ch != '\0') { + if (colorflag && (ch == '>' || ch == '+')) + printf("\033[%sm", add_code); + else if (colorflag && (ch == '<' || ch == '-')) + printf("\033[%sm", del_code); printf("%c", ch); if (Tflag && (diff_format == D_NORMAL || diff_format == D_CONTEXT || @@ -1335,6 +1349,8 @@ } } } + if (colorflag) + printf("\33[m"); return col; }