Leaked source code of windows server 2003
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.

357 lines
11 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Wide Character Routines
  4. // Copyright (C) Microsoft Corporation, 1996, 1997
  5. //
  6. // File: wch.cpp
  7. //
  8. // Contents: Implementation of wide characters routines.
  9. // These routines are being used to avoid dragging in
  10. // the initialisation chunk of the C run-time library
  11. // that would be required by library routines such as
  12. // wcsicmp() etc.
  13. //
  14. //------------------------------------------------------------------------
  15. #include "stdafx.h"
  16. #include "shlwapi.h" // Wrapper routines for non-Win95 calls
  17. #pragma comment(lib, "shlwapi.lib")
  18. //------------------------------------------------------------------------
  19. //
  20. // Function: wch_icmp()
  21. //
  22. // Synopsis: Perform a case-insensitive comparison of two strings.
  23. //
  24. // Arguments: pwch1 First string to compare
  25. // pwch2 Second string to compare
  26. // Treats NULLs as empty strings.
  27. //
  28. // Returns: 0 if the strings are lexically equal (allowing for
  29. // case insensitivity)
  30. // -1 if pwch1 lexically less than pwch2
  31. // +1 if pwch1 lexically greater than pwch2
  32. //
  33. //------------------------------------------------------------------------
  34. int wch_icmp(LPWCH pwch1, LPWCH pwch2)
  35. {
  36. USES_CONVERSION;
  37. if (pwch1 == NULL)
  38. pwch1 = L"";
  39. if (pwch2 == NULL)
  40. pwch2 = L"";
  41. return StrCmpIW(pwch1, pwch2);
  42. }
  43. //------------------------------------------------------------------------
  44. //
  45. // Function: wch_incmp()
  46. //
  47. // Synopsis: Perform a case-insensitive comparison of two strings,
  48. // up to a specified maximum number of characters.
  49. //
  50. // Arguments: pwch1 First string to compare
  51. // pwch2 Second string to compare
  52. // dwMaxLen Maximum number of characters to compare.
  53. //
  54. // Treats NULLs as empty strings.
  55. //
  56. // Returns: 0 if the strings are lexically equal (allowing for
  57. // case insensitivity)
  58. // -1 if pwch1 lexically less than pwch2
  59. // +1 if pwch1 lexically greater than pwch2
  60. //
  61. //------------------------------------------------------------------------
  62. int wch_incmp(LPWCH pwch1, LPWCH pwch2, DWORD dwMaxLen)
  63. {
  64. if (pwch1 == NULL)
  65. pwch1 = L"";
  66. if (pwch2 == NULL)
  67. pwch2 = L"";
  68. return StrCmpNIW(pwch1, pwch2, dwMaxLen);
  69. }
  70. //------------------------------------------------------------------------
  71. //
  72. // Function: wch_len()
  73. //
  74. // Synopsis: Calculate the length of a string.
  75. // Treats NULL as an empty string.
  76. //
  77. // Arguments: pwch String to measure
  78. //
  79. // Returns: Length of given string.
  80. //
  81. //------------------------------------------------------------------------
  82. int wch_len(LPWCH pwch)
  83. {
  84. LPWCH pwchOrig = pwch;
  85. if (pwch == NULL)
  86. return 0;
  87. while (*pwch++ != 0)
  88. ;
  89. return pwch - pwchOrig - 1;
  90. }
  91. //------------------------------------------------------------------------
  92. //
  93. // Function: wch_cmp()
  94. //
  95. // Synopsis: Perform a case-sensitive comparison of two strings.
  96. // Treats NULLs as empty strings.
  97. //
  98. // Arguments: pwch1 First string to compare
  99. // pwch2 Second string to compare
  100. //
  101. // Returns: 0 if the strings are lexically equal
  102. // -1 if pwch1 lexically less than pwch2
  103. // +1 if pwch1 lexically greater than pwch2
  104. //
  105. //------------------------------------------------------------------------
  106. int wch_cmp(LPWCH pwch1, LPWCH pwch2)
  107. {
  108. if (pwch1 == NULL)
  109. pwch1 = L"";
  110. if (pwch2 == NULL)
  111. pwch2 = L"";
  112. for (; *pwch1 != 0 && *pwch1 == *pwch2; pwch1++, pwch2++)
  113. ;
  114. return *pwch1 - *pwch2;
  115. }
  116. //------------------------------------------------------------------------
  117. //
  118. // Function: wch_ncmp()
  119. //
  120. // Synopsis: Perform a case-sensitive comparison of two strings,
  121. // up to a specified maximum number of characters.
  122. //
  123. // Arguments: pwch1 First string to compare
  124. // pwch2 Second string to compare
  125. // dwMaxLen Maximum number of characters to compare.
  126. //
  127. // Treats NULLs as empty strings.
  128. //
  129. // Returns: 0 if the strings are lexically equal (allowing for
  130. // case insensitivity)
  131. // -1 if pwch1 lexically less than pwch2
  132. // +1 if pwch1 lexically greater than pwch2
  133. //
  134. //------------------------------------------------------------------------
  135. int wch_ncmp(LPWCH pwch1, LPWCH pwch2, DWORD dwMaxLen)
  136. {
  137. int cmp;
  138. if (pwch1 == NULL)
  139. pwch1 = L"";
  140. if (pwch2 == NULL)
  141. pwch2 = L"";
  142. for (cmp = 0; cmp == 0 && dwMaxLen-- > 0; pwch1++, pwch2++)
  143. if (*pwch1 == 0)
  144. {
  145. cmp = (*pwch2 == 0) ? 0 : -1;
  146. break;
  147. }
  148. else
  149. cmp = (*pwch2 == 0) ? 1 : (*pwch2 - *pwch1);
  150. return cmp;
  151. }
  152. //------------------------------------------------------------------------
  153. //
  154. // Function: wch_cpy()
  155. //
  156. // Synopsis: Copy a wide-character null-terminated string.
  157. // Treats NULL source as an empty string.
  158. //
  159. // Arguments: pwchDesc Destination buffer.
  160. // pwchSrc Source string.
  161. //
  162. // Returns: Nothing.
  163. //
  164. //------------------------------------------------------------------------
  165. void wch_cpy(LPWCH pwchDest, LPWCH pwchSrc)
  166. {
  167. if (pwchSrc == NULL)
  168. *pwchDest = 0;
  169. else
  170. while ((*pwchDest++ = *pwchSrc++) != 0)
  171. ;
  172. }
  173. //------------------------------------------------------------------------
  174. //
  175. // Function: wch_chr()
  176. //
  177. // Synopsis: Searches for a character in a null-terminated wide-character
  178. // string.
  179. // Treats NULL pwch as an empty string.
  180. //
  181. // Arguments: pwch Search string.
  182. // wch Character to search for.copy.
  183. //
  184. // Returns: Pointer to first occurrence of 'wch' in 'pwch' if found.
  185. // NULL if 'wch' does not occur in 'pwch'.
  186. //
  187. //------------------------------------------------------------------------
  188. LPWCH wch_chr(LPWCH pwch, WCHAR wch)
  189. {
  190. if (pwch != NULL)
  191. for (; *pwch != 0; pwch++)
  192. if (*pwch == wch)
  193. return pwch;
  194. return NULL;
  195. }
  196. //------------------------------------------------------------------------
  197. //
  198. // Function: wch_wildcardMatch()
  199. //
  200. // Synopsis: Determines whether the given text matches the given
  201. // pattern, which interprets the character '*' as a match
  202. // for 0-or-more characters.
  203. // Treats NULL pwchText as an empty string.
  204. // Treats NULL pwchPattern as an empty string.
  205. //
  206. // Arguments: pwchText Text to match.
  207. // pwchPattern Pattern to match against.
  208. // fCaseSensitive Flag to indicate whether match should be
  209. // case sensitive.
  210. //
  211. // Returns: TRUE if the text matches the given pattern.
  212. // FALSE otherwise.
  213. //
  214. //------------------------------------------------------------------------
  215. // ;begin_internal
  216. // compiler bug (VC5 with optimise?)
  217. // ;end_internal
  218. boolean wch_wildcardMatch(LPWCH pwchText, LPWCH pwchPattern,
  219. boolean fCaseSensitive)
  220. {
  221. boolean fMatched;
  222. LPWCH pwchStar;
  223. DWORD dwPatternLen;
  224. if (pwchText == NULL || pwchText[0] == 0)
  225. {
  226. // Empty/NULL text. This matches:
  227. // - Empty/NULL patterns
  228. // - Patterns consisting of a string of '*'s
  229. //
  230. // Equivalently, the text FAILS to match if there
  231. // is at least one non-* character in the pattern.
  232. //
  233. fMatched = TRUE;
  234. if (pwchPattern != NULL)
  235. while (fMatched && *pwchPattern != 0)
  236. fMatched = *pwchPattern++ == L'*';
  237. goto Done;
  238. }
  239. if (pwchPattern == NULL || pwchPattern[0] == 0)
  240. {
  241. // NULL pattern can only match empty text.
  242. // Since we've already dealt with the case of empty text above,
  243. // the match must fail
  244. //
  245. fMatched = FALSE;
  246. goto Done;
  247. }
  248. // Find the occurrence of the first '*' in the pattern ...
  249. //
  250. pwchStar = wch_chr(pwchPattern, L'*');
  251. if (pwchStar == NULL)
  252. {
  253. // No '*'s in the pattern - compute an exact match
  254. //
  255. fMatched = fCaseSensitive
  256. ? wch_cmp(pwchText, pwchPattern) == 0
  257. : wch_icmp(pwchText, pwchPattern) == 0;
  258. goto Done;
  259. }
  260. int (*pfnBufCmp)(LPWCH pwch1, LPWCH pwch2, DWORD dwMaxCmp);
  261. pfnBufCmp = fCaseSensitive ? wch_ncmp : wch_incmp;
  262. // Ensure an exact match for characters preceding the first '*', if any
  263. //
  264. dwPatternLen = pwchStar - pwchPattern;
  265. fMatched = (*pfnBufCmp)(pwchText, pwchPattern, dwPatternLen) == 0;
  266. if (!fMatched)
  267. goto Done;
  268. pwchText += dwPatternLen;
  269. for (;;)
  270. {
  271. DWORD dwTextLen = wch_len(pwchText);
  272. // Skip over leading '*'s in the pattern
  273. //
  274. _ASSERT(*pwchStar == L'*');
  275. while (*pwchStar == L'*')
  276. pwchStar++;
  277. pwchPattern = pwchStar;
  278. // Find the next occurrence of a '*' in the pattern
  279. //
  280. if (*pwchPattern == 0)
  281. {
  282. // This must be have been a trailing '*' in the pattern.
  283. // It automatically matches what remains of the text.
  284. //
  285. fMatched = TRUE;
  286. goto Done;
  287. }
  288. pwchStar = wch_chr(pwchPattern, L'*');
  289. if (pwchStar == NULL)
  290. {
  291. // No more '*'s - require an exact match of remaining
  292. // pattern text with the end of the text.
  293. //
  294. dwPatternLen = wch_len(pwchPattern);
  295. fMatched = (dwTextLen >= dwPatternLen) &&
  296. (*pfnBufCmp)(pwchText + dwTextLen - dwPatternLen,
  297. pwchPattern, dwPatternLen) == 0;
  298. goto Done;
  299. }
  300. // Locate an exact match for the pattern-up-to-next-*
  301. // within the text buffer
  302. //
  303. dwPatternLen = pwchStar - pwchPattern;
  304. fMatched = FALSE;
  305. while (dwTextLen >= dwPatternLen)
  306. {
  307. fMatched = (*pfnBufCmp)(pwchText, pwchPattern, dwPatternLen) == 0;
  308. if (fMatched)
  309. break;
  310. dwTextLen--;
  311. pwchText++;
  312. }
  313. if (!fMatched)
  314. goto Done;
  315. pwchText += dwPatternLen;
  316. }
  317. Done:
  318. return fMatched;
  319. }