Browse Source

Add a few things necessary for openssl (not all)

jD91mZM2 6 năm trước cách đây
mục cha
commit
d3f6985ee9

+ 9 - 0
Cargo.lock

@@ -304,6 +304,7 @@ dependencies = [
  "stdio 0.1.0",
  "stdlib 0.1.0",
  "string 0.1.0",
+ "strings 0.1.0",
  "sys_mman 0.1.0",
  "sys_resource 0.1.0",
  "sys_socket 0.1.0",
@@ -446,6 +447,14 @@ dependencies = [
  "platform 0.1.0",
 ]
 
+[[package]]
+name = "strings"
+version = "0.1.0"
+dependencies = [
+ "cbindgen 0.5.2",
+ "platform 0.1.0",
+]
+
 [[package]]
 name = "strsim"
 version = "0.7.0"

+ 1 - 0
Cargo.toml

@@ -30,6 +30,7 @@ signal = { path = "src/signal" }
 stdio = { path = "src/stdio" }
 stdlib = { path = "src/stdlib" }
 string = { path = "src/string" }
+strings = { path = "src/strings" }
 sys_mman = { path = "src/sys_mman" }
 sys_resource = { path = "src/sys_resource" }
 sys_socket = { path = "src/sys_socket" }

+ 34 - 0
include/sys/param.h

@@ -0,0 +1,34 @@
+#ifndef _SYS_PARAM_H
+#define _SYS_PARAM_H
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+#define __bitop(array, index, op) ((array)[(index) / 8] op (1 << (index) % 8))
+#define setbit(array, index) __bitop(array, index, |=)
+#define clrbit(array, index) __bitop(array, index, &= ~)
+#define isset(array, index) __bitop(array, index, &)
+#define isclr(array, index) !isset(array, index)
+
+#define howmany(bits, size) (((bits) + (size) - 1) / (size))
+#define roundup(bits, size) (howmany(bits, size) * (size))
+#define powerof2(n) !(((n) - 1) & (n))
+
+// Shamelessly copied from musl.
+// Tweak as needed.
+#define MAXSYMLINKS 20
+#define MAXHOSTNAMELEN 64
+#define MAXNAMLEN 255
+#define MAXPATHLEN 4096
+#define NBBY 8
+#define NGROUPS 32
+#define CANBSIZ 255
+#define NOFILE 256
+#define NCARGS 131072
+#define DEV_BSIZE 512
+#define NOGROUP (-1)
+
+#include <sys/resource.h>
+#include <limits.h>
+
+#endif

+ 1 - 1
src/ctype/src/lib.rs

@@ -18,7 +18,7 @@ pub extern "C" fn isalpha(c: c_int) -> c_int {
 
 #[no_mangle]
 pub extern "C" fn isascii(c: c_int) -> c_int {
-    (!(c & !0x7f)) as c_int
+    ((c & !0x7f) == 0) as c_int
 }
 
 #[no_mangle]

+ 1 - 0
src/lib.rs

@@ -20,6 +20,7 @@ pub extern crate signal;
 pub extern crate stdio;
 pub extern crate stdlib;
 pub extern crate string;
+pub extern crate strings;
 pub extern crate sys_mman;
 pub extern crate sys_resource;
 pub extern crate sys_socket;

+ 17 - 0
src/platform/src/lib.rs

@@ -4,6 +4,7 @@
 #![feature(allocator_api)]
 //TODO #![feature(thread_local)]
 
+#[cfg_attr(target_os = "redox", macro_use)]
 extern crate alloc;
 
 #[cfg(all(not(feature = "no_std"), target_os = "linux"))]
@@ -43,6 +44,22 @@ use types::*;
 #[global_allocator]
 static ALLOCATOR: Allocator = Allocator;
 
+pub const AF_INET: c_int = 2;
+pub const SOCK_STREAM: c_int = 1;
+pub const SOCK_DGRAM: c_int = 2;
+pub const SOCK_NONBLOCK: c_int = 0o4000;
+pub const SOCK_CLOEXEC: c_int = 0o2000000;
+
+pub type in_addr_t = [u8; 4];
+pub type in_port_t = u16;
+pub type sa_family_t = u16;
+pub type socklen_t = u32;
+
+pub struct sockaddr {
+    pub sa_family: sa_family_t,
+    pub data: [c_char; 14]
+}
+
 //TODO #[thread_local]
 #[allow(non_upper_case_globals)]
 #[no_mangle]

+ 23 - 1
src/platform/src/linux/mod.rs

@@ -1,6 +1,6 @@
 use core::ptr;
 
-use errno;
+use ::*;
 use types::*;
 
 const AT_FDCWD: c_int = -100;
@@ -19,6 +19,10 @@ pub fn e(sys: usize) -> usize {
     }
 }
 
+pub unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int {
+    e(syscall!(BIND, socket, address, address_len)) as c_int
+}
+
 pub fn brk(addr: *mut c_void) -> *mut c_void {
     unsafe { syscall!(BRK, addr) as *mut c_void }
 }
@@ -39,6 +43,10 @@ pub fn close(fildes: c_int) -> c_int {
     e(unsafe { syscall!(CLOSE, fildes) }) as c_int
 }
 
+pub unsafe fn connect(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int {
+    e(syscall!(CONNECT, socket, address, address_len)) as c_int
+}
+
 pub fn dup(fildes: c_int) -> c_int {
     e(unsafe { syscall!(DUP, fildes) }) as c_int
 }
@@ -171,6 +179,11 @@ pub fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t {
     e(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) }) as ssize_t
 }
 
