mirror of
https://github.com/Noratrieb/libuwuc.git
synced 2026-01-14 11:45:05 +01:00
strtol
This commit is contained in:
parent
9bfadd77d9
commit
84e6db0684
8 changed files with 252 additions and 13 deletions
1
hello.c
1
hello.c
|
|
@ -1,5 +1,4 @@
|
|||
#include<stdio.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int result = printf("Hello, world!\n");
|
||||
if (result != 15) {
|
||||
|
|
|
|||
51
libuwuc/src/error.rs
Normal file
51
libuwuc/src/error.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
use core::{cell::UnsafeCell, ptr::addr_of};
|
||||
|
||||
#[thread_local]
|
||||
static ERRNO: UnsafeCell<i32> = UnsafeCell::new(0);
|
||||
|
||||
pub fn errno_location() -> *const i32 {
|
||||
addr_of!(ERRNO).cast()
|
||||
}
|
||||
|
||||
pub fn errno() -> i32 {
|
||||
unsafe { *ERRNO.get() }
|
||||
}
|
||||
|
||||
pub fn set_errno(errno: i32) {
|
||||
unsafe { ERRNO.get().write(errno) }
|
||||
}
|
||||
|
||||
pub const EPERM: i32 = 1; /* Operation not permitted */
|
||||
pub const ENOENT: i32 = 2; /* No such file or directory */
|
||||
pub const ESRCH: i32 = 3; /* No such process */
|
||||
pub const EINTR: i32 = 4; /* Interrupted system call */
|
||||
pub const EIO: i32 = 5; /* I/O error */
|
||||
pub const ENXIO: i32 = 6; /* No such device or address */
|
||||
pub const E2BIG: i32 = 7; /* Argument list too long */
|
||||
pub const ENOEXEC: i32 = 8; /* Exec format error */
|
||||
pub const EBADF: i32 = 9; /* Bad file number */
|
||||
pub const ECHILD: i32 = 10; /* No child processes */
|
||||
pub const EAGAIN: i32 = 11; /* Try again */
|
||||
pub const ENOMEM: i32 = 12; /* Out of memory */
|
||||
pub const EACCES: i32 = 13; /* Permission denied */
|
||||
pub const EFAULT: i32 = 14; /* Bad address */
|
||||
pub const ENOTBLK: i32 = 15; /* Block device required */
|
||||
pub const EBUSY: i32 = 16; /* Device or resource busy */
|
||||
pub const EEXIST: i32 = 17; /* File exists */
|
||||
pub const EXDEV: i32 = 18; /* Cross-device link */
|
||||
pub const ENODEV: i32 = 19; /* No such device */
|
||||
pub const ENOTDIR: i32 = 20; /* Not a directory */
|
||||
pub const EISDIR: i32 = 21; /* Is a directory */
|
||||
pub const EINVAL: i32 = 22; /* Invalid argument */
|
||||
pub const ENFILE: i32 = 23; /* File table overflow */
|
||||
pub const EMFILE: i32 = 24; /* Too many open files */
|
||||
pub const ENOTTY: i32 = 25; /* Not a typewriter */
|
||||
pub const ETXTBSY: i32 = 26; /* Text file busy */
|
||||
pub const EFBIG: i32 = 27; /* File too large */
|
||||
pub const ENOSPC: i32 = 28; /* No space left on device */
|
||||
pub const ESPIPE: i32 = 29; /* Illegal seek */
|
||||
pub const EROFS: i32 = 30; /* Read-only file system */
|
||||
pub const EMLINK: i32 = 31; /* Too many links */
|
||||
pub const EPIPE: i32 = 32; /* Broken pipe */
|
||||
pub const EDOM: i32 = 33; /* Math argument out of domain of func */
|
||||
pub const ERANGE: i32 = 34; /* Math result not representable */
|
||||
|
|
@ -3,9 +3,9 @@ use core::ffi::c_int;
|
|||
pub mod parse;
|
||||
pub mod printf;
|
||||
|
||||
pub fn is_space(c: c_int) -> c_int {
|
||||
pub fn is_space(c: c_int) -> bool {
|
||||
// todo: is this correct?
|
||||
char::from_u32(c as _)
|
||||
.map(char::is_whitespace)
|
||||
.unwrap_or_default() as _
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,161 @@
|
|||
use core::ffi::{c_int, c_long};
|
||||
|
||||
use crate::utils::SharedThinCstr;
|
||||
use crate::{
|
||||
error::{set_errno, EINVAL},
|
||||
utils::SharedThinCstr,
|
||||
};
|
||||
|
||||
pub unsafe fn parse_long<'a>(
|
||||
pub fn parse_long<'a>(
|
||||
str: SharedThinCstr<'a>,
|
||||
endptr: *mut SharedThinCstr<'a>,
|
||||
endptr: Option<&mut Option<SharedThinCstr<'a>>>,
|
||||
base: c_int,
|
||||
) -> c_long {
|
||||
let mut cur = str;
|
||||
while cur
|
||||
.first()
|
||||
.map(|c| super::is_space(c as _) == 1)
|
||||
.unwrap_or(false)
|
||||
{}
|
||||
if base != 10 {
|
||||
todo!();
|
||||
}
|
||||
let mut chars = str.into_iter().enumerate().peekable();
|
||||
|
||||
0
|
||||
while chars
|
||||
.peek()
|
||||
.map(|&(_, c)| super::is_space(c as _))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
chars.next();
|
||||
}
|
||||
|
||||
let mut negate = false;
|
||||
let mut acc: i64 = 0;
|
||||
|
||||
let write_end = |pos: usize| {
|
||||
if let Some(endptr) = endptr {
|
||||
*endptr = Some(unsafe { str.add(pos) });
|
||||
}
|
||||
};
|
||||
|
||||
let mut last_pos;
|
||||
|
||||
let c = chars.peek();
|
||||
match c {
|
||||
Some((pos, b'+')) => {
|
||||
last_pos = *pos;
|
||||
chars.next();
|
||||
}
|
||||
Some((pos, b'-')) => {
|
||||
last_pos = *pos;
|
||||
chars.next();
|
||||
negate = true
|
||||
}
|
||||
Some((_, c)) if !c.is_ascii_digit() => {
|
||||
write_end(0);
|
||||
set_errno(EINVAL);
|
||||
return 0;
|
||||
}
|
||||
None => {
|
||||
write_end(0);
|
||||
set_errno(EINVAL);
|
||||
return 0;
|
||||
}
|
||||
Some((pos, _)) => {
|
||||
last_pos = *pos;
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match chars.next() {
|
||||
Some((pos, c)) if c.is_ascii_digit() => {
|
||||
last_pos = pos;
|
||||
let n = c - b'0';
|
||||
acc *= 10;
|
||||
if negate {
|
||||
acc -= n as i64;
|
||||
} else {
|
||||
acc += n as i64;
|
||||
}
|
||||
}
|
||||
Some((pos, _)) => {
|
||||
write_end(pos);
|
||||
break;
|
||||
}
|
||||
None => {
|
||||
write_end(last_pos + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acc
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{cstr, utils::SharedThinCstr};
|
||||
|
||||
fn test_strtol(str: SharedThinCstr<'_>, expected: i64, base: i32, parsed_len: usize) {
|
||||
let mut end = None;
|
||||
let result = super::parse_long(str, Some(&mut end), base);
|
||||
assert_eq!(result, expected);
|
||||
let end = end.unwrap();
|
||||
let read = end.as_raw() as usize - str.as_raw() as usize;
|
||||
assert_eq!(read, parsed_len);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_zero() {
|
||||
test_strtol(cstr!("0"), 0, 10, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_ten() {
|
||||
test_strtol(cstr!("10"), 10, 10, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_eleven() {
|
||||
test_strtol(cstr!("11"), 11, 10, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn negative_zero() {
|
||||
test_strtol(cstr!("-0"), 0, 10, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn negative_ten() {
|
||||
test_strtol(cstr!("-10"), -10, 10, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn negative_eleven() {
|
||||
test_strtol(cstr!("-11"), -11, 10, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_leading_whitespace() {
|
||||
test_strtol(cstr!("\t 1"), 1, 10, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_trailing_garbage_one() {
|
||||
test_strtol(cstr!("3uwu"), 3, 10, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_trailing_garbage_two() {
|
||||
test_strtol(cstr!("32uwu"), 32, 10, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_trailing_garbage_many() {
|
||||
test_strtol(cstr!("12345uwu"), 12345, 10, 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_long_max() {
|
||||
test_strtol(cstr!("9223372036854775807"), i64::MAX, 10, 19);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn l_long_min() {
|
||||
test_strtol(cstr!("-9223372036854775808"), i64::MIN, 10, 20);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#![no_std]
|
||||
#![feature(c_variadic)]
|
||||
#![feature(thread_local)]
|
||||
|
||||
#![warn(unreachable_pub)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
|
@ -9,6 +11,7 @@ extern crate std;
|
|||
|
||||
pub mod alloc;
|
||||
pub mod env;
|
||||
pub mod error;
|
||||
pub mod fmt;
|
||||
pub mod io;
|
||||
pub mod mem;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ macro_rules! syscall {
|
|||
"syscall",
|
||||
in("rdi") $number,
|
||||
lateout("rax") out,
|
||||
// rcx and r11 are clobbered https://github.com/torvalds/linux/blob/3b517966c5616ac011081153482a5ba0e91b17ff/tools/include/nolibc/arch-x86_64.h#L19
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
);
|
||||
out
|
||||
}};
|
||||
|
|
@ -22,6 +25,9 @@ macro_rules! syscall {
|
|||
in("rax") $number,
|
||||
in("rdi") $arg1,
|
||||
lateout("rax") out,
|
||||
// rcx and r11 are clobbered
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
);
|
||||
out
|
||||
}};
|
||||
|
|
@ -33,6 +39,9 @@ macro_rules! syscall {
|
|||
in("rdi") $arg1,
|
||||
in("rsi") $arg2,
|
||||
lateout("rax") out,
|
||||
// rcx and r11 are clobbered
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
);
|
||||
out
|
||||
}};
|
||||
|
|
@ -45,6 +54,9 @@ macro_rules! syscall {
|
|||
in("rsi") $arg2,
|
||||
in("rdx") $arg3,
|
||||
lateout("rax") out,
|
||||
// rcx and r11 are clobbered
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
);
|
||||
out
|
||||
}};
|
||||
|
|
@ -58,6 +70,9 @@ macro_rules! syscall {
|
|||
in("rdx") $arg3,
|
||||
in("r10") $arg4,
|
||||
lateout("rax") out,
|
||||
// rcx and r11 are clobbered
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
);
|
||||
out
|
||||
}};
|
||||
|
|
@ -72,6 +87,9 @@ macro_rules! syscall {
|
|||
in("r10") $arg4,
|
||||
in("r8") $arg5,
|
||||
lateout("rax") out,
|
||||
// rcx and r11 are clobbered
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
);
|
||||
out
|
||||
}};
|
||||
|
|
@ -87,6 +105,9 @@ macro_rules! syscall {
|
|||
in("r8") $arg5,
|
||||
in("r9") $arg6,
|
||||
lateout("rax") out,
|
||||
// rcx and r11 are clobbered
|
||||
out("rcx") _,
|
||||
out("r11") _,
|
||||
);
|
||||
out
|
||||
}};
|
||||
|
|
|
|||
|
|
@ -5,3 +5,8 @@ pub extern "C" fn __stack_chk_fail() -> ! {
|
|||
libuwuc::start::abort();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __errno_location() -> *const i32 {
|
||||
libuwuc::error::errno_location()
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
use core::ffi::{c_int, c_long};
|
||||
|
||||
use libuwuc::utils::SharedThinCstr;
|
||||
|
||||
#[no_mangle]
|
||||
|
|
@ -15,6 +17,21 @@ pub unsafe extern "C" fn exit(code: i32) -> ! {
|
|||
libuwuc::start::exit(code as i64 as _)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strtol(nptr: *const u8, endptr: *mut *const u8, base: c_int) -> c_long {
|
||||
let str = SharedThinCstr::from_raw(nptr);
|
||||
libuwuc::fmt::parse::parse_long(
|
||||
str,
|
||||
core::mem::transmute::<*mut *const u8, Option<&mut Option<SharedThinCstr<'_>>>>(endptr),
|
||||
base,
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strtoll(nptr: *const u8, endptr: *mut *const u8, base: c_int) -> c_long {
|
||||
strtol(nptr, endptr, base)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getenv(name: *const u8) -> *const u8 {
|
||||
libuwuc::env::getenv(SharedThinCstr::from_raw(name))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue