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
26static int casecmp(wchar_t a, wchar_t b)
27{
28	return towupper(a) == towupper(b);
29}
30
31static int exactcmp(wchar_t a,wchar_t b)
32{
33	return a == b;
34}
35
36
37static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out,
38		       int (*compfn)(wchar_t a, wchar_t b))
39{
40	wchar_t table[256];
41	int reverse;
42	int i;
43	short first, last;
44
45	if (**p == '^') {
46		reverse = 1;
47		(*p)++;
48	} else
49		reverse=0;
50	for(i=0; i<256; i++)
51		table[i]=0;
52	while(**p != ']') {
53		if(!**p)
54			return 0;
55		if((*p)[1] == '-') {
56			first = **p;
57			(*p)+=2;
58			if(**p == ']')
59				last = 256;
60			else
61				last = *((*p)++);
62			for(i=first; i<=last; i++)
63				table[i] = 1;
64		} else
65			table[(int) *((*p)++)] = 1;
66	}
67	if(out)
68		*out = *s;
69	if(table[(int) *s])
70		return 1 ^ reverse;
71	if(compfn == exactcmp)
72		return reverse;
73	if(table[tolower(*s)]) {
74		if(out)
75			*out = tolower(*s);
76		return 1 ^ reverse;
77	}
78	if(table[toupper(*s)]) {
79		if(out)
80			*out = toupper(*s);
81		return 1 ^ reverse;
82	}
83	return reverse;
84}
85
86
87static int _match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case,
88		  int length,
89		  int (*compfn) (wchar_t a, wchar_t b))
90{
91	for (; *p != '\0' && length; ) {
92		switch (*p) {
93			case '?':	/* match any one character */
94				if (*s == '\0')
95					return(0);
96				if(out)
97					*(out++) = *s;
98				break;
99			case '*':	/* match everything */
100				while (*p == '*' && length) {
101					p++;
102					length--;
103				}
104
105					/* search for next char in pattern */
106				while(*s) {
107					if(_match(s, p, out, Case, length,
108						  compfn))
109						return 1;
110					if(out)
111						*out++ = *s;
112					s++;
113				}
114				continue;
115			case '[':	 /* match range of characters */
116				p++;
117				length--;
118				if(!parse_range(&p, s, out++, compfn))
119					return 0;
120				break;
121			case '\\':	/* Literal match with next character */
122				p++;
123				length--;
124				/* fall thru */
125			default:
126				if (!compfn(*s,*p))
127					return(0);
128				if(out)
129					*(out++) = *p;
130				break;
131		}
132		p++;
133		length--;
134		s++;
135	}
136	if(out)
137		*out = '\0';
138
139					/* string ended prematurely ? */
140	if (*s != '\0')
141		return(0);
142	else
143		return(1);
144}
145
146
147int match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length)
148{
149	int (*compfn)(wchar_t a, wchar_t b);
150
151	if(Case)
152		compfn = casecmp;
153	else
154		/*compfn = exactcmp;*/
155		compfn = casecmp;
156	return _match(s, p, out, Case, length, compfn);
157}
158
159