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