Blame lib/fnmatch.c

Packit 33f14e
/* Copyright (C) 1991-1993, 1996-2007, 2009-2017 Free Software Foundation, Inc.
Packit 33f14e
Packit 33f14e
   This program is free software; you can redistribute it and/or modify
Packit 33f14e
   it under the terms of the GNU General Public License as published by
Packit 33f14e
   the Free Software Foundation; either version 3, or (at your option)
Packit 33f14e
   any later version.
Packit 33f14e
Packit 33f14e
   This program is distributed in the hope that it will be useful,
Packit 33f14e
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 33f14e
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 33f14e
   GNU General Public License for more details.
Packit 33f14e
Packit 33f14e
   You should have received a copy of the GNU General Public License
Packit 33f14e
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 33f14e
Packit 33f14e
#ifndef _LIBC
Packit 33f14e
# include <config.h>
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* Enable GNU extensions in fnmatch.h.  */
Packit 33f14e
#ifndef _GNU_SOURCE
Packit 33f14e
# define _GNU_SOURCE    1
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#include <fnmatch.h>
Packit 33f14e
Packit 33f14e
#include <alloca.h>
Packit 33f14e
#include <assert.h>
Packit 33f14e
#include <ctype.h>
Packit 33f14e
#include <errno.h>
Packit 33f14e
#include <stddef.h>
Packit 33f14e
#include <stdbool.h>
Packit 33f14e
#include <stdlib.h>
Packit 33f14e
#include <string.h>
Packit 33f14e
Packit 33f14e
#define WIDE_CHAR_SUPPORT \
Packit 33f14e
  (HAVE_WCTYPE_H && HAVE_BTOWC && HAVE_ISWCTYPE \
Packit 33f14e
   && HAVE_WMEMCHR && (HAVE_WMEMCPY || HAVE_WMEMPCPY))
Packit 33f14e
Packit 33f14e
/* For platform which support the ISO C amendment 1 functionality we
Packit 33f14e
   support user defined character classes.  */
Packit 33f14e
#if defined _LIBC || WIDE_CHAR_SUPPORT
Packit 33f14e
# include <wctype.h>
Packit 33f14e
# include <wchar.h>
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* We need some of the locale data (the collation sequence information)
Packit 33f14e
   but there is no interface to get this information in general.  Therefore
Packit 33f14e
   we support a correct implementation only in glibc.  */
