diff --git a/check.t b/check.t index 3e12489..e81563e 100644 --- a/check.t +++ b/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: 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 $ @@ -23,9 +23,12 @@ #- # You may also want to test IFS with the script at # 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: - @(#)MIRBSD KSH R40 2011/11/25 + @(#)MIRBSD KSH R40 2011/11/30 description: Check version of shell. stdin: diff --git a/funcs.c b/funcs.c index bc932ba..14e5899 100644 --- a/funcs.c +++ b/funcs.c @@ -38,7 +38,7 @@ #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 /* @@ -2724,8 +2724,10 @@ c_mknod(const char **wp) int c_test(const char **wp) { - int argc, res; + int argc, rv, invert = 0; Test_env te; + Test_op op; + const char *lhs, **swp; te.flags = 0; te.isa = ptest_isa; @@ -2747,63 +2749,96 @@ c_test(const char **wp) te.wp_end = wp + argc; /* - * Handle the special cases from POSIX.2, section 4.62.4. - * Implementation of all the rules isn't necessary since - * our parser does the right thing for the omitted steps. + * Attempt to conform to POSIX special cases. This is pretty + * dumb code straight-forward from the 2008 spec, but unless + * the old pdksh code doesn't live from so many assumptions. */ - if (argc <= 5) { - const char **owp = wp, **owpend = te.wp_end; - int invert = 0; - Test_op op; - const char *opnd1, *opnd2; - - if (argc >= 2 && ((*te.isa)(&te, TM_OPAREN))) { - te.pos.wp = te.wp_end - 1; - if ((*te.isa)(&te, TM_CPAREN)) { - argc -= 2; - te.wp_end--; - te.pos.wp = owp + 2; - } else { - te.pos.wp = owp + 1; - te.wp_end = owpend; - } + switch (argc - 1) { + case 0: + return (1); + case 1: + ptest_one: + op = TO_STNZE; + goto ptest_unary; + case 2: + ptest_two: + if ((*te.isa)(&te, TM_NOT)) { + ++invert; + goto ptest_one; } - - 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)) { - invert++; - } else - break; + 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); } - te.pos.wp = owp + 1; - te.wp_end = owpend; + /* 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; } + /* "The results are unspecified." */ + te.pos.wp = wp + 1; return (test_parse(&te)); } diff --git a/mksh.1 b/mksh.1 index 69d7036..e8015c2 100644 --- a/mksh.1 +++ b/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 $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, @@ -72,7 +72,7 @@ .\" with -mandoc, it might implement .Mx itself, but we want to .\" 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 .\" @@ -3549,7 +3549,7 @@ The file type may be (character type device), or .Cm p -(named pipe). +.Pq named pipe , Tn FIFO . The file created may be modified according to its .Ar mode (via the @@ -4296,7 +4296,8 @@ instead of .Ql xtrace . .It Fl p Ar file .Ar file -is a named pipe. +is a named pipe +.Pq Tn FIFO . .It Fl r Ar file .Ar file 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 .Ed .Pp -Note that some special rules are applied (courtesy of POSIX) -if the number of -arguments to +Note that some special rules are applied (courtesy of +.Px +) if the number of arguments to .Ic test -or +or inside the brackets .Ic \&[ ... \&] is less than five: if leading .Ql \&! -arguments can be stripped such that only one argument remains then a string -length test is performed (again, even if the argument is a unary operator); if -leading -.Ql \&! -arguments can be stripped such that three arguments remain and the second -argument is a binary operator, then the binary operation is performed (even -if the first argument is a unary operator, including an unstripped -.Ql \&! ) . +arguments can be stripped such that only one to three arguments remain, +then the lowered comparison is executed; (thanks to XSI) parentheses +.Ic \e( ... \e) +lower four- and three-argument forms to two- and one-argument forms, +respectively; three-argument forms ultimately prefer binary operations, +followed by negation and parenthesis lowering; two- and four-argument forms +prefer negation followed by parenthesis; the one-argument form always implies +.Fl n . .Pp .Sy Note : A common mistake is to use diff --git a/sh.h b/sh.h index 60d78c1..51d46de 100644 --- a/sh.h +++ b/sh.h @@ -151,9 +151,9 @@ #endif #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 -#define MKSH_VERSION "R40 2011/11/25" +#define MKSH_VERSION "R40 2011/11/30" #ifndef MKSH_INCLUDES_ONLY