]> sjero.net Git - wget/blob - src/fnmatch.c
[svn] Initial revision
[wget] / src / fnmatch.c
1 /* Pattern matching (globbing).
2    Copyright (C) 1991, 1996, 1997 Free Software Foundation, Inc.
3
4 This file is part of Wget.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
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.
15
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
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /* NOTE: Some Un*xes have their own fnmatch() -- yet, they are
21    reportedly unreliable and buggy.  Thus I chose never to use it;
22    this version (from GNU Bash) is used unconditionally.  */
23
24 #include <config.h>
25
26 #include <errno.h>
27 #include "wget.h"
28 #include "fnmatch.h"
29
30 /* Match STRING against the filename pattern PATTERN, returning zero
31    if it matches, FNM_NOMATCH if not.  */
32 int
33 fnmatch (const char *pattern, const char *string, int flags)
34 {
35   register const char *p = pattern, *n = string;
36   register char c;
37
38   if ((flags & ~__FNM_FLAGS) != 0)
39     {
40       errno = EINVAL;
41       return (-1);
42     }
43
44   while ((c = *p++) != '\0')
45     {
46       switch (c)
47         {
48         case '?':
49           if (*n == '\0')
50             return (FNM_NOMATCH);
51           else if ((flags & FNM_PATHNAME) && *n == '/')
52             return (FNM_NOMATCH);
53           else if ((flags & FNM_PERIOD) && *n == '.' &&
54                    (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
55             return (FNM_NOMATCH);
56           break;
57
58         case '\\':
59           if (!(flags & FNM_NOESCAPE))
60             c = *p++;
61           if (*n != c)
62             return (FNM_NOMATCH);
63           break;
64
65         case '*':
66           if ((flags & FNM_PERIOD) && *n == '.' &&
67               (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
68             return (FNM_NOMATCH);
69
70           for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
71             if (((flags & FNM_PATHNAME) && *n == '/') ||
72                 (c == '?' && *n == '\0'))
73               return (FNM_NOMATCH);
74
75           if (c == '\0')
76             return (0);
77
78           {
79             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
80             for (--p; *n != '\0'; ++n)
81               if ((c == '[' || *n == c1) &&
82                   fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
83                 return (0);
84             return (FNM_NOMATCH);
85           }
86
87         case '[':
88           {
89             /* Nonzero if the sense of the character class is
90                inverted.  */
91             register int not;
92
93             if (*n == '\0')
94               return (FNM_NOMATCH);
95
96             if ((flags & FNM_PERIOD) && *n == '.' &&
97                 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
98               return (FNM_NOMATCH);
99
100             /* Make sure there is a closing `]'.  If there isn't,
101                the `[' is just a character to be matched.  */
102             {
103               register const char *np;
104
105               for (np = p; np && *np && *np != ']'; np++);
106
107               if (np && !*np)
108                 {
109                   if (*n != '[')
110                     return (FNM_NOMATCH);
111                   goto next_char;
112                 }
113             }
114
115             not = (*p == '!' || *p == '^');
116             if (not)
117               ++p;
118
119             c = *p++;
120             while (1)
121               {
122                 register char cstart = c, cend = c;
123
124                 if (!(flags & FNM_NOESCAPE) && c == '\\')
125                   cstart = cend = *p++;
126
127                 if (c == '\0')
128                   /* [ (unterminated) loses.  */
129                   return (FNM_NOMATCH);
130
131                 c = *p++;
132
133                 if ((flags & FNM_PATHNAME) && c == '/')
134                   /* [/] can never match.  */
135                   return (FNM_NOMATCH);
136
137                 if (c == '-' && *p != ']')
138                   {
139                     cend = *p++;
140                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
141                       cend = *p++;
142                     if (cend == '\0')
143                       return (FNM_NOMATCH);
144                     c = *p++;
145                   }
146
147                 if (*n >= cstart && *n <= cend)
148                   goto matched;
149
150                 if (c == ']')
151                   break;
152               }
153             if (!not)
154               return (FNM_NOMATCH);
155
156           next_char:
157             break;
158
159           matched:
160             /* Skip the rest of the [...] that already matched.  */
161             while (c != ']')
162               {
163                 if (c == '\0')
164                   /* [... (unterminated) loses.  */
165                   return (FNM_NOMATCH);
166
167                 c = *p++;
168                 if (!(flags & FNM_NOESCAPE) && c == '\\')
169                   /* 1003.2d11 is unclear if this is right.  %%% */
170                   ++p;
171               }
172             if (not)
173               return (FNM_NOMATCH);
174           }
175           break;
176
177         default:
178           if (c != *n)
179             return (FNM_NOMATCH);
180         }
181
182       ++n;
183     }
184
185   if (*n == '\0')
186     return (0);
187
188   return (FNM_NOMATCH);
189 }
190
191 /* Return non-zero if S contains globbing wildcards (`*', `?', `[' or
192    `]').  */
193 int
194 has_wildcards_p (const char *s)
195 {
196   for (; *s; s++)
197     if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
198       return 1;
199   return 0;
200 }