{"thread":{"id":"4509","subject":"[PATCH/RFC] Teach diff about -b and -w flags","startedAt":"2006-06-14T15:40:23Z","lastAt":"2006-06-14T15:40:23Z","messageCount":1,"participants":["Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"21786","messageId":"Pine.LNX.4.63.0606141739020.18794@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4509","inReplyTo":null,"subject":"[PATCH/RFC] Teach diff about -b and -w flags","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-06-14T15:40:23Z","receivedAt":"2006-06-14T15:40:23Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis adds -b (--ignore-space-change) and -w (--ignore-all-space) flags to\ndiff. The main part of the patch is teaching libxdiff about it.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n---\n\n\tNote that -b will not treat DOS and Unix line endings as equal,\n\talthough it would be trivial. Is this desired?\n\n\tAnother question: instead of checking the flags all the time,\n\txdl_line_match (and possibly xdl_hash_record) could be split into\n\tthree different functions, and a function pointer could be set\n\tat init time. This would be faster, but less elegant, no?\n\n diff.c           |   13 +++++++++----\n diff.h           |    1 +\n xdiff/xdiff.h    |    3 +++\n xdiff/xdiffi.c   |   12 ++++++------\n xdiff/xdiffi.h   |    1 -\n xdiff/xmacros.h  |    1 -\n xdiff/xprepare.c |   16 ++++++++++------\n xdiff/xutils.c   |   51 ++++++++++++++++++++++++++++++++++++++++++++++++++-\n xdiff/xutils.h   |    3 ++-\n 9 files changed, 81 insertions(+), 20 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex bc32a4a..5b34f73 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -661,7 +661,7 @@ static void builtin_diff(const char *nam\n \t\tmemset(&ecbdata, 0, sizeof(ecbdata));\n \t\tecbdata.label_path = lbl;\n \t\tecbdata.color_diff = o->color_diff;\n-\t\txpp.flags = XDF_NEED_MINIMAL;\n+\t\txpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;\n \t\txecfg.ctxlen = o->context;\n \t\txecfg.flags = XDL_EMIT_FUNCNAMES;\n \t\tif (!diffopts)\n@@ -686,6 +686,7 @@ static void builtin_diffstat(const char \n \t\t\t     struct diff_filespec *one,\n \t\t\t     struct diff_filespec *two,\n \t\t\t     struct diffstat_t *diffstat,\n+\t\t\t     struct diff_options *o,\n \t\t\t     int complete_rewrite)\n {\n \tmmfile_t mf1, mf2;\n@@ -715,7 +716,7 @@ static void builtin_diffstat(const char \n \t\txdemitconf_t xecfg;\n \t\txdemitcb_t ecb;\n \n-\t\txpp.flags = XDF_NEED_MINIMAL;\n+\t\txpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;\n \t\txecfg.ctxlen = 0;\n \t\txecfg.flags = 0;\n \t\tecb.outf = xdiff_outf;\n@@ -1300,7 +1301,7 @@ static void run_diffstat(struct diff_fil\n \n \tif (DIFF_PAIR_UNMERGED(p)) {\n \t\t/* unmerged */\n-\t\tbuiltin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, 0);\n+\t\tbuiltin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0);\n \t\treturn;\n \t}\n \n@@ -1312,7 +1313,7 @@ static void run_diffstat(struct diff_fil\n \n \tif (p->status == DIFF_STATUS_MODIFIED && p->score)\n \t\tcomplete_rewrite = 1;\n-\tbuiltin_diffstat(name, other, p->one, p->two, diffstat, complete_rewrite);\n+\tbuiltin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite);\n }\n \n static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)\n@@ -1517,6 +1518,10 @@ int diff_opt_parse(struct diff_options *\n \t}\n \telse if (!strcmp(arg, \"--color\"))\n \t\toptions->color_diff = 1;\n+\telse if (!strcmp(arg, \"-w\") || !strcmp(arg, \"--ignore-all-space\"))\n+\t\toptions->xdl_opts |= XDF_IGNORE_WHITESPACE;\n+\telse if (!strcmp(arg, \"-b\") || !strcmp(arg, \"--ignore-space-change\"))\n+\t\toptions->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;\n \telse\n \t\treturn 0;\n \treturn 1;\ndiff --git a/diff.h b/diff.h\nindex 2b821df..7d7b6cd 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -46,6 +46,7 @@ struct diff_options {\n \tint setup;\n \tint abbrev;\n \tconst char *stat_sep;\n+\tlong xdl_opts;\n \n \tint nr_paths;\n \tconst char **paths;\ndiff --git a/xdiff/xdiff.h b/xdiff/xdiff.h\nindex 2540e8a..2ce10b4 100644\n--- a/xdiff/xdiff.h\n+++ b/xdiff/xdiff.h\n@@ -29,6 +29,9 @@ #endif /* #ifdef __cplusplus */\n \n \n #define XDF_NEED_MINIMAL (1 << 1)\n+#define XDF_IGNORE_WHITESPACE (1 << 2)\n+#define XDF_IGNORE_WHITESPACE_CHANGE (1 << 3)\n+#define XDF_WHITESPACE_FLAGS (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)\n \n #define XDL_PATCH_NORMAL '-'\n #define XDL_PATCH_REVERSE '+'\ndiff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c\nindex b95ade2..5d09a16 100644\n--- a/xdiff/xdiffi.c\n+++ b/xdiff/xdiffi.c\n@@ -45,7 +45,7 @@ static long xdl_split(unsigned long cons\n \t\t      long *kvdf, long *kvdb, int need_min, xdpsplit_t *spl,\n \t\t      xdalgoenv_t *xenv);\n static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, long chg2);\n-static int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo);\n+static int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags);\n \n \n \n@@ -397,7 +397,7 @@ static xdchange_t *xdl_add_change(xdchan\n }\n \n \n-static int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo) {\n+static int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {\n \tlong ix, ixo, ixs, ixref, grpsiz, nrec = xdf->nrec;\n \tchar *rchg = xdf->rchg, *rchgo = xdfo->rchg;\n \txrecord_t **recs = xdf->recs;\n@@ -440,7 +440,7 @@ static int xdl_change_compact(xdfile_t *\n \t\t\t * the group.\n \t\t\t */\n \t\t\twhile (ixs > 0 && recs[ixs - 1]->ha == recs[ix - 1]->ha &&\n-\t\t\t       XDL_RECMATCH(recs[ixs - 1], recs[ix - 1])) {\n+\t\t\t       xdl_line_match(recs[ixs - 1]->ptr, recs[ixs - 1]->size, recs[ix - 1]->ptr, recs[ix - 1]->size, flags)) {\n \t\t\t\trchg[--ixs] = 1;\n \t\t\t\trchg[--ix] = 0;\n \n@@ -468,7 +468,7 @@ static int xdl_change_compact(xdfile_t *\n \t\t\t * the group.\n \t\t\t */\n \t\t\twhile (ix < nrec && recs[ixs]->ha == recs[ix]->ha &&\n-\t\t\t       XDL_RECMATCH(recs[ixs], recs[ix])) {\n+\t\t\t       xdl_line_match(recs[ixs]->ptr, recs[ixs]->size, recs[ix]->ptr, recs[ix]->size, flags)) {\n \t\t\t\trchg[ixs++] = 0;\n \t\t\t\trchg[ix++] = 1;\n \n@@ -546,8 +546,8 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf\n \n \t\treturn -1;\n \t}\n-\tif (xdl_change_compact(&xe.xdf1, &xe.xdf2) < 0 ||\n-\t    xdl_change_compact(&xe.xdf2, &xe.xdf1) < 0 ||\n+\tif (xdl_change_compact(&xe.xdf1, &xe.xdf2, xpp->flags) < 0 ||\n+\t    xdl_change_compact(&xe.xdf2, &xe.xdf1, xpp->flags) < 0 ||\n \t    xdl_build_script(&xe, &xscr) < 0) {\n \n \t\txdl_free_env(&xe);\ndiff --git a/xdiff/xdiffi.h b/xdiff/xdiffi.h\nindex dd8f3c9..d3b7271 100644\n--- a/xdiff/xdiffi.h\n+++ b/xdiff/xdiffi.h\n@@ -55,6 +55,5 @@ void xdl_free_script(xdchange_t *xscr);\n int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,\n \t\t  xdemitconf_t const *xecfg);\n \n-\n #endif /* #if !defined(XDIFFI_H) */\n \ndiff --git a/xdiff/xmacros.h b/xdiff/xmacros.h\nindex 78f0260..4c2fde8 100644\n--- a/xdiff/xmacros.h\n+++ b/xdiff/xmacros.h\n@@ -33,7 +33,6 @@ #define XDL_ABS(v) ((v) >= 0 ? (v): -(v)\n #define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9')\n #define XDL_HASHLONG(v, b) (((unsigned long)(v) * GR_PRIME) >> ((CHAR_BIT * sizeof(unsigned long)) - (b)))\n #define XDL_PTRFREE(p) do { if (p) { xdl_free(p); (p) = NULL; } } while (0)\n-#define XDL_RECMATCH(r1, r2) ((r1)->size == (r2)->size && memcmp((r1)->ptr, (r2)->ptr, (r1)->size) == 0)\n #define XDL_LE32_PUT(p, v) \\\n do { \\\n \tunsigned char *__p = (unsigned char *) (p); \\\ndiff --git a/xdiff/xprepare.c b/xdiff/xprepare.c\nindex add5a75..f2a12ae 100644\n--- a/xdiff/xprepare.c\n+++ b/xdiff/xprepare.c\n@@ -43,12 +43,13 @@ typedef struct s_xdlclassifier {\n \txdlclass_t **rchash;\n \tchastore_t ncha;\n \tlong count;\n+\tlong flags;\n } xdlclassifier_t;\n \n \n \n \n-static int xdl_init_classifier(xdlclassifier_t *cf, long size);\n+static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags);\n static void xdl_free_classifier(xdlclassifier_t *cf);\n static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits,\n \t\t\t       xrecord_t *rec);\n@@ -63,9 +64,11 @@ static int xdl_optimize_ctxs(xdfile_t *x\n \n \n \n-static int xdl_init_classifier(xdlclassifier_t *cf, long size) {\n+static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {\n \tlong i;\n \n+\tcf->flags = flags;\n+\n \tcf->hbits = xdl_hashbits((unsigned int) size);\n \tcf->hsize = 1 << cf->hbits;\n \n@@ -103,8 +106,9 @@ static int xdl_classify_record(xdlclassi\n \tline = rec->ptr;\n \thi = (long) XDL_HASHLONG(rec->ha, cf->hbits);\n \tfor (rcrec = cf->rchash[hi]; rcrec; rcrec = rcrec->next)\n-\t\tif (rcrec->ha == rec->ha && rcrec->size == rec->size &&\n-\t\t    !memcmp(line, rcrec->line, rec->size))\n+\t\tif (rcrec->ha == rec->ha &&\n+\t\t\t\txdl_line_match(rcrec->line, rcrec->size,\n+\t\t\t\t\trec->ptr, rec->size, cf->flags))\n \t\t\tbreak;\n \n \tif (!rcrec) {\n@@ -173,7 +177,7 @@ static int xdl_prepare_ctx(mmfile_t *mf,\n \t\t\t\ttop = blk + bsize;\n \t\t\t}\n \t\t\tprev = cur;\n-\t\t\thav = xdl_hash_record(&cur, top);\n+\t\t\thav = xdl_hash_record(&cur, top, xpp->flags);\n \t\t\tif (nrec >= narec) {\n \t\t\t\tnarec *= 2;\n \t\t\t\tif (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *)))) {\n@@ -268,7 +272,7 @@ int xdl_prepare_env(mmfile_t *mf1, mmfil\n \tenl1 = xdl_guess_lines(mf1) + 1;\n \tenl2 = xdl_guess_lines(mf2) + 1;\n \n-\tif (xdl_init_classifier(&cf, enl1 + enl2 + 1) < 0) {\n+\tif (xdl_init_classifier(&cf, enl1 + enl2 + 1, xpp->flags) < 0) {\n \n \t\treturn -1;\n \t}\ndiff --git a/xdiff/xutils.c b/xdiff/xutils.c\nindex 21ab8e7..3dd5fe1 100644\n--- a/xdiff/xutils.c\n+++ b/xdiff/xutils.c\n@@ -189,12 +189,61 @@ long xdl_guess_lines(mmfile_t *mf) {\n \treturn nl + 1;\n }\n \n+int xdl_line_match(const char *l1, long s1, const char *l2, long s2, long flags)\n+{\n+\tint i1, i2;\n+\n+\tif (flags & XDF_IGNORE_WHITESPACE) {\n+\t\tfor (i1 = i2 = 0; i1 < s1 && i2 < s2; i1++, i2++) {\n+\t\t\tif (isspace(l1[i1]))\n+\t\t\t\twhile (isspace(l1[i1]) && i1 < s1)\n+\t\t\t\t\ti1++;\n+\t\t\telse if (isspace(l2[i2]))\n+\t\t\t\twhile (isspace(l2[i2]) && i2 < s2)\n+\t\t\t\t\ti2++;\n+\t\t\telse if (l1[i1] != l2[i2])\n+\t\t\t\treturn l2[i2] - l1[i1];\n+\t\t}\n+\t\tif (i1 >= s1)\n+\t\t\treturn 1;\n+\t\telse if (i2 >= s2)\n+\t\t\treturn -1;\n+\t} else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {\n+\t\tfor (i1 = i2 = 0; i1 < s1 && i2 < s2; i1++, i2++) {\n+\t\t\tif (isspace(l1[i1])) {\n+\t\t\t\tif (!isspace(l2[i2]))\n+\t\t\t\t\treturn -1;\n+\t\t\t\twhile (isspace(l1[i1]) && i1 < s1)\n+\t\t\t\t\ti1++;\n+\t\t\t\twhile (isspace(l2[i2]) && i2 < s2)\n+\t\t\t\t\ti2++;\n+\t\t\t} else if (l1[i1] != l2[i2])\n+\t\t\t\treturn l2[i2] - l1[i1];\n+\t\t}\n+\t\tif (i1 >= s1)\n+\t\t\treturn 1;\n+\t\telse if (i2 >= s2)\n+\t\t\treturn -1;\n+\t} else\n+\t\treturn s1 == s2 && !memcmp(l1, l2, s1);\n+\n+\treturn 0;\n+}\n \n-unsigned long xdl_hash_record(char const **data, char const *top) {\n+unsigned long xdl_hash_record(char const **data, char const *top, long flags) {\n \tunsigned long ha = 5381;\n \tchar const *ptr = *data;\n \n \tfor (; ptr < top && *ptr != '\\n'; ptr++) {\n+\t\tif (isspace(*ptr) && (flags & XDF_WHITESPACE_FLAGS)) {\n+\t\t\twhile (ptr < top && isspace(*ptr) && ptr[1] != '\\n')\n+\t\t\t\tptr++;\n+\t\t\tif (flags & XDF_IGNORE_WHITESPACE_CHANGE) {\n+\t\t\t\tha += (ha << 5);\n+\t\t\t\tha ^= (unsigned long) ' ';\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n \t\tha += (ha << 5);\n \t\tha ^= (unsigned long) *ptr;\n \t}\ndiff --git a/xdiff/xutils.h b/xdiff/xutils.h\nindex ea38ee9..2701eea 100644\n--- a/xdiff/xutils.h\n+++ b/xdiff/xutils.h\n@@ -33,7 +33,8 @@ void *xdl_cha_alloc(chastore_t *cha);\n void *xdl_cha_first(chastore_t *cha);\n void *xdl_cha_next(chastore_t *cha);\n long xdl_guess_lines(mmfile_t *mf);\n-unsigned long xdl_hash_record(char const **data, char const *top);\n+int xdl_line_match(const char *l1, long s1, const char *l2, long s2, long flags);\n+unsigned long xdl_hash_record(char const **data, char const *top, long flags);\n unsigned int xdl_hashbits(unsigned int size);\n int xdl_num_out(char *out, long val);\n long xdl_atol(char const *str, char const **next);\n-- \n1.4.0.ga9a96-dirty\n"}]}