Annotation of gforth/engine/fnmatch.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>