1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![unstable(issue = "0", feature = "windows_stdio")]
17 use io
::{self, Cursor}
;
23 use sys
::handle
::Handle
;
24 use sys_common
::io
::read_to_end_uninitialized
;
26 pub struct NoClose(Option
<Handle
>);
35 utf8
: Mutex
<io
::Cursor
<Vec
<u8>>>,
37 pub struct Stdout(Output
);
38 pub struct Stderr(Output
);
40 pub fn get(handle
: c
::DWORD
) -> io
::Result
<Output
> {
41 let handle
= unsafe { c::GetStdHandle(handle) }
;
42 if handle
== c
::INVALID_HANDLE_VALUE
{
43 Err(io
::Error
::last_os_error())
44 } else if handle
.is_null() {
45 Err(io
::Error
::new(io
::ErrorKind
::Other
,
46 "no stdio handle available for this process"))
48 let ret
= NoClose
::new(handle
);
50 match unsafe { c::GetConsoleMode(handle, &mut out) }
{
51 0 => Ok(Output
::Pipe(ret
)),
52 _
=> Ok(Output
::Console(ret
)),
57 fn write(out
: &Output
, data
: &[u8]) -> io
::Result
<usize> {
58 let handle
= match *out
{
59 Output
::Console(ref c
) => c
.get().raw(),
60 Output
::Pipe(ref p
) => return p
.get().write(data
),
62 // As with stdin on windows, stdout often can't handle writes of large
63 // sizes. For an example, see #14940. For this reason, don't try to
64 // write the entire output buffer on windows.
66 // For some other references, it appears that this problem has been
67 // encountered by others [1] [2]. We choose the number 8K just because
68 // libuv does the same.
70 // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
71 // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html
72 const OUT_MAX
: usize = 8192;
73 let len
= cmp
::min(data
.len(), OUT_MAX
);
74 let utf8
= match str::from_utf8(&data
[..len
]) {
76 Err(ref e
) if e
.valid_up_to() == 0 => return Err(invalid_encoding()),
77 Err(e
) => str::from_utf8(&data
[..e
.valid_up_to()]).unwrap(),
79 let utf16
= utf8
.encode_utf16().collect
::<Vec
<u16>>();
82 c
::WriteConsoleW(handle
,
83 utf16
.as_ptr() as c
::LPCVOID
,
89 // FIXME if this only partially writes the utf16 buffer then we need to
90 // figure out how many bytes of `data` were actually written
91 assert_eq
!(written
as usize, utf16
.len());
96 pub fn new() -> io
::Result
<Stdin
> {
97 get(c
::STD_INPUT_HANDLE
).map(|handle
| {
100 utf8
: Mutex
::new(Cursor
::new(Vec
::new())),
105 pub fn read(&self, buf
: &mut [u8]) -> io
::Result
<usize> {
106 let handle
= match self.handle
{
107 Output
::Console(ref c
) => c
.get().raw(),
108 Output
::Pipe(ref p
) => return p
.get().read(buf
),
110 let mut utf8
= self.utf8
.lock().unwrap();
111 // Read more if the buffer is empty
112 if utf8
.position() as usize == utf8
.get_ref().len() {
113 let mut utf16
= vec
![0u16; 0x1000];
116 c
::ReadConsoleW(handle
,
117 utf16
.as_mut_ptr() as c
::LPVOID
,
122 utf16
.truncate(num
as usize);
123 // FIXME: what to do about this data that has already been read?
124 let data
= match String
::from_utf16(&utf16
) {
125 Ok(utf8
) => utf8
.into_bytes(),
126 Err(..) => return Err(invalid_encoding()),
128 *utf8
= Cursor
::new(data
);
131 // MemReader shouldn't error here since we just filled it
135 pub fn read_to_end(&self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
137 (&mut me
).read_to_end(buf
)
141 #[unstable(reason = "not public", issue = "0", feature = "fd_read")]
142 impl<'a
> Read
for &'a Stdin
{
143 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
147 fn read_to_end(&mut self, buf
: &mut Vec
<u8>) -> io
::Result
<usize> {
148 unsafe { read_to_end_uninitialized(self, buf) }
153 pub fn new() -> io
::Result
<Stdout
> {
154 get(c
::STD_OUTPUT_HANDLE
).map(Stdout
)
157 pub fn write(&self, data
: &[u8]) -> io
::Result
<usize> {
163 pub fn new() -> io
::Result
<Stderr
> {
164 get(c
::STD_ERROR_HANDLE
).map(Stderr
)
167 pub fn write(&self, data
: &[u8]) -> io
::Result
<usize> {
172 // FIXME: right now this raw stderr handle is used in a few places because
173 // std::io::stderr_raw isn't exposed, but once that's exposed this impl
175 impl io
::Write
for Stderr
{
176 fn write(&mut self, data
: &[u8]) -> io
::Result
<usize> {
177 Stderr
::write(self, data
)
179 fn flush(&mut self) -> io
::Result
<()> { Ok(()) }
183 fn new(handle
: c
::HANDLE
) -> NoClose
{
184 NoClose(Some(Handle
::new(handle
)))
187 fn get(&self) -> &Handle { self.0.as_ref().unwrap() }
190 impl Drop
for NoClose
{
192 self.0.take().unwrap().into_raw();
197 pub fn handle(&self) -> &Handle
{
198 let nc
= match *self {
199 Output
::Console(ref c
) => c
,
200 Output
::Pipe(ref c
) => c
,
202 nc
.0.as_ref().unwrap()
206 fn invalid_encoding() -> io
::Error
{
207 io
::Error
::new(io
::ErrorKind
::InvalidData
, "text was not valid unicode")