start strtok

This commit is contained in:
nora 2023-10-08 20:47:23 +02:00
parent 4d4af78afe
commit dfdf45b5c7
17 changed files with 158 additions and 76 deletions

View file

@ -1,17 +1,17 @@
use core::{ffi::CStr, ptr::NonNull}; use core::{ffi::CStr, ptr::NonNull};
use crate::{println, utils::SharedThinCstr}; use crate::{println, utils::CStrRef};
mod global { mod global {
use core::{cell::UnsafeCell, ptr::NonNull}; use core::{cell::UnsafeCell, ptr::NonNull};
use crate::utils::{SharedThinCstr, SyncUnsafeCell}; use crate::utils::{CStrRef, SyncUnsafeCell};
use super::EnvP; use super::EnvP;
static ENVP: SyncUnsafeCell<EnvP> = SyncUnsafeCell(UnsafeCell::new(EnvP(None))); static ENVP: SyncUnsafeCell<EnvP> = SyncUnsafeCell(UnsafeCell::new(EnvP(None)));
pub(super) unsafe fn init(envp: *mut Option<SharedThinCstr<'static>>) { pub(super) unsafe fn init(envp: *mut Option<CStrRef<'static>>) {
assert!((*ENVP.0.get()).0.is_none()); assert!((*ENVP.0.get()).0.is_none());
*ENVP.0.get() = EnvP(Some(NonNull::new(envp).unwrap())); *ENVP.0.get() = EnvP(Some(NonNull::new(envp).unwrap()));
} }
@ -23,21 +23,21 @@ mod global {
} }
} }
pub(crate) unsafe fn init(envp: *mut Option<SharedThinCstr<'static>>) { pub(crate) unsafe fn init(envp: *mut Option<CStrRef<'static>>) {
global::init(envp); global::init(envp);
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct EnvP(Option<NonNull<Option<SharedThinCstr<'static>>>>); struct EnvP(Option<NonNull<Option<CStrRef<'static>>>>);
unsafe impl Sync for EnvP {} unsafe impl Sync for EnvP {}
impl Iterator for EnvP { impl Iterator for EnvP {
type Item = SharedThinCstr<'static>; type Item = CStrRef<'static>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
unsafe { unsafe {
let value: Option<SharedThinCstr<'static>> = self.0.unwrap().as_ptr().read(); let value: Option<CStrRef<'static>> = self.0.unwrap().as_ptr().read();
value.map(|value| { value.map(|value| {
self.0 = Some(NonNull::new_unchecked(self.0.unwrap().as_ptr().add(1))); self.0 = Some(NonNull::new_unchecked(self.0.unwrap().as_ptr().add(1)));
@ -57,11 +57,11 @@ pub(crate) fn debug_env() {
println!("end vars"); println!("end vars");
} }
pub fn getenv(name: SharedThinCstr<'_>) -> Option<SharedThinCstr<'static>> { pub fn getenv(name: CStrRef<'_>) -> Option<CStrRef<'static>> {
getenv_inner(global::get(), name) getenv_inner(global::get(), name)
} }
fn getenv_inner(mut envp: EnvP, name: SharedThinCstr<'_>) -> Option<SharedThinCstr<'static>> { fn getenv_inner(mut envp: EnvP, name: CStrRef<'_>) -> Option<CStrRef<'static>> {
let mut eq_idx = 0; let mut eq_idx = 0;
envp.find(|env| { envp.find(|env| {
// Find ENV // Find ENV
@ -99,7 +99,7 @@ mod tests {
use std::string::ToString; use std::string::ToString;
use std::{ffi::CString, vec::Vec}; use std::{ffi::CString, vec::Vec};
use crate::utils::{cstr, SharedThinCstr}; use crate::utils::{cstr, CStrRef};
use super::EnvP; use super::EnvP;
@ -109,9 +109,9 @@ mod tests {
.map(|s| CString::new(s.to_string()).unwrap()) .map(|s| CString::new(s.to_string()).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut envs: Vec<Option<SharedThinCstr<'static>>> = cstrs let mut envs: Vec<Option<CStrRef<'static>>> = cstrs
.iter() .iter()
.map(|cstr| unsafe { Some(SharedThinCstr::from_raw(cstr.as_ptr() as _)) }) .map(|cstr| unsafe { Some(CStrRef::from_raw(cstr.as_ptr() as _)) })
.collect(); .collect();
envs.push(None); envs.push(None);

View file

@ -1,10 +1,10 @@
use core::ffi::{c_int, c_long}; use core::ffi::{c_int, c_long};
use crate::{error::Error, utils::SharedThinCstr}; use crate::{error::Error, utils::CStrRef};
pub fn parse_long<'a>( pub fn parse_long<'a>(
str: SharedThinCstr<'a>, str: CStrRef<'a>,
endptr: Option<&mut Option<SharedThinCstr<'a>>>, endptr: Option<&mut Option<CStrRef<'a>>>,
base: c_int, base: c_int,
) -> Result<c_long, Error> { ) -> Result<c_long, Error> {
if base != 10 { if base != 10 {
@ -83,9 +83,9 @@ pub fn parse_long<'a>(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{cstr, utils::SharedThinCstr}; use crate::{cstr, utils::CStrRef};
fn test_strtol(str: SharedThinCstr<'_>, expected: i64, base: i32, parsed_len: usize) { fn test_strtol(str: CStrRef<'_>, expected: i64, base: i32, parsed_len: usize) {
let mut end = None; let mut end = None;
let result = super::parse_long(str, Some(&mut end), base).unwrap(); let result = super::parse_long(str, Some(&mut end), base).unwrap();
assert_eq!(result, expected); assert_eq!(result, expected);

View file

@ -1,10 +1,10 @@
use core::ffi::VaList; use core::ffi::VaList;
use crate::{io::IoWrite, utils::SharedThinCstr, error::Error}; use crate::{io::IoWrite, utils::CStrRef, error::Error};
pub unsafe fn printf_generic( pub unsafe fn printf_generic(
mut sink: impl IoWrite, mut sink: impl IoWrite,
format: SharedThinCstr<'_>, format: CStrRef<'_>,
mut args: VaList<'_, '_>, mut args: VaList<'_, '_>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut chars = format.into_iter(); let mut chars = format.into_iter();
@ -47,11 +47,11 @@ mod tests {
use std::string::String; use std::string::String;
use std::vec::Vec; use std::vec::Vec;
use crate::utils::{cstr, SharedThinCstr}; use crate::utils::{cstr, CStrRef};
use super::printf_generic; use super::printf_generic;
unsafe extern "C" fn test_printf(expected: &str, fmt: SharedThinCstr<'_>, mut args: ...) { unsafe extern "C" fn test_printf(expected: &str, fmt: CStrRef<'_>, mut args: ...) {
let mut sink = Vec::new(); let mut sink = Vec::new();
printf_generic(&mut sink, fmt, args.as_va_list()).unwrap(); printf_generic(&mut sink, fmt, args.as_va_list()).unwrap();

View file

@ -1,17 +1,17 @@
use crate::{ use crate::{
error::{Error, SyscallResultExt}, error::{Error, SyscallResultExt},
utils::SharedThinCstr, utils::CStrRef,
}; };
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
pub struct Fd(pub i32); pub struct Fd(pub i32);
pub fn open(arg: SharedThinCstr<'_>, flags: i32) -> Result<Fd, Error> { pub fn open(arg: CStrRef<'_>, flags: i32) -> Result<Fd, Error> {
sys_open(arg, flags) sys_open(arg, flags)
} }
pub fn sys_open(arg: SharedThinCstr<'_>, flags: i32) -> Result<Fd, Error> { pub fn sys_open(arg: CStrRef<'_>, flags: i32) -> Result<Fd, Error> {
unsafe { unsafe {
crate::syscall::syscall!(crate::syscall::SYS_OPEN, arg.as_raw(), flags).syscall_resultify() crate::syscall::syscall!(crate::syscall::SYS_OPEN, arg.as_raw(), flags).syscall_resultify()
} }

View file

@ -1,4 +1,4 @@
use crate::{io::fd, utils::SharedThinCstr}; use crate::{io::fd, utils::CStrRef};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum OpenMode { pub enum OpenMode {
@ -22,7 +22,7 @@ impl OpenMode {
} }
} }
pub fn parse(str: SharedThinCstr<'_>) -> Result<OpenMode, &'static str> { pub fn parse(str: CStrRef<'_>) -> Result<OpenMode, &'static str> {
let mut buf = [0; 2]; let mut buf = [0; 2];
let mut i = 0; let mut i = 0;

View file

@ -4,7 +4,7 @@ use crate::{
alloc, alloc,
error::Error, error::Error,
io::{fd, stream::file::OpenMode}, io::{fd, stream::file::OpenMode},
utils::SharedThinCstr, utils::CStrRef,
}; };
use super::{fd::Fd, IoWrite, EOF}; use super::{fd::Fd, IoWrite, EOF};
@ -32,8 +32,8 @@ impl IoWrite for &FileStream {
} }
pub unsafe fn fopen<'a>( pub unsafe fn fopen<'a>(
pathname: SharedThinCstr<'_>, pathname: CStrRef<'_>,
mode: SharedThinCstr<'_>, mode: CStrRef<'_>,
) -> Result<&'a FileStream, Error> { ) -> Result<&'a FileStream, Error> {
let Ok(mode) = OpenMode::parse(mode) else { let Ok(mode) = OpenMode::parse(mode) else {
return Err(Error::INVAL); return Err(Error::INVAL);

View file

@ -16,6 +16,7 @@ pub mod io;
pub mod mem; pub mod mem;
pub mod misc; pub mod misc;
pub mod start; pub mod start;
pub mod string;
mod stubs; mod stubs;
mod sys; mod sys;
pub mod utils; pub mod utils;

View file

@ -1,4 +1,4 @@
use crate::utils::SharedThinCstr; use crate::utils::CStrRef;
#[inline] #[inline]
pub unsafe fn memset(ptr: *mut u8, constant: u8, len: usize) { pub unsafe fn memset(ptr: *mut u8, constant: u8, len: usize) {
@ -59,13 +59,13 @@ pub unsafe fn memcmp(s1: *const u8, s2: *const u8, size: usize) -> i32 {
} }
#[inline] #[inline]
pub unsafe fn strcmp(s1: SharedThinCstr<'_>, s2: SharedThinCstr<'_>) -> i32 { pub unsafe fn strcmp(s1: CStrRef<'_>, s2: CStrRef<'_>) -> i32 {
s1.into_iter().cmp(s2) as i8 as i32 s1.into_iter().cmp(s2) as i8 as i32
} }
// This technically violates the safety precondition of SharedThinCstr but that's fine, we're careful. // This technically violates the safety precondition of SharedThinCstr but that's fine, we're careful.
#[inline] #[inline]
pub unsafe fn strncmp(s1: SharedThinCstr<'_>, s2: SharedThinCstr<'_>, size: usize) -> i32 { pub unsafe fn strncmp(s1: CStrRef<'_>, s2: CStrRef<'_>, size: usize) -> i32 {
s1.into_iter().take(size).cmp(s2.into_iter().take(size)) as i8 as i32 s1.into_iter().take(size).cmp(s2.into_iter().take(size)) as i8 as i32
} }
@ -81,7 +81,7 @@ pub unsafe fn strlen(mut s: *const u8) -> usize {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{cstr, utils::SharedThinCstr}; use crate::{cstr, utils::CStrRef};
#[test] #[test]
fn memcpy_null() { fn memcpy_null() {
@ -270,8 +270,8 @@ mod tests {
#[test] #[test]
fn strncmp_no_null_term() { fn strncmp_no_null_term() {
// Note: this is violating the safety invariant of SharedThinCstr but thats fine, we're careful. // Note: this is violating the safety invariant of SharedThinCstr but thats fine, we're careful.
let a = unsafe { SharedThinCstr::from_raw(b"0000".as_ptr()) }; let a = unsafe { CStrRef::from_raw(b"0000".as_ptr()) };
let b = unsafe { SharedThinCstr::from_raw(b"0001".as_ptr()) }; let b = unsafe { CStrRef::from_raw(b"0001".as_ptr()) };
let result = unsafe { super::strncmp(a, b, 4) }; let result = unsafe { super::strncmp(a, b, 4) };
assert_eq!(result, -1); assert_eq!(result, -1);
} }

View file

@ -1,11 +1,11 @@
use crate::utils::SharedThinCstr; use crate::utils::CStrRef;
use core::fmt::Write; use core::fmt::Write;
pub fn assert_failed( pub fn assert_failed(
assertion: SharedThinCstr<'_>, assertion: CStrRef<'_>,
file: SharedThinCstr<'_>, file: CStrRef<'_>,
line: u32, line: u32,
_function: Option<SharedThinCstr<'_>>, _function: Option<CStrRef<'_>>,
) -> ! { ) -> ! {
let _ = writeln!( let _ = writeln!(
crate::io::Printer(crate::io::STDERR), crate::io::Printer(crate::io::STDERR),

View file

@ -1,13 +1,13 @@
use core::ffi::{c_char, c_int}; use core::ffi::{c_char, c_int};
use crate::utils::SharedThinCstr; use crate::utils::CStrRef;
/// The entrypoint of the program. /// The entrypoint of the program.
/// This is called by a bit of assembly handling architecture-specific _start. /// This is called by a bit of assembly handling architecture-specific _start.
pub(crate) unsafe extern "C" fn start(rsp: u64) -> ! { pub(crate) unsafe extern "C" fn start(rsp: u64) -> ! {
let argc = (rsp as *const u64).read(); let argc = (rsp as *const u64).read();
let argv = (rsp + 8) as *const *const c_char; let argv = (rsp + 8) as *const *const c_char;
let envp = (8 + 8 * argc + rsp + 8) as *mut Option<SharedThinCstr<'static>>; let envp = (8 + 8 * argc + rsp + 8) as *mut Option<CStrRef<'static>>;
crate::env::init(envp); crate::env::init(envp);

59
libuwuc/src/string.rs Normal file
View file

@ -0,0 +1,59 @@
use crate::utils::CStrRef;
pub unsafe fn strtok(str: *mut u8, delim: CStrRef<'_>, saveptr: *mut *mut u8) -> *const u8 {
if !str.is_null() {
saveptr.write(str);
}
let start = saveptr.read();
let mut end = saveptr.read();
while end.read() != 0 || !delim.into_iter().any(|c| c == end.read()) {
end = end.add(1);
}
end.write(0);
if start == end {
core::ptr::null()
} else {
start
}
}
#[cfg(test)]
mod tests {
extern crate std;
use std::borrow::ToOwned;
use std::vec::Vec;
use crate::{cstr, utils::CStrRef};
fn test_strtok(string: &str, delim: CStrRef<'_>, expected: &[CStrRef<'_>]) {
unsafe {
let mut str = string.to_owned().into_bytes();
str.push(0);
let mut saveptr = core::ptr::null_mut();
let mut out = Vec::new();
loop {
let s = super::strtok(str.as_mut_ptr(), delim, &mut saveptr);
if s.is_null() {
break;
}
out.push(CStrRef::from_raw(s));
}
assert_eq!(out, expected);
}
}
#[test]
fn strtok_manpage_example() {
test_strtok(
"a/bbb///cc;xxxx:yyy:",
cstr!(":;"),
&[cstr!("a/bbbb///cc"), cstr!("xxx"), cstr!("yyy")],
);
}
}

View file

@ -2,13 +2,13 @@ use core::{cell::UnsafeCell, ffi::CStr, fmt::Debug, marker::PhantomData, ptr::No
#[repr(transparent)] #[repr(transparent)]
#[derive(Default)] #[derive(Default)]
pub(crate) struct SyncUnsafeCell<T>(pub(crate) UnsafeCell<T>); pub struct SyncUnsafeCell<T>(pub UnsafeCell<T>);
unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {} unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
pub struct SharedThinCstr<'a>(NonNull<u8>, PhantomData<&'a CStr>); pub struct CStrRef<'a>(NonNull<u8>, PhantomData<&'a CStr>);
#[macro_export] #[macro_export]
macro_rules! cstr { macro_rules! cstr {
@ -16,14 +16,14 @@ macro_rules! cstr {
let s = concat!($value, "\0"); let s = concat!($value, "\0");
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { unsafe {
$crate::utils::SharedThinCstr::from_raw(s.as_ptr().cast()) $crate::utils::CStrRef::from_raw(s.as_ptr().cast())
} }
}}; }};
} }
pub use cstr; pub use cstr;
impl<'a> SharedThinCstr<'a> { impl<'a> CStrRef<'a> {
pub unsafe fn from_raw(ptr: *const u8) -> Self { pub unsafe fn from_raw(ptr: *const u8) -> Self {
Self(NonNull::new_unchecked(ptr as *mut u8), PhantomData) Self(NonNull::new_unchecked(ptr as *mut u8), PhantomData)
} }
@ -50,7 +50,7 @@ impl<'a> SharedThinCstr<'a> {
} }
} }
impl<'a> IntoIterator for SharedThinCstr<'a> { impl<'a> IntoIterator for CStrRef<'a> {
type Item = u8; type Item = u8;
type IntoIter = CStrIter<'a>; type IntoIter = CStrIter<'a>;
@ -60,7 +60,7 @@ impl<'a> IntoIterator for SharedThinCstr<'a> {
} }
} }
pub struct CStrIter<'a>(SharedThinCstr<'a>); pub struct CStrIter<'a>(CStrRef<'a>);
impl<'a> Iterator for CStrIter<'a> { impl<'a> Iterator for CStrIter<'a> {
type Item = u8; type Item = u8;
@ -78,10 +78,10 @@ impl<'a> Iterator for CStrIter<'a> {
} }
} }
unsafe impl<'a> Send for SharedThinCstr<'a> {} unsafe impl<'a> Send for CStrRef<'a> {}
unsafe impl<'a> Sync for SharedThinCstr<'a> {} unsafe impl<'a> Sync for CStrRef<'a> {}
impl<'a> Debug for SharedThinCstr<'a> { impl<'a> Debug for CStrRef<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let str = <&CStr>::from(*self).to_str(); let str = <&CStr>::from(*self).to_str();
match str { match str {
@ -91,22 +91,22 @@ impl<'a> Debug for SharedThinCstr<'a> {
} }
} }
impl<'a> From<SharedThinCstr<'a>> for &'a CStr { impl<'a> From<CStrRef<'a>> for &'a CStr {
fn from(value: SharedThinCstr<'a>) -> Self { fn from(value: CStrRef<'a>) -> Self {
unsafe { CStr::from_ptr(value.0.as_ptr().cast()) } unsafe { CStr::from_ptr(value.0.as_ptr().cast()) }
} }
} }
impl<'a> PartialEq for SharedThinCstr<'a> { impl<'a> PartialEq for CStrRef<'a> {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.into_iter().eq(*other) self.into_iter().eq(*other)
} }
} }
impl<'a> Eq for SharedThinCstr<'a> {} impl<'a> Eq for CStrRef<'a> {}
#[repr(transparent)] #[repr(transparent)]
pub(crate) struct SyncPtr<T>(pub(crate) *mut T); pub struct SyncPtr<T>(pub *mut T);
unsafe impl<T> Send for SyncPtr<T> {} unsafe impl<T> Send for SyncPtr<T> {}
unsafe impl<T> Sync for SyncPtr<T> {} unsafe impl<T> Sync for SyncPtr<T> {}

View file

@ -1,6 +1,6 @@
use libuwuc::{error::IntoOkOrErrno, utils::SharedThinCstr, io::fd::Fd}; use libuwuc::{error::IntoOkOrErrno, utils::CStrRef, io::fd::Fd};
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn open(path: SharedThinCstr<'_>, flags: i32) -> Fd { pub unsafe extern "C" fn open(path: CStrRef<'_>, flags: i32) -> Fd {
libuwuc::io::fd::open(path, flags).into_ok_or_errno() libuwuc::io::fd::open(path, flags).into_ok_or_errno()
} }

View file

@ -1,6 +1,6 @@
use core::ffi::c_uint; use core::ffi::c_uint;
use libuwuc::utils::SharedThinCstr; use libuwuc::utils::CStrRef;
#[no_mangle] #[no_mangle]
pub extern "C" fn __stack_chk_fail() -> ! { pub extern "C" fn __stack_chk_fail() -> ! {
@ -23,9 +23,9 @@ pub unsafe extern "C" fn __assert_fail(
function: *const u8, function: *const u8,
) -> ! { ) -> ! {
libuwuc::misc::assert_failed( libuwuc::misc::assert_failed(
SharedThinCstr::from_raw(assertion), CStrRef::from_raw(assertion),
SharedThinCstr::from_raw(file), CStrRef::from_raw(file),
line, line,
SharedThinCstr::from_nullable(function), CStrRef::from_nullable(function),
) )
} }

View file

@ -3,7 +3,7 @@ use core::ffi::{c_char, c_int};
use libuwuc::{ use libuwuc::{
error::IntoOkOrErrno, error::IntoOkOrErrno,
io::{stream::FileStream, traits::WriteCounter, STDERR, STDIN, STDOUT}, io::{stream::FileStream, traits::WriteCounter, STDERR, STDIN, STDOUT},
utils::SharedThinCstr, utils::CStrRef,
}; };
#[no_mangle] #[no_mangle]
@ -24,7 +24,7 @@ pub unsafe extern "C" fn __printf_chk(_flag: c_int, format: *const u8, mut args:
let result = libuwuc::fmt::printf::printf_generic( let result = libuwuc::fmt::printf::printf_generic(
&mut sink, &mut sink,
SharedThinCstr::from_raw(format), CStrRef::from_raw(format),
args.as_va_list(), args.as_va_list(),
); );
@ -37,7 +37,7 @@ pub unsafe extern "C" fn printf(format: *const u8, mut args: ...) -> c_int {
let result = libuwuc::fmt::printf::printf_generic( let result = libuwuc::fmt::printf::printf_generic(
&mut sink, &mut sink,
SharedThinCstr::from_raw(format), CStrRef::from_raw(format),
args.as_va_list(), args.as_va_list(),
); );
@ -55,7 +55,7 @@ pub unsafe extern "C" fn __fprintf_chk(
let result = libuwuc::fmt::printf::printf_generic( let result = libuwuc::fmt::printf::printf_generic(
&mut sink, &mut sink,
SharedThinCstr::from_raw(format), CStrRef::from_raw(format),
args.as_va_list(), args.as_va_list(),
); );
@ -68,7 +68,7 @@ pub unsafe extern "C" fn fprintf(file: &FileStream, format: *const u8, mut args:
let result = libuwuc::fmt::printf::printf_generic( let result = libuwuc::fmt::printf::printf_generic(
&mut sink, &mut sink,
SharedThinCstr::from_raw(format), CStrRef::from_raw(format),
args.as_va_list(), args.as_va_list(),
); );
@ -86,8 +86,8 @@ pub static stderr: &FileStream = &FileStream::from_raw_fd(STDERR);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn fopen<'a>( pub unsafe extern "C" fn fopen<'a>(
pathname: SharedThinCstr<'_>, pathname: CStrRef<'_>,
mode: SharedThinCstr<'_>, mode: CStrRef<'_>,
) -> Option<&'a FileStream> { ) -> Option<&'a FileStream> {
libuwuc::io::stream::fopen(pathname, mode) libuwuc::io::stream::fopen(pathname, mode)
.map_err(|err| libuwuc::error::set_errno(err.0)) .map_err(|err| libuwuc::error::set_errno(err.0))

View file

@ -1,6 +1,6 @@
use core::ffi::{c_int, c_long}; use core::ffi::{c_int, c_long};
use libuwuc::{error::IntoOkOrErrno, utils::SharedThinCstr}; use libuwuc::{error::IntoOkOrErrno, utils::CStrRef};
// Allocation functions // Allocation functions
@ -35,10 +35,10 @@ pub unsafe extern "C" fn reallocarray(ptr: *mut u8, nmemb: usize, size: usize) -
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn strtol(nptr: *const u8, endptr: *mut *const u8, base: c_int) -> c_long { pub unsafe extern "C" fn strtol(nptr: *const u8, endptr: *mut *const u8, base: c_int) -> c_long {
let str = SharedThinCstr::from_raw(nptr); let str = CStrRef::from_raw(nptr);
libuwuc::fmt::parse::parse_long( libuwuc::fmt::parse::parse_long(
str, str,
core::mem::transmute::<*mut *const u8, Option<&mut Option<SharedThinCstr<'_>>>>(endptr), core::mem::transmute::<*mut *const u8, Option<&mut Option<CStrRef<'_>>>>(endptr),
base, base,
) )
.into_ok_or_errno() .into_ok_or_errno()
@ -53,8 +53,8 @@ pub unsafe extern "C" fn strtoll(nptr: *const u8, endptr: *mut *const u8, base:
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn getenv(name: *const u8) -> *const u8 { pub unsafe extern "C" fn getenv(name: *const u8) -> *const u8 {
libuwuc::env::getenv(SharedThinCstr::from_raw(name)) libuwuc::env::getenv(CStrRef::from_raw(name))
.map(SharedThinCstr::as_raw) .map(CStrRef::as_raw)
.unwrap_or(core::ptr::null()) .unwrap_or(core::ptr::null())
} }

View file

@ -1,4 +1,9 @@
use libuwuc::{error::Error, utils::SharedThinCstr}; use core::cell::UnsafeCell;
use libuwuc::{
error::Error,
utils::{CStrRef, SyncPtr, SyncUnsafeCell},
};
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn memset(ptr: *mut u8, constant: u8, len: usize) { pub unsafe extern "C" fn memset(ptr: *mut u8, constant: u8, len: usize) {
@ -26,13 +31,13 @@ pub unsafe extern "C" fn bcmp(s1: *const u8, s2: *const u8, size: usize) -> i32
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn strcmp(s1: SharedThinCstr<'_>, s2: SharedThinCstr<'_>) -> i32 { pub unsafe extern "C" fn strcmp(s1: CStrRef<'_>, s2: CStrRef<'_>) -> i32 {
libuwuc::mem::strcmp(s1, s2) libuwuc::mem::strcmp(s1, s2)
} }
// This technically violates the safety precondition of SharedThinCstr but that's fine, we're careful. // This technically violates the safety precondition of SharedThinCstr but that's fine, we're careful.
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn strncmp(s1: SharedThinCstr<'_>, s2: SharedThinCstr<'_>, n: usize) -> i32 { pub unsafe extern "C" fn strncmp(s1: CStrRef<'_>, s2: CStrRef<'_>, n: usize) -> i32 {
libuwuc::mem::strncmp(s1, s2, n) libuwuc::mem::strncmp(s1, s2, n)
} }
@ -47,3 +52,20 @@ pub unsafe extern "C" fn strerror(errnum: Error) -> *const u8 {
.map(str::as_ptr) .map(str::as_ptr)
.unwrap_or(core::ptr::null()) .unwrap_or(core::ptr::null())
} }
static STRTOK_GLOBAL: SyncUnsafeCell<SyncPtr<u8>> =
SyncUnsafeCell(UnsafeCell::new(SyncPtr(core::ptr::null_mut())));
#[no_mangle]
pub unsafe extern "C" fn strtok(str: *mut u8, delim: *const u8) -> *const u8 {
strtok_r(str, delim, STRTOK_GLOBAL.0.get().cast::<*const u8>())
}
#[no_mangle]
pub unsafe extern "C" fn strtok_r<'a>(
str: *mut u8,
delim: *const u8,
saveptr: *mut *const u8,
) -> *const u8 {
todo!()
}