stdio: almost fully implemented

This commit is contained in:
2024-01-10 18:55:58 +02:00
parent 37bdd0f7fc
commit 121a746548
11 changed files with 248 additions and 72 deletions
+5
View File
@@ -11,4 +11,9 @@ int scanf(const char *format, ...);
int sscanf(const char *str, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
#define P_tmpdir "/tmp"
#define FILENAME_MAX PATH_MAX
#define FOPEN_MAX OPEN_MAX
#endif
+13
View File
@@ -0,0 +1,13 @@
language = "C"
style = "Type"
sys_includes = ["stddef.h", "stdint.h"]
no_includes = true
include_guard = "_LIMITS_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = []
+19
View File
@@ -0,0 +1,19 @@
// TODO take from yggdrasil-abi
pub const FILESIZEBITS: usize = 64;
pub const MAX_CANON: usize = 64;
pub const LINK_MAX: usize = 4096;
pub const NAME_MAX: usize = 255;
pub const PATH_MAX: usize = 4096;
pub const SYMLINK_MAX: usize = 4096;
pub const PIPE_BUF: usize = 4096;
pub const OPEN_MAX: u32 = u32::MAX - 1;
pub const STREAM_MAX: u32 = OPEN_MAX;
pub const PAGESIZE: usize = 4096;
pub const PAGE_SIZE: usize = PAGESIZE;
pub const ATEXIT_MAX: usize = 32;
+1
View File
@@ -4,6 +4,7 @@ pub mod sys_types;
pub mod sys_wait;
pub mod errno;
pub mod limits;
pub mod locale;
pub mod math;
pub mod stdio;
+1 -1
View File
@@ -1,7 +1,7 @@
language = "C"
style = "Type"
sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h"]
sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h", "limits.h"]
no_includes = true
include_guard = "_STDIO_H"
+74 -3
View File
@@ -43,6 +43,11 @@ fn open_inner<O: FileOpenSource>(source: O, mode_str: &[u8]) -> Result<*mut FILE
}
}
#[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() {
@@ -52,10 +57,26 @@ pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) ->
let pathname = pathname.to_str().unwrap();
let mode = CStr::from_ptr(mode);
match open_inner(Path::from_str(pathname), mode.to_bytes()) {
Ok(file) => file,
Err(_) => null_mut(),
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]
@@ -229,3 +250,53 @@ pub unsafe extern "C" fn setbuffer(stream: *mut FILE, buf: *mut c_char, size: us
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!()
}
+23 -2
View File
@@ -4,11 +4,32 @@ use core::{
};
use crate::{
header::stdlib::realloc,
error,
header::{stdlib::realloc, string::strlen},
io::{Read, Write},
};
use super::{stdin, stdout, EOF, FILE};
use super::{
stderr, stdin, stdout,
unlocked::{flockfile, fputc_unlocked, fputs_unlocked, funlockfile, fwrite_unlocked},
EOF, FILE,
};
#[no_mangle]
unsafe extern "C" fn perror(msg: *const c_char) {
flockfile(stderr);
if !msg.is_null() {
fputs_unlocked(msg, stderr);
fputc_unlocked(b':' as _, stderr);
fputc_unlocked(b' ' as _, stderr);
}
fputs_unlocked(error::errno.to_c_str(), stderr);
fputc_unlocked(b'\n' as _, stderr);
funlockfile(stderr);
}
// Chars
+48 -52
View File
@@ -20,45 +20,11 @@ use crate::{
sync::{Mutex, RawMutex},
};
use super::errno::Errno;
use super::{errno::Errno, limits};
// TODO:
// L_ctermid
// L_tmpnam
//
// SEEK_CUR
// SEEK_END
// SEEK_SET
//
// FILENAME_MAX
// FOPEN_MAX
// TMP_MAX
//
// EOF
//
// P_tmpdir
/*
char *ctermid(char *);
FILE *fdopen(int, const char *);
void flockfile(FILE *);
FILE *fmemopen(void *restrict, size_t, const char *restrict);
FILE *freopen(const char *restrict, const char *restrict,
FILE *restrict);
int ftrylockfile(FILE *);
void funlockfile(FILE *);
FILE *open_memstream(char **, size_t *);
int pclose(FILE *);
void perror(const char *);
FILE *popen(const char *, const char *);
int remove(const char *);
int rename(const char *, const char *);
int renameat(int, const char *, int, const char *);
char *tempnam(const char *, const char *);
FILE *tmpfile(void);
char *tmpnam(char *);
*/
macro_rules! locked_op {
($self:expr, $op:expr) => {{
@@ -139,12 +105,16 @@ impl FILE {
}
}
pub unsafe fn new_builtin(fd: RawFd, flags: FileFlags) -> Self {
pub unsafe fn new_builtin(fd: RawFd, flags: FileFlags, buffered: bool) -> Self {
let inner = FileBacking::File(File::new(fd));
Self {
lock: RawMutex::new(),
output: Box::new(LineWriter::with_capacity(inner.make_ref(), BUFSIZ)),
output: if buffered {
Box::new(LineWriter::with_capacity(inner.make_ref(), BUFSIZ))
} else {
Box::new(UnbufferedWriter::new(inner.make_ref()))
},
inner,
read_buffer: Some(ReadBuffer::owned(BUFSIZ)),
@@ -261,22 +231,22 @@ impl FILE {
}
}
unsafe fn ungetc_unlocked(&mut self, ch: u8) -> bool {
// ungetc() for write doesn't make any sense
if self.set_direction(Direction::Read).is_err() {
return false;
}
if self.ungetc.len() == UNGETC_MAX {
return false;
}
self.ungetc.push(ch);
true
}
pub fn ungetc(&mut self, ch: u8) -> bool {
locked_op!(self, self.ungetc_unlocked(ch))
}
pub fn lock(&mut self) {
self.lock.lock();
}
pub fn try_lock(&mut self) -> bool {
self.lock.try_lock()
}
pub unsafe fn unlock(&mut self) {
self.lock.release();
}
fn reset(&mut self) {
if let Some(read_buffer) = self.read_buffer.as_mut() {
read_buffer.reset();
@@ -367,6 +337,18 @@ impl FILE {
_ => Ok(()),
}
}
unsafe fn ungetc_unlocked(&mut self, ch: u8) -> bool {
// ungetc() for write doesn't make any sense
if self.set_direction(Direction::Read).is_err() {
return false;
}
if self.ungetc.len() == UNGETC_MAX {
return false;
}
self.ungetc.push(ch);
true
}
}
impl fmt::Write for FILE {
@@ -475,6 +457,8 @@ pub const SEEK_SET: c_int = 0;
pub const SEEK_CUR: c_int = 1;
pub const SEEK_END: c_int = 2;
pub const TMP_MAX: usize = 216000;
pub const EOF: c_int = -1;
pub type fpos_t = u64;
@@ -494,9 +478,21 @@ pub unsafe fn deregister_file(file: *mut FILE) -> bool {
}
pub unsafe fn setup_default_files() {
let stdin_ = Box::into_raw(Box::new(FILE::new_builtin(RawFd::STDIN, FileFlags::READ)));
let stdout_ = Box::into_raw(Box::new(FILE::new_builtin(RawFd::STDOUT, FileFlags::WRITE)));
let stderr_ = Box::into_raw(Box::new(FILE::new_builtin(RawFd::STDERR, FileFlags::WRITE)));
let stdin_ = Box::into_raw(Box::new(FILE::new_builtin(
RawFd::STDIN,
FileFlags::READ,
true,
)));
let stdout_ = Box::into_raw(Box::new(FILE::new_builtin(
RawFd::STDOUT,
FileFlags::WRITE,
true,
)));
let stderr_ = Box::into_raw(Box::new(FILE::new_builtin(
RawFd::STDERR,
FileFlags::WRITE,
false,
)));
stdin = stdin_;
stdout = stdout_;
+61 -11
View File
@@ -1,10 +1,31 @@
use core::ffi::{c_int, c_void};
use core::ffi::{c_char, c_int, c_void, CStr};
use yggdrasil_rt::io::RawFd;
use crate::error::{CSizeResult, CZeroResult};
use super::{FileFlags, FILE};
use super::{FileFlags, EOF, FILE};
#[no_mangle]
pub unsafe extern "C" fn flockfile(stream: *mut FILE) {
let stream = stream.as_mut().unwrap();
stream.lock();
}
#[no_mangle]
pub unsafe extern "C" fn ftrylockfile(stream: *mut FILE) -> c_int {
let stream = stream.as_mut().unwrap();
match stream.try_lock() {
true => 0,
false => -1,
}
}
#[no_mangle]
pub unsafe extern "C" fn funlockfile(stream: *mut FILE) {
let stream = stream.as_mut().unwrap();
stream.unlock();
}
#[no_mangle]
pub unsafe extern "C" fn feof_unlocked(stream: *mut FILE) -> c_int {
@@ -74,17 +95,46 @@ pub unsafe extern "C" fn fflush_unlocked(stream: *mut FILE) -> c_int {
}
}
/*
int getc_unlocked(FILE *stream);
int getchar_unlocked(void);
int putc_unlocked(int c, FILE *stream);
int putchar_unlocked(int c);
int fgetc_unlocked(FILE *stream);
int fputc_unlocked(int c, FILE *stream);
*/
#[no_mangle]
pub unsafe extern "C" fn fgetc_unlocked(stream: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
todo!()
}
#[no_mangle]
pub unsafe extern "C" fn getchar_unlocked() -> c_int {
todo!()
}
#[no_mangle]
pub unsafe extern "C" fn putchar_unlocked(c: c_char) -> c_int {
todo!()
}
#[no_mangle]
pub unsafe fn fputc_unlocked(c: c_int, stream: *mut FILE) -> c_int {
let stream = stream.as_mut().unwrap();
match stream.write_unlocked(&[c as u8]) {
Ok(_) => c,
Err(_) => EOF,
}
}
pub unsafe fn fputs_unlocked(s: *const c_char, stream: *mut FILE) -> c_int {
if s.is_null() {
panic!();
}
let s = CStr::from_ptr(s);
let stream = stream.as_mut().unwrap();
match stream.write_unlocked(s.to_bytes()) {
Ok(_) => 0,
Err(_) => EOF,
}
}
+2 -2
View File
@@ -4,6 +4,6 @@ pub mod mem;
pub mod str;
extern "C" {
fn strlen(s: *const c_char) -> usize;
fn memset(a: *mut c_void, c: c_int, n: usize) -> *mut c_void;
pub fn strlen(s: *const c_char) -> usize;
pub fn memset(a: *mut c_void, c: c_int, n: usize) -> *mut c_void;
}
+1 -1
View File
@@ -29,7 +29,7 @@ impl RawMutex {
}
}
fn try_lock(&self) -> bool {
pub fn try_lock(&self) -> bool {
self.value
.compare_exchange(
Self::UNLOCKED,