compat / fnmatch / fnmatch.con commit Merge branch 'jc/format-patch-reroll' (98294e9)
   1/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
   2   This file is part of the GNU C Library.
   3
   4   This library is free software; you can redistribute it and/or
   5   modify it under the terms of the GNU Library General Public License as
   6   published by the Free Software Foundation; either version 2 of the
   7   License, or (at your option) any later version.
   8
   9   This library is distributed in the hope that it will be useful,
  10   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12   Library General Public License for more details.
  13
  14   You should have received a copy of the GNU Library General Public
  15   License along with this library; see the file COPYING.LIB.  If not,
  16   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17   Boston, MA 02111-1307, USA.  */
  18
  19#if HAVE_CONFIG_H
  20# include <config.h>
  21#endif
  22
  23/* Enable GNU extensions in fnmatch.h.  */
  24#ifndef _GNU_SOURCE
  25# define _GNU_SOURCE    1
  26#endif
  27
  28#include <errno.h>
  29#include <fnmatch.h>
  30#include <ctype.h>
  31
  32#if HAVE_STRING_H || defined _LIBC
  33# include <string.h>
  34#else
  35# include <strings.h>
  36#endif
  37
  38#if defined STDC_HEADERS || defined _LIBC
  39# include <stdlib.h>
  40#endif
  41
  42/* For platforms which support the ISO C amendment 1 functionality we
  43   support user defined character classes.  */
  44#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
  45/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
  46# include <wchar.h>
  47# include <wctype.h>
  48#endif
  49
  50/* Comment out all this code if we are using the GNU C Library, and are not
  51   actually compiling the library itself.  This code is part of the GNU C
  52   Library, but also included in many other GNU distributions.  Compiling
  53   and linking in this code is a waste when using the GNU C library
  54   (especially if it is a shared library).  Rather than having every GNU
  55   program understand `configure --with-gnu-libc' and omit the object files,
  56   it is simpler to just do this in the source for each such file.  */
  57
  58#if defined NO_FNMATCH || defined NO_FNMATCH_CASEFOLD || \
  59    defined _LIBC || !defined __GNU_LIBRARY__
  60
  61
  62# if defined STDC_HEADERS || !defined isascii
  63#  define ISASCII(c) 1
  64# else
  65#  define ISASCII(c) isascii(c)
  66# endif
  67
  68# ifdef isblank
  69#  define ISBLANK(c) (ISASCII (c) && isblank (c))
  70# else
  71#  define ISBLANK(c) ((c) == ' ' || (c) == '\t')
  72# endif
  73# ifdef isgraph
  74#  define ISGRAPH(c) (ISASCII (c) && isgraph (c))
  75# else
  76#  define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
  77# endif
  78
  79# define ISPRINT(c) (ISASCII (c) && isprint (c))
  80# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
  81# define ISALNUM(c) (ISASCII (c) && isalnum (c))
  82# define ISALPHA(c) (ISASCII (c) && isalpha (c))
  83# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
  84# define ISLOWER(c) (ISASCII (c) && islower (c))
  85# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
  86# define ISSPACE(c) (ISASCII (c) && isspace (c))
  87# define ISUPPER(c) (ISASCII (c) && isupper (c))
  88# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
  89
  90# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
  91
  92# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
  93/* The GNU C library provides support for user-defined character classes
  94   and the functions from ISO C amendment 1.  */
  95#  ifdef CHARCLASS_NAME_MAX
  96#   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
  97#  else
  98/* This shouldn't happen but some implementation might still have this
  99   problem.  Use a reasonable default value.  */
 100#   define CHAR_CLASS_MAX_LENGTH 256
 101#  endif
 102
 103#  ifdef _LIBC
 104#   define IS_CHAR_CLASS(string) __wctype (string)
 105#  else
 106#   define IS_CHAR_CLASS(string) wctype (string)
 107#  endif
 108# else
 109#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
 110
 111#  define IS_CHAR_CLASS(string)                                               \
 112   (STREQ (string, "alpha") || STREQ (string, "upper")                        \
 113    || STREQ (string, "lower") || STREQ (string, "digit")                     \
 114    || STREQ (string, "alnum") || STREQ (string, "xdigit")                    \
 115    || STREQ (string, "space") || STREQ (string, "print")                     \
 116    || STREQ (string, "punct") || STREQ (string, "graph")                     \
 117    || STREQ (string, "cntrl") || STREQ (string, "blank"))
 118# endif
 119
 120/* Avoid depending on library functions or files
 121   whose names are inconsistent.  */
 122
 123# if !defined _LIBC && !defined getenv
 124extern char *getenv ();
 125# endif
 126
 127# ifndef errno
 128extern int errno;
 129# endif
 130
 131# ifndef NULL
 132#  define NULL 0
 133# endif
 134
 135/* This function doesn't exist on most systems.  */
 136
 137# if !defined HAVE___STRCHRNUL && !defined _LIBC
 138static char *
 139__strchrnul (const char *s, int c)
 140
 141
 142{
 143  char *result = strchr (s, c);
 144  if (result == NULL)
 145    result = strchr (s, '\0');
 146  return result;
 147}
 148# endif
 149
 150# ifndef internal_function
 151/* Inside GNU libc we mark some function in a special way.  In other
 152   environments simply ignore the marking.  */
 153#  define internal_function
 154# endif
 155
 156/* Match STRING against the filename pattern PATTERN, returning zero if
 157   it matches, nonzero if not.  */
 158static int internal_fnmatch __P ((const char *pattern, const char *string,
 159                                  int no_leading_period, int flags))
 160     internal_function;
 161static int
 162internal_function
 163internal_fnmatch (const char *pattern, const char *string, int no_leading_period, int flags)
 164
 165
 166
 167
 168{
 169  register const char *p = pattern, *n = string;
 170  register unsigned char c;
 171
 172/* Note that this evaluates C many times.  */
 173# ifdef _LIBC
 174#  define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
 175# else
 176#  define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
 177# endif
 178
 179  while ((c = *p++) != '\0')
 180    {
 181      c = FOLD (c);
 182
 183      switch (c)
 184        {
 185        case '?':
 186          if (*n == '\0')
 187            return FNM_NOMATCH;
 188          else if (*n == '/' && (flags & FNM_FILE_NAME))
 189            return FNM_NOMATCH;
 190          else if (*n == '.' && no_leading_period
 191                   && (n == string
 192                       || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
 193            return FNM_NOMATCH;
 194          break;
 195
 196        case '\\':
 197          if (!(flags & FNM_NOESCAPE))
 198            {
 199              c = *p++;
 200              if (c == '\0')
 201                /* Trailing \ loses.  */
 202                return FNM_NOMATCH;
 203              c = FOLD (c);
 204            }
 205          if (FOLD ((unsigned char) *n) != c)
 206            return FNM_NOMATCH;
 207          break;
 208
 209        case '*':
 210          if (*n == '.' && no_leading_period
 211              && (n == string
 212                  || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
 213            return FNM_NOMATCH;
 214
 215          for (c = *p++; c == '?' || c == '*'; c = *p++)
 216            {
 217              if (*n == '/' && (flags & FNM_FILE_NAME))
 218                /* A slash does not match a wildcard under FNM_FILE_NAME.  */
 219                return FNM_NOMATCH;
 220              else if (c == '?')
 221                {
 222                  /* A ? needs to match one character.  */
 223                  if (*n == '\0')
 224                    /* There isn't another character; no match.  */
 225                    return FNM_NOMATCH;
 226                  else
 227                    /* One character of the string is consumed in matching
 228                       this ? wildcard, so *??? won't match if there are
 229                       less than three characters.  */
 230                    ++n;
 231                }
 232            }
 233
 234          if (c == '\0')
 235            /* The wildcard(s) is/are the last element of the pattern.
 236               If the name is a file name and contains another slash
 237               this does mean it cannot match.  */
 238            return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
 239                    ? FNM_NOMATCH : 0);
 240          else
 241            {
 242              const char *endp;
 243
 244              endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
 245
 246              if (c == '[')
 247                {
 248                  int flags2 = ((flags & FNM_FILE_NAME)
 249                                ? flags : (flags & ~FNM_PERIOD));
 250
 251                  for (--p; n < endp; ++n)
 252                    if (internal_fnmatch (p, n,
 253                                          (no_leading_period
 254                                           && (n == string
 255                                               || (n[-1] == '/'
 256                                                   && (flags
 257                                                       & FNM_FILE_NAME)))),
 258                                          flags2)
 259                        == 0)
 260                      return 0;
 261                }
 262              else if (c == '/' && (flags & FNM_FILE_NAME))
 263                {
 264                  while (*n != '\0' && *n != '/')
 265                    ++n;
 266                  if (*n == '/'
 267                      && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
 268                                            flags) == 0))
 269                    return 0;
 270                }
 271              else
 272                {
 273                  int flags2 = ((flags & FNM_FILE_NAME)
 274                                ? flags : (flags & ~FNM_PERIOD));
 275
 276                  if (c == '\\' && !(flags & FNM_NOESCAPE))
 277                    c = *p;
 278                  c = FOLD (c);
 279                  for (--p; n < endp; ++n)
 280                    if (FOLD ((unsigned char) *n) == c
 281                        && (internal_fnmatch (p, n,
 282                                              (no_leading_period
 283                                               && (n == string
 284                                                   || (n[-1] == '/'
 285                                                       && (flags
 286                                                           & FNM_FILE_NAME)))),
 287                                              flags2) == 0))
 288                      return 0;
 289                }
 290            }
 291
 292          /* If we come here no match is possible with the wildcard.  */
 293          return FNM_NOMATCH;
 294
 295        case '[':
 296          {
 297            /* Nonzero if the sense of the character class is inverted.  */
 298            static int posixly_correct;
 299            register int not;
 300            char cold;
 301
 302            if (posixly_correct == 0)
 303              posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
 304
 305            if (*n == '\0')
 306              return FNM_NOMATCH;
 307
 308            if (*n == '.' && no_leading_period && (n == string
 309                                                   || (n[-1] == '/'
 310                                                       && (flags
 311                                                           & FNM_FILE_NAME))))
 312              return FNM_NOMATCH;
 313
 314            if (*n == '/' && (flags & FNM_FILE_NAME))
 315              /* `/' cannot be matched.  */
 316              return FNM_NOMATCH;
 317
 318            not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
 319            if (not)
 320              ++p;
 321
 322            c = *p++;
 323            for (;;)
 324              {
 325                unsigned char fn = FOLD ((unsigned char) *n);
 326
 327                if (!(flags & FNM_NOESCAPE) && c == '\\')
 328                  {
 329                    if (*p == '\0')
 330                      return FNM_NOMATCH;
 331                    c = FOLD ((unsigned char) *p);
 332                    ++p;
 333
 334                    if (c == fn)
 335                      goto matched;
 336                  }
 337                else if (c == '[' && *p == ':')
 338                  {
 339                    /* Leave room for the null.  */
 340                    char str[CHAR_CLASS_MAX_LENGTH + 1];
 341                    size_t c1 = 0;
 342# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
 343                    wctype_t wt;
 344# endif
 345                    const char *startp = p;
 346
 347                    for (;;)
 348                      {
 349                        if (c1 > CHAR_CLASS_MAX_LENGTH)
 350                          /* The name is too long and therefore the pattern
 351                             is ill-formed.  */
 352                          return FNM_NOMATCH;
 353
 354                        c = *++p;
 355                        if (c == ':' && p[1] == ']')
 356                          {
 357                            p += 2;
 358                            break;
 359                          }
 360                        if (c < 'a' || c >= 'z')
 361                          {
 362                            /* This cannot possibly be a character class name.
 363                               Match it as a normal range.  */
 364                            p = startp;
 365                            c = '[';
 366                            goto normal_bracket;
 367                          }
 368                        str[c1++] = c;
 369                      }
 370                    str[c1] = '\0';
 371
 372# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
 373                    wt = IS_CHAR_CLASS (str);
 374                    if (wt == 0)
 375                      /* Invalid character class name.  */
 376                      return FNM_NOMATCH;
 377
 378                    if (__iswctype (__btowc ((unsigned char) *n), wt))
 379                      goto matched;
 380# else
 381                    if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
 382                        || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
 383                        || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
 384                        || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
 385                        || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
 386                        || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
 387                        || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
 388                        || (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
 389                        || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
 390                        || (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
 391                        || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
 392                        || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
 393                      goto matched;
 394# endif
 395                  }
 396                else if (c == '\0')
 397                  /* [ (unterminated) loses.  */
 398                  return FNM_NOMATCH;
 399                else
 400                  {
 401                  normal_bracket:
 402                    if (FOLD (c) == fn)
 403                      goto matched;
 404
 405                    cold = c;
 406                    c = *p++;
 407
 408                    if (c == '-' && *p != ']')
 409                      {
 410                        /* It is a range.  */
 411                        unsigned char cend = *p++;
 412                        if (!(flags & FNM_NOESCAPE) && cend == '\\')
 413                          cend = *p++;
 414                        if (cend == '\0')
 415                          return FNM_NOMATCH;
 416
 417                        if (cold <= fn && fn <= FOLD (cend))
 418                          goto matched;
 419
 420                        c = *p++;
 421                      }
 422                  }
 423
 424                if (c == ']')
 425                  break;
 426              }
 427
 428            if (!not)
 429              return FNM_NOMATCH;
 430            break;
 431
 432          matched:
 433            /* Skip the rest of the [...] that already matched.  */
 434            while (c != ']')
 435              {
 436                if (c == '\0')
 437                  /* [... (unterminated) loses.  */
 438                  return FNM_NOMATCH;
 439
 440                c = *p++;
 441                if (!(flags & FNM_NOESCAPE) && c == '\\')
 442                  {
 443                    if (*p == '\0')
 444                      return FNM_NOMATCH;
 445                    /* XXX 1003.2d11 is unclear if this is right.  */
 446                    ++p;
 447                  }
 448                else if (c == '[' && *p == ':')
 449                  {
 450                    do
 451                      if (*++p == '\0')
 452                        return FNM_NOMATCH;
 453                    while (*p != ':' || p[1] == ']');
 454                    p += 2;
 455                    c = *p;
 456                  }
 457              }
 458            if (not)
 459              return FNM_NOMATCH;
 460          }
 461          break;
 462
 463        default:
 464          if (c != FOLD ((unsigned char) *n))
 465            return FNM_NOMATCH;
 466        }
 467
 468      ++n;
 469    }
 470
 471  if (*n == '\0')
 472    return 0;
 473
 474  if ((flags & FNM_LEADING_DIR) && *n == '/')
 475    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
 476    return 0;
 477
 478  return FNM_NOMATCH;
 479
 480# undef FOLD
 481}
 482
 483
 484int
 485fnmatch (const char *pattern, const char *string, int flags)
 486
 487
 488
 489{
 490  return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
 491}
 492
 493#endif  /* _LIBC or not __GNU_LIBRARY__.  */