PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/_locale/interp_locale.py

https://bitbucket.org/pypy/pypy/
Python | 366 lines | 358 code | 7 blank | 1 comment | 2 complexity | 5d158a70a3634541cfb106dc64b78ba6 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rlib import rposix
  2. from rpython.rlib.rarithmetic import intmask
  3. from pypy.interpreter.error import OperationError, oefmt
  4. from pypy.interpreter.gateway import unwrap_spec
  5. from rpython.rlib import rlocale
  6. from pypy.module.exceptions.interp_exceptions import _new_exception, W_Exception
  7. from rpython.rtyper.lltypesystem import lltype, rffi
  8. W_Error = _new_exception('Error', W_Exception, 'locale error')
  9. import sys
  10. def make_error(space, msg):
  11. return OperationError(space.gettypeobject(W_Error.typedef), space.wrap(msg))
  12. def rewrap_error(space, e):
  13. return OperationError(space.gettypeobject(W_Error.typedef),
  14. space.wrap(e.message))
  15. def _fixup_ulcase(space):
  16. stringmod = space.call_function(
  17. space.getattr(space.getbuiltinmodule('__builtin__'),
  18. space.wrap('__import__')), space.wrap('string'))
  19. # create uppercase map string
  20. ul = []
  21. for c in xrange(256):
  22. if rlocale.isupper(c):
  23. ul.append(chr(c))
  24. space.setattr(stringmod, space.wrap('uppercase'), space.wrap(''.join(ul)))
  25. # create lowercase string
  26. ul = []
  27. for c in xrange(256):
  28. if rlocale.islower(c):
  29. ul.append(chr(c))
  30. space.setattr(stringmod, space.wrap('lowercase'), space.wrap(''.join(ul)))
  31. # create letters string
  32. ul = []
  33. for c in xrange(256):
  34. if rlocale.isalpha(c):
  35. ul.append(chr(c))
  36. space.setattr(stringmod, space.wrap('letters'), space.wrap(''.join(ul)))
  37. @unwrap_spec(category=int)
  38. def setlocale(space, category, w_locale=None):
  39. "(integer,string=None) -> string. Activates/queries locale processing."
  40. if space.is_none(w_locale):
  41. locale = None
  42. else:
  43. locale = space.str_w(w_locale)
  44. try:
  45. result = rlocale.setlocale(category, locale)
  46. except rlocale.LocaleError as e:
  47. raise rewrap_error(space, e)
  48. # record changes to LC_CTYPE
  49. if category in (rlocale.LC_CTYPE, rlocale.LC_ALL):
  50. _fixup_ulcase(space)
  51. return space.wrap(result)
  52. def _w_copy_grouping(space, text):
  53. groups = [ space.wrap(ord(group)) for group in text ]
  54. if groups:
  55. groups.append(space.wrap(0))
  56. return space.newlist(groups)
  57. def localeconv(space):
  58. "() -> dict. Returns numeric and monetary locale-specific parameters."
  59. lp = rlocale.localeconv()
  60. # Numeric information
  61. w_result = space.newdict()
  62. w = space.wrap
  63. space.setitem(w_result, w("decimal_point"),
  64. w(rffi.charp2str(lp.c_decimal_point)))
  65. space.setitem(w_result, w("thousands_sep"),
  66. w(rffi.charp2str(lp.c_thousands_sep)))
  67. space.setitem(w_result, w("grouping"),
  68. _w_copy_grouping(space, rffi.charp2str(lp.c_grouping)))
  69. space.setitem(w_result, w("int_curr_symbol"),
  70. w(rffi.charp2str(lp.c_int_curr_symbol)))
  71. space.setitem(w_result, w("currency_symbol"),
  72. w(rffi.charp2str(lp.c_currency_symbol)))
  73. space.setitem(w_result, w("mon_decimal_point"),
  74. w(rffi.charp2str(lp.c_mon_decimal_point)))
  75. space.setitem(w_result, w("mon_thousands_sep"),
  76. w(rffi.charp2str(lp.c_mon_thousands_sep)))
  77. space.setitem(w_result, w("mon_grouping"),
  78. _w_copy_grouping(space, rffi.charp2str(lp.c_mon_grouping)))
  79. space.setitem(w_result, w("positive_sign"),
  80. w(rffi.charp2str(lp.c_positive_sign)))
  81. space.setitem(w_result, w("negative_sign"),
  82. w(rffi.charp2str(lp.c_negative_sign)))
  83. space.setitem(w_result, w("int_frac_digits"),
  84. w(lp.c_int_frac_digits))
  85. space.setitem(w_result, w("frac_digits"),
  86. w(lp.c_frac_digits))
  87. space.setitem(w_result, w("p_cs_precedes"),
  88. w(lp.c_p_cs_precedes))
  89. space.setitem(w_result, w("p_sep_by_space"),
  90. w(lp.c_p_sep_by_space))
  91. space.setitem(w_result, w("n_cs_precedes"),
  92. w(lp.c_n_cs_precedes))
  93. space.setitem(w_result, w("n_sep_by_space"),
  94. w(lp.c_n_sep_by_space))
  95. space.setitem(w_result, w("p_sign_posn"),
  96. w(lp.c_p_sign_posn))
  97. space.setitem(w_result, w("n_sign_posn"),
  98. w(lp.c_n_sign_posn))
  99. return w_result
  100. _strcoll = rlocale.external('strcoll', [rffi.CCHARP, rffi.CCHARP], rffi.INT)
  101. _wcscoll = rlocale.external('wcscoll', [rffi.CWCHARP, rffi.CWCHARP], rffi.INT)
  102. def strcoll(space, w_s1, w_s2):
  103. "string,string -> int. Compares two strings according to the locale."
  104. if (space.isinstance_w(w_s1, space.w_str) and
  105. space.isinstance_w(w_s2, space.w_str)):
  106. s1, s2 = space.str_w(w_s1), space.str_w(w_s2)
  107. s1_c = rffi.str2charp(s1)
  108. s2_c = rffi.str2charp(s2)
  109. try:
  110. return space.wrap(_strcoll(s1_c, s2_c))
  111. finally:
  112. rffi.free_charp(s1_c)
  113. rffi.free_charp(s2_c)
  114. s1, s2 = space.unicode_w(w_s1), space.unicode_w(w_s2)
  115. s1_c = rffi.unicode2wcharp(s1)
  116. s2_c = rffi.unicode2wcharp(s2)
  117. try:
  118. result = _wcscoll(s1_c, s2_c)
  119. finally:
  120. rffi.free_wcharp(s1_c)
  121. rffi.free_wcharp(s2_c)
  122. return space.wrap(result)
  123. _strxfrm = rlocale.external('strxfrm',
  124. [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SIZE_T)
  125. @unwrap_spec(s=str)
  126. def strxfrm(space, s):
  127. "string -> string. Returns a string that behaves for cmp locale-aware."
  128. n1 = len(s) + 1
  129. buf = lltype.malloc(rffi.CCHARP.TO, n1, flavor="raw", zero=True)
  130. s_c = rffi.str2charp(s)
  131. try:
  132. n2 = _strxfrm(buf, s_c, n1) + 1
  133. finally:
  134. rffi.free_charp(s_c)
  135. if n2 > n1:
  136. # more space needed
  137. lltype.free(buf, flavor="raw")
  138. buf = lltype.malloc(rffi.CCHARP.TO, intmask(n2),
  139. flavor="raw", zero=True)
  140. s_c = rffi.str2charp(s)
  141. try:
  142. _strxfrm(buf, s_c, n2)
  143. finally:
  144. rffi.free_charp(s_c)
  145. val = rffi.charp2str(buf)
  146. lltype.free(buf, flavor="raw")
  147. return space.wrap(val)
  148. if rlocale.HAVE_LANGINFO:
  149. @unwrap_spec(key=int)
  150. def nl_langinfo(space, key):
  151. """nl_langinfo(key) -> string
  152. Return the value for the locale information associated with key."""
  153. try:
  154. return space.wrap(rlocale.nl_langinfo(key))
  155. except ValueError:
  156. raise oefmt(space.w_ValueError, "unsupported langinfo constant")
  157. #___________________________________________________________________
  158. # HAVE_LIBINTL dependence
  159. if rlocale.HAVE_LIBINTL:
  160. _gettext = rlocale.external('gettext', [rffi.CCHARP], rffi.CCHARP)
  161. @unwrap_spec(msg=str)
  162. def gettext(space, msg):
  163. """gettext(msg) -> string
  164. Return translation of msg."""
  165. msg_c = rffi.str2charp(msg)
  166. try:
  167. return space.wrap(rffi.charp2str(_gettext(msg_c)))
  168. finally:
  169. rffi.free_charp(msg_c)
  170. _dgettext = rlocale.external('dgettext', [rffi.CCHARP, rffi.CCHARP], rffi.CCHARP)
  171. @unwrap_spec(msg=str)
  172. def dgettext(space, w_domain, msg):
  173. """dgettext(domain, msg) -> string
  174. Return translation of msg in domain."""
  175. if space.is_w(w_domain, space.w_None):
  176. domain = None
  177. msg_c = rffi.str2charp(msg)
  178. try:
  179. result = _dgettext(domain, msg_c)
  180. # note that 'result' may be the same pointer as 'msg_c',
  181. # so it must be converted to an RPython string *before*
  182. # we free msg_c.
  183. result = rffi.charp2str(result)
  184. finally:
  185. rffi.free_charp(msg_c)
  186. else:
  187. domain = space.str_w(w_domain)
  188. domain_c = rffi.str2charp(domain)
  189. msg_c = rffi.str2charp(msg)
  190. try:
  191. result = _dgettext(domain_c, msg_c)
  192. # note that 'result' may be the same pointer as 'msg_c',
  193. # so it must be converted to an RPython string *before*
  194. # we free msg_c.
  195. result = rffi.charp2str(result)
  196. finally:
  197. rffi.free_charp(domain_c)
  198. rffi.free_charp(msg_c)
  199. return space.wrap(result)
  200. _dcgettext = rlocale.external('dcgettext', [rffi.CCHARP, rffi.CCHARP, rffi.INT],
  201. rffi.CCHARP)
  202. @unwrap_spec(msg=str, category=int)
  203. def dcgettext(space, w_domain, msg, category):
  204. """dcgettext(domain, msg, category) -> string
  205. Return translation of msg in domain and category."""
  206. if space.is_w(w_domain, space.w_None):
  207. domain = None
  208. msg_c = rffi.str2charp(msg)
  209. try:
  210. result = _dcgettext(domain, msg_c, rffi.cast(rffi.INT, category))
  211. # note that 'result' may be the same pointer as 'msg_c',
  212. # so it must be converted to an RPython string *before*
  213. # we free msg_c.
  214. result = rffi.charp2str(result)
  215. finally:
  216. rffi.free_charp(msg_c)
  217. else:
  218. domain = space.str_w(w_domain)
  219. domain_c = rffi.str2charp(domain)
  220. msg_c = rffi.str2charp(msg)
  221. try:
  222. result = _dcgettext(domain_c, msg_c,
  223. rffi.cast(rffi.INT, category))
  224. # note that 'result' may be the same pointer as 'msg_c',
  225. # so it must be converted to an RPython string *before*
  226. # we free msg_c.
  227. result = rffi.charp2str(result)
  228. finally:
  229. rffi.free_charp(domain_c)
  230. rffi.free_charp(msg_c)
  231. return space.wrap(result)
  232. _textdomain = rlocale.external('textdomain', [rffi.CCHARP], rffi.CCHARP)
  233. def textdomain(space, w_domain):
  234. """textdomain(domain) -> string
  235. Set the C library's textdomain to domain, returning the new domain."""
  236. if space.is_w(w_domain, space.w_None):
  237. domain = None
  238. result = _textdomain(domain)
  239. result = rffi.charp2str(result)
  240. else:
  241. domain = space.str_w(w_domain)
  242. domain_c = rffi.str2charp(domain)
  243. try:
  244. result = _textdomain(domain_c)
  245. # note that 'result' may be the same pointer as 'domain_c'
  246. # (maybe?) so it must be converted to an RPython string
  247. # *before* we free domain_c.
  248. result = rffi.charp2str(result)
  249. finally:
  250. rffi.free_charp(domain_c)
  251. return space.wrap(result)
  252. _bindtextdomain = rlocale.external('bindtextdomain', [rffi.CCHARP, rffi.CCHARP],
  253. rffi.CCHARP,
  254. save_err=rffi.RFFI_SAVE_ERRNO)
  255. @unwrap_spec(domain=str)
  256. def bindtextdomain(space, domain, w_dir):
  257. """bindtextdomain(domain, dir) -> string
  258. Bind the C library's domain to dir."""
  259. if space.is_w(w_dir, space.w_None):
  260. dir = None
  261. domain_c = rffi.str2charp(domain)
  262. try:
  263. dirname = _bindtextdomain(domain_c, dir)
  264. finally:
  265. rffi.free_charp(domain_c)
  266. else:
  267. dir = space.str_w(w_dir)
  268. domain_c = rffi.str2charp(domain)
  269. dir_c = rffi.str2charp(dir)
  270. try:
  271. dirname = _bindtextdomain(domain_c, dir_c)
  272. finally:
  273. rffi.free_charp(domain_c)
  274. rffi.free_charp(dir_c)
  275. if not dirname:
  276. errno = rposix.get_saved_errno()
  277. raise OperationError(space.w_OSError, space.wrap(errno))
  278. return space.wrap(rffi.charp2str(dirname))
  279. _bind_textdomain_codeset = rlocale.external('bind_textdomain_codeset',
  280. [rffi.CCHARP, rffi.CCHARP], rffi.CCHARP)
  281. if rlocale.HAVE_BIND_TEXTDOMAIN_CODESET:
  282. @unwrap_spec(domain=str)
  283. def bind_textdomain_codeset(space, domain, w_codeset):
  284. """bind_textdomain_codeset(domain, codeset) -> string
  285. Bind the C library's domain to codeset."""
  286. if space.is_w(w_codeset, space.w_None):
  287. codeset = None
  288. domain_c = rffi.str2charp(domain)
  289. try:
  290. result = _bind_textdomain_codeset(domain_c, codeset)
  291. finally:
  292. rffi.free_charp(domain_c)
  293. else:
  294. codeset = space.str_w(w_codeset)
  295. domain_c = rffi.str2charp(domain)
  296. codeset_c = rffi.str2charp(codeset)
  297. try:
  298. result = _bind_textdomain_codeset(domain_c, codeset_c)
  299. finally:
  300. rffi.free_charp(domain_c)
  301. rffi.free_charp(codeset_c)
  302. if not result:
  303. return space.w_None
  304. else:
  305. return space.wrap(rffi.charp2str(result))
  306. if sys.platform == 'win32':
  307. def getdefaultlocale(space):
  308. language, encoding = rlocale.getdefaultlocale()
  309. return space.newtuple([space.wrap(language), space.wrap(encoding)])