]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - lib/glob/fnmatch.c
Imported from ../bash-2.01.tar.gz.
[thirdparty/bash.git] / lib / glob / fnmatch.c
index 0763609021538f07dc862f60bd42853dd8bc3373..2f8eb2402f15b6426bddd2effaceddd0fb67d12d 100644 (file)
@@ -50,15 +50,23 @@ fnmatch (pattern, string, flags)
          if (*n == '\0')
            return (FNM_NOMATCH);
          else if ((flags & FNM_PATHNAME) && *n == '/')
+           /* If we are matching a pathname, `?' can never match a `/'. */
            return (FNM_NOMATCH);
          else if ((flags & FNM_PERIOD) && *n == '.' &&
                   (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+           /* `?' cannot match a `.' if it is the first character of the
+              string or if it is the first character following a slash and
+              we are matching a pathname. */
            return (FNM_NOMATCH);
          break;
 
        case '\\':
          if (!(flags & FNM_NOESCAPE))
-           c = *p++;
+           {
+             c = *p++;
+             if (c == '\0')
+               return (FNM_NOMATCH);
+           }
          if (*n != c)
            return (FNM_NOMATCH);
          break;
@@ -66,23 +74,38 @@ fnmatch (pattern, string, flags)
        case '*':
          if ((flags & FNM_PERIOD) && *n == '.' &&
              (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
+           /* `*' cannot match a `.' if it is the first character of the
+              string or if it is the first character following a slash and
+              we are matching a pathname. */
            return (FNM_NOMATCH);
 
+         /* Collapse multiple consecutive, `*' and `?', but make sure that
+            one character of the string is consumed for each `?'. */
          for (c = *p++; c == '?' || c == '*'; c = *p++)
            {
-             if (((flags & FNM_PATHNAME) && *n == '/') ||
-                 (c == '?' && *n == '\0'))
+             if ((flags & FNM_PATHNAME) && *n == '/')
+               /* A slash does not match a wildcard under FNM_PATHNAME. */
                return (FNM_NOMATCH);
-             if (c == '?')
-               n++;
+             else if (c == '?')
+               {
+                 if (*n == '\0')
+                   return (FNM_NOMATCH);
+                 /* One character of the string is consumed in matching
+                    this ? wildcard, so *??? won't match if there are
+                    fewer than three characters. */
+                 n++;
+               }
            }
 
          if (c == '\0')
            return (0);
 
+         /* General case, use recursion. */
          {
            char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
            for (--p; *n != '\0'; ++n)
+             /* Only call fnmatch if the first character indicates a
+                possible match. */
              if ((c == '[' || *n == c1) &&
                  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
                return (0);
@@ -97,22 +120,30 @@ fnmatch (pattern, string, flags)
            if (*n == '\0')
              return (FNM_NOMATCH);
 
+           /* A character class cannot match a `.' if it is the first
+              character of the string or if it is the first character
+              following a slash and we are matching a pathname. */
            if ((flags & FNM_PERIOD) && *n == '.' &&
                (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
              return (FNM_NOMATCH);
 
-           /* Make sure there is a closing `]'.  If there isn't, the `['
-              is just a character to be matched. */
+           /* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
+              is not preceded by a backslash and is not part of a bracket
+              expression produces undefined results.'  This implementation
+              treats the `[' as just a character to be matched if there is
+              not a closing `]'.  This code will have to be changed when
+              POSIX.2 character classes are implemented. */
            {
              register char *np;
 
-             for (np = p; np && *np && *np != ']'; np++);
+             for (np = p; np && *np && *np != ']'; np++)
+               ;
 
              if (np && !*np)
                {
                  if (*n != '[')
                    return (FNM_NOMATCH);
-                 goto next_char;
+                 break;
                }
            }
              
@@ -123,10 +154,18 @@ fnmatch (pattern, string, flags)
            c = *p++;
            for (;;)
              {
-               register char cstart = c, cend = c;
+               register char cstart, cend;
+
+               /* Initialize cstart and cend in case `-' is the last
+                  character of the pattern. */
+               cstart = cend = c;
 
                if (!(flags & FNM_NOESCAPE) && c == '\\')
-                 cstart = cend = *p++;
+                 {
+                   if (*p == '\0')
+                     return FNM_NOMATCH;
+                   cstart = cend = *p++;
+                 }
 
                if (c == '\0')
                  /* [ (unterminated) loses.  */
@@ -138,6 +177,9 @@ fnmatch (pattern, string, flags)
                  /* [/] can never match.  */
                  return (FNM_NOMATCH);
 
+               /* This introduces a range, unless the `-' is the last
+                  character of the class.  Find the end of the range
+                  and move past it. */
                if (c == '-' && *p != ']')
                  {
                    cend = *p++;
@@ -145,6 +187,7 @@ fnmatch (pattern, string, flags)
                      cend = *p++;
                    if (cend == '\0')
                      return (FNM_NOMATCH);
+
                    c = *p++;
                  }
 
@@ -156,8 +199,6 @@ fnmatch (pattern, string, flags)
              }
            if (!not)
              return (FNM_NOMATCH);
-
-         next_char:
            break;
 
          matched:
@@ -170,8 +211,12 @@ fnmatch (pattern, string, flags)
 
                c = *p++;
                if (!(flags & FNM_NOESCAPE) && c == '\\')
-                 /* 1003.2d11 is unclear if this is right.  %%% */
-                 ++p;
+                 {
+                   if (*p == '\0')
+                     return FNM_NOMATCH;
+                   /* XXX 1003.2d11 is unclear if this is right. */
+                   ++p;
+                 }
              }
            if (not)
              return (FNM_NOMATCH);