From 375aa6204312ee63a0188ab63e5b1018290d3f8d Mon Sep 17 00:00:00 2001
From: Andreas Metzler <ametzler@bebt.de>
Date: Wed, 11 Oct 2017 00:47:08 +0200
Subject: [PATCH] xargs: warn on conflicting options -L, -I, -n

* xargs/xargs.c (warn_mutually_exclusive): Add function to output the
new warning diagnostic.
(main): Call the above new function in order to show a warning message
if conflicting options (-L -l -I -i -n) are specified.
* xargs/xargs.1: Explicitly document the fact that -L -l -I -i -n
options are mutually exclusive and how xargs behaves when more than one
of these options are specified.
* doc/find.texi (node Conflicting xargs options): Likewise.
* xargs/testsuite/config/unix.exp (xargs_start): Replace the full path
of the xargs executable in the stderr output file by its basename.
* xargs/testsuite/xargs.gnu/P3-n1-IARG.xe: Add file containing the
expected output with the new warning diagnostic.
* xargs/testsuite/xargs.posix/L2-n2.xe: Likewise.
* xargs/testsuite/xargs.posix/rc-123.xe: Likewise.
* xargs/testsuite/xargs.sysv/l1n4.xe: Likewise.
* xargs/testsuite/xargs/testsuite/xargs.gnu/P3-n1-IARG.exp: Ensure the
error diagnostic is in C locale to avoid false positives in other locales.
* xargs/testsuite/xargs.posix/L2-n2.exp: Likewise.
* xargs/testsuite/xargs.posix/rc-123.exp: Likewise.
* xargs/testsuite/xargs.sysv/l1n4.exp: Likewise.
* xargs/testsuite/xargs.gnu/conflicting_*: Add test coverage
for combinations of -I -L and -n.
* xargs/testsuite/Makefile.am (EXTRA_DIST_EXP): Reference the new tests.
(EXTRA_DIST_XO): Reference the new *.xo files.
(EXTRA_DIST_XE): Reference the new *.xe files.
* NEWS (Improvements): Mention the change.

Co-authored-by: Bernhard Voelker <mail@bernhard-voelker.de>
---
 NEWS                                            |  3 +++
 doc/find.texi                                   | 21 ++++++++++++++++++
 xargs/testsuite/Makefile.am                     | 27 +++++++++++++++++++++++
 xargs/testsuite/config/unix.exp                 |  1 +
 xargs/testsuite/xargs.gnu/P3-n1-IARG.exp        |  1 +
 xargs/testsuite/xargs.gnu/P3-n1-IARG.xe         |  1 +
 xargs/testsuite/xargs.gnu/conflicting_I_L2.exp  |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_I_L2.xe   |  1 +
 xargs/testsuite/xargs.gnu/conflicting_I_L2.xo   |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_I_n1.exp  |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_I_n1.xo   |  1 +
 xargs/testsuite/xargs.gnu/conflicting_I_n2.exp  |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_I_n2.xe   |  1 +
 xargs/testsuite/xargs.gnu/conflicting_I_n2.xo   |  6 +++++
 xargs/testsuite/xargs.gnu/conflicting_L2_I.exp  |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_L2_I.xe   |  1 +
 xargs/testsuite/xargs.gnu/conflicting_L2_I.xo   |  4 ++++
 xargs/testsuite/xargs.gnu/conflicting_L2_n2.exp |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_L2_n2.xe  |  1 +
 xargs/testsuite/xargs.gnu/conflicting_L2_n2.xo  |  6 +++++
 xargs/testsuite/xargs.gnu/conflicting_n1_I.exp  |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_n1_I.xe   |  1 +
 xargs/testsuite/xargs.gnu/conflicting_n1_I.xo   |  4 ++++
 xargs/testsuite/xargs.gnu/conflicting_n2_I.exp  |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_n2_I.xe   |  1 +
 xargs/testsuite/xargs.gnu/conflicting_n2_I.xo   |  4 ++++
 xargs/testsuite/xargs.gnu/conflicting_n2_L2.exp |  2 ++
 xargs/testsuite/xargs.gnu/conflicting_n2_L2.xe  |  1 +
 xargs/testsuite/xargs.gnu/conflicting_n2_L2.xo  |  2 ++
 xargs/testsuite/xargs.posix/L2-n2.exp           |  1 +
 xargs/testsuite/xargs.posix/L2-n2.xe            |  1 +
 xargs/testsuite/xargs.posix/rc-123.exp          |  1 +
 xargs/testsuite/xargs.posix/rc-123.xe           |  1 +
 xargs/testsuite/xargs.sysv/l1n4.exp             |  1 +
 xargs/testsuite/xargs.sysv/l1n4.xe              |  1 +
 xargs/xargs.1                                   | 29 ++++++++++++++++++++-----
 xargs/xargs.c                                   | 25 +++++++++++++++++++++
 37 files changed, 160 insertions(+), 6 deletions(-)
 create mode 100644 xargs/testsuite/xargs.gnu/P3-n1-IARG.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_L2.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_L2.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_L2.xo
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_n1.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_n1.xo
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_n2.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_n2.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_I_n2.xo
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_L2_I.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_L2_I.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_L2_I.xo
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_L2_n2.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_L2_n2.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_L2_n2.xo
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n1_I.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n1_I.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n1_I.xo
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n2_I.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n2_I.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n2_I.xo
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n2_L2.exp
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n2_L2.xe
 create mode 100644 xargs/testsuite/xargs.gnu/conflicting_n2_L2.xo
 create mode 100644 xargs/testsuite/xargs.posix/L2-n2.xe
 create mode 100644 xargs/testsuite/xargs.posix/rc-123.xe
 create mode 100644 xargs/testsuite/xargs.sysv/l1n4.xe

