Android-x86
Fork
Faire un don

  • R/O
  • HTTP
  • SSH
  • HTTPS

external-mksh: Commit

external/mksh


Commit MetaInfo

Révisionc03993d98f7ed5418a3386b69c3d0e49324fbbc9 (tree)
l'heure2017-12-08 17:37:08
AuteurChih-Wei Huang <cwhuang@linu...>
CommiterChih-Wei Huang

Message de Log

Android 8.1.0 Release 1 (OPM1.171019.011)
-----BEGIN PGP SIGNATURE-----

iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCWibmFAAKCRDorT+BmrEO
eGw5AJ9Wd7hqQv/0ab/IRuiAj+mPDMtuRQCcCzZnonfklaxNV7qaI7Tua4LGlMk=
=ZJSs
-----END PGP SIGNATURE-----

Merge tag 'android-8.1.0_r1' into oreo-x86

Android 8.1.0 Release 1 (OPM1.171019.011)

Change Summary

Modification

--- a/Android.mk
+++ b/Android.mk
@@ -73,7 +73,7 @@ MKSH_CFLAGS += \
7373 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 \
7474 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
7575 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 \
76- -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=541
76+ -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=551
7777
7878 LOCAL_SRC_FILES := $(MKSH_SRC_FILES)
7979
@@ -92,7 +92,6 @@ LOCAL_CFLAGS += $(MKSH_CFLAGS)
9292
9393 include $(BUILD_EXECUTABLE)
9494
95-ifeq ($(PRODUCT_FULL_TREBLE),true)
9695 # /vendor/etc/mkshrc
9796 include $(CLEAR_VARS)
9897
@@ -114,8 +113,6 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_EXECUTABLES)
114113 # mksh source files
115114 LOCAL_SRC_FILES := $(MKSH_SRC_FILES)
116115
117-LOCAL_STATIC_LIBRARIES := libc
118-
119116 LOCAL_C_INCLUDES := $(MKSH_INCLUDES)
120117
121118 # Additional flags first...
@@ -127,10 +124,7 @@ LOCAL_CFLAGS += \
127124
128125 LOCAL_CFLAGS += $(MKSH_CFLAGS)
129126
130-LOCAL_FORCE_STATIC_EXECUTABLE := true
131-
132127 include $(BUILD_EXECUTABLE)
133-endif
134128
135129 MKSH_SRC_FILES:=
136130 MKSH_CFLAGS:=
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,8 +1,8 @@
11 #!/bin/sh
2-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.707 2016/11/11 23:31:29 tg Exp $'
2+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.716 2017/04/12 18:33:22 tg Exp $'
33 #-
44 # Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5-# 2011, 2012, 2013, 2014, 2015, 2016
5+# 2011, 2012, 2013, 2014, 2015, 2016, 2017
66 # mirabilos <m@mirbsd.org>
77 #
88 # Provided that these terms and disclaimer and all copyright notices
@@ -495,6 +495,7 @@ check_categories=
495495 last=
496496 tfn=
497497 legacy=0
498+textmode=0
498499
499500 for i
500501 do
@@ -551,6 +552,12 @@ do
551552 :-r)
552553 r=1
553554 ;;
555+ :-T)
556+ textmode=1
557+ ;;
558+ :+T)
559+ textmode=0
560+ ;;
554561 :-t)
555562 last=t
556563 ;;
@@ -586,16 +593,21 @@ fi
586593 rmf a.exe* a.out* conftest.c conftest.exe* *core core.* ${tfn}* *.bc *.dbg \
587594 *.ll *.o *.gen *.cat1 Rebuild.sh lft no signames.inc test.sh x vv.out
588595
589-SRCS="lalloc.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
596+SRCS="lalloc.c edit.c eval.c exec.c expr.c funcs.c histrap.c jobs.c"
590597 SRCS="$SRCS lex.c main.c misc.c shf.c syn.c tree.c var.c"
591598
592599 if test $legacy = 0; then
593- SRCS="$SRCS edit.c"
594600 check_categories="$check_categories shell:legacy-no int:32"
595601 else
596602 check_categories="$check_categories shell:legacy-yes"
597603 add_cppflags -DMKSH_LEGACY_MODE
598- HAVE_PERSISTENT_HISTORY=0
604+fi
605+
606+if test $textmode = 0; then
607+ check_categories="$check_categories shell:textmode-no shell:binmode-yes"
608+else
609+ check_categories="$check_categories shell:textmode-yes shell:binmode-no"
610+ add_cppflags -DMKSH_WITH_TEXTMODE
599611 fi
600612
601613 if test x"$srcdir" = x"."; then
@@ -766,7 +778,6 @@ Harvey)
766778 add_cppflags -DMKSH__NO_SETEUGID
767779 oswarn=' and will currently not work'
768780 add_cppflags -DMKSH_UNEMPLOYED
769- add_cppflags -DMKSH_NOPROSPECTOFWORK
770781 # these taken from Harvey-OS github and need re-checking
771782 add_cppflags -D_setjmp=setjmp -D_longjmp=longjmp
772783 : "${HAVE_CAN_NO_EH_FRAME=0}"
@@ -849,16 +860,39 @@ OpenBSD)
849860 : "${HAVE_SETLOCALE_CTYPE=0}"
850861 ;;
851862 OS/2)
863+ add_cppflags -DMKSH_ASSUME_UTF8=0; HAVE_ISSET_MKSH_ASSUME_UTF8=1
852864 HAVE_TERMIOS_H=0
853865 HAVE_MKNOD=0 # setmode() incompatible
854- oswarn="; it is currently being ported, get it from"
855- oswarn="$oswarn${nl}https://github.com/komh/mksh-os2 in the meanwhile"
866+ oswarn="; it is being ported"
856867 check_categories="$check_categories nosymlink"
857868 : "${CC=gcc}"
858869 : "${SIZE=: size}"
870+ SRCS="$SRCS os2.c"
859871 add_cppflags -DMKSH_UNEMPLOYED
860872 add_cppflags -DMKSH_NOPROSPECTOFWORK
861873 add_cppflags -DMKSH_NO_LIMITS
874+ add_cppflags -DMKSH_DOSPATH
875+ if test $textmode = 0; then
876+ x='dis'
877+ y='standard OS/2 tools'
878+ else
879+ x='en'
880+ y='standard Unix mksh and other tools'
881+ fi
882+ echo >&2 "
883+OS/2 Note: mksh can be built with or without 'textmode'.
884+Without 'textmode' it will behave like a standard Unix utility,
885+compatible to mksh on all other platforms, using only ASCII LF
886+(0x0A) as line ending character. This is supported by the mksh
887+upstream developer.
888+With 'textmode', mksh will be modified to behave more like other
889+OS/2 utilities, supporting ASCII CR+LF (0x0D 0x0A) as line ending
890+at the cost of deviation from standard mksh. This is supported by
891+the mksh-os2 porter.
892+
893+] You are currently compiling with textmode ${x}abled, introducing
894+] incompatibilities with $y.
895+"
862896 ;;
863897 OSF1)
864898 HAVE_SIG_T=0 # incompatible
@@ -2152,68 +2186,6 @@ test 1 = $fv || check_categories="$check_categories no-histfile"
21522186 ac_testdone
21532187 ac_cppflags
21542188
2155-save_CFLAGS=$CFLAGS
2156-ac_testn compile_time_asserts_$$ '' 'whether compile-time assertions pass' <<-'EOF'
2157- #define MKSH_INCLUDES_ONLY
2158- #include "sh.h"
2159- #ifndef CHAR_BIT
2160- #define CHAR_BIT 8 /* defuse this test on really legacy systems */
2161- #endif
2162- struct ctasserts {
2163- #define cta(name, assertion) char name[(assertion) ? 1 : -1]
2164-/* this one should be defined by the standard */
2165-cta(char_is_1_char, (sizeof(char) == 1) && (sizeof(signed char) == 1) &&
2166- (sizeof(unsigned char) == 1));
2167-cta(char_is_8_bits, ((CHAR_BIT) == 8) && ((int)(unsigned char)0xFF == 0xFF) &&
2168- ((int)(unsigned char)0x100 == 0) && ((int)(unsigned char)(int)-1 == 0xFF));
2169-/* the next assertion is probably not really needed */
2170-cta(short_is_2_char, sizeof(short) == 2);
2171-cta(short_size_no_matter_of_signedness, sizeof(short) == sizeof(unsigned short));
2172-/* the next assertion is probably not really needed */
2173-cta(int_is_4_char, sizeof(int) == 4);
2174-cta(int_size_no_matter_of_signedness, sizeof(int) == sizeof(unsigned int));
2175-
2176-cta(long_ge_int, sizeof(long) >= sizeof(int));
2177-cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long));
2178-
2179-#ifndef MKSH_LEGACY_MODE
2180-/* the next assertion is probably not really needed */
2181-cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
2182-/* but this is */
2183-cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
2184-/* the next assertion is probably not really needed */
2185-cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
2186-/* but the next three are; we REQUIRE unsigned integer wraparound */
2187-cta(uari_has_31_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 2 + 1));
2188-cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3));
2189-cta(uari_wrap_32_bit,
2190- (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
2191- (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
2192-#define NUM 22
2193-#else
2194-#define NUM 16
2195-#endif
2196-/* these are always required */
2197-cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
2198-cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
2199-/* we require these to have the precisely same size and assume 2s complement */
2200-cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t));
2201-
2202-cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
2203-cta(sizet_voidptr_same_size, sizeof(size_t) == sizeof(void *));
2204-cta(sizet_funcptr_same_size, sizeof(size_t) == sizeof(void (*)(void)));
2205-/* our formatting routines assume this */
2206-cta(ptr_fits_in_long, sizeof(size_t) <= sizeof(long));
2207-cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long));
2208-/* for struct alignment people */
2209- char padding[64 - NUM];
2210- };
2211-char ctasserts_dblcheck[sizeof(struct ctasserts) == 64 ? 1 : -1];
2212- int main(void) { return (sizeof(ctasserts_dblcheck) + isatty(0)); }
2213-EOF
2214-CFLAGS=$save_CFLAGS
2215-eval test 1 = \$HAVE_COMPILE_TIME_ASSERTS_$$ || exit 1
2216-
22172189 #
22182190 # extra checks for legacy mksh
22192191 #
@@ -2367,7 +2339,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c
23672339 addsrcs USE_PRINTF_BUILTIN printf.c
23682340 test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
23692341 test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
2370-add_cppflags -DMKSH_BUILD_R=541
2342+add_cppflags -DMKSH_BUILD_R=551
23712343
23722344 $e $bi$me: Finished configuration testing, now producing output.$ao
23732345
--- a/src/check.t
+++ b/src/check.t
@@ -1,8 +1,8 @@
1-# $MirOS: src/bin/mksh/check.t,v 1.756 2016/11/11 23:31:31 tg Exp $
1+# $MirOS: src/bin/mksh/check.t,v 1.775 2017/04/12 17:38:41 tg Exp $
22 # -*- mode: sh -*-
33 #-
44 # Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5-# 2011, 2012, 2013, 2014, 2015, 2016
5+# 2011, 2012, 2013, 2014, 2015, 2016, 2017
66 # mirabilos <m@mirbsd.org>
77 #
88 # Provided that these terms and disclaimer and all copyright notices
@@ -30,22 +30,40 @@
3030 # (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
3131
3232 expected-stdout:
33- @(#)MIRBSD KSH R54 2016/11/11
33+ @(#)MIRBSD KSH R55 2017/04/12
3434 description:
3535 Check version of shell.
3636 stdin:
3737 echo $KSH_VERSION
3838 name: KSH_VERSION
39-category: shell:legacy-no
39+category: !shell:legacy-yes,!shell:textmode-yes
4040 ---
4141 expected-stdout:
42- @(#)LEGACY KSH R54 2016/11/11
42+ @(#)LEGACY KSH R55 2017/04/12
4343 description:
4444 Check version of legacy shell.
4545 stdin:
4646 echo $KSH_VERSION
4747 name: KSH_VERSION-legacy
48-category: shell:legacy-yes
48+category: !shell:legacy-no,!shell:textmode-yes
49+---
50+expected-stdout:
51+ @(#)MIRBSD KSH R55 2017/04/12 +TEXTMODE
52+description:
53+ Check version of shell.
54+stdin:
55+ echo $KSH_VERSION
56+name: KSH_VERSION-textmode
57+category: !shell:legacy-yes,!shell:textmode-no
58+---
59+expected-stdout:
60+ @(#)LEGACY KSH R55 2017/04/12 +TEXTMODE
61+description:
62+ Check version of legacy shell.
63+stdin:
64+ echo $KSH_VERSION
65+name: KSH_VERSION-legacy-textmode
66+category: !shell:legacy-no,!shell:textmode-no
4967 ---
5068 name: selftest-1
5169 description:
@@ -92,23 +110,6 @@ category: disabled
92110 stdin:
93111 set
94112 ---
95-name: selftest-legacy
96-description:
97- Check some things in the LEGACY KSH
98-category: shell:legacy-yes
99-stdin:
100- set +o emacs
101- set +o vi
102- [[ "$(set +o) -o" = *"-o emacs -o"* ]] && echo 1=emacs
103- [[ "$(set +o) -o" = *"-o vi -o"* ]] && echo 1=vi
104- set -o emacs
105- set -o vi
106- [[ "$(set +o) -o" = *"-o emacs -o"* ]] && echo 2=emacs
107- [[ "$(set +o) -o" = *"-o vi -o"* ]] && echo 2=vi
108-expected-stdout:
109- 2=emacs
110- 2=vi
111----
112113 name: selftest-direct-builtin-call
113114 description:
114115 Check that direct builtin calls work
@@ -119,6 +120,26 @@ stdin:
119120 expected-stdout:
120121 -c echo foo
121122 ---
123+name: selftest-pathsep-unix
124+description:
125+ Check that $PATHSEP is set correctly.
126+category: !os:os2
127+stdin:
128+ PATHSEP=.; export PATHSEP
129+ "$__progname" -c 'print -r -- $PATHSEP'
130+expected-stdout:
131+ :
132+---
133+name: selftest-pathsep-dospath
134+description:
135+ Check that $PATHSEP is set correctly.
136+category: os:os2
137+stdin:
138+ PATHSEP=.; export PATHSEP
139+ "$__progname" -c 'print -r -- $PATHSEP'
140+expected-stdout:
141+ ;
142+---
122143 name: alias-1
123144 description:
124145 Check that recursion is detected/avoided in aliases.
@@ -261,14 +282,42 @@ name: alias-11
261282 description:
262283 Check that special argument handling still applies with escaped aliases
263284 stdin:
264- alias local='\typeset'
265- function foo {
266- local x=$1 y=z
285+ alias local1='\typeset'
286+ alias local2='\\builtin typeset'
287+ function fooa {
288+ local1 x=$1 y=z
289+ print -r -- "$x,$y"
290+ }
291+ function foob {
292+ local2 x=$1 y=z
267293 print -r -- "$x,$y"
268294 }
269- foo 'bar - baz'
295+ x=1 y=2; fooa 'bar - baz'
296+ x=1 y=2; foob 'bar - baz'
270297 expected-stdout:
271298 bar - baz,z
299+ bar - baz,z
300+---
301+name: alias-12
302+description:
303+ Something weird from Martijn Dekker
304+stdin:
305+ alias echo=print
306+ x() { echo a; (echo b); x=$(echo c); }
307+ typeset -f x
308+ alias OPEN='{' CLOSE='};'
309+ { OPEN echo hi1; CLOSE }
310+ var=`{ OPEN echo hi2; CLOSE }` && echo "$var"
311+ var=$({ OPEN echo hi3; CLOSE }) && echo "$var"
312+expected-stdout:
313+ x() {
314+ \print a
315+ ( \print b )
316+ x=$(\print c )
317+ }
318+ hi1
319+ hi2
320+ hi3
272321 ---
273322 name: arith-compound
274323 description:
@@ -952,6 +1001,8 @@ stdin:
9521001 echo end-$i
9531002 done
9541003 echo end-3
1004+ for i in a b c; do echo $i; eval break; echo bad-$i; done
1005+ echo end-4
9551006 expected-stdout:
9561007 a
9571008 end-1
@@ -964,6 +1015,8 @@ expected-stdout:
9641015 c:x
9651016 end-c
9661017 end-3
1018+ a
1019+ end-4
9671020 ---
9681021 name: break-2
9691022 description:
@@ -1033,6 +1086,8 @@ stdin:
10331086 echo end-$i
10341087 done
10351088 echo end-3
1089+ for i in a b c; do echo $i; eval continue; echo bad-$i ; done
1090+ echo end-4
10361091 expected-stdout:
10371092 a
10381093 b
@@ -1055,6 +1110,10 @@ expected-stdout:
10551110 c:z
10561111 end-c
10571112 end-3
1113+ a
1114+ b
1115+ c
1116+ end-4
10581117 ---
10591118 name: continue-2
10601119 description:
@@ -2832,7 +2891,7 @@ stdin:
28322891 expected-stdout:
28332892 0
28342893 bar() {
2835- foo 4<<-a <<-b 5<<-c
2894+ \foo 4<<-a <<-b 5<<-c
28362895 four
28372896 a
28382897 zero
@@ -4711,6 +4770,23 @@ expected-stdout:
47114770 8 ok
47124771 <9> <ab> <a b> .
47134772 ---
4773+name: IFS-subst-10
4774+description:
4775+ Scalar context in ${var=$subst}
4776+stdin:
4777+ showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
4778+ set -- one "two three" four
4779+ unset -v var
4780+ save_IFS=$IFS
4781+ IFS=
4782+ set -- ${var=$*}
4783+ IFS=$save_IFS
4784+ echo "var=$var"
4785+ showargs "$@"
4786+expected-stdout:
4787+ var=onetwo threefour
4788+ <onetwo threefour> .
4789+---
47144790 name: IFS-arith-1
47154791 description:
47164792 http://austingroupbugs.net/view.php?id=832
@@ -5205,6 +5281,24 @@ expected-stdout:
52055281 line <6>
52065282 expected-exit: 1
52075283 ---
5284+name: lineno-eval-alias
5285+description:
5286+ Check if LINENO is trapped in eval and aliases
5287+stdin:
5288+ ${ZSH_VERSION+false} || emulate sh; echo $LINENO
5289+ echo $LINENO
5290+ eval ' echo $LINENO
5291+ echo $LINENO
5292+ echo $LINENO'
5293+ echo $LINENO
5294+expected-stdout:
5295+ 1
5296+ 2
5297+ 3
5298+ 3
5299+ 3
5300+ 6
5301+---
52085302 name: unknown-trap
52095303 description:
52105304 Ensure unknown traps are not a syntax error
@@ -6326,7 +6420,7 @@ name: regression-62
63266420 description:
63276421 Check if test -nt/-ot succeeds if second(first) file is missing.
63286422 stdin:
6329- touch a
6423+ :>a
63306424 test a -nt b && echo nt OK || echo nt BAD
63316425 test b -ot a && echo ot OK || echo ot BAD
63326426 expected-stdout:
@@ -7058,6 +7152,11 @@ description:
70587152 Check tilde expansion works
70597153 env-setup: !HOME=/sweet!
70607154 stdin:
7155+ :>'c=a'
7156+ typeset c=[ab]
7157+ :>'d=a'
7158+ x=typeset; $x d=[ab]
7159+ echo "<$c>" "<$d>"
70617160 wd=$PWD
70627161 cd /
70637162 plus=$(print -r -- ~+)
@@ -7067,10 +7166,106 @@ stdin:
70677166 [[ $minus = "$wd" ]]; echo two $? .
70687167 [[ $nix = /sweet ]]; echo nix $? .
70697168 expected-stdout:
7169+ <[ab]> <a>
70707170 one 0 .
70717171 two 0 .
70727172 nix 0 .
70737173 ---
7174+name: tilde-expand-3
7175+description:
7176+ Check mostly Austin 351 stuff
7177+stdin:
7178+ showargs() { for s_arg in "$@"; do echo -n "<$s_arg> "; done; echo .; }
7179+ set "1 b=2" "3 d=4"
7180+ export a=$1 \c=$2
7181+ showargs 1 "$a" "$b" "$c" "$d"
7182+ unset a b c d
7183+ HOME=/tmp
7184+ export \a=~ b=~
7185+ command export c=~
7186+ builtin export d=~
7187+ \\builtin export e=~
7188+ showargs 2 "$a" "$b" "$c" "$d" "$e" ksh
7189+ unset a b c d e
7190+ set -o posix
7191+ export \a=~ b=~
7192+ command export c=~
7193+ builtin export d=~
7194+ \\builtin export e=~
7195+ showargs 3 "$a" "$b" "$c" "$d" "$e" posix
7196+ unset a b c d e
7197+ set +o posix
7198+ export a=$1
7199+ showargs 4 "$a" "$b" ksh
7200+ unset a b
7201+ showargs 5 a=$1 ksh
7202+ export \a=$1
7203+ showargs 6 "$a" "$b" ksh
7204+ unset a b
7205+ set -o posix
7206+ export a=$1
7207+ showargs 7 "$a" "$b" posix
7208+ unset a b
7209+ showargs 8 a=$1 posix
7210+ export \a=$1
7211+ showargs 9 "$a" "$b" posix
7212+ unset a b
7213+ set +o posix
7214+ command echo 10 ksh a=~
7215+ command command export a=~
7216+ showargs 11 "$a"
7217+ unset a
7218+ set -o posix
7219+ command echo 12 posix a=~
7220+ command command export a=~
7221+ showargs 13 "$a"
7222+ unset a
7223+ # unspecified whether /tmp or ~
7224+ var=export; command $var a=~
7225+ showargs 14 "$a"
7226+ echo 'echo "<$foo>"' >bar
7227+ "$__progname" bar
7228+ var=foo
7229+ export $var=1
7230+ "$__progname" bar
7231+ export $var=~
7232+ "$__progname" bar
7233+ # unspecified
7234+ command -- export a=~
7235+ showargs 18 "$a"
7236+ set -A bla
7237+ typeset bla[1]=~:~
7238+ global gbl=~ g2=$1
7239+ local lcl=~ l2=$1
7240+ readonly ro=~ r2=$1
7241+ showargs 19 "${bla[1]}" a=~ "$gbl" "$lcl" "$ro" "$g2" "$l2" "$r2"
7242+ set +o posix
7243+ echo "20 some arbitrary stuff "=~
7244+ set -o posix
7245+ echo "21 some arbitrary stuff "=~
7246+expected-stdout:
7247+ <1> <1 b=2> <> <3> <4> .
7248+ <2> </tmp> </tmp> </tmp> </tmp> </tmp> <ksh> .
7249+ <3> <~> </tmp> </tmp> <~> </tmp> <posix> .
7250+ <4> <1 b=2> <> <ksh> .
7251+ <5> <a=1> <b=2> <ksh> .
7252+ <6> <1> <2> <ksh> .
7253+ <7> <1 b=2> <> <posix> .
7254+ <8> <a=1> <b=2> <posix> .
7255+ <9> <1> <2> <posix> .
7256+ 10 ksh a=/tmp
7257+ <11> </tmp> .
7258+ 12 posix a=~
7259+ <13> </tmp> .
7260+ <14> <~> .
7261+ <>
7262+ <1>
7263+ <~>
7264+ <18> <~> .
7265+ <19> </tmp:/tmp> <a=~> </tmp> </tmp> </tmp> <1 b=2> <1 b=2> <1 b=2> .
7266+ 20 some arbitrary stuff =/tmp
7267+ 21 some arbitrary stuff =~
7268+---
70747269 name: exit-err-1
70757270 description:
70767271 Check some "exit on error" conditions
@@ -7443,7 +7638,7 @@ expected-stdout:
74437638 After error 2
74447639 Exit trap
74457640 expected-stderr-pattern:
7446- /syntax error: 'newline' unexpected/
7641+ /syntax error: unexpected 'newline'/
74477642 ---
74487643 name: test-stlt-1
74497644 description:
@@ -7553,6 +7748,58 @@ expected-stdout:
75537748 2- 1 1 1 =
75547749 3- 0 0 0 =
75557750 ---
7751+name: test-varset-1
7752+description:
7753+ Test the test -v operator
7754+stdin:
7755+ [[ -v a ]]
7756+ rv=$?; echo $((++i)) $rv
7757+ a=
7758+ [[ -v a ]]
7759+ rv=$?; echo $((++i)) $rv
7760+ unset a
7761+ [[ -v a ]]
7762+ rv=$?; echo $((++i)) $rv
7763+ a=x
7764+ [[ -v a ]]
7765+ rv=$?; echo $((++i)) $rv
7766+ nameref b=a
7767+ [[ -v b ]]
7768+ rv=$?; echo $((++i)) $rv
7769+ unset a
7770+ [[ -v b ]]
7771+ rv=$?; echo $((++i)) $rv
7772+ x[1]=y
7773+ [[ -v x ]]
7774+ rv=$?; echo $((++i)) $rv
7775+ [[ -v x[0] ]]
7776+ rv=$?; echo $((++i)) $rv
7777+ [[ -v x[1] ]]
7778+ rv=$?; echo $((++i)) $rv
7779+ [[ -v x[2] ]]
7780+ rv=$?; echo $((++i)) $rv
7781+expected-stdout:
7782+ 1 1
7783+ 2 0
7784+ 3 1
7785+ 4 0
7786+ 5 0
7787+ 6 1
7788+ 7 1
7789+ 8 1
7790+ 9 0
7791+ 10 1
7792+---
7793+name: test-varset-2
7794+description:
7795+ test -v works only on scalars
7796+stdin:
7797+ [[ -v x[*] ]]
7798+ echo ok
7799+expected-exit: e != 0
7800+expected-stderr-pattern:
7801+ /unexpected '\*'/
7802+---
75567803 name: test-stnze-1
75577804 description:
75587805 Check that the short form [ $x ] works
@@ -7903,11 +8150,11 @@ expected-stderr-pattern:
79038150 ---
79048151 name: typeset-1
79058152 description:
7906- Check that global does what typeset is supposed to do
8153+ Check that typeset -g works correctly
79078154 stdin:
79088155 set -A arrfoo 65
79098156 foo() {
7910- global -Uui16 arrfoo[*]
8157+ typeset -g -Uui16 arrfoo[*]
79118158 }
79128159 echo before ${arrfoo[0]} .
79138160 foo
@@ -7917,7 +8164,7 @@ stdin:
79178164 echo inside before ${arrbar[0]} .
79188165 arrbar[0]=97
79198166 echo inside changed ${arrbar[0]} .
7920- global -Uui16 arrbar[*]
8167+ typeset -g -Uui16 arrbar[*]
79218168 echo inside typeset ${arrbar[0]} .
79228169 arrbar[0]=48
79238170 echo inside changed ${arrbar[0]} .
@@ -7935,6 +8182,24 @@ expected-stdout:
79358182 inside changed 16#30 .
79368183 after 16#30 .
79378184 ---
8185+name: typeset-2
8186+description:
8187+ Check that typeset -p on arrays works correctly
8188+stdin:
8189+ set -A x -- a b c
8190+ echo =
8191+ typeset -p x
8192+ echo =
8193+ typeset -p x[1]
8194+expected-stdout:
8195+ =
8196+ set -A x
8197+ typeset x[0]=a
8198+ typeset x[1]=b
8199+ typeset x[2]=c
8200+ =
8201+ typeset x[1]=b
8202+---
79388203 name: typeset-padding-1
79398204 description:
79408205 Check if left/right justification works as per TFM
@@ -8081,7 +8346,7 @@ description:
80818346 -UMKSH_ASSUME_UTF8 => not expected, but if your OS is old,
80828347 try passing HAVE_SETLOCALE_CTYPE=0 to Build.sh
80838348 need-pass: no
8084-category: !os:hpux,!os:msys
8349+category: !os:hpux,!os:msys,!os:os2
80858350 need-ctty: yes
80868351 arguments: !-i!
80878352 env-setup: !PS1=!PS2=!LC_CTYPE=en_US.UTF-8!
@@ -8173,17 +8438,17 @@ stdin:
81738438 alias
81748439 typeset -f
81758440 expected-stdout:
8176- autoload='\typeset -fu'
8177- functions='\typeset -f'
8178- hash='\builtin alias -t'
8179- history='\builtin fc -l'
8180- integer='\typeset -i'
8181- local='\typeset'
8182- login='\exec login'
8183- nameref='\typeset -n'
8441+ autoload='\\builtin typeset -fu'
8442+ functions='\\builtin typeset -f'
8443+ hash='\\builtin alias -t'
8444+ history='\\builtin fc -l'
8445+ integer='\\builtin typeset -i'
8446+ local='\\builtin typeset'
8447+ login='\\builtin exec login'
8448+ nameref='\\builtin typeset -n'
81848449 nohup='nohup '
8185- r='\builtin fc -e -'
8186- type='\builtin whence -v'
8450+ r='\\builtin fc -e -'
8451+ type='\\builtin whence -v'
81878452 ---
81888453 name: aliases-2b
81898454 description:
@@ -8193,17 +8458,17 @@ stdin:
81938458 alias
81948459 typeset -f
81958460 expected-stdout:
8196- autoload='\typeset -fu'
8197- functions='\typeset -f'
8198- hash='\builtin alias -t'
8199- history='\builtin fc -l'
8200- integer='\typeset -i'
8201- local='\typeset'
8202- login='\exec login'
8203- nameref='\typeset -n'
8461+ autoload='\\builtin typeset -fu'
8462+ functions='\\builtin typeset -f'
8463+ hash='\\builtin alias -t'
8464+ history='\\builtin fc -l'
8465+ integer='\\builtin typeset -i'
8466+ local='\\builtin typeset'
8467+ login='\\builtin exec login'
8468+ nameref='\\builtin typeset -n'
82048469 nohup='nohup '
8205- r='\builtin fc -e -'
8206- type='\builtin whence -v'
8470+ r='\\builtin fc -e -'
8471+ type='\\builtin whence -v'
82078472 ---
82088473 name: aliases-3b
82098474 description:
@@ -8213,17 +8478,17 @@ stdin:
82138478 ./sh -c 'alias; typeset -f'
82148479 rm -f sh
82158480 expected-stdout:
8216- autoload='\typeset -fu'
8217- functions='\typeset -f'
8218- hash='\builtin alias -t'
8219- history='\builtin fc -l'
8220- integer='\typeset -i'
8221- local='\typeset'
8222- login='\exec login'
8223- nameref='\typeset -n'
8481+ autoload='\\builtin typeset -fu'
8482+ functions='\\builtin typeset -f'
8483+ hash='\\builtin alias -t'
8484+ history='\\builtin fc -l'
8485+ integer='\\builtin typeset -i'
8486+ local='\\builtin typeset'
8487+ login='\\builtin exec login'
8488+ nameref='\\builtin typeset -n'
82248489 nohup='nohup '
8225- r='\builtin fc -e -'
8226- type='\builtin whence -v'
8490+ r='\\builtin fc -e -'
8491+ type='\\builtin whence -v'
82278492 ---
82288493 name: aliases-cmdline
82298494 description:
@@ -8280,8 +8545,8 @@ stdin:
82808545 :|| local() { :; }
82818546 alias local
82828547 expected-stdout:
8283- local='\typeset'
8284- local='\typeset'
8548+ local='\\builtin typeset'
8549+ local='\\builtin typeset'
82858550 ---
82868551 name: arrays-1
82878552 description:
@@ -8691,21 +8956,21 @@ expected-stdout:
86918956 name: arrassign-fnc-global
86928957 description:
86938958 Check locality of array access inside a function
8694- with the mksh-specific global keyword
8959+ with the bash4/mksh/yash/zsh typeset -g keyword
86958960 stdin:
86968961 function fn {
8697- global x
8962+ typeset -g x
86988963 x+=(f)
86998964 echo ".fn:${x[0]}.${x[1]}.${x[2]}.${x[3]}:"
87008965 }
87018966 function rfn {
87028967 set -A y
8703- global y
8968+ typeset -g y
87048969 y+=(f)
87058970 echo ".rfn:${y[0]}.${y[1]}.${y[2]}.${y[3]}:"
87068971 }
87078972 function fnr {
8708- global z
8973+ typeset -g z
87098974 set -A z
87108975 z+=(f)
87118976 echo ".fnr:${z[0]}.${z[1]}.${z[2]}.${z[3]}:"
@@ -8843,21 +9108,21 @@ expected-stdout:
88439108 name: strassign-fnc-global
88449109 description:
88459110 Check locality of string access inside a function
8846- with the mksh-specific global keyword
9111+ with the bash4/mksh/yash/zsh typeset -g keyword
88479112 stdin:
88489113 function fn {
8849- global x
9114+ typeset -g x
88509115 x+=f
88519116 echo ".fn:$x:"
88529117 }
88539118 function rfn {
88549119 y=
8855- global y
9120+ typeset -g y
88569121 y+=f
88579122 echo ".rfn:$y:"
88589123 }
88599124 function fnr {
8860- global z
9125+ typeset -g z
88619126 z=
88629127 z+=f
88639128 echo ".fnr:$z:"
@@ -9221,7 +9486,7 @@ stdin:
92219486 while (( i < ${#line[*]} )); do
92229487 hv=${line[i++]}
92239488 if (( (pos & 15) == 0 )); then
9224- (( pos )) && print "$dasc|"
9489+ (( pos )) && print -r -- "$dasc|"
92259490 print -n "${pos#16#} "
92269491 dasc=' |'
92279492 fi
@@ -9238,7 +9503,7 @@ stdin:
92389503 print -n ' '
92399504 (( (pos++ & 15) == 7 )) && print -n -- '- '
92409505 done
9241- (( hv == 2147483647 )) || print "$dasc|"
9506+ (( hv == 2147483647 )) || print -r -- "$dasc|"
92429507 }
92439508 expected-stdout:
92449509 00000000 3C 64 E4 DB C3 9B E2 82 - AC C3 9B 40 3E 0A 3C 00 |<d.........@>.<.|
@@ -9277,6 +9542,7 @@ expected-stdout:
92779542 name: print-crlf
92789543 description:
92799544 Check that CR+LF is shown and read as-is
9545+category: shell:textmode-no
92809546 stdin:
92819547 cat >foo <<-'EOF'
92829548 x='bar
@@ -9299,6 +9565,32 @@ expected-stdout:
92999565 {.5}
93009566 {<bar }
93019567 ---
9568+name: print-crlf-textmode
9569+description:
9570+ Check that CR+LF is treated as newline
9571+category: shell:textmode-yes
9572+stdin:
9573+ cat >foo <<-'EOF'
9574+ x='bar
9575+ ' #
9576+ echo .${#x} #
9577+ if test x"$KSH_VERSION" = x""; then #
9578+ printf '<%s>' "$x" #
9579+ else #
9580+ print -nr -- "<$x>" #
9581+ fi #
9582+ EOF
9583+ echo "[$("$__progname" foo)]"
9584+ "$__progname" foo | while IFS= read -r line; do
9585+ print -r -- "{$line}"
9586+ done
9587+expected-stdout:
9588+ [.4
9589+ <bar
9590+ >]
9591+ {.4}
9592+ {<bar}
9593+---
93029594 name: print-lf
93039595 description:
93049596 Check that LF-only is shown and read as-is
@@ -9364,7 +9656,7 @@ stdin:
93649656 while [[ -n $line ]]; do
93659657 hv=1#${line::1}
93669658 if (( (pos & 15) == 0 )); then
9367- (( pos )) && print "$dasc|"
9659+ (( pos )) && print -r -- "$dasc|"
93689660 print -n "${pos#16#} "
93699661 dasc=' |'
93709662 fi
@@ -9382,7 +9674,7 @@ stdin:
93829674 print -n ' '
93839675 (( (pos++ & 15) == 7 )) && print -n -- '- '
93849676 done
9385- (( hv == 2147483647 )) || print "$dasc|"
9677+ (( hv == 2147483647 )) || print -r -- "$dasc|"
93869678 }
93879679 expected-stdout:
93889680 00000000 5C 20 5C 21 5C 22 5C 23 - 5C 24 5C 25 5C 26 5C 27 |\ \!\"\#\$\%\&\'|
@@ -9391,13 +9683,13 @@ expected-stdout:
93919683 00000030 20 5C 39 5C 3A 5C 3B 5C - 3C 5C 3D 5C 3E 5C 3F 5C | \9\:\;\<\=\>\?\|
93929684 00000040 40 5C 41 5C 42 5C 43 5C - 44 1B 5C 46 5C 47 5C 48 |@\A\B\C\D.\F\G\H|
93939685 00000050 5C 49 5C 4A 5C 4B 5C 4C - 5C 4D 5C 4E 5C 4F 5C 50 |\I\J\K\L\M\N\O\P|
9394- 00000060 5C 51 5C 52 5C 53 5C 54 - 20 5C 56 5C 57 5C 58 5C |\Q\R\S\T \V\W\X\|
9395- 00000070 59 5C 5A 5C 5B 5C 5C 5D - 5C 5E 5C 5F 5C 60 07 08 |Y\Z\[\]\^\_\`..|
9396- 00000080 20 20 5C 64 1B 0C 5C 67 - 5C 68 5C 69 5C 6A 5C 6B | \d..\g\h\i\j\k|
9397- 00000090 5C 6C 5C 6D 0A 5C 6F 5C - 70 20 5C 71 0D 5C 73 09 |\l\m.\o\p \q.\s.|
9398- 000000A0 0B 5C 77 5C 79 5C 7A 5C - 7B 5C 7C 5C 7D 5C 7E 20 |.\w\y\z\{\|\}\~ |
9399- 000000B0 E2 82 AC 64 20 EF BF BD - 20 12 33 20 78 20 53 20 |...d ... .3 x S |
9400- 000000C0 53 34 0A - |S4.|
9686+ 00000060 5C 51 5C 52 5C 53 5C 54 - 20 5C 55 5C 56 5C 57 5C |\Q\R\S\T \U\V\W\|
9687+ 00000070 58 5C 59 5C 5A 5C 5B 5C - 5C 5D 5C 5E 5C 5F 5C 60 |X\Y\Z\[\\]\^\_\`|
9688+ 00000080 07 08 20 20 5C 64 1B 0C - 5C 67 5C 68 5C 69 5C 6A |.. \d..\g\h\i\j|
9689+ 00000090 5C 6B 5C 6C 5C 6D 0A 5C - 6F 5C 70 20 5C 71 0D 5C |\k\l\m.\o\p \q.\|
9690+ 000000A0 73 09 5C 75 0B 5C 77 5C - 78 5C 79 5C 7A 5C 7B 5C |s.\u.\w\x\y\z\{\|
9691+ 000000B0 7C 5C 7D 5C 7E 20 E2 82 - AC 64 20 EF BF BD 20 12 ||\}\~ ...d ... .|
9692+ 000000C0 33 20 78 20 53 20 53 34 - 0A |3 x S S4.|
94019693 ---
94029694 name: dollar-doublequoted-strings
94039695 description:
@@ -9439,7 +9731,7 @@ stdin:
94399731 while [[ -n $line ]]; do
94409732 hv=1#${line::1}
94419733 if (( (pos & 15) == 0 )); then
9442- (( pos )) && print "$dasc|"
9734+ (( pos )) && print -r -- "$dasc|"
94439735 print -n "${pos#16#} "
94449736 dasc=' |'
94459737 fi
@@ -9457,7 +9749,7 @@ stdin:
94579749 print -n ' '
94589750 (( (pos++ & 15) == 7 )) && print -n -- '- '
94599751 done
9460- (( hv == 2147483647 )) || print "$dasc|"
9752+ (( hv == 2147483647 )) || print -r -- "$dasc|"
94619753 }
94629754 expected-stdout:
94639755 00000000 20 21 22 23 24 25 26 27 - 28 29 2A 2B 2C 2D 2E 2F | !"#$%&'()*+,-./|
@@ -9767,7 +10059,7 @@ stdin:
976710059 while [[ -n $line ]]; do
976810060 hv=1#${line::1}
976910061 if (( (pos & 15) == 0 )); then
9770- (( pos )) && print "$dasc|"
10062+ (( pos )) && print -r -- "$dasc|"
977110063 print -n "${pos#16#} "
977210064 dasc=' |'
977310065 fi
@@ -9785,7 +10077,7 @@ stdin:
978510077 print -n ' '
978610078 (( (pos++ & 15) == 7 )) && print -n -- '- '
978710079 done
9788- (( hv == 2147483647 )) || print "$dasc|"
10080+ (( hv == 2147483647 )) || print -r -- "$dasc|"
978910081 }
979010082 expected-stdout:
979110083 00000000 48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3 |Hello, World!\..|
@@ -9855,7 +10147,7 @@ stdin:
985510147 dasc=$dasc$dch
985610148 dch=
985710149 elif (( (pos & 7) == 0 )); then
9858- (( pos )) && print "$dasc|"
10150+ (( pos )) && print -r -- "$dasc|"
985910151 print -n "${pos#16#} "
986010152 dasc=' |'
986110153 fi
@@ -9870,7 +10162,7 @@ stdin:
987010162 print -n ' '
987110163 (( (pos++ & 7) == 3 )) && print -n -- '- '
987210164 done
9873- (( hv == 2147483647 )) || print "$dasc|"
10165+ (( hv == 2147483647 )) || print -r -- "$dasc|"
987410166 }
987510167 expected-stdout:
987610168 00000000 0048 0065 006C 006C - 006F 002C 0020 0057 |Hello, W|
@@ -9936,7 +10228,7 @@ stdin:
993610228 while (( i < ${#line[*]} )); do
993710229 hv=${line[i++]}
993810230 if (( (pos & 15) == 0 )); then
9939- (( pos )) && print "$dasc|"
10231+ (( pos )) && print -r -- "$dasc|"
994010232 print -n "${pos#16#} "
994110233 dasc=' |'
994210234 fi
@@ -9953,7 +10245,7 @@ stdin:
995310245 print -n ' '
995410246 (( (pos++ & 15) == 7 )) && print -n -- '- '
995510247 done
9956- (( hv == 2147483647 )) || print "$dasc|"
10248+ (( hv == 2147483647 )) || print -r -- "$dasc|"
995710249 }
995810250 expected-stdout:
995910251 00000000 48 65 6C 6C 6F 2C 20 57 - 6F 72 6C 64 21 5C 0A E3 |Hello, World!\..|
@@ -10019,7 +10311,7 @@ stdin:
1001910311 dasc=$dasc$dch
1002010312 dch=
1002110313 elif (( (pos & 7) == 0 )); then
10022- (( pos )) && print "$dasc|"
10314+ (( pos )) && print -r -- "$dasc|"
1002310315 print -n "${pos#16#} "
1002410316 dasc=' |'
1002510317 fi
@@ -10033,7 +10325,7 @@ stdin:
1003310325 print -n ' '
1003410326 (( (pos++ & 7) == 3 )) && print -n -- '- '
1003510327 done
10036- (( hv == 2147483647 )) || print "$dasc|"
10328+ (( hv == 2147483647 )) || print -r -- "$dasc|"
1003710329 }
1003810330 expected-stdout:
1003910331 00000000 0048 0065 006C 006C - 006F 002C 0020 0057 |Hello, W|
@@ -10124,8 +10416,15 @@ expected-stdout:
1012410416 ---
1012510417 name: ulimit-1
1012610418 description:
10419+ Check that ulimit as used in dot.mksh works or is stubbed
10420+stdin:
10421+ ulimit -c 0
10422+---
10423+name: ulimit-2
10424+description:
1012710425 Check if we can use a specific syntax idiom for ulimit
10128-category: !os:syllable
10426+ XXX Haiku works, but only for -n and -V
10427+category: !os:haiku,!os:syllable
1012910428 stdin:
1013010429 if ! x=$(ulimit -d) || [[ $x = unknown ]]; then
1013110430 #echo expected to fail on this OS
@@ -10170,7 +10469,6 @@ name: bashiop-1
1017010469 description:
1017110470 Check if GNU bash-like I/O redirection works
1017210471 Part 1: this is also supported by GNU bash
10173-category: shell:legacy-no
1017410472 stdin:
1017510473 exec 3>&1
1017610474 function threeout {
@@ -10191,7 +10489,6 @@ name: bashiop-2a
1019110489 description:
1019210490 Check if GNU bash-like I/O redirection works
1019310491 Part 2: this is *not* supported by GNU bash
10194-category: shell:legacy-no
1019510492 stdin:
1019610493 exec 3>&1
1019710494 function threeout {
@@ -10212,7 +10509,6 @@ name: bashiop-2b
1021210509 description:
1021310510 Check if GNU bash-like I/O redirection works
1021410511 Part 2: this is *not* supported by GNU bash
10215-category: shell:legacy-no
1021610512 stdin:
1021710513 exec 3>&1
1021810514 function threeout {
@@ -10233,7 +10529,6 @@ name: bashiop-2c
1023310529 description:
1023410530 Check if GNU bash-like I/O redirection works
1023510531 Part 2: this is supported by GNU bash 4 only
10236-category: shell:legacy-no
1023710532 stdin:
1023810533 echo mir >foo
1023910534 set -o noclobber
@@ -10257,7 +10552,6 @@ name: bashiop-3a
1025710552 description:
1025810553 Check if GNU bash-like I/O redirection fails correctly
1025910554 Part 1: this is also supported by GNU bash
10260-category: shell:legacy-no
1026110555 stdin:
1026210556 echo mir >foo
1026310557 set -o noclobber
@@ -10279,7 +10573,6 @@ name: bashiop-3b
1027910573 description:
1028010574 Check if GNU bash-like I/O redirection fails correctly
1028110575 Part 2: this is *not* supported by GNU bash
10282-category: shell:legacy-no
1028310576 stdin:
1028410577 echo mir >foo
1028510578 set -o noclobber
@@ -10303,7 +10596,6 @@ description:
1030310596 Check if GNU bash-like I/O redirection works
1030410597 Part 4: this is also supported by GNU bash,
1030510598 but failed in some mksh versions
10306-category: shell:legacy-no
1030710599 stdin:
1030810600 exec 3>&1
1030910601 function threeout {
@@ -10325,11 +10617,10 @@ expected-stdout:
1032510617 ras
1032610618 dwa
1032710619 ---
10328-name: bashiop-5-normal
10620+name: bashiop-5
1032910621 description:
1033010622 Check if GNU bash-like I/O redirection is only supported
1033110623 in !POSIX !sh mode as it breaks existing scripts' syntax
10332-category: shell:legacy-no
1033310624 stdin:
1033410625 :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
1033510626 :>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
@@ -10339,20 +10630,6 @@ expected-stdout:
1033910630 2 = bar .
1034010631 3 = bar .
1034110632 ---
10342-name: bashiop-5-legacy
10343-description:
10344- Check if GNU bash-like I/O redirection is not parsed
10345- in lksh as it breaks existing scripts' syntax
10346-category: shell:legacy-yes
10347-stdin:
10348- :>x; echo 1 "$("$__progname" -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
10349- :>x; echo 2 "$("$__progname" -o posix -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
10350- :>x; echo 3 "$("$__progname" -o sh -c 'echo foo>/dev/null&>x echo bar')" = "$(<x)" .
10351-expected-stdout:
10352- 1 = bar .
10353- 2 = bar .
10354- 3 = bar .
10355----
1035610633 name: oksh-eval
1035710634 description:
1035810635 Check expansions.
@@ -10589,7 +10866,6 @@ description:
1058910866 AT&T ksh93 does this still, which means we must keep it as well
1059010867 XXX fails on some old Perl installations
1059110868 need-pass: no
10592-category: shell:legacy-no
1059310869 stdin:
1059410870 cat >cld <<-EOF
1059510871 #!$__perlname
@@ -10622,22 +10898,6 @@ stdin:
1062210898 expected-stdout:
1062310899 Fowl
1062410900 ---
10625-name: fd-cloexec-3
10626-description:
10627- Verify that file descriptors > 2 are not private for LEGACY KSH
10628-category: shell:legacy-yes
10629-stdin:
10630- cat >cld <<-EOF
10631- #!$__perlname
10632- open(my \$fh, ">&", 9) or die "E: open \$!";
10633- syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!";
10634- EOF
10635- chmod +x cld
10636- exec 9>&1
10637- ./cld
10638-expected-stdout:
10639- Fowl
10640----
1064110901 name: comsub-1a
1064210902 description:
1064310903 COMSUB are now parsed recursively, so this works
@@ -10726,10 +10986,10 @@ expected-stdout:
1072610986 x() {
1072710987 case $1 in
1072810988 (u)
10729- echo x
10989+ \echo x
1073010990 ;|
1073110991 (*)
10732- echo $1
10992+ \echo $1
1073310993 ;;
1073410994 esac
1073510995 }
@@ -10737,20 +10997,36 @@ expected-stdout:
1073710997 name: comsub-5
1073810998 description:
1073910999 Check COMSUB works with aliases (does not expand them twice)
11000+ and reentrancy safety
1074011001 stdin:
1074111002 print '#!'"$__progname"'\nfor x in "$@"; do print -r -- "$x"; done' >pfn
1074211003 chmod +x pfn
1074311004 alias echo='echo a'
1074411005 foo() {
11006+ echo moo
1074511007 ./pfn "$(echo foo)"
1074611008 }
1074711009 ./pfn "$(echo b)"
11010+ typeset -f foo >x
11011+ cat x
11012+ foo
11013+ . ./x
1074811014 typeset -f foo
11015+ foo
1074911016 expected-stdout:
1075011017 a b
1075111018 foo() {
10752- ./pfn "$(echo foo )"
11019+ \echo a moo
11020+ ./pfn "$(\echo a foo )"
11021+ }
11022+ a moo
11023+ a foo
11024+ foo() {
11025+ \echo a moo
11026+ ./pfn "$(\echo a foo )"
1075311027 }
11028+ a moo
11029+ a foo
1075411030 ---
1075511031 name: comsub-torture
1075611032 description:
@@ -10861,56 +11137,56 @@ expected-stdout:
1086111137 vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4"
1086211138 }
1086311139 inline_TCOM() {
10864- vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4"
11140+ vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4"
1086511141 }
1086611142 function comsub_TCOM { x=$(
1086711143 vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4"
1086811144 ); }
1086911145 function comsub_TCOM {
10870- x=$(vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" )
11146+ x=$(vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" )
1087111147 }
1087211148 function reread_TCOM { x=$((
1087311149 vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4"
1087411150 )|tr u x); }
1087511151 function reread_TCOM {
10876- x=$(( vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" ) | tr u x )
11152+ x=$( ( vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" ) | \tr u x )
1087711153 }
1087811154 inline_TPAREN_TPIPE_TLIST() {
1087911155 (echo $foo | tr -dc 0-9; echo)
1088011156 }
1088111157 inline_TPAREN_TPIPE_TLIST() {
10882- ( echo $foo | tr -dc 0-9
10883- echo )
11158+ ( \echo $foo | \tr -dc 0-9
11159+ \echo )
1088411160 }
1088511161 function comsub_TPAREN_TPIPE_TLIST { x=$(
1088611162 (echo $foo | tr -dc 0-9; echo)
1088711163 ); }
1088811164 function comsub_TPAREN_TPIPE_TLIST {
10889- x=$(( echo $foo | tr -dc 0-9 ; echo ) )
11165+ x=$( ( \echo $foo | \tr -dc 0-9 ; \echo ) )
1089011166 }
1089111167 function reread_TPAREN_TPIPE_TLIST { x=$((
1089211168 (echo $foo | tr -dc 0-9; echo)
1089311169 )|tr u x); }
1089411170 function reread_TPAREN_TPIPE_TLIST {
10895- x=$(( ( echo $foo | tr -dc 0-9 ; echo ) ) | tr u x )
11171+ x=$( ( ( \echo $foo | \tr -dc 0-9 ; \echo ) ) | \tr u x )
1089611172 }
1089711173 inline_TAND_TOR() {
1089811174 cmd && echo ja || echo nein
1089911175 }
1090011176 inline_TAND_TOR() {
10901- cmd && echo ja || echo nein
11177+ \cmd && \echo ja || \echo nein
1090211178 }
1090311179 function comsub_TAND_TOR { x=$(
1090411180 cmd && echo ja || echo nein
1090511181 ); }
1090611182 function comsub_TAND_TOR {
10907- x=$(cmd && echo ja || echo nein )
11183+ x=$(\cmd && \echo ja || \echo nein )
1090811184 }
1090911185 function reread_TAND_TOR { x=$((
1091011186 cmd && echo ja || echo nein
1091111187 )|tr u x); }
1091211188 function reread_TAND_TOR {
10913- x=$(( cmd && echo ja || echo nein ) | tr u x )
11189+ x=$( ( \cmd && \echo ja || \echo nein ) | \tr u x )
1091411190 }
1091511191 inline_TSELECT() {
1091611192 select file in *; do echo "<$file>" ; break ; done
@@ -10918,21 +11194,21 @@ expected-stdout:
1091811194 inline_TSELECT() {
1091911195 select file in *
1092011196 do
10921- echo "<$file>"
10922- break
11197+ \echo "<$file>"
11198+ \break
1092311199 done
1092411200 }
1092511201 function comsub_TSELECT { x=$(
1092611202 select file in *; do echo "<$file>" ; break ; done
1092711203 ); }
1092811204 function comsub_TSELECT {
10929- x=$(select file in * ; do echo "<$file>" ; break ; done )
11205+ x=$(select file in * ; do \echo "<$file>" ; \break ; done )
1093011206 }
1093111207 function reread_TSELECT { x=$((
1093211208 select file in *; do echo "<$file>" ; break ; done
1093311209 )|tr u x); }
1093411210 function reread_TSELECT {
10935- x=$(( select file in * ; do echo "<$file>" ; break ; done ) | tr u x )
11211+ x=$( ( select file in * ; do \echo "<$file>" ; \break ; done ) | \tr u x )
1093611212 }
1093711213 inline_TFOR_TTIME() {
1093811214 time for i in {1,2,3} ; do echo $i ; done
@@ -10940,20 +11216,20 @@ expected-stdout:
1094011216 inline_TFOR_TTIME() {
1094111217 time for i in {1,2,3}
1094211218 do
10943- echo $i
11219+ \echo $i
1094411220 done
1094511221 }
1094611222 function comsub_TFOR_TTIME { x=$(
1094711223 time for i in {1,2,3} ; do echo $i ; done
1094811224 ); }
1094911225 function comsub_TFOR_TTIME {
10950- x=$(time for i in {1,2,3} ; do echo $i ; done )
11226+ x=$(time for i in {1,2,3} ; do \echo $i ; done )
1095111227 }
1095211228 function reread_TFOR_TTIME { x=$((
1095311229 time for i in {1,2,3} ; do echo $i ; done
1095411230 )|tr u x); }
1095511231 function reread_TFOR_TTIME {
10956- x=$(( time for i in {1,2,3} ; do echo $i ; done ) | tr u x )
11232+ x=$( ( time for i in {1,2,3} ; do \echo $i ; done ) | \tr u x )
1095711233 }
1095811234 inline_TCASE() {
1095911235 case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
@@ -10961,13 +11237,13 @@ expected-stdout:
1096111237 inline_TCASE() {
1096211238 case $foo in
1096311239 (1)
10964- echo eins
11240+ \echo eins
1096511241 ;&
1096611242 (2)
10967- echo zwei
11243+ \echo zwei
1096811244 ;|
1096911245 (*)
10970- echo kann net bis drei zählen
11246+ \echo kann net bis drei zählen
1097111247 ;;
1097211248 esac
1097311249 }
@@ -10975,13 +11251,13 @@ expected-stdout:
1097511251 case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
1097611252 ); }
1097711253 function comsub_TCASE {
10978- x=$(case $foo in (1) echo eins ;& (2) echo zwei ;| (*) echo kann net bis drei zählen ;; esac )
11254+ x=$(case $foo in (1) \echo eins ;& (2) \echo zwei ;| (*) \echo kann net bis drei zählen ;; esac )
1097911255 }
1098011256 function reread_TCASE { x=$((
1098111257 case $foo in 1) echo eins;& 2) echo zwei ;| *) echo kann net bis drei zählen;; esac
1098211258 )|tr u x); }
1098311259 function reread_TCASE {
10984- x=$(( case $foo in (1) echo eins ;& (2) echo zwei ;| (*) echo kann net bis drei zählen ;; esac ) | tr u x )
11260+ x=$( ( case $foo in (1) \echo eins ;& (2) \echo zwei ;| (*) \echo kann net bis drei zählen ;; esac ) | \tr u x )
1098511261 }
1098611262 inline_TIF_TBANG_TDBRACKET_TELIF() {
1098711263 if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
@@ -10989,25 +11265,25 @@ expected-stdout:
1098911265 inline_TIF_TBANG_TDBRACKET_TELIF() {
1099011266 if ! [[ 1 = 1 ]]
1099111267 then
10992- echo eins
11268+ \echo eins
1099311269 elif [[ 1 = 2 ]]
1099411270 then
10995- echo zwei
11271+ \echo zwei
1099611272 else
10997- echo drei
11273+ \echo drei
1099811274 fi
1099911275 }
1100011276 function comsub_TIF_TBANG_TDBRACKET_TELIF { x=$(
1100111277 if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
1100211278 ); }
1100311279 function comsub_TIF_TBANG_TDBRACKET_TELIF {
11004- x=$(if ! [[ 1 = 1 ]] ; then echo eins ; elif [[ 1 = 2 ]] ; then echo zwei ; else echo drei ; fi )
11280+ x=$(if ! [[ 1 = 1 ]] ; then \echo eins ; elif [[ 1 = 2 ]] ; then \echo zwei ; else \echo drei ; fi )
1100511281 }
1100611282 function reread_TIF_TBANG_TDBRACKET_TELIF { x=$((
1100711283 if ! [[ 1 = 1 ]] ; then echo eins; elif [[ 1 = 2 ]]; then echo zwei ;else echo drei; fi
1100811284 )|tr u x); }
1100911285 function reread_TIF_TBANG_TDBRACKET_TELIF {
11010- x=$(( if ! [[ 1 = 1 ]] ; then echo eins ; elif [[ 1 = 2 ]] ; then echo zwei ; else echo drei ; fi ) | tr u x )
11286+ x=$( ( if ! [[ 1 = 1 ]] ; then \echo eins ; elif [[ 1 = 2 ]] ; then \echo zwei ; else \echo drei ; fi ) | \tr u x )
1101111287 }
1101211288 inline_TWHILE() {
1101311289 i=1; while (( i < 10 )); do echo $i; let ++i; done
@@ -11015,24 +11291,24 @@ expected-stdout:
1101511291 inline_TWHILE() {
1101611292 i=1
1101711293 while {
11018- \let] " i < 10 "
11294+ \\builtin let " i < 10 "
1101911295 }
1102011296 do
11021- echo $i
11022- let ++i
11297+ \echo $i
11298+ \let ++i
1102311299 done
1102411300 }
1102511301 function comsub_TWHILE { x=$(
1102611302 i=1; while (( i < 10 )); do echo $i; let ++i; done
1102711303 ); }
1102811304 function comsub_TWHILE {
11029- x=$(i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done )
11305+ x=$(i=1 ; while { \\builtin let " i < 10 " ; } ; do \echo $i ; \let ++i ; done )
1103011306 }
1103111307 function reread_TWHILE { x=$((
1103211308 i=1; while (( i < 10 )); do echo $i; let ++i; done
1103311309 )|tr u x); }
1103411310 function reread_TWHILE {
11035- x=$(( i=1 ; while { \let] " i < 10 " ; } ; do echo $i ; let ++i ; done ) | tr u x )
11311+ x=$( ( i=1 ; while { \\builtin let " i < 10 " ; } ; do \echo $i ; \let ++i ; done ) | \tr u x )
1103611312 }
1103711313 inline_TUNTIL() {
1103811314 i=10; until (( !--i )) ; do echo $i; done
@@ -11040,42 +11316,42 @@ expected-stdout:
1104011316 inline_TUNTIL() {
1104111317 i=10
1104211318 until {
11043- \let] " !--i "
11319+ \\builtin let " !--i "
1104411320 }
1104511321 do
11046- echo $i
11322+ \echo $i
1104711323 done
1104811324 }
1104911325 function comsub_TUNTIL { x=$(
1105011326 i=10; until (( !--i )) ; do echo $i; done
1105111327 ); }
1105211328 function comsub_TUNTIL {
11053- x=$(i=10 ; until { \let] " !--i " ; } ; do echo $i ; done )
11329+ x=$(i=10 ; until { \\builtin let " !--i " ; } ; do \echo $i ; done )
1105411330 }
1105511331 function reread_TUNTIL { x=$((
1105611332 i=10; until (( !--i )) ; do echo $i; done
1105711333 )|tr u x); }
1105811334 function reread_TUNTIL {
11059- x=$(( i=10 ; until { \let] " !--i " ; } ; do echo $i ; done ) | tr u x )
11335+ x=$( ( i=10 ; until { \\builtin let " !--i " ; } ; do \echo $i ; done ) | \tr u x )
1106011336 }
1106111337 inline_TCOPROC() {
1106211338 cat * |& ls
1106311339 }
1106411340 inline_TCOPROC() {
11065- cat * |&
11066- ls
11341+ \cat * |&
11342+ \ls
1106711343 }
1106811344 function comsub_TCOPROC { x=$(
1106911345 cat * |& ls
1107011346 ); }
1107111347 function comsub_TCOPROC {
11072- x=$(cat * |& ls )
11348+ x=$(\cat * |& \ls )
1107311349 }
1107411350 function reread_TCOPROC { x=$((
1107511351 cat * |& ls
1107611352 )|tr u x); }
1107711353 function reread_TCOPROC {
11078- x=$(( cat * |& ls ) | tr u x )
11354+ x=$( ( \cat * |& \ls ) | \tr u x )
1107911355 }
1108011356 inline_TFUNCT_TBRACE_TASYNC() {
1108111357 function korn { echo eins; echo zwei ; }
@@ -11083,11 +11359,11 @@ expected-stdout:
1108311359 }
1108411360 inline_TFUNCT_TBRACE_TASYNC() {
1108511361 function korn {
11086- echo eins
11087- echo zwei
11362+ \echo eins
11363+ \echo zwei
1108811364 }
1108911365 bourne() {
11090- logger * &
11366+ \logger * &
1109111367 }
1109211368 }
1109311369 function comsub_TFUNCT_TBRACE_TASYNC { x=$(
@@ -11095,32 +11371,32 @@ expected-stdout:
1109511371 bourne () { logger * & }
1109611372 ); }
1109711373 function comsub_TFUNCT_TBRACE_TASYNC {
11098- x=$(function korn { echo eins ; echo zwei ; } ; bourne() { logger * & } )
11374+ x=$(function korn { \echo eins ; \echo zwei ; } ; bourne() { \logger * & } )
1109911375 }
1110011376 function reread_TFUNCT_TBRACE_TASYNC { x=$((
1110111377 function korn { echo eins; echo zwei ; }
1110211378 bourne () { logger * & }
1110311379 )|tr u x); }
1110411380 function reread_TFUNCT_TBRACE_TASYNC {
11105- x=$(( function korn { echo eins ; echo zwei ; } ; bourne() { logger * & } ) | tr u x )
11381+ x=$( ( function korn { \echo eins ; \echo zwei ; } ; bourne() { \logger * & } ) | \tr u x )
1110611382 }
1110711383 inline_IOREAD_IOCAT() {
1110811384 tr x u 0<foo >>bar
1110911385 }
1111011386 inline_IOREAD_IOCAT() {
11111- tr x u <foo >>bar
11387+ \tr x u <foo >>bar
1111211388 }
1111311389 function comsub_IOREAD_IOCAT { x=$(
1111411390 tr x u 0<foo >>bar
1111511391 ); }
1111611392 function comsub_IOREAD_IOCAT {
11117- x=$(tr x u <foo >>bar )
11393+ x=$(\tr x u <foo >>bar )
1111811394 }
1111911395 function reread_IOREAD_IOCAT { x=$((
1112011396 tr x u 0<foo >>bar
1112111397 )|tr u x); }
1112211398 function reread_IOREAD_IOCAT {
11123- x=$(( tr x u <foo >>bar ) | tr u x )
11399+ x=$( ( \tr x u <foo >>bar ) | \tr u x )
1112411400 }
1112511401 inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() {
1112611402 cat >|bar <<'EOFN'
@@ -11128,7 +11404,7 @@ expected-stdout:
1112811404 EOFN
1112911405 }
1113011406 inline_IOWRITE_IOCLOB_IOHERE_noIOSKIP() {
11131- cat >|bar <<"EOFN"
11407+ \cat >|bar <<"EOFN"
1113211408 foo
1113311409 EOFN
1113411410
@@ -11139,7 +11415,7 @@ expected-stdout:
1113911415 EOFN
1114011416 ); }
1114111417 function comsub_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
11142- x=$(cat >|bar <<"EOFN"
11418+ x=$(\cat >|bar <<"EOFN"
1114311419 foo
1114411420 EOFN
1114511421 )
@@ -11150,10 +11426,10 @@ expected-stdout:
1115011426 EOFN
1115111427 )|tr u x); }
1115211428 function reread_IOWRITE_IOCLOB_IOHERE_noIOSKIP {
11153- x=$(( cat >|bar <<"EOFN"
11429+ x=$( ( \cat >|bar <<"EOFN"
1115411430 foo
1115511431 EOFN
11156- ) | tr u x )
11432+ ) | \tr u x )
1115711433 }
1115811434 inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() {
1115911435 cat 1>bar <<-EOFI
@@ -11161,7 +11437,7 @@ expected-stdout:
1116111437 EOFI
1116211438 }
1116311439 inline_IOWRITE_noIOCLOB_IOHERE_IOSKIP() {
11164- cat >bar <<-EOFI
11440+ \cat >bar <<-EOFI
1116511441 foo
1116611442 EOFI
1116711443
@@ -11172,7 +11448,7 @@ expected-stdout:
1117211448 EOFI
1117311449 ); }
1117411450 function comsub_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
11175- x=$(cat >bar <<-EOFI
11451+ x=$(\cat >bar <<-EOFI
1117611452 foo
1117711453 EOFI
1117811454 )
@@ -11183,46 +11459,46 @@ expected-stdout:
1118311459 EOFI
1118411460 )|tr u x); }
1118511461 function reread_IOWRITE_noIOCLOB_IOHERE_IOSKIP {
11186- x=$(( cat >bar <<-EOFI
11462+ x=$( ( \cat >bar <<-EOFI
1118711463 foo
1118811464 EOFI
11189- ) | tr u x )
11465+ ) | \tr u x )
1119011466 }
1119111467 inline_IORDWR_IODUP() {
1119211468 sh 1<>/dev/console 0<&1 2>&1
1119311469 }
1119411470 inline_IORDWR_IODUP() {
11195- sh 1<>/dev/console <&1 2>&1
11471+ \sh 1<>/dev/console <&1 2>&1
1119611472 }
1119711473 function comsub_IORDWR_IODUP { x=$(
1119811474 sh 1<>/dev/console 0<&1 2>&1
1119911475 ); }
1120011476 function comsub_IORDWR_IODUP {
11201- x=$(sh 1<>/dev/console <&1 2>&1 )
11477+ x=$(\sh 1<>/dev/console <&1 2>&1 )
1120211478 }
1120311479 function reread_IORDWR_IODUP { x=$((
1120411480 sh 1<>/dev/console 0<&1 2>&1
1120511481 )|tr u x); }
1120611482 function reread_IORDWR_IODUP {
11207- x=$(( sh 1<>/dev/console <&1 2>&1 ) | tr u x )
11483+ x=$( ( \sh 1<>/dev/console <&1 2>&1 ) | \tr u x )
1120811484 }
1120911485 inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
1121011486 echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
1121111487 }
1121211488 inline_COMSUB_EXPRSUB_FUNSUB_VALSUB() {
11213- echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;}
11489+ \echo $(\true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;}
1121411490 }
1121511491 function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$(
1121611492 echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
1121711493 ); }
1121811494 function comsub_COMSUB_EXPRSUB_FUNSUB_VALSUB {
11219- x=$(echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} )
11495+ x=$(\echo $(\true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} )
1122011496 }
1122111497 function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB { x=$((
1122211498 echo $(true) $((1+ 2)) ${ :;} ${| REPLY=x;}
1122311499 )|tr u x); }
1122411500 function reread_COMSUB_EXPRSUB_FUNSUB_VALSUB {
11225- x=$(( echo $(true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} ) | tr u x )
11501+ x=$( ( \echo $(\true ) $((1+ 2)) ${ : ;} ${|REPLY=x ;} ) | \tr u x )
1122611502 }
1122711503 inline_QCHAR_OQUOTE_CQUOTE() {
1122811504 echo fo\ob\"a\`r\'b\$az
@@ -11230,9 +11506,9 @@ expected-stdout:
1123011506 echo 'fo\ob\"a\`r'\''b\$az'
1123111507 }
1123211508 inline_QCHAR_OQUOTE_CQUOTE() {
11233- echo fo\ob\"a\`r\'b\$az
11234- echo "fo\ob\"a\`r\'b\$az"
11235- echo "fo\\ob\\\"a\\\`r"\'"b\\\$az"
11509+ \echo fo\ob\"a\`r\'b\$az
11510+ \echo "fo\ob\"a\`r\'b\$az"
11511+ \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az"
1123611512 }
1123711513 function comsub_QCHAR_OQUOTE_CQUOTE { x=$(
1123811514 echo fo\ob\"a\`r\'b\$az
@@ -11240,7 +11516,7 @@ expected-stdout:
1124011516 echo 'fo\ob\"a\`r'\''b\$az'
1124111517 ); }
1124211518 function comsub_QCHAR_OQUOTE_CQUOTE {
11243- x=$(echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" )
11519+ x=$(\echo fo\ob\"a\`r\'b\$az ; \echo "fo\ob\"a\`r\'b\$az" ; \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" )
1124411520 }
1124511521 function reread_QCHAR_OQUOTE_CQUOTE { x=$((
1124611522 echo fo\ob\"a\`r\'b\$az
@@ -11248,7 +11524,7 @@ expected-stdout:
1124811524 echo 'fo\ob\"a\`r'\''b\$az'
1124911525 )|tr u x); }
1125011526 function reread_QCHAR_OQUOTE_CQUOTE {
11251- x=$(( echo fo\ob\"a\`r\'b\$az ; echo "fo\ob\"a\`r\'b\$az" ; echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" ) | tr u x )
11527+ x=$( ( \echo fo\ob\"a\`r\'b\$az ; \echo "fo\ob\"a\`r\'b\$az" ; \echo "fo\\ob\\\"a\\\`r"\'"b\\\$az" ) | \tr u x )
1125211528 }
1125311529 inline_OSUBST_CSUBST_OPAT_SPAT_CPAT() {
1125411530 [[ ${foo#bl\(u\)b} = @(bar|baz) ]]
@@ -11266,7 +11542,7 @@ expected-stdout:
1126611542 [[ ${foo#bl\(u\)b} = @(bar|baz) ]]
1126711543 )|tr u x); }
1126811544 function reread_OSUBST_CSUBST_OPAT_SPAT_CPAT {
11269- x=$(( [[ ${foo#bl\(u\)b} = @(bar|baz) ]] ) | tr u x )
11545+ x=$( ( [[ ${foo#bl\(u\)b} = @(bar|baz) ]] ) | \tr u x )
1127011546 }
1127111547 inline_heredoc_closed() {
1127211548 x=$(cat <<EOFN
@@ -11274,11 +11550,11 @@ expected-stdout:
1127411550 EOFN); echo $x
1127511551 }
1127611552 inline_heredoc_closed() {
11277- x=$(cat <<EOFN
11553+ x=$(\cat <<EOFN
1127811554 note there must be no space between EOFN and )
1127911555 EOFN
1128011556 )
11281- echo $x
11557+ \echo $x
1128211558 }
1128311559 function comsub_heredoc_closed { x=$(
1128411560 x=$(cat <<EOFN
@@ -11286,10 +11562,10 @@ expected-stdout:
1128611562 EOFN); echo $x
1128711563 ); }
1128811564 function comsub_heredoc_closed {
11289- x=$(x=$(cat <<EOFN
11565+ x=$(x=$(\cat <<EOFN
1129011566 note there must be no space between EOFN and )
1129111567 EOFN
11292- ) ; echo $x )
11568+ ) ; \echo $x )
1129311569 }
1129411570 function reread_heredoc_closed { x=$((
1129511571 x=$(cat <<EOFN
@@ -11297,10 +11573,10 @@ expected-stdout:
1129711573 EOFN); echo $x
1129811574 )|tr u x); }
1129911575 function reread_heredoc_closed {
11300- x=$(( x=$(cat <<EOFN
11576+ x=$( ( x=$(\cat <<EOFN
1130111577 note there must be no space between EOFN and )
1130211578 EOFN
11303- ) ; echo $x ) | tr u x )
11579+ ) ; \echo $x ) | \tr u x )
1130411580 }
1130511581 inline_heredoc_space() {
1130611582 x=$(cat <<EOFN\
@@ -11308,11 +11584,11 @@ expected-stdout:
1130811584 EOFN ); echo $x
1130911585 }
1131011586 inline_heredoc_space() {
11311- x=$(cat <<EOFN\
11587+ x=$(\cat <<EOFN\
1131211588 note the space between EOFN and ) is actually part of the here document marker
1131311589 EOFN
1131411590 )
11315- echo $x
11591+ \echo $x
1131611592 }
1131711593 function comsub_heredoc_space { x=$(
1131811594 x=$(cat <<EOFN\
@@ -11320,10 +11596,10 @@ expected-stdout:
1132011596 EOFN ); echo $x
1132111597 ); }
1132211598 function comsub_heredoc_space {
11323- x=$(x=$(cat <<EOFN\
11599+ x=$(x=$(\cat <<EOFN\
1132411600 note the space between EOFN and ) is actually part of the here document marker
1132511601 EOFN
11326- ) ; echo $x )
11602+ ) ; \echo $x )
1132711603 }
1132811604 function reread_heredoc_space { x=$((
1132911605 x=$(cat <<EOFN\
@@ -11331,10 +11607,10 @@ expected-stdout:
1133111607 EOFN ); echo $x
1133211608 )|tr u x); }
1133311609 function reread_heredoc_space {
11334- x=$(( x=$(cat <<EOFN\
11610+ x=$( ( x=$(\cat <<EOFN\
1133511611 note the space between EOFN and ) is actually part of the here document marker
1133611612 EOFN
11337- ) ; echo $x ) | tr u x )
11613+ ) ; \echo $x ) | \tr u x )
1133811614 }
1133911615 inline_patch_motd() {
1134011616 x=$(sysctl -n kern.version | sed 1q)
@@ -11353,8 +11629,8 @@ expected-stdout:
1135311629 fi
1135411630 }
1135511631 inline_patch_motd() {
11356- x=$(sysctl -n kern.version | sed 1q )
11357- [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
11632+ x=$(\sysctl -n kern.version | \sed 1q )
11633+ [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF
1135811634 1,/^\$/d
1135911635 0a
1136011636 $x
@@ -11362,11 +11638,11 @@ expected-stdout:
1136211638 .
1136311639 wq
1136411640 EOF
11365- )" = @(?) ]] && rm -f /etc/motd
11641+ )" = @(?) ]] && \rm -f /etc/motd
1136611642 if [[ ! -s /etc/motd ]]
1136711643 then
11368- install -c -o root -g wheel -m 664 /dev/null /etc/motd
11369- print -- "$x\n" >/etc/motd
11644+ \install -c -o root -g wheel -m 664 /dev/null /etc/motd
11645+ \print -- "$x\n" >/etc/motd
1137011646 fi
1137111647 }
1137211648 function comsub_patch_motd { x=$(
@@ -11386,7 +11662,7 @@ expected-stdout:
1138611662 fi
1138711663 ); }
1138811664 function comsub_patch_motd {
11389- x=$(x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
11665+ x=$(x=$(\sysctl -n kern.version | \sed 1q ) ; [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF
1139011666 1,/^\$/d
1139111667 0a
1139211668 $x
@@ -11394,7 +11670,7 @@ expected-stdout:
1139411670 .
1139511671 wq
1139611672 EOF
11397- )" = @(?) ]] && rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then install -c -o root -g wheel -m 664 /dev/null /etc/motd ; print -- "$x\n" >/etc/motd ; fi )
11673+ )" = @(?) ]] && \rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then \install -c -o root -g wheel -m 664 /dev/null /etc/motd ; \print -- "$x\n" >/etc/motd ; fi )
1139811674 }
1139911675 function reread_patch_motd { x=$((
1140011676 x=$(sysctl -n kern.version | sed 1q)
@@ -11413,7 +11689,7 @@ expected-stdout:
1141311689 fi
1141411690 )|tr u x); }
1141511691 function reread_patch_motd {
11416- x=$(( x=$(sysctl -n kern.version | sed 1q ) ; [[ -s /etc/motd && "$([[ "$(head -1 /etc/motd )" != $x ]] && ed -s /etc/motd 2>&1 <<-EOF
11692+ x=$( ( x=$(\sysctl -n kern.version | \sed 1q ) ; [[ -s /etc/motd && "$([[ "$(\head -1 /etc/motd )" != $x ]] && \ed -s /etc/motd 2>&1 <<-EOF
1141711693 1,/^\$/d
1141811694 0a
1141911695 $x
@@ -11421,7 +11697,7 @@ expected-stdout:
1142111697 .
1142211698 wq
1142311699 EOF
11424- )" = @(?) ]] && rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then install -c -o root -g wheel -m 664 /dev/null /etc/motd ; print -- "$x\n" >/etc/motd ; fi ) | tr u x )
11700+ )" = @(?) ]] && \rm -f /etc/motd ; if [[ ! -s /etc/motd ]] ; then \install -c -o root -g wheel -m 664 /dev/null /etc/motd ; \print -- "$x\n" >/etc/motd ; fi ) | \tr u x )
1142511701 }
1142611702 inline_wdarrassign() {
1142711703 case x in
@@ -11432,7 +11708,7 @@ expected-stdout:
1143211708 case x in
1143311709 (x)
1143411710 a+=b
11435- \set -A c+ -- d e
11711+ \\builtin set -A c+ -- d e
1143611712 ;;
1143711713 esac
1143811714 }
@@ -11442,7 +11718,7 @@ expected-stdout:
1144211718 esac
1144311719 ); }
1144411720 function comsub_wdarrassign {
11445- x=$(case x in (x) a+=b ; \set -A c+ -- d e ;; esac )
11721+ x=$(case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac )
1144611722 }
1144711723 function reread_wdarrassign { x=$((
1144811724 case x in
@@ -11450,7 +11726,7 @@ expected-stdout:
1145011726 esac
1145111727 )|tr u x); }
1145211728 function reread_wdarrassign {
11453- x=$(( case x in (x) a+=b ; \set -A c+ -- d e ;; esac ) | tr u x )
11729+ x=$( ( case x in (x) a+=b ; \\builtin set -A c+ -- d e ;; esac ) | \tr u x )
1145411730 }
1145511731 ---
1145611732 name: comsub-torture-io
@@ -11517,56 +11793,56 @@ expected-stdout:
1151711793 vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" >&3
1151811794 }
1151911795 inline_TCOM() {
11520- vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" >&3
11796+ vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" >&3
1152111797 }
1152211798 function comsub_TCOM { x=$(
1152311799 vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" >&3
1152411800 ); }
1152511801 function comsub_TCOM {
11526- x=$(vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" >&3 )
11802+ x=$(vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" >&3 )
1152711803 }
1152811804 function reread_TCOM { x=$((
1152911805 vara=1 varb='2 3' cmd arg1 $arg2 "$arg3 4" >&3
1153011806 )|tr u x); }
1153111807 function reread_TCOM {
11532- x=$(( vara=1 varb="2 3" cmd arg1 $arg2 "$arg3 4" >&3 ) | tr u x )
11808+ x=$( ( vara=1 varb="2 3" \cmd arg1 $arg2 "$arg3 4" >&3 ) | \tr u x )
1153311809 }
1153411810 inline_TPAREN_TPIPE_TLIST() {
1153511811 (echo $foo | tr -dc 0-9 >&3; echo >&3) >&3
1153611812 }
1153711813 inline_TPAREN_TPIPE_TLIST() {
11538- ( echo $foo | tr -dc 0-9 >&3
11539- echo >&3 ) >&3
11814+ ( \echo $foo | \tr -dc 0-9 >&3
11815+ \echo >&3 ) >&3
1154011816 }
1154111817 function comsub_TPAREN_TPIPE_TLIST { x=$(
1154211818 (echo $foo | tr -dc 0-9 >&3; echo >&3) >&3
1154311819 ); }
1154411820 function comsub_TPAREN_TPIPE_TLIST {
11545- x=$(( echo $foo | tr -dc 0-9 >&3 ; echo >&3 ) >&3 )
11821+ x=$( ( \echo $foo | \tr -dc 0-9 >&3 ; \echo >&3 ) >&3 )
1154611822 }
1154711823 function reread_TPAREN_TPIPE_TLIST { x=$((
1154811824 (echo $foo | tr -dc 0-9 >&3; echo >&3) >&3
1154911825 )|tr u x); }
1155011826 function reread_TPAREN_TPIPE_TLIST {
11551- x=$(( ( echo $foo | tr -dc 0-9 >&3 ; echo >&3 ) >&3 ) | tr u x )
11827+ x=$( ( ( \echo $foo | \tr -dc 0-9 >&3 ; \echo >&3 ) >&3 ) | \tr u x )
1155211828 }
1155311829 inline_TAND_TOR() {
1155411830 cmd >&3 && >&3 echo ja || echo >&3 nein
1155511831 }
1155611832 inline_TAND_TOR() {
11557- cmd >&3 && echo ja >&3 || echo nein >&3
11833+ \cmd >&3 && \echo ja >&3 || \echo nein >&3
1155811834 }
1155911835 function comsub_TAND_TOR { x=$(
1156011836 cmd >&3 && >&3 echo ja || echo >&3 nein
1156111837 ); }
1156211838 function comsub_TAND_TOR {
11563- x=$(cmd >&3 && echo ja >&3 || echo nein >&3 )
11839+ x=$(\cmd >&3 && \echo ja >&3 || \echo nein >&3 )
1156411840 }
1156511841 function reread_TAND_TOR { x=$((
1156611842 cmd >&3 && >&3 echo ja || echo >&3 nein
1156711843 )|tr u x); }
1156811844 function reread_TAND_TOR {
11569- x=$(( cmd >&3 && echo ja >&3 || echo nein >&3 ) | tr u x )
11845+ x=$( ( \cmd >&3 && \echo ja >&3 || \echo nein >&3 ) | \tr u x )
1157011846 }
1157111847 inline_TSELECT() {
1157211848 select file in *; do echo "<$file>" ; break >&3 ; done >&3
@@ -11574,21 +11850,21 @@ expected-stdout:
1157411850 inline_TSELECT() {
1157511851 select file in *
1157611852 do
11577- echo "<$file>"
11578- break >&3
11853+ \echo "<$file>"
11854+ \break >&3
1157911855 done >&3
1158011856 }
1158111857 function comsub_TSELECT { x=$(
1158211858 select file in *; do echo "<$file>" ; break >&3 ; done >&3
1158311859 ); }
1158411860 function comsub_TSELECT {
11585- x=$(select file in * ; do echo "<$file>" ; break >&3 ; done >&3 )
11861+ x=$(select file in * ; do \echo "<$file>" ; \break >&3 ; done >&3 )
1158611862 }
1158711863 function reread_TSELECT { x=$((
1158811864 select file in *; do echo "<$file>" ; break >&3 ; done >&3
1158911865 )|tr u x); }
1159011866 function reread_TSELECT {
11591- x=$(( select file in * ; do echo "<$file>" ; break >&3 ; done >&3 ) | tr u x )
11867+ x=$( ( select file in * ; do \echo "<$file>" ; \break >&3 ; done >&3 ) | \tr u x )
1159211868 }
1159311869 inline_TFOR_TTIME() {
1159411870 for i in {1,2,3} ; do time >&3 echo $i ; done >&3
@@ -11596,20 +11872,20 @@ expected-stdout:
1159611872 inline_TFOR_TTIME() {
1159711873 for i in {1,2,3}
1159811874 do
11599- time echo $i >&3
11875+ time \echo $i >&3
1160011876 done >&3
1160111877 }
1160211878 function comsub_TFOR_TTIME { x=$(
1160311879 for i in {1,2,3} ; do time >&3 echo $i ; done >&3
1160411880 ); }
1160511881 function comsub_TFOR_TTIME {
11606- x=$(for i in {1,2,3} ; do time echo $i >&3 ; done >&3 )
11882+ x=$(for i in {1,2,3} ; do time \echo $i >&3 ; done >&3 )
1160711883 }
1160811884 function reread_TFOR_TTIME { x=$((
1160911885 for i in {1,2,3} ; do time >&3 echo $i ; done >&3
1161011886 )|tr u x); }
1161111887 function reread_TFOR_TTIME {
11612- x=$(( for i in {1,2,3} ; do time echo $i >&3 ; done >&3 ) | tr u x )
11888+ x=$( ( for i in {1,2,3} ; do time \echo $i >&3 ; done >&3 ) | \tr u x )
1161311889 }
1161411890 inline_TCASE() {
1161511891 case $foo in 1) echo eins >&3;& 2) echo zwei >&3 ;| *) echo kann net bis drei zählen >&3;; esac >&3
@@ -11617,13 +11893,13 @@ expected-stdout:
1161711893 inline_TCASE() {
1161811894 case $foo in
1161911895 (1)
11620- echo eins >&3
11896+ \echo eins >&3
1162111897 ;&
1162211898 (2)
11623- echo zwei >&3
11899+ \echo zwei >&3
1162411900 ;|
1162511901 (*)
11626- echo kann net bis drei zählen >&3
11902+ \echo kann net bis drei zählen >&3
1162711903 ;;
1162811904 esac >&3
1162911905 }
@@ -11631,13 +11907,13 @@ expected-stdout:
1163111907 case $foo in 1) echo eins >&3;& 2) echo zwei >&3 ;| *) echo kann net bis drei zählen >&3;; esac >&3
1163211908 ); }
1163311909 function comsub_TCASE {
11634- x=$(case $foo in (1) echo eins >&3 ;& (2) echo zwei >&3 ;| (*) echo kann net bis drei zählen >&3 ;; esac >&3 )
11910+ x=$(case $foo in (1) \echo eins >&3 ;& (2) \echo zwei >&3 ;| (*) \echo kann net bis drei zählen >&3 ;; esac >&3 )
1163511911 }
1163611912 function reread_TCASE { x=$((
1163711913 case $foo in 1) echo eins >&3;& 2) echo zwei >&3 ;| *) echo kann net bis drei zählen >&3;; esac >&3
1163811914 )|tr u x); }
1163911915 function reread_TCASE {
11640- x=$(( case $foo in (1) echo eins >&3 ;& (2) echo zwei >&3 ;| (*) echo kann net bis drei zählen >&3 ;; esac >&3 ) | tr u x )
11916+ x=$( ( case $foo in (1) \echo eins >&3 ;& (2) \echo zwei >&3 ;| (*) \echo kann net bis drei zählen >&3 ;; esac >&3 ) | \tr u x )
1164111917 }
1164211918 inline_TIF_TBANG_TDBRACKET_TELIF() {
1164311919 if ! [[ 1 = 1 ]] >&3 ; then echo eins; elif [[ 1 = 2 ]] >&3; then echo zwei ;else echo drei; fi >&3
@@ -11645,25 +11921,25 @@ expected-stdout:
1164511921 inline_TIF_TBANG_TDBRACKET_TELIF() {
1164611922 if ! [[ 1 = 1 ]] >&3
1164711923 then
11648- echo eins
11924+ \echo eins
1164911925 elif [[ 1 = 2 ]] >&3
1165011926 then
11651- echo zwei
11927+ \echo zwei
1165211928 else
11653- echo drei
11929+ \echo drei
1165411930 fi >&3
1165511931 }
1165611932 function comsub_TIF_TBANG_TDBRACKET_TELIF { x=$(
1165711933 if ! [[ 1 = 1 ]] >&3 ; then echo eins; elif [[ 1 = 2 ]] >&3; then echo zwei ;else echo drei; fi >&3
1165811934 ); }
1165911935 function comsub_TIF_TBANG_TDBRACKET_TELIF {
11660- x=$(if ! [[ 1 = 1 ]] >&3 ; then echo eins ; elif [[ 1 = 2 ]] >&3 ; then echo zwei ; else echo drei ; fi >&3 )
11936+ x=$(if ! [[ 1 = 1 ]] >&3 ; then \echo eins ; elif [[ 1 = 2 ]] >&3 ; then \echo zwei ; else \echo drei ; fi >&3 )
1166111937 }
1166211938 function reread_TIF_TBANG_TDBRACKET_TELIF { x=$((
1166311939 if ! [[ 1 = 1 ]] >&3 ; then echo eins; elif [[ 1 = 2 ]] >&3; then echo zwei ;else echo drei; fi >&3
1166411940 )|tr u x); }
1166511941 function reread_TIF_TBANG_TDBRACKET_TELIF {
11666- x=$(( if ! [[ 1 = 1 ]] >&3 ; then echo eins ; elif [[ 1 = 2 ]] >&3 ; then echo zwei ; else echo drei ; fi >&3 ) | tr u x )
11942+ x=$( ( if ! [[ 1 = 1 ]] >&3 ; then \echo eins ; elif [[ 1 = 2 ]] >&3 ; then \echo zwei ; else \echo drei ; fi >&3 ) | \tr u x )
1166711943 }
1166811944 inline_TWHILE() {
1166911945 i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
@@ -11671,24 +11947,24 @@ expected-stdout:
1167111947 inline_TWHILE() {
1167211948 i=1
1167311949 while {
11674- \let] " i < 10 "
11950+ \\builtin let " i < 10 "
1167511951 } >&3
1167611952 do
11677- echo $i
11678- let ++i
11953+ \echo $i
11954+ \let ++i
1167911955 done >&3
1168011956 }
1168111957 function comsub_TWHILE { x=$(
1168211958 i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
1168311959 ); }
1168411960 function comsub_TWHILE {
11685- x=$(i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 )
11961+ x=$(i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do \echo $i ; \let ++i ; done >&3 )
1168611962 }
1168711963 function reread_TWHILE { x=$((
1168811964 i=1; while (( i < 10 )) >&3; do echo $i; let ++i; done >&3
1168911965 )|tr u x); }
1169011966 function reread_TWHILE {
11691- x=$(( i=1 ; while { \let] " i < 10 " ; } >&3 ; do echo $i ; let ++i ; done >&3 ) | tr u x )
11967+ x=$( ( i=1 ; while { \\builtin let " i < 10 " ; } >&3 ; do \echo $i ; \let ++i ; done >&3 ) | \tr u x )
1169211968 }
1169311969 inline_TUNTIL() {
1169411970 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
@@ -11696,42 +11972,42 @@ expected-stdout:
1169611972 inline_TUNTIL() {
1169711973 i=10
1169811974 until {
11699- \let] " !--i "
11975+ \\builtin let " !--i "
1170011976 } >&3
1170111977 do
11702- echo $i
11978+ \echo $i
1170311979 done >&3
1170411980 }
1170511981 function comsub_TUNTIL { x=$(
1170611982 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
1170711983 ); }
1170811984 function comsub_TUNTIL {
11709- x=$(i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 )
11985+ x=$(i=10 ; until { \\builtin let " !--i " ; } >&3 ; do \echo $i ; done >&3 )
1171011986 }
1171111987 function reread_TUNTIL { x=$((
1171211988 i=10; until (( !--i )) >&3 ; do echo $i; done >&3
1171311989 )|tr u x); }
1171411990 function reread_TUNTIL {
11715- x=$(( i=10 ; until { \let] " !--i " ; } >&3 ; do echo $i ; done >&3 ) | tr u x )
11991+ x=$( ( i=10 ; until { \\builtin let " !--i " ; } >&3 ; do \echo $i ; done >&3 ) | \tr u x )
1171611992 }
1171711993 inline_TCOPROC() {
1171811994 cat * >&3 |& >&3 ls
1171911995 }
1172011996 inline_TCOPROC() {
11721- cat * >&3 |&
11722- ls >&3
11997+ \cat * >&3 |&
11998+ \ls >&3
1172311999 }
1172412000 function comsub_TCOPROC { x=$(
1172512001 cat * >&3 |& >&3 ls
1172612002 ); }
1172712003 function comsub_TCOPROC {
11728- x=$(cat * >&3 |& ls >&3 )
12004+ x=$(\cat * >&3 |& \ls >&3 )
1172912005 }
1173012006 function reread_TCOPROC { x=$((
1173112007 cat * >&3 |& >&3 ls
1173212008 )|tr u x); }
1173312009 function reread_TCOPROC {
11734- x=$(( cat * >&3 |& ls >&3 ) | tr u x )
12010+ x=$( ( \cat * >&3 |& \ls >&3 ) | \tr u x )
1173512011 }
1173612012 inline_TFUNCT_TBRACE_TASYNC() {
1173712013 function korn { echo eins; echo >&3 zwei ; }
@@ -11739,11 +12015,11 @@ expected-stdout:
1173912015 }
1174012016 inline_TFUNCT_TBRACE_TASYNC() {
1174112017 function korn {
11742- echo eins
11743- echo zwei >&3
12018+ \echo eins
12019+ \echo zwei >&3
1174412020 }
1174512021 bourne() {
11746- logger * >&3 &
12022+ \logger * >&3 &
1174712023 }
1174812024 }
1174912025 function comsub_TFUNCT_TBRACE_TASYNC { x=$(
@@ -11751,32 +12027,32 @@ expected-stdout:
1175112027 bourne () { logger * >&3 & }
1175212028 ); }
1175312029 function comsub_TFUNCT_TBRACE_TASYNC {
11754- x=$(function korn { echo eins ; echo zwei >&3 ; } ; bourne() { logger * >&3 & } )
12030+ x=$(function korn { \echo eins ; \echo zwei >&3 ; } ; bourne() { \logger * >&3 & } )
1175512031 }
1175612032 function reread_TFUNCT_TBRACE_TASYNC { x=$((
1175712033 function korn { echo eins; echo >&3 zwei ; }
1175812034 bourne () { logger * >&3 & }
1175912035 )|tr u x); }
1176012036 function reread_TFUNCT_TBRACE_TASYNC {
11761- x=$(( function korn { echo eins ; echo zwei >&3 ; } ; bourne() { logger * >&3 & } ) | tr u x )
12037+ x=$( ( function korn { \echo eins ; \echo zwei >&3 ; } ; bourne() { \logger * >&3 & } ) | \tr u x )
1176212038 }
1176312039 inline_COMSUB_EXPRSUB() {
1176412040 echo $(true >&3) $((1+ 2))
1176512041 }
1176612042 inline_COMSUB_EXPRSUB() {
11767- echo $(true >&3 ) $((1+ 2))
12043+ \echo $(\true >&3 ) $((1+ 2))
1176812044 }
1176912045 function comsub_COMSUB_EXPRSUB { x=$(
1177012046 echo $(true >&3) $((1+ 2))
1177112047 ); }
1177212048 function comsub_COMSUB_EXPRSUB {
11773- x=$(echo $(true >&3 ) $((1+ 2)) )
12049+ x=$(\echo $(\true >&3 ) $((1+ 2)) )
1177412050 }
1177512051 function reread_COMSUB_EXPRSUB { x=$((
1177612052 echo $(true >&3) $((1+ 2))
1177712053 )|tr u x); }
1177812054 function reread_COMSUB_EXPRSUB {
11779- x=$(( echo $(true >&3 ) $((1+ 2)) ) | tr u x )
12055+ x=$( ( \echo $(\true >&3 ) $((1+ 2)) ) | \tr u x )
1178012056 }
1178112057 ---
1178212058 name: funsub-1
--- a/src/dot.mkshrc
+++ b/src/dot.mkshrc
@@ -1,8 +1,8 @@
11 # $Id$
2-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.108 2016/07/26 22:03:41 tg Exp $
2+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.114 2017/03/19 22:31:26 tg Exp $
33 #-
44 # Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
5-# 2011, 2012, 2013, 2014, 2015, 2016
5+# 2011, 2012, 2013, 2014, 2015, 2016, 2017
66 # mirabilos <m@mirbsd.org>
77 #
88 # Provided that these terms and disclaimer and all copyright notices
@@ -22,65 +22,100 @@
2222 #-
2323 # ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
2424
25-# catch non-mksh (including lksh) trying to run this file
25+# catch non-mksh, non-lksh, trying to run this file
2626 case ${KSH_VERSION:-} in
27-*MIRBSD\ KSH*) ;;
28-*) return 0 ;;
27+*LEGACY\ KSH*|*MIRBSD\ KSH*) ;;
28+*) \return 0 ;;
2929 esac
3030
31-PS1='#'; (( USER_ID )) && PS1='$'; \: "${TERM:=vt100}${HOSTNAME:=$(\ulimit -c \
32- 0; hostname 2>/dev/null)}${EDITOR:=/bin/ed}${USER:=$(\ulimit -c 0; id -un \
33- 2>/dev/null || \echo \?)}${MKSH:=$(\builtin whence -p mksh)}"
34-HOSTNAME=${HOSTNAME%%*([ ]).*}; HOSTNAME=${HOSTNAME##*([ ])}
35-[[ $HOSTNAME = ?(ip6-)localhost?(6) ]] && HOSTNAME=
36-\: "${HOSTNAME:=nil}${MKSH:=/bin/mksh}"; \export EDITOR HOSTNAME MKSH TERM USER
37-PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
38- \typeset e=$?
31+# give MidnightBSD's laffer1 a bit of csh feeling
32+function setenv {
33+ if (( $# )); then
34+ \\builtin eval '\\builtin export "$1"="${2:-}"'
35+ else
36+ \\builtin typeset -x
37+ fi
38+}
39+
40+# pager (not control character safe)
41+smores() (
42+ \\builtin set +m
43+ \\builtin cat "$@" |&
44+ \\builtin trap "rv=\$?; \\\\builtin kill $! >/dev/null 2>&1; \\\\builtin exit \$rv" EXIT
45+ while IFS= \\builtin read -pr line; do
46+ llen=${%line}
47+ (( llen == -1 )) && llen=${#line}
48+ (( llen = llen ? (llen + COLUMNS - 1) / COLUMNS : 1 ))
49+ if (( (curlin += llen) >= LINES )); then
50+ \\builtin print -nr -- $'\e[7m--more--\e[0m'
51+ \\builtin read -u1 || \\builtin exit $?
52+ [[ $REPLY = [Qq]* ]] && \\builtin exit 0
53+ curlin=$llen
54+ fi
55+ \\builtin print -r -- "$line"
56+ done
57+)
58+
59+\\builtin alias ls=ls l='ls -F' la='l -a' ll='l -l' lo='l -alo'
60+\: "${HOSTNAME:=$(\\builtin ulimit -c 0; \\builtin print -r -- $(hostname \
61+ 2>/dev/null))}${EDITOR:=/bin/ed}${TERM:=vt100}${USER:=$(\\builtin ulimit \
62+ -c 0; id -un 2>/dev/null)}${USER:=?}"
63+[[ $HOSTNAME = ?(?(ip6-)localhost?(6)) ]] && HOSTNAME=nil; \\builtin unalias ls
64+\\builtin export EDITOR HOSTNAME TERM USER
65+
66+# minimal support for lksh users
67+if [[ $KSH_VERSION = *LEGACY\ KSH* ]]; then
68+ PS1='$USER@${HOSTNAME%%.*}:$PWD>'
69+ \\builtin return 0
70+fi
71+
72+# mksh-specific from here
73+\: "${MKSH:=$(\\builtin whence -p mksh)}${MKSH:=/bin/mksh}"
74+\\builtin export MKSH
75+
76+PS4='[$EPOCHREALTIME] '; PS1='#'; (( USER_ID )) && PS1='$'; PS1=$'\001\r''${|
77+ \\builtin typeset e=$?
3978
4079 (( e )) && REPLY+="$e|"
4180 REPLY+=${USER}@${HOSTNAME%%.*}:
4281
43- \typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/}
44- d=${d%/}; \typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
82+ \\builtin typeset d=${PWD:-?}/ p=~; [[ $p = ?(*/) ]] || d=${d/#$p\//\~/}
83+ d=${d%/}; \\builtin typeset m=${%d} n p=...; (( m > 0 )) || m=${#d}
4584 (( m > (n = (COLUMNS/3 < 7 ? 7 : COLUMNS/3)) )) && d=${d:(-n)} || p=
4685 REPLY+=$p$d
4786
48- \return $e
87+ \\builtin return $e
4988 } '"$PS1 "
50-\alias ls=ls
51-\unalias ls
52-\alias l='ls -F'
53-\alias la='l -a'
54-\alias ll='l -l'
55-\alias lo='l -alo'
56-\alias doch='sudo mksh -c "$(\builtin fc -ln -1)"'
57-\command -v rot13 >/dev/null || \alias rot13='tr \
89+\\builtin alias doch='sudo mksh -c "$(\\builtin fc -ln -1)"'
90+\\builtin command -v rot13 >/dev/null || \\builtin alias rot13='tr \
5891 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
5992 nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
60-if \command -v hd >/dev/null; then \:; elif \command -v hexdump >/dev/null; then
93+if \\builtin command -v hd >/dev/null; then
94+ \:
95+elif \\builtin command -v hexdump >/dev/null; then
6196 function hd {
6297 hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
6398 -e '" |" "%_p"' -e '"|\n"' "$@"
6499 }
65100 else
66101 function hd {
67- \typeset -Uui16 -Z11 pos=0
68- \typeset -Uui16 -Z5 hv=2147483647
69- \typeset dasc line i
70- \set +U
102+ \\builtin typeset -Uui16 -Z11 pos=0
103+ \\builtin typeset -Uui16 -Z5 hv=2147483647
104+ \\builtin typeset dasc line i
105+ \\builtin set +U
71106
72- \cat "$@" | if \read -arN -1 line; then
73- \typeset -i1 'line[*]'
107+ \\builtin cat "$@" | if \\builtin read -arN -1 line; then
108+ \\builtin typeset -i1 'line[*]'
74109 i=0
75110 while (( i < ${#line[*]} )); do
76111 hv=${line[i++]}
77112 if (( (pos & 15) == 0 )); then
78113 (( pos )) && \
79- \builtin print -r -- "$dasc|"
80- \builtin print -n "${pos#16#} "
114+ \\builtin print -r -- "$dasc|"
115+ \\builtin print -nr "${pos#16#} "
81116 dasc=' |'
82117 fi
83- \builtin print -n "${hv#16#} "
118+ \\builtin print -nr "${hv#16#} "
84119 #XXX EBCDIC, but we need [[:print:]] to fix this
85120 if (( (hv < 32) || (hv > 126) )); then
86121 dasc+=.
@@ -88,69 +123,69 @@ else
88123 dasc+=${line[i-1]#1#}
89124 fi
90125 (( (pos++ & 15) == 7 )) && \
91- \builtin print -n -- '- '
126+ \\builtin print -nr -- '- '
92127 done
93128 while (( pos & 15 )); do
94- \builtin print -n ' '
129+ \\builtin print -nr ' '
95130 (( (pos++ & 15) == 7 )) && \
96- \builtin print -n -- '- '
131+ \\builtin print -nr -- '- '
97132 done
98- (( hv == 2147483647 )) || \builtin print -r -- "$dasc|"
133+ (( hv == 2147483647 )) || \\builtin print -r -- "$dasc|"
99134 fi
100135 }
101136 fi
102137
103138 # Berkeley C shell compatible dirs, popd, and pushd functions
104139 # Z shell compatible chpwd() hook, used to update DIRSTACK[0]
105-DIRSTACKBASE=$(\builtin realpath ~/. 2>/dev/null || \
106- \builtin print -nr -- "${HOME:-/}")
107-set -A DIRSTACK
140+DIRSTACKBASE=$(\\builtin realpath ~/. 2>/dev/null || \
141+ \\builtin print -nr -- "${HOME:-/}")
142+\\builtin set -A DIRSTACK
108143 function chpwd {
109- DIRSTACK[0]=$(\builtin realpath . 2>/dev/null || \
110- \builtin print -r -- "$PWD")
144+ DIRSTACK[0]=$(\\builtin realpath . 2>/dev/null || \
145+ \\builtin print -nr -- "$PWD")
111146 [[ $DIRSTACKBASE = ?(*/) ]] || \
112147 DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/\~}
113148 \:
114149 }
115150 \chpwd .
116151 cd() {
117- \builtin cd "$@" || \return $?
152+ \\builtin cd "$@" || \\builtin return $?
118153 \chpwd "$@"
119154 }
120155 function cd_csh {
121- \typeset d t=${1/#\~/$DIRSTACKBASE}
156+ \\builtin typeset d t=${1/#\~/$DIRSTACKBASE}
122157
123- if ! d=$(\builtin cd "$t" 2>&1); then
124- \builtin print -u2 "${1}: ${d##*cd: $t: }."
125- \return 1
158+ if ! d=$(\\builtin cd "$t" 2>&1); then
159+ \\builtin print -ru2 "${1}: ${d##*cd: $t: }."
160+ \\builtin return 1
126161 fi
127162 \cd "$t"
128163 }
129164 function dirs {
130- \typeset d dwidth
131- \typeset -i fl=0 fv=0 fn=0 cpos=0
165+ \\builtin typeset d dwidth
166+ \\builtin typeset -i fl=0 fv=0 fn=0 cpos=0
132167
133- while \getopts ":lvn" d; do
168+ while \\builtin getopts ":lvn" d; do
134169 case $d {
135170 (l) fl=1 ;;
136171 (v) fv=1 ;;
137172 (n) fn=1 ;;
138- (*) \builtin print -u2 'Usage: dirs [-lvn].'
139- \return 1 ;;
173+ (*) \\builtin print -ru2 'Usage: dirs [-lvn].'
174+ \\builtin return 1 ;;
140175 }
141176 done
142- \shift $((OPTIND - 1))
177+ \\builtin shift $((OPTIND - 1))
143178 if (( $# > 0 )); then
144- \builtin print -u2 'Usage: dirs [-lvn].'
145- \return 1
179+ \\builtin print -ru2 'Usage: dirs [-lvn].'
180+ \\builtin return 1
146181 fi
147182 if (( fv )); then
148183 fv=0
149184 while (( fv < ${#DIRSTACK[*]} )); do
150185 d=${DIRSTACK[fv]}
151186 (( fl )) && d=${d/#\~/$DIRSTACKBASE}
152- \builtin print -r -- "$fv $d"
153- \builtin let fv++
187+ \\builtin print -r -- "$fv $d"
188+ (( ++fv ))
154189 done
155190 else
156191 fv=0
@@ -160,136 +195,117 @@ function dirs {
160195 (( dwidth = (${%d} > 0 ? ${%d} : ${#d}) ))
161196 if (( fn && (cpos += dwidth + 1) >= 79 && \
162197 dwidth < 80 )); then
163- \builtin print
198+ \\builtin print
164199 (( cpos = dwidth + 1 ))
165200 fi
166- \builtin print -nr -- "$d "
167- \builtin let fv++
201+ \\builtin print -nr -- "$d "
202+ (( ++fv ))
168203 done
169- \builtin print
204+ \\builtin print
170205 fi
171- \return 0
206+ \\builtin return 0
172207 }
173208 function popd {
174- \typeset d fa
175- \typeset -i n=1
209+ \\builtin typeset d fa
210+ \\builtin typeset -i n=1
176211
177- while \getopts ":0123456789lvn" d; do
212+ while \\builtin getopts ":0123456789lvn" d; do
178213 case $d {
179214 (l|v|n) fa+=" -$d" ;;
180215 (+*) n=2
181- \break ;;
182- (*) \builtin print -u2 'Usage: popd [-lvn] [+<n>].'
183- \return 1 ;;
216+ \\builtin break ;;
217+ (*) \\builtin print -ru2 'Usage: popd [-lvn] [+<n>].'
218+ \\builtin return 1 ;;
184219 }
185220 done
186- \shift $((OPTIND - n))
221+ \\builtin shift $((OPTIND - n))
187222 n=0
188223 if (( $# > 1 )); then
189- \builtin print -u2 popd: Too many arguments.
190- \return 1
224+ \\builtin print -ru2 popd: Too many arguments.
225+ \\builtin return 1
191226 elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
192227 if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
193- \builtin print -u2 popd: Directory stack not that deep.
194- \return 1
228+ \\builtin print -ru2 popd: Directory stack not that deep.
229+ \\builtin return 1
195230 fi
196231 elif [[ -n $1 ]]; then
197- \builtin print -u2 popd: Bad directory.
198- \return 1
232+ \\builtin print -ru2 popd: Bad directory.
233+ \\builtin return 1
199234 fi
200235 if (( ${#DIRSTACK[*]} < 2 )); then
201- \builtin print -u2 popd: Directory stack empty.
202- \return 1
236+ \\builtin print -ru2 popd: Directory stack empty.
237+ \\builtin return 1
203238 fi
204- \unset DIRSTACK[n]
205- \set -A DIRSTACK -- "${DIRSTACK[@]}"
206- \cd_csh "${DIRSTACK[0]}" || \return 1
239+ \\builtin unset DIRSTACK[n]
240+ \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}"
241+ \cd_csh "${DIRSTACK[0]}" || \\builtin return 1
207242 \dirs $fa
208243 }
209244 function pushd {
210- \typeset d fa
211- \typeset -i n=1
245+ \\builtin typeset d fa
246+ \\builtin typeset -i n=1
212247
213- while \getopts ":0123456789lvn" d; do
248+ while \\builtin getopts ":0123456789lvn" d; do
214249 case $d {
215250 (l|v|n) fa+=" -$d" ;;
216251 (+*) n=2
217- \break ;;
218- (*) \builtin print -u2 'Usage: pushd [-lvn] [<dir>|+<n>].'
219- \return 1 ;;
252+ \\builtin break ;;
253+ (*) \\builtin print -ru2 'Usage: pushd [-lvn] [<dir>|+<n>].'
254+ \\builtin return 1 ;;
220255 }
221256 done
222- \shift $((OPTIND - n))
257+ \\builtin shift $((OPTIND - n))
223258 if (( $# == 0 )); then
224259 if (( ${#DIRSTACK[*]} < 2 )); then
225- \builtin print -u2 pushd: No other directory.
226- \return 1
260+ \\builtin print -ru2 pushd: No other directory.
261+ \\builtin return 1
227262 fi
228263 d=${DIRSTACK[1]}
229264 DIRSTACK[1]=${DIRSTACK[0]}
230- \cd_csh "$d" || \return 1
265+ \cd_csh "$d" || \\builtin return 1
231266 elif (( $# > 1 )); then
232- \builtin print -u2 pushd: Too many arguments.
233- \return 1
267+ \\builtin print -ru2 pushd: Too many arguments.
268+ \\builtin return 1
234269 elif [[ $1 = ++([0-9]) && $1 != +0 ]]; then
235270 if (( (n = ${1#+}) >= ${#DIRSTACK[*]} )); then
236- \builtin print -u2 pushd: Directory stack not that deep.
237- \return 1
271+ \\builtin print -ru2 pushd: Directory stack not that deep.
272+ \\builtin return 1
238273 fi
239274 while (( n-- )); do
240275 d=${DIRSTACK[0]}
241- \unset DIRSTACK[0]
242- \set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
276+ \\builtin unset DIRSTACK[0]
277+ \\builtin set -A DIRSTACK -- "${DIRSTACK[@]}" "$d"
243278 done
244- \cd_csh "${DIRSTACK[0]}" || \return 1
279+ \cd_csh "${DIRSTACK[0]}" || \\builtin return 1
245280 else
246- \set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
247- \cd_csh "$1" || \return 1
281+ \\builtin set -A DIRSTACK -- placeholder "${DIRSTACK[@]}"
282+ \cd_csh "$1" || \\builtin return 1
248283 fi
249284 \dirs $fa
250285 }
251286
252-# pager (not control character safe)
253-smores() (
254- \set +m
255- \cat "$@" |&
256- \trap "rv=\$?; 'kill' $! >/dev/null 2>&1; 'exit' \$rv" EXIT
257- while IFS= \read -pr line; do
258- llen=${%line}
259- (( llen == -1 )) && llen=${#line}
260- (( llen = llen ? (llen + COLUMNS - 1) / COLUMNS : 1 ))
261- if (( (curlin += llen) >= LINES )); then
262- \builtin print -n -- '\e[7m--more--\e[0m'
263- \read -u1 || \exit $?
264- [[ $REPLY = [Qq]* ]] && \exit 0
265- curlin=$llen
266- fi
267- \builtin print -r -- "$line"
268- done
269-)
270-
271287 # base64 encoder and decoder, RFC compliant, NUL safe, not EBCDIC safe
272288 function Lb64decode {
273- \set +U
274- \typeset c s="$*" t
275- [[ -n $s ]] || { s=$(\cat; \builtin print x); s=${s%x}; }
276- \typeset -i i=0 j=0 n=${#s} p=0 v x
277- \typeset -i16 o
289+ \\builtin set +U
290+ \\builtin typeset c s="$*" t
291+ [[ -n $s ]] || { s=$(\\builtin cat; \\builtin print x); s=${s%x}; }
292+ \\builtin typeset -i i=0 j=0 n=${#s} p=0 v x
293+ \\builtin typeset -i16 o
278294
279295 while (( i < n )); do
280296 c=${s:(i++):1}
281297 case $c {
282- (=) \break ;;
298+ (=) \\builtin break ;;
283299 ([A-Z]) (( v = 1#$c - 65 )) ;;
284300 ([a-z]) (( v = 1#$c - 71 )) ;;
285301 ([0-9]) (( v = 1#$c + 4 )) ;;
286302 (+) v=62 ;;
287303 (/) v=63 ;;
288- (*) \continue ;;
304+ (*) \\builtin continue ;;
289305 }
290306 (( x = (x << 6) | v ))
291307 case $((p++)) {
292- (0) \continue ;;
308+ (0) \\builtin continue ;;
293309 (1) (( o = (x >> 4) & 255 )) ;;
294310 (2) (( o = (x >> 2) & 255 )) ;;
295311 (3) (( o = x & 255 ))
@@ -297,63 +313,60 @@ function Lb64decode {
297313 ;;
298314 }
299315 t+=\\x${o#16#}
300- (( ++j & 4095 )) && \continue
301- \builtin print -n $t
316+ (( ++j & 4095 )) && \\builtin continue
317+ \\builtin print -n $t
302318 t=
303319 done
304- \builtin print -n $t
320+ \\builtin print -n $t
305321 }
306-
307-\set -A Lb64encode_tbl -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
308- a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /
309322 function Lb64encode {
310- \set +U
311- \typeset c s t
323+ \\builtin set +U
324+ \\builtin typeset c s t table
325+ \\builtin set -A table -- A B C D E F G H I J K L M N O P Q R S T U V W X Y Z \
326+ a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9 + /
312327 if (( $# )); then
313- \read -raN-1 s <<<"$*"
314- \unset s[${#s[*]}-1]
328+ \\builtin read -raN-1 s <<<"$*"
329+ \\builtin unset s[${#s[*]}-1]
315330 else
316- \read -raN-1 s
331+ \\builtin read -raN-1 s
317332 fi
318- \typeset -i i=0 n=${#s[*]} j v
333+ \\builtin typeset -i i=0 n=${#s[*]} v
319334
320335 while (( i < n )); do
321336 (( v = s[i++] << 16 ))
322- (( j = i < n ? s[i++] : 0 ))
323- (( v |= j << 8 ))
324- (( j = i < n ? s[i++] : 0 ))
325- (( v |= j ))
326- t+=${Lb64encode_tbl[v >> 18]}${Lb64encode_tbl[v >> 12 & 63]}
327- c=${Lb64encode_tbl[v >> 6 & 63]}
337+ (( v |= s[i++] << 8 ))
338+ (( v |= s[i++] ))
339+ t+=${table[v >> 18]}${table[v >> 12 & 63]}
340+ c=${table[v >> 6 & 63]}
328341 if (( i <= n )); then
329- t+=$c${Lb64encode_tbl[v & 63]}
342+ t+=$c${table[v & 63]}
330343 elif (( i == n + 1 )); then
331344 t+=$c=
332345 else
333346 t+===
334347 fi
335348 if (( ${#t} == 76 || i >= n )); then
336- \builtin print $t
349+ \\builtin print -r $t
337350 t=
338351 fi
339352 done
340353 }
341354
342355 # Better Avalanche for the Jenkins Hash
343-\typeset -Z11 -Uui16 Lbafh_v
356+\\builtin typeset -Z11 -Uui16 Lbafh_v
344357 function Lbafh_init {
345358 Lbafh_v=0
346359 }
347360 function Lbafh_add {
348- \set +U
349- \typeset s
361+ \\builtin set +U
362+ \\builtin typeset s
350363 if (( $# )); then
351- \read -raN-1 s <<<"$*"
352- \unset s[${#s[*]}-1]
364+ \\builtin read -raN-1 s <<<"$*"
365+ \\builtin unset s[${#s[*]}-1]
353366 else
354- \read -raN-1 s
367+ \\builtin read -raN-1 s
355368 fi
356- \typeset -i i=0 n=${#s[*]}
369+ \\builtin typeset -i i=0 n=${#s[*]}
357370
358371 while (( i < n )); do
359372 ((# Lbafh_v = (Lbafh_v + s[i++] + 1) * 1025 ))
@@ -361,7 +374,7 @@ function Lbafh_add {
361374 done
362375 }
363376 function Lbafh_finish {
364- \typeset -Ui t
377+ \\builtin typeset -Ui t
365378
366379 ((# t = (((Lbafh_v >> 7) & 0x01010101) * 0x1B) ^ \
367380 ((Lbafh_v << 1) & 0xFEFEFEFE) ))
@@ -373,42 +386,33 @@ function Lbafh_finish {
373386 # strip comments (and leading/trailing whitespace if IFS is set) from
374387 # any file(s) given as argument, or stdin if none, and spew to stdout
375388 function Lstripcom {
376- \set -o noglob
377- \cat "$@" | while \read _line; do
389+ \\builtin set -o noglob
390+ \\builtin cat "$@" | while \\builtin read _line; do
378391 _line=${_line%%#*}
379- [[ -n $_line ]] && \builtin print -r -- $_line
392+ [[ -n $_line ]] && \\builtin print -r -- $_line
380393 done
381394 }
382395
383-# give MidnightBSD's laffer1 a bit of csh feeling
384-function setenv {
385- if (( $# )); then
386- \eval '\export "$1"="${2:-}"'
387- else
388- \typeset -x
389- fi
390-}
391-
392396 # toggle built-in aliases and utilities, and aliases and functions from mkshrc
393397 function enable {
394- \typeset doprnt=0 mode=1 x y z rv=0
395- \typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all
396- \set -A b_alias
397- \set -A i_alias
398- \set -A i_func
398+ \\builtin typeset doprnt=0 mode=1 x y z rv=0
399+ \\builtin typeset b_alias i_alias i_func nalias=0 nfunc=0 i_all
400+ \\builtin set -A b_alias
401+ \\builtin set -A i_alias
402+ \\builtin set -A i_func
399403
400404 # accumulate mksh built-in aliases, in ASCIIbetical order
401- i_alias[nalias]=autoload; b_alias[nalias++]='\typeset -fu'
402- i_alias[nalias]=functions; b_alias[nalias++]='\typeset -f'
403- i_alias[nalias]=hash; b_alias[nalias++]='\builtin alias -t'
404- i_alias[nalias]=history; b_alias[nalias++]='\builtin fc -l'
405- i_alias[nalias]=integer; b_alias[nalias++]='\typeset -i'
406- i_alias[nalias]=local; b_alias[nalias++]='\typeset'
407- i_alias[nalias]=login; b_alias[nalias++]='\exec login'
408- i_alias[nalias]=nameref; b_alias[nalias++]='\typeset -n'
405+ i_alias[nalias]=autoload; b_alias[nalias++]='\\builtin typeset -fu'
406+ i_alias[nalias]=functions; b_alias[nalias++]='\\builtin typeset -f'
407+ i_alias[nalias]=hash; b_alias[nalias++]='\\builtin alias -t'
408+ i_alias[nalias]=history; b_alias[nalias++]='\\builtin fc -l'
409+ i_alias[nalias]=integer; b_alias[nalias++]='\\builtin typeset -i'
410+ i_alias[nalias]=local; b_alias[nalias++]='\\builtin typeset'
411+ i_alias[nalias]=login; b_alias[nalias++]='\\builtin exec login'
412+ i_alias[nalias]=nameref; b_alias[nalias++]='\\builtin typeset -n'
409413 i_alias[nalias]=nohup; b_alias[nalias++]='nohup '
410- i_alias[nalias]=r; b_alias[nalias++]='\builtin fc -e -'
411- i_alias[nalias]=type; b_alias[nalias++]='\builtin whence -v'
414+ i_alias[nalias]=r; b_alias[nalias++]='\\builtin fc -e -'
415+ i_alias[nalias]=type; b_alias[nalias++]='\\builtin whence -v'
412416
413417 # accumulate mksh built-in utilities, in definition order, even ifndef
414418 i_func[nfunc++]=.
@@ -416,6 +420,7 @@ function enable {
416420 i_func[nfunc++]='['
417421 i_func[nfunc++]=alias
418422 i_func[nfunc++]=break
423+ # \\builtin cannot, by design, be overridden
419424 i_func[nfunc++]=builtin
420425 i_func[nfunc++]=cat
421426 i_func[nfunc++]=cd
@@ -434,7 +439,6 @@ function enable {
434439 i_func[nfunc++]=jobs
435440 i_func[nfunc++]=kill
436441 i_func[nfunc++]=let
437- i_func[nfunc++]='let]'
438442 i_func[nfunc++]=print
439443 i_func[nfunc++]=pwd
440444 i_func[nfunc++]=read
@@ -471,11 +475,13 @@ function enable {
471475 i_alias[nalias]=la; b_alias[nalias++]='l -a'
472476 i_alias[nalias]=ll; b_alias[nalias++]='l -l'
473477 i_alias[nalias]=lo; b_alias[nalias++]='l -alo'
474- i_alias[nalias]=doch; b_alias[nalias++]='sudo mksh -c "$(\builtin fc -ln -1)"'
478+ i_alias[nalias]=doch; b_alias[nalias++]='sudo mksh -c "$(\\builtin fc -ln -1)"'
475479 i_alias[nalias]=rot13; b_alias[nalias++]='tr abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
476- i_alias[nalias]=cls; b_alias[nalias++]='\builtin print -n \\ec'
480+ i_alias[nalias]=cls; b_alias[nalias++]='\\builtin print -n \\ec'
477481
478482 # accumulate functions from dot.mkshrc, in definition order
483+ i_func[nfunc++]=setenv
484+ i_func[nfunc++]=smores
479485 i_func[nfunc++]=hd
480486 i_func[nfunc++]=chpwd
481487 i_func[nfunc++]=cd
@@ -483,21 +489,19 @@ function enable {
483489 i_func[nfunc++]=dirs
484490 i_func[nfunc++]=popd
485491 i_func[nfunc++]=pushd
486- i_func[nfunc++]=smores
487492 i_func[nfunc++]=Lb64decode
488493 i_func[nfunc++]=Lb64encode
489494 i_func[nfunc++]=Lbafh_init
490495 i_func[nfunc++]=Lbafh_add
491496 i_func[nfunc++]=Lbafh_finish
492497 i_func[nfunc++]=Lstripcom
493- i_func[nfunc++]=setenv
494498 i_func[nfunc++]=enable
495499
496500 # collect all identifiers, sorted ASCIIbetically
497- \set -sA i_all -- "${i_alias[@]}" "${i_func[@]}"
501+ \\builtin set -sA i_all -- "${i_alias[@]}" "${i_func[@]}"
498502
499503 # handle options, we don't do dynamic loading
500- while \getopts "adf:nps" x; do
504+ while \\builtin getopts "adf:nps" x; do
501505 case $x {
502506 (a)
503507 mode=-1
@@ -506,8 +510,8 @@ function enable {
506510 # deliberately causing an error, like bash-static
507511 ;|
508512 (f)
509- \builtin print -u2 enable: dynamic loading not available
510- \return 2
513+ \\builtin print -ru2 enable: dynamic loading not available
514+ \\builtin return 2
511515 ;;
512516 (n)
513517 mode=0
@@ -516,88 +520,89 @@ function enable {
516520 doprnt=1
517521 ;;
518522 (s)
519- \set -sA i_all -- . : break continue eval exec exit \
520- export readonly return set shift times trap unset
523+ \\builtin set -sA i_all -- . : break continue eval \
524+ exec exit export readonly return set shift times \
525+ trap unset
521526 ;;
522527 (*)
523- \builtin print -u2 enable: usage: \
528+ \\builtin print -ru2 enable: usage: \
524529 "enable [-adnps] [-f filename] [name ...]"
525530 return 2
526531 ;;
527532 }
528533 done
529- \shift $((OPTIND - 1))
534+ \\builtin shift $((OPTIND - 1))
530535
531536 # display builtins enabled/disabled/all/special?
532537 if (( doprnt || ($# == 0) )); then
533538 for x in "${i_all[@]}"; do
534- y=$(\alias "$x") || y=
535- [[ $y = "$x='\\builtin whence -p $x >/dev/null || (\\builtin print mksh: $x: not found; exit 127) && \$(\\builtin whence -p $x)'" ]]; z=$?
539+ y=$(\\builtin alias "$x") || y=
540+ [[ $y = "$x='\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)'" ]]; z=$?
536541 case $mode:$z {
537542 (-1:0|0:0)
538- \print -r -- "enable -n $x"
543+ \\builtin print -r -- "enable -n $x"
539544 ;;
540545 (-1:1|1:1)
541- \print -r -- "enable $x"
546+ \\builtin print -r -- "enable $x"
542547 ;;
543548 }
544549 done
545- \return 0
550+ \\builtin return 0
546551 fi
547552
548553 for x in "$@"; do
549554 z=0
550555 for y in "${i_alias[@]}" "${i_func[@]}"; do
551- [[ $x = "$y" ]] || \continue
556+ [[ $x = "$y" ]] || \\builtin continue
552557 z=1
553- \break
558+ \\builtin break
554559 done
555560 if (( !z )); then
556- \builtin print -ru2 enable: "$x": not a shell builtin
561+ \\builtin print -ru2 enable: "$x": not a shell builtin
557562 rv=1
558- \continue
563+ \\builtin continue
559564 fi
560565 if (( !mode )); then
561566 # disable this
562- \alias "$x=\\builtin whence -p $x >/dev/null || (\\builtin print mksh: $x: not found; exit 127) && \$(\\builtin whence -p $x)"
567+ \\builtin alias "$x=\\\\builtin whence -p $x >/dev/null || (\\\\builtin print -r mksh: $x: not found; \\\\builtin exit 127) && \$(\\\\builtin whence -p $x)"
563568 else
564569 # find out if this is an alias or not, first
565570 z=0
566571 y=-1
567572 while (( ++y < nalias )); do
568- [[ $x = "${i_alias[y]}" ]] || \continue
573+ [[ $x = "${i_alias[y]}" ]] || \\builtin continue
569574 z=1
570- \break
575+ \\builtin break
571576 done
572577 if (( z )); then
573578 # re-enable the original alias body
574- \alias "$x=${b_alias[y]}"
579+ \\builtin alias "$x=${b_alias[y]}"
575580 else
576581 # re-enable the original utility/function
577- \unalias "$x"
582+ \\builtin unalias "$x"
578583 fi
579584 fi
580585 done
581- \return $rv
586+ \\builtin return $rv
582587 }
583588
584589 \: place customisations below this line
585590
586591 for p in ~/.etc/bin ~/bin; do
587- [[ -d $p/. ]] || \continue
588- #XXX OS/2
589- [[ :$PATH: = *:$p:* ]] || PATH=$p:$PATH
592+ [[ -d $p/. ]] || \\builtin continue
593+ [[ $PATHSEP$PATH$PATHSEP = *"$PATHSEP$p$PATHSEP"* ]] || \
594+ PATH=$p$PATHSEP$PATH
590595 done
591596
592-\export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
593-\alias cls='\builtin print -n \\ec'
597+\\builtin export SHELL=$MKSH MANWIDTH=80 LESSHISTFILE=-
598+\\builtin alias cls='\\builtin print -n \\ec'
594599
595-#\unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
600+#\\builtin unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
596601 # LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME
597602 #p=en_GB.UTF-8
598-#\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
599-#\set -U
603+#\\builtin export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
604+#\\builtin set -U
600605
601-\unset p
606+\\builtin unset p
602607
603608 \: place customisations above this line
--- a/src/edit.c
+++ b/src/edit.c
@@ -5,7 +5,7 @@
55
66 /*-
77 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
8- * 2011, 2012, 2013, 2014, 2015, 2016
8+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
99 * mirabilos <m@mirbsd.org>
1010 *
1111 * Provided that these terms and disclaimer and all copyright notices
@@ -28,7 +28,7 @@
2828
2929 #ifndef MKSH_NO_CMDLINE_EDITING
3030
31-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.312 2016/11/11 23:48:28 tg Exp $");
31+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.321 2017/04/12 16:46:20 tg Exp $");
3232
3333 /*
3434 * in later versions we might use libtermcap for this, but since external
@@ -145,6 +145,9 @@ x_read(char *buf)
145145 static int
146146 x_getc(void)
147147 {
148+#ifdef __OS2__
149+ return (_read_kbd(0, 1, 0));
150+#else
148151 char c;
149152 ssize_t n;
150153
@@ -166,6 +169,7 @@ x_getc(void)
166169 x_mode(true);
167170 }
168171 return ((n == 1) ? (int)(unsigned char)c : -1);
172+#endif
169173 }
170174
171175 static void
@@ -339,7 +343,7 @@ x_glob_hlp_tilde_and_rem_qchar(char *s, bool magic_flag)
339343 * and if so, discern "~foo/bar" and "~/baz" from "~blah";
340344 * if we have a directory part (the former), try to expand
341345 */
342- if (*s == '~' && (cp = mksh_sdirsep(s)) != NULL) {
346+ if (*s == '~' && (cp = /* not sdirsep */ strchr(s, '/')) != NULL) {
343347 /* ok, so split into "~foo"/"bar" or "~"/"baz" */
344348 *cp++ = 0;
345349 /* try to expand the tilde */
@@ -658,7 +662,7 @@ x_cf_glob(int *flagsp, const char *buf, int buflen, int pos, int *startp,
658662 }
659663 }
660664
661- if (*toglob == '~' && !mksh_vdirsep(toglob)) {
665+ if (*toglob == '~' && /* not vdirsep */ !vstrchr(toglob, '/')) {
662666 /* neither for '~foo' (but '~foo/bar') */
663667 *flagsp |= XCF_IS_NOSPACE;
664668 goto dont_add_glob;
@@ -949,6 +953,7 @@ static bool xlp_valid; /* lastvis pointer was recalculated */
949953 static char **x_histp; /* history position */
950954 static int x_nextcmd; /* for newline-and-next */
951955 static char **x_histncp; /* saved x_histp for " */
956+static char **x_histmcp; /* saved x_histp for " */
952957 static char *xmp; /* mark pointer */
953958 static unsigned char x_last_command;
954959 static unsigned char (*x_tab)[X_TABSZ]; /* key definition */
@@ -1163,6 +1168,7 @@ static void
11631168 x_modified(void)
11641169 {
11651170 if (!modified) {
1171+ x_histmcp = x_histp;
11661172 x_histp = histptr + 1;
11671173 modified = 1;
11681174 }
@@ -1239,7 +1245,7 @@ x_emacs(char *buf)
12391245 xlp_valid = true;
12401246 xmp = NULL;
12411247 x_curprefix = 0;
1242- x_histp = histptr + 1;
1248+ x_histmcp = x_histp = histptr + 1;
12431249 x_last_command = XFUNC_error;
12441250
12451251 x_init_prompt(true);
@@ -1780,12 +1786,11 @@ x_newline(int c MKSH_A_UNUSED)
17801786 static int
17811787 x_end_of_text(int c MKSH_A_UNUSED)
17821788 {
1783- unsigned char tmp;
1784- char *cp = (void *)&tmp;
1789+ unsigned char tmp[1], *cp = tmp;
17851790
1786- tmp = isedchar(edchars.eof) ? (unsigned char)edchars.eof :
1791+ *tmp = isedchar(edchars.eof) ? (unsigned char)edchars.eof :
17871792 (unsigned char)CTRL('D');
1788- x_zotc3(&cp);
1793+ x_zotc3((char **)&cp);
17891794 x_putc('\r');
17901795 x_putc('\n');
17911796 x_flush();
@@ -1862,9 +1867,11 @@ x_load_hist(char **hp)
18621867 static int
18631868 x_nl_next_com(int c MKSH_A_UNUSED)
18641869 {
1865- if (!x_histncp || (x_histp != x_histncp && x_histp != histptr + 1))
1870+ if (!modified)
1871+ x_histmcp = x_histp;
1872+ if (!x_histncp || (x_histmcp != x_histncp && x_histmcp != histptr + 1))
18661873 /* fresh start of ^O */
1867- x_histncp = x_histp;
1874+ x_histncp = x_histmcp;
18681875 x_nextcmd = source->line - (histptr - x_histncp) + 1;
18691876 return (x_newline('\n'));
18701877 }
@@ -1922,8 +1929,10 @@ x_search_hist(int c)
19221929 offset = -1;
19231930 break;
19241931 }
1925- if (p > pat)
1926- *--p = '\0';
1932+ if (p > pat) {
1933+ p = x_bs0(p - 1, pat);
1934+ *p = '\0';
1935+ }
19271936 if (p == pat)
19281937 offset = -1;
19291938 else
@@ -2933,8 +2942,12 @@ x_e_putc3(const char **cp)
29332942 char *cp2;
29342943
29352944 width = utf_widthadj(*cp, (const char **)&cp2);
2936- while (*cp < cp2)
2937- x_putcf(*(*cp)++);
2945+ if (cp2 == *cp + 1) {
2946+ (*cp)++;
2947+ shf_puts("\xEF\xBF\xBD", shl_out);
2948+ } else
2949+ while (*cp < cp2)
2950+ x_putcf(*(*cp)++);
29382951 } else {
29392952 (*cp)++;
29402953 x_putc(c);
@@ -3162,6 +3175,8 @@ x_prev_histword(int c MKSH_A_UNUSED)
31623175 x_ins(cp);
31633176 *rcp = ch;
31643177 }
3178+ if (!modified)
3179+ x_histmcp = x_histp;
31653180 modified = m + 1;
31663181 return (KSTD);
31673182 }
@@ -3466,7 +3481,7 @@ static void free_edstate(struct edstate *old);
34663481 static struct edstate ebuf;
34673482 static struct edstate undobuf;
34683483
3469-static struct edstate *es; /* current editor state */
3484+static struct edstate *vs; /* current Vi editing mode state */
34703485 static struct edstate *undo;
34713486
34723487 static char *ibuf; /* input buffer */
@@ -3530,7 +3545,7 @@ x_vi(char *buf)
35303545 undobuf.linelen = ebuf.linelen = 0;
35313546 undobuf.cursor = ebuf.cursor = 0;
35323547 undobuf.winleft = ebuf.winleft = 0;
3533- es = &ebuf;
3548+ vs = &ebuf;
35343549 undo = &undobuf;
35353550
35363551 x_init_prompt(true);
@@ -3581,7 +3596,7 @@ x_vi(char *buf)
35813596 unwind(LSHELL);
35823597 } else if (isched(c, edchars.eof) &&
35833598 state != VVERSION) {
3584- if (es->linelen == 0) {
3599+ if (vs->linelen == 0) {
35853600 x_vi_zotc(c);
35863601 c = -1;
35873602 break;
@@ -3598,15 +3613,15 @@ x_vi(char *buf)
35983613 x_putc('\n');
35993614 x_flush();
36003615
3601- if (c == -1 || (ssize_t)LINE <= es->linelen)
3616+ if (c == -1 || (ssize_t)LINE <= vs->linelen)
36023617 return (-1);
36033618
3604- if (es->cbuf != buf)
3605- memcpy(buf, es->cbuf, es->linelen);
3619+ if (vs->cbuf != buf)
3620+ memcpy(buf, vs->cbuf, vs->linelen);
36063621
3607- buf[es->linelen++] = '\n';
3622+ buf[vs->linelen++] = '\n';
36083623
3609- return (es->linelen);
3624+ return (vs->linelen);
36103625 }
36113626
36123627 static int
@@ -3643,7 +3658,7 @@ vi_hook(int ch)
36433658 break;
36443659 case 0:
36453660 if (state == VLIT) {
3646- es->cursor--;
3661+ vs->cursor--;
36473662 refresh(0);
36483663 } else
36493664 refresh(insert != 0);
@@ -3665,8 +3680,8 @@ vi_hook(int ch)
36653680 state = nextstate(ch);
36663681 if (state == VSEARCH) {
36673682 save_cbuf();
3668- es->cursor = 0;
3669- es->linelen = 0;
3683+ vs->cursor = 0;
3684+ vs->linelen = 0;
36703685 if (putbuf(ch == '/' ? "/" : "?", 1,
36713686 false) != 0)
36723687 return (-1);
@@ -3674,8 +3689,8 @@ vi_hook(int ch)
36743689 }
36753690 if (state == VVERSION) {
36763691 save_cbuf();
3677- es->cursor = 0;
3678- es->linelen = 0;
3692+ vs->cursor = 0;
3693+ vs->linelen = 0;
36793694 putbuf(KSH_VERSION,
36803695 strlen(KSH_VERSION), false);
36813696 refresh(0);
@@ -3686,10 +3701,10 @@ vi_hook(int ch)
36863701
36873702 case VLIT:
36883703 if (is_bad(ch)) {
3689- del_range(es->cursor, es->cursor + 1);
3704+ del_range(vs->cursor, vs->cursor + 1);
36903705 vi_error();
36913706 } else
3692- es->cbuf[es->cursor++] = ch;
3707+ vs->cbuf[vs->cursor++] = ch;
36933708 refresh(1);
36943709 state = VNORMAL;
36953710 break;
@@ -3772,8 +3787,8 @@ vi_hook(int ch)
37723787 } else if (isched(ch, edchars.erase) || ch == CTRL('h')) {
37733788 if (srchlen != 0) {
37743789 srchlen--;
3775- es->linelen -= char_len(locpat[srchlen]);
3776- es->cursor = es->linelen;
3790+ vs->linelen -= char_len(locpat[srchlen]);
3791+ vs->cursor = vs->linelen;
37773792 refresh(0);
37783793 return (0);
37793794 }
@@ -3782,8 +3797,8 @@ vi_hook(int ch)
37823797 refresh(0);
37833798 } else if (isched(ch, edchars.kill)) {
37843799 srchlen = 0;
3785- es->linelen = 1;
3786- es->cursor = 1;
3800+ vs->linelen = 1;
3801+ vs->cursor = 1;
37873802 refresh(0);
37883803 return (0);
37893804 } else if (isched(ch, edchars.werase)) {
@@ -3793,16 +3808,16 @@ vi_hook(int ch)
37933808 new_es.cursor = srchlen;
37943809 new_es.cbuf = locpat;
37953810
3796- save_es = es;
3797- es = &new_es;
3811+ save_es = vs;
3812+ vs = &new_es;
37983813 n = backword(1);
3799- es = save_es;
3814+ vs = save_es;
38003815
38013816 i = (unsigned)srchlen;
38023817 while (--i >= n)
3803- es->linelen -= char_len(locpat[i]);
3818+ vs->linelen -= char_len(locpat[i]);
38043819 srchlen = (int)n;
3805- es->cursor = es->linelen;
3820+ vs->cursor = vs->linelen;
38063821 refresh(0);
38073822 return (0);
38083823 } else {
@@ -3811,17 +3826,17 @@ vi_hook(int ch)
38113826 else {
38123827 locpat[srchlen++] = ch;
38133828 if (ISCTRL(ch) && /* but not C1 */ ch < 0x80) {
3814- if ((size_t)es->linelen + 2 >
3815- (size_t)es->cbufsize)
3829+ if ((size_t)vs->linelen + 2 >
3830+ (size_t)vs->cbufsize)
38163831 vi_error();
3817- es->cbuf[es->linelen++] = '^';
3818- es->cbuf[es->linelen++] = UNCTRL(ch);
3832+ vs->cbuf[vs->linelen++] = '^';
3833+ vs->cbuf[vs->linelen++] = UNCTRL(ch);
38193834 } else {
3820- if (es->linelen >= es->cbufsize)
3835+ if (vs->linelen >= vs->cbufsize)
38213836 vi_error();
3822- es->cbuf[es->linelen++] = ch;
3837+ vs->cbuf[vs->linelen++] = ch;
38233838 }
3824- es->cursor = es->linelen;
3839+ vs->cursor = vs->linelen;
38253840 refresh(0);
38263841 }
38273842 return (0);
@@ -3834,18 +3849,18 @@ vi_hook(int ch)
38343849 switch (ch) {
38353850 case 'A':
38363851 /* the cursor may not be at the BOL */
3837- if (!es->cursor)
3852+ if (!vs->cursor)
38383853 break;
38393854 /* nor further in the line than we can search for */
3840- if ((size_t)es->cursor >= sizeof(srchpat) - 1)
3841- es->cursor = sizeof(srchpat) - 2;
3855+ if ((size_t)vs->cursor >= sizeof(srchpat) - 1)
3856+ vs->cursor = sizeof(srchpat) - 2;
38423857 /* anchor the search pattern */
38433858 srchpat[0] = '^';
38443859 /* take the current line up to the cursor */
3845- memmove(srchpat + 1, es->cbuf, es->cursor);
3846- srchpat[es->cursor + 1] = '\0';
3860+ memmove(srchpat + 1, vs->cbuf, vs->cursor);
3861+ srchpat[vs->cursor + 1] = '\0';
38473862 /* set a magic flag */
3848- argc1 = 2 + (int)es->cursor;
3863+ argc1 = 2 + (int)vs->cursor;
38493864 /* and emulate a backwards history search */
38503865 lastsearch = '/';
38513866 *curcmd = 'n';
@@ -3942,52 +3957,52 @@ vi_insert(int ch)
39423957
39433958 if (isched(ch, edchars.erase) || ch == CTRL('h')) {
39443959 if (insert == REPLACE) {
3945- if (es->cursor == undo->cursor) {
3960+ if (vs->cursor == undo->cursor) {
39463961 vi_error();
39473962 return (0);
39483963 }
39493964 if (inslen > 0)
39503965 inslen--;
3951- es->cursor--;
3952- if (es->cursor >= undo->linelen)
3953- es->linelen--;
3966+ vs->cursor--;
3967+ if (vs->cursor >= undo->linelen)
3968+ vs->linelen--;
39543969 else
3955- es->cbuf[es->cursor] = undo->cbuf[es->cursor];
3970+ vs->cbuf[vs->cursor] = undo->cbuf[vs->cursor];
39563971 } else {
3957- if (es->cursor == 0)
3972+ if (vs->cursor == 0)
39583973 return (0);
39593974 if (inslen > 0)
39603975 inslen--;
3961- es->cursor--;
3962- es->linelen--;
3963- memmove(&es->cbuf[es->cursor], &es->cbuf[es->cursor + 1],
3964- es->linelen - es->cursor + 1);
3976+ vs->cursor--;
3977+ vs->linelen--;
3978+ memmove(&vs->cbuf[vs->cursor], &vs->cbuf[vs->cursor + 1],
3979+ vs->linelen - vs->cursor + 1);
39653980 }
39663981 expanded = NONE;
39673982 return (0);
39683983 }
39693984 if (isched(ch, edchars.kill)) {
3970- if (es->cursor != 0) {
3985+ if (vs->cursor != 0) {
39713986 inslen = 0;
3972- memmove(es->cbuf, &es->cbuf[es->cursor],
3973- es->linelen - es->cursor);
3974- es->linelen -= es->cursor;
3975- es->cursor = 0;
3987+ memmove(vs->cbuf, &vs->cbuf[vs->cursor],
3988+ vs->linelen - vs->cursor);
3989+ vs->linelen -= vs->cursor;
3990+ vs->cursor = 0;
39763991 }
39773992 expanded = NONE;
39783993 return (0);
39793994 }
39803995 if (isched(ch, edchars.werase)) {
3981- if (es->cursor != 0) {
3996+ if (vs->cursor != 0) {
39823997 tcursor = backword(1);
3983- memmove(&es->cbuf[tcursor], &es->cbuf[es->cursor],
3984- es->linelen - es->cursor);
3985- es->linelen -= es->cursor - tcursor;
3986- if (inslen < es->cursor - tcursor)
3998+ memmove(&vs->cbuf[tcursor], &vs->cbuf[vs->cursor],
3999+ vs->linelen - vs->cursor);
4000+ vs->linelen -= vs->cursor - tcursor;
4001+ if (inslen < vs->cursor - tcursor)
39874002 inslen = 0;
39884003 else
3989- inslen -= es->cursor - tcursor;
3990- es->cursor = tcursor;
4004+ inslen -= vs->cursor - tcursor;
4005+ vs->cursor = tcursor;
39914006 }
39924007 expanded = NONE;
39934008 return (0);
@@ -4034,7 +4049,7 @@ vi_insert(int ch)
40344049 break;
40354050
40364051 case CTRL('e'):
4037- print_expansions(es, 0);
4052+ print_expansions(vs, 0);
40384053 break;
40394054
40404055 case CTRL('i'):
@@ -4046,17 +4061,17 @@ vi_insert(int ch)
40464061 /* end nonstandard vi commands } */
40474062
40484063 default:
4049- if (es->linelen >= es->cbufsize - 1)
4064+ if (vs->linelen >= vs->cbufsize - 1)
40504065 return (-1);
40514066 ibuf[inslen++] = ch;
40524067 if (insert == INSERT) {
4053- memmove(&es->cbuf[es->cursor + 1], &es->cbuf[es->cursor],
4054- es->linelen - es->cursor);
4055- es->linelen++;
4068+ memmove(&vs->cbuf[vs->cursor + 1], &vs->cbuf[vs->cursor],
4069+ vs->linelen - vs->cursor);
4070+ vs->linelen++;
40564071 }
4057- es->cbuf[es->cursor++] = ch;
4058- if (insert == REPLACE && es->cursor > es->linelen)
4059- es->linelen++;
4072+ vs->cbuf[vs->cursor++] = ch;
4073+ if (insert == REPLACE && vs->cursor > vs->linelen)
4074+ vs->linelen++;
40604075 expanded = NONE;
40614076 }
40624077 return (0);
@@ -4075,18 +4090,18 @@ vi_cmd(int argcnt, const char *cmd)
40754090
40764091 if (is_move(*cmd)) {
40774092 if ((cur = domove(argcnt, cmd, 0)) >= 0) {
4078- if (cur == es->linelen && cur != 0)
4093+ if (cur == vs->linelen && cur != 0)
40794094 cur--;
4080- es->cursor = cur;
4095+ vs->cursor = cur;
40814096 } else
40824097 return (-1);
40834098 } else {
40844099 /* Don't save state in middle of macro.. */
40854100 if (is_undoable(*cmd) && !macro.p) {
4086- undo->winleft = es->winleft;
4087- memmove(undo->cbuf, es->cbuf, es->linelen);
4088- undo->linelen = es->linelen;
4089- undo->cursor = es->cursor;
4101+ undo->winleft = vs->winleft;
4102+ memmove(undo->cbuf, vs->cbuf, vs->linelen);
4103+ undo->linelen = vs->linelen;
4104+ undo->cursor = vs->cursor;
40904105 lastac = argcnt;
40914106 memmove(lastcmd, cmd, MAXVICMD);
40924107 }
@@ -4141,8 +4156,8 @@ vi_cmd(int argcnt, const char *cmd)
41414156 case 'a':
41424157 modified = 1;
41434158 hnum = hlast;
4144- if (es->linelen != 0)
4145- es->cursor++;
4159+ if (vs->linelen != 0)
4160+ vs->cursor++;
41464161 insert = INSERT;
41474162 break;
41484163
@@ -4150,13 +4165,13 @@ vi_cmd(int argcnt, const char *cmd)
41504165 modified = 1;
41514166 hnum = hlast;
41524167 del_range(0, 0);
4153- es->cursor = es->linelen;
4168+ vs->cursor = vs->linelen;
41544169 insert = INSERT;
41554170 break;
41564171
41574172 case 'S':
4158- es->cursor = domove(1, "^", 1);
4159- del_range(es->cursor, es->linelen);
4173+ vs->cursor = domove(1, "^", 1);
4174+ del_range(vs->cursor, vs->linelen);
41604175 modified = 1;
41614176 hnum = hlast;
41624177 insert = INSERT;
@@ -4172,7 +4187,7 @@ vi_cmd(int argcnt, const char *cmd)
41724187 case 'y':
41734188 if (*cmd == cmd[1]) {
41744189 c1 = *cmd == 'c' ? domove(1, "^", 1) : 0;
4175- c2 = es->linelen;
4190+ c2 = vs->linelen;
41764191 } else if (!is_move(cmd[1]))
41774192 return (-1);
41784193 else {
@@ -4180,18 +4195,18 @@ vi_cmd(int argcnt, const char *cmd)
41804195 return (-1);
41814196 if (*cmd == 'c' &&
41824197 (cmd[1] == 'w' || cmd[1] == 'W') &&
4183- !ksh_isspace(es->cbuf[es->cursor])) {
4198+ !ksh_isspace(vs->cbuf[vs->cursor])) {
41844199 do {
41854200 --ncursor;
4186- } while (ksh_isspace(es->cbuf[ncursor]));
4201+ } while (ksh_isspace(vs->cbuf[ncursor]));
41874202 ncursor++;
41884203 }
4189- if (ncursor > es->cursor) {
4190- c1 = es->cursor;
4204+ if (ncursor > vs->cursor) {
4205+ c1 = vs->cursor;
41914206 c2 = ncursor;
41924207 } else {
41934208 c1 = ncursor;
4194- c2 = es->cursor;
4209+ c2 = vs->cursor;
41954210 if (cmd[1] == '%')
41964211 c2++;
41974212 }
@@ -4200,7 +4215,7 @@ vi_cmd(int argcnt, const char *cmd)
42004215 yank_range(c1, c2);
42014216 if (*cmd != 'y') {
42024217 del_range(c1, c2);
4203- es->cursor = c1;
4218+ vs->cursor = c1;
42044219 }
42054220 if (*cmd == 'c') {
42064221 modified = 1;
@@ -4212,13 +4227,13 @@ vi_cmd(int argcnt, const char *cmd)
42124227 case 'p':
42134228 modified = 1;
42144229 hnum = hlast;
4215- if (es->linelen != 0)
4216- es->cursor++;
4230+ if (vs->linelen != 0)
4231+ vs->cursor++;
42174232 while (putbuf(ybuf, yanklen, false) == 0 &&
42184233 --argcnt > 0)
42194234 ;
4220- if (es->cursor != 0)
4221- es->cursor--;
4235+ if (vs->cursor != 0)
4236+ vs->cursor--;
42224237 if (argcnt != 0)
42234238 return (-1);
42244239 break;
@@ -4230,8 +4245,8 @@ vi_cmd(int argcnt, const char *cmd)
42304245 while (putbuf(ybuf, yanklen, false) == 0 &&
42314246 --argcnt > 0)
42324247 any = 1;
4233- if (any && es->cursor != 0)
4234- es->cursor--;
4248+ if (any && vs->cursor != 0)
4249+ vs->cursor--;
42354250 if (argcnt != 0)
42364251 return (-1);
42374252 break;
@@ -4239,15 +4254,15 @@ vi_cmd(int argcnt, const char *cmd)
42394254 case 'C':
42404255 modified = 1;
42414256 hnum = hlast;
4242- del_range(es->cursor, es->linelen);
4257+ del_range(vs->cursor, vs->linelen);
42434258 insert = INSERT;
42444259 break;
42454260
42464261 case 'D':
4247- yank_range(es->cursor, es->linelen);
4248- del_range(es->cursor, es->linelen);
4249- if (es->cursor != 0)
4250- es->cursor--;
4262+ yank_range(vs->cursor, vs->linelen);
4263+ del_range(vs->cursor, vs->linelen);
4264+ if (vs->cursor != 0)
4265+ vs->cursor--;
42514266 break;
42524267
42534268 case 'g':
@@ -4276,7 +4291,7 @@ vi_cmd(int argcnt, const char *cmd)
42764291 case 'I':
42774292 modified = 1;
42784293 hnum = hlast;
4279- es->cursor = domove(1, "^", 1);
4294+ vs->cursor = domove(1, "^", 1);
42804295 insert = INSERT;
42814296 break;
42824297
@@ -4303,7 +4318,7 @@ vi_cmd(int argcnt, const char *cmd)
43034318 break;
43044319
43054320 case 'r':
4306- if (es->linelen == 0)
4321+ if (vs->linelen == 0)
43074322 return (-1);
43084323 modified = 1;
43094324 hnum = hlast;
@@ -4312,11 +4327,11 @@ vi_cmd(int argcnt, const char *cmd)
43124327 else {
43134328 int n;
43144329
4315- if (es->cursor + argcnt > es->linelen)
4330+ if (vs->cursor + argcnt > vs->linelen)
43164331 return (-1);
43174332 for (n = 0; n < argcnt; ++n)
4318- es->cbuf[es->cursor + n] = cmd[1];
4319- es->cursor += n - 1;
4333+ vs->cbuf[vs->cursor + n] = cmd[1];
4334+ vs->cursor += n - 1;
43204335 }
43214336 break;
43224337
@@ -4327,66 +4342,66 @@ vi_cmd(int argcnt, const char *cmd)
43274342 break;
43284343
43294344 case 's':
4330- if (es->linelen == 0)
4345+ if (vs->linelen == 0)
43314346 return (-1);
43324347 modified = 1;
43334348 hnum = hlast;
4334- if (es->cursor + argcnt > es->linelen)
4335- argcnt = es->linelen - es->cursor;
4336- del_range(es->cursor, es->cursor + argcnt);
4349+ if (vs->cursor + argcnt > vs->linelen)
4350+ argcnt = vs->linelen - vs->cursor;
4351+ del_range(vs->cursor, vs->cursor + argcnt);
43374352 insert = INSERT;
43384353 break;
43394354
43404355 case 'v':
43414356 if (!argcnt) {
4342- if (es->linelen == 0)
4357+ if (vs->linelen == 0)
43434358 return (-1);
43444359 if (modified) {
4345- es->cbuf[es->linelen] = '\0';
4346- histsave(&source->line, es->cbuf,
4360+ vs->cbuf[vs->linelen] = '\0';
4361+ histsave(&source->line, vs->cbuf,
43474362 HIST_STORE, true);
43484363 } else
43494364 argcnt = source->line + 1 -
43504365 (hlast - hnum);
43514366 }
43524367 if (argcnt)
4353- shf_snprintf(es->cbuf, es->cbufsize, Tf_sd,
4368+ shf_snprintf(vs->cbuf, vs->cbufsize, Tf_sd,
43544369 "fc -e ${VISUAL:-${EDITOR:-vi}} --",
43554370 argcnt);
43564371 else
4357- strlcpy(es->cbuf,
4372+ strlcpy(vs->cbuf,
43584373 "fc -e ${VISUAL:-${EDITOR:-vi}} --",
4359- es->cbufsize);
4360- es->linelen = strlen(es->cbuf);
4374+ vs->cbufsize);
4375+ vs->linelen = strlen(vs->cbuf);
43614376 return (2);
43624377
43634378 case 'x':
4364- if (es->linelen == 0)
4379+ if (vs->linelen == 0)
43654380 return (-1);
43664381 modified = 1;
43674382 hnum = hlast;
4368- if (es->cursor + argcnt > es->linelen)
4369- argcnt = es->linelen - es->cursor;
4370- yank_range(es->cursor, es->cursor + argcnt);
4371- del_range(es->cursor, es->cursor + argcnt);
4383+ if (vs->cursor + argcnt > vs->linelen)
4384+ argcnt = vs->linelen - vs->cursor;
4385+ yank_range(vs->cursor, vs->cursor + argcnt);
4386+ del_range(vs->cursor, vs->cursor + argcnt);
43724387 break;
43734388
43744389 case 'X':
4375- if (es->cursor > 0) {
4390+ if (vs->cursor > 0) {
43764391 modified = 1;
43774392 hnum = hlast;
4378- if (es->cursor < argcnt)
4379- argcnt = es->cursor;
4380- yank_range(es->cursor - argcnt, es->cursor);
4381- del_range(es->cursor - argcnt, es->cursor);
4382- es->cursor -= argcnt;
4393+ if (vs->cursor < argcnt)
4394+ argcnt = vs->cursor;
4395+ yank_range(vs->cursor - argcnt, vs->cursor);
4396+ del_range(vs->cursor - argcnt, vs->cursor);
4397+ vs->cursor -= argcnt;
43834398 } else
43844399 return (-1);
43854400 break;
43864401
43874402 case 'u':
4388- t = es;
4389- es = undo;
4403+ t = vs;
4404+ vs = undo;
43904405 undo = t;
43914406 break;
43924407
@@ -4434,7 +4449,7 @@ vi_cmd(int argcnt, const char *cmd)
44344449 }
44354450 if (argcnt >= 2) {
44364451 /* flag from cursor-up command */
4437- es->cursor = argcnt - 2;
4452+ vs->cursor = argcnt - 2;
44384453 return (0);
44394454 }
44404455 break;
@@ -4475,16 +4490,16 @@ vi_cmd(int argcnt, const char *cmd)
44754490 }
44764491 modified = 1;
44774492 hnum = hlast;
4478- if (es->cursor != es->linelen)
4479- es->cursor++;
4493+ if (vs->cursor != vs->linelen)
4494+ vs->cursor++;
44804495 while (*p && !issp(*p)) {
44814496 argcnt++;
44824497 p++;
44834498 }
44844499 if (putbuf(T1space, 1, false) != 0 ||
44854500 putbuf(sp, argcnt, false) != 0) {
4486- if (es->cursor != 0)
4487- es->cursor--;
4501+ if (vs->cursor != 0)
4502+ vs->cursor--;
44884503 return (-1);
44894504 }
44904505 insert = INSERT;
@@ -4496,10 +4511,10 @@ vi_cmd(int argcnt, const char *cmd)
44964511 char *p;
44974512 int i;
44984513
4499- if (es->linelen == 0)
4514+ if (vs->linelen == 0)
45004515 return (-1);
45014516 for (i = 0; i < argcnt; i++) {
4502- p = &es->cbuf[es->cursor];
4517+ p = &vs->cbuf[vs->cursor];
45034518 if (ksh_islower(*p)) {
45044519 modified = 1;
45054520 hnum = hlast;
@@ -4509,18 +4524,18 @@ vi_cmd(int argcnt, const char *cmd)
45094524 hnum = hlast;
45104525 *p = ksh_tolower(*p);
45114526 }
4512- if (es->cursor < es->linelen - 1)
4513- es->cursor++;
4527+ if (vs->cursor < vs->linelen - 1)
4528+ vs->cursor++;
45144529 }
45154530 break;
45164531 }
45174532
45184533 case '#':
45194534 {
4520- int ret = x_do_comment(es->cbuf, es->cbufsize,
4521- &es->linelen);
4535+ int ret = x_do_comment(vs->cbuf, vs->cbufsize,
4536+ &vs->linelen);
45224537 if (ret >= 0)
4523- es->cursor = 0;
4538+ vs->cursor = 0;
45244539 return (ret);
45254540 }
45264541
@@ -4528,7 +4543,7 @@ vi_cmd(int argcnt, const char *cmd)
45284543 case '=':
45294544 /* Nonstandard vi/ksh */
45304545 case CTRL('e'):
4531- print_expansions(es, 1);
4546+ print_expansions(vs, 1);
45324547 break;
45334548
45344549
@@ -4564,13 +4579,13 @@ vi_cmd(int argcnt, const char *cmd)
45644579 case '[':
45654580 case 'O':
45664581 state = VPREFIX2;
4567- if (es->linelen != 0)
4568- es->cursor++;
4582+ if (vs->linelen != 0)
4583+ vs->cursor++;
45694584 insert = INSERT;
45704585 return (0);
45714586 }
4572- if (insert == 0 && es->cursor != 0 && es->cursor >= es->linelen)
4573- es->cursor--;
4587+ if (insert == 0 && vs->cursor != 0 && vs->cursor >= vs->linelen)
4588+ vs->cursor--;
45744589 }
45754590 return (0);
45764591 }
@@ -4583,30 +4598,30 @@ domove(int argcnt, const char *cmd, int sub)
45834598
45844599 switch (*cmd) {
45854600 case 'b':
4586- if (!sub && es->cursor == 0)
4601+ if (!sub && vs->cursor == 0)
45874602 return (-1);
45884603 ncursor = backword(argcnt);
45894604 break;
45904605
45914606 case 'B':
4592- if (!sub && es->cursor == 0)
4607+ if (!sub && vs->cursor == 0)
45934608 return (-1);
45944609 ncursor = Backword(argcnt);
45954610 break;
45964611
45974612 case 'e':
4598- if (!sub && es->cursor + 1 >= es->linelen)
4613+ if (!sub && vs->cursor + 1 >= vs->linelen)
45994614 return (-1);
46004615 ncursor = endword(argcnt);
4601- if (sub && ncursor < es->linelen)
4616+ if (sub && ncursor < vs->linelen)
46024617 ncursor++;
46034618 break;
46044619
46054620 case 'E':
4606- if (!sub && es->cursor + 1 >= es->linelen)
4621+ if (!sub && vs->cursor + 1 >= vs->linelen)
46074622 return (-1);
46084623 ncursor = Endword(argcnt);
4609- if (sub && ncursor < es->linelen)
4624+ if (sub && ncursor < vs->linelen)
46104625 ncursor++;
46114626 break;
46124627
@@ -4634,32 +4649,32 @@ domove(int argcnt, const char *cmd, int sub)
46344649
46354650 case 'h':
46364651 case CTRL('h'):
4637- if (!sub && es->cursor == 0)
4652+ if (!sub && vs->cursor == 0)
46384653 return (-1);
4639- ncursor = es->cursor - argcnt;
4654+ ncursor = vs->cursor - argcnt;
46404655 if (ncursor < 0)
46414656 ncursor = 0;
46424657 break;
46434658
46444659 case ' ':
46454660 case 'l':
4646- if (!sub && es->cursor + 1 >= es->linelen)
4661+ if (!sub && vs->cursor + 1 >= vs->linelen)
46474662 return (-1);
4648- if (es->linelen != 0) {
4649- ncursor = es->cursor + argcnt;
4650- if (ncursor > es->linelen)
4651- ncursor = es->linelen;
4663+ if (vs->linelen != 0) {
4664+ ncursor = vs->cursor + argcnt;
4665+ if (ncursor > vs->linelen)
4666+ ncursor = vs->linelen;
46524667 }
46534668 break;
46544669
46554670 case 'w':
4656- if (!sub && es->cursor + 1 >= es->linelen)
4671+ if (!sub && vs->cursor + 1 >= vs->linelen)
46574672 return (-1);
46584673 ncursor = forwword(argcnt);
46594674 break;
46604675
46614676 case 'W':
4662- if (!sub && es->cursor + 1 >= es->linelen)
4677+ if (!sub && vs->cursor + 1 >= vs->linelen)
46634678 return (-1);
46644679 ncursor = Forwword(argcnt);
46654680 break;
@@ -4670,43 +4685,43 @@ domove(int argcnt, const char *cmd, int sub)
46704685
46714686 case '^':
46724687 ncursor = 0;
4673- while (ncursor < es->linelen - 1 &&
4674- ksh_isspace(es->cbuf[ncursor]))
4688+ while (ncursor < vs->linelen - 1 &&
4689+ ksh_isspace(vs->cbuf[ncursor]))
46754690 ncursor++;
46764691 break;
46774692
46784693 case '|':
46794694 ncursor = argcnt;
4680- if (ncursor > es->linelen)
4681- ncursor = es->linelen;
4695+ if (ncursor > vs->linelen)
4696+ ncursor = vs->linelen;
46824697 if (ncursor)
46834698 ncursor--;
46844699 break;
46854700
46864701 case '$':
4687- if (es->linelen != 0)
4688- ncursor = es->linelen;
4702+ if (vs->linelen != 0)
4703+ ncursor = vs->linelen;
46894704 else
46904705 ncursor = 0;
46914706 break;
46924707
46934708 case '%':
4694- ncursor = es->cursor;
4695- while (ncursor < es->linelen &&
4696- (i = bracktype(es->cbuf[ncursor])) == 0)
4709+ ncursor = vs->cursor;
4710+ while (ncursor < vs->linelen &&
4711+ (i = bracktype(vs->cbuf[ncursor])) == 0)
46974712 ncursor++;
4698- if (ncursor == es->linelen)
4713+ if (ncursor == vs->linelen)
46994714 return (-1);
47004715 bcount = 1;
47014716 do {
47024717 if (i > 0) {
4703- if (++ncursor >= es->linelen)
4718+ if (++ncursor >= vs->linelen)
47044719 return (-1);
47054720 } else {
47064721 if (--ncursor < 0)
47074722 return (-1);
47084723 }
4709- t = bracktype(es->cbuf[ncursor]);
4724+ t = bracktype(vs->cbuf[ncursor]);
47104725 if (t == i)
47114726 bcount++;
47124727 else if (t == -i)
@@ -4728,8 +4743,8 @@ redo_insert(int count)
47284743 while (count-- > 0)
47294744 if (putbuf(ibuf, inslen, tobool(insert == REPLACE)) != 0)
47304745 return (-1);
4731- if (es->cursor > 0)
4732- es->cursor--;
4746+ if (vs->cursor > 0)
4747+ vs->cursor--;
47334748 insert = 0;
47344749 return (0);
47354750 }
@@ -4739,7 +4754,7 @@ yank_range(int a, int b)
47394754 {
47404755 yanklen = b - a;
47414756 if (yanklen != 0)
4742- memmove(ybuf, &es->cbuf[a], yanklen);
4757+ memmove(ybuf, &vs->cbuf[a], yanklen);
47434758 }
47444759
47454760 static int
@@ -4777,17 +4792,17 @@ bracktype(int ch)
47774792 static void
47784793 save_cbuf(void)
47794794 {
4780- memmove(holdbufp, es->cbuf, es->linelen);
4781- holdlen = es->linelen;
4795+ memmove(holdbufp, vs->cbuf, vs->linelen);
4796+ holdlen = vs->linelen;
47824797 holdbufp[holdlen] = '\0';
47834798 }
47844799
47854800 static void
47864801 restore_cbuf(void)
47874802 {
4788- es->cursor = 0;
4789- es->linelen = holdlen;
4790- memmove(es->cbuf, holdbufp, holdlen);
4803+ vs->cursor = 0;
4804+ vs->linelen = holdlen;
4805+ memmove(vs->cbuf, holdbufp, holdlen);
47914806 }
47924807
47934808 /* return a new edstate */
@@ -4838,28 +4853,28 @@ putbuf(const char *buf, ssize_t len, bool repl)
48384853 if (len == 0)
48394854 return (0);
48404855 if (repl) {
4841- if (es->cursor + len >= es->cbufsize)
4856+ if (vs->cursor + len >= vs->cbufsize)
48424857 return (-1);
4843- if (es->cursor + len > es->linelen)
4844- es->linelen = es->cursor + len;
4858+ if (vs->cursor + len > vs->linelen)
4859+ vs->linelen = vs->cursor + len;
48454860 } else {
4846- if (es->linelen + len >= es->cbufsize)
4861+ if (vs->linelen + len >= vs->cbufsize)
48474862 return (-1);
4848- memmove(&es->cbuf[es->cursor + len], &es->cbuf[es->cursor],
4849- es->linelen - es->cursor);
4850- es->linelen += len;
4863+ memmove(&vs->cbuf[vs->cursor + len], &vs->cbuf[vs->cursor],
4864+ vs->linelen - vs->cursor);
4865+ vs->linelen += len;
48514866 }
4852- memmove(&es->cbuf[es->cursor], buf, len);
4853- es->cursor += len;
4867+ memmove(&vs->cbuf[vs->cursor], buf, len);
4868+ vs->cursor += len;
48544869 return (0);
48554870 }
48564871
48574872 static void
48584873 del_range(int a, int b)
48594874 {
4860- if (es->linelen != b)
4861- memmove(&es->cbuf[a], &es->cbuf[b], es->linelen - b);
4862- es->linelen -= b - a;
4875+ if (vs->linelen != b)
4876+ memmove(&vs->cbuf[a], &vs->cbuf[b], vs->linelen - b);
4877+ vs->linelen -= b - a;
48634878 }
48644879
48654880 static int
@@ -4867,19 +4882,19 @@ findch(int ch, int cnt, bool forw, bool incl)
48674882 {
48684883 int ncursor;
48694884
4870- if (es->linelen == 0)
4885+ if (vs->linelen == 0)
48714886 return (-1);
4872- ncursor = es->cursor;
4887+ ncursor = vs->cursor;
48734888 while (cnt--) {
48744889 do {
48754890 if (forw) {
4876- if (++ncursor == es->linelen)
4891+ if (++ncursor == vs->linelen)
48774892 return (-1);
48784893 } else {
48794894 if (--ncursor < 0)
48804895 return (-1);
48814896 }
4882- } while (es->cbuf[ncursor] != ch);
4897+ } while (vs->cbuf[ncursor] != ch);
48834898 }
48844899 if (!incl) {
48854900 if (forw)
@@ -4895,19 +4910,19 @@ forwword(int argcnt)
48954910 {
48964911 int ncursor;
48974912
4898- ncursor = es->cursor;
4899- while (ncursor < es->linelen && argcnt--) {
4900- if (ksh_isalnux(es->cbuf[ncursor]))
4901- while (ncursor < es->linelen &&
4902- ksh_isalnux(es->cbuf[ncursor]))
4913+ ncursor = vs->cursor;
4914+ while (ncursor < vs->linelen && argcnt--) {
4915+ if (ksh_isalnux(vs->cbuf[ncursor]))
4916+ while (ncursor < vs->linelen &&
4917+ ksh_isalnux(vs->cbuf[ncursor]))
49034918 ncursor++;
4904- else if (!ksh_isspace(es->cbuf[ncursor]))
4905- while (ncursor < es->linelen &&
4906- !ksh_isalnux(es->cbuf[ncursor]) &&
4907- !ksh_isspace(es->cbuf[ncursor]))
4919+ else if (!ksh_isspace(vs->cbuf[ncursor]))
4920+ while (ncursor < vs->linelen &&
4921+ !ksh_isalnux(vs->cbuf[ncursor]) &&
4922+ !ksh_isspace(vs->cbuf[ncursor]))
49084923 ncursor++;
4909- while (ncursor < es->linelen &&
4910- ksh_isspace(es->cbuf[ncursor]))
4924+ while (ncursor < vs->linelen &&
4925+ ksh_isspace(vs->cbuf[ncursor]))
49114926 ncursor++;
49124927 }
49134928 return (ncursor);
@@ -4918,19 +4933,19 @@ backword(int argcnt)
49184933 {
49194934 int ncursor;
49204935
4921- ncursor = es->cursor;
4936+ ncursor = vs->cursor;
49224937 while (ncursor > 0 && argcnt--) {
4923- while (--ncursor > 0 && ksh_isspace(es->cbuf[ncursor]))
4938+ while (--ncursor > 0 && ksh_isspace(vs->cbuf[ncursor]))
49244939 ;
49254940 if (ncursor > 0) {
4926- if (ksh_isalnux(es->cbuf[ncursor]))
4941+ if (ksh_isalnux(vs->cbuf[ncursor]))
49274942 while (--ncursor >= 0 &&
4928- ksh_isalnux(es->cbuf[ncursor]))
4943+ ksh_isalnux(vs->cbuf[ncursor]))
49294944 ;
49304945 else
49314946 while (--ncursor >= 0 &&
4932- !ksh_isalnux(es->cbuf[ncursor]) &&
4933- !ksh_isspace(es->cbuf[ncursor]))
4947+ !ksh_isalnux(vs->cbuf[ncursor]) &&
4948+ !ksh_isspace(vs->cbuf[ncursor]))
49344949 ;
49354950 ncursor++;
49364951 }
@@ -4943,20 +4958,20 @@ endword(int argcnt)
49434958 {
49444959 int ncursor;
49454960
4946- ncursor = es->cursor;
4947- while (ncursor < es->linelen && argcnt--) {
4948- while (++ncursor < es->linelen - 1 &&
4949- ksh_isspace(es->cbuf[ncursor]))
4961+ ncursor = vs->cursor;
4962+ while (ncursor < vs->linelen && argcnt--) {
4963+ while (++ncursor < vs->linelen - 1 &&
4964+ ksh_isspace(vs->cbuf[ncursor]))
49504965 ;
4951- if (ncursor < es->linelen - 1) {
4952- if (ksh_isalnux(es->cbuf[ncursor]))
4953- while (++ncursor < es->linelen &&
4954- ksh_isalnux(es->cbuf[ncursor]))
4966+ if (ncursor < vs->linelen - 1) {
4967+ if (ksh_isalnux(vs->cbuf[ncursor]))
4968+ while (++ncursor < vs->linelen &&
4969+ ksh_isalnux(vs->cbuf[ncursor]))
49554970 ;
49564971 else
4957- while (++ncursor < es->linelen &&
4958- !ksh_isalnux(es->cbuf[ncursor]) &&
4959- !ksh_isspace(es->cbuf[ncursor]))
4972+ while (++ncursor < vs->linelen &&
4973+ !ksh_isalnux(vs->cbuf[ncursor]) &&
4974+ !ksh_isspace(vs->cbuf[ncursor]))
49604975 ;
49614976 ncursor--;
49624977 }
@@ -4969,13 +4984,13 @@ Forwword(int argcnt)
49694984 {
49704985 int ncursor;
49714986
4972- ncursor = es->cursor;
4973- while (ncursor < es->linelen && argcnt--) {
4974- while (ncursor < es->linelen &&
4975- !ksh_isspace(es->cbuf[ncursor]))
4987+ ncursor = vs->cursor;
4988+ while (ncursor < vs->linelen && argcnt--) {
4989+ while (ncursor < vs->linelen &&
4990+ !ksh_isspace(vs->cbuf[ncursor]))
49764991 ncursor++;
4977- while (ncursor < es->linelen &&
4978- ksh_isspace(es->cbuf[ncursor]))
4992+ while (ncursor < vs->linelen &&
4993+ ksh_isspace(vs->cbuf[ncursor]))
49794994 ncursor++;
49804995 }
49814996 return (ncursor);
@@ -4986,11 +5001,11 @@ Backword(int argcnt)
49865001 {
49875002 int ncursor;
49885003
4989- ncursor = es->cursor;
5004+ ncursor = vs->cursor;
49905005 while (ncursor > 0 && argcnt--) {
4991- while (--ncursor >= 0 && ksh_isspace(es->cbuf[ncursor]))
5006+ while (--ncursor >= 0 && ksh_isspace(vs->cbuf[ncursor]))
49925007 ;
4993- while (ncursor >= 0 && !ksh_isspace(es->cbuf[ncursor]))
5008+ while (ncursor >= 0 && !ksh_isspace(vs->cbuf[ncursor]))
49945009 ncursor--;
49955010 ncursor++;
49965011 }
@@ -5002,14 +5017,14 @@ Endword(int argcnt)
50025017 {
50035018 int ncursor;
50045019
5005- ncursor = es->cursor;
5006- while (ncursor < es->linelen - 1 && argcnt--) {
5007- while (++ncursor < es->linelen - 1 &&
5008- ksh_isspace(es->cbuf[ncursor]))
5020+ ncursor = vs->cursor;
5021+ while (ncursor < vs->linelen - 1 && argcnt--) {
5022+ while (++ncursor < vs->linelen - 1 &&
5023+ ksh_isspace(vs->cbuf[ncursor]))
50095024 ;
5010- if (ncursor < es->linelen - 1) {
5011- while (++ncursor < es->linelen &&
5012- !ksh_isspace(es->cbuf[ncursor]))
5025+ if (ncursor < vs->linelen - 1) {
5026+ while (++ncursor < vs->linelen &&
5027+ !ksh_isspace(vs->cbuf[ncursor]))
50135028 ;
50145029 ncursor--;
50155030 }
@@ -5036,10 +5051,10 @@ grabhist(int save, int n)
50365051 }
50375052 if (save)
50385053 save_cbuf();
5039- if ((es->linelen = strlen(hptr)) >= es->cbufsize)
5040- es->linelen = es->cbufsize - 1;
5041- memmove(es->cbuf, hptr, es->linelen);
5042- es->cursor = 0;
5054+ if ((vs->linelen = strlen(hptr)) >= vs->cbufsize)
5055+ vs->linelen = vs->cbufsize - 1;
5056+ memmove(vs->cbuf, hptr, vs->linelen);
5057+ vs->cursor = 0;
50435058 ohnum = n;
50445059 return (0);
50455060 }
@@ -5070,10 +5085,10 @@ grabsearch(int save, int start, int fwd, const char *pat)
50705085 save_cbuf();
50715086 histnum(hist);
50725087 hptr = *histpos();
5073- if ((es->linelen = strlen(hptr)) >= es->cbufsize)
5074- es->linelen = es->cbufsize - 1;
5075- memmove(es->cbuf, hptr, es->linelen);
5076- es->cursor = 0;
5088+ if ((vs->linelen = strlen(hptr)) >= vs->cbufsize)
5089+ vs->linelen = vs->cbufsize - 1;
5090+ memmove(vs->cbuf, hptr, vs->linelen);
5091+ vs->cursor = 0;
50775092 return (hist);
50785093 }
50795094
@@ -5108,12 +5123,12 @@ outofwin(void)
51085123 {
51095124 int cur, col;
51105125
5111- if (es->cursor < es->winleft)
5126+ if (vs->cursor < vs->winleft)
51125127 return (1);
51135128 col = 0;
5114- cur = es->winleft;
5115- while (cur < es->cursor)
5116- col = newcol((unsigned char)es->cbuf[cur++], col);
5129+ cur = vs->winleft;
5130+ while (cur < vs->cursor)
5131+ col = newcol((unsigned char)vs->cbuf[cur++], col);
51175132 if (col >= winwidth)
51185133 return (1);
51195134 return (0);
@@ -5128,19 +5143,19 @@ rewindow(void)
51285143
51295144 holdcur1 = holdcur2 = tcur = 0;
51305145 holdcol1 = holdcol2 = tcol = 0;
5131- while (tcur < es->cursor) {
5146+ while (tcur < vs->cursor) {
51325147 if (tcol - holdcol2 > winwidth / 2) {
51335148 holdcur1 = holdcur2;
51345149 holdcol1 = holdcol2;
51355150 holdcur2 = tcur;
51365151 holdcol2 = tcol;
51375152 }
5138- tcol = newcol((unsigned char)es->cbuf[tcur++], tcol);
5153+ tcol = newcol((unsigned char)vs->cbuf[tcur++], tcol);
51395154 }
51405155 while (tcol - holdcol1 > winwidth / 2)
5141- holdcol1 = newcol((unsigned char)es->cbuf[holdcur1++],
5156+ holdcol1 = newcol((unsigned char)vs->cbuf[holdcur1++],
51425157 holdcol1);
5143- es->winleft = holdcur1;
5158+ vs->winleft = holdcur1;
51445159 }
51455160
51465161 static int
@@ -5161,13 +5176,13 @@ display(char *wb1, char *wb2, int leftside)
51615176 int moreright;
51625177
51635178 col = 0;
5164- cur = es->winleft;
5179+ cur = vs->winleft;
51655180 moreright = 0;
51665181 twb1 = wb1;
5167- while (col < winwidth && cur < es->linelen) {
5168- if (cur == es->cursor && leftside)
5182+ while (col < winwidth && cur < vs->linelen) {
5183+ if (cur == vs->cursor && leftside)
51695184 ncol = col + pwidth;
5170- if ((ch = es->cbuf[cur]) == '\t')
5185+ if ((ch = vs->cbuf[cur]) == '\t')
51715186 do {
51725187 *twb1++ = ' ';
51735188 } while (++col < winwidth && (col & 7) != 0);
@@ -5183,11 +5198,11 @@ display(char *wb1, char *wb2, int leftside)
51835198 col++;
51845199 }
51855200 }
5186- if (cur == es->cursor && !leftside)
5201+ if (cur == vs->cursor && !leftside)
51875202 ncol = col + pwidth - 1;
51885203 cur++;
51895204 }
5190- if (cur == es->cursor)
5205+ if (cur == vs->cursor)
51915206 ncol = col + pwidth;
51925207 if (col < winwidth) {
51935208 while (col < winwidth) {
@@ -5213,13 +5228,13 @@ display(char *wb1, char *wb2, int leftside)
52135228 twb2++;
52145229 col++;
52155230 }
5216- if (es->winleft > 0 && moreright)
5231+ if (vs->winleft > 0 && moreright)
52175232 /*
52185233 * POSIX says to use * for this but that is a globbing
52195234 * character and may confuse people; + is more innocuous
52205235 */
52215236 mc = '+';
5222- else if (es->winleft > 0)
5237+ else if (vs->winleft > 0)
52235238 mc = '<';
52245239 else if (moreright)
52255240 mc = '>';
@@ -5267,7 +5282,7 @@ expand_word(int cmd)
52675282
52685283 /* Undo previous expansion */
52695284 if (cmd == 0 && expanded == EXPAND && buf) {
5270- restore_edstate(es, buf);
5285+ restore_edstate(vs, buf);
52715286 buf = 0;
52725287 expanded = NONE;
52735288 return (0);
@@ -5278,17 +5293,17 @@ expand_word(int cmd)
52785293 }
52795294
52805295 i = XCF_COMMAND_FILE | XCF_FULLPATH;
5281- nwords = x_cf_glob(&i, es->cbuf, es->linelen, es->cursor,
5296+ nwords = x_cf_glob(&i, vs->cbuf, vs->linelen, vs->cursor,
52825297 &start, &end, &words);
52835298 if (nwords == 0) {
52845299 vi_error();
52855300 return (-1);
52865301 }
52875302
5288- buf = save_edstate(es);
5303+ buf = save_edstate(vs);
52895304 expanded = EXPAND;
52905305 del_range(start, end);
5291- es->cursor = start;
5306+ vs->cursor = start;
52925307 i = 0;
52935308 while (i < nwords) {
52945309 if (x_escape(words[i], strlen(words[i]), x_vi_putbuf) != 0) {
@@ -5302,7 +5317,7 @@ expand_word(int cmd)
53025317 }
53035318 i = buf->cursor - end;
53045319 if (rval == 0 && i > 0)
5305- es->cursor += i;
5320+ vs->cursor += i;
53065321 modified = 1;
53075322 hnum = hlast;
53085323 insert = INSERT;
@@ -5328,7 +5343,7 @@ complete_word(int cmd, int count)
53285343 return (0);
53295344 }
53305345 if (cmd == 0 && expanded == PRINT && buf) {
5331- restore_edstate(es, buf);
5346+ restore_edstate(vs, buf);
53325347 buf = 0;
53335348 expanded = NONE;
53345349 return (0);
@@ -5345,7 +5360,7 @@ complete_word(int cmd, int count)
53455360 flags = XCF_COMMAND_FILE;
53465361 if (count)
53475362 flags |= XCF_FULLPATH;
5348- nwords = x_cf_glob(&flags, es->cbuf, es->linelen, es->cursor,
5363+ nwords = x_cf_glob(&flags, vs->cbuf, vs->linelen, vs->cursor,
53495364 &start, &end, &words);
53505365 if (nwords == 0) {
53515366 vi_error();
@@ -5390,9 +5405,9 @@ complete_word(int cmd, int count)
53905405 is_unique = nwords == 1;
53915406 }
53925407
5393- buf = save_edstate(es);
5408+ buf = save_edstate(vs);
53945409 del_range(start, end);
5395- es->cursor = start;
5410+ vs->cursor = start;
53965411
53975412 /*
53985413 * escape all shell-sensitive characters and put the result into
@@ -5544,12 +5559,13 @@ x_eval_region_helper(const char *cmd, size_t len)
55445559 if (!kshsetjmp(e->jbuf)) {
55455560 char *wds = alloc(len + 3, ATEMP);
55465561
5547- wds[0] = FUNSUB;
5562+ wds[0] = FUNASUB;
55485563 memcpy(wds + 1, cmd, len);
55495564 wds[len + 1] = '\0';
55505565 wds[len + 2] = EOS;
55515566
55525567 cp = evalstr(wds, DOSCALAR);
5568+ afree(wds, ATEMP);
55535569 strdupx(cp, cp, AEDIT);
55545570 } else
55555571 cp = NULL;
--- a/src/eval.c
+++ b/src/eval.c
@@ -2,7 +2,7 @@
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5- * 2011, 2012, 2013, 2014, 2015, 2016
5+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
66 * mirabilos <m@mirbsd.org>
77 *
88 * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.194 2016/11/11 23:31:34 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.201 2017/04/06 01:59:54 tg Exp $");
2727
2828 /*
2929 * string expansion
@@ -301,25 +301,36 @@ expand(
301301 word = IFS_WORD;
302302 quote = st->quotew;
303303 continue;
304+ case COMASUB:
304305 case COMSUB:
306+ case FUNASUB:
305307 case FUNSUB:
306308 case VALSUB:
307309 tilde_ok = 0;
308310 if (f & DONTRUNCOMMAND) {
309311 word = IFS_WORD;
310312 *dp++ = '$';
311- *dp++ = c == COMSUB ? '(' : '{';
312- if (c != COMSUB)
313- *dp++ = c == FUNSUB ? ' ' : '|';
313+ switch (c) {
314+ case COMASUB:
315+ case COMSUB:
316+ *dp++ = '(';
317+ c = ')';
318+ break;
319+ case FUNASUB:
320+ case FUNSUB:
321+ case VALSUB:
322+ *dp++ = '{';
323+ *dp++ = c == VALSUB ? '|' : ' ';
324+ c = '}';
325+ break;
326+ }
314327 while (*sp != '\0') {
315328 Xcheck(ds, dp);
316329 *dp++ = *sp++;
317330 }
318- if (c != COMSUB) {
331+ if (c == '}')
319332 *dp++ = ';';
320- *dp++ = '}';
321- } else
322- *dp++ = ')';
333+ *dp++ = c;
323334 } else {
324335 type = comsub(&x, sp, c);
325336 if (type != XBASE && (f & DOBLANK))
@@ -625,13 +636,12 @@ expand(
625636 break;
626637 case '=':
627638 /*
628- * Enabling tilde expansion
629- * after :s here is
630- * non-standard ksh, but is
631- * consistent with rules for
632- * other assignments. Not
633- * sure what POSIX thinks of
634- * this.
639+ * Tilde expansion for string
640+ * variables in POSIX mode is
641+ * governed by Austinbug 351.
642+ * In non-POSIX mode historic
643+ * ksh behaviour (enable it!)
644+ * us followed.
635645 * Not doing tilde expansion
636646 * for integer variables is a
637647 * non-POSIX thing - makes
@@ -640,7 +650,7 @@ expand(
640650 */
641651 if (!(x.var->flag & INTEGER))
642652 f |= DOASNTILDE | DOTILDE;
643- f |= DOTEMP;
653+ f |= DOTEMP | DOSCALAR;
644654 /*
645655 * These will be done after the
646656 * value has been assigned.
@@ -880,10 +890,30 @@ expand(
880890 c = '\n';
881891 --newlines;
882892 } else {
883- while ((c = shf_getc(x.u.shf)) == 0 || c == '\n')
893+ while ((c = shf_getc(x.u.shf)) == 0 ||
894+#ifdef MKSH_WITH_TEXTMODE
895+ c == '\r' ||
896+#endif
897+ c == '\n') {
898+#ifdef MKSH_WITH_TEXTMODE
899+ if (c == '\r') {
900+ c = shf_getc(x.u.shf);
901+ switch (c) {
902+ case '\n':
903+ break;
904+ default:
905+ shf_ungetc(c, x.u.shf);
906+ /* FALLTHROUGH */
907+ case -1:
908+ c = '\r';
909+ break;
910+ }
911+ }
912+#endif
884913 if (c == '\n')
885914 /* save newlines */
886915 newlines++;
916+ }
887917 if (newlines && c != -1) {
888918 shf_ungetc(c, x.u.shf);
889919 c = '\n';
@@ -1197,7 +1227,7 @@ varsub(Expand *xp, const char *sp, const char *word,
11971227 } else if (ctype(c, C_SUBOP1)) {
11981228 slen += 2;
11991229 stype |= c;
1200- } else if (ctype(c, C_SUBOP2)) {
1230+ } else if (ksh_issubop2(c)) {
12011231 /* Note: ksh88 allows :%, :%%, etc */
12021232 slen += 2;
12031233 stype = c;
@@ -1207,12 +1237,16 @@ varsub(Expand *xp, const char *sp, const char *word,
12071237 }
12081238 } else if (c == '@') {
12091239 /* @x where x is command char */
1210- slen += 2;
1211- stype |= 0x100;
1212- if (word[slen] == CHAR) {
1213- stype |= word[slen + 1];
1214- slen += 2;
1240+ switch (c = word[slen + 2] == CHAR ? word[slen + 3] : 0) {
1241+ case '#':
1242+ case '/':
1243+ case 'Q':
1244+ break;
1245+ default:
1246+ return (-1);
12151247 }
1248+ stype |= 0x100 | c;
1249+ slen += 4;
12161250 } else if (stype)
12171251 /* : is not ok */
12181252 return (-1);
@@ -1301,7 +1335,7 @@ varsub(Expand *xp, const char *sp, const char *word,
13011335
13021336 c = stype & 0x7F;
13031337 /* test the compiler's code generator */
1304- if (((stype < 0x100) && (ctype(c, C_SUBOP2) ||
1338+ if (((stype < 0x100) && (ksh_issubop2(c) ||
13051339 (((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
13061340 (state != XARG || (ifs0 || xp->split ?
13071341 (xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
@@ -1311,7 +1345,7 @@ varsub(Expand *xp, const char *sp, const char *word,
13111345 /* expand word instead of variable value */
13121346 state = XBASE;
13131347 if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
1314- (ctype(c, C_SUBOP2) || (state != XBASE && c != '+')))
1348+ (ksh_issubop2(c) || (state != XBASE && c != '+')))
13151349 errorf(Tf_parm, sp);
13161350 *stypep = stype;
13171351 *slenp = slen;
@@ -1322,17 +1356,28 @@ varsub(Expand *xp, const char *sp, const char *word,
13221356 * Run the command in $(...) and read its output.
13231357 */
13241358 static int
1325-comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
1359+comsub(Expand *xp, const char *cp, int fn)
13261360 {
13271361 Source *s, *sold;
13281362 struct op *t;
13291363 struct shf *shf;
1364+ bool doalias = false;
13301365 uint8_t old_utfmode = UTFMODE;
13311366
1367+ switch (fn) {
1368+ case COMASUB:
1369+ fn = COMSUB;
1370+ if (0)
1371+ /* FALLTHROUGH */
1372+ case FUNASUB:
1373+ fn = FUNSUB;
1374+ doalias = true;
1375+ }
1376+
13321377 s = pushs(SSTRING, ATEMP);
13331378 s->start = s->str = cp;
13341379 sold = source;
1335- t = compile(s, true);
1380+ t = compile(s, true, doalias);
13361381 afree(s, ATEMP);
13371382 source = sold;
13381383
@@ -1713,7 +1758,7 @@ maybe_expand_tilde(const char *p, XString *dsp, char **dpp, bool isassign)
17131758
17141759 Xinit(ts, tp, 16, ATEMP);
17151760 /* : only for DOASNTILDE form */
1716- while (p[0] == CHAR && !mksh_cdirsep(p[1]) &&
1761+ while (p[0] == CHAR && /* not cdirsep */ p[1] != '/' &&
17171762 (!isassign || p[1] != ':')) {
17181763 Xcheck(ts, tp);
17191764 *tp++ = p[1];
--- a/src/exec.c
+++ b/src/exec.c
@@ -2,7 +2,7 @@
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5- * 2011, 2012, 2013, 2014, 2015, 2016
5+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
66 * mirabilos <m@mirbsd.org>
77 *
88 * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.186 2016/11/11 23:31:34 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.196 2017/04/12 16:46:21 tg Exp $");
2727
2828 #ifndef MKSH_DEFAULT_EXECSHELL
2929 #define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
@@ -376,9 +376,8 @@ execute(struct op * volatile t,
376376 if (t->right == NULL)
377377 /* should be error */
378378 break;
379- rv = execute(t->left, XERROK, NULL) == 0 ?
380- execute(t->right->left, flags & XERROK, xerrok) :
381- execute(t->right->right, flags & XERROK, xerrok);
379+ rv = execute(execute(t->left, XERROK, NULL) == 0 ?
380+ t->right->left : t->right->right, flags & XERROK, xerrok);
382381 break;
383382
384383 case TCASE:
@@ -806,7 +805,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
806805 /* NOTREACHED */
807806 default:
808807 quitenv(NULL);
809- internal_errorf(Tf_sd, "CFUNC", i);
808+ internal_errorf(Tunexpected_type, Tunwind, Tfunction, i);
810809 }
811810 break;
812811 }
@@ -889,6 +888,9 @@ scriptexec(struct op *tp, const char **ap)
889888 unsigned short m;
890889 ssize_t n;
891890
891+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
892+ setmode(fd, O_TEXT);
893+#endif
892894 /* read first couple of octets from file */
893895 n = read(fd, buf, sizeof(buf) - 1);
894896 close(fd);
@@ -944,6 +946,17 @@ scriptexec(struct op *tp, const char **ap)
944946 if (*cp)
945947 *tp->args-- = (char *)cp;
946948 }
949+#ifdef __OS2__
950+ /*
951+ * Search shell/interpreter name without directory in PATH
952+ * if specified path does not exist
953+ */
954+ if (mksh_vdirsep(sh) && !search_path(sh, path, X_OK, NULL)) {
955+ cp = search_path(_getname(sh), path, X_OK, NULL);
956+ if (cp)
957+ sh = cp;
958+ }
959+#endif
947960 goto nomagic;
948961 noshebang:
949962 m = buf[0] << 8 | buf[1];
@@ -964,6 +977,19 @@ scriptexec(struct op *tp, const char **ap)
964977 buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
965978 (m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
966979 errorf("%s: not executable: magic %04X", tp->str, m);
980+#ifdef __OS2__
981+ cp = _getext(tp->str);
982+ if (cp && (!stricmp(cp, ".cmd") || !stricmp(cp, ".bat"))) {
983+ /* execute .cmd and .bat with OS2_SHELL, usually CMD.EXE */
984+ sh = str_val(global("OS2_SHELL"));
985+ *tp->args-- = "/c";
986+ /* convert slahes to backslashes */
987+ for (cp = tp->str; *cp; cp++) {
988+ if (*cp == '/')
989+ *cp = '\\';
990+ }
991+ }
992+#endif
967993 nomagic:
968994 ;
969995 }
@@ -978,13 +1004,17 @@ scriptexec(struct op *tp, const char **ap)
9781004 errorf(Tf_sD_sD_s, tp->str, sh, cstrerror(errno));
9791005 }
9801006
1007+/* actual 'builtin' built-in utility call is handled in comexec() */
9811008 int
982-shcomexec(const char **wp)
1009+c_builtin(const char **wp)
9831010 {
984- struct tbl *tp;
1011+ return (call_builtin(get_builtin(*wp), wp, Tbuiltin, false));
1012+}
9851013
986- tp = ktsearch(&builtins, *wp, hash(*wp));
987- return (call_builtin(tp, wp, "shcomexec", false));
1014+struct tbl *
1015+get_builtin(const char *s)
1016+{
1017+ return (s && *s ? ktsearch(&builtins, s, hash(s)) : NULL);
9881018 }
9891019
9901020 /*
@@ -1090,6 +1120,14 @@ builtin(const char *name, int (*func) (const char **))
10901120 /* external utility overrides built-in utility, with flags */
10911121 flag |= LOW_BI;
10921122 break;
1123+ case '-':
1124+ /* is declaration utility if argv[1] is one (POSIX: command) */
1125+ flag |= DECL_FWDR;
1126+ break;
1127+ case '^':
1128+ /* is declaration utility (POSIX: export, readonly) */
1129+ flag |= DECL_UTIL;
1130+ break;
10931131 default:
10941132 goto flags_seen;
10951133 }
@@ -1123,7 +1161,11 @@ findcom(const char *name, int flags)
11231161 char *fpath;
11241162 union mksh_cchack npath;
11251163
1126- if (mksh_vdirsep(name)) {
1164+ if (mksh_vdirsep(name)
1165+#ifdef MKSH_DOSPATH
1166+ && (strcmp(name, T_builtin) != 0)
1167+#endif
1168+ ) {
11271169 insert = 0;
11281170 /* prevent FPATH search below */
11291171 flags &= ~FC_FUNC;
@@ -1242,7 +1284,7 @@ search_access(const char *fn, int mode)
12421284 }
12431285 #ifdef __OS2__
12441286 /* treat all files as executable on OS/2 */
1245- sb.st_mode &= S_IXUSR | S_IXGRP | S_IXOTH;
1287+ sb.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
12461288 #endif
12471289 if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
12481290 !(sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
@@ -1251,6 +1293,13 @@ search_access(const char *fn, int mode)
12511293 return (0);
12521294 }
12531295
1296+#ifdef __OS2__
1297+/* check if path is something we want to find, adding executable extensions */
1298+#define search_access(fn, mode) access_ex((search_access), (fn), (mode))
1299+#else
1300+#define search_access(fn, mode) (search_access)((fn), (mode))
1301+#endif
1302+
12541303 /*
12551304 * search for command with PATH
12561305 */
@@ -1272,7 +1321,11 @@ search_path(const char *name, const char *lpath,
12721321 search_path_ok:
12731322 if (errnop)
12741323 *errnop = 0;
1324+#ifndef __OS2__
12751325 return (name);
1326+#else
1327+ return (real_exec_name(name));
1328+#endif
12761329 }
12771330 goto search_path_err;
12781331 }
@@ -1289,6 +1342,10 @@ search_path(const char *name, const char *lpath,
12891342 XcheckN(xs, xp, p - sp);
12901343 memcpy(xp, sp, p - sp);
12911344 xp += p - sp;
1345+#ifdef __OS2__
1346+ if (xp > Xstring(xs, xp) && mksh_cdirsep(xp[-1]))
1347+ xp--;
1348+#endif
12921349 *xp++ = '/';
12931350 }
12941351 sp = p;
@@ -1319,9 +1376,7 @@ call_builtin(struct tbl *tp, const char **wp, const char *where, bool resetspec)
13191376 if (!tp)
13201377 internal_errorf(Tf_sD_s, where, wp[0]);
13211378 builtin_argv0 = wp[0];
1322- builtin_spec = tobool(!resetspec &&
1323- /*XXX odd use of KEEPASN */
1324- ((tp->flag & SPEC_BI) || (Flag(FPOSIX) && (tp->flag & KEEPASN))));
1379+ builtin_spec = tobool(!resetspec && (tp->flag & SPEC_BI));
13251380 shf_reopen(1, SHF_WR, shl_stdout);
13261381 shl_stdout_ok = true;
13271382 ksh_getopt_reset(&builtin_opt, GF_ERROR);
@@ -1450,8 +1505,11 @@ iosetup(struct ioword *iop, struct tbl *tp)
14501505 /* herein() may already have printed message */
14511506 if (u == -1) {
14521507 u = errno;
1453- warningf(true, Tf_cant,
1508+ warningf(true, Tf_cant_ss_s,
1509+#if 0
1510+ /* can't happen */
14541511 iotype == IODUP ? "dup" :
1512+#endif
14551513 (iotype == IOREAD || iotype == IOHERE) ?
14561514 Topen : Tcreate, cp, cstrerror(u));
14571515 }
--- a/src/expr.c
+++ b/src/expr.c
@@ -2,7 +2,7 @@
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5- * 2011, 2012, 2013, 2014, 2016
5+ * 2011, 2012, 2013, 2014, 2016, 2017
66 * mirabilos <m@mirbsd.org>
77 *
88 * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.90 2016/11/07 16:58:48 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.93 2017/04/02 16:47:41 tg Exp $");
2727
2828 #define EXPRTOK_DEFNS
2929 #include "exprtok.h"
@@ -203,7 +203,7 @@ evalerr(Expr_state *es, enum error_type type, const char *str)
203203
204204 case ET_BADLIT:
205205 warningf(true, Tf_sD_s_qs, es->expression,
206- "bad number", str);
206+ Tbadnum, str);
207207 break;
208208
209209 case ET_RECURSIVE:
@@ -572,8 +572,9 @@ exprtoken(Expr_state *es)
572572 if (c == '\0')
573573 es->tok = END;
574574 else if (ksh_isalphx(c)) {
575- for (; ksh_isalnux(c); c = *cp)
576- cp++;
575+ do {
576+ c = *++cp;
577+ } while (ksh_isalnux(c));
577578 if (c == '[') {
578579 size_t len;
579580
@@ -856,6 +857,9 @@ utf_wctomb(char *dst, unsigned int wc)
856857 int
857858 ksh_access(const char *fn, int mode)
858859 {
860+#ifdef __OS2__
861+ return (access_ex(access, fn, mode));
862+#else
859863 int rv;
860864 struct stat sb;
861865
@@ -865,6 +869,7 @@ ksh_access(const char *fn, int mode)
865869 rv = -1;
866870
867871 return (rv);
872+#endif
868873 }
869874
870875 #ifndef MIRBSD_BOOTFLOPPY
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -5,7 +5,7 @@
55
66 /*-
77 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
8- * 2010, 2011, 2012, 2013, 2014, 2015, 2016
8+ * 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
99 * mirabilos <m@mirbsd.org>
1010 *
1111 * Provided that these terms and disclaimer and all copyright notices
@@ -38,7 +38,7 @@
3838 #endif
3939 #endif
4040
41-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.319 2016/11/11 23:48:29 tg Exp $");
41+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.340 2017/04/12 17:46:29 tg Exp $");
4242
4343 #if HAVE_KILLPG
4444 /*
@@ -73,7 +73,7 @@ bi_getn(const char *as, int *ai)
7373 int rv;
7474
7575 if (!(rv = getn(as, ai)))
76- bi_errorf(Tf_sD_s, as, "bad number");
76+ bi_errorf(Tf_sD_s, Tbadnum, as);
7777 return (rv);
7878 }
7979
@@ -92,6 +92,7 @@ c_false(const char **wp MKSH_A_UNUSED)
9292 /*
9393 * A leading = means assignments before command are kept.
9494 * A leading * means a POSIX special builtin.
95+ * A leading ^ means declaration utility, - forwarder.
9596 */
9697 const struct builtin mkshbuiltins[] = {
9798 {Tsgdot, c_dot},
@@ -99,33 +100,34 @@ const struct builtin mkshbuiltins[] = {
99100 {Tbracket, c_test},
100101 /* no =: AT&T manual wrong */
101102 {Talias, c_alias},
102- {"*=break", c_brkcont},
103- {Tgbuiltin, c_builtin},
103+ {Tsgbreak, c_brkcont},
104+ {T__builtin, c_builtin},
105+ {Tbuiltin, c_builtin},
104106 #if !defined(__ANDROID__)
105107 {Tbcat, c_cat},
106108 #endif
107109 {Tcd, c_cd},
108110 /* dash compatibility hack */
109111 {"chdir", c_cd},
110- {Tcommand, c_command},
111- {"*=continue", c_brkcont},
112+ {T_command, c_command},
113+ {Tsgcontinue, c_brkcont},
112114 {"echo", c_print},
113115 {"*=eval", c_eval},
114116 {"*=exec", c_exec},
115117 {"*=exit", c_exitreturn},
116- {Tsgexport, c_typeset},
118+ {Tdsgexport, c_typeset},
117119 {Tfalse, c_false},
118120 {"fc", c_fc},
119121 {Tgetopts, c_getopts},
120- {"=global", c_typeset},
122+ /* deprecated, replaced by typeset -g */
123+ {"^=global", c_typeset},
121124 {Tjobs, c_jobs},
122125 {"kill", c_kill},
123126 {"let", c_let},
124- {"let]", c_let},
125127 {"print", c_print},
126128 {"pwd", c_pwd},
127129 {Tread, c_read},
128- {Tsgreadonly, c_typeset},
130+ {Tdsgreadonly, c_typeset},
129131 #if !defined(__ANDROID__)
130132 {"!realpath", c_realpath},
131133 #endif
@@ -133,7 +135,7 @@ const struct builtin mkshbuiltins[] = {
133135 {"*=return", c_exitreturn},
134136 {Tsgset, c_set},
135137 {"*=shift", c_shift},
136- {"=source", c_dot},
138+ {Tgsource, c_dot},
137139 #if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
138140 {Tsuspend, c_suspend},
139141 #endif
@@ -141,12 +143,12 @@ const struct builtin mkshbuiltins[] = {
141143 {"*=times", c_times},
142144 {"*=trap", c_trap},
143145 {Ttrue, c_true},
144- {Tgtypeset, c_typeset},
146+ {Tdgtypeset, c_typeset},
145147 {"ulimit", c_ulimit},
146148 {"umask", c_umask},
147149 {Tunalias, c_unalias},
148150 {"*=unset", c_unset},
149- {"=wait", c_wait},
151+ {"wait", c_wait},
150152 {"whence", c_whence},
151153 #ifndef MKSH_UNEMPLOYED
152154 {Tbg, c_fgbg},
@@ -193,8 +195,8 @@ static const struct t_op {
193195 {"-f", TO_FILREG },
194196 {"-G", TO_FILGID },
195197 {"-g", TO_FILSETG },
196- {"-h", TO_FILSYM },
197198 {"-H", TO_FILCDF },
199+ {"-h", TO_FILSYM },
198200 {"-k", TO_FILSTCK },
199201 {"-L", TO_FILSYM },
200202 {"-n", TO_STNZE },
@@ -202,10 +204,11 @@ static const struct t_op {
202204 {"-o", TO_OPTION },
203205 {"-p", TO_FILFIFO },
204206 {"-r", TO_FILRD },
205- {"-s", TO_FILGZ },
206207 {"-S", TO_FILSOCK },
208+ {"-s", TO_FILGZ },
207209 {"-t", TO_FILTT },
208210 {"-u", TO_FILSETU },
211+ {"-v", TO_ISSET },
209212 {"-w", TO_FILWR },
210213 {"-x", TO_FILEX },
211214 {"-z", TO_STZER },
@@ -313,8 +316,6 @@ c_print(const char **wp)
313316 bool hist;
314317 /* print words as wide characters? */
315318 bool chars;
316- /* print a "--" argument? */
317- bool pminusminus;
318319 /* writing to a coprocess (SIGPIPE blocked)? */
319320 bool coproc;
320321 bool copipe;
@@ -325,47 +326,39 @@ c_print(const char **wp)
325326 po.ws = ' ';
326327 po.ls = '\n';
327328 po.nl = true;
328- po.exp = true;
329329
330330 if (wp[0][0] == 'e') {
331331 /* "echo" builtin */
332- ++wp;
333-#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
334- if (Flag(FSH)) {
335- /*
336- * MidnightBSD /bin/sh needs a BSD echo, that is,
337- * one that supports -e but does not enable it by
338- * default
339- */
340- po.exp = false;
341- }
342-#endif
343332 if (Flag(FPOSIX) ||
344333 #ifndef MKSH_MIDNIGHTBSD01ASH_COMPAT
345334 Flag(FSH) ||
346335 #endif
347336 Flag(FAS_BUILTIN)) {
348- /* Debian Policy 10.4 compliant "echo" builtin */
337+ /* BSD "echo" cmd, Debian Policy 10.4 compliant */
338+ ++wp;
339+ bsd_echo:
349340 if (*wp && !strcmp(*wp, "-n")) {
350- /* recognise "-n" only as the first arg */
351341 po.nl = false;
352342 ++wp;
353343 }
354- /* print everything as-is */
355344 po.exp = false;
356345 } else {
357- bool new_exp = po.exp, new_nl = po.nl;
358-
359- /**
360- * a compromise between sysV and BSD echo commands:
361- * escape sequences are enabled by default, and -n,
362- * -e and -E are recognised if they appear in argu-
363- * ments with no illegal options (ie, echo -nq will
364- * print -nq).
365- * Different from sysV echo since options are reco-
366- * gnised, different from BSD echo since escape se-
367- * quences are enabled by default.
346+ bool new_exp, new_nl = true;
347+
348+ /*-
349+ * compromise between various historic echos: only
350+ * recognise -Een if they appear in arguments with
351+ * no illegal options; e.g. echo -nq outputs '-nq'
368352 */
353+#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
354+ /* MidnightBSD /bin/sh needs -e supported but off */
355+ if (Flag(FSH))
356+ new_exp = false;
357+ else
358+#endif
359+ /* otherwise compromise on -e enabled by default */
360+ new_exp = true;
361+ goto print_tradparse_beg;
369362
370363 print_tradparse_arg:
371364 if ((s = *wp) && *s++ == '-' && *s) {
@@ -381,6 +374,7 @@ c_print(const char **wp)
381374 new_nl = false;
382375 goto print_tradparse_ch;
383376 case '\0':
377+ print_tradparse_beg:
384378 po.exp = new_exp;
385379 po.nl = new_nl;
386380 ++wp;
@@ -390,10 +384,10 @@ c_print(const char **wp)
390384 }
391385 } else {
392386 /* "print" builtin */
393- const char *opts = "AclNnpRrsu,";
387+ const char *opts = "AcelNnpRrsu,";
394388 const char *emsg;
395389
396- po.pminusminus = false;
390+ po.exp = true;
397391
398392 while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
399393 switch (c) {
@@ -423,11 +417,9 @@ c_print(const char **wp)
423417 }
424418 break;
425419 case 'R':
426- /* fake BSD echo command */
427- po.pminusminus = true;
428- po.exp = false;
429- opts = "en";
430- break;
420+ /* fake BSD echo but don't reset other flags */
421+ wp += builtin_opt.optind;
422+ goto bsd_echo;
431423 case 'r':
432424 po.exp = false;
433425 break;
@@ -451,8 +443,7 @@ c_print(const char **wp)
451443 if (wp[builtin_opt.optind] &&
452444 ksh_isdash(wp[builtin_opt.optind]))
453445 builtin_opt.optind++;
454- } else if (po.pminusminus)
455- builtin_opt.optind--;
446+ }
456447 wp += builtin_opt.optind;
457448 }
458449
@@ -747,7 +738,7 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
747738 break;
748739 #ifndef MKSH_SMALL
749740 default:
750- bi_errorf("%s is of unknown type %d", id, tp->type);
741+ bi_errorf(Tunexpected_type, id, Tcommand, tp->type);
751742 return (1);
752743 #endif
753744 }
@@ -757,380 +748,15 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
757748 return (rv);
758749 }
759750
760-/* typeset, global, export, and readonly */
761-static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool);
762-static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,
763- bool);
764-int
765-c_typeset(const char **wp)
766-{
767- struct tbl *vp, **p;
768- uint32_t fset = 0, fclr = 0, flag;
769- int thing = 0, field = 0, base = 0, i;
770- struct block *l;
771- const char *opts;
772- const char *fieldstr = NULL, *basestr = NULL;
773- bool localv = false, func = false, pflag = false, istset = true;
774- enum namerefflag new_refflag = SRF_NOP;
775-
776- switch (**wp) {
777-
778- /* export */
779- case 'e':
780- fset |= EXPORT;
781- istset = false;
782- break;
783-
784- /* readonly */
785- case 'r':
786- fset |= RDONLY;
787- istset = false;
788- break;
789-
790- /* set */
791- case 's':
792- /* called with 'typeset -' */
793- break;
794-
795- /* typeset */
796- case 't':
797- localv = true;
798- break;
799- }
800-
801- /* see comment below regarding possible opions */
802- opts = istset ? "L#R#UZ#afi#lnprtux" : "p";
803-
804- builtin_opt.flags |= GF_PLUSOPT;
805- /*
806- * AT&T ksh seems to have 0-9 as options which are multiplied
807- * to get a number that is used with -L, -R, -Z or -i (eg, -1R2
808- * sets right justify in a field of 12). This allows options
809- * to be grouped in an order (eg, -Lu12), but disallows -i8 -L3 and
810- * does not allow the number to be specified as a separate argument
811- * Here, the number must follow the RLZi option, but is optional
812- * (see the # kludge in ksh_getopt()).
813- */
814- while ((i = ksh_getopt(wp, &builtin_opt, opts)) != -1) {
815- flag = 0;
816- switch (i) {
817- case 'L':
818- flag = LJUST;
819- fieldstr = builtin_opt.optarg;
820- break;
821- case 'R':
822- flag = RJUST;
823- fieldstr = builtin_opt.optarg;
824- break;
825- case 'U':
826- /*
827- * AT&T ksh uses u, but this conflicts with
828- * upper/lower case. If this option is changed,
829- * need to change the -U below as well
830- */
831- flag = INT_U;
832- break;
833- case 'Z':
834- flag = ZEROFIL;
835- fieldstr = builtin_opt.optarg;
836- break;
837- case 'a':
838- /*
839- * this is supposed to set (-a) or unset (+a) the
840- * indexed array attribute; it does nothing on an
841- * existing regular string or indexed array though
842- */
843- break;
844- case 'f':
845- func = true;
846- break;
847- case 'i':
848- flag = INTEGER;
849- basestr = builtin_opt.optarg;
850- break;
851- case 'l':
852- flag = LCASEV;
853- break;
854- case 'n':
855- new_refflag = (builtin_opt.info & GI_PLUS) ?
856- SRF_DISABLE : SRF_ENABLE;
857- break;
858- /* export, readonly: POSIX -p flag */
859- case 'p':
860- /* typeset: show values as well */
861- pflag = true;
862- if (istset)
863- continue;
864- break;
865- case 'r':
866- flag = RDONLY;
867- break;
868- case 't':
869- flag = TRACE;
870- break;
871- case 'u':
872- /* upper case / autoload */
873- flag = UCASEV_AL;
874- break;
875- case 'x':
876- flag = EXPORT;
877- break;
878- case '?':
879- return (1);
880- }
881- if (builtin_opt.info & GI_PLUS) {
882- fclr |= flag;
883- fset &= ~flag;
884- thing = '+';
885- } else {
886- fset |= flag;
887- fclr &= ~flag;
888- thing = '-';
889- }
890- }
891-
892- if (fieldstr && !bi_getn(fieldstr, &field))
893- return (1);
894- if (basestr) {
895- if (!getn(basestr, &base)) {
896- bi_errorf(Tf_sD_s, "bad integer base", basestr);
897- return (1);
898- }
899- if (base < 1 || base > 36)
900- base = 10;
901- }
902-
903- if (!(builtin_opt.info & GI_MINUSMINUS) && wp[builtin_opt.optind] &&
904- (wp[builtin_opt.optind][0] == '-' ||
905- wp[builtin_opt.optind][0] == '+') &&
906- wp[builtin_opt.optind][1] == '\0') {
907- thing = wp[builtin_opt.optind][0];
908- builtin_opt.optind++;
909- }
910-
911- if (func && (((fset|fclr) & ~(TRACE|UCASEV_AL|EXPORT)) ||
912- new_refflag != SRF_NOP)) {
913- bi_errorf("only -t, -u and -x options may be used with -f");
914- return (1);
915- }
916- if (wp[builtin_opt.optind]) {
917- /*
918- * Take care of exclusions.
919- * At this point, flags in fset are cleared in fclr and vice
920- * versa. This property should be preserved.
921- */
922- if (fset & LCASEV)
923- /* LCASEV has priority over UCASEV_AL */
924- fset &= ~UCASEV_AL;
925- if (fset & LJUST)
926- /* LJUST has priority over RJUST */
927- fset &= ~RJUST;
928- if ((fset & (ZEROFIL|LJUST)) == ZEROFIL) {
929- /* -Z implies -ZR */
930- fset |= RJUST;
931- fclr &= ~RJUST;
932- }
933- /*
934- * Setting these attributes clears the others, unless they
935- * are also set in this command
936- */
937- if ((fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL | LCASEV |
938- INTEGER | INT_U | INT_L)) || new_refflag != SRF_NOP)
939- fclr |= ~fset & (LJUST | RJUST | ZEROFIL | UCASEV_AL |
940- LCASEV | INTEGER | INT_U | INT_L);
941- }
942- if (new_refflag != SRF_NOP) {
943- fclr &= ~(ARRAY | ASSOC);
944- fset &= ~(ARRAY | ASSOC);
945- fclr |= EXPORT;
946- fset |= ASSOC;
947- if (new_refflag == SRF_DISABLE)
948- fclr |= ASSOC;
949- }
950-
951- /* set variables and attributes */
952- if (wp[builtin_opt.optind] &&
953- /* not "typeset -p varname" */
954- !(!func && pflag && !(fset | fclr))) {
955- int rv = 0;
956- struct tbl *f;
957-
958- if (localv && !func)
959- fset |= LOCAL;
960- for (i = builtin_opt.optind; wp[i]; i++) {
961- if (func) {
962- f = findfunc(wp[i], hash(wp[i]),
963- tobool(fset & UCASEV_AL));
964- if (!f) {
965- /* AT&T ksh does ++rv: bogus */
966- rv = 1;
967- continue;
968- }
969- if (fset | fclr) {
970- f->flag |= fset;
971- f->flag &= ~fclr;
972- } else {
973- fpFUNCTf(shl_stdout, 0,
974- tobool(f->flag & FKSH),
975- wp[i], f->val.t);
976- shf_putc('\n', shl_stdout);
977- }
978- } else if (!typeset(wp[i], fset, fclr, field, base)) {
979- bi_errorf(Tf_sD_s, wp[i], Tnot_ident);
980- return (1);
981- }
982- }
983- return (rv);
984- }
985-
986- /* list variables and attributes */
987-
988- /* no difference at this point.. */
989- flag = fset | fclr;
990- if (func) {
991- for (l = e->loc; l; l = l->next) {
992- for (p = ktsort(&l->funs); (vp = *p++); ) {
993- if (flag && (vp->flag & flag) == 0)
994- continue;
995- if (thing == '-')
996- fpFUNCTf(shl_stdout, 0,
997- tobool(vp->flag & FKSH),
998- vp->name, vp->val.t);
999- else
1000- shf_puts(vp->name, shl_stdout);
1001- shf_putc('\n', shl_stdout);
1002- }
1003- }
1004- } else if (wp[builtin_opt.optind]) {
1005- for (i = builtin_opt.optind; wp[i]; i++) {
1006- varsearch(e->loc, &vp, wp[i], hash(wp[i]));
1007- c_typeset_vardump(vp, flag, thing, pflag, istset);
1008- }
1009- } else
1010- c_typeset_vardump_recursive(e->loc, flag, thing, pflag, istset);
1011- return (0);
1012-}
1013-
1014-static void
1015-c_typeset_vardump_recursive(struct block *l, uint32_t flag, int thing,
1016- bool pflag, bool istset)
751+bool
752+valid_alias_name(const char *cp)
1017753 {
1018- struct tbl **blockvars, *vp;
1019-
1020- if (l->next)
1021- c_typeset_vardump_recursive(l->next, flag, thing, pflag, istset);
1022- blockvars = ktsort(&l->vars);
1023- while ((vp = *blockvars++))
1024- c_typeset_vardump(vp, flag, thing, pflag, istset);
1025- /*XXX doesn’t this leak? */
1026-}
1027-
1028-static void
1029-c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag,
1030- bool istset)
1031-{
1032- struct tbl *tvp;
1033- int any_set = 0;
1034- char *s;
1035-
1036- if (!vp)
1037- return;
1038-
1039- /*
1040- * See if the parameter is set (for arrays, if any
1041- * element is set).
1042- */
1043- for (tvp = vp; tvp; tvp = tvp->u.array)
1044- if (tvp->flag & ISSET) {
1045- any_set = 1;
1046- break;
1047- }
1048-
1049- /*
1050- * Check attributes - note that all array elements
1051- * have (should have?) the same attributes, so checking
1052- * the first is sufficient.
1053- *
1054- * Report an unset param only if the user has
1055- * explicitly given it some attribute (like export);
1056- * otherwise, after "echo $FOO", we would report FOO...
1057- */
1058- if (!any_set && !(vp->flag & USERATTRIB))
1059- return;
1060- if (flag && (vp->flag & flag) == 0)
1061- return;
1062- if (!(vp->flag & ARRAY))
1063- /* optimise later conditionals */
1064- any_set = 0;
1065- do {
1066- /*
1067- * Ignore array elements that aren't set unless there
1068- * are no set elements, in which case the first is
1069- * reported on
1070- */
1071- if (any_set && !(vp->flag & ISSET))
1072- continue;
1073- /* no arguments */
1074- if (!thing && !flag) {
1075- if (any_set == 1) {
1076- shprintf(Tf_s_s_sN, Tset, "-A", vp->name);
1077- any_set = 2;
1078- }
1079- /*
1080- * AT&T ksh prints things like export, integer,
1081- * leftadj, zerofill, etc., but POSIX says must
1082- * be suitable for re-entry...
1083- */
1084- shprintf(Tf_s_s, Ttypeset, "");
1085- if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
1086- shprintf(Tf__c_, 'n');
1087- if ((vp->flag & INTEGER))
1088- shprintf(Tf__c_, 'i');
1089- if ((vp->flag & EXPORT))
1090- shprintf(Tf__c_, 'x');
1091- if ((vp->flag & RDONLY))
1092- shprintf(Tf__c_, 'r');
1093- if ((vp->flag & TRACE))
1094- shprintf(Tf__c_, 't');
1095- if ((vp->flag & LJUST))
1096- shprintf("-L%d ", vp->u2.field);
1097- if ((vp->flag & RJUST))
1098- shprintf("-R%d ", vp->u2.field);
1099- if ((vp->flag & ZEROFIL))
1100- shprintf(Tf__c_, 'Z');
1101- if ((vp->flag & LCASEV))
1102- shprintf(Tf__c_, 'l');
1103- if ((vp->flag & UCASEV_AL))
1104- shprintf(Tf__c_, 'u');
1105- if ((vp->flag & INT_U))
1106- shprintf(Tf__c_, 'U');
1107- } else if (pflag) {
1108- shprintf(Tf_s_s, istset ? Ttypeset :
1109- (flag & EXPORT) ? Texport : Treadonly, "");
1110- }
1111- if (any_set)
1112- shprintf("%s[%lu]", vp->name, arrayindex(vp));
754+ while (*cp)
755+ if (!ksh_isalias(*cp))
756+ return (false);
1113757 else
1114- shf_puts(vp->name, shl_stdout);
1115- if ((!thing && !flag && pflag) ||
1116- (thing == '-' && (vp->flag & ISSET))) {
1117- s = str_val(vp);
1118- shf_putc('=', shl_stdout);
1119- /* AT&T ksh can't have justified integers... */
1120- if ((vp->flag & (INTEGER | LJUST | RJUST)) == INTEGER)
1121- shf_puts(s, shl_stdout);
1122- else
1123- print_value_quoted(shl_stdout, s);
1124- }
1125- shf_putc('\n', shl_stdout);
1126-
1127- /*
1128- * Only report first 'element' of an array with
1129- * no set elements.
1130- */
1131- if (!any_set)
1132- return;
1133- } while ((vp = vp->u.array));
758+ ++cp;
759+ return (true);
1134760 }
1135761
1136762 int
@@ -1231,6 +857,11 @@ c_alias(const char **wp)
1231857 strndupx(xalias, alias, val++ - alias, ATEMP);
1232858 alias = xalias;
1233859 }
860+ if (!valid_alias_name(alias) || *alias == '-') {
861+ bi_errorf(Tinvname, alias, Talias);
862+ afree(xalias, ATEMP);
863+ return (1);
864+ }
1234865 h = hash(alias);
1235866 if (val == NULL && !tflag && !xflag) {
1236867 ap = ktsearch(t, alias, h);
@@ -1639,7 +1270,7 @@ c_getopts(const char **wp)
16391270 if (user_opt.optarg == NULL)
16401271 unset(voptarg, 1);
16411272 else
1642- /* This can't fail (have cleared readonly/integer) */
1273+ /* this can't fail (haing cleared readonly/integer) */
16431274 setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
16441275
16451276 rv = 0;
@@ -1737,7 +1368,7 @@ c_shift(const char **wp)
17371368 /* nothing to do */
17381369 return (0);
17391370 } else if (n < 0) {
1740- bi_errorf(Tf_sD_s, arg, "bad number");
1371+ bi_errorf(Tf_sD_s, Tbadnum, arg);
17411372 return (1);
17421373 }
17431374 if (l->argc < n) {
@@ -1798,7 +1429,7 @@ c_umask(const char **wp)
17981429 ++cp;
17991430 }
18001431 if (*cp) {
1801- bi_errorf("bad number");
1432+ bi_errorf(Tbadnum);
18021433 return (1);
18031434 }
18041435 } else {
@@ -1982,6 +1613,10 @@ c_read(const char **wp)
19821613 #else
19831614 #define c_read_opts "Aad:N:n:prsu,"
19841615 #endif
1616+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1617+ int saved_mode;
1618+ int saved_errno;
1619+#endif
19851620
19861621 while ((c = ksh_getopt(wp, &builtin_opt, c_read_opts)) != -1)
19871622 switch (c) {
@@ -2110,7 +1745,15 @@ c_read(const char **wp)
21101745 }
21111746 #endif
21121747
1748+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1749+ saved_mode = setmode(fd, O_TEXT);
1750+#endif
21131751 if ((bytesread = blocking_read(fd, xp, bytesleft)) == (size_t)-1) {
1752+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1753+ saved_errno = errno;
1754+ setmode(fd, saved_mode);
1755+ errno = saved_errno;
1756+#endif
21141757 if (errno == EINTR) {
21151758 /* check whether the signal would normally kill */
21161759 if (!fatal_trap_check()) {
@@ -2125,6 +1768,9 @@ c_read(const char **wp)
21251768 rv = 2;
21261769 goto c_read_out;
21271770 }
1771+#if defined(__OS2__) && defined(MKSH_WITH_TEXTMODE)
1772+ setmode(fd, saved_mode);
1773+#endif
21281774
21291775 switch (readmode) {
21301776 case READALL:
@@ -2386,6 +2032,7 @@ c_eval(const char **wp)
23862032 return (1);
23872033 s = pushs(SWORDS, ATEMP);
23882034 s->u.strv = wp + builtin_opt.optind;
2035+ s->line = current_lineno;
23892036
23902037 /*-
23912038 * The following code handles the case where the command is
@@ -2423,7 +2070,7 @@ c_eval(const char **wp)
24232070
24242071 savef = Flag(FERREXIT);
24252072 Flag(FERREXIT) |= 0x80;
2426- rv = shell(s, false);
2073+ rv = shell(s, 2);
24272074 Flag(FERREXIT) = savef;
24282075 source = saves;
24292076 afree(s, ATEMP);
@@ -2559,7 +2206,7 @@ c_brkcont(const char **wp)
25592206 * scripts, but don't generate an error (ie, keep going).
25602207 */
25612208 if ((unsigned int)n == quit) {
2562- warningf(true, "%s: can't %s", wp[0], wp[0]);
2209+ warningf(true, Tf_cant_s, wp[0], wp[0]);
25632210 return (0);
25642211 }
25652212 /*
@@ -2827,7 +2474,6 @@ c_exec(const char **wp MKSH_A_UNUSED)
28272474 for (i = 0; i < NUFILE; i++) {
28282475 if (e->savefd[i] > 0)
28292476 close(e->savefd[i]);
2830-#ifndef MKSH_LEGACY_MODE
28312477 /*
28322478 * keep all file descriptors > 2 private for ksh,
28332479 * but not for POSIX or legacy/kludge sh
@@ -2835,14 +2481,13 @@ c_exec(const char **wp MKSH_A_UNUSED)
28352481 if (!Flag(FPOSIX) && !Flag(FSH) && i > 2 &&
28362482 e->savefd[i])
28372483 fcntl(i, F_SETFD, FD_CLOEXEC);
2838-#endif
28392484 }
28402485 e->savefd = NULL;
28412486 }
28422487 return (0);
28432488 }
28442489
2845-#if HAVE_MKNOD
2490+#if HAVE_MKNOD && !defined(__OS2__)
28462491 int
28472492 c_mknod(const char **wp)
28482493 {
@@ -2939,14 +2584,13 @@ c_mknod(const char **wp)
29392584 | "(" oexpr ")"
29402585 ;
29412586
2942- unary-operator ::= "-a"|"-r"|"-w"|"-x"|"-e"|"-f"|"-d"|"-c"|"-b"|"-p"|
2943- "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|
2944- "-L"|"-h"|"-S"|"-H";
2587+ unary-operator ::= "-a"|"-b"|"-c"|"-d"|"-e"|"-f"|"-G"|"-g"|"-H"|"-h"|
2588+ "-k"|"-L"|"-n"|"-O"|"-o"|"-p"|"-r"|"-S"|"-s"|"-t"|
2589+ "-u"|"-v"|"-w"|"-x"|"-z";
2590+
2591+ binary-operator ::= "="|"=="|"!="|"<"|">"|"-eq"|"-ne"|"-gt"|"-ge"|
2592+ "-lt"|"-le"|"-ef"|"-nt"|"-ot";
29452593
2946- binary-operator ::= "="|"=="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
2947- "-nt"|"-ot"|"-ef"|
2948- "<"|">" # rules used for [[ ... ]] expressions
2949- ;
29502594 operand ::= <anything>
29512595 */
29522596
@@ -3099,6 +2743,14 @@ test_isop(Test_meta meta, const char *s)
30992743 return (TO_NONOP);
31002744 }
31012745
2746+#ifdef __OS2__
2747+#define test_access(name, mode) access_ex(access, (name), (mode))
2748+#define test_stat(name, buffer) stat_ex((name), (buffer))
2749+#else
2750+#define test_access(name, mode) access((name), (mode))
2751+#define test_stat(name, buffer) stat((name), (buffer))
2752+#endif
2753+
31022754 int
31032755 test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
31042756 bool do_eval)
@@ -3107,6 +2759,7 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
31072759 size_t k;
31082760 struct stat b1, b2;
31092761 mksh_ari_t v1, v2;
2762+ struct tbl *vp;
31102763
31112764 if (!do_eval)
31122765 return (0);
@@ -3153,6 +2806,10 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
31532806 case TO_STZER:
31542807 return (*opnd1 == '\0');
31552808
2809+ /* -v */
2810+ case TO_ISSET:
2811+ return ((vp = isglobal(opnd1, false)) && (vp->flag & ISSET));
2812+
31562813 /* -o */
31572814 case TO_OPTION:
31582815 if ((i = *opnd1) == '!' || i == '?')
@@ -3164,12 +2821,12 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
31642821 /* -r */
31652822 case TO_FILRD:
31662823 /* LINTED use of access */
3167- return (access(opnd1, R_OK) == 0);
2824+ return (test_access(opnd1, R_OK) == 0);
31682825
31692826 /* -w */
31702827 case TO_FILWR:
31712828 /* LINTED use of access */
3172- return (access(opnd1, W_OK) == 0);
2829+ return (test_access(opnd1, W_OK) == 0);
31732830
31742831 /* -x */
31752832 case TO_FILEX:
@@ -3179,11 +2836,11 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
31792836 case TO_FILAXST:
31802837 /* -e */
31812838 case TO_FILEXST:
3182- return (stat(opnd1, &b1) == 0);
2839+ return (test_stat(opnd1, &b1) == 0);
31832840
3184- /* -r */
2841+ /* -f */
31852842 case TO_FILREG:
3186- return (stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
2843+ return (test_stat(opnd1, &b1) == 0 && S_ISREG(b1.st_mode));
31872844
31882845 /* -d */
31892846 case TO_FILID:
@@ -3282,7 +2939,7 @@ test_eval(Test_env *te, Test_op op, const char *opnd1, const char *opnd2,
32822939 * Binary Operators
32832940 */
32842941
3285- /* = */
2942+ /* =, == */
32862943 case TO_STEQL:
32872944 if (te->flags & TEF_DBRACKET) {
32882945 if ((i = gmatchx(opnd1, opnd2, false)))
@@ -3668,7 +3325,7 @@ c_ulimit(const char **wp)
36683325 if (!all)
36693326 print_ulimit(rlimits[i], how);
36703327 else for (i = 0; i < NELEM(rlimits); ++i) {
3671- shprintf("%-20s ", rlimits[i]->name);
3328+ shprintf("-%c: %-20s ", rlimits[i]->optchar, rlimits[i]->name);
36723329 print_ulimit(rlimits[i], how);
36733330 }
36743331 return (0);
--- a/src/histrap.c
+++ b/src/histrap.c
@@ -27,7 +27,7 @@
2727 #include <sys/file.h>
2828 #endif
2929
30-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.159 2016/11/11 18:44:32 tg Exp $");
30+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.160 2017/04/08 01:07:16 tg Exp $");
3131
3232 Trap sigtraps[ksh_NSIG + 1];
3333 static struct sigaction Sigact_ign;
@@ -829,7 +829,7 @@ hist_init(Source *s)
829829 goto retry;
830830 }
831831 if (hs != hist_init_retry)
832- bi_errorf(Tf_cant,
832+ bi_errorf(Tf_cant_ss_s,
833833 "unlink HISTFILE", hname, cstrerror(errno));
834834 histfsize = 0;
835835 return;
@@ -1033,8 +1033,8 @@ inittraps(void)
10331033 if (!strcmp(sigtraps[i].name, "EXIT") ||
10341034 !strcmp(sigtraps[i].name, "ERR")) {
10351035 #ifndef MKSH_SMALL
1036- internal_warningf("ignoring invalid signal name %s",
1037- sigtraps[i].name);
1036+ internal_warningf(Tinvname, sigtraps[i].name,
1037+ "signal");
10381038 #endif
10391039 sigtraps[i].name = null;
10401040 }
--- a/src/lex.c
+++ b/src/lex.c
@@ -2,7 +2,7 @@
22
33 /*-
44 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5- * 2011, 2012, 2013, 2014, 2015, 2016
5+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
66 * mirabilos <m@mirbsd.org>
77 *
88 * Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
2323
2424 #include "sh.h"
2525
26-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.228 2016/08/01 21:38:03 tg Exp $");
26+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.234 2017/04/06 01:59:55 tg Exp $");
2727
2828 /*
2929 * states while lexing word
@@ -489,7 +489,7 @@ yylex(int cf)
489489 * If this is a trim operation,
490490 * treat (,|,) specially in STBRACE.
491491 */
492- if (ctype(c, C_SUBOP2)) {
492+ if (ksh_issubop2(c)) {
493493 ungetsc(c);
494494 if (Flag(FSH))
495495 PUSH_STATE(STBRACEBOURNE);
@@ -532,7 +532,7 @@ yylex(int cf)
532532 case '`':
533533 subst_gravis:
534534 PUSH_STATE(SBQUOTE);
535- *wp++ = COMSUB;
535+ *wp++ = COMASUB;
536536 /*
537537 * We need to know whether we are within double
538538 * quotes in order to translate \" to " within
@@ -885,7 +885,7 @@ yylex(int cf)
885885 Xcheck(ws, wp);
886886 if (statep != &states[1])
887887 /* XXX figure out what is missing */
888- yyerror("no closing quote\n");
888+ yyerror("no closing quote");
889889
890890 /* This done to avoid tests for SHEREDELIM wherever SBASE tested */
891891 if (state == SHEREDELIM)
@@ -893,9 +893,7 @@ yylex(int cf)
893893
894894 dp = Xstring(ws, wp);
895895 if (state == SBASE && (
896-#ifndef MKSH_LEGACY_MODE
897896 (c == '&' && !Flag(FSH) && !Flag(FPOSIX)) ||
898-#endif
899897 c == '<' || c == '>') && ((c2 = Xlength(ws, wp)) == 0 ||
900898 (c2 == 2 && dp[0] == CHAR && ksh_isdigit(dp[1])))) {
901899 struct ioword *iop = alloc(sizeof(struct ioword), ATEMP);
@@ -1016,15 +1014,12 @@ yylex(int cf)
10161014 while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
10171015 *dp++ = *sp++;
10181016 if (c != EOS)
1019- /* word is not unquoted */
1017+ /* word is not unquoted, or space ran out */
10201018 dp = ident;
10211019 /* make sure the ident array stays NUL padded */
10221020 memset(dp, 0, (ident + IDENT) - dp + 1);
10231021
1024- if (!(cf & (KEYWORD | ALIAS)))
1025- return (LWORD);
1026-
1027- if (*ident != '\0') {
1022+ if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
10281023 struct tbl *p;
10291024 uint32_t h = hash(ident);
10301025
@@ -1068,6 +1063,7 @@ yylex(int cf)
10681063 s->start = s->str = p->val.s;
10691064 s->u.tblp = p;
10701065 s->flags |= SF_HASALIAS;
1066+ s->line = source->line;
10711067 s->next = source;
10721068 if (source->type == SEOF) {
10731069 /* prevent infinite recursion at EOS */
@@ -1079,9 +1075,12 @@ yylex(int cf)
10791075 goto Again;
10801076 }
10811077 }
1082- } else if (cf & ALIAS) {
1078+ } else if (*ident == '\0') {
10831079 /* retain typeset et al. even when quoted */
1084- if (assign_command((dp = wdstrip(yylval.cp, 0)), true))
1080+ struct tbl *tt = get_builtin((dp = wdstrip(yylval.cp, 0)));
1081+ uint32_t flag = tt ? tt->flag : 0;
1082+
1083+ if (flag & (DECL_UTIL | DECL_FWDR))
10851084 strlcpy(ident, dp, sizeof(ident));
10861085 afree(dp, ATEMP);
10871086 }
@@ -1204,6 +1203,7 @@ yyerror(const char *fmt, ...)
12041203 error_prefix(true);
12051204 va_start(va, fmt);
12061205 shf_vfprintf(shl_out, fmt, va);
1206+ shf_putc('\n', shl_out);
12071207 va_end(va);
12081208 errorfz();
12091209 }
@@ -1625,7 +1625,7 @@ get_brace_var(XString *wsp, char *wp)
16251625 char *tmp, *p;
16261626
16271627 if (!arraysub(&tmp))
1628- yyerror("missing ]\n");
1628+ yyerror("missing ]");
16291629 *wp++ = c;
16301630 for (p = tmp; *p; ) {
16311631 Xcheck(*wsp, wp);
--- a/src/lksh.1
+++ b/src/lksh.1
@@ -1,6 +1,6 @@
1-.\" $MirOS: src/bin/mksh/lksh.1,v 1.20 2016/11/11 23:31:35 tg Exp $
1+.\" $MirOS: src/bin/mksh/lksh.1,v 1.23 2017/04/02 13:38:02 tg Exp $
22 .\"-
3-.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016
3+.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017
44 .\" mirabilos <m@mirbsd.org>
55 .\"
66 .\" Provided that these terms and disclaimer and all copyright notices
@@ -74,7 +74,7 @@
7474 .\" with -mandoc, it might implement .Mx itself, but we want to
7575 .\" use our own definition. And .Dd must come *first*, always.
7676 .\"
77-.Dd $Mdocdate: November 11 2016 $
77+.Dd $Mdocdate: April 2 2017 $
7878 .\"
7979 .\" Check which macro package we use, and do other -mdoc setup.
8080 .\"
@@ -173,37 +173,34 @@ It is built on
173173 refer to its manual page for details on the scripting language.
174174 It is recommended to port scripts to
175175 .Nm mksh
176-instead of relying on legacy or idiotic POSIX-mandated behaviour,
176+instead of relying on legacy or objectionable POSIX-mandated behaviour,
177177 since the MirBSD Korn Shell scripting language is much more consistent.
178178 .Pp
179+Do not use
180+.Nm
181+as an interactive or login shell; use
182+.Nm mksh
183+instead.
184+.Pp
179185 Note that it's strongly recommended to invoke
180186 .Nm
181-with at least the
187+with
182188 .Fl o Ic posix
183-option, if not both that
184-.Em and Fl o Ic sh ,
185189 to fully enjoy better compatibility to the
186190 .Tn POSIX
187191 standard (which is probably why you use
188192 .Nm
189193 over
190194 .Nm mksh
191-in the first place) or legacy scripts, respectively.
195+in the first place);
196+.Fl o Ic sh
197+(possibly additionally to the above) may be needed for some legacy scripts.
192198 .Sh LEGACY MODE
193199 .Nm
194200 currently has the following differences from
195201 .Nm mksh :
196202 .Bl -bullet
197203 .It
198-.\"XXX TODO: remove (some systems may wish to have lksh as ksh)
199-There is no explicit support for interactive use,
200-nor any command line editing or history code.
201-Hence,
202-.Nm
203-is not suitable as a user's login shell, either; use
204-.Nm mksh
205-instead.
206-.It
207204 The
208205 .Ev KSH_VERSION
209206 string identifies
@@ -241,25 +238,11 @@ Division of the largest negative number by \-1 is Undefined Behaviour.
241238 The compiler is permitted to delete all data and crash the system
242239 if Undefined Behaviour occurs (see above for an example).
243240 .It
244-.\"XXX TODO: move this to FPOSIX
245241 The rotation arithmetic operators are not available.
246242 .It
247243 The shift arithmetic operators take all bits of the second operand into
248244 account; if they exceed permitted precision, the result is unspecified.
249245 .It
250-.\"XXX TODO: move this to FPOSIX
251-The
252-.Tn GNU
253-.Nm bash
254-extension &\*(Gt to redirect stdout and stderr in one go is not parsed.
255-.It
256-.\"XXX TODO: drop along with allowing interactivity
257-The
258-.Nm mksh
259-command line option
260-.Fl T
261-is not available.
262-.It
263246 Unless
264247 .Ic set -o posix
265248 is active,
@@ -275,19 +258,6 @@ passes through the errorlevel from the
275258 .Xr getopt 1
276259 command.
277260 .It
278-.\"XXX TODO: move to FPOSIX/FSH
279-Unlike
280-.At
281-.Nm ksh ,
282-.Nm mksh
283-in
284-.Fl o Ic posix
285-or
286-.Fl o Ic sh
287-mode and
288-.Nm lksh
289-do not keep file descriptors \*(Gt 2 private from sub-processes.
290-.It
291261 Functions defined with the
292262 .Ic function
293263 reserved word share the shell options
@@ -297,16 +267,10 @@ instead of locally scoping them.
297267 .Sh SEE ALSO
298268 .Xr mksh 1
299269 .Pp
300-.Pa https://www.mirbsd.org/mksh.htm
270+.Pa http://www.mirbsd.org/mksh.htm
301271 .Pp
302-.Pa https://www.mirbsd.org/ksh\-chan.htm
272+.Pa http://www.mirbsd.org/ksh\-chan.htm
303273 .Sh CAVEATS
304-The distinction between the shell variants
305-.Pq Nm lksh / Nm mksh
306-and shell flags
307-.Pq Fl o Ic posix / Ic sh
308-will be reworked for an upcoming release.
309-.Pp
310274 To use
311275 .Nm
312276 as
@@ -315,16 +279,22 @@ compilation to enable
315279 .Ic set -o posix
316280 by default if called as
317281 .Nm sh
282+.Pq adding Dv \-DMKSH_BINSHPOSIX to Dv CPPFLAGS
318283 is highly recommended for better standards compliance.
284+.Pp
319285 For better compatibility with legacy scripts, such as many
320286 .Tn Debian
321287 maintainer scripts, Upstart and SYSV init scripts, and other
322-unfixed scripts, using the compile-time options for enabling
288+unfixed scripts, also adding the
289+.Dv \-DMKSH_BINSHREDUCED
290+compile-time option to enable
323291 .Em both
324292 .Ic set -o posix -o sh
325293 when the shell is run as
326-.Nm sh
327-is recommended.
294+.Nm sh ,
295+as well as integrating the optional disrecommended
296+.Xr printf 1
297+builtin, might be necessary.
328298 .Pp
329299 .Nm
330300 tries to make a cross between a legacy bourne/posix compatibl-ish
@@ -332,14 +302,6 @@ shell and a legacy pdksh-alike but
332302 .Dq legacy
333303 is not exactly specified.
334304 .Pp
335-The
336-.Ic set
337-built-in command does not currently have all options one would expect
338-from a full-blown
339-.Nm mksh
340-or
341-.Nm pdksh .
342-.Pp
343305 Talk to the
344306 .Mx
345307 development team using the mailing list at
--- a/src/main.c
+++ b/src/main.c
@@ -5,7 +5,7 @@
55
66 /*-
77 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
8- * 2011, 2012, 2013, 2014, 2015, 2016
8+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
99 * mirabilos <m@mirbsd.org>
1010 *
1111 * Provided that these terms and disclaimer and all copyright notices
@@ -34,7 +34,7 @@
3434 #include <locale.h>
3535 #endif
3636
37-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.322 2016/11/11 23:48:30 tg Exp $");
37+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.332 2017/04/12 16:01:45 tg Exp $");
3838
3939 extern char **environ;
4040
@@ -56,8 +56,6 @@ static mksh_uari_t rndsetup(void);
5656 static void x_sigwinch(int);
5757 #endif
5858
59-static const char initifs[] = "IFS= \t\n";
60-
6159 static const char initsubs[] =
6260 "${PS2=> }"
6361 "${PS3=#? }"
@@ -71,18 +69,18 @@ static const char *initcoms[] = {
7169 Ttypeset, "-x", "HOME", TPATH, TSHELL, NULL,
7270 Ttypeset, "-i10", "COLUMNS", "LINES", "SECONDS", "TMOUT", NULL,
7371 Talias,
74- "integer=\\typeset -i",
75- "local=\\typeset",
72+ "integer=\\\\builtin typeset -i",
73+ "local=\\\\builtin typeset",
7674 /* not "alias -t --": hash -r needs to work */
77- "hash=\\builtin alias -t",
78- "type=\\builtin whence -v",
79- "autoload=\\typeset -fu",
80- "functions=\\typeset -f",
81- "history=\\builtin fc -l",
82- "nameref=\\typeset -n",
75+ "hash=\\\\builtin alias -t",
76+ "type=\\\\builtin whence -v",
77+ "autoload=\\\\builtin typeset -fu",
78+ "functions=\\\\builtin typeset -f",
79+ "history=\\\\builtin fc -l",
80+ "nameref=\\\\builtin typeset -n",
8381 "nohup=nohup ",
84- "r=\\builtin fc -e -",
85- "login=\\exec login",
82+ "r=\\\\builtin fc -e -",
83+ "login=\\\\builtin exec login",
8684 NULL,
8785 /* this is what AT&T ksh seems to track, with the addition of emacs */
8886 Talias, "-tU",
@@ -101,6 +99,51 @@ static bool initio_done;
10199 static struct env env;
102100 struct env *e = &env;
103101
102+/* compile-time assertions */
103+#define cta(name, expr) struct cta_ ## name { char t[(expr) ? 1 : -1]; }
104+
105+/* this one should be defined by the standard */
106+cta(char_is_1_char, (sizeof(char) == 1) && (sizeof(signed char) == 1) &&
107+ (sizeof(unsigned char) == 1));
108+cta(char_is_8_bits, ((CHAR_BIT) == 8) && ((int)(unsigned char)0xFF == 0xFF) &&
109+ ((int)(unsigned char)0x100 == 0) && ((int)(unsigned char)(int)-1 == 0xFF));
110+/* the next assertion is probably not really needed */
111+cta(short_is_2_char, sizeof(short) == 2);
112+cta(short_size_no_matter_of_signedness, sizeof(short) == sizeof(unsigned short));
113+/* the next assertion is probably not really needed */
114+cta(int_is_4_char, sizeof(int) == 4);
115+cta(int_size_no_matter_of_signedness, sizeof(int) == sizeof(unsigned int));
116+
117+cta(long_ge_int, sizeof(long) >= sizeof(int));
118+cta(long_size_no_matter_of_signedness, sizeof(long) == sizeof(unsigned long));
119+
120+#ifndef MKSH_LEGACY_MODE
121+/* the next assertion is probably not really needed */
122+cta(ari_is_4_char, sizeof(mksh_ari_t) == 4);
123+/* but this is */
124+cta(ari_has_31_bit, 0 < (mksh_ari_t)(((((mksh_ari_t)1 << 15) << 15) - 1) * 2 + 1));
125+/* the next assertion is probably not really needed */
126+cta(uari_is_4_char, sizeof(mksh_uari_t) == 4);
127+/* but the next three are; we REQUIRE unsigned integer wraparound */
128+cta(uari_has_31_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 2 + 1));
129+cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3));
130+cta(uari_wrap_32_bit,
131+ (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
132+ (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
133+#endif
134+/* these are always required */
135+cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
136+cta(uari_is_unsigned, (mksh_uari_t)-1 > (mksh_uari_t)0);
137+/* we require these to have the precisely same size and assume 2s complement */
138+cta(ari_size_no_matter_of_signedness, sizeof(mksh_ari_t) == sizeof(mksh_uari_t));
139+
140+cta(sizet_size_no_matter_of_signedness, sizeof(ssize_t) == sizeof(size_t));
141+cta(sizet_voidptr_same_size, sizeof(size_t) == sizeof(void *));
142+cta(sizet_funcptr_same_size, sizeof(size_t) == sizeof(void (*)(void)));
143+/* our formatting routines assume this */
144+cta(ptr_fits_in_long, sizeof(size_t) <= sizeof(long));
145+cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long));
146+
104147 static mksh_uari_t
105148 rndsetup(void)
106149 {
@@ -197,6 +240,8 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
197240 for (i = 0; i < 3; ++i)
198241 if (!isatty(i))
199242 setmode(i, O_BINARY);
243+
244+ os2_init(&argc, &argv);
200245 #endif
201246
202247 /* do things like getpgrp() et al. */
@@ -369,9 +414,10 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
369414 #endif
370415
371416 /* for security */
372- typeset(initifs, 0, 0, 0, 0);
417+ typeset("IFS= \t\n", 0, 0, 0, 0);
373418
374419 /* assign default shell variable values */
420+ typeset("PATHSEP=" MKSH_PATHSEPS, 0, 0, 0, 0);
375421 substitute(initsubs, 0);
376422
377423 /* Figure out the current working directory and set $PWD */
@@ -388,7 +434,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
388434 setstr(vp, current_wd, KSH_RETURN_ERROR);
389435
390436 for (wp = initcoms; *wp != NULL; wp++) {
391- shcomexec(wp);
437+ c_builtin(wp);
392438 while (*wp != NULL)
393439 wp++;
394440 }
@@ -474,7 +520,9 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
474520 * to search for it. This changes the behaviour of a
475521 * simple "mksh foo", but can't be helped.
476522 */
477- s->file = search_path(argv[argi++], path, X_OK, NULL);
523+ s->file = argv[argi++];
524+ if (search_access(s->file, X_OK) != 0)
525+ s->file = search_path(s->file, path, X_OK, NULL);
478526 if (!s->file || !*s->file)
479527 s->file = argv[argi - 1];
480528 #else
@@ -633,7 +681,7 @@ main_init(int argc, const char *argv[], Source **sp, struct block **lp)
633681 }
634682
635683 if (restricted_shell) {
636- shcomexec(restr_com);
684+ c_builtin(restr_com);
637685 /* After typeset command... */
638686 Flag(FRESTRICTED) = 1;
639687 }
@@ -663,9 +711,9 @@ main(int argc, const char *argv[])
663711
664712 if ((rv = main_init(argc, argv, &s, &l)) == 0) {
665713 if (Flag(FAS_BUILTIN)) {
666- rv = shcomexec(l->argv);
714+ rv = c_builtin(l->argv);
667715 } else {
668- shell(s, true);
716+ shell(s, 0);
669717 /* NOTREACHED */
670718 }
671719 }
@@ -718,7 +766,7 @@ include(const char *name, int argc, const char **argv, bool intr_ok)
718766 unwind(i);
719767 /* NOTREACHED */
720768 default:
721- internal_errorf("include %d", i);
769+ internal_errorf(Tunexpected_type, Tunwind, Tsource, i);
722770 /* NOTREACHED */
723771 }
724772 }
@@ -729,7 +777,7 @@ include(const char *name, int argc, const char **argv, bool intr_ok)
729777 s = pushs(SFILE, ATEMP);
730778 s->u.shf = shf;
731779 strdupx(s->file, name, ATEMP);
732- i = shell(s, false);
780+ i = shell(s, 1);
733781 quitenv(s->u.shf);
734782 if (old_argv) {
735783 e->loc->argv = old_argv;
@@ -749,7 +797,7 @@ command(const char *comm, int line)
749797 s = pushs(SSTRING, ATEMP);
750798 s->start = s->str = comm;
751799 s->line = line;
752- rv = shell(s, false);
800+ rv = shell(s, 1);
753801 source = sold;
754802 return (rv);
755803 }
@@ -758,22 +806,33 @@ command(const char *comm, int line)
758806 * run the commands from the input source, returning status.
759807 */
760808 int
761-shell(Source * volatile s, volatile bool toplevel)
809+shell(Source * volatile s, volatile int level)
762810 {
763811 struct op *t;
764812 volatile bool wastty = tobool(s->flags & SF_TTY);
765813 volatile uint8_t attempts = 13;
766- volatile bool interactive = Flag(FTALKING) && toplevel;
814+ volatile bool interactive = (level == 0) && Flag(FTALKING);
767815 volatile bool sfirst = true;
768816 Source *volatile old_source = source;
769817 int i;
770818
771- newenv(E_PARSE);
819+ newenv(level == 2 ? E_EVAL : E_PARSE);
772820 if (interactive)
773821 really_exit = false;
774822 switch ((i = kshsetjmp(e->jbuf))) {
775823 case 0:
776824 break;
825+ case LBREAK:
826+ case LCONTIN:
827+ if (level != 2) {
828+ source = old_source;
829+ quitenv(NULL);
830+ internal_errorf(Tf_cant_s, Tshell,
831+ i == LBREAK ? Tbreak : Tcontinue);
832+ /* NOTREACHED */
833+ }
834+ /* assert: interactive == false */
835+ /* FALLTHROUGH */
777836 case LINTR:
778837 /* we get here if SIGINT not caught or ignored */
779838 case LERROR:
@@ -813,7 +872,7 @@ shell(Source * volatile s, volatile bool toplevel)
813872 default:
814873 source = old_source;
815874 quitenv(NULL);
816- internal_errorf("shell %d", i);
875+ internal_errorf(Tunexpected_type, Tunwind, Tshell, i);
817876 /* NOTREACHED */
818877 }
819878 while (/* CONSTCOND */ 1) {
@@ -830,7 +889,7 @@ shell(Source * volatile s, volatile bool toplevel)
830889 j_notify();
831890 set_prompt(PS1, s);
832891 }
833- t = compile(s, sfirst);
892+ t = compile(s, sfirst, true);
834893 if (interactive)
835894 histsave(&s->line, NULL, HIST_FLUSH, true);
836895 sfirst = false;
@@ -851,7 +910,7 @@ shell(Source * volatile s, volatile bool toplevel)
851910 * immediately after the last command
852911 * executed.
853912 */
854- if (toplevel)
913+ if (level == 0)
855914 unwind(LEXIT);
856915 break;
857916 }
@@ -914,6 +973,7 @@ unwind(int i)
914973 case E_INCL:
915974 case E_LOOP:
916975 case E_ERRH:
976+ case E_EVAL:
917977 kshlongjmp(e->jbuf, i);
918978 /* NOTREACHED */
919979 case E_NONE:
@@ -1277,12 +1337,10 @@ bi_errorf(const char *fmt, ...)
12771337 VWARNINGF_BUILTIN, fmt, va);
12781338 va_end(va);
12791339
1280- /*
1281- * POSIX special builtins and ksh special builtins cause
1282- * non-interactive shells to exit. XXX may not want LERROR here
1283- */
1340+ /* POSIX special builtins cause non-interactive shells to exit */
12841341 if (builtin_spec) {
12851342 builtin_argv0 = NULL;
1343+ /* may not want to use LERROR here */
12861344 unwind(LERROR);
12871345 }
12881346 }
@@ -1385,19 +1443,19 @@ initio(void)
13851443 #ifdef DF
13861444 if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
13871445 if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp))
1388- errorf("cannot get home directory");
1446+ errorf("can't get home directory");
13891447 lfp = shf_smprintf(Tf_sSs, lfp, "mksh-dbg.txt");
13901448 }
13911449
13921450 if ((shl_dbg_fd = open(lfp, O_WRONLY | O_APPEND | O_CREAT, 0600)) < 0)
1393- errorf("cannot open debug output file %s", lfp);
1451+ errorf("can't open debug output file %s", lfp);
13941452 if (shl_dbg_fd < FDBASE) {
13951453 int nfd;
13961454
13971455 nfd = fcntl(shl_dbg_fd, F_DUPFD, FDBASE);
13981456 close(shl_dbg_fd);
13991457 if ((shl_dbg_fd = nfd) == -1)
1400- errorf("cannot dup debug output file");
1458+ errorf("can't dup debug output file");
14011459 }
14021460 fcntl(shl_dbg_fd, F_SETFD, FD_CLOEXEC);
14031461 shf_fdopen(shl_dbg_fd, SHF_WR, shl_dbg);
@@ -1413,7 +1471,7 @@ ksh_dup2(int ofd, int nfd, bool errok)
14131471 int rv;
14141472
14151473 if (((rv = dup2(ofd, nfd)) < 0) && !errok && (errno != EBADF))
1416- errorf("too many files open in shell");
1474+ errorf(Ttoo_many_files);
14171475
14181476 #ifdef __ultrix
14191477 /*XXX imake style */
@@ -1437,7 +1495,7 @@ savefd(int fd)
14371495 (errno == EBADF || errno == EPERM))
14381496 return (-1);
14391497 if (nfd < 0 || nfd > SHRT_MAX)
1440- errorf("too many files open in shell");
1498+ errorf(Ttoo_many_files);
14411499 fcntl(nfd, F_SETFD, FD_CLOEXEC);
14421500 return ((short)nfd);
14431501 }
@@ -1470,6 +1528,10 @@ openpipe(int *pv)
14701528 pv[1] = savefd(lpv[1]);
14711529 if (pv[1] != lpv[1])
14721530 close(lpv[1]);
1531+#ifdef __OS2__
1532+ setmode(pv[0], O_BINARY);
1533+ setmode(pv[1], O_BINARY);
1534+#endif
14731535 }
14741536
14751537 void
--- a/src/misc.c
+++ b/src/misc.c
@@ -3,7 +3,7 @@
33
44 /*-
55 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6- * 2011, 2012, 2013, 2014, 2015, 2016
6+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
77 * mirabilos <m@mirbsd.org>
88 *
99 * Provided that these terms and disclaimer and all copyright notices
@@ -30,7 +30,7 @@
3030 #include <grp.h>
3131 #endif
3232
33-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.249 2016/11/11 23:31:35 tg Exp $");
33+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.255 2017/04/12 16:46:22 tg Exp $");
3434
3535 #define KSH_CHVT_FLAG
3636 #ifdef MKSH_SMALL
@@ -40,10 +40,6 @@ __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.249 2016/11/11 23:31:35 tg Exp $");
4040 #define KSH_CHVT_CODE
4141 #define KSH_CHVT_FLAG
4242 #endif
43-#ifdef MKSH_LEGACY_MODE
44-#undef KSH_CHVT_CODE
45-#undef KSH_CHVT_FLAG
46-#endif
4743
4844 /* type bits for unsigned char */
4945 unsigned char chtypes[UCHAR_MAX + 1];
@@ -93,11 +89,10 @@ setctypes(const char *s, int t)
9389 void
9490 initctypes(void)
9591 {
96- setctypes(letters_uc, C_ALPHA);
97- setctypes(letters_lc, C_ALPHA);
98- chtypes['_'] |= C_ALPHA;
92+ setctypes(letters_uc, C_ALPHX);
93+ setctypes(letters_lc, C_ALPHX);
94+ chtypes['_'] |= C_ALPHX;
9995 setctypes("0123456789", C_DIGIT);
100- /* \0 added automatically */
10196 setctypes(TC_LEX1, C_LEX1);
10297 setctypes("*@#!$-?", C_VAR1);
10398 setctypes(TC_IFSWS, C_IFSWS);
@@ -506,7 +501,7 @@ parse_args(const char **argv,
506501 if (arrayset) {
507502 const char *ccp = NULL;
508503
509- if (*array)
504+ if (array && *array)
510505 ccp = skip_varname(array, false);
511506 if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) {
512507 bi_errorf(Tf_sD_s, array, Tnot_ident);
@@ -1541,12 +1536,11 @@ do_realpath(const char *upath)
15411536 /* symlink target is an absolute path */
15421537 xp = Xstring(xs, xp);
15431538 beginning_of_a_pathname:
1544- /* assert: (ip == ipath)[0] == '/' */
1539+ /* assert: mksh_cdirsep((ip == ipath)[0]) */
15451540 /* assert: xp == xs.beg => start of path */
15461541
15471542 /* exactly two leading slashes? (SUSv4 3.266) */
1548- /* @komh do NOT use mksh_cdirsep() here */
1549- if (ip[1] == '/' && ip[2] != '/') {
1543+ if (ip[1] == ip[0] && !mksh_cdirsep(ip[2])) {
15501544 /* keep them, e.g. for UNC pathnames */
15511545 Xput(xs, xp, '/');
15521546 }
@@ -1711,15 +1705,13 @@ simplify_path(char *p)
17111705 case 0:
17121706 return;
17131707 case '/':
1708+#ifdef MKSH_DOSPATH
1709+ case '\\':
1710+#endif
17141711 /* exactly two leading slashes? (SUSv4 3.266) */
1715- /* @komh no mksh_cdirsep() here! */
1716- if (p[1] == '/' && p[2] != '/')
1712+ if (p[1] == p[0] && !mksh_cdirsep(p[2]))
17171713 /* keep them, e.g. for UNC pathnames */
17181714 ++p;
1719-#ifdef __OS2__
1720- /* FALLTHROUGH */
1721- case '\\':
1722-#endif
17231715 needslash = true;
17241716 break;
17251717 default:
@@ -2157,7 +2149,7 @@ getrusage(int what, struct rusage *ru)
21572149 int
21582150 unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
21592151 {
2160- int wc, i, c, fc;
2152+ int wc, i, c, fc, n;
21612153
21622154 fc = (*fg)();
21632155 switch (fc) {
@@ -2245,7 +2237,8 @@ unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
22452237 * four (U: eight) digits; convert to Unicode
22462238 */
22472239 wc = 0;
2248- while (i--) {
2240+ n = 0;
2241+ while (n < i || i == -1) {
22492242 wc <<= 4;
22502243 if ((c = (*fg)()) >= ord('0') && c <= ord('9'))
22512244 wc += ksh_numdig(c);
@@ -2258,7 +2251,10 @@ unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
22582251 (*fp)(c);
22592252 break;
22602253 }
2254+ ++n;
22612255 }
2256+ if (!n)
2257+ goto unknown_escape;
22622258 if ((cstyle && wc > 0xFF) || fc != 'x')
22632259 /* Unicode marker */
22642260 wc += 0x100;
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,8 +1,8 @@
1-.\" $MirOS: src/bin/mksh/mksh.1,v 1.420 2016/11/11 23:31:36 tg Exp $
1+.\" $MirOS: src/bin/mksh/mksh.1,v 1.442 2017/04/12 18:30:58 tg Exp $
22 .\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
33 .\"-
44 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
5-.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016
5+.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017
66 .\" mirabilos <m@mirbsd.org>
77 .\"
88 .\" Provided that these terms and disclaimer and all copyright notices
@@ -76,7 +76,7 @@
7676 .\" with -mandoc, it might implement .Mx itself, but we want to
7777 .\" use our own definition. And .Dd must come *first*, always.
7878 .\"
79-.Dd $Mdocdate: November 11 2016 $
79+.Dd $Mdocdate: April 12 2017 $
8080 .\"
8181 .\" Check which macro package we use, and do other -mdoc setup.
8282 .\"
@@ -186,23 +186,8 @@ sometimes does take portable shell scripting or various standards
186186 into account all information is first and foremost presented with
187187 .Nm
188188 in mind and should be taken as such.
189-.Ss I'm an Android user, so what's mksh?
190-.Nm mksh
191-is a
192-.Ux
193-shell / command interpreter, similar to
194-.Nm COMMAND.COM
195-or
196-.Nm CMD.EXE ,
197-which has been included with
198-.Tn Android Open Source Project
199-for a while now.
200-Basically, it's a program that runs in a terminal (console window),
201-takes user input and runs commands or scripts, which it can also
202-be asked to do by other programs, even in the background.
203-Any privilege pop-ups you might be encountering are thus not
204-.Nm mksh
205-issues but questions by some other program utilising it.
189+.Ss I use Android, OS/2, etc. so what...?
190+Please see the FAQ at the end of this document.
206191 .Ss Invocation
207192 Most builtins can be called directly, for example if a link points from its
208193 name to the shell; not all make sense, have been tested or work at all though.
@@ -1130,17 +1115,17 @@ also by newline) may be one same parse tree.
11301115 .Pp
11311116 The following command aliases are defined automatically by the shell:
11321117 .Bd -literal -offset indent
1133-autoload=\*(aq\etypeset \-fu\*(aq
1134-functions=\*(aq\etypeset \-f\*(aq
1135-hash=\*(aq\ebuiltin alias \-t\*(aq
1136-history=\*(aq\ebuiltin fc \-l\*(aq
1137-integer=\*(aq\etypeset \-i\*(aq
1138-local=\*(aq\etypeset\*(aq
1139-login=\*(aq\eexec login\*(aq
1140-nameref=\*(aq\etypeset \-n\*(aq
1118+autoload=\*(aq\e\ebuiltin typeset \-fu\*(aq
1119+functions=\*(aq\e\ebuiltin typeset \-f\*(aq
1120+hash=\*(aq\e\ebuiltin alias \-t\*(aq
1121+history=\*(aq\e\ebuiltin fc \-l\*(aq
1122+integer=\*(aq\e\ebuiltin typeset \-i\*(aq
1123+local=\*(aq\e\ebuiltin typeset\*(aq
1124+login=\*(aq\e\ebuiltin exec login\*(aq
1125+nameref=\*(aq\e\ebuiltin typeset \-n\*(aq
11411126 nohup=\*(aqnohup \*(aq
1142-r=\*(aq\ebuiltin fc \-e \-\*(aq
1143-type=\*(aq\ebuiltin whence \-v\*(aq
1127+r=\*(aq\e\ebuiltin fc \-e \-\*(aq
1128+type=\*(aq\e\ebuiltin whence \-v\*(aq
11441129 .Ed
11451130 .Pp
11461131 Tracked aliases allow the shell to remember where it found a particular
@@ -2035,9 +2020,11 @@ searched when looking for commands and files sourced using the
20352020 .Dq Li \&.
20362021 command (see below).
20372022 An empty string resulting from a leading or trailing
2038-colon, or two adjacent colons, is treated as a
2023+(semi)colon, or two adjacent ones, is treated as a
20392024 .Dq Li \&.
20402025 (the current directory).
2026+.It Ev PATHSEP
2027+A colon (semicolon on OS/2), for the user's convenience.
20412028 .It Ev PGRP
20422029 The process ID of the shell's process group leader.
20432030 .It Ev PIPESTATUS
@@ -2127,7 +2114,7 @@ Due to a strong suggestion from David G. Korn,
21272114 .Nm
21282115 now also supports the following form:
21292116 .Bd -literal -offset indent
2130-PS1=$'\e1\er\e1\ee[7m\e1$PWD\e1\ee[0m\e1\*(Gt '
2117+PS1=$\*(aq\e1\er\e1\ee[7m\e1$PWD\e1\ee[0m\e1\*(Gt \*(aq
21312118 .Ed
21322119 .It Ev PS2
21332120 Secondary prompt string, by default
@@ -2185,9 +2172,18 @@ files are created in
21852172 The effective user id of the shell.
21862173 .El
21872174 .Ss Tilde expansion
2188-Tilde expansion which is done in parallel with parameter substitution, is done
2189-on words starting with an unquoted
2175+Tilde expansion, which is done in parallel with parameter substitution,
2176+is applied to words starting with an unquoted
21902177 .Ql \*(TI .
2178+In parameter assignments (such as those preceding a simple-command or those
2179+occurring in the arguments of a declaration utility), tilde expansion is done
2180+after any assignment (i.e. after the equals sign) or after an unquoted colon
2181+.Pq Ql \&: ;
2182+login names are also delimited by colons.
2183+The Korn shell, except in POSIX mode, always expands tildes after unquoted
2184+equals signs, not just in assignment context (see below), and enables tab
2185+completion for tildes after all unquoted colons during command line editing.
2186+.Pp
21912187 The characters following the tilde, up to the first
21922188 .Ql / ,
21932189 if any, are assumed to be a login name.
@@ -2208,21 +2204,6 @@ If the login name is not found in the password file or
22082204 if any quoting or parameter substitution occurs in the login name, no
22092205 substitution is performed.
22102206 .Pp
2211-In parameter assignments
2212-(such as those preceding a simple-command or those occurring
2213-in the arguments of
2214-.Ic alias ,
2215-.Ic export ,
2216-.Ic global ,
2217-.Ic readonly
2218-and
2219-.Ic typeset ) ,
2220-tilde expansion is done after any assignment
2221-(i.e. after the equals sign)
2222-or after an unquoted colon
2223-.Pq Ql \&: ;
2224-login names are also delimited by colons.
2225-.Pp
22262207 The home directory of previously expanded login names are cached and re-used.
22272208 The
22282209 .Ic alias Fl d
@@ -2586,7 +2567,7 @@ Redirections are processed after
25862567 pipelines are created and in the order they are given, so the following
25872568 will print an error with a line number prepended to it:
25882569 .Pp
2589-.D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
2570+.Dl $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
25902571 .Pp
25912572 File descriptors created by I/O redirections are private to the shell.
25922573 .Ss Arithmetic expressions
@@ -2946,6 +2927,12 @@ function.
29462927 A function can be made to finish immediately using the
29472928 .Ic return
29482929 command; this may also be used to explicitly specify the exit status.
2930+Note that when called in a subshell,
2931+.Ic return
2932+will only exit that subshell and will not cause the original shell to exit
2933+a running function (see the
2934+.Ic while Ns Li \&... Ns Ic read
2935+loop FAQ below).
29492936 .Pp
29502937 Functions defined with the
29512938 .Ic function
@@ -3022,18 +3009,18 @@ Additional
30223009 .Nm
30233010 commands keeping assignments:
30243011 .Pp
3025-.Ic builtin , global , source , typeset ,
3026-.Ic wait
3012+.Ic global , source , typeset
30273013 .Pp
30283014 Builtins that are not special:
30293015 .Pp
30303016 .Ic [ , alias , bg , bind ,
3031-.Ic cat , cd , command , echo ,
3032-.Ic false , fc , fg , getopts ,
3033-.Ic jobs , kill , let , print ,
3034-.Ic pwd , read , realpath , rename ,
3035-.Ic sleep , suspend , test , true ,
3036-.Ic ulimit , umask , unalias , whence
3017+.Ic builtin , cat , cd , command ,
3018+.Ic echo , false , fc , fg ,
3019+.Ic getopts , jobs , kill , let ,
3020+.Ic print , pwd , read , realpath ,
3021+.Ic rename , sleep , suspend , test ,
3022+.Ic true , ulimit , umask , unalias ,
3023+.Ic wait , whence
30373024 .Pp
30383025 Once the type of command has been determined, any command-line parameter
30393026 assignments are performed and exported for the duration of the command.
@@ -3082,6 +3069,8 @@ For any name without a value, the existing alias is listed.
30823069 Any name with a value defines an alias (see
30833070 .Sx Aliases
30843071 above).
3072+.Li \&[A\-Za\-z0\-9_!%,@\-]
3073+are valid in names except they may not begin with a hyphen-minus.
30853074 .Pp
30863075 When listing aliases, one of two formats is used.
30873076 Normally, aliases are listed as
@@ -3217,6 +3206,18 @@ Execute the built-in command
32173206 .Ar command .
32183207 .Pp
32193208 .It Xo
3209+.Ic \ebuiltin
3210+.Ar command Op Ar arg ...
3211+.Xc
3212+Same as
3213+.Ic builtin .
3214+Additionally acts as declaration utility forwarder, i.e. this is a
3215+declaration utility (see
3216+.Sx Tilde expansion )
3217+.No iff Ar command
3218+is a declaration utility.
3219+.Pp
3220+.It Xo
32203221 .Ic cat
32213222 .Op Fl u
32223223 .Op Ar
@@ -3346,6 +3347,7 @@ cannot be a shell function;
33463347 and secondly, special built-in commands lose their specialness
33473348 (i.e. redirection and utility errors do not cause the shell to
33483349 exit, and command assignments are not permanent).
3350+The declaration utility property is not reset.
33493351 .Pp
33503352 If the
33513353 .Fl p
@@ -3421,8 +3423,10 @@ If the
34213423 .Ic posix
34223424 or
34233425 .Ic sh
3424-option is set or this is a direct builtin call, only the first argument
3425-is treated as an option, and only if it is exactly
3426+option is set or this is a direct builtin call or
3427+.Ic print
3428+.Fl R ,
3429+only the first argument is treated as an option, and only if it is exactly
34263430 .Dq Li \-n .
34273431 Backslash interpretation is disabled.
34283432 .Pp
@@ -3463,7 +3467,7 @@ Note that the Bourne shell differs here;
34633467 it does pass these file descriptors on.
34643468 .Pp
34653469 .It Ic exit Op Ar status
3466-The shell exits with the specified exit status.
3470+The shell or subshell exits with the specified exit status.
34673471 If
34683472 .Ar status
34693473 is not specified, the exit status is the current value of the
@@ -3478,6 +3482,7 @@ parameter.
34783482 Sets the export attribute of the named parameters.
34793483 Exported parameters are passed in the environment to executed commands.
34803484 If values are specified, the named parameters are also assigned.
3485+This is a declaration utility.
34813486 .Pp
34823487 If no parameters are specified, all parameters with the export attribute
34833488 set are printed one per line; either their names, or, if a
@@ -3632,9 +3637,22 @@ resetting
36323637 .Ev OPTIND
36333638 may lead to unexpected results.
36343639 .Pp
3635-.It global Ar ...
3640+.It Xo
3641+.Ic global
3642+.Op Ic +\-aglpnrtUux
3643+.Oo Fl L Ns Op Ar n
3644+.No \*(Ba Fl R Ns Op Ar n
3645+.No \*(Ba Fl Z Ns Op Ar n Oc
3646+.Op Fl i Ns Op Ar n
3647+.Oo Ar name
3648+.Op Ns = Ns Ar value
3649+.Ar ... Oc
3650+.Xc
36363651 See
3637-.Ic typeset .
3652+.Ic typeset Fl g .
3653+.No Deprecated , Em will
3654+be removed from a future version of
3655+.Nm .
36383656 .Pp
36393657 .It Xo
36403658 .Ic hash
@@ -3712,12 +3730,8 @@ If an error occurs during
37123730 the parsing or evaluation of an expression, the exit status is greater than 1.
37133731 Since expressions may need to be quoted,
37143732 .No \&(( Ar expr No ))
3715-is syntactic sugar for
3716-.No "{ let '" Ns Ar expr Ns "'; }" .
3717-.Pp
3718-.It Ic let]
3719-Internally used alias for
3720-.Ic let .
3733+is syntactic sugar for:
3734+.Dl "{ \e\ebuiltin let \*(aq" Ns Ar expr Ns "\*(aq; }"
37213735 .Pp
37223736 .It Xo
37233737 .Ic mknod
@@ -3757,13 +3771,13 @@ however, distributors may have added this as builtin as a speed hack.
37573771 .Pp
37583772 .It Xo
37593773 .Ic print
3760-.Oo Fl AclNnprsu Ns Oo Ar n Oc \*(Ba
3761-.Fl R Op Fl en Oc
3774+.Oo Fl AcelNnprsu Ns Oo Ar n Oc \*(Ba
3775+.Fl R Op Fl n Oc
37623776 .Op Ar argument ...
37633777 .Xc
37643778 Print the specified argument(s) on the standard output,
37653779 separated by spaces, terminated with a newline.
3766-The C escapes mentioned in
3780+The escapes mentioned in
37673781 .Sx Backslash expansion
37683782 above, as well as
37693783 .Dq Li \ec ,
@@ -3789,6 +3803,9 @@ utility, tab completion, the
37893803 built-in utility and the
37903804 .Ic select
37913805 statement do.
3806+.It Fl e
3807+Restore backslash expansion after a previous
3808+.Fl r .
37923809 .It Fl l
37933810 Change the output word separator to newline.
37943811 .It Fl N
@@ -3803,7 +3820,7 @@ above).
38033820 Inhibit backslash expansion.
38043821 .It Fl s
38053822 Print to the history file instead of standard output.
3806-.It Fl u Op Ar n
3823+.It Fl u Ns Op Ar n
38073824 Print to the file descriptor
38083825 .Ar n Pq defaults to 1 if omitted
38093826 instead of standard output.
@@ -3811,31 +3828,13 @@ instead of standard output.
38113828 .Pp
38123829 The
38133830 .Fl R
3814-option is used to emulate, to some degree, the
3831+option mostly emulates the
38153832 .Bx
38163833 .Xr echo 1
3817-command which does not process
3818-.Ql \e
3819-sequences unless the
3820-.Fl e
3821-option is given.
3822-As above, the
3823-.Fl n
3824-option suppresses the trailing newline.
3825-.Pp
3826-.It Ic printf Ar format Op Ar arguments ...
3827-Formatted output.
3828-Approximately the same as the
3829-.Xr printf 1 ,
3830-utility, except it uses the same
3831-.Sx Backslash expansion
3832-and I/O code and does not handle floating point as the rest of
3833-.Nm mksh .
3834-An external utility is preferred over the builtin.
3835-This is not normally part of
3836-.Nm mksh ;
3837-however, distributors may have added this as builtin as a speed hack.
3838-Do not use in new code.
3834+command which does not expand backslashes and interprets
3835+its first argument as option only if it is exactly
3836+.Dq Li \-n
3837+.Pq to suppress the trailing newline .
38393838 .Pp
38403839 .It Ic pwd Op Fl LP
38413840 Print the present working directory.
@@ -3970,40 +3969,6 @@ If no input is read or a timeout occurred,
39703969 .Ic read
39713970 exits with a non-zero status.
39723971 .Pp
3973-Another handy set of tricks:
3974-If
3975-.Ic read
3976-is run in a loop such as
3977-.Ic while read foo; do ...; done
3978-then leading whitespace will be removed (IFS) and backslashes processed.
3979-You might want to use
3980-.Ic while IFS= read \-r foo; do ...; done
3981-for pristine I/O.
3982-Similarly, when using the
3983-.Fl a
3984-option, use of the
3985-.Fl r
3986-option might be prudent; the same applies for:
3987-.Bd -literal -offset indent
3988-find . \-type f \-print0 \*(Ba& \e
3989- while IFS= read \-d \*(aq\*(aq \-pr filename; do
3990- print \-r \-\- "found \*(Lt${filename#./}\*(Gt"
3991-done
3992-.Ed
3993-.Pp
3994-The inner loop will be executed in a subshell and variable changes
3995-cannot be propagated if executed in a pipeline:
3996-.Bd -literal -offset indent
3997-bar \*(Ba baz \*(Ba while read foo; do ...; done
3998-.Ed
3999-.Pp
4000-Use co-processes instead:
4001-.Bd -literal -offset indent
4002-bar \*(Ba baz \*(Ba&
4003-while read \-p foo; do ...; done
4004-exec 3\*(Gt&p; exec 3\*(Gt&\-
4005-.Ed
4006-.Pp
40073972 .It Xo
40083973 .Ic readonly
40093974 .Op Fl p
@@ -4012,6 +3977,7 @@ exec 3\*(Gt&p; exec 3\*(Gt&\-
40123977 .Ar ... Oc
40133978 .Xc
40143979 Sets the read-only attribute of the named parameters.
3980+This is a declaration utility.
40153981 If values are given,
40163982 parameters are set to them before setting the attribute.
40173983 Once a parameter is
@@ -4266,7 +4232,6 @@ Background jobs are run with lower priority.
42664232 .It Fl o Ic braceexpand
42674233 Enable brace expansion (a.k.a. alternation).
42684234 This is enabled by default.
4269-If disabled, tilde expansion after an equals sign is disabled as a side effect.
42704235 .It Fl o Ic emacs
42714236 Enable BRL emacs-like command-line editing (interactive shells only); see
42724237 .Sx Emacs editing mode .
@@ -4507,34 +4472,6 @@ is a symbolic link.
45074472 .It Fl O Ar file
45084473 .Ar file Ns 's
45094474 owner is the shell's effective user ID.
4510-.It Fl o Ar option
4511-Shell
4512-.Ar option
4513-is set (see the
4514-.Ic set
4515-command above for a list of options).
4516-As a non-standard extension, if the option starts with a
4517-.Ql \&! ,
4518-the test is negated; the test always fails if
4519-.Ar option
4520-doesn't exist (so [ \-o foo \-o \-o !foo ] returns true if and only if option
4521-.Ar foo
4522-exists).
4523-The same can be achieved with [ \-o ?foo ] like in
4524-.At
4525-.Nm ksh93 .
4526-.Ar option
4527-can also be the short flag led by either
4528-.Ql \-
4529-or
4530-.Ql +
4531-.Pq no logical negation ,
4532-for example
4533-.Dq Li \-x
4534-or
4535-.Dq Li +x
4536-instead of
4537-.Dq Li xtrace .
45384475 .It Fl p Ar file
45394476 .Ar file
45404477 is a named pipe
@@ -4596,6 +4533,38 @@ is not empty.
45964533 .It Fl z Ar string
45974534 .Ar string
45984535 is empty.
4536+.It Fl v Ar name
4537+The shell parameter
4538+.Ar name
4539+is set.
4540+.It Fl o Ar option
4541+Shell
4542+.Ar option
4543+is set (see the
4544+.Ic set
4545+command above for a list of options).
4546+As a non-standard extension, if the option starts with a
4547+.Ql \&! ,
4548+the test is negated; the test always fails if
4549+.Ar option
4550+doesn't exist (so [ \-o foo \-o \-o !foo ] returns true if and only if option
4551+.Ar foo
4552+exists).
4553+The same can be achieved with [ \-o ?foo ] like in
4554+.At
4555+.Nm ksh93 .
4556+.Ar option
4557+can also be the short flag led by either
4558+.Ql \-
4559+or
4560+.Ql +
4561+.Pq no logical negation ,
4562+for example
4563+.Dq Li \-x
4564+or
4565+.Dq Li +x
4566+instead of
4567+.Dq Li xtrace .
45994568 .It Ar string No = Ar string
46004569 Strings are equal.
46014570 .It Ar string No == Ar string
@@ -4800,28 +4769,23 @@ traps in functions are not yet implemented.
48004769 A command that exits with a zero value.
48014770 .Pp
48024771 .It Xo
4803-.Ic global
4804-.Oo Op Ic +\-alpnrtUux
4805-.Op Fl L Ns Op Ar n
4806-.Op Fl R Ns Op Ar n
4807-.Op Fl Z Ns Op Ar n
4772+.Ic typeset
4773+.Op Ic +\-aglpnrtUux
4774+.Oo Fl L Ns Op Ar n
4775+.No \*(Ba Fl R Ns Op Ar n
4776+.No \*(Ba Fl Z Ns Op Ar n Oc
48084777 .Op Fl i Ns Op Ar n
4809-.No \*(Ba Fl f Op Fl tux Oc
48104778 .Oo Ar name
48114779 .Op Ns = Ns Ar value
48124780 .Ar ... Oc
48134781 .Xc
48144782 .It Xo
48154783 .Ic typeset
4816-.Oo Op Ic +\-alpnrtUux
4817-.Op Fl LRZ Ns Op Ar n
4818-.Op Fl i Ns Op Ar n
4819-.No \*(Ba Fl f Op Fl tux Oc
4820-.Oo Ar name
4821-.Op Ns = Ns Ar value
4822-.Ar ... Oc
4784+.Fl f Op Fl tux
4785+.Op Ar name ...
48234786 .Xc
48244787 Display or set parameter attributes.
4788+This is a declaration utility.
48254789 With no
48264790 .Ar name
48274791 arguments, parameter attributes are displayed; if no options are used, the
@@ -4837,27 +4801,16 @@ parameter values are not printed.
48374801 If
48384802 .Ar name
48394803 arguments are given, the attributes of the named parameters are set
4840-.Pq Ic \-
4804+.Pq Ic \&\-
48414805 or cleared
4842-.Pq Ic + .
4806+.Pq Ic \&+ ;
4807+inside a function, this will cause the parameters to be created
4808+(with no value) in the local scope (but see
4809+.Fl g ) .
48434810 Values for parameters may optionally be specified.
48444811 For
48454812 .Ar name Ns \&[*] ,
4846-the change affects the entire array, and no value may be specified.
4847-.Pp
4848-If
4849-.Ic typeset
4850-is used inside a function, any parameters specified are localised.
4851-This is not done by the otherwise identical
4852-.Ic global .
4853-.Em Note :
4854-This means that
4855-.Nm No 's Ic global
4856-command is
4857-.Em not
4858-equivalent to other programming languages' as it does not allow a
4859-function called from another function to access a parameter at truly
4860-global scope, but only prevents putting an accessed one into local scope.
4813+the change affects all elements of the array, and no value may be specified.
48614814 .Pp
48624815 When
48634816 .Fl f
@@ -4877,6 +4830,9 @@ Indexed array attribute.
48774830 .It Fl f
48784831 Function mode.
48794832 Display or set functions and their attributes, instead of parameters.
4833+.It Fl g
4834+Do not cause named parameters to be created in
4835+the local scope when called inside a function.
48804836 .It Fl i Ns Op Ar n
48814837 Integer attribute.
48824838 .Ar n
@@ -5028,7 +4984,7 @@ once they are set.
50284984 Also note that the types of limits available are system
50294985 dependent \*(en some systems have only the
50304986 .Fl f
5031-limit.
4987+limit, or not even that, or can set only the soft limits
50324988 .Bl -tag -width 5n
50334989 .It Fl a
50344990 Display all limits; unless
@@ -5395,11 +5351,11 @@ Most other historic,
53955351 or opinionated differences can be disabled by using this mode; these are:
53965352 .Bl -bullet
53975353 .It
5398-The GNU
5354+The incompatible GNU
53995355 .Nm bash
54005356 I/O redirection
54015357 .Ic &\*(Gt Ns Ar file
5402-is no longer supported.
5358+is not supported.
54035359 .It
54045360 File descriptors created by I/O redirections are inherited by
54055361 child processes.
@@ -5409,20 +5365,34 @@ Numbers with a leading digit zero are interpreted as octal.
54095365 The
54105366 .Nm echo
54115367 builtin does not interpret backslashes and only supports the exact option
5412-.Dq Li \-n .
5368+.Fl n .
5369+.It
5370+Alias expansion with a trailing space only reruns on command words.
5371+.It
5372+Tilde expansion follows POSIX instead of Korn shell rules.
54135373 .It
5414-\&... (list is incomplete and may change for R54)
5374+The exit status of
5375+.Ic fg
5376+is always 0.
5377+.It
5378+.Ic kill
5379+.Fl l
5380+only lists signal names, all in one line.
5381+.It
5382+.Ic getopts
5383+does not accept options with a leading
5384+.Ql + .
54155385 .El
54165386 .Ss SH mode
54175387 Compatibility mode; intended for use with legacy scripts that
54185388 cannot easily be fixed; the changes are as follows:
54195389 .Bl -bullet
54205390 .It
5421-The GNU
5391+The incompatible GNU
54225392 .Nm bash
54235393 I/O redirection
54245394 .Ic &\*(Gt Ns Ar file
5425-is no longer supported.
5395+is not supported.
54265396 .It
54275397 File descriptors created by I/O redirections are inherited by
54285398 child processes.
@@ -5430,7 +5400,9 @@ child processes.
54305400 The
54315401 .Nm echo
54325402 builtin does not interpret backslashes and only supports the exact option
5433-.Dq Li \-n .
5403+.Fl n ,
5404+unless built with
5405+.Ev \-DMKSH_MIDNIGHTBSD01ASH_COMPAT .
54345406 .It
54355407 The substitution operations
54365408 .Sm off
@@ -5460,7 +5432,16 @@ and
54605432 .Xc
54615433 wrongly do not require a parenthesis to be escaped and do not parse extglobs.
54625434 .It
5463-\&... (list is incomplete and may change for R54)
5435+The getopt construct from
5436+.Xr lksh 1
5437+passes through the errorlevel.
5438+.It
5439+.Nm sh
5440+.Fl c
5441+eats a leading
5442+.Fl \-
5443+if built with
5444+.Ev \-DMKSH_MIDNIGHTBSD01ASH_COMPAT .
54645445 .El
54655446 .Ss Interactive input line editing
54665447 The shell supports three modes of reading command lines from a
@@ -5744,9 +5725,6 @@ Goes to history number
57445725 .No KILL Pq \*(haU
57455726 .Xc
57465727 Deletes the entire input line.
5747-If Ctrl-U should only delete the line up to the cursor, use:
5748-.Pp
5749-.D1 $ bind \-m \*(haU='\*(ha[0\*(haK'
57505728 .It kill\-region: \*(haW
57515729 Deletes the input between the cursor and the mark.
57525730 .It Xo kill\-to\-eol:
@@ -6514,7 +6492,7 @@ contains the system and suid profile.
65146492 .Xr utf\-8 7 ,
65156493 .Xr mknod 8
65166494 .Pp
6517-.Pa https://www.mirbsd.org/ksh\-chan.htm
6495+.Pa http://www.mirbsd.org/ksh\-chan.htm
65186496 .Rs
65196497 .%A Morris Bolsky
65206498 .%B "The KornShell Command and Programming Language"
@@ -6608,9 +6586,17 @@ The effort of several projects, such as Debian and OpenBSD, and other
66086586 contributors including our users, to improve the shell is appreciated.
66096587 See the documentation, web site and CVS for details.
66106588 .Pp
6589+.Nm mksh\-os2
6590+is developed by
6591+.An KO Myung-Hun Aq Mt komh@chollian.net .
6592+.Pp
6593+.Nm mksh\-w32
6594+is developed by
6595+.An Michael Langguth Aq Mt lan@scalaris.com .
6596+.Pp
66116597 The BSD daemon is Copyright \(co Marshall Kirk McKusick.
66126598 The complete legalese is at:
6613-.Pa https://www.mirbsd.org/TaC\-mksh.txt
6599+.Pa http://www.mirbsd.org/TaC\-mksh.txt
66146600 .\"
66156601 .\" This boils down to: feel free to use mksh.ico as application icon
66166602 .\" or shortcut for mksh or mksh/Win32 or OS/2; distro patches are ok
@@ -6625,24 +6611,6 @@ The complete legalese is at:
66256611 .\" to protect it or lose it, which McKusick almost did.
66266612 .\"
66276613 .Sh CAVEATS
6628-.Nm
6629-has a different scope model from
6630-.At
6631-.Nm ksh ,
6632-which leads to subtle differences in semantics for identical builtins.
6633-This can cause issues with a
6634-.Ic nameref
6635-to suddenly point to a local variable by accident; fixing this is hard.
6636-.Pp
6637-The parts of a pipeline, like below, are executed in subshells.
6638-Thus, variable assignments inside them are not visible in the
6639-surrounding execution environment.
6640-Use co-processes instead.
6641-.Bd -literal -offset indent
6642-foo \*(Ba bar \*(Ba read baz # will not change $baz
6643-foo \*(Ba bar \*(Ba& read \-p baz # will, however, do so
6644-.Ed
6645-.Pp
66466614 .Nm mksh
66476615 provides a consistent 32-bit integer arithmetic implementation, both
66486616 signed and unsigned, with sign of the result of a remainder operation
@@ -6687,6 +6655,8 @@ case ${KSH_VERSION:\-} in
66876655 esac
66886656 .Ed
66896657 In near future, (Unicode) locale tracking will be implemented though.
6658+.Pp
6659+See also the FAQ below.
66906660 .Sh BUGS
66916661 Suspending (using \*(haZ) pipelines like the one below will only suspend
66926662 the currently running part of the pipeline; in this example,
@@ -6710,7 +6680,7 @@ for the in-memory portion of the history is slow, should use
67106680 .Xr memmove 3 .
67116681 .Pp
67126682 This document attempts to describe
6713-.Nm mksh\ R54
6683+.Nm mksh\ R55
67146684 and up,
67156685 .\" with vendor patches from insert-your-name-here,
67166686 compiled without any options impacting functionality, such as
@@ -6727,9 +6697,8 @@ for an operating environment supporting all of its advanced needs.
67276697 Please report bugs in
67286698 .Nm
67296699 to the
6730-.Mx
6731-mailing list at
67326700 .Aq Mt miros\-mksh@mirbsd.org
6701+mailing list
67336702 or in the
67346703 .Li \&#\&!/bin/mksh
67356704 .Pq or Li \&#ksh
@@ -6738,3 +6707,177 @@ IRC channel at
67386707 .Pq Port 6697 SSL, 6667 unencrypted ,
67396708 or at:
67406709 .Pa https://launchpad.net/mksh
6710+.Sh FREQUENTLY ASKED QUESTIONS
6711+This FAQ attempts to document some of the questions users of
6712+.Nm
6713+or readers of this manual page may encounter.
6714+.Ss I'm an Android user, so what's mksh?
6715+.Nm mksh
6716+is a
6717+.Ux
6718+shell / command interpreter, similar to
6719+.Nm COMMAND.COM
6720+or
6721+.Nm CMD.EXE ,
6722+which has been included with
6723+.Tn Android Open Source Project
6724+for a while now.
6725+Basically, it's a program that runs in a terminal (console window),
6726+takes user input and runs commands or scripts, which it can also
6727+be asked to do by other programs, even in the background.
6728+Any privilege pop-ups you might be encountering are thus not
6729+.Nm mksh
6730+issues but questions by some other program utilising it.
6731+.Ss "I'm an OS/2 user, what do I need to know?"
6732+Unlike the native command prompt, the current working directory is,
6733+for security reasons common on Unix systems which the shell is designed for,
6734+not in the search path at all; if you really need this, run the command
6735+.Li PATH=.$PATHSEP$PATH
6736+or add that to a suitable initialisation file.
6737+.Pp
6738+There are two different newline modes for mksh-os2: standard (Unix) mode,
6739+in which only LF (0A hex) is supported as line separator, and "textmode",
6740+which also accepts ASCII newlines (CR+LF), like most other tools on OS/2,
6741+but creating an incompatibility with standard
6742+.Nm .
6743+If you compiled mksh from source, you will get the standard Unix mode unless
6744+.Fl T
6745+is added during compilation; you will most likely have gotten this shell
6746+through komh's port on Hobbes, or from his OS/2 Factory on eComStation
6747+Korea, which uses "textmode", though.
6748+Most OS/2 users will want to use "textmode" unless they need absolute
6749+compatibility with Unix
6750+.Nm .
6751+.Ss "How do I start mksh on a specific terminal?"
6752+Normally:
6753+.Dl mksh \-T/dev/tty2
6754+.Pp
6755+However, if you want for it to return (e.g. for an embedded
6756+system rescue shell), use this on your real console device instead:
6757+.Dl mksh \-T!/dev/ttyACM0
6758+.Pp
6759+.Nm
6760+can also daemonise (send to the background):
6761+.Dl mksh \-T\- \-c \*(aqexec cdio lock\*(aq
6762+.Ss "POSIX says..."
6763+Run the shell in POSIX mode (and possibly
6764+.Nm lksh
6765+instead of
6766+.Nm mksh ) :
6767+.Dl set \-o posix
6768+.Ss "My prompt from <some other shell> does not work!"
6769+Contact us on the mailing list or on IRC, we'll convert it for you.
6770+.Ss "Something is going wrong with my while...read loop"
6771+Most likely, you've encountered the problem in which the shell runs
6772+all parts of a pipeline as subshell.
6773+The inner loop will be executed in a subshell and variable changes
6774+cannot be propagated if run in a pipeline:
6775+.Bd -literal -offset indent
6776+bar \*(Ba baz \*(Ba while read foo; do ...; done
6777+.Ed
6778+.Pp
6779+Note that
6780+.Ic exit
6781+in the inner loop will only exit the subshell and not the original shell.
6782+Likewise, if the code is inside a function,
6783+.Ic return
6784+in the inner loop will only exit the subshell and won't terminate the function.
6785+.Pp
6786+Use co-processes instead:
6787+.Bd -literal -offset indent
6788+bar \*(Ba baz \*(Ba&
6789+while read \-p foo; do ...; done
6790+exec 3\*(Gt&p; exec 3\*(Gt&\-
6791+.Ed
6792+.Pp
6793+If
6794+.Ic read
6795+is run in a loop such as
6796+.Ic while read foo; do ...; done
6797+then leading whitespace will be removed (IFS) and backslashes processed.
6798+You might want to use
6799+.Ic while IFS= read \-r foo; do ...; done
6800+for pristine I/O.
6801+Similarly, when using the
6802+.Fl a
6803+option, use of the
6804+.Fl r
6805+option might be prudent
6806+.Pq Dq Li read \-raN\-1 arr \*(Ltfile ;
6807+the same applies for NUL-terminated lines:
6808+.Bd -literal -offset indent
6809+find . \-type f \-print0 \*(Ba& \e
6810+ while IFS= read \-d \*(aq\*(aq \-pr filename; do
6811+ print \-r \-\- "found \*(Lt${filename#./}\*(Gt"
6812+done
6813+.Ed
6814+.Pp
6815+.Ss "What differences in function-local scopes are there?"
6816+.Nm
6817+has a different scope model from
6818+.At
6819+.Nm ksh ,
6820+which leads to subtle differences in semantics for identical builtins.
6821+This can cause issues with a
6822+.Ic nameref
6823+to suddenly point to a local variable by accident.
6824+.Pp
6825+.Tn GNU
6826+.Nm bash
6827+allows unsetting local variables; in
6828+.Nm ,
6829+doing so in a function allows back access to the global variable
6830+(actually the one in the next scope up) with the same name.
6831+The following code, when run before the function definitions, changes
6832+the behaviour of
6833+.Ic unset
6834+to behave like other shells (the alias can be removed after the definitions):
6835+.Bd -literal -offset indent
6836+case ${KSH_VERSION:\-} in
6837+*MIRBSD\ KSH*\*(Ba*LEGACY\ KSH*)
6838+ function unset_compat {
6839+ \e\ebuiltin typeset unset_compat_x
6840+
6841+ for unset_compat_x in "$@"; do
6842+ eval "\e\e\e\ebuiltin unset $unset_compat_x[*]"
6843+ done
6844+ }
6845+ \e\ebuiltin alias unset=unset_compat
6846+ ;;
6847+esac
6848+.Ed
6849+.Pp
6850+When a local variable is created (e.g. using
6851+.Ic local ,
6852+.Ic typeset ,
6853+.Ic integer ,
6854+.Ic \e\ebuiltin typeset )
6855+it does not, like in other shells, inherit the value from the global
6856+(next scope up) variable with the same name; it is rather created
6857+without any value (unset but defined).
6858+.Ss "I get an error in this regex comparison"
6859+Use extglobs instead of regexes:
6860+.Dl "[[ foo =~ (foo\*(Babar).*baz ]] # becomes"
6861+.Dl "[[ foo = *@(foo\*(Babar)*baz* ]] # instead"
6862+.Ss "Are there any extensions to avoid?"
6863+.Tn GNU
6864+.Nm bash
6865+supports
6866+.Dq Li &\*(Gt
6867+.Pq and Dq Li \*(Ba&
6868+to redirect both stdout and stderr in one go, but this breaks POSIX
6869+and Korn Shell syntax; use POSIX redirections instead:
6870+.Dl "foo \*(Ba& bar \*(Ba& baz &\*(Gtlog # GNU bash"
6871+.Dl "foo 2\*(Gt&1 \*(Ba bar 2\*(Gt&1 \*(Ba baz \*(Gtlog 2\*(Gt&1 # POSIX"
6872+.Ss "\*(haL (Ctrl-L) does not clear the screen"
6873+Use \*(ha[\*(haL (Escape+Ctrl-L) or rebind it:
6874+.Dl bind \*(aq\*(haL=clear-screen\*(aq
6875+.Ss "\*(haU (Ctrl-U) clears the entire line"
6876+If it should only delete the line up to the cursor, use:
6877+.Dl bind \-m \*(haU=\*(aq\*(ha[0\*(haK\*(aq
6878+.Ss "Cursor Up behaves differently from zsh"
6879+Some shells make Cursor Up search in the history only for
6880+commands starting with what was already entered.
6881+.Nm
6882+separates the shortcuts: Cursor Up goes up one command
6883+and PgUp searches the history as described above.
--- /dev/null
+++ b/src/os2.c
@@ -0,0 +1,557 @@
1+/*-
2+ * Copyright (c) 2015
3+ * KO Myung-Hun <komh@chollian.net>
4+ *
5+ * Provided that these terms and disclaimer and all copyright notices
6+ * are retained or reproduced in an accompanying document, permission
7+ * is granted to deal in this work without restriction, including un-
8+ * limited rights to use, publicly perform, distribute, sell, modify,
9+ * merge, give away, or sublicence.
10+ *
11+ * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12+ * the utmost extent permitted by applicable law, neither express nor
13+ * implied; without malicious intent or gross negligence. In no event
14+ * may a licensor, author or contributor be held liable for indirect,
15+ * direct, other damage, loss, or other issues arising in any way out
16+ * of dealing in the work, even if advised of the possibility of such
17+ * damage or existence of a defect, except proven that it results out
18+ * of said person's immediate fault when using the work as intended.
19+ */
20+
21+#define INCL_DOS
22+#include <os2.h>
23+
24+#include "sh.h"
25+
26+#include <klibc/startup.h>
27+#include <io.h>
28+#include <unistd.h>
29+#include <process.h>
30+
31+__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.1 2017/04/02 15:00:44 tg Exp $");
32+
33+static char *remove_trailing_dots(char *);
34+static int access_stat_ex(int (*)(), const char *, void *);
35+static int test_exec_exist(const char *, char *);
36+static void response(int *, const char ***);
37+static char *make_response_file(char * const *);
38+static void env_slashify(void);
39+static void add_temp(const char *);
40+static void cleanup_temps(void);
41+static void cleanup(void);
42+
43+#define RPUT(x) do { \
44+ if (new_argc >= new_alloc) { \
45+ new_alloc += 20; \
46+ if (!(new_argv = realloc(new_argv, \
47+ new_alloc * sizeof(char *)))) \
48+ goto exit_out_of_memory; \
49+ } \
50+ new_argv[new_argc++] = (x); \
51+} while (/* CONSTCOND */ 0)
52+
53+#define KLIBC_ARG_RESPONSE_EXCLUDE \
54+ (__KLIBC_ARG_DQUOTE | __KLIBC_ARG_WILDCARD | __KLIBC_ARG_SHELL)
55+
56+static void
57+response(int *argcp, const char ***argvp)
58+{
59+ int i, old_argc, new_argc, new_alloc = 0;
60+ const char **old_argv, **new_argv;
61+ char *line, *l, *p;
62+ FILE *f;
63+
64+ old_argc = *argcp;
65+ old_argv = *argvp;
66+ for (i = 1; i < old_argc; ++i)
67+ if (old_argv[i] &&
68+ !(old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) &&
69+ old_argv[i][0] == '@')
70+ break;
71+
72+ if (i >= old_argc)
73+ /* do nothing */
74+ return;
75+
76+ new_argv = NULL;
77+ new_argc = 0;
78+ for (i = 0; i < old_argc; ++i) {
79+ if (i == 0 || !old_argv[i] ||
80+ (old_argv[i][-1] & KLIBC_ARG_RESPONSE_EXCLUDE) ||
81+ old_argv[i][0] != '@' ||
82+ !(f = fopen(old_argv[i] + 1, "rt")))
83+ RPUT(old_argv[i]);
84+ else {
85+ long filesize;
86+
87+ fseek(f, 0, SEEK_END);
88+ filesize = ftell(f);
89+ fseek(f, 0, SEEK_SET);
90+
91+ line = malloc(filesize + /* type */ 1 + /* NUL */ 1);
92+ if (!line) {
93+ exit_out_of_memory:
94+ fputs("Out of memory while reading response file\n", stderr);
95+ exit(255);
96+ }
97+
98+ line[0] = __KLIBC_ARG_NONZERO | __KLIBC_ARG_RESPONSE;
99+ l = line + 1;
100+ while (fgets(l, (filesize + 1) - (l - (line + 1)), f)) {
101+ p = strchr(l, '\n');
102+ if (p) {
103+ /*
104+ * if a line ends with a backslash,
105+ * concatenate with the next line
106+ */
107+ if (p > l && p[-1] == '\\') {
108+ char *p1;
109+ int count = 0;
110+
111+ for (p1 = p - 1; p1 >= l &&
112+ *p1 == '\\'; p1--)
113+ count++;
114+
115+ if (count & 1) {
116+ l = p + 1;
117+
118+ continue;
119+ }
120+ }
121+
122+ *p = 0;
123+ }
124+ p = strdup(line);
125+ if (!p)
126+ goto exit_out_of_memory;
127+
128+ RPUT(p + 1);
129+
130+ l = line + 1;
131+ }
132+
133+ free(line);
134+
135+ if (ferror(f)) {
136+ fputs("Cannot read response file\n", stderr);
137+ exit(255);
138+ }
139+
140+ fclose(f);
141+ }
142+ }
143+
144+ RPUT(NULL);
145+ --new_argc;
146+
147+ *argcp = new_argc;
148+ *argvp = new_argv;
149+}
150+
151+static void
152+init_extlibpath(void)
153+{
154+ const char *vars[] = {
155+ "BEGINLIBPATH",
156+ "ENDLIBPATH",
157+ "LIBPATHSTRICT",
158+ NULL
159+ };
160+ char val[512];
161+ int flag;
162+
163+ for (flag = 0; vars[flag]; flag++) {
164+ DosQueryExtLIBPATH(val, flag + 1);
165+ if (val[0])
166+ setenv(vars[flag], val, 1);
167+ }
168+}
169+
170+/*
171+ * Convert backslashes of environmental variables to forward slahes.
172+ * A backslash may be used as an escaped character when doing 'echo'.
173+ * This leads to an unexpected behavior.
174+ */
175+static void
176+env_slashify(void)
177+{
178+ /*
179+ * PATH and TMPDIR are used by OS/2 as well. That is, they may
180+ * have backslashes as a directory separator.
181+ * BEGINLIBPATH and ENDLIBPATH are special variables on OS/2.
182+ */
183+ const char *var_list[] = {
184+ "PATH",
185+ "TMPDIR",
186+ "BEGINLIBPATH",
187+ "ENDLIBPATH",
188+ NULL
189+ };
190+ const char **var;
191+ char *value;
192+
193+ for (var = var_list; *var; var++) {
194+ value = getenv(*var);
195+
196+ if (value)
197+ _fnslashify(value);
198+ }
199+}
200+
201+void
202+os2_init(int *argcp, const char ***argvp)
203+{
204+ response(argcp, argvp);
205+
206+ init_extlibpath();
207+ env_slashify();
208+
209+ if (!isatty(STDIN_FILENO))
210+ setmode(STDIN_FILENO, O_BINARY);
211+ if (!isatty(STDOUT_FILENO))
212+ setmode(STDOUT_FILENO, O_BINARY);
213+ if (!isatty(STDERR_FILENO))
214+ setmode(STDERR_FILENO, O_BINARY);
215+
216+ atexit(cleanup);
217+}
218+
219+void
220+setextlibpath(const char *name, const char *val)
221+{
222+ int flag;
223+ char *p, *cp;
224+
225+ if (!strcmp(name, "BEGINLIBPATH"))
226+ flag = BEGIN_LIBPATH;
227+ else if (!strcmp(name, "ENDLIBPATH"))
228+ flag = END_LIBPATH;
229+ else if (!strcmp(name, "LIBPATHSTRICT"))
230+ flag = LIBPATHSTRICT;
231+ else
232+ return;
233+
234+ /* convert slashes to backslashes */
235+ strdupx(cp, val, ATEMP);
236+ for (p = cp; *p; p++) {
237+ if (*p == '/')
238+ *p = '\\';
239+ }
240+
241+ DosSetExtLIBPATH(cp, flag);
242+
243+ afree(cp, ATEMP);
244+}
245+
246+/* remove trailing dots */
247+static char *
248+remove_trailing_dots(char *name)
249+{
250+ char *p;
251+
252+ for (p = name + strlen(name); --p > name && *p == '.'; )
253+ /* nothing */;
254+
255+ if (*p != '.' && *p != '/' && *p != '\\' && *p != ':')
256+ p[1] = '\0';
257+
258+ return (name);
259+}
260+
261+#define REMOVE_TRAILING_DOTS(name) \
262+ remove_trailing_dots(memcpy(alloca(strlen(name) + 1), name, strlen(name) + 1))
263+
264+/* alias of stat() */
265+extern int _std_stat(const char *, struct stat *);
266+
267+/* replacement for stat() of kLIBC which fails if there are trailing dots */
268+int
269+stat(const char *name, struct stat *buffer)
270+{
271+ return (_std_stat(REMOVE_TRAILING_DOTS(name), buffer));
272+}
273+
274+/* alias of access() */
275+extern int _std_access(const char *, int);
276+
277+/* replacement for access() of kLIBC which fails if there are trailing dots */
278+int
279+access(const char *name, int mode)
280+{
281+ /*
282+ * On OS/2 kLIBC, X_OK is set only for executable files.
283+ * This prevents scripts from being executed.
284+ */
285+ if (mode & X_OK)
286+ mode = (mode & ~X_OK) | R_OK;
287+
288+ return (_std_access(REMOVE_TRAILING_DOTS(name), mode));
289+}
290+
291+#define MAX_X_SUFFIX_LEN 4
292+
293+static const char *x_suffix_list[] =
294+ { "", ".ksh", ".exe", ".sh", ".cmd", ".com", ".bat", NULL };
295+
296+/* call fn() by appending executable extensions */
297+static int
298+access_stat_ex(int (*fn)(), const char *name, void *arg)
299+{
300+ char *x_name;
301+ const char **x_suffix;
302+ int rc = -1;
303+ size_t x_namelen = strlen(name) + MAX_X_SUFFIX_LEN + 1;
304+
305+ /* otherwise, try to append executable suffixes */
306+ x_name = alloc(x_namelen, ATEMP);
307+
308+ for (x_suffix = x_suffix_list; rc && *x_suffix; x_suffix++) {
309+ strlcpy(x_name, name, x_namelen);
310+ strlcat(x_name, *x_suffix, x_namelen);
311+
312+ rc = fn(x_name, arg);
313+ }
314+
315+ afree(x_name, ATEMP);
316+
317+ return (rc);
318+}
319+
320+/* access()/search_access() version */
321+int
322+access_ex(int (*fn)(const char *, int), const char *name, int mode)
323+{
324+ /*XXX this smells fishy --mirabilos */
325+ return (access_stat_ex(fn, name, (void *)mode));
326+}
327+
328+/* stat() version */
329+int
330+stat_ex(const char *name, struct stat *buffer)
331+{
332+ return (access_stat_ex(stat, name, buffer));
333+}
334+
335+static int
336+test_exec_exist(const char *name, char *real_name)
337+{
338+ struct stat sb;
339+
340+ if (stat(name, &sb) < 0 || !S_ISREG(sb.st_mode))
341+ return (-1);
342+
343+ /* safe due to calculations in real_exec_name() */
344+ memcpy(real_name, name, strlen(name) + 1);
345+
346+ return (0);
347+}
348+
349+const char *
350+real_exec_name(const char *name)
351+{
352+ char x_name[strlen(name) + MAX_X_SUFFIX_LEN + 1];
353+ const char *real_name = name;
354+
355+ if (access_stat_ex(test_exec_exist, real_name, x_name) != -1)
356+ /*XXX memory leak */
357+ strdupx(real_name, x_name, ATEMP);
358+
359+ return (real_name);
360+}
361+
362+/* OS/2 can process a command line up to 32 KiB */
363+#define MAX_CMD_LINE_LEN 32768
364+
365+/* make a response file to pass a very long command line */
366+static char *
367+make_response_file(char * const *argv)
368+{
369+ char rsp_name_arg[] = "@mksh-rsp-XXXXXX";
370+ char *rsp_name = &rsp_name_arg[1];
371+ int arg_len = 0;
372+ int i;
373+
374+ for (i = 0; argv[i]; i++)
375+ arg_len += strlen(argv[i]) + 1;
376+
377+ /*
378+ * If a length of command line is longer than MAX_CMD_LINE_LEN, then
379+ * use a response file. OS/2 cannot process a command line longer
380+ * than 32K. Of course, a response file cannot be recognised by a
381+ * normal OS/2 program, that is, neither non-EMX or non-kLIBC. But
382+ * it cannot accept a command line longer than 32K in itself. So
383+ * using a response file in this case, is an acceptable solution.
384+ */
385+ if (arg_len > MAX_CMD_LINE_LEN) {
386+ int fd;
387+ char *result;
388+
389+ if ((fd = mkstemp(rsp_name)) == -1)
390+ return (NULL);
391+
392+ /* write all the arguments except a 0th program name */
393+ for (i = 1; argv[i]; i++) {
394+ write(fd, argv[i], strlen(argv[i]));
395+ write(fd, "\n", 1);
396+ }
397+
398+ close(fd);
399+ add_temp(rsp_name);
400+ strdupx(result, rsp_name_arg, ATEMP);
401+ return (result);
402+ }
403+
404+ return (NULL);
405+}
406+
407+/* alias of execve() */
408+extern int _std_execve(const char *, char * const *, char * const *);
409+
410+/* replacement for execve() of kLIBC */
411+int
412+execve(const char *name, char * const *argv, char * const *envp)
413+{
414+ const char *exec_name;
415+ FILE *fp;
416+ char sign[2];
417+ char *rsp_argv[3];
418+ char *rsp_name_arg;
419+ int pid;
420+ int status;
421+ int fd;
422+ int rc;
423+
424+ /*
425+ * #! /bin/sh : append .exe
426+ * extproc sh : search sh.exe in PATH
427+ */
428+ exec_name = search_path(name, path, X_OK, NULL);
429+ if (!exec_name) {
430+ errno = ENOENT;
431+ return (-1);
432+ }
433+
434+ /*-
435+ * kLIBC execve() has problems when executing scripts.
436+ * 1. it fails to execute a script if a directory whose name
437+ * is same as an interpreter exists in a current directory.
438+ * 2. it fails to execute a script not starting with sharpbang.
439+ * 3. it fails to execute a batch file if COMSPEC is set to a shell
440+ * incompatible with cmd.exe, such as /bin/sh.
441+ * And ksh process scripts more well, so let ksh process scripts.
442+ */
443+ errno = 0;
444+ if (!(fp = fopen(exec_name, "rb")))
445+ errno = ENOEXEC;
446+
447+ if (!errno && fread(sign, 1, sizeof(sign), fp) != sizeof(sign))
448+ errno = ENOEXEC;
449+
450+ if (fp && fclose(fp))
451+ errno = ENOEXEC;
452+
453+ if (!errno &&
454+ !((sign[0] == 'M' && sign[1] == 'Z') ||
455+ (sign[0] == 'N' && sign[1] == 'E') ||
456+ (sign[0] == 'L' && sign[1] == 'X')))
457+ errno = ENOEXEC;
458+
459+ if (errno == ENOEXEC)
460+ return (-1);
461+
462+ rsp_name_arg = make_response_file(argv);
463+
464+ if (rsp_name_arg) {
465+ rsp_argv[0] = argv[0];
466+ rsp_argv[1] = rsp_name_arg;
467+ rsp_argv[2] = NULL;
468+
469+ argv = rsp_argv;
470+ }
471+
472+ pid = spawnve(P_NOWAIT, exec_name, argv, envp);
473+
474+ afree(rsp_name_arg, ATEMP);
475+
476+ if (pid == -1) {
477+ cleanup_temps();
478+
479+ return (-1);
480+ }
481+
482+ /* close all opened handles */
483+ for (fd = 0; fd < NUFILE; fd++) {
484+ if (fcntl(fd, F_GETFD) == -1)
485+ continue;
486+
487+ close(fd);
488+ }
489+
490+ while ((rc = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
491+ /* nothing */;
492+
493+ cleanup_temps();
494+
495+ /* Is this possible? And is this right? */
496+ if (rc == -1)
497+ return (-1);
498+
499+ if (WIFSIGNALED(status))
500+ _exit(ksh_sigmask(WTERMSIG(status)));
501+
502+ _exit(WEXITSTATUS(status));
503+}
504+
505+static struct temp *templist = NULL;
506+
507+static void
508+add_temp(const char *name)
509+{
510+ struct temp *tp;
511+
512+ tp = alloc(offsetof(struct temp, tffn[0]) + strlen(name) + 1, APERM);
513+ memcpy(tp->tffn, name, strlen(name) + 1);
514+ tp->next = templist;
515+ templist = tp;
516+}
517+
518+/* alias of unlink() */
519+extern int _std_unlink(const char *);
520+
521+/*
522+ * Replacement for unlink() of kLIBC not supporting to remove files used by
523+ * another processes.
524+ */
525+int
526+unlink(const char *name)
527+{
528+ int rc;
529+
530+ rc = _std_unlink(name);
531+ if (rc == -1 && errno != ENOENT)
532+ add_temp(name);
533+
534+ return (rc);
535+}
536+
537+static void
538+cleanup_temps(void)
539+{
540+ struct temp *tp;
541+ struct temp **tpnext;
542+
543+ for (tpnext = &templist, tp = templist; tp; tp = *tpnext) {
544+ if (_std_unlink(tp->tffn) == 0 || errno == ENOENT) {
545+ *tpnext = tp->next;
546+ afree(tp, APERM);
547+ } else {
548+ tpnext = &tp->next;
549+ }
550+ }
551+}
552+
553+static void
554+cleanup(void)
555+{
556+ cleanup_temps();
557+}
--- a/src/sh.h
+++ b/src/sh.h
@@ -10,7 +10,7 @@
1010
1111 /*-
1212 * Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
13- * 2011, 2012, 2013, 2014, 2015, 2016
13+ * 2011, 2012, 2013, 2014, 2015, 2016, 2017
1414 * mirabilos <m@mirbsd.org>
1515 *
1616 * Provided that these terms and disclaimer and all copyright notices
@@ -175,9 +175,9 @@
175175 #endif
176176
177177 #ifdef EXTERN
178-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.791 2016/11/11 23:31:38 tg Exp $");
178+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.808 2017/04/12 17:38:46 tg Exp $");
179179 #endif
180-#define MKSH_VERSION "R54 2016/11/11"
180+#define MKSH_VERSION "R55 2017/04/12"
181181
182182 /* arithmetic types: C implementation */
183183 #if !HAVE_CAN_INTTYPES
@@ -392,13 +392,20 @@ struct rusage {
392392 #endif
393393
394394 #ifdef __OS2__
395+#define MKSH_UNIXROOT "/@unixroot"
396+#else
397+#define MKSH_UNIXROOT ""
398+#endif
399+
400+#ifdef MKSH_DOSPATH
401+#ifndef __GNUC__
402+# error GCC extensions needed later on
403+#endif
395404 #define MKSH_PATHSEPS ";"
396405 #define MKSH_PATHSEPC ';'
397-#define MKSH_UNIXROOT "/@unixroot"
398406 #else
399407 #define MKSH_PATHSEPS ":"
400408 #define MKSH_PATHSEPC ':'
401-#define MKSH_UNIXROOT ""
402409 #endif
403410
404411 #if !HAVE_FLOCK_DECL
@@ -505,12 +512,20 @@ extern int __cdecl setegid(gid_t);
505512 EXTERN const char *safe_prompt; /* safe prompt if PS1 substitution fails */
506513
507514 #ifdef MKSH_LEGACY_MODE
508-#define KSH_VERSIONNAME "LEGACY"
515+#define KSH_VERSIONNAME_ISLEGACY "LEGACY"
516+#else
517+#define KSH_VERSIONNAME_ISLEGACY "MIRBSD"
518+#endif
519+#ifdef MKSH_WITH_TEXTMODE
520+#define KSH_VERSIONNAME_TEXTMODE " +TEXTMODE"
509521 #else
510-#define KSH_VERSIONNAME "MIRBSD"
522+#define KSH_VERSIONNAME_TEXTMODE ""
523+#endif
524+#ifndef KSH_VERSIONNAME_VENDOR_EXT
525+#define KSH_VERSIONNAME_VENDOR_EXT ""
511526 #endif
512-EXTERN const char initvsn[] E_INIT("KSH_VERSION=@(#)" KSH_VERSIONNAME \
513- " KSH " MKSH_VERSION);
527+EXTERN const char initvsn[] E_INIT("KSH_VERSION=@(#)" KSH_VERSIONNAME_ISLEGACY \
528+ " KSH " MKSH_VERSION KSH_VERSIONNAME_TEXTMODE KSH_VERSIONNAME_VENDOR_EXT);
514529 #define KSH_VERSION (initvsn + /* "KSH_VERSION=@(#)" */ 16)
515530
516531 EXTERN const char digits_uc[] E_INIT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
@@ -578,7 +593,7 @@ char *ucstrstr(char *, const char *);
578593 #define mkssert(e) do { } while (/* CONSTCOND */ 0)
579594 #endif
580595
581-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 541)
596+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 551)
582597 #error Must run Build.sh to compile this.
583598 extern void thiswillneverbedefinedIhope(void);
584599 int
@@ -630,14 +645,6 @@ im_sorry_dave(void)
630645 } while (/* CONSTCOND */ 0)
631646 #endif
632647
633-#ifdef MKSH_LEGACY_MODE
634-#ifndef MKSH_NO_CMDLINE_EDITING
635-#define MKSH_NO_CMDLINE_EDITING /* defined */
636-#endif
637-#undef MKSH_S_NOVI
638-#define MKSH_S_NOVI 1
639-#endif
640-
641648 #ifdef MKSH_SMALL
642649 #ifndef MKSH_NOPWNAM
643650 #define MKSH_NOPWNAM /* defined */
@@ -772,6 +779,7 @@ extern struct env {
772779 #define E_LOOP 5 /* executing for/while # */
773780 #define E_ERRH 6 /* general error handler # */
774781 #define E_GONE 7 /* hidden in child */
782+#define E_EVAL 8 /* running eval # */
775783 /* # indicates env has valid jbuf (see unwind()) */
776784
777785 /* struct env.flag values */
@@ -855,8 +863,8 @@ EXTERN char null[] E_INIT("");
855863
856864 #ifndef HAVE_STRING_POOLING /* helpers for pooled strings */
857865 EXTERN const char T4spaces[] E_INIT(" ");
858-#define T1space (T4spaces + 3)
859-EXTERN const char Tcolsp[] E_INIT(": ");
866+#define T1space (Treal_sp2 + 5)
867+#define Tcolsp (Tf_sD_ + 2)
860868 EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
861869 #define TC_IFSWS (TC_LEX1 + 7)
862870 EXTERN const char TFCEDIT_dollaru[] E_INIT("${FCEDIT:-/bin/ed} $_");
@@ -865,15 +873,19 @@ EXTERN const char Tsgdot[] E_INIT("*=.");
865873 EXTERN const char Taugo[] E_INIT("augo");
866874 EXTERN const char Tbracket[] E_INIT("[");
867875 #define Tdot (Tsgdot + 2)
868-EXTERN const char Talias[] E_INIT("alias");
869-EXTERN const char Tbadsubst[] E_INIT("bad substitution");
876+#define Talias (Tunalias + 2)
877+EXTERN const char Tbadnum[] E_INIT("bad number");
878+#define Tbadsubst (Tfg_badsubst + 10)
870879 EXTERN const char Tbg[] E_INIT("bg");
871880 EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize");
872881 #define Tbsize (Tbad_bsize + 12)
873882 EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'");
874883 #define Tbad_sig_s (Tbad_sig_ss + 4)
875-EXTERN const char Tgbuiltin[] E_INIT("=builtin");
876-#define Tbuiltin (Tgbuiltin + 1)
884+EXTERN const char Tsgbreak[] E_INIT("*=break");
885+#define Tbreak (Tsgbreak + 2)
886+EXTERN const char T__builtin[] E_INIT("-\\builtin");
887+#define T_builtin (T__builtin + 1)
888+#define Tbuiltin (T__builtin + 2)
877889 EXTERN const char Toomem[] E_INIT("can't allocate %zu data bytes");
878890 EXTERN const char Tcant_cd[] E_INIT("restricted shell - can't cd");
879891 EXTERN const char Tcant_find[] E_INIT("can't find");
@@ -882,31 +894,35 @@ EXTERN const char Tcant_open[] E_INIT("can't open");
882894 EXTERN const char Tbcat[] E_INIT("!cat");
883895 #define Tcat (Tbcat + 1)
884896 #define Tcd (Tcant_cd + 25)
885-EXTERN const char Tcommand[] E_INIT("command");
897+#define T_command (T_funny_command + 9)
898+#define Tcommand (T_funny_command + 10)
899+EXTERN const char Tsgcontinue[] E_INIT("*=continue");
900+#define Tcontinue (Tsgcontinue + 2)
886901 EXTERN const char Tcreate[] E_INIT("create");
887902 EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected");
888903 EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL");
889-EXTERN const char Tsgexport[] E_INIT("*=export");
890-#define Texport (Tsgexport + 2)
904+EXTERN const char Tdsgexport[] E_INIT("^*=export");
905+#define Texport (Tdsgexport + 3)
891906 #ifdef __OS2__
892907 EXTERN const char Textproc[] E_INIT("extproc");
893908 #endif
894909 EXTERN const char Tfalse[] E_INIT("false");
895910 EXTERN const char Tfg[] E_INIT("fg");
896911 EXTERN const char Tfg_badsubst[] E_INIT("fileglob: bad substitution");
897-EXTERN const char Tfile[] E_INIT("file");
912+#define Tfile (Tfile_fd + 20)
898913 EXTERN const char Tfile_fd[] E_INIT("function definition file");
899914 EXTERN const char TFPATH[] E_INIT("FPATH");
900915 EXTERN const char T_function[] E_INIT(" function");
901916 #define Tfunction (T_function + 1)
902-EXTERN const char T_funny_command[] E_INIT("funny $() command");
917+EXTERN const char T_funny_command[] E_INIT("funny $()-command");
903918 EXTERN const char Tgetopts[] E_INIT("getopts");
904-EXTERN const char Thistory[] E_INIT("history");
919+#define Thistory (Tnot_in_history + 7)
905920 EXTERN const char Tintovfl[] E_INIT("integer overflow %zu %c %zu prevented");
921+EXTERN const char Tinvname[] E_INIT("%s: invalid %s name");
906922 EXTERN const char Tjobs[] E_INIT("jobs");
907923 EXTERN const char Tjob_not_started[] E_INIT("job not started");
908924 EXTERN const char Tmksh[] E_INIT("mksh");
909-EXTERN const char Tname[] E_INIT("name");
925+#define Tname (Tinvname + 15)
910926 EXTERN const char Tno_args[] E_INIT("missing argument");
911927 EXTERN const char Tno_OLDPWD[] E_INIT("no OLDPWD");
912928 EXTERN const char Tnot_ident[] E_INIT("is not an identifier");
@@ -917,77 +933,84 @@ EXTERN const char Tnot_found_s[] E_INIT("%s not found");
917933 #define TOLDPWD (Tno_OLDPWD + 3)
918934 #define Topen (Tcant_open + 6)
919935 #define TPATH (TFPATH + 1)
920-EXTERN const char Tpv[] E_INIT("pv");
936+#define Tpv (TpVv + 1)
921937 EXTERN const char TpVv[] E_INIT("Vpv");
922938 #define TPWD (Tno_OLDPWD + 6)
923-EXTERN const char Tread[] E_INIT("read");
924-EXTERN const char Tsgreadonly[] E_INIT("*=readonly");
925-#define Treadonly (Tsgreadonly + 2)
939+#define Tread (Tshf_read + 4)
940+EXTERN const char Tdsgreadonly[] E_INIT("^*=readonly");
941+#define Treadonly (Tdsgreadonly + 3)
926942 EXTERN const char Tredirection_dup[] E_INIT("can't finish (dup) redirection");
927943 #define Tredirection (Tredirection_dup + 19)
928-EXTERN const char Treal_sp1[] E_INIT("real ");
944+#define Treal_sp1 (Treal_sp2 + 1)
929945 EXTERN const char Treal_sp2[] E_INIT(" real ");
930946 EXTERN const char Treq_arg[] E_INIT("requires an argument");
931947 EXTERN const char Tselect[] E_INIT("select");
932948 EXTERN const char Tsgset[] E_INIT("*=set");
933-#define Tset (Tsgset + 2)
949+#define Tset (Tf_parm + 18)
934950 #define Tsh (Tmksh + 2)
935951 #define TSHELL (TEXECSHELL + 4)
952+#define Tshell (Ttoo_many_files + 23)
936953 EXTERN const char Tshf_read[] E_INIT("shf_read");
937954 EXTERN const char Tshf_write[] E_INIT("shf_write");
955+EXTERN const char Tgsource[] E_INIT("=source");
956+#define Tsource (Tgsource + 1)
938957 EXTERN const char Tj_suspend[] E_INIT("j_suspend");
939958 #define Tsuspend (Tj_suspend + 2)
940959 EXTERN const char Tsynerr[] E_INIT("syntax error");
941960 EXTERN const char Ttime[] E_INIT("time");
942961 EXTERN const char Ttoo_many_args[] E_INIT("too many arguments");
962+EXTERN const char Ttoo_many_files[] E_INIT("too many open files in shell");
943963 EXTERN const char Ttrue[] E_INIT("true");
944964 EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd");
945965 #define Ttty_fd (Ttty_fd_dupof + 7)
946-EXTERN const char Tgtypeset[] E_INIT("=typeset");
947-#define Ttypeset (Tgtypeset + 1)
966+EXTERN const char Tdgtypeset[] E_INIT("^=typeset");
967+#define Ttypeset (Tdgtypeset + 2)
948968 #define Tugo (Taugo + 1)
949969 EXTERN const char Tunalias[] E_INIT("unalias");
950970 #define Tunexpected (TELIF_unexpected + 6)
971+EXTERN const char Tunexpected_type[] E_INIT("%s: unexpected %s type %d");
951972 EXTERN const char Tunknown_option[] E_INIT("unknown option");
952-EXTERN const char Tuser_sp1[] E_INIT("user ");
973+EXTERN const char Tunwind[] E_INIT("unwind");
974+#define Tuser_sp1 (Tuser_sp2 + 1)
953975 EXTERN const char Tuser_sp2[] E_INIT(" user ");
954976 #define Twrite (Tshf_write + 4)
955977 EXTERN const char Tf__S[] E_INIT(" %S");
956-EXTERN const char Tf__d[] E_INIT(" %d");
978+#define Tf__d (Tunexpected_type + 22)
957979 EXTERN const char Tf__ss[] E_INIT(" %s%s");
958-EXTERN const char Tf__sN[] E_INIT(" %s\n");
980+#define Tf__sN (Tf_s_s_sN + 5)
959981 EXTERN const char Tf_sSs[] E_INIT("%s/%s");
960-EXTERN const char Tf_T[] E_INIT("%T");
982+#define Tf_T (Tf_s_T + 3)
961983 EXTERN const char Tf_dN[] E_INIT("%d\n");
962984 EXTERN const char Tf_s_[] E_INIT("%s ");
963985 EXTERN const char Tf_s_T[] E_INIT("%s %T");
964986 EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n");
965-EXTERN const char Tf_s_s[] E_INIT("%s %s");
966-EXTERN const char Tf_s_sD_s[] E_INIT("%s %s: %s");
987+#define Tf_s_s (Tf_sD_s_s + 4)
988+#define Tf_s_sD_s (Tf_cant_ss_s + 6)
967989 EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
968990 EXTERN const char Tf_sD_[] E_INIT("%s: ");
969991 EXTERN const char Tf_szs[] E_INIT("%s: %zd %s");
970992 EXTERN const char Tf_parm[] E_INIT("%s: parameter not set");
971993 EXTERN const char Tf_coproc[] E_INIT("-p: %s");
972-EXTERN const char Tf_cant[] E_INIT("can't %s %s: %s");
973-EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed\n");
994+EXTERN const char Tf_cant_s[] E_INIT("%s: can't %s");
995+EXTERN const char Tf_cant_ss_s[] E_INIT("can't %s %s: %s");
996+EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed");
974997 #if HAVE_MKNOD
975998 EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'");
976999 #endif
9771000 EXTERN const char Tf_S_[] E_INIT("%S ");
9781001 #define Tf_S (Tf__S + 1)
979-EXTERN const char Tf_lu[] E_INIT("%lu");
1002+#define Tf_lu (Tf_toolarge + 17)
9801003 EXTERN const char Tf_toolarge[] E_INIT("%s %s too large: %lu");
9811004 EXTERN const char Tf_ldfailed[] E_INIT("%s %s(%d, %ld) failed: %s");
982-#define Tf_ss (Tf__ss + 1)
1005+#define Tf_ss (Tf_sss + 2)
9831006 EXTERN const char Tf_sss[] E_INIT("%s%s%s");
9841007 EXTERN const char Tf_sD_s_sD_s[] E_INIT("%s: %s %s: %s");
985-EXTERN const char Tf_toomany[] E_INIT("too many %ss\n");
1008+EXTERN const char Tf_toomany[] E_INIT("too many %ss");
9861009 EXTERN const char Tf_sd[] E_INIT("%s %d");
987-#define Tf_s (Tf__ss + 3)
1010+#defi