Better stripping :)?

Hello,

i have following code:

for test in opt_list_args.unwrap()[&index].split_whitespace()
				{
					// println!("{:?}", test);
					process.arg (test);
				}

and the iterator returns some values:

test1
test2
test3
c:\dir
with
whitespace
test4

But c:\dir with whitespace don’t be splitted? I Use at the moment and pattern that i .replace {_} (c:\dir{_}with{_}whitespace) but this is ugly, how can i better split that String? As an example when someone write an directory there with whitespaces?

opt_list_args.unwrap()[&index].split_whitespace()

Why do you have multiple whitespace-delimited arguments in a single string? Where is this string coming from?

Normally you would get arguments from std::env::args(), which properly separates them.

3 Likes

@ExpHP Yes i know :slight_smile:, the opt_list_args comes from an ini file where it gives one section that have this keys with arguments :slight_smile:. But std::env::args() don’t properly separate them when no doubles quotes or singles quotes are around a path, without that he split dir with spaces in 3 and “dir with spaces” in 1.

But the allgorythm that std::env::args() uses that i want to replicate for my arguments that i deliver with an ini file, how rusts std::env::args() do that magic and don’t split an string with quotes around it and only split the string-parts with no quotes around it? When i use split_whitespace he don’t look if quotes are in the String he split :slight_smile:.

???

Okay, that sounds more reasonable, though I’m not sure why your iterator doesn’t return (notice the double-quotes):

test1
test2
test3
"c:\dir
with
whitespace"
test4

But the allgorythm that std::env::args() uses that i want to replicate for my arguments that i deliver with an ini file, how rusts std::env::args() do that magic and don’t split an string with quotes around it and only split the string-parts with no quotes around it?

I doubt that std::env::args() does this; it is probably cmd.exe or powershell that parses the argument list before it starts your program.


Doing this 100% correctly could be difficult. (to my memory, the Windows command line has some really bizarre rules for escaping characters). In order to parse this correctly you’ll want to find a library that acts as a lexer for the windows command line.

In the time since my last message, I was looking around for such a crate, but unfortunately I haven’t found one yet. I’ll keep looking…

3 Likes

I stand corrected. Apparently, windows only tracks one string per command, and it is code that runs before main that usually takes care of argument parsing in C.

Wow. Windows is horrible.

On the bright side, it means that the standard library probably does have a Windows command lexer implemented somewhere. I’ll see if I can find it.

Edit: indeed it does. Maybe we can get this factored out into a crate…

6 Likes

@ExpHP thanks for your investigation. This will be great if we found a crateable solution. An " wihin the " don’t strip and all other please strip" :slight_smile:. An .strip_whitespace_likecmdargs :slight_smile:.

I’m seeing if I can pull it out into a crate.

@cyberpunk: Can you do me a favor and verify that the tests pass? I don’t want to have to set up a Windows testing environment quite just yet… (though I will have to in order to publish it… bleh)

git clone https://github.com/ExpHP/windows-args
cd windows-args
cargo test

To @notriddle who implemented the meat of the code: I added you as an author. Is this okay with you? And would you like to be added as an owner as well? (conversely: Do you have any objections to the crate being on crates.io?)

1 Like

I’ve implemented the Windows quote parsing algorithm for the wild crate.

However, the format is awful, and I do not recommend using it unless absolutely necessary for interoperability with existing Windows ecosystem.

If you need ini with multiple arguments, use TOML instead!

1 Like

Yes.

Yeah, sure.

Hi All,
thx for your work, i will test it in the next hours.Here are 32 Degrees :slight_smile:

@ExpHP Something goes wrong: ???

PS D:\Development\Rust\.projects> cd .\windows-args\
PS D:\Development\Rust\.projects\windows-args> cargo test
   Compiling windows-args v0.1.0 (D:\Development\Rust\.projects\windows-args)
error[E0432]: unresolved import `crate::wtf8::OsStringExt`
 --> src\args.rs:2:29
  |
2 | use crate::wtf8::{OsStrExt, OsStringExt};
  |                             ^^^^^^^^^^^ no `OsStringExt` in `wtf8`. Did you mean to use `OsStrExt`?

error[E0432]: unresolved import `crate::wtf8::OsStringExt`
 --> src\args.rs:2:29
  |
2 | use crate::wtf8::{OsStrExt, OsStringExt};
  |                             ^^^^^^^^^^^ no `OsStringExt` in `wtf8`. Did you mean to use `OsStrExt`?

warning: unused import: `OsStringExt`
 --> src\args.rs:2:29
  |
2 | use crate::wtf8::{OsStrExt, OsStringExt};
  |                             ^^^^^^^^^^^
  |
  = note: #[warn(unused_imports)] on by default

warning: unused import: `OsStringExt`
 --> src\args.rs:2:29
  |
2 | use crate::wtf8::{OsStrExt, OsStringExt};
  |                             ^^^^^^^^^^^
  |
  = note: #[warn(unused_imports)] on by default

error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
  --> src\args.rs:62:44
   |
62 |                     ret_val.push(OsString::from_wide(exe));
   |                                  ----------^^^^^^^^^
   |                                  |
   |                                  function or associated item not found in `std::ffi::OsString`
   |
   = help: items from traits can only be used if the trait is in scope
   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
           `use std::os::windows::ffi::OsStringExt;`

