From 431dcdc840a27f7c7418b7dff73a329eada8a407 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 17 Oct 2014 13:33:08 -0700 Subject: [PATCH] Runtime removal: refactor tty This patch continues runtime removal by moving the tty implementations into `sys`. Because this eliminates APIs in `libnative` and `librustrt`, it is a: [breaking-change] This functionality is likely to be available publicly, in some form, from `std` in the future. --- src/libnative/io/mod.rs | 26 ------ src/libstd/io/stdio.rs | 26 +++--- src/libstd/sys/common/mod.rs | 8 ++ src/libstd/sys/unix/fs.rs | 19 ----- src/libstd/sys/unix/mod.rs | 1 + src/libstd/sys/unix/tty.rs | 47 +++++++++++ src/libstd/sys/windows/mod.rs | 1 + .../sys/windows/tty.rs} | 80 ++++++++++--------- 8 files changed, 112 insertions(+), 96 deletions(-) create mode 100644 src/libstd/sys/unix/tty.rs rename src/{libnative/io/tty_windows.rs => libstd/sys/windows/tty.rs} (79%) diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index 5d6d23f5f03a..8c7751588cef 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -99,30 +99,4 @@ impl IoFactory { } impl rtio::IoFactory for IoFactory { - #[cfg(unix)] - fn tty_open(&mut self, fd: c_int, _readable: bool) - -> IoResult> { - if unsafe { libc::isatty(fd) } != 0 { - Ok(box file::FileDesc::new(fd, true) as Box) - } else { - Err(IoError { - code: libc::ENOTTY as uint, - extra: 0, - detail: None, - }) - } - } - #[cfg(windows)] - fn tty_open(&mut self, fd: c_int, _readable: bool) - -> IoResult> { - if tty::is_tty(fd) { - Ok(box tty::WindowsTTY::new(fd) as Box) - } else { - Err(IoError { - code: libc::ERROR_INVALID_HANDLE as uint, - extra: 0, - detail: None, - }) - } - } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 98644cfc7e99..158d596ea136 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -36,7 +36,7 @@ use kinds::Send; use libc; use option::{Option, Some, None}; use boxed::Box; -use sys::fs::FileDesc; +use sys::{fs, tty}; use result::{Ok, Err}; use rt; use rt::local::Local; @@ -74,17 +74,15 @@ use uint; // tl;dr; TTY works on everything but when windows stdout is redirected, in that // case pipe also doesn't work, but magically file does! enum StdSource { - TTY(Box), - File(FileDesc), + TTY(tty::TTY), + File(fs::FileDesc), } -fn src(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T { - LocalIo::maybe_raise(|io| { - Ok(match io.tty_open(fd, readable) { - Ok(tty) => f(TTY(tty)), - Err(_) => f(File(FileDesc::new(fd, false))), - }) - }).map_err(IoError::from_rtio_error).unwrap() +fn src(fd: libc::c_int, _readable: bool, f: |StdSource| -> T) -> T { + match tty::TTY::new(fd) { + Ok(tty) => f(TTY(tty)), + Err(_) => f(File(fs::FileDesc::new(fd, false))), + } } local_data_key!(local_stdout: Box) @@ -278,7 +276,7 @@ impl Reader for StdReader { // print!'d prompt not being shown until after the user hits // enter. flush(); - tty.read(buf).map_err(IoError::from_rtio_error) + tty.read(buf).map(|i| i as uint) }, File(ref mut file) => file.read(buf).map(|i| i as uint), }; @@ -313,7 +311,7 @@ impl StdWriter { pub fn winsize(&mut self) -> IoResult<(int, int)> { match self.inner { TTY(ref mut tty) => { - tty.get_winsize().map_err(IoError::from_rtio_error) + tty.get_winsize() } File(..) => { Err(IoError { @@ -335,7 +333,7 @@ impl StdWriter { pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { match self.inner { TTY(ref mut tty) => { - tty.set_raw(raw).map_err(IoError::from_rtio_error) + tty.set_raw(raw) } File(..) => { Err(IoError { @@ -372,7 +370,7 @@ impl Writer for StdWriter { let max_size = if cfg!(windows) {8192} else {uint::MAX}; for chunk in buf.chunks(max_size) { try!(match self.inner { - TTY(ref mut tty) => tty.write(chunk).map_err(IoError::from_rtio_error), + TTY(ref mut tty) => tty.write(chunk), File(ref mut file) => file.write(chunk), }) } diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 75c2987078dc..c5f8214a5c38 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -48,6 +48,14 @@ pub fn short_write(n: uint, desc: &'static str) -> IoError { } } +pub fn unimpl() -> IoError { + IoError { + kind: io::IoUnavailable, + desc: "operations not yet supported", + detail: None, + } +} + // unix has nonzero values as errors pub fn mkerr_libc(ret: Int) -> IoResult<()> { if !ret.is_zero() { diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 3dcd99859e8c..2d02c34e958c 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -137,25 +137,6 @@ impl FileDesc { } } -/* - -impl RtioTTY for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner_read(buf) - } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner_write(buf) - } - fn set_raw(&mut self, _raw: bool) -> IoResult<()> { - Err(super::unimpl()) - } - fn get_winsize(&mut self) -> IoResult<(int, int)> { - Err(super::unimpl()) - } - fn isatty(&self) -> bool { false } -} -*/ - impl Drop for FileDesc { fn drop(&mut self) { // closing stdio file handles makes no sense, so never do it. Also, note diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 03a4e56f00dc..4bd1dd201632 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -35,6 +35,7 @@ pub mod pipe; pub mod helper_signal; pub mod process; pub mod timer; +pub mod tty; pub mod addrinfo { pub use sys_common::net::get_host_addresses; diff --git a/src/libstd/sys/unix/tty.rs b/src/libstd/sys/unix/tty.rs new file mode 100644 index 000000000000..28c17fd4966c --- /dev/null +++ b/src/libstd/sys/unix/tty.rs @@ -0,0 +1,47 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use sys::fs::FileDesc; +use prelude::*; +use libc::{mod, c_int}; +use io::{mod, IoResult, IoError}; +use sys_common; + +pub struct TTY { + pub fd: FileDesc, +} + +impl TTY { + pub fn new(fd: c_int) -> IoResult { + if unsafe { libc::isatty(fd) } != 0 { + Ok(TTY { fd: FileDesc::new(fd, true) }) + } else { + Err(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "file descriptor is not a TTY", + detail: None, + }) + } + } + + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { + self.fd.read(buf) + } + pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.fd.write(buf) + } + pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> { + Err(sys_common::unimpl()) + } + pub fn get_winsize(&mut self) -> IoResult<(int, int)> { + Err(sys_common::unimpl()) + } + pub fn isatty(&self) -> bool { false } +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 0dc06de33e0c..98da4d4e7633 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -42,6 +42,7 @@ pub mod pipe; pub mod helper_signal; pub mod process; pub mod timer; +pub mod tty; pub mod addrinfo { pub use sys_common::net::get_host_addresses; diff --git a/src/libnative/io/tty_windows.rs b/src/libstd/sys/windows/tty.rs similarity index 79% rename from src/libnative/io/tty_windows.rs rename to src/libstd/sys/windows/tty.rs index cf2a0f9dda44..7d001e6394c3 100644 --- a/src/libnative/io/tty_windows.rs +++ b/src/libstd/sys/windows/tty.rs @@ -33,16 +33,16 @@ use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE}; use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID}; use libc::{get_osfhandle, CloseHandle}; use libc::types::os::arch::extra::LPCVOID; -use std::io::MemReader; -use std::ptr; -use std::rt::rtio::{IoResult, IoError, RtioTTY}; -use std::str::from_utf8; +use io::{mod, IoError, IoResult, MemReader}; +use prelude::*; +use ptr; +use str::from_utf8; fn invalid_encoding() -> IoError { IoError { - code: ERROR_ILLEGAL_CHARACTER as uint, - extra: 0, - detail: Some("text was not valid unicode".to_string()), + kind: io::InvalidInput, + desc: "text was not valid unicode", + detail: None, } } @@ -56,40 +56,37 @@ pub fn is_tty(fd: c_int) -> bool { } } -pub struct WindowsTTY { +pub struct TTY { closeme: bool, handle: HANDLE, utf8: MemReader, } -impl WindowsTTY { - pub fn new(fd: c_int) -> WindowsTTY { - // If the file descriptor is one of stdin, stderr, or stdout - // then it should not be closed by us - let closeme = match fd { - 0...2 => false, - _ => true, - }; - let handle = unsafe { get_osfhandle(fd) as HANDLE }; - WindowsTTY { - handle: handle, - utf8: MemReader::new(Vec::new()), - closeme: closeme, +impl TTY { + pub fn new(fd: c_int) -> IoResult { + if is_tty(fd) { + // If the file descriptor is one of stdin, stderr, or stdout + // then it should not be closed by us + let closeme = match fd { + 0...2 => false, + _ => true, + }; + let handle = unsafe { get_osfhandle(fd) as HANDLE }; + Ok(TTY { + handle: handle, + utf8: MemReader::new(Vec::new()), + closeme: closeme, + }) + } else { + Err(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "invalid handle provided to function", + detail: None, + }) } } -} -impl Drop for WindowsTTY { - fn drop(&mut self) { - if self.closeme { - // Nobody cares about the return value - let _ = unsafe { CloseHandle(self.handle) }; - } - } -} - -impl RtioTTY for WindowsTTY { - fn read(&mut self, buf: &mut [u8]) -> IoResult { + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { // Read more if the buffer is empty if self.utf8.eof() { let mut utf16 = Vec::from_elem(0x1000, 0u16); @@ -113,7 +110,7 @@ impl RtioTTY for WindowsTTY { Ok(self.utf8.read(buf).unwrap()) } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { + pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { let utf16 = match from_utf8(buf) { Some(utf8) => { utf8.as_slice().utf16_units().collect::>() @@ -131,7 +128,7 @@ impl RtioTTY for WindowsTTY { } } - fn set_raw(&mut self, raw: bool) -> IoResult<()> { + pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { // FIXME // Somebody needs to decide on which of these flags we want match unsafe { SetConsoleMode(self.handle, @@ -146,7 +143,7 @@ impl RtioTTY for WindowsTTY { } } - fn get_winsize(&mut self) -> IoResult<(int, int)> { + pub fn get_winsize(&mut self) -> IoResult<(int, int)> { // FIXME // Get console buffer via CreateFile with CONOUT$ // Make a CONSOLE_SCREEN_BUFFER_INFO @@ -156,5 +153,14 @@ impl RtioTTY for WindowsTTY { } // Let us magically declare this as a TTY - fn isatty(&self) -> bool { true } + pub fn isatty(&self) -> bool { true } +} + +impl Drop for TTY { + fn drop(&mut self) { + if self.closeme { + // Nobody cares about the return value + let _ = unsafe { CloseHandle(self.handle) }; + } + } }