Browse Source

Merge branch 'scanf' into 'master'

Scanf

See merge request redox-os/relibc!277
Jeremy Soller 4 years ago
parent
commit
d0c1160299

+ 4 - 2
src/crti/src/lib.rs

@@ -27,7 +27,8 @@ global_asm!(
 );
 // https://git.musl-libc.org/cgit/musl/tree/crt/aarch64/crti.s
 #[cfg(target_arch = "aarch64")]
-global_asm!(r#"
+global_asm!(
+    r#"
     .section .init
     .global _init
     .type _init,%function
@@ -45,7 +46,8 @@ global_asm!(r#"
         mov x29,sp
         // stp: "stores two doublewords from the first and second argument to memory addressed by addr"
         // Body will be filled in by gcc and ended by crtn.o
-"#);
+"#
+);
 
 #[panic_handler]
 #[linkage = "weak"]

+ 4 - 2
src/crtn/src/lib.rs

@@ -23,7 +23,8 @@ global_asm!(
 );
 // https://git.musl-libc.org/cgit/musl/tree/crt/aarch64/crtn.s
 #[cfg(target_arch = "aarch64")]
-global_asm!(r#"
+global_asm!(
+    r#"
     .section .init
         // This happens after crti.o and gcc has inserted code
         // ldp: "loads two doublewords from memory addressed by the third argument to the first and second"
@@ -35,7 +36,8 @@ global_asm!(r#"
         // ldp: "loads two doublewords from memory addressed by the third argument to the first and second"
         ldp x29,x30,[sp],#16
         ret
-"#);
+"#
+);
 
 #[panic_handler]
 #[linkage = "weak"]

+ 95 - 0
src/header/stdio/lookaheadreader.rs

@@ -0,0 +1,95 @@
+use super::{fseek_locked, ftell_locked, FILE, SEEK_SET};
+use crate::core_io::Read;
+struct LookAheadBuffer {
+    buf: *const u8,
+    pos: isize,
+    look_ahead: isize,
+}
+impl LookAheadBuffer {
+    fn look_ahead(&mut self) -> Result<Option<u8>, i32> {
+        let byte = unsafe { *self.buf.offset(self.look_ahead) };
+        self.look_ahead += 1;
+        Ok(Some(byte))
+    }
+
+    fn commit(&mut self) {
+        self.pos = self.look_ahead;
+    }
+}
+
+impl From<*const u8> for LookAheadBuffer {
+    fn from(buff: *const u8) -> LookAheadBuffer {
+        LookAheadBuffer {
+            buf: buff,
+            pos: 0,
+            look_ahead: 0,
+        }
+    }
+}
+
+struct LookAheadFile<'a> {
+    f: &'a mut FILE,
+    look_ahead: i64,
+}
+
+impl<'a> LookAheadFile<'a> {
+    fn look_ahead(&mut self) -> Result<Option<u8>, i32> {
+        let buf = &mut [0];
+        let seek = unsafe { ftell_locked(self.f) };
+        unsafe { fseek_locked(self.f, self.look_ahead, SEEK_SET) };
+        let ret = match self.f.read(buf) {
+            Ok(0) => Ok(None),
+            Ok(_) => Ok(Some(buf[0])),
+            Err(_) => Err(-1),
+        };
+        unsafe { fseek_locked(self.f, seek, SEEK_SET) };
+        self.look_ahead += 1;
+        ret
+    }
+
+    fn commit(&mut self) {
+        unsafe { fseek_locked(self.f, self.look_ahead, SEEK_SET) };
+    }
+}
+
+impl<'a> From<&'a mut FILE> for LookAheadFile<'a> {
+    fn from(f: &'a mut FILE) -> LookAheadFile<'a> {
+        let look_ahead = unsafe { ftell_locked(f) } as i64;
+        LookAheadFile { f, look_ahead }
+    }
+}
+
+enum LookAheadReaderEnum<'a> {
+    FILE(LookAheadFile<'a>),
+    // (buffer, location)
+    BUFFER(LookAheadBuffer),
+}
+
+pub struct LookAheadReader<'a>(LookAheadReaderEnum<'a>);
+
+impl<'a> LookAheadReader<'a> {
+    pub fn lookahead1(&mut self) -> Result<Option<u8>, i32> {
+        match &mut self.0 {
+            LookAheadReaderEnum::FILE(f) => f.look_ahead(),
+            LookAheadReaderEnum::BUFFER(b) => b.look_ahead(),
+        }
+    }
+    pub fn commit(&mut self) {
+        match &mut self.0 {
+            LookAheadReaderEnum::FILE(f) => f.commit(),
+            LookAheadReaderEnum::BUFFER(b) => b.commit(),
+        }
+    }
+}
+
+impl<'a> From<&'a mut FILE> for LookAheadReader<'a> {
+    fn from(f: &'a mut FILE) -> LookAheadReader {
+        LookAheadReader(LookAheadReaderEnum::FILE(f.into()))
+    }
+}
+
+impl<'a> From<*const u8> for LookAheadReader<'a> {
+    fn from(buff: *const u8) -> LookAheadReader<'a> {
+        LookAheadReader(LookAheadReaderEnum::BUFFER(buff.into()))
+    }
+}

