summary refs log tree commit diff
path: root/src/libstd/rt/io/stdio.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-10-16 11:47:12 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-10-24 14:21:57 -0700
commit35756fbcf6572d588929fde64fb4027f47e9d0af (patch)
tree8a2f0ec01c2eb26f5db34887b8b2335a844d5b9d /src/libstd/rt/io/stdio.rs
parent32b07c6a40bd7e1874244096f413096a6e059a29 (diff)
downloadrust-35756fbcf6572d588929fde64fb4027f47e9d0af.tar.gz
rust-35756fbcf6572d588929fde64fb4027f47e9d0af.zip
Move rt::io::stdio from FileStream to a TTY
We get a little more functionality from libuv for these kinds of streams (things
like terminal dimentions), and it also appears to more gracefully handle the
stream being a window. Beforehand, if you used stdio and hit CTRL+d on a
process, libuv would continually return 0-length successful reads instead of
interpreting that the stream was closed.

I was hoping to be able to write tests for this, but currently the testing
infrastructure doesn't allow tests with a stdin and a stdout, but this has been
manually tested! (not that it means much)
Diffstat (limited to 'src/libstd/rt/io/stdio.rs')
-rw-r--r--src/libstd/rt/io/stdio.rs102
1 files changed, 88 insertions, 14 deletions
diff --git a/src/libstd/rt/io/stdio.rs b/src/libstd/rt/io/stdio.rs
index e6dd9a48099..0bc87c77a9c 100644
--- a/src/libstd/rt/io/stdio.rs
+++ b/src/libstd/rt/io/stdio.rs
@@ -13,7 +13,7 @@ use libc;
 use option::{Option, Some, None};
 use result::{Ok, Err};
 use rt::local::Local;
-use rt::rtio::{RtioFileStream, IoFactoryObject, IoFactory};
+use rt::rtio::{IoFactoryObject, IoFactory, RtioTTYObject, RtioTTY};
 use super::{Reader, Writer, io_error};
 
 /// Creates a new non-blocking handle to the stdin of the current process.
@@ -22,8 +22,8 @@ use super::{Reader, Writer, io_error};
 pub fn stdin() -> StdReader {
     let stream = unsafe {
         let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_from_raw_fd(libc::STDIN_FILENO, false)
-    };
+        (*io).tty_open(libc::STDIN_FILENO, true, false)
+    }.unwrap();
     StdReader { inner: stream }
 }
 
@@ -36,8 +36,8 @@ pub fn stdin() -> StdReader {
 pub fn stdout() -> StdWriter {
     let stream = unsafe {
         let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_from_raw_fd(libc::STDOUT_FILENO, false)
-    };
+        (*io).tty_open(libc::STDOUT_FILENO, false, false)
+    }.unwrap();
     StdWriter { inner: stream }
 }
 
@@ -47,8 +47,8 @@ pub fn stdout() -> StdWriter {
 pub fn stderr() -> StdWriter {
     let stream = unsafe {
         let io: *mut IoFactoryObject = Local::unsafe_borrow();
-        (*io).fs_from_raw_fd(libc::STDERR_FILENO, false)
-    };
+        (*io).tty_open(libc::STDERR_FILENO, false, false)
+    }.unwrap();
     StdWriter { inner: stream }
 }
 
@@ -87,7 +87,30 @@ pub fn println_args(fmt: &fmt::Arguments) {
 
 /// Representation of a reader of a standard input stream
 pub struct StdReader {
-    priv inner: ~RtioFileStream
+    priv inner: ~RtioTTYObject
+}
+
+impl StdReader {
+    /// Controls whether this output stream is a "raw stream" or simply a normal
+    /// stream.
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if an error
+    /// happens.
+    pub fn set_raw(&mut self, raw: bool) {
+        match self.inner.set_raw(raw) {
+            Ok(()) => {},
+            Err(e) => io_error::cond.raise(e),
+        }
+    }
+
+    /// Resets the mode of this stream back to its original state.
+    ///
+    /// # Failure
+    ///
+    /// This function cannot fail.
+    pub fn reset_mode(&mut self) { self.inner.reset_mode(); }
 }
 
 impl Reader for StdReader {
@@ -106,7 +129,50 @@ impl Reader for StdReader {
 
 /// Representation of a writer to a standard output stream
 pub struct StdWriter {
-    priv inner: ~RtioFileStream
+    priv inner: ~RtioTTYObject
+}
+
+impl StdWriter {
+    /// Gets the size of this output window, if possible. This is typically used
+    /// when the writer is attached to something like a terminal, this is used
+    /// to fetch the dimensions of the terminal.
+    ///
+    /// If successful, returns Some((width, height)).
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if an error
+    /// happens.
+    pub fn winsize(&mut self) -> Option<(int, int)> {
+        match self.inner.get_winsize() {
+            Ok(p) => Some(p),
+            Err(e) => {
+                io_error::cond.raise(e);
+                None
+            }
+        }
+    }
+
+    /// Controls whether this output stream is a "raw stream" or simply a normal
+    /// stream.
+    ///
+    /// # Failure
+    ///
+    /// This function will raise on the `io_error` condition if an error
+    /// happens.
+    pub fn set_raw(&mut self, raw: bool) {
+        match self.inner.set_raw(raw) {
+            Ok(()) => {},
+            Err(e) => io_error::cond.raise(e),
+        }
+    }
+
+    /// Resets the mode of this stream back to its original state.
+    ///
+    /// # Failure
+    ///
+    /// This function cannot fail.
+    pub fn reset_mode(&mut self) { self.inner.reset_mode(); }
 }
 
 impl Writer for StdWriter {
@@ -117,10 +183,18 @@ impl Writer for StdWriter {
         }
     }
 
-    fn flush(&mut self) {
-        match self.inner.flush() {
-            Ok(()) => {}
-            Err(e) => io_error::cond.raise(e)
-        }
+    fn flush(&mut self) { /* nothing to do */ }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn smoke() {
+        // Just make sure we can acquire handles
+        stdin();
+        stdout();
+        stderr();
     }
 }