Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
3.4 KiB

  1. //***************************************************************************
  2. //
  3. // (c) 2000-2001 by Microsoft Corp. All Rights Reserved.
  4. //
  5. // like.cpp
  6. //
  7. // a-davcoo 28-Feb-00 Implements the SQL like operation.
  8. //
  9. //***************************************************************************
  10. #include "precomp.h"
  11. #include "like.h"
  12. #include "corex.h"
  13. #define WILDCARD L'%'
  14. #define ANYSINGLECHAR L'_'
  15. CLike::CLike (LPCWSTR expression, WCHAR escape)
  16. : m_expression(NULL)
  17. {
  18. SetExpression( expression, escape );
  19. }
  20. CLike& CLike::operator=( const CLike& rOther )
  21. {
  22. if ( rOther.m_expression != NULL )
  23. {
  24. SetExpression( rOther.m_expression, rOther.m_escape );
  25. }
  26. else
  27. {
  28. delete [] m_expression;
  29. m_expression = NULL;
  30. }
  31. return *this;
  32. }
  33. CLike::~CLike (void)
  34. {
  35. delete [] m_expression;
  36. }
  37. void CLike::SetExpression( LPCWSTR string, WCHAR escape )
  38. {
  39. delete [] m_expression;
  40. m_expression = new WCHAR[wcslen(string)+1];
  41. if ( m_expression == NULL )
  42. {
  43. throw CX_MemoryException();
  44. }
  45. wcscpy( m_expression, string );
  46. m_escape = escape;
  47. }
  48. bool CLike::Match( LPCWSTR string )
  49. {
  50. bool bRes;
  51. if ( m_expression != NULL )
  52. {
  53. bRes = DoLike( m_expression, string, m_escape );
  54. }
  55. else
  56. {
  57. bRes = false;
  58. }
  59. return bRes;
  60. }
  61. bool CLike::DoLike (LPCWSTR pattern, LPCWSTR string, WCHAR escape)
  62. {
  63. bool like=false;
  64. while (!like && *pattern && *string)
  65. {
  66. // Wildcard match.
  67. if (*pattern==WILDCARD)
  68. {
  69. pattern++;
  70. do
  71. {
  72. like=DoLike (pattern, string, escape);
  73. if (!like) string++;
  74. }
  75. while (*string && !like);
  76. }
  77. // Set match.
  78. else if (*pattern=='[')
  79. {
  80. int skip;
  81. if (MatchSet (pattern, string, skip))
  82. {
  83. pattern+=skip;
  84. string++;
  85. }
  86. else
  87. {
  88. break;
  89. }
  90. }
  91. // Single character match.
  92. else
  93. {
  94. if (escape!='\0' && *pattern==escape) pattern++;
  95. if (towupper(*pattern)==towupper(*string) || *pattern==ANYSINGLECHAR)
  96. {
  97. pattern++;
  98. string++;
  99. }
  100. else
  101. {
  102. break;
  103. }
  104. }
  105. }
  106. // Skip any trailing wildcard characters.
  107. while (*pattern==WILDCARD) pattern++;
  108. // It's a match if we reached the end of both strings, or a recursion
  109. // succeeded.
  110. return (!(*pattern) && !(*string)) || like;
  111. }
  112. bool CLike::MatchSet (LPCWSTR pattern, LPCWSTR string, int &skip)
  113. {
  114. // Skip the opening '['.
  115. LPCWSTR pos=pattern+1;
  116. // See if we are matching a [^] set.
  117. bool notinset=(*pos=='^');
  118. if (notinset) pos++;
  119. // See if the target character matches any character in the set.
  120. bool matched=false;
  121. WCHAR lastchar='\0';
  122. while (*pos && *pos!=']' && !matched)
  123. {
  124. // A range of characters is indicated by a '-' unless it's the first
  125. // character in the set (in which case it's just a character to be
  126. // matched.
  127. if (*pos=='-' && lastchar!='\0')
  128. {
  129. pos++;
  130. if (*pos && *pos!=']')
  131. {
  132. matched=(towupper(*string)>=lastchar && towupper(*string)<=towupper(*pos));
  133. lastchar=towupper(*pos);
  134. pos++;
  135. }
  136. }
  137. else
  138. {
  139. // Match a normal character in the set.
  140. lastchar=towupper(*pos);
  141. matched=(towupper(*pos)==towupper(*string));
  142. if (!matched) pos++;
  143. }
  144. }
  145. // Skip the trailing ']'. If the set did not contain a closing ']'
  146. // we return a failed match.
  147. while (*pos && *pos!=']') pos++;
  148. if (*pos==']') pos++;
  149. if (!*pos) matched=false;
  150. // Done.
  151. skip=(int)(pos-pattern);
  152. return matched==!notinset;
  153. }