diff options
author | Robert Vollmert <rvollmert@gmx.net> | 2010-01-20 15:44:40 +0100 |
---|---|---|
committer | Robert Vollmert <rvollmert@gmx.net> | 2010-01-20 17:08:01 +0100 |
commit | 623638dc03d8f233cd80eec9d6de30a504fe64ca (patch) | |
tree | 77b36234895ac50872185e31aa10fd2fdd6d95b6 /crawl-ref/source/pattern.cc | |
parent | 1f4b2d5d177fb670f9ff22a146ebf806f7f92d72 (diff) | |
download | crawl-ref-623638dc03d8f233cd80eec9d6de30a504fe64ca.tar.gz crawl-ref-623638dc03d8f233cd80eec9d6de30a504fe64ca.zip |
Extract pattern templates to pattern.h.
Diffstat (limited to 'crawl-ref/source/pattern.cc')
-rw-r--r-- | crawl-ref/source/pattern.cc | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/crawl-ref/source/pattern.cc b/crawl-ref/source/pattern.cc new file mode 100644 index 0000000000..96662986d0 --- /dev/null +++ b/crawl-ref/source/pattern.cc @@ -0,0 +1,174 @@ +#include "AppHdr.h" + +#include "pattern.h" + +/////////////////////////////////////////////////////////////////////// +// Pattern matching + +inline int pm_lower(int ch, bool icase) +{ + return icase? tolower(ch) : ch; +} + +// Determines whether the pattern specified by 'pattern' matches the given +// text. A pattern is a simple glob, with the traditional * and ? wildcards. +static bool glob_match( const char *pattern, const char *text, bool icase ) +{ + char p, t; + bool special; + + while (true) + { + p = pm_lower(*pattern++, icase); + t = pm_lower(*text++, icase); + special = true; + + if (!p) + return (t == 0); + + if (p == '\\' && *pattern) + { + p = pm_lower(*pattern++, icase); + special = false; + } + + if (p == '*' && special) + { + // Try to match exactly at the current text position... + if (!*pattern || glob_match(pattern, text - 1, icase)) + return (true); + + // Or skip one character in the text and try the wildcard match + // again. If this is the end of the text, the match has failed. + return (t ? glob_match(pattern - 1, text, icase) : false); + } + else if (!t || p != t && (p != '?' || !special)) + return (false); + } +} + +//////////////////////////////////////////////////////////////////// +// Basic glob (always available) + +struct glob_info +{ + std::string s; + bool ignore_case; +}; + +void *compile_glob_pattern(const char *pattern, bool icase) +{ + // If we're using simple globs, we need to box the pattern with '*' + std::string s = std::string("*") + pattern + "*"; + glob_info *gi = new glob_info; + if (gi) + { + gi->s = s; + gi->ignore_case = icase; + } + return gi; +} + +void free_compiled_glob_pattern(void *compiled_pattern) +{ + delete static_cast<glob_info *>( compiled_pattern ); +} + +bool glob_pattern_match(void *compiled_pattern, const char *text, int length) +{ + glob_info *gi = static_cast<glob_info *>( compiled_pattern ); + return glob_match(gi->s.c_str(), text, gi->ignore_case); +} +//////////////////////////////////////////////////////////////////// + +#if defined(REGEX_PCRE) +//////////////////////////////////////////////////////////////////// +// Perl Compatible Regular Expressions + +void *compile_pattern(const char *pattern, bool icase) +{ + const char *error; + int erroffset; + int flags = icase? PCRE_CASELESS : 0; + return pcre_compile(pattern, + flags, + &error, + &erroffset, + NULL); +} + +void free_compiled_pattern(void *cp) +{ + if (cp) + pcre_free(cp); +} + +bool pattern_match(void *compiled_pattern, const char *text, int length) +{ + int ovector[42]; + int pcre_rc = pcre_exec(static_cast<pcre *>(compiled_pattern), + NULL, + text, length, 0, 0, + ovector, sizeof(ovector) / sizeof(*ovector)); + return (pcre_rc >= 0); +} + +//////////////////////////////////////////////////////////////////// +#elif defined(REGEX_POSIX) +//////////////////////////////////////////////////////////////////// +// POSIX regular expressions + +void *compile_pattern(const char *pattern, bool icase) +{ + regex_t *re = new regex_t; + if (!re) + return NULL; + + int flags = REG_EXTENDED | REG_NOSUB; + if (icase) + flags |= REG_ICASE; + int rc = regcomp(re, pattern, flags); + // Nonzero return code == failure + if (rc) + { + delete re; + return NULL; + } + return re; +} + +void free_compiled_pattern(void *cp) +{ + if (cp) + { + regex_t *re = static_cast<regex_t *>( cp ); + regfree(re); + delete re; + } +} + +bool pattern_match(void *compiled_pattern, const char *text, int length) +{ + regex_t *re = static_cast<regex_t *>( compiled_pattern ); + return !regexec(re, text, 0, NULL, 0); +} + +//////////////////////////////////////////////////////////////////// +#else + +void *compile_pattern(const char *pattern, bool icase) +{ + return compile_glob_pattern(pattern, icase); +} + +void free_compiled_pattern(void *cp) +{ + free_compiled_glob_pattern(cp); +} + +bool pattern_match(void *compiled_pattern, const char *text, int length) +{ + return glob_pattern_match(compiled_pattern, text, length); +} + +#endif |