diff --git a/posix/fnmatch.c b/posix/fnmatch.c
index a9b7626..4be7327 100644
--- a/posix/fnmatch.c
+++ b/posix/fnmatch.c
@@ -34,11 +34,7 @@
 # include <stdlib.h>
 #endif
 
-#ifdef _LIBC
-# include <alloca.h>
-#else
-# define alloca_account(size., var) alloca (size)
-#endif
+#include <scratch_buffer.h>
 
 /* For platform which support the ISO C amendement 1 functionality we
    support user defined character classes.  */
@@ -315,128 +311,40 @@ is_char_class (const wchar_t *wcs)
 #  include "fnmatch_loop.c"
 # endif
 
-
 int
 fnmatch (const char *pattern, const char *string, int flags)
 {
 # if HANDLE_MULTIBYTE
-  if (__builtin_expect (MB_CUR_MAX, 1) != 1)
+  if (__glibc_unlikely (MB_CUR_MAX != 1))
     {
-      mbstate_t ps;
-      size_t n;
-      const char *p;
-      wchar_t *wpattern_malloc = NULL;
-      wchar_t *wpattern;
-      wchar_t *wstring_malloc = NULL;
-      wchar_t *wstring;
-      size_t alloca_used = 0;
+      mbstate_t ps = { 0 };
 
-      /* Convert the strings into wide characters.  */
-      memset (&ps, '\0', sizeof (ps));
-      p = pattern;
-#ifdef _LIBC
-      n = __strnlen (pattern, 1024);
-#else
-      n = strlen (pattern);
-#endif
-      if (__glibc_likely (n < 1024))
-	{
-	  wpattern = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t),
-						 alloca_used);
-	  n = mbsrtowcs (wpattern, &p, n + 1, &ps);
-	  if (__glibc_unlikely (n == (size_t) -1))
-	    /* Something wrong.
-	       XXX Do we have to set `errno' to something which mbsrtows hasn't
-	       already done?  */
-	    return -1;
-	  if (p)
-	    {
-	      memset (&ps, '\0', sizeof (ps));
-	      goto prepare_wpattern;
-	    }
-	}
-      else
-	{
-	prepare_wpattern:
-	  n = mbsrtowcs (NULL, &pattern, 0, &ps);
-	  if (__glibc_unlikely (n == (size_t) -1))
-	    /* Something wrong.
-	       XXX Do we have to set `errno' to something which mbsrtows hasn't
-	       already done?  */
-	    return -1;
-	  if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t)))
-	    {
-	      __set_errno (ENOMEM);
-	      return -2;
-	    }
-	  wpattern_malloc = wpattern
-	    = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t));
-	  assert (mbsinit (&ps));
-	  if (wpattern == NULL)
-	    return -2;
-	  (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
-	}
+      /* Calculate the size needed to convert the strings to wide
+	 characters.  */
+      size_t patsize = mbsrtowcs (NULL, &pattern, 0, &ps) + 1;
+      size_t strsize = mbsrtowcs (NULL, &string, 0, &ps) + 1;
+      size_t totsize = patsize + strsize;
 
-      assert (mbsinit (&ps));
-#ifdef _LIBC
-      n = __strnlen (string, 1024);
-#else
-      n = strlen (string);
-#endif
-      p = string;
-      if (__glibc_likely (n < 1024))
-	{
-	  wstring = (wchar_t *) alloca_account ((n + 1) * sizeof (wchar_t),
-						alloca_used);
-	  n = mbsrtowcs (wstring, &p, n + 1, &ps);
-	  if (__glibc_unlikely (n == (size_t) -1))
-	    {
-	      /* Something wrong.
-		 XXX Do we have to set `errno' to something which
-		 mbsrtows hasn't already done?  */
-	    free_return:
-	      free (wpattern_malloc);
-	      return -1;
-	    }
-	  if (p)
-	    {
-	      memset (&ps, '\0', sizeof (ps));
-	      goto prepare_wstring;
-	    }
-	}
-      else
+      struct scratch_buffer s;
+      scratch_buffer_init (&s);
+      if (!scratch_buffer_set_array_size (&s, totsize, sizeof (wchar_t)))
 	{
-	prepare_wstring:
-	  n = mbsrtowcs (NULL, &string, 0, &ps);
-	  if (__glibc_unlikely (n == (size_t) -1))
-	    /* Something wrong.
-	       XXX Do we have to set `errno' to something which mbsrtows hasn't
-	       already done?  */
-	    goto free_return;
-	  if (__glibc_unlikely (n >= (size_t) -1 / sizeof (wchar_t)))
-	    {
-	      free (wpattern_malloc);
-	      __set_errno (ENOMEM);
-	      return -2;
-	    }
-
-	  wstring_malloc = wstring
-	    = (wchar_t *) malloc ((n + 1) * sizeof (wchar_t));
-	  if (wstring == NULL)
-	    {
-	      free (wpattern_malloc);
-	      return -2;
-	    }
-	  assert (mbsinit (&ps));
-	  (void) mbsrtowcs (wstring, &string, n + 1, &ps);
+	  scratch_buffer_free (&s);
+	  errno = ENOMEM;
+	  return -1;
 	}
 
-      int res = internal_fnwmatch (wpattern, wstring, wstring + n,
-				   flags & FNM_PERIOD, flags, NULL,
-				   alloca_used);
+      wchar_t *wpattern = s.data;
+      wchar_t *wstring = wpattern + patsize;
+
+      /* Convert the strings into wide characters.  */
+      mbsrtowcs (wpattern, &pattern, patsize, &ps);
+      mbsrtowcs (wstring, &string, strsize, &ps);
+
+      int res = internal_fnwmatch (wpattern, wstring, wstring + strsize - 1,
+				   flags & FNM_PERIOD, flags, NULL, 0);
 
-      free (wstring_malloc);
-      free (wpattern_malloc);
+      scratch_buffer_free (&s);
 
       return res;
     }
