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.

368 lines
12 KiB

  1. /***
  2. *initmon.c - contains __init_monetary
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Contains the locale-category initialization function: __init_monetary().
  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 Changed _getlocaleinfo interface again.
  21. * 02-08-93 CFW Added _lconv_static_*.
  22. * 02-17-93 CFW Removed debugging print statement.
  23. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  24. * 04-20-93 CFW Check return val.
  25. * 05-20-93 GJF Include windows.h, not individual win*.h files
  26. * 05-24-93 CFW Clean up file (brief is evil).
  27. * 06-11-93 CFW Now inithelp takes void *.
  28. * 09-15-93 CFW Use ANSI conformant "__" names.
  29. * 09-22-93 GJF Merged NT SDK and Cuda versions.
  30. * 04-15-94 GJF Removed declarations of __lconv and __lconv_c (both
  31. * are declared in setlocal.h). Made definition of
  32. * __lconv_intl conditional on DLL_FOR_WIN32S.
  33. * 08-02-94 CFW Change "3;0" to "\3" for grouping as per ANSI.
  34. * 09-06-94 CFW Remove _INTL switch.
  35. * 01-10-95 CFW Debug CRT allocs.
  36. * 06-30-98 GJF Changed to support new multithread scheme - old lconv
  37. * structs must be kept around until all affected threads
  38. * have updated or terminated.
  39. * 12-08-98 GJF Fixed logic in __free_lconv_mon.
  40. * 03-15-99 GJF Added __lconv_mon_refcount
  41. * 04-24-99 PML Added __lconv_intl_refcount
  42. * 10-12-00 PML Don't call fix_grouping if error detected (vs7#169596)
  43. *
  44. *******************************************************************************/
  45. #include <stdlib.h>
  46. #include <windows.h>
  47. #include <locale.h>
  48. #include <setlocal.h>
  49. #include <malloc.h>
  50. #include <limits.h>
  51. #include <dbgint.h>
  52. void __cdecl __free_lconv_mon(struct lconv *);
  53. static void fix_grouping(char *);
  54. /* Pointer to non-C locale lconv */
  55. struct lconv *__lconv_intl = NULL;
  56. #ifdef _MT
  57. /*
  58. * Reference counter for locale info. The value is non-NULL iff the
  59. * info is not from the C locale.
  60. */
  61. int *__lconv_intl_refcount;
  62. /*
  63. * Reference counter for monetary locale info. The value is non-NULL iff the
  64. * monetary info is not from the C locale.
  65. */
  66. int *__lconv_mon_refcount;
  67. #endif
  68. /*
  69. * Note that __lconv_c is used when the monetary category is in the C locale
  70. * but the numeric category may not necessarily be in the C locale.
  71. */
  72. /***
  73. *int __init_monetary() - initialization for LC_MONETARY locale category.
  74. *
  75. *Purpose:
  76. * In non-C locales, read the localized monetary strings into
  77. * __lconv_intl, and also copy the numeric strings from __lconv into
  78. * __lconv_intl. Set __lconv to point to __lconv_intl. The old
  79. * __lconv_intl is not freed until the new one is fully established.
  80. *
  81. * In the C locale, the monetary fields in lconv are filled with
  82. * contain C locale values. Any allocated __lconv_intl fields are freed.
  83. *
  84. * At startup, __lconv points to a static lconv structure containing
  85. * C locale strings. This structure is never used again if
  86. * __init_monetary is called.
  87. *
  88. *Entry:
  89. * None.
  90. *
  91. *Exit:
  92. * 0 success
  93. * 1 fail
  94. *
  95. *Exceptions:
  96. *
  97. *******************************************************************************/
  98. int __cdecl __init_monetary (
  99. void
  100. )
  101. {
  102. struct lconv *lc;
  103. int ret;
  104. LCID ctryid;
  105. #ifdef _MT
  106. int *lc_refcount;
  107. #endif
  108. if ( (__lc_handle[LC_MONETARY] != _CLOCALEHANDLE) ||
  109. (__lc_handle[LC_NUMERIC] != _CLOCALEHANDLE) )
  110. {
  111. /*
  112. * Allocate structure filled with NULL pointers
  113. */
  114. if ( (lc = (struct lconv *)
  115. _calloc_crt(1, sizeof(struct lconv))) == NULL )
  116. return 1;
  117. #ifdef _MT
  118. /*
  119. * Allocate a new reference counter for the lconv structure
  120. */
  121. if ( (lc_refcount = _malloc_crt(sizeof(int))) == NULL )
  122. {
  123. _free_crt(lc);
  124. return 1;
  125. }
  126. *lc_refcount = 0;
  127. #endif
  128. if ( __lc_handle[LC_MONETARY] != _CLOCALEHANDLE )
  129. {
  130. #ifdef _MT
  131. /*
  132. * Allocate a new reference counter for the monetary info
  133. */
  134. if ( (__lconv_mon_refcount = _malloc_crt(sizeof(int))) == NULL )
  135. {
  136. _free_crt(lc);
  137. _free_crt(lc_refcount);
  138. return 1;
  139. }
  140. *__lconv_mon_refcount = 0;
  141. #endif
  142. /*
  143. * Currency is country--not language--dependent. NT
  144. * work-around.
  145. */
  146. ctryid = MAKELCID(__lc_id[LC_MONETARY].wCountry, SORT_DEFAULT);
  147. ret = 0;
  148. ret |= __getlocaleinfo( LC_STR_TYPE, ctryid,
  149. LOCALE_SINTLSYMBOL, (void *)&lc->int_curr_symbol );
  150. ret |= __getlocaleinfo( LC_STR_TYPE, ctryid,
  151. LOCALE_SCURRENCY, (void *)&lc->currency_symbol );
  152. ret |= __getlocaleinfo( LC_STR_TYPE, ctryid,
  153. LOCALE_SMONDECIMALSEP, (void *)&lc->mon_decimal_point );
  154. ret |= __getlocaleinfo( LC_STR_TYPE, ctryid,
  155. LOCALE_SMONTHOUSANDSEP, (void *)&lc->mon_thousands_sep );
  156. ret |= __getlocaleinfo(LC_STR_TYPE, ctryid,
  157. LOCALE_SMONGROUPING, (void *)&lc->mon_grouping );
  158. ret |= __getlocaleinfo( LC_STR_TYPE, ctryid,
  159. LOCALE_SPOSITIVESIGN, (void *)&lc->positive_sign);
  160. ret |= __getlocaleinfo( LC_STR_TYPE, ctryid,
  161. LOCALE_SNEGATIVESIGN, (void *)&lc->negative_sign);
  162. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  163. LOCALE_IINTLCURRDIGITS, (void *)&lc->int_frac_digits);
  164. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  165. LOCALE_ICURRDIGITS, (void *)&lc->frac_digits);
  166. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  167. LOCALE_IPOSSYMPRECEDES, (void *)&lc->p_cs_precedes);
  168. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  169. LOCALE_IPOSSEPBYSPACE, (void *)&lc->p_sep_by_space);
  170. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  171. LOCALE_INEGSYMPRECEDES, (void *)&lc->n_cs_precedes);
  172. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  173. LOCALE_INEGSEPBYSPACE, (void *)&lc->n_sep_by_space);
  174. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  175. LOCALE_IPOSSIGNPOSN, (void *)&lc->p_sign_posn);
  176. ret |= __getlocaleinfo( LC_INT_TYPE, ctryid,
  177. LOCALE_INEGSIGNPOSN, (void *)&lc->n_sign_posn);
  178. if ( ret != 0 ) {
  179. __free_lconv_mon(lc);
  180. _free_crt(lc);
  181. #ifdef _MT
  182. _free_crt(lc_refcount);
  183. #endif
  184. return 1;
  185. }
  186. fix_grouping(lc->mon_grouping);
  187. }
  188. else {
  189. /*
  190. * C locale for monetary category (the numeric category fields,
  191. * which are NOT of the C locale, get fixed up below). Note
  192. * that __lconv_c is copied, rather than directly assigning
  193. * the fields of lc because of the uncertainty of the values of
  194. * the int_frac_digits,..., n_sign_posn fields (SCHAR_MAX or
  195. * UCHAR_MAX, depending on whether or a compliand was built
  196. * with -J.
  197. */
  198. *lc = __lconv_c;
  199. #ifdef _MT
  200. /*
  201. * NULL out the reference count pointer
  202. */
  203. __lconv_mon_refcount = NULL;
  204. #endif
  205. }
  206. /*
  207. * Copy the numeric locale fields from the old struct
  208. */
  209. lc->decimal_point = __lconv->decimal_point;
  210. lc->thousands_sep = __lconv->thousands_sep;
  211. lc->grouping = __lconv->grouping;
  212. __lconv = lc; /* point to new one */
  213. #ifdef _MT
  214. __lconv_intl_refcount = lc_refcount;
  215. #else
  216. __free_lconv_mon(__lconv_intl); /* free the old one */
  217. _free_crt(__lconv_intl);
  218. #endif
  219. __lconv_intl = lc;
  220. }
  221. else {
  222. /*
  223. * C locale for BOTH monetary and numeric categories.
  224. */
  225. #ifdef _MT
  226. /*
  227. * NULL out the reference count pointer
  228. */
  229. __lconv_mon_refcount = NULL;
  230. __lconv_intl_refcount = NULL;
  231. #else
  232. __free_lconv_mon(__lconv_intl); /* free the old one */
  233. _free_crt(__lconv_intl);
  234. #endif
  235. __lconv = &__lconv_c; /* point to new one */
  236. __lconv_intl = NULL;
  237. }
  238. return 0;
  239. }
  240. static void fix_grouping(
  241. char *grouping
  242. )
  243. {
  244. /*
  245. * ANSI specifies that the fields should contain "\3" [\3\0] to indicate
  246. * thousands groupings (100,000,000.00 for example).
  247. * NT uses "3;0"; ASCII 3 instead of value 3 and the ';' is extra.
  248. * So here we convert the NT version to the ANSI version.
  249. */
  250. while (*grouping)
  251. {
  252. /* convert '3' to '\3' */
  253. if (*grouping >= '0' && *grouping <= '9')
  254. {
  255. *grouping = *grouping - '0';
  256. grouping++;
  257. }
  258. /* remove ';' */
  259. else if (*grouping == ';')
  260. {
  261. char *tmp = grouping;
  262. do
  263. *tmp = *(tmp+1);
  264. while (*++tmp);
  265. }
  266. /* unknown (illegal) character, ignore */
  267. else
  268. grouping++;
  269. }
  270. }
  271. /*
  272. * Free the lconv monetary strings.
  273. * Numeric values do not need to be freed.
  274. */
  275. void __cdecl __free_lconv_mon(
  276. struct lconv *l
  277. )
  278. {
  279. if (l == NULL)
  280. return;
  281. #ifdef _MT
  282. if ( (l->int_curr_symbol != __lconv->int_curr_symbol) &&
  283. (l->int_curr_symbol != __lconv_c.int_curr_symbol) )
  284. #else
  285. if ( l->int_curr_symbol != __lconv_c.int_curr_symbol )
  286. #endif
  287. _free_crt(l->int_curr_symbol);
  288. #ifdef _MT
  289. if ( (l->currency_symbol != __lconv->currency_symbol) &&
  290. (l->currency_symbol != __lconv_c.currency_symbol) )
  291. #else
  292. if ( l->currency_symbol != __lconv_c.currency_symbol )
  293. #endif
  294. _free_crt(l->currency_symbol);
  295. #ifdef _MT
  296. if ( (l->mon_decimal_point != __lconv->mon_decimal_point) &&
  297. (l->mon_decimal_point != __lconv_c.mon_decimal_point) )
  298. #else
  299. if ( l->mon_decimal_point != __lconv_c.mon_decimal_point )
  300. #endif
  301. _free_crt(l->mon_decimal_point);
  302. #ifdef _MT
  303. if ( (l->mon_thousands_sep != __lconv->mon_thousands_sep) &&
  304. (l->mon_thousands_sep != __lconv_c.mon_thousands_sep) )
  305. #else
  306. if ( l->mon_thousands_sep != __lconv_c.mon_thousands_sep )
  307. #endif
  308. _free_crt(l->mon_thousands_sep);
  309. #ifdef _MT
  310. if ( (l->mon_grouping != __lconv->mon_grouping) &&
  311. (l->mon_grouping != __lconv_c.mon_grouping) )
  312. #else
  313. if ( l->mon_grouping != __lconv_c.mon_grouping )
  314. #endif
  315. _free_crt(l->mon_grouping);
  316. #ifdef _MT
  317. if ( (l->positive_sign != __lconv->positive_sign) &&
  318. (l->positive_sign != __lconv_c.positive_sign) )
  319. #else
  320. if ( l->positive_sign != __lconv_c.positive_sign )
  321. #endif
  322. _free_crt(l->positive_sign);
  323. #ifdef _MT
  324. if ( (l->negative_sign != __lconv->negative_sign) &&
  325. (l->negative_sign != __lconv_c.negative_sign) )
  326. #else
  327. if ( l->negative_sign != __lconv_c.negative_sign )
  328. #endif
  329. _free_crt(l->negative_sign);
  330. }