303 lines
7.4 KiB
Rust
303 lines
7.4 KiB
Rust
use core::{
|
|
ffi::{c_char, c_int, c_long, c_void, CStr},
|
|
ptr::null_mut,
|
|
};
|
|
|
|
use alloc::boxed::Box;
|
|
use yggdrasil_rt::{
|
|
io::{OpenOptions, RawFd, SeekFrom},
|
|
path::Path,
|
|
};
|
|
|
|
use crate::{
|
|
error::{CSizeResult, CZeroResult},
|
|
header::{errno::Errno, sys_types::off_t},
|
|
io::{Read, Seek, Write},
|
|
};
|
|
|
|
use super::{
|
|
fpos_t, FileFlags, FileOpenSource, FILE, SEEK_CUR, SEEK_END, SEEK_SET, _IOFBF, _IOLBF, _IONBF,
|
|
};
|
|
|
|
fn open_inner<O: FileOpenSource>(source: O, mode_str: &[u8]) -> Result<*mut FILE, Errno> {
|
|
let opts = match mode_str {
|
|
b"r" | b"rb" => OpenOptions::READ,
|
|
b"r+" | b"rb+" => OpenOptions::READ | OpenOptions::WRITE,
|
|
b"w" | b"wb" => OpenOptions::TRUNCATE | OpenOptions::WRITE,
|
|
b"w+" | b"wb+" => OpenOptions::TRUNCATE | OpenOptions::READ | OpenOptions::WRITE,
|
|
b"a" | b"ab" => OpenOptions::APPEND | OpenOptions::READ | OpenOptions::WRITE,
|
|
b"a+" | b"ab+" => OpenOptions::APPEND | OpenOptions::READ | OpenOptions::WRITE,
|
|
// TODO: errno and fail
|
|
_ => todo!(),
|
|
};
|
|
|
|
match source.open_with(opts) {
|
|
Ok(file) => {
|
|
let file = Box::into_raw(Box::new(file));
|
|
unsafe {
|
|
super::register_file(file);
|
|
}
|
|
Ok(file)
|
|
}
|
|
Err(err) => Err(err),
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn ctermid(buffer: *mut c_char) -> *mut c_char {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) -> *mut FILE {
|
|
if pathname.is_null() || mode.is_null() {
|
|
panic!();
|
|
}
|
|
let pathname = CStr::from_ptr(pathname);
|
|
let pathname = pathname.to_str().unwrap();
|
|
let mode = CStr::from_ptr(mode);
|
|
|
|
open_inner(Path::from_str(pathname), mode.to_bytes()).unwrap_or(null_mut())
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE {
|
|
if fd < 0 || mode.is_null() {
|
|
panic!();
|
|
}
|
|
let mode = CStr::from_ptr(mode);
|
|
|
|
open_inner(RawFd(fd as u32), mode.to_bytes()).unwrap_or(null_mut())
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn freopen(
|
|
pathname: *const c_char,
|
|
mode: *const c_char,
|
|
stream: *mut FILE,
|
|
) -> *mut FILE {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn feof(stream: *mut FILE) -> c_int {
|
|
let stream = stream.as_mut().unwrap();
|
|
stream.has_flag(FileFlags::EOF) as _
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn ferror(stream: *mut FILE) -> c_int {
|
|
let stream = stream.as_mut().unwrap();
|
|
stream.has_flag(FileFlags::ERROR) as _
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn clearerr(stream: *mut FILE) {
|
|
let stream = stream.as_mut().unwrap();
|
|
stream.clear_error();
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fclose(stream: *mut FILE) -> c_int {
|
|
if stream.is_null() {
|
|
panic!();
|
|
}
|
|
|
|
if !super::deregister_file(stream) {
|
|
yggdrasil_rt::debug_trace!("fclose() non-registered file: {:p}", stream);
|
|
}
|
|
|
|
stream.close().into_eof_status()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fileno(stream: *mut FILE) -> c_int {
|
|
let stream = stream.as_mut().unwrap();
|
|
match stream.as_raw_fd() {
|
|
Ok(RawFd(fd)) => fd as _,
|
|
Err(_) => -1,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fwrite(
|
|
ptr: *const c_void,
|
|
size: usize,
|
|
nmemb: usize,
|
|
stream: *mut FILE,
|
|
) -> usize {
|
|
if ptr.is_null() {
|
|
panic!();
|
|
}
|
|
let stream = stream.as_mut().unwrap();
|
|
let data = core::slice::from_raw_parts(ptr as *const u8, size * nmemb);
|
|
|
|
stream.write(data).into_size_status() / size
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fread(
|
|
ptr: *mut c_void,
|
|
size: usize,
|
|
nmemb: usize,
|
|
stream: *mut FILE,
|
|
) -> usize {
|
|
if ptr.is_null() {
|
|
panic!();
|
|
}
|
|
let stream = stream.as_mut().unwrap();
|
|
let data = core::slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb);
|
|
|
|
stream.read(data).into_size_status() / size
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int {
|
|
if let Some(stream) = stream.as_mut() {
|
|
stream.flush().into_eof_status()
|
|
} else {
|
|
super::fflush_all().into_eof_status()
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int {
|
|
fseeko(stream, offset.try_into().unwrap(), whence)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) -> c_int {
|
|
let stream = stream.as_mut().unwrap();
|
|
let off = match whence {
|
|
SEEK_SET => SeekFrom::Start(offset.try_into().unwrap()),
|
|
SEEK_CUR => SeekFrom::Current(offset),
|
|
SEEK_END => SeekFrom::End(offset),
|
|
// TODO set errno and fail
|
|
_ => todo!(),
|
|
};
|
|
|
|
match stream.seek(off) {
|
|
Ok(_) => 0,
|
|
Err(_) => -1,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
|
|
ftello(stream).try_into().unwrap()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t {
|
|
let stream = stream.as_mut().unwrap();
|
|
match stream.stream_position() {
|
|
Ok(p) => p.try_into().unwrap(),
|
|
Err(_) => -1,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn rewind(stream: *mut FILE) {
|
|
fseek(stream, 0, SEEK_SET);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int {
|
|
let stream = stream.as_mut().unwrap();
|
|
let pos = pos.as_mut().unwrap();
|
|
match stream.stream_position() {
|
|
Ok(p) => {
|
|
*pos = p;
|
|
0
|
|
}
|
|
Err(_) => -1,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int {
|
|
let stream = stream.as_mut().unwrap();
|
|
let pos = pos.as_ref().unwrap();
|
|
match stream.seek(SeekFrom::Start(*pos as _)) {
|
|
Ok(_) => 0,
|
|
Err(_) => -1,
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn setvbuf(
|
|
stream: *mut FILE,
|
|
buf: *mut c_char,
|
|
mode: c_int,
|
|
size: usize,
|
|
) -> c_int {
|
|
let stream = stream.as_mut().unwrap();
|
|
stream.setvbuf(mode, buf, size).into_eof_status()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn setbuf(stream: *mut FILE, buf: *mut c_char) {
|
|
setbuffer(stream, buf, 0);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn setbuffer(stream: *mut FILE, buf: *mut c_char, size: usize) {
|
|
let mode = if buf.is_null() { _IONBF } else { _IOFBF };
|
|
setvbuf(stream, buf, mode, size);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn setlinebuf(stream: *mut FILE) {
|
|
setvbuf(stream, null_mut(), _IOLBF, 0);
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn fmemopen(buffer: *mut c_void, size: usize, mode: *mut c_char) -> *mut FILE {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn open_memstream(bufptr: *mut *mut c_char, sizeptr: *mut usize) -> *mut FILE {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn pclose(stream: *mut FILE) -> c_int {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn remove(pathname: *const c_char) -> c_int {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn rename(oldname: *const c_char, newname: *const c_char) -> c_int {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn renameat(fd: c_int, oldname: *const c_char, newname: *const c_char) -> c_int {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn tempnam(dir: *const c_char, pfx: *const c_char) -> *mut c_char {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn tmpfile() -> *mut FILE {
|
|
todo!()
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn tmpnam(template: *mut c_char) -> *mut c_char {
|
|
todo!()
|
|
}
|