~ubuntu-branches/ubuntu/gutsy/diffutils/gutsy

« back to all changes in this revision

Viewing changes to lib/fnmatch.c

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2005-02-15 22:45:18 UTC
  • Revision ID: james.westby@ubuntu.com-20050215224518-dw9ti3me00twpcmt
Tags: upstream-2.8.1
ImportĀ upstreamĀ versionĀ 2.8.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 1991, 1992, 1993, 1996, 1997, 2000 Free Software Foundation, Inc.
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; either version 2, or (at your option)
 
6
   any later version.
 
7
 
 
8
   This program 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
 
11
   GNU General Public License for more details.
 
12
 
 
13
  You should have received a copy of the GNU General Public License
 
14
  along with this program; if not, write to the Free Software Foundation,
 
15
  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
16
 
 
17
#if HAVE_CONFIG_H
 
18
# include <config.h>
 
19
#endif
 
20
 
 
21
/* Enable GNU extensions in fnmatch.h.  */
 
22
#ifndef _GNU_SOURCE
 
23
# define _GNU_SOURCE    1
 
24
#endif
 
25
 
 
26
#include <errno.h>
 
27
#include <fnmatch.h>
 
28
#include <ctype.h>
 
29
 
 
30
#if defined STDC_HEADERS || !defined isascii
 
31
# define IN_CTYPE_DOMAIN(c) 1
 
32
#else
 
33
# define IN_CTYPE_DOMAIN(c) isascii (c)
 
34
#endif
 
35
 
 
36
#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
 
37
 
 
38
 
 
39
#ifndef errno
 
40
extern int errno;
 
41
#endif
 
42
 
 
43
/* Match STRING against the filename pattern PATTERN, returning zero if
 
44
   it matches, nonzero if not.  */
 
45
int
 
46
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 evaluates C many times.  */
 
52
#define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER ((unsigned char) (c)) \
 
53
                 ? tolower ((unsigned char) (c)) \
 
54
                 : (c))
 
55
 
 
56
  while ((c = *p++) != '\0')
 
