1- #[ cfg( all( unix, not( any( target_os = "ios" , target_os = "android" ) ) ) ) ]
1+ #[ cfg( any(
2+ unix,
3+ windows,
4+ not( any( target_os = "ios" , target_os = "android" , target_arch = "wasm32" ) )
5+ ) ) ]
26pub ( crate ) use _locale:: make_module;
37
4- #[ cfg( all( unix, not( any( target_os = "ios" , target_os = "android" ) ) ) ) ]
8+ #[ cfg( not( target_arch = "wasm32" ) ) ]
9+ #[ repr( C ) ]
10+ struct lconv {
11+ decimal_point : * mut libc:: c_char ,
12+ thousands_sep : * mut libc:: c_char ,
13+ grouping : * mut libc:: c_char ,
14+ int_curr_symbol : * mut libc:: c_char ,
15+ currency_symbol : * mut libc:: c_char ,
16+ mon_decimal_point : * mut libc:: c_char ,
17+ mon_thousands_sep : * mut libc:: c_char ,
18+ mon_grouping : * mut libc:: c_char ,
19+ positive_sign : * mut libc:: c_char ,
20+ negative_sign : * mut libc:: c_char ,
21+ int_frac_digits : libc:: c_char ,
22+ frac_digits : libc:: c_char ,
23+ p_cs_precedes : libc:: c_char ,
24+ p_sep_by_space : libc:: c_char ,
25+ n_cs_precedes : libc:: c_char ,
26+ n_sep_by_space : libc:: c_char ,
27+ p_sign_posn : libc:: c_char ,
28+ n_sign_posn : libc:: c_char ,
29+ int_p_cs_precedes : libc:: c_char ,
30+ int_n_cs_precedes : libc:: c_char ,
31+ int_p_sep_by_space : libc:: c_char ,
32+ int_n_sep_by_space : libc:: c_char ,
33+ int_p_sign_posn : libc:: c_char ,
34+ int_n_sign_posn : libc:: c_char ,
35+ }
36+
37+ #[ cfg( not( target_arch = "wasm32" ) ) ]
38+ extern "C" {
39+ fn localeconv ( ) -> * mut lconv ;
40+ }
41+
42+ #[ cfg( any(
43+ unix,
44+ windows,
45+ not( any( target_os = "ios" , target_os = "android" , target_arch = "wasm32" ) )
46+ ) ) ]
547#[ pymodule]
648mod _locale {
749 use rustpython_vm:: {
@@ -15,17 +57,25 @@ mod _locale {
1557 ptr,
1658 } ;
1759
60+ #[ cfg( all( unix, not( any( target_os = "ios" , target_os = "android" ) ) ) ) ]
1861 #[ pyattr]
1962 use libc:: {
2063 ABDAY_1 , ABDAY_2 , ABDAY_3 , ABDAY_4 , ABDAY_5 , ABDAY_6 , ABDAY_7 , ABMON_1 , ABMON_10 , ABMON_11 ,
2164 ABMON_12 , ABMON_2 , ABMON_3 , ABMON_4 , ABMON_5 , ABMON_6 , ABMON_7 , ABMON_8 , ABMON_9 ,
2265 ALT_DIGITS , AM_STR , CODESET , CRNCYSTR , DAY_1 , DAY_2 , DAY_3 , DAY_4 , DAY_5 , DAY_6 , DAY_7 ,
23- D_FMT , D_T_FMT , ERA , ERA_D_FMT , ERA_D_T_FMT , ERA_T_FMT , LC_ALL , LC_COLLATE , LC_CTYPE ,
24- LC_MESSAGES , LC_MONETARY , LC_NUMERIC , LC_TIME , MON_1 , MON_10 , MON_11 , MON_12 , MON_2 , MON_3 ,
25- MON_4 , MON_5 , MON_6 , MON_7 , MON_8 , MON_9 , NOEXPR , PM_STR , RADIXCHAR , THOUSEP , T_FMT ,
26- T_FMT_AMPM , YESEXPR ,
66+ D_FMT , D_T_FMT , ERA , ERA_D_FMT , ERA_D_T_FMT , ERA_T_FMT , LC_MESSAGES , MON_1 , MON_10 , MON_11 ,
67+ MON_12 , MON_2 , MON_3 , MON_4 , MON_5 , MON_6 , MON_7 , MON_8 , MON_9 , NOEXPR , PM_STR , RADIXCHAR ,
68+ THOUSEP , T_FMT , T_FMT_AMPM , YESEXPR ,
2769 } ;
2870
71+ #[ pyattr]
72+ use libc:: { LC_ALL , LC_COLLATE , LC_CTYPE , LC_MONETARY , LC_NUMERIC , LC_TIME } ;
73+
74+ #[ cfg( any(
75+ unix,
76+ windows,
77+ not( any( target_os = "ios" , target_os = "android" , target_arch = "wasm32" ) )
78+ ) ) ]
2979 #[ pyattr( name = "CHAR_MAX" ) ]
3080 fn char_max ( vm : & VirtualMachine ) -> PyIntRef {
3181 vm. ctx . new_int ( libc:: c_char:: MAX )
@@ -58,6 +108,11 @@ mod _locale {
58108 Ok ( vm. new_pyobj ( string) )
59109 }
60110
111+ #[ cfg( any(
112+ unix,
113+ windows,
114+ not( any( target_os = "ios" , target_os = "android" , target_arch = "wasm32" ) )
115+ ) ) ]
61116 #[ pyattr( name = "Error" , once) ]
62117 fn error ( vm : & VirtualMachine ) -> PyTypeRef {
63118 vm. ctx . new_exception_type (
@@ -67,76 +122,88 @@ mod _locale {
67122 )
68123 }
69124
125+ #[ cfg( any(
126+ unix,
127+ windows,
128+ not( any( target_os = "ios" , target_os = "android" , target_arch = "wasm32" ) )
129+ ) ) ]
70130 #[ pyfunction]
71131 fn strcoll ( string1 : PyStrRef , string2 : PyStrRef , vm : & VirtualMachine ) -> PyResult {
72132 let cstr1 = CString :: new ( string1. as_str ( ) ) . map_err ( |e| e. to_pyexception ( vm) ) ?;
73133 let cstr2 = CString :: new ( string2. as_str ( ) ) . map_err ( |e| e. to_pyexception ( vm) ) ?;
74134 Ok ( vm. new_pyobj ( unsafe { libc:: strcoll ( cstr1. as_ptr ( ) , cstr2. as_ptr ( ) ) } ) )
75135 }
76136
137+ #[ cfg( any(
138+ unix,
139+ windows,
140+ not( any( target_os = "ios" , target_os = "android" , target_arch = "wasm32" ) )
141+ ) ) ]
77142 #[ pyfunction]
78143 fn strxfrm ( string : PyStrRef , vm : & VirtualMachine ) -> PyResult {
79144 // https://github.com/python/cpython/blob/eaae563b6878aa050b4ad406b67728b6b066220e/Modules/_localemodule.c#L390-L442
80145 let n1 = string. byte_len ( ) + 1 ;
81- let mut buff: Vec < u8 > = vec ! [ 0 ; n1] ;
146+ let mut buff = vec ! [ 0u8 ; n1] ;
82147
83148 let cstr = CString :: new ( string. as_str ( ) ) . map_err ( |e| e. to_pyexception ( vm) ) ?;
84149 let n2 = unsafe { libc:: strxfrm ( buff. as_mut_ptr ( ) as _ , cstr. as_ptr ( ) , n1) } ;
85- buff. truncate ( n2) ;
150+ buff = vec ! [ 0u8 ; n2 + 1 ] ;
151+ unsafe {
152+ libc:: strxfrm ( buff. as_mut_ptr ( ) as _ , cstr. as_ptr ( ) , n2 + 1 ) ;
153+ }
86154 Ok ( vm. new_pyobj ( String :: from_utf8 ( buff) . expect ( "strxfrm returned invalid utf-8 string" ) ) )
87155 }
88156
89- #[ pyfunction]
90- fn localeconv ( vm : & VirtualMachine ) -> PyResult < PyDictRef > {
157+ #[ pyfunction( name = "localeconv" ) ]
158+ fn _localeconv ( vm : & VirtualMachine ) -> PyResult < PyDictRef > {
91159 let result = vm. ctx . new_dict ( ) ;
92160
93161 unsafe {
94- let lc = libc:: localeconv ( ) ;
95-
96162 macro_rules! set_string_field {
97- ( $field: ident) => { {
163+ ( $lc : expr , $ field: ident) => { {
98164 result. set_item(
99165 stringify!( $field) ,
100- pystr_from_raw_cstr( vm, ( * lc) . $field) ?,
166+ pystr_from_raw_cstr( vm, ( * $ lc) . $field) ?,
101167 vm,
102168 ) ?
103169 } } ;
104170 }
105171
106172 macro_rules! set_int_field {
107- ( $field: ident) => { {
108- result. set_item( stringify!( $field) , vm. new_pyobj( ( * lc) . $field) , vm) ?
173+ ( $lc : expr , $ field: ident) => { {
174+ result. set_item( stringify!( $field) , vm. new_pyobj( ( * $ lc) . $field) , vm) ?
109175 } } ;
110176 }
111177
112178 macro_rules! set_group_field {
113- ( $field: ident) => { {
179+ ( $lc : expr , $ field: ident) => { {
114180 result. set_item(
115181 stringify!( $field) ,
116- copy_grouping( ( * lc) . $field, vm) . into( ) ,
182+ copy_grouping( ( * $ lc) . $field, vm) . into( ) ,
117183 vm,
118184 ) ?
119185 } } ;
120186 }
121187
122- set_group_field ! ( mon_grouping) ;
123- set_group_field ! ( grouping) ;
124- set_int_field ! ( int_frac_digits) ;
125- set_int_field ! ( frac_digits) ;
126- set_int_field ! ( p_cs_precedes) ;
127- set_int_field ! ( p_sep_by_space) ;
128- set_int_field ! ( n_cs_precedes) ;
129- set_int_field ! ( p_sign_posn) ;
130- set_int_field ! ( n_sign_posn) ;
131- set_string_field ! ( decimal_point) ;
132- set_string_field ! ( thousands_sep) ;
133- set_string_field ! ( int_curr_symbol) ;
134- set_string_field ! ( currency_symbol) ;
135- set_string_field ! ( mon_decimal_point) ;
136- set_string_field ! ( mon_thousands_sep) ;
137- set_int_field ! ( n_sep_by_space) ;
138- set_string_field ! ( positive_sign) ;
139- set_string_field ! ( negative_sign) ;
188+ let lc = super :: localeconv ( ) ;
189+ set_group_field ! ( lc, mon_grouping) ;
190+ set_group_field ! ( lc, grouping) ;
191+ set_int_field ! ( lc, int_frac_digits) ;
192+ set_int_field ! ( lc, frac_digits) ;
193+ set_int_field ! ( lc, p_cs_precedes) ;
194+ set_int_field ! ( lc, p_sep_by_space) ;
195+ set_int_field ! ( lc, n_cs_precedes) ;
196+ set_int_field ! ( lc, p_sign_posn) ;
197+ set_int_field ! ( lc, n_sign_posn) ;
198+ set_string_field ! ( lc, decimal_point) ;
199+ set_string_field ! ( lc, thousands_sep) ;
200+ set_string_field ! ( lc, int_curr_symbol) ;
201+ set_string_field ! ( lc, currency_symbol) ;
202+ set_string_field ! ( lc, mon_decimal_point) ;
203+ set_string_field ! ( lc, mon_thousands_sep) ;
204+ set_int_field ! ( lc, n_sep_by_space) ;
205+ set_string_field ! ( lc, positive_sign) ;
206+ set_string_field ! ( lc, negative_sign) ;
140207 }
141208 Ok ( result)
142209 }
@@ -149,8 +216,17 @@ mod _locale {
149216 locale : OptionalArg < Option < PyStrRef > > ,
150217 }
151218
219+ #[ cfg( any(
220+ unix,
221+ windows,
222+ not( any( target_os = "ios" , target_os = "android" , target_arch = "wasm32" ) )
223+ ) ) ]
152224 #[ pyfunction]
153225 fn setlocale ( args : LocaleArgs , vm : & VirtualMachine ) -> PyResult {
226+ let error = error ( vm) ;
227+ if cfg ! ( windows) && ( args. category < LC_ALL || args. category > LC_TIME ) {
228+ return Err ( vm. new_exception_msg ( error, String :: from ( "unsupported locale setting" ) ) ) ;
229+ }
154230 unsafe {
155231 let result = match args. locale . flatten ( ) {
156232 None => libc:: setlocale ( args. category , ptr:: null ( ) ) ,
@@ -161,7 +237,6 @@ mod _locale {
161237 }
162238 } ;
163239 if result. is_null ( ) {
164- let error = error ( vm) ;
165240 return Err ( vm. new_exception_msg ( error, String :: from ( "unsupported locale setting" ) ) ) ;
166241 }
167242 pystr_from_raw_cstr ( vm, result)
0 commit comments