The problem is I'm sending it to std::process::Command::new as an args and it's genuinely sending the \
I'll put up example code on the playground (it'll be a little weird because the playground uses linux and it's going to echo a windows command, but it should do as an example
ok, it only manifests in windows, the linux version seems to work correctly.
I've put a working example on the playground that you (being anyone on windows who wants to help) can save and run on a windows computer to verify this behavior
this is the output I get with this version on windows
Note that quotes exist in the shell syntax, but not the logical command. The quotes are only part of the keyboard-based UI, and not semantics of the command.
You're trying to execute a command as if it was interpreted using shell syntax, and you don't understand the concept of command executed without a shell.
fn test_stdin(){
let program = "echo_test"; // this is a custom program that takes a line from stdin and prints it to stdout
let args = [r#"test "something in quotes" "#];
let std_in_string = "test";
//let std_in_string = "test\n";
let test = run(&program,&args,&std_in_string);
println!("{}",test);
}
In that case, the problem is technically unsolvable, and that's a design flaw in Windows that has no solution due to backwards compatibility going all the way back to MS-DOS.
Commands executed in cmd.exe have no concept of quoting, no concept of escaping, because separation of arguments technically doesn't even exist. The command gets entire command as a single string (GetCommandLineW).
So what other systems that emulate concept of separate arguments do, is they hope command won't use GetCommandLineW literally, and instead will use CommandLineToArgvW, which defines its own (very quirky) syntax of separating arguments.
Your problem is that cmd.exe does not use CommandLineToArgvW, but parses its arguments itself, and the switch /c is magical and changes syntax of the rest of the line. Supporting this in a standard library like Rust's just doesn't make sense, since it would have to hardcode a specific exceptions for knowledge that thiscmd.exe with this/c argument uses a custom parser, which is not compatible with CommandLineToArgvW.
cmd isn't the problem. I just posted an example where there's a shell-less exe getting \" escaped arguments
I can provide the source for echo_test if you want to check that yourself, but it's irrelevant for this test since in this instance it just sits there waiting for a newline it never gets.
This in general is impossible to express in cmd.exe, since there's no API to pass separate arguments. What the executed command gets is just one string, and its syntax is undefined (the command can interpret it however it wants, and parses any number of arguments out of it however it imagines).
But in the best effort to preserve the spaces in one arg, the stdlib has to put them in a quoted string. But then it has to differentiate between quote ending the string, and quote inside. To do that it assumes CommandLineToArgvW syntax for it, so it adds a backslash between non-string-terminating quote.
Command::new("notepad")
.args(&[r#"test "something in quotes" "#])
.stdin(Stdio::piped())
the Notepad gets GetCommandLineW with
notepad "test \"something in quotes\" "
and it could call CommandLineToArgvW to get:
notepad
test "something in quotes"
as separate parsed arguments.
Note that if that Command execution was serialized as:
notepad "test "something in quotes" "
or
notepad test "something in quotes"
then the meaning of that command would be different for CommandLineToArgvW. It'd be ["test ", "something in quotes",""] or ["test", "something in quotes"], instead of [r#"test "something in quotes" "#].
Rust has no way of knowing if the executed command will use GetCommandLineW, or some other parser.