1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

wildcard.c: allow the matched string to be a ptrlen.

The main wildcard matching code now doesn't depend on having a NUL
terminator in the string to be matched; instead it works with a pair
of pointers, one working along the string as we match, and the other
identifying the end of the string, and tests that p < target_end
before dereferencing p. User-facing entry points now allow you to pass
either an ordinary ASCIZ const char * or a ptrlen, and set up
target_end accordingly.

For the moment, the _wildcard_ parameter still has to be an ordinary
null-terminated string, but who knows, maybe that will have to change
too at some later point.
This commit is contained in:
Simon Tatham 2018-10-23 18:02:35 +01:00
parent cf8a421fa2
commit d1eb40950c
2 changed files with 24 additions and 10 deletions

View File

@ -1679,6 +1679,7 @@ int agent_exists(void);
* Exports from wildcard.c
*/
const char *wc_error(int value);
int wc_match_pl(const char *wildcard, ptrlen target);
int wc_match(const char *wildcard, const char *target);
int wc_unescape(char *output, const char *wildcard);

View File

@ -97,7 +97,8 @@ const char *wc_error(int value)
* returns zero. If the wildcard fragment suffers a syntax error,
* it returns <0 and the precise value indexes into wc_error.
*/
static int wc_match_fragment(const char **fragment, const char **target)
static int wc_match_fragment(const char **fragment, const char **target,
const char *target_end)
{
const char *f, *t;
@ -107,7 +108,7 @@ static int wc_match_fragment(const char **fragment, const char **target)
* The fragment terminates at either the end of the string, or
* the first (unescaped) *.
*/
while (*f && *f != '*' && *t) {
while (*f && *f != '*' && t < target_end) {
/*
* Extract one character from t, and one character's worth
* of pattern from f, and step along both. Return 0 if they
@ -204,8 +205,10 @@ static int wc_match_fragment(const char **fragment, const char **target)
* successful match, 0 for an unsuccessful match, and <0 for a
* syntax error in the wildcard.
*/
int wc_match(const char *wildcard, const char *target)
static int wc_match_inner(
const char *wildcard, const char *target, size_t target_len)
{
const char *target_end = target + target_len;
int ret;
/*
@ -216,7 +219,7 @@ int wc_match(const char *wildcard, const char *target)
* routine once and give up if it fails.
*/
if (*wildcard != '*') {
ret = wc_match_fragment(&wildcard, &target);
ret = wc_match_fragment(&wildcard, &target, target_end);
if (ret <= 0)
return ret; /* pass back failure or error alike */
}
@ -245,12 +248,12 @@ int wc_match(const char *wildcard, const char *target)
while (*target) {
const char *save_w = wildcard, *save_t = target;
ret = wc_match_fragment(&wildcard, &target);
ret = wc_match_fragment(&wildcard, &target, target_end);
if (ret < 0)
return ret; /* syntax error */
if (ret > 0 && !*wildcard && *target) {
if (ret > 0 && !*wildcard && target != target_end) {
/*
* Final special case - literally.
*
@ -272,9 +275,9 @@ int wc_match(const char *wildcard, const char *target)
* (which is why we saved `wildcard'). Then we
* return whatever that operation returns.
*/
target = save_t + strlen(save_t) - (target - save_t);
target = target_end - (target - save_t);
wildcard = save_w;
return wc_match_fragment(&wildcard, &target);
return wc_match_fragment(&wildcard, &target, target_end);
}
if (ret > 0)
@ -292,7 +295,17 @@ int wc_match(const char *wildcard, const char *target)
* wildcard. Hence, we return 1 if and only if we are also
* right at the end of the target.
*/
return (*target ? 0 : 1);
return target == target_end;
}
int wc_match(const char *wildcard, const char *target)
{
return wc_match_inner(wildcard, target, strlen(target));
}
int wc_match_pl(const char *wildcard, ptrlen target)
{
return wc_match_inner(wildcard, target.ptr, target.len);
}
/*
@ -439,7 +452,7 @@ int main(void)
f = fragment_tests[i].wildcard;
t = fragment_tests[i].target;
eret = fragment_tests[i].expected_result;
aret = wc_match_fragment(&f, &t);
aret = wc_match_fragment(&f, &t, t + strlen(t));
if (aret != eret) {
printf("failed test: /%s/ against /%s/ returned %d not %d\n",
fragment_tests[i].wildcard, fragment_tests[i].target,