## digitalmars.D - Possible bug in std.path?

• Hugo (34/34) May 18 2016 I am having a problem on Windows with the following code:
• Vladimir Panteleev (6/8) May 18 2016 Here you can see the final string value of the program argument
• Hugo (11/15) May 19 2016 What you suggest is non-standard in Windows, and would require
• Steven Schveighoffer (6/18) May 19 2016 Then complain to Microsoft :) This is Microsoft's command shell sending
• Kagamin (6/8) May 19 2016 This is how CommandLineToArgvW behaves, which is called by
• Steven Schveighoffer (9/16) May 19 2016 Thanks for correcting, this is a difference from posix that I forgot abo...
• Steven Schveighoffer (5/22) May 19 2016 For reference to OP, here is the code that accesses original command
• Kagamin (4/6) May 19 2016 One receives unicode arguments by declaring wmain function.
• Vladimir Panteleev (9/17) May 19 2016 As far as I know, CommandLineToArgvW is *the* correct way to
• Kagamin (5/7) May 20 2016 Escaping makes sense for free text arguments, but not for path
• Walter Bright (7/14) May 19 2016 Windows command line processing has special handling for " and \. The \ ...
• Adam D. Ruppe (15/19) May 19 2016 Not exactly... it treats \" as a special case, not \ in general.
• Walter Bright (3/5) May 19 2016 It's not at all weird. It's just garden variety double quoted string beh...
• Hugo (7/14) May 19 2016 I must confess I was a bit misled then by this portion of the
• Walter Bright (3/5) May 19 2016 And it can. It just never received a trailing backslash because that was...
• Hugo (7/12) May 20 2016 Yes, I can see the problem.
• Adam D. Ruppe (11/14) May 20 2016 It is pretty easy to handle, but must happen at a higher level
• Hugo (2/16) May 21 2016 Thank you all.
• Hugo (38/42) Jun 19 2016 Then why doesn't the following code produce the expected output?
• Hugo (9/9) Jun 19 2016 Further, notice what happens if I remove the buildNormalizedPath:
• ag0aep6g (5/14) Jun 19 2016 You're calling Windows' CommandLineToArgvW here. I don't think that's
• Hugo (3/10) Jun 19 2016 I thought the proper way to call GetCommandLineW was precisely
• ag0aep6g (4/6) Jun 19 2016 It may be the proper way, but you don't want the proper way then. I
• Adam D. Ruppe (35/37) Jun 19 2016 Typically, yes, but you are saying you don't like what
• Hugo (16/53) Jun 19 2016 Thanks for the ideas, actually I was trying to do a function
• Hugo (7/10) Jun 19 2016 The problem with that approach is that replace does not work with
• Mike Parker (18/28) Jun 19 2016 FWIW, it seems there's some problem with print wchar* or strings
• Hugo (7/13) Jun 20 2016 There was a bug report in std.conv, which was partially fixed in
• Hugo (36/40) Jun 19 2016 What would be the efficient way to talke this then? I tried regex:
• ag0aep6g (12/15) Jun 19 2016 I don't know if you can solve this with regex alone. May depend on what
• Hugo (10/22) Jun 19 2016 What you suggest is non-standard in Windows, and besides I might
• ag0aep6g (8/10) Jun 19 2016 as a literal double quotation mark character (").
• Hugo (12/18) Jun 19 2016 Perhaps I should have said unusual rather than non-standard. But
• ag0aep6g (7/15) Jun 20 2016 On the other hand, the way D gets the arguments is the same as in
• Hugo (4/6) Jun 20 2016 Not necessarily, cmd.exe is made in C/C++
• ag0aep6g (7/10) Jun 20 2016 As seen on MSDN, it's how "Microsoft C/C++ startup code" does it.
• Hugo (3/13) Jun 20 2016 I guess all the console programs I have used for MS products
Hugo <dmdpathquestion yopmail.com> writes:
I am having a problem on Windows with the following code:

module mytest;

import std.stdio, std.file, std.path;

enum EXIT_SUCCESS = 0;
enum EXIT_FAILURE = -1;

int main(string[] args) {
string appdir;
switch(args.length-1) {
case 0:
writeln("You must provide an argument with a valid
directory path.");
break;
case 1:
appdir = buildNormalizedPath(args[1]);
if(appdir.exists && appdir.isDir) break;
default:
writefln("Error: '%s' is not a valid directory path.",
appdir);
return EXIT_FAILURE;
}
writeln("OK");
return EXIT_SUCCESS;
}

Suppose I compiled this unit on current dir and then executed
these commands:

mkdir "my dir"
mytest "my dir\"

I should get "OK", but instead I get:
Error: 'my test"' is not a valid directory path.

If the trailing backslash is removed it works as intended, but
IMHO buildNormalizedPath should have worked.

In any case, notice the double quote in the output. To me this
suggests the backslash is acting not as a path terminator but as
an escape sequence.

May 18 2016
On Thursday, 19 May 2016 at 03:49:36 UTC, Hugo wrote:

mytest "my dir\"

Here, your backslash is used to escape the second " character.

Error: 'my test"' is not a valid directory path.

Here you can see the final string value of the program argument

The correct invocation is: mytest "my dir\\"

In the future, consider posting to the learn group.

May 18 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Thursday, 19 May 2016 at 05:06:44 UTC, Vladimir Panteleev
wrote:
Here you can see the final string value of the program argument

The correct invocation is: mytest "my dir\\"

What you suggest is non-standard in Windows, and would require
distributing the application with some form of comment saying you
have to use double backslashes, which is unprofessional. Software
should serve the user and not the other way round.

Notice I am not debating the escape character, but the
inconsistency of buildNormalizedPath, which IMHO should have
worked and fixed the trailing backslash.

In the future, consider posting to the learn group.

I did not post there because I thought this was not necessarily a
newbie question. My apologies.

May 19 2016
Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/19/16 9:49 AM, Hugo wrote:
On Thursday, 19 May 2016 at 05:06:44 UTC, Vladimir Panteleev wrote:
Here you can see the final string value of the program argument in

The correct invocation is: mytest "my dir\\"

What you suggest is non-standard in Windows, and would require
distributing the application with some form of comment saying you have
to use double backslashes, which is unprofessional. Software should
serve the user and not the other way round.

Then complain to Microsoft :) This is Microsoft's command shell sending

Notice I am not debating the escape character, but the inconsistency of
buildNormalizedPath, which IMHO should have worked and fixed the
trailing backslash.

buildNormalizedPath is being send the string my dir", what is it
supposed to do with that?

-Steve

May 19 2016
Kagamin <spam here.lot> writes:
On Thursday, 19 May 2016 at 14:53:21 UTC, Steven Schveighoffer
wrote:
Then complain to Microsoft :) This is Microsoft's command shell
sending that parameter to your program.

