1 //
2 // "$Id: filename_match.cxx 7903 2010-11-28 21:06:39Z matt $"
3 //
4 // Pattern matching routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 /* Adapted from Rich Salz. */
29 #include <FL/filename.H>
30 #include <ctype.h>
31 
32 /**
33     Checks if a string \p s matches a pattern \p p.
34     The following syntax is used for the pattern:
35     - * matches any sequence of 0 or more characters.
36     - ? matches any single character.
37     - [set] matches any character in the set. Set can contain any single characters, or a-z to represent a range.
38       To match ] or - they must be the first characters. To match ^ or ! they must not be the first characters.
39     - [^set] or [!set] matches any character not in the set.
40     - {X|Y|Z} or {X,Y,Z} matches any one of the subexpressions literally.
41     - \\x quotes the character x so it has no special meaning.
42     - x all other characters must be matched exactly.
43 
44     \b Include:
45     \code
46     #include <FL/filename.H>
47     \endcode
48 
49     \param[in] s the string to check for a match
50     \param[in] p the string pattern
51     \return non zero if the string matches the pattern
52 */
fl_filename_match(const char * s,const char * p)53 int fl_filename_match(const char *s, const char *p) {
54   int matched;
55 
56   for (;;) {
57     switch(*p++) {
58 
59     case '?' :	// match any single character
60       if (!*s++) return 0;
61       break;
62 
63     case '*' :	// match 0-n of any characters
64       if (!*p) return 1; // do trailing * quickly
65       while (!fl_filename_match(s, p)) if (!*s++) return 0;
66       return 1;
67 
68     case '[': {	// match one character in set of form [abc-d] or [^a-b]
69       if (!*s) return 0;
70       int reverse = (*p=='^' || *p=='!'); if (reverse) p++;
71       matched = 0;
72       char last = 0;
73       while (*p) {
74 	if (*p=='-' && last) {
75 	  if (*s <= *++p && *s >= last ) matched = 1;
76 	  last = 0;
77 	} else {
78 	  if (*s == *p) matched = 1;
79 	}
80 	last = *p++;
81 	if (*p==']') break;
82       }
83       if (matched == reverse) return 0;
84       s++; p++;}
85     break;
86 
87     case '{' : // {pattern1|pattern2|pattern3}
88     NEXTCASE:
89     if (fl_filename_match(s,p)) return 1;
90     for (matched = 0;;) {
91       switch (*p++) {
92       case '\\': if (*p) p++; break;
93       case '{': matched++; break;
94       case '}': if (!matched--) return 0; break;
95       case '|': case ',': if (matched==0) goto NEXTCASE;
96       case 0: return 0;
97       }
98     }
99     case '|':	// skip rest of |pattern|pattern} when called recursively
100     case ',':
101       for (matched = 0; *p && matched >= 0;) {
102 	switch (*p++) {
103 	case '\\': if (*p) p++; break;
104 	case '{': matched++; break;
105 	case '}': matched--; break;
106 	}
107       }
108       break;
109     case '}':
110       break;
111 
112     case 0:	// end of pattern
113       return !*s;
114 
115     case '\\':	// quote next character
116       if (*p) p++;
117       /* FALLTHROUGH */
118     default:
119       if (tolower(*s) != tolower(*(p-1))) return 0;
120       s++;
121       break;
122     }
123   }
124 }
125 
126 //
127 // End of "$Id: filename_match.cxx 7903 2010-11-28 21:06:39Z matt $".
128 //
129