summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2015-04-22 19:51:32 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-04-22 19:51:33 +0000
commitc87de5d0279a299eec916effc751961347ff5eeb (patch)
tree7cf80a0457be3e2dd1d98f8fddfa80e3b63f1174
parentd978a9edb72c818ae3aa2527496ce987f9ef555d (diff)
parentb27ce95e41e941ad22b3dc392d8328251d3a057e (diff)
downloadmksh-android-6.0.1_r53.tar.gz
Merge "Upgrade to mksh 50f."android-m-preview-1android-m-previewandroid-cts-6.0_r9android-cts-6.0_r8android-cts-6.0_r7android-cts-6.0_r6android-cts-6.0_r5android-cts-6.0_r4android-cts-6.0_r32android-cts-6.0_r31android-cts-6.0_r30android-cts-6.0_r3android-cts-6.0_r29android-cts-6.0_r28android-cts-6.0_r27android-cts-6.0_r26android-cts-6.0_r25android-cts-6.0_r24android-cts-6.0_r23android-cts-6.0_r22android-cts-6.0_r21android-cts-6.0_r20android-cts-6.0_r2android-cts-6.0_r19android-cts-6.0_r18android-cts-6.0_r17android-cts-6.0_r16android-cts-6.0_r15android-cts-6.0_r14android-cts-6.0_r13android-cts-6.0_r12android-cts-6.0_r1android-6.0.1_r9android-6.0.1_r81android-6.0.1_r80android-6.0.1_r8android-6.0.1_r79android-6.0.1_r78android-6.0.1_r77android-6.0.1_r74android-6.0.1_r73android-6.0.1_r72android-6.0.1_r70android-6.0.1_r7android-6.0.1_r69android-6.0.1_r68android-6.0.1_r67android-6.0.1_r66android-6.0.1_r65android-6.0.1_r63android-6.0.1_r62android-6.0.1_r61android-6.0.1_r60android-6.0.1_r59android-6.0.1_r58android-6.0.1_r57android-6.0.1_r56android-6.0.1_r55android-6.0.1_r54android-6.0.1_r53android-6.0.1_r52android-6.0.1_r51android-6.0.1_r50android-6.0.1_r5android-6.0.1_r49android-6.0.1_r48android-6.0.1_r47android-6.0.1_r46android-6.0.1_r45android-6.0.1_r43android-6.0.1_r42android-6.0.1_r41android-6.0.1_r40android-6.0.1_r4android-6.0.1_r33android-6.0.1_r32android-6.0.1_r31android-6.0.1_r30android-6.0.1_r3android-6.0.1_r28android-6.0.1_r27android-6.0.1_r26android-6.0.1_r25android-6.0.1_r24android-6.0.1_r22android-6.0.1_r21android-6.0.1_r20android-6.0.1_r18android-6.0.1_r17android-6.0.1_r16android-6.0.1_r13android-6.0.1_r12android-6.0.1_r11android-6.0.1_r10android-6.0.1_r1android-6.0.0_r7android-6.0.0_r6android-6.0.0_r5android-6.0.0_r41android-6.0.0_r4android-6.0.0_r3android-6.0.0_r26android-6.0.0_r25android-6.0.0_r24android-6.0.0_r23android-6.0.0_r2android-6.0.0_r13android-6.0.0_r12android-6.0.0_r11android-6.0.0_r1master-soongmarshmallow-releasemarshmallow-mr3-releasemarshmallow-mr2-releasemarshmallow-mr1-releasemarshmallow-mr1-devmarshmallow-dr1.6-releasemarshmallow-dr1.5-releasemarshmallow-dr1.5-devmarshmallow-dr-releasemarshmallow-dr-dragon-releasemarshmallow-dr-devmarshmallow-devmarshmallow-cts-release
-rw-r--r--Android.mk2
-rw-r--r--Makefrag.inc4
-rw-r--r--src/Build.sh20
-rw-r--r--src/check.pl6
-rw-r--r--src/check.t240
-rw-r--r--src/dot.mkshrc41
-rw-r--r--src/edit.c6
-rw-r--r--src/eval.c4
-rw-r--r--src/exec.c33
-rw-r--r--src/funcs.c38
-rw-r--r--src/histrap.c16
-rw-r--r--src/jobs.c36
-rw-r--r--src/lex.c68
-rw-r--r--src/lksh.125
-rw-r--r--src/main.c22
-rw-r--r--src/misc.c43
-rw-r--r--src/mksh.166
-rw-r--r--src/sh.h29
-rw-r--r--src/syn.c26
-rw-r--r--src/tree.c30
-rw-r--r--src/var.c91
21 files changed, 560 insertions, 286 deletions
diff --git a/Android.mk b/Android.mk
index e208225..a78409f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,6 +79,6 @@ LOCAL_CFLAGS += \
-DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 \
-DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 \
-DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 \
- -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=505
+ -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=506
include $(BUILD_EXECUTABLE)
diff --git a/Makefrag.inc b/Makefrag.inc
index c5d5f6d..9c3632b 100644
--- a/Makefrag.inc
+++ b/Makefrag.inc
@@ -1,4 +1,4 @@
-# Makefile fragment for building mksh R50 2015/03/01
+# Makefile fragment for building mksh R50 2015/04/19
PROG= mksh
MAN= mksh.1
@@ -10,7 +10,7 @@ NONSRCS_INST= dot.mkshrc $(MAN)
NONSRCS_NOINST= Build.sh Makefile Rebuild.sh check.pl check.t test.sh
CC= /huge-ssd/aosp-arm64/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin/*-gcc
CFLAGS= -fno-exceptions -Wno-multichar -fpic -fPIE -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -Os -fomit-frame-pointer -fno-strict-aliasing -Wno-deprecated-declarations -fno-asynchronous-unwind-tables -fstack-protector-strong -fwrapv
-CPPFLAGS= -I. -I'../src' -isystem /huge-ssd/aosp-arm64/bionic/libc/arch-arm64/include -isystem /huge-ssd/aosp-arm64/bionic/libc/include -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi/asm-arm64 -isystem /huge-ssd/aosp-arm64/bionic/libm/include -isystem /huge-ssd/aosp-arm64/bionic/libm/include/arm64 -D_FORTIFY_SOURCE=2 -include /huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/AndroidConfig.h -I/huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/ -DANDROID -DNDEBUG -UDEBUG -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_ISSETUGID=0 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=505
+CPPFLAGS= -I. -I'../src' -isystem /huge-ssd/aosp-arm64/bionic/libc/arch-arm64/include -isystem /huge-ssd/aosp-arm64/bionic/libc/include -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi -isystem /huge-ssd/aosp-arm64/bionic/libc/kernel/uapi/asm-arm64 -isystem /huge-ssd/aosp-arm64/bionic/libm/include -isystem /huge-ssd/aosp-arm64/bionic/libm/include/arm64 -D_FORTIFY_SOURCE=2 -include /huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/AndroidConfig.h -I/huge-ssd/aosp-arm64/build/core/combo/include/arch/linux-arm64/ -DANDROID -DNDEBUG -UDEBUG -DDEBUG_LEAKS -DMKSH_ASSUME_UTF8 -DMKSH_CONSERVATIVE_FDS -DMKSH_DONT_EMIT_IDSTRING -DMKSH_NOPWNAM -DMKSH_BUILDSH -D_GNU_SOURCE -DSETUID_CAN_FAIL_WITH_EAGAIN -DHAVE_ATTRIBUTE_BOUNDED=0 -DHAVE_ATTRIBUTE_FORMAT=1 -DHAVE_ATTRIBUTE_NORETURN=1 -DHAVE_ATTRIBUTE_PURE=1 -DHAVE_ATTRIBUTE_UNUSED=1 -DHAVE_ATTRIBUTE_USED=1 -DHAVE_SYS_TIME_H=1 -DHAVE_TIME_H=1 -DHAVE_BOTH_TIME_H=1 -DHAVE_SYS_BSDTYPES_H=0 -DHAVE_SYS_FILE_H=1 -DHAVE_SYS_MKDEV_H=0 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_BSTRING_H=0 -DHAVE_GRP_H=1 -DHAVE_LIBGEN_H=1 -DHAVE_LIBUTIL_H=0 -DHAVE_PATHS_H=1 -DHAVE_STDINT_H=1 -DHAVE_STRINGS_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_ULIMIT_H=0 -DHAVE_VALUES_H=0 -DHAVE_CAN_INTTYPES=1 -DHAVE_CAN_UCBINTS=1 -DHAVE_CAN_INT8TYPE=1 -DHAVE_CAN_UCBINT8=1 -DHAVE_RLIM_T=1 -DHAVE_SIG_T=1 -DHAVE_SYS_ERRLIST=0 -DHAVE_SYS_SIGNAME=1 -DHAVE_SYS_SIGLIST=1 -DHAVE_FLOCK=1 -DHAVE_LOCK_FCNTL=1 -DHAVE_GETRUSAGE=1 -DHAVE_GETSID=1 -DHAVE_GETTIMEOFDAY=1 -DHAVE_ISSETUGID=0 -DHAVE_KILLPG=1 -DHAVE_MEMMOVE=1 -DHAVE_MKNOD=0 -DHAVE_MMAP=1 -DHAVE_NICE=1 -DHAVE_REVOKE=0 -DHAVE_SETLOCALE_CTYPE=0 -DHAVE_LANGINFO_CODESET=0 -DHAVE_SELECT=1 -DHAVE_SETRESUGID=1 -DHAVE_SETGROUPS=1 -DHAVE_STRERROR=1 -DHAVE_STRSIGNAL=0 -DHAVE_STRLCPY=1 -DHAVE_FLOCK_DECL=1 -DHAVE_REVOKE_DECL=1 -DHAVE_SYS_ERRLIST_DECL=0 -DHAVE_SYS_SIGLIST_DECL=1 -DHAVE_PERSISTENT_HISTORY=0 -DMKSH_BUILD_R=506
LDFLAGS= -nostdlib -Bdynamic -fPIE -pie -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--no-undefined /huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib/crtbegin_dynamic.o
LIBS= -L/huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib -Wl,-rpath-link=/huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib -Wl,--no-whole-archive /huge-ssd/aosp-arm64/out/target/product/flounder/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a -lc /huge-ssd/aosp-arm64/out/target/product/flounder/obj/lib/crtend_android.o
diff --git a/src/Build.sh b/src/Build.sh
index 5c90eb8..70c1d24 100644
--- a/src/Build.sh
+++ b/src/Build.sh
@@ -1,9 +1,9 @@
#!/bin/sh
-srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669.2.2 2015/03/01 15:42:50 tg Exp $'
+srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.669.2.4 2015/04/19 19:18:08 tg Exp $'
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-# 2011, 2012, 2013, 2014
-# Thorsten Glaser <tg@mirbsd.org>
+# 2011, 2012, 2013, 2014, 2015
+# Thorsten “mirabilos” Glaser <tg@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
@@ -1692,6 +1692,7 @@ if test 0 = $HAVE_CAN_LFS_SUS; then
ac_testn can_lfs_aix '!' can_lfs 0 "... with -D_LARGE_FILES=1" <lft.c
test 1 = $HAVE_CAN_LFS_AIX || CPPFLAGS=$save_CPPFLAGS
fi
+rm -f lft.c
rmf lft* # end of large file support test
#
@@ -1780,12 +1781,12 @@ else
HAVE_LINK_WORKS=x
ac_testinit link_works '' 'checking if the final link command may succeed'
fv=1
- cat >conftest.c <<-'EOF'
+ cat >conftest.c <<-EOF
#define EXTERN
#define MKSH_INCLUDES_ONLY
#include "sh.h"
- __RCSID("$MirOS: src/bin/mksh/Build.sh,v 1.669.2.2 2015/03/01 15:42:50 tg Exp $");
- int main(void) { printf("Hello, World!\n"); return (isatty(0)); }
+ __RCSID("$srcversion");
+ int main(void) { printf("Hello, World!\\n"); return (isatty(0)); }
EOF
case $cm in
llvm)
@@ -2150,9 +2151,9 @@ cta(uari_has_32_bit, 0 < (mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4
cta(uari_wrap_32_bit,
(mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 3) >
(mksh_uari_t)(((((mksh_uari_t)1 << 15) << 15) - 1) * 4 + 4));
-#define NUM 21
+#define NUM 22
#else
-#define NUM 15
+#define NUM 16
#endif
/* these are always required */
cta(ari_is_signed, (mksh_ari_t)-1 < (mksh_ari_t)0);
@@ -2165,6 +2166,7 @@ cta(sizet_voidptr_same_size, sizeof(size_t) == sizeof(void *));
cta(sizet_funcptr_same_size, sizeof(size_t) == sizeof(void (*)(void)));
/* our formatting routines assume this */
cta(ptr_fits_in_long, sizeof(size_t) <= sizeof(long));
+cta(ari_fits_in_long, sizeof(mksh_ari_t) <= sizeof(long));
/* for struct alignment people */
char padding[64 - NUM];
};
@@ -2325,7 +2327,7 @@ addsrcs '!' HAVE_STRLCPY strlcpy.c
addsrcs USE_PRINTF_BUILTIN printf.c
test 1 = "$USE_PRINTF_BUILTIN" && add_cppflags -DMKSH_PRINTF_BUILTIN
test 1 = "$HAVE_CAN_VERB" && CFLAGS="$CFLAGS -verbose"
-add_cppflags -DMKSH_BUILD_R=505
+add_cppflags -DMKSH_BUILD_R=506
$e $bi$me: Finished configuration testing, now producing output.$ao
diff --git a/src/check.pl b/src/check.pl
index d688509..ce45773 100644
--- a/src/check.pl
+++ b/src/check.pl
@@ -1,8 +1,8 @@
-# $MirOS: src/bin/mksh/check.pl,v 1.37 2014/08/19 07:43:32 tg Exp $
+# $MirOS: src/bin/mksh/check.pl,v 1.37.2.1 2015/04/12 22:32:16 tg Exp $
# $OpenBSD: th,v 1.1 2013/12/02 20:39:44 millert Exp $
#-
# Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
-# 2012, 2013, 2014
+# 2012, 2013, 2014, 2015
# Thorsten Glaser <tg@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
@@ -568,7 +568,7 @@ run_test
}
push(@argv, $temps) if defined $test{'script'};
- #XXX realpathise, use which/whence -p, or sth. like that
+ #XXX realpathise, use command -v/whence -p/which, or sth. like that
#XXX if !$program_kludge, we get by with not doing it for now tho
$new_env{'__progname'} = $argv[0];
diff --git a/src/check.t b/src/check.t
index cd7c50d..1d59d38 100644
--- a/src/check.t
+++ b/src/check.t
@@ -1,4 +1,4 @@
-# $MirOS: src/bin/mksh/check.t,v 1.667.2.3 2015/03/01 15:42:51 tg Exp $
+# $MirOS: src/bin/mksh/check.t,v 1.667.2.7 2015/04/19 19:18:10 tg Exp $
# -*- mode: sh -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout:
- @(#)MIRBSD KSH R50 2015/03/01
+ @(#)MIRBSD KSH R50 2015/04/19
description:
Check version of shell.
stdin:
@@ -39,7 +39,7 @@ name: KSH_VERSION
category: shell:legacy-no
---
expected-stdout:
- @(#)LEGACY KSH R50 2015/03/01
+ @(#)LEGACY KSH R50 2015/04/19
description:
Check version of legacy shell.
stdin:
@@ -257,6 +257,19 @@ stdin:
expected-stdout:
hello world
---
+name: alias-11
+description:
+ Check that special argument handling still applies with escaped aliases
+stdin:
+ alias local='\typeset'
+ function foo {
+ local x=$1 y=z
+ print -r -- "$x,$y"
+ }
+ foo 'bar - baz'
+expected-stdout:
+ bar - baz,z
+---
name: arith-lazy-1
description:
Check that only one side of ternary operator is evaluated
@@ -4832,6 +4845,66 @@ expected-stdout:
1a:
2: x[A B]
---
+name: read-IFS-2
+description:
+ Complex tests, IFS either colon (IFS-NWS) or backslash (tricky)
+stdin:
+ n=0
+ showargs() { print -nr "$1"; shift; for s_arg in "$@"; do print -nr -- " [$s_arg]"; done; print; }
+ (IFS=\\ a=\<\\\>; showargs 3 $a)
+ (IFS=: b=\<:\>; showargs 4 $b)
+ print -r '<\>' | (IFS=\\ read f g; showargs 5 "$f" "$g")
+ print -r '<\\>' | (IFS=\\ read f g; showargs 6 "$f" "$g")
+ print '<\\\n>' | (IFS=\\ read f g; showargs 7 "$f" "$g")
+ print -r '<\>' | (IFS=\\ read f; showargs 8 "$f")
+ print -r '<\\>' | (IFS=\\ read f; showargs 9 "$f")
+ print '<\\\n>' | (IFS=\\ read f; showargs 10 "$f")
+ print -r '<\>' | (IFS=\\ read -r f g; showargs 11 "$f" "$g")
+ print -r '<\\>' | (IFS=\\ read -r f g; showargs 12 "$f" "$g")
+ print '<\\\n>' | (IFS=\\ read -r f g; showargs 13 "$f" "$g")
+ print -r '<\>' | (IFS=\\ read -r f; showargs 14 "$f")
+ print -r '<\\>' | (IFS=\\ read -r f; showargs 15 "$f")
+ print '<\\\n>' | (IFS=\\ read -r f; showargs 16 "$f")
+ print -r '<:>' | (IFS=: read f g; showargs 17 "$f" "$g")
+ print -r '<::>' | (IFS=: read f g; showargs 18 "$f" "$g")
+ print '<:\n>' | (IFS=: read f g; showargs 19 "$f" "$g")
+ print -r '<:>' | (IFS=: read f; showargs 20 "$f")
+ print -r '<::>' | (IFS=: read f; showargs 21 "$f")
+ print '<:\n>' | (IFS=: read f; showargs 22 "$f")
+ print -r '<:>' | (IFS=: read -r f g; showargs 23 "$f" "$g")
+ print -r '<::>' | (IFS=: read -r f g; showargs 24 "$f" "$g")
+ print '<:\n>' | (IFS=: read -r f g; showargs 25 "$f" "$g")
+ print -r '<:>' | (IFS=: read -r f; showargs 26 "$f")
+ print -r '<::>' | (IFS=: read -r f; showargs 27 "$f")
+ print '<:\n>' | (IFS=: read -r f; showargs 28 "$f")
+expected-stdout:
+ 3 [<] [>]
+ 4 [<] [>]
+ 5 [<] [>]
+ 6 [<] [>]
+ 7 [<>] []
+ 8 [<>]
+ 9 [<\>]
+ 10 [<>]
+ 11 [<] [>]
+ 12 [<] [\>]
+ 13 [<] []
+ 14 [<\>]
+ 15 [<\\>]
+ 16 [<]
+ 17 [<] [>]
+ 18 [<] [:>]
+ 19 [<] []
+ 20 [<:>]
+ 21 [<::>]
+ 22 [<]
+ 23 [<] [>]
+ 24 [<] [:>]
+ 25 [<] []
+ 26 [<:>]
+ 27 [<::>]
+ 28 [<]
+---
name: read-ksh-1
description:
If no var specified, REPLY is used
@@ -8517,6 +8590,50 @@ expected-stdout:
{220->> Bitte keine Werbung einwerfen! << }
{220 Who do you wanna pretend to be today? }
---
+name: print-crlf
+description:
+ Check that CR+LF is shown and read as-is
+stdin:
+ cat >foo <<-'EOF'
+ x='bar
+ ' #
+ if test x"$KSH_VERSION" = x""; then #
+ printf '<%s>' "$x" #
+ else #
+ print -nr -- "<$x>" #
+ fi #
+ EOF
+ echo "[$("$__progname" foo)]"
+ "$__progname" foo | while IFS= read -r line; do
+ print -r -- "{$line}"
+ done
+expected-stdout:
+ [<bar
+ >]
+ {<bar }
+---
+name: print-lf
+description:
+ Check that LF-only is shown and read as-is
+stdin:
+ cat >foo <<-'EOF'
+ x='bar
+ ' #
+ if test x"$KSH_VERSION" = x""; then #
+ printf '<%s>' "$x" #
+ else #
+ print -nr -- "<$x>" #
+ fi #
+ EOF
+ echo "[$("$__progname" foo)]"
+ "$__progname" foo | while IFS= read -r line; do
+ print -r -- "{$line}"
+ done
+expected-stdout:
+ [<bar
+ >]
+ {<bar}
+---
name: print-nul-chars
description:
Check handling of NUL characters for print and COMSUB
@@ -8713,28 +8830,46 @@ expected-exit: e != 0
expected-stderr-pattern:
/\.: missing argument.*\n.*\.: missing argument/
---
-name: alias-function-no-conflict
+name: alias-function-no-conflict-legacy
description:
- make aliases not conflict with functions
- note: for ksh-like functions, the order of preference is
- different; bash outputs baz instead of bar in line 2 below
+ make aliases not conflict with functions, legacy version:
+ undefine these aliases upon definition of the function
+ note: for ksh functions, the order of preference differs in GNU bash
stdin:
+ # POSIX function overrides and removes alias
alias foo='echo bar'
+ foo
foo() {
echo baz
}
+ foo
+ unset -f foo
+ foo 2>/dev/null || echo rab
+ # alias overrides ksh function
alias korn='echo bar'
+ korn
function korn {
echo baz
}
- foo
korn
- unset -f foo
- foo 2>/dev/null || echo rab
+ # alias temporarily overrides POSIX function
+ bla() {
+ echo bfn
+ }
+ bla
+ alias bla='echo bal'
+ bla
+ unalias bla
+ bla
expected-stdout:
- baz
bar
+ baz
rab
+ bar
+ bar
+ bfn
+ bal
+ bfn
---
name: bash-function-parens
description:
@@ -8746,12 +8881,13 @@ stdin:
echo "$1 {"
echo ' echo "bar='\''$0'\'\"
echo '}'
- echo ${2:-foo}
+ print -r -- "${2:-foo}"
}
mk 'function foo' >f-korn
mk 'foo ()' >f-dash
mk 'function foo ()' >f-bash
- mk 'function stop ()' stop >f-stop
+ # pre-R51 can do without a backslash in front of the second stop
+ mk 'function stop ()' 'stop' >f-stop
print '#!'"$__progname"'\nprint -r -- "${0%/f-argh}"' >f-argh
chmod +x f-*
u=$(./f-argh)
@@ -9770,25 +9906,33 @@ description:
Verify that file descriptors > 2 are private for Korn shells
AT&T ksh93 does this still, which means we must keep it as well
category: shell:legacy-no
-file-setup: file 644 "test.sh"
- echo >&3 Fowl
stdin:
- exec 3>&1
- "$__progname" test.sh
+ cat >cld <<-EOF
+ #!$__perlname
+ open(my \$fh, ">&", 9) or die "E: open \$!";
+ syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!";
+ EOF
+ chmod +x cld
+ exec 9>&1
+ ./cld
expected-exit: e != 0
expected-stderr-pattern:
- /bad file descriptor/
+ /E: open /
---
name: fd-cloexec-2
description:
Verify that file descriptors > 2 are not private for POSIX shells
See Debian Bug #154540, Closes: #499139
-file-setup: file 644 "test.sh"
- echo >&3 Fowl
stdin:
- test -n "$POSH_VERSION" || set -o sh
- exec 3>&1
- "$__progname" test.sh
+ cat >cld <<-EOF
+ #!$__perlname
+ open(my \$fh, ">&", 9) or die "E: open \$!";
+ syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!";
+ EOF
+ chmod +x cld
+ test -n "$POSH_VERSION" || set -o posix
+ exec 9>&1
+ ./cld
expected-stdout:
Fowl
---
@@ -9796,11 +9940,15 @@ name: fd-cloexec-3
description:
Verify that file descriptors > 2 are not private for LEGACY KSH
category: shell:legacy-yes
-file-setup: file 644 "test.sh"
- echo >&3 Fowl
stdin:
- exec 3>&1
- "$__progname" test.sh
+ cat >cld <<-EOF
+ #!$__perlname
+ open(my \$fh, ">&", 9) or die "E: open \$!";
+ syswrite(\$fh, "Fowl\\n", 5) or die "E: write \$!";
+ EOF
+ chmod +x cld
+ exec 9>&1
+ ./cld
expected-stdout:
Fowl
---
@@ -11956,3 +12104,41 @@ expected-stderr:
[(p:sh)(f1:sh)(f2:sh)] print '(o1:shx)'
[(p:sh)(f1:sh)(f2:sh)] set +x
---
+name: fksh-flags-legacy
+description:
+ Check that even FKSH functions share the shell flags
+stdin:
+ [[ $KSH_VERSION = Version* ]] && set +B
+ foo() {
+ set +f
+ set -e
+ echo 2 "${-/s}" .
+ }
+ set -fh
+ echo 1 "${-/s}" .
+ foo
+ echo 3 "${-/s}" .
+expected-stdout:
+ 1 fh .
+ 2 eh .
+ 3 eh .
+---
+name: fsh-flags
+description:
+ Check that !FKSH functions share the shell flags
+stdin:
+ [[ $KSH_VERSION = Version* ]] && set +B
+ foo() {
+ set +f
+ set -e
+ echo 2 "${-/s}" .
+ }
+ set -fh
+ echo 1 "${-/s}" .
+ foo
+ echo 3 "${-/s}" .
+expected-stdout:
+ 1 fh .
+ 2 eh .
+ 3 eh .
+---
diff --git a/src/dot.mkshrc b/src/dot.mkshrc
index 4878fd7..f65eaa7 100644
--- a/src/dot.mkshrc
+++ b/src/dot.mkshrc
@@ -1,5 +1,5 @@
# $Id$
-# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89.2.1 2015/01/11 22:39:44 tg Exp $
+# $MirOS: src/bin/mksh/dot.mkshrc,v 1.89.2.3 2015/04/12 22:32:22 tg Exp $
#-
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015
@@ -22,21 +22,23 @@
#-
# ${ENV:-~/.mkshrc}: mksh initialisation file for interactive shells
-# catch non-mksh (including lksh) trying to shell this file
-case $KSH_VERSION in
+# catch non-mksh (including lksh) trying to run this file
+case ${KSH_VERSION:-} in
*MIRBSD\ KSH*) ;;
*) return 0 ;;
esac
-PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
- 2>/dev/null)} = *([ ]|localhost) ]] && HOSTNAME=$(ulimit -c 0; hostname \
- 2>/dev/null); : ${EDITOR:=/bin/ed} ${HOSTNAME:=nil} ${TERM:=vt100}
-: ${MKSH:=$(whence -p mksh)}; PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
+PS1='#'; (( USER_ID )) && PS1='$'; : "${TERM:=vt100}${HOSTNAME:=$(ulimit -c \
+ 0; hostname 2>/dev/null)}${EDITOR:=/bin/ed}${USER:=$(ulimit -c 0; id -un \
+ 2>/dev/null || echo \?)}${MKSH:=$(whence -p mksh)}"
+HOSTNAME=${HOSTNAME%%*([ ]).*}; HOSTNAME=${HOSTNAME##*([ ])}
+[[ $HOSTNAME = ?(ip6-)localhost?(6) ]] && HOSTNAME=
+: "${HOSTNAME:=nil}${MKSH:=/bin/mksh}"; export EDITOR HOSTNAME MKSH TERM USER
+PS4='[$EPOCHREALTIME] '; PS1=$'\001\r''${|
local e=$?
(( e )) && REPLY+="$e|"
- REPLY+=${USER:=$(ulimit -c 0; id -un 2>/dev/null || echo \?)}
- REPLY+=@${HOSTNAME%%.*}:
+ REPLY+=${USER}@${HOSTNAME%%.*}:
local d=${PWD:-?} p=~; [[ $p = ?(*/) ]] || d=${d/#$p/~}
local m=${%d} n p=...; (( m > 0 )) || m=${#d}
@@ -44,7 +46,7 @@ PS1='#'; (( USER_ID )) && PS1='$'; [[ ${HOSTNAME:=$(ulimit -c 0; hostname -s \
REPLY+=$p$d
return $e
-} '"$PS1 "; export EDITOR HOSTNAME MKSH TERM USER
+} '"$PS1 "
alias ls=ls
unalias ls
alias l='ls -F'
@@ -52,10 +54,10 @@ alias la='l -a'
alias ll='l -l'
alias lo='l -alo'
alias doch='sudo mksh -c "$(fc -ln -1)"'
-whence -p rot13 >/dev/null || alias rot13='tr \
+command -v rot13 >/dev/null || alias rot13='tr \
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ \
nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'
-if whence -p hd >/dev/null; then :; elif whence -p hexdump >/dev/null; then
+if command -v hd >/dev/null; then :; elif command -v hexdump >/dev/null; then
function hd {
hexdump -e '"%08.8_ax " 8/1 "%02X " " - " 8/1 "%02X "' \
-e '" |" "%_p"' -e '"|\n"' "$@"
@@ -72,7 +74,8 @@ else
while (( i < ${#line[*]} )); do
hv=${line[i++]}
if (( (pos & 15) == 0 )); then
- (( pos )) && print -r -- "$dasc|"
+ (( pos )) && \
+ print -r -- "$dasc|"
print -n "${pos#16#} "
dasc=' |'
fi
@@ -82,11 +85,13 @@ else
else
dasc+=${line[i-1]#1#}
fi
- (( (pos++ & 15) == 7 )) && print -n -- '- '
+ (( (pos++ & 15) == 7 )) && \
+ print -n -- '- '
done
while (( pos & 15 )); do
print -n ' '
- (( (pos++ & 15) == 7 )) && print -n -- '- '
+ (( (pos++ & 15) == 7 )) && \
+ print -n -- '- '
done
(( hv == 2147483647 )) || print -r -- "$dasc|"
fi; }
@@ -95,10 +100,12 @@ fi
# Berkeley C shell compatible dirs, popd, and pushd functions
# Z shell compatible chpwd() hook, used to update DIRSTACK[0]
-DIRSTACKBASE=$(realpath ~/. 2>/dev/null || print -nr -- "${HOME:-/}")
+DIRSTACKBASE=$(realpath ~/. 2>/dev/null || \
+ print -nr -- "${HOME:-/}")
set -A DIRSTACK
function chpwd {
- DIRSTACK[0]=$(realpath . 2>/dev/null || print -r -- "$PWD")
+ DIRSTACK[0]=$(realpath . 2>/dev/null || \
+ print -r -- "$PWD")
[[ $DIRSTACKBASE = ?(*/) ]] || \
DIRSTACK[0]=${DIRSTACK[0]/#$DIRSTACKBASE/~}
:
diff --git a/src/edit.c b/src/edit.c
index 9165ecd..4f9298c 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: edit.c,v 1.39 2013/12/17 16:37:05 deraadt Exp $ */
+/* $OpenBSD: edit.c,v 1.40 2015/03/12 10:20:30 sthen Exp $ */
/* $OpenBSD: edit.h,v 1.9 2011/05/30 17:14:35 martynas Exp $ */
-/* $OpenBSD: emacs.c,v 1.49 2015/02/16 01:44:41 tedu Exp $ */
+/* $OpenBSD: emacs.c,v 1.50 2015/03/25 12:10:52 jca Exp $ */
/* $OpenBSD: vi.c,v 1.28 2013/12/18 16:45:46 deraadt Exp $ */
/*-
@@ -28,7 +28,7 @@
#ifndef MKSH_NO_CMDLINE_EDITING
-__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276.2.3 2015/03/01 15:42:56 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.276.2.5 2015/04/12 22:32:22 tg Exp $");
/*
* in later versions we might use libtermcap for this, but since external
diff --git a/src/eval.c b/src/eval.c
index f9c189d..81240c5 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.158.2.4 2015/03/01 15:42:58 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.158.2.5 2015/04/12 22:32:24 tg Exp $");
/*
* string expansion
@@ -1353,7 +1353,7 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
struct ioword *io = *t->ioact;
char *name;
- if ((io->flag & IOTYPE) != IOREAD)
+ if ((io->ioflag & IOTYPE) != IOREAD)
errorf("%s: %s", "funny $() command",
snptreef(NULL, 32, "%R", io));
shf = shf_open(name = evalstr(io->name, DOTILDE), O_RDONLY, 0,
diff --git a/src/exec.c b/src/exec.c
index 9b94aaf..f9eeb4c 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec.c,v 1.50 2013/06/10 21:09:27 millert Exp $ */
+/* $OpenBSD: exec.c,v 1.51 2015/04/18 18:28:36 deraadt Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.137.2.2 2015/03/01 15:42:59 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.137.2.4 2015/04/19 19:18:15 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL "/bin/sh"
@@ -92,7 +92,7 @@ execute(struct op * volatile t,
t->ioact != NULL && t->ioact[0] != NULL &&
t->ioact[1] == NULL &&
/* of type "here document" (or "here string") */
- (t->ioact[0]->flag & IOTYPE) == IOHERE &&
+ (t->ioact[0]->ioflag & IOTYPE) == IOHERE &&
/* the variable assignment begins with a valid varname */
(ccp = skip_wdvarname(t->vars[0], true)) != t->vars[0] &&
/* and has no right-hand side (i.e. "varname=") */
@@ -786,8 +786,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
/*
* Were we deleted while executing? If so, free the
- * execution tree. TODO: Unfortunately, the table entry
- * is never re-used until the lookup table is expanded.
+ * execution tree.
*/
if ((tp->flag & (FDELETE|FINUSE)) == FDELETE) {
if (tp->flag & ALLOC) {
@@ -1317,7 +1316,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
{
int u = -1;
char *cp = iop->name;
- int iotype = iop->flag & IOTYPE;
+ int iotype = iop->ioflag & IOTYPE;
bool do_open = true, do_close = false;
int flags = 0;
struct ioword iotmp;
@@ -1329,7 +1328,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
/* Used for tracing and error messages to print expanded cp */
iotmp = *iop;
iotmp.name = (iotype == IOHERE) ? NULL : cp;
- iotmp.flag |= IONAMEXP;
+ iotmp.ioflag |= IONAMEXP;
if (Flag(FXTRACE)) {
change_xtrace(2, false);
@@ -1352,7 +1351,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
* The stat() is here to allow redirections to
* things like /dev/null without error.
*/
- if (Flag(FNOCLOBBER) && !(iop->flag & IOCLOB) &&
+ if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) &&
(stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
flags |= O_EXCL;
break;
@@ -1377,7 +1376,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
u = 1009;
do_close = true;
} else if ((u = check_fd(cp,
- X_OK | ((iop->flag & IORDUP) ? R_OK : W_OK),
+ X_OK | ((iop->ioflag & IORDUP) ? R_OK : W_OK),
&emsg)) < 0) {
char *sp;
@@ -1386,7 +1385,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
afree(sp, ATEMP);
return (-1);
}
- if (u == iop->unit)
+ if (u == (int)iop->unit)
/* "dup from" == "dup to" */
return (0);
break;
@@ -1414,7 +1413,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
/* Do not save if it has already been redirected (i.e. "cat >x >y"). */
if (e->savefd[iop->unit] == 0) {
/* If these are the same, it means unit was previously closed */
- if (u == iop->unit)
+ if (u == (int)iop->unit)
e->savefd[iop->unit] = -1;
else
/*
@@ -1429,7 +1428,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
if (do_close)
close(iop->unit);
- else if (u != iop->unit) {
+ else if (u != (int)iop->unit) {
if (ksh_dup2(u, iop->unit, true) < 0) {
int eno;
char *sp;
@@ -1451,7 +1450,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
* causes the shell to close its copies
*/
else if (tp && tp->type == CSHELL && tp->val.f == c_exec) {
- if (iop->flag & IORDUP)
+ if (iop->ioflag & IORDUP)
/* possible exec <&p */
coproc_read_close(u);
else
@@ -1520,7 +1519,7 @@ herein(struct ioword *iop, char **resbuf)
}
/* lexer substitution flags */
- i = (iop->flag & IOEVAL) ? (ONEWORD | HEREDOC) : 0;
+ i = (iop->ioflag & IOEVAL) ? (ONEWORD | HEREDOC) : 0;
/* skip all the fd setup if we just want the value */
if (resbuf != NULL)
@@ -1587,9 +1586,9 @@ do_selectargs(const char **ap, bool print_menu)
if (call_builtin(findcom("read", FC_BI), read_args, Tselect,
false))
return (NULL);
- s = str_val(global("REPLY"));
- if (*s && getn(s, &i))
- return ((i >= 1 && i <= argct) ? ap[i - 1] : null);
+ if (*(s = str_val(global("REPLY"))))
+ return ((getn(s, &i) && i >= 1 && i <= argct) ?
+ ap[i - 1] : null);
print_menu = true;
}
}
diff --git a/src/funcs.c b/src/funcs.c
index 9603aff..95187e6 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -38,7 +38,7 @@
#endif
#endif
-__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.259.2.2 2015/01/25 15:35:44 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.259.2.5 2015/04/19 19:18:16 tg Exp $");
#if HAVE_KILLPG
/*
@@ -778,7 +778,7 @@ c_typeset(const char **wp)
if (fieldstr && !bi_getn(fieldstr, &field))
return (1);
- if (basestr && (!bi_getn(basestr, &base) || base < 1 || base > 36)) {
+ if (basestr && (!getn(basestr, &base) || base < 1 || base > 36)) {
bi_errorf("%s: %s", "bad integer base", basestr);
return (1);
}
@@ -1817,9 +1817,10 @@ int
c_read(const char **wp)
{
#define is_ifsws(c) (ctype((c), C_IFS) && ctype((c), C_IFSWS))
- int c, fd = 0, rv = 0, lastparm = 0;
+ int c, fd = 0, rv = 0;
bool savehist = false, intoarray = false, aschars = false;
bool rawmode = false, expanding = false;
+ bool lastparmmode = false, lastparmused = false;
enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
char delim = '\n';
size_t bytesleft = 128, bytesread;
@@ -1855,7 +1856,7 @@ c_read(const char **wp)
if (!bi_getn(builtin_opt.optarg, &c))
return (2);
if (c == -1) {
- readmode = READALL;
+ readmode = readmode == BYTES ? READALL : UPTO;
bytesleft = 1024;
} else
bytesleft = (unsigned int)c;
@@ -2123,7 +2124,7 @@ c_read(const char **wp)
}
if (!intoarray && wp[1] == NULL)
- lastparm = 1;
+ lastparmmode = true;
c_read_splitlast:
/* copy until IFS character */
@@ -2148,16 +2149,23 @@ c_read(const char **wp)
}
xsave = Xsavepos(xs, xp);
/* copy word delimiter: IFSWS+IFS,IFSWS */
+ expanding = false;
while (bytesread) {
char ch;
ch = *ccp;
if (!ctype(ch, C_IFS))
break;
- Xcheck(xs, xp);
- Xput(xs, xp, ch);
+ if (lastparmmode && !expanding && !rawmode && ch == '\\') {
+ expanding = true;
+ } else {
+ Xcheck(xs, xp);
+ Xput(xs, xp, ch);
+ }
++ccp;
--bytesread;
+ if (expanding)
+ continue;
if (!ctype(ch, C_IFSWS))
break;
}
@@ -2168,12 +2176,12 @@ c_read(const char **wp)
--bytesread;
}
/* if no more parameters, rinse and repeat */
- if (lastparm && bytesread) {
- ++lastparm;
+ if (lastparmmode && bytesread) {
+ lastparmused = true;
goto c_read_splitlast;
}
/* get rid of the delimiter unless we pack the rest */
- if (lastparm < 2)
+ if (!lastparmused)
xp = Xrestpos(xs, xp, xsave);
c_read_gotword:
Xput(xs, xp, '\0');
@@ -2321,13 +2329,9 @@ c_exitreturn(const char **wp)
goto c_exitreturn_err;
arg = wp[builtin_opt.optind];
- if (arg) {
- if (!getn(arg, &n)) {
- exstat = 1;
- warningf(true, "%s: %s", arg, "bad number");
- } else
- exstat = n & 0xFF;
- } else if (trap_exstat != -1)
+ if (arg)
+ exstat = bi_getn(arg, &n) ? (n & 0xFF) : 1;
+ else if (trap_exstat != -1)
exstat = trap_exstat;
if (wp[0][0] == 'r') {
/* return */
diff --git a/src/histrap.c b/src/histrap.c
index 6d2badf..0dfe1c2 100644
--- a/src/histrap.c
+++ b/src/histrap.c
@@ -27,7 +27,7 @@
#include <sys/file.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134.2.3 2015/03/01 15:43:00 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.134.2.5 2015/04/19 19:18:18 tg Exp $");
Trap sigtraps[NSIG + 1];
static struct sigaction Sigact_ign;
@@ -275,8 +275,9 @@ c_fc(const char **wp)
for (hp = rflag ? hlast : hfirst;
hp >= hfirst && hp <= hlast; hp += rflag ? -1 : 1) {
if (!nflag)
- shf_fprintf(shl_stdout, "%d",
- hist_source->line - (int)(histptr - hp));
+ shf_fprintf(shl_stdout, "%lu",
+ (unsigned long)hist_source->line -
+ (unsigned long)(histptr - hp));
shf_putc('\t', shl_stdout);
/* print multi-line commands correctly */
s = *hp;
@@ -563,7 +564,7 @@ sethistfile(const char *name)
return;
/* if the name is the same as the name we have */
- if (hname && strcmp(hname, name) == 0)
+ if (hname && name && !strcmp(hname, name))
return;
/*
@@ -581,7 +582,8 @@ sethistfile(const char *name)
hist_source->line = 0;
}
- hist_init(hist_source);
+ if (name)
+ hist_init(hist_source);
}
#endif
@@ -712,8 +714,10 @@ hist_init(Source *s)
hist_source = s;
#if HAVE_PERSISTENT_HISTORY
- if ((hname = str_val(global("HISTFILE"))) == NULL)
+ if (((hname = str_val(global("HISTFILE"))) == NULL) || !*hname) {
+ hname = NULL;
return;
+ }
strdupx(hname, hname, APERM);
hs = hist_init_first;
diff --git a/src/jobs.c b/src/jobs.c
index d919c16..7a5b270 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: jobs.c,v 1.40 2013/09/04 15:49:18 millert Exp $ */
+/* $OpenBSD: jobs.c,v 1.41 2015/04/18 18:28:36 deraadt Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
- * 2012, 2013, 2014
+ * 2012, 2013, 2014, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105.2.1 2015/01/25 15:44:06 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.105.2.2 2015/04/19 19:18:18 tg Exp $");
#if HAVE_KILLPG
#define mksh_killpg killpg
@@ -1111,6 +1111,7 @@ j_waitj(Job *j,
int flags,
const char *where)
{
+ Proc *p;
int rv;
#ifdef MKSH_NO_SIGSUSPEND
sigset_t omask;
@@ -1238,9 +1239,10 @@ j_waitj(Job *j,
j_systime = j->systime;
rv = j->status;
- if ((flags & JW_PIPEST) && (j->proc_list != NULL)) {
+ if (!(p = j->proc_list)) {
+ ; /* nothing */
+ } else if (flags & JW_PIPEST) {
uint32_t num = 0;
- Proc *p = j->proc_list;
struct tbl *vp;
unset(vp_pipest, 1);
@@ -1270,15 +1272,13 @@ j_waitj(Job *j,
rv = vp->val.i;
p = p->next;
}
- } else if (Flag(FPIPEFAIL) && (j->proc_list != NULL)) {
- Proc *p = j->proc_list;
- int i;
+ } else if (Flag(FPIPEFAIL)) {
+ do {
+ int i = proc_errorlevel(p);
- while (p != NULL) {
- if ((i = proc_errorlevel(p)))
+ if (i)
rv = i;
- p = p->next;
- }
+ } while ((p = p->next));
}
if (!(flags & JW_ASYNCNOTIFY)
@@ -1644,8 +1644,7 @@ j_lookup(const char *cp, int *ecodep)
size_t len;
int job = 0;
- if (ksh_isdigit(*cp)) {
- getn(cp, &job);
+ if (ksh_isdigit(*cp) && getn(cp, &job)) {
/* Look for last_proc->pid (what $! returns) first... */
for (j = job_list; j != NULL; j = j->next)
if (j->last_proc && j->last_proc->pid == job)
@@ -1657,11 +1656,10 @@ j_lookup(const char *cp, int *ecodep)
for (j = job_list; j != NULL; j = j->next)
if (j->pgrp && j->pgrp == job)
return (j);
- if (ecodep)
- *ecodep = JL_NOSUCH;
- return (NULL);
+ goto j_lookup_nosuch;
}
if (*cp != '%') {
+ j_lookup_invalid:
if (ecodep)
*ecodep = JL_INVALID;
return (NULL);
@@ -1681,7 +1679,8 @@ j_lookup(const char *cp, int *ecodep)
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- getn(cp, &job);
+ if (!getn(cp, &job))
+ goto j_lookup_invalid;
for (j = job_list; j != NULL; j = j->next)
if (j->job == job)
return (j);
@@ -1721,6 +1720,7 @@ j_lookup(const char *cp, int *ecodep)
return (last_match);
break;
}
+ j_lookup_nosuch:
if (ecodep)
*ecodep = JL_NOSUCH;
return (NULL);
diff --git a/src/lex.c b/src/lex.c
index 502284a..305f5a4 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014
+ * 2011, 2012, 2013, 2014, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193.2.1 2015/01/11 22:39:50 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.193.2.5 2015/04/19 19:18:19 tg Exp $");
/*
* states while lexing word
@@ -921,42 +921,41 @@ yylex(int cf)
if (!ksh_isdigit(dp[c2 + 1]))
goto no_iop;
iop->unit = (iop->unit * 10) + dp[c2 + 1] - '0';
+ if (iop->unit >= FDBASE)
+ goto no_iop;
}
- if (iop->unit >= FDBASE)
- goto no_iop;
-
if (c == '&') {
if ((c2 = getsc()) != '>') {
ungetsc(c2);
goto no_iop;
}
c = c2;
- iop->flag = IOBASH;
+ iop->ioflag = IOBASH;
} else
- iop->flag = 0;
+ iop->ioflag = 0;
c2 = getsc();
/* <<, >>, <> are ok, >< is not */
if (c == c2 || (c == '<' && c2 == '>')) {
- iop->flag |= c == c2 ?
+ iop->ioflag |= c == c2 ?
(c == '>' ? IOCAT : IOHERE) : IORDWR;
- if (iop->flag == IOHERE) {
+ if (iop->ioflag == IOHERE) {
if ((c2 = getsc()) == '-') {
- iop->flag |= IOSKIP;
+ iop->ioflag |= IOSKIP;
c2 = getsc();
} else if (c2 == '<')
- iop->flag |= IOHERESTR;
+ iop->ioflag |= IOHERESTR;
ungetsc(c2);
if (c2 == '\n')
- iop->flag |= IONDELIM;
+ iop->ioflag |= IONDELIM;
}
} else if (c2 == '&')
- iop->flag |= IODUP | (c == '<' ? IORDUP : 0);
+ iop->ioflag |= IODUP | (c == '<' ? IORDUP : 0);
else {
- iop->flag |= c == '>' ? IOWRITE : IOREAD;
+ iop->ioflag |= c == '>' ? IOWRITE : IOREAD;
if (c == '>' && c2 == '|')
- iop->flag |= IOCLOB;
+ iop->ioflag |= IOCLOB;
else
ungetsc(c2);
}
@@ -1044,13 +1043,16 @@ yylex(int cf)
} else
while ((dp - ident) < IDENT && (c = *sp++) == CHAR)
*dp++ = *sp++;
- /* make sure the ident array stays NUL padded */
- memset(dp, 0, (ident + IDENT) - dp + 1);
if (c != EOS)
/* word is not unquoted */
- *ident = '\0';
+ dp = ident;
+ /* make sure the ident array stays NUL padded */
+ memset(dp, 0, (ident + IDENT) - dp + 1);
+
+ if (!(cf & (KEYWORD | ALIAS)))
+ return (LWORD);
- if (*ident != '\0' && (cf & (KEYWORD | ALIAS))) {
+ if (*ident != '\0') {
struct tbl *p;
uint32_t h = hash(ident);
@@ -1077,8 +1079,7 @@ yylex(int cf)
* pushed into an SREREAD) which is what
* we want here anyway: find out whether
* the alias name is followed by a POSIX
- * function definition (only the opening
- * parenthesis is checked though)
+ * function definition
*/
++cp;
/* prefer functions over aliases */
@@ -1106,6 +1107,11 @@ yylex(int cf)
goto Again;
}
}
+ } else if (cf & ALIAS) {
+ /* retain typeset et al. even when quoted */
+ if (assign_command((dp = wdstrip(yylval.cp, 0))))
+ strlcpy(ident, dp, sizeof(ident));
+ afree(dp, ATEMP);
}
return (LWORD);
@@ -1117,7 +1123,7 @@ gethere(bool iseof)
struct ioword **p;
for (p = heres; p < herep; p++)
- if (iseof && !((*p)->flag & IOHERESTR))
+ if (iseof && !((*p)->ioflag & IOHERESTR))
/* only here strings at EOF */
return;
else
@@ -1138,7 +1144,7 @@ readhere(struct ioword *iop)
char *xp;
int xpos;
- if (iop->flag & IOHERESTR) {
+ if (iop->ioflag & IOHERESTR) {
/* process the here string */
iop->heredoc = xp = evalstr(iop->delim, DOBLANK);
xpos = strlen(xp) - 1;
@@ -1147,9 +1153,9 @@ readhere(struct ioword *iop)
return;
}
- eof = iop->flag & IONDELIM ? "<<" : evalstr(iop->delim, 0);
+ eof = iop->ioflag & IONDELIM ? "<<" : evalstr(iop->delim, 0);
- if (!(iop->flag & IOEVAL))
+ if (!(iop->ioflag & IOEVAL))
ignore_backslash_newline++;
Xinit(xs, xp, 256, ATEMP);
@@ -1158,10 +1164,10 @@ readhere(struct ioword *iop)
/* beginning of line */
eofp = eof;
xpos = Xsavepos(xs, xp);
- if (iop->flag & IOSKIP) {
+ if (iop->ioflag & IOSKIP) {
/* skip over leading tabs */
while ((c = getsc()) == '\t')
- /* nothing */;
+ ; /* nothing */
goto heredoc_parse_char;
}
heredoc_read_char:
@@ -1220,7 +1226,7 @@ readhere(struct ioword *iop)
Xput(xs, xp, '\0');
iop->heredoc = Xclose(xs, xp);
- if (!(iop->flag & IOEVAL))
+ if (!(iop->ioflag & IOEVAL))
ignore_backslash_newline--;
}
@@ -1474,7 +1480,7 @@ getsc_line(Source *s)
void
set_prompt(int to, Source *s)
{
- cur_prompt = to;
+ cur_prompt = (uint8_t)to;
switch (to) {
/* command */
@@ -1497,8 +1503,8 @@ set_prompt(int to, Source *s)
if (*ps1 != '!' || *++ps1 == '!')
shf_putchar(*ps1++, shf);
else
- shf_fprintf(shf, "%d",
- s ? s->line + 1 : 0);
+ shf_fprintf(shf, "%lu", s ?
+ (unsigned long)s->line + 1 : 0UL);
ps1 = shf_sclose(shf);
saved_atemp = ATEMP;
newenv(E_ERRH);
diff --git a/src/lksh.1 b/src/lksh.1
index 31dc6ff..fe6d59d 100644
--- a/src/lksh.1
+++ b/src/lksh.1
@@ -1,6 +1,6 @@
-.\" $MirOS: src/bin/mksh/lksh.1,v 1.5 2013/05/22 18:18:06 tg Exp $
+.\" $MirOS: src/bin/mksh/lksh.1,v 1.5.2.1 2015/03/21 00:12:45 tg Exp $
.\"-
-.\" Copyright (c) 2008, 2009, 2010, 2012, 2013
+.\" Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015
.\" Thorsten “mirabilos” Glaser <tg@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
@@ -72,7 +72,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
-.Dd $Mdocdate: May 22 2013 $
+.Dd $Mdocdate: March 21 2015 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
@@ -175,7 +175,7 @@ instead of relying on legacy or idiotic POSIX-mandated behaviour,
since the MirBSD Korn Shell scripting language is much more consistent.
.Sh LEGACY MODE
.Nm
-has the following differences from
+currently has the following differences from
.Nm mksh :
.Bl -bullet
.It
@@ -195,6 +195,11 @@ as
.Dq LEGACY KSH
instead of
.Dq MIRBSD KSH .
+Note that the rest of the version string is identical between
+the two shell flavours, and the behaviour and differences can
+change between versions; see the accompanying manual page
+.Xr mksh 1
+for the versions this document applies to.
.It
.Nm
only offers the traditional ten file descriptors to scripts.
@@ -245,11 +250,17 @@ passes through the errorlevel from the
.Xr getopt 1
command.
.It
-.Nm lksh ,
-unlike
+Unlike
.At
.Nm ksh ,
-does not keep file descriptors \*(Gt 2 private.
+.Nm mksh
+in
+.Fl o Ic posix
+or
+.Fl o Ic sh
+mode and
+.Nm lksh
+do not keep file descriptors \*(Gt 2 private from sub-processes.
.El
.Sh SEE ALSO
.Xr mksh 1
diff --git a/src/main.c b/src/main.c
index 59d0b1e..047aad1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -5,7 +5,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013, 2014
+ * 2011, 2012, 2013, 2014, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@@ -34,7 +34,7 @@
#include <locale.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/main.c,v 1.285.2.2 2015/03/01 15:43:01 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/main.c,v 1.285.2.4 2015/04/19 19:18:20 tg Exp $");
extern char **environ;
@@ -1286,8 +1286,9 @@ error_prefix(bool fileline)
strcmp(source->file, kshname) != 0)
shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
if (fileline && source && source->file != NULL) {
- shf_fprintf(shl_out, "%s[%d]: ", source->file,
- source->errline > 0 ? source->errline : source->line);
+ shf_fprintf(shl_out, "%s[%lu]: ", source->file,
+ (unsigned long)(source->errline ?
+ source->errline : source->line));
source->errline = 0;
}
}
@@ -1453,13 +1454,20 @@ closepipe(int *pv)
int
check_fd(const char *name, int mode, const char **emsgp)
{
- int fd, fl;
+ int fd = 0, fl;
if (name[0] == 'p' && !name[1])
return (coproc_getfd(mode, emsgp));
- for (fd = 0; ksh_isdigit(*name); ++name)
+ while (ksh_isdigit(*name)) {
fd = (fd * 10) + *name - '0';
- if (*name || fd >= FDBASE) {
+ if (fd >= FDBASE) {
+ if (emsgp)
+ *emsgp = "file descriptor too large";
+ return (-1);
+ }
+ ++name;
+ }
+ if (*name) {
if (emsgp)
*emsgp = "illegal file descriptor name";
return (-1);
diff --git a/src/misc.c b/src/misc.c
index 7c8d114..74bafbe 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: misc.c,v 1.39 2015/01/16 06:39:32 deraadt Exp $ */
+/* $OpenBSD: misc.c,v 1.40 2015/03/18 15:12:36 tedu Exp $ */
/* $OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $ */
/*-
@@ -30,7 +30,7 @@
#include <grp.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219.2.2 2015/03/01 15:43:02 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.219.2.3 2015/03/20 22:21:04 tg Exp $");
#define KSH_CHVT_FLAG
#ifdef MKSH_SMALL
@@ -1289,32 +1289,27 @@ print_columns(struct shf *shf, unsigned int n,
afree(str, ATEMP);
}
-/* Strip any nul bytes from buf - returns new length (nbytes - # of nuls) */
+/* strip all NUL bytes from buf; output is NUL-terminated if stripped */
void
-strip_nuls(char *buf, int nbytes)
+strip_nuls(char *buf, size_t len)
{
- char *dst;
+ char *cp, *dp, *ep;
- /*
- * nbytes check because some systems (older FreeBSDs) have a
- * buggy memchr()
- */
- if (nbytes && (dst = memchr(buf, '\0', nbytes))) {
- char *end = buf + nbytes;
- char *p, *q;
+ if (!len || !(dp = memchr(buf, '\0', len)))
+ return;
- for (p = dst; p < end; p = q) {
- /* skip a block of nulls */
- while (++p < end && *p == '\0')
- ;
- /* find end of non-null block */
- if (!(q = memchr(p, '\0', end - p)))
- q = end;
- memmove(dst, p, q - p);
- dst += q - p;
- }
- *dst = '\0';
- }
+ ep = buf + len;
+ cp = dp;
+
+ cp_has_nul_byte:
+ while (cp++ < ep && *cp == '\0')
+ ; /* nothing */
+ while (cp < ep && *cp != '\0')
+ *dp++ = *cp++;
+ if (cp < ep)
+ goto cp_has_nul_byte;
+
+ *dp = '\0';
}
/*
diff --git a/src/mksh.1 b/src/mksh.1
index 5ad143c..5e41d13 100644
--- a/src/mksh.1
+++ b/src/mksh.1
@@ -1,5 +1,5 @@
-.\" $MirOS: src/bin/mksh/mksh.1,v 1.344.2.3 2015/03/01 15:43:03 tg Exp $
-.\" $OpenBSD: ksh.1,v 1.156 2015/01/16 15:32:32 schwarze Exp $
+.\" $MirOS: src/bin/mksh/mksh.1,v 1.344.2.5 2015/04/12 22:32:30 tg Exp $
+.\" $OpenBSD: ksh.1,v 1.159 2015/03/25 12:10:52 jca Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
.\" 2010, 2011, 2012, 2013, 2014, 2015
@@ -74,7 +74,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
-.Dd $Mdocdate: March 1 2015 $
+.Dd $Mdocdate: April 12 2015 $
.\"
.\" Check which macro package we use, and do other -mdoc setup.
.\"
@@ -1125,11 +1125,12 @@ functions=\*(aqtypeset \-f\*(aq
hash=\*(aqalias \-t\*(aq
history=\*(aqfc \-l\*(aq
integer=\*(aqtypeset \-i\*(aq
-local=\*(aqtypeset\*(aq
+local=typeset
login=\*(aqexec login\*(aq
nameref=\*(aqtypeset \-n\*(aq
nohup=\*(aqnohup \*(aq
r=\*(aqfc \-e \-\*(aq
+source=\*(aqPATH=$PATH:. command .\*(aq
stop=\*(aqkill \-STOP\*(aq
type=\*(aqwhence \-v\*(aq
.Ed
@@ -1203,7 +1204,7 @@ and
.Ic return
work, and in that
.Ic exit
-terminates the parent shell.
+terminates the parent shell; shell options are shared.
.Pp
Another variant of substitution are the valsubs (value substitutions)
.Pf ${\*(Ba\& Ns Ar command Ns \&;}
@@ -1254,10 +1255,8 @@ and
.Sq D .
Note that if the
.Ev IFS
-parameter is set to the
-.Dv NULL
-string, no field splitting is done; if the parameter is unset, the default
-value of space, tab, and newline is used.
+parameter is set to the empty string, no field splitting is done;
+if it is unset, the default value of space, tab, and newline is used.
.Pp
Also, note that the field splitting applies only to the immediate result of
the substitution.
@@ -1795,21 +1794,16 @@ word of the previous command.
.It Ev BASHPID
The PID of the shell or subshell.
.It Ev CDPATH
-Search path for the
+Like
+.Ev PATH ,
+but used to resolve the argument to the
.Ic cd
built-in command.
-It works the same way as
-.Ev PATH
-for those directories not beginning with
-.Ql /
-in
-.Ic cd
-commands.
Note that if
.Ev CDPATH
is set and does not contain
.Sq \&.
-or contains an empty path, the current directory is not searched.
+or an empty string element, the current directory is not searched.
Also, the
.Ic cd
built-in command will display the resulting directory when a match is found
@@ -1862,7 +1856,8 @@ See
below for more information.
.It Ev HISTFILE
The name of the file used to store command history.
-When assigned to, history is loaded from the specified file.
+When assigned to or unset, the file is opened, history is truncated
+then loaded from the file; subsequent new lines are appended.
Also, several invocations of the shell will share history if their
.Ev HISTFILE
parameters all point to the same file.
@@ -1870,7 +1865,7 @@ parameters all point to the same file.
.Sy Note :
If
.Ev HISTFILE
-isn't set, no history file is used.
+is unset or empty, no history file is used.
This is different from
.At
.Nm ksh .
@@ -6490,6 +6485,24 @@ will cause the shell (either
or
.Nm lksh )
to behave more like the standard expects.
+.Pp
+For the purpose of
+.Tn POSIX ,
+.Nm mksh
+supports only the
+.Dq C
+locale.
+For users of UTF-8 locales, the following sh code makes the shell
+match the locale:
+.Bd -literal -offset indent
+case ${KSH_VERSION:\-} in
+*MIRBSD\ KSH*\*(Ba*LEGACY\ KSH*)
+ case ${LC_ALL:\-${LC_CTYPE:\-${LANG:\-}}} in
+ *[Uu][Tt][Ff]8*\*(Ba*[Uu][Tt][Ff]\-8*) set \-U ;;
+ *) set +U ;;
+ esac ;;
+esac
+.Ed
.Sh BUGS
Suspending (using \*(haZ) pipelines like the one below will only suspend
the currently running part of the pipeline; in this example,
@@ -6500,9 +6513,22 @@ is immediately printed on suspension (but not later after an
$ /bin/sleep 666 && echo fubar
.Ed
.Pp
+The truncation process involved when changing
+.Ev HISTFILE
+does not free old history entries (leaks memory) and leaks
+old entries into the new history if their line numbers are
+not overwritten by same-numer entries from the persistent
+history file; truncating the on-disc file to
+.Ev HISTSIZE
+lines has always been broken and prone to history file corruption
+when multiple shells are accessing the file; the rollover process
+for the in-memory portion of the history is slow, should use
+.Xr memmove 3 .
+.Pp
This document attempts to describe
.Nm mksh\ R50e
and up,
+.\" with vendor patches from insert-your-name-here,
compiled without any options impacting functionality, such as
.Dv MKSH_SMALL ,
when not called as
diff --git a/src/sh.h b/src/sh.h
index d053ed2..91f8961 100644
--- a/src/sh.h
+++ b/src/sh.h
@@ -169,9 +169,9 @@
#endif
#ifdef EXTERN
-__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.701.2.4 2015/03/01 15:43:05 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.701.2.7 2015/04/19 19:18:21 tg Exp $");
#endif
-#define MKSH_VERSION "R50 2015/03/01"
+#define MKSH_VERSION "R50 2015/04/19"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
@@ -537,7 +537,7 @@ char *ucstrstr(char *, const char *);
#define mkssert(e) do { } while (/* CONSTCOND */ 0)
#endif
-#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 505)
+#if (!defined(MKSH_BUILDMAKEFILE4BSD) && !defined(MKSH_BUILDSH)) || (MKSH_BUILD_R != 506)
#error Must run Build.sh to compile this.
extern void thiswillneverbedefinedIhope(void);
int
@@ -1270,7 +1270,7 @@ EXTERN char *path; /* copy of either PATH or def_path */
EXTERN const char *def_path; /* path to use if PATH not set */
EXTERN char *tmpdir; /* TMPDIR value */
EXTERN const char *prompt;
-EXTERN int cur_prompt; /* PS1 or PS2 */
+EXTERN uint8_t cur_prompt; /* PS1 or PS2 */
EXTERN int current_lineno; /* LINENO value */
/*
@@ -1347,11 +1347,11 @@ struct op {
* IO redirection
*/
struct ioword {
- int unit; /* unit affected */
- int flag; /* action (below) */
- char *name; /* file name (unused if heredoc) */
- char *delim; /* delimiter for <<,<<- */
- char *heredoc; /* content of heredoc */
+ char *name; /* filename (unused if heredoc) */
+ char *delim; /* delimiter for <<, <<- */
+ char *heredoc; /* content of heredoc */
+ unsigned short ioflag; /* action (below) */
+ short unit; /* unit (fd) affected */
};
/* ioword.flag - type of redirection */
@@ -1582,10 +1582,9 @@ typedef union {
#define VARASN BIT(5) /* check for var=word */
#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */
#define ESACONLY BIT(7) /* only accept esac keyword */
-#define CMDWORD BIT(8) /* parsing simple command (alias related) */
-#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
-#define LQCHAR BIT(10) /* source string contains QCHAR */
-#define HEREDOC BIT(11) /* parsing a here document body */
+#define HEREDELIM BIT(8) /* parsing <<,<<- delimiter */
+#define LQCHAR BIT(9) /* source string contains QCHAR */
+#define HEREDOC BIT(10) /* parsing a here document body */
#define HERES 10 /* max number of << in line */
@@ -1876,7 +1875,8 @@ char *quote_value(const char *);
void print_columns(struct shf *, unsigned int,
char *(*)(char *, size_t, unsigned int, const void *),
const void *, size_t, size_t, bool);
-void strip_nuls(char *, int);
+void strip_nuls(char *, size_t)
+ MKSH_A_BOUNDED(__string__, 1, 2);
ssize_t blocking_read(int, char *, size_t)
MKSH_A_BOUNDED(__buffer__, 2, 3);
int reset_nonblock(int);
@@ -1923,6 +1923,7 @@ char *shf_smprintf(const char *, ...)
ssize_t shf_vfprintf(struct shf *, const char *, va_list)
MKSH_A_FORMAT(__printf__, 2, 0);
/* syn.c */
+int assign_command(const char *);
void initkeywords(void);
struct op *compile(Source *, bool);
bool parse_usec(const char *, struct timeval *);
diff --git a/src/syn.c b/src/syn.c
index 0e6e677..67a8ed7 100644
--- a/src/syn.c
+++ b/src/syn.c
@@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
- * 2011, 2012, 2013, 2014
+ * 2011, 2012, 2013, 2014, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94.2.1 2015/01/25 15:35:54 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.94.2.3 2015/04/12 22:32:35 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
@@ -58,7 +58,6 @@ static struct op *newtp(int);
static void syntaxerr(const char *) MKSH_A_NORETURN;
static void nesting_push(struct nesting_state *, int);
static void nesting_pop(struct nesting_state *);
-static int assign_command(const char *);
static int inalias(struct source *) MKSH_A_PURE;
static Test_op dbtestp_isa(Test_env *, Test_meta);
static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
@@ -190,16 +189,16 @@ synio(int cf)
return (NULL);
ACCEPT;
iop = yylval.iop;
- if (iop->flag & IONDELIM)
+ if (iop->ioflag & IONDELIM)
goto gotnulldelim;
- ishere = (iop->flag & IOTYPE) == IOHERE;
+ ishere = (iop->ioflag & IOTYPE) == IOHERE;
musthave(LWORD, ishere ? HEREDELIM : 0);
if (ishere) {
iop->delim = yylval.cp;
if (*ident != 0) {
/* unquoted */
gotnulldelim:
- iop->flag |= IOEVAL;
+ iop->ioflag |= IOEVAL;
}
if (herep > &heres[HERES - 1])
yyerror("too many %ss\n", "<<");
@@ -207,7 +206,7 @@ synio(int cf)
} else
iop->name = yylval.cp;
- if (iop->flag & IOBASH) {
+ if (iop->ioflag & IOBASH) {
char *cp;
nextiop = alloc(sizeof(*iop), ATEMP);
@@ -221,9 +220,9 @@ synio(int cf)
*cp++ = '0' + (iop->unit % 10);
*cp = EOS;
- iop->flag &= ~IOBASH;
+ iop->ioflag &= ~IOBASH;
nextiop->unit = 2;
- nextiop->flag = IODUP;
+ nextiop->ioflag = IODUP;
nextiop->delim = NULL;
nextiop->heredoc = NULL;
}
@@ -289,7 +288,7 @@ get_command(int cf)
t->lineno = source->line;
while (/* CONSTCOND */ 1) {
cf = (t->u.evalflags ? ARRAYVAR : 0) |
- (XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD);
+ (XPsize(args) == 0 ? sALIAS|VARASN : 0);
switch (tpeek(cf)) {
case REDIR:
while ((iop = synio(cf)) != NULL) {
@@ -927,7 +926,7 @@ compile(Source *s, bool skiputf8bom)
* a=a
* $
*/
-static int
+int
assign_command(const char *s)
{
if (!*s)
@@ -997,9 +996,10 @@ dbtestp_isa(Test_env *te, Test_meta meta)
ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP;
else if (meta == TM_UNOP || meta == TM_BINOP) {
if (meta == TM_BINOP && c == REDIR &&
- (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) {
+ (yylval.iop->ioflag == IOREAD ||
+ yylval.iop->ioflag == IOWRITE)) {
ret = TO_NONNULL;
- save = wdcopy(yylval.iop->flag == IOREAD ?
+ save = wdcopy(yylval.iop->ioflag == IOREAD ?
db_lthan : db_gthan, ATEMP);
} else if (uqword && (ret = test_isop(meta, ident)))
save = yylval.cp;
diff --git a/src/tree.c b/src/tree.c
index 8026f8b..3a79c15 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- * 2011, 2012, 2013
+ * 2011, 2012, 2013, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@@ -23,7 +23,7 @@
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72 2013/09/24 20:19:45 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72.2.1 2015/04/12 22:32:35 tg Exp $");
#define INDENT 8
@@ -69,7 +69,7 @@ ptree(struct op *t, int indent, struct shf *shf)
t->ioact != NULL && t->ioact[0] != NULL &&
t->ioact[1] == NULL &&
/* of type "here document" (or "here string") */
- (t->ioact[0]->flag & IOTYPE) == IOHERE) {
+ (t->ioact[0]->ioflag & IOTYPE) == IOHERE) {
fptreef(shf, indent, "%S", t->vars[0]);
break;
}
@@ -221,12 +221,12 @@ ptree(struct op *t, int indent, struct shf *shf)
struct ioword *iop = *ioact++;
/* heredoc is NULL when tracing (set -x) */
- if ((iop->flag & (IOTYPE | IOHERESTR)) == IOHERE &&
+ if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
iop->heredoc) {
shf_putc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
- iop->flag & IONDELIM ? "<<" :
+ iop->ioflag & IONDELIM ? "<<" :
evalstr(iop->delim, 0));
need_nl = true;
}
@@ -246,16 +246,16 @@ ptree(struct op *t, int indent, struct shf *shf)
static void
pioact(struct shf *shf, struct ioword *iop)
{
- int flag = iop->flag;
- int type = flag & IOTYPE;
- int expected;
+ unsigned short flag = iop->ioflag;
+ unsigned short type = flag & IOTYPE;
+ short expected;
expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
(type == IOCAT || type == IOWRITE) ? 1 :
(type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
iop->unit + 1;
if (iop->unit != expected)
- shf_fprintf(shf, "%d", iop->unit);
+ shf_fprintf(shf, "%d", (int)iop->unit);
switch (type) {
case IOREAD:
@@ -285,10 +285,10 @@ pioact(struct shf *shf, struct ioword *iop)
if (type == IOHERE) {
if (iop->delim)
wdvarput(shf, iop->delim, 0, WDS_TPUTS);
- if (iop->flag & IOHERESTR)
+ if (flag & IOHERESTR)
shf_putc(' ', shf);
} else if (iop->name) {
- if (iop->flag & IONAMEXP)
+ if (flag & IONAMEXP)
print_value_quoted(shf, iop->name);
else
wdvarput(shf, iop->name, 0, WDS_TPUTS);
@@ -910,9 +910,9 @@ dumpioact(struct shf *shf, struct op *t)
shf_puts("{IOACT", shf);
while ((iop = *ioact++) != NULL) {
- int type = iop->flag & IOTYPE;
+ unsigned short type = iop->ioflag & IOTYPE;
#define DT(x) case x: shf_puts(#x, shf); break;
-#define DB(x) if (iop->flag & x) shf_puts("|" #x, shf);
+#define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
shf_putc(';', shf);
switch (type) {
@@ -933,14 +933,14 @@ dumpioact(struct shf *shf, struct op *t)
DB(IOBASH)
DB(IOHERESTR)
DB(IONDELIM)
- shf_fprintf(shf, ",unit=%d", iop->unit);
+ shf_fprintf(shf, ",unit=%d", (int)iop->unit);
if (iop->delim) {
shf_puts(",delim<", shf);
dumpwdvar(shf, iop->delim);
shf_putc('>', shf);
}
if (iop->name) {
- if (iop->flag & IONAMEXP) {
+ if (iop->ioflag & IONAMEXP) {
shf_puts(",name=", shf);
print_value_quoted(shf, iop->name);
} else {
diff --git a/src/var.c b/src/var.c
index 452b6e2..f4da69a 100644
--- a/src/var.c
+++ b/src/var.c
@@ -28,7 +28,7 @@
#include <sys/sysctl.h>
#endif
-__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183.2.2 2015/03/01 15:43:07 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/var.c,v 1.183.2.4 2015/04/19 19:18:23 tg Exp $");
/*-
* Variables
@@ -481,41 +481,57 @@ setint(struct tbl *vq, mksh_ari_t n)
static int
getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
{
- mksh_uari_t c, num, base;
+ mksh_uari_t c, num = 0, base = 10;
const char *s;
bool have_base = false, neg = false;
- if (vp->flag&SPECIAL)
+ if (vp->flag & SPECIAL)
getspec(vp);
/* XXX is it possible for ISSET to be set and val.s to be NULL? */
- if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
+ if (!(vp->flag & ISSET) || (!(vp->flag & INTEGER) && vp->val.s == NULL))
return (-1);
- if (vp->flag&INTEGER) {
+ if (vp->flag & INTEGER) {
nump->i = vp->val.i;
return (vp->type);
}
s = vp->val.s + vp->type;
- base = 10;
- num = 0;
- if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') {
- s += 2;
- base = 16;
- have_base = true;
+
+ do {
+ c = (unsigned char)*s++;
+ } while (ksh_isspace(c));
+
+ switch (c) {
+ case '-':
+ neg = true;
+ /* FALLTHROUGH */
+ case '+':
+ c = (unsigned char)*s++;
+ break;
}
- if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) &&
- !(vp->flag & ZEROFIL)) {
- /* interpret as octal (deprecated) */
- base = 8;
- have_base = true;
+
+ if (c == '0' && arith) {
+ if ((s[0] | 0x20) == 'x') {
+ /* interpret as hexadecimal */
+ base = 16;
+ ++s;
+ goto getint_c_style_base;
+ } else if (Flag(FPOSIX) && ksh_isdigit(s[0]) &&
+ !(vp->flag & ZEROFIL)) {
+ /* interpret as octal (deprecated) */
+ base = 8;
+ getint_c_style_base:
+ have_base = true;
+ c = (unsigned char)*s++;
+ }
}
- while ((c = (unsigned char)*s++)) {
- if (c == '-') {
- neg = true;
- continue;
- } else if (c == '#') {
- if (have_base || num < 1 || num > 36)
+
+ do {
+ if (c == '#') {
+ /* ksh-style base determination */
+ if (have_base || num < 1)
return (-1);
if ((base = num) == 1) {
+ /* mksh-specific extension */
unsigned int wc;
if (!UTFMODE)
@@ -530,22 +546,26 @@ getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
wc = 0xEF00 + *(const unsigned char *)s;
nump->u = (mksh_uari_t)wc;
return (1);
- }
+ } else if (base > 36)
+ return (-1);
num = 0;
have_base = true;
continue;
- } else if (ksh_isdigit(c))
+ }
+ if (ksh_isdigit(c))
c -= '0';
- else if (ksh_islower(c))
+ else {
+ c |= 0x20;
+ if (!ksh_islower(c))
+ return (-1);
c -= 'a' - 10;
- else if (ksh_isupper(c))
- c -= 'A' - 10;
- else
- return (-1);
+ }
if (c >= base)
return (-1);
+ /* handle overflow as truncation */
num = num * base + c;
- }
+ } while ((c = (unsigned char)*s++));
+
if (neg)
num = -num;
nump->u = num;
@@ -1144,7 +1164,7 @@ unspecial(const char *name)
}
static time_t seconds; /* time SECONDS last set */
-static int user_lineno; /* what user set $LINENO to */
+static mksh_uari_t user_lineno; /* what user set $LINENO to */
static void
getspec(struct tbl *vp)
@@ -1178,7 +1198,7 @@ getspec(struct tbl *vp)
num.i = histsize;
break;
case V_LINENO:
- num.i = current_lineno + user_lineno;
+ num.u = (mksh_uari_t)current_lineno + user_lineno;
break;
case V_LINES:
num.i = x_lins;
@@ -1308,7 +1328,7 @@ setspec(struct tbl *vp)
break;
case V_LINENO:
/* The -1 is because line numbering starts at 1. */
- user_lineno = num.u - current_lineno - 1;
+ user_lineno = num.u - (mksh_uari_t)current_lineno - 1;
break;
case V_LINES:
if (num.i >= MIN_LINS)
@@ -1350,6 +1370,11 @@ unsetspec(struct tbl *vp)
*/
switch (special(vp->name)) {
+#if HAVE_PERSISTENT_HISTORY
+ case V_HISTFILE:
+ sethistfile(NULL);
+ return;
+#endif
case V_IFS:
setctypes(TC_IFSWS, C_IFS);
ifs0 = ' ';