PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_locale.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 290 lines | 222 code | 42 blank | 26 comment | 18 complexity | 82f9230311c44a67339a44e40779eeff MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. 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 Microsoft Public License, 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 Microsoft Public License.
  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. [Documentation("gets the default locale tuple")]
  48. public static object _getdefaultlocale() {
  49. return PythonTuple.MakeTuple(
  50. CultureInfo.CurrentCulture.Name.Replace('-', '_').Replace(' ', '_'),
  51. #if !SILVERLIGHT // No ANSICodePage in Silverlight
  52. "cp" + CultureInfo.CurrentCulture.TextInfo.ANSICodePage.ToString()
  53. #else
  54. ""
  55. #endif
  56. );
  57. }
  58. [Documentation(@"gets the locale's convetions table.
  59. The conventions table is a dictionary that contains information on how to use
  60. the locale for numeric and monetary formatting")]
  61. public static object localeconv(CodeContext/*!*/ context) {
  62. return GetLocaleInfo(context).GetConventionsTable();
  63. }
  64. [Documentation(@"Sets the current locale for the given category.
  65. LC_ALL: sets locale for all options below
  66. LC_COLLATE: sets locale for collation (strcoll and strxfrm) only
  67. LC_CTYPE: sets locale for CType [unused]
  68. LC_MONETARY: sets locale for the monetary functions (localeconv())
  69. LC_NUMERIC: sets the locale for numeric functions (slocaleconv())
  70. LC_TIME: sets the locale for time functions [unused]
  71. If locale is None then the current setting is returned.
  72. ")]
  73. public static object setlocale(CodeContext/*!*/ context, int category, [DefaultParameterValue(null)]string locale) {
  74. LocaleInfo li = GetLocaleInfo(context);
  75. if (locale == null) {
  76. return li.GetLocale(context, category);
  77. }
  78. return li.SetLocale(context, category, locale);
  79. }
  80. [Documentation("compares two strings using the current locale")]
  81. public static int strcoll(CodeContext/*!*/ context, string string1, string string2) {
  82. return GetLocaleInfo(context).Collate.CompareInfo.Compare(string1, string2, CompareOptions.None);
  83. }
  84. [Documentation(@"returns a transformed string that can be compared using the built-in cmp.
  85. Currently returns the string unmodified")]
  86. public static object strxfrm(string @string) {
  87. return @string;
  88. }
  89. private enum LocaleCategories {
  90. All = 0,
  91. Collate = 1,
  92. CType = 2,
  93. Monetary = 3,
  94. Numeric = 4,
  95. Time = 5,
  96. }
  97. internal class LocaleInfo {
  98. private readonly PythonContext _context;
  99. private PythonDictionary conv;
  100. public LocaleInfo(PythonContext context) {
  101. _context = context;
  102. }
  103. public CultureInfo Collate {
  104. get { return _context.CollateCulture; }
  105. set { _context.CollateCulture = value; }
  106. }
  107. public CultureInfo CType {
  108. get { return _context.CTypeCulture; }
  109. set { _context.CTypeCulture= value; }
  110. }
  111. public CultureInfo Time {
  112. get { return _context.TimeCulture; }
  113. set { _context.TimeCulture = value; }
  114. }
  115. public CultureInfo Monetary {
  116. get { return _context.MonetaryCulture; }
  117. set { _context.MonetaryCulture = value; }
  118. }
  119. public CultureInfo Numeric {
  120. get { return _context.NumericCulture; }
  121. set { _context.NumericCulture = value; }
  122. }
  123. public override string ToString() {
  124. return base.ToString();
  125. }
  126. public PythonDictionary GetConventionsTable() {
  127. CreateConventionsDict();
  128. return conv;
  129. }
  130. public string SetLocale(CodeContext/*!*/ context, int category, string locale) {
  131. switch ((LocaleCategories)category) {
  132. case LocaleCategories.All:
  133. SetLocale(context, LC_COLLATE, locale);
  134. SetLocale(context, LC_CTYPE, locale);
  135. SetLocale(context, LC_MONETARY, locale);
  136. SetLocale(context, LC_NUMERIC, locale);
  137. return SetLocale(context, LC_TIME, locale);
  138. case LocaleCategories.Collate:
  139. return CultureToName(Collate = LocaleToCulture(context, locale));
  140. case LocaleCategories.CType:
  141. return CultureToName(CType = LocaleToCulture(context, locale));
  142. case LocaleCategories.Time:
  143. return CultureToName(Time = LocaleToCulture(context, locale));
  144. case LocaleCategories.Monetary:
  145. Monetary = LocaleToCulture(context, locale);
  146. conv = null;
  147. return CultureToName(Monetary);
  148. case LocaleCategories.Numeric:
  149. Numeric = LocaleToCulture(context, locale);
  150. conv = null;
  151. return CultureToName(Numeric);
  152. default:
  153. throw PythonExceptions.CreateThrowable(_localeerror(context), "unknown locale category");
  154. }
  155. }
  156. public string GetLocale(CodeContext/*!*/ context, int category) {
  157. switch ((LocaleCategories)category) {
  158. case LocaleCategories.All:
  159. if (Collate == CType &&
  160. Collate == Time &&
  161. Collate == Monetary &&
  162. Collate == Numeric) {
  163. // they're all the same, return only 1 name
  164. goto case LocaleCategories.Collate;
  165. }
  166. // return them all...
  167. return String.Format("LC_COLLATE={0};LC_CTYPE={1};LC_MONETARY={2};LC_NUMERIC={3};LC_TIME={4}",
  168. GetLocale(context, LC_COLLATE),
  169. GetLocale(context, LC_CTYPE),
  170. GetLocale(context, LC_MONETARY),
  171. GetLocale(context, LC_NUMERIC),
  172. GetLocale(context, LC_TIME));
  173. case LocaleCategories.Collate: return CultureToName(Collate);
  174. case LocaleCategories.CType: return CultureToName(CType);
  175. case LocaleCategories.Time: return CultureToName(Time);
  176. case LocaleCategories.Monetary: return CultureToName(Monetary);
  177. case LocaleCategories.Numeric: return CultureToName(Numeric);
  178. default:
  179. throw PythonExceptions.CreateThrowable(_localeerror(context), "unknown locale category");
  180. }
  181. }
  182. public string CultureToName(CultureInfo culture) {
  183. if (culture == PythonContext.CCulture) {
  184. return "C";
  185. }
  186. return culture.Name.Replace('-', '_');
  187. }
  188. private CultureInfo LocaleToCulture(CodeContext/*!*/ context, string locale) {
  189. if (locale == "C") {
  190. return PythonContext.CCulture;
  191. }
  192. locale = locale.Replace('_', '-');
  193. try {
  194. return StringUtils.GetCultureInfo(locale);
  195. } catch (ArgumentException) {
  196. throw PythonExceptions.CreateThrowable(_localeerror(context), String.Format("unknown locale: {0}", locale));
  197. }
  198. }
  199. /// <summary>
  200. /// Popupates the given directory w/ the locale information from the given
  201. /// CultureInfo.
  202. /// </summary>
  203. private void CreateConventionsDict() {
  204. conv = new PythonDictionary();
  205. conv["decimal_point"] = Numeric.NumberFormat.NumberDecimalSeparator;
  206. conv["grouping"] = GroupsToList(Numeric.NumberFormat.NumberGroupSizes);
  207. conv["thousands_sep"] = Numeric.NumberFormat.NumberGroupSeparator;
  208. conv["mon_decimal_point"] = Monetary.NumberFormat.CurrencyDecimalSeparator;
  209. conv["mon_thousands_sep"] = Monetary.NumberFormat.CurrencyGroupSeparator;
  210. conv["mon_grouping"] = GroupsToList(Monetary.NumberFormat.CurrencyGroupSizes);
  211. conv["int_curr_symbol"] = Monetary.NumberFormat.CurrencySymbol;
  212. conv["currency_symbol"] = Monetary.NumberFormat.CurrencySymbol;
  213. conv["frac_digits"] = Monetary.NumberFormat.CurrencyDecimalDigits;
  214. conv["int_frac_digits"] = Monetary.NumberFormat.CurrencyDecimalDigits;
  215. conv["positive_sign"] = Monetary.NumberFormat.PositiveSign;
  216. conv["negative_sign"] = Monetary.NumberFormat.NegativeSign;
  217. conv["p_sign_posn"] = Monetary.NumberFormat.CurrencyPositivePattern;
  218. conv["n_sign_posn"] = Monetary.NumberFormat.CurrencyNegativePattern;
  219. }
  220. private static List GroupsToList(int[] groups) {
  221. // .NET: values from 0-9, if the last digit is zero, remaining digits
  222. // go ungrouped, otherwise they're grouped based upon the last value.
  223. // locale: ends in CHAR_MAX if no further grouping is performed, ends in
  224. // zero if the last group size is repeatedly used.
  225. List res = new List(groups);
  226. if (groups.Length > 0 && groups[groups.Length - 1] == 0) {
  227. // replace zero w/ CHAR_MAX, no further grouping is performed
  228. res[res.__len__() - 1] = CHAR_MAX;
  229. } else {
  230. // append 0 to indicate we should repeatedly use the last one
  231. res.AddNoLock(0);
  232. }
  233. return res;
  234. }
  235. }
  236. internal static LocaleInfo/*!*/ GetLocaleInfo(CodeContext/*!*/ context) {
  237. EnsureLocaleInitialized(PythonContext.GetContext(context));
  238. return (LocaleInfo)PythonContext.GetContext(context).GetModuleState(_localeKey);
  239. }
  240. private static PythonType _localeerror(CodeContext/*!*/ context) {
  241. return (PythonType)PythonContext.GetContext(context).GetModuleState("_localeerror");
  242. }
  243. }
  244. }