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.

447 lines
9.8 KiB

  1. /*
  2. * util.c - Utility routines.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. /****************************** Public Functions *****************************/
  9. #ifdef WINNT
  10. //
  11. // These are some helper functions for handling Unicode strings
  12. //
  13. /*----------------------------------------------------------
  14. Purpose: This function converts a wide-char string to a multi-byte
  15. string.
  16. If pszBuf is non-NULL and the converted string can fit in
  17. pszBuf, then *ppszAnsi will point to the given buffer.
  18. Otherwise, this function will allocate a buffer that can
  19. hold the converted string.
  20. If pszWide is NULL, then *ppszAnsi will be freed. Note
  21. that pszBuf must be the same pointer between the call
  22. that converted the string and the call that frees the
  23. string.
  24. Returns: TRUE
  25. FALSE (if out of memory)
  26. Cond: --
  27. */
  28. PRIVATE_CODE
  29. BOOL
  30. AnsiFromUnicode(
  31. LPSTR * ppszAnsi,
  32. LPCWSTR pwszWide, // NULL to clean up
  33. LPSTR pszBuf,
  34. int cchBuf)
  35. {
  36. BOOL bRet;
  37. // Convert the string?
  38. if (pwszWide)
  39. {
  40. // Yes; determine the converted string length
  41. int cch;
  42. LPSTR psz;
  43. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, NULL, 0, NULL, NULL);
  44. // String too big, or is there no buffer?
  45. if (cch > cchBuf || NULL == pszBuf)
  46. {
  47. // Yes; allocate space
  48. cchBuf = cch + 1;
  49. psz = (LPSTR)LocalAlloc(LPTR, CbFromCchA(cchBuf));
  50. }
  51. else
  52. {
  53. // No; use the provided buffer
  54. ASSERT(pszBuf);
  55. psz = pszBuf;
  56. }
  57. if (psz)
  58. {
  59. // Convert the string
  60. cch = WideCharToMultiByte(CP_ACP, 0, pwszWide, -1, psz, cchBuf, NULL, NULL);
  61. bRet = (0 < cch);
  62. }
  63. else
  64. {
  65. bRet = FALSE;
  66. }
  67. *ppszAnsi = psz;
  68. }
  69. else
  70. {
  71. // No; was this buffer allocated?
  72. if (*ppszAnsi && pszBuf != *ppszAnsi)
  73. {
  74. // Yes; clean up
  75. LocalFree((HLOCAL)*ppszAnsi);
  76. *ppszAnsi = NULL;
  77. }
  78. bRet = TRUE;
  79. }
  80. return bRet;
  81. }
  82. /*----------------------------------------------------------
  83. Purpose: Wide-char wrapper for StrToIntExA.
  84. Returns: see StrToIntExA
  85. Cond: --
  86. */
  87. PUBLIC_CODE
  88. BOOL
  89. StrToIntExW(
  90. LPCWSTR pwszString,
  91. DWORD dwFlags, // STIF_ bitfield
  92. int FAR * piRet)
  93. {
  94. CHAR szBuf[MAX_BUF];
  95. LPSTR pszString;
  96. BOOL bRet = AnsiFromUnicode(&pszString, pwszString, szBuf, SIZECHARS(szBuf));
  97. if (bRet)
  98. {
  99. bRet = StrToIntExA(pszString, dwFlags, piRet);
  100. AnsiFromUnicode(&pszString, NULL, szBuf, 0);
  101. }
  102. return bRet;
  103. }
  104. /*----------------------------------------------------------
  105. Purpose: Returns an integer value specifying the length of
  106. the substring in psz that consists entirely of
  107. characters in pszSet. If psz begins with a character
  108. not in pszSet, then this function returns 0.
  109. This is a DBCS-safe version of the CRT strspn().
  110. Returns: see above
  111. Cond: --
  112. */
  113. PUBLIC_CODE
  114. int
  115. StrSpnW(
  116. LPCWSTR psz,
  117. LPCWSTR pszSet)
  118. {
  119. LPCWSTR pszT;
  120. LPCWSTR pszSetT;
  121. ASSERT(psz);
  122. ASSERT(pszSet);
  123. // Go thru the string to be inspected
  124. for (pszT = psz; *pszT; pszT++)
  125. {
  126. // Go thru the char set
  127. for (pszSetT = pszSet; *pszSetT != *pszT; pszSetT++)
  128. {
  129. if (0 == *pszSetT)
  130. {
  131. // Reached end of char set without finding a match
  132. return (int)(pszT - psz);
  133. }
  134. }
  135. }
  136. return (int)(pszT - psz);
  137. }
  138. /*----------------------------------------------------------
  139. Purpose: Returns a pointer to the first occurrence of a character
  140. in psz that belongs to the set of characters in pszSet.
  141. The search does not include the null terminator.
  142. Returns: see above
  143. Cond: --
  144. */
  145. PUBLIC_CODE
  146. LPWSTR
  147. StrPBrkW(
  148. IN LPCWSTR psz,
  149. IN LPCWSTR pszSet)
  150. {
  151. LPCWSTR pszSetT;
  152. ASSERT(psz);
  153. ASSERT(pszSet);
  154. // Go thru the string to be inspected
  155. while (*psz)
  156. {
  157. // Go thru the char set
  158. for (pszSetT = pszSet; *pszSetT; pszSetT++)
  159. {
  160. if (*psz == *pszSetT)
  161. {
  162. // Found first character that matches
  163. return (LPWSTR)psz; // Const -> non-const
  164. }
  165. }
  166. psz++;
  167. }
  168. return NULL;
  169. }
  170. #endif // WINNT
  171. /*----------------------------------------------------------
  172. Purpose: Special verion of atoi. Supports hexadecimal too.
  173. If this function returns FALSE, *piRet is set to 0.
  174. Returns: TRUE if the string is a number, or contains a partial number
  175. FALSE if the string is not a number
  176. Cond: --
  177. */
  178. PUBLIC_CODE
  179. BOOL
  180. StrToIntExA(
  181. LPCSTR pszString,
  182. DWORD dwFlags, // STIF_ bitfield
  183. int FAR * piRet)
  184. {
  185. #define IS_DIGIT(ch) InRange(ch, '0', '9')
  186. BOOL bRet;
  187. int n;
  188. BOOL bNeg = FALSE;
  189. LPCSTR psz;
  190. LPCSTR pszAdj;
  191. // Skip leading whitespace
  192. //
  193. for (psz = pszString; *psz == ' ' || *psz == '\n' || *psz == '\t'; psz = CharNextA(psz))
  194. ;
  195. // Determine possible explicit signage
  196. //
  197. if (*psz == '+' || *psz == '-')
  198. {
  199. bNeg = (*psz == '+') ? FALSE : TRUE;
  200. psz++;
  201. }
  202. // Or is this hexadecimal?
  203. //
  204. pszAdj = CharNextA(psz);
  205. if ((STIF_SUPPORT_HEX & dwFlags) &&
  206. *psz == '0' && (*pszAdj == 'x' || *pszAdj == 'X'))
  207. {
  208. // Yes
  209. // (Never allow negative sign with hexadecimal numbers)
  210. bNeg = FALSE;
  211. psz = CharNextA(pszAdj);
  212. pszAdj = psz;
  213. // Do the conversion
  214. //
  215. for (n = 0; ; psz = CharNextA(psz))
  216. {
  217. if (IS_DIGIT(*psz))
  218. n = 0x10 * n + *psz - '0';
  219. else
  220. {
  221. CHAR ch = *psz;
  222. int n2;
  223. if (ch >= 'a')
  224. ch -= 'a' - 'A';
  225. n2 = ch - 'A' + 0xA;
  226. if (n2 >= 0xA && n2 <= 0xF)
  227. n = 0x10 * n + n2;
  228. else
  229. break;
  230. }
  231. }
  232. // Return TRUE if there was at least one digit
  233. bRet = (psz != pszAdj);
  234. }
  235. else
  236. {
  237. // No
  238. pszAdj = psz;
  239. // Do the conversion
  240. for (n = 0; IS_DIGIT(*psz); psz = CharNextA(psz))
  241. n = 10 * n + *psz - '0';
  242. // Return TRUE if there was at least one digit
  243. bRet = (psz != pszAdj);
  244. }
  245. *piRet = bNeg ? -n : n;
  246. return bRet;
  247. }
  248. /*----------------------------------------------------------
  249. Purpose: Returns an integer value specifying the length of
  250. the substring in psz that consists entirely of
  251. characters in pszSet. If psz begins with a character
  252. not in pszSet, then this function returns 0.
  253. This is a DBCS-safe version of the CRT strspn().
  254. Returns: see above
  255. Cond: --
  256. */
  257. PUBLIC_CODE
  258. int
  259. StrSpnA(
  260. LPCSTR psz,
  261. LPCSTR pszSet)
  262. {
  263. LPCSTR pszT;
  264. LPCSTR pszSetT;
  265. // Go thru the string to be inspected
  266. for (pszT = psz; *pszT; pszT = CharNextA(pszT))
  267. {
  268. // Go thru the char set
  269. for (pszSetT = pszSet; *pszSetT; pszSetT = CharNextA(pszSetT))
  270. {
  271. if (*pszSetT == *pszT)
  272. {
  273. if ( !IsDBCSLeadByte(*pszSetT) )
  274. {
  275. break; // Chars match
  276. }
  277. else if (pszSetT[1] == pszT[1])
  278. {
  279. break; // Chars match
  280. }
  281. }
  282. }
  283. // End of char set?
  284. if (0 == *pszSetT)
  285. {
  286. break; // Yes, no match on this inspected char
  287. }
  288. }
  289. return (int)(pszT - psz);
  290. }
  291. /*----------------------------------------------------------
  292. Purpose: Returns a pointer to the first occurrence of a character
  293. in psz that belongs to the set of characters in pszSet.
  294. The search does not include the null terminator.
  295. If psz contains no characters that are in the set of
  296. characters in pszSet, this function returns NULL.
  297. This function is DBCS-safe.
  298. Returns: see above
  299. Cond: --
  300. */
  301. PUBLIC_CODE
  302. LPSTR
  303. StrPBrkA(
  304. LPCSTR psz,
  305. LPCSTR pszSet)
  306. {
  307. LPCSTR pszSetT;
  308. ASSERT(psz);
  309. ASSERT(pszSet);
  310. while (*psz)
  311. {
  312. for (pszSetT = pszSet; *pszSetT; pszSetT = CharNextA(pszSetT))
  313. {
  314. if (*psz == *pszSetT)
  315. {
  316. // Found first character that matches
  317. return (LPSTR)psz; // Const -> non-const
  318. }
  319. }
  320. psz = CharNextA(psz);
  321. }
  322. return NULL;
  323. }
  324. PUBLIC_CODE BOOL IsPathDirectory(PCSTR pcszPath)
  325. {
  326. DWORD dwAttr;
  327. ASSERT(IS_VALID_STRING_PTR(pcszPath, CSTR));
  328. dwAttr = GetFileAttributes(pcszPath);
  329. return(dwAttr != -1 &&
  330. IS_FLAG_SET(dwAttr, FILE_ATTRIBUTE_DIRECTORY));
  331. }
  332. PUBLIC_CODE BOOL KeyExists(HKEY hkeyRoot, PCSTR pcszSubKey)
  333. {
  334. BOOL bExists;
  335. HKEY hkey;
  336. ASSERT(IS_VALID_HANDLE(hkeyRoot, KEY));
  337. ASSERT(IS_VALID_STRING_PTR(pcszSubKey, CSTR));
  338. bExists = (RegOpenKey(hkeyRoot, pcszSubKey, &hkey) == ERROR_SUCCESS);
  339. if (bExists)
  340. EVAL(RegCloseKey(hkey) == ERROR_SUCCESS);
  341. return(bExists);
  342. }
  343. #ifdef DEBUG
  344. PUBLIC_CODE BOOL IsStringContained(PCSTR pcszBigger, PCSTR pcszSuffix)
  345. {
  346. ASSERT(IS_VALID_STRING_PTR(pcszBigger, CSTR));
  347. ASSERT(IS_VALID_STRING_PTR(pcszSuffix, CSTR));
  348. return(pcszSuffix >= pcszBigger &&
  349. pcszSuffix <= pcszBigger + lstrlen(pcszBigger));
  350. }
  351. #endif