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.

677 lines
21 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: strings.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains all the string handling APIs and functions. Since
  7. * they don't access server-specific data they belong here in the client DLL.
  8. *
  9. * History:
  10. * 10-18-90 DarrinM Created.
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /* LATER these should be in a public header file!!!
  15. * Assorted defines used to support the standard Windows ANSI code page
  16. * (now known as code page 1252 and officially registered by IBM).
  17. * This is intended only for the PDK release. Subsequent releases will
  18. * use the NLSAPI and Unicode.
  19. */
  20. #define LATIN_CAPITAL_LETTER_A_GRAVE (CHAR)0xc0
  21. #define LATIN_CAPITAL_LETTER_THORN (CHAR)0xde
  22. #define LATIN_SMALL_LETTER_SHARP_S (CHAR)0xdf
  23. #define LATIN_SMALL_LETTER_Y_DIAERESIS (CHAR)0xff
  24. #define DIVISION_SIGN (CHAR)0xf7
  25. #define MULTIPLICATION_SIGN (CHAR)0xd7
  26. /***************************************************************************\
  27. * CharLowerA (API)
  28. *
  29. * Convert either a single character or an entire string to lower case. The
  30. * two cases are differentiated by checking the high-word of psz. If it is
  31. * 0 then we just convert the low-word of psz.
  32. *
  33. * History:
  34. * 11-26-90 DarrinM Created non-NLS version.
  35. * 06-22-91 GregoryW Modified to support code page 1252. This is for
  36. * the PDK release only. After the PDK this routine
  37. * will be modified to use the NLSAPI. Also renamed
  38. * API to conform to new naming conventions. AnsiLower
  39. * is now a #define which resolves to this routine.
  40. \***************************************************************************/
  41. FUNCLOG1(LOG_GENERAL, LPSTR, WINAPI, CharLowerA, LPSTR, psz)
  42. LPSTR WINAPI CharLowerA(
  43. LPSTR psz)
  44. {
  45. NTSTATUS st;
  46. /*
  47. * Early out for NULL string or '\0'
  48. */
  49. if (psz == NULL) {
  50. return psz;
  51. }
  52. if (!IS_PTR(psz)) {
  53. WCHAR wch;
  54. #ifdef FE_SB // CharLowerA()
  55. /*
  56. * if only DBCS Leadbyte was passed, just return the character.
  57. * Same behavior as Windows 3.1J and Windows 95 FarEast version.
  58. */
  59. if (IS_DBCS_ENABLED() && IsDBCSLeadByte((BYTE)(ULONG_PTR)psz)) {
  60. return psz;
  61. }
  62. #endif // FE_SB
  63. //
  64. // LATER 14 Feb 92 GregoryW
  65. // For DBCS code pages is a double byte character ever
  66. // passed in the low word of psz or is the high nibble
  67. // of the low word always ignored?
  68. //
  69. st = RtlMultiByteToUnicodeN(&wch, sizeof(WCHAR), NULL, (PCH)&psz, sizeof(CHAR));
  70. if (!NT_SUCCESS(st)) {
  71. /*
  72. * Failed! Caller is not expecting failure, CharLowerA does not
  73. * have a failure indicator, so just return the original character.
  74. */
  75. RIPMSG1(RIP_WARNING, "CharLowerA(%#p) failed\n", psz);
  76. } else {
  77. /*
  78. * The next two calls never fail.
  79. */
  80. LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_LOWERCASE, &wch, 1, &wch, 1);
  81. RtlUnicodeToMultiByteN((PCH)&psz, sizeof(CHAR), NULL, &wch, sizeof(WCHAR));
  82. }
  83. return psz;
  84. }
  85. /*
  86. * psz is a null-terminated string
  87. */
  88. CharLowerBuffA(psz, strlen(psz)+1);
  89. return psz;
  90. }
  91. /***************************************************************************\
  92. * CharUpperA (API)
  93. *
  94. * Convert either a single character or an entire string to upper case. The
  95. * two cases are differentiated by checking the high-word of psz. If it is
  96. * 0 then we just convert the low-word of psz.
  97. *
  98. * History:
  99. * 12-03-90 IanJa derived from DarrinM's non-NLS AnsiLower
  100. * 06-22-91 GregoryW Modified to support code page 1252. This is for
  101. * the PDK release only. After the PDK this routine
  102. * will be modified to use the NLSAPI. Also renamed
  103. * API to conform to new naming conventions. AnsiUpper
  104. * is now a #define which resolves to this routine.
  105. \***************************************************************************/
  106. FUNCLOG1(LOG_GENERAL, LPSTR, WINAPI, CharUpperA, LPSTR, psz)
  107. LPSTR WINAPI CharUpperA(
  108. LPSTR psz)
  109. {
  110. NTSTATUS st;
  111. /*
  112. * Early out for NULL string or '\0'
  113. */
  114. if (psz == NULL) {
  115. return psz;
  116. }
  117. if (!IS_PTR(psz)) {
  118. WCHAR wch;
  119. #ifdef FE_SB // CharLowerA()
  120. /*
  121. * if only DBCS Leadbyte was passed, just return the character.
  122. * Same behavior as Windows 3.1J and Windows 95 FarEast version.
  123. */
  124. if (IS_DBCS_ENABLED() && IsDBCSLeadByte((BYTE)(ULONG_PTR)psz)) {
  125. return psz;
  126. }
  127. #endif // FE_SB
  128. //
  129. // LATER 14 Feb 92 GregoryW
  130. // For DBCS code pages is a double byte character ever
  131. // passed in the low word of psz or is the high nibble
  132. // of the low word always ignored?
  133. //
  134. st = RtlMultiByteToUnicodeN(&wch, sizeof(WCHAR), NULL, (PCH)&psz, sizeof(CHAR));
  135. if (!NT_SUCCESS(st)) {
  136. /*
  137. * Failed! Caller is not expecting failure, CharUpperA does not
  138. * have a failure indicator, so return the original character.
  139. */
  140. RIPMSG1(RIP_WARNING, "CharUpperA(%#p) failed\n", psz);
  141. } else {
  142. /*
  143. * The next two calls never fail.
  144. */
  145. LCMapStringW(LOCALE_USER_DEFAULT, LCMAP_UPPERCASE, &wch, 1, &wch, 1);
  146. RtlUnicodeToMultiByteN((PCH)&psz, sizeof(CHAR), NULL, &wch, sizeof(WCHAR));
  147. }
  148. return psz;
  149. }
  150. /*
  151. * psz is a null-terminated string
  152. */
  153. CharUpperBuffA(psz, strlen(psz)+1);
  154. return psz;
  155. }
  156. /***************************************************************************\
  157. * CharNextA (API)
  158. *
  159. * Move to next character in string unless already at '\0' terminator
  160. * DOES NOT WORK CORRECTLY FOR DBCS (eg: Japanese)
  161. *
  162. * History:
  163. * 12-03-90 IanJa Created non-NLS version.
  164. * 06-22-91 GregoryW Renamed API to conform to new naming conventions.
  165. * AnsiNext is now a #define which resolves to this
  166. * routine. This routine is only intended to support
  167. * code page 1252 for the PDK release.
  168. \***************************************************************************/
  169. FUNCLOG1(LOG_GENERAL, LPSTR, WINAPI, CharNextA, LPCSTR, lpCurrentChar)
  170. LPSTR WINAPI CharNextA(
  171. LPCSTR lpCurrentChar)
  172. {
  173. #ifdef FE_SB // CharNextA(): dbcs enabling
  174. if (IS_DBCS_ENABLED() && IsDBCSLeadByte(*lpCurrentChar)) {
  175. lpCurrentChar++;
  176. }
  177. /*
  178. * if we have only DBCS LeadingByte, we will point string-terminaler.
  179. */
  180. #endif // FE_SB
  181. if (*lpCurrentChar) {
  182. lpCurrentChar++;
  183. }
  184. return (LPSTR)lpCurrentChar;
  185. }
  186. /***************************************************************************\
  187. * CharNextExA (API)
  188. *
  189. * Move to next character in string unless already at '\0' terminator.
  190. *
  191. * History:
  192. * 05-01-95 GregoryW Ported from Win95.
  193. \***************************************************************************/
  194. FUNCLOG3(LOG_GENERAL, LPSTR, WINAPI, CharNextExA, WORD, CodePage, LPCSTR, lpCurrentChar, DWORD, dwFlags)
  195. LPSTR WINAPI CharNextExA(
  196. WORD CodePage,
  197. LPCSTR lpCurrentChar,
  198. DWORD dwFlags)
  199. {
  200. if (lpCurrentChar == (LPSTR)NULL)
  201. {
  202. return (LPSTR)lpCurrentChar;
  203. }
  204. if (IsDBCSLeadByteEx(CodePage, *lpCurrentChar))
  205. {
  206. lpCurrentChar++;
  207. }
  208. if (*lpCurrentChar)
  209. {
  210. lpCurrentChar++;
  211. }
  212. return (LPSTR)lpCurrentChar;
  213. UNREFERENCED_PARAMETER(dwFlags);
  214. }
  215. /***************************************************************************\
  216. * CharPrevA (API)
  217. *
  218. * Move to previous character in string, unless already at start
  219. * DOES NOT WORK CORRECTLY FOR DBCS (eg: Japanese)
  220. *
  221. * History:
  222. * 12-03-90 IanJa Created non-NLS version.
  223. * 06-22-91 GregoryW Renamed API to conform to new naming conventions.
  224. * AnsiPrev is now a #define which resolves to this
  225. * routine. This routine is only intended to support
  226. * code page 1252 for the PDK release.
  227. \***************************************************************************/
  228. FUNCLOG2(LOG_GENERAL, LPSTR, WINAPI, CharPrevA, LPCSTR, lpStart, LPCSTR, lpCurrentChar)
  229. LPSTR WINAPI CharPrevA(
  230. LPCSTR lpStart,
  231. LPCSTR lpCurrentChar)
  232. {
  233. #ifdef FE_SB // CharPrevA : dbcs enabling
  234. if (lpCurrentChar > lpStart) {
  235. if (IS_DBCS_ENABLED()) {
  236. LPCSTR lpChar;
  237. BOOL bDBC = FALSE;
  238. for (lpChar = --lpCurrentChar - 1 ; lpChar >= lpStart ; lpChar--) {
  239. if (!IsDBCSLeadByte(*lpChar))
  240. break;
  241. bDBC = !bDBC;
  242. }
  243. if (bDBC)
  244. lpCurrentChar--;
  245. }
  246. else
  247. lpCurrentChar--;
  248. }
  249. return (LPSTR)lpCurrentChar;
  250. #else
  251. if (lpCurrentChar > lpStart) {
  252. lpCurrentChar--;
  253. }
  254. return (LPSTR)lpCurrentChar;
  255. #endif // FE_SB
  256. }
  257. /***************************************************************************\
  258. * CharPrevExA (API)
  259. *
  260. * Move to previous character in string, unless already at start.
  261. *
  262. * History:
  263. * 05-01-95 GregoryW Ported from Win95.
  264. \***************************************************************************/
  265. FUNCLOG4(LOG_GENERAL, LPSTR, WINAPI, CharPrevExA, WORD, CodePage, LPCSTR, lpStart, LPCSTR, lpCurrentChar, DWORD, dwFlags)
  266. LPSTR WINAPI CharPrevExA(
  267. WORD CodePage,
  268. LPCSTR lpStart,
  269. LPCSTR lpCurrentChar,
  270. DWORD dwFlags)
  271. {
  272. if (lpCurrentChar > lpStart) {
  273. LPCSTR lpChar;
  274. BOOL bDBC = FALSE;
  275. for (lpChar = --lpCurrentChar - 1 ; lpChar >= lpStart ; lpChar--) {
  276. if (!IsDBCSLeadByteEx(CodePage, *lpChar))
  277. break;
  278. bDBC = !bDBC;
  279. }
  280. if (bDBC)
  281. lpCurrentChar--;
  282. }
  283. return (LPSTR)lpCurrentChar;
  284. UNREFERENCED_PARAMETER(dwFlags);
  285. }
  286. /***************************************************************************\
  287. * CharLowerBuffA (API)
  288. *
  289. * History:
  290. * 14-Jan-1991 mikeke from win 3.0
  291. * 06-22-91 GregoryW Renamed API to conform to new naming conventions.
  292. * AnsiLowerBuff is now a #define which resolves to this
  293. * routine. This routine is only intended to support
  294. * code page 1252 for the PDK release.
  295. * 02-20-1992 GregoryW Modified to use NLS API.
  296. \***************************************************************************/
  297. #define CCH_LOCAL_BUFF 256
  298. FUNCLOG2(LOG_GENERAL, DWORD, WINAPI, CharLowerBuffA, LPSTR, psz, DWORD, nLength)
  299. DWORD WINAPI CharLowerBuffA(
  300. LPSTR psz,
  301. DWORD nLength)
  302. {
  303. ULONG cb;
  304. WCHAR awchLocal[CCH_LOCAL_BUFF];
  305. LPWSTR pwszT = awchLocal;
  306. int cwch;
  307. if (nLength == 0) {
  308. return(0);
  309. }
  310. /*
  311. * Convert ANSI to Unicode.
  312. * Use awchLocal if it is big enough, otherwise allocate space.
  313. */
  314. cwch = MBToWCS(
  315. psz, // ANSI buffer
  316. nLength, // length of buffer
  317. &pwszT, // address of Unicode string
  318. (nLength > CCH_LOCAL_BUFF ? -1 : nLength),
  319. (nLength > CCH_LOCAL_BUFF) );
  320. if (cwch != 0) {
  321. CharLowerBuffW(pwszT, cwch);
  322. /*
  323. * This can't fail
  324. */
  325. RtlUnicodeToMultiByteN(
  326. psz, // ANSI string
  327. nLength, // given to us
  328. &cb, // result length
  329. pwszT, // Unicode string
  330. cwch * sizeof(WCHAR)); // length IN BYTES
  331. if (pwszT != awchLocal) {
  332. UserLocalFree(pwszT);
  333. }
  334. return (DWORD)cb;
  335. }
  336. /*
  337. * MBToWCS failed! The caller is not expecting failure,
  338. * so we convert the string to lower case as best we can.
  339. */
  340. RIPMSG2(RIP_WARNING,
  341. "CharLowerBuffA(%#p, %lx) failed\n", psz, nLength);
  342. for (cb=0; cb < nLength; cb++) {
  343. #ifdef FE_SB // CharLowerBuffA(): skip double byte character
  344. if (IS_DBCS_ENABLED() && IsDBCSLeadByte(psz[cb])) {
  345. cb++;
  346. } else if (IsCharUpperA(psz[cb])) {
  347. psz[cb] += 'a'-'A';
  348. }
  349. #else
  350. if (IsCharUpperA(psz[cb])) {
  351. psz[cb] += 'a'-'A';
  352. }
  353. #endif // FE_SB
  354. }
  355. return nLength;
  356. }
  357. /***************************************************************************\
  358. * CharUpperBuffA (API)
  359. *
  360. * History:
  361. * 14-Jan-1991 mikeke from win 3.0
  362. * 06-22-91 GregoryW Renamed API to conform to new naming conventions.
  363. * AnsiUpperBuff is now a #define which resolves to this
  364. * routine. This routine is only intended to support
  365. * code page 1252 for the PDK release.
  366. * 02-Feb-1992 GregoryW Modified to use NLS API.
  367. \***************************************************************************/
  368. FUNCLOG2(LOG_GENERAL, DWORD, WINAPI, CharUpperBuffA, LPSTR, psz, DWORD, nLength)
  369. DWORD WINAPI CharUpperBuffA(
  370. LPSTR psz,
  371. DWORD nLength)
  372. {
  373. DWORD cb;
  374. WCHAR awchLocal[CCH_LOCAL_BUFF];
  375. LPWSTR pwszT = awchLocal;
  376. int cwch;
  377. if (nLength==0) {
  378. return(0);
  379. }
  380. /*
  381. * Convert ANSI to Unicode.
  382. * Use awchLocal if it is big enough, otherwise allocate space.
  383. */
  384. cwch = MBToWCS(
  385. psz, // ANSI buffer
  386. nLength, // length of buffer
  387. &pwszT, // address of Unicode string
  388. (nLength > CCH_LOCAL_BUFF ? -1 : nLength),
  389. (nLength > CCH_LOCAL_BUFF) );
  390. if (cwch != 0) {
  391. CharUpperBuffW(pwszT, cwch);
  392. RtlUnicodeToMultiByteN(
  393. psz, // address of ANSI string
  394. nLength, // given to us
  395. &cb, // result length
  396. pwszT, // Unicode string
  397. cwch * sizeof(WCHAR)); // length IN BYTES
  398. if (pwszT != awchLocal) {
  399. UserLocalFree(pwszT);
  400. }
  401. return (DWORD)cb;
  402. }
  403. /*
  404. * MBToWCS failed! The caller is not expecting failure,
  405. * so we convert the string to upper case as best we can.
  406. */
  407. RIPMSG2(RIP_WARNING,
  408. "CharLowerBuffA(%#p, %lx) failed\n", psz, nLength);
  409. for (cb=0; cb < nLength; cb++) {
  410. #ifdef FE_SB // CharUpperBuffA(): skip double byte characters
  411. if (IS_DBCS_ENABLED() && IsDBCSLeadByte(psz[cb])) {
  412. cb++;
  413. } else if (IsCharLowerA(psz[cb]) &&
  414. /*
  415. * Sometime, LATIN_xxxx code is DBCS LeadingByte depending on ACP.
  416. * In that case, we never come here...
  417. */
  418. (psz[cb] != LATIN_SMALL_LETTER_SHARP_S) &&
  419. (psz[cb] != LATIN_SMALL_LETTER_Y_DIAERESIS)) {
  420. psz[cb] += 'A'-'a';
  421. }
  422. #else
  423. if (IsCharLowerA(psz[cb]) &&
  424. (psz[cb] != LATIN_SMALL_LETTER_SHARP_S) &&
  425. (psz[cb] != LATIN_SMALL_LETTER_Y_DIAERESIS)) {
  426. psz[cb] += 'A'-'a';
  427. }
  428. #endif // FE_SB
  429. }
  430. return nLength;
  431. }
  432. /***************************************************************************\
  433. * IsCharLowerA (API)
  434. *
  435. * History:
  436. * 14-Jan-1991 mikeke from win 3.0
  437. * 22-Jun-1991 GregoryW Modified to support code page 1252 (Windows ANSI
  438. * code page). This is for the PDK only. After the
  439. * PDK this routine will be rewritten to use the
  440. * NLSAPI.
  441. * 02-Feb-1992 GregoryW Modified to use NLS API.
  442. \***************************************************************************/
  443. FUNCLOG1(LOG_GENERAL, BOOL, WINAPI, IsCharLowerA, char, cChar)
  444. BOOL WINAPI IsCharLowerA(
  445. char cChar)
  446. {
  447. WORD ctype1info = 0;
  448. WCHAR wChar = 0;
  449. #ifdef FE_SB // IsCharLowerA()
  450. /*
  451. * if only DBCS Leadbyte was passed, just return FALSE.
  452. * Same behavior as Windows 3.1J and Windows 95 FarEast version.
  453. */
  454. if (IS_DBCS_ENABLED() && IsDBCSLeadByte(cChar)) {
  455. return FALSE;
  456. }
  457. #endif // FE_SB
  458. /*
  459. * The following 2 calls cannot fail here
  460. */
  461. RtlMultiByteToUnicodeN(&wChar, sizeof(WCHAR), NULL, &cChar, sizeof(CHAR));
  462. GetStringTypeW(CT_CTYPE1, &wChar, 1, &ctype1info);
  463. return (ctype1info & C1_LOWER) == C1_LOWER;
  464. }
  465. /***************************************************************************\
  466. * IsCharUpperA (API)
  467. *
  468. * History:
  469. * 22-Jun-1991 GregoryW Created to support code page 1252 (Windows ANSI
  470. * code page). This is for the PDK only. After the
  471. * PDK this routine will be rewritten to use the
  472. * NLSAPI.
  473. * 02-Feb-1992 GregoryW Modified to use NLS API.
  474. \***************************************************************************/
  475. FUNCLOG1(LOG_GENERAL, BOOL, WINAPI, IsCharUpperA, char, cChar)
  476. BOOL WINAPI IsCharUpperA(
  477. char cChar)
  478. {
  479. WORD ctype1info = 0;
  480. WCHAR wChar = 0;
  481. #ifdef FE_SB // IsCharUpperA()
  482. /*
  483. * if only DBCS Leadbyte was passed, just return FALSE.
  484. * Same behavior as Windows 3.1J and Windows 95 FarEast version.
  485. */
  486. if (IS_DBCS_ENABLED() && IsDBCSLeadByte(cChar)) {
  487. return FALSE;
  488. }
  489. #endif // FE_SB
  490. /*
  491. * The following 2 calls cannot fail here
  492. */
  493. RtlMultiByteToUnicodeN(&wChar, sizeof(WCHAR), NULL, &cChar, sizeof(CHAR));
  494. GetStringTypeW(CT_CTYPE1, &wChar, 1, &ctype1info);
  495. return (ctype1info & C1_UPPER) == C1_UPPER;
  496. }
  497. /***************************************************************************\
  498. * IsCharAlphaNumericA (API)
  499. *
  500. * Returns TRUE if character is alphabetical or numerical, otherwise FALSE
  501. *
  502. * History:
  503. * 12-03-90 IanJa Created non-NLS stub version.
  504. * 06-22-91 GregoryW Modified to support code page 1252 (Windows ANSI
  505. * code page). This is for the PDK only. After the
  506. * PDK this routine will be rewritten to use the
  507. * NLSAPI.
  508. * 02-20-92 GregoryW Modified to use the NLS API.
  509. \***************************************************************************/
  510. FUNCLOG1(LOG_GENERAL, BOOL, WINAPI, IsCharAlphaNumericA, char, cChar)
  511. BOOL WINAPI IsCharAlphaNumericA(
  512. char cChar)
  513. {
  514. WORD ctype1info = 0;
  515. WCHAR wChar = 0;
  516. /*
  517. * The following 2 calls cannot fail here
  518. */
  519. RtlMultiByteToUnicodeN(&wChar, sizeof(WCHAR), NULL, &cChar, sizeof(CHAR));
  520. GetStringTypeW(CT_CTYPE1, &wChar, 1, &ctype1info);
  521. #ifdef FE_SB // IsCharAlphaNumericA()
  522. if (ctype1info & C1_ALPHA) {
  523. WORD ctype3info = 0;
  524. if (!IS_DBCS_ENABLED()) {
  525. return TRUE;
  526. }
  527. /*
  528. * We don't want to return TRUE for halfwidth katakana.
  529. * Katakana is linguistic character (C1_ALPHA), but it is not
  530. * alphabet character.
  531. */
  532. GetStringTypeW(CT_CTYPE3, &wChar, 1, &ctype3info);
  533. return ((ctype3info & (C3_KATAKANA|C3_HIRAGANA)) ? FALSE : TRUE);
  534. }
  535. /* Otherwise, it might be digits ? */
  536. return !!(ctype1info & C1_DIGIT);
  537. #else
  538. return (ctype1info & C1_ALPHA) || (ctype1info & C1_DIGIT);
  539. #endif // FE_SB
  540. }
  541. /***************************************************************************\
  542. * IsCharAlphaA (API)
  543. *
  544. * Returns TRUE if character is alphabetical, otherwise FALSE
  545. *
  546. * History:
  547. * 06-22-91 GregoryW Created to support code page 1252 (Windows ANSI
  548. * code page). This is for the PDK only. After the
  549. * PDK this routine will be rewritten to use the
  550. * NLSAPI.
  551. * 02-20-92 GregoryW Modified to use the NLS API.
  552. \***************************************************************************/
  553. FUNCLOG1(LOG_GENERAL, BOOL, WINAPI, IsCharAlphaA, char, cChar)
  554. BOOL WINAPI IsCharAlphaA(
  555. char cChar)
  556. {
  557. WORD ctype1info = 0;
  558. WCHAR wChar = 0;
  559. /*
  560. * The following 2 calls cannot fail here
  561. */
  562. RtlMultiByteToUnicodeN(&wChar, sizeof(WCHAR), NULL, &cChar, sizeof(CHAR));
  563. GetStringTypeW(CT_CTYPE1, &wChar, 1, &ctype1info);
  564. #ifdef FE_SB // IsCharAlphaA()
  565. if ((ctype1info & C1_ALPHA) == C1_ALPHA) {
  566. WORD ctype3info = 0;
  567. if (!IS_DBCS_ENABLED()) {
  568. return TRUE;
  569. }
  570. /*
  571. * We don't want to return TRUE for halfwidth katakana.
  572. * Katakana is linguistic character (C1_ALPHA), but it is not
  573. * alphabet character.
  574. */
  575. GetStringTypeW(CT_CTYPE3, &wChar, 1, &ctype3info);
  576. return ((ctype3info & (C3_KATAKANA|C3_HIRAGANA)) ? FALSE : TRUE);
  577. }
  578. return (FALSE);
  579. #else
  580. return (ctype1info & C1_ALPHA) == C1_ALPHA;
  581. #endif // FE_SB
  582. }