about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--posix/fnmatch.c53
-rw-r--r--posix/testfnm.c3
3 files changed, 48 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index e4027a7209..bd10d114d6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+1999-04-26  Ulrich Drepper  <drepper@cygnus.com>
+
+	* posix/fnmatch.c: Include string.h also for glibc.
+	(fnmatch, case '?'): Optimize if cascades a bit.
+	(fnmatch, case '*'): Correct handling if FNM_PATHNAME is set.
+
+	* posix/testfnm.c: Add test cases for * with FNM_PATHNAME errors.
+
 1999-04-24  Ulrich Drepper  <drepper@cygnus.com>
 
 	* iconv/gconv_builtin.h: Add definitions for UTF16 builtins.
diff --git a/posix/fnmatch.c b/posix/fnmatch.c
index dc389efa39..e0ff2c34d2 100644
--- a/posix/fnmatch.c
+++ b/posix/fnmatch.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 93, 96, 97, 98 Free Software Foundation, Inc.
+/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    This library is free software; you can redistribute it and/or
@@ -29,7 +29,7 @@
 #include <fnmatch.h>
 #include <ctype.h>
 
-#if HAVE_STRING_H
+#if HAVE_STRING_H || defined _LIBC
 # include <string.h>
 #else
 # include <strings.h>
@@ -154,9 +154,9 @@ fnmatch (pattern, string, flags)
 	case '?':
 	  if (*n == '\0')
 	    return FNM_NOMATCH;
-	  else if ((flags & FNM_FILE_NAME) && *n == '/')
+	  else if (*n == '/' && (flags & FNM_FILE_NAME))
 	    return FNM_NOMATCH;
-	  else if ((flags & FNM_PERIOD) && *n == '.' &&
+	  else if (*n == '.' && (flags & FNM_PERIOD) &&
 		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
 	    return FNM_NOMATCH;
 	  break;
@@ -175,13 +175,13 @@ fnmatch (pattern, string, flags)
 	  break;
 
 	case '*':
-	  if ((flags & FNM_PERIOD) && *n == '.' &&
+	  if (*n == '.' && (flags & FNM_PERIOD) &&
 	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
 	    return FNM_NOMATCH;
 
 	  for (c = *p++; c == '?' || c == '*'; c = *p++)
 	    {
-	      if ((flags & FNM_FILE_NAME) && *n == '/')
+	      if (*n == '/' && (flags & FNM_FILE_NAME))
 		/* A slash does not match a wildcard under FNM_FILE_NAME.  */
 		return FNM_NOMATCH;
 	      else if (c == '?')
@@ -199,17 +199,38 @@ fnmatch (pattern, string, flags)
 	    }
 
 	  if (c == '\0')
-	    return 0;
+	    /* The wildcard(s) is/are the last element of the pattern.
+	       If the name is a file name and contains another slash
+	       this does mean it cannot match.  */
+	    return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
+		    ? FNM_NOMATCH : 0);
+	  else
+	    {
+	      const char *endp;
 
-	  {
-	    unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
-	    c1 = FOLD (c1);
-	    for (--p; *n != '\0'; ++n)
-	      if ((c == '[' || FOLD ((unsigned char) *n) == c1) &&
-		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
-		return 0;
-	    return FNM_NOMATCH;
-	  }
+	      if (!(flags & FNM_FILE_NAME) || (endp = strchr (n, '/')) == NULL)
+		endp = strchr (n, '\0');
+
+	      if (c == '[')
+		{
+		  for (--p; n < endp; ++n)
+		    if (fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+		      return 0;
+		}
+	      else
+		{
+		  if (c == '\\' && !(flags & FNM_NOESCAPE))
+		    c = *p;
+		  c = FOLD (c);
+		  for (--p; n < endp; ++n)
+		    if (FOLD ((unsigned char) *n) == c
+			&& fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
+		      return 0;
+		}
+	    }
+
+	  /* If we come here no match is possible with the wildcard.  */
+	  return FNM_NOMATCH;
 
 	case '[':
 	  {
diff --git a/posix/testfnm.c b/posix/testfnm.c
index 5ab761b8b2..b43f9531fb 100644
--- a/posix/testfnm.c
+++ b/posix/testfnm.c
@@ -13,6 +13,9 @@ struct {
   { "a/b", "a[/]b", 0, 0 },
   { "a/b", "a[/]b", FNM_PATHNAME, FNM_NOMATCH },
   { "a/b", "[a-z]/[a-z]", 0, 0 },
+  { "a/b", "*", FNM_FILE_NAME, FNM_NOMATCH },
+  { "a/b", "*[/]b", FNM_FILE_NAME, FNM_NOMATCH },
+  { "a/b", "*[b]", FNM_FILE_NAME, FNM_NOMATCH }
 };
 
 int