瀏覽代碼

Rewrite IO to use core-io library

jD91mZM2 6 年之前
父節點
當前提交
afc1ff134a

+ 0 - 3
include/bits/stdio.h

@@ -1,9 +1,6 @@
 #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, ...);

+ 49 - 10
src/fs.rs

@@ -1,4 +1,5 @@
 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);
+        }
+    }
+}

+ 1 - 0
src/header/stdio/constants.rs

@@ -1,5 +1,6 @@
 use platform::types::*;
 
+pub const EOF: c_int = -1;
 pub const BUFSIZ: size_t = 1024;
 
 pub const UNGET: size_t = 8;

+ 22 - 33
src/header/stdio/default.rs

@@ -1,12 +1,28 @@
-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]

+ 17 - 100
src/header/stdio/helpers.rs

@@ -1,14 +1,17 @@
+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
+    })))
 }

+ 31 - 31
src/header/stdio/internal.rs

@@ -1,31 +1,31 @@
-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
+//}

文件差異過大導致無法顯示
+ 282 - 433
src/header/stdio/mod.rs


+ 9 - 8
src/header/stdio/scanf.rs

@@ -1,7 +1,7 @@
 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,

+ 17 - 38
src/platform/mod.rs

@@ -1,5 +1,6 @@
 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())
         }
     }
 }

+ 1 - 0
tests/Makefile

@@ -16,6 +16,7 @@ EXPECT_BINS=\
 	signal \
 	stdio/all \
 	stdio/buffer \
+	stdio/fgets \
 	stdio/freopen \
 	stdio/fwrite \
 	stdio/getc_unget \

+ 16 - 0
tests/stdio/fgets.c

@@ -0,0 +1,16 @@
+#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;
+        }
+    }
+}

+ 27 - 0
tests/stdio/stdio.in

@@ -1,3 +1,30 @@
 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

部分文件因文件數量過多而無法顯示