xref: /openbsd/gnu/usr.bin/cvs/lib/fnmatch.c (revision e5dd7070)
1 /* Copyright (C) 1992 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 /* Modified slightly by Brian Berliner <berliner@sun.com> and
15    Jim Blandy <jimb@cyclic.com> for CVS use */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "system.h"
22 
23 /* IGNORE(@ */
24 /* #include <ansidecl.h> */
25 /* @) */
26 #include <errno.h>
27 #include <fnmatch.h>
28 
29 #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
30 extern int errno;
31 #endif
32 
33 /* Match STRING against the filename pattern PATTERN, returning zero if
34    it matches, nonzero if not.  */
35 int
36 #if __STDC__
37 fnmatch (const char *pattern, const char *string, int flags)
38 #else
39 fnmatch (pattern, string, flags)
40     char *pattern;
41     char *string;
42     int flags;
43 #endif
44 {
45   register const char *p = pattern, *n = string;
46   register char c;
47 
48   if ((flags & ~__FNM_FLAGS) != 0)
49     {
50       errno = EINVAL;
51       return -1;
52     }
53 
54   while ((c = *p++) != '\0')
55     {
56       switch (c)
57 	{
58 	case '?':
59 	  if (*n == '\0')
60 	    return FNM_NOMATCH;
61 	  else if ((flags & FNM_PATHNAME) && *n == '/')
62 	    return FNM_NOMATCH;
63 	  else if ((flags & FNM_PERIOD) && *n == '.' &&
64 		   (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
65 	    return FNM_NOMATCH;
66 	  break;
67 
68 	case '\\':
69 	  if (!(flags & FNM_NOESCAPE))
70 	    c = *p++;
71 	  if (FOLD_FN_CHAR (*n) != FOLD_FN_CHAR (c))
72 	    return FNM_NOMATCH;
73 	  break;
74 
75 	case '*':
76 	  if ((flags & FNM_PERIOD) && *n == '.' &&
77 	      (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
78 	    return FNM_NOMATCH;
79 
80 	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
81 	    if (((flags & FNM_PATHNAME) && *n == '/') ||
82 		(c == '?' && *n == '\0'))
83 	      return FNM_NOMATCH;
84 
85 	  if (c == '\0')
86 	    return 0;
87 
88 	  {
89 	    char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
90 	    for (--p; *n != '\0'; ++n)
91 	      if ((c == '[' || FOLD_FN_CHAR (*n) == FOLD_FN_CHAR (c1)) &&
92 		  fnmatch(p, n, flags & ~FNM_PERIOD) == 0)
93 		return 0;
94 	    return FNM_NOMATCH;
95 	  }
96 
97 	case '[':
98 	  {
99 	    /* Nonzero if the sense of the character class is inverted.  */
100 	    register int not;
101 
102 	    if (*n == '\0')
103 	      return FNM_NOMATCH;
104 
105 	    if ((flags & FNM_PERIOD) && *n == '.' &&
106 		(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
107 	      return FNM_NOMATCH;
108 
109 	    not = (*p == '!' || *p == '^');
110 	    if (not)
111 	      ++p;
112 
113 	    c = *p++;
114 	    for (;;)
115 	      {
116 		register char cstart = c, cend = c;
117 
118 		if (!(flags & FNM_NOESCAPE) && c == '\\')
119 		  cstart = cend = *p++;
120 
121 		if (c == '\0')
122 		  /* [ (unterminated) loses.  */
123 		  return FNM_NOMATCH;
124 
125 		c = *p++;
126 
127 		if ((flags & FNM_PATHNAME) && c == '/')
128 		  /* [/] can never match.  */
129 		  return FNM_NOMATCH;
130 
131 		if (c == '-' && *p != ']')
132 		  {
133 		    cend = *p++;
134 		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
135 		      cend = *p++;
136 		    if (cend == '\0')
137 		      return FNM_NOMATCH;
138 		    c = *p++;
139 		  }
140 
141 		if (*n >= cstart && *n <= cend)
142 		  goto matched;
143 
144 		if (c == ']')
145 		  break;
146 	      }
147 	    if (!not)
148 	      return FNM_NOMATCH;
149 	    break;
150 
151 	  matched:;
152 	    /* Skip the rest of the [...] that already matched.  */
153 	    while (c != ']')
154 	      {
155 		if (c == '\0')
156 		  /* [... (unterminated) loses.  */
157 		  return FNM_NOMATCH;
158 
159 		c = *p++;
160 		if (!(flags & FNM_NOESCAPE) && c == '\\')
161 		  /* 1003.2d11 is unclear if this is right.  %%% */
162 		  ++p;
163 	      }
164 	    if (not)
165 	      return FNM_NOMATCH;
166 	  }
167 	  break;
168 
169 	default:
170 	  if (FOLD_FN_CHAR (c) != FOLD_FN_CHAR (*n))
171 	    return FNM_NOMATCH;
172 	}
173 
174       ++n;
175     }
176 
177   if (*n == '\0')
178     return 0;
179 
180   return FNM_NOMATCH;
181 }
182