Skip to content
Snippets Groups Projects
Unverified Commit cdf298ba authored by Paul Sajna's avatar Paul Sajna Committed by GitHub
Browse files

Merge branch 'master' into unistd

parents 161d9346 dd0e6187
No related branches found
No related tags found
1 merge request!47implement setid functions and unlink
sys_includes = ["sys/types.h"]
include_guard = "_STAT_H"
include_guard = "_SYS_STAT_H"
language = "C"
[enum]
......
......@@ -85,6 +85,13 @@ pub unsafe fn printf<W: fmt::Write>(mut w: W, format: *const c_char, mut ap: VaL
found_percent = false;
}
'o' => {
let a = ap.get::<c_uint>();
w.write_fmt(format_args!("{:o}", a));
found_percent = false;
}
'-' => {}
'+' => {}
' ' => {}
......
......@@ -416,8 +416,192 @@ pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c
}
#[no_mangle]
pub extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
unimplemented!();
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)> {
match ch {
0 => None,
ch if ch == b'+' as c_char => Some((true, 1)),
ch if ch == b'-' as c_char => Some((false, 1)),
_ => Some((true, 0)),
}
}
fn detect_base(s: *const c_char) -> Option<(c_int, isize)> {
let first = unsafe { *s } as u8;
match first {
0 => None,
b'0' => {
let second = unsafe { *s.offset(1) } as u8;
if second == b'X' || second == b'x' {
Some((16, 2))
} else if second >= b'0' && second <= b'7' {
Some((8, 1))
} else {
// in this case, the prefix (0) is going to be the number
Some((8, 0))
}
}
_ => Some((10, 0)),
}
}
unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
if *s != 0 && *s == b'0' as c_char {
if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) {
Some((val, idx + 1, overflow))
} else {
// in case the prefix is not actually a prefix
Some((0, 1, false))
}
} else {
None
}
}
unsafe fn convert_hex(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
if (*s != 0 && *s == b'0' as c_char)
&& (*s.offset(1) != 0 && (*s.offset(1) == b'x' as c_char || *s.offset(1) == b'X' as c_char))
{
convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow))
} else {
None
}
}
fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, bool)> {
// -1 means the character is invalid
#[cfg_attr(rustfmt, rustfmt_skip)]
const LOOKUP_TABLE: [c_long; 256] = [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
];
let mut num: c_ulong = 0;
let mut idx = 0;
let mut overflowed = false;
loop {
let val = unsafe { LOOKUP_TABLE[*s.offset(idx) as usize] };
if val == -1 || val as c_int >= base {
break;
} else {
if let Some(res) = num.checked_mul(base as c_ulong)
.and_then(|num| num.checked_add(val as c_ulong))
{
num = res;
} else {
unsafe {
platform::errno = ERANGE;
}
num = c_ulong::max_value();
overflowed = true;
}
idx += 1;
}
}
if idx > 0 {
Some((num, idx, overflowed))
} else {
None
}
}
#[no_mangle]
......
......@@ -25,4 +25,5 @@
/rmdir
/setid
/unlink
/stdlib/strtol
/write
......@@ -17,10 +17,11 @@ BINS=\
link \
math \
pipe \
printf \
printf \
rmdir \
setid \
unlink \
stdlib/strtol \
write
all: $(BINS)
......@@ -41,6 +42,7 @@ expected: $(BINS)
for bin in $(BINS); \
do \
echo "# $${bin} #"; \
mkdir -p expected/`dirname $${bin}`; \
"./$${bin}" test args > "expected/$${bin}.stdout" 2> "expected/$${bin}.stderr"; \
done
......@@ -50,6 +52,7 @@ verify: $(BINS)
for bin in $(BINS); \
do \
echo "# $${bin} #"; \
mkdir -p gen/`dirname $${bin}`; \
"./$${bin}" test args > "gen/$${bin}.stdout" 2> "gen/$${bin}.stderr"; \
diff -u "gen/$${bin}.stdout" "expected/$${bin}.stdout"; \
diff -u "gen/$${bin}.stderr" "expected/$${bin}.stderr"; \
......
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
printf("%ld\n", strtol(" -42", NULL, 0));
printf("%ld\n", strtol(" +555", NULL, 0));
printf("%ld\n", strtol(" 1234567890 ", NULL, 0));
printf("%ld\n", strtol(" -42", NULL, 10));
printf("%ld\n", strtol(" +555", NULL, 10));
printf("%ld\n", strtol(" 1234567890 ", NULL, 10));
printf("%lx\n", strtol(" 0x38Acfg", NULL, 0));
printf("%lx\n", strtol("0Xabcdef12", NULL, 16));
printf("%lo\n", strtol(" 073189", NULL, 0));
printf("%lo\n", strtol(" 073189", NULL, 8));
printf("%lo\n", strtol(" 0b", NULL, 8));
if(errno != 0) {
printf("errno is not 0 (%d), something went wrong\n", errno);
}
printf("%lo\n", strtol(" 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