Skip to content

Instantly share code, notes, and snippets.

@leiless
Last active April 10, 2024 06:48
Show Gist options
  • Save leiless/994d161a1d254e267a6d84ad5bf0895a to your computer and use it in GitHub Desktop.
Save leiless/994d161a1d254e267a6d84ad5bf0895a to your computer and use it in GitHub Desktop.
Rust windows: Set stdin(fd=0) translation mode to binary mode.
#[cfg(target_os = "windows")]
extern {
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setmode?view=msvc-170
// https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-6.0/aa298581(v=vs.60)
fn _setmode(fd: std::os::raw::c_int, mode: std::os::raw::c_int) -> std::os::raw::c_int;
// https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/wwfcfxas(v=vs.100)
fn _get_errno(p_value: *mut std::os::raw::c_int) -> std::os::raw::c_int;
}
#[cfg(target_os = "windows")]
pub const _O_TEXT: i32 = 0x4000;
#[cfg(target_os = "windows")]
pub const _O_BINARY: i32 = 0x8000;
#[cfg(target_os = "windows")]
pub const _O_WTEXT: i32 = 0x10000;
#[cfg(target_os = "windows")]
pub const _O_U16TEXT: i32 = 0x20000;
#[cfg(target_os = "windows")]
pub const _O_U8TEXT: i32 = 0x40000;
#[cfg(target_os = "windows")]
// Return the previous translation mode
pub fn fd_setmode(fd: i32, mode: i32) -> anyhow::Result<i32> {
use std::os::raw::c_int;
let rc = unsafe { _setmode(c_int::from(fd), c_int::from(mode)) } as i32;
if rc < 0 {
let mut errno = c_int::default();
let rc2 = unsafe { _get_errno(std::ptr::addr_of_mut!(errno)) };
assert_eq!(rc2, 0, "_get_errno() failed, errno: {}", rc2);
assert_ne!(errno, 0);
Err(anyhow::anyhow!("_setmode() failed, errno: {}", errno))
} else {
Ok(rc)
}
}
fn main() -> anyhow::Result<()> {
#[cfg(target_os = "windows")] {
let prev_mode = fd_setmode(0, _O_BINARY)?;
eprintln!("Previous stdin translation mode: {:#x}", prev_mode);
Ok(())
}
#[cfg(not(target_os = "windows"))]
std::compile_error!("unsupported target os");
}
@leiless
Copy link
Author

leiless commented Apr 10, 2024

Cargo.toml dependencies

[dependencies]
anyhow = "1.0"

Output

$ cargo.exe b
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s

$ target/debug/foobar.exe
Previous stdin translation mode: 0x4000

FYI, you could also change stdout/stderr translation mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment