• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*  Copyright 1986-1992 Emmet P. Gray.
2  *  Copyright 1996-1998,2001,2002,2008,2009 Alain Knaff.
3  *  This file is part of mtools.
4  *
5  *  Mtools is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  Mtools is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Do shell-style pattern matching for '?', '\', '[..]', and '*' wildcards.
19  * Returns 1 if match, 0 if not.
20  */
21 
22 #include "sysincludes.h"
23 #include "mtools.h"
24 
25 
casecmp(wchar_t a,wchar_t b)26 static int casecmp(wchar_t a, wchar_t b)
27 {
28 	return towupper((wint_t)a) == towupper((wint_t)b);
29 }
30 
exactcmp(wchar_t a,wchar_t b)31 static int exactcmp(wchar_t a,wchar_t b)
32 {
33 	return a == b;
34 }
35 
36 
is_in_range(wchar_t ch,const wchar_t ** p,int * reverse)37 static int is_in_range(wchar_t ch, const wchar_t **p, int *reverse) {
38 	wchar_t first, last;
39 	int found=0;
40 	if (**p == '^') {
41 		*reverse = 1;
42 		(*p)++;
43 	} else
44 		*reverse=0;
45 	while( (first = **p) != ']') {
46 		if(!first)
47 			/* Malformed pattern, range not closed */
48 			return 0;
49 		if(*(++(*p)) == '-') {
50 			last = *(++(*p));
51 			if(last==']') {
52 				/* Last "-" in range designates itself */
53 				if(ch == first || ch == '-')
54 					found = 1;
55 				break;
56 			}
57 			(*p)++;
58 
59 			/* a proper range */
60 			if(ch >= first && ch <= last)
61 				found = 1;
62 		} else
63 			/* a Just one character */
64 			if(ch == first)
65 				found = 1;
66 	}
67 	return found;
68 }
69 
parse_range(const wchar_t ** p,const wchar_t * s,wchar_t * out,int (* compfn)(wchar_t a,wchar_t b))70 static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out,
71 		       int (*compfn)(wchar_t a, wchar_t b))
72 {
73 	int reverse;
74 	const wchar_t *p0 = *p;
75 	const wchar_t *p1 = *p;
76 	if(out)
77 		*out = *s;
78 	if(is_in_range(*s, p, &reverse))
79 		return 1 ^ reverse;
80 	if(compfn == exactcmp)
81 		return reverse;
82 	if(is_in_range((wchar_t)towlower((wint_t)*s), &p0, &reverse)) {
83 		if(out)
84 			*out = (wchar_t)towlower((wint_t)*s);
85 		return 1 ^ reverse;
86 	}
87 	if(is_in_range((wchar_t)towupper((wint_t)*s), &p1, &reverse)) {
88 		if(out)
89 			*out = (wchar_t)towupper((wint_t)*s);
90 		return 1 ^ reverse;
91 	}
92 	return reverse;
93 }
94 
95 
_match(const wchar_t * s,const wchar_t * p,wchar_t * out,int Case,int length,int (* compfn)(wchar_t a,wchar_t b))96 static int _match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case,
97 		  int length,
98 		  int (*compfn) (wchar_t a, wchar_t b))
99 {
100 	for (; *p != '\0' && length; ) {
101 		switch (*p) {
102 			case '?':	/* match any one character */
103 				if (*s == '\0')
104 					return(0);
105 				if(out)
106 					*(out++) = *s;
107 				break;
108 			case '*':	/* match everything */
109 				while (*p == '*' && length) {
110 					p++;
111 					length--;
112 				}
113 
114 					/* search for next char in pattern */
115 				while(*s) {
116 					if(_match(s, p, out, Case, length,
117 						  compfn))
118 						return 1;
119 					if(out)
120 						*out++ = *s;
121 					s++;
122 				}
123 				continue;
124 			case '[':	 /* match range of characters */
125 				p++;
126 				length--;
127 				if(!parse_range(&p, s, out++, compfn))
128 					return 0;
129 				break;
130 			case '\\':	/* Literal match with next character */
131 				p++;
132 				length--;
133 				/* fall thru */
134 			default:
135 				if (!compfn(*s,*p))
136 					return(0);
137 				if(out)
138 					*(out++) = *p;
139 				break;
140 		}
141 		p++;
142 		length--;
143 		s++;
144 	}
145 	if(out)
146 		*out = '\0';
147 
148 					/* string ended prematurely ? */
149 	if (*s != '\0')
150 		return(0);
151 	else
152 		return(1);
153 }
154 
155 
match(const wchar_t * s,const wchar_t * p,wchar_t * out,int Case,int length)156 int match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length)
157 {
158 	int (*compfn)(wchar_t a, wchar_t b);
159 
160 	if(Case)
161 		compfn = casecmp;
162 	else
163 		/*compfn = exactcmp;*/
164 		compfn = casecmp;
165 	return _match(s, p, out, Case, length, compfn);
166 }
167 
168