fopen and tests

This commit is contained in:
nora 2023-10-04 21:35:18 +02:00
parent 862ef8dc22
commit b795ee80c9
14 changed files with 97 additions and 45 deletions

View file

@ -6,6 +6,15 @@ use core::{
use linked_list_allocator::LockedHeap; use linked_list_allocator::LockedHeap;
pub fn boxed<T>(value: T) -> *mut T {
let ptr = unsafe { alloc_zeroed(Layout::new::<T>()) }.cast::<T>();
if ptr.is_null() {
return ptr;
}
unsafe { ptr.write(value) };
ptr
}
static ALLOCATOR: LockedHeap = LockedHeap::empty(); static ALLOCATOR: LockedHeap = LockedHeap::empty();
const UNINIT: usize = 0; const UNINIT: usize = 0;
@ -51,7 +60,7 @@ fn init() {
} }
} }
pub unsafe fn malloc_zeroed(size: usize, align: usize) -> *mut u8 { pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
/* /*
|start |align |offset |RETURN VALUE |start |align |offset |RETURN VALUE
*/ */
@ -59,7 +68,7 @@ pub unsafe fn malloc_zeroed(size: usize, align: usize) -> *mut u8 {
init(); init();
let (layout, offset) = Layout::array::<usize>(3) let (layout, offset) = Layout::array::<usize>(3)
.unwrap_unchecked() .unwrap_unchecked()
.extend(Layout::from_size_align_unchecked(size, align)) .extend(layout)
.unwrap_unchecked(); .unwrap_unchecked();
let ptr = ALLOCATOR.alloc_zeroed(layout); let ptr = ALLOCATOR.alloc_zeroed(layout);
@ -75,6 +84,10 @@ pub unsafe fn malloc_zeroed(size: usize, align: usize) -> *mut u8 {
ret_ptr ret_ptr
} }
pub unsafe fn malloc_zeroed(size: usize, align: usize) -> *mut u8 {
alloc_zeroed(Layout::from_size_align_unchecked(size, align))
}
pub unsafe fn free(ptr: *mut u8) { pub unsafe fn free(ptr: *mut u8) {
init(); init();
let offset = ptr.cast::<usize>().sub(1).read(); let offset = ptr.cast::<usize>().sub(1).read();

View file

@ -3,6 +3,7 @@ use crate::{
utils::SharedThinCstr, utils::SharedThinCstr,
}; };
#[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
pub struct Fd(pub i32); pub struct Fd(pub i32);

View file

@ -11,14 +11,14 @@ use crate::{
sys::syscall, sys::syscall,
}; };
pub const STDIN: i32 = 0; pub const STDIN: Fd = Fd(0);
pub const STDOUT: i32 = 1; pub const STDOUT: Fd = Fd(1);
pub const STDERR: i32 = 2; pub const STDERR: Fd = Fd(2);
pub const EOF: i32 = -1; pub const EOF: i32 = -1;
#[doc(hidden)] #[doc(hidden)]
pub struct Printer(pub i32); pub struct Printer(pub Fd);
impl core::fmt::Write for Printer { impl core::fmt::Write for Printer {
fn write_str(&mut self, s: &str) -> core::fmt::Result { fn write_str(&mut self, s: &str) -> core::fmt::Result {
@ -37,13 +37,15 @@ macro_rules! println {
} }
pub use println; pub use println;
use self::fd::Fd;
pub unsafe fn sys_write(fd: i32, buf: &[u8]) -> Result<usize, Error> { pub unsafe fn sys_write(fd: i32, buf: &[u8]) -> Result<usize, Error> {
syscall::syscall!(syscall::SYS_WRITE, fd, buf.as_ptr(), buf.len()).syscall_resultify() syscall::syscall!(syscall::SYS_WRITE, fd, buf.as_ptr(), buf.len()).syscall_resultify()
} }
pub unsafe fn write_all(fd: i32, mut buf: &[u8]) -> Result<(), Error> { pub unsafe fn write_all(fd: Fd, mut buf: &[u8]) -> Result<(), Error> {
while !buf.is_empty() { while !buf.is_empty() {
let result = sys_write(fd, buf)?; let result = sys_write(fd.0, buf)?;
buf = &buf[result..]; buf = &buf[result..];
} }
Ok(()) Ok(())

View file

@ -1,4 +1,4 @@
use crate::utils::SharedThinCstr; use crate::{io::fd, utils::SharedThinCstr};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum OpenMode { pub enum OpenMode {
@ -11,6 +11,17 @@ pub enum OpenMode {
} }
impl OpenMode { impl OpenMode {
pub fn flags(self) -> i32 {
match self {
OpenMode::R => fd::O_RDONLY,
OpenMode::RP => fd::O_RDWR,
OpenMode::W => fd::O_WRONLY | fd::O_CREAT | fd::O_TRUNC,
OpenMode::WP => fd::O_RDWR | fd::O_CREAT | fd::O_TRUNC,
OpenMode::A => fd::O_WRONLY | fd::O_CREAT | fd::O_APPEND,
OpenMode::AP => fd::O_RDWR | fd::O_CREAT | fd::O_APPEND,
}
}
pub fn parse(str: SharedThinCstr<'_>) -> Result<OpenMode, &'static str> { pub fn parse(str: SharedThinCstr<'_>) -> Result<OpenMode, &'static str> {
let mut buf = [0; 2]; let mut buf = [0; 2];
let mut i = 0; let mut i = 0;

View file

@ -1,19 +1,22 @@
pub mod file; pub mod file;
use core::ffi::c_int; use crate::{
alloc,
error::Error,
io::{fd, stream::file::OpenMode},
utils::SharedThinCstr,
};
use crate::{error::Error, io::stream::file::OpenMode, utils::SharedThinCstr}; use super::{fd::Fd, IoWrite, EOF};
use super::{IoWrite, EOF};
/// A `FILE`. /// A `FILE`.
#[repr(C)] #[repr(C)]
pub struct FileStream { pub struct FileStream {
fd: c_int, fd: Fd,
} }
impl FileStream { impl FileStream {
pub const fn from_raw_fd(fd: c_int) -> Self { pub const fn from_raw_fd(fd: Fd) -> Self {
Self { fd } Self { fd }
} }
@ -24,7 +27,7 @@ impl FileStream {
impl IoWrite for &FileStream { impl IoWrite for &FileStream {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
unsafe { super::sys_write(self.fd, buf) } unsafe { super::sys_write(self.fd.0, buf) }
} }
} }
@ -36,7 +39,8 @@ pub unsafe fn fopen<'a>(
return Err(Error::INVAL); return Err(Error::INVAL);
}; };
todo!() let fd = fd::open(pathname, mode.flags())?;
unsafe { Ok(&*alloc::boxed(FileStream { fd })) }
} }
pub fn fputc(c: u8, stream: &FileStream) -> i32 { pub fn fputc(c: u8, stream: &FileStream) -> i32 {

View file

@ -91,7 +91,9 @@ pub unsafe extern "C" fn fopen<'a>(
pathname: SharedThinCstr, pathname: SharedThinCstr,
mode: SharedThinCstr, mode: SharedThinCstr,
) -> Option<&'a FileStream> { ) -> Option<&'a FileStream> {
todo!() libuwuc::io::stream::fopen(pathname, mode)
.map_err(|err| libuwuc::error::set_errno(err.0))
.ok()
} }
#[no_mangle] #[no_mangle]

View file

@ -10,7 +10,7 @@ clean() {
rm -r "${test_dir}" rm -r "${test_dir}"
} }
for test in tests/c/*; do for test in "$SCRIPT_DIR"/tests/c/*; do
name=$(basename $test .c) name=$(basename $test .c)
printf "test $name " printf "test $name "
@ -31,7 +31,7 @@ for test in tests/c/*; do
exit 1 exit 1
fi fi
cd "$SCRIPT_DIR/tests"
OUTPUT=$("$test_dir/$name") OUTPUT=$("$test_dir/$name")
code="$?" code="$?"
if [ "$code" -ne "0" ]; then if [ "$code" -ne "0" ]; then

View file

@ -1,9 +1,10 @@
#include <stdio.h> #include <stdio.h>
#include <assert.h>
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
{
char *self = argv[0]; char *self = argv[0];
char first = self[0]; char first = self[0];
if (first != '/') {
return 1; assert((first < 128) && "argv[0] is not ascii/utf-8");
}
} }

16
tests/c/fopen.c Normal file
View file

@ -0,0 +1,16 @@
#include <stdio.h>
#include <errno.h>
#include <assert.h>
int main(int argc, char *argv[]) {
FILE *file1 = fopen("./c/fopen.c", "r");
assert(file1 && "failed to open file");
FILE *file2 = fopen("./c/fopen.c", "meow");
assert(!file2 && "succeeded opening file despite invalid argument");
assert((errno == EINVAL) && "wrong errno");
FILE *file3 = fopen("/this-does-absolutely-not-exist-at-all-edhjkefhew98", "r");
assert(!file3 && "succeeded despite file not existing");
assert((errno == ENOENT) && "wrong errno");
}

View file

@ -1,14 +1,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h>
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
{
char *env = getenv("PATH"); char *env = getenv("PATH");
if (!env) { assert(env && "PATH doesnt exist");
return 1;
}
char *env2 = getenv( char *env2 = getenv(
"__some absolutely NONSENSE that no one would ever define please.."); "__some absolutely NONSENSE that no one would ever define please..");
if (env2) { assert(!env2 && "nonsense environment variable found");
return 1;
}
} }

View file

@ -1,7 +1,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h>
int main(void) { int main(void)
{
char *alloc = (char *)malloc(10); char *alloc = (char *)malloc(10);
assert(alloc && "allocation failed");
*alloc = 1; *alloc = 1;
*(alloc + 9) = 2; *(alloc + 9) = 2;
free(alloc); free(alloc);

View file

@ -1,13 +1,14 @@
#include <string.h> #include <string.h>
#include <assert.h>
int main(void) { int main(void)
{
char buf[10]; char buf[10];
memset(buf, 34, sizeof(buf)); memset(buf, 34, sizeof(buf));
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i)
if (buf[i] != 34) { {
return 1; assert((buf[i] == 34) && "memset failed to write byte");
}
} }
} }

View file

@ -1,8 +1,8 @@
#include <stdio.h> #include <stdio.h>
#include <assert.h>
int main(int argc, char *argv[]) { int main(int argc, char *argv[])
{
int result = printf("Hello, world!\n"); int result = printf("Hello, world!\n");
if (result != 14) { assert((result == 14) && "printf returned wrong number of chars");
return 1;
}
} }

View file

@ -1,9 +1,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h>
int main(void) { int main(void)
{
char *str = "12"; char *str = "12";
long value = strtol(str, NULL, 10); long value = strtol(str, NULL, 10);
if (value != 12) { assert((value == 12) && "value must be 12");
return 1;
}
} }