Merge commit '91ae6ad199035b1cf'

This commit is contained in:
KO Myung-Hun 2016-01-24 16:36:38 +09:00
commit 6eb125c18a
16 changed files with 394 additions and 252 deletions

View File

@ -1,8 +1,8 @@
#!/bin/sh
srcversion='$MirOS: src/bin/mksh/Build.sh,v 1.693 2015/12/12 22:25:10 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
# 2011, 2012, 2013, 2014, 2015, 2016
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
@ -745,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
;;
@ -753,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
@ -1239,19 +1241,20 @@ dragonegg|llvm)
vv '|' "llc -version"
;;
esac
etd=" on $et"
case $et in
klibc)
add_cppflags -DMKSH_NO_LIMITS
;;
unknown)
# nothing special detected, dont 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
#

27
check.t
View File

@ -1,8 +1,8 @@
# $MirOS: src/bin/mksh/check.t,v 1.716 2015/12/12 23:31:15 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.721 2016/01/20 21:34:09 tg Exp $
# -*- mode: sh -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011, 2012, 2013, 2014, 2015
# 2011, 2012, 2013, 2014, 2015, 2016
# mirabilos <m@mirbsd.org>
#
# Provided that these terms and disclaimer and all copyright notices
@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout:
@(#)MIRBSD KSH R52 2015/12/12
@(#)MIRBSD KSH R52 2016/01/20
description:
Check version of shell.
stdin:
@ -39,7 +39,7 @@ name: KSH_VERSION
category: shell:legacy-no
---
expected-stdout:
@(#)LEGACY KSH R52 2015/12/12
@(#)LEGACY KSH R52 2016/01/20
description:
Check version of legacy shell.
stdin:
@ -6592,12 +6592,24 @@ description:
env-setup: !HOME=/sweet!
stdin:
echo ${A=a=}~ b=~ c=d~ ~
export e=~ f=d~
command command export g=~ h=d~
echo ". $e . $f ."
echo ". $g . $h ."
set -o posix
unset A
unset A e f g h
echo ${A=a=}~ b=~ c=d~ ~
export e=~ f=d~
command command export g=~ h=d~
echo ". $e . $f ."
echo ". $g . $h ."
expected-stdout:
a=/sweet b=/sweet c=d~ /sweet
. /sweet . d~ .
. /sweet . d~ .
a=~ b=~ c=d~ /sweet
. /sweet . d~ .
. /sweet . d~ .
---
name: tilde-expand-2
description:
@ -8515,7 +8527,7 @@ expected-stdout:
name: varexpand-substr-3
description:
Check that some things that work in bash fail.
This is by design. And that some things fail in both.
This is by design. Oh and vice versa, nowadays.
stdin:
export x=abcdefghi n=2
"$__progname" -c 'echo v${x:(n)}x'
@ -8523,12 +8535,13 @@ stdin:
"$__progname" -c 'echo x${x:n}x'
"$__progname" -c 'echo y${x:}x'
"$__progname" -c 'echo z${x}x'
# next fails only in bash
"$__progname" -c 'x=abcdef;y=123;echo ${x:${y:2:1}:2}' >/dev/null 2>&1; echo $?
expected-stdout:
vcdefghix
wcdefghix
zabcdefghix
1
0
expected-stderr-pattern:
/x:n.*bad substitution.*\n.*bad substitution/
---

View File

@ -1,5 +1,5 @@
# $Id$
# $MirOS: src/bin/mksh/dot.mkshrc,v 1.103 2015/12/12 18:47:40 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
@ -596,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

15
eval.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015
* 2011, 2012, 2013, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.178 2015/12/12 22:24:07 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;
@ -488,8 +485,6 @@ expand(
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;
@ -1329,7 +1324,7 @@ 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->ioname, DOTILDE), O_RDONLY,
0, SHF_MAPHI | SHF_CLEXEC);

43
exec.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.168 2015/10/09 21:36:55 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"
@ -1013,6 +1013,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))
@ -1404,7 +1405,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
int u = -1;
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;
@ -1433,14 +1434,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:
@ -1485,6 +1499,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 */

7
expr.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014
* 2011, 2012, 2013, 2014, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/expr.c,v 1.80 2015/11/29 17:05:00 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

269
funcs.c
View File

@ -5,7 +5,7 @@
/*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
* 2010, 2011, 2012, 2013, 2014, 2015
* 2010, 2011, 2012, 2013, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -38,7 +38,7 @@
#endif
#endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.288 2015/12/12 19:27:36 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},
@ -278,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)) {
/*
@ -299,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) ||
@ -309,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:
@ -329,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;
@ -393,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;
@ -416,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:
@ -440,18 +442,22 @@ c_print(const char **wp)
}
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;
/*
@ -461,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
@ -1851,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;
@ -2102,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);
@ -2110,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 */
@ -2215,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 */
@ -2355,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;
@ -2385,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);
}
@ -3664,10 +3689,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 */
@ -3689,54 +3715,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)
@ -3744,6 +3780,7 @@ c_cat(const char **wp)
} while (*wp);
out:
restore_pipe(opipe);
free_osfunc(buf);
return (rv);
}

View File

@ -3,7 +3,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2014, 2015
* 2011, 2012, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -27,7 +27,7 @@
#include <sys/file.h>
#endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.151 2015/11/29 17:05:01 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;
@ -1213,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);

