summaryrefslogtreecommitdiff
path: root/match.c
diff options
context:
space:
mode:
Diffstat (limited to 'match.c')
-rw-r--r--match.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/match.c b/match.c
new file mode 100644
index 0000000..da3a497
--- /dev/null
+++ b/match.c
@@ -0,0 +1,158 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996-1998,2001,2002,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Do shell-style pattern matching for '?', '\', '[..]', and '*' wildcards.
+ * Returns 1 if match, 0 if not.
+ */
+
+#include "sysincludes.h"
+#include "mtools.h"
+
+
+static int casecmp(wchar_t a, wchar_t b)
+{
+ return towupper(a) == towupper(b);
+}
+
+static int exactcmp(wchar_t a,wchar_t b)
+{
+ return a == b;
+}
+
+
+static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out,
+ int (*compfn)(wchar_t a, wchar_t b))
+{
+ wchar_t table[256];
+ int reverse;
+ int i;
+ short first, last;
+
+ if (**p == '^') {
+ reverse = 1;
+ (*p)++;
+ } else
+ reverse=0;
+ for(i=0; i<256; i++)
+ table[i]=0;
+ while(**p != ']') {
+ if(!**p)
+ return 0;
+ if((*p)[1] == '-') {
+ first = **p;
+ (*p)+=2;
+ if(**p == ']')
+ last = 256;
+ else
+ last = *((*p)++);
+ for(i=first; i<=last; i++)
+ table[i] = 1;
+ } else
+ table[(int) *((*p)++)] = 1;
+ }
+ if(out)
+ *out = *s;
+ if(table[(int) *s])
+ return 1 ^ reverse;
+ if(compfn == exactcmp)
+ return reverse;
+ if(table[tolower(*s)]) {
+ if(out)
+ *out = tolower(*s);
+ return 1 ^ reverse;
+ }
+ if(table[toupper(*s)]) {
+ if(out)
+ *out = toupper(*s);
+ return 1 ^ reverse;
+ }
+ return reverse;
+}
+
+
+static int _match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case,
+ int length,
+ int (*compfn) (wchar_t a, wchar_t b))
+{
+ for (; *p != '\0' && length; ) {
+ switch (*p) {
+ case '?': /* match any one character */
+ if (*s == '\0')
+ return(0);
+ if(out)
+ *(out++) = *s;
+ break;
+ case '*': /* match everything */
+ while (*p == '*' && length) {
+ p++;
+ length--;
+ }
+
+ /* search for next char in pattern */
+ while(*s) {
+ if(_match(s, p, out, Case, length,
+ compfn))
+ return 1;
+ if(out)
+ *out++ = *s;
+ s++;
+ }
+ continue;
+ case '[': /* match range of characters */
+ p++;
+ length--;
+ if(!parse_range(&p, s, out++, compfn))
+ return 0;
+ break;
+ case '\\': /* Literal match with next character */
+ p++;
+ length--;
+ /* fall thru */
+ default:
+ if (!compfn(*s,*p))
+ return(0);
+ if(out)
+ *(out++) = *p;
+ break;
+ }
+ p++;
+ length--;
+ s++;
+ }
+ if(out)
+ *out = '\0';
+
+ /* string ended prematurely ? */
+ if (*s != '\0')
+ return(0);
+ else
+ return(1);
+}
+
+
+int match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length)
+{
+ int (*compfn)(wchar_t a, wchar_t b);
+
+ if(Case)
+ compfn = casecmp;
+ else
+ /*compfn = exactcmp;*/
+ compfn = casecmp;
+ return _match(s, p, out, Case, length, compfn);
+}
+