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 {
|
||||
#[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 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<RtioTTY + Send>),
|
||||
File(FileDesc),
|
||||
TTY(tty::TTY),
|
||||
File(fs::FileDesc),
|
||||
}
|
||||
|
||||
fn src<T>(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<T>(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<Writer + Send>)
|
||||
|
@ -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),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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<Int: num::Zero>(ret: Int) -> IoResult<()> {
|
||||
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 {
|
||||
fn drop(&mut self) {
|
||||
// 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 process;
|
||||
pub mod timer;
|
||||
pub mod tty;
|
||||
|
||||
pub mod addrinfo {
|
||||
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 process;
|
||||
pub mod timer;
|
||||
pub mod tty;
|
||||
|
||||
pub mod addrinfo {
|
||||
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::{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<TTY> {
|
||||
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<uint> {
|
||||
pub fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
|
||||
// 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::<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
|
||||
// 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) };
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue