Blame lib/fnmatch.c

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