From: Michael Poole Date: Mon, 30 May 2005 15:11:39 +0000 (+0000) Subject: Correctly match globs that end in escaped wildcards. X-Git-Url: http://git.pk910.de/?p=ircu2.10.12-pk.git;a=commitdiff_plain;h=463d8b682e78af5cc631a0cc06df637901c577e9 Correctly match globs that end in escaped wildcards. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1414 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- diff --git a/ChangeLog b/ChangeLog index d87124e..623f41b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,16 @@ -2005-05-25 Reed Loden +2005-05-30 Michael Poole + + * ircd/match.c (match): Rewrite to handle globs that end in an + escaped wildcard (and hopefully clarify the code). + + * ircd/test/Makefile.in: Add new ircd_match_t test program. + + * ircd/test/ircd_match_t.c: New file. + + * ircd/test/test_stub.c: Emite newlines after log and debug + messages. + +2005-05-25 Reed Loden * ircd/s_err.c (replyTable): Allow for the specification of 'O' or 'o' in RPL_STATSOLINE. diff --git a/ircd/match.c b/ircd/match.c index cd75423..5302018 100644 --- a/ircd/match.c +++ b/ircd/match.c @@ -190,59 +190,56 @@ int match(const char *mask, const char *name) { const char *m = mask, *n = name; const char *m_tmp = mask, *n_tmp = name; - int wild = 0; - - for (;;) - { - if (*m == '*') { - while (*m == '*') /* clean up any additional wildcards */ - m++; - - m_tmp = m; - n_tmp = n; - wild = 1; - } - if (*m == '\\') /* next wildcard is disregarded */ - m++; - - if (!*m) { - if (!*n) - return 0; /* match */ - - for (m--; (m > mask) && (*m == '?'); m--); - ; - - if (*m == '*' && (m > mask)) - return 0; /* match */ - - if (!wild) - return 1; - - m = m_tmp; - n = ++n_tmp; - } - else if (!*n) { - while (*m == '*') /* clean up any additional wildcards */ - m++; + int star_p; - return (*m != 0); - } - if (ToLower(*m) != ToLower(*n) && *m != '?') { - if (!wild) - return 1; /* failure! */ - - m = m_tmp; - n = ++n_tmp; + for (;;) switch (*m) { + case '\0': + if (!*n) + return 0; + backtrack: + if (m_tmp == mask) + return 1; + m = m_tmp; + n = ++n_tmp; + break; + case '\\': + m++; + /* allow escaping to force capitalization */ + if (*m++ != *n++) + return 1; + break; + case '*': case '?': + for (star_p = 0; ; m++) { + if (*m == '*') + star_p = 1; + else if (*m == '?') { + if (!*n++) + goto backtrack; + } else break; } - else { - if (*m) - m++; - if (*n) - n++; + if (star_p) { + if (!*m) + return 0; + else if (*m == '\\') { + m_tmp = ++m; + if (!*m) + return 1; + for (n_tmp = n; *n && *n != *m; n++) ; + } else { + m_tmp = m; + for (n_tmp = n; *n && ToLower(*n) != ToLower(*m); n++) ; + } } + /* and fall through */ + default: + if (!*n) + return *m != '\0'; + if (ToLower(*m) != ToLower(*n)) + goto backtrack; + m++; + n++; + break; } - - return 1; /* no match! */ } /* diff --git a/ircd/test/Makefile.in b/ircd/test/Makefile.in index aa9ecfc..8449b09 100644 --- a/ircd/test/Makefile.in +++ b/ircd/test/Makefile.in @@ -7,12 +7,14 @@ CC = @CC@ TESTPROGS = \ ircd_chattr_t \ - ircd_string_t \ - ircd_in_addr_t + ircd_in_addr_t \ + ircd_match_t \ + ircd_string_t DEP_SRC = \ ircd_chattr_t.c \ ircd_in_addr_t.c \ + ircd_match_t.c \ ircd_string_t.c \ test_stub.c @@ -36,14 +38,18 @@ IRCD_CHATTR_T_OBJS = ircd_chattr_t.o test_stub.o ../ircd_string.o ircd_chattr_t: $(IRCD_CHATTR_T_OBJS) ${CC} -o $@ $(IRCD_CHATTR_T_OBJS) -IRCD_STRING_T_OBJS = ircd_string_t.o test_stub.o ../ircd_string.o -ircd_string_t: $(IRCD_STRING_T_OBJS) - ${CC} -o $@ $(IRCD_STRING_T_OBJS) - IRCD_IN_ADDR_T_OBJS = ircd_in_addr_t.o test_stub.o ../ircd_alloc.o ../ircd_string.o ../match.o ../numnicks.o ircd_in_addr_t: $(IRCD_IN_ADDR_T_OBJS) ${CC} -o $@ $(IRCD_IN_ADDR_T_OBJS) +IRCD_MATCH_T_OBJS = ircd_match_t.o test_stub.o ../ircd_string.o ../match.o +ircd_match_t: $(IRCD_MATCH_T_OBJS) + ${CC} -o $@ $(IRCD_MATCH_T_OBJS) + +IRCD_STRING_T_OBJS = ircd_string_t.o test_stub.o ../ircd_string.o +ircd_string_t: $(IRCD_STRING_T_OBJS) + ${CC} -o $@ $(IRCD_STRING_T_OBJS) + .c.o: ${CC} ${CFLAGS} ${CPPFLAGS} -c $< -o $@ diff --git a/ircd/test/ircd_match_t.c b/ircd/test/ircd_match_t.c new file mode 100644 index 0000000..e051e5f --- /dev/null +++ b/ircd/test/ircd_match_t.c @@ -0,0 +1,74 @@ +/* + * ircd_match_t.c - test cases for irc glob matching + */ + +#include "ircd_log.h" +#include "match.h" +#include +#include + +struct match_test { + const char *glob; + const char *should_match; + const char *shouldnt_match; +}; + +const struct match_test match_tests[] = { + { "\\*", + "*\0", + "a\0*PeacefuL*\0" }, + { "*a*", + "a\0pizza\0abe\0brack\0", + "b\0" }, + { "?", + "*\0a\0?\0", + "*PeacefuL*\0pizza\0???\0" }, + { "abc", + "abc\0", + "abcd\0cabc\0" }, + { "*abc", + "abc\0fooabc\0", + "abra\0abcd\0" }, + { "\\?", + "?\0", + "a\0" }, + { NULL, NULL, NULL } +}; + +void do_match_test(const struct match_test *test) +{ + const char *candidate; + unsigned int matched, not_matched; + int res; + + for (candidate = test->should_match, matched = 0; + *candidate; + candidate += strlen(candidate) + 1, ++matched) { + res = match(test->glob, candidate); + if (res != 0) { + fprintf(stderr, "\"%s\" failed to match \"%s\".\n", test->glob, candidate); + assert(0); + } + } + + for (candidate = test->shouldnt_match, not_matched = 0; + *candidate; + candidate += strlen(candidate) + 1, ++not_matched) { + res = match(test->glob, candidate); + if (res == 0) { + fprintf(stderr, "\"%s\" incorrectly matched \"%s\".\n", test->glob, candidate); + assert(0); + } + } + + printf("Passed: %s (%u matches, %u non-matches)\n", + test->glob, matched, not_matched); +} + +int main(int argc, char *argv[]) +{ + const struct match_test *match; + for (match = match_tests; match->glob; ++match) + do_match_test(match); + return 0; +} diff --git a/ircd/test/test_stub.c b/ircd/test/test_stub.c index aa9227b..e5fe4a4 100644 --- a/ircd/test/test_stub.c +++ b/ircd/test/test_stub.c @@ -17,6 +17,7 @@ log_write(enum LogSys subsys, enum LogLevel severity, unsigned int flags, va_start(args, fmt); vfprintf(stderr, fmt, args); + fputc('\n', stderr); va_end(args); } @@ -27,6 +28,7 @@ debug(int level, const char *form, ...) va_start(args, form); vfprintf(stdout, form, args); + fputc('\n', stdout); va_end(args); }