diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-10-13 10:49:35 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-10-13 10:49:35 +0900 |
commit | e31a2fb64fa509b9d22b7437b1833d6b0d62ee48 (patch) | |
tree | 0af002f5f8523176440deccb21b312aa5a83b0fc | |
parent | c90fa15cbf2fc4380c58ff1b32f31d9ad6f57f81 (diff) | |
download | dash-e31a2fb64fa509b9d22b7437b1833d6b0d62ee48.tar.gz dash-e31a2fb64fa509b9d22b7437b1833d6b0d62ee48.tar.bz2 dash-e31a2fb64fa509b9d22b7437b1833d6b0d62ee48.zip |
Imported Upstream version 0.5.10upstream/0.5.10
-rw-r--r-- | config.h.in | 3 | ||||
-rwxr-xr-x | configure | 49 | ||||
-rw-r--r-- | configure.ac | 18 | ||||
-rw-r--r-- | src/Makefile.in | 88 | ||||
-rw-r--r-- | src/bltin/printf.c | 43 | ||||
-rw-r--r-- | src/bltin/test.c | 16 | ||||
-rw-r--r-- | src/dash.1 | 15 | ||||
-rw-r--r-- | src/eval.c | 17 | ||||
-rw-r--r-- | src/exec.c | 15 | ||||
-rw-r--r-- | src/expand.c | 151 | ||||
-rw-r--r-- | src/expand.h | 1 | ||||
-rw-r--r-- | src/histedit.c | 1 | ||||
-rw-r--r-- | src/input.c | 16 | ||||
-rw-r--r-- | src/input.h | 1 | ||||
-rw-r--r-- | src/jobs.c | 12 | ||||
-rw-r--r-- | src/miscbltin.c | 2 | ||||
-rw-r--r-- | src/mystring.c | 2 | ||||
-rw-r--r-- | src/parser.c | 249 | ||||
-rw-r--r-- | src/redir.c | 2 | ||||
-rw-r--r-- | src/trap.c | 10 | ||||
-rw-r--r-- | src/trap.h | 2 |
21 files changed, 419 insertions, 294 deletions
diff --git a/config.h.in b/config.h.in index 7a2b262..38274d2 100644 --- a/config.h.in +++ b/config.h.in @@ -79,6 +79,9 @@ /* Define to 1 if you have the `strtoumax' function. */ #undef HAVE_STRTOUMAX +/* Define if your `struct stat' has `st_mtim' */ +#undef HAVE_ST_MTIM + /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF @@ -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.9.1. +# Generated by GNU Autoconf 2.69 for dash 0.5.10. # # # 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.9.1' -PACKAGE_STRING='dash 0.5.9.1' +PACKAGE_VERSION='0.5.10' +PACKAGE_STRING='dash 0.5.10' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1269,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.9.1 to adapt to many kinds of systems. +\`configure' configures dash 0.5.10 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1335,7 +1335,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dash 0.5.9.1:";; + short | recursive ) echo "Configuration of dash 0.5.10:";; esac cat <<\_ACEOF @@ -1440,7 +1440,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -dash configure 0.5.9.1 +dash configure 0.5.10 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2034,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.9.1, which was +It was created by dash $as_me 0.5.10, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2849,7 +2849,7 @@ fi # Define the identity of the package. PACKAGE='dash' - VERSION='0.5.9.1' + VERSION='0.5.10' cat >>confdefs.h <<_ACEOF @@ -4715,6 +4715,35 @@ $as_echo "#define open64 open" >>confdefs.h fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stat::st_mtim" >&5 +$as_echo_n "checking for stat::st_mtim... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <time.h> +#include <sys/time.h> +#include <sys/stat.h> +int +main () +{ +struct stat foo; return sizeof(foo.st_mtim.tv_sec) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_st_mtim=yes +else + have_st_mtim=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_st_mtim" >&5 +$as_echo "$have_st_mtim" >&6; } +if test "$have_st_mtim" = "yes"; then + +$as_echo "#define HAVE_ST_MTIM 1" >>confdefs.h + +fi + # Check whether --with-libedit was given. if test "${with_libedit+set}" = set; then : @@ -5313,7 +5342,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.9.1, which was +This file was extended by dash $as_me 0.5.10, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5379,7 +5408,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.9.1 +dash config.status 0.5.10 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 9c4ced8..c36f949 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ -AC_INIT(dash, 0.5.9.1) -AM_INIT_AUTOMAKE([foreign]) +AC_INIT(dash, 0.5.10) +AM_INIT_AUTOMAKE([foreign subdir-objects]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS(config.h) @@ -149,6 +149,20 @@ AC_CHECK_FUNC(open64,, [ AC_DEFINE(open64, open, [64-bit operations are the same as 32-bit]) ]) +dnl Check if struct stat has st_mtim. +AC_MSG_CHECKING(for stat::st_mtim) +AC_COMPILE_IFELSE( +[AC_LANG_PROGRAM([#include <time.h> +#include <sys/time.h> +#include <sys/stat.h>], +[struct stat foo; return sizeof(foo.st_mtim.tv_sec)])], +have_st_mtim=yes, have_st_mtim=no) +AC_MSG_RESULT($have_st_mtim) +if test "$have_st_mtim" = "yes"; then + AC_DEFINE([HAVE_ST_MTIM], [1], + [Define if your `struct stat' has `st_mtim']) +fi + AC_ARG_WITH(libedit, AS_HELP_STRING(--with-libedit, [Compile with libedit support])) use_libedit= if test "$with_libedit" = "yes"; then diff --git a/src/Makefile.in b/src/Makefile.in index 0bd9ad1..059c6e1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -62,6 +62,7 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" PROGRAMS = $(bin_PROGRAMS) +am__dirstamp = $(am__leading_dot)dirstamp am__objects_1 = alias.$(OBJEXT) arith_yacc.$(OBJEXT) \ arith_yylex.$(OBJEXT) cd.$(OBJEXT) error.$(OBJEXT) \ eval.$(OBJEXT) exec.$(OBJEXT) expand.$(OBJEXT) \ @@ -69,8 +70,8 @@ am__objects_1 = alias.$(OBJEXT) arith_yacc.$(OBJEXT) \ mail.$(OBJEXT) main.$(OBJEXT) memalloc.$(OBJEXT) \ miscbltin.$(OBJEXT) mystring.$(OBJEXT) options.$(OBJEXT) \ parser.$(OBJEXT) redir.$(OBJEXT) show.$(OBJEXT) trap.$(OBJEXT) \ - output.$(OBJEXT) printf.$(OBJEXT) system.$(OBJEXT) \ - test.$(OBJEXT) times.$(OBJEXT) var.$(OBJEXT) + output.$(OBJEXT) bltin/printf.$(OBJEXT) system.$(OBJEXT) \ + bltin/test.$(OBJEXT) bltin/times.$(OBJEXT) var.$(OBJEXT) am_dash_OBJECTS = $(am__objects_1) dash_OBJECTS = $(am_dash_OBJECTS) dash_DEPENDENCIES = builtins.o init.o nodes.o signames.o syntax.o @@ -329,12 +330,27 @@ uninstall-binPROGRAMS: clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +bltin/$(am__dirstamp): + @$(MKDIR_P) bltin + @: > bltin/$(am__dirstamp) +bltin/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) bltin/$(DEPDIR) + @: > bltin/$(DEPDIR)/$(am__dirstamp) +bltin/printf.$(OBJEXT): bltin/$(am__dirstamp) \ + bltin/$(DEPDIR)/$(am__dirstamp) +bltin/test.$(OBJEXT): bltin/$(am__dirstamp) \ + bltin/$(DEPDIR)/$(am__dirstamp) +bltin/times.$(OBJEXT): bltin/$(am__dirstamp) \ + bltin/$(DEPDIR)/$(am__dirstamp) dash$(EXEEXT): $(dash_OBJECTS) $(dash_DEPENDENCIES) $(EXTRA_dash_DEPENDENCIES) @rm -f dash$(EXEEXT) $(LINK) $(dash_OBJECTS) $(dash_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) + -rm -f bltin/printf.$(OBJEXT) + -rm -f bltin/test.$(OBJEXT) + -rm -f bltin/times.$(OBJEXT) distclean-compile: -rm -f *.tab.c @@ -358,70 +374,30 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/redir.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/show.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/system.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/times.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/var.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bltin/$(DEPDIR)/printf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bltin/$(DEPDIR)/test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@bltin/$(DEPDIR)/times.Po@am__quote@ .c.o: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c $< +@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ $< .c.obj: -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` - -printf.o: bltin/printf.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT printf.o -MD -MP -MF $(DEPDIR)/printf.Tpo -c -o printf.o `test -f 'bltin/printf.c' || echo '$(srcdir)/'`bltin/printf.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/printf.Tpo $(DEPDIR)/printf.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bltin/printf.c' object='printf.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o printf.o `test -f 'bltin/printf.c' || echo '$(srcdir)/'`bltin/printf.c - -printf.obj: bltin/printf.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT printf.obj -MD -MP -MF $(DEPDIR)/printf.Tpo -c -o printf.obj `if test -f 'bltin/printf.c'; then $(CYGPATH_W) 'bltin/printf.c'; else $(CYGPATH_W) '$(srcdir)/bltin/printf.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/printf.Tpo $(DEPDIR)/printf.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bltin/printf.c' object='printf.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o printf.obj `if test -f 'bltin/printf.c'; then $(CYGPATH_W) 'bltin/printf.c'; else $(CYGPATH_W) '$(srcdir)/bltin/printf.c'; fi` - -test.o: bltin/test.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test.o -MD -MP -MF $(DEPDIR)/test.Tpo -c -o test.o `test -f 'bltin/test.c' || echo '$(srcdir)/'`bltin/test.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test.Tpo $(DEPDIR)/test.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bltin/test.c' object='test.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test.o `test -f 'bltin/test.c' || echo '$(srcdir)/'`bltin/test.c - -test.obj: bltin/test.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test.obj -MD -MP -MF $(DEPDIR)/test.Tpo -c -o test.obj `if test -f 'bltin/test.c'; then $(CYGPATH_W) 'bltin/test.c'; else $(CYGPATH_W) '$(srcdir)/bltin/test.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test.Tpo $(DEPDIR)/test.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bltin/test.c' object='test.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test.obj `if test -f 'bltin/test.c'; then $(CYGPATH_W) 'bltin/test.c'; else $(CYGPATH_W) '$(srcdir)/bltin/test.c'; fi` - -times.o: bltin/times.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT times.o -MD -MP -MF $(DEPDIR)/times.Tpo -c -o times.o `test -f 'bltin/times.c' || echo '$(srcdir)/'`bltin/times.c -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/times.Tpo $(DEPDIR)/times.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bltin/times.c' object='times.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o times.o `test -f 'bltin/times.c' || echo '$(srcdir)/'`bltin/times.c - -times.obj: bltin/times.c -@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT times.obj -MD -MP -MF $(DEPDIR)/times.Tpo -c -o times.obj `if test -f 'bltin/times.c'; then $(CYGPATH_W) 'bltin/times.c'; else $(CYGPATH_W) '$(srcdir)/bltin/times.c'; fi` -@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/times.Tpo $(DEPDIR)/times.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bltin/times.c' object='times.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o times.obj `if test -f 'bltin/times.c'; then $(CYGPATH_W) 'bltin/times.c'; else $(CYGPATH_W) '$(srcdir)/bltin/times.c'; fi` +@am__fastdepCC_FALSE@ $(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ @@ -597,6 +573,8 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f bltin/$(DEPDIR)/$(am__dirstamp) + -rm -f bltin/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -607,7 +585,7 @@ clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) + -rm -rf ./$(DEPDIR) bltin/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -653,7 +631,7 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) + -rm -rf ./$(DEPDIR) bltin/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/bltin/printf.c b/src/bltin/printf.c index a626cee..7785735 100644 --- a/src/bltin/printf.c +++ b/src/bltin/printf.c @@ -98,20 +98,27 @@ static int print_escape_str(const char *f, int *param, int *array, char *s) int total; setstackmark(&smark); - done = conv_escape_str(s, &p); - q = stackblock(); - len = p - q; + done = conv_escape_str(s, &q); + p = stackblock(); + len = q - p; + total = len - 1; + + q[-1] = (!!((f[1] - 's') | done) - 1) & f[2]; + total += !!q[-1]; + if (f[1] == 's') + goto easy; - p = makestrspace(len, p); - memset(p, 'X', len - 1); - p[len - 1] = 0; + p = makestrspace(len, q); + memset(p, 'X', total); + p[total] = 0; q = stackblock(); total = ASPF(&p, f, p); len = strchrnul(p, 'X') - p; - memcpy(p + len, q, strchrnul(p + len, ' ') - (p + len)); + memcpy(p + len, q, strspn(p + len, "X")); +easy: out1mem(p, total); popstackmark(&smark); @@ -209,6 +216,7 @@ pc: if (print_escape_str(start, param, array, getstr())) goto out; + *fmt = 'b'; break; case 'c': { int p = getchr(); @@ -449,21 +457,22 @@ check_conversion(const char *s, const char *ep) int echocmd(int argc, char **argv) { + const char *lastfmt = snlfmt; int nonl; - nonl = *++argv ? equal(*argv, "-n") : 0; - argv += nonl; + if (*++argv && equal(*argv, "-n")) { + argv++; + lastfmt = "%s"; + } do { - int c; + const char *fmt = "%s "; + char *s = *argv; - if (likely(*argv)) - nonl += print_escape_str("%s", NULL, NULL, *argv++); - if (likely((nonl + !*argv) > 1)) - break; + if (!s || !*++argv) + fmt = lastfmt; - c = *argv ? ' ' : '\n'; - out1c(c); - } while (*argv); + nonl = print_escape_str(fmt, NULL, NULL, s ?: nullstr); + } while (!nonl && *argv); return 0; } diff --git a/src/bltin/test.c b/src/bltin/test.c index 58c05fe..d1458df 100644 --- a/src/bltin/test.c +++ b/src/bltin/test.c @@ -476,9 +476,17 @@ newerf (const char *f1, const char *f2) { struct stat b1, b2; +#ifdef HAVE_ST_MTIM + return (stat (f1, &b1) == 0 && + stat (f2, &b2) == 0 && + ( b1.st_mtim.tv_sec > b2.st_mtim.tv_sec || + (b1.st_mtim.tv_sec == b2.st_mtim.tv_sec && (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec ))) + ); +#else return (stat (f1, &b1) == 0 && stat (f2, &b2) == 0 && b1.st_mtime > b2.st_mtime); +#endif } static int @@ -486,9 +494,17 @@ olderf (const char *f1, const char *f2) { struct stat b1, b2; +#ifdef HAVE_ST_MTIM + return (stat (f1, &b1) == 0 && + stat (f2, &b2) == 0 && + (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec || + (b1.st_mtim.tv_sec == b2.st_mtim.tv_sec && (b1.st_mtim.tv_nsec < b2.st_mtim.tv_nsec ))) + ); +#else return (stat (f1, &b1) == 0 && stat (f2, &b2) == 0 && b1.st_mtime < b2.st_mtime); +#endif } static int @@ -606,11 +606,11 @@ and .Dq || are AND-OR list operators. .Dq && -executes the first command, and then executes the second command iff the -exit status of the first command is zero. +executes the first command, and then executes the second command if and only +if the exit status of the first command is zero. .Dq || -is similar, but executes the second command iff the exit status of the first -command is nonzero. +is similar, but executes the second command if and only if the exit status +of the first command is nonzero. .Dq && and .Dq || @@ -2226,13 +2226,12 @@ This mode uses commands, described below, similar to a subset of those described in the vi man page. The command .Ql set -o vi -enables vi-mode editing and place sh into vi insert mode. +enables vi-mode editing and places sh into vi insert mode. With vi-mode enabled, sh can be switched between insert mode and command mode. -The editor is not described in full here, but will be in a later document. -It's similar to vi: typing +It is similar to vi: typing .Aq ESC -will throw you into command VI command mode. +enters vi command mode. Hitting .Aq return while in command mode will pass the line to the shell. @@ -694,6 +694,7 @@ evalcommand(union node *cmd, int flags) #endif { struct localvar_list *localvar_stop; + struct parsefile *file_stop; struct redirtab *redir_stop; struct stackmark smark; union node *argp; @@ -722,6 +723,7 @@ evalcommand(union node *cmd, int flags) TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); setstackmark(&smark); localvar_stop = pushlocalvars(); + file_stop = parsefile; back_exitstatus = 0; cmdentry.cmdtype = CMDBUILTIN; @@ -848,6 +850,8 @@ bail: goto out; } + jp = NULL; + /* Execute the command. */ switch (cmdentry.cmdtype) { default: @@ -856,7 +860,6 @@ bail: INTOFF; jp = makejob(cmd, 1); if (forkshell(jp, cmd, FORK_FG) != 0) { - status = waitforjob(jp); INTON; break; } @@ -875,26 +878,26 @@ bail: if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { if (exception == EXERROR && spclbltin <= 0) { FORCEINTON; - goto readstatus; + break; } raise: longjmp(handler->loc, 1); } - goto readstatus; + break; case CMDFUNCTION: - poplocalvars(1); if (evalfun(cmdentry.u.func, argc, argv, flags)) goto raise; -readstatus: - status = exitstatus; break; } + status = waitforjob(jp); + out: if (cmd->ncmd.redirect) popredir(execcmd); unwindredir(redir_stop); + unwindfiles(file_stop); unwindlocalvars(localvar_stop); if (lastarg) /* dsl: I think this is intended to be used to support @@ -967,9 +970,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) shellparam.p = argv + 1; shellparam.optind = 1; shellparam.optoff = -1; - pushlocalvars(); evaltree(func->n.ndefun.body, flags & EV_TESTED); - poplocalvars(0); funcdone: INTOFF; loopnest = saveloopnest; @@ -743,8 +743,6 @@ describe_command(out, command, path, verbose) struct tblentry *cmdp; const struct alias *ap; - path = path ?: pathval(); - if (verbose) { outstr(command, out); } @@ -767,8 +765,17 @@ describe_command(out, command, path, verbose) goto out; } - /* Then check if it is a tracked alias */ - if ((cmdp = cmdlookup(command, 0)) != NULL) { + /* Then if the standard search path is used, check if it is + * a tracked alias. + */ + if (path == NULL) { + path = pathval(); + cmdp = cmdlookup(command, 0); + } else { + cmdp = NULL; + } + + if (cmdp != NULL) { entry.cmdtype = cmdp->cmdtype; entry.u = cmdp->param; } else { diff --git a/src/expand.c b/src/expand.c index 2a50830..7ed259a 100644 --- a/src/expand.c +++ b/src/expand.c @@ -45,7 +45,9 @@ #include <inttypes.h> #include <limits.h> #include <string.h> +#ifdef HAVE_FNMATCH #include <fnmatch.h> +#endif #ifdef HAVE_GLOB #include <glob.h> #endif @@ -83,7 +85,7 @@ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ /* Add CTLESC when necessary. */ -#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT) +#define QUOTES_ESC (EXP_FULL | EXP_CASE) /* Do not skip NUL characters. */ #define QUOTES_KEEPNUL EXP_TILDE @@ -117,12 +119,12 @@ 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, int *); +STATIC ssize_t varvalue(char *, int, int, int); STATIC void expandmeta(struct strlist *, int); #ifdef HAVE_GLOB STATIC void addglob(const glob_t *); #else -STATIC void expmeta(char *, char *); +STATIC void expmeta(char *, unsigned, unsigned); STATIC struct strlist *expsort(struct strlist *); STATIC struct strlist *msort(struct strlist *, int); #endif @@ -316,13 +318,13 @@ start: case CTLENDVAR: /* ??? */ goto breakloop; case CTLQUOTEMARK: - inquotes ^= EXP_QUOTED; /* "$@" syntax adherence hack */ - if (inquotes && !memcmp(p, dolatstr + 1, - DOLATSTRLEN - 1)) { - p = evalvar(p + 1, flag | inquotes) + 1; + if (!inquotes && !memcmp(p, dolatstr + 1, + DOLATSTRLEN - 1)) { + p = evalvar(p + 1, flag | EXP_QUOTED) + 1; goto start; } + inquotes ^= EXP_QUOTED; addquote: if (flag & QUOTES_ESC) { p--; @@ -333,16 +335,6 @@ addquote: case CTLESC: startloc++; length++; - - /* - * Quoted parameter expansion pattern: remove quote - * unless inside inner quotes or we have a literal - * backslash. - */ - if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) == - EXP_QPAT && *p != '\\') - break; - goto addquote; case CTLVAR: p = evalvar(p, flag | inquotes); @@ -651,8 +643,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla char *(*scan)(char *, char *, char *, char *, int , int); argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? - (flag & (EXP_QUOTED | EXP_QPAT) ? - EXP_QPAT : EXP_CASE) : 0)); + EXP_CASE : 0)); STPUTC('\0', expdest); argbackq = saveargbackq; startp = stackblock() + startloc; @@ -721,7 +712,6 @@ evalvar(char *p, int flag) int c; int startloc; ssize_t varlen; - int easy; int quoted; varflags = *p++; @@ -732,12 +722,11 @@ evalvar(char *p, int flag) quoted = flag & EXP_QUOTED; var = p; - easy = (!quoted || (*var == '@' && shellparam.nparam)); startloc = expdest - (char *)stackblock(); p = strchr(p, '=') + 1; again: - varlen = varvalue(var, varflags, flag, "ed); + varlen = varvalue(var, varflags, flag, quoted); if (varflags & VSNUL) varlen--; @@ -780,8 +769,11 @@ vsplus: if (subtype == VSNORMAL) { record: - if (!easy) - goto end; + if (quoted) { + quoted = *var == '@' && shellparam.nparam; + if (!quoted) + goto end; + } recordregion(startloc, expdest - (char *)stackblock(), quoted); goto end; } @@ -857,8 +849,7 @@ memtodest(const char *p, size_t len, const char *syntax, int quotes) { if (c) { if ((quotes & QUOTES_ESC) && ((syntax[c] == CCTL) || - (((quotes & EXP_FULL) || syntax != BASESYNTAX) && - syntax[c] == CBACK))) + (syntax != BASESYNTAX && syntax[c] == CBACK))) USTPUTC(CTLESC, q); } else if (!(quotes & QUOTES_KEEPNUL)) continue; @@ -887,7 +878,7 @@ strtodest(p, syntax, quotes) */ STATIC ssize_t -varvalue(char *name, int varflags, int flags, int *quotedp) +varvalue(char *name, int varflags, int flags, int quoted) { int num; char *p; @@ -896,11 +887,11 @@ varvalue(char *name, int varflags, int flags, int *quotedp) char sepc; char **ap; char const *syntax; - 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; + char c; sep = (flags & EXP_FULL) << CHAR_BIT; syntax = quoted ? DQSYNTAX : BASESYNTAX; @@ -925,7 +916,7 @@ numvar: case '-': p = makestrspace(NOPTS, expdest); for (i = NOPTS - 1; i >= 0; i--) { - if (optlist[i]) { + if (optlist[i] && optletters[i]) { USTPUTC(optletters[i], p); len++; } @@ -937,12 +928,25 @@ numvar: goto param; /* fall through */ case '*': - if (quoted) - sep = 0; - sep |= ifsset() ? ifsval()[0] : ' '; + /* We will set c to 0 or ~0 depending on whether + * we're doing field splitting. We won't do field + * splitting if either we're quoted or sep is zero. + * + * Instead of testing (quoted || !sep) the following + * trick optimises away any branches by using the + * fact that EXP_QUOTED (which is the only bit that + * can be set in quoted) is the same as EXP_FULL << + * CHAR_BIT (which is the only bit that can be set + * in sep). + */ +#if EXP_QUOTED >> CHAR_BIT != EXP_FULL +#error The following two lines expect EXP_QUOTED == EXP_FULL << CHAR_BIT +#endif + c = !((quoted | ~sep) & EXP_QUOTED) - 1; + sep &= ~quoted; + sep |= ifsset() ? (unsigned char)(c & ifsval()[0]) : ' '; param: sepc = sep; - *quotedp = !sepc; if (!(ap = shellparam.p)) return -1; while ((p = *ap++)) { @@ -1041,7 +1045,10 @@ ifsbreakup(char *string, int maxargs, struct arglist *arglist) realifs = ifsset() ? ifsval() : defifs; ifsp = &ifsfirst; do { + int afternul; + p = string + ifsp->begoff; + afternul = nulonly; nulonly = ifsp->nulonly; ifs = nulonly ? nullstr : realifs; ifsspc = 0; @@ -1106,7 +1113,7 @@ ifsbreakup(char *string, int maxargs, struct arglist *arglist) } if (isifs) { - if (!nulonly) + if (!(afternul || nulonly)) ifsspc = isdefifs; /* Ignore IFS whitespace at start */ if (q == start && ifsspc) { @@ -1197,7 +1204,8 @@ expandmeta(str, flag) ckfree(p); switch (i) { case 0: - if (!(pglob.gl_flags & GLOB_MAGCHAR)) + if ((pglob.gl_flags & (GLOB_NOMAGIC | GLOB_NOCHECK)) == + (GLOB_NOMAGIC | GLOB_NOCHECK)) goto nometa2; addglob(&pglob); globfree(&pglob); @@ -1238,6 +1246,7 @@ addglob(pglob) #else /* HAVE_GLOB */ STATIC char *expdir; +STATIC unsigned expdir_max; STATIC void @@ -1252,6 +1261,7 @@ expandmeta(struct strlist *str, int flag) struct strlist **savelastp; struct strlist *sp; char *p; + unsigned len; if (fflag) goto nometa; @@ -1261,12 +1271,11 @@ expandmeta(struct strlist *str, int flag) INTOFF; p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); - { - int i = strlen(str->text); - expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ - } + len = strlen(p); + expdir_max = len + PATH_MAX; + expdir = ckmalloc(expdir_max); - expmeta(expdir, p); + expmeta(p, len, 0); ckfree(expdir); if (p != str->text) ckfree(p); @@ -1296,8 +1305,9 @@ nometa: */ STATIC void -expmeta(char *enddir, char *name) +expmeta(char *name, unsigned name_len, unsigned expdir_len) { + char *enddir = expdir + expdir_len; char *p; const char *cp; char *start; @@ -1330,7 +1340,7 @@ expmeta(char *enddir, char *name) } } } else { - if (*p == '\\') + if (*p == '\\' && p[1]) esc++; if (p[esc] == '/') { if (metaflag) @@ -1340,15 +1350,15 @@ expmeta(char *enddir, char *name) } } if (metaflag == 0) { /* we've reached the end of the file name */ - if (enddir != expdir) - metaflag++; + if (!expdir_len) + return; p = name; do { - if (*p == '\\') + if (*p == '\\' && p[1]) p++; *enddir++ = *p; } while (*p++); - if (metaflag == 0 || lstat64(expdir, &statb) >= 0) + if (lstat64(expdir, &statb) >= 0) addfname(expdir); return; } @@ -1356,23 +1366,18 @@ expmeta(char *enddir, char *name) if (name < start) { p = name; do { - if (*p == '\\') + if (*p == '\\' && p[1]) p++; *enddir++ = *p++; } while (p < start); } - if (enddir == expdir) { + *enddir = 0; + cp = expdir; + expdir_len = enddir - cp; + if (!expdir_len) cp = "."; - } else if (enddir == expdir + 1 && *expdir == '/') { - cp = "/"; - } else { - cp = expdir; - enddir[-1] = '\0'; - } if ((dirp = opendir(cp)) == NULL) return; - if (enddir != expdir) - enddir[-1] = '/'; if (*endname == 0) { atend = 1; } else { @@ -1380,6 +1385,7 @@ expmeta(char *enddir, char *name) *endname = '\0'; endname += esc + 1; } + name_len -= endname - name; matchdot = 0; p = start; if (*p == '\\') @@ -1394,11 +1400,22 @@ expmeta(char *enddir, char *name) scopy(dp->d_name, enddir); addfname(expdir); } else { - for (p = enddir, cp = dp->d_name; - (*p++ = *cp++) != '\0';) - continue; - p[-1] = '/'; - expmeta(p, endname); + unsigned offset; + unsigned len; + + p = stpcpy(enddir, dp->d_name); + *p = '/'; + + offset = p - expdir + 1; + len = offset + name_len + NAME_MAX; + if (len > expdir_max) { + len += PATH_MAX; + expdir = ckrealloc(expdir, len); + expdir_max = len; + } + + expmeta(endname, name_len, offset); + enddir = expdir + expdir_len; } } } @@ -1644,7 +1661,6 @@ char * _rmescapes(char *str, int flag) { char *p, *q, *r; - unsigned inquotes; int notescaped; int globbing; @@ -1674,24 +1690,23 @@ _rmescapes(char *str, int flag) q = mempcpy(q, str, len); } } - inquotes = 0; globbing = flag & RMESCAPE_GLOB; notescaped = globbing; while (*p) { if (*p == (char)CTLQUOTEMARK) { - inquotes = ~inquotes; p++; notescaped = globbing; continue; } + if (*p == '\\') { + /* naked back slash */ + notescaped = 0; + goto copy; + } if (*p == (char)CTLESC) { p++; if (notescaped) *q++ = '\\'; - } else if (*p == '\\' && !inquotes) { - /* naked back slash */ - notescaped = 0; - goto copy; } notescaped = globbing; copy: diff --git a/src/expand.h b/src/expand.h index 26dc5b4..90f5328 100644 --- a/src/expand.h +++ b/src/expand.h @@ -55,7 +55,6 @@ struct arglist { #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ -#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ #define EXP_WORD 0x80 /* expand word in parameter expansion */ #define EXP_QUOTED 0x100 /* expand word in double quotes */ diff --git a/src/histedit.c b/src/histedit.c index 94465d7..f5c90ab 100644 --- a/src/histedit.c +++ b/src/histedit.c @@ -39,6 +39,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <getopt.h> /* * Editline and history functions (and glue). */ diff --git a/src/input.c b/src/input.c index 06c08d4..ae0c4c8 100644 --- a/src/input.c +++ b/src/input.c @@ -147,8 +147,12 @@ retry: static const char *rl_cp; static int el_len; - if (rl_cp == NULL) + if (rl_cp == NULL) { + struct stackmark smark; + pushstackmark(&smark, stackblocksize()); rl_cp = el_gets(el, &el_len); + popstackmark(&smark); + } if (rl_cp == NULL) nr = 0; else { @@ -475,6 +479,13 @@ popfile(void) } +void unwindfiles(struct parsefile *stop) +{ + while (parsefile != stop) + popfile(); +} + + /* * Return to top level. */ @@ -482,8 +493,7 @@ popfile(void) void popallfiles(void) { - while (parsefile != &basepf) - popfile(); + unwindfiles(&basepf); } diff --git a/src/input.h b/src/input.h index ec97c1d..a9c0517 100644 --- a/src/input.h +++ b/src/input.h @@ -97,5 +97,6 @@ void popstring(void); int setinputfile(const char *, int); void setinputstring(char *); void popfile(void); +void unwindfiles(struct parsefile *); void popallfiles(void); void closescript(void); @@ -53,6 +53,7 @@ #include <termios.h> #undef CEOF /* syntax.h redefines this */ #endif +#include "eval.h" #include "redir.h" #include "show.h" #include "main.h" @@ -648,7 +649,7 @@ out: return retval; sigout: - retval = 128 + pendingsigs; + retval = 128 + pending_sig; goto out; } @@ -973,10 +974,11 @@ waitforjob(struct job *jp) { int st; - TRACE(("waitforjob(%%%d) called\n", jobno(jp))); - while (jp->state == JOBRUNNING) { + TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0)); + while ((jp && jp->state == JOBRUNNING) || gotsigchld) dowait(DOWAIT_BLOCK, jp); - } + if (!jp) + return exitstatus; st = getstatus(jp); #if JOBS if (jp->jobctl) { @@ -1147,7 +1149,7 @@ waitproc(int block, int *status) sigfillset(&mask); sigprocmask(SIG_SETMASK, &mask, &oldmask); - while (!gotsigchld && !pendingsigs) + while (!gotsigchld && !pending_sig) sigsuspend(&oldmask); sigclearmask(); diff --git a/src/miscbltin.c b/src/miscbltin.c index 39b9c47..5ccbbcb 100644 --- a/src/miscbltin.c +++ b/src/miscbltin.c @@ -152,7 +152,7 @@ readcmd(int argc, char **argv) case 1: break; default: - if (errno == EINTR && !pendingsigs) + if (errno == EINTR && !pending_sig) continue; /* fall through */ case 0: diff --git a/src/mystring.c b/src/mystring.c index 0106bd2..de624b8 100644 --- a/src/mystring.c +++ b/src/mystring.c @@ -125,7 +125,7 @@ intmax_t atomax(const char *s, int base) errno = 0; r = strtoimax(s, &p, base); - if (errno != 0) + if (errno == ERANGE) badnum(s); /* diff --git a/src/parser.c b/src/parser.c index 382658e..8e40781 100644 --- a/src/parser.c +++ b/src/parser.c @@ -80,6 +80,18 @@ struct heredoc { int striptabs; /* if set, strip leading tabs */ }; +struct synstack { + const char *syntax; + struct synstack *prev; + struct synstack *next; + int innerdq; + int varpushed; + int dblquote; + int varnest; /* levels of variables expansion */ + int parenlevel; /* levels of parens in arithmetic */ + int dqvarnest; /* levels of variables expansion within double quotes */ +}; + struct heredoc *heredoclist; /* list of here documents to read */ @@ -106,6 +118,7 @@ STATIC void parseheredoc(void); STATIC int peektoken(void); STATIC int readtoken(void); STATIC int xxreadtoken(void); +STATIC int pgetc_eatbnl(); STATIC int readtoken1(int, char const *, char *, int); STATIC void synexpect(int) __attribute__((__noreturn__)); STATIC void synerror(const char *) __attribute__((__noreturn__)); @@ -656,8 +669,10 @@ parseheredoc(void) if (needprompt) { setprompt(2); } - readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, - here->eofmark, here->striptabs); + if (here->here->type == NHERE) + readtoken1(pgetc(), SQSYNTAX, here->eofmark, here->striptabs); + else + readtoken1(pgetc_eatbnl(), DQSYNTAX, here->eofmark, here->striptabs); n = (union node *)stalloc(sizeof (struct narg)); n->narg.type = NARG; n->narg.next = NULL; @@ -782,7 +797,7 @@ xxreadtoken(void) setprompt(2); } for (;;) { /* until token or start of word found */ - c = pgetc(); + c = pgetc_eatbnl(); switch (c) { case ' ': case '\t': case PEOA: @@ -791,30 +806,23 @@ xxreadtoken(void) while ((c = pgetc()) != '\n' && c != PEOF); pungetc(); continue; - case '\\': - if (pgetc() == '\n') { - nlprompt(); - continue; - } - pungetc(); - goto breakloop; case '\n': nlnoprompt(); RETURN(TNL); case PEOF: RETURN(TEOF); case '&': - if (pgetc() == '&') + if (pgetc_eatbnl() == '&') RETURN(TAND); pungetc(); RETURN(TBACKGND); case '|': - if (pgetc() == '|') + if (pgetc_eatbnl() == '|') RETURN(TOR); pungetc(); RETURN(TPIPE); case ';': - if (pgetc() == ';') + if (pgetc_eatbnl() == ';') RETURN(TENDCASE); pungetc(); RETURN(TSEMI); @@ -822,11 +830,9 @@ xxreadtoken(void) RETURN(TLP); case ')': RETURN(TRP); - default: - goto breakloop; } + break; } -breakloop: return readtoken1(c, BASESYNTAX, (char *)NULL, 0); #undef RETURN } @@ -836,7 +842,7 @@ static int pgetc_eatbnl(void) int c; while ((c = pgetc()) == '\\') { - if (pgetc() != '\n') { + if (pgetc2() != '\n') { pungetc(); break; } @@ -847,6 +853,21 @@ static int pgetc_eatbnl(void) return c; } +static void synstack_push(struct synstack **stack, struct synstack *next, + const char *syntax) +{ + memset(next, 0, sizeof(*next)); + next->syntax = syntax; + next->next = *stack; + (*stack)->prev = next; + *stack = next; +} + +static void synstack_pop(struct synstack **stack) +{ + *stack = (*stack)->next; +} + /* @@ -876,24 +897,15 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) size_t len; struct nodelist *bqlist; int quotef; - int dblquote; - int varnest; /* levels of variables expansion */ - int arinest; /* levels of arithmetic expansion */ - int parenlevel; /* levels of parens in arithmetic */ - int dqvarnest; /* levels of variables expansion within double quotes */ int oldstyle; - /* syntax before arithmetic */ - char const *uninitialized_var(prevsyntax); + /* syntax stack */ + struct synstack synbase = { .syntax = syntax }; + struct synstack *synstack = &synbase; - dblquote = 0; if (syntax == DQSYNTAX) - dblquote = 1; + synstack->dblquote = 1; quotef = 0; bqlist = NULL; - varnest = 0; - arinest = 0; - parenlevel = 0; - dqvarnest = 0; STARTSTACKSTR(out); loop: { /* for each line, until end of word */ @@ -901,28 +913,30 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) if (c == '\034' && doprompt && attyset() && ! equal(termval(), "emacs")) { attyline(); - if (syntax == BASESYNTAX) + if (synstack->syntax == BASESYNTAX) return readtoken(); - c = pgetc(); + c = syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); goto loop; } #endif CHECKEND(); /* set c to PEOF if at end of here document */ for (;;) { /* until end of line or end of word */ CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ - switch(syntax[c]) { + switch(synstack->syntax[c]) { case CNL: /* '\n' */ - if (syntax == BASESYNTAX) + if (synstack->syntax == BASESYNTAX && + !synstack->varnest) goto endword; /* exit outer loop */ USTPUTC(c, out); nlprompt(); - c = pgetc(); + c = syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); goto loop; /* continue outer loop */ case CWORD: USTPUTC(c, out); break; case CCTL: - if (eofmark == NULL || dblquote) + if ((!eofmark) | synstack->dblquote | + synstack->varnest) USTPUTC(CTLESC, out); USTPUTC(c, out); break; @@ -933,17 +947,20 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) USTPUTC(CTLESC, out); USTPUTC('\\', out); pungetc(); - } else if (c == '\n') { - nlprompt(); } else { if ( - dblquote && + synstack->dblquote && c != '\\' && c != '`' && c != '$' && ( c != '"' || - eofmark != NULL + (eofmark != NULL && + !synstack->varnest) + ) && ( + c != '}' || + !synstack->varnest ) ) { + USTPUTC(CTLESC, out); USTPUTC('\\', out); } USTPUTC(CTLESC, out); @@ -952,55 +969,64 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) } break; case CSQUOTE: - syntax = SQSYNTAX; + synstack->syntax = SQSYNTAX; quotemark: if (eofmark == NULL) { USTPUTC(CTLQUOTEMARK, out); } break; case CDQUOTE: - syntax = DQSYNTAX; - dblquote = 1; + synstack->syntax = DQSYNTAX; + synstack->dblquote = 1; +toggledq: + if (synstack->varnest) + synstack->innerdq ^= 1; goto quotemark; case CENDQUOTE: - if (eofmark && !varnest) + if (eofmark && !synstack->varnest) { USTPUTC(c, out); - else { - if (dqvarnest == 0) { - syntax = BASESYNTAX; - dblquote = 0; - } - quotef++; - goto quotemark; + break; } - break; + + if (synstack->dqvarnest == 0) { + synstack->syntax = BASESYNTAX; + synstack->dblquote = 0; + } + + quotef++; + + if (c == '"') + goto toggledq; + + goto quotemark; case CVAR: /* '$' */ PARSESUB(); /* parse substitution */ break; case CENDVAR: /* '}' */ - if (varnest > 0) { - varnest--; - if (dqvarnest > 0) { - dqvarnest--; - } + if (!synstack->innerdq && + synstack->varnest > 0) { + if (!--synstack->varnest && + synstack->varpushed) + synstack_pop(&synstack); + else if (synstack->dqvarnest > 0) + synstack->dqvarnest--; USTPUTC(CTLENDVAR, out); } else { USTPUTC(c, out); } break; case CLP: /* '(' in arithmetic */ - parenlevel++; + synstack->parenlevel++; USTPUTC(c, out); break; case CRP: /* ')' in arithmetic */ - if (parenlevel > 0) { + if (synstack->parenlevel > 0) { USTPUTC(c, out); - --parenlevel; + --synstack->parenlevel; } else { - if (pgetc() == ')') { + if (pgetc_eatbnl() == ')') { USTPUTC(CTLENDARI, out); - if (!--arinest) - syntax = prevsyntax; + synstack_pop(&synstack); } else { /* * unbalanced parens @@ -1012,6 +1038,11 @@ quotemark: } break; case CBQUOTE: /* '`' */ + if (checkkwd & CHKEOFMARK) { + USTPUTC('`', out); + break; + } + PARSEBACKQOLD(); break; case CEOF: @@ -1019,21 +1050,21 @@ quotemark: case CIGN: break; default: - if (varnest == 0) + if (synstack->varnest == 0) goto endword; /* exit outer loop */ if (c != PEOA) { USTPUTC(c, out); } } - c = pgetc(); + c = syntax == SQSYNTAX ? pgetc() : pgetc_eatbnl(); } } endword: - if (syntax == ARISYNTAX) + if (synstack->syntax == ARISYNTAX) synerror("Missing '))'"); - if (syntax != BASESYNTAX && eofmark == NULL) + if (synstack->syntax != BASESYNTAX && eofmark == NULL) synerror("Unterminated quoted string"); - if (varnest != 0) { + if (synstack->varnest != 0) { /* { */ synerror("Missing '}'"); } @@ -1132,7 +1163,7 @@ parseredir: { np = (union node *)stalloc(sizeof (struct nfile)); if (c == '>') { np->nfile.fd = 1; - c = pgetc(); + c = pgetc_eatbnl(); if (c == '>') np->type = NAPPEND; else if (c == '|') @@ -1145,7 +1176,7 @@ parseredir: { } } else { /* c == '<' */ np->nfile.fd = 0; - switch (c = pgetc()) { + switch (c = pgetc_eatbnl()) { case '<': if (sizeof (struct nfile) != sizeof (struct nhere)) { np = (union node *)stalloc(sizeof (struct nhere)); @@ -1154,7 +1185,7 @@ parseredir: { np->type = NHERE; heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); heredoc->here = np; - if ((c = pgetc()) == '-') { + if ((c = pgetc_eatbnl()) == '-') { heredoc->striptabs = 1; } else { heredoc->striptabs = 0; @@ -1210,6 +1241,8 @@ parsesub: { PARSEBACKQNEW(); } } else { + const char *newsyn = synstack->syntax; + USTPUTC(CTLVAR, out); typeloc = out - (char *)stackblock(); STADJUST(1, out); @@ -1229,7 +1262,7 @@ varname: STPUTC(c, out); c = pgetc_eatbnl(); } while (is_digit(c)); - } else { + } else if (c != '}') { int cc = c; c = pgetc_eatbnl(); @@ -1257,9 +1290,12 @@ varname: } USTPUTC(cc, out); - } + } else + goto badsub; if (subtype == 0) { + int cc = c; + switch (c) { case ':': subtype = VSNUL; @@ -1273,27 +1309,41 @@ varname: break; case '%': case '#': - { - int cc = c; - subtype = c == '#' ? VSTRIMLEFT : - VSTRIMRIGHT; - c = pgetc_eatbnl(); - if (c == cc) - subtype++; - else - pungetc(); - break; - } + subtype = c == '#' ? VSTRIMLEFT : + VSTRIMRIGHT; + c = pgetc_eatbnl(); + if (c == cc) + subtype++; + else + pungetc(); + + newsyn = BASESYNTAX; + break; } } else { badsub: pungetc(); } + + if (newsyn == ARISYNTAX) + newsyn = DQSYNTAX; + + if ((newsyn != synstack->syntax || synstack->innerdq) && + subtype != VSNORMAL) { + synstack_push(&synstack, + synstack->prev ?: + alloca(sizeof(*synstack)), + newsyn); + + synstack->varpushed++; + synstack->dblquote = newsyn != BASESYNTAX; + } + *((char *)stackblock() + typeloc) = subtype; if (subtype != VSNORMAL) { - varnest++; - if (dblquote) - dqvarnest++; + synstack->varnest++; + if (synstack->dblquote) + synstack->dqvarnest++; } STPUTC('=', out); } @@ -1336,23 +1386,14 @@ parsebackq: { if (needprompt) { setprompt(2); } - switch (pc = pgetc()) { + switch (pc = pgetc_eatbnl()) { case '`': goto done; case '\\': - if ((pc = pgetc()) == '\n') { - nlprompt(); - /* - * If eating a newline, avoid putting - * the newline into the new character - * stream (via the STPUTC after the - * switch). - */ - continue; - } + pc = pgetc_eatbnl(); if (pc != '\\' && pc != '`' && pc != '$' - && (!dblquote || pc != '"')) + && (!synstack->dblquote || pc != '"')) STPUTC('\\', pout); if (pc > PEOA) { break; @@ -1428,10 +1469,10 @@ done: */ parsearith: { - if (++arinest == 1) { - prevsyntax = syntax; - syntax = ARISYNTAX; - } + synstack_push(&synstack, + synstack->prev ?: alloca(sizeof(*synstack)), + ARISYNTAX); + synstack->dblquote = 1; USTPUTC(CTLARI, out); goto parsearith_return; } @@ -1529,7 +1570,7 @@ expandstr(const char *ps) saveprompt = doprompt; doprompt = 0; - readtoken1(pgetc(), DQSYNTAX, FAKEEOFMARK, 0); + readtoken1(pgetc_eatbnl(), DQSYNTAX, FAKEEOFMARK, 0); doprompt = saveprompt; diff --git a/src/redir.c b/src/redir.c index f96a76b..71b0f77 100644 --- a/src/redir.c +++ b/src/redir.c @@ -192,7 +192,7 @@ openredirect(union node *redir) } else if (!S_ISREG(sb.st_mode)) { if ((f = open64(fname, O_WRONLY, 0666)) < 0) goto ecreate; - if (fstat64(f, &sb) < 0 && S_ISREG(sb.st_mode)) { + if (!fstat64(f, &sb) && S_ISREG(sb.st_mode)) { close(f); errno = EEXIST; goto ecreate; @@ -73,7 +73,7 @@ char sigmode[NSIG - 1]; /* indicates specified signal received */ static char gotsig[NSIG - 1]; /* last pending signal */ -volatile sig_atomic_t pendingsigs; +volatile sig_atomic_t pending_sig; /* received SIGCHLD */ int gotsigchld; @@ -291,7 +291,7 @@ onsig(int signo) } gotsig[signo - 1] = 1; - pendingsigs = signo; + pending_sig = signo; if (signo == SIGINT && !trap[SIGINT]) { if (!suppressint) @@ -314,7 +314,7 @@ void dotrap(void) int i; int status, last_status; - if (!pendingsigs) + if (!pending_sig) return; status = savestatus; @@ -323,7 +323,7 @@ void dotrap(void) status = exitstatus; savestatus = status; } - pendingsigs = 0; + pending_sig = 0; barrier(); for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { @@ -331,7 +331,7 @@ void dotrap(void) continue; if (evalskip) { - pendingsigs = i + 1; + pending_sig = i + 1; break; } @@ -38,7 +38,7 @@ extern int trapcnt; extern char sigmode[]; -extern volatile sig_atomic_t pendingsigs; +extern volatile sig_atomic_t pending_sig; extern int gotsigchld; int trapcmd(int, char **); |