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 #include <errno.h>
20 #include "fnmatch.h"
21 
22 #if !defined (__GNU_LIBRARY__) && !defined (STDC_HEADERS)
23 #  if !defined (errno)
24 extern int errno;
25 #  endif /* !errno */
26 #endif
27 
28 /* Match STRING against the filename pattern PATTERN, returning zero if
29    it matches, FNM_NOMATCH if not.  */
30 int
fnmatch(pattern,string,flags)31 fnmatch (pattern, string, flags)
32      char *pattern;
33      char *string;
34      int flags;
35 {
36   register 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 	    /* Make sure there is a closing `]'.  If there isn't, the `['
101 	       is just a character to be matched. */
102 	    {
103 	      register 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 	    for (;;)
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