This is how CommandLineToArgvW behaves, which is called by
druntime to parse the command line. For example, xcopy parses the
command line correctly, e.g. this works as expected:
xcopy file "..\"

May 19 2016
Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/19/16 11:25 AM, Kagamin wrote:
On Thursday, 19 May 2016 at 14:53:21 UTC, Steven Schveighoffer wrote:
Then complain to Microsoft :) This is Microsoft's command shell
sending that parameter to your program.

This is how CommandLineToArgvW behaves, which is called by druntime to
parse the command line. For example, xcopy parses the command line
correctly, e.g. this works as expected:
xcopy file "..\"

Thanks for correcting, this is a difference from posix that I forgot about.

The reason for this (as spelled out in the comments) is to get around
the poor handling of utf8 by Windows.

I think if you write a C program in Windows, your argv/argc will contain .."

You'd have to do the same acrobatics D does to get the original, so I
don't think this is a problem that we need to solve. Use those low-level
functions if you wish.

-Steve

May 19 2016
Steven Schveighoffer <schveiguy yahoo.com> writes:
On 5/19/16 12:02 PM, Steven Schveighoffer wrote:
On 5/19/16 11:25 AM, Kagamin wrote:
On Thursday, 19 May 2016 at 14:53:21 UTC, Steven Schveighoffer wrote:
Then complain to Microsoft :) This is Microsoft's command shell
sending that parameter to your program.

