about summary refs log tree commit diff
path: root/posix
diff options
context:
space:
mode:
Diffstat (limited to 'posix')
-rw-r--r--posix/Versions4
-rw-r--r--posix/fnmatch.c16
-rw-r--r--posix/fnmatch_loop.c39
-rw-r--r--posix/tst-fnmatch.input1
4 files changed, 39 insertions, 21 deletions
diff --git a/posix/Versions b/posix/Versions
index 0d04fccc22..a302f7bed3 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -109,4 +109,8 @@ libc {
     # Used in macros.
     __sysconf;
   }
+  GLIBC_2.2.3 {
+    # Extended Interface.
+    fnmatch;
+  }
 }
diff --git a/posix/fnmatch.c b/posix/fnmatch.c
index 98c5ffc5ca..df4311a79c 100644
--- a/posix/fnmatch.c
+++ b/posix/fnmatch.c
@@ -55,10 +55,13 @@
 # include "../locale/localeinfo.h"
 # include "../locale/elem-hash.h"
 # include "../locale/coll-lookup.h"
+# include <shlib-compat.h>
 
 # define CONCAT(a,b) __CONCAT(a,b)
 # define mbsinit __mbsinit
 # define mbsrtowcs __mbsrtowcs
+# define fnmatch __fnmatch
+extern int fnmatch (const char *pattern, const char *string, int flags);
 #endif
 
 /* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set.  */
@@ -212,6 +215,8 @@ __wcschrnul (s, c)
 # else
 #  define BTOWC(C)	btowc (C)
 # endif
+# define STRLEN(S) strlen (S)
+# define STRCAT(D, S) strcat (D, S)
 # define MEMPCPY(D, S, N) __mempcpy (D, S, N)
 # define MEMCHR(S, C, N) memchr (S, C, N)
 # define STRCOLL(S1, S2) strcoll (S1, S2)
@@ -233,6 +238,8 @@ __wcschrnul (s, c)
 # define END	end_wpattern
 #  define L(CS)	L##CS
 #  define BTOWC(C)	(C)
+#  define STRLEN(S) __wcslen (S)
+#  define STRCAT(D, S) __wcscat (D, S)
 #  define MEMPCPY(D, S, N) __wmempcpy (D, S, N)
 #  define MEMCHR(S, C, N) wmemchr (S, C, N)
 #  define STRCOLL(S1, S2) wcscoll (S1, S2)
@@ -355,4 +362,13 @@ fnmatch (pattern, string, flags)
 			   flags & FNM_PERIOD, flags);
 }
 
+# ifdef _LIBC
+#  undef fnmatch
+versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
+#  if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
+strong_alias (__fnmatch, __fnmatch_old)
+compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
+#  endif
+# endif
+
 #endif	/* _LIBC or not __GNU_LIBRARY__.  */
diff --git a/posix/fnmatch_loop.c b/posix/fnmatch_loop.c
index e9c7af2b7e..940073412e 100644
--- a/posix/fnmatch_loop.c
+++ b/posix/fnmatch_loop.c
@@ -1011,6 +1011,7 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
     CHAR str[0];
   } *list = NULL;
   struct patternlist **lastp = &list;
+  size_t pattern_len = STRLEN (pattern);
   const CHAR *p;
   const CHAR *rs;
 
@@ -1049,9 +1050,14 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
 	  {
 	    /* This means we found the end of the pattern.  */
 #define NEW_PATTERN \
-	    struct patternlist *newp = alloca (sizeof (struct patternlist)    \
-					       + ((p - startp + 1)	      \
-						  * sizeof (CHAR)));	      \
+	    struct patternlist *newp;					      \
+									      \
+	    if (opt == L('?') || opt == L('@'))				      \
+	      newp = alloca (sizeof (struct patternlist)		      \
+			     + (pattern_len * sizeof (CHAR)));		      \
+	    else							      \
+	      newp = alloca (sizeof (struct patternlist)		      \
+			     + ((p - startp + 1) * sizeof (CHAR)));	      \
 	    *((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0');    \
 	    newp->next = NULL;						      \
 	    *lastp = newp;						      \
@@ -1117,24 +1123,15 @@ EXT (INT opt, const CHAR *pattern, const CHAR *string, const CHAR *string_end,
 
     case L('@'):
       do
-	{
-	  for (rs = string; rs <= string_end; ++rs)
-	    /* First match the prefix with the current pattern with the
-	       current pattern.  */
-	    if (FCT (list->str, string, rs, no_leading_period,
-		     flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0
-		/* This was successful.  Now match the rest of the strings
-		   with the rest of the pattern.  */
-		&& (FCT (p, rs, string_end,
-			 rs == string
-			 ? no_leading_period
-			 : (rs[-1] == '/' && NO_LEADING_PERIOD (flags)
-			    ? 1 : 0),
-			 flags & FNM_FILE_NAME
-			 ? flags : flags & ~FNM_PERIOD) == 0))
-	      /* It worked.  Signal success.  */
-	      return 0;
-	}
+	/* I cannot believe it but `strcat' is actually acceptable
+	   here.  Match the entire string with the prefix from the
+	   pattern list and the rest of the pattern following the
+	   pattern list.  */
+	if (FCT (STRCAT (list->str, p), string, string_end,
+		 no_leading_period,
+		 flags & FNM_FILE_NAME ? flags : flags & ~FNM_PERIOD) == 0)
+	  /* It worked.  Signal success.  */
+	  return 0;
       while ((list = list->next) != NULL);
 
       /* None of the patterns lead to a match.  */
diff --git a/posix/tst-fnmatch.input b/posix/tst-fnmatch.input
index 6ae0a2aa82..219124556e 100644
--- a/posix/tst-fnmatch.input
+++ b/posix/tst-fnmatch.input
@@ -714,3 +714,4 @@ C		"]"			"!([!]a[])"	       0       EXTMATCH
 C		")"			"*([)])"	       0       EXTMATCH
 C		"*"			"*([*(])"	       0       EXTMATCH
 C		"abcd"			"*!(|a)cd"	       NOMATCH EXTMATCH
+C		"ab/.a"			"+([abc])/*"	       NOMATCH EXTMATCH|PATHNAME|PERIOD