From 81034aef15c65ada7fdee69cfe67b32ae78d9bcd Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 5 Mar 2013 15:00:17 +1100 Subject: [PATCH] Add --ignore-blanks option. This can be useful when people re-flow you text or otherwise introduce space-damange that just really isn't interesting. Suggested-by: Tom Scogland Signed-off-by: NeilBrown --- ReadMe.c | 3 +- dotest | 7 +++- split.c | 27 ++++++++++-- tests/contrib/abstract/bmerge | 24 +++++++++++ tests/contrib/abstract/new | 23 ++++++++++ tests/contrib/abstract/new2 | 27 ++++++++++++ tests/contrib/abstract/orig | 25 +++++++++++ vpatch.c | 79 +++++++++++++++++++---------------- wiggle.1 | 30 ++++++++++++- wiggle.c | 49 +++++++++++++--------- wiggle.h | 9 ++-- 11 files changed, 236 insertions(+), 67 deletions(-) create mode 100644 tests/contrib/abstract/bmerge create mode 100644 tests/contrib/abstract/new create mode 100644 tests/contrib/abstract/new2 create mode 100644 tests/contrib/abstract/orig diff --git a/ReadMe.c b/ReadMe.c index 4430117..1a171a2 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -31,7 +31,7 @@ char Version[] = "wiggle 0.9 2012-05-14 GPL-2+ http://neil.brown.name/wiggle/\n"; -char short_options[] = "xdmwlrhiW123p::VRvqB"; +char short_options[] = "xdmwlrhiW123p::VRvqBb"; struct option long_options[] = { {"browse", 0, 0, 'B'}, @@ -50,6 +50,7 @@ struct option long_options[] = { {"strip", 1, 0, 'p'}, {"no-ignore", 0, 0, 'i'}, {"show-wiggle", 0, 0, 'W'}, + {"ignore-blanks",0,0, 'b'}, {"self-test", 0, 0, SELF_TEST}, {0, 0, 0, 0} }; diff --git a/dotest b/dotest index 0f62211..e718f13 100755 --- a/dotest +++ b/dotest @@ -41,7 +41,7 @@ fail=0 find . -name core | xargs rm -f list=$(find . -type f \( -name script -o -name diff -o -name ldiff \ -o -name rediff -o -name merge -o -name wmerge -o -name lmerge \ - -o -name replace -o -name Wmerge \) + -o -name replace -o -name Wmerge -o -name bmerge \) ) for path in $list do @@ -96,6 +96,11 @@ do else $TIME $WIGGLE -mW orig new new2 | diff -u Wmerge - ; xit=$? fi ;; + bmerge ) if [ -f patch ] + then $TIME $WIGGLE -mbw orig patch | diff -u bmerge - ; xit=$? + else $TIME $WIGGLE -mbw orig new new2 | diff -u bmerge - ; xit=$? + fi + ;; esac if [ $xit = 0 ]; then msg=SUCCEEDED; else msg=FAILED; fi if grep 'ERROR SUMMARY: [1-9]' $vallog > /dev/null 2>&1 diff --git a/split.c b/split.c index a2880ac..ba2cb26 100644 --- a/split.c +++ b/split.c @@ -56,12 +56,22 @@ static int split_internal(char *start, char *end, int type, while (start < end) { char *cp = start; + char *cp2; + int prefix = 0; + + if (type == (ByWord | IgnoreBlanks)) + while (cp < end && + (*cp == ' ' || *cp == '\t')) { + prefix++; + cp++; + } + start = cp; if (*cp == '\0' && cp+19 < end && cp[18] == '\n') { /* special word */ cp += 20; } else - switch (type) { + switch (type & ByMask) { case ByLine: while (cp < end && *cp != '\n') cp++; @@ -85,11 +95,20 @@ static int split_internal(char *start, char *end, int type, cp++; break; } + cp2 = cp; + if (type == (ByWord | IgnoreBlanks) && + *start && *start != '\n') + while (cp2 < end && + (*cp2 == ' ' || *cp2 == '\t' || *cp2 == '\n')) { + cp2++; + if (cp2[-1] == '\n') + break; + } if (list) { list->start = start; list->len = cp-start; - list->plen = list->len; - list->prefix = 0; + list->plen = cp2-start; + list->prefix = prefix; if (*start) list->hash = hash(start, list->len, 0); else @@ -97,7 +116,7 @@ static int split_internal(char *start, char *end, int type, list++; } cnt++; - start = cp; + start = cp2; } return cnt; } diff --git a/tests/contrib/abstract/bmerge b/tests/contrib/abstract/bmerge new file mode 100644 index 0000000..e9ba52c --- /dev/null +++ b/tests/contrib/abstract/bmerge @@ -0,0 +1,24 @@ +\begin{ abstract } + % Start with a two-sentence (at most) description of the big-picture + % problem and why we care, and a sentence at the end that emphasizes how + % your work is part of the solution. + + Heterogeneous systems with <<<---Central Processing Units |||CPUs ===central CPUs --->>>and accelerators such as GPUs, FPGAs or the upcoming Intel MIC are becoming + mainstream. In these systems, peak performance includes the performance + of not just the CPUs but also all available accelerators. In spite of this + fact, the majority of programming models for heterogeneous computing focus + on only one of these. With the development of Accelerated OpenMP for GPUs, + both from PGI and Cray, we have a clear path to extend traditional OpenMP + applications incrementally to use GPUs. The extensions are geared toward + switching from CPU parallelism to GPU parallelism. However they do not + preserve the former while adding the latter. Thus computational potential is + wasted since either the CPU cores or the GPU cores are left idle. Our goal + is to create a runtime system that can intelligently divide an accelerated + OpenMP region across all available resources automatically. This paper + presents our proof-of-concept runtime system for dynamic task scheduling + across CPUs and GPUs. Further, we motivate the addition of this system into + the proposed \emph{OpenMP for Accelerators} standard. Finally, we show that + this option can produce as much as a two-fold performance improvement over + using either the CPU or GPU alone. + +\end{ abstract } diff --git a/tests/contrib/abstract/new b/tests/contrib/abstract/new new file mode 100644 index 0000000..16b0038 --- /dev/null +++ b/tests/contrib/abstract/new @@ -0,0 +1,23 @@ +\begin{abstract} + % Start with a two-sentence (at most) description of the big-picture + % problem and why we care, and a sentence at the end that emphasizes how + % your work is part of the solution. + + Heterogeneous systems with CPUs and computational accelerators such as GPUs, FPGAs or + the upcoming Intel MIC are becoming mainstream. In these systems, peak performance + includes the performance of not just the CPUs but also all available accelerators. In + spite of this fact, the majority of programming models for heterogeneous computing + focus on only one of these. With the development of Accelerated OpenMP for GPUs, both + from PGI and Cray, we have a clear path to extend traditional OpenMP applications + incrementally to use GPUs. The extensions are geared toward switching from CPU + parallelism to GPU parallelism. However they do not preserve the former while adding + the latter. Thus computational potential is wasted since either the CPU cores or the + GPU cores are left idle. Our goal is to create a runtime system that can + intelligently divide an accelerated OpenMP region across all available resources + automatically. This paper presents our proof-of-concept runtime system for dynamic + task scheduling across CPUs and GPUs. Further, we motivate the addition of this + system into the proposed \emph{OpenMP for Accelerators} standard. Finally, we show + that this option can produce as much as a two-fold performance improvement over using + either the CPU or GPU alone. + +\end{abstract} diff --git a/tests/contrib/abstract/new2 b/tests/contrib/abstract/new2 new file mode 100644 index 0000000..8f4c8a4 --- /dev/null +++ b/tests/contrib/abstract/new2 @@ -0,0 +1,27 @@ +\begin {abstract} + % Start with a two-sentence (at most) description of the big-picture + % problem and why we care, and a sentence at the end that emphasizes how + % your work is part of the solution. + + Heterogeneous systems with central CPUs and accelerators such as + GPUs, FPGAs or the upcoming Intel MIC are becoming mainstream. + In these systems, peak performance includes the performance of not + just the CPUs but also all available accelerators. In spite of + this fact, the majority of programming models for heterogeneous + computing focus on only one of these. With the development of + Accelerated OpenMP for GPUs, both from PGI and Cray, we have a + clear path to extend traditional OpenMP applications incrementally + to use GPUs. The extensions are geared toward switching from CPU + parallelism to GPU parallelism. However they do not preserve the + former while adding the latter. Thus computational potential is + wasted since either the CPU cores or the GPU cores are left idle. + Our goal is to create a runtime system that can intelligently + divide an accelerated OpenMP region across all available resources + automatically. This paper presents our proof-of-concept runtime + system for dynamic task scheduling across CPUs and GPUs. Further, + we motivate the addition of this system into the proposed + \emph{OpenMP for Accelerators} standard. Finally, we show that + this option can produce as much as a two-fold performance + improvement over using either the CPU or GPU alone. + +\end{abstract} diff --git a/tests/contrib/abstract/orig b/tests/contrib/abstract/orig new file mode 100644 index 0000000..73ba1a8 --- /dev/null +++ b/tests/contrib/abstract/orig @@ -0,0 +1,25 @@ +\begin{ abstract } + % Start with a two-sentence (at most) description of the big-picture + % problem and why we care, and a sentence at the end that emphasizes how + % your work is part of the solution. + + Heterogeneous systems with Central Processing Units and computational + accelerators such as GPUs, FPGAs or the upcoming Intel MIC are becoming + mainstream. In these systems, peak performance includes the performance + of not just the CPUs but also all available accelerators. In spite of this + fact, the majority of programming models for heterogeneous computing focus + on only one of these. With the development of Accelerated OpenMP for GPUs, + both from PGI and Cray, we have a clear path to extend traditional OpenMP + applications incrementally to use GPUs. The extensions are geared toward + switching from CPU parallelism to GPU parallelism. However they do not + preserve the former while adding the latter. Thus computational potential is + wasted since either the CPU cores or the GPU cores are left idle. Our goal + is to create a runtime system that can intelligently divide an accelerated + OpenMP region across all available resources automatically. This paper + presents our proof-of-concept runtime system for dynamic task scheduling + across CPUs and GPUs. Further, we motivate the addition of this system into + the proposed \emph{OpenMP for Accelerators} standard. Finally, we show that + this option can produce as much as a two-fold performance improvement over + using either the CPU or GPU alone. + +\end{ abstract } diff --git a/vpatch.c b/vpatch.c index 5437a84..5b265f2 100644 --- a/vpatch.c +++ b/vpatch.c @@ -1248,7 +1248,7 @@ static char *save_query[] = { }; static int merge_window(struct plist *p, FILE *f, int reverse, int replace, - int selftest) + int selftest, int ignore_blanks) { /* Display the merge window in one of the selectable modes, * starting with the 'merge' mode. @@ -1376,9 +1376,9 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace, return 0; } /* FIXME check for errors in the stream */ - fm = split_stream(sm, ByWord); - fb = split_stream(sb, ByWord); - fa = split_stream(sa, ByWord); + fm = split_stream(sm, ByWord | ignore_blanks); + fb = split_stream(sb, ByWord | ignore_blanks); + fa = split_stream(sa, ByWord | ignore_blanks); if (ch) csl1 = pdiff(fm, fb, ch); @@ -2237,7 +2237,7 @@ static int merge_window(struct plist *p, FILE *f, int reverse, int replace, static int show_merge(char *origname, FILE *patch, int reverse, int is_merge, char *before, char *after, - int replace, int selftest) + int replace, int selftest, int ignore_blanks) { struct plist p; @@ -2254,10 +2254,12 @@ static int show_merge(char *origname, FILE *patch, int reverse, p.after = after; freopen("/dev/null","w",stderr); - return merge_window(&p, patch, reverse, replace, selftest); + return merge_window(&p, patch, reverse, replace, selftest, + ignore_blanks); } -static void calc_one(struct plist *pl, FILE *f, int reverse) +static void calc_one(struct plist *pl, FILE *f, int reverse, + int ignore_blanks) { struct stream s1, s2; struct stream s = load_segment(f, pl->start, pl->end); @@ -2281,9 +2283,9 @@ static void calc_one(struct plist *pl, FILE *f, int reverse) struct file ff, fp1, fp2; struct csl *csl1, *csl2; struct ci ci; - ff = split_stream(sf, ByWord); - fp1 = split_stream(s1, ByWord); - fp2 = split_stream(s2, ByWord); + ff = split_stream(sf, ByWord | ignore_blanks); + fp1 = split_stream(s1, ByWord | ignore_blanks); + fp2 = split_stream(s2, ByWord | ignore_blanks); if (pl->chunks) csl1 = pdiff(ff, fp1, pl->chunks); else @@ -2333,7 +2335,7 @@ static int get_prev(int pos, struct plist *pl, int n, int mode) } static int get_next(int pos, struct plist *pl, int n, int mode, - FILE *f, int reverse) + FILE *f, int reverse, int ignore_blanks) { int found = 0; if (pos == -1) @@ -2353,7 +2355,7 @@ static int get_next(int pos, struct plist *pl, int n, int mode, if (pos < 0) return -1; if (pl[pos].calced == 0 && pl[pos].end) - calc_one(pl+pos, f, reverse); + calc_one(pl+pos, f, reverse, ignore_blanks); if (pl[pos].last >= 0) /* always see directories */ found = 1; @@ -2367,7 +2369,8 @@ static int get_next(int pos, struct plist *pl, int n, int mode, return pos; } -static void draw_one(int row, struct plist *pl, FILE *f, int reverse) +static void draw_one(int row, struct plist *pl, FILE *f, int reverse, + int ignore_blanks) { char hdr[12]; hdr[0] = 0; @@ -2379,7 +2382,7 @@ static void draw_one(int row, struct plist *pl, FILE *f, int reverse) } if (pl->calced == 0 && pl->end) /* better load the patch and count the chunks */ - calc_one(pl, f, reverse); + calc_one(pl, f, reverse, ignore_blanks); if (pl->end == 0) { strcpy(hdr, " "); } else { @@ -2419,7 +2422,8 @@ static void draw_one(int row, struct plist *pl, FILE *f, int reverse) clrtoeol(); } -static int save_one(FILE *f, struct plist *pl, int reverse) +static int save_one(FILE *f, struct plist *pl, int reverse, + int ignore_blanks) { struct stream sp, sa, sb, sm; struct file fa, fb, fm; @@ -2432,10 +2436,10 @@ static int save_one(FILE *f, struct plist *pl, int reverse) chunks = split_patch(sp, &sa, &sb); else chunks = split_patch(sp, &sb, &sa); - fb = split_stream(sb, ByWord); - fa = split_stream(sa, ByWord); + fb = split_stream(sb, ByWord | ignore_blanks); + fa = split_stream(sa, ByWord | ignore_blanks); sm = load_file(pl->file); - fm = split_stream(sm, ByWord); + fm = split_stream(sm, ByWord | ignore_blanks); csl1 = pdiff(fm, fb, chunks); csl2 = diff_patch(fb, fa); ci = make_merger(fm, fb, fa, csl1, csl2, 0, 1, 0); @@ -2493,7 +2497,7 @@ static char *saveall_query[] = { NULL }; static void main_window(struct plist *pl, int *np, FILE *f, int reverse, - int replace) + int replace, int ignore_blanks) { /* The main window lists all files together with summary information: * number of chunks, number of wiggles, number of conflicts. @@ -2576,16 +2580,16 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse, /* Ok, row and pos could be trustworthy now */ tpos = pos; for (i = row; i >= 1; i--) { - draw_one(i, &pl[tpos], f, reverse); + draw_one(i, &pl[tpos], f, reverse, ignore_blanks); tpos = get_prev(tpos, pl, *np, mode); } tpos = pos; for (i = row+1; i < rows; i++) { - tpos = get_next(tpos, pl, *np, mode, f, reverse); + tpos = get_next(tpos, pl, *np, mode, f, reverse,ignore_blanks); if (tpos >= 0) - draw_one(i, &pl[tpos], f, reverse); + draw_one(i, &pl[tpos], f, reverse, ignore_blanks); else - draw_one(i, NULL, f, reverse); + draw_one(i, NULL, f, reverse, ignore_blanks); } } attrset(0); @@ -2615,7 +2619,7 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse, case 'N': case 'N'-64: case KEY_DOWN: - tpos = get_next(pos, pl, *np, mode, f, reverse); + tpos = get_next(pos, pl, *np, mode, f, reverse, ignore_blanks); if (tpos >= 0) { pos = tpos; row++; @@ -2637,7 +2641,7 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse, if (getmouse(&mevent) != OK) break; while (row < mevent.y && - (tpos = get_next(pos, pl, *np, mode, f, reverse)) + (tpos = get_next(pos, pl, *np, mode, f, reverse, ignore_blanks)) >= 0) { pos = tpos; row++; @@ -2663,9 +2667,9 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse, } else { int c; if (pl[pos].is_merge) - c = merge_window(&pl[pos], NULL, reverse, 0, 0); + c = merge_window(&pl[pos], NULL, reverse, 0, 0, ignore_blanks); else - c = merge_window(&pl[pos], f, reverse, 0, 0); + c = merge_window(&pl[pos], f, reverse, 0, 0, ignore_blanks); refresh = 2; if (c) { pl[pos].is_merge = 1; @@ -2720,7 +2724,8 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse, if (pl[i].end && !pl[i].is_merge) save_one(f, &pl[i], - reverse); + reverse, + ignore_blanks); } } else cnt = 0; @@ -2751,7 +2756,7 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse, /* Already saved */ mesg = "File is already saved."; } else { - if (save_one(f, &pl[pos], reverse) == 0) { + if (save_one(f, &pl[pos], reverse, ignore_blanks) == 0) { pl[pos].is_merge = 1; snprintf(mesg_buf, cols, "Saved file %s.", @@ -2782,7 +2787,7 @@ static void main_window(struct plist *pl, int *np, FILE *f, int reverse, mesg = "File has been restored."; pl[pos].is_merge = 0; refresh = 1; - calc_one(&pl[pos], f, reverse); + calc_one(&pl[pos], f, reverse, ignore_blanks); } else mesg = "Could not restore file!"; } @@ -2878,7 +2883,7 @@ static void term_init(int doraw) } int vpatch(int argc, char *argv[], int patch, int strip, - int reverse, int replace, int selftest) + int reverse, int replace, int selftest, int ignore_blanks) { /* NOTE argv[0] is first arg... * Behaviour depends on number of args: @@ -2928,7 +2933,7 @@ int vpatch(int argc, char *argv[], int patch, int strip, fprintf(stderr, "%s: aborting\n", Cmd); exit(2); } - main_window(pl, &num_patches, in, reverse, replace); + main_window(pl, &num_patches, in, reverse, replace, ignore_blanks); plist_free(pl, num_patches); fclose(in); break; @@ -2945,17 +2950,17 @@ int vpatch(int argc, char *argv[], int patch, int strip, fprintf(stderr, "%s: aborting\n", Cmd); exit(2); } - main_window(pl, &num_patches, f, reverse, replace); + main_window(pl, &num_patches, f, reverse, replace,ignore_blanks); plist_free(pl, num_patches); } else if (strlen(argv[0]) > 4 && strcmp(argv[0]+strlen(argv[0])-4, ".rej") == 0) { char *origname = strdup(argv[0]); origname[strlen(origname) - 4] = '\0'; show_merge(origname, f, reverse, 0, NULL, NULL, - replace, selftest); + replace, selftest, ignore_blanks); } else show_merge(argv[0], f, reverse, 1, NULL, NULL, - replace, selftest); + replace, selftest, ignore_blanks); break; case 2: /* an orig and a diff/.ref */ @@ -2965,11 +2970,11 @@ int vpatch(int argc, char *argv[], int patch, int strip, exit(1); } show_merge(argv[0], f, reverse, 0, NULL, NULL, - replace, selftest); + replace, selftest, ignore_blanks); break; case 3: /* orig, before, after */ show_merge(argv[0], NULL, reverse, 0, argv[1], argv[2], - replace, selftest); + replace, selftest, ignore_blanks); break; } diff --git a/wiggle.1 b/wiggle.1 index 9154d4c..18591c7 100644 --- a/wiggle.1 +++ b/wiggle.1 @@ -145,14 +145,40 @@ where involved and what needed to be ignored in order of the patch to be wiggled in to place. .TP -.BR -w ", " \-\-words +.BR \-w ", " \-\-words Request that all operations and display be word based. This is the default for the "diff" function. .TP -.BR -l ", " \-\-lines +.BR \-l ", " \-\-lines Request that all operations and display be line based. +.TP +.BR \-b ", " \-\-ignore\-blanks +De-emphasise white space (space, tab, and newline) is determining +differences and changes. + +Normally white space is treated like a word which can be matched or +changed by a patch. When this flag is in force, white space serves +only as a separator between other words and is not matched itself. +The effect of this is that changes in the amount of white space are +not treated as significant. + +To be precise, any white space is combined with the preceeding word +or, in the case of leading space on a line, with the following word. +However it is not involved in any comparisons of that word. If a patch +deletes a word, the attached white space is deleted as well. If a +patch adds a word, the attached white space is added as well. + +An empty line, or one that contains only blanks, will be treated as a +single word that will match any other blank line, no matter how many +spaces it has. + +.B \-b +has no effect in +.B \-\-line +mode. + .TP .BR -p ", " \-\-patch Treat the last named file as a patch instead of a file (with \-\-diff) diff --git a/wiggle.c b/wiggle.c index f084957..9b4c02c 100644 --- a/wiggle.c +++ b/wiggle.c @@ -418,13 +418,13 @@ static int do_diff(int argc, char *argv[], int obj, int ispatch, flist[1] = flist[2]; flist[2] = f; } - fl[0] = split_stream(flist[0], obj == 'l' ? ByLine : ByWord); - fl[1] = split_stream(flist[1], obj == 'l' ? ByLine : ByWord); + fl[0] = split_stream(flist[0], obj); + fl[1] = split_stream(flist[1], obj); if (chunks2 && !chunks1) csl = pdiff(fl[0], fl[1], chunks2); else csl = diff_patch(fl[0], fl[1]); - if (obj == 'l') { + if ((obj & ByMask) == ByLine) { if (!chunks1) printf("@@ -1,%d +1,%d @@\n", fl[0].elcnt, fl[1].elcnt); @@ -447,7 +447,7 @@ static int do_diff(int argc, char *argv[], int obj, int ispatch, return exit_status; } -static int do_merge(int argc, char *argv[], int obj, +static int do_merge(int argc, char *argv[], int obj, int blanks, int reverse, int replace, int ignore, int show_wiggles, int quiet) { @@ -539,15 +539,14 @@ static int do_merge(int argc, char *argv[], int obj, outfile = fdopen(fd, "w"); } - if (obj == 'l') { - fl[0] = split_stream(flist[0], ByLine); - fl[1] = split_stream(flist[1], ByLine); - fl[2] = split_stream(flist[2], ByLine); - } else { - fl[0] = split_stream(flist[0], ByWord); - fl[1] = split_stream(flist[1], ByWord); - fl[2] = split_stream(flist[2], ByWord); - } + if (obj == 'l') + blanks |= ByLine; + else + blanks |= ByWord; + fl[0] = split_stream(flist[0], blanks); + fl[1] = split_stream(flist[1], blanks); + fl[2] = split_stream(flist[2], blanks); + if (chunks2 && !chunks1) csl1 = pdiff(fl[0], fl[1], chunks2); else @@ -584,7 +583,7 @@ static int do_merge(int argc, char *argv[], int obj, return (ci.conflicts > 0); } -static int multi_merge(int argc, char *argv[], int obj, +static int multi_merge(int argc, char *argv[], int obj, int blanks, int reverse, int ignore, int show_wiggles, int replace, int strip, int quiet) @@ -628,7 +627,7 @@ static int multi_merge(int argc, char *argv[], int obj, pl[i].start, pl[i].end, filename); av[0] = pl[i].file; av[1] = name; - rv |= do_merge(2, av, obj, reverse, 1, ignore, + rv |= do_merge(2, av, obj, blanks, reverse, 1, ignore, show_wiggles, quiet); } return rv; @@ -652,6 +651,7 @@ int main(int argc, char *argv[]) char *helpmsg; char *trace; int selftest = 0; + int ignore_blanks = 0; trace = getenv("WIGGLE_TRACE"); if (trace && *trace) @@ -719,6 +719,10 @@ int main(int argc, char *argv[]) reverse = 1; continue; + case 'b': + ignore_blanks = IgnoreBlanks; + continue; + case 'i': ignore = 0; continue; @@ -760,7 +764,8 @@ int main(int argc, char *argv[]) if (mode == 'B') { vpatch(argc-optind, argv+optind, ispatch, - strip, reverse, replace, selftest); + strip, reverse, replace, selftest, + ignore_blanks); /* should not return */ exit(1); } @@ -801,19 +806,25 @@ int main(int argc, char *argv[]) exit_status = extract(argc-optind, argv+optind, ispatch, which); break; case 'd': - exit_status = do_diff(argc-optind, argv+optind, obj, ispatch, which, reverse); + exit_status = do_diff(argc-optind, argv+optind, + (obj == 'l' ? ByLine : ByWord) + | ignore_blanks, + ispatch, which, reverse); break; case 'm': if (ispatch) exit_status = multi_merge(argc-optind, argv+optind, obj, + ignore_blanks, reverse, ignore, show_wiggles, replace, strip, quiet); else - exit_status = do_merge(argc-optind, argv+optind, obj, reverse, replace, - ignore, show_wiggles, quiet); + exit_status = do_merge( + argc-optind, argv+optind, + obj, ignore_blanks, reverse, replace, + ignore, show_wiggles, quiet); break; } exit(exit_status); diff --git a/wiggle.h b/wiggle.h index 8043da4..c8fef5f 100644 --- a/wiggle.h +++ b/wiggle.h @@ -183,7 +183,8 @@ extern void *xmalloc(int len); extern int do_trace; extern int vpatch(int argc, char *argv[], int patch, int strip, - int reverse, int replace, int selftest); + int reverse, int replace, int selftest, + int ignore_blanks); extern char *Cmd; extern char Version[]; @@ -202,6 +203,8 @@ extern char HelpBrowse[]; extern void cleanlist(struct file a, struct file b, struct csl *list); enum { - ByLine, - ByWord, + ByLine = 0, + ByWord = 1, + ByMask = 3, + IgnoreBlanks = 8, /* 'or'ed in */ }; -- 2.39.5