libc: ctype.h, most of stdio.h, string.h
This commit is contained in:
parent
98862b1e49
commit
0a904a21fe
7
userspace/lib/ygglibc/include/bits/ctype.h
Normal file
7
userspace/lib/ygglibc/include/bits/ctype.h
Normal 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
|
@ -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());
|
||||
|
@ -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>;
|
||||
|
15
userspace/lib/ygglibc/src/headers/ctype/cbindgen.toml
Normal file
15
userspace/lib/ygglibc/src/headers/ctype/cbindgen.toml
Normal 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]
|
161
userspace/lib/ygglibc/src/headers/ctype/mod.rs
Normal file
161
userspace/lib/ygglibc/src/headers/ctype/mod.rs
Normal 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!()
|
||||
}
|
@ -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> {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
280
userspace/lib/ygglibc/src/headers/stdio/get_put.rs
Normal file
280
userspace/lib/ygglibc/src/headers/stdio/get_put.rs
Normal 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")
|
||||
}
|
@ -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!()
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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!()
|
||||
}
|
||||
|
@ -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!()
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user