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:
		
							
								
								
									
										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: 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: | ||||
|   | ||||
							
								
								
									
										143
									
								
								funcs.c
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								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)); | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										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 $ | ||||
| .\"- | ||||
| .\" 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 | ||||
|   | ||||
							
								
								
									
										4
									
								
								sh.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								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 | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user