[git commit] test: fix 4-argument case

Denys Vlasenko vda.linux at googlemail.com
Mon Jul 31 17:21:51 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=78b1b1b07ac2784f67bc65bb1d86cc2559a12446
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Upstream dash commit:

    Date: Sun, 13 Jul 2008 19:20:10 +0800
    Fixed 3,4-argument cases for test per POSIX

    ----- Forwarded message from Gerrit Pape <pape at smarden.org> -----

    Subject: Bug#455828: dash: 4-argument test "test \( ! -e \)" yields an error
    Date: Fri, 28 Dec 2007 08:53:29 +0000
    From: Gerrit Pape <pape at smarden.org>
    To: Vincent Lefevre <vincent at vinc17.org>, 455828 at bugs.debian.org

    On Thu, Dec 27, 2007 at 06:23:20PM +0100, Vincent Lefevre wrote:
    > On 2007-12-27 16:00:06 +0000, Gerrit Pape wrote:
    > > On Wed, Dec 12, 2007 at 02:18:47AM +0100, Vincent Lefevre wrote:
    > > > According to POSIX[*], "test \( ! -e \)" is a 4-argument test and is
    > > > here equivalent to "test ! -e". But dash (like ksh93 and bash) yields
    > > > an error:
    > > >
    > > > $ test \( ! -e \) || echo $?
    > > > test: 1: closing paren expected
    > > > 2
    > > > $ test ! -e || echo $?
    > > > 1
    > >
    > > Hi Vincent,
    > >
    > > the -e switch to test takes an argument, a pathname.
    >
    > According to POSIX, in both above examples, "-e" is *not* a switch,
    > just a string.
    >
    >   test \( ! -e \)
    >
    > means: return true if the string "-e" is empty, otherwhise return false.
    > The error in dash is that it incorrectly thinks that "-e" is a switch in
    > this context.

    I see, you're right.  Thanks, Gerrit.

    ----- End forwarded message -----

    This patch hard-codes the 3,4-argument cases in the way required by
    POSIX.

    Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>

function                                             old     new   delta
test_main                                            370     421     +51

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 coreutils/test.c | 48 +++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 39 insertions(+), 9 deletions(-)

diff --git a/coreutils/test.c b/coreutils/test.c
index d8ac42e..a828652 100644
--- a/coreutils/test.c
+++ b/coreutils/test.c
@@ -879,18 +879,48 @@ int test_main(int argc, char **argv)
 			res = (argv[0][0] == '\0');
 			goto ret_special;
 		}
-		if (argv[2] && !argv[3]) {
-			check_operator(argv[1]);
-			if (last_operator->op_type == BINOP) {
-				/* "test [!] arg1 <binary_op> arg2" */
-				args = argv;
-				res = (binop() == 0);
+		if (argv[2]) {
+			if (!argv[3]) {
+				/*
+				 * http://pubs.opengroup.org/onlinepubs/009695399/utilities/test.html
+				 * """ 3 arguments:
+				 * If $2 is a binary primary, perform the binary test of $1 and $3.
+				 * """
+				 */
+				check_operator(argv[1]);
+				if (last_operator->op_type == BINOP) {
+					/* "test [!] arg1 <binary_op> arg2" */
+					args = argv;
+					res = (binop() == 0);
  ret_special:
-				/* If there was leading "!" op... */
-				res ^= negate;
-				goto ret;
+					/* If there was leading "!" op... */
+					res ^= negate;
+					goto ret;
+				}
+				/* """If $1 is '(' and $3 is ')', perform the unary test of $2."""
+				 * Looks like this works without additional coding.
+				 */
+				goto check_negate;
+			}
+			/* argv[3] exists (at least 4 args), is it exactly 4 args? */
+			if (!argv[4]) {
+				/*
+				 * """ 4 arguments:
+				 * If $1 is '!', negate the three-argument test of $2, $3, and $4.
+				 * If $1 is '(' and $4 is ')', perform the two-argument test of $2 and $3.
+				 * """
+				 * Example why code below is necessary: test '(' ! -e ')'
+				 */
+				if (LONE_CHAR(argv[0], '(')
+				 && LONE_CHAR(argv[3], ')')
+				) {
+					/* "test [!] ( x y )" */
+					argv[3] = NULL;
+					argv++;
+				}
 			}
 		}
+ check_negate:
 		if (LONE_CHAR(argv[0], '!')) {
 			argv++;
 			negate ^= 1;


More information about the busybox-cvs mailing list