ensure aliases in COMSUB are not expanded twice

spotted by Jilles Tjoelker again, thanks
This commit is contained in:
tg 2011-12-29 22:03:15 +00:00
parent 68e8b5ab7c
commit dd8925a475
2 changed files with 41 additions and 21 deletions

18
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.504 2011/12/16 20:03:23 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.505 2011/12/29 22:03:12 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 $
@ -8226,6 +8226,22 @@ expected-stdout:
esac esac
} }
--- ---
name: comsub-5
description:
Check COMSUB works with aliases (does not expand them twice)
stdin:
alias echo='echo a'
foo() {
printf '%s\n' "$(echo foo)"
}
printf '%s\n' "$(echo b)"
typeset -f foo
expected-stdout:
a b
foo() {
printf "%s\\n" "$(echo foo )"
}
---
name: comsub-torture name: comsub-torture
description: description:
Check the tree dump functions work correctly Check the tree dump functions work correctly

44
syn.c
View File

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.71 2011/11/22 18:01:41 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.72 2011/12/29 22:03:15 tg Exp $");
extern short subshell_nesting_level; extern short subshell_nesting_level;
extern void yyskiputf8bom(void); extern void yyskiputf8bom(void);
@ -64,6 +64,7 @@ static struct nesting_state nesting; /* \n changed to ; */
static bool reject; /* token(cf) gets symbol again */ static bool reject; /* token(cf) gets symbol again */
static int symbol; /* yylex value */ static int symbol; /* yylex value */
static int sALIAS = ALIAS; /* 0 in yyrecursive */
#define REJECT (reject = true) #define REJECT (reject = true)
#define ACCEPT (reject = false) #define ACCEPT (reject = false)
@ -227,7 +228,7 @@ nested(int type, int smark, int emark)
nesting_push(&old_nesting, smark); nesting_push(&old_nesting, smark);
t = c_list(true); t = c_list(true);
musthave(emark, KEYWORD|ALIAS); musthave(emark, KEYWORD|sALIAS);
nesting_pop(&old_nesting); nesting_pop(&old_nesting);
return (block(type, t, NOBLOCK, NOWORDS)); return (block(type, t, NOBLOCK, NOWORDS));
} }
@ -260,8 +261,8 @@ get_command(int cf)
XPinit(args, 16); XPinit(args, 16);
XPinit(vars, 16); XPinit(vars, 16);
syniocf = KEYWORD|ALIAS; syniocf = KEYWORD|sALIAS;
switch (c = token(cf|KEYWORD|ALIAS|VARASN)) { switch (c = token(cf|KEYWORD|sALIAS|VARASN)) {
default: default:
REJECT; REJECT;
afree(iops, ATEMP); afree(iops, ATEMP);
@ -273,12 +274,12 @@ get_command(int cf)
case LWORD: case LWORD:
case REDIR: case REDIR:
REJECT; REJECT;
syniocf &= ~(KEYWORD|ALIAS); syniocf &= ~(KEYWORD|sALIAS);
t = newtp(TCOM); t = newtp(TCOM);
t->lineno = source->line; t->lineno = source->line;
while (/* CONSTCOND */ 1) { while (/* CONSTCOND */ 1) {
cf = (t->u.evalflags ? ARRAYVAR : 0) | cf = (t->u.evalflags ? ARRAYVAR : 0) |
(XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD); (XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD);
switch (tpeek(cf)) { switch (tpeek(cf)) {
case REDIR: case REDIR:
while ((iop = synio(cf)) != NULL) { while ((iop = synio(cf)) != NULL) {
@ -442,12 +443,12 @@ get_command(int cf)
t = newtp(TIF); t = newtp(TIF);
t->left = c_list(true); t->left = c_list(true);
t->right = thenpart(); t->right = thenpart();
musthave(FI, KEYWORD|ALIAS); musthave(FI, KEYWORD|sALIAS);
nesting_pop(&old_nesting); nesting_pop(&old_nesting);
break; break;
case BANG: case BANG:
syniocf &= ~(KEYWORD|ALIAS); syniocf &= ~(KEYWORD|sALIAS);
t = pipeline(0); t = pipeline(0);
if (t == NULL) if (t == NULL)
syntaxerr(NULL); syntaxerr(NULL);
@ -455,7 +456,7 @@ get_command(int cf)
break; break;
case TIME: case TIME:
syniocf &= ~(KEYWORD|ALIAS); syniocf &= ~(KEYWORD|sALIAS);
t = pipeline(0); t = pipeline(0);
if (t) { if (t) {
t->str = alloc(2, ATEMP); t->str = alloc(2, ATEMP);
@ -506,7 +507,7 @@ dogroup(void)
int c; int c;
struct op *list; struct op *list;
c = token(CONTIN|KEYWORD|ALIAS); c = token(CONTIN|KEYWORD|sALIAS);
/* /*
* A {...} can be used instead of do...done for for/select loops * A {...} can be used instead of do...done for for/select loops
* but not for while/until loops - we don't need to check if it * but not for while/until loops - we don't need to check if it
@ -520,7 +521,7 @@ dogroup(void)
else else
syntaxerr(NULL); syntaxerr(NULL);
list = c_list(true); list = c_list(true);
musthave(c, KEYWORD|ALIAS); musthave(c, KEYWORD|sALIAS);
return (list); return (list);
} }
@ -529,7 +530,7 @@ thenpart(void)
{ {
struct op *t; struct op *t;
musthave(THEN, KEYWORD|ALIAS); musthave(THEN, KEYWORD|sALIAS);
t = newtp(0); t = newtp(0);
t->left = c_list(true); t->left = c_list(true);
if (t->left == NULL) if (t->left == NULL)
@ -543,7 +544,7 @@ elsepart(void)
{ {
struct op *t; struct op *t;
switch (token(KEYWORD|ALIAS|VARASN)) { switch (token(KEYWORD|sALIAS|VARASN)) {
case ELSE: case ELSE:
if ((t = c_list(true)) == NULL) if ((t = c_list(true)) == NULL)
syntaxerr(NULL); syntaxerr(NULL);
@ -567,7 +568,7 @@ caselist(void)
struct op *t, *tl; struct op *t, *tl;
int c; int c;
c = token(CONTIN|KEYWORD|ALIAS); c = token(CONTIN|KEYWORD|sALIAS);
/* A {...} can be used instead of in...esac for case statements */ /* A {...} can be used instead of in...esac for case statements */
if (c == IN) if (c == IN)
c = ESAC; c = ESAC;
@ -584,7 +585,7 @@ caselist(void)
else else
tl->right = tc, tl = tc; tl->right = tc, tl = tc;
} }
musthave(c, KEYWORD|ALIAS); musthave(c, KEYWORD|sALIAS);
return (t); return (t);
} }
@ -613,7 +614,7 @@ casepart(int endtok)
/* initialise to default for ;; or omitted */ /* initialise to default for ;; or omitted */
t->u.charflag = ';'; t->u.charflag = ';';
/* SUSv4 requires the ;; except in the last casepart */ /* SUSv4 requires the ;; except in the last casepart */
if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok) if ((tpeek(CONTIN|KEYWORD|sALIAS)) != endtok)
switch (symbol) { switch (symbol) {
default: default:
syntaxerr(NULL); syntaxerr(NULL);
@ -659,14 +660,14 @@ function_body(char *name,
* only accepts an open-brace. * only accepts an open-brace.
*/ */
if (ksh_func) { if (ksh_func) {
if (tpeek(CONTIN|KEYWORD|ALIAS) == '(' /*)*/) { if (tpeek(CONTIN|KEYWORD|sALIAS) == '(' /*)*/) {
/* function foo () { */ /* function foo () { */
ACCEPT; ACCEPT;
musthave(')', 0); musthave(')', 0);
/* degrade to POSIX function */ /* degrade to POSIX function */
ksh_func = false; ksh_func = false;
} }
musthave('{' /*}*/, CONTIN|KEYWORD|ALIAS); musthave('{' /*}*/, CONTIN|KEYWORD|sALIAS);
REJECT; REJECT;
} }
@ -711,7 +712,7 @@ wordlist(void)
XPinit(args, 16); XPinit(args, 16);
/* POSIX does not do alias expansion here... */ /* POSIX does not do alias expansion here... */
if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) { if ((c = token(CONTIN|KEYWORD|sALIAS)) != IN) {
if (c != ';') if (c != ';')
/* non-POSIX, but AT&T ksh accepts a ; here */ /* non-POSIX, but AT&T ksh accepts a ; here */
REJECT; REJECT;
@ -1107,7 +1108,7 @@ yyrecursive(void)
struct op *t; struct op *t;
char *cp; char *cp;
bool old_reject; bool old_reject;
int old_symbol; int old_symbol, old_salias;
struct ioword **old_herep; struct ioword **old_herep;
/* tell the lexer to accept a closing parenthesis as EOD */ /* tell the lexer to accept a closing parenthesis as EOD */
@ -1118,8 +1119,11 @@ yyrecursive(void)
old_symbol = symbol; old_symbol = symbol;
ACCEPT; ACCEPT;
old_herep = herep; old_herep = herep;
old_salias = sALIAS;
sALIAS = 0;
/* we use TPAREN as a helper container here */ /* we use TPAREN as a helper container here */
t = nested(TPAREN, '(', ')'); t = nested(TPAREN, '(', ')');
sALIAS = old_salias;
herep = old_herep; herep = old_herep;
reject = old_reject; reject = old_reject;
symbol = old_symbol; symbol = old_symbol;