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