bring back ${ foo;} sans dot.mkshrc patch, using a temporary file, and as experimental feature
This commit is contained in:
7
Build.sh
7
Build.sh
@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.588 2012/10/22 16:53:20 tg Exp $'
|
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.589 2012/10/22 20:19:08 tg Exp $'
|
||||||
#-
|
#-
|
||||||
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
# 2011, 2012
|
# 2011, 2012
|
||||||
@ -1370,6 +1370,9 @@ ac_ifcpp 'ifdef MKSH_CONSERVATIVE_FDS' isset_MKSH_CONSERVATIVE_FDS '' \
|
|||||||
#ac_ifcpp 'ifdef MKSH_DISABLE_DEPRECATED' isset_MKSH_DISABLE_DEPRECATED '' \
|
#ac_ifcpp 'ifdef MKSH_DISABLE_DEPRECATED' isset_MKSH_DISABLE_DEPRECATED '' \
|
||||||
# "if deprecated features are to be omitted" && \
|
# "if deprecated features are to be omitted" && \
|
||||||
# check_categories="$check_categories nodeprecated"
|
# check_categories="$check_categories nodeprecated"
|
||||||
|
ac_ifcpp 'ifdef MKSH_DISABLE_EXPERIMENTAL' isset_MKSH_DISABLE_EXPERIMENTAL '' \
|
||||||
|
"if experimental features are to be omitted" && \
|
||||||
|
check_categories="$check_categories noexperimental"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Environment: headers
|
# Environment: headers
|
||||||
@ -1492,7 +1495,7 @@ else
|
|||||||
#define EXTERN
|
#define EXTERN
|
||||||
#define MKSH_INCLUDES_ONLY
|
#define MKSH_INCLUDES_ONLY
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.588 2012/10/22 16:53:20 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.589 2012/10/22 20:19:08 tg Exp $");
|
||||||
int main(void) { printf("Hello, World!\n"); return (0); }
|
int main(void) { printf("Hello, World!\n"); return (0); }
|
||||||
EOF
|
EOF
|
||||||
case $cm in
|
case $cm in
|
||||||
|
27
check.t
27
check.t
@ -1,4 +1,4 @@
|
|||||||
# $MirOS: src/bin/mksh/check.t,v 1.561 2012/10/21 21:55:01 tg Exp $
|
# $MirOS: src/bin/mksh/check.t,v 1.562 2012/10/22 20:19:10 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/10/21
|
@(#)MIRBSD KSH R40 2012/10/22
|
||||||
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/10/21
|
@(#)LEGACY KSH R40 2012/10/22
|
||||||
description:
|
description:
|
||||||
Check version of legacy shell.
|
Check version of legacy shell.
|
||||||
stdin:
|
stdin:
|
||||||
@ -9553,6 +9553,27 @@ 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
|
||||||
|
category: !noexperimental
|
||||||
|
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
|
||||||
|
47
eval.c
47
eval.c
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.128 2012/08/24 21:15:42 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.129 2012/10/22 20:19:12 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 *, bool);
|
static void glob(char *, XPtrV *, bool);
|
||||||
static void globit(XString *, char **, char *, XPtrV *, int);
|
static void globit(XString *, char **, char *, XPtrV *, int);
|
||||||
@ -277,18 +277,33 @@ expand(const char *cp, /* input word */
|
|||||||
quote = st->quotew;
|
quote = st->quotew;
|
||||||
continue;
|
continue;
|
||||||
case COMSUB:
|
case COMSUB:
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
case FUNSUB:
|
||||||
|
#endif
|
||||||
tilde_ok = 0;
|
tilde_ok = 0;
|
||||||
if (f & DONTRUNCOMMAND) {
|
if (f & DONTRUNCOMMAND) {
|
||||||
word = IFS_WORD;
|
word = IFS_WORD;
|
||||||
*dp++ = '$';
|
*dp++ = '$';
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
if (c == FUNSUB) {
|
||||||
|
*dp++ = '{';
|
||||||
|
*dp++ = ' ';
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
*dp++ = '(';
|
*dp++ = '(';
|
||||||
while (*sp != '\0') {
|
while (*sp != '\0') {
|
||||||
Xcheck(ds, dp);
|
Xcheck(ds, dp);
|
||||||
*dp++ = *sp++;
|
*dp++ = *sp++;
|
||||||
}
|
}
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
if (c == FUNSUB) {
|
||||||
|
*dp++ = ';';
|
||||||
|
*dp++ = '}';
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
*dp++ = ')';
|
*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;
|
||||||
@ -1272,7 +1287,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 MKSH_A_UNUSED)
|
||||||
{
|
{
|
||||||
Source *s, *sold;
|
Source *s, *sold;
|
||||||
struct op *t;
|
struct op *t;
|
||||||
@ -1307,6 +1322,30 @@ 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");
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
} else if (fn == FUNSUB) {
|
||||||
|
int ofd1;
|
||||||
|
struct temp *tf = NULL;
|
||||||
|
|
||||||
|
/* create a temporary file, open for writing */
|
||||||
|
maketemp(ATEMP, TT_FUNSUB, &tf);
|
||||||
|
if (!tf->shf) {
|
||||||
|
errorf("can't %s temporary file %s: %s",
|
||||||
|
"create", tf->tffn, strerror(errno));
|
||||||
|
}
|
||||||
|
/* save stdout and make the temporary file it */
|
||||||
|
ofd1 = savefd(1);
|
||||||
|
ksh_dup2(shf_fileno(tf->shf), 1, false);
|
||||||
|
/* run tree, with output thrown into the tempfile */
|
||||||
|
execute(t, XXCOM | XERROK, NULL);
|
||||||
|
/* close the tempfile and restore regular stdout */
|
||||||
|
shf_close(tf->shf);
|
||||||
|
restfd(1, ofd1);
|
||||||
|
/* now open, unlink and free the tempfile for reading */
|
||||||
|
shf = shf_open(tf->tffn, O_RDONLY, 0, SHF_MAPHI | SHF_CLEXEC);
|
||||||
|
unlink(tf->tffn);
|
||||||
|
afree(tf, ATEMP);
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
int ofd1, pv[2];
|
int ofd1, pv[2];
|
||||||
|
|
||||||
|
33
lex.c
33
lex.c
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.168 2012/10/03 17:24:20 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.169 2012/10/22 20:19:13 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;
|
||||||
uint8_t 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,13 @@ 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)))) {
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
if (state == SBASE &&
|
||||||
|
subshell_nesting_type == /*{*/ '}' &&
|
||||||
|
c == /*{*/ '}')
|
||||||
|
/* possibly end ${ :;} */
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
accept_nonword:
|
accept_nonword:
|
||||||
Xcheck(ws, wp);
|
Xcheck(ws, wp);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@ -395,14 +402,30 @@ yylex(int cf)
|
|||||||
} else {
|
} else {
|
||||||
ungetsc(c);
|
ungetsc(c);
|
||||||
subst_command:
|
subst_command:
|
||||||
sp = yyrecursive();
|
c = COMSUB;
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
subst_command2:
|
||||||
|
#endif
|
||||||
|
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 == '{') /*}*/ {
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
c = getsc();
|
||||||
|
if (ctype(c, C_IFSWS)) {
|
||||||
|
/*
|
||||||
|
* non-subenvironment
|
||||||
|
* "command" substitution
|
||||||
|
*/
|
||||||
|
c = FUNSUB;
|
||||||
|
goto subst_command2;
|
||||||
|
}
|
||||||
|
ungetsc(c);
|
||||||
|
#endif
|
||||||
*wp++ = OSUBST;
|
*wp++ = OSUBST;
|
||||||
*wp++ = '{'; /*}*/
|
*wp++ = '{'; /*}*/
|
||||||
wp = get_brace_var(&ws, wp);
|
wp = get_brace_var(&ws, wp);
|
||||||
@ -1171,7 +1194,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
|
||||||
|
16
main.c
16
main.c
@ -34,7 +34,7 @@
|
|||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.232 2012/10/22 16:53:22 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.233 2012/10/22 20:19:14 tg Exp $");
|
||||||
|
|
||||||
extern char **environ;
|
extern char **environ;
|
||||||
|
|
||||||
@ -1377,7 +1377,7 @@ void
|
|||||||
restfd(int fd, int ofd)
|
restfd(int fd, int ofd)
|
||||||
{
|
{
|
||||||
if (fd == 2)
|
if (fd == 2)
|
||||||
shf_flush(&shf_iob[fd]);
|
shf_flush(&shf_iob[/* fd */ 2]);
|
||||||
if (ofd < 0)
|
if (ofd < 0)
|
||||||
/* original fd closed */
|
/* original fd closed */
|
||||||
close(fd);
|
close(fd);
|
||||||
@ -1591,6 +1591,18 @@ maketemp(Area *ap, Temp_type type, struct temp **tlist)
|
|||||||
/* do another cycle */
|
/* do another cycle */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
if (type == TT_FUNSUB) {
|
||||||
|
int nfd;
|
||||||
|
|
||||||
|
/* map us high and mark as close-on-exec */
|
||||||
|
if ((nfd = savefd(i)) != i) {
|
||||||
|
close(i);
|
||||||
|
i = nfd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* shf_fdopen cannot fail, so no fd leak */
|
/* shf_fdopen cannot fail, so no fd leak */
|
||||||
tp->shf = shf_fdopen(i, SHF_WR, NULL);
|
tp->shf = shf_fdopen(i, SHF_WR, NULL);
|
||||||
|
|
||||||
|
11
mksh.1
11
mksh.1
@ -1,4 +1,4 @@
|
|||||||
.\" $MirOS: src/bin/mksh/mksh.1,v 1.295 2012/10/21 17:42:51 tg Exp $
|
.\" $MirOS: src/bin/mksh/mksh.1,v 1.296 2012/10/22 20:19:14 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: October 21 2012 $
|
.Dd $Mdocdate: October 22 2012 $
|
||||||
.\"
|
.\"
|
||||||
.\" Check which macro package we use, and do other -mdoc setup.
|
.\" Check which macro package we use, and do other -mdoc setup.
|
||||||
.\"
|
.\"
|
||||||
@ -1146,9 +1146,14 @@ 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 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
|
||||||
@ -1226,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
|
||||||
|
16
sh.h
16
sh.h
@ -157,9 +157,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXTERN
|
#ifdef EXTERN
|
||||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.596 2012/10/22 16:53:22 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.597 2012/10/22 20:19:16 tg Exp $");
|
||||||
#endif
|
#endif
|
||||||
#define MKSH_VERSION "R40 2012/10/21"
|
#define MKSH_VERSION "R40 2012/10/22"
|
||||||
|
|
||||||
/* arithmetic types: C implementation */
|
/* arithmetic types: C implementation */
|
||||||
#if !HAVE_CAN_INTTYPES
|
#if !HAVE_CAN_INTTYPES
|
||||||
@ -773,8 +773,12 @@ EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
|
|||||||
typedef uint8_t Temp_type;
|
typedef uint8_t Temp_type;
|
||||||
/* expanded heredoc */
|
/* expanded heredoc */
|
||||||
#define TT_HEREDOC_EXP 0
|
#define TT_HEREDOC_EXP 0
|
||||||
/* temp file used for history editing (fc -e) */
|
/* temporary file used for history editing (fc -e) */
|
||||||
#define TT_HIST_EDIT 1
|
#define TT_HIST_EDIT 1
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
/* temporary file used during in-situ command substitution */
|
||||||
|
#define TT_FUNSUB 2
|
||||||
|
#endif
|
||||||
|
|
||||||
/* temp/heredoc files. The file is removed when the struct is freed. */
|
/* temp/heredoc files. The file is removed when the struct is freed. */
|
||||||
struct temp {
|
struct temp {
|
||||||
@ -1286,6 +1290,9 @@ 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} */
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
#define FUNSUB 14 /* ${ foo;} substitution (NUL terminated) */
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IO redirection
|
* IO redirection
|
||||||
@ -1321,7 +1328,6 @@ struct ioword {
|
|||||||
#define XBGND BIT(2) /* command & */
|
#define XBGND BIT(2) /* command & */
|
||||||
#define XPIPEI BIT(3) /* input is pipe */
|
#define XPIPEI BIT(3) /* input is pipe */
|
||||||
#define XPIPEO BIT(4) /* output is pipe */
|
#define XPIPEO BIT(4) /* output is pipe */
|
||||||
#define XPIPE (XPIPEI|XPIPEO) /* member of pipe */
|
|
||||||
#define XXCOM BIT(5) /* `...` command */
|
#define XXCOM BIT(5) /* `...` command */
|
||||||
#define XPCLOSE BIT(6) /* exchild: close close_fd in parent */
|
#define XPCLOSE BIT(6) /* exchild: close close_fd in parent */
|
||||||
#define XCCLOSE BIT(7) /* exchild: close close_fd in child */
|
#define XCCLOSE BIT(7) /* exchild: close close_fd in child */
|
||||||
@ -1922,7 +1928,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 *, ...);
|
||||||
|
37
syn.c
37
syn.c
@ -23,12 +23,11 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.81 2012/10/03 15:50:32 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.82 2012/10/22 20:19:18 tg Exp $");
|
||||||
|
|
||||||
|
extern int subshell_nesting_type;
|
||||||
extern void yyskiputf8bom(void);
|
extern void yyskiputf8bom(void);
|
||||||
|
|
||||||
extern uint8_t subshell_nesting_level;
|
|
||||||
|
|
||||||
struct nesting_state {
|
struct nesting_state {
|
||||||
int start_token; /* token than began nesting (eg, FOR) */
|
int start_token; /* token than began nesting (eg, FOR) */
|
||||||
int start_line; /* line nesting began on */
|
int start_line; /* line nesting began on */
|
||||||
@ -364,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, '{', '}');
|
||||||
@ -1116,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 MKSH_A_UNUSED)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
if (subtype == FUNSUB) {
|
||||||
|
stok = '{';
|
||||||
|
etok = '}';
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
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;
|
||||||
@ -1135,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;
|
||||||
@ -1145,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);
|
||||||
}
|
}
|
||||||
|
16
tree.c
16
tree.c
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.64 2012/08/17 18:34:25 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.65 2012/10/22 20:19:18 tg Exp $");
|
||||||
|
|
||||||
#define INDENT 8
|
#define INDENT 8
|
||||||
|
|
||||||
@ -342,6 +342,12 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
|
|||||||
shf_putc(c, shf);
|
shf_putc(c, shf);
|
||||||
shf_puts(cs, shf);
|
shf_puts(cs, shf);
|
||||||
break;
|
break;
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
case FUNSUB:
|
||||||
|
shf_puts("${ ", shf);
|
||||||
|
cs = ";}";
|
||||||
|
goto pSUB;
|
||||||
|
#endif
|
||||||
case EXPRSUB:
|
case EXPRSUB:
|
||||||
shf_puts("$((", shf);
|
shf_puts("$((", shf);
|
||||||
cs = "))";
|
cs = "))";
|
||||||
@ -581,6 +587,9 @@ wdscan(const char *wp, int c)
|
|||||||
wp++;
|
wp++;
|
||||||
break;
|
break;
|
||||||
case COMSUB:
|
case COMSUB:
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
case FUNSUB:
|
||||||
|
#endif
|
||||||
case EXPRSUB:
|
case EXPRSUB:
|
||||||
while (*wp++ != 0)
|
while (*wp++ != 0)
|
||||||
;
|
;
|
||||||
@ -820,6 +829,11 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
|
|||||||
closeandout:
|
closeandout:
|
||||||
shf_putc('>', shf);
|
shf_putc('>', shf);
|
||||||
break;
|
break;
|
||||||
|
#ifndef MKSH_DISABLE_EXPERIMENTAL
|
||||||
|
case FUNSUB:
|
||||||
|
shf_puts("FUNSUB<", shf);
|
||||||
|
goto dumpsub;
|
||||||
|
#endif
|
||||||
case EXPRSUB:
|
case EXPRSUB:
|
||||||
shf_puts("EXPRSUB<", shf);
|
shf_puts("EXPRSUB<", shf);
|
||||||
goto dumpsub;
|
goto dumpsub;
|
||||||
|
Reference in New Issue
Block a user