diff --git a/src/header/inttypes/mod.rs b/src/header/inttypes/mod.rs index 29eff295dd..2a77afb991 100644 --- a/src/header/inttypes/mod.rs +++ b/src/header/inttypes/mod.rs @@ -80,7 +80,7 @@ pub unsafe extern "C" fn wcstoimax( base: c_int, ) -> intmax_t { skipws!(ptr); - let result = strto_impl!(intmax_t, ptr, base); + let result = wcsto_impl!(intmax_t, ptr, base); if !end.is_null() { unsafe { *end = ptr.cast_mut() }; } @@ -95,7 +95,7 @@ pub unsafe extern "C" fn wcstoumax( base: c_int, ) -> uintmax_t { skipws!(ptr); - let result = strtou_impl!(uintmax_t, ptr, base); + let result = wcsto_impl!(uintmax_t, ptr, base); if !end.is_null() { unsafe { *end = ptr.cast_mut() }; } diff --git a/src/header/wchar/mod.rs b/src/header/wchar/mod.rs index 70b17108fe..7f67b64d78 100644 --- a/src/header/wchar/mod.rs +++ b/src/header/wchar/mod.rs @@ -855,7 +855,7 @@ pub unsafe extern "C" fn wcstol( base: c_int, ) -> c_long { skipws!(ptr); - let result = strto_impl!(c_long, ptr, base); + let result = wcsto_impl!(c_long, ptr, base); if !end.is_null() { unsafe { *end = ptr.cast_mut() }; } @@ -870,7 +870,7 @@ pub unsafe extern "C" fn wcstoll( base: c_int, ) -> c_longlong { skipws!(ptr); - let result = strto_impl!(c_longlong, ptr, base); + let result = wcsto_impl!(c_longlong, ptr, base); if !end.is_null() { unsafe { *end = ptr.cast_mut() }; } @@ -885,7 +885,7 @@ pub unsafe extern "C" fn wcstoul( base: c_int, ) -> c_ulong { skipws!(ptr); - let result = strtou_impl!(c_ulong, ptr, base); + let result = wcsto_impl!(c_ulong, ptr, base); if !end.is_null() { unsafe { *end = ptr.cast_mut() }; } @@ -900,7 +900,7 @@ pub unsafe extern "C" fn wcstoull( base: c_int, ) -> c_ulonglong { skipws!(ptr); - let result = strtou_impl!(c_ulonglong, ptr, base); + let result = wcsto_impl!(c_ulonglong, ptr, base); if !end.is_null() { unsafe { *end = ptr.cast_mut() }; } diff --git a/src/macros.rs b/src/macros.rs index 7ce4ff9505..efe5fef5fe 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -127,11 +127,16 @@ macro_rules! skipws { } #[macro_export] -macro_rules! strtou_impl { - ($type:ident, $ptr:expr, $base:expr) => { - strtou_impl!($type, $ptr, $base, false) - }; - ($type:ident, $ptr:expr, $base:expr, $negative:expr) => {{ +macro_rules! wcsto_impl { + ($type:ident, $ptr:expr, $base:expr) => {{ + let has_minus = unsafe { *$ptr } == '-' as wchar_t; + let has_plus = unsafe { *$ptr } == '+' as wchar_t; + if has_minus || has_plus { + $ptr = unsafe { $ptr.add(1) }; + } + + let type_is_signed = $type::MIN != 0; + let mut base = $base; if (base == 16 || base == 0) @@ -156,7 +161,7 @@ macro_rules! strtou_impl { char::from_u32(unsafe { *$ptr } as u32).and_then(|c| c.to_digit(base as u32)) { let new = result.checked_mul(base as $type).and_then(|result| { - if $negative { + if has_minus && type_is_signed { #[cfg(target_arch = "x86")] { result.checked_sub( @@ -190,6 +195,9 @@ macro_rules! strtou_impl { $ptr = unsafe { $ptr.add(1) }; } + if has_minus && !type_is_signed { + result = $type::MAX - result + 1; + } result }}; } @@ -297,14 +305,6 @@ macro_rules! strto_impl { num }}; - // this variant is used by wchar (also wcstoimax and wcstoumax from inttypes) - ($type:ident, $ptr:expr, $base:expr) => {{ - let negative = unsafe { *$ptr } == '-' as wchar_t; - if negative { - $ptr = unsafe { $ptr.add(1) }; - } - strtou_impl!($type, $ptr, $base, negative) - }}; } #[macro_export]