mirror of
git://sourceware.org/git/valgrind.git
synced 2026-01-12 00:19:31 +08:00
- Update COPYING and VEX/LICENSE.GPL to version 3. - Update README, NEWS, docs/manual license and contributing text. - Update file headers to say either version 3 of the License, or (at your option) any later version. - Leave tests and perf file headers as is, unless the code is derived from Valgrind/VEX. - Leave valgrind.h, cachegrind.h, callgrind.h, drd.h, helgrind.h, memcheck.h and dhat.h Hybrid-BSD licensed.
239 lines
8.4 KiB
C
239 lines
8.4 KiB
C
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- A simple sequence matching facility. ---*/
|
|
/*--- m_seqmatch.c ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2008-2017 OpenWorks Ltd
|
|
info@open-works.co.uk
|
|
|
|
This program 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.
|
|
|
|
This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
#include "pub_core_basics.h"
|
|
#include "pub_core_libcassert.h"
|
|
#include "pub_core_libcbase.h" // VG_(strlen)
|
|
#include "pub_core_seqmatch.h" // self
|
|
|
|
/* ---------------------------------------------------------------------
|
|
A simple sequence matching facility
|
|
------------------------------------------------------------------ */
|
|
|
|
/* See detailed comment in include/pub_tool_seqmatch.h about this. */
|
|
Bool VG_(generic_match) (
|
|
Bool matchAll,
|
|
const void* patt, SizeT szbPatt, UWord nPatt, UWord ixPatt,
|
|
const void* input, SizeT szbInput, UWord nInput, UWord ixInput,
|
|
Bool (*pIsStar)(const void*),
|
|
Bool (*pIsQuery)(const void*),
|
|
Bool (*pattEQinp)(const void*,const void*,void*,UWord),
|
|
void* inputCompleter, Bool (*haveInputInpC)(void*,UWord)
|
|
)
|
|
{
|
|
/* This is the spec, written in my favourite formal specification
|
|
language. It specifies non-greedy matching of '*'s.
|
|
|
|
ma ('*':ps) (i:is) = ma ps (i:is) || ma ('*':ps) is
|
|
ma ('*':ps) [] = ma ps []
|
|
|
|
ma ('?':ps) (i:is) = ma ps is
|
|
ma ('?':ps) [] = False
|
|
|
|
ma (p:ps) (i:is) = p == i && ma ps is
|
|
|
|
ma (p:ps) [] = False
|
|
ma [] (i:is) = False -- m-all, True for m-prefix
|
|
ma [] [] = True
|
|
*/
|
|
Bool havePatt, haveInput;
|
|
const HChar *currPatt, *currInput;
|
|
tailcall:
|
|
vg_assert(nPatt < 1000000); /* arbitrary */
|
|
vg_assert(inputCompleter || (nInput < 1000000)); /* arbitrary */
|
|
vg_assert(ixPatt <= nPatt);
|
|
vg_assert(inputCompleter || ixInput <= nInput);
|
|
|
|
havePatt = ixPatt < nPatt;
|
|
haveInput = inputCompleter ?
|
|
(*haveInputInpC)(inputCompleter, ixInput)
|
|
: ixInput < nInput;
|
|
|
|
/* No specific need to set NULL when !have{Patt,Input}, but guards
|
|
against inadvertantly dereferencing an out of range pointer to
|
|
the pattern or input arrays. */
|
|
currPatt = havePatt ? ((const HChar*)patt) + szbPatt * ixPatt : NULL;
|
|
currInput = haveInput && !inputCompleter ?
|
|
((const HChar*)input) + szbInput * ixInput : NULL;
|
|
|
|
// Deal with the complex case first: wildcards. Do frugal
|
|
// matching. When encountering a '*', first skip no characters
|
|
// at all, and see if the rest of the match still works. Only if
|
|
// that fails do we then skip a character, and retry at the next
|
|
// position.
|
|
//
|
|
// ma ('*':ps) (i:is) = ma ps (i:is) || ma ('*':ps) is
|
|
//
|
|
// If we're out of input, check the rest of the pattern matches
|
|
// the empty input. This really means can only be be empty or
|
|
// composed entirely of '*'s.
|
|
//
|
|
// ma ('*':ps) [] = ma ps []
|
|
//
|
|
if (havePatt && pIsStar(currPatt)) {
|
|
if (haveInput) {
|
|
// ma ('*':ps) (i:is) = ma ps (i:is) || ma ('*':ps) is
|
|
// we unavoidably have to make a real recursive call for the
|
|
// first half of the OR, since this isn't straight tail-recursion.
|
|
if (VG_(generic_match)( matchAll,
|
|
patt, szbPatt, nPatt, ixPatt+1,
|
|
input,szbInput,nInput, ixInput+0,
|
|
pIsStar,pIsQuery,pattEQinp,
|
|
inputCompleter,haveInputInpC) ) {
|
|
return True;
|
|
}
|
|
// but we can tail-recurse for the second call
|
|
ixInput++; goto tailcall;
|
|
} else {
|
|
// ma ('*':ps) [] = ma ps []
|
|
ixPatt++; goto tailcall;
|
|
}
|
|
}
|
|
|
|
// simpler cases now. Deal with '?' wildcards.
|
|
//
|
|
// ma ('?':ps) (i:is) = ma ps is
|
|
// ma ('?':ps) [] = False
|
|
if (havePatt && pIsQuery(currPatt)) {
|
|
if (haveInput) {
|
|
ixPatt++; ixInput++; goto tailcall;
|
|
} else {
|
|
return False;
|
|
}
|
|
}
|
|
|
|
// obvious case with literal chars in the pattern
|
|
//
|
|
// ma (p:ps) (i:is) = p == i && ma ps is
|
|
if (havePatt && haveInput) {
|
|
if (!pattEQinp(currPatt,currInput,inputCompleter,ixInput)) return False;
|
|
ixPatt++; ixInput++; goto tailcall;
|
|
}
|
|
|
|
// if we run out of input before we run out of pattern, we must fail
|
|
// ma (p:ps) [] = False
|
|
if (havePatt && !haveInput) return False;
|
|
|
|
// if we run out of pattern before we run out of input, the
|
|
// verdict depends on the matching mode. If we are trying to
|
|
// match exactly (the pattern must consume the entire input)
|
|
// then the outcome is failure. However, if we're merely attempting
|
|
// to match some prefix of the input, then we have been successful.
|
|
//
|
|
// ma [] (i:is) = False -- m-all, True for m-prefix
|
|
if (!havePatt && haveInput) {
|
|
return matchAll ? False // match-all
|
|
: True; // match-prefix
|
|
}
|
|
|
|
// finally, if both sequence and input are both completely
|
|
// consumed, then we were successful, regardless of matching mode.
|
|
if (!havePatt && !haveInput) return True;
|
|
|
|
// end of cases
|
|
vg_assert(0);
|
|
}
|
|
|
|
|
|
/* And a parameterization of the above, to make it do
|
|
string matching.
|
|
*/
|
|
static Bool charIsStar ( const void* pV ) { return *(const HChar*)pV == '*'; }
|
|
static Bool charIsQuery ( const void* pV ) { return *(const HChar*)pV == '?'; }
|
|
static Bool char_p_EQ_i ( const void* pV, const void* cV,
|
|
void* null_completer, UWord ixcV ) {
|
|
HChar p = *(const HChar*)pV;
|
|
HChar c = *(const HChar*)cV;
|
|
vg_assert(p != '*' && p != '?');
|
|
return p == c;
|
|
}
|
|
Bool VG_(string_match) ( const HChar* patt, const HChar* input )
|
|
{
|
|
return VG_(generic_match)(
|
|
True/* match-all */,
|
|
patt, sizeof(HChar), VG_(strlen)(patt), 0,
|
|
input, sizeof(HChar), VG_(strlen)(input), 0,
|
|
charIsStar, charIsQuery, char_p_EQ_i,
|
|
NULL, NULL
|
|
);
|
|
}
|
|
|
|
|
|
// test cases for the matcher (in match-all mode)
|
|
// typedef struct { char* patt; char* input; Bool xres; } Test;
|
|
//
|
|
//static Test tests[] =
|
|
// {
|
|
// { "" ,"" , True },
|
|
// { "a" ,"" , False },
|
|
// { "a" ,"b" , False },
|
|
// { "a" ,"a" , True },
|
|
// { "a" ,"aa" , False },
|
|
// { "*" ,"" , True },
|
|
// { "**" ,"" , True },
|
|
// { "*" ,"abc", True },
|
|
// { "*a" ,"abc", False },
|
|
// { "*b" ,"abc", False },
|
|
// { "*bc" ,"abc", True },
|
|
// { "a*b" ,"abc", False },
|
|
// { "a*c" ,"abc", True },
|
|
// { "*c" ,"abc", True },
|
|
// { "c*c" ,"abc", False },
|
|
// { "abc*" ,"abc", True },
|
|
// { "abc**" ,"abc", True },
|
|
// { "**abc" ,"abc", True },
|
|
// { "**a*b*c**" ,"abc", True },
|
|
// { "**a*b*d**" ,"abc", False },
|
|
// { "a?b" ,"abc", False },
|
|
// { "a?c" ,"abc", True },
|
|
// { "?" ,"" , False },
|
|
// { "?" ,"a" , True },
|
|
// { "?" ,"ab" , False },
|
|
// { "abcd" ,"abc", False },
|
|
// { "ab" ,"abc", False },
|
|
// { NULL ,NULL , False }
|
|
// };
|
|
//
|
|
//int main ( void )
|
|
//{
|
|
// Test* t;
|
|
// for (t = tests; t->patt; t++) {
|
|
// printf("%-10s %-6s %s\n",
|
|
// t->patt, t->input,
|
|
// match_string_all((UChar*)t->patt,(UChar*)t->input,True)
|
|
// == t->xres
|
|
// ? "pass" : "FAIL" );
|
|
// }
|
|
// return 0;
|
|
//}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end m_seqmatch.c ---*/
|
|
/*--------------------------------------------------------------------*/
|