diff options
author | Mark Hammond <mhammond@skippinet.com.au> | 2002-04-03 01:47:00 (GMT) |
---|---|---|
committer | Mark Hammond <mhammond@skippinet.com.au> | 2002-04-03 01:47:00 (GMT) |
commit | e7fefbf68dc3384b835d38bd8897657d7289f826 (patch) | |
tree | f147bacdfadf2f42b756d3962515b13225f3d27a /PC | |
parent | b0aaec5706237c1086afbbbb9327be59509a6d83 (diff) | |
download | cpython-e7fefbf68dc3384b835d38bd8897657d7289f826.zip cpython-e7fefbf68dc3384b835d38bd8897657d7289f826.tar.gz cpython-e7fefbf68dc3384b835d38bd8897657d7289f826.tar.bz2 |
Fix bugs:
457466: popenx() argument mangling hangs python
226766: popen('python -c"...."') tends to hang
Fixes argument quoting in w9xpopen.exe for Windows 9x. w9xpopen.exe
also never attempts to display a MessageBox when not executed
interactively.
Added test_popen() test. This test currently just executes
"python -c ..." as a child process, and checks that the expected
arguments were all recieved correctly by the child process. This
test succeeds for me on Win9x, win2k and Linux, and I hope it does
for other popen supported platforms too :)
Diffstat (limited to 'PC')
-rw-r--r-- | PC/w9xpopen.c | 56 |
1 files changed, 52 insertions, 4 deletions
diff --git a/PC/w9xpopen.c b/PC/w9xpopen.c index d96d0f5..31448fd 100644 --- a/PC/w9xpopen.c +++ b/PC/w9xpopen.c @@ -16,9 +16,10 @@ #define WINDOWS_LEAN_AND_MEAN #include <windows.h> +#include <stdio.h> const char *usage = -"This program is used by Python's os.pipe function to\n" +"This program is used by Python's os.popen function to\n" "to work around a limitation in Windows 95/98. It is\n" "not designed to be used as stand-alone program."; @@ -28,11 +29,56 @@ int main(int argc, char *argv[]) STARTUPINFO si; PROCESS_INFORMATION pi; DWORD exit_code=0; + int cmdlen = 0; + int i; + char *cmdline, *cmdlinefill; - if (argc != 2) { - MessageBox(NULL, usage, argv[0], MB_OK); + if (argc < 2) { + if (GetFileType(GetStdHandle(STD_INPUT_HANDLE))==FILE_TYPE_CHAR) + /* Attached to a console, and therefore not executed by Python + Display a message box for the inquisitive user + */ + MessageBox(NULL, usage, argv[0], MB_OK); + else { + /* Eeek - executed by Python, but args are screwed! + Write an error message to stdout so there is at + least some clue for the end user when it appears + in their output. + A message box would be hidden and blocks the app. + */ + fprintf(stdout, "Internal popen error - no args specified\n%s\n", usage); + } return 1; } + /* Build up the command-line from the args. + Args with a space are quoted, existing quotes are escaped. + To keep things simple calculating the buffer size, we assume + every character is a quote - ie, we allocate double what we need + in the worst case. As this is only double the command line passed + to us, there is a good chance this is reasonably small, so the total + allocation will almost always be < 512 bytes. + */ + for (i=1;i<argc;i++) + cmdlen += strlen(argv[i])*2 + 3; /* one space, maybe 2 quotes */ + cmdline = cmdlinefill = (char *)malloc(cmdlen+1); + if (cmdline == NULL) + return -1; + for (i=1;i<argc;i++) { + const char *arglook; + int bQuote = strchr(argv[i], ' ') != NULL; + if (bQuote) + *cmdlinefill++ = '"'; + /* escape quotes */ + for (arglook=argv[i];*arglook;arglook++) { + if (*arglook=='"') + *cmdlinefill++ = '\\'; + *cmdlinefill++ = *arglook; + } + if (bQuote) + *cmdlinefill++ = '"'; + *cmdlinefill++ = ' '; + } + *cmdlinefill = '\0'; /* Make child process use this app's standard files. */ ZeroMemory(&si, sizeof si); @@ -43,13 +89,15 @@ int main(int argc, char *argv[]) si.hStdError = GetStdHandle(STD_ERROR_HANDLE); bRet = CreateProcess( - NULL, argv[1], + NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ); + free(cmdline); + if (bRet) { if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) { GetExitCodeProcess(pi.hProcess, &exit_code); |