libc: ctype.h, most of stdio.h, string.h

This commit is contained in:
Mark Poliakov 2024-11-12 11:01:39 +02:00
parent 98862b1e49
commit 0a904a21fe
15 changed files with 980 additions and 245 deletions

View File

@ -0,0 +1,7 @@
#ifndef _YGGDRASIL_CTYPE_H
#define _YGGDRASIL_CTYPE_H 1
#define _tolower(ch) tolower(ch)
#define _toupper(ch) toupper(ch)
#endif

View File

@ -1,18 +1,26 @@
use core::{
alloc::{GlobalAlloc, Layout}, ffi::c_void, ptr::{self, null, null_mut, NonNull}
alloc::{GlobalAlloc, Layout},
ffi::c_void,
ptr::{self, null_mut, NonNull},
};
use libyalloc::{allocator::BucketAllocator, sys::PageProvider};
use yggdrasil_rt::{mem::MappingSource, sys as syscall};
use crate::{error::EResult, headers::errno};
use crate::{
error::EResult,
headers::{
errno,
string::{memcpy, memset},
}, sync::Mutex,
};
struct Allocator;
struct PageProviderImpl;
unsafe impl GlobalAlloc for Allocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let pointer = YALLOC.allocate(layout);
let pointer = YALLOC.lock().allocate(layout);
match pointer {
Some(ptr) => ptr.as_ptr(),
None => null_mut(),
@ -21,7 +29,7 @@ unsafe impl GlobalAlloc for Allocator {
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
let pointer = NonNull::new(ptr).expect("NULL pointer passed to dealloc()");
YALLOC.free(pointer, layout);
YALLOC.lock().free(pointer, layout);
}
}
@ -43,10 +51,10 @@ impl PageProvider for PageProviderImpl {
}
}
const MALLOC_HEADER_SIZE: usize = size_of::<usize>();
const MALLOC_HEADER_SIZE: usize = 16;
unsafe fn get_allocation(ptr: NonNull<u8>) -> (NonNull<u8>, Layout) {
assert!(usize::from(ptr.addr()) > 0x10);
assert!(usize::from(ptr.addr()) > MALLOC_HEADER_SIZE);
let real_ptr = ptr.sub(MALLOC_HEADER_SIZE);
let size = *real_ptr.cast::<usize>().as_ref();
let layout = Layout::from_size_align(size, 16).unwrap();
@ -54,49 +62,69 @@ unsafe fn get_allocation(ptr: NonNull<u8>) -> (NonNull<u8>, Layout) {
}
pub fn c_alloc(size: usize, mut align: usize, zero: bool) -> EResult<NonNull<c_void>> {
assert!(align.is_power_of_two());
if align < align_of::<usize>() {
align = align_of::<usize>();
if align < 16 {
align = 16;
}
if align > 16 {
todo!()
}
let offset = (MALLOC_HEADER_SIZE + align - 1) & !(align - 1);
let size = offset + size;
let size = size + MALLOC_HEADER_SIZE;
let layout = Layout::from_size_align(size, align).unwrap();
let ptr = match unsafe { YALLOC.allocate(layout) } {
let ptr = match YALLOC.lock().allocate(layout) {
Some(value) => value,
None => return EResult::Err(errno::ENOMEM),
};
if zero {
// TODO
unsafe {
memset(ptr.as_ptr().cast(), 0, size);
}
}
unsafe {
// Write the size right below the pointer
ptr.add(offset - size_of::<usize>()).cast::<usize>().write(size);
ptr.cast::<usize>().write(size);
}
unsafe { EResult::Ok(ptr.cast::<c_void>().add(offset)) }
unsafe { EResult::Ok(ptr.cast::<c_void>().add(MALLOC_HEADER_SIZE)) }
}
pub unsafe fn c_realloc(old_ptr: Option<NonNull<c_void>>, size: usize) -> EResult<NonNull<c_void>> {
match old_ptr {
Some(old_ptr) => {
// TODO libyalloc realloc
let (real_old_ptr, old_layout) = get_allocation(old_ptr.cast());
let new_ptr = c_alloc(size, 16, false)?;
memcpy(
new_ptr.cast().as_ptr(),
old_ptr.cast().as_ptr(),
old_layout.size() - MALLOC_HEADER_SIZE,
);
YALLOC.lock().free(real_old_ptr, old_layout);
EResult::Ok(new_ptr)
}
None => c_alloc(size, 16, false),
}
}
pub unsafe fn c_free(ptr: NonNull<c_void>) {
let (real_ptr, layout) = get_allocation(ptr.cast());
YALLOC.lock().free(real_ptr, layout);
}
pub unsafe fn malloc(size: usize) -> EResult<NonNull<c_void>> {
todo!()
// // TODO errno setting
// match c_alloc(size, 16, false) {
// Some(ptr) => ptr.as_ptr(),
// None => null_mut()
// }
c_alloc(size, 16, false)
}
pub unsafe fn free(ptr: NonNull<c_void>) {
todo!()
c_free(ptr)
}
#[global_allocator]
static ALLOCATOR: Allocator = Allocator;
// TODO locking for multithreaded binaries
static mut YALLOC: BucketAllocator<PageProviderImpl> = BucketAllocator::new();
static YALLOC: Mutex<BucketAllocator<PageProviderImpl>> = Mutex::new(BucketAllocator::new());

View File

@ -27,6 +27,10 @@ macro impl_from_residual($($ty:ty),+) {
#[allow(non_upper_case_globals)]
pub static mut errno: Errno = Errno(0);
pub trait ResultExt<T, E> {
fn e_map_err<F: FnOnce(E) -> Errno>(self, map: F) -> EResult<T>;
}
pub trait CResult {
const ERROR: Self;
}
@ -65,7 +69,7 @@ pub struct CFdResult(c_int);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct COffsetResult(off_t);
pub struct COffsetResult(pub(crate) off_t);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
@ -124,6 +128,15 @@ impl<T> EResult<T> {
}
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
fn e_map_err<F: FnOnce(E) -> Errno>(self, map: F) -> EResult<T> {
match self {
Ok(value) => EResult::Ok(value),
Err(value) => EResult::Err(map(value))
}
}
}
impl<T> Try for EResult<T> {
type Output = T;
type Residual = EResult<Infallible>;

View File

@ -0,0 +1,15 @@
language = "C"
style = "Type"
sys_includes = [
"locale.h"
]
no_includes = true
include_guard = "_CTYPE_H"
trailer = "#include <bits/ctype.h>"
usize_type = "size_t"
isize_type = "ssize_t"
[export]

View File

@ -0,0 +1,161 @@
use core::ffi::c_int;
use super::locale::locale_t;
#[no_mangle]
unsafe extern "C" fn isalnum(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_alphanumeric()) as _
}
#[no_mangle]
unsafe extern "C" fn isalpha(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_alphabetic()) as _
}
#[no_mangle]
unsafe extern "C" fn isascii(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii()) as _
}
#[no_mangle]
unsafe extern "C" fn isblank(ch: c_int) -> c_int {
(ch == b' ' as c_int || ch == b'\t' as c_int) as _
}
#[no_mangle]
unsafe extern "C" fn iscntrl(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_control()) as _
}
#[no_mangle]
unsafe extern "C" fn isdigit(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_digit()) as _
}
#[no_mangle]
unsafe extern "C" fn isgraph(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_graphic()) as _
}
#[no_mangle]
unsafe extern "C" fn islower(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_lowercase()) as _
}
#[no_mangle]
unsafe extern "C" fn isprint(ch: c_int) -> c_int {
(ch < 0xFF && ((ch as u8).is_ascii_graphic() || (ch as u8).is_ascii_whitespace())) as _
}
#[no_mangle]
unsafe extern "C" fn ispunct(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_punctuation()) as _
}
#[no_mangle]
unsafe extern "C" fn isspace(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_whitespace()) as _
}
#[no_mangle]
unsafe extern "C" fn isupper(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_uppercase()) as _
}
#[no_mangle]
unsafe extern "C" fn isxdigit(ch: c_int) -> c_int {
(ch < 0xFF && (ch as u8).is_ascii_hexdigit()) as _
}
#[no_mangle]
unsafe extern "C" fn toascii(ch: c_int) -> c_int {
ch & 0x7F
}
#[no_mangle]
unsafe extern "C" fn tolower(ch: c_int) -> c_int {
if ch < 0xFF {
(ch as u8).to_ascii_lowercase() as _
} else {
ch
}
}
#[no_mangle]
unsafe extern "C" fn toupper(ch: c_int) -> c_int {
if ch < 0xFF {
(ch as u8).to_ascii_uppercase() as _
} else {
ch
}
}
#[no_mangle]
unsafe extern "C" fn isalnum_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isalpha_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isblank_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn iscntrl_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isdigit_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isgraph_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn islower_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isprint_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn ispunct_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isspace_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isupper_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn isxdigit_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn tolower_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn toupper_l(_ch: c_int, _locale: locale_t) -> c_int {
unimplemented!()
}

