1use core::ffi::{c_char, c_double, c_float, c_int};
2
3macro_rules! strto_float_impl {
4 ($type:ident, $s:expr, $endptr:expr) => {{
5 let mut s = $s;
6 let endptr = $endptr;
7
8 while isspace(*s as c_int) {
11 s = s.offset(1);
12 }
13
14 let mut result: $type = 0.0;
15 let mut radix = 10;
16
17 let result_sign = match *s as u8 {
18 b'-' => {
19 s = s.offset(1);
20 -1.0
21 }
22 b'+' => {
23 s = s.offset(1);
24 1.0
25 }
26 _ => 1.0,
27 };
28
29 if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' {
30 s = s.offset(2);
31 radix = 16;
32 }
33
34 while let Some(digit) = (*s as u8 as char).to_digit(radix) {
35 result *= radix as $type;
36 result += digit as $type;
37 s = s.offset(1);
38 }
39
40 if *s as u8 == b'.' {
41 s = s.offset(1);
42
43 let mut i = 1.0;
44 while let Some(digit) = (*s as u8 as char).to_digit(radix) {
45 i *= radix as $type;
46 result += digit as $type / i;
47 s = s.offset(1);
48 }
49 }
50
51 let s_before_exponent = s;
52
53 let exponent = match (*s as u8, radix) {
54 (b'e' | b'E', 10) | (b'p' | b'P', 16) => {
55 s = s.offset(1);
56
57 let is_exponent_positive = match *s as u8 {
58 b'-' => {
59 s = s.offset(1);
60 false
61 }
62 b'+' => {
63 s = s.offset(1);
64 true
65 }
66 _ => true,
67 };
68
69 if (*s as u8 as char).is_digit(10) {
71 let mut exponent_value = 0;
72
73 while let Some(digit) = (*s as u8 as char).to_digit(10) {
74 exponent_value *= 10;
75 exponent_value += digit;
76 s = s.offset(1);
77 }
78
79 let exponent_base = match radix {
80 10 => 10u128,
81 16 => 2u128,
82 _ => unreachable!(),
83 };
84
85 if is_exponent_positive {
86 Some(exponent_base.pow(exponent_value) as $type)
87 } else {
88 Some(1.0 / (exponent_base.pow(exponent_value) as $type))
89 }
90 } else {
91 s = s_before_exponent;
93 None
94 }
95 }
96 _ => None,
97 };
98
99 if !endptr.is_null() {
101 *endptr = s as *mut _;
102 }
103
104 if let Some(exponent) = exponent {
105 result_sign * result * exponent
106 } else {
107 result_sign * result
108 }
109 }};
110}
111
112fn isspace(c: c_int) -> bool {
113 c == c_int::from(b' ')
114 || c == c_int::from(b'\t')
115 || c == c_int::from(b'\n')
116 || c == c_int::from(b'\r')
117 || c == 0x0b
118 || c == 0x0c
119}
120
121#[unsafe(no_mangle)]
123pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
124 strto_float_impl!(c_double, s, endptr)
125}
126
127#[unsafe(no_mangle)]
129pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float {
130 strto_float_impl!(c_float, s, endptr)
131}