139734Sbostic /*
2*66839Sbostic * Copyright (c) 1989, 1993, 1994
361111Sbostic * The Regents of the University of California. All rights reserved.
439734Sbostic *
539734Sbostic * This code is derived from software contributed to Berkeley by
639734Sbostic * Guido van Rossum.
739734Sbostic *
842624Sbostic * %sccs.include.redist.c%
939734Sbostic */
1039734Sbostic
1139734Sbostic #if defined(LIBC_SCCS) && !defined(lint)
12*66839Sbostic static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 04/16/94";
1339734Sbostic #endif /* LIBC_SCCS and not lint */
1439734Sbostic
1539734Sbostic /*
16*66839Sbostic * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
1739734Sbostic * Compares a filename or pathname to a pattern.
1839734Sbostic */
1939734Sbostic
2054534Sbostic #include <fnmatch.h>
2139734Sbostic #include <string.h>
2239734Sbostic
2339734Sbostic #define EOS '\0'
2439734Sbostic
25*66839Sbostic static const char *rangematch __P((const char *, int, int));
2643528Sbostic
27*66839Sbostic int
fnmatch(pattern,string,flags)2839734Sbostic fnmatch(pattern, string, flags)
29*66839Sbostic const char *pattern, *string;
3039734Sbostic int flags;
3139734Sbostic {
32*66839Sbostic const char *stringstart;
33*66839Sbostic char c, test;
3439734Sbostic
35*66839Sbostic for (stringstart = string;;)
3639734Sbostic switch (c = *pattern++) {
3739734Sbostic case EOS:
3854534Sbostic return (*string == EOS ? 0 : FNM_NOMATCH);
3939734Sbostic case '?':
40*66839Sbostic if (*string == EOS)
4154534Sbostic return (FNM_NOMATCH);
42*66839Sbostic if (*string == '/' && (flags & FNM_PATHNAME))
43*66839Sbostic return (FNM_NOMATCH);
44*66839Sbostic if (*string == '.' && (flags & FNM_PERIOD) &&
45*66839Sbostic (string == stringstart ||
46*66839Sbostic ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
47*66839Sbostic return (FNM_NOMATCH);
48*66839Sbostic ++string;
4939734Sbostic break;
5039734Sbostic case '*':
5139734Sbostic c = *pattern;
5254534Sbostic /* Collapse multiple stars. */
5339734Sbostic while (c == '*')
5439734Sbostic c = *++pattern;
5539734Sbostic
56*66839Sbostic if (*string == '.' && (flags & FNM_PERIOD) &&
57*66839Sbostic (string == stringstart ||
58*66839Sbostic ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
59*66839Sbostic return (FNM_NOMATCH);
60*66839Sbostic
6154534Sbostic /* Optimize for pattern with * at end or before /. */
6239734Sbostic if (c == EOS)
6339734Sbostic if (flags & FNM_PATHNAME)
64*66839Sbostic return (strchr(string, '/') == NULL ?
6554534Sbostic 0 : FNM_NOMATCH);
6639734Sbostic else
6754534Sbostic return (0);
6839734Sbostic else if (c == '/' && flags & FNM_PATHNAME) {
69*66839Sbostic if ((string = strchr(string, '/')) == NULL)
7054534Sbostic return (FNM_NOMATCH);
7139734Sbostic break;
7239734Sbostic }
7339734Sbostic
7454534Sbostic /* General case, use recursion. */
7539734Sbostic while ((test = *string) != EOS) {
76*66839Sbostic if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
7754534Sbostic return (0);
7839734Sbostic if (test == '/' && flags & FNM_PATHNAME)
7939734Sbostic break;
8039734Sbostic ++string;
8139734Sbostic }
8254534Sbostic return (FNM_NOMATCH);
8339734Sbostic case '[':
84*66839Sbostic if (*string == EOS)
8554534Sbostic return (FNM_NOMATCH);
86*66839Sbostic if (*string == '/' && flags & FNM_PATHNAME)
8754534Sbostic return (FNM_NOMATCH);
88*66839Sbostic if ((pattern =
89*66839Sbostic rangematch(pattern, *string, flags)) == NULL)
90*66839Sbostic return (FNM_NOMATCH);
91*66839Sbostic ++string;
9239734Sbostic break;
9339734Sbostic case '\\':
9454534Sbostic if (!(flags & FNM_NOESCAPE)) {
9539734Sbostic if ((c = *pattern++) == EOS) {
9639734Sbostic c = '\\';
9739734Sbostic --pattern;
9839734Sbostic }
9939734Sbostic }
10039734Sbostic /* FALLTHROUGH */
10139734Sbostic default:
10239734Sbostic if (c != *string++)
10354534Sbostic return (FNM_NOMATCH);
10439734Sbostic break;
10539734Sbostic }
10654534Sbostic /* NOTREACHED */
10739734Sbostic }
10854534Sbostic
10954535Sbostic static const char *
rangematch(pattern,test,flags)110*66839Sbostic rangematch(pattern, test, flags)
111*66839Sbostic const char *pattern;
112*66839Sbostic int test, flags;
11354534Sbostic {
11454534Sbostic int negate, ok;
115*66839Sbostic char c, c2;
11654534Sbostic
11754534Sbostic /*
118*66839Sbostic * A bracket expression starting with an unquoted circumflex
119*66839Sbostic * character produces unspecified results (IEEE 1003.2-1992,
120*66839Sbostic * 3.13.2). This implementation treats it like '!', for
121*66839Sbostic * consistency with the regular expression syntax.
122*66839Sbostic * J.T. Conklin (conklin@ngai.kaleida.com)
12354534Sbostic */
124*66839Sbostic if (negate = (*pattern == '!' || *pattern == '^'))
125*66839Sbostic ++pattern;
126*66839Sbostic
12754534Sbostic for (ok = 0; (c = *pattern++) != ']';) {
128*66839Sbostic if (c == '\\' && !(flags & FNM_NOESCAPE))
129*66839Sbostic c = *pattern++;
13054534Sbostic if (c == EOS)
131*66839Sbostic return (NULL);
132*66839Sbostic if (*pattern == '-'
133*66839Sbostic && (c2 = *(pattern+1)) != EOS && c2 != ']') {
134*66839Sbostic pattern += 2;
135*66839Sbostic if (c2 == '\\' && !(flags & FNM_NOESCAPE))
136*66839Sbostic c2 = *pattern++;
137*66839Sbostic if (c2 == EOS)
138*66839Sbostic return (NULL);
13954534Sbostic if (c <= test && test <= c2)
14054534Sbostic ok = 1;
141*66839Sbostic } else if (c == test)
14254534Sbostic ok = 1;
14354534Sbostic }
14454534Sbostic return (ok == negate ? NULL : pattern);
14554534Sbostic }
146