From ec288a1b53af62ed627a78d71b797d3c45e46cb3 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Thu, 8 Mar 2018 05:13:10 +0000 Subject: [PATCH] Add ctype functions and atoi/atol Add ctype functions - isalnum - isalpha - isascii - isdigit - islower - isspace - isupper Add stdlib functions - atoi - atol Fix some warnings Make a fmt run --- Cargo.lock | 1 + src/ctype/src/lib.rs | 26 ++++-- src/errno/src/lib.rs | 198 ++++++++++++++++++++-------------------- src/platform/src/lib.rs | 1 + src/stdio/src/lib.rs | 2 + src/stdlib/Cargo.toml | 1 + src/stdlib/src/lib.rs | 45 ++++++++- tests/.gitignore | 2 + tests/Makefile | 2 + tests/atoi.c | 12 +++ tests/ctype.c | 46 ++++++++++ 11 files changed, 224 insertions(+), 112 deletions(-) create mode 100644 tests/atoi.c create mode 100644 tests/ctype.c diff --git a/Cargo.lock b/Cargo.lock index c2ea9141fb..a140817596 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -453,6 +453,7 @@ name = "stdlib" version = "0.1.0" dependencies = [ "cbindgen 0.5.0", + "ctype 0.1.0", "platform 0.1.0", "ralloc 1.0.0", ] diff --git a/src/ctype/src/lib.rs b/src/ctype/src/lib.rs index be49d70ee4..73e2851712 100644 --- a/src/ctype/src/lib.rs +++ b/src/ctype/src/lib.rs @@ -8,17 +8,17 @@ use platform::types::*; #[no_mangle] pub extern "C" fn isalnum(c: c_int) -> c_int { - unimplemented!(); + (isdigit(c) != 0 || isalpha(c) != 0) as c_int } #[no_mangle] pub extern "C" fn isalpha(c: c_int) -> c_int { - unimplemented!(); + (islower(c) != 0 || isupper(c) != 0) as c_int } #[no_mangle] pub extern "C" fn isascii(c: c_int) -> c_int { - unimplemented!(); + (!(c & !0x7f)) as c_int } #[no_mangle] @@ -28,7 +28,7 @@ pub extern "C" fn iscntrl(c: c_int) -> c_int { #[no_mangle] pub extern "C" fn isdigit(c: c_int) -> c_int { - unimplemented!(); + (((c - 0x30) as c_uint) < 10) as c_int } #[no_mangle] @@ -38,7 +38,7 @@ pub extern "C" fn isgraph(c: c_int) -> c_int { #[no_mangle] pub extern "C" fn islower(c: c_int) -> c_int { - unimplemented!(); + (((c - 0x61) as c_uint) < 26) as c_int } #[no_mangle] @@ -53,12 +53,12 @@ pub extern "C" fn ispunct(c: c_int) -> c_int { #[no_mangle] pub extern "C" fn isspace(c: c_int) -> c_int { - unimplemented!(); + (c == 0x20) as c_int } #[no_mangle] pub extern "C" fn isupper(c: c_int) -> c_int { - unimplemented!(); + (((c - 0x41) as c_uint) < 26) as c_int } #[no_mangle] @@ -73,10 +73,18 @@ pub extern "C" fn toascii(c: c_int) -> c_int { #[no_mangle] pub extern "C" fn tolower(c: c_int) -> c_int { - unimplemented!(); + if isupper(c) != 0 { + c + 0x20 + } else { + c + } } #[no_mangle] pub extern "C" fn toupper(c: c_int) -> c_int { - unimplemented!(); + if islower(c) != 0 { + c - 0x20 + } else { + c + } } diff --git a/src/errno/src/lib.rs b/src/errno/src/lib.rs index 5d0d6c0091..86ff913534 100644 --- a/src/errno/src/lib.rs +++ b/src/errno/src/lib.rs @@ -6,105 +6,105 @@ extern crate platform; use platform::types::*; -pub const EPERM: c_int = 1; /* Operation not permitted */ -pub const ENOENT: c_int = 2; /* No such file or directory */ -pub const ESRCH: c_int = 3; /* No such process */ -pub const EINTR: c_int = 4; /* Interrupted system call */ -pub const EIO: c_int = 5; /* I/O error */ -pub const ENXIO: c_int = 6; /* No such device or address */ -pub const E2BIG: c_int = 7; /* Argument list too long */ -pub const ENOEXEC: c_int = 8; /* Exec format error */ -pub const EBADF: c_int = 9; /* Bad file number */ -pub const ECHILD: c_int = 10; /* No child processes */ -pub const EAGAIN: c_int = 11; /* Try again */ -pub const ENOMEM: c_int = 12; /* Out of memory */ -pub const EACCES: c_int = 13; /* Permission denied */ -pub const EFAULT: c_int = 14; /* Bad address */ -pub const ENOTBLK: c_int = 15; /* Block device required */ -pub const EBUSY: c_int = 16; /* Device or resource busy */ -pub const EEXIST: c_int = 17; /* File exists */ -pub const EXDEV: c_int = 18; /* Cross-device link */ -pub const ENODEV: c_int = 19; /* No such device */ -pub const ENOTDIR: c_int = 20; /* Not a directory */ -pub const EISDIR: c_int = 21; /* Is a directory */ -pub const EINVAL: c_int = 22; /* Invalid argument */ -pub const ENFILE: c_int = 23; /* File table overflow */ -pub const EMFILE: c_int = 24; /* Too many open files */ -pub const ENOTTY: c_int = 25; /* Not a typewriter */ -pub const ETXTBSY: c_int = 26; /* Text file busy */ -pub const EFBIG: c_int = 27; /* File too large */ -pub const ENOSPC: c_int = 28; /* No space left on device */ -pub const ESPIPE: c_int = 29; /* Illegal seek */ -pub const EROFS: c_int = 30; /* Read-only file system */ -pub const EMLINK: c_int = 31; /* Too many links */ -pub const EPIPE: c_int = 32; /* Broken pipe */ -pub const EDOM: c_int = 33; /* Math argument out of domain of func */ -pub const ERANGE: c_int = 34; /* Math result not representable */ -pub const EDEADLK: c_int = 35; /* Resource deadlock would occur */ -pub const ENAMETOOLONG: c_int = 36; /* File name too long */ -pub const ENOLCK: c_int = 37; /* No record locks available */ -pub const ENOSYS: c_int = 38; /* Function not implemented */ -pub const ENOTEMPTY: c_int = 39; /* Directory not empty */ -pub const ELOOP: c_int = 40; /* Too many symbolic links encountered */ -pub const EWOULDBLOCK: c_int = 41; /* Operation would block */ -pub const ENOMSG: c_int = 42; /* No message of desired type */ -pub const EIDRM: c_int = 43; /* Identifier removed */ -pub const ECHRNG: c_int = 44; /* Channel number out of range */ -pub const EL2NSYNC: c_int = 45; /* Level 2 not synchronized */ -pub const EL3HLT: c_int = 46; /* Level 3 halted */ -pub const EL3RST: c_int = 47; /* Level 3 reset */ -pub const ELNRNG: c_int = 48; /* Link number out of range */ -pub const EUNATCH: c_int = 49; /* Protocol driver not attached */ -pub const ENOCSI: c_int = 50; /* No CSI structure available */ -pub const EL2HLT: c_int = 51; /* Level 2 halted */ -pub const EBADE: c_int = 52; /* Invalid exchange */ -pub const EBADR: c_int = 53; /* Invalid request descriptor */ -pub const EXFULL: c_int = 54; /* Exchange full */ -pub const ENOANO: c_int = 55; /* No anode */ -pub const EBADRQC: c_int = 56; /* Invalid request code */ -pub const EBADSLT: c_int = 57; /* Invalid slot */ +pub const EPERM: c_int = 1; /* Operation not permitted */ +pub const ENOENT: c_int = 2; /* No such file or directory */ +pub const ESRCH: c_int = 3; /* No such process */ +pub const EINTR: c_int = 4; /* Interrupted system call */ +pub const EIO: c_int = 5; /* I/O error */ +pub const ENXIO: c_int = 6; /* No such device or address */ +pub const E2BIG: c_int = 7; /* Argument list too long */ +pub const ENOEXEC: c_int = 8; /* Exec format error */ +pub const EBADF: c_int = 9; /* Bad file number */ +pub const ECHILD: c_int = 10; /* No child processes */ +pub const EAGAIN: c_int = 11; /* Try again */ +pub const ENOMEM: c_int = 12; /* Out of memory */ +pub const EACCES: c_int = 13; /* Permission denied */ +pub const EFAULT: c_int = 14; /* Bad address */ +pub const ENOTBLK: c_int = 15; /* Block device required */ +pub const EBUSY: c_int = 16; /* Device or resource busy */ +pub const EEXIST: c_int = 17; /* File exists */ +pub const EXDEV: c_int = 18; /* Cross-device link */ +pub const ENODEV: c_int = 19; /* No such device */ +pub const ENOTDIR: c_int = 20; /* Not a directory */ +pub const EISDIR: c_int = 21; /* Is a directory */ +pub const EINVAL: c_int = 22; /* Invalid argument */ +pub const ENFILE: c_int = 23; /* File table overflow */ +pub const EMFILE: c_int = 24; /* Too many open files */ +pub const ENOTTY: c_int = 25; /* Not a typewriter */ +pub const ETXTBSY: c_int = 26; /* Text file busy */ +pub const EFBIG: c_int = 27; /* File too large */ +pub const ENOSPC: c_int = 28; /* No space left on device */ +pub const ESPIPE: c_int = 29; /* Illegal seek */ +pub const EROFS: c_int = 30; /* Read-only file system */ +pub const EMLINK: c_int = 31; /* Too many links */ +pub const EPIPE: c_int = 32; /* Broken pipe */ +pub const EDOM: c_int = 33; /* Math argument out of domain of func */ +pub const ERANGE: c_int = 34; /* Math result not representable */ +pub const EDEADLK: c_int = 35; /* Resource deadlock would occur */ +pub const ENAMETOOLONG: c_int = 36; /* File name too long */ +pub const ENOLCK: c_int = 37; /* No record locks available */ +pub const ENOSYS: c_int = 38; /* Function not implemented */ +pub const ENOTEMPTY: c_int = 39; /* Directory not empty */ +pub const ELOOP: c_int = 40; /* Too many symbolic links encountered */ +pub const EWOULDBLOCK: c_int = 41; /* Operation would block */ +pub const ENOMSG: c_int = 42; /* No message of desired type */ +pub const EIDRM: c_int = 43; /* Identifier removed */ +pub const ECHRNG: c_int = 44; /* Channel number out of range */ +pub const EL2NSYNC: c_int = 45; /* Level 2 not synchronized */ +pub const EL3HLT: c_int = 46; /* Level 3 halted */ +pub const EL3RST: c_int = 47; /* Level 3 reset */ +pub const ELNRNG: c_int = 48; /* Link number out of range */ +pub const EUNATCH: c_int = 49; /* Protocol driver not attached */ +pub const ENOCSI: c_int = 50; /* No CSI structure available */ +pub const EL2HLT: c_int = 51; /* Level 2 halted */ +pub const EBADE: c_int = 52; /* Invalid exchange */ +pub const EBADR: c_int = 53; /* Invalid request descriptor */ +pub const EXFULL: c_int = 54; /* Exchange full */ +pub const ENOANO: c_int = 55; /* No anode */ +pub const EBADRQC: c_int = 56; /* Invalid request code */ +pub const EBADSLT: c_int = 57; /* Invalid slot */ pub const EDEADLOCK: c_int = 58; /* Resource deadlock would occur */ -pub const EBFONT: c_int = 59; /* Bad font file format */ -pub const ENOSTR: c_int = 60; /* Device not a stream */ -pub const ENODATA: c_int = 61; /* No data available */ -pub const ETIME: c_int = 62; /* Timer expired */ -pub const ENOSR: c_int = 63; /* Out of streams resources */ -pub const ENONET: c_int = 64; /* Machine is not on the network */ -pub const ENOPKG: c_int = 65; /* Package not installed */ -pub const EREMOTE: c_int = 66; /* Object is remote */ -pub const ENOLINK: c_int = 67; /* Link has been severed */ -pub const EADV: c_int = 68; /* Advertise error */ -pub const ESRMNT: c_int = 69; /* Srmount error */ -pub const ECOMM: c_int = 70; /* Communication error on send */ -pub const EPROTO: c_int = 71; /* Protocol error */ -pub const EMULTIHOP: c_int = 72; /* Multihop attempted */ -pub const EDOTDOT: c_int = 73; /* RFS specific error */ -pub const EBADMSG: c_int = 74; /* Not a data message */ -pub const EOVERFLOW: c_int = 75; /* Value too large for defined data type */ -pub const ENOTUNIQ: c_int = 76; /* Name not unique on network */ -pub const EBADFD: c_int = 77; /* File descriptor in bad state */ -pub const EREMCHG: c_int = 78; /* Remote address changed */ -pub const ELIBACC: c_int = 79; /* Can not access a needed shared library */ -pub const ELIBBAD: c_int = 80; /* Accessing a corrupted shared library */ -pub const ELIBSCN: c_int = 81; /* .lib section in a.out corrupted */ -pub const ELIBMAX: c_int = 82; /* Attempting to link in too many shared libraries */ -pub const ELIBEXEC: c_int = 83; /* Cannot exec a shared library directly */ -pub const EILSEQ: c_int = 84; /* Illegal byte sequence */ -pub const ERESTART: c_int = 85; /* Interrupted system call should be restarted */ -pub const ESTRPIPE: c_int = 86; /* Streams pipe error */ -pub const EUSERS: c_int = 87; /* Too many users */ -pub const ENOTSOCK: c_int = 88; /* Socket operation on non-socket */ -pub const EDESTADDRREQ: c_int = 89; /* Destination address required */ -pub const EMSGSIZE: c_int = 90; /* Message too long */ -pub const EPROTOTYPE: c_int = 91; /* Protocol wrong type for socket */ -pub const ENOPROTOOPT: c_int = 92; /* Protocol not available */ -pub const EPROTONOSUPPORT: c_int = 93; /* Protocol not supported */ -pub const ESOCKTNOSUPPORT: c_int = 94; /* Socket type not supported */ -pub const EOPNOTSUPP: c_int = 95; /* Operation not supported on transport endpoint */ -pub const EPFNOSUPPORT: c_int = 96; /* Protocol family not supported */ -pub const EAFNOSUPPORT: c_int = 97; /* Address family not supported by protocol */ -pub const EADDRINUSE: c_int = 98; /* Address already in use */ -pub const EADDRNOTAVAIL: c_int = 99; /* Cannot assign requested address */ +pub const EBFONT: c_int = 59; /* Bad font file format */ +pub const ENOSTR: c_int = 60; /* Device not a stream */ +pub const ENODATA: c_int = 61; /* No data available */ +pub const ETIME: c_int = 62; /* Timer expired */ +pub const ENOSR: c_int = 63; /* Out of streams resources */ +pub const ENONET: c_int = 64; /* Machine is not on the network */ +pub const ENOPKG: c_int = 65; /* Package not installed */ +pub const EREMOTE: c_int = 66; /* Object is remote */ +pub const ENOLINK: c_int = 67; /* Link has been severed */ +pub const EADV: c_int = 68; /* Advertise error */ +pub const ESRMNT: c_int = 69; /* Srmount error */ +pub const ECOMM: c_int = 70; /* Communication error on send */ +pub const EPROTO: c_int = 71; /* Protocol error */ +pub const EMULTIHOP: c_int = 72; /* Multihop attempted */ +pub const EDOTDOT: c_int = 73; /* RFS specific error */ +pub const EBADMSG: c_int = 74; /* Not a data message */ +pub const EOVERFLOW: c_int = 75; /* Value too large for defined data type */ +pub const ENOTUNIQ: c_int = 76; /* Name not unique on network */ +pub const EBADFD: c_int = 77; /* File descriptor in bad state */ +pub const EREMCHG: c_int = 78; /* Remote address changed */ +pub const ELIBACC: c_int = 79; /* Can not access a needed shared library */ +pub const ELIBBAD: c_int = 80; /* Accessing a corrupted shared library */ +pub const ELIBSCN: c_int = 81; /* .lib section in a.out corrupted */ +pub const ELIBMAX: c_int = 82; /* Attempting to link in too many shared libraries */ +pub const ELIBEXEC: c_int = 83; /* Cannot exec a shared library directly */ +pub const EILSEQ: c_int = 84; /* Illegal byte sequence */ +pub const ERESTART: c_int = 85; /* Interrupted system call should be restarted */ +pub const ESTRPIPE: c_int = 86; /* Streams pipe error */ +pub const EUSERS: c_int = 87; /* Too many users */ +pub const ENOTSOCK: c_int = 88; /* Socket operation on non-socket */ +pub const EDESTADDRREQ: c_int = 89; /* Destination address required */ +pub const EMSGSIZE: c_int = 90; /* Message too long */ +pub const EPROTOTYPE: c_int = 91; /* Protocol wrong type for socket */ +pub const ENOPROTOOPT: c_int = 92; /* Protocol not available */ +pub const EPROTONOSUPPORT: c_int = 93; /* Protocol not supported */ +pub const ESOCKTNOSUPPORT: c_int = 94; /* Socket type not supported */ +pub const EOPNOTSUPP: c_int = 95; /* Operation not supported on transport endpoint */ +pub const EPFNOSUPPORT: c_int = 96; /* Protocol family not supported */ +pub const EAFNOSUPPORT: c_int = 97; /* Address family not supported by protocol */ +pub const EADDRINUSE: c_int = 98; /* Address already in use */ +pub const EADDRNOTAVAIL: c_int = 99; /* Cannot assign requested address */ pub const ENETDOWN: c_int = 100; /* Network is down */ pub const ENETUNREACH: c_int = 101; /* Network is unreachable */ pub const ENETRESET: c_int = 102; /* Network dropped connection because of reset */ @@ -270,5 +270,5 @@ pub static STR_ERROR: [&'static str; 132] = [ "Key has been revoked", "Key was rejected by service", "Owner died", - "State not recoverable" + "State not recoverable", ]; diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index a327053107..5f57298db7 100644 --- a/src/platform/src/lib.rs +++ b/src/platform/src/lib.rs @@ -29,6 +29,7 @@ use core::fmt; use types::*; //TODO #[thread_local] +#[allow(non_upper_case_globals)] #[no_mangle] pub static mut errno: c_int = 0; diff --git a/src/stdio/src/lib.rs b/src/stdio/src/lib.rs index 05933a409a..7ac9d8170d 100644 --- a/src/stdio/src/lib.rs +++ b/src/stdio/src/lib.rs @@ -20,9 +20,11 @@ pub type fpos_t = off_t; pub struct FILE; +#[allow(non_upper_case_globals)] #[no_mangle] pub static mut stdout: *mut FILE = 1 as *mut FILE; +#[allow(non_upper_case_globals)] #[no_mangle] pub static mut stderr: *mut FILE = 2 as *mut FILE; diff --git a/src/stdlib/Cargo.toml b/src/stdlib/Cargo.toml index bc05d632db..4a2fb9f88e 100644 --- a/src/stdlib/Cargo.toml +++ b/src/stdlib/Cargo.toml @@ -10,3 +10,4 @@ cbindgen = { path = "../../cbindgen" } [dependencies] platform = { path = "../platform" } ralloc = { path = "../../ralloc", default-features = false } +ctype = { path = "../ctype" } diff --git a/src/stdlib/src/lib.rs b/src/stdlib/src/lib.rs index da8d3e8ad5..fd25f5b731 100644 --- a/src/stdlib/src/lib.rs +++ b/src/stdlib/src/lib.rs @@ -4,6 +4,7 @@ #![feature(core_intrinsics)] #![feature(global_allocator)] +extern crate ctype; extern crate platform; extern crate ralloc; @@ -55,14 +56,52 @@ pub extern "C" fn atof(s: *const c_char) -> c_double { unimplemented!(); } +macro_rules! dec_num_from_ascii { + ($s: expr, $t: ty) => { + unsafe { + let mut s = $s; + // Iterate past whitespace + while ctype::isspace(*s as c_int) != 0 { + s = s.offset(1); + } + + // Find out if there is a - sign + let neg_sign = match *s { + 0x2d => { + s = s.offset(1); + true + } + // '+' increment s and continue parsing + 0x2b => { + s = s.offset(1); + false + } + _ => false, + }; + + let mut n: $t = 0; + while ctype::isdigit(*s as c_int) != 0 { + n = 10 * n - (*s as $t - 0x30); + s = s.offset(1); + } + + if neg_sign { + n + } else { + -n + } + } + }; +} + #[no_mangle] pub extern "C" fn atoi(s: *const c_char) -> c_int { - unimplemented!(); + dec_num_from_ascii!(s, c_int) } #[no_mangle] pub extern "C" fn atol(s: *const c_char) -> c_long { - unimplemented!(); + dec_num_from_ascii!(s, c_long) } #[no_mangle] @@ -124,8 +163,6 @@ pub extern "C" fn erand(xsubi: [c_ushort; 3]) -> c_double { #[no_mangle] pub unsafe extern "C" fn exit(status: c_int) { - use core::mem; - for i in (0..ATEXIT_FUNCS.len()).rev() { if let Some(func) = ATEXIT_FUNCS[i] { (func)(); diff --git a/tests/.gitignore b/tests/.gitignore index dead47ff35..76cf8f3e05 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,9 +1,11 @@ /alloc /args +/atoi /brk /chdir /create /create.out +/ctype /dup /dup.out /error diff --git a/tests/Makefile b/tests/Makefile index 7d293f7246..d8abbea971 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,9 +1,11 @@ BINS=\ alloc \ + atoi \ brk \ args \ chdir \ create \ + ctype \ dup \ error \ fchdir \ diff --git a/tests/atoi.c b/tests/atoi.c new file mode 100644 index 0000000000..e9af8da95e --- /dev/null +++ b/tests/atoi.c @@ -0,0 +1,12 @@ +#include +#include + +int main(int argc, char* argv[]) { + printf("%d\n", atoi(" -42")); + printf("%d\n", atoi(" +555")); + printf("%d\n", atoi(" 1234567890 ")); + printf("%ld\n", atol(" -42")); + printf("%ld\n", atol(" +555")); + printf("%ld\n", atol(" 1234567890 ")); + return 0; +} diff --git a/tests/ctype.c b/tests/ctype.c new file mode 100644 index 0000000000..a8e9dc10e1 --- /dev/null +++ b/tests/ctype.c @@ -0,0 +1,46 @@ +#include +#include + +struct test_case { + char c; + int isalnum; + int isalpha; + int isascii; + int isdigit; + int islower; + int isspace; + int isupper; +} test_cases[] = { + { 'A', 1, 1, 1, 0, 0, 0, 1}, + { 'z', 1, 1, 1, 0, 1, 0, 0}, + { ' ', 0, 0, 1, 0, 0, 1, 0}, + { '1', 1, 0, 1, 1, 0, 0, 0}, + { '9', 1, 0, 1, 1, 0, 0, 0}, + {0x80, 0, 0, 0, 0, 0, 0, 0} +}; +size_t num_test_cases = sizeof(test_cases)/sizeof(struct test_case); + +#define CHECK_TEST(tc, fn, retval) \ + if (fn(tc.c) != tc.fn) { \ + retval = -1; \ + printf("Unexpected result: " #fn "('%c') != %d\n", tc.c, tc.fn); \ + } +int main(int argc, char* argv[]) { + int retval = 0; + for(int i = 0; i < num_test_cases; ++i) { + struct test_case tc = test_cases[i]; + CHECK_TEST(tc, isalnum, retval); + CHECK_TEST(tc, isalpha, retval); + CHECK_TEST(tc, isascii, retval); + CHECK_TEST(tc, isdigit, retval); + CHECK_TEST(tc, islower, retval); + CHECK_TEST(tc, isspace, retval); + CHECK_TEST(tc, isupper, retval); + } + if (!retval) { + printf("Success: %d\n", retval); + } else { + printf("Failure: %d\n", retval); + } + return retval; +}