Browse Source

Merge branch 'add_fwide' into 'master'

Add fwide function

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

+ 2 - 0
src/header/stdio/default.rs

@@ -21,6 +21,8 @@ impl GlobalFile {
             writer,
 
             pid: None,
+
+            orientation: 0,
         }))
     }
     pub fn get(&self) -> *mut FILE {

+ 2 - 0
src/header/stdio/helpers.rs

@@ -76,5 +76,7 @@ pub unsafe fn _fdopen(fd: c_int, mode: *const c_char) -> Option<*mut FILE> {
         writer,
 
         pid: None,
+
+        orientation: 0,
     })))
 }

+ 76 - 1
src/header/stdio/mod.rs

@@ -9,7 +9,7 @@ use core::{
     cmp,
     ffi::VaList as va_list,
     fmt::{self, Write as WriteFmt},
-    mem,
+    i32, mem,
     ops::{Deref, DerefMut},
     ptr, slice, str,
 };
@@ -85,6 +85,9 @@ pub struct FILE {
 
     // Optional pid for use with popen/pclose
     pid: Option<c_int>,
+
+    // wchar support
+    pub(crate) orientation: c_int,
 }
 
 impl Read for FILE {
@@ -169,6 +172,29 @@ impl FILE {
         }
         LockGuard(self)
     }
+
+    pub fn try_set_orientation(&mut self, mode: c_int) -> c_int {
+        let stream = self.lock();
+        stream.0.try_set_orientation_unlocked(mode)
+    }
+
+    pub fn try_set_orientation_unlocked(&mut self, mode: c_int) -> c_int {
+        if self.orientation == 0 {
+            self.orientation = match mode {
+                1..=i32::MAX => 1,
+                i32::MIN..=-1 => -1,
+                0 => self.orientation,
+            };
+        }
+        self.orientation
+    }
+
+    pub fn try_set_byte_orientation_unlocked(&mut self) -> core::result::Result<(), c_int> {
+        match self.try_set_orientation_unlocked(-1) {
+            i32::MIN..=-1 => Ok(()),
+            x => Err(x),
+        }
+    }
 }
 
 pub struct LockGuard<'a>(&'a mut FILE);
@@ -287,6 +313,10 @@ pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int {
 #[no_mangle]
 pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int {
     let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     getc_unlocked(&mut *stream)
 }
 
@@ -309,6 +339,10 @@ pub unsafe extern "C" fn fgets(
     stream: *mut FILE,
 ) -> *mut c_char {
     let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return ptr::null_mut();
+    }
+
     let mut out = original;
     let max = max as usize;
     let mut left = max.saturating_sub(1); // Make space for the terminating NUL-byte
@@ -422,6 +456,10 @@ pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) ->
 #[no_mangle]
 pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
     let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     putc_unlocked(c, &mut *stream)
 }
 
@@ -429,6 +467,10 @@ pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
 #[no_mangle]
 pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
     let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
 
     if stream.write_all(&buf).is_ok() {
@@ -451,6 +493,10 @@ pub unsafe extern "C" fn fread(
     }
 
     let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return 0;
+    }
+
     let buf = slice::from_raw_parts_mut(ptr as *mut u8, size as usize * nitems as usize);
     let mut read = 0;
     while read < buf.len() {
@@ -504,6 +550,7 @@ pub unsafe extern "C" fn freopen(
         stream.flags = (stream.flags & constants::F_PERM) | new.flags;
         fclose(new);
     }
+    stream.orientation = 0;
     funlockfile(stream);
     stream
 }
@@ -600,6 +647,10 @@ pub unsafe extern "C" fn fwrite(
         return 0;
     }
     let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return 0;