diff --git a/NEWS b/NEWS
index 29aef53..3e47b64 100644
--- a/NEWS
+++ b/NEWS
@@ -46,6 +46,9 @@ xargs now supports the -o, --open-tty option to reopen stdin as /dev/tty
 in the child process before executing the command; useful to run an
 interactive application.  Added for compatibility with BSD.
 
+xargs now warns when more than one of the conflicting options --max-lines,
+--replace and --max-args are specified on the command line.
+
 ** Documentation Changes
 
 Some minor documentation improvements are listed in "Bug Fixes" below.
diff --git a/doc/find.texi b/doc/find.texi
index bf0a4ed..385b335 100644
--- a/doc/find.texi
+++ b/doc/find.texi
@@ -3663,6 +3663,7 @@ a program died due to a fatal signal.
 @menu
 * xargs options::
 * Invoking the shell from xargs::
+* Conflicting xargs options::
 @end menu
 
 @node xargs options
@@ -3811,6 +3812,26 @@ integer.  Values are reused once child processes exit.  This can be
 used in a rudimentary load distribution scheme, for example.
 @end table
 
+@node Conflicting xargs options
+@subsection Conflicting options
+The options @samp{--max-lines} (@samp{-L}, @samp{-l}), @samp{--replace}
+(@samp{-I}, @samp{-i}) and @samp{--max-args} (@samp{-n}) are mutually exclusive.
+
+If some of them are specified at the same time, then @code{xargs} will
+generally use the option specified last on the commandline, i.e., it will
+reset the value of the offending option (given before) to its default value.
+Additionally, @code{xargs} will issue a warning diagnostic on @file{stderr}.
+
+@example
+$ seq 4 | xargs -l2 -n3
+xargs: warning: options -L,-l and -n are mutually exclusive, ignoring previous -L,-l value
+1 2 3
+4
+@end example
+
+The exception to this rule is that @code{-n1} is ignored as a noop after
+@samp{-I} or @samp{-i} because these two options do not actually conflict.
+
 @node Invoking the shell from xargs
 @subsection Invoking the shell from xargs
 
diff --git a/xargs/testsuite/Makefile.am b/xargs/testsuite/Makefile.am
index 7f3f681..5622b55 100644
--- a/xargs/testsuite/Makefile.am
+++ b/xargs/testsuite/Makefile.am
@@ -29,6 +29,14 @@ DEJATOOL = xargs
 EXTRA_DIST_EXP = \
 config/unix.exp \
 xargs.gnu/0n3.exp \
+xargs.gnu/conflicting_I_L2.exp \
+xargs.gnu/conflicting_I_n1.exp \
+xargs.gnu/conflicting_I_n2.exp \
+xargs.gnu/conflicting_L2_I.exp \
+xargs.gnu/conflicting_L2_n2.exp \
+xargs.gnu/conflicting_n1_I.exp \
+xargs.gnu/conflicting_n2_I.exp \
+xargs.gnu/conflicting_n2_L2.exp \
 xargs.gnu/delim-o.exp \
 xargs.gnu/E_-0.exp \
 xargs.gnu/empty_def-r.exp \
