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.

337 lines
11 KiB

  1. /***
  2. *initnum.c - contains __init_numeric
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Contains the locale-category initialization function: __init_numeric().
  8. *
  9. * Each initialization function sets up locale-specific information
  10. * for their category, for use by functions which are affected by
  11. * their locale category.
  12. *
  13. * *** For internal use by setlocale() only ***
  14. *
  15. *Revision History:
  16. * 12-08-91 ETC Created.
  17. * 12-20-91 ETC Updated to use new NLSAPI GetLocaleInfo.
  18. * 12-18-92 CFW Ported to Cuda tree, changed _CALLTYPE4 to _CRTAPI3.
  19. * 12-29-92 CFW Updated to use new _getlocaleinfo wrapper function.
  20. * 01-25-93 KRS Change interface to _getlocaleinfo again.
  21. * 02-08-93 CFW Added _lconv_static_*.
  22. * 02-17-93 CFW Removed debugging print statement.
  23. * 03-17-93 CFW C locale thousands sep is "", not ",".
  24. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  25. * 04-08-93 SKS Replace strdup() with ANSI-conforming _strdup()
  26. * 04-20-93 CFW Check return val.
  27. * 05-20-93 GJF Include windows.h, not individual win*.h files
  28. * 05-24-93 CFW Clean up file (brief is evil).
  29. * 06-11-93 CFW Now inithelp takes void *.
  30. * 09-15-93 CFW Use ANSI conformant "__" names.
  31. * 09-23-93 GJF Merged NT SDK and Cuda versions.
  32. * 09-15-93 CFW Use ANSI conformant "__" names.
  33. * 04-06-94 GJF Removed declaration of __lconv (it is declared in
  34. * setlocal.h). Renamed static vars, decimal_point
  35. * thousands_sep and grouping to dec_pnt, thous_sep
  36. * and grping (resp.). Made the definitions of these
  37. * conditional on DLL_FOR_WIN32S.
  38. * 08-02-94 CFW Change "3;0" to "\3" for grouping as per ANSI.
  39. * 09-06-94 CFW Remove _INTL switch.
  40. * 01-10-95 CFW Debug CRT allocs.
  41. * 01-18-95 GJF Fixed bug introduced with the change above - resetting
  42. * to the C locale didn't reset the thousand_sep and
  43. * grouping fields correctly.
  44. * 02-06-95 CFW assert -> _ASSERTE.
  45. * 07-06-98 GJF Changed to support new multithread scheme - old lconv
  46. * structs must be kept around until all affected threads
  47. * have updated or terminated.
  48. * 12-08-98 GJF Fixed logic in __free_lconv_num.
  49. * 01-25-99 GJF No, I didn't! Try again...
  50. * 03-15-99 GJF Added __lconv_num_refcount
  51. * 04-24-99 PML Added __lconv_intl_refcount
  52. * 09-08-00 GB Fixed leak of __lconv_intl in init_numeric for single
  53. * thread case.
  54. * 10-12-00 PML Don't call fix_grouping if error detected (vs7#169596)
  55. * 11-05-00 PML Fixed double-free of __lconv_intl (vs7#181380)
  56. *
  57. *******************************************************************************/
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <windows.h>
  61. #include <locale.h>
  62. #include <setlocal.h>
  63. #include <malloc.h>
  64. #include <nlsint.h>
  65. #include <dbgint.h>
  66. void __cdecl __free_lconv_num(struct lconv *);
  67. extern struct lconv *__lconv_intl;
  68. #ifdef _MT
  69. /*
  70. * Reference counter for numeric locale info. The value is non-NULL iff the
  71. * numeric info is not from the C locale.
  72. */
  73. int *__lconv_num_refcount;
  74. extern int *__lconv_intl_refcount;
  75. #endif
  76. static void fix_grouping(
  77. char *grouping
  78. )
  79. {
  80. /*
  81. * ANSI specifies that the fields should contain "\3" [\3\0] to indicate
  82. * thousands groupings (100,000,000.00 for example).
  83. * NT uses "3;0"; ASCII 3 instead of value 3 and the ';' is extra.
  84. * So here we convert the NT version to the ANSI version.
  85. */
  86. while (*grouping)
  87. {
  88. /* convert '3' to '\3' */
  89. if (*grouping >= '0' && *grouping <= '9')
  90. {
  91. *grouping = *grouping - '0';
  92. grouping++;
  93. }
  94. /* remove ';' */
  95. else if (*grouping == ';')
  96. {
  97. char *tmp = grouping;
  98. do
  99. *tmp = *(tmp+1);
  100. while (*++tmp);
  101. }
  102. /* unknown (illegal) character, ignore */
  103. else
  104. grouping++;
  105. }
  106. }
  107. /***
  108. *int __init_numeric() - initialization for LC_NUMERIC locale category.
  109. *
  110. *Purpose:
  111. *
  112. *Entry:
  113. * None.
  114. *
  115. *Exit:
  116. * 0 success
  117. * 1 fail
  118. *
  119. *Exceptions:
  120. *
  121. *******************************************************************************/
  122. int __cdecl __init_numeric (
  123. void
  124. )
  125. {
  126. struct lconv *lc;
  127. int ret = 0;
  128. LCID ctryid;
  129. #ifdef _MT
  130. int *lc_refcount;
  131. #endif
  132. if ( (__lc_handle[LC_NUMERIC] != _CLOCALEHANDLE) ||
  133. (__lc_handle[LC_MONETARY] != _CLOCALEHANDLE) )
  134. {
  135. /*
  136. * Allocate structure filled with NULL pointers
  137. */
  138. if ( (lc = (struct lconv *)_calloc_crt(1, sizeof(struct lconv)))
  139. == NULL )
  140. return 1;
  141. /*
  142. * Copy over all fields (esp., the monetary category)
  143. */
  144. *lc = *__lconv;
  145. #ifdef _MT
  146. /*
  147. * Allocate a new reference counter for the lconv structure
  148. */
  149. if ( (lc_refcount = _malloc_crt(sizeof(int))) == NULL )
  150. {
  151. _free_crt(lc);
  152. return 1;
  153. }
  154. *lc_refcount = 0;
  155. #endif
  156. if ( __lc_handle[LC_NUMERIC] != _CLOCALEHANDLE )
  157. {
  158. #ifdef _MT
  159. /*
  160. * Allocate a new reference counter for the numeric info
  161. */
  162. if ( (__lconv_num_refcount = _malloc_crt(sizeof(int))) == NULL )
  163. {
  164. _free_crt(lc);
  165. _free_crt(lc_refcount);
  166. return 1;
  167. }
  168. *__lconv_num_refcount = 0;
  169. #endif
  170. /*
  171. * Numeric data is country--not language--dependent. NT
  172. * work-around.
  173. */
  174. ctryid = MAKELCID(__lc_id[LC_NUMERIC].wCountry, SORT_DEFAULT);
  175. ret |= __getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SDECIMAL,
  176. (void *)&lc->decimal_point);
  177. ret |= __getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_STHOUSAND,
  178. (void *)&lc->thousands_sep);
  179. ret |= __getlocaleinfo(LC_STR_TYPE, ctryid, LOCALE_SGROUPING,
  180. (void *)&lc->grouping);
  181. if (ret) {
  182. /* Clean up before returning failure */
  183. __free_lconv_num(lc);
  184. _free_crt(lc);
  185. #ifdef _MT
  186. _free_crt(lc_refcount);
  187. #endif
  188. return -1;
  189. }
  190. fix_grouping(lc->grouping);
  191. }
  192. else {
  193. /*
  194. * C locale for just the numeric category.
  195. */
  196. #ifdef _MT
  197. /*
  198. * NULL out the reference count pointer
  199. */
  200. __lconv_num_refcount = NULL;
  201. #endif
  202. lc->decimal_point = __lconv_c.decimal_point;
  203. lc->thousands_sep = __lconv_c.thousands_sep;
  204. lc->grouping = __lconv_c.grouping;
  205. }
  206. /*
  207. * Clean up old __lconv and reset it to lc
  208. */
  209. #ifdef _MT
  210. /*
  211. * If this is part of LC_ALL, then we need to free the old __lconv
  212. * set up in init_monetary() before this.
  213. */
  214. if ( (__lconv_intl_refcount != NULL) &&
  215. (*__lconv_intl_refcount == 0) &&
  216. (__lconv_intl_refcount != __ptlocinfo->lconv_intl_refcount) )
  217. {
  218. _free_crt(__lconv_intl_refcount);
  219. _free_crt(__lconv_intl);
  220. }
  221. __lconv_intl_refcount = lc_refcount;
  222. #else
  223. __free_lconv_num(__lconv);
  224. /*
  225. * Recall that __lconv is dynamically allocated (hence must be
  226. * freed) iff __lconv and __lconv_intl are equal iff __lconv_intl
  227. * is non-NULL.
  228. */
  229. _free_crt(__lconv_intl);
  230. #endif
  231. __lconv = __lconv_intl = lc;
  232. }
  233. else {
  234. /*
  235. * C locale for BOTH numeric and monetary categories.
  236. */
  237. #ifdef _MT
  238. /*
  239. * If this is part of LC_ALL, then we need to free the old __lconv
  240. * set up in init_monetary() before this.
  241. */
  242. if ( (__lconv_intl_refcount != NULL) &&
  243. (*__lconv_intl_refcount == 0) &&
  244. (__lconv_intl_refcount != __ptlocinfo->lconv_intl_refcount) )
  245. {
  246. _free_crt(__lconv_intl_refcount);
  247. _free_crt(__lconv_intl);
  248. }
  249. /*
  250. * NULL out the reference count pointer
  251. */
  252. __lconv_num_refcount = NULL;
  253. __lconv_intl_refcount = NULL;
  254. #else
  255. __free_lconv_num(__lconv);
  256. /*
  257. * Recall that __lconv is dynamically allocated (hence must be
  258. * freed) iff __lconv and __lconv_intl are equal iff __lconv_intl
  259. * is non-NULL.
  260. */
  261. _free_crt(__lconv_intl);
  262. #endif
  263. __lconv = &__lconv_c; /* point to new one */
  264. __lconv_intl = NULL;
  265. }
  266. /*
  267. * set global decimal point character
  268. */
  269. *__decimal_point = *__lconv->decimal_point;
  270. __decimal_point_length = 1;
  271. return 0;
  272. }
  273. /*
  274. * Free the lconv numeric strings.
  275. * Numeric values do not need to be freed.
  276. */
  277. void __cdecl __free_lconv_num(
  278. struct lconv *l
  279. )
  280. {
  281. if (l == NULL)
  282. return;
  283. #ifdef _MT
  284. if ( (l->decimal_point != __lconv->decimal_point) &&
  285. (l->decimal_point != __lconv_c.decimal_point) )
  286. #else
  287. if ( l->decimal_point != __lconv_c.decimal_point )
  288. #endif
  289. _free_crt(l->decimal_point);
  290. #ifdef _MT
  291. if ( (l->thousands_sep != __lconv->thousands_sep) &&
  292. (l->thousands_sep != __lconv_c.thousands_sep) )
  293. #else
  294. if ( l->thousands_sep != __lconv_c.thousands_sep )
  295. #endif
  296. _free_crt(l->thousands_sep);
  297. #ifdef _MT
  298. if ( (l->grouping != __lconv->grouping) &&
  299. (l->grouping != __lconv_c.grouping) )
  300. #else
  301. if ( l->grouping != __lconv_c.grouping )
  302. #endif
  303. _free_crt(l->grouping);
  304. }