Packit 33f14e
#ifdef _LIBC
Packit 33f14e
# include "../locale/localeinfo.h"
Packit 33f14e
# include "../locale/elem-hash.h"
Packit 33f14e
# include "../locale/coll-lookup.h"
Packit 33f14e
# include <shlib-compat.h>
Packit 33f14e
Packit 33f14e
# define CONCAT(a,b) __CONCAT(a,b)
Packit 33f14e
# define mbsrtowcs __mbsrtowcs
Packit 33f14e
# define fnmatch __fnmatch
Packit 33f14e
extern int fnmatch (const char *pattern, const char *string, int flags);
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#ifndef SIZE_MAX
Packit 33f14e
# define SIZE_MAX ((size_t) -1)
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
#include "flexmember.h"
Packit 33f14e
Packit 33f14e
#ifndef FALLTHROUGH
Packit 33f14e
# if __GNUC__ < 7
Packit 33f14e
#  define FALLTHROUGH ((void) 0)
Packit 33f14e
# else
Packit 33f14e
#  define FALLTHROUGH __attribute__ ((__fallthrough__))
Packit 33f14e
# endif
Packit 33f14e
#endif
Packit 33f14e
Packit 33f14e
/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set.  */
Packit 33f14e
#define NO_LEADING_PERIOD(flags) \
Packit 33f14e
  ((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
Packit 33f14e
Packit 33f14e
/* Comment out all this code if we are using the GNU C Library, and are not
Packit 33f14e
   actually compiling the library itself, and have not detected a bug
Packit 33f14e
   in the library.  This code is part of the GNU C
Packit 33f14e
   Library, but also included in many other GNU distributions.  Compiling
Packit 33f14e
   and linking in this code is a waste when using the GNU C library
Packit 33f14e
   (especially if it is a shared library).  Rather than having every GNU
Packit 33f14e
   program understand 'configure --with-gnu-libc' and omit the object files,
Packit 33f14e
   it is simpler to just do this in the source for each such file.  */
Packit 33f14e
Packit 33f14e
#if defined _LIBC || !defined __GNU_LIBRARY__ || !HAVE_FNMATCH_GNU
Packit 33f14e
Packit 33f14e
Packit 33f14e
# if ! (defined isblank || (HAVE_ISBLANK && HAVE_DECL_ISBLANK))
Packit 33f14e
#  define isblank(c) ((c) == ' ' || (c) == '\t')
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
# define STREQ(s1, s2) (strcmp (s1, s2) == 0)
Packit 33f14e
Packit 33f14e
# if defined _LIBC || WIDE_CHAR_SUPPORT
Packit 33f14e
/* The GNU C library provides support for user-defined character classes
Packit 33f14e
   and the functions from ISO C amendment 1.  */
Packit 33f14e
#  ifdef CHARCLASS_NAME_MAX
Packit 33f14e
#   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
Packit 33f14e
#  else
Packit 33f14e
/* This shouldn't happen but some implementation might still have this
Packit 33f14e
   problem.  Use a reasonable default value.  */
Packit 33f14e
#   define CHAR_CLASS_MAX_LENGTH 256
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
#  ifdef _LIBC
Packit 33f14e
#   define IS_CHAR_CLASS(string) __wctype (string)
Packit 33f14e
#  else
Packit 33f14e
#   define IS_CHAR_CLASS(string) wctype (string)
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
#  ifdef _LIBC
Packit 33f14e
#   define ISWCTYPE(WC, WT)     __iswctype (WC, WT)
Packit 33f14e
#  else
Packit 33f14e
#   define ISWCTYPE(WC, WT)     iswctype (WC, WT)
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
#  if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
Packit 33f14e
/* In this case we are implementing the multibyte character handling.  */
Packit 33f14e
#   define HANDLE_MULTIBYTE     1
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
# else
Packit 33f14e
#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, 'xdigit'.  */
Packit 33f14e
Packit 33f14e
#  define IS_CHAR_CLASS(string)                                               \
Packit 33f14e
   (STREQ (string, "alpha") || STREQ (string, "upper")                        \
Packit 33f14e
    || STREQ (string, "lower") || STREQ (string, "digit")                     \
Packit 33f14e
    || STREQ (string, "alnum") || STREQ (string, "xdigit")                    \
Packit 33f14e
    || STREQ (string, "space") || STREQ (string, "print")                     \
Packit 33f14e
    || STREQ (string, "punct") || STREQ (string, "graph")                     \
Packit 33f14e
    || STREQ (string, "cntrl") || STREQ (string, "blank"))
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
/* Avoid depending on library functions or files
Packit 33f14e
   whose names are inconsistent.  */
Packit 33f14e
Packit 33f14e
/* Global variable.  */
Packit 33f14e
static int posixly_correct;
Packit 33f14e
Packit 33f14e
# ifndef internal_function
Packit 33f14e
/* Inside GNU libc we mark some function in a special way.  In other
Packit 33f14e
   environments simply ignore the marking.  */
Packit 33f14e
#  define internal_function
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
/* Note that this evaluates C many times.  */
Packit 33f14e
# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
Packit 33f14e
# define CHAR   char
Packit 33f14e
# define UCHAR  unsigned char
Packit 33f14e
# define INT    int
Packit 33f14e
# define FCT    internal_fnmatch
Packit 33f14e
# define EXT    ext_match
Packit 33f14e
# define END    end_pattern
Packit 33f14e
# define L_(CS) CS
Packit 33f14e
# ifdef _LIBC
Packit 33f14e
#  define BTOWC(C)      __btowc (C)
Packit 33f14e
# else
Packit 33f14e
#  define BTOWC(C)      btowc (C)
Packit 33f14e
# endif
Packit 33f14e
# define STRLEN(S) strlen (S)
Packit 33f14e
# define STRCAT(D, S) strcat (D, S)
Packit 33f14e
# ifdef _LIBC
Packit 33f14e
#  define MEMPCPY(D, S, N) __mempcpy (D, S, N)
Packit 33f14e
# else
Packit 33f14e
#  if HAVE_MEMPCPY
Packit 33f14e
#   define MEMPCPY(D, S, N) mempcpy (D, S, N)
Packit 33f14e
#  else
Packit 33f14e
#   define MEMPCPY(D, S, N) ((void *) ((char *) memcpy (D, S, N) + (N)))
Packit 33f14e
#  endif
Packit 33f14e
# endif
Packit 33f14e
# define MEMCHR(S, C, N) memchr (S, C, N)
Packit 33f14e
# include "fnmatch_loop.c"
Packit 33f14e
Packit 33f14e
Packit 33f14e
# if HANDLE_MULTIBYTE
Packit 33f14e
#  define FOLD(c) ((flags & FNM_CASEFOLD) ? towlower (c) : (c))
Packit 33f14e
#  define CHAR  wchar_t
Packit 33f14e
#  define UCHAR wint_t
Packit 33f14e
#  define INT   wint_t
Packit 33f14e
#  define FCT   internal_fnwmatch
Packit 33f14e
#  define EXT   ext_wmatch
Packit 33f14e
#  define END   end_wpattern
Packit 33f14e
#  define L_(CS)        L##CS
Packit 33f14e
#  define BTOWC(C)      (C)
Packit 33f14e
#  ifdef _LIBC
Packit 33f14e
#   define STRLEN(S) __wcslen (S)
Packit 33f14e
#   define STRCAT(D, S) __wcscat (D, S)
Packit 33f14e
#   define MEMPCPY(D, S, N) __wmempcpy (D, S, N)
Packit 33f14e
#  else
Packit 33f14e
#   define STRLEN(S) wcslen (S)
Packit 33f14e
#   define STRCAT(D, S) wcscat (D, S)
Packit 33f14e
#   if HAVE_WMEMPCPY
Packit 33f14e
#    define MEMPCPY(D, S, N) wmempcpy (D, S, N)
Packit 33f14e
#   else
Packit 33f14e
#    define MEMPCPY(D, S, N) (wmemcpy (D, S, N) + (N))
Packit 33f14e
#   endif
Packit 33f14e
#  endif
Packit 33f14e
#  define MEMCHR(S, C, N) wmemchr (S, C, N)
Packit 33f14e
#  define WIDE_CHAR_VERSION 1
Packit 33f14e
Packit 33f14e
#  undef IS_CHAR_CLASS
Packit 33f14e
/* We have to convert the wide character string in a multibyte string.  But
Packit 33f14e
   we know that the character class names consist of alphanumeric characters
Packit 33f14e
   from the portable character set, and since the wide character encoding
Packit 33f14e
   for a member of the portable character set is the same code point as
Packit 33f14e
   its single-byte encoding, we can use a simplified method to convert the
Packit 33f14e
   string to a multibyte character string.  */
Packit 33f14e
static wctype_t
Packit 33f14e
is_char_class (const wchar_t *wcs)
Packit 33f14e
{
Packit 33f14e
  char s[CHAR_CLASS_MAX_LENGTH + 1];
Packit 33f14e
  char *cp = s;
Packit 33f14e
Packit 33f14e
  do
Packit 33f14e
    {
Packit 33f14e
      /* Test for a printable character from the portable character set.  */
Packit 33f14e
#  ifdef _LIBC
Packit 33f14e
      if (*wcs < 0x20 || *wcs > 0x7e
Packit 33f14e
          || *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
Packit 33f14e
        return (wctype_t) 0;
Packit 33f14e
#  else
Packit 33f14e
      switch (*wcs)
Packit 33f14e
        {
Packit 33f14e
        case L' ': case L'!': case L'"': case L'#': case L'%':
Packit 33f14e
        case L'&': case L'\'': case L'(': case L')': case L'*':
Packit 33f14e
        case L'+': case L',': case L'-': case L'.': case L'/':
Packit 33f14e
        case L'0': case L'1': case L'2': case L'3': case L'4':
Packit 33f14e
        case L'5': case L'6': case L'7': case L'8': case L'9':
Packit 33f14e
        case L':': case L';': case L'<': case L'=': case L'>':
Packit 33f14e
        case L'?':
Packit 33f14e
        case L'A': case L'B': case L'C': case L'D': case L'E':
Packit 33f14e
        case L'F': case L'G': case L'H': case L'I': case L'J':
Packit 33f14e
        case L'K': case L'L': case L'M': case L'N': case L'O':
Packit 33f14e
        case L'P': case L'Q': case L'R': case L'S': case L'T':
Packit 33f14e
        case L'U': case L'V': case L'W': case L'X': case L'Y':
Packit 33f14e
        case L'Z':
Packit 33f14e
        case L'[': case L'\\': case L']': case L'^': case L'_':
Packit 33f14e
        case L'a': case L'b': case L'c': case L'd': case L'e':
Packit 33f14e
        case L'f': case L'g': case L'h': case L'i': case L'j':
Packit 33f14e
        case L'k': case L'l': case L'm': case L'n': case L'o':
Packit 33f14e
        case L'p': case L'q': case L'r': case L's': case L't':
Packit 33f14e
        case L'u': case L'v': case L'w': case L'x': case L'y':
Packit 33f14e
        case L'z': case L'{': case L'|': case L'}': case L'~':
Packit 33f14e
          break;
Packit 33f14e
        default:
Packit 33f14e
          return (wctype_t) 0;
Packit 33f14e
        }
Packit 33f14e
#  endif
Packit 33f14e
Packit 33f14e
      /* Avoid overrunning the buffer.  */
Packit 33f14e
      if (cp == s + CHAR_CLASS_MAX_LENGTH)
Packit 33f14e
        return (wctype_t) 0;
Packit 33f14e
Packit 33f14e
      *cp++ = (char) *wcs++;
Packit 33f14e
    }
Packit 33f14e
  while (*wcs != L'\0');
Packit 33f14e
Packit 33f14e
  *cp = '\0';
Packit 33f14e
Packit 33f14e
#  ifdef _LIBC
Packit 33f14e
  return __wctype (s);
Packit 33f14e
#  else
Packit 33f14e
  return wctype (s);
Packit 33f14e
#  endif
Packit 33f14e
}
Packit 33f14e
#  define IS_CHAR_CLASS(string) is_char_class (string)
Packit 33f14e
Packit 33f14e
#  include "fnmatch_loop.c"
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
Packit 33f14e
int
Packit 33f14e
fnmatch (const char *pattern, const char *string, int flags)
Packit 33f14e
{
Packit 33f14e
# if HANDLE_MULTIBYTE
Packit 33f14e
#  define ALLOCA_LIMIT 2000
Packit 33f14e
  if (__builtin_expect (MB_CUR_MAX, 1) != 1)
Packit 33f14e
    {
Packit 33f14e
      mbstate_t ps;
Packit 33f14e
      size_t patsize;
Packit 33f14e
      size_t strsize;
Packit 33f14e
      size_t totsize;
Packit 33f14e
      wchar_t *wpattern;
Packit 33f14e
      wchar_t *wstring;
Packit 33f14e
      int res;
Packit 33f14e
Packit 33f14e
      /* Calculate the size needed to convert the strings to
Packit 33f14e
         wide characters.  */
Packit 33f14e
      memset (&ps, '\0', sizeof (ps));
Packit 33f14e
      patsize = mbsrtowcs (NULL, &pattern, 0, &ps) + 1;
Packit 33f14e
      if (__builtin_expect (patsize != 0, 1))
Packit 33f14e
        {
Packit 33f14e
          assert (mbsinit (&ps);;
Packit 33f14e
          strsize = mbsrtowcs (NULL, &string, 0, &ps) + 1;
Packit 33f14e
          if (__builtin_expect (strsize != 0, 1))
Packit 33f14e
            {
Packit 33f14e
              assert (mbsinit (&ps);;
Packit 33f14e
              totsize = patsize + strsize;
Packit 33f14e
              if (__builtin_expect (! (patsize <= totsize
Packit 33f14e
                                       && totsize <= SIZE_MAX / sizeof (wchar_t)),
Packit 33f14e
                                    0))
Packit 33f14e
                {
Packit 33f14e
                  errno = ENOMEM;
Packit 33f14e
                  return -1;
Packit 33f14e
                }
Packit 33f14e
Packit 33f14e
              /* Allocate room for the wide characters.  */
Packit 33f14e
              if (__builtin_expect (totsize < ALLOCA_LIMIT, 1))
Packit 33f14e
                wpattern = (wchar_t *) alloca (totsize * sizeof (wchar_t));
Packit 33f14e
              else
Packit 33f14e
                {
Packit 33f14e
                  wpattern = malloc (totsize * sizeof (wchar_t));
Packit 33f14e
                  if (__builtin_expect (! wpattern, 0))
Packit 33f14e
                    {
Packit 33f14e
                      errno = ENOMEM;
Packit 33f14e
                      return -1;
Packit 33f14e
                    }
Packit 33f14e
                }
Packit 33f14e
              wstring = wpattern + patsize;
Packit 33f14e
Packit 33f14e
              /* Convert the strings into wide characters.  */
Packit 33f14e
              mbsrtowcs (wpattern, &pattern, patsize, &ps);
Packit 33f14e
              assert (mbsinit (&ps);;
Packit 33f14e
              mbsrtowcs (wstring, &string, strsize, &ps);
Packit 33f14e
Packit 33f14e
              res = internal_fnwmatch (wpattern, wstring, wstring + strsize - 1,
Packit 33f14e
                                       flags & FNM_PERIOD, flags);
Packit 33f14e
Packit 33f14e
              if (__builtin_expect (! (totsize < ALLOCA_LIMIT), 0))
Packit 33f14e
                free (wpattern);
Packit 33f14e
              return res;
Packit 33f14e
            }
Packit 33f14e
        }
Packit 33f14e
    }
Packit 33f14e
Packit 33f14e
# endif /* HANDLE_MULTIBYTE */
Packit 33f14e
Packit 33f14e
  return internal_fnmatch (pattern, string, string + strlen (string),
Packit 33f14e
                           flags & FNM_PERIOD, flags);
Packit 33f14e
}
Packit 33f14e
Packit 33f14e
# ifdef _LIBC
Packit 33f14e
#  undef fnmatch
Packit 33f14e
versioned_symbol (libc, __fnmatch, fnmatch, GLIBC_2_2_3);
Packit 33f14e
#  if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_2_3)
Packit 33f14e
strong_alias (__fnmatch, __fnmatch_old)
Packit 33f14e
compat_symbol (libc, __fnmatch_old, fnmatch, GLIBC_2_0);
Packit 33f14e
#  endif
Packit 33f14e
libc_hidden_ver (__fnmatch, fnmatch)
Packit 33f14e
# endif
Packit 33f14e
Packit 33f14e
#endif  /* _LIBC or not __GNU_LIBRARY__.  */