This is the mail archive of the
mailing list for the Cygwin project.
RE: Formatting command line arguments when starting a Cygwin process from a native process
- From: "David Allsopp" <dra27 at cantab dot net>
- To: "'Aaron Digulla'" <digulla at hepe dot com>, <cygwin at cygwin dot com>
- Date: Tue, 10 May 2016 19:02:21 +0200
- Subject: RE: Formatting command line arguments when starting a Cygwin process from a native process
- Authentication-results: sourceware.org; auth=none
- References: <E51C5B015DBD1348A1D85763337FB6D9F04BD207 at Remus dot metastack dot local> <6533-5731e280-9-60079180 at 7271027>
Aaron Digulla wrote:
> David Allsopp wrote:
> > Aaron Digulla wrote:
> > >
> > > Am Samstag, 07. Mai 2016 09:45 CEST, "David Allsopp"
> > > schrieb:
> > >
> > >
> > > > > Then all you need is a rudimentary quoting.
> > > >
> > > > Yes, but the question still remains what that rudimentary quoting
> > > > is -
> > > i.e.
> > > > I can see how to quote spaces which appear in elements of argv,
> > > > but I cannot see how to quote double quotes!
> > >
> > > This should help:
> > > https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/0
> > > 4/23/e veryone-quotes-command-line-arguments-the-wrong-way/
> > This provides documentation for how Microsoft implementations do it, not
> how Cygwin does it. The Cygwin DLL is responsible for determining how a
> Cygwin process gets argc and argv from GetCommandLineW.
> That's correct but I read your question as "how do I start executables
> linked against Cygwin from another Windows process"
That's the correct reading of my question!
> To do that, you need to convert the argument list/array into the stupid
> Windows format because that's what the Cygwin process will expect.
This is not correct - both by reading the code and by testing. If you put this into the program caller.c I posted previously in thread which is intended to start with argv being the literal string a\\b (i.e. 4 characters)
commandLine = "callee \"a\\\\b\"";
and then if callee.c is compiled with i686-w64-mingw32-gcc (Microsoft-world - escaping rules according to MSDN):
argc = 2
argv = callee
argv = a\\b
with argv correctly given in Microsoft's escaping. But if you compile callee.c with gcc (Cygwin-world), you get:
argc = 2
argv = callee
argv = a\b
With the Cygwin DLL applying its interpretation of the escaping (treating \\ within a quoted parameter as an escaped single backslash), and quite clearly not MSDN's (treating \\ as two backslash characters because it's no followed by a double-quote). As an aside, if you have CYGWIN=noglob, you will actually get the same output as the native Windows case with two backslashes (more evidence, if you still need it, about how my question is everything to do with the Cygwin DLL, and nothing to do with MSDN and Microsoft's escaping rules).
There's also the small matter of Cygwin's @file trick for reading command line arguments from files (i.e. an extra escaping rule not indicated in MSDN because it's not part of Windows) - this time have commandLine = "@test", run echo foo>test and this time with a Microsoft-compiled callee, you'll get argv = @test and with a Cygwin-compiled one, you'll get argv = foo
> > > My line of thought is that Cygwin can't get anything which Windows
> > > can't send it. So the first step to solve this mess is to make sure
> > > the arguments which you send to CreateProcess() are correct.
> > >
> > > The next step would be to write a small C utility which dumps it's
> > > arguments, so you can properly debug all kinds of characters.
> > See later email, but IMHO the conversion is something Cygwin should have
> precisely documented, not determined by brittle experimentation.
> Ah... no. You're mixing two or three things. Let me enumerate:
> 1. You have to give your OS (Windows or Unix) the information which
> process you want to start and which arguments to pass. Unix has two ways
> (string array and single string), Windows has only single string.
Which system call in Unix allows you to start a process by giving a single string instead of an array of arguments (or a series of parameters)?
> 2. The OS will put the information into a structure of some kind and pass
> that to the new process.
> 3. If you have a shell (CMD.exe, bash, etc), they will take the structure
> and parse it according to some rules. They will then convert the result
> again into an OS call.
> 4. The C runtime of your executable will know where to get the OS
> structure and how to turn the structure into char ** argv.
> Where is Cygwin in all this? It's part of step #3. Cygwin emulates exec()
> and similar Unix OS functions which an emulated shell like BASH will use.
> Which means Cygwin code in the DLL is irrelevant if you don't have a Unix
> shell somewhere in your process chain.
No, Cygwin is loosely part of step #3 and definitely the whole of #4. If you invoke a Cygwin process from a native process, the Cygwin DLL does the work of #4, not the C runtime. Step #3 is entirely irrelevant to my problem because there is no shell involved.
> If you just want to execute a Cygwin process (= Windows process which
> includes the Cygwin.dll), you need to know #1, #2 and #4.
Indeed - which basically was my original question. Precisely how Cygwin deals with the conversion in Step 4.
Problem reports: http://cygwin.com/problems.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple