-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add localeconv function to locale module #4558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 26 commits
b3e39a2
1ed1b29
7e9390c
b2c1e5f
0dd95e0
65f5036
359c696
1533f7b
09c750c
844a30a
26f103a
9374005
757545f
184f891
ecc21e8
973d2b2
2d37933
082d1ef
f5730c4
31941a4
0c5ecb5
26f04e2
0268af5
44a36af
9801409
fcfa35a
a44a593
9e5be11
6291ca9
38d2253
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
#[cfg(all(unix, not(any(target_os = "ios", target_os = "android"))))] | ||
pub(crate) use _locale::make_module; | ||
|
||
#[cfg(all(unix, not(any(target_os = "ios", target_os = "android"))))] | ||
#[pymodule] | ||
mod _locale { | ||
use rustpython_vm::{ | ||
builtins::{PyDictRef, PyIntRef, PyListRef, PyStrRef, PyTypeRef}, | ||
function::OptionalArg, | ||
PyObjectRef, PyResult, VirtualMachine, | ||
}; | ||
|
||
#[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, | ||
}; | ||
Comment on lines
+18
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not all of these constants are available on every platform. When I encountered this sort of problem in the past, I looked up each item individually in the I realized back then (and I still maintain) that this process would prove to be tedious and error-prone. Perhaps I should look into using the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried with Window locale.h this afternoon and found out that Window API uses different naming convention (prefix with W, if I remember). Hence, if we would like to fix it, I'm afraid that we need to implement our own locale interaction. I will do it in another PR once this module takes shape. Right now, I put this module limit to unix system only! |
||
|
||
use std::{ | ||
ffi::{CStr, CString}, | ||
ptr, | ||
}; | ||
|
||
#[pyattr(name = "CHAR_MAX")] | ||
fn char_max(vm: &VirtualMachine) -> PyIntRef { | ||
vm.ctx.new_int(libc::c_char::MAX) | ||
} | ||
|
||
unsafe fn copy_grouping(group: *mut libc::c_char, vm: &VirtualMachine) -> PyListRef { | ||
let mut group_vec: Vec<PyObjectRef> = Vec::new(); | ||
let mut ptr = group; | ||
|
||
while ![0_i8, libc::c_char::MAX].contains(&*ptr) { | ||
let val = vm.ctx.new_int(*ptr); | ||
group_vec.push(val.into()); | ||
ptr = ptr.offset(1); | ||
} | ||
// https://github.com/python/cpython/blob/677320348728ce058fa3579017e985af74a236d4/Modules/_localemodule.c#L80 | ||
if !group_vec.is_empty() { | ||
group_vec.push(vm.ctx.new_int(0i32).into()); | ||
} | ||
vm.ctx.new_list(group_vec) | ||
} | ||
|
||
unsafe fn _parse_ptr_to_str(vm: &VirtualMachine, raw_ptr: *const libc::c_char) -> PyResult { | ||
let slice = unsafe { CStr::from_ptr(raw_ptr) }; | ||
let cstr = slice | ||
.to_str() | ||
.expect("localeconv always return decodable string"); | ||
|
||
Ok(vm.new_pyobj(cstr)) | ||
} | ||
|
||
#[pyattr(name = "Error", once)] | ||
fn error(vm: &VirtualMachine) -> PyTypeRef { | ||
vm.ctx.new_exception_type( | ||
"locale", | ||
"Error", | ||
Some(vec![vm.ctx.exceptions.exception_type.to_owned()]), | ||
) | ||
} | ||
|
||
#[pyfunction] | ||
fn localeconv(vm: &VirtualMachine) -> PyResult<PyDictRef> { | ||
let result = vm.ctx.new_dict(); | ||
|
||
unsafe { | ||
let lc = libc::localeconv(); | ||
|
||
macro_rules! set_string_field { | ||
($field:ident) => {{ | ||
F438 td> | result.set_item(stringify!($field), _parse_ptr_to_str(vm, (*lc).$field)?, vm)? | |
}}; | ||
} | ||
|
||
macro_rules! set_int_field { | ||
($field:ident) => {{ | ||
result.set_item(stringify!($field), vm.new_pyobj((*lc).$field), vm)? | ||
}}; | ||
} | ||
|
||
macro_rules! set_group_field { | ||
($field:ident) => {{ | ||
result.set_item( | ||
stringify!($field), | ||
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); | ||
} | ||
Ok(result) | ||
} | ||
|
||
#[derive(FromArgs)] | ||
struct LocaleArgs { | ||
#[pyarg(any)] | ||
category: i32, | ||
#[pyarg(any, optional)] | ||
locale: OptionalArg<Option<PyStrRef>>, | ||
} | ||
|
||
#[pyfunction] | ||
fn setlocale(args: LocaleArgs, vm: &VirtualMachine) -> PyResult { | ||
unsafe { | ||
let result = match args.locale.flatten() { | ||
None => libc::setlocale(args.category, ptr::null()), | ||
Some(l) => { | ||
let l_str = CString::new(l.to_string()).expect("expect to be always converted"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not always successful
|
||
let l_ptr = CStr::as_ptr(&l_str); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. because CString implements
works exactly same way. |
||
libc::setlocale(args.category, l_ptr) | ||
} | ||
}; | ||
if result.is_null() { | ||
let error = error(vm); | ||
return Err(vm.new_exception_msg(error, String::from("unsupported locale setting"))); | ||
} | ||
_parse_ptr_to_str(vm, result) | ||
} | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.