implement VALSUBs

This commit is contained in:
tg 2013-05-02 21:59:54 +00:00
parent 54a698d564
commit 1d0409d932
10 changed files with 130 additions and 53 deletions

View File

@ -1,5 +1,5 @@
#!/bin/sh
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.629 2013/05/02 20:21:36 tg Exp $'
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.630 2013/05/02 21:59:44 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -1531,7 +1531,7 @@ else
#define EXTERN
#define MKSH_INCLUDES_ONLY
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.629 2013/05/02 20:21:36 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.630 2013/05/02 21:59:44 tg Exp $");
int main(void) { printf("Hello, World!\n"); return (0); }
EOF
case $cm in
@ -2046,7 +2046,7 @@ addsrcs USE_PRINTF_BUILTIN printf.c
test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
test -n "$LDSTATIC" && add_cppflags -DMKSH_OPTSTATIC
add_cppflags -DMKSH_BUILD_R=459
add_cppflags -DMKSH_BUILD_R=461
$e $bi$me: Finished configuration testing, now producing output.$ao

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/Makefile,v 1.120 2013/04/27 18:50:21 tg Exp $
# $MirOS: src/bin/mksh/Makefile,v 1.121 2013/05/02 21:59:45 tg Exp $
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -54,7 +54,7 @@ CPPFLAGS+= -DMKSH_ASSUME_UTF8 -DMKSH_DISABLE_DEPRECATED \
-DHAVE_SETGROUPS=1 -DHAVE_STRERROR=0 -DHAVE_STRSIGNAL=0 \
-DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
-DHAVE_SYS_ERRLIST_DECL=1 -DHAVE_SYS_SIGLIST_DECL=1 \
-DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=459
-DHAVE_PERSISTENT_HISTORY=1 -DMKSH_BUILD_R=461
CPPFLAGS+= -D${${PROG:L}_tf:C/(Mir${MAN:E}{0,1}){2}/4/:S/x/mksh_BUILD/:U}
COPTS+= -std=c99 -Wall
.endif

