Commit | Line | Data |
---|---|---|
d4120dc2 KB |
1 | /* |
2 | * Copyright (c) 1989 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Guido van Rossum. | |
7 | * | |
269a7923 | 8 | * %sccs.include.redist.c% |
d4120dc2 KB |
9 | */ |
10 | ||
11 | #if defined(LIBC_SCCS) && !defined(lint) | |
92f9656c | 12 | static char sccsid[] = "@(#)fnmatch.c 5.6 (Berkeley) %G%"; |
d4120dc2 KB |
13 | #endif /* LIBC_SCCS and not lint */ |
14 | ||
15 | /* | |
92f9656c | 16 | * Function fnmatch() as proposed in POSIX 1003.2 B.6 (D11.2). |
d4120dc2 KB |
17 | * Compares a filename or pathname to a pattern. |
18 | */ | |
19 | ||
e4dacb25 | 20 | #include <fnmatch.h> |
d4120dc2 KB |
21 | #include <string.h> |
22 | ||
23 | #define EOS '\0' | |
24 | ||
92f9656c | 25 | static const char *rangematch __P((const char *, int)); |
2a3f39bf | 26 | |
d4120dc2 | 27 | fnmatch(pattern, string, flags) |
e4dacb25 | 28 | register const char *pattern, *string; |
d4120dc2 KB |
29 | int flags; |
30 | { | |
31 | register char c; | |
e4dacb25 | 32 | char test; |
d4120dc2 KB |
33 | |
34 | for (;;) | |
35 | switch (c = *pattern++) { | |
36 | case EOS: | |
e4dacb25 | 37 | return (*string == EOS ? 0 : FNM_NOMATCH); |
d4120dc2 KB |
38 | case '?': |
39 | if ((test = *string++) == EOS || | |
40 | test == '/' && flags & FNM_PATHNAME) | |
e4dacb25 | 41 | return (FNM_NOMATCH); |
d4120dc2 KB |
42 | break; |
43 | case '*': | |
44 | c = *pattern; | |
e4dacb25 | 45 | /* Collapse multiple stars. */ |
d4120dc2 KB |
46 | while (c == '*') |
47 | c = *++pattern; | |
48 | ||
e4dacb25 | 49 | /* Optimize for pattern with * at end or before /. */ |
d4120dc2 KB |
50 | if (c == EOS) |
51 | if (flags & FNM_PATHNAME) | |
e4dacb25 KB |
52 | return (index(string, '/') == NULL ? |
53 | 0 : FNM_NOMATCH); | |
d4120dc2 | 54 | else |
e4dacb25 | 55 | return (0); |
d4120dc2 KB |
56 | else if (c == '/' && flags & FNM_PATHNAME) { |
57 | if ((string = index(string, '/')) == NULL) | |
e4dacb25 | 58 | return (FNM_NOMATCH); |
d4120dc2 KB |
59 | break; |
60 | } | |
61 | ||
e4dacb25 | 62 | /* General case, use recursion. */ |
d4120dc2 | 63 | while ((test = *string) != EOS) { |
e4dacb25 KB |
64 | if (!fnmatch(pattern, string, flags)) |
65 | return (0); | |
d4120dc2 KB |
66 | if (test == '/' && flags & FNM_PATHNAME) |
67 | break; | |
68 | ++string; | |
69 | } | |
e4dacb25 | 70 | return (FNM_NOMATCH); |
d4120dc2 KB |
71 | case '[': |
72 | if ((test = *string++) == EOS || | |
73 | test == '/' && flags & FNM_PATHNAME) | |
e4dacb25 | 74 | return (FNM_NOMATCH); |
d4120dc2 | 75 | if ((pattern = rangematch(pattern, test)) == NULL) |
e4dacb25 | 76 | return (FNM_NOMATCH); |
d4120dc2 KB |
77 | break; |
78 | case '\\': | |
e4dacb25 | 79 | if (!(flags & FNM_NOESCAPE)) { |
d4120dc2 KB |
80 | if ((c = *pattern++) == EOS) { |
81 | c = '\\'; | |
82 | --pattern; | |
83 | } | |
84 | if (c != *string++) | |
e4dacb25 | 85 | return (FNM_NOMATCH); |
d4120dc2 KB |
86 | break; |
87 | } | |
88 | /* FALLTHROUGH */ | |
89 | default: | |
90 | if (c != *string++) | |
e4dacb25 | 91 | return (FNM_NOMATCH); |
d4120dc2 KB |
92 | break; |
93 | } | |
e4dacb25 KB |
94 | /* NOTREACHED */ |
95 | } | |
96 | ||
92f9656c | 97 | static const char * |
e4dacb25 | 98 | rangematch(pattern, test) |
92f9656c | 99 | register const char *pattern; |
e4dacb25 KB |
100 | register int test; |
101 | { | |
102 | register char c, c2; | |
103 | int negate, ok; | |
104 | ||
105 | if (negate = (*pattern == '!')) | |
106 | ++pattern; | |
107 | ||
108 | /* | |
109 | * XXX | |
110 | * TO DO: quoting | |
111 | */ | |
112 | for (ok = 0; (c = *pattern++) != ']';) { | |
113 | if (c == EOS) | |
114 | return (NULL); /* Illegal pattern. */ | |
115 | if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') { | |
116 | if (c <= test && test <= c2) | |
117 | ok = 1; | |
118 | pattern += 2; | |
119 | } | |
120 | else if (c == test) | |
121 | ok = 1; | |
122 | } | |
123 | return (ok == negate ? NULL : pattern); | |
d4120dc2 | 124 | } |