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.

808 lines
21 KiB

  1. //============================================================================
  2. //
  3. // DBCS aware string routines...
  4. //
  5. //
  6. //============================================================================
  7. #include "ctlspriv.h"
  8. #include <winnlsp.h> // Get private NORM_ flag for StrEqIntl()
  9. // for those of us who don't ssync to nt's build headers
  10. #ifndef NORM_STOP_ON_NULL
  11. #define NORM_STOP_ON_NULL 0x10000000
  12. #endif
  13. // WARNING: all of these APIs do not setup DS, so you can not access
  14. // any data in the default data seg of this DLL.
  15. //
  16. // do not create any global variables... talk to chrisg if you don't
  17. // understand thid
  18. #define READNATIVEWORD(x) (*(UNALIGNED WORD *)x)
  19. /*
  20. * StrEndN - Find the end of a string, but no more than n bytes
  21. * Assumes lpStart points to start of null terminated string
  22. * nBufSize is the maximum length
  23. * returns ptr to just after the last byte to be included
  24. */
  25. LPSTR lstrfns_StrEndNA(LPCSTR lpStart, int nBufSize)
  26. {
  27. LPCSTR lpEnd;
  28. for (lpEnd = lpStart + nBufSize; *lpStart && OFFSETOF(lpStart) < OFFSETOF(lpEnd);
  29. lpStart = AnsiNext(lpStart))
  30. continue; /* just getting to the end of the string */
  31. if (OFFSETOF(lpStart) > OFFSETOF(lpEnd))
  32. {
  33. /* We can only get here if the last byte before lpEnd was a lead byte
  34. */
  35. lpStart -= 2;
  36. }
  37. return((LPSTR)lpStart);
  38. }
  39. LPWSTR lstrfns_StrEndNW(LPCWSTR lpStart, int nBufSize)
  40. {
  41. LPCWSTR lpEnd;
  42. for (lpEnd = lpStart + nBufSize; *lpStart && (lpStart < lpEnd);
  43. lpStart++)
  44. continue; /* just getting to the end of the string */
  45. return((LPWSTR)lpStart);
  46. }
  47. /*
  48. * ChrCmp - Case sensitive character comparison for DBCS
  49. * Assumes w1, wMatch are characters to be compared
  50. * Return FALSE if they match, TRUE if no match
  51. */
  52. __inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
  53. {
  54. /* Most of the time this won't match, so test it first for speed.
  55. */
  56. if (LOBYTE(w1) == LOBYTE(wMatch))
  57. {
  58. if (IsDBCSLeadByte(LOBYTE(w1)))
  59. {
  60. return(w1 != wMatch);
  61. }
  62. return FALSE;
  63. }
  64. return TRUE;
  65. }
  66. __inline BOOL ChrCmpW_inline(WCHAR w1, WCHAR wMatch)
  67. {
  68. return(!(w1 == wMatch));
  69. }
  70. /*
  71. * ChrCmpI - Case insensitive character comparison for DBCS
  72. * Assumes w1, wMatch are characters to be compared;
  73. * HIBYTE of wMatch is 0 if not a DBC
  74. * Return FALSE if match, TRUE if not
  75. */
  76. BOOL ChrCmpIA(WORD w1, WORD wMatch)
  77. {
  78. char sz1[3], sz2[3];
  79. if (IsDBCSLeadByte(sz1[0] = LOBYTE(w1)))
  80. {
  81. sz1[1] = HIBYTE(w1);
  82. sz1[2] = '\0';
  83. }
  84. else
  85. sz1[1] = '\0';
  86. #if defined(BIG_ENDIAN)
  87. sz2[0] = LOBYTE(wMatch);
  88. sz2[1] = HIBYTE(wMatch);
  89. #else
  90. *(WORD FAR *)sz2 = wMatch;
  91. #endif
  92. sz2[2] = '\0';
  93. return lstrcmpiA(sz1, sz2);
  94. }
  95. BOOL ChrCmpIW(WCHAR w1, WCHAR wMatch)
  96. {
  97. WCHAR sz1[2], sz2[2];
  98. sz1[0] = w1;
  99. sz1[1] = TEXT('\0');
  100. sz2[0] = wMatch;
  101. sz2[1] = TEXT('\0');
  102. return lstrcmpiW(sz1, sz2);
  103. }
  104. LPWSTR StrCpyNW(LPWSTR psz1, LPCWSTR psz2, int cchMax)
  105. {
  106. LPWSTR psz = psz1;
  107. ASSERT(psz1);
  108. ASSERT(psz2);
  109. if (0 < cchMax)
  110. {
  111. // Leave room for the null terminator
  112. while (0 < --cchMax)
  113. {
  114. if ( !(*psz1++ = *psz2++) )
  115. break;
  116. }
  117. if (0 == cchMax)
  118. *psz1 = '\0';
  119. }
  120. return psz;
  121. }
  122. /*
  123. * StrChr - Find first occurrence of character in string
  124. * Assumes lpStart points to start of null terminated string
  125. * wMatch is the character to match
  126. * returns ptr to the first occurrence of ch in str, NULL if not found.
  127. */
  128. LPSTR FAR PASCAL StrChrA(LPCSTR lpStart, WORD wMatch)
  129. {
  130. for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  131. {
  132. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  133. {
  134. return((LPSTR)lpStart);
  135. }
  136. }
  137. return (NULL);
  138. }
  139. #ifdef ALIGNMENT_SCENARIO
  140. LPWSTR StrChrSlowW(const UNALIGNED WCHAR *lpStart, WCHAR wMatch)
  141. {
  142. for ( ; *lpStart; lpStart++)
  143. {
  144. if (!ChrCmpW_inline(*lpStart, wMatch))
  145. {
  146. return((LPWSTR)lpStart);
  147. }
  148. }
  149. return NULL;
  150. }
  151. #endif
  152. LPWSTR FAR PASCAL StrChrW(LPCWSTR lpStart, WCHAR wMatch)
  153. {
  154. //
  155. // BUGBUG raymondc
  156. // Apparently, somebody is passing unaligned strings to StrChrW.
  157. // Find out who and make them stop.
  158. //
  159. ASSERT(!((ULONG_PTR)lpStart & 1)); // Assert alignedness
  160. #ifdef ALIGNMENT_SCENARIO
  161. //
  162. // Since unaligned strings arrive so rarely, put the slow
  163. // version in a separate function so the common case stays
  164. // fast. Believe it or not, we call StrChrW so often that
  165. // it is now a performance-sensitive function!
  166. //
  167. if ((ULONG_PTR)lpStart & 1)
  168. return StrChrSlowW(lpStart, wMatch);
  169. #endif
  170. for ( ; *lpStart; lpStart++)
  171. {
  172. if (!ChrCmpW_inline(*lpStart, wMatch))
  173. {
  174. return((LPWSTR)lpStart);
  175. }
  176. }
  177. return (NULL);
  178. }
  179. /*
  180. * StrRChr - Find last occurrence of character in string
  181. * Assumes lpStart points to start of string
  182. * lpEnd points to end of string (NOT included in search)
  183. * wMatch is the character to match
  184. * returns ptr to the last occurrence of ch in str, NULL if not found.
  185. */
  186. LPSTR FAR PASCAL StrRChrA(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  187. {
  188. LPCSTR lpFound = NULL;
  189. if (!lpEnd)
  190. lpEnd = lpStart + lstrlenA(lpStart);
  191. for ( ; OFFSETOF(lpStart) < OFFSETOF(lpEnd); lpStart = AnsiNext(lpStart))
  192. {
  193. if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  194. lpFound = lpStart;
  195. }
  196. return ((LPSTR)lpFound);
  197. }
  198. LPWSTR FAR PASCAL StrRChrW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch)
  199. {
  200. LPCWSTR lpFound = NULL;
  201. if (!lpEnd)
  202. lpEnd = lpStart + lstrlenW(lpStart);
  203. for ( ; lpStart < lpEnd; lpStart++)
  204. {
  205. if (!ChrCmpW_inline(*lpStart, wMatch))
  206. lpFound = lpStart;
  207. }
  208. return ((LPWSTR)lpFound);
  209. }
  210. /*
  211. * StrRChrI - Find last occurrence of character in string, case insensitive
  212. * Assumes lpStart points to start of string
  213. * lpEnd points to end of string (NOT included in search)
  214. * wMatch is the character to match
  215. * returns ptr to the last occurrence of ch in str, NULL if not found.
  216. */
  217. LPSTR FAR PASCAL StrRChrIA(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  218. {
  219. LPCSTR lpFound = NULL;
  220. if (!lpEnd)
  221. lpEnd = lpStart + lstrlenA(lpStart);
  222. wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  223. for ( ; OFFSETOF(lpStart) < OFFSETOF(lpEnd); lpStart = AnsiNext(lpStart))
  224. {
  225. if (!ChrCmpIA(READNATIVEWORD(lpStart), wMatch))
  226. lpFound = lpStart;
  227. }
  228. return ((LPSTR)lpFound);
  229. }
  230. LPWSTR FAR PASCAL StrRChrIW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch)
  231. {
  232. LPCWSTR lpFound = NULL;
  233. if (!lpEnd)
  234. lpEnd = lpStart + lstrlenW(lpStart);
  235. for ( ; lpStart < lpEnd; lpStart++)
  236. {
  237. if (!ChrCmpIW(*lpStart, wMatch))
  238. lpFound = lpStart;
  239. }
  240. return ((LPWSTR)lpFound);
  241. }
  242. // StrCSpn: return index to first char of lpStr that is present in lpSet.
  243. // Includes the NUL in the comparison; if no lpSet chars are found, returns
  244. // the index to the NUL in lpStr.
  245. // Just like CRT strcspn.
  246. //
  247. int FAR PASCAL StrCSpnA(LPCSTR lpStr, LPCSTR lpSet)
  248. {
  249. // nature of the beast: O(lpStr*lpSet) work
  250. LPCSTR lp = lpStr;
  251. if (!lpStr || !lpSet)
  252. return 0;
  253. while (*lp)
  254. {
  255. if (StrChrA(lpSet, READNATIVEWORD(lp)))
  256. return (int)(lp-lpStr);
  257. lp = AnsiNext(lp);
  258. }
  259. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  260. }
  261. int FAR PASCAL StrCSpnW(LPCWSTR lpStr, LPCWSTR lpSet)
  262. {
  263. // nature of the beast: O(lpStr*lpSet) work
  264. LPCWSTR lp = lpStr;
  265. if (!lpStr || !lpSet)
  266. return 0;
  267. while (*lp)
  268. {
  269. if (StrChrW(lpSet, *lp))
  270. return (int)(lp-lpStr);
  271. lp++;
  272. }
  273. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  274. }
  275. // StrCSpnI: case-insensitive version of StrCSpn.
  276. //
  277. int FAR PASCAL StrCSpnIA(LPCSTR lpStr, LPCSTR lpSet)
  278. {
  279. // nature of the beast: O(lpStr*lpSet) work
  280. LPCSTR lp = lpStr;
  281. if (!lpStr || !lpSet)
  282. return 0;
  283. while (*lp)
  284. {
  285. if (StrChrIA(lpSet, READNATIVEWORD(lp)))
  286. return (int)(lp-lpStr);
  287. lp = AnsiNext(lp);
  288. }
  289. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  290. }
  291. int FAR PASCAL StrCSpnIW(LPCWSTR lpStr, LPCWSTR lpSet)
  292. {
  293. // nature of the beast: O(lpStr*lpSet) work
  294. LPCWSTR lp = lpStr;
  295. if (!lpStr || !lpSet)
  296. return 0;
  297. while (*lp)
  298. {
  299. if (StrChrIW(lpSet, *lp))
  300. return (int)(lp-lpStr);
  301. lp++;
  302. }
  303. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  304. }
  305. /*
  306. * StrCmpN - Compare n bytes
  307. *
  308. * returns See lstrcmp return values.
  309. * BUGBUG, won't work if source strings are in ROM
  310. */
  311. int FAR PASCAL StrCmpNA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  312. {
  313. char sz1[4];
  314. char sz2[4];
  315. LPCSTR lpszEnd = lpStr1 + nChar;
  316. //DebugMsg(DM_TRACE, "StrCmpN: %s %s %d returns:", lpStr1, lpStr2, nChar);
  317. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1 = AnsiNext(lpStr1), lpStr2 = AnsiNext(lpStr2)) {
  318. WORD wMatch;
  319. wMatch = (WORD) (*lpStr2 | (*(lpStr2+1)<<8));
  320. if (ChrCmpA_inline(READNATIVEWORD(lpStr1), wMatch)) {
  321. int iRet;
  322. (*(WORD FAR *)sz1) = READNATIVEWORD(lpStr1);
  323. (*(WORD FAR *)sz2) = wMatch;
  324. *AnsiNext(sz1) = 0;
  325. *AnsiNext(sz2) = 0;
  326. iRet = lstrcmpA(sz1, sz2);
  327. //DebugMsg(DM_TRACE, ".................... %d", iRet);
  328. return iRet;
  329. }
  330. }
  331. //DebugMsg(DM_TRACE, ".................... 0");
  332. return 0;
  333. }
  334. int FAR PASCAL StrCmpNW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  335. {
  336. WCHAR sz1[2];
  337. WCHAR sz2[2];
  338. int i;
  339. LPCWSTR lpszEnd = lpStr1 + nChar;
  340. //DebugMsg(DM_TRACE, "StrCmpN: %s %s %d returns:", lpStr1, lpStr2, nChar);
  341. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1++, lpStr2++) {
  342. i = ChrCmpW_inline(*lpStr1, *lpStr2);
  343. if (i) {
  344. int iRet;
  345. sz1[0] = *lpStr1;
  346. sz2[0] = *lpStr2;
  347. sz1[1] = TEXT('\0');
  348. sz2[1] = TEXT('\0');
  349. iRet = lstrcmpW(sz1, sz2);
  350. //DebugMsg(DM_TRACE, ".................... %d", iRet);
  351. return iRet;
  352. }
  353. }
  354. //DebugMsg(DM_TRACE, ".................... 0");
  355. return 0;
  356. }
  357. /*
  358. * StrCmpNI - Compare n bytes, case insensitive
  359. *
  360. * returns See lstrcmpi return values.
  361. */
  362. int StrCmpNIA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  363. {
  364. int i;
  365. // Win95 doesn't support NORM_STOP_ON_NULL
  366. i = CompareStringA(GetThreadLocale(), NORM_IGNORECASE | NORM_STOP_ON_NULL,
  367. lpStr1, nChar, lpStr2, nChar);
  368. if (!i)
  369. {
  370. i = CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE | NORM_STOP_ON_NULL,
  371. lpStr1, nChar, lpStr2, nChar);
  372. }
  373. return i - CSTR_EQUAL;
  374. }
  375. int StrCmpNIW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  376. {
  377. int i;
  378. // Win95 doesn't support NORM_STOP_ON_NULL
  379. i = CompareStringW(GetThreadLocale(), NORM_IGNORECASE | NORM_STOP_ON_NULL,
  380. lpStr1, nChar, lpStr2, nChar);
  381. if (!i)
  382. {
  383. i = CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE | NORM_STOP_ON_NULL,
  384. lpStr1, nChar, lpStr2, nChar);
  385. }
  386. return i - CSTR_EQUAL;
  387. }
  388. /*
  389. * IntlStrEq
  390. *
  391. * returns TRUE if strings are equal, FALSE if not
  392. */
  393. BOOL IntlStrEqWorkerA(BOOL fCaseSens, LPCSTR lpString1, LPCSTR lpString2, int nChar) {
  394. int retval;
  395. DWORD dwFlags = fCaseSens ? LOCALE_USE_CP_ACP : (NORM_IGNORECASE | LOCALE_USE_CP_ACP);
  396. //
  397. // On NT we can tell CompareString to stop at a '\0' if one is found before nChar chars
  398. //
  399. dwFlags |= NORM_STOP_ON_NULL;
  400. retval = CompareStringA( GetThreadLocale(),
  401. dwFlags,
  402. lpString1,
  403. nChar,
  404. lpString2,
  405. nChar );
  406. if (retval == 0)
  407. {
  408. //
  409. // The caller is not expecting failure. Try the system
  410. // default locale id.
  411. //
  412. retval = CompareStringA( GetSystemDefaultLCID(),
  413. dwFlags,
  414. lpString1,
  415. nChar,
  416. lpString2,
  417. nChar );
  418. }
  419. if (retval == 0)
  420. {
  421. if (lpString1 && lpString2)
  422. {
  423. //
  424. // The caller is not expecting failure. We've never had a
  425. // failure indicator before. We'll do a best guess by calling
  426. // the C runtimes to do a non-locale sensitive compare.
  427. //
  428. if (fCaseSens)
  429. retval = StrCmpNA(lpString1, lpString2, nChar) + 2;
  430. else {
  431. retval = StrCmpNIA(lpString1, lpString2, nChar) + 2;
  432. }
  433. }
  434. else
  435. {
  436. retval = 2;
  437. }
  438. }
  439. return (retval == 2);
  440. }
  441. BOOL IntlStrEqWorkerW(BOOL fCaseSens, LPCWSTR lpString1, LPCWSTR lpString2, int nChar) {
  442. int retval;
  443. DWORD dwFlags = fCaseSens ? 0 : NORM_IGNORECASE;
  444. //
  445. // On NT we can tell CompareString to stop at a '\0' if one is found before nChar chars
  446. //
  447. dwFlags |= NORM_STOP_ON_NULL;
  448. retval = CompareStringW( GetThreadLocale(),
  449. dwFlags,
  450. lpString1,
  451. nChar,
  452. lpString2,
  453. nChar );
  454. if (retval == 0)
  455. {
  456. //
  457. // The caller is not expecting failure. Try the system
  458. // default locale id.
  459. //
  460. retval = CompareStringW( GetSystemDefaultLCID(),
  461. dwFlags,
  462. lpString1,
  463. nChar,
  464. lpString2,
  465. nChar );
  466. }
  467. if (retval == 0)
  468. {
  469. if (lpString1 && lpString2)
  470. {
  471. //
  472. // The caller is not expecting failure. We've never had a
  473. // failure indicator before. We'll do a best guess by calling
  474. // the C runtimes to do a non-locale sensitive compare.
  475. //
  476. if (fCaseSens)
  477. retval = StrCmpNW(lpString1, lpString2, nChar) + 2;
  478. else {
  479. retval = StrCmpNIW(lpString1, lpString2, nChar) + 2;
  480. }
  481. }
  482. else
  483. {
  484. retval = 2;
  485. }
  486. }
  487. return (retval == 2);
  488. }
  489. /*
  490. * StrRStrI - Search for last occurrence of a substring
  491. *
  492. * Assumes lpSource points to the null terminated source string
  493. * lpLast points to where to search from in the source string
  494. * lpLast is not included in the search
  495. * lpSrch points to string to search for
  496. * returns last occurrence of string if successful; NULL otherwise
  497. */
  498. LPSTR FAR PASCAL StrRStrIA(LPCSTR lpSource, LPCSTR lpLast, LPCSTR lpSrch)
  499. {
  500. LPCSTR lpFound = NULL;
  501. LPSTR lpEnd;
  502. char cHold;
  503. if (!lpLast)
  504. lpLast = lpSource + lstrlenA(lpSource);
  505. if (lpSource >= lpLast || *lpSrch == 0)
  506. return NULL;
  507. lpEnd = lstrfns_StrEndNA(lpLast, (UINT)(lstrlenA(lpSrch)-1));
  508. cHold = *lpEnd;
  509. *lpEnd = 0;
  510. while ((lpSource = StrStrIA(lpSource, lpSrch))!=0 &&
  511. OFFSETOF(lpSource) < OFFSETOF(lpLast))
  512. {
  513. lpFound = lpSource;
  514. lpSource = AnsiNext(lpSource);
  515. }
  516. *lpEnd = cHold;
  517. return((LPSTR)lpFound);
  518. }
  519. LPWSTR FAR PASCAL StrRStrIW(LPCWSTR lpSource, LPCWSTR lpLast, LPCWSTR lpSrch)
  520. {
  521. LPCWSTR lpFound = NULL;
  522. LPWSTR lpEnd;
  523. WCHAR cHold;
  524. if (!lpLast)
  525. lpLast = lpSource + lstrlenW(lpSource);
  526. if (lpSource >= lpLast || *lpSrch == 0)
  527. return NULL;
  528. lpEnd = lstrfns_StrEndNW(lpLast, (UINT)(lstrlenW(lpSrch)-1));
  529. cHold = *lpEnd;
  530. *lpEnd = 0;
  531. while ((lpSource = StrStrIW(lpSource, lpSrch))!=0 &&
  532. lpSource < lpLast)
  533. {
  534. lpFound = lpSource;
  535. lpSource++;
  536. }
  537. *lpEnd = cHold;
  538. return((LPWSTR)lpFound);
  539. }
  540. /*
  541. * StrStr - Search for first occurrence of a substring
  542. *
  543. * Assumes lpSource points to source string
  544. * lpSrch points to string to search for
  545. * returns first occurrence of string if successful; NULL otherwise
  546. */
  547. LPSTR FAR PASCAL StrStrA(LPCSTR lpFirst, LPCSTR lpSrch)
  548. {
  549. UINT uLen;
  550. WORD wMatch;
  551. uLen = (UINT)lstrlenA(lpSrch);
  552. wMatch = READNATIVEWORD(lpSrch);
  553. for ( ; (lpFirst=StrChrA(lpFirst, wMatch))!=0 && !IntlStrEqNA(lpFirst, lpSrch, uLen);
  554. lpFirst=AnsiNext(lpFirst))
  555. continue; /* continue until we hit the end of the string or get a match */
  556. return((LPSTR)lpFirst);
  557. }
  558. LPWSTR FAR PASCAL StrStrW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  559. {
  560. UINT uLen;
  561. WCHAR wMatch;
  562. uLen = (UINT)lstrlenW(lpSrch);
  563. wMatch = *lpSrch;
  564. for ( ; (lpFirst=StrChrW(lpFirst, wMatch))!=0 && !IntlStrEqNW(lpFirst, lpSrch, uLen);
  565. lpFirst++)
  566. continue; /* continue until we hit the end of the string or get a match */
  567. return((LPWSTR)lpFirst);
  568. }
  569. /*
  570. * StrChrI - Find first occurrence of character in string, case insensitive
  571. * Assumes lpStart points to start of null terminated string
  572. * wMatch is the character to match
  573. * returns ptr to the first occurrence of ch in str, NULL if not found.
  574. */
  575. LPSTR FAR PASCAL StrChrIA(LPCSTR lpStart, WORD wMatch)
  576. {
  577. wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  578. for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  579. {
  580. if (!ChrCmpIA(READNATIVEWORD(lpStart), wMatch))
  581. return((LPSTR)lpStart);
  582. }
  583. return (NULL);
  584. }
  585. LPWSTR FAR PASCAL StrChrIW(LPCWSTR lpStart, WCHAR wMatch)
  586. {
  587. for ( ; *lpStart; lpStart++)
  588. {
  589. if (!ChrCmpIW(*lpStart, wMatch))
  590. return((LPWSTR)lpStart);
  591. }
  592. return (NULL);
  593. }
  594. /*
  595. * StrStrI - Search for first occurrence of a substring, case insensitive
  596. *
  597. * Assumes lpFirst points to source string
  598. * lpSrch points to string to search for
  599. * returns first occurrence of string if successful; NULL otherwise
  600. */
  601. LPSTR FAR PASCAL StrStrIA(LPCSTR lpFirst, LPCSTR lpSrch)
  602. {
  603. UINT uLen;
  604. WORD wMatch;
  605. uLen = (UINT)lstrlenA(lpSrch);
  606. wMatch = READNATIVEWORD(lpSrch);
  607. for ( ; (lpFirst = StrChrIA(lpFirst, wMatch)) != 0 && !IntlStrEqNIA(lpFirst, lpSrch, uLen);
  608. lpFirst=AnsiNext(lpFirst))
  609. continue; /* continue until we hit the end of the string or get a match */
  610. return((LPSTR)lpFirst);
  611. }
  612. LPWSTR FAR PASCAL StrStrIW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  613. {
  614. UINT uLen;
  615. WCHAR wMatch;
  616. uLen = (UINT)lstrlenW(lpSrch);
  617. wMatch = *lpSrch;
  618. for ( ; (lpFirst = StrChrIW(lpFirst, wMatch)) != 0 && !IntlStrEqNIW(lpFirst, lpSrch, uLen);
  619. lpFirst++)
  620. continue; /* continue until we hit the end of the string or get a match */
  621. return((LPWSTR)lpFirst);
  622. }
  623. ////////////////////////////////////////////////////////////////////
  624. //
  625. // Plug UI support with SHLWAPI
  626. //
  627. #define SHLWAPIMLISMLHINSTANCE_ORD 429
  628. typedef BOOL (* PFNMLISMLHINSTANCE)(HINSTANCE);
  629. typedef HRESULT (*PFNDLLGETVERSION)(DLLVERSIONINFO * pinfo);
  630. HMODULE GetShlwapiHModule()
  631. {
  632. HMODULE hmodShlwapi = GetModuleHandle(TEXT("SHLWAPI"));
  633. if (hmodShlwapi)
  634. {
  635. PFNDLLGETVERSION pfnDllGetVersion = (PFNDLLGETVERSION)GetProcAddress(hmodShlwapi, "DllGetVersion");
  636. if (pfnDllGetVersion)
  637. {
  638. DLLVERSIONINFO dllinfo;
  639. dllinfo.cbSize = sizeof(DLLVERSIONINFO);
  640. if (pfnDllGetVersion(&dllinfo) == NOERROR)
  641. {
  642. if (dllinfo.dwMajorVersion < 5)
  643. {
  644. // This guy doesn't support ML functions
  645. hmodShlwapi = NULL;
  646. }
  647. }
  648. }
  649. }
  650. return hmodShlwapi;
  651. }
  652. BOOL MLIsMLHInstance(HINSTANCE hInst)
  653. {
  654. BOOL fRet = FALSE;
  655. HMODULE hmodShlwapi = GetShlwapiHModule();
  656. if (hmodShlwapi)
  657. {
  658. PFNMLISMLHINSTANCE pfnMLIsMLHInstance;
  659. pfnMLIsMLHInstance = (PFNMLISMLHINSTANCE)GetProcAddress(hmodShlwapi, (LPCSTR)SHLWAPIMLISMLHINSTANCE_ORD);
  660. if (pfnMLIsMLHInstance)
  661. {
  662. fRet = pfnMLIsMLHInstance(hInst);
  663. }
  664. }
  665. return fRet;
  666. }