Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4973 | right-hear | 1 | /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
2 | #include |
||
3 | #include |
||
4 | #include |
||
5 | #include |
||
6 | #include |
||
7 | |||
8 | #define EOS '\0' |
||
9 | |||
10 | static const char *rangematch(const char *pattern, char test, int nocase); |
||
11 | |||
12 | #define isslash(c) ((c) == '\\' || (c) == '/') |
||
13 | |||
14 | static const char * |
||
15 | find_slash(const char *s) |
||
16 | { |
||
17 | while (*s) |
||
18 | { |
||
19 | if (isslash(*s)) |
||
20 | return s; |
||
21 | s++; |
||
22 | } |
||
23 | return 0; |
||
24 | } |
||
25 | |||
26 | static const char * |
||
27 | rangematch(const char *pattern, char test, int nocase) |
||
28 | { |
||
29 | char c, c2; |
||
30 | int negate, ok; |
||
31 | |||
32 | if ((negate = (*pattern == '!'))) |
||
33 | ++pattern; |
||
34 | |||
35 | for (ok = 0; (c = *pattern++) != ']';) |
||
36 | { |
||
37 | if (c == 0) |
||
38 | return 0; /* illegal pattern */ |
||
39 | if (*pattern == '-' && (c2 = pattern[1]) != 0 && c2 != ']') |
||
40 | { |
||
41 | if (c <= test && test <= c2) |
||
42 | ok = 1; |
||
43 | if (nocase && toupper(c) <= toupper(test) && toupper(test) <= toupper(c2)) |
||
44 | ok = 1; |
||
45 | pattern += 2; |
||
46 | } |
||
47 | else if (c == test) |
||
48 | ok = 1; |
||
49 | else if (nocase && (toupper(c) == toupper(test))) |
||
50 | ok = 1; |
||
51 | } |
||
52 | return ok == negate ? NULL : pattern; |
||
53 | } |
||
54 | |||
55 | int |
||
56 | fnmatch(const char *pattern, const char *string, int flags) |
||
57 | { |
||
58 | char c; |
||
59 | char test; |
||
60 | |||
61 | for (;;) |
||
62 | switch ((c = *pattern++)) |
||
63 | { |
||
64 | case 0: |
||
65 | return *string == 0 ? 0 : FNM_NOMATCH; |
||
66 | |||
67 | case '?': |
||
68 | if ((test = *string++) == 0 || |
||
69 | (isslash(test) && (flags & FNM_PATHNAME))) |
||
70 | return(FNM_NOMATCH); |
||
71 | break; |
||
72 | |||
73 | case '*': |
||
74 | c = *pattern; |
||
75 | /* collapse multiple stars */ |
||
76 | while (c == '*') |
||
77 | c = *++pattern; |
||
78 | |||
79 | /* optimize for pattern with * at end or before / */ |
||
80 | if (c == 0) |
||
81 | if (flags & FNM_PATHNAME) |
||
82 | return find_slash(string) ? FNM_NOMATCH : 0; |
||
83 | else |
||
84 | return 0; |
||
85 | else if (isslash(c) && flags & FNM_PATHNAME) |
||
86 | { |
||
87 | if ((string = find_slash(string)) == NULL) |
||
88 | return FNM_NOMATCH; |
||
89 | break; |
||
90 | } |
||
91 | |||
92 | /* general case, use recursion */ |
||
93 | while ((test = *string) != 0) |
||
94 | { |
||
95 | if (fnmatch(pattern, string, flags) == 0) |
||
96 | return(0); |
||
97 | if (isslash(test) && flags & FNM_PATHNAME) |
||
98 | break; |
||
99 | ++string; |
||
100 | } |
||
101 | return FNM_NOMATCH; |
||
102 | |||
103 | case '[': |
||
104 | if ((test = *string++) == 0 || |
||
105 | (isslash(test) && flags & FNM_PATHNAME)) |
||
106 | return FNM_NOMATCH; |
||
107 | if ((pattern = rangematch(pattern, test, flags & FNM_NOCASE)) == NULL) |
||
108 | return FNM_NOMATCH; |
||
109 | break; |
||
110 | |||
111 | case '\\': |
||
112 | if (!(flags & FNM_NOESCAPE) && pattern[1] && strchr("*?[\\", pattern[1])) |
||
113 | { |
||
114 | if ((c = *pattern++) == 0) |
||
115 | { |
||
116 | c = '\\'; |
||
117 | --pattern; |
||
118 | } |
||
119 | if (c != *string++) |
||
120 | return FNM_NOMATCH; |
||
121 | break; |
||
122 | } |
||
123 | /* FALLTHROUGH */ |
||
124 | |||
125 | default: |
||
126 | if (isslash(c) && isslash(*string)) |
||
127 | { |
||
128 | string++; |
||
129 | break; |
||
130 | } |
||
131 | if (flags & FNM_NOCASE) |
||
132 | { |
||
133 | if (toupper(c) != toupper(*string++)) |
||
134 | return FNM_NOMATCH; |
||
135 | } |
||
136 | else |
||
137 | { |
||
138 | if (c != *string++) |
||
139 | return FNM_NOMATCH; |
||
140 | } |
||
141 | break; |
||
142 | } |
||
143 | }=>=>=>=> |