summary refs log tree commit diff
path: root/posix/fnmatch.c
diff options
context:
space:
mode:
Diffstat (limited to 'posix/fnmatch.c')
-rw-r--r--posix/fnmatch.c96
1 files changed, 67 insertions, 29 deletions
diff --git a/posix/fnmatch.c b/posix/fnmatch.c
index e0ff2c34d2..d31c375bd2 100644
--- a/posix/fnmatch.c
+++ b/posix/fnmatch.c
@@ -129,11 +129,10 @@ extern int errno;
 
 /* Match STRING against the filename pattern PATTERN, returning zero if
    it matches, nonzero if not.  */
-int
-fnmatch (pattern, string, flags)
-     const char *pattern;
-     const char *string;
-     int flags;
+static int
+internal_function
+internal_fnmatch (const char *pattern, const char *string,
+		  int no_leading_period, int flags)
 {
   register const char *p = pattern, *n = string;
   register unsigned char c;
@@ -156,8 +155,7 @@ fnmatch (pattern, string, flags)
 	    return FNM_NOMATCH;
 	  else if (*n == '/' && (flags & FNM_FILE_NAME))
 	    return FNM_NOMATCH;
-	  else if (*n == '.' && (flags & FNM_PERIOD) &&
-		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+	  else if (*n == '.' && no_leading_period)
 	    return FNM_NOMATCH;
 	  break;
 
@@ -175,8 +173,7 @@ fnmatch (pattern, string, flags)
 	  break;
 
 	case '*':
-	  if (*n == '.' && (flags & FNM_PERIOD) &&
-	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+	  if (*n == '.' && no_leading_period)
 	    return FNM_NOMATCH;
 
 	  for (c = *p++; c == '?' || c == '*'; c = *p++)
@@ -214,9 +211,22 @@ fnmatch (pattern, string, flags)
 	      if (c == '[')
 		{
 		  for (--p; n < endp; ++n)
-		    if (fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+		    if (internal_fnmatch (p, n,
+					  (n == string) && no_leading_period,
+					  ((flags & FNM_FILE_NAME)
+					   ? flags : (flags & ~FNM_PERIOD)))
+			== 0)
 		      return 0;
 		}
+	      else if (c == '/' && (flags & FNM_FILE_NAME))
+		{
+		  while (*n != '\0' && *n != '/')
+		    ++n;
+		  if (*n == '/'
+		      && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
+					    flags) == 0))
+		    return 0;
+		}
 	      else
 		{
 		  if (c == '\\' && !(flags & FNM_NOESCAPE))
@@ -224,7 +234,13 @@ fnmatch (pattern, string, flags)
 		  c = FOLD (c);
 		  for (--p; n < endp; ++n)
 		    if (FOLD ((unsigned char) *n) == c
-			&& fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+			&& (internal_fnmatch (p, n,
+					      ((n == string)
+					       && no_leading_period),
+					      ((flags & FNM_FILE_NAME)
+					       ? flags
+					       : (flags & ~FNM_PERIOD)))
+			    == 0))
 		      return 0;
 		}
 	    }
@@ -245,8 +261,7 @@ fnmatch (pattern, string, flags)
 	    if (*n == '\0')
 	      return FNM_NOMATCH;
 
-	    if (*n == '.' && (flags & FNM_PERIOD) &&
-		(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
+	    if (*n == '.' && no_leading_period)
 	      return FNM_NOMATCH;
 
 	    if (*n == '/' && (flags & FNM_FILE_NAME))
@@ -294,7 +309,15 @@ fnmatch (pattern, string, flags)
 			    p += 2;
 			    break;
 			  }
-			str[c1++] = 'c';
+			if (c < 'a' || c >= 'z')
+			  {
+			    /* This cannot possibly be a character class name.
+			       Match it as a normal range.  */
+			    --p;
+			    c = '[';
+			    goto normal_bracket;
+			  }
+			str[c1++] = c;
 		      }
 		    str[c1] = '\0';
 
@@ -325,26 +348,31 @@ fnmatch (pattern, string, flags)
 		else if (c == '\0')
 		  /* [ (unterminated) loses.  */
 		  return FNM_NOMATCH;
-		else if (FOLD (c) == fn)
-		  goto matched;
-
-		cold = c;
-		c = *p++;
-
-		if (c == '-' && *p != ']')
+		else
 		  {
-		    /* It is a range.  */
-		    unsigned char cend = *p++;
-		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
-		      cend = *p++;
-		    if (cend == '\0')
-		      return FNM_NOMATCH;
-
-		    if (cold <= fn && fn <= FOLD (cend))
+		  normal_bracket:
+		    if (FOLD (c) == fn)
 		      goto matched;
 
+		    cold = c;
 		    c = *p++;
+
+		    if (c == '-' && *p != ']')
+		      {
+			/* It is a range.  */
+			unsigned char cend = *p++;
+			if (!(flags & FNM_NOESCAPE) && cend == '\\')
+			  cend = *p++;
+			if (cend == '\0')
+			  return FNM_NOMATCH;
+
+			if (cold <= fn && fn <= FOLD (cend))
+			  goto matched;
+
+			c = *p++;
+		      }
 		  }
+
 		if (c == ']')
 		  break;
 	      }
@@ -404,4 +432,14 @@ fnmatch (pattern, string, flags)
 # undef FOLD
 }
 
+
+int
+fnmatch (pattern, string, flags)
+     const char *pattern;
+     const char *string;
+     int flags;
+{
+  return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
+}
+
 #endif	/* _LIBC or not __GNU_LIBRARY__.  */