Blame gnulib/lib/fnmatch.c

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