]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20181012 snapshot
authorChet Ramey <chet.ramey@case.edu>
Mon, 15 Oct 2018 13:08:29 +0000 (09:08 -0400)
committerChet Ramey <chet.ramey@case.edu>
Mon, 15 Oct 2018 13:08:29 +0000 (09:08 -0400)
14 files changed:
CWRU/CWRU.chlog
MANIFEST
config-top.h
examples/loadables/Makefile.in
examples/loadables/README
examples/loadables/seq.c [new file with mode: 0644]
execute_cmd.c
po/de.po
tests/redir.right
tests/redir11.sub
tests/redir5.sub
tests/vredir.right
tests/vredir.tests
trap.c

index db59b332d6b37b034a9ed63e078288543f12bb5a..05b025db5806b2cf1bf3e4ed1b997b77822bfbd1 100644 (file)
@@ -4550,3 +4550,23 @@ trap.c
          or without, case-insensitively if requested, and return SIGRTMIN+n.
          These values could be different than what was available at compile
          time. Report and patch from Rasmus Villemoes <rv@rasumsvillemoes.dk>
+
+                                  10/8
+                                  ----
+execute_cmd.c
+       - execute_command_internal: only set line_number from command->value.Subshell
+         if the type == cm_subshell; otherwise defer and set later
+
+                                  10/10
+                                  -----
+examples/loadables/seq.c
+       - seq: new loadable builtin, derived originally from coreutils:seq.c
+         but with very little of that code remaining
+
+                                  10/12
+                                  -----
+trap.c
+       - run_pending_traps,_run_trap_internal: honor evalnest_max and
+         increment/decrement evalnest accordingly, since trap actions
+         are processed as if run by `eval'. Feature suggsted by Mike
+         Gerwitz <mtg@gnu.org>
index a5875966b97f6632fac0324dc52462c2cdc3442a..aa9819e4a5585c4330606b9bd827136a9fcd83f7 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -675,6 +675,7 @@ examples/loadables/necho.c  f
 examples/loadables/hello.c     f
 examples/loadables/print.c     f
 examples/loadables/realpath.c  f
+examples/loadables/seq.c       f
 examples/loadables/setpgid.c   f
 examples/loadables/sleep.c     f
 examples/loadables/strftime.c  f
index 9b345507d9054006c83432644beaf2fb08c392b1..56dbd51e61ad5baf4ac53da0907dba9de93c1d45 100644 (file)
    no longer exists.  This behavior is the default in Posix mode. */
 #define CHECKHASH_DEFAULT 0
 
-/* Define to the maximum level of recursion you want for the eval builtin.
+/* Define to the maximum level of recursion you want for the eval builtin
+   and trap handlers (since traps are run as if run by eval).
    0 means the limit is not active. */
 #define EVALNEST_MAX 0
 
index 0facc0ba913a41d1a05a4c8b7ed19720fbbcc4be..54424cea4a251ca94dc6a604501af871e0abf3b6 100644 (file)
@@ -103,7 +103,7 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
 ALLPROG = print truefalse sleep finfo logname basename dirname \
          tty pathchk tee head mkdir rmdir printenv id whoami \
          uname sync push ln unlink realpath strftime mypid setpgid
-OTHERPROG = necho hello cat pushd stat rm fdflags
+OTHERPROG = necho hello cat pushd stat rm fdflags seq
 
 all:   $(SHOBJ_STATUS)
 
@@ -148,6 +148,9 @@ rm: rm.o
 fdflags:       fdflags.o
        $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ fdflags.o $(SHOBJ_LIBS)
 
+seq:   seq.o
+       $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ seq.o $(SHOBJ_LIBS)
+
 logname:       logname.o
        $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
 
@@ -293,3 +296,5 @@ realpath.o: realpath.c
 strftime.o: strftime.c
 setpgid.o: setpgid.c
 stat.o: stat.c
+fdflags.o: fdflags.c
+seq.o: seq.c
index 91febd48e8d69d3a86e947fa4f6e35a5d2562c37..f9bcfac648773379fddb80fd74ce2b54101d94c6 100644 (file)
@@ -50,6 +50,7 @@ ln.c          Make links.
 loadables.h    File loadable builtins can include for shell definitions.
 logname.c      Print login name of current user.
 Makefile.in    Simple makefile for the sample loadable builtins.
+Makefile.inc.in        Sample makefile to use for loadable builtin development.
 mkdir.c                Make directories.
 mypid.c                Add $MYPID variable, demonstrate use of unload hook functio.n
 necho.c                echo without options or argument interpretation.
@@ -60,6 +61,7 @@ push.c                Anyone remember TOPS-20?
 realpath.c     Canonicalize pathnames, resolving symlinks.
 rm.c           Remove files and directories.
 rmdir.c                Remove directory.
+seq.c          Print a sequence of decimal or floating point numbers.
 setpgid.c      Set a process's pgrp; example of how to wrap a system call.
 sleep.c                sleep for fractions of a second.
 stat.c         populate an associative array with information about a file
diff --git a/examples/loadables/seq.c b/examples/loadables/seq.c
new file mode 100644 (file)
index 0000000..ebf1299
--- /dev/null
@@ -0,0 +1,490 @@
+/* seq - print sequence of numbers to standard output.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Written as bash builtin by Chet Ramey. Portions from seq.c by Ulrich Drepper. */
+
+#include <config.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "bashansi.h"
+#include "loadables.h"
+#include "bashintl.h"
+
+#ifndef errno
+extern int errno;
+#endif
+
+#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
+typedef long double floatmax_t;
+#  define FLOATMAX_CONV "L"
+#  define strtofltmax   strtold
+#  define FLOATMAX_FMT "%Lg"
+#  define FLOATMAX_WFMT "%0.Lf"
+#  define USE_LONG_DOUBLE
+#else
+typedef double floatmax_t;
+#  define FLOATMAX_CONV ""
+#  define strtofltmax   strtod
+#  define FLOATMAX_FMT "%g"
+#  define FLOATMAX_WFMT "%0.f"
+#endif
+static floatmax_t getfloatmax __P((const char *));
+static char *genformat __P((floatmax_t, floatmax_t, floatmax_t));
+
+#define MAX(a, b) (((a) < (b))? (b) : (a))
+
+static int conversion_error = 0;
+
+/* If true print all number with equal width.  */
+static int equal_width;
+
+/* The string used to separate two numbers.  */
+static char const *separator;
+
+/* The string output after all numbers have been output. */
+static char const terminator[] = "\n";
+
+static char decimal_point;
+
+/* Pretty much the same as the version in builtins/printf.def */
+static floatmax_t
+getfloatmax (arg)
+     const char *arg;
+{
+  floatmax_t ret;
+  char *ep;
+
+  errno = 0;
+  ret = strtofltmax (arg, &ep);
+
+  if (*ep)
+    {
+      sh_invalidnum ((char *)arg);
+      conversion_error = 1;
+    }
+  else if (errno == ERANGE)
+    {
+      builtin_error ("warning: %s: %s", arg, strerror(ERANGE));
+      conversion_error = 1;
+    }
+
+  if (ret == -0.0)
+    ret = 0.0;
+
+  return (ret);
+}
+
+/* If FORMAT is a valid printf format for a double argument, return
+   its long double equivalent, allocated from dynamic storage. This
+   was written by Ulrich Drepper, taken from coreutils:seq.c */
+static char *
+long_double_format (char const *fmt)
+{
+  size_t i;
+  size_t length_modifier_offset;
+  int has_L;
+
+  for (i = 0; ! (fmt[i] == '%' && fmt[i + 1] != '%'); i += (fmt[i] == '%') + 1)
+    {
+      if (!fmt[i])
+       {
+         builtin_error ("format %s has no %% directive", fmt);
+         return 0;
+       }
+    }
+
+  i++;
+  i += strspn (fmt + i, "-+#0 '");     /* zero or more flags */
+  i += strspn (fmt + i, "0123456789"); /* optional minimum field width */
+  if (fmt[i] == '.')                   /* optional precision */
+    {
+      i++;
+      i += strspn (fmt + i, "0123456789");
+    }
+
+  length_modifier_offset = i;          /* optional length modifier */
+  /* we could ignore an 'l' length modifier here */
+  has_L = (fmt[i] == 'L');
+  i += has_L;
+  switch (fmt[i])
+    {
+    case '\0':
+      builtin_error ("format %s ends in %%", fmt);
+      return 0;
+    case 'A':
+    case 'a':
+    case 'e':
+    case 'E':
+    case 'f':
+    case 'F':
+    case 'g':
+    case 'G':
+      break;
+    default:
+      builtin_error ("format %s has unknown `%%%c' directive", fmt, fmt[i]);
+      return 0;
+    }
+  for (i++; ; i += (fmt[i] == '%') + 1)
+    if (fmt[i] == '%' && fmt[i + 1] != '%')
+      {
+        builtin_error ("format %s has too many %% directives", fmt);
+        return 0;
+      }
+    else if (fmt[i] == 0)
+      {
+        size_t format_size = i + 1;
+        char *ldfmt = xmalloc (format_size + 1);
+        memcpy (ldfmt, fmt, length_modifier_offset);
+#ifdef USE_LONG_DOUBLE
+        ldfmt[length_modifier_offset] = 'L';
+        strcpy (ldfmt + length_modifier_offset + 1,
+                fmt + length_modifier_offset + has_L);
+#else
+        strcpy (ldfmt + length_modifier_offset, fmt + length_modifier_offset)
+#endif
+        return ldfmt;
+      }
+}
+
+/* Return the number of digits following the decimal point in NUMBUF */
+static int
+getprec (numbuf)
+     const char *numbuf;
+{
+  int p;
+  char *dp;
+
+  if (dp = strchr (numbuf, decimal_point))
+    dp++;              /* skip over decimal point */
+  for (p = 0; dp && *dp && ISDIGIT (*dp); dp++)
+    p++;
+  return p;
+}
+
+/* Return the default format given FIRST, INCR, and LAST.  */
+static char *
+genformat (first, incr, last)
+       floatmax_t first, incr, last;
+{
+  static char buf[6 + 2 * INT_STRLEN_BOUND (int)];
+  int wfirst, wlast, width;
+  int iprec, fprec, lprec, prec;
+
+  if (equal_width == 0)
+    return (FLOATMAX_FMT);
+
+  /* OK, we have to figure out the largest number of decimal places. This is
+     a little more expensive than using the original strings. */
+  snprintf (buf, sizeof (buf), FLOATMAX_FMT, incr);
+  iprec = getprec (buf);
+
+  wfirst = snprintf (buf, sizeof (buf), FLOATMAX_FMT, first);
+  fprec = getprec (buf);
+    
+  prec = MAX (fprec, iprec);
+
+  wlast = snprintf (buf, sizeof (buf), FLOATMAX_FMT, last);
+  lprec = getprec (buf);
+
+  /* increase first width by any increased precision in increment */
+  wfirst += (prec - fprec);
+
+  /* adjust last width to use precision from first/incr */
+  wlast += (prec - lprec);
+
+  if (lprec && prec == 0)
+    wlast--;           /* no decimal point */
+  if (lprec == 0 && prec)
+    wlast++;           /* include decimal point */
+  if (fprec == 0 && prec)
+    wfirst++;          /* include decimal point */
+
+  width = MAX (wfirst, wlast);
+  if (width)
+    sprintf (buf, "%%0%d.%d%sf", width, prec, FLOATMAX_CONV);
+  else
+    sprintf (buf, "%%.%d%sf", prec, FLOATMAX_CONV);
+
+  return buf;
+}
+
+int
+print_fltseq (fmt, first, last, incr)
+     const char *fmt;
+     floatmax_t first, last, incr;
+{
+  int n;
+  floatmax_t next;
+  const char *s;
+
+  n = 0;               /* interation counter */
+  s = "";
+  for (next = first; incr >= 0 ? (next <= last) : (next >= last); next = first + n * incr)
+    {
+      QUIT;
+      if (*s && fputs (s, stdout) == EOF)
+       return (sh_chkwrite (EXECUTION_FAILURE));
+      if (printf (fmt, next) < 0)
+       return (sh_chkwrite (EXECUTION_FAILURE));
+      s = separator;
+      n++;
+    }
+
+  if (n > 0 && fputs (terminator, stdout) == EOF)
+    return (sh_chkwrite (EXECUTION_FAILURE));
+  return (sh_chkwrite (EXECUTION_SUCCESS));
+}
+
+/* must be <= INT_STRLEN_BOUND(intmax_t) */
+int
+width_needed (num)
+     intmax_t num;
+{
+  int ret;
+
+  ret = num < 0;               /* sign */
+  if (ret)
+    num = -num;
+  do
+    ret++;
+  while (num /= 10);
+  return ret;
+}
+
+int
+print_intseq (ifirst, ilast, iincr)
+     intmax_t ifirst, ilast, iincr;
+{
+  char intwfmt[6 + INT_STRLEN_BOUND(int) + sizeof (PRIdMAX)];
+  const char *s;
+  intmax_t i, next;
+
+  /* compute integer format string */
+  if (equal_width)     /* -w supplied */
+    {
+      int wfirst, wlast, width;
+
+      wfirst = width_needed (ifirst);
+      wlast = width_needed (ilast);
+      width = MAX(wfirst, wlast);
+
+      /* The leading %s is for the separator */
+      snprintf (intwfmt, sizeof (intwfmt), "%%s%%0%u" PRIdMAX, width);
+    }
+
+  /* We could use braces.c:mkseq here but that allocates lots of memory */
+  s = "";
+  for (i = ifirst; (ifirst <= ilast) ? (i <= ilast) : (i >= ilast); i = next)
+    {
+      QUIT;
+      /* The leading %s is for the separator */
+      if (printf (equal_width ?  intwfmt : "%s%" PRIdMAX, s, i) < 0)
+       return (sh_chkwrite (EXECUTION_FAILURE));
+      s = separator;
+      next = i + iincr;
+    }
+
+  if (fputs (terminator, stdout) == EOF)
+    return (sh_chkwrite (EXECUTION_FAILURE));
+  return (sh_chkwrite (EXECUTION_SUCCESS));
+}
+
+int
+seq_builtin (list)
+     WORD_LIST *list;
+{
+  floatmax_t first, last, incr;
+  intmax_t ifirst, ilast, iincr;
+  WORD_LIST *l;
+  int opt, nargs, intseq, freefmt;
+  char *first_str, *incr_str, *last_str;
+  char const *fmtstr;          /* The printf(3) format used for output.  */
+
+  equal_width = 0;
+  separator = "\n";
+  fmtstr = NULL;
+
+  first = 1.0;
+  last = 0.0;
+  incr = 0.0;          /* set later */
+  ifirst = ilast = iincr = 0;
+  first_str = incr_str = last_str = 0;
+
+  intseq = freefmt = 0;
+  opt = 0;
+
+  reset_internal_getopt ();
+  while (opt != -1)
+    {
+      l = lcurrent ? lcurrent : list;
+      if (l && l->word && l->word->word && l->word->word[0] == '-' &&
+          (l->word->word[1] == '.' || DIGIT (l->word->word[1])))
+       {
+         loptend = l;
+         break;        /* negative number */
+       }
+      if ((opt = internal_getopt (list, "f:s:w")) == -1)
+        break;
+
+      switch (opt)
+       {
+       case 'f':
+         fmtstr = list_optarg;
+         break;
+       case 's':
+         separator = list_optarg;
+         break;
+       case 'w':
+         equal_width = 1;
+         break;
+       CASE_HELPOPT;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (list == 0)
+    {
+      builtin_usage ();
+      return (EXECUTION_FAILURE);
+    }
+
+  for (nargs = 1, l = list; l->next; l = l->next)
+    nargs++;
+  if (nargs > 3)
+    {
+      builtin_usage ();
+      return (EXECUTION_FAILURE);
+    }
+
+  /* LAST */
+  conversion_error = 0;
+  last = getfloatmax (last_str = l->word->word);
+  if (conversion_error)
+    return (EXECUTION_FAILURE);
+
+  /* FIRST LAST */
+  if (nargs > 1)
+    {
+      conversion_error = 0;
+      first = getfloatmax (first_str = list->word->word);
+      if (conversion_error)
+       return (EXECUTION_FAILURE);
+    }
+
+  /* FIRST INCR LAST */
+  if (nargs > 2)
+    {
+      conversion_error = 0;
+      incr = getfloatmax (incr_str = list->next->word->word);
+      if (conversion_error)
+       return (EXECUTION_FAILURE);
+      if (incr == 0.0)
+       {
+         builtin_error ("zero %screment", (first < last) ?  "in" : "de");
+         return (EXECUTION_FAILURE);
+       }
+    }
+
+  /* Sanitize arguments */
+  if (incr == 0.0)
+    incr = (first <= last) ?  1.0 : -1.0;
+  if ((incr < 0.0 && first < last) || (incr > 0 && first > last))
+    {
+      builtin_error ("incorrect %screment", (first < last) ?  "in" : "de");
+      return (EXECUTION_FAILURE);
+    }
+
+  /* validate format here */
+  if (fmtstr)
+    {
+      fmtstr = long_double_format (fmtstr);
+      freefmt = 1;
+      if (fmtstr == 0)
+       return (EXECUTION_FAILURE);
+    }
+      
+  if (fmtstr != NULL && equal_width)
+    {
+      builtin_warning ("-w ignored when the format string is specified");
+      equal_width = 0;
+    }
+
+  /* Placeholder for later additional conditions */
+  if (last_str && all_digits (last_str) &&
+      (first_str == 0 || all_digits (first_str)) &&
+      (incr_str == 0 || all_digits (incr_str)) &&
+      fmtstr == NULL)
+    intseq = 1;
+
+  if (intseq)
+    {
+      ifirst = (intmax_t)first; /* truncation */
+      ilast = (intmax_t)last;
+      iincr = (intmax_t)incr;
+
+      return (print_intseq (ifirst, ilast, iincr));
+    }
+
+  decimal_point = locale_decpoint ();
+  if (fmtstr == NULL)
+    fmtstr = genformat (first, incr, last);
+
+  print_fltseq (fmtstr, first, last, incr);
+
+  if (freefmt)
+    free ((void *)fmtstr);
+  return sh_chkwrite (EXECUTION_SUCCESS);
+}
+
+/* Taken largely from GNU seq. */
+char *seq_doc[] = {
+       "Print numbers from FIRST to LAST, in steps of INCREMENT.",
+       "",
+       "-f FORMAT    use printf style floating-point FORMAT",
+       "-s STRING    use STRING to separate numbers (default: \\n)",
+       "-w           equalize width by padding with leading zeroes",
+       "",
+       "If FIRST or INCREMENT is omitted, it defaults to 1.  However, an",
+       "omitted INCREMENT defaults to -1 when LAST is smaller than FIRST.",
+       "The sequence of numbers ends when the sum of the current number and",
+       "INCREMENT would become greater than LAST.",
+       "FIRST, INCREMENT, and LAST are interpreted as floating point values.",
+       "",
+       "FORMAT must be suitable for printing one argument of type 'double';",
+       "it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point",
+       "decimal numbers with maximum precision PREC, and to %g otherwise.",
+       (char *)NULL
+};     
+
+struct builtin seq_struct = {
+       "seq",
+       seq_builtin,
+       BUILTIN_ENABLED,
+       seq_doc,
+       "seq [-f format] [-s separator] [-w] [FIRST [INCR]] LAST",
+       0
+};
index a418bbb58b02713701881e7617ae31ba9a29792a..045863302242f2597bc64caf9d9e0af71524b398 100644 (file)
@@ -624,7 +624,9 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
 
       /* Fork a subshell, turn off the subshell bit, turn off job
         control and call execute_command () on the command again. */
-      line_number_for_err_trap = line_number = command->value.Subshell->line;  /* XXX - save value? */
+      if (command->type == cm_subshell)
+       line_number_for_err_trap = line_number = command->value.Subshell->line; /* XXX - save value? */
+       /* Otherwise we defer setting line_number */
       tcmd = make_command_string (command);
       paren_pid = make_child (p = savestring (tcmd), asynchronous);
 
index 752238ec83e5e448b5c680c02ffde911606c2912..a314f9ad7f41b5dcff3e11e703219f241aec0d66 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -7,7 +7,7 @@ msgstr ""
 "Project-Id-Version: bash 4.4\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2016-09-10 12:42-0400\n"
-"PO-Revision-Date: 2018-07-22 00:02+0200\n"
+"PO-Revision-Date: 2018-10-14 21:29+0200\n"
 "Last-Translator: Nils Naumann <nau@gmx.net>\n"
 "Language-Team: German <translation-team-de@lists.sourceforge.net>\n"
 "Language: de\n"
@@ -1549,7 +1549,7 @@ msgstr "Dateiende beim Suchen nach passender `)' erreicht."
 #: pcomplete.c:1126
 #, c-format
 msgid "completion: function `%s' not found"
-msgstr ""
+msgstr "completion: Funktion `%s' nicht gefunden."
 
 #: pcomplete.c:1646
 #, c-format
@@ -1583,7 +1583,7 @@ msgstr ""
 #: print_cmd.c:1534
 #, c-format
 msgid "cprintf: `%c': invalid format character"
-msgstr ""
+msgstr "cprintf: `%c': Ungültiges Formatsymbol."
 
 #: redir.c:124 redir.c:171
 msgid "file descriptor out of range"
@@ -4636,8 +4636,33 @@ msgid ""
 "    Returns success unless an invalid option is given or a write or assignment\n"
 "    error occurs."
 msgstr ""
-"Returns success unless an invalid option is given or a write or\n"
-"    assignment error occurs.<"
+"Formatierte Ausgabe der ARGUMENTE.\n"
+"    \n"
+"    Optionen:\n"
+"      -v var\tDie formatierte Ausgabe ver Variable var zuweisen statt\n"
+"    \t\tsie an die Standardausgebe zu senden.\n"
+"    \n"
+"    Die FORMAT Zeichenkette kann einfache Zeichen enthalten, die unverändert an\n"
+"    die Standardausgabe geschickt werden. Escape-Sequenzen werden umgewandelt\n"
+"    und an die Standardausgabe geschickt sowie Formatanweisungen, welche das \n"
+"    nachfolgende ARGUMENT auswerten und ausgeben.\n"
+"    \n"
+"    Gegenüber der in printf(1) beschriebenen Standardverion werden zusätzliche\n"
+"    Formatanweisungen ausgewertet:\n"
+"    \n"
+"      %b\tWertet Escape-Sequenzen des zugehörigen Arguments aus.\n"
+"      %q\tBettet das Argument so ein, dass es als Shelleingabe\n"
+"                verwendet werden kann.\n"
+"      %(fmt)T\tAusgabe der aus FMT entstehende Datum-Zeit Zeichenkette, dass\n"
+"    \t        sie als Zeichenkette für strftime(3) verwendet werden kann.\n"
+"    \n"
+"    Die Formatangebe wird wiederverwendet bis alle Argmente ausgewertet sind.\n"
+"    Wenn weniger Argumente als Formatangaben vorhanden sind, werden für die\n"
+"    Argumente Nullwerte bzw. leere Zeichenketten eingesetzt.\n"
+"    \n"
+"    Rücgabewert:\n"
+"    Gibt Erfolg zurück, außer es wird eine ungültige Option angegeben oder ein\n"
+"    Aus- bzw. Zuweisungsfehler auftritt."
 
 #: builtins.c:1953
 msgid ""
index 75ed45551c5f0b74c5e46fdaebe80f46a457a737..d4ab60d52da1dcb783dbbe5350289779bfa57eee 100644 (file)
@@ -64,14 +64,14 @@ f
 typeset -f f
 
 # make sure it was closed
-read -u 5 foo
+read -u 5 foo 2>&1 | grep -q 'invalid file descriptor'
 echo after read
 
 exec 5<&0
 
 exec <&-
 
-read abcde
+read abcde 2>&1 | grep -q 'read error'
 
 exec 0<&9-
 read line
@@ -84,9 +84,7 @@ f ()
         echo "$line";
     done
 }
-./redir5.sub: line 20: read: 5: invalid file descriptor: Bad file descriptor
 after read
-./redir5.sub: line 27: read: read error: 0: Bad file descriptor
 # tests of ksh93-like dup-and-close redirection operators
 /
 /
@@ -141,19 +139,10 @@ bix ()
 foo
 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 1
-./redir11.sub: line 8: $a: Bad file descriptor
-./redir11.sub: line 9: $(echo $a): Bad file descriptor
 7
 after: 42
-./redir11.sub: line 24: echo: write error: Bad file descriptor
-./redir11.sub: line 25: echo: write error: Bad file descriptor
-./redir11.sub: line 26: $(a=4 foo): Bad file descriptor
-./redir11.sub: line 27: $(a=4 foo): Bad file descriptor
-./redir11.sub: line 30: $a: Bad file descriptor
-./redir11.sub: line 31: $(echo $a): Bad file descriptor
-./redir11.sub: line 39: $(ss= declare -i ss): ambiguous redirect
+./redir11.sub: line 40: $(ss= declare -i ss): ambiguous redirect
 after: 42
 a+=3
 foo
 foo
-./redir11.sub: line 53: $(echo $a): Bad file descriptor
index 59ed493a3cee30a64f89279ec6fb6747d4f926dd..a919602c744b03478e3ef796e29a1654c97b59ee 100644 (file)
@@ -4,9 +4,10 @@
 a=1
 a=4 b=7 ss=4 echo $a
 
+# use grep to avoid differences due to different system error messages
 a=42
-a=2 echo foo >&$a
-a=2 echo foo >&$(echo $a)
+a=2 echo foo 2>&1 >&$a | { grep -q '\$a: Bad file' || echo 'redir11 bad 1'; }
+a=2 echo foo 2>&1 >&$(echo $a) | { grep -q 'Bad file' || echo 'redir11 bad 2'; }
 
 foo()
 {
@@ -21,14 +22,14 @@ a=4 b=7 foo
 echo after: $a
 
 unset a
-a=4 echo foo >&$(foo)
-a=1 echo foo >&$(foo)
-a=1 echo foo >&$(a=4 foo)
-echo foo >&$(a=4 foo)
+a=4 echo foo 2>&1 >&$(foo) | { grep -q 'Bad file' || echo 'redir11 bad 3'; }
+a=1 echo foo 2>&1 >&$(foo) | { grep -q 'Bad file' || echo 'redir11 bad 4'; }
+a=1 echo foo 2>&1 >&$(a=4 foo) | { grep -q 'Bad file' || echo 'redir11 bad 5'; }
+echo foo 2>&1 >&$(a=4 foo) | { grep -q 'Bad file' || echo 'redir11 bad 6'; }
 
 a=42
-a=2 echo foo >&$a
-a=2 echo foo >&$(echo $a)
+a=2 echo foo 2>&1 >&$a | { grep -q 'Bad file' || echo 'redir11 bad 7'; }
+a=2 echo foo 2>&1 >&$(echo $a) | { grep -q 'Bad file' || echo 'redir11 bad 8'; }
 
 unset -f foo
 foo()
@@ -50,4 +51,4 @@ a=9 echo foo >&$(echo $a)
 a=2
 a=9 eval echo foo >&$(echo $a)
 a=2
-a=9 eval echo foo '>&$(echo $a)'
+a=9 eval echo foo '2>&1 >&$(echo $a)' | { grep -q 'Bad file' || echo 'redir11 bad 9'; }
index 5d59d39c522bcced7e37160096ca09dc0a9e04d9..ee7b045af819bd17938c5417eba27d244c8ee8bb 100644 (file)
@@ -17,14 +17,14 @@ f
 typeset -f f
 
 # make sure it was closed
-read -u 5 foo
+read -u 5 foo 2>&1 | grep -q 'invalid file descriptor' 
 echo after read
 
 exec 5<&0
 
 exec <&-
 
-read abcde
+read abcde 2>&1 | grep -q 'read error'
 
 exec 0<&9-
 read line
index f449ae6fa5096f76cca0263123b4bddaa296953d..f4fe0db83475ca51ce559ecd3bdaece91aebb0a9 100644 (file)
@@ -11,9 +11,6 @@ bar ()
 ./vredir.tests: line 6: v: readonly variable
 ./vredir.tests: line 6: v: cannot assign fd to variable
 42
-./vredir.tests: line 25: $v: Bad file descriptor
-./vredir.tests: line 26: $v: Bad file descriptor
-./vredir.tests: line 27: $v: Bad file descriptor
 bar is a function
 bar () 
 { 
index b81c671c2eff06e95b4cf481ecbb7e99305cb589..ce77deb7541d00ef58e5ab16c8ad77f44d4e3870 100644 (file)
@@ -22,9 +22,9 @@ exec {v}>&-
 readonly v=42
 bar
 
-echo foo 1 >&$v
-echo foo 2 >&$v
-echo foo 3 >&$v
+echo foo 1 2>&1 >&$v | { grep -q '\$v: Bad' || echo 'bad foo 1'; }
+echo foo 2 2>&1 >&$v | { grep -q '\$v: Bad' || echo 'bad foo 2'; }
+echo foo 3 2>&1 >&$v | { grep -q '\$v: Bad' || echo 'bad foo 3'; }
 
 cat $TMPFILE
 rm -f $TMPFILE
diff --git a/trap.c b/trap.c
index 6c74478765f910d5ed48edcb589a0e0929997342..ceb83951a0bb1376c9f5d8a94ed273ce38733a01 100644 (file)
--- a/trap.c
+++ b/trap.c
@@ -1,7 +1,7 @@
 /* trap.c -- Not the trap command, but useful functions for manipulating
    those objects.  The trap command is in builtins/trap.def. */
 
-/* Copyright (C) 1987-2015 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2018 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -312,9 +312,15 @@ run_pending_traps ()
 #if defined (SIGWINCH)
       if (running_trap == SIGWINCH+1 && pending_traps[SIGWINCH])
        return;                 /* no recursive SIGWINCH trap invocations */
-#else
-      ;
 #endif
+      /* could check for running the trap handler for the same signal here
+        (running_trap == sig+1) */
+      if (evalnest_max && evalnest > evalnest_max)
+       {
+         internal_error (_("trap handler: maximum trap handler level exceeded (%d)"), evalnest_max);
+         evalnest = 0;
+         jump_to_top_level (DISCARD);
+       }
     }
 
   catch_flag = trapped_signal_received = 0;
@@ -339,6 +345,8 @@ run_pending_traps ()
          if (sig == SIGINT)
            {
              pending_traps[sig] = 0;   /* XXX */
+             /* We don't modify evalnest here, since run_interrupt_trap() calls
+                _run_trap_internal, which does. */
              run_interrupt_trap (0);
              CLRINTERRUPT;
            }
@@ -348,10 +356,14 @@ run_pending_traps ()
                   (sigmodes[SIGCHLD] & SIG_INPROGRESS) == 0)
            {
              sigmodes[SIGCHLD] |= SIG_INPROGRESS;
+             /* We modify evalnest here even though run_sigchld_trap can run
+                the trap action more than once */
+             evalnest++;
              x = pending_traps[sig];
              pending_traps[sig] = 0;
              run_sigchld_trap (x);     /* use as counter */
              running_trap = 0;
+             evalnest--;
              sigmodes[SIGCHLD] &= ~SIG_INPROGRESS;
              /* continue here rather than reset pending_traps[SIGCHLD] below in
                 case there are recursive calls to run_pending_traps and children
@@ -415,7 +427,9 @@ run_pending_traps ()
 #endif
              /* XXX - set pending_traps[sig] = 0 here? */
              pending_traps[sig] = 0;
+             evalnest++;
              evalstring (savestring (trap_list[sig]), "trap", SEVAL_NONINT|SEVAL_NOHIST|SEVAL_RESETLINE);
+             evalnest--;
 #if defined (JOB_CONTROL)
              restore_pipeline (1);
 #endif
@@ -488,7 +502,7 @@ trap_handler (sig)
 
       errno = oerrno;
     }
-
+  
   SIGRETURN (0);
 }
 
@@ -1012,6 +1026,7 @@ _run_trap_internal (sig, tag)
       flags = SEVAL_NONINT|SEVAL_NOHIST;
       if (sig != DEBUG_TRAP && sig != RETURN_TRAP && sig != ERROR_TRAP)
        flags |= SEVAL_RESETLINE;
+      evalnest++;
       if (function_code == 0)
         {
          parse_and_execute (trap_command, tag, flags);
@@ -1019,6 +1034,7 @@ _run_trap_internal (sig, tag)
         }
       else
         trap_exit_value = return_catch_value;
+      evalnest--;
 
 #if defined (JOB_CONTROL)
       if (sig != DEBUG_TRAP)   /* run_debug_trap does this */