Browse Source

Add implmentation for fwide posix function.

This function is used to set the orientation of a stream to either
byte-oriented or wchar-oriented.

More info on this function is here:
https://man7.org/linux/man-pages/man3/fwide.3p.html

This implementation only impmlemnts the manual switching and does
not yet guard against using a byte-oriented stream with wchar
functions and vice versa. Those step will come in additional
commits.

Signed-off-by: Wren Turkal <[email protected]>
Wren Turkal 4 years ago
parent
commit
865b7962a1

+ 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,
     })))
 }

+ 16 - 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,18 @@ impl FILE {
         }
         LockGuard(self)
     }
+
+    pub fn try_set_orientation(&mut self, mode: c_int) -> c_int {
+        let mut stream = self.lock();
+        if stream.0.orientation == 0 {
+            stream.0.orientation = match mode {
+                1..=i32::MAX => 1,
+                i32::MIN..=-1 => -1,
+                0 => stream.0.orientation,
+            };
+        }
+        stream.0.orientation
+    }
 }
 
 pub struct LockGuard<'a>(&'a mut FILE);

+ 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 \

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


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

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

+ 47 - 0
tests/wchar/fwide.c

@@ -0,0 +1,47 @@
+#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 main() {
+	int(*tests[])(void) = {
+		&test_initial_orientation,
+		&test_manual_byte_orientation,
+		&test_manual_wchar_orientation,
+	};
+	for(int i=0; i<sizeof(tests)/sizeof(int(*)(void)); i++) {
+		printf("%d\n", (*tests[i])());
+	}
+}
+