about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorElahn Ientile <github@elahn.com.au>2016-12-10 09:46:47 +1000
committerElahn Ientile <github@elahn.com.au>2016-12-10 09:46:47 +1000
commitf9bca00469f4e6826c79638a5058c838ab4c1925 (patch)
treede621eeec786f494d602bdbbdafcafbf0ae3a8bb /src/libstd
parente9aa73d2bf3c94bc4ff32afeb2b20f28c677dafa (diff)
downloadrust-f9bca00469f4e6826c79638a5058c838ab4c1925.tar.gz
rust-f9bca00469f4e6826c79638a5058c838ab4c1925.zip
Ctrl-Z returns from Stdin.read() when reading from the console on
Windows.
Fixes #19914.
Fixes read(), read_to_string(), read_to_end(), etc.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/sys/windows/c.rs13
-rw-r--r--src/libstd/sys/windows/stdio.rs24
2 files changed, 33 insertions, 4 deletions
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 1a563127f7f..6ac3e08f908 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -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,
diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs
index 72788776ded..e4335b9d0bb 100644
--- a/src/libstd/sys/windows/stdio.rs
+++ b/src/libstd/sys/windows/stdio.rs
@@ -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