Ctrl-Z returns from Stdin.read() when reading from the console on
Windows. Fixes #19914. Fixes read(), read_to_string(), read_to_end(), etc.
This commit is contained in:
parent
e9aa73d2bf
commit
f9bca00469
2 changed files with 33 additions and 4 deletions
|
|
@ -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")]
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue