|
@@ -635,19 +635,55 @@ pub extern "C" fn srandom(seed: c_uint) {
|
|
|
}
|
|
|
|
|
|
#[no_mangle]
|
|
|
-pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
|
|
|
- // TODO: endptr
|
|
|
+pub unsafe extern "C" fn strtod(mut s: *const c_char, endptr: *mut *mut c_char) -> c_double {
|
|
|
+ while ctype::isspace(*s as c_int) != 0 {
|
|
|
+ s = s.offset(1);
|
|
|
+ }
|
|
|
|
|
|
- use core::str::FromStr;
|
|
|
+ let mut result = 0.0;
|
|
|
+ let mut radix = 10;
|
|
|
|
|
|
- let s_str = str::from_utf8_unchecked(platform::c_str(s));
|
|
|
- match f64::from_str(s_str) {
|
|
|
- Ok(ok) => ok as c_double,
|
|
|
- Err(_err) => {
|
|
|
- platform::errno = EINVAL;
|
|
|
- 0.0
|
|
|
+ let negative = match *s as u8 {
|
|
|
+ b'-' => { s = s.offset(1); true },
|
|
|
+ b'+' => { s = s.offset(1); false },
|
|
|
+ _ => false
|
|
|
+ };
|
|
|
+
|
|
|
+ if *s as u8 == b'0' && *s.offset(1) as u8 == b'x' {
|
|
|
+ s = s.offset(2);
|
|
|
+ radix = 16;
|
|
|
+ }
|
|
|
+
|
|
|
+ while let Some(digit) = (*s as u8 as char).to_digit(radix) {
|
|
|
+ result *= radix as c_double;
|
|
|
+ result += digit as c_double;
|
|
|
+ s = s.offset(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if *s as u8 == b'.' {
|
|
|
+ s = s.offset(1);
|
|
|
+
|
|
|
+ let mut i = 1.0;
|
|
|
+ while let Some(digit) = (*s as u8 as char).to_digit(radix) {
|
|
|
+ i *= radix as c_double;
|
|
|
+ result += digit as c_double / i;
|
|
|
+ s = s.offset(1);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if !endptr.is_null() {
|
|
|
+ // This is stupid, but apparently strto* functions want
|
|
|
+ // const input but mut output, yet the man page says
|
|
|
+ // "stores the address of the first invalid character in *endptr"
|
|
|
+ // so obviously it doesn't want us to clone it.
|
|
|
+ *endptr = s as *mut _;
|
|
|
+ }
|
|
|
+
|
|
|
+ if negative {
|
|
|
+ -result
|
|
|
+ } else {
|
|
|
+ result
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
pub fn is_positive(ch: c_char) -> Option<(bool, isize)> {
|