-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Windows: Use WriteFile to write to a UTF-8 console #134622
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,21 +84,43 @@ fn is_console(handle: c::HANDLE) -> bool { | |
unsafe { c::GetConsoleMode(handle, &mut mode) != 0 } | ||
} | ||
|
||
/// Returns true if the attached console's code page is currently UTF-8. | ||
#[cfg(not(target_vendor = "win7"))] | ||
fn is_utf8_console() -> bool { | ||
unsafe { c::GetConsoleOutputCP() == c::CP_UTF8 } | ||
} | ||
|
||
#[cfg(target_vendor = "win7")] | ||
fn is_utf8_console() -> bool { | ||
// Windows 7 has a fun "feature" where WriteFile on a console handle will return | ||
// the number of UTF-16 code units written and not the number of bytes from the input string. | ||
// So we always claim the console isn't UTF-8 to trigger the WriteConsole fallback code. | ||
false | ||
} | ||
|
||
fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> io::Result<usize> { | ||
if data.is_empty() { | ||
return Ok(0); | ||
} | ||
|
||
let handle = get_handle(handle_id)?; | ||
if !is_console(handle) { | ||
if !is_console(handle) || is_utf8_console() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be worried about race conditions at all with changes in the mode setting? My sense is probably no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably not. It is possible that the code page could be changed after |
||
unsafe { | ||
let handle = Handle::from_raw_handle(handle); | ||
let ret = handle.write(data); | ||
let _ = handle.into_raw_handle(); // Don't close the handle | ||
return ret; | ||
} | ||
} else { | ||
write_console_utf16(data, incomplete_utf8, handle) | ||
} | ||
} | ||
|
||
fn write_console_utf16( | ||
data: &[u8], | ||
incomplete_utf8: &mut IncompleteUtf8, | ||
handle: c::HANDLE, | ||
) -> io::Result<usize> { | ||
if incomplete_utf8.len > 0 { | ||
assert!( | ||
incomplete_utf8.len < 4, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this cheap enough to call on every write? I guess we're already calling GetConsoleMode on every write...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I don't love it but it is cheap. Especially when compared to the previous code where if
is_console
is true then it will be doing a full UTF-8 to UTF-16 conversion using a small buffer (necessitating multiple calls towrite
).