1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <string.h>
4
5 #define ASTERISK '*' /* The '*' metacharacter */
6 #define QUESTION '?' /* The '?' metacharacter */
7 #define LEFT_BRACKET '[' /* The '[' metacharacter */
8 #define RIGHT_BRACKET ']' /* The ']' metacharacter */
9
10 #define IS_OCTAL(ch) (ch >= '0' && ch <= '7')
11
12 /* Filenames in BACKUP savesets can contain only these uppercase
13 letters, I think. */
14 #define IS_UC(ch) (ch >= 'A' && ch <= 'Z')
15
16 typedef int BOOLEAN;
17 #define VOID void
18 #define TRUE 1
19 #define FALSE 0
20 #define EOS '\000'
21
22 static BOOLEAN do_list ();
23 static char nextch ();
24 static VOID list_parse ();
25
26
27 /*
28 * FUNCTION
29 *
30 * match test string for wildcard match
31 *
32 * SYNOPSIS
33 *
34 * BOOLEAN match (string, pattern)
35 * register char *string;
36 * register char *pattern;
37 *
38 * DESCRIPTION
39 *
40 * Test string for match using pattern. The pattern may
41 * contain the normal shell metacharacters for pattern
42 * matching. The '*' character matches any string,
43 * including the null string. The '?' character matches
44 * any single character. A list of characters enclosed
45 * in '[' and ']' matches any character in the list.
46 * If the first character following the beginning '['
47 * is a '!' then any character not in the list is matched.
48 *
49 */
50
51
52 /*
53 * PSEUDO CODE
54 *
55 * Begin match
56 * Switch on type of pattern character
57 * Case ASTERISK:
58 * Attempt to match asterisk
59 * Break
60 * Case QUESTION MARK:
61 * Attempt to match question mark
62 * Break
63 * Case EOS:
64 * Match is result of EOS on string test
65 * Break
66 * Case default:
67 * If explicit match then
68 * Match is result of submatch
69 * Else
70 * Match is FALSE
71 * End if
72 * Break
73 * End switch
74 * Return result of match test
75 * End match
76 *
77 */
78
match(string,pattern)79 BOOLEAN match (string, pattern)
80 register char *string;
81 register char *pattern;
82 {
83 register BOOLEAN ismatch;
84
85 ismatch = FALSE;
86 switch (*pattern) {
87 case ASTERISK:
88 pattern++;
89 do {
90 ismatch = match (string, pattern);
91 } while (!ismatch && *string++ != EOS);
92 break;
93 case QUESTION:
94 if (*string != EOS) {
95 ismatch = match (++string, ++pattern);
96 }
97 break;
98 case EOS:
99 if (*string == EOS) {
100 ismatch = TRUE;
101 }
102 break;
103 case LEFT_BRACKET:
104 if (*string != EOS) {
105 ismatch = do_list (string, pattern);
106 }
107 break;
108 default:
109 if (*string++ == *pattern++) {
110 ismatch = match (string, pattern);
111 } else {
112 ismatch = FALSE;
113 }
114 break;
115 }
116 return (ismatch);
117 }
118
119
120 /*
121 * FUNCTION
122 *
123 * do_list process a list and following substring
124 *
125 * SYNOPSIS
126 *
127 * static BOOLEAN do_list (string, pattern)
128 * register char *string;
129 * register char *pattern;
130 *
131 * DESCRIPTION
132 *
133 * Called when a list is found in the pattern. Returns
134 * TRUE if the current character matches the list and
135 * the remaining substring matches the remaining pattern.
136 *
137 * Returns FALSE if either the current character fails to
138 * match the list or the list matches but the remaining
139 * substring and subpattern's don't.
140 *
141 * RESTRICTIONS
142 *
143 * The mechanism used to match characters in an inclusive
144 * pair (I.E. [a-d]) may not be portable to machines
145 * in which the native character set is not ASCII.
146 *
147 * The rules implemented here are:
148 *
149 * (1) The backslash character may be
150 * used to quote any special character.
151 * I.E. "\]" and "\-" anywhere in list,
152 * or "\!" at start of list.
153 *
154 * (2) The sequence \nnn becomes the character
155 * given by nnn (in octal).
156 *
157 * (3) Any non-escaped ']' marks the end of list.
158 *
159 * (4) A list beginning with the special character
160 * '!' matches any character NOT in list.
161 * The '!' character is only special if it
162 * is the first character in the list.
163 *
164 */
165
166
167 /*
168 * PSEUDO CODE
169 *
170 * Begin do_list
171 * Default result is no match
172 * Skip over the opening left bracket
173 * If the next pattern character is a '!' then
174 * List match gives FALSE
175 * Skip over the '!' character
176 * Else
177 * List match gives TRUE
178 * End if
179 * While not at closing bracket or EOS
180 * Get lower and upper bounds
181 * If character in bounds then
182 * Result is same as sense flag.
183 * Skip over rest of list
184 * End if
185 * End while
186 * If match found then
187 * If not at end of pattern then
188 * Call match with rest of pattern
189 * End if
190 * End if
191 * Return match result
192 * End do_list
193 *
194 */
195
do_list(string,pattern)196 static BOOLEAN do_list (string, pattern)
197 register char *string;
198 char *pattern;
199 {
200 register BOOLEAN ismatch;
201 register BOOLEAN if_found;
202 register BOOLEAN if_not_found;
203 auto char lower;
204 auto char upper;
205
206 pattern++;
207 if (*pattern == '!') {
208 if_found = FALSE;
209 if_not_found = TRUE;
210 pattern++;
211 } else {
212 if_found = TRUE;
213 if_not_found = FALSE;
214 }
215 ismatch = if_not_found;
216 while (*pattern != ']' && *pattern != EOS) {
217 list_parse (&pattern, &lower, &upper);
218 if (*string >= lower && *string <= upper) {
219 ismatch = if_found;
220 while (*pattern != ']' && *pattern != EOS) {pattern++;}
221 }
222 }
223 if (*pattern++ != ']') {
224 fprintf (stderr, "warning - character class error\n");
225 } else {
226 if (ismatch) {
227 ismatch = match (++string, pattern);
228 }
229 }
230 return (ismatch);
231 }
232
233
234 /*
235 * FUNCTION
236 *
237 * list_parse parse part of list into lower and upper bounds
238 *
239 * SYNOPSIS
240 *
241 * static VOID list_parse (patp, lowp, highp)
242 * char **patp;
243 * char *lowp;
244 * char *highp;
245 *
246 * DESCRIPTION
247 *
248 * Given pointer to a pattern pointer (patp), pointer to
249 * a place to store lower bound (lowp), and pointer to a
250 * place to store upper bound (highp), parses part of
251 * the list, updating the pattern pointer in the process.
252 *
253 * For list characters which are not part of a range,
254 * the lower and upper bounds are set to that character.
255 *
256 */
257
list_parse(patp,lowp,highp)258 static VOID list_parse (patp, lowp, highp)
259 char **patp;
260 char *lowp;
261 char *highp;
262 {
263 *lowp = nextch (patp);
264 if (**patp == '-') {
265 (*patp)++;
266 *highp = nextch (patp);
267 } else {
268 *highp = *lowp;
269 }
270 }
271
272
273 /*
274 * FUNCTION
275 *
276 * nextch determine next character in a pattern
277 *
278 * SYNOPSIS
279 *
280 * static char nextch (patp)
281 * char **patp;
282 *
283 * DESCRIPTION
284 *
285 * Given pointer to a pointer to a pattern, uses the pattern
286 * pointer to determine the next character in the pattern,
287 * subject to translation of backslash-char and backslash-octal
288 * sequences.
289 *
290 * The character pointer is updated to point at the next pattern
291 * character to be processed.
292 *
293 */
294
nextch(patp)295 static char nextch (patp)
296 char **patp;
297 {
298 register char ch;
299 register char chsum;
300 register int count;
301
302 ch = *(*patp)++;
303 if (ch == '\\') {
304 ch = *(*patp)++;
305 if (IS_OCTAL (ch)) {
306 chsum = 0;
307 for (count = 0; count < 3 && IS_OCTAL (ch); count++) {
308 chsum *= 8;
309 chsum += ch - '0';
310 ch = *(*patp)++;
311 }
312 (*patp)--;
313 ch = chsum;
314 }
315 }
316 return (ch);
317 }
318
319 char *
strlocase(str)320 strlocase(str)
321 char *str;
322 {
323 int i;
324
325 for (i = 0; i < strlen(str); i++) {
326 if (IS_UC (str[i])) {
327 str[i] = str[i] - 'A' + 'a';
328 }
329 }
330 return (str);
331 }
332