• add code to support GNU bash’s “&> file” I/O redirection extension,
and make it fit into mksh’s model (also gives us a couple of things GNU bash doesn’t have • add regression tests for all of these Lukas “smultron” Upton from MidnightBSD spotted a script with /bin/sh shebang invalidly using “&>” in some Apple backup toolkit, 10x XXX why fds are limited to one digit?
This commit is contained in:
parent
fcb931ae2e
commit
c77d67ef4d
131
check.t
131
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
|
||||
---
|
||||
|
24
lex.c
24
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) {
|
||||
|
38
mksh.1
38
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 ,
|
||||
|
5
sh.h
5
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 */
|
||||
|
32
syn.c
32
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user