1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 03:32:24 +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

8
NEWS
View file

@ -3,6 +3,14 @@ For full details, see the git log at: https://github.com/ksh93/ksh
Any uppercase BUG_* names are modernish shell bug IDs.
2021-11-13:
- The test/[ built-in command is fixed so that the binary -a (and) and -o (or)
operators, as in [ "$a" -a "$b" ] or [ "$a" -o "$b" ], work even if "$a" is
'!' or '('. To avoid breaking backwards compatibility with the nonstandard
unary [ -a "$file" ] and [ -o "$option" ] operators in combination with '!'
or parentheses, this fix is only activated if the posix option is on.
2021-11-07:
- Fixed a bug that could corrupt output if standard output is closed upon

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, '('))

View file

@ -57,7 +57,7 @@ const Shtable_t shtab_testops[] =
};
const char sh_opttest[] =
"[-1c?\n@(#)$Id: test (ksh 93u+m) 2020-08-31 $\n]"
"[-1c?\n@(#)$Id: test (ksh 93u+m) 2021-11-13 $\n]"
"[--catalog?" SH_DICT "]"
"[+NAME?test, [ - evaluate expression]"
"[+DESCRIPTION?\btest\b evaluates expressions and returns its result using the "
@ -97,7 +97,7 @@ const char sh_opttest[] =
"[+?Operators marked with a * are not part of the POSIX standard.]"
"}"
"[+UNARY OPERATORS?These evaluate as True if:]{"
"[+-a \afile\a *?Same as \b-e\b.]"
"[+-a \afile\a *?Deprecated. Same as \b-e\b.]"
"[+-b \afile\a?\afile\a is a block special file.]"
"[+-c \afile\a?\afile\a is a character special file.]"
"[+-d \afile\a?\afile\a is a directory.]"

View file

@ -21,7 +21,7 @@
#define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */
#define SH_RELEASE_SVER "1.0.0-beta.2" /* semantic version number: https://semver.org */
#define SH_RELEASE_DATE "2021-11-07" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_DATE "2021-11-13" /* must be in this format for $((.sh.version)) */
#define SH_RELEASE_CPYR "(c) 2020-2021 Contributors to ksh " SH_RELEASE_FORK
/* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */

View file

@ -7244,6 +7244,12 @@ disables the \fB&>\fR redirection shorthand;
.IP \[bu]
makes the \fB<>\fR redirection operator default to redirecting standard input
if no file descriptor number precedes it;
.IP \[bu]
changes the \fBtest\fR/\fB[\fR built-in command to make its deprecated
\fIexpr1\fR \fB-a\fR \fIexpr2\fR and \fIexpr1\fR \fB-o\fR \fIexpr2\fR operators
work even if \fIexpr1\fR equals "\fB!\fR" or "\fb(\fR" (which means the
nonstandard unary \fB-a\fR \fIfile\fR and \fB-o\fR \fIoption\fR operators
cannot be directly negated using \fB!\fR or wrapped in parentheses);
and
.IP \[bu]
disables a hack that makes \fBtest -t\fR (\fB[ -t ]\fR) equivalent to
@ -7451,13 +7457,15 @@ to those specified for the \f3[[\fP compound command under
above, but with several important differences. The \f3=\fP, \f3==\fP and
\f3!=\fP operators test for string (in)equality without pattern matching;
the \f3==\fP variant is nonstandard and should not be used. The \f3=\(ap\fP,
\f3<\fP, \f3>\fP, \f3&&\fP and \f3||\fP operators are not available. Most
\f3<\fP, \f3>\fP, \f3&&\fP and \f3||\fP operators are not available. Instead
of \f3&&\fP and \f3||\fP, the \f3-a\fP and \f3-o\fP binary operators can be
used, but they are fraught with pitfalls due to grammatical ambiguities and
therefore deprecated in favor of invoking separate \f3test\fP commands. Most
importantly, as \f3test\fP and \f3[\fP are simple regular commands, field
splitting and file name generation \f2are\fP performed on all their
arguments and all aspects of regular shell grammar (such as redirection)
remain active. This is usually harmful, so care must be taken to quote
arguments and expansions to avoid this. There are also certain inherent
grammatical ambiguities in the expressions. To avoid the many pitfalls
arguments and expansions to avoid this. To avoid the many pitfalls
arising from these issues, the \f3[[\fP compound command should be used
instead. The primary purpose of the \f3test\fP and \f3[\fP commands is
compatibility with other shells that lack \f3[[\fP.

View file

@ -423,5 +423,16 @@ foo=10
&& [ ! ! -n x -a ! ! ! ! -n x -a ! ! ! ! ! ! -n x ] \
|| err_exit '! does not negate ! in [ ... ]'
# ======
# https://github.com/ksh93/ksh/issues/330
if (set -o posix) 2>/dev/null
then set -o posix -o trackall
test ! -a "" && err_exit "POSIX test/[: binary -a operator does not work with '!' as left-hand expression"
test \( -a \) 2>/dev/null || err_exit "POSIX test/[: binary -a operator does not work with '(' as left-hand expression"
test ! -o trackall || err_exit "POSIX test/[: binary -o operator does not work with '!' as left-hand expression"
test \( -o \) 2>/dev/null || err_exit "POSIX test/[: binary -o operator does not work with '(' as left-hand expression"
set +o posix
fi
# ======
exit $((Errors<125?Errors:125))