1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

test/[: Fix binary -a/-o operators in POSIX mode

POSIX requires
	test "$a" -a "$b"
to return true if both $a and $b are non-empty, and
	test "$a" -o "$b"
to return true if either $a or $b is non-empty.

In ksh, this fails if "$a" is '!' or '(' as this causes ksh to
interpret the -a and -o as unary operators (-a being a file
existence test like -e, and -o being a shell option test).

$ test ! -a ""; echo "$?"
0		(expected: 1/false)
$ set -o trackall; test ! -o trackall; echo "$?"
1		(expected: 0/true)
$ test \( -a \); echo "$?"
ksh: test: argument expected
2		(expected: 0/true)
$ test \( -o \)
ksh: test: argument expected
2		(expected: 0/true)

Unfortunately this problem cannot be fixed without risking breakage
in legacy scripts. For instance, a script may well use
	test ! -a filename
to check that a filename is nonexistent. POSIX specifies that this
always return true as it is a test for the non-emptiness of both
strings '!' and 'filename'.

So this commit fixes it for POSIX mode only.

src/cmd/ksh93/bltins/test.c: e3():
- If the posix option is active, specially handle the case of
  having at least three arguments with the second being -a or -o,
  overriding their handling as unary operators.

src/cmd/ksh93/data/testops.c:
- Update 'test --man --' date and say that unary -a is deprecated.

src/cmd/ksh93/sh.1:
- Document the fix under the -o posix option.
- For test/[, explain that binary -a/-o are deprecated.

src/cmd/ksh93/tests/bracket.sh:
- Add tests based on reproducers in bug report.

Resolves: https://github.com/ksh93/ksh/issues/330
This commit is contained in:
Martijn Dekker 2021-11-13 03:17:54 +01:00
parent 568cfdbda7
commit 6f5c9fea93
6 changed files with 47 additions and 8 deletions

View file

@ -243,8 +243,9 @@ done:
/*
* evaluate a test expression.
* flag is 0 on outer level
* flag is 1 when in parenthesis
* flag is 2 when evaluating -a
* flag is 1 when in parentheses
* flag is 2 when evaluating -a (TEST_AND)
* flag is 3 when evaluating -o (TEST_OR)
*/
static int expr(struct test *tp,register int flag)
{
@ -308,6 +309,17 @@ static int e3(struct test *tp)
register int op;
char *binop;
arg=nxtarg(tp,0);
if(sh_isoption(SH_POSIX) && tp->ap + 1 < tp->ac && ((op=sh_lookup(tp->av[tp->ap],shtab_testops)) & TEST_BINOP))
{ /*
* In POSIX mode, makes sure standard binary -a/-o takes precedence
* over nonstandard unary -a/-o if the lefthand expression is "!" or "("
*/
tp->ap++;
if(op==TEST_AND)
return(*arg && expr(tp,2));
else /* TEST_OR */
return(*arg || expr(tp,3));
}
if(arg && c_eq(arg, '!'))
return(!e3(tp));
if(c_eq(arg, '('))