Files
ygglibc/src/header/stdio/file.rs
T

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!()
}