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.

385 lines
13 KiB

  1. /***
  2. *a_cmp.c - A version of CompareString.
  3. *
  4. * Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Use either CompareStringA or CompareStringW depending on which is
  8. * available
  9. *
  10. *Revision History:
  11. * 09-14-93 CFW Module created.
  12. * 09-17-93 CFW Use unsigned chars.
  13. * 09-23-93 CFW Correct NLS API params and comments about same.
  14. * 10-07-93 CFW Optimize WideCharToMultiByte, use NULL default char.
  15. * 10-22-93 CFW Test for invalid MB chars using global preset flag.
  16. * 11-09-93 CFW Allow user to pass in code page.
  17. * 11-18-93 CFW Test for entry point function stubs.
  18. * 02-23-94 CFW Use W flavor whenever possible.
  19. * 03-31-94 CFW Include awint.h.
  20. * 05-09-94 CFW Do not let CompareString compare past NULL.
  21. * 06-03-94 CFW Test for empty string early.
  22. * 11/01-94 CFW But not too early for MB strings.
  23. * 12-21-94 CFW Remove invalid MB chars NT 3.1 hack.
  24. * 12-27-94 CFW Call direct, all OS's have stubs.
  25. * 01-10-95 CFW Debug CRT allocs.
  26. * 02-06-95 CFW assert -> _ASSERTE.
  27. * 02-15-97 RDK For narrow comparsion, try W version first so Windows NT
  28. * can process nonANSI codepage correctly.
  29. * 05-15-97 GJF Moved W version into another file, renamed this as
  30. * a_cmp.c. Replaced use of _malloc_crt/_free_crt with
  31. * _alloca. Also, detab-ed and cleaned up the code a bit.
  32. * 05-27-98 GJF Changed strncnt() so that it will never examine the
  33. * (cnt + 1)-th byte of the string.
  34. * 08-18-98 GJF Use _malloc_crt if _alloca fails.
  35. * 12-10-99 GB Added support for recovery from stack overflow around
  36. * _alloca().
  37. * 05-17-00 GB Use ERROR_CALL_NOT_IMPLEMENTED for existance of W API
  38. * 08-23-00 GB Fixed bug with non Ansi CP on Win9x.
  39. *
  40. *******************************************************************************/
  41. #include <cruntime.h>
  42. #include <internal.h>
  43. #include <dbgint.h>
  44. #include <stdlib.h>
  45. #include <setlocal.h>
  46. #include <locale.h>
  47. #include <awint.h>
  48. #include <dbgint.h>
  49. #include <malloc.h>
  50. #include <awint.h>
  51. #define USE_W 1
  52. #define USE_A 2
  53. /***
  54. *int __cdecl strncnt - count characters in a string, up to n.
  55. *
  56. *Purpose:
  57. * Internal local support function. Counts characters in string before NULL.
  58. * If NULL not found in n chars, then return n.
  59. *
  60. *Entry:
  61. * const char *string - start of string
  62. * int n - byte count
  63. *
  64. *Exit:
  65. * returns number of bytes from start of string to
  66. * NULL (exclusive), up to n.
  67. *
  68. *Exceptions:
  69. *
  70. *******************************************************************************/
  71. static int __cdecl strncnt (
  72. const char *string,
  73. int cnt
  74. )
  75. {
  76. int n = cnt;
  77. char *cp = (char *)string;
  78. while (n-- && *cp)
  79. cp++;
  80. return cnt - n - 1;
  81. }
  82. /***
  83. *int __cdecl __crtCompareStringA - Get type information about an ANSI string.
  84. *
  85. *Purpose:
  86. * Internal support function. Assumes info in ANSI string format. Tries
  87. * to use NLS API call CompareStringA if available and uses CompareStringW
  88. * if it must. If neither are available it fails and returns 0.
  89. *
  90. *Entry:
  91. * LCID Locale - locale context for the comparison.
  92. * DWORD dwCmpFlags - see NT\Chicago docs
  93. * LPCSTR lpStringn - multibyte string to be compared
  94. * int cchCountn - char (byte) count (NOT including NULL)
  95. * (-1 if NULL terminated)
  96. * int code_page - for MB/WC conversion. If 0, use __lc_codepage
  97. *
  98. *Exit:
  99. * Success: 1 - if lpString1 < lpString2
  100. * 2 - if lpString1 == lpString2
  101. * 3 - if lpString1 > lpString2
  102. * Failure: 0
  103. *
  104. *Exceptions:
  105. *
  106. *******************************************************************************/
  107. int __cdecl __crtCompareStringA(
  108. LCID Locale,
  109. DWORD dwCmpFlags,
  110. LPCSTR lpString1,
  111. int cchCount1,
  112. LPCSTR lpString2,
  113. int cchCount2,
  114. int code_page
  115. )
  116. {
  117. static int f_use = 0;
  118. /*
  119. * Look for unstubbed 'preferred' flavor. Otherwise use available flavor.
  120. * Must actually call the function to ensure it's not a stub.
  121. * (Always try wide version first so WinNT can process codepage correctly.)
  122. */
  123. if (0 == f_use)
  124. {
  125. if (0 != CompareStringW(0, 0, L"\0", 1, L"\0", 1))
  126. f_use = USE_W;
  127. else if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  128. f_use = USE_A;
  129. }
  130. /*
  131. * CompareString will compare past NULL. Must find NULL if in string
  132. * before cchCountn chars.
  133. */
  134. if (cchCount1 > 0)
  135. cchCount1 = strncnt(lpString1, cchCount1);
  136. if (cchCount2 > 0)
  137. cchCount2 = strncnt(lpString2, cchCount2);
  138. /* Use "A" version */
  139. if (USE_A == f_use || f_use == 0)
  140. {
  141. char *cbuffer1 = NULL;
  142. char *cbuffer2 = NULL;
  143. int ret;
  144. int AnsiCP;
  145. if (0 == Locale)
  146. Locale = __lc_handle[LC_CTYPE];
  147. if (0 == code_page)
  148. code_page = __lc_codepage;
  149. if ( -1 == (AnsiCP = __ansicp(Locale)))
  150. return FALSE;
  151. /* If current CP is not ANSI CP for the given Locale, convert the
  152. * string from current CP to ansi CP as CompareStringA uses
  153. * ANSI CP to compare strings.
  154. */
  155. if ( AnsiCP != code_page)
  156. {
  157. cbuffer1 = __convertcp(code_page,
  158. AnsiCP,
  159. lpString1,
  160. &cchCount1,
  161. NULL,
  162. 0);
  163. if (cbuffer1 == NULL)
  164. return FALSE;
  165. cbuffer2 = __convertcp(code_page,
  166. AnsiCP,
  167. lpString2,
  168. &cchCount2,
  169. NULL,
  170. 0);
  171. if (cbuffer2 == NULL)
  172. {
  173. _free_crt(cbuffer1);
  174. return FALSE;
  175. }
  176. lpString1 = cbuffer1;
  177. lpString2 = cbuffer2;
  178. }
  179. ret = CompareStringA( Locale,
  180. dwCmpFlags,
  181. lpString1,
  182. cchCount1,
  183. lpString2,
  184. cchCount2 );
  185. if ( cbuffer1 != NULL)
  186. {
  187. _free_crt(cbuffer1);
  188. _free_crt(cbuffer2);
  189. }
  190. return ret;
  191. }
  192. /* Use "W" version */
  193. if (USE_W == f_use)
  194. {
  195. int buff_size1;
  196. int buff_size2;
  197. wchar_t *wbuffer1;
  198. wchar_t *wbuffer2;
  199. int malloc_flag1 = 0;
  200. int malloc_flag2 = 0;
  201. int retcode = 0;
  202. /*
  203. * Use __lc_codepage for conversion if code_page not specified
  204. */
  205. if (0 == code_page)
  206. code_page = __lc_codepage;
  207. /*
  208. * Special case: at least one count is zero
  209. */
  210. if (!cchCount1 || !cchCount2)
  211. {
  212. unsigned char *cp; // char pointer
  213. CPINFO lpCPInfo; // struct for use with GetCPInfo
  214. /* both strings zero */
  215. if (cchCount1 == cchCount2)
  216. return 2;
  217. /* string 1 greater */
  218. if (cchCount2 > 1)
  219. return 1;
  220. /* string 2 greater */
  221. if (cchCount1 > 1)
  222. return 3;
  223. /*
  224. * one has zero count, the other has a count of one
  225. * - if the one count is a naked lead byte, the strings are equal
  226. * - otherwise it is a single character and they are unequal
  227. */
  228. if (GetCPInfo(code_page, &lpCPInfo) == FALSE)
  229. return 0;
  230. _ASSERTE(cchCount1==0 && cchCount2==1 || cchCount1==1 && cchCount2==0);
  231. /* string 1 has count of 1 */
  232. if (cchCount1 > 0)
  233. {
  234. if (lpCPInfo.MaxCharSize < 2)
  235. return 3;
  236. for ( cp = (unsigned char *)lpCPInfo.LeadByte ;
  237. cp[0] && cp[1] ;
  238. cp += 2 )
  239. if ( (*(unsigned char *)lpString1 >= cp[0]) &&
  240. (*(unsigned char *)lpString1 <= cp[1]) )
  241. return 2;
  242. return 3;
  243. }
  244. /* string 2 has count of 1 */
  245. if (cchCount2 > 0)
  246. {
  247. if (lpCPInfo.MaxCharSize < 2)
  248. return 1;
  249. for ( cp = (unsigned char *)lpCPInfo.LeadByte ;
  250. cp[0] && cp[1] ;
  251. cp += 2 )
  252. if ( (*(unsigned char *)lpString2 >= cp[0]) &&
  253. (*(unsigned char *)lpString2 <= cp[1]) )
  254. return 2;
  255. return 1;
  256. }
  257. }
  258. /*
  259. * Convert strings and return the requested information.
  260. */
  261. /* find out how big a buffer we need (includes NULL if any) */
  262. if ( 0 == (buff_size1 = MultiByteToWideChar( code_page,
  263. MB_PRECOMPOSED |
  264. MB_ERR_INVALID_CHARS,
  265. lpString1,
  266. cchCount1,
  267. NULL,
  268. 0 )) )
  269. return 0;
  270. /* allocate enough space for chars */
  271. __try {
  272. wbuffer1 = (wchar_t *)_alloca( buff_size1 * sizeof(wchar_t) );
  273. }
  274. __except( EXCEPTION_EXECUTE_HANDLER ) {
  275. _resetstkoflw();
  276. wbuffer1 = NULL;
  277. }
  278. if ( wbuffer1 == NULL ) {
  279. if ( (wbuffer1 = (wchar_t *)_malloc_crt(buff_size1 * sizeof(wchar_t)))
  280. == NULL )
  281. return 0;
  282. malloc_flag1++;
  283. }
  284. /* do the conversion */
  285. if ( 0 == MultiByteToWideChar( code_page,
  286. MB_PRECOMPOSED,
  287. lpString1,
  288. cchCount1,
  289. wbuffer1,
  290. buff_size1 ) )
  291. goto error_cleanup;
  292. /* find out how big a buffer we need (includes NULL if any) */
  293. if ( 0 == (buff_size2 = MultiByteToWideChar( code_page,
  294. MB_PRECOMPOSED |
  295. MB_ERR_INVALID_CHARS,
  296. lpString2,
  297. cchCount2,
  298. NULL,
  299. 0 )) )
  300. goto error_cleanup;
  301. /* allocate enough space for chars */
  302. __try {
  303. wbuffer2 = (wchar_t *)_alloca( buff_size2 * sizeof(wchar_t) );
  304. }
  305. __except( EXCEPTION_EXECUTE_HANDLER ) {
  306. _resetstkoflw();
  307. wbuffer2 = NULL;
  308. }
  309. if ( wbuffer2 == NULL ) {
  310. if ( (wbuffer2 = (wchar_t *)_malloc_crt(buff_size2 * sizeof(wchar_t)))
  311. == NULL )
  312. goto error_cleanup;
  313. malloc_flag2++;
  314. }
  315. /* do the conversion */
  316. if ( 0 != MultiByteToWideChar( code_page,
  317. MB_PRECOMPOSED,
  318. lpString2,
  319. cchCount2,
  320. wbuffer2,
  321. buff_size2 ) )
  322. retcode = CompareStringW( Locale,
  323. dwCmpFlags,
  324. wbuffer1,
  325. buff_size1,
  326. wbuffer2,
  327. buff_size2 );
  328. if ( malloc_flag2 )
  329. _free_crt(wbuffer2);
  330. error_cleanup:
  331. if ( malloc_flag1 )
  332. _free_crt(wbuffer1);
  333. return retcode;
  334. }
  335. else /* f_use is neither USE_A nor USE_W */
  336. return 0;
  337. }