From c99db9d292c5f63c83ae2b441a67121d76553413 Mon Sep 17 00:00:00 2001 From: Brian Downing Date: Thu, 14 Aug 2008 00:36:50 -0500 Subject: Make xdi_diff_outf interface for running xdiff_outf diffs To prepare for the need to initialize and release resources for an xdi_diff with the xdiff_outf output function, make a new function to wrap this usage. Old: ecb.outf = xdiff_outf; ecb.priv = &state; ... xdi_diff(file_p, file_o, &xpp, &xecfg, &ecb); New: xdi_diff_outf(file_p, file_o, &state.xm, &xpp, &xecfg, &ecb); Signed-off-by: Brian Downing Signed-off-by: Junio C Hamano --- diff.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index bf5d5f15a3..913a92f3e9 100644 --- a/diff.c +++ b/diff.c @@ -459,10 +459,8 @@ static void diff_words_show(struct diff_words_data *diff_words) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; - ecb.outf = xdiff_outf; - ecb.priv = diff_words; diff_words->xm.consume = fn_out_diff_words_aux; - xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); + xdi_diff_outf(&minus, &plus, &diff_words->xm, &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); @@ -1521,15 +1519,13 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!prefixcmp(diffopts, "-u")) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - ecb.outf = xdiff_outf; - ecb.priv = &ecbdata; ecbdata.xm.consume = fn_out_consume; if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) { ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); ecbdata.diff_words->file = o->file; } - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, &ecbdata.xm, &xpp, &xecfg, &ecb); if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) free_diff_words_data(&ecbdata); } @@ -1580,9 +1576,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b, memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; - ecb.outf = xdiff_outf; - ecb.priv = diffstat; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, &diffstat->xm, &xpp, &xecfg, &ecb); } free_and_return: @@ -1628,9 +1622,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL; - ecb.outf = xdiff_outf; - ecb.priv = &data; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, &data.xm, &xpp, &xecfg, &ecb); if ((data.ws_rule & WS_TRAILING_SPACE) && data.trailing_blanks_start) { @@ -3128,9 +3120,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = 3; xecfg.flags = XDL_EMIT_FUNCNAMES; - ecb.outf = xdiff_outf; - ecb.priv = &data; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, &data.xm, &xpp, &xecfg, &ecb); } SHA1_Final(sha1, &ctx); -- cgit v1.3 From 8a3f524bf2ac534b313a7d8e70cc164cef744949 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Aug 2008 23:18:22 -0700 Subject: xdiff-interface: hide the whole "xdiff_emit_state" business from the caller This further enhances xdi_diff_outf() interface so that it takes two common parameters: the callback function that processes one line at a time, and a pointer to its application specific callback data structure. xdi_diff_outf() creates its own "xdiff_emit_state" structure and stashes these two away inside it, which is used by the lowest level output function in the xdiff_outf() callchain, consume_one(), to call back to the application layer. With this restructuring, we lift the requirement that the caller supplied callback data structure embeds xdiff_emit_state structure as its first member. Signed-off-by: Junio C Hamano --- builtin-blame.c | 4 +--- combine-diff.c | 7 ++----- diff.c | 27 ++++++++++----------------- xdiff-interface.c | 23 ++++++++++++++++++----- xdiff-interface.h | 11 ++--------- 5 files changed, 33 insertions(+), 39 deletions(-) (limited to 'diff.c') diff --git a/builtin-blame.c b/builtin-blame.c index 8cca3b16d2..e4d12de8a9 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -465,7 +465,6 @@ struct patch { }; struct blame_diff_state { - struct xdiff_emit_state xm; struct patch *ret; unsigned hunk_post_context; unsigned hunk_in_pre_context : 1; @@ -529,12 +528,11 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o, memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = context; memset(&state, 0, sizeof(state)); - state.xm.consume = process_u_diff; state.ret = xmalloc(sizeof(struct patch)); state.ret->chunks = NULL; state.ret->num = 0; - xdi_diff_outf(file_p, file_o, &state.xm, &xpp, &xecfg, &ecb); + xdi_diff_outf(file_p, file_o, process_u_diff, &state, &xpp, &xecfg, &ecb); if (state.ret->num) { struct chunk *chunk; diff --git a/combine-diff.c b/combine-diff.c index 72dd6d2234..31ec0c5165 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -143,8 +143,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len) } struct combine_diff_state { - struct xdiff_emit_state xm; - unsigned int lno; int ob, on, nb, nn; unsigned long nmask; @@ -218,15 +216,14 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file, xpp.flags = XDF_NEED_MINIMAL; memset(&xecfg, 0, sizeof(xecfg)); memset(&state, 0, sizeof(state)); - state.xm.consume = consume_line; state.nmask = nmask; state.sline = sline; state.lno = 1; state.num_parent = num_parent; state.n = n; - xdi_diff_outf(&parent_file, result_file, - &state.xm, &xpp, &xecfg, &ecb); + xdi_diff_outf(&parent_file, result_file, consume_line, &state, + &xpp, &xecfg, &ecb); free(parent_file.ptr); /* Assign line numbers for this parent. diff --git a/diff.c b/diff.c index 913a92f3e9..a6c143251c 100644 --- a/diff.c +++ b/diff.c @@ -369,7 +369,6 @@ static void diff_words_append(char *line, unsigned long len, } struct diff_words_data { - struct xdiff_emit_state xm; struct diff_words_buffer minus, plus; FILE *file; }; @@ -459,9 +458,8 @@ static void diff_words_show(struct diff_words_data *diff_words) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; - diff_words->xm.consume = fn_out_diff_words_aux; - xdi_diff_outf(&minus, &plus, &diff_words->xm, &xpp, &xecfg, &ecb); - + xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, + &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); diff_words->minus.text.size = diff_words->plus.text.size = 0; @@ -475,7 +473,6 @@ static void diff_words_show(struct diff_words_data *diff_words) typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); struct emit_callback { - struct xdiff_emit_state xm; int nparents, color_diff; unsigned ws_rule; sane_truncate_fn truncate; @@ -706,8 +703,6 @@ static char *pprint_rename(const char *a, const char *b) } struct diffstat_t { - struct xdiff_emit_state xm; - int nr; int alloc; struct diffstat_file { @@ -1129,7 +1124,6 @@ static void free_diffstat_info(struct diffstat_t *diffstat) } struct checkdiff_t { - struct xdiff_emit_state xm; const char *filename; int lineno; struct diff_options *o; @@ -1519,13 +1513,13 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!prefixcmp(diffopts, "-u")) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - ecbdata.xm.consume = fn_out_consume; if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) { ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); ecbdata.diff_words->file = o->file; } - xdi_diff_outf(&mf1, &mf2, &ecbdata.xm, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, + &xpp, &xecfg, &ecb); if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) free_diff_words_data(&ecbdata); } @@ -1576,7 +1570,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b, memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; - xdi_diff_outf(&mf1, &mf2, &diffstat->xm, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, + &xpp, &xecfg, &ecb); } free_and_return: @@ -1597,7 +1592,6 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, return; memset(&data, 0, sizeof(data)); - data.xm.consume = checkdiff_consume; data.filename = name_b ? name_b : name_a; data.lineno = 0; data.o = o; @@ -1622,7 +1616,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL; - xdi_diff_outf(&mf1, &mf2, &data.xm, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, + &xpp, &xecfg, &ecb); if ((data.ws_rule & WS_TRAILING_SPACE) && data.trailing_blanks_start) { @@ -3010,7 +3005,6 @@ static void diff_summary(FILE *file, struct diff_filepair *p) } struct patch_id_t { - struct xdiff_emit_state xm; SHA_CTX *ctx; int patchlen; }; @@ -3055,7 +3049,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) SHA1_Init(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); data.ctx = &ctx; - data.xm.consume = patch_id_consume; for (i = 0; i < q->nr; i++) { xpparam_t xpp; @@ -3120,7 +3113,8 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = 3; xecfg.flags = XDL_EMIT_FUNCNAMES; - xdi_diff_outf(&mf1, &mf2, &data.xm, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, + &xpp, &xecfg, &ecb); } SHA1_Final(sha1, &ctx); @@ -3197,7 +3191,6 @@ void diff_flush(struct diff_options *options) struct diffstat_t diffstat; memset(&diffstat, 0, sizeof(struct diffstat_t)); - diffstat.xm.consume = diffstat_consume; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; if (check_pair_status(p)) diff --git a/xdiff-interface.c b/xdiff-interface.c index bf98866c4f..944ad9887f 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -1,5 +1,12 @@ #include "cache.h" #include "xdiff-interface.h" +#include "strbuf.h" + +struct xdiff_emit_state { + xdiff_emit_consume_fn consume; + void *consume_callback_data; + struct strbuf remainder; +}; static int parse_num(char **cp_p, int *num_p) { @@ -55,7 +62,7 @@ static void consume_one(void *priv_, char *s, unsigned long size) unsigned long this_size; ep = memchr(s, '\n', size); this_size = (ep == NULL) ? size : (ep - s + 1); - priv->consume(priv, s, this_size); + priv->consume(priv->consume_callback_data, s, this_size); size -= this_size; s += this_size; } @@ -128,15 +135,21 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co } int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2, - struct xdiff_emit_state *state, xpparam_t const *xpp, + xdiff_emit_consume_fn fn, void *consume_callback_data, + xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *xecb) { int ret; + struct xdiff_emit_state state; + + memset(&state, 0, sizeof(state)); + state.consume = fn; + state.consume_callback_data = consume_callback_data; xecb->outf = xdiff_outf; - xecb->priv = state; - strbuf_init(&state->remainder, 0); + xecb->priv = &state; + strbuf_init(&state.remainder, 0); ret = xdi_diff(mf1, mf2, xpp, xecfg, xecb); - strbuf_release(&state->remainder); + strbuf_release(&state.remainder); return ret; } diff --git a/xdiff-interface.h b/xdiff-interface.h index f6a1ec2220..558492ba38 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -2,20 +2,13 @@ #define XDIFF_INTERFACE_H #include "xdiff/xdiff.h" -#include "strbuf.h" - -struct xdiff_emit_state; typedef void (*xdiff_emit_consume_fn)(void *, char *, unsigned long); -struct xdiff_emit_state { - xdiff_emit_consume_fn consume; - struct strbuf remainder; -}; - int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2, - struct xdiff_emit_state *state, xpparam_t const *xpp, + xdiff_emit_consume_fn fn, void *consume_callback_data, + xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *xecb); int parse_hunk_header(char *line, int len, int *ob, int *on, -- cgit v1.3 From a624eaa7820f4f9814e41e911c665a0aba2fce34 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Fri, 15 Aug 2008 13:39:26 +0200 Subject: add boolean diff.suppress-blank-empty config option GNU diff's --suppress-blank-empty option makes it so that diff no longer outputs trailing white space unless the input data has it. With this option, empty context lines are now empty also in diff -u output. Before, they would have a single trailing space. * diff.c (diff_suppress_blank_empty): New global. (git_diff_basic_config): Set it. (fn_out_consume): Honor it. * t/t4029-diff-trailing-space.sh: New file. * Documentation/config.txt: Document it. Signed-off-by: Jim Meyering Signed-off-by: Junio C Hamano --- Documentation/config.txt | 4 ++++ diff.c | 13 +++++++++++++ t/t4029-diff-trailing-space.sh | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100755 t/t4029-diff-trailing-space.sh (limited to 'diff.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index 676c39bb84..9020675866 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -567,6 +567,10 @@ diff.autorefreshindex:: affects only 'git-diff' Porcelain, and not lower level 'diff' commands, such as 'git-diff-files'. +diff.suppress-blank-empty:: + A boolean to inhibit the standard behavior of printing a space + before each empty output line. Defaults to false. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the diff --git a/diff.c b/diff.c index bf5d5f15a3..fe43407b78 100644 --- a/diff.c +++ b/diff.c @@ -20,6 +20,7 @@ static int diff_detect_rename_default; static int diff_rename_limit_default = 200; +static int diff_suppress_blank_empty; int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; @@ -176,6 +177,12 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } + /* like GNU diff's --suppress-blank-empty option */ + if (!strcmp(var, "diff.suppress-blank-empty")) { + diff_suppress_blank_empty = git_config_bool(var, value); + return 0; + } + if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); if (ep != var + 4) { @@ -580,6 +587,12 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } + if (diff_suppress_blank_empty + && len == 2 && line[0] == ' ' && line[1] == '\n') { + line[0] = '\n'; + len = 1; + } + /* This is not really necessary for now because * this codepath only deals with two-way diffs. */ diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh new file mode 100755 index 0000000000..4ca65e0332 --- /dev/null +++ b/t/t4029-diff-trailing-space.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Copyright (c) Jim Meyering +# +test_description='diff honors config option, diff.suppress-blank-empty' + +. ./test-lib.sh + +cat <<\EOF > exp || +diff --git a/f b/f +index 5f6a263..8cb8bae 100644 +--- a/f ++++ b/f +@@ -1,2 +1,2 @@ + +-x ++y +EOF +exit 1 + +test_expect_success \ + "$test_description" \ + 'printf "\nx\n" > f && + git add f && + git commit -q -m. f && + printf "\ny\n" > f && + git config --bool diff.suppress-blank-empty true && + git diff f > actual && + test_cmp exp actual && + perl -i.bak -p -e "s/^\$/ /" exp && + git config --bool diff.suppress-blank-empty false && + git diff f > actual && + test_cmp exp actual && + git config --bool --unset diff.suppress-blank-empty && + git diff f > actual && + test_cmp exp actual + ' + +test_done -- cgit v1.3 From c35539eb10b0ab2a180e523f03ff65dc061bd47e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 20 Aug 2008 11:47:55 -0700 Subject: diff --check: do not get confused by new blank lines in the middle The code remembered that the last diff output it saw was an empty line, and tried to reset that state whenever it sees a context line, a non-blank new line, or a new hunk. However, this codepath asks the underlying diff engine to feed diff without any context, and the "just saw an empty line" state was not reset if you added a new blank line in the last hunk of your patch, even if it is not the last line of the file. Signed-off-by: Junio C Hamano --- diff.c | 1 + t/t4015-diff-whitespace.sh | 11 +++++++++++ 2 files changed, 12 insertions(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index bf5d5f15a3..f70e6b4912 100644 --- a/diff.c +++ b/diff.c @@ -1627,6 +1627,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, xdemitcb_t ecb; memset(&xecfg, 0, sizeof(xecfg)); + xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = XDF_NEED_MINIMAL; ecb.outf = xdiff_outf; ecb.priv = &data; diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index a27fccc8dc..ec98509fd2 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -341,4 +341,15 @@ test_expect_success 'checkdiff detects trailing blank lines' ' git diff --check | grep "ends with blank" ' +test_expect_success 'checkdiff allows new blank lines' ' + git checkout x && + mv x y && + ( + echo "/* This is new */" && + echo "" && + cat y + ) >x && + git diff --check +' + test_done -- cgit v1.3 From 7c17205b64a0e668d8a6e59109043bd4f2af3a0c Mon Sep 17 00:00:00 2001 From: Kirill Smelkov Date: Wed, 20 Aug 2008 19:57:07 +0400 Subject: Teach "git diff -p" Python funcname patterns Find classes, functions, and methods definitions. Signed-off-by: Kirill Smelkov Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 2 ++ diff.c | 1 + 2 files changed, 3 insertions(+) (limited to 'diff.c') diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index db16b0ca5b..9279df5349 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -316,6 +316,8 @@ patterns are available: - `pascal` suitable for source code in the Pascal/Delphi language. +- `python` suitable for source code in the Python language. + - `ruby` suitable for source code in the Ruby language. - `tex` suitable for source code for LaTeX documents. diff --git a/diff.c b/diff.c index 5923fe281b..2215416441 100644 --- a/diff.c +++ b/diff.c @@ -1394,6 +1394,7 @@ static struct builtin_funcname_pattern { }, { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, + { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" }, { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, }; -- cgit v1.3 From 1a1fcf4abeb2ed4ef6075970788711cf62405158 Mon Sep 17 00:00:00 2001 From: Johan Herland Date: Wed, 20 Aug 2008 19:49:15 +0200 Subject: Teach "git diff -p" HTML funcname patterns Find lines with

..

tags. [jc: while at it, reordered entries to sort alphabetically.] Signed-off-by: Johan Herland Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 2 ++ diff.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'diff.c') diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 9279df5349..5495d695c6 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -322,6 +322,8 @@ patterns are available: - `tex` suitable for source code for LaTeX documents. +- `html` suitable for HTML/XHTML documents. + Performing a three-way merge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/diff.c b/diff.c index 2215416441..18fa7a712c 100644 --- a/diff.c +++ b/diff.c @@ -1381,6 +1381,8 @@ static struct builtin_funcname_pattern { const char *name; const char *pattern; } builtin_funcname_pattern[] = { + { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, + { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" }, { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|" "new\\|return\\|switch\\|throw\\|while\\)\n" "^[ ]*\\(\\([ ]*" @@ -1392,10 +1394,9 @@ static struct builtin_funcname_pattern { "\\|" "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$" }, - { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, - { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" }, { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, + { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, }; static const char *diff_funcname_pattern(struct diff_filespec *one) -- cgit v1.3 From 441bca0bbc6d80a78ce332ef4fa6225155dfbce6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 28 Aug 2008 16:19:08 -0700 Subject: Fix '--dirstat' with cross-directory renaming The dirstat code depends on the fact that we always generate diffs with the names sorted, since it then just does a single-pass walk-over of the sorted list of names and how many changes there were. The sorting means that all files are nicely grouped by directory. That all works fine. Except when we have rename detection, and suddenly the nicely sorted list of pathnames isn't all that sorted at all. And now the single-pass dirstat walk gets all confused, and you can get results like this: [torvalds@nehalem linux]$ git diff --dirstat=2 -M v2.6.27-rc4..v2.6.27-rc5 3.0% arch/powerpc/configs/ 6.8% arch/arm/configs/ 2.7% arch/powerpc/configs/ 4.2% arch/arm/configs/ 5.6% arch/powerpc/configs/ 8.4% arch/arm/configs/ 5.5% arch/powerpc/configs/ 23.3% arch/arm/configs/ 8.6% arch/powerpc/configs/ 4.0% arch/ 4.4% drivers/usb/musb/ 4.0% drivers/watchdog/ 7.6% drivers/ 3.5% fs/ The trivial fix is to add a sorting pass, fixing it to: [torvalds@nehalem linux]$ git diff --dirstat=2 -M v2.6.27-rc4..v2.6.27-rc5 43.0% arch/arm/configs/ 25.5% arch/powerpc/configs/ 5.3% arch/ 4.4% drivers/usb/musb/ 4.0% drivers/watchdog/ 7.6% drivers/ 3.5% fs/ Spot the difference. In case anybody wonders: it's because of a ton of renames from {include/asm-blackfin => arch/blackfin/include/asm} that just totally messed up the file ordering in between arch/arm and arch/powerpc. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- diff.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index f70e6b4912..7b4300a74a 100644 --- a/diff.c +++ b/diff.c @@ -1054,6 +1054,13 @@ static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long ch return this_dir; } +static int dirstat_compare(const void *_a, const void *_b) +{ + const struct dirstat_file *a = _a; + const struct dirstat_file *b = _b; + return strcmp(a->name, b->name); +} + static void show_dirstat(struct diff_options *options) { int i; @@ -1113,6 +1120,7 @@ static void show_dirstat(struct diff_options *options) return; /* Show all directories with more than x% of the changes */ + qsort(dir.files, dir.nr, sizeof(dir.files[0]), dirstat_compare); gather_dirstat(options->file, &dir, changed, "", 0); } -- cgit v1.3 From 392809702016cde59d50a7b07e8c27f6d0ec3c3f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 27 Aug 2008 19:48:01 -0700 Subject: diff: Help "less" hide ^M from the output When the tracked contents have CRLF line endings, colored diff output shows "^M" at the end of output lines, which is distracting, even though the pager we use by default ("less") knows to hide them. The problem is that "less" hides a carriage-return only at the end of the line, immediately before a line feed. The colored diff output does not take this into account, and emits four element sequence for each line: - force this color; - the line up to but not including the terminating line feed; - reset color - line feed. By including the carriage return at the end of the line in the second item, we are breaking the smart our pager has in order not to show "^M". This can be fixed by changing the sequence to: - force this color; - the line up to but not including the terminating end-of-line; - reset color - end-of-line. where end-of-line is either a single linefeed or a CRLF pair. When the output is not colored, "force this color" and "reset color" sequences are both empty, so we won't have this problem with or without this patch. Signed-off-by: Junio C Hamano --- combine-diff.c | 16 ++++++++++++++-- diff.c | 9 ++++++++- t/t4019-diff-wserror.sh | 12 ++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) (limited to 'diff.c') diff --git a/combine-diff.c b/combine-diff.c index 4dfc330867..aa9d79ea0b 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -500,6 +500,18 @@ static int hunk_comment_line(const char *bol) return (isalpha(ch) || ch == '_' || ch == '$'); } +static void show_line_to_eol(const char *line, int len, const char *reset) +{ + int saw_cr_at_eol = 0; + if (len < 0) + len = strlen(line); + saw_cr_at_eol = (len && line[len-1] == '\r'); + + printf("%.*s%s%s\n", len - saw_cr_at_eol, line, + reset, + saw_cr_at_eol ? "\r" : ""); +} + static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, int use_color) { @@ -593,7 +605,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, else putchar(' '); } - printf("%s%s\n", ll->line, c_reset); + show_line_to_eol(ll->line, -1, c_reset); ll = ll->next; } if (cnt < lno) @@ -617,7 +629,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, putchar(' '); p_mask <<= 1; } - printf("%.*s%s\n", sl->len, sl->bol, c_reset); + show_line_to_eol(sl->bol, sl->len, c_reset); } } } diff --git a/diff.c b/diff.c index 7b4300a74a..6d56c69810 100644 --- a/diff.c +++ b/diff.c @@ -511,13 +511,20 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) { - int has_trailing_newline = (len > 0 && line[len-1] == '\n'); + int has_trailing_newline, has_trailing_carriage_return; + + has_trailing_newline = (len > 0 && line[len-1] == '\n'); if (has_trailing_newline) len--; + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; fputs(set, file); fwrite(line, len, 1, file); fputs(reset, file); + if (has_trailing_carriage_return) + fputc('\r', file); if (has_trailing_newline) fputc('\n', file); } diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 7eae1f4500..84a1fe3115 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -178,4 +178,16 @@ test_expect_success 'trailing empty lines (2)' ' ' +test_expect_success 'do not color trailing cr in context' ' + git config --unset core.whitespace + rm -f .gitattributes && + echo AAAQ | tr Q "\015" >G && + git add G && + echo BBBQ | tr Q "\015" >>G + git diff --color G | tr "\015" Q >output && + grep "BBB.*${blue_grep}Q" output && + grep "AAA.*\[mQ" output + +' + test_done -- cgit v1.3 From a5a818ee4877e4458e8e6741a03ac3b19941d58a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 18 Aug 2008 20:08:09 -0700 Subject: diff: vary default prefix depending on what are compared With a new configuration "diff.mnemonicprefix", "git diff" shows the differences between various combinations of preimage and postimage trees with prefixes different from the standard "a/" and "b/". Hopefully this will make the distinction stand out for some people. "git diff" compares the (i)ndex and the (w)ork tree; "git diff HEAD" compares a (c)ommit and the (w)ork tree; "git diff --cached" compares a (c)ommit and the (i)ndex; "git-diff HEAD:file1 file2" compares an (o)bject and a (w)ork tree entity; "git diff --no-index a b" compares two non-git things (1) and (2). Because these mnemonics now have meanings, they are swapped when reverse diff is in effect and this feature is enabled. Signed-off-by: Junio C Hamano --- Documentation/config.txt | 16 ++++++++++++++++ builtin-diff.c | 2 ++ combine-diff.c | 8 ++++++-- diff-lib.c | 3 +++ diff-no-index.c | 1 + diff.c | 46 ++++++++++++++++++++++++++++++++++++++++------ diff.h | 2 ++ 7 files changed, 70 insertions(+), 8 deletions(-) (limited to 'diff.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index 81f981509a..74af36de5c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -581,6 +581,22 @@ diff.external:: you want to use an external diff program only on a subset of your files, you might want to use linkgit:gitattributes[5] instead. +diff.mnemonicprefix:: + If set, 'git-diff' uses a prefix pair that is different from the + standard "a/" and "b/" depending on what is being compared. When + this configuration is in effect, reverse diff output also swaps + the order of the prefixes: +'git-diff';; + compares the (i)ndex and the (w)ork tree; +'git-diff HEAD';; + compares a (c)ommit and the (w)ork tree; +'git diff --cached';; + compares a (c)ommit and the (i)ndex; +'git-diff HEAD:file1 file2';; + compares an (o)bject and a (w)ork tree entity; +'git diff --no-index a b';; + compares two non-git things (1) and (2). + diff.renameLimit:: The number of files to consider when performing the copy/rename detection; equivalent to the 'git-diff' option '-l'. diff --git a/builtin-diff.c b/builtin-diff.c index 7ffea97505..266337b832 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -74,6 +74,8 @@ static int builtin_diff_b_f(struct rev_info *revs, if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) die("'%s': not a regular file or symlink", path); + diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/"); + if (blob[0].mode == S_IFINVALID) blob[0].mode = canon_mode(st.st_mode); diff --git a/combine-diff.c b/combine-diff.c index 4dfc330867..19bd60e346 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -675,9 +675,13 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, int i, show_hunks; int working_tree_file = is_null_sha1(elem->sha1); int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? 40 : DEFAULT_ABBREV; + const char *a_prefix, *b_prefix; mmfile_t result_file; context = opt->context; + a_prefix = opt->a_prefix ? opt->a_prefix : "a/"; + b_prefix = opt->b_prefix ? opt->b_prefix : "b/"; + /* Read the result of merge first */ if (!working_tree_file) result = grab_blob(elem->sha1, &result_size); @@ -853,13 +857,13 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, dump_quoted_path("--- ", "", "/dev/null", c_meta, c_reset); else - dump_quoted_path("--- ", opt->a_prefix, elem->path, + dump_quoted_path("--- ", a_prefix, elem->path, c_meta, c_reset); if (deleted) dump_quoted_path("+++ ", "", "/dev/null", c_meta, c_reset); else - dump_quoted_path("+++ ", opt->b_prefix, elem->path, + dump_quoted_path("+++ ", b_prefix, elem->path, c_meta, c_reset); dump_sline(sline, cnt, num_parent, DIFF_OPT_TST(opt, COLOR_DIFF)); diff --git a/diff-lib.c b/diff-lib.c index e7eaff9a68..ae96c64ca2 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -63,6 +63,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option) ? CE_MATCH_RACY_IS_DIRTY : 0); char symcache[PATH_MAX]; + diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/"); + if (diff_unmerged_stage < 0) diff_unmerged_stage = 2; entries = active_nr; @@ -469,6 +471,7 @@ int run_diff_index(struct rev_info *revs, int cached) if (unpack_trees(1, &t, &opts)) exit(128); + diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/"); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; diff --git a/diff-no-index.c b/diff-no-index.c index 7d68b7f1be..b60d3455da 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -252,6 +252,7 @@ void diff_no_index(struct rev_info *revs, if (queue_diff(&revs->diffopt, revs->diffopt.paths[0], revs->diffopt.paths[1])) exit(1); + diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); diff --git a/diff.c b/diff.c index 7b4300a74a..c1804efed9 100644 --- a/diff.c +++ b/diff.c @@ -23,6 +23,7 @@ static int diff_rename_limit_default = 200; int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; +static int diff_mnemonic_prefix; static char diff_colors[][COLOR_MAXLEN] = { "\033[m", /* reset */ @@ -149,6 +150,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_auto_refresh_index = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.mnemonicprefix")) { + diff_mnemonic_prefix = git_config_bool(var, value); + return 0; + } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); if (!prefixcmp(var, "diff.")) { @@ -305,6 +310,15 @@ static void emit_rewrite_diff(const char *name_a, const char *new = diff_get_color(color_diff, DIFF_FILE_NEW); const char *reset = diff_get_color(color_diff, DIFF_RESET); static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT; + const char *a_prefix, *b_prefix; + + if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) { + a_prefix = o->b_prefix; + b_prefix = o->a_prefix; + } else { + a_prefix = o->a_prefix; + b_prefix = o->b_prefix; + } name_a += (*name_a == '/'); name_b += (*name_b == '/'); @@ -313,8 +327,8 @@ static void emit_rewrite_diff(const char *name_a, strbuf_reset(&a_name); strbuf_reset(&b_name); - quote_two_c_style(&a_name, o->a_prefix, name_a, 0); - quote_two_c_style(&b_name, o->b_prefix, name_b, 0); + quote_two_c_style(&a_name, a_prefix, name_a, 0); + quote_two_c_style(&b_name, b_prefix, name_b, 0); diff_populate_filespec(one, 0); diff_populate_filespec(two, 0); @@ -1432,6 +1446,14 @@ static const char *diff_funcname_pattern(struct diff_filespec *one) return NULL; } +void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b) +{ + if (!options->a_prefix) + options->a_prefix = a; + if (!options->b_prefix) + options->b_prefix = b; +} + static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -1445,9 +1467,19 @@ static void builtin_diff(const char *name_a, char *a_one, *b_two; const char *set = diff_get_color_opt(o, DIFF_METAINFO); const char *reset = diff_get_color_opt(o, DIFF_RESET); + const char *a_prefix, *b_prefix; + + diff_set_mnemonic_prefix(o, "a/", "b/"); + if (DIFF_OPT_TST(o, REVERSE_DIFF)) { + a_prefix = o->b_prefix; + b_prefix = o->a_prefix; + } else { + a_prefix = o->a_prefix; + b_prefix = o->b_prefix; + } - a_one = quote_two(o->a_prefix, name_a + (*name_a == '/')); - b_two = quote_two(o->b_prefix, name_b + (*name_b == '/')); + a_one = quote_two(a_prefix, name_a + (*name_a == '/')); + b_two = quote_two(b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; fprintf(o->file, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset); @@ -2308,8 +2340,10 @@ void diff_setup(struct diff_options *options) DIFF_OPT_CLR(options, COLOR_DIFF); options->detect_rename = diff_detect_rename_default; - options->a_prefix = "a/"; - options->b_prefix = "b/"; + if (!diff_mnemonic_prefix) { + options->a_prefix = "a/"; + options->b_prefix = "b/"; + } } int diff_setup_done(struct diff_options *options) diff --git a/diff.h b/diff.h index 50fb5ddb0b..9a679f58f5 100644 --- a/diff.h +++ b/diff.h @@ -160,6 +160,8 @@ extern void diff_tree_combined(const unsigned char *sha1, const unsigned char pa extern void diff_tree_combined_merge(const unsigned char *sha1, int, struct rev_info *); +void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b); + extern void diff_addremove(struct diff_options *, int addremove, unsigned mode, -- cgit v1.3 From f88d225feb117f0429540da90b2552e198fa2e82 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 2 Sep 2008 17:28:59 -0700 Subject: diff --cumulative is a sub-option of --dirstat The option used to be implemented as if it is a totally independent one, but "git diff --cumulative" would not mean anything without "--dirstat". This makes --cumulative imply --dirstat. Signed-off-by: Junio C Hamano --- diff.c | 9 ++++++--- diff.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 7b4300a74a..b3a7da70a5 100644 --- a/diff.c +++ b/diff.c @@ -1072,7 +1072,7 @@ static void show_dirstat(struct diff_options *options) dir.alloc = 0; dir.nr = 0; dir.percent = options->dirstat_percent; - dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE; + dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE); changed = 0; for (i = 0; i < q->nr; i++) { @@ -2298,6 +2298,7 @@ void diff_setup(struct diff_options *options) options->break_opt = -1; options->rename_limit = -1; options->dirstat_percent = 3; + DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE); options->context = 3; options->change = diff_change; @@ -2470,8 +2471,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->output_format |= DIFF_FORMAT_SHORTSTAT; else if (opt_arg(arg, 'X', "dirstat", &options->dirstat_percent)) options->output_format |= DIFF_FORMAT_DIRSTAT; - else if (!strcmp(arg, "--cumulative")) - options->output_format |= DIFF_FORMAT_CUMULATIVE; + else if (!strcmp(arg, "--cumulative")) { + options->output_format |= DIFF_FORMAT_DIRSTAT; + DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); + } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) diff --git a/diff.h b/diff.h index 50fb5ddb0b..7f53bebf33 100644 --- a/diff.h +++ b/diff.h @@ -31,7 +31,6 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_FORMAT_PATCH 0x0010 #define DIFF_FORMAT_SHORTSTAT 0x0020 #define DIFF_FORMAT_DIRSTAT 0x0040 -#define DIFF_FORMAT_CUMULATIVE 0x0080 /* These override all above */ #define DIFF_FORMAT_NAME 0x0100 @@ -64,6 +63,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_CHECK_FAILED (1 << 16) #define DIFF_OPT_RELATIVE_NAME (1 << 17) #define DIFF_OPT_IGNORE_SUBMODULES (1 << 18) +#define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) -- cgit v1.3 From fd33777b7871eefa440f89ccf7c432895af09c74 Mon Sep 17 00:00:00 2001 From: Heikki Orsila Date: Fri, 5 Sep 2008 22:27:35 +0300 Subject: diff --dirstat-by-file: count changed files, not lines This new option --dirstat-by-file is the same as --dirstat, but it counts "impacted files" instead of "impacted lines" (lines that are added or removed). Signed-off-by: Heikki Orsila Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 3 +++ diff.c | 10 +++++++++- diff.h | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 6e268326da..7788d4fa4a 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -65,6 +65,9 @@ endif::git-format-patch[] can be set with "--dirstat=limit". Changes in a child directory is not counted for the parent directory, unless "--cumulative" is used. +--dirstat-by-file[=limit]:: + Same as --dirstat, but counts changed files instead of lines. + --summary:: Output a condensed summary of extended header information such as creations, renames and mode changes. diff --git a/diff.c b/diff.c index cbd151bbc8..2de86eb760 100644 --- a/diff.c +++ b/diff.c @@ -1110,9 +1110,13 @@ static void show_dirstat(struct diff_options *options) /* * Original minus copied is the removed material, * added is the new material. They are both damages - * made to the preimage. + * made to the preimage. In --dirstat-by-file mode, count + * damaged files, not damaged lines. This is done by + * counting only a single damaged line per file. */ damage = (p->one->size - copied) + added; + if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0) + damage = 1; ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc); dir.files[dir.nr].name = name; @@ -2476,6 +2480,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--cumulative")) { options->output_format |= DIFF_FORMAT_DIRSTAT; DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); + } else if (opt_arg(arg, 0, "dirstat-by-file", + &options->dirstat_percent)) { + options->output_format |= DIFF_FORMAT_DIRSTAT; + DIFF_OPT_SET(options, DIRSTAT_BY_FILE); } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; diff --git a/diff.h b/diff.h index 7f53bebf33..c34688881d 100644 --- a/diff.h +++ b/diff.h @@ -64,6 +64,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_RELATIVE_NAME (1 << 17) #define DIFF_OPT_IGNORE_SUBMODULES (1 << 18) #define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19) +#define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) -- cgit v1.3 From 9d865356abc08b253bc15b5fb50471d80c828be1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 6 Sep 2008 19:09:16 -0700 Subject: diff Porcelain: do not disable auto index refreshing on -C -C When we enabled the automatic refreshing of the index to "diff" Porcelain, we disabled it when --find-copies-harder was asked, but there is no good reason to do so. In the following command sequence, the first "diff" shows an "empty" diff exposing stat dirtyness, while the second one does not. $ >foo $ git add foo $ touch foo $ git diff -C -C $ git diff -C This fixes the inconsistency. Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index b3a7da70a5..85d690183f 100644 --- a/diff.c +++ b/diff.c @@ -3394,7 +3394,7 @@ void diffcore_std(struct diff_options *options) if (DIFF_OPT_TST(options, QUIET)) return; - if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER)) + if (options->skip_stat_unmatch) diffcore_skip_stat_unmatch(options); if (options->break_opt != -1) diffcore_break(options->break_opt); -- cgit v1.3 From df58a8274d6865020682a6739bc59b87a9761991 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 1 Sep 2008 23:20:26 -0700 Subject: diff --quiet: make it synonym to --exit-code >/dev/null The point of --quiet was to return the status as early as possible without doing any extra processing. Well behaved scripts, when they expect to run many diff operations inside, are supposed to run "update-index --refresh" upfront; we do not want them to pay the price of iterating over the index and comparing the contents to fix the stat dirtiness, and we avoided most of the processing in diffcore_std() when --quiet is in effect. But scripts that adhere to the good practice won't have to pay any more price than the necessary lstat(2) that will report stat cleanliness, as long as only -q is given without any fancier diff options. More importantly, users who do ask for "--quiet -M --filter=D" (in order to notice only the deletion, not paths that disappeared only because they have been renamed away) deserve to get the result they asked for, even it means they have to pay the extra price; the alternative is to get a cheap early return that gives a result they did not ask for, which is much worse. Signed-off-by: Junio C Hamano --- diff.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 85d690183f..13be211568 100644 --- a/diff.c +++ b/diff.c @@ -2393,13 +2393,6 @@ int diff_setup_done(struct diff_options *options) DIFF_OPT_SET(options, EXIT_WITH_STATUS); } - /* - * If we postprocess in diffcore, we cannot simply return - * upon the first hit. We need to run diff as usual. - */ - if (options->pickaxe || options->filter) - DIFF_OPT_CLR(options, QUIET); - return 0; } @@ -3391,9 +3384,6 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) void diffcore_std(struct diff_options *options) { - if (DIFF_OPT_TST(options, QUIET)) - return; - if (options->skip_stat_unmatch) diffcore_skip_stat_unmatch(options); if (options->break_opt != -1) -- cgit v1.3 From af9ce1ffc6de9774e90a91f27fb1febd027f74f1 Mon Sep 17 00:00:00 2001 From: Andreas Ericsson Date: Sun, 7 Sep 2008 22:15:29 +0200 Subject: Teach "git diff -p" to locate PHP class methods Otherwise it will always print the class-name rather than the name of the function inside that class. While we're at it, reorder the gitattributes manpage to list the built-in funcname pattern names in alphabetical order. Signed-off-by: Andreas Ericsson Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 6 ++++-- diff.c | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'diff.c') diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 5fb5007413..75124d2612 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -311,18 +311,20 @@ patterns are available: - `bibtex` suitable for files with BibTeX coded references. +- `html` suitable for HTML/XHTML documents. + - `java` suitable for source code in the Java lanugage. - `pascal` suitable for source code in the Pascal/Delphi language. +- `php` suitable for source code in the PHP language. + - `python` suitable for source code in the Python language. - `ruby` suitable for source code in the Ruby language. - `tex` suitable for source code for LaTeX documents. -- `html` suitable for HTML/XHTML documents. - Performing a three-way merge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/diff.c b/diff.c index cbd151bbc8..e7afbe28c1 100644 --- a/diff.c +++ b/diff.c @@ -1402,6 +1402,7 @@ static struct builtin_funcname_pattern { "\\|" "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$" }, + { "php", "^[\t ]*\\(\\(function\\|class\\).*\\)" }, { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" }, { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, -- cgit v1.3 From 45e7ca0f0e1042c26d56b578165365c3f70c0121 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 18 Sep 2008 17:40:48 -0500 Subject: diff.c: return pattern entry pointer rather than just the hunk header pattern This is in preparation for associating a flag with each pattern which will control how the pattern is interpreted. For example, as a basic or extended regular expression. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- diff.c | 55 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 5e01b2bb27..406a76a203 100644 --- a/diff.c +++ b/diff.c @@ -94,32 +94,35 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val * to define a customized regexp to find the beginning of a function to * be used for hunk header lines of "diff -p" style output. */ -static struct funcname_pattern { +struct funcname_pattern_entry { char *name; char *pattern; - struct funcname_pattern *next; +}; +static struct funcname_pattern_list { + struct funcname_pattern_list *next; + struct funcname_pattern_entry e; } *funcname_pattern_list; static int parse_funcname_pattern(const char *var, const char *ep, const char *value) { const char *name; int namelen; - struct funcname_pattern *pp; + struct funcname_pattern_list *pp; name = var + 5; /* "diff." */ namelen = ep - name; for (pp = funcname_pattern_list; pp; pp = pp->next) - if (!strncmp(pp->name, name, namelen) && !pp->name[namelen]) + if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen]) break; if (!pp) { pp = xcalloc(1, sizeof(*pp)); - pp->name = xmemdupz(name, namelen); + pp->e.name = xmemdupz(name, namelen); pp->next = funcname_pattern_list; funcname_pattern_list = pp; } - free(pp->pattern); - pp->pattern = xstrdup(value); + free(pp->e.pattern); + pp->e.pattern = xstrdup(value); return 0; } @@ -1377,20 +1380,17 @@ int diff_filespec_is_binary(struct diff_filespec *one) return one->is_binary; } -static const char *funcname_pattern(const char *ident) +static const struct funcname_pattern_entry *funcname_pattern(const char *ident) { - struct funcname_pattern *pp; + struct funcname_pattern_list *pp; for (pp = funcname_pattern_list; pp; pp = pp->next) - if (!strcmp(ident, pp->name)) - return pp->pattern; + if (!strcmp(ident, pp->e.name)) + return &pp->e; return NULL; } -static struct builtin_funcname_pattern { - const char *name; - const char *pattern; -} builtin_funcname_pattern[] = { +static const struct funcname_pattern_entry builtin_funcname_pattern[] = { { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|" "new\\|return\\|switch\\|throw\\|while\\)\n" "^[ ]*\\(\\([ ]*" @@ -1407,9 +1407,10 @@ static struct builtin_funcname_pattern { { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, }; -static const char *diff_funcname_pattern(struct diff_filespec *one) +static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one) { - const char *ident, *pattern; + const char *ident; + const struct funcname_pattern_entry *pe; int i; diff_filespec_check_attr(one); @@ -1424,9 +1425,9 @@ static const char *diff_funcname_pattern(struct diff_filespec *one) return funcname_pattern("default"); /* Look up custom "funcname.$ident" regexp from config. */ - pattern = funcname_pattern(ident); - if (pattern) - return pattern; + pe = funcname_pattern(ident); + if (pe) + return pe; /* * And define built-in fallback patterns here. Note that @@ -1434,7 +1435,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one) */ for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++) if (!strcmp(ident, builtin_funcname_pattern[i].name)) - return builtin_funcname_pattern[i].pattern; + return &builtin_funcname_pattern[i]; return NULL; } @@ -1512,11 +1513,11 @@ static void builtin_diff(const char *name_a, xdemitconf_t xecfg; xdemitcb_t ecb; struct emit_callback ecbdata; - const char *funcname_pattern; + const struct funcname_pattern_entry *pe; - funcname_pattern = diff_funcname_pattern(one); - if (!funcname_pattern) - funcname_pattern = diff_funcname_pattern(two); + pe = diff_funcname_pattern(one); + if (!pe) + pe = diff_funcname_pattern(two); memset(&xecfg, 0, sizeof(xecfg)); memset(&ecbdata, 0, sizeof(ecbdata)); @@ -1528,8 +1529,8 @@ static void builtin_diff(const char *name_a, xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; xecfg.flags = XDL_EMIT_FUNCNAMES; - if (funcname_pattern) - xdiff_set_find_func(&xecfg, funcname_pattern); + if (pe) + xdiff_set_find_func(&xecfg, pe->pattern); if (!diffopts) ; else if (!prefixcmp(diffopts, "--unified=")) -- cgit v1.3 From a013585b20ac757b0e75a72181ffa44674f35235 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 18 Sep 2008 17:42:48 -0500 Subject: diff.c: associate a flag with each pattern and use it for compiling regex This is in preparation for allowing extended regular expression patterns. Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- diff.c | 21 ++++++++++++--------- xdiff-interface.c | 4 ++-- xdiff-interface.h | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 406a76a203..6881cf4efa 100644 --- a/diff.c +++ b/diff.c @@ -97,13 +97,14 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val struct funcname_pattern_entry { char *name; char *pattern; + int cflags; }; static struct funcname_pattern_list { struct funcname_pattern_list *next; struct funcname_pattern_entry e; } *funcname_pattern_list; -static int parse_funcname_pattern(const char *var, const char *ep, const char *value) +static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags) { const char *name; int namelen; @@ -123,6 +124,7 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v } free(pp->e.pattern); pp->e.pattern = xstrdup(value); + pp->e.cflags = cflags; return 0; } @@ -185,7 +187,8 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) if (!strcmp(ep, ".funcname")) { if (!value) return config_error_nonbool(var); - return parse_funcname_pattern(var, ep, value); + return parse_funcname_pattern(var, ep, value, + 0); } } } @@ -1395,16 +1398,16 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = { "new\\|return\\|switch\\|throw\\|while\\)\n" "^[ ]*\\(\\([ ]*" "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}" - "[ ]*([^;]*\\)$" }, + "[ ]*([^;]*\\)$", 0 }, { "pascal", "^\\(\\(procedure\\|function\\|constructor\\|" "destructor\\|interface\\|implementation\\|" "initialization\\|finalization\\)[ \t]*.*\\)$" "\\|" - "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$" - }, - { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, - { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, - { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, + "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$", + 0 }, + { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$", 0 }, + { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$", 0 }, + { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$", 0 }, }; static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one) @@ -1530,7 +1533,7 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = o->context; xecfg.flags = XDL_EMIT_FUNCNAMES; if (pe) - xdiff_set_find_func(&xecfg, pe->pattern); + xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); if (!diffopts) ; else if (!prefixcmp(diffopts, "--unified=")) diff --git a/xdiff-interface.c b/xdiff-interface.c index 61dc5c5470..2c81f40cb6 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -206,7 +206,7 @@ static long ff_regexp(const char *line, long len, return result; } -void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value) +void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags) { int i; struct ff_regs *regs; @@ -231,7 +231,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value) expression = buffer = xstrndup(value, ep - value); else expression = value; - if (regcomp(®->re, expression, 0)) + if (regcomp(®->re, expression, cflags)) die("Invalid regexp to look for hunk header: %s", expression); free(buffer); value = ep + 1; diff --git a/xdiff-interface.h b/xdiff-interface.h index f7f791d96b..33cab9dd59 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -21,6 +21,6 @@ int parse_hunk_header(char *line, int len, int read_mmfile(mmfile_t *ptr, const char *filename); int buffer_is_binary(const char *ptr, unsigned long size); -extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line); +extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags); #endif -- cgit v1.3 From 45d9414fa5599b41578625961b53e18a9b9148c7 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 18 Sep 2008 17:44:33 -0500 Subject: diff.*.xfuncname which uses "extended" regex's for hunk header selection Currently, the hunk headers produced by 'diff -p' are customizable by setting the diff.*.funcname option in the config file. The 'funcname' option takes a basic regular expression. This functionality was designed using the GNU regex library which, by default, allows using backslashed versions of some extended regular expression operators, even in Basic Regular Expression mode. For example, the following characters, when backslashed, are interpreted according to the extended regular expression rules: ?, +, and |. As such, the builtin funcname patterns were created using some extended regular expression operators. Other platforms which adhere more strictly to the POSIX spec do not interpret the backslashed extended RE operators in Basic Regular Expression mode. This causes the pattern matching for the builtin funcname patterns to fail on those platforms. Introduce a new option 'xfuncname' which uses extended regular expressions, and advertise it _instead_ of funcname. Since most users are on GNU platforms, the majority of funcname patterns are created and tested there. Advertising only xfuncname should help to avoid the creation of non-portable patterns which work with GNU regex but not elsewhere. Additionally, the extended regular expressions may be less ugly and complicated compared to the basic RE since many common special operators do not need to be backslashed. For example, the GNU Basic RE: ^[ ]*\\(\\(public\\|static\\).*\\)$ becomes the following Extended RE: ^[ ]*((public|static).*)$ Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- Documentation/gitattributes.txt | 4 ++-- diff.c | 5 +++++ t/t4018-diff-funcname.sh | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) (limited to 'diff.c') diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 94e6752aa2..9259637609 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -288,13 +288,13 @@ for paths. *.tex diff=tex ------------------------ -Then, you would define "diff.tex.funcname" configuration to +Then, you would define "diff.tex.xfuncname" configuration to specify a regular expression that matches a line that you would want to appear as the hunk header, like this: ------------------------ [diff "tex"] - funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$" + xfuncname = "^(\\\\(sub)*section\\{.*)$" ------------------------ Note. A single level of backslashes are eaten by the diff --git a/diff.c b/diff.c index 6881cf4efa..dabb4b4a02 100644 --- a/diff.c +++ b/diff.c @@ -189,6 +189,11 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return config_error_nonbool(var); return parse_funcname_pattern(var, ep, value, 0); + } else if (!strcmp(ep, ".xfuncname")) { + if (!value) + return config_error_nonbool(var); + return parse_funcname_pattern(var, ep, value, + REG_EXTENDED); } } } diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 18bcd9713d..602d68f092 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -58,7 +58,7 @@ test_expect_success 'last regexp must not be negated' ' ' test_expect_success 'alternation in pattern' ' - git config diff.java.funcname "^[ ]*\\(\\(public\\|static\\).*\\)$" + git config diff.java.xfuncname "^[ ]*((public|static).*)$" && git diff --no-index Beer.java Beer-correct.java | grep "^@@.*@@ public static void main(" ' -- cgit v1.3 From 6a6baf9b4e819a0bbfd70627f966cd7144dd8301 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 19 Sep 2008 23:45:04 -0700 Subject: diff: use extended regexp to find hunk headers Using ERE elements such as "|" (alternation) by backquoting in BRE is a GNU extension and should not be done in portable programs. Signed-off-by: Junio C Hamano --- diff.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index dabb4b4a02..175a044a34 100644 --- a/diff.c +++ b/diff.c @@ -1399,20 +1399,23 @@ static const struct funcname_pattern_entry *funcname_pattern(const char *ident) } static const struct funcname_pattern_entry builtin_funcname_pattern[] = { - { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|" - "new\\|return\\|switch\\|throw\\|while\\)\n" - "^[ ]*\\(\\([ ]*" - "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}" - "[ ]*([^;]*\\)$", 0 }, - { "pascal", "^\\(\\(procedure\\|function\\|constructor\\|" - "destructor\\|interface\\|implementation\\|" - "initialization\\|finalization\\)[ \t]*.*\\)$" - "\\|" - "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$", - 0 }, - { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$", 0 }, - { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$", 0 }, - { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$", 0 }, + { "java", + "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" + "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$", + REG_EXTENDED }, + { "pascal", + "^((procedure|function|constructor|destructor|interface|" + "implementation|initialization|finalization)[ \t]*.*)$" + "|" + "^(.*=[ \t]*(class|record).*)$", + REG_EXTENDED }, + { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", + REG_EXTENDED }, + { "tex", + "^(\\\\((sub)*section|chapter|part)\\*{0,1}\{.*)$", + REG_EXTENDED }, + { "ruby", "^[ \t]*((class|module|def)[ \t].*)$", + REG_EXTENDED }, }; static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one) -- cgit v1.3 From 1883a0d3b7ad7c9de1ac790bda6f1a6181237439 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 19 Sep 2008 23:52:49 -0700 Subject: diff: use extended regexp to find hunk headers Using ERE elements such as "|" (alternation) by backquoting in BRE is a GNU extension and should not be done in portable programs. Signed-off-by: Junio C Hamano --- diff.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 5b9b074856..a733010170 100644 --- a/diff.c +++ b/diff.c @@ -1406,7 +1406,7 @@ static const struct funcname_pattern_entry *funcname_pattern(const char *ident) static const struct funcname_pattern_entry builtin_funcname_pattern[] = { { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", REG_EXTENDED }, - { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$", 0 }, + { "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED }, { "java", "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$", @@ -1417,8 +1417,8 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = { "|" "^(.*=[ \t]*(class|record).*)$", REG_EXTENDED }, - { "php", "^[\t ]*\\(\\(function\\|class\\).*\\)", 0 }, - { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$", 0 }, + { "php", "^[\t ]*((function|class).*)", REG_EXTENDED }, + { "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED }, { "ruby", "^[ \t]*((class|module|def)[ \t].*)$", REG_EXTENDED }, { "tex", -- cgit v1.3 From 3d8dccd74aa29a9019c4e8b52e75a40189e6f5cb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Sep 2008 00:52:11 -0700 Subject: diff: fix "multiple regexp" semantics to find hunk header comment When multiple regular expressions are concatenated with "\n", they were traditionally AND'ed together, and only a line that matches _all_ of them is taken as a match. This however is unwieldy when multiple regexp feature is used to specify alternatives. This fixes the semantics to take the first match. A nagative pattern, if matches, makes the line to fail as before. A match with a positive pattern will be the final match, and what it captures in $1 is used as the hunk header comment. We could write alternatives using "|" in ERE, but the machinery can only use captured $1 as the hunk header comment (or $0 if there is no match in $1), so you cannot write: "junk ( A | B ) | garbage ( C | D )" and expect both "junk" and "garbage" to get stripped with the existing code. With this fix, you can write it as: "junk ( A | B ) \n garbage ( C | D )" and the way capture works would match the user expectation more naturally. Signed-off-by: Junio C Hamano --- diff.c | 2 +- xdiff-interface.c | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index a733010170..1bcbbd5bb1 100644 --- a/diff.c +++ b/diff.c @@ -1414,7 +1414,7 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = { { "pascal", "^((procedure|function|constructor|destructor|interface|" "implementation|initialization|finalization)[ \t]*.*)$" - "|" + "\n" "^(.*=[ \t]*(class|record).*)$", REG_EXTENDED }, { "php", "^[\t ]*((function|class).*)", REG_EXTENDED }, diff --git a/xdiff-interface.c b/xdiff-interface.c index 7f1a7d3ffc..6c6bb19973 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -194,26 +194,29 @@ static long ff_regexp(const char *line, long len, char *line_buffer = xstrndup(line, len); /* make NUL terminated */ struct ff_regs *regs = priv; regmatch_t pmatch[2]; - int result = 0, i; + int i; + int result = -1; for (i = 0; i < regs->nr; i++) { struct ff_reg *reg = regs->array + i; - if (reg->negate ^ !!regexec(®->re, - line_buffer, 2, pmatch, 0)) { - free(line_buffer); - return -1; + if (!regexec(®->re, line_buffer, 2, pmatch, 0)) { + if (reg->negate) + goto fail; + break; } } + if (regs->nr <= i) + goto fail; i = pmatch[1].rm_so >= 0 ? 1 : 0; line += pmatch[i].rm_so; result = pmatch[i].rm_eo - pmatch[i].rm_so; if (result > buffer_size) result = buffer_size; else - while (result > 0 && (isspace(line[result - 1]) || - line[result - 1] == '\n')) + while (result > 0 && (isspace(line[result - 1]))) result--; memcpy(buffer, line, result); + fail: free(line_buffer); return result; } -- cgit v1.3 From 96d1a8e9d44fd635fad8466dbe0aab6d73495c9f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 Sep 2008 15:30:12 -0700 Subject: diff hunk pattern: fix misconverted "\{" tex macro introducers Pointed out by Brandon Casey. Signed-off-by: Junio C Hamano --- diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 175a044a34..a283738616 100644 --- a/diff.c +++ b/diff.c @@ -1409,10 +1409,10 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = { "|" "^(.*=[ \t]*(class|record).*)$", REG_EXTENDED }, - { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", + { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", REG_EXTENDED }, { "tex", - "^(\\\\((sub)*section|chapter|part)\\*{0,1}\{.*)$", + "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", REG_EXTENDED }, { "ruby", "^[ \t]*((class|module|def)[ \t].*)$", REG_EXTENDED }, -- cgit v1.3 From fdac6692a0b0eda293f9f1bf4bc49b05b29f3c45 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Mon, 22 Sep 2008 18:26:20 -0500 Subject: t4018-diff-funcname: test syntax of builtin xfuncname patterns [jc: fixes bibtex pattern breakage exposed by this test] Signed-off-by: Brandon Casey Signed-off-by: Junio C Hamano --- diff.c | 2 +- t/t4018-diff-funcname.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 0f98bff46b..05dd8f0b56 100644 --- a/diff.c +++ b/diff.c @@ -1404,7 +1404,7 @@ static const struct funcname_pattern_entry *funcname_pattern(const char *ident) } static const struct funcname_pattern_entry builtin_funcname_pattern[] = { - { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", + { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", REG_EXTENDED }, { "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED }, { "java", diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 99fff973eb..520e095c59 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -32,7 +32,7 @@ EOF sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java -builtin_patterns="bibtex java pascal ruby tex" +builtin_patterns="bibtex html java pascal php python ruby tex" for p in $builtin_patterns do test_expect_success "builtin $p pattern compiles" ' -- cgit v1.3 From 416f80a60b209d2ca0326407b801e9fb6ed8fdd7 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Mon, 29 Sep 2008 16:52:01 -0500 Subject: diff.c: remove duplicate bibtex pattern introduced by merge 92bb9785 Signed-off-by: Brandon Casey Signed-off-by: Shawn O. Pearce --- diff.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index b001d7b507..7c982b4947 100644 --- a/diff.c +++ b/diff.c @@ -1439,8 +1439,6 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = { { "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED }, { "ruby", "^[ \t]*((class|module|def)[ \t].*)$", REG_EXTENDED }, - { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", - REG_EXTENDED }, { "tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", REG_EXTENDED }, -- cgit v1.3 From 9126f0091f271f090cc030a788219574ab0fea97 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 1 Oct 2008 14:05:20 -0400 Subject: fix openssl headers conflicting with custom SHA1 implementations On ARM I have the following compilation errors: CC fast-import.o In file included from cache.h:8, from builtin.h:6, from fast-import.c:142: arm/sha1.h:14: error: conflicting types for 'SHA_CTX' /usr/include/openssl/sha.h:105: error: previous declaration of 'SHA_CTX' was here arm/sha1.h:16: error: conflicting types for 'SHA1_Init' /usr/include/openssl/sha.h:115: error: previous declaration of 'SHA1_Init' was here arm/sha1.h:17: error: conflicting types for 'SHA1_Update' /usr/include/openssl/sha.h:116: error: previous declaration of 'SHA1_Update' was here arm/sha1.h:18: error: conflicting types for 'SHA1_Final' /usr/include/openssl/sha.h:117: error: previous declaration of 'SHA1_Final' was here make: *** [fast-import.o] Error 1 This is because openssl header files are always included in git-compat-util.h since commit 684ec6c63c whenever NO_OPENSSL is not set, which somehow brings in clashing with the custom ARM version. Compilation of git is probably broken on PPC too for the same reason. Turns out that the only file requiring openssl/ssl.h and openssl/err.h is imap-send.c. But only moving those problematic includes there doesn't solve the issue as it also includes cache.h which brings in the conflicting local SHA1 header file. As suggested by Jeff King, the best solution is to rename our references to SHA1 functions and structure to something git specific, and define those according to the implementation used. Signed-off-by: Nicolas Pitre Signed-off-by: Shawn O. Pearce --- arm/sha1.c | 16 ++++++++-------- arm/sha1.h | 15 ++++++++++----- arm/sha1_arm.S | 4 ++-- builtin-unpack-objects.c | 10 +++++----- cache.h | 8 +++++++- csum-file.c | 8 ++++---- csum-file.h | 2 +- diff.c | 12 ++++++------ fast-import.c | 18 +++++++++--------- http-push.c | 10 +++++----- http-walker.c | 10 +++++----- index-pack.c | 8 ++++---- mozilla-sha1/sha1.c | 18 +++++++++--------- mozilla-sha1/sha1.h | 13 +++++++++---- pack-check.c | 16 ++++++++-------- pack-write.c | 30 +++++++++++++++--------------- patch-id.c | 12 ++++++------ ppc/sha1.c | 18 +++++++++--------- ppc/sha1.h | 15 ++++++++++----- ppc/sha1ppc.S | 4 ++-- read-cache.c | 28 ++++++++++++++-------------- rerere.c | 10 +++++----- sha1_file.c | 10 +++++----- test-sha1.c | 8 ++++---- 24 files changed, 162 insertions(+), 141 deletions(-) (limited to 'diff.c') diff --git a/arm/sha1.c b/arm/sha1.c index 9e3ae038e8..c61ad4aff9 100644 --- a/arm/sha1.c +++ b/arm/sha1.c @@ -8,9 +8,9 @@ #include #include "sha1.h" -extern void sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W); +extern void arm_sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W); -void SHA1_Init(SHA_CTX *c) +void arm_SHA1_Init(arm_SHA_CTX *c) { c->len = 0; c->hash[0] = 0x67452301; @@ -20,7 +20,7 @@ void SHA1_Init(SHA_CTX *c) c->hash[4] = 0xc3d2e1f0; } -void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n) +void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n) { uint32_t workspace[80]; unsigned int partial; @@ -32,12 +32,12 @@ void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n) if (partial) { done = 64 - partial; memcpy(c->buffer + partial, p, done); - sha_transform(c->hash, c->buffer, workspace); + arm_sha_transform(c->hash, c->buffer, workspace); partial = 0; } else done = 0; while (n >= done + 64) { - sha_transform(c->hash, p + done, workspace); + arm_sha_transform(c->hash, p + done, workspace); done += 64; } } else @@ -46,7 +46,7 @@ void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n) memcpy(c->buffer + partial, p + done, n - done); } -void SHA1_Final(unsigned char *hash, SHA_CTX *c) +void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c) { uint64_t bitlen; uint32_t bitlen_hi, bitlen_lo; @@ -57,7 +57,7 @@ void SHA1_Final(unsigned char *hash, SHA_CTX *c) bitlen = c->len << 3; offset = c->len & 0x3f; padlen = ((offset < 56) ? 56 : (64 + 56)) - offset; - SHA1_Update(c, padding, padlen); + arm_SHA1_Update(c, padding, padlen); bitlen_hi = bitlen >> 32; bitlen_lo = bitlen & 0xffffffff; @@ -69,7 +69,7 @@ void SHA1_Final(unsigned char *hash, SHA_CTX *c) bits[5] = bitlen_lo >> 16; bits[6] = bitlen_lo >> 8; bits[7] = bitlen_lo; - SHA1_Update(c, bits, 8); + arm_SHA1_Update(c, bits, 8); for (i = 0; i < 5; i++) { uint32_t v = c->hash[i]; diff --git a/arm/sha1.h b/arm/sha1.h index 3952646349..b61b618486 100644 --- a/arm/sha1.h +++ b/arm/sha1.h @@ -7,12 +7,17 @@ #include -typedef struct sha_context { +typedef struct { uint64_t len; uint32_t hash[5]; unsigned char buffer[64]; -} SHA_CTX; +} arm_SHA_CTX; -void SHA1_Init(SHA_CTX *c); -void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n); -void SHA1_Final(unsigned char *hash, SHA_CTX *c); +void arm_SHA1_Init(arm_SHA_CTX *c); +void arm_SHA1_Update(arm_SHA_CTX *c, const void *p, unsigned long n); +void arm_SHA1_Final(unsigned char *hash, arm_SHA_CTX *c); + +#define git_SHA_CTX arm_SHA_CTX +#define git_SHA1_Init arm_SHA1_Init +#define git_SHA1_Update arm_SHA1_Update +#define git_SHA1_Final arm_SHA1_Final diff --git a/arm/sha1_arm.S b/arm/sha1_arm.S index 8c1cb99fb4..41e92636e0 100644 --- a/arm/sha1_arm.S +++ b/arm/sha1_arm.S @@ -10,7 +10,7 @@ */ .text - .globl sha_transform + .globl arm_sha_transform /* * void sha_transform(uint32_t *hash, const unsigned char *data, uint32_t *W); @@ -18,7 +18,7 @@ * note: the "data" pointer may be unaligned. */ -sha_transform: +arm_sha_transform: stmfd sp!, {r4 - r8, lr} diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 40b20f26e8..d2796b6309 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -19,7 +19,7 @@ static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] static unsigned char buffer[4096]; static unsigned int offset, len; static off_t consumed_bytes; -static SHA_CTX ctx; +static git_SHA_CTX ctx; /* * When running under --strict mode, objects whose reachability are @@ -59,7 +59,7 @@ static void *fill(int min) if (min > sizeof(buffer)) die("cannot fill %d bytes", min); if (offset) { - SHA1_Update(&ctx, buffer, offset); + git_SHA1_Update(&ctx, buffer, offset); memmove(buffer, buffer + offset, len); offset = 0; } @@ -539,10 +539,10 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix) /* We don't take any non-flag arguments now.. Maybe some day */ usage(unpack_usage); } - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); unpack_all(); - SHA1_Update(&ctx, buffer, offset); - SHA1_Final(sha1, &ctx); + git_SHA1_Update(&ctx, buffer, offset); + git_SHA1_Final(sha1, &ctx); if (strict) write_rest(); if (hashcmp(fill(20), sha1)) diff --git a/cache.h b/cache.h index 7027c896bf..9f4e5c0d45 100644 --- a/cache.h +++ b/cache.h @@ -6,8 +6,14 @@ #include "hash.h" #include SHA1_HEADER -#include +#ifndef git_SHA_CTX +#define git_SHA_CTX SHA_CTX +#define git_SHA1_Init SHA1_Init +#define git_SHA1_Update SHA1_Update +#define git_SHA1_Final SHA1_Final +#endif +#include #if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200 #define deflateBound(c,s) ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11) #endif diff --git a/csum-file.c b/csum-file.c index bb70c75ee1..717d29fc03 100644 --- a/csum-file.c +++ b/csum-file.c @@ -36,11 +36,11 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags) unsigned offset = f->offset; if (offset) { - SHA1_Update(&f->ctx, f->buffer, offset); + git_SHA1_Update(&f->ctx, f->buffer, offset); sha1flush(f, f->buffer, offset); f->offset = 0; } - SHA1_Final(f->buffer, &f->ctx); + git_SHA1_Final(f->buffer, &f->ctx); if (result) hashcpy(result, f->buffer); if (flags & (CSUM_CLOSE | CSUM_FSYNC)) { @@ -82,7 +82,7 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count) buf = (char *) buf + nr; left -= nr; if (!left) { - SHA1_Update(&f->ctx, data, offset); + git_SHA1_Update(&f->ctx, data, offset); sha1flush(f, data, offset); offset = 0; } @@ -105,7 +105,7 @@ struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp f->tp = tp; f->name = name; f->do_crc = 0; - SHA1_Init(&f->ctx); + git_SHA1_Init(&f->ctx); return f; } diff --git a/csum-file.h b/csum-file.h index 72c9487f4f..9e13342eb3 100644 --- a/csum-file.h +++ b/csum-file.h @@ -7,7 +7,7 @@ struct progress; struct sha1file { int fd; unsigned int offset; - SHA_CTX ctx; + git_SHA_CTX ctx; off_t total; struct progress *tp; const char *name; diff --git a/diff.c b/diff.c index 7c982b4947..4e4e439e03 100644 --- a/diff.c +++ b/diff.c @@ -3087,7 +3087,7 @@ static void diff_summary(FILE *file, struct diff_filepair *p) } struct patch_id_t { - SHA_CTX *ctx; + git_SHA_CTX *ctx; int patchlen; }; @@ -3115,7 +3115,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len) new_len = remove_space(line, len); - SHA1_Update(data->ctx, line, new_len); + git_SHA1_Update(data->ctx, line, new_len); data->patchlen += new_len; } @@ -3124,11 +3124,11 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) { struct diff_queue_struct *q = &diff_queued_diff; int i; - SHA_CTX ctx; + git_SHA_CTX ctx; struct patch_id_t data; char buffer[PATH_MAX * 4 + 20]; - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); data.ctx = &ctx; @@ -3190,7 +3190,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) len2, p->two->path, len1, p->one->path, len2, p->two->path); - SHA1_Update(&ctx, buffer, len1); + git_SHA1_Update(&ctx, buffer, len1); xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = 3; @@ -3199,7 +3199,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) &xpp, &xecfg, &ecb); } - SHA1_Final(sha1, &ctx); + git_SHA1_Final(sha1, &ctx); return 0; } diff --git a/fast-import.c b/fast-import.c index ab6689a64d..3c035a5788 100644 --- a/fast-import.c +++ b/fast-import.c @@ -845,7 +845,7 @@ static int oecmp (const void *a_, const void *b_) static char *create_index(void) { static char tmpfile[PATH_MAX]; - SHA_CTX ctx; + git_SHA_CTX ctx; struct sha1file *f; struct object_entry **idx, **c, **last, *e; struct object_entry_pool *o; @@ -882,17 +882,17 @@ static char *create_index(void) idx_fd = xmkstemp(tmpfile); f = sha1fd(idx_fd, tmpfile); sha1write(f, array, 256 * sizeof(int)); - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); for (c = idx; c != last; c++) { uint32_t offset = htonl((*c)->offset); sha1write(f, &offset, 4); sha1write(f, (*c)->sha1, sizeof((*c)->sha1)); - SHA1_Update(&ctx, (*c)->sha1, 20); + git_SHA1_Update(&ctx, (*c)->sha1, 20); } sha1write(f, pack_data->sha1, sizeof(pack_data->sha1)); sha1close(f, NULL, CSUM_FSYNC); free(idx); - SHA1_Final(pack_data->sha1, &ctx); + git_SHA1_Final(pack_data->sha1, &ctx); return tmpfile; } @@ -1033,15 +1033,15 @@ static int store_object( unsigned char hdr[96]; unsigned char sha1[20]; unsigned long hdrlen, deltalen; - SHA_CTX c; + git_SHA_CTX c; z_stream s; hdrlen = sprintf((char*)hdr,"%s %lu", typename(type), (unsigned long)dat->len) + 1; - SHA1_Init(&c); - SHA1_Update(&c, hdr, hdrlen); - SHA1_Update(&c, dat->buf, dat->len); - SHA1_Final(sha1, &c); + git_SHA1_Init(&c); + git_SHA1_Update(&c, hdr, hdrlen); + git_SHA1_Update(&c, dat->buf, dat->len); + git_SHA1_Final(sha1, &c); if (sha1out) hashcpy(sha1out, sha1); diff --git a/http-push.c b/http-push.c index c9dd9a1f64..42f4d78e54 100644 --- a/http-push.c +++ b/http-push.c @@ -126,7 +126,7 @@ struct transfer_request char errorstr[CURL_ERROR_SIZE]; long http_code; unsigned char real_sha1[20]; - SHA_CTX c; + git_SHA_CTX c; z_stream stream; int zret; int rename; @@ -209,7 +209,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, request->stream.next_out = expn; request->stream.avail_out = sizeof(expn); request->zret = inflate(&request->stream, Z_SYNC_FLUSH); - SHA1_Update(&request->c, expn, + git_SHA1_Update(&request->c, expn, sizeof(expn) - request->stream.avail_out); } while (request->stream.avail_in && request->zret == Z_OK); data_received++; @@ -270,7 +270,7 @@ static void start_fetch_loose(struct transfer_request *request) inflateInit(&request->stream); - SHA1_Init(&request->c); + git_SHA1_Init(&request->c); url = xmalloc(strlen(remote->url) + 50); request->url = xmalloc(strlen(remote->url) + 50); @@ -310,7 +310,7 @@ static void start_fetch_loose(struct transfer_request *request) if (prev_read == -1) { memset(&request->stream, 0, sizeof(request->stream)); inflateInit(&request->stream); - SHA1_Init(&request->c); + git_SHA1_Init(&request->c); if (prev_posn>0) { prev_posn = 0; lseek(request->local_fileno, 0, SEEK_SET); @@ -742,7 +742,7 @@ static void finish_request(struct transfer_request *request) fprintf(stderr, "Warning: requested range invalid; we may already have all the data.\n"); inflateEnd(&request->stream); - SHA1_Final(request->real_sha1, &request->c); + git_SHA1_Final(request->real_sha1, &request->c); if (request->zret != Z_STREAM_END) { unlink(request->tmpfile); } else if (hashcmp(request->obj->sha1, request->real_sha1)) { diff --git a/http-walker.c b/http-walker.c index 9dc6b27b45..7271c7d19d 100644 --- a/http-walker.c +++ b/http-walker.c @@ -36,7 +36,7 @@ struct object_request char errorstr[CURL_ERROR_SIZE]; long http_code; unsigned char real_sha1[20]; - SHA_CTX c; + git_SHA_CTX c; z_stream stream; int zret; int rename; @@ -83,7 +83,7 @@ static size_t fwrite_sha1_file(void *ptr, size_t eltsize, size_t nmemb, obj_req->stream.next_out = expn; obj_req->stream.avail_out = sizeof(expn); obj_req->zret = inflate(&obj_req->stream, Z_SYNC_FLUSH); - SHA1_Update(&obj_req->c, expn, + git_SHA1_Update(&obj_req->c, expn, sizeof(expn) - obj_req->stream.avail_out); } while (obj_req->stream.avail_in && obj_req->zret == Z_OK); data_received++; @@ -144,7 +144,7 @@ static void start_object_request(struct walker *walker, inflateInit(&obj_req->stream); - SHA1_Init(&obj_req->c); + git_SHA1_Init(&obj_req->c); url = xmalloc(strlen(obj_req->repo->base) + 51); obj_req->url = xmalloc(strlen(obj_req->repo->base) + 51); @@ -184,7 +184,7 @@ static void start_object_request(struct walker *walker, if (prev_read == -1) { memset(&obj_req->stream, 0, sizeof(obj_req->stream)); inflateInit(&obj_req->stream); - SHA1_Init(&obj_req->c); + git_SHA1_Init(&obj_req->c); if (prev_posn>0) { prev_posn = 0; lseek(obj_req->local, 0, SEEK_SET); @@ -244,7 +244,7 @@ static void finish_object_request(struct object_request *obj_req) } inflateEnd(&obj_req->stream); - SHA1_Final(obj_req->real_sha1, &obj_req->c); + git_SHA1_Final(obj_req->real_sha1, &obj_req->c); if (obj_req->zret != Z_STREAM_END) { unlink(obj_req->tmpfile); return; diff --git a/index-pack.c b/index-pack.c index 530d820370..2e4c0885f2 100644 --- a/index-pack.c +++ b/index-pack.c @@ -67,7 +67,7 @@ static struct progress *progress; static unsigned char input_buffer[4096]; static unsigned int input_offset, input_len; static off_t consumed_bytes; -static SHA_CTX input_ctx; +static git_SHA_CTX input_ctx; static uint32_t input_crc32; static int input_fd, output_fd, pack_fd; @@ -119,7 +119,7 @@ static void flush(void) if (input_offset) { if (output_fd >= 0) write_or_die(output_fd, input_buffer, input_offset); - SHA1_Update(&input_ctx, input_buffer, input_offset); + git_SHA1_Update(&input_ctx, input_buffer, input_offset); memmove(input_buffer, input_buffer + input_offset, input_len); input_offset = 0; } @@ -188,7 +188,7 @@ static char *open_pack_file(char *pack_name) output_fd = -1; pack_fd = input_fd; } - SHA1_Init(&input_ctx); + git_SHA1_Init(&input_ctx); return pack_name; } @@ -588,7 +588,7 @@ static void parse_pack_objects(unsigned char *sha1) /* Check pack integrity */ flush(); - SHA1_Final(sha1, &input_ctx); + git_SHA1_Final(sha1, &input_ctx); if (hashcmp(fill(20), sha1)) die("pack is corrupted (SHA1 mismatch)"); use(20); diff --git a/mozilla-sha1/sha1.c b/mozilla-sha1/sha1.c index 3f06b83567..95a4ebf496 100644 --- a/mozilla-sha1/sha1.c +++ b/mozilla-sha1/sha1.c @@ -35,9 +35,9 @@ #include "sha1.h" -static void shaHashBlock(SHA_CTX *ctx); +static void shaHashBlock(moz_SHA_CTX *ctx); -void SHA1_Init(SHA_CTX *ctx) { +void moz_SHA1_Init(moz_SHA_CTX *ctx) { int i; ctx->lenW = 0; @@ -56,7 +56,7 @@ void SHA1_Init(SHA_CTX *ctx) { } -void SHA1_Update(SHA_CTX *ctx, const void *_dataIn, int len) { +void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *_dataIn, int len) { const unsigned char *dataIn = _dataIn; int i; @@ -75,7 +75,7 @@ void SHA1_Update(SHA_CTX *ctx, const void *_dataIn, int len) { } -void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx) { +void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx) { unsigned char pad0x80 = 0x80; unsigned char pad0x00 = 0x00; unsigned char padlen[8]; @@ -91,10 +91,10 @@ void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx) { padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); - SHA1_Update(ctx, &pad0x80, 1); + moz_SHA1_Update(ctx, &pad0x80, 1); while (ctx->lenW != 56) - SHA1_Update(ctx, &pad0x00, 1); - SHA1_Update(ctx, padlen, 8); + moz_SHA1_Update(ctx, &pad0x00, 1); + moz_SHA1_Update(ctx, padlen, 8); /* Output hash */ @@ -106,13 +106,13 @@ void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx) { /* * Re-initialize the context (also zeroizes contents) */ - SHA1_Init(ctx); + moz_SHA1_Init(ctx); } #define SHA_ROT(X,n) (((X) << (n)) | ((X) >> (32-(n)))) -static void shaHashBlock(SHA_CTX *ctx) { +static void shaHashBlock(moz_SHA_CTX *ctx) { int t; unsigned int A,B,C,D,E,TEMP; diff --git a/mozilla-sha1/sha1.h b/mozilla-sha1/sha1.h index 16f2d3d43c..aa48a46cf7 100644 --- a/mozilla-sha1/sha1.h +++ b/mozilla-sha1/sha1.h @@ -38,8 +38,13 @@ typedef struct { unsigned int W[80]; int lenW; unsigned int sizeHi,sizeLo; -} SHA_CTX; +} moz_SHA_CTX; -void SHA1_Init(SHA_CTX *ctx); -void SHA1_Update(SHA_CTX *ctx, const void *dataIn, int len); -void SHA1_Final(unsigned char hashout[20], SHA_CTX *ctx); +void moz_SHA1_Init(moz_SHA_CTX *ctx); +void moz_SHA1_Update(moz_SHA_CTX *ctx, const void *dataIn, int len); +void moz_SHA1_Final(unsigned char hashout[20], moz_SHA_CTX *ctx); + +#define git_SHA_CTX moz_SHA_CTX +#define git_SHA1_Init moz_SHA1_Init +#define git_SHA1_Update moz_SHA1_Update +#define git_SHA1_Final moz_SHA1_Final diff --git a/pack-check.c b/pack-check.c index f596bf2db5..90c33b1b84 100644 --- a/pack-check.c +++ b/pack-check.c @@ -47,7 +47,7 @@ static int verify_packfile(struct packed_git *p, { off_t index_size = p->index_size; const unsigned char *index_base = p->index_data; - SHA_CTX ctx; + git_SHA_CTX ctx; unsigned char sha1[20], *pack_sig; off_t offset = 0, pack_sig_ofs = p->pack_size - 20; uint32_t nr_objects, i; @@ -60,16 +60,16 @@ static int verify_packfile(struct packed_git *p, * immediately. */ - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); while (offset < pack_sig_ofs) { unsigned int remaining; unsigned char *in = use_pack(p, w_curs, offset, &remaining); offset += remaining; if (offset > pack_sig_ofs) remaining -= (unsigned int)(offset - pack_sig_ofs); - SHA1_Update(&ctx, in, remaining); + git_SHA1_Update(&ctx, in, remaining); } - SHA1_Final(sha1, &ctx); + git_SHA1_Final(sha1, &ctx); pack_sig = use_pack(p, w_curs, pack_sig_ofs, NULL); if (hashcmp(sha1, pack_sig)) err = error("%s SHA1 checksum mismatch", @@ -135,7 +135,7 @@ int verify_pack(struct packed_git *p) { off_t index_size; const unsigned char *index_base; - SHA_CTX ctx; + git_SHA_CTX ctx; unsigned char sha1[20]; int err = 0; struct pack_window *w_curs = NULL; @@ -146,9 +146,9 @@ int verify_pack(struct packed_git *p) index_base = p->index_data; /* Verify SHA1 sum of the index file */ - SHA1_Init(&ctx); - SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20)); - SHA1_Final(sha1, &ctx); + git_SHA1_Init(&ctx); + git_SHA1_Update(&ctx, index_base, (unsigned int)(index_size - 20)); + git_SHA1_Final(sha1, &ctx); if (hashcmp(sha1, index_base + index_size - 20)) err = error("Packfile index for %s SHA1 mismatch", p->pack_name); diff --git a/pack-write.c b/pack-write.c index 3621f1dd32..b426006c58 100644 --- a/pack-write.c +++ b/pack-write.c @@ -25,7 +25,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, off_t last_obj_offset = 0; uint32_t array[256]; int i, fd; - SHA_CTX ctx; + git_SHA_CTX ctx; uint32_t index_version; if (nr_objects) { @@ -86,7 +86,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, sha1write(f, array, 256 * 4); /* compute the SHA1 hash of sorted object names. */ - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); /* * Write the actual SHA1 entries.. @@ -99,7 +99,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, sha1write(f, &offset, 4); } sha1write(f, obj->sha1, 20); - SHA1_Update(&ctx, obj->sha1, 20); + git_SHA1_Update(&ctx, obj->sha1, 20); } if (index_version >= 2) { @@ -140,7 +140,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, sha1write(f, sha1, 20); sha1close(f, NULL, CSUM_FSYNC); - SHA1_Final(sha1, &ctx); + git_SHA1_Final(sha1, &ctx); return index_name; } @@ -168,12 +168,12 @@ void fixup_pack_header_footer(int pack_fd, off_t partial_pack_offset) { int aligned_sz, buf_sz = 8 * 1024; - SHA_CTX old_sha1_ctx, new_sha1_ctx; + git_SHA_CTX old_sha1_ctx, new_sha1_ctx; struct pack_header hdr; char *buf; - SHA1_Init(&old_sha1_ctx); - SHA1_Init(&new_sha1_ctx); + git_SHA1_Init(&old_sha1_ctx); + git_SHA1_Init(&new_sha1_ctx); if (lseek(pack_fd, 0, SEEK_SET) != 0) die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); @@ -181,9 +181,9 @@ void fixup_pack_header_footer(int pack_fd, die("Unable to reread header of %s: %s", pack_name, strerror(errno)); if (lseek(pack_fd, 0, SEEK_SET) != 0) die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); - SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr)); + git_SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr)); hdr.hdr_entries = htonl(object_count); - SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr)); + git_SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr)); write_or_die(pack_fd, &hdr, sizeof(hdr)); partial_pack_offset -= sizeof(hdr); @@ -198,7 +198,7 @@ void fixup_pack_header_footer(int pack_fd, break; if (n < 0) die("Failed to checksum %s: %s", pack_name, strerror(errno)); - SHA1_Update(&new_sha1_ctx, buf, n); + git_SHA1_Update(&new_sha1_ctx, buf, n); aligned_sz -= n; if (!aligned_sz) @@ -207,11 +207,11 @@ void fixup_pack_header_footer(int pack_fd, if (!partial_pack_sha1) continue; - SHA1_Update(&old_sha1_ctx, buf, n); + git_SHA1_Update(&old_sha1_ctx, buf, n); partial_pack_offset -= n; if (partial_pack_offset == 0) { unsigned char sha1[20]; - SHA1_Final(sha1, &old_sha1_ctx); + git_SHA1_Final(sha1, &old_sha1_ctx); if (hashcmp(sha1, partial_pack_sha1) != 0) die("Unexpected checksum for %s " "(disk corruption?)", pack_name); @@ -220,7 +220,7 @@ void fixup_pack_header_footer(int pack_fd, * pack, which also means making partial_pack_offset * big enough not to matter anymore. */ - SHA1_Init(&old_sha1_ctx); + git_SHA1_Init(&old_sha1_ctx); partial_pack_offset = ~partial_pack_offset; partial_pack_offset -= MSB(partial_pack_offset, 1); } @@ -228,8 +228,8 @@ void fixup_pack_header_footer(int pack_fd, free(buf); if (partial_pack_sha1) - SHA1_Final(partial_pack_sha1, &old_sha1_ctx); - SHA1_Final(new_pack_sha1, &new_sha1_ctx); + git_SHA1_Final(partial_pack_sha1, &old_sha1_ctx); + git_SHA1_Final(new_pack_sha1, &new_sha1_ctx); write_or_die(pack_fd, new_pack_sha1, 20); fsync_or_die(pack_fd, pack_name); } diff --git a/patch-id.c b/patch-id.c index 9349bc5580..871f1d20c0 100644 --- a/patch-id.c +++ b/patch-id.c @@ -1,6 +1,6 @@ #include "cache.h" -static void flush_current_id(int patchlen, unsigned char *id, SHA_CTX *c) +static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c) { unsigned char result[20]; char name[50]; @@ -8,10 +8,10 @@ static void flush_current_id(int patchlen, unsigned char *id, SHA_CTX *c) if (!patchlen) return; - SHA1_Final(result, c); + git_SHA1_Final(result, c); memcpy(name, sha1_to_hex(id), 41); printf("%s %s\n", sha1_to_hex(result), name); - SHA1_Init(c); + git_SHA1_Init(c); } static int remove_space(char *line) @@ -31,10 +31,10 @@ static void generate_id_list(void) { static unsigned char sha1[20]; static char line[1000]; - SHA_CTX ctx; + git_SHA_CTX ctx; int patchlen = 0; - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); while (fgets(line, sizeof(line), stdin) != NULL) { unsigned char n[20]; char *p = line; @@ -67,7 +67,7 @@ static void generate_id_list(void) /* Compute the sha without whitespace */ len = remove_space(line); patchlen += len; - SHA1_Update(&ctx, line, len); + git_SHA1_Update(&ctx, line, len); } flush_current_id(patchlen, sha1, &ctx); } diff --git a/ppc/sha1.c b/ppc/sha1.c index 738e36c1e8..ec6a1926d4 100644 --- a/ppc/sha1.c +++ b/ppc/sha1.c @@ -10,10 +10,10 @@ #include #include "sha1.h" -extern void sha1_core(uint32_t *hash, const unsigned char *p, - unsigned int nblocks); +extern void ppc_sha1_core(uint32_t *hash, const unsigned char *p, + unsigned int nblocks); -int SHA1_Init(SHA_CTX *c) +int ppc_SHA1_Init(ppc_SHA_CTX *c) { c->hash[0] = 0x67452301; c->hash[1] = 0xEFCDAB89; @@ -25,7 +25,7 @@ int SHA1_Init(SHA_CTX *c) return 0; } -int SHA1_Update(SHA_CTX *c, const void *ptr, unsigned long n) +int ppc_SHA1_Update(ppc_SHA_CTX *c, const void *ptr, unsigned long n) { unsigned long nb; const unsigned char *p = ptr; @@ -38,12 +38,12 @@ int SHA1_Update(SHA_CTX *c, const void *ptr, unsigned long n) nb = n; memcpy(&c->buf.b[c->cnt], p, nb); if ((c->cnt += nb) == 64) { - sha1_core(c->hash, c->buf.b, 1); + ppc_sha1_core(c->hash, c->buf.b, 1); c->cnt = 0; } } else { nb = n >> 6; - sha1_core(c->hash, p, nb); + ppc_sha1_core(c->hash, p, nb); nb <<= 6; } n -= nb; @@ -52,7 +52,7 @@ int SHA1_Update(SHA_CTX *c, const void *ptr, unsigned long n) return 0; } -int SHA1_Final(unsigned char *hash, SHA_CTX *c) +int ppc_SHA1_Final(unsigned char *hash, ppc_SHA_CTX *c) { unsigned int cnt = c->cnt; @@ -60,13 +60,13 @@ int SHA1_Final(unsigned char *hash, SHA_CTX *c) if (cnt > 56) { if (cnt < 64) memset(&c->buf.b[cnt], 0, 64 - cnt); - sha1_core(c->hash, c->buf.b, 1); + ppc_sha1_core(c->hash, c->buf.b, 1); cnt = 0; } if (cnt < 56) memset(&c->buf.b[cnt], 0, 56 - cnt); c->buf.l[7] = c->len; - sha1_core(c->hash, c->buf.b, 1); + ppc_sha1_core(c->hash, c->buf.b, 1); memcpy(hash, c->hash, 20); return 0; } diff --git a/ppc/sha1.h b/ppc/sha1.h index c3c51aa4d4..c405f734c2 100644 --- a/ppc/sha1.h +++ b/ppc/sha1.h @@ -5,7 +5,7 @@ */ #include -typedef struct sha_context { +typedef struct { uint32_t hash[5]; uint32_t cnt; uint64_t len; @@ -13,8 +13,13 @@ typedef struct sha_context { unsigned char b[64]; uint64_t l[8]; } buf; -} SHA_CTX; +} ppc_SHA_CTX; -int SHA1_Init(SHA_CTX *c); -int SHA1_Update(SHA_CTX *c, const void *p, unsigned long n); -int SHA1_Final(unsigned char *hash, SHA_CTX *c); +int ppc_SHA1_Init(ppc_SHA_CTX *c); +int ppc_SHA1_Update(ppc_SHA_CTX *c, const void *p, unsigned long n); +int ppc_SHA1_Final(unsigned char *hash, ppc_SHA_CTX *c); + +#define git_SHA_CTX ppc_SHA_CTX +#define git_SHA1_Init ppc_SHA1_Init +#define git_SHA1_Update ppc_SHA1_Update +#define git_SHA1_Final ppc_SHA1_Final diff --git a/ppc/sha1ppc.S b/ppc/sha1ppc.S index f132696ee7..1711eef6e7 100644 --- a/ppc/sha1ppc.S +++ b/ppc/sha1ppc.S @@ -162,8 +162,8 @@ add RE(t),RE(t),%r0; rotlwi RB(t),RB(t),30 STEPUP4(fn, (t)+12, (s)+12,); \ STEPUP4(fn, (t)+16, (s)+16, loadk) - .globl sha1_core -sha1_core: + .globl ppc_sha1_core +ppc_sha1_core: stwu %r1,-80(%r1) stmw %r13,4(%r1) diff --git a/read-cache.c b/read-cache.c index 5b1b3ad03b..901064bf1a 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1072,16 +1072,16 @@ struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really) static int verify_hdr(struct cache_header *hdr, unsigned long size) { - SHA_CTX c; + git_SHA_CTX c; unsigned char sha1[20]; if (hdr->hdr_signature != htonl(CACHE_SIGNATURE)) return error("bad signature"); if (hdr->hdr_version != htonl(2)) return error("bad index version"); - SHA1_Init(&c); - SHA1_Update(&c, hdr, size - 20); - SHA1_Final(sha1, &c); + git_SHA1_Init(&c); + git_SHA1_Update(&c, hdr, size - 20); + git_SHA1_Final(sha1, &c); if (hashcmp(sha1, (unsigned char *)hdr + size - 20)) return error("bad index file sha1 signature"); return 0; @@ -1278,11 +1278,11 @@ int unmerged_index(const struct index_state *istate) static unsigned char write_buffer[WRITE_BUFFER_SIZE]; static unsigned long write_buffer_len; -static int ce_write_flush(SHA_CTX *context, int fd) +static int ce_write_flush(git_SHA_CTX *context, int fd) { unsigned int buffered = write_buffer_len; if (buffered) { - SHA1_Update(context, write_buffer, buffered); + git_SHA1_Update(context, write_buffer, buffered); if (write_in_full(fd, write_buffer, buffered) != buffered) return -1; write_buffer_len = 0; @@ -1290,7 +1290,7 @@ static int ce_write_flush(SHA_CTX *context, int fd) return 0; } -static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len) +static int ce_write(git_SHA_CTX *context, int fd, void *data, unsigned int len) { while (len) { unsigned int buffered = write_buffer_len; @@ -1312,7 +1312,7 @@ static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len) return 0; } -static int write_index_ext_header(SHA_CTX *context, int fd, +static int write_index_ext_header(git_SHA_CTX *context, int fd, unsigned int ext, unsigned int sz) { ext = htonl(ext); @@ -1321,13 +1321,13 @@ static int write_index_ext_header(SHA_CTX *context, int fd, (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0; } -static int ce_flush(SHA_CTX *context, int fd) +static int ce_flush(git_SHA_CTX *context, int fd) { unsigned int left = write_buffer_len; if (left) { write_buffer_len = 0; - SHA1_Update(context, write_buffer, left); + git_SHA1_Update(context, write_buffer, left); } /* Flush first if not enough space for SHA1 signature */ @@ -1338,7 +1338,7 @@ static int ce_flush(SHA_CTX *context, int fd) } /* Append the SHA1 signature at the end */ - SHA1_Final(write_buffer + left, context); + git_SHA1_Final(write_buffer + left, context); left += 20; return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0; } @@ -1392,7 +1392,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce) } } -static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce) +static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce) { int size = ondisk_ce_size(ce); struct ondisk_cache_entry *ondisk = xcalloc(1, size); @@ -1416,7 +1416,7 @@ static int ce_write_entry(SHA_CTX *c, int fd, struct cache_entry *ce) int write_index(const struct index_state *istate, int newfd) { - SHA_CTX c; + git_SHA_CTX c; struct cache_header hdr; int i, err, removed; struct cache_entry **cache = istate->cache; @@ -1430,7 +1430,7 @@ int write_index(const struct index_state *istate, int newfd) hdr.hdr_version = htonl(2); hdr.hdr_entries = htonl(entries - removed); - SHA1_Init(&c); + git_SHA1_Init(&c); if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0) return -1; diff --git a/rerere.c b/rerere.c index 8447caeebc..121f911414 100644 --- a/rerere.c +++ b/rerere.c @@ -73,7 +73,7 @@ static int write_rr(struct string_list *rr, int out_fd) static int handle_file(const char *path, unsigned char *sha1, const char *output) { - SHA_CTX ctx; + git_SHA_CTX ctx; char buf[1024]; int hunk_no = 0; enum { @@ -95,7 +95,7 @@ static int handle_file(const char *path, } if (sha1) - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); strbuf_init(&one, 0); strbuf_init(&two, 0); @@ -127,9 +127,9 @@ static int handle_file(const char *path, fputs(">>>>>>>\n", out); } if (sha1) { - SHA1_Update(&ctx, one.buf ? one.buf : "", + git_SHA1_Update(&ctx, one.buf ? one.buf : "", one.len + 1); - SHA1_Update(&ctx, two.buf ? two.buf : "", + git_SHA1_Update(&ctx, two.buf ? two.buf : "", two.len + 1); } strbuf_reset(&one); @@ -154,7 +154,7 @@ static int handle_file(const char *path, if (out) fclose(out); if (sha1) - SHA1_Final(sha1, &ctx); + git_SHA1_Final(sha1, &ctx); if (hunk != RR_CONTEXT) { if (output) unlink(output); diff --git a/sha1_file.c b/sha1_file.c index 70ff904717..7515987868 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2132,16 +2132,16 @@ static void write_sha1_file_prepare(const void *buf, unsigned long len, const char *type, unsigned char *sha1, char *hdr, int *hdrlen) { - SHA_CTX c; + git_SHA_CTX c; /* Generate the header */ *hdrlen = sprintf(hdr, "%s %lu", type, len)+1; /* Sha1.. */ - SHA1_Init(&c); - SHA1_Update(&c, hdr, *hdrlen); - SHA1_Update(&c, buf, len); - SHA1_Final(sha1, &c); + git_SHA1_Init(&c); + git_SHA1_Update(&c, hdr, *hdrlen); + git_SHA1_Update(&c, buf, len); + git_SHA1_Final(sha1, &c); } /* diff --git a/test-sha1.c b/test-sha1.c index 78d7e983a7..9b98d07c78 100644 --- a/test-sha1.c +++ b/test-sha1.c @@ -2,7 +2,7 @@ int main(int ac, char **av) { - SHA_CTX ctx; + git_SHA_CTX ctx; unsigned char sha1[20]; unsigned bufsz = 8192; char *buffer; @@ -20,7 +20,7 @@ int main(int ac, char **av) die("OOPS"); } - SHA1_Init(&ctx); + git_SHA1_Init(&ctx); while (1) { ssize_t sz, this_sz; @@ -39,9 +39,9 @@ int main(int ac, char **av) } if (this_sz == 0) break; - SHA1_Update(&ctx, buffer, this_sz); + git_SHA1_Update(&ctx, buffer, this_sz); } - SHA1_Final(sha1, &ctx); + git_SHA1_Final(sha1, &ctx); puts(sha1_to_hex(sha1)); exit(0); } -- cgit v1.3 From 71b989e7dd1dcf891369319cfeda0ed8b6a152e1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 5 Oct 2008 15:35:15 -0400 Subject: fix bogus "diff --git" header from "diff --no-index" When "git diff --no-index" is given an absolute pathname, it would generate a diff header with the absolute path prepended by the prefix, like: diff --git a/dev/null b/foo Not only is this nonsensical, and not only does it violate the description of diffs given in git-diff(1), but it would produce broken binary diffs. Unlike text diffs, the binary diffs don't contain the filenames anywhere else, and so "git apply" relies on this header to figure out the filename. This patch just refuses to use an invalid name for anything visible in the diff. Now, this fixes the "git diff --no-index --binary a /dev/null" kind of case (and we'll end up using "a" as the basename), but some other insane cases are impossible to handle. If you do git diff --no-index --binary a /bin/echo you'll still get a patch like diff --git a/a b/bin/echo old mode 100644 new mode 100755 index ... and "git apply" will refuse to apply it for a couple of reasons, and the diff is simply bogus. And that, btw, is no longer a bug, I think. It's impossible to know whethe the user meant for the patch to be a rename or not. And as such, refusing to apply it because you don't know what name you should use is probably _exactly_ the right thing to do! Original problem reported by Imre Deak. Test script and problem description by Jeff King. Signed-off-by: Jeff King Signed-off-by: Linus Torvalds Signed-off-by: Shawn O. Pearce --- diff.c | 4 ++++ t/t4012-diff-binary.sh | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 781fa15ac1..f91f256c56 100644 --- a/diff.c +++ b/diff.c @@ -1465,6 +1465,10 @@ static void builtin_diff(const char *name_a, const char *set = diff_get_color_opt(o, DIFF_METAINFO); const char *reset = diff_get_color_opt(o, DIFF_RESET); + /* Never use a non-valid filename anywhere if at all possible */ + name_a = DIFF_FILE_VALID(one) ? name_a : name_b; + name_b = DIFF_FILE_VALID(two) ? name_b : name_a; + a_one = quote_two(o->a_prefix, name_a + (*name_a == '/')); b_two = quote_two(o->b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index 64c372a025..eac12712db 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -77,4 +77,25 @@ test_expect_success 'apply binary patch' \ tree1=`git write-tree` && test "$tree1" = "$tree0"' +q_to_nul() { + perl -pe 'y/Q/\000/' +} + +nul_to_q() { + perl -pe 'y/\000/Q/' +} + +test_expect_success 'diff --no-index with binary creation' ' + echo Q | q_to_nul >binary && + (:# hide error code from diff, which just indicates differences + git diff --binary --no-index /dev/null binary >current || + true + ) && + rm binary && + git apply --binary expected && + nul_to_q actual && + test_cmp expected actual +' + test_done -- cgit v1.3 From 5d1e958e2467ef295637844fd85be7a8ab187ef1 Mon Sep 17 00:00:00 2001 From: Jonathan del Strother Date: Wed, 1 Oct 2008 00:46:34 +0100 Subject: Teach git diff about Objective-C syntax Add support for recognition of Objective-C class & instance methods, C functions, and class implementation/interfaces. Signed-off-by: Jonathan del Strother Signed-off-by: Shawn O. Pearce --- Documentation/gitattributes.txt | 2 ++ diff.c | 10 ++++++++++ 2 files changed, 12 insertions(+) (limited to 'diff.c') diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 2ae771f2fb..26945593cb 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -315,6 +315,8 @@ patterns are available: - `java` suitable for source code in the Java language. +- `objc` suitable for source code in the Objective-C language. + - `pascal` suitable for source code in the Pascal/Delphi language. - `php` suitable for source code in the PHP language. diff --git a/diff.c b/diff.c index 02e948c9dd..2af3a97487 100644 --- a/diff.c +++ b/diff.c @@ -1429,6 +1429,16 @@ static const struct funcname_pattern_entry builtin_funcname_pattern[] = { "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$", REG_EXTENDED }, + { "objc", + /* Negate C statements that can look like functions */ + "!^[ \t]*(do|for|if|else|return|switch|while)\n" + /* Objective-C methods */ + "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n" + /* C functions */ + "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n" + /* Objective-C class/protocol definitions */ + "^(@(implementation|interface|protocol)[ \t].*)$", + REG_EXTENDED }, { "pascal", "^((procedure|function|constructor|destructor|interface|" "implementation|initialization|finalization)[ \t]*.*)$" -- cgit v1.3 From f285a2d7ed6548666989406de8f0e7233eb84368 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Thu, 9 Oct 2008 14:12:12 -0500 Subject: Replace calls to strbuf_init(&foo, 0) with STRBUF_INIT initializer Many call sites use strbuf_init(&foo, 0) to initialize local strbuf variable "foo" which has not been accessed since its declaration. These can be replaced with a static initialization using the STRBUF_INIT macro which is just as readable, saves a function call, and takes up fewer lines. Signed-off-by: Brandon Casey Signed-off-by: Shawn O. Pearce --- archive-tar.c | 6 ++---- archive.c | 6 ++---- builtin-apply.c | 26 ++++++++------------------ builtin-blame.c | 3 +-- builtin-branch.c | 3 +-- builtin-cat-file.c | 3 +-- builtin-checkout-index.c | 4 +--- builtin-checkout.c | 12 ++++-------- builtin-clean.c | 6 ++---- builtin-clone.c | 9 +++------ builtin-commit.c | 15 +++++---------- builtin-fetch--tool.c | 3 +-- builtin-fmt-merge-msg.c | 4 +--- builtin-help.c | 4 +--- builtin-log.c | 13 ++++--------- builtin-merge.c | 27 +++++++++------------------ builtin-remote.c | 8 ++------ builtin-rev-list.c | 3 +-- builtin-rev-parse.c | 4 +--- builtin-show-branch.c | 3 +-- builtin-stripspace.c | 3 +-- builtin-tag.c | 3 +-- builtin-update-index.c | 10 +++------- combine-diff.c | 3 +-- config.c | 6 ++---- convert.c | 3 +-- diff.c | 15 +++++---------- editor.c | 3 +-- exec_cmd.c | 4 +--- fsck.c | 3 +-- git.c | 3 +-- graph.c | 13 ++++--------- hash-object.c | 4 +--- imap-send.c | 3 +-- log-tree.c | 3 +-- merge-recursive.c | 3 +-- mktag.c | 3 +-- mktree.c | 6 ++---- pretty.c | 3 +-- read-cache.c | 3 +-- remote.c | 3 +-- rerere.c | 4 +--- sha1_file.c | 6 ++---- walker.c | 3 +-- ws.c | 3 +-- wt-status.c | 10 +++------- 46 files changed, 91 insertions(+), 197 deletions(-) (limited to 'diff.c') diff --git a/archive-tar.c b/archive-tar.c index 13029619e5..ba890ebdec 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -124,11 +124,10 @@ static int write_tar_entry(struct archiver_args *args, unsigned int mode, void *buffer, unsigned long size) { struct ustar_header header; - struct strbuf ext_header; + struct strbuf ext_header = STRBUF_INIT; int err = 0; memset(&header, 0, sizeof(header)); - strbuf_init(&ext_header, 0); if (!sha1) { *header.typeflag = TYPEFLAG_GLOBAL_HEADER; @@ -211,10 +210,9 @@ static int write_tar_entry(struct archiver_args *args, static int write_global_extended_header(struct archiver_args *args) { const unsigned char *sha1 = args->commit_sha1; - struct strbuf ext_header; + struct strbuf ext_header = STRBUF_INIT; int err; - strbuf_init(&ext_header, 0); strbuf_append_ext_header(&ext_header, "comment", sha1_to_hex(sha1), 40); err = write_tar_entry(args, NULL, NULL, 0, 0, ext_header.buf, ext_header.len); diff --git a/archive.c b/archive.c index 44ab008039..849eed553e 100644 --- a/archive.c +++ b/archive.c @@ -29,11 +29,10 @@ static void format_subst(const struct commit *commit, struct strbuf *buf) { char *to_free = NULL; - struct strbuf fmt; + struct strbuf fmt = STRBUF_INIT; if (src == buf->buf) to_free = strbuf_detach(buf, NULL); - strbuf_init(&fmt, 0); for (;;) { const char *b, *c; @@ -65,10 +64,9 @@ static void *sha1_file_to_archive(const char *path, const unsigned char *sha1, buffer = read_sha1_file(sha1, type, sizep); if (buffer && S_ISREG(mode)) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; size_t size = 0; - strbuf_init(&buf, 0); strbuf_attach(&buf, buffer, *sizep, *sizep + 1); convert_to_working_tree(path, buf.buf, buf.len, &buf); if (commit) diff --git a/builtin-apply.c b/builtin-apply.c index bf80610506..f1f675819f 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -321,13 +321,12 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) const char *start = line; if (*line == '"') { - struct strbuf name; + struct strbuf name = STRBUF_INIT; /* * Proposed "new-style" GNU patch/diff format; see * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 */ - strbuf_init(&name, 0); if (!unquote_c_style(&name, line, NULL)) { char *cp; @@ -675,11 +674,8 @@ static char *git_header_name(char *line, int llen) if (*line == '"') { const char *cp; - struct strbuf first; - struct strbuf sp; - - strbuf_init(&first, 0); - strbuf_init(&sp, 0); + struct strbuf first = STRBUF_INIT; + struct strbuf sp = STRBUF_INIT; if (unquote_c_style(&first, line, &second)) goto free_and_fail1; @@ -741,10 +737,9 @@ static char *git_header_name(char *line, int llen) */ for (second = name; second < line + llen; second++) { if (*second == '"') { - struct strbuf sp; + struct strbuf sp = STRBUF_INIT; const char *np; - strbuf_init(&sp, 0); if (unquote_c_style(&sp, second, NULL)) goto free_and_fail2; @@ -1508,11 +1503,10 @@ static const char minuses[]= static void show_stats(struct patch *patch) { - struct strbuf qname; + struct strbuf qname = STRBUF_INIT; char *cp = patch->new_name ? patch->new_name : patch->old_name; int max, add, del; - strbuf_init(&qname, 0); quote_c_style(cp, &qname, NULL, 0); /* @@ -2292,14 +2286,12 @@ static void add_to_fn_table(struct patch *patch) static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; struct image image; size_t len; char *img; struct patch *tpatch; - strbuf_init(&buf, 0); - if (!(patch->is_copy || patch->is_rename) && ((tpatch = in_fn_table(patch->old_name)) != NULL)) { if (tpatch == (struct patch *) -1) { @@ -2779,7 +2771,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size) { int fd; - struct strbuf nbuf; + struct strbuf nbuf = STRBUF_INIT; if (S_ISGITLINK(mode)) { struct stat st; @@ -2798,7 +2790,6 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf, if (fd < 0) return -1; - strbuf_init(&nbuf, 0); if (convert_to_working_tree(path, buf, size, &nbuf)) { size = nbuf.len; buf = nbuf.buf; @@ -3060,13 +3051,12 @@ static void prefix_patches(struct patch *p) static int apply_patch(int fd, const char *filename, int options) { size_t offset; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; struct patch *list = NULL, **listp = &list; int skipped_patch = 0; /* FIXME - memory leak when using multiple patch files as inputs */ memset(&fn_table, 0, sizeof(struct string_list)); - strbuf_init(&buf, 0); patch_input_file = filename; read_patch_file(&buf, fd); offset = 0; diff --git a/builtin-blame.c b/builtin-blame.c index df537593d0..48cc0c175d 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -2062,7 +2062,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con struct commit *commit; struct origin *origin; unsigned char head_sha1[20]; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; const char *ident; time_t now; int size, len; @@ -2082,7 +2082,6 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con origin = make_origin(commit, path); - strbuf_init(&buf, 0); if (!contents_from || strcmp("-", contents_from)) { struct stat st; const char *read_from; diff --git a/builtin-branch.c b/builtin-branch.c index b1a2ad7a6b..8d634ff571 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -334,11 +334,10 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, } if (verbose) { - struct strbuf subject; + struct strbuf subject = STRBUF_INIT; const char *sub = " **** invalid ref ****"; char stat[128]; - strbuf_init(&subject, 0); stat[0] = '\0'; commit = item->commit; diff --git a/builtin-cat-file.c b/builtin-cat-file.c index 3fba6b9e74..30d00a6664 100644 --- a/builtin-cat-file.c +++ b/builtin-cat-file.c @@ -189,9 +189,8 @@ static int batch_one_object(const char *obj_name, int print_contents) static int batch_objects(int print_contents) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; - strbuf_init(&buf, 0); while (strbuf_getline(&buf, stdin, '\n') != EOF) { int error = batch_one_object(buf.buf, print_contents); if (error) diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 55b7aafe06..4ba27024c5 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -268,13 +268,11 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) } if (read_from_stdin) { - struct strbuf buf, nbuf; + struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; if (all) die("git checkout-index: don't mix '--all' and '--stdin'"); - strbuf_init(&buf, 0); - strbuf_init(&nbuf, 0); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; if (line_termination && buf.buf[0] == '"') { diff --git a/builtin-checkout.c b/builtin-checkout.c index 3762f71aae..ad04a184a2 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -310,8 +310,7 @@ static void show_local_changes(struct object *head) static void describe_detached_head(char *msg, struct commit *commit) { - struct strbuf sb; - strbuf_init(&sb, 0); + struct strbuf sb = STRBUF_INIT; parse_commit(commit); pretty_print_commit(CMIT_FMT_ONELINE, commit, &sb, 0, NULL, NULL, 0, 0); fprintf(stderr, "%s %s... %s\n", msg, @@ -360,8 +359,7 @@ struct branch_info { static void setup_branch_path(struct branch_info *branch) { - struct strbuf buf; - strbuf_init(&buf, 0); + struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, "refs/heads/"); strbuf_addstr(&buf, branch->name); branch->path = strbuf_detach(&buf, NULL); @@ -484,7 +482,7 @@ static void update_refs_for_switch(struct checkout_opts *opts, struct branch_info *old, struct branch_info *new) { - struct strbuf msg; + struct strbuf msg = STRBUF_INIT; const char *old_desc; if (opts->new_branch) { create_branch(old->name, opts->new_branch, new->name, 0, @@ -493,7 +491,6 @@ static void update_refs_for_switch(struct checkout_opts *opts, setup_branch_path(new); } - strbuf_init(&msg, 0); old_desc = old->name; if (!old_desc) old_desc = sha1_to_hex(old->commit->object.sha1); @@ -738,8 +735,7 @@ no_reference: } if (opts.new_branch) { - struct strbuf buf; - strbuf_init(&buf, 0); + struct strbuf buf = STRBUF_INIT; strbuf_addstr(&buf, "refs/heads/"); strbuf_addstr(&buf, opts.new_branch); if (!get_sha1(buf.buf, rev)) diff --git a/builtin-clean.c b/builtin-clean.c index 48bf29f40a..f78c2fb108 100644 --- a/builtin-clean.c +++ b/builtin-clean.c @@ -31,11 +31,11 @@ int cmd_clean(int argc, const char **argv, const char *prefix) int i; int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0; int ignored_only = 0, baselen = 0, config_set = 0, errors = 0; - struct strbuf directory; + struct strbuf directory = STRBUF_INIT; struct dir_struct dir; const char *path, *base; static const char **pathspec; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; const char *qname; char *seen = NULL; struct option options[] = { @@ -58,7 +58,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, options, builtin_clean_usage, 0); - strbuf_init(&buf, 0); memset(&dir, 0, sizeof(dir)); if (ignored_only) dir.show_ignored = 1; @@ -88,7 +87,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix) if (baselen) path = base = xmemdupz(*pathspec, baselen); read_directory(&dir, path, base, baselen, pathspec); - strbuf_init(&directory, 0); if (pathspec) seen = xmalloc(argc > 0 ? argc : 1); diff --git a/builtin-clone.c b/builtin-clone.c index 49d2eb9c2b..1ddc14b9c7 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -264,10 +264,9 @@ pid_t junk_pid; static void remove_junk(void) { - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; if (getpid() != junk_pid) return; - strbuf_init(&sb, 0); if (junk_git_dir) { strbuf_addstr(&sb, junk_git_dir); remove_dir_recursively(&sb, 0); @@ -354,7 +353,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) char *path, *dir; const struct ref *refs, *head_points_at, *remote_head, *mapped_refs; char branch_top[256], key[256], value[256]; - struct strbuf reflog_msg; + struct strbuf reflog_msg = STRBUF_INIT; struct transport *transport = NULL; char *src_ref_prefix = "refs/heads/"; @@ -404,7 +403,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (!stat(dir, &buf)) die("destination directory '%s' already exists.", dir); - strbuf_init(&reflog_msg, 0); strbuf_addf(&reflog_msg, "clone: from %s", repo); if (option_bare) @@ -526,7 +524,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) create_symref("HEAD", head_points_at->name, NULL); if (!option_bare) { - struct strbuf head_ref; + struct strbuf head_ref = STRBUF_INIT; const char *head = head_points_at->name; if (!prefixcmp(head, "refs/heads/")) @@ -539,7 +537,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) head_points_at->old_sha1, NULL, 0, DIE_ON_ERR); - strbuf_init(&head_ref, 0); strbuf_addstr(&head_ref, branch_top); strbuf_addstr(&head_ref, "HEAD"); diff --git a/builtin-commit.c b/builtin-commit.c index b920257524..a2755dc3be 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -448,7 +448,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) { struct stat statbuf; int commitable, saved_color_setting; - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; char *buffer; FILE *fp; const char *hook_arg1 = NULL; @@ -458,7 +458,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix) if (!no_verify && run_hook(index_file, "pre-commit", NULL)) return 0; - strbuf_init(&sb, 0); if (message.len) { strbuf_addbuf(&sb, &message); hook_arg1 = "message"; @@ -511,10 +510,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix) stripspace(&sb, 0); if (signoff) { - struct strbuf sob; + struct strbuf sob = STRBUF_INIT; int i; - strbuf_init(&sob, 0); strbuf_addstr(&sob, sign_off_header); strbuf_addstr(&sob, fmt_name(getenv("GIT_COMMITTER_NAME"), getenv("GIT_COMMITTER_EMAIL"))); @@ -672,7 +670,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) */ static int message_is_empty(struct strbuf *sb) { - struct strbuf tmpl; + struct strbuf tmpl = STRBUF_INIT; const char *nl; int eol, i, start = 0; @@ -680,7 +678,6 @@ static int message_is_empty(struct strbuf *sb) return 0; /* See if the template is just a prefix of the message. */ - strbuf_init(&tmpl, 0); if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) { stripspace(&tmpl, cleanup_mode == CLEANUP_ALL); if (start + tmpl.len <= sb->len && @@ -931,7 +928,7 @@ static const char commit_utf8_warn[] = int cmd_commit(int argc, const char **argv, const char *prefix) { - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; const char *index_file, *reflog_msg; char *nl, *p; unsigned char commit_sha1[20]; @@ -966,12 +963,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix) for (c = commit->parents; c; c = c->next) pptr = &commit_list_insert(c->item, pptr)->next; } else if (in_merge) { - struct strbuf m; + struct strbuf m = STRBUF_INIT; FILE *fp; reflog_msg = "commit (merge)"; pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; - strbuf_init(&m, 0); fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) die("could not open %s for reading: %s", @@ -991,7 +987,6 @@ int cmd_commit(int argc, const char **argv, const char *prefix) parents = reduce_heads(parents); /* Finally, get the commit message */ - strbuf_init(&sb, 0); if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { rollback_index_files(); die("could not read commit message"); diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c index 7460ab7fce..469b07e240 100644 --- a/builtin-fetch--tool.c +++ b/builtin-fetch--tool.c @@ -5,8 +5,7 @@ static char *get_stdin(void) { - struct strbuf buf; - strbuf_init(&buf, 0); + struct strbuf buf = STRBUF_INIT; if (strbuf_read(&buf, 0, 1024) < 0) { die("error reading standard input: %s", strerror(errno)); } diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index c6324dc795..df18f4070f 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -358,7 +358,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) }; FILE *in = stdin; - struct strbuf input, output; + struct strbuf input = STRBUF_INIT, output = STRBUF_INIT; int ret; git_config(fmt_merge_msg_config, NULL); @@ -372,10 +372,8 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) die("cannot open %s", inpath); } - strbuf_init(&input, 0); if (strbuf_read(&input, fileno(in), 0) < 0) die("could not read input file %s", strerror(errno)); - strbuf_init(&output, 0); ret = fmt_merge_msg(merge_summary, &input, &output); if (ret) diff --git a/builtin-help.c b/builtin-help.c index 64207cbfe9..f076efa921 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -322,11 +322,9 @@ static const char *cmd_to_page(const char *git_cmd) static void setup_man_path(void) { - struct strbuf new_path; + struct strbuf new_path = STRBUF_INIT; const char *old_path = getenv("MANPATH"); - strbuf_init(&new_path, 0); - /* We should always put ':' after our path. If there is no * old_path, the ':' at the end will let 'man' to try * system-wide paths after ours to find the manual page. If diff --git a/builtin-log.c b/builtin-log.c index fc5e4da822..794821f6bc 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -628,10 +628,9 @@ static void gen_message_id(struct rev_info *info, char *base) const char *committer = git_committer_info(IDENT_WARN_ON_NO_NAME); const char *email_start = strrchr(committer, '<'); const char *email_end = strrchr(committer, '>'); - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; if (!email_start || !email_end || email_start > email_end - 1) die("Could not extract email from committer identity."); - strbuf_init(&buf, 0); strbuf_addf(&buf, "%s.%lu.git.%.*s", base, (unsigned long) time(NULL), (int)(email_end - email_start - 1), email_start + 1); @@ -650,7 +649,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, const char *msg; const char *extra_headers = rev->extra_headers; struct shortlog log; - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; int i; const char *encoding = "utf-8"; struct diff_options opts; @@ -671,7 +670,6 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout, committer = git_committer_info(0); msg = body; - strbuf_init(&sb, 0); pp_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822, encoding); pp_title_line(CMIT_FMT_EMAIL, &msg, &sb, subject_start, extra_headers, @@ -753,7 +751,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) const char *in_reply_to = NULL; struct patch_ids ids; char *add_signoff = NULL; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; git_config(git_format_config, NULL); init_revisions(&rev, prefix); @@ -861,8 +859,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) } argc = j; - strbuf_init(&buf, 0); - for (i = 0; i < extra_hdr_nr; i++) { strbuf_addstr(&buf, extra_hdr[i]); strbuf_addch(&buf, '\n'); @@ -1139,8 +1135,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix) sign = '-'; if (verbose) { - struct strbuf buf; - strbuf_init(&buf, 0); + struct strbuf buf = STRBUF_INIT; pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, 0, NULL, NULL, 0, 0); printf("%c %s %s\n", sign, diff --git a/builtin-merge.c b/builtin-merge.c index 38266baf5f..5e2b7f12c3 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -226,7 +226,7 @@ static void reset_hard(unsigned const char *sha1, int verbose) static void restore_state(void) { - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; const char *args[] = { "stash", "apply", NULL, NULL }; if (is_null_sha1(stash)) @@ -234,7 +234,6 @@ static void restore_state(void) reset_hard(head, 1); - strbuf_init(&sb, 0); args[2] = sha1_to_hex(stash); /* @@ -258,7 +257,7 @@ static void squash_message(void) { struct rev_info rev; struct commit *commit; - struct strbuf out; + struct strbuf out = STRBUF_INIT; struct commit_list *j; int fd; @@ -282,7 +281,6 @@ static void squash_message(void) if (prepare_revision_walk(&rev)) die("revision walk setup failed"); - strbuf_init(&out, 0); strbuf_addstr(&out, "Squashed commit of the following:\n"); while ((commit = get_revision(&rev)) != NULL) { strbuf_addch(&out, '\n'); @@ -327,9 +325,8 @@ static int run_hook(const char *name) static void finish(const unsigned char *new_head, const char *msg) { - struct strbuf reflog_message; + struct strbuf reflog_message = STRBUF_INIT; - strbuf_init(&reflog_message, 0); if (!msg) strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION")); else { @@ -380,7 +377,7 @@ static void merge_name(const char *remote, struct strbuf *msg) { struct object *remote_head; unsigned char branch_head[20], buf_sha[20]; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; const char *ptr; int len, early; @@ -389,7 +386,6 @@ static void merge_name(const char *remote, struct strbuf *msg) if (!remote_head) die("'%s' does not point to a commit", remote); - strbuf_init(&buf, 0); strbuf_addstr(&buf, "refs/heads/"); strbuf_addstr(&buf, remote); resolve_ref(buf.buf, branch_head, 0, 0); @@ -444,10 +440,9 @@ static void merge_name(const char *remote, struct strbuf *msg) if (!strcmp(remote, "FETCH_HEAD") && !access(git_path("FETCH_HEAD"), R_OK)) { FILE *fp; - struct strbuf line; + struct strbuf line = STRBUF_INIT; char *ptr; - strbuf_init(&line, 0); fp = fopen(git_path("FETCH_HEAD"), "r"); if (!fp) die("could not open %s for reading: %s", @@ -545,7 +540,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, const char **args; int i = 0, ret; struct commit_list *j; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; int index_fd; struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); @@ -592,7 +587,6 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, } else { args = xmalloc((4 + commit_list_count(common) + commit_list_count(remoteheads)) * sizeof(char *)); - strbuf_init(&buf, 0); strbuf_addf(&buf, "merge-%s", strategy); args[i++] = buf.buf; for (j = common; j; j = j->next) @@ -847,7 +841,7 @@ static int evaluate_result(void) int cmd_merge(int argc, const char **argv, const char *prefix) { unsigned char result_tree[20]; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; const char *head_arg; int flag, head_invalid = 0, i; int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0; @@ -896,7 +890,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * Traditional format never would have "-m" so it is an * additional safety measure to check for it. */ - strbuf_init(&buf, 0); if (!have_message && is_old_style_invocation(argc, argv)) { strbuf_addstr(&merge_msg, argv[0]); @@ -926,7 +919,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) reset_hard(remote_head->sha1, 0); return 0; } else { - struct strbuf msg; + struct strbuf msg = STRBUF_INIT; /* We are invoked directly as the first-class UI. */ head_arg = "HEAD"; @@ -939,7 +932,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * codepath so we discard the error in this * loop. */ - strbuf_init(&msg, 0); for (i = 0; i < argc; i++) merge_name(argv[i], &msg); fmt_merge_msg(option_log, &msg, &merge_msg); @@ -1014,7 +1006,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) !common->next && !hashcmp(common->item->object.sha1, head)) { /* Again the most common case of merging one remote. */ - struct strbuf msg; + struct strbuf msg = STRBUF_INIT; struct object *o; char hex[41]; @@ -1024,7 +1016,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix) hex, find_unique_abbrev(remoteheads->item->object.sha1, DEFAULT_ABBREV)); - strbuf_init(&msg, 0); strbuf_addstr(&msg, "Fast forward"); if (have_message) strbuf_addstr(&msg, diff --git a/builtin-remote.c b/builtin-remote.c index 90a4e35828..6b3325dfa9 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -54,7 +54,7 @@ static int add(int argc, const char **argv) struct string_list track = { NULL, 0, 0 }; const char *master = NULL; struct remote *remote; - struct strbuf buf, buf2; + struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT; const char *name, *url; int i; @@ -81,9 +81,6 @@ static int add(int argc, const char **argv) remote->fetch_refspec_nr)) die("remote %s already exists.", name); - strbuf_init(&buf, 0); - strbuf_init(&buf2, 0); - strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name); if (!valid_fetch_refspec(buf2.buf)) die("'%s' is not a valid remote name", name); @@ -352,7 +349,7 @@ static int rm(int argc, const char **argv) OPT_END() }; struct remote *remote; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; struct known_remotes known_remotes = { NULL, NULL }; struct string_list branches = { NULL, 0, 0, 1 }; struct branches_for_remote cb_data = { NULL, &branches, &known_remotes }; @@ -368,7 +365,6 @@ static int rm(int argc, const char **argv) known_remotes.to_delete = remote; for_each_remote(add_known_remote, &known_remotes); - strbuf_init(&buf, 0); strbuf_addf(&buf, "remote.%s", remote->name); if (git_config_rename_section(buf.buf, NULL) < 1) return error("Could not remove config section '%s'", buf.buf); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index facaff288d..06cdeb7ebe 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -107,8 +107,7 @@ static void show_commit(struct commit *commit) putchar('\n'); if (revs.verbose_header && commit->buffer) { - struct strbuf buf; - strbuf_init(&buf, 0); + struct strbuf buf = STRBUF_INIT; pretty_print_commit(revs.commit_format, commit, &buf, revs.abbrev, NULL, NULL, revs.date_mode, 0); diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 9aa049ec17..81d5a6ffc9 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -307,19 +307,17 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix) OPT_END(), }; - struct strbuf sb, parsed; + struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT; const char **usage = NULL; struct option *opts = NULL; int onb = 0, osz = 0, unb = 0, usz = 0; - strbuf_init(&parsed, 0); strbuf_addstr(&parsed, "set --"); argc = parse_options(argc, argv, parseopt_opts, parseopt_usage, PARSE_OPT_KEEP_DASHDASH); if (argc < 1 || strcmp(argv[0], "--")) usage_with_options(parseopt_usage, parseopt_opts); - strbuf_init(&sb, 0); /* get the usage up to the first line with a -- on it */ for (;;) { if (strbuf_getline(&sb, stdin, '\n') == EOF) diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 233eed499d..306b850c72 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -259,11 +259,10 @@ static void join_revs(struct commit_list **list_p, static void show_one_commit(struct commit *commit, int no_name) { - struct strbuf pretty; + struct strbuf pretty = STRBUF_INIT; const char *pretty_str = "(unavailable)"; struct commit_name *name = commit->util; - strbuf_init(&pretty, 0); if (commit->object.parsed) { pretty_print_commit(CMIT_FMT_ONELINE, commit, &pretty, 0, NULL, NULL, 0, 0); diff --git a/builtin-stripspace.c b/builtin-stripspace.c index c0b21301ba..d6e3896c00 100644 --- a/builtin-stripspace.c +++ b/builtin-stripspace.c @@ -70,14 +70,13 @@ void stripspace(struct strbuf *sb, int skip_comments) int cmd_stripspace(int argc, const char **argv, const char *prefix) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; int strip_comments = 0; if (argc > 1 && (!strcmp(argv[1], "-s") || !strcmp(argv[1], "--strip-comments"))) strip_comments = 1; - strbuf_init(&buf, 0); if (strbuf_read(&buf, 0, 1024) < 0) die("could not read the input"); diff --git a/builtin-tag.c b/builtin-tag.c index f2853d08c7..b13fa34d8c 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -338,7 +338,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset) int cmd_tag(int argc, const char **argv, const char *prefix) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; unsigned char object[20], prev[20]; char ref[PATH_MAX]; const char *object_ref, *tag; @@ -388,7 +388,6 @@ int cmd_tag(int argc, const char **argv, const char *prefix) if (verify) return for_each_tag_name(argv, verify_tag); - strbuf_init(&buf, 0); if (msg.given || msgfile) { if (msg.given && msgfile) die("only one -F or -m option is allowed."); diff --git a/builtin-update-index.c b/builtin-update-index.c index 3a2291b03e..65d5775107 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -297,11 +297,9 @@ static void update_one(const char *path, const char *prefix, int prefix_length) static void read_index_info(int line_termination) { - struct strbuf buf; - struct strbuf uq; + struct strbuf buf = STRBUF_INIT; + struct strbuf uq = STRBUF_INIT; - strbuf_init(&buf, 0); - strbuf_init(&uq, 0); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { char *ptr, *tab; char *path_name; @@ -717,10 +715,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) free((char*)p); } if (read_from_stdin) { - struct strbuf buf, nbuf; + struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; - strbuf_init(&buf, 0); - strbuf_init(&nbuf, 0); setup_work_tree(); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; diff --git a/combine-diff.c b/combine-diff.c index de83c6972e..5aa1104d34 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -742,9 +742,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, /* If not a fake symlink, apply filters, e.g. autocrlf */ if (is_file) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; - strbuf_init(&buf, 0); if (convert_to_git(elem->path, result, len, &buf, safe_crlf)) { free(result); result = strbuf_detach(&buf, &len); diff --git a/config.c b/config.c index 18d305c890..b8d289d217 100644 --- a/config.c +++ b/config.c @@ -753,9 +753,8 @@ static int store_write_section(int fd, const char* key) { const char *dot; int i, success; - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; - strbuf_init(&sb, 0); dot = memchr(key, '.', store.baselen); if (dot) { strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key); @@ -780,7 +779,7 @@ static int store_write_pair(int fd, const char* key, const char* value) int i, success; int length = strlen(key + store.baselen + 1); const char *quote = ""; - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; /* * Check to see if the value needs to be surrounded with a dq pair. @@ -797,7 +796,6 @@ static int store_write_pair(int fd, const char* key, const char* value) if (i && value[i - 1] == ' ') quote = "\""; - strbuf_init(&sb, 0); strbuf_addf(&sb, "\t%.*s = %s", length, key + store.baselen + 1, quote); diff --git a/convert.c b/convert.c index 78efed800d..1816e977b7 100644 --- a/convert.c +++ b/convert.c @@ -281,7 +281,7 @@ static int apply_filter(const char *path, const char *src, size_t len, * (child --> cmd) --> us */ int ret = 1; - struct strbuf nbuf; + struct strbuf nbuf = STRBUF_INIT; struct async async; struct filter_params params; @@ -299,7 +299,6 @@ static int apply_filter(const char *path, const char *src, size_t len, if (start_async(&async)) return 0; /* error was already reported */ - strbuf_init(&nbuf, 0); if (strbuf_read(&nbuf, async.out, len) < 0) { error("read from external filter %s failed", cmd); ret = 0; diff --git a/diff.c b/diff.c index 2af3a97487..1c6be897b2 100644 --- a/diff.c +++ b/diff.c @@ -217,9 +217,8 @@ static char *quote_two(const char *one, const char *two) { int need_one = quote_c_style(one, NULL, NULL, 1); int need_two = quote_c_style(two, NULL, NULL, 1); - struct strbuf res; + struct strbuf res = STRBUF_INIT; - strbuf_init(&res, 0); if (need_one + need_two) { strbuf_addch(&res, '"'); quote_c_style(one, &res, NULL, 1); @@ -683,7 +682,7 @@ static char *pprint_rename(const char *a, const char *b) { const char *old = a; const char *new = b; - struct strbuf name; + struct strbuf name = STRBUF_INIT; int pfx_length, sfx_length; int len_a = strlen(a); int len_b = strlen(b); @@ -691,7 +690,6 @@ static char *pprint_rename(const char *a, const char *b) int qlen_a = quote_c_style(a, NULL, NULL, 0); int qlen_b = quote_c_style(b, NULL, NULL, 0); - strbuf_init(&name, 0); if (qlen_a || qlen_b) { quote_c_style(a, &name, NULL, 0); strbuf_addstr(&name, " => "); @@ -834,8 +832,7 @@ static void fill_print_name(struct diffstat_file *file) return; if (!file->is_renamed) { - struct strbuf buf; - strbuf_init(&buf, 0); + struct strbuf buf = STRBUF_INIT; if (quote_c_style(file->name, &buf, NULL, 0)) { pname = strbuf_detach(&buf, NULL); } else { @@ -1820,10 +1817,9 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int static int populate_from_stdin(struct diff_filespec *s) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; size_t size = 0; - strbuf_init(&buf, 0); if (strbuf_read(&buf, 0, 0) < 0) return error("error while reading from stdin %s", strerror(errno)); @@ -1875,7 +1871,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) if (!s->sha1_valid || reuse_worktree_file(s->path, s->sha1, 0)) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; struct stat st; int fd; @@ -1918,7 +1914,6 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) /* * Convert from working tree format to canonical git format */ - strbuf_init(&buf, 0); if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) { size_t size = 0; munmap(s->data, s->size); diff --git a/editor.c b/editor.c index eebc3e95fe..4d469d076b 100644 --- a/editor.c +++ b/editor.c @@ -26,9 +26,8 @@ int launch_editor(const char *path, struct strbuf *buffer, const char *const *en int i = 0; int failed; const char *args[6]; - struct strbuf arg0; + struct strbuf arg0 = STRBUF_INIT; - strbuf_init(&arg0, 0); if (strcspn(editor, "$ \t'") != len) { /* there are specials */ strbuf_addf(&arg0, "%s \"$@\"", editor); diff --git a/exec_cmd.c b/exec_cmd.c index ce6741eb68..cdd35f9195 100644 --- a/exec_cmd.c +++ b/exec_cmd.c @@ -59,9 +59,7 @@ static void add_path(struct strbuf *out, const char *path) void setup_path(void) { const char *old_path = getenv("PATH"); - struct strbuf new_path; - - strbuf_init(&new_path, 0); + struct strbuf new_path = STRBUF_INIT; add_path(&new_path, argv_exec_path); add_path(&new_path, getenv(EXEC_PATH_ENVIRONMENT)); diff --git a/fsck.c b/fsck.c index 797e3178ae..0cf5f012bd 100644 --- a/fsck.c +++ b/fsck.c @@ -307,9 +307,8 @@ int fsck_error_function(struct object *obj, int type, const char *fmt, ...) { va_list ap; int len; - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; - strbuf_init(&sb, 0); strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)"); va_start(ap, fmt); diff --git a/git.c b/git.c index f4b0cf611b..89feb0b6dc 100644 --- a/git.c +++ b/git.c @@ -389,10 +389,9 @@ static void handle_internal_command(int argc, const char **argv) static void execv_dashed_external(const char **argv) { - struct strbuf cmd; + struct strbuf cmd = STRBUF_INIT; const char *tmp; - strbuf_init(&cmd, 0); strbuf_addf(&cmd, "git-%s", argv[0]); /* diff --git a/graph.c b/graph.c index 5f821706c6..162a516ee1 100644 --- a/graph.c +++ b/graph.c @@ -1010,14 +1010,12 @@ int graph_is_commit_finished(struct git_graph const *graph) void graph_show_commit(struct git_graph *graph) { - struct strbuf msgbuf; + struct strbuf msgbuf = STRBUF_INIT; int shown_commit_line = 0; if (!graph) return; - strbuf_init(&msgbuf, 0); - while (!shown_commit_line) { shown_commit_line = graph_next_line(graph, &msgbuf); fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); @@ -1031,12 +1029,11 @@ void graph_show_commit(struct git_graph *graph) void graph_show_oneline(struct git_graph *graph) { - struct strbuf msgbuf; + struct strbuf msgbuf = STRBUF_INIT; if (!graph) return; - strbuf_init(&msgbuf, 0); graph_next_line(graph, &msgbuf); fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); strbuf_release(&msgbuf); @@ -1044,12 +1041,11 @@ void graph_show_oneline(struct git_graph *graph) void graph_show_padding(struct git_graph *graph) { - struct strbuf msgbuf; + struct strbuf msgbuf = STRBUF_INIT; if (!graph) return; - strbuf_init(&msgbuf, 0); graph_padding_line(graph, &msgbuf); fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); strbuf_release(&msgbuf); @@ -1057,7 +1053,7 @@ void graph_show_padding(struct git_graph *graph) int graph_show_remainder(struct git_graph *graph) { - struct strbuf msgbuf; + struct strbuf msgbuf = STRBUF_INIT; int shown = 0; if (!graph) @@ -1066,7 +1062,6 @@ int graph_show_remainder(struct git_graph *graph) if (graph_is_commit_finished(graph)) return 0; - strbuf_init(&msgbuf, 0); for (;;) { graph_next_line(graph, &msgbuf); fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); diff --git a/hash-object.c b/hash-object.c index a4d127cf78..20937ff94c 100644 --- a/hash-object.c +++ b/hash-object.c @@ -34,10 +34,8 @@ static void hash_object(const char *path, const char *type, int write_object, static void hash_stdin_paths(const char *type, int write_objects) { - struct strbuf buf, nbuf; + struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; - strbuf_init(&buf, 0); - strbuf_init(&nbuf, 0); while (strbuf_getline(&buf, stdin, '\n') != EOF) { if (buf.buf[0] == '"') { strbuf_reset(&nbuf); diff --git a/imap-send.c b/imap-send.c index af7e08c094..3703dbd1af 100644 --- a/imap-send.c +++ b/imap-send.c @@ -1266,10 +1266,9 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data, int *uid) static int read_message(FILE *f, struct msg_data *msg) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; memset(msg, 0, sizeof(*msg)); - strbuf_init(&buf, 0); do { if (strbuf_fread(&buf, CHUNKSIZE, f) <= 0) diff --git a/log-tree.c b/log-tree.c index 2c1f3e673a..cec3c06136 100644 --- a/log-tree.c +++ b/log-tree.c @@ -252,7 +252,7 @@ void log_write_email_headers(struct rev_info *opt, const char *name, void show_log(struct rev_info *opt) { - struct strbuf msgbuf; + struct strbuf msgbuf = STRBUF_INIT; struct log_info *log = opt->loginfo; struct commit *commit = log->commit, *parent = log->parent; int abbrev = opt->diffopt.abbrev; @@ -381,7 +381,6 @@ void show_log(struct rev_info *opt) /* * And then the pretty-printed message itself */ - strbuf_init(&msgbuf, 0); if (need_8bit_cte >= 0) need_8bit_cte = has_non_ascii(opt->add_signoff); pretty_print_commit(opt->commit_format, commit, &msgbuf, diff --git a/merge-recursive.c b/merge-recursive.c index 6bc3eac85c..245232a408 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -498,8 +498,7 @@ static void update_file_flags(struct merge_options *o, if (type != OBJ_BLOB) die("blob expected for %s '%s'", sha1_to_hex(sha), path); if (S_ISREG(mode)) { - struct strbuf strbuf; - strbuf_init(&strbuf, 0); + struct strbuf strbuf = STRBUF_INIT; if (convert_to_working_tree(path, buf, size, &strbuf)) { free(buf); size = strbuf.len; diff --git a/mktag.c b/mktag.c index 0b34341f71..ba3d495e07 100644 --- a/mktag.c +++ b/mktag.c @@ -153,7 +153,7 @@ static int verify_tag(char *buffer, unsigned long size) int main(int argc, char **argv) { - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; unsigned char result_sha1[20]; if (argc != 1) @@ -161,7 +161,6 @@ int main(int argc, char **argv) setup_git_directory(); - strbuf_init(&buf, 0); if (strbuf_read(&buf, 0, 4096) < 0) { die("could not read from stdin"); } diff --git a/mktree.c b/mktree.c index e0da110a98..514fd9b15a 100644 --- a/mktree.c +++ b/mktree.c @@ -65,8 +65,8 @@ static const char mktree_usage[] = "git-mktree [-z]"; int main(int ac, char **av) { - struct strbuf sb; - struct strbuf p_uq; + struct strbuf sb = STRBUF_INIT; + struct strbuf p_uq = STRBUF_INIT; unsigned char sha1[20]; int line_termination = '\n'; @@ -82,8 +82,6 @@ int main(int ac, char **av) av++; } - strbuf_init(&sb, 0); - strbuf_init(&p_uq, 0); while (strbuf_getline(&sb, stdin, line_termination) != EOF) { char *ptr, *ntr; unsigned mode; diff --git a/pretty.c b/pretty.c index 8beafa08d3..1e79943339 100644 --- a/pretty.c +++ b/pretty.c @@ -234,7 +234,7 @@ static char *get_header(const struct commit *commit, const char *key) static char *replace_encoding_header(char *buf, const char *encoding) { - struct strbuf tmp; + struct strbuf tmp = STRBUF_INIT; size_t start, len; char *cp = buf; @@ -250,7 +250,6 @@ static char *replace_encoding_header(char *buf, const char *encoding) return buf; /* should not happen but be defensive */ len = cp + 1 - (buf + start); - strbuf_init(&tmp, 0); strbuf_attach(&tmp, buf, strlen(buf), strlen(buf) + 1); if (is_encoding_utf8(encoding)) { /* we have re-coded to UTF-8; drop the header */ diff --git a/read-cache.c b/read-cache.c index 6f344f345d..c229fd4d0d 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1467,9 +1467,8 @@ int write_index(const struct index_state *istate, int newfd) /* Write extension data here */ if (istate->cache_tree) { - struct strbuf sb; + struct strbuf sb = STRBUF_INIT; - strbuf_init(&sb, 0); cache_tree_write(&sb, istate->cache_tree); err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0 || ce_write(&c, newfd, sb.buf, sb.len) < 0; diff --git a/remote.c b/remote.c index a2d7ab146e..d5efadd93d 100644 --- a/remote.c +++ b/remote.c @@ -245,7 +245,7 @@ static void read_branches_file(struct remote *remote) { const char *slash = strchr(remote->name, '/'); char *frag; - struct strbuf branch; + struct strbuf branch = STRBUF_INIT; int n = slash ? slash - remote->name : 1000; FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r"); char *s, *p; @@ -283,7 +283,6 @@ static void read_branches_file(struct remote *remote) * #branch specified. The "master" (or specified) branch is * fetched and stored in the local branch of the same name. */ - strbuf_init(&branch, 0); frag = strchr(p, '#'); if (frag) { *(frag++) = '\0'; diff --git a/rerere.c b/rerere.c index 121f911414..5bb5316cda 100644 --- a/rerere.c +++ b/rerere.c @@ -79,7 +79,7 @@ static int handle_file(const char *path, enum { RR_CONTEXT = 0, RR_SIDE_1, RR_SIDE_2, RR_ORIGINAL, } hunk = RR_CONTEXT; - struct strbuf one, two; + struct strbuf one = STRBUF_INIT, two = STRBUF_INIT; FILE *f = fopen(path, "r"); FILE *out = NULL; @@ -97,8 +97,6 @@ static int handle_file(const char *path, if (sha1) git_SHA1_Init(&ctx); - strbuf_init(&one, 0); - strbuf_init(&two, 0); while (fgets(buf, sizeof(buf), f)) { if (!prefixcmp(buf, "<<<<<<< ")) { if (hunk != RR_CONTEXT) diff --git a/sha1_file.c b/sha1_file.c index ea6bd996b2..3fbb0820a0 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2386,8 +2386,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size, * Convert blobs to git internal format */ if ((type == OBJ_BLOB) && path) { - struct strbuf nbuf; - strbuf_init(&nbuf, 0); + struct strbuf nbuf = STRBUF_INIT; if (convert_to_git(path, buf, size, &nbuf, write_object ? safe_crlf : 0)) { buf = strbuf_detach(&nbuf, &size); @@ -2411,8 +2410,7 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, size_t size = xsize_t(st->st_size); if (!S_ISREG(st->st_mode)) { - struct strbuf sbuf; - strbuf_init(&sbuf, 0); + struct strbuf sbuf = STRBUF_INIT; if (strbuf_read(&sbuf, fd, 4096) >= 0) ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object, type, path); diff --git a/walker.c b/walker.c index 0e68ee6d2e..6b4cf70c6a 100644 --- a/walker.c +++ b/walker.c @@ -215,9 +215,8 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag, int walker_targets_stdin(char ***target, const char ***write_ref) { int targets = 0, targets_alloc = 0; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; *target = NULL; *write_ref = NULL; - strbuf_init(&buf, 0); while (1) { char *rf_one = NULL; char *tg_one; diff --git a/ws.c b/ws.c index 7a7ff130a3..b1efcd9d75 100644 --- a/ws.c +++ b/ws.c @@ -99,8 +99,7 @@ unsigned whitespace_rule(const char *pathname) /* The returned string should be freed by the caller. */ char *whitespace_error_string(unsigned ws) { - struct strbuf err; - strbuf_init(&err, 0); + struct strbuf err = STRBUF_INIT; if (ws & WS_TRAILING_SPACE) strbuf_addstr(&err, "trailing whitespace"); if (ws & WS_SPACE_BEFORE_TAB) { diff --git a/wt-status.c b/wt-status.c index 7cf890f243..d2eac36aea 100644 --- a/wt-status.c +++ b/wt-status.c @@ -103,10 +103,8 @@ static void wt_status_print_filepair(struct wt_status *s, { const char *c = color(t); const char *one, *two; - struct strbuf onebuf, twobuf; + struct strbuf onebuf = STRBUF_INIT, twobuf = STRBUF_INIT; - strbuf_init(&onebuf, 0); - strbuf_init(&twobuf, 0); one = quote_path(p->one->path, -1, &onebuf, s->prefix); two = quote_path(p->two->path, -1, &twobuf, s->prefix); @@ -190,9 +188,8 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q, static void wt_status_print_initial(struct wt_status *s) { int i; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; - strbuf_init(&buf, 0); if (active_nr) { s->commitable = 1; wt_status_print_cached_header(s); @@ -268,9 +265,8 @@ static void wt_status_print_untracked(struct wt_status *s) struct dir_struct dir; int i; int shown_header = 0; - struct strbuf buf; + struct strbuf buf = STRBUF_INIT; - strbuf_init(&buf, 0); memset(&dir, 0, sizeof(dir)); if (!s->untracked) { -- cgit v1.3 From be58e70dbadf3cb3f4aa5829d513d886ae8bc460 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 5 Oct 2008 17:43:21 -0400 Subject: diff: unify external diff and funcname parsing code Both sets of code assume that one specifies a diff profile as a gitattribute via the "diff=foo" attribute. They then pull information about that profile from the config as diff.foo.*. The code for each is currently completely separate from the other, which has several disadvantages: - there is duplication as we maintain code to create and search the separate lists of external drivers and funcname patterns - it is difficult to add new profile options, since it is unclear where they should go - the code is difficult to follow, as we rely on the "check if this file is binary" code to find the funcname pattern as a side effect. This is the first step in refactoring the binary-checking code. This patch factors out these diff profiles into "userdiff" drivers. A file with "diff=foo" uses the "foo" driver, which is specified by a single struct. Note that one major difference between the two pieces of code is that the funcname patterns are always loaded, whereas external drivers are loaded only for the "git diff" porcelain; the new code takes care to retain that situation. Signed-off-by: Jeff King Signed-off-by: Shawn O. Pearce --- Makefile | 2 + diff.c | 251 +++++++------------------------------------------------------ userdiff.c | 160 +++++++++++++++++++++++++++++++++++++++ userdiff.h | 23 ++++++ 4 files changed, 212 insertions(+), 224 deletions(-) create mode 100644 userdiff.c create mode 100644 userdiff.h (limited to 'diff.c') diff --git a/Makefile b/Makefile index 308dc70b5d..d6f3695c97 100644 --- a/Makefile +++ b/Makefile @@ -389,6 +389,7 @@ LIB_H += transport.h LIB_H += tree.h LIB_H += tree-walk.h LIB_H += unpack-trees.h +LIB_H += userdiff.h LIB_H += utf8.h LIB_H += wt-status.h @@ -485,6 +486,7 @@ LIB_OBJS += tree-diff.o LIB_OBJS += tree.o LIB_OBJS += tree-walk.o LIB_OBJS += unpack-trees.o +LIB_OBJS += userdiff.o LIB_OBJS += usage.o LIB_OBJS += utf8.o LIB_OBJS += walker.o diff --git a/diff.c b/diff.c index 1c6be897b2..d50355e842 100644 --- a/diff.c +++ b/diff.c @@ -11,6 +11,7 @@ #include "attr.h" #include "run-command.h" #include "utf8.h" +#include "userdiff.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -56,80 +57,6 @@ static int parse_diff_color_slot(const char *var, int ofs) die("bad config variable '%s'", var); } -static struct ll_diff_driver { - const char *name; - struct ll_diff_driver *next; - const char *cmd; -} *user_diff, **user_diff_tail; - -/* - * Currently there is only "diff..command" variable; - * because there are "diff.color." variables, we are parsing - * this in a bit convoluted way to allow low level diff driver - * called "color". - */ -static int parse_lldiff_command(const char *var, const char *ep, const char *value) -{ - const char *name; - int namelen; - struct ll_diff_driver *drv; - - name = var + 5; - namelen = ep - name; - for (drv = user_diff; drv; drv = drv->next) - if (!strncmp(drv->name, name, namelen) && !drv->name[namelen]) - break; - if (!drv) { - drv = xcalloc(1, sizeof(struct ll_diff_driver)); - drv->name = xmemdupz(name, namelen); - if (!user_diff_tail) - user_diff_tail = &user_diff; - *user_diff_tail = drv; - user_diff_tail = &(drv->next); - } - - return git_config_string(&(drv->cmd), var, value); -} - -/* - * 'diff..funcname' attribute can be specified in the configuration - * to define a customized regexp to find the beginning of a function to - * be used for hunk header lines of "diff -p" style output. - */ -struct funcname_pattern_entry { - char *name; - char *pattern; - int cflags; -}; -static struct funcname_pattern_list { - struct funcname_pattern_list *next; - struct funcname_pattern_entry e; -} *funcname_pattern_list; - -static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags) -{ - const char *name; - int namelen; - struct funcname_pattern_list *pp; - - name = var + 5; /* "diff." */ - namelen = ep - name; - - for (pp = funcname_pattern_list; pp; pp = pp->next) - if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen]) - break; - if (!pp) { - pp = xcalloc(1, sizeof(*pp)); - pp->e.name = xmemdupz(name, namelen); - pp->next = funcname_pattern_list; - funcname_pattern_list = pp; - } - free(pp->e.pattern); - pp->e.pattern = xstrdup(value); - pp->e.cflags = cflags; - return 0; -} - /* * These are to give UI layer defaults. * The core-level commands such as git-diff-files should @@ -162,11 +89,11 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); - if (!prefixcmp(var, "diff.")) { - const char *ep = strrchr(var, '.'); - if (ep != var + 4 && !strcmp(ep, ".command")) - return parse_lldiff_command(var, ep, value); + switch (userdiff_config_porcelain(var, value)) { + case 0: break; + case -1: return -1; + default: return 0; } return git_diff_basic_config(var, value, cb); @@ -193,21 +120,10 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } - if (!prefixcmp(var, "diff.")) { - const char *ep = strrchr(var, '.'); - if (ep != var + 4) { - if (!strcmp(ep, ".funcname")) { - if (!value) - return config_error_nonbool(var); - return parse_funcname_pattern(var, ep, value, - 0); - } else if (!strcmp(ep, ".xfuncname")) { - if (!value) - return config_error_nonbool(var); - return parse_funcname_pattern(var, ep, value, - REG_EXTENDED); - } - } + switch (userdiff_config_basic(var, value)) { + case 0: break; + case -1: return -1; + default: return 0; } return git_color_default_config(var, value, cb); @@ -1352,46 +1268,24 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two) emit_binary_diff_body(file, two, one); } -static void setup_diff_attr_check(struct git_attr_check *check) -{ - static struct git_attr *attr_diff; - - if (!attr_diff) { - attr_diff = git_attr("diff", 4); - } - check[0].attr = attr_diff; -} - static void diff_filespec_check_attr(struct diff_filespec *one) { - struct git_attr_check attr_diff_check; + struct userdiff_driver *drv; int check_from_data = 0; if (one->checked_attr) return; - setup_diff_attr_check(&attr_diff_check); + drv = userdiff_find_by_path(one->path); one->is_binary = 0; - one->funcname_pattern_ident = NULL; - if (!git_checkattr(one->path, 1, &attr_diff_check)) { - const char *value; - - /* binaryness */ - value = attr_diff_check.value; - if (ATTR_TRUE(value)) - ; - else if (ATTR_FALSE(value)) - one->is_binary = 1; - else - check_from_data = 1; - - /* funcname pattern ident */ - if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value)) - ; - else - one->funcname_pattern_ident = value; - } + /* binaryness */ + if (drv == USERDIFF_ATTR_TRUE) + ; + else if (drv == USERDIFF_ATTR_FALSE) + one->is_binary = 1; + else + check_from_data = 1; if (check_from_data) { if (!one->data && DIFF_FILE_VALID(one)) @@ -1408,80 +1302,12 @@ int diff_filespec_is_binary(struct diff_filespec *one) return one->is_binary; } -static const struct funcname_pattern_entry *funcname_pattern(const char *ident) -{ - struct funcname_pattern_list *pp; - - for (pp = funcname_pattern_list; pp; pp = pp->next) - if (!strcmp(ident, pp->e.name)) - return &pp->e; - return NULL; -} - -static const struct funcname_pattern_entry builtin_funcname_pattern[] = { - { "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", - REG_EXTENDED }, - { "html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", REG_EXTENDED }, - { "java", - "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" - "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$", - REG_EXTENDED }, - { "objc", - /* Negate C statements that can look like functions */ - "!^[ \t]*(do|for|if|else|return|switch|while)\n" - /* Objective-C methods */ - "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n" - /* C functions */ - "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n" - /* Objective-C class/protocol definitions */ - "^(@(implementation|interface|protocol)[ \t].*)$", - REG_EXTENDED }, - { "pascal", - "^((procedure|function|constructor|destructor|interface|" - "implementation|initialization|finalization)[ \t]*.*)$" - "\n" - "^(.*=[ \t]*(class|record).*)$", - REG_EXTENDED }, - { "php", "^[\t ]*((function|class).*)", REG_EXTENDED }, - { "python", "^[ \t]*((class|def)[ \t].*)$", REG_EXTENDED }, - { "ruby", "^[ \t]*((class|module|def)[ \t].*)$", - REG_EXTENDED }, - { "tex", - "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", - REG_EXTENDED }, -}; - -static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one) +static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one) { - const char *ident; - const struct funcname_pattern_entry *pe; - int i; - - diff_filespec_check_attr(one); - ident = one->funcname_pattern_ident; - - if (!ident) - /* - * If the config file has "funcname.default" defined, that - * regexp is used; otherwise NULL is returned and xemit uses - * the built-in default. - */ - return funcname_pattern("default"); - - /* Look up custom "funcname.$ident" regexp from config. */ - pe = funcname_pattern(ident); - if (pe) - return pe; - - /* - * And define built-in fallback patterns here. Note that - * these can be overridden by the user's config settings. - */ - for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++) - if (!strcmp(ident, builtin_funcname_pattern[i].name)) - return &builtin_funcname_pattern[i]; - - return NULL; + struct userdiff_driver *drv = userdiff_find_by_path(one->path); + if (!drv) + drv = userdiff_find_by_name("default"); + return drv && drv->funcname.pattern ? &drv->funcname : NULL; } void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b) @@ -1579,7 +1405,7 @@ static void builtin_diff(const char *name_a, xdemitconf_t xecfg; xdemitcb_t ecb; struct emit_callback ecbdata; - const struct funcname_pattern_entry *pe; + const struct userdiff_funcname *pe; pe = diff_funcname_pattern(one); if (!pe) @@ -2117,29 +1943,6 @@ static void run_external_diff(const char *pgm, } } -static const char *external_diff_attr(const char *name) -{ - struct git_attr_check attr_diff_check; - - if (!name) - return NULL; - - setup_diff_attr_check(&attr_diff_check); - if (!git_checkattr(name, 1, &attr_diff_check)) { - const char *value = attr_diff_check.value; - if (!ATTR_TRUE(value) && - !ATTR_FALSE(value) && - !ATTR_UNSET(value)) { - struct ll_diff_driver *drv; - - for (drv = user_diff; drv; drv = drv->next) - if (!strcmp(drv->name, value)) - return drv->cmd; - } - } - return NULL; -} - static void run_diff_cmd(const char *pgm, const char *name, const char *other, @@ -2153,9 +1956,9 @@ static void run_diff_cmd(const char *pgm, if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL)) pgm = NULL; else { - const char *cmd = external_diff_attr(attr_path); - if (cmd) - pgm = cmd; + struct userdiff_driver *drv = userdiff_find_by_path(attr_path); + if (drv && drv->external) + pgm = drv->external; } if (pgm) { diff --git a/userdiff.c b/userdiff.c new file mode 100644 index 0000000000..80e2857abb --- /dev/null +++ b/userdiff.c @@ -0,0 +1,160 @@ +#include "userdiff.h" +#include "cache.h" +#include "attr.h" + +static struct userdiff_driver *drivers; +static int ndrivers; +static int drivers_alloc; + +#define FUNCNAME(name, pattern) \ + { name, NULL, { pattern, REG_EXTENDED } } +static struct userdiff_driver builtin_drivers[] = { +FUNCNAME("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$"), +FUNCNAME("java", + "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" + "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$"), +FUNCNAME("objc", + /* Negate C statements that can look like functions */ + "!^[ \t]*(do|for|if|else|return|switch|while)\n" + /* Objective-C methods */ + "^[ \t]*([-+][ \t]*\\([ \t]*[A-Za-z_][A-Za-z_0-9* \t]*\\)[ \t]*[A-Za-z_].*)$\n" + /* C functions */ + "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n" + /* Objective-C class/protocol definitions */ + "^(@(implementation|interface|protocol)[ \t].*)$"), +FUNCNAME("pascal", + "^((procedure|function|constructor|destructor|interface|" + "implementation|initialization|finalization)[ \t]*.*)$" + "\n" + "^(.*=[ \t]*(class|record).*)$"), +FUNCNAME("php", "^[\t ]*((function|class).*)"), +FUNCNAME("python", "^[ \t]*((class|def)[ \t].*)$"), +FUNCNAME("ruby", "^[ \t]*((class|module|def)[ \t].*)$"), +FUNCNAME("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$"), +FUNCNAME("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$"), +}; +#undef FUNCNAME + +static struct userdiff_driver driver_true = { + "diff=true", + NULL, + { NULL, 0 } +}; +struct userdiff_driver *USERDIFF_ATTR_TRUE = &driver_true; + +static struct userdiff_driver driver_false = { + "!diff", + NULL, + { NULL, 0 } +}; +struct userdiff_driver *USERDIFF_ATTR_FALSE = &driver_false; + +static struct userdiff_driver *userdiff_find_by_namelen(const char *k, int len) +{ + int i; + for (i = 0; i < ndrivers; i++) { + struct userdiff_driver *drv = drivers + i; + if (!strncmp(drv->name, k, len) && !drv->name[len]) + return drv; + } + for (i = 0; i < ARRAY_SIZE(builtin_drivers); i++) { + struct userdiff_driver *drv = builtin_drivers + i; + if (!strncmp(drv->name, k, len) && !drv->name[len]) + return drv; + } + return NULL; +} + +static struct userdiff_driver *parse_driver(const char *var, + const char *value, const char *type) +{ + struct userdiff_driver *drv; + const char *dot; + const char *name; + int namelen; + + if (prefixcmp(var, "diff.")) + return NULL; + dot = strrchr(var, '.'); + if (dot == var + 4) + return NULL; + if (strcmp(type, dot+1)) + return NULL; + + name = var + 5; + namelen = dot - name; + drv = userdiff_find_by_namelen(name, namelen); + if (!drv) { + ALLOC_GROW(drivers, ndrivers+1, drivers_alloc); + drv = &drivers[ndrivers++]; + memset(drv, 0, sizeof(*drv)); + drv->name = xmemdupz(name, namelen); + } + return drv; +} + +static int parse_funcname(struct userdiff_funcname *f, const char *k, + const char *v, int cflags) +{ + if (git_config_string(&f->pattern, k, v) < 0) + return -1; + f->cflags = cflags; + return 1; +} + +static int parse_string(const char **d, const char *k, const char *v) +{ + if (git_config_string(d, k, v) < 0) + return -1; + return 1; +} + +int userdiff_config_basic(const char *k, const char *v) +{ + struct userdiff_driver *drv; + + if ((drv = parse_driver(k, v, "funcname"))) + return parse_funcname(&drv->funcname, k, v, 0); + if ((drv = parse_driver(k, v, "xfuncname"))) + return parse_funcname(&drv->funcname, k, v, REG_EXTENDED); + + return 0; +} + +int userdiff_config_porcelain(const char *k, const char *v) +{ + struct userdiff_driver *drv; + + if ((drv = parse_driver(k, v, "command"))) + return parse_string(&drv->external, k, v); + + return 0; +} + +struct userdiff_driver *userdiff_find_by_name(const char *name) { + int len = strlen(name); + return userdiff_find_by_namelen(name, len); +} + +struct userdiff_driver *userdiff_find_by_path(const char *path) +{ + static struct git_attr *attr; + struct git_attr_check check; + + if (!attr) + attr = git_attr("diff", 4); + check.attr = attr; + + if (!path) + return NULL; + if (git_checkattr(path, 1, &check)) + return NULL; + + if (ATTR_TRUE(check.value)) + return &driver_true; + if (ATTR_FALSE(check.value)) + return &driver_false; + if (ATTR_UNSET(check.value)) + return NULL; + return userdiff_find_by_name(check.value); +} diff --git a/userdiff.h b/userdiff.h new file mode 100644 index 0000000000..c64c5f5669 --- /dev/null +++ b/userdiff.h @@ -0,0 +1,23 @@ +#ifndef USERDIFF_H +#define USERDIFF_H + +struct userdiff_funcname { + const char *pattern; + int cflags; +}; + +struct userdiff_driver { + const char *name; + const char *external; + struct userdiff_funcname funcname; +}; + +extern struct userdiff_driver *USERDIFF_ATTR_TRUE; +extern struct userdiff_driver *USERDIFF_ATTR_FALSE; + +int userdiff_config_basic(const char *k, const char *v); +int userdiff_config_porcelain(const char *k, const char *v); +struct userdiff_driver *userdiff_find_by_name(const char *name); +struct userdiff_driver *userdiff_find_by_path(const char *path); + +#endif /* USERDIFF */ -- cgit v1.3 From 122aa6f9c000d0d286898e2eb7b3504ac6cb9ebd Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 5 Oct 2008 17:43:36 -0400 Subject: diff: introduce diff..binary The "diff" gitattribute is somewhat overloaded right now. It can say one of three things: 1. this file is definitely binary, or definitely not (i.e., diff or !diff) 2. this file should use an external diff engine (i.e., diff=foo, diff.foo.command = custom-script) 3. this file should use particular funcname patterns (i.e., diff=foo, diff.foo.(x?)funcname = some-regex) Most of the time, there is no conflict between these uses, since using one implies that the other is irrelevant (e.g., an external diff engine will decide for itself whether the file is binary). However, there is at least one conflicting situation: there is no way to say "use the regular rules to determine whether this file is binary, but if we do diff it textually, use this funcname pattern." That is, currently setting diff=foo indicates that the file is definitely text. This patch introduces a "binary" config option for a diff driver, so that one can explicitly set diff.foo.binary. We default this value to "don't know". That is, setting a diff attribute to "foo" and using "diff.foo.funcname" will have no effect on the binaryness of a file. To get the current behavior, one can set diff.foo.binary to true. This patch also has one additional advantage: it cleans up the interface to the userdiff code a bit. Before, calling code had to know more about whether attributes were false, true, or unset to determine binaryness. Now that binaryness is a property of a driver, we can represent these situations just by passing back a driver struct. Signed-off-by: Jeff King Signed-off-by: Shawn O. Pearce --- diff.c | 52 ++++++++++++++++++++++------------------------------ diffcore.h | 8 ++++++-- userdiff.c | 19 ++++++++++++++++--- userdiff.h | 4 +--- 4 files changed, 45 insertions(+), 38 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index d50355e842..dabd7f50ec 100644 --- a/diff.c +++ b/diff.c @@ -1268,46 +1268,37 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two) emit_binary_diff_body(file, two, one); } -static void diff_filespec_check_attr(struct diff_filespec *one) +void diff_filespec_load_driver(struct diff_filespec *one) { - struct userdiff_driver *drv; - int check_from_data = 0; - - if (one->checked_attr) - return; - - drv = userdiff_find_by_path(one->path); - one->is_binary = 0; - - /* binaryness */ - if (drv == USERDIFF_ATTR_TRUE) - ; - else if (drv == USERDIFF_ATTR_FALSE) - one->is_binary = 1; - else - check_from_data = 1; - - if (check_from_data) { - if (!one->data && DIFF_FILE_VALID(one)) - diff_populate_filespec(one, 0); - - if (one->data) - one->is_binary = buffer_is_binary(one->data, one->size); - } + if (!one->driver) + one->driver = userdiff_find_by_path(one->path); + if (!one->driver) + one->driver = userdiff_find_by_name("default"); } int diff_filespec_is_binary(struct diff_filespec *one) { - diff_filespec_check_attr(one); + if (one->is_binary == -1) { + diff_filespec_load_driver(one); + if (one->driver->binary != -1) + one->is_binary = one->driver->binary; + else { + if (!one->data && DIFF_FILE_VALID(one)) + diff_populate_filespec(one, 0); + if (one->data) + one->is_binary = buffer_is_binary(one->data, + one->size); + if (one->is_binary == -1) + one->is_binary = 0; + } + } return one->is_binary; } static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespec *one) { - struct userdiff_driver *drv = userdiff_find_by_path(one->path); - if (!drv) - drv = userdiff_find_by_name("default"); - return drv && drv->funcname.pattern ? &drv->funcname : NULL; + diff_filespec_load_driver(one); + return one->driver->funcname.pattern ? &one->driver->funcname : NULL; } void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b) @@ -1559,6 +1550,7 @@ struct diff_filespec *alloc_filespec(const char *path) spec->path = (char *)(spec + 1); memcpy(spec->path, path, namelen+1); spec->count = 1; + spec->is_binary = -1; return spec; } diff --git a/diffcore.h b/diffcore.h index 8ae35785fd..713cca785c 100644 --- a/diffcore.h +++ b/diffcore.h @@ -22,6 +22,8 @@ #define MINIMUM_BREAK_SIZE 400 /* do not break a file smaller than this */ +struct userdiff_driver; + struct diff_filespec { unsigned char sha1[20]; char *path; @@ -40,8 +42,10 @@ struct diff_filespec { #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0) unsigned should_free : 1; /* data should be free()'ed */ unsigned should_munmap : 1; /* data should be munmap()'ed */ - unsigned checked_attr : 1; - unsigned is_binary : 1; /* data should be considered "binary" */ + + struct userdiff_driver *driver; + /* data should be considered "binary"; -1 means "don't know yet" */ + int is_binary; }; extern struct diff_filespec *alloc_filespec(const char *); diff --git a/userdiff.c b/userdiff.c index 80e2857abb..58478a6912 100644 --- a/userdiff.c +++ b/userdiff.c @@ -7,7 +7,7 @@ static int ndrivers; static int drivers_alloc; #define FUNCNAME(name, pattern) \ - { name, NULL, { pattern, REG_EXTENDED } } + { name, NULL, -1, { pattern, REG_EXTENDED } } static struct userdiff_driver builtin_drivers[] = { FUNCNAME("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$"), FUNCNAME("java", @@ -32,22 +32,23 @@ FUNCNAME("python", "^[ \t]*((class|def)[ \t].*)$"), FUNCNAME("ruby", "^[ \t]*((class|module|def)[ \t].*)$"), FUNCNAME("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$"), FUNCNAME("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$"), +{ "default", NULL, -1, { NULL, 0 } }, }; #undef FUNCNAME static struct userdiff_driver driver_true = { "diff=true", NULL, + 0, { NULL, 0 } }; -struct userdiff_driver *USERDIFF_ATTR_TRUE = &driver_true; static struct userdiff_driver driver_false = { "!diff", NULL, + 1, { NULL, 0 } }; -struct userdiff_driver *USERDIFF_ATTR_FALSE = &driver_false; static struct userdiff_driver *userdiff_find_by_namelen(const char *k, int len) { @@ -89,6 +90,7 @@ static struct userdiff_driver *parse_driver(const char *var, drv = &drivers[ndrivers++]; memset(drv, 0, sizeof(*drv)); drv->name = xmemdupz(name, namelen); + drv->binary = -1; } return drv; } @@ -109,6 +111,15 @@ static int parse_string(const char **d, const char *k, const char *v) return 1; } +static int parse_tristate(int *b, const char *k, const char *v) +{ + if (v && !strcasecmp(v, "auto")) + *b = -1; + else + *b = git_config_bool(k, v); + return 1; +} + int userdiff_config_basic(const char *k, const char *v) { struct userdiff_driver *drv; @@ -117,6 +128,8 @@ int userdiff_config_basic(const char *k, const char *v) return parse_funcname(&drv->funcname, k, v, 0); if ((drv = parse_driver(k, v, "xfuncname"))) return parse_funcname(&drv->funcname, k, v, REG_EXTENDED); + if ((drv = parse_driver(k, v, "binary"))) + return parse_tristate(&drv->binary, k, v); return 0; } diff --git a/userdiff.h b/userdiff.h index c64c5f5669..1c1eb042b4 100644 --- a/userdiff.h +++ b/userdiff.h @@ -9,12 +9,10 @@ struct userdiff_funcname { struct userdiff_driver { const char *name; const char *external; + int binary; struct userdiff_funcname funcname; }; -extern struct userdiff_driver *USERDIFF_ATTR_TRUE; -extern struct userdiff_driver *USERDIFF_ATTR_FALSE; - int userdiff_config_basic(const char *k, const char *v); int userdiff_config_porcelain(const char *k, const char *v); struct userdiff_driver *userdiff_find_by_name(const char *name); -- cgit v1.3 From 9cb92c390cefd3bf3f71bbda12eb04893c861361 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 5 Oct 2008 17:43:45 -0400 Subject: diff: add filter for converting binary to text When diffing binary files, it is sometimes nice to see the differences of a canonical text form rather than either a binary patch or simply "binary files differ." Until now, the only option for doing this was to define an external diff command to perform the diff. This was a lot of work, since the external command needed to take care of doing the diff itself (including mode changes), and lost the benefit of git's colorization and other options. This patch adds a text conversion option, which converts a file to its canonical format before performing the diff. This is less flexible than an arbitrary external diff, but is much less work to set up. For example: $ echo '*.jpg diff=exif' >>.gitattributes $ git config diff.exif.textconv exiftool $ git config diff.exif.binary false allows one to see jpg diffs represented by the text output of exiftool. Signed-off-by: Jeff King Signed-off-by: Shawn O. Pearce --- diff.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- userdiff.c | 2 ++ userdiff.h | 1 + 3 files changed, 50 insertions(+), 2 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index dabd7f50ec..e368fef14f 100644 --- a/diff.c +++ b/diff.c @@ -38,6 +38,9 @@ static char diff_colors[][COLOR_MAXLEN] = { "\033[41m", /* WHITESPACE (red background) */ }; +static void diff_filespec_load_driver(struct diff_filespec *one); +static char *run_textconv(const char *, struct diff_filespec *, size_t *); + static int parse_diff_color_slot(const char *var, int ofs) { if (!strcasecmp(var+ofs, "plain")) @@ -290,8 +293,19 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) } else if (diff_populate_filespec(one, 0)) return -1; - mf->ptr = one->data; - mf->size = one->size; + + diff_filespec_load_driver(one); + if (one->driver->textconv) { + size_t size; + mf->ptr = run_textconv(one->driver->textconv, one, &size); + if (!mf->ptr) + return -1; + mf->size = size; + } + else { + mf->ptr = one->data; + mf->size = one->size; + } return 0; } @@ -3373,3 +3387,34 @@ void diff_unmerge(struct diff_options *options, fill_filespec(one, sha1, mode); diff_queue(&diff_queued_diff, one, two)->is_unmerged = 1; } + +static char *run_textconv(const char *pgm, struct diff_filespec *spec, + size_t *outsize) +{ + struct diff_tempfile temp; + const char *argv[3]; + const char **arg = argv; + struct child_process child; + struct strbuf buf = STRBUF_INIT; + + prepare_temp_file(spec->path, &temp, spec); + *arg++ = pgm; + *arg++ = temp.name; + *arg = NULL; + + memset(&child, 0, sizeof(child)); + child.argv = argv; + child.out = -1; + if (start_command(&child) != 0 || + strbuf_read(&buf, child.out, 0) < 0 || + finish_command(&child) != 0) { + if (temp.name == temp.tmp_path) + unlink(temp.name); + error("error running textconv command '%s'", pgm); + return NULL; + } + if (temp.name == temp.tmp_path) + unlink(temp.name); + + return strbuf_detach(&buf, outsize); +} diff --git a/userdiff.c b/userdiff.c index 58478a6912..d95257ab3b 100644 --- a/userdiff.c +++ b/userdiff.c @@ -140,6 +140,8 @@ int userdiff_config_porcelain(const char *k, const char *v) if ((drv = parse_driver(k, v, "command"))) return parse_string(&drv->external, k, v); + if ((drv = parse_driver(k, v, "textconv"))) + return parse_string(&drv->textconv, k, v); return 0; } diff --git a/userdiff.h b/userdiff.h index 1c1eb042b4..f29c18ffb3 100644 --- a/userdiff.h +++ b/userdiff.h @@ -11,6 +11,7 @@ struct userdiff_driver { const char *external; int binary; struct userdiff_funcname funcname; + const char *textconv; }; int userdiff_config_basic(const char *k, const char *v); -- cgit v1.3 From 9ccd0a88ac3ea13ac2df4630bfd01c02084f965e Mon Sep 17 00:00:00 2001 From: Brian Downing Date: Sat, 25 Oct 2008 15:30:37 +0200 Subject: Always initialize xpparam_t to 0 We're going to be adding some parameters to this, so we can't have any uninitialized data in it. Signed-off-by: Brian Downing Signed-off-by: Junio C Hamano --- builtin-blame.c | 1 + builtin-rerere.c | 1 + combine-diff.c | 1 + diff.c | 5 +++++ merge-file.c | 1 + 5 files changed, 9 insertions(+) (limited to 'diff.c') diff --git a/builtin-blame.c b/builtin-blame.c index 593b539f1e..5ca7065171 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -523,6 +523,7 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o, xdemitconf_t xecfg; xdemitcb_t ecb; + memset(&xpp, 0, sizeof(xpp)); xpp.flags = xdl_opts; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = context; diff --git a/builtin-rerere.c b/builtin-rerere.c index dd4573fe8d..d4dec6b715 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -98,6 +98,7 @@ static int diff_two(const char *file1, const char *label1, printf("--- a/%s\n+++ b/%s\n", label1, label2); fflush(stdout); + memset(&xpp, 0, sizeof(xpp)); xpp.flags = XDF_NEED_MINIMAL; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; diff --git a/combine-diff.c b/combine-diff.c index 5aa1104d34..ec8df39bb0 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -213,6 +213,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file, parent_file.ptr = grab_blob(parent, &sz); parent_file.size = sz; + memset(&xpp, 0, sizeof(xpp)); xpp.flags = XDF_NEED_MINIMAL; memset(&xecfg, 0, sizeof(xecfg)); memset(&state, 0, sizeof(state)); diff --git a/diff.c b/diff.c index 1c6be897b2..f141e7c8ff 100644 --- a/diff.c +++ b/diff.c @@ -470,6 +470,7 @@ static void diff_words_show(struct diff_words_data *diff_words) mmfile_t minus, plus; int i; + memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); minus.size = diff_words->minus.text.size; minus.ptr = xmalloc(minus.size); @@ -1585,6 +1586,7 @@ static void builtin_diff(const char *name_a, if (!pe) pe = diff_funcname_pattern(two); + memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); memset(&ecbdata, 0, sizeof(ecbdata)); ecbdata.label_path = lbl; @@ -1658,6 +1660,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b, xdemitconf_t xecfg; xdemitcb_t ecb; + memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, @@ -1704,6 +1707,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, xdemitconf_t xecfg; xdemitcb_t ecb; + memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = XDF_NEED_MINIMAL; @@ -3149,6 +3153,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) struct diff_filepair *p = q->queue[i]; int len1, len2; + memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); if (p->status == 0) return error("internal diff status error"); diff --git a/merge-file.c b/merge-file.c index 2a939c9dd8..3120a95f78 100644 --- a/merge-file.c +++ b/merge-file.c @@ -61,6 +61,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2) xdemitconf_t xecfg; xdemitcb_t ecb; + memset(&xpp, 0, sizeof(xpp)); xpp.flags = XDF_NEED_MINIMAL; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 3; -- cgit v1.3 From 72cf48414071636546eddfbfc828eda81649cb48 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 26 Oct 2008 00:41:28 -0400 Subject: diff: add missing static declaration This function isn't used outside of diff.c; the 'static' was simply overlooked in the original writing. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index e368fef14f..d1fd594ba3 100644 --- a/diff.c +++ b/diff.c @@ -1282,7 +1282,7 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two) emit_binary_diff_body(file, two, one); } -void diff_filespec_load_driver(struct diff_filespec *one) +static void diff_filespec_load_driver(struct diff_filespec *one) { if (!one->driver) one->driver = userdiff_find_by_path(one->path); -- cgit v1.3 From 04427ac8483f61dcb01a48c78a821f5042c88195 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 26 Oct 2008 00:44:53 -0400 Subject: refactor userdiff textconv code The original implementation of textconv put the conversion into fill_mmfile. This was a bad idea for a number of reasons: - it made the semantics of fill_mmfile unclear. In some cases, it was allocating data (if a text conversion occurred), and in some cases not (if we could use the data directly from the filespec). But the caller had no idea which had happened, and so didn't know whether the memory should be freed - similarly, the caller had no idea if a text conversion had occurred, and so didn't know whether the contents should be treated as binary or not. This meant that we incorrectly guessed that text-converted content was binary and didn't actually show it (unless the user overrode us with "diff.foo.binary = false", which then created problems in plumbing where the text conversion did _not_ occur) - not all callers of fill_mmfile want the text contents. In particular, we don't really want diffstat, whitespace checks, patch id generation, etc, to look at the converted contents. This patch pulls the conversion code directly into builtin_diff, so that we only see the conversion when generating an actual patch. We also then know whether we are doing a conversion, so we can check the binary-ness and free the data from the mmfile appropriately (the previous version leaked quite badly when text conversion was used) Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 48 +++++++++++++++++++++++++++++++++++------------- t/t4030-diff-textconv.sh | 6 +++--- 2 files changed, 38 insertions(+), 16 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index d1fd594ba3..6f01595ece 100644 --- a/diff.c +++ b/diff.c @@ -294,18 +294,8 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) else if (diff_populate_filespec(one, 0)) return -1; - diff_filespec_load_driver(one); - if (one->driver->textconv) { - size_t size; - mf->ptr = run_textconv(one->driver->textconv, one, &size); - if (!mf->ptr) - return -1; - mf->size = size; - } - else { - mf->ptr = one->data; - mf->size = one->size; - } + mf->ptr = one->data; + mf->size = one->size; return 0; } @@ -1323,6 +1313,14 @@ void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const options->b_prefix = b; } +static const char *get_textconv(struct diff_filespec *one) +{ + if (!DIFF_FILE_VALID(one)) + return NULL; + diff_filespec_load_driver(one); + return one->driver->textconv; +} + static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -1337,6 +1335,7 @@ static void builtin_diff(const char *name_a, const char *set = diff_get_color_opt(o, DIFF_METAINFO); const char *reset = diff_get_color_opt(o, DIFF_RESET); const char *a_prefix, *b_prefix; + const char *textconv_one, *textconv_two; diff_set_mnemonic_prefix(o, "a/", "b/"); if (DIFF_OPT_TST(o, REVERSE_DIFF)) { @@ -1390,8 +1389,12 @@ static void builtin_diff(const char *name_a, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); + textconv_one = get_textconv(one); + textconv_two = get_textconv(two); + if (!DIFF_OPT_TST(o, TEXT) && - (diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) { + ( (diff_filespec_is_binary(one) && !textconv_one) || + (diff_filespec_is_binary(two) && !textconv_two) )) { /* Quite common confusing case */ if (mf1.size == mf2.size && !memcmp(mf1.ptr, mf2.ptr, mf1.size)) @@ -1412,6 +1415,21 @@ static void builtin_diff(const char *name_a, struct emit_callback ecbdata; const struct userdiff_funcname *pe; + if (textconv_one) { + size_t size; + mf1.ptr = run_textconv(textconv_one, one, &size); + if (!mf1.ptr) + die("unable to read files to diff"); + mf1.size = size; + } + if (textconv_two) { + size_t size; + mf2.ptr = run_textconv(textconv_two, two, &size); + if (!mf2.ptr) + die("unable to read files to diff"); + mf2.size = size; + } + pe = diff_funcname_pattern(one); if (!pe) pe = diff_funcname_pattern(two); @@ -1443,6 +1461,10 @@ static void builtin_diff(const char *name_a, &xpp, &xecfg, &ecb); if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) free_diff_words_data(&ecbdata); + if (textconv_one) + free(mf1.ptr); + if (textconv_two) + free(mf2.ptr); } free_ab_and_return: diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 1b0964843e..090a21d0b5 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -52,7 +52,7 @@ test_expect_success 'setup textconv filters' ' git config diff.fail.textconv false ' -test_expect_failure 'diff produces text' ' +test_expect_success 'diff produces text' ' git diff HEAD^ HEAD >diff && find_diff actual && test_cmp expect.text actual @@ -64,7 +64,7 @@ test_expect_success 'diff-tree produces binary' ' test_cmp expect.binary actual ' -test_expect_failure 'log produces text' ' +test_expect_success 'log produces text' ' git log -1 -p >log && find_diff actual && test_cmp expect.text actual @@ -80,7 +80,7 @@ cat >expect.stat <<'EOF' file | Bin 2 -> 4 bytes 1 files changed, 0 insertions(+), 0 deletions(-) EOF -test_expect_failure 'diffstat does not run textconv' ' +test_expect_success 'diffstat does not run textconv' ' echo file diff=fail >.gitattributes && git diff --stat HEAD^ HEAD >actual && test_cmp expect.stat actual -- cgit v1.3 From c7534ef4a12bb44806d522fc8e3961e390f9169b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 26 Oct 2008 00:45:55 -0400 Subject: userdiff: require explicitly allowing textconv Diffs that have been produced with textconv almost certainly cannot be applied, so we want to be careful not to generate them in things like format-patch. This introduces a new diff options, ALLOW_TEXTCONV, which controls this behavior. It is off by default, but is explicitly turned on for the "log" family of commands, as well as the "diff" porcelain (but not diff-* plumbing). Because both text conversion and external diffing are controlled by these diff options, we can get rid of the "plumbing versus porcelain" distinction when reading the config. This was an attempt to control the same thing, but suffered from being too coarse-grained. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-diff.c | 1 + builtin-log.c | 1 + diff.c | 26 +++++++++++--------------- diff.h | 1 + t/t4030-diff-textconv.sh | 2 +- userdiff.c | 10 +--------- userdiff.h | 3 +-- 7 files changed, 17 insertions(+), 27 deletions(-) (limited to 'diff.c') diff --git a/builtin-diff.c b/builtin-diff.c index 9c8c295732..2de5834c11 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -300,6 +300,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) } DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, RECURSIVE); + DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV); /* * If the user asked for our exit code then don't start a diff --git a/builtin-log.c b/builtin-log.c index a0944f70a4..75d698f0ce 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -59,6 +59,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix, } else die("unrecognized argument: %s", arg); } + DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV); } /* diff --git a/diff.c b/diff.c index 6f01595ece..608223ab56 100644 --- a/diff.c +++ b/diff.c @@ -93,12 +93,6 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); - switch (userdiff_config_porcelain(var, value)) { - case 0: break; - case -1: return -1; - default: return 0; - } - return git_diff_basic_config(var, value, cb); } @@ -109,6 +103,12 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } + switch (userdiff_config(var, value)) { + case 0: break; + case -1: return -1; + default: return 0; + } + if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); if (!value) @@ -123,12 +123,6 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } - switch (userdiff_config_basic(var, value)) { - case 0: break; - case -1: return -1; - default: return 0; - } - return git_color_default_config(var, value, cb); } @@ -1335,7 +1329,7 @@ static void builtin_diff(const char *name_a, const char *set = diff_get_color_opt(o, DIFF_METAINFO); const char *reset = diff_get_color_opt(o, DIFF_RESET); const char *a_prefix, *b_prefix; - const char *textconv_one, *textconv_two; + const char *textconv_one = NULL, *textconv_two = NULL; diff_set_mnemonic_prefix(o, "a/", "b/"); if (DIFF_OPT_TST(o, REVERSE_DIFF)) { @@ -1389,8 +1383,10 @@ static void builtin_diff(const char *name_a, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); - textconv_one = get_textconv(one); - textconv_two = get_textconv(two); + if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) { + textconv_one = get_textconv(one); + textconv_two = get_textconv(two); + } if (!DIFF_OPT_TST(o, TEXT) && ( (diff_filespec_is_binary(one) && !textconv_one) || diff --git a/diff.h b/diff.h index a49d865bd9..42582edee6 100644 --- a/diff.h +++ b/diff.h @@ -65,6 +65,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_IGNORE_SUBMODULES (1 << 18) #define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19) #define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20) +#define DIFF_OPT_ALLOW_TEXTCONV (1 << 21) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 090a21d0b5..1df48ae12a 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -70,7 +70,7 @@ test_expect_success 'log produces text' ' test_cmp expect.text actual ' -test_expect_failure 'format-patch produces binary' ' +test_expect_success 'format-patch produces binary' ' git format-patch --no-binary --stdout HEAD^ >patch && find_diff actual && test_cmp expect.binary actual diff --git a/userdiff.c b/userdiff.c index d95257ab3b..3681062ebf 100644 --- a/userdiff.c +++ b/userdiff.c @@ -120,7 +120,7 @@ static int parse_tristate(int *b, const char *k, const char *v) return 1; } -int userdiff_config_basic(const char *k, const char *v) +int userdiff_config(const char *k, const char *v) { struct userdiff_driver *drv; @@ -130,14 +130,6 @@ int userdiff_config_basic(const char *k, const char *v) return parse_funcname(&drv->funcname, k, v, REG_EXTENDED); if ((drv = parse_driver(k, v, "binary"))) return parse_tristate(&drv->binary, k, v); - - return 0; -} - -int userdiff_config_porcelain(const char *k, const char *v) -{ - struct userdiff_driver *drv; - if ((drv = parse_driver(k, v, "command"))) return parse_string(&drv->external, k, v); if ((drv = parse_driver(k, v, "textconv"))) diff --git a/userdiff.h b/userdiff.h index f29c18ffb3..ba2945770b 100644 --- a/userdiff.h +++ b/userdiff.h @@ -14,8 +14,7 @@ struct userdiff_driver { const char *textconv; }; -int userdiff_config_basic(const char *k, const char *v); -int userdiff_config_porcelain(const char *k, const char *v); +int userdiff_config(const char *k, const char *v); struct userdiff_driver *userdiff_find_by_name(const char *name); struct userdiff_driver *userdiff_find_by_path(const char *path); -- cgit v1.3 From 2675773af893ae81f9b09f18c1f2ec86ca2158e7 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 26 Oct 2008 00:46:21 -0400 Subject: only textconv regular files We treat symlinks as text containing the results of the symlink, so it doesn't make much sense to text-convert them. Similarly gitlink components just end up as the text "Subproject commit $sha1", which we should leave intact. Note that a typechange may be broken into two parts: the removal of the old part and the addition of the new. In that case, we _do_ show the textconv for any part which is the addition or removal of a file we would ordinarily textconv, since it is purely acting on the file contents. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 2 ++ t/t4030-diff-textconv.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 608223ab56..23d454e71d 100644 --- a/diff.c +++ b/diff.c @@ -1311,6 +1311,8 @@ static const char *get_textconv(struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) return NULL; + if (!S_ISREG(one->mode)) + return NULL; diff_filespec_load_driver(one); return one->driver->textconv; } diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 1df48ae12a..3945731e9a 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -104,7 +104,7 @@ index ad8b3d2..67be421 \ No newline at end of file EOF # make a symlink the hard way that works on symlink-challenged file systems -test_expect_failure 'textconv does not act on symlinks' ' +test_expect_success 'textconv does not act on symlinks' ' echo -n frotz > file && git add file && git ls-files -s | sed -e s/100644/120000/ | -- cgit v1.3 From e10ea8126c27b079e81932ca487747b4961d0604 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sun, 7 Dec 2008 21:57:01 -0500 Subject: diff: allow turning on textconv explicitly for plumbing Some history viewers use the diff plumbing to generate diffs rather than going through the "git diff" porcelain. Currently, there is no way for them to specify that they would like to see the text-converted version of the diff. This patch adds a "--textconv" option to allow such a plumbing user to allow text conversion. The user can then tell the viewer whether or not they would like text conversion enabled. While it may be tempting add a configuration option rather than requiring each plumbing user to be configured to pass --textconv, that is somewhat dangerous. Text-converted diffs generally cannot be applied directly, so each plumbing user should "opt in" to generating such a diff, either by explicit request of the user or by confirming that their output will not be fed to patch. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index f644947c82..e21af3b7ee 100644 --- a/diff.c +++ b/diff.c @@ -2477,6 +2477,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_SET(options, ALLOW_EXTERNAL); else if (!strcmp(arg, "--no-ext-diff")) DIFF_OPT_CLR(options, ALLOW_EXTERNAL); + else if (!strcmp(arg, "--textconv")) + DIFF_OPT_SET(options, ALLOW_TEXTCONV); + else if (!strcmp(arg, "--no-textconv")) + DIFF_OPT_CLR(options, ALLOW_TEXTCONV); else if (!strcmp(arg, "--ignore-submodules")) DIFF_OPT_SET(options, IGNORE_SUBMODULES); -- cgit v1.3 From 0c01857df57fe8723714e49459e0c061fcaf056b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 9 Dec 2008 03:12:28 -0500 Subject: diff: fix handling of binary rewrite diffs The current emit_rewrite_diff code always writes a text patch without checking whether the content is binary. This means that if you end up with a rewrite diff for a binary file, you get lots of raw binary goo in your patch. Instead, if we have binary files, then let's just skip emit_rewrite_diff altogether. We will already have shown the "dissimilarity index" line, so it is really about the diff contents. If binary diffs are turned off, the "Binary files a/file and b/file differ" message should be the same in either case. If we do have binary patches turned on, there isn't much point in making a less-efficient binary patch that does a total rewrite; no human is going to read it, and since binary patches don't apply with any fuzz anyway, the result of application should be the same. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 4 +++- t/t4031-diff-rewrite-binary.sh | 45 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100755 t/t4031-diff-rewrite-binary.sh (limited to 'diff.c') diff --git a/diff.c b/diff.c index e21af3b7ee..50277b82b2 100644 --- a/diff.c +++ b/diff.c @@ -1376,7 +1376,9 @@ static void builtin_diff(const char *name_a, */ if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; - if (complete_rewrite) { + if (complete_rewrite && + !diff_filespec_is_binary(one) && + !diff_filespec_is_binary(two)) { emit_rewrite_diff(name_a, name_b, one, two, o); o->found_changes = 1; goto free_ab_and_return; diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh new file mode 100755 index 0000000000..e16c355103 --- /dev/null +++ b/t/t4031-diff-rewrite-binary.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +test_description='rewrite diff on binary file' + +. ./test-lib.sh + +# We must be large enough to meet the MINIMUM_BREAK_SIZE +# requirement. +make_file() { + for i in 1 2 3 4 5 6 7 8 9 10 + do + for j in 1 2 3 4 5 6 7 8 9 + do + for k in 1 2 3 4 5 + do + printf "$1\n" + done + done + done >file +} + +test_expect_success 'create binary file with changes' ' + make_file "\\0" && + git add file && + make_file "\\01" +' + +test_expect_success 'vanilla diff is binary' ' + git diff >diff && + grep "Binary files a/file and b/file differ" diff +' + +test_expect_success 'rewrite diff is binary' ' + git diff -B >diff && + grep "dissimilarity index" diff && + grep "Binary files a/file and b/file differ" diff +' + +test_expect_success 'rewrite diff can show binary patch' ' + git diff -B --binary >diff && + grep "dissimilarity index" diff && + grep "GIT binary patch" diff +' + +test_done -- cgit v1.3 From 3aa1f7ca3779f73164b285c070b71abcdd7397c1 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Tue, 9 Dec 2008 03:13:21 -0500 Subject: diff: respect textconv in rewrite diffs Currently we just skip rewrite diffs for binary files; this patch makes an exception for files which will be textconv'd, and actually performs the textconv before generating the diff. Conceptually, rewrite diffs should be in the exact same format as the a non-rewrite diff, except that we refuse to share any context. Thus it makes very little sense for "git diff" to show a textconv'd diff, but for "git diff -B" to show "Binary files differ". Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 48 +++++++++++++++++++++++++++++++----------- t/t4031-diff-rewrite-binary.sh | 24 ++++++++++++++++++++- 2 files changed, 59 insertions(+), 13 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 50277b82b2..afefe087bb 100644 --- a/diff.c +++ b/diff.c @@ -229,6 +229,8 @@ static void emit_rewrite_diff(const char *name_a, const char *name_b, struct diff_filespec *one, struct diff_filespec *two, + const char *textconv_one, + const char *textconv_two, struct diff_options *o) { int lc_a, lc_b; @@ -241,6 +243,8 @@ static void emit_rewrite_diff(const char *name_a, const char *reset = diff_get_color(color_diff, DIFF_RESET); static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT; const char *a_prefix, *b_prefix; + const char *data_one, *data_two; + size_t size_one, size_two; if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) { a_prefix = o->b_prefix; @@ -262,8 +266,27 @@ static void emit_rewrite_diff(const char *name_a, diff_populate_filespec(one, 0); diff_populate_filespec(two, 0); - lc_a = count_lines(one->data, one->size); - lc_b = count_lines(two->data, two->size); + if (textconv_one) { + data_one = run_textconv(textconv_one, one, &size_one); + if (!data_one) + die("unable to read files to diff"); + } + else { + data_one = one->data; + size_one = one->size; + } + if (textconv_two) { + data_two = run_textconv(textconv_two, two, &size_two); + if (!data_two) + die("unable to read files to diff"); + } + else { + data_two = two->data; + size_two = two->size; + } + + lc_a = count_lines(data_one, size_one); + lc_b = count_lines(data_two, size_two); fprintf(o->file, "%s--- %s%s%s\n%s+++ %s%s%s\n%s@@ -", metainfo, a_name.buf, name_a_tab, reset, @@ -273,9 +296,9 @@ static void emit_rewrite_diff(const char *name_a, print_line_count(o->file, lc_b); fprintf(o->file, " @@%s\n", reset); if (lc_a) - copy_file_with_prefix(o->file, '-', one->data, one->size, old, reset); + copy_file_with_prefix(o->file, '-', data_one, size_one, old, reset); if (lc_b) - copy_file_with_prefix(o->file, '+', two->data, two->size, new, reset); + copy_file_with_prefix(o->file, '+', data_two, size_two, new, reset); } static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) @@ -1334,6 +1357,11 @@ static void builtin_diff(const char *name_a, const char *a_prefix, *b_prefix; const char *textconv_one = NULL, *textconv_two = NULL; + if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) { + textconv_one = get_textconv(one); + textconv_two = get_textconv(two); + } + diff_set_mnemonic_prefix(o, "a/", "b/"); if (DIFF_OPT_TST(o, REVERSE_DIFF)) { a_prefix = o->b_prefix; @@ -1377,9 +1405,10 @@ static void builtin_diff(const char *name_a, if ((one->mode ^ two->mode) & S_IFMT) goto free_ab_and_return; if (complete_rewrite && - !diff_filespec_is_binary(one) && - !diff_filespec_is_binary(two)) { - emit_rewrite_diff(name_a, name_b, one, two, o); + (textconv_one || !diff_filespec_is_binary(one)) && + (textconv_two || !diff_filespec_is_binary(two))) { + emit_rewrite_diff(name_a, name_b, one, two, + textconv_one, textconv_two, o); o->found_changes = 1; goto free_ab_and_return; } @@ -1388,11 +1417,6 @@ static void builtin_diff(const char *name_a, if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0) die("unable to read files to diff"); - if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) { - textconv_one = get_textconv(one); - textconv_two = get_textconv(two); - } - if (!DIFF_OPT_TST(o, TEXT) && ( (diff_filespec_is_binary(one) && !textconv_one) || (diff_filespec_is_binary(two) && !textconv_two) )) { diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh index e16c355103..157ed85a79 100755 --- a/t/t4031-diff-rewrite-binary.sh +++ b/t/t4031-diff-rewrite-binary.sh @@ -7,6 +7,8 @@ test_description='rewrite diff on binary file' # We must be large enough to meet the MINIMUM_BREAK_SIZE # requirement. make_file() { + # common first line to help identify rewrite versus regular diff + printf "=\n" >file for i in 1 2 3 4 5 6 7 8 9 10 do for j in 1 2 3 4 5 6 7 8 9 @@ -16,7 +18,7 @@ make_file() { printf "$1\n" done done - done >file + done >>file } test_expect_success 'create binary file with changes' ' @@ -42,4 +44,24 @@ test_expect_success 'rewrite diff can show binary patch' ' grep "GIT binary patch" diff ' +{ + echo "#!$SHELL_PATH" + cat >dump <<'EOF' +perl -e '$/ = undef; $_ = <>; s/./ord($&)/ge; print $_' < "$1" +EOF +} >dump +chmod +x dump + +test_expect_success 'setup textconv' ' + echo file diff=foo >.gitattributes && + git config diff.foo.textconv "$PWD"/dump +' + +test_expect_success 'rewrite diff respects textconv' ' + git diff -B >diff && + grep "dissimilarity index" diff && + grep "^-61" diff && + grep "^-0" diff +' + test_done -- cgit v1.3 From cf219d8c68ada1aa2855f4862f15753a32d09641 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 17 Dec 2008 10:26:13 -0800 Subject: Make 'diff_populate_filespec()' use the new 'strbuf_readlink()' This makes all tests pass on a system where 'lstat()' has been hacked to return bogus data in st_size for symlinks. Of course, the test coverage isn't complete, but it's a good baseline. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- diff.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index afefe087bb..4b2029caa1 100644 --- a/diff.c +++ b/diff.c @@ -1773,19 +1773,17 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) s->size = xsize_t(st.st_size); if (!s->size) goto empty; - if (size_only) - return 0; if (S_ISLNK(st.st_mode)) { - int ret; - s->data = xmalloc(s->size); - s->should_free = 1; - ret = readlink(s->path, s->data, s->size); - if (ret < 0) { - free(s->data); + struct strbuf sb = STRBUF_INIT; + + if (strbuf_readlink(&sb, s->path, s->size)) goto err_empty; - } + s->data = strbuf_detach(&sb, &s->size); + s->should_free = 1; return 0; } + if (size_only) + return 0; fd = open(s->path, O_RDONLY); if (fd < 0) goto err_empty; -- cgit v1.3 From dfab6aaecfe9df67123efc778f6aea4e9814715a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 17 Dec 2008 10:31:36 -0800 Subject: Make 'prepare_temp_file()' ignore st_size for symlinks The code was already set up to not really need it, so this just massages it a bit to remove the use entirely. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- diff.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 4b2029caa1..f160c1a35b 100644 --- a/diff.c +++ b/diff.c @@ -1881,13 +1881,12 @@ static void prepare_temp_file(const char *name, if (S_ISLNK(st.st_mode)) { int ret; char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */ - size_t sz = xsize_t(st.st_size); - if (sizeof(buf) <= st.st_size) - die("symlink too long: %s", name); - ret = readlink(name, buf, sz); + ret = readlink(name, buf, sizeof(buf)); if (ret < 0) die("readlink(%s)", name); - prep_temp_blob(temp, buf, sz, + if (ret == sizeof(buf)) + die("symlink too long: %s", name); + prep_temp_blob(temp, buf, ret, (one->sha1_valid ? one->sha1 : null_sha1), (one->sha1_valid ? -- cgit v1.3 From 0956a6db7ae3a93c7bce62c1e3a6e0795055ad9f Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Thu, 18 Dec 2008 17:56:51 +0100 Subject: Fix type-mismatch compiler warning from diff_populate_filespec() The type of the size member of filespec is ulong, while strbuf_detach expects a size_t pointer. This patch should fix the warning: Signed-off-by: Junio C Hamano --- diff.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index f160c1a35b..0484601f42 100644 --- a/diff.c +++ b/diff.c @@ -1778,7 +1778,8 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only) if (strbuf_readlink(&sb, s->path, s->size)) goto err_empty; - s->data = strbuf_detach(&sb, &s->size); + s->size = sb.len; + s->data = strbuf_detach(&sb, NULL); s->should_free = 1; return 0; } -- cgit v1.3 From 6d0e674a575421347abe5749e645ca6dc78c8207 Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Sun, 28 Dec 2008 19:45:32 +0100 Subject: diff: add option to show context between close hunks Merge two hunks if there is only the specified number of otherwise unshown context between them. For --inter-hunk-context=1, the resulting patch has the same number of lines but shows uninterrupted context instead of a context header line in between. Patches generated with this option are easier to read but are also more likely to conflict if the file to be patched contains other changes. This patch keeps the default for this option at 0. It is intended to just make the feature available in order to see its advantages and downsides. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 4 ++ contrib/completion/git-completion.bash | 2 + diff.c | 4 ++ diff.h | 1 + t/t4032-diff-inter-hunk-context.sh | 92 ++++++++++++++++++++++++++++++++++ xdiff/xdiff.h | 1 + xdiff/xemit.c | 3 +- 7 files changed, 106 insertions(+), 1 deletion(-) create mode 100755 t/t4032-diff-inter-hunk-context.sh (limited to 'diff.c') diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index c62b45cdba..c7fcc8007a 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -215,6 +215,10 @@ endif::git-format-patch[] -w:: Shorthand for "--ignore-all-space". +--inter-hunk-context=:: + Show the context between diff hunks, up to the specified number + of lines, thereby fusing hunks that are close to each other. + --exit-code:: Make the program exit with codes similar to diff(1). That is, it exits with 1 if there were differences and diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index e00454983e..a046441974 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -776,6 +776,7 @@ _git_diff () --no-ext-diff --no-prefix --src-prefix= --dst-prefix= --base --ours --theirs + --inter-hunk-context= " return ;; @@ -967,6 +968,7 @@ _git_log () --color-words --walk-reflogs --parents --children --full-history --merge + --inter-hunk-context= " return ;; diff --git a/diff.c b/diff.c index 0484601f42..56b80f9609 100644 --- a/diff.c +++ b/diff.c @@ -1469,6 +1469,7 @@ static void builtin_diff(const char *name_a, ecbdata.file = o->file; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; + xecfg.interhunkctxlen = o->interhunkcontext; xecfg.flags = XDL_EMIT_FUNCNAMES; if (pe) xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags); @@ -2538,6 +2539,9 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->b_prefix = arg + 13; else if (!strcmp(arg, "--no-prefix")) options->a_prefix = options->b_prefix = ""; + else if (opt_arg(arg, '\0', "inter-hunk-context", + &options->interhunkcontext)) + ; else if (!prefixcmp(arg, "--output=")) { options->file = fopen(arg + strlen("--output="), "w"); options->close_file = 1; diff --git a/diff.h b/diff.h index 42582edee6..4d5a32781d 100644 --- a/diff.h +++ b/diff.h @@ -78,6 +78,7 @@ struct diff_options { const char *a_prefix, *b_prefix; unsigned flags; int context; + int interhunkcontext; int break_opt; int detect_rename; int skip_stat_unmatch; diff --git a/t/t4032-diff-inter-hunk-context.sh b/t/t4032-diff-inter-hunk-context.sh new file mode 100755 index 0000000000..e4e3e28fc7 --- /dev/null +++ b/t/t4032-diff-inter-hunk-context.sh @@ -0,0 +1,92 @@ +#!/bin/sh + +test_description='diff hunk fusing' + +. ./test-lib.sh + +f() { + echo $1 + i=1 + while test $i -le $2 + do + echo $i + i=$(expr $i + 1) + done + echo $3 +} + +t() { + case $# in + 4) hunks=$4; cmd="diff -U$3";; + 5) hunks=$5; cmd="diff -U$3 --inter-hunk-context=$4";; + esac + label="$cmd, $1 common $2" + file=f$1 + expected=expected.$file.$3.$hunks + + if ! test -f $file + then + f A $1 B >$file + git add $file + git commit -q -m. $file + f X $1 Y >$file + fi + + test_expect_success "$label: count hunks ($hunks)" " + test $(git $cmd $file | grep '^@@ ' | wc -l) = $hunks + " + + test -f $expected && + test_expect_success "$label: check output" " + git $cmd $file | grep -v '^index ' >actual && + test_cmp $expected actual + " +} + +cat <expected.f1.0.1 || exit 1 +diff --git a/f1 b/f1 +--- a/f1 ++++ b/f1 +@@ -1,3 +1,3 @@ +-A ++X + 1 +-B ++Y +EOF + +cat <expected.f1.0.2 || exit 1 +diff --git a/f1 b/f1 +--- a/f1 ++++ b/f1 +@@ -1 +1 @@ +-A ++X +@@ -3 +3 @@ A +-B ++Y +EOF + +# common lines ctx intrctx hunks +t 1 line 0 2 +t 1 line 0 0 2 +t 1 line 0 1 1 +t 1 line 0 2 1 +t 1 line 1 1 + +t 2 lines 0 2 +t 2 lines 0 0 2 +t 2 lines 0 1 2 +t 2 lines 0 2 1 +t 2 lines 1 1 + +t 3 lines 1 2 +t 3 lines 1 0 2 +t 3 lines 1 1 1 +t 3 lines 1 2 1 + +t 9 lines 3 2 +t 9 lines 3 2 2 +t 9 lines 3 3 1 + +test_done diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 84fff583e2..361f802319 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -84,6 +84,7 @@ typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long typedef struct s_xdemitconf { long ctxlen; + long interhunkctxlen; unsigned long flags; find_func_t find_func; void *find_func_priv; diff --git a/xdiff/xemit.c b/xdiff/xemit.c index 4625c1b421..05bfa41f10 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -59,9 +59,10 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t * */ xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) { xdchange_t *xch, *xchp; + long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen; for (xchp = xscr, xch = xscr->next; xch; xchp = xch, xch = xch->next) - if (xch->i1 - (xchp->i1 + xchp->chg1) > 2 * xecfg->ctxlen) + if (xch->i1 - (xchp->i1 + xchp->chg1) > max_common) break; return xchp; -- cgit v1.3 From d75307084da5f89329de190bb9b4a3196cec1d0e Mon Sep 17 00:00:00 2001 From: Alexander Potashev Date: Sun, 4 Jan 2009 21:38:41 +0300 Subject: remove trailing LF in die() messages LF at the end of format strings given to die() is redundant because die already adds one on its own. Signed-off-by: Alexander Potashev Signed-off-by: Junio C Hamano --- builtin-cat-file.c | 2 +- builtin-clone.c | 14 +++++++------- builtin-fetch.c | 2 +- builtin-init-db.c | 2 +- builtin-log.c | 2 +- builtin-mailinfo.c | 2 +- builtin-merge-recursive.c | 2 +- builtin-update-index.c | 2 +- connect.c | 2 +- daemon.c | 2 +- diff.c | 2 +- git.c | 2 +- grep.c | 2 +- imap-send.c | 6 +++--- index-pack.c | 2 +- pack-redundant.c | 8 ++++---- 16 files changed, 27 insertions(+), 27 deletions(-) (limited to 'diff.c') diff --git a/builtin-cat-file.c b/builtin-cat-file.c index 30d00a6664..8fad19daed 100644 --- a/builtin-cat-file.c +++ b/builtin-cat-file.c @@ -137,7 +137,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) break; default: - die("git cat-file: unknown option: %s\n", exp_type); + die("git cat-file: unknown option: %s", exp_type); } if (!buf) diff --git a/builtin-clone.c b/builtin-clone.c index 2feac9c5cb..f1a1a0c365 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -192,15 +192,15 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) dir = opendir(src->buf); if (!dir) - die("failed to open %s\n", src->buf); + die("failed to open %s", src->buf); if (mkdir(dest->buf, 0777)) { if (errno != EEXIST) - die("failed to create directory %s\n", dest->buf); + die("failed to create directory %s", dest->buf); else if (stat(dest->buf, &buf)) - die("failed to stat %s\n", dest->buf); + die("failed to stat %s", dest->buf); else if (!S_ISDIR(buf.st_mode)) - die("%s exists and is not a directory\n", dest->buf); + die("%s exists and is not a directory", dest->buf); } strbuf_addch(src, '/'); @@ -224,16 +224,16 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) } if (unlink(dest->buf) && errno != ENOENT) - die("failed to unlink %s\n", dest->buf); + die("failed to unlink %s", dest->buf); if (!option_no_hardlinks) { if (!link(src->buf, dest->buf)) continue; if (option_local) - die("failed to create link %s\n", dest->buf); + die("failed to create link %s", dest->buf); option_no_hardlinks = 1; } if (copy_file(dest->buf, src->buf, 0666)) - die("failed to copy file to %s\n", dest->buf); + die("failed to copy file to %s", dest->buf); } closedir(dir); } diff --git a/builtin-fetch.c b/builtin-fetch.c index 7568163af2..de6f3074b1 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -607,7 +607,7 @@ static void set_option(const char *name, const char *value) { int r = transport_set_option(transport, name, value); if (r < 0) - die("Option \"%s\" value \"%s\" is not valid for %s\n", + die("Option \"%s\" value \"%s\" is not valid for %s", name, value, transport->url); if (r > 0) warning("Option \"%s\" is ignored for %s\n", diff --git a/builtin-init-db.c b/builtin-init-db.c index d30c3fe2ca..ee3911f8ee 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -29,7 +29,7 @@ static void safe_create_dir(const char *dir, int share) } } else if (share && adjust_shared_perm(dir)) - die("Could not make %s writable by group\n", dir); + die("Could not make %s writable by group", dir); } static void copy_templates_1(char *path, int baselen, diff --git a/builtin-log.c b/builtin-log.c index bc4e1e9654..4a02ee987a 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -815,7 +815,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) committer = git_committer_info(IDENT_ERROR_ON_NO_NAME); endpos = strchr(committer, '>'); if (!endpos) - die("bogus committer info %s\n", committer); + die("bogus committer info %s", committer); add_signoff = xmemdupz(committer, endpos - committer + 1); } else if (!strcmp(argv[i], "--attach")) { diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c index e890f7a6d1..f7c8c08b32 100644 --- a/builtin-mailinfo.c +++ b/builtin-mailinfo.c @@ -494,7 +494,7 @@ static void convert_to_utf8(struct strbuf *line, const char *charset) return; out = reencode_string(line->buf, metainfo_charset, charset); if (!out) - die("cannot convert from %s to %s\n", + die("cannot convert from %s to %s", charset, metainfo_charset); strbuf_attach(line, out, strlen(out), strlen(out)); } diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 6b534c1a66..703045bfc8 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -33,7 +33,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix) } if (argc < 4) - die("Usage: %s ... -- ...\n", argv[0]); + die("Usage: %s ... -- ...", argv[0]); for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "--")) diff --git a/builtin-update-index.c b/builtin-update-index.c index 65d5775107..5604977505 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -486,7 +486,7 @@ static int unresolve_one(const char *path) static void read_head_pointers(void) { if (read_ref("HEAD", head_sha1)) - die("No HEAD -- no initial commit yet?\n"); + die("No HEAD -- no initial commit yet?"); if (read_ref("MERGE_HEAD", merge_head_sha1)) { fprintf(stderr, "Not in the middle of a merge.\n"); exit(0); diff --git a/connect.c b/connect.c index 2f55ad2c25..2f23ab3b87 100644 --- a/connect.c +++ b/connect.c @@ -315,7 +315,7 @@ static int git_tcp_connect_sock(char *host, int flags) /* Not numeric */ struct servent *se = getservbyname(port,"tcp"); if ( !se ) - die("Unknown port %s\n", port); + die("Unknown port %s", port); nport = se->s_port; } diff --git a/daemon.c b/daemon.c index 60bf6c743c..540700ee84 100644 --- a/daemon.c +++ b/daemon.c @@ -716,7 +716,7 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p) gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); if (gai) - die("getaddrinfo() failed: %s\n", gai_strerror(gai)); + die("getaddrinfo() failed: %s", gai_strerror(gai)); for (ai = ai0; ai; ai = ai->ai_next) { int sockfd; diff --git a/diff.c b/diff.c index 0484601f42..c159a5fc65 100644 --- a/diff.c +++ b/diff.c @@ -2039,7 +2039,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one) if (lstat(one->path, &st) < 0) die("stat %s", one->path); if (index_path(one->sha1, one->path, &st, 0)) - die("cannot hash %s\n", one->path); + die("cannot hash %s", one->path); } } else diff --git a/git.c b/git.c index e0d9071358..a53e24feae 100644 --- a/git.c +++ b/git.c @@ -158,7 +158,7 @@ static int handle_alias(int *argcp, const char ***argv) if (ret >= 0 && WIFEXITED(ret) && WEXITSTATUS(ret) != 127) exit(WEXITSTATUS(ret)); - die("Failed to run '%s' when expanding alias '%s'\n", + die("Failed to run '%s' when expanding alias '%s'", alias_string + 1, alias_command); } count = split_cmdline(alias_string, &new_argv); diff --git a/grep.c b/grep.c index 600f69f2fe..49e9319965 100644 --- a/grep.c +++ b/grep.c @@ -395,7 +395,7 @@ static int match_expr_eval(struct grep_opt *o, h |= match_expr_eval(o, x->u.binary.right, bol, eol, ctx, 1); break; default: - die("Unexpected node type (internal error) %d\n", x->node); + die("Unexpected node type (internal error) %d", x->node); } if (collect_hits) x->hit |= h; diff --git a/imap-send.c b/imap-send.c index 3703dbd1af..c3fa0df855 100644 --- a/imap-send.c +++ b/imap-send.c @@ -115,9 +115,9 @@ static int nfvasprintf(char **strp, const char *fmt, va_list ap) len = vsnprintf(tmp, sizeof(tmp), fmt, ap); if (len < 0) - die("Fatal: Out of memory\n"); + die("Fatal: Out of memory"); if (len >= sizeof(tmp)) - die("imap command overflow !\n"); + die("imap command overflow!"); *strp = xmemdupz(tmp, len); return len; } @@ -482,7 +482,7 @@ static int nfsnprintf(char *buf, int blen, const char *fmt, ...) va_start(va, fmt); if (blen <= 0 || (unsigned)(ret = vsnprintf(buf, blen, fmt, va)) >= (unsigned)blen) - die("Fatal: buffer too small. Please report a bug.\n"); + die("Fatal: buffer too small. Please report a bug."); va_end(va); return ret; } diff --git a/index-pack.c b/index-pack.c index 60ed41a993..2931511e8c 100644 --- a/index-pack.c +++ b/index-pack.c @@ -178,7 +178,7 @@ static char *open_pack_file(char *pack_name) } else output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600); if (output_fd < 0) - die("unable to create %s: %s\n", pack_name, strerror(errno)); + die("unable to create %s: %s", pack_name, strerror(errno)); pack_fd = output_fd; } else { input_fd = open(pack_name, O_RDONLY); diff --git a/pack-redundant.c b/pack-redundant.c index 25b81a445c..e93eb966e2 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -463,7 +463,7 @@ static void minimize(struct pack_list **min) pll_free(perm_all); } if (perm_ok == NULL) - die("Internal error: No complete sets found!\n"); + die("Internal error: No complete sets found!"); /* find the permutation with the smallest size */ perm = perm_ok; @@ -573,14 +573,14 @@ static struct pack_list * add_pack_file(char *filename) struct packed_git *p = packed_git; if (strlen(filename) < 40) - die("Bad pack filename: %s\n", filename); + die("Bad pack filename: %s", filename); while (p) { if (strstr(p->pack_name, filename)) return add_pack(p); p = p->next; } - die("Filename %s not found in packed_git\n", filename); + die("Filename %s not found in packed_git", filename); } static void load_all(void) @@ -636,7 +636,7 @@ int main(int argc, char **argv) add_pack_file(*(argv + i++)); if (local_packs == NULL) - die("Zero packs found!\n"); + die("Zero packs found!"); load_all_objects(); -- cgit v1.3 From 34292bddb861f3cb52a524fdce67234430a744fe Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 1 Jan 2009 17:39:17 +0100 Subject: Introduce the diff option '--patience' This commit teaches Git to produce diff output using the patience diff algorithm with the diff option '--patience'. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 3 + Makefile | 2 +- diff.c | 2 + t/t4033-diff-patience.sh | 168 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100755 t/t4033-diff-patience.sh (limited to 'diff.c') diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index c62b45cdba..808bf87277 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -40,6 +40,9 @@ endif::git-format-patch[] --patch-with-raw:: Synonym for "-p --raw". +--patience: + Generate a diff using the "patience diff" algorithm. + --stat[=width[,name-width]]:: Generate a diffstat. You can override the default output width for 80-column terminal by "--stat=width". diff --git a/Makefile b/Makefile index aabf0130b9..33e6fa403e 100644 --- a/Makefile +++ b/Makefile @@ -1287,7 +1287,7 @@ $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \ - xdiff/xmerge.o + xdiff/xmerge.o xdiff/xpatience.o $(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \ xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h diff --git a/diff.c b/diff.c index 0484601f42..4aeab7746c 100644 --- a/diff.c +++ b/diff.c @@ -2471,6 +2471,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE; else if (!strcmp(arg, "--ignore-space-at-eol")) options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL; + else if (!strcmp(arg, "--patience")) + options->xdl_opts |= XDF_PATIENCE_DIFF; /* flags options */ else if (!strcmp(arg, "--binary")) { diff --git a/t/t4033-diff-patience.sh b/t/t4033-diff-patience.sh new file mode 100755 index 0000000000..1eb14989df --- /dev/null +++ b/t/t4033-diff-patience.sh @@ -0,0 +1,168 @@ +#!/bin/sh + +test_description='patience diff algorithm' + +. ./test-lib.sh + +cat >file1 <<\EOF +#include + +// Frobs foo heartily +int frobnitz(int foo) +{ + int i; + for(i = 0; i < 10; i++) + { + printf("Your answer is: "); + printf("%d\n", foo); + } +} + +int fact(int n) +{ + if(n > 1) + { + return fact(n-1) * n; + } + return 1; +} + +int main(int argc, char **argv) +{ + frobnitz(fact(10)); +} +EOF + +cat >file2 <<\EOF +#include + +int fib(int n) +{ + if(n > 2) + { + return fib(n-1) + fib(n-2); + } + return 1; +} + +// Frobs foo heartily +int frobnitz(int foo) +{ + int i; + for(i = 0; i < 10; i++) + { + printf("%d\n", foo); + } +} + +int main(int argc, char **argv) +{ + frobnitz(fib(10)); +} +EOF + +cat >expect <<\EOF +diff --git a/file1 b/file2 +index 6faa5a3..e3af329 100644 +--- a/file1 ++++ b/file2 +@@ -1,26 +1,25 @@ + #include + ++int fib(int n) ++{ ++ if(n > 2) ++ { ++ return fib(n-1) + fib(n-2); ++ } ++ return 1; ++} ++ + // Frobs foo heartily + int frobnitz(int foo) + { + int i; + for(i = 0; i < 10; i++) + { +- printf("Your answer is: "); + printf("%d\n", foo); + } + } + +-int fact(int n) +-{ +- if(n > 1) +- { +- return fact(n-1) * n; +- } +- return 1; +-} +- + int main(int argc, char **argv) + { +- frobnitz(fact(10)); ++ frobnitz(fib(10)); + } +EOF + +test_expect_success 'patience diff' ' + + test_must_fail git diff --no-index --patience file1 file2 > output && + test_cmp expect output + +' + +test_expect_success 'patience diff output is valid' ' + + mv file2 expect && + git apply < output && + test_cmp expect file2 + +' + +cat >uniq1 <<\EOF +1 +2 +3 +4 +5 +6 +EOF + +cat >uniq2 <<\EOF +a +b +c +d +e +f +EOF + +cat >expect <<\EOF +diff --git a/uniq1 b/uniq2 +index b414108..0fdf397 100644 +--- a/uniq1 ++++ b/uniq2 +@@ -1,6 +1,6 @@ +-1 +-2 +-3 +-4 +-5 +-6 ++a ++b ++c ++d ++e ++f +EOF + +test_expect_success 'completely different files' ' + + test_must_fail git diff --no-index --patience uniq1 uniq2 > output && + test_cmp expect output + +' + +test_done -- cgit v1.3 From 23c1575f747393f9847874fd1ed72a44557459d1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 17 Jan 2009 17:29:43 +0100 Subject: color-words: refactor word splitting and use ALLOC_GROW() Word splitting is now performed by the function diff_words_fill(), avoiding having the same code twice. In the same spirit, avoid duplicating the code of ALLOC_GROW(). Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index d23548292a..c111eef13e 100644 --- a/diff.c +++ b/diff.c @@ -326,10 +326,7 @@ struct diff_words_buffer { static void diff_words_append(char *line, unsigned long len, struct diff_words_buffer *buffer) { - if (buffer->text.size + len > buffer->alloc) { - buffer->alloc = (buffer->text.size + len) * 3 / 2; - buffer->text.ptr = xrealloc(buffer->text.ptr, buffer->alloc); - } + ALLOC_GROW(buffer->text.ptr, buffer->text.size + len, buffer->alloc); line++; len--; memcpy(buffer->text.ptr + buffer->text.size, line, len); @@ -398,6 +395,22 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) } } +/* + * This function splits the words in buffer->text, and stores the list with + * newline separator into out. + */ +static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out) +{ + int i; + out->size = buffer->text.size; + out->ptr = xmalloc(out->size); + memcpy(out->ptr, buffer->text.ptr, out->size); + for (i = 0; i < out->size; i++) + if (isspace(out->ptr[i])) + out->ptr[i] = '\n'; + buffer->current = 0; +} + /* this executes the word diff on the accumulated buffers */ static void diff_words_show(struct diff_words_data *diff_words) { @@ -405,26 +418,11 @@ static void diff_words_show(struct diff_words_data *diff_words) xdemitconf_t xecfg; xdemitcb_t ecb; mmfile_t minus, plus; - int i; memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); - minus.size = diff_words->minus.text.size; - minus.ptr = xmalloc(minus.size); - memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size); - for (i = 0; i < minus.size; i++) - if (isspace(minus.ptr[i])) - minus.ptr[i] = '\n'; - diff_words->minus.current = 0; - - plus.size = diff_words->plus.text.size; - plus.ptr = xmalloc(plus.size); - memcpy(plus.ptr, diff_words->plus.text.ptr, plus.size); - for (i = 0; i < plus.size; i++) - if (isspace(plus.ptr[i])) - plus.ptr[i] = '\n'; - diff_words->plus.current = 0; - + diff_words_fill(&diff_words->minus, &minus); + diff_words_fill(&diff_words->plus, &plus); xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, -- cgit v1.3 From 2e5d2003b28820f88296e47a79eb440ca0295000 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 17 Jan 2009 17:29:44 +0100 Subject: color-words: change algorithm to allow for 0-character word boundaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up until now, the color-words code assumed that word boundaries are identical to white space characters. Therefore, it could get away with a very simple scheme: it copied the hunks, substituted newlines for each white space character, called libxdiff with the processed text, and then identified the text to output by the offsets (which agreed since the original text had the same length). This code was ugly, for a number of reasons: - it was impossible to introduce 0-character word boundaries, - we had to print everything word by word, and - the code needed extra special handling of newlines in the removed part. Fix all of these issues by processing the text such that - we build word lists, separated by newlines, - we remember the original offsets for every word, and - after calling libxdiff on the wordlists, we parse the hunk headers, and find the corresponding offsets, and then - we print the removed/added parts in one go. The pre and post samples in the test were provided by Santi Béjar. Note that there is some strange special handling of hunk headers where one line range is 0 due to POSIX: in this case, the start is one too low. In other words a hunk header '@@ -1,0 +2 @@' actually means that the line must be added after the _second_ line of the pre text, _not_ the first. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 157 +++++++++++++++++++++++++++++--------------------- t/t4034-diff-words.sh | 66 +++++++++++++++++++++ 2 files changed, 157 insertions(+), 66 deletions(-) create mode 100755 t/t4034-diff-words.sh (limited to 'diff.c') diff --git a/diff.c b/diff.c index c111eef13e..37c886a815 100644 --- a/diff.c +++ b/diff.c @@ -319,8 +319,10 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) struct diff_words_buffer { mmfile_t text; long alloc; - long current; /* output pointer */ - int suppressed_newline; + struct diff_words_orig { + const char *begin, *end; + } *orig; + int orig_nr, orig_alloc; }; static void diff_words_append(char *line, unsigned long len, @@ -335,80 +337,89 @@ static void diff_words_append(char *line, unsigned long len, struct diff_words_data { struct diff_words_buffer minus, plus; + const char *current_plus; FILE *file; }; -static void print_word(FILE *file, struct diff_words_buffer *buffer, int len, int color, - int suppress_newline) +static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) { - const char *ptr; - int eol = 0; + struct diff_words_data *diff_words = priv; + int minus_first, minus_len, plus_first, plus_len; + const char *minus_begin, *minus_end, *plus_begin, *plus_end; - if (len == 0) + if (line[0] != '@' || parse_hunk_header(line, len, + &minus_first, &minus_len, &plus_first, &plus_len)) return; - ptr = buffer->text.ptr + buffer->current; - buffer->current += len; + /* POSIX requires that first be decremented by one if len == 0... */ + if (minus_len) { + minus_begin = diff_words->minus.orig[minus_first].begin; + minus_end = + diff_words->minus.orig[minus_first + minus_len - 1].end; + } else + minus_begin = minus_end = + diff_words->minus.orig[minus_first].end; - if (ptr[len - 1] == '\n') { - eol = 1; - len--; - } + if (plus_len) { + plus_begin = diff_words->plus.orig[plus_first].begin; + plus_end = diff_words->plus.orig[plus_first + plus_len - 1].end; + } else + plus_begin = plus_end = diff_words->plus.orig[plus_first].end; - fputs(diff_get_color(1, color), file); - fwrite(ptr, len, 1, file); - fputs(diff_get_color(1, DIFF_RESET), file); + if (diff_words->current_plus != plus_begin) + fwrite(diff_words->current_plus, + plus_begin - diff_words->current_plus, 1, + diff_words->file); + if (minus_begin != minus_end) + color_fwrite_lines(diff_words->file, + diff_get_color(1, DIFF_FILE_OLD), + minus_end - minus_begin, minus_begin); + if (plus_begin != plus_end) + color_fwrite_lines(diff_words->file, + diff_get_color(1, DIFF_FILE_NEW), + plus_end - plus_begin, plus_begin); - if (eol) { - if (suppress_newline) - buffer->suppressed_newline = 1; - else - putc('\n', file); - } -} - -static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) -{ - struct diff_words_data *diff_words = priv; - - if (diff_words->minus.suppressed_newline) { - if (line[0] != '+') - putc('\n', diff_words->file); - diff_words->minus.suppressed_newline = 0; - } - - len--; - switch (line[0]) { - case '-': - print_word(diff_words->file, - &diff_words->minus, len, DIFF_FILE_OLD, 1); - break; - case '+': - print_word(diff_words->file, - &diff_words->plus, len, DIFF_FILE_NEW, 0); - break; - case ' ': - print_word(diff_words->file, - &diff_words->plus, len, DIFF_PLAIN, 0); - diff_words->minus.current += len; - break; - } + diff_words->current_plus = plus_end; } /* - * This function splits the words in buffer->text, and stores the list with - * newline separator into out. + * This function splits the words in buffer->text, stores the list with + * newline separator into out, and saves the offsets of the original words + * in buffer->orig. */ static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out) { - int i; - out->size = buffer->text.size; - out->ptr = xmalloc(out->size); - memcpy(out->ptr, buffer->text.ptr, out->size); - for (i = 0; i < out->size; i++) - if (isspace(out->ptr[i])) - out->ptr[i] = '\n'; - buffer->current = 0; + int i, j; + + out->size = 0; + out->ptr = xmalloc(buffer->text.size); + + /* fake an empty "0th" word */ + ALLOC_GROW(buffer->orig, 1, buffer->orig_alloc); + buffer->orig[0].begin = buffer->orig[0].end = buffer->text.ptr; + buffer->orig_nr = 1; + + for (i = 0; i < buffer->text.size; i++) { + if (isspace(buffer->text.ptr[i])) + continue; + for (j = i + 1; j < buffer->text.size && + !isspace(buffer->text.ptr[j]); j++) + ; /* find the end of the word */ + + /* store original boundaries */ + ALLOC_GROW(buffer->orig, buffer->orig_nr + 1, + buffer->orig_alloc); + buffer->orig[buffer->orig_nr].begin = buffer->text.ptr + i; + buffer->orig[buffer->orig_nr].end = buffer->text.ptr + j; + buffer->orig_nr++; + + /* store one word */ + memcpy(out->ptr + out->size, buffer->text.ptr + i, j - i); + out->ptr[out->size + j - i] = '\n'; + out->size += j - i + 1; + + i = j - 1; + } } /* this executes the word diff on the accumulated buffers */ @@ -419,22 +430,34 @@ static void diff_words_show(struct diff_words_data *diff_words) xdemitcb_t ecb; mmfile_t minus, plus; + /* special case: only removal */ + if (!diff_words->plus.text.size) { + color_fwrite_lines(diff_words->file, + diff_get_color(1, DIFF_FILE_OLD), + diff_words->minus.text.size, diff_words->minus.text.ptr); + diff_words->minus.text.size = 0; + return; + } + + diff_words->current_plus = diff_words->plus.text.ptr; + memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); diff_words_fill(&diff_words->minus, &minus); diff_words_fill(&diff_words->plus, &plus); xpp.flags = XDF_NEED_MINIMAL; - xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; + xecfg.ctxlen = 0; xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); + if (diff_words->current_plus != diff_words->plus.text.ptr + + diff_words->plus.text.size) + fwrite(diff_words->current_plus, + diff_words->plus.text.ptr + diff_words->plus.text.size + - diff_words->current_plus, 1, + diff_words->file); diff_words->minus.text.size = diff_words->plus.text.size = 0; - - if (diff_words->minus.suppressed_newline) { - putc('\n', diff_words->file); - diff_words->minus.suppressed_newline = 0; - } } typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); @@ -458,7 +481,9 @@ static void free_diff_words_data(struct emit_callback *ecbdata) diff_words_show(ecbdata->diff_words); free (ecbdata->diff_words->minus.text.ptr); + free (ecbdata->diff_words->minus.orig); free (ecbdata->diff_words->plus.text.ptr); + free (ecbdata->diff_words->plus.orig); free(ecbdata->diff_words); ecbdata->diff_words = NULL; } diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh new file mode 100755 index 0000000000..b22195f8bb --- /dev/null +++ b/t/t4034-diff-words.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +test_description='word diff colors' + +. ./test-lib.sh + +test_expect_success setup ' + + git config diff.color.old red + git config diff.color.new green + +' + +decrypt_color () { + sed \ + -e 's/.\[1m//g' \ + -e 's/.\[31m//g' \ + -e 's/.\[32m//g' \ + -e 's/.\[36m//g' \ + -e 's/.\[m//g' +} + +word_diff () { + test_must_fail git diff --no-index "$@" pre post > output && + decrypt_color < output > output.decrypted && + test_cmp expect output.decrypted +} + +cat > pre <<\EOF +h(4) + +a = b + c +EOF + +cat > post <<\EOF +h(4),hh[44] + +a = b + c + +aa = a + +aeff = aeff * ( aaa ) +EOF + +cat > expect <<\EOF +diff --git a/pre b/post +index 330b04f..5ed8eff 100644 +--- a/pre ++++ b/post +@@ -1,3 +1,7 @@ +h(4)h(4),hh[44] + +a = b + c + +aa = a + +aeff = aeff * ( aaa ) +EOF + +test_expect_success 'word diff with runs of whitespace' ' + + word_diff --color-words + +' + +test_done -- cgit v1.3 From 2b6a5417d750d086d1da906e46de2b3ad8df6753 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 17 Jan 2009 17:29:45 +0100 Subject: color-words: take an optional regular expression describing words In some applications, words are not delimited by white space. To allow for that, you can specify a regular expression describing what makes a word with git diff --color-words='[A-Za-z0-9]+' Note that words cannot contain newline characters. As suggested by Thomas Rast, the words are the exact matches of the regular expression. Note that a regular expression beginning with a '^' will match only a word at the beginning of the hunk, not a word at the beginning of a line, and is probably not what you want. This commit contains a quoting fix by Thomas Rast. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 6 +++- diff.c | 64 ++++++++++++++++++++++++++++++++++++------ diff.h | 1 + t/t4034-diff-words.sh | 57 +++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 10 deletions(-) (limited to 'diff.c') diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 43793d7500..2c1fa4b102 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -91,8 +91,12 @@ endif::git-format-patch[] Turn off colored diff, even when the configuration file gives the default to color output. ---color-words:: +--color-words[=regex]:: Show colored word diff, i.e. color words which have changed. ++ +Optionally, you can pass a regular expression that tells Git what the +words are that you are looking for; The default is to interpret any +stretch of non-whitespace as a word. --no-renames:: Turn off rename detection, even when the configuration diff --git a/diff.c b/diff.c index 37c886a815..9fb3d0df31 100644 --- a/diff.c +++ b/diff.c @@ -333,12 +333,14 @@ static void diff_words_append(char *line, unsigned long len, len--; memcpy(buffer->text.ptr + buffer->text.size, line, len); buffer->text.size += len; + buffer->text.ptr[buffer->text.size] = '\0'; } struct diff_words_data { struct diff_words_buffer minus, plus; const char *current_plus; FILE *file; + regex_t *word_regex; }; static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) @@ -382,17 +384,49 @@ static void fn_out_diff_words_aux(void *priv, char *line, unsigned long len) diff_words->current_plus = plus_end; } +/* This function starts looking at *begin, and returns 0 iff a word was found. */ +static int find_word_boundaries(mmfile_t *buffer, regex_t *word_regex, + int *begin, int *end) +{ + if (word_regex && *begin < buffer->size) { + regmatch_t match[1]; + if (!regexec(word_regex, buffer->ptr + *begin, 1, match, 0)) { + char *p = memchr(buffer->ptr + *begin + match[0].rm_so, + '\n', match[0].rm_eo - match[0].rm_so); + *end = p ? p - buffer->ptr : match[0].rm_eo + *begin; + *begin += match[0].rm_so; + return *begin >= *end; + } + return -1; + } + + /* find the next word */ + while (*begin < buffer->size && isspace(buffer->ptr[*begin])) + (*begin)++; + if (*begin >= buffer->size) + return -1; + + /* find the end of the word */ + *end = *begin + 1; + while (*end < buffer->size && !isspace(buffer->ptr[*end])) + (*end)++; + + return 0; +} + /* * This function splits the words in buffer->text, stores the list with * newline separator into out, and saves the offsets of the original words * in buffer->orig. */ -static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out) +static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out, + regex_t *word_regex) { int i, j; + long alloc = 0; out->size = 0; - out->ptr = xmalloc(buffer->text.size); + out->ptr = NULL; /* fake an empty "0th" word */ ALLOC_GROW(buffer->orig, 1, buffer->orig_alloc); @@ -400,11 +434,8 @@ static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out) buffer->orig_nr = 1; for (i = 0; i < buffer->text.size; i++) { - if (isspace(buffer->text.ptr[i])) - continue; - for (j = i + 1; j < buffer->text.size && - !isspace(buffer->text.ptr[j]); j++) - ; /* find the end of the word */ + if (find_word_boundaries(&buffer->text, word_regex, &i, &j)) + return; /* store original boundaries */ ALLOC_GROW(buffer->orig, buffer->orig_nr + 1, @@ -414,6 +445,7 @@ static void diff_words_fill(struct diff_words_buffer *buffer, mmfile_t *out) buffer->orig_nr++; /* store one word */ + ALLOC_GROW(out->ptr, out->size + j - i + 1, alloc); memcpy(out->ptr + out->size, buffer->text.ptr + i, j - i); out->ptr[out->size + j - i] = '\n'; out->size += j - i + 1; @@ -443,9 +475,10 @@ static void diff_words_show(struct diff_words_data *diff_words) memset(&xpp, 0, sizeof(xpp)); memset(&xecfg, 0, sizeof(xecfg)); - diff_words_fill(&diff_words->minus, &minus); - diff_words_fill(&diff_words->plus, &plus); + diff_words_fill(&diff_words->minus, &minus, diff_words->word_regex); + diff_words_fill(&diff_words->plus, &plus, diff_words->word_regex); xpp.flags = XDF_NEED_MINIMAL; + /* as only the hunk header will be parsed, we need a 0-context */ xecfg.ctxlen = 0; xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, &xpp, &xecfg, &ecb); @@ -484,6 +517,7 @@ static void free_diff_words_data(struct emit_callback *ecbdata) free (ecbdata->diff_words->minus.orig); free (ecbdata->diff_words->plus.text.ptr); free (ecbdata->diff_words->plus.orig); + free(ecbdata->diff_words->word_regex); free(ecbdata->diff_words); ecbdata->diff_words = NULL; } @@ -1506,6 +1540,14 @@ static void builtin_diff(const char *name_a, ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); ecbdata.diff_words->file = o->file; + if (o->word_regex) { + ecbdata.diff_words->word_regex = (regex_t *) + xmalloc(sizeof(regex_t)); + if (regcomp(ecbdata.diff_words->word_regex, + o->word_regex, REG_EXTENDED)) + die ("Invalid regular expression: %s", + o->word_regex); + } } xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, &xpp, &xecfg, &ecb); @@ -2517,6 +2559,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_CLR(options, COLOR_DIFF); else if (!strcmp(arg, "--color-words")) options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS; + else if (!prefixcmp(arg, "--color-words=")) { + options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS; + options->word_regex = arg + 14; + } else if (!strcmp(arg, "--exit-code")) DIFF_OPT_SET(options, EXIT_WITH_STATUS); else if (!strcmp(arg, "--quiet")) diff --git a/diff.h b/diff.h index 4d5a32781d..23cd90c2e6 100644 --- a/diff.h +++ b/diff.h @@ -98,6 +98,7 @@ struct diff_options { int stat_width; int stat_name_width; + const char *word_regex; /* this is set by diffcore for DIFF_FORMAT_PATCH */ int found_changes; diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index b22195f8bb..4873486301 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -63,4 +63,61 @@ test_expect_success 'word diff with runs of whitespace' ' ' +cat > expect <<\EOF +diff --git a/pre b/post +index 330b04f..5ed8eff 100644 +--- a/pre ++++ b/post +@@ -1,3 +1,7 @@ +h(4),hh[44] + +a = b + c + +aa = a + +aeff = aeff * ( aaa ) +EOF + +test_expect_success 'word diff with a regular expression' ' + + word_diff --color-words="[a-z]+" + +' + +echo 'aaa (aaa)' > pre +echo 'aaa (aaa) aaa' > post + +cat > expect <<\EOF +diff --git a/pre b/post +index c29453b..be22f37 100644 +--- a/pre ++++ b/post +@@ -1 +1 @@ +aaa (aaa) aaa +EOF + +test_expect_success 'test parsing words for newline' ' + + word_diff --color-words="a+" + +' + +echo '(:' > pre +echo '(' > post + +cat > expect <<\EOF +diff --git a/pre b/post +index 289cb9d..2d06f37 100644 +--- a/pre ++++ b/post +@@ -1 +1 @@ +(: +EOF + +test_expect_success 'test when words are only removed at the end' ' + + word_diff --color-words=. + +' + test_done -- cgit v1.3 From bf82940dbf12f066ba42a2a03a5bb626ba22c067 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Sat, 17 Jan 2009 17:29:46 +0100 Subject: color-words: enable REG_NEWLINE to help user We silently truncate a match at the newline, which may lead to unexpected behaviour, e.g., when matching "<[^>]*>" against since then "" doesn't!) even though the regex said only angle-bracket-delimited things can be words. To alleviate the problem slightly, use REG_NEWLINE so that negated classes can't match a newline. Of course newlines can still be matched explicitly. Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- diff.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 9fb3d0df31..00c661f82e 100644 --- a/diff.c +++ b/diff.c @@ -1544,7 +1544,8 @@ static void builtin_diff(const char *name_a, ecbdata.diff_words->word_regex = (regex_t *) xmalloc(sizeof(regex_t)); if (regcomp(ecbdata.diff_words->word_regex, - o->word_regex, REG_EXTENDED)) + o->word_regex, + REG_EXTENDED | REG_NEWLINE)) die ("Invalid regular expression: %s", o->word_regex); } -- cgit v1.3 From 80c49c3de2d5a3aa12b0980a65f1163c8aef0c16 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Sat, 17 Jan 2009 17:29:48 +0100 Subject: color-words: make regex configurable via attributes Make the --color-words splitting regular expression configurable via the diff driver's 'wordregex' attribute. The user can then set the driver on a file in .gitattributes. If a regex is given on the command line, it overrides the driver's setting. We also provide built-in regexes for the languages that already had funcname patterns, and add an appropriate diff driver entry for C/++. (The patterns are designed to run UTF-8 sequences into a single chunk to make sure they remain readable.) Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 4 +++ Documentation/gitattributes.txt | 21 +++++++++++ diff.c | 10 ++++++ t/t4034-diff-words.sh | 36 +++++++++++++++++++ userdiff.c | 78 +++++++++++++++++++++++++++++++++-------- userdiff.h | 1 + 6 files changed, 135 insertions(+), 15 deletions(-) (limited to 'diff.c') diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 8689a92d8d..1edb82e8e1 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -102,6 +102,10 @@ differences. You may want to append `|[^[:space:]]` to your regular expression to make sure that it matches all non-whitespace characters. A match that contains a newline is silently truncated(!) at the newline. ++ +The regex can also be set via a diff driver, see +linkgit:gitattributes[1]; giving it explicitly overrides any diff +driver setting. --no-renames:: Turn off rename detection, even when the configuration diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index 8af22eccac..ba3ba12730 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -317,6 +317,8 @@ patterns are available: - `bibtex` suitable for files with BibTeX coded references. +- `cpp` suitable for source code in the C and C++ languages. + - `html` suitable for HTML/XHTML documents. - `java` suitable for source code in the Java language. @@ -334,6 +336,25 @@ patterns are available: - `tex` suitable for source code for LaTeX documents. +Customizing word diff +^^^^^^^^^^^^^^^^^^^^^ + +You can customize the rules that `git diff --color-words` uses to +split words in a line, by specifying an appropriate regular expression +in the "diff.*.wordregex" configuration variable. For example, in TeX +a backslash followed by a sequence of letters forms a command, but +several such commands can be run together without intervening +whitespace. To separate them, use a regular expression such as + +------------------------ +[diff "tex"] + wordregex = "\\\\[a-zA-Z]+|[{}]|\\\\.|[^\\{}[:space:]]+" +------------------------ + +A built-in pattern is provided for all languages listed in the +previous section. + + Performing text diffs of binary files ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/diff.c b/diff.c index 00c661f82e..9fcde963db 100644 --- a/diff.c +++ b/diff.c @@ -1380,6 +1380,12 @@ static const struct userdiff_funcname *diff_funcname_pattern(struct diff_filespe return one->driver->funcname.pattern ? &one->driver->funcname : NULL; } +static const char *userdiff_word_regex(struct diff_filespec *one) +{ + diff_filespec_load_driver(one); + return one->driver->word_regex; +} + void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b) { if (!options->a_prefix) @@ -1540,6 +1546,10 @@ static void builtin_diff(const char *name_a, ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); ecbdata.diff_words->file = o->file; + if (!o->word_regex) + o->word_regex = userdiff_word_regex(one); + if (!o->word_regex) + o->word_regex = userdiff_word_regex(two); if (o->word_regex) { ecbdata.diff_words->word_regex = (regex_t *) xmalloc(sizeof(regex_t)); diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 4873486301..744221bef9 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -84,6 +84,41 @@ test_expect_success 'word diff with a regular expression' ' ' +test_expect_success 'set a diff driver' ' + git config diff.testdriver.wordregex "[^[:space:]]" && + cat < .gitattributes +pre diff=testdriver +post diff=testdriver +EOF +' + +test_expect_success 'option overrides default' ' + + word_diff --color-words="[a-z]+" + +' + +cat > expect <<\EOF +diff --git a/pre b/post +index 330b04f..5ed8eff 100644 +--- a/pre ++++ b/post +@@ -1,3 +1,7 @@ +h(4),hh[44] + +a = b + c + +aa = a + +aeff = aeff * ( aaa ) +EOF + +test_expect_success 'use default supplied by driver' ' + + word_diff --color-words + +' + echo 'aaa (aaa)' > pre echo 'aaa (aaa) aaa' > post @@ -100,6 +135,7 @@ test_expect_success 'test parsing words for newline' ' word_diff --color-words="a+" + ' echo '(:' > pre diff --git a/userdiff.c b/userdiff.c index 3681062ebf..2b55509485 100644 --- a/userdiff.c +++ b/userdiff.c @@ -6,14 +6,20 @@ static struct userdiff_driver *drivers; static int ndrivers; static int drivers_alloc; -#define FUNCNAME(name, pattern) \ - { name, NULL, -1, { pattern, REG_EXTENDED } } +#define PATTERNS(name, pattern, wordregex) \ + { name, NULL, -1, { pattern, REG_EXTENDED }, wordregex } static struct userdiff_driver builtin_drivers[] = { -FUNCNAME("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$"), -FUNCNAME("java", +PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$", + "[^<>= \t]+|[^[:space:]]|[\x80-\xff]+"), +PATTERNS("java", "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n" - "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$"), -FUNCNAME("objc", + "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$", + "[a-zA-Z_][a-zA-Z0-9_]*" + "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" + "|[-+*/<>%&^|=!]=" + "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|" + "|[^[:space:]]|[\x80-\xff]+"), +PATTERNS("objc", /* Negate C statements that can look like functions */ "!^[ \t]*(do|for|if|else|return|switch|while)\n" /* Objective-C methods */ @@ -21,20 +27,60 @@ FUNCNAME("objc", /* C functions */ "^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$\n" /* Objective-C class/protocol definitions */ - "^(@(implementation|interface|protocol)[ \t].*)$"), -FUNCNAME("pascal", + "^(@(implementation|interface|protocol)[ \t].*)$", + /* -- */ + "[a-zA-Z_][a-zA-Z0-9_]*" + "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" + "|[^[:space:]]|[\x80-\xff]+"), +PATTERNS("pascal", "^((procedure|function|constructor|destructor|interface|" "implementation|initialization|finalization)[ \t]*.*)$" "\n" - "^(.*=[ \t]*(class|record).*)$"), -FUNCNAME("php", "^[\t ]*((function|class).*)"), -FUNCNAME("python", "^[ \t]*((class|def)[ \t].*)$"), -FUNCNAME("ruby", "^[ \t]*((class|module|def)[ \t].*)$"), -FUNCNAME("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$"), -FUNCNAME("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$"), + "^(.*=[ \t]*(class|record).*)$", + /* -- */ + "[a-zA-Z_][a-zA-Z0-9_]*" + "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+" + "|<>|<=|>=|:=|\\.\\." + "|[^[:space:]]|[\x80-\xff]+"), +PATTERNS("php", "^[\t ]*((function|class).*)", + /* -- */ + "[a-zA-Z_][a-zA-Z0-9_]*" + "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+" + "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->" + "|[^[:space:]]|[\x80-\xff]+"), +PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$", + /* -- */ + "[a-zA-Z_][a-zA-Z0-9_]*" + "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?" + "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?" + "|[^[:space:]|[\x80-\xff]+"), + /* -- */ +PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$", + /* -- */ + "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*" + "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?." + "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~" + "|[^[:space:]|[\x80-\xff]+"), +PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", + "[={}\"]|[^={}\" \t]+"), +PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", + "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+|[^[:space:]]"), +PATTERNS("cpp", + /* Jump targets or access declarations */ + "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n" + /* C/++ functions/methods at top level */ + "^([A-Za-z_][A-Za-z_0-9]*([ \t]+[A-Za-z_][A-Za-z_0-9]*([ \t]*::[ \t]*[^[:space:]]+)?){1,}[ \t]*\\([^;]*)$\n" + /* compound type at top level */ + "^((struct|class|enum)[^;]*)$", + /* -- */ + "[a-zA-Z_][a-zA-Z0-9_]*" + "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?" + "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->" + "|[^[:space:]]|[\x80-\xff]+"), { "default", NULL, -1, { NULL, 0 } }, }; -#undef FUNCNAME +#undef PATTERNS static struct userdiff_driver driver_true = { "diff=true", @@ -134,6 +180,8 @@ int userdiff_config(const char *k, const char *v) return parse_string(&drv->external, k, v); if ((drv = parse_driver(k, v, "textconv"))) return parse_string(&drv->textconv, k, v); + if ((drv = parse_driver(k, v, "wordregex"))) + return parse_string(&drv->word_regex, k, v); return 0; } diff --git a/userdiff.h b/userdiff.h index ba2945770b..c3151594f5 100644 --- a/userdiff.h +++ b/userdiff.h @@ -11,6 +11,7 @@ struct userdiff_driver { const char *external; int binary; struct userdiff_funcname funcname; + const char *word_regex; const char *textconv; }; -- cgit v1.3 From 950db8798d51cb183c858938263425b367b21dfd Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 20 Jan 2009 22:08:33 +0100 Subject: Rename diff.suppress-blank-empty to diff.suppressBlankEmpty All the other config variables use CamelCase. This config variable should not be an exception. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- Documentation/config.txt | 2 +- diff.c | 4 +++- t/t4029-diff-trailing-space.sh | 8 ++++---- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'diff.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index 52786c7df5..26551ea6e1 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -635,7 +635,7 @@ diff.renames:: will enable basic rename detection. If set to "copies" or "copy", it will detect copies, as well. -diff.suppress-blank-empty:: +diff.suppressBlankEmpty:: A boolean to inhibit the standard behavior of printing a space before each empty output line. Defaults to false. diff --git a/diff.c b/diff.c index 0484601f42..5b85b4077a 100644 --- a/diff.c +++ b/diff.c @@ -118,7 +118,9 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) } /* like GNU diff's --suppress-blank-empty option */ - if (!strcmp(var, "diff.suppress-blank-empty")) { + if (!strcmp(var, "diff.suppressblankempty") || + /* for backwards compatibility */ + !strcmp(var, "diff.suppress-blank-empty")) { diff_suppress_blank_empty = git_config_bool(var, value); return 0; } diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh index 4ca65e0332..9ddbbcde57 100755 --- a/t/t4029-diff-trailing-space.sh +++ b/t/t4029-diff-trailing-space.sh @@ -2,7 +2,7 @@ # # Copyright (c) Jim Meyering # -test_description='diff honors config option, diff.suppress-blank-empty' +test_description='diff honors config option, diff.suppressBlankEmpty' . ./test-lib.sh @@ -24,14 +24,14 @@ test_expect_success \ git add f && git commit -q -m. f && printf "\ny\n" > f && - git config --bool diff.suppress-blank-empty true && + git config --bool diff.suppressBlankEmpty true && git diff f > actual && test_cmp exp actual && perl -i.bak -p -e "s/^\$/ /" exp && - git config --bool diff.suppress-blank-empty false && + git config --bool diff.suppressBlankEmpty false && git diff f > actual && test_cmp exp actual && - git config --bool --unset diff.suppress-blank-empty && + git config --bool --unset diff.suppressBlankEmpty && git diff f > actual && test_cmp exp actual ' -- cgit v1.3 From 98a4d87b87e9846eafd21ba232cc2b7ba3f718fc Mon Sep 17 00:00:00 2001 From: Boyd Stephen Smith Jr Date: Tue, 20 Jan 2009 21:46:57 -0600 Subject: color-words: Support diff.wordregex config option When diff is invoked with --color-words (w/o =regex), use the regular expression the user has configured as diff.wordregex. diff drivers configured via attributes take precedence over the diff.wordregex-words setting. If the user wants to change them, they have their own configuration variables. Signed-off-by: Boyd Stephen Smith Jr Signed-off-by: Junio C Hamano --- Documentation/config.txt | 6 ++++++ Documentation/diff-options.txt | 7 ++++--- diff.c | 5 +++++ t/t4034-diff-words.sh | 45 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 58 insertions(+), 5 deletions(-) (limited to 'diff.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index 7408bb2d34..0ca983ac3b 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -639,6 +639,12 @@ diff.suppress-blank-empty:: A boolean to inhibit the standard behavior of printing a space before each empty output line. Defaults to false. +diff.wordregex:: + A POSIX Extended Regular Expression used to determine what is a "word" + when performing word-by-word difference calculations. Character + sequences that match the regular expression are "words", all other + characters are *ignorable* whitespace. + fetch.unpackLimit:: If the number of objects fetched over the git native transfer is below this diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 1edb82e8e1..164e2c5348 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -103,9 +103,10 @@ expression to make sure that it matches all non-whitespace characters. A match that contains a newline is silently truncated(!) at the newline. + -The regex can also be set via a diff driver, see -linkgit:gitattributes[1]; giving it explicitly overrides any diff -driver setting. +The regex can also be set via a diff driver or configuration option, see +linkgit:gitattributes[1] or linkgit:git-config[1]. Giving it explicitly +overrides any diff driver or configuration setting. Diff drivers +override configuration settings. --no-renames:: Turn off rename detection, even when the configuration diff --git a/diff.c b/diff.c index 9fcde963db..ed8b83c68f 100644 --- a/diff.c +++ b/diff.c @@ -23,6 +23,7 @@ static int diff_detect_rename_default; static int diff_rename_limit_default = 200; static int diff_suppress_blank_empty; int diff_use_color_default = -1; +static const char *diff_word_regex_cfg; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; @@ -92,6 +93,8 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); + if (!strcmp(var, "diff.wordregex")) + return git_config_string(&diff_word_regex_cfg, var, value); return git_diff_basic_config(var, value, cb); } @@ -1550,6 +1553,8 @@ static void builtin_diff(const char *name_a, o->word_regex = userdiff_word_regex(one); if (!o->word_regex) o->word_regex = userdiff_word_regex(two); + if (!o->word_regex) + o->word_regex = diff_word_regex_cfg; if (o->word_regex) { ecbdata.diff_words->word_regex = (regex_t *) xmalloc(sizeof(regex_t)); diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 744221bef9..6bcc153084 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -77,6 +77,7 @@ a = b + c aeff = aeff * ( aaa ) EOF +cp expect expect.letter-runs-are-words test_expect_success 'word diff with a regular expression' ' @@ -92,7 +93,7 @@ post diff=testdriver EOF ' -test_expect_success 'option overrides default' ' +test_expect_success 'option overrides .gitattributes' ' word_diff --color-words="[a-z]+" @@ -112,13 +113,53 @@ a = b + c aeff = aeff * ( aaa ) EOF +cp expect expect.non-whitespace-is-word -test_expect_success 'use default supplied by driver' ' +test_expect_success 'use regex supplied by driver' ' word_diff --color-words ' +test_expect_success 'set diff.wordregex option' ' + git config diff.wordregex "[[:alnum:]]+" +' + +cp expect.letter-runs-are-words expect + +test_expect_success 'command-line overrides config' ' + word_diff --color-words="[a-z]+" +' + +cp expect.non-whitespace-is-word expect + +test_expect_success '.gitattributes override config' ' + word_diff --color-words +' + +test_expect_success 'remove diff driver regex' ' + git config --unset diff.testdriver.wordregex +' + +cat > expect <<\EOF +diff --git a/pre b/post +index 330b04f..5ed8eff 100644 +--- a/pre ++++ b/post +@@ -1,3 +1,7 @@ +h(4),hh[44] + +a = b + c + +aa = a + +aeff = aeff * ( aaa ) +EOF + +test_expect_success 'use configured regex' ' + word_diff --color-words +' + echo 'aaa (aaa)' > pre echo 'aaa (aaa) aaa' > post -- cgit v1.3 From 479b0ae81c9291a8bb8d7b2347cc58eeaa701304 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Jan 2009 00:59:56 -0500 Subject: diff: refactor tempfile cleanup handling There are two pieces of code that create tempfiles for diff: run_external_diff and run_textconv. The former cleans up its tempfiles in the face of premature death (i.e., by die() or by signal), but the latter does not. After this patch, they will both use the same cleanup routines. To make clear what the change is, let me first explain what happens now: - run_external_diff uses a static global array of 2 diff_tempfile structs (since it knows it will always need exactly 2 tempfiles). It calls prepare_temp_file (which doesn't know anything about the global array) on each of the structs, creating the tempfiles that need to be cleaned up. It then registers atexit and signal handlers to look through the global array and remove the tempfiles. If it succeeds, it calls the handler manually (which marks the tempfile structs as unused). - textconv has its own tempfile struct, which it allocates using prepare_temp_file and cleans up manually. No signal or atexit handlers. The new code moves the installation of cleanup handlers into the prepare_temp_file function. Which means that that function now has to understand that there is static tempfile storage. So what happens now is: - run_external_diff calls prepare_temp_file - prepare_temp_file calls claim_diff_tempfile, which allocates an unused slot from our global array - prepare_temp_file installs (if they have not already been installed) atexit and signal handlers for cleanup - prepare_temp_file sets up the tempfile as usual - prepare_temp_file returns a pointer to the allocated tempfile The advantage being that run_external_diff no longer has to care about setting up cleanup handlers. Now by virtue of calling prepare_temp_file, run_textconv gets the same benefit, as will any future users of prepare_temp_file. There are also a few side benefits to the specific implementation: - we now install cleanup handlers _before_ allocating the tempfile, closing a race which could leave temp cruft - when allocating a slot in the global array, we will now detect a situation where the old slots were not properly vacated (i.e., somebody forgot to call remove upon leaving the function). In the old code, such a situation would silently overwrite the tempfile names, meaning we would forget to clean them up. The new code dies with a bug warning. - we make sure only to install the signal handler once. This isn't a big deal, since we are just overwriting the old handler, but will become an issue when a later patch converts the code to use sigchain Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 107 +++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 55 insertions(+), 52 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index d23548292a..3cfc0b636c 100644 --- a/diff.c +++ b/diff.c @@ -165,6 +165,33 @@ static struct diff_tempfile { char tmp_path[PATH_MAX]; } diff_temp[2]; +static struct diff_tempfile *claim_diff_tempfile(void) { + int i; + for (i = 0; i < ARRAY_SIZE(diff_temp); i++) + if (!diff_temp[i].name) + return diff_temp + i; + die("BUG: diff is failing to clean up its tempfiles"); +} + +static int remove_tempfile_installed; + +static void remove_tempfile(void) +{ + int i; + for (i = 0; i < ARRAY_SIZE(diff_temp); i++) + if (diff_temp[i].name == diff_temp[i].tmp_path) { + unlink(diff_temp[i].name); + diff_temp[i].name = NULL; + } +} + +static void remove_tempfile_on_signal(int signo) +{ + remove_tempfile(); + signal(SIGINT, SIG_DFL); + raise(signo); +} + static int count_lines(const char *data, int size) { int count, ch, completely_empty = 1, nl_just_seen = 0; @@ -1857,10 +1884,11 @@ static void prep_temp_blob(struct diff_tempfile *temp, sprintf(temp->mode, "%06o", mode); } -static void prepare_temp_file(const char *name, - struct diff_tempfile *temp, - struct diff_filespec *one) +static struct diff_tempfile *prepare_temp_file(const char *name, + struct diff_filespec *one) { + struct diff_tempfile *temp = claim_diff_tempfile(); + if (!DIFF_FILE_VALID(one)) { not_a_valid_file: /* A '-' entry produces this for file-2, and @@ -1869,7 +1897,13 @@ static void prepare_temp_file(const char *name, temp->name = "/dev/null"; strcpy(temp->hex, "."); strcpy(temp->mode, "."); - return; + return temp; + } + + if (!remove_tempfile_installed) { + atexit(remove_tempfile); + signal(SIGINT, remove_tempfile_on_signal); + remove_tempfile_installed = 1; } if (!one->sha1_valid || @@ -1909,7 +1943,7 @@ static void prepare_temp_file(const char *name, */ sprintf(temp->mode, "%06o", one->mode); } - return; + return temp; } else { if (diff_populate_filespec(one, 0)) @@ -1917,24 +1951,7 @@ static void prepare_temp_file(const char *name, prep_temp_blob(temp, one->data, one->size, one->sha1, one->mode); } -} - -static void remove_tempfile(void) -{ - int i; - - for (i = 0; i < 2; i++) - if (diff_temp[i].name == diff_temp[i].tmp_path) { - unlink(diff_temp[i].name); - diff_temp[i].name = NULL; - } -} - -static void remove_tempfile_on_signal(int signo) -{ - remove_tempfile(); - signal(SIGINT, SIG_DFL); - raise(signo); + return temp; } /* An external diff command takes: @@ -1952,34 +1969,22 @@ static void run_external_diff(const char *pgm, int complete_rewrite) { const char *spawn_arg[10]; - struct diff_tempfile *temp = diff_temp; int retval; - static int atexit_asked = 0; - const char *othername; const char **arg = &spawn_arg[0]; - othername = (other? other : name); - if (one && two) { - prepare_temp_file(name, &temp[0], one); - prepare_temp_file(othername, &temp[1], two); - if (! atexit_asked && - (temp[0].name == temp[0].tmp_path || - temp[1].name == temp[1].tmp_path)) { - atexit_asked = 1; - atexit(remove_tempfile); - } - signal(SIGINT, remove_tempfile_on_signal); - } - if (one && two) { + struct diff_tempfile *temp_one, *temp_two; + const char *othername = (other ? other : name); + temp_one = prepare_temp_file(name, one); + temp_two = prepare_temp_file(othername, two); *arg++ = pgm; *arg++ = name; - *arg++ = temp[0].name; - *arg++ = temp[0].hex; - *arg++ = temp[0].mode; - *arg++ = temp[1].name; - *arg++ = temp[1].hex; - *arg++ = temp[1].mode; + *arg++ = temp_one->name; + *arg++ = temp_one->hex; + *arg++ = temp_one->mode; + *arg++ = temp_two->name; + *arg++ = temp_two->hex; + *arg++ = temp_two->mode; if (other) { *arg++ = other; *arg++ = xfrm_msg; @@ -3448,15 +3453,15 @@ void diff_unmerge(struct diff_options *options, static char *run_textconv(const char *pgm, struct diff_filespec *spec, size_t *outsize) { - struct diff_tempfile temp; + struct diff_tempfile *temp; const char *argv[3]; const char **arg = argv; struct child_process child; struct strbuf buf = STRBUF_INIT; - prepare_temp_file(spec->path, &temp, spec); + temp = prepare_temp_file(spec->path, spec); *arg++ = pgm; - *arg++ = temp.name; + *arg++ = temp->name; *arg = NULL; memset(&child, 0, sizeof(child)); @@ -3465,13 +3470,11 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, if (start_command(&child) != 0 || strbuf_read(&buf, child.out, 0) < 0 || finish_command(&child) != 0) { - if (temp.name == temp.tmp_path) - unlink(temp.name); + remove_tempfile(); error("error running textconv command '%s'", pgm); return NULL; } - if (temp.name == temp.tmp_path) - unlink(temp.name); + remove_tempfile(); return strbuf_detach(&buf, outsize); } -- cgit v1.3 From 4a16d072723b48699ea162da24eff05eba298834 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Jan 2009 01:02:35 -0500 Subject: chain kill signals for cleanup functions If a piece of code wanted to do some cleanup before exiting (e.g., cleaning up a lockfile or a tempfile), our usual strategy was to install a signal handler that did something like this: do_cleanup(); /* actual work */ signal(signo, SIG_DFL); /* restore previous behavior */ raise(signo); /* deliver signal, killing ourselves */ For a single handler, this works fine. However, if we want to clean up two _different_ things, we run into a problem. The most recently installed handler will run, but when it removes itself as a handler, it doesn't put back the first handler. This patch introduces sigchain, a tiny library for handling a stack of signal handlers. You sigchain_push each handler, and use sigchain_pop to restore whoever was before you in the stack. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- .gitignore | 1 + Makefile | 3 +++ builtin-clone.c | 5 +++-- builtin-fetch--tool.c | 5 +++-- builtin-fetch.c | 5 +++-- diff.c | 5 +++-- http-push.c | 11 ++++++----- lockfile.c | 13 +++++++------ sigchain.c | 43 +++++++++++++++++++++++++++++++++++++++++++ sigchain.h | 9 +++++++++ t/t0005-signals.sh | 22 ++++++++++++++++++++++ test-sigchain.c | 22 ++++++++++++++++++++++ 12 files changed, 125 insertions(+), 19 deletions(-) create mode 100644 sigchain.c create mode 100644 sigchain.h create mode 100755 t/t0005-signals.sh create mode 100644 test-sigchain.c (limited to 'diff.c') diff --git a/.gitignore b/.gitignore index d9adce585a..f28a54d262 100644 --- a/.gitignore +++ b/.gitignore @@ -152,6 +152,7 @@ test-match-trees test-parse-options test-path-utils test-sha1 +test-sigchain common-cmds.h *.tar.gz *.dsc diff --git a/Makefile b/Makefile index 2b873fa99f..fd02decc01 100644 --- a/Makefile +++ b/Makefile @@ -388,6 +388,7 @@ LIB_H += revision.h LIB_H += run-command.h LIB_H += sha1-lookup.h LIB_H += sideband.h +LIB_H += sigchain.h LIB_H += strbuf.h LIB_H += tag.h LIB_H += transport.h @@ -481,6 +482,7 @@ LIB_OBJS += sha1-lookup.o LIB_OBJS += sha1_name.o LIB_OBJS += shallow.o LIB_OBJS += sideband.o +LIB_OBJS += sigchain.o LIB_OBJS += strbuf.o LIB_OBJS += symlinks.o LIB_OBJS += tag.o @@ -1364,6 +1366,7 @@ TEST_PROGRAMS += test-match-trees$X TEST_PROGRAMS += test-parse-options$X TEST_PROGRAMS += test-path-utils$X TEST_PROGRAMS += test-sha1$X +TEST_PROGRAMS += test-sigchain$X all:: $(TEST_PROGRAMS) diff --git a/builtin-clone.c b/builtin-clone.c index f1a1a0c365..18b9392334 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -19,6 +19,7 @@ #include "strbuf.h" #include "dir.h" #include "pack-refs.h" +#include "sigchain.h" /* * Overall FIXMEs: @@ -288,7 +289,7 @@ static void remove_junk(void) static void remove_junk_on_signal(int signo) { remove_junk(); - signal(SIGINT, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -438,7 +439,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } junk_git_dir = git_dir; atexit(remove_junk); - signal(SIGINT, remove_junk_on_signal); + sigchain_push(SIGINT, remove_junk_on_signal); setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1); diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c index 469b07e240..b1d7f8fb32 100644 --- a/builtin-fetch--tool.c +++ b/builtin-fetch--tool.c @@ -2,6 +2,7 @@ #include "cache.h" #include "refs.h" #include "commit.h" +#include "sigchain.h" static char *get_stdin(void) { @@ -186,7 +187,7 @@ static void remove_keep(void) static void remove_keep_on_signal(int signo) { remove_keep(); - signal(SIGINT, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -245,7 +246,7 @@ static int fetch_native_store(FILE *fp, char buffer[1024]; int err = 0; - signal(SIGINT, remove_keep_on_signal); + sigchain_push(SIGINT, remove_keep_on_signal); atexit(remove_keep); while (fgets(buffer, sizeof(buffer), stdin)) { diff --git a/builtin-fetch.c b/builtin-fetch.c index de6f3074b1..8c86974cbe 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -10,6 +10,7 @@ #include "transport.h" #include "run-command.h" #include "parse-options.h" +#include "sigchain.h" static const char * const builtin_fetch_usage[] = { "git fetch [options] [ ...]", @@ -58,7 +59,7 @@ static void unlock_pack(void) static void unlock_pack_on_signal(int signo) { unlock_pack(); - signal(SIGINT, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -672,7 +673,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) ref_nr = j; } - signal(SIGINT, unlock_pack_on_signal); + sigchain_push(SIGINT, unlock_pack_on_signal); atexit(unlock_pack); exit_code = do_fetch(transport, parse_fetch_refspec(ref_nr, refs), ref_nr); diff --git a/diff.c b/diff.c index 3cfc0b636c..9c9977d892 100644 --- a/diff.c +++ b/diff.c @@ -12,6 +12,7 @@ #include "run-command.h" #include "utf8.h" #include "userdiff.h" +#include "sigchain.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -188,7 +189,7 @@ static void remove_tempfile(void) static void remove_tempfile_on_signal(int signo) { remove_tempfile(); - signal(SIGINT, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -1902,7 +1903,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, if (!remove_tempfile_installed) { atexit(remove_tempfile); - signal(SIGINT, remove_tempfile_on_signal); + sigchain_push(SIGINT, remove_tempfile_on_signal); remove_tempfile_installed = 1; } diff --git a/http-push.c b/http-push.c index a4b7d08663..dec395deed 100644 --- a/http-push.c +++ b/http-push.c @@ -10,6 +10,7 @@ #include "exec_cmd.h" #include "remote.h" #include "list-objects.h" +#include "sigchain.h" #include @@ -1363,7 +1364,7 @@ static void remove_locks(void) static void remove_locks_on_signal(int signo) { remove_locks(); - signal(signo, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -2261,10 +2262,10 @@ int main(int argc, char **argv) goto cleanup; } - signal(SIGINT, remove_locks_on_signal); - signal(SIGHUP, remove_locks_on_signal); - signal(SIGQUIT, remove_locks_on_signal); - signal(SIGTERM, remove_locks_on_signal); + sigchain_push(SIGINT, remove_locks_on_signal); + sigchain_push(SIGHUP, remove_locks_on_signal); + sigchain_push(SIGQUIT, remove_locks_on_signal); + sigchain_push(SIGTERM, remove_locks_on_signal); /* Check whether the remote has server info files */ remote->can_update_info_refs = 0; diff --git a/lockfile.c b/lockfile.c index 8589155532..3cd57dc385 100644 --- a/lockfile.c +++ b/lockfile.c @@ -2,6 +2,7 @@ * Copyright (c) 2005, Junio C Hamano */ #include "cache.h" +#include "sigchain.h" static struct lock_file *lock_file_list; static const char *alternate_index_output; @@ -24,7 +25,7 @@ static void remove_lock_file(void) static void remove_lock_file_on_signal(int signo) { remove_lock_file(); - signal(signo, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -136,11 +137,11 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= lk->fd) { if (!lock_file_list) { - signal(SIGINT, remove_lock_file_on_signal); - signal(SIGHUP, remove_lock_file_on_signal); - signal(SIGTERM, remove_lock_file_on_signal); - signal(SIGQUIT, remove_lock_file_on_signal); - signal(SIGPIPE, remove_lock_file_on_signal); + sigchain_push(SIGINT, remove_lock_file_on_signal); + sigchain_push(SIGHUP, remove_lock_file_on_signal); + sigchain_push(SIGTERM, remove_lock_file_on_signal); + sigchain_push(SIGQUIT, remove_lock_file_on_signal); + sigchain_push(SIGPIPE, remove_lock_file_on_signal); atexit(remove_lock_file); } lk->owner = getpid(); diff --git a/sigchain.c b/sigchain.c new file mode 100644 index 0000000000..a18d505e56 --- /dev/null +++ b/sigchain.c @@ -0,0 +1,43 @@ +#include "sigchain.h" +#include "cache.h" + +#define SIGCHAIN_MAX_SIGNALS 32 + +struct sigchain_signal { + sigchain_fun *old; + int n; + int alloc; +}; +static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS]; + +static void check_signum(int sig) +{ + if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS) + die("BUG: signal out of range: %d", sig); +} + +int sigchain_push(int sig, sigchain_fun f) +{ + struct sigchain_signal *s = signals + sig; + check_signum(sig); + + ALLOC_GROW(s->old, s->n + 1, s->alloc); + s->old[s->n] = signal(sig, f); + if (s->old[s->n] == SIG_ERR) + return -1; + s->n++; + return 0; +} + +int sigchain_pop(int sig) +{ + struct sigchain_signal *s = signals + sig; + check_signum(sig); + if (s->n < 1) + return 0; + + if (signal(sig, s->old[s->n - 1]) == SIG_ERR) + return -1; + s->n--; + return 0; +} diff --git a/sigchain.h b/sigchain.h new file mode 100644 index 0000000000..254ebb0fa6 --- /dev/null +++ b/sigchain.h @@ -0,0 +1,9 @@ +#ifndef SIGCHAIN_H +#define SIGCHAIN_H + +typedef void (*sigchain_fun)(int); + +int sigchain_push(int sig, sigchain_fun f); +int sigchain_pop(int sig); + +#endif /* SIGCHAIN_H */ diff --git a/t/t0005-signals.sh b/t/t0005-signals.sh new file mode 100755 index 0000000000..9707af7d03 --- /dev/null +++ b/t/t0005-signals.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +test_description='signals work as we expect' +. ./test-lib.sh + +cat >expect <actual + case "$?" in + 130) true ;; # POSIX w/ SIGINT=2 + 3) true ;; # Windows + *) false ;; + esac && + test_cmp expect actual +' + +test_done diff --git a/test-sigchain.c b/test-sigchain.c new file mode 100644 index 0000000000..8747deac62 --- /dev/null +++ b/test-sigchain.c @@ -0,0 +1,22 @@ +#include "sigchain.h" +#include "cache.h" + +#define X(f) \ +static void f(int sig) { \ + puts(#f); \ + fflush(stdout); \ + sigchain_pop(sig); \ + raise(sig); \ +} +X(one) +X(two) +X(three) +#undef X + +int main(int argc, char **argv) { + sigchain_push(SIGINT, one); + sigchain_push(SIGINT, two); + sigchain_push(SIGINT, three); + raise(SIGINT); + return 0; +} -- cgit v1.3 From 57b235a4bc8884a57c6f863605a54b7bfceb0997 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Jan 2009 01:03:08 -0500 Subject: refactor signal handling for cleanup functions The current code is very inconsistent about which signals are caught for doing cleanup of temporary files and lock files. Some callsites checked only SIGINT, while others checked a variety of death-dealing signals. This patch factors out those signals to a single function, and then calls it everywhere. For some sites, that means this is a simple clean up. For others, it is an improvement in that they will now properly clean themselves up after a larger variety of signals. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-clone.c | 2 +- builtin-fetch--tool.c | 2 +- builtin-fetch.c | 2 +- diff.c | 2 +- http-push.c | 5 +---- lockfile.c | 6 +----- sigchain.c | 9 +++++++++ sigchain.h | 2 ++ 8 files changed, 17 insertions(+), 13 deletions(-) (limited to 'diff.c') diff --git a/builtin-clone.c b/builtin-clone.c index 18b9392334..44c80734b7 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -439,7 +439,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } junk_git_dir = git_dir; atexit(remove_junk); - sigchain_push(SIGINT, remove_junk_on_signal); + sigchain_push_common(remove_junk_on_signal); setenv(CONFIG_ENVIRONMENT, xstrdup(mkpath("%s/config", git_dir)), 1); diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c index b1d7f8fb32..29356d25db 100644 --- a/builtin-fetch--tool.c +++ b/builtin-fetch--tool.c @@ -246,7 +246,7 @@ static int fetch_native_store(FILE *fp, char buffer[1024]; int err = 0; - sigchain_push(SIGINT, remove_keep_on_signal); + sigchain_push_common(remove_keep_on_signal); atexit(remove_keep); while (fgets(buffer, sizeof(buffer), stdin)) { diff --git a/builtin-fetch.c b/builtin-fetch.c index 8c86974cbe..1e4a3d9c51 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -673,7 +673,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) ref_nr = j; } - sigchain_push(SIGINT, unlock_pack_on_signal); + sigchain_push_common(unlock_pack_on_signal); atexit(unlock_pack); exit_code = do_fetch(transport, parse_fetch_refspec(ref_nr, refs), ref_nr); diff --git a/diff.c b/diff.c index 9c9977d892..8ce898a6b0 100644 --- a/diff.c +++ b/diff.c @@ -1903,7 +1903,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, if (!remove_tempfile_installed) { atexit(remove_tempfile); - sigchain_push(SIGINT, remove_tempfile_on_signal); + sigchain_push_common(remove_tempfile_on_signal); remove_tempfile_installed = 1; } diff --git a/http-push.c b/http-push.c index dec395deed..7d5c23edc4 100644 --- a/http-push.c +++ b/http-push.c @@ -2262,10 +2262,7 @@ int main(int argc, char **argv) goto cleanup; } - sigchain_push(SIGINT, remove_locks_on_signal); - sigchain_push(SIGHUP, remove_locks_on_signal); - sigchain_push(SIGQUIT, remove_locks_on_signal); - sigchain_push(SIGTERM, remove_locks_on_signal); + sigchain_push_common(remove_locks_on_signal); /* Check whether the remote has server info files */ remote->can_update_info_refs = 0; diff --git a/lockfile.c b/lockfile.c index 3cd57dc385..021c3375c1 100644 --- a/lockfile.c +++ b/lockfile.c @@ -137,11 +137,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= lk->fd) { if (!lock_file_list) { - sigchain_push(SIGINT, remove_lock_file_on_signal); - sigchain_push(SIGHUP, remove_lock_file_on_signal); - sigchain_push(SIGTERM, remove_lock_file_on_signal); - sigchain_push(SIGQUIT, remove_lock_file_on_signal); - sigchain_push(SIGPIPE, remove_lock_file_on_signal); + sigchain_push_common(remove_lock_file_on_signal); atexit(remove_lock_file); } lk->owner = getpid(); diff --git a/sigchain.c b/sigchain.c index a18d505e56..1118b99e57 100644 --- a/sigchain.c +++ b/sigchain.c @@ -41,3 +41,12 @@ int sigchain_pop(int sig) s->n--; return 0; } + +void sigchain_push_common(sigchain_fun f) +{ + sigchain_push(SIGINT, f); + sigchain_push(SIGHUP, f); + sigchain_push(SIGTERM, f); + sigchain_push(SIGQUIT, f); + sigchain_push(SIGPIPE, f); +} diff --git a/sigchain.h b/sigchain.h index 254ebb0fa6..618083bce0 100644 --- a/sigchain.h +++ b/sigchain.h @@ -6,4 +6,6 @@ typedef void (*sigchain_fun)(int); int sigchain_push(int sig, sigchain_fun f); int sigchain_pop(int sig); +void sigchain_push_common(sigchain_fun f); + #endif /* SIGCHAIN_H */ -- cgit v1.3 From b67b9612e1a90ae093445abeaeff930e9f4cf936 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 26 Jan 2009 00:08:24 -0800 Subject: diff.c: output correct index lines for a split diff A patch that changes the filetype (e.g. regular file to symlink) of a path must be split into a deletion event followed by a creation event, which means that we need to have two independent metainfo lines for each. However, the code reused the single set of metainfo lines. As the blob object names recorded on the index lines are usually not used nor validated on the receiving end, this is not an issue with normal use of the resulting patch. However, when accepting a binary patch to delete a blob, git-apply verified that the postimage blob object name on the index line is 0{40}, hence a patch that deletes a regular file blob that records binary contents to create a blob with different filetype (e.g. a symbolic link) failed to apply. "git am -3" also uses the blob object names recorded on the index line, so it would also misbehave when synthesizing a preimage tree. This moves the code to generate metainfo lines around, so that two independent sets of metainfo lines are used for the split halves. Additional tests by Jeff King. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 146 ++++++++++++++++++++++++-------------------- t/t4114-apply-typechange.sh | 18 ++++++ 2 files changed, 98 insertions(+), 66 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index f91f256c56..6fea3c0347 100644 --- a/diff.c +++ b/diff.c @@ -2096,16 +2096,86 @@ static const char *external_diff_attr(const char *name) return NULL; } +static int similarity_index(struct diff_filepair *p) +{ + return p->score * 100 / MAX_SCORE; +} + +static void fill_metainfo(struct strbuf *msg, + const char *name, + const char *other, + struct diff_filespec *one, + struct diff_filespec *two, + struct diff_options *o, + struct diff_filepair *p) +{ + strbuf_init(msg, PATH_MAX * 2 + 300); + switch (p->status) { + case DIFF_STATUS_COPIED: + strbuf_addf(msg, "similarity index %d%%", similarity_index(p)); + strbuf_addstr(msg, "\ncopy from "); + quote_c_style(name, msg, NULL, 0); + strbuf_addstr(msg, "\ncopy to "); + quote_c_style(other, msg, NULL, 0); + strbuf_addch(msg, '\n'); + break; + case DIFF_STATUS_RENAMED: + strbuf_addf(msg, "similarity index %d%%", similarity_index(p)); + strbuf_addstr(msg, "\nrename from "); + quote_c_style(name, msg, NULL, 0); + strbuf_addstr(msg, "\nrename to "); + quote_c_style(other, msg, NULL, 0); + strbuf_addch(msg, '\n'); + break; + case DIFF_STATUS_MODIFIED: + if (p->score) { + strbuf_addf(msg, "dissimilarity index %d%%\n", + similarity_index(p)); + break; + } + /* fallthru */ + default: + /* nothing */ + ; + } + if (one && two && hashcmp(one->sha1, two->sha1)) { + int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV; + + if (DIFF_OPT_TST(o, BINARY)) { + mmfile_t mf; + if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) || + (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) + abbrev = 40; + } + strbuf_addf(msg, "index %.*s..%.*s", + abbrev, sha1_to_hex(one->sha1), + abbrev, sha1_to_hex(two->sha1)); + if (one->mode == two->mode) + strbuf_addf(msg, " %06o", one->mode); + strbuf_addch(msg, '\n'); + } + if (msg->len) + strbuf_setlen(msg, msg->len - 1); +} + static void run_diff_cmd(const char *pgm, const char *name, const char *other, const char *attr_path, struct diff_filespec *one, struct diff_filespec *two, - const char *xfrm_msg, + struct strbuf *msg, struct diff_options *o, - int complete_rewrite) + struct diff_filepair *p) { + const char *xfrm_msg = NULL; + int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score; + + if (msg) { + fill_metainfo(msg, name, other, one, two, o, p); + xfrm_msg = msg->len ? msg->buf : NULL; + } + if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL)) pgm = NULL; else { @@ -2145,11 +2215,6 @@ static void diff_fill_sha1_info(struct diff_filespec *one) hashclr(one->sha1); } -static int similarity_index(struct diff_filepair *p) -{ - return p->score * 100 / MAX_SCORE; -} - static void strip_prefix(int prefix_length, const char **namep, const char **otherp) { /* Strip the prefix but do not molest /dev/null and absolute paths */ @@ -2163,13 +2228,11 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) { const char *pgm = external_diff(); struct strbuf msg; - char *xfrm_msg; struct diff_filespec *one = p->one; struct diff_filespec *two = p->two; const char *name; const char *other; const char *attr_path; - int complete_rewrite = 0; name = p->one->path; other = (strcmp(name, p->two->path) ? p->two->path : NULL); @@ -2179,83 +2242,34 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o) if (DIFF_PAIR_UNMERGED(p)) { run_diff_cmd(pgm, name, NULL, attr_path, - NULL, NULL, NULL, o, 0); + NULL, NULL, NULL, o, p); return; } diff_fill_sha1_info(one); diff_fill_sha1_info(two); - strbuf_init(&msg, PATH_MAX * 2 + 300); - switch (p->status) { - case DIFF_STATUS_COPIED: - strbuf_addf(&msg, "similarity index %d%%", similarity_index(p)); - strbuf_addstr(&msg, "\ncopy from "); - quote_c_style(name, &msg, NULL, 0); - strbuf_addstr(&msg, "\ncopy to "); - quote_c_style(other, &msg, NULL, 0); - strbuf_addch(&msg, '\n'); - break; - case DIFF_STATUS_RENAMED: - strbuf_addf(&msg, "similarity index %d%%", similarity_index(p)); - strbuf_addstr(&msg, "\nrename from "); - quote_c_style(name, &msg, NULL, 0); - strbuf_addstr(&msg, "\nrename to "); - quote_c_style(other, &msg, NULL, 0); - strbuf_addch(&msg, '\n'); - break; - case DIFF_STATUS_MODIFIED: - if (p->score) { - strbuf_addf(&msg, "dissimilarity index %d%%\n", - similarity_index(p)); - complete_rewrite = 1; - break; - } - /* fallthru */ - default: - /* nothing */ - ; - } - - if (hashcmp(one->sha1, two->sha1)) { - int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV; - - if (DIFF_OPT_TST(o, BINARY)) { - mmfile_t mf; - if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) || - (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two))) - abbrev = 40; - } - strbuf_addf(&msg, "index %.*s..%.*s", - abbrev, sha1_to_hex(one->sha1), - abbrev, sha1_to_hex(two->sha1)); - if (one->mode == two->mode) - strbuf_addf(&msg, " %06o", one->mode); - strbuf_addch(&msg, '\n'); - } - - if (msg.len) - strbuf_setlen(&msg, msg.len - 1); - xfrm_msg = msg.len ? msg.buf : NULL; - if (!pgm && DIFF_FILE_VALID(one) && DIFF_FILE_VALID(two) && (S_IFMT & one->mode) != (S_IFMT & two->mode)) { - /* a filepair that changes between file and symlink + /* + * a filepair that changes between file and symlink * needs to be split into deletion and creation. */ struct diff_filespec *null = alloc_filespec(two->path); run_diff_cmd(NULL, name, other, attr_path, - one, null, xfrm_msg, o, 0); + one, null, &msg, o, p); free(null); + strbuf_release(&msg); + null = alloc_filespec(one->path); run_diff_cmd(NULL, name, other, attr_path, - null, two, xfrm_msg, o, 0); + null, two, &msg, o, p); free(null); } else run_diff_cmd(pgm, name, other, attr_path, - one, two, xfrm_msg, o, complete_rewrite); + one, two, &msg, o, p); strbuf_release(&msg); } diff --git a/t/t4114-apply-typechange.sh b/t/t4114-apply-typechange.sh index 55334927ab..0f185caa44 100755 --- a/t/t4114-apply-typechange.sh +++ b/t/t4114-apply-typechange.sh @@ -25,6 +25,10 @@ test_expect_success 'setup repository and commits' ' git update-index foo && git commit -m "foo back to file" && git branch foo-back-to-file && + printf "\0" > foo && + git update-index foo && + git commit -m "foo becomes binary" && + git branch foo-becomes-binary && rm -f foo && git update-index --remove foo && mkdir foo && @@ -85,6 +89,20 @@ test_expect_success 'symlink becomes file' ' ' test_debug 'cat patch' +test_expect_success 'binary file becomes symlink' ' + git checkout -f foo-becomes-binary && + git diff-tree -p --binary HEAD foo-symlinked-to-bar > patch && + git apply --index < patch + ' +test_debug 'cat patch' + +test_expect_success 'symlink becomes binary file' ' + git checkout -f foo-symlinked-to-bar && + git diff-tree -p --binary HEAD foo-becomes-binary > patch && + git apply --index < patch + ' +test_debug 'cat patch' + test_expect_success 'symlink becomes directory' ' git checkout -f foo-symlinked-to-bar && -- cgit v1.3 From a8344abe0f70f9fc629ee055d73ffa65fbc58311 Mon Sep 17 00:00:00 2001 From: Nazri Ramliy Date: Thu, 12 Feb 2009 21:36:14 +0800 Subject: Bugfix: GIT_EXTERNAL_DIFF with more than one changed files When there is more than one file that are changed, running git diff with GIT_EXTERNAL_DIFF incorrectly diagnoses an programming error and dies. The check introduced in 479b0ae (diff: refactor tempfile cleanup handling, 2009-01-22) to detect a temporary file slot that forgot to remove its temporary file was inconsistent with the way the codepath to remove the temporary to mark the slot that it is done with it. This patch fixes this problem and adds a test case for it. Signed-off-by: Nazri Ramliy Acked-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 8 ++++---- t/t4020-diff-external.sh | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index a5a540fd38..be3859e0a7 100644 --- a/diff.c +++ b/diff.c @@ -184,11 +184,11 @@ static int remove_tempfile_installed; static void remove_tempfile(void) { int i; - for (i = 0; i < ARRAY_SIZE(diff_temp); i++) - if (diff_temp[i].name == diff_temp[i].tmp_path) { + for (i = 0; i < ARRAY_SIZE(diff_temp); i++) { + if (diff_temp[i].name == diff_temp[i].tmp_path) unlink(diff_temp[i].name); - diff_temp[i].name = NULL; - } + diff_temp[i].name = NULL; + } } static void remove_tempfile_on_signal(int signo) diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index caea292f15..281680d95a 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -128,4 +128,12 @@ test_expect_success 'force diff with "diff"' ' test_cmp "$TEST_DIRECTORY"/t4020/diff.NUL actual ' +test_expect_success 'GIT_EXTERNAL_DIFF with more than one changed files' ' + echo anotherfile > file2 && + git add file2 && + git commit -m "added 2nd file" && + echo modified >file2 && + GIT_EXTERNAL_DIFF=echo git diff +' + test_done -- cgit v1.3 From dc6ebd4cc5028d59146e02e30f7945ee91974e6e Mon Sep 17 00:00:00 2001 From: Arjen Laarhoven Date: Fri, 13 Feb 2009 22:53:40 +0100 Subject: Clean up use of ANSI color sequences Remove the literal ANSI escape sequences and replace them by readable constants. Signed-off-by: Arjen Laarhoven Signed-off-by: Junio C Hamano --- builtin-branch.c | 10 +++++----- color.c | 8 +++----- color.h | 10 ++++++++++ diff.c | 16 ++++++++-------- pretty.c | 8 ++++---- wt-status.c | 10 +++++----- 6 files changed, 35 insertions(+), 27 deletions(-) (limited to 'diff.c') diff --git a/builtin-branch.c b/builtin-branch.c index 56a1971d69..fe139e1f05 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -32,11 +32,11 @@ static unsigned char head_sha1[20]; static int branch_use_color = -1; static char branch_colors[][COLOR_MAXLEN] = { - "\033[m", /* reset */ - "", /* PLAIN (normal) */ - "\033[31m", /* REMOTE (red) */ - "", /* LOCAL (normal) */ - "\033[32m", /* CURRENT (green) */ + GIT_COLOR_RESET, + GIT_COLOR_NORMAL, /* PLAIN */ + GIT_COLOR_RED, /* REMOTE */ + GIT_COLOR_NORMAL, /* LOCAL */ + GIT_COLOR_GREEN, /* CURRENT */ }; enum color_branch { COLOR_BRANCH_RESET = 0, diff --git a/color.c b/color.c index db4dccfb77..62977f4808 100644 --- a/color.c +++ b/color.c @@ -1,8 +1,6 @@ #include "cache.h" #include "color.h" -#define COLOR_RESET "\033[m" - int git_use_color_default = 0; static int parse_color(const char *name, int len) @@ -54,7 +52,7 @@ void color_parse_mem(const char *value, int value_len, const char *var, int bg = -2; if (!strncasecmp(value, "reset", len)) { - strcpy(dst, "\033[m"); + strcpy(dst, GIT_COLOR_RESET); return; } @@ -175,7 +173,7 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt, r += fprintf(fp, "%s", color); r += vfprintf(fp, fmt, args); if (*color) - r += fprintf(fp, "%s", COLOR_RESET); + r += fprintf(fp, "%s", GIT_COLOR_RESET); if (trail) r += fprintf(fp, "%s", trail); return r; @@ -217,7 +215,7 @@ int color_fwrite_lines(FILE *fp, const char *color, char *p = memchr(buf, '\n', count); if (p != buf && (fputs(color, fp) < 0 || fwrite(buf, p ? p - buf : count, 1, fp) != 1 || - fputs(COLOR_RESET, fp) < 0)) + fputs(GIT_COLOR_RESET, fp) < 0)) return -1; if (!p) return 0; diff --git a/color.h b/color.h index 5019df82f7..6846be1706 100644 --- a/color.h +++ b/color.h @@ -4,6 +4,16 @@ /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ #define COLOR_MAXLEN 24 +#define GIT_COLOR_NORMAL "" +#define GIT_COLOR_RESET "\033[m" +#define GIT_COLOR_BOLD "\033[1m" +#define GIT_COLOR_RED "\033[31m" +#define GIT_COLOR_GREEN "\033[32m" +#define GIT_COLOR_YELLOW "\033[33m" +#define GIT_COLOR_BLUE "\033[34m" +#define GIT_COLOR_CYAN "\033[36m" +#define GIT_COLOR_BG_RED "\033[41m" + /* * This variable stores the value of color.ui */ diff --git a/diff.c b/diff.c index be3859e0a7..a3db16ea66 100644 --- a/diff.c +++ b/diff.c @@ -30,14 +30,14 @@ int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static char diff_colors[][COLOR_MAXLEN] = { - "\033[m", /* reset */ - "", /* PLAIN (normal) */ - "\033[1m", /* METAINFO (bold) */ - "\033[36m", /* FRAGINFO (cyan) */ - "\033[31m", /* OLD (red) */ - "\033[32m", /* NEW (green) */ - "\033[33m", /* COMMIT (yellow) */ - "\033[41m", /* WHITESPACE (red background) */ + GIT_COLOR_RESET, + GIT_COLOR_NORMAL, /* PLAIN */ + GIT_COLOR_BOLD, /* METAINFO */ + GIT_COLOR_CYAN, /* FRAGINFO */ + GIT_COLOR_RED, /* OLD */ + GIT_COLOR_GREEN, /* NEW */ + GIT_COLOR_YELLOW, /* COMMIT */ + GIT_COLOR_BG_RED, /* WHITESPACE */ }; static void diff_filespec_load_driver(struct diff_filespec *one); diff --git a/pretty.c b/pretty.c index cc460b5697..66bae42f99 100644 --- a/pretty.c +++ b/pretty.c @@ -567,16 +567,16 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, return end - placeholder + 1; } if (!prefixcmp(placeholder + 1, "red")) { - strbuf_addstr(sb, "\033[31m"); + strbuf_addstr(sb, GIT_COLOR_RED); return 4; } else if (!prefixcmp(placeholder + 1, "green")) { - strbuf_addstr(sb, "\033[32m"); + strbuf_addstr(sb, GIT_COLOR_GREEN); return 6; } else if (!prefixcmp(placeholder + 1, "blue")) { - strbuf_addstr(sb, "\033[34m"); + strbuf_addstr(sb, GIT_COLOR_BLUE); return 5; } else if (!prefixcmp(placeholder + 1, "reset")) { - strbuf_addstr(sb, "\033[m"); + strbuf_addstr(sb, GIT_COLOR_RESET); return 6; } else return 0; diff --git a/wt-status.c b/wt-status.c index 96ff2f8f56..dd87339ff7 100644 --- a/wt-status.c +++ b/wt-status.c @@ -15,11 +15,11 @@ int wt_status_relative_paths = 1; int wt_status_use_color = -1; int wt_status_submodule_summary; static char wt_status_colors[][COLOR_MAXLEN] = { - "", /* WT_STATUS_HEADER: normal */ - "\033[32m", /* WT_STATUS_UPDATED: green */ - "\033[31m", /* WT_STATUS_CHANGED: red */ - "\033[31m", /* WT_STATUS_UNTRACKED: red */ - "\033[31m", /* WT_STATUS_NOBRANCH: red */ + GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */ + GIT_COLOR_GREEN, /* WT_STATUS_UPDATED */ + GIT_COLOR_RED, /* WT_STATUS_CHANGED */ + GIT_COLOR_RED, /* WT_STATUS_UNTRACKED */ + GIT_COLOR_RED, /* WT_STATUS_NOBRANCH */ }; enum untracked_status_type show_untracked_files = SHOW_NORMAL_UNTRACKED_FILES; -- cgit v1.3 From 4b15b4ab5f9b19caff6d4a910ecc3e1d4f0e13f0 Mon Sep 17 00:00:00 2001 From: Keith Cascio Date: Fri, 13 Feb 2009 09:33:34 -0800 Subject: Remove redundant bit clears from diff_setup() All bits already clear after memset(0). Signed-off-by: Junio C Hamano --- diff.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index be3859e0a7..006aa017e2 100644 --- a/diff.c +++ b/diff.c @@ -2326,15 +2326,12 @@ void diff_setup(struct diff_options *options) options->break_opt = -1; options->rename_limit = -1; options->dirstat_percent = 3; - DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE); options->context = 3; options->change = diff_change; options->add_remove = diff_addremove; if (diff_use_color_default > 0) DIFF_OPT_SET(options, COLOR_DIFF); - else - DIFF_OPT_CLR(options, COLOR_DIFF); options->detect_rename = diff_detect_rename_default; if (!diff_mnemonic_prefix) { -- cgit v1.3 From cd673c1f17228d272c4b7f81fbb28bc31cf0cac6 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 27 Feb 2009 23:15:53 -0800 Subject: has_sha1_pack(): refactor "pretend these packs do not exist" interface Most of the callers of this function except only one pass NULL to its last parameter, ignore_packed. Introduce has_sha1_kept_pack() function that has the function signature and the semantics of this function, and convert the sole caller that does not pass NULL to call this new function. All other callers and has_sha1_pack() lose the ignore_packed parameter. Signed-off-by: Junio C Hamano --- builtin-count-objects.c | 2 +- builtin-fsck.c | 2 +- builtin-prune-packed.c | 2 +- cache.h | 3 ++- diff.c | 2 +- revision.c | 3 ++- sha1_file.c | 32 +++++++++++++++++++++++++------- 7 files changed, 33 insertions(+), 13 deletions(-) (limited to 'diff.c') diff --git a/builtin-count-objects.c b/builtin-count-objects.c index 91b5487478..c095e8dd2b 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -61,7 +61,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, hex[40] = 0; if (get_sha1_hex(hex, sha1)) die("internal error"); - if (has_sha1_pack(sha1, NULL)) + if (has_sha1_pack(sha1)) (*packed_loose)++; } } diff --git a/builtin-fsck.c b/builtin-fsck.c index 30971ce0ad..491375dc59 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -158,7 +158,7 @@ static void check_reachable_object(struct object *obj) * do a full fsck */ if (!obj->parsed) { - if (has_sha1_pack(obj->sha1, NULL)) + if (has_sha1_pack(obj->sha1)) return; /* it is in pack - forget about it */ printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1)); errors_found |= ERROR_REACHABLE; diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 10cb8df845..2d5b2cd353 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -23,7 +23,7 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(hex+2, de->d_name, 38); if (get_sha1_hex(hex, sha1)) continue; - if (!has_sha1_pack(sha1, NULL)) + if (!has_sha1_pack(sha1)) continue; memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) diff --git a/cache.h b/cache.h index 42f2f2754b..c1539bf89a 100644 --- a/cache.h +++ b/cache.h @@ -565,7 +565,8 @@ extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned l extern int move_temp_to_file(const char *tmpfile, const char *filename); -extern int has_sha1_pack(const unsigned char *sha1, const char **ignore); +extern int has_sha1_pack(const unsigned char *sha1); +extern int has_sha1_kept_pack(const unsigned char *sha1, const char **ignore); extern int has_sha1_file(const unsigned char *sha1); extern int has_loose_object_nonlocal(const unsigned char *sha1); diff --git a/diff.c b/diff.c index f91f256c56..a34d26c23f 100644 --- a/diff.c +++ b/diff.c @@ -1743,7 +1743,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int * objects however would tend to be slower as they need * to be individually opened and inflated. */ - if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1, NULL)) + if (!FAST_WORKING_DIRECTORY && !want_file && has_sha1_pack(sha1)) return 0; len = strlen(name); diff --git a/revision.c b/revision.c index 45fd7a3660..746eeed972 100644 --- a/revision.c +++ b/revision.c @@ -1485,7 +1485,8 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) { if (commit->object.flags & SHOWN) return commit_ignore; - if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed)) + if (revs->unpacked && + has_sha1_kept_pack(commit->object.sha1, revs->ignore_packed)) return commit_ignore; if (revs->show_all) return commit_show; diff --git a/sha1_file.c b/sha1_file.c index 88035a0cd1..ac4375d298 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -1874,7 +1874,8 @@ int matches_pack_name(struct packed_git *p, const char *name) return 0; } -static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed) +static int find_pack_ent(const unsigned char *sha1, struct pack_entry *e, + const char **ignore_packed) { static struct packed_git *last_found = (void *)1; struct packed_git *p; @@ -1934,6 +1935,17 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, cons return 0; } +static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) +{ + return find_pack_ent(sha1, e, NULL); +} + +static int find_kept_pack_entry(const unsigned char *sha1, struct pack_entry *e, + const char **ignore_packed) +{ + return find_pack_ent(sha1, e, ignore_packed); +} + struct packed_git *find_sha1_pack(const unsigned char *sha1, struct packed_git *packs) { @@ -1975,7 +1987,7 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep) struct pack_entry e; int status; - if (!find_pack_entry(sha1, &e, NULL)) { + if (!find_pack_entry(sha1, &e)) { /* Most likely it's a loose object. */ status = sha1_loose_object_info(sha1, sizep); if (status >= 0) @@ -1983,7 +1995,7 @@ int sha1_object_info(const unsigned char *sha1, unsigned long *sizep) /* Not a loose object; someone else may have just packed it. */ reprepare_packed_git(); - if (!find_pack_entry(sha1, &e, NULL)) + if (!find_pack_entry(sha1, &e)) return status; } return packed_object_info(e.p, e.offset, sizep); @@ -1995,7 +2007,7 @@ static void *read_packed_sha1(const unsigned char *sha1, struct pack_entry e; void *data; - if (!find_pack_entry(sha1, &e, NULL)) + if (!find_pack_entry(sha1, &e)) return NULL; data = cache_or_unpack_entry(e.p, e.offset, size, type, 1); if (!data) { @@ -2395,17 +2407,23 @@ int has_pack_file(const unsigned char *sha1) return 1; } -int has_sha1_pack(const unsigned char *sha1, const char **ignore_packed) +int has_sha1_pack(const unsigned char *sha1) +{ + struct pack_entry e; + return find_pack_entry(sha1, &e); +} + +int has_sha1_kept_pack(const unsigned char *sha1, const char **ignore_packed) { struct pack_entry e; - return find_pack_entry(sha1, &e, ignore_packed); + return find_kept_pack_entry(sha1, &e, ignore_packed); } int has_sha1_file(const unsigned char *sha1) { struct pack_entry e; - if (find_pack_entry(sha1, &e, NULL)) + if (find_pack_entry(sha1, &e)) return 1; return has_loose_object(sha1); } -- cgit v1.3 From 628d5c2b707db207e47c42ca112b182aa171cfaa Mon Sep 17 00:00:00 2001 From: Keith Cascio Date: Mon, 16 Feb 2009 19:26:49 -0800 Subject: Use DIFF_XDL_SET/DIFF_OPT_SET instead of raw bit-masking Signed-off-by: Keith Cascio Signed-off-by: Junio C Hamano --- diff.c | 17 ++++++++++------- diff.h | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 006aa017e2..ff3624e9f6 100644 --- a/diff.c +++ b/diff.c @@ -2567,13 +2567,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) /* xdiff options */ else if (!strcmp(arg, "-w") || !strcmp(arg, "--ignore-all-space")) - options->xdl_opts |= XDF_IGNORE_WHITESPACE; + DIFF_XDL_SET(options, IGNORE_WHITESPACE); else if (!strcmp(arg, "-b") || !strcmp(arg, "--ignore-space-change")) - options->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE; + DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE); else if (!strcmp(arg, "--ignore-space-at-eol")) - options->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL; + DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); else if (!strcmp(arg, "--patience")) - options->xdl_opts |= XDF_PATIENCE_DIFF; + DIFF_XDL_SET(options, PATIENCE_DIFF); /* flags options */ else if (!strcmp(arg, "--binary")) { @@ -2594,10 +2594,13 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_SET(options, COLOR_DIFF); else if (!strcmp(arg, "--no-color")) DIFF_OPT_CLR(options, COLOR_DIFF); - else if (!strcmp(arg, "--color-words")) - options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS; + else if (!strcmp(arg, "--color-words")) { + DIFF_OPT_SET(options, COLOR_DIFF); + DIFF_OPT_SET(options, COLOR_DIFF_WORDS); + } else if (!prefixcmp(arg, "--color-words=")) { - options->flags |= DIFF_OPT_COLOR_DIFF | DIFF_OPT_COLOR_DIFF_WORDS; + DIFF_OPT_SET(options, COLOR_DIFF); + DIFF_OPT_SET(options, COLOR_DIFF_WORDS); options->word_regex = arg + 14; } else if (!strcmp(arg, "--exit-code")) diff --git a/diff.h b/diff.h index 6703a4fb4f..6616877ee5 100644 --- a/diff.h +++ b/diff.h @@ -69,6 +69,9 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) +#define DIFF_XDL_TST(opts, flag) ((opts)->xdl_opts & XDF_##flag) +#define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag) +#define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag) struct diff_options { const char *filter; -- cgit v1.3 From eb3a9dd3279fe4b05f286665986ebf6d43a6ccc0 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Sat, 7 Mar 2009 21:02:10 +0100 Subject: Remove unused function scope local variables These variables were unused and can be removed safely: builtin-clone.c::cmd_clone(): use_local_hardlinks, use_separate_remote builtin-fetch-pack.c::find_common(): len builtin-remote.c::mv(): symref diff.c::show_stats():show_stats(): total diffcore-break.c::should_break(): base_size fast-import.c::validate_raw_date(): date, sign fsck.c::fsck_tree(): o_sha1, sha1 xdiff-interface.c::parse_num(): read_some Signed-off-by: Benjamin Kramer Signed-off-by: Junio C Hamano --- builtin-clone.c | 6 ------ builtin-fetch-pack.c | 3 +-- builtin-remote.c | 3 +-- diff.c | 4 +--- diffcore-break.c | 3 +-- fast-import.c | 8 +++----- fsck.c | 6 +----- xdiff-interface.c | 3 +-- 8 files changed, 9 insertions(+), 27 deletions(-) (limited to 'diff.c') diff --git a/builtin-clone.c b/builtin-clone.c index c338910b1c..92826cd14c 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -365,8 +365,6 @@ static void install_branch_config(const char *local, int cmd_clone(int argc, const char **argv, const char *prefix) { - int use_local_hardlinks = 1; - int use_separate_remote = 1; int is_bundle = 0; struct stat buf; const char *repo_name, *repo, *work_tree, *git_dir; @@ -388,9 +386,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (argc == 0) die("You must specify a repository to clone."); - if (option_no_hardlinks) - use_local_hardlinks = 0; - if (option_mirror) option_bare = 1; @@ -399,7 +394,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix) die("--bare and --origin %s options are incompatible.", option_origin); option_no_checkout = 1; - use_separate_remote = 0; } if (!option_origin) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 67fb80ec48..c2e5adc884 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -216,9 +216,8 @@ static int find_common(int fd[2], unsigned char *result_sha1, if (args.depth > 0) { char line[1024]; unsigned char sha1[20]; - int len; - while ((len = packet_read_line(fd[0], line, sizeof(line)))) { + while (packet_read_line(fd[0], line, sizeof(line))) { if (!prefixcmp(line, "shallow ")) { if (get_sha1_hex(line + 8, sha1)) die("invalid shallow line: %s", line); diff --git a/builtin-remote.c b/builtin-remote.c index ac69d37c8a..e171096ece 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -484,9 +484,8 @@ static int mv(int argc, const char **argv) struct string_list_item *item = remote_branches.items + i; int flag = 0; unsigned char sha1[20]; - const char *symref; - symref = resolve_ref(item->string, sha1, 1, &flag); + resolve_ref(item->string, sha1, 1, &flag); if (!(flag & REF_ISSYMREF)) continue; if (delete_ref(item->string, NULL, REF_NODEREF)) diff --git a/diff.c b/diff.c index 3feca1b173..e06c93707f 100644 --- a/diff.c +++ b/diff.c @@ -875,7 +875,7 @@ static void fill_print_name(struct diffstat_file *file) static void show_stats(struct diffstat_t* data, struct diff_options *options) { - int i, len, add, del, total, adds = 0, dels = 0; + int i, len, add, del, adds = 0, dels = 0; int max_change = 0, max_len = 0; int total_files = data->nr; int width, name_width; @@ -978,14 +978,12 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) */ add = added; del = deleted; - total = add + del; adds += add; dels += del; if (width <= max_change) { add = scale_linear(add, width, max_change); del = scale_linear(del, width, max_change); - total = add + del; } show_name(options->file, prefix, name, len, reset, set); fprintf(options->file, "%5d%s", added + deleted, diff --git a/diffcore-break.c b/diffcore-break.c index 31cdcfe8bc..d7097bb576 100644 --- a/diffcore-break.c +++ b/diffcore-break.c @@ -45,7 +45,7 @@ static int should_break(struct diff_filespec *src, * The value we return is 1 if we want the pair to be broken, * or 0 if we do not. */ - unsigned long delta_size, base_size, max_size; + unsigned long delta_size, max_size; unsigned long src_copied, literal_added, src_removed; *merge_score_p = 0; /* assume no deletion --- "do not break" @@ -64,7 +64,6 @@ static int should_break(struct diff_filespec *src, if (diff_populate_filespec(src, 0) || diff_populate_filespec(dst, 0)) return 0; /* error but caught downstream */ - base_size = ((src->size < dst->size) ? src->size : dst->size); max_size = ((src->size > dst->size) ? src->size : dst->size); if (max_size < MINIMUM_BREAK_SIZE) return 0; /* we do not break too small filepair */ diff --git a/fast-import.c b/fast-import.c index 3748ddf48d..beeac0d004 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1745,21 +1745,19 @@ static void parse_data(struct strbuf *sb) static int validate_raw_date(const char *src, char *result, int maxlen) { const char *orig_src = src; - char *endp, sign; - unsigned long date; + char *endp; errno = 0; - date = strtoul(src, &endp, 10); + strtoul(src, &endp, 10); if (errno || endp == src || *endp != ' ') return -1; src = endp + 1; if (*src != '-' && *src != '+') return -1; - sign = *src; - date = strtoul(src + 1, &endp, 10); + strtoul(src + 1, &endp, 10); if (errno || endp == src || *endp || (endp - orig_src) >= maxlen) return -1; diff --git a/fsck.c b/fsck.c index 97f76c5815..511b82cba9 100644 --- a/fsck.c +++ b/fsck.c @@ -148,20 +148,17 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func) struct tree_desc desc; unsigned o_mode; const char *o_name; - const unsigned char *o_sha1; init_tree_desc(&desc, item->buffer, item->size); o_mode = 0; o_name = NULL; - o_sha1 = NULL; while (desc.size) { unsigned mode; const char *name; - const unsigned char *sha1; - sha1 = tree_entry_extract(&desc, &name, &mode); + tree_entry_extract(&desc, &name, &mode); if (strchr(name, '/')) has_full_path = 1; @@ -207,7 +204,6 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func) o_mode = mode; o_name = name; - o_sha1 = sha1; } retval = 0; diff --git a/xdiff-interface.c b/xdiff-interface.c index d782f06d99..b9b0db8d86 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -15,11 +15,10 @@ static int parse_num(char **cp_p, int *num_p) { char *cp = *cp_p; int num = 0; - int read_some; while ('0' <= *cp && *cp <= '9') num = num * 10 + *cp++ - '0'; - if (!(read_some = cp - *cp_p)) + if (!(cp - *cp_p)) return -1; *cp_p = cp; *num_p = num; -- cgit v1.3 From 4e218f54b3de6aa8ef7d15020c4507031a519f7d Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 21 Mar 2009 12:42:52 +0100 Subject: Smudge the files fed to external diff and textconv When preparing temporary files for an external diff or textconv, it is easier on the external tools, especially when they are implemented using platform tools, if they are fed the input after convert_to_working_tree(). This fixes msysGit issue 177. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 13 ++++++++++--- t/t4020-diff-external.sh | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 006aa017e2..11798af0c1 100644 --- a/diff.c +++ b/diff.c @@ -1948,17 +1948,23 @@ void diff_free_filespec_data(struct diff_filespec *s) s->cnt_data = NULL; } -static void prep_temp_blob(struct diff_tempfile *temp, +static void prep_temp_blob(const char *path, struct diff_tempfile *temp, void *blob, unsigned long size, const unsigned char *sha1, int mode) { int fd; + struct strbuf buf = STRBUF_INIT; fd = git_mkstemp(temp->tmp_path, PATH_MAX, ".diff_XXXXXX"); if (fd < 0) die("unable to create temp-file: %s", strerror(errno)); + if (convert_to_working_tree(path, + (const char *)blob, (size_t)size, &buf)) { + blob = buf.buf; + size = buf.len; + } if (write_in_full(fd, blob, size) != size) die("unable to write temp-file"); close(fd); @@ -1966,6 +1972,7 @@ static void prep_temp_blob(struct diff_tempfile *temp, strcpy(temp->hex, sha1_to_hex(sha1)); temp->hex[40] = 0; sprintf(temp->mode, "%06o", mode); + strbuf_release(&buf); } static struct diff_tempfile *prepare_temp_file(const char *name, @@ -2006,7 +2013,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, die("readlink(%s)", name); if (ret == sizeof(buf)) die("symlink too long: %s", name); - prep_temp_blob(temp, buf, ret, + prep_temp_blob(name, temp, buf, ret, (one->sha1_valid ? one->sha1 : null_sha1), (one->sha1_valid ? @@ -2032,7 +2039,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, else { if (diff_populate_filespec(one, 0)) die("cannot read data blob for %s", one->path); - prep_temp_blob(temp, one->data, one->size, + prep_temp_blob(name, temp, one->data, one->size, one->sha1, one->mode); } return temp; diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 281680d95a..f8c99f1a98 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -136,4 +136,20 @@ test_expect_success 'GIT_EXTERNAL_DIFF with more than one changed files' ' GIT_EXTERNAL_DIFF=echo git diff ' +echo "#!$SHELL_PATH" >fake-diff.sh +cat >> fake-diff.sh <<\EOF +cat $2 >> crlfed.txt +EOF +chmod a+x fake-diff.sh + +keep_only_cr () { + tr -dc '\015' +} + +test_expect_success 'external diff with autocrlf = true' ' + git config core.autocrlf true && + GIT_EXTERNAL_DIFF=./fake-diff.sh git diff && + test $(wc -l < crlfed.txt) = $(cat crlfed.txt | keep_only_cr | wc -c) +' + test_done -- cgit v1.3 From 150115aded2e1e0a83db7366f59e4b5bf1aa8135 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 22 Mar 2009 15:26:07 -0700 Subject: diff --cached: do not borrow from a work tree when a path is marked as assume-unchanged When the index says that the file in the work tree that corresponds to the blob object that is used for comparison is known to be unchanged, "diff" reads from the file and applies convert_to_git(), instead of inflating the object, to feed the internal diff engine with, because an earlier benchnark found that it tends to be faster to use this optimization. However, the index can lie when the path is marked as assume-unchanged. Disable the optimization for such paths. Signed-off-by: Junio C Hamano --- diff.c | 10 +++++++++- t/t4020-diff-external.sh | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index bf5d5f15a3..c2d277a52d 100644 --- a/diff.c +++ b/diff.c @@ -1687,7 +1687,8 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int struct stat st; int pos, len; - /* We do not read the cache ourselves here, because the + /* + * We do not read the cache ourselves here, because the * benchmark with my previous version that always reads cache * shows that it makes things worse for diff-tree comparing * two linux-2.6 kernel trees in an already checked out work @@ -1727,6 +1728,13 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int if (hashcmp(sha1, ce->sha1) || !S_ISREG(ce->ce_mode)) return 0; + /* + * If ce is marked as "assume unchanged", there is no + * guarantee that work tree matches what we are looking for. + */ + if (ce->ce_flags & CE_VALID) + return 0; + /* * If ce matches the file in the work tree, we can reuse it. */ diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 637b4e19d5..f853b8a894 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -107,4 +107,12 @@ test_expect_success 'force diff with "diff"' ' test_cmp ../t4020/diff.NUL actual ' +test_expect_success 'diff --cached' ' + git add file && + git update-index --assume-unchanged file && + echo second >file && + git diff --cached >actual && + test_cmp ../t4020/diff.NUL actual +' + test_done -- cgit v1.3 From cced5fbc241f1274ba532040b985f38c15bbf555 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 9 Apr 2009 11:46:15 -0700 Subject: Allow users to un-configure rename detection I told people on the kernel mailing list to please use "-M" when sending me rename patches, so that I can see what they do while reading email rather than having to apply the patch and then look at the end result. I also told them that if they want to make it the default, they can just add [diff] renames to their ~/.gitconfig file. And while I was thinking about that, I wanted to also check whether you can then mark individual projects to _not_ have that default in the per-repository .git/config file. And you can't. Currently you cannot have a global "enable renames by default" and then a local ".. but not for _this_ project". Why? Because if somebody writes [diff] renames = no we simply ignore it, rather than resetting "diff_detect_rename_default" back to zero. Fixed thusly. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- diff.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index e0fa78c84d..3ac71686eb 100644 --- a/diff.c +++ b/diff.c @@ -62,6 +62,15 @@ static int parse_diff_color_slot(const char *var, int ofs) die("bad config variable '%s'", var); } +static int git_config_rename(const char *var, const char *value) +{ + if (!value) + return DIFF_DETECT_RENAME; + if (!strcasecmp(value, "copies") || !strcasecmp(value, "copy")) + return DIFF_DETECT_COPY; + return git_config_bool(var,value) ? DIFF_DETECT_RENAME : 0; +} + /* * These are to give UI layer defaults. * The core-level commands such as git-diff-files should @@ -75,13 +84,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return 0; } if (!strcmp(var, "diff.renames")) { - if (!value) - diff_detect_rename_default = DIFF_DETECT_RENAME; - else if (!strcasecmp(value, "copies") || - !strcasecmp(value, "copy")) - diff_detect_rename_default = DIFF_DETECT_COPY; - else if (git_config_bool(var,value)) - diff_detect_rename_default = DIFF_DETECT_RENAME; + diff_detect_rename_default = git_config_rename(var, value); return 0; } if (!strcmp(var, "diff.autorefreshindex")) { -- cgit v1.3 From a408e0e649b79ede7422bf837a31d281e4188cef Mon Sep 17 00:00:00 2001 From: Markus Heidelberg Date: Sat, 25 Apr 2009 00:06:47 +0200 Subject: diff: do not color --stat output like patch context The diffstat used the color.diff.plain slot (context text) for coloring filenames and the whole summary line. This didn't look nice and the affected text isn't patch context at all. Signed-off-by: Markus Heidelberg Signed-off-by: Junio C Hamano --- diff.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 3ac71686eb..d581d4d9ff 100644 --- a/diff.c +++ b/diff.c @@ -839,10 +839,9 @@ static int scale_linear(int it, int width, int max_change) } static void show_name(FILE *file, - const char *prefix, const char *name, int len, - const char *reset, const char *set) + const char *prefix, const char *name, int len) { - fprintf(file, " %s%s%-*s%s |", set, prefix, len, name, reset); + fprintf(file, " %s%-*s |", prefix, len, name); } static void show_graph(FILE *file, char ch, int cnt, const char *set, const char *reset) @@ -956,7 +955,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) } if (data->files[i]->is_binary) { - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, " Bin "); fprintf(options->file, "%s%d%s", del_c, deleted, reset); fprintf(options->file, " -> "); @@ -966,7 +965,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) continue; } else if (data->files[i]->is_unmerged) { - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, " Unmerged\n"); continue; } @@ -988,7 +987,7 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) add = scale_linear(add, width, max_change); del = scale_linear(del, width, max_change); } - show_name(options->file, prefix, name, len, reset, set); + show_name(options->file, prefix, name, len); fprintf(options->file, "%5d%s", added + deleted, added + deleted ? " " : ""); show_graph(options->file, '+', add, add_c, reset); @@ -996,8 +995,8 @@ static void show_stats(struct diffstat_t* data, struct diff_options *options) fprintf(options->file, "\n"); } fprintf(options->file, - "%s %d files changed, %d insertions(+), %d deletions(-)%s\n", - set, total_files, adds, dels, reset); + " %d files changed, %d insertions(+), %d deletions(-)\n", + total_files, adds, dels); } static void show_shortstats(struct diffstat_t* data, struct diff_options *options) -- cgit v1.3 From 691f1a28bf57618d8b44a193b1d28013c858aba6 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 29 Apr 2009 23:22:56 +0200 Subject: replace direct calls to unlink(2) with unlink_or_warn This helps to notice when something's going wrong, especially on systems which lock open files. I used the following criteria when selecting the code for replacement: - it was already printing a warning for the unlink failures - it is in a function which already printing something or is called from such a function - it is in a static function, returning void and the function is only called from a builtin main function (cmd_) - it is in a function which handles emergency exit (signal handlers) - it is in a function which is obvously cleaning up the lockfiles Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- builtin-apply.c | 4 ++-- builtin-fetch-pack.c | 2 +- builtin-prune-packed.c | 4 ++-- builtin-prune.c | 4 ++-- builtin-receive-pack.c | 2 +- builtin-remote.c | 4 ++-- builtin-rerere.c | 2 +- builtin-tag.c | 2 +- builtin-verify-tag.c | 2 +- diff.c | 2 +- entry.c | 2 +- fast-import.c | 4 ++-- http-push.c | 12 ++++++------ http-walker.c | 14 +++++++------- ll-merge.c | 2 +- lockfile.c | 4 ++-- pack-refs.c | 2 +- refs.c | 15 +++++---------- rerere.c | 2 +- server-info.c | 2 +- sha1_file.c | 2 +- transport.c | 2 +- unpack-trees.c | 2 +- 23 files changed, 44 insertions(+), 49 deletions(-) (limited to 'diff.c') diff --git a/builtin-apply.c b/builtin-apply.c index 7b404ef660..8a3771e87e 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2781,7 +2781,7 @@ static void remove_file(struct patch *patch, int rmdir_empty) if (rmdir(patch->old_name)) warning("unable to remove submodule %s", patch->old_name); - } else if (!unlink(patch->old_name) && rmdir_empty) { + } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) { remove_path(patch->old_name); } } @@ -2891,7 +2891,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned if (!try_create_file(newpath, mode, buf, size)) { if (!rename(newpath, path)) return; - unlink(newpath); + unlink_or_warn(newpath); break; } if (errno != EEXIST) diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 5d134be47c..bd97cfd9bf 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -814,7 +814,7 @@ struct ref *fetch_pack(struct fetch_pack_args *my_args, fd = hold_lock_file_for_update(&lock, shallow, LOCK_DIE_ON_ERROR); if (!write_shallow_commits(fd, 0)) { - unlink(shallow); + unlink_or_warn(shallow); rollback_lock_file(&lock); } else { commit_lock_file(&lock); diff --git a/builtin-prune-packed.c b/builtin-prune-packed.c index 4942892e9f..00590b1c3c 100644 --- a/builtin-prune-packed.c +++ b/builtin-prune-packed.c @@ -28,8 +28,8 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) memcpy(pathname + len, de->d_name, 38); if (opts & DRY_RUN) printf("rm -f %s\n", pathname); - else if (unlink(pathname) < 0) - error("unable to unlink %s", pathname); + else + unlink_or_warn(pathname); display_progress(progress, i + 1); } pathname[len] = 0; diff --git a/builtin-prune.c b/builtin-prune.c index 545e9c1f94..145ba83651 100644 --- a/builtin-prune.c +++ b/builtin-prune.c @@ -27,7 +27,7 @@ static int prune_tmp_object(const char *path, const char *filename) } printf("Removing stale temporary file %s\n", fullpath); if (!show_only) - unlink(fullpath); + unlink_or_warn(fullpath); return 0; } @@ -47,7 +47,7 @@ static int prune_object(char *path, const char *filename, const unsigned char *s (type > 0) ? typename(type) : "unknown"); } if (!show_only) - unlink(fullpath); + unlink_or_warn(fullpath); return 0; } diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c index a970b39505..035b723e50 100644 --- a/builtin-receive-pack.c +++ b/builtin-receive-pack.c @@ -702,7 +702,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) unpack_status = unpack(); execute_commands(unpack_status); if (pack_lockfile) - unlink(pack_lockfile); + unlink_or_warn(pack_lockfile); if (report_status) report(unpack_status); run_receive_hook(post_receive_hook); diff --git a/builtin-remote.c b/builtin-remote.c index 2ed752cbf1..71abf68404 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -525,8 +525,8 @@ static int migrate_file(struct remote *remote) path = git_path("remotes/%s", remote->name); else if (remote->origin == REMOTE_BRANCHES) path = git_path("branches/%s", remote->name); - if (path && unlink(path)) - warning("failed to remove '%s'", path); + if (path) + unlink_or_warn(path); return 0; } diff --git a/builtin-rerere.c b/builtin-rerere.c index 020af7377b..adfb7b5f48 100644 --- a/builtin-rerere.c +++ b/builtin-rerere.c @@ -116,7 +116,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix) if (!has_rerere_resolution(name)) unlink_rr_item(name); } - unlink(git_path("rr-cache/MERGE_RR")); + unlink_or_warn(git_path("rr-cache/MERGE_RR")); } else if (!strcmp(argv[1], "gc")) garbage_collect(&merge_rr); else if (!strcmp(argv[1], "status")) diff --git a/builtin-tag.c b/builtin-tag.c index 01e73747d0..e544430094 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -338,7 +338,7 @@ static void create_tag(const unsigned char *object, const char *tag, exit(128); } if (path) { - unlink(path); + unlink_or_warn(path); free(path); } } diff --git a/builtin-verify-tag.c b/builtin-verify-tag.c index 729a1593e6..7f7fda42f9 100644 --- a/builtin-verify-tag.c +++ b/builtin-verify-tag.c @@ -55,7 +55,7 @@ static int run_gpg_verify(const char *buf, unsigned long size, int verbose) close(gpg.in); ret = finish_command(&gpg); - unlink(path); + unlink_or_warn(path); return ret; } diff --git a/diff.c b/diff.c index 3ac71686eb..6802f5ac12 100644 --- a/diff.c +++ b/diff.c @@ -189,7 +189,7 @@ static void remove_tempfile(void) int i; for (i = 0; i < ARRAY_SIZE(diff_temp); i++) { if (diff_temp[i].name == diff_temp[i].tmp_path) - unlink(diff_temp[i].name); + unlink_or_warn(diff_temp[i].name); diff_temp[i].name = NULL; } } diff --git a/entry.c b/entry.c index 915514aa5c..cc841edf90 100644 --- a/entry.c +++ b/entry.c @@ -35,7 +35,7 @@ static void create_directories(const char *path, int path_len, */ if (mkdir(buf, 0777)) { if (errno == EEXIST && state->force && - !unlink(buf) && !mkdir(buf, 0777)) + !unlink_or_warn(buf) && !mkdir(buf, 0777)) continue; die("cannot create directory at %s", buf); } diff --git a/fast-import.c b/fast-import.c index 8d959af3b2..6a618e9163 100644 --- a/fast-import.c +++ b/fast-import.c @@ -931,7 +931,7 @@ static void unkeep_all_packs(void) struct packed_git *p = all_packs[k]; snprintf(name, sizeof(name), "%s/pack/pack-%s.keep", get_object_directory(), sha1_to_hex(p->sha1)); - unlink(name); + unlink_or_warn(name); } } @@ -981,7 +981,7 @@ static void end_packfile(void) } else { close(old_p->pack_fd); - unlink(old_p->pack_name); + unlink_or_warn(old_p->pack_name); } free(old_p); diff --git a/http-push.c b/http-push.c index 5138224cc3..29e8ebfebb 100644 --- a/http-push.c +++ b/http-push.c @@ -315,9 +315,9 @@ static void start_fetch_loose(struct transfer_request *request) "%s.temp", filename); snprintf(prevfile, sizeof(prevfile), "%s.prev", request->filename); - unlink(prevfile); + unlink_or_warn(prevfile); rename(request->tmpfile, prevfile); - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); if (request->local_fileno != -1) error("fd leakage in start: %d", request->local_fileno); @@ -372,7 +372,7 @@ static void start_fetch_loose(struct transfer_request *request) } while (prev_read > 0); close(prevlocal); } - unlink(prevfile); + unlink_or_warn(prevfile); /* Reset inflate/SHA1 if there was an error reading the previous temp file; also rewind to the beginning of the local file. */ @@ -784,7 +784,7 @@ static void finish_request(struct transfer_request *request) request->http_code != 416) { if (stat(request->tmpfile, &st) == 0) { if (st.st_size == 0) - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); } } else { if (request->http_code == 416) @@ -793,9 +793,9 @@ static void finish_request(struct transfer_request *request) git_inflate_end(&request->stream); git_SHA1_Final(request->real_sha1, &request->c); if (request->zret != Z_STREAM_END) { - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); } else if (hashcmp(request->obj->sha1, request->real_sha1)) { - unlink(request->tmpfile); + unlink_or_warn(request->tmpfile); } else { request->rename = move_temp_to_file( diff --git a/http-walker.c b/http-walker.c index c5a3ea3b31..7321ccc9fe 100644 --- a/http-walker.c +++ b/http-walker.c @@ -111,9 +111,9 @@ static void start_object_request(struct walker *walker, struct walker_data *data = walker->data; snprintf(prevfile, sizeof(prevfile), "%s.prev", obj_req->filename); - unlink(prevfile); + unlink_or_warn(prevfile); rename(obj_req->tmpfile, prevfile); - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); if (obj_req->local != -1) error("fd leakage in start: %d", obj_req->local); @@ -177,7 +177,7 @@ static void start_object_request(struct walker *walker, } while (prev_read > 0); close(prevlocal); } - unlink(prevfile); + unlink_or_warn(prevfile); /* Reset inflate/SHA1 if there was an error reading the previous temp file; also rewind to the beginning of the local file. */ @@ -238,18 +238,18 @@ static void finish_object_request(struct object_request *obj_req) } else if (obj_req->curl_result != CURLE_OK) { if (stat(obj_req->tmpfile, &st) == 0) if (st.st_size == 0) - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); return; } git_inflate_end(&obj_req->stream); git_SHA1_Final(obj_req->real_sha1, &obj_req->c); if (obj_req->zret != Z_STREAM_END) { - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); return; } if (hashcmp(obj_req->sha1, obj_req->real_sha1)) { - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); return; } obj_req->rename = @@ -809,7 +809,7 @@ static void abort_object_request(struct object_request *obj_req) close(obj_req->local); obj_req->local = -1; } - unlink(obj_req->tmpfile); + unlink_or_warn(obj_req->tmpfile); if (obj_req->slot) { release_active_slot(obj_req->slot); obj_req->slot = NULL; diff --git a/ll-merge.c b/ll-merge.c index fa2ca5250c..81c02ad053 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -219,7 +219,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn, close(fd); bad: for (i = 0; i < 3; i++) - unlink(temp[i]); + unlink_or_warn(temp[i]); strbuf_release(&cmd); return status; } diff --git a/lockfile.c b/lockfile.c index 3dbb2d1ff9..984eb320fc 100644 --- a/lockfile.c +++ b/lockfile.c @@ -16,7 +16,7 @@ static void remove_lock_file(void) lock_file_list->filename[0]) { if (lock_file_list->fd >= 0) close(lock_file_list->fd); - unlink(lock_file_list->filename); + unlink_or_warn(lock_file_list->filename); } lock_file_list = lock_file_list->next; } @@ -259,7 +259,7 @@ void rollback_lock_file(struct lock_file *lk) if (lk->filename[0]) { if (lk->fd >= 0) close(lk->fd); - unlink(lk->filename); + unlink_or_warn(lk->filename); } lk->filename[0] = 0; } diff --git a/pack-refs.c b/pack-refs.c index 2c76fb181f..301fc60eae 100644 --- a/pack-refs.c +++ b/pack-refs.c @@ -66,7 +66,7 @@ static void prune_ref(struct ref_to_prune *r) struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1); if (lock) { - unlink(git_path("%s", r->name)); + unlink_or_warn(git_path("%s", r->name)); unlock_ref(lock); } } diff --git a/refs.c b/refs.c index e65a3b4c4e..2b1f0f0e6e 100644 --- a/refs.c +++ b/refs.c @@ -1002,12 +1002,10 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt) } else { path = git_path("%s", refname); } - err = unlink(path); - if (err && errno != ENOENT) { + err = unlink_or_warn(path); + if (err && errno != ENOENT) ret = 1; - error("unlink(%s) failed: %s", - path, strerror(errno)); - } + if (!(delopt & REF_NODEREF)) lock->lk->filename[i] = '.'; } @@ -1017,10 +1015,7 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt) */ ret |= repack_without_ref(refname); - err = unlink(git_path("logs/%s", lock->ref_name)); - if (err && errno != ENOENT) - warning("unlink(%s) failed: %s", - git_path("logs/%s", lock->ref_name), strerror(errno)); + unlink_or_warn(git_path("logs/%s", lock->ref_name)); invalidate_cached_refs(); unlock_ref(lock); return ret; @@ -1381,7 +1376,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master, if (adjust_shared_perm(git_HEAD)) { error("Unable to fix permissions on %s", lockpath); error_unlink_return: - unlink(lockpath); + unlink_or_warn(lockpath); error_free_return: free(git_HEAD); return -1; diff --git a/rerere.c b/rerere.c index 713c6e16ac..87360dc23e 100644 --- a/rerere.c +++ b/rerere.c @@ -173,7 +173,7 @@ static int handle_file(const char *path, git_SHA1_Final(sha1, &ctx); if (hunk != RR_CONTEXT) { if (output) - unlink(output); + unlink_or_warn(output); return error("Could not parse conflict hunks in %s", path); } if (wrerror) diff --git a/server-info.c b/server-info.c index 66b0d9d878..d096dc7718 100644 --- a/server-info.c +++ b/server-info.c @@ -246,7 +246,7 @@ int update_server_info(int force) errs = errs | update_info_packs(force); /* remove leftover rev-cache file if there is any */ - unlink(git_path("info/rev-cache")); + unlink_or_warn(git_path("info/rev-cache")); return errs; } diff --git a/sha1_file.c b/sha1_file.c index f708cf4f67..dd474116a8 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2247,7 +2247,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename) goto out; ret = errno; } - unlink(tmpfile); + unlink_or_warn(tmpfile); if (ret) { if (ret != EEXIST) { return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret)); diff --git a/transport.c b/transport.c index 3dfb03c06e..efecb65258 100644 --- a/transport.c +++ b/transport.c @@ -1069,7 +1069,7 @@ int transport_fetch_refs(struct transport *transport, const struct ref *refs) void transport_unlock_pack(struct transport *transport) { if (transport->pack_lockfile) { - unlink(transport->pack_lockfile); + unlink_or_warn(transport->pack_lockfile); free(transport->pack_lockfile); transport->pack_lockfile = NULL; } diff --git a/unpack-trees.c b/unpack-trees.c index e4eb8fa3af..aaacaf1015 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -61,7 +61,7 @@ static void unlink_entry(struct cache_entry *ce) { if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce))) return; - if (unlink(ce->name)) + if (unlink_or_warn(ce->name)) return; schedule_dir_for_removal(ce->name, ce_namelen(ce)); } -- cgit v1.3 From 4b25d091ba53c758fae0096b8c0662371857b9d9 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 1 May 2009 12:06:36 +0300 Subject: Fix a bunch of pointer declarations (codestyle) Essentially; s/type* /type */ as per the coding guidelines. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- alias.c | 4 ++-- alloc.c | 2 +- attr.c | 4 ++-- builtin-blame.c | 8 ++++---- builtin-checkout-index.c | 4 ++-- builtin-describe.c | 4 ++-- builtin-fetch-pack.c | 2 +- builtin-help.c | 6 +++--- builtin-update-index.c | 6 +++--- cache.h | 2 +- combine-diff.c | 4 ++-- compat/mingw.c | 2 +- config.c | 30 +++++++++++++++--------------- contrib/convert-objects/convert-objects.c | 6 +++--- diff-no-index.c | 2 +- diff.c | 4 ++-- dir.c | 2 +- fast-import.c | 14 +++++++------- git.c | 8 ++++---- lockfile.c | 2 +- reflog-walk.c | 2 +- run-command.c | 2 +- server-info.c | 4 ++-- sha1_file.c | 2 +- wt-status.c | 2 +- 25 files changed, 64 insertions(+), 64 deletions(-) (limited to 'diff.c') diff --git a/alias.c b/alias.c index ccb1108c94..e687fe54c1 100644 --- a/alias.c +++ b/alias.c @@ -27,7 +27,7 @@ int split_cmdline(char *cmdline, const char ***argv) int src, dst, count = 0, size = 16; char quoted = 0; - *argv = xmalloc(sizeof(char*) * size); + *argv = xmalloc(sizeof(char *) * size); /* split alias_string */ (*argv)[count++] = cmdline; @@ -40,7 +40,7 @@ int split_cmdline(char *cmdline, const char ***argv) ; /* skip */ if (count >= size) { size += 16; - *argv = xrealloc(*argv, sizeof(char*) * size); + *argv = xrealloc(*argv, sizeof(char *) * size); } (*argv)[count++] = cmdline + dst; } else if (!quoted && (c == '\'' || c == '"')) { diff --git a/alloc.c b/alloc.c index 216c23a6f8..6ef6753d18 100644 --- a/alloc.c +++ b/alloc.c @@ -57,7 +57,7 @@ DEFINE_ALLOCATOR(object, union any_object) #define SZ_FMT "%zu" #endif -static void report(const char* name, unsigned int count, size_t size) +static void report(const char *name, unsigned int count, size_t size) { fprintf(stderr, "%10s: %8u (" SZ_FMT " kB)\n", name, count, size); } diff --git a/attr.c b/attr.c index f1ca4f5859..98eb636f13 100644 --- a/attr.c +++ b/attr.c @@ -224,7 +224,7 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, if (is_macro) res->u.attr = git_attr(name, namelen); else { - res->u.pattern = (char*)&(res->state[num_attr]); + res->u.pattern = (char *)&(res->state[num_attr]); memcpy(res->u.pattern, name, namelen); res->u.pattern[namelen] = 0; } @@ -275,7 +275,7 @@ static void free_attr_elem(struct attr_stack *e) setto == ATTR__UNKNOWN) ; else - free((char*) setto); + free((char *) setto); } free(a); } diff --git a/builtin-blame.c b/builtin-blame.c index 83141fc84e..cf74a92614 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -873,7 +873,7 @@ static void find_copy_in_blob(struct scoreboard *sb, * Prepare mmfile that contains only the lines in ent. */ cp = nth_line(sb, ent->lno); - file_o.ptr = (char*) cp; + file_o.ptr = (char *) cp; cnt = ent->num_lines; while (cnt && cp < sb->final_buf + sb->final_buf_size) { @@ -1704,7 +1704,7 @@ static int prepare_lines(struct scoreboard *sb) while (len--) { if (bol) { sb->lineno = xrealloc(sb->lineno, - sizeof(int* ) * (num + 1)); + sizeof(int *) * (num + 1)); sb->lineno[num] = buf - sb->final_buf; bol = 0; } @@ -1714,7 +1714,7 @@ static int prepare_lines(struct scoreboard *sb) } } sb->lineno = xrealloc(sb->lineno, - sizeof(int* ) * (num + incomplete + 1)); + sizeof(int *) * (num + incomplete + 1)); sb->lineno[num + incomplete] = buf - sb->final_buf; sb->num_lines = num + incomplete; return sb->num_lines; @@ -1889,7 +1889,7 @@ static const char *parse_loc(const char *spec, return spec; /* it could be a regexp of form /.../ */ - for (term = (char*) spec + 1; *term && *term != '/'; term++) { + for (term = (char *) spec + 1; *term && *term != '/'; term++) { if (*term == '\\') term++; } diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 0d534bc023..afe35e246c 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -124,7 +124,7 @@ static int checkout_file(const char *name, int prefix_length) static void checkout_all(const char *prefix, int prefix_length) { int i, errs = 0; - struct cache_entry* last_ce = NULL; + struct cache_entry *last_ce = NULL; for (i = 0; i < active_nr ; i++) { struct cache_entry *ce = active_cache[i]; @@ -278,7 +278,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) p = prefix_path(prefix, prefix_length, arg); checkout_file(p, prefix_length); if (p < arg || p > arg + strlen(arg)) - free((char*)p); + free((char *)p); } if (read_from_stdin) { diff --git a/builtin-describe.c b/builtin-describe.c index 3a007ed1ca..63c6a19da5 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -334,7 +334,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) die("--long is incompatible with --abbrev=0"); if (contains) { - const char **args = xmalloc((7 + argc) * sizeof(char*)); + const char **args = xmalloc((7 + argc) * sizeof(char *)); int i = 0; args[i++] = "name-rev"; args[i++] = "--name-only"; @@ -349,7 +349,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix) args[i++] = s; } } - memcpy(args + i, argv, argc * sizeof(char*)); + memcpy(args + i, argv, argc * sizeof(char *)); args[i + argc] = NULL; return cmd_name_rev(i + argc, args, prefix); } diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 5d134be47c..cbe5f206f5 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -111,7 +111,7 @@ static void mark_common(struct commit *commit, Get the next rev to send, ignoring the common. */ -static const unsigned char* get_rev(void) +static const unsigned char *get_rev(void) { struct commit *commit = NULL; diff --git a/builtin-help.c b/builtin-help.c index e7fbe9af63..67dda3e6e6 100644 --- a/builtin-help.c +++ b/builtin-help.c @@ -114,7 +114,7 @@ static int check_emacsclient_version(void) return 0; } -static void exec_woman_emacs(const char* path, const char *page) +static void exec_woman_emacs(const char *path, const char *page) { if (!check_emacsclient_version()) { /* This works only with emacsclient version >= 22. */ @@ -128,7 +128,7 @@ static void exec_woman_emacs(const char* path, const char *page) } } -static void exec_man_konqueror(const char* path, const char *page) +static void exec_man_konqueror(const char *path, const char *page) { const char *display = getenv("DISPLAY"); if (display && *display) { @@ -156,7 +156,7 @@ static void exec_man_konqueror(const char* path, const char *page) } } -static void exec_man_man(const char* path, const char *page) +static void exec_man_man(const char *path, const char *page) { if (!path) path = "man"; diff --git a/builtin-update-index.c b/builtin-update-index.c index 1fde893cfa..92beaaf4b3 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -292,7 +292,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length) report("add '%s'", path); free_return: if (p < path || p > path + strlen(path)) - free((char*)p); + free((char *)p); } static void read_index_info(int line_termination) @@ -509,7 +509,7 @@ static int do_unresolve(int ac, const char **av, const char *p = prefix_path(prefix, prefix_length, arg); err |= unresolve_one(p); if (p < arg || p > arg + strlen(arg)) - free((char*)p); + free((char *)p); } return err; } @@ -712,7 +712,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (set_executable_bit) chmod_path(set_executable_bit, p); if (p < path || p > path + strlen(path)) - free((char*)p); + free((char *)p); } if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; diff --git a/cache.h b/cache.h index d0d48b4c88..b8503ad91c 100644 --- a/cache.h +++ b/cache.h @@ -846,7 +846,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1, extern void pack_report(void); extern int open_pack_index(struct packed_git *); -extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); +extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); extern void close_pack_windows(struct packed_git *); extern void unuse_pack(struct pack_window **); extern void free_pack_by_name(const char *); diff --git a/combine-diff.c b/combine-diff.c index d210656861..60d03676bb 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -24,7 +24,7 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr, path = q->queue[i]->two->path; len = strlen(path); p = xmalloc(combine_diff_path_size(num_parent, len)); - p->path = (char*) &(p->parent[num_parent]); + p->path = (char *) &(p->parent[num_parent]); memcpy(p->path, path, len); p->path[len] = 0; p->len = len; @@ -1063,7 +1063,7 @@ void diff_tree_combined_merge(const unsigned char *sha1, for (parents = commit->parents, num_parent = 0; parents; parents = parents->next, num_parent++) - hashcpy((unsigned char*)(parent + num_parent), + hashcpy((unsigned char *)(parent + num_parent), parents->item->object.sha1); diff_tree_combined(sha1, parent, num_parent, dense, rev); } diff --git a/compat/mingw.c b/compat/mingw.c index 2a047019e8..cdeda1d985 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -562,7 +562,7 @@ static char **get_path_split(void) if (!n) return NULL; - path = xmalloc((n+1)*sizeof(char*)); + path = xmalloc((n+1)*sizeof(char *)); p = envpath; i = 0; do { diff --git a/config.c b/config.c index f76a78311e..1682273c12 100644 --- a/config.c +++ b/config.c @@ -724,16 +724,16 @@ int git_config(config_fn_t fn, void *data) static struct { int baselen; - char* key; + char *key; int do_not_match; - regex_t* value_regex; + regex_t *value_regex; int multi_replace; size_t offset[MAX_MATCHES]; enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; int seen; } store; -static int matches(const char* key, const char* value) +static int matches(const char *key, const char *value) { return !strcmp(key, store.key) && (store.value_regex == NULL || @@ -741,7 +741,7 @@ static int matches(const char* key, const char* value) !regexec(store.value_regex, value, 0, NULL, 0))); } -static int store_aux(const char* key, const char* value, void *cb) +static int store_aux(const char *key, const char *value, void *cb) { const char *ep; size_t section_len; @@ -810,7 +810,7 @@ static int write_error(const char *filename) return 4; } -static int store_write_section(int fd, const char* key) +static int store_write_section(int fd, const char *key) { const char *dot; int i, success; @@ -835,7 +835,7 @@ static int store_write_section(int fd, const char* key) return success; } -static int store_write_pair(int fd, const char* key, const char* value) +static int store_write_pair(int fd, const char *key, const char *value) { int i, success; int length = strlen(key + store.baselen + 1); @@ -883,8 +883,8 @@ static int store_write_pair(int fd, const char* key, const char* value) return success; } -static ssize_t find_beginning_of_line(const char* contents, size_t size, - size_t offset_, int* found_bracket) +static ssize_t find_beginning_of_line(const char *contents, size_t size, + size_t offset_, int *found_bracket) { size_t equal_offset = size, bracket_offset = size; ssize_t offset; @@ -909,7 +909,7 @@ contline: return offset; } -int git_config_set(const char* key, const char* value) +int git_config_set(const char *key, const char *value) { return git_config_set_multivar(key, value, NULL, 0); } @@ -937,15 +937,15 @@ int git_config_set(const char* key, const char* value) * - the config file is removed and the lock file rename()d to it. * */ -int git_config_set_multivar(const char* key, const char* value, - const char* value_regex, int multi_replace) +int git_config_set_multivar(const char *key, const char *value, + const char *value_regex, int multi_replace) { int i, dot; int fd = -1, in_fd; int ret; - char* config_filename; + char *config_filename; struct lock_file *lock = NULL; - const char* last_dot = strrchr(key, '.'); + const char *last_dot = strrchr(key, '.'); if (config_exclusive_filename) config_filename = xstrdup(config_exclusive_filename); @@ -1026,13 +1026,13 @@ int git_config_set_multivar(const char* key, const char* value, goto out_free; } - store.key = (char*)key; + store.key = (char *)key; if (!store_write_section(fd, key) || !store_write_pair(fd, key, value)) goto write_err_out; } else { struct stat st; - char* contents; + char *contents; size_t contents_sz, copy_begin, copy_end; int i, new_line = 0; diff --git a/contrib/convert-objects/convert-objects.c b/contrib/convert-objects/convert-objects.c index 90e7900e6d..f3b57bf1d2 100644 --- a/contrib/convert-objects/convert-objects.c +++ b/contrib/convert-objects/convert-objects.c @@ -59,7 +59,7 @@ static void convert_ascii_sha1(void *buffer) struct entry *entry; if (get_sha1_hex(buffer, sha1)) - die("expected sha1, got '%s'", (char*) buffer); + die("expected sha1, got '%s'", (char *) buffer); entry = convert_entry(sha1); memcpy(buffer, sha1_to_hex(entry->new_sha1), 40); } @@ -100,7 +100,7 @@ static int write_subdirectory(void *buffer, unsigned long size, const char *base if (!slash) { newlen += sprintf(new + newlen, "%o %s", mode, path); new[newlen++] = '\0'; - hashcpy((unsigned char*)new + newlen, (unsigned char *) buffer + len - 20); + hashcpy((unsigned char *)new + newlen, (unsigned char *) buffer + len - 20); newlen += 20; used += len; @@ -271,7 +271,7 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu unsigned long orig_size = size; if (memcmp(buffer, "tree ", 5)) - die("Bad commit '%s'", (char*) buffer); + die("Bad commit '%s'", (char *) buffer); convert_ascii_sha1((char *) buffer + 5); buffer = (char *) buffer + 46; /* "tree " + "hex sha1" + "\n" */ while (!memcmp(buffer, "parent ", 7)) { diff --git a/diff-no-index.c b/diff-no-index.c index 42c1dd8ad3..4ebc1dbd87 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -233,7 +233,7 @@ void diff_no_index(struct rev_info *revs, if (prefix) { int len = strlen(prefix); - revs->diffopt.paths = xcalloc(2, sizeof(char*)); + revs->diffopt.paths = xcalloc(2, sizeof(char *)); for (i = 0; i < 2; i++) { const char *p = argv[argc - 2 + i]; /* diff --git a/diff.c b/diff.c index 3ac71686eb..363dcb9613 100644 --- a/diff.c +++ b/diff.c @@ -876,7 +876,7 @@ static void fill_print_name(struct diffstat_file *file) file->print_name = pname; } -static void show_stats(struct diffstat_t* data, struct diff_options *options) +static void show_stats(struct diffstat_t *data, struct diff_options *options) { int i, len, add, del, adds = 0, dels = 0; int max_change = 0, max_len = 0; @@ -1025,7 +1025,7 @@ static void show_shortstats(struct diffstat_t* data, struct diff_options *option total_files, adds, dels); } -static void show_numstat(struct diffstat_t* data, struct diff_options *options) +static void show_numstat(struct diffstat_t *data, struct diff_options *options) { int i; diff --git a/dir.c b/dir.c index c91ebfb46f..15677da47c 100644 --- a/dir.c +++ b/dir.c @@ -156,7 +156,7 @@ void add_exclude(const char *string, const char *base, if (len && string[len - 1] == '/') { char *s; x = xmalloc(sizeof(*x) + len); - s = (char*)(x+1); + s = (char *)(x+1); memcpy(s, string, len - 1); s[len - 1] = '\0'; string = s; diff --git a/fast-import.c b/fast-import.c index 8d959af3b2..e9d23ffb2f 100644 --- a/fast-import.c +++ b/fast-import.c @@ -212,7 +212,7 @@ struct tree_content; struct tree_entry { struct tree_content *tree; - struct atom_str* name; + struct atom_str *name; struct tree_entry_ms { uint16_t mode; @@ -313,7 +313,7 @@ static unsigned int object_entry_alloc = 5000; static struct object_entry_pool *blocks; static struct object_entry *object_table[1 << 16]; static struct mark_set *marks; -static const char* mark_file; +static const char *mark_file; /* Our last blob */ static struct last_object last_blob = { STRBUF_INIT, 0, 0, 0 }; @@ -672,7 +672,7 @@ static struct branch *lookup_branch(const char *name) static struct branch *new_branch(const char *name) { unsigned int hc = hc_str(name, strlen(name)) % branch_table_sz; - struct branch* b = lookup_branch(name); + struct branch *b = lookup_branch(name); if (b) die("Invalid attempt to create duplicate branch: %s", name); @@ -1035,7 +1035,7 @@ static int store_object( git_SHA_CTX c; z_stream s; - hdrlen = sprintf((char*)hdr,"%s %lu", typename(type), + hdrlen = sprintf((char *)hdr,"%s %lu", typename(type), (unsigned long)dat->len) + 1; git_SHA1_Init(&c); git_SHA1_Update(&c, hdr, hdrlen); @@ -1217,7 +1217,7 @@ static const char *get_mode(const char *str, uint16_t *modep) static void load_tree(struct tree_entry *root) { - unsigned char* sha1 = root->versions[1].sha1; + unsigned char *sha1 = root->versions[1].sha1; struct object_entry *myoe; struct tree_content *t; unsigned long size; @@ -1258,8 +1258,8 @@ static void load_tree(struct tree_entry *root) e->versions[0].mode = e->versions[1].mode; e->name = to_atom(c, strlen(c)); c += e->name->str_len + 1; - hashcpy(e->versions[0].sha1, (unsigned char*)c); - hashcpy(e->versions[1].sha1, (unsigned char*)c); + hashcpy(e->versions[0].sha1, (unsigned char *)c); + hashcpy(e->versions[1].sha1, (unsigned char *)c); c += 20; } free(buf); diff --git a/git.c b/git.c index cc5aaa76f1..5a00726d09 100644 --- a/git.c +++ b/git.c @@ -47,7 +47,7 @@ static void commit_pager_choice(void) { } } -static int handle_options(const char*** argv, int* argc, int* envchanged) +static int handle_options(const char ***argv, int *argc, int *envchanged) { int handled = 0; @@ -136,7 +136,7 @@ static int handle_alias(int *argcp, const char ***argv) int envchanged = 0, ret = 0, saved_errno = errno; const char *subdir; int count, option_count; - const char** new_argv; + const char **new_argv; const char *alias_command; char *alias_string; int unused_nongit; @@ -187,10 +187,10 @@ static int handle_alias(int *argcp, const char ***argv) "trace: alias expansion: %s =>", alias_command); - new_argv = xrealloc(new_argv, sizeof(char*) * + new_argv = xrealloc(new_argv, sizeof(char *) * (count + *argcp + 1)); /* insert after command name */ - memcpy(new_argv + count, *argv + 1, sizeof(char*) * *argcp); + memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); new_argv[count+*argcp] = NULL; *argv = new_argv; diff --git a/lockfile.c b/lockfile.c index 3dbb2d1ff9..828d19f452 100644 --- a/lockfile.c +++ b/lockfile.c @@ -109,7 +109,7 @@ static char *resolve_symlink(char *p, size_t s) * link is a relative path, so I must replace the * last element of p with it. */ - char *r = (char*)last_path_elm(p); + char *r = (char *)last_path_elm(p); if (r - p + link_len < s) strcpy(r, link); else { diff --git a/reflog-walk.c b/reflog-walk.c index fd065f4e1a..5623ea6b48 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -241,7 +241,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) commit->object.flags &= ~(ADDED | SEEN | SHOWN); } -void show_reflog_message(struct reflog_walk_info* info, int oneline, +void show_reflog_message(struct reflog_walk_info *info, int oneline, enum date_mode dmode) { if (info && info->last_commit_reflog) { diff --git a/run-command.c b/run-command.c index b05c734d05..eb2efc3307 100644 --- a/run-command.c +++ b/run-command.c @@ -106,7 +106,7 @@ int start_command(struct child_process *cmd) if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) - putenv((char*)*cmd->env); + putenv((char *)*cmd->env); else unsetenv(*cmd->env); } diff --git a/server-info.c b/server-info.c index 66b0d9d878..906ce5b272 100644 --- a/server-info.c +++ b/server-info.c @@ -132,8 +132,8 @@ static int read_pack_info_file(const char *infofile) static int compare_info(const void *a_, const void *b_) { - struct pack_info * const* a = a_; - struct pack_info * const* b = b_; + struct pack_info *const *a = a_; + struct pack_info *const *b = b_; if (0 <= (*a)->old_num && 0 <= (*b)->old_num) /* Keep the order in the original */ diff --git a/sha1_file.c b/sha1_file.c index f708cf4f67..28bd9082fc 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -791,7 +791,7 @@ static int in_window(struct pack_window *win, off_t offset) && (offset + 20) <= (win_off + win->len); } -unsigned char* use_pack(struct packed_git *p, +unsigned char *use_pack(struct packed_git *p, struct pack_window **w_cursor, off_t offset, unsigned int *left) diff --git a/wt-status.c b/wt-status.c index 929b00f592..1b6df45450 100644 --- a/wt-status.c +++ b/wt-status.c @@ -40,7 +40,7 @@ static int parse_status_slot(const char *var, int offset) die("bad config variable '%s'", var); } -static const char* color(int slot) +static const char *color(int slot) { return wt_status_use_color > 0 ? wt_status_colors[slot] : ""; } -- cgit v1.3 From 3cd7388d57db4f4a29949e8de96493fb77059484 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 25 May 2009 06:46:09 -0400 Subject: convert bare readlink to strbuf_readlink This particular readlink call never NUL-terminated its result, making it a potential source of bugs (though there is no bug now, as it currently always respects the length field). Let's just switch it to strbuf_readlink which is shorter and less error-prone. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index f06876be67..dcfbcb0215 100644 --- a/diff.c +++ b/diff.c @@ -2014,18 +2014,15 @@ static struct diff_tempfile *prepare_temp_file(const char *name, die("stat(%s): %s", name, strerror(errno)); } if (S_ISLNK(st.st_mode)) { - int ret; - char buf[PATH_MAX + 1]; /* ought to be SYMLINK_MAX */ - ret = readlink(name, buf, sizeof(buf)); - if (ret < 0) + struct strbuf sb = STRBUF_INIT; + if (strbuf_readlink(&sb, name, st.st_size) < 0) die("readlink(%s)", name); - if (ret == sizeof(buf)) - die("symlink too long: %s", name); - prep_temp_blob(name, temp, buf, ret, + prep_temp_blob(name, temp, sb.buf, sb.len, (one->sha1_valid ? one->sha1 : null_sha1), (one->sha1_valid ? one->mode : S_IFLNK)); + strbuf_release(&sb); } else { /* we can borrow from the file in the work tree */ -- cgit v1.3 From 003b33a8ad686ee4a0d0b36635bfd6aba940b24a Mon Sep 17 00:00:00 2001 From: David Aguilar Date: Sun, 31 May 2009 01:35:52 -0700 Subject: diff: generate pretty filenames in prep_temp_blob() Naturally, prep_temp_blob() did not care about filenames. As a result, GIT_EXTERNAL_DIFF and textconv generated filenames such as ".diff_XXXXXX". This modifies prep_temp_blob() to generate user-friendly filenames when creating temporary files. Diffing "name.ext" now generates "XXXXXX_name.ext". Signed-off-by: David Aguilar Signed-off-by: Junio C Hamano --- cache.h | 2 ++ diff.c | 12 +++++++++++- path.c | 16 ++++++++++++++++ t/t4020-diff-external.sh | 9 +++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/cache.h b/cache.h index b8503ad91c..871c9844e8 100644 --- a/cache.h +++ b/cache.h @@ -614,6 +614,8 @@ extern int is_empty_blob_sha1(const unsigned char *sha1); int git_mkstemp(char *path, size_t n, const char *template); +int git_mkstemps(char *path, size_t n, const char *template, int suffix_len); + /* * NOTE NOTE NOTE!! * diff --git a/diff.c b/diff.c index dcfbcb0215..4d0a5b9ae6 100644 --- a/diff.c +++ b/diff.c @@ -1964,8 +1964,16 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp, { int fd; struct strbuf buf = STRBUF_INIT; + struct strbuf template = STRBUF_INIT; + char *path_dup = xstrdup(path); + const char *base = basename(path_dup); - fd = git_mkstemp(temp->tmp_path, PATH_MAX, ".diff_XXXXXX"); + /* Generate "XXXXXX_basename.ext" */ + strbuf_addstr(&template, "XXXXXX_"); + strbuf_addstr(&template, base); + + fd = git_mkstemps(temp->tmp_path, PATH_MAX, template.buf, + strlen(base) + 1); if (fd < 0) die("unable to create temp-file: %s", strerror(errno)); if (convert_to_working_tree(path, @@ -1981,6 +1989,8 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp, temp->hex[40] = 0; sprintf(temp->mode, "%06o", mode); strbuf_release(&buf); + strbuf_release(&template); + free(path_dup); } static struct diff_tempfile *prepare_temp_file(const char *name, diff --git a/path.c b/path.c index 8a0a6741fd..047fdb0a1f 100644 --- a/path.c +++ b/path.c @@ -139,6 +139,22 @@ int git_mkstemp(char *path, size_t len, const char *template) return mkstemp(path); } +/* git_mkstemps() - create tmp file with suffix honoring TMPDIR variable. */ +int git_mkstemps(char *path, size_t len, const char *template, int suffix_len) +{ + const char *tmp; + size_t n; + + tmp = getenv("TMPDIR"); + if (!tmp) + tmp = "/tmp"; + n = snprintf(path, len, "%s/%s", tmp, template); + if (len <= n) { + errno = ENAMETOOLONG; + return -1; + } + return mkstemps(path, suffix_len); +} int validate_headref(const char *path) { diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 0720001281..4ea42e00da 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -136,6 +136,15 @@ test_expect_success 'GIT_EXTERNAL_DIFF with more than one changed files' ' GIT_EXTERNAL_DIFF=echo git diff ' +test_expect_success 'GIT_EXTERNAL_DIFF generates pretty paths' ' + touch file.ext && + git add file.ext && + echo with extension > file.ext && + GIT_EXTERNAL_DIFF=echo git diff file.ext | grep ......_file\.ext && + git update-index --force-remove file.ext && + rm file.ext +' + echo "#!$SHELL_PATH" >fake-diff.sh cat >> fake-diff.sh <<\EOF cat $2 >> crlfed.txt -- cgit v1.3 From 802f9c9cb21321d3ffe7576e01bbe31c51bd4c70 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Mon, 8 Jun 2009 22:34:30 +0200 Subject: diff.c: plug a memory leak in an error path Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- diff.c | 1 + 1 file changed, 1 insertion(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index d24bff1e46..f0b580c150 100644 --- a/diff.c +++ b/diff.c @@ -3590,6 +3590,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, if (start_command(&child) != 0 || strbuf_read(&buf, child.out, 0) < 0 || finish_command(&child) != 0) { + strbuf_release(&buf); remove_tempfile(); error("error running textconv command '%s'", pgm); return NULL; -- cgit v1.3 From d824cbba02a4061400a0e382f9bd241fbbff34f0 Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Sat, 27 Jun 2009 17:58:46 +0200 Subject: Convert existing die(..., strerror(errno)) to die_errno() Change calls to die(..., strerror(errno)) to use the new die_errno(). In the process, also make slight style adjustments: at least state _something_ about the function that failed (instead of just printing the pathname), and put paths in single quotes. Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- bisect.c | 5 ++--- branch.c | 4 ++-- builtin-apply.c | 6 +++--- builtin-blame.c | 7 +++---- builtin-clone.c | 11 +++++------ builtin-commit-tree.c | 2 +- builtin-commit.c | 23 ++++++++++------------- builtin-config.c | 4 ++-- builtin-diff.c | 2 +- builtin-fast-export.c | 2 +- builtin-fetch--tool.c | 2 +- builtin-fmt-merge-msg.c | 3 +-- builtin-fsck.c | 8 ++++---- builtin-grep.c | 2 +- builtin-merge.c | 8 ++++---- builtin-mv.c | 2 +- builtin-pack-objects.c | 14 +++++--------- builtin-rm.c | 2 +- builtin-send-pack.c | 2 +- builtin-tag.c | 7 +++---- builtin-unpack-objects.c | 2 +- csum-file.c | 5 ++--- daemon.c | 15 +++++++-------- diff.c | 4 ++-- dir.c | 2 +- entry.c | 8 ++++---- fast-import.c | 4 ++-- git.c | 6 +++--- index-pack.c | 21 ++++++++++----------- merge-recursive.c | 6 +++--- pack-refs.c | 7 +++---- pack-write.c | 10 +++++----- pkt-line.c | 4 ++-- read-cache.c | 6 +++--- refs.c | 2 +- run-command.c | 4 ++-- setup.c | 8 ++++---- sha1_file.c | 2 +- shell.c | 2 +- test-sha1.c | 2 +- wrapper.c | 8 ++++---- write_or_die.c | 6 +++--- 42 files changed, 117 insertions(+), 133 deletions(-) (limited to 'diff.c') diff --git a/bisect.c b/bisect.c index c43c120bde..281e16ad19 100644 --- a/bisect.c +++ b/bisect.c @@ -461,7 +461,7 @@ void read_bisect_paths(struct argv_array *array) FILE *fp = fopen(filename, "r"); if (!fp) - die("Could not open file '%s': %s", filename, strerror(errno)); + die_errno("Could not open file '%s'", filename); while (strbuf_getline(&str, fp, '\n') != EOF) { char *quoted; @@ -632,8 +632,7 @@ static void mark_expected_rev(char *bisect_rev_hex) int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) - die("could not create file '%s': %s", - filename, strerror(errno)); + die_errno("could not create file '%s'", filename); bisect_rev_hex[len] = '\n'; write_or_die(fd, bisect_rev_hex, len + 1); diff --git a/branch.c b/branch.c index 62030af4b5..05ef3f5c9c 100644 --- a/branch.c +++ b/branch.c @@ -172,7 +172,7 @@ void create_branch(const char *head, lock = lock_any_ref_for_update(ref.buf, NULL, 0); if (!lock) - die("Failed to lock ref for update: %s.", strerror(errno)); + die_errno("Failed to lock ref for update"); if (reflog) log_all_ref_updates = 1; @@ -188,7 +188,7 @@ void create_branch(const char *head, setup_tracking(name, real_ref, track); if (write_ref_sha1(lock, sha1, msg) < 0) - die("Failed to write ref: %s.", strerror(errno)); + die_errno("Failed to write ref"); strbuf_release(&ref); free(real_ref); diff --git a/builtin-apply.c b/builtin-apply.c index 94ba2bdd5b..6526c087b9 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -280,7 +280,7 @@ static void say_patch_name(FILE *output, const char *pre, static void read_patch_file(struct strbuf *sb, int fd) { if (strbuf_read(sb, fd, 0) < 0) - die("git apply: read returned %s", strerror(errno)); + die_errno("git apply: failed to read"); /* * Make sure that we have some slop in the buffer @@ -2864,7 +2864,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf, strbuf_release(&nbuf); if (close(fd) < 0) - die("closing file %s: %s", path, strerror(errno)); + die_errno("closing file '%s'", path); return 0; } @@ -3354,7 +3354,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix) fd = open(arg, O_RDONLY); if (fd < 0) - die("can't open patch '%s': %s", arg, strerror(errno)); + die_errno("can't open patch '%s'", arg); read_stdin = 0; set_default_whitespace_mode(whitespace_option); errs |= apply_patch(fd, arg, options); diff --git a/builtin-blame.c b/builtin-blame.c index 0c2d29a430..7d8fbd5919 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -2035,7 +2035,7 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con contents_from = "standard input"; mode = 0; if (strbuf_read(&buf, 0, 0) < 0) - die("read error %s from stdin", strerror(errno)); + die_errno("failed to read from stdin"); } convert_to_git(path, buf.buf, buf.len, &buf, 0); origin->file.ptr = buf.buf; @@ -2261,8 +2261,7 @@ parse_done: argc = parse_options_end(&ctx); if (revs_file && read_ancestry(revs_file)) - die("reading graft file %s failed: %s", - revs_file, strerror(errno)); + die_errno("reading graft file '%s' failed", revs_file); if (cmd_is_annotate) { output_option |= OUTPUT_ANNOTATE_COMPAT; @@ -2350,7 +2349,7 @@ parse_done: setup_work_tree(); if (!has_string_in_work_tree(path)) - die("cannot stat path %s: %s", path, strerror(errno)); + die_errno("cannot stat path '%s'", path); } setup_revisions(argc, argv, &revs, NULL); diff --git a/builtin-clone.c b/builtin-clone.c index 5c46496a43..5f34414ff7 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -252,8 +252,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) } if (unlink(dest->buf) && errno != ENOENT) - die("failed to unlink %s: %s", - dest->buf, strerror(errno)); + die_errno("failed to unlink '%s'", dest->buf); if (!option_no_hardlinks) { if (!link(src->buf, dest->buf)) continue; @@ -420,11 +419,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (!option_bare) { junk_work_tree = work_tree; if (safe_create_leading_directories_const(work_tree) < 0) - die("could not create leading directories of '%s': %s", - work_tree, strerror(errno)); + die_errno("could not create leading directories of '%s'", + work_tree); if (!dest_exists && mkdir(work_tree, 0755)) - die("could not create work tree dir '%s': %s.", - work_tree, strerror(errno)); + die_errno("could not create work tree dir '%s'.", + work_tree); set_git_work_tree(work_tree); } junk_git_dir = git_dir; diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 0453425c47..6467077731 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -124,7 +124,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) } if (strbuf_read(&buffer, 0, 0) < 0) - die("git commit-tree: read returned %s", strerror(errno)); + die_errno("git commit-tree: failed to read"); if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) { printf("%s\n", sha1_to_hex(commit_sha1)); diff --git a/builtin-commit.c b/builtin-commit.c index 41e222d267..88c51bdd3a 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -438,8 +438,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix) hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) - die("could not read log file '%s': %s", - logfile, strerror(errno)); + die_errno("could not read log file '%s'", + logfile); hook_arg1 = "message"; } else if (use_message) { buffer = strstr(use_message_buffer, "\n\n"); @@ -450,16 +450,15 @@ static int prepare_to_commit(const char *index_file, const char *prefix) hook_arg2 = use_message; } else if (!stat(git_path("MERGE_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0) - die("could not read MERGE_MSG: %s", strerror(errno)); + die_errno("could not read MERGE_MSG"); hook_arg1 = "merge"; } else if (!stat(git_path("SQUASH_MSG"), &statbuf)) { if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0) - die("could not read SQUASH_MSG: %s", strerror(errno)); + die_errno("could not read SQUASH_MSG"); hook_arg1 = "squash"; } else if (template_file && !stat(template_file, &statbuf)) { if (strbuf_read_file(&sb, template_file, 0) < 0) - die("could not read %s: %s", - template_file, strerror(errno)); + die_errno("could not read '%s'", template_file); hook_arg1 = "template"; } @@ -472,8 +471,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) fp = fopen(git_path(commit_editmsg), "w"); if (fp == NULL) - die("could not open %s: %s", - git_path(commit_editmsg), strerror(errno)); + die_errno("could not open '%s'", git_path(commit_editmsg)); if (cleanup_mode != CLEANUP_NONE) stripspace(&sb, 0); @@ -497,7 +495,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) } if (fwrite(sb.buf, 1, sb.len, fp) < sb.len) - die("could not write commit template: %s", strerror(errno)); + die_errno("could not write commit template"); strbuf_release(&sb); @@ -940,8 +938,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix) pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next; fp = fopen(git_path("MERGE_HEAD"), "r"); if (fp == NULL) - die("could not open %s for reading: %s", - git_path("MERGE_HEAD"), strerror(errno)); + die_errno("could not open '%s' for reading", + git_path("MERGE_HEAD")); while (strbuf_getline(&m, fp, '\n') != EOF) { unsigned char sha1[20]; if (get_sha1_hex(m.buf, sha1) < 0) @@ -952,8 +950,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) strbuf_release(&m); if (!stat(git_path("MERGE_MODE"), &statbuf)) { if (strbuf_read_file(&sb, git_path("MERGE_MODE"), 0) < 0) - die("could not read MERGE_MODE: %s", - strerror(errno)); + die_errno("could not read MERGE_MODE"); if (!strcmp(sb.buf, "no-ff")) allow_fast_forward = 0; } diff --git a/builtin-config.c b/builtin-config.c index 60915f91ca..a2d656edb3 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -383,8 +383,8 @@ int cmd_config(int argc, const char **argv, const char *unused_prefix) check_argc(argc, 0, 0); if (git_config(show_all_config, NULL) < 0) { if (config_exclusive_filename) - die("unable to read config file %s: %s", - config_exclusive_filename, strerror(errno)); + die_errno("unable to read config file '%s'", + config_exclusive_filename); else die("error processing config file(s)"); } diff --git a/builtin-diff.c b/builtin-diff.c index d75d69bf57..2e51f408f9 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -70,7 +70,7 @@ static int builtin_diff_b_f(struct rev_info *revs, usage(builtin_diff_usage); if (lstat(path, &st)) - die("'%s': %s", path, strerror(errno)); + die_errno("failed to stat '%s'", path); if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) die("'%s': not a regular file or symlink", path); diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 6cef810312..333d43894a 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -451,7 +451,7 @@ static void import_marks(char *input_file) char line[512]; FILE *f = fopen(input_file, "r"); if (!f) - die("cannot read %s: %s", input_file, strerror(errno)); + die_errno("cannot read '%s'", input_file); while (fgets(line, sizeof(line), f)) { uint32_t mark; diff --git a/builtin-fetch--tool.c b/builtin-fetch--tool.c index 29356d25db..3dbdf7a288 100644 --- a/builtin-fetch--tool.c +++ b/builtin-fetch--tool.c @@ -8,7 +8,7 @@ static char *get_stdin(void) { struct strbuf buf = STRBUF_INIT; if (strbuf_read(&buf, 0, 1024) < 0) { - die("error reading standard input: %s", strerror(errno)); + die_errno("error reading standard input"); } return strbuf_detach(&buf, NULL); } diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index fbf9582e66..1248d5e3a3 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -372,8 +372,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) } if (strbuf_read(&input, fileno(in), 0) < 0) - die("could not read input file %s", strerror(errno)); - + die_errno("could not read input file"); ret = fmt_merge_msg(merge_summary, &input, &output); if (ret) return ret; diff --git a/builtin-fsck.c b/builtin-fsck.c index 7da706cac3..a49dbe14c7 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -225,15 +225,15 @@ static void check_unreachable_object(struct object *obj) &type, &size); if (buf) { if (fwrite(buf, size, 1, f) != 1) - die("Could not write %s: %s", - filename, strerror(errno)); + die_errno("Could not write '%s'", + filename); free(buf); } } else fprintf(f, "%s\n", sha1_to_hex(obj->sha1)); if (fclose(f)) - die("Could not finish %s: %s", - filename, strerror(errno)); + die_errno("Could not finish '%s'", + filename); } return; } diff --git a/builtin-grep.c b/builtin-grep.c index 73fc922c49..e5583686a2 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -594,7 +594,7 @@ static int file_callback(const struct option *opt, const char *arg, int unset) patterns = fopen(arg, "r"); if (!patterns) - die("'%s': %s", arg, strerror(errno)); + die_errno("cannot open '%s'", arg); while (strbuf_getline(&sb, patterns, '\n') == 0) { /* ignore empty line like grep does */ if (sb.len == 0) diff --git a/builtin-merge.c b/builtin-merge.c index 8d101eff0b..436263bc19 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -294,9 +294,9 @@ static void squash_message(void) NULL, NULL, rev.date_mode, 0); } if (write(fd, out.buf, out.len) < 0) - die("Writing SQUASH_MSG: %s", strerror(errno)); + die_errno("Writing SQUASH_MSG"); if (close(fd)) - die("Finishing SQUASH_MSG: %s", strerror(errno)); + die_errno("Finishing SQUASH_MSG"); strbuf_release(&out); } @@ -428,8 +428,8 @@ static void merge_name(const char *remote, struct strbuf *msg) fp = fopen(git_path("FETCH_HEAD"), "r"); if (!fp) - die("could not open %s for reading: %s", - git_path("FETCH_HEAD"), strerror(errno)); + die_errno("could not open '%s' for reading", + git_path("FETCH_HEAD")); strbuf_getline(&line, fp, '\n'); fclose(fp); ptr = strstr(line.buf, "\tnot-for-merge\t"); diff --git a/builtin-mv.c b/builtin-mv.c index 8b81d4b51d..024dfebf7e 100644 --- a/builtin-mv.c +++ b/builtin-mv.c @@ -209,7 +209,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix) printf("Renaming %s to %s\n", src, dst); if (!show_only && mode != INDEX && rename(src, dst) < 0 && !ignore_errors) - die ("renaming %s failed: %s", src, strerror(errno)); + die_errno ("renaming '%s' failed", src); if (mode == WORKING_DIRECTORY) continue; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 9742b45c4d..60355d41fd 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -536,11 +536,9 @@ static void write_pack_file(void) base_name, sha1_to_hex(sha1)); free_pack_by_name(tmpname); if (adjust_perm(pack_tmp_name, mode)) - die("unable to make temporary pack file readable: %s", - strerror(errno)); + die_errno("unable to make temporary pack file readable"); if (rename(pack_tmp_name, tmpname)) - die("unable to rename temporary pack file: %s", - strerror(errno)); + die_errno("unable to rename temporary pack file"); /* * Packs are runtime accessed in their mtime @@ -566,11 +564,9 @@ static void write_pack_file(void) snprintf(tmpname, sizeof(tmpname), "%s-%s.idx", base_name, sha1_to_hex(sha1)); if (adjust_perm(idx_tmp_name, mode)) - die("unable to make temporary index file readable: %s", - strerror(errno)); + die_errno("unable to make temporary index file readable"); if (rename(idx_tmp_name, tmpname)) - die("unable to rename temporary index file: %s", - strerror(errno)); + die_errno("unable to rename temporary index file"); free(idx_tmp_name); free(pack_tmp_name); @@ -1880,7 +1876,7 @@ static void read_object_list_from_stdin(void) if (!ferror(stdin)) die("fgets returned NULL, not EOF, not error!"); if (errno != EINTR) - die("fgets: %s", strerror(errno)); + die_errno("fgets"); clearerr(stdin); continue; } diff --git a/builtin-rm.c b/builtin-rm.c index 0cc4912718..57975dbcfd 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -257,7 +257,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) continue; } if (!removed) - die("git rm: %s: %s", path, strerror(errno)); + die_errno("git rm: '%s'", path); } } diff --git a/builtin-send-pack.c b/builtin-send-pack.c index be3b0926de..8fe5ab90b6 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -59,7 +59,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext po.out = fd; po.git_cmd = 1; if (start_command(&po)) - die("git pack-objects failed (%s)", strerror(errno)); + die_errno("git pack-objects failed"); /* * We feed the pack-objects we just spawned with revision diff --git a/builtin-tag.c b/builtin-tag.c index dc3db62811..7b51095c80 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -308,8 +308,7 @@ static void create_tag(const unsigned char *object, const char *tag, path = git_pathdup("TAG_EDITMSG"); fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (fd < 0) - die("could not create file '%s': %s", - path, strerror(errno)); + die_errno("could not create file '%s'", path); if (!is_null_sha1(prev)) write_tag_body(fd, prev); @@ -446,8 +445,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) die("cannot read %s", msgfile); } else { if (strbuf_read_file(&buf, msgfile, 1024) < 0) - die("could not open or read '%s': %s", - msgfile, strerror(errno)); + die_errno("could not open or read '%s'", + msgfile); } } } diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c index 9a773239ca..41e9ac526c 100644 --- a/builtin-unpack-objects.c +++ b/builtin-unpack-objects.c @@ -68,7 +68,7 @@ static void *fill(int min) if (ret <= 0) { if (!ret) die("early EOF"); - die("read error on input: %s", strerror(errno)); + die_errno("read error on input"); } len += ret; } while (len < min); diff --git a/csum-file.c b/csum-file.c index 2ddb12a0b7..4d50cc5ce1 100644 --- a/csum-file.c +++ b/csum-file.c @@ -26,7 +26,7 @@ static void flush(struct sha1file *f, void * buf, unsigned int count) } if (!ret) die("sha1 file '%s' write error. Out of diskspace", f->name); - die("sha1 file '%s' write error (%s)", f->name, strerror(errno)); + die_errno("sha1 file '%s' write error", f->name); } } @@ -55,8 +55,7 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags) if (flags & CSUM_FSYNC) fsync_or_die(f->fd, f->name); if (close(f->fd)) - die("%s: sha1 file error on close (%s)", - f->name, strerror(errno)); + die_errno("%s: sha1 file error on close", f->name); fd = 0; } else fd = f->fd; diff --git a/daemon.c b/daemon.c index b2babcc076..0c2f32635a 100644 --- a/daemon.c +++ b/daemon.c @@ -862,7 +862,7 @@ static int service_loop(int socknum, int *socklist) case ECONNABORTED: continue; default: - die("accept returned %s", strerror(errno)); + die_errno("accept returned"); } } handle(incoming, (struct sockaddr *)&ss, sslen); @@ -878,7 +878,7 @@ static void sanitize_stdfds(void) while (fd != -1 && fd < 2) fd = dup(fd); if (fd == -1) - die("open /dev/null or dup failed: %s", strerror(errno)); + die_errno("open /dev/null or dup failed"); if (fd > 2) close(fd); } @@ -889,12 +889,12 @@ static void daemonize(void) case 0: break; case -1: - die("fork failed: %s", strerror(errno)); + die_errno("fork failed"); default: exit(0); } if (setsid() == -1) - die("setsid failed: %s", strerror(errno)); + die_errno("setsid failed"); close(0); close(1); close(2); @@ -905,9 +905,9 @@ static void store_pid(const char *path) { FILE *f = fopen(path, "w"); if (!f) - die("cannot open pid file %s: %s", path, strerror(errno)); + die_errno("cannot open pid file '%s'", path); if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0) - die("failed to write pid file %s: %s", path, strerror(errno)); + die_errno("failed to write pid file '%s'", path); } static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid) @@ -1107,8 +1107,7 @@ int main(int argc, char **argv) socklen_t slen = sizeof(ss); if (!freopen("/dev/null", "w", stderr)) - die("failed to redirect stderr to /dev/null: %s", - strerror(errno)); + die_errno("failed to redirect stderr to /dev/null"); if (getpeername(0, peer, &slen)) peer = NULL; diff --git a/diff.c b/diff.c index 4d0a5b9ae6..48043f5bdb 100644 --- a/diff.c +++ b/diff.c @@ -1975,7 +1975,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp, fd = git_mkstemps(temp->tmp_path, PATH_MAX, template.buf, strlen(base) + 1); if (fd < 0) - die("unable to create temp-file: %s", strerror(errno)); + die_errno("unable to create temp-file"); if (convert_to_working_tree(path, (const char *)blob, (size_t)size, &buf)) { blob = buf.buf; @@ -2021,7 +2021,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, if (lstat(name, &st) < 0) { if (errno == ENOENT) goto not_a_valid_file; - die("stat(%s): %s", name, strerror(errno)); + die_errno("stat(%s)", name); } if (S_ISLNK(st.st_mode)) { struct strbuf sb = STRBUF_INIT; diff --git a/dir.c b/dir.c index bbfcb566e6..74b3bbf6fd 100644 --- a/dir.c +++ b/dir.c @@ -759,7 +759,7 @@ char *get_relative_cwd(char *buffer, int size, const char *dir) if (!dir) return NULL; if (!getcwd(buffer, size)) - die("can't find the current directory: %s", strerror(errno)); + die_errno("can't find the current directory"); if (!is_absolute_path(dir)) dir = make_absolute_path(dir); diff --git a/entry.c b/entry.c index cc841edf90..8ec880bdbd 100644 --- a/entry.c +++ b/entry.c @@ -51,7 +51,7 @@ static void remove_subtree(const char *path) char *name; if (!dir) - die("cannot opendir %s (%s)", path, strerror(errno)); + die_errno("cannot opendir '%s'", path); strcpy(pathbuf, path); name = pathbuf + strlen(path); *name++ = '/'; @@ -61,15 +61,15 @@ static void remove_subtree(const char *path) continue; strcpy(name, de->d_name); if (lstat(pathbuf, &st)) - die("cannot lstat %s (%s)", pathbuf, strerror(errno)); + die_errno("cannot lstat '%s'", pathbuf); if (S_ISDIR(st.st_mode)) remove_subtree(pathbuf); else if (unlink(pathbuf)) - die("cannot unlink %s (%s)", pathbuf, strerror(errno)); + die_errno("cannot unlink '%s'", pathbuf); } closedir(dir); if (rmdir(path)) - die("cannot rmdir %s (%s)", path, strerror(errno)); + die_errno("cannot rmdir '%s'", path); } static int create_file(const char *path, unsigned int mode) diff --git a/fast-import.c b/fast-import.c index a2a24588a9..d31a4e8217 100644 --- a/fast-import.c +++ b/fast-import.c @@ -2342,7 +2342,7 @@ static void import_marks(const char *input_file) char line[512]; FILE *f = fopen(input_file, "r"); if (!f) - die("cannot read %s: %s", input_file, strerror(errno)); + die_errno("cannot read '%s'", input_file); while (fgets(line, sizeof(line), f)) { uintmax_t mark; char *end; @@ -2448,7 +2448,7 @@ int main(int argc, const char **argv) fclose(pack_edges); pack_edges = fopen(a + 20, "a"); if (!pack_edges) - die("Cannot open %s: %s", a + 20, strerror(errno)); + die_errno("Cannot open '%s'", a + 20); } else if (!strcmp(a, "--force")) force_update = 1; else if (!strcmp(a, "--quiet")) diff --git a/git.c b/git.c index 7d7f949f0d..b035676e93 100644 --- a/git.c +++ b/git.c @@ -200,7 +200,7 @@ static int handle_alias(int *argcp, const char ***argv) } if (subdir && chdir(subdir)) - die("Cannot change to %s: %s", subdir, strerror(errno)); + die_errno("Cannot change to '%s'", subdir); errno = saved_errno; @@ -257,11 +257,11 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) /* Check for ENOSPC and EIO errors.. */ if (fflush(stdout)) - die("write failure on standard output: %s", strerror(errno)); + die_errno("write failure on standard output"); if (ferror(stdout)) die("unknown write failure on standard output"); if (fclose(stdout)) - die("close failed on standard output: %s", strerror(errno)); + die_errno("close failed on standard output"); return 0; } diff --git a/index-pack.c b/index-pack.c index 6e93ee6af6..cf6446fc43 100644 --- a/index-pack.c +++ b/index-pack.c @@ -143,7 +143,7 @@ static void *fill(int min) if (ret <= 0) { if (!ret) die("early EOF"); - die("read error on input: %s", strerror(errno)); + die_errno("read error on input"); } input_len += ret; if (from_stdin) @@ -178,13 +178,12 @@ static char *open_pack_file(char *pack_name) } else output_fd = open(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600); if (output_fd < 0) - die("unable to create %s: %s", pack_name, strerror(errno)); + die_errno("unable to create '%s'", pack_name); pack_fd = output_fd; } else { input_fd = open(pack_name, O_RDONLY); if (input_fd < 0) - die("cannot open packfile '%s': %s", - pack_name, strerror(errno)); + die_errno("cannot open packfile '%s'", pack_name); output_fd = -1; pack_fd = input_fd; } @@ -370,7 +369,7 @@ static void *get_data_from_pack(struct object_entry *obj) do { ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy); if (n < 0) - die("cannot pread pack file: %s", strerror(errno)); + die_errno("cannot pread pack file"); if (!n) die("premature end of pack file, %lu bytes missing", len - rdy); @@ -631,7 +630,7 @@ static void parse_pack_objects(unsigned char *sha1) /* If input_fd is a file, we should have reached its end now. */ if (fstat(input_fd, &st)) - die("cannot fstat packfile: %s", strerror(errno)); + die_errno("cannot fstat packfile"); if (S_ISREG(st.st_mode) && lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size) die("pack has junk at the end"); @@ -788,7 +787,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name, fsync_or_die(output_fd, curr_pack_name); err = close(output_fd); if (err) - die("error while closing pack file: %s", strerror(errno)); + die_errno("error while closing pack file"); } if (keep_msg) { @@ -801,16 +800,16 @@ static void final(const char *final_pack_name, const char *curr_pack_name, if (keep_fd < 0) { if (errno != EEXIST) - die("cannot write keep file '%s' (%s)", - keep_name, strerror(errno)); + die_errno("cannot write keep file '%s'", + keep_name); } else { if (keep_msg_len > 0) { write_or_die(keep_fd, keep_msg, keep_msg_len); write_or_die(keep_fd, "\n", 1); } if (close(keep_fd) != 0) - die("cannot close written keep file '%s' (%s)", - keep_name, strerror(errno)); + die_errno("cannot close written keep file '%s'", + keep_name); report = "keep"; } } diff --git a/merge-recursive.c b/merge-recursive.c index f5df9b961b..5d9140b8d6 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -438,7 +438,7 @@ static void flush_buffer(int fd, const char *buf, unsigned long size) /* Ignore epipe */ if (errno == EPIPE) break; - die("merge-recursive: %s", strerror(errno)); + die_errno("merge-recursive"); } else if (!ret) { die("merge-recursive: disk full?"); } @@ -554,7 +554,7 @@ static void update_file_flags(struct merge_options *o, mode = 0666; fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode); if (fd < 0) - die("failed to open %s: %s", path, strerror(errno)); + die_errno("failed to open '%s'", path); flush_buffer(fd, buf, size); close(fd); } else if (S_ISLNK(mode)) { @@ -562,7 +562,7 @@ static void update_file_flags(struct merge_options *o, safe_create_leading_directories_const(path); unlink(path); if (symlink(lnk, path)) - die("failed to symlink %s: %s", path, strerror(errno)); + die_errno("failed to symlink '%s'", path); free(lnk); } else die("do not know what to do with %06o %s '%s'", diff --git a/pack-refs.c b/pack-refs.c index 301fc60eae..7f43f8ac33 100644 --- a/pack-refs.c +++ b/pack-refs.c @@ -93,8 +93,7 @@ int pack_refs(unsigned int flags) LOCK_DIE_ON_ERROR); cbdata.refs_file = fdopen(fd, "w"); if (!cbdata.refs_file) - die("unable to create ref-pack file structure (%s)", - strerror(errno)); + die_errno("unable to create ref-pack file structure"); /* perhaps other traits later as well */ fprintf(cbdata.refs_file, "# pack-refs with: peeled \n"); @@ -103,7 +102,7 @@ int pack_refs(unsigned int flags) if (ferror(cbdata.refs_file)) die("failed to write ref-pack file"); if (fflush(cbdata.refs_file) || fsync(fd) || fclose(cbdata.refs_file)) - die("failed to write ref-pack file (%s)", strerror(errno)); + die_errno("failed to write ref-pack file"); /* * Since the lock file was fdopen()'ed and then fclose()'ed above, * assign -1 to the lock file descriptor so that commit_lock_file() @@ -111,7 +110,7 @@ int pack_refs(unsigned int flags) */ packed.fd = -1; if (commit_lock_file(&packed) < 0) - die("unable to overwrite old ref-pack file (%s)", strerror(errno)); + die_errno("unable to overwrite old ref-pack file"); if (cbdata.flags & PACK_REFS_PRUNE) prune_refs(cbdata.ref_to_prune); return 0; diff --git a/pack-write.c b/pack-write.c index 7053538f4c..741efcd93b 100644 --- a/pack-write.c +++ b/pack-write.c @@ -51,7 +51,7 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600); } if (fd < 0) - die("unable to create %s: %s", index_name, strerror(errno)); + die_errno("unable to create '%s'", index_name); f = sha1fd(fd, index_name); /* if last object's offset is >= 2^31 we should use index V2 */ @@ -174,11 +174,11 @@ void fixup_pack_header_footer(int pack_fd, git_SHA1_Init(&new_sha1_ctx); if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); + die_errno("Failed seeking to start of '%s'", pack_name); if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - die("Unable to reread header of %s: %s", pack_name, strerror(errno)); + die_errno("Unable to reread header of '%s'", pack_name); if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); + die_errno("Failed seeking to start of '%s'", pack_name); git_SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr)); hdr.hdr_entries = htonl(object_count); git_SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr)); @@ -195,7 +195,7 @@ void fixup_pack_header_footer(int pack_fd, if (!n) break; if (n < 0) - die("Failed to checksum %s: %s", pack_name, strerror(errno)); + die_errno("Failed to checksum '%s'", pack_name); git_SHA1_Update(&new_sha1_ctx, buf, n); aligned_sz -= n; diff --git a/pkt-line.c b/pkt-line.c index f5d00863a6..b691abebd7 100644 --- a/pkt-line.c +++ b/pkt-line.c @@ -28,7 +28,7 @@ ssize_t safe_write(int fd, const void *buf, ssize_t n) } if (!ret) die("write error (disk full?)"); - die("write error (%s)", strerror(errno)); + die_errno("write error"); } return nn; } @@ -67,7 +67,7 @@ static void safe_read(int fd, void *buffer, unsigned size) { ssize_t ret = read_in_full(fd, buffer, size); if (ret < 0) - die("read error (%s)", strerror(errno)); + die_errno("read error"); else if (ret < size) die("The remote end hung up unexpectedly"); } diff --git a/read-cache.c b/read-cache.c index 3f587110cb..f76b5bb2e1 100644 --- a/read-cache.c +++ b/read-cache.c @@ -638,7 +638,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags) { struct stat st; if (lstat(path, &st)) - die("%s: unable to stat (%s)", path, strerror(errno)); + die_errno("unable to stat '%s'", path); return add_to_index(istate, path, &st, flags); } @@ -1251,11 +1251,11 @@ int read_index_from(struct index_state *istate, const char *path) if (fd < 0) { if (errno == ENOENT) return 0; - die("index file open failed (%s)", strerror(errno)); + die_errno("index file open failed"); } if (fstat(fd, &st)) - die("cannot stat the open index (%s)", strerror(errno)); + die_errno("cannot stat the open index"); errno = EINVAL; mmap_size = xsize_t(st.st_size); diff --git a/refs.c b/refs.c index 24438c652f..dffe395a97 100644 --- a/refs.c +++ b/refs.c @@ -1418,7 +1418,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * logfile = git_path("logs/%s", ref); logfd = open(logfile, O_RDONLY, 0); if (logfd < 0) - die("Unable to read log %s: %s", logfile, strerror(errno)); + die_errno("Unable to read log '%s'", logfile); fstat(logfd, &st); if (!st.st_size) die("Log %s is empty.", logfile); diff --git a/run-command.c b/run-command.c index eb2efc3307..ff3d8e2d8b 100644 --- a/run-command.c +++ b/run-command.c @@ -101,8 +101,8 @@ int start_command(struct child_process *cmd) } if (cmd->dir && chdir(cmd->dir)) - die("exec %s: cd to %s failed (%s)", cmd->argv[0], - cmd->dir, strerror(errno)); + die_errno("exec '%s': cd to '%s' failed", cmd->argv[0], + cmd->dir); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) diff --git a/setup.c b/setup.c index ebd60de9ce..4d27f28c8f 100644 --- a/setup.c +++ b/setup.c @@ -81,7 +81,7 @@ void verify_filename(const char *prefix, const char *arg) if (errno == ENOENT) die("ambiguous argument '%s': unknown revision or path not in the working tree.\n" "Use '--' to separate paths from revisions", arg); - die("'%s': %s", arg, strerror(errno)); + die_errno("failed to stat '%s'", arg); } /* @@ -103,7 +103,7 @@ void verify_non_filename(const char *prefix, const char *arg) die("ambiguous argument '%s': both revision and filename\n" "Use '--' to separate filenames from revisions", arg); if (errno != ENOENT && errno != ENOTDIR) - die("'%s': %s", arg, strerror(errno)); + die_errno("failed to stat '%s'", arg); } const char **get_pathspec(const char *prefix, const char **pathspec) @@ -257,7 +257,7 @@ const char *read_gitfile_gently(const char *path) return NULL; fd = open(path, O_RDONLY); if (fd < 0) - die("Error opening %s: %s", path, strerror(errno)); + die_errno("Error opening '%s'", path); buf = xmalloc(st.st_size + 1); len = read_in_full(fd, buf, st.st_size); close(fd); @@ -389,7 +389,7 @@ const char *setup_git_directory_gently(int *nongit_ok) die("Not a git repository (or any of the parent directories): %s", DEFAULT_GIT_DIR_ENVIRONMENT); } if (chdir("..")) - die("Cannot change to %s/..: %s", cwd, strerror(errno)); + die_errno("Cannot change to '%s/..'", cwd); } inside_git_dir = 0; diff --git a/sha1_file.c b/sha1_file.c index e73cd4fc0b..1964a6d39b 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -2287,7 +2287,7 @@ static void close_sha1_file(int fd) if (fsync_object_files) fsync_or_die(fd, "sha1 file"); if (close(fd) != 0) - die("error when closing sha1 file (%s)", strerror(errno)); + die_errno("error when closing sha1 file"); } /* Size of directory component, including the ending '/' */ diff --git a/shell.c b/shell.c index b968be79f4..e4864e04da 100644 --- a/shell.c +++ b/shell.c @@ -60,7 +60,7 @@ int main(int argc, char **argv) while (devnull_fd >= 0 && devnull_fd <= 2) devnull_fd = dup(devnull_fd); if (devnull_fd == -1) - die("opening /dev/null failed (%s)", strerror(errno)); + die_errno("opening /dev/null failed"); close (devnull_fd); /* diff --git a/test-sha1.c b/test-sha1.c index 9b98d07c78..80daba980e 100644 --- a/test-sha1.c +++ b/test-sha1.c @@ -32,7 +32,7 @@ int main(int ac, char **av) if (sz == 0) break; if (sz < 0) - die("test-sha1: %s", strerror(errno)); + die_errno("test-sha1"); this_sz += sz; cp += sz; room -= sz; diff --git a/wrapper.c b/wrapper.c index 7eb3218ee9..c9be1400c0 100644 --- a/wrapper.c +++ b/wrapper.c @@ -96,7 +96,7 @@ void *xmmap(void *start, size_t length, release_pack_memory(length, fd); ret = mmap(start, length, prot, flags, fd, offset); if (ret == MAP_FAILED) - die("Out of memory? mmap failed: %s", strerror(errno)); + die_errno("Out of memory? mmap failed"); } return ret; } @@ -175,7 +175,7 @@ int xdup(int fd) { int ret = dup(fd); if (ret < 0) - die("dup failed: %s", strerror(errno)); + die_errno("dup failed"); return ret; } @@ -183,7 +183,7 @@ FILE *xfdopen(int fd, const char *mode) { FILE *stream = fdopen(fd, mode); if (stream == NULL) - die("Out of memory? fdopen failed: %s", strerror(errno)); + die_errno("Out of memory? fdopen failed"); return stream; } @@ -193,7 +193,7 @@ int xmkstemp(char *template) fd = mkstemp(template); if (fd < 0) - die("Unable to create temporary file: %s", strerror(errno)); + die_errno("Unable to create temporary file"); return fd; } diff --git a/write_or_die.c b/write_or_die.c index 4c29255df1..d45b536021 100644 --- a/write_or_die.c +++ b/write_or_die.c @@ -41,14 +41,14 @@ void maybe_flush_or_die(FILE *f, const char *desc) */ if (errno == EPIPE || errno == EINVAL) exit(0); - die("write failure on %s: %s", desc, strerror(errno)); + die_errno("write failure on '%s'", desc); } } void fsync_or_die(int fd, const char *msg) { if (fsync(fd) < 0) { - die("%s: fsync error (%s)", msg, strerror(errno)); + die_errno("fsync error on '%s'", msg); } } @@ -57,7 +57,7 @@ void write_or_die(int fd, const void *buf, size_t count) if (write_in_full(fd, buf, count) < 0) { if (errno == EPIPE) exit(0); - die("write error (%s)", strerror(errno)); + die_errno("write error"); } } -- cgit v1.3 From 0721c314a5c8fddc877140ab5a333c42c62f780d Mon Sep 17 00:00:00 2001 From: Thomas Rast Date: Sat, 27 Jun 2009 17:58:47 +0200 Subject: Use die_errno() instead of die() when checking syscalls Lots of die() calls did not actually report the kind of error, which can leave the user confused as to the real problem. Use die_errno() where we check a system/library call that sets errno on failure, or one of the following that wrap such calls: Function Passes on error from -------- -------------------- odb_pack_keep open read_ancestry fopen read_in_full xread strbuf_read xread strbuf_read_file open or strbuf_read_file strbuf_readlink readlink write_in_full xwrite Signed-off-by: Thomas Rast Signed-off-by: Junio C Hamano --- abspath.c | 12 ++++++------ builtin-add.c | 2 +- builtin-apply.c | 6 +++--- builtin-archive.c | 4 ++-- builtin-blame.c | 8 ++++---- builtin-clone.c | 10 +++++----- builtin-commit.c | 5 +++-- builtin-fast-export.c | 2 +- builtin-fmt-merge-msg.c | 2 +- builtin-fsck.c | 2 +- builtin-init-db.c | 21 +++++++++++---------- builtin-log.c | 4 ++-- builtin-mailsplit.c | 6 +++--- builtin-merge.c | 21 ++++++++++++--------- builtin-rev-parse.c | 2 +- builtin-revert.c | 2 +- builtin-stripspace.c | 2 +- builtin-tag.c | 2 +- builtin-tar-tree.c | 2 +- combine-diff.c | 2 +- diff.c | 6 +++--- entry.c | 2 +- fast-import.c | 4 ++-- hash-object.c | 2 +- ll-merge.c | 2 +- mktag.c | 2 +- read-cache.c | 2 +- setup.c | 10 +++++----- transport.c | 4 ++-- unpack-file.c | 2 +- 30 files changed, 79 insertions(+), 74 deletions(-) (limited to 'diff.c') diff --git a/abspath.c b/abspath.c index 649f34f833..4bee0ba1ec 100644 --- a/abspath.c +++ b/abspath.c @@ -41,13 +41,13 @@ const char *make_absolute_path(const char *path) if (*buf) { if (!*cwd && !getcwd(cwd, sizeof(cwd))) - die ("Could not get current working directory"); + die_errno ("Could not get current working directory"); if (chdir(buf)) - die ("Could not switch to '%s'", buf); + die_errno ("Could not switch to '%s'", buf); } if (!getcwd(buf, PATH_MAX)) - die ("Could not get current working directory"); + die_errno ("Could not get current working directory"); if (last_elem) { int len = strlen(buf); @@ -63,7 +63,7 @@ const char *make_absolute_path(const char *path) if (!lstat(buf, &st) && S_ISLNK(st.st_mode)) { len = readlink(buf, next_buf, PATH_MAX); if (len < 0) - die ("Invalid symlink: %s", buf); + die_errno ("Invalid symlink '%s'", buf); if (PATH_MAX <= len) die("symbolic link too long: %s", buf); next_buf[len] = '\0'; @@ -75,7 +75,7 @@ const char *make_absolute_path(const char *path) } if (*cwd && chdir(cwd)) - die ("Could not change back to '%s'", cwd); + die_errno ("Could not change back to '%s'", cwd); return buf; } @@ -109,7 +109,7 @@ const char *make_nonrelative_path(const char *path) } else { const char *cwd = get_pwd_cwd(); if (!cwd) - die("Cannot determine the current working directory"); + die_errno("Cannot determine the current working directory"); if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX) die("Too long path: %.*s", 60, path); } diff --git a/builtin-add.c b/builtin-add.c index c1b229a9d8..8f651c137a 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -220,7 +220,7 @@ int edit_patch(int argc, const char **argv, const char *prefix) launch_editor(file, NULL, NULL); if (stat(file, &st)) - die("Could not stat '%s'", file); + die_errno("Could not stat '%s'", file); if (!st.st_size) die("Empty patch. Aborted."); diff --git a/builtin-apply.c b/builtin-apply.c index 6526c087b9..dbc7f2165d 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2823,8 +2823,8 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned } else { if (!cached) { if (lstat(path, &st) < 0) - die("unable to stat newly created file %s", - path); + die_errno("unable to stat newly created file '%s'", + path); fill_stat_cache_info(ce, &st); } if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0) @@ -2913,7 +2913,7 @@ static void create_one_file(char *path, unsigned mode, const char *buf, unsigned ++nr; } } - die("unable to write file %s mode %o", path, mode); + die_errno("unable to write file '%s' mode %o", path, mode); } static void create_file(struct patch *patch) diff --git a/builtin-archive.c b/builtin-archive.c index 3c5a5a7822..f9a4bea41e 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -13,10 +13,10 @@ static void create_output_file(const char *output_file) { int output_fd = open(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666); if (output_fd < 0) - die("could not create archive file: %s ", output_file); + die_errno("could not create archive file '%s'", output_file); if (output_fd != 1) { if (dup2(output_fd, 1) < 0) - die("could not redirect output"); + die_errno("could not redirect output"); else close(output_fd); } diff --git a/builtin-blame.c b/builtin-blame.c index 7d8fbd5919..fd6ca51eeb 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -2008,23 +2008,23 @@ static struct commit *fake_working_tree_commit(const char *path, const char *con if (contents_from) { if (stat(contents_from, &st) < 0) - die("Cannot stat %s", contents_from); + die_errno("Cannot stat '%s'", contents_from); read_from = contents_from; } else { if (lstat(path, &st) < 0) - die("Cannot lstat %s", path); + die_errno("Cannot lstat '%s'", path); read_from = path; } mode = canon_mode(st.st_mode); switch (st.st_mode & S_IFMT) { case S_IFREG: if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) - die("cannot open or read %s", read_from); + die_errno("cannot open or read '%s'", read_from); break; case S_IFLNK: if (strbuf_readlink(&buf, read_from, st.st_size) < 0) - die("cannot readlink %s", read_from); + die_errno("cannot readlink '%s'", read_from); break; default: die("unsupported file type %s", read_from); diff --git a/builtin-clone.c b/builtin-clone.c index 5f34414ff7..d2b0757e53 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -220,13 +220,13 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) dir = opendir(src->buf); if (!dir) - die("failed to open %s", src->buf); + die_errno("failed to open '%s'", src->buf); if (mkdir(dest->buf, 0777)) { if (errno != EEXIST) - die("failed to create directory %s", dest->buf); + die_errno("failed to create directory '%s'", dest->buf); else if (stat(dest->buf, &buf)) - die("failed to stat %s", dest->buf); + die_errno("failed to stat '%s'", dest->buf); else if (!S_ISDIR(buf.st_mode)) die("%s exists and is not a directory", dest->buf); } @@ -257,11 +257,11 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest) if (!link(src->buf, dest->buf)) continue; if (option_local) - die("failed to create link %s", dest->buf); + die_errno("failed to create link '%s'", dest->buf); option_no_hardlinks = 1; } if (copy_file(dest->buf, src->buf, 0666)) - die("failed to copy file to %s", dest->buf); + die_errno("failed to copy file to '%s'", dest->buf); } closedir(dir); } diff --git a/builtin-commit.c b/builtin-commit.c index 88c51bdd3a..4bcce06fbf 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -434,7 +434,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix) if (isatty(0)) fprintf(stderr, "(reading log message from standard input)\n"); if (strbuf_read(&sb, 0, 0) < 0) - die("could not read log from standard input"); + die_errno("could not read log from standard input"); hook_arg1 = "message"; } else if (logfile) { if (strbuf_read_file(&sb, logfile, 0) < 0) @@ -964,8 +964,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) /* Finally, get the commit message */ strbuf_reset(&sb); if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0) { + int saved_errno = errno; rollback_index_files(); - die("could not read commit message"); + die("could not read commit message: %s", strerror(saved_errno)); } /* Truncate the message just before the diff, if any. */ diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 333d43894a..9a8a6fc6b1 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -119,7 +119,7 @@ static void handle_object(const unsigned char *sha1) printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size); if (size && fwrite(buf, size, 1, stdout) != 1) - die ("Could not write blob %s", sha1_to_hex(sha1)); + die_errno ("Could not write blob '%s'", sha1_to_hex(sha1)); printf("\n"); show_progress(); diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index 1248d5e3a3..9d524000b5 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -368,7 +368,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix) if (inpath && strcmp(inpath, "-")) { in = fopen(inpath, "r"); if (!in) - die("cannot open %s", inpath); + die_errno("cannot open '%s'", inpath); } if (strbuf_read(&input, fileno(in), 0) < 0) diff --git a/builtin-fsck.c b/builtin-fsck.c index a49dbe14c7..d0f48cdd2a 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -217,7 +217,7 @@ static void check_unreachable_object(struct object *obj) return; } if (!(f = fopen(filename, "w"))) - die("Could not open %s", filename); + die_errno("Could not open '%s'", filename); if (obj->type == OBJ_BLOB) { enum object_type type; unsigned long size; diff --git a/builtin-init-db.c b/builtin-init-db.c index d1fa12a59e..4a5600631c 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -61,20 +61,20 @@ static void copy_templates_1(char *path, int baselen, memcpy(template + template_baselen, de->d_name, namelen+1); if (lstat(path, &st_git)) { if (errno != ENOENT) - die("cannot stat %s", path); + die_errno("cannot stat '%s'", path); } else exists = 1; if (lstat(template, &st_template)) - die("cannot stat template %s", template); + die_errno("cannot stat template '%s'", template); if (S_ISDIR(st_template.st_mode)) { DIR *subdir = opendir(template); int baselen_sub = baselen + namelen; int template_baselen_sub = template_baselen + namelen; if (!subdir) - die("cannot opendir %s", template); + die_errno("cannot opendir '%s'", template); path[baselen_sub++] = template[template_baselen_sub++] = '/'; path[baselen_sub] = @@ -91,16 +91,17 @@ static void copy_templates_1(char *path, int baselen, int len; len = readlink(template, lnk, sizeof(lnk)); if (len < 0) - die("cannot readlink %s", template); + die_errno("cannot readlink '%s'", template); if (sizeof(lnk) <= len) die("insanely long symlink %s", template); lnk[len] = 0; if (symlink(lnk, path)) - die("cannot symlink %s %s", lnk, path); + die_errno("cannot symlink '%s' '%s'", lnk, path); } else if (S_ISREG(st_template.st_mode)) { if (copy_file(path, template, st_template.st_mode)) - die("cannot copy %s to %s", template, path); + die_errno("cannot copy '%s' to '%s'", template, + path); } else error("ignoring template %s", template); @@ -350,7 +351,7 @@ static int guess_repository_type(const char *git_dir) if (!strcmp(".", git_dir)) return 1; if (!getcwd(cwd, sizeof(cwd))) - die("cannot tell cwd"); + die_errno("cannot tell cwd"); if (!strcmp(git_dir, cwd)) return 1; /* @@ -440,11 +441,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix) if (!git_work_tree_cfg) { git_work_tree_cfg = xcalloc(PATH_MAX, 1); if (!getcwd(git_work_tree_cfg, PATH_MAX)) - die ("Cannot access current working directory."); + die_errno ("Cannot access current working directory"); } if (access(get_git_work_tree(), X_OK)) - die ("Cannot access work tree '%s'", - get_git_work_tree()); + die_errno ("Cannot access work tree '%s'", + get_git_work_tree()); } set_git_dir(make_absolute_path(git_dir)); diff --git a/builtin-log.c b/builtin-log.c index 0d34050556..750957cfa9 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -1013,8 +1013,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (use_stdout) die("standard output, or directory, which one?"); if (mkdir(output_directory, 0777) < 0 && errno != EEXIST) - die("Could not create directory %s", - output_directory); + die_errno("Could not create directory '%s'", + output_directory); } if (rev.pending.nr == 1) { diff --git a/builtin-mailsplit.c b/builtin-mailsplit.c index 71f3b3b874..ad5f6b593d 100644 --- a/builtin-mailsplit.c +++ b/builtin-mailsplit.c @@ -81,7 +81,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare) fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0666); if (fd < 0) - die("cannot open output file %s", name); + die_errno("cannot open output file '%s'", name); output = fdopen(fd, "w"); /* Copy it out, while searching for a line that begins with @@ -91,7 +91,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare) int is_partial = len && buf[len-1] != '\n'; if (fwrite(buf, 1, len, output) != len) - die("cannot write output"); + die_errno("cannot write output"); len = read_line_with_nul(buf, sizeof(buf), mbox); if (len == 0) { @@ -99,7 +99,7 @@ static int split_one(FILE *mbox, const char *name, int allow_bare) status = 1; break; } - die("cannot read mbox"); + die_errno("cannot read mbox"); } if (!is_partial && !is_bare && is_from_line(buf, len)) break; /* done with one message */ diff --git a/builtin-merge.c b/builtin-merge.c index 436263bc19..82335b09ed 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -268,7 +268,7 @@ static void squash_message(void) printf("Squash commit -- not updating HEAD\n"); fd = open(git_path("SQUASH_MSG"), O_WRONLY | O_CREAT, 0666); if (fd < 0) - die("Could not write to %s", git_path("SQUASH_MSG")); + die_errno("Could not write to '%s'", git_path("SQUASH_MSG")); init_revisions(&rev, NULL); rev.ignore_merges = 1; @@ -764,7 +764,8 @@ static int suggest_conflicts(void) fp = fopen(git_path("MERGE_MSG"), "a"); if (!fp) - die("Could not open %s for writing", git_path("MERGE_MSG")); + die_errno("Could not open '%s' for writing", + git_path("MERGE_MSG")); fprintf(fp, "\nConflicts:\n"); for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; @@ -1186,27 +1187,29 @@ int cmd_merge(int argc, const char **argv, const char *prefix) sha1_to_hex(j->item->object.sha1)); fd = open(git_path("MERGE_HEAD"), O_WRONLY | O_CREAT, 0666); if (fd < 0) - die("Could open %s for writing", - git_path("MERGE_HEAD")); + die_errno("Could not open '%s' for writing", + git_path("MERGE_HEAD")); if (write_in_full(fd, buf.buf, buf.len) != buf.len) - die("Could not write to %s", git_path("MERGE_HEAD")); + die_errno("Could not write to '%s'", git_path("MERGE_HEAD")); close(fd); strbuf_addch(&merge_msg, '\n'); fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666); if (fd < 0) - die("Could open %s for writing", git_path("MERGE_MSG")); + die_errno("Could not open '%s' for writing", + git_path("MERGE_MSG")); if (write_in_full(fd, merge_msg.buf, merge_msg.len) != merge_msg.len) - die("Could not write to %s", git_path("MERGE_MSG")); + die_errno("Could not write to '%s'", git_path("MERGE_MSG")); close(fd); fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666); if (fd < 0) - die("Could open %s for writing", git_path("MERGE_MODE")); + die_errno("Could not open '%s' for writing", + git_path("MERGE_MODE")); strbuf_reset(&buf); if (!allow_fast_forward) strbuf_addf(&buf, "no-ff"); if (write_in_full(fd, buf.buf, buf.len) != buf.len) - die("Could not write to %s", git_path("MERGE_MODE")); + die_errno("Could not write to '%s'", git_path("MERGE_MODE")); close(fd); } diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c index 112d622cda..da26dbc020 100644 --- a/builtin-rev-parse.c +++ b/builtin-rev-parse.c @@ -592,7 +592,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) continue; } if (!getcwd(cwd, PATH_MAX)) - die("unable to get current working directory"); + die_errno("unable to get current working directory"); printf("%s/.git\n", cwd); continue; } diff --git a/builtin-revert.c b/builtin-revert.c index c87115af30..151aa6a981 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -135,7 +135,7 @@ static void add_to_msg(const char *string) { int len = strlen(string); if (write_in_full(msg_fd, string, len) < 0) - die ("Could not write to MERGE_MSG"); + die_errno ("Could not write to MERGE_MSG"); } static void add_message_to_msg(const char *message) diff --git a/builtin-stripspace.c b/builtin-stripspace.c index d6e3896c00..1fd2205d53 100644 --- a/builtin-stripspace.c +++ b/builtin-stripspace.c @@ -78,7 +78,7 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix) strip_comments = 1; if (strbuf_read(&buf, 0, 1024) < 0) - die("could not read the input"); + die_errno("could not read the input"); stripspace(&buf, strip_comments); diff --git a/builtin-tag.c b/builtin-tag.c index 7b51095c80..165bec3069 100644 --- a/builtin-tag.c +++ b/builtin-tag.c @@ -442,7 +442,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix) else { if (!strcmp(msgfile, "-")) { if (strbuf_read(&buf, 0, 1024) < 0) - die("cannot read %s", msgfile); + die_errno("cannot read '%s'", msgfile); } else { if (strbuf_read_file(&buf, msgfile, 1024) < 0) die_errno("could not open or read '%s'", diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index f88e721936..8b3a35e12d 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -91,7 +91,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix) n = write_in_full(1, content + 11, 41); if (n < 41) - die("git get-tar-commit-id: write error"); + die_errno("git get-tar-commit-id: write error"); return 0; } diff --git a/combine-diff.c b/combine-diff.c index 60d03676bb..bbf74fc42e 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -746,7 +746,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, done = read_in_full(fd, result, len); if (done < 0) - die("read error '%s'", elem->path); + die_errno("read error '%s'", elem->path); else if (done < len) die("early EOF '%s'", elem->path); diff --git a/diff.c b/diff.c index 48043f5bdb..aec613f85a 100644 --- a/diff.c +++ b/diff.c @@ -1982,7 +1982,7 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp, size = buf.len; } if (write_in_full(fd, blob, size) != size) - die("unable to write temp-file"); + die_errno("unable to write temp-file"); close(fd); temp->name = temp->tmp_path; strcpy(temp->hex, sha1_to_hex(sha1)); @@ -2026,7 +2026,7 @@ static struct diff_tempfile *prepare_temp_file(const char *name, if (S_ISLNK(st.st_mode)) { struct strbuf sb = STRBUF_INIT; if (strbuf_readlink(&sb, name, st.st_size) < 0) - die("readlink(%s)", name); + die_errno("readlink(%s)", name); prep_temp_blob(name, temp, sb.buf, sb.len, (one->sha1_valid ? one->sha1 : null_sha1), @@ -2219,7 +2219,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one) return; } if (lstat(one->path, &st) < 0) - die("stat %s", one->path); + die_errno("stat '%s'", one->path); if (index_path(one->sha1, one->path, &st, 0)) die("cannot hash %s", one->path); } diff --git a/entry.c b/entry.c index 8ec880bdbd..d3e86c722a 100644 --- a/entry.c +++ b/entry.c @@ -37,7 +37,7 @@ static void create_directories(const char *path, int path_len, if (errno == EEXIST && state->force && !unlink_or_warn(buf) && !mkdir(buf, 0777)) continue; - die("cannot create directory at %s", buf); + die_errno("cannot create directory at '%s'", buf); } } free(buf); diff --git a/fast-import.c b/fast-import.c index d31a4e8217..7ef9865aa6 100644 --- a/fast-import.c +++ b/fast-import.c @@ -905,10 +905,10 @@ static char *keep_pack(char *curr_index_name) keep_fd = odb_pack_keep(name, sizeof(name), pack_data->sha1); if (keep_fd < 0) - die("cannot create keep file"); + die_errno("cannot create keep file"); write_or_die(keep_fd, keep_msg, strlen(keep_msg)); if (close(keep_fd)) - die("failed to write keep file"); + die_errno("failed to write keep file"); snprintf(name, sizeof(name), "%s/pack/pack-%s.pack", get_object_directory(), sha1_to_hex(pack_data->sha1)); diff --git a/hash-object.c b/hash-object.c index 47cf43c3cd..9455dd0709 100644 --- a/hash-object.c +++ b/hash-object.c @@ -29,7 +29,7 @@ static void hash_object(const char *path, const char *type, int write_object, int fd; fd = open(path, O_RDONLY); if (fd < 0) - die("Cannot open %s", path); + die_errno("Cannot open '%s'", path); hash_fd(fd, type, write_object, vpath); } diff --git a/ll-merge.c b/ll-merge.c index 81c02ad053..caf22be927 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -152,7 +152,7 @@ static void create_temp(mmfile_t *src, char *path) strcpy(path, ".merge_file_XXXXXX"); fd = xmkstemp(path); if (write_in_full(fd, src->ptr, src->size) != src->size) - die("unable to write temp-file"); + die_errno("unable to write temp-file"); close(fd); } diff --git a/mktag.c b/mktag.c index 99a356e9ee..a609e3ebd1 100644 --- a/mktag.c +++ b/mktag.c @@ -165,7 +165,7 @@ int main(int argc, char **argv) setup_git_directory(); if (strbuf_read(&buf, 0, 4096) < 0) { - die("could not read from stdin"); + die_errno("could not read from stdin"); } /* Verify it for some basic sanity: it needs to start with diff --git a/read-cache.c b/read-cache.c index f76b5bb2e1..4e3e272ee4 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1265,7 +1265,7 @@ int read_index_from(struct index_state *istate, const char *path) mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); close(fd); if (mmap == MAP_FAILED) - die("unable to map index file"); + die_errno("unable to map index file"); hdr = mmap; if (verify_hdr(hdr, mmap_size) < 0) diff --git a/setup.c b/setup.c index 4d27f28c8f..e3781b656d 100644 --- a/setup.c +++ b/setup.c @@ -327,7 +327,7 @@ const char *setup_git_directory_gently(int *nongit_ok) return NULL; set_git_dir(make_absolute_path(gitdirenv)); if (chdir(work_tree_env) < 0) - die ("Could not chdir to %s", work_tree_env); + die_errno ("Could not chdir to '%s'", work_tree_env); strcat(buffer, "/"); return retval; } @@ -339,7 +339,7 @@ const char *setup_git_directory_gently(int *nongit_ok) } if (!getcwd(cwd, sizeof(cwd)-1)) - die("Unable to read current working directory"); + die_errno("Unable to read current working directory"); ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs); if (ceil_offset < 0 && has_dos_drive_prefix(cwd)) @@ -382,7 +382,7 @@ const char *setup_git_directory_gently(int *nongit_ok) if (offset <= ceil_offset) { if (nongit_ok) { if (chdir(cwd)) - die("Cannot come back to cwd"); + die_errno("Cannot come back to cwd"); *nongit_ok = 1; return NULL; } @@ -493,10 +493,10 @@ const char *setup_git_directory(void) static char buffer[PATH_MAX + 1]; char *rel; if (retval && chdir(retval)) - die ("Could not jump back into original cwd"); + die_errno ("Could not jump back into original cwd"); rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree()); if (rel && *rel && chdir(get_git_work_tree())) - die ("Could not jump to working directory"); + die_errno ("Could not jump to working directory"); return rel && *rel ? strcat(rel, "/") : NULL; } diff --git a/transport.c b/transport.c index 17891d5149..8decd663f1 100644 --- a/transport.c +++ b/transport.c @@ -158,7 +158,7 @@ static struct ref *get_refs_via_rsync(struct transport *transport, int for_push) strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX")); if (!mkdtemp(temp_dir.buf)) - die ("Could not make temporary directory"); + die_errno ("Could not make temporary directory"); temp_dir_len = temp_dir.len; strbuf_addstr(&buf, rsync_url(transport->url)); @@ -321,7 +321,7 @@ static int rsync_transport_push(struct transport *transport, strbuf_addstr(&temp_dir, git_path("rsync-refs-XXXXXX")); if (!mkdtemp(temp_dir.buf)) - die ("Could not make temporary directory"); + die_errno ("Could not make temporary directory"); strbuf_addch(&temp_dir, '/'); if (flags & TRANSPORT_PUSH_ALL) { diff --git a/unpack-file.c b/unpack-file.c index 75cd2f1a6a..ac9cbf7cd8 100644 --- a/unpack-file.c +++ b/unpack-file.c @@ -17,7 +17,7 @@ static char *create_temp_file(unsigned char *sha1) strcpy(path, ".merge_file_XXXXXX"); fd = xmkstemp(path); if (write_in_full(fd, buf, size) != size) - die("unable to write temp-file"); + die_errno("unable to write temp-file"); close(fd); return path; } -- cgit v1.3 From 8cfe5f1cd5dabc3a21bc792327747deefeff6dff Mon Sep 17 00:00:00 2001 From: René Scharfe Date: Thu, 2 Jul 2009 00:01:43 +0200 Subject: userdiff: add xdiff_clear_find_func() xdiff_set_find_func() is used to set user defined regular expressions for finding function signatures. Add xdiff_clear_find_func(), which frees the memory allocated by the former, making the API complete. Also, use the new function in diff.c (the only call site of xdiff_set_find_func()) to clean up after ourselves. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- diff.c | 1 + xdiff-interface.c | 15 +++++++++++++++ xdiff-interface.h | 1 + 3 files changed, 17 insertions(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 43835d756c..892921cdc7 100644 --- a/diff.c +++ b/diff.c @@ -1603,6 +1603,7 @@ static void builtin_diff(const char *name_a, free(mf1.ptr); if (textconv_two) free(mf2.ptr); + xdiff_clear_find_func(&xecfg); } free_ab_and_return: diff --git a/xdiff-interface.c b/xdiff-interface.c index b9b0db8d86..01f14fb50f 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -309,6 +309,21 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags) } } +void xdiff_clear_find_func(xdemitconf_t *xecfg) +{ + if (xecfg->find_func) { + int i; + struct ff_regs *regs = xecfg->find_func_priv; + + for (i = 0; i < regs->nr; i++) + regfree(®s->array[i].re); + free(regs->array); + free(regs); + xecfg->find_func = NULL; + xecfg->find_func_priv = NULL; + } +} + int git_xmerge_style = -1; int git_xmerge_config(const char *var, const char *value, void *cb) diff --git a/xdiff-interface.h b/xdiff-interface.h index 7352b9a9c2..55572c39a1 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -21,6 +21,7 @@ int read_mmfile(mmfile_t *ptr, const char *filename); int buffer_is_binary(const char *ptr, unsigned long size); extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags); +extern void xdiff_clear_find_func(xdemitconf_t *xecfg); extern int git_xmerge_config(const char *var, const char *value, void *cb); extern int git_xmerge_style; -- cgit v1.3 From f245194f9a13d5108c3a59fd4ab1770ae9fd5b65 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 22 May 2009 12:45:29 -0700 Subject: diff: change semantics of "ignore whitespace" options Traditionally, the --ignore-whitespace* options have merely meant to tell the diff output routine that some class of differences are not worth showing in the textual diff output, so that the end user has easier time to review the remaining (presumably more meaningful) changes. These options never affected the outcome of the command, given as the exit status when the --exit-code option was in effect (either directly or indirectly). When you have only whitespace changes, however, you might expect git diff -b --exit-code to report that there is _no_ change with zero exit status. Change the semantics of --ignore-whitespace* options to mean more than "omit showing the difference in text". The exit status, when --exit-code is in effect, is computed by checking if we found any differences at the path level, while diff frontends feed filepairs to the diffcore engine. When "ignore whitespace" options are in effect, we defer this determination until the very end of diffcore transformation. We simply do not know until the textual diff is generated, which comes very late in the pipeline. When --quiet is in effect, various diff frontends optimize by breaking out early from the loop that enumerates the filepairs, when we find the first path level difference; when --ignore-whitespace* is used the above change automatically disables this optimization. Signed-off-by: Junio C Hamano --- diff.c | 34 +++++++++++++++++++++--- diff.h | 1 + t/t4037-whitespace-status.sh | 63 ++++++++++++++++++++++++++++++++++++++++++++ tree-diff.c | 3 ++- 4 files changed, 97 insertions(+), 4 deletions(-) create mode 100755 t/t4037-whitespace-status.sh (limited to 'diff.c') diff --git a/diff.c b/diff.c index cd35e0c2d7..467925d931 100644 --- a/diff.c +++ b/diff.c @@ -2378,6 +2378,20 @@ int diff_setup_done(struct diff_options *options) if (count > 1) die("--name-only, --name-status, --check and -s are mutually exclusive"); + /* + * Most of the time we can say "there are changes" + * only by checking if there are changed paths, but + * --ignore-whitespace* options force us to look + * inside contets. + */ + + if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) || + DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) || + DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL)) + DIFF_OPT_SET(options, DIFF_FROM_CONTENTS); + else + DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS); + if (DIFF_OPT_TST(options, FIND_COPIES_HARDER)) options->detect_rename = DIFF_DETECT_COPY; @@ -3330,6 +3344,18 @@ free_queue: q->nr = q->alloc = 0; if (options->close_file) fclose(options->file); + + /* + * Report the contents level differences with HAS_CHANGES; + * diff_addremove/diff_change does not set the bit when + * DIFF_FROM_CONTENTS is in effect (e.g. with -w). + */ + if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) { + if (options->found_changes) + DIFF_OPT_SET(options, HAS_CHANGES); + else + DIFF_OPT_CLR(options, HAS_CHANGES); + } } static void diffcore_apply_filter(const char *filter) @@ -3466,7 +3492,7 @@ void diffcore_std(struct diff_options *options) diff_resolve_rename_copy(); diffcore_apply_filter(options->filter); - if (diff_queued_diff.nr) + if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) DIFF_OPT_SET(options, HAS_CHANGES); else DIFF_OPT_CLR(options, HAS_CHANGES); @@ -3526,7 +3552,8 @@ void diff_addremove(struct diff_options *options, fill_filespec(two, sha1, mode); diff_queue(&diff_queued_diff, one, two); - DIFF_OPT_SET(options, HAS_CHANGES); + if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) + DIFF_OPT_SET(options, HAS_CHANGES); } void diff_change(struct diff_options *options, @@ -3558,7 +3585,8 @@ void diff_change(struct diff_options *options, fill_filespec(two, new_sha1, new_mode); diff_queue(&diff_queued_diff, one, two); - DIFF_OPT_SET(options, HAS_CHANGES); + if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) + DIFF_OPT_SET(options, HAS_CHANGES); } void diff_unmerge(struct diff_options *options, diff --git a/diff.h b/diff.h index 6616877ee5..538e4f0d8f 100644 --- a/diff.h +++ b/diff.h @@ -66,6 +66,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19) #define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20) #define DIFF_OPT_ALLOW_TEXTCONV (1 << 21) +#define DIFF_OPT_DIFF_FROM_CONTENTS (1 << 22) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) diff --git a/t/t4037-whitespace-status.sh b/t/t4037-whitespace-status.sh new file mode 100755 index 0000000000..a30b03bcf2 --- /dev/null +++ b/t/t4037-whitespace-status.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +test_description='diff --exit-code with whitespace' +. ./test-lib.sh + +test_expect_success setup ' + mkdir a b && + echo >c && + echo >a/d && + echo >b/e && + git add . && + test_tick && + git commit -m initial && + echo " " >a/d && + test_tick && + git commit -a -m second && + echo " " >a/d && + echo " " >b/e && + git add a/d +' + +test_expect_success 'diff-tree --exit-code' ' + test_must_fail git diff --exit-code HEAD^ HEAD && + test_must_fail git diff-tree --exit-code HEAD^ HEAD +' + +test_expect_success 'diff-tree -b --exit-code' ' + git diff -b --exit-code HEAD^ HEAD && + git diff-tree -b -p --exit-code HEAD^ HEAD && + git diff-tree -b --exit-code HEAD^ HEAD +' + +test_expect_success 'diff-index --cached --exit-code' ' + test_must_fail git diff --cached --exit-code HEAD && + test_must_fail git diff-index --cached --exit-code HEAD +' + +test_expect_success 'diff-index -b -p --cached --exit-code' ' + git diff -b --cached --exit-code HEAD && + git diff-index -b -p --cached --exit-code HEAD +' + +test_expect_success 'diff-index --exit-code' ' + test_must_fail git diff --exit-code HEAD && + test_must_fail git diff-index --exit-code HEAD +' + +test_expect_success 'diff-index -b -p --exit-code' ' + git diff -b --exit-code HEAD && + git diff-index -b -p --exit-code HEAD +' + +test_expect_success 'diff-files --exit-code' ' + test_must_fail git diff --exit-code && + test_must_fail git diff-files --exit-code +' + +test_expect_success 'diff-files -b -p --exit-code' ' + git diff -b --exit-code && + git diff-files -b -p --exit-code +' + +test_done diff --git a/tree-diff.c b/tree-diff.c index 0459e54d3d..7c526d33f4 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -286,7 +286,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru int baselen = strlen(base); for (;;) { - if (DIFF_OPT_TST(opt, QUIET) && DIFF_OPT_TST(opt, HAS_CHANGES)) + if (DIFF_OPT_TST(opt, QUIET) && + DIFF_OPT_TST(opt, HAS_CHANGES)) break; if (opt->nr_paths) { skip_uninteresting(t1, base, baselen, opt); -- cgit v1.3 From 90b1994170900514a1ce7a3345e25cb7216915cc Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 23 May 2009 01:15:35 -0700 Subject: diff: Rename QUIET internal option to QUICK The option "QUIET" primarily meant "find if we have _any_ difference as quick as possible and report", which means we often do not even have to look at blobs if we know the trees are different by looking at the higher level (e.g. "diff-tree A B"). As a side effect, because there is no point showing one change that we happened to have found first, it also enables NO_OUTPUT and EXIT_WITH_STATUS options, making the end result look quiet. Rename the internal option to QUICK to reflect this better; it also makes grepping the source tree much easier, as there are other kinds of QUIET option everywhere. Signed-off-by: Junio C Hamano --- builtin-log.c | 2 +- builtin-rev-list.c | 2 +- diff-lib.c | 4 ++-- diff.c | 4 ++-- diff.h | 2 +- revision.c | 2 +- tree-diff.c | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) (limited to 'diff.c') diff --git a/builtin-log.c b/builtin-log.c index 0c2fa0ae2d..7903e5a78f 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -537,7 +537,7 @@ static int reopen_stdout(struct commit *commit, struct rev_info *rev) get_patch_filename(commit, rev->nr, fmt_patch_suffix, &filename); - if (!DIFF_OPT_TST(&rev->diffopt, QUIET)) + if (!DIFF_OPT_TST(&rev->diffopt, QUICK)) fprintf(realstdout, "%s\n", filename.buf + outdir_offset); if (freopen(filename.buf, "w", stdout) == NULL) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 4ba1c12e0b..69753dc206 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -320,7 +320,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) memset(&info, 0, sizeof(info)); info.revs = &revs; - quiet = DIFF_OPT_TST(&revs.diffopt, QUIET); + quiet = DIFF_OPT_TST(&revs.diffopt, QUICK); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; diff --git a/diff-lib.c b/diff-lib.c index ad2a4cde74..b7813af614 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -73,7 +73,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) struct cache_entry *ce = active_cache[i]; int changed; - if (DIFF_OPT_TST(&revs->diffopt, QUIET) && + if (DIFF_OPT_TST(&revs->diffopt, QUICK) && DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) break; @@ -523,7 +523,7 @@ int index_differs_from(const char *def, int diff_flags) init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, def); - DIFF_OPT_SET(&rev.diffopt, QUIET); + DIFF_OPT_SET(&rev.diffopt, QUICK); DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS); rev.diffopt.flags |= diff_flags; run_diff_index(&rev, 1); diff --git a/diff.c b/diff.c index 467925d931..91d6ea21a9 100644 --- a/diff.c +++ b/diff.c @@ -2452,7 +2452,7 @@ int diff_setup_done(struct diff_options *options) * to have found. It does not make sense not to return with * exit code in such a case either. */ - if (DIFF_OPT_TST(options, QUIET)) { + if (DIFF_OPT_TST(options, QUICK)) { options->output_format = DIFF_FORMAT_NO_OUTPUT; DIFF_OPT_SET(options, EXIT_WITH_STATUS); } @@ -2643,7 +2643,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) else if (!strcmp(arg, "--exit-code")) DIFF_OPT_SET(options, EXIT_WITH_STATUS); else if (!strcmp(arg, "--quiet")) - DIFF_OPT_SET(options, QUIET); + DIFF_OPT_SET(options, QUICK); else if (!strcmp(arg, "--ext-diff")) DIFF_OPT_SET(options, ALLOW_EXTERNAL); else if (!strcmp(arg, "--no-ext-diff")) diff --git a/diff.h b/diff.h index 538e4f0d8f..a7e7ccbd42 100644 --- a/diff.h +++ b/diff.h @@ -55,7 +55,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_COLOR_DIFF (1 << 8) #define DIFF_OPT_COLOR_DIFF_WORDS (1 << 9) #define DIFF_OPT_HAS_CHANGES (1 << 10) -#define DIFF_OPT_QUIET (1 << 11) +#define DIFF_OPT_QUICK (1 << 11) #define DIFF_OPT_NO_INDEX (1 << 12) #define DIFF_OPT_ALLOW_EXTERNAL (1 << 13) #define DIFF_OPT_EXIT_WITH_STATUS (1 << 14) diff --git a/revision.c b/revision.c index 9f5dac5f1d..b8afc7c2b5 100644 --- a/revision.c +++ b/revision.c @@ -791,7 +791,7 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->ignore_merges = 1; revs->simplify_history = 1; DIFF_OPT_SET(&revs->pruning, RECURSIVE); - DIFF_OPT_SET(&revs->pruning, QUIET); + DIFF_OPT_SET(&revs->pruning, QUICK); revs->pruning.add_remove = file_add_remove; revs->pruning.change = file_change; revs->lifo = 1; diff --git a/tree-diff.c b/tree-diff.c index 7c526d33f4..7d745b4406 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -286,7 +286,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru int baselen = strlen(base); for (;;) { - if (DIFF_OPT_TST(opt, QUIET) && + if (DIFF_OPT_TST(opt, QUICK) && DIFF_OPT_TST(opt, HAS_CHANGES)) break; if (opt->nr_paths) { -- cgit v1.3 From b4d1690df11ae6ce382b93778616b1a20f1774ff Mon Sep 17 00:00:00 2001 From: Nguyễn Thái Ngọc Duy Date: Thu, 20 Aug 2009 20:46:58 +0700 Subject: Teach Git to respect skip-worktree bit (reading part) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit grep: turn on --cached for files that is marked skip-worktree ls-files: do not check for deleted file that is marked skip-worktree update-index: ignore update request if it's skip-worktree, while still allows removing diff*: skip worktree version Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- builtin-commit.c | 5 ++ builtin-grep.c | 2 +- builtin-ls-files.c | 2 + builtin-update-index.c | 38 +++++---- diff-lib.c | 5 +- diff.c | 2 +- read-cache.c | 8 +- t/t7011-skip-worktree-reading.sh | 163 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 199 insertions(+), 26 deletions(-) create mode 100755 t/t7011-skip-worktree-reading.sh (limited to 'diff.c') diff --git a/builtin-commit.c b/builtin-commit.c index 4bcce06fbf..a0b1fd35cb 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -180,6 +180,11 @@ static void add_remove_files(struct string_list *list) for (i = 0; i < list->nr; i++) { struct stat st; struct string_list_item *p = &(list->items[i]); + int pos = index_name_pos(&the_index, p->string, strlen(p->string)); + struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos]; + + if (ce && ce_skip_worktree(ce)) + continue; if (!lstat(p->string, &st)) { if (add_to_cache(p->string, &st, 0)) diff --git a/builtin-grep.c b/builtin-grep.c index ad0e0a5385..813fe9778a 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -517,7 +517,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached, * are identical, even if worktree file has been modified, so use * cache version instead */ - if (cached || (ce->ce_flags & CE_VALID)) { + if (cached || (ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) { if (ce_stage(ce)) continue; hit |= grep_sha1(opt, ce->sha1, ce->name, 0); diff --git a/builtin-ls-files.c b/builtin-ls-files.c index c1afbad453..ad7e44784f 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -194,6 +194,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) continue; if (ce->ce_flags & CE_UPDATE) continue; + if (ce_skip_worktree(ce)) + continue; err = lstat(ce->name, &st); if (show_deleted && err) show_ce_entry(tag_removed, ce); diff --git a/builtin-update-index.c b/builtin-update-index.c index 5e97d09497..97b9ea61f7 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -172,29 +172,29 @@ static int process_directory(const char *path, int len, struct stat *st) return error("%s: is a directory - add files inside instead", path); } -/* - * Process a regular file - */ -static int process_file(const char *path, int len, struct stat *st) -{ - int pos = cache_name_pos(path, len); - struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos]; - - if (ce && S_ISGITLINK(ce->ce_mode)) - return error("%s is already a gitlink, not replacing", path); - - return add_one_path(ce, path, len, st); -} - static int process_path(const char *path) { - int len; + int pos, len; struct stat st; + struct cache_entry *ce; len = strlen(path); if (has_symlink_leading_path(path, len)) return error("'%s' is beyond a symbolic link", path); + pos = cache_name_pos(path, len); + ce = pos < 0 ? NULL : active_cache[pos]; + if (ce && ce_skip_worktree(ce)) { + /* + * working directory version is assumed "good" + * so updating it does not make sense. + * On the other hand, removing it from index should work + */ + if (allow_remove && remove_file_from_cache(path)) + return error("%s: cannot remove from the index", path); + return 0; + } + /* * First things first: get the stat information, to decide * what to do about the pathname! @@ -205,7 +205,13 @@ static int process_path(const char *path) if (S_ISDIR(st.st_mode)) return process_directory(path, len, &st); - return process_file(path, len, &st); + /* + * Process a regular file + */ + if (ce && S_ISGITLINK(ce->ce_mode)) + return error("%s is already a gitlink, not replacing", path); + + return add_one_path(ce, path, len, &st); } static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, diff --git a/diff-lib.c b/diff-lib.c index 22da66ef14..b0b379d9d2 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -159,7 +159,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) continue; } - if (ce_uptodate(ce)) + if (ce_uptodate(ce) || ce_skip_worktree(ce)) continue; /* If CE_VALID is set, don't look at workdir for file removal */ @@ -339,7 +339,8 @@ static void do_oneway_diff(struct unpack_trees_options *o, int match_missing, cached; /* if the entry is not checked out, don't examine work tree */ - cached = o->index_only || (idx && (idx->ce_flags & CE_VALID)); + cached = o->index_only || + (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx))); /* * Backward compatibility wart - "diff-index -m" does * not mean "do not ignore merges", but "match_missing". diff --git a/diff.c b/diff.c index cd35e0c2d7..3970df4afc 100644 --- a/diff.c +++ b/diff.c @@ -1805,7 +1805,7 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int * If ce is marked as "assume unchanged", there is no * guarantee that work tree matches what we are looking for. */ - if (ce->ce_flags & CE_VALID) + if ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) return 0; /* diff --git a/read-cache.c b/read-cache.c index 4e3e272ee4..5ee7d9da9c 100644 --- a/read-cache.c +++ b/read-cache.c @@ -265,7 +265,7 @@ int ie_match_stat(const struct index_state *istate, * If it's marked as always valid in the index, it's * valid whatever the checked-out copy says. */ - if (!ignore_valid && (ce->ce_flags & CE_VALID)) + if (!ignore_valid && ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))) return 0; /* @@ -1004,11 +1004,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate, if (ce_uptodate(ce)) return ce; - /* - * CE_VALID means the user promised us that the change to - * the work tree does not matter and told us not to worry. - */ - if (!ignore_valid && (ce->ce_flags & CE_VALID)) { + if (!ignore_valid && ((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce))) { ce_mark_uptodate(ce); return ce; } diff --git a/t/t7011-skip-worktree-reading.sh b/t/t7011-skip-worktree-reading.sh new file mode 100755 index 0000000000..e996928de2 --- /dev/null +++ b/t/t7011-skip-worktree-reading.sh @@ -0,0 +1,163 @@ +#!/bin/sh +# +# Copyright (c) 2008 Nguyễn Thái Ngọc Duy +# + +test_description='skip-worktree bit test' + +. ./test-lib.sh + +cat >expect.full <expect.skip < expected && + git ls-files --stage 1 > result && + test_cmp expected result && + test ! -f 1 +} + +setup_dirty() { + git update-index --force-remove 1 && + echo dirty > 1 && + git update-index --add --cacheinfo 100644 $NULL_SHA1 1 && + git update-index --skip-worktree 1 +} + +test_dirty() { + echo "100644 $NULL_SHA1 0 1" > expected && + git ls-files --stage 1 > result && + test_cmp expected result && + echo dirty > expected + test_cmp expected 1 +} + +test_expect_success 'setup' ' + test_commit init && + mkdir sub && + touch ./1 ./2 sub/1 sub/2 && + git add 1 2 sub/1 sub/2 && + git update-index --skip-worktree 1 sub/1 && + git ls-files -t > result && + test_cmp expect.skip result +' + +test_expect_success 'update-index' ' + setup_absent && + git update-index 1 && + test_absent +' + +test_expect_success 'update-index' ' + setup_dirty && + git update-index 1 && + test_dirty +' + +test_expect_success 'update-index --remove' ' + setup_absent && + git update-index --remove 1 && + test -z "$(git ls-files 1)" && + test ! -f 1 +' + +test_expect_success 'update-index --remove' ' + setup_dirty && + git update-index --remove 1 && + test -z "$(git ls-files 1)" && + echo dirty > expected && + test_cmp expected 1 +' + +test_expect_success 'ls-files --delete' ' + setup_absent && + test -z "$(git ls-files -d)" +' + +test_expect_success 'ls-files --delete' ' + setup_dirty && + test -z "$(git ls-files -d)" +' + +test_expect_success 'ls-files --modified' ' + setup_absent && + test -z "$(git ls-files -m)" +' + +test_expect_success 'ls-files --modified' ' + setup_dirty && + test -z "$(git ls-files -m)" +' + +test_expect_success 'grep with skip-worktree file' ' + git update-index --no-skip-worktree 1 && + echo test > 1 && + git update-index 1 && + git update-index --skip-worktree 1 && + rm 1 && + test "$(git grep --no-ext-grep test)" = "1:test" +' + +echo ":000000 100644 $ZERO_SHA0 $NULL_SHA1 A 1" > expected +test_expect_success 'diff-index does not examine skip-worktree absent entries' ' + setup_absent && + git diff-index HEAD -- 1 > result && + test_cmp expected result +' + +test_expect_success 'diff-index does not examine skip-worktree dirty entries' ' + setup_dirty && + git diff-index HEAD -- 1 > result && + test_cmp expected result +' + +test_expect_success 'diff-files does not examine skip-worktree absent entries' ' + setup_absent && + test -z "$(git diff-files -- one)" +' + +test_expect_success 'diff-files does not examine skip-worktree dirty entries' ' + setup_dirty && + test -z "$(git diff-files -- one)" +' + +test_expect_success 'git-rm succeeds on skip-worktree absent entries' ' + setup_absent && + git rm 1 +' + +test_expect_failure 'commit on skip-worktree absent entries' ' + git reset && + setup_absent && + test_must_fail git commit -m null 1 +' + +test_expect_failure 'commit on skip-worktree dirty entries' ' + git reset && + setup_dirty && + test_must_fail git commit -m null 1 +' + +test_done -- cgit v1.3 From 97bf2a08095197f43b20b3bc1124552ae24d71bf Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Sun, 30 Aug 2009 22:27:02 +0200 Subject: diff.c: fix typoes in comments Should be squashed when we reroll 'next' into the main commit. --- diff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 91d6ea21a9..24bd3fce3f 100644 --- a/diff.c +++ b/diff.c @@ -2382,7 +2382,7 @@ int diff_setup_done(struct diff_options *options) * Most of the time we can say "there are changes" * only by checking if there are changed paths, but * --ignore-whitespace* options force us to look - * inside contets. + * inside contents. */ if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) || @@ -3346,7 +3346,7 @@ free_queue: fclose(options->file); /* - * Report the contents level differences with HAS_CHANGES; + * Report the content-level differences with HAS_CHANGES; * diff_addremove/diff_change does not set the bit when * DIFF_FROM_CONTENTS is in effect (e.g. with -w). */ -- cgit v1.3 From eeefa7c90e1b754a2b01d73fd93aaf90afdc4914 Mon Sep 17 00:00:00 2001 From: Brian Gianforcaro Date: Tue, 1 Sep 2009 01:35:10 -0400 Subject: Style fixes, add a space after if/for/while. The majority of code in core git appears to use a single space after if/for/while. This is an attempt to bring more code to this standard. These are entirely cosmetic changes. Signed-off-by: Brian Gianforcaro Signed-off-by: Junio C Hamano --- builtin-blame.c | 2 +- builtin-clone.c | 2 +- builtin-for-each-ref.c | 2 +- builtin-pack-objects.c | 2 +- builtin-remote.c | 4 ++-- builtin-shortlog.c | 2 +- connect.c | 2 +- diff.c | 2 +- pack-redundant.c | 29 ++++++++++++++--------------- remote.c | 2 +- upload-pack.c | 2 +- var.c | 5 ++--- wt-status.c | 2 +- 13 files changed, 28 insertions(+), 30 deletions(-) (limited to 'diff.c') diff --git a/builtin-blame.c b/builtin-blame.c index fd6ca51eeb..7512773b40 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -1348,7 +1348,7 @@ static void get_ac_line(const char *inbuf, const char *what, /* * Now, convert both name and e-mail using mailmap */ - if(map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) { + if (map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) { /* Add a trailing '>' to email, since map_user returns plain emails Note: It already has '<', since we replace from mail+1 */ mailpos = memchr(mail, '\0', mail_len); diff --git a/builtin-clone.c b/builtin-clone.c index 0d2b4a8200..991a7ae92f 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -515,7 +515,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) option_upload_pack); refs = transport_get_remote_refs(transport); - if(refs) + if (refs) transport_fetch_refs(transport, refs); } diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index d7cc8cafbf..a5a83f1469 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -576,7 +576,7 @@ static void populate_value(struct refinfo *ref) if (!prefixcmp(name, "refname")) refname = ref->refname; - else if(!prefixcmp(name, "upstream")) { + else if (!prefixcmp(name, "upstream")) { struct branch *branch; /* only local branches may have an upstream */ if (prefixcmp(ref->refname, "refs/heads/")) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index c4337480fd..c918d4bfc4 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -1808,7 +1808,7 @@ static void prepare_pack(int window, int depth) static int git_pack_config(const char *k, const char *v, void *cb) { - if(!strcmp(k, "pack.window")) { + if (!strcmp(k, "pack.window")) { window = git_config_int(k, v); return 0; } diff --git a/builtin-remote.c b/builtin-remote.c index 008abfe092..0777dd719b 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -385,7 +385,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0); matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"), fetch_map, 1); - for(ref = matches; ref; ref = ref->next) + for (ref = matches; ref; ref = ref->next) string_list_append(abbrev_branch(ref->name), &states->heads); free_refs(fetch_map); @@ -484,7 +484,7 @@ static int read_remote_branches(const char *refname, const char *symref; strbuf_addf(&buf, "refs/remotes/%s", rename->old); - if(!prefixcmp(refname, buf.buf)) { + if (!prefixcmp(refname, buf.buf)) { item = string_list_append(xstrdup(refname), rename->remote_branches); symref = resolve_ref(refname, orig_sha1, 1, &flag); if (flag & REF_ISSYMREF) diff --git a/builtin-shortlog.c b/builtin-shortlog.c index 6a3812ee18..4d4a3c82d6 100644 --- a/builtin-shortlog.c +++ b/builtin-shortlog.c @@ -56,7 +56,7 @@ static void insert_one_record(struct shortlog *log, /* copy author name to namebuf, to support matching on both name and email */ memcpy(namebuf, author, boemail - author); len = boemail - author; - while(len > 0 && isspace(namebuf[len-1])) + while (len > 0 && isspace(namebuf[len-1])) len--; namebuf[len] = 0; diff --git a/connect.c b/connect.c index 76e542776a..7945e38ac1 100644 --- a/connect.c +++ b/connect.c @@ -513,7 +513,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, signal(SIGCHLD, SIG_DFL); host = strstr(url, "://"); - if(host) { + if (host) { *host = '\0'; protocol = get_protocol(url); host += 3; diff --git a/diff.c b/diff.c index cd35e0c2d7..e1be189742 100644 --- a/diff.c +++ b/diff.c @@ -2691,7 +2691,7 @@ static int parse_num(const char **cp_p) num = 0; scale = 1; dot = 0; - for(;;) { + for (;;) { ch = *cp; if ( !dot && ch == '.' ) { scale = 1; diff --git a/pack-redundant.c b/pack-redundant.c index 48a12bc135..69a7ab2e27 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -55,16 +55,15 @@ static inline struct llist_item *llist_item_get(void) } else { int i = 1; new = xmalloc(sizeof(struct llist_item) * BLKSIZE); - for(;i < BLKSIZE; i++) { + for (; i < BLKSIZE; i++) llist_item_put(&new[i]); - } } return new; } static void llist_free(struct llist *list) { - while((list->back = list->front)) { + while ((list->back = list->front)) { list->front = list->front->next; llist_item_put(list->back); } @@ -146,7 +145,7 @@ static inline struct llist_item *llist_insert_sorted_unique(struct llist *list, if (cmp > 0) { /* we insert before this entry */ return llist_insert(list, prev, sha1); } - if(!cmp) { /* already exists */ + if (!cmp) { /* already exists */ return l; } prev = l; @@ -168,7 +167,7 @@ redo_from_start: int cmp = hashcmp(l->sha1, sha1); if (cmp > 0) /* not in list, since sorted */ return prev; - if(!cmp) { /* found */ + if (!cmp) { /* found */ if (prev == NULL) { if (hint != NULL && hint != list->front) { /* we don't know the previous element */ @@ -218,7 +217,7 @@ static inline struct pack_list * pack_list_insert(struct pack_list **pl, static inline size_t pack_list_size(struct pack_list *pl) { size_t ret = 0; - while(pl) { + while (pl) { ret++; pl = pl->next; } @@ -396,7 +395,7 @@ static size_t get_pack_redundancy(struct pack_list *pl) return 0; while ((subset = pl->next)) { - while(subset) { + while (subset) { ret += sizeof_union(pl->pack, subset->pack); subset = subset->next; } @@ -427,7 +426,7 @@ static void minimize(struct pack_list **min) pl = local_packs; while (pl) { - if(pl->unique_objects->size) + if (pl->unique_objects->size) pack_list_insert(&unique, pl); else pack_list_insert(&non_unique, pl); @@ -479,7 +478,7 @@ static void minimize(struct pack_list **min) *min = min_perm; /* add the unique packs to the list */ pl = unique; - while(pl) { + while (pl) { pack_list_insert(min, pl); pl = pl->next; } @@ -516,7 +515,7 @@ static void cmp_local_packs(void) struct pack_list *subset, *pl = local_packs; while ((subset = pl)) { - while((subset = subset->next)) + while ((subset = subset->next)) cmp_two_packs(pl, subset); pl = pl->next; } @@ -608,23 +607,23 @@ int main(int argc, char **argv) for (i = 1; i < argc; i++) { const char *arg = argv[i]; - if(!strcmp(arg, "--")) { + if (!strcmp(arg, "--")) { i++; break; } - if(!strcmp(arg, "--all")) { + if (!strcmp(arg, "--all")) { load_all_packs = 1; continue; } - if(!strcmp(arg, "--verbose")) { + if (!strcmp(arg, "--verbose")) { verbose = 1; continue; } - if(!strcmp(arg, "--alt-odb")) { + if (!strcmp(arg, "--alt-odb")) { alt_odb = 1; continue; } - if(*arg == '-') + if (*arg == '-') usage(pack_redundant_usage); else break; diff --git a/remote.c b/remote.c index c3ada2d72b..4b5b905979 100644 --- a/remote.c +++ b/remote.c @@ -1038,7 +1038,7 @@ static int match_explicit(struct ref *src, struct ref *dst, case 0: if (!memcmp(dst_value, "refs/", 5)) matched_dst = make_linked_ref(dst_value, dst_tail); - else if((dst_guess = guess_ref(dst_value, matched_src))) + else if ((dst_guess = guess_ref(dst_value, matched_src))) matched_dst = make_linked_ref(dst_guess, dst_tail); else error("unable to push to unqualified destination: %s\n" diff --git a/upload-pack.c b/upload-pack.c index 4d8be834ff..dacbc7614b 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -427,7 +427,7 @@ static int get_common_commits(void) save_commit_buffer = 0; - for(;;) { + for (;;) { int len = packet_read_line(0, line, sizeof(line)); reset_timeout(); diff --git a/var.c b/var.c index 7362ed8735..125c0d1676 100644 --- a/var.c +++ b/var.c @@ -21,9 +21,8 @@ static struct git_var git_vars[] = { static void list_vars(void) { struct git_var *ptr; - for(ptr = git_vars; ptr->read; ptr++) { + for (ptr = git_vars; ptr->read; ptr++) printf("%s=%s\n", ptr->name, ptr->read(IDENT_WARN_ON_NO_NAME)); - } } static const char *read_var(const char *var) @@ -31,7 +30,7 @@ static const char *read_var(const char *var) struct git_var *ptr; const char *val; val = NULL; - for(ptr = git_vars; ptr->read; ptr++) { + for (ptr = git_vars; ptr->read; ptr++) { if (strcmp(var, ptr->name) == 0) { val = ptr->read(IDENT_ERROR_ON_NO_NAME); break; diff --git a/wt-status.c b/wt-status.c index 63598ce40c..33954564c6 100644 --- a/wt-status.c +++ b/wt-status.c @@ -326,7 +326,7 @@ static void wt_status_collect_untracked(struct wt_status *s) setup_standard_excludes(&dir); fill_directory(&dir, NULL); - for(i = 0; i < dir.nr; i++) { + for (i = 0; i < dir.nr; i++) { struct dir_entry *ent = dir.entries[i]; if (!cache_name_is_other(ent->name, ent->len)) continue; -- cgit v1.3 From b8d9c1a66b99ad3ca8069add010dafdd1bc6cab8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 3 Sep 2009 23:59:25 -0700 Subject: diff.c: the builtin_diff() deals with only two-file comparison The combined diff is implemented in combine_diff() and fn_out_consume() codepath never has to deal with anything but two-file comparision. Drop nparents from the emit_callback structure and simplify the code. Signed-off-by: Junio C Hamano --- diff.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 6fea3c0347..1eddd590ec 100644 --- a/diff.c +++ b/diff.c @@ -489,7 +489,7 @@ typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); struct emit_callback { struct xdiff_emit_state xm; - int nparents, color_diff; + int color_diff; unsigned ws_rule; sane_truncate_fn truncate; const char **label_path; @@ -549,9 +549,8 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons emit_line(ecbdata->file, set, reset, line, len); else { /* Emit just the prefix, then the rest. */ - emit_line(ecbdata->file, set, reset, line, ecbdata->nparents); - ws_check_emit(line + ecbdata->nparents, - len - ecbdata->nparents, ecbdata->ws_rule, + emit_line(ecbdata->file, set, reset, line, 1); + ws_check_emit(line + 1, len - 1, ecbdata->ws_rule, ecbdata->file, set, reset, ws); } } @@ -576,7 +575,6 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u static void fn_out_consume(void *priv, char *line, unsigned long len) { - int i; int color; struct emit_callback *ecbdata = priv; const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO); @@ -598,13 +596,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } - /* 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; + if (line[0] == '@') { len = sane_truncate_line(ecbdata, line, len); emit_line(ecbdata->file, diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO), @@ -614,15 +606,12 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) return; } - if (len < ecbdata->nparents) { + if (len < 1) { emit_line(ecbdata->file, reset, reset, line, len); return; } color = DIFF_PLAIN; - if (ecbdata->diff_words && ecbdata->nparents != 1) - /* fall back to normal diff */ - free_diff_words_data(ecbdata); if (ecbdata->diff_words) { if (line[0] == '-') { diff_words_append(line, len, @@ -641,13 +630,10 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) emit_line(ecbdata->file, plain, reset, line, len); return; } - for (i = 0; i < ecbdata->nparents && len; i++) { - if (line[i] == '-') - color = DIFF_FILE_OLD; - else if (line[i] == '+') - color = DIFF_FILE_NEW; - } - + if (line[0] == '-') + color = DIFF_FILE_OLD; + else if (line[0] == '+') + color = DIFF_FILE_NEW; if (color != DIFF_FILE_NEW) { emit_line(ecbdata->file, diff_get_color(ecbdata->color_diff, color), -- cgit v1.3 From 5b5061efd88e1d113a4484369dfab654b43364de Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 3 Sep 2009 22:30:27 -0700 Subject: diff --whitespace=warn/error: obey blank-at-eof The "diff --check" code used to conflate trailing-space whitespace error class with this, but now we have a proper separate error class, we should check it under blank-at-eof, not trailing-space. The whitespace error is not about _having_ blank lines at end, but about adding _new_ blank lines. To keep the message consistent with what is given by "git apply", call whitespace_error_string() to generate it, instead of using a hardcoded custom message. Signed-off-by: Junio C Hamano --- diff.c | 10 +++++++--- t/t4015-diff-whitespace.sh | 4 ++-- t/t4019-diff-wserror.sh | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 1eddd590ec..a693d184c9 100644 --- a/diff.c +++ b/diff.c @@ -1650,10 +1650,14 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, ecb.priv = &data; xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); - if ((data.ws_rule & WS_TRAILING_SPACE) && + if ((data.ws_rule & WS_BLANK_AT_EOF) && data.trailing_blanks_start) { - fprintf(o->file, "%s:%d: ends with blank lines.\n", - data.filename, data.trailing_blanks_start); + static char *err; + + if (!err) + err = whitespace_error_string(WS_BLANK_AT_EOF); + fprintf(o->file, "%s:%d: %s\n", + data.filename, data.trailing_blanks_start, err); data.status = 1; /* report errors */ } } diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index b1cbd36d17..a5d4461574 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -335,10 +335,10 @@ test_expect_success 'line numbers in --check output are correct' ' ' -test_expect_success 'checkdiff detects trailing blank lines' ' +test_expect_success 'checkdiff detects new trailing blank lines (1)' ' echo "foo();" >x && echo "" >>x && - git diff --check | grep "ends with blank" + git diff --check | grep "new blank line" ' test_expect_success 'checkdiff allows new blank lines' ' diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 84a1fe3115..1517fff9c6 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -165,7 +165,7 @@ test_expect_success 'trailing empty lines (1)' ' rm -f .gitattributes && test_must_fail git diff --check >output && - grep "ends with blank lines." output && + grep "new blank line at" output && grep "trailing whitespace" output ' -- cgit v1.3 From 467babf8d059caee9587567452fc8b46505b4e67 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 3 Sep 2009 23:39:43 -0700 Subject: diff --whitespace=warn/error: fix blank-at-eof check The "diff --check" logic used to share the same issue as the one fixed for "git apply" earlier in this series, in that a patch that adds new blank lines at end could appear as @@ -l,5 +m,7 @@$ _context$ _context$ -deleted$ +$ +$ +$ _$ _$ where _ stands for SP and $ shows a end-of-line. Instead of looking at each line in the patch in the callback, simply count the blank lines from the end in two versions, and notice the presence of new ones. Signed-off-by: Junio C Hamano --- diff.c | 64 ++++++++++++++++++++++++++++++++++------------ t/t4015-diff-whitespace.sh | 7 +++++ 2 files changed, 55 insertions(+), 16 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index a693d184c9..c19c4760fe 100644 --- a/diff.c +++ b/diff.c @@ -1149,7 +1149,6 @@ struct checkdiff_t { struct diff_options *o; unsigned ws_rule; unsigned status; - int trailing_blanks_start; }; static int is_conflict_marker(const char *line, unsigned long len) @@ -1193,10 +1192,6 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) if (line[0] == '+') { unsigned bad; data->lineno++; - if (!ws_blank_line(line + 1, len - 1, data->ws_rule)) - data->trailing_blanks_start = 0; - else if (!data->trailing_blanks_start) - data->trailing_blanks_start = data->lineno; if (is_conflict_marker(line + 1, len - 1)) { data->status |= 1; fprintf(data->o->file, @@ -1216,14 +1211,12 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len) data->o->file, set, reset, ws); } else if (line[0] == ' ') { data->lineno++; - data->trailing_blanks_start = 0; } else if (line[0] == '@') { char *plus = strchr(line, '+'); if (plus) data->lineno = strtol(plus, NULL, 10) - 1; else die("invalid diff"); - data->trailing_blanks_start = 0; } } @@ -1437,6 +1430,44 @@ static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_fi return NULL; } +static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) +{ + char *ptr = mf->ptr; + long size = mf->size; + int cnt = 0; + + if (!size) + return cnt; + ptr += size - 1; /* pointing at the very end */ + if (*ptr != '\n') + ; /* incomplete line */ + else + ptr--; /* skip the last LF */ + while (mf->ptr < ptr) { + char *prev_eol; + for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--) + if (*prev_eol == '\n') + break; + if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule)) + break; + cnt++; + ptr = prev_eol - 1; + } + return cnt; +} + +static int adds_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, unsigned ws_rule) +{ + int l1, l2, at; + l1 = count_trailing_blank(mf1, ws_rule); + l2 = count_trailing_blank(mf2, ws_rule); + if (l2 <= l1) + return 0; + /* starting where? */ + at = count_lines(mf1->ptr, mf1->size); + return (at - l1) + 1; /* the line number counts from 1 */ +} + static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -1650,15 +1681,16 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, ecb.priv = &data; xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); - if ((data.ws_rule & WS_BLANK_AT_EOF) && - data.trailing_blanks_start) { - static char *err; - - if (!err) - err = whitespace_error_string(WS_BLANK_AT_EOF); - fprintf(o->file, "%s:%d: %s\n", - data.filename, data.trailing_blanks_start, err); - data.status = 1; /* report errors */ + if (data.ws_rule & WS_BLANK_AT_EOF) { + int blank_at_eof = adds_blank_at_eof(&mf1, &mf2, data.ws_rule); + if (blank_at_eof) { + static char *err; + if (!err) + err = whitespace_error_string(WS_BLANK_AT_EOF); + fprintf(o->file, "%s:%d: %s.\n", + data.filename, blank_at_eof, err); + data.status = 1; /* report errors */ + } } } free_and_return: diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index a5d4461574..e0b481d42b 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -341,6 +341,13 @@ test_expect_success 'checkdiff detects new trailing blank lines (1)' ' git diff --check | grep "new blank line" ' +test_expect_success 'checkdiff detects new trailing blank lines (2)' ' + { echo a; echo b; echo; echo; } >x && + git add x && + { echo a; echo; echo; echo; echo; } >x && + git diff --check | grep "new blank line" +' + test_expect_success 'checkdiff allows new blank lines' ' git checkout x && mv x y && -- cgit v1.3 From 690ed8436326484fe7e3f4deac4cffd780c7d630 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 4 Sep 2009 00:41:15 -0700 Subject: diff --color: color blank-at-eof Since the coloring logic processed the patch output one line at a time, we couldn't easily color code the new blank lines at the end of file. Reuse the adds_blank_at_eof() function to find where the runs of such blank lines start, keep track of the line number in the preimage while processing the patch output one line at a time, and paint the new blank lines that appear after that line to implement this. Signed-off-by: Junio C Hamano --- diff.c | 37 +++++++++++++++++++++++++++---------- t/t4019-diff-wserror.sh | 9 +++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index c19c4760fe..2b285b8ce9 100644 --- a/diff.c +++ b/diff.c @@ -491,6 +491,8 @@ struct emit_callback { struct xdiff_emit_state xm; int color_diff; unsigned ws_rule; + int blank_at_eof; + int lno_in_preimage; sane_truncate_fn truncate; const char **label_path; struct diff_words_data *diff_words; @@ -547,6 +549,12 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons if (!*ws) emit_line(ecbdata->file, set, reset, line, len); + else if ((ecbdata->ws_rule & WS_BLANK_AT_EOF) && + ecbdata->blank_at_eof && + (ecbdata->blank_at_eof <= ecbdata->lno_in_preimage) && + ws_blank_line(line + 1, len - 1, ecbdata->ws_rule)) + /* Blank line at EOF */ + emit_line(ecbdata->file, ws, reset, line, len); else { /* Emit just the prefix, then the rest. */ emit_line(ecbdata->file, set, reset, line, 1); @@ -573,9 +581,16 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u return allot - l; } +static int find_preimage_lno(const char *line) +{ + char *p = strchr(line, '-'); + if (!p) + return 0; /* should not happen */ + return strtol(p+1, NULL, 10); +} + static void fn_out_consume(void *priv, char *line, unsigned long len) { - int color; struct emit_callback *ecbdata = priv; const char *meta = diff_get_color(ecbdata->color_diff, DIFF_METAINFO); const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN); @@ -598,6 +613,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) if (line[0] == '@') { len = sane_truncate_line(ecbdata, line, len); + ecbdata->lno_in_preimage = find_preimage_lno(line); emit_line(ecbdata->file, diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO), reset, line, len); @@ -611,7 +627,6 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) return; } - color = DIFF_PLAIN; if (ecbdata->diff_words) { if (line[0] == '-') { diff_words_append(line, len, @@ -630,14 +645,13 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) emit_line(ecbdata->file, plain, reset, line, len); return; } - if (line[0] == '-') - color = DIFF_FILE_OLD; - else if (line[0] == '+') - color = DIFF_FILE_NEW; - if (color != DIFF_FILE_NEW) { - emit_line(ecbdata->file, - diff_get_color(ecbdata->color_diff, color), - reset, line, len); + + if (line[0] != '+') { + const char *color = + diff_get_color(ecbdata->color_diff, + line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN); + ecbdata->lno_in_preimage++; + emit_line(ecbdata->file, color, reset, line, len); return; } emit_add_line(reset, ecbdata, line, len); @@ -1557,6 +1571,9 @@ static void builtin_diff(const char *name_a, ecbdata.color_diff = DIFF_OPT_TST(o, COLOR_DIFF); ecbdata.found_changesp = &o->found_changes; ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); + if (ecbdata.ws_rule & WS_BLANK_AT_EOF) + ecbdata.blank_at_eof = + adds_blank_at_eof(&mf1, &mf2, ecbdata.ws_rule); ecbdata.file = o->file; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 1517fff9c6..1e75f1a110 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -190,4 +190,13 @@ test_expect_success 'do not color trailing cr in context' ' ' +test_expect_success 'color new trailing blank lines' ' + { echo a; echo b; echo; echo; } >x && + git add x && + { echo a; echo; echo; echo; echo; } >x && + git diff --color x >output && + cnt=$(grep "${blue_grep}" output | wc -l) && + test $cnt = 2 +' + test_done -- cgit v1.3 From d68fe26f3e03b230ac9bbbcf002a9acdc4bebde9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 14 Sep 2009 22:05:57 -0700 Subject: diff --whitespace: fix blank lines at end The earlier logic tried to colour any and all blank lines that were added beyond the last blank line in the original, but this was very wrong. If you added 96 blank lines, a non-blank line, and then 3 blank lines at the end, only the last 3 lines should trigger the error, not the earlier 96 blank lines. We need to also make sure that the lines are after the last non-blank line in the postimage as well before deciding to paint them. Signed-off-by: Junio C Hamano --- diff.c | 74 +++++++++++++++++++++++++++++++++++-------------- t/t4019-diff-wserror.sh | 2 +- 2 files changed, 54 insertions(+), 22 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 2b285b8ce9..63a3bfc333 100644 --- a/diff.c +++ b/diff.c @@ -491,8 +491,10 @@ struct emit_callback { struct xdiff_emit_state xm; int color_diff; unsigned ws_rule; - int blank_at_eof; + int blank_at_eof_in_preimage; + int blank_at_eof_in_postimage; int lno_in_preimage; + int lno_in_postimage; sane_truncate_fn truncate; const char **label_path; struct diff_words_data *diff_words; @@ -542,6 +544,17 @@ static void emit_line(FILE *file, const char *set, const char *reset, const char fputc('\n', file); } +static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) +{ + if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) && + ecbdata->blank_at_eof_in_preimage && + ecbdata->blank_at_eof_in_postimage && + ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage && + ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage)) + return 0; + return ws_blank_line(line + 1, len - 1, ecbdata->ws_rule); +} + static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) { const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); @@ -549,11 +562,8 @@ static void emit_add_line(const char *reset, struct emit_callback *ecbdata, cons if (!*ws) emit_line(ecbdata->file, set, reset, line, len); - else if ((ecbdata->ws_rule & WS_BLANK_AT_EOF) && - ecbdata->blank_at_eof && - (ecbdata->blank_at_eof <= ecbdata->lno_in_preimage) && - ws_blank_line(line + 1, len - 1, ecbdata->ws_rule)) - /* Blank line at EOF */ + else if (new_blank_line_at_eof(ecbdata, line, len)) + /* Blank line at EOF - paint '+' as well */ emit_line(ecbdata->file, ws, reset, line, len); else { /* Emit just the prefix, then the rest. */ @@ -581,12 +591,19 @@ static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, u return allot - l; } -static int find_preimage_lno(const char *line) +static void find_lno(const char *line, struct emit_callback *ecbdata) { - char *p = strchr(line, '-'); + const char *p; + ecbdata->lno_in_preimage = 0; + ecbdata->lno_in_postimage = 0; + p = strchr(line, '-'); if (!p) - return 0; /* should not happen */ - return strtol(p+1, NULL, 10); + return; /* cannot happen */ + ecbdata->lno_in_preimage = strtol(p + 1, NULL, 10); + p = strchr(p, '+'); + if (!p) + return; /* cannot happen */ + ecbdata->lno_in_postimage = strtol(p + 1, NULL, 10); } static void fn_out_consume(void *priv, char *line, unsigned long len) @@ -613,7 +630,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) if (line[0] == '@') { len = sane_truncate_line(ecbdata, line, len); - ecbdata->lno_in_preimage = find_preimage_lno(line); + find_lno(line, ecbdata); emit_line(ecbdata->file, diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO), reset, line, len); @@ -651,10 +668,13 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) diff_get_color(ecbdata->color_diff, line[0] == '-' ? DIFF_FILE_OLD : DIFF_PLAIN); ecbdata->lno_in_preimage++; + if (line[0] == ' ') + ecbdata->lno_in_postimage++; emit_line(ecbdata->file, color, reset, line, len); - return; + } else { + ecbdata->lno_in_postimage++; + emit_add_line(reset, ecbdata, line, len); } - emit_add_line(reset, ecbdata, line, len); } static char *pprint_rename(const char *a, const char *b) @@ -1470,16 +1490,23 @@ static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) return cnt; } -static int adds_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, unsigned ws_rule) +static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, + struct emit_callback *ecbdata) { int l1, l2, at; + unsigned ws_rule = ecbdata->ws_rule; l1 = count_trailing_blank(mf1, ws_rule); l2 = count_trailing_blank(mf2, ws_rule); - if (l2 <= l1) - return 0; - /* starting where? */ + if (l2 <= l1) { + ecbdata->blank_at_eof_in_preimage = 0; + ecbdata->blank_at_eof_in_postimage = 0; + return; + } at = count_lines(mf1->ptr, mf1->size); - return (at - l1) + 1; /* the line number counts from 1 */ + ecbdata->blank_at_eof_in_preimage = (at - l1) + 1; + + at = count_lines(mf2->ptr, mf2->size); + ecbdata->blank_at_eof_in_postimage = (at - l2) + 1; } static void builtin_diff(const char *name_a, @@ -1572,8 +1599,7 @@ static void builtin_diff(const char *name_a, ecbdata.found_changesp = &o->found_changes; ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); if (ecbdata.ws_rule & WS_BLANK_AT_EOF) - ecbdata.blank_at_eof = - adds_blank_at_eof(&mf1, &mf2, ecbdata.ws_rule); + check_blank_at_eof(&mf1, &mf2, &ecbdata); ecbdata.file = o->file; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; @@ -1699,7 +1725,13 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); if (data.ws_rule & WS_BLANK_AT_EOF) { - int blank_at_eof = adds_blank_at_eof(&mf1, &mf2, data.ws_rule); + struct emit_callback ecbdata; + int blank_at_eof; + + ecbdata.ws_rule = data.ws_rule; + check_blank_at_eof(&mf1, &mf2, &ecbdata); + blank_at_eof = ecbdata.blank_at_eof_in_preimage; + if (blank_at_eof) { static char *err; if (!err) diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 1e75f1a110..3a3663fbcb 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -193,7 +193,7 @@ test_expect_success 'do not color trailing cr in context' ' test_expect_success 'color new trailing blank lines' ' { echo a; echo b; echo; echo; } >x && git add x && - { echo a; echo; echo; echo; echo; } >x && + { echo a; echo; echo; echo; echo c; echo; echo; echo; echo; } >x && git diff --color x >output && cnt=$(grep "${blue_grep}" output | wc -l) && test $cnt = 2 -- cgit v1.3 From 6957eb9a39cc765862e125edeef0dd70f359cff1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 14 Sep 2009 18:44:01 -0700 Subject: diff.c: shuffling code around Move function, type, and structure definitions for fill_mmfile(), count_trailing_blank(), check_blank_at_eof(), emit_line(), new_blank_line_at_eof(), emit_add_line(), sane_truncate_fn, and emit_callback up in the file, so that they can be refactored into helper functions and reused by codepath for emitting rewrite patches. This only moves the lines around to make the next two patches easier to read. Signed-off-by: Junio C Hamano --- diff.c | 250 ++++++++++++++++++++++++++++++++--------------------------------- 1 file changed, 125 insertions(+), 125 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 63a3bfc333..75489665ba 100644 --- a/diff.c +++ b/diff.c @@ -241,6 +241,23 @@ static struct diff_tempfile { char tmp_path[PATH_MAX]; } diff_temp[2]; +typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); + +struct emit_callback { + struct xdiff_emit_state xm; + int color_diff; + unsigned ws_rule; + int blank_at_eof_in_preimage; + int blank_at_eof_in_postimage; + int lno_in_preimage; + int lno_in_postimage; + sane_truncate_fn truncate; + const char **label_path; + struct diff_words_data *diff_words; + int *found_changesp; + FILE *file; +}; + static int count_lines(const char *data, int size) { int count, ch, completely_empty = 1, nl_just_seen = 0; @@ -301,6 +318,114 @@ static void copy_file_with_prefix(FILE *file, fprintf(file, "%s\n\\ No newline at end of file\n", reset); } +static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) +{ + if (!DIFF_FILE_VALID(one)) { + mf->ptr = (char *)""; /* does not matter */ + mf->size = 0; + return 0; + } + else if (diff_populate_filespec(one, 0)) + return -1; + mf->ptr = one->data; + mf->size = one->size; + return 0; +} + +static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) +{ + char *ptr = mf->ptr; + long size = mf->size; + int cnt = 0; + + if (!size) + return cnt; + ptr += size - 1; /* pointing at the very end */ + if (*ptr != '\n') + ; /* incomplete line */ + else + ptr--; /* skip the last LF */ + while (mf->ptr < ptr) { + char *prev_eol; + for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--) + if (*prev_eol == '\n') + break; + if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule)) + break; + cnt++; + ptr = prev_eol - 1; + } + return cnt; +} + +static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, + struct emit_callback *ecbdata) +{ + int l1, l2, at; + unsigned ws_rule = ecbdata->ws_rule; + l1 = count_trailing_blank(mf1, ws_rule); + l2 = count_trailing_blank(mf2, ws_rule); + if (l2 <= l1) { + ecbdata->blank_at_eof_in_preimage = 0; + ecbdata->blank_at_eof_in_postimage = 0; + return; + } + at = count_lines(mf1->ptr, mf1->size); + ecbdata->blank_at_eof_in_preimage = (at - l1) + 1; + + at = count_lines(mf2->ptr, mf2->size); + ecbdata->blank_at_eof_in_postimage = (at - l2) + 1; +} + +static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) +{ + int has_trailing_newline, has_trailing_carriage_return; + + has_trailing_newline = (len > 0 && line[len-1] == '\n'); + if (has_trailing_newline) + len--; + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; + + fputs(set, file); + fwrite(line, len, 1, file); + fputs(reset, file); + if (has_trailing_carriage_return) + fputc('\r', file); + if (has_trailing_newline) + fputc('\n', file); +} + +static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) +{ + if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) && + ecbdata->blank_at_eof_in_preimage && + ecbdata->blank_at_eof_in_postimage && + ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage && + ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage)) + return 0; + return ws_blank_line(line + 1, len - 1, ecbdata->ws_rule); +} + +static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) +{ + const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); + const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); + + if (!*ws) + emit_line(ecbdata->file, set, reset, line, len); + else if (new_blank_line_at_eof(ecbdata, line, len)) + /* Blank line at EOF - paint '+' as well */ + emit_line(ecbdata->file, ws, reset, line, len); + else { + /* Emit just the prefix, then the rest. */ + emit_line(ecbdata->file, set, reset, line, 1); + ws_check_emit(line + 1, len - 1, ecbdata->ws_rule, + ecbdata->file, set, reset, ws); + } +} + static void emit_rewrite_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -345,20 +470,6 @@ static void emit_rewrite_diff(const char *name_a, copy_file_with_prefix(o->file, '+', two->data, two->size, new, reset); } -static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) -{ - if (!DIFF_FILE_VALID(one)) { - mf->ptr = (char *)""; /* does not matter */ - mf->size = 0; - return 0; - } - else if (diff_populate_filespec(one, 0)) - return -1; - mf->ptr = one->data; - mf->size = one->size; - return 0; -} - struct diff_words_buffer { mmfile_t text; long alloc; @@ -485,23 +596,6 @@ static void diff_words_show(struct diff_words_data *diff_words) } } -typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); - -struct emit_callback { - struct xdiff_emit_state xm; - int color_diff; - unsigned ws_rule; - int blank_at_eof_in_preimage; - int blank_at_eof_in_postimage; - int lno_in_preimage; - int lno_in_postimage; - sane_truncate_fn truncate; - const char **label_path; - struct diff_words_data *diff_words; - int *found_changesp; - FILE *file; -}; - static void free_diff_words_data(struct emit_callback *ecbdata) { if (ecbdata->diff_words) { @@ -524,55 +618,6 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) return ""; } -static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) -{ - int has_trailing_newline, has_trailing_carriage_return; - - has_trailing_newline = (len > 0 && line[len-1] == '\n'); - if (has_trailing_newline) - len--; - has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); - if (has_trailing_carriage_return) - len--; - - fputs(set, file); - fwrite(line, len, 1, file); - fputs(reset, file); - if (has_trailing_carriage_return) - fputc('\r', file); - if (has_trailing_newline) - fputc('\n', file); -} - -static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) -{ - if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) && - ecbdata->blank_at_eof_in_preimage && - ecbdata->blank_at_eof_in_postimage && - ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage && - ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage)) - return 0; - return ws_blank_line(line + 1, len - 1, ecbdata->ws_rule); -} - -static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) -{ - const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); - const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); - - if (!*ws) - emit_line(ecbdata->file, set, reset, line, len); - else if (new_blank_line_at_eof(ecbdata, line, len)) - /* Blank line at EOF - paint '+' as well */ - emit_line(ecbdata->file, ws, reset, line, len); - else { - /* Emit just the prefix, then the rest. */ - emit_line(ecbdata->file, set, reset, line, 1); - ws_check_emit(line + 1, len - 1, ecbdata->ws_rule, - ecbdata->file, set, reset, ws); - } -} - static unsigned long sane_truncate_line(struct emit_callback *ecb, char *line, unsigned long len) { const char *cp; @@ -1464,51 +1509,6 @@ static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_fi return NULL; } -static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) -{ - char *ptr = mf->ptr; - long size = mf->size; - int cnt = 0; - - if (!size) - return cnt; - ptr += size - 1; /* pointing at the very end */ - if (*ptr != '\n') - ; /* incomplete line */ - else - ptr--; /* skip the last LF */ - while (mf->ptr < ptr) { - char *prev_eol; - for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--) - if (*prev_eol == '\n') - break; - if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule)) - break; - cnt++; - ptr = prev_eol - 1; - } - return cnt; -} - -static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, - struct emit_callback *ecbdata) -{ - int l1, l2, at; - unsigned ws_rule = ecbdata->ws_rule; - l1 = count_trailing_blank(mf1, ws_rule); - l2 = count_trailing_blank(mf2, ws_rule); - if (l2 <= l1) { - ecbdata->blank_at_eof_in_preimage = 0; - ecbdata->blank_at_eof_in_postimage = 0; - return; - } - at = count_lines(mf1->ptr, mf1->size); - ecbdata->blank_at_eof_in_preimage = (at - l1) + 1; - - at = count_lines(mf2->ptr, mf2->size); - ecbdata->blank_at_eof_in_postimage = (at - l2) + 1; -} - static void builtin_diff(const char *name_a, const char *name_b, struct diff_filespec *one, -- cgit v1.3 From 250f79930d84af54dce15320914ea911d58dd8ca Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 14 Sep 2009 18:44:01 -0700 Subject: diff.c: split emit_line() from the first char and the rest of the line A new helper function emit_line_0() takes the first line of diff output (typically "-", " ", or "+") separately from the remainder of the line. No other functional changes. This change will make it easier to reuse the logic when emitting the rewrite diff, as we do not want to copy a line only to add "+"/"-"/" " immediately before its first character when we produce rewrite diff output. Signed-off-by: Junio C Hamano --- diff.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 75489665ba..e4aaebf0d0 100644 --- a/diff.c +++ b/diff.c @@ -377,18 +377,31 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2, ecbdata->blank_at_eof_in_postimage = (at - l2) + 1; } -static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) +static void emit_line_0(FILE *file, const char *set, const char *reset, + int first, const char *line, int len) { int has_trailing_newline, has_trailing_carriage_return; + int nofirst; - has_trailing_newline = (len > 0 && line[len-1] == '\n'); - if (has_trailing_newline) - len--; - has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); - if (has_trailing_carriage_return) - len--; + if (len == 0) { + has_trailing_newline = (first == '\n'); + has_trailing_carriage_return = (!has_trailing_newline && + (first == '\r')); + nofirst = has_trailing_newline || has_trailing_carriage_return; + } else { + has_trailing_newline = (len > 0 && line[len-1] == '\n'); + if (has_trailing_newline) + len--; + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; + nofirst = 0; + } fputs(set, file); + + if (!nofirst) + fputc(first, file); fwrite(line, len, 1, file); fputs(reset, file); if (has_trailing_carriage_return) @@ -397,6 +410,12 @@ static void emit_line(FILE *file, const char *set, const char *reset, const char fputc('\n', file); } +static void emit_line(FILE *file, const char *set, const char *reset, + const char *line, int len) +{ + emit_line_0(file, set, reset, line[0], line+1, len-1); +} + static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line, int len) { if (!((ecbdata->ws_rule & WS_BLANK_AT_EOF) && -- cgit v1.3 From 018cff70462eb59779c96a383531c4440fb35b9c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 14 Sep 2009 18:44:01 -0700 Subject: diff.c: emit_add_line() takes only the rest of the line As the first character on the line that is fed to this function is always "+", it is pointless to send that along with the rest of the line. This change will make it easier to reuse the logic when emitting the rewrite diff, as we do not want to copy a line only to add "+"/"-"/" " immediately before its first character when we produce rewrite diff output. Signed-off-by: Junio C Hamano --- diff.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index e4aaebf0d0..07cf04365c 100644 --- a/diff.c +++ b/diff.c @@ -424,23 +424,25 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage && ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage)) return 0; - return ws_blank_line(line + 1, len - 1, ecbdata->ws_rule); + return ws_blank_line(line, len, ecbdata->ws_rule); } -static void emit_add_line(const char *reset, struct emit_callback *ecbdata, const char *line, int len) +static void emit_add_line(const char *reset, + struct emit_callback *ecbdata, + const char *line, int len) { const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); if (!*ws) - emit_line(ecbdata->file, set, reset, line, len); + emit_line_0(ecbdata->file, set, reset, '+', line, len); else if (new_blank_line_at_eof(ecbdata, line, len)) /* Blank line at EOF - paint '+' as well */ - emit_line(ecbdata->file, ws, reset, line, len); + emit_line_0(ecbdata->file, ws, reset, '+', line, len); else { /* Emit just the prefix, then the rest. */ - emit_line(ecbdata->file, set, reset, line, 1); - ws_check_emit(line + 1, len - 1, ecbdata->ws_rule, + emit_line_0(ecbdata->file, set, reset, '+', "", 0); + ws_check_emit(line, len, ecbdata->ws_rule, ecbdata->file, set, reset, ws); } } @@ -737,7 +739,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) emit_line(ecbdata->file, color, reset, line, len); } else { ecbdata->lno_in_postimage++; - emit_add_line(reset, ecbdata, line, len); + emit_add_line(reset, ecbdata, line + 1, len - 1); } } -- cgit v1.3 From 7f7ee2ff2dfbb8435a4b46750f573ef0f7d0b853 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 14 Sep 2009 18:44:01 -0700 Subject: diff -B: colour whitespace errors We used to send the old and new contents more or less straight out to the output with only the original "old is red, new is green" colouring. Now all the necessary support routines have been prepared, call them with a line of data at a time from the output code and have them check and color whitespace errors in exactly the same way as they are called from the low level diff callback routines. Signed-off-by: Junio C Hamano --- diff.c | 75 +++++++++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 26 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 07cf04365c..8414478032 100644 --- a/diff.c +++ b/diff.c @@ -296,28 +296,6 @@ static void print_line_count(FILE *file, int count) } } -static void copy_file_with_prefix(FILE *file, - int prefix, const char *data, int size, - const char *set, const char *reset) -{ - int ch, nl_just_seen = 1; - while (0 < size--) { - ch = *data++; - if (nl_just_seen) { - fputs(set, file); - putc(prefix, file); - } - if (ch == '\n') { - nl_just_seen = 1; - fputs(reset, file); - } else - nl_just_seen = 0; - putc(ch, file); - } - if (!nl_just_seen) - fprintf(file, "%s\n\\ No newline at end of file\n", reset); -} - static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one) { if (!DIFF_FILE_VALID(one)) { @@ -447,6 +425,38 @@ static void emit_add_line(const char *reset, } } +static void emit_rewrite_lines(struct emit_callback *ecb, + int prefix, const char *data, int size) +{ + const char *endp = NULL; + static const char *nneof = " No newline at end of file\n"; + const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD); + const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET); + + while (0 < size) { + int len; + + endp = memchr(data, '\n', size); + len = endp ? (endp - data + 1) : size; + if (prefix != '+') { + ecb->lno_in_preimage++; + emit_line_0(ecb->file, old, reset, '-', + data, len); + } else { + ecb->lno_in_postimage++; + emit_add_line(reset, ecb, data, len); + } + size -= len; + data += len; + } + if (!endp) { + const char *plain = diff_get_color(ecb->color_diff, + DIFF_PLAIN); + emit_line_0(ecb->file, plain, reset, '\\', + nneof, strlen(nneof)); + } +} + static void emit_rewrite_diff(const char *name_a, const char *name_b, struct diff_filespec *one, @@ -458,10 +468,23 @@ static void emit_rewrite_diff(const char *name_a, const char *name_a_tab, *name_b_tab; const char *metainfo = diff_get_color(color_diff, DIFF_METAINFO); const char *fraginfo = diff_get_color(color_diff, DIFF_FRAGINFO); - const char *old = diff_get_color(color_diff, DIFF_FILE_OLD); - const char *new = diff_get_color(color_diff, DIFF_FILE_NEW); const char *reset = diff_get_color(color_diff, DIFF_RESET); static struct strbuf a_name = STRBUF_INIT, b_name = STRBUF_INIT; + struct emit_callback ecbdata; + + memset(&ecbdata, 0, sizeof(ecbdata)); + ecbdata.color_diff = color_diff; + ecbdata.found_changesp = &o->found_changes; + ecbdata.ws_rule = whitespace_rule(name_b ? name_b : name_a); + ecbdata.file = o->file; + if (ecbdata.ws_rule & WS_BLANK_AT_EOF) { + mmfile_t mf1, mf2; + fill_mmfile(&mf1, one); + fill_mmfile(&mf2, two); + check_blank_at_eof(&mf1, &mf2, &ecbdata); + } + ecbdata.lno_in_preimage = 1; + ecbdata.lno_in_postimage = 1; name_a += (*name_a == '/'); name_b += (*name_b == '/'); @@ -486,9 +509,9 @@ static void emit_rewrite_diff(const char *name_a, print_line_count(o->file, lc_b); fprintf(o->file, " @@%s\n", reset); if (lc_a) - copy_file_with_prefix(o->file, '-', one->data, one->size, old, reset); + emit_rewrite_lines(&ecbdata, '-', one->data, one->size); if (lc_b) - copy_file_with_prefix(o->file, '+', two->data, two->size, new, reset); + emit_rewrite_lines(&ecbdata, '+', two->data, two->size); } struct diff_words_buffer { -- cgit v1.3 From 2775d92c53d7b00758fa98e4ad8bce1e59445b05 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Sun, 11 Oct 2009 23:46:11 +0300 Subject: diff.c: stylefix Essentially; s/type* /type */ as per the coding guidelines. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index e1be189742..b39c1b6f7f 100644 --- a/diff.c +++ b/diff.c @@ -999,7 +999,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) total_files, adds, dels); } -static void show_shortstats(struct diffstat_t* data, struct diff_options *options) +static void show_shortstats(struct diffstat_t *data, struct diff_options *options) { int i, adds = 0, dels = 0, total_files = data->nr; -- cgit v1.3 From 752c0c24926aacbceca0d27de6ad22cbb7dd0709 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Mon, 19 Oct 2009 14:38:32 +0200 Subject: Add the --submodule option to the diff option family When you use the option --submodule=log you can see the submodule summaries inlined in the diff, instead of not-quite-helpful SHA-1 pairs. The format imitates what "git submodule summary" shows. To do that, /.git/objects/ is added to the alternate object databases (if that directory exists). This option was requested by Jens Lehmann at the GitTogether in Berlin. Signed-off-by: Johannes Schindelin Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- Documentation/diff-options.txt | 7 +++ Makefile | 2 + diff.c | 18 +++++++ diff.h | 3 ++ submodule.c | 113 +++++++++++++++++++++++++++++++++++++++++ submodule.h | 8 +++ 6 files changed, 151 insertions(+) create mode 100644 submodule.c create mode 100644 submodule.h (limited to 'diff.c') diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 9276faeb11..e26b84706f 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -87,6 +87,13 @@ endif::git-format-patch[] Show only names and status of changed files. See the description of the `--diff-filter` option on what the status letters mean. +--submodule[=]:: + Chose the output format for submodule differences. can be one of + 'short' and 'log'. 'short' just shows pairs of commit names, this format + is used when this option is not given. 'log' is the default value for this + option and lists the commits in that commit range like the 'summary' + option of linkgit:git-submodule[1] does. + --color:: Show colored diff. diff --git a/Makefile b/Makefile index 12defd4c97..efade29ea8 100644 --- a/Makefile +++ b/Makefile @@ -448,6 +448,7 @@ LIB_H += sideband.h LIB_H += sigchain.h LIB_H += strbuf.h LIB_H += string-list.h +LIB_H += submodule.h LIB_H += tag.h LIB_H += transport.h LIB_H += tree.h @@ -546,6 +547,7 @@ LIB_OBJS += sideband.o LIB_OBJS += sigchain.o LIB_OBJS += strbuf.o LIB_OBJS += string-list.o +LIB_OBJS += submodule.o LIB_OBJS += symlinks.o LIB_OBJS += tag.o LIB_OBJS += trace.o diff --git a/diff.c b/diff.c index e1be189742..6c63b87a8c 100644 --- a/diff.c +++ b/diff.c @@ -13,6 +13,7 @@ #include "utf8.h" #include "userdiff.h" #include "sigchain.h" +#include "submodule.h" #ifdef NO_FAST_WORKING_DIRECTORY #define FAST_WORKING_DIRECTORY 0 @@ -1453,6 +1454,17 @@ static void builtin_diff(const char *name_a, const char *a_prefix, *b_prefix; const char *textconv_one = NULL, *textconv_two = NULL; + if (DIFF_OPT_TST(o, SUBMODULE_LOG) && + (!one->mode || S_ISGITLINK(one->mode)) && + (!two->mode || S_ISGITLINK(two->mode))) { + const char *del = diff_get_color_opt(o, DIFF_FILE_OLD); + const char *add = diff_get_color_opt(o, DIFF_FILE_NEW); + show_submodule_summary(o->file, one ? one->path : two->path, + one->sha1, two->sha1, + del, add, reset); + return; + } + if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) { textconv_one = get_textconv(one); textconv_two = get_textconv(two); @@ -2640,6 +2652,12 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_OPT_CLR(options, ALLOW_TEXTCONV); else if (!strcmp(arg, "--ignore-submodules")) DIFF_OPT_SET(options, IGNORE_SUBMODULES); + else if (!strcmp(arg, "--submodule")) + DIFF_OPT_SET(options, SUBMODULE_LOG); + else if (!prefixcmp(arg, "--submodule=")) { + if (!strcmp(arg + 12, "log")) + DIFF_OPT_SET(options, SUBMODULE_LOG); + } /* misc options */ else if (!strcmp(arg, "-z")) diff --git a/diff.h b/diff.h index 6616877ee5..2740421cfe 100644 --- a/diff.h +++ b/diff.h @@ -66,6 +66,9 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19) #define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20) #define DIFF_OPT_ALLOW_TEXTCONV (1 << 21) + +#define DIFF_OPT_SUBMODULE_LOG (1 << 23) + #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) diff --git a/submodule.c b/submodule.c new file mode 100644 index 0000000000..d5fce7a882 --- /dev/null +++ b/submodule.c @@ -0,0 +1,113 @@ +#include "cache.h" +#include "submodule.h" +#include "dir.h" +#include "diff.h" +#include "commit.h" +#include "revision.h" + +int add_submodule_odb(const char *path) +{ + struct strbuf objects_directory = STRBUF_INIT; + struct alternate_object_database *alt_odb; + + strbuf_addf(&objects_directory, "%s/.git/objects/", path); + if (!is_directory(objects_directory.buf)) + return -1; + + /* avoid adding it twice */ + for (alt_odb = alt_odb_list; alt_odb; alt_odb = alt_odb->next) + if (alt_odb->name - alt_odb->base == objects_directory.len && + !strncmp(alt_odb->base, objects_directory.buf, + objects_directory.len)) + return 0; + + alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb)); + alt_odb->next = alt_odb_list; + strcpy(alt_odb->base, objects_directory.buf); + alt_odb->name = alt_odb->base + objects_directory.len; + alt_odb->name[2] = '/'; + alt_odb->name[40] = '\0'; + alt_odb->name[41] = '\0'; + alt_odb_list = alt_odb; + prepare_alt_odb(); + return 0; +} + +void show_submodule_summary(FILE *f, const char *path, + unsigned char one[20], unsigned char two[20], + const char *del, const char *add, const char *reset) +{ + struct rev_info rev; + struct commit *commit, *left = left, *right; + struct commit_list *merge_bases, *list; + const char *message = NULL; + struct strbuf sb = STRBUF_INIT; + static const char *format = " %m %s"; + int fast_forward = 0, fast_backward = 0; + + if (is_null_sha1(two)) + message = "(submodule deleted)"; + else if (add_submodule_odb(path)) + message = "(not checked out)"; + else if (is_null_sha1(one)) + message = "(new submodule)"; + else if (!(left = lookup_commit_reference(one)) || + !(right = lookup_commit_reference(two))) + message = "(commits not present)"; + + if (!message) { + init_revisions(&rev, NULL); + setup_revisions(0, NULL, &rev, NULL); + rev.left_right = 1; + rev.first_parent_only = 1; + left->object.flags |= SYMMETRIC_LEFT; + add_pending_object(&rev, &left->object, path); + add_pending_object(&rev, &right->object, path); + merge_bases = get_merge_bases(left, right, 1); + if (merge_bases) { + if (merge_bases->item == left) + fast_forward = 1; + else if (merge_bases->item == right) + fast_backward = 1; + } + for (list = merge_bases; list; list = list->next) { + list->item->object.flags |= UNINTERESTING; + add_pending_object(&rev, &list->item->object, + sha1_to_hex(list->item->object.sha1)); + } + if (prepare_revision_walk(&rev)) + message = "(revision walker failed)"; + } + + strbuf_addf(&sb, "Submodule %s %s..", path, + find_unique_abbrev(one, DEFAULT_ABBREV)); + if (!fast_backward && !fast_forward) + strbuf_addch(&sb, '.'); + strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV)); + if (message) + strbuf_addf(&sb, " %s\n", message); + else + strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : ""); + fwrite(sb.buf, sb.len, 1, f); + + if (!message) { + while ((commit = get_revision(&rev))) { + strbuf_setlen(&sb, 0); + if (commit->object.flags & SYMMETRIC_LEFT) { + if (del) + strbuf_addstr(&sb, del); + } + else if (add) + strbuf_addstr(&sb, add); + format_commit_message(commit, format, &sb, + rev.date_mode); + if (reset) + strbuf_addstr(&sb, reset); + strbuf_addch(&sb, '\n'); + fprintf(f, "%s", sb.buf); + } + clear_commit_marks(left, ~0); + clear_commit_marks(right, ~0); + } + strbuf_release(&sb); +} diff --git a/submodule.h b/submodule.h new file mode 100644 index 0000000000..4c0269d679 --- /dev/null +++ b/submodule.h @@ -0,0 +1,8 @@ +#ifndef SUBMODULE_H +#define SUBMODULE_H + +void show_submodule_summary(FILE *f, const char *path, + unsigned char one[20], unsigned char two[20], + const char *del, const char *add, const char *reset); + +#endif -- cgit v1.3 From a4ca1465ec8afee798bf8f11d727179ca3da64a9 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Thu, 29 Oct 2009 11:45:03 +0100 Subject: diff --color-words -U0: fix the location of hunk headers Colored word diff without context lines firstly printed all the hunk headers among each other and then printed the diff. This was due to the code relying on getting at least one context line at the end of each hunk, where the colored words would be flushed (it is done that way to be able to ignore rewrapped lines). Noticed by Markus Heidelberg. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- diff.c | 6 ++++++ t/t4034-diff-words.sh | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index e1be189742..b7ecfe3b17 100644 --- a/diff.c +++ b/diff.c @@ -656,6 +656,12 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) for (i = 0; i < len && line[i] == '@'; i++) ; if (2 <= i && i < len && line[i] == ' ') { + /* flush --color-words even for --unified=0 */ + if (ecbdata->diff_words && + (ecbdata->diff_words->minus.text.size || + ecbdata->diff_words->plus.text.size)) + diff_words_show(ecbdata->diff_words); + ecbdata->nparents = i - 1; len = sane_truncate_line(ecbdata, line, len); emit_line(ecbdata->file, diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 82240cf44d..21db6e95c4 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -77,7 +77,7 @@ cat > expect <<\EOF aeff = aeff * ( aaa ) EOF -test_expect_failure 'word diff without context' ' +test_expect_success 'word diff without context' ' word_diff --color-words --unified=0 -- cgit v1.3 From 76fd28283f7eeea246a06994edd43ab60e59d853 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 30 Oct 2009 10:09:06 -0700 Subject: diff --color-words: bit of clean-up When we introduced the "word diff" mode, we could have done one of three things: * change fn_out_consume() to "this is called every time a line worth of diff becomes ready from the lower-level diff routine. This function knows two sets of helpers (one for line-oriented diff, another for word diff), and each set has various functions to be called at certain places (e.g. hunk header, context, ...). The function's role is to inspect the incoming line, and dispatch appropriate helpers to produce either line- or word- oriented diff output." * introduce fn_out_consume_word_diff() that is "this is called every time a line worth of diff becomes ready from the lower-level diff routine, and here is what we do to prepare word oriented diff using that line." without touching fn_out_consume() at all. * Do neither of the above, and keep fn_out_consume() to "this is called every time a line worth of diff becomes ready from the lower-level diff routine, and here is what we do to output line oriented diff using that line." but sprinkle a handful of 'are we in word-diff mode? if so do this totally different thing' at random places. This patch is to at least abstract the details of "this totally different thing" out from the main codepath, in order to improve readability. We can later refactor it by introducing fn_out_consume_word_diff(), taking the second route above, but that is a separate topic. Signed-off-by: Junio C Hamano --- diff.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index b7ecfe3b17..8c66e4a0d4 100644 --- a/diff.c +++ b/diff.c @@ -541,14 +541,18 @@ struct emit_callback { FILE *file; }; +/* In "color-words" mode, show word-diff of words accumulated in the buffer */ +static void diff_words_flush(struct emit_callback *ecbdata) +{ + if (ecbdata->diff_words->minus.text.size || + ecbdata->diff_words->plus.text.size) + diff_words_show(ecbdata->diff_words); +} + static void free_diff_words_data(struct emit_callback *ecbdata) { if (ecbdata->diff_words) { - /* flush buffers */ - if (ecbdata->diff_words->minus.text.size || - ecbdata->diff_words->plus.text.size) - diff_words_show(ecbdata->diff_words); - + diff_words_flush(ecbdata); free (ecbdata->diff_words->minus.text.ptr); free (ecbdata->diff_words->minus.orig); free (ecbdata->diff_words->plus.text.ptr); @@ -656,12 +660,8 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) for (i = 0; i < len && line[i] == '@'; i++) ; if (2 <= i && i < len && line[i] == ' ') { - /* flush --color-words even for --unified=0 */ - if (ecbdata->diff_words && - (ecbdata->diff_words->minus.text.size || - ecbdata->diff_words->plus.text.size)) - diff_words_show(ecbdata->diff_words); - + if (ecbdata->diff_words) + diff_words_flush(ecbdata); ecbdata->nparents = i - 1; len = sane_truncate_line(ecbdata, line, len); emit_line(ecbdata->file, @@ -691,9 +691,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) &ecbdata->diff_words->plus); return; } - if (ecbdata->diff_words->minus.text.size || - ecbdata->diff_words->plus.text.size) - diff_words_show(ecbdata->diff_words); + diff_words_flush(ecbdata); line++; len--; emit_line(ecbdata->file, plain, reset, line, len); -- cgit v1.3 From 3e97c7c6af2901cec63bf35fcd43ae3472e24af8 Mon Sep 17 00:00:00 2001 From: Greg Bacon Date: Thu, 19 Nov 2009 15:12:24 -0600 Subject: No diff -b/-w output for all-whitespace changes Change git-diff's whitespace-ignoring modes to generate output only if a non-empty patch results, which git-apply rejects. Update the tests to look for the new behavior. Signed-off-by: Greg Bacon Signed-off-by: Junio C Hamano --- diff.c | 35 +++++++++++++++++++++++++++-------- t/t4015-diff-whitespace.sh | 14 ++++++++++++-- 2 files changed, 39 insertions(+), 10 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 0d7f5ea4a8..108de23611 100644 --- a/diff.c +++ b/diff.c @@ -189,6 +189,7 @@ struct emit_callback { struct diff_words_data *diff_words; int *found_changesp; FILE *file; + struct strbuf *header; }; static int count_lines(const char *data, int size) @@ -755,6 +756,11 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN); const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); + if (ecbdata->header) { + fprintf(ecbdata->file, "%s", ecbdata->header->buf); + strbuf_reset(ecbdata->header); + ecbdata->header = NULL; + } *(ecbdata->found_changesp) = 1; if (ecbdata->label_path[0]) { @@ -1561,6 +1567,7 @@ static void builtin_diff(const char *name_a, const char *reset = diff_get_color_opt(o, DIFF_RESET); const char *a_prefix, *b_prefix; const char *textconv_one = NULL, *textconv_two = NULL; + struct strbuf header = STRBUF_INIT; if (DIFF_OPT_TST(o, SUBMODULE_LOG) && (!one->mode || S_ISGITLINK(one->mode)) && @@ -1595,25 +1602,26 @@ static void builtin_diff(const char *name_a, b_two = quote_two(b_prefix, name_b + (*name_b == '/')); lbl[0] = DIFF_FILE_VALID(one) ? a_one : "/dev/null"; lbl[1] = DIFF_FILE_VALID(two) ? b_two : "/dev/null"; - fprintf(o->file, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset); + strbuf_addf(&header, "%sdiff --git %s %s%s\n", set, a_one, b_two, reset); if (lbl[0][0] == '/') { /* /dev/null */ - fprintf(o->file, "%snew file mode %06o%s\n", set, two->mode, reset); + strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset); if (xfrm_msg && xfrm_msg[0]) - fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset); + strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset); } else if (lbl[1][0] == '/') { - fprintf(o->file, "%sdeleted file mode %06o%s\n", set, one->mode, reset); + strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset); if (xfrm_msg && xfrm_msg[0]) - fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset); + strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset); } else { if (one->mode != two->mode) { - fprintf(o->file, "%sold mode %06o%s\n", set, one->mode, reset); - fprintf(o->file, "%snew mode %06o%s\n", set, two->mode, reset); + strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset); + strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset); } if (xfrm_msg && xfrm_msg[0]) - fprintf(o->file, "%s%s%s\n", set, xfrm_msg, reset); + strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset); + /* * we do not run diff between different kind * of objects. @@ -1623,6 +1631,8 @@ static void builtin_diff(const char *name_a, if (complete_rewrite && (textconv_one || !diff_filespec_is_binary(one)) && (textconv_two || !diff_filespec_is_binary(two))) { + fprintf(o->file, "%s", header.buf); + strbuf_reset(&header); emit_rewrite_diff(name_a, name_b, one, two, textconv_one, textconv_two, o); o->found_changes = 1; @@ -1640,6 +1650,8 @@ static void builtin_diff(const char *name_a, if (mf1.size == mf2.size && !memcmp(mf1.ptr, mf2.ptr, mf1.size)) goto free_ab_and_return; + fprintf(o->file, "%s", header.buf); + strbuf_reset(&header); if (DIFF_OPT_TST(o, BINARY)) emit_binary_diff(o->file, &mf1, &mf2); else @@ -1656,6 +1668,11 @@ static void builtin_diff(const char *name_a, struct emit_callback ecbdata; const struct userdiff_funcname *pe; + if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS)) { + fprintf(o->file, "%s", header.buf); + strbuf_reset(&header); + } + if (textconv_one) { size_t size; mf1.ptr = run_textconv(textconv_one, one, &size); @@ -1685,6 +1702,7 @@ static void builtin_diff(const char *name_a, if (ecbdata.ws_rule & WS_BLANK_AT_EOF) check_blank_at_eof(&mf1, &mf2, &ecbdata); ecbdata.file = o->file; + ecbdata.header = header.len ? &header : NULL; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; @@ -1729,6 +1747,7 @@ static void builtin_diff(const char *name_a, } free_ab_and_return: + strbuf_release(&header); diff_free_filespec_data(one); diff_free_filespec_data(two); free(a_one); diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 8dd147d78f..90f3342373 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -93,8 +93,6 @@ git diff > out test_expect_success 'another test, without options' 'test_cmp expect out' cat << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 EOF git diff -w > out test_expect_success 'another test, with -w' 'test_cmp expect out' @@ -386,6 +384,18 @@ test_expect_success 'checkdiff allows new blank lines' ' git diff --check ' +cat <expect +EOF +test_expect_success 'whitespace-only changes not reported' ' + git reset --hard && + echo >x "hello world" && + git add x && + git commit -m "hello 1" && + echo >x "hello world" && + git diff -b >actual && + test_cmp expect actual +' + test_expect_success 'combined diff with autocrlf conversion' ' git reset --hard && -- cgit v1.3 From 06a4755270b86a2af20a5c1f0d785311472b5223 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 27 Nov 2009 22:04:10 -0800 Subject: emit_line(): don't emit an empty followed by a newline When emit_line() is called with an empty line (but non-zero length, as we send line terminating LF or CRLF to the function), it used to emit followed by a newline. Stop the wastefulness. Signed-off-by: Junio C Hamano --- diff.c | 13 +++++++------ t/t4034-diff-words.sh | 8 ++++---- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 0d7f5ea4a8..108c7d7644 100644 --- a/diff.c +++ b/diff.c @@ -295,12 +295,13 @@ static void emit_line_0(FILE *file, const char *set, const char *reset, nofirst = 0; } - fputs(set, file); - - if (!nofirst) - fputc(first, file); - fwrite(line, len, 1, file); - fputs(reset, file); + if (len || !nofirst) { + fputs(set, file); + if (!nofirst) + fputc(first, file); + fwrite(line, len, 1, file); + fputs(reset, file); + } if (has_trailing_carriage_return) fputc('\r', file); if (has_trailing_newline) diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 21db6e95c4..2d24fbeda6 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -49,7 +49,7 @@ cat > expect <<\EOF +++ b/post @@ -1,3 +1,7 @@ h(4)h(4),hh[44] - + a = b + c aa = a @@ -90,7 +90,7 @@ cat > expect <<\EOF +++ b/post @@ -1,3 +1,7 @@ h(4),hh[44] - + a = b + c aa = a @@ -126,7 +126,7 @@ cat > expect <<\EOF +++ b/post @@ -1,3 +1,7 @@ h(4),hh[44] - + a = b + c aa = a @@ -168,7 +168,7 @@ cat > expect <<\EOF +++ b/post @@ -1,3 +1,7 @@ h(4),hh[44] - + a = b + c aa = a -- cgit v1.3 From 89cb73a19ac94d15babf77af490fa5db78908234 Mon Sep 17 00:00:00 2001 From: Bert Wesarg Date: Fri, 27 Nov 2009 07:55:18 +0100 Subject: Give the hunk comment its own color Inspired by the coloring of quilt. Introduce a separate color and paint the hunk comment part, i.e. the name of the function, in a separate color "diff.func" (defaults to plain). Whitespace between hunk header and hunk comment is printed in plain color. Signed-off-by: Bert Wesarg Signed-off-by: Junio C Hamano --- Documentation/config.txt | 8 ++++---- combine-diff.c | 5 ++++- diff.c | 43 ++++++++++++++++++++++++++++++++++++++++--- diff.h | 1 + t/t4034-diff-words.sh | 4 +++- 5 files changed, 52 insertions(+), 9 deletions(-) (limited to 'diff.c') diff --git a/Documentation/config.txt b/Documentation/config.txt index a8e0876a2a..a1e36d7e42 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -635,10 +635,10 @@ color.diff.:: Use customized color for diff colorization. `` specifies which part of the patch to use the specified color, and is one of `plain` (context text), `meta` (metainformation), `frag` - (hunk header), `old` (removed lines), `new` (added lines), - `commit` (commit headers), or `whitespace` (highlighting - whitespace errors). The values of these variables may be specified as - in color.branch.. + (hunk header), 'func' (function in hunk header), `old` (removed lines), + `new` (added lines), `commit` (commit headers), or `whitespace` + (highlighting whitespace errors). The values of these variables may be + specified as in color.branch.. color.grep:: When set to `always`, always highlight matches. When `false` (or diff --git a/combine-diff.c b/combine-diff.c index 5b63af1eeb..61626912e3 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -524,6 +524,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, int i; unsigned long lno = 0; const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO); + const char *c_func = diff_get_color(use_color, DIFF_FUNCINFO); const char *c_new = diff_get_color(use_color, DIFF_FILE_NEW); const char *c_old = diff_get_color(use_color, DIFF_FILE_OLD); const char *c_plain = diff_get_color(use_color, DIFF_PLAIN); @@ -588,7 +589,9 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, comment_end = i; } if (comment_end) - putchar(' '); + printf("%s%s %s%s", c_reset, + c_plain, c_reset, + c_func); for (i = 0; i < comment_end; i++) putchar(hunk_comment[i]); } diff --git a/diff.c b/diff.c index 108c7d7644..d952686926 100644 --- a/diff.c +++ b/diff.c @@ -39,6 +39,7 @@ static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_GREEN, /* NEW */ GIT_COLOR_YELLOW, /* COMMIT */ GIT_COLOR_BG_RED, /* WHITESPACE */ + GIT_COLOR_NORMAL, /* FUNCINFO */ }; static void diff_filespec_load_driver(struct diff_filespec *one); @@ -60,6 +61,8 @@ static int parse_diff_color_slot(const char *var, int ofs) return DIFF_COMMIT; if (!strcasecmp(var+ofs, "whitespace")) return DIFF_WHITESPACE; + if (!strcasecmp(var+ofs, "func")) + return DIFF_FUNCINFO; die("bad config variable '%s'", var); } @@ -345,6 +348,42 @@ static void emit_add_line(const char *reset, } } +static void emit_hunk_header(struct emit_callback *ecbdata, + const char *line, int len) +{ + const char *plain = diff_get_color(ecbdata->color_diff, DIFF_PLAIN); + const char *frag = diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO); + const char *func = diff_get_color(ecbdata->color_diff, DIFF_FUNCINFO); + const char *reset = diff_get_color(ecbdata->color_diff, DIFF_RESET); + static const char atat[2] = { '@', '@' }; + const char *cp, *ep; + + /* + * As a hunk header must begin with "@@ -, + @@", + * it always is at least 10 bytes long. + */ + if (len < 10 || + memcmp(line, atat, 2) || + !(ep = memmem(line + 2, len - 2, atat, 2))) { + emit_line(ecbdata->file, plain, reset, line, len); + return; + } + ep += 2; /* skip over @@ */ + + /* The hunk header in fraginfo color */ + emit_line(ecbdata->file, frag, reset, line, ep - line); + + /* blank before the func header */ + for (cp = ep; ep - line < len; ep++) + if (*ep != ' ' && *ep != '\t') + break; + if (ep != cp) + emit_line(ecbdata->file, plain, reset, cp, ep - cp); + + if (ep < line + len) + emit_line(ecbdata->file, func, reset, ep, line + len - ep); +} + static struct diff_tempfile *claim_diff_tempfile(void) { int i; for (i = 0; i < ARRAY_SIZE(diff_temp); i++) @@ -782,9 +821,7 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) diff_words_flush(ecbdata); len = sane_truncate_line(ecbdata, line, len); find_lno(line, ecbdata); - emit_line(ecbdata->file, - diff_get_color(ecbdata->color_diff, DIFF_FRAGINFO), - reset, line, len); + emit_hunk_header(ecbdata, line, len); if (line[len-1] != '\n') putc('\n', ecbdata->file); return; diff --git a/diff.h b/diff.h index 2740421cfe..15fcecdecd 100644 --- a/diff.h +++ b/diff.h @@ -130,6 +130,7 @@ enum color_diff { DIFF_FILE_NEW = 5, DIFF_COMMIT = 6, DIFF_WHITESPACE = 7, + DIFF_FUNCINFO = 8, }; const char *diff_get_color(int diff_use_color, enum color_diff ix); #define diff_get_color_opt(o, ix) \ diff --git a/t/t4034-diff-words.sh b/t/t4034-diff-words.sh index 2d24fbeda6..1c21276c55 100755 --- a/t/t4034-diff-words.sh +++ b/t/t4034-diff-words.sh @@ -8,6 +8,7 @@ test_expect_success setup ' git config diff.color.old red git config diff.color.new green + git config diff.color.func magenta ' @@ -16,6 +17,7 @@ decrypt_color () { -e 's/.\[1m//g' \ -e 's/.\[31m//g' \ -e 's/.\[32m//g' \ + -e 's/.\[35m//g' \ -e 's/.\[36m//g' \ -e 's/.\[m//g' } @@ -70,7 +72,7 @@ cat > expect <<\EOF +++ b/post @@ -1 +1 @@ h(4)h(4),hh[44] -@@ -3,0 +4,4 @@ a = b + c +@@ -3,0 +4,4 @@ a = b + c aa = a -- cgit v1.3 From 8b8e862490bba040299905cc0541560f24a11c41 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Sat, 12 Dec 2009 07:25:24 -0500 Subject: ignore unknown color configuration When parsing the config file, if there is a value that is syntactically correct but unused, we generally ignore it. This lets non-core porcelains store arbitrary information in the config file, and it means that configuration files can be shared between new and old versions of git (the old versions might simply ignore certain configuration). The one exception to this is color configuration; if we encounter a color.{diff,branch,status}.$slot variable, we die if it is not one of the recognized slots (presumably as a safety valve for user misconfiguration). This behavior has existed since 801235c (diff --color: use $GIT_DIR/config, 2006-06-24), but hasn't yet caused a problem. No porcelain has wanted to store extra colors, and we once a color area (like color.diff) has been introduced, we've never changed the set of color slots. However, that changed recently with the addition of color.diff.func. Now a user with color.diff.func in their config can no longer freely switch between v1.6.6 and older versions; the old versions will complain about the existence of the variable. This patch loosens the check to match the rest of git-config; unknown color slots are simply ignored. This doesn't fix this particular problem, as the older version (without this patch) is the problem, but it at least prevents it from happening again in the future. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- builtin-branch.c | 4 +++- builtin-commit.c | 4 +++- diff.c | 4 +++- t/t4026-color.sh | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) (limited to 'diff.c') diff --git a/builtin-branch.c b/builtin-branch.c index 9f57992062..c77f632886 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -65,7 +65,7 @@ static int parse_branch_color_slot(const char *var, int ofs) return BRANCH_COLOR_LOCAL; if (!strcasecmp(var+ofs, "current")) return BRANCH_COLOR_CURRENT; - die("bad config variable '%s'", var); + return -1; } static int git_branch_config(const char *var, const char *value, void *cb) @@ -76,6 +76,8 @@ static int git_branch_config(const char *var, const char *value, void *cb) } if (!prefixcmp(var, "color.branch.")) { int slot = parse_branch_color_slot(var, 13); + if (slot < 0) + return 0; if (!value) return config_error_nonbool(var); color_parse(value, var, branch_colors[slot]); diff --git a/builtin-commit.c b/builtin-commit.c index 2299dc75ce..7d3c6a86f7 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -841,7 +841,7 @@ static int parse_status_slot(const char *var, int offset) return WT_STATUS_NOBRANCH; if (!strcasecmp(var+offset, "unmerged")) return WT_STATUS_UNMERGED; - die("bad config variable '%s'", var); + return -1; } static int git_status_config(const char *k, const char *v, void *cb) @@ -861,6 +861,8 @@ static int git_status_config(const char *k, const char *v, void *cb) } if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) { int slot = parse_status_slot(k, 13); + if (slot < 0) + return 0; if (!v) return config_error_nonbool(k); color_parse(v, k, s->color_palette[slot]); diff --git a/diff.c b/diff.c index cc0cb2b31f..72f25b5284 100644 --- a/diff.c +++ b/diff.c @@ -59,7 +59,7 @@ static int parse_diff_color_slot(const char *var, int ofs) return DIFF_COMMIT; if (!strcasecmp(var+ofs, "whitespace")) return DIFF_WHITESPACE; - die("bad config variable '%s'", var); + return -1; } static int git_config_rename(const char *var, const char *value) @@ -118,6 +118,8 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); + if (slot < 0) + return 0; if (!value) return config_error_nonbool(var); color_parse(value, var, diff_colors[slot]); diff --git a/t/t4026-color.sh b/t/t4026-color.sh index b61e5169f4..5ade44c043 100755 --- a/t/t4026-color.sh +++ b/t/t4026-color.sh @@ -66,4 +66,21 @@ test_expect_success 'extra character after attribute' ' invalid_color "dimX" ' +test_expect_success 'unknown color slots are ignored (diff)' ' + git config --unset diff.color.new + git config color.diff.nosuchslotwilleverbedefined white && + git diff --color +' + +test_expect_success 'unknown color slots are ignored (branch)' ' + git config color.branch.nosuchslotwilleverbedefined white && + git branch -a +' + +test_expect_success 'unknown color slots are ignored (status)' ' + git config color.status.nosuchslotwilleverbedefined white || exit + git status + case $? in 0|1) : ok ;; *) false ;; esac +' + test_done -- cgit v1.3 From 70d7099916c9621e157c620f9cc7fc982f109c55 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 30 Dec 2009 04:02:53 -0500 Subject: textconv: stop leaking file descriptors We read the output from textconv helpers over a pipe, but we never actually closed our end of the pipe after using it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 387d19fded..69147b802f 100644 --- a/diff.c +++ b/diff.c @@ -3485,11 +3485,13 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, if (start_command(&child) != 0 || strbuf_read(&buf, child.out, 0) < 0 || finish_command(&child) != 0) { + close(child.out); if (temp.name == temp.tmp_path) unlink(temp.name); error("error running textconv command '%s'", pgm); return NULL; } + close(child.out); if (temp.name == temp.tmp_path) unlink(temp.name); -- cgit v1.3 From 41a457e4f814a0e514548b3178e7692129f0fcfe Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 30 Dec 2009 06:01:09 -0500 Subject: textconv: use shell to run helper Currently textconv helpers are run directly. Running through the shell is useful because the user can provide a program with command line arguments, like "antiword -f". It also makes textconv more consistent with other parts of git, most of which run their helpers using the shell. The downside is that textconv helpers with shell metacharacters (like space) in the filename will be broken. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 1 + t/t4030-diff-textconv.sh | 2 +- t/t4031-diff-rewrite-binary.sh | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 08bbd3e907..4af7c3f925 100644 --- a/diff.c +++ b/diff.c @@ -3771,6 +3771,7 @@ static char *run_textconv(const char *pgm, struct diff_filespec *spec, *arg = NULL; memset(&child, 0, sizeof(child)); + child.use_shell = 1; child.argv = argv; child.out = -1; if (start_command(&child) != 0 || diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index a3f0897a52..c16d538f46 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -48,7 +48,7 @@ test_expect_success 'file is considered binary by plumbing' ' test_expect_success 'setup textconv filters' ' echo file diff=foo >.gitattributes && - git config diff.foo.textconv "$PWD"/hexdump && + git config diff.foo.textconv "\"$PWD\""/hexdump && git config diff.fail.textconv false ' diff --git a/t/t4031-diff-rewrite-binary.sh b/t/t4031-diff-rewrite-binary.sh index a894c60622..27fb31b401 100755 --- a/t/t4031-diff-rewrite-binary.sh +++ b/t/t4031-diff-rewrite-binary.sh @@ -54,7 +54,7 @@ chmod +x dump test_expect_success 'setup textconv' ' echo file diff=foo >.gitattributes && - git config diff.foo.textconv "$PWD"/dump + git config diff.foo.textconv "\"$PWD\""/dump ' test_expect_success 'rewrite diff respects textconv' ' -- cgit v1.3 From 7ed7fac45a696ba6343707c7c8f4b268f309be32 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 30 Dec 2009 06:03:35 -0500 Subject: diff: run external diff helper with shell This is mostly to make it more consistent with the rest of git, which uses the shell to exec helpers. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 4af7c3f925..3b235e39ba 100644 --- a/diff.c +++ b/diff.c @@ -2275,7 +2275,7 @@ static void run_external_diff(const char *pgm, } *arg = NULL; fflush(NULL); - retval = run_command_v_opt(spawn_arg, 0); + retval = run_command_v_opt(spawn_arg, RUN_USING_SHELL); remove_tempfile(); if (retval) { fprintf(stderr, "external diff died, stopping at %s.\n", name); -- cgit v1.3 From 730f72840cc50c523fe4cdd796ea2d2fc4571a28 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 20 Sep 2009 00:03:39 -0700 Subject: unpack-trees.c: look ahead in the index This makes the traversal of index be in sync with the tree traversal. When unpack_callback() is fed a set of tree entries from trees, it inspects the name of the entry and checks if the an index entry with the same name could be hiding behind the current index entry, and (1) if the name appears in the index as a leaf node, it is also fed to the n_way_merge() callback function; (2) if the name is a directory in the index, i.e. there are entries in that are underneath it, then nothing is fed to the n_way_merge() callback function; (3) otherwise, if the name comes before the first eligible entry in the index, the index entry is first unpacked alone. When traverse_trees_recursive() descends into a subdirectory, the cache_bottom pointer is moved to walk index entries within that directory. All of these are omitted for diff-index, which does not even want to be fed an index entry and a tree entry with D/F conflicts. This fixes 3-way read-tree and exposes a bug in other parts of the system in t6035, test #5. The test prepares these three trees: O = HEAD^ 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a/b-2/c/d 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a/b/c/d 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a/x A = HEAD 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a/b-2/c/d 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a/b/c/d 100644 blob 587be6b4c3f93f93c489c0111bba5596147a26cb a/x B = master 120000 blob a36b77384451ea1de7bd340ffca868249626bc52 a/b 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a/b-2/c/d 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a/x With a clean index that matches HEAD, running git read-tree -m -u --aggressive $O $A $B now yields 120000 a36b77384451ea1de7bd340ffca868249626bc52 3 a/b 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 a/b-2/c/d 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 1 a/b/c/d 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 2 a/b/c/d 100644 587be6b4c3f93f93c489c0111bba5596147a26cb 0 a/x which is correct. "master" created "a/b" symlink that did not exist, and removed "a/b/c/d" while HEAD did not do touch either path. Before this series, read-tree did not notice the situation and resolved addition of "a/b" and removal of "a/b/c/d" independently. If A = HEAD had another path "a/b/c/e" added, this merge should conflict but instead it silently resolved "a/b" and then immediately overwrote it to add "a/b/c/e", which was quite bogus. Tests in t1012 start to work with this. Signed-off-by: Junio C Hamano --- diff-lib.c | 1 + diff.c | 17 +++++++ diff.h | 1 + t/t1012-read-tree-df.sh | 8 ++-- unpack-trees.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 140 insertions(+), 7 deletions(-) (limited to 'diff.c') diff --git a/diff-lib.c b/diff-lib.c index f759917d33..c9998f4c91 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -425,6 +425,7 @@ int run_diff_index(struct rev_info *revs, int cached) exit(128); diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/"); + diffcore_fix_diff_index(&revs->diffopt); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; diff --git a/diff.c b/diff.c index 08bbd3e907..3bfb4a19d2 100644 --- a/diff.c +++ b/diff.c @@ -3628,6 +3628,23 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) *q = outq; } +static int diffnamecmp(const void *a_, const void *b_) +{ + const struct diff_filepair *a = *((const struct diff_filepair **)a_); + const struct diff_filepair *b = *((const struct diff_filepair **)b_); + const char *name_a, *name_b; + + name_a = a->one ? a->one->path : a->two->path; + name_b = b->one ? b->one->path : b->two->path; + return strcmp(name_a, name_b); +} + +void diffcore_fix_diff_index(struct diff_options *options) +{ + struct diff_queue_struct *q = &diff_queued_diff; + qsort(q->queue, q->nr, sizeof(q->queue[0]), diffnamecmp); +} + void diffcore_std(struct diff_options *options) { if (options->skip_stat_unmatch) diff --git a/diff.h b/diff.h index 15fcecdecd..471f606a92 100644 --- a/diff.h +++ b/diff.h @@ -208,6 +208,7 @@ extern int diff_setup_done(struct diff_options *); #define DIFF_PICKAXE_REGEX 2 extern void diffcore_std(struct diff_options *); +extern void diffcore_fix_diff_index(struct diff_options *); #define COMMON_DIFF_OPTIONS_HELP \ "\ncommon diff options:\n" \ diff --git a/t/t1012-read-tree-df.sh b/t/t1012-read-tree-df.sh index f1e650ac39..9811d467da 100755 --- a/t/t1012-read-tree-df.sh +++ b/t/t1012-read-tree-df.sh @@ -51,7 +51,7 @@ test_expect_success setup ' : ' -test_expect_failure '3-way (1)' ' +test_expect_success '3-way (1)' ' settree A-000 && git read-tree -m -u O-000 A-000 B-000 && checkindex <<-EOF @@ -63,7 +63,7 @@ test_expect_failure '3-way (1)' ' EOF ' -test_expect_failure '3-way (2)' ' +test_expect_success '3-way (2)' ' settree A-001 && git read-tree -m -u O-000 A-001 B-000 && checkindex <<-EOF @@ -76,7 +76,7 @@ test_expect_failure '3-way (2)' ' EOF ' -test_expect_failure '3-way (3)' ' +test_expect_success '3-way (3)' ' settree A-010 && git read-tree -m -u O-010 A-010 B-010 && checkindex <<-EOF @@ -90,7 +90,7 @@ test_expect_failure '3-way (3)' ' EOF ' -test_expect_failure '2-way (1)' ' +test_expect_success '2-way (1)' ' settree O-020 && git read-tree -m -u O-020 A-020 && checkindex <<-EOF diff --git a/unpack-trees.c b/unpack-trees.c index 685adb4b77..74cabc36ff 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -231,9 +231,37 @@ static int unpack_index_entry(struct cache_entry *ce, return ret; } +static int find_cache_pos(struct traverse_info *, const struct name_entry *); + +static void restore_cache_bottom(struct traverse_info *info, int bottom) +{ + struct unpack_trees_options *o = info->data; + + if (o->diff_index_cached) + return; + o->cache_bottom = bottom; +} + +static int switch_cache_bottom(struct traverse_info *info) +{ + struct unpack_trees_options *o = info->data; + int ret, pos; + + if (o->diff_index_cached) + return 0; + ret = o->cache_bottom; + pos = find_cache_pos(info->prev, &info->name); + + if (pos < -1) + o->cache_bottom = -2 - pos; + else if (pos < 0) + o->cache_bottom = o->src_index->cache_nr; + return ret; +} + static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info) { - int i; + int i, ret, bottom; struct tree_desc t[MAX_UNPACK_TREES]; struct traverse_info newinfo; struct name_entry *p; @@ -254,7 +282,11 @@ static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long sha1 = names[i].sha1; fill_tree_descriptor(t+i, sha1); } - return traverse_trees(n, t, &newinfo); + + bottom = switch_cache_bottom(&newinfo); + ret = traverse_trees(n, t, &newinfo); + restore_cache_bottom(&newinfo, bottom); + return ret; } /* @@ -393,6 +425,82 @@ static int unpack_failed(struct unpack_trees_options *o, const char *message) return -1; } +/* NEEDSWORK: give this a better name and share with tree-walk.c */ +static int name_compare(const char *a, int a_len, + const char *b, int b_len) +{ + int len = (a_len < b_len) ? a_len : b_len; + int cmp = memcmp(a, b, len); + if (cmp) + return cmp; + return (a_len - b_len); +} + +/* + * The tree traversal is looking at name p. If we have a matching entry, + * return it. If name p is a directory in the index, do not return + * anything, as we will want to match it when the traversal descends into + * the directory. + */ +static int find_cache_pos(struct traverse_info *info, + const struct name_entry *p) +{ + int pos; + struct unpack_trees_options *o = info->data; + struct index_state *index = o->src_index; + int pfxlen = info->pathlen; + int p_len = tree_entry_len(p->path, p->sha1); + + for (pos = o->cache_bottom; pos < index->cache_nr; pos++) { + struct cache_entry *ce = index->cache[pos]; + const char *ce_name, *ce_slash; + int cmp, ce_len; + + if (!ce_in_traverse_path(ce, info)) + continue; + if (ce->ce_flags & CE_UNPACKED) + continue; + ce_name = ce->name + pfxlen; + ce_slash = strchr(ce_name, '/'); + if (ce_slash) + ce_len = ce_slash - ce_name; + else + ce_len = ce_namelen(ce) - pfxlen; + cmp = name_compare(p->path, p_len, ce_name, ce_len); + /* + * Exact match; if we have a directory we need to + * delay returning it. + */ + if (!cmp) + return ce_slash ? -2 - pos : pos; + if (0 < cmp) + continue; /* keep looking */ + /* + * ce_name sorts after p->path; could it be that we + * have files under p->path directory in the index? + * E.g. ce_name == "t-i", and p->path == "t"; we may + * have "t/a" in the index. + */ + if (p_len < ce_len && !memcmp(ce_name, p->path, p_len) && + ce_name[p_len] < '/') + continue; /* keep looking */ + break; + } + return -1; +} + +static struct cache_entry *find_cache_entry(struct traverse_info *info, + const struct name_entry *p) +{ + int pos = find_cache_pos(info, p); + struct unpack_trees_options *o = info->data; + + if (0 <= pos) + return o->src_index->cache[pos]; + else + return NULL; +} + static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *names, struct traverse_info *info) { struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, }; @@ -406,8 +514,14 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str /* Are we supposed to look at the index too? */ if (o->merge) { while (1) { - struct cache_entry *ce = next_cache_entry(o); int cmp; + struct cache_entry *ce; + + if (o->diff_index_cached) + ce = next_cache_entry(o); + else + ce = find_cache_entry(info, p); + if (!ce) break; cmp = compare_entry(ce, info, p); -- cgit v1.3 From 8e08b4198c40cd6d3a5d1a7e60a599adabece08e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 16 Jan 2010 18:42:53 +0100 Subject: Teach diff that modified submodule directory is dirty A diff run in superproject only compares the name of the commit object bound at the submodule paths. When we compare with a work tree and the checked out submodule directory is dirty (e.g. has either staged or unstaged changes, or has new files the user forgot to add to the index), show the work tree side as "dirty". Signed-off-by: Junio C Hamano Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- diff.c | 9 +++-- t/t4027-diff-submodule.sh | 84 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 3 deletions(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 04beb26a6a..750c066a5e 100644 --- a/diff.c +++ b/diff.c @@ -2029,9 +2029,14 @@ static int populate_from_stdin(struct diff_filespec *s) static int diff_populate_gitlink(struct diff_filespec *s, int size_only) { int len; - char *data = xmalloc(100); + char *data = xmalloc(100), *dirty = ""; + + /* Are we looking at the work tree? */ + if (!s->sha1_valid && is_submodule_modified(s->path)) + dirty = "-dirty"; + len = snprintf(data, 100, - "Subproject commit %s\n", sha1_to_hex(s->sha1)); + "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty); s->data = data; s->size = len; s->should_free = 1; diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index 5cf8924b21..83c1914771 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -32,7 +32,8 @@ test_expect_success setup ' cd sub && git rev-list HEAD ) && - echo ":160000 160000 $3 $_z40 M sub" >expect + echo ":160000 160000 $3 $_z40 M sub" >expect && + subtip=$3 subprev=$2 ' test_expect_success 'git diff --raw HEAD' ' @@ -50,6 +51,87 @@ test_expect_success 'git diff-files --raw' ' test_cmp expect actual.files ' +expect_from_to () { + printf "%sSubproject commit %s\n+Subproject commit %s\n" \ + "-" "$1" "$2" +} + +test_expect_success 'git diff HEAD' ' + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev && + test_cmp expect.body actual.body +' + +test_expect_success 'git diff HEAD with dirty submodule (work tree)' ' + echo >>sub/world && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev-dirty && + test_cmp expect.body actual.body +' + +test_expect_success 'git diff HEAD with dirty submodule (index)' ' + ( + cd sub && + git reset --hard && + echo >>world && + git add world + ) && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev-dirty && + test_cmp expect.body actual.body +' + +test_expect_success 'git diff HEAD with dirty submodule (untracked)' ' + ( + cd sub && + git reset --hard && + git clean -qfdx && + >cruft + ) && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subtip $subprev-dirty && + test_cmp expect.body actual.body +' + +test_expect_success 'git diff HEAD with dirty submodule (work tree, refs match)' ' + git commit -m "x" sub && + echo >>sub/world && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body +' + +test_expect_success 'git diff HEAD with dirty submodule (index, refs match)' ' + ( + cd sub && + git reset --hard && + echo >>world && + git add world + ) && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body +' + +test_expect_success 'git diff HEAD with dirty submodule (untracked, refs match)' ' + ( + cd sub && + git reset --hard && + git clean -qfdx && + >cruft + ) && + git diff HEAD >actual && + sed -e "1,/^@@/d" actual >actual.body && + expect_from_to >expect.body $subprev $subprev-dirty && + test_cmp expect.body actual.body +' + test_expect_success 'git diff (empty submodule dir)' ' : >empty && rm -rf sub/* sub/.git && -- cgit v1.3 From e3d42c4773bccebb50f01b108d20b06c6a11e615 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Mon, 18 Jan 2010 21:26:18 +0100 Subject: Performance optimization for detection of modified submodules In the worst case is_submodule_modified() got called three times for each submodule. The information we got from scanning the whole submodule tree the first time can be reused instead. New parameters have been added to diff_change() and diff_addremove(), the information is stored in a new member of struct diff_filespec. Its value is then reused instead of calling is_submodule_modified() again. When no explicit "-dirty" is needed in the output the call to is_submodule_modified() is not necessary when the submodules HEAD already disagrees with the ref of the superproject, as this alone marks it as modified. To achieve that, get_stat_data() got an extra argument. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- diff-lib.c | 46 +++++++++++++++++++++++++++++++--------------- diff.c | 15 +++++++++++---- diff.h | 10 ++++++---- diffcore.h | 1 + revision.c | 5 +++-- tree-diff.c | 8 ++++---- 6 files changed, 56 insertions(+), 29 deletions(-) (limited to 'diff.c') diff --git a/diff-lib.c b/diff-lib.c index 9cdf6daa90..23e180eed1 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -73,6 +73,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) unsigned int oldmode, newmode; struct cache_entry *ce = active_cache[i]; int changed; + unsigned dirty_submodule = 0; if (DIFF_OPT_TST(&revs->diffopt, QUICK) && DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES)) @@ -173,12 +174,16 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (silent_on_removed) continue; diff_addremove(&revs->diffopt, '-', ce->ce_mode, - ce->sha1, ce->name); + ce->sha1, ce->name, 0); continue; } changed = ce_match_stat(ce, &st, ce_option); - if (S_ISGITLINK(ce->ce_mode) && !changed) - changed = is_submodule_modified(ce->name); + if (S_ISGITLINK(ce->ce_mode) + && (!changed || (revs->diffopt.output_format & DIFF_FORMAT_PATCH)) + && is_submodule_modified(ce->name)) { + changed = 1; + dirty_submodule = 1; + } if (!changed) { ce_mark_uptodate(ce); if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER)) @@ -188,7 +193,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) newmode = ce_mode_from_stat(ce, st.st_mode); diff_change(&revs->diffopt, oldmode, newmode, ce->sha1, (changed ? null_sha1 : ce->sha1), - ce->name); + ce->name, 0, dirty_submodule); } diffcore_std(&revs->diffopt); @@ -204,16 +209,18 @@ int run_diff_files(struct rev_info *revs, unsigned int option) static void diff_index_show_file(struct rev_info *revs, const char *prefix, struct cache_entry *ce, - const unsigned char *sha1, unsigned int mode) + const unsigned char *sha1, unsigned int mode, + unsigned dirty_submodule) { diff_addremove(&revs->diffopt, prefix[0], mode, - sha1, ce->name); + sha1, ce->name, dirty_submodule); } static int get_stat_data(struct cache_entry *ce, const unsigned char **sha1p, unsigned int *modep, - int cached, int match_missing) + int cached, int match_missing, + unsigned *dirty_submodule, int output_format) { const unsigned char *sha1 = ce->sha1; unsigned int mode = ce->ce_mode; @@ -233,8 +240,13 @@ static int get_stat_data(struct cache_entry *ce, return -1; } changed = ce_match_stat(ce, &st, 0); - if (changed - || (S_ISGITLINK(ce->ce_mode) && is_submodule_modified(ce->name))) { + if (S_ISGITLINK(ce->ce_mode) + && (!changed || (output_format & DIFF_FORMAT_PATCH)) + && is_submodule_modified(ce->name)) { + changed = 1; + *dirty_submodule = 1; + } + if (changed) { mode = ce_mode_from_stat(ce, st.st_mode); sha1 = null_sha1; } @@ -251,15 +263,17 @@ static void show_new_file(struct rev_info *revs, { const unsigned char *sha1; unsigned int mode; + unsigned dirty_submodule = 0; /* * New file in the index: it might actually be different in * the working copy. */ - if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) + if (get_stat_data(new, &sha1, &mode, cached, match_missing, + &dirty_submodule, revs->diffopt.output_format) < 0) return; - diff_index_show_file(revs, "+", new, sha1, mode); + diff_index_show_file(revs, "+", new, sha1, mode, dirty_submodule); } static int show_modified(struct rev_info *revs, @@ -270,11 +284,13 @@ static int show_modified(struct rev_info *revs, { unsigned int mode, oldmode; const unsigned char *sha1; + unsigned dirty_submodule = 0; - if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) { + if (get_stat_data(new, &sha1, &mode, cached, match_missing, + &dirty_submodule, revs->diffopt.output_format) < 0) { if (report_missing) diff_index_show_file(revs, "-", old, - old->sha1, old->ce_mode); + old->sha1, old->ce_mode, 0); return -1; } @@ -309,7 +325,7 @@ static int show_modified(struct rev_info *revs, return 0; diff_change(&revs->diffopt, oldmode, mode, - old->sha1, sha1, old->name); + old->sha1, sha1, old->name, 0, dirty_submodule); return 0; } @@ -356,7 +372,7 @@ static void do_oneway_diff(struct unpack_trees_options *o, * Something removed from the tree? */ if (!idx) { - diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode); + diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode, 0); return; } diff --git a/diff.c b/diff.c index 750c066a5e..8986873c0e 100644 --- a/diff.c +++ b/diff.c @@ -2032,7 +2032,7 @@ static int diff_populate_gitlink(struct diff_filespec *s, int size_only) char *data = xmalloc(100), *dirty = ""; /* Are we looking at the work tree? */ - if (!s->sha1_valid && is_submodule_modified(s->path)) + if (!s->sha1_valid && s->dirty_submodule) dirty = "-dirty"; len = snprintf(data, 100, @@ -3719,7 +3719,7 @@ int diff_result_code(struct diff_options *opt, int status) void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, - const char *concatpath) + const char *concatpath, unsigned dirty_submodule) { struct diff_filespec *one, *two; @@ -3751,8 +3751,10 @@ void diff_addremove(struct diff_options *options, if (addremove != '+') fill_filespec(one, sha1, mode); - if (addremove != '-') + if (addremove != '-') { fill_filespec(two, sha1, mode); + two->dirty_submodule = dirty_submodule; + } diff_queue(&diff_queued_diff, one, two); if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) @@ -3763,7 +3765,8 @@ void diff_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, - const char *concatpath) + const char *concatpath, + unsigned old_dirty_submodule, unsigned new_dirty_submodule) { struct diff_filespec *one, *two; @@ -3776,6 +3779,8 @@ void diff_change(struct diff_options *options, const unsigned char *tmp_c; tmp = old_mode; old_mode = new_mode; new_mode = tmp; tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c; + tmp = old_dirty_submodule; old_dirty_submodule = new_dirty_submodule; + new_dirty_submodule = tmp; } if (options->prefix && @@ -3786,6 +3791,8 @@ void diff_change(struct diff_options *options, two = alloc_filespec(concatpath); fill_filespec(one, old_sha1, old_mode); fill_filespec(two, new_sha1, new_mode); + one->dirty_submodule = old_dirty_submodule; + two->dirty_submodule = new_dirty_submodule; diff_queue(&diff_queued_diff, one, two); if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) diff --git a/diff.h b/diff.h index 6f6d0ed01d..968a8dce95 100644 --- a/diff.h +++ b/diff.h @@ -14,12 +14,13 @@ typedef void (*change_fn_t)(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, - const char *fullpath); + const char *fullpath, + unsigned old_dirty_submodule, unsigned new_dirty_submodule); typedef void (*add_remove_fn_t)(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, - const char *fullpath); + const char *fullpath, unsigned dirty_submodule); typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, struct diff_options *options, void *data); @@ -177,13 +178,14 @@ extern void diff_addremove(struct diff_options *, int addremove, unsigned mode, const unsigned char *sha1, - const char *fullpath); + const char *fullpath, unsigned dirty_submodule); extern void diff_change(struct diff_options *, unsigned mode1, unsigned mode2, const unsigned char *sha1, const unsigned char *sha2, - const char *fullpath); + const char *fullpath, + unsigned dirty_submodule1, unsigned dirty_submodule2); extern void diff_unmerge(struct diff_options *, const char *path, diff --git a/diffcore.h b/diffcore.h index 5b634585e8..66687c3fe5 100644 --- a/diffcore.h +++ b/diffcore.h @@ -42,6 +42,7 @@ struct diff_filespec { #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0) unsigned should_free : 1; /* data should be free()'ed */ unsigned should_munmap : 1; /* data should be munmap()'ed */ + unsigned dirty_submodule : 1; /* For submodules: its work tree is dirty */ struct userdiff_driver *driver; /* data should be considered "binary"; -1 means "don't know yet" */ diff --git a/revision.c b/revision.c index 25fa14d93e..769cfd4251 100644 --- a/revision.c +++ b/revision.c @@ -268,7 +268,7 @@ static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, - const char *fullpath) + const char *fullpath, unsigned dirty_submodule) { int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD; @@ -281,7 +281,8 @@ static void file_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, - const char *fullpath) + const char *fullpath, + unsigned old_dirty_submodule, unsigned new_dirty_submodule) { tree_difference = REV_TREE_DIFFERENT; DIFF_OPT_SET(options, HAS_CHANGES); diff --git a/tree-diff.c b/tree-diff.c index 7d745b4406..fe9f52c479 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -68,7 +68,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { newbase[baselen + pathlen1] = 0; opt->change(opt, mode1, mode2, - sha1, sha2, newbase); + sha1, sha2, newbase, 0, 0); newbase[baselen + pathlen1] = '/'; } retval = diff_tree_sha1(sha1, sha2, newbase, opt); @@ -77,7 +77,7 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const } fullname = malloc_fullname(base, baselen, path1, pathlen1); - opt->change(opt, mode1, mode2, sha1, sha2, fullname); + opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0); free(fullname); return 0; } @@ -241,7 +241,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { newbase[baselen + pathlen] = 0; - opt->add_remove(opt, *prefix, mode, sha1, newbase); + opt->add_remove(opt, *prefix, mode, sha1, newbase, 0); newbase[baselen + pathlen] = '/'; } @@ -252,7 +252,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree free(newbase); } else { char *fullname = malloc_fullname(base, baselen, path, pathlen); - opt->add_remove(opt, prefix[0], mode, sha1, fullname); + opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0); free(fullname); } } -- cgit v1.3 From 721ceec1ad12625e90b395fd0be0fae9049ebc22 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 24 Jan 2010 15:09:00 +0100 Subject: Teach diff --submodule that modified submodule directory is dirty Since commit 8e08b4 git diff does append "-dirty" to the work tree side if the working directory of a submodule contains new or modified files. Lets do the same when the --submodule option is used. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- diff.c | 2 +- submodule.c | 3 +++ submodule.h | 1 + t/t4041-diff-submodule.sh | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) (limited to 'diff.c') diff --git a/diff.c b/diff.c index 160dbfd718..0190ec6d9f 100644 --- a/diff.c +++ b/diff.c @@ -1615,7 +1615,7 @@ static void builtin_diff(const char *name_a, const char *del = diff_get_color_opt(o, DIFF_FILE_OLD); const char *add = diff_get_color_opt(o, DIFF_FILE_NEW); show_submodule_summary(o->file, one ? one->path : two->path, - one->sha1, two->sha1, + one->sha1, two->sha1, two->dirty_submodule, del, add, reset); return; } diff --git a/submodule.c b/submodule.c index f657bee379..ca0527fbcb 100644 --- a/submodule.c +++ b/submodule.c @@ -36,6 +36,7 @@ static int add_submodule_odb(const char *path) void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], + unsigned dirty_submodule, const char *del, const char *add, const char *reset) { struct rev_info rev; @@ -85,6 +86,8 @@ void show_submodule_summary(FILE *f, const char *path, if (!fast_backward && !fast_forward) strbuf_addch(&sb, '.'); strbuf_addf(&sb, "%s", find_unique_abbrev(two, DEFAULT_ABBREV)); + if (dirty_submodule) + strbuf_add(&sb, "-dirty", 6); if (message) strbuf_addf(&sb, " %s\n", message); else diff --git a/submodule.h b/submodule.h index 0773121eb5..233696555e 100644 --- a/submodule.h +++ b/submodule.h @@ -3,6 +3,7 @@ void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], + unsigned dirty_submodule, const char *del, const char *add, const char *reset); int is_submodule_modified(const char *path); diff --git a/t/t4041-diff-submodule.sh b/t/t4041-diff-submodule.sh index 5bb4fed3f5..464305405a 100755 --- a/t/t4041-diff-submodule.sh +++ b/t/t4041-diff-submodule.sh @@ -191,6 +191,73 @@ EOF " commit_file sm1 && +test_expect_success 'submodule is up to date' " + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +EOF +" + +test_expect_success 'submodule contains untracked content' " + echo new > sm1/new-file && + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +Submodule sm1 $head6..$head6-dirty: +EOF +" + +test_expect_success 'submodule contains untracked and modifed content' " + echo new > sm1/foo6 && + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +Submodule sm1 $head6..$head6-dirty: +EOF +" + +test_expect_success 'submodule contains modifed content' " + rm -f sm1/new-file && + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +Submodule sm1 $head6..$head6-dirty: +EOF +" + +(cd sm1; git commit -mchange foo6 >/dev/null) && +head8=$(cd sm1; git rev-parse --verify HEAD | cut -c1-7) && +test_expect_success 'submodule is modified' " + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +Submodule sm1 $head6..$head8: + > change +EOF +" + +test_expect_success 'modified submodule contains untracked content' " + echo new > sm1/new-file && + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +Submodule sm1 $head6..$head8-dirty: + > change +EOF +" + +test_expect_success 'modified submodule contains untracked and modifed content' " + echo modification >> sm1/foo6 && + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +Submodule sm1 $head6..$head8-dirty: + > change +EOF +" + +test_expect_success 'modified submodule contains modifed content' " + rm -f sm1/new-file && + git diff-index -p --submodule=log HEAD >actual && + diff actual - <<-EOF +Submodule sm1 $head6..$head8-dirty: + > change +EOF +" + rm -rf sm1 test_expect_success 'deleted submodule' " git diff-index -p --submodule=log HEAD >actual && -- cgit v1.3