drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / coregrind / m_seqmatch.c
blob06151ee0f810974b55fed8d90cb8b3cf164b8b76
2 /*--------------------------------------------------------------------*/
3 /*--- A simple sequence matching facility. ---*/
4 /*--- m_seqmatch.c ---*/
5 /*--------------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright (C) 2008-2017 OpenWorks Ltd
12 info@open-works.co.uk
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
30 #include "pub_core_basics.h"
31 #include "pub_core_libcassert.h"
32 #include "pub_core_libcbase.h" // VG_(strlen)
33 #include "pub_core_seqmatch.h" // self
35 /* ---------------------------------------------------------------------
36 A simple sequence matching facility
37 ------------------------------------------------------------------ */
39 /* See detailed comment in include/pub_tool_seqmatch.h about this. */
40 Bool VG_(generic_match) (
41 Bool matchAll,
42 const void* patt, SizeT szbPatt, UWord nPatt, UWord ixPatt,
43 const void* input, SizeT szbInput, UWord nInput, UWord ixInput,
44 Bool (*pIsStar)(const void*),
45 Bool (*pIsQuery)(const void*),
46 Bool (*pattEQinp)(const void*,const void*,void*,UWord),
47 void* inputCompleter, Bool (*haveInputInpC)(void*,UWord)
50 /* This is the spec, written in my favourite formal specification
51 language. It specifies non-greedy matching of '*'s.
53 ma ('*':ps) (i:is) = ma ps (i:is) || ma ('*':ps) is
54 ma ('*':ps) [] = ma ps []
56 ma ('?':ps) (i:is) = ma ps is
57 ma ('?':ps) [] = False
59 ma (p:ps) (i:is) = p == i && ma ps is
61 ma (p:ps) [] = False
62 ma [] (i:is) = False -- m-all, True for m-prefix
63 ma [] [] = True
65 Bool havePatt, haveInput;
66 const HChar *currPatt, *currInput;
67 tailcall:
68 vg_assert(nPatt >= 0 && nPatt < 1000000); /* arbitrary */
69 vg_assert(inputCompleter
70 || (nInput >= 0 && nInput < 1000000)); /* arbitrary */
71 vg_assert(ixPatt >= 0 && ixPatt <= nPatt);
72 vg_assert(ixInput >= 0 && (inputCompleter || ixInput <= nInput));
74 havePatt = ixPatt < nPatt;
75 haveInput = inputCompleter ?
76 (*haveInputInpC)(inputCompleter, ixInput)
77 : ixInput < nInput;
79 /* No specific need to set NULL when !have{Patt,Input}, but guards
80 against inadvertantly dereferencing an out of range pointer to
81 the pattern or input arrays. */
82 currPatt = havePatt ? ((const HChar*)patt) + szbPatt * ixPatt : NULL;
83 currInput = haveInput && !inputCompleter ?
84 ((const HChar*)input) + szbInput * ixInput : NULL;
86 // Deal with the complex case first: wildcards. Do frugal
87 // matching. When encountering a '*', first skip no characters
88 // at all, and see if the rest of the match still works. Only if
89 // that fails do we then skip a character, and retry at the next
90 // position.
92 // ma ('*':ps) (i:is) = ma ps (i:is) || ma ('*':ps) is
94 // If we're out of input, check the rest of the pattern matches
95 // the empty input. This really means can only be be empty or
96 // composed entirely of '*'s.
98 // ma ('*':ps) [] = ma ps []
100 if (havePatt && pIsStar(currPatt)) {
101 if (haveInput) {
102 // ma ('*':ps) (i:is) = ma ps (i:is) || ma ('*':ps) is
103 // we unavoidably have to make a real recursive call for the
104 // first half of the OR, since this isn't straight tail-recursion.
105 if (VG_(generic_match)( matchAll,
106 patt, szbPatt, nPatt, ixPatt+1,
107 input,szbInput,nInput, ixInput+0,
108 pIsStar,pIsQuery,pattEQinp,
109 inputCompleter,haveInputInpC) ) {
110 return True;
112 // but we can tail-recurse for the second call
113 ixInput++; goto tailcall;
114 } else {
115 // ma ('*':ps) [] = ma ps []
116 ixPatt++; goto tailcall;
120 // simpler cases now. Deal with '?' wildcards.
122 // ma ('?':ps) (i:is) = ma ps is
123 // ma ('?':ps) [] = False
124 if (havePatt && pIsQuery(currPatt)) {
125 if (haveInput) {
126 ixPatt++; ixInput++; goto tailcall;
127 } else {
128 return False;
132 // obvious case with literal chars in the pattern
134 // ma (p:ps) (i:is) = p == i && ma ps is
135 if (havePatt && haveInput) {
136 if (!pattEQinp(currPatt,currInput,inputCompleter,ixInput)) return False;
137 ixPatt++; ixInput++; goto tailcall;
140 // if we run out of input before we run out of pattern, we must fail
141 // ma (p:ps) [] = False
142 if (havePatt && !haveInput) return False;
144 // if we run out of pattern before we run out of input, the
145 // verdict depends on the matching mode. If we are trying to
146 // match exactly (the pattern must consume the entire input)
147 // then the outcome is failure. However, if we're merely attempting
148 // to match some prefix of the input, then we have been successful.
150 // ma [] (i:is) = False -- m-all, True for m-prefix
151 if (!havePatt && haveInput) {
152 return matchAll ? False // match-all
153 : True; // match-prefix
156 // finally, if both sequence and input are both completely
157 // consumed, then we were successful, regardless of matching mode.
158 if (!havePatt && !haveInput) return True;
160 // end of cases
161 vg_assert(0);
165 /* And a parameterization of the above, to make it do
166 string matching.
168 static Bool charIsStar ( const void* pV ) { return *(const HChar*)pV == '*'; }
169 static Bool charIsQuery ( const void* pV ) { return *(const HChar*)pV == '?'; }
170 static Bool char_p_EQ_i ( const void* pV, const void* cV,
171 void* null_completer, UWord ixcV ) {
172 HChar p = *(const HChar*)pV;
173 HChar c = *(const HChar*)cV;
174 vg_assert(p != '*' && p != '?');
175 return p == c;
177 Bool VG_(string_match) ( const HChar* patt, const HChar* input )
179 return VG_(generic_match)(
180 True/* match-all */,
181 patt, sizeof(HChar), VG_(strlen)(patt), 0,
182 input, sizeof(HChar), VG_(strlen)(input), 0,
183 charIsStar, charIsQuery, char_p_EQ_i,
184 NULL, NULL
189 // test cases for the matcher (in match-all mode)
190 // typedef struct { char* patt; char* input; Bool xres; } Test;
192 //static Test tests[] =
193 // {
194 // { "" ,"" , True },
195 // { "a" ,"" , False },
196 // { "a" ,"b" , False },
197 // { "a" ,"a" , True },
198 // { "a" ,"aa" , False },
199 // { "*" ,"" , True },
200 // { "**" ,"" , True },
201 // { "*" ,"abc", True },
202 // { "*a" ,"abc", False },
203 // { "*b" ,"abc", False },
204 // { "*bc" ,"abc", True },
205 // { "a*b" ,"abc", False },
206 // { "a*c" ,"abc", True },
207 // { "*c" ,"abc", True },
208 // { "c*c" ,"abc", False },
209 // { "abc*" ,"abc", True },
210 // { "abc**" ,"abc", True },
211 // { "**abc" ,"abc", True },
212 // { "**a*b*c**" ,"abc", True },
213 // { "**a*b*d**" ,"abc", False },
214 // { "a?b" ,"abc", False },
215 // { "a?c" ,"abc", True },
216 // { "?" ,"" , False },
217 // { "?" ,"a" , True },
218 // { "?" ,"ab" , False },
219 // { "abcd" ,"abc", False },
220 // { "ab" ,"abc", False },
221 // { NULL ,NULL , False }
222 // };
224 //int main ( void )
226 // Test* t;
227 // for (t = tests; t->patt; t++) {
228 // printf("%-10s %-6s %s\n",
229 // t->patt, t->input,
230 // match_string_all((UChar*)t->patt,(UChar*)t->input,True)
231 // == t->xres
232 // ? "pass" : "FAIL" );
233 // }
234 // return 0;
237 /*--------------------------------------------------------------------*/
238 /*--- end m_seqmatch.c ---*/
239 /*--------------------------------------------------------------------*/