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.

704 lines
15 KiB

  1. //*******************************************************************************************
  2. //
  3. // Filename : strings.c
  4. //
  5. // DBCS aware string routines...
  6. //
  7. // Copyright (c) 1994 - 1996 Microsoft Corporation. All rights reserved
  8. //
  9. //*******************************************************************************************
  10. #include "pch.h"
  11. #include "strings.h"
  12. #ifdef UNICODE
  13. #define _StrEndN _StrEndNW
  14. #define ChrCmp ChrCmpW
  15. #define ChrCmpI ChrCmpIW
  16. #else
  17. #define _StrEndN _StrEndNA
  18. #define ChrCmp ChrCmpA
  19. #define ChrCmpI ChrCmpIA
  20. #endif
  21. /*
  22. * StrEndN - Find the end of a string, but no more than n bytes
  23. * Assumes pStart points to start of null terminated string
  24. * nBufSize is the maximum length
  25. * returns ptr to just after the last byte to be included
  26. */
  27. LPSTR _StrEndNA(LPCSTR pStart, int nBufSize)
  28. {
  29. LPCSTR pEnd;
  30. for (pEnd = pStart + nBufSize; *pStart && pStart < pEnd; pStart = AnsiNext(pStart))
  31. continue; /* just getting to the end of the string */
  32. if (pStart > pEnd)
  33. {
  34. /* We can only get here if the last byte before pEnd was a lead byte
  35. */
  36. pStart -= 2;
  37. }
  38. return (LPSTR)pStart;
  39. }
  40. LPWSTR _StrEndNW(LPCWSTR pStart, int nBufSize)
  41. {
  42. #ifdef UNICODE
  43. LPCWSTR pEnd;
  44. for (pEnd = pStart + nBufSize; *pStart && (pStart < pEnd);
  45. pStart++)
  46. continue; /* just getting to the end of the string */
  47. return((LPWSTR)pStart);
  48. #else
  49. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  50. return NULL;
  51. #endif
  52. }
  53. /*
  54. * ChrCmp - Case sensitive character comparison for DBCS
  55. * Assumes w1, wMatch are characters to be compared
  56. * Return FALSE if they match, TRUE if no match
  57. */
  58. BOOL ChrCmpA(WORD w1, WORD wMatch)
  59. {
  60. /* Most of the time this won't match, so test it first for speed.
  61. */
  62. if (LOBYTE(w1) == LOBYTE(wMatch))
  63. {
  64. if (IsDBCSLeadByte(LOBYTE(w1)))
  65. {
  66. return(w1 != wMatch);
  67. }
  68. return FALSE;
  69. }
  70. return TRUE;
  71. }
  72. BOOL ChrCmpW(WORD w1, WORD wMatch)
  73. {
  74. #ifdef UNICODE
  75. return(!(w1 == wMatch));
  76. #else
  77. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  78. return FALSE;
  79. #endif
  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(WORD w1, WORD wMatch)
  102. {
  103. #ifdef UNICODE
  104. TCHAR sz1[2], sz2[2];
  105. sz1[0] = w1;
  106. sz1[1] = TEXT('\0');
  107. sz2[0] = wMatch;
  108. sz2[1] = TEXT('\0');
  109. return lstrcmpiW(sz1, sz2);
  110. #else
  111. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  112. return FALSE;
  113. #endif
  114. }
  115. /*
  116. * StrChr - Find first occurrence of character in string
  117. * Assumes pStart points to start of null terminated string
  118. * wMatch is the character to match
  119. * returns ptr to the first occurrence of ch in str, NULL if not found.
  120. */
  121. LPSTR StrChrA(LPCSTR pStart, WORD wMatch)
  122. {
  123. for ( ; *pStart; pStart = AnsiNext(pStart))
  124. {
  125. if (!ChrCmpA(*(UNALIGNED WORD *)pStart, wMatch))
  126. {
  127. return((LPSTR)pStart);
  128. }
  129. }
  130. return (NULL);
  131. }
  132. LPWSTR StrChrW(LPCWSTR pStart, WORD wMatch)
  133. {
  134. #ifdef UNICODE
  135. for ( ; *pStart; pStart = AnsiNext(pStart))
  136. {
  137. // Need a tmp word since casting ptr to WORD * will
  138. // fault on MIPS, ALPHA
  139. WORD wTmp;
  140. memcpy(&wTmp, pStart, sizeof(WORD));
  141. if (!ChrCmpW(wTmp, wMatch))
  142. {
  143. return((LPWSTR)pStart);
  144. }
  145. }
  146. return (NULL);
  147. #else
  148. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  149. return NULL;
  150. #endif
  151. }
  152. /*
  153. * StrRChr - Find last occurrence of character in string
  154. * Assumes pStart points to start of string
  155. * pEnd points to end of string (NOT included in search)
  156. * wMatch is the character to match
  157. * returns ptr to the last occurrence of ch in str, NULL if not found.
  158. */
  159. LPSTR StrRChrA(LPCSTR pStart, LPCSTR pEnd, WORD wMatch)
  160. {
  161. LPCSTR lpFound = NULL;
  162. if (!pEnd)
  163. pEnd = pStart + lstrlenA(pStart);
  164. for ( ; pStart < pEnd; pStart = AnsiNext(pStart))
  165. {
  166. if (!ChrCmpA(*(UNALIGNED WORD *)pStart, wMatch))
  167. lpFound = pStart;
  168. }
  169. return ((LPSTR)lpFound);
  170. }
  171. LPWSTR StrRChrW(LPCWSTR pStart, LPCWSTR pEnd, WORD wMatch)
  172. {
  173. #ifdef UNICODE
  174. LPCWSTR lpFound = NULL;
  175. if (!pEnd)
  176. pEnd = pStart + lstrlenW(pStart);
  177. for ( ; pStart < pEnd; pStart++)
  178. {
  179. if (!ChrCmpW(*(UNALIGNED WORD *)pStart, wMatch))
  180. lpFound = pStart;
  181. }
  182. return ((LPWSTR)lpFound);
  183. #else
  184. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  185. return NULL;
  186. #endif
  187. }
  188. /*
  189. * StrChrI - Find first occurrence of character in string, case insensitive
  190. * Assumes pStart points to start of null terminated string
  191. * wMatch is the character to match
  192. * returns ptr to the first occurrence of ch in str, NULL if not found.
  193. */
  194. LPSTR StrChrIA(LPCSTR pStart, WORD wMatch)
  195. {
  196. wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  197. for ( ; *pStart; pStart = AnsiNext(pStart))
  198. {
  199. if (!ChrCmpIA(*(UNALIGNED WORD *)pStart, wMatch))
  200. return((LPSTR)pStart);
  201. }
  202. return (NULL);
  203. }
  204. LPWSTR StrChrIW(LPCWSTR pStart, WORD wMatch)
  205. {
  206. #ifdef UNICODE
  207. for ( ; *pStart; pStart++)
  208. {
  209. if (!ChrCmpIW(*(WORD *)pStart, wMatch))
  210. return((LPWSTR)pStart);
  211. }
  212. return (NULL);
  213. #else
  214. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  215. return NULL;
  216. #endif
  217. }
  218. /*
  219. * StrRChrI - Find last occurrence of character in string, case insensitive
  220. * Assumes pStart points to start of string
  221. * pEnd points to end of string (NOT included in search)
  222. * wMatch is the character to match
  223. * returns ptr to the last occurrence of ch in str, NULL if not found.
  224. */
  225. LPSTR StrRChrIA(LPCSTR pStart, LPCSTR pEnd, WORD wMatch)
  226. {
  227. LPCSTR lpFound = NULL;
  228. if (!pEnd)
  229. pEnd = pStart + lstrlenA(pStart);
  230. wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  231. for ( ; pStart < pEnd; pStart = AnsiNext(pStart))
  232. {
  233. if (!ChrCmpIA(*(UNALIGNED WORD *)pStart, wMatch))
  234. lpFound = pStart;
  235. }
  236. return ((LPSTR)lpFound);
  237. }
  238. LPWSTR StrRChrIW(LPCWSTR pStart, LPCWSTR pEnd, WORD wMatch)
  239. {
  240. #ifdef UNICODE
  241. LPCWSTR lpFound = NULL;
  242. if (!pEnd)
  243. pEnd = pStart + lstrlenW(pStart);
  244. for ( ; pStart < pEnd; pStart++)
  245. {
  246. if (!ChrCmpIW(*(WORD *)pStart, wMatch))
  247. lpFound = pStart;
  248. }
  249. return ((LPWSTR)lpFound);
  250. #else
  251. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  252. return NULL;
  253. #endif
  254. }
  255. // StrCSpn: return index to first char of lpStr that is present in lpSet.
  256. // Includes the NUL in the comparison; if no lpSet chars are found, returns
  257. // the index to the NUL in lpStr.
  258. // Just like CRT strcspn.
  259. //
  260. int StrCSpnA(LPCSTR lpStr, LPCSTR lpSet)
  261. {
  262. // nature of the beast: O(lpStr*lpSet) work
  263. LPCSTR lp = lpStr;
  264. if (!lpStr || !lpSet)
  265. return 0;
  266. while (*lp)
  267. {
  268. if (StrChrA(lpSet, *(UNALIGNED WORD *)lp))
  269. return (int)(lp-lpStr);
  270. lp = AnsiNext(lp);
  271. }
  272. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  273. }
  274. int StrCSpnW(LPCWSTR lpStr, LPCWSTR lpSet)
  275. {
  276. #ifdef UNICODE
  277. // nature of the beast: O(lpStr*lpSet) work
  278. LPCWSTR lp = lpStr;
  279. if (!lpStr || !lpSet)
  280. return 0;
  281. while (*lp)
  282. {
  283. if (StrChrW(lpSet, *(WORD *)lp))
  284. return (int)(lp-lpStr);
  285. lp++;
  286. }
  287. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  288. #else
  289. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  290. return -1;
  291. #endif
  292. }
  293. // StrCSpnI: case-insensitive version of StrCSpn.
  294. //
  295. int StrCSpnIA(LPCSTR lpStr, LPCSTR lpSet)
  296. {
  297. // nature of the beast: O(lpStr*lpSet) work
  298. LPCSTR lp = lpStr;
  299. if (!lpStr || !lpSet)
  300. return 0;
  301. while (*lp)
  302. {
  303. if (StrChrIA(lpSet, *(UNALIGNED WORD *)lp))
  304. return (int)(lp-lpStr);
  305. lp = AnsiNext(lp);
  306. }
  307. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  308. }
  309. int StrCSpnIW(LPCWSTR lpStr, LPCWSTR lpSet)
  310. {
  311. #ifdef UNICODE
  312. // nature of the beast: O(lpStr*lpSet) work
  313. LPCWSTR lp = lpStr;
  314. if (!lpStr || !lpSet)
  315. return 0;
  316. while (*lp)
  317. {
  318. if (StrChrIW(lpSet, *(WORD *)lp))
  319. return (int)(lp-lpStr);
  320. lp++;
  321. }
  322. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  323. #else
  324. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  325. return -1;
  326. #endif
  327. }
  328. /*
  329. * StrCmpN - Compare n bytes
  330. *
  331. * returns See lstrcmp return values.
  332. * won't work if source strings are in ROM
  333. */
  334. int StrCmpNA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  335. {
  336. char sz1[4];
  337. char sz2[4];
  338. int i;
  339. LPCSTR lpszEnd = lpStr1 + nChar;
  340. //DebugMsg(DM_TRACE, "StrCmpN: %s %s %d returns:", lpStr1, lpStr2, nChar);
  341. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1 = AnsiNext(lpStr1), lpStr2 = AnsiNext(lpStr2)) {
  342. WORD wMatch;
  343. if (IsDBCSLeadByte(*lpStr2))
  344. lpStr2++;
  345. wMatch = (WORD) *lpStr2;
  346. i = ChrCmpA(*(UNALIGNED WORD *)lpStr1, wMatch);
  347. if (i) {
  348. int iRet;
  349. (*(WORD *)sz1) = *(UNALIGNED WORD *)lpStr1;
  350. (*(WORD *)sz2) = *(UNALIGNED WORD *)lpStr2;
  351. *AnsiNext(sz1) = 0;
  352. *AnsiNext(sz2) = 0;
  353. iRet = lstrcmpA(sz1, sz2);
  354. //DebugMsg(DM_TRACE, ".................... %d", iRet);
  355. return iRet;
  356. }
  357. }
  358. //DebugMsg(DM_TRACE, ".................... 0");
  359. return 0;
  360. }
  361. int StrCmpNW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  362. {
  363. #ifdef UNICODE
  364. WCHAR sz1[2];
  365. WCHAR sz2[2];
  366. int i;
  367. LPCWSTR lpszEnd = lpStr1 + nChar;
  368. //DebugMsg(DM_TRACE, "StrCmpN: %s %s %d returns:", lpStr1, lpStr2, nChar);
  369. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1++, lpStr2++) {
  370. i = ChrCmpW(*lpStr1, *lpStr2);
  371. if (i) {
  372. int iRet;
  373. sz1[0] = *lpStr1;
  374. sz2[0] = *lpStr2;
  375. sz1[1] = TEXT('\0');
  376. sz2[1] = TEXT('\0');
  377. iRet = lstrcmpW(sz1, sz2);
  378. //DebugMsg(DM_TRACE, ".................... %d", iRet);
  379. return iRet;
  380. }
  381. }
  382. //DebugMsg(DM_TRACE, ".................... 0");
  383. return 0;
  384. #else
  385. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  386. return -1;
  387. #endif
  388. }
  389. /*
  390. * StrCmpNI - Compare n bytes, case insensitive
  391. *
  392. * returns See lstrcmpi return values.
  393. */
  394. int StrCmpNIA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  395. {
  396. int i;
  397. LPCSTR lpszEnd = lpStr1 + nChar;
  398. //DebugMsg(DM_TRACE, "StrCmpNI: %s %s %d returns:", lpStr1, lpStr2, nChar);
  399. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); (lpStr1 = AnsiNext(lpStr1)), (lpStr2 = AnsiNext(lpStr2))) {
  400. WORD wMatch;
  401. wMatch = (UINT)(IsDBCSLeadByte(*lpStr2)) ? *(WORD *)lpStr2 : (WORD)(BYTE)(*lpStr2);
  402. i = ChrCmpIA(*(UNALIGNED WORD *)lpStr1, wMatch);
  403. if (i) {
  404. //DebugMsg(DM_TRACE, ".................... %d", i);
  405. return i;
  406. }
  407. }
  408. //DebugMsg(DM_TRACE, ".................... 0");
  409. return 0;
  410. }
  411. int StrCmpNIW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  412. {
  413. #ifdef UNICODE
  414. int i;
  415. LPCWSTR lpszEnd = lpStr1 + nChar;
  416. //DebugMsg(DM_TRACE, "StrCmpNI: %s %s %d returns:", lpStr1, lpStr2, nChar);
  417. for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1++, lpStr2++) {
  418. i = ChrCmpIW(*lpStr1, *lpStr2);
  419. if (i) {
  420. //DebugMsg(DM_TRACE, ".................... %d", i);
  421. return i;
  422. }
  423. }
  424. //DebugMsg(DM_TRACE, ".................... 0");
  425. return 0;
  426. #else
  427. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  428. return -1;
  429. #endif
  430. }
  431. /*
  432. * StrRStrI - Search for last occurrence of a substring
  433. *
  434. * Assumes lpSource points to the null terminated source string
  435. * lpLast points to where to search from in the source string
  436. * lpLast is not included in the search
  437. * lpSrch points to string to search for
  438. * returns last occurrence of string if successful; NULL otherwise
  439. */
  440. LPSTR StrRStrIA(LPCSTR lpSource, LPCSTR lpLast, LPCSTR lpSrch)
  441. {
  442. LPCSTR lpFound = NULL;
  443. LPSTR pEnd;
  444. char cHold;
  445. if (!lpLast)
  446. lpLast = lpSource + lstrlenA(lpSource);
  447. if (lpSource >= lpLast || *lpSrch == 0)
  448. return NULL;
  449. pEnd = _StrEndNA(lpLast, (UINT)(lstrlenA(lpSrch)-1));
  450. cHold = *pEnd;
  451. *pEnd = 0;
  452. while ((lpSource = StrStrIA(lpSource, lpSrch)) != 0 && lpSource < lpLast)
  453. {
  454. lpFound = lpSource;
  455. lpSource = AnsiNext(lpSource);
  456. }
  457. *pEnd = cHold;
  458. return((LPSTR)lpFound);
  459. }
  460. LPWSTR StrRStrIW(LPCWSTR lpSource, LPCWSTR lpLast, LPCWSTR lpSrch)
  461. {
  462. #ifdef UNICODE
  463. LPCWSTR lpFound = NULL;
  464. LPWSTR pEnd;
  465. WCHAR cHold;
  466. if (!lpLast)
  467. lpLast = lpSource + lstrlenW(lpSource);
  468. if (lpSource >= lpLast || *lpSrch == 0)
  469. return NULL;
  470. pEnd = _StrEndNW(lpLast, (UINT)(lstrlenW(lpSrch)-1));
  471. cHold = *pEnd;
  472. *pEnd = 0;
  473. while ((lpSource = StrStrIW(lpSource, lpSrch))!=0 &&
  474. lpSource < lpLast)
  475. {
  476. lpFound = lpSource;
  477. lpSource++;
  478. }
  479. *pEnd = cHold;
  480. return((LPWSTR)lpFound);
  481. #else
  482. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  483. return NULL;
  484. #endif
  485. }
  486. /*
  487. * StrStr - Search for first occurrence of a substring
  488. *
  489. * Assumes lpSource points to source string
  490. * lpSrch points to string to search for
  491. * returns first occurrence of string if successful; NULL otherwise
  492. */
  493. LPSTR StrStrA(LPCSTR lpFirst, LPCSTR lpSrch)
  494. {
  495. UINT uLen;
  496. WORD wMatch;
  497. uLen = (UINT)lstrlenA(lpSrch);
  498. wMatch = *(UNALIGNED WORD *)lpSrch;
  499. for ( ; (lpFirst=StrChrA(lpFirst, wMatch))!=0 && StrCmpNA(lpFirst, lpSrch, uLen);
  500. lpFirst=AnsiNext(lpFirst))
  501. continue; /* continue until we hit the end of the string or get a match */
  502. return((LPSTR)lpFirst);
  503. }
  504. LPWSTR StrStrW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  505. {
  506. #ifdef UNICODE
  507. UINT uLen;
  508. WORD wMatch;
  509. uLen = (UINT)lstrlenW(lpSrch);
  510. wMatch = *(WORD *)lpSrch;
  511. for ( ; (lpFirst=StrChrW(lpFirst, wMatch))!=0 && StrCmpNW(lpFirst, lpSrch, uLen);
  512. lpFirst++)
  513. continue; /* continue until we hit the end of the string or get a match */
  514. return((LPWSTR)lpFirst);
  515. #else
  516. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  517. return NULL;
  518. #endif
  519. }
  520. /*
  521. * StrStrI - Search for first occurrence of a substring, case insensitive
  522. *
  523. * Assumes lpFirst points to source string
  524. * lpSrch points to string to search for
  525. * returns first occurrence of string if successful; NULL otherwise
  526. */
  527. LPSTR StrStrIA(LPCSTR lpFirst, LPCSTR lpSrch)
  528. {
  529. UINT uLen;
  530. WORD wMatch;
  531. uLen = (UINT)lstrlenA(lpSrch);
  532. wMatch = *(UNALIGNED WORD *)lpSrch;
  533. for ( ; (lpFirst = StrChrIA(lpFirst, wMatch)) != 0 && StrCmpNIA(lpFirst, lpSrch, uLen);
  534. lpFirst=AnsiNext(lpFirst))
  535. continue; /* continue until we hit the end of the string or get a match */
  536. return((LPSTR)lpFirst);
  537. }
  538. LPWSTR StrStrIW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  539. {
  540. #ifdef UNICODE
  541. UINT uLen;
  542. WORD wMatch;
  543. uLen = (UINT)lstrlenW(lpSrch);
  544. wMatch = *(WORD *)lpSrch;
  545. for ( ; (lpFirst = StrChrIW(lpFirst, wMatch)) != 0 && StrCmpNIW(lpFirst, lpSrch, uLen);
  546. lpFirst++)
  547. continue; /* continue until we hit the end of the string or get a match */
  548. return((LPWSTR)lpFirst);
  549. #else
  550. SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  551. return NULL;
  552. #endif
  553. }