about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYonggang Luo <luoyonggang@gmail.com>2020-10-08 22:26:31 +0000
committerYonggang Luo <luoyonggang@gmail.com>2021-02-17 17:54:04 +0000
commitfa23ddf6e6932b0caa6ee14bd479264398a3a2a7 (patch)
tree8a6836facce8391bf03150f7634d7649c5b8cd5d
parentee88f46bb5e27c4d9f30326e69ff2298dcbeecb1 (diff)
downloadrust-fa23ddf6e6932b0caa6ee14bd479264398a3a2a7.tar.gz
rust-fa23ddf6e6932b0caa6ee14bd479264398a3a2a7.zip
Expose force_quotes on Windows.
Quotes the arg and not quotes the arg have different effect on Windows when the program called
are msys2/cygwin program.
Refer to https://github.com/msys2/MSYS2-packages/issues/2176

Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
-rw-r--r--library/std/src/sys/windows/ext/process.rs21
-rw-r--r--library/std/src/sys/windows/process.rs12
-rw-r--r--library/std/src/sys/windows/process/tests.rs26
3 files changed, 49 insertions, 10 deletions
diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs
index 3d680a7f2d9..67412e16779 100644
--- a/library/std/src/sys/windows/ext/process.rs
+++ b/library/std/src/sys/windows/ext/process.rs
@@ -105,6 +105,22 @@ pub trait CommandExt: Sealed {
     /// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
     #[stable(feature = "windows_process_extensions", since = "1.16.0")]
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
+
+    /// Forces all arguments to be wrapped in quote (`"`) characters.
+    ///
+    /// This is useful for passing arguments to [MSYS2/Cygwin][1] based
+    /// executables: these programs will expand unquoted arguments containing
+    /// wildcard characters (`?` and `*`) by searching for any file paths
+    /// matching the wildcard pattern.
+    ///
+    /// Adding quotes has no effect when passing arguments to programs
+    /// that use [msvcrt][2]. This includes programs built with both
+    /// MinGW and MSVC.
+    ///
+    /// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
+    /// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
+    #[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
 }
 
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -113,4 +129,9 @@ impl CommandExt for process::Command {
         self.as_inner_mut().creation_flags(flags);
         self
     }
+
+    fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
+        self.as_inner_mut().force_quotes(enabled);
+        self
+    }
 }
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 243065b94b1..83d37795ee5 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -78,6 +78,7 @@ pub struct Command {
     stdin: Option<Stdio>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
+    force_quotes_enabled: bool,
 }
 
 pub enum Stdio {
@@ -109,6 +110,7 @@ impl Command {
             stdin: None,
             stdout: None,
             stderr: None,
+            force_quotes_enabled: false,
         }
     }
 
@@ -134,6 +136,10 @@ impl Command {
         self.flags = flags;
     }
 
+    pub fn force_quotes(&mut self, enabled: bool) {
+        self.force_quotes_enabled = enabled;
+    }
+
     pub fn get_program(&self) -> &OsStr {
         &self.program
     }
@@ -181,7 +187,7 @@ impl Command {
         si.dwFlags = c::STARTF_USESTDHANDLES;
 
         let program = program.as_ref().unwrap_or(&self.program);
-        let mut cmd_str = make_command_line(program, &self.args)?;
+        let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
         cmd_str.push(0); // add null terminator
 
         // stolen from the libuv code.
@@ -467,7 +473,7 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
 
 // Produces a wide string *without terminating null*; returns an error if
 // `prog` or any of the `args` contain a nul.
-fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
+fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> {
     // Encode the command and arguments in a command line string such
     // that the spawned process may recover them using CommandLineToArgvW.
     let mut cmd: Vec<u16> = Vec::new();
@@ -476,7 +482,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
     append_arg(&mut cmd, prog, true)?;
     for arg in args {
         cmd.push(' ' as u16);
-        append_arg(&mut cmd, arg, false)?;
+        append_arg(&mut cmd, arg, force_quotes)?;
     }
     return Ok(cmd);
 
diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs
index 81627ad139b..8830ae049c6 100644
--- a/library/std/src/sys/windows/process/tests.rs
+++ b/library/std/src/sys/windows/process/tests.rs
@@ -3,29 +3,41 @@ use crate::ffi::{OsStr, OsString};
 
 #[test]
 fn test_make_command_line() {
-    fn test_wrapper(prog: &str, args: &[&str]) -> String {
+    fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
         let command_line = &make_command_line(
             OsStr::new(prog),
             &args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
+            force_quotes,
         )
         .unwrap();
         String::from_utf16(command_line).unwrap()
     }
 
-    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
+    assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
 
     assert_eq!(
-        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
         "\"C:\\Program Files\\blah\\blah.exe\" aaa"
     );
     assert_eq!(
-        test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
+        "\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
+    );
+    assert_eq!(
+        test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
+        "\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
+    );
+    assert_eq!(
+        test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
         "\"C:\\Program Files\\test\" aa\\\"bb"
     );
-    assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
-    assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\");
+    assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
+    assert_eq!(
+        test_wrapper("echo", &["\" \\\" \\", "\\"], false),
+        "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
+    );
     assert_eq!(
-        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
+        test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
         "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
     );
 }