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 prelude::v1::*;
|
|
|
|
|
use io::prelude::*;
|
|
|
|
|
|
|
|
|
|
use io::{self, Cursor};
|
|
|
|
|
use ptr;
|
|
|
|
|
use str;
|
|
|
|
|
use sync::Mutex;
|
|
|
|
|
use sys::c;
|
|
|
|
|
use sys::cvt;
|
|
|
|
|
use sys::handle::Handle;
|
2016-02-12 00:17:24 -08:00
|
|
|
use sys_common::io::read_to_end_uninitialized;
|
2015-02-24 23:27:20 -08:00
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
pub struct NoClose(Option<Handle>);
|
2015-02-24 23:27:20 -08:00
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
pub enum Output {
|
2015-02-24 23:27:20 -08:00
|
|
|
Console(NoClose),
|
|
|
|
|
Pipe(NoClose),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Stdin {
|
|
|
|
|
handle: Output,
|
|
|
|
|
utf8: Mutex<io::Cursor<Vec<u8>>>,
|
|
|
|
|
}
|
|
|
|
|
pub struct Stdout(Output);
|
|
|
|
|
pub struct Stderr(Output);
|
|
|
|
|
|
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() {
|
|
|
|
|
Err(io::Error::new(io::ErrorKind::Other,
|
2015-03-31 16:20:09 -07:00
|
|
|
"no stdio handle available for this process"))
|
2015-02-24 23:27:20 -08:00
|
|
|
} else {
|
|
|
|
|
let ret = NoClose::new(handle);
|
|
|
|
|
let mut out = 0;
|
|
|
|
|
match unsafe { c::GetConsoleMode(handle, &mut out) } {
|
|
|
|
|
0 => Ok(Output::Pipe(ret)),
|
|
|
|
|
_ => Ok(Output::Console(ret)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn write(out: &Output, data: &[u8]) -> io::Result<usize> {
|
|
|
|
|
let handle = match *out {
|
|
|
|
|
Output::Console(ref c) => c.get().raw(),
|
|
|
|
|
Output::Pipe(ref p) => return p.get().write(data),
|
|
|
|
|
};
|
|
|
|
|
let utf16 = match str::from_utf8(data).ok() {
|
std: Stabilize APIs for the 1.8 release
This commit is the result of the FCPs ending for the 1.8 release cycle for both
the libs and the lang suteams. The full list of changes are:
Stabilized
* `braced_empty_structs`
* `augmented_assignments`
* `str::encode_utf16` - renamed from `utf16_units`
* `str::EncodeUtf16` - renamed from `Utf16Units`
* `Ref::map`
* `RefMut::map`
* `ptr::drop_in_place`
* `time::Instant`
* `time::SystemTime`
* `{Instant,SystemTime}::now`
* `{Instant,SystemTime}::duration_since` - renamed from `duration_from_earlier`
* `{Instant,SystemTime}::elapsed`
* Various `Add`/`Sub` impls for `Time` and `SystemTime`
* `SystemTimeError`
* `SystemTimeError::duration`
* Various impls for `SystemTimeError`
* `UNIX_EPOCH`
* `ops::{Add,Sub,Mul,Div,Rem,BitAnd,BitOr,BitXor,Shl,Shr}Assign`
Deprecated
* Scoped TLS (the `scoped_thread_local!` macro)
* `Ref::filter_map`
* `RefMut::filter_map`
* `RwLockReadGuard::map`
* `RwLockWriteGuard::map`
* `Condvar::wait_timeout_with`
Closes #27714
Closes #27715
Closes #27746
Closes #27748
Closes #27908
Closes #29866
2016-02-25 15:52:29 -08:00
|
|
|
Some(utf8) => utf8.encode_utf16().collect::<Vec<u16>>(),
|
2015-02-24 23:27:20 -08:00
|
|
|
None => return Err(invalid_encoding()),
|
|
|
|
|
};
|
|
|
|
|
let mut written = 0;
|
|
|
|
|
try!(cvt(unsafe {
|
|
|
|
|
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())
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// 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());
|
|
|
|
|
Ok(data.len())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Stdin {
|
2015-06-09 21:39:36 -07:00
|
|
|
pub fn new() -> io::Result<Stdin> {
|
|
|
|
|
get(c::STD_INPUT_HANDLE).map(|handle| {
|
|
|
|
|
Stdin {
|
|
|
|
|
handle: handle,
|
|
|
|
|
utf8: Mutex::new(Cursor::new(Vec::new())),
|
|
|
|
|
}
|
|
|
|
|
})
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
|
|
|
|
let handle = match self.handle {
|
|
|
|
|
Output::Console(ref c) => c.get().raw(),
|
|
|
|
|
Output::Pipe(ref p) => return p.get().read(buf),
|
|
|
|
|
};
|
|
|
|
|
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;
|
|
|
|
|
try!(cvt(unsafe {
|
|
|
|
|
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,
|
|
|
|
|
ptr::null_mut())
|
|
|
|
|
}));
|
|
|
|
|
utf16.truncate(num as usize);
|
|
|
|
|
// FIXME: what to do about this data that has already been read?
|
|
|
|
|
let data = match String::from_utf16(&utf16) {
|
|
|
|
|
Ok(utf8) => utf8.into_bytes(),
|
|
|
|
|
Err(..) => return Err(invalid_encoding()),
|
|
|
|
|
};
|
|
|
|
|
*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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
|
|
|
|
unsafe { read_to_end_uninitialized(self, 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> {
|
|
|
|
|
get(c::STD_OUTPUT_HANDLE).map(Stdout)
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
|
|
|
|
write(&self.0, data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Stderr {
|
2015-06-09 21:39:36 -07:00
|
|
|
pub fn new() -> io::Result<Stderr> {
|
|
|
|
|
get(c::STD_ERROR_HANDLE).map(Stderr)
|
2015-02-24 23:27:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
|
|
|
|
write(&self.0, data)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-24 23:27:20 -08:00
|
|
|
impl NoClose {
|
2015-11-02 16:23:22 -08:00
|
|
|
fn new(handle: c::HANDLE) -> NoClose {
|
2015-02-24 23:27:20 -08:00
|
|
|
NoClose(Some(Handle::new(handle)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get(&self) -> &Handle { self.0.as_ref().unwrap() }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Drop for NoClose {
|
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
self.0.take().unwrap().into_raw();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-27 13:44:20 -07:00
|
|
|
impl Output {
|
|
|
|
|
pub fn handle(&self) -> &Handle {
|
|
|
|
|
let nc = match *self {
|
|
|
|
|
Output::Console(ref c) => c,
|
|
|
|
|
Output::Pipe(ref c) => c,
|
|
|
|
|
};
|
|
|
|
|
nc.0.as_ref().unwrap()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|