diff --git a/usr.bin/diff3/diff3.1 b/usr.bin/diff3/diff3.1 index f0fd481c75f1..6968af44bfbd 100644 --- a/usr.bin/diff3/diff3.1 +++ b/usr.bin/diff3/diff3.1 @@ -38,7 +38,7 @@ .Nd 3-way differential file comparison .Sh SYNOPSIS .Nm diff3 -.Op Fl 3AaEeiTXx +.Op Fl 3AaEeimTXx .Op Fl Fl diff-program Ar program .Op Fl Fl strip-trailing-cr .Op Fl L | Fl Fl label Ar label1 @@ -117,6 +117,8 @@ Defines labels to print instead of file names .Ar file2 and .Ar file3 . +.It Fl m, Fl Fl merge +Merge output instead of generating ed script. .It Fl T, Fl Fl initial-tab In the normal listing, use a tab instead of two spaces diff --git a/usr.bin/diff3/diff3.c b/usr.bin/diff3/diff3.c index 5df6357065fc..629e23288875 100644 --- a/usr.bin/diff3/diff3.c +++ b/usr.bin/diff3/diff3.c @@ -153,6 +153,7 @@ static void prange(struct range *, bool); static void repos(int); static void edscript(int) __dead2; static void Ascript(int) __dead2; +static void mergescript(int) __dead2; static void increase(void); static void usage(void) __dead2; static void printrange(FILE *, struct range *); @@ -389,7 +390,9 @@ merge(int m1, int m2) } } - if (Aflag) + if (mflag) + mergescript(j); + else if (Aflag) Ascript(j); else if (eflag) edscript(j); @@ -687,6 +690,86 @@ Ascript(int n) exit(overlapcnt > 0); } +/* + * Output the merged file directly (don't generate an ed script). When + * regurgitating diffs we need to walk forward through the file and print any + * inbetween lines. + */ +static void +mergescript(int i) +{ + struct range r; + int n; + + r.from = 1; + r.to = 1; + + for (n = 1; n < i+1; n++) { + /* print any lines leading up to here */ + r.to = de[n].old.from; + printrange(fp[0], &r); + + if (de[n].type == DIFF_TYPE2) { + printf("%s %s\n", oldmark, f2mark); + printrange(fp[1], &de[n].old); + printf("=======\n"); + printrange(fp[2], &de[n].new); + printf("%s %s\n", newmark, f3mark); + } else if (de[n].type == DIFF_TYPE3) { + if (!oflag || !overlap[n]) { + printrange(fp[2], &de[n].new); + } else { + + printf("%s %s\n", oldmark, f1mark); + printrange(fp[0], &de[n].old); + + printf("%s %s\n", orgmark, f2mark); + if (de[n].old.from == de[n].old.to) { + struct range or; + or.from = de[n].old.from -1; + or.to = de[n].new.to; + printrange(fp[1], &or); + } else + printrange(fp[1], &de[n].old); + + printf("=======\n"); + + printrange(fp[2], &de[n].new); + printf("%s %s\n", newmark, f3mark); + } + } + + if (de[n].old.from == de[n].old.to) + r.from = de[n].new.to; + else + r.from = de[n].old.to; + } + /* + * Print from the final range to the end of 'myfile'. Any deletions or + * additions to this file should have been handled by now. + * + * If the ranges are the same we need to rewind a line. + * If the new range is 0 length (from == to), we need to use the old + * range. + */ + if ((de[n-1].old.from == de[n-1].new.from) && + (de[n-1].old.to == de[n-1].new.to)) + r.from--; + else if (de[n-1].new.from == de[n-1].new.to) + r.from = de[n-1].old.from; + + /* + * If the range is a 3 way merge then we need to skip a line in the + * trailing output. + */ + if (de[n-1].type == DIFF_TYPE3) + r.from++; + + r.to = INT_MAX; + printrange(fp[0], &r); + exit(overlapcnt > 0); +} + static void increase(void) { diff --git a/usr.bin/diff3/tests/Makefile b/usr.bin/diff3/tests/Makefile index fc69dea260e8..0785e78aaee3 100644 --- a/usr.bin/diff3/tests/Makefile +++ b/usr.bin/diff3/tests/Makefile @@ -22,6 +22,7 @@ ${PACKAGE}FILES+= \ 8.out \ 9.out \ long-ed.out \ - long-A.out + long-A.out \ + long-merge.out \ .include diff --git a/usr.bin/diff3/tests/diff3_test.sh b/usr.bin/diff3/tests/diff3_test.sh index 8df84b0d8ff2..c30f258128af 100755 --- a/usr.bin/diff3/tests/diff3_test.sh +++ b/usr.bin/diff3/tests/diff3_test.sh @@ -4,6 +4,7 @@ atf_test_case diff3 atf_test_case diff3_lesssimple atf_test_case diff3_ed atf_test_case diff3_A +atf_test_case diff3_merge diff3_body() { @@ -56,10 +57,22 @@ diff3_A_body() diff3 -A -L long-m.txt -L long-o.txt -L long-y.txt $(atf_get_srcdir)/long-m.txt $(atf_get_srcdir)/long-o.txt $(atf_get_srcdir)/long-y.txt } + +diff3_merge_body() +{ + atf_check -s exit:1 -o file:$(atf_get_srcdir)/9.out \ + diff3 -m -L 1 -L 2 -L 3 $(atf_get_srcdir)/1.txt $(atf_get_srcdir)/2.txt $(atf_get_srcdir)/3.txt + atf_check -s exit:1 -o file:$(atf_get_srcdir)/tao-merge.out \ + diff3 -m -L lao.txt -L tzu.txt -L tao.txt $(atf_get_srcdir)/lao.txt $(atf_get_srcdir)/tzu.txt $(atf_get_srcdir)/tao.txt + atf_check -s exit:1 -o file:$(atf_get_srcdir)/long-merge.out \ + diff3 -m -L long-m.txt -L long-o.txt -L long-y.txt $(atf_get_srcdir)/long-m.txt $(atf_get_srcdir)/long-o.txt $(atf_get_srcdir)/long-y.txt +} + atf_init_test_cases() { atf_add_test_case diff3 # atf_add_test_case diff3_lesssimple atf_add_test_case diff3_ed atf_add_test_case diff3_A + atf_add_test_case diff3_merge } diff --git a/usr.bin/diff3/tests/long-merge.out b/usr.bin/diff3/tests/long-merge.out new file mode 100644 index 000000000000..5139a48fa429 --- /dev/null +++ b/usr.bin/diff3/tests/long-merge.out @@ -0,0 +1,35 @@ +This is a long file +These lines are the same in all three files +These lines are the same in all three files +This line is different in mine, not better +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +This line is different in yours, much butter +These lines are the same in all three files +These lines are the same in all three files +<<<<<<< long-o.txt +This line is different in yours and mine, but the same +======= +This line is different in yours and mine, the same is in both +>>>>>>> long-y.txt +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +<<<<<<< long-m.txt +This line is different in yours and mine, best change in mine +||||||| long-o.txt +This line is different in yours and mine, but the different in each +======= +This line is different in yours and mine, but the best in yours +>>>>>>> long-y.txt +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files +These lines are the same in all three files