error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
  --> src\args.rs:87:44
   |
87 |                     ret_val.push(OsString::from_wide(exe));
   |                                  ----------^^^^^^^^^
   |                                  |
   |                                  function or associated item not found in `std::ffi::OsString`
   |
   = help: items from traits can only be used if the trait is in scope
   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
           `use std::os::windows::ffi::OsStringExt;`

error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
  --> src\args.rs:62:44
   |
62 |                     ret_val.push(OsString::from_wide(exe));
   |                                  ----------^^^^^^^^^
   |                                  |
   |                                  function or associated item not found in `std::ffi::OsString`
error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
   --> src\args.rs:129:44
    |
129 |                     ret_val.push(OsString::from_wide(&cur[..]));
    |                                  ----------^^^^^^^^^
    |                                  |
    |                                  function or associated item not found in `std::ffi::OsString`
   |
    |
   = help: items from traits can only be used if the trait is in scope
    = help: items from traits can only be used if the trait is in scope
   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
           `use std::os::windows::ffi::OsStringExt;`

    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
            `use std::os::windows::ffi::OsStringExt;`

error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
   --> src\args.rs:146:32
    |
146 |         ret_val.push(OsString::from_wide(&cur[..]));
    |                      ----------^^^^^^^^^
    |                      |
    |                      function or associated item not found in `std::ffi::OsString`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
            `use std::os::windows::ffi::OsStringExt;`

error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
  --> src\args.rs:87:44
   |
87 |                     ret_val.push(OsString::from_wide(exe));
   |                                  ----------^^^^^^^^^
   |                                  |
   |                                  function or associated item not found in `std::ffi::OsString`
   |
   = help: items from traits can only be used if the trait is in scope
   = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
           `use std::os::windows::ffi::OsStringExt;`

error: aborting due to 5 previous errors

Some errors occurred: E0432, E0599.
For more information about an error, try `rustc --explain E0432`.
error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
   --> src\args.rs:129:44
    |
129 |                     ret_val.push(OsString::from_wide(&cur[..]));
    |                                  ----------^^^^^^^^^
    |                                  |
    |                                  function or associated item not found in `std::ffi::OsString`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
            `use std::os::windows::ffi::OsStringExt;`

error[E0599]: no function or associated item named `from_wide` found for type `std::ffi::OsString` in the current scope
   --> src\args.rs:146:32
    |
146 |         ret_val.push(OsString::from_wide(&cur[..]));
    |                      ----------^^^^^^^^^
    |                      |
    |                      function or associated item not found in `std::ffi::OsString`
    |
    = help: items from traits can only be used if the trait is in scope
    = note: the following trait is implemented but not in scope, perhaps add a `use` for it:
            `use std::os::windows::ffi::OsStringExt;`

error: Could not compile `windows-args`.
warning: build failed, waiting for other jobs to finish...
error: aborting due to 5 previous errors

Some errors occurred: E0432, E0599.
For more information about an error, try `rustc --explain E0432`.
error: Could not compile `windows-args`.

To learn more, run the command again with --verbose.
PS D:\Development\Rust\.projects\windows-args>

If exact behavior of windows isn’t required, shell_words::split does this kind of splitting - keeping words surrounded by single or double quotes together.

1 Like

Okay, thanks for the test. I’ll try to fix this and get it up on the weekend.

1 Like

@ExpHP Cool and Thx.

@kornel would you be interested in using this crate for wild? I notice the design of your implementation is quite different from the one in std; is there any particular property about it that this crate would need in order to tempt you? :slight_smile:

(e.g. the fact that it’s safe code, or the fact that it can read one argument at a time)

Actually, I may test your implementation against a comprehensive test suite to see if it is a suitable replacement, since these properties do seem to make it superior…

@cyberpunk It is published!

https://crates.io/crates/windows-args

There are two slightly different functions (parse_args and parse_cmd). Make sure to pick the right one for your use case! If it’s just arguments, use parse_args, and if it includes the executable name, use parse_cmd.

3 Likes

@ExpHP Thank you for extending the Rust Library :sunny:

@ExpHP My hope that this crate can also solve this problem has unfortunately not been fulfilled.

https://users.rust-lang.org/t/strange-escaping/29322

Whenever i give rust an String with no whitespace he cut the double quotes out for an argument, but when i deliver rust Enviroment Variables rust must deliver the double quotes.

let test3 = “%UserProfile\Videos”;
command -> cmd /k (echo | cd) -> double quotes don’t delivered.

let test3 = “c:\users\user with ws\Videos”;
command all is good echo and cd are perfectly interpreted, i think rust deliver the doubles quotes.

Do you know, how can i tell rust to keep his hands off my double quotes? :smile:. At this i combine all my answers from other questions, check if env vars are delivered and the resolve this env vars in rust and not on os level, but this i think are overdosed :slight_smile:???

What std implementation do you mean?

I’ve reinvented mine from scratch, because I need to know which characters were quoted and which not. Any impl that returns args as just strings can’t work for simulating bash-like globbing.

I think my impl is accurate for args, but I know it doesn’t parse command name quite the way it should (because the 0th arg of course has a different syntax…)

Ah. Rats. Yeah, there’s no working around that…