summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2017-09-13 14:55:55 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2017-09-13 14:55:56 +0900
commit8d39e6d71933b767be25ad1af9b0e7811b68d887 (patch)
tree0c9f0352bf11c867b548b7f77dea9092df874979
parent28fa0c6c450514aa381ec146faf402c6cf08b507 (diff)
downloaddash-8d39e6d71933b767be25ad1af9b0e7811b68d887.tar.gz
dash-8d39e6d71933b767be25ad1af9b0e7811b68d887.tar.bz2
dash-8d39e6d71933b767be25ad1af9b0e7811b68d887.zip
Imported Upstream version 0.5.9
Change-Id: I04e65a1a0673e829746152c57b2e8e0cce90719c Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
-rw-r--r--ChangeLog70
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure47
-rw-r--r--configure.ac33
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.in2
-rw-r--r--src/bltin/printf.c196
-rw-r--r--src/bltin/test.c32
-rw-r--r--src/cd.c14
-rw-r--r--src/dash.119
-rw-r--r--src/error.c1
-rw-r--r--src/eval.c113
-rw-r--r--src/eval.h2
-rw-r--r--src/expand.c51
-rw-r--r--src/hetio.h22
-rw-r--r--src/histedit.c3
-rw-r--r--src/input.c146
-rw-r--r--src/input.h49
-rw-r--r--src/main.c29
-rw-r--r--src/mkbuiltins9
-rw-r--r--src/output.c90
-rw-r--r--src/output.h3
-rw-r--r--src/parser.c149
-rw-r--r--src/trap.c44
-rw-r--r--src/var.c5
25 files changed, 676 insertions, 458 deletions
diff --git a/ChangeLog b/ChangeLog
index a466a7f..406e20c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,73 @@
+2014-11-17 Stéphane Aulery <saulery@free.fr>
+
+ * Correct typo in manual page.
+ * Document redirection file descriptor limitation.
+
+2014-10-30 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Catch variable length expansions on non-existant specials.
+
+2014-10-28 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Removed unnecessary pungetc on EOF from parser.
+ * Simplify EOF/newline handling in list parser.
+
+2014-10-27 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Add printf support for format string a, A, and F.
+ * Handle embedded NULs correctly in printf.
+ * Replace open-coded flushall in preadbuffer.
+ * Add likely tag in outmem.
+ * Add ifdefs around MEM_OUT handling in outmem.
+ * Remove unnecessary restoration of format string in printf.
+ * Remove getintmax in printf.
+ * Use error instead of warnx for fatal errors in printf.
+ * Optimise handling of backslash octals in printf.
+ * Simplify echo command.
+ * Handle -- in dotcmd.
+
+2014-10-13 Eric Blake <eblake@redhat.com>
+
+ * cd: support drive letters on Cygwin.
+
+2014-10-08 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Split unquoted $@/$* correctly when IFS is set but empty.
+ * Do not split quoted VSLENGTH and VSTRIM.
+ * Optimise nulonly away and just use quoted as before.
+
+2014-10-07 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Use setvareq to set OPTIND initially.
+
+2014-10-06 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Exit without arguments in a trap should use status outside traps.
+ * Do not allow break to break across function calls.
+ * Move common skipcount logic into skiploop.
+ * Allow return in loop conditional to set exit status.
+ * Return without arguments in a trap should use status outside traps.
+
+2014-10-03 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Do not clobber exitstatus in evalcommand.
+
+2014-10-02 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Fix use-after-free in dotrap/evalstring.
+ * Make sure evalskip is zero before running traps.
+ * Set exitstatus in onint.
+
+2014-09-29 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Kill pgetc_macro.
+ * Handle backslash newlines properly after dollar sign.
+ * Add nlprompt/nlnoprompt helpers.
+
+2014-09-28 Herbert Xu <herbert@gondor.apana.org.au>
+
+ * Correctly handle test ! ! = !.
+
2014-09-26 Herbert Xu <herbert@gondor.apana.org.au>
* Small optimisation of command -pv change.
diff --git a/config.h.in b/config.h.in
index 85b33ad..7a2b262 100644
--- a/config.h.in
+++ b/config.h.in
@@ -88,6 +88,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
+/* Define if your faccessat tells root all files are executable */
+#undef HAVE_TRADITIONAL_FACCESSAT
+
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
diff --git a/configure b/configure
index d5c6a50..3d5a8de 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for dash 0.5.8.
+# Generated by GNU Autoconf 2.69 for dash 0.5.9.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='dash'
PACKAGE_TARNAME='dash'
-PACKAGE_VERSION='0.5.8'
-PACKAGE_STRING='dash 0.5.8'
+PACKAGE_VERSION='0.5.9'
+PACKAGE_STRING='dash 0.5.9'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -714,6 +714,7 @@ enable_dependency_tracking
enable_static
enable_fnmatch
enable_glob
+enable_test_workaround
with_libedit
enable_lineno
'
@@ -1268,7 +1269,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures dash 0.5.8 to adapt to many kinds of systems.
+\`configure' configures dash 0.5.9 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1334,7 +1335,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of dash 0.5.8:";;
+ short | recursive ) echo "Configuration of dash 0.5.9:";;
esac
cat <<\_ACEOF
@@ -1347,6 +1348,9 @@ Optional Features:
--enable-static Build statical linked program
--enable-fnmatch Use fnmatch(3) from libc
--enable-glob Use glob(3) from libc
+ --enable-test-workaround
+ Guard against faccessat(2) that tells root all files
+ are executable
--disable-lineno Disable LINENO support
Optional Packages:
@@ -1436,7 +1440,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-dash configure 0.5.8
+dash configure 0.5.9
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2030,7 +2034,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by dash $as_me 0.5.8, which was
+It was created by dash $as_me 0.5.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2845,7 +2849,7 @@ fi
# Define the identity of the package.
PACKAGE='dash'
- VERSION='0.5.8'
+ VERSION='0.5.9'
cat >>confdefs.h <<_ACEOF
@@ -4614,6 +4618,29 @@ fi
done
+
+# Check whether --enable-test-workaround was given.
+if test "${enable_test_workaround+set}" = set; then :
+ enableval=$enable_test_workaround;
+else
+ enable_test_workaround=auto
+fi
+
+
+if test "enable_test_workaround" = "auto" &&
+ test "$ac_cv_func_faccessat" = yes; then
+ case `uname -s 2>/dev/null` in
+ GNU/kFreeBSD | \
+ FreeBSD)
+ enable_test_workaround=yes
+ esac
+fi
+if test "$enable_test_workaround" = "yes"; then
+
+$as_echo "#define HAVE_TRADITIONAL_FACCESSAT 1" >>confdefs.h
+
+fi
+
if test "$enable_fnmatch" = yes; then
use_fnmatch=
for ac_func in fnmatch
@@ -5286,7 +5313,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by dash $as_me 0.5.8, which was
+This file was extended by dash $as_me 0.5.9, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -5352,7 +5379,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-dash config.status 0.5.8
+dash config.status 0.5.9
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 60a2a26..4c2c179 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(dash, 0.5.8)
+AC_INIT(dash, 0.5.9)
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_SRCDIR([src/main.c])
@@ -90,6 +90,37 @@ AC_CHECK_FUNCS(bsearch faccessat getpwnam getrlimit isalpha killpg \
sigsetmask stpcpy strchrnul strsignal strtod strtoimax \
strtoumax sysconf)
+dnl Check whether it's worth working around FreeBSD PR kern/125009.
+dnl The traditional behavior of access/faccessat is crazy, but
+dnl POSIX.1-2008 explicitly allows those functions to misbehave.
+dnl
+dnl Unaffected kernels:
+dnl
+dnl - all versions of Linux
+dnl - NetBSD sys/kern/vfs_subr.c 1.64, 1997-04-23
+dnl - FreeBSD 9 (r212002), 2010-09-10
+dnl - OpenBSD sys/kern/vfs_subr.c 1.166, 2008-06-09
+dnl
+dnl Also worked around in Debian's libc0.1 2.13-19 when using
+dnl kFreeBSD 8.
+
+AC_ARG_ENABLE(test-workaround, AS_HELP_STRING(--enable-test-workaround, \
+ [Guard against faccessat(2) that tells root all files are executable]),,
+ [enable_test_workaround=auto])
+
+if test "enable_test_workaround" = "auto" &&
+ test "$ac_cv_func_faccessat" = yes; then
+ case `uname -s 2>/dev/null` in
+ GNU/kFreeBSD | \
+ FreeBSD)
+ enable_test_workaround=yes
+ esac
+fi
+if test "$enable_test_workaround" = "yes"; then
+ AC_DEFINE([HAVE_TRADITIONAL_FACCESSAT], [1],
+ [Define if your faccessat tells root all files are executable])
+fi
+
if test "$enable_fnmatch" = yes; then
use_fnmatch=
AC_CHECK_FUNCS(fnmatch, use_fnmatch=yes)
diff --git a/src/Makefile.am b/src/Makefile.am
index 2a37381..120ffa2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,7 @@ dash_CFILES = \
dash_SOURCES = \
$(dash_CFILES) \
alias.h arith_yacc.h bltin/bltin.h cd.h error.h eval.h exec.h \
- expand.h hetio.h \
+ expand.h \
init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
show.h system.h trap.h var.h
diff --git a/src/Makefile.in b/src/Makefile.in
index fc65e4f..4ccb12c 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -236,7 +236,7 @@ dash_CFILES = \
dash_SOURCES = \
$(dash_CFILES) \
alias.h arith_yacc.h bltin/bltin.h cd.h error.h eval.h exec.h \
- expand.h hetio.h \
+ expand.h \
init.h input.h jobs.h machdep.h mail.h main.h memalloc.h miscbltin.h \
myhistedit.h mystring.h options.h output.h parser.h redir.h shell.h \
show.h system.h trap.h var.h
diff --git a/src/bltin/printf.c b/src/bltin/printf.c
index 5f9e81c..9673e10 100644
--- a/src/bltin/printf.c
+++ b/src/bltin/printf.c
@@ -40,12 +40,11 @@
#include <string.h>
#include <unistd.h>
-static int conv_escape_str(char *);
+static int conv_escape_str(char *, char **);
static char *conv_escape(char *, int *);
static int getchr(void);
static double getdouble(void);
-static intmax_t getintmax(void);
-static uintmax_t getuintmax(void);
+static uintmax_t getuintmax(int);
static char *getstr(void);
static char *mklong(const char *, const char *);
static void check_conversion(const char *, const char *);
@@ -73,6 +72,53 @@ static char **gargv;
} \
}
+#define ASPF(sp, f, func) ({ \
+ int ret; \
+ switch ((char *)param - (char *)array) { \
+ default: \
+ ret = xasprintf(sp, f, array[0], array[1], func); \
+ break; \
+ case sizeof(*param): \
+ ret = xasprintf(sp, f, array[0], func); \
+ break; \
+ case 0: \
+ ret = xasprintf(sp, f, func); \
+ break; \
+ } \
+ ret; \
+})
+
+
+static int print_escape_str(const char *f, int *param, int *array, char *s)
+{
+ struct stackmark smark;
+ char *p, *q;
+ int done;
+ int len;
+ int total;
+
+ setstackmark(&smark);
+ done = conv_escape_str(s, &p);
+ q = stackblock();
+ len = p - q;
+
+ p = makestrspace(len, p);
+ memset(p, 'X', len - 1);
+ p[len - 1] = 0;
+
+ q = stackblock();
+ total = ASPF(&p, f, p);
+
+ len = strchrnul(p, 'X') - p;
+ memcpy(p + len, q, strchrnul(p + len, ' ') - (p + len));
+
+ out1mem(p, total);
+
+ popstackmark(&smark);
+ return done;
+}
+
+
int printfcmd(int argc, char *argv[])
{
char *fmt;
@@ -86,10 +132,8 @@ int printfcmd(int argc, char *argv[])
argv = argptr;
format = *argv;
- if (!format) {
- warnx("usage: printf format [arg ...]");
- goto err;
- }
+ if (!format)
+ error("usage: printf format [arg ...]");
gargv = ++argv;
@@ -132,39 +176,33 @@ pc:
/* skip to field width */
fmt += strspn(fmt, SKIP1);
if (*fmt == '*')
- *param++ = getintmax();
+ *param++ = getuintmax(1);
/* skip to possible '.', get following precision */
fmt += strspn(fmt, SKIP2);
if (*fmt == '.')
++fmt;
if (*fmt == '*')
- *param++ = getintmax();
+ *param++ = getuintmax(1);
fmt += strspn(fmt, SKIP2);
ch = *fmt;
- if (!ch) {
- warnx("missing format character");
- goto err;
- }
+ if (!ch)
+ error("missing format character");
/* null terminate format string to we can use it
as an argument to printf. */
nextch = fmt[1];
fmt[1] = 0;
switch (ch) {
- case 'b': {
- int done = conv_escape_str(getstr());
- char *p = stackblock();
+ case 'b':
*fmt = 's';
- PF(start, p);
/* escape if a \c was encountered */
- if (done)
+ if (print_escape_str(start, param, array,
+ getstr()))
goto out;
- *fmt = 'b';
break;
- }
case 'c': {
int p = getchr();
PF(start, p);
@@ -177,23 +215,26 @@ pc:
}
case 'd':
case 'i': {
- intmax_t p = getintmax();
- char *f = mklong(start, fmt);
- PF(f, p);
+ uintmax_t p = getuintmax(1);
+ start = mklong(start, fmt);
+ PF(start, p);
break;
}
case 'o':
case 'u':
case 'x':
case 'X': {
- uintmax_t p = getuintmax();
- char *f = mklong(start, fmt);
- PF(f, p);
+ uintmax_t p = getuintmax(0);
+ start = mklong(start, fmt);
+ PF(start, p);
break;
}
+ case 'a':
+ case 'A':
case 'e':
case 'E':
case 'f':
+ case 'F':
case 'g':
case 'G': {
double p = getdouble();
@@ -201,8 +242,7 @@ pc:
break;
}
default:
- warnx("%s: invalid directive", start);
- goto err;
+ error("%s: invalid directive", start);
}
*++fmt = nextch;
}
@@ -210,8 +250,6 @@ pc:
out:
return rval;
-err:
- return 1;
}
@@ -220,8 +258,9 @@ err:
* Halts processing string if a \c escape is encountered.
*/
static int
-conv_escape_str(char *str)
+conv_escape_str(char *str, char **sp)
{
+ int c;
int ch;
char *cp;
@@ -229,16 +268,14 @@ conv_escape_str(char *str)
STARTSTACKSTR(cp);
do {
- int c;
-
- ch = *str++;
+ c = ch = *str++;
if (ch != '\\')
continue;
- ch = *str++;
- if (ch == 'c') {
+ c = *str++;
+ if (c == 'c') {
/* \c as in SYSV echo - abort all processing.... */
- ch = 0x100;
+ c = ch = 0x100;
continue;
}
@@ -247,25 +284,14 @@ conv_escape_str(char *str)
* They start with a \0, and are followed by 0, 1, 2,
* or 3 octal digits.
*/
- if (ch == '0') {
- unsigned char i;
- i = 3;
- ch = 0;
- do {
- unsigned k = octtobin(*str);
- if (k > 7)
- break;
- str++;
- ch <<= 3;
- ch += k;
- } while (--i);
- continue;
- }
+ if (c == '0' && isodigit(*str))
+ str++;
/* Finally test for sequences valid in the format string */
str = conv_escape(str - 1, &c);
- ch = c;
- } while (STPUTC(ch, cp), (char)ch);
+ } while (STPUTC(c, cp), (char)ch);
+
+ *sp = cp;
return ch;
}
@@ -283,12 +309,11 @@ conv_escape(char *str, int *conv_ch)
switch (ch) {
default:
- case 0:
- value = '\\';
- goto out;
+ if (!isodigit(*str)) {
+ value = '\\';
+ goto out;
+ }
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
ch = 3;
value = 0;
do {
@@ -357,30 +382,8 @@ getstr(void)
return val;
}
-static intmax_t
-getintmax(void)
-{
- intmax_t val = 0;
- char *cp, *ep;
-
- cp = *gargv;
- if (cp == NULL)
- goto out;
- gargv++;
-
- val = (unsigned char) cp[1];
- if (*cp == '\"' || *cp == '\'')
- goto out;
-
- errno = 0;
- val = strtoimax(cp, &ep, 0);
- check_conversion(cp, ep);
-out:
- return val;
-}
-
static uintmax_t
-getuintmax(void)
+getuintmax(int sign)
{
uintmax_t val = 0;
char *cp, *ep;
@@ -395,7 +398,7 @@ getuintmax(void)
goto out;
errno = 0;
- val = strtoumax(cp, &ep, 0);
+ val = sign ? strtoimax(cp, &ep, 0) : strtoumax(cp, &ep, 0);
check_conversion(cp, ep);
out:
return val;
@@ -439,34 +442,21 @@ check_conversion(const char *s, const char *ep)
int
echocmd(int argc, char **argv)
{
- int nonl = 0;
- struct output *outs = out1;
-
- if (!*++argv)
- goto end;
- if (equal(*argv, "-n")) {
- nonl = ~nonl;
- if (!*++argv)
- goto end;
- }
+ int nonl;
+
+ nonl = *++argv ? equal(*argv, "-n") : 0;
+ argv += nonl;
do {
int c;
- nonl += conv_escape_str(*argv);
- outstr(stackblock(), outs);
+ if (likely(*argv))
+ nonl += print_escape_str("%s", NULL, NULL, *argv++);
if (nonl > 0)
break;
- c = ' ';
- if (!*++argv) {
-end:
- if (nonl) {
- break;
- }
- c = '\n';
- }
- outc(c, outs);
+ c = *argv ? ' ' : '\n';
+ out1c(c);
} while (*argv);
return 0;
}
diff --git a/src/bltin/test.c b/src/bltin/test.c
index baa91a5..58c05fe 100644
--- a/src/bltin/test.c
+++ b/src/bltin/test.c
@@ -155,6 +155,14 @@ static int test_st_mode(const struct stat64 *, int);
static int bash_group_member(gid_t);
#endif
+#ifdef HAVE_FACCESSAT
+# ifdef HAVE_TRADITIONAL_FACCESSAT
+static inline int faccessat_confused_about_superuser(void) { return 1; }
+# else
+static inline int faccessat_confused_about_superuser(void) { return 0; }
+# endif
+#endif
+
static inline intmax_t getn(const char *s)
{
return atomax10(s);
@@ -177,7 +185,7 @@ testcmd(int argc, char **argv)
{
const struct t_op *op;
enum token n;
- int res;
+ int res = 1;
if (*argv[0] == '[') {
if (*argv[--argc] != ']')
@@ -185,11 +193,14 @@ testcmd(int argc, char **argv)
argv[argc] = NULL;
}
+ t_wp_op = NULL;
+
+recheck:
argv++;
argc--;
if (argc < 1)
- return 1;
+ return res;
/*
* POSIX prescriptions: he who wrote this deserves the Nobel
@@ -209,6 +220,9 @@ testcmd(int argc, char **argv)
argv[--argc] = NULL;
argv++;
argc--;
+ } else if (!strcmp(argv[0], "!")) {
+ res = 0;
+ goto recheck;
}
}
@@ -216,7 +230,7 @@ testcmd(int argc, char **argv)
eval:
t_wp = argv;
- res = !oexpr(n);
+ res ^= oexpr(n);
argv = t_wp;
if (argv[0] != NULL && argv[1] != NULL)
@@ -489,8 +503,20 @@ equalf (const char *f1, const char *f2)
}
#ifdef HAVE_FACCESSAT
+static int has_exec_bit_set(const char *path)
+{
+ struct stat64 st;
+
+ if (stat64(path, &st))
+ return 0;
+ return st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH);
+}
+
static int test_file_access(const char *path, int mode)
{
+ if (faccessat_confused_about_superuser() &&
+ mode == X_OK && geteuid() == 0 && !has_exec_bit_set(path))
+ return 0;
return !faccessat(AT_FDCWD, path, mode, AT_EACCESS);
}
#else /* HAVE_FACCESSAT */
diff --git a/src/cd.c b/src/cd.c
index 2d9d4b5..a4e024d 100644
--- a/src/cd.c
+++ b/src/cd.c
@@ -38,6 +38,9 @@
#include <string.h>
#include <unistd.h>
#include <limits.h>
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif
/*
* The cd and pwd commands.
@@ -194,6 +197,17 @@ updatepwd(const char *dir)
char *cdcomppath;
const char *lim;
+#ifdef __CYGWIN__
+ /* On cygwin, thanks to drive letters, some absolute paths do
+ not begin with slash; but cygwin includes a function that
+ forces normalization to the posix form */
+ char pathbuf[PATH_MAX];
+ if (cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE, dir, pathbuf,
+ sizeof(pathbuf)) < 0)
+ sh_error("can't normalize %s", dir);
+ dir = pathbuf;
+#endif
+
cdcomppath = sstrdup(dir);
STARTSTACKSTR(new);
if (*dir != '/') {
diff --git a/src/dash.1 b/src/dash.1
index 489cea2..832eae7 100644
--- a/src/dash.1
+++ b/src/dash.1
@@ -385,7 +385,7 @@ is one of the redirection operators mentioned previously.
Following is a list of the possible redirections.
The
.Bq n
-is an optional number, as in
+is an optional number between 0 and 9, as in
.Sq 3
(not
.Sq Bq 3 ) ,
@@ -402,11 +402,13 @@ Append standard output (or n) to file.
.It [n] Ns \*[Lt] file
Redirect standard input (or n) from file.
.It [n1] Ns \*[Lt]& Ns n2
-Duplicate standard input (or n1) from file descriptor n2.
+Copy file descriptor n2 as stdout (or fd n1).
+fd n2.
.It [n] Ns \*[Lt]&-
Close standard input (or n).
.It [n1] Ns \*[Gt]& Ns n2
-Duplicate standard output (or n1) to n2.
+Copy file descriptor n2 as stdin (or fd n1).
+fd n2.
.It [n] Ns \*[Gt]&-
Close standard output (or n).
.It [n] Ns \*[Lt]\*[Gt] file
@@ -596,7 +598,7 @@ semicolons, or ampersands, and optionally terminated by one of these three
characters.
The commands in a list are executed in the order they are written.
If command is followed by an ampersand, the shell starts the
-command and immediately proceed onto the next command; otherwise it waits
+command and immediately proceeds onto the next command; otherwise it waits
for the command to terminate before proceeding to the next one.
.Ss Short-Circuit List Operators
.Dq &&
@@ -1400,14 +1402,9 @@ By specifying a colon as the first character of
.Va optstring
all errors will be ignored.
.Pp
-A nonzero value is returned when the last option is reached.
-If there are no remaining arguments,
+After the last option
.Ic getopts
-will set
-.Va var
-to the special option,
-.Dq -- ,
-otherwise, it will set
+will return a non-zero value and set
.Va var
to
.Dq \&? .
diff --git a/src/error.c b/src/error.c
index 9d31989..f9ea919 100644
--- a/src/error.c
+++ b/src/error.c
@@ -105,6 +105,7 @@ onint(void) {
signal(SIGINT, SIG_DFL);
raise(SIGINT);
}
+ exitstatus = SIGINT + 128;
exraise(EXINT);
/* NOTREACHED */
}
diff --git a/src/eval.c b/src/eval.c
index c7358a6..071fb1b 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -74,6 +74,7 @@ static int funcline; /* starting line number of current function, or 0 if not i
char *commandname;
int exitstatus; /* exit status of last command */
int back_exitstatus; /* exit status of backquoted command */
+int savestatus = -1; /* exit status of last command outside traps */
#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
@@ -114,6 +115,10 @@ INCLUDE "eval.h"
RESET {
evalskip = 0;
loopnest = 0;
+ if (savestatus >= 0) {
+ exitstatus = savestatus;
+ savestatus = -1;
+ }
}
#endif
@@ -160,6 +165,7 @@ evalstring(char *s, int flags)
struct stackmark smark;
int status;
+ s = sstrdup(s);
setinputstring(s);
setstackmark(&smark);
@@ -171,7 +177,9 @@ evalstring(char *s, int flags)
if (evalskip)
break;
}
+ popstackmark(&smark);
popfile();
+ stunalloc(s);
return status;
}
@@ -194,6 +202,9 @@ evaltree(union node *n, int flags)
TRACE(("evaltree(NULL) called\n"));
goto out;
}
+
+ dotrap();
+
#ifndef SMALL
displayhist = 1; /* show history substitutions done with fc */
#endif
@@ -305,8 +316,7 @@ out:
if (checkexit & exitstatus)
goto exexit;
- if (pendingsigs)
- dotrap();
+ dotrap();
if (flags & EV_EXIT) {
exexit:
@@ -329,27 +339,45 @@ void evaltreenr(union node *n, int flags)
#endif
+static int skiploop(void)
+{
+ int skip = evalskip;
+
+ switch (skip) {
+ case 0:
+ break;
+
+ case SKIPBREAK:
+ case SKIPCONT:
+ if (likely(--skipcount <= 0)) {
+ evalskip = 0;
+ break;
+ }
+
+ skip = SKIPBREAK;
+ break;
+ }
+
+ return skip;
+}
+
+
STATIC void
evalloop(union node *n, int flags)
{
+ int skip;
int status;
loopnest++;
status = 0;
flags &= EV_TESTED;
- for (;;) {
+ do {
int i;
evaltree(n->nbinary.ch1, EV_TESTED);
- if (evalskip) {
-skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
- evalskip = 0;
- continue;
- }
- if (evalskip == SKIPBREAK && --skipcount <= 0)
- evalskip = 0;
- break;
- }
+ skip = skiploop();
+ if (skip)
+ continue;
i = exitstatus;
if (n->type != NWHILE)
i = !i;
@@ -357,11 +385,11 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
break;
evaltree(n->nbinary.ch2, flags);
status = exitstatus;
- if (evalskip)
- goto skipping;
- }
+ skip = skiploop();
+ } while (!(skip & ~SKIPCONT));
+ if (skip != SKIPFUNC)
+ exitstatus = status;
loopnest--;
- exitstatus = status;
}
@@ -382,9 +410,6 @@ evalfor(union node *n, int flags)
arglist.lastp = &arglist.list;
for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
- /* XXX */
- if (evalskip)
- goto out;
}
*arglist.lastp = NULL;
@@ -394,18 +419,10 @@ evalfor(union node *n, int flags)
for (sp = arglist.list ; sp ; sp = sp->next) {
setvar(n->nfor.var, sp->text, 0);
evaltree(n->nfor.body, flags);
- if (evalskip) {
- if (evalskip == SKIPCONT && --skipcount <= 0) {
- evalskip = 0;
- continue;
- }
- if (evalskip == SKIPBREAK && --skipcount <= 0)
- evalskip = 0;
+ if (skiploop() & ~SKIPCONT)
break;
- }
}
loopnest--;
-out:
popstackmark(&smark);
}
@@ -848,21 +865,12 @@ bail:
listsetvar(varlist.list, VEXPORT);
}
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
- int status;
- int i;
-
- i = exception;
- if (i == EXEXIT)
- goto raise;
-
- status = (i == EXINT) ? SIGINT + 128 : 2;
- exitstatus = status;
-
- if (i == EXINT || spclbltin > 0) {
-raise:
- longjmp(handler->loc, 1);
+ if (exception == EXERROR && spclbltin <= 0) {
+ FORCEINTON;
+ break;
}
- FORCEINTON;
+raise:
+ longjmp(handler->loc, 1);
}
break;
@@ -927,9 +935,11 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
struct jmploc jmploc;
int e;
int savefuncline;
+ int saveloopnest;
saveparam = shellparam;
savefuncline = funcline;
+ saveloopnest = loopnest;
savehandler = handler;
if ((e = setjmp(jmploc.loc))) {
goto funcdone;
@@ -939,6 +949,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
shellparam.malloc = 0;
func->count++;
funcline = func->n.ndefun.linno;
+ loopnest = 0;
INTON;
shellparam.nparam = argc - 1;
shellparam.p = argv + 1;
@@ -949,13 +960,14 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
poplocalvars(0);
funcdone:
INTOFF;
+ loopnest = saveloopnest;
funcline = savefuncline;
freefunc(func);
freeparam(&shellparam);
shellparam = saveparam;
handler = savehandler;
INTON;
- evalskip &= ~SKIPFUNC;
+ evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
return e;
}
@@ -1035,12 +1047,23 @@ breakcmd(int argc, char **argv)
int
returncmd(int argc, char **argv)
{
+ int skip;
+ int status;
+
/*
* If called outside a function, do what ksh does;
* skip the rest of the file.
*/
- evalskip = SKIPFUNC;
- return argv[1] ? number(argv[1]) : exitstatus;
+ if (argv[1]) {
+ skip = SKIPFUNC;
+ status = number(argv[1]);
+ } else {
+ skip = SKIPFUNCDEF;
+ status = exitstatus;
+ }
+ evalskip = skip;
+
+ return status;
}
diff --git a/src/eval.h b/src/eval.h
index dc8acd2..6e8acda 100644
--- a/src/eval.h
+++ b/src/eval.h
@@ -37,6 +37,7 @@
extern char *commandname; /* currently executing command */
extern int exitstatus; /* exit status of last command */
extern int back_exitstatus; /* exit status of backquoted command */
+extern int savestatus; /* exit status of last command outside traps */
struct backcmd { /* result of evalbackcmd */
@@ -61,3 +62,4 @@ extern int evalskip;
#define SKIPBREAK (1 << 0)
#define SKIPCONT (1 << 1)
#define SKIPFUNC (1 << 2)
+#define SKIPFUNCDEF (1 << 3)
diff --git a/src/expand.c b/src/expand.c
index 11fd7b7..b2d710d 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -116,7 +116,7 @@ STATIC const char *subevalvar(char *, char *, int, int, int, int, int);
STATIC char *evalvar(char *, int);
STATIC size_t strtodest(const char *, const char *, int);
STATIC void memtodest(const char *, size_t, const char *, int);
-STATIC ssize_t varvalue(char *, int, int);
+STATIC ssize_t varvalue(char *, int, int, int *);
STATIC void expandmeta(struct strlist *, int);
#ifdef HAVE_GLOB
STATIC void addglob(const glob_t *);
@@ -736,7 +736,7 @@ evalvar(char *p, int flag)
p = strchr(p, '=') + 1;
again:
- varlen = varvalue(var, varflags, flag);
+ varlen = varvalue(var, varflags, flag, &quoted);
if (varflags & VSNUL)
varlen--;
@@ -751,28 +751,22 @@ vsplus:
argstr(p, flag | EXP_TILDE | EXP_WORD);
goto end;
}
- if (easy)
- goto record;
- goto end;
+ goto record;
}
if (subtype == VSASSIGN || subtype == VSQUESTION) {
- if (varlen < 0) {
- if (subevalvar(p, var, 0, subtype, startloc,
- varflags, flag & ~QUOTES_ESC)) {
- varflags &= ~VSNUL;
- /*
- * Remove any recorded regions beyond
- * start of variable
- */
- removerecordregions(startloc);
- goto again;
- }
- goto end;
- }
- if (easy)
+ if (varlen >= 0)
goto record;
- goto end;
+
+ subevalvar(p, var, 0, subtype, startloc, varflags,
+ flag & ~QUOTES_ESC);
+ varflags &= ~VSNUL;
+ /*
+ * Remove any recorded regions beyond
+ * start of variable
+ */
+ removerecordregions(startloc);
+ goto again;
}
if (varlen < 0 && uflag)
@@ -784,9 +778,9 @@ vsplus:
}
if (subtype == VSNORMAL) {
+record:
if (!easy)
goto end;
-record:
recordregion(startloc, expdest - (char *)stackblock(), quoted);
goto end;
}
@@ -892,7 +886,7 @@ strtodest(p, syntax, quotes)
*/
STATIC ssize_t
-varvalue(char *name, int varflags, int flags)
+varvalue(char *name, int varflags, int flags, int *quotedp)
{
int num;
char *p;
@@ -901,13 +895,13 @@ varvalue(char *name, int varflags, int flags)
char sepc;
char **ap;
char const *syntax;
- int quoted = flags & EXP_QUOTED;
+ int quoted = *quotedp;
int subtype = varflags & VSTYPE;
int discard = subtype == VSPLUS || subtype == VSLENGTH;
int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
ssize_t len = 0;
- sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
+ sep = (flags & EXP_FULL) << CHAR_BIT;
syntax = quoted ? DQSYNTAX : BASESYNTAX;
switch (*name) {
@@ -938,15 +932,18 @@ numvar:
expdest = p;
break;
case '@':
- if (sep)
+ if (quoted && sep)
goto param;
/* fall through */
case '*':
- sep = ifsset() ? ifsval()[0] : ' ';
+ if (quoted)
+ sep = 0;
+ sep |= ifsset() ? ifsval()[0] : ' ';
param:
+ sepc = sep;
+ *quotedp = !sepc;
if (!(ap = shellparam.p))
return -1;
- sepc = sep;
while ((p = *ap++)) {
len += strtodest(p, syntax, quotes);
diff --git a/src/hetio.h b/src/hetio.h
deleted file mode 100644
index c3e915c..0000000
--- a/src/hetio.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Termios command line History and Editting for NetBSD sh (ash)
- * Copyright (c) 1999
- * Main code: Adam Rogoyski <rogoyski@cs.utexas.edu>
- * Etc: Dave Cinege <dcinege@psychosis.com>
- *
- * You may use this code as you wish, so long as the original author(s)
- * are attributed in any redistributions of the source code.
- * This code is 'as is' with no warranty.
- * This code may safely be consumed by a BSD or GPL license.
- *
- * v 0.5 19990328 Initial release
- *
- * Future plans: Simple file and path name completion. (like BASH)
- *
- */
-
-void hetio_init(void);
-int hetio_read_input(int fd);
-void hetio_reset_term(void);
-
-extern int hetio_inter;
diff --git a/src/histedit.c b/src/histedit.c
index b27d629..94465d7 100644
--- a/src/histedit.c
+++ b/src/histedit.c
@@ -372,8 +372,7 @@ histcmd(int argc, char **argv)
out2str(s);
}
- evalstring(strcpy(stalloc(strlen(s) + 1), s),
- 0);
+ evalstring(s, 0);
if (displayhist && hist) {
/*
* XXX what about recursive and
diff --git a/src/input.c b/src/input.c
index d31c45b..06c08d4 100644
--- a/src/input.c
+++ b/src/input.c
@@ -58,45 +58,10 @@
#include "myhistedit.h"
#endif
-#ifdef HETIO
-#include "hetio.h"
-#endif
-
#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
#define IBUFSIZ (BUFSIZ + 1)
-MKINIT
-struct strpush {
- struct strpush *prev; /* preceding string on stack */
- char *prevstring;
- int prevnleft;
- struct alias *ap; /* if push was associated with an alias */
- char *string; /* remember the string since it may change */
-};
-
-/*
- * The parsefile structure pointed to by the global variable parsefile
- * contains information about the current file being read.
- */
-MKINIT
-struct parsefile {
- struct parsefile *prev; /* preceding file on stack */
- int linno; /* current line */
- int fd; /* file descriptor (or -1 if string) */
- int nleft; /* number of chars left in this line */
- int lleft; /* number of chars left in this buffer */
- char *nextc; /* next char in buffer */
- char *buf; /* input buffer */
- struct strpush *strpush; /* for pushing strings at this level */
- struct strpush basestrpush; /* so pushing one is fast */
-};
-
-
-int plinno = 1; /* input line number */
-int parsenleft; /* copy of parsefile->nleft */
-MKINIT int parselleft; /* copy of parsefile->lleft */
-char *parsenextc; /* copy of parsefile->nextc */
MKINIT struct parsefile basepf; /* top level input file */
MKINIT char basebuf[IBUFSIZ]; /* buffer for top level input file */
struct parsefile *parsefile = &basepf; /* current input file */
@@ -109,6 +74,7 @@ EditLine *el; /* cookie for editline package */
STATIC void pushfile(void);
static int preadfd(void);
static void setinputfd(int fd, int push);
+static int preadbuffer(void);
#ifdef mkinit
INCLUDE <stdio.h>
@@ -117,10 +83,12 @@ INCLUDE "error.h"
INIT {
basepf.nextc = basepf.buf = basebuf;
+ basepf.linno = 1;
}
RESET {
- parselleft = parsenleft = 0; /* clear input buffer */
+ /* clear input buffer */
+ basepf.lleft = basepf.nleft = 0;
popallfiles();
}
#endif
@@ -134,7 +102,20 @@ RESET {
int
pgetc(void)
{
- return pgetc_macro();
+ int c;
+
+ if (parsefile->unget)
+ return parsefile->lastc[--parsefile->unget];
+
+ if (--parsefile->nleft >= 0)
+ c = (signed char)*parsefile->nextc++;
+ else
+ c = preadbuffer();
+
+ parsefile->lastc[1] = parsefile->lastc[0];
+ parsefile->lastc[0] = c;
+
+ return c;
}
@@ -147,7 +128,7 @@ pgetc2()
{
int c;
do {
- c = pgetc_macro();
+ c = pgetc();
} while (c == PEOA);
return c;
}
@@ -158,7 +139,7 @@ preadfd(void)
{
int nr;
char *buf = parsefile->buf;
- parsenextc = buf;
+ parsefile->nextc = buf;
retry:
#ifndef SMALL
@@ -184,11 +165,6 @@ retry:
} else
#endif
-
-#ifdef HETIO
- nr = hetio_read_input(parsefile->fd);
- if (nr == -255)
-#endif
nr = read(parsefile->fd, buf, IBUFSIZ - 1);
@@ -219,8 +195,7 @@ retry:
* 4) Process input up to the next newline, deleting nul characters.
*/
-int
-preadbuffer(void)
+static int preadbuffer(void)
{
char *q;
int more;
@@ -229,34 +204,33 @@ preadbuffer(void)
#endif
char savec;
- while (unlikely(parsefile->strpush)) {
+ if (unlikely(parsefile->strpush)) {
if (
- parsenleft == -1 && parsefile->strpush->ap &&
- parsenextc[-1] != ' ' && parsenextc[-1] != '\t'
+ parsefile->nleft == -1 &&
+ parsefile->strpush->ap &&
+ parsefile->nextc[-1] != ' ' &&
+ parsefile->nextc[-1] != '\t'
) {
return PEOA;
}
popstring();
- if (--parsenleft >= 0)
- return (signed char)*parsenextc++;
+ return pgetc();
}
- if (unlikely(parsenleft == EOF_NLEFT || parsefile->buf == NULL))
+ if (unlikely(parsefile->nleft == EOF_NLEFT ||
+ parsefile->buf == NULL))
return PEOF;
- flushout(&output);
-#ifdef FLUSHERR
- flushout(&errout);
-#endif
+ flushall();
- more = parselleft;
+ more = parsefile->lleft;
if (more <= 0) {
again:
if ((more = preadfd()) <= 0) {
- parselleft = parsenleft = EOF_NLEFT;
+ parsefile->lleft = parsefile->nleft = EOF_NLEFT;
return PEOF;
}
}
- q = parsenextc;
+ q = parsefile->nextc;
/* delete nul characters */
#ifndef SMALL
@@ -274,7 +248,7 @@ again:
q++;
if (c == '\n') {
- parsenleft = q - parsenextc - 1;
+ parsefile->nleft = q - parsefile->nextc - 1;
break;
}
@@ -291,13 +265,13 @@ again:
}
if (more <= 0) {
- parsenleft = q - parsenextc - 1;
- if (parsenleft < 0)
+ parsefile->nleft = q - parsefile->nextc - 1;
+ if (parsefile->nleft < 0)
goto again;
break;
}
}
- parselleft = more;
+ parsefile->lleft = more;
savec = *q;
*q = '\0';
@@ -307,13 +281,13 @@ again:
HistEvent he;
INTOFF;
history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
- parsenextc);
+ parsefile->nextc);
INTON;
}
#endif
if (vflag) {
- out2str(parsenextc);
+ out2str(parsefile->nextc);
#ifdef FLUSHERR
flushout(out2);
#endif
@@ -321,19 +295,18 @@ again:
*q = savec;
- return (signed char)*parsenextc++;
+ return (signed char)*parsefile->nextc++;
}
/*
- * Undo the last call to pgetc. Only one character may be pushed back.
+ * Undo a call to pgetc. Only two characters may be pushed back.
* PEOF may be pushed back.
*/
void
pungetc(void)
{
- parsenleft++;
- parsenextc--;
+ parsefile->unget++;
}
/*
@@ -355,15 +328,18 @@ pushstring(char *s, void *ap)
parsefile->strpush = sp;
} else
sp = parsefile->strpush = &(parsefile->basestrpush);
- sp->prevstring = parsenextc;
- sp->prevnleft = parsenleft;
+ sp->prevstring = parsefile->nextc;
+ sp->prevnleft = parsefile->nleft;
+ sp->unget = parsefile->unget;
+ memcpy(sp->lastc, parsefile->lastc, sizeof(sp->lastc));
sp->ap = (struct alias *)ap;
if (ap) {
((struct alias *)ap)->flag |= ALIASINUSE;
sp->string = s;
}
- parsenextc = s;
- parsenleft = len;
+ parsefile->nextc = s;
+ parsefile->nleft = len;
+ parsefile->unget = 0;
INTON;
}
@@ -374,7 +350,8 @@ popstring(void)
INTOFF;
if (sp->ap) {
- if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') {
+ if (parsefile->nextc[-1] == ' ' ||
+ parsefile->nextc[-1] == '\t') {
checkkwd |= CHKALIAS;
}
if (sp->string != sp->ap->val) {
@@ -385,8 +362,10 @@ popstring(void)
unalias(sp->ap->name);
}
}
- parsenextc = sp->prevstring;
- parsenleft = sp->prevnleft;
+ parsefile->nextc = sp->prevstring;
+ parsefile->nleft = sp->prevnleft;
+ parsefile->unget = sp->unget;
+ memcpy(parsefile->lastc, sp->lastc, sizeof(sp->lastc));
/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
parsefile->strpush = sp->prev;
if (sp != &(parsefile->basestrpush))
@@ -435,7 +414,7 @@ setinputfd(int fd, int push)
parsefile->fd = fd;
if (parsefile->buf == NULL)
parsefile->buf = ckmalloc(IBUFSIZ);
- parselleft = parsenleft = 0;
+ parsefile->lleft = parsefile->nleft = 0;
plinno = 1;
}
@@ -449,8 +428,8 @@ setinputstring(char *string)
{
INTOFF;
pushfile();
- parsenextc = string;
- parsenleft = strlen(string);
+ parsefile->nextc = string;
+ parsefile->nleft = strlen(string);
parsefile->buf = NULL;
plinno = 1;
INTON;
@@ -468,15 +447,12 @@ pushfile(void)
{
struct parsefile *pf;
- parsefile->nleft = parsenleft;
- parsefile->lleft = parselleft;
- parsefile->nextc = parsenextc;
- parsefile->linno = plinno;
pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
pf->prev = parsefile;
pf->fd = -1;
pf->strpush = NULL;
pf->basestrpush.prev = NULL;
+ pf->unget = 0;
parsefile = pf;
}
@@ -495,10 +471,6 @@ popfile(void)
popstring();
parsefile = pf->prev;
ckfree(pf);
- parsenleft = parsefile->nleft;
- parselleft = parsefile->lleft;
- parsenextc = parsefile->nextc;
- plinno = parsefile->linno;
INTON;
}
diff --git a/src/input.h b/src/input.h
index 50a7797..ec97c1d 100644
--- a/src/input.h
+++ b/src/input.h
@@ -41,18 +41,56 @@ enum {
INPUT_NOFILE_OK = 2,
};
+struct alias;
+
+struct strpush {
+ struct strpush *prev; /* preceding string on stack */
+ char *prevstring;
+ int prevnleft;
+ struct alias *ap; /* if push was associated with an alias */
+ char *string; /* remember the string since it may change */
+
+ /* Remember last two characters for pungetc. */
+ int lastc[2];
+
+ /* Number of outstanding calls to pungetc. */
+ int unget;
+};
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+struct parsefile {
+ struct parsefile *prev; /* preceding file on stack */
+ int linno; /* current line */
+ int fd; /* file descriptor (or -1 if string) */
+ int nleft; /* number of chars left in this line */
+ int lleft; /* number of chars left in this buffer */
+ char *nextc; /* next char in buffer */
+ char *buf; /* input buffer */
+ struct strpush *strpush; /* for pushing strings at this level */
+ struct strpush basestrpush; /* so pushing one is fast */
+
+ /* Remember last two characters for pungetc. */
+ int lastc[2];
+
+ /* Number of outstanding calls to pungetc. */
+ int unget;
+};
+
+extern struct parsefile *parsefile;
+
/*
* The input line number. Input.c just defines this variable, and saves
* and restores it when files are pushed and popped. The user of this
* package must set its value.
*/
-extern int plinno;
-extern int parsenleft; /* number of characters left in input buffer */
-extern char *parsenextc; /* next character in input buffer */
+#define plinno (parsefile->linno)
int pgetc(void);
int pgetc2(void);
-int preadbuffer(void);
void pungetc(void);
void pushstring(char *, void *);
void popstring(void);
@@ -61,6 +99,3 @@ void setinputstring(char *);
void popfile(void);
void popallfiles(void);
void closescript(void);
-
-#define pgetc_macro() \
- (--parsenleft >= 0 ? (signed char)*parsenextc++ : preadbuffer())
diff --git a/src/main.c b/src/main.c
index f79ad7d..bedb663 100644
--- a/src/main.c
+++ b/src/main.c
@@ -60,10 +60,6 @@
#include "exec.h"
#include "cd.h"
-#ifdef HETIO
-#include "hetio.h"
-#endif
-
#define PROFILE 0
int rootpid;
@@ -206,10 +202,6 @@ cmdloop(int top)
int numeof = 0;
TRACE(("cmdloop(%d) called\n", top));
-#ifdef HETIO
- if(iflag && top)
- hetio_init();
-#endif
for (;;) {
int skip;
@@ -242,7 +234,7 @@ cmdloop(int top)
skip = evalskip;
if (skip) {
- evalskip &= ~SKIPFUNC;
+ evalskip &= ~(SKIPFUNC | SKIPFUNCDEF);
break;
}
}
@@ -321,15 +313,19 @@ dotcmd(int argc, char **argv)
{
int status = 0;
- if (argc >= 2) { /* That's what SVR2 does */
+ nextopt(nullstr);
+ argv = argptr;
+
+ if (*argv) {
char *fullname;
- fullname = find_dot_file(argv[1]);
+ fullname = find_dot_file(*argv);
setinputfile(fullname, INPUT_PUSH_FILE);
commandname = fullname;
status = cmdloop(0);
popfile();
}
+
return status;
}
@@ -339,8 +335,15 @@ exitcmd(int argc, char **argv)
{
if (stoppedjobs())
return 0;
- if (argc > 1)
- exitstatus = number(argv[1]);
+
+ if (argc > 1) {
+ int status = number(argv[1]);
+
+ exitstatus = status;
+ if (savestatus >= 0)
+ savestatus = status;
+ }
+
exraise(EXEXIT);
/* NOTREACHED */
}
diff --git a/src/mkbuiltins b/src/mkbuiltins
index f562ae2..8c74d6b 100644
--- a/src/mkbuiltins
+++ b/src/mkbuiltins
@@ -69,7 +69,7 @@ cat <<\!
#include "builtins.h"
!
-< $builtins sed '/^#/d; /^$/d' > $temp
+< $builtins sed '/^#/d; /^ *$/d' > $temp
awk '{ printf "int %s(int, char **);\n", $1}' $temp
echo '
const struct builtincmd builtincmd[] = {'
@@ -78,7 +78,7 @@ awk '{ for (i = 2 ; i <= NF ; i++) {
if ($i ~ /^-/)
line = $(++i) "\t" line
print line
- }}' $temp | LC_COLLATE=C sort -k 1,1 | tee $temp2 | awk '{
+ }}' $temp | LC_ALL= LC_COLLATE=C sort -k 1,1 | tee $temp2 | awk '{
opt = ""
if (NF > 2) {
opt = substr($2, 2)
@@ -97,8 +97,9 @@ cat <<\!
*/
!
-sed 's/ -[a-z]*//' $temp2 | nl -b a -v 0 | LC_COLLATE=C sort -u -k 3,3 |
-tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |
+sed 's/ -[a-z]*//' $temp2 | nl -b a -v 0 |
+ LC_ALL= LC_COLLATE=C sort -u -k 3,3 |
+ tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ |
awk '{ printf "#define %s (builtincmd + %d)\n", $3, $1}'
printf '\n#define NUMBUILTINS %d\n' $(wc -l < $temp2)
echo '
diff --git a/src/output.c b/src/output.c
index f62e7ea..4d3b4c2 100644
--- a/src/output.c
+++ b/src/output.c
@@ -99,9 +99,6 @@ struct output *out1 = &output;
struct output *out2 = &errout;
-#ifndef USE_GLIBC_STDIO
-static void __outstr(const char *, size_t, struct output *);
-#endif
static int xvsnprintf(char *, size_t, const char *, va_list);
@@ -134,16 +131,20 @@ RESET {
#endif
-#ifndef USE_GLIBC_STDIO
-static void
-__outstr(const char *p, size_t len, struct output *dest)
+void
+outmem(const char *p, size_t len, struct output *dest)
{
+#ifdef USE_GLIBC_STDIO
+ INTOFF;
+ fwrite(p, 1, len, dest->stream);
+ INTON;
+#else
size_t bufsize;
size_t offset;
size_t nleft;
nleft = dest->end - dest->nextc;
- if (nleft >= len) {
+ if (likely(nleft >= len)) {
buffered:
dest->nextc = mempcpy(dest->nextc, p, len);
return;
@@ -153,10 +154,13 @@ buffered:
if (!bufsize) {
;
} else if (dest->buf == NULL) {
+#ifdef notyet
if (dest->fd == MEM_OUT && len > bufsize) {
bufsize = len;
}
+#endif
offset = 0;
+#ifdef notyet
goto alloc;
} else if (dest->fd == MEM_OUT) {
offset = bufsize;
@@ -168,6 +172,7 @@ buffered:
if (bufsize < offset)
goto err;
alloc:
+#endif
INTOFF;
dest->buf = ckrealloc(dest->buf, bufsize);
dest->bufsize = bufsize;
@@ -183,11 +188,13 @@ alloc:
goto buffered;
if ((xwrite(dest->fd, p, len))) {
+#ifdef notyet
err:
+#endif
dest->flags |= OUTPUT_ERR;
}
-}
#endif
+}
void
@@ -201,7 +208,7 @@ outstr(const char *p, struct output *file)
size_t len;
len = strlen(p);
- __outstr(p, len, file);
+ outmem(p, len, file);
#endif
}
@@ -213,7 +220,7 @@ void
outcslow(int c, struct output *dest)
{
char buf = c;
- __outstr(&buf, 1, dest);
+ outmem(&buf, 1, dest);
}
#endif
@@ -283,35 +290,58 @@ fmtstr(char *outbuf, size_t length, const char *fmt, ...)
}
+static int xvasprintf(char **sp, size_t size, const char *f, va_list ap)
+{
+ char *s;
+ int len;
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ len = xvsnprintf(*sp, size, f, ap2);
+ va_end(ap2);
+ if (len < 0)
+ sh_error("xvsnprintf failed");
+ if (len < size)
+ return len;
+
+ s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
+ *sp = s;
+ len = xvsnprintf(s, len + 1, f, ap);
+ return len;
+}
+
+
+int xasprintf(char **sp, const char *f, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, f);
+ ret = xvasprintf(sp, 0, f, ap);
+ va_end(ap);
+ return ret;
+}
+
+
#ifndef USE_GLIBC_STDIO
void
doformat(struct output *dest, const char *f, va_list ap)
{
struct stackmark smark;
char *s;
- int len, ret;
- size_t size;
- va_list ap2;
+ int len;
+ int olen;
- va_copy(ap2, ap);
- size = dest->end - dest->nextc;
- len = xvsnprintf(dest->nextc, size, f, ap2);
- va_end(ap2);
- if (len < 0) {
- dest->flags |= OUTPUT_ERR;
- return;
- }
- if (len < size) {
+ setstackmark(&smark);
+ s = dest->nextc;
+ olen = dest->end - dest->nextc;
+ len = xvasprintf(&s, olen, f, ap);
+ if (likely(olen > len)) {
dest->nextc += len;
- return;
+ goto out;
}
- setstackmark(&smark);
- s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1);
- ret = xvsnprintf(s, len + 1, f, ap);
- if (ret == len)
- __outstr(s, len, dest);
- else
- dest->flags |= OUTPUT_ERR;
+ outmem(s, len, dest);
+out:
popstackmark(&smark);
}
#endif
diff --git a/src/output.h b/src/output.h
index f853e9d..c43d493 100644
--- a/src/output.h
+++ b/src/output.h
@@ -63,6 +63,7 @@ extern struct output memout;
extern struct output *out1;
extern struct output *out2;
+void outmem(const char *, size_t, struct output *);
void outstr(const char *, struct output *);
#ifndef USE_GLIBC_STDIO
void outcslow(int, struct output *);
@@ -75,6 +76,7 @@ void out1fmt(const char *, ...)
__attribute__((__format__(__printf__,1,2)));
int fmtstr(char *, size_t, const char *, ...)
__attribute__((__format__(__printf__,3,4)));
+int xasprintf(char **, const char *, ...);
#ifndef USE_GLIBC_STDIO
void doformat(struct output *, const char *, va_list);
#endif
@@ -115,6 +117,7 @@ static inline void outc(int ch, struct output *file)
#endif
#define out1c(c) outc((c), out1)
#define out2c(c) outcslow((c), out2)
+#define out1mem(s, l) outmem((s), (l), out1)
#define out1str(s) outstr((s), out1)
#define out2str(s) outstr((s), out2)
#define outerr(f) (f)->flags
diff --git a/src/parser.c b/src/parser.c
index 572cbcd..382658e 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -135,19 +135,13 @@ static inline int realeofmark(const char *eofmark)
union node *
parsecmd(int interact)
{
- int t;
-
tokpushback = 0;
+ checkkwd = 0;
+ heredoclist = 0;
doprompt = interact;
if (doprompt)
setprompt(doprompt);
needprompt = 0;
- t = readtoken();
- if (t == TEOF)
- return NEOF;
- if (t == TNL)
- return NULL;
- tokpushback++;
return list(1);
}
@@ -158,11 +152,27 @@ list(int nlflag)
union node *n1, *n2, *n3;
int tok;
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if (nlflag == 2 && tokendlist[peektoken()])
- return NULL;
n1 = NULL;
for (;;) {
+ switch (peektoken()) {
+ case TNL:
+ if (!(nlflag & 1))
+ break;
+ parseheredoc();
+ return n1;
+
+ case TEOF:
+ if (!n1 && (nlflag & 1))
+ n1 = NEOF;
+ parseheredoc();
+ return n1;
+ }
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (nlflag == 2 && tokendlist[peektoken()])
+ return n1;
+ nlflag |= 2;
+
n2 = andor();
tok = readtoken();
if (tok == TBACKGND) {
@@ -189,31 +199,15 @@ list(int nlflag)
n1 = n3;
}
switch (tok) {
- case TBACKGND:
- case TSEMI:
- tok = readtoken();
- /* fall through */
case TNL:
- if (tok == TNL) {
- parseheredoc();
- if (nlflag == 1)
- return n1;
- } else {
- tokpushback++;
- }
- checkkwd = CHKNL | CHKKWD | CHKALIAS;
- if (tokendlist[peektoken()])
- return n1;
- break;
case TEOF:
- if (heredoclist)
- parseheredoc();
- else
- pungetc(); /* push back EOF on input */
tokpushback++;
- return n1;
+ /* fall through */
+ case TBACKGND:
+ case TSEMI:
+ break;
default:
- if (nlflag == 1)
+ if ((nlflag & 1))
synexpect(-1);
tokpushback++;
return n1;
@@ -743,6 +737,19 @@ out:
return (t);
}
+static void nlprompt(void)
+{
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+}
+
+static void nlnoprompt(void)
+{
+ plinno++;
+ needprompt = doprompt;
+}
+
/*
* Read the next input token.
@@ -775,7 +782,7 @@ xxreadtoken(void)
setprompt(2);
}
for (;;) { /* until token or start of word found */
- c = pgetc_macro();
+ c = pgetc();
switch (c) {
case ' ': case '\t':
case PEOA:
@@ -786,16 +793,13 @@ xxreadtoken(void)
continue;
case '\\':
if (pgetc() == '\n') {
- plinno++;
- if (doprompt)
- setprompt(2);
+ nlprompt();
continue;
}
pungetc();
goto breakloop;
case '\n':
- plinno++;
- needprompt = doprompt;
+ nlnoprompt();
RETURN(TNL);
case PEOF:
RETURN(TEOF);
@@ -827,6 +831,22 @@ breakloop:
#undef RETURN
}
+static int pgetc_eatbnl(void)
+{
+ int c;
+
+ while ((c = pgetc()) == '\\') {
+ if (pgetc() != '\n') {
+ pungetc();
+ break;
+ }
+
+ nlprompt();
+ }
+
+ return c;
+}
+
/*
@@ -895,9 +915,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
if (syntax == BASESYNTAX)
goto endword; /* exit outer loop */
USTPUTC(c, out);
- plinno++;
- if (doprompt)
- setprompt(2);
+ nlprompt();
c = pgetc();
goto loop; /* continue outer loop */
case CWORD:
@@ -916,9 +934,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
USTPUTC('\\', out);
pungetc();
} else if (c == '\n') {
- plinno++;
- if (doprompt)
- setprompt(2);
+ nlprompt();
} else {
if (
dblquote &&
@@ -1009,7 +1025,7 @@ quotemark:
USTPUTC(c, out);
}
}
- c = pgetc_macro();
+ c = pgetc();
}
}
endword:
@@ -1074,8 +1090,7 @@ checkend: {
if (c == '\n' || c == PEOF) {
c = PEOF;
- plinno++;
- needprompt = doprompt;
+ nlnoprompt();
} else {
int len;
@@ -1179,7 +1194,7 @@ parsesub: {
char *p;
static const char types[] = "}-+?=";
- c = pgetc();
+ c = pgetc_eatbnl();
if (
(checkkwd & CHKEOFMARK) ||
c <= PEOA ||
@@ -1188,7 +1203,7 @@ parsesub: {
USTPUTC('$', out);
pungetc();
} else if (c == '(') { /* $(command) or $((arith)) */
- if (pgetc() == '(') {
+ if (pgetc_eatbnl() == '(') {
PARSEARITH();
} else {
pungetc();
@@ -1200,25 +1215,24 @@ parsesub: {
STADJUST(1, out);
subtype = VSNORMAL;
if (likely(c == '{')) {
- c = pgetc();
+ c = pgetc_eatbnl();
subtype = 0;
}
varname:
if (is_name(c)) {
do {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_eatbnl();
} while (is_in_name(c));
} else if (is_digit(c)) {
do {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_eatbnl();
} while (is_digit(c));
- }
- else if (is_special(c)) {
+ } else {
int cc = c;
- c = pgetc();
+ c = pgetc_eatbnl();
if (!subtype && cc == '#') {
subtype = VSLENGTH;
@@ -1227,7 +1241,7 @@ varname:
goto varname;
cc = c;
- c = pgetc();
+ c = pgetc_eatbnl();
if (cc == '}' || c != '}') {
pungetc();
subtype = 0;
@@ -1236,16 +1250,20 @@ varname:
}
}
+ if (!is_special(cc)) {
+ if (subtype == VSLENGTH)
+ subtype = 0;
+ goto badsub;
+ }
+
USTPUTC(cc, out);
}
- else
- goto badsub;
if (subtype == 0) {
switch (c) {
case ':':
subtype = VSNUL;
- c = pgetc();
+ c = pgetc_eatbnl();
/*FALLTHROUGH*/
default:
p = strchr(types, c);
@@ -1259,7 +1277,7 @@ varname:
int cc = c;
subtype = c == '#' ? VSTRIMLEFT :
VSTRIMRIGHT;
- c = pgetc();
+ c = pgetc_eatbnl();
if (c == cc)
subtype++;
else
@@ -1324,9 +1342,7 @@ parsebackq: {
case '\\':
if ((pc = pgetc()) == '\n') {
- plinno++;
- if (doprompt)
- setprompt(2);
+ nlprompt();
/*
* If eating a newline, avoid putting
* the newline into the new character
@@ -1348,8 +1364,7 @@ parsebackq: {
synerror("EOF in backquote substitution");
case '\n':
- plinno++;
- needprompt = doprompt;
+ nlnoprompt();
break;
default:
@@ -1427,10 +1442,6 @@ parsearith: {
#ifdef mkinit
INCLUDE "parser.h"
-RESET {
- tokpushback = 0;
- checkkwd = 0;
-}
#endif
diff --git a/src/trap.c b/src/trap.c
index 17316c9..82d4263 100644
--- a/src/trap.c
+++ b/src/trap.c
@@ -51,10 +51,6 @@
#include "trap.h"
#include "mystring.h"
-#ifdef HETIO
-#include "hetio.h"
-#endif
-
/*
* Sigmode records the current value of the signal handlers for the various
* modes. A value of zero means that the current handler is not known.
@@ -314,25 +310,40 @@ void dotrap(void)
char *p;
char *q;
int i;
- int savestatus;
+ int status, last_status;
- savestatus = exitstatus;
+ if (!pendingsigs)
+ return;
+
+ status = savestatus;
+ last_status = status;
+ if (likely(status < 0)) {
+ status = exitstatus;
+ savestatus = status;
+ }
pendingsigs = 0;
barrier();
for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
if (!*q)
continue;
+
+ if (evalskip) {
+ pendingsigs = i + 1;
+ break;
+ }
+
*q = 0;
p = trap[i + 1];
if (!p)
continue;
evalstring(p, 0);
- exitstatus = savestatus;
- if (evalskip)
- break;
+ if (evalskip != SKIPFUNC)
+ exitstatus = status;
}
+
+ savestatus = last_status;
}
@@ -366,18 +377,11 @@ exitshell(void)
{
struct jmploc loc;
char *p;
- volatile int status;
-#ifdef HETIO
- hetio_reset_term();
-#endif
- status = exitstatus;
- TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
- if (setjmp(loc.loc)) {
- if (exception == EXEXIT)
- status = exitstatus;
+ savestatus = exitstatus;
+ TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
+ if (setjmp(loc.loc))
goto out;
- }
handler = &loc;
if ((p = trap[0])) {
trap[0] = NULL;
@@ -392,7 +396,7 @@ out:
if (likely(!setjmp(loc.loc)))
setjobctl(0);
flushall();
- _exit(status);
+ _exit(savestatus);
/* NOTREACHED */
}
diff --git a/src/var.c b/src/var.c
index fa24854..cc6f7f2 100644
--- a/src/var.c
+++ b/src/var.c
@@ -80,6 +80,7 @@ const char defifsvar[] = "IFS= \t\n";
#else
const char defifs[] = " \t\n";
#endif
+MKINIT char defoptindvar[] = "OPTIND=1";
int lineno;
char linenovar[sizeof("LINENO=")+sizeof(int)*CHAR_BIT/3+1] = "LINENO=";
@@ -100,7 +101,7 @@ struct var varinit[] = {
{ 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 },
{ 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 },
{ 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 },
- { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset },
+ { 0, VSTRFIXED|VTEXTFIXED, defoptindvar, getoptsreset },
#ifdef WITH_LINENO
{ 0, VSTRFIXED|VTEXTFIXED, linenovar, 0 },
#endif
@@ -142,7 +143,7 @@ INIT {
}
}
- setvarint("OPTIND", 1, 0);
+ setvareq(defoptindvar, VTEXTFIXED);
fmtstr(ppid + 5, sizeof(ppid) - 5, "%ld", (long) getppid());
setvareq(ppid, VTEXTFIXED);