implement ksh93 feature ${ foo;}

This commit is contained in:
tg 2012-07-30 21:37:17 +00:00
parent 8e51bb7a23
commit 9b7b7f742e
10 changed files with 146 additions and 72 deletions

42
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.552 2012/07/30 19:58:03 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.553 2012/07/30 21:37:08 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 $
@ -29,7 +29,7 @@
# http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R40 2012/07/21 @(#)MIRBSD KSH R40 2012/07/30
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -38,7 +38,7 @@ name: KSH_VERSION
category: shell:legacy-no category: shell:legacy-no
--- ---
expected-stdout: expected-stdout:
@(#)LEGACY KSH R40 2012/07/21 @(#)LEGACY KSH R40 2012/07/30
description: description:
Check version of legacy shell. Check version of legacy shell.
stdin: stdin:
@ -6194,21 +6194,6 @@ expected-stdout:
expected-stderr-pattern: expected-stderr-pattern:
/(Unrecognized character .... ignored at \..t4 line 1)*/ /(Unrecognized character .... ignored at \..t4 line 1)*/
--- ---
name: utf8bom-3
description:
Reading the UTF-8 BOM should enable the utf8-mode flag
(temporarily for COMSUBs)
stdin:
"$__progname" -c ':; if [[ $- = *U* ]]; then echo 1 on; else echo 1 off; fi'
"$__progname" -c ':; if [[ $- = *U* ]]; then echo 2 on; else echo 2 off; fi'
"$__progname" -c 'if [[ $- = *U* ]]; then echo 3 on; else echo 3 off; fi; x=$(:; if [[ $- = *U* ]]; then echo 4 on; else echo 4 off; fi); echo $x; if [[ $- = *U* ]]; then echo 5 on; else echo 5 off; fi'
expected-stdout:
1 off
2 on
3 off
4 on
5 off
---
name: utf8opt-1a name: utf8opt-1a
description: description:
Check that the utf8-mode flag is not set at non-interactive startup Check that the utf8-mode flag is not set at non-interactive startup
@ -9520,6 +9505,26 @@ expected-stdout:
x=$(( echo $(true >&3 ) $((1+ 2)) ) | tr u x ) x=$(( echo $(true >&3 ) $((1+ 2)) ) | tr u x )
} }
--- ---
name: funsub-1
description:
Check that non-subenvironment command substitution works
stdin:
set -e
foo=bar
echo "ob $foo ."
echo "${
echo "ib $foo :"
foo=baz
echo "ia $foo :"
false
}" .
echo "oa $foo ."
expected-stdout:
ob bar .
ib bar :
ia baz : .
oa baz .
---
name: test-stnze-1 name: test-stnze-1
description: description:
Check that the short form [ $x ] works Check that the short form [ $x ] works
@ -9613,7 +9618,6 @@ expected-stdout:
name: event-subst-3 name: event-subst-3
description: description:
Check that '!' substitution in noninteractive mode is ignored Check that '!' substitution in noninteractive mode is ignored
category: !smksh
file-setup: file 755 "falsetto" file-setup: file 755 "falsetto"
#! /bin/sh #! /bin/sh
echo molto bene echo molto bene

View File

