1#include "includes.h"
2#ifndef HAVE_FNMATCH
3
4/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
5
6NOTE: The canonical source of this file is maintained with the GNU C Library.
7Bugs can be reported to bug-glibc@prep.ai.mit.edu.
8
9This program is free software; you can redistribute it and/or modify it
10under the terms of the GNU General Public License as published by the
11Free Software Foundation; either version 2, or (at your option) any
12later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
22
23#if defined (STDC_HEADERS) || !defined (isascii)
24#define ISASCII(c) 1
25#else
26#define ISASCII(c) isascii(c)
27#endif
28
29#define ISUPPER(c) (ISASCII (c) && isupper (c))
30
31
32/* Comment out all this code if we are using the GNU C Library, and are not
33   actually compiling the library itself.  This code is part of the GNU C
34   Library, but also included in many other GNU distributions.  Compiling
35   and linking in this code is a waste when using the GNU C library
36   (especially if it is a shared library).  Rather than having every GNU
37   program understand `configure --with-gnu-libc' and omit the object files,
38   it is simpler to just do this in the source for each such file.  */
39
40#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
41extern int errno;
42#endif
43
44/* Match STRING against the filename pattern PATTERN, returning zero if
45   it matches, nonzero if not.  */
46int fnmatch (const char *pattern, const char *string, int flags)
47{
48  register const char *p = pattern, *n = string;
49  register char c;
50
51/* Note that this evalutes C many times.  */
52#define FOLD(c)	((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
53
54  while ((c = *p++) != '\0')
55    {
56      c = FOLD (c);
57
58      switch (c)
59	{
60	case '?':
61	  if (*n == '\0')
62	    return FNM_NOMATCH;
63	  else if ((flags & FNM_FILE_NAME) && *n == '/')
64	    return FNM_NOMATCH;
65	  else if ((flags & FNM_PERIOD) && *n == '.' &&
66		   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
67	    return FNM_NOMATCH;
68	  break;
69
70	case '\\':
71	  if (!(flags & FNM_NOESCAPE))
72	    {
73	      c = *p++;
74	      c = FOLD (c);
75	    }
76	  if (FOLD (*n) != c)
77	    return FNM_NOMATCH;
78	  break;
79
80	case '*':
81	  if ((flags & FNM_PERIOD) && *n == '.' &&
82	      (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
83	    return FNM_NOMATCH;
84
85	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
86	    if (((flags & FNM_FILE_NAME) && *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	    c1 = FOLD (c1);
96	    for (--p; *n != '\0'; ++n)
97	      if ((c == '[' || FOLD (*n) == c1) &&
98		  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
99		return 0;
100	    return FNM_NOMATCH;
101	  }
102
103	case '[':
104	  {
105	    /* Nonzero if the sense of the character class is 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_FILE_NAME) && n[-1] == '/')))
113	      return FNM_NOMATCH;
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		cstart = cend = FOLD (cstart);
128
129		if (c == '\0')
130		  /* [ (unterminated) loses.  */
131		  return FNM_NOMATCH;
132
133		c = *p++;
134		c = FOLD (c);
135
136		if ((flags & FNM_FILE_NAME) && c == '/')
137		  /* [/] can never match.  */
138		  return FNM_NOMATCH;
139
140		if (c == '-' && *p != ']')
141		  {
142		    cend = *p++;
143		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
144		      cend = *p++;
145		    if (cend == '\0')
146		      return FNM_NOMATCH;
147		    cend = FOLD (cend);
148
149		    c = *p++;
150		  }
151
152		if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
153		  goto matched;
154
155		if (c == ']')
156		  break;
157	      }
158	    if (!not)
159	      return FNM_NOMATCH;
160	    break;
161
162	  matched:;
163	    /* Skip the rest of the [...] that already matched.  */
164	    while (c != ']')
165	      {
166		if (c == '\0')
167		  /* [... (unterminated) loses.  */
168		  return FNM_NOMATCH;
169
170		c = *p++;
171		if (!(flags & FNM_NOESCAPE) && c == '\\')
172		  /* XXX 1003.2d11 is unclear if this is right.  */
173		  ++p;
174	      }
175	    if (not)
176	      return FNM_NOMATCH;
177	  }
178	  break;
179
180	default:
181	  if (c != FOLD (*n))
182	    return FNM_NOMATCH;
183	}
184
185      ++n;
186    }
187
188  if (*n == '\0')
189    return 0;
190
191  if ((flags & FNM_LEADING_DIR) && *n == '/')
192    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
193    return 0;
194
195  return FNM_NOMATCH;
196}
197
198#else	/* HAVE_FNMATCH */
199 void fnmatch_dummy(void) {}
200#endif
201