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.
This commit is contained in:
parent
b8f1193bb1
commit
431dcdc840
8 changed files with 112 additions and 96 deletions
|
@ -99,30 +99,4 @@ impl IoFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl rtio::IoFactory for IoFactory {
|
impl rtio::IoFactory for IoFactory {
|
||||||
#[cfg(unix)]
|
|
||||||
fn tty_open(&mut self, fd: c_int, _readable: bool)
|
|
||||||
-> IoResult<Box<rtio::RtioTTY + Send>> {
|
|
||||||
if unsafe { libc::isatty(fd) } != 0 {
|
|
||||||
Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioTTY + Send>)
|
|
||||||
} 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<Box<rtio::RtioTTY + Send>> {
|
|
||||||
if tty::is_tty(fd) {
|
|
||||||
Ok(box tty::WindowsTTY::new(fd) as Box<rtio::RtioTTY + Send>)
|
|
||||||
} else {
|
|
||||||
Err(IoError {
|
|
||||||
code: libc::ERROR_INVALID_HANDLE as uint,
|
|
||||||
extra: 0,
|
|
||||||
detail: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ use kinds::Send;
|
||||||
use libc;
|
use libc;
|
||||||
use option::{Option, Some, None};
|
use option::{Option, Some, None};
|
||||||
use boxed::Box;
|
use boxed::Box;
|
||||||
use sys::fs::FileDesc;
|
use sys::{fs, tty};
|
||||||
use result::{Ok, Err};
|
use result::{Ok, Err};
|
||||||
use rt;
|
use rt;
|
||||||
use rt::local::Local;
|
use rt::local::Local;
|
||||||
|
@ -74,17 +74,15 @@ use uint;
|
||||||
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
|
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
|
||||||
// case pipe also doesn't work, but magically file does!
|
// case pipe also doesn't work, but magically file does!
|
||||||
enum StdSource {
|
enum StdSource {
|
||||||
TTY(Box<RtioTTY + Send>),
|
TTY(tty::TTY),
|
||||||
File(FileDesc),
|
File(fs::FileDesc),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
|
fn src<T>(fd: libc::c_int, _readable: bool, f: |StdSource| -> T) -> T {
|
||||||
LocalIo::maybe_raise(|io| {
|
match tty::TTY::new(fd) {
|
||||||
Ok(match io.tty_open(fd, readable) {
|
Ok(tty) => f(TTY(tty)),
|
||||||
Ok(tty) => f(TTY(tty)),
|
Err(_) => f(File(fs::FileDesc::new(fd, false))),
|
||||||
Err(_) => f(File(FileDesc::new(fd, false))),
|
}
|
||||||
})
|
|
||||||
}).map_err(IoError::from_rtio_error).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
local_data_key!(local_stdout: Box<Writer + Send>)
|
local_data_key!(local_stdout: Box<Writer + Send>)
|
||||||
|
@ -278,7 +276,7 @@ impl Reader for StdReader {
|
||||||
// print!'d prompt not being shown until after the user hits
|
// print!'d prompt not being shown until after the user hits
|
||||||
// enter.
|
// enter.
|
||||||
flush();
|
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),
|
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)> {
|
pub fn winsize(&mut self) -> IoResult<(int, int)> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
TTY(ref mut tty) => {
|
TTY(ref mut tty) => {
|
||||||
tty.get_winsize().map_err(IoError::from_rtio_error)
|
tty.get_winsize()
|
||||||
}
|
}
|
||||||
File(..) => {
|
File(..) => {
|
||||||
Err(IoError {
|
Err(IoError {
|
||||||
|
@ -335,7 +333,7 @@ impl StdWriter {
|
||||||
pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
|
pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
|
||||||
match self.inner {
|
match self.inner {
|
||||||
TTY(ref mut tty) => {
|
TTY(ref mut tty) => {
|
||||||
tty.set_raw(raw).map_err(IoError::from_rtio_error)
|
tty.set_raw(raw)
|
||||||
}
|
}
|
||||||
File(..) => {
|
File(..) => {
|
||||||
Err(IoError {
|
Err(IoError {
|
||||||
|
@ -372,7 +370,7 @@ impl Writer for StdWriter {
|
||||||
let max_size = if cfg!(windows) {8192} else {uint::MAX};
|
let max_size = if cfg!(windows) {8192} else {uint::MAX};
|
||||||
for chunk in buf.chunks(max_size) {
|
for chunk in buf.chunks(max_size) {
|
||||||
try!(match self.inner {
|
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),
|
File(ref mut file) => file.write(chunk),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
// unix has nonzero values as errors
|
||||||
pub fn mkerr_libc<Int: num::Zero>(ret: Int) -> IoResult<()> {
|
pub fn mkerr_libc<Int: num::Zero>(ret: Int) -> IoResult<()> {
|
||||||
if !ret.is_zero() {
|
if !ret.is_zero() {
|
||||||
|
|
|
@ -137,25 +137,6 @@ impl FileDesc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
impl RtioTTY for FileDesc {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
|
|
||||||
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 {
|
impl Drop for FileDesc {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// closing stdio file handles makes no sense, so never do it. Also, note
|
// closing stdio file handles makes no sense, so never do it. Also, note
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub mod pipe;
|
||||||
pub mod helper_signal;
|
pub mod helper_signal;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
pub mod tty;
|
||||||
|
|
||||||
pub mod addrinfo {
|
pub mod addrinfo {
|
||||||
pub use sys_common::net::get_host_addresses;
|
pub use sys_common::net::get_host_addresses;
|
||||||
|
|
47
src/libstd/sys/unix/tty.rs
Normal file
47
src/libstd/sys/unix/tty.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<TTY> {
|
||||||
|
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<uint> {
|
||||||
|
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 }
|
||||||
|
}
|
|
@ -42,6 +42,7 @@ pub mod pipe;
|
||||||
pub mod helper_signal;
|
pub mod helper_signal;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
pub mod tty;
|
||||||
|
|
||||||
pub mod addrinfo {
|
pub mod addrinfo {
|
||||||
pub use sys_common::net::get_host_addresses;
|
pub use sys_common::net::get_host_addresses;
|
||||||
|
|
|
@ -33,16 +33,16 @@ use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
|
||||||
use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
|
use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
|
||||||
use libc::{get_osfhandle, CloseHandle};
|
use libc::{get_osfhandle, CloseHandle};
|
||||||
use libc::types::os::arch::extra::LPCVOID;
|
use libc::types::os::arch::extra::LPCVOID;
|
||||||
use std::io::MemReader;
|
use io::{mod, IoError, IoResult, MemReader};
|
||||||
use std::ptr;
|
use prelude::*;
|
||||||
use std::rt::rtio::{IoResult, IoError, RtioTTY};
|
use ptr;
|
||||||
use std::str::from_utf8;
|
use str::from_utf8;
|
||||||
|
|
||||||
fn invalid_encoding() -> IoError {
|
fn invalid_encoding() -> IoError {
|
||||||
IoError {
|
IoError {
|
||||||
code: ERROR_ILLEGAL_CHARACTER as uint,
|
kind: io::InvalidInput,
|
||||||
extra: 0,
|
desc: "text was not valid unicode",
|
||||||
detail: Some("text was not valid unicode".to_string()),
|
detail: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,40 +56,37 @@ pub fn is_tty(fd: c_int) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WindowsTTY {
|
pub struct TTY {
|
||||||
closeme: bool,
|
closeme: bool,
|
||||||
handle: HANDLE,
|
handle: HANDLE,
|
||||||
utf8: MemReader,
|
utf8: MemReader,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowsTTY {
|
impl TTY {
|
||||||
pub fn new(fd: c_int) -> WindowsTTY {
|
pub fn new(fd: c_int) -> IoResult<TTY> {
|
||||||
// If the file descriptor is one of stdin, stderr, or stdout
|
if is_tty(fd) {
|
||||||
// then it should not be closed by us
|
// If the file descriptor is one of stdin, stderr, or stdout
|
||||||
let closeme = match fd {
|
// then it should not be closed by us
|
||||||
0...2 => false,
|
let closeme = match fd {
|
||||||
_ => true,
|
0...2 => false,
|
||||||
};
|
_ => true,
|
||||||
let handle = unsafe { get_osfhandle(fd) as HANDLE };
|
};
|
||||||
WindowsTTY {
|
let handle = unsafe { get_osfhandle(fd) as HANDLE };
|
||||||
handle: handle,
|
Ok(TTY {
|
||||||
utf8: MemReader::new(Vec::new()),
|
handle: handle,
|
||||||
closeme: closeme,
|
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 {
|
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
|
||||||
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<uint> {
|
|
||||||
// Read more if the buffer is empty
|
// Read more if the buffer is empty
|
||||||
if self.utf8.eof() {
|
if self.utf8.eof() {
|
||||||
let mut utf16 = Vec::from_elem(0x1000, 0u16);
|
let mut utf16 = Vec::from_elem(0x1000, 0u16);
|
||||||
|
@ -113,7 +110,7 @@ impl RtioTTY for WindowsTTY {
|
||||||
Ok(self.utf8.read(buf).unwrap())
|
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) {
|
let utf16 = match from_utf8(buf) {
|
||||||
Some(utf8) => {
|
Some(utf8) => {
|
||||||
utf8.as_slice().utf16_units().collect::<Vec<u16>>()
|
utf8.as_slice().utf16_units().collect::<Vec<u16>>()
|
||||||
|
@ -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
|
// FIXME
|
||||||
// Somebody needs to decide on which of these flags we want
|
// Somebody needs to decide on which of these flags we want
|
||||||
match unsafe { SetConsoleMode(self.handle,
|
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
|
// FIXME
|
||||||
// Get console buffer via CreateFile with CONOUT$
|
// Get console buffer via CreateFile with CONOUT$
|
||||||
// Make a CONSOLE_SCREEN_BUFFER_INFO
|
// Make a CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
@ -156,5 +153,14 @@ impl RtioTTY for WindowsTTY {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let us magically declare this as a TTY
|
// 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) };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue