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