Initial import package mtools: Programs for accessing MS-DOS disks without mounting...
[profile/ivi/mtools.git] / match.c
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
26 static int casecmp(wchar_t a, wchar_t b)
27 {
28         return towupper(a) == towupper(b);
29 }
30
31 static int exactcmp(wchar_t a,wchar_t b)
32 {
33         return a == b;
34 }
35
36
37 static 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
87 static 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
147 int 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