Formerly ../posix/fnmatch.c.~13~
[kopensolaris-gnu/glibc.git] / posix / fnmatch.c
1 /* Copyright (C) 1991 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 /* IGNORE(@ */
20 #include <ansidecl.h>
21 /* @) */
22 #include <errno.h>
23 #include <fnmatch.h>
24
25 #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
26 extern int errno;
27 #endif
28
29 /* Match STRING against the filename pattern PATTERN, returning zero if
30    it matches, nonzero if not.  */
31 int
32 DEFUN(fnmatch, (pattern, string, flags),
33       CONST char *pattern AND CONST char *string AND 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 inverted.  */
90             register int not;
91             
92             if (*n == '\0')
93               return FNM_NOMATCH;
94             
95             if ((flags & FNM_PERIOD) && *n == '.' &&
96                 (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
97               return FNM_NOMATCH;
98             
99             not = (*p == '!' || *p == '^');
100             if (not)
101               ++p;
102             
103             c = *p++;
104             for (;;)
105               {
106                 register char cstart = c, cend = c;
107                 
108                 if (!(flags & FNM_NOESCAPE) && c == '\\')
109                   cstart = cend = *p++;
110                 
111                 if (c == '\0')
112                   /* [ (unterminated) loses.  */
113                   return FNM_NOMATCH;
114                 
115                 c = *p++;
116                 
117                 if ((flags & FNM_PATHNAME) && c == '/')
118                   /* [/] can never match.  */
119                   return FNM_NOMATCH;
120                 
121                 if (c == '-' && *p != ']')
122                   {
123                     cend = *p++;
124                     if (!(flags & FNM_NOESCAPE) && cend == '\\')
125                       cend = *p++;
126                     if (cend == '\0')
127                       return FNM_NOMATCH;
128                     c = *p++;
129                   }
130                 
131                 if (*n >= cstart && *n <= cend)
132                   goto matched;
133                 
134                 if (c == ']')
135                   break;
136               }
137             if (!not)
138               return FNM_NOMATCH;
139             break;
140             
141           matched:;
142             /* Skip the rest of the [...] that already matched.  */
143             while (c != ']')
144               {
145                 if (c == '\0')
146                   /* [... (unterminated) loses.  */
147                   return FNM_NOMATCH;
148                 
149                 c = *p++;
150                 if (!(flags & FNM_NOESCAPE) && c == '\\')
151                   /* 1003.2d11 is unclear if this is right.  %%% */
152                   ++p;
153               }
154             if (not)
155               return FNM_NOMATCH;
156           }
157           break;
158           
159         default:
160           if (c != *n)
161             return FNM_NOMATCH;
162         }
163       
164       ++n;
165     }
166
167   if (*n == '\0')
168     return 0;
169
170   return FNM_NOMATCH;
171 }