2015-02-24 23:27:20 -08:00
|
|
|
// Copyright 2015 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.
|
|
|
|
|
2016-02-12 10:29:25 -08:00
|
|
|
#![unstable(issue = "0", feature = "windows_stdio")]
|
|
|
|
|
2015-02-24 23:27:20 -08:00
|
|
|
use io::prelude::*;
|
|
|
|
|
2016-03-12 04:18:17 +00:00
|
|
|
use cmp;
|
2015-02-24 23:27:20 -08:00
|
|
|
use io::{self, Cursor};
|
|
|
|
use ptr;
|
|
|
|
use str;
|
|
|
|
use sync::Mutex;
|
|
|
|
use sys::c;
|
|
|
|
use sys::cvt;
|
|
|
|
use sys::handle::Handle;
|
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
pub enum Output {
|
2017-03-13 22:27:12 -07:00
|
|
|
Console(c::HANDLE),
|
|
|
|
Pipe(c::HANDLE),
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Stdin {
|
|
|
|
utf8: Mutex<io::Cursor<Vec<u8>>>,
|
|
|
|
}
|
2017-03-13 22:27:12 -07:00
|
|
|
pub struct Stdout;
|
|
|
|
pub struct Stderr;
|
2015-02-24 23:27:20 -08:00
|
|
|
|
2015-11-02 16:23:22 -08:00
|
|
|
pub fn get(handle: c::DWORD) -> io::Result<Output> {
|
2015-02-24 23:27:20 -08:00
|
|
|
let handle = unsafe { c::GetStdHandle(handle) };
|
2015-11-02 16:23:22 -08:00
|
|
|
if handle == c::INVALID_HANDLE_VALUE {
|
2015-02-24 23:27:20 -08:00
|
|
|
Err(io::Error::last_os_error())
|
|
|
|
} else if handle.is_null() {
|
2017-03-13 22:27:12 -07:00
|
|
|
Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
|
2015-02-24 23:27:20 -08:00
|
|
|
} else {
|
|
|
|
let mut out = 0;
|
|
|
|
match unsafe { c::GetConsoleMode(handle, &mut out) } {
|
2017-03-13 22:27:12 -07:00
|
|
|
0 => Ok(Output::Pipe(handle)),
|
|
|
|
_ => Ok(Output::Console(handle)),
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-13 22:27:12 -07:00
|
|
|
fn write(handle: c::DWORD, data: &[u8]) -> io::Result<usize> {
|
|
|
|
let handle = match try!(get(handle)) {
|
|
|
|
Output::Console(c) => c,
|
|
|
|
Output::Pipe(p) => {
|
|
|
|
let handle = Handle::new(p);
|
|
|
|
let ret = handle.write(data);
|
|
|
|
handle.into_raw();
|
|
|
|
return ret
|
|
|
|
}
|
2015-02-24 23:27:20 -08:00
|
|
|
};
|
2017-03-13 22:27:12 -07:00
|
|
|
|
2016-03-10 19:09:02 +00:00
|
|
|
// As with stdin on windows, stdout often can't handle writes of large
|
|
|
|
// sizes. For an example, see #14940. For this reason, don't try to
|
|
|
|
// write the entire output buffer on windows.
|
|
|
|
//
|
|
|
|
// For some other references, it appears that this problem has been
|
|
|
|
// encountered by others [1] [2]. We choose the number 8K just because
|
|
|
|
// libuv does the same.
|
|
|
|
//
|
|
|
|
// [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
|
|
|
|
// [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html
|
|
|
|
const OUT_MAX: usize = 8192;
|
2016-03-12 04:18:17 +00:00
|
|
|
let len = cmp::min(data.len(), OUT_MAX);
|
|
|
|
let utf8 = match str::from_utf8(&data[..len]) {
|
|
|
|
Ok(s) => s,
|
|
|
|
Err(ref e) if e.valid_up_to() == 0 => return Err(invalid_encoding()),
|
|
|
|
Err(e) => str::from_utf8(&data[..e.valid_up_to()]).unwrap(),
|
2015-02-24 23:27:20 -08:00
|
|
|
};
|
2016-03-12 04:18:17 +00:00
|
|
|
let utf16 = utf8.encode_utf16().collect::<Vec<u16>>();
|
2015-02-24 23:27:20 -08:00
|
|
|
let mut written = 0;
|
2016-03-22 22:01:37 -05:00
|
|
|
cvt(unsafe {
|
2015-02-24 23:27:20 -08:00
|
|
|
c::WriteConsoleW(handle,
|
2015-11-02 16:23:22 -08:00
|
|
|
utf16.as_ptr() as c::LPCVOID,
|
2015-02-24 23:27:20 -08:00
|
|
|
utf16.len() as u32,
|
|
|
|
&mut written,
|
|
|
|
ptr::null_mut())
|
2016-03-22 22:01:37 -05:00
|
|
|
})?;
|
2015-02-24 23:27:20 -08:00
|
|
|
|
|
|
|
// FIXME if this only partially writes the utf16 buffer then we need to
|
|
|
|
// figure out how many bytes of `data` were actually written
|
|
|
|
assert_eq!(written as usize, utf16.len());
|
2016-03-12 04:18:17 +00:00
|
|
|
Ok(utf8.len())
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Stdin {
|
2015-06-09 21:39:36 -07:00
|
|
|
pub fn new() -> io::Result<Stdin> {
|
2017-03-13 22:27:12 -07:00
|
|
|
Ok(Stdin {
|
|
|
|
utf8: Mutex::new(Cursor::new(Vec::new())),
|
2015-06-09 21:39:36 -07:00
|
|
|
})
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
2017-03-13 22:27:12 -07:00
|
|
|
let handle = match try!(get(c::STD_INPUT_HANDLE)) {
|
|
|
|
Output::Console(c) => c,
|
|
|
|
Output::Pipe(p) => {
|
|
|
|
let handle = Handle::new(p);
|
|
|
|
let ret = handle.read(buf);
|
|
|
|
handle.into_raw();
|
|
|
|
return ret
|
|
|
|
}
|
2015-02-24 23:27:20 -08:00
|
|
|
};
|
|
|
|
let mut utf8 = self.utf8.lock().unwrap();
|
|
|
|
// Read more if the buffer is empty
|
|
|
|
if utf8.position() as usize == utf8.get_ref().len() {
|
2015-07-08 22:52:55 +02:00
|
|
|
let mut utf16 = vec![0u16; 0x1000];
|
2015-02-24 23:27:20 -08:00
|
|
|
let mut num = 0;
|
2016-12-10 09:46:47 +10:00
|
|
|
let mut input_control = readconsole_input_control(CTRL_Z_MASK);
|
2016-03-22 22:01:37 -05:00
|
|
|
cvt(unsafe {
|
2015-02-24 23:27:20 -08:00
|
|
|
c::ReadConsoleW(handle,
|
2015-11-02 16:23:22 -08:00
|
|
|
utf16.as_mut_ptr() as c::LPVOID,
|
2015-02-24 23:27:20 -08:00
|
|
|
utf16.len() as u32,
|
|
|
|
&mut num,
|
2016-12-10 09:46:47 +10:00
|
|
|
&mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
|
2016-03-22 22:01:37 -05:00
|
|
|
})?;
|
2015-02-24 23:27:20 -08:00
|
|
|
utf16.truncate(num as usize);
|
|
|
|
// FIXME: what to do about this data that has already been read?
|
2016-12-10 09:46:47 +10:00
|
|
|
let mut data = match String::from_utf16(&utf16) {
|
2015-02-24 23:27:20 -08:00
|
|
|
Ok(utf8) => utf8.into_bytes(),
|
|
|
|
Err(..) => return Err(invalid_encoding()),
|
|
|
|
};
|
2017-03-13 22:27:12 -07:00
|
|
|
if let Some(&last_byte) = data.last() {
|
|
|
|
if last_byte == CTRL_Z {
|
|
|
|
data.pop();
|
2016-12-10 09:46:47 +10:00
|
|
|
}
|
|
|
|
}
|
2015-02-24 23:27:20 -08:00
|
|
|
*utf8 = Cursor::new(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
// MemReader shouldn't error here since we just filled it
|
|
|
|
utf8.read(buf)
|
|
|
|
}
|
2016-02-12 00:17:24 -08:00
|
|
|
|
|
|
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
|
|
let mut me = self;
|
|
|
|
(&mut me).read_to_end(buf)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[unstable(reason = "not public", issue = "0", feature = "fd_read")]
|
|
|
|
impl<'a> Read for &'a Stdin {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
|
(**self).read(buf)
|
|
|
|
}
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Stdout {
|
2015-06-09 21:39:36 -07:00
|
|
|
pub fn new() -> io::Result<Stdout> {
|
2017-03-13 22:27:12 -07:00
|
|
|
Ok(Stdout)
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
2017-03-13 22:27:12 -07:00
|
|
|
write(c::STD_OUTPUT_HANDLE, data)
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
2016-11-28 18:25:47 -07:00
|
|
|
|
|
|
|
pub fn flush(&self) -> io::Result<()> {
|
|
|
|
Ok(())
|
|
|
|
}
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Stderr {
|
2015-06-09 21:39:36 -07:00
|
|
|
pub fn new() -> io::Result<Stderr> {
|
2017-03-13 22:27:12 -07:00
|
|
|
Ok(Stderr)
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
2017-03-13 22:27:12 -07:00
|
|
|
write(c::STD_ERROR_HANDLE, data)
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
2016-11-28 18:25:47 -07:00
|
|
|
|
|
|
|
pub fn flush(&self) -> io::Result<()> {
|
|
|
|
Ok(())
|
|
|
|
}
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
2015-03-11 15:24:14 -07:00
|
|
|
// FIXME: right now this raw stderr handle is used in a few places because
|
|
|
|
// std::io::stderr_raw isn't exposed, but once that's exposed this impl
|
|
|
|
// should go away
|
|
|
|
impl io::Write for Stderr {
|
|
|
|
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
|
|
|
Stderr::write(self, data)
|
|
|
|
}
|
2016-11-28 21:06:42 -07:00
|
|
|
|
2016-11-28 18:25:47 -07:00
|
|
|
fn flush(&mut self) -> io::Result<()> {
|
|
|
|
Stderr::flush(self)
|
|
|
|
}
|
2015-03-11 15:24:14 -07:00
|
|
|
}
|
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
impl Output {
|
2017-03-13 22:27:12 -07:00
|
|
|
pub fn handle(&self) -> c::HANDLE {
|
|
|
|
match *self {
|
|
|
|
Output::Console(c) => c,
|
|
|
|
Output::Pipe(c) => c,
|
|
|
|
}
|
2015-04-27 13:44:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-24 23:27:20 -08:00
|
|
|
fn invalid_encoding() -> io::Error {
|
2015-05-09 18:57:26 +03:00
|
|
|
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
2016-09-22 00:29:00 +00:00
|
|
|
|
2016-12-10 09:46:47 +10:00
|
|
|
fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CONTROL {
|
|
|
|
c::CONSOLE_READCONSOLE_CONTROL {
|
|
|
|
nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
|
|
|
|
nInitialChars: 0,
|
|
|
|
dwCtrlWakeupMask: wakeup_mask,
|
|
|
|
dwControlKeyState: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const CTRL_Z: u8 = 0x1A;
|
|
|
|
const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A
|
|
|
|
|
2017-11-01 12:50:13 -07:00
|
|
|
pub fn is_ebadf(err: &io::Error) -> bool {
|
|
|
|
err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32)
|
|
|
|
}
|
|
|
|
|
2016-09-30 21:01:53 +00:00
|
|
|
// The default buffer capacity is 64k, but apparently windows
|
|
|
|
// doesn't like 64k reads on stdin. See #13304 for details, but the
|
|
|
|
// idea is that on windows we use a slightly smaller buffer that's
|
|
|
|
// been seen to be acceptable.
|
|
|
|
pub const STDIN_BUF_SIZE: usize = 8 * 1024;
|