]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
more changes for bracket expressions in patterns
authorChet Ramey <chet.ramey@case.edu>
Fri, 2 Dec 2022 16:41:48 +0000 (11:41 -0500)
committerChet Ramey <chet.ramey@case.edu>
Fri, 2 Dec 2022 16:41:48 +0000 (11:41 -0500)
20 files changed:
CWRU/CWRU.chlog
MANIFEST
builtins/evalstring.c
doc/bash.1
lib/glob/glob.c
lib/glob/gmisc.c
lib/glob/sm_loop.c
lib/glob/smatch.c
lib/readline/display.c
patchlevel.h
po/ko.gmo
po/ko.po
tests/glob-bracket.right [new file with mode: 0644]
tests/glob-bracket.tests [new file with mode: 0644]
tests/misc/glob-test [new file with mode: 0644]
tests/run-all
tests/run-glob-bracket [new file with mode: 0644]
tests/run-minimal
tests/trap.tests
tests/trap7.sub [new file with mode: 0644]

index 469e5318da01316060490372e45790f5f69635c6..a17de8478eaaf116076c629d2a938eb57ad13c6f 100644 (file)
@@ -4579,3 +4579,37 @@ variables.c
          find_variable_last_nameref_context: make sure to return
          &nameref_maxloop_value consistently and handle getting it as a
          return value from other functions
