//*************************************************************************** // // (c) 2000 by Microsoft Corp. All Rights Reserved. // // like.cpp // // a-davcoo 28-Feb-00 Implements the SQL like operation. // //*************************************************************************** #include "precomp.h" #include "like.h" #define WILDCARD L'%' #define ANYSINGLECHAR L'_' CLike::CLike (LPCWSTR expression, WCHAR escape) { m_expression=new WCHAR[wcslen(expression)+1]; if(m_expression) wcscpy (m_expression, expression); m_escape=escape; } CLike::~CLike (void) { delete [] m_expression; } bool CLike::Match (LPCWSTR string) { // m_expression might be NULL in out-of-memory return DoLike (m_expression, string, m_escape); } bool CLike::DoLike (LPCWSTR pattern, LPCWSTR string, WCHAR escape) { // pattern might be NULL in out-of-memory if(pattern == NULL) return false; bool like=false; while (!like && *pattern && *string) { // Wildcard match. if (*pattern==WILDCARD) { pattern++; do { like=DoLike (pattern, string, escape); if (!like) string++; } while (*string && !like); } // Set match. else if (*pattern=='[') { int skip; if (MatchSet (pattern, string, skip)) { pattern+=skip; string++; } else { break; } } // Single character match. else { if (escape!='\0' && *pattern==escape) pattern++; if (towupper(*pattern)==towupper(*string) || *pattern==ANYSINGLECHAR) { pattern++; string++; } else { break; } } } // Skip any trailing wildcard characters. while (*pattern==WILDCARD) pattern++; // It's a match if we reached the end of both strings, or a recursion // succeeded. return (!(*pattern) && !(*string)) || like; } bool CLike::MatchSet (LPCWSTR pattern, LPCWSTR string, int &skip) { // Skip the opening '['. LPCWSTR pos=pattern+1; // See if we are matching a [^] set. bool notinset=(*pos=='^'); if (notinset) pos++; // See if the target character matches any character in the set. bool matched=false; WCHAR lastchar='\0'; while (*pos && *pos!=']' && !matched) { // A range of characters is indicated by a '-' unless it's the first // character in the set (in which case it's just a character to be // matched. if (*pos=='-' && lastchar!='\0') { pos++; if (*pos && *pos!=']') { matched=(towupper(*string)>=lastchar && towupper(*string)<=towupper(*pos)); lastchar=towupper(*pos); pos++; } } else { // Match a normal character in the set. lastchar=towupper(*pos); matched=(towupper(*pos)==towupper(*string)); if (!matched) pos++; } } // Skip the trailing ']'. If the set did not contain a closing ']' // we return a failed match. while (*pos && *pos!=']') pos++; if (*pos==']') pos++; if (!*pos) matched=false; // Done. skip=(int)(pos-pattern); return matched==!notinset; }