Annotation of src/lib/libc/gen/fnmatch.c, Revision 1.20
1.20 ! agc 1: /* $NetBSD: fnmatch.c,v 1.19 2002/10/06 03:15:46 provos Exp $ */
1.11 cgd 2:
1.1 cgd 3: /*
1.11 cgd 4: * Copyright (c) 1989, 1993, 1994
1.6 cgd 5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * This code is derived from software contributed to Berkeley by
8: * Guido van Rossum.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.20 ! agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: */
34:
1.12 christos 35: #include <sys/cdefs.h>
1.1 cgd 36: #if defined(LIBC_SCCS) && !defined(lint)
1.11 cgd 37: #if 0
38: static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
39: #else
1.20 ! agc 40: __RCSID("$NetBSD: fnmatch.c,v 1.19 2002/10/06 03:15:46 provos Exp $");
1.11 cgd 41: #endif
1.1 cgd 42: #endif /* LIBC_SCCS and not lint */
43:
44: /*
1.7 jtc 45: * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
1.1 cgd 46: * Compares a filename or pathname to a pattern.
47: */
48:
1.13 jtc 49: #include "namespace.h"
1.15 lukem 50:
51: #include <assert.h>
1.18 thorpej 52: #include <ctype.h>
1.3 jtc 53: #include <fnmatch.h>
1.1 cgd 54: #include <string.h>
1.13 jtc 55:
56: #ifdef __weak_alias
1.17 mycroft 57: __weak_alias(fnmatch,_fnmatch)
1.13 jtc 58: #endif
1.1 cgd 59:
60: #define EOS '\0'
61:
1.7 jtc 62: static const char *rangematch __P((const char *, int, int));
1.1 cgd 63:
1.18 thorpej 64: static __inline int
65: foldcase(int ch, int flags)
66: {
67:
68: if ((flags & FNM_CASEFOLD) != 0 && isupper(ch))
69: return (tolower(ch));
70: return (ch);
71: }
72:
73: #define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags))
74:
1.9 jtc 75: int
1.1 cgd 76: fnmatch(pattern, string, flags)
1.11 cgd 77: const char *pattern, *string;
1.1 cgd 78: int flags;
79: {
1.11 cgd 80: const char *stringstart;
81: char c, test;
1.1 cgd 82:
1.15 lukem 83: _DIAGASSERT(pattern != NULL);
84: _DIAGASSERT(string != NULL);
85:
1.11 cgd 86: for (stringstart = string;;)
1.18 thorpej 87: switch (c = FOLDCASE(*pattern++, flags)) {
1.1 cgd 88: case EOS:
1.19 provos 89: if ((flags & FNM_LEADING_DIR) && *string == '/')
90: return (0);
1.3 jtc 91: return (*string == EOS ? 0 : FNM_NOMATCH);
1.1 cgd 92: case '?':
1.8 jtc 93: if (*string == EOS)
1.3 jtc 94: return (FNM_NOMATCH);
1.8 jtc 95: if (*string == '/' && (flags & FNM_PATHNAME))
96: return (FNM_NOMATCH);
97: if (*string == '.' && (flags & FNM_PERIOD) &&
1.11 cgd 98: (string == stringstart ||
99: ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
1.8 jtc 100: return (FNM_NOMATCH);
101: ++string;
1.1 cgd 102: break;
103: case '*':
1.18 thorpej 104: c = FOLDCASE(*pattern, flags);
1.3 jtc 105: /* Collapse multiple stars. */
1.1 cgd 106: while (c == '*')
1.18 thorpej 107: c = FOLDCASE(*++pattern, flags);
1.1 cgd 108:
1.8 jtc 109: if (*string == '.' && (flags & FNM_PERIOD) &&
1.11 cgd 110: (string == stringstart ||
111: ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
1.8 jtc 112: return (FNM_NOMATCH);
113:
1.3 jtc 114: /* Optimize for pattern with * at end or before /. */
1.14 christos 115: if (c == EOS) {
1.1 cgd 116: if (flags & FNM_PATHNAME)
1.19 provos 117: return ((flags & FNM_LEADING_DIR) ||
118: strchr(string, '/') == NULL ?
1.3 jtc 119: 0 : FNM_NOMATCH);
1.1 cgd 120: else
1.3 jtc 121: return (0);
1.14 christos 122: } else if (c == '/' && flags & FNM_PATHNAME) {
1.10 jtc 123: if ((string = strchr(string, '/')) == NULL)
1.3 jtc 124: return (FNM_NOMATCH);
1.1 cgd 125: break;
126: }
127:
1.3 jtc 128: /* General case, use recursion. */
1.18 thorpej 129: while ((test = FOLDCASE(*string, flags)) != EOS) {
130: if (!fnmatch(pattern, string,
131: flags & ~FNM_PERIOD))
1.3 jtc 132: return (0);
1.1 cgd 133: if (test == '/' && flags & FNM_PATHNAME)
134: break;
135: ++string;
136: }
1.3 jtc 137: return (FNM_NOMATCH);
1.1 cgd 138: case '[':
1.8 jtc 139: if (*string == EOS)
140: return (FNM_NOMATCH);
141: if (*string == '/' && flags & FNM_PATHNAME)
1.3 jtc 142: return (FNM_NOMATCH);
1.11 cgd 143: if ((pattern =
1.18 thorpej 144: rangematch(pattern, FOLDCASE(*string, flags),
145: flags)) == NULL)
1.3 jtc 146: return (FNM_NOMATCH);
1.8 jtc 147: ++string;
1.1 cgd 148: break;
149: case '\\':
1.3 jtc 150: if (!(flags & FNM_NOESCAPE)) {
1.18 thorpej 151: if ((c = FOLDCASE(*pattern++, flags)) == EOS) {
1.1 cgd 152: c = '\\';
153: --pattern;
154: }
155: }
156: /* FALLTHROUGH */
157: default:
1.18 thorpej 158: if (c != FOLDCASE(*string++, flags))
1.3 jtc 159: return (FNM_NOMATCH);
1.1 cgd 160: break;
161: }
1.3 jtc 162: /* NOTREACHED */
163: }
164:
165: static const char *
1.7 jtc 166: rangematch(pattern, test, flags)
1.11 cgd 167: const char *pattern;
168: int test, flags;
1.3 jtc 169: {
170: int negate, ok;
1.11 cgd 171: char c, c2;
1.15 lukem 172:
173: _DIAGASSERT(pattern != NULL);
1.3 jtc 174:
1.11 cgd 175: /*
176: * A bracket expression starting with an unquoted circumflex
1.7 jtc 177: * character produces unspecified results (IEEE 1003.2-1992,
1.11 cgd 178: * 3.13.2). This implementation treats it like '!', for
179: * consistency with the regular expression syntax.
180: * J.T. Conklin (conklin@ngai.kaleida.com)
1.3 jtc 181: */
1.12 christos 182: if ((negate = (*pattern == '!' || *pattern == '^')) != 0)
1.11 cgd 183: ++pattern;
1.7 jtc 184:
1.18 thorpej 185: for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) {
1.11 cgd 186: if (c == '\\' && !(flags & FNM_NOESCAPE))
1.18 thorpej 187: c = FOLDCASE(*pattern++, flags);
1.11 cgd 188: if (c == EOS)
1.7 jtc 189: return (NULL);
190: if (*pattern == '-'
1.18 thorpej 191: && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS &&
192: c2 != ']') {
1.7 jtc 193: pattern += 2;
1.11 cgd 194: if (c2 == '\\' && !(flags & FNM_NOESCAPE))
1.18 thorpej 195: c2 = FOLDCASE(*pattern++, flags);
1.11 cgd 196: if (c2 == EOS)
1.7 jtc 197: return (NULL);
1.11 cgd 198: if (c <= test && test <= c2)
1.3 jtc 199: ok = 1;
1.11 cgd 200: } else if (c == test)
1.7 jtc 201: ok = 1;
1.3 jtc 202: }
203: return (ok == negate ? NULL : pattern);
1.1 cgd 204: }
CVSweb <webmaster@jp.NetBSD.org>