diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2000-07-17 23:01:21 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2000-07-17 23:01:21 +0000 |
commit | f726675da85a1c25e47a171f7efaa49fd01f1b2b (patch) | |
tree | ec2ae59c4f602f3ff85954c543060a83cbbee48f /usr.bin/make/str.c | |
parent | d33ae331261991b2696b6c6dc6778787fbe0f470 (diff) |
This does replace Str_Match with a better routine, which handles negated
intervals, and \\ in intervals.
Accordingly, var.c no longer needs to copy the :Marg to replace \: with :
We don't use fnmatch(3) because of various optimizations which are harder
to achieve in a generic setting.
Also add regression suite for the Str_Match function.
Diffstat (limited to 'usr.bin/make/str.c')
-rw-r--r-- | usr.bin/make/str.c | 206 |
1 files changed, 118 insertions, 88 deletions
diff --git a/usr.bin/make/str.c b/usr.bin/make/str.c index 7dbebe561c2..7aeb5f1551a 100644 --- a/usr.bin/make/str.c +++ b/usr.bin/make/str.c @@ -1,4 +1,4 @@ -/* $OpenBSD: str.c,v 1.13 2000/07/17 22:57:37 espie Exp $ */ +/* $OpenBSD: str.c,v 1.14 2000/07/17 23:01:20 espie Exp $ */ /* $NetBSD: str.c,v 1.13 1996/11/06 17:59:23 christos Exp $ */ /*- @@ -43,7 +43,7 @@ #if 0 static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; #else -static char rcsid[] = "$OpenBSD: str.c,v 1.13 2000/07/17 22:57:37 espie Exp $"; +static char rcsid[] = "$OpenBSD: str.c,v 1.14 2000/07/17 23:01:20 espie Exp $"; #endif #endif /* not lint */ @@ -223,103 +223,133 @@ done: argv[argc] = (char *)NULL; * * See if a particular string matches a particular pattern. * - * Results: Non-zero is returned if string matches pattern, 0 otherwise. The + * Results: TRUE is returned if string matches pattern, FALSE otherwise. The * matching operation permits the following special characters in the * pattern: *?\[] (see the man page for details on what these mean). - * - * Side effects: None. */ -int +Boolean Str_Match(string, pattern) - const char *string; /* String */ - const char *pattern; /* Pattern */ + const char *string; /* String */ + const char *pattern; /* Pattern */ { - char c2; - - for (;;) { - /* - * See if we're at the end of both the pattern and the - * string. If, we succeeded. If we're at the end of the - * pattern but not at the end of the string, we failed. - */ - if (*pattern == 0) - return(!*string); - if (*string == 0 && *pattern != '*') - return(0); - /* - * Check for a "*" as the next pattern character. It matches - * any substring. We handle this by calling ourselves - * recursively for each postfix of string, until either we - * match or we reach the end of the string. - */ - if (*pattern == '*') { - pattern += 1; - if (*pattern == 0) - return(1); - while (*string != 0) { - if (Str_Match(string, pattern)) - return(1); - ++string; - } - return(0); + while (*pattern != '\0') { + /* Check for a "*" as the next pattern character. It matches + * any substring. We handle this by calling ourselves + * recursively for each postfix of string, until either we + * match or we reach the end of the string. */ + if (*pattern == '*') { + pattern++; + /* Skip over contiguous sequences of `?*', so that recursive + * calls only occur on `real' characters. */ + while (*pattern == '?' || *pattern == '*') { + if (*pattern == '?') { + if (*string == '\0') + return FALSE; + else + string++; } - /* - * Check for a "?" as the next pattern character. It matches - * any single character. - */ - if (*pattern == '?') - goto thisCharOK; - /* - * Check for a "[" as the next pattern character. It is - * followed by a list of characters that are acceptable, or - * by a range (two characters separated by "-"). - */ - if (*pattern == '[') { - ++pattern; - for (;;) { - if ((*pattern == ']') || (*pattern == 0)) - return(0); - if (*pattern == *string) - break; - if (pattern[1] == '-') { - c2 = pattern[2]; - if (c2 == 0) - return(0); - if ((*pattern <= *string) && - (c2 >= *string)) - break; - if ((*pattern >= *string) && - (c2 <= *string)) - break; - pattern += 2; - } - ++pattern; - } - while ((*pattern != ']') && (*pattern != 0)) - ++pattern; - goto thisCharOK; + pattern++; + } + if (*pattern == '\0') + return TRUE; + for (; *string != '\0'; string++) + if (Str_Match(string, pattern)) + return TRUE; + return FALSE; + } else if (*string == '\0') + return FALSE; + /* Check for a "[" as the next pattern character. It is + * followed by a list of characters that are acceptable, or + * by a range (two characters separated by "-"). */ + else if (*pattern == '[') { + pattern++; + if (*pattern == '\0') + return FALSE; + if (*pattern == '!' || *pattern == '^') { + pattern++; + if (*pattern == '\0') + return FALSE; + /* Negative match */ + for (;;) { + if (*pattern == '\\') { + if (*++pattern == '\0') + return FALSE; + } + if (*pattern == *string) + return FALSE; + if (pattern[1] == '-') { + if (pattern[2] == '\0') + return FALSE; + if (*pattern < *string && *string <= pattern[2]) + return FALSE; + if (pattern[2] <= *string && *string < *pattern) + return FALSE; + pattern += 3; + } else + pattern++; + if (*pattern == '\0') + return FALSE; + /* The test for ']' is done at the end so that ']' + * can be used at the start of the range without '\' */ + if (*pattern == ']') + break; } - /* - * If the next pattern character is '/', just strip off the - * '/' so we do exact matching on the character that follows. - */ - if (*pattern == '\\') { - ++pattern; - if (*pattern == 0) - return(0); + } else { + for (;;) { + if (*pattern == '\\') { + if (*++pattern == '\0') + return FALSE; + } + if (*pattern == *string) + break; + if (pattern[1] == '-') { + if (pattern[2] == '\0') + return FALSE; + if (*pattern < *string && *string <= pattern[2]) + break; + if (pattern[2] <= *string && *string < *pattern) + break; + pattern += 3; + } else + pattern++; + /* The test for ']' is done at the end so that ']' + * can be used at the start of the range without '\' */ + if (*pattern == '\0' || *pattern == ']') + return FALSE; + } + /* Found matching character, skip over rest of class. */ + while (*pattern != ']') { + if (*pattern == '\\') + pattern++; + /* A non-terminated character class is ok. */ + if (*pattern == '\0') + break; + pattern++; } - /* - * There's no special character. Just make sure that the - * next characters of each string match. - */ - if (*pattern != *string) - return(0); -thisCharOK: ++pattern; - ++string; + } } + /* '?' matches any single character, so shunt test. */ + else if (*pattern != '?') { + /* If the next pattern character is '\', just strip off the + * '\' so we do exact matching on the character that follows. */ + if (*pattern == '\\') { + if (*++pattern == '\0') + return FALSE; + } + /* There's no special character. Just make sure that + * the next characters of each string match. */ + if (*pattern != *string) + return FALSE; + } + pattern++; + string++; + } + if (*string == '\0') + return TRUE; + else + return FALSE; } - /*- *----------------------------------------------------------------------- * Str_SYSVMatch -- |