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