This is how CommandLineToArgvW behaves, which is called by druntime to
parse the command line. For example, xcopy parses the command line
correctly, e.g. this works as expected:
xcopy file "..\"

Thanks for correcting, this is a difference from posix that I forgot about.

The reason for this (as spelled out in the comments) is to get around
the poor handling of utf8 by Windows.

I think if you write a C program in Windows, your argv/argc will contain
.."

You'd have to do the same acrobatics D does to get the original, so I
don't think this is a problem that we need to solve. Use those low-level
functions if you wish.

For reference to OP, here is the code that accesses original command
line, which you can model for your desired behavior:

https://github.com/dlang/druntime/blob/master/src/rt/dmain2.d#L356

-Steve

May 19 2016
Kagamin <spam here.lot> writes:
On Thursday, 19 May 2016 at 16:02:27 UTC, Steven Schveighoffer
wrote:
The reason for this (as spelled out in the comments) is to get
around the poor handling of utf8 by Windows.

One receives unicode arguments by declaring wmain function.
AFAIK, mingw and msvc do it fine, not sure about dmc.

May 19 2016
On Thursday, 19 May 2016 at 15:25:02 UTC, Kagamin wrote:
On Thursday, 19 May 2016 at 14:53:21 UTC, Steven Schveighoffer
wrote:
Then complain to Microsoft :) This is Microsoft's command
shell sending that parameter to your program.

This is how CommandLineToArgvW behaves, which is called by
druntime to parse the command line. For example, xcopy parses
the command line correctly, e.g. this works as expected:
xcopy file "..\"

As far as I know, CommandLineToArgvW is *the* correct way to
parse command-line arguments on Windows. If you do not use it,
then your program will not work correctly when invoked by other
programs which assume you use it, and this includes most programs
which use libraries that accept program arguments as an array
(which is the correct abstraction for program arguments anyway).

The fact that some standard Windows utilities do not obey this
convention is more likely a historical artifact from DOS days.

May 19 2016
Kagamin <spam here.lot> writes:
On Thursday, 19 May 2016 at 19:40:16 UTC, Vladimir Panteleev
wrote:
The fact that some standard Windows utilities do not obey this
convention is more likely a historical artifact from DOS days.

arguments, hence funny heuristics. That said one can use forward
slashes as folder separators on windows.

May 20 2016
Walter Bright <newshound2 digitalmars.com> writes:
On 5/18/2016 8:49 PM, Hugo wrote:
mytest "my dir\"

I should get "OK", but instead I get:
Error: 'my test"' is not a valid directory path.

