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