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