diff --git a/include/libwebsockets/lws-tokenize.h b/include/libwebsockets/lws-tokenize.h index 70379de0b..830101978 100644 --- a/include/libwebsockets/lws-tokenize.h +++ b/include/libwebsockets/lws-tokenize.h @@ -251,3 +251,15 @@ LWS_VISIBLE LWS_EXTERN int lws_strexp_expand(lws_strexp_t *exp, const char *in, size_t len, size_t *pused_in, size_t *pused_out); +/** + * lws_strcmp_wildcard() - strcmp but the first arg can have wildcards + * + * \p wildcard: a string that may contain zero to three *, and may lack a NUL + * \p len: length of the wildcard string + * \p check: string to test to see if it matches wildcard + * + * Exactly like strcmp, but supports patterns like "a*", "a*b", "a*b*" etc + * where a and b are arbitrary substrings + */ +LWS_VISIBLE LWS_EXTERN int +lws_strcmp_wildcard(const char *wildcard, size_t len, const char *check); diff --git a/lib/core/libwebsockets.c b/lib/core/libwebsockets.c index 0bf3a6df4..df658a255 100644 --- a/lib/core/libwebsockets.c +++ b/lib/core/libwebsockets.c @@ -1135,6 +1135,82 @@ drain: return LSTRX_DONE; } +int +lws_strcmp_wildcard(const char *wildcard, size_t len, const char *check) +{ + const char *match[3], *wc[3], *wc_end = wildcard + len; + int sp = 0; + + do { + + if (wildcard == wc_end) { + /* + * We reached the end of wildcard, but not of check, + * and the last thing in wildcard was not a * or we + * would have completed already... if we can rewind, + * let's try that... + */ + if (sp) { + wildcard = wc[sp - 1]; + check = match[--sp]; + + continue; + } + + /* otherwise it's the end of the road for this one */ + + return 1; + } + + if (*wildcard == '*') { + + if (++wildcard == wc_end) + /* + * Wildcard ended on a *, so we know we will + * match unconditionally + */ + return 0; + + /* + * Now we need to stick wildcard here and see if there + * is any remaining match exists, for eg b of "a*b" + */ + + if (sp == LWS_ARRAY_SIZE(match)) { + lwsl_err("%s: exceeds * stack\n", __func__); + return 1; /* we can't deal with it */ + } + + wc[sp] = wildcard; + /* if we ever pop and come back here, pick up from +1 */ + match[sp++] = check + 1; + continue; + } + + if (*(check++) == *wildcard) { + + if (wildcard == wc_end) + return 0; + /* + * We're still compatible with wildcard... keep going + */ + wildcard++; + + continue; + } + + if (!sp) + /* + * We're just trying to match literals, and failed... + */ + return 1; + + /* we're looking for a post-* match... keep looking... */ + + } while (*check); + + return !!*wildcard; +} #if LWS_MAX_SMP > 1 diff --git a/minimal-examples/api-tests/api-test-lws_tokenize/main.c b/minimal-examples/api-tests/api-test-lws_tokenize/main.c index 06fcb69db..b55678958 100644 --- a/minimal-examples/api-tests/api-test-lws_tokenize/main.c +++ b/minimal-examples/api-tests/api-test-lws_tokenize/main.c @@ -660,6 +660,67 @@ int main(int argc, const char **argv) } } + if (lws_strcmp_wildcard("allied", 6, "allied")) { + lwsl_user("%s: wc 1 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("a*", 2, "allied")) { + lwsl_user("%s: wc 2 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("all*", 4, "allied")) { + lwsl_user("%s: wc 3 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("all*d", 5, "allied")) { + lwsl_user("%s: wc 4 fail\n", __func__); + fail++; + } + if (!lws_strcmp_wildcard("b*", 2, "allied")) { + lwsl_user("%s: wc 5 fail\n", __func__); + fail++; + } + if (!lws_strcmp_wildcard("b*ed", 4, "allied")) { + lwsl_user("%s: wc 6 fail\n", __func__); + fail++; + } + if (!lws_strcmp_wildcard("allie", 5, "allied")) { + lwsl_user("%s: wc 7 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("allie*", 6, "allied")) { + lwsl_user("%s: wc 8 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("*llie*", 6, "allied")) { + lwsl_user("%s: wc 9 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("*llied", 6, "allied")) { + lwsl_user("%s: wc 10 fail\n", __func__); + fail++; + } + if (!lws_strcmp_wildcard("*llie", 5, "allied")) { + lwsl_user("%s: wc 11 fail\n", __func__); + fail++; + } + if (!lws_strcmp_wildcard("*nope", 5, "allied")) { + lwsl_user("%s: wc 12 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("*li*", 4, "allied")) { + lwsl_user("%s: wc 13 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("*", 1, "allied")) { + lwsl_user("%s: wc 14 fail\n", __func__); + fail++; + } + if (lws_strcmp_wildcard("*abc*d", 6, "xxabyyabcdd")) { + lwsl_user("%s: wc 15 fail\n", __func__); + fail++; + } + lwsl_user("Completed: PASS: %d, FAIL: %d\n", ok, fail); return !(ok && !fail);