+pub unsafe fn recvfrom(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int,
+        address: *mut sockaddr, address_len: *mut socklen_t) -> ssize_t {
+    e(syscall!(RECVFROM, socket, buf, len, flags, address, address_len)) as ssize_t
+}
+
 pub fn rename(old: *const c_char, new: *const c_char) -> c_int {
     e(unsafe { syscall!(RENAMEAT, AT_FDCWD, old, AT_FDCWD, new) }) as c_int
 }
@@ -179,6 +192,11 @@ pub fn rmdir(path: *const c_char) -> c_int {
     e(unsafe { syscall!(UNLINKAT, AT_FDCWD, path, AT_REMOVEDIR) }) as c_int
 }
 
+pub unsafe fn sendto(socket: c_int, buf: *const c_void, len: size_t, flags: c_int,
+        dest_addr: *const sockaddr, dest_len: socklen_t) -> ssize_t {
+    e(syscall!(SENDTO, socket, buf, len, flags, dest_addr, dest_len)) as ssize_t
+}
+
 pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int {
     e(unsafe { syscall!(SETPGID, pid, pgid) }) as c_int
 }
@@ -195,6 +213,10 @@ pub fn stat(file: *const c_char, buf: *mut stat) -> c_int {
     e(unsafe { syscall!(NEWFSTATAT, AT_FDCWD, file, buf, 0) }) as c_int
 }
 
+pub fn socket(domain: c_int, kind: c_int, protocol: c_int) -> c_int {
+    e(unsafe { syscall!(SOCKET, domain, kind, protocol) }) as c_int
+}
+
 pub fn uname(utsname: usize) -> c_int {
     e(unsafe { syscall!(UNAME, utsname, 0) }) as c_int
 }

+ 112 - 2
src/platform/src/redox/mod.rs

@@ -1,3 +1,4 @@
+use alloc;
 use core::mem;
 use core::ptr;
 use core::slice;
@@ -6,10 +7,16 @@ use syscall::data::Stat as redox_stat;
 use syscall::data::TimeSpec as redox_timespec;
 use syscall::flag::*;
 
-use c_str;
-use errno;
+use ::*;
 use types::*;
 
