Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
/* Enable GNU extensions in fnmatch.h. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#include <assert.h>
#include <errno.h>
#include <fnmatch.h>
#include <ctype.h>
#include <string.h>
#if defined STDC_HEADERS || defined _LIBC
# include <stdlib.h>
#endif
#ifdef _LIBC
# include <alloca.h>
#else
# define alloca_account(size., var) alloca (size)
#endif
/* For platform which support the ISO C amendement 1 functionality we
support user defined character classes. */
#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
# include <wchar.h>
# include <wctype.h>
#endif
/* We need some of the locale data (the collation sequence information)
but there is no interface to get this information in general. Therefore
we support a correct implementation only in glibc. */
#ifdef _LIBC
# 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 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. */
#define NO_LEADING_PERIOD(flags) \
((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined _LIBC || !defined __GNU_LIBRARY__
# if defined STDC_HEADERS || !defined isascii
# define ISASCII(c) 1
# else
# define ISASCII(c) isascii(c)
# endif
# ifdef isblank
# define ISBLANK(c) (ISASCII (c) && isblank (c))
# else
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
# endif
# ifdef isgraph
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
# else
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
# endif
# define ISPRINT(c) (ISASCII (c) && isprint (c))
# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
# define ISALNUM(c) (ISASCII (c) && isalnum (c))
# define ISALPHA(c) (ISASCII (c) && isalpha (c))
# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
# define ISLOWER(c) (ISASCII (c) && islower (c))
# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
# define ISSPACE(c) (ISASCII (c) && isspace (c))
# define ISUPPER(c) (ISASCII (c) && isupper (c))
# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* The GNU C library provides support for user-defined character classes
and the functions from ISO C amendement 1. */
# ifdef CHARCLASS_NAME_MAX
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
# else
/* This shouldn't happen but some implementation might still have this
problem. Use a reasonable default value. */
# define CHAR_CLASS_MAX_LENGTH 256
# endif
# ifdef _LIBC
# define IS_CHAR_CLASS(string) __wctype (string)
# else
# define IS_CHAR_CLASS(string) wctype (string)
# endif
# ifdef _LIBC
# define ISWCTYPE(WC, WT) __iswctype (WC, WT)
# else
# define ISWCTYPE(WC, WT) iswctype (WC, WT)
# endif
# if (HAVE_MBSTATE_T && HAVE_MBSRTOWCS) || _LIBC
/* In this case we are implementing the multibyte character handling. */
# define HANDLE_MULTIBYTE 1
# endif
# else
# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
# define IS_CHAR_CLASS(string) \
(STREQ (string, "alpha") || STREQ (string, "upper") \
|| STREQ (string, "lower") || STREQ (string, "digit") \
|| STREQ (string, "alnum") || STREQ (string, "xdigit") \
|| STREQ (string, "space") || STREQ (string, "print") \
|| STREQ (string, "punct") || STREQ (string, "graph") \
|| STREQ (string, "cntrl") || STREQ (string, "blank"))
# endif
/* Avoid depending on library functions or files
whose names are inconsistent. */
# if !defined _LIBC && !defined getenv
extern char *getenv ();
# endif
# ifndef errno
extern int errno;
# endif
/* Global variable. */
static int posixly_correct;
/* This function doesn't exist on most systems. */
# if !defined HAVE___STRCHRNUL && !defined _LIBC
static char *
__strchrnul (const char *s, int c)
{
char *result = strchr (s, c);
if (result == NULL)
result = strchr (s, '\0');
return result;
}
# endif
# if HANDLE_MULTIBYTE && !defined HAVE___STRCHRNUL && !defined _LIBC
static wchar_t *
__wcschrnul (const wchar_t *s, wint_t c)
{
wchar_t *result = wcschr (s, c);
if (result == NULL)
result = wcschr (s, '\0');
return result;
}
# endif
# ifndef internal_function
/* Inside GNU libc we mark some function in a special way. In other
environments simply ignore the marking. */
# define internal_function
# endif
/* Note that this evaluates C many times. */
# ifdef _LIBC
# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
# else
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
# endif
# define CHAR char
# define UCHAR unsigned char
# define INT int
# define FCT internal_fnmatch
# define EXT ext_match
# define END end_pattern
# define STRUCT fnmatch_struct
# define L(CS) CS
# ifdef _LIBC
# define BTOWC(C) __btowc (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)
# define WIDE_CHAR_VERSION 0
# include <locale/weight.h>
# define FINDIDX findidx
# include "fnmatch_loop.c"
# if HANDLE_MULTIBYTE
/* Note that this evaluates C many times. */
# ifdef _LIBC
# define FOLD(c) ((flags & FNM_CASEFOLD) ? __towlower (c) : (c))
# else
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? towlower (c) : (c))
# endif
# define CHAR wchar_t
# define UCHAR wint_t
# define INT wint_t
# define FCT internal_fnwmatch
# define EXT ext_wmatch
# define END end_wpattern
# define STRUCT fnwmatch_struct
# 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)
# define WIDE_CHAR_VERSION 1
/* Change the name the header defines so it doesn't conflict with
the <locale/weight.h> version included above. */
# define findidx findidxwc
# include <locale/weightwc.h>
# undef findidx
# define FINDIDX findidxwc
# undef IS_CHAR_CLASS
/* We have to convert the wide character string in a multibyte string. But
we know that the character class names consist of alphanumeric characters
from the portable character set, and since the wide character encoding
for a member of the portable character set is the same code point as
its single-byte encoding, we can use a simplified method to convert the
string to a multibyte character string. */
static wctype_t
is_char_class (const wchar_t *wcs)
{
char s[CHAR_CLASS_MAX_LENGTH + 1];
char *cp = s;
do
{
/* Test for a printable character from the portable character set. */
# ifdef _LIBC
if (*wcs < 0x20 || *wcs > 0x7e
|| *wcs == 0x24 || *wcs == 0x40 || *wcs == 0x60)
return (wctype_t) 0;
# else
switch (*wcs)
{
case L' ': case L'!': case L'"': case L'#': case L'%':
case L'&': case L'\'': case L'(': case L')': case L'*':
case L'+': case L',': case L'-': case L'.': case L'/':
case L'0': case L'1': case L'2': case L'3': case L'4':
case L'5': case L'6': case L'7': case L'8': case L'9':
case L':': case L';': case L'<': case L'=': case L'>':
case L'?':
case L'A': case L'B': case L'C': case L'D': case L'E':
case L'F': case L'G': case L'H': case L'I': case L'J':
case L'K': case L'L': case L'M': case L'N': case L'O':
case L'P': case L'Q': case L'R': case L'S': case L'T':
case L'U': case L'V': case L'W': case L'X': case L'Y':
case L'Z':
case L'[': case L'\\': case L']': case L'^': case L'_':
case L'a': case L'b': case L'c': case L'd': case L'e':
case L'f': case L'g': case L'h': case L'i': case L'j':
case L'k': case L'l': case L'm': case L'n': case L'o':
case L'p': case L'q': case L'r': case L's': case L't':
case L'u': case L'v': case L'w': case L'x': case L'y':
case L'z': case L'{': case L'|': case L'}': case L'~':
break;
default:
return (wctype_t) 0;
}
# endif
/* Avoid overrunning the buffer. */
if (cp == s + CHAR_CLASS_MAX_LENGTH)
return (wctype_t) 0;
*cp++ = (char) *wcs++;
}
while (*wcs != L'\0');
*cp = '\0';
# ifdef _LIBC
return __wctype (s);
# else
return wctype (s);
# endif
}
# define IS_CHAR_CLASS(string) is_char_class (string)
# 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)
{
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;
/* 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);
}
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
{
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);
}
int res = internal_fnwmatch (wpattern, wstring, wstring + n,
flags & FNM_PERIOD, flags, NULL,
alloca_used);
free (wstring_malloc);
free (wpattern_malloc);
return res;
}
# endif /* mbstate_t and mbsrtowcs or _LIBC. */
return internal_fnmatch (pattern, string, string + strlen (string),
flags & FNM_PERIOD, flags, NULL, 0);
}
# 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
libc_hidden_ver (__fnmatch, fnmatch)
# endif
#endif /* _LIBC or not __GNU_LIBRARY__. */