57
    {
 
58
      c = FOLD (c);
 
59
 
 
60
      switch (c)
 
61
        {
 
62
        case '?':
 
63
          if (*n == '\0')
 
64
            return FNM_NOMATCH;
 
65
          else if ((flags & FNM_FILE_NAME) && *n == '/')
 
66
            return FNM_NOMATCH;
 
67
          else if ((flags & FNM_PERIOD) && *n == '.' &&
 
68
                   (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
 
69
            return FNM_NOMATCH;
 
70
          break;
 
71
 
 
72
        case '\\':
 
73
          if (!(flags & FNM_NOESCAPE))
 
74
            {
 
75
              c = *p++;
 
76
              if (c == '\0')
 
77
                /* Trailing \ loses.  */
 
78
                return FNM_NOMATCH;
 
79
              c = FOLD (c);
 
80
            }
 
81
          if (FOLD (*n) != c)
 
82
            return FNM_NOMATCH;
 
83
          break;
 
84
 
 
85
        case '*':
 
86
          if ((flags & FNM_PERIOD) && *n == '.' &&
 
87
              (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
 
88
            return FNM_NOMATCH;
 
89
 
 
90
          for (c = *p++; c == '?' || c == '*'; c = *p++)
 
91
            {
 
92
              if (c == '?')
 
93
                {
 
94
                  /* A ? needs to match one character.  */
 
95
                  if (*n == '\0' || (*n == '/' && (flags & FNM_FILE_NAME)))
 
96
                    /* There isn't another character; no match.  */
 
97
                    return FNM_NOMATCH;
 
98
                  else
 
99
                    /* One character of the string is consumed in matching
 
100
                       this ? wildcard, so *??? won't match if there are
 
101
                       less than three characters.  */
 
102
                    ++n;
 
103
                }
 
104
            }
 
105
 
 
106
          if (c == '\0')
 
107
            {
 
108
              if ((flags & (FNM_FILE_NAME | FNM_LEADING_DIR)) == FNM_FILE_NAME)
 
109
                for (; *n != '\0'; n++)
 
110
                  if (*n == '/')
 
111
                    return FNM_NOMATCH;
 
112
              return 0;
 
113
            }
 
114
 
 
115
          {
 
116
            char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
 
117
            c1 = FOLD (c1);
 
118
            for (--p; *n != '\0'; ++n)
 
119
              if ((c == '[' || FOLD (*n) == c1) &&
 
120
                  fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
 
121
                return 0;
 
122
              else if (*n == '/' && (flags & FNM_FILE_NAME))
 
123
                break;
 
124
            return FNM_NOMATCH;
 
125
          }
 
126
 
 
127
        case '[':
 
128
          {
 
129
            /* Nonzero if the sense of the character class is inverted.  */
 
130
            register int not;
 
131
 
 
132
            if (*n == '\0')
 
133
              return FNM_NOMATCH;
 
134
 
 
135
            if ((flags & FNM_PERIOD) && *n == '.' &&
 
136
                (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/')))
 
137
              return FNM_NOMATCH;
 
138
 
 
139
            not = (*p == '!' || *p == '^');
 
140
            if (not)
 
141
              ++p;
 
142
 
 
143
            c = *p++;
 
144
            for (;;)
 
145
              {
 
146
                register char cstart = c, cend = c;
 
147
 
 
148
                if (!(flags & FNM_NOESCAPE) && c == '\\')
 
149
                  {
 
150
                    if (*p == '\0')
 
151
                      return FNM_NOMATCH;
 
152
                    cstart = cend = *p++;
 
153
                  }
 
154
 
 
155
                cstart = cend = FOLD (cstart);
 
156
 
 
157
                if (c == '\0')
 
158
                  /* [ (unterminated) loses.  */
 
159
                  return FNM_NOMATCH;
 
160
 
 
161
                c = *p++;
 
162
                c = FOLD (c);
 
163
 
 
164
                if ((flags & FNM_FILE_NAME) && c == '/')
 
165
                  /* [/] can never match.  */
 
166
                  return FNM_NOMATCH;
 
167
 
 
168
                if (c == '-' && *p != ']')
 
169
                  {
 
170
                    cend = *p++;
 
171
                    if (!(flags & FNM_NOESCAPE) && cend == '\\')
 
172
                      cend = *p++;
 
173
                    if (cend == '\0')
 
174
                      return FNM_NOMATCH;
 
175
                    cend = FOLD (cend);
 
176
 
 
177
                    c = *p++;
 
178
                  }
 
179
 
 
180
                if (FOLD (*n) >= cstart && FOLD (*n) <= cend)
 
181
                  goto matched;
 
182
 
 
183
                if (c == ']')
 
184
                  break;
 
185
              }
 
186
            if (!not)
 
187
              return FNM_NOMATCH;
 
188
            break;
 
189
 
 
190
          matched:;
 
191
            /* Skip the rest of the [...] that already matched.  */
 
192
            while (c != ']')
 
193
              {
 
194
                if (c == '\0')
 
195
                  /* [... (unterminated) loses.  */
 
196
                  return FNM_NOMATCH;
 
197
 
 
198
                c = *p++;
 
199
                if (!(flags & FNM_NOESCAPE) && c == '\\')
 
200
                  {
 
201
                    if (*p == '\0')
 
202
                      return FNM_NOMATCH;
 
203
                    /* XXX 1003.2d11 is unclear if this is right.  */
 
204
                    ++p;
 
205
                  }
 
206
              }
 
207
            if (not)
 
208
              return FNM_NOMATCH;
 
209
          }
 
210
          break;
 
211
 
 
212
        default:
 
213
          if (c != FOLD (*n))
 
214
            return FNM_NOMATCH;
 
215
        }
 
216
 
 
217
      ++n;
 
218
    }
 
219
 
 
220
  if (*n == '\0')
 
221
    return 0;
 
222
 
 
223
  if ((flags & FNM_LEADING_DIR) && *n == '/')
 
224
    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
 
225
    return 0;
 
226
 
 
227
  return FNM_NOMATCH;
 
228
 
 
229
#undef FOLD
 
230
}