+#[repr(C)]
+struct SockData {
+    port: in_port_t,
+    addr: in_addr_t,
+    _pad: [c_char; 8]
+}
+
 pub fn e(sys: Result<usize, syscall::Error>) -> usize {
     match sys {
         Ok(ok) => ok,
@@ -22,6 +29,45 @@ pub fn e(sys: Result<usize, syscall::Error>) -> usize {
     }
 }
 
+macro_rules! bind_or_connect {
+    (bind $path:expr) => {
+        concat!("/", $path)
+    };
+    (connect $path:expr) => {
+        $path
+    };
+    ($mode:ident $socket:expr, $address:expr, $address_len:expr) => {{
+        if (*$address).sa_family as c_int != AF_INET {
+            errno = syscall::EAFNOSUPPORT;
+            return -1;
+        }
+        if ($address_len as usize) < mem::size_of::<sockaddr>() {
+            errno = syscall::EINVAL;
+            return -1;
+        }
+        let data: &SockData = mem::transmute(&(*$address).data);
+        let addr = &data.addr;
+        let port = in_port_t::from_be(data.port); // This is transmuted from bytes in BigEndian order
+        let path = format!(bind_or_connect!($mode "{}.{}.{}.{}:{}"), addr[0], addr[1], addr[2], addr[3], port);
+
+        // Duplicate the socket, and then duplicate the copy back to the original fd
+        let fd = e(syscall::dup($socket as usize, path.as_bytes()));
+        if (fd as c_int) < 0 {
+            return -1;
+        }
+        let result = syscall::dup2(fd, $socket as usize, &[]);
+        let _ = syscall::close(fd);
+        if (e(result) as c_int) < 0 {
+            return -1;
+        }
+        0
+    }}
+}
+
+pub unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int {
+    bind_or_connect!(bind socket, address, address_len)
+}
+
 pub fn brk(addr: *mut c_void) -> *mut c_void {
     unsafe { syscall::brk(addr as usize).unwrap_or(0) as *mut c_void }
 }
@@ -59,6 +105,10 @@ pub fn close(fd: c_int) -> c_int {
     e(syscall::close(fd as usize)) as c_int
 }
 
+pub unsafe fn connect(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int {
+    bind_or_connect!(connect socket, address, address_len)
+}
+
 pub fn dup(fd: c_int) -> c_int {
     e(syscall::dup(fd as usize, &[])) as c_int
 }
@@ -331,6 +381,24 @@ pub fn read(fd: c_int, buf: &mut [u8]) -> ssize_t {
     e(syscall::read(fd as usize, buf)) as ssize_t
 }
 
+pub unsafe fn recvfrom(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int,
+        address: *mut sockaddr, address_len: *mut socklen_t) -> ssize_t {
+    if flags != 0 {
+        errno = syscall::EOPNOTSUPP;
+        return -1;
+    }
+    let data = slice::from_raw_parts_mut(
+        &mut (*address).data as *mut _ as *mut u8,
+        (*address).data.len()
+    );
+    let pathlen = e(syscall::fpath(socket as usize, data));
+    if pathlen < 0 {
+        return -1;
+    }
+    *address_len = pathlen as socklen_t;
+    read(socket, slice::from_raw_parts_mut(buf as *mut u8, len))
+}
+
 pub fn rename(oldpath: *const c_char, newpath: *const c_char) -> c_int {
     let (oldpath, newpath) = unsafe { (c_str(oldpath), c_str(newpath)) };
     match syscall::open(oldpath, O_WRONLY) {
@@ -348,6 +416,16 @@ pub fn rmdir(path: *const c_char) -> c_int {
     e(syscall::rmdir(path)) as c_int
 }
 
+pub unsafe fn sendto(socket: c_int, buf: *const c_void, len: size_t, flags: c_int,
+        _dest_addr: *const sockaddr, _dest_len: socklen_t) -> ssize_t {
+    // TODO: Use dest_addr and dest_len
+    if flags != 0 {
+        errno = syscall::EOPNOTSUPP;
+        return -1;
+    }
+    write(socket, slice::from_raw_parts(buf as *const u8, len))
+}
+
 pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int {
     e(syscall::setpgid(pid as usize, pgid as usize)) as c_int
 }
@@ -372,6 +450,38 @@ pub fn stat(path: *const c_char, buf: *mut stat) -> c_int {
     }
 }
 
+pub unsafe fn socket(domain: c_int, mut kind: c_int, protocol: c_int) -> c_int {
+    if domain != AF_INET {
+        errno = syscall::EAFNOSUPPORT;
+        return -1;
+    }
+    if protocol != 0 {
+        errno = syscall::EPROTONOSUPPORT;
+        return -1;
+    }
+
+    let mut flags = O_RDWR;
+    if kind & SOCK_NONBLOCK == SOCK_NONBLOCK {
+        kind &= !SOCK_NONBLOCK;
+        flags |= O_NONBLOCK;
+    }
+    if kind & SOCK_CLOEXEC == SOCK_CLOEXEC {
+        kind &= !SOCK_CLOEXEC;
+        flags |= O_CLOEXEC;
+    }
+
+    // The tcp: and udp: schemes allow using no path,
+    // and later specifying one using `dup`.
+    match kind {
+        SOCK_STREAM => e(syscall::open("tcp:", flags)) as c_int,
+        SOCK_DGRAM  => e(syscall::open("udp:", flags)) as c_int,
+        _ => {
+            errno = syscall::EPROTOTYPE;
+            -1
+        }
+    }
+}
+
 pub fn unlink(path: *const c_char) -> c_int {
     let path = unsafe { c_str(path) };
     e(syscall::unlink(path)) as c_int

+ 2 - 4
src/stdio/src/printf.rs

@@ -55,13 +55,11 @@ pub unsafe fn printf<W: Write>(mut w: W, format: *const c_char, mut ap: VaList)
                     w.write_fmt(format_args!("0x{:x}", a))
                 }
                 's' => {
-                    let a = ap.get::<usize>();
+                    let a = ap.get::<*const c_char>();
 
                     found_percent = false;
 
-                    w.write_str(str::from_utf8_unchecked(platform::c_str(
-                        a as *const c_char,
-                    )))
+                    w.write_str(str::from_utf8_unchecked(platform::c_str(a)))
                 }
                 'u' => {
                     let a = ap.get::<c_uint>();

+ 1 - 1
src/stdlib/src/lib.rs

@@ -229,7 +229,7 @@ pub extern "C" fn erand(xsubi: [c_ushort; 3]) -> c_double {
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn exit(status: c_int) -> ! {
+pub unsafe extern "C" fn exit(status: c_int) {
     for i in (0..ATEXIT_FUNCS.len()).rev() {
         if let Some(func) = ATEXIT_FUNCS[i] {
             (func)();

+ 7 - 8
src/string/src/lib.rs

@@ -126,14 +126,13 @@ pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_ch
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn strchr(s: *const c_char, c: c_int) -> *mut c_char {
-    let c = c as i8;
-    let mut i = 0;
-    while *s.offset(i) != 0 {
-        if *s.offset(i) == c {
-            return s.offset(i) as *mut c_char;
+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;
         }
-        i += 1;
+        s = s.offset(1);
     }
     ptr::null_mut()
 }
@@ -276,7 +275,7 @@ pub unsafe extern "C" fn strncpy(s1: *mut c_char, s2: *const c_char, n: usize) -
     }
 
     // if length of s2 < n, pad s1 with zeroes
-    for _ in cmp::min(n, s2_len)..n {
+    while idx < s2_len {
         *s1.offset(idx as isize) = 0;
         idx += 1;
     }

+ 11 - 0
src/strings/Cargo.toml

@@ -0,0 +1,11 @@
+[package]
+name = "strings"
+version = "0.1.0"
+authors = ["jD91mZM2 <[email protected]>"]
+build = "build.rs"
+
+[build-dependencies]
+cbindgen = { path = "../../cbindgen" }
+
+[dependencies]
+platform = { path = "../platform" }

+ 11 - 0
src/strings/build.rs

@@ -0,0 +1,11 @@
+extern crate cbindgen;
+
+use std::{env, fs};
+
+fn main() {
+    let crate_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set");
+    fs::create_dir_all("../../target/include").expect("failed to create include directory");
+    cbindgen::generate(crate_dir)
+        .expect("failed to generate bindings")
+        .write_to_file("../../target/include/strings.h");
+}

+ 7 - 0
src/strings/cbindgen.toml

@@ -0,0 +1,7 @@
+sys_includes = ["stddef.h", "stdint.h"]
+include_guard = "_STRINGS_H"
+language = "C"
+style = "Tag"
+
+[enum]
+prefix_with_name = true

+ 136 - 0
src/strings/src/lib.rs

@@ -0,0 +1,136 @@
+//! strings implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/strings.h.html
+#![no_std]
+#![feature(alloc)]
+
+extern crate alloc;
+extern crate platform;
+
+use alloc::Vec;
+use core::ptr;
+use platform::types::*;
+
+#[no_mangle]
+pub unsafe extern "C" fn bcmp(mut first: *const c_void, mut second: *const c_void, n: size_t) -> c_int {
+    let first = first as *const c_char;
+    let second = second as *const c_char;
+
+    for i in 0..n as isize {
+        if *first.offset(i) != *second.offset(i) {
+            return -1;
+        }
+    }
+    0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn bcopy(src: *const c_void, dst: *mut c_void, n: size_t) {
+    let src = src as *mut c_char;
+    let dst = dst as *mut c_char;
+
+    let mut tmp = Vec::with_capacity(n);
+    for i in 0..n as isize {
+        tmp.push(*src.offset(i));
+    }
+    for (i, val) in tmp.into_iter().enumerate() {
+        *dst.offset(i as isize) = val;
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn bzero(src: *mut c_void, n: size_t) {
+    let src = src as *mut c_char;
+
+    for i in 0..n as isize {
+        *src.offset(i) = 0;
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn ffs(mut i: c_int) -> c_int {
+    if i == 0 {
+        return 0;
+    }
+    let mut n = 1;
+    while i & 1 == 0 {
+        i >>= 1;
+        n += 1;
+    }
+    n
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn index(mut s: *const c_char, c: c_int) -> *mut c_char {
+    while *s != 0 {
+        if *s == c as c_char {
+            // Input is const but output is mutable. WHY C, WHY DO THIS?
+            return s as *mut c_char;
+        }
+        s = s.offset(1);
+    }
+    ptr::null_mut()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rindex(mut s: *const c_char, c: c_int) -> *mut c_char {
+    let original = s;
+    while *s != 0 {
+        s = s.offset(1);
+    }
+
+    while s != original {
+        s = s.offset(-1);
+        if *s == c as c_char {
+            // Input is const but output is mutable. WHY C, WHY DO THIS?
+            return s as *mut c_char;
+        }
+    }
+    ptr::null_mut()
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn strcasecmp(mut first: *const c_char, mut second: *const c_char) -> c_int {
+    while *first != 0 && *second != 0 {
+        let mut i = *first;
+        let mut j = *second;
+
+        if i >= b'A' as c_char && i <= b'Z' as c_char {
+            i += (b'a' - b'A') as c_char;
+        }
+        if j >= b'A' as c_char && j <= b'Z' as c_char {
+            j += (b'a' - b'A') as c_char;
+        }
+
+        if i != j {
+            return -1;
+        }
+
+        first = first.offset(1);
+        second = first.offset(1);
+    }
+    // Both strings ended at the same time too
+    (*first == *second) as c_int
+}
+#[no_mangle]
+pub unsafe extern "C" fn strncasecmp(mut first: *const c_char, mut second: *const c_char, mut n: size_t) -> c_int {
+    while *first != 0 && *second != 0 && n > 0 {
+        let mut i = *first;
+        let mut j = *second;
+
+        if i >= b'A' as c_char && i <= b'Z' as c_char {
+            i += (b'a' - b'A') as c_char;
+        }
+        if j >= b'A' as c_char && j <= b'Z' as c_char {
+            j += (b'a' - b'A') as c_char;
+        }
+
+        if i != j {
+            return -1;
+        }
+
+        first = first.offset(1);
+        second = first.offset(1);
+        n -= 1;
+    }
+    // Both strings ended at the same time too
+    (n == 0 || *first == *second) as c_int
+}

+ 19 - 10
src/sys_socket/src/lib.rs

@@ -5,17 +5,26 @@
 
 extern crate platform;
 
+use core::ptr;
 use platform::types::*;
 
+pub type in_addr_t = [u8; 4];
+pub type in_port_t = u16;
 pub type sa_family_t = u16;
 pub type socklen_t = u32;
 
 #[repr(C)]
 pub struct sockaddr {
     pub sa_family: sa_family_t,
-    pub sa_data: [c_char; 14],
+    data: [c_char; 14]
 }
 
+pub const AF_INET: c_int = 2;
+pub const SOCK_STREAM: c_int = 1;
+pub const SOCK_DGRAM: c_int = 2;
+pub const SOCK_NONBLOCK: c_int = 0o4000;
+pub const SOCK_CLOEXEC: c_int = 0o2000000;
+
 #[no_mangle]
 pub unsafe extern "C" fn accept(
     socket: c_int,
@@ -31,7 +40,7 @@ pub unsafe extern "C" fn bind(
     address: *const sockaddr,
     address_len: socklen_t,
 ) -> c_int {
-    unimplemented!();
+    platform::bind(socket, address as *const platform::sockaddr, address_len)
 }
 
 #[no_mangle]
@@ -40,7 +49,7 @@ pub unsafe extern "C" fn connect(
     address: *const sockaddr,
     address_len: socklen_t,
 ) -> c_int {
-    unimplemented!();
+    platform::connect(socket, address as *const platform::sockaddr, address_len)
 }
 
 #[no_mangle]
@@ -84,7 +93,7 @@ pub unsafe extern "C" fn recv(
     length: size_t,
     flags: c_int,
 ) -> ssize_t {
-    unimplemented!();
+    recvfrom(socket, buffer, length, flags, ptr::null_mut(), ptr::null_mut())
 }
 
 #[no_mangle]
@@ -96,7 +105,7 @@ pub unsafe extern "C" fn recvfrom(
     address: *mut sockaddr,
     address_len: *mut socklen_t,
 ) -> ssize_t {
-    unimplemented!();
+    platform::recvfrom(socket, buffer, length, flags, address as *mut platform::sockaddr, address_len)
 }
 
 #[no_mangle]
@@ -106,11 +115,11 @@ pub unsafe extern "C" fn send(
     length: size_t,
     flags: c_int,
 ) -> ssize_t {
-    unimplemented!();
+    sendto(socket, message, length, flags, ptr::null(), 0)
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn sento(
+pub unsafe extern "C" fn sendto(
     socket: c_int,
     message: *const c_void,
     length: size_t,
@@ -118,7 +127,7 @@ pub unsafe extern "C" fn sento(
     dest_addr: *const sockaddr,
     dest_len: socklen_t,
 ) -> ssize_t {
-    unimplemented!();
+    platform::sendto(socket, message, length, flags, dest_addr as *const platform::sockaddr, dest_len)
 }
 
 #[no_mangle]
@@ -138,8 +147,8 @@ pub unsafe extern "C" fn shutdown(socket: c_int, how: c_int) -> c_int {
 }
 
 #[no_mangle]
-pub unsafe extern "C" fn socket(domain: c_int, _type: c_int, protocol: c_int) -> c_int {
-    unimplemented!();
+pub unsafe extern "C" fn socket(domain: c_int, kind: c_int, protocol: c_int) -> c_int {
+    platform::socket(domain, kind, protocol)
 }
 
 #[no_mangle]

+ 1 - 0
tests/.gitignore

@@ -32,6 +32,7 @@
 /setjmp
 /sleep
 /sprintf
+/strings
 /stdlib/a64l
 /stdlib/bsearch
 /stdlib/mktemp

+ 2 - 1
tests/Makefile

@@ -26,6 +26,7 @@ EXPECT_BINS=\
 	setjmp \
 	sleep \
 	sprintf \
+	strings \
 	stdio/fwrite \
 	stdio/all \
 	stdio/freopen \
@@ -116,4 +117,4 @@ TAILLIBS=\
 	../target/openlibm/libopenlibm.a
 
 %: %.c $(HEADLIBS) $(TAILLIBS)
-	gcc -fno-stack-protector -Wall -g $(CFLAGS) $(HEADLIBS) "$<" $(TAILLIBS) -o "$@"
+	gcc -fno-builtin -fno-stack-protector -Wall -g $(CFLAGS) $(HEADLIBS) "$<" $(TAILLIBS) -o "$@"

+ 1 - 1
tests/expected/string/strchr.stdout

@@ -1,3 +1,3 @@
 ello
 ld
-
+1

+ 0 - 0
tests/expected/strings.stderr


+ 0 - 0
tests/expected/strings.stdout


+ 1 - 1
tests/string/strchr.c

@@ -4,7 +4,7 @@
 int main(int argc, char* argv[]) {
 	printf("%s\n", strchr("hello", 'e')); // should be ello
 	printf("%s\n", strchr("world", 'l')); // should be ld
-	printf("%s\n", strchr("world", 0)); // should be ''
+	printf("%i\n", strchr("world", 0) == NULL); // should be 1
 
     return 0;
 }

+ 30 - 0
tests/strings.c

@@ -0,0 +1,30 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+
+int main() {
+    assert(!bcmp("hello", "hehe", 2));
+    assert(bcmp("hello", "haha", 2));
+
+    char* new = malloc(3);
+    bcopy("hi", new, 3); // include nul byte
+
+    assert(!strcasecmp("hi", new));
+    assert(!strcasecmp("hi", "HI"));
+    assert(!strncasecmp("hi", "HIHI", 2));
+
+    bzero(new, 1);
+    assert(*new == 0);
+    assert(*(new+1) == 'i');
+    assert(*(new+2) == 0);
+
+    assert(ffs(1) == 1);
+    assert(ffs(2) == 2);
+    assert(ffs(3) == 1);
+    assert(ffs(10) == 2);
+
+    char* str = "hihih";
+    assert(index(str, 'i') == str + 1);
+    assert(rindex(str, 'i') == str + 3);
+}