Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 77f7c7a

Browse files
committedDec 26, 2016
Auto merge of #38274 - elahn:windows-readconsole-ctrl-z, r=alexcrichton
Ctrl-Z returns from Stdin.read() when reading from the console on Windows Fixes #19914. Fixes read(), read_to_string(), read_to_end(), etc. r? @alexcrichton
2 parents b7e5148 + f9bca00 commit 77f7c7a

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed
 

‎src/libstd/sys/windows/c.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,16 @@ pub enum EXCEPTION_DISPOSITION {
818818
ExceptionCollidedUnwind
819819
}
820820

821+
#[repr(C)]
822+
#[derive(Copy, Clone)]
823+
pub struct CONSOLE_READCONSOLE_CONTROL {
824+
pub nLength: ULONG,
825+
pub nInitialChars: ULONG,
826+
pub dwCtrlWakeupMask: ULONG,
827+
pub dwControlKeyState: ULONG,
828+
}
829+
pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;
830+
821831
#[link(name = "ws2_32")]
822832
#[link(name = "userenv")]
823833
#[link(name = "shell32")]
@@ -848,12 +858,11 @@ extern "system" {
848858
pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
849859
pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
850860

851-
// FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
852861
pub fn ReadConsoleW(hConsoleInput: HANDLE,
853862
lpBuffer: LPVOID,
854863
nNumberOfCharsToRead: DWORD,
855864
lpNumberOfCharsRead: LPDWORD,
856-
pInputControl: LPVOID) -> BOOL;
865+
pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
857866

858867
pub fn WriteConsoleW(hConsoleOutput: HANDLE,
859868
lpBuffer: LPCVOID,

‎src/libstd/sys/windows/stdio.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,27 @@ impl Stdin {
111111
if utf8.position() as usize == utf8.get_ref().len() {
112112
let mut utf16 = vec![0u16; 0x1000];
113113
let mut num = 0;
114+
let mut input_control = readconsole_input_control(CTRL_Z_MASK);
114115
cvt(unsafe {
115116
c::ReadConsoleW(handle,
116117
utf16.as_mut_ptr() as c::LPVOID,
117118
utf16.len() as u32,
118119
&mut num,
119-
ptr::null_mut())
120+
&mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
120121
})?;
121122
utf16.truncate(num as usize);
122123
// FIXME: what to do about this data that has already been read?
123-
let data = match String::from_utf16(&utf16) {
124+
let mut data = match String::from_utf16(&utf16) {
124125
Ok(utf8) => utf8.into_bytes(),
125126
Err(..) => return Err(invalid_encoding()),
126127
};
128+
if let Output::Console(_) = self.handle {
129+
if let Some(&last_byte) = data.last() {
130+
if last_byte == CTRL_Z {
131+
data.pop();
132+
}
133+
}
134+
}
127135
*utf8 = Cursor::new(data);
128136
}
129137

@@ -217,6 +225,18 @@ fn invalid_encoding() -> io::Error {
217225
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
218226
}
219227

228+
fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CONTROL {
229+
c::CONSOLE_READCONSOLE_CONTROL {
230+
nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
231+
nInitialChars: 0,
232+
dwCtrlWakeupMask: wakeup_mask,
233+
dwControlKeyState: 0,
234+
}
235+
}
236+
237+
const CTRL_Z: u8 = 0x1A;
238+
const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A
239+
220240
pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
221241
// The default buffer capacity is 64k, but apparently windows
222242
// doesn't like 64k reads on stdin. See #13304 for details, but the

0 commit comments

Comments
 (0)
Failed to load comments.