+
+                                  11/29
+                                  -----
+lib/readline/display.c
+       - _rl_update_final: if there is only one line (_rl_vis_botlin == 0)
+         and that line is empty (botline_length == 0), assume there is no
+         prompt and the line has no contents, so output the CR/LF to indicate
+         that the newline has been read. From a report from
+         Kevin Pulo <kev@pulo.com.au>
+
+                                  11/30
+                                  -----
+builtins/evalstring.c
+       - parse_and_execute: if we are executing the eval builtin, and the
+         return status from the command is suppressed (builtin_ignoring_errexit),
+         set CMD_IGNORE_RETURN in the parsed command's flags. From a report
+         from Tycho Kirchner <tychokirchner@mail.de>
+
+                                  12/1
+                                  ----
+lib/glob/sm_loop.c
+       - PARSE_SUBBRACKET: a reworked PARSE_COLLSYM, generalized to handle
+         [:, [=, and [. special bracket expressions
+       - BRACKMATCH: change to use PARSE_SUBBRACKET consistently to parse
+         [:, [=, and [. special bracket expressions
+       - PATSCAN: takes new FLAGS arg, changed all callers to just pass the
+         flags they get through to PATSCAN
+       - PATSCAN: call PARSE_SUBBRACKET for [:, [=, and [. to treat them
+         consistently (uses FLAGS argument here)
+       - PATSCAN: handle FNM_NOESCAPE appearing in FLAGS argument
+       This set of fixes contributed by Koichi Murase <myoga.murase@gmail.com>
+
+lib/glob/{glob,gmisc}.c
+       - PATSCAN: change all callers to add extra flags arg of 0
index e3b2d37c9cdad9f6201792357954f7c9e817b057..65f6a094c435beb2d2b2f80ff4fa6708733bad90 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1168,6 +1168,8 @@ tests/globstar.right      f
 tests/globstar1.sub    f
 tests/globstar2.sub    f
 tests/globstar3.sub    f
+tests/glob-bracket.tests       f
+tests/glob-bracket.right       f
 tests/heredoc.tests    f
 tests/heredoc.right    f
 tests/heredoc1.sub     f
@@ -1414,6 +1416,7 @@ tests/run-extglob3        f
 tests/run-func         f
 tests/run-getopts      f
 tests/run-glob-test    f
+tests/run-glob-bracket f
 tests/run-globstar     f
 tests/run-heredoc      f
 tests/run-herestr      f
@@ -1494,6 +1497,7 @@ tests/trap3.sub           f
 tests/trap4.sub                f
 tests/trap5.sub                f
 tests/trap6.sub                f
+tests/trap7.sub                f
 tests/type.tests       f
 tests/type.right       f
 tests/type1.sub                f
index 1bb630e4e9650b03bc5cb7b3bc40a2c55e36fbf0..6f752eda7aff3494b00d1405c7ca801855e4ecf4 100644 (file)
@@ -234,6 +234,7 @@ parse_prologue (string, flags, tag)
   unwind_protect_int (loop_level);
   unwind_protect_int (executing_list);
   unwind_protect_int (comsub_ignore_return);
+  unwind_protect_int (builtin_ignoring_errexit);
   if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
     unwind_protect_int (interactive);
 
@@ -299,7 +300,7 @@ parse_and_execute (string, from_file, flags)
      const char *from_file;
      int flags;
 {
-  int code, lreset;
+  int code, lreset, ignore_return;
   volatile int should_jump_to_top_level, last_result;
   COMMAND *volatile command;
   volatile sigset_t pe_sigmask;
@@ -309,6 +310,8 @@ parse_and_execute (string, from_file, flags)
   parse_and_execute_level++;
 
   lreset = flags & SEVAL_RESETLINE;
+  ignore_return = (this_shell_builtin == eval_builtin || this_shell_builtin == source_builtin) &&
+                 builtin_ignoring_errexit;
 
 #if defined (HAVE_POSIX_SIGNALS)
   /* If we longjmp and are going to go on, use this to restore signal mask */
@@ -476,6 +479,9 @@ parse_and_execute (string, from_file, flags)
              if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
                command->flags |= CMD_IGNORE_RETURN;
 
+             if (ignore_return)
+               command->flags |= CMD_IGNORE_RETURN;
+
 #if defined (ONESHOT)
              /*
               * IF
index d9b60edf1706398b096e6ee89c03443d87d88ff8..c1389240c8835ad66dc09f7301d67b3c550b53f4 100644 (file)
@@ -3984,7 +3984,7 @@ Matches anything except one of the given patterns
 .RE
 .PD
 .PP
-The\fBextglob\fP option changes the behavior of the parser, since the
+The \fBextglob\fP option changes the behavior of the parser, since the
 parentheses are normally treated as operators with syntactic meaning.
 To ensure that extended matching patterns are parsed correctly, make sure
 that \fBextglob\fP is enabled before parsing constructs containing the
index b66af85c67fc90e67b8e29f51adf41f20d242fb9..686d0f6b41cca5ec341b56801ea426c7d58b4ec9 100644 (file)
@@ -127,8 +127,8 @@ static int glob_testdir PARAMS((char *, int));
 static char **glob_dir_to_array PARAMS((char *, char **, int));
 
 /* Make sure these names continue to agree with what's in smatch.c */
-extern char *glob_patscan PARAMS((char *, char *, int));
-extern wchar_t *glob_patscan_wc PARAMS((wchar_t *, wchar_t *, int));
+extern char *glob_patscan PARAMS((char *, char *, int, int));
+extern wchar_t *glob_patscan_wc PARAMS((wchar_t *, wchar_t *, wint_t, int));
 
 /* And this from gmisc.c/gm_loop.c */
 extern int wextglob_pattern_p PARAMS((wchar_t *));
@@ -207,7 +207,7 @@ extglob_skipname (pat, dname, flags)
   wild = *pat == '*' || *pat == '?';
   pp = pat + 2;
   se = pp + strlen (pp);               /* end of pattern string */
-  pe = glob_patscan (pp, se, 0);       /* end of extglob pattern */
+  pe = glob_patscan (pp, se, 0, 0);    /* end of extglob pattern */
 
   /* if pe == 0, this is an invalid extglob pattern */
   if (pe == 0)
@@ -234,7 +234,7 @@ extglob_skipname (pat, dname, flags)
   nullpat = pe >= (pat + 2) && pe[-2] == '(' && pe[-1] == ')';
 
   /* check every subpattern */
-  while (t = glob_patscan (pp, pe, '|'))
+  while (t = glob_patscan (pp, pe, '|', 0))
     {
       /* If T == PE and *T == 0 (&& PE[-1] == RPAREN), we have hit the end
         of a pattern with no trailing characters. */
@@ -358,7 +358,7 @@ wextglob_skipname (pat, dname, flags)
   wild = *pat == L'*' || *pat == L'?';
   pp = pat + 2;
   se = pp + wcslen (pp);
-  pe = glob_patscan_wc (pp, se, 0);
+  pe = glob_patscan_wc (pp, se, 0, 0);
 
   /* if pe == 0, this is an invalid extglob pattern */
   if (pe == 0)
@@ -382,7 +382,7 @@ wextglob_skipname (pat, dname, flags)
   nullpat = pe >= (pat + 2) && pe[-2] == L'(' && pe[-1] == L')';
 
   /* check every subpattern */
-  while (t = glob_patscan_wc (pp, pe, '|'))
+  while (t = glob_patscan_wc (pp, pe, '|', 0))
     {
       n = t[-1];       /* ( */
       if (wextglob_pattern_p (pp) && n == L')')                /* nested extglob? */
index f3d74cea5bf6c8784322338aad8e45a1ebf332fc..24fdf746341bf88687a054263b72f4758a801db0 100644 (file)
@@ -38,7 +38,7 @@
 #include "glob.h"
 
 /* Make sure these names continue to agree with what's in smatch.c */
-extern char *glob_patscan PARAMS((char *, char *, int));
+extern char *glob_patscan PARAMS((char *, char *, int, int));
 
 /* Compile `gm_loop.c' for single-byte characters. */
 #define CHAR   char
@@ -92,7 +92,7 @@ glob_dirscan (pat, dirsep)
        {
          if (se == 0)
            se = p + strlen (p) - 1;
-         pe = glob_patscan (p + 2, se, 0);
+         pe = glob_patscan (p + 2, se, 0, 0);
          if (pe == 0)
            continue;
          else if (*pe == 0)
index 5d62e60b63c3ed9b944485668233917ba538baee..f419b0365579c83eaf7db6c10bb3526dc24c86a3 100644 (file)
@@ -27,13 +27,13 @@ struct STRUCT
 int FCT PARAMS((CHAR *, CHAR *, int));
 
 static int GMATCH PARAMS((CHAR *, CHAR *, CHAR *, CHAR *, struct STRUCT *, int));
-static CHAR *PARSE_COLLSYM PARAMS((CHAR *, INT *));
+static inline CHAR *PARSE_SUBBRACKET PARAMS((CHAR *, int));
 static CHAR *BRACKMATCH PARAMS((CHAR *, U_CHAR, int));
 static int EXTMATCH PARAMS((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
 
 extern void DEQUOTE_PATHNAME PARAMS((CHAR *));
 
-/*static*/ CHAR *PATSCAN PARAMS((CHAR *, CHAR *, INT));
+/*static*/ CHAR *PATSCAN PARAMS((CHAR *, CHAR *, INT, int));
 
 int
 FCT (pattern, string, flags)
@@ -192,7 +192,7 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
                     that's OK, since we can match 0 or 1 occurrences.
                     We need to skip the glob pattern and see if we
                     match the rest of the string. */
-                 newn = PATSCAN (p + 1, pe, 0);
+                 newn = PATSCAN (p + 1, pe, 0, flags);
                  /* If NEWN is 0, we have an ill-formed pattern. */
                  p = newn ? newn : pe;
                }
@@ -225,7 +225,7 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
                     that's OK, since we can match 0 or more occurrences.
                     We need to skip the glob pattern and see if we
                     match the rest of the string. */
-                 newn = PATSCAN (p + 1, pe, 0);
+                 newn = PATSCAN (p + 1, pe, 0, flags);
                  /* If NEWN is 0, we have an ill-formed pattern. */
                  p = newn ? newn : pe;
                }
@@ -380,35 +380,27 @@ fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
   return (FNM_NOMATCH);
 }
 
-/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
-   the value of the symbol, and move P past the collating symbol expression.
-   The value is returned in *VP, if VP is not null. */
-static CHAR *
-PARSE_COLLSYM (p, vp)
+#define SLASH_PATHNAME(c)      (c == L('/') && (flags & FNM_PATHNAME))
+
+/* Parse a special bracket expression symbol ([.sym.], [=char=], [:cclass:]),
+   starting at P, and return the position of the terminating .], =], or :].
+   P points to the character after the opening bracket. Returns NULL if the
+   symbol isn't correctly terminated. */
+static inline CHAR *
+PARSE_SUBBRACKET (p, flags)
      CHAR *p;
-     INT *vp;
+     int flags;
 {
-  register int pc;
-  INT val;
+  CHAR type;           /* the type of special bracket expression symbol */
 
-  p++;                         /* move past the `.' */
-         
-  for (pc = 0; p[pc]; pc++)
-    if (p[pc] == L('.') && p[pc+1] == L(']'))
-      break;
-   if (p[pc] == 0)
-    {
-      if (vp)
-       *vp = INVALID;
-      return (p + pc);
-    }
-   val = COLLSYM (p, pc);
-   if (vp)
-     *vp = val;
-   return (p + pc + 2);
-}
+  type = *p;
 
-#define SLASH_PATHNAME(c)      (c == L('/') && (flags & FNM_PATHNAME))
+  /* POSIX allows a right bracket to appear in a collating symbol. */
+  while (*++p != L('\0') && SLASH_PATHNAME (*p) == 0 && (type != L('.') && *p == L(']')) == 0)
+    if (*p == type && p[1] == L(']'))
+      return p;
+  return NULL;
+}
 
 /* Use prototype definition here because of type promotion. */
 static CHAR *
@@ -423,10 +415,10 @@ BRACKMATCH (p, test, flags)
 {
   register CHAR cstart, cend, c;
   register int not;    /* Nonzero if the sense of the character class is inverted.  */
-  int brcnt, forcecoll, isrange;
+  int forcecoll, isrange;
   INT pc;
   CHAR *savep;
-  CHAR *brchrp;
+  CHAR *close;
   U_CHAR orig_test;
 
   orig_test = test;
@@ -451,18 +443,13 @@ BRACKMATCH (p, test, flags)
 
       /* POSIX.2 equivalence class:  [=c=].  See POSIX.2 2.8.3.2.  Find
         the end of the equivalence class, move the pattern pointer past
-        it, and check for equivalence.  XXX - this handles only
-        single-character equivalence classes, which is wrong, or at
-        least incomplete. */
-      if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']'))
+        it, and check for equivalence. */
+      if (c == L('[') && *p == L('=') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
        {
-         pc = FOLD (p[1]);
-         p += 4;
-
-         /* Finding a slash in a bracket expression means you have to
-            match the bracket as an ordinary character (see below). */
-         if (pc == L('/') && (flags & FNM_PATHNAME))
-           return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
+         p++;
+         pc = COLLSYM (p, close - p);
+         pc = FOLD (pc);
+         p = close + 2;
 
          if (COLLEQUIV (test, pc))
            {
@@ -486,30 +473,21 @@ BRACKMATCH (p, test, flags)
        }
 
       /* POSIX.2 character class expression.  See POSIX.2 2.8.3.2. */
-      if (c == L('[') && *p == L(':'))
+      if (c == L('[') && *p == L(':') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
        {
-         CHAR *close, *ccname;
+         CHAR *ccname;
 
          pc = 0;       /* make sure invalid char classes don't match. */
-         /* Find end of character class name */
-         for (close = p + 1; *close != '\0' && SLASH_PATHNAME(*close) == 0; close++)
-           if (*close == L(':') && *(close+1) == L(']'))
-             break;
 
-         if (*close != L('\0') && SLASH_PATHNAME(*close) == 0)
+         ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
+         if (ccname)
            {
-             ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
-             if (ccname == 0)
-               pc = 0;
-             else
-               {
-                 bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
-                 *(ccname + (close - p - 1)) = L('\0');
-                 /* As a result of a POSIX discussion, char class names are
-                    allowed to be quoted (?) */
-                 DEQUOTE_PATHNAME (ccname);
-                 pc = IS_CCLASS (orig_test, (XCHAR *)ccname);
-               }
+             bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
+             *(ccname + (close - p - 1)) = L('\0');
+             /* As a result of a POSIX discussion, char class names are
+                allowed to be quoted (?) */
+             DEQUOTE_PATHNAME (ccname);
+             pc = IS_CCLASS (orig_test, (XCHAR *)ccname);
              if (pc == -1)
                {
                  /* CCNAME is not a valid character class in the current
@@ -521,14 +499,12 @@ BRACKMATCH (p, test, flags)
                     string. If we don't want to do that, take out the update
                     of P. */
                  pc = 0;
-                 p = close + 2;
                }
-             else
-               p = close + 2;          /* move past the closing `]' */
-
-             free (ccname);
            }
-           
+         free (ccname);
+
+         p = close + 2;
+
          if (pc)
            {
 /*[*/        /* Move past the closing `]', since the first thing we do at
@@ -556,13 +532,11 @@ BRACKMATCH (p, test, flags)
         the symbol name, make sure it is terminated by `.]', translate
         the name to a character using the external table, and do the
         comparison. */
-      if (c == L('[') && *p == L('.'))
+      if (c == L('[') && *p == L('.') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
        {
-         p = PARSE_COLLSYM (p, &pc);
-         /* An invalid collating symbol cannot be the first point of a
-            range.  If it is, we set cstart to one greater than `test',
-            so any comparisons later will fail. */
-         cstart = (pc == INVALID) ? test + 1 : pc;
+         p++;
+         cstart = COLLSYM (p, close - p);
+         p = close + 2;
          forcecoll = 1;
        }
 
@@ -616,13 +590,11 @@ BRACKMATCH (p, test, flags)
            return ((test == L('[')) ? savep : (CHAR *)0);
          else if (cend == L('/') && (flags & FNM_PATHNAME))
            return ((test == L('[')) ? savep : (CHAR *)0);
-         if (cend == L('[') && *p == L('.'))
+         if (cend == L('[') && *p == L('.') && (close = PARSE_SUBBRACKET (p, flags)) != NULL)
            {
-             p = PARSE_COLLSYM (p, &pc);
-             /* An invalid collating symbol cannot be the second part of a
-                range expression.  If we get one, we set cend to one fewer
-                than the test character to make sure the range test fails. */
-             cend = (pc == INVALID) ? test - 1 : pc;
+             p++;
+             cend = COLLSYM (p, close - p);
+             p = close + 2;
              forcecoll = 1;
            }
          cend = FOLD (cend);
@@ -658,46 +630,29 @@ BRACKMATCH (p, test, flags)
 matched:
   /* Skip the rest of the [...] that already matched.  */
   c = *--p;
-  brcnt = 1;
-  brchrp = 0;
-  while (brcnt > 0)
+  while (1)
     {
-      int oc;
-
       /* A `[' without a matching `]' is just another character to match. */
       if (c == L('\0'))
        return ((test == L('[')) ? savep : (CHAR *)0);
       else if (c == L('/') && (flags & FNM_PATHNAME))
        return ((test == L('[')) ? savep : (CHAR *)0);
 
-      oc = c;
       c = *p++;
       if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.')))
        {
-         brcnt++;
-         brchrp = p++;         /* skip over the char after the left bracket */
-         c = *p;
-         if (c == L('\0'))
-           return ((test == L('[')) ? savep : (CHAR *)0);
-         else if (c == L('/') && (flags & FNM_PATHNAME))
-           return ((test == L('[')) ? savep : (CHAR *)0);
-         /* If *brchrp == ':' we should check that the rest of the characters
-            form a valid character class name. We don't do that yet, but we
-            keep BRCHRP in case we want to. */
-       }
-      /* We only want to check brchrp if we set it above. */
-      else if (c == L(']') && brcnt > 1 && brchrp != 0 && oc == *brchrp)
-       {
-         brcnt--;
-         brchrp = 0;           /* just in case */
+         if ((close = PARSE_SUBBRACKET (p, flags)) != NULL)
+           p = close + 2;
        }
       /* Left bracket loses its special meaning inside a bracket expression.
          It is only valid when followed by a `.', `=', or `:', which we check
          for above. Technically the right bracket can appear in a collating
-         symbol, so we check for that here. Otherwise, it terminates the
-         bracket expression. */
-      else if (c == L(']') && (brchrp == 0 || *brchrp != L('.')) && brcnt >= 1)
-       brcnt = 0;
+         symbol, so we check for that as well. The right brackets terminating
+         collating symbols, equivalence classes, or character classes are
+         processed by PARSE_SUBBRACKET. Otherwise, a right bracket terminates
+         the bracket expression. */
+      else if (c == L(']'))
+       break;
       else if (!(flags & FNM_NOESCAPE) && c == L('\\'))
        {
          if (*p == '\0')
@@ -734,16 +689,15 @@ matched:
    first character after the matching DELIM or NULL if the pattern is
    empty or invalid. */
 /*static*/ CHAR *
-PATSCAN (string, end, delim)
+PATSCAN (string, end, delim, flags)
      CHAR *string, *end;
      INT delim;
+     int flags;
 {
   int pnest, bnest, skip;
-  INT cchar;
-  CHAR *s, c, *bfirst;
+  CHAR *s, c, *bfirst, *t;
 
   pnest = bnest = skip = 0;
-  cchar = 0;
   bfirst = NULL;
 
   if (string == end)
@@ -761,7 +715,8 @@ PATSCAN (string, end, delim)
       switch (c)
        {
        case L('\\'):
-         skip = 1;
+         if ((flags & FNM_NOESCAPE) == 0)
+           skip = 1;
          break;
 
        case L('\0'):
@@ -779,7 +734,11 @@ PATSCAN (string, end, delim)
              bnest++;
            }
          else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('='))
-           cchar = s[1];
+           {
+             t = PARSE_SUBBRACKET (s + 1, flags);
+             if (t)
+               s = t + 2 - 1;  /* -1 to cancel s++ in loop above */
+           }
          break;
 
        /* `]' is not special if it's the first char (after a leading `!'
@@ -788,9 +747,7 @@ PATSCAN (string, end, delim)
        case L(']'):
          if (bnest)
            {
-             if (cchar && s[-1] == cchar)
-               cchar = 0;
-             else if (s != bfirst)
+             if (s != bfirst)
                {
                  bnest--;
                  bfirst = 0;
@@ -879,7 +836,7 @@ fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
 fprintf(stderr, "extmatch: flags = %d\n", flags);
 #endif
 
-  prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */
+  prest = PATSCAN (p + (*p == L('(')), pe, 0, flags); /* ) */
   if (prest == 0)
     /* If PREST is 0, we failed to scan a valid pattern.  In this
        case, we just want to compare the two as strings. */
@@ -902,7 +859,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
         string. */
       for (psub = p + 1; ; psub = pnext)
        {
-         pnext = PATSCAN (psub, pe, L('|'));
+         pnext = PATSCAN (psub, pe, L('|'), flags);
          for (srest = s; srest <= se; srest++)
            {
              /* Match this substring (S -> SREST) against this
@@ -939,7 +896,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
         rest of the string. */
       for (psub = p + 1; ; psub = pnext)
        {
-         pnext = PATSCAN (psub, pe, L('|'));
+         pnext = PATSCAN (psub, pe, L('|'), flags);
          srest = (prest == pe) ? se : s;
          for ( ; srest <= se; srest++)
            {
@@ -960,7 +917,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
          m1 = 0;
          for (psub = p + 1; ; psub = pnext)
            {
-             pnext = PATSCAN (psub, pe, L('|'));
+             pnext = PATSCAN (psub, pe, L('|'), flags);
              /* If one of the patterns matches, just bail immediately. */
              if (m1 = (GMATCH (s, srest, psub, pnext - 1, NULL, flags) == 0))
                break;
@@ -1001,7 +958,7 @@ fprintf(stderr, "extmatch: flags = %d\n", flags);
 #undef FCT
 #undef GMATCH
 #undef COLLSYM
-#undef PARSE_COLLSYM
+#undef PARSE_SUBBRACKET
 #undef PATSCAN
 #undef STRCOMPARE
 #undef EXTMATCH
index a40b9e5efd5ccc85cbc600f7f6afb867f1fd0ee0..fd95e6cb7ebf379e5704d1fd565a0e79e64f44f2 100644 (file)
@@ -322,7 +322,7 @@ is_cclass (c, name)
 #define FCT                    internal_strmatch
 #define GMATCH                 gmatch
 #define COLLSYM                        collsym
-#define PARSE_COLLSYM          parse_collsym
+#define PARSE_SUBBRACKET       parse_subbracket
 #define BRACKMATCH             brackmatch
 #define PATSCAN                        glob_patscan
 #define STRCOMPARE             strcompare
@@ -578,7 +578,7 @@ posix_cclass_only (pattern)
 #define FCT                    internal_wstrmatch
 #define GMATCH                 gmatch_wc
 #define COLLSYM                        collwcsym
-#define PARSE_COLLSYM          parse_collwcsym
+#define PARSE_SUBBRACKET       parse_subbracket_wc
 #define BRACKMATCH             brackmatch_wc
 #define PATSCAN                        glob_patscan_wc
 #define STRCOMPARE             wscompare
index 0e42930aefd2622228d24a20a8429a58875a06cc..2d3747f252367283e1e62a94de4043833e8bf5f8 100644 (file)
@@ -3394,9 +3394,9 @@ _rl_update_final (void)
       puts_face (&last_line[_rl_screenwidth - 1 + woff],
                 &last_face[_rl_screenwidth - 1 + woff], 1);
     }
-  _rl_vis_botlin = 0;
-  if (botline_length > 0 || _rl_last_c_pos > 0)
+  if ((_rl_vis_botlin == 0 && botline_length == 0) || botline_length > 0 || _rl_last_c_pos > 0)
     rl_crlf ();
+  _rl_vis_botlin = 0;
   fflush (rl_outstream);
   rl_display_fixed++;
 }
index 81cb67282ce3a16fbe1fda4b513df868d0d5b389..91de6238439d9c4434bc4fa715d3f119eb3c6d59 100644 (file)
@@ -25,6 +25,6 @@
    regexp `^#define[   ]*PATCHLEVEL', since that's what support/mkversion.sh
    looks for to find the patch level (for the sccs version string). */
 
-#define PATCHLEVEL 9
+#define PATCHLEVEL 12
 
 #endif /* _PATCHLEVEL_H_ */
index 11fe7d2e9858d04c9db976bb385371ebee86eab1..ef6d0ede93337b9ab0e0a6dc1796ae2d6f3fba6e 100644 (file)
Binary files a/po/ko.gmo and b/po/ko.gmo differ
index 4b3fbc621f8fd05f0f8d5ebc0db7ee66db954f57..09e249e4ab4c32caa30fec65ddec25e76a068de9 100644 (file)
--- a/po/ko.po
+++ b/po/ko.po
@@ -9,7 +9,7 @@ msgstr ""
 "Project-Id-Version: bash-5.2-rc1\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-01-11 14:50-0500\n"
-"PO-Revision-Date: 2022-06-25 01:50+0900\n"
+"PO-Revision-Date: 2022-11-29 14:23+0900\n"
 "Last-Translator: Seong-ho Cho <darkcircle.0426@gmail.com>\n"
 "Language-Team: Korean <translation-team-ko@googlegroups.com>\n"
 "Language: ko\n"
@@ -566,7 +566,7 @@ msgstr ""
 "셸에 대한 일반적인 정보를 더 확인하려면 `info bash'를 사용하십시오.\n"
 "이 목록에 없는 명령어에 대해 더 알아보려면 `man -k' 또는 `info'를 사용하십시오.\n"
 "\n"
-"명령어 이름 다음의 별(*) 표시는 해당 명령어의 비활성 상태을 의미합니다.\n"
+"명령어 이름 다음의 별(*) 표시는 해당 명령어를 사용하지 않음을 의미합니다.\n"
 "\n"
 
 #: builtins/history.def:159
@@ -1737,7 +1737,7 @@ msgstr "셸 옵션:\n"
 
 #: shell.c:2069
 msgid "\t-ilrsD or -c command or -O shopt_option\t\t(invocation only)\n"
-msgstr "\t-ilrsD 또는 -c <명령> 또는 -O shopt_option\t\t(invocation 전용)\n"
+msgstr "\t-ilrsD 또는 -c <명령> 또는 -O <shopt_옵션>\t\t(실행 전용)\n"
 
 #: shell.c:2088
 #, c-format
@@ -2289,7 +2289,7 @@ msgstr "eval [인자 ...]"
 
 #: builtins.c:96
 msgid "getopts optstring name [arg ...]"
-msgstr "getopts optstring name [<인자> ...]"
+msgstr "getopts <옵션문자열> <이름> [<인자> ...]"
 
 #: builtins.c:98
 msgid "exec [-cl] [-a name] [command [argument ...]] [redirection ...]"
@@ -2309,11 +2309,11 @@ msgstr "fc [-e <편집기이름>] [-lnr] [<처음>] [<종결>] 또는 fc -s [<
 
 #: builtins.c:109
 msgid "fg [job_spec]"
-msgstr "fg [<JOBSPEC>]"
+msgstr "fg [<작업명세>]"
 
 #: builtins.c:113
 msgid "bg [job_spec ...]"
-msgstr "bg [<JOBSPEC> ...]"
+msgstr "bg [<작업명세> ...]"
 
 #: builtins.c:116
 msgid "hash [-lr] [-p pathname] [-dt] [name ...]"
@@ -2329,15 +2329,15 @@ msgstr "history [-c] [-d <오프셋>] [n] 또는 history -anrw [<파일이름>]
 
 #: builtins.c:127
 msgid "jobs [-lnprs] [jobspec ...] or jobs -x command [args]"
-msgstr "jobs [-lnprs] [jobspec ...] 또는 jobs -x command [args]"
+msgstr "jobs [-lnprs] [<작업명세> ...] 또는 jobs -x <명령> [<인자> ...]"
 
 #: builtins.c:131
 msgid "disown [-h] [-ar] [jobspec ... | pid ...]"
-msgstr "disown [-h] [-ar] [<JOBSPEC> ... | <PID> ...]"
+msgstr "disown [-h] [-ar] [<작업명세> ... | <PID> ...]"
 
 #: builtins.c:134
 msgid "kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]"
-msgstr "kill [-s <시그널명세> | -n <시그널번호> | -<시그널명세>] <PID> | <JOBSPEC> ... 또는 kill -l [<시그널명세>]"
+msgstr "kill [-s <시그널명세> | -n <시그널번호> | -<시그널명세>] <PID> | <작업명세> ... 또는 kill -l [<시그널명세>]"
 
 #: builtins.c:136
 msgid "let arg [arg ...]"
@@ -5057,8 +5057,7 @@ msgstr ""
 "    HOME\t로그인 후 접근하는 완전한 경로 이름입니다.\n"
 "    HOSTNAME\t현재 호스트 이름입니다.\n"
 "    HOSTTYPE\t이 배시 버전이 실행하고 있는 시스템의 CPU 형식입니다.\n"
-"    IGNOREEOF\n"
-"EOF 문자 입력을 유일한 입력으로 받는 셸의 동작을\n"
+"    IGNOREEOF\tEOF 문자 입력을 유일한 입력으로 받는 셸의 동작을\n"
 "    \t\t제어합니다.  설정하면, 이 변수의 값은 셸을 나가기\n"
 "    \t\t전 빈 줄에 한줄로 나타낼 EOF 문자 수 입니다 (기본 10개).\n"
 "    \t\t설정을 해제하면, EOF는 입력 끝을 나타냅니다.\n"
diff --git a/tests/glob-bracket.right b/tests/glob-bracket.right
new file mode 100644 (file)
index 0000000..112722f
--- /dev/null
@@ -0,0 +1,103 @@
+--- $GLOBIGNORE vs fnmatch(3) ---
+#1: pat=ab/cd/efg        yes/yes
+#2: pat=ab[/]cd/efg      no/no
+#3: pat=ab[/a]cd/efg     no/no
+#4: pat=ab[a/]cd/efg     no/no
+#5: pat=ab[!a]cd/efg     no/no
+#6: pat=ab[.-0]cd/efg    no/no
+#7: pat=*/*/efg          yes/yes
+#8: pat=*[/]*/efg        no/no
+#9: pat=*[/a]*/efg       no/no
+#10: pat=*[a/]*/efg       no/no
+#11: pat=*[!a]*/efg       no/no
+#12: pat=*[.-0]*/efg      no/no
+#13: pat=*/*/efg          yes/yes
+#14: pat=*[b]/*/efg       yes/yes
+#15: pat=*[ab]/*/efg      yes/yes
+#16: pat=*[ba]/*/efg      yes/yes
+#17: pat=*[!a]/*/efg      yes/yes
+#18: pat=*[a-c]/*/efg     yes/yes
+#19: pat=ab@(/)cd/efg     no/no
+#20: pat=*@(/)cd/efg      no/no
+#21: pat=*/cd/efg         yes/yes
+
+---Tests for a slash in bracket expressions---
+#22: pat=ab[/]ef              str=ab[/]ef          yes/yes
+#23: pat=ab[/]ef              str=ab/ef            no/no
+#24: pat=ab[c/d]ef            str=ab[c/d]ef        yes/yes
+#25: pat=ab[c/d]ef            str=abcef            no/no
+#26: pat=ab[.-/]ef            str=ab[.-/]ef        yes/yes
+#27: pat=ab[.-/]ef            str=ab.ef            no/no
+#28: pat=ab[[=/=]]ef          str=ab[[=/=]]ef      yes/yes
+#29: pat=ab[[=/=]]ef          str=ab/ef            no/no
+#30: pat=ab[[=c=]/]ef         str=ab[=/]ef         yes/yes
+#31: pat=ab[[=c=]/]ef         str=abcef            no/no
+#32: pat=ab[[:alpha:]/]ef     str=ab[:/]ef         yes/yes
+#33: pat=ab[[:alpha:]/]ef     str=abxef            no/no
+#34: pat=ab[/[abc]]ef         str=ab[/c]ef         yes/yes
+#35: pat=ab[/[abc]]ef         str=abc]ef           no/no
+#36: pat=ab[c[=/=]]ef         str=ab[c[=/=]]ef     yes/yes
+#37: pat=ab[c[=/=]]ef         str=abc[=/=]ef       no/no
+#38: pat=ab[c[=/=]]ef         str=abcef            no/no
+#39: pat=a[b\/c]              str=a[b/c]           yes/yes
+#40: pat=a[b\/c]              str=ab               no/no
+#41: pat=a[b\/c]              str=ac               no/no
+
+---Tests for incomplete bracket expressions---
+#42: pat=ab[c                 str=ab[c             yes/yes
+#43: pat=ab[c                 str=abc              no/no
+#44: pat=ab[c[=d=             str=ab[c[=d=         yes/yes
+#45: pat=ab[c[=d=             str=abc              no/no
+#46: pat=ab[c[.d              str=ab[c[.d          yes/yes
+#47: pat=ab[c[.d              str=abc              no/no
+#48: pat=ab[c[:alpha:         str=ab[c[:alpha:     yes/yes
+#49: pat=ab[c[:alpha:         str=abc              no/no
+#50: pat=ab[c-                str=ab[c-            yes/yes
+#51: pat=ab[c-                str=abc              no/no
+#52: pat=ab[c\                str=ab[c\            yes/yes
+#53: pat=ab[c\                str=abc              no/no
+#54: pat=ab[[\                str=ab[[\            yes/yes
+#55: pat=ab[[\                str=ab[              no/no
+
+--- PATSCAN vs BRACKMATCH ---
+#56: pat=@([[.].])A])         str=]                yes/yes
+#57: pat=@([[.].])A])         str===]A])           no/no
+#58: pat=@([[.].])A])         str=AA])             no/no
+#59: pat=@([[=]=])A])         str=]                no/no
+#60: pat=@([[=]=])A])         str===]A])           yes/yes
+#61: pat=@([[=]=])A])         str=AA])             no/no
+
+--- BRACKMATCH: after match vs before match ---
+#62: pat=[[=]=]ab]            str=a                no/no
+#63: pat=[[.[=.]ab]           str=a                yes/yes
+#64: pat=[[.[==].]ab]         str=a                yes/yes
+
+#65: pat=[a[=]=]b]            str=a                no/no
+#66: pat=[a[.[=.]b]           str=a                yes/yes
+#67: pat=[a[.[==].]b]         str=a                yes/yes
+
+#68: pat=[a[=]=]b]            str=b                no/no
+#69: pat=[a[=]=]b]            str=a=]b]            yes/yes
+#70: pat=[a[.[=.]b]           str=b                yes/yes
+#71: pat=[a[.[=.]b]           str=ab]              no/no
+#72: pat=[a[.[==].]b]         str=b                yes/yes
+#73: pat=[a[.[==].]b]         str=ab]              no/no
+
+--- incomplete POSIX brackets ---
+#74: pat=x[a[:y]              str=x[               yes/yes
+#75: pat=x[a[:y]              str=x:               yes/yes
+#76: pat=x[a[:y]              str=xy               yes/yes
+#77: pat=x[a[:y]              str=x[ay             no/no
+
+#78: pat=x[a[.y]              str=x[               yes/yes
+#79: pat=x[a[.y]              str=x.               yes/yes
+#80: pat=x[a[.y]              str=xy               yes/yes
+#81: pat=x[a[.y]              str=x[ay             no/no
+
+#82: pat=x[a[=y]              str=x[               yes/yes
+#83: pat=x[a[=y]              str=x=               yes/yes
+#84: pat=x[a[=y]              str=xy               yes/yes
+#85: pat=x[a[=y]              str=x[ay             no/no
+
+--- MISC tests ---
+#86: pat=a\                   str=a\               yes/yes
diff --git a/tests/glob-bracket.tests b/tests/glob-bracket.tests
new file mode 100644 (file)
index 0000000..35a55fa
--- /dev/null
@@ -0,0 +1,291 @@
+#   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 <http://www.gnu.org/licenses/>.
+#
+# tests of various aspects of pathname expansion, mostly dealing with bracket
+# expressions
+
+LC_COLLATE=C
+
+ORIG_DIR=$PWD
+
+: ${TMPDIR:=/tmp} ${BUILD_DIR:=$ORIG_DIR}
+
+trap 'rm -rf $TESTDIR $WORK_DIR' EXIT
+
+WORK_DIR=${TMPDIR}/globtest-$$
+
+mkdir $WORK_DIR || {
+       echo "cannot create directory $WORK_DIR" >&2
+       exit 1
+}
+cd $WORK_DIR || {
+       echo "cannot cd to directory $WORK_DIR" >&2
+       exit 1
+}
+
+gcc -O2 -xc -o ./fnmatch - <<-EOF
+       #include <fnmatch.h>
+       #include <stdlib.h>
+       #include <stdio.h>
+
+       int main(int argc, char **argv) {
+         if (2 >= argc) {
+           fprintf(stderr, "usage: fnmatch string pattern\n");
+           exit(2);
+         }
+
+#ifdef FNM_EXTMATCH
+         int flags = FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH;
+#else
+         int flags = FNM_PATHNAME | FNM_PERIOD;
+#endif
+         if (fnmatch(argv[2], argv[1], flags) == 0)
+           return 0;
+         return 1;
+       }
+EOF
+
+eval $(grep -E '^(CC |SHOBJ_).*=' $BUILD_DIR/examples/loadables/Makefile | sed -e 's/[ ]*=[ ]*/="/' -e 's/$/"/' )
+
+if [ "$SHOBJ_STATUS" != "supported" ]; then
+       echo "glob-bracket: shared objects not supported, cannot continue" >&2
+       exit 2
+fi
+
+cat > ./strmatch.c <<-EOF
+       #define BUILTIN_ENABLED 0x01
+       struct word_desc { char* word; int flags; };
+       struct word_list { struct word_list* next; struct word_desc* word; };
+       struct builtin {
+         const char* name;
+         int (*function)(struct word_list*);
+         int flags;
+         const char** long_doc;
+         const char* short_doc;
+         char* handle;
+       };
+
+       /*#include <glob/strmatch.h>*/
+       int strmatch(char *pattern, char *string, int flags);
+       #define FNM_PATHNAME    (1 << 0)
+       #define FNM_NOESCAPE    (1 << 1)
+       #define FNM_PERIOD      (1 << 2)
+       #define FNM_LEADING_DIR (1 << 3)
+       #define FNM_CASEFOLD    (1 << 4)
+       #define FNM_EXTMATCH    (1 << 5)
+       #define FNM_FIRSTCHAR   (1 << 6)
+       #define FNM_DOTDOT      (1 << 7)
+
+       static int strmatch_builtin(struct word_list* list) {
+         char *str, *pat;
+         if (!list || !list->word) return 2;
+         str = list->word->word;
+         if (!list->next || !list->next->word) return 2;
+         pat = list->next->word->word;
+
+         if (strmatch (pat, str, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0)
+           return 0;
+         return 1;
+       }
+       static const char* strmatch_doc[] = { "This is a builtin to test the behavior of strmatch", 0 };
+       struct builtin strmatch_struct = { "strmatch", strmatch_builtin, BUILTIN_ENABLED, strmatch_doc, "strmatch string pattern", 0, };
+EOF
+
+${SHOBJ_CC} ${SHOBJ_CFLAGS} -c -o strmatch.o strmatch.c
+rm -f strmatch.c
+
+${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o strmatch.so strmatch.o ${SHOBJ_LIBS}
+rm -f strmatch.o
+
+if [ ! -f strmatch.so ] ; then
+       echo "glob-bracket: cannot create strmatch loadable builtin" >&2
+       exit 2
+fi
+
+enable -f ./strmatch.so strmatch || {
+       echo "glob-bracket: cannot load strmatch builtin" >&2
+       exit 2
+}
+       
+check_count=1
+
+if [ -z "$BASH_TSTOUT" ]; then
+       yes=$(printf '\033[32myes\033[m') no=$(printf '\033[31mno\033[m')
+else
+       yes=yes no=no
+fi
+
+function check {
+  # bash impl
+  if strmatch "$2" "$1"; then
+    local strmatch=$yes
+  else
+    local strmatch=$no
+  fi
+
+  # fnmatch
+  local expect=${3-}
+  if [[ ! $expect ]]; then
+    if $WORK_DIR/fnmatch "$2" "$1"; then
+      expect=$yes
+    else
+      expect=$no
+    fi
+  fi
+  printf '#%d: pat=%-20s str=%-16s %s/%s\n' "$((check_count++))" "$1" "$2" "$strmatch" "$expect"
+}
+
+function pcheck {
+  local GLOBIGNORE=$1
+
+  # bash impl
+  local -a f=(*/*/efg*)
+  if [[ $f == '*/*/efg*' ]]; then
+    local strmatch=$yes
+  else
+    local strmatch=$no
+  fi
+
+  # Linux fnmatch
+  if $WORK_DIR/fnmatch ab/cd/efg "$1"; then
+    local fnmatch=$yes
+  else
+    local fnmatch=$no
+  fi
+
+  printf '#%d: pat=%-16s %s/%s\n' "$((check_count++))" "$1" "$strmatch" "$fnmatch"
+}
+
+TESTDIR=${TMPDIR}/pathtest-$$
+TESTPATH=${TESTDIR}/ab/cd/efg
+mkdir -p $TESTPATH
+
+if [ -d "$TESTPATH" ] && cd "$TESTDIR"; then
+echo '--- $GLOBIGNORE vs fnmatch(3) ---'
+pcheck 'ab/cd/efg'
+pcheck 'ab[/]cd/efg'
+pcheck 'ab[/a]cd/efg'
+pcheck 'ab[a/]cd/efg'
+pcheck 'ab[!a]cd/efg'
+pcheck 'ab[.-0]cd/efg'
+pcheck '*/*/efg'
+pcheck '*[/]*/efg'
+pcheck '*[/a]*/efg'
+pcheck '*[a/]*/efg'
+pcheck '*[!a]*/efg'
+pcheck '*[.-0]*/efg'
+
+pcheck '*/*/efg'
+pcheck '*[b]/*/efg'
+pcheck '*[ab]/*/efg'
+pcheck '*[ba]/*/efg'
+pcheck '*[!a]/*/efg'
+pcheck '*[a-c]/*/efg'
+
+pcheck 'ab@(/)cd/efg'
+pcheck '*@(/)cd/efg'
+pcheck '*/cd/efg'
+
+cd "$WORK_DIR"
+fi
+
+echo
+echo '---Tests for a slash in bracket expressions---'
+check 'ab[/]ef'          'ab[/]ef'     "$yes"
+check 'ab[/]ef'          'ab/ef'       "$no"
+check 'ab[c/d]ef'        'ab[c/d]ef'   "$yes"
+check 'ab[c/d]ef'        'abcef'       "$no"
+check 'ab[.-/]ef'        'ab[.-/]ef'   "$yes"
+check 'ab[.-/]ef'        'ab.ef'       "$no"
+check 'ab[[=/=]]ef'      'ab[[=/=]]ef' "$yes"
+check 'ab[[=/=]]ef'      'ab/ef'       "$no"
+check 'ab[[=c=]/]ef'     'ab[=/]ef'    "$yes"
+check 'ab[[=c=]/]ef'     'abcef'       "$no"
+check 'ab[[:alpha:]/]ef' 'ab[:/]ef'    "$yes"
+check 'ab[[:alpha:]/]ef' 'abxef'       "$no"
+check 'ab[/[abc]]ef'     'ab[/c]ef'    "$yes"
+check 'ab[/[abc]]ef'     'abc]ef'      "$no"
+check 'ab[c[=/=]]ef'     'ab[c[=/=]]ef' "$yes"
+check 'ab[c[=/=]]ef'     'abc[=/=]ef'   "$no"
+check 'ab[c[=/=]]ef'     'abcef'        "$no"
+check 'a[b\/c]'          'a[b/c]'      "$yes"
+check 'a[b\/c]'          'ab'          "$no"
+check 'a[b\/c]'          'ac'          "$no"
+
+echo
+echo '---Tests for incomplete bracket expressions---'
+check 'ab[c'             'ab[c'         "$yes"
+check 'ab[c'             'abc'          "$no"
+check 'ab[c[=d='         'ab[c[=d='     "$yes"
+check 'ab[c[=d='         'abc'          "$no"
+check 'ab[c[.d'          'ab[c[.d'      "$yes"
+check 'ab[c[.d'          'abc'          "$no"
+check 'ab[c[:alpha:'     'ab[c[:alpha:' "$yes"
+check 'ab[c[:alpha:'     'abc'          "$no"
+check 'ab[c-'            'ab[c-'        "$yes"
+check 'ab[c-'            'abc'          "$no"
+check 'ab[c\'            'ab[c\'        "$yes"
+check 'ab[c\'            'abc'          "$no"
+check 'ab[[\'            'ab[[\'        "$yes"
+check 'ab[[\'            'ab['          "$no"
+
+echo
+echo '--- PATSCAN vs BRACKMATCH ---'
+check '@([[.].])A])' ']'        "$yes"
+check '@([[.].])A])' '==]A])'   "$no"
+check '@([[.].])A])' 'AA])'     "$no"
+check '@([[=]=])A])' ']'        "$no"
+check '@([[=]=])A])' '==]A])'   "$yes"
+check '@([[=]=])A])' 'AA])'     "$no"
+
+echo
+echo '--- BRACKMATCH: after match vs before match ---'
+check '[[=]=]ab]'    'a'     "$no"
+check '[[.[=.]ab]'   'a'     "$yes"
+check '[[.[==].]ab]' 'a'     "$yes"
+echo
+check '[a[=]=]b]'    'a'     "$no"
+check '[a[.[=.]b]'   'a'     "$yes"
+check '[a[.[==].]b]' 'a'     "$yes"
+echo
+check '[a[=]=]b]'    'b'     "$no"
+check '[a[=]=]b]'    'a=]b]' "$yes"
+check '[a[.[=.]b]'   'b'     "$yes"
+check '[a[.[=.]b]'   'ab]'   "$no"
+check '[a[.[==].]b]' 'b'     "$yes"
+check '[a[.[==].]b]' 'ab]'   "$no"
+
+echo
+echo '--- incomplete POSIX brackets ---'
+check 'x[a[:y]' 'x['   "$yes"
+check 'x[a[:y]' 'x:'   "$yes"
+check 'x[a[:y]' 'xy'   "$yes"
+check 'x[a[:y]' 'x[ay' "$no"
+echo                   
+check 'x[a[.y]' 'x['   "$yes"
+check 'x[a[.y]' 'x.'   "$yes"
+check 'x[a[.y]' 'xy'   "$yes"
+check 'x[a[.y]' 'x[ay' "$no"
+echo                   
+check 'x[a[=y]' 'x['   "$yes"
+check 'x[a[=y]' 'x='   "$yes"
+check 'x[a[=y]' 'xy'   "$yes"
+check 'x[a[=y]' 'x[ay' "$no"
+
+echo
+echo '--- MISC tests ---'
+check 'a\'               'a\'          "$yes"
+
+cd $ORIG_DIR
+
+exit 0
diff --git a/tests/misc/glob-test b/tests/misc/glob-test
new file mode 100644 (file)
index 0000000..d32988b
--- /dev/null
@@ -0,0 +1,388 @@
+export LC_COLLATE=C
+#
+# test the shell globbing
+#
+expect()
+{
+       echo expect "$@"
+}
+
+# First, a test that bash-2.01.1 fails
+${THIS_SH} ./glob1.sub
+
+MYDIR=$PWD     # save where we are
+
+TESTDIR=/tmp/glob-test
+mkdir $TESTDIR
+builtin cd $TESTDIR || { echo $0: cannot cd to $TESTDIR >&2 ; exit 1; }
+rm -rf *
+
+touch a b c d abc abd abe bb bcd ca cb dd de Beware
+mkdir bdir
+
+# see if `regular' globbing works right
+expect '<a> <abc> <abd> <abe> <X*>'
+recho a* X*
+
+expect '<a> <abc> <abd> <abe>'
+recho \a*
+
+# see if null glob expansion works
+shopt -s nullglob
+
+expect '<a> <abc> <abd> <abe>'
+recho a* X*
+
+shopt -u nullglob
+
+# see if the failglob option works
+
+mkdir tmp
+touch tmp/l1 tmp/l2 tmp/l3
+builtin echo tmp/l[12] tmp/*4 tmp/*3
+shopt -s failglob
+builtin echo tmp/l[12] tmp/*4 tmp/*3
+rm -r tmp
+shopt -u failglob
+
+# see if the code that expands directories only works
+expect '<bdir/>'
+recho b*/
+
+# Test quoted and unquoted globbing characters
+expect '<*>'
+recho \*
+
+expect '<a*>'
+recho 'a*'
+
+expect '<a*>'
+recho a\*
+
+expect '<c> <ca> <cb> <a*> <*q*>'
+recho c* a\* *q*
+
+expect '<**>'
+recho "*"*
+
+expect '<**>'
+recho \**
+
+expect '<\.\./*/>'
+recho "\.\./*/"
+
+expect '<s/\..*//>'
+recho 's/\..*//'
+
+# Pattern from Larry Wall's Configure that caused bash to blow up
+expect '</^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/>'
+recho "/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*"'$'"/\1/"
+
+# Make sure character classes work properly
+
+expect '<abc> <abd> <abe> <bb> <cb>'
+recho [a-c]b*
+
+expect '<abd> <abe> <bb> <bcd> <bdir> <ca> <cb> <dd> <de>'
+recho [a-y]*[^c]
+
+expect '<abd> <abe>'
+recho a*[^c]
+
+touch a-b aXb
+expect '<a-b> <aXb>'
+recho a[X-]b
+
+touch .x .y
+expect '<Beware> <d> <dd> <de>'
+recho [^a-c]*
+
+# Make sure that filenames with embedded globbing characters are handled
+# properly
+mkdir a\*b
+> a\*b/ooo
+
+expect '<a*b/ooo>'
+recho a\*b/*
+
+expect '<a*b/ooo>'
+recho a\*?/*
+
+expect '<no match>'
+cmd='echo !7'
+case "$cmd" in
+*\\!*) echo match ;;
+*) echo no match ;;
+esac
+
+expect '<not there>'
+file='r.*'
+case $file in
+*.\*) echo not there ;;
+*) echo there ;;
+esac
+
+# examples from the Posix.2 spec (d11.2, p. 243)
+expect '<abc>'
+recho a[b]c
+
+expect '<abc>'
+recho a["b"]c
+
+expect '<abc>'
+recho a[\b]c
+
+expect '<abc>'
+recho a?c
+
+expect '<match 1>'
+case abc in
+a"b"c) echo 'match 1' ;;
+*)     echo 'BAD match 1' ;;
+esac
+
+expect '<match 2>'
+case abc in
+a*c)   echo 'match 2' ;;
+*)     echo 'BAD match 2' ;;
+esac
+
+expect '<ok 1>'
+case abc in
+"a?c") echo 'bad 1' ;;
+*)     echo 'ok 1' ;;
+esac
+
+expect '<ok 2>'
+case abc in
+a\*c)  echo 'bad 2' ;;
+*)     echo 'ok 2' ;;
+esac
+
+expect '<ok 3>'
+case abc in
+a\[b]c)        echo 'bad 3' ;;
+*)     echo 'ok 3' ;;
+esac
+
+expect '<ok 4>'
+case "$nosuchvar" in
+"")    echo 'ok 4' ;;
+*)     echo 'bad 4' ;;
+esac
+
+# This is very odd, but sh and ksh seem to agree
+expect '<ok 5>'
+case abc in
+a["\b"]c) echo 'ok 5' ;;
+*)     echo 'bad 5' ;;
+esac
+
+mkdir man
+mkdir man/man1
+touch man/man1/bash.1
+expect '<man/man1/bash.1>'
+recho */man*/bash.*
+expect '<man/man1/bash.1>'
+recho $(echo */man*/bash.*)
+expect '<man/man1/bash.1>'
+recho "$(echo */man*/bash.*)"
+
+# tests with multiple `*'s
+case abc in
+a***c) echo ok 1;;
+esac
+
+case abc in
+a*****?c)      echo ok 2;;
+esac
+
+case abc in
+?*****??)      echo ok 3;;
+esac
+
+case abc in
+*****??)       echo ok 4;;
+esac
+
+case abc in
+*****??c)      echo ok 5;;
+esac
+
+case abc in
+?*****?c)      echo ok 6;;
+esac
+
+case abc in
+?***?****c)    echo ok 7;;
+esac
+
+case abc in
+?***?****?)    echo ok 8;;
+esac
+
+case abc in
+?***?****)     echo ok 9;;
+esac
+
+case abc in
+*******c)      echo ok 10;;
+esac
+
+case abc in
+*******?)      echo ok 11;;
+esac
+
+case abcdecdhjk in
+a*cd**?**??k)  echo ok 20;;
+esac
+
+case abcdecdhjk in
+a**?**cd**?**??k)      echo ok 21;;
+esac
+
+case abcdecdhjk in
+a**?**cd**?**??k***)   echo ok 22;;
+esac
+
+case abcdecdhjk in
+a**?**cd**?**??***k)   echo ok 23;;
+esac
+
+case abcdecdhjk in
+a**?**cd**?**??***k**) echo ok 24;;
+esac
+
+case abcdecdhjk in
+a****c**?**??*****)    echo ok 25;;
+esac
+
+case '-' in
+[-abc])        echo ok 26 ;;
+esac
+
+case '-' in
+[abc-]) echo ok 27 ;;
+esac
+
+case '\' in
+\\)    echo ok 28 ;;
+esac
+
+case '\' in
+[\\])  echo ok 29 ;;
+esac
+
+case '\' in
+'\')   echo ok 30 ;;
+esac
+
+case '[' in
+[[])   echo ok 31 ;;
+esac
+
+# a `[' without a closing `]' is just another character to match, in the
+# bash implementation
+case '[' in
+[)     echo ok 32 ;;
+esac
+
+case '[abc' in
+[*)    echo 'ok 33';;
+esac
+
+# a right bracket shall lose its special meaning and represent itself in
+# a bracket expression if it occurs first in the list.  -- POSIX.2 2.8.3.2
+case ']' in
+[]])   echo ok 34 ;;
+esac
+
+case '-' in
+[]-])  echo ok 35 ;;
+esac
+
+# a backslash should just escape the next character in this context
+case p in
+[a-\z])        echo ok 36 ;;
+esac
+
+# this was a bug in all versions up to bash-2.04-release
+case "/tmp" in
+[/\\]*) echo ok 37 ;;
+esac
+
+# none of these should output anything
+
+case abc in
+??**********?****?)    echo bad 1;;
+esac
+
+case abc in
+??**********?****c)    echo bad 2;;
+esac
+
+case abc in
+?************c****?****)       echo bad 3;;
+esac
+
+case abc in
+*c*?**)        echo bad 4;;
+esac
+
+case abc in
+a*****c*?**)   echo bad 5;;
+esac
+
+case abc in
+a********???*******)   echo bad 6;;
+esac
+
+case 'a' in
+[])    echo bad 7 ;;
+esac
+
+case '[' in
+[abc)  echo bad 8;;
+esac
+
+# let's start testing the case-insensitive globbing code
+recho b*
+
+shopt -s nocaseglob
+recho b*
+
+recho [b]*
+shopt -u nocaseglob
+
+# make sure set -f works right
+set -f
+recho *
+set +f
+
+# test out the GLOBIGNORE code
+GLOBIGNORE='.*:*c:*e:?'
+recho *
+
+GLOBIGNORE='.*:*b:*d:?'
+recho *
+
+# see if GLOBIGNORE can substitute for `set -f'
+GLOBIGNORE='.*:*'
+recho *
+
+unset GLOBIGNORE
+expect '<man/man1/bash.1>'
+recho */man*/bash.*
+
+# make sure null values for GLOBIGNORE have no effect
+GLOBIGNORE=
+expect '<man/man1/bash.1>'
+recho */man*/bash.*
+
+# this is for the benefit of pure coverage, so it writes the pcv file
+# in the right place, and for gprof
+builtin cd $MYDIR
+
+rm -rf $TESTDIR
+
+exit 0
index 1f749239562eb213807065847aafc10daaea144d..19e3229bacce31e87f41b68abdb38e890db9fc5f 100644 (file)
@@ -18,7 +18,7 @@
 export TMPDIR
 
 # basic /bin/sh syntax
