diff --git a/check.t b/check.t index 381063b..05a2c9e 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.200 2008/06/21 19:30:49 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.201 2008/06/28 22:51:54 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 $ @@ -7,7 +7,7 @@ # http://www.research.att.com/~gsf/public/ifs.sh expected-stdout: - @(#)MIRBSD KSH R34 2008/06/08 + @(#)MIRBSD KSH R34 2008/06/28 description: Check version of shell. stdin: @@ -5000,4 +5000,129 @@ stdin: expected-stdout: okay --- - +name: bashiop-1 +description: + Check if GNU bash-like I/O redirection works + Part 1: this is also supported by GNU bash +stdin: + exec 3>&1 + function threeout { + echo ras + echo dwa >&2 + echo tri >&3 + } + threeout &>foo + echo === + cat foo +expected-stdout: + tri + === + ras + dwa +--- +name: bashiop-2a +description: + Check if GNU bash-like I/O redirection works + Part 2: this is *not* supported by GNU bash +stdin: + exec 3>&1 + function threeout { + echo ras + echo dwa >&2 + echo tri >&3 + } + threeout 3&>foo + echo === + cat foo +expected-stdout: + ras + === + dwa + tri +--- +name: bashiop-2b +description: + Check if GNU bash-like I/O redirection works + Part 2: this is *not* supported by GNU bash +stdin: + exec 3>&1 + function threeout { + echo ras + echo dwa >&2 + echo tri >&3 + } + threeout 3>foo &>&3 + echo === + cat foo +expected-stdout: + === + ras + dwa + tri +--- +name: bashiop-2c +description: + Check if GNU bash-like I/O redirection works + Part 2: this is *not* supported by GNU bash +stdin: + echo mir >foo + set -o noclobber + exec 3>&1 + function threeout { + echo ras + echo dwa >&2 + echo tri >&3 + } + threeout &>>foo + echo === + cat foo +expected-stdout: + tri + === + mir + ras + dwa +--- +name: bashiop-3a +description: + Check if GNU bash-like I/O redirection fails correctly + Part 1: this is also supported by GNU bash +stdin: + echo mir >foo + set -o noclobber + exec 3>&1 + function threeout { + echo ras + echo dwa >&2 + echo tri >&3 + } + threeout &>foo + echo === + cat foo +expected-stdout: + === + mir +expected-stderr-pattern: /.*: cannot (create|overwrite) .*/ +--- +name: bashiop-3b +description: + Check if GNU bash-like I/O redirection fails correctly + Part 2: this is *not* supported by GNU bash +stdin: + echo mir >foo + set -o noclobber + exec 3>&1 + function threeout { + echo ras + echo dwa >&2 + echo tri >&3 + } + threeout &>|foo + echo === + cat foo +expected-stdout: + tri + === + ras + dwa +--- diff --git a/lex.c b/lex.c index 2fc3910..aac1b11 100644 --- a/lex.c +++ b/lex.c @@ -2,7 +2,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.61 2008/06/28 22:01:44 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.62 2008/06/28 22:51:54 tg Exp $"); /* * states while lexing word @@ -771,7 +771,7 @@ yylex(int cf) state = SBASE; dp = Xstring(ws, wp); - if ((c == '<' || c == '>') && state == SBASE && + if ((c == '<' || c == '>' || c == '&') && state == SBASE && ((c2 = Xlength(ws, wp)) == 0 || (c2 == 2 && dp[0] == CHAR && ksh_isdigit(dp[1])))) { struct ioword *iop = (struct ioword *)alloc(sizeof (*iop), @@ -780,12 +780,22 @@ yylex(int cf) if (c2 == 2) iop->unit = dp[1] - '0'; else - iop->unit = c == '>' ? 1 : 0; + iop->unit = c == '<' ? 0 : 1; + + if (c == '&') { + if ((c2 = getsc()) != '>') { + ungetsc(c2); + goto no_iop; + } + c = c2; + iop->flag = IOBASH; + } else + iop->flag = 0; c2 = getsc(); /* <<, >>, <> are ok, >< is not */ if (c == c2 || (c == '<' && c2 == '>')) { - iop->flag = c == c2 ? + iop->flag |= c == c2 ? (c == '>' ? IOCAT : IOHERE) : IORDWR; if (iop->flag == IOHERE) { if ((c2 = getsc()) == '-') @@ -794,9 +804,9 @@ yylex(int cf) ungetsc(c2); } } else if (c2 == '&') - iop->flag = IODUP | (c == '<' ? IORDUP : 0); + iop->flag |= IODUP | (c == '<' ? IORDUP : 0); else { - iop->flag = c == '>' ? IOWRITE : IOREAD; + iop->flag |= c == '>' ? IOWRITE : IOREAD; if (c == '>' && c2 == '|') iop->flag |= IOCLOB; else @@ -809,6 +819,8 @@ yylex(int cf) Xfree(ws, wp); /* free word */ yylval.iop = iop; return REDIR; + no_iop: + ; } if (wp == dp && state == SBASE) { diff --git a/mksh.1 b/mksh.1 index a4f77b5..4719d30 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.129 2008/06/08 16:57:52 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.130 2008/06/28 22:51:55 tg Exp $ .\" $OpenBSD: ksh.1,v 1.122 2008/05/17 23:31:52 sobrado Exp $ .\"- .\" Try to make GNU groff and AT&T nroff more compatible @@ -30,7 +30,7 @@ .el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 .. .\"- -.Dd $Mdocdate: June 8 2008 $ +.Dd $Mdocdate: June 28 2008 $ .Dt MKSH 1 .Os MirBSD .Sh NAME @@ -252,6 +252,7 @@ The meta-characters are used in building the following .Ql \*(Gt , .Ql \*(Gt& , .Ql \*(Gt\*(Gt , +.Ql &\*(Gt , etc. are used to specify redirections (see .Sx Input/output redirection below); @@ -2015,6 +2016,37 @@ indicating standard input is to be closed. Same as .Ic \*(Lt& , except the operation is done on standard output. +.It &\*(Gt Ar file +Same as +.Ic \*(Gt Ar file 2\*(Gt&1 . +This is a GNU +.Nm bash +extension supported by +.Nm +which also supports the preceding explicit fd digit, for example, +.Ic 3&\*(Gt Ar file +is the same as +.Ic 3\*(Gt Ar file 2\*(Gt&3 +in +.Nm +but a syntax error in GNU +.Nm bash . +.It Xo +.No &\*(Gt| Ar file , +.No &\*(Gt\*(Gt Ar file , +.No &\*(Gt& Ar fd +.Xc +Same as +.Ic \*(Gt| Ar file , +.Ic \*(Gt\*(Gt Ar file , +or +.Ic \*(Gt& Ar fd , +followed by +.Ic 2\*(Gt&1 , +as above. +These are +.Nm +extensions. .El .Pp In any of the above redirections, the file descriptor that is redirected @@ -5489,7 +5521,7 @@ and many other persons, and is currently maintained by .An Thorsten Glaser Aq tg@mirbsd.de . .Sh BUGS This document attempts to describe -.Nm mksh\ R34 +.Nm mksh\ R35 and up, compiled without any options impacting functionality, such as .Dv MKSH_SMALL , diff --git a/sh.h b/sh.h index 2cd29dd..689065a 100644 --- a/sh.h +++ b/sh.h @@ -100,9 +100,9 @@ #define __SCCSID(x) __IDSTRING(sccsid,x) #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.219 2008/06/08 17:15:30 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.220 2008/06/28 22:51:55 tg Exp $"); #endif -#define MKSH_VERSION "R34 2008/06/08" +#define MKSH_VERSION "R34 2008/06/28" #ifndef MKSH_INCLUDES_ONLY @@ -970,6 +970,7 @@ struct ioword { #define IOCLOB BIT(6) /* >|, override -o noclobber */ #define IORDUP BIT(7) /* x<&y (as opposed to x>&y) */ #define IONAMEXP BIT(8) /* name has been expanded */ +#define IOBASH BIT(9) /* &> etc. */ /* execute/exchild flags */ #define XEXEC BIT(0) /* execute without forking */ diff --git a/syn.c b/syn.c index 782d76b..fc523a8 100644 --- a/syn.c +++ b/syn.c @@ -2,7 +2,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.21 2008/05/17 18:47:02 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.22 2008/06/28 22:51:56 tg Exp $"); struct nesting_state { int start_token; /* token than began nesting (eg, FOR) */ @@ -144,10 +144,17 @@ static struct ioword * synio(int cf) { struct ioword *iop; + static struct ioword *nextiop = NULL; int ishere; + if (nextiop != NULL) { + iop = nextiop; + nextiop = NULL; + return (iop); + } + if (tpeek(cf) != REDIR) - return NULL; + return (NULL); ACCEPT; iop = yylval.iop; ishere = (iop->flag&IOTYPE) == IOHERE; @@ -161,7 +168,18 @@ synio(int cf) *herep++ = iop; } else iop->name = yylval.cp; - return iop; + + if (iop->flag & IOBASH) { + nextiop = (struct ioword *)alloc(sizeof (*iop), ATEMP); + + iop->flag &= ~IOBASH; + nextiop->unit = 2; + nextiop->flag = IODUP; + nextiop->name = shf_smprintf("%d", iop->unit); + nextiop->delim = NULL; + nextiop->heredoc = NULL; + } + return (iop); } static struct op * @@ -211,9 +229,11 @@ get_command(int cf) (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD); switch (tpeek(cf)) { case REDIR: - if (iopn >= NUFILE) - yyerror("too many redirections\n"); - iops[iopn++] = synio(cf); + while ((iop = synio(cf)) != NULL) { + if (iopn >= NUFILE) + yyerror("too many redirections\n"); + iops[iopn++] = iop; + } break; case LWORD: