Skip to content
Snippets Groups Projects
Verified Commit afc1ff13 authored by jD91mZM2's avatar jD91mZM2
Browse files

Rewrite IO to use core-io library

parent aff35892
No related branches found
No related tags found
No related merge requests found
#ifndef _BITS_STDIO_H
#define _BITS_STDIO_H
#define EOF (-1)
#define BUFSIZ 1024
typedef struct FILE FILE;
int fprintf(FILE * stream, const char * fmt, ...);
......
use c_str::CStr;
use core::ops::Deref;
use header::fcntl::O_CREAT;
use header::unistd::{SEEK_SET, SEEK_CUR, SEEK_END};
use io;
......@@ -11,48 +12,70 @@ fn last_os_error() -> io::Error {
io::Error::from_raw_os_error(errno)
}
pub struct File(c_int);
pub struct File {
pub fd: c_int,
/// To avoid self referential FILE struct that needs both a reader and a writer,
/// make "reference" files that share fd but don't close on drop.
pub reference: bool
}
impl File {
pub fn new(fd: c_int) -> Self {
Self {
fd,
reference: false
}
}
pub fn open(path: &CStr, oflag: c_int) -> io::Result<Self> {
match Sys::open(path, oflag, 0) {
-1 => Err(last_os_error()),
ok => Ok(File(ok)),
ok => Ok(Self::new(ok)),
}
}
pub fn create(path: &CStr, oflag: c_int, mode: mode_t) -> io::Result<Self> {
match Sys::open(path, oflag | O_CREAT, mode) {
-1 => Err(last_os_error()),
ok => Ok(File(ok)),
ok => Ok(Self::new(ok)),
}
}
pub fn sync_all(&self) -> io::Result<()> {
match Sys::fsync(self.0) {
match Sys::fsync(self.fd) {
-1 => Err(last_os_error()),
_ok => Ok(()),
}
}
pub fn set_len(&self, size: u64) -> io::Result<()> {
match Sys::ftruncate(self.0, size as off_t) {
match Sys::ftruncate(self.fd, size as off_t) {
-1 => Err(last_os_error()),
_ok => Ok(()),
}
}
pub fn try_clone(&self) -> io::Result<Self> {
match Sys::dup(self.0) {
match Sys::dup(self.fd) {
-1 => Err(last_os_error()),
ok => Ok(File(ok)),
ok => Ok(Self::new(ok)),
}
}
/// Create a new file pointing to the same underlying descriptor. This file
/// will know it's a "reference" and won't close the fd. It will, however,
/// not prevent the original file from closing the fd.
pub unsafe fn get_ref(&self) -> Self {
Self {
fd: self.fd,
reference: false
}
}
}
impl io::Read for File {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match Sys::read(self.0, buf) {
match Sys::read(self.fd, buf) {
-1 => Err(last_os_error()),
ok => Ok(ok as usize),
}
......@@ -61,7 +84,7 @@ impl io::Read for File {
impl io::Write for File {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match Sys::write(self.0, buf) {
match Sys::write(self.fd, buf) {
-1 => Err(last_os_error()),
ok => Ok(ok as usize),
}
......@@ -80,9 +103,25 @@ impl io::Seek for File {
io::SeekFrom::End(end) => (end as off_t, SEEK_END),
};
match Sys::lseek(self.0, offset, whence) {
match Sys::lseek(self.fd, offset, whence) {
-1 => Err(last_os_error()),
ok => Ok(ok as u64),
}
}
}
impl Deref for File {
type Target = c_int;
fn deref(&self) -> &Self::Target {
&self.fd
}
}
impl Drop for File {
fn drop(&mut self) {
if !self.reference {
let _ = Sys::close(self.fd);
}
}
}
use platform::types::*;
pub const EOF: c_int = -1;
pub const BUFSIZ: size_t = 1024;
pub const UNGET: size_t = 8;
......
use super::{constants, BUFSIZ, FILE, UNGET};
use super::{constants, Buffer, BUFSIZ, FILE, UNGET};
use core::cell::UnsafeCell;
use core::ptr;
use core::sync::atomic::AtomicBool;
use fs::File;
use io::LineWriter;
use platform::types::*;
pub struct GlobalFile(UnsafeCell<FILE>);
impl GlobalFile {
const fn new(file: FILE) -> Self {
GlobalFile(UnsafeCell::new(file))
fn new(file: c_int, flags: c_int) -> Self {
let file = File::new(file);
let writer = LineWriter::new(unsafe { file.get_ref() });
GlobalFile(UnsafeCell::new(FILE {
lock: AtomicBool::new(false),
file,
flags: constants::F_PERM | flags,
read_buf: Buffer::Owned(vec![0; BUFSIZ]),
read_pos: 0,
read_size: 0,
unget: None,
writer
}))
}
pub fn get(&self) -> *mut FILE {
self.0.get()
......@@ -17,40 +33,13 @@ unsafe impl Sync for GlobalFile {}
lazy_static! {
#[allow(non_upper_case_globals)]
pub static ref default_stdin: GlobalFile = GlobalFile::new(FILE {
flags: constants::F_PERM | constants::F_NOWR,
read: None,
write: None,
fd: 0,
buf: vec![0u8;(BUFSIZ + UNGET) as usize],
buf_char: -1,
unget: UNGET,
lock: AtomicBool::new(false),
});
pub static ref default_stdin: GlobalFile = GlobalFile::new(0, constants::F_NOWR);
#[allow(non_upper_case_globals)]
pub static ref default_stdout: GlobalFile = GlobalFile::new(FILE {
flags: constants::F_PERM | constants::F_NORD,
read: None,
write: None,
fd: 1,
buf: vec![0u8;(BUFSIZ + UNGET) as usize],
buf_char: b'\n' as i8,
unget: 0,
lock: AtomicBool::new(false),
});
pub static ref default_stdout: GlobalFile = GlobalFile::new(1, constants::F_NORD);
#[allow(non_upper_case_globals)]
pub static ref default_stderr: GlobalFile = GlobalFile::new(FILE {
flags: constants::F_PERM | constants::F_NORD,
read: None,
write: None,
fd: 2,
buf: vec![0u8;(BUFSIZ + UNGET) as usize],
buf_char: -1,
unget: 0,
lock: AtomicBool::new(false),
});
pub static ref default_stderr: GlobalFile = GlobalFile::new(2, constants::F_NORD);
}
#[no_mangle]
......
use alloc::boxed::Box;
use core::sync::atomic::AtomicBool;
use core::{mem, ptr};
use fs::File;
use header::errno;
use header::fcntl::*;
use header::string::strchr;
use platform;
use io::LineWriter;
use platform::types::*;
use platform;
use super::constants::*;
use super::{BUFSIZ, FILE, UNGET};
use super::{Buffer, FILE};
/// Parse mode flags as a string and output a mode flags integer
pub unsafe fn parse_mode_flags(mode_str: *const c_char) -> i32 {
......@@ -61,104 +64,18 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> {
flags |= F_APP;
}
let f = platform::alloc(mem::size_of::<FILE>()) as *mut FILE;
// Allocate the file
if f.is_null() {
None
} else {
ptr::write(
f,
FILE {
flags: flags,
read: None,
write: None,
fd: fd,
buf: vec![0u8; BUFSIZ + UNGET],
buf_char: -1,
unget: UNGET,
lock: AtomicBool::new(false),
},
);
Some(f)
}
}
/// Write buffer `buf` of length `l` into `stream`
pub fn fwritex(buf: *const u8, l: size_t, stream: &mut FILE) -> size_t {
use core::ptr::copy_nonoverlapping;
use core::slice;
let buf: &'static [u8] = unsafe { slice::from_raw_parts(buf, l) };
let mut l = l;
let mut advance = 0;
if stream.write.is_none() && !stream.can_write() {
// We can't write to this stream
return 0;
}
if let Some((wbase, mut wpos, wend)) = stream.write {
if l > wend - wpos {
// We can't fit all of buf in the buffer
return stream.write(buf);
}
let i = if stream.buf_char >= 0 {
let mut i = l;
while i > 0 && buf[i - 1] != b'\n' {
i -= 1;
}
if i > 0 {
let n = stream.write(buf);
match stream.write {
Some((_, new_wpos, _)) => wpos = new_wpos,
None => unreachable!("stream.write should never be None after a write call")
}
if n < i {
return n;
}
advance += i;
l -= i;
}
i
} else {
0
};
let file = File::new(fd);
let writer = LineWriter::new(file.get_ref());
unsafe {
copy_nonoverlapping(
&buf[advance..] as *const _ as *const u8,
&mut stream.buf[wpos..] as *mut _ as *mut u8,
l,
);
}
stream.write = Some((wbase, wpos + l, wend));
l + i
} else {
0
}
}
/// Flush `stream` without locking it.
pub fn fflush_unlocked(stream: &mut FILE) -> c_int {
if let Some((wbase, wpos, _)) = stream.write {
if wpos > wbase {
stream.write(&[]);
/*
if stream.wpos.is_null() {
return -1;
}
*/
}
}
if let Some((rpos, rend)) = stream.read {
if rpos < rend {
stream.seek(rpos as i64 - rend as i64, SEEK_CUR);
}
}
Some(Box::into_raw(Box::new(FILE {
lock: AtomicBool::new(false),
stream.write = None;
stream.read = None;
0
file,
flags,
read_buf: Buffer::Owned(vec![0; BUFSIZ as usize]),
read_pos: 0,
read_size: 0,
unget: None,
writer
})))
}
use super::{constants, FILE};
use platform::types::*;
pub fn ftello(stream: &mut FILE) -> off_t {
let pos = stream.seek(
0,
if let Some((wbase, wpos, _)) = stream.write {
if (stream.flags & constants::F_APP > 0) && wpos > wbase {
constants::SEEK_END
} else {
constants::SEEK_CUR
}
} else {
constants::SEEK_CUR
},
);
if pos < 0 {
return pos;
}
let rdiff = if let Some((rpos, rend)) = stream.read {
rend - rpos
} else {
0
};
let wdiff = if let Some((wbase, wpos, _)) = stream.write {
wpos - wbase
} else {
0
};
pos - rdiff as i64 + wdiff as i64
}
//use super::{constants, FILE};
//use platform::types::*;
//
//pub fn ftello(stream: &mut FILE) -> off_t {
// let pos = stream.seek(
// 0,
// if let Some((wbase, wpos, _)) = stream.write {
// if (stream.flags & constants::F_APP > 0) && wpos > wbase {
// constants::SEEK_END
// } else {
// constants::SEEK_CUR
// }
// } else {
// constants::SEEK_CUR
// },
// );
// if pos < 0 {
// return pos;
// }
// let rdiff = if let Some((rpos, rend)) = stream.read {
// rend - rpos
// } else {
// 0
// };
// let wdiff = if let Some((wbase, wpos, _)) = stream.write {
// wpos - wbase
// } else {
// 0
// };
// pos - rdiff as i64 + wdiff as i64
//}
This diff is collapsed.
use alloc::String;
use alloc::Vec;
use io::Read;
use platform::types::*;
use platform::ReadByte;
use va_list::VaList;
#[derive(PartialEq, Eq)]
......@@ -27,7 +27,7 @@ unsafe fn next_byte(string: &mut *const c_char) -> Result<u8, c_int> {
}
}
unsafe fn inner_scanf<R: ReadByte>(
unsafe fn inner_scanf<R: Read>(
mut r: R,
mut format: *const c_char,
mut ap: VaList,
......@@ -39,14 +39,15 @@ unsafe fn inner_scanf<R: ReadByte>(
macro_rules! read {
() => {{
match r.read_u8() {
Ok(Some(b)) => {
byte = b;
let mut buf = &mut [byte];
match r.read(buf) {
Ok(0) => false,
Ok(_) => {
byte = buf[0];
count += 1;
true
}
Ok(None) => false,
Err(()) => return Err(-1),
Err(_) => return Err(-1),
}
}};
}
......@@ -420,7 +421,7 @@ unsafe fn inner_scanf<R: ReadByte>(
}
Ok(matched)
}
pub unsafe fn scanf<R: ReadByte>(r: R, format: *const c_char, ap: VaList) -> c_int {
pub unsafe fn scanf<R: Read>(r: R, format: *const c_char, ap: VaList) -> c_int {
match inner_scanf(r, format, ap) {
Ok(n) => n,
Err(n) => n,
......
use alloc::vec::Vec;
use core::{fmt, ptr};
use io::{self, Read};
pub use self::allocator::*;
......@@ -70,16 +71,6 @@ impl<'a, W: WriteByte> WriteByte for &'a mut W {
}
}
pub trait ReadByte {
fn read_u8(&mut self) -> Result<Option<u8>, ()>;
}
impl<'a, R: ReadByte> ReadByte for &'a mut R {
fn read_u8(&mut self) -> Result<Option<u8>, ()> {
(**self).read_u8()
}
}
pub struct FileWriter(pub c_int);
impl FileWriter {
......@@ -110,13 +101,13 @@ impl FileReader {
}
}
impl ReadByte for FileReader {
fn read_u8(&mut self) -> Result<Option<u8>, ()> {
let mut buf = [0];
match self.read(&mut buf) {
0 => Ok(None),
n if n < 0 => Err(()),
_ => Ok(Some(buf[0])),
impl Read for FileReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let i = Sys::read(self.0, buf);
if i >= 0 {
Ok(i as usize)
} else {
Err(io::Error::from_raw_os_error(-i as i32))
}
}
}
......@@ -182,32 +173,20 @@ impl WriteByte for UnsafeStringWriter {
}
}
pub struct StringReader<'a>(pub &'a [u8]);
impl<'a> ReadByte for StringReader<'a> {
fn read_u8(&mut self) -> Result<Option<u8>, ()> {
if self.0.is_empty() {
Ok(None)
} else {
let byte = self.0[0];
self.0 = &self.0[1..];
Ok(Some(byte))
}
}
}
pub struct UnsafeStringReader(pub *const u8);
impl ReadByte for UnsafeStringReader {
fn read_u8(&mut self) -> Result<Option<u8>, ()> {
impl Read for UnsafeStringReader {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
unsafe {
if *self.0 == 0 {
Ok(None)
} else {
let byte = *self.0;
for i in 0..buf.len() {
if *self.0 == 0 {
return Ok(i);
}
buf[i] = *self.0;
self.0 = self.0.offset(1);
Ok(Some(byte))
}
Ok(buf.len())
}
}
}
......
......@@ -16,6 +16,7 @@ EXPECT_BINS=\
signal \
stdio/all \
stdio/buffer \
stdio/fgets \
stdio/freopen \
stdio/fwrite \
stdio/getc_unget \
......
#include <stdio.h>
int main() {
//FILE *f = fopen("/etc/ssl/certs/ca-certificates.crt", "r");
FILE *f = fopen("stdio/stdio.in", "r");
char line[256];
while (1) {
if (fgets(line, 256, f)) {
fputs(line, stdout);
} else {
puts("EOF");
break;
}
}
}
Hello World!
Line 2
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
ggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
lllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll
mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt
uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment