Formerly ../posix/fnmatch.c.~14~
[kopensolaris-gnu/glibc.git] / posix / fnmatch.c
1 /* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
2
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Library General Public License as
5 published by the Free Software Foundation; either version 2 of the
6 License, or (at your option) any later version.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public
14 License along with this library; see the file COPYING.LIB.  If
15 not, write to the, 1992 Free Software Foundation, Inc., 675 Mass Ave,
16 Cambridge, MA 02139, USA.  */
17
18 /* @ */
19 #include <ansidecl.h>
20 /* @ */
21 #include <errno.h>
22 #include <fnmatch.h>
23
24 #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
25 extern int errno;
26 #endif
27
28 /* Match STRING against the filename pattern PATTERN, returning zero if
29    it matches, nonzero if not.  */
30 int
31 fnmatch (pattern, string, flags)
32      const char *pattern;
33      const char *string;
34      int flags;
35 {
36   register const char *p = pattern, *n = string;
37   register char c;
38
39   if ((flags & ~__FNM_FLAGS) != 0)
40     {
41       errno = EINVAL;
42       return -1;
43     }
44
45   while ((c = *p++) != '\0')
46     {
47       switch (c)
48         {
49         case '?':
50           if (*n == '\0')
51             return FNM_NOMATCH;
52           else if ((flags & FNM_PATHNAME) && *n == '/')
53             return FNM_NOMATCH;
54           else if ((flags & FNM_PERIOD) && *n == '.' &&
55                    (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
56             return FNM_NOMATCH;
57           break;
58
59         case '\\':
60           if (!(flags & FNM_NOESCAPE))
61             c = *p++;
62           if (*n != c)
63             return FNM_NOMATCH;
64           break;
65
66         case '*':
67           if ((flags & FNM_PERIOD) && *n == '.' &&
68               (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
69             return FNM_NOMATCH;
70
71           for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
72             if (((flags & FNM_PATHNAME) && *n == '/') ||
73                 (c == '?' && *n == '\0'))
74               return FNM_NOMATCH;
75
76           if (c == '\0')
77             return 0;
78
79           {
80             char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
81             for (--p; *n != '\0'; ++n)
82               if ((c == '[' || *n == c1) &&
83                   fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
84                 return 0;
85             return FNM_NOMATCH;
86           }
87
88         case '[':
89           {
90             /* Nonzero if the sense of the character class is 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             not = (*p == '!' || *p == '^');
101             if (not)
102               ++p;
103
104             c = *p++;
105             for (;;)
106               {
107                 register char cstart = c, cend = c;
108
109                 if (!(flags & FNM_NOESCAPE) && c == '\\')
110                   cstart = cend = *p++;
111
112                 if (c == '\0')
113                   /* [ (unterminated) loses.  */
114                   return FNM_NOMATCH;
115
116                 c = *p++;
117
118                 if ((flags & FNM_PATHNAME) && c == '/')
119                   /* [/] can never match.  */
120                   return FNM_NOMATCH;
121
122                 if (c == '-' && *p != ']')
123                   {
124                     cend = *p++;
125                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
126                       cend = *p++;
127                     if (cend == '\0')
128                       return FNM_NOMATCH;
129                     c = *p++;
130                   }
131
132                 if (*n >= cstart && *n <= cend)
133                   goto matched;
134
135                 if (c == ']')
136                   break;
137               }
138             if (!not)
139               return FNM_NOMATCH;
140             break;
141
142           matched:;
143             /* Skip the rest of the [...] that already matched.  */
144             while (c != ']')
145               {
146                 if (c == '\0')
147                   /* [... (unterminated) loses.  */
148                   return FNM_NOMATCH;
149
150                 c = *p++;
151                 if (!(flags & FNM_NOESCAPE) && c == '\\')
152                   /* 1003.2d11 is unclear if this is right.  %%% */
153                   ++p;
154               }
155             if (not)
156               return FNM_NOMATCH;
157           }
158           break;
159
160         default:
161           if (c != *n)
162             return FNM_NOMATCH;
163         }
164
165       ++n;
166     }
167
168   if (*n == '\0')
169     return 0;
170
171   return FNM_NOMATCH;
172 }