@ -1,7 +1,8 @@
# $Id$ # $Id$
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.69 2011/12/31 01:07:19 tg Exp $ # $MirOS: src/bin/mksh/dot.mkshrc,v 1.70 2012/07/30 21:37:10 tg Exp $
#- #-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012
# Thorsten Glaser <tg@mirbsd.org> # Thorsten Glaser <tg@mirbsd.org>
# #
# Provided that these terms and disclaimer and all copyright notices # Provided that these terms and disclaimer and all copyright notices
@ -29,7 +30,7 @@ function precmd {
(( e )) && print -n "$e|" (( e )) && print -n "$e|"
} }
PS1=$'\001\r''$(precmd)${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \? PS1=$'\001\r''${ precmd;}${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?
)}@${HOSTNAME%%.*}:$(local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || \ )}@${HOSTNAME%%.*}:$(local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || \
d=${d/#$p/~}; local m=${%d} n p=...; (( m > 0 )) || m=${#d} d=${d/#$p/~}; local m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || \ (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || \

49
eval.c
View File

@ -23,7 +23,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.122 2012/07/30 17:28:21 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/eval.c,v 1.123 2012/07/30 21:37:11 tg Exp $");
/* /*
* string expansion * string expansion
@ -58,7 +58,7 @@ typedef struct Expand {
#define IFS_NWS 2 /* have seen IFS non-white-space */ #define IFS_NWS 2 /* have seen IFS non-white-space */
static int varsub(Expand *, const char *, const char *, int *, int *); static int varsub(Expand *, const char *, const char *, int *, int *);
static int comsub(Expand *, const char *); static int comsub(Expand *, const char *, int);
static char *trimsub(char *, char *, int); static char *trimsub(char *, char *, int);
static void glob(char *, XPtrV *, int); static void glob(char *, XPtrV *, int);
static void globit(XString *, char **, char *, XPtrV *, int); static void globit(XString *, char **, char *, XPtrV *, int);
@ -278,17 +278,27 @@ expand(const char *cp, /* input word */
quote = st->quotew; quote = st->quotew;
continue; continue;
case COMSUB: case COMSUB:
case FUNSUB:
tilde_ok = 0; tilde_ok = 0;
if (f & DONTRUNCOMMAND) { if (f & DONTRUNCOMMAND) {
word = IFS_WORD; word = IFS_WORD;
*dp++ = '$'; *dp++ = '('; *dp++ = '$';
if (c == FUNSUB) {
*dp++ = '{';
*dp++ = ' ';
} else
*dp++ = '(';
while (*sp != '\0') { while (*sp != '\0') {
Xcheck(ds, dp); Xcheck(ds, dp);
*dp++ = *sp++; *dp++ = *sp++;
} }
*dp++ = ')'; if (c == FUNSUB) {
*dp++ = ';';
*dp++ = '}';
} else
*dp++ = ')';
} else { } else {
type = comsub(&x, sp); type = comsub(&x, sp, c);
if (type == XCOM && (f&DOBLANK)) if (type == XCOM && (f&DOBLANK))
doblank++; doblank++;
sp = strnul(sp) + 1; sp = strnul(sp) + 1;
@ -611,8 +621,8 @@ expand(const char *cp, /* input word */
case '#': case '#':
case '%': case '%':
/* ! DOBLANK,DOBRACE,DOTILDE */ /* ! DOBLANK,DOBRACE,DOTILDE */
f = DOPAT | (f&DONTRUNCOMMAND) | f = (f & DONTRUNCOMMAND) |
DOTEMP; DOPAT | DOTEMP;
st->quotew = quote = 0; st->quotew = quote = 0;
/* /*
* Prepend open pattern (so | * Prepend open pattern (so |
@ -1272,7 +1282,7 @@ varsub(Expand *xp, const char *sp, const char *word,
* Run the command in $(...) and read its output. * Run the command in $(...) and read its output.
*/ */
static int static int
comsub(Expand *xp, const char *cp) comsub(Expand *xp, const char *cp, int fn)
{ {
Source *s, *sold; Source *s, *sold;
struct op *t; struct op *t;
@ -1286,10 +1296,15 @@ comsub(Expand *xp, const char *cp)
afree(s, ATEMP); afree(s, ATEMP);
source = sold; source = sold;
UTFMODE = old_utfmode;
if (t == NULL) if (t == NULL)
return (XBASE); return (XBASE);
if (t != NULL && t->type == TCOM && /* no waitlast() unless specifically enabled later */
xp->split = false;
if (t->type == TCOM &&
*t->args == NULL && *t->vars == NULL && t->ioact != NULL) { *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
/* $(<file) */ /* $(<file) */
struct ioword *io = *t->ioact; struct ioword *io = *t->ioact;
@ -1302,10 +1317,9 @@ comsub(Expand *xp, const char *cp)
SHF_MAPHI|SHF_CLEXEC); SHF_MAPHI|SHF_CLEXEC);
if (shf == NULL) if (shf == NULL)
errorf("%s: %s %s", name, "can't open", "$() input"); errorf("%s: %s %s", name, "can't open", "$() input");
/* no waitlast() */
xp->split = false;
} else { } else {
int ofd1, pv[2]; int ofd1, pv[2];
openpipe(pv); openpipe(pv);
shf = shf_fdopen(pv[0], SHF_RD, NULL); shf = shf_fdopen(pv[0], SHF_RD, NULL);
ofd1 = savefd(1); ofd1 = savefd(1);
@ -1313,14 +1327,16 @@ comsub(Expand *xp, const char *cp)
ksh_dup2(pv[1], 1, false); ksh_dup2(pv[1], 1, false);
close(pv[1]); close(pv[1]);
} }
execute(t, XFORK|XXCOM|XPIPEO, NULL); execute(t, XXCOM | XPIPEO |
(fn == FUNSUB ? XERROK : XFORK), NULL);
restfd(1, ofd1); restfd(1, ofd1);
startlast(); if (fn != FUNSUB) {
/* waitlast() */ startlast();
xp->split = true; /* waitlast() */
xp->split = true;
}
} }
UTFMODE = old_utfmode;
xp->u.shf = shf; xp->u.shf = shf;
return (XCOM); return (XCOM);
} }
@ -1328,7 +1344,6 @@ comsub(Expand *xp, const char *cp)
/* /*
* perform #pattern and %pattern substitution in ${} * perform #pattern and %pattern substitution in ${}
*/ */
static char * static char *
trimsub(char *str, char *pat, int how) trimsub(char *str, char *pat, int how)
{ {

28
lex.c
View File

@ -23,7 +23,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.165 2012/07/01 15:54:55 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.166 2012/07/30 21:37:12 tg Exp $");
/* /*
* states while lexing word * states while lexing word
@ -109,7 +109,7 @@ void yyskiputf8bom(void);
static int backslash_skip; static int backslash_skip;
static int ignore_backslash_newline; static int ignore_backslash_newline;
static struct sretrace_info *retrace_info; static struct sretrace_info *retrace_info;
short subshell_nesting_level = 0; int subshell_nesting_type = 0;
/* optimised getsc_bn() */ /* optimised getsc_bn() */
#define o_getsc() (*source->str != '\0' && *source->str != '\\' && \ #define o_getsc() (*source->str != '\0' && *source->str != '\\' && \
@ -262,6 +262,11 @@ yylex(int cf)
while (!((c = getsc()) == 0 || while (!((c = getsc()) == 0 ||
((state == SBASE || state == SHEREDELIM || state == SHERESTRING) && ((state == SBASE || state == SHEREDELIM || state == SHERESTRING) &&
ctype(c, C_LEX1)))) { ctype(c, C_LEX1)))) {
if (state == SBASE &&
subshell_nesting_type == /*{*/ '}' &&
c == /*{*/ '}')
/* possibly end ${ :;} */
break;
accept_nonword: accept_nonword:
Xcheck(ws, wp); Xcheck(ws, wp);
switch (state) { switch (state) {
@ -395,14 +400,27 @@ yylex(int cf)
} else { } else {
ungetsc(c); ungetsc(c);
subst_command: subst_command:
sp = yyrecursive(); c = COMSUB;
subst_command2:
sp = yyrecursive(c);
cz = strlen(sp) + 1; cz = strlen(sp) + 1;
XcheckN(ws, wp, cz); XcheckN(ws, wp, cz);
*wp++ = COMSUB; *wp++ = c;
memcpy(wp, sp, cz); memcpy(wp, sp, cz);
wp += cz; wp += cz;
} }
} else if (c == '{') /*}*/ { } else if (c == '{') /*}*/ {
c = getsc();
if (ctype(c, C_IFSWS)) {
/*
* non-subenvironment
* "command" substitution
*/
c = FUNSUB;
goto subst_command2;
}
ungetsc(c);
*wp++ = OSUBST; *wp++ = OSUBST;
*wp++ = '{'; /*}*/ *wp++ = '{'; /*}*/
wp = get_brace_var(&ws, wp); wp = get_brace_var(&ws, wp);
@ -1171,7 +1189,7 @@ readhere(struct ioword *iop)
/* end of here document marker, what to do? */ /* end of here document marker, what to do? */
switch (c) { switch (c) {
case /*(*/ ')': case /*(*/ ')':
if (!subshell_nesting_level) if (!subshell_nesting_type)
/*- /*-
* not allowed outside $(...) or (...) * not allowed outside $(...) or (...)
* => mismatch * => mismatch

6
misc.c
View File

@ -30,7 +30,7 @@
#include <grp.h> #include <grp.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.196 2012/07/20 21:18:45 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.197 2012/07/30 21:37:13 tg Exp $");
#define KSH_CHVT_FLAG #define KSH_CHVT_FLAG
#ifdef MKSH_SMALL #ifdef MKSH_SMALL
@ -101,9 +101,9 @@ initctypes(void)
chtypes['_'] |= C_ALPHA; chtypes['_'] |= C_ALPHA;
setctypes("0123456789", C_DIGIT); setctypes("0123456789", C_DIGIT);
/* \0 added automatically */ /* \0 added automatically */
setctypes(" \t\n|&;<>()", C_LEX1); setctypes(TC_LEX1, C_LEX1);
setctypes("*@#!$-?", C_VAR1); setctypes("*@#!$-?", C_VAR1);
setctypes(" \t\n", C_IFSWS); setctypes(TC_IFSWS, C_IFSWS);
setctypes("=-+?", C_SUBOP1); setctypes("=-+?", C_SUBOP1);
setctypes("\t\n \"#$&'()*;<=>?[\\]`|", C_QUOTE); setctypes("\t\n \"#$&'()*;<=>?[\\]`|", C_QUOTE);
} }

16
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.290 2012/07/25 19:40:40 tg Exp $ .\" $MirOS: src/bin/mksh/mksh.1,v 1.291 2012/07/30 21:37:13 tg Exp $
.\" $OpenBSD: ksh.1,v 1.144 2012/07/08 08:13:20 guenther Exp $ .\" $OpenBSD: ksh.1,v 1.144 2012/07/08 08:13:20 guenther Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@ -74,7 +74,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to .\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always. .\" use our own definition. And .Dd must come *first*, always.
.\" .\"
.Dd $Mdocdate: July 25 2012 $ .Dd $Mdocdate: July 30 2012 $
.\" .\"
.\" Check which macro package we use, and do other -mdoc setup. .\" Check which macro package we use, and do other -mdoc setup.
.\" .\"
@ -1145,9 +1145,15 @@ or
command substitutions take the form command substitutions take the form
.Pf $( Ns Ar command Ns \&) .Pf $( Ns Ar command Ns \&)
or (deprecated) or (deprecated)
.Pf \` Ns Ar command Ns \` ; .Pf \` Ns Ar command Ns \`
or (executed in the current environment)
.Pf ${\ \& Ar command Ns \&;}
and strip trailing newlines;
and arithmetic substitutions take the form and arithmetic substitutions take the form
.Pf $(( Ns Ar expression Ns )) . .Pf $(( Ns Ar expression Ns )) .
Parsing the current-environment command substitution requires a space,
tab or newline after the opening brace and that the closing brace be
recognised as a keyword (i.e. is preceded by a newline or semicolon).
.Pp .Pp
If a substitution appears outside of double quotes, the results of the If a substitution appears outside of double quotes, the results of the
substitution are generally subject to word or field splitting according to substitution are generally subject to word or field splitting according to
@ -1225,6 +1231,8 @@ A command substitution is replaced by the output generated by the specified
command which is run in a subshell. command which is run in a subshell.
For For
.Pf $( Ns Ar command Ns \&) .Pf $( Ns Ar command Ns \&)
and
.Pf ${\ \& Ar command Ns \&;}
substitutions, normal quoting rules are used when substitutions, normal quoting rules are used when
.Ar command .Ar command
is parsed; however, for the deprecated is parsed; however, for the deprecated
@ -1963,7 +1971,7 @@ x=$(print \e\e001)
PS1="$x$(print \e\er)$x$(tput smso)$x\e$PWD$x$(tput rmso)$x\*(Gt " PS1="$x$(print \e\er)$x$(tput smso)$x\e$PWD$x$(tput rmso)$x\*(Gt "
.Ed .Ed
.Pp .Pp
Due to pressure from David G. Korn, Due to a strong suggestion from David G. Korn,
.Nm .Nm
now also supports the following form: now also supports the following form:
.Bd -literal -offset indent .Bd -literal -offset indent

9
sh.h
View File

@ -157,9 +157,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.575 2012/07/30 17:04:30 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.576 2012/07/30 21:37:15 tg Exp $");
#endif #endif
#define MKSH_VERSION "R40 2012/07/21" #define MKSH_VERSION "R40 2012/07/30"
/* arithmetic types: C implementation */ /* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES #if !HAVE_CAN_INTTYPES
@ -765,6 +765,8 @@ EXTERN const char Tgbuiltin[] E_INIT("=builtin");
#define Tbuiltin (Tgbuiltin + 1) /* "builtin" */ #define Tbuiltin (Tgbuiltin + 1) /* "builtin" */
EXTERN const char T_function[] E_INIT(" function"); EXTERN const char T_function[] E_INIT(" function");
#define Tfunction (T_function + 1) /* "function" */ #define Tfunction (T_function + 1) /* "function" */
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
#define TC_IFSWS (TC_LEX1 + 7) /* space tab newline */
typedef uint8_t Temp_type; typedef uint8_t Temp_type;
/* expanded heredoc */ /* expanded heredoc */
@ -1281,6 +1283,7 @@ struct op {
#define SPAT 10 /* separate pattern: | */ #define SPAT 10 /* separate pattern: | */
#define CPAT 11 /* close pattern: ) */ #define CPAT 11 /* close pattern: ) */
#define ADELIM 12 /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */ #define ADELIM 12 /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
#define FUNSUB 14 /* ${ foo;} substitution (NUL terminated) */
/* /*
* IO redirection * IO redirection
@ -1903,7 +1906,7 @@ ssize_t shf_vfprintf(struct shf *, const char *, va_list)
void initkeywords(void); void initkeywords(void);
struct op *compile(Source *, bool); struct op *compile(Source *, bool);
bool parse_usec(const char *, struct timeval *); bool parse_usec(const char *, struct timeval *);
char *yyrecursive(void); char *yyrecursive(int);
/* tree.c */ /* tree.c */
void fptreef(struct shf *, int, const char *, ...); void fptreef(struct shf *, int, const char *, ...);
char *snptreef(char *, ssize_t, const char *, ...); char *snptreef(char *, ssize_t, const char *, ...);

36
syn.c
View File

@ -23,9 +23,9 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.78 2012/07/30 17:04:31 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.79 2012/07/30 21:37:16 tg Exp $");
extern short subshell_nesting_level; extern int subshell_nesting_type;
extern void yyskiputf8bom(void); extern void yyskiputf8bom(void);
struct nesting_state { struct nesting_state {
@ -363,12 +363,15 @@ get_command(int cf)
Leave: Leave:
break; break;
case '(': case '(': /*)*/ {
int subshell_nesting_type_saved;
Subshell: Subshell:
++subshell_nesting_level; subshell_nesting_type_saved = subshell_nesting_type;
subshell_nesting_type = ')';
t = nested(TPAREN, '(', ')'); t = nested(TPAREN, '(', ')');
--subshell_nesting_level; subshell_nesting_type = subshell_nesting_type_saved;
break; break;
}
case '{': /*}*/ case '{': /*}*/
t = nested(TBRACE, '{', '}'); t = nested(TBRACE, '{', '}');
@ -1115,16 +1118,29 @@ parse_usec(const char *s, struct timeval *tv)
* a COMSUB recursively using the main shell parser and lexer * a COMSUB recursively using the main shell parser and lexer
*/ */
char * char *
yyrecursive(void) yyrecursive(int subtype)
{ {
struct op *t; struct op *t;
char *cp; char *cp;
bool old_reject; bool old_reject;
int old_symbol, old_salias; int old_symbol, old_salias, old_nesting_type;
struct ioword **old_herep; struct ioword **old_herep;
int stok, etok;
switch (subtype) {
case FUNSUB:
stok = '{';
etok = '}';
break;
case COMSUB:
default:
stok = '(';
etok = ')';
}
/* tell the lexer to accept a closing parenthesis as EOD */ /* tell the lexer to accept a closing parenthesis as EOD */
++subshell_nesting_level; old_nesting_type = subshell_nesting_type;
subshell_nesting_type = etok;
/* push reject state, parse recursively, pop reject state */ /* push reject state, parse recursively, pop reject state */
old_reject = reject; old_reject = reject;
@ -1134,7 +1150,7 @@ yyrecursive(void)
old_salias = sALIAS; old_salias = sALIAS;
sALIAS = 0; sALIAS = 0;
/* we use TPAREN as a helper container here */ /* we use TPAREN as a helper container here */
t = nested(TPAREN, '(', ')'); t = nested(TPAREN, stok, etok);
sALIAS = old_salias; sALIAS = old_salias;
herep = old_herep; herep = old_herep;
reject = old_reject; reject = old_reject;
@ -1144,6 +1160,6 @@ yyrecursive(void)
cp = snptreef(NULL, 0, "%T", t->left); cp = snptreef(NULL, 0, "%T", t->left);
tfree(t, ATEMP); tfree(t, ATEMP);
--subshell_nesting_level; subshell_nesting_type = old_nesting_type;
return (cp); return (cp);
} }

21
tree.c
View File

@ -23,7 +23,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.62 2012/07/30 19:58:05 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.63 2012/07/30 21:37:17 tg Exp $");
#define INDENT 8 #define INDENT 8
@ -292,6 +292,7 @@ static const char *
wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode) wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
{ {
int c; int c;
const char *cs;
/*- /*-
* problems: * problems:
@ -335,16 +336,20 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
} }
case COMSUB: case COMSUB:
shf_puts("$(", shf); shf_puts("$(", shf);
cs = ")";
pSUB:
while ((c = *wp++) != 0) while ((c = *wp++) != 0)
shf_putc(c, shf); shf_putc(c, shf);
shf_putc(')', shf); shf_puts(cs, shf);
break; break;
case FUNSUB:
shf_puts("${ ", shf);
cs = ";}";
goto pSUB;
case EXPRSUB: case EXPRSUB:
shf_puts("$((", shf); shf_puts("$((", shf);
while ((c = *wp++) != 0) cs = "))";
shf_putc(c, shf); goto pSUB;
shf_puts("))", shf);
break;
case OQUOTE: case OQUOTE:
if (opmode & WDS_TPUTS) { if (opmode & WDS_TPUTS) {
quotelevel++; quotelevel++;
@ -580,6 +585,7 @@ wdscan(const char *wp, int c)
wp++; wp++;
break; break;
case COMSUB: case COMSUB:
case FUNSUB:
case EXPRSUB: case EXPRSUB:
while (*wp++ != 0) while (*wp++ != 0)
; ;
@ -819,6 +825,9 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
closeandout: closeandout:
shf_putc('>', shf); shf_putc('>', shf);
break; break;
case FUNSUB:
shf_puts("FUNSUB<", shf);
goto dumpsub;
case EXPRSUB: case EXPRSUB:
shf_puts("EXPRSUB<", shf); shf_puts("EXPRSUB<", shf);
goto dumpsub; goto dumpsub;

4
var.c
View File

@ -27,7 +27,7 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.152 2012/07/01 15:38:09 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/var.c,v 1.153 2012/07/30 21:37:17 tg Exp $");
/*- /*-
* Variables * Variables
@ -1254,7 +1254,7 @@ unsetspec(struct tbl *vp)
flushcom(true); flushcom(true);
break; break;
case V_IFS: case V_IFS:
setctypes(" \t\n", C_IFS); setctypes(TC_IFSWS, C_IFS);
ifs0 = ' '; ifs0 = ' ';
break; break;
case V_TMPDIR: case V_TMPDIR: