xref: /aosp_15_r20/bootable/libbootloader/gbl/libc/src/strtoul.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker 
15*5225e6b1SAndroid Build Coastguard Worker //! This library provides implementation for strtoul libc functions family.
16*5225e6b1SAndroid Build Coastguard Worker //! https://en.cppreference.com/w/cpp/string/byte/strtoul
17*5225e6b1SAndroid Build Coastguard Worker 
18*5225e6b1SAndroid Build Coastguard Worker use core::ffi::{c_char, c_int, c_ulong, CStr};
19*5225e6b1SAndroid Build Coastguard Worker use safemath::SafeNum;
20*5225e6b1SAndroid Build Coastguard Worker 
21*5225e6b1SAndroid Build Coastguard Worker /// unsigned long int strtoul(const char *s, char **endptr, int base);
22*5225e6b1SAndroid Build Coastguard Worker ///
23*5225e6b1SAndroid Build Coastguard Worker /// # Safety
24*5225e6b1SAndroid Build Coastguard Worker ///
25*5225e6b1SAndroid Build Coastguard Worker /// * `s` must be valid pointer to null terminated C string
26*5225e6b1SAndroid Build Coastguard Worker /// * `endptr` must be a valid pointer that is available for writing or null
27*5225e6b1SAndroid Build Coastguard Worker #[no_mangle]
strtoul( s: *const c_char, endptr: *mut *const c_char, base: c_int, ) -> c_ulong28*5225e6b1SAndroid Build Coastguard Worker pub unsafe extern "C" fn strtoul(
29*5225e6b1SAndroid Build Coastguard Worker     s: *const c_char,
30*5225e6b1SAndroid Build Coastguard Worker     endptr: *mut *const c_char,
31*5225e6b1SAndroid Build Coastguard Worker     base: c_int,
32*5225e6b1SAndroid Build Coastguard Worker ) -> c_ulong {
33*5225e6b1SAndroid Build Coastguard Worker     assert!(!s.is_null());
34*5225e6b1SAndroid Build Coastguard Worker     assert!(base == 0 || base == 8 || base == 10 || base == 16);
35*5225e6b1SAndroid Build Coastguard Worker 
36*5225e6b1SAndroid Build Coastguard Worker     let mut pos = 0;
37*5225e6b1SAndroid Build Coastguard Worker     let mut base = base;
38*5225e6b1SAndroid Build Coastguard Worker     let mut negative = false;
39*5225e6b1SAndroid Build Coastguard Worker 
40*5225e6b1SAndroid Build Coastguard Worker     // SAFETY: `s` is a valid null terminated string
41*5225e6b1SAndroid Build Coastguard Worker     let bytes = unsafe { CStr::from_ptr(s) }.to_bytes();
42*5225e6b1SAndroid Build Coastguard Worker 
43*5225e6b1SAndroid Build Coastguard Worker     // Skip leading whitespace
44*5225e6b1SAndroid Build Coastguard Worker     while pos < bytes.len() && bytes[pos].is_ascii_whitespace() {
45*5225e6b1SAndroid Build Coastguard Worker         pos += 1;
46*5225e6b1SAndroid Build Coastguard Worker     }
47*5225e6b1SAndroid Build Coastguard Worker 
48*5225e6b1SAndroid Build Coastguard Worker     // Handle sign
49*5225e6b1SAndroid Build Coastguard Worker     if pos < bytes.len() {
50*5225e6b1SAndroid Build Coastguard Worker         match bytes[pos] {
51*5225e6b1SAndroid Build Coastguard Worker             b'+' => pos += 1,
52*5225e6b1SAndroid Build Coastguard Worker             b'-' => {
53*5225e6b1SAndroid Build Coastguard Worker                 pos += 1;
54*5225e6b1SAndroid Build Coastguard Worker                 negative = true;
55*5225e6b1SAndroid Build Coastguard Worker             }
56*5225e6b1SAndroid Build Coastguard Worker             _ => {}
57*5225e6b1SAndroid Build Coastguard Worker         }
58*5225e6b1SAndroid Build Coastguard Worker     }
59*5225e6b1SAndroid Build Coastguard Worker 
60*5225e6b1SAndroid Build Coastguard Worker     // Handle base prefixes
61*5225e6b1SAndroid Build Coastguard Worker     if (base == 16 || base == 0)
62*5225e6b1SAndroid Build Coastguard Worker         && pos < bytes.len() - 1
63*5225e6b1SAndroid Build Coastguard Worker         && bytes[pos] == b'0'
64*5225e6b1SAndroid Build Coastguard Worker         && (bytes[pos + 1] == b'x' || bytes[pos + 1] == b'X')
65*5225e6b1SAndroid Build Coastguard Worker     {
66*5225e6b1SAndroid Build Coastguard Worker         pos += 2;
67*5225e6b1SAndroid Build Coastguard Worker         base = 16;
68*5225e6b1SAndroid Build Coastguard Worker     }
69*5225e6b1SAndroid Build Coastguard Worker     if (base == 8 || base == 0) && pos < bytes.len() && bytes[pos] == b'0' {
70*5225e6b1SAndroid Build Coastguard Worker         pos += 1;
71*5225e6b1SAndroid Build Coastguard Worker         base = 8;
72*5225e6b1SAndroid Build Coastguard Worker     }
73*5225e6b1SAndroid Build Coastguard Worker     if base == 0 {
74*5225e6b1SAndroid Build Coastguard Worker         base = 10;
75*5225e6b1SAndroid Build Coastguard Worker     }
76*5225e6b1SAndroid Build Coastguard Worker 
77*5225e6b1SAndroid Build Coastguard Worker     let mut result: SafeNum = 0.into();
78*5225e6b1SAndroid Build Coastguard Worker     while pos < bytes.len() {
79*5225e6b1SAndroid Build Coastguard Worker         let symbol = bytes[pos];
80*5225e6b1SAndroid Build Coastguard Worker         let value = match symbol {
81*5225e6b1SAndroid Build Coastguard Worker             b'0'..=b'7' if base == 8 => symbol - b'0',
82*5225e6b1SAndroid Build Coastguard Worker             b'0'..=b'9' if base == 10 || base == 16 => symbol - b'0',
83*5225e6b1SAndroid Build Coastguard Worker             b'a'..=b'f' if base == 16 => symbol - b'a' + 10,
84*5225e6b1SAndroid Build Coastguard Worker             b'A'..=b'F' if base == 16 => symbol - b'A' + 10,
85*5225e6b1SAndroid Build Coastguard Worker             _ => break,
86*5225e6b1SAndroid Build Coastguard Worker         };
87*5225e6b1SAndroid Build Coastguard Worker         result = result * base + value;
88*5225e6b1SAndroid Build Coastguard Worker         pos += 1;
89*5225e6b1SAndroid Build Coastguard Worker     }
90*5225e6b1SAndroid Build Coastguard Worker 
91*5225e6b1SAndroid Build Coastguard Worker     if !endptr.is_null() {
92*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: `endptr` is a non-null pointer which is available for writing, `s` is a valid
93*5225e6b1SAndroid Build Coastguard Worker         // non-null pointer, `pos` is guaranteed to be within `s` by `pos < bytes.len()` checks.
94*5225e6b1SAndroid Build Coastguard Worker         unsafe { *endptr = s.add(pos) };
95*5225e6b1SAndroid Build Coastguard Worker     }
96*5225e6b1SAndroid Build Coastguard Worker 
97*5225e6b1SAndroid Build Coastguard Worker     match c_ulong::try_from(result) {
98*5225e6b1SAndroid Build Coastguard Worker         Ok(result) if negative => result.overflowing_neg().0,
99*5225e6b1SAndroid Build Coastguard Worker         Ok(result) => result,
100*5225e6b1SAndroid Build Coastguard Worker         _ => c_ulong::MAX,
101*5225e6b1SAndroid Build Coastguard Worker     }
102*5225e6b1SAndroid Build Coastguard Worker }
103*5225e6b1SAndroid Build Coastguard Worker 
104*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
105*5225e6b1SAndroid Build Coastguard Worker mod test {
106*5225e6b1SAndroid Build Coastguard Worker     use super::*;
107*5225e6b1SAndroid Build Coastguard Worker     use std::ffi::CString;
108*5225e6b1SAndroid Build Coastguard Worker     use std::ptr::null_mut;
109*5225e6b1SAndroid Build Coastguard Worker 
to_cstr(s: &str) -> CString110*5225e6b1SAndroid Build Coastguard Worker     fn to_cstr(s: &str) -> CString {
111*5225e6b1SAndroid Build Coastguard Worker         CString::new(s).unwrap()
112*5225e6b1SAndroid Build Coastguard Worker     }
113*5225e6b1SAndroid Build Coastguard Worker 
do_strtoul(input: &str, base: i32) -> (c_ulong, Option<usize>)114*5225e6b1SAndroid Build Coastguard Worker     fn do_strtoul(input: &str, base: i32) -> (c_ulong, Option<usize>) {
115*5225e6b1SAndroid Build Coastguard Worker         let input_cstr = to_cstr(input);
116*5225e6b1SAndroid Build Coastguard Worker         let mut end_ptr: *const c_char = null_mut();
117*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: `input_cstr` is a null terminated string, `end_ptr` is initialized null pointer
118*5225e6b1SAndroid Build Coastguard Worker         let result = unsafe { strtoul(input_cstr.as_ptr(), &mut end_ptr, base) };
119*5225e6b1SAndroid Build Coastguard Worker 
120*5225e6b1SAndroid Build Coastguard Worker         let end_position = if end_ptr.is_null() {
121*5225e6b1SAndroid Build Coastguard Worker             None
122*5225e6b1SAndroid Build Coastguard Worker         } else {
123*5225e6b1SAndroid Build Coastguard Worker             let start_ptr = input_cstr.as_ptr();
124*5225e6b1SAndroid Build Coastguard Worker             // SAFETY: `end_ptr` is a pointer within the string that `start_ptr` points to
125*5225e6b1SAndroid Build Coastguard Worker             Some(unsafe { end_ptr.offset_from(start_ptr) } as usize)
126*5225e6b1SAndroid Build Coastguard Worker         };
127*5225e6b1SAndroid Build Coastguard Worker 
128*5225e6b1SAndroid Build Coastguard Worker         (result, end_position)
129*5225e6b1SAndroid Build Coastguard Worker     }
130*5225e6b1SAndroid Build Coastguard Worker 
do_strtoul_no_endptr(input: &str, base: i32) -> c_ulong131*5225e6b1SAndroid Build Coastguard Worker     fn do_strtoul_no_endptr(input: &str, base: i32) -> c_ulong {
132*5225e6b1SAndroid Build Coastguard Worker         let input_cstr = to_cstr(input);
133*5225e6b1SAndroid Build Coastguard Worker         // SAFETY: `input_cstr` is a null terminated string
134*5225e6b1SAndroid Build Coastguard Worker         unsafe { strtoul(input_cstr.as_ptr(), null_mut(), base) }
135*5225e6b1SAndroid Build Coastguard Worker     }
136*5225e6b1SAndroid Build Coastguard Worker 
137*5225e6b1SAndroid Build Coastguard Worker     // strtoul tests
138*5225e6b1SAndroid Build Coastguard Worker 
139*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_decimal()140*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_decimal() {
141*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("12345", 10);
142*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 12345);
143*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(5));
144*5225e6b1SAndroid Build Coastguard Worker     }
145*5225e6b1SAndroid Build Coastguard Worker 
146*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_no_endptr()147*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_no_endptr() {
148*5225e6b1SAndroid Build Coastguard Worker         let r = do_strtoul_no_endptr("12345", 10);
149*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 12345);
150*5225e6b1SAndroid Build Coastguard Worker     }
151*5225e6b1SAndroid Build Coastguard Worker 
152*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_zero()153*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_zero() {
154*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0", 10);
155*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0);
156*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(1));
157*5225e6b1SAndroid Build Coastguard Worker     }
158*5225e6b1SAndroid Build Coastguard Worker 
159*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_empty()160*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_empty() {
161*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("", 10);
162*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0);
163*5225e6b1SAndroid Build Coastguard Worker         // Empty input, end_ptr should point to the start
164*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(0));
165*5225e6b1SAndroid Build Coastguard Worker     }
166*5225e6b1SAndroid Build Coastguard Worker 
167*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_empty_no_endptr()168*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_empty_no_endptr() {
169*5225e6b1SAndroid Build Coastguard Worker         let r = do_strtoul_no_endptr("", 10);
170*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0);
171*5225e6b1SAndroid Build Coastguard Worker     }
172*5225e6b1SAndroid Build Coastguard Worker 
173*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_invalid_characters()174*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_invalid_characters() {
175*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("123abc", 10);
176*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 123);
177*5225e6b1SAndroid Build Coastguard Worker         // Parsing stops at 'a', so end_ptr should point to index 3
178*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(3));
179*5225e6b1SAndroid Build Coastguard Worker     }
180*5225e6b1SAndroid Build Coastguard Worker 
181*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_positive_sign()182*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_positive_sign() {
183*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("+456", 10);
184*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 456);
185*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(4));
186*5225e6b1SAndroid Build Coastguard Worker     }
187*5225e6b1SAndroid Build Coastguard Worker 
188*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_negative_sign()189*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_negative_sign() {
190*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("-1000", 10);
191*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 18446744073709550616);
192*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(5));
193*5225e6b1SAndroid Build Coastguard Worker     }
194*5225e6b1SAndroid Build Coastguard Worker 
195*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_negative_zero_sign()196*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_negative_zero_sign() {
197*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("-0", 10);
198*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0);
199*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(2));
200*5225e6b1SAndroid Build Coastguard Worker     }
201*5225e6b1SAndroid Build Coastguard Worker 
202*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_prefix_spaces()203*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_prefix_spaces() {
204*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("   456", 10);
205*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 456);
206*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(6));
207*5225e6b1SAndroid Build Coastguard Worker     }
208*5225e6b1SAndroid Build Coastguard Worker 
209*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_leading_zeroes()210*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_leading_zeroes() {
211*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0000456", 10);
212*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 456);
213*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(7));
214*5225e6b1SAndroid Build Coastguard Worker     }
215*5225e6b1SAndroid Build Coastguard Worker 
216*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_overflow()217*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_overflow() {
218*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("999999999999999999999999999999", 10);
219*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, c_ulong::MAX);
220*5225e6b1SAndroid Build Coastguard Worker         // Whole input string got processed, so end_ptr should point to the end
221*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(30));
222*5225e6b1SAndroid Build Coastguard Worker     }
223*5225e6b1SAndroid Build Coastguard Worker 
224*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_octal()225*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_octal() {
226*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("12345", 8);
227*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0o12345);
228*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(5));
229*5225e6b1SAndroid Build Coastguard Worker     }
230*5225e6b1SAndroid Build Coastguard Worker 
231*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_octal_prefix()232*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_octal_prefix() {
233*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("01234", 8);
234*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0o1234);
235*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(5));
236*5225e6b1SAndroid Build Coastguard Worker     }
237*5225e6b1SAndroid Build Coastguard Worker 
238*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_octal_invalid_characters()239*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_octal_invalid_characters() {
240*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("1289", 8);
241*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0o12);
242*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(2));
243*5225e6b1SAndroid Build Coastguard Worker     }
244*5225e6b1SAndroid Build Coastguard Worker 
245*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_octal_prefix_spaces()246*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_octal_prefix_spaces() {
247*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("   0755", 8);
248*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0o755);
249*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(7));
250*5225e6b1SAndroid Build Coastguard Worker     }
251*5225e6b1SAndroid Build Coastguard Worker 
252*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_octal_leading_zeroes()253*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_octal_leading_zeroes() {
254*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0000456", 8);
255*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0o456);
256*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(7));
257*5225e6b1SAndroid Build Coastguard Worker     }
258*5225e6b1SAndroid Build Coastguard Worker 
259*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_octal_overflow()260*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_octal_overflow() {
261*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("7777777777777777777777", 8);
262*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, c_ulong::MAX);
263*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(22));
264*5225e6b1SAndroid Build Coastguard Worker     }
265*5225e6b1SAndroid Build Coastguard Worker 
266*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_hex()267*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_hex() {
268*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("12345", 16);
269*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x12345);
270*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(5));
271*5225e6b1SAndroid Build Coastguard Worker     }
272*5225e6b1SAndroid Build Coastguard Worker 
273*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_hex_prefix()274*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_hex_prefix() {
275*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0x1234", 16);
276*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x1234);
277*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(6));
278*5225e6b1SAndroid Build Coastguard Worker     }
279*5225e6b1SAndroid Build Coastguard Worker 
280*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_hex_invalid_characters()281*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_hex_invalid_characters() {
282*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("12g89", 16);
283*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x12);
284*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(2));
285*5225e6b1SAndroid Build Coastguard Worker     }
286*5225e6b1SAndroid Build Coastguard Worker 
287*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_hex_prefix_spaces()288*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_hex_prefix_spaces() {
289*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("   0x7F5", 16);
290*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x7F5);
291*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(8));
292*5225e6b1SAndroid Build Coastguard Worker     }
293*5225e6b1SAndroid Build Coastguard Worker 
294*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_hex_leading_zeroes()295*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_hex_leading_zeroes() {
296*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0000456", 16);
297*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x456);
298*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(7));
299*5225e6b1SAndroid Build Coastguard Worker     }
300*5225e6b1SAndroid Build Coastguard Worker 
301*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_hex_overflow()302*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_hex_overflow() {
303*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("FFFFFFFFFFFFFFFFFFFF", 16);
304*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, c_ulong::MAX);
305*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(20));
306*5225e6b1SAndroid Build Coastguard Worker     }
307*5225e6b1SAndroid Build Coastguard Worker 
308*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_autodetect_decimal()309*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_autodetect_decimal() {
310*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("12345", 0);
311*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 12345);
312*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(5));
313*5225e6b1SAndroid Build Coastguard Worker     }
314*5225e6b1SAndroid Build Coastguard Worker 
315*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_autodetect_octal()316*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_autodetect_octal() {
317*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("01234", 0);
318*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0o1234);
319*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(5));
320*5225e6b1SAndroid Build Coastguard Worker     }
321*5225e6b1SAndroid Build Coastguard Worker 
322*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_autodetect_hex()323*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_autodetect_hex() {
324*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0x1234", 0);
325*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x1234);
326*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(6));
327*5225e6b1SAndroid Build Coastguard Worker     }
328*5225e6b1SAndroid Build Coastguard Worker 
329*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_autodetect_hex_invalid()330*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_autodetect_hex_invalid() {
331*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0x12G34", 0);
332*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x12);
333*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(4));
334*5225e6b1SAndroid Build Coastguard Worker     }
335*5225e6b1SAndroid Build Coastguard Worker 
336*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_autodetect_hex_leading_spaces()337*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_autodetect_hex_leading_spaces() {
338*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("   0x7F5", 0);
339*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, 0x7F5);
340*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(8));
341*5225e6b1SAndroid Build Coastguard Worker     }
342*5225e6b1SAndroid Build Coastguard Worker 
343*5225e6b1SAndroid Build Coastguard Worker     #[test]
strtoul_autodetect_hex_overflow()344*5225e6b1SAndroid Build Coastguard Worker     fn strtoul_autodetect_hex_overflow() {
345*5225e6b1SAndroid Build Coastguard Worker         let (r, end) = do_strtoul("0xFFFFFFFFFFFFFFFFFFFF", 0);
346*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(r, c_ulong::MAX);
347*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(end, Some(22));
348*5225e6b1SAndroid Build Coastguard Worker     }
349*5225e6b1SAndroid Build Coastguard Worker }
350