Merge branch 'add_fwide' into 'master'
Add fwide function See merge request redox-os/relibc!291
This commit is contained in:
@@ -21,6 +21,8 @@ impl GlobalFile {
|
||||
writer,
|
||||
|
||||
pid: None,
|
||||
|
||||
orientation: 0,
|
||||
}))
|
||||
}
|
||||
pub fn get(&self) -> *mut FILE {
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -100,6 +100,7 @@ EXPECT_NAMES=\
|
||||
unistd/swab \
|
||||
unistd/write \
|
||||
waitpid \
|
||||
wchar/fwide \
|
||||
wchar/mbrtowc \
|
||||
wchar/mbsrtowcs \
|
||||
wchar/printf-on-wchars \
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
Hello
|
||||
0
|
||||
0
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
+27
-1
@@ -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])());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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])());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user