Skip to content

Commit

Permalink
Ctrl-Z returns from Stdin.read() when reading from the console on
Browse files Browse the repository at this point in the history
Windows.
Fixes #19914.
Fixes read(), read_to_string(), read_to_end(), etc.
  • Loading branch information
elahn committed Dec 9, 2016
1 parent e9aa73d commit f9bca00
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 4 deletions.
13 changes: 11 additions & 2 deletions src/libstd/sys/windows/c.rs
Expand Up @@ -819,6 +819,16 @@ pub enum EXCEPTION_DISPOSITION {
ExceptionCollidedUnwind
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CONSOLE_READCONSOLE_CONTROL {
pub nLength: ULONG,
pub nInitialChars: ULONG,
pub dwCtrlWakeupMask: ULONG,
pub dwControlKeyState: ULONG,
}
pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;

#[link(name = "ws2_32")]
#[link(name = "userenv")]
#[link(name = "shell32")]
Expand Down Expand Up @@ -849,12 +859,11 @@ extern "system" {
pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);

// FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
pub fn ReadConsoleW(hConsoleInput: HANDLE,
lpBuffer: LPVOID,
nNumberOfCharsToRead: DWORD,
lpNumberOfCharsRead: LPDWORD,
pInputControl: LPVOID) -> BOOL;
pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;

pub fn WriteConsoleW(hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
Expand Down
24 changes: 22 additions & 2 deletions src/libstd/sys/windows/stdio.rs
Expand Up @@ -111,19 +111,27 @@ impl Stdin {
if utf8.position() as usize == utf8.get_ref().len() {
let mut utf16 = vec![0u16; 0x1000];
let mut num = 0;
let mut input_control = readconsole_input_control(CTRL_Z_MASK);
cvt(unsafe {
c::ReadConsoleW(handle,
utf16.as_mut_ptr() as c::LPVOID,
utf16.len() as u32,
&mut num,
ptr::null_mut())
&mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
})?;
utf16.truncate(num as usize);
// FIXME: what to do about this data that has already been read?
let data = match String::from_utf16(&utf16) {
let mut data = match String::from_utf16(&utf16) {
Ok(utf8) => utf8.into_bytes(),
Err(..) => return Err(invalid_encoding()),
};
if let Output::Console(_) = self.handle {
if let Some(&last_byte) = data.last() {
if last_byte == CTRL_Z {
data.pop();
}
}
}
*utf8 = Cursor::new(data);
}

Expand Down Expand Up @@ -206,6 +214,18 @@ fn invalid_encoding() -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
}

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

pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
// The default buffer capacity is 64k, but apparently windows
// doesn't like 64k reads on stdin. See #13304 for details, but the
Expand Down

0 comments on commit f9bca00

Please sign in to comment.