]> git.neil.brown.name Git - wiggle.git/commitdiff
Add --ignore-blanks option.
authorNeilBrown <neilb@suse.de>
Tue, 5 Mar 2013 04:00:17 +0000 (15:00 +1100)
committerNeilBrown <neilb@suse.de>
Tue, 5 Mar 2013 04:00:17 +0000 (15:00 +1100)
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 <tom.scogland@vt.edu>
Signed-off-by: NeilBrown <neilb@suse.de>
ReadMe.c
dotest
split.c
tests/contrib/abstract/bmerge [new file with mode: 0644]
tests/contrib/abstract/new [new file with mode: 0644]
tests/contrib/abstract/new2 [new file with mode: 0644]
tests/contrib/abstract/orig [new file with mode: 0644]
vpatch.c
wiggle.1
wiggle.c
wiggle.h

index 443011736f90be3b048f7cc30614157f08df7f07..1a171a2ddd43ea53e7fd02b817d6460b5f8bcbf7 100644 (file)
--- 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 0f622118025c959a7881395d4623ef26541a20ce..e718f13c9d1e86e16652d42a0bb5159a39eae9cb 100755 (executable)
--- 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 a2880acb8a7bf6a16adc45144d30980154cda4b3..ba2cb2687fdc8f4d121254d4b5da67c669d340f6 100644 (file)
--- 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 (file)
index 0000000..e9ba52c
--- /dev/null
@@ -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 (file)
index 0000000..16b0038
--- /dev/null
@@ -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 (file)
index 0000000..8f4c8a4
--- /dev/null
@@ -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 (file)
index 0000000..73ba1a8
--- /dev/null
@@ -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 }
index 5437a849f98d148e19cf44f46549b2998a4b80da..5b265f2eb9e6186b8257d7c16968a54c442d9664 100644 (file)
--- 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;
        }
 
index 9154d4c4af1f3783821fa9da5ae1d2a1bfeaf8fc..18591c7e9ae7ddf4d07517555757c3027d7c126e 100644 (file)
--- 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)
index f084957202d85d025ec989ae9e438d296fb73101..9b4c02c2753a1ff4c6368eb2d36368d80cd10ac3 100644 (file)
--- 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);
index 8043da45871134a5dd46dc901208dcf12c7ffef6..c8fef5f8642b74bf5b396d65f26e8b8dc4a5985c 100644 (file)
--- 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 */
 };