Merge commit '91ae6ad199035b1cf'
This commit is contained in:
commit
6eb125c18a
11
Build.sh
11
Build.sh
@ -1,8 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/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,
|
# 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>
|
# mirabilos <m@mirbsd.org>
|
||||||
#
|
#
|
||||||
# Provided that these terms and disclaimer and all copyright notices
|
# Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -745,6 +745,7 @@ GNU)
|
|||||||
*tendracc*) ;;
|
*tendracc*) ;;
|
||||||
*) add_cppflags -D_GNU_SOURCE ;;
|
*) add_cppflags -D_GNU_SOURCE ;;
|
||||||
esac
|
esac
|
||||||
|
add_cppflags -DSETUID_CAN_FAIL_WITH_EAGAIN
|
||||||
# define MKSH__NO_PATH_MAX to use Hurd-only functions
|
# define MKSH__NO_PATH_MAX to use Hurd-only functions
|
||||||
add_cppflags -DMKSH__NO_PATH_MAX
|
add_cppflags -DMKSH__NO_PATH_MAX
|
||||||
;;
|
;;
|
||||||
@ -753,6 +754,7 @@ GNU/kFreeBSD)
|
|||||||
*tendracc*) ;;
|
*tendracc*) ;;
|
||||||
*) add_cppflags -D_GNU_SOURCE ;;
|
*) add_cppflags -D_GNU_SOURCE ;;
|
||||||
esac
|
esac
|
||||||
|
add_cppflags -DSETUID_CAN_FAIL_WITH_EAGAIN
|
||||||
;;
|
;;
|
||||||
Haiku)
|
Haiku)
|
||||||
add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1
|
add_cppflags -DMKSH_ASSUME_UTF8; HAVE_ISSET_MKSH_ASSUME_UTF8=1
|
||||||
@ -1239,19 +1241,20 @@ dragonegg|llvm)
|
|||||||
vv '|' "llc -version"
|
vv '|' "llc -version"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
etd=" on $et"
|
||||||
case $et in
|
case $et in
|
||||||
klibc)
|
klibc)
|
||||||
add_cppflags -DMKSH_NO_LIMITS
|
add_cppflags -DMKSH_NO_LIMITS
|
||||||
;;
|
;;
|
||||||
unknown)
|
unknown)
|
||||||
# nothing special detected, don’t worry
|
# nothing special detected, don’t worry
|
||||||
unset et
|
etd=
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
# huh?
|
# huh?
|
||||||
;;
|
;;
|
||||||
esac
|
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
|
rmf conftest.c conftest.o conftest a.out* a.exe* conftest.exe* vv.out
|
||||||
|
|
||||||
#
|
#
|
||||||
|
27
check.t
27
check.t
@ -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 -*-
|
# -*- mode: sh -*-
|
||||||
#-
|
#-
|
||||||
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
# 2011, 2012, 2013, 2014, 2015
|
# 2011, 2012, 2013, 2014, 2015, 2016
|
||||||
# mirabilos <m@mirbsd.org>
|
# mirabilos <m@mirbsd.org>
|
||||||
#
|
#
|
||||||
# Provided that these terms and disclaimer and all copyright notices
|
# 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
|
# (2013/12/02 20:39:44) http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
|
||||||
|
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
@(#)MIRBSD KSH R52 2015/12/12
|
@(#)MIRBSD KSH R52 2016/01/20
|
||||||
description:
|
description:
|
||||||
Check version of shell.
|
Check version of shell.
|
||||||
stdin:
|
stdin:
|
||||||
@ -39,7 +39,7 @@ name: KSH_VERSION
|
|||||||
category: shell:legacy-no
|
category: shell:legacy-no
|
||||||
---
|
---
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
@(#)LEGACY KSH R52 2015/12/12
|
@(#)LEGACY KSH R52 2016/01/20
|
||||||
description:
|
description:
|
||||||
Check version of legacy shell.
|
Check version of legacy shell.
|
||||||
stdin:
|
stdin:
|
||||||
@ -6592,12 +6592,24 @@ description:
|
|||||||
env-setup: !HOME=/sweet!
|
env-setup: !HOME=/sweet!
|
||||||
stdin:
|
stdin:
|
||||||
echo ${A=a=}~ b=~ c=d~ ~
|
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
|
set -o posix
|
||||||
unset A
|
unset A e f g h
|
||||||
echo ${A=a=}~ b=~ c=d~ ~
|
echo ${A=a=}~ b=~ c=d~ ~
|
||||||
|
export e=~ f=d~
|
||||||
|
command command export g=~ h=d~
|
||||||
|
echo ". $e . $f ."
|
||||||
|
echo ". $g . $h ."
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
a=/sweet b=/sweet c=d~ /sweet
|
a=/sweet b=/sweet c=d~ /sweet
|
||||||
|
. /sweet . d~ .
|
||||||
|
. /sweet . d~ .
|
||||||
a=~ b=~ c=d~ /sweet
|
a=~ b=~ c=d~ /sweet
|
||||||
|
. /sweet . d~ .
|
||||||
|
. /sweet . d~ .
|
||||||
---
|
---
|
||||||
name: tilde-expand-2
|
name: tilde-expand-2
|
||||||
description:
|
description:
|
||||||
@ -8515,7 +8527,7 @@ expected-stdout:
|
|||||||
name: varexpand-substr-3
|
name: varexpand-substr-3
|
||||||
description:
|
description:
|
||||||
Check that some things that work in bash fail.
|
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:
|
stdin:
|
||||||
export x=abcdefghi n=2
|
export x=abcdefghi n=2
|
||||||
"$__progname" -c 'echo v${x:(n)}x'
|
"$__progname" -c 'echo v${x:(n)}x'
|
||||||
@ -8523,12 +8535,13 @@ stdin:
|
|||||||
"$__progname" -c 'echo x${x:n}x'
|
"$__progname" -c 'echo x${x:n}x'
|
||||||
"$__progname" -c 'echo y${x:}x'
|
"$__progname" -c 'echo y${x:}x'
|
||||||
"$__progname" -c 'echo z${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 $?
|
"$__progname" -c 'x=abcdef;y=123;echo ${x:${y:2:1}:2}' >/dev/null 2>&1; echo $?
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
vcdefghix
|
vcdefghix
|
||||||
wcdefghix
|
wcdefghix
|
||||||
zabcdefghix
|
zabcdefghix
|
||||||
1
|
0
|
||||||
expected-stderr-pattern:
|
expected-stderr-pattern:
|
||||||
/x:n.*bad substitution.*\n.*bad substitution/
|
/x:n.*bad substitution.*\n.*bad substitution/
|
||||||
---
|
---
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# $Id$
|
# $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,
|
# Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010,
|
||||||
# 2011, 2012, 2013, 2014, 2015
|
# 2011, 2012, 2013, 2014, 2015
|
||||||
@ -596,8 +596,8 @@ done
|
|||||||
#\unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
|
#\unset LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_IDENTIFICATION LC_MONETARY \
|
||||||
# LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME
|
# LC_NAME LC_NUMERIC LC_TELEPHONE LC_TIME
|
||||||
#p=en_GB.UTF-8
|
#p=en_GB.UTF-8
|
||||||
#\set -U
|
|
||||||
#\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
|
#\export LANG=C LC_CTYPE=$p LC_MEASUREMENT=$p LC_MESSAGES=$p LC_PAPER=$p
|
||||||
|
#\set -U
|
||||||
|
|
||||||
\unset p
|
\unset p
|
||||||
|
|
||||||
|
15
eval.c
15
eval.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
* 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>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
* string expansion
|
||||||
@ -437,8 +437,6 @@ expand(
|
|||||||
beg = wdcopy(sp, ATEMP);
|
beg = wdcopy(sp, ATEMP);
|
||||||
mid = beg + (wdscan(sp, ADELIM) - sp);
|
mid = beg + (wdscan(sp, ADELIM) - sp);
|
||||||
stg = beg + (wdscan(sp, CSUBST) - sp);
|
stg = beg + (wdscan(sp, CSUBST) - sp);
|
||||||
if (mid >= stg)
|
|
||||||
goto unwind_substsyn;
|
|
||||||
mid[-2] = EOS;
|
mid[-2] = EOS;
|
||||||
if (mid[-1] == /*{*/'}') {
|
if (mid[-1] == /*{*/'}') {
|
||||||
sp += mid - beg - 1;
|
sp += mid - beg - 1;
|
||||||
@ -446,9 +444,8 @@ expand(
|
|||||||
} else {
|
} else {
|
||||||
end = mid +
|
end = mid +
|
||||||
(wdscan(mid, ADELIM) - mid);
|
(wdscan(mid, ADELIM) - mid);
|
||||||
if (end >= stg ||
|
if (end[-1] != /*{*/ '}')
|
||||||
/* more than max delimiters */
|
/* more than max delimiters */
|
||||||
end[-1] != /*{*/ '}')
|
|
||||||
goto unwind_substsyn;
|
goto unwind_substsyn;
|
||||||
end[-2] = EOS;
|
end[-2] = EOS;
|
||||||
sp += end - beg - 1;
|
sp += end - beg - 1;
|
||||||
@ -488,8 +485,6 @@ expand(
|
|||||||
s = wdcopy(sp, ATEMP);
|
s = wdcopy(sp, ATEMP);
|
||||||
p = s + (wdscan(sp, ADELIM) - sp);
|
p = s + (wdscan(sp, ADELIM) - sp);
|
||||||
d = s + (wdscan(sp, CSUBST) - sp);
|
d = s + (wdscan(sp, CSUBST) - sp);
|
||||||
if (p >= d)
|
|
||||||
goto unwind_substsyn;
|
|
||||||
p[-2] = EOS;
|
p[-2] = EOS;
|
||||||
if (p[-1] == /*{*/'}')
|
if (p[-1] == /*{*/'}')
|
||||||
d = NULL;
|
d = NULL;
|
||||||
@ -1329,7 +1324,7 @@ comsub(Expand *xp, const char *cp, int fn MKSH_A_UNUSED)
|
|||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
if ((io->ioflag & IOTYPE) != IOREAD)
|
if ((io->ioflag & IOTYPE) != IOREAD)
|
||||||
errorf("%s: %s", "funny $() command",
|
errorf("%s: %s", T_funny_command,
|
||||||
snptreef(NULL, 32, "%R", io));
|
snptreef(NULL, 32, "%R", io));
|
||||||
shf = shf_open(name = evalstr(io->ioname, DOTILDE), O_RDONLY,
|
shf = shf_open(name = evalstr(io->ioname, DOTILDE), O_RDONLY,
|
||||||
0, SHF_MAPHI | SHF_CLEXEC);
|
0, SHF_MAPHI | SHF_CLEXEC);
|
||||||
|
43
exec.c
43
exec.c
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
#ifndef MKSH_DEFAULT_EXECSHELL
|
||||||
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
|
#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 == /* ECOFF_SH */ 0x0500 || m == 0x0005) ||
|
||||||
(m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) ||
|
(m == /* bzip */ 0x425A) || (m == /* "MZ" */ 0x4D5A) ||
|
||||||
(m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) ||
|
(m == /* "NE" */ 0x4E45) || (m == /* "LX" */ 0x4C58) ||
|
||||||
|
(m == /* ksh93 */ 0x0B13) || (m == /* LZIP */ 0x4C5A) ||
|
||||||
(m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' &&
|
(m == /* xz */ 0xFD37 && buf[2] == 'z' && buf[3] == 'X' &&
|
||||||
buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
|
buf[4] == 'Z') || (m == /* 7zip */ 0x377A) ||
|
||||||
(m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
|
(m == /* gzip */ 0x1F8B) || (m == /* .Z */ 0x1F9D))
|
||||||
@ -1404,7 +1405,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
|
|||||||
int u = -1;
|
int u = -1;
|
||||||
char *cp = iop->ioname;
|
char *cp = iop->ioname;
|
||||||
int iotype = iop->ioflag & IOTYPE;
|
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;
|
int flags = 0;
|
||||||
struct ioword iotmp;
|
struct ioword iotmp;
|
||||||
struct stat statb;
|
struct stat statb;
|
||||||
@ -1433,14 +1434,27 @@ iosetup(struct ioword *iop, struct tbl *tp)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IOWRITE:
|
case IOWRITE:
|
||||||
flags = O_WRONLY | O_CREAT | O_TRUNC;
|
if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB)) {
|
||||||
/*
|
/* >file under set -C */
|
||||||
* The stat() is here to allow redirections to
|
if (stat(cp, &statb)) {
|
||||||
* things like /dev/null without error.
|
/* nonexistent file */
|
||||||
*/
|
flags = O_WRONLY | O_CREAT | O_EXCL;
|
||||||
if (Flag(FNOCLOBBER) && !(iop->ioflag & IOCLOB) &&
|
} else if (S_ISREG(statb.st_mode)) {
|
||||||
(stat(cp, &statb) < 0 || S_ISREG(statb.st_mode)))
|
/* regular file, refuse clobbering */
|
||||||
flags |= O_EXCL;
|
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;
|
break;
|
||||||
|
|
||||||
case IORDWR:
|
case IORDWR:
|
||||||
@ -1485,6 +1499,15 @@ iosetup(struct ioword *iop, struct tbl *tp)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
u = binopen3(cp, flags, 0666);
|
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) {
|
if (u < 0) {
|
||||||
/* herein() may already have printed message */
|
/* herein() may already have printed message */
|
||||||
|
7
expr.c
7
expr.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
* 2011, 2012, 2013, 2014
|
* 2011, 2012, 2013, 2014, 2016
|
||||||
* mirabilos <m@mirbsd.org>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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[] */
|
/* the order of these enums is constrained by the order of opinfo[] */
|
||||||
enum token {
|
enum token {
|
||||||
@ -659,7 +659,8 @@ exprtoken(Expr_state *es)
|
|||||||
es->tok = VAR;
|
es->tok = VAR;
|
||||||
} else if (c == '1' && cp[1] == '#') {
|
} else if (c == '1' && cp[1] == '#') {
|
||||||
cp += 2;
|
cp += 2;
|
||||||
cp += utf_ptradj(cp);
|
if (*cp)
|
||||||
|
cp += utf_ptradj(cp);
|
||||||
strndupx(tvar, es->tokp, cp - es->tokp, ATEMP);
|
strndupx(tvar, es->tokp, cp - es->tokp, ATEMP);
|
||||||
goto process_tvar;
|
goto process_tvar;
|
||||||
#ifndef MKSH_SMALL
|
#ifndef MKSH_SMALL
|
||||||
|
269
funcs.c
269
funcs.c
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
* 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>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -38,7 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#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
|
#if HAVE_KILLPG
|
||||||
/*
|
/*
|
||||||
@ -103,7 +103,7 @@ const struct builtin mkshbuiltins[] = {
|
|||||||
{"cd", c_cd},
|
{"cd", c_cd},
|
||||||
/* dash compatibility hack */
|
/* dash compatibility hack */
|
||||||
{"chdir", c_cd},
|
{"chdir", c_cd},
|
||||||
{"command", c_command},
|
{Tcommand, c_command},
|
||||||
{"*=continue", c_brkcont},
|
{"*=continue", c_brkcont},
|
||||||
{"echo", c_print},
|
{"echo", c_print},
|
||||||
{"*=eval", c_eval},
|
{"*=eval", c_eval},
|
||||||
@ -278,20 +278,18 @@ static void s_put(int);
|
|||||||
int
|
int
|
||||||
c_print(const char **wp)
|
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 fd = 1, c;
|
||||||
int flags = PO_EXPAND | PO_NL;
|
const char *s;
|
||||||
const char *s, *emsg;
|
|
||||||
XString xs;
|
XString xs;
|
||||||
char *xp;
|
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') {
|
if (wp[0][0] == 'e') {
|
||||||
/* echo builtin */
|
/* "echo" builtin */
|
||||||
wp++;
|
++wp;
|
||||||
#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
|
#ifdef MKSH_MIDNIGHTBSD01ASH_COMPAT
|
||||||
if (Flag(FSH)) {
|
if (Flag(FSH)) {
|
||||||
/*
|
/*
|
||||||
@ -299,7 +297,7 @@ c_print(const char **wp)
|
|||||||
* one that supports -e but does not enable it by
|
* one that supports -e but does not enable it by
|
||||||
* default
|
* default
|
||||||
*/
|
*/
|
||||||
flags = PO_NL;
|
po_exp = false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (Flag(FPOSIX) ||
|
if (Flag(FPOSIX) ||
|
||||||
@ -309,14 +307,14 @@ c_print(const char **wp)
|
|||||||
Flag(FAS_BUILTIN)) {
|
Flag(FAS_BUILTIN)) {
|
||||||
/* Debian Policy 10.4 compliant "echo" builtin */
|
/* Debian Policy 10.4 compliant "echo" builtin */
|
||||||
if (*wp && !strcmp(*wp, "-n")) {
|
if (*wp && !strcmp(*wp, "-n")) {
|
||||||
/* we recognise "-n" only as the first arg */
|
/* recognise "-n" only as the first arg */
|
||||||
flags = 0;
|
po_nl = false;
|
||||||
wp++;
|
++wp;
|
||||||
} else
|
}
|
||||||
/* otherwise, we print everything as-is */
|
/* print everything as-is */
|
||||||
flags = PO_NL;
|
po_exp = false;
|
||||||
} else {
|
} else {
|
||||||
int nflags = flags;
|
bool new_exp = po_exp, new_nl = po_nl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a compromise between sysV and BSD echo commands:
|
* a compromise between sysV and BSD echo commands:
|
||||||
@ -329,62 +327,65 @@ c_print(const char **wp)
|
|||||||
* quences are enabled by default.
|
* quences are enabled by default.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
while ((s = *wp) && *s == '-' && s[1]) {
|
print_tradparse_arg:
|
||||||
while (*++s)
|
if ((s = *wp) && *s++ == '-' && *s) {
|
||||||
if (*s == 'n')
|
print_tradparse_ch:
|
||||||
nflags &= ~PO_NL;
|
switch ((c = *s++)) {
|
||||||
else if (*s == 'e')
|
case 'E':
|
||||||
nflags |= PO_EXPAND;
|
new_exp = false;
|
||||||
else if (*s == 'E')
|
goto print_tradparse_ch;
|
||||||
nflags &= ~PO_EXPAND;
|
case 'e':
|
||||||
else
|
new_exp = true;
|
||||||
/*
|
goto print_tradparse_ch;
|
||||||
* bad option: don't use
|
case 'n':
|
||||||
* nflags, print argument
|
new_nl = false;
|
||||||
*/
|
goto print_tradparse_ch;
|
||||||
break;
|
case '\0':
|
||||||
|
po_exp = new_exp;
|
||||||
if (*s)
|
po_nl = new_nl;
|
||||||
break;
|
++wp;
|
||||||
wp++;
|
goto print_tradparse_arg;
|
||||||
flags = nflags;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int optc;
|
/* "print" builtin */
|
||||||
const char *opts = "Rnprsu,";
|
const char *opts = "npRrsu,";
|
||||||
|
const char *emsg;
|
||||||
|
/* print a "--" argument */
|
||||||
|
bool po_pminusminus = false;
|
||||||
|
|
||||||
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
|
while ((c = ksh_getopt(wp, &builtin_opt, opts)) != -1)
|
||||||
switch (optc) {
|
switch (c) {
|
||||||
case 'R':
|
|
||||||
/* fake BSD echo command */
|
|
||||||
flags |= PO_PMINUSMINUS;
|
|
||||||
flags &= ~PO_EXPAND;
|
|
||||||
opts = "ne";
|
|
||||||
break;
|
|
||||||
case 'e':
|
case 'e':
|
||||||
flags |= PO_EXPAND;
|
po_exp = true;
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
flags &= ~PO_NL;
|
po_nl = false;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
|
if ((fd = coproc_getfd(W_OK, &emsg)) < 0) {
|
||||||
bi_errorf("%s: %s", "-p", emsg);
|
bi_errorf("-p: %s", emsg);
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'R':
|
||||||
|
/* fake BSD echo command */
|
||||||
|
po_pminusminus = true;
|
||||||
|
po_exp = false;
|
||||||
|
opts = "en";
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
flags &= ~PO_EXPAND;
|
po_exp = false;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
flags |= PO_HIST;
|
po_hist = true;
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
if (!*(s = builtin_opt.optarg))
|
if (!*(s = builtin_opt.optarg))
|
||||||
fd = 0;
|
fd = 0;
|
||||||
else if ((fd = check_fd(s, W_OK, &emsg)) < 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);
|
return (1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -393,22 +394,23 @@ c_print(const char **wp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(builtin_opt.info & GI_MINUSMINUS)) {
|
if (!(builtin_opt.info & GI_MINUSMINUS)) {
|
||||||
/* treat a lone - like -- */
|
/* treat a lone "-" like "--" */
|
||||||
if (wp[builtin_opt.optind] &&
|
if (wp[builtin_opt.optind] &&
|
||||||
ksh_isdash(wp[builtin_opt.optind]))
|
ksh_isdash(wp[builtin_opt.optind]))
|
||||||
builtin_opt.optind++;
|
builtin_opt.optind++;
|
||||||
} else if (flags & PO_PMINUSMINUS)
|
} else if (po_pminusminus)
|
||||||
builtin_opt.optind--;
|
builtin_opt.optind--;
|
||||||
wp += builtin_opt.optind;
|
wp += builtin_opt.optind;
|
||||||
}
|
}
|
||||||
|
|
||||||
Xinit(xs, xp, 128, ATEMP);
|
Xinit(xs, xp, 128, ATEMP);
|
||||||
|
|
||||||
while (*wp != NULL) {
|
if (*wp != NULL) {
|
||||||
|
print_read_arg:
|
||||||
s = *wp;
|
s = *wp;
|
||||||
while ((c = *s++) != '\0') {
|
while ((c = *s++) != '\0') {
|
||||||
Xcheck(xs, xp);
|
Xcheck(xs, xp);
|
||||||
if ((flags & PO_EXPAND) && c == '\\') {
|
if (po_exp && c == '\\') {
|
||||||
s_ptr = s;
|
s_ptr = s;
|
||||||
c = unbksl(false, s_get, s_put);
|
c = unbksl(false, s_get, s_put);
|
||||||
s = s_ptr;
|
s = s_ptr;
|
||||||
@ -416,11 +418,11 @@ c_print(const char **wp)
|
|||||||
/* rejected by generic function */
|
/* rejected by generic function */
|
||||||
switch ((c = *s++)) {
|
switch ((c = *s++)) {
|
||||||
case 'c':
|
case 'c':
|
||||||
flags &= ~PO_NL;
|
po_nl = false;
|
||||||
/* AT&T brain damage */
|
/* AT&T brain damage */
|
||||||
continue;
|
continue;
|
||||||
case '\0':
|
case '\0':
|
||||||
s--;
|
--s;
|
||||||
c = '\\';
|
c = '\\';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -440,18 +442,22 @@ c_print(const char **wp)
|
|||||||
}
|
}
|
||||||
Xput(xs, xp, c);
|
Xput(xs, xp, c);
|
||||||
}
|
}
|
||||||
if (*++wp != NULL)
|
if (*++wp != NULL) {
|
||||||
Xput(xs, xp, ' ');
|
Xput(xs, xp, ' ');
|
||||||
|
goto print_read_arg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (flags & PO_NL)
|
if (po_nl)
|
||||||
Xput(xs, xp, '\n');
|
Xput(xs, xp, '\n');
|
||||||
|
|
||||||
if (flags & PO_HIST) {
|
c = 0;
|
||||||
|
if (po_hist) {
|
||||||
Xput(xs, xp, '\0');
|
Xput(xs, xp, '\0');
|
||||||
histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
|
histsave(&source->line, Xstring(xs, xp), HIST_STORE, false);
|
||||||
Xfree(xs, xp);
|
Xfree(xs, xp);
|
||||||
} else {
|
} else {
|
||||||
int len = Xlength(xs, xp);
|
size_t len = Xlength(xs, xp);
|
||||||
|
bool po_coproc = false;
|
||||||
int opipe = 0;
|
int opipe = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -461,30 +467,36 @@ c_print(const char **wp)
|
|||||||
* not enough).
|
* not enough).
|
||||||
*/
|
*/
|
||||||
if (coproc.write >= 0 && coproc.write == fd) {
|
if (coproc.write >= 0 && coproc.write == fd) {
|
||||||
flags |= PO_COPROC;
|
po_coproc = true;
|
||||||
opipe = block_pipe();
|
opipe = block_pipe();
|
||||||
}
|
}
|
||||||
for (s = Xstring(xs, xp); len > 0; ) {
|
|
||||||
if ((c = write(fd, s, len)) < 0) {
|
s = Xstring(xs, xp);
|
||||||
if (flags & PO_COPROC)
|
while (len > 0) {
|
||||||
restore_pipe(opipe);
|
ssize_t nwritten;
|
||||||
|
|
||||||
|
if ((nwritten = write(fd, s, len)) < 0) {
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
/* allow user to ^C out */
|
if (po_coproc)
|
||||||
|
restore_pipe(opipe);
|
||||||
|
/* give the user a chance to ^C out */
|
||||||
intrcheck();
|
intrcheck();
|
||||||
if (flags & PO_COPROC)
|
/* interrupted, try again */
|
||||||
|
if (po_coproc)
|
||||||
opipe = block_pipe();
|
opipe = block_pipe();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return (1);
|
c = 1;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
s += c;
|
s += nwritten;
|
||||||
len -= c;
|
len -= nwritten;
|
||||||
}
|
}
|
||||||
if (flags & PO_COPROC)
|
if (po_coproc)
|
||||||
restore_pipe(opipe);
|
restore_pipe(opipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1851,13 +1863,15 @@ c_read(const char **wp)
|
|||||||
enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
|
enum { LINES, BYTES, UPTO, READALL } readmode = LINES;
|
||||||
char delim = '\n';
|
char delim = '\n';
|
||||||
size_t bytesleft = 128, bytesread;
|
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;
|
char *cp, *allocd = NULL, *xp;
|
||||||
const char *ccp;
|
const char *ccp;
|
||||||
XString xs;
|
XString xs;
|
||||||
size_t xsave = 0;
|
size_t xsave = 0;
|
||||||
mksh_ttyst tios;
|
mksh_ttyst tios;
|
||||||
bool restore_tios = false;
|
bool restore_tios = false;
|
||||||
|
/* to catch read -aN2 foo[i] */
|
||||||
|
bool subarray = false;
|
||||||
#if HAVE_SELECT
|
#if HAVE_SELECT
|
||||||
bool hastimeout = false;
|
bool hastimeout = false;
|
||||||
struct timeval tv, tvlim;
|
struct timeval tv, tvlim;
|
||||||
@ -2102,6 +2116,7 @@ c_read(const char **wp)
|
|||||||
XinitN(xs, 128, ATEMP);
|
XinitN(xs, 128, ATEMP);
|
||||||
if (intoarray) {
|
if (intoarray) {
|
||||||
vp = global(*wp);
|
vp = global(*wp);
|
||||||
|
subarray = last_lookup_was_array;
|
||||||
if (vp->flag & RDONLY) {
|
if (vp->flag & RDONLY) {
|
||||||
c_read_splitro:
|
c_read_splitro:
|
||||||
bi_errorf("read-only: %s", *wp);
|
bi_errorf("read-only: %s", *wp);
|
||||||
@ -2110,10 +2125,10 @@ c_read(const char **wp)
|
|||||||
afree(cp, ATEMP);
|
afree(cp, ATEMP);
|
||||||
goto c_read_out;
|
goto c_read_out;
|
||||||
}
|
}
|
||||||
/* exporting an array is currently pointless */
|
|
||||||
unset(vp, 1);
|
|
||||||
/* counter for array index */
|
/* counter for array index */
|
||||||
c = 0;
|
c = subarray ? arrayindex(vp) : 0;
|
||||||
|
/* exporting an array is currently pointless */
|
||||||
|
unset(vp, subarray ? 0 : 1);
|
||||||
}
|
}
|
||||||
if (!aschars) {
|
if (!aschars) {
|
||||||
/* skip initial IFS whitespace */
|
/* skip initial IFS whitespace */
|
||||||
@ -2215,7 +2230,18 @@ c_read(const char **wp)
|
|||||||
c_read_gotword:
|
c_read_gotword:
|
||||||
Xput(xs, xp, '\0');
|
Xput(xs, xp, '\0');
|
||||||
if (intoarray) {
|
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 {
|
} else {
|
||||||
vq = global(*wp);
|
vq = global(*wp);
|
||||||
/* must be checked before exporting */
|
/* must be checked before exporting */
|
||||||
@ -2355,16 +2381,14 @@ int
|
|||||||
c_exitreturn(const char **wp)
|
c_exitreturn(const char **wp)
|
||||||
{
|
{
|
||||||
int n, how = LEXIT;
|
int n, how = LEXIT;
|
||||||
const char *arg;
|
|
||||||
|
|
||||||
if (ksh_getopt(wp, &builtin_opt, null) == '?')
|
if (wp[1]) {
|
||||||
goto c_exitreturn_err;
|
if (wp[2])
|
||||||
arg = wp[builtin_opt.optind];
|
goto c_exitreturn_err;
|
||||||
|
exstat = bi_getn(wp[1], &n) ? (n & 0xFF) : 1;
|
||||||
if (arg)
|
} else if (trap_exstat != -1)
|
||||||
exstat = bi_getn(arg, &n) ? (n & 0xFF) : 1;
|
|
||||||
else if (trap_exstat != -1)
|
|
||||||
exstat = trap_exstat;
|
exstat = trap_exstat;
|
||||||
|
|
||||||
if (wp[0][0] == 'r') {
|
if (wp[0][0] == 'r') {
|
||||||
/* return */
|
/* return */
|
||||||
struct env *ep;
|
struct env *ep;
|
||||||
@ -2385,12 +2409,13 @@ c_exitreturn(const char **wp)
|
|||||||
how = LSHELL;
|
how = LSHELL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get rid of any i/o redirections */
|
/* get rid of any I/O redirections */
|
||||||
quitenv(NULL);
|
quitenv(NULL);
|
||||||
unwind(how);
|
unwind(how);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
|
||||||
c_exitreturn_err:
|
c_exitreturn_err:
|
||||||
|
bi_errorf("too many arguments");
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3664,10 +3689,11 @@ c_realpath(const char **wp)
|
|||||||
int
|
int
|
||||||
c_cat(const char **wp)
|
c_cat(const char **wp)
|
||||||
{
|
{
|
||||||
int fd = STDIN_FILENO, rv, eno;
|
int fd = STDIN_FILENO, rv;
|
||||||
ssize_t n, w;
|
ssize_t n, w;
|
||||||
const char *fn = "<stdin>";
|
const char *fn = "<stdin>";
|
||||||
char *buf, *cp;
|
char *buf, *cp;
|
||||||
|
int opipe = 0;
|
||||||
#define MKSH_CAT_BUFSIZ 4096
|
#define MKSH_CAT_BUFSIZ 4096
|
||||||
|
|
||||||
/* parse options: POSIX demands we support "-u" as no-op */
|
/* parse options: POSIX demands we support "-u" as no-op */
|
||||||
@ -3689,54 +3715,64 @@ c_cat(const char **wp)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* catch SIGPIPE */
|
||||||
|
opipe = block_pipe();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (*wp) {
|
if (*wp) {
|
||||||
fn = *wp++;
|
fn = *wp++;
|
||||||
if (ksh_isdash(fn))
|
if (ksh_isdash(fn))
|
||||||
fd = STDIN_FILENO;
|
fd = STDIN_FILENO;
|
||||||
else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
|
else if ((fd = binopen2(fn, O_RDONLY)) < 0) {
|
||||||
eno = errno;
|
bi_errorf("%s: %s", fn, cstrerror(errno));
|
||||||
bi_errorf("%s: %s", fn, cstrerror(eno));
|
|
||||||
rv = 1;
|
rv = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (/* CONSTCOND */ 1) {
|
while (/* CONSTCOND */ 1) {
|
||||||
n = blocking_read(fd, (cp = buf), MKSH_CAT_BUFSIZ);
|
if ((n = blocking_read(fd, (cp = buf),
|
||||||
eno = errno;
|
MKSH_CAT_BUFSIZ)) == -1) {
|
||||||
/* give the user a chance to ^C out */
|
if (errno == EINTR) {
|
||||||
intrcheck();
|
restore_pipe(opipe);
|
||||||
if (n == -1) {
|
/* give the user a chance to ^C out */
|
||||||
if (eno == EINTR) {
|
intrcheck();
|
||||||
/* interrupted, try again */
|
/* interrupted, try again */
|
||||||
|
opipe = block_pipe();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* an error occured during reading */
|
/* an error occured during reading */
|
||||||
bi_errorf("%s: %s", fn, cstrerror(eno));
|
bi_errorf("%s: %s", fn, cstrerror(errno));
|
||||||
rv = 1;
|
rv = 1;
|
||||||
break;
|
break;
|
||||||
} else if (n == 0)
|
} else if (n == 0)
|
||||||
/* end of file reached */
|
/* end of file reached */
|
||||||
break;
|
break;
|
||||||
while (n) {
|
while (n) {
|
||||||
w = write(STDOUT_FILENO, cp, n);
|
if ((w = write(STDOUT_FILENO, cp, n)) != -1) {
|
||||||
eno = errno;
|
n -= w;
|
||||||
/* give the user a chance to ^C out */
|
cp += w;
|
||||||
intrcheck();
|
continue;
|
||||||
if (w == -1) {
|
}
|
||||||
if (eno == EINTR)
|
if (errno == EINTR) {
|
||||||
/* interrupted, try again */
|
restore_pipe(opipe);
|
||||||
continue;
|
/* 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 */
|
/* an error occured during writing */
|
||||||
bi_errorf("%s: %s", "<stdout>",
|
bi_errorf("%s: %s", "<stdout>",
|
||||||
cstrerror(eno));
|
cstrerror(errno));
|
||||||
rv = 1;
|
rv = 1;
|
||||||
if (fd != STDIN_FILENO)
|
|
||||||
close(fd);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
n -= w;
|
if (fd != STDIN_FILENO)
|
||||||
cp += w;
|
close(fd);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fd != STDIN_FILENO)
|
if (fd != STDIN_FILENO)
|
||||||
@ -3744,6 +3780,7 @@ c_cat(const char **wp)
|
|||||||
} while (*wp);
|
} while (*wp);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
restore_pipe(opipe);
|
||||||
free_osfunc(buf);
|
free_osfunc(buf);
|
||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
* 2011, 2012, 2014, 2015
|
* 2011, 2012, 2014, 2015, 2016
|
||||||
* mirabilos <m@mirbsd.org>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -27,7 +27,7 @@
|
|||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#endif
|
#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];
|
Trap sigtraps[ksh_NSIG + 1];
|
||||||
static struct sigaction Sigact_ign;
|
static struct sigaction Sigact_ign;
|
||||||
@ -1213,7 +1213,7 @@ fatal_trap_check(void)
|
|||||||
do {
|
do {
|
||||||
if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
|
if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL)))
|
||||||
/* return value is used as an exit code */
|
/* return value is used as an exit code */
|
||||||
return (128 + p->signal);
|
return (ksh_sigmask(p->signal));
|
||||||
++p;
|
++p;
|
||||||
} while (--i);
|
} while (--i);
|
||||||
return (0);
|
return (0);
|
||||||
|
11
jobs.c
11
jobs.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
|
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011,
|
||||||
* 2012, 2013, 2014, 2015
|
* 2012, 2013, 2014, 2015, 2016
|
||||||
* mirabilos <m@mirbsd.org>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
#if HAVE_KILLPG
|
||||||
#define mksh_killpg killpg
|
#define mksh_killpg killpg
|
||||||
@ -215,14 +215,11 @@ j_init(void)
|
|||||||
static int
|
static int
|
||||||
proc_errorlevel(Proc *p)
|
proc_errorlevel(Proc *p)
|
||||||
{
|
{
|
||||||
int termsig;
|
|
||||||
|
|
||||||
switch (p->state) {
|
switch (p->state) {
|
||||||
case PEXITED:
|
case PEXITED:
|
||||||
return ((WEXITSTATUS(p->status)) & 255);
|
return ((WEXITSTATUS(p->status)) & 255);
|
||||||
case PSIGNALLED:
|
case PSIGNALLED:
|
||||||
termsig = WTERMSIG(p->status);
|
return (ksh_sigmask(WTERMSIG(p->status)));
|
||||||
return ((termsig < 1 || termsig > 127) ? 255 : 128 + termsig);
|
|
||||||
default:
|
default:
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -756,7 +753,7 @@ waitfor(const char *cp, int *sigp)
|
|||||||
|
|
||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
/* we were interrupted */
|
/* we were interrupted */
|
||||||
*sigp = 128 + -rv;
|
*sigp = ksh_sigmask(-rv);
|
||||||
|
|
||||||
return (rv);
|
return (rv);
|
||||||
}
|
}
|
||||||
|
45
lex.c
45
lex.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
* 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>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
* states while lexing word
|
||||||
@ -94,8 +94,7 @@ static void ungetsc_i(int);
|
|||||||
static int getsc_uu(void);
|
static int getsc_uu(void);
|
||||||
static void getsc_line(Source *);
|
static void getsc_line(Source *);
|
||||||
static int getsc_bn(void);
|
static int getsc_bn(void);
|
||||||
static int s_get(void);
|
static int getsc_i(void);
|
||||||
static void s_put(int);
|
|
||||||
static char *get_brace_var(XString *, char *);
|
static char *get_brace_var(XString *, char *);
|
||||||
static bool arraysub(char **);
|
static bool arraysub(char **);
|
||||||
static void gethere(void);
|
static void gethere(void);
|
||||||
@ -112,7 +111,7 @@ static int ignore_backslash_newline;
|
|||||||
#define o_getsc_u() ((*source->str != '\0') ? *source->str++ : getsc_uu())
|
#define o_getsc_u() ((*source->str != '\0') ? *source->str++ : getsc_uu())
|
||||||
|
|
||||||
/* retrace helper */
|
/* retrace helper */
|
||||||
#define o_getsc_r(carg) { \
|
#define o_getsc_r(carg) \
|
||||||
int cev = (carg); \
|
int cev = (carg); \
|
||||||
struct sretrace_info *rp = retrace_info; \
|
struct sretrace_info *rp = retrace_info; \
|
||||||
\
|
\
|
||||||
@ -122,17 +121,17 @@ static int ignore_backslash_newline;
|
|||||||
rp = rp->next; \
|
rp = rp->next; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
return (cev); \
|
return (cev);
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
|
|
||||||
static int getsc(void);
|
|
||||||
|
|
||||||
|
/* callback */
|
||||||
static int
|
static int
|
||||||
getsc(void)
|
getsc_i(void)
|
||||||
{
|
{
|
||||||
o_getsc_r(o_getsc());
|
o_getsc_r(o_getsc());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
|
||||||
|
#define getsc getsc_i
|
||||||
#else
|
#else
|
||||||
static int getsc_r(int);
|
static int getsc_r(int);
|
||||||
|
|
||||||
@ -269,7 +268,7 @@ yylex(int cf)
|
|||||||
}
|
}
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case SBASE:
|
case SBASE:
|
||||||
if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
|
if (c == '[' && (cf & CMDASN)) {
|
||||||
/* temporary */
|
/* temporary */
|
||||||
*wp = EOS;
|
*wp = EOS;
|
||||||
if (is_wdvarname(Xstring(ws, wp), false)) {
|
if (is_wdvarname(Xstring(ws, wp), false)) {
|
||||||
@ -550,8 +549,10 @@ yylex(int cf)
|
|||||||
* undefined results occur.”).
|
* undefined results occur.”).
|
||||||
*/
|
*/
|
||||||
statep->ls_bool = false;
|
statep->ls_bool = false;
|
||||||
|
#ifdef austingroupbugs1015_is_still_not_resolved
|
||||||
if (Flag(FPOSIX))
|
if (Flag(FPOSIX))
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
s2 = statep;
|
s2 = statep;
|
||||||
base = state_info.base;
|
base = state_info.base;
|
||||||
while (/* CONSTCOND */ 1) {
|
while (/* CONSTCOND */ 1) {
|
||||||
@ -588,8 +589,8 @@ yylex(int cf)
|
|||||||
*wp++ = CQUOTE;
|
*wp++ = CQUOTE;
|
||||||
ignore_backslash_newline--;
|
ignore_backslash_newline--;
|
||||||
} else if (c == '\\') {
|
} else if (c == '\\') {
|
||||||
if ((c2 = unbksl(true, s_get, s_put)) == -1)
|
if ((c2 = unbksl(true, getsc_i, ungetsc)) == -1)
|
||||||
c2 = s_get();
|
c2 = getsc();
|
||||||
if (c2 == 0)
|
if (c2 == 0)
|
||||||
statep->ls_bool = true;
|
statep->ls_bool = true;
|
||||||
if (!statep->ls_bool) {
|
if (!statep->ls_bool) {
|
||||||
@ -777,6 +778,7 @@ yylex(int cf)
|
|||||||
Source *s;
|
Source *s;
|
||||||
|
|
||||||
ungetsc(c2);
|
ungetsc(c2);
|
||||||
|
ungetsc(c);
|
||||||
/*
|
/*
|
||||||
* mismatched parenthesis -
|
* mismatched parenthesis -
|
||||||
* assume we were really
|
* assume we were really
|
||||||
@ -789,6 +791,7 @@ yylex(int cf)
|
|||||||
s->start = s->str = s->u.freeme = dp;
|
s->start = s->str = s->u.freeme = dp;
|
||||||
s->next = source;
|
s->next = source;
|
||||||
source = s;
|
source = s;
|
||||||
|
ungetsc('('/*)*/);
|
||||||
return ('('/*)*/);
|
return ('('/*)*/);
|
||||||
}
|
}
|
||||||
} else if (c == '(')
|
} else if (c == '(')
|
||||||
@ -1088,7 +1091,7 @@ yylex(int cf)
|
|||||||
}
|
}
|
||||||
} else if (cf & ALIAS) {
|
} else if (cf & ALIAS) {
|
||||||
/* retain typeset et al. even when quoted */
|
/* 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));
|
strlcpy(ident, dp, sizeof(ident));
|
||||||
afree(dp, ATEMP);
|
afree(dp, ATEMP);
|
||||||
}
|
}
|
||||||
@ -1783,15 +1786,3 @@ pop_state_i(State_info *si, Lex_state *old_end)
|
|||||||
|
|
||||||
return (si->base + STATE_BSIZE - 1);
|
return (si->base + STATE_BSIZE - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
s_get(void)
|
|
||||||
{
|
|
||||||
return (getsc());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
s_put(int c)
|
|
||||||
{
|
|
||||||
ungetsc(c);
|
|
||||||
}
|
|
||||||
|
56
mksh.1
56
mksh.1
@ -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 $
|
.\" $OpenBSD: ksh.1,v 1.160 2015/07/04 13:27:04 feinerer Exp $
|
||||||
.\"-
|
.\"-
|
||||||
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
.\" 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>
|
.\" mirabilos <m@mirbsd.org>
|
||||||
.\"
|
.\"
|
||||||
.\" Provided that these terms and disclaimer and all copyright notices
|
.\" 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
|
.\" with -mandoc, it might implement .Mx itself, but we want to
|
||||||
.\" use our own definition. And .Dd must come *first*, always.
|
.\" 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.
|
.\" 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
|
Its command language is a superset of the
|
||||||
.Xr sh C
|
.Xr sh C
|
||||||
shell language and largely compatible to the original Korn shell.
|
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?
|
.Ss I'm an Android user, so what's mksh?
|
||||||
.Nm mksh
|
.Nm mksh
|
||||||
is a
|
is a
|
||||||
@ -434,7 +439,7 @@ Whitespace and meta-characters can be quoted individually using a backslash
|
|||||||
or in groups using double
|
or in groups using double
|
||||||
.Pq Sq \&"
|
.Pq Sq \&"
|
||||||
or single
|
or single
|
||||||
.Pq Sq \*(aq
|
.Pq Dq \*(aq
|
||||||
quotes.
|
quotes.
|
||||||
Note that the following characters are also treated specially by the
|
Note that the following characters are also treated specially by the
|
||||||
shell and must be quoted if they are to represent themselves:
|
shell and must be quoted if they are to represent themselves:
|
||||||
@ -988,7 +993,7 @@ case both the
|
|||||||
.Ql \e
|
.Ql \e
|
||||||
and the newline are stripped.
|
and the newline are stripped.
|
||||||
Second, a single quote
|
Second, a single quote
|
||||||
.Pq Sq \*(aq
|
.Pq Dq \*(aq
|
||||||
quotes everything up to the next single quote (this may span lines).
|
quotes everything up to the next single quote (this may span lines).
|
||||||
Third, a double quote
|
Third, a double quote
|
||||||
.Pq Sq \&"
|
.Pq Sq \&"
|
||||||
@ -1001,8 +1006,8 @@ up to the next unquoted double quote.
|
|||||||
.Ql $
|
.Ql $
|
||||||
and
|
and
|
||||||
.Ql \`
|
.Ql \`
|
||||||
inside double quotes have their usual meaning (i.e. parameter, command, or
|
inside double quotes have their usual meaning (i.e. parameter, arithmetic,
|
||||||
arithmetic substitution) except no field splitting is carried out on the
|
or command substitution) except no field splitting is carried out on the
|
||||||
results of double-quoted substitutions.
|
results of double-quoted substitutions.
|
||||||
If a
|
If a
|
||||||
.Ql \e
|
.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.
|
the expanded result is treated as any other single-quoted string.
|
||||||
If a double-quoted string is preceded by an unquoted
|
If a double-quoted string is preceded by an unquoted
|
||||||
.Ql $ ,
|
.Ql $ ,
|
||||||
the latter is ignored.
|
the
|
||||||
|
.Ql $
|
||||||
|
is simply ignored.
|
||||||
.Ss Backslash expansion
|
.Ss Backslash expansion
|
||||||
In places where backslashes are expanded, certain C and
|
In places where backslashes are expanded, certain C and
|
||||||
.At
|
.At
|
||||||
@ -1286,6 +1293,8 @@ command which is run in a subshell.
|
|||||||
For
|
For
|
||||||
.Pf $( Ns Ar command Ns \&)
|
.Pf $( Ns Ar command Ns \&)
|
||||||
and
|
and
|
||||||
|
.Pf ${\*(Ba\& Ns Ar command Ns \&;}
|
||||||
|
and
|
||||||
.Pf ${\ \& Ar command Ns \&;}
|
.Pf ${\ \& Ar command Ns \&;}
|
||||||
substitutions, normal quoting rules are used when
|
substitutions, normal quoting rules are used when
|
||||||
.Ar command
|
.Ar command
|
||||||
@ -1296,6 +1305,8 @@ form, a
|
|||||||
followed by any of
|
followed by any of
|
||||||
.Ql $ ,
|
.Ql $ ,
|
||||||
.Ql \` ,
|
.Ql \` ,
|
||||||
|
.Ql \&"
|
||||||
|
.Pq currently, and violating Tn POSIX ,
|
||||||
or
|
or
|
||||||
.Ql \e
|
.Ql \e
|
||||||
is stripped (a
|
is stripped (a
|
||||||
@ -1744,7 +1755,7 @@ command below for a list of options).
|
|||||||
The exit status of the last non-asynchronous command executed.
|
The exit status of the last non-asynchronous command executed.
|
||||||
If the last command was killed by a signal,
|
If the last command was killed by a signal,
|
||||||
.Ic $?\&
|
.Ic $?\&
|
||||||
is set to 128 plus the signal number.
|
is set to 128 plus the signal number, but at most 255.
|
||||||
.It Ev 0
|
.It Ev 0
|
||||||
The name of the shell, determined as follows:
|
The name of the shell, determined as follows:
|
||||||
the first argument to
|
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
|
Once the type of command has been determined, any command-line parameter
|
||||||
assignments are performed and exported for the duration of the command.
|
assignments are performed and exported for the duration of the command.
|
||||||
.Pp
|
.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
|
.Pp
|
||||||
.Bl -tag -width false -compact
|
.Bl -tag -width false -compact
|
||||||
.It Ic \&. Ar file Op Ar arg ...
|
.It Ic \&. Ar file Op Ar arg ...
|
||||||
@ -3815,7 +3827,8 @@ Store the result without word splitting into the parameter
|
|||||||
.Ev REPLY )
|
.Ev REPLY )
|
||||||
as array of characters (wide characters if the
|
as array of characters (wide characters if the
|
||||||
.Ic utf8\-mode
|
.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
|
.It Fl d Ar x
|
||||||
Use the first byte of
|
Use the first byte of
|
||||||
.Ar x ,
|
.Ar x ,
|
||||||
@ -4138,6 +4151,12 @@ or
|
|||||||
case-insensitively; for direct builtin calls depending on the
|
case-insensitively; for direct builtin calls depending on the
|
||||||
aforementioned environment variables; or for stdin or scripts,
|
aforementioned environment variables; or for stdin or scripts,
|
||||||
if the input begins with a UTF-8 Byte Order Mark.
|
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
|
.It Fl u \*(Ba Fl o Ic nounset
|
||||||
Referencing of an unset parameter, other than
|
Referencing of an unset parameter, other than
|
||||||
.Dq $@
|
.Dq $@
|
||||||
@ -6552,6 +6571,7 @@ case ${KSH_VERSION:\-} in
|
|||||||
esac ;;
|
esac ;;
|
||||||
esac
|
esac
|
||||||
.Ed
|
.Ed
|
||||||
|
In near future, (Unicode) locale tracking will be implemented though.
|
||||||
.Sh BUGS
|
.Sh BUGS
|
||||||
Suspending (using \*(haZ) pipelines like the one below will only suspend
|
Suspending (using \*(haZ) pipelines like the one below will only suspend
|
||||||
the currently running part of the pipeline; in this example,
|
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
|
for the in-memory portion of the history is slow, should use
|
||||||
.Xr memmove 3 .
|
.Xr memmove 3 .
|
||||||
.Pp
|
.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
|
This document attempts to describe
|
||||||
.Nm mksh\ R52
|
.Nm mksh\ R52b
|
||||||
and up,
|
and up,
|
||||||
.\" with vendor patches from insert-your-name-here,
|
.\" with vendor patches from insert-your-name-here,
|
||||||
compiled without any options impacting functionality, such as
|
compiled without any options impacting functionality, such as
|
||||||
|
19
sh.h
19
sh.h
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
* Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
* 2011, 2012, 2013, 2014, 2015
|
* 2011, 2012, 2013, 2014, 2015, 2016
|
||||||
* mirabilos <m@mirbsd.org>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -175,9 +175,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EXTERN
|
#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
|
#endif
|
||||||
#define MKSH_VERSION "R52 2015/12/12"
|
#define MKSH_VERSION "R52 2016/01/20"
|
||||||
|
|
||||||
/* arithmetic types: C implementation */
|
/* arithmetic types: C implementation */
|
||||||
#if !HAVE_CAN_INTTYPES
|
#if !HAVE_CAN_INTTYPES
|
||||||
@ -379,6 +379,8 @@ struct rusage {
|
|||||||
#define ksh_NSIG 64
|
#define ksh_NSIG 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ksh_sigmask(sig) (((sig) < 1 || (sig) > 127) ? 255 : 128 + (sig))
|
||||||
|
|
||||||
|
|
||||||
/* OS-dependent additions (functions, variables, by OS) */
|
/* OS-dependent additions (functions, variables, by OS) */
|
||||||
|
|
||||||
@ -862,6 +864,8 @@ EXTERN const char Tgbuiltin[] E_INIT("=builtin");
|
|||||||
#define Tbuiltin (Tgbuiltin + 1) /* "builtin" */
|
#define Tbuiltin (Tgbuiltin + 1) /* "builtin" */
|
||||||
EXTERN const char T_function[] E_INIT(" function");
|
EXTERN const char T_function[] E_INIT(" function");
|
||||||
#define Tfunction (T_function + 1) /* "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");
|
EXTERN const char TC_LEX1[] E_INIT("|&;<>() \t\n");
|
||||||
#define TC_IFSWS (TC_LEX1 + 7) /* space tab newline */
|
#define TC_IFSWS (TC_LEX1 + 7) /* space tab newline */
|
||||||
|
|
||||||
@ -1186,6 +1190,8 @@ struct tbl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
EXTERN struct tbl vtemp;
|
EXTERN struct tbl vtemp;
|
||||||
|
/* set by global() and local() */
|
||||||
|
EXTERN bool last_lookup_was_array;
|
||||||
|
|
||||||
/* common flag bits */
|
/* common flag bits */
|
||||||
#define ALLOC BIT(0) /* val.s has been allocated */
|
#define ALLOC BIT(0) /* val.s has been allocated */
|
||||||
@ -1628,13 +1634,12 @@ typedef union {
|
|||||||
#define ALIAS BIT(2) /* recognise alias */
|
#define ALIAS BIT(2) /* recognise alias */
|
||||||
#define KEYWORD BIT(3) /* recognise keywords */
|
#define KEYWORD BIT(3) /* recognise keywords */
|
||||||
#define LETEXPR BIT(4) /* get expression inside (( )) */
|
#define LETEXPR BIT(4) /* get expression inside (( )) */
|
||||||
#define VARASN BIT(5) /* check for var=word */
|
#define CMDASN BIT(5) /* parse x[1 & 2] as one word, for typeset */
|
||||||
#define ARRAYVAR BIT(6) /* parse x[1 & 2] as one word */
|
#define HEREDOC BIT(6) /* parsing a here document body */
|
||||||
#define ESACONLY BIT(7) /* only accept esac keyword */
|
#define ESACONLY BIT(7) /* only accept esac keyword */
|
||||||
#define CMDWORD BIT(8) /* parsing simple command (alias related) */
|
#define CMDWORD BIT(8) /* parsing simple command (alias related) */
|
||||||
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
|
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
|
||||||
#define LQCHAR BIT(10) /* source string contains QCHAR */
|
#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 */
|
#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)
|
ssize_t shf_vfprintf(struct shf *, const char *, va_list)
|
||||||
MKSH_A_FORMAT(__printf__, 2, 0);
|
MKSH_A_FORMAT(__printf__, 2, 0);
|
||||||
/* syn.c */
|
/* syn.c */
|
||||||
int assign_command(const char *);
|
int assign_command(const char *, bool);
|
||||||
void initkeywords(void);
|
void initkeywords(void);
|
||||||
struct op *compile(Source *, bool);
|
struct op *compile(Source *, bool);
|
||||||
bool parse_usec(const char *, struct timeval *);
|
bool parse_usec(const char *, struct timeval *);
|
||||||
|
4
shf.c
4
shf.c
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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() */
|
/* flags to shf_emptybuf() */
|
||||||
#define EB_READSW 0x01 /* about to switch to reading */
|
#define EB_READSW 0x01 /* about to switch to reading */
|
||||||
@ -1121,6 +1121,8 @@ cstrerror(int errnum)
|
|||||||
#endif
|
#endif
|
||||||
case EACCES:
|
case EACCES:
|
||||||
return ("Permission denied");
|
return ("Permission denied");
|
||||||
|
case EEXIST:
|
||||||
|
return ("File exists");
|
||||||
case ENOTDIR:
|
case ENOTDIR:
|
||||||
return ("Not a directory");
|
return ("Not a directory");
|
||||||
#ifdef EINVAL
|
#ifdef EINVAL
|
||||||
|
43
syn.c
43
syn.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009,
|
||||||
* 2011, 2012, 2013, 2014, 2015
|
* 2011, 2012, 2013, 2014, 2015, 2016
|
||||||
* mirabilos <m@mirbsd.org>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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 {
|
struct nesting_state {
|
||||||
int start_token; /* token than began nesting (eg, FOR) */
|
int start_token; /* token than began nesting (eg, FOR) */
|
||||||
@ -272,7 +272,6 @@ get_command(int cf)
|
|||||||
int c, iopn = 0, syniocf, lno;
|
int c, iopn = 0, syniocf, lno;
|
||||||
struct ioword *iop, **iops;
|
struct ioword *iop, **iops;
|
||||||
XPtrV args, vars;
|
XPtrV args, vars;
|
||||||
char *tcp;
|
|
||||||
struct nesting_state old_nesting;
|
struct nesting_state old_nesting;
|
||||||
|
|
||||||
/* NUFILE is small enough to leave this addition unchecked */
|
/* NUFILE is small enough to leave this addition unchecked */
|
||||||
@ -281,7 +280,7 @@ get_command(int cf)
|
|||||||
XPinit(vars, 16);
|
XPinit(vars, 16);
|
||||||
|
|
||||||
syniocf = KEYWORD|sALIAS;
|
syniocf = KEYWORD|sALIAS;
|
||||||
switch (c = token(cf|KEYWORD|sALIAS|VARASN)) {
|
switch (c = token(cf|KEYWORD|sALIAS|CMDASN)) {
|
||||||
default:
|
default:
|
||||||
REJECT;
|
REJECT;
|
||||||
afree(iops, ATEMP);
|
afree(iops, ATEMP);
|
||||||
@ -296,9 +295,18 @@ get_command(int cf)
|
|||||||
syniocf &= ~(KEYWORD|sALIAS);
|
syniocf &= ~(KEYWORD|sALIAS);
|
||||||
t = newtp(TCOM);
|
t = newtp(TCOM);
|
||||||
t->lineno = source->line;
|
t->lineno = source->line;
|
||||||
|
goto get_command_begin;
|
||||||
while (/* CONSTCOND */ 1) {
|
while (/* CONSTCOND */ 1) {
|
||||||
cf = (t->u.evalflags ? ARRAYVAR : 0) |
|
bool check_assign_cmd;
|
||||||
(XPsize(args) == 0 ? sALIAS|VARASN : CMDWORD);
|
|
||||||
|
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)) {
|
switch (tpeek(cf)) {
|
||||||
case REDIR:
|
case REDIR:
|
||||||
while ((iop = synio(cf)) != NULL) {
|
while ((iop = synio(cf)) != NULL) {
|
||||||
@ -316,9 +324,12 @@ get_command(int cf)
|
|||||||
* dubious but AT&T ksh acts this way
|
* dubious but AT&T ksh acts this way
|
||||||
*/
|
*/
|
||||||
if (iopn == 0 && XPsize(vars) == 0 &&
|
if (iopn == 0 && XPsize(vars) == 0 &&
|
||||||
XPsize(args) == 0 &&
|
check_assign_cmd) {
|
||||||
assign_command(ident))
|
if (assign_command(ident, false))
|
||||||
t->u.evalflags = DOVACHECK;
|
t->u.evalflags = DOVACHECK;
|
||||||
|
else if (strcmp(ident, Tcommand) != 0)
|
||||||
|
check_assign_cmd = false;
|
||||||
|
}
|
||||||
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
|
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
|
||||||
is_wdvarassign(yylval.cp))
|
is_wdvarassign(yylval.cp))
|
||||||
XPput(vars, yylval.cp);
|
XPput(vars, yylval.cp);
|
||||||
@ -329,6 +340,8 @@ get_command(int cf)
|
|||||||
case '(' /*)*/:
|
case '(' /*)*/:
|
||||||
if (XPsize(args) == 0 && XPsize(vars) == 1 &&
|
if (XPsize(args) == 0 && XPsize(vars) == 1 &&
|
||||||
is_wdvarassign(yylval.cp)) {
|
is_wdvarassign(yylval.cp)) {
|
||||||
|
char *tcp;
|
||||||
|
|
||||||
/* wdarrassign: foo=(bar) */
|
/* wdarrassign: foo=(bar) */
|
||||||
ACCEPT;
|
ACCEPT;
|
||||||
|
|
||||||
@ -400,6 +413,7 @@ get_command(int cf)
|
|||||||
case LWORD:
|
case LWORD:
|
||||||
break;
|
break;
|
||||||
case '(': /*)*/
|
case '(': /*)*/
|
||||||
|
c = '(';
|
||||||
goto Subshell;
|
goto Subshell;
|
||||||
default:
|
default:
|
||||||
syntaxerr(NULL);
|
syntaxerr(NULL);
|
||||||
@ -431,7 +445,7 @@ get_command(int cf)
|
|||||||
case FOR:
|
case FOR:
|
||||||
case SELECT:
|
case SELECT:
|
||||||
t = newtp((c == FOR) ? TFOR : TSELECT);
|
t = newtp((c == FOR) ? TFOR : TSELECT);
|
||||||
musthave(LWORD, ARRAYVAR);
|
musthave(LWORD, CMDASN);
|
||||||
if (!is_wdvarname(yylval.cp, true))
|
if (!is_wdvarname(yylval.cp, true))
|
||||||
yyerror("%s: %s\n", c == FOR ? "for" : Tselect,
|
yyerror("%s: %s\n", c == FOR ? "for" : Tselect,
|
||||||
"bad identifier");
|
"bad identifier");
|
||||||
@ -572,7 +586,7 @@ elsepart(void)
|
|||||||
{
|
{
|
||||||
struct op *t;
|
struct op *t;
|
||||||
|
|
||||||
switch (token(KEYWORD|sALIAS|VARASN)) {
|
switch (token(KEYWORD|sALIAS|CMDASN)) {
|
||||||
case ELSE:
|
case ELSE:
|
||||||
if ((t = c_list(true)) == NULL)
|
if ((t = c_list(true)) == NULL)
|
||||||
syntaxerr(NULL);
|
syntaxerr(NULL);
|
||||||
@ -943,13 +957,14 @@ compile(Source *s, bool skiputf8bom)
|
|||||||
* $
|
* $
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
assign_command(const char *s)
|
assign_command(const char *s, bool docommand)
|
||||||
{
|
{
|
||||||
if (!*s)
|
if (!*s)
|
||||||
return (0);
|
return (0);
|
||||||
return ((strcmp(s, Talias) == 0) ||
|
return ((strcmp(s, Talias) == 0) ||
|
||||||
(strcmp(s, Texport) == 0) ||
|
(strcmp(s, Texport) == 0) ||
|
||||||
(strcmp(s, Treadonly) == 0) ||
|
(strcmp(s, Treadonly) == 0) ||
|
||||||
|
(docommand && (strcmp(s, Tcommand) == 0)) ||
|
||||||
(strcmp(s, Ttypeset) == 0));
|
(strcmp(s, Ttypeset) == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -991,7 +1006,7 @@ static const char db_gthan[] = { CHAR, '>', EOS };
|
|||||||
static Test_op
|
static Test_op
|
||||||
dbtestp_isa(Test_env *te, Test_meta meta)
|
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;
|
bool uqword;
|
||||||
char *save = NULL;
|
char *save = NULL;
|
||||||
Test_op ret = TO_NONOP;
|
Test_op ret = TO_NONOP;
|
||||||
@ -1037,7 +1052,7 @@ static const char *
|
|||||||
dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
|
dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
|
||||||
bool do_eval MKSH_A_UNUSED)
|
bool do_eval MKSH_A_UNUSED)
|
||||||
{
|
{
|
||||||
int c = tpeek(ARRAYVAR);
|
int c = tpeek(CMDASN);
|
||||||
|
|
||||||
if (c != LWORD)
|
if (c != LWORD)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
21
tree.c
21
tree.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
||||||
* 2011, 2012, 2013, 2015
|
* 2011, 2012, 2013, 2015, 2016
|
||||||
* mirabilos <m@mirbsd.org>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#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
|
#define INDENT 8
|
||||||
|
|
||||||
@ -318,6 +318,10 @@ wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
|
|||||||
case EOS:
|
case EOS:
|
||||||
return (--wp);
|
return (--wp);
|
||||||
case ADELIM:
|
case ADELIM:
|
||||||
|
if (*wp == /*{*/'}') {
|
||||||
|
++wp;
|
||||||
|
goto wdvarput_csubst;
|
||||||
|
}
|
||||||
case CHAR:
|
case CHAR:
|
||||||
c = *wp++;
|
c = *wp++;
|
||||||
shf_putc(c, shf);
|
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);
|
wp = wdvarput(shf, wp, 0, opmode);
|
||||||
break;
|
break;
|
||||||
case CSUBST:
|
case CSUBST:
|
||||||
if (*wp++ == '}')
|
if (*wp++ == '}') {
|
||||||
|
wdvarput_csubst:
|
||||||
shf_putc('}', shf);
|
shf_putc('}', shf);
|
||||||
|
}
|
||||||
return (wp);
|
return (wp);
|
||||||
case OPAT:
|
case OPAT:
|
||||||
shf_putchar(*wp++, shf);
|
shf_putchar(*wp++, shf);
|
||||||
@ -581,8 +587,10 @@ wdscan(const char *wp, int c)
|
|||||||
case EOS:
|
case EOS:
|
||||||
return (wp);
|
return (wp);
|
||||||
case ADELIM:
|
case ADELIM:
|
||||||
if (c == ADELIM)
|
if (c == ADELIM && nest == 0)
|
||||||
return (wp + 1);
|
return (wp + 1);
|
||||||
|
if (*wp == /*{*/'}')
|
||||||
|
goto wdscan_csubst;
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case CHAR:
|
case CHAR:
|
||||||
case QCHAR:
|
case QCHAR:
|
||||||
@ -604,6 +612,7 @@ wdscan(const char *wp, int c)
|
|||||||
;
|
;
|
||||||
break;
|
break;
|
||||||
case CSUBST:
|
case CSUBST:
|
||||||
|
wdscan_csubst:
|
||||||
wp++;
|
wp++;
|
||||||
if (c == CSUBST && nest == 0)
|
if (c == CSUBST && nest == 0)
|
||||||
return (wp);
|
return (wp);
|
||||||
@ -807,6 +816,10 @@ dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
|
|||||||
shf_puts("EOS", shf);
|
shf_puts("EOS", shf);
|
||||||
return (--wp);
|
return (--wp);
|
||||||
case ADELIM:
|
case ADELIM:
|
||||||
|
if (*wp == /*{*/'}') {
|
||||||
|
shf_puts("]ADELIM(})", shf);
|
||||||
|
return (wp + 1);
|
||||||
|
}
|
||||||
shf_puts("ADELIM=", shf);
|
shf_puts("ADELIM=", shf);
|
||||||
if (0)
|
if (0)
|
||||||
case CHAR:
|
case CHAR:
|
||||||
|
65
var.c
65
var.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
* 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>
|
* mirabilos <m@mirbsd.org>
|
||||||
*
|
*
|
||||||
* Provided that these terms and disclaimer and all copyright notices
|
* Provided that these terms and disclaimer and all copyright notices
|
||||||
@ -28,7 +28,7 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#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
|
* Variables
|
||||||
@ -218,14 +218,16 @@ array_index_calc(const char *n, bool *arrayp, uint32_t *valp)
|
|||||||
return (n);
|
return (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define vn vname.ro
|
||||||
/*
|
/*
|
||||||
* Search for variable, if not found create globally.
|
* Search for variable, if not found create globally.
|
||||||
*/
|
*/
|
||||||
struct tbl *
|
struct tbl *
|
||||||
global(const char *n)
|
global(const char *n)
|
||||||
{
|
{
|
||||||
struct block *l = e->loc;
|
|
||||||
struct tbl *vp;
|
struct tbl *vp;
|
||||||
|
union mksh_cchack vname;
|
||||||
|
struct block *l = e->loc;
|
||||||
int c;
|
int c;
|
||||||
bool array;
|
bool array;
|
||||||
uint32_t h, val;
|
uint32_t h, val;
|
||||||
@ -234,9 +236,9 @@ global(const char *n)
|
|||||||
* check to see if this is an array;
|
* check to see if this is an array;
|
||||||
* dereference namerefs; must come first
|
* dereference namerefs; must come first
|
||||||
*/
|
*/
|
||||||
n = array_index_calc(n, &array, &val);
|
vn = array_index_calc(n, &array, &val);
|
||||||
h = hash(n);
|
h = hash(vn);
|
||||||
c = (unsigned char)n[0];
|
c = (unsigned char)vn[0];
|
||||||
if (!ksh_isalphx(c)) {
|
if (!ksh_isalphx(c)) {
|
||||||
if (array)
|
if (array)
|
||||||
errorf("bad substitution");
|
errorf("bad substitution");
|
||||||
@ -246,15 +248,15 @@ global(const char *n)
|
|||||||
vp->areap = ATEMP;
|
vp->areap = ATEMP;
|
||||||
*vp->name = c;
|
*vp->name = c;
|
||||||
if (ksh_isdigit(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 can't fail here */
|
||||||
setstr(vp, l->argv[c], KSH_RETURN_ERROR);
|
setstr(vp, l->argv[c], KSH_RETURN_ERROR);
|
||||||
vp->flag |= RDONLY;
|
vp->flag |= RDONLY;
|
||||||
return (vp);
|
goto out;
|
||||||
}
|
}
|
||||||
vp->flag |= RDONLY;
|
vp->flag |= RDONLY;
|
||||||
if (n[1] != '\0')
|
if (vn[1] != '\0')
|
||||||
return (vp);
|
goto out;
|
||||||
vp->flag |= ISSET|INTEGER;
|
vp->flag |= ISSET|INTEGER;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '$':
|
case '$':
|
||||||
@ -278,17 +280,24 @@ global(const char *n)
|
|||||||
default:
|
default:
|
||||||
vp->flag &= ~(ISSET|INTEGER);
|
vp->flag &= ~(ISSET|INTEGER);
|
||||||
}
|
}
|
||||||
return (vp);
|
goto out;
|
||||||
}
|
}
|
||||||
l = varsearch(e->loc, &vp, n, h);
|
l = varsearch(e->loc, &vp, vn, h);
|
||||||
if (vp != NULL)
|
if (vp != NULL) {
|
||||||
return (array ? arraysearch(vp, val) : vp);
|
if (array)
|
||||||
vp = ktenter(&l->vars, n, h);
|
vp = arraysearch(vp, val);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
vp = ktenter(&l->vars, vn, h);
|
||||||
if (array)
|
if (array)
|
||||||
vp = arraysearch(vp, val);
|
vp = arraysearch(vp, val);
|
||||||
vp->flag |= DEFINED;
|
vp->flag |= DEFINED;
|
||||||
if (special(n))
|
if (special(vn))
|
||||||
vp->flag |= SPECIAL;
|
vp->flag |= SPECIAL;
|
||||||
|
out:
|
||||||
|
last_lookup_was_array = array;
|
||||||
|
if (vn != n)
|
||||||
|
afree(vname.rw, ATEMP);
|
||||||
return (vp);
|
return (vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,8 +307,9 @@ global(const char *n)
|
|||||||
struct tbl *
|
struct tbl *
|
||||||
local(const char *n, bool copy)
|
local(const char *n, bool copy)
|
||||||
{
|
{
|
||||||
struct block *l = e->loc;
|
|
||||||
struct tbl *vp;
|
struct tbl *vp;
|
||||||
|
union mksh_cchack vname;
|
||||||
|
struct block *l = e->loc;
|
||||||
bool array;
|
bool array;
|
||||||
uint32_t h, val;
|
uint32_t h, val;
|
||||||
|
|
||||||
@ -307,20 +317,20 @@ local(const char *n, bool copy)
|
|||||||
* check to see if this is an array;
|
* check to see if this is an array;
|
||||||
* dereference namerefs; must come first
|
* dereference namerefs; must come first
|
||||||
*/
|
*/
|
||||||
n = array_index_calc(n, &array, &val);
|
vn = array_index_calc(n, &array, &val);
|
||||||
h = hash(n);
|
h = hash(vn);
|
||||||
if (!ksh_isalphx(*n)) {
|
if (!ksh_isalphx(*vn)) {
|
||||||
vp = &vtemp;
|
vp = &vtemp;
|
||||||
vp->flag = DEFINED|RDONLY;
|
vp->flag = DEFINED|RDONLY;
|
||||||
vp->type = 0;
|
vp->type = 0;
|
||||||
vp->areap = ATEMP;
|
vp->areap = ATEMP;
|
||||||
return (vp);
|
goto out;
|
||||||
}
|
}
|
||||||
vp = ktenter(&l->vars, n, h);
|
vp = ktenter(&l->vars, vn, h);
|
||||||
if (copy && !(vp->flag & DEFINED)) {
|
if (copy && !(vp->flag & DEFINED)) {
|
||||||
struct tbl *vq;
|
struct tbl *vq;
|
||||||
|
|
||||||
varsearch(l->next, &vq, n, h);
|
varsearch(l->next, &vq, vn, h);
|
||||||
if (vq != NULL) {
|
if (vq != NULL) {
|
||||||
vp->flag |= vq->flag &
|
vp->flag |= vq->flag &
|
||||||
(EXPORT | INTEGER | RDONLY | LJUST | RJUST |
|
(EXPORT | INTEGER | RDONLY | LJUST | RJUST |
|
||||||
@ -333,10 +343,15 @@ local(const char *n, bool copy)
|
|||||||
if (array)
|
if (array)
|
||||||
vp = arraysearch(vp, val);
|
vp = arraysearch(vp, val);
|
||||||
vp->flag |= DEFINED;
|
vp->flag |= DEFINED;
|
||||||
if (special(n))
|
if (special(vn))
|
||||||
vp->flag |= SPECIAL;
|
vp->flag |= SPECIAL;
|
||||||
|
out:
|
||||||
|
last_lookup_was_array = array;
|
||||||
|
if (vn != n)
|
||||||
|
afree(vname.rw, ATEMP);
|
||||||
return (vp);
|
return (vp);
|
||||||
}
|
}
|
||||||
|
#undef vn
|
||||||
|
|
||||||
/* get variable string value */
|
/* get variable string value */
|
||||||
char *
|
char *
|
||||||
@ -1492,7 +1507,7 @@ arrayname(const char *str)
|
|||||||
const char *p;
|
const char *p;
|
||||||
char *rv;
|
char *rv;
|
||||||
|
|
||||||
if ((p = cstrchr(str, '[')) == 0)
|
if (!(p = cstrchr(str, '[')))
|
||||||
/* Shouldn't happen, but why worry? */
|
/* Shouldn't happen, but why worry? */
|
||||||
strdupx(rv, str, ATEMP);
|
strdupx(rv, str, ATEMP);
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user