View File

@ -1,4 +1,4 @@
use core::ffi::{c_char, c_int, CStr};
use core::ffi::{c_int, CStr};
macro_rules! static_cstr {
($string:expr) => {
@ -136,12 +136,11 @@ static ERRNO_STRINGS: &[&CStr] = &[
];
impl Errno {
pub fn to_c_str(&self) -> *const c_char {
pub fn to_c_str(&self) -> &CStr {
ERRNO_STRINGS
.get(self.0 as usize)
.copied()
.unwrap_or(SUCCESS)
.as_ptr() as *const _
}
pub fn from_c_int(v: c_int) -> Option<Self> {

View File

@ -2,13 +2,13 @@
// <aio.h> -
// <arpa/inet.h> -
// <assert.h> -
// <assert.h> +
// <complex.h> -
// <cpio.h> -
// <ctype.h> -
// <ctype.h> +
// <dirent.h> -
// <dlfcn.h> -
// <errno.h> ~
// <errno.h> +
// <fcntl.h> -
// <fenv.h> -
// <float.h> -
@ -83,12 +83,13 @@
// <wctype.h> -
// <wordexp.h> -
pub mod ctype;
pub mod errno;
pub mod locale;
pub mod stdio;
pub mod stdlib;
pub mod string;
pub mod unistd;
pub mod strings;
pub mod unistd;
pub mod sys_types;

View File

@ -1,22 +1,30 @@
use core::{
ffi::{c_char, c_int, c_long, c_void},
ptr::NonNull,
ptr::{null_mut, NonNull},
};
use alloc::boxed::Box;
use yggdrasil_rt::{debug_trace, io::OpenOptions, path::Path};
use yggdrasil_rt::{
debug_trace,
io::{OpenOptions, RawFd, SeekFrom},
path::Path,
};
use crate::{
error::{CEofResult, CFdResult, CIntZeroResult, CPtrResult, EResult},
headers::sys_types::off_t,
error::{
CEofResult, CFdResult, CIntZeroResult, COffsetResult, CPtrResult, CResult, EResult,
ResultExt, TryFromExt,
},
headers::{errno, sys_types::off_t},
io::{
self,
managed::{FileOpenSource, FILE},
Seek, Write,
},
util::{PointerExt, PointerStrExt},
};
use super::fpos_t;
use super::{fpos_t, SEEK_SET, _IOFBF, _IOLBF, _IONBF};
fn open_inner<O: FileOpenSource>(source: O, mode_str: &[u8]) -> EResult<NonNull<FILE>> {
let opts = match mode_str {
@ -43,7 +51,10 @@ fn open_inner<O: FileOpenSource>(source: O, mode_str: &[u8]) -> EResult<NonNull<
}
#[no_mangle]
unsafe extern "C" fn clearerr(fp: *mut FILE) {}
unsafe extern "C" fn clearerr(fp: *mut FILE) {
let fp = fp.ensure_mut();
fp.clear_error();
}
#[no_mangle]
unsafe extern "C" fn fclose(fp: *mut FILE) -> CEofResult {
@ -59,55 +70,72 @@ unsafe extern "C" fn fclose(fp: *mut FILE) -> CEofResult {
#[no_mangle]
unsafe extern "C" fn fdopen(fd: c_int, mode: *const c_char) -> CPtrResult<FILE> {
todo!()
let fd = RawFd::e_try_from(fd)?;
let mode = mode.ensure_cstr();
let file = open_inner(fd, mode.to_bytes())?;
CPtrResult::success(file)
}
#[no_mangle]
unsafe extern "C" fn feof(fp: *mut FILE) -> c_int {
todo!()
let fp = fp.ensure_mut();
fp.is_eof() as _
}
#[no_mangle]
unsafe extern "C" fn ferror(fp: *mut FILE) -> c_int {
todo!()
let fp = fp.ensure_mut();
fp.is_error() as _
}
#[no_mangle]
unsafe extern "C" fn fflush(fp: *mut FILE) -> CIntZeroResult {
todo!()
let fp = fp.ensure_mut();
fp.flush()?;
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn fileno(fp: *mut FILE) -> CFdResult {
todo!()
let fp = fp.ensure_mut();
let fd = fp.fd();
match fd {
Some(fd) => CFdResult::success(fd),
None => CFdResult::ERROR,
}
}
#[no_mangle]
unsafe extern "C" fn flockfile(fp: *mut FILE) {
todo!()
let fp = fp.ensure_mut();
fp.lock();
}
#[no_mangle]
unsafe extern "C" fn fgetpos(fp: *mut FILE, pos: *mut fpos_t) -> c_int {
todo!()
unsafe extern "C" fn fgetpos(fp: *mut FILE, pos: *mut fpos_t) -> CIntZeroResult {
let fp = fp.ensure_mut();
let pos = pos.ensure_mut();
let p = fp.stream_position()?;
*pos = p;
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn fmemopen(
buffer: *mut c_void,
size: usize,
mode: *const c_char,
_buffer: *mut c_void,
_size: usize,
_mode: *const c_char,
) -> CPtrResult<FILE> {
todo!()
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn freopen(
path: *const c_char,
mode: *const c_char,
fp: *mut FILE,
_path: *const c_char,
_mode: *const c_char,
_fp: *mut FILE,
) -> CPtrResult<FILE> {
todo!()
unimplemented!()
}
#[no_mangle]
@ -119,74 +147,100 @@ unsafe extern "C" fn fopen(path: *const c_char, mode: *const c_char) -> CPtrResu
}
#[no_mangle]
unsafe extern "C" fn fseek(fp: *mut FILE, offset: c_long, whence: c_int) -> c_int {
todo!()
unsafe extern "C" fn fseek(fp: *mut FILE, offset: c_long, whence: c_int) -> CIntZeroResult {
let offset: off_t = offset.try_into().e_map_err(|_| errno::EINVAL)?;
fseeko(fp, offset, whence)
}
#[no_mangle]
unsafe extern "C" fn fseeko(fp: *mut FILE, offset: off_t, whence: c_int) -> c_int {
todo!()
unsafe extern "C" fn fseeko(fp: *mut FILE, offset: off_t, whence: c_int) -> CIntZeroResult {
let seek = SeekFrom::e_try_from((offset, whence))?;
let fp = fp.ensure_mut();
fp.seek(seek)?;
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn fsetpos(fp: *mut FILE, pos: *const fpos_t) -> c_int {
todo!()
unsafe extern "C" fn fsetpos(fp: *mut FILE, pos: *const fpos_t) -> CIntZeroResult {
let fp = fp.ensure_mut();
let pos = *pos.ensure();
fp.seek(SeekFrom::Start(pos))?;
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn ftell(fp: *mut FILE) -> c_long {
todo!()
match ftello(fp) {
COffsetResult::ERROR => -1,
COffsetResult(off) => off,
}
}
#[no_mangle]
unsafe extern "C" fn ftello(fp: *mut FILE) -> off_t {
todo!()
unsafe extern "C" fn ftello(fp: *mut FILE) -> COffsetResult {
let fp = fp.ensure_mut();
let pos = fp.stream_position()?;
COffsetResult::success(pos)
}
#[no_mangle]
unsafe extern "C" fn ftrylockfile(fp: *mut FILE) -> c_int {
todo!()
unsafe extern "C" fn ftrylockfile(_fp: *mut FILE) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn funlockfile(fp: *mut FILE) {
todo!()
let fp = fp.ensure_mut();
fp.unlock();
}
#[no_mangle]
unsafe extern "C" fn open_memstream(
ptr: *mut *mut c_char,
sizeloc: *mut usize,
_ptr: *mut *mut c_char,
_sizeloc: *mut usize,
) -> CPtrResult<FILE> {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn pclose(_fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn pclose(fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn popen(command: *const c_char, ty: *const c_char) -> CPtrResult<FILE> {
unsafe extern "C" fn popen(_command: *const c_char, _ty: *const c_char) -> CPtrResult<FILE> {
todo!()
}
#[no_mangle]
unsafe extern "C" fn rewind(fp: *mut FILE) {
todo!()
fseek(fp, 0, SEEK_SET);
}
#[no_mangle]
unsafe extern "C" fn setbuf(fp: *mut FILE, buf: *mut c_char) {
todo!()
setbuffer(fp, buf, 0);
}
#[no_mangle]
unsafe extern "C" fn setbuffer(fp: *mut FILE, buf: *mut c_char, size: usize) {
let mode = if buf.is_null() { _IONBF } else { _IOFBF };
setvbuf(fp, buf, mode, size);
}
#[no_mangle]
unsafe extern "C" fn setlinebuf(fp: *mut FILE) {
setvbuf(fp, null_mut(), _IOLBF, 0);
}
#[no_mangle]
unsafe extern "C" fn setvbuf(
fp: *mut FILE,
buffer: *mut c_void,
buffer: *mut c_char,
mode: c_int,
size: usize,
) -> c_int {
todo!()
) -> CIntZeroResult {
let fp = fp.ensure_mut();
fp.setvbuf(mode, buffer, size)?;
CIntZeroResult::SUCCESS
}

View File

@ -0,0 +1,280 @@
// get*
use core::{
ffi::{c_char, c_int},
ptr::{null_mut, NonNull},
};
use crate::{
allocator,
error::{CEofResult, CIsizeResult, CPtrResult, CResult, EResult},
headers::errno,
io::{
managed::{stdin, stdout, FILE},
Read, Write,
},
util::{PointerExt, PointerStrExt},
};
#[no_mangle]
unsafe extern "C" fn fgetc(fp: *mut FILE) -> CEofResult {
let fp = fp.ensure_mut();
let mut buf = [0];
fp.read_exact(&mut buf)?;
CEofResult::success(buf[0] as _)
}
#[no_mangle]
unsafe extern "C" fn fgets(s: *mut c_char, size: c_int, fp: *mut FILE) -> CPtrResult<c_char> {
let fp = fp.ensure_mut();
let mut s = NonNull::new(s).unwrap();
if size <= 0 {
return CPtrResult::ERROR;
}
// Nothing to read
if size == 1 {
*s.as_mut() = 0;
return CPtrResult::success(s);
}
let size = size as usize;
let mut pos = 0;
let mut buf = [0];
let slice = NonNull::slice_from_raw_parts(s, size).as_mut();
while pos < size - 1 {
let ch = match fp.read(&mut buf)? {
1 => buf[0],
_ => break,
};
slice[pos] = ch as _;
pos += 1;
if ch == b'\n' {
break;
}
}
if pos == 0 {
CPtrResult::ERROR
} else {
slice[pos] = 0;
CPtrResult::success(s)
}
}
#[no_mangle]
unsafe extern "C" fn getc(fp: *mut FILE) -> CEofResult {
fgetc(fp)
}
#[no_mangle]
unsafe extern "C" fn getchar() -> CEofResult {
fgetc(stdin)
}
#[no_mangle]
unsafe extern "C" fn fgetc_unlocked(fp: *mut FILE) -> CEofResult {
let fp = fp.ensure_mut();
let mut buf = [0];
match fp.read_unlocked(&mut buf)? {
1 => CEofResult::success(buf[0] as _),
_ => CEofResult::ERROR,
}
}
#[no_mangle]
unsafe extern "C" fn getc_unlocked(fp: *mut FILE) -> CEofResult {
fgetc_unlocked(fp)
}
#[no_mangle]
unsafe extern "C" fn getchar_unlocked() -> CEofResult {
getc_unlocked(stdin)
}
// put*
#[no_mangle]
unsafe extern "C" fn fputc(ch: c_int, fp: *mut FILE) -> CEofResult {
let fp = fp.ensure_mut();
let ch = ch as u8;
fp.write_all(&[ch])?;
CEofResult::success(ch as c_int)
}
#[no_mangle]
unsafe extern "C" fn fputs(str: *const c_char, fp: *mut FILE) -> CEofResult {
let fp = fp.ensure_mut();
let str = str.ensure_cstr();
fp.write_all(str.to_bytes())?;
CEofResult::success(0)
}
#[no_mangle]
unsafe extern "C" fn putc(ch: c_int, fp: *mut FILE) -> CEofResult {
fputc(ch, fp)
}
#[no_mangle]
unsafe extern "C" fn putchar(ch: c_int) -> CEofResult {
fputc(ch, stdout)
}
#[no_mangle]
unsafe extern "C" fn putc_unlocked(ch: c_int, fp: *mut FILE) -> CEofResult {
let fp = fp.ensure_mut();
let ch = ch as u8;
match fp.write_unlocked(&[ch])? {
1 => CEofResult::success(ch as _),
_ => CEofResult::ERROR,
}
}
#[no_mangle]
unsafe extern "C" fn putchar_unlocked(ch: c_int) -> CEofResult {
putc_unlocked(ch, stdout)
}
#[no_mangle]
unsafe extern "C" fn puts(str: *const c_char) -> CEofResult {
let str = str.ensure_cstr();
let out = stdout.ensure_mut();
out.write_all(str.to_bytes())?;
out.write_all(b"\n")?;
CEofResult::success(0)
}
// ungetc
#[no_mangle]
unsafe extern "C" fn ungetc(ch: c_int, fp: *mut FILE) -> CEofResult {
let fp = fp.ensure_mut();
fp.ungetc(ch as _)?;
CEofResult::success(ch)
}
// getdelim
struct MallocBufferWriter {
buffer: Option<NonNull<c_char>>,
capacity: usize,
position: usize,
}
impl MallocBufferWriter {
unsafe fn new(buffer: Option<NonNull<c_char>>, mut capacity: usize) -> Self {
if buffer.is_none() {
capacity = 0;
}
Self {
buffer,
capacity,
position: 0,
}
}
fn try_reserve(&mut self) -> EResult<&mut c_char> {
if self.position == self.capacity {
self.capacity = (self.capacity + 64) & !63;
self.buffer = Some(
unsafe { allocator::c_realloc(self.buffer.map(NonNull::cast), self.capacity) }?
.cast(),
);
}
let buffer = self.buffer.unwrap();
EResult::Ok(unsafe { buffer.add(self.position).as_mut() })
}
fn putc(&mut self, ch: c_int) -> EResult<()> {
let item = self.try_reserve()?;
*item = ch as _;
self.position += 1;
EResult::Ok(())
}
}
fn getdelim_inner(
buffer: Option<NonNull<c_char>>,
capacity: usize,
delim: c_int,
stream: &mut FILE,
) -> (MallocBufferWriter, EResult<()>) {
let mut writer = unsafe { MallocBufferWriter::new(buffer, capacity) };
let mut buf = [0];
loop {
let ch = match stream.read(&mut buf) {
EResult::Ok(1) => buf[0] as c_int,
EResult::Ok(_) => break,
EResult::Err(err) => return (writer, EResult::Err(err)),
};
match writer.putc(ch) {
EResult::Ok(()) => (),
EResult::Err(err) => {
return (writer, EResult::Err(err));
}
}
if ch == delim {
break;
}
}
if writer.position == 0 {
// EOF reached before anything could be read
return (writer, EResult::Err(errno::ESUCCESS));
}
match writer.putc(0) {
EResult::Ok(()) => (),
EResult::Err(err) => {
return (writer, EResult::Err(err));
}
}
(writer, EResult::Ok(()))
}
#[no_mangle]
unsafe extern "C" fn getdelim(
lineptr: *mut *mut c_char,
n: *mut usize,
delim: c_int,
fp: *mut FILE,
) -> CIsizeResult {
let lineptr = lineptr.ensure_mut();
let buffer = NonNull::new(*lineptr);
let n = n.ensure_mut();
let fp = fp.ensure_mut();
let (writer, result) = getdelim_inner(buffer, *n, delim, fp);
match writer.buffer {
Some(buffer) => *lineptr = buffer.as_ptr(),
None => *lineptr = null_mut(),
}
*n = writer.capacity;
result?;
assert_ne!(writer.position, 0);
CIsizeResult::success(writer.position - 1)
}
#[no_mangle]
unsafe extern "C" fn getline(
lineptr: *mut *mut c_char,
size: *mut usize,
fp: *mut FILE,
) -> CIsizeResult {
getdelim(lineptr, size, b'\n' as _, fp)
}
#[no_mangle]
unsafe extern "C" fn gets(_buf: *mut c_char) -> *mut c_char {
unimplemented!("DO NOT USE")
}

View File

@ -1,31 +1,11 @@
use core::ffi::{c_char, c_int, c_void};
use core::{ffi::{c_char, c_int, c_void}, ptr::NonNull};
use crate::{
error::{CEofResult, CUsizeResult},
io::{managed::{stdout, FILE}, Read, Write},
error::{CEofResult, CPtrResult, CResult, CUsizeResult},
io::{managed::{stdin, stdout, FILE}, Read, Write},
util::{PointerExt, PointerStrExt},
};
#[no_mangle]
unsafe extern "C" fn fgetc(fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fgets(buf: *mut c_char, size: c_int, fp: *mut FILE) -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fputc(ch: c_int, fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fputs(str: *const c_char, fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fread(
buf: *mut c_void,
@ -54,76 +34,3 @@ unsafe extern "C" fn fwrite(
CUsizeResult::success(len)
}
#[no_mangle]
unsafe extern "C" fn getc(fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn getchar() -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn getc_unlocked(fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn getchar_unlocked() -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn getdelim(
lineptr: *mut *mut c_char,
size: *mut usize,
delim: c_int,
fp: *mut FILE,
) -> isize {
todo!()
}
#[no_mangle]
unsafe extern "C" fn getline(lineptr: *mut *mut c_char, size: *mut usize, fp: *mut FILE) -> isize {
todo!()
}
#[no_mangle]
unsafe extern "C" fn gets(buf: *mut c_char) -> *mut c_char {
todo!()
}
#[no_mangle]
unsafe extern "C" fn putc(ch: c_int, fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn putchar(ch: c_int) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn putc_unlocked(ch: c_int, fp: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn putchar_unlocked(ch: c_int) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn puts(str: *const c_char) -> CEofResult {
let str = str.ensure_cstr();
let out = stdout.ensure_mut();
out.write_all(str.to_bytes())?;
out.write_all(b"\n")?;
CEofResult::success(0)
}
#[no_mangle]
unsafe extern "C" fn ungetc(ch: c_int, fp: *mut FILE) -> c_int {
todo!()
}

View File

@ -1,11 +1,20 @@
use core::ffi::c_int;
mod file;
mod get_put;
mod io;
mod printf;
mod scanf;
mod file;
mod io;
mod util;
// includes:
// va_list from <stdarg.h>
// FILE from <bits/stdio.h>
// size_t from <stddef.h>
// ssize_t from <sys/types.h>
//
// stdin, stdout, stderr as externs from <bits/stdio.h>
pub const _IOFBF: c_int = 0;
pub const _IOLBF: c_int = 1;
pub const _IONBF: c_int = 2;
@ -14,6 +23,8 @@ pub const SEEK_SET: c_int = 0;
pub const SEEK_CUR: c_int = 1;
pub const SEEK_END: c_int = 2;
pub const FILENAME_MAX: usize = 4096;
pub const FOPEN_MAX: usize = 4096;
pub const TMP_MAX: usize = 216000;
pub const EOF: c_int = -1;
@ -22,4 +33,4 @@ pub type fpos_t = u64;
pub const BUFSIZ: usize = 8192;
const UNGETC_MAX: usize = 128;
pub const UNGETC_MAX: usize = 128;

View File

@ -1,35 +1,50 @@
use core::ffi::{c_char, c_int};
use crate::{error::CPtrResult, io::managed::FILE};
use crate::{
error::{self, CPtrResult},
io::managed::{stderr, FILE},
util::{PointerExt, PointerStrExt},
};
#[no_mangle]
unsafe extern "C" fn perror(message: *const c_char) {
let out = stderr.ensure_mut();
out.lock();
if !message.is_null() {
let message = message.ensure_cstr();
out.write_unlocked(message.to_bytes()).ok();
out.write_unlocked(b": ").ok();
}
out.write_unlocked(error::errno.to_c_str().to_bytes()).ok();
out.write_unlocked(b"\n").ok();
out.unlock();
}
#[no_mangle]
unsafe extern "C" fn ctermid(_buf: *mut c_char) -> *mut c_char {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn remove(_path: *const c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn ctermid(buf: *mut c_char) -> *mut c_char {
unsafe extern "C" fn rename(_src: *const c_char, _dst: *const c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn remove(path: *const c_char) -> c_int {
unsafe extern "C" fn renameat(_atfd: c_int, _src: *const c_char, _dst: *const c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn rename(src: *const c_char, dst: *const c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn renameat(atfd: c_int, src: *const c_char, dst: *const c_char) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn tempnam(dir: *const c_char, prefix: *const c_char) -> *mut c_char {
unsafe extern "C" fn tempnam(_dir: *const c_char, _prefix: *const c_char) -> *mut c_char {
todo!()
}
@ -39,6 +54,6 @@ unsafe extern "C" fn tmpfile() -> CPtrResult<FILE> {
}
#[no_mangle]
unsafe extern "C" fn tmpnam(template: *mut c_char) -> *mut c_char {
unsafe extern "C" fn tmpnam(_template: *mut c_char) -> *mut c_char {
todo!()
}

View File

@ -1,11 +1,11 @@
use core::{
cmp::Ordering,
ffi::{c_char, c_int},
ptr::null_mut,
ptr::{null_mut, NonNull},
};
use crate::{
allocator,
allocator::{self, malloc},
error::CPtrResult,
headers::{
errno::{self, Errno},
@ -20,7 +20,7 @@ unsafe extern "C" fn stpcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char
if dst.is_null() || src.is_null() {
panic!();
}
let ptr = mempcpy(dst as _, src as _, strlen(src)) as *mut c_char;
let ptr = mempcpy(dst.cast(), src.cast(), strlen(src)).cast::<c_char>();
*ptr = 0;
ptr
}
@ -30,8 +30,8 @@ unsafe extern "C" fn stpncpy(dst: *mut c_char, src: *const c_char, n: usize) ->
if dst.is_null() || src.is_null() {
panic!();
}
memset(dst as _, 0, n);
mempcpy(dst as _, src as _, strnlen(src, n)) as _
memset(dst.cast(), 0, n);
mempcpy(dst.cast(), src.cast(), strnlen(src, n)).cast()
}
#[no_mangle]
@ -51,7 +51,7 @@ unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
loop {
if *s == c as _ {
return s as _;
return s.cast_mut();
}
if *s == 0 {
@ -95,13 +95,13 @@ unsafe extern "C" fn strcspn(mut s: *const c_char, reject: *const c_char) -> usi
unsafe extern "C" fn strdup(s: *const c_char) -> CPtrResult<c_char> {
let len = strlen(s);
let data = allocator::c_alloc(len + 1, 1, false)?;
memcpy(data.cast().as_ptr(), s as _, len + 1);
memcpy(data.cast().as_ptr(), s.cast(), len + 1);
CPtrResult::success(data.cast())
}
unsafe fn strerror_inner(e: c_int) -> *const c_char {
if let Some(errno) = Errno::from_c_int(e) {
errno.to_c_str()
errno.to_c_str().as_ptr()
} else {
errno::UNKNOWN_ERROR.as_ptr()
}
@ -127,7 +127,7 @@ unsafe extern "C" fn strncat(dst: *mut c_char, src: *const c_char, n: usize) ->
}
let len = strnlen(src, n);
let ptr = dst.add(strlen(dst));
let ptr = mempcpy(ptr as _, src as _, len) as *mut c_char;
let ptr = mempcpy(ptr.cast(), src.cast(), len).cast::<c_char>();
*ptr = 0;
dst
@ -171,8 +171,13 @@ unsafe extern "C" fn strncpy(dst: *mut c_char, src: *const c_char, n: usize) ->
}
#[no_mangle]
unsafe extern "C" fn strndup(s: *const c_char, n: usize) -> *mut c_char {
todo!()
unsafe extern "C" fn strndup(s: *const c_char, n: usize) -> CPtrResult<c_char> {
let src = NonNull::new(s.cast_mut()).unwrap();
let len = strnlen(s, n);
let dst = malloc(len + 1)?.cast();
dst.copy_from_nonoverlapping(src, len);
dst.add(len).write(0);
CPtrResult::success(dst)
}
#[no_mangle]
@ -203,7 +208,7 @@ unsafe extern "C" fn strpbrk(mut a: *const c_char, b: *const c_char) -> *mut c_c
}
if !strchr(b, c as _).is_null() {
return a as _;
return a.cast_mut();
}
a = a.add(1);
@ -221,7 +226,7 @@ unsafe extern "C" fn strrchr(a: *const c_char, c: c_int) -> *mut c_char {
let n = strnlen(a, usize::MAX);
for i in (0..n).rev() {
if *a.add(i) == c as _ {
return a.add(i) as _;
return a.add(i).cast_mut();
}
}
@ -229,7 +234,7 @@ unsafe extern "C" fn strrchr(a: *const c_char, c: c_int) -> *mut c_char {
}
#[no_mangle]
unsafe extern "C" fn strsignal(signum: c_int) -> *mut c_char {
unsafe extern "C" fn strsignal(_signum: c_int) -> *mut c_char {
todo!()
}
@ -256,12 +261,12 @@ unsafe extern "C" fn strstr(mut a: *const c_char, b: *const c_char) -> *mut c_ch
}
let n = strnlen(b, usize::MAX);
if *a == 0 && *b == 0 {
return a as _;
return a.cast_mut();
}
while *a != 0 {
if strncmp(a, b, n) == 0 {
return a as _;
return a.cast_mut();
}
a = a.add(1);
}
@ -306,31 +311,31 @@ unsafe extern "C" fn strtok_r(
*saveptr = null_mut();
}
*str.add(len) = 0;
str as _
str.cast()
}
// TODO locales
#[no_mangle]
unsafe extern "C" fn strcoll(a: *const c_char, b: *const c_char) -> c_int {
todo!()
unsafe extern "C" fn strcoll(_a: *const c_char, _b: *const c_char) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn strcoll_l(a: *const c_char, b: *const c_char, l: locale_t) -> c_int {
todo!()
unsafe extern "C" fn strcoll_l(_a: *const c_char, _b: *const c_char, _l: locale_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn strerror_l(e: c_int, l: locale_t) -> *mut c_char {
todo!()
unsafe extern "C" fn strerror_l(_e: c_int, _l: locale_t) -> *mut c_char {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn strxfrm(a: *mut c_char, b: *const c_char, n: usize) -> usize {
todo!()
unsafe extern "C" fn strxfrm(_a: *mut c_char, _b: *const c_char, _n: usize) -> usize {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn strxfrm_l(a: *mut c_char, b: *const c_char, n: usize, l: locale_t) -> usize {
todo!()
unsafe extern "C" fn strxfrm_l(_a: *mut c_char, _b: *const c_char, _n: usize, _l: locale_t) -> usize {
unimplemented!()
}

View File

@ -1,10 +1,13 @@
#![allow(non_upper_case_globals)]
use core::{
fmt, ops::{Deref, DerefMut}, ptr::{null_mut, NonNull}
ffi::{c_char, c_int},
fmt,
ops::{Deref, DerefMut},
ptr::{null_mut, NonNull},
};
use alloc::{boxed::Box, collections::btree_set::BTreeSet};
use alloc::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec};
use bitflags::bitflags;
use yggdrasil_rt::{
io::{FileMode, OpenOptions, RawFd, SeekFrom},
@ -12,15 +15,16 @@ use yggdrasil_rt::{
};
use crate::{
error::EResult,
headers::errno,
error::{EResult, TryFromExt},
headers::{
errno,
stdio::{BUFSIZ, UNGETC_MAX, _IOFBF, _IOLBF, _IONBF},
},
sync::{Mutex, RawMutex},
};
use super::{
buffer::{FileWriter, FullBufferedWriter, LineBufferedWriter, ReadBuffer, UnbufferedWriter},
raw::RawFile,
AsRawFd, FromRawFd, Read, Seek, Write,
buffer::{FileWriter, FullBufferedWriter, LineBufferedWriter, ReadBuffer, UnbufferedWriter}, raw::RawFile, AsRawFd, BufRead, FromRawFd, Read, Seek, Write
};
macro locked_op($self:expr, $op:expr) {{
@ -50,6 +54,12 @@ pub enum BufferingMode {
None,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Direction {
Read,
Write
}
pub enum FileBacking {
File(ManagedFile),
}
@ -67,6 +77,13 @@ pub struct FILE {
write_buffer: Box<dyn FileWriter>,
flags: FileFlags,
ungetc: Vec<u8>,
// NOTE:
// man setvbuf(3):
// The setvbuf() function may be used only after opening a stream and
// before any other operations have been performed on it.
last_operation: Option<Direction>
}
// ManagedFile
@ -191,8 +208,8 @@ impl FILE {
let write_buffer = backing.make_ref();
let write_buffer: Box<dyn FileWriter> = match buffering {
BufferingMode::None => Box::new(UnbufferedWriter::new(write_buffer)),
BufferingMode::Line => Box::new(LineBufferedWriter::with_capacity(write_buffer, 1024)),
BufferingMode::Full => Box::new(FullBufferedWriter::with_capacity(write_buffer, 1024)),
BufferingMode::Line => Box::new(LineBufferedWriter::with_capacity(write_buffer, BUFSIZ)),
BufferingMode::Full => Box::new(FullBufferedWriter::with_capacity(write_buffer, BUFSIZ)),
};
Self {
@ -203,6 +220,9 @@ impl FILE {
read_buffer: None,
flags,
ungetc: Vec::new(),
last_operation: None,
}
}
@ -238,22 +258,71 @@ impl FILE {
}
}
pub fn reset(&mut self) {
if let Some(read_buffer) = self.read_buffer.as_mut() {
read_buffer.reset();
pub fn fd(&self) -> Option<RawFd> {
match &self.inner {
FileBacking::File(file) => Some(file.as_raw_fd()),
}
self.write_buffer.reset();
self.flags &= !(FileFlags::ERROR | FileFlags::EOF);
}
unsafe fn read_unlocked(&mut self, data: &mut [u8]) -> EResult<usize> {
pub fn is_eof(&self) -> bool {
self.flags.contains(FileFlags::EOF)
}
pub fn is_error(&self) -> bool {
self.flags.contains(FileFlags::ERROR)
}
pub fn clear_error(&mut self) {
self.flags.remove(FileFlags::ERROR);
}
pub unsafe fn lock(&mut self) {
self.lock.lock();
}
pub unsafe fn unlock(&mut self) {
self.lock.release();
}
// pub fn reset(&mut self) {
// if let Some(read_buffer) = self.read_buffer.as_mut() {
// read_buffer.reset();
// }
// self.write_buffer.reset();
// self.flags &= !(FileFlags::ERROR | FileFlags::EOF);
// self.ungetc.clear();
// self.last_operation = None;
// }
pub fn setvbuf(&mut self, mode: c_int, buffer: *mut c_char, size: usize) -> EResult<()> {
locked_op!(self, self.setvbuf_unlocked(mode, buffer, size))
}
pub fn ungetc(&mut self, ch: u8) -> EResult<()> {
locked_op!(self, self.ungetc_unlocked(ch))
}
pub unsafe fn read_unlocked(&mut self, data: &mut [u8]) -> EResult<usize> {
if !self.flags.contains(FileFlags::READ) {
self.flags |= FileFlags::ERROR;
return EResult::Err(errno::EBADF);
}
self.set_direction(Direction::Read)?;
if !self.ungetc.is_empty() {
let amount = core::cmp::min(self.ungetc.len(), data.len());
data[..amount].copy_from_slice(&self.ungetc[..amount]);
self.ungetc.drain(..amount);
return EResult::Ok(amount);
}
if self.read_buffer.is_some() {
todo!()
let buf = self.fill_buf()?;
let len = core::cmp::min(data.len(), buf.len());
data[..len].copy_from_slice(&buf[..len]);
self.consume(len);
EResult::Ok(len)
} else {
match self.inner.read(data) {
EResult::Ok(0) => {
@ -269,12 +338,14 @@ impl FILE {
}
}
unsafe fn write_unlocked(&mut self, data: &[u8]) -> EResult<usize> {
pub unsafe fn write_unlocked(&mut self, data: &[u8]) -> EResult<usize> {
if !self.flags.contains(FileFlags::WRITE) {
self.flags |= FileFlags::ERROR;
return EResult::Err(errno::EBADF);
}
self.set_direction(Direction::Write)?;
match self.write_buffer.write(data) {
EResult::Ok(len) => EResult::Ok(len),
EResult::Err(err) => {
@ -285,19 +356,115 @@ impl FILE {
}
unsafe fn flush_unlocked(&mut self) -> EResult<()> {
if !self.flags.contains(FileFlags::WRITE) {
self.flags |= FileFlags::ERROR;
return EResult::Err(errno::EBADF);
}
self.ungetc.clear();
self.last_operation = None;
match self.write_buffer.flush() {
EResult::Ok(()) => EResult::Ok(()),
EResult::Ok(()) => {
EResult::Ok(())
},
EResult::Err(err) => {
self.flags |= FileFlags::ERROR;
EResult::Err(err)
}
}
}
unsafe fn seek_unlocked(&mut self, off: SeekFrom) -> EResult<u64> {
self.flush_unlocked()?;
match self.inner.seek(off) {
EResult::Ok(pos) => {
self.flags &= !FileFlags::EOF;
EResult::Ok(pos)
}
EResult::Err(err) => {
self.flags |= FileFlags::ERROR;
EResult::Err(err)
}
}
}
unsafe fn ungetc_unlocked(&mut self, ch: u8) -> EResult<()> {
// ungetc() for write doesn't make any sense
self.set_direction(Direction::Read)?;
if self.ungetc.len() == UNGETC_MAX {
return EResult::Err(errno::ENOMEM);
}
self.ungetc.push(ch);
EResult::Ok(())
}
unsafe fn setvbuf_unlocked(
&mut self,
mode: c_int,
buffer: *mut c_char,
capacity: usize,
) -> EResult<()> {
let mode = BufferingMode::e_try_from(mode)?;
if self.last_operation.is_some() {
self.flags |= FileFlags::ERROR;
return EResult::Err(errno::EINVAL);
}
self.ungetc.clear();
let mut read_capacity = capacity;
let mut write_capacity = capacity;
// Set read buffer
match mode {
BufferingMode::None => self.read_buffer = None,
BufferingMode::Line | BufferingMode::Full => {
if buffer.is_null() {
if read_capacity == 0 {
read_capacity = BUFSIZ;
}
self.read_buffer = Some(ReadBuffer::owned(read_capacity));
} else {
assert_ne!(read_capacity, 0);
let slice =
unsafe { core::slice::from_raw_parts_mut(buffer.cast(), read_capacity) };
self.read_buffer = Some(ReadBuffer::borrowed(slice));
}
}
}
// Set write buffer
let file_ref = unsafe { self.inner.make_ref() };
match mode {
BufferingMode::None => self.write_buffer = Box::new(UnbufferedWriter::new(file_ref)),
BufferingMode::Line => {
if write_capacity == 0 {
write_capacity = BUFSIZ;
}
self.write_buffer =
Box::new(LineBufferedWriter::with_capacity(file_ref, write_capacity));
}
BufferingMode::Full => {
if write_capacity == 0 {
write_capacity = BUFSIZ;
}
self.write_buffer =
Box::new(FullBufferedWriter::with_capacity(file_ref, write_capacity));
}
}
EResult::Ok(())
}
unsafe fn set_direction(&mut self, direction: Direction) -> EResult<()> {
match self.last_operation.replace(direction) {
Some(dir) if dir != direction => {
self.flags |= FileFlags::ERROR;
EResult::Err(errno::EINVAL)
},
_ => EResult::Ok(())
}
}
}
impl Read for FILE {
@ -316,6 +483,35 @@ impl Write for FILE {
}
}
impl Seek for FILE {
fn seek(&mut self, pos: SeekFrom) -> EResult<u64> {
locked_op!(self, self.seek_unlocked(pos))
}
}
impl BufRead for FILE {
fn fill_buf(&mut self) -> EResult<&[u8]> {
let buffer = self.read_buffer.as_mut().unwrap();
match buffer.fill_from(&mut self.inner) {
EResult::Ok(slice) => {
if slice.is_empty() {
self.flags |= FileFlags::EOF;
}
EResult::Ok(slice)
}
EResult::Err(err) => {
self.flags |= FileFlags::ERROR;
EResult::Err(err)
}
}
}
fn consume(&mut self, amount: usize) {
let buffer = self.read_buffer.as_mut().unwrap();
buffer.consume(amount);
}
}
impl FileOpenSource for &Path {
fn open_with(self, opts: OpenOptions) -> EResult<FILE> {
let f = ManagedFile::open_at(None, self, opts, FileMode::default_file())?;
@ -330,9 +526,35 @@ impl FileOpenSource for &Path {
}
}
impl FileOpenSource for RawFd {
fn open_with(self, opts: OpenOptions) -> EResult<FILE> {
let f = unsafe { RawFile::from_raw_fd(self) };
let mut flags = FileFlags::empty();
if opts.contains(OpenOptions::READ) {
flags |= FileFlags::READ;
}
if opts.contains(OpenOptions::WRITE) {
flags |= FileFlags::WRITE;
}
EResult::Ok(unsafe { FILE::from_raw_file(f, flags) })
}
}
impl fmt::Write for FILE {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.write_all(s.as_bytes()).into_result(|_| fmt::Error, true)
self.write_all(s.as_bytes())
.into_result(|_| fmt::Error, true)
}
}
impl TryFromExt<c_int> for BufferingMode {
fn e_try_from(value: c_int) -> EResult<Self> {
match value {
_IOFBF => EResult::Ok(Self::Full),
_IOLBF => EResult::Ok(Self::Line),
_IONBF => EResult::Ok(Self::None),
_ => EResult::Err(errno::EINVAL),
}
}
}

View File

@ -1,4 +1,4 @@
use core::{ffi::c_int, mem::MaybeUninit};
use core::{ffi::{c_int, c_long}, mem::MaybeUninit};
use yggdrasil_rt::{io::{PipeOptions, RawFd, SeekFrom}, sys as syscall};
@ -46,10 +46,27 @@ pub trait Write {
pub trait Read {
fn read(&mut self, data: &mut [u8]) -> EResult<usize>;
fn read_exact(&mut self, buf: &mut [u8]) -> EResult<()> {
match self.read(buf) {
EResult::Ok(n) if n == buf.len() => EResult::Ok(()),
EResult::Ok(_) => todo!(),
EResult::Err(err) => EResult::Err(err)
}
}
}
pub trait BufRead {
fn fill_buf(&mut self) -> EResult<&[u8]>;
fn consume(&mut self, amount: usize);
}
pub trait Seek {
fn seek(&mut self, pos: SeekFrom) -> EResult<u64>;
fn stream_position(&mut self) -> EResult<u64> {
self.seek(SeekFrom::Current(0))
}
}
pub trait FromRawFd {