]> sjero.net Git - wget/blob - src/fnmatch.c
[svn] Add a fresher getopt.c.
[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 #ifdef HAVE_STRING_H
39 # include <string.h>
40 #else
41 # include <strings.h>
42 #endif /* HAVE_STRING_H */
43 #include "fnmatch.h"
44
45 /* Match STRING against the filename pattern PATTERN, returning zero
46    if it matches, FNM_NOMATCH if not.  */
47 int
48 fnmatch (const char *pattern, const char *string, int flags)
49 {
50   register const char *p = pattern, *n = string;
51   register char c;
52
53   if ((flags & ~__FNM_FLAGS) != 0)
54     {
55       errno = EINVAL;
56       return (-1);
57     }
58
59   while ((c = *p++) != '\0')
60     {
61       switch (c)
62         {
63         case '?':
64           if (*n == '\0')
65             return (FNM_NOMATCH);
66           else if ((flags & FNM_PATHNAME) && *n == '/')
67             return (FNM_NOMATCH);
68           else if ((flags & FNM_PERIOD) && *n == '.' &&
69                    (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
70             return (FNM_NOMATCH);
71           break;
72
73         case '\\':
74           if (!(flags & FNM_NOESCAPE))
75             c = *p++;
76           if (*n != c)
77             return (FNM_NOMATCH);
78           break;
79
80         case '*':
81           if ((flags & FNM_PERIOD) && *n == '.' &&
82               (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
83             return (FNM_NOMATCH);
84
85           for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
86             if (((flags & FNM_PATHNAME) && *n == '/') ||
87                 (c == '?' && *n == '\0'))
88               return (FNM_NOMATCH);
89
90           if (c == '\0')
91             return (0);
92
93           {
94             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
95             for (--p; *n != '\0'; ++n)
96               if ((c == '[' || *n == c1) &&
97                   fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
98                 return (0);
99             return (FNM_NOMATCH);
100           }
101
102         case '[':
103           {
104             /* Nonzero if the sense of the character class is
105                inverted.  */
106             register int not;
107
108             if (*n == '\0')
109               return (FNM_NOMATCH);
110
111             if ((flags & FNM_PERIOD) && *n == '.' &&
112                 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
113               return (FNM_NOMATCH);
114
115             /* Make sure there is a closing `]'.  If there isn't,
116                the `[' is just a character to be matched.  */
117             {
118               register const char *np;
119
120               for (np = p; np && *np && *np != ']'; np++);
121
122               if (np && !*np)
123                 {
124                   if (*n != '[')
125                     return (FNM_NOMATCH);
126                   goto next_char;
127                 }
128             }
129
130             not = (*p == '!' || *p == '^');
131             if (not)
132               ++p;
133
134             c = *p++;
135             while (1)
136               {
137                 register char cstart = c, cend = c;
138
139                 if (!(flags & FNM_NOESCAPE) && c == '\\')
140                   cstart = cend = *p++;
141
142                 if (c == '\0')
143                   /* [ (unterminated) loses.  */
144                   return (FNM_NOMATCH);
145
146                 c = *p++;
147
148                 if ((flags & FNM_PATHNAME) && c == '/')
149                   /* [/] can never match.  */
150                   return (FNM_NOMATCH);
151
152                 if (c == '-' && *p != ']')
153                   {
154                     cend = *p++;
155                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
156                       cend = *p++;
157                     if (cend == '\0')
158                       return (FNM_NOMATCH);
159                     c = *p++;
160                   }
161
162                 if (*n >= cstart && *n <= cend)
163                   goto matched;
164
165                 if (c == ']')
166                   break;
167               }
168             if (!not)
169               return (FNM_NOMATCH);
170
171           next_char:
172             break;
173
174           matched:
175             /* Skip the rest of the [...] that already matched.  */
176             while (c != ']')
177               {
178                 if (c == '\0')
179                   /* [... (unterminated) loses.  */
180                   return (FNM_NOMATCH);
181
182                 c = *p++;
183                 if (!(flags & FNM_NOESCAPE) && c == '\\')
184                   /* 1003.2d11 is unclear if this is right.  %%% */
185                   ++p;
186               }
187             if (not)
188               return (FNM_NOMATCH);
189           }
190           break;
191
192         default:
193           if (c != *n)
194             return (FNM_NOMATCH);
195         }
196
197       ++n;
198     }
199
200   if (*n == '\0')
201     return (0);
202
203   return (FNM_NOMATCH);
204 }
205
206 /* Return non-zero if S has a leading '/'  or contains '../' */
207 int
208 has_insecure_name_p (const char *s)
209 {
210   if (*s == '/')
211     return 1;
212
213   if (strstr(s, "../") != 0)
214     return 1;
215
216   return 0;
217 }
218
219 /* Return non-zero if S contains globbing wildcards (`*', `?', `[' or
220    `]').  */
221 int
222 has_wildcards_p (const char *s)
223 {
224   for (; *s; s++)
225     if (*s == '*' || *s == '?' || *s == '[' || *s == ']')
226       return 1;
227   return 0;
228 }