Windows command line processing has special handling for " and \. The \ is used
to escape the next character, which here is a ". You can see the resulting
argument is [my test"]. Note the quote.

If the trailing backslash is removed it works as intended, but IMHO
buildNormalizedPath should have worked.

buildNormalizedPath is passed [my test"]. It cannot possibly do as you suggest.

In any case, notice the double quote in the output. To me this suggests the
backslash is acting not as a path terminator but as an escape sequence.

This is happening because of how standard Windows programs deal with " and
\ on the command line.

May 19 2016
Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 19 May 2016 at 22:13:36 UTC, Walter Bright wrote:

Windows command line processing has special handling for " and
\. The \ is used to escape the next character, which here is a
". You can see the resulting argument is [my test"]. Note the
quote.

Not exactly... it treats \" as a special case, not \ in general.

https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391%28v=vs.85%29.aspx

Quote:

CommandLineToArgvW has a special interpretation of backslash
characters when they are followed by a quotation mark character
("), as follows:

2n backslashes followed by a quotation mark produce n
backslashes followed by a quotation mark.
(2n) + 1 backslashes followed by a quotation mark again
produce n backslashes followed by a quotation mark.
n backslashes not followed by a quotation mark simply produce
n backslashes.

So indeed, the OP stumbled upon a weird case of Windows command
line, but it is really just this one weird case.

May 19 2016
Walter Bright <newshound2 digitalmars.com> writes:
On 5/19/2016 3:41 PM, Adam D. Ruppe wrote:
So indeed, the OP stumbled upon a weird case of Windows command line, but it is
really just this one weird case.

It's not at all weird. It's just garden variety double quoted string behavior.
Linux has its own quoting scheme on the command line, too.

May 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Thursday, 19 May 2016 at 22:44:06 UTC, Walter Bright wrote:
On 5/19/2016 3:41 PM, Adam D. Ruppe wrote:
So indeed, the OP stumbled upon a weird case of Windows
command line, but it is
really just this one weird case.

It's not at all weird. It's just garden variety double quoted
string behavior. Linux has its own quoting scheme on the
command line, too.

I must confess I was a bit misled then by this portion of the
unittest:

assert (buildNormalizedPath(c:\foo\.\bar/..\\baz\) ==
c:\foo\baz);

Since I saw somewhere D could use different quoting styles, I
assumed the function would deal with the trailing backslash.

May 19 2016
Walter Bright <newshound2 digitalmars.com> writes:
On 5/19/2016 6:35 PM, Hugo wrote:
I assumed the
function would deal with the trailing backslash.

And it can. It just never received a trailing backslash because that was
removed
by the Windows argument processing.

May 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Friday, 20 May 2016 at 03:40:23 UTC, Walter Bright wrote:
On 5/19/2016 6:35 PM, Hugo wrote:
I assumed the
function would deal with the trailing backslash.

And it can. It just never received a trailing backslash because
that was removed by the Windows argument processing.

Yes, I can see the problem.

On the other hand, regular console commands and many console
applications for Windows work as expected, so there must be a way
to deal with this properly, and IMHO this would be usefull in
to find a (perhaps sub-optimal) woraround.

May 20 2016
Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 20 May 2016 at 15:18:39 UTC, Hugo wrote:
On the other hand, regular console commands and many console
applications for Windows work as expected, so there must be a
way to deal with this properly

It is pretty easy to handle, but must happen at a higher level
than buildNormalizedPath.

Use GetCommandLine to fetch the original thing the user typed,
then process it yourself.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156%28v=vs.85%29.aspx

But buildNormalizedPath cannot do this itself because its
argument doesn't necessarily come from the command line.

Your main() function could use it to get the string you pass to
the other functions though. That's probably what most the Windows
built in things do when they need to.

May 20 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Friday, 20 May 2016 at 17:41:22 UTC, Adam D. Ruppe wrote:
On Friday, 20 May 2016 at 15:18:39 UTC, Hugo wrote:
On the other hand, regular console commands and many console
applications for Windows work as expected, so there must be a
way to deal with this properly

It is pretty easy to handle, but must happen at a higher level
than buildNormalizedPath.

Use GetCommandLine to fetch the original thing the user typed,
then process it yourself.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156%28v=vs.85%29.aspx

But buildNormalizedPath cannot do this itself because its
argument doesn't necessarily come from the command line.

Your main() function could use it to get the string you pass to
the other functions though. That's probably what most the
Windows built in things do when they need to.

Thank you all.

May 21 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Friday, 20 May 2016 at 17:41:22 UTC, Adam D. Ruppe wrote:
[...]

Use GetCommandLine to fetch the original thing the user typed,
then process it yourself.

[...]

Then why doesn't the following code produce the expected output?

import std.stdio, std.file, std.path;
version (Windows) {
import core.sys.windows.windows, std.conv;
pragma(lib, "shell32.lib");
}

enum EXIT_SUCCESS = 0;
enum EXIT_FAILURE = 1;

int main(string[] originalargs) {
string[] args;
version (Windows) {
SetConsoleOutputCP(65001);
int wargc;
auto wargs = CommandLineToArgvW(GetCommandLineW(), &wargc);
if (wargs) {
for(uint i; i < wargc; i++) args ~=
buildNormalizedPath(text(wargs[i]));
} else {
writeln("Error getting command line arguments.");
return EXIT_FAILURE;
}
} else args = originalargs;
foreach(uint i, string a; args) writefln("Argument %d: '%s'",
i, a);
return EXIT_SUCCESS;
}

Test from Windows:
mytestapp dir1 dir2 "..\my parent dir\"
(all valid arguments)

Output:
Argument 0: 'mytestapp'
Argument 1: 'dir1'
Argument 2: 'dir2'
Argument 3: '..\my parent dir"'

Notice: I had to use std.conv from master branch because
otherwise text() wouldn't dereference wargs (of type wchar**).

PS. Please forgive me the delay.

Jun 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
Further, notice what happens if I remove the buildNormalizedPath:

mytestapp dir1 ..\ "another dir\"

Argument 0: 'mytestapp '
Argument 1: 'dir'
Argument 2: '..\'
Argument 3: 'another dir"'

Apparently the backslash is still being interpreted as an escape
when followed by a double quote, even if the arguments come from
GetCommandLineW.

Jun 19 2016
ag0aep6g <anonymous example.com> writes:
On 06/19/2016 02:23 PM, Hugo wrote:
On Friday, 20 May 2016 at 17:41:22 UTC, Adam D. Ruppe wrote:
[...]

Use GetCommandLine to fetch the original thing the user typed, then
process it yourself.

[...]

Then why doesn't the following code produce the expected output?

[...]
auto wargs = CommandLineToArgvW(GetCommandLineW(), &wargc);

You're calling Windows' CommandLineToArgvW here. I don't think that's
what Adam meant by "process it yourself". If you don't like how
CommandLineToArgvW parses the command line, don't use it.

Jun 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Sunday, 19 June 2016 at 14:29:27 UTC, ag0aep6g wrote:
[...]
auto wargs = CommandLineToArgvW(GetCommandLineW(),
&wargc);

You're calling Windows' CommandLineToArgvW here. I don't think
that's what Adam meant by "process it yourself". If you don't
like how CommandLineToArgvW parses the command line, don't use
it.

I thought the proper way to call GetCommandLineW was precisely
through CommandLineToArgvW, now I am lost.

Jun 19 2016
ag0aep6g <anonymous example.com> writes:
On 06/19/2016 05:36 PM, Hugo wrote:
I thought the proper way to call GetCommandLineW was precisely through
CommandLineToArgvW, now I am lost.

It may be the proper way, but you don't want the proper way then. I
don't know if there's a Windows function for the behavior you want. If
there isn't, you may have to implemented it yourself.

Jun 19 2016
Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 19 June 2016 at 15:36:08 UTC, Hugo wrote:
I thought the proper way to call GetCommandLineW was precisely
through CommandLineToArgvW, now I am lost.

Typically, yes, but you are saying you don't like what
CommandLineToArgvW does (it is responsible for handling quotes
and backslash escapes), so I'm saying you can do it some other
way.

GetCommandLineW will give you a raw string of what the user
typed. From there, you can treat it all as one argument or split
it up however you like.

One potentially simple option would be to preprocess it by doing
a .replace(\", \\") then pass to CommandLineToArgvW to hack
in the extra slash... or you could do a simple little splitter
yourself, something along the lines of:

---
bool inQuote;
size_t startIdx;
string[] args;

foreach(idx, ch; your_command_line) {
if(ch == '"')
inQuote = !inQuote;
else if(ch == ' ') {
if(!inQuote) {
args ~= to!string(your_command_line[startIdx .. idx];
startIdx = idx + 1;
}
}
}

if(startIdx != your_command_line.length)
args ~= to!string(your_command_line[startIdx .. $]; --- or something along those lines, I didn't actually test that. (btw the to!string is optional, you could just leave them as wstrings) But the idea is to just split on space unless you are inside quotes, doing nothing special on backslashes. That'd be what you want (I think).  Jun 19 2016 Hugo <dmdpathquestion yopmail.com> writes: On Sunday, 19 June 2016 at 23:01:26 UTC, Adam D. Ruppe wrote: On Sunday, 19 June 2016 at 15:36:08 UTC, Hugo wrote: I thought the proper way to call GetCommandLineW was precisely through CommandLineToArgvW, now I am lost. Typically, yes, but you are saying you don't like what CommandLineToArgvW does (it is responsible for handling quotes and backslash escapes), so I'm saying you can do it some other way. GetCommandLineW will give you a raw string of what the user typed. From there, you can treat it all as one argument or split it up however you like. One potentially simple option would be to preprocess it by doing a .replace(\", \\") then pass to CommandLineToArgvW to hack in the extra slash... or you could do a simple little splitter yourself, something along the lines of: --- bool inQuote; size_t startIdx; string[] args; foreach(idx, ch; your_command_line) { if(ch == '"') inQuote = !inQuote; else if(ch == ' ') { if(!inQuote) { args ~= to!string(your_command_line[startIdx .. idx]; startIdx = idx + 1; } } } if(startIdx != your_command_line.length) args ~= to!string(your_command_line[startIdx ..$];
---

or something along those lines, I didn't actually test that.

(btw the to!string is optional, you could just leave them as
wstrings)

But the idea is to just split on space unless you are inside
quotes, doing nothing special on backslashes. That'd be what
you want (I think).

Thanks for the ideas, actually I was trying to do a function
similar to your splitter (but still having some problems with it):

void cleanArgs(in string cmdline, ref string[] args) {
uint argc = 0;
bool inQuotedMode = false;
bool lastCharIsBlank = false;
foreach(char c; cmdline) {
if(c == '"') inQuotedMode = !inQuotedMode;
if(inQuotedMode || (!inQuotedMode && c!=' ')) args[argc] ~= c;
if(!inQuotedMode && c==' ' && !lastCharIsBlank) {
argc++;
lastCharIsBlank = true;
}
}
}

Jun 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Sunday, 19 June 2016 at 23:01:26 UTC, Adam D. Ruppe wrote:
One potentially simple option would be to preprocess it by
doing a .replace(\", \\") then pass to CommandLineToArgvW
to hack in the extra slash...

The problem with that approach is that replace does not work with
wchar*. I might convert it to string, replace and then typecast
as wchar* again because that's what CommandLineToArgvW expects,
but when I try to convert the output to strings again, all I get
conversion or typecast.

Jun 19 2016
Mike Parker <aldacron gmail.com> writes:
On Monday, 20 June 2016 at 05:11:12 UTC, Hugo wrote:
On Sunday, 19 June 2016 at 23:01:26 UTC, Adam D. Ruppe wrote:
One potentially simple option would be to preprocess it by
doing a .replace(\", \\") then pass to CommandLineToArgvW
to hack in the extra slash...

The problem with that approach is that replace does not work
with wchar*. I might convert it to string, replace and then
typecast as wchar* again because that's what CommandLineToArgvW
expects, but when I try to convert the output to strings again,
lost during conversion or typecast.

FWIW, it seems there's some problem with print wchar* or strings
converted from wchar*. With these lines:

auto cmdLine = GetCommandLineW();
auto str = to!string(cmdLine);
writeln(str);

Whether I use to!string or to!wstring, whether I print str or
cmdLine, all I get are addresses. However, replacing
GetCommandLineW with GetCommandLineA yields the correct result
(my test is compiled as slash.exe):

Command: slash "foo\"
Output: slash  "foo\"

It shouldn't hurt to use the A variant, as Windows will do the
necessary conversions under the hood. However, I'd love to know
what the problem is with converting wchar* to a string type. This

auto foo = "I'm a wstring"w.ptr;
writeln(to!wstring(foo));

Jun 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Monday, 20 June 2016 at 05:44:53 UTC, Mike Parker wrote:
It shouldn't hurt to use the A variant, as Windows will do the
necessary conversions under the hood. However, I'd love to know
what the problem is with converting wchar* to a string type.

auto foo = "I'm a wstring"w.ptr;
writeln(to!wstring(foo));

There was a bug report in std.conv, which was partially fixed in
master branch (the one I used). Compiling your code with that fix
produces the expected result. However it seems something is still
missing.

Regarding GetCommandLineA, I could use it but I believe this
would exclude several eastern languages, for example.

Jun 20 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Sunday, 19 June 2016 at 14:29:27 UTC, ag0aep6g wrote:
You're calling Windows' CommandLineToArgvW here. I don't think
that's what Adam meant by "process it yourself". If you don't
like how CommandLineToArgvW parses the command line, don't use
it.

What would be the efficient way to talke this then? I tried regex:

import std.stdio, std.file, std.path;
version (Windows) {
import core.sys.windows.windows, std.conv, std.regex;
pragma(lib, "shell32.lib");
}

enum EXIT_SUCCESS = 0;
enum EXIT_FAILURE = 1;

int main(string[] originalargs) {
string[] args;
version (Windows) {
SetConsoleOutputCP(65001);
static re = regex(\s+, "g");
auto wargs = GetCommandLineW();
if (wargs) {
args = split(text(wargs), re);
debug writefln("'%s'", text(wargs));
} else {
writeln("Error getting command line arguments.");
return EXIT_FAILURE;
}
} else args = originalargs;
foreach(uint i, string a; args) writefln("Argument %d: '%s'",
i, a);
return EXIT_SUCCESS;
}

However it doesn't quite work will all cases (besides I fear in
this case a regexp could offer an unnecessary entry point for an
exploit):

mytestapp dir1 ..\     "another dir\"

Argument 0: 'mytestapp'
Argument 1: 'dir1'
Argument 2: '..\'
Argument 3: '"another'
Argument 4: 'dir\"'

Jun 19 2016
ag0aep6g <anonymous example.com> writes:
On 06/19/2016 06:21 PM, Hugo wrote:
What would be the efficient way to talke this then? I tried regex:

[...]
However it doesn't quite work will all cases (besides I fear in this
case a regexp could offer an unnecessary entry point for an exploit):

I don't know if you can solve this with regex alone. May depend on what
exact behavior you want. Maybe just write a little function instead that
splits the command line, handling quotes and such as you want. If you're
not comfortable writing this, then maybe you're in over your head here.

Of course, all this wouldn't be necessary if you could change the
command line instead to conform with the usual syntax. If the weird
behavior you're going for is just personal preference, and there's no
actual need, I'd suggest to just write the command lines in the normal
way with escape sequences (i.e. "foo\\" to get a trailing backlash

Jun 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Sunday, 19 June 2016 at 17:49:55 UTC, ag0aep6g wrote:
I don't know if you can solve this with regex alone. May depend
on what exact behavior you want. Maybe just write a little
function instead that splits the command line, handling quotes
and such as you want. If you're not comfortable writing this,

Of course, all this wouldn't be necessary if you could change
the command line instead to conform with the usual syntax. If
the weird behavior you're going for is just personal
preference, and there's no actual need, I'd suggest to just
write the command lines in the normal way with escape sequences
(i.e. "foo\\" to get a trailing backlash instead of a trailing
quote).

What you suggest is non-standard in Windows, and besides I might
not be the only user of the application.

I was thinking in doing pecisely what you suggest, writing a
little function.

I like programming little apps now and then as a hobby, but
giving up every time I encounter a difficulty is not for me. I
was just asking in case some of the experienced D programmer here
could recommend an efficient and preferably simple way to do it.
;)

Jun 19 2016
ag0aep6g <anonymous example.com> writes:
On 06/20/2016 12:38 AM, Hugo wrote:
What you suggest is non-standard in Windows,

I don't buy this. MSDN says about "Parsing C++ Command-Line Arguments" [1]:

A double quotation mark preceded by a backslash (\") is interpreted

as a literal double quotation mark character (").

As we've seen, that's also how Windows' own CommandLineToArgvW function
behaves. I don't see how you can consider this "non-standard", when
Windows provides a nice function for it, while there doesn't seem to be
one for your way, or at least it's harder to find.

[1] https://msdn.microsoft.com/en-us/library/17w5ykft.aspx

Jun 19 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Sunday, 19 June 2016 at 23:12:10 UTC, ag0aep6g wrote:
On 06/20/2016 12:38 AM, Hugo wrote:
What you suggest is non-standard in Windows,

Arguments" [1]:

A double quotation mark preceded by a backslash (\") is

interpreted as a literal double quotation mark character (").

Perhaps I should have said unusual rather than non-standard. But
if you want to understand better what I mean, try doing this in
the command line, it works correctly:

cd \
mkdir test
cd test\
mkdir "..\second test\"
cd "..\second test\"

While it's true that you can also do this, it's not typical:

mkdir "\third test\\"
cd "\third test\\"

Jun 19 2016
ag0aep6g <anonymous example.com> writes:
On Monday, 20 June 2016 at 02:19:22 UTC, Hugo wrote:
Perhaps I should have said unusual rather than non-standard.
But if you want to understand better what I mean, try doing
this in the command line, it works correctly:

cd \
mkdir test
cd test\
mkdir "..\second test\"
cd "..\second test\"

On the other hand, the way D gets the arguments is the same as in
C/C++. Doing it differently than that would be unusual, too.

Either way, someone is going to be surprised. I would guess that
you're in the minority here with your expectation. It's better
then to surprise you than the majority of people who expect the
same behavior as in C/C++ programs.

Jun 20 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Monday, 20 June 2016 at 10:01:25 UTC, ag0aep6g wrote:
On the other hand, the way D gets the arguments is the same as
in C/C++. Doing it differently than that would be unusual, too.

Not necessarily, cmd.exe is made in C/C++
AFAIK, most other console applications for Windows behave the
same way too.

Jun 20 2016
ag0aep6g <anonymous example.com> writes:
On Monday, 20 June 2016 at 12:38:23 UTC, Hugo wrote:
Not necessarily, cmd.exe is made in C/C++
AFAIK, most other console applications for Windows behave the
same way too.

As seen on MSDN, it's how "Microsoft C/C++ startup code" does it.
It's what you get in a C main's argv. Populating a D main's args
in a different way would be unusual.

Of course you can parse the command line yourself, and do it
differently then. You can do this in C, in C++, and in D too. But
the default is the other way, in all of them.

Jun 20 2016
Hugo <dmdpathquestion yopmail.com> writes:
On Monday, 20 June 2016 at 12:55:21 UTC, ag0aep6g wrote:
On Monday, 20 June 2016 at 12:38:23 UTC, Hugo wrote:
Not necessarily, cmd.exe is made in C/C++
AFAIK, most other console applications for Windows behave the
same way too.

As seen on MSDN, it's how "Microsoft C/C++ startup code" does
it. It's what you get in a C main's argv. Populating a D main's
args in a different way would be unusual.

Of course you can parse the command line yourself, and do it
differently then. You can do this in C, in C++, and in D too.
But the default is the other way, in all of them.

I guess all the console programs I have used for MS products
(since MS-DOS) have been unusual then according to MSDN. ;)

Jun 20 2016