63
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.611 2013/05/02 20:28:10 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.612 2013/05/02 21:59:45 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 $
@ -29,7 +29,7 @@
# http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
expected-stdout:
@(#)MIRBSD KSH R45 2013/04/27
@(#)MIRBSD KSH R46 2013/05/02
description:
Check version of shell.
stdin:
@ -38,7 +38,7 @@ name: KSH_VERSION
category: shell:legacy-no
---
expected-stdout:
@(#)LEGACY KSH R45 2013/04/27
@(#)LEGACY KSH R46 2013/05/02
description:
Check version of legacy shell.
stdin:
@ -8922,8 +8922,8 @@ stdin:
EOFI
#IORDWR_IODUP
sh 1<>/dev/console 0<&1 2>&1
#COMSUB_EXPRSUB
echo $(true) $((1+ 2))
#COMSUB_EXPRSUB_FUNSUB_VALSUB
echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
#QCHAR_OQUOTE_CQUOTE
echo fo\ob\"a\`r\'b\$az
echo "fo\ob\"a\`r\'b\$az"
@ -9305,23 +9305,23 @@ expected-stdout:
function reread_IORDWR_IODUP {
x=$(( sh 1<>/dev/console <&1 2>&1 ) | tr u x )
}
inline_COMSUB_EXPRSUB() {
echo $(true) $((1+ 2))
inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
}
inline_COMSUB_EXPRSUB() {
echo $(true ) $((1+ 2))
inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;}
}
function comsub_COMSUB_EXPRSUB { x=$(
echo $(true) $((1+ 2))
function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$(
echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
); }
function comsub_COMSUB_EXPRSUB {
x=$(echo $(true ) $((1+ 2)) )
function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB {
x=$(echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} )
}
function reread_COMSUB_EXPRSUB { x=$((
echo $(true) $((1+ 2))
function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$((
echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
)|tr u x); }
function reread_COMSUB_EXPRSUB {
x=$(( echo $(true ) $((1+ 2)) ) | tr u x )
function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB {
x=$(( echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} ) | tr u x )
}
inline_QCHAR_OQUOTE_CQUOTE() {
echo fo\ob\"a\`r\'b\$az
@ -9907,6 +9907,35 @@ expected-stdout:
2:ya x2,1,0.
3:ya,1,3.
---
name: valsub-1
description:
Check that "value substitutions" work as advertised
stdin:
x=1
y=2
z=3
REPLY=4
echo "before: x<$x> y<$y> z<$z> R<$REPLY>"
x=${|
local y
echo "begin: x<$x> y<$y> z<$z> R<$REPLY>"
x=5
y=6
z=7
REPLY=8
echo "end: x<$x> y<$y> z<$z> R<$REPLY>"
}
echo "after: x<$x> y<$y> z<$z> R<$REPLY>"
# ensure trailing newlines are kept
t=${|REPLY=$'foo\n\n';}
typeset -p t
expected-stdout:
before: x<1> y<2> z<3> R<4>
begin: x<1> y<> z<3> R<>
end: x<5> y<6> z<7> R<8>
after: x<8> y<2> z<7> R<4>
typeset t=$'foo\n\n'
---
name: test-stnze-1
description:
Check that the short form [ $x ] works

View File

@ -1,5 +1,5 @@
# $Id$
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.81 2013/05/02 21:46:29 tg Exp $
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.82 2013/05/02 21:59:48 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013
@ -31,19 +31,20 @@ esac
PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
2>/dev/null)} = *([ ]|localhost) ]] && HOSTNAME=$(ulimit -c 0; hostname \
2>/dev/null); : ${EDITOR:=/bin/ed} ${HOSTNAME:=nil} ${TERM:=vt100}
function precmd {
: ${MKSH:=$(whence -p mksh)}; PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
local e=$?
(( e )) && print -n "$e|"
# precmd is required to retain the errorlevel when ${ …;} is used
(( e )) && REPLY+="$e|"
REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)}
REPLY+=@${HOSTNAME%%.*}:
local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
local m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
REPLY+=$p$d
return $e
}
PS1=$'\001\r''${ precmd;}${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?
)}@${HOSTNAME%%.*}:${ local e=$? d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || \
d=${d/#$p/~}; local m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || \
p=; print -nr -- "$p$d"; return $e;} '"$PS1 "; PS4='[$EPOCHREALTIME] '
: ${MKSH:=$(whence -p mksh)}; export EDITOR HOSTNAME MKSH TERM USER
} '"$PS1 "; export EDITOR HOSTNAME MKSH TERM USER
alias ls=ls
unalias ls
alias l='ls -F'

36
eval.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.138 2013/03/29 17:33:06 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.139 2013/05/02 21:59:49 tg Exp $");
/*
* string expansion
@ -66,6 +66,7 @@ typedef struct {
static int varsub(Expand *, const char *, const char *, int *, int *);
static int comsub(Expand *, const char *, int);
static void funsub(struct op *);
static char *valsub(struct op *, Area *);
static char *trimsub(char *, char *, int);
static void glob(char *, XPtrV *, bool);
static void globit(XString *, char **, char *, XPtrV *, int);
@ -298,27 +299,26 @@ expand(
continue;
case COMSUB:
case FUNSUB:
case VALSUB:
tilde_ok = 0;
if (f & DONTRUNCOMMAND) {
word = IFS_WORD;
*dp++ = '$';
if (c == FUNSUB) {
*dp++ = '{';
*dp++ = ' ';
} else
*dp++ = '(';
*dp++ = c == COMSUB ? '(' : '{';
if (c != COMSUB)
*dp++ = c == FUNSUB ? ' ' : '|';
while (*sp != '\0') {
Xcheck(ds, dp);
*dp++ = *sp++;
}
if (c == FUNSUB) {
if (c != COMSUB) {
*dp++ = ';';
*dp++ = '}';
} else
*dp++ = ')';
} else {
type = comsub(&x, sp, c);
if (type == XCOM && (f&DOBLANK))
if (type != XBASE && (f & DOBLANK))
doblank++;
sp = strnul(sp) + 1;
newlines = 0;
@ -1366,6 +1366,10 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
/* rewind the tempfile and restore regular stdout */
lseek(shf_fileno(shf), (off_t)0, SEEK_SET);
restfd(1, ofd1);
} else if (fn == VALSUB) {
xp->str = valsub(t, ATEMP);
subst_exstat = exstat & 0xFF;
return (XSUB);
} else {
int ofd1, pv[2];
@ -1832,3 +1836,19 @@ funsub(struct op *t)
execute(t, XXCOM | XERROK, NULL);
popblock();
}
static char *
valsub(struct op *t, Area *ap)
{
char *cp;
struct tbl *vp;
newblock();
vp = local("REPLY", false);
e->type = E_FUNC;
if (!kshsetjmp(e->jbuf))
execute(t, XXCOM | XERROK, NULL);
strdupx(cp, str_val(vp), ap);
popblock();
return (cp);
}

