summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2016-02-03 01:14:56 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-02-03 01:14:56 +0000
commitb394f11bc41d75abb6fc623dd9e15eef626eb380 (patch)
treee3963fe270bfdcebde4a60507c95ae519f25626f
parentf688e8a1ab15366682b71b040c32e1518ff7bd50 (diff)
parentfc0307d88e2ab13777f102dc63c0d1c968dc8bb2 (diff)
downloadmksh-brillo-m10-release.tar.gz
Merge "Upgrade to mksh R52b."android-wear-n-preview-3android-wear-n-preview-2android-wear-n-preview-1android-wear-7.1.1_r1android-n-preview-5android-n-preview-4android-n-preview-3android-n-preview-2android-n-preview-1android-n-iot-preview-2android-cts_7.1_r1android-cts-7.1_r9android-cts-7.1_r8android-cts-7.1_r7android-cts-7.1_r6android-cts-7.1_r5android-cts-7.1_r4android-cts-7.1_r3android-cts-7.1_r29android-cts-7.1_r28android-cts-7.1_r27android-cts-7.1_r26android-cts-7.1_r25android-cts-7.1_r24android-cts-7.1_r23android-cts-7.1_r22android-cts-7.1_r21android-cts-7.1_r20android-cts-7.1_r2android-cts-7.1_r19android-cts-7.1_r18android-cts-7.1_r17android-cts-7.1_r16android-cts-7.1_r15android-cts-7.1_r14android-cts-7.1_r13android-cts-7.1_r12android-cts-7.1_r11android-cts-7.1_r10android-cts-7.1_r1android-cts-7.0_r9android-cts-7.0_r8android-cts-7.0_r7android-cts-7.0_r6android-cts-7.0_r5android-cts-7.0_r4android-cts-7.0_r33android-cts-7.0_r32android-cts-7.0_r31android-cts-7.0_r30android-cts-7.0_r3android-cts-7.0_r29android-cts-7.0_r28android-cts-7.0_r27android-cts-7.0_r26android-cts-7.0_r25android-cts-7.0_r24android-cts-7.0_r23android-cts-7.0_r22android-cts-7.0_r21android-cts-7.0_r20android-cts-7.0_r2android-cts-7.0_r19android-cts-7.0_r18android-cts-7.0_r17android-cts-7.0_r16android-cts-7.0_r15android-cts-7.0_r14android-cts-7.0_r13android-cts-7.0_r12android-cts-7.0_r11android-cts-7.0_r10android-cts-7.0_r1android-7.1.2_r9android-7.1.2_r8android-7.1.2_r6android-7.1.2_r5android-7.1.2_r4android-7.1.2_r39android-7.1.2_r38android-7.1.2_r37android-7.1.2_r36android-7.1.2_r33android-7.1.2_r32android-7.1.2_r30android-7.1.2_r3android-7.1.2_r29android-7.1.2_r28android-7.1.2_r27android-7.1.2_r25android-7.1.2_r24android-7.1.2_r23android-7.1.2_r2android-7.1.2_r19android-7.1.2_r18android-7.1.2_r17android-7.1.2_r16android-7.1.2_r15android-7.1.2_r14android-7.1.2_r13android-7.1.2_r12android-7.1.2_r11android-7.1.2_r10android-7.1.2_r1android-7.1.1_r9android-7.1.1_r8android-7.1.1_r7android-7.1.1_r61android-7.1.1_r60android-7.1.1_r6android-7.1.1_r59android-7.1.1_r58android-7.1.1_r57android-7.1.1_r56android-7.1.1_r55android-7.1.1_r54android-7.1.1_r53android-7.1.1_r52android-7.1.1_r51android-7.1.1_r50android-7.1.1_r49android-7.1.1_r48android-7.1.1_r47android-7.1.1_r46android-7.1.1_r45android-7.1.1_r44android-7.1.1_r43android-7.1.1_r42android-7.1.1_r41android-7.1.1_r40android-7.1.1_r4android-7.1.1_r39android-7.1.1_r38android-7.1.1_r35android-7.1.1_r33android-7.1.1_r32android-7.1.1_r31android-7.1.1_r3android-7.1.1_r28android-7.1.1_r27android-7.1.1_r26android-7.1.1_r25android-7.1.1_r24android-7.1.1_r23android-7.1.1_r22android-7.1.1_r21android-7.1.1_r20android-7.1.1_r2android-7.1.1_r17android-7.1.1_r16android-7.1.1_r15android-7.1.1_r14android-7.1.1_r13android-7.1.1_r12android-7.1.1_r11android-7.1.1_r10android-7.1.1_r1android-7.1.0_r7android-7.1.0_r6android-7.1.0_r5android-7.1.0_r4android-7.1.0_r3android-7.1.0_r2android-7.1.0_r1android-7.0.0_r9android-7.0.0_r8android-7.0.0_r7android-7.0.0_r6android-7.0.0_r5android-7.0.0_r4android-7.0.0_r36android-7.0.0_r35android-7.0.0_r34android-7.0.0_r33android-7.0.0_r32android-7.0.0_r31android-7.0.0_r30android-7.0.0_r3android-7.0.0_r29android-7.0.0_r28android-7.0.0_r27android-7.0.0_r24android-7.0.0_r21android-7.0.0_r19android-7.0.0_r17android-7.0.0_r15android-7.0.0_r14android-7.0.0_r13android-7.0.0_r12android-7.0.0_r11android-7.0.0_r10android-7.0.0_r1nougat-releasenougat-mr2.3-releasenougat-mr2.2-releasenougat-mr2.1-releasenougat-mr2-security-releasenougat-mr2-releasenougat-mr2-pixel-releasenougat-mr2-devnougat-mr1.8-releasenougat-mr1.7-releasenougat-mr1.6-releasenougat-mr1.5-releasenougat-mr1.4-releasenougat-mr1.3-releasenougat-mr1.2-releasenougat-mr1.1-releasenougat-mr1-wear-releasenougat-mr1-volantis-releasenougat-mr1-security-releasenougat-mr1-releasenougat-mr1-flounder-releasenougat-mr1-devnougat-mr1-cts-releasenougat-mr0.5-releasenougat-dr1-releasenougat-devnougat-cts-releasenougat-bugfix-releasen-iot-preview-2brillo-m10-releasebrillo-m10-dev
-rw-r--r--Android.mk3
-rw-r--r--src/Build.sh29
-rw-r--r--src/check.pl4
-rw-r--r--src/check.t776
-rw-r--r--src/dot.mkshrc27
-rw-r--r--src/edit.c20
-rw-r--r--src/emacsfn.h22
-rw-r--r--src/eval.c128
-rw-r--r--src/exec.c90
-rw-r--r--src/expr.c11
-rw-r--r--src/funcs.c315
-rw-r--r--src/histrap.c16
-rw-r--r--src/jobs.c70
-rw-r--r--src/lalloc.c4
-rw-r--r--src/lex.c198
-rw-r--r--src/lksh.177
-rw-r--r--src/main.c29
-rw-r--r--src/mirhash.h4
-rw-r--r--src/misc.c14
-rw-r--r--src/mksh.1336
-rw-r--r--src/rlimits.gen23
-rw-r--r--src/rlimits.opt22
-rw-r--r--src/sh.h61
-rw-r--r--src/sh_flags.gen23
-rw-r--r--src/sh_flags.opt22
-rw-r--r--src/shf.c18
-rw-r--r--src/strlcpy.c4
-rw-r--r--src/syn.c81
-rw-r--r--src/tree.c86
-rw-r--r--src/var.c90
-rw-r--r--src/var_spec.h22
31 files changed, 1452 insertions, 1173 deletions
diff --git a/Android.mk b/Android.mk
index 9b1d914..12f3c83 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,6 +36,7 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/src
# Additional flags first...
LOCAL_CFLAGS += \
+ -DMKSH_DEFAULT_PROFILEDIR=\"/system/etc\" \
-DMKSHRC_PATH=\"/system/etc/mkshrc\" \
-DMKSH_DEFAULT_EXECSHELL=\"/system/bin/sh\" \
-DMKSH_DEFAULT_TMPDIR=\"/data/local\" \
@@ -79,6 +80,6 @@ LOCAL_CFLAGS += \
-DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 \
-DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
-DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 \
- -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=511
+ -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=521
include $(BUILD_EXECUTABLE)
diff --git a/src/Build.sh b/src/Build.sh
index d5884be..0bd52d5 100644
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,9 +1,9 @@
#!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.689 2015/07/10 17:16:23 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.695 2016/01/02 20:11:31 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-# 2011, 2012, 2013, 2014, 2015
-# Thorsten “mirabilos” Glaser <tg@mirbsd.org>
+# 2011, 2012, 2013, 2014, 2015, 2016
+# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
@@ -100,6 +100,7 @@ do_genopt() {
srcfile=$1
test -f "$srcfile" || genopt_die Source file \$srcfile not set.
bn=`basename "$srcfile" | sed 's/.opt$//'`
+ o_hdr='/* +++ GENERATED FILE +++ DO NOT EDIT +++ */'
o_gen=
o_str=
o_sym=
@@ -128,6 +129,9 @@ do_genopt() {
;;
*:@@*)
genopt_die ;;
+ 0:/\*-|0:\ \**|0:)
+ o_hdr=$o_hdr$nl$line
+ ;;
0:@*|1:@*)
# begin of a definition block
sym=`echo "$line" | sed 's/^@//'`
@@ -177,6 +181,7 @@ do_genopt() {
echo "\"$opts\""
test -n "$cond" && echo "#endif"
done | {
+ echo "$o_hdr"
echo "#ifndef $o_sym$o_gen"
echo "#else"
cat
@@ -740,6 +745,7 @@ GNU)
*tendracc*) ;;
*) add_cppflags -D_GNU_SOURCE ;;
esac
+ add_cppflags -DSETUID_CAN_FAIL_WITH_EAGAIN
# define MKSH__NO_PATH_MAX to use Hurd-only functions
add_cppflags -DMKSH__NO_PATH_MAX
;;
@@ -748,6 +754,7 @@ GNU/kFreeBSD)
*tendracc*) ;;
*) add_cppflags -D_GNU_SOURCE ;;
esac
+ add_cppflags -DSETUID_CAN_FAIL_WITH_EAGAIN
;;
Haiku)
add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1
@@ -1195,7 +1202,7 @@ tcc)
;;
tendra)
vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V 2>&1 | \
- fgrep -i -e version -e release"
+ grep -F -i -e version -e release"
;;
ucode)
vv '|' "$CC $CFLAGS $CPPFLAGS $LDFLAGS $NOWARN $LIBS -V"
@@ -1232,19 +1239,20 @@ dragonegg|llvm)
vv '|' "llc -version"
;;
esac
+etd=" on $et"
case $et in
klibc)
add_cppflags -DMKSH_NO_LIMITS
;;
unknown)
# nothing special detected, don’t worry
- unset et
+ etd=
;;
*)
# huh?
;;
esac
-$e "$bi==> which compiler seems to be used...$ao $ui$ct${et+ on $et}$ao"
+$e "$bi==> which compiler seems to be used...$ao $ui$ct$etd$ao"
rmf conftest.c conftest.o conftest a.out* a.exe* conftest.exe* vv.out
#
@@ -1918,11 +1926,6 @@ ac_test gettimeofday <<-'EOF'
int main(void) { struct timeval tv; return (gettimeofday(&tv, NULL)); }
EOF
-ac_test issetugid <<-'EOF'
- #include <unistd.h>
- int main(void) { return (issetugid()); }
-EOF
-
ac_test killpg <<-'EOF'
#include <signal.h>
int main(int ac, char *av[]) { return (av[0][killpg(123, ac)]); }
@@ -2342,7 +2345,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c
addsrcs USE_PRINTF_BUILTIN printf.c
test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
-add_cppflags -DMKSH_BUILD_R=511
+add_cppflags -DMKSH_BUILD_R=521
$e $bi$me: Finished configuration testing, now producing output.$ao
@@ -2414,7 +2417,7 @@ cat >test.sh <<-EOF
args[\${#args[*]}]=\$TMPDIR
fi
print Testing mksh for conformance:
- fgrep -e MirOS: -e MIRBSD "\$sflag"
+ grep -F -e Mir''OS: -e MIRBSD "\$sflag"
print "This shell is actually:\\n\\t\$KSH_VERSION"
print 'test.sh built for mksh $dstversion'
cstr='\$os = defined \$^O ? \$^O : "unknown";'
diff --git a/src/check.pl b/src/check.pl
index 4417f82..a80d4e1 100644
--- a/src/check.pl
+++ b/src/check.pl
@@ -1,9 +1,9 @@
-# $MirOS: src/bin/mksh/check.pl,v 1.40 2015/07/10 19:36:31 tg Exp $
+# $MirOS: src/bin/mksh/check.pl,v 1.42 2015/11/29 17:05:00 tg Exp $
# $OpenBSD: th,v 1.1 2013/12/02 20:39:44 millert Exp $
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
# 2012, 2013, 2014, 2015
-# Thorsten Glaser <tg@mirbsd.org>
+# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
diff --git a/src/check.t b/src/check.t
index 989722b..98d260d 100644
--- a/src/check.t
+++ b/src/check.t
@@ -1,9 +1,9 @@
-# $MirOS: src/bin/mksh/check.t,v 1.703 2015/07/10 19:36:31 tg Exp $
+# $MirOS: src/bin/mksh/check.t,v 1.721 2016/01/20 21:34:09 tg Exp $
# -*- mode: sh -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-# 2011, 2012, 2013, 2014, 2015
-# Thorsten Glaser <tg@mirbsd.org>
+# 2011, 2012, 2013, 2014, 2015, 2016
+# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
@@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout:
- @(#)MIRBSD KSH R51 2015/07/10
+ @(#)MIRBSD KSH R52 2016/01/20
description:
Check version of shell.
stdin:
@@ -39,7 +39,7 @@ name: KSH_VERSION
category: shell:legacy-no
---
expected-stdout:
- @(#)LEGACY KSH R51 2015/07/10
+ @(#)LEGACY KSH R52 2016/01/20
description:
Check version of legacy shell.
stdin:
@@ -270,6 +270,14 @@ stdin:
expected-stdout:
bar - baz,z
---
+name: arith-compound
+description:
+ Check that arithmetic expressions are compound constructs
+stdin:
+ { ! (( 0$(cat >&2) )) <<<1; } <<<2
+expected-stderr:
+ 1
+---
name: arith-lazy-1
description:
Check that only one side of ternary operator is evaluated
@@ -475,6 +483,9 @@ stdin:
va[1975973142]=right
va[4123456789]=wrong
echo x7 ${va[#4123456789%2147483647]}
+ # make sure multiple calculations don't interfere with each other
+ let '# mca = -4 % -2' ' mcb = -4 % -2'
+ echo x8 $mca $mcb
expected-stdout:
x1 -1 4294967295
x2 -171510507 4123456789
@@ -483,6 +494,7 @@ expected-stdout:
x5 -171510507 4123456789
x6 1975973142 1975973142
x7 right
+ x8 -4 0
---
name: arith-limit32-1
description:
@@ -1664,6 +1676,17 @@ expected-stdout:
1=02.
2=02.
---
+name: expand-weird-4
+description:
+ Check that tilde expansion is enabled in ${x#~}
+ and cases that are modelled after it (${x/~/~})
+stdin:
+ HOME=/etc
+ a="~/x"
+ echo "<${a#~}> <${a#\~}> <${b:-~}> <${b:-\~}> <${c:=~}><$c> <${a/~}> <${a/x/~}> <${a/x/\~}>"
+expected-stdout:
+ <~/x> </x> <~> <\~> <~><~> <~/x> <~//etc> <~/~>
+---
name: expand-number-1
description:
Check that positional arguments do not overflow
@@ -1857,13 +1880,15 @@ stdin:
echo 20: ${x/\//.}
echo 21: ${x//\//.}
echo 22: ${x///.}
- echo 23: ${x//#1/9}
- echo 24: ${x//%1/9}
- echo 25: ${x//\%1/9}
- echo 26: ${x//\\%1/9}
- echo 27: ${x//\a/9}
- echo 28: ${x//\\a/9}
- echo 29: ${x/2/$y}
+ echo 23: ${x/#1/9}
+ echo 24: ${x//#1/9}
+ echo 25: ${x/%1/9}
+ echo 26: ${x//%1/9}
+ echo 27: ${x//\%1/9}
+ echo 28: ${x//\\%1/9}
+ echo 29: ${x//\a/9}
+ echo 30: ${x//\\a/9}
+ echo 31: ${x/2/$y}
expected-stdout:
1: 122321_ab/cde_b/c_1221
2: 131_ab/cde_b/c_11
@@ -1888,12 +1913,14 @@ expected-stdout:
21: 1222321_ab.cde_b.c_1221
22: 1222321_ab/cde_b/c_1221
23: 9222321_ab/cde_b/c_1221
- 24: 1222321_ab/cde_b/c_1229
+ 24: 1222321_ab/cde_b/c_1221
25: 1222321_ab/cde_b/c_1229
26: 1222321_ab/cde_b/c_1221
- 27: 1222321_9b/cde_b/c_1221
- 28: 1222321_9b/cde_b/c_1221
- 29: 1xyz22321_ab/cde_b/c_1221
+ 27: 1222321_ab/cde_b/c_1221
+ 28: 1222321_ab/cde_b/c_1221
+ 29: 1222321_9b/cde_b/c_1221
+ 30: 1222321_ab/cde_b/c_1221
+ 31: 1xyz22321_ab/cde_b/c_1221
---
name: eglob-substrpl-2
description:
@@ -1918,6 +1945,7 @@ name: eglob-substrpl-3a
description:
Check substring replacement works with variables and slashes, too
stdin:
+ HOME=/etc
pfx=/home/user
wd=/home/user/tmp
echo "${wd/#$pfx/~}"
@@ -1927,9 +1955,9 @@ stdin:
echo "${wd/#"\$pfx"/~}"
echo "${wd/#'\$pfx'/~}"
expected-stdout:
- ~/tmp
+ /etc/tmp
/home/user/tmp
- ~/tmp
+ /etc/tmp
/home/user/tmp
/home/user/tmp
/home/user/tmp
@@ -1938,20 +1966,22 @@ name: eglob-substrpl-3b
description:
More of this, bash fails it (bash4 passes)
stdin:
+ HOME=/etc
pfx=/home/user
wd=/home/user/tmp
echo "${wd/#$(echo /home/user)/~}"
echo "${wd/#"$(echo /home/user)"/~}"
echo "${wd/#'$(echo /home/user)'/~}"
expected-stdout:
- ~/tmp
- ~/tmp
+ /etc/tmp
+ /etc/tmp
/home/user/tmp
---
name: eglob-substrpl-3c
description:
Even more weird cases
stdin:
+ HOME=/etc
pfx=/home/user
wd='$pfx/tmp'
echo 1: ${wd/#$pfx/~}
@@ -1977,31 +2007,31 @@ stdin:
echo 17: ${ts/+($tp)/$tr}
echo 18: ${ts/+($tp)/c/d}
echo 19: ${ts/+($tp)/c\/d}
- echo 25: ${ts//a\/b/$tr}
- echo 26: ${ts//a\/b/\$tr}
- echo 27: ${ts//$tp/$tr}
- echo 28: ${ts//$tp/c/d}
- echo 29: ${ts//$tp/c\/d}
- echo 30: ${ts//+(a\/b)/$tr}
- echo 31: ${ts//+(a\/b)/\$tr}
- echo 32: ${ts//+($tp)/$tr}
- echo 33: ${ts//+($tp)/c/d}
- echo 34: ${ts//+($tp)/c\/d}
+ echo 20: ${ts//a\/b/$tr}
+ echo 21: ${ts//a\/b/\$tr}
+ echo 22: ${ts//$tp/$tr}
+ echo 23: ${ts//$tp/c/d}
+ echo 24: ${ts//$tp/c\/d}
+ echo 25: ${ts//+(a\/b)/$tr}
+ echo 26: ${ts//+(a\/b)/\$tr}
+ echo 27: ${ts//+($tp)/$tr}
+ echo 28: ${ts//+($tp)/c/d}
+ echo 29: ${ts//+($tp)/c\/d}
tp="+($tp)"
- echo 40: ${ts/$tp/$tr}
- echo 41: ${ts//$tp/$tr}
+ echo 30: ${ts/$tp/$tr}
+ echo 31: ${ts//$tp/$tr}
expected-stdout:
1: $pfx/tmp
- 2: ~/tmp
+ 2: /etc/tmp
3: $pfx/tmp
- 4: ~/tmp
- 5: ~/tmp
- 6: ~/tmp
+ 4: /etc/tmp
+ 5: /etc/tmp
+ 6: $pfx/tmp
7: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
8: $tra/b$tp$tp_a/b$tp_*(a/b)_*($tp)
9: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
10: a/ba/bc/d$tp_a/b$tp_*(a/b)_*($tp)
- 11: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
+ 11: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
12: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
13: c/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
14: c\/da/b$tp$tp_a/b$tp_*(a/b)_*($tp)
@@ -2010,21 +2040,21 @@ expected-stdout:
17: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
18: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
19: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
- 25: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 26: $tr$tr$tp$tp_$tr$tp_*($tr)_*($tp)
- 27: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 28: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 29: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 30: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 31: $tr$tp$tp_$tr$tp_*($tr)_*($tp)
- 32: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 33: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 34: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
- 40: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
- 41: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
+ 20: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 21: $tr$tr$tp$tp_$tr$tp_*($tr)_*($tp)
+ 22: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 23: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 24: c/dc/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 25: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 26: $tr$tp$tp_$tr$tp_*($tr)_*($tp)
+ 27: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 28: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 29: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+ 30: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
+ 31: a/ba/b$tp$tp_a/b$tp_*(a/b)_*($tp)
# This is what GNU bash does:
-# 40: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
-# 41: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
+# 30: c/d$tp$tp_a/b$tp_*(a/b)_*($tp)
+# 31: c/d$tp$tp_c/d$tp_*(c/d)_*($tp)
---
name: eglob-utf8-1
description:
@@ -2325,6 +2355,8 @@ stdin:
tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<\$bar
tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<-foo
tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<"$(echo "foo bar")"
+ tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<"A $(echo "foo bar") B"
+ tr abcdefghijklmnopqrstuvwxyz nopqrstuvwxyzabcdefghijklm <<<\$b\$b$bar
expected-stdout:
sbb
sbb
@@ -2334,6 +2366,9 @@ expected-stdout:
$one
-sbb
sbb one
+ A sbb one B
+ $o$oone
+ onm
---
name: heredoc-9b
description:
@@ -2423,7 +2458,7 @@ stdin:
print -r -- "| ${v//$'\n'/^} |"
expected-stdout:
function foo {
- vc=<<-EOF
+ vc=<<-EOF
=c $x \x40=
EOF
@@ -2476,11 +2511,11 @@ stdin:
print -r -- "| ${v//$'\n'/^} |"
expected-stdout:
function foo {
- vc=<<-
+ vc=<<-
=c $x \x40=
<<
- vd=<<-""
+ vd=<<-""
=d $x \x40=
@@ -2538,6 +2573,46 @@ expected-stdout:
3 baz a b baz
3 bla "a b" bla
---
+name: heredoc-14
+description:
+ Check that using multiple here documents works
+stdin:
+ foo() {
+ echo "got $(cat) on stdin"
+ echo "got $(cat <&4) on fd#4"
+ echo "got $(cat <&5) on fd#5"
+ }
+ bar() {
+ foo 4<<-a <<-b 5<<-c
+ four
+ a
+ zero
+ b
+ five
+ c
+ }
+ x=$(typeset -f bar)
+ eval "$x"
+ y=$(typeset -f bar)
+ [[ $x = "$y" ]]; echo $?
+ typeset -f bar
+ bar
+expected-stdout:
+ 0
+ bar() {
+ foo 4<<-a <<-b 5<<-c
+ four
+ a
+ zero
+ b
+ five
+ c
+
+ }
+ got zero on stdin
+ got four on fd#4
+ got five on fd#5
+---
name: heredoc-comsub-1
description:
Tests for here documents in COMSUB, taken from Austin ML
@@ -5019,7 +5094,7 @@ description:
called - I don't know what this will break.
stdin:
: "${PWD:-`pwd 2> /dev/null`}"
- : "${PWD:?"PWD not set - can't do test"}"
+ : "${PWD:?"PWD not set - cannot do test"}"
mkdir Y
cat > Y/xxxscript << EOF
#!/bin/sh
@@ -6335,6 +6410,41 @@ expected-stderr-pattern:
/bad substitution/
expected-exit: 1
---
+name: xxx-variable-syntax-4
+description:
+ Not all kinds of trims are currently impossible, check those who do
+stdin:
+ foo() {
+ echo "<$*> X${*:+ }X"
+ }
+ foo a b
+ foo "" c
+ foo ""
+ foo "" ""
+ IFS=:
+ foo a b
+ foo "" c
+ foo ""
+ foo "" ""
+ IFS=
+ foo a b
+ foo "" c
+ foo ""
+ foo "" ""
+expected-stdout:
+ <a b> X X
+ < c> X X
+ <> XX
+ < > X X
+ <a:b> X X
+ <:c> X X
+ <> XX
+ <:> X X
+ <ab> X X
+ <c> X X
+ <> XX
+ <> XX
+---
name: xxx-substitution-eval-order
description:
Check order of evaluation of expressions
@@ -6460,18 +6570,13 @@ name: xxx-param-subst-qmark-1
description:
Check suppresion of error message with null string. According to
POSIX, it shouldn't print the error as 'word' isn't ommitted.
- ksh88/93, Solaris /bin/sh and /usr/xpg4/bin/sh all print the error,
- that's why the condition is reversed.
+ ksh88/93, Solaris /bin/sh and /usr/xpg4/bin/sh all print the error.
stdin:
unset foo
x=
echo x${foo?$x}
expected-exit: 1
-# POSIX
-#expected-fail: yes
-#expected-stderr-pattern: !/not set/
-# common use
-expected-stderr-pattern: /parameter null or not set/
+expected-stderr-pattern: !/not set/
---
name: xxx-param-_-1
# fails due to weirdness of execv stuff
@@ -6487,12 +6592,24 @@ description:
env-setup: !HOME=/sweet!
stdin:
echo ${A=a=}~ b=~ c=d~ ~
- set +o braceexpand
- unset A
+ export e=~ f=d~
+ command command export g=~ h=d~
+ echo ". $e . $f ."
+ echo ". $g . $h ."
+ set -o posix
+ unset A e f g h
echo ${A=a=}~ b=~ c=d~ ~
+ export e=~ f=d~
+ command command export g=~ h=d~
+ echo ". $e . $f ."
+ echo ". $g . $h ."
expected-stdout:
a=/sweet b=/sweet c=d~ /sweet
+ . /sweet . d~ .
+ . /sweet . d~ .
a=~ b=~ c=d~ /sweet
+ . /sweet . d~ .
+ . /sweet . d~ .
---
name: tilde-expand-2
description:
@@ -6981,6 +7098,131 @@ expected-stdout:
2- 1 1 1 =
3- 0 0 0 =
---
+name: test-stnze-1
+description:
+ Check that the short form [ $x ] works
+stdin:
+ i=0
+ [ -n $x ]
+ rv=$?; echo $((++i)) $rv
+ [ $x ]
+ rv=$?; echo $((++i)) $rv
+ [ -n "$x" ]
+ rv=$?; echo $((++i)) $rv
+ [ "$x" ]
+ rv=$?; echo $((++i)) $rv
+ x=0
+ [ -n $x ]
+ rv=$?; echo $((++i)) $rv
+ [ $x ]
+ rv=$?; echo $((++i)) $rv
+ [ -n "$x" ]
+ rv=$?; echo $((++i)) $rv
+ [ "$x" ]
+ rv=$?; echo $((++i)) $rv
+ x='1 -a 1 = 2'
+ [ -n $x ]
+ rv=$?; echo $((++i)) $rv
+ [ $x ]
+ rv=$?; echo $((++i)) $rv
+ [ -n "$x" ]
+ rv=$?; echo $((++i)) $rv
+ [ "$x" ]
+ rv=$?; echo $((++i)) $rv
+expected-stdout:
+ 1 0
+ 2 1
+ 3 1
+ 4 1
+ 5 0
+ 6 0
+ 7 0
+ 8 0
+ 9 1
+ 10 1
+ 11 0
+ 12 0
+---
+name: test-stnze-2
+description:
+ Check that the short form [[ $x ]] works (ksh93 extension)
+stdin:
+ i=0
+ [[ -n $x ]]
+ rv=$?; echo $((++i)) $rv
+ [[ $x ]]
+ rv=$?; echo $((++i)) $rv
+ [[ -n "$x" ]]
+ rv=$?; echo $((++i)) $rv
+ [[ "$x" ]]
+ rv=$?; echo $((++i)) $rv
+ x=0
+ [[ -n $x ]]
+ rv=$?; echo $((++i)) $rv
+ [[ $x ]]
+ rv=$?; echo $((++i)) $rv
+ [[ -n "$x" ]]
+ rv=$?; echo $((++i)) $rv
+ [[ "$x" ]]
+ rv=$?; echo $((++i)) $rv
+ x='1 -a 1 = 2'
+ [[ -n $x ]]
+ rv=$?; echo $((++i)) $rv
+ [[ $x ]]
+ rv=$?; echo $((++i)) $rv
+ [[ -n "$x" ]]
+ rv=$?; echo $((++i)) $rv
+ [[ "$x" ]]
+ rv=$?; echo $((++i)) $rv
+expected-stdout:
+ 1 1
+ 2 1
+ 3 1
+ 4 1
+ 5 0
+ 6 0
+ 7 0
+ 8 0
+ 9 0
+ 10 0
+ 11 0
+ 12 0
+---
+name: test-numeq
+description:
+ Check numeric -eq works (R40d regression); spotted by Martijn Dekker
+stdin:
+ tst() {
+ eval "$2"
+ case $? in
+ (0) echo yepp 0 \#"$*" ;;
+ (1) echo nope 1 \#"$*" ;;
+ (2) echo terr 2 \#"$*" ;;
+ (*) echo wtf\? $? \#"$*" ;;
+ esac
+ }
+ tst 1 'test 2 -eq 2'
+ tst 2 'test 2 -eq 2a'
+ tst 3 'test 2 -eq 3'
+ tst 4 'test 2 -ne 2'
+ tst 5 'test 2 -ne 2a'
+ tst 6 'test 2 -ne 3'
+ tst 7 'test \! 2 -eq 2'
+ tst 8 'test \! 2 -eq 2a'
+ tst 9 'test \! 2 -eq 3'
+expected-stdout:
+ yepp 0 #1 test 2 -eq 2
+ terr 2 #2 test 2 -eq 2a
+ nope 1 #3 test 2 -eq 3
+ nope 1 #4 test 2 -ne 2
+ terr 2 #5 test 2 -ne 2a
+ yepp 0 #6 test 2 -ne 3
+ nope 1 #7 test \! 2 -eq 2
+ terr 2 #8 test \! 2 -eq 2a
+ yepp 0 #9 test \! 2 -eq 3
+expected-stderr-pattern:
+ /bad number/
+---
name: mkshrc-1
description:
Check that ~/.mkshrc works correctly.
@@ -7451,50 +7693,6 @@ expected-stdout:
name: aliases-1
description:
Check if built-in shell aliases are okay
-category: !android,!arge,!os:os2
-stdin:
- alias
- typeset -f
-expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
- nohup='nohup '
- r='\builtin fc -e -'
- source='PATH=$PATH:. \command .'
- stop='\kill -STOP'
- type='\builtin whence -v'
----
-name: aliases-1-hartz4
-description:
- Check if built-in shell aliases are okay
-category: android,arge
-stdin:
- alias
- typeset -f
-expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
- nohup='nohup '
- r='\builtin fc -e -'
- source='PATH=$PATH:. \command .'
- type='\builtin whence -v'
----
-name: aliases-1-os2
-description:
- Check if built-in shell aliases are okay
-category: os:os2
stdin:
alias
typeset -f
@@ -7509,13 +7707,11 @@ expected-stdout:
nameref='\typeset -n'
nohup='nohup '
r='\builtin fc -e -'
- source='PATH=$PATH;. \command .'
type='\builtin whence -v'
---
name: aliases-2b
description:
Check if “set -o sh” does not influence built-in aliases
-category: !android,!arge,!os:os2
arguments: !-o!sh!
stdin:
alias
@@ -7531,59 +7727,11 @@ expected-stdout:
nameref='\typeset -n'
nohup='nohup '
r='\builtin fc -e -'
- source='PATH=$PATH:. \command .'
- stop='\kill -STOP'
type='\builtin whence -v'
---
name: aliases-3b
description:
Check if running as sh does not influence built-in aliases
-category: !android,!arge,!os:os2
-stdin:
- cp "$__progname" sh
- ./sh -c 'alias; typeset -f'
- rm -f sh
-expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
- nohup='nohup '
- r='\builtin fc -e -'
- source='PATH=$PATH:. \command .'
- stop='\kill -STOP'
- type='\builtin whence -v'
----
-name: aliases-2b-hartz4
-description:
- Check if “set -o sh” does not influence built-in aliases
-category: android,arge
-arguments: !-o!sh!
-stdin:
- alias
- typeset -f
-expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
- nohup='nohup '
- r='\builtin fc -e -'
- source='PATH=$PATH:. \command .'
- type='\builtin whence -v'
----
-name: aliases-3b-hartz4
-description:
- Check if running as sh does not influence built-in aliases
-category: android,arge
stdin:
cp "$__progname" sh
./sh -c 'alias; typeset -f'
@@ -7599,51 +7747,6 @@ expected-stdout:
nameref='\typeset -n'
nohup='nohup '
r='\builtin fc -e -'
- source='PATH=$PATH:. \command .'
- type='\builtin whence -v'
----
-name: aliases-2b-os2
-description:
- Check if “set -o sh” does not influence built-in aliases
-category: os:os2
-arguments: !-o!sh!
-stdin:
- alias
- typeset -f
-expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
- nohup='nohup '
- r='\builtin fc -e -'
- source='PATH=$PATH;. \command .'
- type='\builtin whence -v'
----
-name: aliases-3b-os2
-description:
- Check if running as sh does not influence built-in aliases
-category: os:os2
-stdin:
- cp "$__progname" sh
- ./sh -c 'alias; typeset -f'
- rm -f sh
-expected-stdout:
- autoload='\typeset -fu'
- functions='\typeset -f'
- hash='\builtin alias -t'
- history='\builtin fc -l'
- integer='\typeset -i'
- local='\typeset'
- login='\exec login'
- nameref='\typeset -n'
- nohup='nohup '
- r='\builtin fc -e -'
- source='PATH=$PATH;. \command .'
type='\builtin whence -v'
---
name: aliases-cmdline
@@ -7660,7 +7763,6 @@ expected-stdout:
name: aliases-funcdef-1
description:
Check if POSIX functions take precedences over aliases
-category: shell:legacy-no
stdin:
alias foo='echo makro'
foo() {
@@ -7670,23 +7772,9 @@ stdin:
expected-stdout:
makro
---
-name: aliases-funcdef-1-legacy
-description:
- Check if POSIX functions take precedences over aliases
-category: shell:legacy-yes
-stdin:
- alias foo='echo makro'
- foo() {
- echo funktion
- }
- foo
-expected-stdout:
- funktion
----
name: aliases-funcdef-2
description:
Check if POSIX functions take precedences over aliases
-category: shell:legacy-no
stdin:
alias foo='echo makro'
foo () {
@@ -7696,19 +7784,6 @@ stdin:
expected-stdout:
makro
---
-name: aliases-funcdef-2-legacy
-description:
- Check if POSIX functions take precedences over aliases
-category: shell:legacy-yes
-stdin:
- alias foo='echo makro'
- foo () {
- echo funktion
- }
- foo
-expected-stdout:
- funktion
----
name: aliases-funcdef-3
description:
Check if aliases take precedences over Korn functions
@@ -8452,7 +8527,7 @@ expected-stdout:
name: varexpand-substr-3
description:
Check that some things that work in bash fail.
- This is by design. And that some things fail in both.
+ This is by design. Oh and vice versa, nowadays.
stdin:
export x=abcdefghi n=2
"$__progname" -c 'echo v${x:(n)}x'
@@ -8460,12 +8535,13 @@ stdin:
"$__progname" -c 'echo x${x:n}x'
"$__progname" -c 'echo y${x:}x'
"$__progname" -c 'echo z${x}x'
+ # next fails only in bash
"$__progname" -c 'x=abcdef;y=123;echo ${x:${y:2:1}:2}' >/dev/null 2>&1; echo $?
expected-stdout:
vcdefghix
wcdefghix
zabcdefghix
- 1
+ 0
expected-stderr-pattern:
/x:n.*bad substitution.*\n.*bad substitution/
---
@@ -8633,13 +8709,36 @@ expected-stdout:
0
1
---
+name: varexpand-funny-chars
+description:
+ Check some characters
+ XXX \uEF80 is asymmetric, possibly buggy so we don’t check this
+stdin:
+ x=$'<\x00>'; typeset -p x
+ x=$'<\x01>'; typeset -p x
+ x=$'<\u0000>'; typeset -p x
+ x=$'<\u0001>'; typeset -p x
+expected-stdout:
+ typeset x='<'
+ typeset x=$'<\001>'
+ typeset x='<'
+ typeset x=$'<\001>'
+---
name: print-funny-chars
description:
Check print builtin's capability to output designated characters
stdin:
print '<\0144\0344\xDB\u00DB\u20AC\uDB\x40>'
+ print '<\x00>'
+ print '<\x01>'
+ print '<\u0000>'
+ print '<\u0001>'
expected-stdout:
<dÛ€Û@>
+ <
+ <>
+ <
+ <>
---
name: print-bksl-c
description:
@@ -8915,54 +9014,11 @@ stdin:
"$__progname" -c source
expected-exit: e != 0
expected-stderr-pattern:
- /\.: missing argument.*\n.*\.: missing argument/
----
-name: alias-function-no-conflict-legacy
-description:
- make aliases not conflict with functions, legacy version:
- undefine these aliases upon definition of the function
- note: for ksh functions, the order of preference differs in GNU bash
-category: shell:legacy-yes
-stdin:
- # POSIX function overrides and removes alias
- alias foo='echo bar'
- foo
- foo() {
- echo baz
- }
- foo
- unset -f foo
- foo 2>/dev/null || echo rab
- # alias overrides ksh function
- alias korn='echo bar'
- korn
- function korn {
- echo baz
- }
- korn
- # alias temporarily overrides POSIX function
- bla() {
- echo bfn
- }
- bla
- alias bla='echo bal'
- bla
- unalias bla
- bla
-expected-stdout:
- bar
- baz
- rab
- bar
- bar
- bfn
- bal
- bfn
+ /\.: missing argument.*\n.*source: missing argument/
---
name: alias-function-no-conflict
description:
make aliases not conflict with function definitions
-category: shell:legacy-no
stdin:
# POSIX function can be defined, but alias overrides it
alias foo='echo bar'
@@ -9014,20 +9070,16 @@ stdin:
mk 'function foo' >f-korn
mk 'foo ()' >f-dash
mk 'function foo ()' >f-bash
- # lksh can do without the backslash, too (cf. aliases-funcdef-2-legacy)
- mk 'function stop ()' '\stop' >f-stop
print '#!'"$__progname"'\nprint -r -- "${0%/f-argh}"' >f-argh
chmod +x f-*
u=$(./f-argh)
x="korn: $(./f-korn)"; echo "${x/@("$u")/.}"
x="dash: $(./f-dash)"; echo "${x/@("$u")/.}"
x="bash: $(./f-bash)"; echo "${x/@("$u")/.}"
- x="stop: $(./f-stop)"; echo "${x/@("$u")/.}"
expected-stdout:
korn: bar='foo'
dash: bar='./f-dash'
bash: bar='./f-bash'
- stop: bar='./f-stop'
---
name: integer-base-one-1
description:
@@ -10456,7 +10508,9 @@ expected-stdout:
}
inline_TWHILE() {
i=1
- while \let] " i < 10 "
+ while {
+ \let] " i < 10 "
+ }
do
echo $i
let ++i
@@ -10466,20 +10520,22 @@ expected-stdout:
i=1; while (( i < 10 )); do echo $i; let ++i; done
); }
function comsub_TWHILE {
- x=$(i=1 ; while \let] " i < 10 " ; do echo $i ; let ++i ; done )
+ x=$(i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done )
}
function reread_TWHILE { x=$((
i=1; while (( i < 10 )); do echo $i; let ++i; done
)|tr u x); }
function reread_TWHILE {
- x=$(( i=1 ; while \let] " i < 10 " ; do echo $i ; let ++i ; done ) | tr u x )
+ x=$(( i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done ) | tr u x )
}
inline_TUNTIL() {
i=10; until (( !--i )) ; do echo $i; done
}
inline_TUNTIL() {
i=10
- until \let] " !--i "
+ until {
+ \let] " !--i "
+ }
do
echo $i
done
@@ -10488,13 +10544,13 @@ expected-stdout:
i=10; until (( !--i )) ; do echo $i; done
); }
function comsub_TUNTIL {
- x=$(i=10 ; until \let] " !--i " ; do echo $i ; done )
+ x=$(i=10 ; until { \let] " !--i " ; } ; do echo $i ; done )
}
function reread_TUNTIL { x=$((
i=10; until (( !--i )) ; do echo $i; done
)|tr u x); }
function reread_TUNTIL {
- x=$(( i=10 ; until \let] " !--i " ; do echo $i ; done ) | tr u x )
+ x=$(( i=10 ; until { \let] " !--i " ; } ; do echo $i ; done ) | tr u x )
}
inline_TCOPROC() {
cat * |& ls
@@ -10566,7 +10622,7 @@ expected-stdout:
EOFN
}
inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() {
- cat >|bar <<"EOFN"
+ cat >|bar <<"EOFN"
foo
EOFN
@@ -10577,7 +10633,7 @@ expected-stdout:
EOFN
); }
function comsub_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
- x=$(cat >|bar <<"EOFN"
+ x=$(cat >|bar <<"EOFN"
foo
EOFN
)
@@ -10588,7 +10644,7 @@ expected-stdout:
EOFN
)|tr u x); }
function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
- x=$(( cat >|bar <<"EOFN"
+ x=$(( cat >|bar <<"EOFN"
foo
EOFN
) | tr u x )
@@ -10599,7 +10655,7 @@ expected-stdout:
EOFI
}
inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() {
- cat >bar <<-EOFI
+ cat >bar <<-EOFI
foo
EOFI
@@ -10610,7 +10666,7 @@ expected-stdout:
EOFI
); }
function comsub_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
- x=$(cat >bar <<-EOFI
+ x=$(cat >bar <<-EOFI
foo
EOFI
)
@@ -10621,7 +10677,7 @@ expected-stdout:
EOFI
)|tr u x); }
function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
- x=$(( cat >bar <<-EOFI
+ x=$(( cat >bar <<-EOFI
foo
EOFI
) | tr u x )
@@ -10712,7 +10768,7 @@ expected-stdout:
EOFN); echo $x
}
inline_heredoc_closed() {
- x=$(cat <<EOFN
+ x=$(cat <<EOFN
note there must be no space between EOFN and )
EOFN
)
@@ -10724,7 +10780,7 @@ expected-stdout:
EOFN); echo $x
); }
function comsub_heredoc_closed {
- x=$(x=$(cat <<EOFN
+ x=$(x=$(cat <<EOFN
note there must be no space between EOFN and )
EOFN
) ; echo $x )
@@ -10735,7 +10791,7 @@ expected-stdout:
EOFN); echo $x
)|tr u x); }
function reread_heredoc_closed {
- x=$(( x=$(cat <<EOFN
+ x=$(( x=$(cat <<EOFN
note there must be no space between EOFN and )
EOFN
) ; echo $x ) | tr u x )
@@ -10746,7 +10802,7 @@ expected-stdout:
EOFN ); echo $x
}
inline_heredoc_space() {
- x=$(cat <<EOFN\
+ x=$(cat <<EOFN\
note the space between EOFN and ) is actually part of the here document marker
EOFN
)
@@ -10758,7 +10814,7 @@ expected-stdout:
EOFN ); echo $x
); }
function comsub_heredoc_space {
- x=$(x=$(cat <<EOFN\
+ x=$(x=$(cat <<EOFN\
note the space between EOFN and ) is actually part of the here document marker
EOFN
) ; echo $x )
@@ -10769,7 +10825,7 @@ expected-stdout:
EOFN ); echo $x
)|tr u x); }
function reread_heredoc_space {
- x=$(( x=$(cat <<EOFN\
+ x=$(( x=$(cat <<EOFN\
note the space between EOFN and ) is actually part of the here document marker
EOFN
) ; echo $x ) | tr u x )
@@ -10792,7 +10848,7 @@ expected-stdout:
}
inline_patch_motd() {
x=$(sysctl -n kern.version | sed 1q )
- [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
+ [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
1,/^\$/d
0a
$x
@@ -10824,7 +10880,7 @@ expected-stdout:
fi
); }
function comsub_patch_motd {
- x=$(x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
+ x=$(x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
1,/^\$/d
0a
$x
@@ -10851,7 +10907,7 @@ expected-stdout:
fi
)|tr u x); }
function reread_patch_motd {
- x=$(( x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
+ x=$(( x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
1,/^\$/d
0a
$x
@@ -11108,7 +11164,9 @@ expected-stdout:
}
inline_TWHILE() {
i=1
- while \let] " i < 10 " >&3
+ while {
+ \let] " i < 10 "
+ } >&3
do
echo $i
let ++i
@@ -11118,20 +11176,22 @@ expected-stdout:
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
); }
function comsub_TWHILE {
- x=$(i=1 ; while \let] " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 )
+ x=$(i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 )
}
function reread_TWHILE { x=$((
i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
)|tr u x); }
function reread_TWHILE {
- x=$(( i=1 ; while \let] " i < 10 " >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
+ x=$(( i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
}
inline_TUNTIL() {
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
}
inline_TUNTIL() {
i=10
- until \let] " !--i " >&3
+ until {
+ \let] " !--i "
+ } >&3
do
echo $i
done >&3
@@ -11140,13 +11200,13 @@ expected-stdout:
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
); }
function comsub_TUNTIL {
- x=$(i=10 ; until \let] " !--i " >&3 ; do echo $i ; done >&3 )
+ x=$(i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 )
}
function reread_TUNTIL { x=$((
i=10; until (( !--i )) >&3 ; do echo $i; done >&3
)|tr u x); }
function reread_TUNTIL {
- x=$(( i=10 ; until \let] " !--i " >&3 ; do echo $i ; done >&3 ) | tr u x )
+ x=$(( i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 ) | tr u x )
}
inline_TCOPROC() {
cat * >&3 |& >&3 ls
@@ -11278,96 +11338,6 @@ expected-stdout:
typeset t=$'foo\n\n'
this used to segfault.
---
-name: test-stnze-1
-description:
- Check that the short form [ $x ] works
-stdin:
- i=0
- [ -n $x ]
- rv=$?; echo $((++i)) $rv
- [ $x ]
- rv=$?; echo $((++i)) $rv
- [ -n "$x" ]
- rv=$?; echo $((++i)) $rv
- [ "$x" ]
- rv=$?; echo $((++i)) $rv
- x=0
- [ -n $x ]
- rv=$?; echo $((++i)) $rv
- [ $x ]
- rv=$?; echo $((++i)) $rv
- [ -n "$x" ]
- rv=$?; echo $((++i)) $rv
- [ "$x" ]
- rv=$?; echo $((++i)) $rv
- x='1 -a 1 = 2'
- [ -n $x ]
- rv=$?; echo $((++i)) $rv
- [ $x ]
- rv=$?; echo $((++i)) $rv
- [ -n "$x" ]
- rv=$?; echo $((++i)) $rv
- [ "$x" ]
- rv=$?; echo $((++i)) $rv
-expected-stdout:
- 1 0
- 2 1
- 3 1
- 4 1
- 5 0
- 6 0
- 7 0
- 8 0
- 9 1
- 10 1
- 11 0
- 12 0
----
-name: test-stnze-2
-description:
- Check that the short form [[ $x ]] works (ksh93 extension)
-stdin:
- i=0
- [[ -n $x ]]
- rv=$?; echo $((++i)) $rv
- [[ $x ]]
- rv=$?; echo $((++i)) $rv
- [[ -n "$x" ]]
- rv=$?; echo $((++i)) $rv
- [[ "$x" ]]
- rv=$?; echo $((++i)) $rv
- x=0
- [[ -n $x ]]
- rv=$?; echo $((++i)) $rv
- [[ $x ]]
- rv=$?; echo $((++i)) $rv
- [[ -n "$x" ]]
- rv=$?; echo $((++i)) $rv
- [[ "$x" ]]
- rv=$?; echo $((++i)) $rv
- x='1 -a 1 = 2'
- [[ -n $x ]]
- rv=$?; echo $((++i)) $rv
- [[ $x ]]
- rv=$?; echo $((++i)) $rv
- [[ -n "$x" ]]
- rv=$?; echo $((++i)) $rv
- [[ "$x" ]]
- rv=$?; echo $((++i)) $rv
-expected-stdout:
- 1 1
- 2 1
- 3 1
- 4 1
- 5 0
- 6 0
- 7 0
- 8 0
- 9 0
- 10 0
- 11 0
- 12 0
----
name: event-subst-3
description:
Check that '!' substitution in noninteractive mode is ignored
@@ -11733,6 +11703,16 @@ stdin:
expected-stdout:
fxbar 0
---
+name: better-parens-5
+description:
+ Another corner case
+stdin:
+ ( (echo 'fo o$bar' "baz\$bla\"" m\$eh) | tr a A)
+ ((echo 'fo o$bar' "baz\$bla\"" m\$eh) | tr a A)
+expected-stdout:
+ fo o$bAr bAz$blA" m$eh
+ fo o$bAr bAz$blA" m$eh
+---
name: echo-test-1
description:
Test what the echo builtin does (mksh)
diff --git a/src/dot.mkshrc b/src/dot.mkshrc
index 4c64395..ab13f9d 100644
--- a/src/dot.mkshrc
+++ b/src/dot.mkshrc
@@ -1,9 +1,9 @@
# $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.100 2015/07/10 19:36:33 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.104 2015/12/31 21:00:12 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015
-# Thorsten Glaser <tg@mirbsd.org>
+# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
@@ -40,7 +40,7 @@ PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
(( e )) && REPLY+="$e|"
REPLY+=${USER}@${HOSTNAME%%.*}:
- \typeset d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
+ \typeset d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/\~}
\typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
(( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
REPLY+=$p$d
@@ -109,7 +109,7 @@ function chpwd {
DIRSTACK[0]=$(\builtin realpath . 2>/dev/null || \
\builtin print -r -- "$PWD")
[[ $DIRSTACKBASE = ?(*/) ]] || \
- DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/~}
+ DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/\~}
\:
}
\chpwd .
@@ -118,7 +118,7 @@ cd() {
\chpwd "$@"
}
function cd_csh {
- \typeset d t=${1/#~/$DIRSTACKBASE}
+ \typeset d t=${1/#\~/$DIRSTACKBASE}
if ! d=$(\builtin cd "$t" 2>&1); then
\builtin print -u2 "${1}: ${d##*cd: $t: }."
@@ -148,7 +148,7 @@ function dirs {
fv=0
while (( fv < ${#DIRSTACK[*]} )); do
d=${DIRSTACK[fv]}
- (( fl )) && d=${d/#~/$DIRSTACKBASE}
+ (( fl )) && d=${d/#\~/$DIRSTACKBASE}
\builtin print -r -- "$fv $d"
\builtin let fv++
done
@@ -156,7 +156,7 @@ function dirs {
fv=0
while (( fv < ${#DIRSTACK[*]} )); do
d=${DIRSTACK[fv]}
- (( fl )) && d=${d/#~/$DIRSTACKBASE}
+ (( fl )) && d=${d/#\~/$DIRSTACKBASE}
(( dwidth = (${%d} > 0 ? ${%d} : ${#d}) ))
if (( fn && (cpos += dwidth + 1) >= 79 && \
dwidth < 80 )); then
@@ -384,7 +384,11 @@ function Lstripcom {
# give MidnightBSD's laffer1 a bit of csh feeling
function setenv {
- \eval "'export' \"$1\""'="$2"'
+ if (( $# )); then
+ \eval '\export "$1"="${2:-}"'
+ else
+ \typeset -x
+ fi
}
# toggle built-in aliases and utilities, and aliases and functions from mkshrc
@@ -406,9 +410,6 @@ function enable {
i_alias[nalias]=nameref; b_alias[nalias++]='\typeset -n'
i_alias[nalias]=nohup; b_alias[nalias++]='nohup '
i_alias[nalias]=r; b_alias[nalias++]='\builtin fc -e -'
- #XXX OS/2
- i_alias[nalias]=source; b_alias[nalias++]='PATH=$PATH:. \command .'
- i_alias[nalias]=stop; b_alias[nalias++]='\kill -STOP'
i_alias[nalias]=type; b_alias[nalias++]='\builtin whence -v'
# accumulate mksh built-in utilities, in definition order, even ifndef
@@ -445,6 +446,7 @@ function enable {
i_func[nfunc++]=return
i_func[nfunc++]=set
i_func[nfunc++]=shift
+ i_func[nfunc++]=source
i_func[nfunc++]=suspend
i_func[nfunc++]=test
i_func[nfunc++]=times
@@ -464,6 +466,7 @@ function enable {
i_func[nfunc++]=printf
i_func[nfunc++]=sleep
i_func[nfunc++]=domainname
+ i_func[nfunc++]=extproc
# accumulate aliases from dot.mkshrc, in definition order
i_alias[nalias]=l; b_alias[nalias++]='ls -F'
@@ -593,8 +596,8 @@ done
#\unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
# LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME
#p=en_GB.UTF-8
-#\set -U
#\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
+#\set -U
\unset p
diff --git a/src/edit.c b/src/edit.c
index 4578647..5433e6a 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -1,12 +1,12 @@
-/* $OpenBSD: edit.c,v 1.40 2015/03/12 10:20:30 sthen Exp $ */
+/* $OpenBSD: edit.c,v 1.41 2015/09/01 13:12:31 tedu Exp $ */
/* $OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $ */
-/* $OpenBSD: emacs.c,v 1.50 2015/03/25 12:10:52 jca Exp $ */
-/* $OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $ */
+/* $OpenBSD: emacs.c,v 1.52 2015/09/10 22:48:58 nicm Exp $ */
+/* $OpenBSD: vi.c,v 1.30 2015/09/10 22:48:58 nicm Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2014, 2015
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -28,7 +28,7 @@
#ifndef MKSH_NO_CMDLINE_EDITING
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.290 2015/07/10 19:36:34 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.292 2015/10/09 16:11:13 tg Exp $");
/*
* in later versions we might use libtermcap for this, but since external
@@ -2262,12 +2262,8 @@ x_kill(int c MKSH_A_UNUSED)
static void
x_push(int nchars)
{
- char *cp;
-
- strndupx(cp, xcp, nchars, AEDIT);
- if (killstack[killsp])
- afree(killstack[killsp], AEDIT);
- killstack[killsp] = cp;
+ afree(killstack[killsp], AEDIT);
+ strndupx(killstack[killsp], xcp, nchars, AEDIT);
killsp = (killsp + 1) % KILLSIZE;
}
diff --git a/src/emacsfn.h b/src/emacsfn.h
index 6e64cfb..ba14d09 100644
--- a/src/emacsfn.h
+++ b/src/emacsfn.h
@@ -1,5 +1,25 @@
+/*-
+ * Copyright (c) 2009, 2010, 2015
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
#if defined(EMACSFN_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.6 2015/07/10 18:41:07 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/emacsfn.h,v 1.7 2015/12/12 21:08:44 tg Exp $");
#define FN(cname,sname,flags) static int x_##cname(int);
#elif defined(EMACSFN_ENUMS)
#define FN(cname,sname,flags) XFUNC_##cname,
diff --git a/src/eval.c b/src/eval.c
index 0b585bc..3e670da 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2,8 +2,8 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.170 2015/07/06 17:45:33 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.180 2016/01/19 23:12:12 tg Exp $");
/*
* string expansion
@@ -437,8 +437,6 @@ expand(
beg = wdcopy(sp, ATEMP);
mid = beg + (wdscan(sp, ADELIM) - sp);
stg = beg + (wdscan(sp, CSUBST) - sp);
- if (mid >= stg)
- goto unwind_substsyn;
mid[-2] = EOS;
if (mid[-1] == /*{*/'}') {
sp += mid - beg - 1;
@@ -446,9 +444,8 @@ expand(
} else {
end = mid +
(wdscan(mid, ADELIM) - mid);
- if (end >= stg ||
- /* more than max delimiters */
- end[-1] != /*{*/ '}')
+ if (end[-1] != /*{*/ '}')
+ /* more than max delimiters */
goto unwind_substsyn;
end[-2] = EOS;
sp += end - beg - 1;
@@ -483,56 +480,37 @@ expand(
case '/': {
char *s, *p, *d, *sbeg, *end;
char *pat, *rrep;
- char *tpat0, *tpat1, *tpat2;
+ char fpat = 0, *tpat1, *tpat2;
s = wdcopy(sp, ATEMP);
p = s + (wdscan(sp, ADELIM) - sp);
d = s + (wdscan(sp, CSUBST) - sp);
- if (p >= d)
- goto unwind_substsyn;
p[-2] = EOS;
if (p[-1] == /*{*/'}')
d = NULL;
else
d[-2] = EOS;
sp += (d ? d : p) - s - 1;
- tpat0 = wdstrip(s,
- WDS_KEEPQ | WDS_MAGIC);
- pat = substitute(tpat0, 0);
- if (d) {
- d = wdstrip(p, WDS_KEEPQ);
- rrep = substitute(d, 0);
- afree(d, ATEMP);
- } else
- rrep = null;
+ if (!(stype & 0x80) &&
+ s[0] == CHAR &&
+ (s[1] == '#' || s[1] == '%'))
+ fpat = s[1];
+ pat = evalstr(s + (fpat ? 2 : 0),
+ DOTILDE | DOSCALAR | DOPAT);
+ rrep = d ? evalstr(p,
+ DOTILDE | DOSCALAR) : null;
afree(s, ATEMP);
- s = d = pat;
- while (*s)
- if (*s != '\\' ||
- s[1] == '%' ||
- s[1] == '#' ||
- s[1] == '\0' ||
- /* XXX really? */ s[1] == '\\' ||
- s[1] == '/')
- *d++ = *s++;
- else
- s++;
- *d = '\0';
- afree(tpat0, ATEMP);
/* check for special cases */
- switch (*pat) {
- case '#':
- case '%':
- tpat0 = pat + 1;
- break;
- case '\0':
- /* empty pattern, reject */
+ if (!*pat && !fpat) {
+ /*
+ * empty unanchored
+ * pattern => reject
+ */
goto no_repl;
- default:
- tpat0 = pat;
}
- if (gmatchx(null, tpat0, false)) {
+ if ((stype & 0x80) &&
+ gmatchx(null, pat, false)) {
/*
* pattern matches empty
* string => don't loop
@@ -545,15 +523,14 @@ expand(
sbeg = s;
/* first see if we have any match at all */
- tpat0 = pat;
- if (*pat == '#') {
+ if (fpat == '#') {
/* anchor at the beginning */
- tpat1 = shf_smprintf("%s%c*", ++tpat0, MAGIC);
+ tpat1 = shf_smprintf("%s%c*", pat, MAGIC);
tpat2 = tpat1;
- } else if (*pat == '%') {
+ } else if (fpat == '%') {
/* anchor at the end */
- tpat1 = shf_smprintf("%c*%s", MAGIC, ++tpat0);
- tpat2 = tpat0;
+ tpat1 = shf_smprintf("%c*%s", MAGIC, pat);
+ tpat2 = pat;
} else {
/* float */
tpat1 = shf_smprintf("%c*%s%c*", MAGIC, pat, MAGIC);
@@ -568,7 +545,7 @@ expand(
goto end_repl;
end = strnul(s);
/* now anchor the beginning of the match */
- if (*pat != '#')
+ if (fpat != '#')
while (sbeg <= end) {
if (gmatchx(sbeg, tpat2, false))
break;
@@ -577,13 +554,13 @@ expand(
}
/* now anchor the end of the match */
p = end;
- if (*pat != '%')
+ if (fpat != '%')
while (p >= sbeg) {
bool gotmatch;
c = *p;
*p = '\0';
- gotmatch = tobool(gmatchx(sbeg, tpat0, false));
+ gotmatch = tobool(gmatchx(sbeg, pat, false));
*p = c;
if (gotmatch)
break;
@@ -608,9 +585,11 @@ expand(
}
case '#':
case '%':
- /* ! DOBLANK,DOBRACE,DOTILDE */
+ /* ! DOBLANK,DOBRACE */
f = (f & DONTRUNCOMMAND) |
- DOPAT | DOTEMP | DOSCALAR;
+ DOPAT | DOTILDE |
+ DOTEMP | DOSCALAR;
+ tilde_ok = 1;
st->quotew = quote = 0;
/*
* Prepend open pattern (so |
@@ -648,6 +627,9 @@ expand(
tilde_ok = 1;
break;
case '?':
+ if (*sp == CSUBST)
+ errorf("%s: parameter null or not set",
+ st->var->name);
f &= ~DOBLANK;
f |= DOTEMP;
/* FALLTHROUGH */
@@ -743,14 +725,12 @@ expand(
st = st->prev;
word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
continue;
- case '?': {
- char *s = Xrestpos(ds, dp, st->base);
+ case '?':
+ dp = Xrestpos(ds, dp, st->base);
errorf("%s: %s", st->var->name,
- dp == s ?
- "parameter null or not set" :
- (debunk(s, s, strlen(s) + 1), s));
- }
+ debunk(dp, dp, strlen(dp) + 1));
+ break;
case '0':
case '/':
case 0x100 | '#':
@@ -919,6 +899,8 @@ expand(
(word == IFS_IWS || word == IFS_NWS) &&
!ctype(c, C_IFSWS))) {
emit_word:
+ if (f & DOHERESTR)
+ *dp++ = '\n';
*dp++ = '\0';
cp = Xclose(ds, dp);
if (fdo & DOBRACE)
@@ -999,9 +981,8 @@ expand(
break;
case '=':
/* Note first unquoted = for ~ */
- if (!(f & DOTEMP) && !saw_eq &&
- (Flag(FBRACEEXPAND) ||
- (f & DOASNTILDE))) {
+ if (!(f & DOTEMP) && (!Flag(FPOSIX) ||
+ (f & DOASNTILDE)) && !saw_eq) {
saw_eq = true;
tilde_ok = 1;
}
@@ -1057,6 +1038,17 @@ expand(
}
}
+static bool
+hasnonempty(const char **strv)
+{
+ size_t i = 0;
+
+ while (strv[i])
+ if (*strv[i++])
+ return (true);
+ return (false);
+}
+
/*
* Prepare to generate the string returned by ${} substitution.
*/
@@ -1285,7 +1277,9 @@ varsub(Expand *xp, const char *sp, const char *word,
c = stype & 0x7F;
/* test the compiler's code generator */
if (((stype < 0x100) && (ctype(c, C_SUBOP2) || c == '/' ||
- (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
+ (((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
+ (state != XARG || (ifs0 || xp->split ?
+ (xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
c == '=' || c == '-' || c == '?' : c == '+'))) ||
stype == (0x80 | '0') || stype == (0x100 | '#') ||
stype == (0x100 | 'Q'))
@@ -1330,10 +1324,10 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
char *name;
if ((io->ioflag & IOTYPE) != IOREAD)
- errorf("%s: %s", "funny $() command",
+ errorf("%s: %s", T_funny_command,
snptreef(NULL, 32, "%R", io));
- shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
- SHF_MAPHI|SHF_CLEXEC);
+ shf = shf_open(name = evalstr(io->ioname, DOTILDE), O_RDONLY,
+ 0, SHF_MAPHI | SHF_CLEXEC);
if (shf == NULL)
warningf(!Flag(FTALKING), "%s: %s %s: %s", name,
"can't open", "$(<...) input", cstrerror(errno));
diff --git a/src/exec.c b/src/exec.c
index 6a743a2..9361c19 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1,9 +1,9 @@
-/* $OpenBSD: exec.c,v 1.51 2015/04/18 18:28:36 deraadt Exp $ */
+/* $OpenBSD: exec.c,v 1.52 2015/09/10 22:48:58 nicm Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.160 2015/07/10 19:36:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.170 2015/12/31 21:03:47 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
@@ -39,7 +39,6 @@ static const char *do_selectargs(const char **, bool);
static Test_op dbteste_isa(Test_env *, Test_meta);
static const char *dbteste_getopnd(Test_env *, Test_op, bool);
static void dbteste_error(Test_env *, int, const char *);
-static int search_access(const char *, int);
/* XXX: horrible kludge to fit within the framework */
static void plain_fmt_entry(char *, size_t, unsigned int, const void *);
static void select_fmt_entry(char *, size_t, unsigned int, const void *);
@@ -1000,6 +999,7 @@ scriptexec(struct op *tp, const char **ap)
(m == /* ECOFF_SH */ 0x0500 || m == 0x0005) ||
(m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) ||
(m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) ||
+ (m == /* ksh93 */ 0x0B13) || (m == /* LZIP */ 0x4C5A) ||
(m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' &&
buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
(m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
@@ -1065,14 +1065,6 @@ define(const char *name, struct op *t)
nhash = hash(name);
-#ifdef MKSH_LEGACY_MODE
- if (t != NULL && !tobool(t->u.ksh_func)) {
- /* drop same-name aliases for POSIX functions */
- if ((tp = ktsearch(&aliases, name, nhash)))
- ktdelete(tp);
- }
-#endif
-
while (/* CONSTCOND */ 1) {
tp = findfunc(name, nhash, true);
@@ -1257,7 +1249,7 @@ flushcom(bool all)
}
/* check if path is something we want to find */
-static int
+int
search_access(const char *fn, int mode)
{
struct stat sb;
@@ -1266,9 +1258,13 @@ search_access(const char *fn, int mode)
/* file does not exist */
return (ENOENT);
/* LINTED use of access */
- if (access(fn, mode) < 0)
+ if (access(fn, mode) < 0) {
/* file exists, but we can't access it */
- return (errno);
+ int eno;
+
+ eno = errno;
+ return (eno ? eno : EACCES);
+ }
if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
!(sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
/* access(2) may say root can execute everything */
@@ -1344,7 +1340,9 @@ call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec)
if (!tp)
internal_errorf("%s: %s", where, wp[0]);
builtin_argv0 = wp[0];
- builtin_spec = tobool(!resetspec && (tp->flag & SPEC_BI));
+ builtin_spec = tobool(!resetspec &&
+ /*XXX odd use of KEEPASN */
+ ((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN))));
shf_reopen(1, SHF_WR, shl_stdout);
shl_stdout_ok = true;
ksh_getopt_reset(&builtin_opt, GF_ERROR);
@@ -1363,9 +1361,9 @@ static int
iosetup(struct ioword *iop, struct tbl *tp)
{
int u = -1;
- char *cp = iop->name;
+ char *cp = iop->ioname;
int iotype = iop->ioflag & IOTYPE;
- bool do_open = true, do_close = false;
+ bool do_open = true, do_close = false, do_fstat = false;
int flags = 0;
struct ioword iotmp;
struct stat statb;
@@ -1375,7 +1373,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
/* Used for tracing and error messages to print expanded cp */
iotmp = *iop;
- iotmp.name = (iotype == IOHERE) ? NULL : cp;
+ iotmp.ioname = (iotype == IOHERE) ? NULL : cp;
iotmp.ioflag |= IONAMEXP;
if (Flag(FXTRACE)) {
@@ -1394,14 +1392,27 @@ iosetup(struct ioword *iop, struct tbl *tp)
break;
case IOWRITE:
- flags = O_WRONLY | O_CREAT | O_TRUNC;
- /*
- * The stat() is here to allow redirections to
- * things like /dev/null without error.
- */
- if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) &&
- (stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
- flags |= O_EXCL;
+ if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB)) {
+ /* >file under set -C */
+ if (stat(cp, &statb)) {
+ /* nonexistent file */
+ flags = O_WRONLY | O_CREAT | O_EXCL;
+ } else if (S_ISREG(statb.st_mode)) {
+ /* regular file, refuse clobbering */
+ goto clobber_refused;
+ } else {
+ /*
+ * allow redirections to things
+ * like /dev/null without error
+ */
+ flags = O_WRONLY;
+ /* but check again after opening */
+ do_fstat = true;
+ }
+ } else {
+ /* >|file or set +C */
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ }
break;
case IORDWR:
@@ -1446,6 +1457,15 @@ iosetup(struct ioword *iop, struct tbl *tp)
return (-1);
}
u = binopen3(cp, flags, 0666);
+ if (do_fstat && u >= 0) {
+ /* prevent race conditions */
+ if (fstat(u, &statb) || S_ISREG(statb.st_mode)) {
+ close(u);
+ clobber_refused:
+ u = -1;
+ errno = EEXIST;
+ }
+ }
}
if (u < 0) {
/* herein() may already have printed message */
@@ -1482,7 +1502,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
char *sp;
eno = errno;
- warningf(true, "%s %s %s",
+ warningf(true, "%s %s: %s",
"can't finish (dup) redirection",
(sp = snptreef(NULL, 32, "%R", &iotmp)),
cstrerror(eno));
@@ -1518,9 +1538,9 @@ iosetup(struct ioword *iop, struct tbl *tp)
* unquoted, the string is expanded first.
*/
static int
-hereinval(const char *content, int sub, char **resbuf, struct shf *shf)
+hereinval(struct ioword *iop, int sub, char **resbuf, struct shf *shf)
{
- const char * volatile ccp = content;
+ const char * volatile ccp = iop->heredoc;
struct source *s, *osource;
osource = source;
@@ -1531,7 +1551,9 @@ hereinval(const char *content, int sub, char **resbuf, struct shf *shf)
/* special to iosetup(): don't print error */
return (-2);
}
- if (sub) {
+ if (iop->ioflag & IOHERESTR) {
+ ccp = evalstr(iop->delim, DOHERESTR | DOSCALAR | DOHEREDOC);
+ } else if (sub) {
/* do substitutions on the content of heredoc */
s = pushs(SSTRING, ATEMP);
s->start = s->str = ccp;
@@ -1560,7 +1582,7 @@ herein(struct ioword *iop, char **resbuf)
int i;
/* ksh -c 'cat <<EOF' can cause this... */
- if (iop->heredoc == NULL) {
+ if (iop->heredoc == NULL && !(iop->ioflag & IOHERESTR)) {
warningf(true, "%s missing", "here document");
/* special to iosetup(): don't print error */
return (-2);
@@ -1571,7 +1593,7 @@ herein(struct ioword *iop, char **resbuf)
/* skip all the fd setup if we just want the value */
if (resbuf != NULL)
- return (hereinval(iop->heredoc, i, resbuf, NULL));
+ return (hereinval(iop, i, resbuf, NULL));
/*
* Create temp file to hold content (done before newenv
@@ -1588,7 +1610,7 @@ herein(struct ioword *iop, char **resbuf)
return (-2);
}
- if (hereinval(iop->heredoc, i, NULL, shf) == -2) {
+ if (hereinval(iop, i, NULL, shf) == -2) {
close(fd);
/* special to iosetup(): don't print error */
return (-2);
diff --git a/src/expr.c b/src/expr.c
index ef544df..64b9481 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -2,8 +2,8 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2014, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.77 2014/12/15 23:26:36 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.81 2016/01/14 21:17:50 tg Exp $");
/* the order of these enums is constrained by the order of opinfo[] */
enum token {
@@ -659,7 +659,8 @@ exprtoken(Expr_state *es)
es->tok = VAR;
} else if (c == '1' && cp[1] == '#') {
cp += 2;
- cp += utf_ptradj(cp);
+ if (*cp)
+ cp += utf_ptradj(cp);
strndupx(tvar, es->tokp, cp - es->tokp, ATEMP);
goto process_tvar;
#ifndef MKSH_SMALL
@@ -916,6 +917,7 @@ ksh_access(const char *fn, int mode)
return (rv);
}
+#ifndef MIRBSD_BOOTFLOPPY
/* From: X11/xc/programs/xterm/wcwidth.c,v 1.8 2014/06/24 19:53:53 tg Exp $ */
struct mb_ucsrange {
@@ -1195,3 +1197,4 @@ utf_wcwidth(unsigned int wc)
return (2);
return (1);
}
+#endif
diff --git a/src/funcs.c b/src/funcs.c
index 0d2aec3..ab6e3b7 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -1,12 +1,12 @@
-/* $OpenBSD: c_ksh.c,v 1.34 2013/12/17 16:37:05 deraadt Exp $ */
-/* $OpenBSD: c_sh.c,v 1.45 2014/08/27 08:26:04 jmc Exp $ */
+/* $OpenBSD: c_ksh.c,v 1.37 2015/09/10 22:48:58 nicm Exp $ */
+/* $OpenBSD: c_sh.c,v 1.46 2015/07/20 20:46:24 guenther Exp $ */
/* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */
/* $OpenBSD: c_ulimit.c,v 1.19 2013/11/28 10:33:37 sobrado Exp $ */
/*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- * 2010, 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2010, 2011, 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -38,7 +38,7 @@
#endif
#endif
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.280 2015/07/09 20:52:39 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.293 2016/01/20 21:34:11 tg Exp $");
#if HAVE_KILLPG
/*
@@ -103,7 +103,7 @@ const struct builtin mkshbuiltins[] = {
{"cd", c_cd},
/* dash compatibility hack */
{"chdir", c_cd},
- {"command", c_command},
+ {Tcommand, c_command},
{"*=continue", c_brkcont},
{"echo", c_print},
{"*=eval", c_eval},
@@ -127,6 +127,7 @@ const struct builtin mkshbuiltins[] = {
{"*=return", c_exitreturn},
{Tsgset, c_set},
{"*=shift", c_shift},
+ {"=source", c_dot},
#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
{"suspend", c_suspend},
#endif
@@ -277,20 +278,18 @@ static void s_put(int);
int
c_print(const char **wp)
{
-#define PO_NL BIT(0) /* print newline */
-#define PO_EXPAND BIT(1) /* expand backslash sequences */
-#define PO_PMINUSMINUS BIT(2) /* print a -- argument */
-#define PO_HIST BIT(3) /* print to history instead of stdout */
-#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
int fd = 1, c;
- int flags = PO_EXPAND | PO_NL;
- const char *s, *emsg;
+ const char *s;
XString xs;
char *xp;
+ /* print newline; expand backslash sequences */
+ bool po_nl = true, po_exp = true;
+ /* print to history instead of file descriptor / stdout */
+ bool po_hist = false;
if (wp[0][0] == 'e') {
- /* echo builtin */
- wp++;
+ /* "echo" builtin */
+ ++wp;
#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
if (Flag(FSH)) {
/*
@@ -298,7 +297,7 @@ c_print(const char **wp)
* one that supports -e but does not enable it by
* default
*/
- flags = PO_NL;
+ po_exp = false;
}
#endif
if (Flag(FPOSIX) ||
@@ -308,14 +307,14 @@ c_print(const char **wp)
Flag(FAS_BUILTIN)) {
/* Debian Policy 10.4 compliant "echo" builtin */
if (*wp && !strcmp(*wp, "-n")) {
- /* we recognise "-n" only as the first arg */
- flags = 0;
- wp++;
- } else
- /* otherwise, we print everything as-is */
- flags = PO_NL;
+ /* recognise "-n" only as the first arg */
+ po_nl = false;
+ ++wp;
+ }
+ /* print everything as-is */
+ po_exp = false;
} else {
- int nflags = flags;
+ bool new_exp = po_exp, new_nl = po_nl;
/**
* a compromise between sysV and BSD echo commands:
@@ -328,62 +327,65 @@ c_print(const char **wp)
* quences are enabled by default.
*/
- while ((s = *wp) && *s == '-' && s[1]) {
- while (*++s)
- if (*s == 'n')
- nflags &= ~PO_NL;
- else if (*s == 'e')
- nflags |= PO_EXPAND;
- else if (*s == 'E')
- nflags &= ~PO_EXPAND;
- else
- /*
- * bad option: don't use
- * nflags, print argument
- */
- break;
-
- if (*s)
- break;
- wp++;
- flags = nflags;
+ print_tradparse_arg:
+ if ((s = *wp) && *s++ == '-' && *s) {
+ print_tradparse_ch:
+ switch ((c = *s++)) {
+ case 'E':
+ new_exp = false;
+ goto print_tradparse_ch;
+ case 'e':
+ new_exp = true;
+ goto print_tradparse_ch;
+ case 'n':
+ new_nl = false;
+ goto print_tradparse_ch;
+ case '\0':
+ po_exp = new_exp;
+ po_nl = new_nl;
+ ++wp;
+ goto print_tradparse_arg;
+ }
}
}
} else {
- int optc;
- const char *opts = "Rnprsu,";
-
- while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
- switch (optc) {
- case 'R':
- /* fake BSD echo command */
- flags |= PO_PMINUSMINUS;
- flags &= ~PO_EXPAND;
- opts = "ne";
- break;
+ /* "print" builtin */
+ const char *opts = "npRrsu,";
+ const char *emsg;
+ /* print a "--" argument */
+ bool po_pminusminus = false;
+
+ while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
+ switch (c) {
case 'e':
- flags |= PO_EXPAND;
+ po_exp = true;
break;
case 'n':
- flags &= ~PO_NL;
+ po_nl = false;
break;
case 'p':
if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
- bi_errorf("%s: %s", "-p", emsg);
+ bi_errorf("-p: %s", emsg);
return (1);
}
break;
+ case 'R':
+ /* fake BSD echo command */
+ po_pminusminus = true;
+ po_exp = false;
+ opts = "en";
+ break;
case 'r':
- flags &= ~PO_EXPAND;
+ po_exp = false;
break;
case 's':
- flags |= PO_HIST;
+ po_hist = true;
break;
case 'u':
if (!*(s = builtin_opt.optarg))
fd = 0;
else if ((fd = check_fd(s, W_OK, &emsg)) < 0) {
- bi_errorf("%s: %s: %s", "-u", s, emsg);
+ bi_errorf("-u%s: %s", s, emsg);
return (1);
}
break;
@@ -392,22 +394,23 @@ c_print(const char **wp)
}
if (!(builtin_opt.info & GI_MINUSMINUS)) {
- /* treat a lone - like -- */
+ /* treat a lone "-" like "--" */
if (wp[builtin_opt.optind] &&
ksh_isdash(wp[builtin_opt.optind]))
builtin_opt.optind++;
- } else if (flags & PO_PMINUSMINUS)
- builtin_opt.optind--;
+ } else if (po_pminusminus)
+ builtin_opt.optind--;
wp += builtin_opt.optind;
}
Xinit(xs, xp, 128, ATEMP);
- while (*wp != NULL) {
+ if (*wp != NULL) {
+ print_read_arg:
s = *wp;
while ((c = *s++) != '\0') {
Xcheck(xs, xp);
- if ((flags & PO_EXPAND) && c == '\\') {
+ if (po_exp && c == '\\') {
s_ptr = s;
c = unbksl(false, s_get, s_put);
s = s_ptr;
@@ -415,11 +418,11 @@ c_print(const char **wp)
/* rejected by generic function */
switch ((c = *s++)) {
case 'c':
- flags &= ~PO_NL;
+ po_nl = false;
/* AT&T brain damage */
continue;
case '\0':
- s--;
+ --s;
c = '\\';
break;
default:
@@ -430,25 +433,31 @@ c_print(const char **wp)
char ts[4];
ts[utf_wctomb(ts, c - 0x100)] = 0;
- for (c = 0; ts[c]; ++c)
+ c = 0;
+ do {
Xput(xs, xp, ts[c]);
+ } while (ts[++c]);
continue;
}
}
Xput(xs, xp, c);
}
- if (*++wp != NULL)
+ if (*++wp != NULL) {
Xput(xs, xp, ' ');
+ goto print_read_arg;
+ }
}
- if (flags & PO_NL)
+ if (po_nl)
Xput(xs, xp, '\n');
- if (flags & PO_HIST) {
+ c = 0;
+ if (po_hist) {
Xput(xs, xp, '\0');
histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
Xfree(xs, xp);
} else {
- int len = Xlength(xs, xp);
+ size_t len = Xlength(xs, xp);
+ bool po_coproc = false;
int opipe = 0;
/*
@@ -458,30 +467,36 @@ c_print(const char **wp)
* not enough).
*/
if (coproc.write >= 0 && coproc.write == fd) {
- flags |= PO_COPROC;
+ po_coproc = true;
opipe = block_pipe();
}
- for (s = Xstring(xs, xp); len > 0; ) {
- if ((c = write(fd, s, len)) < 0) {
- if (flags & PO_COPROC)
- restore_pipe(opipe);
+
+ s = Xstring(xs, xp);
+ while (len > 0) {
+ ssize_t nwritten;
+
+ if ((nwritten = write(fd, s, len)) < 0) {
if (errno == EINTR) {
- /* allow user to ^C out */
+ if (po_coproc)
+ restore_pipe(opipe);
+ /* give the user a chance to ^C out */
intrcheck();
- if (flags & PO_COPROC)
+ /* interrupted, try again */
+ if (po_coproc)
opipe = block_pipe();
continue;
}
- return (1);
+ c = 1;
+ break;
}
- s += c;
- len -= c;
+ s += nwritten;
+ len -= nwritten;
}
- if (flags & PO_COPROC)
+ if (po_coproc)
restore_pipe(opipe);
}
- return (0);
+ return (c);
}
static int
@@ -1305,7 +1320,8 @@ c_fgbg(const char **wp)
rv = j_resume(*wp, bg);
else
rv = j_resume("%%", bg);
- return (bg ? 0 : rv);
+ /* fg returns $? of the job unless POSIX */
+ return ((bg | Flag(FPOSIX)) ? 0 : rv);
}
#endif
@@ -1374,7 +1390,7 @@ c_kill(const char **wp)
for (; wp[i]; i++) {
if (!bi_getn(wp[i], &n))
return (1);
-#if (ksh_NSIG < 128)
+#if (ksh_NSIG <= 128)
if (n > 128 && n < 128 + ksh_NSIG)
n -= 128;
#endif
@@ -1383,9 +1399,16 @@ c_kill(const char **wp)
else
shprintf("%d\n", n);
}
+ } else if (Flag(FPOSIX)) {
+ n = 1;
+ while (n < ksh_NSIG) {
+ shf_puts(sigtraps[n].name, shl_stdout);
+ shf_putc(++n == ksh_NSIG ? '\n' : ' ',
+ shl_stdout);
+ }
} else {
ssize_t w, mess_cols = 0, mess_octs = 0;
- int j = ksh_NSIG;
+ int j = ksh_NSIG - 1;
struct kill_info ki = { 0, 0 };
do {
@@ -1436,7 +1459,8 @@ void
getopts_reset(int val)
{
if (val >= 1) {
- ksh_getopt_reset(&user_opt, GF_NONAME | GF_PLUSOPT);
+ ksh_getopt_reset(&user_opt, GF_NONAME |
+ (Flag(FPOSIX) ? 0 : GF_PLUSOPT));
user_opt.optind = user_opt.uoptind = val;
}
}
@@ -1777,7 +1801,11 @@ c_dot(const char **wp)
bi_errorf("missing argument");
return (1);
}
- if ((file = search_path(cp, path, R_OK, &errcode)) == NULL) {
+ file = search_path(cp, path, R_OK, &errcode);
+ if (!file && errcode == ENOENT && wp[0][0] == 's' &&
+ search_access(cp, R_OK) == 0)
+ file = cp;
+ if (!file) {
bi_errorf("%s: %s", cp, cstrerror(errcode));
return (1);
}
@@ -1835,13 +1863,15 @@ c_read(const char **wp)
enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
char delim = '\n';
size_t bytesleft = 128, bytesread;
- struct tbl *vp /* FU gcc */ = NULL, *vq;
+ struct tbl *vp /* FU gcc */ = NULL, *vq = NULL;
char *cp, *allocd = NULL, *xp;
const char *ccp;
XString xs;
size_t xsave = 0;
mksh_ttyst tios;
bool restore_tios = false;
+ /* to catch read -aN2 foo[i] */
+ bool subarray = false;
#if HAVE_SELECT
bool hastimeout = false;
struct timeval tv, tvlim;
@@ -2086,6 +2116,7 @@ c_read(const char **wp)
XinitN(xs, 128, ATEMP);
if (intoarray) {
vp = global(*wp);
+ subarray = last_lookup_was_array;
if (vp->flag & RDONLY) {
c_read_splitro:
bi_errorf("read-only: %s", *wp);
@@ -2094,10 +2125,10 @@ c_read(const char **wp)
afree(cp, ATEMP);
goto c_read_out;
}
- /* exporting an array is currently pointless */
- unset(vp, 1);
/* counter for array index */
- c = 0;
+ c = subarray ? arrayindex(vp) : 0;
+ /* exporting an array is currently pointless */
+ unset(vp, subarray ? 0 : 1);
}
if (!aschars) {
/* skip initial IFS whitespace */
@@ -2199,7 +2230,18 @@ c_read(const char **wp)
c_read_gotword:
Xput(xs, xp, '\0');
if (intoarray) {
- vq = arraysearch(vp, c++);
+ if (subarray) {
+ /* array element passed, accept first read */
+ if (vq) {
+ bi_errorf("nested arrays not yet supported");
+ goto c_read_spliterr;
+ }
+ vq = vp;
+ if (c)
+ /* [0] doesn't */
+ vq->flag |= AINDEX;
+ } else
+ vq = arraysearch(vp, c++);
} else {
vq = global(*wp);
/* must be checked before exporting */
@@ -2293,7 +2335,7 @@ int
c_trap(const char **wp)
{
Trap *p = sigtraps;
- int i = ksh_NSIG + 1;
+ int i = ksh_NSIG;
const char *s;
if (ksh_getopt(wp, &builtin_opt, null) == '?')
@@ -2308,7 +2350,7 @@ c_trap(const char **wp)
shprintf(" %s\n", p->name);
}
++p;
- } while (--i);
+ } while (i--);
return (0);
}
@@ -2339,16 +2381,14 @@ int
c_exitreturn(const char **wp)
{
int n, how = LEXIT;
- const char *arg;
- if (ksh_getopt(wp, &builtin_opt, null) == '?')
- goto c_exitreturn_err;
- arg = wp[builtin_opt.optind];
-
- if (arg)
- exstat = bi_getn(arg, &n) ? (n & 0xFF) : 1;
- else if (trap_exstat != -1)
+ if (wp[1]) {
+ if (wp[2])
+ goto c_exitreturn_err;
+ exstat = bi_getn(wp[1], &n) ? (n & 0xFF) : 1;
+ } else if (trap_exstat != -1)
exstat = trap_exstat;
+
if (wp[0][0] == 'r') {
/* return */
struct env *ep;
@@ -2369,12 +2409,13 @@ c_exitreturn(const char **wp)
how = LSHELL;
}
- /* get rid of any i/o redirections */
+ /* get rid of any I/O redirections */
quitenv(NULL);
unwind(how);
/* NOTREACHED */
c_exitreturn_err:
+ bi_errorf("too many arguments");
return (1);
}
@@ -2542,7 +2583,7 @@ p_time(struct shf *shf, bool posix, long tv_sec, int tv_usec, int width,
shf_fprintf(shf, "%s%*ld.%02d%s", prefix, width,
tv_sec, tv_usec, suffix);
else
- shf_fprintf(shf, "%s%*ldm%d.%02ds%s", prefix, width,
+ shf_fprintf(shf, "%s%*ldm%02d.%02ds%s", prefix, width,
tv_sec / 60, (int)(tv_sec % 60), tv_usec, suffix);
}
@@ -2840,7 +2881,7 @@ c_test(const char **wp)
/*
* Attempt to conform to POSIX special cases. This is pretty
- * dumb code straight-forward from the 2008 spec, but unless
+ * dumb code straight-forward from the 2008 spec, but unlike
* the old pdksh code doesn't live from so many assumptions.
* It does, though, inline some calls to '(*te.funcname)()'.
*/
@@ -2861,6 +2902,8 @@ c_test(const char **wp)
ptest_unary:
rv = test_eval(&te, op, *te.pos.wp++, NULL, true);
ptest_out:
+ if (te.flags & TEF_ERROR)
+ return (T_ERR_EXIT);
return ((invert & 1) ? rv : !rv);
}
/* let the parser deal with anything else */
@@ -3638,10 +3681,11 @@ c_realpath(const char **wp)
int
c_cat(const char **wp)
{
- int fd = STDIN_FILENO, rv, eno;
+ int fd = STDIN_FILENO, rv;
ssize_t n, w;
const char *fn = "<stdin>";
char *buf, *cp;
+ int opipe = 0;
#define MKSH_CAT_BUFSIZ 4096
/* parse options: POSIX demands we support "-u" as no-op */
@@ -3663,54 +3707,64 @@ c_cat(const char **wp)
return (1);
}
+ /* catch SIGPIPE */
+ opipe = block_pipe();
+
do {
if (*wp) {
fn = *wp++;
if (ksh_isdash(fn))
fd = STDIN_FILENO;
else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
- eno = errno;
- bi_errorf("%s: %s", fn, cstrerror(eno));
+ bi_errorf("%s: %s", fn, cstrerror(errno));
rv = 1;
continue;
}
}
while (/* CONSTCOND */ 1) {
- n = blocking_read(fd, (cp = buf), MKSH_CAT_BUFSIZ);
- eno = errno;
- /* give the user a chance to ^C out */
- intrcheck();
- if (n == -1) {
- if (eno == EINTR) {
+ if ((n = blocking_read(fd, (cp = buf),
+ MKSH_CAT_BUFSIZ)) == -1) {
+ if (errno == EINTR) {
+ restore_pipe(opipe);
+ /* give the user a chance to ^C out */
+ intrcheck();
/* interrupted, try again */
+ opipe = block_pipe();
continue;
}
/* an error occured during reading */
- bi_errorf("%s: %s", fn, cstrerror(eno));
+ bi_errorf("%s: %s", fn, cstrerror(errno));
rv = 1;
break;
} else if (n == 0)
/* end of file reached */
break;
while (n) {
- w = write(STDOUT_FILENO, cp, n);
- eno = errno;
- /* give the user a chance to ^C out */
- intrcheck();
- if (w == -1) {
- if (eno == EINTR)
- /* interrupted, try again */
- continue;
+ if ((w = write(STDOUT_FILENO, cp, n)) != -1) {
+ n -= w;
+ cp += w;
+ continue;
+ }
+ if (errno == EINTR) {
+ restore_pipe(opipe);
+ /* give the user a chance to ^C out */
+ intrcheck();
+ /* interrupted, try again */
+ opipe = block_pipe();
+ continue;
+ }
+ if (errno == EPIPE) {
+ /* fake receiving signel */
+ rv = ksh_sigmask(SIGPIPE);
+ } else {
/* an error occured during writing */
bi_errorf("%s: %s", "<stdout>",
- cstrerror(eno));
+ cstrerror(errno));
rv = 1;
- if (fd != STDIN_FILENO)
- close(fd);
- goto out;
}
- n -= w;
- cp += w;
+ if (fd != STDIN_FILENO)
+ close(fd);
+ goto out;
}
}
if (fd != STDIN_FILENO)
@@ -3718,6 +3772,7 @@ c_cat(const char **wp)
} while (*wp);
out:
+ restore_pipe(opipe);
free_osfunc(buf);
return (rv);
}
diff --git a/src/histrap.c b/src/histrap.c
index 7a96aa8..57f2124 100644
--- a/src/histrap.c
+++ b/src/histrap.c
@@ -1,10 +1,10 @@
-/* $OpenBSD: history.c,v 1.40 2014/11/20 15:22:39 tedu Exp $ */
+/* $OpenBSD: history.c,v 1.41 2015/09/01 13:12:31 tedu Exp $ */
/* $OpenBSD: trap.c,v 1.23 2010/05/19 17:36:08 jasper Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -27,7 +27,7 @@
#include <sys/file.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.149 2015/07/09 20:52:40 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.152 2016/01/14 23:18:08 tg Exp $");
Trap sigtraps[ksh_NSIG + 1];
static struct sigaction Sigact_ign;
@@ -898,8 +898,7 @@ histload(Source *s, unsigned char *base, size_t bytes)
if (lno >= s->line - (histptr - history) && lno <= s->line) {
hp = &histptr[lno - s->line];
- if (*hp)
- afree(*hp, APERM);
+ afree(*hp, APERM);
strdupx(*hp, (char *)(base + 4), APERM);
}
} else {
@@ -1214,7 +1213,7 @@ fatal_trap_check(void)
do {
if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
/* return value is used as an exit code */
- return (128 + p->signal);
+ return (ksh_sigmask(p->signal));
++p;
} while (--i);
return (0);
@@ -1376,8 +1375,7 @@ settrap(Trap *p, const char *s)
{
sig_t f;
- if (p->trap)
- afree(p->trap, APERM);
+ afree(p->trap, APERM);
/* handles s == NULL */
strdupx(p->trap, s, APERM);
p->flags |= TF_CHANGED;
diff --git a/src/jobs.c b/src/jobs.c
index 8469f83..0cecdc5 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1,9 +1,9 @@
-/* $OpenBSD: jobs.c,v 1.41 2015/04/18 18:28:36 deraadt Exp $ */
+/* $OpenBSD: jobs.c,v 1.43 2015/09/10 22:48:58 nicm Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
- * 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.112 2015/04/19 14:40:09 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.117 2016/01/14 23:18:09 tg Exp $");
#if HAVE_KILLPG
#define mksh_killpg killpg
@@ -86,7 +86,7 @@ struct job {
int flags; /* see JF_* */
volatile int state; /* job state */
int status; /* exit status of last process */
- int32_t age; /* number of jobs started */
+ int age; /* number of jobs started */
Coproc_id coproc_id; /* 0 or id of coprocess output pipe */
#ifndef MKSH_UNEMPLOYED
mksh_ttyst ttystat; /* saved tty state for stopped jobs */
@@ -118,7 +118,7 @@ static Job *async_job;
static pid_t async_pid;
static int nzombie; /* # of zombies owned by this process */
-static int32_t njobs; /* # of jobs started */
+static int njobs; /* # of jobs started */
#ifndef CHILD_MAX
#define CHILD_MAX 25
@@ -217,9 +217,9 @@ proc_errorlevel(Proc *p)
{
switch (p->state) {
case PEXITED:
- return (WEXITSTATUS(p->status));
+ return ((WEXITSTATUS(p->status)) & 255);
case PSIGNALLED:
- return (128 + WTERMSIG(p->status));
+ return (ksh_sigmask(WTERMSIG(p->status)));
default:
return (0);
}
@@ -753,7 +753,7 @@ waitfor(const char *cp, int *sigp)
if (rv < 0)
/* we were interrupted */
- *sigp = 128 + -rv;
+ *sigp = ksh_sigmask(-rv);
return (rv);
}
@@ -889,7 +889,7 @@ j_resume(const char *cp, int bg)
(long)kshpgrp, "failed", cstrerror(errno));
}
sigprocmask(SIG_SETMASK, &omask, NULL);
- bi_errorf("%s %s %s", "can't continue job",
+ bi_errorf("%s %s: %s", "can't continue job",
cp, cstrerror(eno));
return (1);
}
@@ -1223,14 +1223,14 @@ j_waitj(Job *j,
* even when not monitoring, but this doesn't make sense since
* a tty generated ^C goes to the whole process group)
*/
- {
- int status;
-
- status = j->last_proc->status;
- if (Flag(FMONITOR) && j->state == PSIGNALLED &&
- WIFSIGNALED(status) &&
- (sigtraps[WTERMSIG(status)].flags & TF_TTY_INTR))
- trapsig(WTERMSIG(status));
+ if (Flag(FMONITOR) && j->state == PSIGNALLED &&
+ WIFSIGNALED(j->last_proc->status)) {
+ int termsig;
+
+ if ((termsig = WTERMSIG(j->last_proc->status)) > 0 &&
+ termsig < ksh_NSIG &&
+ (sigtraps[termsig].flags & TF_TTY_INTR))
+ trapsig(termsig);
}
#endif
}
@@ -1527,7 +1527,7 @@ j_print(Job *j, int how, struct shf *shf)
Proc *p;
int state;
int status;
- int coredumped;
+ bool coredumped;
char jobchar = ' ';
char buf[64];
const char *filler;
@@ -1551,41 +1551,49 @@ j_print(Job *j, int how, struct shf *shf)
jobchar = '-';
for (p = j->proc_list; p != NULL;) {
- coredumped = 0;
+ coredumped = false;
switch (p->state) {
case PRUNNING:
memcpy(buf, "Running", 8);
break;
- case PSTOPPED:
- strlcpy(buf, sigtraps[WSTOPSIG(p->status)].mess,
- sizeof(buf));
+ case PSTOPPED: {
+ int stopsig = WSTOPSIG(p->status);
+
+ strlcpy(buf, stopsig > 0 && stopsig < ksh_NSIG ?
+ sigtraps[stopsig].mess : "Stopped", sizeof(buf));
break;
- case PEXITED:
+ }
+ case PEXITED: {
+ int exitstatus = (WEXITSTATUS(p->status)) & 255;
+
if (how == JP_SHORT)
buf[0] = '\0';
- else if (WEXITSTATUS(p->status) == 0)
+ else if (exitstatus == 0)
memcpy(buf, "Done", 5);
else
shf_snprintf(buf, sizeof(buf), "Done (%d)",
- WEXITSTATUS(p->status));
+ exitstatus);
break;
- case PSIGNALLED:
+ }
+ case PSIGNALLED: {
+ int termsig = WTERMSIG(p->status);
#ifdef WCOREDUMP
if (WCOREDUMP(p->status))
- coredumped = 1;
+ coredumped = true;
#endif
/*
* kludge for not reporting 'normal termination
* signals' (i.e. SIGINT, SIGPIPE)
*/
if (how == JP_SHORT && !coredumped &&
- (WTERMSIG(p->status) == SIGINT ||
- WTERMSIG(p->status) == SIGPIPE)) {
+ (termsig == SIGINT || termsig == SIGPIPE)) {
buf[0] = '\0';
} else
- strlcpy(buf, sigtraps[WTERMSIG(p->status)].mess,
+ strlcpy(buf, termsig > 0 && termsig < ksh_NSIG ?
+ sigtraps[termsig].mess : "Signalled",
sizeof(buf));
break;
+ }
default:
buf[0] = '\0';
}
diff --git a/src/lalloc.c b/src/lalloc.c
index f943365..4eca6a5 100644
--- a/src/lalloc.c
+++ b/src/lalloc.c
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2009, 2010, 2011, 2013, 2014
- * Thorsten Glaser <tg@mirbsd.org>
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -20,7 +20,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.21 2014/11/25 20:00:39 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.23 2015/11/29 17:05:01 tg Exp $");
/* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */
#if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0)
diff --git a/src/lex.c b/src/lex.c
index fb80244..e5305ae 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -1,9 +1,9 @@
-/* $OpenBSD: lex.c,v 1.49 2013/12/17 16:37:06 deraadt Exp $ */
+/* $OpenBSD: lex.c,v 1.51 2015/09/10 22:48:58 nicm Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.204 2015/07/05 19:53:46 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.218 2016/01/20 21:34:12 tg Exp $");
/*
* states while lexing word
@@ -38,8 +38,8 @@ __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.204 2015/07/05 19:53:46 tg Exp $");
#define SQBRACE 7 /* inside "${}" */
#define SBQUOTE 8 /* inside `` */
#define SASPAREN 9 /* inside $(( )) */
-#define SHEREDELIM 10 /* parsing <<,<<-,<<< delimiter */
-#define SHEREDQUOTE 11 /* parsing " in <<,<<-,<<< delimiter */
+#define SHEREDELIM 10 /* parsing << or <<- delimiter */
+#define SHEREDQUOTE 11 /* parsing " in << or <<- delimiter */
#define SPATTERN 12 /* parsing *(...|...) pattern (*+?@!) */
#define SADELIM 13 /* like SBASE, looking for delimiter */
#define STBRACEKORN 14 /* parsing ${...[#%]...} !FSH */
@@ -61,7 +61,7 @@ typedef struct lex_state {
/* point to the next state block */
struct lex_state *base;
/* marks start of state output in output string */
- int start;
+ size_t start;
/* SBQUOTE: true if in double quotes: "`...`" */
/* SEQUOTE: got NUL, ignore rest of string */
bool abool;
@@ -94,11 +94,10 @@ static void ungetsc_i(int);
static int getsc_uu(void);
static void getsc_line(Source *);
static int getsc_bn(void);
-static int s_get(void);
-static void s_put(int);
+static int getsc_i(void);
static char *get_brace_var(XString *, char *);
static bool arraysub(char **);
-static void gethere(bool);
+static void gethere(void);
static Lex_state *push_state_i(State_info *, Lex_state *);
static Lex_state *pop_state_i(State_info *, Lex_state *);
@@ -112,7 +111,7 @@ static int ignore_backslash_newline;
#define o_getsc_u() ((*source->str != '\0') ? *source->str++ : getsc_uu())
/* retrace helper */
-#define o_getsc_r(carg) { \
+#define o_getsc_r(carg) \
int cev = (carg); \
struct sretrace_info *rp = retrace_info; \
\
@@ -122,17 +121,17 @@ static int ignore_backslash_newline;
rp = rp->next; \
} \
\
- return (cev); \
-}
-
-#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
-static int getsc(void);
+ return (cev);
+/* callback */
static int
-getsc(void)
+getsc_i(void)
{
o_getsc_r(o_getsc());
}
+
+#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
+#define getsc getsc_i
#else
static int getsc_r(int);
@@ -234,26 +233,14 @@ yylex(int cf)
if (source->flags & SF_ALIAS) {
/* trailing ' ' in alias definition */
source->flags &= ~SF_ALIAS;
- cf |= ALIAS;
+ /* POSIX: trailing space only counts if parsing simple cmd */
+ if (!Flag(FPOSIX) || (cf & CMDWORD))
+ cf |= ALIAS;
}
/* Initial state: one of SWORD SLETPAREN SHEREDELIM SBASE */
statep->type = state;
- /* check for here string */
- if (state == SHEREDELIM) {
- c = getsc();
- if (c == '<') {
- state = SHEREDELIM;
- while ((c = getsc()) == ' ' || c == '\t')
- ;
- ungetsc(c);
- c = '<';
- goto accept_nonword;
- }
- ungetsc(c);
- }
-
/* collect non-special or quoted characters to form word */
while (!((c = getsc()) == 0 ||
((state == SBASE || state == SHEREDELIM) && ctype(c, C_LEX1)))) {
@@ -262,7 +249,6 @@ yylex(int cf)
c == /*{*/ '}')
/* possibly end ${ :;} */
break;
- accept_nonword:
Xcheck(ws, wp);
switch (state) {
case SADELIM:
@@ -282,7 +268,7 @@ yylex(int cf)
}
/* FALLTHROUGH */
case SBASE:
- if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
+ if (c == '[' && (cf & CMDASN)) {
/* temporary */
*wp = EOS;
if (is_wdvarname(Xstring(ws, wp), false)) {
@@ -539,27 +525,34 @@ yylex(int cf)
PUSH_STATE(SBQUOTE);
*wp++ = COMSUB;
/*
- * Need to know if we are inside double quotes
- * since sh/AT&T-ksh translate the \" to " in
- * "`...\"...`".
- * This is not done in POSIX mode (section
- * 3.2.3, Double Quotes: "The backquote shall
- * retain its special meaning introducing the
- * other form of command substitution (see
- * 3.6.3). The portion of the quoted string
- * from the initial backquote and the
- * characters up to the next backquote that
- * is not preceded by a backslash (having
- * escape characters removed) defines that
- * command whose output replaces `...` when
- * the word is expanded."
- * Section 3.6.3, Command Substitution:
- * "Within the backquoted style of command
- * substitution, backslash shall retain its
- * literal meaning, except when followed by
- * $ ` \.").
+ * We need to know whether we are within double
+ * quotes, since most shells translate \" to "
+ * within "…`…\"…`…". This is not done in POSIX
+ * mode (§2.2.3 Double-Quotes: “The backquote
+ * shall retain its special meaning introducing
+ * the other form of command substitution (see
+ * Command Substitution). The portion of the
+ * quoted string from the initial backquote and
+ * the characters up to the next backquote that
+ * is not preceded by a <backslash>, having
+ * escape characters removed, defines that
+ * command whose output replaces "`...`" when
+ * the word is expanded.”; §2.6.3 Command
+ * Substitution: “Within the backquoted style
+ * of command substitution, <backslash> shall
+ * retain its literal meaning, except when
+ * followed by: '$', '`', or <backslash>. The
+ * search for the matching backquote shall be
+ * satisfied by the first unquoted non-escaped
+ * backquote; during this search, if a
+ * non-escaped backquote is encountered[…],
+ * undefined results occur.”).
*/
statep->ls_bool = false;
+#ifdef austingroupbugs1015_is_still_not_resolved
+ if (Flag(FPOSIX))
+ break;
+#endif
s2 = statep;
base = state_info.base;
while (/* CONSTCOND */ 1) {
@@ -596,8 +589,8 @@ yylex(int cf)
*wp++ = CQUOTE;
ignore_backslash_newline--;
} else if (c == '\\') {
- if ((c2 = unbksl(true, s_get, s_put)) == -1)
- c2 = s_get();
+ if ((c2 = unbksl(true, getsc_i, ungetsc)) == -1)
+ c2 = getsc();
if (c2 == 0)
statep->ls_bool = true;
if (!statep->ls_bool) {
@@ -609,10 +602,11 @@ yylex(int cf)
} else {
cz = utf_wctomb(ts, c2 - 0x100);
ts[cz] = 0;
- for (cz = 0; ts[cz]; ++cz) {
+ cz = 0;
+ do {
*wp++ = QCHAR;
*wp++ = ts[cz];
- }
+ } while (ts[++cz]);
}
}
} else if (!statep->ls_bool) {
@@ -747,8 +741,9 @@ yylex(int cf)
case 0:
/* trailing \ is lost */
break;
+ case '$':
+ case '`':
case '\\':
- case '$': case '`':
*wp++ = c;
break;
case '"':
@@ -783,6 +778,7 @@ yylex(int cf)
Source *s;
ungetsc(c2);
+ ungetsc(c);
/*
* mismatched parenthesis -
* assume we were really
@@ -790,11 +786,12 @@ yylex(int cf)
*/
*wp = EOS;
sp = Xstring(ws, wp);
- dp = wdstrip(sp, WDS_KEEPQ);
+ dp = wdstrip(sp + 1, WDS_TPUTS);
s = pushs(SREREAD, source->areap);
s->start = s->str = s->u.freeme = dp;
s->next = source;
source = s;
+ ungetsc('('/*)*/);
return ('('/*)*/);
}
} else if (c == '(')
@@ -806,7 +803,7 @@ yylex(int cf)
++statep->nparen;
goto Sbase2;
- /* <<, <<-, <<< delimiter */
+ /* << or <<- delimiter */
case SHEREDELIM:
/*
* here delimiters need a special case since
@@ -844,7 +841,7 @@ yylex(int cf)
}
break;
- /* " in <<, <<-, <<< delimiter */
+ /* " in << or <<- delimiter */
case SHEREDQUOTE:
if (c != '"')
goto Subst;
@@ -941,14 +938,12 @@ yylex(int cf)
iop->ioflag |= c == c2 ?
(c == '>' ? IOCAT : IOHERE) : IORDWR;
if (iop->ioflag == IOHERE) {
- if ((c2 = getsc()) == '-') {
+ if ((c2 = getsc()) == '-')
iop->ioflag |= IOSKIP;
- c2 = getsc();
- } else if (c2 == '<')
+ else if (c2 == '<')
iop->ioflag |= IOHERESTR;
- ungetsc(c2);
- if (c2 == '\n')
- iop->ioflag |= IONDELIM;
+ else
+ ungetsc(c2);
}
} else if (c2 == '&')
iop->ioflag |= IODUP | (c == '<' ? IORDUP : 0);
@@ -960,7 +955,7 @@ yylex(int cf)
ungetsc(c2);
}
- iop->name = NULL;
+ iop->ioname = NULL;
iop->delim = NULL;
iop->heredoc = NULL;
/* free word */
@@ -998,12 +993,14 @@ yylex(int cf)
}
#endif
} else if (c == '\n') {
- gethere(false);
- if (cf & CONTIN)
- goto Again;
- } else if (c == '\0')
- /* need here strings at EOF */
- gethere(true);
+ if (cf & HEREDELIM)
+ ungetsc(c);
+ else {
+ gethere();
+ if (cf & CONTIN)
+ goto Again;
+ }
+ }
return (c);
}
@@ -1026,23 +1023,8 @@ yylex(int cf)
/* copy word to unprefixed string ident */
sp = yylval.cp;
dp = ident;
- if ((cf & HEREDELIM) && (sp[1] == '<')) {
- herestringloop:
- switch ((c = *sp++)) {
- case CHAR:
- ++sp;
- /* FALLTHROUGH */
- case OQUOTE:
- case CQUOTE:
- goto herestringloop;
- default:
- break;
- }
- /* dummy value */
- *dp++ = 'x';
- } else
- while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
- *dp++ = *sp++;
+ while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
+ *dp++ = *sp++;
if (c != EOS)
/* word is not unquoted */
dp = ident;
@@ -1109,7 +1091,7 @@ yylex(int cf)
}
} else if (cf & ALIAS) {
/* retain typeset et al. even when quoted */
- if (assign_command((dp = wdstrip(yylval.cp, 0))))
+ if (assign_command((dp = wdstrip(yylval.cp, 0)), true))
strlcpy(ident, dp, sizeof(ident));
afree(dp, ATEMP);
}
@@ -1118,15 +1100,12 @@ yylex(int cf)
}
static void
-gethere(bool iseof)
+gethere(void)
{
struct ioword **p;
for (p = heres; p < herep; p++)
- if (iseof && !((*p)->ioflag & IOHERESTR))
- /* only here strings at EOF */
- return;
- else
+ if (!((*p)->ioflag & IOHERESTR))
readhere(*p);
herep = heres;
}
@@ -1142,18 +1121,9 @@ readhere(struct ioword *iop)
const char *eof, *eofp;
XString xs;
char *xp;
- int xpos;
-
- if (iop->ioflag & IOHERESTR) {
- /* process the here string */
- iop->heredoc = xp = evalstr(iop->delim, DOBLANK);
- xpos = strlen(xp) - 1;
- memmove(xp, xp + 1, xpos);
- xp[xpos] = '\n';
- return;
- }
+ size_t xpos;
- eof = iop->ioflag & IONDELIM ? "<<" : evalstr(iop->delim, 0);
+ eof = evalstr(iop->delim, 0);
if (!(iop->ioflag & IOEVAL))
ignore_backslash_newline++;
@@ -1816,15 +1786,3 @@ pop_state_i(State_info *si, Lex_state *old_end)
return (si->base + STATE_BSIZE - 1);
}
-
-static int
-s_get(void)
-{
- return (getsc());
-}
-
-static void
-s_put(int c)
-{
- ungetsc(c);
-}
diff --git a/src/lksh.1 b/src/lksh.1
index a13d7a0..8b26166 100644
--- a/src/lksh.1
+++ b/src/lksh.1
@@ -1,7 +1,7 @@
-.\" $MirOS: src/bin/mksh/lksh.1,v 1.10 2015/04/12 22:32:12 tg Exp $
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.16 2015/12/12 22:25:14 tg Exp $
.\"-
.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015
-.\" Thorsten “mirabilos” Glaser <tg@mirbsd.org>
+.\" mirabilos <m@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
.\" are retained or reproduced in an accompanying document, permission
@@ -72,7 +72,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
-.Dd $Mdocdate: April 12 2015 $
+.Dd $Mdocdate: December 12 2015 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
@@ -173,12 +173,27 @@ It is recommended to port scripts to
.Nm mksh
instead of relying on legacy or idiotic POSIX-mandated behaviour,
since the MirBSD Korn Shell scripting language is much more consistent.
+.Pp
+Note that it's strongly recommended to invoke
+.Nm
+with at least the
+.Fl o Ic posix
+option, if not both that
+.Em and Fl o Ic sh ,
+to fully enjoy better compatibility to the
+.Tn POSIX
+standard (which is probably why you use
+.Nm
+over
+.Nm mksh
+in the first place) or legacy scripts, respectively.
.Sh LEGACY MODE
.Nm
currently has the following differences from
.Nm mksh :
.Bl -bullet
.It
+.\"XXX TODO: remove (some systems may wish to have lksh as ksh)
There is no explicit support for interactive use,
nor any command line editing or history code.
Hence,
@@ -202,33 +217,44 @@ change between versions; see the accompanying manual page
for the versions this document applies to.
.It
.Nm
-only offers the traditional ten file descriptors to scripts.
-.It
-.Nm
uses
.Tn POSIX
arithmetics, which has quite a few implications:
-The data type for arithmetics is the host ISO C
+The data type for arithmetics is the host
+.Tn ISO
+C
.Vt long
data type.
-Signed integer wraparound is Undefined Behaviour.
+Signed integer wraparound is Undefined Behaviour; this means that...
+.Bd -literal -offset indent
+$ echo $((2147483647 + 1))
+.Ed
+.Pp
+\&... is permitted to, e.g. delete all files on your system
+(the figure differs for non-32-bit systems, the rule doesn't).
The sign of the result of a modulo operation with at least one
negative operand is unspecified.
Shift operations on negative numbers are unspecified.
Division of the largest negative number by \-1 is Undefined Behaviour.
The compiler is permitted to delete all data and crash the system
-if Undefined Behaviour occurs.
+if Undefined Behaviour occurs (see above for an example).
+.It
+.Nm
+only offers the traditional ten file descriptors to scripts.
.It
+.\"XXX TODO: move this to FPOSIX
The rotation arithmetic operators are not available.
.It
The shift arithmetic operators take all bits of the second operand into
account; if they exceed permitted precision, the result is unspecified.
.It
+.\"XXX TODO: move this to FPOSIX
The
.Tn GNU
.Nm bash
extension &\*(Gt to redirect stdout and stderr in one go is not parsed.
.It
+.\"XXX TODO: drop along with allowing interactivity
The
.Nm mksh
command line option
@@ -250,6 +276,7 @@ passes through the errorlevel from the
.Xr getopt 1
command.
.It
+.\"XXX TODO: move to FPOSIX/FSH
Unlike
.At
.Nm ksh ,
@@ -262,17 +289,6 @@ mode and
.Nm lksh
do not keep file descriptors \*(Gt 2 private from sub-processes.
.It
-.Nm lksh
-undefines an alias when a
-.Tn POSIX
-function with the same name is defined,
-to make that function immediately callable.
-In
-.Nm mksh ,
-aliases have precedence; the name must be quoted or
-.Ic unalias Ns ed
-to access it.
-.It
Functions defined with the
.Ic function
reserved word share the shell options
@@ -286,13 +302,30 @@ instead of locally scoping them.
.Pp
.Pa https://www.mirbsd.org/ksh\-chan.htm
.Sh CAVEATS
+The distinction between the shell variants
+.Pq Nm lksh / Nm mksh
+and shell flags
+.Pq Fl o Ic posix / Ic sh
+will be reworked for an upcoming release.
+.Pp
To use
.Nm
as
.Pa /bin/sh ,
compilation to enable
.Ic set -o posix
-by default is highly recommended for better standards compliance.
+by default if called as
+.Nm sh
+is highly recommended for better standards compliance.
+For better compatibility with legacy scripts, such as many
+.Tn Debian
+maintainer scripts, Upstart and SYSV init scripts, and other
+unfixed scripts, using the compile-time options for enabling
+.Em both
+.Ic set -o posix -o sh
+when the shell is run as
+.Nm sh
+is recommended.
.Pp
.Nm
tries to make a cross between a legacy bourne/posix compatibl-ish
@@ -302,7 +335,7 @@ is not exactly specified.
.Pp
The
.Ic set
-built-in command does not have all options one would expect
+built-in command does not currently have all options one would expect
from a full-blown
.Nm mksh
or
diff --git a/src/main.c b/src/main.c
index bca8471..bd013df 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,12 +1,12 @@
-/* $OpenBSD: main.c,v 1.55 2015/02/09 09:09:30 jsg Exp $ */
+/* $OpenBSD: main.c,v 1.57 2015/09/10 22:48:58 nicm Exp $ */
/* $OpenBSD: tty.c,v 1.10 2014/08/10 02:44:26 guenther Exp $ */
-/* $OpenBSD: io.c,v 1.25 2014/08/11 20:28:47 guenther Exp $ */
-/* $OpenBSD: table.c,v 1.15 2012/02/19 07:52:30 otto Exp $ */
+/* $OpenBSD: io.c,v 1.26 2015/09/11 08:00:27 guenther Exp $ */
+/* $OpenBSD: table.c,v 1.16 2015/09/01 13:12:31 tedu Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -34,7 +34,7 @@
#include <locale.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.300 2015/07/10 19:36:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.306 2015/10/09 21:36:57 tg Exp $");
extern char **environ;
@@ -71,18 +71,12 @@ static const char *initcoms[] = {
/* not "alias -t --": hash -r needs to work */
"hash=\\builtin alias -t",
"type=\\builtin whence -v",
-#if !defined(ANDROID) && !defined(MKSH_UNEMPLOYED)
- /* not in Android for political reasons */
- /* not in ARGE mksh due to no job control */
- "stop=\\kill -STOP",
-#endif
"autoload=\\typeset -fu",
"functions=\\typeset -f",
"history=\\builtin fc -l",
"nameref=\\typeset -n",
"nohup=nohup ",
"r=\\builtin fc -e -",
- "source=PATH=$PATH" MKSH_PATHSEPS ". \\command .",
"login=\\exec login",
NULL,
/* this is what AT&T ksh seems to track, with the addition of emacs */
@@ -202,7 +196,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
/* do things like getpgrp() et al. */
chvt_reinit();
- /* make sure argv[] is sane */
+ /* make sure argv[] is sane, for weird OSes */
if (!*argv) {
argv = empty_argv;
argc = 1;
@@ -255,7 +249,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
/* define built-in commands and see if we were called as one */
ktinit(APERM, &builtins,
- /* currently up to 51 builtins: 75% of 128 = 2^7 */
+ /* currently up to 54 builtins: 75% of 128 = 2^7 */
7);
for (i = 0; mkshbuiltins[i].name != NULL; i++)
if (!strcmp(ccp, builtin(mkshbuiltins[i].name,
@@ -416,11 +410,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
setint_n((vp_pipest = global("PIPESTATUS")), 0, 10);
/* Set this before parsing arguments */
- Flag(FPRIVILEGED) = (
-#if HAVE_ISSETUGID
- issetugid() ||
-#endif
- kshuid != ksheuid || kshgid != kshegid) ? 2 : 0;
+ Flag(FPRIVILEGED) = (kshuid != ksheuid || kshgid != kshegid) ? 2 : 0;
/* this to note if monitor is set on command line (see below) */
#ifndef MKSH_UNEMPLOYED
@@ -1269,8 +1259,7 @@ bi_errorf(const char *fmt, ...)
/*
* POSIX special builtins and ksh special builtins cause
- * non-interactive shells to exit.
- * XXX odd use of KEEPASN; also may not want LERROR here
+ * non-interactive shells to exit. XXX may not want LERROR here
*/
if (builtin_spec) {
builtin_argv0 = NULL;
diff --git a/src/mirhash.h b/src/mirhash.h
index df4a9dc..0105b22 100644
--- a/src/mirhash.h
+++ b/src/mirhash.h
@@ -1,6 +1,6 @@
/*-
* Copyright © 2011, 2014, 2015
- * Thorsten “mirabilos” Glaser <tg@mirbsd.org>
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -44,7 +44,7 @@
#include <sys/types.h>
-__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.4 2015/05/30 22:14:06 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/mirhash.h,v 1.6 2015/11/29 17:05:02 tg Exp $");
/*-
* BAFH itself is defined by the following primitives:
diff --git a/src/misc.c b/src/misc.c
index deb95c3..2923e35 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1,10 +1,10 @@
-/* $OpenBSD: misc.c,v 1.40 2015/03/18 15:12:36 tedu Exp $ */
-/* $OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $ */
+/* $OpenBSD: misc.c,v 1.41 2015/09/10 22:48:58 nicm Exp $ */
+/* $OpenBSD: path.c,v 1.13 2015/09/05 09:47:08 jsg Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -30,7 +30,7 @@
#include <grp.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.238 2015/07/10 19:36:36 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.240 2015/10/09 16:11:17 tg Exp $");
#define KSH_CHVT_FLAG
#ifdef MKSH_SMALL
@@ -1570,16 +1570,14 @@ do_realpath(const char *upath)
}
/* return target path */
- if (ldest != NULL)
- afree(ldest, ATEMP);
+ afree(ldest, ATEMP);
afree(ipath, ATEMP);
return (Xclose(xs, xp));
notfound:
/* save; freeing memory might trash it */
llen = errno;
- if (ldest != NULL)
- afree(ldest, ATEMP);
+ afree(ldest, ATEMP);
afree(ipath, ATEMP);
Xfree(xs, xp);
errno = llen;
diff --git a/src/mksh.1 b/src/mksh.1
index c612c68..923c721 100644
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,9 +1,9 @@
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.377 2015/07/10 19:35:39 tg Exp $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.388 2016/01/20 22:04:54 tg Exp $
.\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
-.\" 2010, 2011, 2012, 2013, 2014, 2015
-.\" Thorsten “mirabilos” Glaser <tg@mirbsd.org>
+.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016
+.\" mirabilos <m@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
.\" are retained or reproduced in an accompanying document, permission
@@ -74,7 +74,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
-.Dd $Mdocdate: July 10 2015 $
+.Dd $Mdocdate: January 20 2016 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
@@ -179,6 +179,11 @@ script use.
Its command language is a superset of the
.Xr sh C
shell language and largely compatible to the original Korn shell.
+At times, this manual page may give scripting advice; while it
+sometimes does take portable shell scripting or various standards
+into account all information is first and foremost presented with
+.Nm
+in mind and should be taken as such.
.Ss I'm an Android user, so what's mksh?
.Nm mksh
is a
@@ -434,7 +439,7 @@ Whitespace and meta-characters can be quoted individually using a backslash
or in groups using double
.Pq Sq \&"
or single
-.Pq Sq \*(aq
+.Pq Dq \*(aq
quotes.
Note that the following characters are also treated specially by the
shell and must be quoted if they are to represent themselves:
@@ -914,7 +919,7 @@ is evaluated; equivalent to
.Sx Arithmetic expressions
and the
.Ic let
-command, below).
+command, below) in a compound construct.
.It Bq Bq Ar \ \&expression\ \&
Similar to the
.Ic test
@@ -988,7 +993,7 @@ case both the
.Ql \e
and the newline are stripped.
Second, a single quote
-.Pq Sq \*(aq
+.Pq Dq \*(aq
quotes everything up to the next single quote (this may span lines).
Third, a double quote
.Pq Sq \&"
@@ -1001,8 +1006,8 @@ up to the next unquoted double quote.
.Ql $
and
.Ql \`
-inside double quotes have their usual meaning (i.e. parameter, command, or
-arithmetic substitution) except no field splitting is carried out on the
+inside double quotes have their usual meaning (i.e. parameter, arithmetic,
+or command substitution) except no field splitting is carried out on the
results of double-quoted substitutions.
If a
.Ql \e
@@ -1026,7 +1031,9 @@ characters inside can be escaped and do not terminate the string then);
the expanded result is treated as any other single-quoted string.
If a double-quoted string is preceded by an unquoted
.Ql $ ,
-the latter is ignored.
+the
+.Ql $
+is simply ignored.
.Ss Backslash expansion
In places where backslashes are expanded, certain C and
.At
@@ -1130,8 +1137,6 @@ login=\*(aq\eexec login\*(aq
nameref=\*(aq\etypeset \-n\*(aq
nohup=\*(aqnohup \*(aq
r=\*(aq\ebuiltin fc \-e \-\*(aq
-source=\*(aqPATH=$PATH:. \ecommand .\*(aq
-stop=\*(aq\ekill \-STOP\*(aq
type=\*(aq\ebuiltin whence \-v\*(aq
.Ed
.Pp
@@ -1288,6 +1293,8 @@ command which is run in a subshell.
For
.Pf $( Ns Ar command Ns \&)
and
+.Pf ${\*(Ba\& Ns Ar command Ns \&;}
+and
.Pf ${\ \& Ar command Ns \&;}
substitutions, normal quoting rules are used when
.Ar command
@@ -1298,6 +1305,8 @@ form, a
followed by any of
.Ql $ ,
.Ql \` ,
+.Ql \&"
+.Pq currently, and violating Tn POSIX ,
or
.Ql \e
is stripped (a
@@ -1627,31 +1636,40 @@ Cannot be applied to a vector.
.Xc
.It Xo
.Pf ${ Ar name
+.Pf /# Ar pattern / Ar string No }
+.Xc
+.It Xo
+.Pf ${ Ar name
+.Pf /% Ar pattern / Ar string No }
+.Xc
+.It Xo
+.Pf ${ Ar name
.Pf // Ar pattern / Ar string No }
.Xc
.Sm on
-Similar to ${..##..} substitution, but it replaces the longest match of
-.Ar pattern ,
-anchored anywhere in the value, with
-.Ar string .
-If
+The longest match of
.Ar pattern
-begins with
-.Ql # ,
-it is anchored at the beginning of the value; if it begins with
-.Ql % ,
-it is anchored at the end.
-Empty patterns cause no replacement to happen.
-A single leading
-.Ql /
-or use of a pattern that matches the empty string causes the
-replacement to happen only once; two leading slashes cause
-all occurrences of matches in the value to be replaced.
-If the trailing
-.Pf / Ar string
-is omitted, any matches of
+in the value of parameter
+.Ar name
+is replaced with
+.Ar string
+(deleted if
+.Ar string
+is empty; the trailing slash
+.Pq Ql /
+may be omitted in that case).
+A leading slash followed by
+.Ql #
+or
+.Ql %
+causes the pattern to be anchored at the beginning or end of
+the value, respectively; empty unanchored
+.Ar pattern Ns s
+cause no replacement; a single leading slash or use of a
.Ar pattern
-are replaced by the empty string, i.e. deleted.
+that matches the empty string causes the replacement to
+happen only once; two leading slashes cause all occurrences
+of matches in the value to be replaced.
Cannot be applied to a vector.
Inefficiently implemented, may be slow.
.Pp
@@ -1737,7 +1755,7 @@ command below for a list of options).
The exit status of the last non-asynchronous command executed.
If the last command was killed by a signal,
.Ic $?\&
-is set to 128 plus the signal number.
+is set to 128 plus the signal number, but at most 255.
.It Ev 0
The name of the shell, determined as follows:
the first argument to
@@ -1946,8 +1964,8 @@ Assigning 1 to this parameter causes
.Ic getopts
to process arguments from the beginning the next time it is invoked.
.It Ev PATH
-A colon separated list of directories that are searched when looking for
-commands and files sourced using the
+A colon (semicolon on OS/2) separated list of directories that are
+searched when looking for commands and files sourced using the
.Sq \&.
command (see below).
An empty string resulting from a leading or trailing
@@ -2336,7 +2354,7 @@ input is initially set to be from
.Pa /dev/null ,
and commands for which any of the following redirections have been specified:
.Bl -tag -width XXxxmarker
-.It \*(Gt Ar file
+.It \*(Gt Ns Ar file
Standard output is redirected to
.Ar file .
If
@@ -2352,13 +2370,13 @@ for reading and then truncate it when it opens it for writing, before
.Ar cmd
gets a chance to actually read
.Ar foo .
-.It \*(Gt\*(Ba Ar file
+.It \*(Gt\*(Ba Ns Ar file
Same as
.Ic \*(Gt ,
except the file is truncated, even if the
.Ic noclobber
option is set.
-.It \*(Gt\*(Gt Ar file
+.It \*(Gt\*(Gt Ns Ar file
Same as
.Ic \*(Gt ,
except if
@@ -2367,15 +2385,15 @@ exists it is appended to instead of being truncated.
Also, the file is opened
in append mode, so writes always go to the end of the file (see
.Xr open 2 ) .
-.It \*(Lt Ar file
+.It \*(Lt Ns Ar file
Standard input is redirected from
.Ar file ,
which is opened for reading.
-.It \*(Lt\*(Gt Ar file
+.It \*(Lt\*(Gt Ns Ar file
Same as
.Ic \*(Lt ,
except the file is opened for reading and writing.
-.It \*(Lt\*(Lt Ar marker
+.It \*(Lt\*(Lt Ns Ar marker
After reading the command line containing this kind of redirection (called a
.Dq here document ) ,
the shell copies lines from the command source into a temporary file until a
@@ -2415,11 +2433,11 @@ or double
.Sq \&""
quotes with nothing in between, the here document ends at the next empty line
and substitution will not be performed.
-.It \*(Lt\*(Lt\- Ar marker
+.It \*(Lt\*(Lt\- Ns Ar marker
Same as
.Ic \*(Lt\*(Lt ,
except leading tabs are stripped from lines in the here document.
-.It \*(Lt\*(Lt\*(Lt Ar word
+.It \*(Lt\*(Lt\*(Lt Ns Ar word
Same as
.Ic \*(Lt\*(Lt ,
except that
@@ -2427,7 +2445,7 @@ except that
.Em is
the here document.
This is called a here string.
-.It \*(Lt& Ar fd
+.It \*(Lt& Ns Ar fd
Standard input is duplicated from file descriptor
.Ar fd .
.Ar fd
@@ -2441,42 +2459,35 @@ indicating standard input is to be closed.
Note that
.Ar fd
is limited to a single digit in most shell implementations.
-.It \*(Gt& Ar fd
+.It \*(Gt& Ns Ar fd
Same as
.Ic \*(Lt& ,
except the operation is done on standard output.
-.It &\*(Gt Ar file
+.It &\*(Gt Ns Ar file
Same as
-.Ic \*(Gt Ar file 2\*(Gt&1 .
-This is a GNU
+.Ic \*(Gt Ns Ar file 2\*(Gt&1 .
+This is a deprecated (legacy) GNU
.Nm bash
extension supported by
.Nm
which also supports the preceding explicit fd number, for example,
-.Ic 3&\*(Gt Ar file
+.Ic 3&\*(Gt Ns Ar file
is the same as
-.Ic 3\*(Gt Ar file 2\*(Gt&3
+.Ic 3\*(Gt Ns Ar file 2\*(Gt&3
in
.Nm
but a syntax error in GNU
.Nm bash .
-Setting the
-.Fl o Ar posix
-or
-.Fl o Ar sh
-shell options disable parsing of this redirection;
-it's a compatibility feature to legacy scripts, to
-not be used when writing new shell code.
.It Xo
-.No &\*(Gt\*(Ba Ar file ,
-.No &\*(Gt\*(Gt Ar file ,
-.No &\*(Gt& Ar fd
+.No &\*(Gt\*(Ba Ns Ar file ,
+.No &\*(Gt\*(Gt Ns Ar file ,
+.No &\*(Gt& Ns Ar fd
.Xc
Same as
-.Ic \*(Gt\*(Ba Ar file ,
-.Ic \*(Gt\*(Gt Ar file ,
+.Ic \*(Gt\*(Ba Ns Ar file ,
+.Ic \*(Gt\*(Gt Ns Ar file ,
or
-.Ic \*(Gt& Ar fd ,
+.Ic \*(Gt& Ns Ar fd ,
followed by
.Ic 2\*(Gt&1 ,
as above.
@@ -2516,12 +2527,7 @@ will print an error with a line number prepended to it:
.Pp
.D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
.Pp
-File descriptors created by input/output redirections are private to the
-Korn shell, but passed to sub-processes if
-.Fl o Ic posix
-or
-.Fl o Ic sh
-is set.
+File descriptors created by I/O redirections are private to the shell.
.Ss Arithmetic expressions
Integer arithmetic expressions can be used with the
.Ic let
@@ -2597,12 +2603,8 @@ in all forms of arithmetic expressions, except as numeric arguments to the
built-in command.
Prefixing numbers with a sole digit zero
.Pq Sq 0
-leads to the shell interpreting it as base-8 (octal) integer in
-.Ic posix
-mode
-.Em only ;
-historically, (pd)ksh has never done so either anyway,
-and it's unsafe to do that, but POSIX demands it nowadays.
+does not cause interpretation as octal, as that's unsafe to do.
+.Pp
As a special
.Nm mksh
extension, numbers to the base of one are treated as either (8-bit
@@ -2626,7 +2628,9 @@ octet not forming a valid and minimal CESU-8 sequence is passed, the
behaviour is undefined (usually, the shell aborts with a parse error,
but rarely, it succeeds, e.g. on the sequence C2 20).
That's why you should always use ASCII mode unless you know that the
-input is well-formed UTF-8 in the range of 0000..FFFD.
+input is well-formed UTF-8 in the range of 0000..FFFD if you use this
+feature, as opposed to
+.Ic read Fl a .
.Pp
The operators are evaluated as follows:
.Bl -tag -width Ds -offset indent
@@ -2956,23 +2960,24 @@ Additional
.Nm
commands keeping assignments:
.Pp
-.Ic builtin , global , typeset , wait
+.Ic builtin , global , source , typeset ,
+.Ic wait
.Pp
Builtins that are not special:
.Pp
.Ic [ , alias , bg , bind ,
.Ic cat , cd , command , echo ,
.Ic false , fc , fg , getopts ,
-.Ic jobs , kill , let , mknod ,
-.Ic print , pwd , read , realpath ,
-.Ic rename , sleep , suspend , test ,
-.Ic true , ulimit , umask , unalias ,
-.Ic whence
+.Ic jobs , kill , let , print ,
+.Ic pwd , read , realpath , rename ,
+.Ic sleep , suspend , test , true ,
+.Ic ulimit , umask , unalias , whence
.Pp
Once the type of command has been determined, any command-line parameter
assignments are performed and exported for the duration of the command.
.Pp
-The following describes the special and regular built-in commands:
+The following describes the special and regular built-in commands and
+builtin-like reserved words:
.Pp
.Bl -tag -width false -compact
.It Ic \&. Ar file Op Ar arg ...
@@ -3649,7 +3654,7 @@ the parsing or evaluation of an expression, the exit status is greater than 1.
Since expressions may need to be quoted,
.No \&(( Ar expr No ))
is syntactic sugar for
-.No let \&" Ns Ar expr Ns \&" .
+.No "{ let '" Ns Ar expr Ns "'; }" .
.Pp
.It Ic let]
Internally used alias for
@@ -3687,10 +3692,6 @@ option),
and
.Ar minor
(minor device number).
-.Pp
-See
-.Xr mknod 8
-for further information.
This is not normally part of
.Nm mksh ;
however, distributors may have added this as builtin as a speed hack.
@@ -3826,7 +3827,8 @@ Store the result without word splitting into the parameter
.Ev REPLY )
as array of characters (wide characters if the
.Ic utf8\-mode
-option is enacted, octets otherwise).
+option is enacted, octets otherwise); the codepoints are
+encoded as decimal numbers by default.
.It Fl d Ar x
Use the first byte of
.Ar x ,
@@ -4149,6 +4151,12 @@ or
case-insensitively; for direct builtin calls depending on the
aforementioned environment variables; or for stdin or scripts,
if the input begins with a UTF-8 Byte Order Mark.
+.Pp
+In near future, locale tracking will be implemented, which means that
+.Ic set Fl +U
+is changed whenever one of the
+.Tn POSIX
+locale-related environment variables changes.
.It Fl u \*(Ba Fl o Ic nounset
Referencing of an unset parameter, other than
.Dq $@
@@ -4241,19 +4249,25 @@ commands above for more details.
Make the exit status of a pipeline (before logically complementing) the
rightmost non-zero errorlevel, or zero if all commands exited with zero.
.It Fl o Ic posix
-Enable a somewhat more
-.Px
-ish mode.
+Behave closer to the standards
+(see
+.Sx POSIX mode
+for details).
+Automatically enabled if the basename of the shell invocation begins with
+.Dq sh
+and this autodetection feature is compiled in
+.Pq not in MirBSD .
As a side effect, setting this flag turns off
.Ic braceexpand
mode, which can be turned back on manually, and
.Ic sh
-mode.
+mode (unless both are enabled at the same time).
.It Fl o Ic sh
Enable
.Pa /bin/sh
.Pq kludge
-mode.
+mode (see
+.Sx SH mode ) .
Automatically enabled if the basename of the shell invocation begins with
.Dq sh
and this autodetection feature is compiled in
@@ -4262,7 +4276,7 @@ As a side effect, setting this flag turns off
.Ic braceexpand
mode, which can be turned back on manually, and
.Ic posix
-mode.
+mode (unless both are enabled at the same time).
.It Fl o Ic vi
Enable
.Xr vi 1 Ns -like
@@ -4332,16 +4346,9 @@ Signal delivery may continue execution earlier.
Like
.Ic \&. Po Do dot Dc Pc ,
except that the current working directory is appended to the
-.Ev PATH
-in GNU
+search path (GNU
.Nm bash
-and
-.Nm mksh .
-In
-.Nm ksh93
-and
-.Nm mksh ,
-this is implemented as a shell alias instead of a builtin.
+extension).
.Pp
.It Ic suspend
Stops the shell as if it had received the suspend character from
@@ -5301,6 +5308,69 @@ If another attempt
is immediately made to exit the shell, the running jobs are sent a
.Dv SIGHUP
signal and the shell exits.
+.Ss POSIX mode
+Entering
+.Ic set Fl o Ic posix
+mode will cause
+.Nm
+to behave even more
+.Tn POSIX
+compliant in places where the defaults or opinions differ.
+Note that
+.Nm mksh
+will still operate with unsigned 32-bit arithmetics; use
+.Nm lksh
+if arithmetics on the host
+.Vt long
+data type, complete with ISO C Undefined Behaviour, are required;
+refer to the
+.Xr lksh 1
+manual page for details.
+Most other historic,
+.At
+.Nm ksh Ns -compatible ,
+or opinionated differences can be disabled by using this mode; these are:
+.Bl -bullet
+.It
+The GNU
+.Nm bash
+I/O redirection
+.Ic &\*(Gt Ns Ar file
+is no longer supported.
+.It
+File descriptors created by I/O redirections are inherited by
+child processes.
+.It
+Numbers with a leading digit zero are interpreted as octal.
+.It
+The
+.Nm echo
+builtin does not interpret backslashes and only supports the exact option
+.Dq Fl n .
+.It
+\&... (list is incomplete and may change for R53)
+.El
+.Ss SH mode
+Compatibility mode; intended for use with legacy scripts that
+cannot easily be fixed; the changes are as follows:
+.Bl -bullet
+.It
+The GNU
+.Nm bash
+I/O redirection
+.Ic &\*(Gt Ns Ar file
+is no longer supported.
+.It
+File descriptors created by I/O redirections are inherited by
+child processes.
+.It
+The
+.Nm echo
+builtin does not interpret backslashes and only supports the exact option
+.Dq Fl n .
+.It
+\&... (list is incomplete and may change for R53)
+.El
.Ss Interactive input line editing
The shell supports three modes of reading command lines from a
.Xr tty 4
@@ -6303,6 +6373,7 @@ contains the system and suid profile.
.Xr cat 1 ,
.Xr ed 1 ,
.Xr getopt 1 ,
+.Xr lksh 1 ,
.Xr sed 1 ,
.Xr sh 1 ,
.Xr stty 1 ,
@@ -6328,8 +6399,6 @@ contains the system and suid profile.
.Xr utf\-8 7 ,
.Xr mknod 8
.Pp
-.Pa http://docsrv.sco.com:507/en/man/html.C/sh.C.html
-.Pp
.Pa https://www.mirbsd.org/ksh\-chan.htm
.Rs
.%A Morris Bolsky
@@ -6396,8 +6465,8 @@ contains the system and suid profile.
.An -nosplit
.Nm "The MirBSD Korn Shell"
is developed by
-.An Thorsten Glaser Aq tg@mirbsd.org
-and currently maintained as part of The MirOS Project.
+.An mirabilos Aq Mt m@mirbsd.org
+as part of The MirOS Project.
This shell is based on the public domain 7th edition Bourne shell clone by
.An Charles Forsyth ,
who kindly agreed to, in countries where the Public Domain status of the work
@@ -6416,10 +6485,10 @@ The first release of
was created by
.An Eric Gisin ,
and it was subsequently maintained by
-.An John R. MacMillan Aq Mt change!john@sq.sq.com ,
-.An Simon J. Gerraty Aq Mt sjg@zen.void.oz.au ,
+.An John R. MacMillan ,
+.An Simon J. Gerraty ,
and
-.An Michael Rendell Aq Mt michael@cs.mun.ca .
+.An Michael Rendell .
The effort of several projects, such as Debian and OpenBSD, and other
contributors including our users, to improve the shell is appreciated.
See the documentation, CVS, and web site for details.
@@ -6429,10 +6498,11 @@ The complete legalese is at:
.Pa https://www.mirbsd.org/TaC\-mksh.txt
.\"
.\" This boils down to: feel free to use mksh.ico as application icon
-.\" or shortcut for mksh or mksh/Win32; distro patches are ok (but we
-.\" request they amend $KSH_VERSION when modifying mksh). Authors are
-.\" Marshall Kirk McKusick (UCB), Rick Collette (ekkoBSD), Thorsten
-.\" Glaser, Benny Siegert (MirBSD), Michael Langguth (mksh/Win32).
+.\" or shortcut for mksh or mksh/Win32 or OS/2; distro patches are ok
+.\" (but we request they amend $KSH_VERSION when modifying mksh).
+.\" Authors are Marshall Kirk McKusick (UCB), Rick Collette (ekkoBSD),
+.\" mirabilos, Benny Siegert (MirBSD), Michael Langguth (mksh/Win32),
+.\" KO Myung-Hun (mksh for OS/2).
.\"
.\" As far as MirBSD is concerned, the files themselves are free
.\" to modification and distribution under BSD/MirOS Licence, the
@@ -6461,23 +6531,16 @@ foo \*(Ba bar \*(Ba& read \-p baz # will, however, do so
.Nm mksh
provides a consistent set of 32-bit integer arithmetics, both signed
and unsigned, with defined wraparound and sign of the result of a
-remainder operation, even (defying POSIX) on 64-bit systems.
-If you require 64-bit integer arithmetics, use
-.Nm lksh Pq legacy mksh
-instead, but be aware that, in POSIX, it's legal for the OS to make
-.Li print $((2147483647 + 1))
-delete all files on your system, as it's Undefined Behaviour.
+remainder operation, even (defying POSIX) on 36-bit and 64-bit systems.
.Pp
.Nm mksh
provides a consistent, clear interface normally.
-This may deviate from POSIX in optional or opinionated places, such
-as whether leading-digit-zero numbers should be interpreted as octal.
+This may deviate from POSIX in historic or opinionated places.
.Ic set Fl o Ic posix
-will cause the shell (either
-.Nm mksh
-or
-.Nm lksh )
-to behave more like the standard expects.
+(see
+.Sx POSIX mode
+for details)
+will cause the shell to behave more conformant.
.Pp
For the purpose of
.Tn POSIX ,
@@ -6508,6 +6571,7 @@ case ${KSH_VERSION:\-} in
esac ;;
esac
.Ed
+In near future, (Unicode) locale tracking will be implemented though.
.Sh BUGS
Suspending (using \*(haZ) pipelines like the one below will only suspend
the currently running part of the pipeline; in this example,
@@ -6530,8 +6594,20 @@ when multiple shells are accessing the file; the rollover process
for the in-memory portion of the history is slow, should use
.Xr memmove 3 .
.Pp
+Handling of backslash plus double-quote inside the (deprecated)
+.Pf \` Ns Ar command Ns \`
+form of command substitution when the substitution itself is
+also inside double quotes currently deliberately violates
+.Tn POSIX
+even in
+.Fl o Ic posix
+mode until Austin group bug 1015 has been resolved either way,
+as the current wording of the standard prohibits the current
+and historic practice of several shells which several scripts
+(admittedly wrongly) depend on.
+.Pp
This document attempts to describe
-.Nm mksh\ R51
+.Nm mksh\ R52b
and up,
.\" with vendor patches from insert-your-name-here,
compiled without any options impacting functionality, such as
@@ -6550,7 +6626,7 @@ Please report bugs in
to the
.Mx
mailing list at
-.Aq miros\-mksh@mirbsd.org
+.Aq Mt miros\-mksh@mirbsd.org
or in the
.Li \&#\&!/bin/mksh
.Pq or Li \&#ksh
diff --git a/src/rlimits.gen b/src/rlimits.gen
index ddb4cc8..96f5eff 100644
--- a/src/rlimits.gen
+++ b/src/rlimits.gen
@@ -1,6 +1,27 @@
+/* +++ GENERATED FILE +++ DO NOT EDIT +++ */
+/*-
+ * Copyright (c) 2013, 2015
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
#ifndef RLIMITS_OPTCS
#if defined(RLIMITS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.2 2015/05/01 23:16:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.3 2015/12/12 21:08:44 tg Exp $");
#elif defined(RLIMITS_ITEMS)
#define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid),
#endif
diff --git a/src/rlimits.opt b/src/rlimits.opt
index 3759da8..4f933ab 100644
--- a/src/rlimits.opt
+++ b/src/rlimits.opt
@@ -1,5 +1,25 @@
+/*-
+ * Copyright (c) 2013, 2015
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
@RLIMITS_DEFNS
-__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.2 2015/05/01 23:16:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/rlimits.opt,v 1.3 2015/12/12 21:08:44 tg Exp $");
@RLIMITS_ITEMS
#define FN(lname,lid,lfac,lopt) (const struct limits *)(&rlimits_ ## lid),
@@
diff --git a/src/sh.h b/src/sh.h
index c3109e5..239cc23 100644
--- a/src/sh.h
+++ b/src/sh.h
@@ -1,8 +1,8 @@
-/* $OpenBSD: sh.h,v 1.33 2013/12/18 13:53:12 millert Exp $ */
+/* $OpenBSD: sh.h,v 1.35 2015/09/10 22:48:58 nicm Exp $ */
/* $OpenBSD: shf.h,v 1.6 2005/12/11 18:53:51 deraadt Exp $ */
/* $OpenBSD: table.h,v 1.8 2012/02/19 07:52:30 otto Exp $ */
/* $OpenBSD: tree.h,v 1.10 2005/03/28 21:28:22 deraadt Exp $ */
-/* $OpenBSD: expand.h,v 1.6 2005/03/30 17:16:37 deraadt Exp $ */
+/* $OpenBSD: expand.h,v 1.7 2015/09/01 13:12:31 tedu Exp $ */
/* $OpenBSD: lex.h,v 1.13 2013/03/03 19:11:34 guenther Exp $ */
/* $OpenBSD: proto.h,v 1.35 2013/09/04 15:49:19 millert Exp $ */
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
@@ -10,8 +10,8 @@
/*-
* Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -108,6 +108,9 @@
#if HAVE_VALUES_H
#include <values.h>
#endif
+#ifdef MIRBSD_BOOTFLOPPY
+#include <wchar.h>
+#endif
#undef __attribute__
#if HAVE_ATTRIBUTE_BOUNDED
@@ -172,9 +175,9 @@
#endif
#ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.739 2015/07/10 19:36:37 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.757 2016/01/20 21:34:13 tg Exp $");
#endif
-#define MKSH_VERSION "R51 2015/07/10"
+#define MKSH_VERSION "R52 2016/01/20"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
@@ -337,15 +340,15 @@ struct rusage {
/* determine ksh_NSIG: first, use the traditional definitions */
#undef ksh_NSIG
#if defined(NSIG)
-#define ksh_NSIG NSIG
+#define ksh_NSIG (NSIG)
#elif defined(_NSIG)
-#define ksh_NSIG _NSIG
+#define ksh_NSIG (_NSIG)
#elif defined(SIGMAX)
#define ksh_NSIG (SIGMAX + 1)
#elif defined(_SIGMAX)
#define ksh_NSIG (_SIGMAX + 1)
#elif defined(NSIG_MAX)
-#define ksh_NSIG NSIG_MAX
+#define ksh_NSIG (NSIG_MAX)
#else
# error Please have your platform define NSIG.
#endif
@@ -367,7 +370,7 @@ struct rusage {
#else
/* since it’s usable, prefer it */
#undef ksh_NSIG
-#define ksh_NSIG NSIG_MAX
+#define ksh_NSIG (NSIG_MAX)
#endif
/* if NSIG_MAX is now still defined, use sysconf(_SC_NSIG) at runtime */
#endif
@@ -376,6 +379,8 @@ struct rusage {
#define ksh_NSIG 64
#endif
+#define ksh_sigmask(sig) (((sig) < 1 || (sig) > 127) ? 255 : 128 + (sig))
+
/* OS-dependent additions (functions, variables, by OS) */
@@ -573,7 +578,7 @@ char *ucstrstr(char *, const char *);
#define mkssert(e) do { } while (/* CONSTCOND */ 0)
#endif
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 511)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 521)
#error Must run Build.sh to compile this.
extern void thiswillneverbedefinedIhope(void);
int
@@ -859,6 +864,8 @@ EXTERN const char Tgbuiltin[] E_INIT("=builtin");
#define Tbuiltin (Tgbuiltin + 1) /* "builtin" */
EXTERN const char T_function[] E_INIT(" function");
#define Tfunction (T_function + 1) /* "function" */
+EXTERN const char T_funny_command[] E_INIT("funny $() command");
+#define Tcommand (T_funny_command + 10) /* "command" */
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
#define TC_IFSWS (TC_LEX1 + 7) /* space tab newline */
@@ -1026,7 +1033,7 @@ EXTERN Getopt user_opt; /* parsing state for getopts builtin command */
/* This for co-processes */
/* something that won't (realisticly) wrap */
-typedef int32_t Coproc_id;
+typedef int Coproc_id;
struct coproc {
void *job; /* 0 or job of co-process using input pipe */
@@ -1045,7 +1052,7 @@ EXTERN sigset_t sm_default, sm_sigchld;
/* name of called builtin function (used by error functions) */
EXTERN const char *builtin_argv0;
-/* is called builtin SPEC_BI? */
+/* is called builtin SPEC_BI? (also KEEPASN, odd use though) */
EXTERN bool builtin_spec;
/* current working directory */
@@ -1070,12 +1077,8 @@ EXTERN mksh_ari_t x_lins E_INIT(24); /* tty lines */
/* Determine the location of the system (common) profile */
#ifndef MKSH_DEFAULT_PROFILEDIR
-#if defined(ANDROID)
-#define MKSH_DEFAULT_PROFILEDIR "/system/etc"
-#else
#define MKSH_DEFAULT_PROFILEDIR "/etc"
#endif
-#endif
#define MKSH_SYSTEM_PROFILE MKSH_DEFAULT_PROFILEDIR "/profile"
#define MKSH_SUID_PROFILE MKSH_DEFAULT_PROFILEDIR "/suid_profile"
@@ -1187,6 +1190,8 @@ struct tbl {
};
EXTERN struct tbl vtemp;
+/* set by global() and local() */
+EXTERN bool last_lookup_was_array;
/* common flag bits */
#define ALLOC BIT(0) /* val.s has been allocated */
@@ -1396,7 +1401,7 @@ struct op {
* IO redirection
*/
struct ioword {
- char *name; /* filename (unused if heredoc) */
+ char *ioname; /* filename (unused if heredoc) */
char *delim; /* delimiter for <<, <<- */
char *heredoc; /* content of heredoc */
unsigned short ioflag; /* action (below) */
@@ -1452,6 +1457,7 @@ struct ioword {
#define DOTCOMEXEC BIT(11) /* not an eval flag, used by sh -c hack */
#define DOSCALAR BIT(12) /* change field handling to non-list context */
#define DOHEREDOC BIT(13) /* change scalar handling to heredoc body */
+#define DOHERESTR BIT(14) /* append a newline char */
#define X_EXTRA 20 /* this many extra bytes in X string */
@@ -1628,12 +1634,12 @@ typedef union {
#define ALIAS BIT(2) /* recognise alias */
#define KEYWORD BIT(3) /* recognise keywords */
#define LETEXPR BIT(4) /* get expression inside (( )) */
-#define VARASN BIT(5) /* check for var=word */
-#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */
+#define CMDASN BIT(5) /* parse x[1 & 2] as one word, for typeset */
+#define HEREDOC BIT(6) /* parsing a here document body */
#define ESACONLY BIT(7) /* only accept esac keyword */
-#define HEREDELIM BIT(8) /* parsing <<,<<- delimiter */
-#define LQCHAR BIT(9) /* source string contains QCHAR */
-#define HEREDOC BIT(10) /* parsing a here document body */
+#define CMDWORD BIT(8) /* parsing simple command (alias related) */
+#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
+#define LQCHAR BIT(10) /* source string contains QCHAR */
#define HERES 10 /* max number of << in line */
@@ -1715,6 +1721,7 @@ int define(const char *, struct op *);
const char *builtin(const char *, int (*)(const char **));
struct tbl *findcom(const char *, int);
void flushcom(bool);
+int search_access(const char *, int);
const char *search_path(const char *, const char *, int, int *);
void pr_menu(const char * const *);
void pr_list(char * const *);
@@ -1728,7 +1735,11 @@ int utf_widthadj(const char *, const char **);
size_t utf_mbswidth(const char *) MKSH_A_PURE;
const char *utf_skipcols(const char *, int) MKSH_A_PURE;
size_t utf_ptradj(const char *) MKSH_A_PURE;
+#ifdef MIRBSD_BOOTFLOPPY
+#define utf_wcwidth(i) wcwidth((wchar_t)(i))
+#else
int utf_wcwidth(unsigned int) MKSH_A_PURE;
+#endif
int ksh_access(const char *, int);
struct tbl *tempvar(void);
/* funcs.c */
@@ -1979,7 +1990,7 @@ char *shf_smprintf(const char *, ...)
ssize_t shf_vfprintf(struct shf *, const char *, va_list)
MKSH_A_FORMAT(__printf__, 2, 0);
/* syn.c */
-int assign_command(const char *);
+int assign_command(const char *, bool);
void initkeywords(void);
struct op *compile(Source *, bool);
bool parse_usec(const char *, struct timeval *);
@@ -1992,8 +2003,6 @@ struct op *tcopy(struct op *, Area *);
char *wdcopy(const char *, Area *);
const char *wdscan(const char *, int);
#define WDS_TPUTS BIT(0) /* tputS (dumpwdvar) mode */
-#define WDS_KEEPQ BIT(1) /* keep quote characters */
-#define WDS_MAGIC BIT(2) /* make MAGIC */
char *wdstrip(const char *, int);
void tfree(struct op *, Area *);
void dumpchar(struct shf *, int);
diff --git a/src/sh_flags.gen b/src/sh_flags.gen
index 7cd0882..bcbc729 100644
--- a/src/sh_flags.gen
+++ b/src/sh_flags.gen
@@ -1,6 +1,27 @@
+/* +++ GENERATED FILE +++ DO NOT EDIT +++ */
+/*-
+ * Copyright (c) 2013, 2014, 2015
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
#ifndef SHFLAGS_OPTCS
#if defined(SHFLAGS_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.3 2015/05/01 23:16:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.4 2015/12/12 21:08:44 tg Exp $");
#elif defined(SHFLAGS_ENUMS)
#define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0,
diff --git a/src/sh_flags.opt b/src/sh_flags.opt
index 1d592c5..9f364d5 100644
--- a/src/sh_flags.opt
+++ b/src/sh_flags.opt
@@ -1,5 +1,25 @@
+/*-
+ * Copyright (c) 2013, 2014, 2015
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
@SHFLAGS_DEFNS
-__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.3 2015/05/01 23:16:31 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh_flags.opt,v 1.4 2015/12/12 21:08:44 tg Exp $");
@SHFLAGS_ENUMS
#define FN(sname,cname,flags,ochar) cname,
#define F0(sname,cname,flags,ochar) cname = 0,
diff --git a/src/shf.c b/src/shf.c
index 1c9e3d5..3b63c7b 100644
--- a/src/shf.c
+++ b/src/shf.c
@@ -3,7 +3,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
* 2012, 2013, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -25,7 +25,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.66 2015/07/09 20:52:43 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.69 2015/12/31 20:38:59 tg Exp $");
/* flags to shf_emptybuf() */
#define EB_READSW 0x01 /* about to switch to reading */
@@ -1099,14 +1099,10 @@ cstrerror(int errnum)
switch (errnum) {
case 0:
return ("Undefined error: 0");
-#ifdef EPERM
case EPERM:
return ("Operation not permitted");
-#endif
-#ifdef ENOENT
case ENOENT:
return ("No such file or directory");
-#endif
#ifdef ESRCH
case ESRCH:
return ("No such process");
@@ -1115,22 +1111,20 @@ cstrerror(int errnum)
case E2BIG:
return ("Argument list too long");
#endif
-#ifdef ENOEXEC
case ENOEXEC:
return ("Exec format error");
-#endif
+ case EBADF:
+ return ("Bad file descriptor");
#ifdef ENOMEM
case ENOMEM:
return ("Cannot allocate memory");
#endif
-#ifdef EACCES
case EACCES:
return ("Permission denied");
-#endif
-#ifdef ENOTDIR
+ case EEXIST:
+ return ("File exists");
case ENOTDIR:
return ("Not a directory");
-#endif
#ifdef EINVAL
case EINVAL:
return ("Invalid argument");
diff --git a/src/strlcpy.c b/src/strlcpy.c
index c0ebfd5..ba8581e 100644
--- a/src/strlcpy.c
+++ b/src/strlcpy.c
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2006, 2008, 2009, 2013
- * Thorsten Glaser <tg@mirbsd.org>
+ * mirabilos <m@mirbsd.org>
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
@@ -18,7 +18,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/strlcpy.c,v 1.8 2013/11/05 22:10:15 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/strlcpy.c,v 1.10 2015/11/29 17:05:02 tg Exp $");
/*
* Copy src to string dst of size siz. At most siz-1 characters
diff --git a/src/syn.c b/src/syn.c
index dafeda9..ab32418 100644
--- a/src/syn.c
+++ b/src/syn.c
@@ -1,9 +1,9 @@
-/* $OpenBSD: syn.c,v 1.29 2013/06/03 18:40:05 jca Exp $ */
+/* $OpenBSD: syn.c,v 1.30 2015/09/01 13:12:31 tedu Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- * 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.101 2015/04/29 20:07:35 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.109 2016/01/19 23:12:15 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
@@ -172,6 +172,8 @@ c_list(bool multi)
return (t);
}
+static const char IONDELIM_delim[] = { CHAR, '<', CHAR, '<', EOS };
+
static struct ioword *
synio(int cf)
{
@@ -189,33 +191,41 @@ synio(int cf)
return (NULL);
ACCEPT;
iop = yylval.iop;
- if (iop->ioflag & IONDELIM)
- goto gotnulldelim;
ishere = (iop->ioflag & IOTYPE) == IOHERE;
- musthave(LWORD, ishere ? HEREDELIM : 0);
+ if (iop->ioflag & IOHERESTR) {
+ musthave(LWORD, 0);
+ } else if (ishere && tpeek(HEREDELIM) == '\n') {
+ ACCEPT;
+ yylval.cp = wdcopy(IONDELIM_delim, ATEMP);
+ iop->ioflag |= IOEVAL | IONDELIM;
+ } else
+ musthave(LWORD, ishere ? HEREDELIM : 0);
if (ishere) {
iop->delim = yylval.cp;
- if (*ident != 0) {
+ if (*ident != 0 && !(iop->ioflag & IOHERESTR)) {
/* unquoted */
- gotnulldelim:
iop->ioflag |= IOEVAL;
}
if (herep > &heres[HERES - 1])
yyerror("too many %ss\n", "<<");
*herep++ = iop;
} else
- iop->name = yylval.cp;
+ iop->ioname = yylval.cp;
if (iop->ioflag & IOBASH) {
char *cp;
nextiop = alloc(sizeof(*iop), ATEMP);
- nextiop->name = cp = alloc(5, ATEMP);
+#ifdef MKSH_CONSERVATIVE_FDS
+ nextiop->ioname = cp = alloc(3, ATEMP);
+#else
+ nextiop->ioname = cp = alloc(5, ATEMP);
if (iop->unit > 9) {
*cp++ = CHAR;
*cp++ = digits_lc[iop->unit / 10];
}
+#endif
*cp++ = CHAR;
*cp++ = digits_lc[iop->unit % 10];
*cp = EOS;
@@ -262,7 +272,6 @@ get_command(int cf)
int c, iopn = 0, syniocf, lno;
struct ioword *iop, **iops;
XPtrV args, vars;
- char *tcp;
struct nesting_state old_nesting;
/* NUFILE is small enough to leave this addition unchecked */
@@ -271,7 +280,7 @@ get_command(int cf)
XPinit(vars, 16);
syniocf = KEYWORD|sALIAS;
- switch (c = token(cf|KEYWORD|sALIAS|VARASN)) {
+ switch (c = token(cf|KEYWORD|sALIAS|CMDASN)) {
default:
REJECT;
afree(iops, ATEMP);
@@ -286,9 +295,18 @@ get_command(int cf)
syniocf &= ~(KEYWORD|sALIAS);
t = newtp(TCOM);
t->lineno = source->line;
+ goto get_command_begin;
while (/* CONSTCOND */ 1) {
- cf = (t->u.evalflags ? ARRAYVAR : 0) |
- (XPsize(args) == 0 ? sALIAS|VARASN : 0);
+ bool check_assign_cmd;
+
+ if (XPsize(args) == 0) {
+ get_command_begin:
+ check_assign_cmd = true;
+ cf = sALIAS | CMDASN;
+ } else if (t->u.evalflags)
+ cf = CMDWORD | CMDASN;
+ else
+ cf = CMDWORD;
switch (tpeek(cf)) {
case REDIR:
while ((iop = synio(cf)) != NULL) {
@@ -306,9 +324,12 @@ get_command(int cf)
* dubious but AT&T ksh acts this way
*/
if (iopn == 0 && XPsize(vars) == 0 &&
- XPsize(args) == 0 &&
- assign_command(ident))
- t->u.evalflags = DOVACHECK;
+ check_assign_cmd) {
+ if (assign_command(ident, false))
+ t->u.evalflags = DOVACHECK;
+ else if (strcmp(ident, Tcommand) != 0)
+ check_assign_cmd = false;
+ }
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
is_wdvarassign(yylval.cp))
XPput(vars, yylval.cp);
@@ -319,6 +340,8 @@ get_command(int cf)
case '(' /*)*/:
if (XPsize(args) == 0 && XPsize(vars) == 1 &&
is_wdvarassign(yylval.cp)) {
+ char *tcp;
+
/* wdarrassign: foo=(bar) */
ACCEPT;
@@ -390,6 +413,7 @@ get_command(int cf)
case LWORD:
break;
case '(': /*)*/
+ c = '(';
goto Subshell;
default:
syntaxerr(NULL);
@@ -421,7 +445,7 @@ get_command(int cf)
case FOR:
case SELECT:
t = newtp((c == FOR) ? TFOR : TSELECT);
- musthave(LWORD, ARRAYVAR);
+ musthave(LWORD, CMDASN);
if (!is_wdvarname(yylval.cp, true))
yyerror("%s: %s\n", c == FOR ? "for" : Tselect,
"bad identifier");
@@ -510,6 +534,12 @@ get_command(int cf)
XPfree(vars);
}
+ if (c == MDPAREN) {
+ t = block(TBRACE, t, NULL);
+ t->ioact = t->left->ioact;
+ t->left->ioact = NULL;
+ }
+
return (t);
}
@@ -556,7 +586,7 @@ elsepart(void)
{
struct op *t;
- switch (token(KEYWORD|sALIAS|VARASN)) {
+ switch (token(KEYWORD|sALIAS|CMDASN)) {
case ELSE:
if ((t = c_list(true)) == NULL)
syntaxerr(NULL);
@@ -822,8 +852,8 @@ initkeywords(void)
static void
syntaxerr(const char *what)
{
- /* 2<<- is the longest redirection, I think */
- char redir[6];
+ /* 23<<- is the longest redirection, I think */
+ char redir[8];
const char *s;
struct tokeninfo const *tt;
int c;
@@ -927,13 +957,14 @@ compile(Source *s, bool skiputf8bom)
* $
*/
int
-assign_command(const char *s)
+assign_command(const char *s, bool docommand)
{
if (!*s)
return (0);
return ((strcmp(s, Talias) == 0) ||
(strcmp(s, Texport) == 0) ||
(strcmp(s, Treadonly) == 0) ||
+ (docommand && (strcmp(s, Tcommand) == 0)) ||
(strcmp(s, Ttypeset) == 0));
}
@@ -975,7 +1006,7 @@ static const char db_gthan[] = { CHAR, '>', EOS };
static Test_op
dbtestp_isa(Test_env *te, Test_meta meta)
{
- int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
+ int c = tpeek(CMDASN | (meta == TM_BINOP ? 0 : CONTIN));
bool uqword;
char *save = NULL;
Test_op ret = TO_NONOP;
@@ -1021,7 +1052,7 @@ static const char *
dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
bool do_eval MKSH_A_UNUSED)
{
- int c = tpeek(ARRAYVAR);
+ int c = tpeek(CMDASN);
if (c != LWORD)
return (NULL);
diff --git a/src/tree.c b/src/tree.c
index c057559..7a7df5d 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -1,9 +1,9 @@
-/* $OpenBSD: tree.c,v 1.20 2012/06/27 07:17:19 otto Exp $ */
+/* $OpenBSD: tree.c,v 1.21 2015/09/01 13:12:31 tedu Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.73 2015/04/11 22:03:32 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.80 2016/01/14 22:30:43 tg Exp $");
#define INDENT 8
@@ -226,7 +226,6 @@ ptree(struct op *t, int indent, struct shf *shf)
shf_putc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
- iop->ioflag & IONDELIM ? "<<" :
evalstr(iop->delim, 0));
need_nl = true;
}
@@ -265,6 +264,8 @@ pioact(struct shf *shf, struct ioword *iop)
shf_puts("<<", shf);
if (flag & IOSKIP)
shf_putc('-', shf);
+ else if (flag & IOHERESTR)
+ shf_putc('<', shf);
break;
case IOCAT:
shf_puts(">>", shf);
@@ -283,17 +284,15 @@ pioact(struct shf *shf, struct ioword *iop)
}
/* name/delim are NULL when printing syntax errors */
if (type == IOHERE) {
- if (iop->delim)
+ if (iop->delim && !(iop->ioflag & IONDELIM))
wdvarput(shf, iop->delim, 0, WDS_TPUTS);
- if (flag & IOHERESTR)
- shf_putc(' ', shf);
- } else if (iop->name) {
+ } else if (iop->ioname) {
if (flag & IONAMEXP)
- print_value_quoted(shf, iop->name);
+ print_value_quoted(shf, iop->ioname);
else
- wdvarput(shf, iop->name, 0, WDS_TPUTS);
- shf_putc(' ', shf);
+ wdvarput(shf, iop->ioname, 0, WDS_TPUTS);
}
+ shf_putc(' ', shf);
prevent_semicolon = false;
}
@@ -309,7 +308,7 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
* `...` -> $(...)
* 'foo' -> "foo"
* x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
- * x${foo:-'hi'} -> x${foo:-hi} unless WDS_KEEPQ
+ * x${foo:-'hi'} -> x${foo:-hi}
* could change encoding to:
* OQUOTE ["'] ... CQUOTE ["']
* COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
@@ -319,12 +318,12 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
case EOS:
return (--wp);
case ADELIM:
+ if (*wp == /*{*/'}') {
+ ++wp;
+ goto wdvarput_csubst;
+ }
case CHAR:
c = *wp++;
- if ((opmode & WDS_MAGIC) &&
- (ISMAGIC(c) || c == '[' || c == '!' ||
- c == '-' || c == ']' || c == '*' || c == '?'))
- shf_putc(MAGIC, shf);
shf_putc(c, shf);
break;
case QCHAR: {
@@ -336,8 +335,7 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
if (quotelevel == 0)
doq = true;
} else {
- if (!(opmode & WDS_KEEPQ))
- doq = false;
+ doq = false;
}
if (doq)
shf_putc('\\', shf);
@@ -389,25 +387,20 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
wp = wdvarput(shf, wp, 0, opmode);
break;
case CSUBST:
- if (*wp++ == '}')
+ if (*wp++ == '}') {
+ wdvarput_csubst:
shf_putc('}', shf);
+ }
return (wp);
case OPAT:
- if (opmode & WDS_MAGIC) {
- shf_putc(MAGIC, shf);
- shf_putchar(*wp++ | 0x80, shf);
- } else {
- shf_putchar(*wp++, shf);
- shf_putc('(', shf);
- }
+ shf_putchar(*wp++, shf);
+ shf_putc('(', shf);
break;
case SPAT:
c = '|';
if (0)
case CPAT:
c = /*(*/ ')';
- if (opmode & WDS_MAGIC)
- shf_putc(MAGIC, shf);
shf_putc(c, shf);
break;
}
@@ -594,8 +587,10 @@ wdscan(const char *wp, int c)
case EOS:
return (wp);
case ADELIM:
- if (c == ADELIM)
+ if (c == ADELIM && nest == 0)
return (wp + 1);
+ if (*wp == /*{*/'}')
+ goto wdscan_csubst;
/* FALLTHROUGH */
case CHAR:
case QCHAR:
@@ -617,6 +612,7 @@ wdscan(const char *wp, int c)
;
break;
case CSUBST:
+ wdscan_csubst:
wp++;
if (c == CSUBST && nest == 0)
return (wp);
@@ -673,8 +669,8 @@ iocopy(struct ioword **iow, Area *ap)
q = alloc(sizeof(struct ioword), ap);
ior[i] = q;
*q = *p;
- if (p->name != NULL)
- q->name = wdcopy(p->name, ap);
+ if (p->ioname != NULL)
+ q->ioname = wdcopy(p->ioname, ap);
if (p->delim != NULL)
q->delim = wdcopy(p->delim, ap);
if (p->heredoc != NULL)
@@ -696,8 +692,7 @@ tfree(struct op *t, Area *ap)
if (t == NULL)
return;
- if (t->str != NULL)
- afree(t->str, ap);
+ afree(t->str, ap);
if (t->vars != NULL) {
for (w = t->vars; *w != NULL; w++)
@@ -732,12 +727,9 @@ iofree(struct ioword **iow, Area *ap)
iop = iow;
while ((p = *iop++) != NULL) {
- if (p->name != NULL)
- afree(p->name, ap);
- if (p->delim != NULL)
- afree(p->delim, ap);
- if (p->heredoc != NULL)
- afree(p->heredoc, ap);
+ afree(p->ioname, ap);
+ afree(p->delim, ap);
+ afree(p->heredoc, ap);
afree(p, ap);
}
afree(iow, ap);
@@ -748,6 +740,8 @@ fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
{
if (isksh)
fptreef(shf, i, "%s %s %T", Tfunction, k, v);
+ else if (ktsearch(&keywords, k, hash(k)))
+ fptreef(shf, i, "%s %s() %T", Tfunction, k, v);
else
fptreef(shf, i, "%s() %T", k, v);
}
@@ -822,6 +816,10 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
shf_puts("EOS", shf);
return (--wp);
case ADELIM:
+ if (*wp == /*{*/'}') {
+ shf_puts("]ADELIM(})", shf);
+ return (wp + 1);
+ }
shf_puts("ADELIM=", shf);
if (0)
case CHAR:
@@ -934,18 +932,18 @@ dumpioact(struct shf *shf, struct op *t)
DB(IOHERESTR)
DB(IONDELIM)
shf_fprintf(shf, ",unit=%d", (int)iop->unit);
- if (iop->delim) {
+ if (iop->delim && !(iop->ioflag & IONDELIM)) {
shf_puts(",delim<", shf);
dumpwdvar(shf, iop->delim);
shf_putc('>', shf);
}
- if (iop->name) {
+ if (iop->ioname) {
if (iop->ioflag & IONAMEXP) {
shf_puts(",name=", shf);
- print_value_quoted(shf, iop->name);
+ print_value_quoted(shf, iop->ioname);
} else {
shf_puts(",name<", shf);
- dumpwdvar(shf, iop->name);
+ dumpwdvar(shf, iop->ioname);
shf_putc('>', shf);
}
}
diff --git a/src/var.c b/src/var.c
index 428192c..d816eb1 100644
--- a/src/var.c
+++ b/src/var.c
@@ -1,9 +1,9 @@
-/* $OpenBSD: var.c,v 1.41 2015/04/17 17:20:41 deraadt Exp $ */
+/* $OpenBSD: var.c,v 1.44 2015/09/10 11:37:42 jca Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014, 2015
- * Thorsten Glaser <tg@mirbsd.org>
+ * 2011, 2012, 2013, 2014, 2015, 2016
+ * mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
* are retained or reproduced in an accompanying document, permission
@@ -28,7 +28,7 @@
#include <sys/sysctl.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.193 2015/07/10 19:36:38 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.197 2016/01/14 22:49:33 tg Exp $");
/*-
* Variables
@@ -218,14 +218,16 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp)
return (n);
}
+#define vn vname.ro
/*
* Search for variable, if not found create globally.
*/
struct tbl *
global(const char *n)
{
- struct block *l = e->loc;
struct tbl *vp;
+ union mksh_cchack vname;
+ struct block *l = e->loc;
int c;
bool array;
uint32_t h, val;
@@ -234,9 +236,9 @@ global(const char *n)
* check to see if this is an array;
* dereference namerefs; must come first
*/
- n = array_index_calc(n, &array, &val);
- h = hash(n);
- c = (unsigned char)n[0];
+ vn = array_index_calc(n, &array, &val);
+ h = hash(vn);
+ c = (unsigned char)vn[0];
if (!ksh_isalphx(c)) {
if (array)
errorf("bad substitution");
@@ -246,15 +248,15 @@ global(const char *n)
vp->areap = ATEMP;
*vp->name = c;
if (ksh_isdigit(c)) {
- if (getn(n, &c) && (c <= l->argc))
+ if (getn(vn, &c) && (c <= l->argc))
/* setstr can't fail here */
setstr(vp, l->argv[c], KSH_RETURN_ERROR);
vp->flag |= RDONLY;
- return (vp);
+ goto out;
}
vp->flag |= RDONLY;
- if (n[1] != '\0')
- return (vp);
+ if (vn[1] != '\0')
+ goto out;
vp->flag |= ISSET|INTEGER;
switch (c) {
case '$':
@@ -278,17 +280,24 @@ global(const char *n)
default:
vp->flag &= ~(ISSET|INTEGER);
}
- return (vp);
+ goto out;
}
- l = varsearch(e->loc, &vp, n, h);
- if (vp != NULL)
- return (array ? arraysearch(vp, val) : vp);
- vp = ktenter(&l->vars, n, h);
+ l = varsearch(e->loc, &vp, vn, h);
+ if (vp != NULL) {
+ if (array)
+ vp = arraysearch(vp, val);
+ goto out;
+ }
+ vp = ktenter(&l->vars, vn, h);
if (array)
vp = arraysearch(vp, val);
vp->flag |= DEFINED;
- if (special(n))
+ if (special(vn))
vp->flag |= SPECIAL;
+ out:
+ last_lookup_was_array = array;
+ if (vn != n)
+ afree(vname.rw, ATEMP);
return (vp);
}
@@ -298,8 +307,9 @@ global(const char *n)
struct tbl *
local(const char *n, bool copy)
{
- struct block *l = e->loc;
struct tbl *vp;
+ union mksh_cchack vname;
+ struct block *l = e->loc;
bool array;
uint32_t h, val;
@@ -307,20 +317,20 @@ local(const char *n, bool copy)
* check to see if this is an array;
* dereference namerefs; must come first
*/
- n = array_index_calc(n, &array, &val);
- h = hash(n);
- if (!ksh_isalphx(*n)) {
+ vn = array_index_calc(n, &array, &val);
+ h = hash(vn);
+ if (!ksh_isalphx(*vn)) {
vp = &vtemp;
vp->flag = DEFINED|RDONLY;
vp->type = 0;
vp->areap = ATEMP;
- return (vp);
+ goto out;
}
- vp = ktenter(&l->vars, n, h);
+ vp = ktenter(&l->vars, vn, h);
if (copy && !(vp->flag & DEFINED)) {
struct tbl *vq;
- varsearch(l->next, &vq, n, h);
+ varsearch(l->next, &vq, vn, h);
if (vq != NULL) {
vp->flag |= vq->flag &
(EXPORT | INTEGER | RDONLY | LJUST | RJUST |
@@ -333,10 +343,15 @@ local(const char *n, bool copy)
if (array)
vp = arraysearch(vp, val);
vp->flag |= DEFINED;
- if (special(n))
+ if (special(vn))
vp->flag |= SPECIAL;
+ out:
+ last_lookup_was_array = array;
+ if (vn != n)
+ afree(vname.rw, ATEMP);
return (vp);
}
+#undef vn
/* get variable string value */
char *
@@ -710,8 +725,7 @@ exportprep(struct tbl *vp, const char *val)
/* offset to value */
vp->type = xp - vp->val.s;
memcpy(xp, val, vallen);
- if (op != NULL)
- afree(op, vp->areap);
+ afree(op, vp->areap);
}
/*
@@ -949,8 +963,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
t->type = 0;
}
}
- if (free_me)
- afree(free_me, t->areap);
+ afree(free_me, t->areap);
}
}
if (!ok)
@@ -976,8 +989,7 @@ typeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
/* setstr can't fail (readonly check already done) */
setstr(vp, val, KSH_RETURN_ERROR | 0x4);
- if (tval != NULL)
- afree(tval, ATEMP);
+ afree(tval, ATEMP);
}
/* only x[0] is ever exported, so use vpbase */
@@ -1260,18 +1272,15 @@ setspec(struct tbl *vp)
ifs0 = *s;
return;
case V_PATH:
- if (path)
- afree(path, APERM);
+ afree(path, APERM);
s = str_val(vp);
strdupx(path, s, APERM);
/* clear tracked aliases */
flushcom(true);
return;
case V_TMPDIR:
- if (tmpdir) {
- afree(tmpdir, APERM);
- tmpdir = NULL;
- }
+ afree(tmpdir, APERM);
+ tmpdir = NULL;
/*
* Use tmpdir iff it is an absolute path, is writable
* and searchable and is a directory...
@@ -1380,8 +1389,7 @@ unsetspec(struct tbl *vp)
ifs0 = ' ';
break;
case V_PATH:
- if (path)
- afree(path, APERM);
+ afree(path, APERM);
strdupx(path, def_path, APERM);
/* clear tracked aliases */
flushcom(true);
@@ -1480,7 +1488,7 @@ arrayname(const char *str)
const char *p;
char *rv;
- if ((p = cstrchr(str, '[')) == 0)
+ if (!(p = cstrchr(str, '[')))
/* Shouldn't happen, but why worry? */
strdupx(rv, str, ATEMP);
else
diff --git a/src/var_spec.h b/src/var_spec.h
index 1ed25e2..7d09584 100644
--- a/src/var_spec.h
+++ b/src/var_spec.h
@@ -1,5 +1,25 @@
+/*-
+ * Copyright (c) 2009, 2011, 2012
+ * mirabilos <m@mirbsd.org>
+ *
+ * Provided that these terms and disclaimer and all copyright notices
+ * are retained or reproduced in an accompanying document, permission
+ * is granted to deal in this work without restriction, including un-
+ * limited rights to use, publicly perform, distribute, sell, modify,
+ * merge, give away, or sublicence.
+ *
+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
+ * the utmost extent permitted by applicable law, neither express nor
+ * implied; without malicious intent or gross negligence. In no event
+ * may a licensor, author or contributor be held liable for indirect,
+ * direct, other damage, loss, or other issues arising in any way out
+ * of dealing in the work, even if advised of the possibility of such
+ * damage or existence of a defect, except proven that it results out
+ * of said person's immediate fault when using the work as intended.
+ */
+
#if defined(VARSPEC_DEFNS)
-__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.6 2012/11/30 16:45:25 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var_spec.h,v 1.7 2015/12/12 21:08:44 tg Exp $");
#define FN(name) /* nothing */
#elif defined(VARSPEC_ENUMS)
#define FN(name) V_##name,