+    }
+
     let buf = slice::from_raw_parts(ptr as *const u8, size as usize * nitems as usize);
     let mut written = 0;
     while written < buf.len() {
@@ -627,6 +678,10 @@ pub unsafe extern "C" fn getchar() -> c_int {
 /// Get a char from a stream without locking the stream
 #[no_mangle]
 pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     let mut buf = [0];
 
     match (*stream).read(&mut buf) {
@@ -806,6 +861,10 @@ pub unsafe extern "C" fn putchar(c: c_int) -> c_int {
 /// Put a character `c` into `stream` without locking `stream`
 #[no_mangle]
 pub unsafe extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int {
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     match (*stream).write(&[c as u8]) {
         Ok(0) | Err(_) => EOF,
         Ok(_) => c,
@@ -822,6 +881,10 @@ pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> c_int {
 #[no_mangle]
 pub unsafe extern "C" fn puts(s: *const c_char) -> c_int {
     let mut stream = (&mut *stdout).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
 
     if stream.write_all(&buf).is_err() {
@@ -1001,6 +1064,10 @@ unsafe extern "C" fn tmpnam_inner(buf: *mut c_char, offset: usize) -> *mut c_cha
 #[no_mangle]
 pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
     let mut stream = (*stream).lock();
+    if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     stream.unget.push(c as u8);
     c
 }
@@ -1008,6 +1075,10 @@ pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
 #[no_mangle]
 pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
     let mut file = (*file).lock();
+    if let Err(_) = file.try_set_byte_orientation_unlocked() {
+        return -1;
+    }
+
     printf::printf(&mut *file, format, ap)
 }
 
@@ -1053,6 +1124,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();
+        if let Err(_) = file.try_set_byte_orientation_unlocked() {
+            return -1;
+        }
+
         let f: &mut FILE = &mut *file;
         let reader: LookAheadReader = f.into();
         scanf::scanf(reader, format, ap)

+ 3 - 3
src/header/wchar/mod.rs

@@ -89,9 +89,9 @@ pub unsafe extern "C" fn fputws(ws: *const wchar_t, stream: *mut FILE) -> c_int
     }
 }
 
-// #[no_mangle]
-pub extern "C" fn fwide(stream: *mut FILE, mode: c_int) -> c_int {
-    unimplemented!();
+#[no_mangle]
+pub unsafe extern "C" fn fwide(stream: *mut FILE, mode: c_int) -> c_int {
+    (*stream).try_set_orientation(mode)
 }
 
 #[no_mangle]

+ 2 - 0
src/platform/types.rs

@@ -1,3 +1,5 @@
+use core::i32;
+
 // Use repr(u8) as LLVM expects `void*` to be the same as `i8*` to help enable
 // more optimization opportunities around it recognizing things like
 // malloc/free.

+ 1 - 0
tests/Makefile

@@ -100,6 +100,7 @@ EXPECT_NAMES=\
 	unistd/swab \
 	unistd/write \
 	waitpid \
+	wchar/fwide \
 	wchar/mbrtowc \
 	wchar/mbsrtowcs \
 	wchar/printf-on-wchars \

+ 2 - 0
tests/expected/stdio/freopen.stdout

@@ -1 +1,3 @@
 Hello
+0
+0

+ 0 - 0
tests/expected/wchar/fwide.stderr


+ 4 - 0
tests/expected/wchar/fwide.stdout

@@ -0,0 +1,4 @@
+0
+0
+0
+0

+ 27 - 1
tests/stdio/freopen.c

@@ -1,12 +1,38 @@
+#include <assert.h>
 #include <stdio.h>
+#include <wchar.h>
 
 #include "test_helpers.h"
 
-int main(void) {
+int test_reopen_opens_file(void) {
     FILE *f = freopen("stdio/stdio.in", "r", stdin);
     ERROR_IF(freopen, f, == NULL);
 
     char in[6];
     fgets(in, 6, stdin);
     printf("%s\n", in); // should print Hello
+    fclose(f);
+    return 0;
+}
+
+int test_reopen_resets_orientation(void) {
+    FILE *f = freopen("stdio/stdio.in", "r", stdin);
+    assert(fwide(f, 0) == 0);
+    assert(fwide(f, -1) == -1);
+
+    f = freopen("stdio/stdio.in", "r", stdin);
+    assert(fwide(f, 0) == 0);
+
+    fclose(f);
+    return 0;
+}
+
+int main(void) {
+    int(*tests[])(void) = {
+        &test_reopen_opens_file,
+        &test_reopen_resets_orientation,
+    };
+    for(int i=0; i<sizeof(tests)/sizeof(int(*)(void)); i++) {
+        printf("%d\n", (*tests[i])());
+    }
 }

+ 60 - 0
tests/wchar/fwide.c

@@ -0,0 +1,60 @@
+#include <assert.h>
+#include <stdio.h>
+#include <wchar.h>
+
+int test_initial_orientation(void) {
+	FILE *f = tmpfile();
+	assert(fwide(f, 0) == 0);
+	return 0;
+}
+
+int test_manual_byte_orientation(void) {
+	FILE *f = tmpfile();
+
+	// set manually to byte orientation
+	assert(fwide(f, -483) == -1);
+
+	// Cannot change to wchar orientation
+	assert(fwide(f, 1) == -1);
+
+	fclose(f);
+	return 0;
+}
+
+int test_manual_wchar_orientation(void) {
+	FILE *f = tmpfile();
+
+	// set manually to wchar orientation
+	assert(fwide(f, 483) == 1);
+
+	// Cannot change to byte orientation
+	assert(fwide(f, -1) == 1);
+
+	fclose(f);
+	return 0;
+}
+
+int test_orientation_after_fprintf(void) {
+	// open file and write bytes; implicitly setting the bytes orientation
+	FILE *f = tmpfile();
+	assert(fprintf(f, "blah\n") == 5);
+
+	// Check that bytes orientation is set
+	assert(fwide(f, 0) == -1);
+
+	fclose(f);
+	return 0;
+}
+
+int main() {
+	int(*tests[])(void) = {
+		&test_initial_orientation,
+		&test_manual_byte_orientation,
+		&test_manual_wchar_orientation,
+		&test_orientation_after_fprintf,
+	};
+	for(int i=0; i<sizeof(tests)/sizeof(int(*)(void)); i++) {
+		printf("%d\n", (*tests[i])());
+	}
+}
+