[Distutils] install w/o build, spaces in directory names
Wed, 16 Feb 2000 19:27:00 +0100
> On 11 February 2000, Thomas Heller said:
> > I tried quoting the parameters for _spawn_nt in the following way,
> > which worked for me (after changing some paths to include spaces,
> > which I usually avoid). Not sure if cmd should also be quoted:
> Well, this patch looks better than nothing. But I have a couple
> questions for the Windows crowd:
> * when I use 'os.spawnv()', just how many levels of software are
> involved (C library? kernel? the child program being run?) in
> parsing the command line -- i.e. in splitting the
> Python-list-of-strings up into the argv seen by the child program?
> In other words, whose rules do we have to work with here to properly
> handle filenames with spaces in them?
Eventually os.spawnv() calls the win32 API funtion CreateProcess.
This is somewhat comparable to a unix-kernel call.
Before, the argument list is concatenated into in single string, with
all the arguments separated by blanks. This explains at least, that
arguments containing blanks _must_ be quoted somehow, otherwise
there would be no way to separate them again.
> * regardless of who's involved, what *are* the rules? Ie. what
> characters in a command-line argument will cause that argument to
> need quoting? What are the allowed quote characters? How
> do you deal with arguments that contain the quote characters (ie.
> what if I had a directory named
> Program "Files"
The following characters are not allowed in filenames and directory names:
\ / : * ? " < > |
This is not only imposed by the GUI or the shell (cmd.exe resp. command.com),
you get a windows error:
>>> open ("\"", "a")
Traceback (innermost last):
File "<stdin>", line 1, in ?
IOError: [Errno 22] Invalid argument: '"'
> * is any of this standard or documented, or does it vary from
> application to application?
It is the responsibility of the application or the C-startup code in the
Assume the following program:
int main (int argc, char **argv)
printf ("%s\n", *argv++);
compiled into test.exe.
Playing with this gives some interesting insights about the way the commandline
is parsed in the startup code of the runtime library:
Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> import os
>>> # First, a simple one
>>> os.spawnv (os.P_WAIT, "test.exe", ["a", "b", "c"])
0 #<-- This is the return code of os.spawnv().
>>> # Would you have expected the following?
>>> os.spawnv (os.P_WAIT, "test.exe", ["a b c", "d", "e"])
>>> # Quoted an argument
>>> os.spawnv (os.P_WAIT, "test.exe", ["\"a b c\"", "d", "e"])
a b c
>>> #Incompletely quoted argument
>>> os.spawnv (os.P_WAIT, "test.exe", ["\"a b c", "d", "e"])
a b c d e
>>> os.spawnv (os.P_WAIT, "test.exe", ["a b c\"", "d", "e"])
c d e
>>> os.spawnv (os.P_WAIT, "test.exe", ["a b c\" \"d e"])
Interesting, isn't it?
It seems that
-I"c:\Program files" can be used as well as "-Ic:\Program Files",
as well as -Ic:\Program" "files
So these rules are trivial, assuming that VC uses this standard
argument parsing, my patch should work (except that every arg should
cmd = map (_quote_if_needed, cmd)
> (BTW Thomas, your patch was backwards. This is easy to workaround -- I
> just have to run "patch -R" -- but it's easier to read patches if you
> say "diff <old_file> <new_file>" rather than "diff <new_file>
> <old_file>", which is what I suspect you did.)
Thanks for that, I noted it shortly after the mail was out :-)