Skip to content

Commit d59cf56

Browse files
committed
Refactor: Move argument building into args
1 parent 3ea4493 commit d59cf56

File tree

2 files changed

+70
-69
lines changed

2 files changed

+70
-69
lines changed

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

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ mod tests;
88

99
use crate::ffi::OsString;
1010
use crate::fmt;
11+
use crate::io;
1112
use crate::marker::PhantomData;
1213
use crate::num::NonZeroU16;
1314
use crate::os::windows::prelude::*;
1415
use crate::path::PathBuf;
1516
use crate::ptr::NonNull;
1617
use crate::sys::c;
18+
use crate::sys::process::ensure_no_nuls;
1719
use crate::sys::windows::os::current_exe;
1820
use crate::vec;
1921

@@ -234,3 +236,66 @@ impl Iterator for WStrUnits<'_> {
234236
}
235237
}
236238
}
239+
240+
#[derive(Debug)]
241+
pub(crate) enum Arg {
242+
/// Add quotes (if needed)
243+
Regular(OsString),
244+
/// Append raw string without quoting
245+
Raw(OsString),
246+
}
247+
248+
enum Quote {
249+
// Every arg is quoted
250+
Always,
251+
// Whitespace and empty args are quoted
252+
Auto,
253+
// Arg appended without any changes (#29494)
254+
Never,
255+
}
256+
257+
pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> io::Result<()> {
258+
let (arg, quote) = match arg {
259+
Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }),
260+
Arg::Raw(arg) => (arg, Quote::Never),
261+
};
262+
263+
// If an argument has 0 characters then we need to quote it to ensure
264+
// that it actually gets passed through on the command line or otherwise
265+
// it will be dropped entirely when parsed on the other end.
266+
ensure_no_nuls(arg)?;
267+
let arg_bytes = arg.bytes();
268+
let (quote, escape) = match quote {
269+
Quote::Always => (true, true),
270+
Quote::Auto => {
271+
(arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true)
272+
}
273+
Quote::Never => (false, false),
274+
};
275+
if quote {
276+
cmd.push('"' as u16);
277+
}
278+
279+
let mut backslashes: usize = 0;
280+
for x in arg.encode_wide() {
281+
if escape {
282+
if x == '\\' as u16 {
283+
backslashes += 1;
284+
} else {
285+
if x == '"' as u16 {
286+
// Add n+1 backslashes to total 2n+1 before internal '"'.
287+
cmd.extend((0..=backslashes).map(|_| '\\' as u16));
288+
}
289+
backslashes = 0;
290+
}
291+
}
292+
cmd.push(x);
293+
}
294+
295+
if quote {
296+
// Add n backslashes to total 2n before ending '"'.
297+
cmd.extend((0..backslashes).map(|_| '\\' as u16));
298+
cmd.push('"' as u16);
299+
}
300+
Ok(())
301+
}

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

Lines changed: 5 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::os::windows::ffi::{OsStrExt, OsStringExt};
1717
use crate::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle};
1818
use crate::path::{Path, PathBuf};
1919
use crate::ptr;
20+
use crate::sys::args::{self, Arg};
2021
use crate::sys::c;
2122
use crate::sys::c::NonZeroDWORD;
2223
use crate::sys::cvt;
@@ -27,7 +28,7 @@ use crate::sys::pipe::{self, AnonPipe};
2728
use crate::sys::stdio;
2829
use crate::sys_common::mutex::StaticMutex;
2930
use crate::sys_common::process::{CommandEnv, CommandEnvs};
30-
use crate::sys_common::{AsInner, IntoInner};
31+
use crate::sys_common::IntoInner;
3132

3233
use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
3334

@@ -147,7 +148,7 @@ impl AsRef<OsStr> for EnvKey {
147148
}
148149
}
149150

150-
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
151+
pub(crate) fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
151152
if str.as_ref().encode_wide().any(|b| b == 0) {
152153
Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
153154
} else {
@@ -181,14 +182,6 @@ pub struct StdioPipes {
181182
pub stderr: Option<AnonPipe>,
182183
}
183184

184-
#[derive(Debug)]
185-
enum Arg {
186-
/// Add quotes (if needed)
187-
Regular(OsString),
188-
/// Append raw string without quoting
189-
Raw(OsString),
190-
}
191-
192185
impl Command {
193186
pub fn new(program: &OsStr) -> Command {
194187
Command {
@@ -724,15 +717,6 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
724717
}
725718
}
726719

727-
enum Quote {
728-
// Every arg is quoted
729-
Always,
730-
// Whitespace and empty args are quoted
731-
Auto,
732-
// Arg appended without any changes (#29494)
733-
Never,
734-
}
735-
736720
// Produces a wide string *without terminating null*; returns an error if
737721
// `prog` or any of the `args` contain a nul.
738722
fn make_command_line(
@@ -763,57 +747,9 @@ fn make_command_line(
763747

764748
for arg in args {
765749
cmd.push(' ' as u16);
766-
let (arg, quote) = match arg {
767-
Arg::Regular(arg) => (arg, if force_quotes { Quote::Always } else { Quote::Auto }),
768-
Arg::Raw(arg) => (arg, Quote::Never),
769-
};
770-
append_arg(&mut cmd, arg, quote)?;
771-
}
772-
if is_batch_file {
773-
cmd.push(b'"' as u16);
774-
}
775-
return Ok(cmd);
776-
777-
fn append_arg(cmd: &mut Vec<u16>, arg: &OsStr, quote: Quote) -> io::Result<()> {
778-
// If an argument has 0 characters then we need to quote it to ensure
779-
// that it actually gets passed through on the command line or otherwise
780-
// it will be dropped entirely when parsed on the other end.
781-
ensure_no_nuls(arg)?;
782-
let arg_bytes = &arg.as_inner().inner.as_inner();
783-
let (quote, escape) = match quote {
784-
Quote::Always => (true, true),
785-
Quote::Auto => {
786-
(arg_bytes.iter().any(|c| *c == b' ' || *c == b'\t') || arg_bytes.is_empty(), true)
787-
}
788-
Quote::Never => (false, false),
789-
};
790-
if quote {
791-
cmd.push('"' as u16);
792-
}
793-
794-
let mut backslashes: usize = 0;
795-
for x in arg.encode_wide() {
796-
if escape {
797-
if x == '\\' as u16 {
798-
backslashes += 1;
799-
} else {
800-
if x == '"' as u16 {
801-
// Add n+1 backslashes to total 2n+1 before internal '"'.
802-
cmd.extend((0..=backslashes).map(|_| '\\' as u16));
803-
}
804-
backslashes = 0;
805-
}
806-
}
807-
cmd.push(x);
808-
}
809-
810-
if quote {
811-
// Add n backslashes to total 2n before ending '"'.
812-
cmd.extend((0..backslashes).map(|_| '\\' as u16));
813-
cmd.push('"' as u16);
814-
}
815-
Ok(())
750+
args::append_arg(&mut cmd, arg, force_quotes)?;
816751
}
752+
Ok(cmd)
817753
}
818754

819755
fn make_envp(maybe_env: Option<BTreeMap<EnvKey, OsString>>) -> io::Result<(*mut c_void, Vec<u16>)> {

0 commit comments

Comments
 (0)