+ 15 - 10
src/header/stdio/mod.rs

@@ -39,9 +39,10 @@ mod getdelim;
 
 mod ext;
 mod helpers;
+mod lookaheadreader;
 mod printf;
 mod scanf;
-
+use lookaheadreader::LookAheadReader;
 static mut TMPNAM_BUF: [c_char; L_tmpnam as usize + 1] = [0; L_tmpnam as usize + 1];
 
 enum Buffer<'a> {
@@ -514,9 +515,12 @@ pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int)
 
 /// Seek to an offset `offset` from `whence`
 #[no_mangle]
-pub unsafe extern "C" fn fseeko(stream: *mut FILE, mut off: off_t, whence: c_int) -> c_int {
+pub unsafe extern "C" fn fseeko(stream: *mut FILE, off: off_t, whence: c_int) -> c_int {
     let mut stream = (*stream).lock();
+    fseek_locked(&mut *stream, off, whence)
+}
 
+pub unsafe fn fseek_locked(stream: &mut FILE, mut off: off_t, whence: c_int) -> c_int {
     if whence == SEEK_CUR {
         // Since it's a buffered writer, our actual cursor isn't where the user
         // thinks
@@ -555,7 +559,10 @@ pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
 /// Get the current position of the cursor in the file
 #[no_mangle]
 pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t {
-    let stream = (*stream).lock();
+    let mut stream = (*stream).lock();
+    ftell_locked(&mut *stream)
+}
+pub unsafe extern "C" fn ftell_locked(stream: &mut FILE) -> off_t {
     let pos = Sys::lseek(*stream.file, 0, SEEK_CUR);
     if pos < 0 {
         return -1;
@@ -1043,9 +1050,10 @@ pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_
 pub unsafe extern "C" fn vfscanf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
     let ret = {
         let mut file = (*file).lock();
-        scanf::scanf(&mut *file, format, ap)
+        let f: &mut FILE = &mut *file;
+        let reader: LookAheadReader = f.into();
+        scanf::scanf(reader, format, ap)
     };
-    fseeko(file, -1, SEEK_CUR);
     ret
 }
 
@@ -1056,9 +1064,6 @@ pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
 
 #[no_mangle]
 pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int {
-    scanf::scanf(
-        &mut platform::UnsafeStringReader(s as *const u8),
-        format,
-        ap,
-    )
+    let reader = (s as *const u8).into();
+    scanf::scanf(reader, format, ap)
 }

+ 24 - 13
src/header/stdio/scanf.rs

@@ -1,4 +1,5 @@
-use crate::{io::Read, platform::types::*};
+use super::lookaheadreader::LookAheadReader;
+use crate::platform::types::*;
 use alloc::{string::String, vec::Vec};
 use core::ffi::VaList as va_list;
 
@@ -25,8 +26,8 @@ unsafe fn next_byte(string: &mut *const c_char) -> Result<u8, c_int> {
     }
 }
 
-unsafe fn inner_scanf<R: Read>(
-    mut r: R,
+unsafe fn inner_scanf(
+    mut r: LookAheadReader,
     mut format: *const c_char,
     mut ap: va_list,
 ) -> Result<c_int, c_int> {
@@ -37,15 +38,14 @@ unsafe fn inner_scanf<R: Read>(
 
     macro_rules! read {
         () => {{
-            let buf = &mut [byte];
-            match r.read(buf) {
-                Ok(0) => false,
-                Ok(_) => {
-                    byte = buf[0];
+            match r.lookahead1() {
+                Ok(None) => false,
+                Ok(Some(b)) => {
+                    byte = b;
                     count += 1;
                     true
                 }
-                Err(_) => return Err(-1),
+                Err(x) => return Err(x),
             }
         }};
     }
@@ -59,7 +59,10 @@ unsafe fn inner_scanf<R: Read>(
         };
         (inner $($placeholder:expr)*) => {
             if !skip_read && !read!() {
-                return Ok(matched);
+                match matched {
+                    0 => return Ok(-1),
+                    a => return Ok(a),
+                }
             }
             $(else {
                 // Hacky way of having this optional
@@ -86,6 +89,7 @@ unsafe fn inner_scanf<R: Read>(
             if c != byte {
                 return Ok(matched);
             }
+            r.commit();
         } else {
             c = next_byte(&mut format)?;
 
@@ -215,6 +219,7 @@ unsafe fn inner_scanf<R: Read>(
                             dot = true;
                         }
                         n.push(byte as char);
+                        r.commit();
                         width = width.map(|w| w - 1);
                         if width.map(|w| w > 0).unwrap_or(true) && !read!() {
                             return Ok(matched);
@@ -344,6 +349,7 @@ unsafe fn inner_scanf<R: Read>(
                     if let Some(ptr) = ptr {
                         *ptr = 0;
                         matched += 1;
+                        r.commit();
                     }
                 }
                 b'c' => {
@@ -362,6 +368,7 @@ unsafe fn inner_scanf<R: Read>(
 
                     if ptr.is_some() {
                         matched += 1;
+                        r.commit();
                     }
                 }
                 b'[' => {
@@ -402,12 +409,15 @@ unsafe fn inner_scanf<R: Read>(
                     let mut ptr: Option<*mut c_char> = if ignore { None } else { Some(ap.arg()) };
 
                     // While we haven't used up all the width, and it matches
+                    let mut data_stored = false;
                     while width.map(|w| w > 0).unwrap_or(true) && !invert == matches.contains(&byte)
                     {
                         if let Some(ref mut ptr) = ptr {
                             **ptr = byte as c_char;
                             *ptr = ptr.offset(1);
+                            data_stored = true;
                         }
+                        r.commit();
                         // Decrease the width, and read a new character unless the width is 0
                         width = width.map(|w| w - 1);
                         if width.map(|w| w > 0).unwrap_or(true) && !read!() {
@@ -418,8 +428,8 @@ unsafe fn inner_scanf<R: Read>(
                         }
                     }
 
-                    if let Some(ptr) = ptr {
-                        *ptr = 0;
+                    if data_stored {
+                        *ptr.unwrap() = 0;
                         matched += 1;
                     }
                 }
@@ -444,7 +454,8 @@ unsafe fn inner_scanf<R: Read>(
     }
     Ok(matched)
 }
-pub unsafe fn scanf<R: Read>(r: R, format: *const c_char, ap: va_list) -> c_int {
+
+pub unsafe fn scanf(r: LookAheadReader, format: *const c_char, ap: va_list) -> c_int {
     match inner_scanf(r, format, ap) {
         Ok(n) => n,
         Err(n) => n,

+ 5 - 5
src/header/sys_random/mod.rs

@@ -1,14 +1,14 @@
 use core::slice;
 
-use crate::platform::{Pal, Sys, types::*};
+use crate::platform::{types::*, Pal, Sys};
 
 pub const GRND_NONBLOCK: c_uint = 1;
 pub const GRND_RANDOM: c_uint = 2;
 
 #[no_mangle]
 pub unsafe extern "C" fn getrandom(buf: *mut c_void, buflen: size_t, flags: c_uint) -> ssize_t {
-    Sys::getrandom(slice::from_raw_parts_mut(
-        buf as *mut u8,
-        buflen as usize
-    ), flags)
+    Sys::getrandom(
+        slice::from_raw_parts_mut(buf as *mut u8, buflen as usize),
+        flags,
+    )
 }

+ 1 - 1
src/ld_so/linker.rs

@@ -26,10 +26,10 @@ use crate::{
 };
 
 use super::{
+    access,
     debug::{RTLDDebug, RTLDState, _dl_debug_state, _r_debug},
     tcb::{Master, Tcb},
     PAGE_SIZE,
-    access,
 };
 
 #[cfg(target_os = "redox")]

+ 3 - 7
src/ld_so/mod.rs

@@ -1,11 +1,7 @@
 use goblin::elf::program_header::{self, program_header32, program_header64, ProgramHeader};
 
 use self::tcb::{Master, Tcb};
-use crate::{
-start::Stack,
-c_str::CStr,
-platform::types::*
-};
+use crate::{c_str::CStr, platform::types::*, start::Stack};
 pub const PAGE_SIZE: usize = 4096;
 
 pub mod debug;
@@ -85,8 +81,8 @@ pub fn static_init(sp: &'static Stack) {
 
 // Wrapper over the systemcall, Do not use outside of ld_so
 pub unsafe fn access(path: *const c_char, mode: c_int) -> c_int {
-        let path = CStr::from_ptr(path);
-        syscall!(ACCESS, (path).as_ptr(), mode) as c_int
+    let path = CStr::from_ptr(path);
+    syscall!(ACCESS, (path).as_ptr(), mode) as c_int
 }
 
 #[cfg(target_os = "linux")]

+ 4 - 4
src/platform/redox/ptrace.rs

@@ -5,6 +5,10 @@
 //! compatibility. So, this module will be a hellhole.
 
 use super::super::{errno, types::*, Pal, PalPtrace, PalSignal, Sys};
+#[cfg(target_arch = "aarch64")]
+use crate::header::arch_aarch64_user::user_regs_struct;
+#[cfg(target_arch = "x86_64")]
+use crate::header::arch_x64_user::user_regs_struct;
 use crate::{
     c_str::CString,
     fs::File,
@@ -12,10 +16,6 @@ use crate::{
     io::{self, prelude::*},
     sync::{Mutex, Once},
 };
-#[cfg(target_arch = "aarch64")]
-use crate::header::arch_aarch64_user::user_regs_struct;
-#[cfg(target_arch = "x86_64")]
-use crate::header::arch_x64_user::user_regs_struct;
 
 use alloc::collections::{btree_map::Entry, BTreeMap};
 use core::mem;

+ 4 - 1
src/platform/redox/socket.rs

@@ -143,7 +143,10 @@ unsafe fn inner_get_name(
         inner_af_unix(&buf[5..], address, address_len);
     } else {
         // Socket doesn't belong to any scheme
-        panic!("socket {:?} doesn't match either tcp, udp or chan schemes", str::from_utf8(buf));
+        panic!(
+            "socket {:?} doesn't match either tcp, udp or chan schemes",
+            str::from_utf8(buf)
+        );
     }
 
     Ok(0)

+ 5 - 3
src/platform/test/mod.rs

@@ -68,12 +68,14 @@ fn clock_gettime() {
 
 #[test]
 fn getrandom() {
-    use crate::header::sys_random;
-    use crate::platform::types::ssize_t;
+    use crate::{header::sys_random, platform::types::ssize_t};
 
     let mut arrays = [[0; 32]; 32];
     for i in 1..arrays.len() {
-        assert_eq!(Sys::getrandom(&mut arrays[i], 0), arrays[i].len() as ssize_t);
+        assert_eq!(
+            Sys::getrandom(&mut arrays[i], 0),
+            arrays[i].len() as ssize_t
+        );
 
         for j in 0..arrays.len() {
             if i != j {

+ 1 - 0
tests/Makefile

@@ -45,6 +45,7 @@ EXPECT_NAMES=\
 	stdio/ungetc_multiple \
 	stdio/ungetc_ftell \
 	stdio/fscanf_offby1 \
+	stdio/fscanf \
 	stdio/printf_neg_pad \
 	stdlib/a64l \
 	stdlib/alloc \

+ 0 - 0
tests/expected/stdio/fscanf.stderr


+ 14 - 0
tests/expected/stdio/fscanf.stdout

@@ -0,0 +1,14 @@
+1 2 3 9
+9
+16
+35
+48
+92
+109
+152
+201
+241
+276
+293
+299
+301

+ 13 - 13
tests/expected/stdio/scanf.stdout

@@ -1,14 +1,14 @@
-1, { sa: 12, ia: 0, ib: 0, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4:  }
-2, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4:  }
-1, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4:  }
-0, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4:  }
-1, { sa: 12, ia: 18, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: Hello, string2: , string3: , string4:  }
-1, { sa: 12, ia: 15, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: a, string1: Hello, string2: , string3: , string4:  }
-2, { sa: 12, ia: 15, ib: 837, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4:  }
-1, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4:  }
-0, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: elllo, string2: , string3: , string4:  }
-4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: e, string2: o, string3: l, string4: d }
-4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: a, string2: e, string3: f, string4: dddddd }
-4, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: a, string2: e, string3: f, string4: dddddd }
-1, { sa: 12, ia: 0, ib: 8, ic: 0, fa: 0.100000, da: 0.000000, ptr: (nil), char: h, string1: testbbbb, string2: e, string3: f, string4: dddddd }
+2, { sa: 12, ia: 345, ib: 0, ic: 0, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4:  }
+3, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.000000, da: 0.000000, ptr: (nil), char: a, string1: , string2: , string3: , string4:  }
+2, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: (nil), char: a, string1: , string2: , string3: , string4:  }
+1, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string1: , string2: , string3: , string4:  }
+1, { sa: 12, ia: 18, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string1: Hello, string2: , string3: , string4:  }
+1, { sa: 12, ia: 15, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: a, string1: Hello, string2: , string3: , string4:  }
+2, { sa: 12, ia: 15, ib: 837, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: elllo, string2: , string3: , string4:  }
+1, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: elllo, string2: , string3: , string4:  }
+0, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: elllo, string2: , string3: , string4:  }
+4, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: e, string2: o, string3: l, string4: d }
+4, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: a, string2: e, string3: f, string4: dddddd }
+4, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: a, string2: e, string3: f, string4: dddddd }
+1, { sa: 12, ia: 0, ib: 8, ic: 8, fa: 0.100000, da: 0.200000, ptr: 0xabcdef, char: h, string1: testbbbb, string2: e, string3: f, string4: dddddd }
 3 "https" "//" "redox-os.org" ""

+ 13 - 0
tests/stdio/fscanf.c

@@ -0,0 +1,13 @@
+//@ 1 2 3
+//@ SS
+#include <stdio.h>
+int main() {
+    FILE *f = fopen("stdio/fscanf.c", "r");
+    int x, y, z;
+    fscanf(f, "//@ %d %d %d",&x , &y, &z);
+    printf("%d %d %d %ld\n", x, y, z, ftell(f));
+    while(-1 != fscanf(f, "%*[^\n]")) {
+        printf("%ld\n", ftell(f));
+        getc(f);
+    }
+}