Skip to content

Commit fa23ddf

Browse files
committed
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 msys2/MSYS2-packages#2176 Signed-off-by: Yonggang Luo <luoyonggang@gmail.com>
1 parent ee88f46 commit fa23ddf

File tree

3 files changed

+49
-10
lines changed

3 files changed

+49
-10
lines changed

library/std/src/sys/windows/ext/process.rs

+21
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,22 @@ pub trait CommandExt: Sealed {
105105
/// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
106106
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
107107
fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
108+
109+
/// Forces all arguments to be wrapped in quote (`"`) characters.
110+
///
111+
/// This is useful for passing arguments to [MSYS2/Cygwin][1] based
112+
/// executables: these programs will expand unquoted arguments containing
113+
/// wildcard characters (`?` and `*`) by searching for any file paths
114+
/// matching the wildcard pattern.
115+
///
116+
/// Adding quotes has no effect when passing arguments to programs
117+
/// that use [msvcrt][2]. This includes programs built with both
118+
/// MinGW and MSVC.
119+
///
120+
/// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
121+
/// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
122+
#[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
123+
fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
108124
}
109125

110126
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -113,4 +129,9 @@ impl CommandExt for process::Command {
113129
self.as_inner_mut().creation_flags(flags);
114130
self
115131
}
132+
133+
fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
134+
self.as_inner_mut().force_quotes(enabled);
135+
self
136+
}
116137
}

library/std/src/sys/windows/process.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ pub struct Command {
7878
stdin: Option<Stdio>,
7979
stdout: Option<Stdio>,
8080
stderr: Option<Stdio>,
81+
force_quotes_enabled: bool,
8182
}
8283

8384
pub enum Stdio {
@@ -109,6 +110,7 @@ impl Command {
109110
stdin: None,
110111
stdout: None,
111112
stderr: None,
113+
force_quotes_enabled: false,
112114
}
113115
}
114116

@@ -134,6 +136,10 @@ impl Command {
134136
self.flags = flags;
135137
}
136138

139+
pub fn force_quotes(&mut self, enabled: bool) {
140+
self.force_quotes_enabled = enabled;
141+
}
142+
137143
pub fn get_program(&self) -> &OsStr {
138144
&self.program
139145
}
@@ -181,7 +187,7 @@ impl Command {
181187
si.dwFlags = c::STARTF_USESTDHANDLES;
182188

183189
let program = program.as_ref().unwrap_or(&self.program);
184-
let mut cmd_str = make_command_line(program, &self.args)?;
190+
let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
185191
cmd_str.push(0); // add null terminator
186192

187193
// stolen from the libuv code.
@@ -467,7 +473,7 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
467473

468474
// Produces a wide string *without terminating null*; returns an error if
469475
// `prog` or any of the `args` contain a nul.
470-
fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
476+
fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> {
471477
// Encode the command and arguments in a command line string such
472478
// that the spawned process may recover them using CommandLineToArgvW.
473479
let mut cmd: Vec<u16> = Vec::new();
@@ -476,7 +482,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
476482
append_arg(&mut cmd, prog, true)?;
477483
for arg in args {
478484
cmd.push(' ' as u16);
479-
append_arg(&mut cmd, arg, false)?;
485+
append_arg(&mut cmd, arg, force_quotes)?;
480486
}
481487
return Ok(cmd);
482488

library/std/src/sys/windows/process/tests.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,41 @@ use crate::ffi::{OsStr, OsString};
33

44
#[test]
55
fn test_make_command_line() {
6-
fn test_wrapper(prog: &str, args: &[&str]) -> String {
6+
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
77
let command_line = &make_command_line(
88
OsStr::new(prog),
99
&args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
10+
force_quotes,
1011
)
1112
.unwrap();
1213
String::from_utf16(command_line).unwrap()
1314
}
1415

15-
assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
16+
assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
1617

1718
assert_eq!(
18-
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
19+
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
1920
"\"C:\\Program Files\\blah\\blah.exe\" aaa"
2021
);
2122
assert_eq!(
22-
test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
23+
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
24+
"\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
25+
);
26+
assert_eq!(
27+
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
28+
"\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
29+
);
30+
assert_eq!(
31+
test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
2332
"\"C:\\Program Files\\test\" aa\\\"bb"
2433
);
25-
assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
26-
assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\");
34+
assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
35+
assert_eq!(
36+
test_wrapper("echo", &["\" \\\" \\", "\\"], false),
37+
"\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
38+
);
2739
assert_eq!(
28-
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
40+
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
2941
"\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
3042
);
3143
}

0 commit comments

Comments
 (0)