*** empty log message ***
[coreutils.git] / lib / fnmatch.c
blobf772ecc970884517d5ba06d8ba94b42e8744e48b
1 /* Copyright (C) 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
3 NOTE: The canonical source of this file is maintained with the GNU C
4 Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #if HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include <errno.h>
25 #include <fnmatch.h>
26 #include <ctype.h>
28 #if defined (STDC_HEADERS) || !defined (isascii)
29 # define ISASCII(c) 1
30 #else
31 # define ISASCII(c) isascii(c)
32 #endif
34 #define ISUPPER(c) (ISASCII (c) && isupper (c))
36 # ifndef errno
37 extern int errno;
38 # endif
40 /* Match STRING against the filename pattern PATTERN, returning zero if
41 it matches, nonzero if not. */
42 int
43 fnmatch (pattern, string, flags)
44 const char *pattern;
45 const char *string;
46 int flags;
48 register const char *p = pattern, *n = string;
49 register char c;
51 /* Note that this evaluates C many times. */
52 # define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
54 while ((c = *p++) != '\0')
56 c = FOLD (c);
58 switch (c)
60 case '?':
61 if (*n == '\0')
62 return FNM_NOMATCH;
63 else if ((flags & FNM_FILE_NAME) && *n == '/')
64 return FNM_NOMATCH;
65 else if ((flags & FNM_PERIOD) && *n == '.' &&
66 (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
67 return FNM_NOMATCH;
68 break;
70 case '\\':
71 if (!(flags & FNM_NOESCAPE))
73 c = *p++;
74 c = FOLD (c);
76 if (FOLD (*n) != c)
77 return FNM_NOMATCH;
78 break;
80 case '*':
81 if ((flags & FNM_PERIOD) && *n == '.' &&
82 (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
83 return FNM_NOMATCH;
85 for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
86 if (((flags & FNM_FILE_NAME) && *n == '/') ||
87 (c == '?' && *n == '\0'))
88 return FNM_NOMATCH;
90 if (c == '\0')
91 return 0;
94 char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
95 c1 = FOLD (c1);
96 for (--p; *n != '\0'; ++n)
97 if ((c == '[' || FOLD (*n) == c1) &&
98 fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
99 return 0;
100 return FNM_NOMATCH;
103 case '[':
105 /* Nonzero if the sense of the character class is inverted. */
106 register int not;
108 if (*n == '\0')
109 return FNM_NOMATCH;
111 if ((flags & FNM_PERIOD) && *n == '.' &&
112 (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
113 return FNM_NOMATCH;
115 not = (*p == '!' || *p == '^');
116 if (not)
117 ++p;
119 c = *p++;
120 for (;;)
122 register char cstart = c, cend = c;
124 if (!(flags & FNM_NOESCAPE) && c == '\\')
125 cstart = cend = *p++;
127 cstart = cend = FOLD (cstart);
129 if (c == '\0')
130 /* [ (unterminated) loses. */
131 return FNM_NOMATCH;
133 c = *p++;
134 c = FOLD (c);
136 if ((flags & FNM_FILE_NAME) && c == '/')
137 /* [/] can never match. */
138 return FNM_NOMATCH;
140 if (c == '-' && *p != ']')
142 cend = *p++;
143 if (!(flags & FNM_NOESCAPE) && cend == '\\')
144 cend = *p++;
145 if (cend == '\0')
146 return FNM_NOMATCH;
147 cend = FOLD (cend);
149 c = *p++;
152 if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
153 goto matched;
155 if (c == ']')
156 break;
158 if (!not)
159 return FNM_NOMATCH;
160 break;
162 matched:;
163 /* Skip the rest of the [...] that already matched. */
164 while (c != ']')
166 if (c == '\0')
167 /* [... (unterminated) loses. */
168 return FNM_NOMATCH;
170 c = *p++;
171 if (!(flags & FNM_NOESCAPE) && c == '\\')
172 /* XXX 1003.2d11 is unclear if this is right. */
173 ++p;
175 if (not)
176 return FNM_NOMATCH;
178 break;
180 default:
181 if (c != FOLD (*n))
182 return FNM_NOMATCH;
185 ++n;
188 if (*n == '\0')
189 return 0;
191 if ((flags & FNM_LEADING_DIR) && *n == '/')
192 /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
193 return 0;
195 return FNM_NOMATCH;
197 # undef FOLD