11
jobs.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
* 2012, 2013, 2014, 2015
* 2012, 2013, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/jobs.c,v 1.116 2015/10/09 16:11:15 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
@ -215,14 +215,11 @@ j_init(void)
static int
proc_errorlevel(Proc *p)
{
int termsig;
switch (p->state) {
case PEXITED:
return ((WEXITSTATUS(p->status)) & 255);
case PSIGNALLED:
termsig = WTERMSIG(p->status);
return ((termsig < 1 || termsig > 127) ? 255 : 128 + termsig);
return (ksh_sigmask(WTERMSIG(p->status)));
default:
return (0);
}
@ -756,7 +753,7 @@ waitfor(const char *cp, int *sigp)
if (rv < 0)
/* we were interrupted */
*sigp = 128 + -rv;
*sigp = ksh_sigmask(-rv);
return (rv);
}

45
lex.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015
* 2011, 2012, 2013, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.214 2015/12/12 19:05:52 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.218 2016/01/20 21:34:12 tg Exp $");
/*
* states while lexing word
@ -94,8 +94,7 @@ 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(void);
@ -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);
@ -269,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)) {
@ -550,8 +549,10 @@ yylex(int cf)
* 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) {
@ -588,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) {
@ -777,6 +778,7 @@ yylex(int cf)
Source *s;
ungetsc(c2);
ungetsc(c);
/*
* mismatched parenthesis -
* assume we were really
@ -789,6 +791,7 @@ yylex(int cf)
s->start = s->str = s->u.freeme = dp;
s->next = source;
source = s;
ungetsc('('/*)*/);
return ('('/*)*/);
}
} else if (c == '(')
@ -1088,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);
}
@ -1783,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);
}

56
mksh.1
View File

@ -1,8 +1,8 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.383 2015/12/12 22:25:14 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
.\" 2010, 2011, 2012, 2013, 2014, 2015, 2016
.\" mirabilos <m@mirbsd.org>
.\"
.\" Provided that these terms and disclaimer and all copyright notices
@ -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: December 12 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:
@ -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
@ -1286,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
@ -1296,6 +1305,8 @@ form, a
followed by any of
.Ql $ ,
.Ql \` ,
.Ql \&"
.Pq currently, and violating Tn POSIX ,
or
.Ql \e
is stripped (a
@ -1744,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
@ -2965,7 +2976,8 @@ Builtins that are not special:
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 ...
@ -3815,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 ,
@ -4138,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 $@
@ -6552,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,
@ -6574,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\ R52
.Nm mksh\ R52b
and up,
.\" with vendor patches from insert-your-name-here,
compiled without any options impacting functionality, such as

19
sh.h
View File

@ -10,7 +10,7 @@
/*-
* Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015
* 2011, 2012, 2013, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -175,9 +175,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.751 2015/12/12 22:25:15 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.757 2016/01/20 21:34:13 tg Exp $");
#endif
#define MKSH_VERSION "R52 2015/12/12"
#define MKSH_VERSION "R52 2016/01/20"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
@ -379,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) */
@ -862,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 */
@ -1186,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 */
@ -1628,13 +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 CMDWORD BIT(8) /* parsing simple command (alias related) */
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
#define LQCHAR BIT(10) /* source string contains QCHAR */
#define HEREDOC BIT(11) /* parsing a here document body */
#define HERES 10 /* max number of << in line */
@ -1993,7 +1998,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 *);

4
shf.c
View File

@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.68 2015/10/09 15:38:36 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 */
@ -1121,6 +1121,8 @@ cstrerror(int errnum)
#endif
case EACCES:
return ("Permission denied");
case EEXIST:
return ("File exists");
case ENOTDIR:
return ("Not a directory");
#ifdef EINVAL

43
syn.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
* 2011, 2012, 2013, 2014, 2015
* 2011, 2012, 2013, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.107 2015/12/12 21:03:53 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) */
@ -272,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 */
@ -281,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);
@ -296,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 : CMDWORD);
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) {
@ -316,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);
@ -329,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;
@ -400,6 +413,7 @@ get_command(int cf)
case LWORD:
break;
case '(': /*)*/
c = '(';
goto Subshell;
default:
syntaxerr(NULL);
@ -431,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");
@ -572,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);
@ -943,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));
}
@ -991,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;
@ -1037,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);

21
tree.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2015
* 2011, 2012, 2013, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.79 2015/12/12 19:08:58 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.80 2016/01/14 22:30:43 tg Exp $");
#define INDENT 8
@ -318,6 +318,10 @@ 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++;
shf_putc(c, shf);
@ -383,8 +387,10 @@ 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:
shf_putchar(*wp++, shf);
@ -581,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:
@ -604,6 +612,7 @@ wdscan(const char *wp, int c)
;
break;
case CSUBST:
wdscan_csubst:
wp++;
if (c == CSUBST && nest == 0)
return (wp);
@ -807,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:

65
var.c
View File

@ -2,7 +2,7 @@
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
* 2011, 2012, 2013, 2014, 2015
* 2011, 2012, 2013, 2014, 2015, 2016
* mirabilos <m@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -28,7 +28,7 @@
#include <sys/sysctl.h>
#endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.195 2015/10/09 16:11:19 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 *
@ -1492,7 +1507,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