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.

759 lines
18 KiB

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