X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=diff.c;h=bc32a4aa29171af6ca268a54cde881934079de83;hb=42d504248830452275dbe1c864f0b1771d7b1a05;hp=e16e0bfc0a8999477f2c1d68a6b82cbc3867e8e5;hpb=440f869d6539a2c08e50ec4ac1375645247f57fd;p=git.git diff --git a/diff.c b/diff.c index e16e0bfc0..bc32a4aa2 100644 --- a/diff.c +++ b/diff.c @@ -25,6 +25,20 @@ int git_diff_config(const char *var, const char *value) return git_default_config(var, value); } +enum color_diff { + DIFF_PLAIN = 0, + DIFF_METAINFO = 1, + DIFF_FILE_OLD = 2, + DIFF_FILE_NEW = 3, +}; + +static const char *diff_colors[] = { + "\033[0;0m", + "\033[1;35m", + "\033[1;31m", + "\033[1;34m", +}; + static char *quote_one(const char *str) { int needlen; @@ -177,23 +191,54 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) } struct emit_callback { + struct xdiff_emit_state xm; + int nparents, color_diff; const char **label_path; }; -static int fn_out(void *priv, mmbuffer_t *mb, int nbuf) +static inline void color_diff(int diff_use_color, enum color_diff ix) +{ + if (diff_use_color) + fputs(diff_colors[ix], stdout); +} + +static void fn_out_consume(void *priv, char *line, unsigned long len) { int i; struct emit_callback *ecbdata = priv; if (ecbdata->label_path[0]) { + color_diff(ecbdata->color_diff, DIFF_METAINFO); printf("--- %s\n", ecbdata->label_path[0]); + color_diff(ecbdata->color_diff, DIFF_METAINFO); printf("+++ %s\n", ecbdata->label_path[1]); ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } - for (i = 0; i < nbuf; i++) - if (!fwrite(mb[i].ptr, mb[i].size, 1, stdout)) - return -1; - return 0; + + /* This is not really necessary for now because + * this codepath only deals with two-way diffs. + */ + for (i = 0; i < len && line[i] == '@'; i++) + ; + if (2 <= i && i < len && line[i] == ' ') { + ecbdata->nparents = i - 1; + color_diff(ecbdata->color_diff, DIFF_METAINFO); + } + else if (len < ecbdata->nparents) + color_diff(ecbdata->color_diff, DIFF_PLAIN); + else { + int nparents = ecbdata->nparents; + int color = DIFF_PLAIN; + for (i = 0; i < nparents && len; i++) { + if (line[i] == '-') + color = DIFF_FILE_OLD; + else if (line[i] == '+') + color = DIFF_FILE_NEW; + } + color_diff(ecbdata->color_diff, color); + } + fwrite(line, len, 1, stdout); + color_diff(ecbdata->color_diff, DIFF_PLAIN); } static char *pprint_rename(const char *a, const char *b) @@ -237,7 +282,7 @@ static char *pprint_rename(const char *a, const char *b) if (a_midlen < 0) a_midlen = 0; if (b_midlen < 0) b_midlen = 0; - name = xmalloc(len_a + len_b - pfx_length - sfx_length + 7); + name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7); sprintf(name, "%.*s{%.*s => %.*s}%s", pfx_length, a, a_midlen, a + pfx_length, @@ -299,6 +344,7 @@ static void diffstat_consume(void *priv, char *line, unsigned long len) static const char pluses[] = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"; static const char minuses[]= "----------------------------------------------------------------------"; +const char mime_boundary_leader[] = "------------"; static void show_stats(struct diffstat_t* data) { @@ -397,6 +443,46 @@ static void show_stats(struct diffstat_t* data) total_files, adds, dels); } +struct checkdiff_t { + struct xdiff_emit_state xm; + const char *filename; + int lineno; +}; + +static void checkdiff_consume(void *priv, char *line, unsigned long len) +{ + struct checkdiff_t *data = priv; + + if (line[0] == '+') { + int i, spaces = 0; + + data->lineno++; + + /* check space before tab */ + for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++) + if (line[i] == ' ') + spaces++; + if (line[i - 1] == '\t' && spaces) + printf("%s:%d: space before tab:%.*s\n", + data->filename, data->lineno, (int)len, line); + + /* check white space at line end */ + if (line[len - 1] == '\n') + len--; + if (isspace(line[len - 1])) + printf("%s:%d: white space at end: %.*s\n", + data->filename, data->lineno, (int)len, line); + } else if (line[0] == ' ') + data->lineno++; + else if (line[0] == '@') { + char *plus = strchr(line, '+'); + if (plus) + data->lineno = strtol(plus, NULL, 10); + else + die("invalid diff"); + } +} + static unsigned char *deflate_it(char *data, unsigned long size, unsigned long *result_size) @@ -508,25 +594,35 @@ static void builtin_diff(const char *name_a, b_two = quote_two("b/", name_b); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; + color_diff(o->color_diff, DIFF_METAINFO); printf("diff --git %s %s\n", a_one, b_two); if (lbl[0][0] == '/') { /* /dev/null */ + color_diff(o->color_diff, DIFF_METAINFO); printf("new file mode %06o\n", two->mode); - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } } else if (lbl[1][0] == '/') { printf("deleted file mode %06o\n", one->mode); - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } } else { if (one->mode != two->mode) { + color_diff(o->color_diff, DIFF_METAINFO); printf("old mode %06o\n", one->mode); + color_diff(o->color_diff, DIFF_METAINFO); printf("new mode %06o\n", two->mode); } - if (xfrm_msg && xfrm_msg[0]) + if (xfrm_msg && xfrm_msg[0]) { + color_diff(o->color_diff, DIFF_METAINFO); puts(xfrm_msg); + } /* * we do not run diff between different kind * of objects. @@ -534,6 +630,7 @@ static void builtin_diff(const char *name_a, if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; if (complete_rewrite) { + color_diff(o->color_diff, DIFF_PLAIN); emit_rewrite_diff(name_a, name_b, one, two); goto free_ab_and_return; } @@ -561,7 +658,9 @@ static void builtin_diff(const char *name_a, xdemitcb_t ecb; struct emit_callback ecbdata; + memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.label_path = lbl; + ecbdata.color_diff = o->color_diff; xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = o->context; xecfg.flags = XDL_EMIT_FUNCNAMES; @@ -571,8 +670,9 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!strncmp(diffopts, "-u", 2)) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - ecb.outf = fn_out; + ecb.outf = xdiff_outf; ecb.priv = &ecbdata; + ecbdata.xm.consume = fn_out_consume; xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); } @@ -624,6 +724,41 @@ static void builtin_diffstat(const char *name_a, const char *name_b, } } +static void builtin_checkdiff(const char *name_a, const char *name_b, + struct diff_filespec *one, + struct diff_filespec *two) +{ + mmfile_t mf1, mf2; + struct checkdiff_t data; + + if (!two) + return; + + memset(&data, 0, sizeof(data)); + data.xm.consume = checkdiff_consume; + data.filename = name_b ? name_b : name_a; + data.lineno = 0; + + if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) + die("unable to read files to diff"); + + if (mmfile_is_binary(&mf2)) + return; + else { + /* Crazy xdl interfaces.. */ + xpparam_t xpp; + xdemitconf_t xecfg; + xdemitcb_t ecb; + + xpp.flags = XDF_NEED_MINIMAL; + xecfg.ctxlen = 0; + xecfg.flags = 0; + ecb.outf = xdiff_outf; + ecb.priv = &data; + xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + } +} + struct diff_filespec *alloc_filespec(const char *path) { int namelen = strlen(path); @@ -1180,6 +1315,25 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o, builtin_diffstat(name, other, p->one, p->two, diffstat, complete_rewrite); } +static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) +{ + const char *name; + const char *other; + + if (DIFF_PAIR_UNMERGED(p)) { + /* unmerged */ + return; + } + + name = p->one->path; + other = (strcmp(name, p->two->path) ? p->two->path : NULL); + + diff_fill_sha1_info(p->one); + diff_fill_sha1_info(p->two); + + builtin_checkdiff(name, other, p->one, p->two); +} + void diff_setup(struct diff_options *options) { memset(options, 0, sizeof(*options)); @@ -1205,9 +1359,18 @@ int diff_setup_done(struct diff_options *options) * recursive bits for other formats here. */ if ((options->output_format == DIFF_FORMAT_PATCH) || - (options->output_format == DIFF_FORMAT_DIFFSTAT)) + (options->output_format == DIFF_FORMAT_DIFFSTAT) || + (options->output_format == DIFF_FORMAT_CHECKDIFF)) options->recursive = 1; + /* + * These combinations do not make sense. + */ + if (options->output_format == DIFF_FORMAT_RAW) + options->with_raw = 0; + if (options->output_format == DIFF_FORMAT_DIFFSTAT) + options->with_stat = 0; + if (options->detect_rename && options->rename_limit < 0) options->rename_limit = diff_rename_limit_default; if (options->setup & DIFF_SETUP_USE_CACHE) { @@ -1288,6 +1451,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) } else if (!strcmp(arg, "--stat")) options->output_format = DIFF_FORMAT_DIFFSTAT; + else if (!strcmp(arg, "--check")) + options->output_format = DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) options->summary = 1; else if (!strcmp(arg, "--patch-with-stat")) { @@ -1350,6 +1515,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (40 < options->abbrev) options->abbrev = 40; } + else if (!strcmp(arg, "--color")) + options->color_diff = 1; else return 0; return 1; @@ -1610,6 +1777,19 @@ static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, run_diffstat(p, o, diffstat); } +static void diff_flush_checkdiff(struct diff_filepair *p, + struct diff_options *o) +{ + if (diff_unmodified_pair(p)) + return; + + if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) || + (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode))) + return; /* no tree diffs in patch format */ + + run_checkdiff(p, o); +} + int diff_queue_is_empty(void) { struct diff_queue_struct *q = &diff_queued_diff; @@ -1740,6 +1920,9 @@ static void flush_one_pair(struct diff_filepair *p, case DIFF_FORMAT_DIFFSTAT: diff_flush_stat(p, options, diffstat); break; + case DIFF_FORMAT_CHECKDIFF: + diff_flush_checkdiff(p, options); + break; case DIFF_FORMAT_PATCH: diff_flush_patch(p, options); break; @@ -1867,7 +2050,13 @@ void diff_flush(struct diff_options *options) show_stats(diffstat); free(diffstat); diffstat = NULL; - putchar(options->line_termination); + if (options->summary) + for (i = 0; i < q->nr; i++) + diff_summary(q->queue[i]); + if (options->stat_sep) + fputs(options->stat_sep, stdout); + else + putchar(options->line_termination); } for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; @@ -1880,7 +2069,7 @@ void diff_flush(struct diff_options *options) } for (i = 0; i < q->nr; i++) { - if (options->summary) + if (diffstat && options->summary) diff_summary(q->queue[i]); diff_free_filepair(q->queue[i]); }