1- #[ cfg( all( unix, not( any( target_os = "ios" , target_os = "android" ) ) ) ) ]
21pub ( crate ) use _locale:: make_module;
32
4- #[ cfg( all( unix, not( any( target_os = "ios" , target_os = "android" ) ) ) ) ]
3+ #[ cfg( windows) ]
4+ #[ repr( C ) ]
5+ struct lconv {
6+ decimal_point : * mut libc:: c_char ,
7+ thousands_sep : * mut libc:: c_char ,
8+ grouping : * mut libc:: c_char ,
9+ int_curr_symbol : * mut libc:: c_char ,
10+ currency_symbol : * mut libc:: c_char ,
11+ mon_decimal_point : * mut libc:: c_char ,
12+ mon_thousands_sep : * mut libc:: c_char ,
13+ mon_grouping : * mut libc:: c_char ,
14+ positive_sign : * mut libc:: c_char ,
15+ negative_sign : * mut libc:: c_char ,
16+ int_frac_digits : libc:: c_char ,
17+ frac_digits : libc:: c_char ,
18+ p_cs_precedes : libc:: c_char ,
19+ p_sep_by_space : libc:: c_char ,
20+ n_cs_precedes : libc:: c_char ,
21+ n_sep_by_space : libc:: c_char ,
22+ p_sign_posn : libc:: c_char ,
23+ n_sign_posn : libc:: c_char ,
24+ int_p_cs_precedes : libc:: c_char ,
25+ int_n_cs_precedes : libc:: c_char ,
26+ int_p_sep_by_space : libc:: c_char ,
27+ int_n_sep_by_space : libc:: c_char ,
28+ int_p_sign_posn : libc:: c_char ,
29+ int_n_sign_posn : libc:: c_char ,
30+ }
31+
32+ #[ cfg( windows) ]
33+ extern "C" {
34+ fn localeconv ( ) -> * mut lconv ;
35+ }
36+
37+ #[ cfg( unix) ]
38+ use libc:: localeconv;
39+
540#[ pymodule]
641mod _locale {
742 use rustpython_vm:: {
@@ -15,17 +50,20 @@ mod _locale {
1550 ptr,
1651 } ;
1752
53+ #[ cfg( all( unix, not( any( target_os = "ios" , target_os = "android" ) ) ) ) ]
1854 #[ pyattr]
1955 use libc:: {
2056 ABDAY_1 , ABDAY_2 , ABDAY_3 , ABDAY_4 , ABDAY_5 , ABDAY_6 , ABDAY_7 , ABMON_1 , ABMON_10 , ABMON_11 ,
2157 ABMON_12 , ABMON_2 , ABMON_3 , ABMON_4 , ABMON_5 , ABMON_6 , ABMON_7 , ABMON_8 , ABMON_9 ,
2258 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 ,
59+ D_FMT , D_T_FMT , ERA , ERA_D_FMT , ERA_D_T_FMT , ERA_T_FMT , LC_MESSAGES , MON_1 , MON_10 , MON_11 ,
60+ MON_12 , MON_2 , MON_3 , MON_4 , MON_5 , MON_6 , MON_7 , MON_8 , MON_9 , NOEXPR , PM_STR , RADIXCHAR ,
61+ THOUSEP , T_FMT , T_FMT_AMPM , YESEXPR ,
2762 } ;
2863
64+ #[ pyattr]
65+ use libc:: { LC_ALL , LC_COLLATE , LC_CTYPE , LC_MONETARY , LC_NUMERIC , LC_TIME } ;
66+
2967 #[ pyattr( name = "CHAR_MAX" ) ]
3068 fn char_max ( vm : & VirtualMachine ) -> PyIntRef {
3169 vm. ctx . new_int ( libc:: c_char:: MAX )
@@ -78,11 +116,14 @@ mod _locale {
78116 fn strxfrm ( string : PyStrRef , vm : & VirtualMachine ) -> PyResult {
79117 // https://github.com/python/cpython/blob/eaae563b6878aa050b4ad406b67728b6b066220e/Modules/_localemodule.c#L390-L442
80118 let n1 = string. byte_len ( ) + 1 ;
81- let mut buff: Vec < u8 > = vec ! [ 0 ; n1] ;
119+ let mut buff = vec ! [ 0u8 ; n1] ;
82120
83121 let cstr = CString :: new ( string. as_str ( ) ) . map_err ( |e| e. to_pyexception ( vm) ) ?;
84122 let n2 = unsafe { libc:: strxfrm ( buff. as_mut_ptr ( ) as _ , cstr. as_ptr ( ) , n1) } ;
85- buff. truncate ( n2) ;
123+ buff = vec ! [ 0u8 ; n2 + 1 ] ;
124+ unsafe {
125+ libc:: strxfrm ( buff. as_mut_ptr ( ) as _ , cstr. as_ptr ( ) , n2 + 1 ) ;
126+ }
86127 Ok ( vm. new_pyobj ( String :: from_utf8 ( buff) . expect ( "strxfrm returned invalid utf-8 string" ) ) )
87128 }
88129
@@ -91,52 +132,51 @@ mod _locale {
91132 let result = vm. ctx . new_dict ( ) ;
92133
93134 unsafe {
94- let lc = libc:: localeconv ( ) ;
95-
96135 macro_rules! set_string_field {
97- ( $field: ident) => { {
136+ ( $lc : expr , $ field: ident) => { {
98137 result. set_item(
99138 stringify!( $field) ,
100- pystr_from_raw_cstr( vm, ( * lc) . $field) ?,
139+ pystr_from_raw_cstr( vm, ( * $ lc) . $field) ?,
101140 vm,
102141 ) ?
103142 } } ;
104143 }
105144
106145 macro_rules! set_int_field {
107- ( $field: ident) => { {
108- result. set_item( stringify!( $field) , vm. new_pyobj( ( * lc) . $field) , vm) ?
146+ ( $lc : expr , $ field: ident) => { {
147+ result. set_item( stringify!( $field) , vm. new_pyobj( ( * $ lc) . $field) , vm) ?
109148 } } ;
110149 }
111150
112151 macro_rules! set_group_field {
113- ( $field: ident) => { {
152+ ( $lc : expr , $ field: ident) => { {
114153 result. set_item(
115154 stringify!( $field) ,
116- copy_grouping( ( * lc) . $field, vm) . into( ) ,
155+ copy_grouping( ( * $ lc) . $field, vm) . into( ) ,
117156 vm,
118157 ) ?
119158 } } ;
120159 }
121160
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) ;
161+ let lc = super :: localeconv ( ) ;
162+ set_group_field ! ( lc, mon_grouping) ;
163+ set_group_field ! ( lc, grouping) ;
164+ set_int_field ! ( lc, int_frac_digits) ;
165+ set_int_field ! ( lc, frac_digits) ;
166+ set_int_field ! ( lc, p_cs_precedes) ;
167+ set_int_field ! ( lc, p_sep_by_space) ;
168+ set_int_field ! ( lc, n_cs_precedes) ;
169+ set_int_field ! ( lc, p_sign_posn) ;
170+ set_int_field ! ( lc, n_sign_posn) ;
171+ set_string_field ! ( lc, decimal_point) ;
172+ set_string_field ! ( lc, thousands_sep) ;
173+ set_string_field ! ( lc, int_curr_symbol) ;
174+ set_string_field ! ( lc, currency_symbol) ;
175+ set_string_field ! ( lc, mon_decimal_point) ;
176+ set_string_field ! ( lc, mon_thousands_sep) ;
177+ set_int_field ! ( lc, n_sep_by_space) ;
178+ set_string_field ! ( lc, positive_sign) ;
179+ set_string_field ! ( lc, negative_sign) ;
140180 }
141181 Ok ( result)
142182 }
@@ -151,6 +191,10 @@ mod _locale {
151191
152192 #[ pyfunction]
153193 fn setlocale ( args : LocaleArgs , vm : & VirtualMachine ) -> PyResult {
194+ let error = error ( vm) ;
195+ if cfg ! ( windows) && ( args. category < LC_ALL || args. category > LC_TIME ) {
196+ return Err ( vm. new_exception_msg ( error, String :: from ( "unsupported locale setting" ) ) ) ;
197+ }
154198 unsafe {
155199 let result = match args. locale . flatten ( ) {
156200 None => libc:: setlocale ( args. category , ptr:: null ( ) ) ,
@@ -161,7 +205,6 @@ mod _locale {
161205 }
162206 } ;
163207 if result. is_null ( ) {
164- let error = error ( vm) ;
165208 return Err ( vm. new_exception_msg ( error, String :: from ( "unsupported locale setting" ) ) ) ;
166209 }
167210 pystr_from_raw_cstr ( vm, result)
0 commit comments