Large reorganization of headers (WIP)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
sys_includes = ["stddef.h", "stdint.h"]
|
||||
include_guard = "_STRING_H"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
@@ -0,0 +1,408 @@
|
||||
//! string implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html
|
||||
|
||||
use core::cmp;
|
||||
use core::mem;
|
||||
use core::ptr;
|
||||
use core::usize;
|
||||
|
||||
use header::signal;
|
||||
use header::errno::*;
|
||||
use platform;
|
||||
use platform::types::*;
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memccpy(
|
||||
dest: *mut c_void,
|
||||
src: *const c_void,
|
||||
c: c_int,
|
||||
n: usize,
|
||||
) -> *mut c_void {
|
||||
let to = memchr(src, c, n);
|
||||
if to.is_null() {
|
||||
return to;
|
||||
}
|
||||
let dist = (to as usize) - (src as usize);
|
||||
if memcpy(dest, src, dist).is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
(dest as *mut u8).offset(dist as isize + 1) as *mut c_void
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memchr(s: *const c_void, c: c_int, n: usize) -> *mut c_void {
|
||||
let mut s = s as *const u8;
|
||||
let c = c as u8;
|
||||
let mut n = n;
|
||||
// read one byte at a time until s is aligned
|
||||
while s as usize % mem::size_of::<usize>() != 0 {
|
||||
if n == 0 {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
if *s == c {
|
||||
return s as *mut c_void;
|
||||
}
|
||||
n -= 1;
|
||||
s = s.offset(1);
|
||||
}
|
||||
let mut s = s as *const usize;
|
||||
let lowbits = !0 as usize / 255;
|
||||
let highbits = lowbits * 0x80;
|
||||
let repeated_c = lowbits * c as usize;
|
||||
while n >= mem::size_of::<usize>() {
|
||||
// read multiple bytes at a time
|
||||
// turn the requested byte into 8 zero bits
|
||||
let m = *s ^ repeated_c;
|
||||
// subtracting one from zero flips high bit from 0 to 1
|
||||
if (m.wrapping_sub(lowbits) & !m & highbits) != 0 {
|
||||
break;
|
||||
}
|
||||
n -= mem::size_of::<usize>();
|
||||
s = s.offset(1);
|
||||
}
|
||||
let mut s = s as *const u8;
|
||||
while n > 0 {
|
||||
if *s == c {
|
||||
return s as *mut c_void;
|
||||
}
|
||||
n -= 1;
|
||||
s = s.offset(1);
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
let a = *(s1 as *const u8).offset(i as isize);
|
||||
let b = *(s2 as *const u8).offset(i as isize);
|
||||
if a != b {
|
||||
return a as i32 - b as i32;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memcpy(s1: *mut c_void, s2: *const c_void, n: usize) -> *mut c_void {
|
||||
platform::memcpy(s1, s2, n)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memmove(s1: *mut c_void, s2: *const c_void, n: usize) -> *mut c_void {
|
||||
if s2 < s1 as *const c_void {
|
||||
// copy from end
|
||||
let mut i = n;
|
||||
while i != 0 {
|
||||
i -= 1;
|
||||
*(s1 as *mut u8).offset(i as isize) = *(s2 as *const u8).offset(i as isize);
|
||||
}
|
||||
} else {
|
||||
// copy from beginning
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
*(s1 as *mut u8).offset(i as isize) = *(s2 as *const u8).offset(i as isize);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
s1
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void {
|
||||
let mut i = 0;
|
||||
while i < n {
|
||||
*(s as *mut u8).offset(i as isize) = c as u8;
|
||||
i += 1;
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
|
||||
strncat(s1, s2, usize::MAX)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
|
||||
let c = c as c_char;
|
||||
while *s != 0 {
|
||||
if *s == c {
|
||||
return s as *mut c_char;
|
||||
}
|
||||
s = s.offset(1);
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
|
||||
strncmp(s1, s2, usize::MAX)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int {
|
||||
// relibc has no locale stuff (yet)
|
||||
strcmp(s1, s2)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
|
||||
let mut i = 0;
|
||||
|
||||
loop {
|
||||
let byte = *src.offset(i);
|
||||
*dst.offset(i) = byte;
|
||||
|
||||
if byte == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
dst
|
||||
}
|
||||
|
||||
pub unsafe fn inner_strspn(s1: *const c_char, s2: *const c_char, cmp: bool) -> size_t {
|
||||
let s1 = s1 as *const u8;
|
||||
let s2 = s2 as *const u8;
|
||||
|
||||
// The below logic is effectively ripped from the musl implementation. It
|
||||
// works by placing each byte as it's own bit in an array of numbers. Each
|
||||
// number can hold up to 8 * mem::size_of::<usize>() bits. We need 256 bits
|
||||
// in total, to fit one byte.
|
||||
|
||||
const BITSIZE: usize = 8 * mem::size_of::<usize>();
|
||||
let mut byteset = [0usize; 256 / BITSIZE];
|
||||
|
||||
let mut i = 0;
|
||||
while *s2.offset(i) != 0 {
|
||||
byteset[(*s2.offset(i) as usize) / BITSIZE] |=
|
||||
1 << (*s2.offset(i) as usize & (BITSIZE-1));
|
||||
i += 1;
|
||||
}
|
||||
|
||||
i = 0; // reset
|
||||
while *s1.offset(i) != 0 &&
|
||||
(byteset[(*s1.offset(i) as usize) / BITSIZE] &
|
||||
1 << (*s1.offset(i) as usize & (BITSIZE-1)) != 0) == cmp {
|
||||
i += 1;
|
||||
}
|
||||
i as size_t
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> size_t {
|
||||
inner_strspn(s1, s2, false)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char {
|
||||
strndup(s1, usize::MAX)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strndup(s1: *const c_char, size: usize) -> *mut c_char {
|
||||
let len = strnlen(s1, size);
|
||||
|
||||
// the "+ 1" is to account for the NUL byte
|
||||
let buffer = platform::alloc(len + 1) as *mut c_char;
|
||||
if buffer.is_null() {
|
||||
platform::errno = ENOMEM as c_int;
|
||||
} else {
|
||||
//memcpy(buffer, s1, len)
|
||||
for i in 0..len as isize {
|
||||
*buffer.offset(i) = *s1.offset(i);
|
||||
}
|
||||
*buffer.offset(len as isize) = 0;
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
|
||||
use core::fmt::Write;
|
||||
|
||||
static mut strerror_buf: [u8; 256] = [0; 256];
|
||||
|
||||
let mut w = platform::StringWriter(strerror_buf.as_mut_ptr(), strerror_buf.len());
|
||||
|
||||
if errnum >= 0 && errnum < STR_ERROR.len() as c_int {
|
||||
w.write_str(STR_ERROR[errnum as usize]);
|
||||
} else {
|
||||
w.write_fmt(format_args!("Unknown error {}", errnum));
|
||||
}
|
||||
|
||||
strerror_buf.as_mut_ptr() as *mut c_char
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
|
||||
strnlen(s, usize::MAX)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strnlen(s: *const c_char, size: usize) -> size_t {
|
||||
platform::c_str_n(s, size).len() as size_t
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: usize) -> *mut c_char {
|
||||
let mut idx = strlen(s1 as *const _) as isize;
|
||||
for i in 0..n as isize {
|
||||
if *s2.offset(i) == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
*s1.offset(idx) = *s2.offset(i);
|
||||
idx += 1;
|
||||
}
|
||||
*s1.offset(idx) = 0;
|
||||
|
||||
s1
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int {
|
||||
let s1 = core::slice::from_raw_parts(s1 as *const c_uchar, n);
|
||||
let s2 = core::slice::from_raw_parts(s2 as *const c_uchar, n);
|
||||
|
||||
for (&a, &b) in s1.iter().zip(s2.iter()) {
|
||||
let val = (a as c_int) - (b as c_int);
|
||||
if a != b || a == 0 {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: usize) -> *mut c_char {
|
||||
let mut i = 0;
|
||||
|
||||
while *src.offset(i) != 0 && (i as usize) < n {
|
||||
*dst.offset(i) = *src.offset(i);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
for i in i..n as isize {
|
||||
*dst.offset(i) = 0;
|
||||
}
|
||||
|
||||
dst
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strpbrk(s1: *const c_char, s2: *const c_char) -> *mut c_char {
|
||||
let p = s1.offset(strcspn(s1, s2) as isize);
|
||||
if *p != 0 {
|
||||
p as *mut c_char
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
|
||||
let len = strlen(s) as isize;
|
||||
let c = c as i8;
|
||||
let mut i = len - 1;
|
||||
while i >= 0 {
|
||||
if *s.offset(i) == c {
|
||||
return s.offset(i) as *mut c_char;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strsignal(sig: c_int) -> *mut c_char {
|
||||
// Mutating this is undefined behavior I believe. But I just can't create a
|
||||
// &'static mut str. Alternative is allocating everything on the heap...
|
||||
signal::_signal_strings[sig as usize].as_ptr() as *const c_char as *mut c_char
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strspn(s1: *const c_char, s2: *const c_char) -> size_t {
|
||||
inner_strspn(s1, s2, true)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strstr(s1: *const c_char, s2: *const c_char) -> *mut c_char {
|
||||
let mut i = 0;
|
||||
while *s1.offset(i) != 0 {
|
||||
let mut j = 0;
|
||||
while *s2.offset(j) != 0 && *s1.offset(j + i) != 0 {
|
||||
if *s2.offset(j) != *s1.offset(j + i) {
|
||||
break;
|
||||
}
|
||||
j += 1;
|
||||
if *s2.offset(j) == 0 {
|
||||
return s1.offset(i) as *mut c_char;
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_char {
|
||||
static mut HAYSTACK: *mut c_char = ptr::null_mut();
|
||||
unsafe {
|
||||
return strtok_r(s1, delimiter, &mut HAYSTACK);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn strtok_r(
|
||||
s: *mut c_char,
|
||||
delimiter: *const c_char,
|
||||
lasts: *mut *mut c_char,
|
||||
) -> *mut c_char {
|
||||
// Loosely based on GLIBC implementation
|
||||
unsafe {
|
||||
let mut haystack = s;
|
||||
if haystack.is_null() {
|
||||
if (*lasts).is_null() {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
haystack = *lasts;
|
||||
}
|
||||
|
||||
// Skip past any extra delimiter left over from previous call
|
||||
haystack = haystack.add(strspn(haystack, delimiter));
|
||||
if *haystack == 0 {
|
||||
*lasts = ptr::null_mut();
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
// Build token by injecting null byte into delimiter
|
||||
let token = haystack;
|
||||
haystack = strpbrk(token, delimiter);
|
||||
if !haystack.is_null() {
|
||||
haystack.write(0);
|
||||
haystack = haystack.add(1);
|
||||
*lasts = haystack;
|
||||
} else {
|
||||
*lasts = ptr::null_mut();
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strxfrm(s1: *mut c_char, s2: *const c_char, n: usize) -> size_t {
|
||||
// relibc has no locale stuff (yet)
|
||||
let len = strlen(s2);
|
||||
if len < n {
|
||||
strcpy(s1, s2);
|
||||
}
|
||||
len
|
||||
}
|
||||
Reference in New Issue
Block a user