@@ -130,6 +138,14 @@ xargs.sysv/trace.exp
 EXTRA_DIST_XO = \
 xargs.gnu/0n3.xo \
 xargs.gnu/E_-0.xo \
+xargs.gnu/conflicting_I_L2.xo \
+xargs.gnu/conflicting_I_n1.xo \
+xargs.gnu/conflicting_I_n2.xo \
+xargs.gnu/conflicting_L2_I.xo \
+xargs.gnu/conflicting_L2_n2.xo \
+xargs.gnu/conflicting_n1_I.xo \
+xargs.gnu/conflicting_n2_I.xo \
+xargs.gnu/conflicting_n2_L2.xo \
 xargs.gnu/delim-o.xo \
 xargs.gnu/idef-0.xo \
 xargs.gnu/idef-s26-0.xo \
@@ -213,9 +229,20 @@ xargs.sysv/trace.xo
 
 
 EXTRA_DIST_XE = \
+xargs.gnu/conflicting_I_L2.xe \
+xargs.gnu/conflicting_I_n2.xe \
+xargs.gnu/conflicting_L2_I.xe \
+xargs.gnu/conflicting_L2_n2.xe \
+xargs.gnu/conflicting_n1_I.xe \
+xargs.gnu/conflicting_n2_I.xe \
+xargs.gnu/conflicting_n2_L2.xe \
+xargs.gnu/P3-n1-IARG.xe \
 xargs.gnu/space-t-0.xe \
+xargs.posix/L2-n2.xe \
+xargs.posix/rc-123.xe \
 xargs.sysv/empty_def-t.xe \
 xargs.sysv/empty-t.xe \
+xargs.sysv/l1n4.xe \
 xargs.sysv/s25-t.xe \
 xargs.sysv/space-t.xe \
 xargs.sysv/trace.xe
