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