12
lex.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.184 2013/03/29 17:33:55 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.185 2013/05/02 21:59:49 tg Exp $");
/*
* states while lexing word
@ -421,8 +421,14 @@ yylex(int cf)
wp += cz;
}
} else if (c == '{') /*}*/ {
c = getsc();
if (ctype(c, C_IFSWS)) {
if ((c = getsc()) == '|') {
/*
* non-subenvironment
* value substitution
*/
c = VALSUB;
goto subst_command2;
} else if (ctype(c, C_IFSWS)) {
/*
* non-subenvironment
* "command" substitution

11
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.314 2013/05/02 20:28:13 tg Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.315 2013/05/02 21:59:50 tg Exp $
.\" $OpenBSD: ksh.1,v 1.146 2013/03/18 11:10:52 mpi Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@ -1182,6 +1182,15 @@ work, and in that
.Ic exit
terminates the parent shell.
.Pp
Another variant of substitution are the valsubs (value substitutions)
.Pf ${\*(Ba\& Ns Ar command Ns \&;}
which are also executed in the current environment, like funsubs, but
share their I/O with the parent; instead, they evaluate to whatever
the, initially empty, expression-local variable
.Ev REPLY
is set to within the
.Ar command Ns No s .
.Pp
If a substitution appears outside of double quotes, the results of the
substitution are generally subject to word or field splitting according to
the current value of the

7
sh.h
View File

@ -164,9 +164,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.653 2013/04/27 19:16:27 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.654 2013/05/02 21:59:52 tg Exp $");
#endif
#define MKSH_VERSION "R45 2013/04/27"
#define MKSH_VERSION "R46 2013/05/02"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
@ -520,7 +520,7 @@ char *ucstrstr(char *, const char *);
#define mkssert(e) do { } while (/* CONSTCOND */ 0)
#endif
#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 459)
#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 461)
#error Must run Build.sh to compile this.
int
im_sorry_dave(void)
@ -1327,6 +1327,7 @@ struct op {
#define CPAT 11 /* close pattern: ) */
#define ADELIM 12 /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
#define FUNSUB 14 /* ${ foo;} substitution (NUL terminated) */
#define VALSUB 15 /* ${|foo;} substitution (NUL terminated) */
/*
* IO redirection

4
syn.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.90 2013/04/26 21:22:50 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.91 2013/05/02 21:59:53 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
@ -1129,7 +1129,7 @@ yyrecursive(int subtype MKSH_A_UNUSED)
struct yyrecursive_state *ys;
int stok, etok;
if (subtype == FUNSUB) {
if (subtype != COMSUB) {
stok = '{';
etok = '}';
} else {

17
tree.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012
* 2011, 2012, 2013
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.68 2013/03/24 00:56:27 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.69 2013/05/02 21:59:54 tg Exp $");
#define INDENT 8
@ -349,7 +349,14 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
shf_puts(cs, shf);
break;
case FUNSUB:
shf_puts("${ ", shf);
c = ' ';
if (0)
/* FALLTHROUGH */
case VALSUB:
c = '|';
shf_putc('$', shf);
shf_putc('{', shf);
shf_putc(c, shf);
cs = ";}";
goto pSUB;
case EXPRSUB:
@ -592,6 +599,7 @@ wdscan(const char *wp, int c)
break;
case COMSUB:
case FUNSUB:
case VALSUB:
case EXPRSUB:
while (*wp++ != 0)
;
@ -834,6 +842,9 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
case FUNSUB:
shf_puts("FUNSUB<", shf);
goto dumpsub;
case VALSUB:
shf_puts("VALSUB<", shf);
goto dumpsub;
case EXPRSUB:
shf_puts("EXPRSUB<", shf);
goto dumpsub;