Browse Source

Added freopen() and relevant tests

Tom Almeida 7 years ago
parent
commit
8d40424020
4 changed files with 49 additions and 2 deletions
  1. 38 2
      src/stdio/src/lib.rs
  2. 1 0
      tests/.gitignore
  3. 1 0
      tests/Makefile
  4. 9 0
      tests/stdio/freopen.c

+ 38 - 2
src/stdio/src/lib.rs

@@ -311,12 +311,48 @@ pub unsafe extern "C" fn fread(
 }
 
 #[no_mangle]
-pub extern "C" fn freopen(
+pub unsafe extern "C" fn freopen(
     filename: *const c_char,
     mode: *const c_char,
     stream: *mut FILE,
 ) -> *mut FILE {
-    unimplemented!();
+    let mut flags = helpers::parse_mode_flags(mode);
+    flockfile(stream);
+
+    helpers::fflush_unlocked(stream);
+    if filename.is_null() { // Reopen stream in new mode
+        if flags & fcntl::O_CLOEXEC > 0 {
+            fcntl::sys_fcntl((*stream).fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
+        }
+        flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC);
+        if fcntl::sys_fcntl((*stream).fd, fcntl::F_SETFL, flags) < 0 {
+            funlockfile(stream);
+            fclose(stream);
+            return ptr::null_mut();
+        }
+    } else {
+        let new = fopen(filename, mode);
+        if new.is_null() {
+            funlockfile(stream);
+            fclose(stream);
+            return ptr::null_mut();
+        }
+        if (*new).fd == (*stream).fd {
+            (*new).fd = -1;
+        } else if platform::dup2((*new).fd, (*stream).fd) < 0 || fcntl::sys_fcntl((*stream).fd, fcntl::F_SETFL, flags&fcntl::O_CLOEXEC) < 0 {
+            fclose(new);
+            funlockfile(stream);
+            fclose(stream);
+            return ptr::null_mut();
+        }
+        (*stream).flags = ((*stream).flags & constants::F_PERM) | (*new).flags;
+        (*stream).read = (*new).read;
+        (*stream).write = (*new).write;
+        (*stream).seek = (*new).seek;
+        fclose(new);
+    }
+    funlockfile(stream);
+    stream
 }
 
 /// Seek to an offset `offset` from `whence`

+ 1 - 0
tests/.gitignore

@@ -30,6 +30,7 @@
 /stdlib/a64l
 /stdio/fwrite
 /stdio/all
+/stdio/freopen
 /string/strncmp
 /string/strcspn
 /string/strchr

+ 1 - 0
tests/Makefile

@@ -24,6 +24,7 @@ EXPECT_BINS=\
 	sprintf \
 	stdio/fwrite \
 	stdio/all \
+	stdio/freopen \
 	stdlib/strtol \
 	stdlib/a64l \
 	string/strncmp \

+ 9 - 0
tests/stdio/freopen.c

@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main(int argc, char ** argv) {
+	freopen("stdio/stdio.in", "r", stdin);
+	char in[6];
+	fgets(in, 6, stdin);
+	printf("%s\n", in); // should print Hello
+	return 0;
+}