move from sys to gen
[unix-history] / usr / src / lib / libc / gen / fnmatch.c
CommitLineData
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 12static 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 25static const char *rangematch __P((const char *, int));
2a3f39bf 26
d4120dc2 27fnmatch(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 97static const char *
e4dacb25 98rangematch(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}