mirror of
https://github.com/Noratrieb/libuwuc.git
synced 2026-01-16 12:45:12 +01:00
more tests
This commit is contained in:
parent
043c960708
commit
1827bd19c9
12 changed files with 240 additions and 72 deletions
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
use core::ffi::c_char;
|
use core::ffi::c_char;
|
||||||
|
|
||||||
use libuwuc::{println, utils::SharedThinCstr};
|
use libuwuc::println;
|
||||||
|
|
||||||
extern crate rawc;
|
extern crate rawc;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn main(_argc: i32, _argv: *const *const c_char) -> i32 {
|
extern "C" fn main(_argc: i32, _argv: *const *const c_char) -> i32 {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
let pwd = libuwuc::env::getenv(SharedThinCstr::from_array(b"PWD\0"));
|
let pwd = libuwuc::env::getenv(libuwuc::cstr!("PWD"));
|
||||||
println!("PWD={pwd:?}");
|
println!("PWD={pwd:?}");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ mod global {
|
||||||
|
|
||||||
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>) {
|
pub(super) unsafe fn init(envp: *mut Option<SharedThinCstr<'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>) {
|
pub(crate) unsafe fn init(envp: *mut Option<SharedThinCstr<'static>>) {
|
||||||
global::init(envp);
|
global::init(envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
struct EnvP(Option<NonNull<Option<SharedThinCstr>>>);
|
struct EnvP(Option<NonNull<Option<SharedThinCstr<'static>>>>);
|
||||||
|
|
||||||
unsafe impl Sync for EnvP {}
|
unsafe impl Sync for EnvP {}
|
||||||
|
|
||||||
impl Iterator for EnvP {
|
impl Iterator for EnvP {
|
||||||
type Item = SharedThinCstr;
|
type Item = SharedThinCstr<'static>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let value: Option<SharedThinCstr> = self.0.unwrap().as_ptr().read();
|
let value: Option<SharedThinCstr<'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> {
|
pub fn getenv(name: SharedThinCstr<'_>) -> Option<SharedThinCstr<'static>> {
|
||||||
getenv_inner(global::get(), name)
|
getenv_inner(global::get(), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getenv_inner(mut envp: EnvP, name: SharedThinCstr) -> Option<SharedThinCstr> {
|
fn getenv_inner(mut envp: EnvP, name: SharedThinCstr<'_>) -> Option<SharedThinCstr<'static>> {
|
||||||
let mut eq_idx = 0;
|
let mut eq_idx = 0;
|
||||||
envp.find(|env| {
|
envp.find(|env| {
|
||||||
// Find ENV
|
// Find ENV
|
||||||
|
|
@ -109,13 +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>> = cstrs
|
let mut envs: Vec<Option<SharedThinCstr<'static>>> = cstrs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|cstr| unsafe {
|
.map(|cstr| unsafe { Some(SharedThinCstr::from_raw(cstr.as_ptr() as _)) })
|
||||||
Some(SharedThinCstr::from_ptr(
|
|
||||||
NonNull::new(cstr.as_ptr() as _).unwrap(),
|
|
||||||
))
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
envs.push(None);
|
envs.push(None);
|
||||||
|
|
||||||
|
|
@ -126,34 +122,28 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn getenv_exact_first() {
|
fn getenv_exact_first() {
|
||||||
with_envp(&["UWU=a"], |envp| {
|
with_envp(&["UWU=a"], |envp| {
|
||||||
assert_eq!(
|
assert_eq!(super::getenv_inner(envp, cstr!("UWU")).unwrap(), cstr!("a"));
|
||||||
super::getenv_inner(envp, cstr("UWU\0")).unwrap(),
|
|
||||||
cstr("a\0")
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn getenv_previous_mismatches() {
|
fn getenv_previous_mismatches() {
|
||||||
with_envp(&["UW=a", "UWUU=b", "UWU=c"], |envp| {
|
with_envp(&["UW=a", "UWUU=b", "UWU=c"], |envp| {
|
||||||
assert_eq!(
|
assert_eq!(super::getenv_inner(envp, cstr!("UWU")).unwrap(), cstr!("c"));
|
||||||
super::getenv_inner(envp, cstr("UWU\0")).unwrap(),
|
|
||||||
cstr("c\0")
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn getenv_name_long() {
|
fn getenv_name_long() {
|
||||||
with_envp(&["U=w"], |envp| {
|
with_envp(&["U=w"], |envp| {
|
||||||
assert_eq!(super::getenv_inner(envp, cstr("LONG_NAME\0")), None);
|
assert_eq!(super::getenv_inner(envp, cstr!("LONG_NAME")), None);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn getenv_same_length() {
|
fn getenv_same_length() {
|
||||||
with_envp(&["OWO=a", "UWU=b"], |envp| {
|
with_envp(&["OWO=a", "UWU=b"], |envp| {
|
||||||
assert_eq!(super::getenv_inner(envp, cstr("UWU\0")), Some(cstr("b\0")));
|
assert_eq!(super::getenv_inner(envp, cstr!("UWU")), Some(cstr!("b")));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,11 @@
|
||||||
pub mod printf;
|
use core::ffi::c_int;
|
||||||
|
|
||||||
|
pub mod parse;
|
||||||
|
pub mod printf;
|
||||||
|
|
||||||
|
pub fn is_space(c: c_int) -> c_int {
|
||||||
|
// todo: is this correct?
|
||||||
|
char::from_u32(c as _)
|
||||||
|
.map(char::is_whitespace)
|
||||||
|
.unwrap_or_default() as _
|
||||||
|
}
|
||||||
|
|
|
||||||
18
libuwuc/src/fmt/parse.rs
Normal file
18
libuwuc/src/fmt/parse.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
use core::ffi::{c_int, c_long};
|
||||||
|
|
||||||
|
use crate::utils::SharedThinCstr;
|
||||||
|
|
||||||
|
pub unsafe fn parse_long<'a>(
|
||||||
|
str: SharedThinCstr<'a>,
|
||||||
|
endptr: *mut 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)
|
||||||
|
{}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
@ -4,8 +4,8 @@ use crate::{io::IoWrite, utils::SharedThinCstr};
|
||||||
|
|
||||||
pub unsafe fn printf_generic(
|
pub unsafe fn printf_generic(
|
||||||
mut sink: impl IoWrite,
|
mut sink: impl IoWrite,
|
||||||
format: SharedThinCstr,
|
format: SharedThinCstr<'_>,
|
||||||
args: VaList<'_, '_>,
|
_args: VaList<'_, '_>,
|
||||||
) -> Result<(), i32> {
|
) -> Result<(), i32> {
|
||||||
let mut chars = format.into_iter();
|
let mut chars = format.into_iter();
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ mod tests {
|
||||||
|
|
||||||
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: SharedThinCstr<'_>, 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();
|
||||||
|
|
@ -41,12 +41,14 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "variadic")]
|
||||||
fn empty_format() {
|
fn empty_format() {
|
||||||
unsafe { test_printf("\0", cstr("\0")) }
|
unsafe { test_printf("\0", cstr!("")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, ignore = "variadic")]
|
||||||
fn constant_string() {
|
fn constant_string() {
|
||||||
unsafe { test_printf("hello, world\0", cstr("hello, world\0")) }
|
unsafe { test_printf("hello, world\0", cstr!("hello, world")) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(c_variadic)]
|
#![feature(c_variadic)]
|
||||||
#![warn(unreachable_pub)]
|
#![warn(unreachable_pub)]
|
||||||
|
#![warn(rust_2018_idioms)]
|
||||||
#![allow(clippy::missing_safety_doc)]
|
#![allow(clippy::missing_safety_doc)]
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -40,3 +40,128 @@ pub unsafe fn strlen(mut s: *const u8) -> usize {
|
||||||
}
|
}
|
||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn memcpy_null() {
|
||||||
|
unsafe { super::memcpy(std::ptr::null_mut(), std::ptr::null_mut(), 0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcpy() {
|
||||||
|
let src = [1, 2, 3];
|
||||||
|
let mut dest = [0; 3];
|
||||||
|
unsafe { super::memcpy(dest.as_mut_ptr(), src.as_ptr(), 3) };
|
||||||
|
assert_eq!(dest, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memset_null() {
|
||||||
|
unsafe { super::memset(std::ptr::null_mut(), 0, 0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memset() {
|
||||||
|
let mut dest = [1; 10];
|
||||||
|
unsafe { super::memset(dest.as_mut_ptr(), 0, 9) };
|
||||||
|
assert_eq!(&dest[..9], &[0; 9]);
|
||||||
|
assert_eq!(dest[9], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_null() {
|
||||||
|
let result = unsafe { super::memcmp(std::ptr::null(), std::ptr::null(), 0) };
|
||||||
|
assert_eq!(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_eq_one() {
|
||||||
|
let a = [1];
|
||||||
|
let b = [1];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 1)};
|
||||||
|
assert_eq!(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_eq_two() {
|
||||||
|
let a = [1, 2];
|
||||||
|
let b = [1, 2];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 2) };
|
||||||
|
assert_eq!(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_eq_many() {
|
||||||
|
let a = [1, 2, 5, 3, 5, 67, 7];
|
||||||
|
let b = [1, 2, 5, 3, 5, 67, 7];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 7) };
|
||||||
|
assert_eq!(result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_lt_one() {
|
||||||
|
let a = [0];
|
||||||
|
let b = [1];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 1)};
|
||||||
|
assert_eq!(result, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_lt_two() {
|
||||||
|
let a = [1, 1];
|
||||||
|
let b = [1, 2];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 2) };
|
||||||
|
assert_eq!(result, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_lt_many() {
|
||||||
|
let a = [1, 2, 5, 3, 4, 67, 7];
|
||||||
|
let b = [1, 2, 5, 3, 5, 67, 7];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 7) };
|
||||||
|
assert_eq!(result, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_gt_one() {
|
||||||
|
let a = [255];
|
||||||
|
let b = [1];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 1)};
|
||||||
|
assert_eq!(result, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_gt_two() {
|
||||||
|
let a = [1, 4];
|
||||||
|
let b = [1, 2];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 2) };
|
||||||
|
assert_eq!(result, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcmp_gt_many() {
|
||||||
|
let a = [1, 2, 6, 3, 4, 67, 7];
|
||||||
|
let b = [1, 2, 5, 3, 5, 67, 7];
|
||||||
|
let result = unsafe { super::memcmp(a.as_ptr(), b.as_ptr(), 7) };
|
||||||
|
assert_eq!(result, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strlen_empty() {
|
||||||
|
let str = b"\0";
|
||||||
|
assert_eq!(unsafe { super::strlen(str.as_ptr()) }, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strlen_one() {
|
||||||
|
let str = b"A\0";
|
||||||
|
assert_eq!(unsafe { super::strlen(str.as_ptr()) }, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strlen_many() {
|
||||||
|
let str = b"meow meow meow meow\0";
|
||||||
|
assert_eq!(unsafe { super::strlen(str.as_ptr()) }, 19);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::utils::SharedThinCstr;
|
||||||
/// 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(argc: u64, argv: *const *const c_char, rsp: u64) -> ! {
|
pub(crate) unsafe extern "C" fn start(argc: u64, argv: *const *const c_char, rsp: u64) -> ! {
|
||||||
let envp = (8 + 8 * argc + rsp + 8) as *mut Option<SharedThinCstr>;
|
let envp = (8 + 8 * argc + rsp + 8) as *mut Option<SharedThinCstr<'static>>;
|
||||||
|
|
||||||
crate::env::init(envp);
|
crate::env::init(envp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
use core::{
|
use core::{cell::UnsafeCell, ffi::CStr, fmt::Debug, marker::PhantomData, ptr::NonNull};
|
||||||
cell::UnsafeCell,
|
|
||||||
ffi::{c_char, CStr},
|
|
||||||
fmt::Debug,
|
|
||||||
ptr::NonNull,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -13,44 +8,55 @@ unsafe impl<T: Sync> Sync for SyncUnsafeCell<T> {}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct SharedThinCstr(pub NonNull<c_char>);
|
pub struct SharedThinCstr<'a>(NonNull<u8>, PhantomData<&'a CStr>);
|
||||||
|
|
||||||
impl SharedThinCstr {
|
#[macro_export]
|
||||||
pub unsafe fn from_ptr(ptr: NonNull<c_char>) -> Self {
|
macro_rules! cstr {
|
||||||
Self(ptr)
|
($value:literal) => {{
|
||||||
|
let s = concat!($value, "\0");
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
unsafe { $crate::utils::SharedThinCstr::from_raw(s.as_ptr().cast()) }
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use cstr;
|
||||||
|
|
||||||
|
impl<'a> SharedThinCstr<'a> {
|
||||||
|
pub unsafe fn from_raw(ptr: *const u8) -> Self {
|
||||||
|
Self(NonNull::new_unchecked(ptr as *mut u8), PhantomData)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn from_raw(ptr: *const c_char) -> Self {
|
pub fn as_ptr(self) -> NonNull<u8> {
|
||||||
Self(NonNull::new_unchecked(ptr as _))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_array<const N: usize>(arr: &[u8; N]) -> Self {
|
|
||||||
assert!(arr[N - 1] == 0);
|
|
||||||
unsafe { Self(NonNull::new_unchecked(arr as *const u8 as *mut c_char)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_ptr(self) -> NonNull<c_char> {
|
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_raw(self) -> *const u8 {
|
||||||
|
self.0.as_ptr()
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn add(self, amount: usize) -> Self {
|
pub unsafe fn add(self, amount: usize) -> Self {
|
||||||
Self(NonNull::new_unchecked(self.0.as_ptr().add(amount)))
|
Self::from_raw(self.0.as_ptr().add(amount))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn first(self) -> Option<u8> {
|
||||||
|
let c = unsafe { self.0.as_ptr().read() };
|
||||||
|
(c != 0).then_some(c as _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoIterator for SharedThinCstr {
|
impl<'a> IntoIterator for SharedThinCstr<'a> {
|
||||||
type Item = u8;
|
type Item = u8;
|
||||||
|
|
||||||
type IntoIter = CStrIter;
|
type IntoIter = CStrIter<'a>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
CStrIter(self)
|
CStrIter(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CStrIter(SharedThinCstr);
|
pub struct CStrIter<'a>(SharedThinCstr<'a>);
|
||||||
|
|
||||||
impl Iterator for CStrIter {
|
impl<'a> Iterator for CStrIter<'a> {
|
||||||
type Item = u8;
|
type Item = u8;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
|
@ -66,10 +72,10 @@ impl Iterator for CStrIter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for SharedThinCstr {}
|
unsafe impl<'a> Send for SharedThinCstr<'a> {}
|
||||||
unsafe impl Sync for SharedThinCstr {}
|
unsafe impl<'a> Sync for SharedThinCstr<'a> {}
|
||||||
|
|
||||||
impl Debug for SharedThinCstr {
|
impl<'a> Debug for SharedThinCstr<'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 {
|
||||||
|
|
@ -79,25 +85,19 @@ impl Debug for SharedThinCstr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SharedThinCstr> for &CStr {
|
impl<'a> From<SharedThinCstr<'a>> for &'a CStr {
|
||||||
fn from(value: SharedThinCstr) -> Self {
|
fn from(value: SharedThinCstr<'a>) -> Self {
|
||||||
unsafe { CStr::from_ptr(value.0.as_ptr()) }
|
unsafe { CStr::from_ptr(value.0.as_ptr().cast()) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for SharedThinCstr {
|
impl<'a> PartialEq for SharedThinCstr<'a> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.into_iter().eq(*other)
|
self.into_iter().eq(*other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for SharedThinCstr {}
|
impl<'a> Eq for SharedThinCstr<'a> {}
|
||||||
|
|
||||||
|
|
||||||
pub fn cstr(s: &str) -> SharedThinCstr {
|
|
||||||
assert_eq!(s.as_bytes()[s.len() - 1], 0);
|
|
||||||
unsafe { SharedThinCstr::from_ptr(NonNull::new(s.as_ptr() as _).unwrap()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub(crate) struct SyncPtr<T>(pub(crate) *mut T);
|
pub(crate) struct SyncPtr<T>(pub(crate) *mut T);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ pub unsafe extern "C" fn puts(s: *const c_char) -> i32 {
|
||||||
// PRINTF:
|
// PRINTF:
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn __printf_chk(_flag: c_int, format: *const c_char, mut args: ...) -> c_int {
|
pub unsafe extern "C" fn __printf_chk(_flag: c_int, format: *const u8, mut args: ...) -> c_int {
|
||||||
let mut sink = WriteCounter(stdout, 0);
|
let mut sink = WriteCounter(stdout, 0);
|
||||||
|
|
||||||
let result = libuwuc::fmt::printf::printf_generic(
|
let result = libuwuc::fmt::printf::printf_generic(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use libuwuc::utils::SharedThinCstr;
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 {
|
pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 {
|
||||||
libuwuc::alloc::malloc_zeroed(size, 16)
|
libuwuc::alloc::malloc_zeroed(size, 16)
|
||||||
|
|
@ -12,3 +14,10 @@ pub unsafe extern "C" fn free(ptr: *mut u8) {
|
||||||
pub unsafe extern "C" fn exit(code: i32) -> ! {
|
pub unsafe extern "C" fn exit(code: i32) -> ! {
|
||||||
libuwuc::start::exit(code as i64 as _)
|
libuwuc::start::exit(code as i64 as _)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn getenv(name: *const u8) -> *const u8 {
|
||||||
|
libuwuc::env::getenv(SharedThinCstr::from_raw(name))
|
||||||
|
.map(SharedThinCstr::as_raw)
|
||||||
|
.unwrap_or(core::ptr::null())
|
||||||
|
}
|
||||||
|
|
|
||||||
13
tests/c/getenv.c
Normal file
13
tests/c/getenv.c
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char *env = getenv("PATH");
|
||||||
|
if (!env) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *env2 = getenv("__some absolutely NONSENSE that no one would ever define please..");
|
||||||
|
if (env2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue