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.

148 lines
2.9 KiB

  1. //***************************************************************************
  2. //
  3. // (c) 2000 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. #define WILDCARD L'%'
  13. #define ANYSINGLECHAR L'_'
  14. CLike::CLike (LPCWSTR expression, WCHAR escape)
  15. {
  16. m_expression=new WCHAR[wcslen(expression)+1];
  17. if(m_expression)
  18. wcscpy (m_expression, expression);
  19. m_escape=escape;
  20. }
  21. CLike::~CLike (void)
  22. {
  23. delete [] m_expression;
  24. }
  25. bool CLike::Match (LPCWSTR string)
  26. {
  27. // m_expression might be NULL in out-of-memory
  28. return DoLike (m_expression, string, m_escape);
  29. }
  30. bool CLike::DoLike (LPCWSTR pattern, LPCWSTR string, WCHAR escape)
  31. {
  32. // pattern might be NULL in out-of-memory
  33. if(pattern == NULL)
  34. return false;
  35. bool like=false;
  36. while (!like && *pattern && *string)
  37. {
  38. // Wildcard match.
  39. if (*pattern==WILDCARD)
  40. {
  41. pattern++;
  42. do
  43. {
  44. like=DoLike (pattern, string, escape);
  45. if (!like) string++;
  46. }
  47. while (*string && !like);
  48. }
  49. // Set match.
  50. else if (*pattern=='[')
  51. {
  52. int skip;
  53. if (MatchSet (pattern, string, skip))
  54. {
  55. pattern+=skip;
  56. string++;
  57. }
  58. else
  59. {
  60. break;
  61. }
  62. }
  63. // Single character match.
  64. else
  65. {
  66. if (escape!='\0' && *pattern==escape) pattern++;
  67. if (towupper(*pattern)==towupper(*string) || *pattern==ANYSINGLECHAR)
  68. {
  69. pattern++;
  70. string++;
  71. }
  72. else
  73. {
  74. break;
  75. }
  76. }
  77. }
  78. // Skip any trailing wildcard characters.
  79. while (*pattern==WILDCARD) pattern++;
  80. // It's a match if we reached the end of both strings, or a recursion
  81. // succeeded.
  82. return (!(*pattern) && !(*string)) || like;
  83. }
  84. bool CLike::MatchSet (LPCWSTR pattern, LPCWSTR string, int &skip)
  85. {
  86. // Skip the opening '['.
  87. LPCWSTR pos=pattern+1;
  88. // See if we are matching a [^] set.
  89. bool notinset=(*pos=='^');
  90. if (notinset) pos++;
  91. // See if the target character matches any character in the set.
  92. bool matched=false;
  93. WCHAR lastchar='\0';
  94. while (*pos && *pos!=']' && !matched)
  95. {
  96. // A range of characters is indicated by a '-' unless it's the first
  97. // character in the set (in which case it's just a character to be
  98. // matched.
  99. if (*pos=='-' && lastchar!='\0')
  100. {
  101. pos++;
  102. if (*pos && *pos!=']')
  103. {
  104. matched=(towupper(*string)>=lastchar && towupper(*string)<=towupper(*pos));
  105. lastchar=towupper(*pos);
  106. pos++;
  107. }
  108. }
  109. else
  110. {
  111. // Match a normal character in the set.
  112. lastchar=towupper(*pos);
  113. matched=(towupper(*pos)==towupper(*string));
  114. if (!matched) pos++;
  115. }
  116. }
  117. // Skip the trailing ']'. If the set did not contain a closing ']'
  118. // we return a failed match.
  119. while (*pos && *pos!=']') pos++;
  120. if (*pos==']') pos++;
  121. if (!*pos) matched=false;
  122. // Done.
  123. skip=(int)(pos-pattern);
  124. return matched==!notinset;
  125. }