1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Non-blocking access to stdin, stdout, and stderr.
13 //! This module provides bindings to the local event loop's TTY interface, using it
14 //! to offer synchronous but non-blocking versions of stdio. These handles can be
15 //! inspected for information about terminal dimensions or for related information
16 //! about the stream or terminal to which it is attached.
21 //! # #![feature(old_io)]
22 //! # #![allow(unused_must_use)]
24 //! use std::old_io::*;
26 //! let mut out = old_io::stdout();
27 //! out.write_all(b"Hello, world!");
30 use self::StdSource::*;
37 use old_io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer,
38 standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
39 use marker::{Sync, Send};
43 use option::Option::{Some, None};
44 use ops::{Deref, DerefMut, FnOnce};
46 use result::Result::{Ok, Err};
50 use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT};
54 // And so begins the tale of acquiring a uv handle to a stdio stream on all
55 // platforms in all situations. Our story begins by splitting the world into two
56 // categories, windows and unix. Then one day the creators of unix said let
57 // there be redirection! And henceforth there was redirection away from the
58 // console for standard I/O streams.
60 // After this day, the world split into four factions:
62 // 1. Unix with stdout on a terminal.
63 // 2. Unix with stdout redirected.
64 // 3. Windows with stdout on a terminal.
65 // 4. Windows with stdout redirected.
67 // Many years passed, and then one day the nation of libuv decided to unify this
68 // world. After months of toiling, uv created three ideas: TTY, Pipe, File.
69 // These three ideas propagated throughout the lands and the four great factions
70 // decided to settle among them.
72 // The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
73 // doing so, they even enhanced themselves further then their Pipe/File
74 // brethren, becoming the dominant powers.
76 // The group of 4, however, decided to work independently. They abandoned the
77 // common TTY belief throughout, and even abandoned the fledgling Pipe belief.
78 // The members of the 4th faction decided to only align themselves with File.
80 // tl;dr; TTY works on everything but when windows stdout is redirected, in that
81 // case pipe also doesn't work, but magically file does!
87 fn src<T, F>(fd: libc::c_int, _readable: bool, f: F) -> T where
88 F: FnOnce(StdSource) -> T,
90 match tty::TTY::new(fd) {
91 Ok(tty) => f(TTY(tty)),
92 Err(_) => f(File(fs::FileDesc::new(fd, false))),
97 static LOCAL_STDOUT: RefCell<Option<Box<Writer + Send>>> = {
102 struct RaceBox(BufferedReader<StdReader>);
104 unsafe impl Send for RaceBox {}
105 unsafe impl Sync for RaceBox {}
107 /// A synchronized wrapper around a buffered reader from stdin
109 pub struct StdinReader {
110 inner: Arc<Mutex<RaceBox>>,
113 unsafe impl Send for StdinReader {}
114 unsafe impl Sync for StdinReader {}
116 /// A guard for exclusive access to `StdinReader`'s internal `BufferedReader`.
117 pub struct StdinReaderGuard<'a> {
118 inner: MutexGuard<'a, RaceBox>,
121 impl<'a> Deref for StdinReaderGuard<'a> {
122 type Target = BufferedReader<StdReader>;
124 fn deref(&self) -> &BufferedReader<StdReader> {
129 impl<'a> DerefMut for StdinReaderGuard<'a> {
130 fn deref_mut(&mut self) -> &mut BufferedReader<StdReader> {
136 /// Locks the `StdinReader`, granting the calling thread exclusive access
137 /// to the underlying `BufferedReader`.
139 /// This provides access to methods like `chars` and `lines`.
144 /// # #![feature(old_io)]
146 /// use std::old_io::*;
148 /// let mut stdin = old_io::stdin();
149 /// for line in stdin.lock().lines() {
150 /// println!("{}", line.unwrap());
153 pub fn lock<'a>(&'a mut self) -> StdinReaderGuard<'a> {
155 inner: self.inner.lock().unwrap()
159 /// Like `Buffer::read_line`.
161 /// The read is performed atomically - concurrent read calls in other
162 /// threads will not interleave with this one.
163 pub fn read_line(&mut self) -> IoResult<String> {
164 self.inner.lock().unwrap().0.read_line()
167 /// Like `Buffer::read_until`.
169 /// The read is performed atomically - concurrent read calls in other
170 /// threads will not interleave with this one.
171 pub fn read_until(&mut self, byte: u8) -> IoResult<Vec<u8>> {
172 self.inner.lock().unwrap().0.read_until(byte)
175 /// Like `Buffer::read_char`.
177 /// The read is performed atomically - concurrent read calls in other
178 /// threads will not interleave with this one.
179 pub fn read_char(&mut self) -> IoResult<char> {
180 self.inner.lock().unwrap().0.read_char()
184 impl Reader for StdinReader {
185 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
186 self.inner.lock().unwrap().0.read(buf)
189 // We have to manually delegate all of these because the default impls call
190 // read more than once and we don't want those calls to interleave (or
191 // incur the costs of repeated locking).
193 fn read_at_least(&mut self, min: usize, buf: &mut [u8]) -> IoResult<usize> {
194 self.inner.lock().unwrap().0.read_at_least(min, buf)
197 fn push_at_least(&mut self, min: usize, len: usize, buf: &mut Vec<u8>) -> IoResult<usize> {
198 self.inner.lock().unwrap().0.push_at_least(min, len, buf)
201 fn read_to_end(&mut self) -> IoResult<Vec<u8>> {
202 self.inner.lock().unwrap().0.read_to_end()
205 fn read_le_uint_n(&mut self, nbytes: usize) -> IoResult<u64> {
206 self.inner.lock().unwrap().0.read_le_uint_n(nbytes)
209 fn read_be_uint_n(&mut self, nbytes: usize) -> IoResult<u64> {
210 self.inner.lock().unwrap().0.read_be_uint_n(nbytes)
214 /// Creates a new handle to the stdin of the current process.
216 /// The returned handle is a wrapper around a global `BufferedReader` shared
217 /// by all threads. If buffered access is not desired, the `stdin_raw` function
218 /// is provided to provided unbuffered access to stdin.
220 /// See `stdout()` for more notes about this function.
221 pub fn stdin() -> StdinReader {
222 // We're following the same strategy as kimundi's lazy_static library
223 static mut STDIN: *mut StdinReader = 0 as *mut StdinReader;
224 static ONCE: Once = ONCE_INIT;
228 // The default buffer capacity is 64k, but apparently windows
229 // doesn't like 64k reads on stdin. See #13304 for details, but the
230 // idea is that on windows we use a slightly smaller buffer that's
231 // been seen to be acceptable.
232 let stdin = if cfg!(windows) {
233 BufferedReader::with_capacity(8 * 1024, stdin_raw())
235 BufferedReader::new(stdin_raw())
237 let stdin = StdinReader {
238 inner: Arc::new(Mutex::new(RaceBox(stdin)))
240 STDIN = boxed::into_raw(box stdin);
242 // Make sure to free it at exit
243 let _ = rt::at_exit(|| {
244 Box::from_raw(STDIN);
245 STDIN = ptr::null_mut();
253 /// Creates a new non-blocking handle to the stdin of the current process.
255 /// Unlike `stdin()`, the returned reader is *not* a buffered reader.
257 /// See `stdout()` for more notes about this function.
258 pub fn stdin_raw() -> StdReader {
259 src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
262 /// Creates a line-buffered handle to the stdout of the current process.
264 /// Note that this is a fairly expensive operation in that at least one memory
265 /// allocation is performed. Additionally, this must be called from a runtime
266 /// task context because the stream returned will be a non-blocking object using
267 /// the local scheduler to perform the I/O.
269 /// Care should be taken when creating multiple handles to an output stream for
270 /// a single process. While usage is still safe, the output may be surprising if
271 /// no synchronization is performed to ensure a sane output.
272 pub fn stdout() -> LineBufferedWriter<StdWriter> {
273 LineBufferedWriter::new(stdout_raw())
276 /// Creates an unbuffered handle to the stdout of the current process
278 /// See notes in `stdout()` for more information.
279 pub fn stdout_raw() -> StdWriter {
280 src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
283 /// Creates a line-buffered handle to the stderr of the current process.
285 /// See `stdout()` for notes about this function.
286 pub fn stderr() -> LineBufferedWriter<StdWriter> {
287 LineBufferedWriter::new(stderr_raw())
290 /// Creates an unbuffered handle to the stderr of the current process
292 /// See notes in `stdout()` for more information.
293 pub fn stderr_raw() -> StdWriter {
294 src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
297 /// Resets the task-local stdout handle to the specified writer
299 /// This will replace the current task's stdout handle, returning the old
300 /// handle. All future calls to `print` and friends will emit their output to
301 /// this specified handle.
303 /// Note that this does not need to be called for all new tasks; the default
304 /// output handle is to the process's stdout stream.
305 pub fn set_stdout(stdout: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
306 let mut new = Some(stdout);
307 LOCAL_STDOUT.with(|slot| {
308 mem::replace(&mut *slot.borrow_mut(), new.take())
309 }).and_then(|mut s| {
315 /// Resets the task-local stderr handle to the specified writer
317 /// This will replace the current task's stderr handle, returning the old
318 /// handle. Currently, the stderr handle is used for printing panic messages
319 /// during task panic.
321 /// Note that this does not need to be called for all new tasks; the default
322 /// output handle is to the process's stderr stream.
323 #[unstable(feature = "old_io")]
324 #[deprecated(since = "1.0.0", reason = "replaced with std::io::set_panic")]
325 pub fn set_stderr(_stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
329 // Helper to access the local task's stdout handle
331 // Note that this is not a safe function to expose because you can create an
332 // aliased pointer very easily:
334 // with_task_stdout(|io1| {
335 // with_task_stdout(|io2| {
336 // // io1 aliases io2
339 fn with_task_stdout<F>(f: F) where F: FnOnce(&mut Writer) -> IoResult<()> {
340 let mut my_stdout: Box<Writer + Send> = LOCAL_STDOUT.with(|slot| {
341 slot.borrow_mut().take()
342 }).unwrap_or_else(|| {
345 let result = f(&mut *my_stdout);
346 let mut var = Some(my_stdout);
347 LOCAL_STDOUT.with(|slot| {
348 *slot.borrow_mut() = var.take();
352 Err(e) => panic!("failed printing to stdout: {:?}", e),
356 /// Flushes the local task's stdout handle.
358 /// By default, this stream is a line-buffering stream, so flushing may be
359 /// necessary to ensure that all output is printed to the screen (if there are
360 /// no newlines printed).
362 /// Note that logging macros do not use this stream. Using the logging macros
363 /// will emit output to stderr, and while they are line buffered the log
364 /// messages are always terminated in a newline (no need to flush).
366 with_task_stdout(|io| io.flush())
369 /// Prints a string to the stdout of the current process. No newline is emitted
370 /// after the string is printed.
371 pub fn print(s: &str) {
372 with_task_stdout(|io| io.write_all(s.as_bytes()))
375 /// Prints a string to the stdout of the current process. A literal
376 /// `\n` character is printed to the console after the string.
377 pub fn println(s: &str) {
378 with_task_stdout(|io| {
379 io.write_all(s.as_bytes()).and_then(|()| io.write_all(&[b'\n']))
383 /// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
384 /// with the `format_args!` macro.
385 #[stable(feature = "rust1", since = "1.0.0")]
386 pub fn print_args(fmt: fmt::Arguments) {
387 with_task_stdout(|io| write!(io, "{}", fmt))
390 /// Similar to `println`, but takes a `fmt::Arguments` structure to be
391 /// compatible with the `format_args!` macro.
392 #[stable(feature = "rust1", since = "1.0.0")]
393 pub fn println_args(fmt: fmt::Arguments) {
394 with_task_stdout(|io| writeln!(io, "{}", fmt))
397 /// Representation of a reader of a standard input stream
398 pub struct StdReader {
403 /// Returns whether this stream is attached to a TTY instance or not.
404 pub fn isatty(&self) -> bool {
412 impl Reader for StdReader {
413 fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
414 let ret = match self.inner {
415 TTY(ref mut tty) => {
416 // Flush the task-local stdout so that weird issues like a
417 // print!'d prompt not being shown until after the user hits
420 tty.read(buf).map(|i| i as usize)
422 File(ref mut file) => file.read(buf).map(|i| i as usize),
425 // When reading a piped stdin, libuv will return 0-length reads when
426 // stdin reaches EOF. For pretty much all other streams it will
427 // return an actual EOF error, but apparently for stdin it's a
428 // little different. Hence, here we convert a 0 length read to an
429 // end-of-file indicator so the caller knows to stop reading.
430 Ok(0) => { Err(standard_error(EndOfFile)) }
431 ret @ Ok(..) | ret @ Err(..) => ret,
436 /// Representation of a writer to a standard output stream
437 pub struct StdWriter {
441 unsafe impl Send for StdWriter {}
442 unsafe impl Sync for StdWriter {}
445 /// Gets the size of this output window, if possible. This is typically used
446 /// when the writer is attached to something like a terminal, this is used
447 /// to fetch the dimensions of the terminal.
449 /// If successful, returns `Ok((width, height))`.
453 /// This function will return an error if the output stream is not actually
454 /// connected to a TTY instance, or if querying the TTY instance fails.
455 pub fn winsize(&mut self) -> IoResult<(isize, isize)> {
457 TTY(ref mut tty) => {
463 desc: "stream is not a tty",
470 /// Controls whether this output stream is a "raw stream" or simply a normal
475 /// This function will return an error if the output stream is not actually
476 /// connected to a TTY instance, or if querying the TTY instance fails.
477 pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
479 TTY(ref mut tty) => {
485 desc: "stream is not a tty",
492 /// Returns whether this stream is attached to a TTY instance or not.
493 pub fn isatty(&self) -> bool {
501 impl Writer for StdWriter {
502 fn write_all(&mut self, buf: &[u8]) -> IoResult<()> {
503 // As with stdin on windows, stdout often can't handle writes of large
504 // sizes. For an example, see #14940. For this reason, chunk the output
505 // buffer on windows, but on unix we can just write the whole buffer all
508 // For some other references, it appears that this problem has been
509 // encountered by others [1] [2]. We choose the number 8KB just because
510 // libuv does the same.
512 // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
513 // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html
514 let max_size = if cfg!(windows) {8192} else {usize::MAX};
515 for chunk in buf.chunks(max_size) {
516 try!(match self.inner {
517 TTY(ref mut tty) => tty.write(chunk),
518 File(ref mut file) => file.write(chunk),
530 use sync::mpsc::channel;
535 // Just make sure we can acquire handles