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>