PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_Main/Languages/IronPython/IronPython.Modules/_locale.cs

#
C# | 296 lines | 227 code | 43 blank | 26 comment | 18 complexity | b70534ca547b5e8276db538347bf50f1 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Globalization;
  17. using System.Runtime.CompilerServices;
  18. using System.Runtime.InteropServices;
  19. using IronPython.Runtime;
  20. using IronPython.Runtime.Exceptions;
  21. using IronPython.Runtime.Types;
  22. using Microsoft.Scripting;
  23. using Microsoft.Scripting.Runtime;
  24. using Microsoft.Scripting.Utils;
  25. [assembly: PythonModule("_locale", typeof(IronPython.Modules.PythonLocale))]
  26. namespace IronPython.Modules {
  27. public static class PythonLocale {
  28. public const string __doc__ = "Provides access for querying and manipulating the current locale settings";
  29. private static readonly object _localeKey = new object();
  30. [SpecialName]
  31. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  32. EnsureLocaleInitialized(context);
  33. context.EnsureModuleException("_localeerror", dict, "Error", "_locale");
  34. }
  35. internal static void EnsureLocaleInitialized(PythonContext context) {
  36. if (!context.HasModuleState(_localeKey)) {
  37. context.SetModuleState(_localeKey, new LocaleInfo(context));
  38. }
  39. }
  40. public const int CHAR_MAX = 127;
  41. public const int LC_ALL = (int)LocaleCategories.All;
  42. public const int LC_COLLATE = (int)LocaleCategories.Collate;
  43. public const int LC_CTYPE = (int)LocaleCategories.CType;
  44. public const int LC_MONETARY = (int)LocaleCategories.Monetary;
  45. public const int LC_NUMERIC = (int)LocaleCategories.Numeric;
  46. public const int LC_TIME = (int)LocaleCategories.Time;
  47. internal static string PreferredEncoding {
  48. get {
  49. #if !SILVERLIGHT // No ANSICodePage in Silverlight
  50. return "cp" + CultureInfo.CurrentCulture.TextInfo.ANSICodePage.ToString();
  51. #else
  52. return "";
  53. #endif
  54. }
  55. }
  56. [Documentation("gets the default locale tuple")]
  57. public static object _getdefaultlocale() {
  58. return PythonTuple.MakeTuple(
  59. CultureInfo.CurrentCulture.Name.Replace('-', '_').Replace(' ', '_'),
  60. PreferredEncoding
  61. );
  62. }
  63. [Documentation(@"gets the locale's convetions table.
  64. The conventions table is a dictionary that contains information on how to use
  65. the locale for numeric and monetary formatting")]
  66. public static object localeconv(CodeContext/*!*/ context) {
  67. return GetLocaleInfo(context).GetConventionsTable();
  68. }
  69. [Documentation(@"Sets the current locale for the given category.
  70. LC_ALL: sets locale for all options below
  71. LC_COLLATE: sets locale for collation (strcoll and strxfrm) only
  72. LC_CTYPE: sets locale for CType [unused]
  73. LC_MONETARY: sets locale for the monetary functions (localeconv())
  74. LC_NUMERIC: sets the locale for numeric functions (slocaleconv())
  75. LC_TIME: sets the locale for time functions [unused]
  76. If locale is None then the current setting is returned.
  77. ")]
  78. public static object setlocale(CodeContext/*!*/ context, int category, [DefaultParameterValue(null)]string locale) {
  79. LocaleInfo li = GetLocaleInfo(context);
  80. if (locale == null) {
  81. return li.GetLocale(context, category);
  82. }
  83. return li.SetLocale(context, category, locale);
  84. }
  85. [Documentation("compares two strings using the current locale")]
  86. public static int strcoll(CodeContext/*!*/ context, string string1, string string2) {
  87. return GetLocaleInfo(context).Collate.CompareInfo.Compare(string1, string2, CompareOptions.None);
  88. }
  89. [Documentation(@"returns a transformed string that can be compared using the built-in cmp.
  90. Currently returns the string unmodified")]
  91. public static object strxfrm(string @string) {
  92. return @string;
  93. }
  94. private enum LocaleCategories {
  95. All = 0,
  96. Collate = 1,
  97. CType = 2,
  98. Monetary = 3,
  99. Numeric = 4,
  100. Time = 5,
  101. }
  102. internal class LocaleInfo {
  103. private readonly PythonContext _context;
  104. private PythonDictionary conv;
  105. public LocaleInfo(PythonContext context) {
  106. _context = context;
  107. }
  108. public CultureInfo Collate {
  109. get { return _context.CollateCulture; }
  110. set { _context.CollateCulture = value; }
  111. }
  112. public CultureInfo CType {
  113. get { return _context.CTypeCulture; }
  114. set { _context.CTypeCulture= value; }
  115. }
  116. public CultureInfo Time {
  117. get { return _context.TimeCulture; }
  118. set { _context.TimeCulture = value; }
  119. }
  120. public CultureInfo Monetary {
  121. get { return _context.MonetaryCulture; }
  122. set { _context.MonetaryCulture = value; }
  123. }
  124. public CultureInfo Numeric {
  125. get { return _context.NumericCulture; }
  126. set { _context.NumericCulture = value; }
  127. }
  128. public override string ToString() {
  129. return base.ToString();
  130. }
  131. public PythonDictionary GetConventionsTable() {
  132. CreateConventionsDict();
  133. return conv;
  134. }
  135. public string SetLocale(CodeContext/*!*/ context, int category, string locale) {
  136. switch ((LocaleCategories)category) {
  137. case LocaleCategories.All:
  138. SetLocale(context, LC_COLLATE, locale);
  139. SetLocale(context, LC_CTYPE, locale);
  140. SetLocale(context, LC_MONETARY, locale);
  141. SetLocale(context, LC_NUMERIC, locale);
  142. return SetLocale(context, LC_TIME, locale);
  143. case LocaleCategories.Collate:
  144. return CultureToName(Collate = LocaleToCulture(context, locale));
  145. case LocaleCategories.CType:
  146. return CultureToName(CType = LocaleToCulture(context, locale));
  147. case LocaleCategories.Time:
  148. return CultureToName(Time = LocaleToCulture(context, locale));
  149. case LocaleCategories.Monetary:
  150. Monetary = LocaleToCulture(context, locale);
  151. conv = null;
  152. return CultureToName(Monetary);
  153. case LocaleCategories.Numeric:
  154. Numeric = LocaleToCulture(context, locale);
  155. conv = null;
  156. return CultureToName(Numeric);
  157. default:
  158. throw PythonExceptions.CreateThrowable(_localeerror(context), "unknown locale category");
  159. }
  160. }
  161. public string GetLocale(CodeContext/*!*/ context, int category) {
  162. switch ((LocaleCategories)category) {
  163. case LocaleCategories.All:
  164. if (Collate == CType &&
  165. Collate == Time &&
  166. Collate == Monetary &&
  167. Collate == Numeric) {
  168. // they're all the same, return only 1 name
  169. goto case LocaleCategories.Collate;
  170. }
  171. // return them all...
  172. return String.Format("LC_COLLATE={0};LC_CTYPE={1};LC_MONETARY={2};LC_NUMERIC={3};LC_TIME={4}",
  173. GetLocale(context, LC_COLLATE),
  174. GetLocale(context, LC_CTYPE),
  175. GetLocale(context, LC_MONETARY),
  176. GetLocale(context, LC_NUMERIC),
  177. GetLocale(context, LC_TIME));
  178. case LocaleCategories.Collate: return CultureToName(Collate);
  179. case LocaleCategories.CType: return CultureToName(CType);
  180. case LocaleCategories.Time: return CultureToName(Time);
  181. case LocaleCategories.Monetary: return CultureToName(Monetary);
  182. case LocaleCategories.Numeric: return CultureToName(Numeric);
  183. default:
  184. throw PythonExceptions.CreateThrowable(_localeerror(context), "unknown locale category");
  185. }
  186. }
  187. public string CultureToName(CultureInfo culture) {
  188. if (culture == PythonContext.CCulture) {
  189. return "C";
  190. }
  191. return culture.Name.Replace('-', '_');
  192. }
  193. private CultureInfo LocaleToCulture(CodeContext/*!*/ context, string locale) {
  194. if (locale == "C") {
  195. return PythonContext.CCulture;
  196. }
  197. locale = locale.Replace('_', '-');
  198. try {
  199. return StringUtils.GetCultureInfo(locale);
  200. } catch (ArgumentException) {
  201. throw PythonExceptions.CreateThrowable(_localeerror(context), String.Format("unknown locale: {0}", locale));
  202. }
  203. }
  204. /// <summary>
  205. /// Popupates the given directory w/ the locale information from the given
  206. /// CultureInfo.
  207. /// </summary>
  208. private void CreateConventionsDict() {
  209. conv = new PythonDictionary();
  210. conv["decimal_point"] = Numeric.NumberFormat.NumberDecimalSeparator;
  211. conv["grouping"] = GroupsToList(Numeric.NumberFormat.NumberGroupSizes);
  212. conv["thousands_sep"] = Numeric.NumberFormat.NumberGroupSeparator;
  213. conv["mon_decimal_point"] = Monetary.NumberFormat.CurrencyDecimalSeparator;
  214. conv["mon_thousands_sep"] = Monetary.NumberFormat.CurrencyGroupSeparator;
  215. conv["mon_grouping"] = GroupsToList(Monetary.NumberFormat.CurrencyGroupSizes);
  216. conv["int_curr_symbol"] = Monetary.NumberFormat.CurrencySymbol;
  217. conv["currency_symbol"] = Monetary.NumberFormat.CurrencySymbol;
  218. conv["frac_digits"] = Monetary.NumberFormat.CurrencyDecimalDigits;
  219. conv["int_frac_digits"] = Monetary.NumberFormat.CurrencyDecimalDigits;
  220. conv["positive_sign"] = Monetary.NumberFormat.PositiveSign;
  221. conv["negative_sign"] = Monetary.NumberFormat.NegativeSign;
  222. conv["p_sign_posn"] = Monetary.NumberFormat.CurrencyPositivePattern;
  223. conv["n_sign_posn"] = Monetary.NumberFormat.CurrencyNegativePattern;
  224. }
  225. private static List GroupsToList(int[] groups) {
  226. // .NET: values from 0-9, if the last digit is zero, remaining digits
  227. // go ungrouped, otherwise they're grouped based upon the last value.
  228. // locale: ends in CHAR_MAX if no further grouping is performed, ends in
  229. // zero if the last group size is repeatedly used.
  230. List res = new List(groups);
  231. if (groups.Length > 0 && groups[groups.Length - 1] == 0) {
  232. // replace zero w/ CHAR_MAX, no further grouping is performed
  233. res[res.__len__() - 1] = CHAR_MAX;
  234. } else {
  235. // append 0 to indicate we should repeatedly use the last one
  236. res.AddNoLock(0);
  237. }
  238. return res;
  239. }
  240. }
  241. internal static LocaleInfo/*!*/ GetLocaleInfo(CodeContext/*!*/ context) {
  242. EnsureLocaleInitialized(PythonContext.GetContext(context));
  243. return (LocaleInfo)PythonContext.GetContext(context).GetModuleState(_localeKey);
  244. }
  245. private static PythonType _localeerror(CodeContext/*!*/ context) {
  246. return (PythonType)PythonContext.GetContext(context).GetModuleState("_localeerror");
  247. }
  248. }
  249. }