xref: /plan9/sys/src/ape/cmd/diff/fnmatch.c (revision 0b459c2cb92b7c9d88818e9a2f72e678e5bc4553)
1*0b459c2cSDavid du Colombier /* Copyright (C) 1992 Free Software Foundation, Inc.
2*0b459c2cSDavid du Colombier This file is part of the GNU C Library.
3*0b459c2cSDavid du Colombier 
4*0b459c2cSDavid du Colombier The GNU C Library is free software; you can redistribute it and/or
5*0b459c2cSDavid du Colombier modify it under the terms of the GNU Library General Public License as
6*0b459c2cSDavid du Colombier published by the Free Software Foundation; either version 2 of the
7*0b459c2cSDavid du Colombier License, or (at your option) any later version.
8*0b459c2cSDavid du Colombier 
9*0b459c2cSDavid du Colombier The GNU C Library is distributed in the hope that it will be useful,
10*0b459c2cSDavid du Colombier but WITHOUT ANY WARRANTY; without even the implied warranty of
11*0b459c2cSDavid du Colombier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12*0b459c2cSDavid du Colombier Library General Public License for more details.  */
13*0b459c2cSDavid du Colombier 
14*0b459c2cSDavid du Colombier /* Modified slightly by Brian Berliner <berliner@sun.com> and
15*0b459c2cSDavid du Colombier    Jim Blandy <jimb@cyclic.com> for CVS use */
16*0b459c2cSDavid du Colombier 
17*0b459c2cSDavid du Colombier #ifdef HAVE_CONFIG_H
18*0b459c2cSDavid du Colombier #include "config.h"
19*0b459c2cSDavid du Colombier #endif
20*0b459c2cSDavid du Colombier 
21*0b459c2cSDavid du Colombier #include "system.h"
22*0b459c2cSDavid du Colombier 
23*0b459c2cSDavid du Colombier /* IGNORE(@ */
24*0b459c2cSDavid du Colombier /* #include <ansidecl.h> */
25*0b459c2cSDavid du Colombier /* @) */
26*0b459c2cSDavid du Colombier #include <errno.h>
27*0b459c2cSDavid du Colombier #include "fnmatch.h"
28*0b459c2cSDavid du Colombier 
29*0b459c2cSDavid du Colombier #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
30*0b459c2cSDavid du Colombier extern int errno;
31*0b459c2cSDavid du Colombier #endif
32*0b459c2cSDavid du Colombier 
33*0b459c2cSDavid du Colombier /* Match STRING against the filename pattern PATTERN, returning zero if
34*0b459c2cSDavid du Colombier    it matches, nonzero if not.  */
35*0b459c2cSDavid du Colombier int
36*0b459c2cSDavid du Colombier #if __STDC__
fnmatch(const char * pattern,const char * string,int flags)37*0b459c2cSDavid du Colombier fnmatch (const char *pattern, const char *string, int flags)
38*0b459c2cSDavid du Colombier #else
39*0b459c2cSDavid du Colombier fnmatch (pattern, string, flags)
40*0b459c2cSDavid du Colombier     char *pattern;
41*0b459c2cSDavid du Colombier     char *string;
42*0b459c2cSDavid du Colombier     int flags;
43*0b459c2cSDavid du Colombier #endif
44*0b459c2cSDavid du Colombier {
45*0b459c2cSDavid du Colombier   register const char *p = pattern, *n = string;
46*0b459c2cSDavid du Colombier   register char c;
47*0b459c2cSDavid du Colombier 
48*0b459c2cSDavid du Colombier   if ((flags & ~__FNM_FLAGS) != 0)
49*0b459c2cSDavid du Colombier     {
50*0b459c2cSDavid du Colombier       errno = EINVAL;
51*0b459c2cSDavid du Colombier       return -1;
52*0b459c2cSDavid du Colombier     }
53*0b459c2cSDavid du Colombier 
54*0b459c2cSDavid du Colombier   while ((c = *p++) != '\0')
55*0b459c2cSDavid du Colombier     {
56*0b459c2cSDavid du Colombier       switch (c)
57*0b459c2cSDavid du Colombier 	{
58*0b459c2cSDavid du Colombier 	case '?':
59*0b459c2cSDavid du Colombier 	  if (*n == '\0')
60*0b459c2cSDavid du Colombier 	    return FNM_NOMATCH;
61*0b459c2cSDavid du Colombier 	  else if ((flags & FNM_PATHNAME) && *n == '/')
62*0b459c2cSDavid du Colombier 	    return FNM_NOMATCH;
63*0b459c2cSDavid du Colombier 	  else if ((flags & FNM_PERIOD) && *n == '.' &&
64*0b459c2cSDavid du Colombier 		   (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
65*0b459c2cSDavid du Colombier 	    return FNM_NOMATCH;
66*0b459c2cSDavid du Colombier 	  break;
67*0b459c2cSDavid du Colombier 
68*0b459c2cSDavid du Colombier 	case '\\':
69*0b459c2cSDavid du Colombier 	  if (!(flags & FNM_NOESCAPE))
70*0b459c2cSDavid du Colombier 	    c = *p++;
71*0b459c2cSDavid du Colombier 	  if (FOLD_FN_CHAR (*n) != FOLD_FN_CHAR (c))
72*0b459c2cSDavid du Colombier 	    return FNM_NOMATCH;
73*0b459c2cSDavid du Colombier 	  break;
74*0b459c2cSDavid du Colombier 
75*0b459c2cSDavid du Colombier 	case '*':
76*0b459c2cSDavid du Colombier 	  if ((flags & FNM_PERIOD) && *n == '.' &&
77*0b459c2cSDavid du Colombier 	      (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
78*0b459c2cSDavid du Colombier 	    return FNM_NOMATCH;
79*0b459c2cSDavid du Colombier 
80*0b459c2cSDavid du Colombier 	  for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
81*0b459c2cSDavid du Colombier 	    if (((flags & FNM_PATHNAME) && *n == '/') ||
82*0b459c2cSDavid du Colombier 		(c == '?' && *n == '\0'))
83*0b459c2cSDavid du Colombier 	      return FNM_NOMATCH;
84*0b459c2cSDavid du Colombier 
85*0b459c2cSDavid du Colombier 	  if (c == '\0')
86*0b459c2cSDavid du Colombier 	    return 0;
87*0b459c2cSDavid du Colombier 
88*0b459c2cSDavid du Colombier 	  {
89*0b459c2cSDavid du Colombier 	    char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
90*0b459c2cSDavid du Colombier 	    for (--p; *n != '\0'; ++n)
91*0b459c2cSDavid du Colombier 	      if ((c == '[' || FOLD_FN_CHAR (*n) == FOLD_FN_CHAR (c1)) &&
92*0b459c2cSDavid du Colombier 		  fnmatch(p, n, flags & ~FNM_PERIOD) == 0)
93*0b459c2cSDavid du Colombier 		return 0;
94*0b459c2cSDavid du Colombier 	    return FNM_NOMATCH;
95*0b459c2cSDavid du Colombier 	  }
96*0b459c2cSDavid du Colombier 
97*0b459c2cSDavid du Colombier 	case '[':
98*0b459c2cSDavid du Colombier 	  {
99*0b459c2cSDavid du Colombier 	    /* Nonzero if the sense of the character class is inverted.  */
100*0b459c2cSDavid du Colombier 	    register int not;
101*0b459c2cSDavid du Colombier 
102*0b459c2cSDavid du Colombier 	    if (*n == '\0')
103*0b459c2cSDavid du Colombier 	      return FNM_NOMATCH;
104*0b459c2cSDavid du Colombier 
105*0b459c2cSDavid du Colombier 	    if ((flags & FNM_PERIOD) && *n == '.' &&
106*0b459c2cSDavid du Colombier 		(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
107*0b459c2cSDavid du Colombier 	      return FNM_NOMATCH;
108*0b459c2cSDavid du Colombier 
109*0b459c2cSDavid du Colombier 	    not = (*p == '!' || *p == '^');
110*0b459c2cSDavid du Colombier 	    if (not)
111*0b459c2cSDavid du Colombier 	      ++p;
112*0b459c2cSDavid du Colombier 
113*0b459c2cSDavid du Colombier 	    c = *p++;
114*0b459c2cSDavid du Colombier 	    for (;;)
115*0b459c2cSDavid du Colombier 	      {
116*0b459c2cSDavid du Colombier 		register char cstart = c, cend = c;
117*0b459c2cSDavid du Colombier 
118*0b459c2cSDavid du Colombier 		if (!(flags & FNM_NOESCAPE) && c == '\\')
119*0b459c2cSDavid du Colombier 		  cstart = cend = *p++;
120*0b459c2cSDavid du Colombier 
121*0b459c2cSDavid du Colombier 		if (c == '\0')
122*0b459c2cSDavid du Colombier 		  /* [ (unterminated) loses.  */
123*0b459c2cSDavid du Colombier 		  return FNM_NOMATCH;
124*0b459c2cSDavid du Colombier 
125*0b459c2cSDavid du Colombier 		c = *p++;
126*0b459c2cSDavid du Colombier 
127*0b459c2cSDavid du Colombier 		if ((flags & FNM_PATHNAME) && c == '/')
128*0b459c2cSDavid du Colombier 		  /* [/] can never match.  */
129*0b459c2cSDavid du Colombier 		  return FNM_NOMATCH;
130*0b459c2cSDavid du Colombier 
131*0b459c2cSDavid du Colombier 		if (c == '-' && *p != ']')
132*0b459c2cSDavid du Colombier 		  {
133*0b459c2cSDavid du Colombier 		    cend = *p++;
134*0b459c2cSDavid du Colombier 		    if (!(flags & FNM_NOESCAPE) && cend == '\\')
135*0b459c2cSDavid du Colombier 		      cend = *p++;
136*0b459c2cSDavid du Colombier 		    if (cend == '\0')
137*0b459c2cSDavid du Colombier 		      return FNM_NOMATCH;
138*0b459c2cSDavid du Colombier 		    c = *p++;
139*0b459c2cSDavid du Colombier 		  }
140*0b459c2cSDavid du Colombier 
141*0b459c2cSDavid du Colombier 		if (*n >= cstart && *n <= cend)
142*0b459c2cSDavid du Colombier 		  goto matched;
143*0b459c2cSDavid du Colombier 
144*0b459c2cSDavid du Colombier 		if (c == ']')
145*0b459c2cSDavid du Colombier 		  break;
146*0b459c2cSDavid du Colombier 	      }
147*0b459c2cSDavid du Colombier 	    if (!not)
148*0b459c2cSDavid du Colombier 	      return FNM_NOMATCH;
149*0b459c2cSDavid du Colombier 	    break;
150*0b459c2cSDavid du Colombier 
151*0b459c2cSDavid du Colombier 	  matched:;
152*0b459c2cSDavid du Colombier 	    /* Skip the rest of the [...] that already matched.  */
153*0b459c2cSDavid du Colombier 	    while (c != ']')
154*0b459c2cSDavid du Colombier 	      {
155*0b459c2cSDavid du Colombier 		if (c == '\0')
156*0b459c2cSDavid du Colombier 		  /* [... (unterminated) loses.  */
157*0b459c2cSDavid du Colombier 		  return FNM_NOMATCH;
158*0b459c2cSDavid du Colombier 
159*0b459c2cSDavid du Colombier 		c = *p++;
160*0b459c2cSDavid du Colombier 		if (!(flags & FNM_NOESCAPE) && c == '\\')
161*0b459c2cSDavid du Colombier 		  /* 1003.2d11 is unclear if this is right.  %%% */
162*0b459c2cSDavid du Colombier 		  ++p;
163*0b459c2cSDavid du Colombier 	      }
164*0b459c2cSDavid du Colombier 	    if (not)
165*0b459c2cSDavid du Colombier 	      return FNM_NOMATCH;
166*0b459c2cSDavid du Colombier 	  }
167*0b459c2cSDavid du Colombier 	  break;
168*0b459c2cSDavid du Colombier 
169*0b459c2cSDavid du Colombier 	default:
170*0b459c2cSDavid du Colombier 	  if (FOLD_FN_CHAR (c) != FOLD_FN_CHAR (*n))
171*0b459c2cSDavid du Colombier 	    return FNM_NOMATCH;
172*0b459c2cSDavid du Colombier 	}
173*0b459c2cSDavid du Colombier 
174*0b459c2cSDavid du Colombier       ++n;
175*0b459c2cSDavid du Colombier     }
176*0b459c2cSDavid du Colombier 
177*0b459c2cSDavid du Colombier   if (*n == '\0')
178*0b459c2cSDavid du Colombier     return 0;
179*0b459c2cSDavid du Colombier 
180*0b459c2cSDavid du Colombier   return FNM_NOMATCH;
181*0b459c2cSDavid du Colombier }
182