mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
Add locale implementation for windows
This commit is contained in:
committed by
Jeong YunWon
parent
c15f670f2c
commit
19193cd2a4
4
Lib/test/test_locale.py
vendored
4
Lib/test/test_locale.py
vendored
@@ -343,7 +343,6 @@ class TestFrFRNumberFormatting(FrFRCookedTest, BaseFormattingTest):
|
||||
class TestCollation(unittest.TestCase):
|
||||
# Test string collation functions
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_strcoll(self):
|
||||
self.assertLess(locale.strcoll('a', 'b'), 0)
|
||||
self.assertEqual(locale.strcoll('a', 'a'), 0)
|
||||
@@ -352,7 +351,6 @@ class TestCollation(unittest.TestCase):
|
||||
self.assertRaises(ValueError, locale.strcoll, 'a\0', 'a')
|
||||
self.assertRaises(ValueError, locale.strcoll, 'a', 'a\0')
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_strxfrm(self):
|
||||
self.assertLess(locale.strxfrm('a'), locale.strxfrm('b'))
|
||||
# embedded null character
|
||||
@@ -504,7 +502,6 @@ class NormalizeTest(unittest.TestCase):
|
||||
|
||||
|
||||
class TestMiscellaneous(unittest.TestCase):
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_defaults_UTF8(self):
|
||||
# Issue #18378: on (at least) macOS setting LC_CTYPE to "UTF-8" is
|
||||
# valid. Furthermore LC_CTYPE=UTF is used by the UTF-8 locale coercing
|
||||
@@ -562,7 +559,6 @@ class TestMiscellaneous(unittest.TestCase):
|
||||
self.assertRaises(TypeError, locale.strcoll, "a", None)
|
||||
self.assertRaises(TypeError, locale.strcoll, b"a", None)
|
||||
|
||||
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
|
||||
def test_setlocale_category(self):
|
||||
locale.setlocale(locale.LC_ALL)
|
||||
locale.setlocale(locale.LC_TIME)
|
||||
|
||||
@@ -115,4 +115,4 @@ features = [
|
||||
]
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
system-configuration = "0.5.0"
|
||||
system-configuration = "0.5.0"
|
||||
@@ -160,7 +160,7 @@ pub fn get_module_inits() -> impl Iterator<Item = (Cow<'static, str>, StdlibInit
|
||||
{
|
||||
"_uuid" => uuid::make_module,
|
||||
}
|
||||
#[cfg(all(unix, not(any(target_os = "ios", target_os = "android"))))]
|
||||
#[cfg(any(unix, windows, not(any(target_os = "ios", target_os = "android", target_arch="wasm32"))))]
|
||||
{
|
||||
"_locale" => locale::make_module,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,49 @@
|
||||
#[cfg(all(unix, not(any(target_os = "ios", target_os = "android"))))]
|
||||
#[cfg(any(
|
||||
unix,
|
||||
windows,
|
||||
not(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))
|
||||
))]
|
||||
pub(crate) use _locale::make_module;
|
||||
|
||||
#[cfg(all(unix, not(any(target_os = "ios", target_os = "android"))))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[repr(C)]
|
||||
struct lconv {
|
||||
decimal_point: *mut libc::c_char,
|
||||
thousands_sep: *mut libc::c_char,
|
||||
grouping: *mut libc::c_char,
|
||||
int_curr_symbol: *mut libc::c_char,
|
||||
currency_symbol: *mut libc::c_char,
|
||||
mon_decimal_point: *mut libc::c_char,
|
||||
mon_thousands_sep: *mut libc::c_char,
|
||||
mon_grouping: *mut libc::c_char,
|
||||
positive_sign: *mut libc::c_char,
|
||||
negative_sign: *mut libc::c_char,
|
||||
int_frac_digits: libc::c_char,
|
||||
frac_digits: libc::c_char,
|
||||
p_cs_precedes: libc::c_char,
|
||||
p_sep_by_space: libc::c_char,
|
||||
n_cs_precedes: libc::c_char,
|
||||
n_sep_by_space: libc::c_char,
|
||||
p_sign_posn: libc::c_char,
|
||||
n_sign_posn: libc::c_char,
|
||||
int_p_cs_precedes: libc::c_char,
|
||||
int_n_cs_precedes: libc::c_char,
|
||||
int_p_sep_by_space: libc::c_char,
|
||||
int_n_sep_by_space: libc::c_char,
|
||||
int_p_sign_posn: libc::c_char,
|
||||
int_n_sign_posn: libc::c_char,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
extern "C" {
|
||||
fn localeconv() -> *mut lconv;
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
windows,
|
||||
not(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))
|
||||
))]
|
||||
#[pymodule]
|
||||
mod _locale {
|
||||
use rustpython_vm::{
|
||||
@@ -15,17 +57,25 @@ mod _locale {
|
||||
ptr,
|
||||
};
|
||||
|
||||
#[cfg(all(unix, not(any(target_os = "ios", target_os = "android"))))]
|
||||
#[pyattr]
|
||||
use libc::{
|
||||
ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7, ABMON_1, ABMON_10, ABMON_11,
|
||||
ABMON_12, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9,
|
||||
ALT_DIGITS, AM_STR, CODESET, CRNCYSTR, DAY_1, DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7,
|
||||
D_FMT, D_T_FMT, ERA, ERA_D_FMT, ERA_D_T_FMT, ERA_T_FMT, LC_ALL, LC_COLLATE, LC_CTYPE,
|
||||
LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME, MON_1, MON_10, MON_11, MON_12, MON_2, MON_3,
|
||||
MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, NOEXPR, PM_STR, RADIXCHAR, THOUSEP, T_FMT,
|
||||
T_FMT_AMPM, YESEXPR,
|
||||
D_FMT, D_T_FMT, ERA, ERA_D_FMT, ERA_D_T_FMT, ERA_T_FMT, LC_MESSAGES, MON_1, MON_10, MON_11,
|
||||
MON_12, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, NOEXPR, PM_STR, RADIXCHAR,
|
||||
THOUSEP, T_FMT, T_FMT_AMPM, YESEXPR,
|
||||
};
|
||||
|
||||
#[pyattr]
|
||||
use libc::{LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME};
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
windows,
|
||||
not(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))
|
||||
))]
|
||||
#[pyattr(name = "CHAR_MAX")]
|
||||
fn char_max(vm: &VirtualMachine) -> PyIntRef {
|
||||
vm.ctx.new_int(libc::c_char::MAX)
|
||||
@@ -58,6 +108,11 @@ mod _locale {
|
||||
Ok(vm.new_pyobj(string))
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
windows,
|
||||
not(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))
|
||||
))]
|
||||
#[pyattr(name = "Error", once)]
|
||||
fn error(vm: &VirtualMachine) -> PyTypeRef {
|
||||
vm.ctx.new_exception_type(
|
||||
@@ -67,6 +122,11 @@ mod _locale {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
windows,
|
||||
not(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))
|
||||
))]
|
||||
#[pyfunction]
|
||||
fn strcoll(string1: PyStrRef, string2: PyStrRef, vm: &VirtualMachine) -> PyResult {
|
||||
let cstr1 = CString::new(string1.as_str()).map_err(|e| e.to_pyexception(vm))?;
|
||||
@@ -74,69 +134,76 @@ mod _locale {
|
||||
Ok(vm.new_pyobj(unsafe { libc::strcoll(cstr1.as_ptr(), cstr2.as_ptr()) }))
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
windows,
|
||||
not(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))
|
||||
))]
|
||||
#[pyfunction]
|
||||
fn strxfrm(string: PyStrRef, vm: &VirtualMachine) -> PyResult {
|
||||
// https://github.com/python/cpython/blob/eaae563b6878aa050b4ad406b67728b6b066220e/Modules/_localemodule.c#L390-L442
|
||||
let n1 = string.byte_len() + 1;
|
||||
let mut buff: Vec<u8> = vec![0; n1];
|
||||
let mut buff = vec![0u8; n1];
|
||||
|
||||
let cstr = CString::new(string.as_str()).map_err(|e| e.to_pyexception(vm))?;
|
||||
let n2 = unsafe { libc::strxfrm(buff.as_mut_ptr() as _, cstr.as_ptr(), n1) };
|
||||
buff.truncate(n2);
|
||||
buff = vec![0u8; n2 + 1];
|
||||
unsafe {
|
||||
libc::strxfrm(buff.as_mut_ptr() as _, cstr.as_ptr(), n2 + 1);
|
||||
}
|
||||
Ok(vm.new_pyobj(String::from_utf8(buff).expect("strxfrm returned invalid utf-8 string")))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn localeconv(vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
#[pyfunction(name = "localeconv")]
|
||||
fn _localeconv(vm: &VirtualMachine) -> PyResult<PyDictRef> {
|
||||
let result = vm.ctx.new_dict();
|
||||
|
||||
unsafe {
|
||||
let lc = libc::localeconv();
|
||||
|
||||
macro_rules! set_string_field {
|
||||
($field:ident) => {{
|
||||
($lc:expr, $field:ident) => {{
|
||||
result.set_item(
|
||||
stringify!($field),
|
||||
pystr_from_raw_cstr(vm, (*lc).$field)?,
|
||||
pystr_from_raw_cstr(vm, (*$lc).$field)?,
|
||||
vm,
|
||||
)?
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! set_int_field {
|
||||
($field:ident) => {{
|
||||
result.set_item(stringify!($field), vm.new_pyobj((*lc).$field), vm)?
|
||||
($lc:expr, $field:ident) => {{
|
||||
result.set_item(stringify!($field), vm.new_pyobj((*$lc).$field), vm)?
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! set_group_field {
|
||||
($field:ident) => {{
|
||||
($lc:expr, $field:ident) => {{
|
||||
result.set_item(
|
||||
stringify!($field),
|
||||
copy_grouping((*lc).$field, vm).into(),
|
||||
copy_grouping((*$lc).$field, vm).into(),
|
||||
vm,
|
||||
)?
|
||||
}};
|
||||
}
|
||||
|
||||
set_group_field!(mon_grouping);
|
||||
set_group_field!(grouping);
|
||||
set_int_field!(int_frac_digits);
|
||||
set_int_field!(frac_digits);
|
||||
set_int_field!(p_cs_precedes);
|
||||
set_int_field!(p_sep_by_space);
|
||||
set_int_field!(n_cs_precedes);
|
||||
set_int_field!(p_sign_posn);
|
||||
set_int_field!(n_sign_posn);
|
||||
set_string_field!(decimal_point);
|
||||
set_string_field!(thousands_sep);
|
||||
set_string_field!(int_curr_symbol);
|
||||
set_string_field!(currency_symbol);
|
||||
set_string_field!(mon_decimal_point);
|
||||
set_string_field!(mon_thousands_sep);
|
||||
set_int_field!(n_sep_by_space);
|
||||
set_string_field!(positive_sign);
|
||||
set_string_field!(negative_sign);
|
||||
let lc = super::localeconv();
|
||||
set_group_field!(lc, mon_grouping);
|
||||
set_group_field!(lc, grouping);
|
||||
set_int_field!(lc, int_frac_digits);
|
||||
set_int_field!(lc, frac_digits);
|
||||
set_int_field!(lc, p_cs_precedes);
|
||||
set_int_field!(lc, p_sep_by_space);
|
||||
set_int_field!(lc, n_cs_precedes);
|
||||
set_int_field!(lc, p_sign_posn);
|
||||
set_int_field!(lc, n_sign_posn);
|
||||
set_string_field!(lc, decimal_point);
|
||||
set_string_field!(lc, thousands_sep);
|
||||
set_string_field!(lc, int_curr_symbol);
|
||||
set_string_field!(lc, currency_symbol);
|
||||
set_string_field!(lc, mon_decimal_point);
|
||||
set_string_field!(lc, mon_thousands_sep);
|
||||
set_int_field!(lc, n_sep_by_space);
|
||||
set_string_field!(lc, positive_sign);
|
||||
set_string_field!(lc, negative_sign);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
@@ -149,8 +216,17 @@ mod _locale {
|
||||
locale: OptionalArg<Option<PyStrRef>>,
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
unix,
|
||||
windows,
|
||||
not(any(target_os = "ios", target_os = "android", target_arch = "wasm32"))
|
||||
))]
|
||||
#[pyfunction]
|
||||
fn setlocale(args: LocaleArgs, vm: &VirtualMachine) -> PyResult {
|
||||
let error = error(vm);
|
||||
if cfg!(windows) && (args.category < LC_ALL || args.category > LC_TIME) {
|
||||
return Err(vm.new_exception_msg(error, String::from("unsupported locale setting")));
|
||||
}
|
||||
unsafe {
|
||||
let result = match args.locale.flatten() {
|
||||
None => libc::setlocale(args.category, ptr::null()),
|
||||
@@ -161,7 +237,6 @@ mod _locale {
|
||||
}
|
||||
};
|
||||
if result.is_null() {
|
||||
let error = error(vm);
|
||||
return Err(vm.new_exception_msg(error, String::from("unsupported locale setting")));
|
||||
}
|
||||
pystr_from_raw_cstr(vm, result)
|
||||
|
||||
Reference in New Issue
Block a user