rewrite funcs.c:c_test(), i.e. test(1) and [(1), to follow POSIX and XSI
in the cases where they are defined unambiguously; bug reported by Jilles Tjoelker in <20111129232526.GC14357@stack.nl> due to a report by Stefano Lattarini on bug-autoconf in the ambiguous case, I stick to traditional pdksh behaviour, which means test ! a = b vs. test a = b and test ! a -o b vs. test a -o b behave different from each other (in the second case, the NOT operator binds strong; POSIX demands a reduction to 3 arguments and negating that result in the first case), so we're at two known not-ok in the FreeBSD® testsuite. (81 and 82 in regress.sh,v 1.3)
This commit is contained in:
parent
44a27fa8e0
commit
2fb9df56e4
7
check.t
7
check.t
@ -1,4 +1,4 @@
|
|||||||
# $MirOS: src/bin/mksh/check.t,v 1.496 2011/11/26 00:45:18 tg Exp $
|
# $MirOS: src/bin/mksh/check.t,v 1.497 2011/11/30 21:34:10 tg Exp $
|
||||||
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
|
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
|
||||||
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
|
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
|
||||||
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
|
||||||
@ -23,9 +23,12 @@
|
|||||||
#-
|
#-
|
||||||
# You may also want to test IFS with the script at
|
# You may also want to test IFS with the script at
|
||||||
# http://www.research.att.com/~gsf/public/ifs.sh
|
# http://www.research.att.com/~gsf/public/ifs.sh
|
||||||
|
#
|
||||||
|
# More testsuites at:
|
||||||
|
# http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
|
||||||
|
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
@(#)MIRBSD KSH R40 2011/11/25
|
@(#)MIRBSD KSH R40 2011/11/30
|
||||||
description:
|
description:
|
||||||
Check version of shell.
|
Check version of shell.
|
||||||
stdin:
|
stdin:
|
||||||
|
143
funcs.c
143
funcs.c
@ -38,7 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.199 2011/11/19 17:42:24 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.200 2011/11/30 21:34:12 tg Exp $");
|
||||||
|
|
||||||
#if HAVE_KILLPG
|
#if HAVE_KILLPG
|
||||||
/*
|
/*
|
||||||
@ -2724,8 +2724,10 @@ c_mknod(const char **wp)
|
|||||||
int
|
int
|
||||||
c_test(const char **wp)
|
c_test(const char **wp)
|
||||||
{
|
{
|
||||||
int argc, res;
|
int argc, rv, invert = 0;
|
||||||
Test_env te;
|
Test_env te;
|
||||||
|
Test_op op;
|
||||||
|
const char *lhs, **swp;
|
||||||
|
|
||||||
te.flags = 0;
|
te.flags = 0;
|
||||||
te.isa = ptest_isa;
|
te.isa = ptest_isa;
|
||||||
@ -2747,63 +2749,96 @@ c_test(const char **wp)
|
|||||||
te.wp_end = wp + argc;
|
te.wp_end = wp + argc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle the special cases from POSIX.2, section 4.62.4.
|
* Attempt to conform to POSIX special cases. This is pretty
|
||||||
* Implementation of all the rules isn't necessary since
|
* dumb code straight-forward from the 2008 spec, but unless
|
||||||
* our parser does the right thing for the omitted steps.
|
* the old pdksh code doesn't live from so many assumptions.
|
||||||
*/
|
*/
|
||||||
if (argc <= 5) {
|
switch (argc - 1) {
|
||||||
const char **owp = wp, **owpend = te.wp_end;
|
case 0:
|
||||||
int invert = 0;
|
return (1);
|
||||||
Test_op op;
|
case 1:
|
||||||
const char *opnd1, *opnd2;
|
ptest_one:
|
||||||
|
op = TO_STNZE;
|
||||||
if (argc >= 2 && ((*te.isa)(&te, TM_OPAREN))) {
|
goto ptest_unary;
|
||||||
te.pos.wp = te.wp_end - 1;
|
case 2:
|
||||||
if ((*te.isa)(&te, TM_CPAREN)) {
|
ptest_two:
|
||||||
argc -= 2;
|
|
||||||
te.wp_end--;
|
|
||||||
te.pos.wp = owp + 2;
|
|
||||||
} else {
|
|
||||||
te.pos.wp = owp + 1;
|
|
||||||
te.wp_end = owpend;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (--argc >= 0) {
|
|
||||||
if ((*te.isa)(&te, TM_END))
|
|
||||||
return (!0);
|
|
||||||
if (argc == 3) {
|
|
||||||
opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
|
|
||||||
if ((op = (*te.isa)(&te, TM_BINOP))) {
|
|
||||||
opnd2 = (*te.getopnd)(&te, op, 1);
|
|
||||||
res = (*te.eval)(&te, op, opnd1,
|
|
||||||
opnd2, 1);
|
|
||||||
if (te.flags & TEF_ERROR)
|
|
||||||
return (T_ERR_EXIT);
|
|
||||||
if (invert & 1)
|
|
||||||
res = !res;
|
|
||||||
return (!res);
|
|
||||||
}
|
|
||||||
/* back up to opnd1 */
|
|
||||||
te.pos.wp--;
|
|
||||||
}
|
|
||||||
if (argc == 1) {
|
|
||||||
opnd1 = (*te.getopnd)(&te, TO_NONOP, 1);
|
|
||||||
res = (*te.eval)(&te, TO_STNZE, opnd1,
|
|
||||||
NULL, 1);
|
|
||||||
if (invert & 1)
|
|
||||||
res = !res;
|
|
||||||
return (!res);
|
|
||||||
}
|
|
||||||
if ((*te.isa)(&te, TM_NOT)) {
|
if ((*te.isa)(&te, TM_NOT)) {
|
||||||
invert++;
|
++invert;
|
||||||
} else
|
goto ptest_one;
|
||||||
|
}
|
||||||
|
if ((op = (*te.isa)(&te, TM_UNOP))) {
|
||||||
|
ptest_unary:
|
||||||
|
rv = (*te.eval)(&te, op,
|
||||||
|
(*te.getopnd)(&te, op, true), NULL, true);
|
||||||
|
ptest_out:
|
||||||
|
return ((invert & 1) ? rv : !rv);
|
||||||
|
}
|
||||||
|
/* let the parser deal with anything else */
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
ptest_three:
|
||||||
|
swp = te.pos.wp;
|
||||||
|
/* skip lhs, without evaluation */
|
||||||
|
(*te.getopnd)(&te, TO_NONOP, false);
|
||||||
|
if ((op = (*te.isa)(&te, TM_BINOP))) {
|
||||||
|
const char *rhs;
|
||||||
|
|
||||||
|
/* read rhs, with evaluation */
|
||||||
|
rhs = (*te.getopnd)(&te, op, true);
|
||||||
|
/* back up to lhs */
|
||||||
|
te.pos.wp = swp;
|
||||||
|
/* re-read lhs, with evaluation */
|
||||||
|
lhs = (*te.getopnd)(&te, op, true);
|
||||||
|
/* finally run the test of lhs op rhs */
|
||||||
|
rv = (*te.eval)(&te, op, lhs, rhs, true);
|
||||||
|
goto ptest_out;
|
||||||
|
}
|
||||||
|
/* back up to lhs */
|
||||||
|
te.pos.wp = swp;
|
||||||
|
if ((*te.isa)(&te, TM_NOT)) {
|
||||||
|
++invert;
|
||||||
|
goto ptest_two;
|
||||||
|
}
|
||||||
|
if ((*te.isa)(&te, TM_OPAREN)) {
|
||||||
|
swp = te.pos.wp;
|
||||||
|
/* skip operand, without evaluation */
|
||||||
|
(*te.getopnd)(&te, TO_NONOP, false);
|
||||||
|
/* check for closing parenthesis */
|
||||||
|
op = (*te.isa)(&te, TM_CPAREN);
|
||||||
|
/* back up to operand */
|
||||||
|
te.pos.wp = swp;
|
||||||
|
/* if there was a closing paren, handle it */
|
||||||
|
if (op)
|
||||||
|
goto ptest_one;
|
||||||
|
/* backing up is done before calling the parser */
|
||||||
|
}
|
||||||
|
/* let the parser deal with it */
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if ((*te.isa)(&te, TM_NOT)) {
|
||||||
|
++invert;
|
||||||
|
goto ptest_three;
|
||||||
|
}
|
||||||
|
if ((*te.isa)(&te, TM_OPAREN)) {
|
||||||
|
swp = te.pos.wp;
|
||||||
|
/* skip two operands, without evaluation */
|
||||||
|
(*te.getopnd)(&te, TO_NONOP, false);
|
||||||
|
(*te.getopnd)(&te, TO_NONOP, false);
|
||||||
|
/* check for closing parenthesis */
|
||||||
|
op = (*te.isa)(&te, TM_CPAREN);
|
||||||
|
/* back up to first operand */
|
||||||
|
te.pos.wp = swp;
|
||||||
|
/* if there was a closing paren, handle it */
|
||||||
|
if (op)
|
||||||
|
goto ptest_two;
|
||||||
|
/* backing up is done before calling the parser */
|
||||||
|
}
|
||||||
|
/* defer this to the parser */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
te.pos.wp = owp + 1;
|
|
||||||
te.wp_end = owpend;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* "The results are unspecified." */
|
||||||
|
te.pos.wp = wp + 1;
|
||||||
return (test_parse(&te));
|
return (test_parse(&te));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
mksh.1
33
mksh.1
@ -1,4 +1,4 @@
|
|||||||
.\" $MirOS: src/bin/mksh/mksh.1,v 1.278 2011/11/11 22:14:02 tg Exp $
|
.\" $MirOS: src/bin/mksh/mksh.1,v 1.279 2011/11/30 21:34:14 tg Exp $
|
||||||
.\" $OpenBSD: ksh.1,v 1.141 2011/09/03 22:59:08 jmc Exp $
|
.\" $OpenBSD: ksh.1,v 1.141 2011/09/03 22:59:08 jmc Exp $
|
||||||
.\"-
|
.\"-
|
||||||
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
||||||
@ -72,7 +72,7 @@
|
|||||||
.\" with -mandoc, it might implement .Mx itself, but we want to
|
.\" with -mandoc, it might implement .Mx itself, but we want to
|
||||||
.\" use our own definition. And .Dd must come *first*, always.
|
.\" use our own definition. And .Dd must come *first*, always.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: November 11 2011 $
|
.Dd $Mdocdate: November 30 2011 $
|
||||||
.\"
|
.\"
|
||||||
.\" Check which macro package we use
|
.\" Check which macro package we use
|
||||||
.\"
|
.\"
|
||||||
@ -3549,7 +3549,7 @@ The file type may be
|
|||||||
(character type device),
|
(character type device),
|
||||||
or
|
or
|
||||||
.Cm p
|
.Cm p
|
||||||
(named pipe).
|
.Pq named pipe , Tn FIFO .
|
||||||
The file created may be modified according to its
|
The file created may be modified according to its
|
||||||
.Ar mode
|
.Ar mode
|
||||||
(via the
|
(via the
|
||||||
@ -4296,7 +4296,8 @@ instead of
|
|||||||
.Ql xtrace .
|
.Ql xtrace .
|
||||||
.It Fl p Ar file
|
.It Fl p Ar file
|
||||||
.Ar file
|
.Ar file
|
||||||
is a named pipe.
|
is a named pipe
|
||||||
|
.Pq Tn FIFO .
|
||||||
.It Fl r Ar file
|
.It Fl r Ar file
|
||||||
.Ar file
|
.Ar file
|
||||||
exists and is readable.
|
exists and is readable.
|
||||||
@ -4394,22 +4395,22 @@ a mathematical term or the name of an integer variable:
|
|||||||
x=1; [ "x" \-eq 1 ] evaluates to true
|
x=1; [ "x" \-eq 1 ] evaluates to true
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Note that some special rules are applied (courtesy of POSIX)
|
Note that some special rules are applied (courtesy of
|
||||||
if the number of
|
.Px
|
||||||
arguments to
|
) if the number of arguments to
|
||||||
.Ic test
|
.Ic test
|
||||||
or
|
or inside the brackets
|
||||||
.Ic \&[ ... \&]
|
.Ic \&[ ... \&]
|
||||||
is less than five: if leading
|
is less than five: if leading
|
||||||
.Ql \&!
|
.Ql \&!
|
||||||
arguments can be stripped such that only one argument remains then a string
|
arguments can be stripped such that only one to three arguments remain,
|
||||||
length test is performed (again, even if the argument is a unary operator); if
|
then the lowered comparison is executed; (thanks to XSI) parentheses
|
||||||
leading
|
.Ic \e( ... \e)
|
||||||
.Ql \&!
|
lower four- and three-argument forms to two- and one-argument forms,
|
||||||
arguments can be stripped such that three arguments remain and the second
|
respectively; three-argument forms ultimately prefer binary operations,
|
||||||
argument is a binary operator, then the binary operation is performed (even
|
followed by negation and parenthesis lowering; two- and four-argument forms
|
||||||
if the first argument is a unary operator, including an unstripped
|
prefer negation followed by parenthesis; the one-argument form always implies
|
||||||
.Ql \&! ) .
|
.Fl n .
|
||||||
.Pp
|
.Pp
|
||||||
.Sy Note :
|
.Sy Note :
|
||||||
A common mistake is to use
|
A common mistake is to use
|
||||||
|
4
sh.h
4
sh.h
@ -151,9 +151,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXTERN
|
#ifdef EXTERN
|
||||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.505 2011/11/26 00:45:21 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.506 2011/11/30 21:34:15 tg Exp $");
|
||||||
#endif
|
#endif
|
||||||
#define MKSH_VERSION "R40 2011/11/25"
|
#define MKSH_VERSION "R40 2011/11/30"
|
||||||
|
|
||||||
#ifndef MKSH_INCLUDES_ONLY
|
#ifndef MKSH_INCLUDES_ONLY
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user