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.

1195 lines
32 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: strings.cpp
  4. //
  5. // Module: CMUTIL.DLL
  6. //
  7. // Synopsis: Basic string manipulation routines
  8. //
  9. // Copyright (c) 1997-1999 Microsoft Corporation
  10. //
  11. // Author: henryt Created 03/01/98
  12. //
  13. //+----------------------------------------------------------------------------
  14. #include "cmmaster.h"
  15. //+----------------------------------------------------------------------------
  16. //
  17. // Function: WzToSz
  18. //
  19. // Synopsis: Standard conversion function for converting Wide Characters to
  20. // Ansi Characters
  21. //
  22. // Arguments: IN LPCWSTR pszwStrIn - Input Unicode string
  23. // OUT LPSTR pszStrOut - Ansi Ouput Buffer
  24. // IN int nOutBufferSize - number of Chars in pszStrOut
  25. //
  26. // Returns: int - 0 on failure, if return Value is > nOutBufferSize then the
  27. // buffer is too small. Otherwise the number of chars copied
  28. // to pszStrOut.
  29. //
  30. // History: Created Header 4/22/99
  31. //
  32. //+----------------------------------------------------------------------------
  33. CMUTILAPI int WzToSz(IN LPCWSTR pszwStrIn, OUT LPSTR pszStrOut, IN int nOutBufferSize)
  34. {
  35. int nReturn = 0;
  36. //
  37. // nOutBufferSize could be 0 and pszStrOut could be NULL (passing zero size and a NULL out
  38. // buffer causes WideCharToMultiByte to return the number of chars needed to convert the
  39. // input string. It is used as a sizing technique). Only check pszwStrIn
  40. //
  41. if (pszwStrIn)
  42. {
  43. nReturn = WideCharToMultiByte(CP_ACP, 0, pszwStrIn, -1, pszStrOut, nOutBufferSize, NULL, NULL);
  44. }
  45. else
  46. {
  47. SetLastError(ERROR_INVALID_PARAMETER);
  48. }
  49. return nReturn;
  50. }
  51. //+----------------------------------------------------------------------------
  52. //
  53. // Function: SzToWz
  54. //
  55. // Synopsis: Standard Wrapper for converting from an Ansi string to a Wide String
  56. //
  57. // Arguments: IN LPCSTR pszInput - Ansi String to Convert
  58. // OUT LPWSTR pszwOutput - Wide string output buffer
  59. // IN int nBufferSize - number of chars in Wide String buffer
  60. //
  61. // Returns: int - 0 on failure, otherwise if return is < nBufferSize then insufficient
  62. // buffer space. Otherwise the number of chars copied to the buffer.
  63. //
  64. // History: quintinb Created 4/22/99
  65. //
  66. //+----------------------------------------------------------------------------
  67. CMUTILAPI int SzToWz(IN LPCSTR pszInput, OUT LPWSTR pszwOutput, IN int nBufferSize)
  68. {
  69. int nReturn = 0;
  70. if (pszInput)
  71. {
  72. return MultiByteToWideChar(CP_ACP, 0, pszInput, -1, pszwOutput, nBufferSize);
  73. }
  74. else
  75. {
  76. SetLastError(ERROR_INVALID_PARAMETER);
  77. }
  78. return nReturn;
  79. }
  80. //+----------------------------------------------------------------------------
  81. //
  82. // Function: SzToWzWithAlloc
  83. //
  84. // Synopsis: Simple wrapper to encapsulate converting a string from
  85. // MultiByte To Wide Char that Allocates memory using the sizing
  86. // capabilities of the MultiByteToWideChar Api.
  87. //
  88. // Arguments: LPCSTR pszAnsiString - Source string to be converted.
  89. //
  90. // Returns: LPWSTR - returns NULL on failure, otherwise the converted string.
  91. // The caller is responsible for freeing the Alloc-ed Memory.
  92. //
  93. // History: quintinb Created 4/8/99
  94. //
  95. //+----------------------------------------------------------------------------
  96. CMUTILAPI LPWSTR SzToWzWithAlloc(LPCSTR pszAnsiString)
  97. {
  98. LPWSTR pszwString = NULL;
  99. //
  100. // Find out how large the string is by calling MultiByteToWideChar with
  101. // Zero for the size field.
  102. //
  103. if (NULL != pszAnsiString)
  104. {
  105. DWORD dwSize = SzToWz(pszAnsiString, NULL, 0);
  106. CMASSERTMSG((dwSize != 0), TEXT("SzToWzWithAlloc -- First MultiByteToWideChar Failed."));
  107. if (0 != dwSize)
  108. {
  109. pszwString = (LPWSTR)CmMalloc(dwSize*sizeof(WCHAR));
  110. CMASSERTMSG(pszwString, TEXT("SzToWzWithAlloc -- CmMalloc of pszwString Failed."));
  111. if (pszwString)
  112. {
  113. if (!SzToWz(pszAnsiString, pszwString, dwSize))
  114. {
  115. //
  116. // Make sure to return a NULL string if we fail.
  117. //
  118. CMASSERTMSG(FALSE, TEXT("SzToWzWithAlloc -- Second MultiByteToWideChar Failed."));
  119. CmFree(pszwString);
  120. pszwString = NULL;
  121. }
  122. #ifdef DEBUG
  123. else
  124. {
  125. //
  126. // If this is a debug build then we want to take the Wide string that we are going to
  127. // return, convert it to Ansi and compare it to the original ansi string passed in.
  128. //
  129. LPSTR pszString;
  130. DWORD dwSize = WzToSz(pszwString, NULL, 0);
  131. if (0 != dwSize)
  132. {
  133. pszString = (LPSTR)CmMalloc(dwSize*sizeof(CHAR));
  134. CMASSERTMSG(pszString, TEXT("SzToWzWithAlloc -- conversion of return value back to original Ansi string failed. Unable to allocate memory."));
  135. if (pszString)
  136. {
  137. if (WzToSz(pszwString, pszString, dwSize))
  138. {
  139. MYDBGASSERT(0 == lstrcmpA(pszString, pszAnsiString));
  140. }
  141. else
  142. {
  143. CMASSERTMSG(FALSE, TEXT("SzToWzWithAlloc -- conversion of return value back to original Ansi string failed."));
  144. }
  145. CmFree(pszString);
  146. }
  147. }
  148. else
  149. {
  150. CMASSERTMSG(FALSE, TEXT("SzToWzWithAlloc -- conversion of return value back to original Ansi string failed. Unable to properly size the string."));
  151. }
  152. }
  153. #endif
  154. }
  155. }
  156. }
  157. return pszwString;
  158. }
  159. //+----------------------------------------------------------------------------
  160. //
  161. // Function: WzToSzWithAlloc
  162. //
  163. // Synopsis: Simple wrapper to encapsulate converting a string from
  164. // Unicode to MBCS that allocates memory using the sizing
  165. // capabilities of the WideCharToMultiByte Api.
  166. //
  167. // Arguments: LPCWSTR pszwWideString - Source string to be converted.
  168. //
  169. // Returns: LPSTR - returns NULL on failure, otherwise the converted string.
  170. // The caller is responsible for freeing the Alloc-ed Memory.
  171. //
  172. // History: quintinb Created 4/8/99
  173. //
  174. //+----------------------------------------------------------------------------
  175. CMUTILAPI LPSTR WzToSzWithAlloc(LPCWSTR pszwWideString)
  176. {
  177. LPSTR pszString = NULL;
  178. //
  179. // Find out how large the string is by calling WideCharToMultiByte with
  180. // Zero for the size field.
  181. //
  182. if (NULL != pszwWideString)
  183. {
  184. DWORD dwSize = WzToSz(pszwWideString, NULL, 0);
  185. CMASSERTMSG((0 != dwSize), TEXT("WzToSzWithAlloc -- First WzToSz Failed."));
  186. if (0 != dwSize)
  187. {
  188. pszString = (LPSTR)CmMalloc(dwSize*sizeof(CHAR));
  189. CMASSERTMSG(pszString, TEXT("WzToSzWithAlloc -- CmMalloc failed to alloc pszString."));
  190. if (pszString)
  191. {
  192. if (!WzToSz(pszwWideString, pszString, dwSize))
  193. {
  194. //
  195. // Make sure to return a NULL string if we fail.
  196. //
  197. CMASSERTMSG(FALSE, TEXT("WzToSzWithAlloc -- Second WzToSz Failed."));
  198. CmFree(pszString);
  199. pszString = NULL;
  200. }
  201. #ifdef DEBUG
  202. else
  203. {
  204. //
  205. // If this is a debug build then we want to take the Ansi string that we are
  206. // going to return, convert it to Unicode and compare it to the original Unicode
  207. // string passed in.
  208. //
  209. LPWSTR pszwString;
  210. DWORD dwSize = SzToWz(pszString, NULL, 0);
  211. if (0 != dwSize)
  212. {
  213. pszwString = (LPWSTR)CmMalloc(dwSize*sizeof(WCHAR));
  214. CMASSERTMSG(pszwString, TEXT("WzToSzWithAlloc -- conversion of return value back to original Ansi string failed. Unable to allocate memory."));
  215. if (pszwString)
  216. {
  217. if (SzToWz(pszString, pszwString, dwSize))
  218. {
  219. MYDBGASSERT(0 == lstrcmpU(pszwString, pszwWideString));
  220. }
  221. else
  222. {
  223. CMASSERTMSG(FALSE, TEXT("WzToSzWithAlloc -- conversion of return value back to original Ansi string failed."));
  224. }
  225. CmFree(pszwString);
  226. }
  227. }
  228. else
  229. {
  230. CMASSERTMSG(FALSE, TEXT("WzToSzWithAlloc -- conversion of return value back to original Ansi string failed. Unable to properly size the string."));
  231. }
  232. }
  233. #endif
  234. }
  235. }
  236. }
  237. return pszString;
  238. }
  239. //+----------------------------------------------------------------------------
  240. //
  241. // Function: CmStrTrimA
  242. //
  243. // Synopsis: Helper function to trim leading and trailing blanks from a
  244. // string
  245. //
  246. // Arguments: LPTSTR pszStr - The string to be trimmed
  247. //
  248. // Returns: void WINAPI - Nothing
  249. //
  250. // History: nickball Created Header 3/11/98
  251. //
  252. //+----------------------------------------------------------------------------
  253. CMUTILAPI void WINAPI CmStrTrimA(LPSTR pszStr)
  254. {
  255. //
  256. // first, skip all the spaces at the begining of the string
  257. //
  258. MYDBGASSERT(pszStr);
  259. if (pszStr)
  260. {
  261. LPSTR pszTmp = pszStr;
  262. while (CmIsSpaceA(pszTmp))
  263. {
  264. pszTmp = CharNextA(pszTmp);
  265. }
  266. if (pszTmp != pszStr)
  267. {
  268. CmMoveMemory(pszStr, pszTmp, lstrlenA(pszTmp)+1);
  269. }
  270. //
  271. // secondly, delete all the spaces at the end of the string
  272. //
  273. pszTmp = CmEndOfStrA(pszStr);
  274. while (pszTmp != pszStr)
  275. {
  276. pszTmp = CharPrevA(pszStr, pszTmp);
  277. if (!CmIsSpaceA(pszTmp))
  278. {
  279. break;
  280. }
  281. *pszTmp = TEXT('\0');
  282. }
  283. }
  284. }
  285. //+----------------------------------------------------------------------------
  286. //
  287. // Function: CmStrTrimW
  288. //
  289. // Synopsis: Helper function to trim leading and trailing blanks from a
  290. // string.
  291. //
  292. // Arguments: LPTSTR pszStr - The string to be trimmed
  293. //
  294. // Returns: void WINAPI - Nothing
  295. //
  296. // History: quintinb Created 2/27/99
  297. //
  298. //+----------------------------------------------------------------------------
  299. CMUTILAPI void WINAPI CmStrTrimW(LPWSTR pszStr)
  300. {
  301. //
  302. // first, skip all the spaces at the begining of the string
  303. //
  304. MYDBGASSERT(pszStr);
  305. if (pszStr)
  306. {
  307. LPWSTR pszTmp = pszStr;
  308. while (CmIsSpaceW(pszTmp))
  309. {
  310. pszTmp = CharNextU(pszTmp);
  311. }
  312. if (pszTmp != pszStr)
  313. {
  314. CmMoveMemory(pszStr, pszTmp, (lstrlenU(pszTmp)+1)*sizeof(WCHAR));
  315. }
  316. //
  317. // secondly, delete all the spaces at the end of the string
  318. //
  319. pszTmp = CmEndOfStrW(pszStr);
  320. while (pszTmp != pszStr)
  321. {
  322. pszTmp = CharPrevU(pszStr, pszTmp);
  323. if (!CmIsSpaceW(pszTmp))
  324. {
  325. break;
  326. }
  327. *pszTmp = TEXT('\0');
  328. }
  329. }
  330. }
  331. //+----------------------------------------------------------------------------
  332. //
  333. // Function: CmIsSpaceA
  334. //
  335. // Synopsis: Checks to see if the char is a space. Note that spaces, new line chars,
  336. // line feed chars, tabs, and most other forms of whitespace are considered
  337. // spaces.
  338. //
  339. // Arguments: psz - an ansi or dbcs char
  340. //
  341. // Returns: TRUE or FALSE
  342. //
  343. //+----------------------------------------------------------------------------
  344. CMUTILAPI BOOL WINAPI CmIsSpaceA(LPSTR psz)
  345. {
  346. WORD wType = 0;
  347. MYDBGASSERT(psz);
  348. if (psz)
  349. {
  350. if (IsDBCSLeadByte(*psz))
  351. {
  352. MYVERIFY(GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 2, &wType));
  353. }
  354. else
  355. {
  356. MYVERIFY(GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 1, &wType));
  357. }
  358. }
  359. return (wType & C1_SPACE);
  360. }
  361. //+----------------------------------------------------------------------------
  362. //
  363. // Function: CmIsSpaceW
  364. //
  365. // Synopsis: Checks to see if the char is a space. Note that spaces, new line chars,
  366. // line feed chars, tabs, and most other forms of whitespace are considered
  367. // spaces.
  368. //
  369. // Arguments: psz - pointer to a string
  370. //
  371. // Returns: TRUE or FALSE
  372. //
  373. //+----------------------------------------------------------------------------
  374. CMUTILAPI BOOL WINAPI CmIsSpaceW(LPWSTR pszwStr)
  375. {
  376. WORD wType = 0;
  377. LPWSTR pszwNextChar;
  378. int iCharCount;
  379. MYDBGASSERT(pszwStr);
  380. if (pszwStr)
  381. {
  382. pszwNextChar = CharNextU(pszwStr);
  383. iCharCount = (INT)(pszwNextChar - pszwStr);
  384. if (0 == GetStringTypeExU(LOCALE_USER_DEFAULT, CT_CTYPE1, pszwStr, iCharCount, &wType))
  385. {
  386. CMTRACE3(TEXT("CmIsSpaceW -- GetStringTypeExW failed on %s, iCharCount is %d, GLE=%u"), pszwStr, iCharCount, GetLastError());
  387. return FALSE;
  388. }
  389. }
  390. return (wType & C1_SPACE);
  391. }
  392. //+----------------------------------------------------------------------------
  393. //
  394. // Function: CmIsDigitA
  395. //
  396. // Synopsis: Checks to see if the char is a digit.
  397. //
  398. // Arguments: psz - an ansi or dbcs char
  399. //
  400. // Returns: TRUE or FALSE
  401. //
  402. //+----------------------------------------------------------------------------
  403. CMUTILAPI BOOL WINAPI CmIsDigitA(LPSTR psz)
  404. {
  405. WORD wType = 0;
  406. MYDBGASSERT(psz);
  407. if (psz)
  408. {
  409. if (IsDBCSLeadByte(*psz))
  410. {
  411. MYVERIFY(GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 2, &wType));
  412. }
  413. else
  414. {
  415. MYVERIFY(GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, psz, 1, &wType));
  416. }
  417. }
  418. return (wType & C1_DIGIT);
  419. }
  420. //+----------------------------------------------------------------------------
  421. //
  422. // Function: CmIsDigitW
  423. //
  424. // Synopsis: Checks to see if the WCHAR is a digit.
  425. //
  426. // Arguments: pszwStr -- WCHAR string
  427. //
  428. // Returns: TRUE or FALSE
  429. //
  430. //+----------------------------------------------------------------------------
  431. CMUTILAPI BOOL WINAPI CmIsDigitW(LPWSTR pszwStr)
  432. {
  433. WORD wType = 0;
  434. LPWSTR pszwNextChar;
  435. int iCharCount;
  436. MYDBGASSERT(pszwStr);
  437. if (pszwStr)
  438. {
  439. pszwNextChar = CharNextU(pszwStr);
  440. iCharCount = (INT)(pszwNextChar - pszwStr);
  441. if (0 == GetStringTypeExU(LOCALE_USER_DEFAULT, CT_CTYPE1, pszwStr, iCharCount, &wType))
  442. {
  443. CMTRACE1(TEXT("CmIsDigitW -- GetStringTypeExU failed, GLE=%u"), GetLastError());
  444. return FALSE;
  445. }
  446. }
  447. return (wType & C1_DIGIT);
  448. }
  449. //+----------------------------------------------------------------------------
  450. //
  451. // Function: CmEndOfStrA
  452. //
  453. // Synopsis: Given a string, returns the ptr to the end of the string(null char).
  454. //
  455. // Arguments: psz - an ansi or dbcs char
  456. //
  457. // Returns: LPSTR ptr to null char
  458. //
  459. //+----------------------------------------------------------------------------
  460. CMUTILAPI LPSTR WINAPI CmEndOfStrA(LPSTR psz)
  461. {
  462. MYDBGASSERT(psz);
  463. if (psz)
  464. {
  465. while (*psz)
  466. {
  467. psz = CharNextA(psz);
  468. }
  469. }
  470. return psz;
  471. }
  472. //+----------------------------------------------------------------------------
  473. //
  474. // Function: CmEndOfStrW
  475. //
  476. // Synopsis: Given a string, returns the ptr to the end of the string(null char).
  477. //
  478. // Arguments: pszwStr - a WCHAR
  479. //
  480. // Returns: LPWSTR ptr to null char
  481. //
  482. //+----------------------------------------------------------------------------
  483. CMUTILAPI LPWSTR WINAPI CmEndOfStrW(LPWSTR pszwStr)
  484. {
  485. MYDBGASSERT(pszwStr);
  486. if (pszwStr)
  487. {
  488. while (*pszwStr)
  489. {
  490. pszwStr = CharNextU(pszwStr);
  491. }
  492. }
  493. return pszwStr;
  494. }
  495. //+----------------------------------------------------------------------------
  496. //
  497. // Function: CmStrCpyAllocA
  498. //
  499. // Synopsis: Copies pszSrc into a newly allocated buffer (using CmMalloc) and
  500. // returns the buffer to its caller who is responsible for freeing
  501. // the buffer.
  502. //
  503. // Arguments: LPCSTR pszSrc - source string
  504. //
  505. // Returns: LPSTR - returns NULL if pszSrc is NULL or the Alloc fails,
  506. // otherwise it returns the newly allocated buffer with
  507. // a copy of pszSrc in it.
  508. //
  509. // History: quintinb Created Header and changed name to include Alloc 4/9/99
  510. //
  511. //+----------------------------------------------------------------------------
  512. CMUTILAPI LPSTR CmStrCpyAllocA(LPCSTR pszSrc)
  513. {
  514. LPSTR pszBuffer = NULL;
  515. if (pszSrc)
  516. {
  517. pszBuffer = (LPSTR) CmMalloc(lstrlenA(pszSrc) + 1);
  518. if (pszBuffer)
  519. {
  520. lstrcpyA(pszBuffer, pszSrc);
  521. }
  522. }
  523. return (pszBuffer);
  524. }
  525. //+----------------------------------------------------------------------------
  526. //
  527. // Function: CmStrCpyAllocW
  528. //
  529. // Synopsis: Copies pszSrc into a newly allocated buffer (using CmMalloc) and
  530. // returns the buffer to its caller who is responsible for freeing
  531. // the buffer.
  532. //
  533. // Arguments: LPCSTR pszSrc - source string
  534. //
  535. // Returns: LPSTR - returns NULL if pszSrc is NULL or the Alloc fails,
  536. // otherwise it returns the newly allocated buffer with
  537. // a copy of pszSrc in it.
  538. //
  539. // History: quintinb Created Header and changed name to include Alloc 4/9/99
  540. //
  541. //+----------------------------------------------------------------------------
  542. CMUTILAPI LPWSTR CmStrCpyAllocW(LPCWSTR pszSrc)
  543. {
  544. LPWSTR pszBuffer = NULL;
  545. if (pszSrc)
  546. {
  547. size_t nLen = lstrlenU(pszSrc) + 1;
  548. pszBuffer = (LPWSTR) CmMalloc(nLen*sizeof(WCHAR));
  549. if (pszBuffer)
  550. {
  551. lstrcpyU(pszBuffer, pszSrc);
  552. }
  553. }
  554. return (pszBuffer);
  555. }
  556. //+----------------------------------------------------------------------------
  557. //
  558. // Function: CmStrCatAllocA
  559. //
  560. // Synopsis: This function reallocs the passed in string to a size large enough
  561. // to hold the original data and the concatenates the new string onto
  562. // the original string.
  563. //
  564. // Arguments: LPSTR *ppszDst - original string
  565. // LPCSTR pszSrc - new piece of string to concatenate
  566. //
  567. // Returns: LPSTR - pointer to the concatenated string
  568. //
  569. // History: quintinb Created Header 4/9/99
  570. //
  571. //+----------------------------------------------------------------------------
  572. CMUTILAPI LPSTR CmStrCatAllocA(LPSTR *ppszDst, LPCSTR pszSrc)
  573. {
  574. if (!ppszDst)
  575. {
  576. return NULL;
  577. }
  578. if (pszSrc && *pszSrc)
  579. {
  580. DWORD dwSize = (lstrlenA(*ppszDst) + lstrlenA(pszSrc) + 1);
  581. LPSTR pszTmp = (LPSTR)CmRealloc((LPVOID)*ppszDst, dwSize);
  582. if (NULL != pszTmp)
  583. {
  584. lstrcatA(pszTmp, pszSrc);
  585. *ppszDst = pszTmp;
  586. }
  587. }
  588. return (*ppszDst);
  589. }
  590. //+----------------------------------------------------------------------------
  591. //
  592. // Function: CmStrCatAllocW
  593. //
  594. // Synopsis: This function reallocs the passed in string to a size large enough
  595. // to hold the original data and the concatenates the new string onto
  596. // the original string.
  597. //
  598. // Arguments: LPWSTR *ppszDst - original string
  599. // LPCWSTR pszSrc - new piece of string to concatenate
  600. //
  601. // Returns: LPWSTR - pointer to the concatenated string
  602. //
  603. // History: quintinb Created Header 4/9/99
  604. //
  605. //+----------------------------------------------------------------------------
  606. CMUTILAPI LPWSTR CmStrCatAllocW(LPWSTR *ppszDst, LPCWSTR pszSrc)
  607. {
  608. if (!ppszDst)
  609. {
  610. return NULL;
  611. }
  612. if (pszSrc && *pszSrc)
  613. {
  614. DWORD dwSize = (lstrlenU(*ppszDst) + lstrlenU(pszSrc) + 1)*sizeof(WCHAR);
  615. LPWSTR pszTmp = (LPWSTR)CmRealloc((LPVOID)*ppszDst, dwSize);
  616. if (NULL != pszTmp)
  617. {
  618. lstrcatU(pszTmp, pszSrc);
  619. *ppszDst = pszTmp;
  620. }
  621. }
  622. return (*ppszDst);
  623. }
  624. //+----------------------------------------------------------------------------
  625. //
  626. // Function: CmStrchrA
  627. //
  628. // Synopsis: This function returns the first occurence of ch in the string pszString.
  629. //
  630. // Arguments: LPCSTR pszString - String to search in
  631. // CHAR ch - character to look for
  632. //
  633. // Returns: LPSTR - pointer to the first occurence of the Character ch in pszString
  634. //
  635. // History: quintinb Created Header 4/9/99
  636. //
  637. //+----------------------------------------------------------------------------
  638. CMUTILAPI LPSTR WINAPI CmStrchrA(LPCSTR pszString, const char ch)
  639. {
  640. LPSTR pszTmp = (LPSTR)pszString;
  641. if (NULL == pszTmp)
  642. {
  643. CMASSERTMSG(FALSE, TEXT("CmStrchr - NULL pointer passed"));
  644. return NULL;
  645. }
  646. while (*pszTmp && (*pszTmp != ch))
  647. {
  648. pszTmp = CharNextA(pszTmp);
  649. }
  650. if (*pszTmp == ch)
  651. {
  652. return pszTmp;
  653. }
  654. return NULL;
  655. }
  656. //+----------------------------------------------------------------------------
  657. //
  658. // Function: CmStrchrW
  659. //
  660. // Synopsis: This function returns the first occurence of ch in the string pszString.
  661. //
  662. // Arguments: LPCWSTR pszString - String to search in
  663. // WCHAR ch - character to look for
  664. //
  665. // Returns: LPWSTR - pointer to the first occurence of the Character ch in pszString
  666. //
  667. // History: quintinb Created Header 4/9/99
  668. //
  669. //+----------------------------------------------------------------------------
  670. CMUTILAPI LPWSTR WINAPI CmStrchrW(LPCWSTR pszString, const WCHAR ch)
  671. {
  672. LPWSTR pszTmp = (LPWSTR)pszString;
  673. if (NULL == pszTmp)
  674. {
  675. CMASSERTMSG(FALSE, TEXT("CmStrchr - NULL pointer passed"));
  676. return NULL;
  677. }
  678. while (*pszTmp && (*pszTmp != ch))
  679. {
  680. pszTmp = CharNextU(pszTmp);
  681. }
  682. if (*pszTmp == ch)
  683. {
  684. return pszTmp;
  685. }
  686. return NULL;
  687. }
  688. //+----------------------------------------------------------------------------
  689. //
  690. // Function: CmStrrchrA
  691. //
  692. // Synopsis: Find the last occurence of a character in a string
  693. //
  694. // Arguments: LPCSTR pszString - string to search in
  695. // CHAR ch - character to look for
  696. //
  697. // Returns: LPSTR - NULL if the char is not found, a pointer to the char in
  698. // the string otherwise
  699. //
  700. // History: quintinb Created Header and cleaned up 4/9/99
  701. //
  702. //+----------------------------------------------------------------------------
  703. CMUTILAPI LPSTR CmStrrchrA (LPCSTR pszString, const char ch)
  704. {
  705. LPSTR pszTmp = NULL;
  706. LPSTR pszCurrent = (LPSTR)pszString;
  707. if (NULL == pszString)
  708. {
  709. CMASSERTMSG(FALSE, TEXT("CmStrrchr - NULL pointer passed"));
  710. }
  711. else
  712. {
  713. while (TEXT('\0') != *pszCurrent)
  714. {
  715. if (ch == (*pszCurrent))
  716. {
  717. pszTmp = pszCurrent;
  718. }
  719. pszCurrent = CharNextA(pszCurrent);
  720. }
  721. }
  722. return pszTmp;
  723. }
  724. //+----------------------------------------------------------------------------
  725. //
  726. // Function: CmStrrchrW
  727. //
  728. // Synopsis: Find the last occurence of a character in a string
  729. //
  730. // Arguments: LPCWSTR pszString - string to search in
  731. // WCHAR ch - character to look for
  732. //
  733. // Returns: LPWSTR - NULL if the char is not found, a pointer to the char in
  734. // the string otherwise
  735. //
  736. // History: quintinb Created Header and cleaned up 4/9/99
  737. //
  738. //+----------------------------------------------------------------------------
  739. CMUTILAPI LPWSTR CmStrrchrW (LPCWSTR pszString, const WCHAR ch)
  740. {
  741. LPWSTR pszTmp = NULL;
  742. LPWSTR pszCurrent = (LPWSTR)pszString;
  743. if (NULL == pszString)
  744. {
  745. CMASSERTMSG(FALSE, TEXT("CmStrrchr - NULL pointer passed"));
  746. }
  747. else
  748. {
  749. while (TEXT('\0') != *pszCurrent)
  750. {
  751. if (ch == (*pszCurrent))
  752. {
  753. pszTmp = pszCurrent;
  754. }
  755. pszCurrent = CharNextU(pszCurrent);
  756. }
  757. }
  758. return pszTmp;
  759. }
  760. //+----------------------------------------------------------------------------
  761. //
  762. // Function: CmStrtokA
  763. //
  764. // Synopsis: CM implementation of strtok
  765. //
  766. // Arguments: LPSTR pszStr - string to tokenize or NULL if getting a second token
  767. // LPCSTR pszControl - set of token chars
  768. //
  769. // Returns: LPSTR - NULL if no token could be found or a pointer to a token string.
  770. //
  771. // History: quintinb Created Header and cleaned up for UNICODE conversion 4/9/99
  772. //
  773. //+----------------------------------------------------------------------------
  774. CMUTILAPI LPSTR CmStrtokA(LPSTR pszStr, LPCSTR pszControl)
  775. {
  776. LPSTR pszToken;
  777. LPSTR pszTmpStr;
  778. LPCSTR pszTmpCtl;
  779. LPSTR pszTmpDelim;
  780. //
  781. // If the pszStr param is NULL, then we need to retrieve the stored string
  782. //
  783. if (NULL != pszStr)
  784. {
  785. pszTmpStr = pszStr;
  786. }
  787. else
  788. {
  789. pszTmpStr = (LPSTR)TlsGetValue(g_dwTlsIndex);
  790. }
  791. //
  792. // Find beginning of token (skip over leading delimiters). Note that
  793. // there is no token if this loop sets string to point to the terminal
  794. // null (*string == '\0')
  795. //
  796. while (*pszTmpStr)
  797. {
  798. for (pszTmpCtl = pszControl; *pszTmpCtl && *pszTmpCtl != *pszTmpStr;
  799. pszTmpCtl = CharNextA(pszTmpCtl))
  800. {
  801. ; // do nothing
  802. }
  803. if (!*pszTmpCtl)
  804. {
  805. break;
  806. }
  807. pszTmpStr = CharNextA(pszTmpStr);
  808. }
  809. pszToken = pszTmpStr;
  810. //
  811. // Find the end of the token. If it is not the end of the string,
  812. // put a null there.
  813. //
  814. for ( ; *pszTmpStr ; pszTmpStr = CharNextA(pszTmpStr))
  815. {
  816. for (pszTmpCtl = pszControl; *pszTmpCtl && *pszTmpCtl != *pszTmpStr;
  817. pszTmpCtl = CharNextA(pszTmpCtl))
  818. {
  819. ; // Do nothing
  820. }
  821. if (*pszTmpCtl)
  822. {
  823. pszTmpDelim = pszTmpStr;
  824. pszTmpStr = CharNextA(pszTmpStr);
  825. *pszTmpDelim = '\0';
  826. break;
  827. }
  828. }
  829. //
  830. // Update nextoken (or the corresponding field in the per-thread data structure
  831. //
  832. TlsSetValue(g_dwTlsIndex, (LPVOID)pszTmpStr);
  833. //
  834. // Determine if a token has been found.
  835. //
  836. if (pszToken == pszTmpStr)
  837. {
  838. return NULL;
  839. }
  840. else
  841. {
  842. return pszToken;
  843. }
  844. }
  845. //+----------------------------------------------------------------------------
  846. //
  847. // Function: CmStrtokW
  848. //
  849. // Synopsis: CM implementation of strtok
  850. //
  851. // Arguments: LPWSTR pszStr - string to tokenize or NULL if getting a second tokey
  852. // LPCWSTR pszControl - set of token chars
  853. //
  854. // Returns: LPWSTR - NULL if no token could be found or a pointer to a token string.
  855. //
  856. // History: quintinb Created Header and cleaned up for UNICODE conversion 4/9/99
  857. //
  858. //+----------------------------------------------------------------------------
  859. CMUTILAPI LPWSTR CmStrtokW(LPWSTR pszStr, LPCWSTR pszControl)
  860. {
  861. LPWSTR pszToken;
  862. LPWSTR pszTmpStr;
  863. LPWSTR pszTmpCtl;
  864. LPWSTR pszTmpDelim;
  865. //
  866. // If the pszStr param is NULL, then we need to retrieve the stored string
  867. //
  868. if (NULL != pszStr)
  869. {
  870. pszTmpStr = pszStr;
  871. }
  872. else
  873. {
  874. pszTmpStr = (LPWSTR)TlsGetValue(g_dwTlsIndex);
  875. }
  876. //
  877. // Find beginning of token (skip over leading delimiters). Note that
  878. // there is no token iff this loop sets string to point to the terminal
  879. // null (*string == '\0')
  880. //
  881. while (*pszTmpStr)
  882. {
  883. for (pszTmpCtl = (LPWSTR)pszControl; *pszTmpCtl && *pszTmpCtl != *pszTmpStr;
  884. pszTmpCtl = CharNextU(pszTmpCtl))
  885. {
  886. ; // do nothing
  887. }
  888. if (!*pszTmpCtl)
  889. {
  890. break;
  891. }
  892. pszTmpStr = CharNextU(pszTmpStr);
  893. }
  894. pszToken = pszTmpStr;
  895. //
  896. // Find the end of the token. If it is not the end of the string,
  897. // put a null there.
  898. //
  899. for ( ; *pszTmpStr ; pszTmpStr = CharNextU(pszTmpStr))
  900. {
  901. for (pszTmpCtl = (LPWSTR)pszControl; *pszTmpCtl && *pszTmpCtl != *pszTmpStr;
  902. pszTmpCtl = CharNextU(pszTmpCtl))
  903. {
  904. ; // Do nothing
  905. }
  906. if (*pszTmpCtl)
  907. {
  908. pszTmpDelim = pszTmpStr;
  909. pszTmpStr = CharNextU(pszTmpStr);
  910. *pszTmpDelim = L'\0';
  911. break;
  912. }
  913. }
  914. //
  915. // Update nextoken (or the corresponding field in the per-thread data structure
  916. //
  917. TlsSetValue(g_dwTlsIndex, (LPVOID)pszTmpStr);
  918. //
  919. // Determine if a token has been found.
  920. //
  921. if (pszToken == pszTmpStr)
  922. {
  923. return NULL;
  924. }
  925. else
  926. {
  927. return pszToken;
  928. }
  929. }
  930. //+----------------------------------------------------------------------------
  931. //
  932. // Function: CmStrStrA
  933. //
  934. // Synopsis: Simple replacement for StrStr from C runtime
  935. //
  936. // Arguments: LPCTSTR pszString - The string to search in
  937. // LPCTSTR pszSubString - The string to search for
  938. //
  939. // Returns: LPTSTR - Ptr to the first occurence of pszSubString in pszString.
  940. // NULL if pszSubString does not occur in pszString
  941. //
  942. //
  943. // History: nickball Created Header 04/01/98
  944. // nickball Added ptr check 02/21/99
  945. // quintinb rewrote for unicode conversion 04/08/99
  946. //
  947. //+----------------------------------------------------------------------------
  948. CMUTILAPI LPSTR CmStrStrA(LPCSTR pszString, LPCSTR pszSubString)
  949. {
  950. //
  951. // Check the inputs
  952. //
  953. MYDBGASSERT(pszString);
  954. MYDBGASSERT(pszSubString);
  955. if (NULL == pszSubString || NULL == pszString)
  956. {
  957. return NULL;
  958. }
  959. //
  960. // Check to make sure we have something to look for
  961. //
  962. if (TEXT('\0') == pszSubString[0])
  963. {
  964. return((LPSTR)pszString);
  965. }
  966. //
  967. // Okay, start looking for the string
  968. //
  969. LPSTR pszCurrent = (LPSTR)pszString;
  970. LPSTR pszTmp1;
  971. LPSTR pszTmp2;
  972. while (*pszCurrent)
  973. {
  974. pszTmp1 = pszCurrent;
  975. pszTmp2 = (LPSTR) pszSubString;
  976. while (*pszTmp1 && *pszTmp2 && ((*pszTmp1) == (*pszTmp2)))
  977. {
  978. pszTmp1 = CharNextA(pszTmp1);
  979. pszTmp2 = CharNextA(pszTmp2);
  980. }
  981. if (TEXT('\0') == *pszTmp2)
  982. {
  983. return pszCurrent;
  984. }
  985. pszCurrent = CharNextA(pszCurrent);
  986. }
  987. return NULL;
  988. }
  989. //+----------------------------------------------------------------------------
  990. //
  991. // Function: CmStrStrW
  992. //
  993. // Synopsis: Simple replacement for StrStr from C runtime
  994. //
  995. // Arguments: LPCTSTR pszString - The string to search in
  996. // LPCTSTR pszSubString - The string to search for
  997. //
  998. // Returns: LPTSTR - Ptr to the first occurence of pszSubString in pszString.
  999. // NULL if pszSubString does not occur in pszString
  1000. //
  1001. //
  1002. // History: nickball Created Header 04/01/98
  1003. // nickball Added ptr check 02/21/99
  1004. // quintinb rewrote for unicode conversion 04/08/99
  1005. //
  1006. //+----------------------------------------------------------------------------
  1007. CMUTILAPI LPWSTR CmStrStrW(LPCWSTR pszString, LPCWSTR pszSubString)
  1008. {
  1009. //
  1010. // Check the inputs
  1011. //
  1012. MYDBGASSERT(pszString);
  1013. MYDBGASSERT(pszSubString);
  1014. if (NULL == pszSubString || NULL == pszString)
  1015. {
  1016. return NULL;
  1017. }
  1018. //
  1019. // Check to make sure we have something to look for
  1020. //
  1021. if (TEXT('\0') == pszSubString[0])
  1022. {
  1023. return((LPWSTR)pszString);
  1024. }
  1025. //
  1026. // Okay, start looking for the string
  1027. //
  1028. LPWSTR pszCurrent = (LPWSTR)pszString;
  1029. LPWSTR pszTmp1;
  1030. LPWSTR pszTmp2;
  1031. while (*pszCurrent)
  1032. {
  1033. pszTmp1 = pszCurrent;
  1034. pszTmp2 = (LPWSTR) pszSubString;
  1035. while (*pszTmp1 && *pszTmp2 && ((*pszTmp1) == (*pszTmp2)))
  1036. {
  1037. pszTmp1 = CharNextU(pszTmp1);
  1038. pszTmp2 = CharNextU(pszTmp2);
  1039. }
  1040. if (TEXT('\0') == *pszTmp2)
  1041. {
  1042. return pszCurrent;
  1043. }
  1044. pszCurrent = CharNextU(pszCurrent);
  1045. }
  1046. return NULL;
  1047. }