stdio: almost fully implemented
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 = []
|
||||
@@ -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;
|
||||
@@ -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,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"
|
||||
|
||||
@@ -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!()
|
||||
}
|
||||
|
||||
@@ -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
@@ -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_;
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -29,7 +29,7 @@ impl RawMutex {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_lock(&self) -> bool {
|
||||
pub fn try_lock(&self) -> bool {
|
||||
self.value
|
||||
.compare_exchange(
|
||||
Self::UNLOCKED,
|
||||
|
||||
Reference in New Issue
Block a user