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 sscanf(const char *str, const char *format, ...);
|
||||||
int fscanf(FILE *stream, 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
|
#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 sys_wait;
|
||||||
|
|
||||||
pub mod errno;
|
pub mod errno;
|
||||||
|
pub mod limits;
|
||||||
pub mod locale;
|
pub mod locale;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod stdio;
|
pub mod stdio;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
language = "C"
|
language = "C"
|
||||||
style = "Type"
|
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
|
no_includes = true
|
||||||
|
|
||||||
include_guard = "_STDIO_H"
|
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]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) -> *mut FILE {
|
pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) -> *mut FILE {
|
||||||
if pathname.is_null() || mode.is_null() {
|
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 pathname = pathname.to_str().unwrap();
|
||||||
let mode = CStr::from_ptr(mode);
|
let mode = CStr::from_ptr(mode);
|
||||||
|
|
||||||
match open_inner(Path::from_str(pathname), mode.to_bytes()) {
|
open_inner(Path::from_str(pathname), mode.to_bytes()).unwrap_or(null_mut())
|
||||||
Ok(file) => file,
|
}
|
||||||
Err(_) => 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]
|
#[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) {
|
pub unsafe extern "C" fn setlinebuf(stream: *mut FILE) {
|
||||||
setvbuf(stream, null_mut(), _IOLBF, 0);
|
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::{
|
use crate::{
|
||||||
header::stdlib::realloc,
|
error,
|
||||||
|
header::{stdlib::realloc, string::strlen},
|
||||||
io::{Read, Write},
|
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
|
// Chars
|
||||||
|
|
||||||
|
|||||||
+48
-52
@@ -20,45 +20,11 @@ use crate::{
|
|||||||
sync::{Mutex, RawMutex},
|
sync::{Mutex, RawMutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::errno::Errno;
|
use super::{errno::Errno, limits};
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// L_ctermid
|
// L_ctermid
|
||||||
// L_tmpnam
|
// 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 {
|
macro_rules! locked_op {
|
||||||
($self:expr, $op:expr) => {{
|
($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));
|
let inner = FileBacking::File(File::new(fd));
|
||||||
Self {
|
Self {
|
||||||
lock: RawMutex::new(),
|
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,
|
inner,
|
||||||
read_buffer: Some(ReadBuffer::owned(BUFSIZ)),
|
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 {
|
pub fn ungetc(&mut self, ch: u8) -> bool {
|
||||||
locked_op!(self, self.ungetc_unlocked(ch))
|
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) {
|
fn reset(&mut self) {
|
||||||
if let Some(read_buffer) = self.read_buffer.as_mut() {
|
if let Some(read_buffer) = self.read_buffer.as_mut() {
|
||||||
read_buffer.reset();
|
read_buffer.reset();
|
||||||
@@ -367,6 +337,18 @@ impl FILE {
|
|||||||
_ => Ok(()),
|
_ => 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 {
|
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_CUR: c_int = 1;
|
||||||
pub const SEEK_END: c_int = 2;
|
pub const SEEK_END: c_int = 2;
|
||||||
|
|
||||||
|
pub const TMP_MAX: usize = 216000;
|
||||||
|
|
||||||
pub const EOF: c_int = -1;
|
pub const EOF: c_int = -1;
|
||||||
|
|
||||||
pub type fpos_t = u64;
|
pub type fpos_t = u64;
|
||||||
@@ -494,9 +478,21 @@ pub unsafe fn deregister_file(file: *mut FILE) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn setup_default_files() {
|
pub unsafe fn setup_default_files() {
|
||||||
let stdin_ = Box::into_raw(Box::new(FILE::new_builtin(RawFd::STDIN, FileFlags::READ)));
|
let stdin_ = Box::into_raw(Box::new(FILE::new_builtin(
|
||||||
let stdout_ = Box::into_raw(Box::new(FILE::new_builtin(RawFd::STDOUT, FileFlags::WRITE)));
|
RawFd::STDIN,
|
||||||
let stderr_ = Box::into_raw(Box::new(FILE::new_builtin(RawFd::STDERR, FileFlags::WRITE)));
|
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_;
|
stdin = stdin_;
|
||||||
stdout = stdout_;
|
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 yggdrasil_rt::io::RawFd;
|
||||||
|
|
||||||
use crate::error::{CSizeResult, CZeroResult};
|
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]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn feof_unlocked(stream: *mut FILE) -> c_int {
|
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#[no_mangle]
|
||||||
int getc_unlocked(FILE *stream);
|
pub unsafe extern "C" fn fgetc_unlocked(stream: *mut FILE) -> c_int {
|
||||||
int getchar_unlocked(void);
|
todo!()
|
||||||
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]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
|
pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
|
||||||
todo!()
|
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;
|
pub mod str;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn strlen(s: *const c_char) -> usize;
|
pub fn strlen(s: *const c_char) -> usize;
|
||||||
fn memset(a: *mut c_void, c: c_int, n: usize) -> *mut c_void;
|
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
|
self.value
|
||||||
.compare_exchange(
|
.compare_exchange(
|
||||||
Self::UNLOCKED,
|
Self::UNLOCKED,
|
||||||
|
|||||||
Reference in New Issue
Block a user