diff --git a/xargs/testsuite/config/unix.exp b/xargs/testsuite/config/unix.exp
index a870858..1188a57 100644
--- a/xargs/testsuite/config/unix.exp
+++ b/xargs/testsuite/config/unix.exp
@@ -156,6 +156,7 @@ proc xargs_start { passfail options {infile ""} {errh ""} {command ""} } {
     # if stderr check is enabled,
     if {$errfile != ""} then {
 	if {[file exists $errfile]} then {
+	    catch "exec sed -i s/^.*xargs:/xargs:/ xargs.err" tmp
 	    set cmp_cmd "cmp xargs.err $errfile"
 	    send_log "$cmp_cmd\n"
 	    catch "exec $cmp_cmd" cmperr
diff --git a/xargs/testsuite/xargs.gnu/P3-n1-IARG.exp b/xargs/testsuite/xargs.gnu/P3-n1-IARG.exp
index 7579589..5ff49d8 100644
--- a/xargs/testsuite/xargs.gnu/P3-n1-IARG.exp
+++ b/xargs/testsuite/xargs.gnu/P3-n1-IARG.exp
@@ -1 +1,2 @@
+set env(LC_ALL) "C"
 xargs_start p {-P3 -n1 -IARG sh -c ARG} Pdata.xi
diff --git a/xargs/testsuite/xargs.gnu/P3-n1-IARG.xe b/xargs/testsuite/xargs.gnu/P3-n1-IARG.xe
new file mode 100644
index 0000000..1dbd52f
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/P3-n1-IARG.xe
@@ -0,0 +1 @@
+xargs: warning: options -n and -I,-i are mutually exclusive, ignoring previous -n value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_L2.exp b/xargs/testsuite/xargs.gnu/conflicting_I_L2.exp
new file mode 100644
index 0000000..62971f0
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_L2.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-I REPL -L2 echo REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_L2.xe b/xargs/testsuite/xargs.gnu/conflicting_I_L2.xe
new file mode 100644
index 0000000..36759b9
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_L2.xe
@@ -0,0 +1 @@
+xargs: warning: options -I,-i and -L are mutually exclusive, ignoring previous -I,-i value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_L2.xo b/xargs/testsuite/xargs.gnu/conflicting_I_L2.xo
new file mode 100644
index 0000000..f6d42a8
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_L2.xo
@@ -0,0 +1,2 @@
+REPL first nonblank line second nonblank line
+REPL third nonblank line fourth nonblank line
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_n1.exp b/xargs/testsuite/xargs.gnu/conflicting_I_n1.exp
new file mode 100644
index 0000000..9872e26
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_n1.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-I REPL -n1 echo REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_n1.xo b/xargs/testsuite/xargs.gnu/conflicting_I_n1.xo
new file mode 100644
index 0000000..5d92c07
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_n1.xo
@@ -0,0 +1 @@
+REPL first nonblank line second nonblank line third nonblank line fourth nonblank line
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_n2.exp b/xargs/testsuite/xargs.gnu/conflicting_I_n2.exp
new file mode 100644
index 0000000..005ffa5
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_n2.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-I REPL -n2 echo REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_n2.xe b/xargs/testsuite/xargs.gnu/conflicting_I_n2.xe
new file mode 100644
index 0000000..2da6e2c
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_n2.xe
@@ -0,0 +1 @@
+xargs: warning: options -I,-i and -n are mutually exclusive, ignoring previous -I,-i value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_I_n2.xo b/xargs/testsuite/xargs.gnu/conflicting_I_n2.xo
new file mode 100644
index 0000000..2eee060
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_I_n2.xo
@@ -0,0 +1,6 @@
+REPL first nonblank
+REPL line second
+REPL nonblank line
+REPL third nonblank
+REPL line fourth
+REPL nonblank line
diff --git a/xargs/testsuite/xargs.gnu/conflicting_L2_I.exp b/xargs/testsuite/xargs.gnu/conflicting_L2_I.exp
new file mode 100644
index 0000000..12d005f
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_L2_I.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-L2 -I REPL echo REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_L2_I.xe b/xargs/testsuite/xargs.gnu/conflicting_L2_I.xe
new file mode 100644
index 0000000..27a2ab7
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_L2_I.xe
@@ -0,0 +1 @@
+xargs: warning: options -L,-l and -I,-i are mutually exclusive, ignoring previous -L,-l value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_L2_I.xo b/xargs/testsuite/xargs.gnu/conflicting_L2_I.xo
new file mode 100644
index 0000000..3d6b0f8
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_L2_I.xo
@@ -0,0 +1,4 @@
+first nonblank line
+second nonblank line
+third nonblank line
+fourth nonblank line
diff --git a/xargs/testsuite/xargs.gnu/conflicting_L2_n2.exp b/xargs/testsuite/xargs.gnu/conflicting_L2_n2.exp
new file mode 100644
index 0000000..7fb7f9f
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_L2_n2.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-L2 -n2 echo REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_L2_n2.xe b/xargs/testsuite/xargs.gnu/conflicting_L2_n2.xe
new file mode 100644
index 0000000..0ec24b3
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_L2_n2.xe
@@ -0,0 +1 @@
+xargs: warning: options -L,-l and -n are mutually exclusive, ignoring previous -L,-l value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_L2_n2.xo b/xargs/testsuite/xargs.gnu/conflicting_L2_n2.xo
new file mode 100644
index 0000000..2eee060
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_L2_n2.xo
@@ -0,0 +1,6 @@
+REPL first nonblank
+REPL line second
+REPL nonblank line
+REPL third nonblank
+REPL line fourth
+REPL nonblank line
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n1_I.exp b/xargs/testsuite/xargs.gnu/conflicting_n1_I.exp
new file mode 100644
index 0000000..cb82f27
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n1_I.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-n1 -I REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n1_I.xe b/xargs/testsuite/xargs.gnu/conflicting_n1_I.xe
new file mode 100644
index 0000000..1dbd52f
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n1_I.xe
@@ -0,0 +1 @@
+xargs: warning: options -n and -I,-i are mutually exclusive, ignoring previous -n value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n1_I.xo b/xargs/testsuite/xargs.gnu/conflicting_n1_I.xo
new file mode 100644
index 0000000..fd40910
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n1_I.xo
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n2_I.exp b/xargs/testsuite/xargs.gnu/conflicting_n2_I.exp
new file mode 100644
index 0000000..eb22728
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n2_I.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-n2 -I REPL echo REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n2_I.xe b/xargs/testsuite/xargs.gnu/conflicting_n2_I.xe
new file mode 100644
index 0000000..1dbd52f
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n2_I.xe
@@ -0,0 +1 @@
+xargs: warning: options -n and -I,-i are mutually exclusive, ignoring previous -n value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n2_I.xo b/xargs/testsuite/xargs.gnu/conflicting_n2_I.xo
new file mode 100644
index 0000000..3d6b0f8
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n2_I.xo
@@ -0,0 +1,4 @@
+first nonblank line
+second nonblank line
+third nonblank line
+fourth nonblank line
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n2_L2.exp b/xargs/testsuite/xargs.gnu/conflicting_n2_L2.exp
new file mode 100644
index 0000000..7adb30f
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n2_L2.exp
@@ -0,0 +1,2 @@
+set env(LC_ALL) "C"
+xargs_start p {-n2 -L2 echo REPL} lines.xi
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n2_L2.xe b/xargs/testsuite/xargs.gnu/conflicting_n2_L2.xe
new file mode 100644
index 0000000..1d013ba
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n2_L2.xe
@@ -0,0 +1 @@
+xargs: warning: options -n and -L are mutually exclusive, ignoring previous -n value
diff --git a/xargs/testsuite/xargs.gnu/conflicting_n2_L2.xo b/xargs/testsuite/xargs.gnu/conflicting_n2_L2.xo
new file mode 100644
index 0000000..f6d42a8
--- /dev/null
+++ b/xargs/testsuite/xargs.gnu/conflicting_n2_L2.xo
@@ -0,0 +1,2 @@
+REPL first nonblank line second nonblank line
+REPL third nonblank line fourth nonblank line
diff --git a/xargs/testsuite/xargs.posix/L2-n2.exp b/xargs/testsuite/xargs.posix/L2-n2.exp
index 88a939f..9a979cc 100644
--- a/xargs/testsuite/xargs.posix/L2-n2.exp
+++ b/xargs/testsuite/xargs.posix/L2-n2.exp
@@ -1 +1,2 @@
+set env(LC_ALL) "C"
 xargs_start p {-L2 -n2} ldata.xi
diff --git a/xargs/testsuite/xargs.posix/L2-n2.xe b/xargs/testsuite/xargs.posix/L2-n2.xe
new file mode 100644
index 0000000..0ec24b3
--- /dev/null
+++ b/xargs/testsuite/xargs.posix/L2-n2.xe
@@ -0,0 +1 @@
+xargs: warning: options -L,-l and -n are mutually exclusive, ignoring previous -L,-l value
diff --git a/xargs/testsuite/xargs.posix/rc-123.exp b/xargs/testsuite/xargs.posix/rc-123.exp
index 217de0f..1bcf490 100644
--- a/xargs/testsuite/xargs.posix/rc-123.exp
+++ b/xargs/testsuite/xargs.posix/rc-123.exp
@@ -1 +1,2 @@
+set env(LC_ALL) "C"
 xargs_start 123 {-n1 -IARG sh -c ARG} ftt.xi
diff --git a/xargs/testsuite/xargs.posix/rc-123.xe b/xargs/testsuite/xargs.posix/rc-123.xe
new file mode 100644
index 0000000..1dbd52f
--- /dev/null
+++ b/xargs/testsuite/xargs.posix/rc-123.xe
@@ -0,0 +1 @@
+xargs: warning: options -n and -I,-i are mutually exclusive, ignoring previous -n value
diff --git a/xargs/testsuite/xargs.sysv/l1n4.exp b/xargs/testsuite/xargs.sysv/l1n4.exp
index 4eef466..26a586f 100644
--- a/xargs/testsuite/xargs.sysv/l1n4.exp
+++ b/xargs/testsuite/xargs.sysv/l1n4.exp
@@ -1 +1,2 @@
+set env(LC_ALL) "C"
 xargs_start p {-l1 -n4} files.xi
diff --git a/xargs/testsuite/xargs.sysv/l1n4.xe b/xargs/testsuite/xargs.sysv/l1n4.xe
new file mode 100644
index 0000000..0ec24b3
--- /dev/null
+++ b/xargs/testsuite/xargs.sysv/l1n4.xe
@@ -0,0 +1 @@
+xargs: warning: options -L,-l and -n are mutually exclusive, ignoring previous -L,-l value
diff --git a/xargs/xargs.1 b/xargs/xargs.1
index 3bedd67..30fd70c 100644
--- a/xargs/xargs.1
+++ b/xargs/xargs.1
@@ -299,6 +299,29 @@ and exit.
 Print the version number of
 .B xargs
 and exit.
+.PP
+The options
+.B \-\-max-lines (\-L, \-l), \-\-replace (\-I, \-i)
+and
+.B \-\-max-args (\-n)
+are mutually exclusive. If some of them are specified at the same
+time, then
+.B xargs
+will generally use the option specified last on the command line,
+i.e., it will reset the value of the offending option (given before)
+to its default value.
+Additionally,
+.B xargs
+will issue a warning diagnostic on
+.B stderr.
+The exception to this rule is that
+.B \-n1
+is ignored as a noop after
+.B \-I
+or
+.B \-i
+because these two options do not actually conflict.
+
 .SH "EXAMPLES"
 .nf
 .B find /tmp \-name core \-type f \-print | xargs /bin/rm \-f
@@ -405,12 +428,6 @@ programs are properly installed at your site, the command
 should give you access to the complete manual.
 
 .SH "BUGS"
-The
-.B \-L
-option is incompatible with the
-.B \-I
-option, but perhaps should not be.
-.P
 It is not possible for
 .B xargs
 to be used securely, since there will always be a time gap between the
diff --git a/xargs/xargs.c b/xargs/xargs.c
index 80828f5..48f30bf 100644
--- a/xargs/xargs.c
+++ b/xargs/xargs.c
@@ -388,6 +388,15 @@ static FILE* fopen_cloexec_for_read_only (const char *file_name)
 }
 
 
+static void warn_mutually_exclusive (const char *option, const char *offending)
+{
+  error (0, 0,
+	 _("warning: options %s and %s are mutually exclusive, "
+	   "ignoring previous %s value"),
+	   offending, option, offending);
+}
+
+
 int
 main (int argc, char **argv)
 {
@@ -546,14 +555,22 @@ main (int argc, char **argv)
 	  else
 	    bc_ctl.replace_pat = "{}";
 	  /* -i excludes -n -l.  */
+	  if (bc_ctl.args_per_exec != 0)
+	    warn_mutually_exclusive ("-I,-i", "-n");
 	  bc_ctl.args_per_exec = 0;
+	  if (bc_ctl.lines_per_exec != 0)
+	    warn_mutually_exclusive ("-I,-i", "-L,-l");
 	  bc_ctl.lines_per_exec = 0;
 	  break;
 
 	case 'L':		/* POSIX */
 	  bc_ctl.lines_per_exec = parse_num (optarg, 'L', 1L, -1L, 1);
 	  /* -L excludes -i -n.  */
+	  if (bc_ctl.args_per_exec != 0)
+	    warn_mutually_exclusive ("-L", "-n");
 	  bc_ctl.args_per_exec = 0;
+	  if (bc_ctl.replace_pat != NULL)
+	    warn_mutually_exclusive ("-L", "-I,-i");
 	  bc_ctl.replace_pat = NULL;
 	  break;
 
@@ -563,18 +580,26 @@ main (int argc, char **argv)
 	  else
 	    bc_ctl.lines_per_exec = 1;
 	  /* -l excludes -i -n.  */
+	  if (bc_ctl.args_per_exec != 0)
+	    warn_mutually_exclusive ("-l", "-n");
 	  bc_ctl.args_per_exec = 0;
+	  if (bc_ctl.replace_pat != NULL)
+	    warn_mutually_exclusive ("-l", "-I,-i");
 	  bc_ctl.replace_pat = NULL;
 	  break;
 
 	case 'n':
 	  bc_ctl.args_per_exec = parse_num (optarg, 'n', 1L, -1L, 1);
 	  /* -n excludes -i -l.  */
+	  if (bc_ctl.lines_per_exec != 0)
+	    warn_mutually_exclusive ("-n", "-L,-l");
 	  bc_ctl.lines_per_exec = 0;
 	  if (bc_ctl.args_per_exec == 1 && bc_ctl.replace_pat)
 	    /* ignore -n1 in '-i -n1' */
 	    bc_ctl.args_per_exec = 0;
 	  else
+	    if (bc_ctl.replace_pat != NULL)
+	      warn_mutually_exclusive ("-n", "-I,-i");
 	    bc_ctl.replace_pat = NULL;
 	  break;
 
-- 
2.1.4