-SUFFIX=`${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))'`
+SUFFIX=$( ${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))' )
 
 BASH_TSTOUT=${TMPDIR}/bashtst-$SUFFIX  # for now
 export BASH_TSTOUT
diff --git a/tests/run-glob-bracket b/tests/run-glob-bracket
new file mode 100644 (file)
index 0000000..ed269d5
--- /dev/null
@@ -0,0 +1,5 @@
+PATH=$PATH:`pwd`
+export PATH
+
+${THIS_SH} ./glob-bracket.tests > ${BASH_TSTOUT} 2>&1
+diff ${BASH_TSTOUT} glob-bracket.right && rm -f ${BASH_TSTOUT}
index 0c3a2e5fb1a05cc4d3135a23c5092a6bd1e7ee80..ece8cffe9c2ddaf1a352988f4652b6a6fe64fca0 100644 (file)
@@ -22,7 +22,7 @@
 export TMPDIR
 
 # basic /bin/sh syntax
-SUFFIX=`${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))'`
+SUFFIX=$( ${THIS_SH} -c 'echo $(( $RANDOM + $BASHPID ))' )
 
 BASH_TSTOUT=${TMPDIR}/bashtst-$SUFFIX  # for now
 export BASH_TSTOUT
index 4f808be3e44aa5b675e7af20af5e5f33d9f5d714..fc579764902f0e427aee609b44d7f948cf74022e 100644 (file)
@@ -90,6 +90,9 @@ ${THIS_SH} ./trap4.sub
 # Return trap issues
 ${THIS_SH} ./trap6.sub
 
+# eval and ERR trap
+${THIS_SH} ./trap7.sub
+
 #
 # show that setting a trap on SIGCHLD is not disastrous.
 #
diff --git a/tests/trap7.sub b/tests/trap7.sub
new file mode 100644 (file)
index 0000000..8da401a
--- /dev/null
@@ -0,0 +1,8 @@
+func()
+{
+     eval "trap 'return 42' ERR; false"
+     return 0
+}
+
+set -o errtrace
+func || echo oops: $?