From db9cccfbb1a724acf65756da9439009da433b810 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 20 Apr 2020 16:14:44 +0000 Subject: diff(1): reject conflicting formatting options This matches GNU diff(1) behavior and, more importantly, eliminates any source of confusion if multiple formatting options are specified. Note that the committed diff differs slightly from the submitted: I've modified it so that we initialize diff_format to something that isn't an accepted format option so that we can also reject --normal -c and -c --normal, which would've otherwise been accepted because the default was --normal. After option parsing we default it to D_NORMAL if it's still unset. PR: 243975 Submitted by: fehmi noyan isi MFC after: 1 week --- usr.bin/diff/diff.c | 35 +++++++++++++++++++++++++++++++++-- usr.bin/diff/diff.h | 3 +++ usr.bin/diff/tests/diff_test.sh | 18 ++++++++++++++++-- 3 files changed, 52 insertions(+), 4 deletions(-) (limited to 'usr.bin/diff') diff --git a/usr.bin/diff/diff.c b/usr.bin/diff/diff.c index a4e86b7855a8..91928651b188 100644 --- a/usr.bin/diff/diff.c +++ b/usr.bin/diff/diff.c @@ -100,6 +100,7 @@ static struct option longopts[] = { }; void usage(void) __dead2; +void conflicting_format(void) __dead2; void push_excludes(char *); void push_ignore_pats(char *); void read_excludes_file(char *file); @@ -120,7 +121,7 @@ main(int argc, char **argv) prevoptind = 1; newarg = 1; diff_context = 3; - diff_format = 0; + diff_format = D_UNSET; while ((ch = getopt_long(argc, argv, OPTIONS, longopts, NULL)) != -1) { switch (ch) { case '0': case '1': case '2': case '3': case '4': @@ -141,6 +142,8 @@ main(int argc, char **argv) break; case 'C': case 'c': + if (diff_format != D_UNSET) + conflicting_format(); cflag = 1; diff_format = D_CONTEXT; if (optarg != NULL) { @@ -154,13 +157,19 @@ main(int argc, char **argv) dflags |= D_MINIMAL; break; case 'D': + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_IFDEF; ifdefname = optarg; break; case 'e': + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_EDIT; break; case 'f': + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_REVERSE; break; case 'H': @@ -193,10 +202,12 @@ main(int argc, char **argv) Nflag = 1; break; case 'n': + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_NREVERSE; break; case 'p': - if (diff_format == 0) + if (diff_format == D_UNSET) diff_format = D_CONTEXT; dflags |= D_PROTOTYPE; break; @@ -207,6 +218,8 @@ main(int argc, char **argv) rflag = 1; break; case 'q': + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_BRIEF; break; case 'S': @@ -223,6 +236,8 @@ main(int argc, char **argv) break; case 'U': case 'u': + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_UNIFIED; if (optarg != NULL) { l = strtol(optarg, &ep, 10); @@ -249,9 +264,13 @@ main(int argc, char **argv) push_excludes(optarg); break; case 'y': + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_SIDEBYSIDE; break; case OPT_CHANGED_GROUP_FORMAT: + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_GFORMAT; group_format = optarg; break; @@ -264,6 +283,8 @@ main(int argc, char **argv) ignore_file_case = 0; break; case OPT_NORMAL: + if (diff_format != D_UNSET) + conflicting_format(); diff_format = D_NORMAL; break; case OPT_TSIZE: @@ -287,6 +308,8 @@ main(int argc, char **argv) newarg = optind != prevoptind; prevoptind = optind; } + if (diff_format == D_UNSET) + diff_format = D_NORMAL; argc -= optind; argv += optind; @@ -491,3 +514,11 @@ usage(void) exit(2); } + +void +conflicting_format(void) +{ + + fprintf(stderr, "error: conflicting output format options.\n"); + usage(); +} diff --git a/usr.bin/diff/diff.h b/usr.bin/diff/diff.h index 6a2c4cbea721..30387610fc19 100644 --- a/usr.bin/diff/diff.h +++ b/usr.bin/diff/diff.h @@ -50,6 +50,9 @@ #define D_GFORMAT 7 /* Diff with defined changed group format */ #define D_SIDEBYSIDE 8 /* Side by side */ +#define D_UNSET -2 + + /* * Output flags */ diff --git a/usr.bin/diff/tests/diff_test.sh b/usr.bin/diff/tests/diff_test.sh index b605c4733f09..8385a6224865 100755 --- a/usr.bin/diff/tests/diff_test.sh +++ b/usr.bin/diff/tests/diff_test.sh @@ -11,6 +11,7 @@ atf_test_case brief_format atf_test_case b230049 atf_test_case Bflag atf_test_case tabsize +atf_test_case conflicting_format simple_body() { @@ -49,8 +50,6 @@ unified_body() { atf_check -o file:$(atf_get_srcdir)/unified_p.out -s eq:1 \ diff -up -L input_c1.in -L input_c2.in "$(atf_get_srcdir)/input_c1.in" "$(atf_get_srcdir)/input_c2.in" - atf_check -o file:$(atf_get_srcdir)/unified_c9999.out -s eq:1 \ - diff -u -c9999 -L input_c1.in -L input_c2.in "$(atf_get_srcdir)/input_c1.in" "$(atf_get_srcdir)/input_c2.in" atf_check -o file:$(atf_get_srcdir)/unified_9999.out -s eq:1 \ diff -u9999 -L input_c1.in -L input_c2.in "$(atf_get_srcdir)/input_c1.in" "$(atf_get_srcdir)/input_c2.in" } @@ -175,6 +174,20 @@ tabsize_body() diff -t --tabsize 1 A B } +conflicting_format_body() +{ + printf "\tA\n" > A + printf "\tB\n" > B + + atf_check -s exit:2 -e ignore diff -c -u A B + atf_check -s exit:2 -e ignore diff -e -f A B + atf_check -s exit:2 -e ignore diff -y -q A B + atf_check -s exit:2 -e ignore diff -q -u A B + atf_check -s exit:2 -e ignore diff -q -c A B + atf_check -s exit:2 -e ignore diff --normal -c A B + atf_check -s exit:2 -e ignore diff -c --normal A B +} + atf_init_test_cases() { atf_add_test_case simple @@ -188,4 +201,5 @@ atf_init_test_cases() atf_add_test_case b230049 atf_add_test_case Bflag atf_add_test_case tabsize + atf_add_test_case conflicting_format } -- cgit v1.3