Skip to content
Snippets Groups Projects
Unverified Commit 6e8e6ad5 authored by Jeremy Soller's avatar Jeremy Soller Committed by GitHub
Browse files

Merge pull request #121 from Arcterus/strtoul

stdlib: implement strtoul() and strtol() using a macro
parents 018f9508 1bcc40c0
No related branches found
No related tags found
No related merge requests found
...@@ -388,7 +388,7 @@ pub extern "C" fn qsort( ...@@ -388,7 +388,7 @@ pub extern "C" fn qsort(
width: size_t, width: size_t,
compar: Option<extern "C" fn(*const c_void, *const c_void) -> c_int>, compar: Option<extern "C" fn(*const c_void, *const c_void) -> c_int>,
) { ) {
unimplemented!(); unimplemented!()
} }
#[no_mangle] #[no_mangle]
...@@ -466,7 +466,7 @@ pub extern "C" fn srandom(seed: c_uint) { ...@@ -466,7 +466,7 @@ pub extern "C" fn srandom(seed: c_uint) {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double { pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
//TODO: endptr // TODO: endptr
use core::str::FromStr; use core::str::FromStr;
...@@ -480,90 +480,6 @@ pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c ...@@ -480,90 +480,6 @@ pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c
} }
} }
#[no_mangle]
pub unsafe extern "C" fn strtol(
s: *const c_char,
endptr: *mut *const c_char,
base: c_int,
) -> c_long {
let set_endptr = |idx: isize| {
if !endptr.is_null() {
*endptr = s.offset(idx);
}
};
let invalid_input = || {
platform::errno = EINVAL;
set_endptr(0);
};
// only valid bases are 2 through 36
if base != 0 && (base < 2 || base > 36) {
invalid_input();
return 0;
}
let mut idx = 0;
// skip any whitespace at the beginning of the string
while ctype::isspace(*s.offset(idx) as c_int) != 0 {
idx += 1;
}
// check for +/-
let positive = match is_positive(*s.offset(idx)) {
Some((pos, i)) => {
idx += i;
pos
}
None => {
invalid_input();
return 0;
}
};
// convert the string to a number
let num_str = s.offset(idx);
let res = match base {
0 => detect_base(num_str).and_then(|(base, i)| convert_integer(num_str.offset(i), base)),
8 => convert_octal(num_str),
16 => convert_hex(num_str),
_ => convert_integer(num_str, base),
};
// check for error parsing octal/hex prefix
// also check to ensure a number was indeed parsed
let (num, i, _) = match res {
Some(res) => res,
None => {
invalid_input();
return 0;
}
};
idx += i;
// account for the sign
let mut num = num as c_long;
num = if num.is_negative() {
platform::errno = ERANGE;
if positive {
c_long::max_value()
} else {
c_long::min_value()
}
} else {
if positive {
num
} else {
-num
}
};
set_endptr(idx);
num
}
fn is_positive(ch: c_char) -> Option<(bool, isize)> { fn is_positive(ch: c_char) -> Option<(bool, isize)> {
match ch { match ch {
0 => None, 0 => None,
...@@ -669,11 +585,125 @@ fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, boo ...@@ -669,11 +585,125 @@ fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, boo
} }
} }
#[no_mangle] macro_rules! strto_impl {
pub extern "C" fn strtoul(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulong { ($funcname:ident, $rettype:ty, $signed:expr, $maxval:expr, $minval:expr) => {
unimplemented!(); #[no_mangle]
pub unsafe extern "C" fn $funcname(s: *const c_char,
endptr: *mut *const c_char,
base: c_int)
-> $rettype {
// ensure these are constants
const CHECK_SIGN: bool = $signed;
const MAX_VAL: $rettype = $maxval;
const MIN_VAL: $rettype = $minval;
let set_endptr = |idx: isize| {
if !endptr.is_null() {
*endptr = s.offset(idx);
}
};
let invalid_input = || {
platform::errno = EINVAL;
set_endptr(0);
};
// only valid bases are 2 through 36
if base != 0 && (base < 2 || base > 36) {
invalid_input();
return 0;
}
let mut idx = 0;
// skip any whitespace at the beginning of the string
while ctype::isspace(*s.offset(idx) as c_int) != 0 {
idx += 1;
}
// check for +/-
let positive = match is_positive(*s.offset(idx)) {
Some((pos, i)) => {
idx += i;
pos
}
None => {
invalid_input();
return 0;
}
};
// convert the string to a number
let num_str = s.offset(idx);
let res = match base {
0 => detect_base(num_str).and_then(|(base, i)| {
convert_integer(num_str.offset(i), base)
}),
8 => convert_octal(num_str),
16 => convert_hex(num_str),
_ => convert_integer(num_str, base),
};
// check for error parsing octal/hex prefix
// also check to ensure a number was indeed parsed
let (num, i, overflow) = match res {
Some(res) => res,
None => {
invalid_input();
return 0;
}
};
idx += i;
let overflow = if CHECK_SIGN {
overflow || (num as c_long).is_negative()
} else {
overflow
};
// account for the sign
let num = num as $rettype;
let num = if overflow {
platform::errno = ERANGE;
if CHECK_SIGN {
if positive {
MAX_VAL
} else {
MIN_VAL
}
} else {
MAX_VAL
}
} else {
if positive {
num
} else {
// not using -num to keep the compiler happy
num.overflowing_neg().0
}
};
set_endptr(idx);
num
}
}
} }
strto_impl!(
strtoul,
c_ulong,
false,
c_ulong::max_value(),
c_ulong::min_value()
);
strto_impl!(
strtol,
c_long,
true,
c_long::max_value(),
c_long::min_value()
);
#[no_mangle] #[no_mangle]
pub extern "C" fn system(command: *const c_char) -> c_int { pub extern "C" fn system(command: *const c_char) -> c_int {
unimplemented!(); unimplemented!();
...@@ -711,10 +741,3 @@ pub extern "C" fn wcstombs(s: *mut c_char, pwcs: *const wchar_t, n: size_t) -> s ...@@ -711,10 +741,3 @@ pub extern "C" fn wcstombs(s: *mut c_char, pwcs: *const wchar_t, n: size_t) -> s
pub extern "C" fn wctomb(s: *mut c_char, wchar: wchar_t) -> c_int { pub extern "C" fn wctomb(s: *mut c_char, wchar: wchar_t) -> c_int {
unimplemented!(); unimplemented!();
} }
/*
#[no_mangle]
pub extern "C" fn func(args) -> c_int {
unimplemented!();
}
*/
...@@ -28,6 +28,7 @@ EXPECT_BINS=\ ...@@ -28,6 +28,7 @@ EXPECT_BINS=\
stdio/freopen \ stdio/freopen \
stdlib/bsearch \ stdlib/bsearch \
stdlib/strtol \ stdlib/strtol \
stdlib/strtoul \
stdlib/a64l \ stdlib/a64l \
stdlib/rand \ stdlib/rand \
string/strncmp \ string/strncmp \
......
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("%ld\n", strtoul(" -42", NULL, 0));
printf("%ld\n", strtoul(" +555", NULL, 0));
printf("%ld\n", strtoul(" 1234567890 ", NULL, 0));
printf("%ld\n", strtoul(" -42", NULL, 10));
printf("%ld\n", strtoul(" +555", NULL, 10));
printf("%ld\n", strtoul(" 1234567890 ", NULL, 10));
printf("%lx\n", strtoul(" 0x38Acfg", NULL, 0));
printf("%lx\n", strtoul("0Xabcdef12", NULL, 16));
printf("%lo\n", strtoul(" 073189", NULL, 0));
printf("%lo\n", strtoul(" 073189", NULL, 8));
printf("%lo\n", strtoul(" 0b", NULL, 8));
if(errno != 0) {
printf("errno is not 0 (%d), something went wrong\n", errno);
}
printf("%lo\n", strtoul(" 0b", NULL, 0));
if(errno != 0) {
printf("errno is not 0 (%d), something went wrong\n", errno);
}
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment