diff --git a/src/main.rs b/src/main.rs index 4b82077b31..da94fb26cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -248,7 +248,7 @@ fn create_settings(matches: &ArgMatches) -> PySettings { .chain(cmd.skip(1).map(ToOwned::to_owned)) .collect() } else { - vec![] + vec!["".to_owned()] }; settings.argv = argv; diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs index 6c7cc8ec2d..9c16b419d9 100644 --- a/vm/src/stdlib/mod.rs +++ b/vm/src/stdlib/mod.rs @@ -1,3 +1,7 @@ +use crate::pyobject::PyObjectRef; +use crate::vm::VirtualMachine; +use std::collections::HashMap; + pub mod array; #[cfg(feature = "rustpython-parser")] pub(crate) mod ast; @@ -33,15 +37,17 @@ mod tokenize; mod unicodedata; mod warnings; mod weakref; -use std::collections::HashMap; -use crate::vm::VirtualMachine; +#[cfg(not(target_arch = "wasm32"))] +#[macro_use] +mod os; + #[cfg(not(target_arch = "wasm32"))] mod faulthandler; +#[cfg(windows)] +mod msvcrt; #[cfg(not(target_arch = "wasm32"))] mod multiprocessing; -#[cfg(not(target_arch = "wasm32"))] -mod os; #[cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))] mod pwd; #[cfg(not(target_arch = "wasm32"))] @@ -57,8 +63,6 @@ mod winreg; #[cfg(not(target_arch = "wasm32"))] mod zlib; -use crate::pyobject::PyObjectRef; - pub type StdlibInitFunc = Box PyObjectRef>; pub fn get_module_inits() -> HashMap { @@ -136,6 +140,7 @@ pub fn get_module_inits() -> HashMap { // Windows-only #[cfg(windows)] { + modules.insert("msvcrt".to_owned(), Box::new(msvcrt::make_module)); modules.insert("_winapi".to_owned(), Box::new(winapi::make_module)); modules.insert("winreg".to_owned(), Box::new(winreg::make_module)); } diff --git a/vm/src/stdlib/msvcrt.rs b/vm/src/stdlib/msvcrt.rs new file mode 100644 index 0000000000..6861328520 --- /dev/null +++ b/vm/src/stdlib/msvcrt.rs @@ -0,0 +1,58 @@ +use crate::obj::objbytes::PyBytesRef; +use crate::obj::objstr::PyStringRef; +use crate::pyobject::{PyObjectRef, PyResult}; +use crate::VirtualMachine; + +use itertools::Itertools; + +extern "C" { + fn _getch() -> i32; + fn _getwch() -> u32; + fn _getche() -> i32; + fn _getwche() -> u32; + fn _putch(c: u32) -> i32; + fn _putwch(c: u16) -> u32; +} + +fn msvcrt_getch() -> Vec { + let c = unsafe { _getch() }; + vec![c as u8] +} +fn msvcrt_getwch() -> String { + let c = unsafe { _getwch() }; + std::char::from_u32(c).unwrap().to_string() +} +fn msvcrt_getche() -> Vec { + let c = unsafe { _getche() }; + vec![c as u8] +} +fn msvcrt_getwche() -> String { + let c = unsafe { _getwche() }; + std::char::from_u32(c).unwrap().to_string() +} +fn msvcrt_putch(b: PyBytesRef, vm: &VirtualMachine) -> PyResult<()> { + let &c = b.get_value().iter().exactly_one().map_err(|_| { + vm.new_type_error("putch() argument must be a byte string of length 1".to_owned()) + })?; + unsafe { suppress_iph!(_putch(c.into())) }; + Ok(()) +} +fn msvcrt_putwch(s: PyStringRef, vm: &VirtualMachine) -> PyResult<()> { + let c = s.as_str().chars().exactly_one().map_err(|_| { + vm.new_type_error("putch() argument must be a string of length 1".to_owned()) + })?; + unsafe { suppress_iph!(_putwch(c as u16)) }; + Ok(()) +} + +pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { + let ctx = &vm.ctx; + py_module!(vm, "_msvcrt", { + "getch" => ctx.new_function(msvcrt_getch), + "getwch" => ctx.new_function(msvcrt_getwch), + "getche" => ctx.new_function(msvcrt_getche), + "getwche" => ctx.new_function(msvcrt_getwche), + "putch" => ctx.new_function(msvcrt_putch), + "putwch" => ctx.new_function(msvcrt_putwch), + }) +} diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 801b852ded..51e6e85068 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -1211,13 +1211,15 @@ type InvalidParamHandler = extern "C" fn( ); #[cfg(windows)] extern "C" { - fn _set_thread_local_invalid_parameter_handler( + #[doc(hidden)] + pub fn _set_thread_local_invalid_parameter_handler( pNew: InvalidParamHandler, ) -> InvalidParamHandler; } #[cfg(windows)] -extern "C" fn silent_iph_handler( +#[doc(hidden)] +pub extern "C" fn silent_iph_handler( _: *const libc::wchar_t, _: *const libc::wchar_t, _: *const libc::wchar_t, @@ -1226,13 +1228,16 @@ extern "C" fn silent_iph_handler( ) { } +#[macro_export] macro_rules! suppress_iph { ($e:expr) => {{ #[cfg(windows)] { - let old = _set_thread_local_invalid_parameter_handler(silent_iph_handler); + let old = $crate::stdlib::os::_set_thread_local_invalid_parameter_handler( + $crate::stdlib::os::silent_iph_handler, + ); let ret = $e; - _set_thread_local_invalid_parameter_handler(old); + $crate::stdlib::os::_set_thread_local_invalid_parameter_handler(old); ret } #[cfg(not(windows))]